nethack-3.4.3/0040755000000000000000000000000007764735105011656 5ustar rootrootnethack-3.4.3/dat/0040755000000000000000000000000007764735121012424 5ustar rootrootnethack-3.4.3/dat/Arch.des0100644000000000000000000003605007764735040013777 0ustar rootroot# SCCS Id: @(#)Arch.des 3.4 1997/01/31 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Lord Carnarvon # and receive your quest assignment. # MAZE: "Arc-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ............................................................................ ............................................................................ ....................}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}................. ....................}-------------------------------------}................. ....................}|..S......+.................+.......|}................. ....................}-S---------------+----------|.......|}................. ....................}|.|...............|.......+.|.......|}................. ....................}|.|...............---------.---------}................. ....................}|.S.\.............+.................+.................. ....................}|.|...............---------.---------}................. ....................}|.|...............|.......+.|.......|}................. ....................}-S---------------+----------|.......|}................. ....................}|..S......+.................+.......|}................. ....................}-------------------------------------}................. ....................}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}................. ............................................................................ ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION: (22,06,23,06),unlit,"ordinary" REGION: (25,06,30,06),unlit,"ordinary" REGION: (32,06,48,06),unlit,"ordinary" REGION: (50,06,56,08),lit,"ordinary" REGION: (40,08,46,08),unlit,"ordinary" REGION: (22,08,22,12),unlit,"ordinary" REGION: (24,08,38,12),unlit,"ordinary" REGION: (48,08,48,08),lit,"ordinary" REGION: (40,10,56,10),lit,"ordinary" REGION: (48,12,48,12),lit,"ordinary" REGION: (40,12,46,12),unlit,"ordinary" REGION: (50,12,56,14),lit,"ordinary" REGION: (22,14,23,14),unlit,"ordinary" REGION: (25,14,30,14),unlit,"ordinary" REGION: (32,14,48,14),unlit,"ordinary" # Stairs STAIR:(55,07),down # Portal arrival point BRANCH:(63,06,63,06),(0,0,0,0) # Doors DOOR:closed,(22,07) DOOR:closed,(38,07) DOOR:locked,(47,08) DOOR:locked,(23,10) DOOR:locked,(39,10) DOOR:locked,(57,10) DOOR:locked,(47,12) DOOR:closed,(22,13) DOOR:closed,(38,13) DOOR:locked,(24,14) DOOR:closed,(31,14) DOOR:locked,(49,14) # Lord Carnarvon MONSTER:'@',"Lord Carnarvon",(25,10) # The treasure of Lord Carnarvon OBJECT:'(',"chest",(25,10) # student guards for the audience chamber MONSTER:'@',"student",(26,09) MONSTER:'@',"student",(27,09) MONSTER:'@',"student",(28,09) MONSTER:'@',"student",(26,10) MONSTER:'@',"student",(28,10) MONSTER:'@',"student",(26,11) MONSTER:'@',"student",(27,11) MONSTER:'@',"student",(28,11) # city watch guards in the antechambers MONSTER:'@',"watchman",(50,06) MONSTER:'@',"watchman",(50,14) # Eels in the moat MONSTER:';',"giant eel",(20,10) MONSTER:';',"giant eel",(45,04) MONSTER:';',"giant eel",(33,16) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: 'S',random,(60,09) MONSTER: 'M',random,(60,10) MONSTER: 'S',random,(60,11) MONSTER: 'S',random,(60,12) MONSTER: 'M',random,(60,13) MONSTER: 'S',random,(61,10) MONSTER: 'S',random,(61,11) MONSTER: 'S',random,(61,12) MONSTER: 'S',random,(30,03) MONSTER: 'M',random,(20,17) MONSTER: 'S',random,(67,02) MONSTER: 'S',random,(10,19) # # The "locate" level for the quest. # # Here you have to find the Entrance to the Tomb of the Toltec Kings # to go further towards your assigned quest. # MAZE: "Arc-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ............................................................................ ........................-------------------------------..................... ........................|....|.S......................|..................... ........................|....|.|.|+------------------.|..................... ........................|....|.|.|.|.........|......|.|..................... ........................|....|.|.|.|.........|......|.|..................... ........................|---+-.|.|.|..---....+......|.|..................... ........................|....|.|.|.---|.|....|......|.|..................... ........................|....S.|.|.+..S.|--S-----S--|.|..................... ........................|....|.|.|.---|.|....|......+.|..................... ........................|---+-.|.|.|..---....|.------.|..................... ........................|....|.|.|.|.........|.|....+.|..................... ........................|....|.|.|.|.........|+|....|-|..................... ........................|....|.|.|------------+------.S..................... ........................|....|.S......................|..................... ........................-------------------------------..................... ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(25,04,28,07),lit,"temple" REGION:(25,09,28,11),unlit,"temple" REGION:(25,13,28,16),lit,"temple" REGION:(30,04,30,16),lit,"ordinary" REGION:(32,04,32,16),unlit,"ordinary" REGION:(33,04,53,04),unlit,"ordinary",unfilled,true REGION:(36,10,37,10),unlit,"ordinary" REGION:(39,09,39,11),unlit,"ordinary" REGION:(36,06,42,08),unlit,"ordinary",unfilled,true REGION:(36,12,42,14),unlit,"ordinary",unfilled,true REGION:(46,06,51,09),unlit,"ordinary" REGION:(46,11,49,11),unlit,"ordinary",unfilled,true REGION:(48,13,51,14),unlit,"ordinary" # Doors DOOR:closed,(31,04) DOOR:closed,(28,08) DOOR:locked,(29,10) DOOR:closed,(28,12) DOOR:closed,(31,16) DOOR:locked,(34,05) DOOR:locked,(35,10) DOOR:locked,(38,10) DOOR:closed,(43,10) DOOR:closed,(45,08) DOOR:locked,(46,14) DOOR:locked,(46,15) DOOR:locked,(49,10) DOOR:locked,(52,11) DOOR:closed,(52,13) DOOR:closed,(54,15) # Stairs STAIR:(03,17),up STAIR:(39,10),down # Altars - three types. All are unattended. ALTAR:(26,05),align[0],altar ALTAR:(26,10),align[1],altar ALTAR:(26,15),align[2],altar # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Treasure? ENGRAVING:random,engrave,"X marks the spot." ENGRAVING:random,engrave,"X marks the spot." ENGRAVING:random,engrave,"X marks the spot." ENGRAVING:random,engrave,"X marks the spot." # Random traps TRAP:"spiked pit",(24,02) TRAP:"spiked pit",(37,00) TRAP:"spiked pit",(23,05) TRAP:"spiked pit",(26,19) TRAP:"spiked pit",(55,10) TRAP:"spiked pit",(55,08) TRAP:"pit",(51,01) TRAP:"pit",(23,18) TRAP:"pit",(31,18) TRAP:"pit",(48,19) TRAP:"pit",(55,15) TRAP:"magic",(60,04) TRAP:"statue",(72,07) TRAP:"statue",random TRAP:"statue",random TRAP:"anti magic",(64,12) TRAP:"sleep gas",random TRAP:"sleep gas",random TRAP:"dart",random TRAP:"dart",random TRAP:"dart",random TRAP:"rolling boulder",(32,10) TRAP:"rolling boulder",(40,16) # Random monsters. MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'M',random,random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',random,random # # The "goal" level for the quest. # # Here you meet Minion of Huhetotl your nemesis monster. You have to # defeat Minion of Huhetotl in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Arc-goal", ' ' GEOMETRY:center,center MAP --------- |..|.|..| -----------|..S.S..|----------- |.|........|+-|.|-+|........|.| |.S........S..|.|..S........S.| |.|........|..|.|..|........|.| ------------------+------------------ |..|..........|.......|..........|..| |..|..........+.......|..........S..| |..S..........|.......+..........|..| |..|..........|.......|..........|..| ------------------+------------------ |.|........|..|.|..|........|.| |.S........S..|.|..S........S.| |.|........|+-|.|-+|........|.| -----------|..S.S..|----------- |..|.|..| --------- ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(35,02,36,03),unlit,"ordinary" REGION:(40,02,41,03),unlit,"ordinary" REGION:(24,04,24,06),unlit,"ordinary" REGION:(26,04,33,06),lit,"ordinary" REGION:(38,02,38,06),unlit,"ordinary" REGION:(43,04,50,06),lit,"ordinary" REGION:(52,04,52,06),unlit,"ordinary" REGION:(35,05,36,06),unlit,"ordinary" REGION:(40,05,41,06),unlit,"ordinary" REGION:(21,08,22,11),unlit,"ordinary" REGION:(24,08,33,11),lit,"ordinary" REGION:(35,08,41,11),unlit,"ordinary" REGION:(43,08,52,11),lit,"ordinary" REGION:(54,08,55,11),unlit,"ordinary" REGION:(24,13,24,15),unlit,"ordinary" REGION:(26,13,33,15),unlit,"ordinary" REGION:(35,13,36,14),unlit,"ordinary" REGION:(35,16,36,17),unlit,"ordinary" REGION:(38,13,38,17),unlit,"ordinary" REGION:(40,13,41,14),unlit,"ordinary" REGION:(40,16,41,17),unlit,"ordinary" REGION:(43,13,50,15),unlit,"temple" REGION:(52,13,52,15),unlit,"ordinary" # Stairs STAIR:(38,10),up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # The altar of Huhetotl. Unattended. ALTAR:(50,14),chaos,altar # Objects OBJECT:'(',"crystal ball",(50,14),blessed,5,"The Orb of Detection" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:"rolling boulder",(46,14) # Random monsters. MONSTER:'&',"Minion of Huhetotl",(50,14) MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'S',random,random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',"human mummy",random MONSTER:'M',random,random # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # LEVEL: "Arc-fila" # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'S', random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random MONSTER: 'S', random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'S', random, random ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random MONSTER: 'S', random, random MONSTER: 'M', "human mummy", random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'S', random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'S', random, random RANDOM_CORRIDORS LEVEL: "Arc-filb" # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'M', random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random MONSTER: 'M', random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'M', random, random ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random MONSTER: 'S', random, random MONSTER: 'M', "human mummy", random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'S', random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'S', random, random RANDOM_CORRIDORS nethack-3.4.3/dat/Barb.des0100644000000000000000000003141607764735040013771 0ustar rootroot# SCCS Id: @(#)Barb.des 3.4 1991/12/22 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Pelias, # and receive your quest assignment. # MAZE: "Bar-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ..................................PP........................................ ...................................PP....................................... ...................................PP....................................... ....................................PP...................................... ........--------------......-----....PPP.................................... ........|...S........|......+...|...PPP..................................... ........|----........|......|...|....PP..................................... ........|.\..........+......-----........................................... ........|----........|...............PP..................................... ........|...S........|...-----.......PPP.................................... ........--------------...+...|......PPPPP................................... .........................|...|.......PPP.................................... ...-----......-----......-----........PP.................................... ...|...+......|...+..--+--.............PP................................... ...|...|......|...|..|...|..............PP.................................. ...-----......-----..|...|.............PPPP................................. .....................-----............PP..PP................................ .....................................PP...PP................................ ....................................PP...PP................................. ....................................PP....PP................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(09,05,11,05),unlit,"ordinary" REGION:(09,07,11,07),lit,"ordinary" REGION:(09,09,11,09),unlit,"ordinary" REGION:(13,05,20,09),lit,"ordinary" REGION:(29,05,31,06),lit,"ordinary" REGION:(26,10,28,11),lit,"ordinary" REGION:(04,13,06,14),lit,"ordinary" REGION:(15,13,17,14),lit,"ordinary" REGION:(22,14,24,15),lit,"ordinary" # Stairs STAIR:(09,09),down # Portal arrival point BRANCH:(62,02,62,02),(0,0,0,0) # Doors DOOR:locked,(12,05) DOOR:locked,(12,09) DOOR:closed,(21,07) DOOR:open,(07,13) DOOR:open,(18,13) DOOR:open,(23,13) DOOR:open,(25,10) DOOR:open,(28,05) # Elder MONSTER:'@',"Pelias",(10,07) # The treasure of Pelias OBJECT:'(',"chest",(09,05) # chieftain guards for the audience chamber MONSTER:'@',"chieftain",(10,05) MONSTER:'@',"chieftain",(10,09) MONSTER:'@',"chieftain",(11,05) MONSTER:'@',"chieftain",(11,09) MONSTER:'@',"chieftain",(14,05) MONSTER:'@',"chieftain",(14,09) MONSTER:'@',"chieftain",(16,05) MONSTER:'@',"chieftain",(16,09) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # One trap to keep the ogres at bay. TRAP:"spiked pit",(37,07) # Eels in the river MONSTER:';',"giant eel",(36,01) MONSTER:';',"giant eel",(37,09) MONSTER:';',"giant eel",(39,15) # Monsters on siege duty. MONSTER:'O',"ogre",(40,08),hostile MONSTER:'O',"ogre",(41,06),hostile MONSTER:'O',"ogre",(41,07),hostile MONSTER:'O',"ogre",(41,08),hostile MONSTER:'O',"ogre",(41,09),hostile MONSTER:'O',"ogre",(41,10),hostile MONSTER:'O',"ogre",(42,06),hostile MONSTER:'O',"ogre",(42,07),hostile MONSTER:'O',"ogre",(42,08),hostile MONSTER:'O',"ogre",(42,09),hostile MONSTER:'O',"ogre",(42,10),hostile # # The "locate" level for the quest. # # Here you have to infiltrate the Duali Oasis to go # further towards your assigned quest. # MAZE: "Bar-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ..........PPP......................................... ...........PP.......................................... ....... ..........PP...........-----..........------------------ .......... ...........PP..........+...|..........|....S...........|.. ............ ..........PPP..........|...|..........|-----...........|... ............. ...........PPP.........-----..........+....+...........|... ............. ..........PPPPPPPPP...................+....+...........S................. ........PPPPPPPPPPPPP.........-----...|-----...........|................ ......PPPPPPPPPPPPPP..P.......+...|...|....S...........| ... .....PPPPPPP......P..PPPP.....|...|...------------------.. ... ....PPPPPPP.........PPPPPP....-----........................ ........ ...PPPPPPP..........PPPPPPP.................................. .......... ....PPPPPPP........PPPPPPP.................................... .......... .....PPPPP........PPPPPPP.........-----........................ ........ ......PPP..PPPPPPPPPPPP...........+...|......................... ..... ..........PPPPPPPPPPP.............|...|......................... .... ..........PPPPPPPPP...............-----......................... . ..............PPP................................................. ...............PP.................................................... ................PPP................................................... ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(24,03,26,04),unlit,"ordinary" REGION:(31,08,33,09),unlit,"ordinary" REGION:(35,14,37,15),unlit,"ordinary" REGION:(39,03,54,08),lit,"ordinary" REGION:(56,00,75,08),unlit,"ordinary" REGION:(64,09,75,16),unlit,"ordinary" # Doors DOOR:open,(23,03) DOOR:open,(30,08) DOOR:open,(34,14) DOOR:locked,(38,05) DOOR:locked,(38,06) DOOR:closed,(43,03) DOOR:closed,(43,05) DOOR:closed,(43,06) DOOR:closed,(43,08) DOOR:locked,(55,06) # Stairs STAIR:(05,02),up STAIR:(70,13),down # Objects OBJECT:random,random,(42,03) OBJECT:random,random,(42,03) OBJECT:random,random,(42,03) OBJECT:random,random,(41,03) OBJECT:random,random,(41,03) OBJECT:random,random,(41,03) OBJECT:random,random,(41,03) OBJECT:random,random,(41,08) OBJECT:random,random,(41,08) OBJECT:random,random,(42,08) OBJECT:random,random,(42,08) OBJECT:random,random,(42,08) OBJECT:random,random,(71,13) OBJECT:random,random,(71,13) OBJECT:random,random,(71,13) # Random traps TRAP:"spiked pit",(10,13) TRAP:"spiked pit",(21,07) TRAP:"spiked pit",(67,08) TRAP:"spiked pit",(68,09) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'O',"ogre",(12,09),hostile MONSTER:'O',"ogre",(18,11),hostile MONSTER:'O',"ogre",(45,05),hostile MONSTER:'O',"ogre",(45,06),hostile MONSTER:'O',"ogre",(47,05),hostile MONSTER:'O',"ogre",(46,05),hostile MONSTER:'O',"ogre",(56,03),hostile MONSTER:'O',"ogre",(56,04),hostile MONSTER:'O',"ogre",(56,05),hostile MONSTER:'O',"ogre",(56,06),hostile MONSTER:'O',"ogre",(57,03),hostile MONSTER:'O',"ogre",(57,04),hostile MONSTER:'O',"ogre",(57,05),hostile MONSTER:'O',"ogre",(57,06),hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',random,random,hostile MONSTER:'T',random,random,hostile MONSTER:'T',"rock troll",(46,06),hostile MONSTER:'T',"rock troll",(47,06),hostile MONSTER:'T',"rock troll",(56,07),hostile MONSTER:'T',"rock troll",(57,07),hostile MONSTER:'T',"rock troll",(70,13),hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',random,random,hostile # # The "goal" level for the quest. # # Here you meet Thoth Amon, your nemesis monster. You have to # defeat Thoth Amon in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Bar-goal", ' ' GEOMETRY:center,center MAP ............. .................. .... ......................... .... ....... .......................... ....... ...... ........................ ....... .. ...................................... .. .. ..................... .. .. .................. .. .. ..S...S.............. ................ .. ........ ... ......... .. ...... .. ... .... .. ... .. ...... ........ .... .. .................. ........ ...... ...... ...................... ...... .. .... .................. ........... .............. ........... ENDMAP # Dungeon Description REGION:(00,00,75,19),unlit,"ordinary" # Secret doors DOOR:locked,(22,09) DOOR:locked,(26,09) # Stairs STAIR:(36,05),up # The altar. Unattended. ALTAR:(63,04),noncoaligned,altar NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:'*',"luckstone",(63,04),blessed,0,"The Heart of Ahriman" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'@',"Thoth Amon",(63,04),hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',"ogre",random,hostile MONSTER:'O',random,random,hostile MONSTER:'O',random,random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',"rock troll",random,hostile MONSTER:'T',random,random,hostile WALLIFY # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Bar-fila" , ' ' INIT_MAP: '.' , '.' , true , true , unlit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', random, random, hostile MONSTER: 'T', "rock troll", random, hostile MAZE: "Bar-filb" , ' ' INIT_MAP: '.' , ' ' , true , true , unlit , true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', "ogre", random, hostile MONSTER: 'O', random , random, hostile MONSTER: 'T', "rock troll", random, hostile MONSTER: 'T', "rock troll", random, hostile MONSTER: 'T', "rock troll", random, hostile MONSTER: 'T', random , random, hostile nethack-3.4.3/dat/Caveman.des0100644000000000000000000002672207764735040014501 0ustar rootroot# SCCS Id: @(#)Caveman.des 3.4 1995/10/07 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Shaman Karnov # and receive your quest assignment. # MAZE: "Cav-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ...... .......................... ... .... ...... ...... .......................... ........ .... ..... ..BB ............................. ......... .... .. .. ...................... ....... .. .... .. .. .................... .. ....... .. ... .. S BB ..... ....... .... .... .. ... . .. ........ .. .. .. ... .. ...... .. ............ .. ... . .... .. ........ .. ........... ... .. .. ............. ................... ..... ..... ............................... ........... .....B................ ... ... ..... . .......... .... . ... .......... ... ... .. ............. .. ................... .... BB .. ......... BB ... .......... .. ... ... ...... ..... B ........ .. .. .... ... .......... .......... ..... ... ..... ........ .. ... . ..... .... .. ... .. ENDMAP # Dungeon Description REGION:(00,00,75,19),unlit,"ordinary" REGION:(13,01,40,05),lit,"temple",unfilled,true # The occupied rooms. REGION:(02,01,08,03),lit,"ordinary",unfilled,true REGION:(01,11,06,14),lit,"ordinary",unfilled,true REGION:(13,08,18,10),lit,"ordinary",unfilled,true REGION:(05,17,14,18),lit,"ordinary",unfilled,true REGION:(17,16,23,18),lit,"ordinary",unfilled,true REGION:(35,16,44,18),lit,"ordinary",unfilled,true # Stairs STAIR:(02,03),down # Portal arrival point BRANCH:(71,09,71,09),(0,0,0,0) # Doors DOOR:locked,(19,06) # The temple altar (this will force a priest(ess) to be created) ALTAR:(36,02),coaligned,shrine # Shaman Karnov MONSTER:'@',"Shaman Karnov",(35,02) # The treasure of Shaman Karnov OBJECT:'(',"chest",(34,02) # neanderthal guards for the audience chamber MONSTER:'@',"neanderthal",(20,03) MONSTER:'@',"neanderthal",(20,02) MONSTER:'@',"neanderthal",(20,01) MONSTER:'@',"neanderthal",(21,03) MONSTER:'@',"neanderthal",(21,02) MONSTER:'@',"neanderthal",(21,01) MONSTER:'@',"neanderthal",(22,01) MONSTER:'@',"neanderthal",(26,09) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:"pit",(47,11) TRAP:"pit",(57,10) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty (in the outer caves). MONSTER: 'h',"bugbear",(47,02),hostile MONSTER: 'h',"bugbear",(48,03),hostile MONSTER: 'h',"bugbear",(49,04),hostile MONSTER: 'h',"bugbear",(67,03),hostile MONSTER: 'h',"bugbear",(69,04),hostile MONSTER: 'h',"bugbear",(51,13),hostile MONSTER: 'h',"bugbear",(53,14),hostile MONSTER: 'h',"bugbear",(55,15),hostile MONSTER: 'h',"bugbear",(63,10),hostile MONSTER: 'h',"bugbear",(65,09),hostile MONSTER: 'h',"bugbear",(67,10),hostile MONSTER: 'h',"bugbear",(69,11),hostile WALLIFY # # The "locate" level for the quest. # # Here you have to find the lair of Tiamat to go # further towards your assigned quest. # MAZE: "Cav-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ............. ........... ............... ............. ............. ............... .......... ........... ............. ............... ... ... .................. ... .......... ... .................. ... ............ BBB................... ... .......... ...................... ..... .. .....B........................ .... ............... . ........B.......................... ...... .. .............S.............. .................. .... .. ........... ............... .. ... .................... .... BB................... .. .. .. ............... .. ....... .... ..... .... .. ....... S ............ ....... .. ....... ..... ... .... ....... ..... ...... ....... ENDMAP # Dungeon Description REGION:(00,00,75,19),unlit,"ordinary" REGION:(52,06,73,15),lit,"ordinary",unfilled,true # Doors DOOR:locked,(28,11) # Stairs STAIR:(04,03),up STAIR:(73,10),down # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'h',"bugbear",(02,10),hostile MONSTER:'h',"bugbear",(03,11),hostile MONSTER:'h',"bugbear",(04,12),hostile MONSTER:'h',"bugbear",(02,11),hostile MONSTER:'h',"bugbear",(16,16),hostile MONSTER:'h',"bugbear",(17,17),hostile MONSTER:'h',"bugbear",(18,18),hostile MONSTER:'h',"bugbear",(19,16),hostile MONSTER:'h',"bugbear",(30,06),hostile MONSTER:'h',"bugbear",(31,07),hostile MONSTER:'h',"bugbear",(32,08),hostile MONSTER:'h',"bugbear",(33,06),hostile MONSTER:'h',"bugbear",(34,07),hostile MONSTER:'h',"bugbear",random,hostile MONSTER:'h',"bugbear",random,hostile MONSTER:'h',"bugbear",random,hostile MONSTER:'h',"bugbear",random,hostile MONSTER:'h',random,random,hostile MONSTER:'H',random,random,hostile MONSTER:'H',"hill giant",(03,12),hostile MONSTER:'H',"hill giant",(20,17),hostile MONSTER:'H',"hill giant",(35,08),hostile MONSTER:'H',"hill giant",random,hostile MONSTER:'H',"hill giant",random,hostile MONSTER:'H',"hill giant",random,hostile MONSTER:'H',"hill giant",random,hostile MONSTER:'H',random,random,hostile WALLIFY # # The "goal" level for the quest. # # Here you meet Tiamat your nemesis monster. You have to # defeat Tiamat in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Cav-goal", ' ' GEOMETRY:center,center MAP ..................... ....................... ......................... ........................... ............................. ............................... ................................. ................................... ..................................... ....................................... ..................................... ................................... ................................. ............................... ............................. ........................... ......................... ....................... ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # Stairs STAIR:random,up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:')',"mace",(23,10),blessed,0,"The Sceptre of Might" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # monsters. MONSTER:'D',"Chromatic Dragon",(23,10),asleep MONSTER:'F',"shrieker",(26,13) MONSTER:'F',"shrieker",(25,8) MONSTER:'F',"shrieker",(45,11) WALLIFY # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Cav-fila" , ' ' INIT_MAP: '.' , ' ' , true , true , random , true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', random, random, hostile MONSTER: 'H', "hill giant", random, hostile MAZE: "Cav-filb" , ' ' INIT_MAP: '.' , ' ' , true , true , random , true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', "bugbear", random, hostile MONSTER: 'h', random, random, hostile MONSTER: 'h', random, random, hostile MONSTER: 'H', "hill giant", random, hostile MONSTER: 'H', "hill giant", random, hostile nethack-3.4.3/dat/Healer.des0100644000000000000000000002621507764735040014324 0ustar rootroot# SCCS Id: @(#)Healer.des 3.4 1995/04/16 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991, 1993 by M. Stephenson, P. Winner # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Hippocrates # and receive your quest assignment. # MAZE: "Hea-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP PPPP........PPPP.....PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP.P..PPPPP......PPPPPPPP PPP..........PPPP...PPPPP.........................PPPP..PPPPP........PPPPPPP PP............PPPPPPPP..............................PPP...PPPP......PPPPPPPP P.....PPPPPPPPPPPPPPP................................PPPPPPPPPPPPPPPPPPPPPPP PPPP....PPPPPPPPPPPP...................................PPPPP.PPPPPPPPPPPPPPP PPPP........PPPPP.........-----------------------........PP...PPPPPPP.....PP PPP............PPPPP....--|.|......S..........S.|--.....PPPP.PPPPPPP.......P PPPP..........PPPPP.....|.S.|......-----------|S|.|......PPPPPP.PPP.......PP PPPPPP......PPPPPP......|.|.|......|...|......|.|.|.....PPPPPP...PP.......PP PPPPPPPPPPPPPPPPPPP.....+.|.|......S.\.S......|.|.+......PPPPPP.PPPP.......P PPP...PPPPP...PPPP......|.|.|......|...|......|.|.|.......PPPPPPPPPPP.....PP PP.....PPP.....PPP......|.|S|-----------......|.S.|......PPPPPPPPPPPPPPPPPPP PPP..PPPPP...PPPP.......--|.S..........S......|.|--.....PPPPPPPPP....PPPPPPP PPPPPPPPPPPPPPPP..........-----------------------..........PPPPP..........PP PPPPPPPPPPPPPPPPP........................................PPPPPP............P PPP.............PPPP...................................PPP..PPPP..........PP PP...............PPPPP................................PPPP...PPPP........PPP PPP.............PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP....PPPPPP PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # Stairs STAIR:(37,9),down # Portal arrival point BRANCH:(04,12,04,12),(0,0,0,0) # altar for the Temple ALTAR:(32,09),neutral,altar # Doors DOOR:locked,(24,10) DOOR:closed,(26,08) DOOR:closed,(27,12) DOOR:locked,(28,13) DOOR:closed,(35,07) DOOR:locked,(35,10) DOOR:locked,(39,10) DOOR:closed,(39,13) DOOR:locked,(46,07) DOOR:closed,(47,08) DOOR:closed,(48,12) DOOR:locked,(50,10) # Hippocrates MONSTER:'@',"Hippocrates",(37,10) # The treasure of Hippocrates OBJECT:'(',"chest",(37,10) # intern guards for the audience chamber MONSTER:'@',"attendant",(29,08) MONSTER:'@',"attendant",(29,09) MONSTER:'@',"attendant",(29,10) MONSTER:'@',"attendant",(29,11) MONSTER:'@',"attendant",(40,09) MONSTER:'@',"attendant",(40,10) MONSTER:'@',"attendant",(40,11) MONSTER:'@',"attendant",(40,13) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: 'r',"rabid rat",random MONSTER: ';',"giant eel",random MONSTER: ';',"shark",random MONSTER: ';', random, random MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile # # The "locate" level for the quest. # # Here you have to find the Temple of Coeus to go # further towards your assigned quest. # MAZE: "Hea-loca",' ' FLAGS: hardfloor # INIT_MAP: '.' , 'P', true , true , lit , false GEOMETRY:center,center MAP PPPPPPPPPPPPP.......PPPPPPPPPPP PPPPPPPP...............PPPPPPPP PPPP.....-------------...PPPPPP PPPPP....|.S.........|....PPPPP PPP......+.|.........|...PPPPPP PPP......+.|.........|..PPPPPPP PPPP.....|.S.........|..PPPPPPP PPPPP....-------------....PPPPP PPPPPPPP...............PPPPPPPP PPPPPPPPPPP........PPPPPPPPPPPP ENDMAP # Dungeon Description REGION:(00,00,30,09),lit,"ordinary" REGION:(12,03,20,06),lit,"temple" # Doors DOOR:closed,(09,04) DOOR:closed,(09,05) DOOR:locked,(11,03) DOOR:locked,(11,06) # Stairs STAIR:(04,04),up STAIR:(20,06),down # Non diggable walls NON_DIGGABLE:(11,02,21,07) # Altar in the temple. ALTAR:(13,05), chaos, shrine # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',random,random,hostile MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"kraken",random MONSTER:';',"shark",random MONSTER:';',"shark",random MONSTER:';',random, random,hostile MONSTER:';',random, random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile # # The "goal" level for the quest. # # Here you meet Cyclops your nemesis monster. You have to # defeat Cyclops in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Hea-goal", 'P' # INIT_MAP: '.' , 'P' , false , true , lit , false GEOMETRY:center,center MAP .P....................................PP. PP.......PPPPPPP....PPPPPPP....PPPP...PP. ...PPPPPPP....PPPPPPP.....PPPPPP..PPP...P ...PP..............................PPP... ..PP..............................PP..... ..PP..............................PPP.... ..PPP..............................PP.... .PPP..............................PPPP... ...PP............................PPP...PP ..PPPP...PPPPP..PPPP...PPPPP.....PP...PP. P....PPPPP...PPPP..PPPPP...PPPPPPP...PP.. PPP..................................PPP. ENDMAP # Dungeon Description REGION:(00,00,40,11),lit,"ordinary" # Stairs STAIR:(39,10),up # Non diggable walls NON_DIGGABLE:(00,00,40,11) # Objects OBJECT:')',"quarterstaff",(20,06),blessed,0,"The Staff of Aesculapius" OBJECT:'/',"lightning",(20,06) OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'H',"Cyclops",(20,06),hostile MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',"rabid rat",random MONSTER:'r',random,random,hostile MONSTER:'r',random,random,hostile MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"shark",random MONSTER:';',"shark",random MONSTER:';',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Hea-fila" , 'P' INIT_MAP: '.' , 'P' , false , true , lit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'r', "rabid rat", random MONSTER: 'r', random, random,hostile MONSTER: 'r', random, random,hostile MONSTER: ';', "giant eel", random MONSTER: ';', "giant eel", random MONSTER: ';', "electric eel", random MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random MAZE: "Hea-filb" , 'P' INIT_MAP: '.' , 'P' , false , true , lit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'r', "rabid rat", random MONSTER: 'r', "rabid rat", random MONSTER: 'r', random, random,hostile MONSTER: 'r', random, random,hostile MONSTER: ';', "giant eel", random MONSTER: ';', "giant eel", random MONSTER: ';', "giant eel", random MONSTER: ';', "giant eel", random MONSTER: ';', "giant eel", random MONSTER: ';', "electric eel", random MONSTER: ';', "electric eel", random MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'D',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile MONSTER: 'S',random,random,hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random nethack-3.4.3/dat/Knight.des0100644000000000000000000003057607764735040014355 0ustar rootroot# SCCS Id: @(#)Knight.des 3.4 1995/04/16 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991,92 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, King Arthur # and receive your quest assignment. # MAZE: "Kni-strt",'.' FLAGS: noteleport,hardfloor # This is a kludge to init the level as a lit field. INIT_MAP: '.' , '.' , false , false , lit , false GEOMETRY:center,center MAP .................................................. .-----......................................-----. .|...|......................................|...|. .--|+-------------------++-------------------+|--. ...|...................+..+...................|... ...|.|-----------------|++|-----------------|.|... ...|.|.................|..|.........|.......|.|... ...|.|...\.............+..+.........|.......|.|... ...|.|.................+..+.........+.......|.|... ...|.|.................|..|.........|.......|.|... ...|.|--------------------------------------|.|... ...|..........................................|... .--|+----------------------------------------+|--. .|...|......................................|...|. .-----......................................-----. .................................................. ENDMAP # Dungeon Description REGION:(00,00,49,15),lit,"ordinary" REGION:(04,04,45,11),unlit,"ordinary" REGION:(06,06,22,09),lit,"throne" , unfilled REGION:(27,06,43,09),lit,"ordinary" # Portal arrival point BRANCH:(20,14,20,14),(0,0,0,0) # Stairs STAIR:(40,7),down # Doors # Outside Doors DOOR:locked,(24,03) DOOR:locked,(25,03) # Inside Doors DOOR:closed,(23,04) DOOR:closed,(26,04) DOOR:locked,(24,05) DOOR:locked,(25,05) DOOR:closed,(23,07) DOOR:closed,(26,07) DOOR:closed,(23,08) DOOR:closed,(26,08) DOOR:closed,(36,08) # Watchroom Doors DOOR:closed,(04,03) DOOR:closed,(45,03) DOOR:closed,(04,12) DOOR:closed,(45,12) # King Arthur MONSTER:'@',"King Arthur",(09,07) # The treasure of King Arthur OBJECT:'(',"chest",(09,07) # knight guards for the watchrooms MONSTER:'@',"knight",(04,02),peaceful MONSTER:'@',"knight",(04,13),peaceful MONSTER:'@',"knight",(45,02),peaceful MONSTER:'@',"knight",(45,13),peaceful # page guards for the audience chamber MONSTER:'@',"page",(16,06) MONSTER:'@',"page",(18,06) MONSTER:'@',"page",(20,06) MONSTER:'@',"page",(16,09) MONSTER:'@',"page",(18,09) MONSTER:'@',"page",(20,09) # Non diggable walls NON_DIGGABLE:(00,00,49,15) # Random traps TRAP:"sleep gas",(24,04) TRAP:"sleep gas",(25,04) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: 'i',"quasit",(14,00),hostile MONSTER: 'i',"quasit",(16,00),hostile MONSTER: 'i',"quasit",(18,00),hostile MONSTER: 'i',"quasit",(20,00),hostile MONSTER: 'i',"quasit",(22,00),hostile MONSTER: 'i',"quasit",(24,00),hostile MONSTER: 'i',"quasit",(26,00),hostile MONSTER: 'i',"quasit",(28,00),hostile MONSTER: 'i',"quasit",(30,00),hostile MONSTER: 'i',"quasit",(32,00),hostile MONSTER: 'i',"quasit",(34,00),hostile MONSTER: 'i',"quasit",(36,00),hostile # # The "locate" level for the quest. # # Here you have to find your way to the Isle of Glass to go # further towards your assigned quest. # MAZE: "Kni-loca",' ' FLAGS: hardfloor INIT_MAP: '.' , 'P' , false , true , lit , false GEOMETRY:center,center MAP ...PPP.........PPPP..............PPPP... .PPPP...........PP................PPPP.. PP.................................PPP.. ....................................PPP. .....................................PP. .......................................P ........................................ PP...................................PPP .PPP...............................PPP.. ..PP.............................PPPP... ..PPP...........................PPPPPP.. ....PPPP.........PPP.........PPPP..PP... ENDMAP # Dungeon Description # The Isle of Glass is a Tor rising out of the swamps surrounding it. REGION:(00,00,39,11),lit,"ordinary" # The top area of the Tor is a holy site. REGION:(09,02,27,09),lit,"temple" # Stairs STAIR:(38,0),up STAIR:(18,05),down # The altar atop the Tor and its attendant (creating altar makes the priest). ALTAR:(17,05),neutral,shrine # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps # All of the avenues are guarded by magic except for the East. # South TRAP:"magic",(08,11) TRAP:"magic",(09,11) TRAP:"magic",(10,11) TRAP:"magic",(11,11) TRAP:"magic",(12,11) TRAP:"magic",(13,11) TRAP:"magic",(14,11) TRAP:"magic",(15,11) TRAP:"magic",(16,11) TRAP:"magic",(20,11) TRAP:"magic",(21,11) TRAP:"magic",(22,11) TRAP:"magic",(23,11) TRAP:"magic",(24,11) TRAP:"magic",(25,11) TRAP:"magic",(26,11) TRAP:"magic",(27,11) TRAP:"magic",(28,11) # West TRAP:"magic",(00,03) TRAP:"magic",(00,04) TRAP:"magic",(00,05) TRAP:"magic",(00,06) # North TRAP:"magic",(06,00) TRAP:"magic",(07,00) TRAP:"magic",(08,00) TRAP:"magic",(09,00) TRAP:"magic",(10,00) TRAP:"magic",(11,00) TRAP:"magic",(12,00) TRAP:"magic",(13,00) TRAP:"magic",(14,00) TRAP:"magic",(19,00) TRAP:"magic",(20,00) TRAP:"magic",(21,00) TRAP:"magic",(22,00) TRAP:"magic",(23,00) TRAP:"magic",(24,00) TRAP:"magic",(25,00) TRAP:"magic",(26,00) TRAP:"magic",(27,00) TRAP:"magic",(28,00) TRAP:"magic",(29,00) TRAP:"magic",(30,00) TRAP:"magic",(31,00) TRAP:"magic",(32,00) # Even so, there are magic "sinkholes" around. TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"anti magic",random # Random monsters. MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',random,random,hostile MONSTER:'j',random,random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',random,random,hostile # # The "goal" level for the quest. # # Here you meet Ixoth your nemesis monster. You have to # defeat Ixoth in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Kni-goal", ' ' GEOMETRY:center,center MAP ....PPPP..PPP.. .PPPPP...PP.. .......... ................................. ..PPPPP...P.. ........... ................................... ..PPP....... ........... ...................................... ...PPP....... ......... ............... ..................... ........... ............ ............ ...................... ............ ............. ....... ..................... .............................. ......................... ............................... .................................. ............................. .................................... ......... ...................................................... .....PP... ..................................................... .....PPP.... .................................................... ......PPP.... .............. .................................... .......PPP.... ............. ..................................... ........PP... ............ ...................................... ...PPP........ .......... .................................. ..PPPPP........ .......... .............................. ....PPPPP...... ......... .......................... .......PPPP... ENDMAP # Dungeon Description REGION:(00,00,14,19),lit,"ordinary" REGION:(15,00,75,19),unlit,"ordinary" # Stairs STAIR:(03,08),up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:'(',"mirror",(50,06),blessed,0,"The Magic Mirror of Merlin" OBJECT:random,random,(33,01) OBJECT:random,random,(33,02) OBJECT:random,random,(33,03) OBJECT:random,random,(33,04) OBJECT:random,random,(33,05) OBJECT:random,random,(34,01) OBJECT:random,random,(34,02) OBJECT:random,random,(34,03) OBJECT:random,random,(34,04) OBJECT:random,random,(34,05) OBJECT:random,random,(35,01) OBJECT:random,random,(35,02) OBJECT:random,random,(35,03) OBJECT:random,random,(35,04) OBJECT:random,random,(35,05) OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:"spiked pit",(13,07) TRAP:"spiked pit",(12,08) TRAP:"spiked pit",(12,09) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'D',"Ixoth",(50,06),hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',"quasit",random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',"ochre jelly",random,hostile MONSTER:'j',random,random,hostile # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Kni-fila" , '.' INIT_MAP: '.' , 'P' , false , true , lit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'i', "quasit", random, hostile MONSTER: 'i', "quasit", random, hostile MONSTER: 'i', "quasit", random, hostile MONSTER: 'i', "quasit", random, hostile MONSTER: 'i', random, random, hostile MONSTER: 'j', "ochre jelly", random, hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random MAZE: "Kni-filb" , '.' INIT_MAP: '.' , 'P' , false , true , lit , false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'i', "quasit", random, hostile MONSTER: 'i', "quasit", random, hostile MONSTER: 'i', "quasit", random, hostile MONSTER: 'i', "quasit", random, hostile MONSTER: 'i', random, random, hostile MONSTER: 'j', "ochre jelly", random, hostile MONSTER: 'j', "ochre jelly", random, hostile MONSTER: 'j', "ochre jelly", random, hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random nethack-3.4.3/dat/Monk.des0100644000000000000000000002616507764735040014034 0ustar rootroot# SCCS Id: @(#)Monk.des 3.4 2002/04/08 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991-2 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, the Grand Master # and receive your quest assignment. # MAZE: "Mon-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ............................................................................ ....................------------------------------------.................... ....................|................|.....|.....|.....|.................... ....................|..------------..|--+-----+-----+--|.................... ....................|..|..........|..|.................|.................... ....................|..|..........|..|+---+---+-----+--|.................... ..................---..|..........|......|...|...|.....|.................... ..................+....|..........+......|...|...|.....|.................... ..................+....|..........+......|...|...|.....|.................... ..................---..|..........|......|...|...|.....|.................... ....................|..|..........|..|+-----+---+---+--|.................... ....................|..|..........|..|.................|.................... ....................|..------------..|--+-----+-----+--|.................... ....................|................|.....|.....|.....|.................... ....................------------------------------------.................... ............................................................................ ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(24,06,33,13),lit,"temple" # Portal arrival point BRANCH:(05,04,05,04),(0,0,0,0) # Stairs STAIR:(52,09),down # Doors DOOR:locked,(18,09) DOOR:locked,(18,10) DOOR:closed,(34,09) DOOR:closed,(34,10) DOOR:closed,(40,05) DOOR:closed,(46,05) DOOR:closed,(52,05) DOOR:locked,(38,07) DOOR:closed,(42,07) DOOR:closed,(46,07) DOOR:closed,(52,07) DOOR:locked,(38,12) DOOR:closed,(44,12) DOOR:closed,(48,12) DOOR:closed,(52,12) DOOR:closed,(40,14) DOOR:closed,(46,14) DOOR:closed,(52,14) # Unattended Altar - unaligned due to conflict - player must align it. ALTAR:(28,09),noalign,altar # The Grand Master MONSTER:'@',"Grand Master",(28,10) # No treasure chest! # guards for the audience chamber MONSTER:'@',"abbot",(32,07) MONSTER:'@',"abbot",(32,08) MONSTER:'@',"abbot",(32,11) MONSTER:'@',"abbot",(32,12) MONSTER:'@',"abbot",(33,07) MONSTER:'@',"abbot",(33,08) MONSTER:'@',"abbot",(33,11) MONSTER:'@',"abbot",(33,12) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:"dart",(20,09) TRAP:"dart",(20,10) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: 'E',"earth elemental",(37,01) MONSTER: 'E',"earth elemental",(37,18) MONSTER: 'E',"earth elemental",(03,03) MONSTER: 'E',"earth elemental",(65,04) MONSTER: 'E',"earth elemental",(12,11) MONSTER: 'E',"earth elemental",(60,12) MONSTER: 'E',"earth elemental",(14,08) MONSTER: 'E',"earth elemental",(55,00) MONSTER: 'X',"xorn",(18,18) MONSTER: 'X',"xorn",(59,10) MONSTER: 'X',"xorn",(13,09) MONSTER: 'X',"xorn",(01,17) # # The "locate" level for the quest. # # Here you have to locate the Monastery of the Earth-Lord to # go further towards your assigned quest. # MAZE: "Mon-loca",' ' GEOMETRY:center,center # 1 2 3 4 5 6 7 #123456789012345678901234567890123456789012345678901234567890123456789012345 MAP ---------------------------------------------------- -------- ---.................................................- --.....| ---...--------........------........................--- ---...| ---.....- --.......- ----..................---- --.-- ---.....---- --------- --..................-- --..| ---...----- ----.----.....----.....--- --..|| ----..---- -----..--- |...--- |.......--- --...| |...--- ----....--- |.--- |.........-- --...|| |...- ----.....--- ---- |..........---....| |...---- ----......--- | |...|.......-....|| |......----- ---.........- | -----...|............| |..........----- ----...........--- -------......||...........|| |..............-----................--- |............|||..........| |-S----...............................--- |...........|| |.........|| |.....|..............------.............-----..........|| ||........| |.....|.............-- ---.........................|| |.......|| |.....|.............- ---.....................--| ||......| |---S--------.......---- --.................---- |.....|| |...........|..........--------..............----- ||....| |...........|............................----- |....| ------------------------------------------ ------ ENDMAP # Random Monsters RANDOM_MONSTERS: 'E', 'X' # Dungeon Description REGION:(00,00,75,20),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,75,20) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random # # The "goal" level for the quest. # # Here you meet Master Kaen, your nemesis monster. You have to # defeat Master Kaen in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Mon-goal", ' ' INIT_MAP: 'L' , '.' , false , false , unlit , false GEOMETRY:center,center MAP .L......L.LLL.......LL.... .LLL.......L......LL...... LL.LL.............L.LL.... .......................... ......................LL.. ......................LLL. LL........................ .LL....................... .LL................LL.L... ..LL.....L.LL.......LLL... .........LLL.........L.... ENDMAP # Dungeon Description RANDOM_PLACES:(14,04),(13,07) REGION:(00,00,25,10),unlit,"ordinary" # Stairs STAIR:(20,05),up # Objects OBJECT:'(',"lenses",place[0],blessed,0,"The Eyes of the Overworld" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'@',"Master Kaen",place[0] ALTAR:place[0],noalign,altar MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'E',"earth elemental",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random MONSTER: 'X',"xorn",random # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "fila" is the upper filler, between the # start and locate levels, and "filb" the lower between the locate # and goal levels. # LEVEL: "Mon-fila" # Random Monsters RANDOM_MONSTERS: 'E', 'X' # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'E', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random MONSTER: 'E', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'X', "xorn", random MONSTER: 'E', "earth elemental", random ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random MONSTER: 'E', random, random, hostile MONSTER: 'E', "earth elemental", random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'X', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'E', "earth elemental", random RANDOM_CORRIDORS LEVEL: "Mon-filb" # Random Monsters RANDOM_MONSTERS: 'E', 'X' # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'X', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random MONSTER: 'X', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'E', random, random, hostile ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random MONSTER: 'E', random, random, hostile MONSTER: 'E', "earth elemental", random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'X', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'E', "earth elemental", random RANDOM_CORRIDORS nethack-3.4.3/dat/Priest.des0100644000000000000000000002355007764735040014371 0ustar rootroot# SCCS Id: @(#)Priest.des 3.4 2002/04/08 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991-2 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, High Priest # and receive your quest assignment. # MAZE: "Pri-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ............................................................................ ....................------------------------------------.................... ....................|................|.....|.....|.....|.................... ....................|..------------..|--+-----+-----+--|.................... ....................|..|..........|..|.................|.................... ....................|..|..........|..|+---+---+-----+--|.................... ..................---..|..........|......|...|...|.....|.................... ..................+....|..........+......|...|...|.....|.................... ..................+....|..........+......|...|...|.....|.................... ..................---..|..........|......|...|...|.....|.................... ....................|..|..........|..|+-----+---+---+--|.................... ....................|..|..........|..|.................|.................... ....................|..------------..|--+-----+-----+--|.................... ....................|................|.....|.....|.....|.................... ....................------------------------------------.................... ............................................................................ ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(24,06,33,13),lit,"temple" # Portal arrival point BRANCH:(05,04,05,04),(0,0,0,0) # Stairs STAIR:(52,09),down # Doors DOOR:locked,(18,09) DOOR:locked,(18,10) DOOR:closed,(34,09) DOOR:closed,(34,10) DOOR:closed,(40,05) DOOR:closed,(46,05) DOOR:closed,(52,05) DOOR:locked,(38,07) DOOR:closed,(42,07) DOOR:closed,(46,07) DOOR:closed,(52,07) DOOR:locked,(38,12) DOOR:closed,(44,12) DOOR:closed,(48,12) DOOR:closed,(52,12) DOOR:closed,(40,14) DOOR:closed,(46,14) DOOR:closed,(52,14) # Unattended Altar - unaligned due to conflict - player must align it. ALTAR:(28,09),noalign,altar # High Priest MONSTER:'@',"Arch Priest",(28,10) # The treasure of High Priest OBJECT:'(',"chest",(27,10) # knight guards for the audience chamber MONSTER:'@',"acolyte",(32,07) MONSTER:'@',"acolyte",(32,08) MONSTER:'@',"acolyte",(32,11) MONSTER:'@',"acolyte",(32,12) MONSTER:'@',"acolyte",(33,07) MONSTER:'@',"acolyte",(33,08) MONSTER:'@',"acolyte",(33,11) MONSTER:'@',"acolyte",(33,12) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:"dart",(20,09) TRAP:"dart",(20,10) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: 'Z',"human zombie",(37,01) MONSTER: 'Z',"human zombie",(37,18) MONSTER: 'Z',"human zombie",(03,03) MONSTER: 'Z',"human zombie",(65,04) MONSTER: 'Z',"human zombie",(12,11) MONSTER: 'Z',"human zombie",(60,12) MONSTER: 'Z',"human zombie",(14,08) MONSTER: 'Z',"human zombie",(55,00) MONSTER: 'Z',"human zombie",(18,18) MONSTER: 'Z',"human zombie",(59,10) MONSTER: 'Z',"human zombie",(13,09) MONSTER: 'Z',"human zombie",(01,17) # # The "locate" level for the quest. # # Here you have to locate the Temple of Nalzok to go # further towards your assigned quest. # MAZE: "Pri-loca",' ' FLAGS: hardfloor # This is a kludge to init the level as a lit field. INIT_MAP: '.' , '.' , false , false , lit , false GEOMETRY:center,center MAP ........................................ ........................................ ..........----------+----------......... ..........|........|.|........|......... ..........|........|.|........|......... ..........|----.----.----.----|......... ..........+...................+......... ..........+...................+......... ..........|----.----.----.----|......... ..........|........|.|........|......... ..........|........|.|........|......... ..........----------+----------......... ........................................ ........................................ ENDMAP # Dungeon Description REGION:(00,00,09,13),unlit,"morgue" REGION:(09,00,30,01),unlit,"morgue" REGION:(09,12,30,13),unlit,"morgue" REGION:(31,00,39,13),unlit,"morgue" REGION:(11,03,29,10),lit,"temple",filled,true # The altar inside the temple ALTAR:(20,07),noalign,shrine MONSTER:'@',"aligned priest",(20,07),noalign,hostile # Doors DOOR:locked,(10,06) DOOR:locked,(10,07) DOOR:locked,(20,02) DOOR:locked,(20,11) DOOR:locked,(30,06) DOOR:locked,(30,07) # Stairs # Note: The up stairs are *intentionally* off of the map. STAIR:(43,05),up STAIR:(20,06),down # Non diggable walls NON_DIGGABLE:(10,02,30,13) # Objects (inside the antechambers). OBJECT:random,random,(14,03) OBJECT:random,random,(15,03) OBJECT:random,random,(16,03) OBJECT:random,random,(14,10) OBJECT:random,random,(15,10) OBJECT:random,random,(16,10) OBJECT:random,random,(17,10) OBJECT:random,random,(24,03) OBJECT:random,random,(25,03) OBJECT:random,random,(26,03) OBJECT:random,random,(27,03) OBJECT:random,random,(24,10) OBJECT:random,random,(25,10) OBJECT:random,random,(26,10) OBJECT:random,random,(27,10) # Random traps TRAP:random,(15,04) TRAP:random,(25,04) TRAP:random,(15,09) TRAP:random,(25,09) TRAP:random,random TRAP:random,random # No random monsters - the morgue generation will put them in. # # The "goal" level for the quest. # # Here you meet Nalzok your nemesis monster. You have to # defeat Nalzok in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Pri-goal", ' ' INIT_MAP: 'L' , '.' , false , false , unlit , false GEOMETRY:center,center MAP .L......L.LLL.......LL.... .LLL.......L......LL...... LL.LL.............L.LL.... .......................... ......................LL.. ......................LLL. LL........................ .LL....................... .LL................LL.L... ..LL.....L.LL.......LLL... .........LLL.........L.... ENDMAP # Dungeon Description RANDOM_PLACES:(14,04),(13,07) REGION:(00,00,25,10),unlit,"ordinary" # Stairs STAIR:(20,05),up # Objects OBJECT:'[',"helm of brilliance",place[0],blessed,0,"The Mitre of Holiness" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'&',"Nalzok",place[0] MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',random,random MONSTER:'Z',random,random MONSTER:'W',"wraith",random MONSTER:'W',"wraith",random MONSTER:'W',"wraith",random MONSTER:'W',"wraith",random MONSTER:'W',"wraith",random MONSTER:'W',"wraith",random MONSTER:'W',"wraith",random MONSTER:'W',"wraith",random MONSTER:'W',random,random # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # LEVEL: "Pri-fila" # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'Z', "human zombie", random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'Z', "human zombie", random ROOM: "morgue" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'W', "wraith", random ROOM: "morgue" , random, random, random, random OBJECT: random, random, random TRAP: random, random RANDOM_CORRIDORS LEVEL: "Pri-filb" # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'Z', "human zombie", random MONSTER: 'W', "wraith", random ROOM: "morgue" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random,random,random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'Z', "human zombie", random MONSTER: 'W', "wraith", random ROOM: "morgue" , random, random, random, random STAIR: random, down OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'Z', "human zombie", random MONSTER: 'W', "wraith", random ROOM: "morgue" , random, random, random, random OBJECT: random, random, random TRAP: random, random RANDOM_CORRIDORS nethack-3.4.3/dat/Ranger.des0100644000000000000000000002766607764735040014355 0ustar rootroot# SCCS Id: @(#)Ranger.des 3.4 2001/02/01 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Orion, # and receive your quest assignment. # MAZE: "Ran-strt",'.' FLAGS: noteleport,hardfloor,arboreal INIT_MAP:'.','.',true,true,lit,false GEOMETRY:left,center #1234567890123456789012345678901234567890123456789012345678901234567890 MAP .. ................................... . .. .. .. ...............F............... .. . .. .F. .. . . .. .............F............. .. . . . .. .. . . . . .. ....................... .. ... . . . .. .. . ... . .. .|..................... ...... FFF . . ..S.................. ... . .. .|................. .... ... . . . .. .. . . . . . .. ....................... .. . . . . .. .. . . . .. .............F............. .. . . .. .F. .. . .. ...............F............... .. .. .. ................................... . .. ENDMAP # Dungeon Description REGION:(00,00,40,20),lit,"ordinary" # Stairs STAIR:(10,10),down # Portal arrival point; just about anywhere on the right hand side of the map BRANCH:levregion(51,2,77,18),(0,0,40,20) # Orion MONSTER:'@',"Orion",(20,10) # The treasure of Orion OBJECT:'(',"chest",(20,10) # Guards for the audience chamber MONSTER:'@',"hunter",(19,09) MONSTER:'@',"hunter",(20,09) MONSTER:'@',"hunter",(21,09) MONSTER:'@',"hunter",(19,10) MONSTER:'@',"hunter",(21,10) MONSTER:'@',"hunter",(19,11) MONSTER:'@',"hunter",(20,11) MONSTER:'@',"hunter",(21,11) # Non diggable walls NON_DIGGABLE:(00,00,40,20) # Traps TRAP:"arrow",(30,09) TRAP:"arrow",(30,10) TRAP:"pit",(40,09) TRAP:"spiked pit",random TRAP:"bear",random TRAP:"bear",random # Monsters on siege duty. MONSTER: 'H',"minotaur",(33,09),hostile,asleep MONSTER: 'C',"forest centaur",(19,03),hostile MONSTER: 'C',"forest centaur",(19,04),hostile MONSTER: 'C',"forest centaur",(19,05),hostile MONSTER: 'C',"forest centaur",(21,03),hostile MONSTER: 'C',"forest centaur",(21,04),hostile MONSTER: 'C',"forest centaur",(21,05),hostile MONSTER: 'C',"forest centaur",(01,09),hostile MONSTER: 'C',"forest centaur",(02,09),hostile MONSTER: 'C',"forest centaur",(03,09),hostile MONSTER: 'C',"forest centaur",(01,11),hostile MONSTER: 'C',"forest centaur",(02,11),hostile MONSTER: 'C',"forest centaur",(03,11),hostile MONSTER: 'C',"forest centaur",(19,15),hostile MONSTER: 'C',"forest centaur",(19,16),hostile MONSTER: 'C',"forest centaur",(19,17),hostile MONSTER: 'C',"forest centaur",(21,15),hostile MONSTER: 'C',"forest centaur",(21,16),hostile MONSTER: 'C',"forest centaur",(21,17),hostile MONSTER: 'C',"plains centaur",random,hostile MONSTER: 'C',"plains centaur",random,hostile MONSTER: 'C',"plains centaur",random,hostile MONSTER: 'C',"plains centaur",random,hostile MONSTER: 'C',"plains centaur",random,hostile MONSTER: 'C',"plains centaur",random,hostile MONSTER: 's',"scorpion",random,hostile MONSTER: 's',"scorpion",random,hostile # # The "locate" level for the quest. # # Here you have to infiltrate the Cave of the Wumpus to go # further towards your assigned quest. # MAZE: "Ran-loca",' ' FLAGS: hardfloor GEOMETRY:center,center #1234567890123456789012345678901234567890123456789012345678901234567890 MAP ....... ......... ....... ................... ................... .... ....... ....... .... ... ..... . ..... . ..... ... . .......... ..... ........... ..... .......... . . .. ..... .......... ..... .......... ..... .. . . . . ..... . ..... . . . . . ..... ............. ..... . . . . ................ ....... ................ . . . . ..... ....... ..... . . . . . ...... ...... . . . . . ........... ......... ........... . . . . .......... .......... . . . .. ..... . ..... . ..... .. . . .......... ..... ........... ..... .......... . . ..... .......... ..... .......... ..... . . . ..... . ..... . . ... ....... ....... ....... ... .............. ............. .............. ....... ....... ....... ....... ....... ENDMAP # Dungeon Description REGION:(00,00,54,19),lit,"ordinary" # Stairs STAIR:(25,05),up STAIR:(27,18),down # Non diggable walls NON_DIGGABLE:(00,00,54,19) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:"spiked pit",random TRAP:"spiked pit",random TRAP:"teleport",random TRAP:"teleport",random TRAP:"arrow",random TRAP:"arrow",random # Random monsters. MONSTER:'q',"wumpus",(27,18),hostile,asleep MONSTER:'B',"giant bat",random,hostile MONSTER:'B',"giant bat",random,hostile MONSTER:'B',"giant bat",random,hostile MONSTER:'B',"giant bat",random,hostile MONSTER:'C',"forest centaur",random,hostile MONSTER:'C',"forest centaur",random,hostile MONSTER:'C',"forest centaur",random,hostile MONSTER:'C',"forest centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'s',"scorpion",random,hostile MONSTER:'s',"scorpion",random,hostile MONSTER:'s',"scorpion",random,hostile MONSTER:'s',"scorpion",random,hostile MONSTER:'s',random,random,hostile MONSTER:'s',random,random,hostile # # The "goal" level for the quest. # # Here you meet Scorpius, your nemesis monster. You have to # defeat Scorpius in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Ran-goal", ' ' GEOMETRY:center,center MAP ... ... .......................................................................... ... + ... . ............ ....... . ....... . . ............................. . ........ .........S.. . . ............ . ...... . . . ....... .. . . ......... . .... + . ... . .. . . S . ......... .S. .S............... . . ... . ... . ......... . . . ........ .....S.+.......+....\....+........+. . . ... ... S ......... .. ..... . . .. ......... .. ...... . . ....... ... + .... .... .......... . . .............. .. . ...... .. ............. . . ............. . .......... ...... . ... + ... .......................................................................... ... ... ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # Stairs STAIR:(19,10),up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:')',"bow",(37,10),blessed,0,"The Longbow of Diana" OBJECT:'(',"chest",(37,10) OBJECT:random,random,(36,09) OBJECT:random,random,(36,10) OBJECT:random,random,(36,11) OBJECT:random,random,(37,09) OBJECT:random,random,(37,11) OBJECT:random,random,(38,09) OBJECT:random,random,(38,10) OBJECT:random,random,(38,11) OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # doors DOOR:locked,(12,08) DOOR:closed,(22,10) DOOR:locked,(24,10) DOOR:closed,(25,11) DOOR:closed,(32,10) DOOR:closed,(37,03) DOOR:closed,(37,07) DOOR:closed,(37,13) DOOR:closed,(37,16) DOOR:closed,(42,10) DOOR:locked,(46,08) DOOR:closed,(51,10) DOOR:locked,(53,08) DOOR:closed,(65,05) # Random monsters. MONSTER:'s',"Scorpius",(37,10),hostile MONSTER:'C',"forest centaur",(36,09),hostile MONSTER:'C',"forest centaur",(36,10),hostile MONSTER:'C',"forest centaur",(36,11),hostile MONSTER:'C',"forest centaur",(37,09),hostile MONSTER:'C',"forest centaur",(37,11),hostile MONSTER:'C',"forest centaur",(38,09),hostile MONSTER:'C',"mountain centaur",(38,10),hostile MONSTER:'C',"mountain centaur",(38,11),hostile MONSTER:'C',"mountain centaur",(02,02),hostile MONSTER:'C',"mountain centaur",(71,02),hostile MONSTER:'C',"mountain centaur",(02,16),hostile MONSTER:'C',"mountain centaur",(71,16),hostile MONSTER:'C',"forest centaur",random,hostile MONSTER:'C',"forest centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',"mountain centaur",random,hostile MONSTER:'C',random,random,hostile MONSTER:'C',random,random,hostile MONSTER:'s',"scorpion",(03,02),hostile MONSTER:'s',"scorpion",(72,02),hostile MONSTER:'s',"scorpion",(03,17),hostile MONSTER:'s',"scorpion",(72,17),hostile MONSTER:'s',"scorpion",(41,10),hostile MONSTER:'s',"scorpion",(33,09),hostile MONSTER:'s',"scorpion",random,hostile MONSTER:'s',"scorpion",random,hostile MONSTER:'s',random,random,hostile WALLIFY # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "fila" is the upper filler, between the # start and locate levels, and "filb" the lower between the locate # and goal levels. # MAZE: "Ran-fila" , ' ' INIT_MAP: '.' , 'T', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: 'C', "mountain centaur", random, hostile MONSTER: 'C', "mountain centaur", random, hostile MONSTER: 'C', "forest centaur", random, hostile MONSTER: 'C', "forest centaur", random, hostile MONSTER: 'C', "forest centaur", random, hostile MONSTER: 'C', random, random, hostile MONSTER: 's', "scorpion", random, hostile MAZE: "Ran-filb" , ' ' INIT_MAP: '.' , ' ', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: 'C', "mountain centaur", random, hostile MONSTER: 'C', "mountain centaur", random, hostile MONSTER: 'C', "mountain centaur", random, hostile MONSTER: 'C', "mountain centaur", random, hostile MONSTER: 'C', random, random, hostile MONSTER: 's', "scorpion", random, hostile MONSTER: 's', "scorpion", random, hostile nethack-3.4.3/dat/Rogue.des0100644000000000000000000004112207764735040014177 0ustar rootroot# SCCS Id: @(#)Rogue.des 3.4 2002/02/15 # Copyright (c) 1992 by Dean Luick # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Master of Thieves # and receive your quest assignment. # MAZE: "Rog-strt",' ' FLAGS: noteleport, hardfloor, nommap GEOMETRY:center,center # 1 2 3 4 5 6 7 #123456789012345678901234567890123456789012345678901234567890123456789012345 MAP ---------------------------------.------------------------------------------ |.....|.||..........|....|......|.|.........|.......+............---.......| |.....|..+..........+....---....S.|...-S-----.-----.|............+.+.......| |.....+.||........---......|....|.|...|.....|.|...|.---.....------.--------| |-----|.-------|..|........------.-----.....|.--..|...-------..............| |.....|........------+------..........+.....|..--S---.........------.-----.. |.....|.------...............-----.}}.--------.|....-------.---....|.+...--| |..-+--.|....|-----.--------.|...|.....+.....|.|....|.....+.+......|.--....| |..|....|....|....+.|......|.|...-----.|.....|.--...|.....|.|......|..|....| |..|.-----S----...|.+....-----...|...|.----..|..|.---....--.---S-----.|----| |..|.|........|...------.|.S.....|...|....-----.+.|......|..|.......|.|....| |---.-------..|...|....|.|.|.....|...----.|...|.|---.....|.|-.......|.---..| ...........|..S...|....---.----S----..|...|...+.|..-------.---+-....|...--+| |---------.---------...|......|....S..|.---...|.|..|...........----.---....| |........|.........|...+.------....|---.---...|.--+-.----.----....|.+...--+| |........|.---+---.|----.--........|......-----......|..|..|.--+-.|.-S-.|..| |........|.|.....|........----------.----.......---.--..|-.|....|.-----.|..| |----....+.|.....----+---............|..|--------.+.|...SS.|....|.......|..| |...--+-----.....|......|.------------............---...||.------+--+----..| |..........S.....|......|.|..........S............|.....||...|.....|....|..| -------------------------.-------------------------------------------------- ENDMAP # Dungeon Description #REGION:(00,00,75,20),lit,"ordinary" # The down stairs is at one of the 4 "exits". The others are mimics, # mimicing stairwells. RANDOM_PLACES: (33,0), (0,12), (25,20), (75,05) STAIR:place[0],down MONSTER:'m',"giant mimic", place[1], m_feature "staircase down" MONSTER:'m',"large mimic", place[2], m_feature "staircase down" MONSTER:'m',"small mimic", place[3], m_feature "staircase down" # Portal arrival point BRANCH:(19,09,19,09),(0,0,0,0) # Doors (secret) #DOOR:locked|closed|open,(xx,yy) DOOR: locked, (32, 2) DOOR: locked, (63, 9) DOOR: locked, (27,10) DOOR: locked, (31,12) DOOR: locked, (35,13) DOOR: locked, (69,15) DOOR: locked, (56,17) DOOR: locked, (57,17) DOOR: locked, (11,19) DOOR: locked, (37,19) DOOR: locked, (39, 2) DOOR: locked, (49, 5) DOOR: locked, (10, 9) DOOR: locked, (14,12) # Doors (regular) DOOR: closed, (52, 1) DOOR: closed, ( 9, 2) DOOR: closed, (20, 2) DOOR: closed, (65, 2) DOOR: closed, (67, 2) DOOR: closed, ( 6, 3) DOOR: closed, (21, 5) DOOR: closed, (38, 5) DOOR: closed, (69, 6) DOOR: closed, ( 4, 7) DOOR: closed, (39, 7) DOOR: closed, (58, 7) DOOR: closed, (60, 7) DOOR: closed, (18, 8) DOOR: closed, (20, 9) DOOR: closed, (48,10) DOOR: closed, (46,12) DOOR: closed, (62,12) DOOR: closed, (74,12) DOOR: closed, (23,14) DOOR: closed, (23,14) DOOR: closed, (50,14) DOOR: closed, (68,14) DOOR: closed, (74,14) DOOR: closed, (14,15) DOOR: closed, (63,15) DOOR: closed, ( 9,17) DOOR: closed, (21,17) DOOR: closed, (50,17) DOOR: closed, ( 6,18) DOOR: closed, (65,18) DOOR: closed, (68,18) # Master of Thieves MONSTER:'@',"Master of Thieves",(36,11) # The treasure of Master of Thieves OBJECT:'(',"chest",(36,11) # thug guards, room #1 MONSTER:'@',"thug",(28,10) MONSTER:'@',"thug",(29,11) MONSTER:'@',"thug",(30,09) MONSTER:'@',"thug",(31,07) # thug guards, room #2 MONSTER:'@',"thug",(31,13) MONSTER:'@',"thug",(33,14) MONSTER:'@',"thug",(30,15) #thug guards, room #3 MONSTER:'@',"thug",(35,09) MONSTER:'@',"thug",(36,13) # Non diggable walls NON_DIGGABLE:(00,00,75,20) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # # Monsters to get in the way. # # West exit MONSTER: 'l',"leprechaun",(01,12),hostile MONSTER: 'n',"water nymph",(02,12),hostile # North exit MONSTER: 'n',"water nymph",(33,01),hostile MONSTER: 'l',"leprechaun",(33,02),hostile # East exit MONSTER: 'n',"water nymph",(74,05),hostile MONSTER: 'l',"leprechaun",(74,04),hostile # South exit MONSTER: 'l',"leprechaun",(25,19),hostile MONSTER: 'n',"water nymph",(25,18),hostile # Wandering the streets. What I'd really like for this is a random # location, but make sure we're on a given type, e.g. street (if they # existed, of course). MONSTER: 'n',"water nymph",(07,05),hostile MONSTER: 'l',"leprechaun",(28,06),hostile MONSTER: 'n',"water nymph",(38,07),hostile MONSTER: 'l',"leprechaun",(45,01),hostile MONSTER: 'n',"water nymph",(59,07),hostile MONSTER: 'l',"leprechaun",(62,14),hostile MONSTER: 'n',"water nymph",(71,14),hostile MONSTER: 'l',"leprechaun",(39,13),hostile MONSTER: 'n',"water nymph",(18,14),hostile MONSTER: ':',"chameleon",(19,08),hostile MONSTER: ':',"chameleon",(22,08),hostile MONSTER: ':',"chameleon",(16,08),hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile # # The "locate" level for the quest. # # Here you have to find the entrance to the Assassins' Guild to go # further towards your assigned quest. # MAZE: "Rog-loca",' ' GEOMETRY:center,center # 1 2 3 4 5 6 7 #123456789012345678901234567890123456789012345678901234567890123456789012345 MAP ---------------------------------------------------- -------- ---.................................................- --.....| ---...--------........-------.......................--- ---...| ---.....- ---......- ---..................---- --.-- ---.....---- -------- --..................-- --..| ---...----- ----.----.....----.....--- --..|| ----..---- -----..--- |...--- |.......--- --...| |...--- ----....--- |.--- |.........-- --...|| |...- ----.....--- ---- |..........---....| |...---- ----......--- | |...|.......-....|| |......----- ---.........- | -----...|............| |..........----- ----...........--- -------......||...........|| |..............-----................--- |............|||..........| |------...............................--- |...........|| |.........|| |.....|..............------.............-----..........|| ||........| |.....|.............-- ---.........................|| |.......|| |.....|.............- ---.....................--| ||......| |-S----------.......---- --.................---- |.....|| |...........|..........--------..............----- ||....| |...........|............................----- |....| ------------------------------------------ ------ ENDMAP # Dungeon Description REGION:(00,00,75,20),lit,"ordinary" # Doors #DOOR:locked|closed|open,(xx,yy) # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,75,20) # Objects OBJECT:'?',"teleportation",(11,18),cursed,0 OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',random,random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',random,random,hostile MONSTER:'N',random,random,hostile MONSTER:'N',random,random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile # # The "goal" level for the quest. Teleportation and digging are # disallowed. # # You have to reach The Master Assassin via some means other than # simple searching or digging since there is no path between your # arrival point and his location. # MAZE: "Rog-goal", ' ' FLAGS: noteleport GEOMETRY:center,center # 1 2 3 4 5 6 7 #123456789012345678901234567890123456789012345678901234567890123456789012345 MAP ----- -------.......................................|-----------------| |...| -----.....|.......................................|.................| |...----...|.....|.......................................|....---------....| |.---......---..--.................................------------.......|....| |...............|..................................|..|...|...----........-| |.....-----....--.................................|-..--..-|.....----S----| |--S---...|....|.................................|-........-|....|........| |.........---------.............................|-....}}....-|...|...|....| |....|.....S......|............................|-.....}}.....-|..--.------| |-----.....--.....|...........................|-...}}}}}}}}...-|....|.....-- |...........--....------S-----...............|-....}}}}}}}}....-|..........| |............--........|...| |..............--.....}}.}}........----------S- |.............|........|...| |..............|......}}}}}}}}......|...|.....| |S-.---.---.---.---.---|...| ------------...--........}}.}}.....--..---....| |.---.---.---.---.-S-..----- |....|.....|....|-....}}}}}}}}....---..S.|--..| |...|.......|..........|...---....---...S.....|-...}}}}}}}}...-|.S..|...|..| |...|..|....|..........|............|..--..----|-.....}}.....-|..----...-S-- |...|---....----.......|----- ......|...---| |-....}}....-|...|..--.--..| -----.....---.....--.---....--...--------..| |-........-|....|.........| |.............|..........|.............S... |S-------|.....|..-----..| ---------------------------------------- ...... ---------- ---- ENDMAP # Dungeon Description REGION:(00,00,75,20),lit,"ordinary" # Stairs STAIR:levregion(01,00,15,20),(01,18,04,20),up # Doors # Non diggable walls NON_DIGGABLE:(00,00,75,20) # One trap to keep the gnomes at bay. TRAP:"spiked pit",(37,07) # Objects OBJECT:'(',"skeleton key",(38,10),blessed,0,"The Master Key of Thievery" OBJECT:'%',"tin",(26,12),"chameleon",0 OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'@',"Master Assassin",(38,10),hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',"leprechaun",random,hostile MONSTER:'l',random,random,hostile MONSTER:'l',random,random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',"guardian naga",random,hostile MONSTER:'N',random,random,hostile MONSTER:'N',random,random,hostile MONSTER:'N',random,random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER: ':',"chameleon",random,hostile MONSTER:';',"shark",(51,14),hostile MONSTER:';',"shark",(53,09),hostile MONSTER:';',"shark",(55,15),hostile MONSTER:';',"shark",(58,10),hostile # # The "fill" level for the quest. # # This level is used to fill out any levels not occupied by specific # levels as defined above. # LEVEL: "Rog-fila" # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'l', "leprechaun", random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random MONSTER: 'l', "leprechaun", random, hostile MONSTER: 'N', "guardian naga", random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'n', "water nymph", random, hostile ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random TRAP: random, random MONSTER: 'l', random, random, hostile MONSTER: 'N', "guardian naga", random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random TRAP: random, random MONSTER: 'l', "leprechaun", random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random TRAP: random, random MONSTER: 'l', "leprechaun", random, hostile MONSTER: 'n', "water nymph", random, hostile RANDOM_CORRIDORS # # currently a & b are the same. # LEVEL: "Rog-filb" # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'l', "leprechaun", random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random MONSTER: 'l', "leprechaun", random, hostile MONSTER: 'N', "guardian naga", random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'n', "water nymph", random, hostile ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random TRAP: random, random MONSTER: 'l', random, random, hostile MONSTER: 'N', "guardian naga", random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random TRAP: random, random MONSTER: 'l', "leprechaun", random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random TRAP: random, random MONSTER: 'l', "leprechaun", random, hostile MONSTER: 'n', "water nymph", random, hostile RANDOM_CORRIDORS nethack-3.4.3/dat/Samurai.des0100644000000000000000000003233007764735040014520 0ustar rootroot# SCCS Id: @(#)Samurai.des 3.4 2002/04/08 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991-92 by M. Stephenson, P. Winner # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Lord Sato # and receive your quest assignment. # MAZE: "Sam-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ..............................................................PP............ ...............................................................PP........... ..........---------------------------------------------------...PPP......... ..........|......|.........|...|..............|...|.........|....PPPPP...... ......... |......|.........S...|..............|...S.........|.....PPPP...... ..........|......|.........|---|..............|---|.........|.....PPP....... ..........+......|.........+...-------++-------...+.........|......PP....... ..........+......|.........|......................|.........|......PP....... ......... |......---------------------++--------------------|........PP..... ..........|.................................................|.........PP.... ..........|.................................................|...........PP.. ..........----------------------------------------...-------|............PP. ..........................................|.................|.............PP .............. ................. .........|.................|..............P ............. } ............... } ........|.................|............... .............. ........PP....... .........|.................|............... .....................PPP..................|.................|............... ......................PP..................-------------------............... ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(18,03,26,07),lit,"throne",unfilled # Portal arrival zone BRANCH:(62,12,70,17),(0,0,0,0) # Stairs STAIR:(29,04),down # Doors DOOR:locked,(10,06) DOOR:locked,(10,07) DOOR:closed,(27,04) DOOR:closed,(27,06) DOOR:closed,(38,06) DOOR:locked,(38,08) DOOR:closed,(39,06) DOOR:locked,(39,08) DOOR:closed,(50,04) DOOR:closed,(50,06) # Lord Sato MONSTER:'@',"Lord Sato",(20,04) # The treasure of Lord Sato OBJECT:'(',"chest",(20,04) # roshi guards for the audience chamber MONSTER:'@',"roshi",(18,04) MONSTER:'@',"roshi",(18,05) MONSTER:'@',"roshi",(18,06) MONSTER:'@',"roshi",(18,07) MONSTER:'@',"roshi",(26,04) MONSTER:'@',"roshi",(26,05) MONSTER:'@',"roshi",(26,06) MONSTER:'@',"roshi",(26,07) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: '@',"ninja",(64,00),hostile MONSTER: 'd',"wolf",(65,01) MONSTER: '@',"ninja",(67,02),hostile MONSTER: '@',"ninja",(69,05),hostile MONSTER: '@',"ninja",(69,06),hostile MONSTER: 'd',"wolf",(69,07) MONSTER: '@',"ninja",(70,06),hostile MONSTER: '@',"ninja",(70,07),hostile MONSTER: '@',"ninja",(72,01),hostile MONSTER: 'd',"wolf",(75,09) MONSTER: '@',"ninja",(73,05),hostile MONSTER: '@',"ninja",(68,02),hostile MONSTER:'E',"stalker",random # # The "locate" level for the quest. # # Here you have to invade the Shogun's Castle to go # further towards your assigned quest. # MAZE: "Sam-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ............................................................................ ............................................................................ ........-----..................................................-----........ ........|...|..................................................|...|........ ........|...---..}..--+------------------------------+--..}..---...|........ ........|-|...|.....|...|....|....|....|....|....|.|...|.....|...|-|........ ..........|...-------...|....|....|....|....|....S.|...-------...|.......... ..........|-|.........------+----+-+-------+-+--------.........|-|.......... ............|..--------.|}........................}|.--------..|............ ............|..+........+..........................+........+..|............ ............|..+........+..........................+........+..|............ ............|..--------.|}........................}|.--------..|............ ..........|-|.........--------+-+-------+-+----+------.........|-|.......... ..........|...-------...|.S....|....|....|....|....|...-------...|.......... ........|-|...|.....|...|.|....|....|....|....|....|...|.....|...|-|........ ........|...---..}..--+------------------------------+--..}..---...|........ ........|...|..................................................|...|........ ........-----..................................................-----........ ............................................................................ ............................................................................ ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # Doors DOOR:locked,(22,04) DOOR:locked,(22,15) DOOR:locked,(53,04) DOOR:locked,(53,15) DOOR:locked,(49,06) DOOR:locked,(26,13) DOOR:locked,(28,07) DOOR:locked,(30,12) DOOR:locked,(33,07) DOOR:locked,(32,12) DOOR:locked,(35,07) DOOR:locked,(40,12) DOOR:locked,(43,07) DOOR:locked,(42,12) DOOR:locked,(45,07) DOOR:locked,(47,12) DOOR:closed,(15,09) DOOR:closed,(15,10) DOOR:closed,(24,09) DOOR:closed,(24,10) DOOR:closed,(51,09) DOOR:closed,(51,10) DOOR:closed,(60,09) DOOR:closed,(60,10) # Stairs STAIR:(10,10),up STAIR:(25,14),down # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Objects OBJECT:'*',random,(25,05) OBJECT:'*',random,(26,05) OBJECT:'*',random,(27,05) OBJECT:'*',random,(28,05) OBJECT:'*',random,(25,06) OBJECT:'*',random,(26,06) OBJECT:'*',random,(27,06) OBJECT:'*',random,(28,06) # OBJECT:'[',random,(40,05) OBJECT:'[',random,(41,05) OBJECT:'[',random,(42,05) OBJECT:'[',random,(43,05) OBJECT:'[',random,(40,06) OBJECT:'[',random,(41,06) OBJECT:'[',random,(42,06) OBJECT:'[',random,(43,06) # OBJECT:')',random,(27,13) OBJECT:')',random,(28,13) OBJECT:')',random,(29,13) OBJECT:')',random,(30,13) OBJECT:')',random,(27,14) OBJECT:')',random,(28,14) OBJECT:')',random,(29,14) OBJECT:')',random,(30,14) # OBJECT:'(',random,(37,13) OBJECT:'(',random,(38,13) OBJECT:'(',random,(39,13) OBJECT:'(',random,(40,13) OBJECT:'(',random,(37,14) OBJECT:'(',random,(38,14) OBJECT:'(',random,(39,14) OBJECT:'(',random,(40,14) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'@',"ninja",(15,05),hostile MONSTER:'@',"ninja",(16,05),hostile MONSTER:'d',"wolf",(17,05) MONSTER:'d',"wolf",(18,05) MONSTER:'@',"ninja",(19,05),hostile MONSTER:'d',"wolf",(15,14) MONSTER:'d',"wolf",(16,14) MONSTER:'@',"ninja",(17,14),hostile MONSTER:'@',"ninja",(18,14),hostile MONSTER:'d',"wolf",(56,05) MONSTER:'@',"ninja",(57,05),hostile MONSTER:'d',"wolf",(58,05) MONSTER:'d',"wolf",(59,05) MONSTER:'@',"ninja",(56,14),hostile MONSTER:'d',"wolf",(57,14) MONSTER:'@',"ninja",(58,14),hostile MONSTER:'d',random,(59,14) MONSTER:'d',"wolf",(60,14) MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random # "guards" for the central courtyard. MONSTER:'@',"samurai",(30,05),hostile MONSTER:'@',"samurai",(31,05),hostile MONSTER:'@',"samurai",(32,05),hostile MONSTER:'@',"samurai",(32,14),hostile MONSTER:'@',"samurai",(33,14),hostile MONSTER:'@',"samurai",(34,14),hostile # # The "goal" level for the quest. # # Here you meet Takauji, your nemesis monster. You have to # defeat him in combat to gain the artifact you have been # assigned to retrieve. # MAZE: "Sam-goal", ' ' FLAGS: noteleport GEOMETRY:center,center MAP ....................... ......---------.---------...... ......----.................----...... ....----.....-------------.....----.... ....--.....----...........----.....--.... ...||....---....---------....---....||... ...|....--....---.......---....--....|... ....|...||...---...--+--...---...||...|.... ....|...|....|....|-...-|....|....|...|.... ....|...|....|....+.....+....|........|.... ....|...|....|....|-...-|....|....|...|.... ....|...||...---...--+--...---...||...|.... ...|....--....---.......---....--....|... ...||....---....----.----....---....||... ....--.....----...........----.....--.... ....----.....-------------.....----.... ......----.................----...... ......-------------------...... ....................... ENDMAP # Dungeon Description RANDOM_PLACES:(02,11),(42,09) REGION:(00,00,44,19),unlit,"ordinary" # Doors DOOR:closed,(19,10) DOOR:closed,(22,08) DOOR:closed,(22,12) DOOR:closed,(25,10) # Stairs STAIR:place[0],up # Non diggable walls NON_DIGGABLE:(00,00,44,19) # Objects OBJECT:')',"tsurugi",(22,10),blessed,0,"The Tsurugi of Muramasa" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # TRAP:"board",(22,09) TRAP:"board",(24,10) TRAP:"board",(22,11) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'@',"Ashikaga Takauji",(22,10) MONSTER:'@',"samurai",random,hostile MONSTER:'@',"samurai",random,hostile MONSTER:'@',"samurai",random,hostile MONSTER:'@',"samurai",random,hostile MONSTER:'@',"samurai",random,hostile MONSTER:'@',"ninja",random,hostile MONSTER:'@',"ninja",random,hostile MONSTER:'@',"ninja",random,hostile MONSTER:'@',"ninja",random,hostile MONSTER:'@',"ninja",random,hostile MONSTER:'d',"wolf",random MONSTER:'d',"wolf",random MONSTER:'d',"wolf",random MONSTER:'d',"wolf",random MONSTER:'d',random,random MONSTER:'d',random,random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random MONSTER:'E',"stalker",random # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Sam-fila", ' ' INIT_MAP: '.' , 'P', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'd', random, random MONSTER: 'd', "wolf", random MONSTER: 'd', "wolf", random MONSTER: 'd', "wolf", random MONSTER: 'd', "wolf", random MONSTER: 'd', "wolf", random MONSTER: 'E', "stalker", random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random MAZE: "Sam-filb", ' ' GEOMETRY:center,center MAP ------------- ------------- |...........| |...........| |...-----...|----------------------------------|...-----...| |...| |...|..................................|...| |...| |...-----..........................................-----...| |...........|--S----------------------------S--|...........| ----...--------.|..........................|.--------...---- |...|........+..........................+........|...| |...|........+..........................+........|...| ----...--------.|..........................|.--------...---- |...........|--S----------------------------S--|...........| |...-----..........................................-----...| |...| |...|..................................|...| |...| |...-----...|----------------------------------|...-----...| |...........| |...........| ------------- ------------- ENDMAP REGION:(00,00,59,15),unlit,"ordinary" # Doors DOOR:closed,(16,07) DOOR:closed,(16,08) DOOR:closed,(43,07) DOOR:closed,(43,08) # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'd', random, random MONSTER: 'd', "wolf", random MONSTER: 'd', "wolf", random MONSTER: 'd', "wolf", random MONSTER: 'd', "wolf", random MONSTER: 'E', "stalker", random MONSTER: 'E', "stalker", random MONSTER: 'E', "stalker", random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random nethack-3.4.3/dat/Tourist.des0100644000000000000000000004075707764735040014604 0ustar rootroot# SCCS Id: @(#)Tourist.des 3.4 1992/09/26 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991,92 by M. Stephenson, P. Winner # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Twoflower # and receive your quest assignment. # MAZE: "Tou-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP .......}}....---------..-------------------------------------------------... ........}}...|.......|..|.-------------------------------------------...|... .........}}..|.......|..|.|......|......|.............|......|......|...|... ..........}}.|.......|..|.|......+......+.............+......+..\...|...|... ...........}}}..........|.|......|......|.............|......|......|...|... .............}}.........|.|----S-|--S---|S----------S-|---S--|------|...|... ..............}}}.......|...............................................|... ................}}}.....----S------++--S----------S----------S-----------... ..................}}........... .. ................................... ......-------......}}}}........}}}}..}}}}..}}}}..}}}}....................... ......|.....|.......}}}}}}..}}}} .. }}}}..}}}}..}}}..................... ......|.....+...........}}}}}}........................}}}..}}}}..}}}..}}}... ......|.....|...........................................}}}}..}}}..}}}}.}}}} ......-------............................................................... ............................................................................ ...-------......-------..................................................... ...|.....|......|.....|..................................................... ...|.....+......+.....|..................................................... ...|.....|......|.....|..................................................... ...-------......-------..................................................... ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(14,01,20,03),unlit,"morgue" REGION:(07,10,11,12),unlit,"ordinary" REGION:(04,16,08,18),unlit,"ordinary" REGION:(17,16,21,18),unlit,"ordinary" REGION:(27,02,32,04),unlit,"ordinary" REGION:(34,02,39,04),unlit,"ordinary" REGION:(41,02,53,04),unlit,"ordinary" REGION:(55,02,60,04),unlit,"ordinary" REGION:(62,02,67,04),lit,"ordinary" # Stairs STAIR:(66,03),down # Portal arrival point BRANCH:(68,14,68,14),(0,0,0,0) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Doors DOOR:locked,(31,05) DOOR:locked,(36,05) DOOR:locked,(41,05) DOOR:locked,(52,05) DOOR:locked,(58,05) DOOR:locked,(28,07) DOOR:locked,(39,07) DOOR:locked,(50,07) DOOR:locked,(61,07) DOOR:closed,(33,03) DOOR:closed,(40,03) DOOR:closed,(54,03) DOOR:closed,(61,03) DOOR:open,(12,11) DOOR:open,(09,17) DOOR:open,(16,17) DOOR:locked,(35,07) DOOR:locked,(36,07) # Monsters on siege duty. MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',"giant spider",random MONSTER: 's',random,random MONSTER: 's',random,random MONSTER: 'C',"forest centaur",random MONSTER: 'C',"forest centaur",random MONSTER: 'C',"forest centaur",random MONSTER: 'C',"forest centaur",random MONSTER: 'C',"forest centaur",random MONSTER: 'C',"forest centaur",random MONSTER: 'C',"forest centaur",random MONSTER: 'C',"forest centaur",random MONSTER: 'C',random,random # Twoflower MONSTER:'@',"Twoflower",(64,03) # The treasure of Twoflower OBJECT:'(',"chest",(64,03) # guides for the audience chamber MONSTER:'@',"guide",(29,03) MONSTER:'@',"guide",(32,04) MONSTER:'@',"guide",(35,02) MONSTER:'@',"guide",(38,03) MONSTER:'@',"guide",(45,03) MONSTER:'@',"guide",(48,02) MONSTER:'@',"guide",(49,04) MONSTER:'@',"guide",(51,03) MONSTER:'@',"guide",(57,03) MONSTER:'@',"guide",(62,04) MONSTER:'@',"guide",(66,04) # path guards MONSTER:'@',"watchman",(35,08) MONSTER:'@',"watchman",(36,08) # river monsters MONSTER:';',"giant eel",(62,12) MONSTER:';',"piranha",(47,10) MONSTER:';',"piranha",(29,11) MONSTER:';',"kraken",(34,09) MONSTER:';',"kraken",(37,09) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # # The "locate" level for the quest. # # Here you have to find the Thieves' Guild Hall to go # further towards your assigned quest. # MAZE: "Tou-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ---------------------------------------------------------------------------- |....|......|..........|......|......|...|....|.....|......|...............| |....|......|.|------|.|......|......|.|.|....|..}..|......|.|----------|..| |....|--+----.|......|.|-S---+|+-----|.|.S....|.....|---+--|.|..........+..| |....|........|......|.|...|.........|.|------|..............|..........|-+| |....+...}}...+......|.|...|.|-----|.|..............|--+----------------|..| |----|........|------|.|---|.|.....|......|-----+-|.|.......|...........|--| |............................|.....|.|--+-|.......|.|.......|...........|..| |----|.....|-------------|...|--+--|.|....|.......|.|-----------+-------|..| |....+.....+.........S...|...........|....|-------|........................| |....|.....|.........|...|.|---------|....|.........|-------|.|----------|.| |....|.....|---------|---|.|......|..+....|-------|.|.......|.+......S.\.|.| |....|.....+.........S...|.|......|..|....|.......|.|.......|.|......|...|.| |-------|..|.........|---|.|+-------------------+-|.|.......+.|----------|.| |.......+..|---------|.........|.........|..........|.......|.|..........|.| |.......|..............|--+--|.|.........|.|----+-----------|.|..........|.| |---------+-|--+-----|-|.....|.|.........|.|........|.|.....+.|..........+.| |...........|........|.S.....|.|----+----|.|--------|.|.....|.|----------|.| |...........|........|.|.....|........................|.....|..............| ---------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" NON_DIGGABLE:(00,00,75,19) # REGION:(01,01,04,05),unlit,"morgue" REGION:(15,03,20,05),lit,"shop" REGION:(62,03,71,04),lit,"shop" REGION:(01,17,11,18),lit,"barracks" REGION:(12,09,20,10),lit,"barracks" REGION:(53,11,59,14),lit,"zoo" REGION:(63,14,72,16),lit,"barracks" REGION:(32,14,40,16),lit,"temple" # REGION:(06,01,11,02),random,"ordinary" REGION:(24,01,29,02),random,"ordinary" REGION:(31,01,36,02),random,"ordinary" REGION:(42,01,45,03),random,"ordinary" REGION:(53,01,58,02),random,"ordinary" REGION:(24,04,26,05),random,"ordinary" REGION:(30,06,34,07),random,"ordinary" REGION:(73,05,74,05),unlit,"ordinary" REGION:(01,09,04,12),random,"ordinary" REGION:(01,14,07,15),random,"ordinary" REGION:(12,12,20,13),random,"ordinary" REGION:(13,17,20,18),random,"ordinary" REGION:(22,09,24,10),random,"ordinary" REGION:(22,12,24,12),random,"ordinary" REGION:(24,16,28,18),random,"ordinary" REGION:(28,11,33,12),random,"ordinary" REGION:(35,11,36,12),lit,"ordinary" REGION:(38,08,41,12),random,"ordinary" REGION:(43,07,49,08),random,"ordinary" REGION:(43,12,49,12),random,"ordinary" REGION:(44,16,51,16),random,"ordinary" REGION:(53,06,59,07),random,"ordinary" REGION:(61,06,71,07),random,"ordinary" REGION:(55,16,59,18),random,"ordinary" REGION:(63,11,68,12),random,"ordinary" REGION:(70,11,72,12),random,"ordinary" # Stairs STAIR:(10,04),up STAIR:(73,05),down # Non diggable walls NON_DIGGABLE:(00,00,75,19) DOOR:closed,(05,05) DOOR:closed,(05,09) DOOR:closed,(08,14) DOOR:closed,(08,03) DOOR:closed,(11,09) DOOR:closed,(11,12) DOOR:closed,(10,16) DOOR:closed,(14,05) DOOR:closed,(15,16) DOOR:locked,(21,09) DOOR:locked,(21,12) DOOR:closed,(23,17) DOOR:closed,(25,03) DOOR:closed,(26,15) DOOR:closed,(29,03) DOOR:closed,(28,13) DOOR:closed,(31,03) DOOR:closed,(32,08) DOOR:closed,(37,11) DOOR:closed,(36,17) DOOR:locked,(41,03) DOOR:closed,(40,07) DOOR:closed,(48,06) DOOR:closed,(48,13) DOOR:closed,(48,15) DOOR:closed,(56,03) DOOR:closed,(55,05) DOOR:closed,(72,03) DOOR:locked,(74,04) DOOR:closed,(64,08) DOOR:closed,(62,11) DOOR:closed,(69,11) DOOR:closed,(60,13) DOOR:closed,(60,16) DOOR:closed,(73,16) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Toilet paper OBJECT:'?',"blank paper",(71,12) OBJECT:'?',"blank paper",(71,12) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',random,random MONSTER:'s',random,random # # The "goal" level for the quest. # # Here you meet the Master of Thieves your nemesis monster. You have to # defeat the Master of Thieves in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Tou-goal", ' ' GEOMETRY:center,center MAP ---------------------------------------------------------------------------- |.........|.........|..........|..| |.................|........|........|..| |.........|.........|..........|..| |....--------.....|........|........|..| |------S--|--+-----------+------..| |....|......|.....|........|........|..| |.........|.......................| |....|......+.....--+-------------+--..| |.........|.......................| |....|......|..........................| |-S-----S-|......----------.......| |....|......|..........................| |..|..|...|......|........|.......| |....-----------.........----..........| |..+..+...|......|........|.......| |....|.........|.........|}}|..........| |..|..|...|......+........|.......| |....|.........+.........|}}|..........| |..|..|...|......|........|.......S.S....|.........|.........----..........| |---..----|......|........|.......| |....|.........|.......................| |.........+......|+F-+F-+F|.......| |....-----------.......................| |---..----|......|..|..|..|.......| |......................--------------..| |..|..|...|......--F-F--F--.......| |......................+............|..| |..+..+...|.......................| |--.---...-----+-----..|............|..| |--|..----|--+-----------+------..| |.....|...|.........|..|------------|..| |..+..+...|.........|..........|..| |.....|...|.........|..+............|..| |..|..|...|.........|..........|..| |.....|...|.........|..|............|..| ---------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" # The Inn REGION:(01,01,09,02),lit,"ordinary" REGION:(01,04,09,05),lit,"barracks" REGION:(01,07,02,10),unlit,"ordinary" REGION:(07,07,09,10),unlit,"ordinary" REGION:(01,14,02,15),unlit,"ordinary" REGION:(07,14,09,15),unlit,"ordinary" REGION:(01,17,02,18),unlit,"ordinary" REGION:(07,17,09,18),unlit,"ordinary" # REGION:(11,01,19,02),unlit,"barracks" REGION:(21,01,30,02),unlit,"ordinary" REGION:(11,17,19,18),unlit,"barracks" REGION:(21,17,30,18),unlit,"ordinary" # Police Station REGION:(18,07,25,11),lit,"ordinary" REGION:(18,13,19,13),unlit,"ordinary" REGION:(21,13,22,13),unlit,"ordinary" REGION:(24,13,25,13),unlit,"ordinary" # The town itself REGION:(42,03,47,06),unlit,"ordinary" REGION:(42,08,50,11),unlit,"ordinary" REGION:(37,16,41,18),unlit,"morgue" REGION:(47,16,55,18),unlit,"ordinary" REGION:(55,01,62,03),unlit,"ordinary" REGION:(64,01,71,03),unlit,"ordinary" REGION:(60,14,71,15),lit,"shop" REGION:(60,17,71,18),lit,"shop" # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Stairs STAIR:(70,08),up # Doors DOOR:locked,(07,03) DOOR:locked,(02,06) DOOR:locked,(08,06) DOOR:closed,(03,08) DOOR:closed,(06,08) DOOR:open,(10,12) DOOR:closed,(03,15) DOOR:closed,(06,15) DOOR:closed,(03,17) DOOR:closed,(06,17) DOOR:closed,(13,03) DOOR:random,(25,03) DOOR:closed,(13,16) DOOR:random,(25,16) DOOR:locked,(17,09) DOOR:locked,(18,12) DOOR:locked,(21,12) DOOR:locked,(24,12) DOOR:locked,(34,10) DOOR:locked,(36,10) DOOR:random,(48,04) DOOR:random,(56,04) DOOR:random,(70,04) DOOR:random,(51,09) DOOR:random,(51,15) DOOR:open,(59,14) DOOR:open,(59,17) # Objects OBJECT:'(',"credit card",(04,01),blessed,0,"The Platinum Yendorian Express Card" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'@',"Master of Thieves",(04,01),hostile MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',"giant spider",random MONSTER:'s',random,random MONSTER:'s',random,random # ladies of the evening MONSTER:'&',"succubus",(02,08) MONSTER:'&',"succubus",(08,08) MONSTER:'&',"incubus",(02,14) MONSTER:'&',"incubus",(08,14) MONSTER:'&',"incubus",(02,17) MONSTER:'&',"incubus",(08,17) # Police station (with drunken prisoners) MONSTER:'K',"Kop Kaptain",(24,09),hostile MONSTER:'K',"Kop Lieutenant",(20,09),hostile MONSTER:'K',"Kop Lieutenant",(22,11),hostile MONSTER:'K',"Kop Lieutenant",(22,07),hostile MONSTER:'K',"Keystone Kop",(19,07),hostile MONSTER:'K',"Keystone Kop",(19,08),hostile MONSTER:'K',"Keystone Kop",(22,09),hostile MONSTER:'K',"Keystone Kop",(24,11),hostile MONSTER:'K',"Keystone Kop",(19,11),hostile MONSTER:'@',"prisoner",(19,13) MONSTER:'@',"prisoner",(21,13) MONSTER:'@',"prisoner",(24,13) # MONSTER:'@',"watchman",(33,10),hostile WALLIFY # # The "fill" level for the quest. # # This level is used to fill out any levels not occupied by specific # levels as defined above. # MAZE: "Tou-fila" , ' ' INIT_MAP: '.' , ' ', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: '@', "soldier", random, hostile MONSTER: '@', "soldier", random, hostile MONSTER: '@', "soldier", random, hostile MONSTER: '@', "soldier", random, hostile MONSTER: '@', "soldier", random, hostile MONSTER: 'H', random, random, hostile MONSTER: 'C', random, random, hostile MAZE: "Tou-filb" , ' ' INIT_MAP: '.' , ' ', true, true, random, true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # MONSTER: '@', "soldier", random, hostile MONSTER: '@', "captain", random, hostile MONSTER: '@', "captain", random, hostile MONSTER: 'H', random, random, hostile MONSTER: 'H', random, random, hostile MONSTER: 'C', random, random, hostile MONSTER: 's', random, random nethack-3.4.3/dat/Valkyrie.des0100644000000000000000000002354407764735040014714 0ustar rootroot# SCCS Id: @(#)Valkyrie.des 3.4 2002/05/02 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1991-2 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, the Norn, # and receive your quest assignment. # MAZE: "Val-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP IIIIIIPPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII IIIIPPPPPIIIIIIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...IIIIIIIIIIIIIIIIIIIII IIIIPLLPPIIIIIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII..{..IIIIIIIIIIIIIIIIIIII IIIIPLPPIIIIIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.....IIIIIIPPPIIIIIIIIII IIIPPPPPIIIIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.IIIIIPPLPIIIIIIIIII IIIIPIIIIIIII..IIIIPPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.IIIIIPLPPIIIIIIIIII IIIIIIIIIIII..IIIIIPLPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII..IIIIIPPPIIIIIIIIIII IIIIIIII.....IIIIIIPPPIIII|----------------|IIIIIPPPIII.IIIIIIIIIIIIIIIIIIII IIIIIII..III...IIIIIIIIIII|................|IIIIIPLPII..IIIIIIIIIIIIIIIIIIII IIIIII..IIIIII......IIIII.|................|.IIIIPPPII.IIIIIIIIIIIIIIIIIIIII IIIII..IIIIIIIIIIII.......+................+...IIIIIII.IIIIIIIIIIIIIIIIIIIII IIII..IIIIIIIII.....IIIII.|................|.I...IIIII.IIIIIIIIIIIIIIIIIIIII III..IIIIIIIII..IIIIIIIIII|................|IIII.......IIIIIIIIIIIIIIIIIIIII IIII..IIIIIII..IIIIIIIIIII|----------------|IIIIIIIIII...IIIIIIIIIIIIIIIIIII IIIIII..IIII..IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIPPPPIIII...IIIIIIIIIIIIIIIII IIIIIII......IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIPLLPPIIIII...IIIIIIIIIIIIIII IIIIPPPIP...IIIIIIIIIIIPIIIIIIIIIIIIIIIIIIIIIIIIPPPPIIIIIIII...I......IIIIII IIIPPLPPIIIIIIIIIIIIIIPPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.........IIIII IIIIPPPIIIIIIIIIIIIIIPPLPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII.......IIIIII IIIIIIIIIIIIIIIIIIIIIIPPPIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(27,08,42,12),lit,"ordinary" # Portal arrival point BRANCH:(66,17,66,17),(0,0,0,0) # Stairs STAIR:(18,01),down FOUNTAIN:(53,02) # Doors DOOR:locked,(26,10) DOOR:locked,(43,10) # Norn MONSTER:'@',"Norn",(35,10) # The treasure of the Norn OBJECT:'(',"chest",(36,10) # valkyrie guards for the audience chamber MONSTER:'@',"warrior",(27,08) MONSTER:'@',"warrior",(27,09) MONSTER:'@',"warrior",(27,11) MONSTER:'@',"warrior",(27,12) MONSTER:'@',"warrior",(42,08) MONSTER:'@',"warrior",(42,09) MONSTER:'@',"warrior",(42,11) MONSTER:'@',"warrior",(42,12) # Non diggable walls NON_DIGGABLE:(26,07,43,13) # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random # Monsters on siege duty. MONSTER: 'a',"fire ant",(04,12) MONSTER: 'a',"fire ant",(08,08) MONSTER: 'a',"fire ant",(14,04) MONSTER: 'a',"fire ant",(17,11) MONSTER: 'a',"fire ant",(24,10) MONSTER: 'a',"fire ant",(45,10) MONSTER: 'a',"fire ant",(54,02) MONSTER: 'a',"fire ant",(55,07) MONSTER: 'a',"fire ant",(58,14) MONSTER: 'a',"fire ant",(63,17) MONSTER: 'H',"fire giant",(18,01),hostile MONSTER: 'H',"fire giant",(10,16),hostile # # The "locate" level for the quest. # # Here you have to find the cave of Surtur to go # further towards your assigned quest. # MAZE: "Val-loca",' ' FLAGS: hardfloor INIT_MAP: '.' , 'I' , true , true , lit , false GEOMETRY:center,center MAP PPPP.... ....PPPPP. PLP... .PPLLLPP PPP ....................... PPPLLP .. ............................ PPPP . ............................... .... ................................. .. .................................... . ................................... . .................................. . .. .............................. PP .PPP .......................... PLP .PLLP ..PLLP .PPPP.. ....PPPP ENDMAP # Dungeon Description REGION:(00,00,39,12),lit,"ordinary" # Stairs STAIR:(48,14),up STAIR:(20,06),down # Non diggable walls NON_DIGGABLE:(00,00,39,12) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',random,random MONSTER:'H',random,random,hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',random,random,hostile # # The "goal" level for the quest. # # Here you meet Lord Surtur your nemesis monster. You have to # defeat Lord Surtur in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Val-goal", 'L' INIT_MAP: '.' , 'L' , true , true , lit , false GEOMETRY:center,center MAP .L............................LLLLL LLL.........LLLLL.LLLLL.........LLL .LLL......LLLLLLLLLLLLLLL.......LL. .LLL.....LLL|---------|LLL.....L... ..LL....LL|--.........--|LL.....LLL .......LL|-...LLLLLLL...-|LL.....L. .......LL|...LL.....LL...|LL....... ......LL|-..LL.......LL..-|LL...... ......LL|.................|LL...... ......LL|-..LL.......LL..-|LL...... .......LL|...LL.....LL...|LL....... .......LL|-...LLLLLLL...-|LL....... ..L.....LL|--.........--|LL.....LL. ..LL.....LLL|---------|LLL....LLLL. ..LLL.....LLLLLLLLLLLLLLL...LLLLL.. .LLLL.......LLLLL.LLLLL.....LLLL... ..LL............................... ENDMAP # Dungeon Description REGION:(00,00,34,16),lit,"ordinary" # Stairs # Note: The up stairs are *intentionally* off of the map. STAIR:(45,10),up # Non diggable walls NON_DIGGABLE:(00,00,34,16) # Drawbridges DRAWBRIDGE:(17,02),south,open DRAWBRIDGE:(17,14),north,open # Objects OBJECT:'(',"crystal ball",(17,08),blessed,5,"The Orb of Fate" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Traps TRAP:"board",(13,08) TRAP:"board",(21,08) # Random traps TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"board",random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'H',"Lord Surtur",(17,08) MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',"fire ant",random MONSTER:'a',random,random MONSTER:'a',random,random MONSTER:'H',"fire giant",(10,06),hostile MONSTER:'H',"fire giant",(10,07),hostile MONSTER:'H',"fire giant",(10,08),hostile MONSTER:'H',"fire giant",(10,09),hostile MONSTER:'H',"fire giant",(10,10),hostile MONSTER:'H',"fire giant",(24,06),hostile MONSTER:'H',"fire giant",(24,07),hostile MONSTER:'H',"fire giant",(24,08),hostile MONSTER:'H',"fire giant",(24,09),hostile MONSTER:'H',"fire giant",(24,10),hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',"fire giant",random,hostile MONSTER:'H',random,random,hostile # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # MAZE: "Val-fila" , 'I' INIT_MAP: '.' , 'I' , true , true , lit, false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'a', "fire ant", random MONSTER: 'a', "fire ant", random MONSTER: 'a', "fire ant", random MONSTER: 'a', "fire ant", random MONSTER: 'a', "fire ant", random MONSTER: 'a', random, random MONSTER: 'H', "fire giant", random, hostile # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random MAZE: "Val-filb" , 'L' INIT_MAP: '.' , 'L' , true , true , lit, false NOMAP # STAIR: random, up STAIR: random, down # OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'a', "fire ant", random MONSTER: 'a', "fire ant", random MONSTER: 'a', "fire ant", random MONSTER: 'a', random, random MONSTER: 'H', "fire giant", random, hostile MONSTER: 'H', "fire giant", random, hostile MONSTER: 'H', "fire giant", random, hostile # TRAP: "fire", random TRAP: "fire", random TRAP: "fire", random TRAP: "fire", random TRAP: "fire", random TRAP: random, random TRAP: random, random nethack-3.4.3/dat/Wizard.des0100644000000000000000000003546107764735040014367 0ustar rootroot# SCCS Id: @(#)Wizard.des 3.4 1992/07/11 # Copyright (c) 1992 by David Cohrs # NetHack may be freely redistributed. See license for details. # # The "start" level for the quest. # # Here you meet your (besieged) class leader, Neferet the Green # and receive your quest assignment. # MAZE: "Wiz-strt",' ' FLAGS: noteleport,hardfloor GEOMETRY:center,center MAP ............................................................................ .....................C....CC.C........................C..................... ..........CCC.....................CCC....................................... ........CC........-----------.......C.C...C...C....C........................ .......C.....---------------------...C..C..C..C............................. ......C..C...------....\....------....C.....C............................... ........C...||....|.........|....||......................................... .......C....||....|.........+....||......................................... .......C...||---+--.........|....|||........................................ ......C....||...............|--S--||........................................ ...........||--+--|++----|---|..|.SS..........C......C...................... ........C..||.....|..|...|...|--|.||..CC..C.....C..........C................ .......C...||.....|..|.--|.|.|....||.................C..C................... .....C......||....|..|.....|.|.--||..C..C..........C...........}}}.......... ......C.C...||....|..-----.|.....||...C.C.C..............C....}}}}}}........ .........C...------........|------....C..C.....C..CC.C......}}}}}}}}}}}..... .........CC..---------------------...C.C..C.....CCCCC.C.......}}}}}}}}...... .........C........-----------..........C.C.......CCC.........}}}}}}}}}...... ..........C.C.........................C............C...........}}}}}........ ......................CCC.C................................................. ENDMAP # Dungeon Description REGION:(00,00,75,19),lit,"ordinary" REGION:(35,00,49,03),unlit,"ordinary" REGION:(43,12,49,16),unlit,"ordinary" REGION:(19,11,33,15),unlit,"ordinary",unfilled,true REGION:(30,10,31,10),unlit,"ordinary" # Stairs STAIR:(30,10),down # Portal arrival point BRANCH:(63,06,63,06),(0,0,0,0) # Doors DOOR:closed,(31,09) DOOR:closed,(16,08) DOOR:closed,(28,07) DOOR:locked,(34,10) DOOR:locked,(35,10) DOOR:closed,(15,10) DOOR:locked,(19,10) DOOR:locked,(20,10) # Neferet the Green, the quest leader MONSTER:'@',"Neferet the Green",(23,05) # The treasure of the quest leader OBJECT:'(',"chest",(24,05) # apprentice guards for the audience chamber MONSTER:'@',"apprentice",(30,07) MONSTER:'@',"apprentice",(24,06) MONSTER:'@',"apprentice",(15,06) MONSTER:'@',"apprentice",(15,12) MONSTER:'@',"apprentice",(26,11) MONSTER:'@',"apprentice",(27,11) MONSTER:'@',"apprentice",(19,09) MONSTER:'@',"apprentice",(20,09) # Eels in the pond MONSTER:';',"giant eel",(62,14) MONSTER:';',"giant eel",(69,15) MONSTER:';',"giant eel",(67,17) # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters on siege duty. MONSTER: 'B',random,(60,09),hostile MONSTER: 'W',random,(60,10),hostile MONSTER: 'B',random,(60,11),hostile MONSTER: 'B',random,(60,12),hostile MONSTER: 'i',random,(60,13),hostile MONSTER: 'B',random,(61,10),hostile MONSTER: 'B',random,(61,11),hostile MONSTER: 'B',random,(61,12),hostile MONSTER: 'B',random,(35,03),hostile MONSTER: 'i',random,(35,17),hostile MONSTER: 'B',random,(36,17),hostile MONSTER: 'B',random,(34,16),hostile MONSTER: 'i',random,(34,17),hostile MONSTER: 'W',random,(67,02),hostile MONSTER: 'B',random,(10,19),hostile # # The "locate" level for the quest. # # Here you have to find the Entrance to the Tower of Darkness to go # further towards your assigned quest. # MAZE: "Wiz-loca",' ' FLAGS: hardfloor GEOMETRY:center,center MAP ............. ....................................................... .............. .............}}}}}}}.}}}}}}}}}}}}}}}}}}}.}}}}}}}....... .............. ..............}.................................}....... .............. ..............}.---------S---------------------.}....... ............... .........C....}.|.............................|.}....... ............... ..........C....}.|.---------------------------.|.}....... ............... .........CCC.....|.|.........................|.|......... ................ ....C....CCC...}.|.|.---S-------------------.|.|.}....... .......C..C..... .....C....CCC...}.|.|.|......+.......+......|.|.|.}....... .............C..CC.....C....CCC...}.|.|.|......|-------|......|.|.|.}....... ................ ....C....CCC...}.|.|.|......|.......S......|.|.|.}....... ......C..C..... ....C....CCC...}.|.|.|......|-------|......|.|.|.}....... ............C.. ...C....CCC...}.|.|.|......+.......+......|.|.|.}....... ........C...... ....C....CCC...}.|.|.-----------------------.|.|.}....... ....C......C... ........CCC.....|.|.........................|.|......... ......C..C.... .........C....}.|.--------------------S------.|.}....... .............. .........C....}.|.............................|.}....... ............. ..............}.-------------------------------.}....... ............. .............}.................................}....... ............. .............}}}}}}}.}}}}}}}}}}}}}}}}}}}.}}}}}}}....... ............. ....................................................... ENDMAP # Dungeon Description REGION:(00,00,75,20),lit,"ordinary" REGION:(37,04,65,16),unlit,"ordinary" REGION:(41,08,46,12),lit,"ordinary" REGION:(56,08,61,12),lit,"ordinary" REGION:(48,08,54,08),unlit,"ordinary" REGION:(48,12,54,12),unlit,"ordinary" REGION:(48,10,54,10),unlit,"ordinary" # Doors DOOR:locked,(45,03) DOOR:locked,(43,07) DOOR:locked,(58,15) DOOR:locked,(55,10) DOOR:locked,(55,08) DOOR:locked,(55,12) DOOR:locked,(47,08) DOOR:locked,(47,12) # Stairs STAIR:(03,17),up STAIR:(48,10),down # Non diggable walls NON_DIGGABLE:(00,00,75,20) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:"spiked pit",(24,02) TRAP:"spiked pit",(07,10) TRAP:"spiked pit",(23,05) TRAP:"spiked pit",(26,19) TRAP:"spiked pit",(72,02) TRAP:"spiked pit",(72,12) TRAP:"falling rock",(45,16) TRAP:"falling rock",(65,13) TRAP:"falling rock",(55,06) TRAP:"falling rock",(39,11) TRAP:"falling rock",(57,09) TRAP:"magic",random TRAP:"statue",random TRAP:"statue",random TRAP:"polymorph",random TRAP:"anti magic",(53,10) TRAP:"sleep gas",random TRAP:"sleep gas",random TRAP:"dart",random TRAP:"dart",random TRAP:"dart",random # Random monsters. MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'i',random,random,hostile # # The "goal" level for the quest. # # Here you meet the Dark One, your nemesis monster. You have to # defeat the Dark One in combat to gain the artifact you have # been assigned to retrieve. # MAZE: "Wiz-goal", ' ' GEOMETRY:center,center MAP ------------- ------------- |...........| |...........| -------|...........-------------------...........| |......S...........|..|..|..|..|..|..|...........| |......|...........|..|..|..|..|..|..|...........| |......|...........-F+-F+-F+-F+-F+-F+-...........| --S----|...........S.................+...........| |......|...........-F+-F+-F+-F+-F+-F+-...........| |......|...........|..|..|..|..|..|..|...........| |......|...........|..|..|..|..|..|..|...........| -------|...........-------------------...........| |...........| |...........| ------------- ------------- ENDMAP # Dungeon Description REGION:(13,10,18,12),unlit,"temple" REGION:(13,06,18,08),lit,"ordinary" REGION:(20,04,30,14),unlit,"ordinary" REGION:(32,06,33,07),unlit,"ordinary" REGION:(35,06,36,07),unlit,"ordinary" REGION:(38,06,39,07),unlit,"ordinary" REGION:(41,06,42,07),unlit,"ordinary" REGION:(44,06,45,07),unlit,"ordinary" REGION:(47,06,48,07),unlit,"ordinary" REGION:(32,09,48,09),unlit,"ordinary" REGION:(32,11,33,12),unlit,"ordinary" REGION:(35,11,36,12),unlit,"ordinary" REGION:(38,11,39,12),unlit,"ordinary" REGION:(41,11,42,12),unlit,"ordinary" REGION:(44,11,45,12),unlit,"ordinary" REGION:(47,11,48,12),unlit,"ordinary" REGION:(50,04,60,14),lit,"ordinary" # Doors DOOR:locked,(19,06) DOOR:locked,(14,09) DOOR:locked,(31,09) DOOR:locked,(33,08) DOOR:locked,(36,08) DOOR:locked,(39,08) DOOR:locked,(42,08) DOOR:locked,(45,08) DOOR:locked,(48,08) DOOR:locked,(33,10) DOOR:locked,(36,10) DOOR:locked,(39,10) DOOR:locked,(42,10) DOOR:locked,(45,10) DOOR:locked,(48,10) DOOR:locked,(49,09) # Stairs STAIR:(55,05),up # Non diggable walls NON_DIGGABLE:(00,00,75,19) # The altar. This is not a shrine. ALTAR:(16,11),noncoaligned,altar # Objects OBJECT:'"',"amulet of ESP",(16,11),blessed,0,"The Eye of the Aethiopica" OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'@',"Dark One",(16,11) MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'B',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'i',random,random,hostile MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'i',random,random,hostile # Captive Monsters in the dungeon MONSTER:'@',"rogue",(35,06),peaceful,"Pug" MONSTER:'Y',"owlbear",(47,06),peaceful,asleep MONSTER:'@',"wizard",(32,11),peaceful,asleep,"Newt" MONSTER:'@',"Grey-elf",(44,11),peaceful MONSTER:'H',"hill giant",(47,11),peaceful,asleep MONSTER:'G',"gnomish wizard",(38,06),peaceful MONSTER:'@',"prisoner",(35,11),peaceful MONSTER:'@',"prisoner",(41,11),peaceful,asleep # # The "fill" levels for the quest. # # These levels are used to fill out any levels not occupied by specific # levels as defined above. "filla" is the upper filler, between the # start and locate levels, and "fillb" the lower between the locate # and goal levels. # LEVEL: "Wiz-fila" # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'i', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random MONSTER: 'i', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'B', "vampire bat", random MONSTER: 'B', "vampire bat", random ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random MONSTER: 'i', random, random, hostile MONSTER: 'B', "vampire bat", random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'i', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'B', "vampire bat", random RANDOM_CORRIDORS LEVEL: "Wiz-filb" # ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random MONSTER: 'X', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random,random,random MONSTER: 'i', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random OBJECT: random,random,random MONSTER: 'X', random, random, hostile ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random MONSTER: 'i', random, random, hostile MONSTER: 'B', "vampire bat", random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'i', random, random, hostile ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: 'B', "vampire bat", random RANDOM_CORRIDORS nethack-3.4.3/dat/bigroom.des0100644000000000000000000003633707764735040014570 0ustar rootroot# SCCS Id: @(#)bigroom.des 3.4 1990/04/15 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1990 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # These are the bigroom levels: # MAZE:"bigrm-1",' ' GEOMETRY:center,center MAP --------------------------------------------------------------------------- |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| --------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(01,01,73,16),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random # Here, just play with the lighting... MAZE:"bigrm-2",' ' GEOMETRY:center,center MAP --------------------------------------------------------------------------- |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| --------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(01,01,23,06),lit,"ordinary" REGION:(01,07,23,10),unlit,"ordinary" REGION:(01,11,23,16),lit,"ordinary" REGION:(24,01,50,06),unlit,"ordinary" REGION:(24,07,50,10),lit,"ordinary" REGION:(24,11,50,16),unlit,"ordinary" REGION:(51,01,73,06),lit,"ordinary" REGION:(51,07,73,10),unlit,"ordinary" REGION:(51,11,73,16),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random # Now, let's get fancy... MAZE:"bigrm-3",' ' GEOMETRY:center,center MAP --------------------------------------------------------------------------- |.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| |.........................................................................| |.........................................................................| |.........................................................................| |..............---.......................................---..............| |...............|.........................................|...............| |.....|.|.|.|.|---|.|.|.|.|...................|.|.|.|.|.|---|.|.|.|.|.....| |.....|-------- --------|...................|---------- --------|.....| |.....|.|.|.|.|---|.|.|.|.|...................|.|.|.|.|.|---|.|.|.|.|.....| |...............|.........................................|...............| |..............---.......................................---..............| |.........................................................................| |.........................................................................| |.........................................................................| |.........................................................................| |.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.|.| --------------------------------------------------------------------------- ENDMAP # Dungeon Description REGION:(01,01,73,16),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random,(01,01) MONSTER:random,random,(13,01) MONSTER:random,random,(25,01) MONSTER:random,random,(37,01) MONSTER:random,random,(49,01) MONSTER:random,random,(61,01) MONSTER:random,random,(73,01) MONSTER:random,random,(07,07) MONSTER:random,random,(13,07) MONSTER:random,random,(25,07) MONSTER:random,random,(37,07) MONSTER:random,random,(49,07) MONSTER:random,random,(61,07) MONSTER:random,random,(67,07) MONSTER:random,random,(07,09) MONSTER:random,random,(13,09) MONSTER:random,random,(25,09) MONSTER:random,random,(37,09) MONSTER:random,random,(49,09) MONSTER:random,random,(61,09) MONSTER:random,random,(67,09) MONSTER:random,random,(01,16) MONSTER:random,random,(13,16) MONSTER:random,random,(25,16) MONSTER:random,random,(37,16) MONSTER:random,random,(49,16) MONSTER:random,random,(61,16) MONSTER:random,random,(73,16) MAZE:"bigrm-4",' ' GEOMETRY:center,center MAP ----------- ----------- |.........| |.........| |.........|-----------| |-----------|.........| |-|...................|----------| |----------|...................|-| -|.............................|-------|.............................|- -|.................................................................|- -|...............................................................|- -|.............................................................|- -|...........................................................|- -|...........................................................|- -|.............................................................|- -|...............................................................|- -|.................................................................|- -|.............................|-------|.............................|- |-|...................|----------| |----------|...................|-| |.........|-----------| |-----------|.........| |.........| |.........| ----------- ----------- ENDMAP # Dungeon Description REGION:(01,01,73,16),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Fountains FOUNTAIN:(05,02) FOUNTAIN:(05,15) FOUNTAIN:(69,02) FOUNTAIN:(69,15) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random # Try an oval room... MAZE:"bigrm-5",' ' GEOMETRY:center,center MAP ------------------ ---------................--------- -------................................------- ------............................................------ ----......................................................---- ---............................................................--- ---................................................................--- ---....................................................................--- |........................................................................| |........................................................................| |........................................................................| ---....................................................................--- ---................................................................--- ---............................................................--- ----......................................................---- ------............................................------ -------................................------- ---------................--------- ------------------ ENDMAP # Dungeon Description REGION:(00,00,72,18),lit,"ordinary" # Stairs STAIR:random,up STAIR:random,down # Non diggable walls NON_DIGGABLE:(00,00,72,18) # Objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random nethack-3.4.3/dat/castle.des0100644000000000000000000001723607764735040014402 0ustar rootroot# SCCS Id: @(#)castle.des 3.4 2002/05/02 # Copyright (c) 1989 by Jean-Christophe Collet # NetHack may be freely redistributed. See license for details. # # This is the stronghold level : # there are several ways to enter it : # - opening the drawbridge (wand of opening, knock spell, playing # the appropriate tune) # # - enter via the back entry (this suppose a ring of levitation, boots # of water walking, etc.) # # Note : If you don't play the right tune, you get indications like in the # MasterMind game... # # To motivate the player : there are 4 storerooms (armors, weapons, food and # gems) and a wand of wishing in one of the 4 towers... MAZE:"castle",random FLAGS: noteleport GEOMETRY:center,center MAP }}}}}}}}}.............................................}}}}}}}}} }-------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------} }|.....|-----------------------------------------------|.....|} }|.....+...............................................+.....|} }-------------------------------+-----------------------------} }}}}}}|........|..........+...........|.......S.S.......|}}}}}} .....}|........|..........|...........|.......|.|.......|}..... .....}|........------------...........---------S---------}..... .....}|...{....+..........+.........\.S.................+...... .....}|........------------...........---------S---------}..... .....}|........|..........|...........|.......|.|.......|}..... }}}}}}|........|..........+...........|.......S.S.......|}}}}}} }-------------------------------+-----------------------------} }|.....+...............................................+.....|} }|.....|-----------------------------------------------|.....|} }-------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------} }}}}}}}}}.............................................}}}}}}}}} ENDMAP # Random registers initialisation RANDOM_OBJECTS:'[',')','*','%' RANDOM_PLACES:(04,02),(58,02),(04,14),(58,14) RANDOM_MONSTERS:'L','N','E','H','M','O','R','T','X','Z' TELEPORT_REGION:levregion(01,00,10,20),(1,1,61,15),down TELEPORT_REGION:levregion(69,00,79,20),(1,1,61,15),up STAIR:levregion(01,00,10,20),(0,0,62,16),up FOUNTAIN:(10,08) # Doors DOOR:closed,(07,03) DOOR:closed,(55,03) DOOR:locked,(32,04) DOOR:locked,(26,05) DOOR:locked,(46,05) DOOR:locked,(48,05) DOOR:locked,(47,07) DOOR:closed,(15,08) DOOR:closed,(26,08) DOOR:locked,(38,08) DOOR:locked,(56,08) DOOR:locked,(47,09) DOOR:locked,(26,11) DOOR:locked,(46,11) DOOR:locked,(48,11) DOOR:locked,(32,12) DOOR:closed,(07,13) DOOR:closed,(55,13) # The drawbridge DRAWBRIDGE:(05,08),east,closed # Storeroom number 1 OBJECT:object[0],random,(39,05) OBJECT:object[0],random,(40,05) OBJECT:object[0],random,(41,05) OBJECT:object[0],random,(42,05) OBJECT:object[0],random,(43,05) OBJECT:object[0],random,(44,05) OBJECT:object[0],random,(45,05) OBJECT:object[0],random,(39,06) OBJECT:object[0],random,(40,06) OBJECT:object[0],random,(41,06) OBJECT:object[0],random,(42,06) OBJECT:object[0],random,(43,06) OBJECT:object[0],random,(44,06) OBJECT:object[0],random,(45,06) # Storeroom number 2 OBJECT:object[1],random,(49,05) OBJECT:object[1],random,(50,05) OBJECT:object[1],random,(51,05) OBJECT:object[1],random,(52,05) OBJECT:object[1],random,(53,05) OBJECT:object[1],random,(54,05) OBJECT:object[1],random,(55,05) OBJECT:object[1],random,(49,06) OBJECT:object[1],random,(50,06) OBJECT:object[1],random,(51,06) OBJECT:object[1],random,(52,06) OBJECT:object[1],random,(53,06) OBJECT:object[1],random,(54,06) OBJECT:object[1],random,(55,06) # Storeroom number 3 OBJECT:object[2],random,(39,10) OBJECT:object[2],random,(40,10) OBJECT:object[2],random,(41,10) OBJECT:object[2],random,(42,10) OBJECT:object[2],random,(43,10) OBJECT:object[2],random,(44,10) OBJECT:object[2],random,(45,10) OBJECT:object[2],random,(39,11) OBJECT:object[2],random,(40,11) OBJECT:object[2],random,(41,11) OBJECT:object[2],random,(42,11) OBJECT:object[2],random,(43,11) OBJECT:object[2],random,(44,11) OBJECT:object[2],random,(45,11) # Storeroom number 4 OBJECT:object[3],random,(49,10) OBJECT:object[3],random,(50,10) OBJECT:object[3],random,(51,10) OBJECT:object[3],random,(52,10) OBJECT:object[3],random,(53,10) OBJECT:object[3],random,(54,10) OBJECT:object[3],random,(55,10) OBJECT:object[3],random,(49,11) OBJECT:object[3],random,(50,11) OBJECT:object[3],random,(51,11) OBJECT:object[3],random,(52,11) OBJECT:object[3],random,(53,11) OBJECT:object[3],random,(54,11) OBJECT:object[3],random,(55,11) # THE WAND OF WISHING in 1 of the 4 towers CONTAINER:'(',"chest",place[0] OBJECT:'/',"wishing",contained # Prevent monsters from eating it. (@'s never eat objects) ENGRAVING:place[0],burn,"Elbereth" # The treasure of the lord OBJECT:'(',"chest",(37,08) # Traps TRAP:"trap door",(40,08) TRAP:"trap door",(44,08) TRAP:"trap door",(48,08) TRAP:"trap door",(52,08) TRAP:"trap door",(55,08) # Soldiers guarding the entry hall MONSTER:'@',"soldier",(08,06) MONSTER:'@',"soldier",(09,05) MONSTER:'@',"soldier",(11,05) MONSTER:'@',"soldier",(12,06) MONSTER:'@',"soldier",(08,10) MONSTER:'@',"soldier",(09,11) MONSTER:'@',"soldier",(11,11) MONSTER:'@',"soldier",(12,10) MONSTER:'@',"lieutenant",(09,08) # Soldiers guarding the towers MONSTER:'@',"soldier",(03,02) MONSTER:'@',"soldier",(05,02) MONSTER:'@',"soldier",(57,02) MONSTER:'@',"soldier",(59,02) MONSTER:'@',"soldier",(03,14) MONSTER:'@',"soldier",(05,14) MONSTER:'@',"soldier",(57,14) MONSTER:'@',"soldier",(59,14) # The four dragons that are guarding the storerooms MONSTER:'D',random,(47,05) MONSTER:'D',random,(47,06) MONSTER:'D',random,(47,10) MONSTER:'D',random,(47,11) # Sea monsters in the moat MONSTER:';',"giant eel",(05,07) MONSTER:';',"giant eel",(05,09) MONSTER:';',"giant eel",(57,07) MONSTER:';',"giant eel",(57,09) MONSTER:';',"shark",(05,00) MONSTER:';',"shark",(05,16) MONSTER:';',"shark",(57,00) MONSTER:';',"shark",(57,16) # The throne room and the court monsters MONSTER:monster[0],random,(27,05) MONSTER:monster[1],random,(30,05) MONSTER:monster[2],random,(33,05) MONSTER:monster[3],random,(36,05) MONSTER:monster[4],random,(28,06) MONSTER:monster[5],random,(31,06) MONSTER:monster[6],random,(34,06) MONSTER:monster[7],random,(37,06) MONSTER:monster[8],random,(27,07) MONSTER:monster[9],random,(30,07) MONSTER:monster[0],random,(33,07) MONSTER:monster[1],random,(36,07) MONSTER:monster[2],random,(28,08) MONSTER:monster[3],random,(31,08) MONSTER:monster[4],random,(34,08) MONSTER:monster[5],random,(27,09) MONSTER:monster[6],random,(30,09) MONSTER:monster[7],random,(33,09) MONSTER:monster[8],random,(36,09) MONSTER:monster[9],random,(28,10) MONSTER:monster[0],random,(31,10) MONSTER:monster[1],random,(34,10) MONSTER:monster[2],random,(37,10) MONSTER:monster[3],random,(27,11) MONSTER:monster[4],random,(30,11) MONSTER:monster[5],random,(33,11) MONSTER:monster[6],random,(36,11) # MazeWalks MAZEWALK:(00,10),west MAZEWALK:(62,06),east # Non diggable walls NON_DIGGABLE:(00,00,62,16) # Subrooms: # Entire castle area REGION:(00,00,62,16),unlit,"ordinary" # Courtyards REGION:(00,05,05,11),lit,"ordinary" REGION:(57,05,62,11),lit,"ordinary" # Throne room REGION:(27,05,37,11),lit,"throne",unfilled # Antechamber REGION:(07,05,14,11),lit,"ordinary" # Storerooms REGION:(39,05,45,06),lit,"ordinary" REGION:(39,10,45,11),lit,"ordinary" REGION:(49,05,55,06),lit,"ordinary" REGION:(49,10,55,11),lit,"ordinary" # Corners REGION:(02,02,06,03),lit,"ordinary" REGION:(56,02,60,03),lit,"ordinary" REGION:(02,13,06,14),lit,"ordinary" REGION:(56,13,60,14),lit,"ordinary" # Barracks REGION:(16,05,25,06),lit,"barracks" REGION:(16,10,25,11),lit,"barracks" # Hallways REGION:(08,03,54,03),unlit,"ordinary" REGION:(08,13,54,13),unlit,"ordinary" REGION:(16,08,25,08),unlit,"ordinary" REGION:(39,08,55,08),unlit,"ordinary" # Storeroom alcoves REGION:(47,05,47,06),unlit,"ordinary" REGION:(47,10,47,11),unlit,"ordinary" nethack-3.4.3/dat/cmdhelp0100644000000000000000000001215107764735040013760 0ustar rootroot^ Show the type of a trap ^[ Cancel command ^A Redo the previous command ^C Quit the game ^D Kick something (usually a door, chest, or box) ^E Search a room (available in debug mode only) ^F Map the level (available in debug mode only) ^G Create a monster (available in debug mode only) ^I Identify all items (available in debug mode only) ^O Show location of special levels (available in debug mode only) ^P Toggle through previously displayed game messages ^R Redraw screen ^T Teleport around level ^V Teleport between levels (available in debug mode only) ^W Wish (available in debug mode only) ^X Show your attributes (intrinsic ones included in debug or explore mode) ^Z Suspend game (only if defined) a Apply (use) a tool A Remove all armor b Go southwest 1 space B Go southwest until you are on top of something ^B Go southwest until you are near something c Close a door C Call (name) a particular monster d Drop an item D Drop specific item types e Eat something E Engrave writing on the floor f Fire ammunition from quiver F Followed by direction, fight a monster (even if you don't sense it) g Followed by direction, move until you are near something G Followed by direction, same as control-direction h Go west 1 space (if number_pad is on, display help message) H Go west until you are on top of something ^H Go west until you are near something i Show your inventory I Inventory specific item types j Go south 1 space (or if number_pad is on, jump to another location) J Go south until you are on top of something ^J Go south until you are near something k Go north 1 space (or if number_pad is on, kick something) K Go north until you are on top of something ^K Go north until you are near something l Go east 1 space (or if number_pad is on, loot a box on the floor) L Go east until you are on top of something ^L Go east until you are near something m Followed by direction, move without picking anything up or fighting M Followed by direction, move a distance without picking anything up n Go southeast 1 space N Go southeast until you are on something (if number_pad, name an object) ^N Go southeast until you are near something o Open a door O Show option settings, possibly change them p Pay your shopping bill P Put on an accessory (ring, amulet, etc) q Quaff (drink) something (potion, water, etc) Q Select ammunition for quiver r Read a scroll or spellbook R Remove an accessory (ring, amulet, etc) s Search for traps and secret doors S Save the game t Throw something T Take off one piece of armor u Go northeast 1 space (or if number_pad is on, untrap something) U Go northeast until you are on top of something ^U Go northeast until you are near something v Show version V Show long version and game history w Wield (put in use) a weapon W Wear a piece of armor x Swap wielded and secondary weapons X Enter explore (discovery) mode (only if defined) y Go northwest 1 space Y Go northwest until you are on top of something ^Y Go northwest until you are near something z Zap a wand Z Zap (cast) a spell < Go up a staircase > Go down a staircase / Show what type of thing a symbol corresponds to ? Give a help message & Tell what a command does ! Do a shell escape (only if defined) \ Show what object types have been discovered _ Travel via a shortest-path algorithm to a point on the map . Rest one move while doing nothing Rest one move while doing nothing (if rest_on_space option is on) : Look at what is on the floor ; Show what type of thing a map symbol on the level corresponds to , Pick up things at the current location @ Toggle the pickup option on/off ) Show the weapon currently wielded [ Show the armor currently worn = Show the ring(s) currently worn " Show the amulet currently worn ( Show the tools currently in use * Show all equipment in use (combination of the ),[,=,",( commands) $ Count your gold + List known spells # Perform an extended command M-? Display extended command help (if the platform allows this) M-2 Toggle two-weapon combat (unless number_pad is enabled) M-a Adjust inventory letters M-c Talk to someone M-d Dip an object into something M-e Advance or check weapons skills M-f Force a lock M-i Invoke an object's special powers M-j Jump to another location M-l Loot a box on the floor M-m Use a monster's special ability M-n Name an item or type of object M-o Offer a sacrifice to the gods M-p Pray to the gods for help M-q Quit M-r Rub a lamp M-s Sit down M-t Turn undead M-u Untrap something (trap, door, or chest) M-v Print compile time options for this version of NetHack M-w Wipe off your face nethack-3.4.3/dat/data.base0100644000000000000000000062416207764735041014202 0ustar rootroot# SCCS Id: @(#)data.base 3.4 2003/07/23 # Copyright (c) 1994, 1995, 1996 by the NetHack Development Team # Copyright (c) 1994 by Boudewijn Wayers # NetHack may be freely redistributed. See license for details. # # This is the source file for the "data" file generated by `makedefs -d'. # A line starting with a # is a comment and is ignored by makedefs. # Any other line not starting with whitespace is a creature or an item. # # Each entry should be comprised of: # the thing/person being described on a line by itself, in lowercase; # on each succeeding line a description. # # If the first character of a key field is "~", then anything which matches # the rest of that key will be treated as if it did not match any of the # following keys for that entry. For instance, `~orc ??m*' preceding `orc*' # prevents "orc mummy" and "orc zombie" from matching. # abbot For it had been long apparent to Count Landulf that nothing could be done with his seventh son Thomas, except to make him an Abbot or something of that kind. Born in 1226, he had from childhood a mysterious objection to becoming a predatory eagle, or even to taking an ordinary interest in falconry or tilting or any other gentlemanly pursuits. He was a large and heavy and quiet boy, and phenomenally silent, scarcely opening his mouth except to say suddenly to his schoolmaster in an explosive manner, "What is God?" The answer is not recorded but it is probable that the asker went on worrying out answers for himself. [ The Runaway Abbot, by G. K. Chesterton ] aclys aklys A short studded or spiked club attached to a cord allowing it to be drawn back to the wielder after having been thrown. It should not be confused with the atlatl, which is a device used to throw spears for longer distances. aleax Said to be a doppelganger sent to inflict divine punishment for alignment violations. *altar Altars are of three types: 1. In Temples. These are for Sacrifices [...]. The stone top will have grooves for blood, and the whole will be covered with _dry brown stains of a troubling kind_ from former Sacrifices. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] To every man upon this earth Death cometh soon or late; And how can man die better Than facing fearful odds For the ashes of his fathers And the temples of his gods? [ Lays of Ancient Rome, by Thomas B. Macaulay ] amaterasu omikami The Shinto sun goddess, Amaterasu Omikami is the central figure of Shintoism and the ancestral deity of the imperial house. One of the daughters of the primordial god Izanagi and said to be his favourite offspring, she was born from his left eye. [ Encyclopedia of Gods, by Michael Jordan ] amber* "Tree sap," Wu explained, "often flows over insects and traps them. The insects are then perfectly preserved within the fossil. One finds all kinds of insects in amber - including biting insects that have sucked blood from larger animals." [ Jurassic Park, by Michael Crichton ] *amnesia maud Get thee hence, nor come again, Mix not memory with doubt, Pass, thou deathlike type of pain, Pass and cease to move about! 'Tis the blot upon the brain That will show itself without. ... For, Maud, so tender and true, As long as my life endures I feel I shall owe you a debt, That I never can hope to pay; And if ever I should forget That I owe this debt to you And for your sweet sake to yours; O then, what then shall I say? - If ever I should forget, May God make me more wretched Than ever I have been yet! [ Maud, And Other Poems by Alfred, Lord Tennyson ] ~amulet of yendor *amulet amulet of * "The complete Amulet can keep off all the things that make people unhappy -- jealousy, bad temper, pride, disagreeableness, greediness, selfishness, laziness. Evil spirits, people called them when the Amulet was made. Don't you think it would be nice to have it?" "Very," said the children, quite without enthusiasm. "And it can give you strength and courage." "That's better," said Cyril. "And virtue." "I suppose it's nice to have that," said Jane, but not with much interest. "And it can give you your heart's desire." "Now you're talking," said Robert. [ The Story of the Amulet, by Edith Nesbit ] amulet of yendor This mysterious talisman is the object of your quest. It is said to possess powers which mere mortals can scarcely comprehend, let alone utilize. The gods will grant the gift of immortality to the adventurer who can deliver it from the depths of Moloch's Sanctum and offer it on the appropriate high altar on the Astral Plane. angel* He answered and said unto them, he that soweth the good seed is the Son of man; the field is the world, and the good seed are the children of the kingdom; but the weeds are the children of the wicked one; the enemy that sowed them is the devil; the harvest is the end of the world; and the reapers are the angels. As therefore the weeds are gathered and burned in the fire; so shall it be in the end of this world. [...] So shall it be at the end of the world; the angels shall come forth, and sever the wicked from among the just, and shall cast them into the furnace of fire; there shall be wailing and gnashing of teeth. [ The Gospel According to Matthew, 13:37-42, 49-50 ] anhur An Egyptian god of war and a great hunter, few gods can match his fury. Unlike many gods of war, he is a force for good. The wrath of Anhur is slow to come, but it is inescapable once earned. Anhur is a mighty figure with four arms. He is often seen with a powerful lance that requires both of his right arms to wield and which is tipped with a fragment of the sun. He is married to Mehut, a lion-headed goddess. ankh-morpork The twin city of Ankh-Morpork, foremost of all the cities bounding the Circle Sea, was as a matter of course the home of a large number of gangs, thieves' guilds, syndicates and similar organisations. This was one of the reasons for its wealth. Most of the humbler folk on the widdershin side of the river, in Morpork's mazy alleys, supplemented their meagre incomes by filling some small role for one or other of the competing gangs. [ The Colour of Magic by Terry Pratchett ] anshar A primordial Babylonian-Akkadian deity, Anshar is mentioned in the Babylonian creation epic _Enuma Elish_ as one of a pair of offspring (with Kishar) of Lahmu and Lahamu. Anshar is linked with heaven while Kishar is identified with earth. [ Encyclopedia of Gods, by Michael Jordan ] ant * ant This giant variety of the ordinary ant will fight just as fiercely as its small, distant cousin. Various varieties exist, and they are known and feared for their relentless persecution of their victims. anu Anu was the Babylonian god of the heavens, the monarch of the north star. He was the oldest of the Babylonian gods, the father of all gods, and the ruler of heaven and destiny. Anu features strongly in the _atiku_ festival in Babylon, Uruk and other cities. ape * ape The most highly evolved of all the primates, as shown by all their anatomical characters and particularly the development of the brain. Both arboreal and terrestrial, the apes have the forelimbs much better developed than the hind limbs. Tail entirely absent. Growth is slow and sexual maturity reached at quite an advanced age. [ A Field Guide to the Larger Mammals of Africa by Dorst ] Aldo the gorilla had a plan. It was a good plan. It was right. He knew it. He smacked his lips in anticipation as he thought of it. Yes. Apes should be strong. Apes should be masters. Apes should be proud. Apes should make the Earth shake when they walked. Apes should _rule_ the Earth. [ Battle for the Planet of the Apes, by David Gerrold ] apple NEWTONIAN, adj. Pertaining to a philosophy of the universe invented by Newton, who discovered that an apple will fall to the ground, but was unable to say why. His successors and disciples have advanced so far as to be able to say when. [ The Devil's Dictionary, by Ambrose Bierce ] archeologist * archeologist Archeology is the search for fact, not truth. [...] So forget any ideas you've got about lost cities, exotic travel, and digging up the world. We do not follow maps to buried treasure, and X never, ever, marks the spot. [ Indiana Jones and the Last Crusade ] archon Archons are the predominant inhabitants of the heavens. However unusual their appearance, they are not generally evil. They are beings at peace with themselves and their surroundings. arioch Arioch, the patron demon of Elric's ancestors; one of the most powerful of all the Dukes of Hell, who was called Knight of the Swords, Lord of the Seven Darks, Lord of the Higher Hell and many more names besides. [ Elric of Melnibone, by Michael Moorcock ] *arrow I shot an arrow into the air, It fell to earth, I knew not where; For, so swiftly it flew, the sight Could not follow it in its flight. I breathed a song into the air, It fell to earth, I knew not where; For who has sight so keen and strong That it can follow the flight of song? Long, long afterward, in an oak I found the arrow still unbroke; And the song, from beginning to end, I found again in the heart of a friend. [ The Arrow and the Song, by Henry Wadsworth Longfellow ] ashikaga takauji Ashikaga Takauji was a daimyo of the Minamoto clan who joined forces with the Go-Daigo to defeat the Hojo armies. Later when Go-Daigo attempted to reduce the powers of the samurai clans he rebelled against him. He defeated Go- Daigo and established the emperor Komyo on the throne. Go-Daigo eventually escaped and established another government in the town of Yoshino. This period of dual governments was known as the Nambokucho. [ Samurai - The Story of a Warrior Tradition, by Cook ] asmodeus It is said that Asmodeus is the overlord over all of hell. His appearance, unlike many other demons and devils, is human apart from his horns and tail. He can freeze flesh with a touch. athame The consecrated ritual knife of a Wiccan initiate (one of four basic tools, together with the wand, chalice and pentacle). Traditionally, the athame is a double-edged, black-handled, cross-hilted dagger of between six and eighteen inches length. athen* Athene was the offspring of Zeus, and without a mother. She sprang forth from his head completely armed. Her favourite bird was the owl, and the plant sacred to her is the olive. [ Bulfinch's Mythology by Thomas Bulfinch ] axolotl A mundane salamander, harmless. bag bag of * sack "Now, this third handkerchief," Mein Herr proceeded, "has also four edges, which you can trace continuously round and round: all you need do is to join its four edges to the four edges of the opening. The Purse is then complete, and its outer surface--" "I see!" Lady Muriel eagerly interrupted. "Its outer surface will be continuous with its inner surface! But it will take time. I'll sew it up after tea." She laid aside the bag, and resumed her cup of tea. "But why do you call it Fortunatus's Purse, Mein Herr?" The dear old man beamed upon her, with a jolly smile, looking more exactly like the Professor than ever. "Don't you see, my child--I should say Miladi? Whatever is inside that Purse, is outside it; and whatever is outside it, is inside it. So you have all the wealth of the world in that leetle Purse!" [ Sylvie and Bruno Concluded, by Lewis Carroll ] b*lzebub The "lord of the flies" is a translation of the Hebrew Ba'alzevuv (Beelzebub in Greek). It has been suggested that it was a mistranslation of a mistransliterated word which gave us this pungent and suggestive name of the Devil, a devil whose name suggests that he is devoted to decay, destruction, demoralization, hysteria and panic... [ Notes on _Lord of the Flies_, by E. L. Epstein ] balrog ... It came to the edge of the fire and the light faded as if a cloud had bent over it. Then with a rush it leaped the fissure. The flames roared up to greet it, and wreathed about it; and a black smoke swirled in the air. Its streaming mane kindled, and blazed behind it. In its right hand was a blade like a stabbing tongue of fire; in its left it held a whip of many thongs. 'Ai, ai!' wailed Legolas. 'A Balrog! A Balrog is come!' [ The Fellowship of the Ring, by J.R.R. Tolkien ] baluchitherium titanothere Extinct rhinos include a variety of forms, the most spectacular being _Baluchitherium_ from the Oligocene of Asia, which is the largest known land mammal. Its body, 18 feet high at the shoulder and carried on massive limbs, allowed the 4-foot-long head to browse on the higher branches of trees. Though not as enormous, the titanotheres of the early Tertiary were also large perissodactyls, _Brontotherium_ of the Oligocene being 8 feet high at the shoulder. [ Prehistoric Animals, by Barry Cox ] banana He took another step and she cocked her right wrist in viciously. She heard the spring click. Weight slapped into her hand. "Here!" she shrieked hysterically, and brought her arm up in a hard sweep, meaning to gut him, leaving him to blunder around the room with his intestines hanging out in steaming loops. Instead he roared laughter, hands on his hips, flaming face cocked back, squeezing and contorting with great good humor. "Oh, my dear!" he cried, and went off into another gale of laughter. She looked stupidly down at her hand. It held a firm yellow banana with a blue and white Chiquita sticker on it. She dropped it, horrified, to the carpet, where it became a sickly yellow grin, miming Flagg's own. "You'll tell," he whispered. "Oh yes indeed you will." And Dayna knew he was right. [ The Stand, by Stephen King ] barbarian * barbarian They dressed alike -- in buckskin boots, leathern breeks and deerskin shirts, with broad girdles that held axes and short swords; and they were all gaunt and scarred and hard-eyed; sinewy and taciturn. They were wild men, of a sort, yet there was still a wide gulf between them and the Cimmerian. They were sons of civilization, reverted to a semi-barbarism. He was a barbarian of a thousand generations of barbarians. They had acquired stealth and craft, but he had been born to these things. He excelled them even in lithe economy of motion. They were wolves, but he was a tiger. [ Conan - The Warrior, by Robert E. Howard ] barbed devil Barbed devils lack any real special abilities, though they are quite difficult to kill. *bat A bat, flitting in the darkness outside, took the wrong turn as it made its nightly rounds and came in through the window which had been left healthfully open. It then proceeded to circle the room in the aimless fat-headed fashion habitual with bats, who are notoriously among the less intellectually gifted of God's creatures. Show me a bat, says the old proverb, and I will show you something that ought to be in some kind of a home. [ A Pelican at Blandings, by P. G. Wodehouse ] *bee This giant variety of its useful normal cousin normally appears in small groups, looking for raw material to produce the royal jelly needed to feed their queen. On rare occasions, one may stumble upon a bee-hive, in which the queen bee is being well provided for, and guarded against intruders. *beetle [ The Creator ] has an inordinate fondness for beetles. [ attributed to biologist J.B.S. Haldane ] The common name for the insects with wings shaped like shields (_Coleoptera_), one of the ten sub-species into which the insects are divided. They are characterized by the shields (the front pair of wings) under which the back wings are folded. [ Van Dale's Groot Woordenboek der Nederlandse Taal ] bell of opening "A bell, book and candle job." The Bursar sighed. "We tried that, Archchancellor." The Archchancellor leaned towards him. "Eh?" he said. "I _said_, we tried that Archchancellor," said the Bursar loudly, directing his voice at the old man's ear. "After dinner, you remember? We used Humptemper's _Names of the Ants_ and rang Old Tom."* "Did we, indeed. Worked, did it?" "_No_, Archchancellor." * Old Tom was the single cracked bronze bell in the University bell tower. [ Eric, by Terry Pratchett ] blindfold The blindfolding was performed by binding a piece of the yellowish linen whereof those of the Amahagger who condescended to wear anything in particular made their dresses tightly round the eyes. This linen I afterwards discovered was taken from the tombs, and was not, as I had first supposed, of native manufacture. The bandage was then knotted at the back of the head, and finally brought down again and the ends bound under the chin to prevent its slipping. Ustane was, by the way, also blindfolded, I do not know why, unless it was from fear that she should impart the secrets of the route to us. [ She, by H. Rider Haggard ] blind io On this particular day Blind Io, by dint of constant vigilance the chief of the gods, sat with his chin on his hand and looked at the gaming board on the red marble table in front of him. Blind Io had got his name because, where his eye sockets should have been, there were nothing but two areas of blank skin. His eyes, of which he had an impressively large number, led a semi-independent life of their own. Several were currently hovering above the table. [ The Colour of Magic, by Terry Pratchett ] * blob gelatinous cube ooze * ooze *pudding * slime These giant amoeboid creatures look like nothing more than puddles of slime, but they both live and move, feeding on metal or wood as well as the occasional dungeon explorer to supplement their diet. But we were not on a station platform. We were on the track ahead as the nightmare, plastic column of fetid black iridescence oozed tightly onward through its fifteen-foot sinus, gathering unholy speed and driving before it a spiral, re-thickening cloud of the pallid abyss vapor. It was a terrible, indescribable thing vaster than any subway train -- a shapeless congeries of protoplasmic bubbles, faintly self-luminous, and with myriads of temporary eyes forming and unforming as pustules of greenish light all over the tunnel-filling front that bore down upon us, crushing the frantic penguins and slithering over the glistening floor that it and its kind had swept so evilly free of all litter. [ At the Mountains of Madness, by H.P. Lovecraft ] bone devil Bone devils attack with weapons and with a great hooked tail which causes a loss of strength to those they sting. book of the dead candelabrum* *candle Faustus: Come on Mephistopheles. What shall we do? Mephistopheles: Nay, I know not. We shall be cursed with bell, book, and candle. Faustus: How? Bell, book, and candle, candle, book, and bell, Forward and backward, to curse Faustus to hell. Anon you shall hear a hog grunt, a calf bleat, and an ass bray, Because it is Saint Peter's holy day. (Enter all the Friars to sing the dirge) [ Doctor Faustus and Other Plays, by Christopher Marlowe ] *boot* In Fantasyland these are remarkable in that they seldom or never wear out and are suitable for riding or walking in without the need of Socks. Boots never pinch, rub, or get stones in them; nor do nails stick upwards into the feet from the soles. They are customarily mid-calf length or knee-high, slip on and off easily and never smell of feet. Unfortunately, the formula for making this splendid footwear is a closely guarded secret, possibly derived from nonhumans (see Dwarfs, Elves, and Gnomes). [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] boulder I worked the lever well under, and stretched my back; the end of the stone rose up, and I kicked the fulcrum under. Then, when I was going to bear down, I remembered there was something to get out from below; when I let go of the lever, the stone would fall again. I sat down to think, on the root of the oak tree; and, seeing it stand about the ground, I saw my way. It was lucky I had brought a longer lever. It would just reach to wedge under the oak root. Bearing it down so far would have been easy for a heavy man, but was a hard fight for me. But this time I meant to do it if it killed me, because I knew it could be done. Twice I got it nearly there, and twice the weight bore it up again; but when I flung myself on it the third time, I heard in my ears the sea-sound of Poseidon. Then I knew this time I would do it; and so I did. [ The King Must Die, by Mary Renault ] ~*longbow of diana bow * bow "Stand to it, my hearts of gold," said the old bowman as he passed from knot to knot. "By my hilt! we are in luck this journey. Bear in mind the old saying of the Company." "What is that, Aylward?" cried several, leaning on their bows and laughing at him. "'Tis the master-bowyer's rede: 'Every bow well bent. Every shaft well sent. Every stave well nocked. Every string well locked.' There, with that jingle in his head, a bracer on his left hand, a shooting glove on his right, and a farthing's-worth of wax in his girdle, what more doth a bowman need?" "It would not be amiss," said Hordle John, "if under his girdle he had four farthings'-worth of wine." [ The White Company, by Sir Arthur Conan Doyle ] brigit Brigit (Brigid, Bride, Banfile), which means the Exalted One, was the Celtic (continental European and Irish) fertility goddess. She was originally celebrated on February first in the festival of Imbolc, which coincided with the beginning of lactation in ewes and was regarded in Scotland as the date on which Brigit deposed the blue-faced hag of winter. The Christian calendar adopted the same date for the Feast of St. Brigit. There is no record that a Christian saint ever actually existed, but in Irish mythology she became the midwife to the Virgin Mary. [ Encyclopedia of Gods, by Michael Jordan ] ~stormbringer *broadsword Bring me my broadsword And clear understanding. Bring me my cross of gold, As a talisman. [ "Broadsword" (refrain) by Ian Anderson ] bugbear Bugbears are relatives of goblins, although they tend to be larger and more hairy. They are aggressive carnivores and sometimes kill just for the treasure their victims may be carrying. bugle 'I read you by your bugle horn And by your palfrey good, I read you for a Ranger sworn To keep the King's green-wood.' 'A Ranger, Lady, winds his horn, And 'tis at peep of light; His blast is heard at merry morn, And mine at dead of night.' [ Brignall Banks, by Sir Walter Scott ] *camaxtli A classical Mesoamerican Aztec god, also known as Mixcoatl- Camaxtli (the Cloud Serpent), Camaxtli is the god of war. He is also a deity of hunting and fire who received human sacrifice of captured prisoners. According to tradition, the sun god Tezcatlipoca transformed himself into Mixcoatl-Camaxtli to make fire by twirling the sacred fire sticks. [ Encyclopedia of Gods, by Michael Jordan ] candy bar Only once a year, on his birthday, did Charlie Bucket ever get to taste a bit of chocolate. The whole family saved up their money for that special occasion, and when the great day arrived, Charlie was always presented with one small chocolate bar to eat all by himself. And each time he received it, on those marvelous birthday mornings, he would place it carefully in a small wooden box that he owned, and treasure it as though it were a bar of solid gold; and for the next few days, he would allow himself only to look at it, but never to touch it. Then at last, when he could stand it no longer, he would peel back a tiny bit of the paper wrapping at one corner to expose a tiny bit of chocolate, and then he would take a tiny nibble - just enough to allow the lovely sweet taste to spread out slowly over his tongue. The next day, he would take another tiny nibble, and so on, and so on. And in this way, Charlie would make his ten-cent bar of birthday chocolate last him for more than a month. [ Charlie and the Chocolate Factory, by Roald Dahl ] s*d*g*r* cat Imagine a sealed container, so perfectly constructed that no physical influence can pass either inwards or outwards across its walls. Imagine that inside the container is a cat, and also a device that can be triggered by some quantum event. If that event takes place, then the device smashes a phial containing cyanide and the cat is killed. If the event does not take place, the cat lives on. In Schroedinger's original version, the quantum event was the decay of a radioactive atom. ... To the outside observer, the cat is indeed in a linear combination of being alive and dead, and only when the container is finally opened would the cat's state vector collapse into one or the other. On the other hand, to a (suitably protected) observer inside the container, the cat's state-vector would have collapsed much earlier, and the outside observer's linear combination has no relevance. [ The Emperor's New Mind, by Roger Penrose ] *cat kitten Well-known quadruped domestic animal from the family of predatory felines (_Felis ochreata domestica_), with a thick, soft pelt; often kept as a pet. Various folklores have the cat associated with magic and the gods of ancient Egypt. So Ulthar went to sleep in vain anger; and when the people awakened at dawn - behold! Every cat was back at his accustomed hearth! Large and small, black, grey, striped, yellow and white, none was missing. Very sleek and fat did the cats appear, and sonorous with purring content. [ The Cats of Ulthar, by H.P. Lovecraft ] # this one doesn't work very well for dwarven and gnomish cavemen cave*man human cave*man Now it was light enough to leave. Moon-Watcher picked up the shriveled corpse and dragged it after him as he bent under the low overhang of the cave. Once outside, he threw the body over his shoulder and stood upright - the only animal in all this world able to do so. Among his kind, Moon-Watcher was almost a giant. He was nearly five feet high, and though badly undernourished weighed over a hundred pounds. His hairy, muscular body was halfway between ape and man, but his head was already much nearer to man than ape. The forehead was low, and there were ridges over the eye sockets, yet he unmistakably held in his genes the promise of humanity. [ 2001: A Space Odyssey, by Arthur C. Clarke ] *centaur Of all the monsters put together by the Greek imagination the Centaurs (Kentauroi) constituted a class in themselves. Despite a strong streak of sensuality, in their make-up, their normal behaviour was moral, and they took a kindly thought of man's welfare. The attempted outrage of Nessos on Deianeira, and that of the whole tribe of Centaurs on the Lapith women, are more than offset by the hospitality of Pholos and by the wisdom of Cheiron, physician, prophet, lyrist, and the instructor of Achilles. Further, the Centaurs were peculiar in that their nature, which united the body of a horse with the trunk and head of a man, involved an unthinkable duplication of vital organs and important members. So grotesque a combination seems almost un-Greek. These strange creatures were said to live in the caves and clefts of the mountains, myths associating them especially with the hills of Thessaly and the range of Erymanthos. [ Mythology of all races, Vol. 1, pp. 270-271 ] centipede I observed here, what I had often seen before, that certain districts abound in centipedes. Here they have light reddish bodies and blue legs; great myriapedes are seen crawling every where. Although they do no harm, they excite in man a feeling of loathing. Perhaps our appearance produces a similar feeling in the elephant and other large animals. Where they have been much disturbed, they certainly look upon us with great distrust, as the horrid biped that ruins their peace. [ Travels and Researches in South Africa, by Dr. David Livingstone ] cerberus kerberos Cerberus, (or Kerberos in Greek), was the three-headed dog that guarded the Gates of Hell. He allowed any dead to enter, and likewise prevented them all from ever leaving. He was bested only twice: once when Orpheus put him to sleep by playing bewitching music on his lyre, and the other time when Hercules confronted him and took him to the world of the living (as his twelfth and last labor). chameleon Name of a family (_Chameleonidae_) and race (_Chameleo_) of scaly lizards, especially the _Chameleo vulgaris_ species, with a short neck, claws, a grasping tail, a long, extendible tongue and mutually independent moving eyes. When it is scared or angry, it inflates itself and its transparent skin shows its blood: the skin first appears greenish, then gradually changes color until it is a spotted red. The final color depends on the background color as well, hence the (figurative) implication of unreliability. [Capitalized:] a constellation of the southern hemisphere (Chameleo). [ Van Dale's Groot Woordenboek der Nederlandse Taal ] charo*n When an ancient Greek died, his soul went to the nether world: the Hades. To reach the nether world, the souls had to cross the river Styx, the river that separated the living from the dead. The Styx could be crossed by ferry, whose shabby ferry- man, advanced in age, was called Charon. The deceased's next- of-kin would place a coin under his tongue, to pay the ferry- man. chest large box Dantes rapidly cleared away the earth around the chest. Soon the center lock appeared, then the handles at each end, all delicately wrought in the manner of that period when art made precious even the basest of metals. He took the chest by the two handles and tried to lift it, but it was impossible. He tried to open it; it was locked. He inserted the sharp end of his pickaxe between the chest and the lid and pushed down on the handle. The lid creaked, then flew open. Dantes was seized with a sort of giddy fever. He cocked his gun and placed it beside him. The he closed his eyes like a child, opened them and stood dumbfounded. The chest was divided into three compartments. In the first were shining gold coins. In the second, unpolished gold ingots packed in orderly stacks. From the third compartment, which was half full, Dantes picked up handfuls of diamonds, pearls and rubies. As they fell through his fingers in a glittering cascade, they gave forth the sound of hail beating against the windowpanes. [ The Count of Monte Cristo, by Alexandre Dumas ] chih*sung*tzu A Chinese rain god. chromatic dragon tiamat Tiamat is said to be the mother of evil dragonkind. She is extremely vain. ~elven cloak ~oilskin cloak *cloak* Cloaks are the universal outer garb of everyone who is not a Barbarian. It is hard to see why. They are open in front and require you at most times to use one hand to hold them shut. On horseback they leave the shirt-sleeved arms and most of the torso exposed to wind and Weather. The OMTs [ Official Management Terms ] for Cloaks well express their difficulties. They are constantly _swirling and dripping_ and becoming _heavy with water_ in rainy Weather, _entangling with trees_ or _swords_, or needing to be _pulled close around her/his shivering body_. This seems to suggest they are less than practical for anyone on an arduous Tour. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] cloud* I wandered lonely as a cloud That floats on high o'er vales and hills, When all at once I saw a crowd, A host, of golden daffodils; Beside the lake, beneath the trees, Fluttering and dancing in the breeze. [ I Wandered Lonely as a Cloud, by William Wordsworth ] cobra Darzee and his wife only cowered down in the nest without answering, for from the thick grass at the foot of the bush there came a low hiss -- a horrid cold sound that made Rikki-tikki jump back two clear feet. Then inch by inch out of the grass rose up the head and spread hood of Nag, the big black cobra, and he was five feet long from tongue to tail. When he had lifted one-third of himself clear of the ground, he stayed balancing to and fro exactly as a dandelion-tuft balances in the wind, and he looked at Rikki-tikki with the wicked snake's eyes that never change their expression, whatever the snake may be thinking of. 'Who is Nag?' said he. '_I_ am Nag. The great God Brahm put his mark upon all our people, when the first cobra spread his hood to keep the sun off Brahm as he slept. Look, and be afraid!' [ Rikki-tikki-tavi, by Rudyard Kipling ] c*ckatrice Once in a great while, when the positions of the stars are just right, a seven-year-old rooster will lay an egg. Then, along will come a snake, to coil around the egg, or a toad, to squat upon the egg, keeping it warm and helping it to hatch. When it hatches, out comes a creature called basilisk, or cockatrice, the most deadly of all creatures. A single glance from its yellow, piercing toad's eyes will kill both man and beast. Its power of destruction is said to be so great that sometimes simply to hear its hiss can prove fatal. Its breath is so venomous that it causes all vegetation to wither. There is, however, one creature which can withstand the basilisk's deadly gaze, and this is the weasel. No one knows why this is so, but although the fierce weasel can slay the basilisk, it will itself be killed in the struggle. Perhaps the weasel knows the basilisk's fatal weakness: if it ever sees its own reflection in a mirror it will perish instantly. But even a dead basilisk is dangerous, for it is said that merely touching its lifeless body can cause a person to sicken and die. [ Mythical Beasts by Deirdre Headon (The Leprechaun Library) and other sources ] cornuthaum He was dressed in a flowing gown with fur tippets which had the signs of the zodiac embroidered over it, with various cabalistic signs, such as triangles with eyes in them, queer crosses, leaves of trees, bones of birds and animals, and a planetarium whose stars shone like bits of looking-glass with the sun on them. He had a pointed hat like a dunce's cap, or like the headgear worn by ladies of that time, except that the ladies were accustomed to have a bit of veil floating from the top of it. [ The Once and Future King, by T.H. White ] "A wizard!" Dooley exclaimed, astounded. "At your service, sirs," said the wizard. "How perceptive of you to notice. I suppose my hat rather gives me away. Something of a beacon, I don't doubt." His hat was pretty much that, tall and cone-shaped with stars and crescent moons all over it. All in all, it couldn't have been more wizardish. [ The Elfin Ship, James P. Blaylock ] couatl A mythical feathered serpent. The couatl are very rare. coyote This carnivore is known for its voracious appetite and inflated view of its own intelligence. cram* If you want to know what cram is, I can only say that I don't know the recipe; but it is biscuitish, keeps good indefinitely, is supposed to be sustaining, and is certainly not entertaining, being in fact very uninteresting except as a chewing exercise. It was made by the Lake-men for long journeys. [ The Hobbit, by J.R.R. Tolkien ] *crocodile A big animal with the appearance of a lizard, constituting an order of the reptiles (_Loricata_ or _Crocodylia_), the crocodile is a large, dangerous predator native to tropical and subtropical climes. It spends most of its time in large bodies of water. croesus kroisos creosote Croesus (in Greek: Kroisos), the wealthy last king of Lydia; his empire was destroyed when he attacked Cyrus in 549, after the Oracle of Delphi (q.v.) had told him: "if you attack the Persians, you will destroy a mighty empire". Herodotus relates of his legendary conversation with Solon of Athens, who impressed upon him that being rich does not imply being happy and that no one should be considered fortunate before his death. crom Warily Conan scanned his surroundings, all of his senses alert for signs of possible danger. Off in the distance, he could see the familiar shapes of the Camp of the Duali tribe. Suddenly, the hairs on his neck stand on end as he detects the aura of evil magic in the air. Without thought, he readies his weapon, and mutters under his breath: "By Crom, there will be blood spilt today." [ Conan the Avenger by Robert E. Howard, Bjorn Nyberg, and L. Sprague de Camp ] crossbow* "God save thee, ancient Mariner! From the fiends, that plague thee thus! - Why look'st thou so?" - With my cross-bow I shot the Albatross. [ The Rime of the Ancient Mariner, by Samuel Taylor Coleridge ] crystal ball You look into one of these and see _vapours swirling like clouds_. These shortly clear away to show a sort of video without sound of something that is going to happen to you soon. It is seldom good news. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] curse* Curses are longstanding ill-wishings which, in Fantasyland, often manifest as semisentient. They have to be broken or dispelled. The method varies according to the type and origin of the Curse: [...] 4. Curses on Rings and Swords. You have problems. Rings have to be returned whence they came, preferably at over a thousand degrees Fahrenheit, and the Curse means you won't want to do this. Swords usually resist all attempts to raise their Curses. Your best source is to hide the Sword or give it to someone you dislike. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] cwn*n A pack of snow-white, red-eared spectral hounds which sometimes took part in the kidnappings and raids the inhabitants of the underworld sometimes make on this world (the Wild Hunt). They are associated in Wales with the sounds of migrating wild geese, and are said to be leading the souls of the damned to hell. The phantom chase is usually heard or seen in midwinter and is accompanied by a howling wind. [ Encyclopedia Mythica, ed. M.F. Lindemans ] cyclops And after he had milked his cattle swiftly, he again took hold of two of my men and had them as his supper. Then I went, with a tub of red wine, to stand before the Cyclops, saying: "A drop of wine after all this human meat, so you can taste the delicious wine that is stored in our ship, Cyclops." He took the tub and emptied it. He appreciated the priceless wine that much that he promptly asked me for a second tub. "Give it", he said, "and give me your name as well". ... Thrice I filled the tub, and after the wine had clouded his mind, I said to him, in a tone as sweet as honey: "You have asked my name, Cyclops? Well, my name is very well known. I'll give it to you, if you give me the gift you promised me as a guest. My name is Nobody. All call me thus: my father and my mother and my friends." Ruthlessly he answered to this: "Nobody, I will eat you last of all; your host of friends will completely precede you. That will be my present to you, my friend." And after these words he fell down backwards, restrained by the all-restrainer Hupnos. His monstrous neck slid into the dust; the red wine squirted from his throat; the drunk vomited lumps of human flesh. [ The Odyssey, (chapter Epsilon), by Homer ] ~sting *dagger Is this a dagger which I see before me, The handle toward my hand? Come, let me clutch thee. I have thee not, and yet I see thee still. Art thou not, fatal vision, sensible To feeling as to sight? or art thou but A dagger of the mind, a false creation, Proceeding from the heat-oppressed brain? I see thee yet, in form as palpable As this which now I draw. [ Macbeth, by William Shakespeare ] dark one ... But he ruled rather by force and fear, if they might avail; and those who perceived his shadow spreading over the world called him the Dark Lord and named him the Enemy; and he gathered again under his government all the evil things of the days of Morgoth that remained on earth or beneath it, and the Orcs were at his command and multiplied like flies. Thus the Black Years began ... [ The Silmarillion, by J.R.R. Tolkien ] demogorgon Demogorgon, the prince of demons, wallows in filth and can spread a quickly fatal illness to his victims while rending them. He is a mighty spellcaster, and he can drain the life of mortals with a touch of his tail. demon It is often very hard to discover what any given Demon looks like, apart from a general impression of large size, huge fangs, staring eyes, many limbs, and an odd color; but all accounts agree that Demons are very powerful, very Magic (in a nonhuman manner), and made of some substance that can squeeze through a keyhole yet not be pierced with a Sword. This makes them difficult to deal with, even on the rare occasions when they are friendly. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] dingo A wolflike wild dog, Canis dingo, of Australia, having a reddish- or yellowish-brown coat, believed to have been introduced by the aborigines. [Webster's Encyclopedic Unabridged Dictionary of the English Language] disenchanter Ask not, what your magic can do to it. Ask what it can do to your magic. dispater Dispater is an arch-devil who rules the city of Dis. He is a powerful mage. djinn* The djinn are genies from the elemental plane of Air. There, among their kind, they have their own societies. They are sometimes encountered on earth and may even be summoned here to perform some service for powerful wizards. The wizards often leave them about for later service, safely tucked away in a flask or lamp. Once in a while, such a tool is found by a lucky rogue, and some djinn are known to be so grateful when released that they might grant their rescuer a wish. ~hachi ~slasher ~sirius *dog pup* A domestic animal, the _tame dog_ (_Canis familiaris_), of which numerous breeds exist. The male is called a dog, while the female is called a bitch. Because of its known loyalty to man and gentleness with children, it is the world's most popular domestic animal. It can easily be trained to perform various tasks. ~trap*door *door doorway Through me you pass into the city of woe: Through me you pass into eternal pain: Through me among the people lost for aye. Justice the founder of my fabric mov'd: To rear me was the task of power divine, Supremest wisdom, and primeval love. Before me things create were none, save things Eternal, and eternal I endure. All hope abandon ye who enter here. [ The Inferno, from The Divine Comedy of Dante Alighieri, translated by H.F. Cary ] doppelganger "Then we can only give thanks that this is Antarctica, where there is not one, single, solitary, living thing for it to imitate, except these animals in camp." "Us," Blair giggled. "It can imitate us. Dogs can't make four hundred miles to the sea; there's no food. There aren't any skua gulls to imitate at this season. There aren't any penguins this far inland. There's nothing that can reach the sea from this point - except us. We've got brains. We can do it. Don't you see - it's got to imitate us - it's got to be one of us - that's the only way it can fly an airplane - fly a plane for two hours, and rule - be - all Earth's inhabitants. A world for the taking - if it imitates us! [ Who Goes There?, by John W. Campbell ] Xander: Let go! I have to kill the demon bot! Xander Double (grabbing the gun): Anya, get out of the way. Buffy: Xander! Xander Double: That's all right, Buffy. I have him. Xander: No, Buffy, I'm me. Help me! Anya: My gun, he's got my gun. Riley: You own a gun? Buffy: Xander, gun holding Xander, give it to me. Anya: Buffy, which one's real? Xander: I am. Xander Double: No, _I_ am. [ Buffy the Vampire Slayer, Episode 5.03, "The Replacement" ] *dragon *xoth In the West the dragon was the natural enemy of man. Although preferring to live in bleak and desolate regions, whenever it was seen among men it left in its wake a trail of destruction and disease. Yet any attempt to slay this beast was a perilous undertaking. For the dragon's assailant had to contend not only with clouds of sulphurous fumes pouring from its fire breathing nostrils, but also with the thrashings of its tail, the most deadly part of its serpent-like body. [ Mythical Beasts by Deirdre Headon (The Leprechaun Library) ] "One whom the dragons will speak with," he said, "that is a dragonlord, or at least that is the center of the matter. It's not a trick of mastering the dragons, as most people think. Dragons have no masters. The question is always the same, with a dragon: will he talk to you or will he eat you? If you can count upon his doing the former, and not doing the latter, why then you're a dragonlord." [ The Tombs of Atuan, by Ursula K. Le Guin ] *drum* Many travelers have seen the drums of the great apes, and some have heard the sounds of their beating and the noise of the wild, weird revelry of these first lords of the jungle, but Tarzan, Lord Greystoke, is, doubtless, the only human being who ever joined in the fierce, mad, intoxicating revel of the Dum-Dum. [ Tarzan of the Apes, by Edgar Rice Burroughs ] ~dwarf ??m* dwarf* dwar* cave*man Dwarfs have faces like men (ugly men, with wrinkled, leathery skins), but are generally either flat-footed, duck-footed, or have feet pointing backwards. They are of the earth, earthy, living in the darkest of caverns and venturing forth only with the cloaks by which they can make themselves invisible, and others disguised as toads. Miners often come across them, and sometimes establish reasonably close relations with them. ... The miners of Cornwall were always delighted to hear a bucca busily mining away, for all dwarfs have an infallible nose for precious metals. Among other things, dwarfs are rightly valued for their skill as blacksmiths and jewellers: they made Odin his famous spear Gungnir, and Thor his hammer; for Freya they designed a magnificent necklace, and for Frey a golden boar. And in their spare time they are excellent bakers. Ironically, despite their odd feet, they are particularly fond of dancing. They can also see into the future, and consequently are excellent meteorologists. They can be free with presents to people they like, and a dwarvish gift is likely to turn to gold in the hand. But on the whole they are a snappish lot. [ The Immortals, by Derek and Julia Parker ] earendil elwing In after days, when because of the triumph of Morgoth Elves and Men became estranged, as he most wished, those of the Elven-race that lived still in Middle-earth waned and faded, and Men usurped the sunlight. Then the Quendi wandered in the lonely places of the great lands and the isles, and took to the moonlight and the starlight, and to the woods and the caves, becoming as shadows and memories, save those who ever and anon set sail into the West and vanished from Middle-earth. But in the dawn of years Elves and Men were allies and held themselves akin, and there were some among Men that learned the wisdom of the Eldar, and became great and valiant among the captains of the Noldor. And in the glory and beauty of the Elves, and in their fate, full share had the offspring of elf and mortal, Earendil, and Elwing, and Elrond their child. [ The Silmarillion, by J.R.R. Tolkien ] eel giant eel The behaviour of eels in fresh water extends the air of mystery surrounding them. They move freely into muddy, silty bottoms of lakes, lying buried in the daylight hours in summer. [...] Eels are voracious carnivores, feeding mainly at night and consuming a wide variety of fishes and invertebrate creatures. Contrary to earlier thinking, eels seek living rather than dead creatures and are not habitual eaters of carrion. [ Freshwater Fishes of Canada, by Scott and Crossman ] egg But I asked why not keep it and let the hen sit on it till it hatched, and then we could see what would come out of it. "Nothing good, I'm certain of that," Mom said. "It would probably be something horrible. But just remember, if it's a crocodile or a dragon or something like that, I won't have it in my house for one minute." [ The Enormous Egg, by Oliver Butterworth ] elbereth ... Even as they stepped over the threshold a single clear voice rose in song. A Elbereth Gilthoniel, silivren penna miriel o menel aglar elenath! Na-chaered palan-diriel o galadhremmin ennorath, Fanuilos, le linnathon nef aear, si nef aearon! Frodo halted for a moment, looking back. Elrond was in his chair and the fire was on his face like summer-light upon the trees. Near him sat the Lady Arwen. [...] He stood still enchanted, while the sweet syllables of the elvish song fell like clear jewels of blended word and melody. "It is a song to Elbereth," said Bilbo. "They will sing that, and other songs of the Blessed Realm, many times tonight. Come on!" [ The Fellowship of the Ring, by J.R.R. Tolkien ] electric eel South-American fish (_Gymnotus electricus_), living in fresh water. Shaped like a serpent, it can grow up to 2 metres. This eel is known for its electrical organ which enables it to paralyse creatures up to the size of a horse. [ Van Dale's Groot Woordenboek der Nederlandse Taal ] *elemental Elementals are manifestations of the basic nature of the universe. There are four known forms of elementals: air, fire, water, and earth. Some mystics have postulated the necessity for a fifth type, the spirit elemental, but none have ever been encountered, at least on this plane of existence. ~elf ??m* *elf* elvenking The Elves sat round the fire upon the grass or upon the sawn rings of old trunks. Some went to and fro bearing cups and pouring drinks; others brought food on heaped plates and dishes. "This is poor fare," they said to the hobbits; "for we are lodging in the greenwood far from our halls. If ever you are our guests at home, we will treat you better." "It seems to me good enough for a birthday-party," said Frodo. Pippin afterwards recalled little of either food or drink, for his mind was filled with the light upon the elf-faces, and the sound of voices so various and so beautiful that he felt in a waking dream. [...] Sam could never describe in words, nor picture clearly to himself, what he felt or thought that night, though it remained in his memory as one of the chief events of his life. The nearest he ever got was to say: "Well, sir, if I could grow apples like that, I would call myself a gardener. But it was the singing that went to my heart, if you know what I mean." [ The Fellowship of the Ring, by J.R.R. Tolkien ] elven cloak The Elves next unwrapped and gave to each of the Company the clothes they had brought. For each they had provided a hood and cloak, made according to his size, of the light but warm silken stuff that the Galadrim wove. It was hard to say of what colour they were: grey with the hue of twilight under the trees they seemed to be; and yet if they were moved, or set in another light, they were green as shadowed leaves, or brown as fallow fields by night, dusk-silver as water under the stars. [ The Fellowship of the Ring, by J.R.R. Tolkien ] emerald 'Put off that mask of burning gold With emerald eyes.' 'O no, my dear, you make so bold To find if hearts be wild and wise, And yet not cold.' 'I would but find what's there to find, Love or deceit.' 'It was the mask engaged your mind, And after set your heart to beat, Not what's behind.' 'But lest you are my enemy, I must enquire.' 'O no, my dear, let all that be; What matter, so there is but fire In you, in me?' [ The Mask, by W.B. Yeats ] erinys erinyes These female-seeming devils named after the Furies of mythology attack hand to hand and poison their unwary victims as well. ettin The two-headed giant, or ettin, is a vicious and unpredictable hunter that stalks by night and eats any meat it can catch. excalibur At first only its tip was visible, but then it rose, straight, proud, all that was noble and great and wondrous. The tip of the blade pointed toward the moon, as if it would cleave it in two. The blade itself gleamed like a beacon in the night. There was no light source for the sword to be reflecting from, for the moon had darted behind a cloud in fear. The sword was glowing from the intensity of its strength and power and knowledge that it was justice incarnate, and that after a slumber of uncounted years its time had again come. After the blade broke the surface, the hilt was visible, and holding the sword was a single strong, yet feminine hand, wearing several rings that bore jewels sparkling with the blue-green color of the ocean. [ Knight Life, by Peter David ] expensive camera There was a time when Rincewind had quite liked the iconoscope. He believed, against all experience, that the world was fundamentally understandable, and that if he could only equip himself with the right mental toolbox he could take the back off and see how it worked. He was, of course, dead wrong. The iconoscope didn't take pictures by letting light fall onto specially treated paper, as he had surmised, but by the far simpler method of imprisoning a small demon with a good eye for colour and a speedy hand with a paintbrush. He had been very upset to find that out. [ The Light Fantastic, by Terry Pratchett ] eye of the aethiopica This is a powerful amulet of ESP. In addition to its standard powers, it regenerates the energy of anyone who carries it, allowing them to cast spells more often. It also reduces any spell damage to the person who carries it by half, and protects from magic missiles. Finally, when invoked it has the power to instantly open a portal to any other area of the dungeon, allowing its invoker to travel quickly between areas. eyes of the overworld ... and finally there is "the Eyes of the Overworld". This obscure artifact pushes the wearer's view sense into the "overworld" -- another name for a segment of the Astral Plane. Usually, there is nothing to be seen. However, the wearer is also able to look back and see the area around herself, much like looking on a map. Why anyone would want to ... figurine* Then it appeared in Paris at just about the time that Paris was full of Carlists who had to get out of Spain. One of them must have brought it with him, but, whoever he was, it's likely he knew nothing about its real value. It had been -- no doubt as a precaution during the Carlist trouble in Spain -- painted or enameled over to look like nothing more than a fairly interesting black statuette. And in that disguise, sir, it was, you might say, kicked around Paris for seventy years by private owners and dealers too stupid to see what it was under the skin. [ The Maltese Falcon, by Dashiell Hammett ] floating eye Floating eyes, not surprisingly, are large, floating eyeballs which drift about the dungeon. Though not dangerous in and of themselves, their power to paralyse those who gaze at their large eye in combat is widely feared. Many are the tales of those who struck a floating eye, were paralysed by its mystic powers, and then nibbled to death by some other creature that lurked around nearby. flesh golem With an anxiety that almost amounted to agony, I collected the instruments of life around me, that I might infuse a spark of being into the lifeless thing that lay at my feet. It was already one in the morning; the rain pattered dismally against the panes, and my candle was nearly burnt out, when, by the glimmer of the half-extinguished light, I saw the dull yellow eye of the creature open; it breathed hard, and a convulsive motion agitated its limbs. How can I describe my emotions at this catastrophe, or how delineate the wretch whom with such infinite pains and care I had endeavoured to form? His limbs were in proportion, and I had selected his features as beautiful. Beautiful!--Great God! His yellow skin scarcely covered the work of muscles and arteries beneath; his hair was of a lustrous black, and flowing; his teeth of a pearly whiteness; but these luxuriances only formed a more horrid contrast with his watery eyes, that seemed almost of the same colour as the dun white sockets in which they were set, his shrivelled complexion and straight black lips. [ Frankenstein, by Mary Wollstonecraft Shelley ] *flute With this thou canst do mighty deeds And change men's passions for thy needs: A man's despair with joy allay, Turn bachelors old to lovers gay. [ The Magic Flute, by Wolfgang Amadeus Mozart ] fog cloud The fog comes on little cat feet. It sits looking over harbor and city on silent haunches and then moves on. [ Fog, by Carl Sandburg ] fountain Rest! This little Fountain runs Thus for aye: -- It never stays For the look of summer suns, Nor the cold of winter days. Whose'er shall wander near, When the Syrian heat is worst, Let him hither come, nor fear Lest he may not slake his thirst: He will find this little river Running still, as bright as ever. Let him drink, and onward hie, Bearing but in thought, that I, Erotas, bade the Naiad fall, And thank the great god Pan for all! [ For a Fountain, by Bryan Waller Procter ] fox One hot summer's day a Fox was strolling through an orchard till he came to a bunch of Grapes just ripening on a vine which had been trained over a lofty branch. "Just the thing to quench my thirst," quoth he. Drawing back a few paces, he took a run and a jump, and just missed the bunch. Turning round again with a One, Two, Three, he jumped up, but with no greater success. Again and again he tried after the tempting morsel, but at last had to give it up, and walked away with his nose in the air, saying: "I am sure they are sour." [ Aesop's Fables ] *fung* Fungi, division of simple plants that lack chlorophyll, true stems, roots, and leaves. Unlike algae, fungi cannot photosynthesize, and live as parasites or saprophytes. The division comprises the slime molds and true fungi. True fungi are multicellular (with the exception of yeasts); the body of most true fungi consists of slender cottony filaments, or hyphae. All fungi are capable of asexual reproduction by cell division, budding, fragmentation, or spores. Those that reproduce sexually alternate a sexual generation (gametophyte) with a spore-producing one. The four classes of true fungi are the algaelike fungi (e.g., black bread mold and downy mildew), sac fungi (e.g., yeasts, powdery mildews, truffles, and blue and green molds such as Penicillium), basidium fungi (e.g., mushrooms and puffballs) and imperfect fungi (e.g., species that cause athlete's foot and ringworm). Fungi help decompose organic matter (important in soil renewal); are valuable as a source of antibiotics, vitamins, and various chemicals; and for their role in fermentation, e.g., in bread and alcoholic beverage production. [ The Concise Columbia Encyclopedia ] *gargoyle And so it came to pass that while Man ruled on Earth, the gargoyles waited, lurking, hidden from the light. Reborn every 600 years in Man's reckoning of time, the gargoyles joined battle against Man to gain dominion over the Earth. In each coming, the gargoyles were nearly destroyed by Men who flourished in greater numbers. Now it has been so many hundreds of years that it seems the ancient statues and paintings of gargoyles are just products of Man's imagination. In this year, with Man's thoughts turned toward the many ills he has brought among himself, Man has forgotten his most ancient adversary, the gargoyles. [ Excerpt from the opening narration to the movie _Gargoyles_, written by Stephen and Elinor Karpf ] *garlic 1 November - All day long we have travelled, and at a good speed. The horses seem to know that they are being kindly treated, for they go willingly their full stage at best speed. We have now had so many changes and find the same thing so constantly that we are encouraged to think that the journey will be an easy one. Dr. Van Helsing is laconic, he tells the farmers that he is hurrying to Bistritz, and pays them well to make the exchange of horses. We get hot soup, or coffee, or tea, and off we go. It is a lovely country. Full of beauties of all imaginable kinds, and the people are brave, and strong, and simple, and seem full of nice qualities. They are very, very superstitious. In the first house where we stopped, when the woman who served us saw the scar on my forehead, she crossed herself and put out two fingers towards me, to keep off the evil eye. I believe they went to the trouble of putting an extra amount of garlic into our food, and I can't abide garlic. Ever since then I have taken care not to take off my hat or veil, and so have escaped their suspicions. [ Dracula, by Bram Stoker ] # gas spore -- see *spore geryon Geryon is an arch-devil sometimes called the Wild Beast, attacking with his claws and poison sting. His ranking in Hell is rumored to be quite low. *ghost And now the souls of the dead who had gone below came swarming up from Erebus -- fresh brides, unmarried youths, old men with life's long suffering behind them, tender young girls still nursing this first anguish in their hearts, and a great throng of warriors killed in battle, their spear-wounds gaping yet and all their armour stained with blood. From this multitude of souls, as they fluttered to and fro by the trench, there came a moaning that was horrible to hear. Panic drained the blood from my cheeks. [ The Odyssey, (chapter Lambda), by Homer ] ghoul The forces of the gloom know each other, and are strangely balanced by each other. Teeth and claws fear what they cannot grasp. Blood-drinking bestiality, voracious appetites, hunger in search of prey, the armed instincts of nails and jaws which have for source and aim the belly, glare and smell out uneasily the impassive spectral forms straying beneath a shroud, erect in its vague and shuddering robe, and which seem to them to live with a dead and terrible life. These brutalities, which are only matter, entertain a confused fear of having to deal with the immense obscurity condensed into an unknown being. A black figure barring the way stops the wild beast short. That which emerges from the cemetery intimidates and disconcerts that which emerges from the cave; the ferocious fear the sinister; wolves recoil when they encounter a ghoul. [ Les Miserables, by Victor Hugo ] *giant giant humanoid Giants have always walked the earth, though they are rare in these times. They range in size from little over nine feet to a towering twenty feet or more. The larger ones use huge boulders as weapons, hurling them over large distances. All types of giants share a love for men - roasted, boiled, or fried. Their table manners are legendary. # note: "gnomish wizard" is a monster; cave*man entry doesn't fit nonhumans ~gnome ??m* gnome* gnomish wizard gnom* cave*man ... And then a gnome came by, carrying a bundle, an old fellow three times as large as an imp and wearing clothes of a sort, especially a hat. And he was clearly just as frightened as the imps though he could not go so fast. Ramon Alonzo saw that there must be some great trouble that was vexing magical things; and, since gnomes speak the language of men, and will answer if spoken to gently, he raised his hat, and asked of the gnome his name. The gnome did not stop his hasty shuffle a moment as he answered 'Alaraba' and grabbed the rim of his hat but forgot to doff it. 'What is the trouble, Alaraba?' said Ramon Alonzo. 'White magic. Run!' said the gnome .. [ The Charwoman's Shadow, by Lord Dunsany ] "Muggles have garden gnomes, too, you know," Harry told Ron as they crossed the lawn. "Yeah, I've seen those things they think are gnomes," said Ron, bent double with his head in a peony bush, "like fat little Santa Clauses with fishing rods..." There was a violent scuffling noise, the peony bush shuddered, and Ron straightened up. "This is a gnome," he said grimly. "Geroff me! Gerroff me!" squealed the gnome. It was certainly nothing like Santa Claus. It was small and leathery looking, with a large, knobby, bald head exactly like a potato. Ron held it at arm's length as it kicked out at him with its horny little feet; he grasped it around the ankles and turned it upside down. [ Harry Potter and the Chamber of Secrets, by J. K. Rowling ] goblin Now goblins are cruel, wicked, and bad-hearted. They make no beautiful things, but they make many clever ones. They can tunnel and mine as well as any but the most skilled dwarves, when they take the trouble, though they are usually untidy and dirty. Hammers, axes, swords, daggers, pickaxes, tongs, and also instruments of torture, they make very well, or get other people to make to their design, prisoners and slaves that have to work till they die for want of air and light. [ The Hobbit, by J.R.R. Tolkien ] god goddess Goddesses and Gods operate in ones, threesomes, or whole pantheons of nine or more (see Religion). Most of them claim to have made the world, and this is indeed a likely claim in the case of threesomes or pantheons: Fantasyland does have the air of having been made by a committee. But all Goddesses and Gods, whether they say they made the world or not, have very detailed short-term plans for it which they are determined to carry out. Consequently they tend to push people into the required actions by the use of coincidence or Prophecy, or just by narrowing down your available choices of what to do next: if a deity is pushing you, things will go miserably badly until there is only one choice left to you. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] gold gold piece zorkmid A metal of characteristic yellow colour, the most precious metal used as a common commercial medium of exchange. Symbol, Au; at. no. 79; at. wt. 197.2. It is the most malleable and ductile of all metals, and very heavy (sp. gr., 19.3). It is quite unalterable by heat, moisture, and most corrosive agents, and therefore well suited for its use in coin and jewelry. [ Webster's New International Dictionary of the English Language, Second Edition ] gold golem The bellows he set away from the fire, and gathered all the tools wherewith he wrought into a silver chest; and with a sponge wiped he his face and his two hands withal, and his mighty neck and shaggy breast, and put upon him a tunic, and grasped a stout staff, and went forth halting; but there moved swiftly to support their lord handmaidens wrought of gold in the semblance of living maids. In them is understanding in their hearts, and in them speech and strength, and they know cunning handiwork by gift of the immortal gods. [ The Iliad, by Homer ] ~gold golem ~flesh golem *golem "The original story harks back, so they say, to the sixteenth century. Using long-lost formulas from the Kabbala, a rabbi is said to have made an artificial man -- the so-called Golem -- to help ring the bells in the Synagogue and for all kinds of other menial work. "But he hadn't made a full man, and it was animated by some sort of vegetable half-life. What life it had, too, so the story runs, was only derived from the magic charm placed behind its teeth each day, that drew down to itself what was known as the `free sidereal strength of the universe.' "One evening, before evening prayers, the rabbi forgot to take the charm out of the Golem's mouth, and it fell into a frenzy. It raged through the dark streets, smashing everything in its path, until the rabbi caught up with it, removed the charm, and destroyed it. Then the Golem collapsed, lifeless. All that was left of it was a small clay image, which you can still see in the Old Synagogue." ... [ The Golem, by Gustav Meyrink ] grave "Who'd care to dig 'em," said the old, old man, "Those six feet marked in chalk? Much I talk, more I walk; Time I were buried," said the old, old man. [ Three Songs to the Same Tune, by W.B. Yeats ] grayswandir Why had I been wearing Grayswandir? Would another weapon have affected a Logrus-ghost as strongly? Had it really been my father, then, who had brought me here? And had he felt I might need the extra edge his weapon could provide? I wanted to think so, to believe that he had been more than a Pattern-ghost. [ Knight of Shadows, by Roger Zelazny ] *grease ANOINT, v.t. To grease a king or other great functionary already sufficiently slippery. [ The Devil's Dictionary, by Ambrose Bierce ] gremlin The gremlin is a highly intelligent and completely evil creature. It lives to torment other creatures and will go to great lengths to inflict pain or cause injury. Suddenly, Wilson thought about war, about the newspaper stories which recounted the alleged existence of creatures in the sky who plagued the Allied pilots in their duties. They called them gremlins, he remembered. Were there, actually, such beings? Did they, truly, exist up here, never falling, riding on the wind, apparently of bulk and weight, yet impervious to gravity? He was thinking that when the man appeared again. [ Nightmare at 20,000 Feet, by Richard Matheson ] grid bug These electronically based creatures are not native to this universe. They appear to come from a world whose laws of motion are radically different from ours. Tron looked to his mate and pilot. "I'm going to check on the beam connection, Yori. You two can keep a watch out for grid bugs." Tron paced forward along the slender catwalk that still seemed awfully insubstantial to Flynn, though he knew it to be amazingly sturdy. He gazed after Tron, asking himself what in the world a grid bug was, and hoping that the beam connection -- to which he'd given no thought whatsoever until this moment -- was healthy and sound." [ Tron, novel by Brian Daley, story by Steven Lisberger ] gunyoki The samurai's last meal before battle. It was usually made up of cooked chestnuts, dried seaweed, and sake. hachi Hachi was a dog that went with his master, a professor, to the Shibuya train station every morning. In the afternoon, when his master was to return from work Hachi would be there waiting. One day his master died at the office, and did not return. For over ten years Hachi returned to the station every afternoon to wait for his master. When Hachi died a statue was erected on the station platform in his honor. It is said to bring you luck if you touch his statue. *harp A triangular stringed instrument, often Magic. Even when not Magic, a Harp is surprisingly portable and tough and can be carried everywhere on the back of the Bard or Harper in all weathers. A Harp seldom goes out of tune and never warps. Its strings break only in very rare instances, usually because the Harper is sulking or crossed in love. This is just as well as no one seems to make or sell spare strings. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] After breakfast was over, the ogre called out: "Wife, wife, bring me my golden harp." So she brought it and put it on the table before him. Then he said: "Sing!" and the golden harp sang most beautifully. And it went on singing till the ogre fell asleep, and commenced to snore like thunder. Then Jack lifted up the copper-lid very quietly and got down like a mouse and crept on hands and knees till he came to the table, when up he crawled, caught hold of the golden harp and dashed with it towards the door. But the harp called out quite loud: "Master! Master!" and the ogre woke up just in time to see Jack running off with his harp. [ Jack and the Beanstalk, from English Fairy Tales, by Joseph Jacobs ] healer * healer attendant doctor physician I swear by Apollo the physician, and Aesculapius, and Health, and All-heal, and all the gods and goddesses, that, according to my ability and judgment, I will keep this Oath and this stipulation -- to reckon him who taught me this Art equally dear to me as my parents, to share my substance with him, and relieve his necessities if required; to look upon his offspring in the same footing as my own brothers, and to teach them this art, if they shall wish to learn it, without fee or stipulation; and that by precept, lecture, and every other mode of instruction, I will impart a knowledge of the Art to my own sons, and those of my teachers, and to disciples bound by a stipulation and oath according to the law of medicine, but to none others. I will follow that system of regimen which, according to my ability and judgment, I consider for the benefit of my patients, and abstain from whatever is deleterious and mischievous. [...] [ Hippocrates' Oath, translated by Francis Adams ] PHYSICIAN, n. One upon whom we set our hopes when ill and our dogs when well. [ The Devil's Dictionary, by Ambrose Bierce ] heart of ahriman The other three drew in their breath sharply, and the dark, powerful man who stood at the head of the sarcophagus whispered: "The Heart of Ahriman!" The other lifted a quick hand for silence. Somewhere a dog began howling dolefully, and a stealthy step padded outside the barred and bolted door. ... But none looked aside from the mummy case over which the man in the ermine-trimmed robe was now moving the great flaming jewel, while he muttered an incantation that was old when Atlantis sank. The glare of the gem dazzled their eyes, so that they could not be sure what they saw; but with a splintering crash, the carven lid of the sarcophagus burst outward as if from some irresistible pressure applied from within and the four men, bending eagerly forward, saw the occupant -- a huddled, withered, wizened shape, with dried brown limbs like dead wood showing through moldering bandages. "Bring that thing back?" muttered the small dark man who stood on the right, with a short, sardonic laugh. "It is ready to crumble at a touch. We are fools ---" [ Conan The Conqueror, by Robert E. Howard ] hell hound* Hell hounds are fire-breathing canines from another plane of existence brought here in the service of evil beings. A hell hound resembles a large hound with rust-red or red-brown fur, and red, glowing eyes. The markings, teeth, and tongue are soot black. It stands two to three feet high at the shoulder and has a distinct odour of smoke and sulphur. The baying sounds it makes have an eerie, hollow tone that sends a shiver through any who hear them. hermes Messenger and herald of the Olympians. Being required to do a great deal of travelling and speaking in public, he became the god of eloquence, travellers, merchants, and thieves. He was one of the most energetic of the Greek gods, a Machiavellian character full of trickery and sexual vigour. Like other Greek gods, he is endowed with not-inconsiderable sexual prowess which he directs towards countryside nymphs. He is a god of boundaries, guardian of graves and patron deity of shepherds. He is usually depicted as a handsome young man wearing winged golden sandals and holding a magical herald's staff consisting of intertwined serpents, the kerykeion. He is reputedly the only being able to find his way to the underworld ferry of Charon and back again. He is said to have invented, among other things, the lyre, Pan's Pipes, numbers, the alphabet, weights and measures, and sacrificing. hezrou "Hezrou" is the common name for the type II demon. It is among the weaker of demons, but still quite formidable. hippocrates Greek physician, recognized as the father of medicine. He is believed to have been born on the island of Cos, to have studied under his father, a physician, to have traveled for some time, perhaps studying in Athens, and to have then returned to practice, teach, and write at Cos. The Hippocratic or Coan school that formed around him was of enormous importance in separating medicine from superstition and philosophic speculation, placing it on a strictly scientific plane based on objective observation and critical deductive reasoning. [ The Columbia Encyclopedia, Sixth Edition ] hobbit Hobbits are an unobtrusive but very ancient people, more numerous formerly than they are today; for they love peace and quiet and good tilled earth: a well-ordered and well- farmed countryside was their favourite haunt. They do not and did not understand or like machines more complicated than a forge-bellows, a water-mill, or a handloom, although they were skillful with tools. Even in ancient days they were, as a rule, shy of "the Big Folk", as they call us, and now they avoid us with dismay and are becoming hard to find. [ The Fellowship of the Ring, by J.R.R. Tolkien ] hobgoblin Hobgoblin. Used by the Puritans and in later times for wicked goblin spirits, as in Bunyan's "Hobgoblin nor foul friend", but its more correct use is for the friendly spirits of the brownie type. In "A midsummer night's dream" a fairy says to Shakespeare's Puck: Those that Hobgoblin call you, and sweet Puck, You do their work, and they shall have good luck: Are you not he? and obviously Puck would not wish to be called a hobgoblin if that was an ill-omened word. Hobgoblins are on the whole, good-humoured and ready to be helpful, but fond of practical joking, and like most of the fairies rather nasty people to annoy. Boggarts hover on the verge of hobgoblindom. Bogles are just over the edge. One Hob mentioned by Henderson, was Hob Headless who haunted the road between Hurworth and Neasham, but could not cross the little river Kent, which flowed into the Tess. He was exorcised and laid under a large stone by the roadside for ninety-nine years and a day. If anyone was so unwary as to sit on that stone, he would be unable to quit it for ever. The ninety-nine years is nearly up, so trouble may soon be heard of on the road between Hurworth and Neasham. [ A Dictionary of Fairies, by Katharine Briggs ] holy water "We want a word with you," said Ligur (in a tone of voice intended to imply that "word" was synonymous with "horrifically painful eternity"), and the squat demon pushed open the office door. The bucket teetered, then fell neatly on Ligur's head. Drop a lump of sodium in water. Watch it flame and burn and spin around crazily, flaring and sputtering. This was like that, just nastier. The demon peeled and flared and flickered. Oily brown smoke oozed from it, and it screamed and it screamed and it screamed. Then it crumpled, folded in on itself, and what was left lay glistening on the burnt and blackened circle of carpet, looking like a handful of mashed slugs. "Hi," said Crowley to Hastur, who had been walking behind Ligur, and had unfortunately not been so much as splashed. There are some things that are unthinkable; there are some depths that not even demons would believe other demons would stoop to. ". . . Holy water. You bastard," said Hastur. "You complete _bastard_. He hadn't never done nothing to _you_." "Yet," corrected Crowley. [ Good Omens, by Neil Gaiman and Terry Pratchett ] hom*nculus A homunculus is a creature summoned by a mage to perform some particular task. They are particularly good at spying. They are smallish creatures, but very agile. They can put their victims to sleep with a venomous bite, but due to their size, the effect does not last long on humans. "Tothapis cut him off. 'Be still and hearken. You will travel aboard the sacred wingboat. Of it you may not have heard; but it will bear you thither in a night and a day and a night. With you will go a homunculus that can relay your words to me, and mine to you, across the leagues between at the speed of thought.'" [ Conan the Rebel, by Poul Anderson ] # also gets 'pruning hook' aka guisarme *hook But as for Queequeg -- why, Queequeg sat there among them -- at the head of the table, too, it so chanced; as cool as an icicle. To be sure I cannot say much for his breeding. His greatest admirer could not have cordially justified his bringing his harpoon into breakfast with him, and using it there without ceremony; reaching over the table with it, to the imminent jeopardy of many heads, and grappling the beefsteaks towards him. [ Moby Dick, by Herman Melville ] ~unicorn horn *horn Roland hath set the Olifant to his mouth, He grasps it well, and with great virtue sounds. High are those peaks, afar it rings and loud, Thirty great leagues they hear its echoes mount. So Charles heard, and all his comrades round; Then said that King: "Battle they do, our counts!" And Guenelun answered, contrarious: "That were a lie, in any other mouth." [ The Song of Roland ] horned devil Horned devils lack any real special abilities, though they are quite difficult to kill. ~horsem* *horse King Richard III: A horse! a horse! my kingdom for a horse! Catesby: Withdraw, my lord; I'll help you to a horse. King Richard III: Slave, I have set my life upon a cast, And I will stand the hazard of the die: I think there be six Richmonds in the field; Five have I slain to-day instead of him. A horse! a horse! my kingdom for a horse! [ King Richard III, by William Shakespeare ] *horsem* rider* death famine pestilence war hunger [Pestilence:] And I saw when the Lamb opened one of the seals, and I heard, as it were the noise of thunder, one of the four beasts saying, Come and see. And I saw, and behold a white horse: and he that sat on him had a bow; and a crown was given unto him: and he went forth conquering, and to conquer. [War:] And when he had opened the second seal, I heard the second beast say, Come and see. And there went out another horse that was red: and power was given to him that sat thereon to take peace from the earth, and that they should kill one another: and there was given unto him a great sword. [Famine:] And when he had opened the third seal, I heard the third beast say, Come and see. And I beheld, and lo a black horse; and he that sat on him had a pair of balances in his hand. And I heard a voice in the midst of the four beasts say, A measure of wheat for a penny, and three measures of barley for a penny; and see thou hurt not the oil and the wine. [Death:] And when he had opened the fourth seal, I heard the voice of the fourth beast say, Come and see. And I looked, and behold a pale horse: and his name that sat on him was Death, and Hell followed with him. And power was given unto them over the fourth part of the earth, to kill with sword, and with hunger, and with death, and with the beasts of the earth. [ Revelations of John, 6:1-8 ] huan*ti The first of five mythical Chinese emperors, Huan Ti is known as the yellow emperor. He rules the _moving_ heavens, as opposed to the _dark_ heavens. He is an inventor, said to have given mankind among other things, the wheel, armour, and the compass. He is the god of fortune telling and war. hu*h*eto*l minion of huhetotl Huehuetotl, or Huhetotl, which means Old God, was the Aztec (classical Mesoamerican) god of fire. He is generally associated with paternalism and one of the group classed as the Xiuhtecuhtli complex. He is known to send his minions to wreak havoc upon ordinary humans. [ after the Encyclopedia of Gods, by Michael Jordan ] humanoid Humanoids are all approximately the size of a human, and may be mistaken for one at a distance. They are usually of a tribal nature, and will fiercely defend their lairs. Usually hostile, they may even band together to raid and pillage human settlements. human chieftain guard ninja nurse page ronin shopkeeper student thug warrior *watch* player These strange creatures live mostly on the surface of the earth, gathering together in societies of various forms, but occasionally a stray will descend into the depths and commit mayhem among the dungeon residents who, naturally, often resent the intrusion of such beasts. They are capable of using weapons and magic, and it is even rumored that the Wizard of Yendor is a member of this species. hunter What of the hunting, hunter bold? Brother, the watch was long and cold. What of the quarry ye went to kill? Brother, he crops in the jungle still. Where is the power that made your pride? Brother, it ebbs from my flank and side. Where is the haste that ye hurry by? Brother, I go to my lair to die. [ The Jungle Book, by Rudyard Kipling ] ice devil Ice devils are large semi-insectoid creatures, who are equally at home in the fires of Hell and the cold of Limbo, and who can cause the traveller to feel the latter with just a touch of their tail. imp ... imps ... little creatures of two feet high that could gambol and jump prodigiously; ... [ The Charwoman's Shadow, by Lord Dunsany ] An 'imp' is an off-shoot or cutting. Thus an 'ymp tree' was a grafted tree, or one grown from a cutting, not from seed. 'Imp' properly means a small devil, an off-shoot of Satan, but the distinction between goblins or bogles and imps from hell is hard to make, and many in the Celtic countries as well as the English Puritans regarded all fairies as devils. The fairies of tradition often hover uneasily between the ghostly and the diabolic state. [ A Dictionary of Fairies, by Katharine Briggs ] incubus succubus The incubus and succubus are male and female versions of the same demon, one who lies with a human for its own purposes, usually to the detriment of the mortals who are unwise in their dealings with them. *iron ball *iron chain "You are fettered, " said Scrooge, trembling. "Tell me why?" "I wear the chain I forged in life," replied the Ghost. "I made it link by link, and yard by yard; I girded it on of my own free will, and of my own free will I wore it. Is its pattern strange to you?" Scrooge trembled more and more. "Or would you know," pursued the Ghost, "the weight and length of the strong coil you bear yourself? It was full as heavy and as long as this, seven Christmas Eves ago. You have laboured on it, since. It is a ponderous chain!" [ A Christmas Carol, by Charles Dickens ] ishtar Ishtar (the star of heaven) is the Mesopotamian goddess of fertility and war. She is usually depicted with wings and weapon cases at her shoulders, carrying a ceremonial double- headed mace-scimitar embellished with lion heads, frequently being accompanied by a lion. She is symbolized by an eight- pointed star. [ Encyclopedia of Gods, by Michael Jordan ] issek Now Issek of the Jug, whom Fafhrd chose to serve, was once of the most lowly and unsuccessful of the gods, godlets rather, in Lankhmar. He had dwelt there for about thirteen years, during which time he had traveled only two squares up the Street of the Gods and was now back again, ready for oblivion. He is not to be confused with Issek the Armless, Issek of the Burnt Legs, Flayed Issek, or any other of the numerous and colorfully mutilated divinities of that name. Indeed, his unpopularity may have been due in part to the fact that the manner of his death -- racking -- was not deemed particularly spectacular. ... However, after Fafhrd became his acolyte, things somehow began to change. [ Swords In The Mist, by Fritz Leiber ] izchak The shopkeeper of the lighting shop in the town level of the gnomish mines is a tribute to Izchak Miller, a founding member of the NetHack development team and a personal friend of a large number of us. Izchak contributed greatly to the game, coding a large amount of the shopkeep logic (hence the nature of the tribute) as well as a good part of the alignment system, the prayer code and the rewrite of "hell" in the 3.1 release. Izchak was a professor of Philosophy, who taught at many respected institutions, including MIT and Stanford, and who also worked, for a period of time, at Xerox PARC. Izchak was the first "librarian" of the NetHack project, and was a founding member of the DevTeam, joining in 1986 while he was working at the University of Pennsylvania (hence our former mailing list address). Until the 3.1.3 release, Izchak carefully kept all of the code synchronized and arbitrated disputes between members of the development teams. Izchak Miller passed away at the age of 58, in the early morning hours of April 1, 1994 from complications due to cancer. We then dedicated NetHack 3.2 in his memory. [ Mike Stephenson, for the NetHack DevTeam ] jabberwock vorpal* "Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!" He took his vorpal sword in hand; Long time the manxome foe he sought -- So rested he by the Tumtum tree, And stood awhile in thought. And, as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came! One, two! One, two! And through and through The vorpal blade went snicker-snack! He left it dead, and with its head He went galumphing back. [ Jabberwocky, by Lewis Carroll ] jackal In Asiatic folktale, jackal provides for the lion; he scares up game, which the lion kills and eats, and receives what is left as reward. In stories from northern India he is sometimes termed "minister to the king," i.e. to the lion. From the legend that he does not kill his own food has arisen the legend of his cowardice. Jackal's heart must never be eaten, for instance, in the belief of peoples indigenous to the regions where the jackal abounds. ... In Hausa Negro folktale Jackal plays the role of sagacious judge and is called "O Learned One of the Forest." The Bushmen say that Jackal goes around behaving the way he does "because he is Jackal". [ Funk & Wagnalls Standard Dictionary of Folklore ] jade* Nothing grew among the ruins of the city. The streets were broken and the walls of the houses had fallen, but there were no weeds flowering in the cracks and it seemed that the city had but recently been brought down by an earthquake. Only one thing still stood intact, towering over the ruins. It was a gigantic statue of white, gray and green jade - the statue of a naked youth with a face of almost feminine beauty that turned sightless eyes toward the north. "The eyes!" Duke Avan Astran said. "They're gone!" [ The Jade Man's Eyes, by Michael Moorcock ] jaguar Large, flesh-eating animal of the cat family, of Central and South America. This feline predator (_Panthera onca_) is sometimes incorrectly called a panther. [ Van Dale's Groot Woordenboek der Nederlandse Taal ] jellyfish I do not care to share the seas With jellyfishes such as these; Particularly Portuguese. [ Lines on Meeting a Portuguese Man-o'-war while Bathing, by Michael Flanders ] juiblex jubilex Little is known about the Faceless Lord, even the correct spelling of his name. He does not have a physical form as we know it, and those who have peered into his realm claim he is a slime-like creature who swallows other creatures alive, spits acidic secretions, and causes disease in his victims which can be almost instantly fatal. kabuto The kabuto is the helmet worn by the samurai. It was characterized by a prominent beaked front which jutted out over the brow to protect the wearer's face; a feature that gives rise to their modern Japanese name of 'shokaku tsuki kabuto' (battering-ram helmet). Their main constructional element was an oval plate, the shokaku bo, slightly domed for the head with a narrow prolongation in front that curved forwards and downwards where it developed a pronounced central fold. Two horizontal strips encircling the head were riveted to this frontal strip: the lower one, the koshimaki (hip wrap), formed the lower edge of the helmet bowl; the other, the do maki (body wrap), was set at about the level of the temples. Filling the gaps between these strips and the shokaku bo were small plates, sometimes triangular but more commonly rectangular in shape. Because the front projected so far from the head, the triangular gap beneath was filled by a small plate, the shoshaku tei ita, whose rear edge bent downwards into a flange that rested against the forehead. [ Arms & Armour of the Samurai, by Bottomley & Hopson ] katana The katana is a long, single-edged samurai sword with a slightly curved blade. Its long handle is designed to allow it to be wielded with either one or two hands. ki-rin The ki-rin is a strange-looking flying creature. It has scales, a mane like a lion, a tail, hooves, and a horn. It is brightly colored, and can usually be found flying in the sky looking for good deeds to reward. king arthur *arthur Ector took both his sons to the church before which the anvil had been placed. There, standing before the anvil, he commanded Kay: "Put the sword back into the steel if you really think the throne is yours!" But the sword glanced off the steel. "Now it is your turn", Ector said facing Arthur. The young man lifted the sword and thrust with both arms; the blade whizzed through the air with a flash and drilled the metal as if it were mere butter. Ector and Kay dropped to their knees before Arthur. "Why, father and brother, do you bow before me?", Arthur asked with wonder in his voice. "Because now I know for sure that you are the king, not only by birth but also by law", Ector said. "You are no son of mine nor are you Kay's brother. Immediately after your birth, Merlin the Wise brought you to me to be raised safely. And though it was me that named you Arthur when you were baptized, you are really the son of brave king Uther Pendragon and queen Igraine..." And after these words, the lord rose and went to see the arch- bishop to impart to him what had passed. [ Van Gouden Tijden Zingen de Harpen, by Vladimir Hulpach, Emanuel Frynta, and Vackav Cibula ] knife stiletto Possibly perceiving an expression of dubiosity on their faces, the globetrotter went on adhering to his adventures. -- And I seen a man killed in Trieste by an Italian chap. Knife in his back. Knife like that. Whilst speaking he produced a dangerous looking clasp knife, quite in keeping with his character, and held it in the striking position. -- In a knockingshop it was count of a tryon between two smugglers. Fellow hid behind a door, come up behind him. Like that. Prepare to meet your God, says he. Chuck! It went into his back up to the butt. [ Ulysses, by James Joyce ] knight * knight Here lies the noble fearless knight, Whose valour rose to such a height; When Death at last had struck him down, His was the victory and renown. He reck'd the world of little prize, And was a bugbear in men's eyes; But had the fortune in his age To live a fool and die a sage. [ Don Quixote of La Mancha by Miquel de Cervantes Saavedra ] ~kobold ??m* *kobold* The race of kobolds are reputed to be an artificial creation of a master wizard (demi-god?). They are about 3' tall with a vaguely dog-like face. They bear a violent dislike of the Elven race, and will go out of their way to cause trouble for Elves at any time. *kop* The Kops are a brilliant concept. To take a gaggle of inept policemen and display them over and over again in a series of riotously funny physical punishments plays equally well to the peanut gallery and the expensive box seats. People hate cops. Even people who have never had anything to do with cops hate them. Of course, we count on them to keep order and to protect us when we need protecting, and we love them on television shows in which they have nerves of steel and hearts of gold, but in the abstract, as a nation, collectively we hate them. They are too much like high school principals. We're very happy to see their pants fall down, and they look good to us with pie on their faces. The Keystone Kops turn up--and they get punished for it, as they crash into each other, fall down, and suffer indignity after indignity. Here is pure movie satisfaction. The Kops are very skillfully presented. The comic originality and timing in one of their chase scenes requires imagination to think up, talent to execute, understanding of the medium, and, of course, raw courage to perform. The Kops are madmen presented as incompetents, and they're madmen rushing around in modern machines. What's more, the machines they were operating in their routines were newly invented and not yet experienced by the average moviegoer. (In the early days of automobiles, it was reported that there were only two cars registered in all of Kansas City, and they ran into each other. There is both poetry and philosophy in this fact, but most of all, there is humor. Sennett got the humor.) [ Silent Stars, by Jeanine Basinger ] kos "I am not a coward!" he cried. "I'll dare Thieves' House and fetch you Krovas' head and toss it with blood a-drip at Vlana's feet. I swear that, witness me, Kos the god of dooms, by the brown bones of Nalgron my father and by his sword Graywand here at my side!" [ Swords and Deviltry, by Fritz Leiber ] koto A Japanese harp. kraken Out from the water a long sinuous tentacle had crawled; it was pale-green and luminous and wet. Its fingered end had hold of Frodo's foot, and was dragging him into the water. Sam on his knees was now slashing at it with a knife. The arm let go of Frodo, and Sam pulled him away, crying out for help. Twenty other arms came rippling out. The dark water boiled, and there was a hideous stench. [ The Fellowship of the Ring, by J.R.R. Tolkien ] *lady offler Blind Io took up the dice-box, which was a skull whose various orifices had been stoppered with rubies, and with several of his eyes on the Lady he rolled three fives. She smiled. This was the nature of the Lady's eyes: they were bright green, lacking iris or pupil, and they glowed from within. The room was silent as she scrabbled in her box of pieces and, from the very bottom, produced a couple that she set down on the board with two decisive clicks. The rest of the players, as one God, craned forward to peer at them. "A wenegade wiffard and fome fort of clerk," said Offler the Crocodile God, hindered as usual by his tusks. "Well, weally!" With one claw he pushed a pile of bone-white tokens into the centre of the table. The Lady nodded slightly. She picked up the dice-cup and held it as steady as a rock, yet all the Gods could hear the three cubes rattling about inside. And then she sent them bouncing across the table. A six. A three. A five. Something was happening to the five, however. Battered by the chance collision of several billion molecules, the die flipped onto a point, spun gently and came down a seven. Blind Io picked up the cube and counted the sides. "Come _on_," he said wearily, "Play fair." [ The Colour of Magic, by Terry Pratchett ] *lamp When he came to himself he told his mother what had passed, and showed her the lamp and the fruits he had gathered in the garden, which were in reality precious stones. He then asked for some food. "Alas! child," she said, "I have nothing in the house, but I have spun a little cotton and will go and sell it." Aladdin bade her keep her cotton, for he would sell the lamp instead. As it was very dirty she began to rub it, that it might fetch a higher price. Instantly a hideous genie appeared, and asked what she would have. She fainted away, but Aladdin, snatching the lamp, said boldly: "Fetch me something to eat!" [ Aladdin, from The Arabian Nights, by Andrew Lang ] lance With this the wind increased, and the mill sails began to turn about; which Don Quixote espying, said, 'Although thou movest more arms than the giant Briareus thou shalt stoop to me.' And, after saying this, and commending himself most devoutly to his Lady Dulcinea, desiring her to succor him in that trance, covering himself well with his buckler, and setting his lance on his rest, he spurred on Rozinante, and encountered with the first mill that was before him, and, striking his lance into the sail, the wind swung it about with such fury, that it broke his lance into shivers, carrying him and his horse after it, and finally tumbled him a good way off from it on the field in evil plight. [ Don Quixote of La Mancha by Miquel de Cervantes Saavedra ] leash They had splendid heads, fine shoulders, strong legs, and straight tails. The spots on their bodies were jet-black and mostly the size of a two-shilling piece; they had smaller spots on their heads, legs, and tails. Their noses and eye- rims were black. Missis had a most winning expression. Pongo, though a dog born to command, had a twinkle in his eye. They walked side by side with great dignity, only putting the Dearlys on the leash to lead them over crossings. [ The Hundred and One Dalmatians, by Dodie Smith ] lembas* In the morning, as they were beginning to pack their slender goods, Elves that could speak their tongue came to them and brought them many gifts of food and clothing for their journey. The food was mostly in the form of very thin cakes, made of a meal that was baked a light brown on the outside, and inside was the colour of cream. Gimli took up one of the cakes and looked at it with a doubtful eye. 'Cram,' he said under his breath, as he broke off a crisp corner and nibbled at it. His expression quickly changed, and he ate all the rest of the cake with relish. 'No more, no more!' cried the Elves laughing. 'You have eaten enough already for a long day's march.' 'I thought it was only a kind of cram, such as the Dalemen make for journeys in the wild,' said the Dwarf. 'So it is,' they answered. 'But we call it lembas or waybread, and it is more strengthening than any foods made by Men, and it is more pleasant than cram, by all accounts.' [ The Fellowship of the Ring, by J.R.R. Tolkien ] lemure The lowliest of the inhabitants of hell. leocrotta leu*otta ... the leucrocotta, a wild beast of extraordinary swiftness, the size of the wild ass, with the legs of a Stag, the neck, tail, and breast of a lion, the head of a badger, a cloven hoof, the mouth slit up as far as the ears, and one continuous bone instead of teeth; it is said, too, that this animal can imitate the human voice. [ Curious Creatures in Zoology, by John Ashton ] leprechaun The Irish Leprechaun is the Faeries' shoemaker and is known under various names in different parts of Ireland: Cluricaune in Cork, Lurican in Kerry, Lurikeen in Kildare and Lurigadaun in Tipperary. Although he works for the Faeries, the Leprechaun is not of the same species. He is small, has dark skin and wears strange clothes. His nature has something of the manic-depressive about it: first he is quite happy, whistling merrily as he nails a sole on to a shoe; a few minutes later, he is sullen and morose, drunk on his home-made heather ale. The Leprechaun's two great loves are tobacco and whiskey, and he is a first-rate con-man, impossible to out-fox. No one, no matter how clever, has ever managed to cheat him out of his hidden pot of gold or his magic shilling. At the last minute he always thinks of some way to divert his captor's attention and vanishes in the twinkling of an eye. [ A Field Guide to the Little People by Nancy Arrowsmith & George Moorse ] *lich But on its heels ere the sunset faded, there came a second apparition, striding with incredible strides and halting when it loomed almost upon me in the red twilight-the monstrous mummy of some ancient king still crowned with untarnished gold but turning to my gaze a visage that more than time or the worm had wasted. Broken swathings flapped about the skeleton legs, and above the crown that was set with sapphires and orange rubies, a black something swayed and nodded horribly; but, for an instant, I did not dream what it was. Then, in its middle, two oblique and scarlet eyes opened and glowed like hellish coals, and two ophidian fangs glittered in an ape-like mouth. A squat, furless, shapeless head on a neck of disproportionate extent leaned unspeakably down and whispered in the mummy's ear. Then, with one stride, the titanic lich took half the distance between us, and from out the folds of the tattered sere-cloth a gaunt arm arose, and fleshless, taloned fingers laden with glowering gems, reached out and fumbled for my throat . . . [ The Abominations of Yondo, Clark Ashton Smith, 1926 ] lichen The chamber was of unhewn rock, round, as near as might be, eighteen or twenty feet across, and gay with rich variety of fern and moss and lichen. The fern was in its winter still, or coiling for the spring-tide; but moss was in abundant life, some feathering, and some gobleted, and some with fringe of red to it. [ Lorna Doone, by R.D. Blackmore ] ~* of light * light Strange creatures formed from energy rather than matter, lights are given to self-destructive behavior when battling foes. gecko iguana lizard Lizards, snakes and the burrowing amphisbaenids make up the order Squamata, meaning the scaly ones. The elongate, slim, long-tailed bodies of lizards have become modified to enable them to live in a wide range of habitats. Lizards can be expert burrowers, runners, swimmers and climbers, and a few can manage crude, short-distance gliding on rib-supported "wings". Most are carnivores, feeding on invertebrate and small vertebrate prey, but others feed on vegetation. [ Macmillan Illustrated Animal Encyclopedia ] loki Loki, or Lopt, is described in Snorri's _Edda_ as being "pleasing and handsome in appearance, evil in character, and very capricious in behaviour". He is the son of the giant Farbauti and of Laufey. Loki is the Norse god of cunning, evil, thieves, and fire. He hated the other gods and wanted to ruin them and overthrow the universe. He committed many murders. As a thief, he stole Freyja's necklace, Thor's belt and gauntlets of power, and the apples of youth. Able to shapechange at will, he is said to have impersonated at various times a mare, flea, fly, falcon, seal, and an old crone. As a mare he gave birth to Odin's horse Sleipnir. He also allegedly sired the serpent Midgard, the mistress of the netherworld, Hel, and the wolf Fenrir, who will devour the sun at Ragnarok. *longbow of diana This legendary bow grants ESP when carried and can reflect magical attacks when wielded. When invoked it provides a supply of arrows. # long worm -- see "worm" looking glass mirror But as Snow White grew, she became more and more beautiful, and by the time she was seven years old she was as beautiful as the day and more beautiful than the queen herself. One day when the queen said to her mirror: "Mirror, Mirror, here I stand. Who is the fairest in the land?" - the mirror replied: "You, O Queen, are the fairest here, But Snow White is a thousand times more fair." [ Snow White, by Jakob and Wilhelm Grimm ] lord carnarvon Lord Carnarvon was a personality who could have been produced nowhere but in England, a mixture of sportsman and collector, gentleman and world traveler, a realist in action and a romantic in feeling. ... In 1903 he went for the first time to Egypt in search of a mild climate and while there visited the excavation sites of several archaeological expeditions. ... In 1906 he began his own excavations. [ Gods, Graves, and Scholars, by C. W. Ceram ] lord sato Lord Sato was the family head of the Taro Clan, and a mighty daimyo. He is a loyal servant of the Emperor, and will do everything in his power to further the imperial cause. lord surt* Yet first was the world in the southern region, which was named Muspell; it is light and hot; that region is glowing and burning, and impassable to such as are outlanders and have not their holdings there. He who sits there at the land's-end, to defend the land, is called Surtr; he brandishes a flaming sword, and at the end of the world he shall go forth and harry, and overcome all the gods, and burn all the world with fire. [ The Prose Edda, by Snorri Sturluson ] lug* Lugh, or Lug, was the sun god of the Irish Celts. One of his weapons was a rod-sling which worshippers sometimes saw in the sky as a rainbow. As a tribal god, he was particularly skilled in the use of his massive, invincible spear, which fought on its own accord. One of his epithets is _lamfhada_ (of the long arm). He was a young and apparently more attractive deity than Dagda, the father of the gods. Being able to shapeshift, his name translates as lynx. lurker* These dungeon scavengers are very adept at blending into the surrounding walls and ceilings of the dungeon due to the stone-like coloring of their skin. lycanthrope were* human were* *were In 1573, the Parliament of Dole published a decree, permitting the inhabitants of the Franche-Comte to pursue and kill a were-wolf or loup-garou, which infested that province, "notwithstanding the existing laws concerning the chase." The people were empowered to "assemble with javelins, halberds, pikes, arquebuses and clubs, to hunt and pursue the said were-wolf in all places where they could find it, and to take, burn, and kill it, without incurring any fine or other penalty." The hunt seems to have been successful, if we may judge from the fact that the same tribunal in the following year condemned to be burned a man named Giles Garnier, who ran on all fours in the forest and fields and devoured little children, "even on Friday." The poor lycanthrope, it appears, had as slight respect for ecclesiastical feasts as the French pig, which was not restrained by any feeling of piety from eating infants on a fast day. [ The History of Vampires, by Dudley Wright ] lynx To dream of seeing a lynx, enemies are undermining your business and disrupting your home affairs. For a woman, this dream indicates that she has a wary woman rivaling her in the affections of her lover. If she kills the lynx, she will overcome her rival. [ 10,000 Dreams Interpreted, by Gustavus Hindman Miller ] magic marker The pen is mightier than the sword. [ Richelieu, by Edward Bulwer-Lytton ] magic mirror of merlin This powerful mirror was created by Merlin, the druid, in ages past, when trees sang and rocks danced. It protects all who carry it from magic missiles, and gives them ESP. mail d*emon It is rumoured that these strange creatures can be harmed by domesticated canines only. ma*annan* Normally called Manannan, Ler's son was the patron of merchants and sailors. Manannan had a sword which never failed to slay, a boat which propelled itself wherever its owner wished, a horse which was swifter than the wind, and magic armour which no sword could pierce. He later became god of the sea, beneath which he lived in Tir na nOc, the underworld. manes The gnats of the dungeon, these swarming monsters are rarely seen alone. marduk First insisting on recognition as supreme commander, Marduk defeated the Dragon, cut her body in two, and from it created heaven and earth, peopling the world with human beings who not unnaturally showed intense gratitude for their lives. The gods were also properly grateful, invested him with many titles, and eventually permitted themselves to be embodied in him, so that he became supreme god, plotting the whole course of known life from the paths of the planets to the daily events in the lives of men. [ The Immortals, by Derek and Julia Parker ] marilith The marilith has a torso shaped like that of a human female, and the lower body of a great snake. It has multiple arms, and can freely attack with all of them. Since it is intelligent enough to use weapons, this means it can cause great damage. mars The god of war, and one of the most prominent and worshipped gods. In early Roman history he was a god of spring, growth in nature, and fertility, and the protector of cattle. Mars is also mentioned as a chthonic god (earth-god) and this could explain why he became a god of death and finally a god of war. He is the son of Jupiter and Juno. [ Encyclopedia Mythica, ed. M.F. Lindemans ] master assassin He strolled down the stairs, followed by a number of assassins. When he was directly in front of Ymor he said: "I've come for the tourist." ... "One step more and you'll leave here with fewer eyeballs than you came with," said the thiefmaster. "So sit down and have a drink, Zlorf, and let's talk about this sensibly. _I_ thought we had an agreement. You don't rob -- I don't kill. Not for payment, that is," he added after a pause. Zlorf took the proffered beer. "So?" he said. "I'll kill him. Then you rob him. Is he that funny looking one over there?" "Yes." Zlorf stared at Twoflower, who grinned at him. He shrugged. He seldom wasted time wondering why people wanted other people dead. It was just a living. "Who is your client, may I ask?" said Ymor. Zlorf held up a hand. "Please!" he protested. "Professional etiquette." [ The Colour of Magic, by Terry Pratchett ] master key of thievery This skeleton key was fashioned in ages past and imbued with a powerful magic which allows it to open any lock. When carried, it grants its owner warning, teleport control, and reduces all physical damage by half. Finally, when invoked, it has the ability to disarm any trap. master of thieves There was a flutter of wings at the window. Ymor shifted his bulk out of the chair and crossed the room, coming back with a large raven. After he'd unfastened the message capsule from its leg it flew up to join its fellows lurking among the rafters. Withel regarded it without love. Ymor's ravens were notoriously loyal to their master, to the extent that Withel's one attempt to promote himself to the rank of greatest thief in Ankh-Morpork had cost their master's right hand man his left eye. But not his life, however. Ymor never grudged a man his ambitions. [ The Colour of Magic, by Terry Pratchett ] mastodon Any large, elephantlike mammal of the genera Mammut, Mastodon, etc., from the Oligocene and Pleistocene epochs, having conical projections on the molar teeth. [ Webster's Encyclopedic Unabridged Dictionary of the English Language ] meat* huge chunk of meat Some hae meat and canna eat, And some would eat that want it; But we hae meat, and we can eat, Sae let the Lord be thankit. [ Grace Before Meat, by Robert Burns ] medusa Medusa, one of the three Gorgons or Graeae, is the only one of her sisters to have assumed mortal form and inhabited the dungeon world. When Perseus was grown up Polydectes sent him to attempt the conquest of Medusa, a terrible monster who had laid waste the country. She was once a beautiful maiden whose hair was her chief glory, but as she dared to vie in beauty with Minerva, the goddess deprived her of her charms and changed her beautiful ringlets into hissing serpents. She became a cruel monster of so frightful an aspect that no living thing could behold her without being turned into stone. All around the cavern where she dwelt might be seen the stony figures of men and animals which had chanced to catch a glimpse of her and had been petrified with the sight. Perseus, favoured by Minerva and Mercury, the former of whom lent him her shield and the latter his winged shoes, approached Medusa while she slept and taking care not to look directly at her, but guided by her image reflected in the bright shield which he bore, he cut off her head and gave it to Minerva, who fixed it in the middle of her Aegis. [ Bulfinch's Mythology, by Thomas Bulfinch ] melon "What is it, Umbopa, son of a fool?" I shouted in Zulu. "It is food and water, Macumazahn," and again he waved the green thing. Then I saw what he had got. It was a melon. We had hit upon a patch of wild melons, thousands of them, and dead ripe. "Melons!" I yelled to Good, who was next me; and in another second he had his false teeth fixed in one. I think we ate about six each before we had done, and, poor fruit as they were, I doubt if I ever thought anything nicer. [ King Solomon's Mines, by H. Rider Haggard ] mercury Roman god of commerce, trade and travellers. He is commonly depicted carrying a caduceus (a staff with two snakes intertwining around it) and a purse. *mimic The ancestors of the modern day chameleon, these creatures can assume the form of anything in their surroundings. They may assume the shape of objects or dungeon features. Unlike the chameleon though, which assumes the shape of another creature and goes in hunt of food, the mimic waits patiently for its meals to come in search of it. *mind flayer This creature has a humanoid body, tentacles around its covered mouth, and three long fingers on each hand. Mind flayers are telepathic, and love to devour intelligent beings, especially humans. If they hit their victim with a tentacle, the mind flayer will slowly drain it of all intelligence, eventually killing its victim. mine* Made by Dwarfs. The Rule here is that the Mine is either long deserted or at most is inhabited by a few survivors who will make confused claims to have been driven out/decimated by humans/ other Dwarfs/Minions of the Dark Lord. Inhabited or not, this Mine will be very complex, with many levels of galleries, beautifully carved and engineered. What was being mined here is not always evident, but at least some of the time it will appear to have been Jewels, since it is customary to find unwanted emeralds, etc., still embedded in the rock of the walls. Metal will also be present, but only when made up into armor and weapons (_wondrous_). [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] minotaur The Minotaur was a monster, half bull, half human, the offspring of Minos' wife Pasiphae and a wonderfully beautiful bull. ... When the Minotaur was born Minos did not kill him. He had Daedalus, a great architect and inventor, construct a place of confinement for him from which escape was impossible. Daedalus built the Labyrinth, famous throughout the world. Once inside, one would go endlessly along its twisting paths without ever finding the exit. [ Mythology, by Edith Hamilton ] mit*ra* Originating in India (Mitra), Mithra is a god of light who was translated into the attendant of the god Ahura Mazda in the light religion of Persia; from this he was adopted as the Roman deity Mithras. He is not generally regarded as a sky god but a personification of the fertilizing power of warm, light air. According to the _Avesta_, he possesses 10,000 eyes and ears and rides in a chariot drawn by white horses. Mithra, according to Zarathustra, is concerned with the endless battle between light and dark forces: he represents truth. He is responsible for the keeping of oaths and contracts. He is attributed with the creation of both plants and animals. His chief adversary is Ahriman, the power of darkness. [ The Encyclopaedia of Myths and Legends of All Nations, by Herbert Spencer Robinson and Knox Wilson ] *mithril* _Mithril_! All folk desired it. It could be beaten like copper, and polished like glass; and the Dwarves could make of it a metal, light and yet harder than tempered steel. Its beauty was like to that of common silver, but the beauty of _mithril_ did not tarnish or grow dim. [ The Fellowship of the Ring, by J.R.R. Tolkien ] *mitre of holiness This helm of brilliance performs all of the normal functions of a helm of brilliance, but also has the ability to protect anyone who carries it from fire. When invoked, it boosts the energy of the invoker, allowing them to cast more spells. mjollnir Forged by the dwarves Eitri and Brokk, in response to Loki's challenge, Mjollnir is an indestructible war hammer. It has two magical properties: when thrown it always returned to Thor's hand; and it could be made to shrink in size until it could fit inside Thor's shirt. Its only flaw is that it has a short handle. The other gods judged Mjollnir the winner of the contest because, of all the treasures created, it alone had the power to protect them from the giants. As the legends surrounding Mjollnir grew, it began to take on the quality of "vigja", or consecration. Thor used it to consecrate births, weddings, and even to raise his goats from the dead. In the Norse mythologies Mjollnir is considered to represent Thor's governance over the entire cycle of life - fertility, birth, destruction, and resurrection. ~slime mold *mold Mold, multicellular organism of the division Fungi, typified by plant bodies composed of a network of cottony filaments. The colors of molds are due to spores borne on the filaments. Most molds are saprophytes. Some species (e.g., penicillium) are used in making cheese and antibiotics. [ The Concise Columbia Encyclopedia ] mol?ch And the Lord spake unto Moses, saying, Again, thou shalt say to the children of Israel, Whosoever he be of the children of Israel, or of the strangers that sojourn in Israel, that giveth any of his seed unto Molech; he shall surely be put to death: the people of the land shall stone him with stones. And I will set my face against that man, and will cut him off from among his people; because he hath given of his seed unto Molech, to defile my sanctuary, and to profane my holy name. And if the people of the land do any ways hide their eyes from the man, when he giveth of his seed unto Molech, and kill him not: Then I will set my face against that man, and against his family, and will cut him off, and all that go a whoring after him, to commit whoredom with Molech, from among their people. [ Leviticus 20:1-5 ] monk * monk grand master master kaen One day, an army general invited the Buddhist monk I-Hsiu (literally, "One Rest") to his military head office for a dinner. I-Hsiu was not accustomed to wearing luxurious clothings and so he just put on an old ordinary casual robe to go to the military base. To him, "form is void". As he approached the base, two soldiers appeared before him and shouted, "Where does this beggar came from? Identify yourself! You do not have permission to be around here!" "My name is I-Hsiu Dharma Master. I am invited by your general for a supper." The two soldiers examined the monk closely and said, "You liar. How come my general invites such a shabby monk to dinner? He invites the very solemn venerable I-Hsiu to our base for a great ceremony today, not you. Now, get out!" I-Hsiu was unable to convince the soldiers that he was indeed the invited guest, so he returned to the temple and changed to a very formal solemn ceremonial robe for the dinner. And as he returned to the military base, the soldiers observed that he was such a great Buddhist monk, let him in with honour. At the dinner, I-Hsiu sat in front of the table full of food but, instead of putting the food into his month, he picked up the food with his chopsticks and put it into his sleeves. The general was curious, and whispered to him, "This is very embarrassing. Do you want to take some food back to the temple? I will order the cook to prepare some take out orders for you." "No" replied the monk. "When I came here, I was not allowed into the base by your soldiers until I wear this ceremonial robe. You do not invite me for a dinner. You invite my robe. Therefore, my robe is eating the food, not me." [ Dining with a General - a Zen Buddhism Koan ] monkey "Listen, man-cub," said the Bear, and his voice rumbled like thunder on a hot night. "I have taught thee all the Law of the Jungle for all the peoples of the jungle--except the Monkey-Folk who live in the trees. They have no law. They are outcasts. They have no speech of their own, but use the stolen words which they overhear when they listen, and peep, and wait up above in the branches. Their way is not our way. They are without leaders. They have no remembrance. They boast and chatter and pretend that they are a great people about to do great affairs in the jungle, but the falling of a nut turns their minds to laughter and all is forgotten. We of the jungle have no dealings with them. We do not drink where the monkeys drink; we do not go where the monkeys go; we do not hunt where they hunt; we do not die where they die...." [ The Jungle Book, by Rudyard Kipling ] mumak* ... the Mumak of Harad was indeed a beast of vast bulk, and the like of him does not walk now in Middle-Earth; his kin that live still in latter days are but memories of his girth and majesty. On he came, ... his great legs like trees, enormous sail-like ears spread out, long snout upraised like a huge serpent about to strike, his small red eyes raging. His upturned hornlike tusks ... dripped with blood. [ The Two Towers, by J.R.R. Tolkien ] *mummy But for an account of the manner in which the body was bandaged, and a list of the unguents and other materials employed in the process, and the words of power which were spoken as each bandage was laid in its place, we must have recourse to a very interesting papyrus which has been edited and translated by M. Maspero under the title of Le Rituel de l'Embaumement. ... Everything that could be done to preserve the body was now done, and every member of it was, by means of the words of power which changed perishable substances into imperishable, protected to all eternity; when the final covering of purple or white linen had been fastened upon it, the body was ready for the tomb. [ Egyptian Magic, by E.A. Wallis Budge ] mummy wrapping He held a white cloth -- it was a serviette he had brought with him -- over the lower part of his face, so that his mouth and jaws were completely hidden, and that was the reason for his muffled voice. But it was not that which startled Mrs. Hall. It was the fact that all his forehead above his blue glasses was covered by a white bandage, and that another covered his ears, leaving not a scrap of his face exposed excepting only his pink, peaked nose. It was bright, pink, and shiny just as it had been at first. He wore a dark-brown velvet jacket with a high, black, linen- lined collar turned up about his neck. The thick black hair, escaping as it could below and between the cross bandages, project in curious tails and horns, giving him the strangest appearance conceivable. [ The Invisible Man, by H.G. Wells ] *naga* *naja* The naga is a mystical creature with the body of a snake and the head of a man or woman. They will fiercely protect the territory they consider their own. Some nagas can be forced to serve as guardians by a spellcaster of great power. naginata A Japanese pole-arm, fitted with a curved single-edged blade. The blades ranged in length from two to four feet, mounted on shafts about four to five feet long. The naginata were cut with a series of short grooves near to the tang, above which the back edge was thinned, but not sharpened, so that the greater part of the blade was a flattened diamond shape in section. Seen in profile, the curve is slight or non- existent near the tang, becoming more pronounced towards the point. "With his naginata he killed five, but with the sixth it snapped asunder in the midst and, flinging it away, he drew his sword, wielding it in the zigzag style, the interlacing, cross, reversed dragonfly, waterwheel, and eight-sides-at- once styles of fencing and cutting down eight men; but as he brought down the ninth with a mighty blow on the helmet, the blade snapped at the hilt." [ Story of Tsutsui no Jomio Meishu from Tales of Heike ] nalfeshnee Not only do these demons do physical damage with their claws and bite, but they are capable of using magic as well. nalzok Nalzok is Moloch's cunning and unfailingly loyal battle lieutenant, to whom he trusts the command of warfare when he does not wish to exercise it himself. Nalzok is a major demon, known to command the undead. He is hungry for power, and secretly covets Moloch's position. Moloch doesn't trust him, but, trusting his own power enough, chooses to allow Nalzok his position because he is useful. neanderthal* 1. Valley between Duesseldorf and Elberfeld in Germany, where an ancient skull of a prehistoric ancestor to modern man was found. 2. Human(oid) of the race mentioned above. neferet neferet the green Neferet the Green holds office in her hidden tower, only reachable by magical means, where she teaches her apprentices the enigmatic skills of occultism. Despite her many years, she continues to investigate new spells, especially those involving translocation. It is further rumored that when she was an apprentice herself, she accidentally turned her skin green, and has kept it that way ever since. newt (kinds of) small animal, like a lizard, which spends most of its time in the water. [ Oxford's Student's Dictionary of Current English ] "Fillet of a fenny snake, In the cauldron boil and bake; Eye of newt and toe of frog, Wool of bat and tongue of dog, Adder's fork and blind-worm's sting, Lizard's leg and howlet's wing, For a charm of powerful trouble, Like a hell-broth boil and bubble." [ Macbeth, by William Shakespeare ] ninja-to A Japanese broadsword. *norn The Norns were the three Norse Fates, or the goddesses of fate. Female giants, they brought the wonderful Golden Age to an end. They cast lots over the cradle of every child that was born, and placed gifts in the cradle. Their names were Urda, Verdandi, and Skuld, representing the past, the present, and the future. Urda and Verdandi were kindly disposed, but Skuld was cruel and savage. Their tasks were to sew the web of fate, to water the sacred ash, Yggdrasil, and to keep it in good condition by placing fresh earth around it daily. In her fury, Skuld often spoiled the work of her sisters by tearing the web to shreds. [ The Encyclopedia of Myths and Legends of All Nations by Herbert Spencer Robinson and Knox Wilson ] nunchaku A Japanese flail. *nymph A female creature from Roman and Greek mythology, the nymph occupied rivers, forests, ponds, etc. A nymph's beauty is beyond words: an ever-young woman with sleek figure and long, thick hair, radiant skin and perfect teeth, full lips and gentle eyes. A nymph's scent is delightful, and her long robe glows, hemmed with golden threads and embroidered with rainbow hues of unearthly magnificence. A nymph's demeanour is graceful and charming, her mind quick and witty. "Theseus felt her voice pulling him down into fathoms of sleep. The song was the skeleton of his dream, and the dream was full of terror. Demon girls were after him, and a bull- man was goring him. Everywhere there was blood. There was pain. There was fear. But his head was in the nymph's lap and her musk was about him, her voice weaving the dream. He knew then that she had been sent to tell him of something dreadful that was to happen to him later. Her song was a warning. But she had brought him a new kind of joy, one that made him see everything differently. The boy, who was to become a hero, suddenly knew then what most heroes learn later -- and some too late -- that joy blots suffering and that the road to nymphs is beset by monsters." [ The Minotaur by Bernard Evslin ] odin Also called Sigtyr (god of Victory), Val-father (father of the slain), One-Eyed, Hanga-god (god of the hanged), Farma- god (god of cargoes), Hapta-god (god of prisoners), and Othin. He is the prime god of the Norsemen: god of war and victory, wisdom and prophecy, poetry, the dead, air and wind, hospitality, and magic. As the god of war and victory, Odin is ruler of the Valkyries, warrior-maidens who lived in the halls of Valhalla in Asgard, the hall of dead heroes where he held his court. These chosen ones will defend the realm of the gods against the Frost Giants on the final day of reckoning, Ragnarok. As god of the wind, Odin rides through the air on his eight- footed horse, Sleipnir, wielding Gungner, his spear, normally accompanied by his ravens, Hugin and Munin, who he would also use as his spies. As a god of hospitality, he enjoys visiting the earth in disguise to see how people were behaving and to see how they would treat him, not knowing who he was. Odin is usually represented as a one-eyed wise old man with a long white beard and a wide-brimmed hat (he gave one of his eyes to Mimir, the guardian of the well of wisdom in Hel, in exchange for a draught of knowledge). ogre* Anyone who has met a gluttonous, nude, angry ogre, will not easily forget this encounter -- if he survives it at all. Both male and female ogres can easily grow as tall as three metres. Build and facial expressions would remind one of a Neanderthal. Its small, pointy, keen teeth are striking. Since ogres avoid direct sunlight, their ragged, unfurry skin is as white as a sheet. They enjoy coating their body with lard and usually wear nothing but a loin-cloth. An elf would smell its rancid stench at ten metres distance. Ogres are solitary creatures: very rarely one may encounter a female with two or three young. They are the only real carnivores among the humanoids, and its favourite meal is -- not surprisingly -- human flesh. They sometimes ally with orcs or goblins, but only when they anticipate a good meaty meal. [ het Boek van de Regels; Het Oog des Meesters ] oilskin cloak During our watches below we overhauled our clothes, and made and mended everything for bad weather. Each of us had made for himself a suit of oil-cloth or tarpaulin, and these we got out, and gave thorough coatings of oil or tar, and hung upon the stays to dry. Our stout boots, too, we covered over with a thick mixture of melted grease and tar. Thus we took advantage of the warm sun and fine weather of the Pacific to prepare for its other face. [ Two Years Before the Mast, by Richard Henry Dana ] oilskin sack Summer passed all too quickly. On the last day of camp, Mr. Brickle called his counselors together and paid them what he owed them. Louis received one hundred dollars - the first money he had ever earned. He had no wallet and no pockets, so Mr. Brickle placed the money in a waterproof bag that had a drawstring. He hung this moneybag around Louis' neck, along with the trumpet, the slate, the chalk pencil, and the lifesaving medal. [ The Trumpet of the Swan, by E.B. White ] olog-hai But at the end of the Third Age a troll-race not before seen appeared in southern Mirkwood and in the mountain borders of Mordor. Olog-hai they were called in the Black Speech. That Sauron bred them none doubted, though from what stock was not known. Some held that they were not Trolls but giant Orcs; but the Olog-hai were in fashion of body and mind quite unlike even the largest of Orc-kind, whom they far surpassed in size and power. Trolls they were, but filled with the evil will of their master: a fell race, strong, agile, fierce and cunning, but harder than stone. Unlike the older race of the Twilight they could endure the Sun.... They spoke little, and the only tongue they knew was the Black Speech of Barad-dur. [ The Return of the King, by J.R.R. Tolkien ] oracle delphi p*thia Delphi under towering Parnassus, where Apollo's oracle was, plays an important part in mythology. Castalia was its sacred spring; Cephissus its river. It was held to be the center of the world, so many pilgrims came to it, from foreign countries as well as Greece. No other shrine rivaled it. The answers to the questions asked by the anxious seekers for Truth were delivered by a priestess who went into a trance before she spoke. [ Mythology, by Edith Hamilton ] orange pear What was the fruit like? Unfortunately, no one can describe a taste. All I can say is that, compared with those fruits, the freshest grapefruit you've ever eaten was dull, and the juiciest orange was dry, and the most melting pear was hard and woody, and the sweetest wild strawberry was sour. And there were no seeds or stones, and no wasps. If you had once eaten that fruit, all the nicest things in this world would taste like medicines after it. But I can't describe it. You can't find out what it is like unless you can get to that country and taste it for yourself. [ The Last Battle, by C.S. Lewis ] pyrolisk At first glance around the corner, I thought it was another cockatrice. I had encountered the wretched creatures two or three times since leaving the open area. I quickly ducked my head back and considered what to do next. My heart had begun to thump audibly as I patted my pack to make sure I still had the dead lizards at close reach. A check of my attire showed no obvious holes or damage. I had to keep moving. One deep breath, and a count of three, two, one, and around the corner I bolted. But it was no cockatrice! I felt a sudden intense searing of the skin around my face, and flames began to leap from my pack. I tossed it to the ground, and quickly retreated back, around that corner, desperately striving to get out of its sight. *orb of detection This Orb is a crystal ball of exceptional powers. When carried, it grants ESP, limits damage done by spells, and protects the carrier from magic missiles. When invoked it allows the carrier to become invisible. orb of fate Some say that Odin himself created this ancient crystal ball, although others argue that Loki created it and forged Odin's signature on the bottom. In any case, it is a powerful artifact. Anyone who carries it is granted the gift of warning, and damage, both spell and physical, is partially absorbed by the orb itself. When invoked it has the power to teleport the invoker between levels. goblin king orcrist The Great Goblin gave a truly awful howl of rage when he looked at it, and all his soldiers gnashed their teeth, clashed their shields, and stamped. They knew the sword at once. It had killed hundreds of goblins in its time, when the fair elves of Gondolin hunted them in the hills or did battle before their walls. They had called it Orcrist, Goblin-cleaver, but the goblins called it simply Biter. They hated it and hated worse any one that carried it. [ The Hobbit, by J.R.R. Tolkien ] orcus Orcus, Prince of the Undead, has a ram's head and a poison stinger. He is most feared, though, for his powerful magic abilities. His wand causes death to those he chooses. ~orc ??m* ~orcish barbarian ~orcish ranger ~orcish rogue ~orcish wizard orc* * orc uruk*hai Orcs, bipeds with a humanoid appearance, are related to the goblins, but much bigger and more dangerous. The average orc is only moderately intelligent, has broad, muscled shoulders, a short neck, a sloping forehead and a thick, dark fur. Their lower eye-teeth are pointing forward, like a boar's. Female orcs are more lightly built and bare-chested. Not needing any clothing, they do like to dress in variegated apparels. Suspicious by nature, orcs live in tribes or hordes. They tend to live underground as well as above ground (but they dislike sunlight). Orcs can use all weapons, tools and armours that are used by men. Since they don't have the talent to fashion these themselves, they are constantly hunting for them. There is nothing a horde of orcs cannot use. [ het Boek van de Regels; Het Oog des Meesters ] orion sirius Orion was the son of Neptune. He was a handsome giant and a mighty hunter. His father gave him the power of wading through the depths of the sea, or, as others say, of walking on its surface. He dwelt as a hunter with Diana (Artemis), with whom he was a favourite, and it is even said she was about to marry him. Her brother was highly displeased and often chid her, but to no purpose. One day, observing Orion wading through the sea with his head just above the water, Apollo pointed it out to his sister and maintained that she could not hit that black thing on the sea. The archer-goddess discharged a shaft with fatal aim. The waves rolled the dead body of Orion to the land, and bewailing her fatal error with many tears, Diana placed him among the stars, where he appears as a giant, with a girdle, sword, lion's skin, and club. Sirius, his dog, follows him, and the Pleiads fly before him. [ Bulfinch's Mythology, by Thomas Bulfinch ] osaku The osaku is a small tool for picking locks. owlbear Owlbears are probably the crossbreed creation of a demented wizard; given the lethal nature of this creation, it is quite likely the wizard who created them is no longer alive. As the name might already suggest, owlbears are a cross between a giant owl and a bear. They are covered with fur and feathers. panther And lo! almost where the ascent began, A panther light and swift exceedingly, Which with a spotted skin was covered o'er! And never moved she from before my face, Nay, rather did impede so much my way, That many times I to return had turned. [ Dante's Inferno, as translated by Henry Wadsworth Longfellow ] pelias Conan cried out sharply and recoiled, thrusting his companion back. Before them rose the great shimmering white form of Satha, an ageless hate in its eyes. Conan tensed himself for one mad berserker onslaught -- to thrust the glowing faggot into that fiendish countenance and throw his life into the ripping sword- stroke. But the snake was not looking at him. It was glaring over his shoulder at the man called Pelias, who stood with his arms folded, smiling. And in the great, cold, yellow eyes slowly the hate died out in a glitter of pure fear -- the only time Conan ever saw such an expression in a reptile's eyes. With a swirling rush like the sweep of a strong wind, the great snake was gone. "What did he see to frighten him?" asked Conan, eyeing his companion uneasily. "The scaled people see what escapes the mortal eye," answered Pelias cryptically. "You see my fleshy guise, he saw my naked soul." [ Conan the Usurper, by Robert E. Howard and L. Sprague de Camp ] pick*ax* The mine is full of holes; With the wound of pickaxes. But look at the goldsmith's store. There, there is gold everywhere. [ Divan-i Kebir Meter 2, by Mevlana Celaleddin Rumi ] *piercer Ye Piercer doth look like unto a stalactyte, and hangeth from the roofs of caves and caverns. Unto the height of a man, and thicker than a man's thigh do they grow, and in groups do they hang. If a creature doth pass beneath them, they will by its heat and noise perceive it, and fall upon it to kill and devour it, though in any other way they move but exceeding slow. [ the Bestiary of Xygag ] piranha They live in "schools." Many times they will wait for prey to come to the shallow water of the river. Then the large group of piranhas will attack. These large groups are able to kill large animals... Their lower teeth fit perfectly into the spaces of their upper teeth, creating a tremendous vice-like bite... Piranhas are attracted to any disturbance in the water. [ http://www.animalsoftherainforest.com ] pit spiked pit Amid the thought of the fiery destruction that impended, the idea of the coolness of the well came over my soul like balm. I rushed to its deadly brink. I threw my straining vision below. The glare from the enkindled roof illumined its inmost recesses. Yet, for a wild moment, did my spirit refuse to comprehend the meaning of what I saw. At length it forced -- it wrestled its way into my soul -- it burned itself in upon my shuddering reason. Oh! for a voice to speak! -- oh! horror! -- oh! any horror but this! [ The Pit and the Pendulum, by Edgar Allan Poe ] pit fiend Pit fiends are among the more powerful of devils, capable of attacking twice with weapons as well as grabbing and crushing the life out of those unwary enough to enter their domains. platinum yendorian express card This is an ancient artifact made of an unknown material. It is rectangular in shape, very thin, and inscribed with unreadable ancient runes. When carried, it grants the one who carries it ESP, and reduces all spell induced damage done to the carrier by half. It also protects from magic missile attacks. Finally, its power is such that when invoked, it can charge other objects. pony Hey! now! Come hoy now! Whither do you wander? Up, down, near or far, here, there or yonder? Sharp-ears, Wise-nose, Swish-tail and Bumpkin, White-socks my little lad, and old Fatty Lumpkin! [...] Tom called them one by one and they climbed over the brow and stood in a line. Then Tom bowed to the hobbits. "Here are your ponies, now!" he said. "They've more sense (in some ways) than you wandering hobbits have -- more sense in their noses. For they sniff danger ahead which you walk right into; and if they run to save themselves, then they run the right way." [ The Fellowship of the Ring, by J.R.R. Tolkien ] *portal Portals can be Mirrors, Pictures, Standing Stones, Stone Circles, Windows, and special gates set up for the purpose. You will travel through them both to distant parts of the continent and to and from our own world. The precise manner of their working is a Management secret. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] poseido*n Poseido(o)n, lord of the seas and father of rivers and fountains, was the son of Chronos and Rhea, brother of Zeus, Hades, Hera, Hestia and Demeter. His rank of ruler of the waves he received by lot at the Council Meeting of the Gods, at which Zeus took the upper world for himself and gave dominion over the lower world to Hades. Poseidon is associated in many ways with horses and thus is the god of horses. He taught men how to ride and manage the animal he invented and is looked upon as the originator and guardian deity of horse races. His symbol is the familiar trident or three-pronged spear with which he can split rocks, cause or quell storms, and shake the earth, a power which makes him the god of earthquakes as well. Physically, he is shown as a strong and powerful ruler, every inch a king. [ The Encyclopedia of Myths and Legends of All Nations, by Herbert Robinson and Knox Wilson ] *potion* POTABLE, n. Suitable for drinking. Water is said to be potable; indeed, some declare it our natural beverage, although even they find it palatable only when suffering from the recurrent disorder known as thirst, for which it is a medicine. Upon nothing has so great and diligent ingenuity been brought to bear in all ages and in all countries, except the most uncivilized, as upon the invention of substitutes for water. To hold that this general aversion to that liquid has no basis in the preservative instinct of the race is to be unscientific -- and without science we are as the snakes and toads. [ The Devil's Dictionary, by Ambrose Bierce ] priest* * priest* acolyte [...] For the two priests were talking exactly like priests, piously, with learning and leisure, about the most aerial enigmas of theology. The little Essex priest spoke the more simply, with his round face turned to the strengthening stars; the other talked with his head bowed, as if he were not even worthy to look at them. But no more innocently clerical conversation could have been heard in any white Italian cloister or black Spanish cathedral. The first he heard was the tail of one of Father Brown's sentences, which ended: "... what they really meant in the Middle Ages by the heavens being incorruptible." The taller priest nodded his bowed head and said: "Ah, yes, these modern infidels appeal to their reason; but who can look at those millions of worlds and not feel that there may well be wonderful universes above us where reason is utterly unreasonable?" [ The Innocence of Father Brown, by G.K. Chesterton ] prisoner Where am I? In the Village. What do you want? Information. Whose side are you on? That would be telling. We want information ... information ... You won't get it. By hook or by crook, we will. Who are you? The new Number 2. Who is Number 1? You are Number 6. I am not a number! I am a free man! [ The Prisoner, by Patrick McGoohan ] ptah Known under various names (Nu, Neph, Cenubis, Amen-Kneph, Khery-Bakef), Ptah is the creator god and god of craftsmen. He is usually depicted as wearing a closely fitting robe with only his hands free. His most distinctive features are the invariable skull-cap exposing only his face and ears, and the _was_ or rod of domination which he holds, consisting of a staff surmounted by the _ankh_ symbol of life. He is otherwise symbolized by his sacred animal, the bull. *purple worm A gargantuan version of the harmless rain-worm, the purple worm poses a huge threat to the ordinary adventurer. It is known to swallow whole and digest its victims within only a few minutes. These worms are always on guard, sensitive to the most minute vibrations in the earth, but may also be awakened by a remote shriek. quadruped The woodlands and other regions are inhabited by multitudes of four-legged creatures which cannot be simply classified. They might not have fiery breath or deadly stings, but adventurers have nevertheless met their end numerous times due to the claws, hooves, or bites of such animals. quantum mechanic These creatures are not native to this universe; they seem to have strangely derived powers, and unknown motives. quasit Quasits are small, evil creatures, related to imps. Their talons release a very toxic poison when used in an attack. quest Many, possibly most, Tours are organized as a Quest. This is like a large-scale treasure hunt, with clues scattered all over the continent, a few false leads, Mystical Masters as game-show hosts, and the Dark Lord and the Terrain to make the Quest interestingly difficult. [...] In order to be assured of your future custom, the Management has a further Rule: Tourists, far from being rewarded for achieving their Quest Object, must then go on to conquer the Dark Lord or set about Saving the World, or both. And why not? By then you will have had a lot of practice in that sort of thing and, besides, the Quest Object is usually designed to help you do it. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] quetzalcoatl One of the principal Aztec-Toltec gods was the great and wise Quetzalcoatl, who was called Kukumatz in Guatemala, and Kukulcan in Yucatan. His image, the plumed serpent, is found on both the oldest and the most recent Indian edifices. ... The legend tells how the Indian deity Quetzalcoatl came from the "Land of the Rising Sun". He wore a long white robe and had a beard; he taught the people crafts and customs and laid down wise laws. He created an empire in which the ears of corn were as long as men are tall, and caused bolls of colored cotton to grow on cotton plants. But for some reason or other he had to leave his empire. ... But all the legends of Quetzalcoatl unanimously agree that he promised to come again. [ Gods, Graves, and Scholars, by C. W. Ceram ] quit* Maltar: [...] I remembered a little saying I learned my first day at the academy. Natalie: Yeah, yeah, I know. Winners never quit and quitters never win. Maltar: What? No! Winners never quit and quitters should be cast into the flaming pit of death. [ Snow Day, directed by Chris Koch, written by Will McRobb and Chris Viscardi ] raijin raiden The god of thunder. ranger * ranger "Lonely men are we, Rangers of the wild, hunters -- but hunters ever of the servants of the Enemy; for they are found in many places, not in Mordor only. If Gondor, Boromir, has been a stalwart tower, we have played another part. Many evil things there are that your strong walls and bright swords do not stay. You know little of the lands beyond your bounds. Peace and freedom, do you say? The North would have known them little but for us. Fear would have destroyed them. But when dark things come from the houseless hills, or creep from sunless woods, they fly from us. What roads would any dare to tread, what safety would there be in quiet lands, or in the homes of simple men at night, if the Dunedain were asleep, or were all gone into the grave?" [ The Fellowship of the Ring, by J.R.R. Tolkien ] rat * rat Rats are long-tailed rodents. They are aggressive, omnivorous, and adaptable, often carrying diseases. "The rat," said O'Brien, still addressing his invisible audience, "although a rodent, is carnivorous. You are aware of that. You will have heard of the things that happen in the poor quarters of this town. In some streets a woman dare not leave her baby alone in the house, even for five minutes. The rats are certain to attack it. Within quite a small time they will strip it to the bones. They also attack sick or dying people. They show astonishing intelligence in knowing when a human being is helpless." [ 1984, by George Orwell ] raven But the raven, sitting lonely on the placid bust, spoke only That one word, as if his soul in that one word he did outpour. Nothing further then he uttered -- not a feather then he fluttered-- Till I scarcely more than muttered, 'other friends have flown before-- On the morrow *he* will leave me, as my hopes have flown before.' Then the bird said, 'Nevermore.' [ The Raven - Edgar Allan Poe ] *ring ring of * Three Rings for the Elven-kings under the sky, Seven for the Dwarf-lords in their halls of stone, Nine for Mortal Men doomed to die, One for the Dark Lord on his dark throne, In the Land of Mordor where the Shadows lie. One Ring to rule them all, One Ring to find them, One Ring to bring them all and in the darkness bind them In the Land of Mordor where the Shadows lie. [ The Fellowship of the Ring, by J.R.R. Tolkien ] robe Robes are the only garments, apart from Shirts, ever to have sleeves. They have three uses: 1. As the official uniform of Priests, Priestesses, Monks, Nuns (see Nunnery), and Wizards. The OMT [ Official Management Term ] prescribed for the Robes of Priests and Nuns is that they _fall in severe folds_; of Priestesses that they _float_; and of Wizards that they _swirl_. You can thus see who you are dealing with. 2. For Kings. The OMT here is _falling in stately folds_. 3. As the garb of Desert Nomads. [...] [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] rock Bilbo saw that the moment had come when he must do something. He could not get up at the brutes and he had nothing to shoot with; but looking about he saw that in this place there were many stones lying in what appeared to be a now dry little watercourse. Bilbo was a pretty fair shot with a stone, and it did not take him long to find a nice smooth egg-shaped one that fitted his hand cosily. As a boy he used to practise throwing stones at things, until rabbits and squirrels, and even birds, got out of his way as quick as lightning if they saw him stoop; and even grownup he had still spent a deal of his time at quoits, dart-throwing, shooting at the wand, bowls, ninepins and other quiet games of the aiming and throwing sort - indeed he could do lots of things, besides blowing smoke-rings, asking riddles and cooking, that I haven't time to tell you about. There is no time now. While he was picking up stones, the spider had reached Bombur, and soon he would have been dead. At that moment Bilbo threw. The stone struck the spider plunk on the head, and it dropped senseless off the tree, flop to the ground, with all its legs curled up. [ The Hobbit, by J.R.R. Tolkien ] rock mole A rock mole is a member of the rodent family. They get their name from their ability to tunnel through rock in the same fashion that a mole tunnels through earth. They are known to eat anything they come across in their diggings, although it is still unknown how they convert some of these things into something of nutritional value. rogue * rogue I understand the business, I hear it: to have an open ear, a quick eye, and a nimble hand, is necessary for a cut-purse; a good nose is requisite also, to smell out work for the other senses. I see this is the time that the unjust man doth thrive. <...> The prince himself is about a piece of iniquity, stealing away from his father with his clog at his heels: if I thought it were a piece of honesty to acquaint the king withal, I would not do't: I hold it the more knavery to conceal it; and therein am I constant to my profession. [ Autolycus the Rogue, from The Winter's Tale by William Shakespeare ] rothe The rothe (pronounced roth-AY) is a musk ox-like creature with an aversion to light. It prefers to live underground near lichen and moss. *royal jelly "'Royal Jelly,'" he read aloud, "'must be a substance of tremendous nourishing power, for on this diet alone, the honey-bee larva increases in weight fifteen hundred times in five days!'" "How much?" "Fifteen hundred times, Mabel. And you know what that means if you put it in terms of a human being? It means," he said, lowering his voice, leaning forward, fixing her with those small pale eyes, "it means that in five days a baby weighing seven and a half pounds to start off with would increase in weight to five tons!" [ Royal Jelly, by Roald Dahl ] rust monster These strange creatures live on a diet of metals. They can turn a suit of armour into so much useless rusted scrap in no time at all. *saber *sabre Flashed all their sabres bare, Flashed as they turned in air, Sab'ring the gunners there, Charging an army, while All the world wondered: Plunged in the battery smoke, Right through the line they broke; Cossack and Russian Reeled from the sabre-stroke Shattered and sundered. Then they rode back, but not-- Not the six hundred. [ The Charge of the Light Brigade, by Alfred, Lord Tennyson ] saddle The horseman serves the horse, The neat-herd serves the neat, The merchant serves the purse, The eater serves his meat; 'Tis the day of the chattel, Web to weave, and corn to grind, Things are in the saddle, And ride mankind. [ Ode, by Ralph Waldo Emerson ] sake Japanese rice wine. salamander For hundreds of years, many people believed that salamanders were magical. In England in the Middle Ages, people thought that fire created salamanders. When they set fire to damp logs, dozens of the slimy creatures scurried out. The word salamander, in fact, comes from a Greek word meaning "fire animal". [ Salamanders, by Cherie Winner ] samurai * samurai By that time, Narahara had already slipped his arm from the sleeve of his outer robe, drew out his two-and-a-half-foot Fujiwara Tadahiro sword, and, brandishing it over his head, began barreling toward the foreigners. In less than a minute, he had charged upon them and cut one of them through the torso. The man fled, clutching his bulging guts, finally to fall from his horse at the foot of a pine tree about a thousand yards away. Kaeda Takeji finished him off. The other two Englishmen were severely wounded as they tried to flee. Only the woman managed to escape virtually unscathed. [ The Fox-horse, from Drunk as a Lord, by Ryotaro Shiba ] sandestin Ildefonse left the terrace and almost immediately sounds of contention came from the direction of the work-room. Ildefonse presently returned to the terrace, followed by Osherl and a second sandestin using the guise of a gaunt blue bird-like creature, some six feet in height. Ildefonse spoke in scathing tones: "Behold these two creatures! They can roam the chronoplex as easily as you or I can walk around the table; yet neither has the wit to announce his presence upon arrival. I found Osherl asleep in his fulgurite and Sarsem perched in the rafters." [...] "No matter," said Rhialto. "He has brought Sarsem, and this was his requirement. In the main, Osherl, you have done well!" "And my indenture point?" "Much depends upon Sarsem's testimony. Sarsem, will you sit?" "In this guise, I find it more convenient to stand." "Then why not alter to human form and join us in comfort at the table?" "That is a good idea." Sarsem became a naked young epicene in an integument of lavender scales with puffs of purple hair like pom-poms growing down his back. He seated himself at the table but declined refreshment. "This human semblance, though typical, is after all, only a guise. If I were to put such things inside myself, I might well become uneasy." [ Rhialto the Marvellous, by Jack Vance ] sasquatch The name _Sasquatch_ doesn't really become important in Canada until the 1930s, when it appeared in the works of J. W. Burns, a British Columbian writer who used a great deal of Indian lore in his stories. Burn's Sasquatch was a giant Indian who lived in the wilderness. He was hairy only in the sense that he had long hair on his head, and while this Sasquatch lived a wild and primitive life, he was fully human. Burns's character proved to be quite popular. There was a Sasquatch Inn near the town of Harrison, British Columbia, and Harrison even had a local celebration called "Sasquatch Days." The celebration which had been dormant for years was revived as part of British Columbia's centennial, and one of the events was to be a Sasquatch hunt. The hunt never took place, perhaps it was never supposed to, but the publicity about it did bring out a number of people who said they had encountered a Sasquatch -- not Burns's giant Indian, but the hairy apelike creature that we have all come to know. [ The Encyclopedia of Monsters, by Daniel Cohen ] *sceptre of might This mace was created aeons ago in some unknown cave, and has been passed down from generation to generation of cave dwellers. It is a very mighty mace indeed, and in addition will protect anyone who carries it from magic missile attacks. When invoked, it causes conflict in the area around it. scimitar Oh, how handsome, how noble was the Vizier Ali Tebelin, my father, as he stood there in the midst of the shot, his scimitar in his hand, his face black with powder! How his enemies fled before him! [ The Count of Monte Cristo, by Alexandre Dumas ] scorpio* A sub-species of the spider (_Scorpionidae_), the scorpion distinguishes itself from them by having a lower body that ends in a long, jointed tail tapering to a poisonous stinger. They have eight legs and pincers. [ Van Dale's Groot Woordenboek der Nederlandse Taal ] scorpius Since early times, the Scorpion has represented death, darkness, and evil. Scorpius is the reputed slayer of Orion the Hunter. [...] The gods put both scorpion and hunter among the stars, but on opposite sides of the sky so they would never fight again. As Scorpius rises in the east, Orion sets in the west. [ 365 Starry Nights, by Chet Raymo ] *scroll scroll * And I was gazing on the surges prone, With many a scalding tear and many a groan, When at my feet emerg'd an old man's hand, Grasping this scroll, and this same slender wand. I knelt with pain--reached out my hand--had grasp'd Those treasures--touch'd the knuckles--they unclasp'd-- I caught a finger: but the downward weight O'erpowered me--it sank. Then 'gan abate The storm, and through chill aguish gloom outburst The comfortable sun. I was athirst To search the book, and in the warming air Parted its dripping leaves with eager care. Strange matters did it treat of, and drew on My soul page after page, till well-nigh won Into forgetfulness; when, stupefied, I read these words, and read again, and tried My eyes against the heavens, and read again. [ Endymion, by John Keats ] shad* Shades are undead creatures. They differ from zombies in that a zombie is an undead animation of a corpse, while a shade is an undead creature magically created by the use of black magic. shaman karnov Making his quarters in the Caves of the Ancestors, Shaman Karnov unceasingly tries to shield his neanderthal people from Tiamat's minions' harassments. shan*lai*ching The Chinese god of Mountains and Seas, also the name of an old book (also Shan Hai Tjing), the book of mountains and seas - which deals with the monster Kung Kung trying to seize power from Yao, the fourth emperor. [ Spectrum Atlas van de Mythologie ] shark As the shark moved, its dark top reflected virtually no light. The denticles on its skin muted the whoosh of its movements as the shark rose, driven by the power of the great tail sweeping from side to side, like a scythe. The fish exploded upward. Charles Bruder felt a slight vacuum tug in the motion of the sea, noted it as a passing current, the pull of a wave, the tickle of undertow. He could not have heard the faint sucking rush of water not far beneath him. He couldn't have seen or heard what was hurtling from the murk at astonishing speed, jaws unhinging, widening, for the enormous first bite. It was the classic attack that no other creature in nature could make -- a bomb from the depths. [ Close to Shore, by Michael Capuzzo ] shito A Japanese stabbing knife. shrieker With a single, savage thrust of her spear, the warrior-woman impaled the fungus, silencing it. However, it was too late: the alarm had been raised[...] Suddenly, a large, dark shape rose from the abyss before them, its fetid bulk looming overhead...The monster was some kind of great dark worm, but that was about all they were sure of. [ The Adventurers, Epic IV, by Thomas A. Miller ] skeleton A skeleton is a magically animated undead creature. Unlike shades, only a humanoid creature can be used to create a skeleton. No one knows why this is true, but it has become an accepted fact amongst the practitioners of the black arts. slasher "That dog belonged to a settler who tried to build his cabin on the bank of the river a few miles south of the fort," grunted Conan. ... "We took him to the fort and dressed his wounds, but after he recovered he took to the woods and turned wild. -- What now, Slasher, are you hunting the men who killed your master?" ... "Let him come," muttered Conan. "He can smell the devils before we can see them." ... Slasher cleared the timbers with a bound and leaped into the bushes. They were violently shaken and then the dog slunk back to Balthus' side, his jaws crimson. ... "He was a man," said Conan. "I drink to his shade, and to the shade of the dog, who knew no fear." He quaffed part of the wine, then emptied the rest upon the floor, with a curious heathen gesture, and smashed the goblet. "The heads of ten Picts shall pay for this, and seven heads for the dog, who was a better warrior than many a man." [ Conan The Warrior, by Robert E Howard ] slime mold Slime mold or slime fungus, organism usually classified with the fungi, but showing equal affinity to the protozoa. Slime molds have complex life cycles with an animal-like motile phase, in which feeding and growth occur, and a plant-like immotile reproductive phase. The motile phase, commonly found under rotting logs and damp leaves, consists of either solitary amoebalike cells or a brightly colored multinucleate mass of protoplasm called a plasmodium, which creeps about and feeds by amoeboid movement. [ The Concise Columbia Encyclopedia ] sling And it came to pass, when the Philistine arose, and came and drew nigh to meet David, that David hasted, and ran toward the army to meet the Philistine. And David put his hand in his bag, and took thence a stone, and slang it, and smote the Philistine in his forehead, that the stone sunk into his forehead; and he fell upon his face to the earth. So David prevailed over the Philistine with a sling and with a stone, and smote the Philistine, and slew him; but there was no sword in the hand of David. [ 1 Samuel 17:48-50 ] *snake serpent water moccasin python pit viper Now the serpent was more subtle than any beast of the field which the Lord God had made. And he said unto the woman, Yea, hath God said, Ye shall not eat of every tree of the garden? And the woman said unto the serpent, We may eat of the fruit of the trees of the garden: but of the fruit of the tree which is in the midst of the garden, God hath said, Ye shall not eat of it, neither shall ye touch it, lest ye die. And the serpent said unto the woman, Ye shall not surely die: for God doth know that in the day ye eat thereof, then your eyes shall be opened, and ye shall be as gods, knowing good and evil. And when the woman saw that the tree was good for food, and that it was pleasant to the eyes, and a tree to be desired to make one wise, she took of the fruit thereof, and did eat, and gave also unto her husband with her; and he did eat. And the Lord God said unto the woman, What is this that thou hast done? And the woman said, The serpent beguiled me, and I did eat. And the Lord God said unto the serpent, Because thou hast done this, thou art cursed above all cattle, and above every beast of the field; upon thy belly shalt thou go, and dust shalt thou eat all the days of thy life: And I will put enmity between thee and the woman, and between thy seed and her seed; it shall bruise thy head, and thou shalt bruise his heel. [ Genesis 3:1-6,13-15 ] snickersnee Ah, never shall I forget the cry, or the shriek that shrieked he, As I gnashed my teeth, and from my sheath I drew my Snickersnee! --Koko, Lord high executioner of Titipu [ The Mikado, by Sir W.S. Gilbert ] sokoban Sokoban (Japanese for "warehouse person") is a puzzle-type game where the player must push around treasure to a goal area. It apparently won first prize in a Japanese programming contest. [ Xsokoban web site ] *soldier sergeant lieutenant captain The soldiers of Yendor are well-trained in the art of war, many trained by the Wizard himself. Some say the soldiers are explorers who were unfortunate enough to be captured, and put under the Wizard's spell. Those who have survived encounters with soldiers say they travel together in platoons, and are fierce fighters. Because of the load of their combat gear, however, one can usually run away from them, and doing so is considered a wise thing. *spear javelin - they come together with great random, and a spear is brast, and one party brake his shield and the other one goes down, horse and man, over his horse-tail and brake his neck, and then the next candidate comes randoming in, and brast his spear, and the other man brast his shield, and down he goes, horse and man, over his horse-tail, and brake his neck, and then there's another elected, and another and another and still another, till the material is all used up; and when you come to figure up results, you can't tell one fight from another, nor who whipped; and as a picture of living, raging, roaring battle, sho! why it's pale and noiseless - just ghosts scuffling in a fog. Dear me, what would this barren vocabulary get out of the mightiest spectacle? - the burning of Rome in Nero's time, for instance? Why, it would merely say 'Town burned down; no insurance; boy brast a window, fireman brake his neck!' Why, that ain't a picture! [ A Connecticut Yankee in King Arthur's Court, by Mark Twain ] *spellbook* The Book of Three lay closed on the table. Taran had never been allowed to read the volume for himself; now he was sure it held more than Dallben chose to tell him. In the sun- filled room, with Dallben still meditating and showing no sign of stopping, Taran rose and moved through the shimmering beams. From the forest came the monotonous tick of a beetle. His hands reached for the cover. Taran gasped in pain and snatched them away. They smarted as if each of his fingers had been stung by hornets. He jumped back, stumbled against the bench, and dropped to the floor, where he put his fingers woefully into his mouth. Dallben's eyes blinked open. He peered at Taran and yawned slowly. "You had better see Coll about a lotion for those hands," he advised. "Otherwise, I shouldn't be surprised if they blistered." [ The Book of Three, by Lloyd Alexander ] *spider Eight legged creature capable of spinning webs to trap prey. "You mean you eat flies?" gasped Wilbur. "Certainly. Flies, bugs, grasshoppers, choice beetles, moths, butterflies, tasty cockroaches, gnats, midges, daddy longlegs, centipedes, mosquitoes, crickets - anything that is careless enough to get caught in my web. I have to live, don't I?" "Why, yes, of course," said Wilbur. [ Charlotte's Web, by E.B. White ] *spore *sphere The attack by those who want to die -- this is the attack against which you cannot prepare a perfect defense. --Human aphorism [ The Dosadi Experiment, by Frank Herbert ] ~*aesculapius *staff So they stood, each in his place, neither moving a finger's breadth back, for one good hour, and many blows were given and received by each in that time, till here and there were sore bones and bumps, yet neither thought of crying "Enough," or seemed likely to fall from off the bridge. Now and then they stopped to rest, and each thought that he never had seen in all his life before such a hand at quarterstaff. At last Robin gave the stranger a blow upon the ribs that made his jacket smoke like a damp straw thatch in the sun. So shrewd was the stroke that the stranger came within a hair's breadth of falling off the bridge; but he regained himself right quickly, and, by a dexterous blow, gave Robin a crack on the crown that caused the blood to flow. Then Robin grew mad with anger, and smote with all his might at the other; but the stranger warded the blow, and once again thwacked Robin, and this time so fairly that he fell heels over head into the water, as the queen pin falls in a game of bowls. [ The Merry Adventures of Robin Hood, by Howard Pyle ] *staff of aesculapius This staff is considered sacred to all healers, as it truly holds the powers of life and death. When wielded, it protects its user from all life draining attacks, and additionally gives the wielder the power of regeneration. When invoked it performs healing magic. stair* Up he went -- very quickly at first -- then more slowly -- then in a little while even more slowly than that -- and finally, after many minutes of climbing up the endless stairway, one weary foot was barely able to follow the other. Milo suddenly realized that with all his effort he was no closer to the top than when he began, and not a great deal further from the bottom. But he struggled on for a while longer, until at last, completely exhausted, he collapsed onto one of the steps. "I should have known it," he mumbled, resting his tired legs and filling his lungs with air. "This is just like the line that goes on forever, and I'll never get there." "You wouldn't like it much anyway," someone replied gently. "Infinity is a dreadfully poor place. They can never manage to make ends meet." [ The Phantom Tollbooth, by Norton Juster ] Dr. Ray Stantz: Hey, where do those stairs go? Dr. Peter Venkman: They go up. [ Ghostbusters, directed by Ivan Reitman, written by Dan Ackroyd and Harold Ramis ] ~statue trap statue* Then at last he began to wonder why the lion was standing so still - for it hadn't moved one inch since he first set eyes on it. Edmund now ventured a little nearer, still keeping in the shadow of the arch as much as he could. He now saw from the way the lion was standing that it couldn't have been looking at him at all. ("But supposing it turns its head?" thought Edmund.) In fact it was staring at something else - namely a little dwarf who stood with his back to it about four feet away. "Aha!" thought Edmund. "When it springs at the dwarf then will be my chance to escape." But still the lion never moved, nor did the dwarf. And now at last Edmund remembered what the others had said about the White Witch turning people into stone. Perhaps this was only a stone lion. And as soon as he had thought of that he noticed that the lion's back and the top of its head were covered with snow. Of course it must be only a statue! [ The Lion, the Witch and the Wardrobe by C.S. Lewis ] sting There was the usual dim grey light of the forest-day about him when he came to his senses. The spider lay dead beside him, and his sword-blade was stained black. Somehow the killing of the giant spider, all alone and by himself in the dark without the help of the wizard or the dwarves or of anyone else, made a great difference to Mr. Baggins. He felt a different person, and much fiercer and bolder in spite of an empty stomach, as he wiped his sword on the grass and put it back into its sheath. "I will give you a name," he said to it, "and I shall call you Sting." [ The Hobbit, by J.R.R. Tolkien ] stormbringer There were sounds in the distance, incongruent with the sounds of even this nameless, timeless sea: thin sounds, agonized and terrible, for all that they remained remote - yet the ship followed them, as if drawn by them; they grew louder - pain and despair were there, but terror was predominant. Elric had heard such sounds echoing from his cousin Yyrkoon's sardonically named 'Pleasure Chambers' in the days before he had fled the responsibilities of ruling all that remained of the old Melnibonean Empire. These were the voices of men whose very souls were under siege; men to whom death meant not mere extinction, but a continuation of existence, forever in thrall to some cruel and supernatural master. He had heard men cry so when his salvation and his nemesis, his great black battle-blade Stormbringer, drank their souls. [ The Lands Beyond the World, by Michael Moorcock ] susano*o The Shinto chthonic and weather god and brother of the sun goddess Amaterasu, he was born from the nose of the primordial creator god Izanagi and represents the physical, material world. He has been expelled from heaven and taken up residence on earth. [ Encyclopedia of Gods, by Michael Jordan ] tanko Samurai plate armor of the Yamato period (AD 300 - 710). tengu The tengu was the most troublesome creature of Japanese legend. Part bird and part man, with red beak for a nose and flashing eyes, the tengu was notorious for stirring up feuds and prolonging enmity between families. Indeed, the belligerent tengu were supposed to have been man's first instructors in the use of arms. [ Mythical Beasts, by Deirdre Headon (The Leprechaun Library) ] thoth The Egyptian god of the moon and wisdom, Thoth is the patron deity of scribes and of knowledge, including scientific, medical and mathematical writing, and is said to have given mankind the art of hieroglyphic writing. He is important as a mediator and counsellor amongst the gods and is the scribe of the Heliopolis Ennead pantheon. According to mythology, he was born from the head of the god Seth. He may be depicted in human form with the head of an ibis, wholly as an ibis, or as a seated baboon sometimes with its torso covered in feathers. His attributes include a crown which consists of a crescent moon surmounted by a moon disc. Thoth is generally regarded as a benign deity. He is also scrupulously fair and is responsible not only for entering in the record the souls who pass to afterlife, but of adjudicating in the Hall of the Two Truths. The Pyramid Texts reveal a violent side of his nature by which he decapitates the adversaries of truth and wrenches out their hearts. [ Encyclopedia of Gods, by Michael Jordan ] thoth*amon Men say that he [Thutothmes] has opposed Thoth-Amon, who is master of all priests of Set, and dwells in Luxor, and that Thutothmes seeks hidden power [The Heart of Ahriman] to overthrow the Great One. [ Conan the Conqueror, by Robert E. Howard ] *throne Methought I saw the footsteps of a throne Which mists and vapours from mine eyes did shroud-- Nor view of who might sit thereon allowed; But all the steps and ground about were strown With sights the ruefullest that flesh and bone Ever put on; a miserable crowd, Sick, hale, old, young, who cried before that cloud, "Thou art our king, O Death! to thee we groan." Those steps I clomb; the mists before me gave Smooth way; and I beheld the face of one Sleeping alone within a mossy cave, With her face up to heaven; that seemed to have Pleasing remembrance of a thought foregone; A lovely Beauty in a summer grave! [ Sonnet, by William Wordsworth ] tiger 1. A well-known tropical predator (_Felis tigris_): a feline. It has a yellowish skin with darker spots or stripes. 2. Figurative: _a paper tiger_, something that is meant to scare, but has no really scaring effect whatsoever, (after a statement by Mao Ze Dong, August 1946). [ Van Dale's Groot Woordenboek der Nederlandse Taal ] Tyger! Tyger! burning bright In the forests of the night, What immortal hand or eye Could frame thy fearful symmetry? [ The Tyger, by William Blake ] tin tin of * tinning kit "You know salmon, Sarge," said Nobby. "It is a fish of which I am aware, yes." "You know they sell kind of slices of it in tins..." "So I am given to understand, yes." "Weell...how come all the tins are the same size? Salmon gets thinner at both ends." "Interesting point, Nobby. I think-" [ Soul Music, by Terry Pratchett ] tin opener Less than thirty Cat tribes now survived, roaming the cargo decks on their hind legs in a desperate search for food. But the food had gone. The supplies were finished. Weak and ailing, they prayed at the supply hold's silver mountains: huge towering acres of metal rocks which, in their pagan way, the mutant Cats believed watched over them. Amid the wailing and the screeching one Cat stood up and held aloft the sacred icon. The icon which had been passed down as holy, and one day would make its use known. It was a piece of V-shaped metal with a revolving handle on its head. He took down a silver rock from the silver mountain, while the other Cats cowered and screamed at the blasphemy. He placed the icon on the rim of the rock, and turned the handle. And the handle turned. And the rock opened. And inside the rock was Alphabetti spaghetti in tomato sauce. [ Red Dwarf, by Rob Grant and Doug Naylor ] titan Gaea, mother earth, arose from the Chaos and gave birth to Uranus, heaven, who became her consort. Uranus hated all their children, because he feared they might challenge his own authority. Those children, the Titans, the Gigantes, and the Cyclops, were banished to the nether world. Their enraged mother eventually released the youngest titan, Chronos (time), and encouraged him to castrate his father and rule in his place. Later, he too was challenged by his own son, Zeus, and he and his fellow titans were ousted from Mount Olympus. [ Greek Mythology, by Richard Patrick ] touch*stone "Gold is tried by a touchstone, men by gold." [ Chilon (c. 560 BC) ] tourist * tourist The road from Ankh-Morpork to Chrim is high, white and winding, a thirty-league stretch of potholes and half-buried rocks that spirals around mountains and dips into cool green valleys of citrus trees, crosses liana-webbed gorges on creaking rope bridges and is generally more picturesque than useful. Picturesque. That was a new word to Rincewind the wizard (BMgc, Unseen University [failed]). It was one of a number he had picked up since leaving the charred ruins of Ankh-Morpork. Quaint was another one. Picturesque meant -- he decided after careful observation of the scenery that inspired Twoflower to use the word -- that the landscape was horribly precipitous. Quaint, when used to describe the occasional village through which they passed, meant fever- ridden and tumbledown. Twoflower was a tourist, the first ever seen on the discworld. Tourist, Rincewind had decided, meant "idiot". [ The Colour of Magic, by Terry Pratchett ] towel The Hitchhiker's Guide to the Galaxy has a few things to say on the subject of towels. A towel, it says, is about the most massively useful thing an interstellar hitchhiker can have. Partly it has great practical value. You can wrap it around you for warmth as you bound across the cold moons of Jaglan Beta; you can lie on it on the brilliant marble-sanded beaches of Santraginus V, inhaling the heady sea vapors; you can sleep under it beneath the stars which shine so redly on the desert world of Kakrafoon; use it to sail a miniraft down down the slow heavy River Moth; wet it for use in hand-to-hand combat; wrap it round your head to ward off noxious fumes or avoid the gaze of the Ravenous Bugblatter Beast of Traal (a mind-bogglingly stupid animal, it assumes that if you can't see it, it can't see you - daft as a brush, but very very ravenous); you can wave your towel in emergencies as a distress signal, and of course dry yourself off with it if it still seems to be clean enough. [ The Hitchhiker's Guide to the Galaxy, by Douglas Adams ] *tower Towers (_brooding_, _dark_) stand alone in Waste Areas and almost always belong to Wizards. All are several stories high, round, doorless, virtually windowless, and composed of smooth blocks of masonry that make them very hard to climb. [...] You will have to go to a Tower and then break into it at some point towards the end of your Tour. [ The Tough Guide to Fantasyland, by Diana Wynne Jones ] trap*door I knew my Erik too well to feel at all comfortable on jumping into his house. I knew what he had made of a certain palace at Mazenderan. From being the most honest building conceivable, he soon turned it into a house of the very devil, where you could not utter a word but it was overheard or repeated by an echo. With his trap-doors the monster was responsible for endless tragedies of all kinds. [ The Phantom of the Opera, by Gaston Leroux ] trapper The trapper is a creature which has evolved a chameleon-like ability to blend into the dungeon surroundings. It captures its prey by remaining very still and blending into the surrounding dungeon features, until an unsuspecting creature passes by. It wraps itself around its prey and digests it. tree I think that I shall never see A poem lovely as a tree. A tree whose hungry mouth is prest Against the earth's sweet flowing breast; A tree that looks at God all day, And lifts her leafy arms to pray; A tree that may in Summer wear A nest of robins in her hair; Upon whose bosom snow has lain; Who intimately lives with rain. Poems are made by fools like me, But only God can make a tree. [ Trees - Joyce Kilmer ] tripe tripe ration If you start from scratch, cooking tripe is a long-drawn-out affair. Fresh whole tripe calls for a minimum of 12 hours of cooking, some time-honored recipes demanding as much as 24. To prepare fresh tripe, trim if necessary. Wash it thoroughly, soaking overnight, and blanch, for 1/2 hour in salted water. Wash well again, drain and cut for cooking. When cooked, the texture of tripe should be like that of soft gristle. More often, alas, because the heat has not been kept low enough, it has the consistency of wet shoe leather. [ Joy of Cooking, by I Rombauer and M Becker ] *troll The troll shambled closer. He was perhaps eight feet tall, perhaps more. His forward stoop, with arms dangling past thick claw-footed legs to the ground, made it hard to tell. The hairless green skin moved upon his body. His head was a gash of a mouth, a yard-long nose, and two eyes which drank the feeble torchlight and never gave back a gleam. [...] Like a huge green spider, the troll's severed hand ran on its fingers. Across the mounded floor, up onto a log with one taloned forefinger to hook it over the bark, down again it scrambled, until it found the cut wrist. And there it grew fast. The troll's smashed head seethed and knit together. He clambered back on his feet and grinned at them. The waning faggot cast red light over his fangs. [ Three Hearts and Three Lions, by Poul Anderson ] *tsurugi of muramasa This most ancient of swords has been passed down through the leadership of the Samurai legions for hundreds of years. It is said to grant luck to its wielder, but its main power is terrible to behold. It has the capability to cut in half any creature it is wielded against, instantly killing them. ~*muramasa tsurugi The tsurugi, also known as the long samurai sword, is an extremely sharp, two-handed blade favored by the samurai. It is made of hardened steel, and is manufactured using a special process, causing it to never rust. The tsurugi is rumored to be so sharp that it can occasionally cut opponents in half! twoflower guide "Rincewind!" Twoflower sprang off the bed. The wizard jumped back, wrenching his features into a smile. "My dear chap, right on time! We'll just have lunch, and then I'm sure you've got a wonderful programme lined up for this afternoon!" "Er --" "That's great!" Rincewind took a deep breath. "Look," he said desperately, "let's eat somewhere else. There's been a bit of a fight down below." "A tavern brawl? Why didn't you wake me up?" "Well, you see, I - _what_?" "I thought I made myself clear this morning, Rincewind. I want to see genuine Morporkian life - the slave market, the Whore Pits, the Temple of Small Gods, the Beggar's Guild... and a genuine tavern brawl." A faint note of suspicion entered Twoflower's voice. "You _do_ have them, don't you? You know, people swinging on chandeliers, swordfights over the table, the sort of thing Hrun the Barbarian and the Weasel are always getting involved in. You know -- _excitement_." [ The Colour of Magic, by Terry Pratchett ] tyr Yet remains that one of the Aesir who is called Tyr: he is most daring, and best in stoutness of heart, and he has much authority over victory in battle; it is good for men of valor to invoke him. It is a proverb, that he is Tyr-valiant, who surpasses other men and does not waver. He is wise, so that it is also said, that he that is wisest is Tyr-prudent. This is one token of his daring: when the Aesir enticed Fenris-Wolf to take upon him the fetter Gleipnir, the wolf did not believe them, that they would loose him, until they laid Tyr's hand into his mouth as a pledge. But when the Aesir would not loose him, then he bit off the hand at the place now called 'the wolf's joint;' and Tyr is one- handed, and is not called a reconciler of men. [ The Prose Edda, by Snorri Sturluson ] *hulk Umber hulks are powerful subterranean predators whose iron-like claws allow them to burrow through solid stone in search of prey. They are tremendously strong; muscles bulge beneath their thick, scaly hides and their powerful arms and legs all end in great claws. *unicorn unicorn horn Men have always sought the elusive unicorn, for the single twisted horn which projected from its forehead was thought to be a powerful talisman. It was said that the unicorn had simply to dip the tip of its horn in a muddy pool for the water to become pure. Men also believed that to drink from this horn was a protection against all sickness, and that if the horn was ground to a powder it would act as an antidote to all poisons. Less than 200 years ago in France, the horn of a unicorn was used in a ceremony to test the royal food for poison. Although only the size of a small horse, the unicorn is a very fierce beast, capable of killing an elephant with a single thrust from its horn. Its fleetness of foot also makes this solitary creature difficult to capture. However, it can be tamed and captured by a maiden. Made gentle by the sight of a virgin, the unicorn can be lured to lay its head in her lap, and in this docile mood, the maiden may secure it with a golden rope. [ Mythical Beasts, by Deirdre Headon (The Leprechaun Library) ] Martin took a small sip of beer. "Almost ready," he said. "You hold your beer awfully well." Tlingel laughed. "A unicorn's horn is a detoxicant. Its possession is a universal remedy. I wait until I reach the warm glow stage, then I use my horn to burn off any excess and keep me right there." [ Unicorn Variations, by Roger Zelazny ] valkyrie * valkyrie The Valkyries were the thirteen choosers of the slain, the beautiful warrior-maids of Odin who rode through the air and over the sea. They watched the progress of the battle and selected the heroes who were to fall fighting. After they were dead, the maidens rewarded the heroes by kissing them and then led their souls to Valhalla, where the warriors lived happily in an ideal existence, drinking and eating without restraint and fighting over again the battles in which they died and in which they had won their deathless fame. [ The Encyclopaedia of Myths and Legends of All Nations, by Herbert Robinson and Knox Wilson ] vampire vampire bat vampire lord The Oxford English Dictionary is quite unequivocal: _vampire_ - "a preternatural being of a malignant nature (in the original and usual form of the belief, a reanimated corpse), supposed to seek nourishment, or do harm, by sucking the blood of sleeping persons. ..." venus Venus, the goddess of love and beauty, was the daughter of Jupiter and Dione. Others say that Venus sprang from the foam of the sea. The zephyr wafted her along the waves to the Isle of Cyprus, where she was received and attired by the Seasons, and then led to the assembly of the gods. All were charmed with her beauty, and each one demanded her for his wife. Jupiter gave her to Vulcan, in gratitude for the service he had rendered in forging thunderbolts. So the most beautiful of the goddesses became the wife of the most ill-favoured of gods. [ Bulfinch's Mythology, by Thomas Bulfinch ] vlad* Vlad Dracula the Impaler was a 15th-Century monarch of the Birgau region of the Carpathian Mountains, in what is now Romania. In Romanian history he is best known for two things. One was his skilled handling of the Ottoman Turks, which kept them from making further inroads into Christian Europe. The other was the ruthless manner in which he ran his fiefdom. He dealt with perceived challengers to his rule by impaling them upright on wooden stakes. Visiting dignitaries who failed to doff their hats had them nailed to their head. *vortex vortices Swirling clouds of pure elemental energies, the vortices are thought to be related to the larger elementals. Though the vortices do no damage when touched, they are noted for being able to envelop unwary travellers. The hapless fool thus swallowed by a vortex will soon perish from exposure to the element the vortex is composed of. vrock The vrock is one of the weaker forms of demon. It resembles a cross between a human being and a vulture and does physical damage by biting and by using the claws on both its arms and feet. wakizashi The samurai warrior traditionally wears two swords; the wakizashi is the shorter of the two. See also katana. wand of * *wand 'Saruman!' he cried, and his voice grew in power and authority. 'Behold, I am not Gandalf the Grey, whom you betrayed. I am Gandalf the White, who has returned from death. You have no colour now, and I cast you from the order and from the Council.' He raised his hand, and spoke slowly in a clear cold voice. 'Saruman, your staff is broken.' There was a crack, and the staff split asunder in Saruman's hand, and the head of it fell down at Gandalf's feet. 'Go!' said Gandalf. With a cry Saruman fell back and crawled away. [ The Two Towers, by J.R.R. Tolkien ] warg Suddenly Aragorn leapt to his feet. "How the wind howls!" he cried. "It is howling with wolf-voices. The Wargs have come west of the Mountains!" "Need we wait until morning then?" said Gandalf. "It is as I said. The hunt is up! Even if we live to see the dawn, who now will wish to journey south by night with the wild wolves on his trail?" "How far is Moria?" asked Boromir. "There was a door south-west of Caradhras, some fifteen miles as the crow flies, and maybe twenty as the wolf runs," answered Gandalf grimly. "Then let us start as soon as it is light tomorrow, if we can," said Boromir. "The wolf that one hears is worse than the orc that one fears." "True!" said Aragorn, loosening his sword in its sheath. "But where the warg howls, there also the orc prowls." [ The Fellowship of the Ring, by J.R.R. Tolkien ] ~mjollnir war*hammer They had come together at the ford of the Trident while the battle crashed around them, Robert with his warhammer and his great antlered helm, the Targaryen prince armored all in black. On his breastplate was the three-headed dragon of his House, wrought all in rubies that flashed like fire in the sunlight. The waters of the Trident ran red around the hooves of their destriers as they circled and clashed, again and again, until at last a crushing blow from Robert's hammer stove in the dragon and the chest behind it. When Ned had finally come on the scene, Rhaegar lay dead in the stream, while men of both armies scrambled in the swirling waters for rubies knocked free of his armor. [ A Game of Thrones, by George R.R. Martin ] water Day after day, day after day, We stuck, nor breath nor motion; As idle as a painted ship Upon a painted ocean. Water, water, everywhere, And all the boards did shrink; Water, water, everywhere Nor any drop to drink. [ The Rime of the Ancient Mariner, by Samuel Taylor Coleridge ] web Oh what a tangled web we weave, When first we practise to deceive! [ Marmion, by Sir Walter Scott ] # werecritter -- see "lycanthrope" *wight When he came to himself again, for a moment he could recall nothing except a sense of dread. Then suddenly he knew that he was imprisoned, caught hopelessly; he was in a barrow. A Barrow-wight had taken him, and he was probably already under the dreadful spells of the Barrow-wights about which whispered tales spoke. He dared not move, but lay as he found himself: flat on his back upon a cold stone with his hands on his breast. [ The Fellowship of the Ring, by J.R.R. Tolkien ] # note: need to convert player character "gnomish wizard" into just "wizard" # in the lookup code to avoid conflict with the monster of that same name ~gnomish wizard wizard * wizard apprentice Ebenezum walked before me along the closest thing we could find to a path in these overgrown woods. Every few paces he would pause, so that I, burdened with a pack stuffed with arcane and heavy paraphernalia, could catch up with his wizardly strides. He, as usual, carried nothing, preferring, as he often said, to keep his hands free for quick conjuring and his mind free for the thoughts of a mage. [ A Dealing with Demons, by Craig Shaw Gardner ] wizard of yendor No one knows how old this mighty wizard is, or from whence he came. It is known that, having lived a span far greater than any normal man's, he grew weary of lesser mortals; and so, spurning all human company, he forsook the dwellings of men and went to live in the depths of the Earth. He took with him a dreadful artifact, the Book of the Dead, which is said to hold great power indeed. Many have sought to find the wizard and his treasure, but none have found him and lived to tell the tale. Woe be to the incautious adventurer who disturbs this mighty sorcerer! wolf *wolf *wolf cub The ancestors of the modern day domestic dog, wolves are powerful muscular animals with bushy tails. Intelligent, social animals, wolves live in family groups or packs made up of multiple family units. These packs cooperate in hunting down prey. woodchuck The Usenet Oracle requires an answer to this question! > How much wood could a woodchuck chuck if a woodchuck could > chuck wood? "Oh, heck! I'll handle *this* one!" The Oracle spun the terminal back toward himself, unlocked the ZOT-guard lock, and slid the glass guard away from the ZOT key. "Ummmm....could you turn around for a minute? ZOTs are too graphic for the uninitiated. Even *I* get a little squeamish sometimes..." The neophyte turned around, and heard the Oracle slam his finger on a computer key, followed by a loud ZZZZOTTTTT and the smell of ozone. [ Excerpted from Internet Oracularity 576.6 ] *worm long worm tail worm tooth crysknife [The crysknife] is manufactured in two forms from teeth taken from dead sandworms. The two forms are "fixed" and "unfixed". An unfixed knife requires proximity to a human body's electrical field to prevent disintegration. Fixed knives are treated for storage. All are about 20 centimeters long. [ Dune, by Frank Herbert ] wraith nazgul Immediately, though everything else remained as before, dim and dark, the shapes became terribly clear. He was able to see beneath their black wrappings. There were five tall figures: two standing on the lip of the dell, three advancing. In their white faces burned keen and merciless eyes; under their mantles were long grey robes; upon their grey hairs were helms of silver; in their haggard hands were swords of steel. Their eyes fell on him and pierced him, as they rushed towards him. Desperate, he drew his own sword, and it seemed to him that it flickered red, as if it was a firebrand. Two of the figures halted. The third was taller than the others: his hair was long and gleaming and on his helm was a crown. In one hand he held a long sword, and in the other a knife; both the knife and the hand that held it glowed with a pale light. He sprang forward and bore down on Frodo. [ The Fellowship of the Ring, by J.R.R. Tolkien ] wumpus The Wumpus, by the way, is not bothered by the hazards since he has sucker feet and is too big for a bat to lift. If you try to shoot him and miss, there's also a chance that he'll up and move himself into another cave, though by nature the Wumpus is a sedentary creature. [ wump (6) -- "Hunt the Wumpus" ] xan They sent their friend the mosquito [xan] ahead of them to find out what lay ahead. "Since you are the one who sucks the blood of men walking along paths," they told the mosquito, "go and sting the men of Xibalba." The mosquito flew down the dark road to the Underworld. Entering the house of the Lords of Death, he stung the first person that he saw... The mosquito stung this man as well, and when he yelled, the man next to him asked, "Gathered Blood, what's wrong?" So he flew along the row stinging all the seated men until he knew the names of all twelve. [ Popul Vuh, as translated by Ralph Nelson ] xorn A distant cousin of the earth elemental, the xorn has the ability to shift the cells of its body around in such a way that it becomes porous to inert material. This gives it the ability to pass through any obstacle that might be between it and its next meal. ya The arrow of choice of the samurai, ya are made of very straight bamboo, and are tipped with hardened steel. yeenoghu Yeenoghu, the demon lord of gnolls, still exists although all his followers have been wiped off the face of the earth. He casts magic projectiles at those close to him, and a mere gaze into his piercing eyes may hopelessly confuse the battle-weary adventurer. yeti The Abominable Snowman, or yeti, is one of the truly great unknown animals of the twentieth century. It is a large hairy biped that lives in the Himalayan region of Asia ... The story of the Abominable Snowman is filled with mysteries great and small, and one of the most difficult of all is how it got that awful name. The creature is neither particularly abominable, nor does it necessarily live in the snows. _Yeti_ is a Tibetan word which may apply either to a real, but unknown animal of the Himalayas, or to a mountain spirit or demon -- no one is quite sure which. And after nearly half a century in which Westerners have trampled around looking for the yeti, and asking all sorts of questions, the original native traditions concerning the creature have become even more muddled and confused. [ The Encyclopedia of Monsters, by Daniel Cohen ] *yugake Japanese leather archery gloves. Gloves made for use while practicing had thumbs reinforced with horn. Those worn into battle had thumbs reinforced with a double layer of leather. yumi The samurai is highly trained with a special type of bow, the yumi. Like the ya, the yumi is made of bamboo. With the yumi-ya, the bow and arrow, the samurai is an extremely accurate and deadly warrior. *zombie The zombi... is a soulless human corpse, still dead, but taken from the grave and endowed by sorcery with a mechanical semblance of life, -- it is a dead body which is made to walk and act and move as if it were alive. [ W. B. Seabrook ] zruty The zruty are wild and gigantic beings, living in the wildernesses of the Tatra mountains. nethack-3.4.3/dat/dungeon.def0100644000000000000000000001016307764735041014542 0ustar rootroot# SCCS Id: @(#)dungeon.def 3.4 1996/03/10 # Copyright (c) 1990-95 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The dungeon description file for the "standard" 3.1 NetHack. # # Note: The order of the definition of dungeons in this file # reflects in their order of creation in the real dungeon. # The "Main" branch must *always* be first. # Also note that the order of the dungeons in this file # determines the order in which branch levels are assigned. # If two dungeons have overlapping ranges for their entry # points, then you should list the dungeon with the _least_ # number of choices for its branch level _first_. # DUNGEON: "The Dungeons of Doom" "D" (25, 5) ALIGNMENT: unaligned BRANCH: "The Gnomish Mines" @ (2, 3) %REINCARNATION LEVEL: "rogue" "R" @ (15, 4) LEVEL: "oracle" "O" @ (5, 5) LEVALIGN: neutral CHAINBRANCH: "Sokoban" "oracle" + (1, 0) up RNDLEVEL: "bigrm" "B" @ (10, 3) 40 5 CHAINBRANCH: "The Quest" "oracle" + (6, 2) portal BRANCH: "Fort Ludios" @ (18, 4) portal RNDLEVEL: "medusa" "none" @ (-5, 4) 2 LEVALIGN: chaotic LEVEL: "castle" "none" @ (-1, 0) CHAINBRANCH: "Gehennom" "castle" + (0, 0) no_down BRANCH: "The Elemental Planes" @ (1, 0) no_down up # # Gehennom # # Now re-worked for 3.1, hell is hopefully going to be a little # less boring. Also, in 3.1, the tower is not considered as a # part of hell, but is set up as a separate dungeon. # # Gehennom is no longer considered "hellish" as a complete dungeon. # That is, fire resistance is no longer a condition for survival in # it. However, Gehennom, and the special levels in it in particular, # is abundant with fire traps. As a result, fire resistance is still # a prudent survival strategy in Gehennom. # # Note: Gehennom *must* be the second dungeon defined so that # monsters can properly migrate here under certain # circumstances. # DUNGEON: "Gehennom" "G" (20, 5) DESCRIPTION: mazelike DESCRIPTION: hellish ALIGNMENT: noalign BRANCH: "Vlad's Tower" @ (9, 5) up LEVEL: "valley" "V" @ (1, 0) LEVEL: "sanctum" "none" @ (-1, 0) LEVEL: "juiblex" "J" @ (4, 4) LEVEL: "baalz" "B" @ (6, 4) LEVEL: "asmodeus" "A" @ (2, 6) LEVEL: "wizard1" "none" @ (11, 6) CHAINLEVEL: "wizard2" "X" "wizard1" + (1, 0) CHAINLEVEL: "wizard3" "Y" "wizard1" + (2, 0) LEVEL: "orcus" "O" @ (10, 6) LEVEL: "fakewiz1" "F" @ (-6,4) LEVEL: "fakewiz2" "G" @ (-6,4) # # The Mines of the Gnomes of Zurich. # DUNGEON: "The Gnomish Mines" "M" (8, 2) ALIGNMENT: lawful DESCRIPTION: mazelike RNDLEVEL: "minetn" "T" @ (3, 2) 7 LEVELDESC: town RNDLEVEL: "minend" "E" @ (-1, 0) 3 # # The Questdungeon # # This is a proto-dungeon. The level file names will be prepended with # the first letter of the character name during initialization. # A special "x-fill" level must be defined in the levels description # file. It will be used for all levels not defined explicitly below. # DUNGEON: "The Quest" "Q" (5, 2) LEVEL: "x-strt" "none" @ (1, 1) LEVEL: "x-loca" "L" @ (3, 1) LEVEL: "x-goal" "none" @ (-1, 0) # # Sokoban # DUNGEON: "Sokoban" "none" (4, 0) DESCRIPTION: mazelike ALIGNMENT: neutral ENTRY: -1 RNDLEVEL: "soko1" "none" @ (1, 0) 2 RNDLEVEL: "soko2" "none" @ (2, 0) 2 RNDLEVEL: "soko3" "none" @ (3, 0) 2 RNDLEVEL: "soko4" "none" @ (4, 0) 2 # # The Central Vault of Croesus. # DUNGEON: "Fort Ludios" "K" (1, 0) DESCRIPTION: mazelike ALIGNMENT: unaligned LEVEL: "knox" "K" @ (-1, 0) # # Vlad's Tower # # It has been removed from Gehennom, and it is surrounded by stone. # Must not allow bones files for its top level. # DUNGEON: "Vlad's Tower" "T" (3, 0) PROTOFILE: "tower" DESCRIPTION: mazelike ALIGNMENT: chaotic ENTRY: -1 LEVEL: "tower1" "none" @ (1, 0) # # The Endgame levels # # Enter on 2nd level from bottom; 1st (from bottom) is a # placeholder for surface level, and should be unreachable. # [Note: the name "dummy" is checked for in init_dungeons().] # DUNGEON: "The Elemental Planes" "E" (6, 0) DESCRIPTION: mazelike ALIGNMENT: unaligned ENTRY: -2 LEVEL: "astral" "none" @ (1, 0) LEVEL: "water" "none" @ (2, 0) LEVEL: "fire" "none" @ (3, 0) LEVEL: "air" "none" @ (4, 0) LEVEL: "earth" "none" @ (5, 0) LEVEL: "dummy" "none" @ (6, 0) nethack-3.4.3/dat/endgame.des0100644000000000000000000006065107764735041014527 0ustar rootroot# SCCS Id: @(#)endgame.des 3.4 2002/01/19 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1992,1993 by Izchak Miller, David Cohrs, # and Timo Hakulinen # NetHack may be freely redistributed. See license for details. # # These are the ENDGAME levels: earth, air, fire, water, and astral. # The top-most level, the Astral Level, has 3 temples and shrines. # Players are supposed to sacrifice the Amulet of Yendor on the appropriate # shrine. MAZE:"earth",' ' FLAGS: noteleport,hardfloor,shortsighted MESSAGE: "Well done, mortal!" MESSAGE: "But now thou must face the final Test..." MESSAGE: "Prove thyself worthy or perish!" GEOMETRY:center,center # The player lands, upon arrival, in the # lower-right cavern. The location of the # portal to the next level is randomly chosen. # This map has no visible outer boundary, and # is mostly diggable "rock". MAP ... .... .. ..... ... .. .... .... ... .... ... .... ... . .. .. ....... . .. .. ... . . .. . ... .. .. . .. . .. ... . ... ... .. ... .. .... .. .. ... .. ..... ... ... .... .. ENDMAP # Since there are no stairs, this forces the hero's initial placement TELEPORT_REGION:(69,16,69,16),(0,0,0,0) PORTAL:(0,0,75,19),(65,13,75,19),"air" # Some helpful monsters. Making sure a # pick axe and at least one wand of digging # are available. MONSTER:'@',"Elvenking",(67,16) MONSTER:'H',"minotaur",(67,14) # An assortment of earth-appropriate nasties # in each cavern. MONSTER:'E',"earth elemental",(52,13),hostile MONSTER:'E',"earth elemental",(53,13),hostile MONSTER:'T',"rock troll",(53,12) MONSTER:'H',"stone giant",(54,12) # MONSTER:'S',"pit viper",(70,05) MONSTER:'&',"barbed devil",(69,06) MONSTER:'H',"stone giant",(69,08) MONSTER:''',"stone golem",(71,08) MONSTER:'&',"pit fiend",(70,09) MONSTER:'E',"earth elemental",(70,08),hostile # MONSTER:'E',"earth elemental",(60,03),hostile MONSTER:'H',"stone giant",(61,04) MONSTER:'E',"earth elemental",(62,04),hostile MONSTER:'E',"earth elemental",(61,05),hostile MONSTER:'s',"scorpion",(62,05) MONSTER:'p',"rock piercer",(63,05) # MONSTER:'U',"umber hulk",(40,05) MONSTER:'v',"dust vortex",(42,05) MONSTER:'T',"rock troll",(38,06) MONSTER:'E',"earth elemental",(39,06),hostile MONSTER:'E',"earth elemental",(41,06),hostile MONSTER:'E',"earth elemental",(38,07),hostile MONSTER:'H',"stone giant",(39,07) MONSTER:'E',"earth elemental",(43,07),hostile MONSTER:''',"stone golem",(37,08) MONSTER:'S',"pit viper",(43,08) MONSTER:'S',"pit viper",(43,09) MONSTER:'T',"rock troll",(44,10) # MONSTER:'E',"earth elemental",(02,01),hostile MONSTER:'E',"earth elemental",(03,01),hostile MONSTER:''',"stone golem",(01,02) MONSTER:'E',"earth elemental",(02,02),hostile MONSTER:'T',"rock troll",(04,03) MONSTER:'T',"rock troll",(03,03) MONSTER:'&',"pit fiend",(03,04) MONSTER:'E',"earth elemental",(04,05),hostile MONSTER:'S',"pit viper",(05,06) # MONSTER:'E',"earth elemental",(21,02),hostile MONSTER:'E',"earth elemental",(21,03),hostile MONSTER:'H',"minotaur",(21,04) MONSTER:'E',"earth elemental",(21,05),hostile MONSTER:'T',"rock troll",(22,05) MONSTER:'E',"earth elemental",(22,06),hostile MONSTER:'E',"earth elemental",(23,06),hostile # MONSTER:'S',"pit viper",(14,08) MONSTER:'&',"barbed devil",(14,09) MONSTER:'E',"earth elemental",(13,10),hostile MONSTER:'T',"rock troll",(12,11) MONSTER:'E',"earth elemental",(14,12),hostile MONSTER:'E',"earth elemental",(15,13),hostile MONSTER:'H',"stone giant",(17,13) MONSTER:''',"stone golem",(18,13) MONSTER:'&',"pit fiend",(18,12) MONSTER:'E',"earth elemental",(18,11),hostile MONSTER:'E',"earth elemental",(18,10),hostile # MONSTER:'&',"barbed devil",(02,16) MONSTER:'E',"earth elemental",(03,16),hostile MONSTER:'T',"rock troll",(02,17) MONSTER:'E',"earth elemental",(04,17),hostile MONSTER:'E',"earth elemental",(04,18),hostile OBJECT:'`',"boulder",random MAZE:"air",' ' FLAGS: noteleport,hardfloor,shortsighted # The following messages are somewhat obtuse, to make then # equally meaningful if the player can see or not. MESSAGE: "What a strange feeling!" MESSAGE: "You notice that there is no gravity here." GEOMETRY:center,center # The player lands, upon arrival, in the # lower-left area. The location of the # portal to the next level is randomly chosen. # This map has no visible outer boundary, and # is all "air". MAP AAAAAAAAAAAAAAAAAAAAAAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAACCCCCCAAAAAAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAACCAACCCCCAAAAAACCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAACCACCCCCCCAAAAACCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAACCCCCCCCCCAAAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAACCCCAAACCAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAACCCCAAAAAACCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAACCCCCCCAAAACCACCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAACCCCAAAAAAACCACAACCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCAACCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAACCCCAAACCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACACACCCCCAAACCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAACAACCCCCCCAAAACCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACACCCCCCCCAAACCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCCCCCCCCAACCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAACACCCCCCCCCCACCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAACAACCCCCCCCCCCCCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAACCCCCCAAACCCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAACCAAAAAACCCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACCCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA ENDMAP # Use up and down regions to partition the level into three parts; # teleportation can't cross from one part into another. # The up region is where you'll arrive after activating the portal from # the preceding level; the exit portal is placed inside the down region. TELEPORT_REGION:levregion(01,00,24,20),levregion(25,00,79,20),up TELEPORT_REGION:levregion(56,00,79,20),levregion(01,00,55,20),down PORTAL:levregion(57,01,78,19),(0,0,0,0),"fire" REGION:(00,00,75,19),lit,"ordinary" MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'E',"air elemental",random,hostile MONSTER:'e',"floating eye",random,hostile MONSTER:'e',"floating eye",random,hostile MONSTER:'e',"floating eye",random,hostile MONSTER:'y',"yellow light",random,hostile MONSTER:'y',"yellow light",random,hostile MONSTER:'y',"yellow light",random,hostile MONSTER:'A',"couatl",random MONSTER:'D',random,random MONSTER:'D',random,random MONSTER:'D',random,random MONSTER:'D',random,random MONSTER:'D',random,random MONSTER:'E',random,random MONSTER:'E',random,random MONSTER:'E',random,random MONSTER:'J',random,random MONSTER:'J',random,random MONSTER:'&',"djinni",random,hostile MONSTER:'&',"djinni",random,hostile MONSTER:'&',"djinni",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"fog cloud",random,hostile MONSTER:'v',"energy vortex",random,hostile MONSTER:'v',"energy vortex",random,hostile MONSTER:'v',"energy vortex",random,hostile MONSTER:'v',"energy vortex",random,hostile MONSTER:'v',"energy vortex",random,hostile MONSTER:'v',"steam vortex",random,hostile MONSTER:'v',"steam vortex",random,hostile MONSTER:'v',"steam vortex",random,hostile MONSTER:'v',"steam vortex",random,hostile MONSTER:'v',"steam vortex",random,hostile MAZE:"fire",' ' FLAGS: noteleport,hardfloor,shortsighted GEOMETRY:center,center # The player lands, upon arrival, in the # lower-right. The location of the # portal to the next level is randomly chosen. # This map has no visible outer boundary, and # is mostly open area, with lava lakes and bunches of fire traps. MAP ............................................................................ ....LLLLLLLL............L.......................LLL......................... ...LL...................L......................LLLL................LL....... ...L.............LLLL...LL....LL...............LLLLL.............LLL........ .LLLL..............LL....L.....LLL..............LLLL..............LLLL...... ..........LLLL...LLLL...LLL....LLL......L........LLLL....LL........LLL...... ........LLLLLLL...LL.....L......L......LL.........LL......LL........LL...L.. ........LL..LLL..LL......LL......LLLL..L.........LL......LLL............LL.. ....L..LL....LLLLL.................LLLLLLL.......L......LL............LLLLLL ....L..L.....LL.LLLL.......L............L........LLLLL.LL......LL.........LL ....LL........L...LL......LL.............LLL.....L...LLL.......LLL.........L .....LLLLLL........L.......LLL.............L....LL...L.LLL......LLLLLLL..... ..........LLLL............LL.L.............L....L...LL.........LLL..LLL..... ...........................LLLLL...........LL...L...L........LLLL..LLLLLL... .....LLLL.............LL....LL.......LLL...LL.......L..LLL....LLLLLLL....... .......LLL.........LLLLLLLLLLL......LLLLL...L...........LL...LL...LL........ .........LL.......LL.........LL.......LLL....L..LLL....LL.........LL........ ..........LLLLLLLLL...........LL....LLL.......LLLLL.....LL........LL........ .................L.............LLLLLL............LL...LLLL.........LL....... .................................LL....................LL................... ENDMAP TELEPORT_REGION:(69,16,69,16),(0,0,0,0) PORTAL:(0,0,75,19),(65,13,75,19),"water" TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random TRAP:"fire",random # An assortment of fire-appropriate nasties MONSTER:'D',"red dragon",random MONSTER:'&',"balrog",random MONSTER:'E',"fire elemental",random,hostile MONSTER:'E',"fire elemental",random,hostile MONSTER:'v',"fire vortex",random MONSTER:'d',"hell hound",random # MONSTER:'H',"fire giant",random MONSTER:'&',"barbed devil",random MONSTER:'d',"hell hound",random MONSTER:''',"stone golem",random MONSTER:'&',"pit fiend",random MONSTER:'E',"fire elemental",random,hostile # MONSTER:'E',"fire elemental",random,hostile MONSTER:'d',"hell hound",random MONSTER:'E',"fire elemental",random,hostile MONSTER:'E',"fire elemental",random,hostile MONSTER:'s',"scorpion",random MONSTER:'H',"fire giant",random # MONSTER:'d',"hell hound",random MONSTER:'v',"dust vortex",random MONSTER:'v',"fire vortex",random MONSTER:'E',"fire elemental",random,hostile MONSTER:'E',"fire elemental",random,hostile MONSTER:'E',"fire elemental",random,hostile MONSTER:'d',"hell hound",random MONSTER:'E',"fire elemental",random,hostile MONSTER:''',"stone golem",random MONSTER:'S',"pit viper",random MONSTER:'S',"pit viper",random MONSTER:'v',"fire vortex",random # MONSTER:'E',"fire elemental",random,hostile MONSTER:'E',"fire elemental",random,hostile MONSTER:'H',"fire giant",random MONSTER:'E',"fire elemental",random,hostile MONSTER:'v',"fire vortex",random MONSTER:'v',"fire vortex",random MONSTER:'&',"pit fiend",random MONSTER:'E',"fire elemental",random,hostile MONSTER:'S',"pit viper",random # MONSTER:':',"salamander",random,hostile MONSTER:':',"salamander",random,hostile MONSTER:'H',"minotaur",random MONSTER:':',"salamander",random,hostile MONSTER:'v',"steam vortex",random MONSTER:':',"salamander",random,hostile MONSTER:':',"salamander",random,hostile # MONSTER:'H',"fire giant",random MONSTER:'&',"barbed devil",random MONSTER:'E',"fire elemental",random,hostile MONSTER:'v',"fire vortex",random MONSTER:'E',"fire elemental",random,hostile MONSTER:'E',"fire elemental",random,hostile MONSTER:'d',"hell hound",random MONSTER:'H',"fire giant",random MONSTER:'&',"pit fiend",random MONSTER:'E',"fire elemental",random,hostile MONSTER:'E',"fire elemental",random,hostile # MONSTER:'&',"barbed devil",random MONSTER:':',"salamander",random,hostile MONSTER:'v',"steam vortex",random MONSTER:':',"salamander",random,hostile MONSTER:':',"salamander",random,hostile OBJECT:'`',"boulder",random OBJECT:'`',"boulder",random OBJECT:'`',"boulder",random OBJECT:'`',"boulder",random OBJECT:'`',"boulder",random MAZE:"water",' ' FLAGS: noteleport,hardfloor,shortsighted MESSAGE: "You find yourself suspended in an air bubble surrounded by water." GEOMETRY:center,center # The player lands upon arrival to an air bubble # within the leftmost third of the level. The # portal to the next level is randomly located in an air # bubble within the rightmost third of the level. # Bubbles are generated by special code in mkmaze.c for now. MAP WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW WWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWWW ENDMAP TELEPORT_REGION:(0,0,25,19),(0,0,0,0) PORTAL:(51,0,75,19),(0,0,0,0),"astral" # A fisherman's dream... MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"giant eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"electric eel",random MONSTER:';',"kraken",random MONSTER:';',"kraken",random MONSTER:';',"kraken",random MONSTER:';',"kraken",random MONSTER:';',"kraken",random MONSTER:';',"kraken",random MONSTER:';',"kraken",random MONSTER:';',"kraken",random MONSTER:';',"kraken",random MONSTER:';',"shark",random MONSTER:';',"shark",random MONSTER:';',"shark",random MONSTER:';',"shark",random MONSTER:';',"piranha",random MONSTER:';',"piranha",random MONSTER:';',"piranha",random MONSTER:';',"piranha",random MONSTER:';',"jellyfish",random MONSTER:';',"jellyfish",random MONSTER:';',"jellyfish",random MONSTER:';',"jellyfish",random MONSTER:';',random,random MONSTER:';',random,random MONSTER:';',random,random MONSTER:';',random,random # These guys feel like home here MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MONSTER:'E',"water elemental",random,hostile MAZE:"astral",' ' FLAGS: noteleport,hardfloor,nommap,shortsighted MESSAGE: "You arrive on the Astral Plane!" MESSAGE: "Here the High Temples of the aligned gods are located." MESSAGE: "You sense alarm, hostility, and excitement in the air!" GEOMETRY:center,center MAP --------------- |.............| |..---------..| |..|.......|..| --------------- |..|.......|..| --------------- |.............| |..|.......|..| |.............| |..---------..-| |-------| |..|.......|..| |-------| |-..---------..| |..|.......|...-| |-.......-| |..|.......|..| |-.......-| |-...|.......|..| |..|.......|....-|-.........-||..----+----..||-.........-|-....|.......|..| |..|.......+.....+...........||.............||...........+.....+.......|..| |..|.......|....-|-.........-|--|.........|--|-.........-|-....|.......|..| |..|.......|...-| |-.......-| -|---+---|- |-.......-| |-...|.......|..| |..---------..-| |---+---| |-.......-| |---+---| |-..---------..| |.............| |...|-----|-.........-|-----|...| |.............| --------------- |.........|...........|.........| --------------- -------...|-.........-|...------- |....|-.......-|....| ---...|---+---|...--- |...............| ----------------- ENDMAP # Rider locations RANDOM_PLACES:(23,9),(37,14),(51,9) # Where the player will land on arrival TELEPORT_REGION:(29,15,45,15),(30,15,44,15) # Lit courts REGION:(01,05,16,14),lit,"ordinary",filled,true REGION:(31,01,44,10),lit,"ordinary",filled,true REGION:(61,05,74,14),lit,"ordinary",filled,true # A Sanctum for each alignment # The shrines' alignments are shuffled for # each game REGION:(04,07,10,11),lit,"temple" REGION:(34,03,40,07),lit,"temple" REGION:(64,07,70,11),lit,"temple" ALTAR:(07,09),align[0],sanctum ALTAR:(37,05),align[1],sanctum ALTAR:(67,09),align[2],sanctum # Doors DOOR:closed,(11,09) DOOR:closed,(17,09) DOOR:locked,(23,12) DOOR:locked,(37,08) DOOR:closed,(37,11) DOOR:closed,(37,17) DOOR:locked,(51,12) DOOR:locked,(57,09) DOOR:closed,(63,09) # Non diggable and phazeable everywhere NON_DIGGABLE:(00,00,74,19) NON_PASSWALL:(00,00,74,19) # Moloch's horde # West round room MONSTER:'@',"aligned priest",(18,09),noalign,hostile MONSTER:'@',"aligned priest",(19,08),noalign,hostile MONSTER:'@',"aligned priest",(19,09),noalign,hostile MONSTER:'@',"aligned priest",(19,10),noalign,hostile MONSTER:'A',"Angel",(20,09),noalign,hostile MONSTER:'A',"Angel",(20,10),noalign,hostile MONSTER:'&',"Pestilence",place[0],hostile # South-central round room MONSTER:'@',"aligned priest",(36,12),noalign,hostile MONSTER:'@',"aligned priest",(37,12),noalign,hostile MONSTER:'@',"aligned priest",(38,12),noalign,hostile MONSTER:'@',"aligned priest",(36,13),noalign,hostile MONSTER:'A',"Angel",(38,13),noalign,hostile MONSTER:'A',"Angel",(37,13),noalign,hostile MONSTER:'&',"Death",place[1],hostile # East round room MONSTER:'@',"aligned priest",(56,09),noalign,hostile MONSTER:'@',"aligned priest",(55,08),noalign,hostile MONSTER:'@',"aligned priest",(55,09),noalign,hostile MONSTER:'@',"aligned priest",(55,10),noalign,hostile MONSTER:'A',"Angel",(54,09),noalign,hostile MONSTER:'A',"Angel",(54,10),noalign,hostile MONSTER:'&',"Famine",place[2],hostile # # The aligned horde # # We do not know in advance the alignment of the # player. The mpeaceful bit will need resetting # when the level is created. The setting here is # but a place holder. # # West court MONSTER:'@',"aligned priest",(12,07),chaos,hostile MONSTER:'@',"aligned priest",(13,07),chaos,peaceful MONSTER:'@',"aligned priest",(14,07),law,hostile MONSTER:'@',"aligned priest",(12,11),law,peaceful MONSTER:'@',"aligned priest",(13,11),neutral,hostile MONSTER:'@',"aligned priest",(14,11),neutral,peaceful MONSTER:'A',"Angel",(11,05),chaos,hostile MONSTER:'A',"Angel",(12,05),chaos,peaceful MONSTER:'A',"Angel",(13,05),law,hostile MONSTER:'A',"Angel",(11,13),law,peaceful MONSTER:'A',"Angel",(12,13),neutral,hostile MONSTER:'A',"Angel",(13,13),neutral,peaceful # Central court MONSTER:'@',"aligned priest",(32,09),chaos,hostile MONSTER:'@',"aligned priest",(33,09),chaos,peaceful MONSTER:'@',"aligned priest",(34,09),law,hostile MONSTER:'@',"aligned priest",(40,09),law,peaceful MONSTER:'@',"aligned priest",(41,09),neutral,hostile MONSTER:'@',"aligned priest",(42,09),neutral,peaceful MONSTER:'A',"Angel",(31,08),chaos,hostile MONSTER:'A',"Angel",(32,08),chaos,peaceful MONSTER:'A',"Angel",(31,09),law,hostile MONSTER:'A',"Angel",(42,08),law,peaceful MONSTER:'A',"Angel",(43,08),neutral,hostile MONSTER:'A',"Angel",(43,09),neutral,peaceful # East court MONSTER:'@',"aligned priest",(60,07),chaos,hostile MONSTER:'@',"aligned priest",(61,07),chaos,peaceful MONSTER:'@',"aligned priest",(62,07),law,hostile MONSTER:'@',"aligned priest",(60,11),law,peaceful MONSTER:'@',"aligned priest",(61,11),neutral,hostile MONSTER:'@',"aligned priest",(62,11),neutral,peaceful MONSTER:'A',"Angel",(61,05),chaos,hostile MONSTER:'A',"Angel",(62,05),chaos,peaceful MONSTER:'A',"Angel",(63,05),law,hostile MONSTER:'A',"Angel",(61,13),law,peaceful MONSTER:'A',"Angel",(62,13),neutral,hostile MONSTER:'A',"Angel",(63,13),neutral,peaceful # # Assorted nasties MONSTER:'L',random,random,hostile MONSTER:'L',random,random,hostile MONSTER:'L',random,random,hostile MONSTER:'V',random,random,hostile MONSTER:'V',random,random,hostile MONSTER:'V',random,random,hostile MONSTER:'D',random,random,hostile MONSTER:'D',random,random,hostile MONSTER:'D',random,random,hostile nethack-3.4.3/dat/gehennom.des0100644000000000000000000004777707764735041014745 0ustar rootroot# SCCS Id: @(#)gehennom.des 3.4 1996/11/09 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1992 by M. Stephenson and Izchak Miller # NetHack may be freely redistributed. See license for details. # MAZE: "valley", ' ' FLAGS: noteleport,hardfloor,nommap GEOMETRY:center,center MAP ---------------------------------------------------------------------------- |...S.|..|.....| |.....-| |................| |...............| |...| |---|.|.--.---.| |......--- ----..........-----.-----....---........---.-.| | |.|.|..| |.| --........| |.............| |.......---| |-...........--| | |...S..| |.| |.......-----.......------| |--------..---......------- | |----------- |.| |-......| |....|...-- |...-----................---- | |.....S....---.| |.......| |....|...| |..............----------- | |.....|.|......| |.....--- |......--- |....---.......| | |.....|.|------| |....-- --....-- |-------- ----....--------------- | |.....|--......---BBB-| |...-- |.......| |..................| | |..........||........-| --...| |.......| |...||.............| | |.....|...-||-........------....| |.......---- |...||.............-- | |.....|--......---...........--------..........| |.......---------...-- | |.....| |------| |--.......--| |..B......----- -----....| |.| |....--- | |.....| |......--| ------..| |----..B......| |.--------.-- |-.....---| |------ |........| |.|....| |.....----BBBB---------...........---.........| | |........| |...|..| |.....| |-.............--------...........---| | --.....-----------.| |....-----.....---------- |.........---- | | |..|..B...........| |.|..........|.| |.|........| | ---------------------------------------------------------------------------- ENDMAP # Dungeon Description # The shrine to Moloch. REGION:(01,06,05,14),lit,"temple" # The Morgues REGION:(19,01,24,08),unlit,"morgue",filled,true REGION:(09,14,16,18),unlit,"morgue",filled,true REGION:(37,09,43,14),unlit,"morgue",filled,true # Stairs STAIR:(01,01),down # Branch location BRANCH:(66,17,66,17),(0,0,0,0) TELEPORT_REGION:(58,09,72,18),(0,0,0,0),down # Secret Doors DOOR:locked,(04,01) DOOR:locked,(08,04) DOOR:locked,(06,06) # The altar of Moloch. ALTAR:(03,10),noalign,shrine # Non diggable walls - everywhere! NON_DIGGABLE:(00,00,75,19) # Objects # **LOTS** of dead bodies (all human). # note: no priest(esse)s or monks - maybe Moloch has a *special* # fate reserved for members of *those* classes. # OBJECT:'%',"corpse",random,"archeologist",0 OBJECT:'%',"corpse",random,"archeologist",0 OBJECT:'%',"corpse",random,"barbarian",0 OBJECT:'%',"corpse",random,"barbarian",0 OBJECT:'%',"corpse",random,"caveman",0 OBJECT:'%',"corpse",random,"cavewoman",0 OBJECT:'%',"corpse",random,"healer",0 OBJECT:'%',"corpse",random,"healer",0 OBJECT:'%',"corpse",random,"knight",0 OBJECT:'%',"corpse",random,"knight",0 OBJECT:'%',"corpse",random,"ranger",0 OBJECT:'%',"corpse",random,"ranger",0 OBJECT:'%',"corpse",random,"rogue",0 OBJECT:'%',"corpse",random,"rogue",0 OBJECT:'%',"corpse",random,"samurai",0 OBJECT:'%',"corpse",random,"samurai",0 OBJECT:'%',"corpse",random,"tourist",0 OBJECT:'%',"corpse",random,"tourist",0 OBJECT:'%',"corpse",random,"valkyrie",0 OBJECT:'%',"corpse",random,"valkyrie",0 OBJECT:'%',"corpse",random,"wizard",0 OBJECT:'%',"corpse",random,"wizard",0 # # Some random weapons and armor. # OBJECT:'[',random,random OBJECT:'[',random,random OBJECT:'[',random,random OBJECT:'[',random,random OBJECT:')',random,random OBJECT:')',random,random OBJECT:')',random,random OBJECT:')',random,random # # Some random loot. # OBJECT:'*',"ruby",random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'/',random,random OBJECT:'/',random,random OBJECT:'=',random,random OBJECT:'=',random,random OBJECT:'+',random,random OBJECT:'+',random,random OBJECT:'(',random,random OBJECT:'(',random,random OBJECT:'(',random,random # (Not so) Random traps. TRAP:"spiked pit", (05,02) TRAP:"spiked pit", (14,05) TRAP:"sleep gas", (03,01) TRAP:"board", (21,12) TRAP:"board", random TRAP:"dart", (60,01) TRAP:"dart", (26,17) TRAP:"anti magic", random TRAP:"anti magic", random TRAP:"magic", random TRAP:"magic", random # Random monsters. # The ghosts. MONSTER:' ',"ghost",random MONSTER:' ',"ghost",random MONSTER:' ',"ghost",random MONSTER:' ',"ghost",random MONSTER:' ',"ghost",random MONSTER:' ',"ghost",random # Add a few bats for atmosphere. MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random MONSTER:'B',"vampire bat",random # And a lich for good measure. MONSTER:'L',random,random # Some undead nasties for good measure MONSTER:'V',random,random MONSTER:'V',random,random MONSTER:'V',random,random MONSTER:'Z',random,random MONSTER:'Z',random,random MONSTER:'Z',random,random MONSTER:'Z',random,random MONSTER:'M',random,random MONSTER:'M',random,random MONSTER:'M',random,random MONSTER:'M',random,random # # The Juiblex level # MAZE:"juiblex",' ' FLAGS:noteleport,shortsighted INIT_MAP:'.','}',true,true,unlit,false # guarantee at least one open spot to ensure successful stair placement GEOMETRY:left,bottom MAP }}}}}}}} }}...}}} }}}...}} }}}}.}}} }}}}}}}} ENDMAP OBJECT:'`',"boulder",random GEOMETRY:right,top MAP }}}}}}}} }}}}.}}} }}}...}} }}...}}} }}}}}}}} ENDMAP OBJECT:'`',"boulder",random # lair GEOMETRY:center,center MAP ..}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.. .}}}.}}}}}..}}}..}}}}}..}}}..}}}}}..}}}..}}}}}.}}}. }}}...}}..}}.}.}}.}}.}}}...}}}.}}}..}}}..}}}}...}}} .}}}.}}.}}}.}}.}}.}}...}}.}}.....}}.....}....}.}}}. ..}}}..}}}.}}.}}.}}..}}.....}}.}}}.}}.}}}}}}}}}}}.. .}}}..}}}}}.}}.}}.}}...}}}}}.....}}.}}}}}}.....}}}. }}}..}}...}}..}}.}}}.}}}...}}}.}}}.}.}}}}..P.P..}}} }}.}}}}...}}}}}.}...}}}..P..}}}.}.}}}.}}}}.....}}}} }.}}}}.}}.}..}.}}}}}}}..P.P..}}}.}}}.}}..}}...}}}}. .}}}}.}}}}....}}}}}.}}}..P..}}}.}}}}.}}..}}...}}}.} }}}}..}}.}}..}}}}...}}}}...}}}.}}}}}.}}}}.}}}}}}.}} }}}...}}...}}}..}}}}}}}}}}}}.....}}}}.}}...}..}.}}} .}}}..}}.}}}}....}}..}}}..}}.....}}}}.}}}.}....}}}. ..}}}.}}}}..}}..}}..}}..}}..}}.}}}..}.}..}}}..}}}.. .}}}.}}}}....}}}}..}}....}}}}}}}...}}}....}}}}.}}}. }}}...}}}....}}}..}}}....}}}..}}...}}}....}}}...}}} .}}}.}}}}}..}}}..}}}}}..}}}..}}}}}..}}}..}}}}}.}}}. ..}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.}}}}}.. ENDMAP # Random registers RANDOM_MONSTERS:'j','b','P','F' RANDOM_PLACES:(04,02),(46,02),(04,15),(46,15) # Dungeon description REGION:(00,00,50,17),unlit,"swamp" MAZEWALK:(00,09),west MAZEWALK:(50,08),east STAIR:levregion(01,00,11,20),(0,0,50,17),down STAIR:levregion(69,00,79,20),(0,0,50,17),up BRANCH:levregion(01,00,11,20),(0,0,50,17) TELEPORT_REGION:levregion(01,00,11,20),(0,0,50,17),up TELEPORT_REGION:levregion(69,00,79,20),(0,0,50,17),down FOUNTAIN:place[0] MONSTER:'m',"giant mimic",place[1],m_feature "fountain" MONSTER:'m',"giant mimic",place[2],m_feature "fountain" MONSTER:'m',"giant mimic",place[3],m_feature "fountain" # The demon of the swamp MONSTER:'&',"Juiblex",(25,08) # And a couple demons MONSTER:'i',"lemure",(43,08) MONSTER:'i',"lemure",(44,08) MONSTER:'i',"lemure",(45,08) # Some liquids and gems OBJECT:'*',random,(43,06) OBJECT:'*',random,(45,06) OBJECT:'!',random,(43,09) OBJECT:'!',random,(44,09) OBJECT:'!',random,(45,09) # And lots of blobby monsters MONSTER:monster[0],random,(25,06) MONSTER:monster[1],random,(24,07) MONSTER:monster[2],random,(26,07) MONSTER:monster[3],random,(23,08) MONSTER:monster[3],random,(27,08) MONSTER:monster[2],random,(24,09) MONSTER:monster[1],random,(26,09) MONSTER:monster[0],random,(25,10) MONSTER:'j',random,random MONSTER:'j',random,random MONSTER:'j',random,random MONSTER:'j',random,random MONSTER:'P',random,random MONSTER:'P',random,random MONSTER:'P',random,random MONSTER:'P',random,random MONSTER:'b',random,random MONSTER:'b',random,random MONSTER:'b',random,random MONSTER:'F',random,random MONSTER:'F',random,random MONSTER:'F',random,random MONSTER:'m',random,random MONSTER:'m',random,random MONSTER:';',"jellyfish",random MONSTER:';',"jellyfish",random # Some random objects OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'`',"boulder",random # Some traps TRAP:"sleep gas",random TRAP:"sleep gas",random TRAP:"anti magic",random TRAP:"anti magic",random TRAP:"magic",random TRAP:"magic",random # # The Orcus Level # MAZE:"orcus",random FLAGS: noteleport,shortsighted GEOMETRY:right,center # A ghost town MAP .|....|....|....|..............|....|........ .|....|....|....|..............|....|........ .|....|....|....|--...-+-------|............. .|....|....|....|..............+............. .|.........|....|..............|....|........ .--+-...-+----+--....-------...--------.-+--- .....................|.....|................. .....................|.....|................. .--+----....-+---....|.....|...----------+--- .|....|....|....|....---+---...|......|...... .|.........|....|..............|......|...... .----...---------.....-----....+......|...... .|........................|....|......|...... .----------+-...--+--|....|....----------+--- .|....|..............|....+....|............. .|....+.......|......|....|....|............. .|....|.......|......|....|....|............. ENDMAP MAZEWALK:(00,06),west # Entire main area REGION:(01,00,44,16),unlit,"ordinary" STAIR:(33,15),down STAIR:levregion(01,00,12,20),levregion(20,01,70,20),up BRANCH:levregion(01,00,12,20),levregion(20,01,70,20) TELEPORT_REGION:levregion(01,00,12,20),levregion(20,01,70,20) # Wall "ruins" OBJECT:'`',"boulder",(19,02) OBJECT:'`',"boulder",(20,02) OBJECT:'`',"boulder",(21,02) OBJECT:'`',"boulder",(36,02) OBJECT:'`',"boulder",(36,03) OBJECT:'`',"boulder",(06,04) OBJECT:'`',"boulder",(05,05) OBJECT:'`',"boulder",(06,05) OBJECT:'`',"boulder",(07,05) OBJECT:'`',"boulder",(39,05) OBJECT:'`',"boulder",(08,08) OBJECT:'`',"boulder",(09,08) OBJECT:'`',"boulder",(10,08) OBJECT:'`',"boulder",(11,08) OBJECT:'`',"boulder",(06,10) OBJECT:'`',"boulder",(05,11) OBJECT:'`',"boulder",(06,11) OBJECT:'`',"boulder",(07,11) OBJECT:'`',"boulder",(21,11) OBJECT:'`',"boulder",(21,12) OBJECT:'`',"boulder",(13,13) OBJECT:'`',"boulder",(14,13) OBJECT:'`',"boulder",(15,13) OBJECT:'`',"boulder",(14,14) # Doors DOOR:closed,(23,02) DOOR:open,(31,03) DOOR:nodoor,(03,05) DOOR:closed,(09,05) DOOR:closed,(14,05) DOOR:closed,(41,05) DOOR:open,(03,08) DOOR:nodoor,(13,08) DOOR:open,(41,08) DOOR:closed,(24,09) DOOR:closed,(31,11) DOOR:open,(11,13) DOOR:closed,(18,13) DOOR:closed,(41,13) DOOR:open,(26,14) DOOR:closed,(06,15) # Special rooms ALTAR:(24,07),noalign,sanctum REGION:(22,12,25,16),unlit,"morgue" REGION:(32,09,37,12),lit,"shop" REGION:(12,00,15,04),lit,"shop" # Some traps. TRAP:"spiked pit", random TRAP:"sleep gas", random TRAP:"anti magic", random TRAP:"fire", random TRAP:"fire", random TRAP:"fire", random TRAP:"magic", random TRAP:"magic", random # Some random objects OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # The resident nasty MONSTER:'&',"Orcus",(33,15) # And its preferred companions MONSTER:'Z',"human zombie",(32,15) MONSTER:' ',"shade",(32,14) MONSTER:' ',"shade",(32,16) MONSTER:'V',"vampire",(35,16) MONSTER:'V',"vampire",(35,14) MONSTER:'V',"vampire lord",(36,14) MONSTER:'V',"vampire lord",(36,15) # Randomly placed companions MONSTER:'Z',"skeleton",random MONSTER:'Z',"skeleton",random MONSTER:'Z',"skeleton",random MONSTER:'Z',"skeleton",random MONSTER:'Z',"skeleton",random MONSTER:' ',"shade",random MONSTER:' ',"shade",random MONSTER:' ',"shade",random MONSTER:' ',"shade",random MONSTER:'Z',"giant zombie",random MONSTER:'Z',"giant zombie",random MONSTER:'Z',"giant zombie",random MONSTER:'Z',"ettin zombie",random MONSTER:'Z',"ettin zombie",random MONSTER:'Z',"ettin zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'Z',"human zombie",random MONSTER:'V',"vampire",random MONSTER:'V',"vampire",random MONSTER:'V',"vampire",random MONSTER:'V',"vampire lord",random MONSTER:'V',"vampire lord",random # A few more for the party MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random # # The Asmodeus Level # MAZE:"asmodeus",random FLAGS: noteleport # First part GEOMETRY:half-left,center MAP --------------------- |.............|.....| |.............S.....| |---+------------...| |.....|.........|-+-- |..---|.........|.... |..|..S.........|.... |..|..|.........|.... |..|..|.........|-+-- |..|..-----------...| |..S..........|.....| --------------------- ENDMAP STAIR:levregion(01,00,6,20),levregion(6,1,70,16),up BRANCH:levregion(01,00,6,20),levregion(6,1,70,16) TELEPORT_REGION:levregion(01,00,6,20),levregion(6,1,70,16) # Doors DOOR:closed,(04,03) DOOR:locked,(18,04) DOOR:closed,(18,08) # STAIR:(13,07),down # Non diggable walls NON_DIGGABLE:(00,00,20,11) # Entire main area REGION:(01,01,20,10),unlit,"ordinary" # The fellow in residence MONSTER:'&',"Asmodeus",(12,07) # Some random weapons and armor. OBJECT:'[',random,random OBJECT:'[',random,random OBJECT:')',random,random OBJECT:')',random,random OBJECT:'*',random,random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random # Some traps. TRAP:"spiked pit", (05,02) TRAP:"fire", (08,06) TRAP:"sleep gas", random TRAP:"anti magic", random TRAP:"fire", random TRAP:"magic", random TRAP:"magic", random # Random monsters. MONSTER:' ',"ghost",(11,07) MONSTER:'&',"horned devil",(10,05) MONSTER:'L',random,random # Some Vampires for good measure MONSTER:'V',random,random MONSTER:'V',random,random MONSTER:'V',random,random # Second part GEOMETRY:half-right,center MAP --------------------------------- ................................| ................................+ ................................| --------------------------------- ENDMAP MAZEWALK:(32,02),east # Non diggable walls NON_DIGGABLE:(00,00,32,04) DOOR:closed,(32,02) MONSTER:'&',random,random MONSTER:'&',random,random MONSTER:'&',random,random TRAP:"anti magic", random TRAP:"fire", random TRAP:"magic", random # # The Baalzebub level # MAZE:"baalz",random FLAGS: noteleport GEOMETRY:right,center MAP ------------------------------------------------- | --- ---- | ---- | ------------ | | ------ | --------|..........|--- | |....| -------|...........-------------- ---....|--|..................S............|---- ....--....S..----------------|............S...| ---....|--|..................|............|---- | |....| -------|...........-----S-------- | ------ | --------|..........|--- | ---- | ------------ | | --- ---- ------------------------------------------------- ENDMAP STAIR:levregion(01,00,15,20),levregion(15,1,70,16),up BRANCH:levregion(01,00,15,20),levregion(15,1,70,16) TELEPORT_REGION:levregion(01,00,15,20),levregion(15,1,70,16) NON_DIGGABLE:(00,00,46,12) MAZEWALK:(00,06),west STAIR:(44,06),down # The fellow in residence MONSTER:'&',"Baalzebub",(35,06) # Some random weapons and armor. OBJECT:'[',random,random OBJECT:'[',random,random OBJECT:')',random,random OBJECT:')',random,random OBJECT:'*',random,random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random # Some traps. TRAP:"spiked pit", random TRAP:"fire", random TRAP:"sleep gas", random TRAP:"anti magic", random TRAP:"fire", random TRAP:"magic", random TRAP:"magic", random # Random monsters. MONSTER:' ',"ghost",(37,07) MONSTER:'&',"horned devil",(32,05) MONSTER:'&',"barbed devil",(38,07) MONSTER:'L',random,random # Some Vampires for good measure MONSTER:'V',random,random MONSTER:'V',random,random MONSTER:'V',random,random # # The Sanctum Level # MAZE:"sanctum", ' ' FLAGS: noteleport,hardfloor,nommap GEOMETRY:center,center MAP ---------------------------------------------------------------------------- | -------------- | | |............| ------- | | -------............----- |.....| | | |......................| --.....| --------- | | ----......................---------|......---- |.......| | | |........---------..........|......+.........| ------+---..| | | ---........|.......|..........--S----|.........| |........|..| | | |..........|.......|.............| |.........-------..---------- | | |..........|.......|..........---- |..........|....|..|......| | | |..........|.......|..........| --.......----+---S---S--..| | | |..........---------..........| |.......|.............|..| | | ---...........................| -----+-------S---------S--- | | |...........................| |...| |......| |....|-- | | ----.....................---- |...---....--- ---......| | | |.....................| |..........| |.....---- | | -------...........----- --...------- |.....| | | |...........| |...| |.....| | | ------------- ----- ------- | ---------------------------------------------------------------------------- ENDMAP REGION:(15,07,21,10),lit,"temple" ALTAR:(18,08),noalign,sanctum REGION:(41,06,48,11),unlit,"morgue",filled,true # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Invisible barrier separating the left & right halves of the level NON_PASSWALL:(37,00,39,19) # Doors DOOR:closed,(40,06) DOOR:locked,(62,06) DOOR:closed,(46,12) DOOR:closed,(53,10) # Surround the temple with fire TRAP:"fire",(13,05) TRAP:"fire",(14,05) TRAP:"fire",(15,05) TRAP:"fire",(16,05) TRAP:"fire",(17,05) TRAP:"fire",(18,05) TRAP:"fire",(19,05) TRAP:"fire",(20,05) TRAP:"fire",(21,05) TRAP:"fire",(22,05) TRAP:"fire",(23,05) TRAP:"fire",(13,12) TRAP:"fire",(14,12) TRAP:"fire",(15,12) TRAP:"fire",(16,12) TRAP:"fire",(17,12) TRAP:"fire",(18,12) TRAP:"fire",(19,12) TRAP:"fire",(20,12) TRAP:"fire",(21,12) TRAP:"fire",(22,12) TRAP:"fire",(23,12) TRAP:"fire",(13,06) TRAP:"fire",(13,07) TRAP:"fire",(13,08) TRAP:"fire",(13,09) TRAP:"fire",(13,10) TRAP:"fire",(13,11) TRAP:"fire",(23,06) TRAP:"fire",(23,07) TRAP:"fire",(23,08) TRAP:"fire",(23,09) TRAP:"fire",(23,10) TRAP:"fire",(23,11) # Some traps. TRAP:"spiked pit", random TRAP:"fire", random TRAP:"sleep gas", random TRAP:"anti magic", random TRAP:"fire", random TRAP:"magic", random # Some random objects OBJECT:'[',random,random OBJECT:'[',random,random OBJECT:'[',random,random OBJECT:'[',random,random OBJECT:')',random,random OBJECT:')',random,random OBJECT:'*',random,random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random # Some monsters. MONSTER:'&',"horned devil",(14,12),hostile MONSTER:'&',"barbed devil",(18,08),hostile MONSTER:'&',"erinys",(10,04),hostile MONSTER:'&',"marilith",(07,09),hostile MONSTER:'&',"nalfeshnee",(27,08),hostile # Moloch's horde MONSTER:'@',"aligned priest",(20,03),noalign,hostile MONSTER:'@',"aligned priest",(15,04),noalign,hostile MONSTER:'@',"aligned priest",(11,05),noalign,hostile MONSTER:'@',"aligned priest",(11,07),noalign,hostile MONSTER:'@',"aligned priest",(11,09),noalign,hostile MONSTER:'@',"aligned priest",(11,12),noalign,hostile MONSTER:'@',"aligned priest",(15,13),noalign,hostile MONSTER:'@',"aligned priest",(17,13),noalign,hostile MONSTER:'@',"aligned priest",(21,13),noalign,hostile # A few nasties MONSTER:'L',random,random MONSTER:'L',random,random MONSTER:'V',random,random MONSTER:'V',random,random MONSTER:'V',random,random STAIR:(63,15),up nethack-3.4.3/dat/help0100644000000000000000000002442307764735041013302 0ustar rootroot Welcome to NetHack! ( description of version 3.4 ) NetHack is a Dungeons and Dragons like game where you (the adventurer) descend into the depths of the dungeon in search of the Amulet of Yendor, reputed to be hidden somewhere below the twentieth level. You begin your adventure with a pet that can help you in many ways, and can be trained to do all sorts of things. On the way you will find useful (or useless) items, quite possibly with magic properties, and assorted monsters. You can attack a monster by trying to move onto the space a monster is on (but often it is much wiser to leave it alone). Unlike most adventure games, which give you a verbal description of your location, NetHack gives you a visual image of the dungeon level you are on. NetHack uses the following symbols: - and | The walls of a room, possibly also open doors or a grave. . The floor of a room or a doorway. # A corridor, or iron bars, or a tree, or possibly a kitchen sink (if your dungeon has sinks), or a drawbridge. > Stairs down: a way to the next level. < Stairs up: a way to the previous level. @ You (usually), or another human. ) A weapon of some sort. [ A suit or piece of armor. % Something edible (not necessarily healthy). / A wand. = A ring. ? A scroll. ! A potion. ( Some other useful object (pick-axe, key, lamp...) $ A pile of gold. * A gem or rock (possibly valuable, possibly worthless). + A closed door, or a spellbook containing a spell you can learn. ^ A trap (once you detect it). " An amulet, or a spider web. 0 An iron ball. _ An altar, or an iron chain. { A fountain. } A pool of water or moat or a pool of lava. \ An opulent throne. ` A boulder or statue. A to Z, a to z, and several others: Monsters. I Invisible or unseen monster's last known location You can find out what a symbol represents by typing '/' and following the directions to move the cursor to the symbol in question. For instance, a 'd' may turn out to be a dog. y k u 7 8 9 Move commands: \|/ \|/ yuhjklbn: go one step in specified direction h-.-l 4-.-6 YUHJKLBN: go in specified direction until you /|\ /|\ hit a wall or run into something b j n 1 2 3 g: run in direction until something numberpad interesting is seen G, same, except a branching corridor isn't < up ^: considered interesting (the ^ in this case means the Control key, not a caret) > down m: move without picking up objects F: fight even if you don't sense a monster If the number_pad option is set, the number keys move instead. Depending on the platform, Shift number (on the numberpad), Meta number, or Alt number will invoke the YUHJKLBN commands. Control may or may not work when number_pad is enabled, depending on the platform's capabilities. Commands: NetHack knows the following commands: ? Help menu. / Tell what a symbol represents. You may choose to specify a location or give a symbol argument. & Tell what a command does. < Go up a staircase (if you are standing on it). > Go down a staircase (if you are standing on it). . Rest, do nothing for one turn. _ Travel via a shortest-path algorithm to a point on the map a Apply (use) a tool (pick-axe, key, lamp...) A Remove all armor. ^A Redo the previous command c Close a door. C Call (name) an individual monster. d Drop something. d7a: drop seven items of object a. D Drop multiple items. This command is implemented in two different ways. One way is: "D" displays a list of all of your items, from which you can pick and choose what to drop. A "+" next to an item means that it will be dropped, a "-" means that it will not be dropped. Toggle an item to be selected/deselected by typing the letter adjacent to its description. Select all items with "+", deselect all items with "=". The moves you from one page of the listing to the next. The other way is: "D" will ask the question "What kinds of things do you want to drop? [!%= au]". You should type zero or more object symbols possibly followed by 'a' and/or 'u'. Da - drop all objects, without asking for confirmation. Du - drop only unpaid objects (when in a shop). D%u - drop only unpaid food. ^D Kick (for doors, usually). e Eat food. E Engrave a message on the floor. E- - write in the dust with your fingers. f Fire ammunition from quiver. F Followed by direction, fight a monster (even if you don't sense it). i Display your inventory. I Display selected parts of your inventory, as in I* - list all gems in inventory. Iu - list all unpaid items. Ix - list all used up items that are on your shopping bill. I$ - count your money. o Open a door. O Review current options and possibly change them. A menu displaying the option settings will be displayed and most can be changed by simply selecting their entry. Options are usually set before the game with a NETHACKOPTIONS environment variable, or via a config file (defaults.nh, NetHack Defaults, nethack.cnf, .nethackrc, etc.), not with the 'O' command. p Pay your shopping bill. P Put on an accessory (ring, amulet, etc). ^P Repeat last message (subsequent ^P's repeat earlier messages). The behavior can be varied via the msg_window option. q Drink (quaff) something (potion, water, etc). Q Select ammunition for quiver. r Read a scroll or spellbook. R Remove an accessory (ring, amulet, etc). ^R Redraw the screen. s Search for secret doors and traps around you. S Save the game. t Throw an object or shoot a projectile. T Take off armor. ^T Teleport, if you are able. v Displays the version number. V Display a longer identification of the version, including the history of the game. w Wield weapon. w- means wield nothing, use bare hands. W Wear armor. x Swap wielded and secondary weapons. X Switch the game to explore (discovery) mode. ^X Show your attributes. z Zap a wand. Z Cast a spell. ^Z Suspend the game. : Look at what is here. ; Look at what is somewhere else. , Pick up some things. @ Toggle the pickup option. ^ Ask for the type of a trap you found earlier. ) Tell what weapon you are wielding. [ Tell what armor you are wearing. = Tell what rings you are wearing. " Tell what amulet you are wearing. ( Tell what tools you are using. * Tell what equipment you are using; combines the preceding five. $ Count your gold pieces. + List the spells you know; also rearrange them if desired. \ Show what types of objects have been discovered. ! Escape to a shell, if supported in your version and OS. # Introduces one of the "extended" commands. To get a list of the commands you can use with "#" type "#?". The extended commands you can use depends upon what options the game was compiled with, along with your class and what type of monster you most closely resemble at a given moment. If your keyboard has a meta key (which, when pressed in combination with another key, modifies it by setting the 'meta' (8th, or 'high') bit), these extended commands can be invoked by meta-ing the first letter of the command. An alt key may have a similar effect. If the "number_pad" option is on, some additional letter commands are available: h displays the help menu, like '?' j Jump to another location. k Kick (for doors, usually). l Loot a box on the floor. n followed by number of times to repeat the next command N Name an object or type of object. u Untrap a trapped object or door. You can put a number before a command to repeat it that many times, as in "40." or "20s.". If you have the number_pad option set, you must type 'n' to prefix the count, as in "n40." or "n20s". Some information is displayed on the bottom line or perhaps in a box, depending on the platform you are using. You see your attributes, your alignment, what dungeon level you are on, how many hit points you have now (and will have when fully recovered), what your armor class is (the lower the better), your experience level, and the state of your stomach. Optionally, you may or may not see other information such as spell points, how much gold you have, etc. Have Fun, and Happy Hacking! nethack-3.4.3/dat/hh0100644000000000000000000001304507764735041012747 0ustar rootrooty k u 7 8 9 Move commands: \|/ \|/ yuhjklbn: go one step in specified direction h-.-l 4-.-6 YUHJKLBN: go in specified direction until you /|\ /|\ hit a wall or run into something b j n 1 2 3 g: run in direction until something numberpad interesting is seen G, same, except a branching corridor isn't < up ^: considered interesting (the ^ in this case means the Control key, not a caret) > down m: move without picking up objects/fighting F: fight even if you don't sense a monster If the number_pad option is set, the number keys move instead. Depending on the platform, Shift number (on the numberpad), Meta number, or Alt number will invoke the YUHJKLBN commands. Control may or may not work when number_pad is enabled, depending on the platform's capabilities. General commands: ? help display one of several informative texts #quit quit end the game without saving current game S save save the game (to be continued later) and exit ! sh escape to some SHELL (if allowed) ^Z suspend suspend the game (independent of your current suspend char) O options set options / whatis tell what a map symbol represents \ known display list of what's been discovered v version display version number V history display game history X explore switch the game to explore (discovery) mode ^A again redo the previous command (^A denotes the keystroke CTRL-A) ^R redraw redraw the screen ^P prevmsg repeat previous message (subsequent ^P's repeat earlier ones) # introduces an extended command (#? for a list of them) Game commands: ^D kick kick (a door, or something else) ^T 'port teleport (if you can) ^X show show your attributes a apply apply or use a tool (pick-axe, key, camera, etc.) A armor take off all armor c close close a door C call name an individual monster (ex. baptize your dog) d drop drop an object. d7a: drop seven items of object 'a' D Drop drop selected types of objects e eat eat something E engrave write a message in the dust on the floor (E- use fingers) f fire fire ammunition from quiver F fight followed by direction, fight a monster i invent list your inventory (all objects you are carrying) I Invent list selected parts of your inventory Iu: list unpaid objects Ix: list unpaid but used up items I$: count your money o open open a door p pay pay your bill (in a shop) P puton put on an accessory (ring, amulet, etc) q quaff drink something (potion, water, etc) Q quiver select ammunition for quiver r read read a scroll or spellbook R remove remove an accessory (ring, amulet, etc) s search search for secret doors, hidden traps and monsters t throw throw or shoot a weapon T takeoff take off some armor w wield wield a weapon (w- wield nothing) W wear put on some armor x xchange swap wielded and secondary weapons z zap zap a wand Z Zap cast a spell < up go up the stairs > down go down the stairs ^ trap_id identify a previously found trap ),[,=,",( ask for current items of specified symbol in use * ask for combination of ),[,=,",( all at once $ gold count your gold + spells list the spells you know; also rearrange them if desired _ travel move via a shortest-path algorithm to a point on the map . rest wait a moment , pickup pick up all you can carry @ toggle "pickup" (auto pickup) option on and off : look look at what is here ; farlook look at what is somewhere else by selecting a map symbol Keyboards that have a meta key can also use these extended commands via the meta modifier instead of the # prefix: M-? Display extended command help (if the platform allows this) M-2 twoweapon toggle two-weapon combat (unless number_pad is enabled) M-a adjust adjust inventory letters M-c chat talk to someone M-d dip dip an object into something M-e enhance advance or check weapons skills M-f force force a lock M-i invoke invoke an object's special powers M-j jump jump to another location M-l loot loot a box on the floor M-m monster use a monster's special ability M-n name name an item or type of object M-o offer offer a sacrifice to the gods M-p pray pray to the gods for help M-q quit stop playing M-r rub rub a lamp or a stone M-s sit sit down M-t turn turn undead M-u untrap untrap something M-v version print compile time options for this version M-w wipe wipe off your face If the "number_pad" option is on, these additional variants are available: n followed by number of times to repeat the next command h help display one of several informative texts, like '?' j jump jump to another location k kick kick something (usually a door) l loot loot a box on the floor N name name an item or type of object u untrap untrap something (usually a trapped object) nethack-3.4.3/dat/history0100644000000000000000000002434707764735041014060 0ustar rootrootNetHack History file for release 3.4 Behold, mortal, the origins of NetHack... Jay Fenlason wrote the original Hack with help from Kenny Woodland, Mike Thome, and Jon Payne. Andries Brouwer did a major re-write, transforming Hack into a very different game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for UNIX(tm) machines to the Usenet. Don G. Kneller ported Hack 1.0.3 to Microsoft(tm) C and MS-DOS(tm), producing PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went on to produce at least four more versions (3.0, 3.2, 3.51, and 3.6). R. Black ported PC HACK 3.51 to Lattice(tm) C and the Atari 520/1040ST, producing ST Hack 1.03. Mike Stephenson merged these various versions back together, incorporating many of the added features, and produced NetHack version 1.4. He then coordinated a cast of thousands in enhancing and debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. Later, Mike coordinated a major rewrite of the game, heading a team which included Ken Arromdee, Jean-Christophe Collet, Steve Creps, Eric Hendrickson, Izchak Miller, Eric S. Raymond, John Rupley, Mike Threepoint, and Janet Walz, to produce NetHack 3.0c. The same group subsequently released ten patch- level revisions and updates of 3.0. NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by Timo Hakulinen, and to VMS by David Gentzel. The three of them and Kevin Darcy later joined the main development team to produce subsequent revisions of 3.0. Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga. Norm Meluch, Stephen Spackman and Pierre Martineau designed overlay code for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. Headed by Mike Stephenson and coordinated by Izchak Miller and Janet Walz, the development team which now included Ken Arromdee, David Cohrs, Jean-Christophe Collet, Kevin Darcy, Matt Day, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Raymond, and Eric Smith undertook a radical revision of 3.0. They re-structured the game's design, and re-wrote major parts of the code. They added multiple dungeons, a new display, special individual character quests, a new endgame and many other new features, and produced NetHack 3.1. Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for the Amiga. Norm Meluch and Kevin Smolkowski, with help from Carl Schelin, Stephen Spackman, Steve VanDevender, and Paul Winner, ported NetHack 3.1 to the PC. Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Engber, David Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim Lennan, Rob Menke, and Andy Swanson developed NetHack 3.1 for the Macintosh, porting it for MPW. Building on their development, Barton House added a Think C port. Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith ported NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua Delahunty, is responsible for the VMS version of NetHack 3.1. Michael Allison ported NetHack 3.1 to Windows NT. Dean Luick, with help from David Cohrs, developed NetHack 3.1 for X11. Warwick Allison wrote a tiled version of NetHack for the Atari; he later contributed the tiles to the DevTeam and tile support was then added to other platforms. The 3.2 development team, comprised of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, released version 3.2 in April of 1996. Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all thirteen members of the original development team remained on the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2, one of the founding members of the development team, Dr. Izchak Miller, passed away. That release of the game was dedicated to him by the development and porting teams. Version 3.2 proved to be more stable than previous versions. Many bugs were fixed, abuses eliminated, and game features tuned for better game play. During the lifespan of NetHack 3.1 and 3.2, several enthusiasts of the game added their own modifications to the game and made these "variants" publicly available: Tom Proudfoot and Yuval Oren created NetHack++, which was quickly renamed NetHack--. Working independently, Stephen White wrote NetHack Plus. Tom Proudfoot later merged NetHack Plus and his own NetHack-- to produce SLASH. Larry Stewart-Zerba and Warwick Allison improved the spellcasting system with the Wizard Patch. Warwick Allison also ported NetHack to use the Qt interface. Warren Cheung combined SLASH with the Wizard Patch to produce Slash'em, and with the help of Kevin Hugo, added more features. Kevin later joined the DevTeam and incorporated the best of these ideas in NetHack 3.3. The final update to 3.2 was the bug fix release 3.2.3, which was released simultaneously with 3.3.0 in December 1999 just in time for the Year 2000. The 3.3 development team, consisting of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, released 3.3.0 in December 1999 and 3.3.1 in August of 2000. Version 3.3 offered many firsts. It was the first version to separate race and profession. The Elf class was removed in preference to an elf race, and the races of dwarves, gnomes, and orcs made their first appearance in the game alongside the familiar human race. Monk and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, Wizards. It was also the first version to allow you to ride a steed, and was the first version to have a publicly available web-site listing all the bugs that had been discovered. Despite that constantly growing bug list, 3.3 proved stable enough to last for more than a year and a half. The 3.4 development team initially consisted of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul Winner, with Warwick Allison joining just before the release of NetHack 3.4.0 in March 2002. As with version 3.3, various people contributed to the game as a whole as well as supporting ports on the different platforms that NetHack runs on: Pat Rankin maintained 3.4 for VMS. Michael Allison maintained NetHack 3.4 for the MS-DOS platform. Paul Winner and Yitzhak Sapir provided encouragement. Dean Luick, Mark Modrall, and Kevin Hugo maintained and enhanced the Macintosh port of 3.4. Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and Yitzhak Sapir maintained and enhanced 3.4 for the Microsoft Windows platform. Alex Kompel contributed a new graphical interface for the Windows port. Alex Kompel also contributed a Windows CE port for 3.4.1. Ron Van Iwaarden maintained 3.4 for OS/2. Janne Salmijarvi and Teemu Suikki maintained and enhanced the Amiga port of 3.4 after Janne Salmijarvi resurrected it for 3.3.1. Christian `Marvin' Bressler maintained 3.4 for the Atari after he resurrected it for 3.3.1. There is a NetHack web site maintained by Ken Lorber at http://www.nethack.org/. - - - - - - - - - - From time to time, some depraved individual out there in netland sends a particularly intriguing modification to help out with the game. The Gods of the Dungeon sometimes make note of the names of the worst of these miscreants in this, the list of Dungeoneers: Adam Aronow Izchak Miller Mike Stephenson Alex Kompel J. Ali Harlow Norm Meluch Andreas Dorn Janet Walz Olaf Seibert Andy Church Janne Salmijarvi Pasi Kallinen Andy Swanson Jean-Christophe Collet Pat Rankin Ari Huttunen Jochen Erwied Paul Winner Barton House John Kallen Pierre Martineau Benson I. Margulies John Rupley Ralf Brown Bill Dyer John S. Bien Ray Chason Boudewijn Waijers Johnny Lee Richard Addison Bruce Cox Jon W{tte Richard Beigel Bruce Holloway Jonathan Handler Richard P. Hughey Bruce Mewborne Joshua Delahunty Rob Menke Carl Schelin Keizo Yamamoto Robin Johnson Chris Russo Ken Arnold Roderick Schertler David Cohrs Ken Arromdee Roland McGrath David Damerell Ken Lorber Ron Van Iwaarden David Gentzel Ken Washikita Ronnen Miller David Hairston Kevin Darcy Ross Brown Dean Luick Kevin Hugo Sascha Wostmann Del Lamb Kevin Sitze Scott Bigham Deron Meranda Kevin Smolkowski Scott R. Turner Dion Nicolaas Kevin Sweet Stephen Spackman Dylan O'Donnell Lars Huttar Stephen White Eric Backus Malcolm Ryan Steve Creps Eric Hendrickson Mark Gooderum Steve Linhart Eric R. Smith Mark Modrall Steve VanDevender Eric S. Raymond Marvin Bressler Teemu Suikki Erik Andersen Matthew Day Tim Lennan Frederick Roeber Merlyn LeRoy Timo Hakulinen Gil Neiger Michael Allison Tom Almy Greg Laskin Michael Feir Tom West Greg Olson Michael Hamel Warren Cheung Gregg Wonderly Michael Sokolov Warwick Allison Hao-yang Wang Mike Engber Yitzhak Sapir Helge Hafting Mike Gallop Irina Rempt-Drijfhout Mike Passaretti nethack-3.4.3/dat/knox.des0100644000000000000000000000764607764735041014113 0ustar rootroot# SCCS Id: @(#)knox.des 3.4 1994/08/20 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1992 by Izchak Miller # NetHack may be freely redistributed. See license for details. # MAZE:"knox",' ' FLAGS: noteleport GEOMETRY:center,center MAP ---------------------------------------------------------------------------- | |........|...............................................................| | |........|.................................................------------..| | -------+--.................................................|..........|..| | |........}}}}}}}....................}}}}}}}..........|..........|..| | |........}-----}....................}-----}..........--+--+--...|..| | ---........}|...|}}}}}}}}}}}}}}}}}}}}}}|...|}.................|...|..| | |..........}---S------------------------S---}.................|...|..| | |..........}}}|...............|..........|}}}.................+...|..| | -------..........}|...............S..........|}...................|...|..| | |.....|..........}|...............|......\...S}...................|...|..| | |.....+........}}}|...............|..........|}}}.................+...|..| | |.....|........}---S------------------------S---}.................|...|..| | |.....|........}|...|}}}}}}}}}}}}}}}}}}}}}}|...|}.................|...|..| | |..-S----......}-----}....................}-----}..........--+--+--...|..| | |..|....|......}}}}}}}....................}}}}}}}..........|..........|..| | |..|....|..................................................|..........|..| | -----------................................................------------..| | |..............................................................| ---------------------------------------------------------------------------- ENDMAP # Non diggable walls NON_DIGGABLE:(00,00,75,19) # Portal arrival point BRANCH:(08,16,08,16),(0,0,0,0) # Throne room, with Croesus on the throne REGION:(37,08,46,11),lit,"throne" MONSTER:'@',"Croesus",(43,10),hostile # The Vault # Using unfilled morgue for # identification in mkmaze.c REGION:(21,08,35,11),lit,"morgue",unfilled # Corner towers REGION:(19,06,21,06),lit,"ordinary" REGION:(46,06,48,06),lit,"ordinary" REGION:(19,13,21,13),lit,"ordinary" REGION:(46,13,48,13),lit,"ordinary" # A welcoming committee REGION:(03,10,07,13),lit,"zoo",filled,true # arrival chamber; needs to be a real room to control migrating monsters, # and `unfilled' is a kludge to force an ordinary room to remain a room REGION:(06,15,09,16),unlit,"ordinary",unfilled # Barracks REGION:(62,03,71,04),lit,"barracks",filled,true # Doors DOOR:closed,(06,14) DOOR:closed,(09,03) DOOR:open,(63,05) DOOR:open,(66,05) DOOR:open,(68,08) DOOR:locked,(08,11) DOOR:open,(68,11) DOOR:closed,(63,14) DOOR:closed,(66,14) # Soldiers guarding the fort MONSTER:'@',"soldier",(12,14) MONSTER:'@',"soldier",(12,13) MONSTER:'@',"soldier",(11,10) MONSTER:'@',"soldier",(13,02) MONSTER:'@',"soldier",(14,03) MONSTER:'@',"soldier",(20,02) MONSTER:'@',"soldier",(30,02) MONSTER:'@',"soldier",(40,02) MONSTER:'@',"soldier",(30,16) MONSTER:'@',"soldier",(32,16) MONSTER:'@',"soldier",(40,16) MONSTER:'@',"soldier",(54,16) MONSTER:'@',"soldier",(54,14) MONSTER:'@',"soldier",(54,13) MONSTER:'@',"soldier",(57,10) MONSTER:'@',"soldier",(57,09) MONSTER:'@',"lieutenant",(15,08) # Four dragons guarding each side MONSTER:'D',random,(18,09) MONSTER:'D',random,(49,10) MONSTER:'D',random,(33,05) MONSTER:'D',random,(33,14) # Eels in the moat MONSTER:';',"giant eel",(17,08) MONSTER:';',"giant eel",(17,11) MONSTER:';',"giant eel",(48,08) MONSTER:';',"giant eel",(48,11) # The corner rooms treasures OBJECT:'*',"diamond",(19,06) OBJECT:'*',"diamond",(20,06) OBJECT:'*',"diamond",(21,06) OBJECT:'*',"emerald",(19,13) OBJECT:'*',"emerald",(20,13) OBJECT:'*',"emerald",(21,13) OBJECT:'*',"ruby",(46,06) OBJECT:'*',"ruby",(47,06) OBJECT:'*',"ruby",(48,06) OBJECT:'*',"amethyst",(46,13) OBJECT:'*',"amethyst",(47,13) OBJECT:'*',"amethyst",(48,13) nethack-3.4.3/dat/license0100644000000000000000000001141307764735041013767 0ustar rootroot NETHACK GENERAL PUBLIC LICENSE (Copyright 1989 M. Stephenson) (Based on the BISON general public license, copyright 1988 Richard M. Stallman) Everyone is permitted to copy and distribute verbatim copies of this license, but changing it is not allowed. You can also use this wording to make the terms for other programs. The license agreements of most software companies keep you at the mercy of those companies. By contrast, our general public license is intended to give everyone the right to share NetHack. To make sure that you get the rights we want you to have, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. Hence this license agreement. Specifically, we want to make sure that you have the right to give away copies of NetHack, that you receive source code or else can get it if you want it, that you can change NetHack or use pieces of it in new free programs, and that you know you can do these things. To make sure that everyone has such rights, we have to forbid you to deprive anyone else of these rights. For example, if you distribute copies of NetHack, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. Also, for our own protection, we must make certain that everyone finds out that there is no warranty for NetHack. If NetHack is modified by someone else and passed on, we want its recipients to know that what they have is not what we distributed. Therefore we (Mike Stephenson and other holders of NetHack copyrights) make the following terms which say what you must do to be allowed to distribute or change NetHack. COPYING POLICIES 1. You may copy and distribute verbatim copies of NetHack source code as you receive it, in any medium, provided that you keep intact the notices on all files that refer to copyrights, to this License Agreement, and to the absence of any warranty; and give any other recipients of the NetHack program a copy of this License Agreement along with the program. 2. You may modify your copy or copies of NetHack or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above (including distributing this License Agreement), provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains or is a derivative of NetHack or any part thereof, to be licensed at no charge to all third parties on terms identical to those contained in this License Agreement (except that you may choose to grant more extensive warranty protection to some or all third parties, at your option) c) You may charge a distribution fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 3. You may copy and distribute NetHack (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with full information as to how to obtain the complete machine-readable source code from an appropriate archive site. (This alternative is allowed only for noncommercial distribution.) For these purposes, complete source code means either the full source distribution as originally released over Usenet or updated copies of the files in this distribution used to create the object code or executable. 4. You may not copy, sublicense, distribute or transfer NetHack except as expressly provided under this License Agreement. Any attempt otherwise to copy, sublicense, distribute or transfer NetHack is void and your rights to use the program under this License agreement shall be automatically terminated. However, parties who have received computer software programs from you with this License Agreement will not have their licenses terminated so long as such parties remain in full compliance. Stated plainly: You are permitted to modify NetHack, or otherwise use parts of NetHack, provided that you comply with the conditions specified above; in particular, your modified NetHack or program containing parts of NetHack must remain freely available as provided in this License Agreement. In other words, go ahead and share NetHack, but don't try to stop anyone else from sharing it farther. nethack-3.4.3/dat/medusa.des0100644000000000000000000002021407764735041014374 0ustar rootroot# SCCS Id: @(#)medusa.des 3.4 1996/05/11 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1990, 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # These are the Medusa's levels : # MAZE:"medusa-1",' ' FLAGS: noteleport GEOMETRY:center,center MAP }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}.}}}}}..}}}}}......}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}....}}}...}}}}} }...}}.....}}}}}....}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}...............} }....}}}}}}}}}}....}}}..}}}}}}}}}}}.......}}}}}}}}}}}}}}}}..}}.....}}}...}} }....}}}}}}}}.....}}}}..}}}}}}.................}}}}}}}}}}}.}}}}.....}}...}} }....}}}}}}}}}}}}.}}}}.}}}}}}.-----------------.}}}}}}}}}}}}}}}}}.........} }....}}}}}}}}}}}}}}}}}}.}}}...|...............S...}}}}}}}}}}}}}}}}}}}....}} }.....}.}}....}}}}}}}}}.}}....--------+--------....}}}}}}..}}}}}}}}}}}...}} }......}}}}..}}}}}}}}}}}}}........|.......|........}}}}}....}}}}}}}}}}}}}}} }.....}}}}}}}}}}}}}}}}}}}}........|.......|........}}}}}...}}}}}}}}}.}}}}}} }.....}}}}}}}}}}}}}}}}}}}}....--------+--------....}}}}}}.}.}}}}}}}}}}}}}}} }......}}}}}}}}}}}}}}}}}}}}...S...............|...}}}}}}}}}}}}}}}}}.}}}}}}} }.......}}}}}}}..}}}}}}}}}}}}.-----------------.}}}}}}}}}}}}}}}}}....}}}}}} }........}}.}}....}}}}}}}}}}}}.................}}}}}..}}}}}}}}}.......}}}}} }.......}}}}}}}......}}}}}}}}}}}}}}.......}}}}}}}}}.....}}}}}}...}}..}}}}}} }.....}}}}}}}}}}}.....}}}}}}}}}}}}}}}}}}}}}}.}}}}}}}..}}}}}}}}}}....}}}}}}} }}..}}}}}}}}}}}}}....}}}}}}}}}}}}}}}}}}}}}}...}}..}}}}}}}.}}.}}}}..}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ENDMAP # Dungeon Description # (must maintain one room definition; `unfilled' forces its room to be kept) REGION:(00,00,74,19),lit,"ordinary" REGION:(31,07,45,07),unlit,"ordinary" REGION:(35,09,41,10),unlit,"ordinary",unfilled REGION:(31,12,45,12),unlit,"ordinary" # Teleport: down to up stairs island, up to Medusa's island TELEPORT_REGION:(01,01,05,17),(0,0,0,0),down TELEPORT_REGION:(26,04,50,15),(0,0,0,0),up # Stairs STAIR:(05,14),up STAIR:(36,10),down # Doors DOOR:closed,(46,07) DOOR:locked,(38,08) DOOR:locked,(38,11) DOOR:closed,(30,12) # Branch, not allowed inside Medusa's building. BRANCH:levregion(01,00,79,20),(30,06,46,13) # Non diggable walls NON_DIGGABLE:(30,06,46,13) # Objects CONTAINER:'`',"statue",(36,10),uncursed,"knight",3,"Perseus" OBJECT[75%]:'[',"shield of reflection",contained,cursed,+0 OBJECT[25%]:'[',"levitation boots",contained,random,+0 OBJECT[50%]:')',"scimitar",contained,blessed,+2 OBJECT[50%]:'(',"sack",contained # These aren't really containers, but specifying CONTAINER forces them to be # empty, since CONTAINERs contain only what is explicitly specified. CONTAINER:'`',"statue",random CONTAINER:'`',"statue",random CONTAINER:'`',"statue",random CONTAINER:'`',"statue",random CONTAINER:'`',"statue",random CONTAINER:'`',"statue",random CONTAINER:'`',"statue",random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:"board",(38,07) TRAP:"board",(38,12) # Random monsters MONSTER:'@',"Medusa",(36,10),asleep MONSTER:';',"giant eel",(11,06) MONSTER:';',"giant eel",(23,13) MONSTER:';',"giant eel",(29,02) MONSTER:';',"jellyfish",(02,02) MONSTER:';',"jellyfish",(00,08) MONSTER:';',"jellyfish",(04,18) MONSTER:'T',"water troll",(51,03) MONSTER:'T',"water troll",(64,11) MONSTER:'S',random,(38,07) MONSTER:'S',random,(38,12) MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MAZE:"medusa-2",' ' FLAGS: noteleport GEOMETRY:center,center MAP }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }------}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}-------}}}}}}}}--------------} }|....|}}}}}}}}}..}.}}..}}}}}}}}}}}}}..}}}}}}-.....--}}}}}}}|............|} }|....|.}}}}}}}}}}}.}...}}..}}}}}}}}}}}}}}}}}---......}}}}}.|............|} }S....|.}}}}}}---}}}}}}}}}}}}}}}}}}}}}}}}}}---...|..-}}}}}}.S..----------|} }|....|.}}}}}}-...}}}}}}}}}.}}...}.}}}}.}}}......----}}}}}}.|............|} }|....|.}}}}}}-....--}}}}}}}}}}}}}}}}}}}}}}----...--}}}}}}}.|..--------+-|} }|....|.}}}}}}}......}}}}...}}}}}}.}}}}}}}}}}}---..---}}}}}.|..|..S...|..|} }|....|.}}}}}}-....-}}}}}}}------}}}}}}}}}}}}}}-...|.-}}}}}.|..|..|...|..|} }|....|.}}}}}}}}}---}}}}}}}........}}}}}}}}}}---.|....}}}}}.|..|..|...|..|} }|....|.}}}}}}}}}}}}}}}}}}-....|...-}}}}}}}}--...----.}}}}}.|..|..|...|..|} }|....|.}}}}}}..}}}}}}}}}}---..--------}}}}}-..---}}}}}}}}}.|..|..-------|} }|...}|...}}}.}}}}}}...}}}}}--..........}}}}..--}}}}}}}}}}}.|..|.........|} }|...}S...}}.}}}}}}}}}}}}}}}-..--------}}}}}}}}}}}}}}...}}}.|..--------..S} }|...}|...}}}}}}}..}}}}}}----..|....-}}}}}}}}}}}}}}}}}..}}}.|............|} }|....|}}}}}....}}}}..}}.-.......----}}......}}}}}}.......}}|............|} }------}}}}}}}}}}}}}}}}}}---------}}}}}}}}}}}}}}}}}}}}}}}}}}--------------} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} }}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}} ENDMAP # Dungeon Description REGION:(00,00,74,19),lit,"ordinary" REGION:(02,03,05,16),unlit,"ordinary" REGION:(61,03,72,16),unlit,"ordinary",unfilled,true REGION:(71,08,72,11),unlit,"ordinary" REGION:(67,08,69,11),lit,"ordinary" # Teleport: down to up stairs island, up to Medusa's island TELEPORT_REGION:(02,03,05,16),(0,0,0,0),down TELEPORT_REGION:(61,03,72,16),(0,0,0,0),up # Stairs STAIR:(04,09),up STAIR:(68,10),down # Doors DOOR:locked,(71,07) # Branch, not allowed on Medusa's island. BRANCH:levregion(01,00,79,20),(59,01,73,17) # Non diggable walls NON_DIGGABLE:(01,02,06,17) NON_DIGGABLE:(60,02,73,17) # Objects CONTAINER:'`',"statue",(68,10),uncursed,"knight",3,"Perseus" OBJECT[25%]:'[',"shield of reflection",contained,cursed,+0 OBJECT[75%]:'[',"levitation boots",contained,random,+0 OBJECT[50%]:')',"scimitar",contained,blessed,+2 OBJECT[50%]:'(',"sack",contained CONTAINER:'`',"statue",(64,08) CONTAINER:'`',"statue",(65,08) CONTAINER:'`',"statue",(64,09) CONTAINER:'`',"statue",(65,09) CONTAINER:'`',"statue",(64,10) CONTAINER:'`',"statue",(65,10) CONTAINER:'`',"statue",(64,11) CONTAINER:'`',"statue",(65,11) OBJECT:'`',"boulder",(04,04) OBJECT:'/',random,(52,09) OBJECT:'`',"boulder",(52,09) OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Traps TRAP:"magic",(03,12) TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Monsters. MONSTER:'@',"Medusa",(68,10),asleep MONSTER:'g',"gremlin",(02,14) MONSTER:'H',"titan",(02,05) MONSTER:';',"electric eel",(10,13) MONSTER:';',"electric eel",(11,13) MONSTER:';',"electric eel",(10,14) MONSTER:';',"electric eel",(11,14) MONSTER:';',"electric eel",(10,15) MONSTER:';',"electric eel",(11,15) MONSTER:';',"jellyfish",(01,01) MONSTER:';',"jellyfish",(00,08) MONSTER:';',"jellyfish",(04,19) MONSTER:''',"stone golem",(64,08),asleep MONSTER:''',"stone golem",(65,08),asleep MONSTER:''',"stone golem",(64,09),asleep MONSTER:''',"stone golem",(65,09),asleep MONSTER:'S',"cobra",(64,10),asleep MONSTER:'S',"cobra",(65,10),asleep MONSTER:'A',random,(72,08) MONSTER:'y',"yellow light",(72,11),asleep MONSTER:random,random,(17,07) MONSTER:random,random,(28,11) MONSTER:random,random,(32,13) MONSTER:random,random,(49,09) MONSTER:random,random,(48,07) MONSTER:random,random,(65,03) MONSTER:random,random,(70,04) MONSTER:random,random,(70,15) MONSTER:random,random,(65,16) MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random nethack-3.4.3/dat/mines.des0100644000000000000000000007271607764735041014247 0ustar rootroot# SCCS Id: @(#)mines.des 3.4 2002/05/02 # Copyright (c) 1989-95 by Jean-Christophe Collet # Copyright (c) 1991-95 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The "fill" level for the mines. # # This level is used to fill out any levels not occupied by # specific levels as defined below. # MAZE: "minefill" , ' ' INIT_MAP: '.' , ' ' , true , true , random , true NOMAP # STAIR: random, up STAIR: random, down # OBJECT: '*', random, random OBJECT: '*', random, random OBJECT: '*', random, random OBJECT: '(', random, random OBJECT: random, random, random OBJECT: random, random, random OBJECT: random, random, random # MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome lord", random MONSTER: 'h', "dwarf", random MONSTER: 'h', "dwarf", random MONSTER: 'G', random, random MONSTER: 'G', random, random MONSTER: 'h', random, random # TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random TRAP: random, random # Minetown variant 1 # "Frontier Town" # LEVEL: "minetn-1" ROOM: "ordinary" , lit, (3,3), (center,center), (31,15) NAME: "town" FOUNTAIN: (13, 7) FOUNTAIN: (20, 7) # The Town Watch MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watch captain", random, peaceful SUBROOM: "shop" , lit, (2,2), (3,4), "town" CHANCE: 90 DOOR: false, closed, south, random SUBROOM: "tool shop", lit, (2,9), (3,4), "town" CHANCE: 90 DOOR: false, closed, north, random SUBROOM: "ordinary", unlit, (6,2), (3,4), "town" DOOR: false, closed, south, random SUBROOM: "ordinary", lit, (6,9), (3,4), "town" DOOR: false, closed, north, random SUBROOM: "food shop", lit, (10,2), (2,3), "town" CHANCE: 90 DOOR: false, closed, south, random SUBROOM: "candle shop", lit, (22,2), (3,3), "town" DOOR: false, closed, south, random SUBROOM: "ordinary", unlit, (10,10), (2,3), "town" DOOR: false, locked, east, random MONSTER: 'G', "gnome", random SUBROOM: "ordinary", lit, (19,2), (2,3), "town" DOOR: false, locked, west, random MONSTER: 'G', "gnome", random SUBROOM: "temple", lit, (15,9), (4,4), "town" DOOR: false, closed, north, random ALTAR:(02,02),align[0],shrine MONSTER: 'G', "gnomish wizard", random MONSTER: 'G', "gnomish wizard", random SUBROOM: "ordinary", lit, (22,10), (2,3), "town" DOOR: false, locked, west, random SUBROOM: "ordinary", lit, (26,2), (3,3), "town" DOOR: false, closed, south, random MONSTER: 'G', "gnome lord", random SUBROOM: "ordinary", unlit, (25,10), (4,3), "town" DOOR: false, closed, north, random ROOM: "ordinary" , random, random, random, random STAIR: random, up ROOM: "ordinary" , random, random, random, random STAIR: random, down TRAP: random, random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random ROOM: "ordinary" , random, random, random, random MONSTER: 'h', "dwarf", random ROOM: "ordinary" , random, random, random, random TRAP: random, random MONSTER: 'G', "gnome", random RANDOM_CORRIDORS # Minetown variant 2 # "Town Square" # LEVEL: "minetn-2" ROOM: "ordinary" , lit, (3,3), (center,center), (31,15) NAME: "town" FOUNTAIN: (17, 5) FOUNTAIN: (13, 8) # The Town Watch MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watch captain", random, peaceful SUBROOM: "ordinary", random, (2,0), (2,2), "town" DOOR: false, closed, west, random SUBROOM: "ordinary", unlit, (5,0), (2,2), "town" DOOR: false, closed, south, random SUBROOM: "ordinary", random, (8,0), (2,2), "town" DOOR: false, closed, east, random SUBROOM: "ordinary", lit, (16,0), (2,2), "town" DOOR: false, closed, west, random SUBROOM: "ordinary", unlit, (19,0), (2,2), "town" DOOR: false, closed, south, random SUBROOM: "ordinary", random, (22,0), (2,2), "town" DOOR: false, locked, south, random MONSTER: 'G', "gnome", random SUBROOM: "ordinary", unlit, (25,0), (2,2), "town" DOOR: false, closed, east, random SUBROOM: "ordinary", lit, (2,5), (2,2), "town" DOOR: false, closed, north, random SUBROOM: "ordinary", lit, (5,5), (2,2), "town" DOOR: false, closed, south, random SUBROOM: "ordinary", random, (8,5), (2,2), "town" DOOR: false, locked, north, random MONSTER: 'G', "gnome", random SUBROOM: "shop" , lit, (2,10), (4,3), "town" CHANCE: 90 DOOR: false, closed, west, random SUBROOM: "tool shop", lit, (23,10), (4,3), "town" CHANCE: 90 DOOR: false, closed, east, random SUBROOM: "food shop", lit, (24,5), (3,4), "town" CHANCE: 90 DOOR: false, closed, north, random SUBROOM: "candle shop", lit, (11,10), (4,3), "town" DOOR: false, closed, east, random SUBROOM: "ordinary", unlit, (7,10), (3,3), "town" DOOR: false, locked, north, random MONSTER: 'G', "gnome", random SUBROOM: "temple", lit, (19,5), (4,4), "town" DOOR: false, closed, north, random ALTAR:(02,02),align[0],shrine MONSTER: 'G', "gnomish wizard", random MONSTER: 'G', "gnomish wizard", random SUBROOM: "ordinary", lit, (18,10), (4,3), "town" DOOR: false, locked, west, random MONSTER: 'G', "gnome lord", random ROOM: "ordinary" , random, random, random, random STAIR: random, up ROOM: "ordinary" , random, random, random, random STAIR: random, down TRAP: random, random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random ROOM: "ordinary" , random, random, random, random MONSTER: 'h', "dwarf", random ROOM: "ordinary" , random, random, random, random TRAP: random, random MONSTER: 'G', "gnome", random RANDOM_CORRIDORS # Minetown variant 3 by Kelly Bailey # "Alley Town" # LEVEL: "minetn-3" ROOM: "ordinary",lit,(3,3),(center,center),(31,15) NAME: "town" FOUNTAIN:(01,06) FOUNTAIN:(29,13) MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watch captain", random, peaceful SUBROOM:"ordinary",random,(2,2),(2,2),"town" DOOR: false,closed,south,random SUBROOM:"tool shop",lit,(5,3),(2,3),"town" CHANCE: 30 DOOR: false,closed,south,random SUBROOM:"ordinary",random,(2,10),(2,3),"town" DOOR: false, locked, north, random MONSTER: 'G',random,random SUBROOM:"ordinary",random,(5,9),(2,2),"town" DOOR: false,closed,north,random SUBROOM:"temple",lit,(10,2),(3,4),"town" DOOR: false,closed,east,random ALTAR:(1,1),align[0],shrine MONSTER: 'G', "gnomish wizard", random MONSTER: 'G', "gnomish wizard", random SUBROOM:"ordinary",random,(11,7),(2,2),"town" DOOR: false,closed,west,random SUBROOM:"shop",lit,(10,10),(3,3),"town" DOOR:false,closed,west,random SUBROOM:"ordinary",random,(14,8),(2,2),"town" DOOR:false,locked,north,random MONSTER: 'G',random,random SUBROOM:"ordinary",random,(14,11),(2,2),"town" DOOR:false,closed,south,random SUBROOM:"tool shop",lit,(17,10),(3,3),"town" CHANCE:40 DOOR:false,closed,north,random SUBROOM:"ordinary",random,(21,11),(2,2),"town" DOOR:false,locked,east,random MONSTER:'G',random,random SUBROOM:"food shop",lit,(26,8),(3,2),"town" CHANCE:90 DOOR:false,closed,west,random SUBROOM:"ordinary",random,(16,2),(2,2),"town" DOOR:false,closed,west,random SUBROOM:"ordinary",random,(19,2),(2,2),"town" DOOR:false,closed,north,random SUBROOM:"wand shop",lit,(19,5),(3,2),"town" CHANCE:30 DOOR:false,closed,west,random SUBROOM: "candle shop",lit,(25,2),(3,3),"town" DOOR:false,closed,south,random ROOM: "ordinary", random, random, random, random STAIR: random, up ROOM: "ordinary" , random, random, random, random STAIR: random, down TRAP: random, random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random ROOM: "ordinary" , random, random, random, random MONSTER: 'h', "dwarf", random ROOM: "ordinary" , random, random, random, random TRAP: random, random MONSTER: 'G', "gnome", random RANDOM_CORRIDORS # Minetown variant 4 by Kelly Bailey # "College Town" # LEVEL: "minetn-4" ROOM: "ordinary",lit,(3,3),(center,center),(30,15) NAME: "town" FOUNTAIN:(08,07) FOUNTAIN:(18,07) MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watch captain", random, peaceful SUBROOM:"book shop",lit,(4,2),(3,3),"town" DOOR: false,closed,south,random SUBROOM:"ordinary",random,(8,2),(2,2),"town" DOOR: false,closed,south,random SUBROOM:"temple",lit,(11,3),(5,4),"town" DOOR: false,closed,south,random ALTAR:(2,1),align[0],shrine MONSTER: 'G', "gnomish wizard", random MONSTER: 'G', "gnomish wizard", random SUBROOM:"ordinary",random,(19,2),(2,2),"town" DOOR: false,closed,south,random MONSTER: 'G', random, random SUBROOM:"candle shop",lit,(22,2),(3,3),"town" DOOR:false,closed,south,random SUBROOM:"ordinary",random,(26,2),(2,2),"town" DOOR:false,locked,east,random MONSTER: 'G',random,random SUBROOM:"tool shop",lit,(4,10),(3,3),"town" CHANCE:90 DOOR:false,closed,north,random SUBROOM:"ordinary",random,(8,11),(2,2),"town" DOOR:false,locked,south,random MONSTER: 'k',"kobold shaman",random MONSTER: 'k',"kobold shaman",random MONSTER: 'f',"kitten",random MONSTER: 'f',random,random SUBROOM:"food shop",lit,(11,11),(3,2),"town" CHANCE:90 DOOR:false,closed,east,random SUBROOM:"ordinary",random,(17,11),(2,2),"town" DOOR:false,closed,west,random SUBROOM:"ordinary",random,(20,10),(2,2),"town" DOOR:false,locked,north,random MONSTER:'G',random,random SUBROOM:"shop",lit,(23,10),(3,3),"town" CHANCE:90 DOOR:false,closed,north,random ROOM: "ordinary" , random, random, random, random STAIR: random, up ROOM: "ordinary" , random, random, random, random STAIR: random, down TRAP: random, random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random ROOM: "ordinary" , random, random, random, random MONSTER: 'h', "dwarf", random ROOM: "ordinary" , random, random, random, random TRAP: random, random MONSTER: 'G', "gnome", random RANDOM_CORRIDORS # "Grotto Town" by Kelly Bailey # MAZE: "minetn-5",' ' GEOMETRY:center,center MAP ----- --------- |...--- ------.......-- ------- --------------- |.....----.........--..| |.....| ------- |.............| --..-....-.----------..| |.....| |.....| --+---+--.----+- --.--.....---- ---- |.....| ------ --....---- |..-...--.-.+..| ---.........---- ----- ---+--- |..+.| ---..-..----..---+-..---..| ----.-....|..----...-- |.| |..|.| ---+-.....-+--........--+- -----..|....-.....---- |.| |..|.------......--................| ------ |..|.............---.-- ----.+..|-.......--..--------+--..-- |....| --......---...........----- |.|..|-...{....---|.........|..-- |....| |........-...-...........----.|..|--.......| |.........|...| ---+--------....-------...---......--.-------....---- -----------...| ------.---...--...--..-..--...-..---...|.--..-...-....------- |.......-- |..|-.........-..---..-..---.....--....|........---...-|....| |.------- |..+...............-+---+-----..--..........--....--...+....| |.|...S. -----.....{....----...............-...........--...-...-|....| |.|...| |..............-- --+--.---------.........--..-........------- |.--+------- -+-----.........| |...|.|....| --.......------...|....---------.....|....| |...| --..------- |...|.+....| ---...--- --..|...--......-...{..+..-+| |...| ---- ------|....| ----- -----.....----........|..|.| ----- ------ ------- --------------- ENDMAP STAIR:(01,01),up STAIR:(46,03),down FOUNTAIN:(50,09) FOUNTAIN:(10,15) FOUNTAIN:(66,18) REGION:(00,00,74,20),unlit,"ordinary" REGION:(09,13,11,17),lit,"ordinary" REGION:(08,14,12,16),lit,"ordinary" REGION:(49,07,51,11),lit,"ordinary" REGION:(48,08,52,10),lit,"ordinary" REGION:(64,17,68,19),lit,"ordinary" REGION:(37,13,39,17),lit,"ordinary" REGION:(36,14,40,17),lit,"ordinary" REGION:(59,02,72,10),lit,"ordinary" MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watch captain", random, peaceful MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome lord", random MONSTER: 'G', "gnome lord", random MONSTER: 'h', "dwarf", random MONSTER: 'h', "dwarf", random MONSTER: 'h', "dwarf", random # The shops REGION:(25,17,28,19),lit,"candle shop" DOOR:closed,(24,18) REGION:(59,9,67,10),lit,"shop" DOOR:closed,(66,08) REGION:(57,13,60,15),lit,"tool shop" DOOR:closed,(56,14) REGION:(05,09,08,10),lit,"food shop" DOOR:closed,(07,11) # Gnome homes DOOR:closed,(04,14) DOOR:locked,(01,17) MONSTER: 'G', "gnomish wizard", (02,19) DOOR:locked,(20,16) MONSTER: 'G', random, (20,18) DOOR:random,(21,14) DOOR:random,(25,14) DOOR:random,(42,08) DOOR:locked,(40,05) MONSTER: 'G', random, (38,07) DOOR:random,(59,03) DOOR:random,(58,06) DOOR:random,(63,03) DOOR:random,(63,05) DOOR:locked,(71,03) DOOR:locked,(71,06) DOOR:closed,(69,04) DOOR:closed,(67,16) MONSTER: 'G', "gnomish wizard", (67,14) OBJECT: '=', random, (70,14) DOOR:locked,(69,18) MONSTER: 'G', "gnome lord", (71,19) DOOR:locked,(73,18) OBJECT: '(', "chest", (73,19) DOOR:locked,(50,06) OBJECT: '(', random, (50,03) OBJECT: '`', "statue", (38,15), "gnome king", 1 # Temple REGION:(29,02,33,04),lit,"temple" DOOR:closed,(31,05) ALTAR:(31,03),align[0],shrine # "Bustling Town" by Kelly Bailey # MAZE: "minetn-6",' ' INIT_MAP:'.','-',true,true,lit,true GEOMETRY:center,top MAP .-----................----------------.- .|...|................|...|..|...|...|.. .|...+..--+--.........|...|..|...|...|.. .|...|..|...|..-----..|...|..|-+---+--.. .-----..|...|--|...|..--+---+-.........| ........|...|..|...+.............-----.. ........-----..|...|......--+-...|...|.. .----...|...|+------..{...|..|...+...|.. .|..+...|...|.............|..|...|...|.. .|..|...|...|-+-.....---+-------------.| .----...--+--..|..-+-|.................. ...|........|..|..|..|----....---------. ...|..T.....----..|..|...+....|......|-. ...|-....{........|..|...|....+......|-. ...--..-....T.....--------....|......|-. .......--.....................---------- ENDMAP REGION:(00,00,38,15),lit,"ordinary" STAIR:levregion(01,03,20,19),(0,0,39,15),up STAIR:levregion(61,03,75,19),(0,0,39,15),down FOUNTAIN:(22,07) FOUNTAIN:(09,13) REGION:(13,5,14,6),unlit,"ordinary" REGION:(9,7,11,9),lit,"candle shop" REGION:(16,4,18,6),lit,"tool shop" REGION:(23,1,25,3),lit,"shop" REGION:(22,12,24,13),lit,"food shop" REGION:(31,12,36,14),lit,"temple" ALTAR:(35,13),align[0],shrine DOOR:closed,(5,2) DOOR:locked,(4,8) DOOR:closed,(10,2) DOOR:closed,(10,10) DOOR:locked,(13,7) DOOR:locked,(14,9) DOOR:closed,(19,5) DOOR:closed,(19,10) DOOR:closed,(24,4) DOOR:closed,(24,9) DOOR:closed,(25,12) DOOR:closed,(28,4) DOOR:locked,(28,6) DOOR:closed,(30,13) DOOR:closed,(31,3) DOOR:closed,(35,3) DOOR:closed,(33,7) MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", (14,6) MONSTER: 'G', "gnome lord", (14,5) MONSTER: 'G', "gnome", (27,8) MONSTER: 'G', "gnome lord", random MONSTER: 'G', "gnome lord", random MONSTER: 'h', "dwarf", random MONSTER: 'h', "dwarf", random MONSTER: 'h', "dwarf", random MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watch captain", random, peaceful MONSTER: '@', "watch captain", random, peaceful # "Bazaar Town" by Kelly Bailey # LEVEL: "minetn-7" ROOM: "ordinary" , lit, (3,3), (center,center), (30,15) NAME: "town" FOUNTAIN: (12, 07) FOUNTAIN: (11, 13) MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watchman", random, peaceful MONSTER: '@', "watch captain", random, peaceful MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome lord",random MONSTER:'Y',"monkey",random MONSTER:'Y',"monkey",random SUBROOM: "ordinary", random, (2,2), (4,2), "town" DOOR: false, closed, south, random SUBROOM: "ordinary", random, (7,2), (2,2), "town" DOOR: false, closed, north, random SUBROOM: "ordinary", random, (7,5), (2,2), "town" DOOR: false, closed, south, random SUBROOM: "ordinary", lit, (10,2), (3,4), "town" MONSTER:'G',"gnome",random MONSTER:'Y',"monkey",random MONSTER:'Y',"monkey",random MONSTER:'Y',"monkey",random DOOR: false, closed, south, random SUBROOM: "ordinary", random, (14,2), (4,2), "town" DOOR: false, closed, south, 0 MONSTER: 'n', random, random SUBROOM: "ordinary", random, (16,5), (2,2), "town" DOOR: false, closed, south, random SUBROOM: "ordinary", unlit, (19,2), (2,2), "town" DOOR: false, locked, east, random MONSTER: 'G',"gnome king",random SUBROOM: "food shop", lit, (19,5), (2,3), "town" CHANCE: 50 DOOR: false, closed, south, random SUBROOM: "ordinary", random, (2,7), (2,2), "town" DOOR: false, closed, east, random SUBROOM: "tool shop", lit, (2,10), (2,3), "town" CHANCE: 50 DOOR: false, closed, south, random SUBROOM: "candle shop", lit, (5,10),(3,3), "town" DOOR: false, closed, north, random SUBROOM: "ordinary", random, (11,10), (2,2), "town" DOOR: false, locked, west, random MONSTER: 'G',random,random SUBROOM: "shop", lit, (14,10), (2,3), "town" CHANCE: 60 DOOR: false, closed, north, random SUBROOM: "ordinary", random, (17,11), (4,2), "town" DOOR: false, closed, north, random SUBROOM: "ordinary", random, (22,11), (2,2), "town" DOOR: false, closed, south, random SINK: (00,00) SUBROOM: "food shop", lit, (25,11), (3,2), "town" CHANCE: 50 DOOR: false, closed, east, random SUBROOM: "tool shop", lit, (25,2), (3,3), "town" CHANCE: 30 DOOR: false, closed, west, random SUBROOM: "temple", lit, (24,6), (4,4), "town" DOOR: false, closed, west, random ALTAR:(02,01),align[0],shrine MONSTER: 'G', "gnomish wizard", random MONSTER: 'G', "gnomish wizard", random ROOM: "ordinary" , random, random, random, random STAIR: random, up ROOM: "ordinary" , random, random, random, random STAIR: random, down TRAP: random, random MONSTER: 'G', "gnome", random MONSTER: 'G', "gnome", random ROOM: "ordinary" , random, random, random, random MONSTER: 'h', "dwarf", random ROOM: "ordinary" , random, random, random, random TRAP: random, random MONSTER: 'G', "gnome", random RANDOM_CORRIDORS # Mine end level variant 1 # "Mimic of the Mines" # MAZE: "minend-1", ' ' GEOMETRY:center,center #1234567890123456789012345678901234567890123456789012345678901234567890 MAP ------------------------------------------------------------------ ------ | |.......| |.......-...| |.....|. | | --------- ----.......-------...........| ---...-S- | | |.......| |..........................-S- --.......| | | |......------- ---........................|. |.......-- | | |..--........-----..........................|. -.-..---- | | --..--.-----........-.....................--- --..-- | | --..--..| -----------..................---.----------..-- | | |...--.| |..S...S..............---................-- | | ----..----- ------------........--- ------------...--- | | |.........-- ---------- ---...-- ----- | | --.....---..-- -------- --...---...-- | | ----..-..-- --..--------------------- --......-- ---........| | |--....----- --..-..................--- |........| |.......-- | |.......| --......................S.. --......-- ---..---- | |--.--.-- ----.................--- ------..------...-- | | |....S.. |...............-..| ..S...........| | -------- -------------------- ------------------------ ENDMAP # Dungeon Description RANDOM_PLACES:(08,16),(13,07),(21,08),(41,14),(50,04),(50,16),(66,01) REGION:(26,01,32,01),unlit,"ordinary",filled,true REGION:(20,08,21,08),unlit,"ordinary" REGION:(23,08,25,08),unlit,"ordinary" # Secret doors DOOR:locked,(07,16) DOOR:locked,(22,08) DOOR:locked,(26,08) DOOR:locked,(40,14) DOOR:locked,(50,03) DOOR:locked,(51,16) DOOR:locked,(66,02) # Stairs STAIR:(36,04),up # Non diggable walls NON_DIGGABLE:(00,00,74,17) # Niches # Note: place[6] empty OBJECT:'*',"diamond",place[0] OBJECT:'*',"emerald",place[0] OBJECT:'*',"worthless piece of violet glass",place[0] MONSTER:'m',random,place[0], m_object "luckstone" OBJECT:'*',"worthless piece of white glass",place[1] OBJECT:'*',"emerald",place[1] OBJECT:'*',"amethyst",place[1] MONSTER:'m',random,place[1], m_object "loadstone" OBJECT:'*',"diamond",place[2] OBJECT:'*',"worthless piece of green glass",place[2] OBJECT:'*',"amethyst",place[2] MONSTER:'m',random,place[2], m_object "flint" OBJECT:'*',"worthless piece of white glass",place[3] OBJECT:'*',"emerald",place[3] OBJECT:'*',"worthless piece of violet glass",place[3] MONSTER:'m',random,place[3], m_object "touchstone" OBJECT:'*',"worthless piece of red glass",place[4] OBJECT:'*',"ruby",place[4] OBJECT:'*',"loadstone",place[4] OBJECT:'*',"ruby",place[5] OBJECT:'*',"worthless piece of red glass",place[5] OBJECT:'*',"luckstone",place[5] # Random objects OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'(',random,random OBJECT:'(',random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters MONSTER:'G',"gnome king",random MONSTER:'G',"gnome lord",random MONSTER:'G',"gnome lord",random MONSTER:'G',"gnome lord",random MONSTER:'G',"gnomish wizard",random MONSTER:'G',"gnomish wizard",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'h',"hobbit",random MONSTER:'h',"hobbit",random MONSTER:'h',"dwarf",random MONSTER:'h',"dwarf",random MONSTER:'h',"dwarf",random MONSTER:'h',random,random # Mine end level variant 2 # "Gnome King's Wine Cellar" # MAZE: "minend-2", ' ' GEOMETRY:center,center MAP --------------------------------------------------------------------------- |...................................................| | |.|---------S--.--|...|--------------------------|..| | |.||---| |.||-| |...|..........................|..| | |.||...| |-|.|.|---...|.............................| .. | |.||...|-|.....|....|-|..........................|..|. .. | |.||.....|-S|..|....|............................|..|.. | |.||--|..|..|..|-|..|----------------------------|..|-. | |.| |..|..|....|..................................|... | |.| |..|..|----|..-----------------------------|..|.... | |.|---|..|--|.......|----------------------------|..|..... | |...........|----.--|......................| |..|....... | |-----------|...|.| |------------------|.|.|-----|..|.....|.. | |-----------|.{.|.|--------------------|.|..........|.....|.... | |...............|.S......................|-------------..-----... | |.--------------|.|--------------------|.|......................... | |.................| |.....................|........ | --------------------------------------------------------------------------- ENDMAP # Dungeon Description FOUNTAIN:(14,13) REGION:(23,03,48,06),lit,"ordinary" REGION:(21,06,22,06),lit,"ordinary" REGION:(14,04,14,04),unlit,"ordinary" REGION:(10,05,14,08),unlit,"ordinary" REGION:(10,09,11,09),unlit,"ordinary" REGION:(15,08,16,08),unlit,"ordinary" # Secret doors DOOR:locked,(12,02) DOOR:locked,(11,06) # Stairs STAIR:(36,04),up # Non diggable walls NON_DIGGABLE:(00,00,52,17) NON_DIGGABLE:(53,00,74,00) NON_DIGGABLE:(53,17,74,17) NON_DIGGABLE:(74,01,74,16) NON_DIGGABLE:(53,07,55,07) NON_DIGGABLE:(53,14,61,14) # The Gnome King's wine cellar. ENGRAVING:(12,03),engrave,"You are now entering the Gnome King's wine cellar." ENGRAVING:(12,04),engrave,"Trespassers will be persecuted!" OBJECT:'!',"booze",(10,07) OBJECT:'!',"booze",(10,07) OBJECT:'!',random,(10,07) OBJECT:'!',"booze",(10,08) OBJECT:'!',"booze",(10,08) OBJECT:'!',random,(10,08) OBJECT:'!',"booze",(10,09) OBJECT:'!',"booze",(10,09) OBJECT:'!',"object detection",(10,09) # Objects # The Treasure chamber... OBJECT:'*',"diamond",(69,04) OBJECT:'*',random,(69,04) OBJECT:'*',"diamond",(69,04) OBJECT:'*',random,(69,04) OBJECT:'*',"emerald",(70,04) OBJECT:'*',random,(70,04) OBJECT:'*',"emerald",(70,04) OBJECT:'*',random,(70,04) OBJECT:'*',"emerald",(69,05) OBJECT:'*',random,(69,05) OBJECT:'*',"ruby",(69,05) OBJECT:'*',random,(69,05) OBJECT:'*',"ruby",(70,05) OBJECT:'*',"amethyst",(70,05) OBJECT:'*',random,(70,05) OBJECT:'*',"amethyst",(70,05) OBJECT:'*',"luckstone",(70,05) # Scattered gems... OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'*',random,random OBJECT:'(',random,random OBJECT:'(',random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random # Random traps TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # Random monsters. MONSTER:'G',"gnome king",random MONSTER:'G',"gnome lord",random MONSTER:'G',"gnome lord",random MONSTER:'G',"gnome lord",random MONSTER:'G',"gnomish wizard",random MONSTER:'G',"gnomish wizard",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'G',"gnome",random MONSTER:'h',"hobbit",random MONSTER:'h',"hobbit",random MONSTER:'h',"dwarf",random MONSTER:'h',"dwarf",random MONSTER:'h',"dwarf",random MONSTER:'h',random,random # "Catacombs" by Kelly Bailey # Relies on some very specific behavior of MAZEWALK. # MAZE:"minend-3",'-' FLAGS:nommap GEOMETRY:center,bottom MAP - - - - - - - - - - -- -- - - . - - - - - - - - - -- - - -- - - - - . - - | ------...---------.-----------...-----.-------.------- ----------------| - - - - - - - - - - - . - - - . - - - - - - - - - - -- - -- - . - - - - - | ------------.---------...-------------------------.--- ------------------| - - - - - - - - - - . . - - --- - . - - - - - - - - -- -- - - - - |.....| | --.---------------.......------------------------------- ----------|.....S-| - - - - |.. ..| - ....... . - - - - |.........| - - - --- - - - - |.....| | ----.----|.....|------.......--------|.........|--------------.------------| - - - - |..{..| - - -.... . --- - -.S.........S - - - - - - - - - - - - - | ---------|.....|--.---...------------|.........|---------------------------| - - - - |.. ..| - - - . - - - - - - |.........| - --- . - - - - - - - - - | ----------------------...-------.---------------------...------------------| ---..| - - - - - - - - . --- - - - - - - - - - - - - - . - - --- - - --- - | -.S..|----.-------.------- ---------.-----------------...----- -----.------- ---..| - - - - - - - -- - - -- . - - - - - . - - - . - . - - -- -- - - - -- -.S..|--------.---.--- -...---------------...{.--------- --------- --|. - - - - - - - -- - - - -- . - - - --- - - - . . - - - - -- - - - - - - ENDMAP RANDOM_PLACES:(1,15),(68,6),(1,13) NON_DIGGABLE:(67,3,73,7) NON_DIGGABLE:(0,12,2,16) FOUNTAIN:(12,08) FOUNTAIN:(51,15) REGION:(0,0,75,16),unlit,"ordinary" REGION:(38,6,46,10),lit,"ordinary" DOOR:closed,(37,8) DOOR:closed,(47,8) DOOR:closed,(73,5) DOOR:closed,(2,15) MAZEWALK:(36,8),west STAIR:(42,8),up # Objects OBJECT:'*',"diamond",random OBJECT:'*',random,random OBJECT:'*',"diamond",random OBJECT:'*',random,random OBJECT:'*',"emerald",random OBJECT:'*',random,random OBJECT:'*',"emerald",random OBJECT:'*',random,random OBJECT:'*',"emerald",random OBJECT:'*',random,random OBJECT:'*',"ruby",random OBJECT:'*',random,random OBJECT:'*',"ruby",random OBJECT:'*',"amethyst",random OBJECT:'*',random,random OBJECT:'*',"amethyst",random OBJECT:'*',"luckstone",place[0] OBJECT:'*',"flint",place[1] OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'+',random,random OBJECT:'+',random,random OBJECT:'+',random,random OBJECT:'+',random,random OBJECT:random,random,random OBJECT:random,random,random OBJECT:random,random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random TRAP:random,random # One-time annoyance factor TRAP:"level teleport",place[0] TRAP:"level teleport",place[1] MONSTER:'M',random,random MONSTER:'M',random,random MONSTER:'M',random,random MONSTER:'M',random,random MONSTER:'M',random,random MONSTER:'M',"ettin mummy",random MONSTER:'V',random,random MONSTER:'Z',random,random MONSTER:'Z',random,random MONSTER:'Z',random,random MONSTER:'Z',random,random MONSTER:'Z',random,random MONSTER:'V',random,random MONSTER:'e',random,random MONSTER:'e',random,random MONSTER:'e',random,random MONSTER:'e',random,random # end mines.des nethack-3.4.3/dat/opthelp0100644000000000000000000003251707764735041014030 0ustar rootrootBoolean options not under specific compile flags (with default values in []): (You can learn which options exist in your version by checking your current option setting, which is reached via the 'O' cmd.) autodig dig if moving and wielding digging tool [FALSE] autopickup automatically pick up objects you move over [TRUE] autoquiver when firing with an empty quiver, select some suitable inventory weapon to fill the quiver [FALSE] BIOS allow the use of IBM ROM BIOS calls [FALSE] cmdassist give help for errors on direction & other commands [TRUE] confirm ask before hitting tame or peaceful monsters [TRUE] DECgraphics use DEC/VT line-drawing characters for the dungeon [FALSE] eight_bit_tty send 8-bit characters straight to terminal [FALSE] extmenu use a menu for selecting extended commands (#) [FALSE] fixinv try to retain the same letter for the same object [TRUE] help print all available info when using the / command [TRUE] IBMgraphics use IBM extended characters for the dungeon [FALSE] ignintr ignore interrupt signal, including breaks [FALSE] legacy print introductory message [TRUE] lit_corridor show a dark corridor as lit if in sight [FALSE] lootabc use a/b/c rather than o/i/b when looting [FALSE] mail enable the mail daemon [TRUE] null allow nulls to be sent to your terminal [TRUE] try turning this option off (forcing NetHack to use its own delay code) if moving objects seem to teleport across rooms number_pad use the number keys to move instead of yuhjklbn [FALSE] perm_invent keep inventory in a permanent window [FALSE] prayconfirm use confirmation prompt when #pray command issued [TRUE] pushweapon when wielding a new weapon, put your previously wielded weapon into the secondary weapon slot [FALSE] rawio allow the use of raw I/O [FALSE] rest_on_space count the space bar as a rest character [FALSE] safe_pet prevent you from (knowingly) attacking your pet(s) [TRUE] showrace show yourself by your race rather than by role [FALSE] silent don't use your terminal's bell sound [TRUE] sortpack group similar kinds of objects in inventory [TRUE] sound enable messages about what your character hears [TRUE] (note: this has nothing to do with your computer's audio capabilities, and the game resets it periodically) sparkle display sparkly effect for resisted magical [TRUE] attacks (e.g. fire attack on fire-resistant monster) standout use standout mode for --More-- on messages [FALSE] time display elapsed game time, in moves [FALSE] tombstone print tombstone when you die [TRUE] toptenwin print topten in a window rather than stdout [FALSE] travel enable the command to travel to a map location via [TRUE] a shortest-path algorithm, usually invoked by '_'. verbose print more commentary during the game [TRUE] There are further boolean options controlled by compilation flags. Boolean option if INSURANCE was set at compile time: checkpoint save game state after each level change, for possible [TRUE] recovery after program crash Boolean option if NEWS was set at compile time: news print any news from game administrator on startup [TRUE] Boolean option if MFLOPPY was set at compile time: checkspace check free disk space before writing files to disk [TRUE] Boolean option if EXP_ON_BOTL was set at compile time: showexp display your accumulated experience points [FALSE] Boolean option if SCORE_ON_BOTL was set at compile time: showscore display your approximate accumulated score [FALSE] Boolean options if TEXTCOLOR was set at compile time: color use different colors for objects on screen [TRUE for micros] hilite_pet display pets in a highlighted manner [FALSE] Boolean option if TIMED_DELAY was set at compile time (tty interface only): timed_delay on unix and VMS, use a timer instead of sending extra screen output when attempting to pause for display effect. on MSDOS without the termcap lib, whether or not to pause for visual effect. [TRUE] Boolean option if USE_TILES was set at compile time (MSDOS protected mode only): preload_tiles control whether tiles get pre-loaded into RAM at the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. [TRUE] Any Boolean option can be negated by prefixing it with a '!' or 'no'. Compound options are written as option_name:option_value. Compound options which can be set during the game are: boulder override the default boulder symbol with another default: [`] disclose the types of information you want offered at the end of the game [ni na nv ng nc] fruit the name of a fruit you enjoy eating [slime mold] (basically a whimsy which NetHack uses from time to time). menustyle user interface for selection of multiple objects: Traditional -- one object at a time prompting; Combination -- prompt for classes of interest, then menu; Partial -- skip class prompt, use menu of all objects; Full -- menu for classes of interest, then object menu; only the first letter ('T','C','P','F') matters; 'N' (None) is a synonym for 'T', as is boolean style negation [Full] packorder a list of default symbols for kinds of objects that gives the order in which your pack will be displayed [")[%?+!=/(*`0_] (If you specify only some kinds of items, the others from the default order will be appended to the end.) pickup_burden when you pick up an item that exceeds this encumberance level (Unburdened, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. [S] pickup_types a list of default symbols for kinds of objects to autopickup when that option is on [all] runmode controls how often the map window is updated when performing multi-step movement (various running modes or travel command): teleport -- don't update map until movement stops; run -- periodically update map (interval is seven steps); walk -- update map after every step; crawl -- like walk, but delay after making each step. (This only affects screen display, not actual movement.) [run] scores the parts of the score list you wish to see when the game ends You choose a combination of top scores, scores around the top scores, and all of your own scores. [!own/3 top/2 around] suppress_alert disable various version-specific warnings about changes in game play or the user interface, such as notification given for the 'Q' command that quitting is now done via #quit (e.g., use suppress_alert:3.3.1 to stop that and any other notifications added in that version or earlier) default: [(none)] Compound options which may be set only on startup are: align Your starting alignment (align:lawful, align:neutral, or align:chaotic). You may specify just the first letter. [RANDOM] catname the name of your first cat [NONE] dogname the name of your first dog [NONE] dungeon a list of symbols to be used in place of the default ones for drawing the dungeon. The symbols are subjected to a fair amount of processing, so that you can use C-style escapes such as \n or \081 as well as indicate control characters by ^x or meta characters by \Mx. As usual, \ can force the next character to be taken literally. Since many of the default symbols are overloaded, they are given here by name instead of symbol, with some added notes: stone (solid rock, normally ' ') vwall hwall tlcorn trcorn blcorn brcorn (room boundaries) crwall tuwall tdwall tlwall trwall (wallified maze characters) nodoor vodoor hodoor (no, vertical, horizontal open door) vcdoor hcdoor (vertical, horizontal closed door) ironbars tree room darkcorr litcorr upstair dnstair upladder dnladder altar grave throne sink fountain pool ice lava vodbridge hodbridge (vertical, horizontal open drawbridge) vcdbridge hcdbridge (vertical, horizontal closed drawbridge) air cloud water default: \ |--------||.-|++##.##<><>_\\#{}.}..##\ #} effects like dungeon, but for special effects symbols vbeam hbeam lslant rslant (generic zap beams) digbeam flashbeam (special beams for digging and cameras) boomleft boomright (boomerangs) ss1 ss2 ss3 ss4 (shielding sequence) sw_topl, sw_topm, sw_topr, (swallow, top row) sw_midl, sw_midr, (swallow, middle row [no center]) sw_botl, sw_botm, sw_botr (swallow, bottom row) extl extm extr (explosion matrix top row) exml exmm exmr (explosion matrix middle row) exbl exbm exbr (explosion matrix bottom row) default: |-\\/*!)(0#@*/-\\||\\-//-\\|\ |\\-/ gender Your starting gender (gender:male or gender:female). You may specify just the first letter. Although you can still denote your gender using the "male" and "female" options, the "gender" option will take precedence. [RANDOM] horsename the name of your first horse [NONE] menu_* create single character accelerators for menu commands. Below is a list of all commands. Each is followed by a list of window- ports that implement them: 'x' is X11, 't' is tty, 'g' is Gem, 'a' is Amiga. menu_deselect_all deselect all items in a menu [-](gxta) menu_deselect_page deselect all items on this page of a menu [\](gta) menu_first_page jump to the first page in a menu [^](gta) menu_invert_all invert all items in a menu [@](gxta) menu_invert_page invert all items on this page of a menu [~](gta) menu_last_page jump to the last page in a menu [|](gta) menu_next_page goto the next menu page [>](gta) menu_previous_page goto the previous menu page [<](gta) menu_search search for a menu item [:](gxa) menu_select_all select all items in a menu [.](gxta) menu_select_page select all items on this page of a menu [,](gta) monsters like dungeon, but for monster symbols default: abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ@\ \\&;:~] msghistory number of top line messages to save [20] name the name of your character [obtained by asking the system or the player] objects like dungeon, but for object symbols default: ])[="(%!?+/$*`0_. pettype your preferred type of pet (cat or dog), if your character class uses both types; or none for no pet [RANDOM] race Your starting race (e.g., race:Human, race:Elf). [RANDOM] role Your starting role (e.g., role:Barbarian, role:Valk). Although you can specify just the first letter(s), it will choose only the first role it finds that matches; thus, it is recommended that you spell out as much of the role name as possible. You can also still denote your role by appending it to the "name" option (e.g., name:Vic-V), but the "role" option will take precedence. [RANDOM] traps like dungeon, but for trap symbols arrow_trap dart_trap falling_rock_trap squeaky_board bear_trap land_mine rolling_boulder_trap sleeping_gas_trap rust_trap fire_trap pit spiked_pit hole trap_door teleportation_trap level_teleporter magic_portal web statue_trap magic_trap anti_magic_trap polymorph_trap default: ^^^^^^^^^^^^^^^^^"^^^^ windowtype windowing system to be used [depends on operating system] Compound option if TTY_GRAPHICS was set at compile time: msg_window the type of message window to use: single -- One message at a time full -- Full window with all saved top line messages reverse -- Same as full, but messages printed most-recent-first combination -- Two single messages, then as full default: single Some sample options lists are: !autopickup,!tombstone,name:Gandalf,scores:own/3 top/2 around female,nonews,dogname:Rover,dungeon: |--------||.-|++.##<><>_\\#{}.}..## #} rest_on_space,!verbose,menustyle:traditional nethack-3.4.3/dat/oracle.des0100644000000000000000000000301607764735041014364 0ustar rootroot# SCCS Id: @(#)oracle.des 3.4 1995/10/07 # NetHack may be freely redistributed. See license for details. # # Oracle level # LEVEL: "oracle" ROOM: "ordinary" , lit, (3,3), (center,center), (11,9) NAME: "central" OBJECT:'`',"statue",(0,0),"forest centaur",1 OBJECT:'`',"statue",(0,8),"mountain centaur",1 OBJECT:'`',"statue",(10,0),"mountain centaur",1 OBJECT:'`',"statue",(10,8),"forest centaur",1 OBJECT:'`',"statue",(5,1),"plains centaur",1 OBJECT:'`',"statue",(5,7),"plains centaur",1 OBJECT:'`',"statue",(2,4),"plains centaur",1 OBJECT:'`',"statue",(8,4),"plains centaur",1 MONSTER: random, random, random MONSTER: random, random, random SUBROOM: "delphi" , lit , (4,3) , (3,3), "central" FOUNTAIN: (0, 1) FOUNTAIN: (1, 0) FOUNTAIN: (1, 2) FOUNTAIN: (2, 1) MONSTER: '@', "Oracle", (1,1) DOOR: false , nodoor , random, random ROOM: "ordinary" , random, random, random, random STAIR: random, up OBJECT: random,random,random ROOM: "ordinary" , random, random, random, random STAIR: random, down OBJECT: random, random, random TRAP: random, random MONSTER: random, random, random MONSTER: random, random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random OBJECT: random, random, random MONSTER: random, random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: random, random, random ROOM: "ordinary" , random, random, random, random OBJECT: random, random, random TRAP: random, random MONSTER: random, random, random RANDOM_CORRIDORS nethack-3.4.3/dat/oracles.txt0100644000000000000000000001241307764735041014614 0ustar rootroot----- If thy wand hath run out of charges, thou mayst zap it again and again; though naught will happen at first, verily, thy persistence shall be rewarded, as one last charge may yet be wrested from it! ----- Though the shopkeepers be wary, thieves have nevertheless stolen much by using their digging wands to hasten exits through the pavement. ----- If thou hast had trouble with rust on thine armor or weapons, thou shouldst know that thou canst prevent this by, while in a confused state, reading the magical parchments which normally are used to cause their enchantment. Unguents of lubrication may provide similar protection, albeit of a transitory nature. ----- Behold the cockatrice, whose diminutive stature belies its hidden might. The cockatrice can petrify any ordinary being it contacts--save those wise adventurers who eat a dead lizard or blob of acid when they feel themselves slowly turning to stone. ----- While some wayfarers rely on scrounging finished armour in the dungeon, the resourceful know the mystical means by which mail may be fashioned out of scales from a dragon's hide. ----- It is customarily known among travelers that extra-healing draughts may clear thy senses when thou art addled by delusory visions. But never forget, the lowly potion which makes one sick may be used for the same purpose. ----- While the consumption of lizard flesh or water beloved of the gods may clear the muddled head, the application of the horn of a creature of utmost purity can alleviate many other afflictions as well. ----- If thou wouldst travel quickly between distant locations, thou must be able to control thy teleports, and in a confused state misread the scroll which usually teleports thyself locally. Daring adventurers have also performed the same feat sans need for scrolls or potions by stepping into a particular ambuscade. ----- Almost all adventurers who come this way hope to pass the dread Medusa. To do this, the best advice is to keep thine eyes blindfolded and to cause the creature to espy its own reflection in a mirror. ----- And where it is written "ad aerarium", diligent searching will often reveal the way to a trap which sends one to the Magic Memory Vault, where the riches of Croesus are stored; however, escaping from the vault with its gold is much harder than getting in. ----- It is well known that wily shopkeepers raise their prices whene'er they espy the garish apparel of the approaching tourist or the countenance of a disfavored patron. They favor the gentle of manner and the fair of face. The boor may expect unprofitable transactions. ----- SINKS The cliche of the kitchen sink swallowing any unfortunate rings that contact its pernicious surface reflecteth greater truth than many homilies, yet even so, few have developed the skill to identify enchanted rings by the transfigurations effected upon the voracious device's frame. ----- The meat of enchanted creatures ofttimes conveyeth magical properties unto the consumer. A fresh corpse of floating eye doth fetch a high price among wizards for its utility in conferring Telepathy, by which the sightless may locate surrounding minds. ----- The detection of blessings and curses is in the domain of the gods. They will make this information available to mortals who request it at their places of worship, or elsewhere for those mortals who devote themselves to the service of the gods. ----- At times, the gods may favor worthy supplicants with named blades whose powers echo throughout legend. Learned wayfarers can reproduce blades of elven lineage, hated of the orcs, without the need for such intervention. ----- There are many stories of a mighty amulet, the origins of which are said to be ancient Yendor. This amulet doth have awesome power, and the gods desire it greatly. Mortals mayst tap only portions of its terrible abilities. The stories tell of mortals seeing what their eyes cannot see and seeking places of magical transportation, while having this amulet in their possession. Others say a mortal must wear the amulet to obtain these powers. But verily, such power comes at great cost, to preserve the balance. ----- It is said that thou mayst gain entry to Moloch's sanctuary, if thou darest, from a place where the ground vibrateth in the deepest depths of Gehennom. Thou needs must have the aid of three magical items. The pure sound of a silver bell shall announce thee. The terrible runes, read from Moloch's book, shall cause the earth to tremble mightily. The light of an enchanted candelabrum shall show thee the way. ----- In the deepest recesses of the Dungeons of Doom, guarding access to the nether regions, there standeth a castle, wherein lieth a wand of wishes. If thou wouldst gain entry, bear with thee an instrument of music, for the pontlevis may be charmed down with the proper melody. What notes comprise it only the gods know, but a musical mastermind may yet succeed by witful improvisation. However, the less perspicacious are not without recourse, should they be prepared to circumambulate the castle to the postern. ----- ELBERETH The name of Elbereth may strike fear into the hearts of thine enemies, if thou dost write it upon the ground at thy feet. If thou maintainest the utmost calm, thy safety will be aided greatly, but beware lest thy clumsy feet scuff the inscription, cancelling its potence. ----- nethack-3.4.3/dat/quest.txt0100644000000000000000000030243607764735041014334 0ustar rootroot# SCCS Id: @(#)quest.txt 3.4 2002/01/30 # Copyright (c) 1991 by M. Stephenson # NetHack may be freely redistributed. See license for details. # # The quest text file for NetHack 3.4 # # These are the "standard" message numbers from qtext.h. All class # dialogue must have at least these entries. # # QT_FIRSTTIME 1 # QT_NEXTTIME 2 # QT_OTHERTIME 3 # # QT_GUARDTALK 5 /* 5 random things guards say before quest */ # QT_GUARDTALK2 10 /* 5 random things guards say after quest */ # # QT_FIRSTLEADER 15 # QT_NEXTLEADER 16 # QT_OTHERLEADER 17 # QT_LASTLEADER 18 # QT_BADLEVEL 19 # QT_BADALIGN 20 # QT_ASSIGNQUEST 21 # # QT_ENCOURAGE 25 /* 1-10 random encouragement messages */ # # QT_FIRSTLOCATE 35 # QT_NEXTLOCATE 36 # # QT_FIRSTACQUIRE 40 # QT_NEXTACQUIRE 41 # # QT_FIRSTNEMESIS 50 # QT_NEXTNEMESIS 51 # QT_OTHERNEMESIS 52 # QT_NEMWANTSIT 53 /* you somehow got the artifact */ # # QT_DISCOURAGE 60 /* 1-10 random maledictive messages */ # # QT_GOTIT 70 # # QT_KILLEDNEM 80 # QT_OFFEREDIT 81 # QT_OFFEREDIT2 82 /* if you throw artifact to leader after #81 */ # # QT_POSTHANKS 90 # QT_HASAMULET 91 # # # Archeologist # %Cc Arc 00001 You are suddenly in familiar surroundings. The buildings in the distance appear to be those of your old alma mater, but something is wrong. It looks as if there has been a riot recently, or %H has been under siege. All of the windows are boarded up, and there are objects scattered around the entrance. Strange forbidding shapes seem to be moving in the distance. %E %Cp Arc 00002 Once again, you are back at %H. %E %Cp Arc 00003 You are back at %H. You have an odd feeling this may be the last time you ever come here. %E %Cp Arc 00005 "Did you see Lash LaRue in 'Song of Old Wyoming' the other night?" %E %Cp Arc 00006 "Hey man, got any potions of hallucination for sale?" %E %Cp Arc 00007 "Did you see the artifact %l brought back from the last dig?" %E %Cp Arc 00008 "So what species do *you* think we evolved from?" %E %Cp Arc 00009 "So you're %ls prize pupil! I don't know what he sees in you." %E %Cp Arc 00010 "Did you see Lash LaRue in 'Song of Old Wyoming' the other night?" %E %Cp Arc 00011 "Hey man, got any potions of hallucination for sale?" %E %Cp Arc 00012 "I guess you are guaranteed to make full professor now." %E %Cp Arc 00013 "So, what was worse, %n or your entrance exams?" %E %Cp Arc 00014 "%oC is impressive, but nothing like the bones I dug up!" %E %Cc Arc 00015 "Finally you have returned, %p. You were always my most promising student. Allow me to see if you are ready for the most difficult task of your career." %E %Cp Arc 00016 "Again, %p, you stand before me. Let me see if you have gained experience in the interim." %E %Cp Arc 00017 "Once more, %p, you have returned from the field. Are you finally ready for the task that must be accomplished?" %E %Cc Arc 00018 "%p, you have failed us. All of my careful training has been in vain. Begone! Your tenure at this college has been revoked! "You are a disgrace to the profession!" %E %Cc Arc 00019 "%p, you are yet too inexperienced to undertake such a demanding quest. A mere %r could not possibly face the rigors demanded and survive. Go forth, and come here again when your adventures have further taught you." %E %Cc Arc 00020 "%pC! I've heard that you've been using sloppy techniques. Your results lately can hardly be called suitable for %ra! "How could you have strayed from the %a path? Go from here, and come back only when you have purified yourself." %E %Cc Arc 00021 "Grave times have befallen the college, for %na has stolen %o. Without it, the board of directors of the university will soon have no choice but to revoke our research grants. "You must locate the entrance to %i. Within it, you will find %n. "You must then defeat %n and return %o to me. "Only in this way will we be able to prevent the budget cuts that could close this college. "May the wisdom of %d be your guide." %E %Cp Arc 00025 "Beware, for %n is powerful and cunning." %E %Cp Arc 00026 "To locate the entrance to %i, you must pass many traps." %E %Cp Arc 00027 "A %nt may be vulnerable to attacks by magical cold." %E %Cp Arc 00028 "Call upon %d when you encounter %n." %E %Cp Arc 00029 "You must destroy %n. It will pursue you otherwise." %E %Cp Arc 00030 "%oC is a mighty talisman. With it you can destroy %n." %E %Cp Arc 00031 "Go forth with the blessings of %d." %E %Cp Arc 00032 "I will have my %gP watch for your return." %E %Cp Arc 00033 "Remember not to stray from the true %a path." %E %Cp Arc 00034 "You may be able to sense %o when you are near." %E %Cc Arc 00035 A plain opens before you. Beyond the plain lies a foreboding edifice. You have the feeling that you will soon find the entrance to %i. %E %Cp Arc 00036 Once again, you are near the entrance to %i. %E %Cc Arc 00040 A strange feeling washes over you, and you think back to things you learned during the many lectures of %l. You realize the feeling must be the presence of %o. %E %Cp Arc 00041 The familiar presence of %o is in the ether. %E %Cc Arc 00050 "So, %p, you think that you can succeed in recovering %o, when your teacher, %l, has already failed. "Come, try your best! I shall destroy you, and gnaw on your bones." %E %Cc Arc 00051 "Again you try to best me, eh %p? Well, you shall fail again. "You shall never recover %o. "I shall bear your soul to the Plane of Origins for my master's pleasure." %E %Cp Arc 00052 "You persist yet %p! Good. Now, you shall die!" %E %Cp Arc 00053 "I shall have %o from you, %p, then feast upon your entrails!" %E %Cp Arc 00060 "Try your best, %p. You cannot defeat me." %E %Cp Arc 00061 "I shall rend the flesh from your body whilst you still breathe!" %E %Cp Arc 00062 "First you, %p, then I shall destroy your mentor, %l." %E %Cp Arc 00063 "Tiring yet, %p? I draw my power from my master and cannot falter!" %E %Cp Arc 00064 "I shall rend thy soul from thy body and consume it!" %E %Cp Arc 00065 "You are far too %a -- it weakens you. You shall die in this place." %E %Cp Arc 00066 "%d has forsaken you! You are lost now!" %E %Cp Arc 00067 "A mere %r cannot hope to defeat me!" %E %Cp Arc 00068 "If you are the best %l can send, I have nothing to fear." %E %Cp Arc 00069 "Die %c! I shall exhibit your carcass as a trophy." %E %Cc Arc 00070 The power of %o flows through your body! You feel as if you could now take on the Wizard of Yendor himself and win, but you know you must return %o to %l. %E %Cp Arc 00080 The body of %n dissipates in a cloud of noxious fumes. %E %Cc Arc 00081 %lC touches %o briefly, gazes into it, then smiles at you and says: "Well done, %p. You have defeated %n and recovered %o. But I fear that it shall never be safe here. Please take %o with you. You, %p, can guard it now far better than I. May the blessings of %d follow you and guard you." %E # assumes Orb of Detection (glass object) %Cc Arc 00082 "Careful, %p! %oC might break, and that would be a tragic loss. You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E %Cc Arc 00090 "Welcome back, %p. Have you progressed with your quest to regain the Amulet of Yendor for %d?" %E %Cc Arc 00091 "Congratulations, %p. I wondered if anyone could prevail against the Wizard and the minions of Moloch. Now, you must embark on one final adventure. "Take the Amulet, and find your way onto the astral plane. There you must find the altar of %d and sacrifice the Amulet on that altar to fulfill your destiny. "Remember, your path now should always be upwards." %E # # Barbarian # %Cc Bar 00001 Warily you scan your surroundings, all of your senses alert for signs of possible danger. Off in the distance, you can %x the familiar shapes of %H. But why, you think, should %l be there? Suddenly, the hairs on your neck stand on end as you detect the aura of evil magic in the air. Without thought, you ready your weapon, and mutter under your breath: "By %d, there will be blood spilt today." %E %Cp Bar 00002 Once again, you near %H. You know that %l will be waiting. %E %Cp Bar 00003 Again, and you think possibly for the last time, you approach %H. %E %Cp Bar 00005 "The battles here have been good -- our enemies' blood soaks the soil!" %E %Cp Bar 00006 "Remember that glory is crushing your enemies beneath your feet!" %E %Cp Bar 00007 "There has been little treasure to loot, since the horde arrived." %E %Cp Bar 00008 "The horde is mighty in numbers, but they have little courage." %E %Cp Bar 00009 "%lC is a strange one, but he has helped defend us." %E %Cp Bar 00010 "The battles here have been good -- our enemies' blood soaks the soil!" %E %Cp Bar 00011 "Remember that glory is crushing your enemies beneath your feet!" %E %Cp Bar 00012 "Times will be good again, now that the horde is vanquished." %E %Cp Bar 00013 "You have brought our clan much honor in defeating %n." %E %Cp Bar 00014 "You will be a worthy successor to %l." %E %Cc Bar 00015 "Ah, %p. You have returned at last. The world is in dire need of your help. There is a great quest you must undertake. "But first, I must see if you are ready to take on such a challenge." %E %Cp Bar 00016 "%p, you are back. Are you ready now for the challenge?" %E %Cp Bar 00017 "Again, you stand before me, %p. Surely you have prepared yourself." %E %Cc Bar 00018 "Pah! You have betrayed the gods, %p. You will never attain the glory which you aspire to. Your failure to follow the true path has closed this future to you. "I will protect these people as best I can, but soon %n will overcome me and destroy all who once called you %s. Now begone!" %E %Cc Bar 00019 "%p, I fear that you are as yet too inexperienced to face %n. Only %Ra with the help of %d could ever hope to defeat him." %E %Cc Bar 00020 "%pC! You have wandered from the path of the %a! If you attempt to overcome %n in this state, he will surely enslave your soul. Your only hope, and ours, lies in your purification. Go forth, and return when you feel ready." %E %Cc Bar 00021 "The world is in great need of your assistance, %p. "About six months ago, I learned that a mysterious sorcerer, known as %n, had begun to gather a large group of cutthroats and brigands about him. "At about the same time, these people you once rode with `liberated' a potent magical talisman, %o, from a Turanian caravan. "%nC and his Black Horde swept down upon %i and defeated the people there, driving them out into the desert. He has taken %o, and seeks to bend it to his will. I detected the subtle changes in the currents of fate, and joined these people. Then I sent forth a summons for you. "If %n can bend %o to his will, he will become almost indestructible. He will then be able to enslave the minds of men across the world. You are the only hope. The gods smile upon you, and with %d behind you, you alone can defeat %n. "You must go to %i. From there, you can track down %n, defeat him, and return %o to us. Only then will the world be safe." %E %Cp Bar 00025 "%nC is strong in the dark arts, but not immune to cold steel." %E %Cp Bar 00026 "Remember that %n is a great sorcerer. He lived in the time of Atlantis." %E %Cp Bar 00027 "If you fail, %p, I will not be able to protect these people long." %E %Cp Bar 00028 "To enter %i, you must be very stealthy. The horde will be on guard." %E %Cp Bar 00029 "Call upon %d in your time of need." %E %Cp Bar 00030 "May %d protect you, and guide your steps." %E %Cp Bar 00031 "If you can lay hands upon %o, carry it for good fortune." %E %Cp Bar 00032 "I cannot stand against %ns sorcery. But %d will help you." %E %Cp Bar 00033 "Do not fear %n. I know you can defeat him." %E %Cp Bar 00034 "You have a great road to travel, %p, but only after you defeat %n." %E %Cc Bar 00035 The scent of water comes to you in the desert breeze. You know that you have located %i. %E %Cp Bar 00036 Yet again you have a chance to infiltrate %i. %E %Cc Bar 00040 The hairs on the nape of your neck lift as you sense an energy in the very air around you. You fight down a primordial panic that seeks to make you turn and run. This is surely the lair of %n. %E %Cp Bar 00041 Yet again you feel the air around you heavy with malevolent magical energy. %E %Cc Bar 00050 "So. This is what that second rate sorcerer %l sends to do his bidding. I have slain many before you. You shall give me little sport. "Prepare to die, %c." %E %Cp Bar 00051 "I have wasted too much time on you already. Now, you shall die." %E %Cp Bar 00052 "You return yet again, %c! Are you prepared for death now?" %E %Cp Bar 00053 "I shall have %o back, you pitiful excuse for %ca. And your life as well." %E %Cp Bar 00060 "My pets will dine on your carcass tonight!" %E %Cp Bar 00061 "You are a sorry excuse for %ra." %E %Cp Bar 00062 "Run while you can, %c. My next spell will be your last." %E %Cp Bar 00063 "I shall use your very skin to bind my next grimoire." %E %Cp Bar 00064 "%d cannot protect you now. Here, you die." %E %Cp Bar 00065 "Your %a nature makes you weak. You cannot defeat me." %E %Cp Bar 00066 "Come, %c. I shall kill you, then unleash the horde on your tribe." %E %Cp Bar 00067 "Once you are dead, my horde shall finish off %l, and your tribe." %E %Cp Bar 00068 "Fight, %c, or are you afraid of the mighty %n?" %E %Cp Bar 00069 "You have failed, %c. Now, my victory is complete." %E %Cc Bar 00070 As you pick up %o, you feel the power of it flowing through your hands. It seems to be in two or more places at once, even though you are holding it. %E %Cc Bar 00080 %nC falls to the ground, and utters a last curse at you. Then his body fades slowly, seemingly dispersing into the air around you. You slowly become aware that the overpowering aura of magic in the air has begun to fade. %E %Cc Bar 00081 When %l sees %o, he smiles, and says: Well done, %p. You have saved the world from certain doom. What, now, should be done with %o? These people, brave as they are, cannot hope to guard it from other sorcerers who will detect it, as surely as %n did. Take %o with you, %p. It will guard you in your adventures, and you can best guard it. You embark on a quest far greater than you realize. Remember me, %p, and return when you have triumphed. I will tell you then of what you must do. You will understand when the time comes. %E %Cc Bar 00082 %l gazes reverently at %o, then back at you. "You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal which brought you here." %E %Cp Bar 00090 "Tell us, %p, have you fared well on your great quest?" %E %Cc Bar 00091 "This is wondrous, %p. I feared that you could not possibly succeed in your quest, but here you are in possession of the Amulet of Yendor! "I have studied the texts of the magi constantly since you left. In the Book of Skelos, I found this: %d will cause a child to be sent into the world. This child is to be made strong by trial of battle and magic, for %d has willed it so. It is said that the child of %d will recover the Amulet of Yendor that was stolen from the Creator at the beginning of time. "As you now possess the amulet, %p, I suspect that the Book speaks of you. The child of %d will take the Amulet, and travel to the Astral Plane, where the Great Temple of %d is to be found. The Amulet will be sacrificed to %d, there on His altar. Then the child will stand by %d as champion of all %cP for eternity. "This is all I know, %p. I hope it will help you." %E # # Cave(wo)man # %Cc Cav 00001 You descend through a barely familiar stairwell that you remember %l showing you when you embarked upon your vision quest. You arrive back at %H, but something seems wrong here. The usual smoke and glowing light of the fires of the outer caves are absent, and an uneasy quiet fills the damp air. %E %Cp Cav 00002 Once again, you arrive back at %H. %E %Cp Cav 00003 For some reason, you think that this may be the last time you will enter %H. %E %Cp Cav 00005 "We have not been able to gather as much food since the Giants sealed off our access to the outer world." %E %Cp Cav 00006 "Since %n sent her minions, we have been constantly fighting." %E %Cp Cav 00007 "I have heard your vision quest was successful. Is this so?" %E %Cp Cav 00008 "So, tell me, %p, how have you fared?" %E %Cp Cav 00009 "%lC grows old. We know not who will guide us after he ascends." %E %Cp Cav 00010 "The rains have returned and the land grows lush again." %E %Cp Cav 00011 "Peace has returned, give thanks to %d!" %E %Cp Cav 00012 "Welcome back! Did you find %o?" %E %Cp Cav 00013 "So, %p, tell us the story of your fight with %n." %E %Cp Cav 00014 "%lC grows old. Perhaps you will guide us after he ascends." %E %Cc Cav 00015 "You have returned from your vision quest, %p. Thank %d. "We are in dire need of your help, my %S. "But first, I must see if you are yet capable of the quest I would ask you to undertake." %E %Cp Cav 00016 "Again, you return to us, %p. Let me see if you are ready now." %E %Cp Cav 00017 "Ah, %p. Are you finally ready?" %E %Cc Cav 00018 "%pC! You have sealed our fate. You seem unable to reform yourself, so I must select another to take your place. "Begone from %H! You have betrayed us by choosing the path of the %C over the true path of the %L. "You no longer live in our eyes." %E %Cc Cav 00019 "Alas, %p, you are as yet too inexperienced to embark upon such a difficult quest as that I propose to give you. "%rA could not possibly survive the rigors demanded to find %i, never mind to confront %n herself. "Adventure some more, and you will learn the skills you will require. %d decrees it." %E %Cc Cav 00020 "%pC! You have deviated from my teachings. You no longer follow the path of the %a as you should. I banish you from these caves, to go forth and purify yourself. Then, you might be able to accomplish this quest." %E %Cc Cav 00021 "You are indeed ready now, %p. I shall tell you a tale of great suffering among your people: "Shortly after you left on your vision quest, the caves were invaded by the creatures sent against us by %n. "She, herself, could not attack us due to her great size, but her minions have harassed us ever since. In the first attacks, many died, and the minions of %n managed to steal %o. They took it to %i and there, none of our %g warriors have been able to go. "You must find %i, and within it wrest %o from %n. She guards it as jealously as she guards all treasures she attains. But with it, we can make our caves safe once more. "Please, %p, recover %o for us, and return it here." %E %Cp Cav 00025 "%nC is immune to her own breath weapons. You should use magic upon her that she does not use herself." %E %Cp Cav 00026 "When you encounter %n, call upon %d for assistance." %E %Cp Cav 00027 "There will be nowhere to hide inside %ns inner sanctum." %E %Cp Cav 00028 "Your best chance with %n will be to keep moving." %E %Cp Cav 00029 "Do not be distracted by the great treasures in %ns lair. Concentrate on %o." %E %Cp Cav 00030 "%oC is the only object that %n truly fears." %E %Cp Cav 00031 "Do not be fooled by %ns size. She is fast, and it is rumored that she uses magic." %E %Cp Cav 00032 "I would send a party of %gP with you, but we will need all of our strength to defend ourselves." %E %Cp Cav 00033 "Remember, be %a at all times. This is your strength." %E %Cp Cav 00034 "If only we had an amulet of reflection, this would not have happened." %E %Cc Cav 00035 You %x many large claw marks on the ground. The tunnels ahead of you are larger than most of those in any cave complex you have ever been in before. Your nose detects the smell of carrion from within, and bones litter the sides of the tunnels. %E %Cp Cav 00036 Once again, you approach %i. %E %Cc Cav 00040 You find yourself in a large cavern, with neatly polished walls, that nevertheless show signs of being scorched by fire. Bones litter the floor, and there are objects scattered everywhere. The air is close with the stench of sulphurous fumes. %nC is clearly visible, but she seems to be asleep. %E %Cp Cav 00041 Once again, you find yourself in the lair of %n. %E %Cc Cav 00050 "So, follower of %l, you seek to invade the lair of %n. Only my meals are allowed down here. Prepare to be eaten!" %E %Cp Cav 00051 "So, again you face me, %c. No one has ever before escaped me. Now I shall kill you." %E %Cp Cav 00052 "You are getting annoying, %c. Prepare to die." %E %Cp Cav 00053 "I'll have %o from you, %c. You shall die." %E %Cp Cav 00060 "You are weak, %c. No challenge for the Mother of all Dragons." %E %Cp Cav 00061 "I grow hungry, %r. You look like a nice appetizer!" %E %Cp Cav 00062 "Join me for lunch? You're the main course, %c." %E %Cp Cav 00063 "With %o, I am invincible! You cannot succeed." %E %Cp Cav 00064 "Your mentor, %l has failed. You are nothing to fear." %E %Cp Cav 00065 "You shall die here, %c. %rA cannot hope to defeat me." %E %Cp Cav 00066 "You, a mere %r challenge the might of %n? Hah!" %E %Cp Cav 00067 "I am the Mother of all Dragons! You cannot hope to defeat me." %E %Cp Cav 00068 "My claws are sharp now. I shall rip you to shreds!" %E %Cp Cav 00069 "%d has deserted you, %c. This is my domain." %E %Cc Cav 00070 As you pick up %o it seems heavy at first, but as you hold it strength flows into your arms. You suddenly feel full of power, as if nothing could possibly stand in your path. %E %Cp Cav 00080 %nC sinks to the ground, her heads flailing about. As she dies, a cloud of noxious fumes billows about her. %E %Cc Cav 00081 %lC glimpses %o in your possession. He smiles and says: You have done it! We are saved. But I fear that %o will always be a target for %C forces who will want it for their own. To prevent further trouble, I would like you, %p, to take %o away with you. It will help you as you quest for the Amulet of Yendor. %E %Cc Cav 00082 %l grasps %o proudly for a moment, then looks at you. "You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal which brought you here." %E %Cp Cav 00090 "%pC! Welcome back. How goes your quest to recover the Amulet for %d?" %E %Cc Cav 00091 "You have been successful, I see, %p. "Now that the Amulet of Yendor is yours, here is what you must do: "Journey upwards to the open air. The Amulet you carry will then take you into the Astral Planes, where the Great Temple of %d casts its influence throughout our world. "Sacrifice the Amulet on the altar. Thus shall %d become supreme!" %E # # Healer # %Cc Hea 00001 What sorcery has brought you back to %H? The smell of fresh funeral pyres tells you that something is amiss with the healing powers that used to practice here. No rhizotomists are tending the materia medica gardens, and where are the common folk who used to come for the cures? You know that you must quickly make your way to the collegium, and %ls iatreion, and find out what has happened in your absence. %E %Cp Hea 00002 After your last experience you expected to be here, but you certainly did not expect to see things so much worse. This time you must succeed. %E %Cp Hea 00003 Again, you %x %H in the distance. The smell of death and disease permeates the air. You do not have to be %Ra to know that %n is on the verge of victory. %E %Cp Hea 00005 "Did you read that new treatise on the therapeutic use of leeches?" %E %Cp Hea 00006 "Paint a red caduceus on your shield and monsters won't hit you." %E %Cp Hea 00007 "I passed handwriting so they are demoting me a rank." %E %Cp Hea 00008 "I've heard that even %l has not been able to cure Chiron." %E %Cp Hea 00009 "We think %n has used his alchemists, and %o, to unleash a new disease we call 'the cold' on Gehennom." %E %Cp Hea 00010 "Did you read that new treatise on the therapeutic use of leeches?" %E %Cp Hea 00011 "Paint a red caduceus on your shield and monsters won't hit you." %E %Cp Hea 00012 "How are you feeling? Perhaps a good bleeding will improve your sprits." %E %Cp Hea 00013 "Have you heard the absurd new theory that diseases are caused by microscopic organisms, and not ill humors?" %E %Cp Hea 00014 "I see that you bring %o, now you can cure this plague!" %E %Cc Hea 00015 Feebly, %l raises his head to look at you. "It is good to see you again, %p. I see the concern in your eyes, but do not worry for me. I am not ready for Hades yet. We have exhausted much of our healing powers holding off %n. I need your fresh strength to carry on our work. "Come closer and let me lay hands on you, and determine if you have the skills necessary to accomplish this mission." %E %Cp Hea 00016 "Again you return to me, %p. I sense that each trip back the pleurisy and maladies of our land begin to infect you. Let us hope and pray to %d that you become ready for your task before you fall victim to the bad humors." %E %Cp Hea 00017 "Chiron has fallen, Hermes has fallen, what else must I tell you to impress upon you the importance of your mission! I hope that you have come prepared this time." %E %Cc Hea 00018 "You have failed us, %p. You are a quack! A charlatan! "Hades will be happy to hear that you are once again practicing your arts on the unsuspecting." %E %Cc Hea 00019 "Alas, %p, you are yet too inexperienced to deal with the rigors of such a task. You must be able to draw on the knowledge of botany, vetenary, and alchemy before I can send you on this quest with good conscience. "Return when you wear %Ra's caduceus." %E %Cc Hea 00020 "You have learned much of the remedies that benefit, but you must also know which physic for which ail. That is why %ds teachings are a part of your training. "Return to us when you have healed thyself." %E %Cc Hea 00021 For the first time, you sense a smile on %ls face. You have indeed learned as much as we can teach you in preparation for this task. Let me tell you what I know of the symptoms and hope that you can provide a cure. A short while ago, the dreaded %nt was fooled by the gods into thinking that he could use %o to find a cure for old age. Think of it, eternal youth! But his good health is accomplished by drawing the health from those around him. He has exhausted his own supply of healthy people and now he seeks to extend his influence into our world. You must recover from him %o and break the spell. You must travel into the swamps to %i, and from there follow the trail to %ns island lair. Be careful. %E %Cp Hea 00025 "Remember, %p, to always wash your hands before operating." %E %Cp Hea 00026 "%nC has no real magic of his own. To this he is vulnerable." %E %Cp Hea 00027 "If you have been true to %d, you can draw on the power of %o." %E %Cp Hea 00028 "Bring with you antidotes for poisons." %E %Cp Hea 00029 "Remember this, %n can twist the powers of %o to hurt instead of heal." %E %Cp Hea 00030 "I have sent for Chiron, but I am afraid he will come too late." %E %Cp Hea 00031 "Maybe when you return the snakes will once again begin to shed." %E %Cp Hea 00032 "The plague grows worse as we speak. Hurry, %p!" %E %Cp Hea 00033 "Many times %n has caused trouble in these lands. It is time that he was eradicated like the diseases he has caused." %E %Cp Hea 00034 "With but one eye, %n should be easy to blind. Remember this." %E %Cc Hea 00035 You stand before the entrance to %i. Strange scratching noises come from within the building. The swampy ground around you seems to stink with disease. %E %Cp Hea 00036 Once again you stand at the entrance to %i. %E %Cc Hea 00040 You stand within sight of the infamous Isle of %n. Even the words of %l had not prepared you for this. Steeling yourself against the wails of the ill that pierce your ears, you hurry on your task. Maybe with %o you can heal them on your return, but not now. %E %Cp Hea 00041 Once again, you %x the Isle of %n in the distance. %E %Cc Hea 00050 "They have made a mistake in sending you, %p. "When I add your youth to mine, it will just make it easier for me to defeat %l." %E %Cp Hea 00051 "Unlike your patients, you seem to keep coming back, %p!" %E %Cp Hea 00052 "Which would you like, %p? Boils, pleurisy, convulsions?" %E %Cp Hea 00053 "I'll have %o back from you, %r. You are not going to live to escape this place." %E %Cp Hea 00060 "They might as well give scalpels to wizards as to let you try to use %o!" %E %Cp Hea 00061 "If I could strike %l, surrounded by his %gP, imagine what I can do to you here by yourself." %E %Cp Hea 00062 "I will put my %Rp to work making a physic out of your ashes." %E %Cp Hea 00063 "As we speak, Hades gathers your patients to join you." %E %Cp Hea 00064 "After I'm done with you, I'll destroy %l as well." %E %Cp Hea 00065 "You will have to kill me if you ever hope to leave this place." %E %Cp Hea 00066 "I will impale your head on my caduceus for all to see." %E %Cp Hea 00067 "There is no materia medica in your sack which will cure you of me!" %E %Cp Hea 00068 "Do not fight too hard, I want your soul strong, not weakened!" %E %Cp Hea 00069 "You should have stopped studying at vetenary." %E %Cc Hea 00070 As you pick up %o, you feel its healing begin to warm your soul. You curse Zeus for taking it from its rightful owner, but at least you hope that %l can put it to good use once again. %E %Cc Hea 00080 The battered body of %n slumps to the ground and gasps out one last curse: You have defeated me, %p, but I shall have my revenge. How, I shall not say, but this curse shall be like a cancer on you. With that %n dies. %E %Cc Hea 00081 As soon as %l sees %o he summons his %gP. Gently, %l reaches out and touches %o. He instructs each of the assembled to do the same. When everyone has finished he speaks to you. Now that we have been replenished we can defeat this plague. You must take %o with you and replenish the worlds you have been called upon to travel next. I wish you could ride Chiron to the end of your journey, but I need him to help me spread the cure. Go now and continue your journey. %E %Cc Hea 00082 %l cautiously handles %o while watching you. "You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal which brought you here." %E %Cp Hea 00090 "You have again returned to us, %p. We have done well in your absence, yes? How fare you upon your quest for the Amulet?" %E %Cc Hea 00091 "Ah, you have recovered the Amulet, %p. Well done! "Now, you should know that you must travel through the elemental planes to the astral, and there return the Amulet to %d. Go forth and may our prayers be as a wind upon your back." %E # # Knight # %Cc Kni 00001 You materialize in the shadows of %H. Immediately, you notice that something is wrong. The fields around the castle are trampled and withered, as if some great battle has been recently fought. Looking closer, you %x long gouges in the walls of %H. You know of only one creature that makes those kinds of marks... %E %Cp Kni 00002 Once again you stand in the shadows of %H. %E %Cp Kni 00003 Again, you stand before %H. You vaguely sense that this may be the last time you stand before %l. %E %Cp Kni 00005 "Hail, %p! Verily, thou lookest well." %E %Cp Kni 00006 "There is word, %p, that %n hath been sighted in the fens near %i." %E %Cp Kni 00007 "Thou art our only hope now, %p." %E %Cp Kni 00008 "Verily, %l could have no better champion, %p." %E %Cp Kni 00009 "Many brave %cP died when %n attacked." %E %Cp Kni 00010 "Hail, %p! Verily, thou lookest well." %E %Cp Kni 00011 "So, %p, didst thou find %n in the fens near %i?" %E %Cp Kni 00012 "Worthy %p, hast thou proven thy right purpose on the body of %n?" %E %Cp Kni 00013 "Verily, %l could have no better champion, %p." %E %Cp Kni 00014 "Hast thou indeed recovered %o?" %E %Cc Kni 00015 "Ah, %p. We see thou hast received Our summons. We are in dire need of thy prowess. But first, We must needs decide if thou art ready for this great undertaking." %E %Cp Kni 00016 "Welcome again, %p. We hope thou art ready now." %E %Cp Kni 00017 "Once again, thou standest before Us, %p. Art thou ready now?" %E %Cc Kni 00018 "Thou disgracest this noble court with thine impure presence. We have been lenient with thee, but no more. Thy name shall be spoken no more. We hereby strip thee of thy title, thy lands, and thy standing as %ca. Begone from Our sight!" %E %Cc Kni 00019 "Verily, %p, thou hast done well. That thou hast survived thus far is a credit to thy valor, but thou art yet unprepared for the demands required as Our Champion. %rA, no matter how pure, could never hope to defeat the foul %n. "Journey forth from this place, and hone thy skills. Return to Our presence when thou hast attained the noble title of %R." %E %Cc Kni 00020 "Thou dishonourest Us, %p! Thou hast strayed from the path of chivalry! Go from Our presence and do penance. Only when thou art again pure mayst thou return hence." %E %Cc Kni 00021 "Ah, %p. Thou art truly ready, as no %c before thee hath been. Hear now Our words: "As thou noticed as thou approached %H, a great battle hath been fought recently in these fields. Know thou that Merlin himself came to aid Us here as We battled the foul %n. In the midst of that battle, %n struck Merlin a great blow, felling him. Then, as Our forces were pressed back, %n stole %o. "We eventually turned the tide, but lost many %cP in doing so. Merlin was taken off by his apprentice, but hath not recovered. We have been told that so long as %n possesseth %o, Merlin will not regain his health. "We hereby charge thee with this most important of duties: "Go forth from this place, to the fens, and there thou wilt find %i. From there, thou must track down %n. Destroy the beast, and return to Us %o. Only then can We restore Merlin to health." %E %Cp Kni 00025 "Remember, %p, follow always the path of %d." %E %Cp Kni 00026 "Though %n is verily a mighty foe, We have confidence in thy victory." %E %Cp Kni 00027 "Beware, for %n hath surrounded himself with hordes of foul creatures." %E %Cp Kni 00028 "Great treasure, 'tis said, is hoarded in the lair of %n." %E %Cp Kni 00029 "If thou possessest %o, %p, %ns magic shall therewith be thwarted." %E %Cp Kni 00030 "The gates of %i are guarded by forces unseen, %p. Go carefully." %E %Cp Kni 00031 "Return %o to Us quickly, %p." %E %Cp Kni 00032 "Destroy %n, %p, else %H shall surely fall." %E %Cp Kni 00033 "Call upon %d when thou art in need." %E %Cp Kni 00034 "To find %i, thou must keep thy heart pure." %E %Cc Kni 00035 You stand at the foot of %i. Atop, you can %x a shrine. Strange energies seem to be focused here, and the hair on the back of your neck stands on end. %E %Cp Kni 00036 Again, you stand at the foot of %i. %E %Cc Kni 00040 As you exit the swamps, you %x before you a huge, gaping hole in the side of a hill. From within, you smell the foul stench of carrion. The pools on either side of the entrance are fouled with blood, and pieces of rusted metal and broken weapons show above the surface. %E %Cp Kni 00041 Again, you stand at the entrance to %ns lair. %E %Cc Kni 00050 "Hah! Another puny %c seeks death. I shall dine well tonight, then tomorrow, %H shall fall!" %E %Cp Kni 00051 "Again, thou challengest me, %r? So be it. Thou wilt die here." %E %Cp Kni 00052 "Thou art truly foolish, %r. I shall dispatch thee anon." %E %Cp Kni 00053 "So, thou darest touch MY property! I shall have that bauble back, puny %r. Thou wilt die in agony!" %E %Cp Kni 00060 "A mere %r can never withstand me!" %E %Cp Kni 00061 "I shall kill thee now, and feast!" %E %Cp Kni 00062 "Puny %c. What manner of death dost thou wish?" %E %Cp Kni 00063 "First thee, %p, then I shall feast upon %l." %E %Cp Kni 00064 "Hah! Thou hast failed, %r. Now thou shalt die." %E %Cp Kni 00065 "Die, %c. Thou art as nothing against my might." %E %Cp Kni 00066 "I shall suck the marrow from thy bones, %c." %E %Cp Kni 00067 "Let's see... Broiled? No. Fried? Nay. Baked? Yea verily, that is the way I like my %c for dinner." %E %Cp Kni 00068 "Thy strength waneth, %p. The time of thy death draweth near." %E %Cp Kni 00069 "Call upon thy precious %d, %p. It shall not avail thee." %E %Cc Kni 00070 As you pick up %o, you feel its protective fields form around your body. You also feel a faint stirring in your mind, as if you are in two places at once, and in the second, you are waking from a long sleep. %E %Cc Kni 00080 As %n sinks to the ground, blood gushing from his open mouth, he defiantly curses you and %l: Thou hast not won yet, %r. By the gods, I shall return and dog thy steps to the grave! His tail flailing madly, %n tries to crawl towards you, but slumps to the ground and dies in a pool of his own blood. %E %Cc Kni 00081 As you approach %l, he beams at you and says: Well done! Thou art truly the Champion of %H. We have received word that Merlin is recovering, and shall soon rejoin Us. He hath instructed Us that thou art now to be the guardian of %o. He feeleth that thou mayst have need of its powers in thine adventures. It is Our wish that thou keepest %o with thee as thou searchest for the fabled Amulet of Yendor. %E # assumes Magic Mirror of Merlin (glass object) %Cc Kni 00082 "Careful, %p! %oC might break, and that would be a tragic loss. Thou art its keeper now, and the time hath come to resume thy search for the Amulet. %Z await thy return through the magic portal that brought thee here." %E %Cp Kni 00090 "Well met, %p. How goeth thy search for the Amulet of Yendor?" %E %Cc Kni 00091 "Thou hast succeeded, We see, %p! Now thou art commanded to take the Amulet to be sacrificed to %d in the plane of the astral. "Merlin hath counseled Us that thou must travel always upwards through the planes of the elements, to achieve this goal. "Go with %d, %p." %E # # Monk # # The quest artifact is "The Eyes of the Overworld", hence needs # to be treated as plural by messages which use %o. # %Cc Mon 00001 You find yourself standing in sight of %H. Something is obviously wrong here. Strange shapes lumber around outside %H! You realize that the %l needs your assistance! %E %Cp Mon 00002 Once again, you stand before %H. %E %Cp Mon 00003 Again you face %H. Your intuition hints that this may be the final time you come here. %E %Cp Mon 00005 "Greetings, honorable %r. It is good to see you." %E %Cp Mon 00006 "Ah, %p! Surely you can help us in our hour of need." %E %Cp Mon 00007 "Greetings, %s. %lC has great need of your help." %E %Cp Mon 00008 "Alas, it seems as if even %d has deserted us." %E %Cp Mon 00009 "May %d be with you, %s." %E %Cp Mon 00010 "Greetings, honorable %r. It is good to see you again." %E %Cp Mon 00011 "Ah, %p! Our deepest gratitude for all of your help." %E %Cp Mon 00012 "Greetings, %s. Perhaps you will take some time to meditate with us?" %E %Cp Mon 00013 "With this test behind you, may %d bring you enlightenment." %E %Cp Mon 00014 "May %d be with you, %s." %E %Cc Mon 00015 "Ah, %p, my %S. You have returned to us at last. A great blow has befallen our order; perhaps you can help us. First, however, I must determine if you are prepared for this great challenge." %E %Cp Mon 00016 "Again, my %S, you stand before me. Are you ready now to help us?" %E %Cp Mon 00017 "Once more, %p, you stand within the sanctum. Are you ready now?" %E %Cc Mon 00018 "You are a heretic, %p! How can you, %ra, deviate so from the teachings of %d? Begone from this temple. You are no longer %sa to this order. We will pray to %d for other assistance, as you have failed us utterly." %E %Cc Mon 00019 "Alas, %p, it is not yet to be. A mere %r could never withstand the might of %n. Go forth, again into the world, and return when you have attained the post of %R." %E %Cc Mon 00020 "This is terrible, %p. You have deviated from the true path! You know that %d requires the most strident devotion of this order. The %shood must stand for utmost piety. "Go from here, atone for your sins against %d. Return only when you have purified yourself." %E %Cc Mon 00021 "Yes, %p. You are truly ready now. Attend to me and I shall tell you of what has transpired: "During one of the Great Meditations a short time ago, %n and a legion of elementals invaded %H. Many %gP were killed, including the one bearing %o. Now, there are barely enough %gP left to keep the elementals at bay. "We need you to find %i, then, from there, travel to %ns lair. If you can manage to defeat %n and return %o here, we can then drive off the legions of elementals that slay our students. "Go with %d as your guide, %p." %E %Cp Mon 00025 "You can prevail, if you rely on %d." %E %Cp Mon 00026 "Remember that %n has great magic at his command." %E %Cp Mon 00027 "Be pure, my %S." %E %Cp Mon 00028 "Beware, %i is surrounded by hordes of earth elementals." %E %Cp Mon 00029 "Remember your studies, and you will prevail!" %E %Cp Mon 00030 "Acquire and wear %o if you can. They will aid you against %n." %E %Cp Mon 00031 "Call upon %d when your need is greatest. You will be answered." %E %Cp Mon 00032 "Remember to use the elementals' strength against them!" %E %Cp Mon 00033 "Do not lose faith, %p. If you do so, %n will grow stronger." %E %Cp Mon 00034 "Wear %o. They will assist you in your efforts." %E %Cc Mon 00035 You remember the descriptions of %i, given to you by the %l. It is ahead that you will find %n's trail. %E %Cp Mon 00036 Again, you stand before %i. %E %Cc Mon 00040 The stench of brimstone is all about you, and the elementals close in from all sides! Ahead, there is a small clearing amidst the bubbling pits of lava... %E %Cp Mon 00041 Again, you have invaded %ns domain. %E %Cc Mon 00050 "Ah, so %l has sent another %g to retrieve %o. "No, I see you are no %g. Perhaps I shall have some fun today after all. Prepare to die, %r! You shall never regain %o." %E %Cp Mon 00051 "So, %r. Again you challenge me." %E %Cp Mon 00052 "Die now, %r. %d has no power here to aid you." %E %Cp Mon 00053 "You shall die, %r, and I will have %o back." %E %Cp Mon 00060 "Submit to my will, %c, and I shall spare you." %E %Cp Mon 00061 "Your puny powers are no match for me, %c." %E %Cp Mon 00062 "I shall have you turned into a zombie for my pleasure!" %E %Cp Mon 00063 "Despair now, %r. %d cannot help you." %E %Cp Mon 00064 "I shall feast upon your soul for many days, %c." %E %Cp Mon 00065 "Your death will be slow and painful. That I promise!" %E %Cp Mon 00066 "You cannot defeat %n, you fool. I shall kill you now." %E %Cp Mon 00067 "Your precious %lt will be my next victim." %E %Cp Mon 00068 "I feel your powers failing you, %r. You shall die now." %E %Cp Mon 00069 "With %o, nothing can stand in my way." %E %Cc Mon 00070 As you pick up %o, you feel the essence of %d fill your soul. You know now why %n stole them from %H, for with them, %ca of %d could easily defeat his plans. You sense a message from %d. Though not verbal, you get the impression that you must return to %l as soon as possible. %E %Cc Mon 00080 %nC gasps: "You have only defeated this mortal body. Know this: my spirit is strong. I shall return and reclaim what is mine!" With that, %n expires. %E %Cc Mon 00081 "You have returned, %p. And with %o, I see. Congratulations. "I have been in meditation, and have received direction from a minion of %d. %d commands that you retain %o. With them, you must recover the Amulet of Yendor. "Go forth, and let %d guide your steps." %E %Cc Mon 00082 %lC studies %o for a moment, then returns his gaze to you. "%oC must remain with you. Use them as you resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E %Cp Mon 00090 "Welcome back, %p. How is your quest for the Amulet going?" %E %Cc Mon 00091 "You have prevailed, %p! %d is surely with you. Now, you must take the amulet, and sacrifice it on %ds altar on the Astral plane. I suspect that I shall never see you again in this life, but I hope to at %ds feet." %E # # Priest # %Cc Pri 00001 You find yourself standing in sight of %H. Something is obviously wrong here. The doors to %H, which usually stand open, are closed. Strange human shapes shamble around outside. You realize that %l needs your assistance! %E %Cp Pri 00002 Once again, you stand before %H. %E %Cp Pri 00003 Again you face %H. Your intuition hints that this may be the final time you come here. %E %Cp Pri 00005 "Greetings, honored %r. It is good to see you." %E %Cp Pri 00006 "Ah, %p! Surely you can help us in our hour of need." %E %Cp Pri 00007 "Greetings, %s. %lC has great need of your help." %E %Cp Pri 00008 "Alas, it seems as if even %d has deserted us." %E %Cp Pri 00009 "May %d be with you, %s." %E %Cp Pri 00010 "Greetings, %r. It is good to see you again." %E %Cp Pri 00011 "Ah, %p! Our deepest gratitude for all of your help." %E %Cp Pri 00012 "Welcome back, %s! With %o, no undead can stand against us." %E %Cp Pri 00013 "Praise be to %d, for delivering us from %n." %E %Cp Pri 00014 "May %d be with you, %s." %E %Cc Pri 00015 "Ah, %p, my %S. You have returned to us at last. A great blow has befallen our order; perhaps you can help us. First, however, I must determine if you are prepared for this great challenge." %E %Cp Pri 00016 "Again, my %S, you stand before me. Are you ready now to help us?" %E %Cp Pri 00017 "Once more, %p, you stand within the sanctum. Are you ready now?" %E %Cc Pri 00018 "You are a heretic, %p! How can you, %ra, deviate so from the teachings of %d? Begone from this temple. You are no longer %sa to this order. We will pray to %d for other assistance, as you have failed us utterly." %E %Cc Pri 00019 "Alas, %p, it is not yet to be. A mere %r could never withstand the might of %n. Go forth, again into the world, and return when you have attained the post of %R." %E %Cc Pri 00020 "This is terrible, %p. You have deviated from the true path! You know that %d requires the most strident devotion of this order. The %shood must stand for utmost piety. "Go from here, atone for your sins against %d. Return only when you have purified yourself." %E %Cc Pri 00021 "Yes, %p. You are truly ready now. Attend to me and I shall tell you of what has transpired: "At one of the Great Festivals a short time ago, %n and a legion of undead invaded %H. Many %gP were killed, including the one carrying %o. "As a final act of vengefulness, %n desecrated the altar here. Without it, we could not mount a counter-attack. Now, there are barely enough %gP left to keep the undead at bay. "We need you to find %i, then, from there, travel to %ns lair. If you can manage to defeat %n and return %o here, we can then drive off the legions of undead that befoul the land. "Go with %d as your guide, %p." %E %Cp Pri 00025 "You can prevail, if you rely on %d." %E %Cp Pri 00026 "Remember that %n has great magic at his command." %E %Cp Pri 00027 "Be pure, my %S." %E %Cp Pri 00028 "Beware, %i is surrounded by a great graveyard." %E %Cp Pri 00029 "You may be able to affect %n with magical cold." %E %Cp Pri 00030 "Acquire and wear %o if you can. It will aid you against %n." %E %Cp Pri 00031 "Call upon %d when your need is greatest. You will be answered." %E %Cp Pri 00032 "The undead legions are weakest during the daylight hours." %E %Cp Pri 00033 "Do not lose faith, %p. If you do so, %n will grow stronger." %E %Cp Pri 00034 "Wear %o. It will assist you against the undead." %E %Cc Pri 00035 You stand facing a large graveyard. The sky above is filled with clouds that seem to get thicker closer to the center. You sense the presence of undead in larger numbers than you have ever encountered before. You remember the descriptions of %i, given to you by %lC. It is ahead that you will find %ns trail. %E %Cp Pri 00036 Again, you stand before %i. %E %Cc Pri 00040 The stench of brimstone is all about you, and the shrieks and moans of tortured souls assault your psyche. Ahead, there is a small clearing amidst the bubbling pits of lava... %E %Cp Pri 00041 Again, you have invaded %ns domain. %E %Cc Pri 00050 "Ah, so %lC has sent another %g to retrieve %o. "No, I see you are no %g. Perhaps I shall have some fun today after all. Prepare to die, %r! You shall never regain %o." %E %Cp Pri 00051 "So, %r. Again you challenge me." %E %Cp Pri 00052 "Die now, %r. %d has no power here to aid you." %E %Cp Pri 00053 "You shall die, %r, and I will have %o back." %E %Cp Pri 00060 "Submit to my will, %c, and I shall spare you." %E %Cp Pri 00061 "Your puny powers are no match for me, %c." %E %Cp Pri 00062 "I shall have you turned into a zombie for my pleasure!" %E %Cp Pri 00063 "Despair now, %r. %d cannot help you." %E %Cp Pri 00064 "I shall feast upon your soul for many days, %c." %E %Cp Pri 00065 "Your death will be slow and painful. That I promise!" %E %Cp Pri 00066 "You cannot defeat %n, you fool. I shall kill you now." %E %Cp Pri 00067 "Your precious %lt will be my next victim." %E %Cp Pri 00068 "I feel your powers failing you, %r. You shall die now." %E %Cp Pri 00069 "With %o, nothing can stand in my way." %E %Cc Pri 00070 As you pick up %o, you feel the essence of %d fill your soul. You know now why %n stole it from %H, for with it, %ca of %d could easily defeat his plans. You sense a message from %d. Though not verbal, you get the impression that you must return to %lC as soon as possible. %E %Cc Pri 00080 You feel a wrenching shift in the ether as %ns body dissolves into a cloud of noxious gas. Suddenly, a voice booms out: Thou hast defeated the least of my minions, %r. Know now that Moloch is aware of thy presence. As for thee, %n, I shall deal with thy failure at my leisure. You then hear the voice of %n, screaming in terror... %E %Cc Pri 00081 "You have returned, %p. And with %o, I see. Congratulations. "I have been in meditation, and have received direction from a minion of %d. %d commands that you retain %o. With it, you must recover the Amulet of Yendor. "Go forth, and let %d guide your steps." %E %Cc Pri 00082 %l reiterates that %o is yours now. "The time has come to resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E %Cp Pri 00090 "Welcome back, %p. How is your quest for the Amulet going?" %E %Cc Pri 00091 "You have prevailed, %p! %d is surely with you. Now, you must take the amulet, and sacrifice it on %ds altar on the Astral plane. I suspect that I shall never see you again in this life, but I hope to at %ds feet." %E # # Ranger # %Cc Ran 00001 You arrive in familiar surroundings. In the distance, you %x the ancient forest grove, the place of worship to %d. Something is wrong, though. Surrounding the grove are centaurs! And they've noticed you! %E %Cp Ran 00002 Once again, you stand before %H. %E %Cp Ran 00003 You have the oddest feeling that this may be the last time you are to enter %H. %E %Cp Ran 00005 "%pC! I have not seen you in many moons. How do you fare?" %E %Cp Ran 00006 "%nC continues to threaten the grove. But we hold fast." %E %Cp Ran 00007 "%lC is growing weak. The magic required to defend the grove drains us." %E %Cp Ran 00008 "Remember %i is hard to enter. Beware the distraction of leatherwings." %E %Cp Ran 00009 "We must regain %o. Without it we will be overrun." %E %Cp Ran 00010 "%pC! I have not seen you in many moons. How do you fare?" %E %Cp Ran 00011 "Birdsong has returned to the grove, surely this means you have defeated %n." %E %Cp Ran 00012 "%lC seems to have regained some of his strength." %E %Cp Ran 00013 "So, tell us how you entered %i, in case some new evil arises there." %E %Cp Ran 00014 "Is that truely %o that I see you carrying?" %E %Cc Ran 00015 "%pC! You have returned! Thank %d. "We have great need of you. But first, I must see if you have the required abilities to take on this responsibility." %E %Cp Ran 00016 "Once again, %p, you stand in our midst. Are you ready now?" %E %Cp Ran 00017 "Ah, you are here again, %p. Allow me to determine your readiness..." %E %Cc Ran 00018 "%pC! You have doomed us all. You fairly radiate %L influences and weaken the power we have raised in this grove as a result! "Begone! We renounce your %shood with us! You are an outcast now!" %E %Cc Ran 00019 "%p, you are yet too inexperienced to withstand the demands of that which we need you to do. %RA might just be able to do this thing. "Return to us when you have learned more, my %S." %E %Cc Ran 00020 "You have strayed, %p! You know that %d requires that we maintain a pure devotion to things %a! "You must go from us. Return when you have purified yourself." %E %Cc Ran 00021 "You are indeed ready, %p. I shall tell you what has transpired, and why we so desperately need your help: "A short time ago, the mountain centaurs to the east invaded and enslaved the plains centaurs in this area. The local leader is now only a figurehead, and serves %n. "During our last gathering of worship here, we were beset by hordes of hostile centaurs, as you witnessed. In the first onslaught a group, headed by %n himself, managed to breach the grove and steal %o. "Since then, we have been besieged. We do not know how much longer we will be able to maintain our magical barriers. "If we are to survive, you, %p, must infiltrate %i. There, you will find a pathway down, to the underground cavern of %n. He has always coveted %o, and will surely keep it. "Recover %o for us, %p! Only then will %d be safe." %E %Cp Ran 00025 "It is rumored that the Forest and Mountain Centaurs have resolved their ancient feud and now band together against us." %E %Cp Ran 00026 "%nC is strong, and very smart." %E %Cp Ran 00027 "Use %o, when you find it. It will help you survive to reach us." %E %Cp Ran 00028 "Remember, let %d be your guide." %E %Cp Ran 00029 "Call upon %d when you face %n. The very act of doing so will infuriate him, and give you advantage." %E %Cp Ran 00030 "%n and his kind have always hated us." %E %Cp Ran 00031 "We cannot hold the grove much longer, %p. Hurry!" %E %Cp Ran 00032 "To infiltrate %i, you must be very stealthy." %E %Cp Ran 00033 "Remember that %n is a braggart. Trust not what he says." %E %Cp Ran 00034 "You can triumph, %p, if you trust in %d." %E %Cc Ran 00035 This must be %i. You are in a cave built of many different rooms, all interconnected by tunnels. Your quest is to find and shoot the evil wumpus that resides elsewhere in the cave without running into any bottomless pits or using up your limited supply of arrows. Good luck. You are in room 9 of the cave. There are tunnels to rooms 5, 8, and 10. *rustle* *rustle* (must be bats nearby) *sniff* (I can smell the evil wumpus nearby!) %E %Cc Ran 00036 Once again, you descend into %i. *whoosh* (I feel a draft from some pits). *rustle* *rustle* (must be bats nearby) %E %Cc Ran 00040 You descend into a weird place, in which roughly cut cave-like walls join with smooth, finished ones, as if someone was in the midst of finishing off the construction of a subterranean complex. Off in the distance, you hear a sound like the clattering of many hooves on rock. %E %Cp Ran 00041 Once again, you enter the distorted castle of %n. %E %Cc Ran 00050 "So, %c. %lC has sent you to recover %o. "Well, I shall keep that bauble. It pleases me. You, %c, shall die." %E %Cp Ran 00051 "Back again, eh? Well, a mere %r is no threat to me! Die, %c!" %E %Cp Ran 00052 "You haven't learned your lesson, %c. You can't kill me! You shall die now." %E %Cp Ran 00053 "I shall have %o from you, %r. Then I shall kill you." %E %Cp Ran 00060 "Your %d is nothing, %c. You are mine now!" %E %Cp Ran 00061 "Run away little %c! You can never hope to defeat %n!" %E %Cp Ran 00062 "My servants will rip you to shreds!" %E %Cp Ran 00063 "I shall display your head as a trophy. What do you think about that wall?" %E %Cp Ran 00064 "I shall break your %ls grove, and destroy all the %gP!" %E %Cp Ran 00065 "%d has abandoned you, %c. You are doomed." %E %Cp Ran 00066 "%rA? %lC sends a mere %r against me? Hah!" %E %Cp Ran 00067 "%lC has failed, %c. %oC will never leave here." %E %Cp Ran 00068 "You really think you can defeat me, eh %c? You are wrong!" %E %Cp Ran 00069 "You weaken, %c. I shall kill you now." %E %Cc Ran 00070 As you pick up %o, it seems to glow, and a warmth fills you completely. You realize that its power is what has protected your %sp against their enemies for so long. You must now return it to %l without delay -- their lives depend on your speed. %E %Cc Ran 00080 %nC collapses to the ground, cursing you and %l, then says: You have defeated me, %r! But I curse you one final time, with my dying breath! You shall die before you leave my castle! %E %Cc Ran 00081 "%pC! You have succeeded! I feared it was not possible! "You have returned with %o! "I fear, now, that the Centaurs will regroup and plot yet another raid. This will take some time, but if you can recover the Amulet of Yendor for %d before that happens, we will be eternally safe. "Take %o with you. It will aid in your quest for the Amulet." %E # assumes The Longbow of Diana %Cc Ran 00082 %l flexs %o reverently. "With this wondrous bow, one need never run out of arrows. You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E %Cp Ran 00090 "Welcome, %p. How have you fared on your quest for the Amulet of Yendor?" %E %Cc Ran 00091 "You have it! You have recovered the Amulet of Yendor! Now attend to me, %p, and I will tell you what must be done: "The Amulet has within it magic, the capability to transport you to the Astral Plane, where the primary circle of %d resides. "To activate this magic, you must travel upwards as far as you can. When you reach the temple, sacrifice the Amulet to %d. "Thus will you fulfill your destiny." %E # # Rogue (with apologies to all Norsk speakers -dean) # %Cc Rog 00001 Unexpectedly, you find yourself back in Ransmannsby, where you trained to be a thief. Quickly you make the guild sign, hoping that you AND word of your arrival reach %ls den. %E %Cp Rog 00002 Once again, you find yourself back in Ransmannsby. Fond memories are replaced by fear, knowing that %l is waiting for you. %E %Cp Rog 00003 You rub your hands through your hair, hoping that the little ones on the back of your neck stay down, and prepare yourself for your meeting with %l. %E %Cp Rog 00005 "I hear that Lady Tyvefelle's household is lightly guarded." %E %Cp Rog 00006 "You're back? Even the Twain don't come back anymore." %E %Cp Rog 00007 "Can you spare an old cutpurse a zorkmid for some grog?" %E %Cp Rog 00008 "Fritz tried to join the other side, and now he's hell-hound chow." %E %Cp Rog 00009 "Be careful what you steal, I hear the boss has perfected turning rocks into worthless pieces of glass." %E %Cp Rog 00010 "I was sure wrong about Lady Tyvefelle's house; I barely got away with my life and lost my lock pick in the process." %E %Cp Rog 00011 "You're back? Even the Twain don't come back anymore." %E %Cp Rog 00012 "Can you spare an old cutpurse a zorkmid for some grog?" %E %Cp Rog 00013 "Fritz tried to join the other side, and now he's hell-hound chow." %E %Cp Rog 00014 "Be careful what you steal, I hear the boss has perfected turning rocks into worthless pieces of glass." %E %Cc Rog 00015 "Well, look who it is boys -- %p has come home. You seem to have fallen behind in your dues. I should kill you as an example to these other worthless cutpurses, but I have a better plan. If you are ready maybe you could work off your back dues by performing a little job for me. Let us just see if you are ready..." %E %Cp Rog 00016 "Well, I didn't expect to see you back. It shows that you are either stupid, or you are finally ready to accept my offer. Let us hope for your sake it isn't stupidity that brings you back." %E %Cp Rog 00017 "Did you perhaps mistake me for some other %lt? You must think me as stupid as your behavior. I warn you not to try my patience." %E %Cc Rog 00018 "Well %gp, it looks like our friend has forgotten who is the boss around here. Our friend seems to think that %rp have been put in charge. Wrong. DEAD WRONG!" Your sudden shift in surroundings prevents you from hearing the end of %ls curse. %E %Cc Rog 00019 "In the time that you've been gone you've only been able to master the arts of %ra? I've trained ten times again as many %Rp in that time. Maybe I should send one of them, no? Where would that leave you, %p? Oh yeah, I remember, I was going to kill you!" %E %Cc Rog 00020 "Maybe I should chain you to my perch here for a while. Perhaps watching real %a men at work will bring some sense back to you. I don't think I could stand the sight of you for that long though. Come back when you can be trusted to act properly." %E %Cc Rog 00021 "Will everyone not going to retrieve %o from that jerk, %n, take one step backwards. Good choice, %p, because I was going to send you anyway. My other %gp are too valuable to me. "Here's the deal. I want %o, %n has %o. You are going to get %o and bring it back to me. So simple an assignment even you can understand it." %E %Cp Rog 00025 "You don't seem to understand, %o isn't here so neither should you be!" %E %Cp Rog 00026 "May %d curse you with lead fingers. Get going!" %E %Cp Rog 00027 "We don't have all year. GET GOING!" %E %Cp Rog 00028 "How would you like a scar necklace? I'm just the jeweler to do it!" %E %Cp Rog 00029 "Lazy S.O.B. Maybe I should call up someone else..." %E %Cp Rog 00030 "Maybe I should open your skull and see if my instructions are inside?" %E %Cp Rog 00031 "This is not a task you can complete in the afterlife, you know." %E %Cp Rog 00032 "Inside every living person is a dead person trying to get out, and I have your key!" %E %Cp Rog 00033 "We're almost out of hell-hound chow, so why don't you just get moving!" %E %Cp Rog 00034 "You know, %o isn't going to come when you whistle. You must get it yourself." %E %Cc Rog 00035 Those damn little hairs tell you that you are nearer to %o. %E %Cp Rog 00036 Not wanting to face %l without having stolen %o, you continue. %E %Cc Rog 00040 You feel a great swelling up of courage, sensing the presence of %o. Or is it fear? %E %Cp Rog 00041 The hairs on the back of your neck whisper -- it's fear. %E %Cc Rog 00050 "Ah! You must be %ls ... er, `hero'. A pleasure to meet you." %E %Cp Rog 00051 "We meet again. Please reconsider your actions." %E %Cp Rog 00052 "Surely, %p, you have learned that you cannot trust any bargains that %l has made. I can show you how to continue on your quest without having to run into him again." %E %Cp Rog 00053 "Please, think for a moment about what you are doing. Do you truly believe that %d would want %l to have %o?" %E %Cp Rog 00060 "May I suggest a compromise. Are you interested in gold or gems?" %E %Cp Rog 00061 "Please don't force me to kill you." %E %Cp Rog 00062 "Grim times are upon us all. Will you not see reason?" %E %Cp Rog 00063 "I knew %l, and you're no %lt, thankfully." %E %Cp Rog 00064 "It is a shame that we are not meeting under more pleasant circumstances." %E %Cp Rog 00065 "I was once like you are now, %p. Believe in me -- our way is better." %E %Cp Rog 00066 "Stay with me, and I will make you %os guardian." %E %Cp Rog 00067 "When you return, with or without %o, %l will have you killed." %E %Cp Rog 00068 "Do not be fooled; I am prepared to kill to defend %o." %E %Cp Rog 00069 "I can reunite you with the Twain. Oh, the stories you can swap." %E %Cc Rog 00070 As you pick up %o, the hairs on the back of your neck fall out. At once you realize why %n was willing to die to keep it out of %ls hands. Somehow you know that you must do likewise. %E %Cc Rog 00080 "I know what you are thinking, %p. It is not too late for you to use %o wisely. For the sake of your guild %sp, do what is right." You sit and wait for death to come for %n, and then you brace yourself for your next meeting with %l! %E %Cc Rog 00081 "Well, I'll be damned. You got it. I am proud of you, a fine %r you've turned out to be. "While you were gone I got to thinking, you and %o together could bring me more treasure than either of you apart, so why don't you take it with you. All I ask is a cut of whatever loot you come by. That is a better deal than I offered %n. "But, you see what happened to %n when he refused. Don't make me find another to send after you this time." %E # assumes Master Key of Thievery (small object) %Cc Rog 00082 %l seems tempted to swap %o for the mundane one you detect in his pocket, but noticing your alertness, evidently chickens out. "Go filch the Amulet before someone else beats you to it. %Z are back the way you came, through the magic portal." %E %Cc Rog 00090 "Quite the little thief, aren't we, %p. Can I interest you in a swap for %o. Look around, anything in the keep is yours for the asking." %E %Cc Rog 00091 "I see that with your abilities, and my brains, we could rule this world. "All that we would need to be all-powerful is for you to take that little trinket you've got there up to the Astral plane. From there, %d will show you what to do with it. Once that's done, we will be invincible!" %E # # Samurai # %Cc Sam 00001 Even before your senses adjust, you recognize the kami of %H. You %x the standard of your teki, %n, flying above the town. How could such a thing have happened? Why are ninja wandering freely; where are the samurai of your daimyo, %l? You quickly say a prayer to Izanagi and Izanami and walk towards town. %E %Cp Sam 00002 Once again, you are back at %H. %E %Cp Sam 00003 You are back at %H. Instantly you sense a subtle change in your karma. You seem to know that if you do not succeed in your quest, %n will have destroyed the kami of %H before you return again. %E %Cp Sam 00005 "To succeed, you must walk like a butterfly on the wind." %E %Cp Sam 00006 "Ikaga desu ka?" %E %Cp Sam 00007 "I fear for The Land of The Gods." %E %Cp Sam 00008 "%nC has hired the Ninja -- be careful." %E %Cp Sam 00009 "If %o is not returned, we will all be ninja." %E %Cp Sam 00010 "Come, join us in celebrating with some sake." %E %Cp Sam 00011 "Ikaga desu ka?" %E %Cp Sam 00012 "You have brought our clan and %l much honor." %E %Cp Sam 00013 "Please %r, sit for a while and tell us how you overcame the Ninja." %E %Cp Sam 00014 "%lC still lives! You have saved us from becoming ronin." %E %Cc Sam 00015 "Ah, %p-san, it is good to see you again. I need someone who can lead my samurai against %n. If you are ready, you will be that person." %E %Cp Sam 00016 "Once again, %p-san, you kneel before me. Are you yet capable of being my vassal?" %E %Cp Sam 00017 "You begin to test my matsu, %p-san. If you cannot determine what I want in a samurai, how can I rely on you to figure out what I need from a samurai?" %E %Cc Sam 00018 "You are no longer my samurai, %p. "Hara-kiri is denied. You are ordered to shave your head and then to become a monk. Your fief and family are forfeit. Wakarimasu?" %E %Cc Sam 00019 "%p-san, you have learned well and honored your family. I require the skills of %Ra in order to defeat %n. Go and seek out teachers. Learn what they have learned. When you are ready, return to me." %E %Cc Sam 00020 "%p-san, you would do better to join the kyokaku. "You have skills, but until you can call upon the bushido to know when and how to use them you are not samurai. When you can think %a and act %a then return." %E %Cc Sam 00021 "Domo %p-san, indeed you are ready. I can now tell you what it is that I require of you. "The daimyo, %n, has betrayed us. He has stolen from us %o and taken it to his donjon deep within %i. "If I cannot show the emperor %o when he comes for the festival he will know that I have failed in my duty, and request that I commit seppuku. "You must gain entrance to %i and retrieve the emperor's property. Be quick! The emperor will be here for the cha-no-you in 5 sticks. "Wakarimasu?" %E %Cp Sam 00025 "To defeat %n you must overcome the seven emotions: hate, adoration, joy, anxiety, anger, grief, and fear." %E %Cp Sam 00026 "Remember your honor is my honor, you perform in my name." %E %Cp Sam 00027 "I will go to the temple and burn incense for your safe return." %E %Cp Sam 00028 "Sayonara." %E %Cp Sam 00029 "There can be honor in defeat, but no gain." %E %Cp Sam 00030 "Your kami must be strong in order to succeed." %E %Cp Sam 00031 "You are indeed a worthy %R, but now you must be a worthy samurai." %E %Cp Sam 00032 "If you fail, %n will be like a tai-fun on the land." %E %Cp Sam 00033 "If you are truly %a, %d will listen." %E %Cp Sam 00034 "Sharpen your swords and your wits for the task before you." %E %Cc Sam 00035 You instinctively reach for your swords. You do not recognize the lay of this land, but you know that your teki are everywhere. %E %Cp Sam 00036 Thankful that your %sp at %H cannot see your fear, you prepare again to advance. %E %Cc Sam 00040 In your mind, you hear the taunts of %n. You become like the rice plant and bend to the ground, offering a prayer to %d. But when the wind has passed, you stand proudly again. Putting your kami in the hands of fate, you advance. %E %Cp Sam 00041 As you arrive once again at the home of %n, your thoughts turn only to %o. %E %Cc Sam 00050 "Ah, so it is to be you, %p-san. I offer you seppuku. I will be your second if you wish." %E %Cp Sam 00051 "I have offered you the honorable exit. Now I will have your head to send unwashed to %l." %E %Cp Sam 00052 "After I have dispatched you, I will curse your kami." %E %Cp Sam 00053 "You have fought my samurai; surely you must know that you will not be able to take %o back to %H." %E %Cp Sam 00060 "Ahh, I finally meet the daimyo of the kyokaku!" %E %Cp Sam 00061 "There is no honor for me in your death." %E %Cp Sam 00062 "You know that I cannot resash my swords until they have killed." %E %Cp Sam 00063 "Your presence only compounds the dishonor of %l in not coming himself." %E %Cp Sam 00064 "I will make tea with your hair and serve it to %l." %E %Cp Sam 00065 "Your fear shows in your eyes, coward!" %E %Cp Sam 00066 "I have not heard of you, %p-san; has your life been that unworthy?" %E %Cp Sam 00067 "If you will not obey me, you will die." %E %Cp Sam 00068 "Kneel now and make the two cuts of honor. I will tell your %sp of your honorable death." %E %Cp Sam 00069 "Your master was a poor teacher. You will pay for his mistakes in your teaching." %E %Cc Sam 00070 As you pick up %o, you feel the strength of its karma. You realize at once why so many good samurai had to die to defend it. You are humbled knowing that you hold one of the artifacts of the sun goddess. %E %Cc Sam 00080 Your healing skills tell you that %ns wounds are mortal. You know that the bushido tells you to finish him and let his kami die with honor, but the thought of so many samurai dead due to this man's dishonor prevents you from giving the final blow. You order that his unwashed head be given to the crows and his body thrown into the sea. %E %Cc Sam 00081 As you bow before %l, he welcomes you: You have brought your family great honor, %p-sama. While you have been gone the emperor's advisors have discovered in the ancient texts that the karma of the samurai who seeks to recover the amulet and the karma of %o are joined as the seasons join to make a year. Because you have shown such fidelity, the emperor requests that you take leave of other obligations and continue on the road that fate has set your feet upon. I would consider it an honor if you would allow me to watch your household until you return with the amulet. With that, %l bows, and places his sword atop %o. %E %Cc Sam 00082 %l holds %o tightly for a moment, then returns his gaze to you. "The time is ripe to recover the Amulet. Return to %Z through the magic portal that transported you here so that you may achieve the destiny which awaits you." %E %Cp Sam 00090 %lC bows. "%p-sama, tell us of your search for the Amulet." %E %Cc Sam 00091 "Ah, %p-sama. You have wasted your efforts returning home. Now that you are in possession of the Amulet, you are honor-bound to finish the quest you have undertaken. There will be plenty of time for saki and stories when you have finished. "Go now, and may our prayers be a wind at your back." %E # # Tourist # %Cc Tou 00001 You breathe a sigh of relief as you find yourself back in the familiar surroundings of %H. You quickly notice that things do not appear the way they did when you left. The town is dark and quiet. There are no sounds coming from behind the town walls, and no campfires burning in the fields. As a matter of fact, you do not %x any movement in the fields at all, and the crops look as though they have been untended for many weeks. %E %Cp Tou 00002 Once again, you are back at %H. %E %Cp Tou 00003 You are back at %H. Things appear to have become so bad that you fear that soon %H will not be here to return to. %E %Cp Tou 00005 "Gehennom on 5 zorkmids a day -- more like 500 a day if you ask me." %E %Cp Tou 00006 "Do you know where I could find some nice postcards of The Gnomish Mines?" %E %Cp Tou 00007 "Have you tried the weird toilets?" %E %Cp Tou 00008 "Don't stay at the Inn, I hear the food is terrible and it has rats." %E %Cp Tou 00009 "They told me that this was the off season!" %E %Cp Tou 00010 "Gehennom on 5 zorkmids a day -- more like 500 a day if you ask me." %E %Cp Tou 00011 "Do you know where I could find some nice postcards of The Gnomish Mines?" %E %Cp Tou 00012 "Have you tried the weird toilets?" %E %Cp Tou 00013 "If you stick around, I'll show you the pictures from my latest trip." %E %Cp Tou 00014 "Did you bring me back any souvenirs?" %E %Cc Tou 00015 "Is it really you, %p! I had given up hope for your return. As you can %x, we are desperately in need of your talents. Someone must defeat %n if our town is become what it once was. "Let me see if you are ready to be that someone." %E %Cp Tou 00016 "Things are getting worse, %p. I hope that this time you are ready." %E %Cp Tou 00017 "I hope that for the sake of %H you have prepared yourself this time." %E %Cc Tou 00018 "It is too late, %p. You are not even worthy to die amongst us. Leave %H and never return." %E %Cc Tou 00019 "There is still too much that you have to learn before you can undertake the next step. Return to us as a proven %R, and perhaps then you will be ready. "Go back now, and may the teachings of %d serve you well." %E %Cc Tou 00020 "It would be an affront to %d to have one not true to the %a path undertake her bidding. "You must not return to us until you have purified yourself of these bad influences on your actions. Remember, only by following the %a path can you hope to overcome the obstacles you will face." %E %Cc Tou 00021 "You have indeed proven yourself a worthy %c, %p. "But now your kinfolk and I must ask you to put aside your travels and help us in our time of need. After you left us we elected a new mayor, %n. He proved to be a most heinous and vile creature. "Soon after taking office he absconded with %o and fled town, leaving behind his henchmen to rule over us. In order for us to regain control of our town, you must enter %i and recover %o. "Do not be distracted on your quest. If you do not return quickly I fear that all will be lost. Let us both pray now that %d will guide you and keep you safe." %E %Cp Tou 00025 "Do not be fooled by the false promises of %n." %E %Cp Tou 00026 "To enter %i you must pass many traps." %E %Cp Tou 00027 "If you do not return with %o, your quest will be in vain." %E %Cp Tou 00028 "Do not be afraid to call upon %d if you truly need help." %E %Cp Tou 00029 "If you do not destroy %n, he will follow you back here!" %E %Cp Tou 00030 "Take %o from %n and you may be able to defeat him." %E %Cp Tou 00031 "You must hurry, %p!" %E %Cp Tou 00032 "You are like %Sa to me, %p. Do not let me down." %E %Cp Tou 00033 "If you are %a at all times you may succeed, %p." %E %Cp Tou 00034 "Let all who meet you on your journey know that you are on an quest for %l and grant safe passage." %E %Cc Tou 00035 Only your faith in %d keeps you from trembling. You %x the handiwork of %ns henchlings everywhere. %E %Cp Tou 00036 You know that this time you must find and destroy %n. %E %Cc Tou 00040 You sense the presence of %o. %E %Cp Tou 00041 You gain confidence, knowing that you may soon be united with %o. %E %Cc Tou 00050 "So, %p, %l thinks that you can wrest %o from me! "It only proves how desperate he has become that he sends %ra to try and defeat me. When this day is over, I will have you enslaved in the mines where you will rue the day that you ever entered %i." %E %Cp Tou 00051 "I let you live the last time because it gave me pleasure. This time I will destroy you, %p." %E %Cc Tou 00052 "These meetings come to bore me. You disturb my workings with %o. "If you do not run away now, I will inflict so much suffering on you that %l will feel guilty for ever having sent his %S to me!" %E %Cc Tou 00053 "You fool. You do not know how to call upon the powers of %o. "Return it to me and I will teach you how to use it, and together we will rule %H. But do so now, as my patience grows thin." %E %Cp Tou 00060 "I defeated %l and I will defeat you, %p." %E %Cp Tou 00061 "Where is %d now! You must realize no one can help you here." %E %Cp Tou 00062 "Beg for mercy now and I may be lenient on you." %E %Cp Tou 00063 "If you were not so %a, you might have stood a chance." %E %Cp Tou 00064 "Vengeance is mine at last, %p." %E %Cp Tou 00065 "I only wish that %l had a more worthy %r to send against me." %E %Cp Tou 00066 "With %o in my possession you cannot hope to defeat me." %E %Cp Tou 00067 "%nC has never been defeated, NEVER!" %E %Cp Tou 00068 "Are you truly the best %H has to send against me? I pity %l." %E %Cp Tou 00069 "How do you spell %p? I want to ensure the marker on your grave is correct as a warning to your %sp." %E %Cc Tou 00070 As you pick up %o, you feel a great weight has been lifted from your shoulders. Your only thoughts are to quickly return to %H and find %l. %E %Cc Tou 00080 You turn in the direction of %n. As his earthly body begins to vanish before your eyes, you hear him curse: You shall never be rid of me, %p! I will find you where ever you go and regain what is rightly mine. %E %Cc Tou 00081 As %l detects the presence of %o, he almost smiles for the first time in many a full moon. As he looks up from %o he says: You have recovered %o. You are its owner now, but not its master. Let it work with you as you continue your journey. With its help, and %d to guide you on the %a path, you may yet recover the Amulet of Yendor. %E %Cc Tou 00082 "%oC is yours now. %Z await your return through the magic portal that brought you here." %E %Cp Tou 00090 "I could not be more proud than if you were my own %S, %p! Tell me of your adventures in quest of the Amulet of Yendor." %E %Cc Tou 00091 "Stand back and let me look at you, %p. Now that you have recovered the Amulet of Yendor, I'm afraid living out your days in %H would seem pretty tame. "You have come too far to stop now, for there are still more tasks that our oral history foretells for you. Forever more, though, your name shall be spoken by the %gP with awe. You are truly an inspiration to your %sp!" %E # # Valkyrie # %Cc Val 00001 You materialize at the base of a snowy hill. Atop the hill sits a place you know well, %H. You immediately realize that something here is very wrong! In places, the snow and ice have been melted into steaming pools of water. Fumaroles and pools of bubbling lava surround the hill. The stench of sulphur is carried through the air, and you %x creatures that should not be able to live in this environment moving towards you. %E %Cp Val 00002 Once again, you are near the abode of %l. %E %Cp Val 00003 Again you materialize near %ls abode. You have a nagging feeling that this may be the last time you come here. %E %Cp Val 00005 "Hail, and well met, brave %c." %E %Cp Val 00006 "May %d guide your steps, %p." %E %Cp Val 00007 "%lC weakens. Without %o, her foresight is dim." %E %Cp Val 00008 "You must hurry, %p, else Ragnarok may well come." %E %Cp Val 00009 "I would deal with this foul %n myself, but %d forbids it." %E %Cp Val 00010 "Hail, and well met, brave %c." %E %Cp Val 00011 "May %d guide your steps, %p." %E %Cp Val 00012 "%lC told us you had succeeded!" %E %Cp Val 00013 "You recovered %o just in time, %p." %E %Cp Val 00014 "Hail %d, for delivering %o back to us." %E %Cc Val 00015 "Ah, %p, my %S. You have returned to %H at last. We are in dire need of your aid, but I must determine if you are yet ready for such an undertaking. "Let me read your fate..." %E %Cp Val 00016 "Let me read the future for you now, %p, perhaps you have managed to change it enough..." %E %Cp Val 00017 "Again, I shall read your fate, my %S. Let us both hope that you have made changes to become ready for this task..." %E %Cc Val 00018 "No, %p. Your fate is sealed. I must cast about for another champion. Begone from my presence, and never return. Know this, that you shall never succeed in this life, and Valhalla is denied to you." %E %Cc Val 00019 "I see you and %n fighting, %p. But you are not prepared and shall die at %ns hand if you proceed. No. This will not do. Go back out into the world, and grow more experienced at the ways of war. Only when you have returned %Ra will you be able to defeat %n." %E %Cc Val 00020 "NO! This is terrible. I see you becoming an ally of %n, and leading his armies in the final great battles. This must not come to pass! You have strayed from the %a path. You must purge yourself, and return here only when you have regained a state of purity." %E %Cc Val 00021 "It is not clear, %p, for my sight is limited without %o. But it is now likely that you can defeat %n, and recover %o. "A short time ago, %n and his minions attacked this place. They opened the huge volcanic vents you %x about the hill, and attacked. I knew that this was to come to pass, and had asked %d for a group of %gP to help defend this place. The few you %x here are the mightiest of Valhalla's own, and are all that are left of one hundred %d sent. "Despite the great and glorious battle we fought, %n managed at last to steal %o. This has upset the balance of the universe, and unless %o is returned into my care, %n may start Ragnarok. "You must find the entrance to %i. Travel downward from there and you will find %ns lair. Defeat him and return %o to me." %E %Cp Val 00025 "Go with the blessings of %d." %E %Cp Val 00026 "Call upon %d when you are in need." %E %Cp Val 00027 "Use %o if you can. It will protect you." %E %Cp Val 00028 "Magical cold is very effective against %n." %E %Cp Val 00029 "To face %n, you will need to be immune to fire." %E %Cp Val 00030 "May %d strengthen your sword-arm." %E %Cp Val 00031 "Trust in %d. He will not desert you." %E %Cp Val 00032 "It becomes more likely that Ragnarok will come with every passing moment. You must hurry, %p." %E %Cp Val 00033 "If %n can master %o, he will be powerful enough to face %d far earlier than is fated. This must not be!" %E %Cp Val 00034 "Remember your training, %p. You can succeed." %E %Cc Val 00035 The ice and snow gives way to a valley floor. You %x ahead of you a huge round hill surrounded by pools of lava. This then is the entrance to %i. It looks like you're not going to get in without a fight though. %E %Cp Val 00036 Once again, you stand before the entrance to %i. %E %Cc Val 00040 Through clouds of sulphurous gasses, you %x a rock palisade surrounded with a moat of bubbling lava. You remember the description from something that %l said. This is the lair of %n. %E %Cp Val 00041 Once again, you stand in sight of %ns lair. %E %Cc Val 00050 "So! %lC has finally sent %ca to challenge me! "I thought that mastering %o would enable me to challenge %d, but it has shown me that first I must kill you! So come, little %s. Once I defeat you, I can at last begin the final battle with %d." %E %Cp Val 00051 "Again you challenge me, %r. Good. I will kill you now." %E %Cp Val 00052 "Have you not learned yet? You cannot defeat %n!" %E %Cp Val 00053 "I will kill you, %c, and wrest %o from your mangled hands." %E %Cp Val 00060 "I am your death, %c." %E %Cp Val 00061 "You cannot prevail, %r. I have foreseen your every move." %E %Cp Val 00062 "With you out of the way, Valhalla will be mine for the taking." %E %Cp Val 00063 "I killed scores of %ds best when I took %o. Do you really think that one %c can stand against me?" %E %Cp Val 00064 "Who bears the souls of %cP to Valhalla, %r?" %E %Cp Val 00065 "No, %d cannot help you here." %E %Cp Val 00066 "Some instrument of %d you are, %p. You are a weakling!" %E %Cp Val 00067 "Never have I seen %ca so clumsy in battle." %E %Cp Val 00068 "You die now, little %s." %E %Cp Val 00069 "Your body I destroy now, your soul when my hordes overrun Valhalla!" %E %Cc Val 00070 As you pick up %o, your mind is suddenly filled with images, and you perceive all of the possibilities of each potential choice you could make. As you begin to control and channel your thoughts, you realize that you must return %o to %lC immediately. %E %Cc Val 00080 A look of surprise and horror appears on %ns face. No!!! %o has lied to me! I have been misled! Suddenly, %n grasps his head and screams in agony, then dies. %E %Cc Val 00081 As you approach, %lC rises and touches %o. "You may take %o with you, %p. I have removed from it the power to foretell the future, for that power no mortal should have. Its other abilities, however, you have at your disposal. "You must now begin in %ds name to search for the Amulet of Yendor. May your steps be guided by %d, my %S." %E # assumes Orb of Fate (glass object) %Cc Val 00082 "Careful, %p! %oC might break, and that would be a tragic loss. You are its keeper now, and the time has come to resume your search for the Amulet. %Z await your return through the magic portal that brought you here." %E %Cp Val 00090 "Greetings, %p. I have not been able to pay as much attention to your search for the Amulet as I have wished. How do you fare?" %E %Cc Val 00091 "Excellent, %p. I see you have recovered the Amulet! "You must take the Amulet to the Great Temple of %d, on the Astral plane. There you must offer the Amulet to %d. "Go now, my %S. I cannot tell you your fate, as the power of the Amulet interferes with mine. I hope for your success." %E # # Wizard # %Cc Wiz 00001 You are suddenly in familiar surroundings. You notice what appears to be a large, squat stone structure nearby. Wait! That looks like the tower of your former teacher, %l. However, things are not the same as when you were last here. Mists and areas of unexplained darkness surround the tower. There is movement in the shadows. Your teacher would never allow such unaesthetic forms to surround the tower... unless something were dreadfully wrong! %E %Cp Wiz 00002 Once again, you are back at %H. %E %Cp Wiz 00003 You are back at %H. You have an odd feeling this may be the last time you ever come here. %E %Cp Wiz 00005 "Would you happen to have some eye of newt in that overstuffed pack, %s?" %E %Cp Wiz 00006 "Ah, the spell to create the magic portal worked. Outstanding!" %E %Cp Wiz 00007 "Hurry! %lC may not survive that casting of the portal spell!!" %E %Cp Wiz 00008 "The spells of %n were just too powerful for us to withstand." %E %Cp Wiz 00009 "I, too, will venture into the world, because %n is but one of many evils to be vanquished." %E %Cp Wiz 00010 "I have some eye of newt to trade, do you have a spare blind-worm's sting?" %E %Cp Wiz 00011 "The magic portal now seems like it will remain stable for quite some time." %E %Cp Wiz 00012 "Have you noticed how much stronger %l is since %o was recovered?" %E %Cp Wiz 00013 "Thank %d! We weren't positive you would defeat %n." %E %Cp Wiz 00014 "I, too, will venture into the world, because %n was but one of many evils to be vanquished." %E %Cc Wiz 00015 "Come closer, %p, for my voice falters in my old age. Yes, I see that you have come a long way since you went out into the world, leaving the safe confines of this tower. However, I must first determine if you have all of the skills required to take on the task I require of you." %E %Cp Wiz 00016 "Well, %p, you have returned. Perhaps you are now ready..." %E %Cp Wiz 00017 "This is getting tedious, %p, but perseverance is a sign of a true mage. I certainly hope that you are truly ready this time!" %E %Cc Wiz 00018 "You fool, %p! Why did I waste all of those years teaching you the esoteric arts? Get out of here! I shall find another." %E %Cc Wiz 00019 "Alas, %p, you have not yet shown your proficiency as a worthy spellcaster. As %ra, you would surely be overcome in the challenge ahead. Go, now, expand your horizons, and return when you have attained renown as %Ra." %E %Cc Wiz 00020 "You amaze me, %p! How many times did I tell you that the way of a mage is an exacting one. One must use the world with care, lest one leave it in ruins and simplify the task of %n. "You must go back and show your worthiness. Do not return until you are truly ready for this quest. May %d guide you in this task." %E %Cc Wiz 00021 "Yes, %p, you truly are ready for this dire task. Listen, carefully, for what I tell you now will be of vital importance. "Since you left us to hone your skills in the world, we unexpectedly came under attack by the forces of %n. As you know, we thought %n had perished at the end of the last age, but, alas, this was not the case. "%nC sent an army of abominations against us. Among them was a minion, mindless and ensorcelled, and thus, in the confusion, it was able to penetrate our defenses. Alas, this creature has stolen %o and I fear it has delivered %o to %n. "Over the years, I had woven most of my power into this amulet, and thus, without it, I have but a shadow of my former power, and I fear that I shall soon perish. "You must travel to %i, and within its dungeons, find and overcome %n, and return %o to me. "Go now, with %d, and complete this quest before it is too late." %E %Cp Wiz 00025 "Beware, for %n is immune to most magical attacks." %E %Cp Wiz 00026 "To enter %i you must pass many traps." %E %Cp Wiz 00027 "%nC may be vulnerable to physical attacks." %E %Cp Wiz 00028 "%d will come to your aid when you call." %E %Cp Wiz 00029 "You must utterly destroy %n. He will pursue you otherwise." %E %Cp Wiz 00030 "%oC is a mighty artifact. With it you can destroy %n." %E %Cp Wiz 00031 "Go forth with the blessings of %d." %E %Cp Wiz 00032 "I will have my %gP watch for your return." %E %Cp Wiz 00033 "Feel free to take any items in that chest that might aid you." %E %Cp Wiz 00034 "You will know when %o is near. Proceed with care!" %E %Cc Wiz 00035 Wisps of fog swirl nearby. You feel that %ns lair is close. %E %Cp Wiz 00036 You believe that you may once again invade %i. %E %Cc Wiz 00040 You feel your mentor's presence; perhaps %o is nearby. %E %Cp Wiz 00041 The aura of %o tingles at the edge of your perception. %E %Cc Wiz 00050 "Ah, I recognize you, %p. So, %l has sent you to steal %o from me, hmmm? Well, %l is a fool to send such a mental weakling against me. "Your destruction, however, should make for good sport. In the end, you shall beg me to kill you!" %E %Cc Wiz 00051 "How nice of you to return, %p! I enjoyed our last meeting. Are you still hungry for more pain? "Come! Your soul, like %o, shall soon be mine to command." %E %Cp Wiz 00052 "I'm sure that your perseverance shall be the subject of innumerable ballads, but you shall not be around to hear them, I fear!" %E %Cp Wiz 00053 "Thief! %o belongs to me, now. I shall feed your living flesh to my minions." %E %Cp Wiz 00060 "Your puny powers are no match for me, fool!" %E %Cp Wiz 00061 "When you are defeated, your torment will last for a thousand years." %E %Cp Wiz 00062 "After your downfall, %p, I shall devour %l for dessert!" %E %Cp Wiz 00063 "Are you ready yet to beg for mercy? I could be lenient..." %E %Cp Wiz 00064 "Your soul shall join the enslaved multitude I command!" %E %Cp Wiz 00065 "Your lack of will is evident, and you shall die as a result." %E %Cp Wiz 00066 "Your faith in %d is for naught! Come, submit to me now!" %E %Cp Wiz 00067 "A mere %r is nothing compared to my skill!" %E %Cp Wiz 00068 "So, you are the best hope of %l? How droll." %E %Cp Wiz 00069 "Feel my power, %c! My victory is imminent!" %E %Cc Wiz 00070 As you touch %o, its comforting power infuses you with new energy. You feel as if you can detect others' thoughts flowing through it. Although you yearn to wear %o and attack the Wizard of Yendor, you know you must return it to its rightful owner, %l. %E %Cc Wiz 00080 %nC croaks out, as his body begins to shrivel up: I shall haunt your progress until the end of time. A thousand curses on you and %l. Then, the body bursts into a cloud of choking dust, and blows away. %E %Cc Wiz 00081 %lC notices %o in your possession, beams at you and says: I knew you could defeat %n and retrieve %o. We shall never forget this brave service. Take %o with you in your quest for the Amulet of Yendor. I can sense that it has attuned itself to you already. May %d guide you in your quest, and keep you from harm. %E %Cc Wiz 00082 "You are the keeper of %o now. It is time to recover the /other/ Amulet. %Z await your return through the magic portal which brought you here." %E %Cp Wiz 00090 "Come near, my %S, and share your adventures with me. So, have you succeeded in your quest for the Amulet of Yendor?" %E %Cc Wiz 00091 "Congratulations, %p. I always knew that if anyone could succeed in defeating the Wizard of Yendor and his minions, it would be you. "Go now, and take the Amulet to the astral plane. Once there, present the Amulet on the altar of %d. Along the way you shall pass through the four elemental planes. These planes are like nothing you have ever experienced before, so be prepared! "For this you were born, %s! I am very proud of you." %E # # General # %Cc - 00001 It is written in the Book of %d: After the Creation, the cruel god Moloch rebelled against the authority of Marduk the Creator. Moloch stole from Marduk the most powerful of all the artifacts of the gods, the Amulet of Yendor, and he hid it in the dark cavities of Gehennom, the Under World, where he now lurks, and bides his time. Your %G %d seeks to possess the Amulet, and with it to gain deserved ascendance over the other gods. You, a newly trained %r, have been heralded from birth as the instrument of %d. You are destined to recover the Amulet for your deity, or die in the attempt. Your hour of destiny has come. For the sake of us all: Go bravely with %d! %E %Cp - 00002 You receive a faint telepathic message from %l: Your help is urgently needed at %H! Look for a ...ic transporter. You couldn't quite make out that last message. %E %Cp - 00003 You again sense %l pleading for help. %E %Cp - 00004 You again sense %l demanding your attendance. %E # Completed the quest by returning with artifact, but not carrying # the Bell of Opening; quest leader lets you know that it is needed. #[ Should this be role-specific so that each leader has variant text? ] %Cp - 00005 "The silver bell which was hoarded by %n will be essential in locating the Amulet of Yendor." %E # # Angelic maledictions. # %Cp - 00010 "Repent, and thou shalt be saved!" %E %Cp - 00011 "Thou shalt pay for thine insolence!" %E %Cp - 00012 "Very soon, my child, thou shalt meet thy maker." %E %Cp - 00013 "The great %D has sent me to make you pay for your sins!" %E %Cp - 00014 "The wrath of %D is now upon you!" %E %Cp - 00015 "Thy life belongs to %D now!" %E %Cp - 00016 "Dost thou wish to receive thy final blessing?" %E %Cp - 00017 "Thou art but a godless void." %E %Cp - 00018 "Thou art not worthy to seek the Amulet." %E %Cp - 00019 "No one expects the Spanish Inquisition!" %E # # Demonic maledictions. # %Cp - 00030 "I first mistook thee for a statue, when I regarded thy head of stone." %E %Cp - 00031 "Come here often?" %E %Cp - 00032 "Doth pain excite thee? Wouldst thou prefer the whip?" %E %Cp - 00033 "Thinkest thou it shall tickle as I rip out thy lungs?" %E %Cp - 00034 "Eat slime and die!" %E %Cp - 00035 "Go ahead, fetch thy mama! I shall wait." %E %Cp - 00036 "Go play leapfrog with a herd of unicorns!" %E %Cp - 00037 "Hast thou been drinking, or art thou always so clumsy?" %E %Cp - 00038 "This time I shall let thee off with a spanking, but let it not happen again." %E %Cp - 00039 "I've met smarter (and prettier) acid blobs." %E %Cp - 00040 "Look! Thy bootlace is undone!" %E %Cp - 00041 "Mercy! Dost thou wish me to die of laughter?" %E %Cp - 00042 "Run away! Live to flee another day!" %E %Cp - 00043 "Thou hadst best fight better than thou canst dress!" %E %Cp - 00044 "Twixt thy cousin and thee, Medusa is the prettier." %E %Cp - 00045 "Methinks thou wert unnaturally stirred by yon corpse back there, eh, varlet?" %E %Cp - 00046 "Up thy nose with a rubber hose!" %E %Cp - 00047 "Verily, thy corpse could not smell worse!" %E %Cp - 00048 "Wait! I shall polymorph into a grid bug to give thee a fighting chance!" %E %Cp - 00049 "Why search for the Amulet? Thou wouldst but lose it, cretin." %E # # Banishment message (for converted hero) # %Cc - 00060 "You have betrayed all those who hold allegiance to %d, as you once did. My allegiance to %d holds fast and I cannot condone or accept what you have done. Leave this place. You shall never set foot at %H again. That which you seek is now lost forever, for without the Bell of Opening, you will never be able to enter the place where he who has the Amulet resides. Go now! You are banished from this place. %E # # TEST PATTERN # %Cc - 00099 %p: return(plname); %c: return(pl_character); %r: return((char *)rank_of(u.ulevel)); %R: return((char *)rank_of(MIN_QUEST_LEVEL)); %s: return((flags.female) ? "sister" : "brother" ); %S: return((flags.female) ? "daughter" : "son" ); %l: return((char *)ldrname()); %i: return(intermed()); %o: return(artiname()); %n: return((char *)neminame()); %g: return((char *)guardname()); %G: return((char *)align_gtitle(u.ualignbase[1])); %H: return((char *)homebase()); %a: return(Alignnam(u.ualignbase[1])); %A: return(Alignnam(u.ualign.type)); %d: return((char *)align_gname(u.ualignbase[1])); %D: return((char *)align_gname(A_LAWFUL)); %C: return("chaotic"); %N: return("neutral"); %L: return("lawful"); %x: return((Blind) ? "sense" : "see"); %Z: return("The Dungeons of Doom"); %%: return(percent_sign); a suffix: return an(root); A suffix: return An(root); C suffix: return capitalized(root); p suffix: return makeplural(root); P suffix: return makeplural(capitalized(root)); s suffix: return s_suffix(root); S suffix: return s_suffix(capitalized(root)); t suffix: return strip_the_prefix(root); %E nethack-3.4.3/dat/rumors.fal0100644000000000000000000005407707764735041014452 0ustar rootroot"So when I die, the first thing I will see in heaven is a score list?" 1st Law of Hacking: leaving is much more difficult than entering. 2nd Law of Hacking: first in, first out. 3rd Law of Hacking: the last blow counts most. 4th Law of Hacking: you will find the exit at the entrance. A chameleon imitating a mail daemon often delivers scrolls of fire. A cockatrice corpse is guaranteed to be untainted! A dead cockatrice is just a dead lizard. A dragon is just a snake that ate a scroll of fire. A fading corridor enlightens your insight. A glowing potion is too hot to drink. A good amulet may protect you against guards. A lizard corpse is a good thing to turn undead. A long worm can be defined recursively. So how should you attack it? A monstrous mind is a toy forever. A nymph will be very pleased if you call her by her real name: Lorelei. A ring of dungeon master control is a great find. A ring of extra ring finger is useless if not enchanted. A rope may form a trail in a maze. A staff may recharge if you drop it for awhile. A visit to the Zoo is very educational; you meet interesting animals. A wand of deaf is a more dangerous weapon than a wand of sheep. A wand of vibration might bring the whole cave crashing about your ears. A winner never quits. A quitter never wins. A wish? Okay, make me a fortune cookie! Afraid of mimics? Try to wear a ring of true seeing. All monsters are created evil, but some are more evil than others. Always attack a floating eye from behind! An elven cloak is always the height of fashion. Any small object that is accidentally dropped will hide under a larger object. Archeologists find more bones piles. Austin Powers says: My Mojo is back! Yeah, baby! Balrogs do not appear above level 20. Banana peels work especially well against Keystone Kops. Be careful when eating bananas. Monsters might slip on the peels. Better leave the dungeon; otherwise you might get hurt badly. Beware of the potion of nitroglycerin -- it's not for the weak of heart. Beware: there's always a chance that your wand explodes as you try to zap it! Beyond the 23rd level lies a happy retirement in a room of your own. Changing your suit without dropping your sword? You must be kidding! Close the door! You're letting the heat out! Cockatrices might turn themselves to stone faced with a mirror. Consumption of home-made food is strictly forbidden in this dungeon. Dark room? Your chance to develop your photographs! Dark rooms are not *completely* dark: just wait and let your eyes adjust... David London sez, "Hey guys, *WIELD* a lizard corpse against a cockatrice!" Death is just life's way of telling you you've been fired. Demi-gods don't need any help from the gods. Demons *HATE* Priests and Priestesses. Didn't you forget to pay? Didn't your mother tell you not to eat food off the floor? Direct a direct hit on your direct opponent, directing in the right direction. Do you want to make more money? Sure, we all do! Join the Fort Ludios guard! Does your boss know what you're doing right now? Don't bother wishing for things. You'll probably find one on the next level. Don't eat too much: you might start hiccoughing! Don't play NetHack at your work; your boss might hit you! Don't tell a soul you found a secret door, otherwise it isn't a secret anymore. Drinking potions of booze may land you in jail if you are under 21. Drop your vanity and get rid of your jewels! Pickpockets about! Eat 10 cloves of garlic and keep all humans at a two-square distance. Eels hide under mud. Use a unicorn to clear the water and make them visible. Elf has extra speed. Engrave your wishes with a wand of wishing. Eventually you will come to admire the swift elegance of a retreating nymph. Ever heard hissing outside? I *knew* you hadn't! Ever lifted a dragon corpse? Ever seen a leocrotta dancing the tengu? Ever seen your weapon glow plaid? Ever tamed a shopkeeper? Ever tried digging through a Vault Guard? Ever tried enchanting a rope? Floating eyes can't stand Hawaiian shirts. For any remedy there is a misery. Giant bats turn into giant vampires. Good day for overcoming obstacles. Try a steeplechase. Half Moon tonight. (At least it's better than no Moon at all.) Help! I'm being held prisoner in a fortune cookie factory! Housecats have nine lives, kittens only one. How long can you tread water? Hungry? There is an abundance of food on the next level. I guess you've never hit a mail daemon with the Amulet of Yendor... If you are the shopkeeper, you can take things for free. If you ask really nicely, the Wizard will give you the Amulet. If you can't learn to do it well, learn to enjoy doing it badly. If you thought the Wizard was bad, just wait till you meet the Warlord! If you turn blind, don't expect your dog to be turned into a seeing-eye dog. If you want to feel great, you must eat something real big. If you want to float, you'd better eat a floating eye. If your ghost kills a player, it increases your score. Increase mindpower: Tame your own ghost! It furthers one to see the great man. It's easy to overlook a monster in a wood. Just below any trap door there may be another one. Just keep falling! Katanas are very sharp; watch you don't cut yourself. Keep a clear mind: quaff clear potions. Kicking the terminal doesn't hurt the monsters. Killer bees keep appearing till you kill their queen. Killer bunnies can be tamed with carrots only. Latest news? Put `rec.games.roguelike.nethack' in your .newsrc! Learn how to spell. Play NetHack! Leprechauns hide their gold in a secret room. Let your fingers do the walking on the yulkjhnb keys. Let's face it: this time you're not going to win. Let's have a party, drink a lot of booze. Liquor sellers do not drink; they hate to see you twice. Lunar eclipse tonight. May as well quit now! Meeting your own ghost decreases your luck considerably! Money to invest? Take it to the local branch of the Magic Memory Vault! Monsters come from nowhere to hit you everywhere. Monsters sleep because you are boring, not because they ever get tired. Most monsters prefer minced meat. That's why they are hitting you! Most of the bugs in NetHack are on the floor. Much ado Nothing Happens. Multi-player NetHack is a myth. NetHack is addictive. Too late, you're already hooked. Never ask a shopkeeper for a price list. Never burn a tree, unless you like getting whacked with a +5 shovel. Never eat with glowing hands! Never mind the monsters hitting you: they just replace the charwomen. Never play leapfrog with a unicorn. Never step on a cursed engraving. Never swim with a camera: there's nothing to take pictures of. Never teach your pet rust monster to fetch. Never trust a random generator in magic fields. Never use a wand of death. No level contains two shops. The maze is no level. So... No part of this fortune may be reproduced, stored in a retrieval system, ... Not all rumors are as misleading as this one. Nymphs and nurses like beautiful rings. Nymphs are blondes. Are you a gentleman? Offering a unicorn a worthless piece of glass might prove to be fatal! Old hackers never die: young ones do. One has to leave shops before closing time. One homunculus a day keeps the doctor away. One level further down somebody is getting killed, right now. Only a wizard can use a magic whistle. Only adventurers of evil alignment think of killing their dog. Only chaotic evils kill sleeping monsters. Only real trappers escape traps. Only real wizards can write scrolls. Operation OVERKILL has started now. Ouch. I hate when that happens. PLEASE ignore previous rumor. Polymorph into an ettin; meet your opponents face to face to face. Praying will frighten demons. Row (3x) that boat gently down the stream, Charon (4x), death is but a dream. Running is good for your legs. Screw up your courage! You've screwed up everything else. Seepage? Leaky pipes? Rising damp? Summon the plumber! Segmentation fault (core dumped). Shopkeepers are insured by Croesus himself! Shopkeepers sometimes die from old age. Some mazes (especially small ones) have no solutions, says man 6 maze. Some questions the Sphynx asks just *don't* have any answers. Sometimes "mu" is the answer. Sorry, no fortune this time. Better luck next cookie! Spare your scrolls of make-edible until it's really necessary! Stormbringer doesn't steal souls. People steal souls. Suddenly, the dungeon will collapse... Taming a mail daemon may cause a system security violation. The crowd was so tough, the Stooges won't play the Dungeon anymore, nyuk nyuk. The leprechauns hide their treasure in a small hidden room. The longer the wand the better. The magic word is "XYZZY". The meek shall inherit your bones files. The mines are dark and deep, and I have levels to go before I sleep. The use of dynamite is dangerous. There are no worms in the UNIX version. There is a trap on this level! They say that Demogorgon, Asmodeus, Orcus, Yeenoghu & Juiblex is no law firm. They say that Geryon has an evil twin, beware! They say that Medusa would make a terrible pet. They say that NetHack bugs are Seldon planned. They say that NetHack comes in 256 flavors. They say that NetHack is just a computer game. They say that NetHack is more than just a computer game. They say that NetHack is never what it used to be. They say that a baby dragon is too small to hurt or help you. They say that a black pudding is simply a brown pudding gone bad. They say that a black sheep has 3 bags full of wool. They say that a blank scroll is like a blank check. They say that a cat named Morris has nine lives. They say that a desperate shopper might pay any price in a shop. They say that a diamond dog is everybody's best friend. They say that a dwarf lord can carry a pick-axe because his armor is light. They say that a floating eye can defeat Medusa. They say that a fortune only has 1 line and you can't read between it. They say that a fortune only has 1 line, but you can read between it. They say that a fountain looks nothing like a regularly erupting geyser. They say that a gold doubloon is worth more than its weight in gold. They say that a grid bug won't pay a shopkeeper for zapping you in a shop. They say that a gypsy could tell your fortune for a price. They say that a hacker named Alice once level teleported by using a mirror. They say that a hacker named David once slew a giant with a sling and a rock. They say that a hacker named Dorothy once rode a fog cloud to Oz. They say that a hacker named Mary once lost a white sheep in the mazes. They say that a helm of brilliance is not to be taken lightly. They say that a hot dog and a hell hound are the same thing. They say that a lamp named Aladdin's Lamp contains a djinni with 3 wishes. They say that a large dog named Lassie will lead you to the amulet. They say that a long sword is not a light sword. They say that a manes won't mince words with you. They say that a mind is a terrible thing to waste. They say that a plain nymph will only wear a wire ring in one ear. They say that a plumed hat could be a previously used crested helmet. They say that a potion of oil is difficult to grasp. They say that a potion of yogurt is a cancelled potion of sickness. They say that a purple worm is not a baby purple dragon. They say that a quivering blob tastes different than a gelatinous cube. They say that a runed broadsword named Stormbringer attracts vortices. They say that a scroll of summoning has other names. They say that a shaman can bestow blessings but usually doesn't. They say that a shaman will bless you for an eye of newt and wing of bat. They say that a shimmering gold shield is not a polished silver shield. They say that a spear will hit a neo-otyugh. (Do YOU know what that is?) They say that a spotted dragon is the ultimate shape changer. They say that a stethoscope is no good if you can only hear your heartbeat. They say that a succubus named Suzy will sometimes warn you of danger. They say that a wand of cancellation is not like a wand of polymorph. They say that a wood golem named Pinocchio would be easy to control. They say that after killing a dragon it's time for a change of scenery. They say that an amulet of strangulation is worse than ring around the collar. They say that an attic is the best place to hide your toys. They say that an axe named Cleaver once belonged to a hacker named Beaver. They say that an eye of newt and a wing of bat are double the trouble. They say that an incubus named Izzy sometimes makes women feel sensitive. They say that an opulent throne room is rarely a place to wish you'd be in. They say that an unlucky hacker once had a nose bleed at an altar and died. They say that and they say this but they never say never, never! They say that any quantum mechanic knows that speed kills. They say that applying a unicorn horn means you've missed the point. They say that blue stones are radioactive, beware. They say that building a dungeon is a team effort. They say that chaotic characters never get a kick out of altars. They say that collapsing a dungeon often creates a panic. They say that counting your eggs before they hatch shows that you care. They say that dipping a bag of tricks in a fountain won't make it an icebox. They say that dipping an eel and brown mold in hot water makes bouillabaisse. They say that donating a doubloon is extremely pious charity. They say that dungeoneers prefer dark chocolate. They say that eating royal jelly attracts grizzly owlbears. They say that eggs, pancakes and juice are just a mundane breakfast. They say that everyone knows why Medusa stands alone in the dark. They say that everyone wanted rec.games.hack to undergo a name change. They say that finding a winning strategy is a deliberate move on your part. They say that finding worthless glass is worth something. They say that fortune cookies are food for thought. They say that gold is only wasted on a pet dragon. They say that good things come to those that wait. They say that greased objects will slip out of monsters' hands. They say that if you can't spell then you'll wish you had a spellbook. They say that if you live by the sword, you'll die by the sword. They say that if you play like a monster you'll have a better game. They say that if you sleep with a demon you might awake with a headache. They say that if you step on a crack you could break your mother's back. They say that if you're invisible you can still be heard! They say that if you're lucky you can feel the runes on a scroll. They say that in the big picture gold is only small change. They say that in the dungeon it's not what you know that really matters. They say that in the dungeon moon rocks are really dilithium crystals. They say that in the dungeon the boorish customer is never right. They say that in the dungeon you don't need a watch to tell time. They say that in the dungeon you need something old, new, burrowed and blue. They say that in the dungeon you should always count your blessings. They say that iron golem plate mail isn't worth wishing for. They say that it takes four quarterstaffs to make one staff. They say that it's not over till the fat ladies sing. They say that it's not over till the fat lady shouts `Off with its head'. They say that kicking a heavy statue is really a dumb move. They say that kicking a valuable gem doesn't seem to make sense. They say that leprechauns know Latin and you should too. They say that minotaurs get lost outside of the mazes. They say that most trolls are born again. They say that naming your cat Garfield will make you more attractive. They say that no one knows everything about everything in the dungeon. They say that no one plays NetHack just for the fun of it. They say that no one really subscribes to rec.games.roguelike.nethack. They say that no one will admit to starting a rumor. They say that nurses sometimes carry scalpels and never use them. They say that once you've met one wizard you've met them all. They say that one troll is worth 10,000 newts. They say that only David can find the zoo! They say that only angels play their harps for their pets. They say that only big spenders carry gold. They say that orc shamans are healthy, wealthy and wise. They say that playing NetHack is like walking into a death trap. They say that problem breathing is best treated by a proper diet. They say that quaffing many potions of levitation can give you a headache. They say that queen bees get that way by eating royal jelly. They say that reading a scare monster scroll is the same as saying Elbereth. They say that real hackers always are controlled. They say that real hackers never sleep. They say that shopkeepers are insured by Croesus himself! They say that shopkeepers never carry more than 20 gold pieces, at night. They say that shopkeepers never sell blessed potions of invisibility. They say that soldiers wear kid gloves and silly helmets. They say that some Kops are on the take. They say that some guards' palms can be greased. They say that some monsters may kiss your boots to stop your drum playing. They say that sometimes you can be the hit of the party when playing a horn. They say that the NetHack gods generally welcome your sacrifices. They say that the Three Rings are named Vilya, Nenya and Narya. They say that the Wizard of Yendor has a death wish. They say that the `hair of the dog' is sometimes an effective remedy. They say that the best time to save your game is now before it's too late. They say that the biggest obstacle in NetHack is your mind. They say that the gods are angry when they hit you with objects. They say that the priesthood are specially favored by the gods. They say that the way to make a unicorn happy is to give it what it wants. They say that there are no black or white stones, only gray. They say that there are no skeletons hence there are no skeleton keys. They say that there is a clever rogue in every hacker just dying to escape. They say that there is no such thing as free advice. They say that there is only one way to win at NetHack. They say that there once was a fearsome chaotic samurai named Luk No. They say that there was a time when cursed holy water wasn't water. They say that there's no point in crying over a gray ooze. They say that there's only hope left after you've opened Pandora's box. They say that trap doors should always be marked `Caution: Trap Door'. They say that using an amulet of change isn't a difficult operation. They say that water walking boots are better if you are fast like Hermes. They say that when you wear a circular amulet you might resemble a troll. They say that when you're hungry you can get a pizza in 30 moves or it's free. They say that when your god is angry you should try another one. They say that wielding a unicorn horn takes strength. They say that with speed boots you never worry about hit and run accidents. They say that you can defeat a killer bee with a unicorn horn. They say that you can only cross the River Styx in Charon's boat. They say that you can only kill a lich once and then you'd better be careful. They say that you can only wish for things you've already had. They say that you can train a cat by talking gently to it. They say that you can train a dog by talking firmly to it. They say that you can trust your gold with the king. They say that you can't wipe your greasy bare hands on a blank scroll. They say that you cannot trust scrolls of rumor. They say that you could fall head over heels for an energy vortex. They say that you need a key in order to open locked doors. They say that you need a mirror to notice a mimic in an antique shop. They say that you really can use a pick-axe unless you really can't. They say that you should always store your tools in the cellar. They say that you should be careful while climbing the ladder to success. They say that you should call your armor `rustproof'. They say that you should name your dog Spuds to have a cool pet. They say that you should name your weapon after your first monster kill. They say that you should never introduce a rope golem to a succubus. They say that you should never sleep near invisible ring wraiths. They say that you should never try to leave the dungeon with a bag of gems. They say that you should remove your armor before sitting on a throne. This fortune cookie is copy protected. This fortune cookie is the property of Fortune Cookies, Inc. This release contains 10% recycled material. Time stands still as the succubus changes her calendar to January 1, 2000. Tired? Try a scroll of charging on yourself. To achieve the next higher rating, you need 3 more points. To reach heaven, escape the dungeon while wearing a ring of levitation. Tourists wear shirts loud enough to wake the dead. Try calling your katana Moulinette. Ulch! That meat was painted! Unfortunately, this message was left intentionally blank. Using a morning star in the evening has no effect. Waltz, dumb nymph, for quick jigs vex. Want a hint? Zap a wand of make invisible on your weapon! Want to ascend in a hurry? Apply at Gizmonic Institute. Wanted: shopkeepers. Send a scroll of mail to Mage of Yendor/Level 35/Dungeon. Warning: fortune reading can be hazardous to your health. We have new ways of detecting treachery... Wet towels make great weapons! What a pity, you cannot read it! Whatever can go wrong, will go wrong. When a piercer drops in on you, you will be tempted to hit the ceiling! When in a maze follow the right wall and you will never get lost. When you have a key, you don't have to wait for the guard. Why are you wasting time reading fortunes? Wish for a master key and open the Magic Memory Vault! Wizard expects every monster to do its duty. Wow! You could've had a potion of fruit juice! Yet Another Silly Message (YASM). You are destined to be misled by a fortune. You can get a genuine Amulet of Yendor by doing the following: --More-- You can make holy water by boiling the hell out of it. You can protect yourself from black dragons by doing the following: --More-- You can't get by the snake. You choke on the fortune cookie. --More-- You feel like someone is pulling your leg. You have to outwit the Sphynx or pay her. You hear the fortune cookie's hissing! You may get rich selling letters, but beware of being blackmailed! You offend Shai-Hulud by sheathing your crysknife without having drawn blood. You swallowed the fortune! You want to regain strength? Two levels ahead is a guesthouse! You will encounter a tall, dark, and gruesome creature... nethack-3.4.3/dat/rumors.tru0100644000000000000000000004727607764735041014525 0ustar rootrootA blindfold can be very useful if you're telepathic. A candelabrum affixed with seven candles shows the way with a magical light. A crystal plate mail will not rust. A katana might slice a worm in two. A magic vomit pump could be useful for gourmands. A nymph knows how to unlock chains. A potion of blindness lets you see invisible things. A priest can get the gods to listen easily. A priestess and a virgin you might be, but that unicorn won't care. A ring of conflict is a bad thing if there is a nurse in the room. A short sword is not as good as a long sword. A succubus will go farther than a nymph. A wand can exorcize a past explorer's ghost. Acid blobs should be attacked bare-handed. Affairs with nymphs are often very expensive. Afraid of nymphs? Wear a ring of adornment. Afraid of your valuables being stolen? Carry more junk! Always be aware of the phase of the moon! Always sweep the floor before engraving important messages. Amulets of Yendor are hard to make. Even for a wand of wishing. An elven cloak protects against magic. An umber hulk can be a confusing sight. As Crom is my witness, I'll never go hungry again! Asking about monsters may be very useful. Attack long worms from the rear -- that is so much safer! Attacking an eel where there is none is usually a fatal mistake! Bandaging wounds helps keep up appearances. Bashing monsters with a bow is not such a good idea. Be careful! The Wizard may plan an ambush! Be nice to a nurse: Put away your weapon and take off your clothes. Being digested is a painfully slow process. Blank scrolls make more interesting reading. Blind? Catch a floating eye! Booksellers never read scrolls; they might get carried away. Chemistry 101: Never pour water into acid. Concise conquest: Control, confuse, conjure, condemn. Conserve energy, turn off the lights. Digging up a grave could be a bad idea... Dilithium crystals are rare indeed. Dogs are attracted by the smell of tripe. Dogs are superstitious; they never step on cursed items. Dogs of ghosts aren't angry, just hungry. Don't forget! Large dogs are MUCH harder to kill than little dogs. Don't mess with shopkeepers, or you'll get the Guild after you. Dragons never whip their children; they wouldn't feel it! Eat your carrots. They're good for your eyes. Eating a freezing sphere is like eating a yeti. Eating a killer bee is like eating a scorpion. Eating a tengu is like eating a nymph. Eating a wraith is a rewarding experience! Eating unpaid leprechauns may be advantageous. Elbereth has quite a reputation around these parts. Elf corpses are incompatible with the sandman, and at times the gods as well. Elven cloaks cannot rust. Even evil players have a guardian angel. Ever fought with an enchanted tooth? Ever tried reading while confused? Ever tried to put a troll into a large box? Ever wondered why one would want to dip something in a potion? Expensive cameras have penetrating flash lights. Extra staircases lead to extra levels. Fiery letters might deter monsters. For a good time engrave `Elbereth'. Gems are too precious to be thrown away carelessly. Getting hungry? Stop wearing rings! Getting too warm? Take off that Amulet of Yendor and stay away from the exit! Gods expect the best from their priesthood. Gods look down their noses at demigods. Got a question? Try rec.games.roguelike.nethack. Grave robbers sometimes get rich. Guy Montag keeps his scrolls in a bag. Handle your flasks carefully -- there might be a ghost inside! Holy water has many uses. Horses trust their riders, even when not so deserved. Hunger is a confusing experience for a dog! I once knew a hacker who ate too fast and choked to death. I smell a maze of twisty little passages. I wish I never wished a wand of wishing. (Wishful thinking.) I wouldn't advise playing catch with a giant. I'm watching you. -- The Wizard of Yendor Ice boxes keep your food fresh. If you are being punished, it's done with a deadly weapon. If you kill the Wizard, you get promoted to demi-god. If you need a wand of digging, kindly ask the minotaur. If you want to hit, use a dagger. If you want to rob a shop, train your dog. If you're lost, try buying a map next time you're in a shop. Inside a shop you better take a look at the price tags before buying anything. It is bad manners to use a wand in a shop. It is dangerous to visit a graveyard at midnight. It is not always a good idea to whistle for your dog. It is rumored that the Wizard has hired some help. It is the letter 'c' and not 'e' that changes status to statue. It might be a good idea to offer the unicorn a ruby. It would be peculiarly sad were your dog turned to stone. It's a `d' eats `d' world. Keep your armors away from rust. Keep your weaponry away from acids. Kill a unicorn of your color and you kill your luck. Leather is waterproof. Ever see a cow with an umbrella? Leprechauns are the most skilled cutpurses in this dungeon. Lizard corpses protect against cockatrices. Money lost, little lost; honor lost, much lost; pluck lost, all lost. Most monsters can't swim. Music hath charms to affect the stubborn drawbridge. Music hath charms to soothe the savage beast. Never attack a guard. Never ride a long worm. Never use your best weapon to engrave a curse. No easy fighting with a heavy load! Nurses are trained to touch naked persons: they don't harm them. Nymphs can unlink more than your chain mail. Once your little dog will be a big dog, and you will be proud of it. Only female monsters can lay eggs. Opening a tin is difficult, especially when you attempt it bare handed! Orcs and killer bees share their lifestyle. Orcs do not procreate in dark rooms. Plain nymphs are harmless. Playing AD&D may be helpful. Playing Gauntlet might be enlightening in some situations. Playing billiards pays when you are in a shop. Polymorphing a shopkeeper might make you safer. Polymorphing your dog probably makes you safer. Potions don't usually mix, but sometimes... Psst! It's done with mirrors! Put on a ring of teleportation: it will take you away from onslaught. Rays aren't boomerangs, of course, but still... Read the manual before entering the cave -- you might get killed otherwise. Reading Herbert might be enlightening in one case. Reading Tolkien might help you. Reading scrolls after drinking booze can give confusing results. Riding a dragon can be an uplifting experience. Rust monsters love water. There are potions they hate, however. Sacks protect contents from temperatures up to 452 degrees fahrenheit. Scrolls fading? It's not the heat, it's the humidity. Shopkeepers accept credit cards, as long as you pay cash. Shopkeepers can spot a tourist a mile away with those Hawaiian shirts. Shopkeepers can't tell identical twins apart. Shopkeepers don't read, so what use is engraving in a shop? Shopkeepers have incredible patience. Shopkeepers might raise their prices for tourists. Shopkeepers value money more than revenge. Some monsters can be tamed. I once saw a hacker with a tame dragon! Someone once said that what goes up < might come down >. Someone's been spiking the pits! Sometimes monsters are more likely to fight each other than attack you. Spinach, carrot, and jelly -- a meal fit for a nurse! Tainted meat is even more sickening than poison! Telepathy is just a trick: once you know how to do it, it's easy. The Leprechaun Gold Tru$t is no division of the Magic Memory Vault. The Wizard finds death to be quite an experience. The best equipment for your work is, of course, the most expensive. The gods don't appreciate pesky priesthood. The gods will get angry if you kill your dog. The magic marker is mightier than the sword. The moon is not the only heavenly body to influence this game. The orc swings his orcish broadsword named Elfrist at you. You die... The secret of wands of Nothing Happens: try again! There has always been something mystical about mirrors. There is a Mastermind deep in the dungeon. There is a big treasure hidden in the zoo! There is more magic in this cave than meets the eye. There is no harm in praising a large dog. There is nothing like eating a mimic. There once was a Knight named Lancelot who liked to ride with his lance a lot. They say a gelatinous cube can paralyze you... They say that Juiblex is afraid of a wand of digging. They say that Medusa would like to put you on a pedestal. They say that Vlad lives!!! ... in the mazes. They say that `Elbereth' is often written about. They say that a bag of holding can't hold everything. They say that a blessed tin of quasit meat is a quick meal. They say that a cat avoids traps. They say that a cave spider will occasionally eat cave spider eggs. They say that a clever wizard can have stats: 18/** 24 18 24 24 24. They say that a clove of garlic makes a good talisman if handled right. They say that a cursed scroll of teleportation could land you in trouble. They say that a diamond is another kind of luck stone. They say that a dog can be trained to fetch objects. They say that a gelatinous cube makes a healthy breakfast. They say that a giant gets strong by eating right, try it! They say that a grid bug won't hit you when you cross it. They say that a lembas wafer is a very light snack. They say that a loadstone has a strange attraction and is not bad luck. They say that a lock pick by any other name is still a lock pick. They say that a lucky amulet will block poisoned arrows. They say that a mirror will freeze a floating eye but you can still see it. They say that a neutral character might get Giantslayer. They say that a polymorph trap is magic and magic protection prevents it. They say that a potion of healing can cancel a potion of sickness. They say that a potion of monster detection sometimes works both ways. They say that a sink looks different from high above the floor. They say that a summoned demon could improve your game. They say that a tin of wraith meat is a rare dining experience. They say that a unicorn might bring you luck. They say that a wand of cancellation is like a wand of polymorph. They say that a wand of locking can close more than just doors. They say that a wand of polymorph can change your game. They say that a wizard is even more powerful the second time around. They say that a xorn knows of no obstacles when pursuing you. They say that abusing a credit card could shock you sooner or later. They say that amulets, like most things, can be deadly or life saving. They say that an altar can identify blessings. They say that an ooze will bite your boots and a rockmole will eat them. They say that an unlucky hacker was once killed by an exploding tin. They say that antique dealers are always interested in precious stones. They say that bandaging one's wounds helps to keep up one's appearance. They say that booze can be diluted but not cancelled. They say that by listening carefully, you can hear a secret door! They say that carrots and carrot juice may improve your vision. They say that cave spiders are not considered expensive health food. They say that demigods must leave behind their prized earthly possessions. They say that disturbing a djinni can be a costly mistake. They say that dragon scales can be quite enchanting. They say that dropping coins into a fountain will not grant you a wish. They say that dwarves lawfully mind their own business. They say that eating a bat corpse will make you batty, for a while. They say that eating a cram ration is a smart move. They say that eating blue jelly is cool if you don't fight the feeling. They say that escaping a dungeon is only the beginning of the end. They say that feeling an unexpected draft of air is sort of a breakthrough. They say that finding a cursed gray stone is always bad luck. They say that gaining a level is an experience that can raise your sights. They say that garter snake meat rarely tastes good but it's still healthy. They say that gauntlets of dexterity have a hidden enchanted touch. They say that going to heaven is just another way of escaping the dungeon. They say that golden nagas are law-abiding denizens as long as you are too. They say that gremlins can make you feel cooler than you are now. They say that grid bugs only exist in a strictly Cartesian sense. They say that hackers often feel jumpy about eating nymphs. They say that having polymorph control won't shock you. They say that if it's hard getting your food down another bite could kill. They say that if you don't wear glasses why bother with carrots? They say that if you notice a loose board beneath you, don't step on it. They say that if you start at the bottom the only place to go is up. They say that if you teleport to heaven you're presumed to be dead already. They say that in a shop you can be charged for old charges. They say that in lighter moments you could think of ways to pass a stone. They say that in the dungeon breaking a mirror can be seven years bad luck. They say that in the dungeon you don't usually have any luck at all. They say that in time a blessed luckstone can make your god happy. They say that it is easier to kill the Wizard than to make him stand still. They say that it only takes 1 zorkmid to meet the Kops. They say that it's a blast when you mix the right potions together. They say that it's not blind luck if you catch a glimpse of Medusa. They say that killing a shopkeeper brings bad luck. They say that monsters never step on a scare monster scroll. They say that most monsters find flute recitals extremely boring. They say that mummy corpses are not well preserved. They say that naturally a wand of wishing would be heavily guarded. They say that no one notices the junk underneath a boulder. They say that nobody expects a unicorn horn to rust. They say that nobody knows if an explorer can live forever. Do you? They say that nothing can change the fact that some potions contain a djinni. They say that nothing can change the fact that some potions contain a ghost. They say that nymphs always fall for rock'n'roll, try it! They say that once an Olog-Hai is canned it never shows its face again. They say that once upon a time xans would never scratch your boots. They say that only an experienced wizard can do the tengu shuffle. They say that only chaotics can kill shopkeepers and get away with it. They say that only female monsters can lay eggs. They say that playing a horn really bad is really good. They say that rubbing a glowing potion does not make it a magic lamp. They say that scalpels become dull because they're not athames. They say that shopkeepers don't like pick-axes. They say that shopkeepers don't mind you bringing your pets in the shop. They say that shopkeepers don't usually mind if you sneak into a shop. They say that shopkeepers often have a large amount of money in their purses. They say that shopkeepers often remember things that you might forget. They say that sinks and armor don't mix, take your cloak off now! They say that sinks run hot and cold and many flavors in between. They say that snake charmers aren't charismatic, just musical. They say that soldiers are always prepared and usually protected. They say that some eggs could hatch in your pack, lucky or not. They say that some fire ants will make you a hot meal. They say that some horns play hot music and others are too cool for words. They say that some humanoids are nonetheless quite human. They say that some shopkeepers consider gems to be family heirlooms. They say that some shopkeepers recognize gems but they won't tell you. They say that some stones are much much heavier than others. They say that some yetis are full of hot air. They say that something very special would be in a well-protected place. They say that speed boots aren't fast enough to let you walk on water. They say that teleport traps are the devil's work. They say that tengu don't wear rings, why should you? They say that tengu never steal gold although they would be good at it. They say that that which was stolen once can be stolen again, ask any nymph. They say that the Delphic Oracle knows that lizard corpses aren't confusing. They say that the Hand of Elbereth can hold up your prayers. They say that the Leprechaun King is rich as Croesus. They say that the Wizard of Yendor is schizophrenic and suicidal. They say that the experienced character knows how to convert an altar. They say that the gods are happy when they drop objects at your feet. They say that the idea of invisible Nazguls has a certain ring to it. They say that the lady of the lake now lives in a fountain somewhere. They say that the local shopkeeper frowns upon the rude tourist. They say that the only door to the vampire's tower is on its lowest level. They say that the only good djinni is a grateful djinni. They say that the thing about genocide is that it works both ways. They say that the unicorn horn rule is if it ain't broke then don't fix it. They say that the view from a fog cloud is really very moving. They say that the walls in shops are made of extra hard material. They say that there are at least 15 ways to lose a pair of levitation boots. They say that throwing glass gems is the same as throwing rocks. They say that trespassing a boulder is probably beneath you. They say that unicorns are fond of precious gems. They say that prayer at an altar can sometimes make the water there holy. They say that what goes down the drain might come back up. They say that wielded, a long sword named Fire Brand makes you feel cooler. They say that wielded, a long sword named Frost Brand makes you hot stuff. They say that wiping its face is impossible for a floating eye. They say that with a floating eye you could see in the dark. They say that you are lucky if you can get a unicorn to catch a ruby. They say that you are what you eat. They say that you can find named weapons at an altar if you're lucky. They say that you can safely touch cockatrice eggs but why bother? They say that you can't break an amulet of reflection. They say that you don't always get what you wish for. They say that you should always be prepared for a final challenge. They say that you should ask a dwarf to let you into a locked shop. They say that you should pray for divine inspiration. They say that you should religiously give your gold away. They say that you will never get healthy by eating geckos. They say that zapping yourself with a wand of undead turning is stupid. They say the Wizard's castle is booby-trapped! They say the gods get angry if you kill your dog. They say the gods get angry if you pray too much. They say there is a powerful magic item hidden in a castle deep down! Those who wield a cockatrice corpse have a rocky road ahead of them. Throwing food at a wild dog might tame him. To a full belly all food is bad. Trolls are described as rubbery: they keep bouncing back. Try the fall-back end-run play against ghosts. Try using your magic marker on wet scrolls. Two wrongs don't make a right, but three lefts do. Valkyries come from the north, and have commensurate abilities. Vampires hate garlic. Vault guards never disturb their Lords. Vegetarians enjoy lichen and seaweed. Visitors are requested not to apply genocide to shopkeepers. Watch out, the Wizard might come back. Water traps have no effect on dragons. What is a cockatrice going to eat when it gets hungry? Who needs an apron if they're made of glass? Why do you suppose they call them MAGIC markers? Why do you think they call them mercenaries? Why would anybody in his sane mind engrave "Elbereth"? Wishing too much may bring you too little. You can't bribe soldier ants. You can't leave a shop through the back door: there isn't one! You may discover a fine spirit inside a potion bottle. You may want to dip into a potion of bottled blessings. You might be able to bribe a demon lord. You might trick a shopkeeper if you're invisible. You should certainly learn about quantum mechanics. You're going into the morgue at midnight??? Your dog knows what to eat; maybe you should take lessons. Zap yourself and see what happens... Zapping a wand of undead turning might bring your dog back to life. nethack-3.4.3/dat/sokoban.des0100644000000000000000000003345107764735041014561 0ustar rootroot# SCCS Id: @(#)sokoban.des 3.4 1999/03/15 # Copyright (c) 1998-1999 by Kevin Hugo # NetHack may be freely redistributed. See license for details. # # In case you haven't played the game Sokoban, you'll learn # quickly. This branch isn't particularly difficult, just time # consuming. Some players may wish to skip this branch. # # The following actions are currently permitted without penalty: # Carrying or throwing a boulder already in inventory # (player or nonplayer). # Teleporting boulders. # Digging in the floor. # The following actions are permitted, but with a luck penalty: # Breaking boulders. # Stone-to-fleshing boulders. # Creating new boulders (e.g., with a scroll of earth). # Jumping. # Being pulled by a thrown iron ball. # Hurtling through the air from Newton's 3rd law. # Squeezing past boulders when naked or as a giant. # These actions are not permitted: # Moving diagonally between two boulders and/or walls. # Pushing a boulder diagonally. # Picking up boulders (player or nonplayer). # Digging or walking through walls. # Teleporting within levels or between levels of this branch. # Using cursed potions of gain level. # Escaping a pit/hole (e.g., by flying, levitation, or # passing a dexterity check). # Bones files are not permitted. ### Bottom (first) level of Sokoban ### MAZE:"soko4-1",' ' FLAGS:noteleport,hardfloor GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP ------ ----- |....| |...| |....----...| |...........| |..|-|.|-|..| ---------|.--- |......|.....| |..----|.....| --.| |.....| |.|---|.....| |...........| |..|--------- ---- ENDMAP BRANCH:(06,04,06,04),(0,0,0,0) STAIR:(06,06),up REGION:(00,00,13,12),lit,"ordinary" NON_DIGGABLE:(00,00,13,12) NON_PASSWALL:(00,00,13,12) # Boulders OBJECT:'`',"boulder",(02,02) OBJECT:'`',"boulder",(02,03) # OBJECT:'`',"boulder",(10,02) OBJECT:'`',"boulder",(09,03) OBJECT:'`',"boulder",(10,04) # OBJECT:'`',"boulder",(08,07) OBJECT:'`',"boulder",(09,08) OBJECT:'`',"boulder",(09,09) OBJECT:'`',"boulder",(08,10) OBJECT:'`',"boulder",(10,10) # Traps TRAP:"pit",(03,06) TRAP:"pit",(04,06) TRAP:"pit",(05,06) TRAP:"pit",(02,08) TRAP:"pit",(02,09) TRAP:"pit",(04,10) TRAP:"pit",(05,10) TRAP:"pit",(06,10) TRAP:"pit",(07,10) # A little help OBJECT:'?',"earth",(02,11) OBJECT:'?',"earth",(03,11) # Random objects OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'=',random,random OBJECT:'/',random,random MAZE:"soko4-2",' ' FLAGS:noteleport,hardfloor GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP -------- ------ |.|....|-|....| |.|-..........| |.||....|.....| |.||....|.....| |.|-----|.----- |.| |......| |.-----|......| |.............| |..|---|......| ---- -------- ENDMAP BRANCH:(03,01,03,01),(0,0,0,0) STAIR:(01,01),up REGION:(00,00,14,10),lit,"ordinary" NON_DIGGABLE:(00,00,14,10) NON_PASSWALL:(00,00,14,10) # Boulders OBJECT:'`',"boulder",(05,02) OBJECT:'`',"boulder",(06,02) OBJECT:'`',"boulder",(06,03) OBJECT:'`',"boulder",(07,03) # OBJECT:'`',"boulder",(09,05) OBJECT:'`',"boulder",(10,03) OBJECT:'`',"boulder",(11,02) OBJECT:'`',"boulder",(12,03) # OBJECT:'`',"boulder",(07,08) OBJECT:'`',"boulder",(08,08) OBJECT:'`',"boulder",(09,08) OBJECT:'`',"boulder",(10,08) # Traps TRAP:"pit",(01,02) TRAP:"pit",(01,03) TRAP:"pit",(01,04) TRAP:"pit",(01,05) TRAP:"pit",(01,06) TRAP:"pit",(01,07) TRAP:"pit",(03,08) TRAP:"pit",(04,08) TRAP:"pit",(05,08) TRAP:"pit",(06,08) # A little help OBJECT:'?',"earth",(01,09) OBJECT:'?',"earth",(02,09) # Random objects OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'=',random,random OBJECT:'/',random,random ### Second level ### MAZE:"soko3-1",' ' FLAGS:noteleport GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP ----------- ----------- |....|....|-- |.........| |....|......| |.........| |.........|-- |.........| |....|....| |.........| |-.--------- |.........| |....|.....| |.........| |....|.....| |.........| |..........| |.........| |....|.....|---------------+| |....|......................| ----------------------------- ENDMAP STAIR:(11,02),down STAIR:(23,04),up DOOR:locked,(27,09) REGION:(00,00,28,11),lit,"ordinary" NON_DIGGABLE:(00,00,28,11) NON_PASSWALL:(00,00,28,11) # Boulders OBJECT:'`',"boulder",(03,02) OBJECT:'`',"boulder",(04,02) # OBJECT:'`',"boulder",(06,02) OBJECT:'`',"boulder",(06,03) OBJECT:'`',"boulder",(07,02) # OBJECT:'`',"boulder",(03,06) OBJECT:'`',"boulder",(02,07) OBJECT:'`',"boulder",(03,07) OBJECT:'`',"boulder",(03,08) OBJECT:'`',"boulder",(02,09) OBJECT:'`',"boulder",(03,09) OBJECT:'`',"boulder",(04,09) # OBJECT:'`',"boulder",(06,07) OBJECT:'`',"boulder",(06,09) OBJECT:'`',"boulder",(08,07) OBJECT:'`',"boulder",(08,10) OBJECT:'`',"boulder",(09,08) OBJECT:'`',"boulder",(09,09) OBJECT:'`',"boulder",(10,07) OBJECT:'`',"boulder",(10,10) # Traps TRAP:"hole",(12,10) TRAP:"hole",(13,10) TRAP:"hole",(14,10) TRAP:"hole",(15,10) TRAP:"hole",(16,10) TRAP:"hole",(17,10) TRAP:"hole",(18,10) TRAP:"hole",(19,10) TRAP:"hole",(20,10) TRAP:"hole",(21,10) TRAP:"hole",(22,10) TRAP:"hole",(23,10) TRAP:"hole",(24,10) TRAP:"hole",(25,10) TRAP:"hole",(26,10) # Random objects OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'=',random,random OBJECT:'/',random,random MAZE:"soko3-2",' ' FLAGS:noteleport GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP ---- ----------- -|..|------- |.........| |..........| |.........| |..-----.-.| |.........| |..|...|...| |.........| |.........-| |.........| |.......|..| |.........| |.----..--.| |.........| |........|.-- |.........| |.---.-.....------------+| |...|...-................| |.........---------------- ----|..|..| ------- ENDMAP STAIR:(03,01),down STAIR:(20,04),up DOOR:locked,(24,09) REGION:(00,00,25,13),lit,"ordinary" NON_DIGGABLE:(00,00,25,13) NON_PASSWALL:(00,00,25,13) # Boulders OBJECT:'`',"boulder",(02,03) OBJECT:'`',"boulder",(08,03) OBJECT:'`',"boulder",(09,04) OBJECT:'`',"boulder",(02,05) OBJECT:'`',"boulder",(04,05) OBJECT:'`',"boulder",(09,05) OBJECT:'`',"boulder",(02,06) OBJECT:'`',"boulder",(05,06) OBJECT:'`',"boulder",(06,07) OBJECT:'`',"boulder",(03,08) OBJECT:'`',"boulder",(07,08) OBJECT:'`',"boulder",(05,09) OBJECT:'`',"boulder",(10,09) OBJECT:'`',"boulder",(07,10) OBJECT:'`',"boulder",(10,10) OBJECT:'`',"boulder",(03,11) # Traps TRAP:"hole",(12,10) TRAP:"hole",(13,10) TRAP:"hole",(14,10) TRAP:"hole",(15,10) TRAP:"hole",(16,10) TRAP:"hole",(17,10) TRAP:"hole",(18,10) TRAP:"hole",(19,10) TRAP:"hole",(20,10) TRAP:"hole",(21,10) TRAP:"hole",(22,10) TRAP:"hole",(23,10) # Random objects OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'=',random,random OBJECT:'/',random,random ### Third level ### MAZE:"soko2-1",' ' FLAGS:noteleport GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP -------------------- |........|...|.....| |.....-..|.-.|.....| |..|.....|...|.....| |-.|..-..|.-.|.....| |...--.......|.....| |...|...-...-|.....| |...|..|...--|.....| |-..|..|----------+| |..................| |...|..|------------ -------- ENDMAP STAIR:(06,10),down STAIR:(16,04),up DOOR:locked,(18,08) REGION:(00,00,19,11),lit,"ordinary" NON_DIGGABLE:(00,00,19,11) NON_PASSWALL:(00,00,19,11) # Boulders OBJECT:'`',"boulder",(02,02) OBJECT:'`',"boulder",(03,02) # OBJECT:'`',"boulder",(05,03) OBJECT:'`',"boulder",(07,03) OBJECT:'`',"boulder",(07,02) OBJECT:'`',"boulder",(08,02) # OBJECT:'`',"boulder",(10,03) OBJECT:'`',"boulder",(11,03) # OBJECT:'`',"boulder",(02,07) OBJECT:'`',"boulder",(02,08) OBJECT:'`',"boulder",(03,09) # OBJECT:'`',"boulder",(05,07) OBJECT:'`',"boulder",(06,06) # Traps TRAP:"hole",(08,09) TRAP:"hole",(09,09) TRAP:"hole",(10,09) TRAP:"hole",(11,09) TRAP:"hole",(12,09) TRAP:"hole",(13,09) TRAP:"hole",(14,09) TRAP:"hole",(15,09) TRAP:"hole",(16,09) TRAP:"hole",(17,09) # Random objects OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'=',random,random OBJECT:'/',random,random MAZE:"soko2-2",' ' FLAGS:noteleport GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP -------- --|.|....| |........|---------- |.-...-..|.|.......| |...-......|.......| |.-....|...|.......| |....-.--.-|.......| |..........|.......| |.--...|...|.......| |....-.|---|.......| --|....|----------+| |................| ------------------ ENDMAP STAIR:(06,11),down STAIR:(15,06),up DOOR:locked,(18,10) REGION:(00,00,19,12),lit,"ordinary" NON_DIGGABLE:(00,00,19,12) NON_PASSWALL:(00,00,19,12) # Boulders OBJECT:'`',"boulder",(04,02) OBJECT:'`',"boulder",(04,03) OBJECT:'`',"boulder",(05,03) OBJECT:'`',"boulder",(07,03) OBJECT:'`',"boulder",(08,03) OBJECT:'`',"boulder",(02,04) OBJECT:'`',"boulder",(03,04) OBJECT:'`',"boulder",(05,05) OBJECT:'`',"boulder",(06,06) OBJECT:'`',"boulder",(09,06) OBJECT:'`',"boulder",(03,07) OBJECT:'`',"boulder",(04,07) OBJECT:'`',"boulder",(07,07) OBJECT:'`',"boulder",(06,09) OBJECT:'`',"boulder",(05,10) OBJECT:'`',"boulder",(05,11) # Traps TRAP:"hole",(07,11) TRAP:"hole",(08,11) TRAP:"hole",(09,11) TRAP:"hole",(10,11) TRAP:"hole",(11,11) TRAP:"hole",(12,11) TRAP:"hole",(13,11) TRAP:"hole",(14,11) TRAP:"hole",(15,11) TRAP:"hole",(16,11) TRAP:"hole",(17,11) # Random objects OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'=',random,random OBJECT:'/',random,random ### Top (last) level of Sokoban ### MAZE:"soko1-1",' ' FLAGS:noteleport GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP -------------------------- |........................| |.......|---------------.| -------.------ |.| |...........| |.| |...........| |.| --------.----- |.| |............| |.| |............| |.| -----.-------- ------|.| |..........| --|.....|.| |..........| |.+.....|.| |.........|- |-|.....|.| -------.---- |.+.....+.| |........| |-|.....|-- |........| |.+.....| |...|----- --|.....| ----- ------- ENDMAP RANDOM_PLACES:(16,11),(16,13),(16,15) STAIR:(01,01),down REGION:(00,00,25,17),lit,"ordinary" NON_DIGGABLE:(00,00,25,17) NON_PASSWALL:(00,00,25,17) # Boulders OBJECT:'`',"boulder",(03,05) OBJECT:'`',"boulder",(05,05) OBJECT:'`',"boulder",(07,05) OBJECT:'`',"boulder",(09,05) OBJECT:'`',"boulder",(11,05) # OBJECT:'`',"boulder",(04,07) OBJECT:'`',"boulder",(04,08) OBJECT:'`',"boulder",(06,07) OBJECT:'`',"boulder",(09,07) OBJECT:'`',"boulder",(11,07) # OBJECT:'`',"boulder",(03,12) OBJECT:'`',"boulder",(04,10) OBJECT:'`',"boulder",(05,12) OBJECT:'`',"boulder",(06,10) OBJECT:'`',"boulder",(07,11) OBJECT:'`',"boulder",(08,10) OBJECT:'`',"boulder",(09,12) # OBJECT:'`',"boulder",(03,14) # Traps TRAP:"hole",(08,01) TRAP:"hole",(09,01) TRAP:"hole",(10,01) TRAP:"hole",(11,01) TRAP:"hole",(12,01) TRAP:"hole",(13,01) TRAP:"hole",(14,01) TRAP:"hole",(15,01) TRAP:"hole",(16,01) TRAP:"hole",(17,01) TRAP:"hole",(18,01) TRAP:"hole",(19,01) TRAP:"hole",(20,01) TRAP:"hole",(21,01) TRAP:"hole",(22,01) TRAP:"hole",(23,01) MONSTER:'m',"giant mimic", random, m_object "boulder" MONSTER:'m',"giant mimic", random, m_object "boulder" # Random objects OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'=',random,random OBJECT:'/',random,random # Rewards DOOR:locked,(23,13) DOOR:closed,(17,11) DOOR:closed,(17,13) DOOR:closed,(17,15) REGION:(18,10,22,16),lit,"zoo",filled,true OBJECT:'(',"bag of holding",place[0] ENGRAVING:place[0],burn,"Elbereth" MAZE:"soko1-2",' ' FLAGS:noteleport GEOMETRY:center,center #12345678901234567890123456789012345678901234567890 MAP ------------------------ |......................| |..-------------------.| ----.| ----- |.| |..|.-- --...| |.| |.....|--|....| |.| |.....|..|....| |.| --....|......-- |.| |.......|...| ------|.| |....|..|...| --|.....|.| |....|--|...| |.+.....|.| |.......|..-- |-|.....|.| ----....|.-- |.+.....+.| ---.--.| |-|.....|-- |.....| |.+.....| |..|..| --|.....| ------- ------- ENDMAP RANDOM_PLACES:(16,10),(16,12),(16,14) STAIR:(06,15),down REGION:(00,00,25,16),lit,"ordinary" NON_DIGGABLE:(00,00,25,16) NON_PASSWALL:(00,00,25,16) # Boulders OBJECT:'`',"boulder",(04,04) OBJECT:'`',"boulder",(02,06) OBJECT:'`',"boulder",(03,06) OBJECT:'`',"boulder",(04,07) OBJECT:'`',"boulder",(05,07) OBJECT:'`',"boulder",(02,08) OBJECT:'`',"boulder",(05,08) OBJECT:'`',"boulder",(03,09) OBJECT:'`',"boulder",(04,09) OBJECT:'`',"boulder",(03,10) OBJECT:'`',"boulder",(05,10) OBJECT:'`',"boulder",(06,12) # OBJECT:'`',"boulder",(07,14) # OBJECT:'`',"boulder",(11,05) OBJECT:'`',"boulder",(12,06) OBJECT:'`',"boulder",(10,07) OBJECT:'`',"boulder",(11,07) OBJECT:'`',"boulder",(10,08) OBJECT:'`',"boulder",(12,09) OBJECT:'`',"boulder",(11,10) # Traps TRAP:"hole",(05,01) TRAP:"hole",(06,01) TRAP:"hole",(07,01) TRAP:"hole",(08,01) TRAP:"hole",(09,01) TRAP:"hole",(10,01) TRAP:"hole",(11,01) TRAP:"hole",(12,01) TRAP:"hole",(13,01) TRAP:"hole",(14,01) TRAP:"hole",(15,01) TRAP:"hole",(16,01) TRAP:"hole",(17,01) TRAP:"hole",(18,01) TRAP:"hole",(19,01) TRAP:"hole",(20,01) TRAP:"hole",(21,01) TRAP:"hole",(22,01) MONSTER:'m',"giant mimic", random, m_object "boulder" MONSTER:'m',"giant mimic", random, m_object "boulder" # Random objects OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'%',random,random OBJECT:'=',random,random OBJECT:'/',random,random # Rewards DOOR:locked,(23,12) DOOR:closed,(17,10) DOOR:closed,(17,12) DOOR:closed,(17,14) REGION:(18,09,22,15),lit,"zoo",filled,true OBJECT:'"',"amulet of reflection",place[0] ENGRAVING:place[0],burn,"Elbereth" nethack-3.4.3/dat/tower.des0100644000000000000000000000644007764735041014263 0ustar rootroot# SCCS Id: @(#)tower.des 3.4 1990/02/26 # Copyright (c) 1989 by Jean-Christophe Collet # NetHack may be freely redistributed. See license for details. # # Upper stage of Vlad's tower MAZE:"tower1",' ' FLAGS: noteleport,hardfloor GEOMETRY:half-left,center MAP --- --- --- |.| |.| |.| ---S---S---S--- |.......+.+...| ---+-----.----- |...\.|.+.| ---+-----.----- |.......+.+...| ---S---S---S--- |.| |.| |.| --- --- --- ENDMAP LADDER:(11,05),down # The lord and his court MONSTER:'V',"Vlad the Impaler",(06,05) MONSTER:'V',random,(03,09) MONSTER:'V',random,(07,09) MONSTER:'V',random,(11,09) MONSTER:'V',random,(03,01) MONSTER:'V',random,(07,01) MONSTER:'V',random,(11,01) # The doors DOOR:closed,(08,03) DOOR:closed,(10,03) DOOR:closed,(03,04) DOOR:locked,(10,05) DOOR:locked,(08,07) DOOR:locked,(10,07) DOOR:closed,(03,06) # treasures OBJECT:'(',"chest",(07,05) OBJECT:'(',"chest",(03,09) OBJECT:'(',"chest",(07,09) OBJECT:'(',"chest",(11,09) OBJECT:'(',"chest",(03,01) OBJECT:'(',"chest",(07,01) OBJECT:'(',"chest",(11,01) # We have to protect the tower against outside attacks NON_DIGGABLE:(00,00,14,10) # Intermediate stage of Vlad's tower MAZE:"tower2",' ' FLAGS: noteleport,hardfloor GEOMETRY:half-left,center MAP --- --- --- |.| |.| |.| ---S---S---S--- |.S.........S.| ---.------+---- |......|..| --------.------ |.S......+..S.| ---S---S---S--- |.| |.| |.| --- --- --- ENDMAP # Random places are the 10 niches RANDOM_PLACES:(03,01),(07,01),(11,01),(01,03),(13,03), (01,07),(13,07),(03,09),(07,09),(11,09) LADDER:(11,05),up LADDER:(03,07),down DOOR:locked,(10,04) DOOR:locked,(09,07) MONSTER:'&',random,place[0] MONSTER:'&',random,place[1] MONSTER:'d',"hell hound pup",place[2] MONSTER:'d',"hell hound pup",place[3] MONSTER:'d',"winter wolf",place[4] CONTAINER:'(',"chest",place[5] OBJECT:'"',"amulet of life saving",contained CONTAINER:'(',"chest",place[6] OBJECT:'"',"amulet of strangulation",contained OBJECT:'[',"water walking boots",place[7] OBJECT:'[',"crystal plate mail",place[8] OBJECT:'+',"invisibility",place[9] # Walls in the tower are non diggable NON_DIGGABLE:(00,00,14,10) # Bottom most stage of Vlad's tower MAZE:"tower3",' ' FLAGS: noteleport,hardfloor GEOMETRY:half-left,center MAP --- --- --- |.| |.| |.| ---S---S---S--- |.S.........S.| -----.........----- |...|.........+...| |.---.........---.| |.|.S.........S.|.| |.---S---S---S---.| |...|.|.|.|.|.|...| ---.---.---.---.--- |.............| --------------- ENDMAP # Random places are the 10 niches RANDOM_PLACES:(05,01),(09,01),(13,01),(03,03),(15,03), (03,07),(15,07),(05,09),(09,09),(13,09) BRANCH:(02,05,02,05),(00,00,00,00) LADDER:(05,07),up # Entry door is, of course, locked DOOR:locked,(14,05) # Let's put a dragon behind the door, just for the fun... MONSTER:'D',random,(13,05) MONSTER:random,random,(12,04) MONSTER:random,random,(12,06) MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random MONSTER:random,random,random OBJECT:')',"long sword",place[0] TRAP:random,place[0] OBJECT:'(',"lock pick",place[1] TRAP:random,place[1] OBJECT:'[',"elven cloak",place[2] TRAP:random,place[2] OBJECT:'(',"blindfold",place[3] TRAP:random,place[3] # Walls in the tower are non diggable NON_DIGGABLE:(00,00,18,12) nethack-3.4.3/dat/wizhelp0100644000000000000000000000122707764735041014031 0ustar rootrootDebug-Mode Quick Reference: ^E == detect secret doors and traps. ^F == do magic mapping. ^G == create monster. ^I == identify items in pack. ^O == tell locations of special levels. ^T == do intra-level teleport. ^V == do trans-level teleport. ^W == make wish. ^X == show attributes including intrinsic attributes. #levelchange == change experience level #lightsources == show mobile light sources #monpolycontrol == control monster polymorphs #panic == panic test #polyself == polymorph self #seenv == show seen vectors #stats == show memory statistics #timeout == look at timeout queue #vision == show vision array #wmode == show wall modes nethack-3.4.3/dat/yendor.des0100644000000000000000000001620007764735041014416 0ustar rootroot# SCCS Id: @(#)yendor.des 3.4 1996/10/20 # Copyright (c) 1989 by Jean-Christophe Collet # Copyright (c) 1992 by M. Stephenson and Izchak Miller # NetHack may be freely redistributed. See license for details. # # The top (real) wizard level. # Keeping the Moat for old-time's sake MAZE:"wizard1",random FLAGS:noteleport,hardfloor GEOMETRY:center,center MAP ----------------------------. |.......|..|.........|.....|. |.......S..|.}}}}}}}.|.....|. |..--S--|..|.}}---}}.|---S-|. |..|....|..|.}--.--}.|..|..|. |..|....|..|.}|...|}.|..|..|. |..--------|.}--.--}.|..|..|. |..|.......|.}}---}}.|..|..|. |..S.......|.}}}}}}}.|..|..|. |..|.......|.........|..|..|. |..|.......|-----------S-S-|. |..|.......S...............|. ----------------------------. ENDMAP STAIR:levregion(01,00,79,20),(0,0,28,12),up STAIR:levregion(01,00,79,20),(0,0,28,12),down BRANCH:levregion(01,00,79,20),(0,0,28,12) TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12) # Make it a morgue for rm id in mkmaze.c # for the purpose of random sdoor placement REGION:(12,01,20,09),unlit,"morgue",unfilled MAZEWALK:(28,05),east LADDER:(06,05),down # Non diggable walls # Walls inside the moat stay diggable NON_DIGGABLE:(00,00,11,12) NON_DIGGABLE:(11,00,21,00) NON_DIGGABLE:(11,10,27,12) NON_DIGGABLE:(21,00,27,10) # Non passable walls NON_PASSWALL:(00,00,11,12) NON_PASSWALL:(11,00,21,00) NON_PASSWALL:(11,10,27,12) NON_PASSWALL:(21,00,27,10) # The wizard and his guards MONSTER:'@',"Wizard of Yendor",(16,05),asleep MONSTER:'d',"hell hound",(15,05) MONSTER:'V',"vampire lord",(17,05) # The local treasure OBJECT:'+',"Book of the Dead",(16,05) # Surrounding terror MONSTER:';',"kraken",(14,02) MONSTER:';',"giant eel",(17,02) MONSTER:';',"kraken",(13,04) MONSTER:';',"giant eel",(13,06) MONSTER:';',"kraken",(19,04) MONSTER:';',"giant eel",(19,06) MONSTER:';',"kraken",(15,08) MONSTER:';',"giant eel",(17,08) MONSTER:';',"piranha",(15,02) MONSTER:';',"piranha",(19,08) # Random monsters MONSTER:'D',random,random MONSTER:'H',random,random MONSTER:'&',random,random MONSTER:'&',random,random MONSTER:'&',random,random MONSTER:'&',random,random # And to make things a little harder. TRAP:"board",(16,04) TRAP:"board",(16,06) TRAP:"board",(15,05) TRAP:"board",(17,05) # Random traps. TRAP:"spiked pit",random TRAP:"sleep gas",random TRAP:"anti magic",random TRAP:"magic",random # Some random loot. OBJECT:'*',"ruby",random OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'+',random,random OBJECT:'+',random,random OBJECT:'+',random,random # The middle wizard level. MAZE:"wizard2",random FLAGS:noteleport,hardfloor GEOMETRY:center,center MAP ----------------------------. |.....|.S....|.............|. |.....|.-------S--------S--|. |.....|.|.........|........|. |..-S--S|.........|........|. |..|....|.........|------S-|. |..|....|.........|.....|..|. |-S-----|.........|.....|..|. |.......|.........|S--S--..|. |.......|.........|.|......|. |-----S----S-------.|......|. |............|....S.|......|. ----------------------------. ENDMAP STAIR:levregion(01,00,79,20),(0,0,28,12),up STAIR:levregion(01,00,79,20),(0,0,28,12),down BRANCH:levregion(01,00,79,20),(0,0,28,12) TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12) REGION:(09,03,17,09),unlit,"zoo" DOOR:closed,(15,02) DOOR:closed,(11,10) MAZEWALK:(28,05),east LADDER:(12,01),up LADDER:(14,11),down # Non diggable walls everywhere NON_DIGGABLE:(00,00,27,12) # NON_PASSWALL:(00,00,06,12) NON_PASSWALL:(06,00,27,02) NON_PASSWALL:(16,02,27,12) NON_PASSWALL:(06,12,16,12) # Random traps. TRAP:"spiked pit",random TRAP:"sleep gas",random TRAP:"anti magic",random TRAP:"magic",random # Some random loot. OBJECT:'!',random,random OBJECT:'!',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'+',random,random # treasures OBJECT:'"',random,(04,06) # The bottom wizard level. # Memorialize the fakewiz setup. MAZE:"wizard3",random FLAGS:noteleport,hardfloor GEOMETRY:center,center MAP ----------------------------. |..|............S..........|. |..|..------------------S--|. |..|..|.........|..........|. |..S..|.}}}}}}}.|..........|. |..|..|.}}---}}.|-S--------|. |..|..|.}--.--}.|..|.......|. |..|..|.}|...|}.|..|.......|. |..---|.}--.--}.|..|.......|. |.....|.}}---}}.|..|.......|. |.....S.}}}}}}}.|..|.......|. |.....|.........|..S.......|. ----------------------------. ENDMAP STAIR:levregion(01,00,79,20),(0,0,28,12),up STAIR:levregion(01,00,79,20),(0,0,28,12),down BRANCH:levregion(01,00,79,20),(0,0,28,12) TELEPORT_REGION:levregion(01,00,79,20),(0,0,27,12) PORTAL:(25,11,25,11),(0,0,0,0),"fakewiz1" MAZEWALK:(28,09),east REGION:(07,03,15,11),unlit,"morgue",unfilled REGION:(17,06,18,11),unlit,"beehive" # make the entry chamber a real room; it affects monster arrival; # `unfilled' is a kludge to force an ordinary room to remain a room REGION:(20,06,26,11),unlit,"ordinary",unfilled DOOR:closed,(18,05) DOOR:closed,(19,11) LADDER:(11,07),up # Non diggable walls # Walls inside the moat stay diggable NON_DIGGABLE:(00,00,06,12) NON_DIGGABLE:(06,00,27,02) NON_DIGGABLE:(16,02,27,12) NON_DIGGABLE:(06,12,16,12) # NON_PASSWALL:(00,00,06,12) NON_PASSWALL:(06,00,27,02) NON_PASSWALL:(16,02,27,12) NON_PASSWALL:(06,12,16,12) # MONSTER:'L',random,(10,07) MONSTER:'V',"vampire lord",(12,07) # Some surrounding horrors MONSTER:';',"kraken",(08,05) MONSTER:';',"giant eel",(08,08) MONSTER:';',"kraken",(14,05) MONSTER:';',"giant eel",(14,08) # Other monsters MONSTER:'L',random,random MONSTER:'D',random,random MONSTER:'D',random,(26,09) MONSTER:'&',random,random MONSTER:'&',random,random MONSTER:'&',random,random # And to make things a little harder. TRAP:"board",(10,07) TRAP:"board",(12,07) TRAP:"board",(11,06) TRAP:"board",(11,08) # Some loot OBJECT:')',random,random OBJECT:'!',random,random OBJECT:'?',random,random OBJECT:'?',random,random OBJECT:'(',random,random # treasures OBJECT:'"',random,(11,07) # The former decoy wizard levels. # There are two of these, and we need to # distinguish between them for the portal. MAZE:"fakewiz1",random GEOMETRY:center,center MAP ......... .}}}}}}}. .}}---}}. .}--.--}. .}|...|}. .}--.--}. .}}---}}. .}}}}}}}. ENDMAP STAIR:levregion(01,00,79,20),(0,0,8,7),up STAIR:levregion(01,00,79,20),(0,0,8,7),down BRANCH:levregion(01,00,79,20),(0,0,8,7) TELEPORT_REGION:levregion(01,00,79,20),(2,2,6,6) PORTAL:(4,4,4,4),(0,0,0,0),"wizard3" MAZEWALK:(08,05),east REGION:(04,03,06,06),unlit,"ordinary",unfilled,true MONSTER:'L',random,(04,04) MONSTER:'V',"vampire lord",(03,04) MONSTER:';',"kraken",(06,06) # And to make things a little harder. TRAP:"board",(04,03) TRAP:"board",(04,05) TRAP:"board",(03,04) TRAP:"board",(05,04) MAZE:"fakewiz2",random GEOMETRY:center,center MAP ......... .}}}}}}}. .}}---}}. .}--.--}. .}|...|}. .}--.--}. .}}---}}. .}}}}}}}. ENDMAP STAIR:levregion(01,00,79,20),(0,0,8,7),up STAIR:levregion(01,00,79,20),(0,0,8,7),down BRANCH:levregion(01,00,79,20),(0,0,8,7) TELEPORT_REGION:levregion(01,00,79,20),(2,2,6,6) MAZEWALK:(08,05),east REGION:(04,03,06,06),unlit,"ordinary",unfilled,true MONSTER:'L',random,(04,04) MONSTER:'V',"vampire lord",(03,04) MONSTER:';',"kraken",(06,06) # And to make things a little harder. TRAP:"board",(04,03) TRAP:"board",(04,05) TRAP:"board",(03,04) TRAP:"board",(05,04) # treasures OBJECT:'"',random,(04,04) nethack-3.4.3/Files0100644000000000000000000003465107764735041012650 0ustar rootrootThis is a listing of all files in a full NetHack 3.4 distribution, organized in their standard manner on a UNIX system. It indicates which files are necessary for which versions, so that you can tell which files may be deleted from or not transferred to your system if you wish. .: (files in top directory) Files Porting README dat: (files for all versions) Arch.des Barb.des Caveman.des Healer.des Knight.des Monk.des Priest.des Ranger.des Rogue.des Samurai.des Tourist.des Valkyrie.des Wizard.des bigroom.des castle.des cmdhelp data.base dungeon.def endgame.des gehennom.des help hh history knox.des license medusa.des mines.des opthelp oracle.des oracles.txt quest.txt rumors.fal rumors.tru sokoban.des tower.des wizhelp yendor.des doc: (files for all versions) Guidebook.mn Guidebook.tex Guidebook.txt dgn_comp.6 dgn_comp.txt dlb.6 dlb.txt fixes22.0 fixes30.0 fixes31.1 fixes31.2 fixes31.3 fixes32.0 fixes32.1 fixes32.2 fixes32.3 fixes33.0 fixes33.1 fixes34.0 fixes34.1 fixes34.2 fixes34.3 lev_comp.6 lev_comp.txt nethack.6 nethack.txt recover.6 recover.txt tmac.n window.doc include: (files for all versions) align.h amiconf.h artifact.h artilist.h attrib.h beconf.h color.h config.h config1.h coord.h decl.h def_os2.h dgn_file.h display.h dlb.h dungeon.h edog.h emin.h engrave.h epri.h eshk.h extern.h flag.h func_tab.h global.h hack.h lev.h mail.h mfndpos.h micro.h mkroom.h monattk.h mondata.h monflag.h monst.h monsym.h nhlan.h ntconf.h obj.h objclass.h os2conf.h patchlevel.h pcconf.h permonst.h prop.h qtext.h quest.h rect.h region.h rm.h skills.h sp_lev.h spell.h system.h tcap.h timeout.h tosconf.h tradstdc.h trampoli.h trap.h unixconf.h vault.h vision.h vmsconf.h wceconf.h winami.h winprocs.h wintype.h you.h youprop.h (file for tty versions) wintty.h (files for X versions) tile2x11.h winX.h xwindow.h xwindowp.h (files for Qt versions) qt_clust.h qt_kde0.h qt_win.h qt_xpms.h qttableview.h (files for Gem versions) bitmfile.h gem_rsc.h load_img.h wingem.h (file for GNOME versions) winGnome.h (files for various Macintosh versions) mac-carbon.h mac-qt.h mac-term.h macconf.h macpopup.h mactty.h macwin.h mttypriv.h src: (files for all versions) allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c files.c fountain.c hack.c hacklib.c invent.c light.c lock.c mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c mklev.c mkmap.c mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c options.c pager.c pickup.c pline.c polyself.c potion.c pray.c priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c rnd.c role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c steal.c steed.c teleport.c timeout.c topten.c track.c trap.c u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c windows.c wizard.c worm.c worn.c write.c zap.c sys/amiga: (files for Amiga versions) Build.ami Install.ami Makefile.agc Makefile.ami NetHack.cnf amidos.c amidos.p amifont.uu amifont8.uu amigst.c amii.hlp amimenu.c amirip.c amisnd.c amistack.c amitty.c amiwind.c amiwind.p clipwin.c colorwin.c cvtsnd.c grave16.xpm ifchange mkdmake txt2iff.c winami.c winami.p winchar.c windefs.h winext.h winfuncs.c winkey.c winmenu.c winproto.h winreq.c winstr.c xpm2iff.c sys/atari: (files for Atari version) Install.tos atarifnt.uue nethack.mnu setup.g tos.c unx2atar.sed sys/be: (files for BeOS version) README bemain.c sys/mac: (files for Macintosh versions) Files.r Install.mw MacHelp NHDeflts NHrsrc.hqx NHsound.hqx News README dprintf.c maccurs.c macerrs.c macfile.c machelp.hqx macmain.c macmenu.c macsnd.c mactopl.c mactty.c macunix.c macwin.c mgetline.c mmodal.c mrecover.c mrecover.hqx mttymain.c sys/msdos: (files for MSDOS version) Install.dos Makefile.BC Makefile.GCC Makefile.MSC NHAccess.nh moveinit.pat msdos.c msdoshlp.txt ovlinit.c pckeys.c pctiles.c pctiles.h pcvideo.h portio.h schema1.BC schema2.BC schema3.MSC setup.bat sound.c tile2bin.c video.c vidtxt.c vidvga.c (files for running MSDOS binary under Windows) nhico.uu nhpif.uu sys/os2: (files for OS/2 version) Install.os2 Makefile.os2 nhpmico.uu os2.c sys/share: (files for MSDOS and OS/2 versions) Makefile.lib termcap.uu (file for MSDOS, OS/2, NT, Amiga, and Atari versions) pcmain.c (files for MSDOS, OS/2, NT, and Atari versions) pcsys.c pcunix.c (file for MSDOS, OS/2, and Atari versions) NetHack.cnf pctty.c (files for UNIX and Be versions) ioctl.c unixtty.c (file for NT version) nhlan.c (Berkeley random number file, which may be included in any version) random.c (Berkeley uudecode file, which may be used in build process of any version) uudecode.c (file for VMS version) tclib.c (file for MSDOS, OS/2, and VMS versions) termcap (lex/yacc output for special level and dungeon compilers) dgn_comp.h dgn_lex.c dgn_yacc.c lev_comp.h lev_lex.c lev_yacc.c sys/share/sounds: (files for Amiga and Macintosh versions) README bell.uu bugle.uu erthdrum.uu firehorn.uu frsthorn.uu lethdrum.uu mgcflute.uu mgcharp.uu toolhorn.uu wdnflute.uu wdnharp.uu sys/unix: (files for UNIX versions) Install.unx Makefile.dat Makefile.doc Makefile.src Makefile.top Makefile.utl README.linux depend.awk nethack.sh setup.sh unixmain.c unixres.c unixunix.c (files for replacement cpp, apparently only needed by some UNIX systems) cpp1.shr cpp2.shr cpp3.shr (file for sound driver for 386 UNIX) snd86unx.shr sys/vms: (files for VMS version) Install.vms Makefile.dat Makefile.doc Makefile.src Makefile.top Makefile.utl install.com lev_lex.h nethack.com oldcrtl.c spec_lev.com vmsbuild.com vmsfiles.c vmsmail.c vmsmain.c vmsmisc.c vmstty.c vmsunix.c sys/wince: (files for Windows CE and PocketPC) Install.ce bootstrp.mak celib.c cesetup.bat cesound.c defaults.nh keypad.uu menubar.uu mhaskyn.c mhaskyn.h mhcmd.c mhcmd.h mhcolor.c mhcolor.h mhdlg.c mhdlg.h mhfont.c mhfont.h mhinput.c mhinput.h mhmain.c mhmain.h mhmap.c mhmap.h mhmenu.c mhmenu.h mhmsg.h mhmsgwnd.c mhmsgwnd.h mhrip.c mhrip.h mhstatus.c mhstatus.h mhtext.c mhtext.h mhtxtbuf.c mhtxtbuf.h mswproc.c newres.h resource.h winMS.h winhack.c winhack.rc winhcksp.rc winmain.c sys/wince/ceinc: (header files for Windows CE and PocketPC) assert.h errno.h fcntl.h sys/wince/ceinc/sys: (sys/stat.h for Windows CE and PocketPC) stat.h sys/winnt: (files for Windows 9x, NT and Windows2000 version) Install.nt Makefile.bcc Makefile.gcc Makefile.msc console.rc defaults.nh mapimail.c nethack.def nh340key.c nhdefkey.c nhico.uu nhraykey.c nhsetup.bat ntsound.c nttty.c porthelp win32api.h winnt.c util: (files for all versions) dgn_main.c dlb_main.c lev_main.c makedefs.c panic.c recover.c (lex/yacc input for special level and dungeon compilers) dgn_comp.l dgn_comp.y lev_comp.l lev_comp.y win/Qt: (files for the Qt widget library - X11, Windows, Mac OS X, or Qtopia) Info.plist Install.Qt knethack.lnk knh-mini.xpm knh.xpm nhicns.uu nhsplash.xpm qt_clust.cpp qt_win.cpp qttableview.cpp tileedit.cpp tileedit.h qpe-nethack.control win/X11: (files for X versions) Install.X11 NetHack.ad Window.c dialogs.c ibm.bdf nethack.rc nh10.bdf nh32icon nh56icon nh72icon nh_icon.xpm pet_mark.xbm rip.xpm tile2x11.c winX.c winmap.c winmenu.c winmesg.c winmisc.c winstat.c wintext.c winval.c win/gem: (files for GEM versions) Install.gem bitmfile.c gem_rsc.uu gem_rso.uu gr_rect.c gr_rect.h load_img.c tile2img.c title.uu wingem.c wingem1.c xpm2img.c win/gnome: (files for GNOME versions) README gn_xpms.h gnaskstr.c gnaskstr.h gnbind.c gnbind.h gnglyph.c gnglyph.h gnmain.c gnmain.h gnmap.c gnmap.h gnmenu.c gnmenu.h gnmesg.c gnmesg.h gnomeprv.h gnopts.c gnopts.h gnplayer.c gnplayer.h gnsignal.c gnsignal.h gnstatus.c gnstatus.h gntext.c gntext.h gnworn.c gnworn.h gnyesno.c gnyesno.h mapbg.xpm win/share: (files for versions using optional tiles) gifread.c monsters.txt objects.txt other.txt ppmwrite.c thintile.c tile.doc tile.h tile2bmp.c tilemap.c tiletext.c win/tty: (files for tty versions) getline.c termcap.c topl.c wintty.c win/win32: (files for Windows 9x, NT, Windows 2000, and Windows XP version) dgncomp.dsp dgnstuff.dsp dgnstuff.mak dlb_main.dsp levcomp.dsp levstuff.dsp levstuff.mak makedefs.dsp mhaskyn.c mhaskyn.h mhdlg.c mhdlg.h mhfont.c mhfont.h mhinput.c mhinput.h mhmain.c mhmain.h mhmap.c mhmap.h mhmenu.c mhmenu.h mhmsg.h mhmsgwnd.c mhmsgwnd.h mhrip.c mhrip.h mhsplash.c mhsplash.h mhstatus.c mhstatus.h mhtext.c mhtext.h mnsel.uu mnselcnt.uu mnunsel.uu mswproc.c nethack.dsw nethackw.dsp petmark.uu recover.dsp resource.h rip.uu splash.uu tile2bmp.dsp tilemap.dsp tiles.dsp tiles.mak uudecode.dsp winMS.h winhack.c winhack.rc This is a list of files produced by auxiliary programs. They can all be regenerated from the files in the distribution. dat: (files generated by makedefs at playground creation time) data dungeon.pdf options oracles quest.dat rumors (file generated by dgn_comp at playground creation time) dungeon (files generated by lev_comp at playground creation time) Arc-fila.lev Arc-filb.lev Arc-goal.lev Arc-loca.lev Arc-strt.lev Bar-fila.lev Bar-filb.lev Bar-goal.lev Bar-loca.lev Bar-strt.lev Cav-fila.lev Cav-filb.lev Cav-goal.lev Cav-loca.lev Cav-strt.lev Hea-fila.lev Hea-filb.lev Hea-goal.lev Hea-loca.lev Hea-strt.lev Kni-fila.lev Kni-filb.lev Kni-goal.lev Kni-loca.lev Kni-strt.lev Mon-fila.lev Mon-filb.lev Mon-goal.lev Mon-loca.lev Mon-strt.lev Pri-fila.lev Pri-filb.lev Pri-goal.lev Pri-loca.lev Pri-strt.lev Ran-fila.lev Ran-filb.lev Ran-goal.lev Ran-loca.lev Ran-strt.lev Rog-fila.lev Rog-filb.lev Rog-goal.lev Rog-loca.lev Rog-strt.lev Sam-fila.lev Sam-filb.lev Sam-goal.lev Sam-loca.lev Sam-strt.lev Tou-fila.lev Tou-filb.lev Tou-goal.lev Tou-loca.lev Tou-strt.lev Val-fila.lev Val-filb.lev Val-goal.lev Val-loca.lev Val-strt.lev Wiz-fila.lev Wiz-filb.lev Wiz-goal.lev Wiz-loca.lev Wiz-strt.lev air.lev asmodeus.lev astral.lev baalz.lev bigrm-1.lev bigrm-2.lev bigrm-3.lev bigrm-4.lev bigrm-5.lev castle.lev earth.lev fakewiz1.lev fakewiz2.lev fire.lev juiblex.lev knox.lev medusa-1.lev medusa-2.lev minefill.lev minend-1.lev minend-2.lev minetn-1.lev minetn-2.lev oracle.lev orcus.lev sanctum.lev soko1-1.lev soko1-2.lev soko2-1.lev soko2-2.lev soko3-1.lev soko3-2.lev soko4-1.lev soko4-2.lev tower1.lev tower2.lev tower3.lev valley.lev water.lev wizard1.lev wizard2.lev wizard3.lev (tile files optionally generated for X ports at playground creation time) pet_mark.xbm rip.xpm x11tiles (files generated for Qt interface on Mac OS X) nethack.icns Info.plist include: (files generated by makedefs at compile time) date.h onames.h pm.h vis_tab.h src: (files generated by makedefs at compile time) monstr.c vis_tab.c (file optionally generated by tilemap at compile time) tile.c (files generated by 'moc' for Qt interface at compile time) qt_kde0.moc qt_win.moc qttableview.moc NOTE: If your binaries were compiled with the data librarian (DLB) option, your playground will not contain all of the files listed here. All of the files listed as being required for the playground must still have been built by your compiler, but the DLB code will roll them up into another file (or files). nethack-3.4.3/Porting0100644000000000000000000001625107764735041013224 0ustar rootroot NetHack Porting Guidelines v 3.4 1999-11-29 1.0 Introduction This document goes through the steps required to port NetHack to a new machine. The basic steps in porting the program are: 1. Get the code onto your machine. The parts of the current directory setup you definitely need include src (NetHack code shared by all systems), include (include files), util (code for utility programs), and dat (various data files). The documentation in doc is strongly recommended. You already have the files in the top directory since you're reading this one. :-) A full list of the distribution files and their associated OSes may be found in the top-level file "Files". If your machine uses an OS already supported, you need the sys subdirectory for that OS and possibly sys/share. Otherwise, get the closest match (say sys/msdos for single-tasking OSes and sys/unix for multi-user OSes, along with sys/share, if nothing else comes to mind). You may want others for comparison. If your machine uses a windowing system already supported, you need the win subdirectory for that system (or the appropriate sys subdirectory if the windowing system was previously considered restricted to one OS). 2. Modify the appropriate include files to customize NetHack to your system. You may need to add a new OS-specific "*conf.h" file (see unixconf.h, pcconf.h, tosconf.h, etc. as examples). 3. If your machine uses a new OS instead of a variant of existing OSes, add a new sys subdirectory. Add, if required, a OS- specific copy of "main.c", "tty.c" and "unix.c". Possibly add an OS-specific library (see "msdos.c" and "tos.c" as examples) to provide functions NetHack wants and your OS lacks. 4. If your machine uses a new windowing system, follow doc/window.doc carefully. Put files implementing these routines in a win or sys subdirectory as appropriate. 5. If your compilation environment isn't close to one already supported, try starting from the UNIX makefiles. Modify the top level makefile and the src makefile as required. Then run an initial compile. You are bound to get some errors. You should be able to fix them in a fairly simple fashion. If things seem to be getting too complex, take a step back, and possibly send us some mail. We might be able to help. 6. Mail all of your fixes to us in a contextual form so that we can easily integrate them into the code. One general rule of thumb exists. Always add code. Don't delete somebody else's code for yours -- it won't work on their machine if you do. Always add your OS specific code inside #ifdef / #else / #endif constructs so that it will be able to be folded back into the original code easily. 2.0 Include Files 2.1 config.h The file "config.h" is a master configuration file that determines the basic features of the game, as well as many of the security options. It is intended that end users configure the game by editing "config.h" and an appropriate "*conf.h" file, so any #defines for individual preferences should be added to those files. OS-specific #defines that are not intended to be changed should also go in "*conf.h"; try to find the most appropriate place for other #defines. The following sections may require modification: - Section 1: OS and window system selection. You may have to put a #define for your OS here. If your OS is yet another UNIX variant, put the #define in unixconf.h instead. An unfortunately large amount of stuff shares this section because the #definitions have to be seen before *conf.h is reached. Don't add to this unless necessary. - Section 2: Global parameters and filenames. These will have to be customized to your system. - Section 3: Type definitions and other compiler behavior. These will have to be matched to your compiler. 2.2 global.h This file defines things specific to NetHack that should not require modification by an end user. For a new port, you may have to add automatic inclusion of another auxiliary config file (*conf.h) which you wrote for your system. 2.3 extern.h If you create any new source modules or new functions in old modules, you must enter the names of the new external references (the functions defined there for external use) in this file. 2.4 system.h This file contains references for all hooks into the OS (via the standard "C" libraries). Depending on what your standard library looks like, you may have to put new entries into this file. 3.0 Source files The first step in getting the game up is to get the "makedefs" program running. This program is used to create configuration-specific files for the game. Once "makedefs" has been built, the rest of the game can be compiled. You may have to create an OS-specific module to handle things you want to use, like a mouse or a ram-disk. The utility compilers "dgn_comp" and "lev_comp" may be a better place to start. They also require "makedefs" but are independent of "nethack". They are usually the last programs made, but since they are much smaller they may be more tractable when first arguing with the include files. These programs create binary data files that "nethack" uses to guide its dungeon creation. 3.1 Makefiles This distribution provides makefiles for several kinds of systems. There are joint makefiles for the various varieties of UNIX, makefiles for MSDOS, a makefile for NT, and so on. You may have to create a new makefile for your specific machine. You may even have to translate some makefiles into a form more congenial to your system. If possible, however, add to one of those provided. 3.2 termcap.c If your system wants to use tty windowing and it doesn't run off of a termcap or terminfo database, you may have to put the appropriate terminal control strings into termcap.c. This has already been done for MSDOS, and these mods can be used as an example. You can also consider using the termcap code from sys/share/tclib.c or sys/share/termcap.uu, especially if your system supports multiple kinds of terminals. 3.3 main.c You may need to create a new "main.c" module. If you do, call it [OS]main.c where the [OS] is replaced with the name of the OS you are porting to. This file contains the mainline module, which reads options from the command line (or wherever) and processes them. It also contains various functions associated with game startup. 3.4 tty.c You may need to create a new "tty.c" module. If you do, call it [OS]tty.c where the [OS] is replaced with the name of the OS you are porting to. This file contains the routines that configure the terminal/console for raw I/O, etc. 3.5 unix.c You may need to create a new "unix.c" module. If you do, call it [OS]unix.c where the [OS] is replaced with the name of the OS you are porting to. This file contains some OS dependencies concerning time and filename creation. An object of the NetHack development project is to get the game working on as many different types of hardware and under as many different operating systems as is practical. Any assistance will be appreciated. nethack-3.4.3/README0100644000000000000000000002761107764735041012541 0ustar rootroot NetHack 3.4.3 -- General information NetHack 3.4 is an enhancement to the dungeon exploration game NetHack. It is a distant descendent of Rogue and Hack, and a direct descendent of NetHack 3.3. NetHack 3.4.3 is a bugfix release for NetHack 3.4.2. * Several dozen general bug fixes including at least one fatal bug * Correct several inconsistencies * Handle level completely filled with monsters better * win32tty performance enhancements when playing on Windows 98 and Windows Me * win32gui player selection fixes * X11 player selection fixes, one of which could be fatal * Eliminated a gold-in-shop-container cheat * Include bones file version compatibility info in options file A fuller list of changes for this release can be found in the file doc/fixes34.3 in the source distribution. The text in there was written for the development team's own use and is provided "as is", so please do not ask us to further explain the entries in that file. The internal structure of bones and save files has not changed between NetHack 3.4.0, 3.4.1, 3.4.2 and now 3.4.3. That means that if you use the same compiler, the same compiler version and compiler switches, the same NetHack compile-time options, and you have not incorporated any additional source code patches that altered the save file format on your system, then bones and save files from 3.4.0 through 3.4.3 should be compatible. - - - - - - - - - - - Please read items (1), (2) and (3) BEFORE doing anything with your new code. 1. Unpack the code in a dedicated new directory. We will refer to that directory as the 'Top' directory. It makes no difference what you call it. 2. If there is no flaw in the packaging, many sub-directories will be automatically created, and files will be deposited in them: a. A 'dat' directory, which contains a variety of data files. b. A 'doc' directory, which contains various documentation. c. An 'include' directory, which contains *.h files. d. A 'src' directory, which contains game *.c files used by all versions. e. A 'util' directory, which contains files for utility programs. f. A 'sys' directory, which contains subdirectories for files that are operating-system specific. g. A 'sys/share' subdirectory, which contains files shared by some OSs. h. A 'sys/share/sounds' subsubdirectory, which contains sound files shared by some OSs. i. A 'sys/amiga' subdirectory, which contains files specific to AmigaDOS. j. A 'sys/amiga/ship' subsubdirectory k. A 'sys/atari' subdirectory, which contains files specific to TOS. l. A 'sys/be' subdirectory, which contains files specific to Be OS. m. A 'sys/mac' subdirectory, which contains files specific to MacOS. n. A 'sys/msdos' subdirectory, which contains files specific to MS-DOS. o. A 'sys/os2' subdirectory, which contains files specific to OS/2. p. A 'sys/unix' subdirectory, which contains files specific to UNIX. q. A 'sys/vms' subdirectory, which contains files specific to VMS. r. A 'sys/wince' subdirectory, which contains files specific to Windows CE. s. A 'sys/winnt' subdirectory, which contains files specific to Windows NT. t. A 'win' directory, which contains subdirectories for files that are windowing-system specific (but not operating-system specific). u. A 'win/share' subdirectory, which contains files shared by some windowing systems. v. A 'win/Qt' subdirectory, which contains files specific to Qt. w. A 'win/X11' subdirectory, which contains files specific to X11. x. A 'win/gem' subdirectory, which contains files specific to GEM. y. A 'win/gnome' subdirectory, which contains files specific to GNOME. z. A 'win/tty' subdirectory, which contains files specific to ttys. A. A 'win/win32' subdirectory, which contains files specific to the Windows Win32 API. The names of these directories should not be changed unless you are ready to go through the makefiles and the makedefs program and change all the directory references in them. 3. Having unpacked, you should have a file called 'Files' in your Top directory. This file contains the list of all the files you now SHOULD have in each directory. Please check the files in each directory against this list to make sure that you have a complete set. 4. Before you do anything else, please read carefully the file called "license" in the 'dat' subdirectory. It is expected that you comply with the terms of that license, and we are very serious about it. 5. If everything is in order, you can now turn to trying to get the program to compile and run on your particular system. It is worth mentioning that the default configuration is SysV/Sun/Solaris2.x (simply because the code was housed on such a system). It is also worth mentioning here that NetHack 3.4 is a huge program. If you intend to run it on a small machine, you'll have to make hard choices among the options available in config.h. The files sys/*/Install.* were written to guide you in configuring the program for your operating system. The files win/*/Install.* are available, where necessary, to help you in configuring the program for particular windowing environments. Reading them, and the man pages, should answer most of your questions. At the time of this release, NetHack 3.4 is known to run/compile on: Apple Macintosh running MacOS 7.5 or higher, LinuxPPC, BeOS 4.0 Atari ST/TT/Falcon running TOS (or MultiTOS) with GCC Commodore Amiga running AmigaDOS 3.0 or higher with SAS/C 6.x (but see Makefile.ami about DICE and Manx) DEC Alpha/VMS (aka OpenVMS AXP), running V1.x through V7.1 DEC VAX/VMS, running V4.6 through V7.1 HP 9000s700 running HP-UX 10.x, 11.x IBM PS/2 and AT compatibles running OS/2 - 2.0 and up with GCC emx Intel 80386 or greater (or clone) boxes running MS-DOS with DPMI. Intel 80386 or greater (or clone) boxes running Linux, or BSDI. Intel 80386 or greater (or clone) boxes running Windows 95/98/Me. Intel 80386 or greater (or clone) boxes running Windows NT/2000/XP/2003. Intel Pentium or better (or clone) running BeOS 4.5 Sun SPARC based machine running SunOS 4.x, Solaris 2.x, or Solaris 7 NetHack 3.4 will also run on the following, but a cross-compiler hosted on another platform, such as win32, is required to build from source. Pocket PC devices running Windows CE 3.0 and higher H/PC Pro devices running Windows CE 2.11 and higher. Palm Size PC 1.1 devices running Windows CE 2.11 Previous versions of NetHack were tested on the following systems, and we expect that NetHack 3.4 will work on them as well: AT&T 3B1 running System V (3.51) AT&T 3B2/600 & 3B2/622 running System V R3.2.1 AT&T 3B2/1000 Model 80 running System V R3.2.2 AT&T 3B4000 running System V AT&T 6386 running System V R3.2 Data General AViiON systems running DG/UX DEC vaxen running BSD, Ultrix Decstations running Ultrix 3.1, 4.x Encore Multimax running UMAX 4.2 Gould NP1 running UTX 3/2 HP 9000s300 running HP-UX HP 9000s700 running HP-UX 9.x IBM PC/RT and RS/6000 running AIX 3.x IBM PS/2 and AT compatibles running OS/2 1.1 - 2.0 (and probably Warp) with Microsoft 6.0, and OS/2 2.0 and up with IBM CSet++ 2.0. Intel 80386 or greater (or clone) running 386BSD Mips M2000 running RiscOS 4.1 NeXT running Mach (using BSD configuration) Pyramid 9820x running OSx 4.4c SGI Iris running IRIX Stardent Vistra 800 running SysV R4.0 Stride 460 running UniStride 2.1 Sun-3s, -4s, and -386is running SunOS 3.x Sun-3s and -386is running SunOS 4.x Valid Logic Systems SCALD-System Unless otherwise mentioned, the compiler used was the OS-vendor's C compiler. With the demise of Windows NT on the DEC Alpha, no attempt has been made to build NetHack 3.4.3 on that platform. Windows 98/Me have been the most problematic Windows platforms for running NetHack so far. Patches for 3.4.2 (courtesy Michael Lehotay) have been incorporated into 3.4.3 to help make them work better. Your results may vary. A build for Intel 80286 machines and DOS "real mode" overlaid versions has not been produced for 3.4.3. Nobody on the porting team has the time or the software to attempt the necessary tuning that will allow it to achieve the balance of having just the right amount of available memory, and still have acceptable performance. The sources necessary to do so are still included in the source distribution, so if someone has access to a real-mode compiler and lots of spare time on their hands, you may be able to get things working. Of course you do so at your own risk. - - - - - - - - - - - If you have problems building the game, or you find bugs in it, we recommend filing a bug report from our "Contact Us" web page at: http://www.nethack.org/ When sending correspondence, please observe the following: o Please be sure to include your machine type, OS, and patchlevel. o Never send us binary files (e.g. save files or bones files). Whichever platform you are using, only a small minority of the development team has access to it, and you will rapidly annoy the others. If you have found a bug and think that your save file would aid in solving the problem, send us a description in words of the problem, your machine type, your operating system, and the version of NetHack. Tell us that you have a save file, but do not actually send it. In the rare case that we think your save file would be helpful, you will be contacted by a member of the development team with the address of a specific person to send the save file to. o Though we make an effort to reply to each bug report, it may take some time before you receive feedback. This is especially true during the period immediately after a new release, when we get the most bug reports. o We don't give hints for playing the game. o Don't bother to ask when the next version will be out. You will not get a reply. If you don't have access to the world wide web, or if you want to submit a patch for the NetHack source code via email directly, you can direct it to this address: nethack-bugs (at) nethack.org If you've changed something to get NetHack to run on your system, it's likely that others have done it by making slightly different modifications. By routing your patches through the development team, we should be able to avoid making everyone else choose among variant patches claiming to do the same thing, to keep most of the copies of 3.4 synchronized by means of official patches, and to maintain the painfully-created file organization. (This process has been working since the time when everyone just posted their own patches to 2.3. At that time, there were no archived bug-fixes to give to people who got 2.3 after its initial release, so the same bugs kept being discovered by new batches of people.) We have been successful in preventing this from happening since the 3.0 release. Please cooperate to keep this from happening to 3.4. It is inevitable that we will reject some proposed additions of new features either because they do not fit our conception of the game, or because they require more code than we consider they're worth. If we reject your feature, you are free, of course, to post the patches to the net yourself and let the marketplace decide their worth. All of this amounts to the following: If you decide to apply a free-lanced patch to your 3.4 code, you are on your own. In our own patches, we will assume that your code is synchronized with ours. -- Good luck, and happy Hacking -- nethack-3.4.3/doc/0040755000000000000000000000000007764735105012423 5ustar rootrootnethack-3.4.3/doc/Guidebook.mn0100644000000000000000000034231707764735041014675 0ustar rootroot.\" $Revision: 1.61.2.20 $ $Date: 2003/12/03 03:00:47 $ .ds h0 "NetHack Guidebook .ds h1 .ds h2 % .ds vr "NetHack 3.4 .ds f0 "\*(vr .ds f1 .ds f2 "December 2, 2003 .mt A Guide to the Mazes of Menace (Guidebook for NetHack) .au Eric S. Raymond (Extensively edited and expanded for 3.4) .hn 1 Introduction Recently, you have begun to find yourself unfulfilled and distant in your daily occupation. Strange dreams of prospecting, stealing, crusading, and combat have haunted you in your sleep for many months, but you aren't sure of the reason. You wonder whether you have in fact been having those dreams all your life, and somehow managed to forget about them until now. Some nights you awaken suddenly and cry out, terrified at the vivid recollection of the strange and powerful creatures that seem to be lurking behind every corner of the dungeon in your dream. Could these details haunting your dreams be real? As each night passes, you feel the desire to enter the mysterious caverns near the ruins grow stronger. Each morning, however, you quickly put the idea out of your head as you recall the tales of those who entered the caverns before you and did not return. Eventually you can resist the yearning to seek out the fantastic place in your dreams no longer. After all, when other adventurers came back this way after spending time in the caverns, they usually seemed better off than when they passed through the first time. And who was to say that all of those who did not return had not just kept going? .pg Asking around, you hear about a bauble, called the Amulet of Yendor by some, which, if you can find it, will bring you great wealth. One legend you were told even mentioned that the one who finds the amulet will be granted immortality by the gods. The amulet is rumored to be somewhere beyond the Valley of Gehennom, deep within the Mazes of Menace. Upon hearing the legends, you immediately realize that there is some profound and undiscovered reason that you are to descend into the caverns and seek out that amulet of which they spoke. Even if the rumors of the amulet's powers are untrue, you decide that you should at least be able to sell the tales of your adventures to the local minstrels for a tidy sum, especially if you encounter any of the terrifying and magical creatures of your dreams along the way. You spend one last night fortifying yourself at the local inn, becoming more and more depressed as you watch the odds of your success being posted on the inn's walls getting lower and lower. .pg In the morning you awake, collect your belongings, and set off for the dungeon. After several days of uneventful travel, you see the ancient ruins that mark the entrance to the Mazes of Menace. It is late at night, so you make camp at the entrance and spend the night sleeping under the open skies. In the morning, you gather your gear, eat what may be your last meal outside, and enter the dungeon... .hn 1 What is going on here? .pg You have just begun a game of NetHack. Your goal is to grab as much treasure as you can, retrieve the Amulet of Yendor, and escape the Mazes of Menace alive. .pg Your abilities and strengths for dealing with the hazards of adventure will vary with your background and training: .pg \fIArcheologists\fP understand dungeons pretty well; this enables them to move quickly and sneak up on the local nasties. They start equipped with the tools for a proper scientific expedition. .pg \fIBarbarians\fP are warriors out of the hinterland, hardened to battle. They begin their quests with naught but uncommon strength, a trusty hauberk, and a great two-handed sword. .pg \fICavemen\fP and \fICavewomen\fP start with exceptional strength but, unfortunately, with neolithic weapons. .pg \fIHealers\fP are wise in medicine and apothecary. They know the herbs and simples that can restore vitality, ease pain, anesthetize, and neutralize poisons; and with their instruments, they can divine a being's state of health or sickness. Their medical practice earns them quite reasonable amounts of money, with which they enter the dungeon. .pg \fIKnights\fP are distinguished from the common skirmisher by their devotion to the ideals of chivalry and by the surpassing excellence of their armor. .pg \fIMonks\fP are ascetics, who by rigorous practice of physical and mental disciplines have become capable of fighting as effectively without weapons as with. They wear no armor but make up for it with increased mobility. .pg \fIPriests\fP and \fIPriestesses\fP are clerics militant, crusaders advancing the cause of righteousness with arms, armor, and arts thaumaturgic. Their ability to commune with deities via prayer occasionally extricates them from peril, but can also put them in it. .pg \fIRangers\fP are most at home in the woods, and some say slightly out of place in a dungeon. They are, however, experts in archery as well as tracking and stealthy movement. .pg \fIRogues\fP are agile and stealthy thieves, with knowledge of locks, traps, and poisons. Their advantage lies in surprise, which they employ to great advantage. .pg \fISamurai\fP are the elite warriors of feudal Nippon. They are lightly armored and quick, and wear the \fIdai-sho\fP, two swords of the deadliest keenness. .pg \fITourists\fP start out with lots of gold (suitable for shopping with), a credit card, lots of food, some maps, and an expensive camera. Most monsters don't like being photographed. .pg \fIValkyries\fP are hardy warrior women. Their upbringing in the harsh Northlands makes them strong, inures them to extremes of cold, and instills in them stealth and cunning. .pg \fIWizards\fP start out with a knowledge of magic, a selection of magical items, and a particular affinity for dweomercraft. Although seemingly weak and easy to overcome at first sight, an experienced Wizard is a deadly foe. .pg You may also choose the race of your character: .pg \fIDwarves\fP are smaller than humans or elves, but are stocky and solid individuals. Dwarves' most notable trait is their great expertise in mining and metalwork. Dwarvish armor is said to be second in quality not even to the mithril armor of the Elves. .pg \fIElves\fP are agile, quick, and perceptive; very little of what goes on will escape an Elf. The quality of Elven craftsmanship often gives them an advantage in arms and armor. .pg \fIGnomes\fP are smaller than but generally similar to dwarves. Gnomes are known to be expert miners, and it is known that a secret underground mine complex built by this race exists within the Mazes of Menace, filled with both riches and danger. .pg \fIHumans\fP are by far the most common race of the surface world, and are thus the norm by which other races are often compared. Although they have no special abilities, they can succeed in any role. .pg \fIOrcs\fP are a cruel and barbaric race that hate every living thing (including other orcs). Above all others, Orcs hate Elves with a passion unequalled, and will go out of their way to kill one at any opportunity. The armor and weapons fashioned by the Orcs are typically of inferior quality. .hn 1 What do all those things on the screen mean? .pg On the screen is kept a map of where you have been and what you have seen on the current dungeon level; as you explore more of the level, it appears on the screen in front of you. .pg When NetHack's ancestor \fIrogue\fP first appeared, its screen orientation was almost unique among computer fantasy games. Since then, screen orientation has become the norm rather than the exception; NetHack continues this fine tradition. Unlike text adventure games that accept commands in pseudo-English sentences and explain the results in words, NetHack commands are all one or two keystrokes and the results are displayed graphically on the screen. A minimum screen size of 24 lines by 80 columns is recommended; if the screen is larger, only a 21x80 section will be used for the map. .pg NetHack can even be played by blind players, with the assistance of Braille readers or speech synthesisers. Instructions for configuring NetHack for the blind are included later in this document. .pg NetHack generates a new dungeon every time you play it; even the authors still find it an entertaining and exciting game despite having won several times. .pg NetHack offers a variety of display options. The options available to you will vary from port to port, depending on the capabilities of your hardware and software, and whether various compile-time options were enabled when your executable was created. The three possible display options are: a monochrome character interface, a color character interface, and a graphical interface using small pictures called tiles. The two character interfaces allow fonts with other characters to be substituted, but the default assignments use standard ASCII characters to represent everything. There is no difference between the various display options with respect to game play. Because we cannot reproduce the tiles or colors in the Guidebook, and because it is common to all ports, we will use the default ASCII characters from the monochrome character display when referring to things you might see on the screen during your game. .pg In order to understand what is going on in NetHack, first you must understand what NetHack is doing with the screen. The NetHack screen replaces the ``You see ...'' descriptions of text adventure games. Figure 1 is a sample of what a NetHack screen might look like. The way the screen looks for you depends on your platform. .TS S center tab(~); a. _ The bat bites! ------ |....| ---------- |.<..|####...@...$.| |....-# |...B....+ |....| |.d......| ------ -------|-- Player the Rambler St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15 Neutral Dlvl:1 $:0 HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak _ .TE .ce 1 Figure 1 .hn 2 The status lines (bottom) .pg The bottom two lines of the screen contain several cryptic pieces of information describing your current status. If either status line becomes longer than the width of the screen, you might not see all of it. Here are explanations of what the various status items mean (though your configuration may not have all the status items listed below): .lp "Rank " Your character's name and professional ranking (based on the experience level, see below). .lp Strength A measure of your character's strength; one of your six basic attributes. A human character's attributes can range from 3 to 18 inclusive; non-humans may exceed these limits (occasionally you may get super-strengths of the form 18/xx, and magic can also cause attributes to exceed the normal limits). The higher your strength, the stronger you are. Strength affects how successfully you perform physical tasks, how much damage you do in combat, and how much loot you can carry. .lp Dexterity Dexterity affects your chances to hit in combat, to avoid traps, and do other tasks requiring agility or manipulation of objects. .lp Constitution Constitution affects your ability to recover from injuries and other strains on your stamina. .lp Intelligence Intelligence affects your ability to cast spells and read spellbooks. .lp Wisdom Wisdom comes from your practical experience (especially when dealing with magic). It affects your magical energy. .lp Charisma Charisma affects how certain creatures react toward you. In particular, it can affect the prices shopkeepers offer you. .lp Alignment \fBLawful\fP, \fBNeutral\fP, or \fBChaotic\fP. Often, Lawful is taken as good and Chaotic as evil, but legal and ethical do not always coincide. Your alignment influences how other monsters react toward you. Monsters of a like alignment are more likely to be non-aggressive, while those of an opposing alignment are more likely to be seriously offended at your presence. .lp "Dungeon Level How deep you are in the dungeon. You start at level one and the number increases as you go deeper into the dungeon. Some levels are special, and are identified by a name and not a number. The Amulet of Yendor is reputed to be somewhere beneath the twentieth level. .lp "Gold " The number of gold pieces you are openly carrying. Gold which you have concealed in containers is not counted. .lp "Hit Points Your current and maximum hit points. Hit points indicate how much damage you can take before you die. The more you get hit in a fight, the lower they get. You can regain hit points by resting, or by using certain magical items or spells. The number in parentheses is the maximum number your hit points can reach. .lp Power Spell points. This tells you how much mystic energy (\fImana\fP) you have available for spell casting. Again, resting will regenerate the amount available. .lp "Armor Class A measure of how effectively your armor stops blows from unfriendly creatures. The lower this number is, the more effective the armor; it is quite possible to have negative armor class. .lp Experience Your current experience level and experience points. As you adventure, you gain experience points. At certain experience point totals, you gain an experience level. The more experienced you are, the better you fight and withstand magical attacks. Many dungeons show only your experience level here. .lp "Time " The number of turns elapsed so far, displayed if you have the .op time option set. .lp "Hunger status Your current hunger status, ranging from \fBSatiated\fP down to \fBFainting\fP. If your hunger status is normal, it is not displayed. .pg Additional status flags may appear after the hunger status: \fBConf\fP when you're confused, \fBFoodPois\fP or \fBIll\fP when sick, \fBBlind\fP when you can't see, \fBStun\fP when stunned, and \fBHallu\fP when hallucinating. .hn 2 The message line (top) .pg The top line of the screen is reserved for messages that describe things that are impossible to represent visually. If you see a ``\fB--More--\fP'' on the top line, this means that NetHack has another message to display on the screen, but it wants to make certain that you've read the one that is there first. To read the next message, just press the space bar. .hn 2 The map (rest of the screen) .pg The rest of the screen is the map of the level as you have explored it so far. Each symbol on the screen represents something. You can set various graphics options to change some of the symbols the game uses; otherwise, the game will use default symbols. Here is a list of what the default symbols mean: .lp "- and | The walls of a room, or an open door. Or a grave (|). .lp . The floor of a room, ice, or a doorless doorway. .lp # A corridor, or iron bars, or a tree, or possibly a kitchen sink (if your dungeon has sinks), or a drawbridge. .lp > Stairs down: a way to the next level. .lp < Stairs up: a way to the previous level. .lp + A closed door, or a spellbook containing a spell you may be able to learn. .lp @ Your character or a human. .lp $ A pile of gold. .lp ^ A trap (once you have detected it). .lp ) A weapon. .lp [ A suit or piece of armor. .lp % Something edible (not necessarily healthy). .lp ? A scroll. .lp / A wand. .lp = A ring. .lp ! A potion. .lp ( A useful item (pick-axe, key, lamp...). .lp """ An amulet or a spider web. .lp * A gem or rock (possibly valuable, possibly worthless). .lp ` A boulder or statue. .lp 0 An iron ball. .lp _ An altar, or an iron chain. .lp { A fountain. .lp } A pool of water or moat or a pool of lava. .lp "\e An opulent throne. .lp "a-zA-Z and other symbols Letters and certain other symbols represent the various inhabitants of the Mazes of Menace. Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. .lp I This marks the last known location of an invisible or otherwise unseen monster. Note that the monster could have moved. The 'F' and 'm' commands may be useful here. .pg You need not memorize all these symbols; you can ask the game what any symbol represents with the `/' command (see the next section for more info). .hn 1 Commands .pg Commands are initiated by typing one or two characters. Some commands, like ``search'', do not require that any more information be collected by NetHack. Other commands might require additional information, for example a direction, or an object to be used. For those commands that require additional information, NetHack will present you with either a menu of choices or with a command line prompt requesting information. Which you are presented with will depend chiefly on how you have set the .op menustyle option. .pg For example, a common question, in the form ``What do you want to use?\ [a-zA-Z\ ?*]'', asks you to choose an object you are carrying. Here, ``a-zA-Z'' are the inventory letters of your possible choices. Typing `?' gives you an inventory list of these items, so you can see what each letter refers to. In this example, there is also a `*' indicating that you may choose an object not on the list, if you wanted to use something unexpected. Typing a `*' lists your entire inventory, so you can see the inventory letters of every object you're carrying. Finally, if you change your mind and decide you don't want to do this command after all, you can press the ESC key to abort the command. .pg You can put a number before some commands to repeat them that many times; for example, ``10s'' will search ten times. If you have the .op number_pad option set, you must type `n' to prefix a count, so the example above would be typed ``n10s'' instead. Commands for which counts make no sense ignore them. In addition, movement commands can be prefixed for greater control (see below). To cancel a count or a prefix, press the ESC key. .pg The list of commands is rather long, but it can be read at any time during the game through the `?' command, which accesses a menu of helpful texts. Here are the commands for your reference: .lp ? Help menu: display one of several help texts available. .lp / Tell what a symbol represents. You may choose to specify a location or type a symbol (or even a whole word) to explain. Specifying a location is done by moving the cursor to a particular spot on the map and then pressing one of `.', `,', `;', or `:'. `.' will explain the symbol at the chosen location, conditionally check for ``More info?'' depending upon whether the .op help option is on, and then you will be asked to pick another location; `,' will explain the symbol but skip any additional information; `;' will skip additional info and also not bother asking you to choose another location to examine; `:' will show additional info, if any, without asking for confirmation. When picking a location, pressing the ESC key will terminate this command, or pressing `?' will give a brief reminder about how it works. .pg Specifying a name rather than a location always gives any additional information available about that name. .lp & Tell what a command does. .lp < Go up to the previous level (if you are on a staircase or ladder). .lp > Go down to the next level (if you are on a staircase or ladder). .lp [yuhjklbn] Go one step in the direction indicated (see Figure 2). If you sense or remember a monster there, you will fight the monster instead. Only these one-step movement commands cause you to fight monsters; the others (below) are ``safe.'' .sd .TS S center; c c. y k u 7 8 9 \e | / \e | / h- . -l 4- . -6 / | \e / | \e b j n 1 2 3 (if \fBnumber_pad\fP is set) .TE .ed .ce 1 Figure 2 .lp [YUHJKLBN] Go in that direction until you hit a wall or run into something. .lp m[yuhjklbn] Prefix: move without picking up objects or fighting (even if you remember a monster there) .lp F[yuhjklbn] Prefix: fight a monster (even if you only guess one is there) .lp M[yuhjklbn] Prefix: move far, no pickup. .lp "g[yuhjklbn] Prefix: move until something interesting is found. .lp "G[yuhjklbn] or [yuhjklbn] Prefix: same as `g', but forking of corridors is not considered interesting. .lp _ Travel to a map location via a shortest-path algorithm. The shortest path is computed over map locations the hero knows about (e.g. seen or previously traversed). If there is no known path, a guess is made instead. Stops on most of the same conditions as the `G' command, but without picking up objects, similar to the `M' command. For ports with mouse support, the command is also invoked when a mouse-click takes place on a location other than the current position. .lp . Rest, do nothing for one turn. .lp a Apply (use) a tool (pick-axe, key, lamp...). .lp A Remove one or more worn items, such as armor. Use `T' (take off) to take off only one piece of armor or `R' (remove) to take off only one accessory. .lp ^A Redo the previous command. .lp c Close a door. .lp C Call (name) an individual monster. .lp ^C Panic button. Quit the game. .lp d Drop something. Ex. ``d7a'' means drop seven items of object \fIa\fP. .lp D Drop several things. In answer to the question ``What kinds of things do you want to drop? [!%= BUCXaium]'' you should type zero or more object symbols possibly followed by `a' and/or `i' and/or `u' and/or `m'. In addition, one or more of the blessed/uncursed/cursed groups may be typed. .sd .si DB - drop all objects known to be blessed. DU - drop all objects known to be uncursed. DC - drop all objects known to be cursed. DX - drop all objects of unknown B/U/C status. Da - drop all objects, without asking for confirmation. Di - examine your inventory before dropping anything. Du - drop only unpaid objects (when in a shop). Dm - use a menu to pick which object(s) to drop. D%u - drop only unpaid food. .ei .ed .lp ^D Kick something (usually a door). .lp e Eat food. .\" Make sure Elbereth is not hyphenated below, the exact spelling matters .hw Elbereth .lp E Engrave a message on the floor. Engraving the word ``Elbereth'' will cause most monsters to not attack you hand-to-hand (but if you attack, you will rub it out); this is often useful to give yourself a breather. (This feature may be compiled out of the game, so your version might not have it.) .sd .si E- - write in the dust with your fingers. .ei .ed .lp f Fire one of the objects placed in your quiver. You may select ammunition with a previous `Q' command, or let the computer pick something appropriate if .op autoquiver is true. .lp i List your inventory (everything you're carrying). .lp I List selected parts of your inventory. .sd .si I* - list all gems in inventory; Iu - list all unpaid items; Ix - list all used up items that are on your shopping bill; I$ - count your money. .ei .ed .lp o Open a door. .lp O Set options. A menu showing the current option values will be displayed. You can change most values simply by selecting the menu entry for the given option (ie, by typing its letter or clicking upon it, depending on your user interface). For the non-boolean choices, a further menu or prompt will appear once you've closed this menu. The available options are listed later in this Guidebook. Options are usually set before the game rather than with the `O' command; see the section on options below. .lp p Pay your shopping bill. .lp P Put on a ring or other accessory (amulet, blindfold). .lp ^P Repeat previous message. Subsequent ^P's repeat earlier messages. The behavior can be varied via the msg_window option. .lp q Quaff (drink) something (potion, water, etc). .lp Q Select an object for your quiver. You can then throw this using the `f' command. (In versions prior to 3.3 this was the command to quit the game, which has now been moved to `#quit'.) .lp r Read a scroll or spellbook. .lp R Remove an accessory (ring, amulet, etc). .lp ^R Redraw the screen. .lp s Search for secret doors and traps around you. It usually takes several tries to find something. .lp S Save (and suspend) the game. The game will be restored automatically the next time you play. .lp t Throw an object or shoot a projectile. .lp T Take off armor. .lp ^T Teleport, if you have the ability. .lp v Display version number. .lp V Display the game history. .lp w Wield weapon. .sd .si w- - wield nothing, use your bare hands. .ei .ed .lp W Wear armor. .lp x Exchange your wielded weapon with the item in your alternate weapon slot. The latter is used as your secondary weapon when engaging in two-weapon combat. Note that if one of these slots is empty, the exchange still takes place. .lp X Enter explore (discovery) mode, explained in its own section later. .lp ^X Display your name, role, race, gender, and alignment as well as the various deities in your game. .lp z Zap a wand. To aim at yourself, use `.' for the direction. .lp Z Zap (cast) a spell. To cast at yourself, use `.' for the direction. .lp ^Z Suspend the game .ux " versions with job control only)." ( .lp : Look at what is here. .lp ; Show what type of thing a visible symbol corresponds to. .lp , Pick up some things. May be preceded by `m' to force a selection menu. .lp @ Toggle the .op autopickup option on and off. .lp ^ Ask for the type of a trap you found earlier. .lp ) Tell what weapon you are wielding. .lp [ Tell what armor you are wearing. .lp = Tell what rings you are wearing. .lp """ Tell what amulet you are wearing. .lp ( Tell what tools you are using. .lp * Tell what equipment you are using; combines the preceding five type-specific commands into one. .lp $ Count your gold pieces. .lp + List the spells you know. Using this command, you can also rearrange the order in which your spells are listed. They are shown via a menu, and if you select a spell in that menu, you'll be re-prompted for another spell to swap places with it, and then have opportunity to make further exchanges. .lp "\e Show what types of objects have been discovered. .lp ! Escape to a shell. .lp # Perform an extended command. As you can see, the authors of NetHack used up all the letters, so this is a way to introduce the less frequently used commands. What extended commands are available depends on what features the game was compiled with. .lp #adjust Adjust inventory letters (most useful when the .op fixinv option is ``on''). .lp #chat Talk to someone. .lp #conduct List which challenges you have adhered to. See the section below entitled ``Conduct'' for details. .lp #dip Dip an object into something. .lp #enhance Advance or check weapons and spell skills. .lp #force Force a lock. .lp #invoke Invoke an object's special powers. .lp #jump Jump to another location. .lp #loot Loot a box or bag on the floor beneath you, or the saddle from a horse standing next to you. .lp #monster Use a monster's special ability (when polymorphed into monster form). .lp #name Name an item or type of object. .lp #offer Offer a sacrifice to the gods. .lp #pray Pray to the gods for help. .lp #quit Quit the program without saving your game. .lp #ride Ride (or stop riding) a monster. .lp #rub Rub a lamp or a stone. .lp #sit Sit down. .lp #turn Turn undead. .lp #twoweapon Toggle two-weapon combat on or off. Note that you must use suitable weapons for this type of combat, or it will be automatically turned off. .lp #untrap Untrap something (trap, door, or chest). .lp #version Print compile time options for this version of NetHack. .lp #wipe Wipe off your face. .lp #? Help menu: get the list of available extended commands. .pg If your keyboard has a meta key (which, when pressed in combination with another key, modifies it by setting the `meta' [8th, or `high'] bit), you can invoke many extended commands by meta-ing the first letter of the command. .\" In {\it NT, OS/2, PC\/ {\rm and} ST NetHack}, .\" the `Alt' key can be used in this fashion; .\" on the Amiga set the {\it altmeta\/} option to get this behavior. In NT, OS/2, and PC NetHack, the `Alt' key can be used in this fashion. .lp M-? #? (not supported by all platforms) .lp M-2 #twoweapon (unless the number_pad option is enabled) .lp M-a #adjust .lp M-c #chat .lp M-d #dip .lp M-e #enhance .lp M-f #force .lp M-i #invoke .lp M-j #jump .lp M-l #loot .lp M-m #monster .lp M-n #name .lp M-o #offer .lp M-p #pray .lp M-q #quit .lp M-r #rub .lp M-s #sit .lp M-t #turn .lp M-u #untrap .lp M-v #version .lp M-w #wipe .pg If the .op number_pad option is on, some additional letter commands are available: .lp h Help menu: display one of several help texts available, like ``?''. .lp j Jump to another location. Same as ``#jump'' or ``M-j''. .lp k Kick something (usually a door). Same as `^D'. .lp l Loot a box or bag on the floor beneath you, or the saddle from a horse standing next to you. Same as ``#loot'' or ``M-l''. .lp N Name an item or type of object. Same as ``#name'' or ``M-n''. .lp u Untrap a trap, door, or chest. Same as ``#untrap'' or ``M-u''. .hn 1 Rooms and corridors .pg Rooms and corridors in the dungeon are either lit or dark. Any lit areas within your line of sight will be displayed; dark areas are only displayed if they are within one space of you. Walls and corridors remain on the map as you explore them. .pg Secret corridors are hidden. You can find them with the `s' (search) command. .hn 2 Doorways .pg Doorways connect rooms and corridors. Some doorways have no doors; you can walk right through. Others have doors in them, which may be open, closed, or locked. To open a closed door, use the `o' (open) command; to close it again, use the `c' (close) command. .pg You can get through a locked door by using a tool to pick the lock with the `a' (apply) command, or by kicking it open with the `^D' (kick) command. .pg Open doors cannot be entered diagonally; you must approach them straight on, horizontally or vertically. Doorways without doors are not restricted in this fashion. .pg Doors can be useful for shutting out monsters. Most monsters cannot open doors, although a few don't need to (ex. ghosts can walk through doors). .pg Secret doors are hidden. You can find them with the `s' (search) command. Once found they are in all ways equivalent to normal doors. .hn 2 Traps (`^') .pg There are traps throughout the dungeon to snare the unwary delver. For example, you may suddenly fall into a pit and be stuck for a few turns trying to climb out. Traps don't appear on your map until you see one triggered by moving onto it, see something fall into it, or you discover it with the `s' (search) command. Monsters can fall prey to traps, too, which can be a very useful defensive strategy. .pg There is a special pre-mapped branch of the dungeon based on the classic computer game ``Sokoban.'' The goal is to push the boulders into the pits or holes. With careful foresight, it is possible to complete all of the levels according to the traditional rules of Sokoban. Some allowances are permitted in case the player gets stuck; however, they will lower your luck. .hn 2 Stairs (`<', `>') .pg In general, each level in the dungeon will have a staircase going up (`<') to the previous level and another going down (`>') to the next level. There are some exceptions though. For instance, fairly early in the dungeon you will find a level with two down staircases, one continuing into the dungeon and the other branching into an area known as the Gnomish Mines. Those mines eventually hit a dead end, so after exploring them (if you choose to do so), you'll need to climb back up to the main dungeon. .pg When you traverse a set of stairs, or trigger a trap which sends you to another level, the level you're leaving will be deactivated and stored in a file on disk. If you're moving to a previously visited level, it will be loaded from its file on disk and reactivated. If you're moving to a level which has not yet been visited, it will be created (from scratch for most random levels, from a template for some ``special'' levels, or loaded from the remains of an earlier game for a ``bones'' level as briefly described below). Monsters are only active on the current level; those on other levels are essentially placed into stasis. .pg Ordinarily when you climb a set of stairs, you will arrive on the corresponding staircase at your destination. However, pets (see below) and some other monsters will follow along if they're close enough when you travel up or down stairs, and occasionally one of these creatures will displace you during the climb. When that occurs, the pet or other monster will arrive on the staircase and you will end up nearby. .hn 2 Ladders (`<', `>') .pg Ladders serve the same purpose as staircases, and the two types of inter-level connections are nearly indistinguishable during game play. .hn 2 Shops and shopping .pg Occasionally you will run across a room with a shopkeeper near the door and many items lying on the floor. You can buy items by picking them up and then using the `p' command. You can inquire about the price of an item prior to picking it up by using the ``#chat'' command while standing on it. Using an item prior to paying for it will incur a charge, and the shopkeeper won't allow you to leave the shop until you have paid any debt you owe. .pg You can sell items to a shopkeeper by dropping them to the floor while inside a shop. You will either be offered an amount of gold and asked whether you're willing to sell, or you'll be told that the shopkeeper isn't interested (generally, your item needs to be compatible with the type of merchandise carried by the shop). .pg If you drop something in a shop by accident, the shopkeeper will usually claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. .pg Shopkeepers sometimes run out of money. When that happens, you'll be offered credit instead of gold when you try to sell something. Credit can be used to pay for purchases, but it is only good in the shop where it was obtained; other shopkeepers won't honor it. (If you happen to find a "credit card" in the dungeon, don't bother trying to use it in shops; shopkeepers will not accept it.) .pg The `$' command, which reports the amount of gold you are carrying (in inventory, not inside bags or boxes), will also show current shop debt or credit, if any. The `Iu' command lists unpaid items (those which still belong to the shop) if you are carrying any. The `Ix' command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. .hn 3 Shop idiosyncracies .pg Several aspects of shop behavior might be unexpected. .\" note: using * instead of \(bu is better for plain text output .lp * 2 The price of a given item can vary due to a variety of factors. .lp * 2 A shopkeeper treats the spot immediately inside the door as if it were outside the shop. .lp * 2 While the shopkeeper watches you like a hawk, he will generally ignore any other customers. .lp * 2 If a shop is "closed for inventory", it will not open of its own accord. .lp * 2 Shops do not get restocked with new items, regardless of inventory depletion. .hn 1 Monsters .pg Monsters you cannot see are not displayed on the screen. Beware! You may suddenly come upon one in a dark place. Some magic items can help you locate them before they locate you (which some monsters can do very well). .pg The commands `/' and `;' may be used to obtain information about those monsters who are displayed on the screen. The command `C' allows you to assign a name to a monster, which may be useful to help distinguish one from another when multiple monsters are present. Assigning a name which is just a space will remove any prior name. .pg The extended command ``#chat'' can be used to interact with an adjacent monster. There is no actual dialog (in other words, you don't get to choose what you'll say), but chatting with some monsters such as a shopkeeper or the Oracle of Delphi can produce useful results. .hn 2 Fighting .pg If you see a monster and you wish to fight it, just attempt to walk into it. Many monsters you find will mind their own business unless you attack them. Some of them are very dangerous when angered. Remember: discretion is the better part of valor. .pg If you can't see a monster (if it is invisible, or if you are blinded), the symbol `I' will be shown when you learn of its presence. If you attempt to walk into it, you will try to fight it just like a monster that you can see; of course, if the monster has moved, you will attack empty air. If you guess that the monster has moved and you don't wish to fight, you can use the `m' command to move without fighting; likewise, if you don't remember a monster but want to try fighting anyway, you can use the `F' command. .hn 2 Your pet .pg You start the game with a little dog (`d'), cat (`f'), or pony (`u'), which follows you about the dungeon and fights monsters with you. Like you, your pet needs food to survive. It usually feeds itself on fresh carrion and other meats. If you're worried about it or want to train it, you can feed it, too, by throwing it food. A properly trained pet can be very useful under certain circumstances. .pg Your pet also gains experience from killing monsters, and can grow over time, gaining hit points and doing more damage. Initially, your pet may even be better at killing things than you, which makes pets useful for low-level characters. .pg Your pet will follow you up and down staircases if it is next to you when you move. Otherwise your pet will be stranded and may become wild. Similarly, when you trigger certain types of traps which alter your location (for instance, a trap door which drops you to a lower dungeon level), any adjacent pet will accompany you and any non-adjacent pet will be left behind. Your pet may trigger such traps itself; you will not be carried along with it even if adjacent at the time. .hn 2 Steeds .pg Some types of creatures in the dungeon can actually be ridden if you have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer has had to resort to magic and wizardry in order to forge the alliance. Once you do have the beast under your control however, you can easily climb in and out of the saddle with the `#ride' command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. .pg Riding skill is managed by the `#enhance' command. See the section on Weapon proficiency for more information about that. .hn 2 Bones levels .pg You may encounter the shades and corpses of other adventurers (or even former incarnations of yourself!) and their personal effects. Ghosts are hard to kill, but easy to avoid, since they're slow and do little damage. You can plunder the deceased adventurer's possessions; however, they are likely to be cursed. Beware of whatever killed the former player; it is probably still lurking around, gloating over its last victory. .hn 1 Objects .pg When you find something in the dungeon, it is common to want to pick it up. In NetHack, this is accomplished automatically by walking over the object (unless you turn off the .op autopickup option (see below), or move with the `m' prefix (see above)), or manually by using the `,' command. .pg If you're carrying too many items, NetHack will tell you so and you won't be able to pick up anything more. Otherwise, it will add the object(s) to your pack and tell you what you just picked up. .pg As you add items to your inventory, you also add the weight of that object to your load. The amount that you can carry depends on your strength and your constitution. The stronger you are, the less the additional load will affect you. There comes a point, though, when the weight of all of that stuff you are carrying around with you through the dungeon will encumber you. Your reactions will get slower and you'll burn calories faster, requiring food more frequently to cope with it. Eventually, you'll be so overloaded that you'll either have to discard some of what you're carrying or collapse under its weight. .pg NetHack will tell you how badly you have loaded yourself. The symbols `Burdened', `Stressed', `Strained', `Overtaxed' and `Overloaded' are displayed on the bottom line display to indicate your condition. .pg When you pick up an object, it is assigned an inventory letter. Many commands that operate on objects must ask you to find out which object you want to use. When NetHack asks you to choose a particular object you are carrying, you are usually presented with a list of inventory letters to choose from (see Commands, above). .pg Some objects, such as weapons, are easily differentiated. Others, like scrolls and potions, are given descriptions which vary according to type. During a game, any two objects with the same description are the same type. However, the descriptions will vary from game to game. .pg When you use one of these objects, if its effect is obvious, NetHack will remember what it is for you. If its effect isn't extremely obvious, you will be asked what you want to call this type of object so you will recognize it later. You can also use the ``#name'' command for the same purpose at any time, to name all objects of a particular type or just an individual object. When you use ``#name'' on an object which has already been named, specifying a space as the value will remove the prior name instead of assigning a new one. .hn 2 Curses and Blessings .pg Any object that you find may be cursed, even if the object is otherwise helpful. The most common effect of a curse is being stuck with (and to) the item. Cursed weapons weld themselves to your hand when wielded, so you cannot unwield them. Any cursed item you wear is not removable by ordinary means. In addition, cursed arms and armor usually, but not always, bear negative enchantments that make them less effective in combat. Other cursed objects may act poorly or detrimentally in other ways. .pg Objects can also be blessed. Blessed items usually work better or more beneficially than normal uncursed items. For example, a blessed weapon will do more damage against demons. .pg There are magical means of bestowing or removing curses upon objects, so even if you are stuck with one, you can still have the curse lifted and the item removed. Priests and Priestesses have an innate sensitivity to this property in any object, so they can more easily avoid cursed objects than other character roles. .pg An item with unknown status will be reported in your inventory with no prefix. An item which you know the state of will be distinguished in your inventory by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the description of the item. .hn 2 Weapons (`)') .pg Given a chance, most monsters in the Mazes of Menace will gratuitously try to kill you. You need weapons for self-defense (killing them first). Without a weapon, you do only 1-2 hit points of damage (plus bonuses, if any). Monk characters are an exception; they normally do much more damage with bare hands than they do with weapons. .pg There are wielded weapons, like maces and swords, and thrown weapons, like arrows and spears. To hit monsters with a weapon, you must wield it and attack them, or throw it at them. You can simply elect to throw a spear. To shoot an arrow, you should first wield a bow, then throw the arrow. Crossbows shoot crossbow bolts. Slings hurl rocks and (other) stones (like gems). .pg Enchanted weapons have a ``plus'' (or ``to hit enhancement'' which can be either positive or negative) that adds to your chance to hit and the damage you do to a monster. The only way to determine a weapon's enchantment is to have it magically identified somehow. Most weapons are subject to some type of damage like rust. Such ``erosion'' damage can be repaired. .pg The chance that an attack will successfully hit a monster, and the amount of damage such a hit will do, depends upon many factors. Among them are: type of weapon, quality of weapon (enchantment and/or erosion), experience level, strength, dexterity, encumbrance, and proficiency (see below). The monster's armor class - a general defense rating, not necessarily due to wearing of armor - is a factor too; also, some monsters are particularly vulnerable to certain types of weapons. .pg Many weapons can be wielded in one hand; some require both hands. When wielding a two-handed weapon, you can not wear a shield, and vice versa. When wielding a one-handed weapon, you can have another weapon ready to use by setting things up with the `x' command, which exchanges your primary (the one being wielded) and alternate weapons. And if you have proficiency in the ``two weapon combat'' skill, you may wield both weapons simultaneously as primary and secondary; use the `#twoweapon' extended command to engage or disengage that. Only some types of characters (barbarians, for instance) have the necessary skill available. Even with that skill, using two weapons at once incurs a penalty in the chance to hit your target compared to using just one weapon at a time. .pg There might be times when you'd rather not wield any weapon at all. To accomplish that, wield `-', or else use the `A' command which allows you to unwield the current weapon in addition to taking off other worn items. .pg Those of you in the audience who are AD&D players, be aware that each weapon which existed in AD&D does roughly the same damage to monsters in NetHack. Some of the more obscure weapons (such as the \fIaklys\fP, \fIlucern hammer\fP, and \fIbec-de-corbin\fP) are defined in an appendix to \fIUnearthed Arcana\fP, an AD&D supplement. .pg The commands to use weapons are `w' (wield), `t' (throw), `f' (fire, an alternative way of throwing), `Q' (quiver), `x' (exchange), `#twoweapon', and `#enhance' (see below). .hn 3 Throwing and shooting .pg You can throw just about anything via the `t' command. It will prompt for the item to throw; picking `?' will list things in your inventory which are considered likely to be thrown, or picking `*' will list your entire inventory. After you've chosen what to throw, you will be prompted for a direction rather than for a specific target. The distance something can be thrown depends mainly on the type of object and your strength. Arrows can be thrown by hand, but can be thrown much farther and will be more likely to hit when thrown while you are wielding a bow. .pg You can simplify the throwing operation by using the `Q' command to select your preferred ``missile'', then using the `f' command to throw it. You'll be prompted for a direction as above, but you don't have to specify which item to throw each time you use `f'. There is also an option, .op autoquiver, which has NetHack choose another item to automatically fill your quiver when the inventory slot used for `Q' runs out. .pg Some characters have the ability to fire a volley of multiple items in a single turn. Knowing how to load several rounds of ammunition at once -- or hold several missiles in your hand -- and still hit a target is not an easy task. Rangers are among those who are adept at this task, as are those with a high level of proficiency in the relevant weapon skill (in bow skill if you're wielding one to shoot arrows, in crossbow skill if you're wielding one to shoot bolts, or in sling skill if you're wielding one to shoot stones). The number of items that the character has a chance to fire varies from turn to turn. You can explicitly limit the number of shots by using a numeric prefix before the `t' or `f' command. For example, ``2f'' (or ``n2f'' if using .op number_pad mode) would ensure that at most 2 arrows are shot even if you could have fired 3. If you specify a larger number than would have been shot (``4f'' in this example), you'll just end up shooting the same number (3, here) as if no limit had been specified. Once the volley is in motion, all of the items will travel in the same direction; if the first ones kill a monster, the others can still continue beyond that spot. .hn 3 Weapon proficiency .pg You will have varying degrees of skill in the weapons available. Weapon proficiency, or weapon skills, affect how well you can use particular types of weapons, and you'll be able to improve your skills as you progress through a game, depending on your role, your experience level, and use of the weapons. .pg For the purposes of proficiency, weapons have been divided up into various groups such as daggers, broadswords, and polearms. Each role has a limit on what level of proficiency a character can achieve for each group. For instance, wizards can become highly skilled in daggers or staves but not in swords or bows. .pg The `#enhance' extended command is used to review current weapons proficiency (also spell proficiency) and to choose which skill(s) to improve when you've used one or more skills enough to become eligible to do so. The skill rankings are ``none'' (sometimes also referred to as ``restricted'', because you won't be able to advance), ``unskilled'', ``basic'', ``skilled'', and ``expert''. Restricted skills simply will not appear in the list shown by `#enhance'. (Divine intervention might unrestrict a particular skill, in which case it will start at unskilled and be limited to basic.) Some characters can enhance their barehanded combat or martial arts skill beyond expert to ``master'' or ``grand master''. .pg Use of a weapon in which you're restricted or unskilled will incur a modest penalty in the chance to hit a monster and also in the amount of damage done when you do hit; at basic level, there is no penalty or bonus; at skilled level, you receive a modest bonus in the chance to hit and amount of damage done; at expert level, the bonus is higher. A successful hit has a chance to boost your training towards the next skill level (unless you've already reached the limit for this skill). Once such training reaches the threshold for that next level, you'll be told that you feel more confident in your skills. At that point you can use `#enhance' to increase one or more skills. Such skills are not increased automatically because there is a limit to your total overall skills, so you need to actively choose which skills to enhance and which to ignore. .hn 2 Armor (`[') .pg Lots of unfriendly things lurk about; you need armor to protect yourself from their blows. Some types of armor offer better protection than others. Your armor class is a measure of this protection. Armor class (AC) is measured as in AD&D, with 10 being the equivalent of no armor, and lower numbers meaning better armor. Each suit of armor which exists in AD&D gives the same protection in NetHack. Here is an (incomplete) list of the armor classes provided by various suits of armor: .TS S center; a n. dragon scale mail 1 plate mail 3 crystal plate mail 3 bronze plate mail 4 splint mail 4 banded mail 4 dwarvish mithril-coat 4 elven mithril-coat 5 chain mail 5 orcish chain mail 6 scale mail 6 studded leather armor 7 ring mail 7 orcish ring mail 8 leather armor 8 leather jacket 9 no armor 10 .TE .pg You can also wear other pieces of armor (ex. helmets, boots, shields, cloaks) to lower your armor class even further, but you can only wear one item of each category (one suit of armor, one cloak, one helmet, one shield, and so on) at a time. .pg If a piece of armor is enchanted, its armor protection will be better (or worse) than normal, and its ``plus'' (or minus) will subtract from your armor class. For example, a +1 chain mail would give you better protection than normal chain mail, lowering your armor class one unit further to 4. When you put on a piece of armor, you immediately find out the armor class and any ``plusses'' it provides. Cursed pieces of armor usually have negative enchantments (minuses) in addition to being unremovable. .pg Many types of armor are subject to some kind of damage like rust. Such damage can be repaired. Some types of armor may inhibit spell casting. .pg The commands to use armor are `W' (wear) and `T' (take off). The `A' command can also be used to take off armor as well as other worn items. .hn 2 Food (`%') .pg Food is necessary to survive. If you go too long without eating you will faint, and eventually die of starvation. Some types of food will spoil, and become unhealthy to eat, if not protected. Food stored in ice boxes or tins (``cans'') will usually stay fresh, but ice boxes are heavy, and tins take a while to open. .pg When you kill monsters, they usually leave corpses which are also ``food.'' Many, but not all, of these are edible; some also give you special powers when you eat them. A good rule of thumb is ``you are what you eat.'' .pg Some character roles and some monsters are vegetarian. Vegetarian monsters will typically never eat animal corpses, while vegetarian players can, but with some rather unpleasant side-effects. .pg You can name one food item after something you like to eat with the .op fruit option. .pg The command to eat food is `e'. .hn 2 Scrolls (`?') .pg Scrolls are labeled with various titles, probably chosen by ancient wizards for their amusement value (ex. ``READ ME,'' or ``THANX MAUD'' backwards). Scrolls disappear after you read them (except for blank ones, without magic spells on them). .pg One of the most useful of these is the \fIscroll of identify\fP, which can be used to determine what another object is, whether it is cursed or blessed, and how many uses it has left. Some objects of subtle enchantment are difficult to identify without these. .pg A mail daemon may run up and deliver mail to you as a \fIscroll of mail\fP (on versions compiled with this feature). To use this feature on versions where NetHack mail delivery is triggered by electronic mail appearing in your system mailbox, you must let NetHack know where to look for new mail by setting the ``MAIL'' environment variable to the file name of your mailbox. You may also want to set the ``MAILREADER'' environment variable to the file name of your favorite reader, so NetHack can shell to it when you read the scroll. On versions of NetHack where mail is randomly generated internal to the game, these environment variables are ignored. You can disable the mail daemon by turning off the .op mail option. .pg The command to read a scroll is `r'. .hn 2 Potions (`!') .pg Potions are distinguished by the color of the liquid inside the flask. They disappear after you quaff them. .pg Clear potions are potions of water. Sometimes these are blessed or cursed, resulting in holy or unholy water. Holy water is the bane of the undead, so potions of holy water are good things to throw (`t') at them. It is also sometimes very useful to dip (``#dip'') an object into a potion. .pg The command to drink a potion is `q' (quaff). .hn 2 Wands (`/') .pg Magic wands usually have multiple magical charges. Some wands are directional\(emyou must give a direction in which to zap them. You can also zap them at yourself (just give a `.' or `s' for the direction). Be warned, however, for this is often unwise. Other wands are nondirectional\(emthey don't require a direction. The number of charges in a wand is random and decreases by one whenever you use it. .pg When the number of charges left in a wand becomes zero, attempts to use the wand will usually result in nothing happening. Occasionally, however, it may be possible to squeeze the last few mana points from an otherwise spent wand, destroying it in the process. A wand may be recharged by using suitable magic, but doing so runs the risk of causing it to explode. The chance for such an explosion starts out very small and increases each time the wand is recharged. .pg In a truly desperate situation, when your back is up against the wall, you might decide to go for broke and break your wand. This is not for the faint of heart. Doing so will almost certainly cause a catastrophic release of magical energies. .pg When you have fully identified a particular wand, inventory display will include additional information in parentheses: the number of times it has been recharged followed by a colon and then by its current number of charges. A current charge count of -1 is a special case indicating that the wand has been cancelled. .pg The command to use a wand is `z' (zap). To break one, use the `a' (apply) command. .hn 2 Rings (`=') .pg Rings are very useful items, since they are relatively permanent magic, unlike the usually fleeting effects of potions, scrolls, and wands. .pg Putting on a ring activates its magic. You can wear only two rings, one on each ring finger. .pg Most rings also cause you to grow hungry more rapidly, the rate varying with the type of ring. .pg The commands to use rings are `P' (put on) and `R' (remove). .hn 2 Spellbooks (`+') .pg Spellbooks are tomes of mighty magic. When studied with the `r' (read) command, they transfer to the reader the knowledge of a spell (and therefore eventually become unreadable) \(em unless the attempt backfires. Reading a cursed spellbook or one with mystic runes beyond your ken can be harmful to your health! .pg A spell (even when learned) can also backfire when you cast it. If you attempt to cast a spell well above your experience level, or if you have little skill with the appropriate spell type, or cast it at a time when your luck is particularly bad, you can end up wasting both the energy and the time required in casting. .pg Casting a spell calls forth magical energies and focuses them with your naked mind. Some of the magical energy released comes from within you, and casting several spells in a row may tire you. Casting of spells also requires practice. With practice, your skill in each category of spell casting will improve. Over time, however, your memory of each spell will dim, and you will need to relearn it. .pg Some spells are directional\(emyou must give a direction in which to cast them. You can also cast them at yourself (just give a `.' or `s' for the direction). Be warned, however, for this is often unwise. Other spells are nondirectional\(emthey don't require a direction. .pg Just as weapons are divided into groups in which a character can become proficient (to varying degrees), spells are similarly grouped. Successfully casting a spell exercises the skill group; sufficient skill may increase the potency of the spell and reduce the risk of spell failure. Skill slots are shared with weapons skills. (See also the section on ``Weapon proficiency''.) .pg Casting a spell also requires flexible movement, and wearing various types of armor may interfere with that. .pg The command to read a spellbook is the same as for scrolls, `r' (read). The `+' command lists your current spells, their levels, categories, and chances for failure. The `Z' (cast) command casts a spell. .hn 2 Tools (`(') .pg Tools are miscellaneous objects with various purposes. Some tools have a limited number of uses, akin to wand charges. For example, lamps burn out after a while. Other tools are containers, which objects can be placed into or taken out of. .pg The command to use tools is `a' (apply). .hn 3 Containers .pg You may encounter bags, boxes, and chests in your travels. A tool of this sort can be opened with the ``#loot'' extended command when you are standing on top of it (that is, on the same floor spot), or with the `a' (apply) command when you are carrying it. However, chests are often locked, and are in any case unwieldy objects. You must set one down before unlocking it by using a key or lock-picking tool with the `a' (apply) command, by kicking it with the `^D' command, or by using a weapon to force the lock with the ``#force'' extended command. .pg Some chests are trapped, causing nasty things to happen when you unlock or open them. You can check for and try to deactivate traps with the ``#untrap'' extended command. .hn 2 Amulets (`"') .pg Amulets are very similar to rings, and often more powerful. Like rings, amulets have various magical properties, some beneficial, some harmful, which are activated by putting them on. .pg Only one amulet may be worn at a time, around your neck. .pg The commands to use amulets are the same as for rings, `P' (put on) and `R' (remove). .hn 2 Gems (`*') .pg Some gems are valuable, and can be sold for a lot of gold. They are also a far more efficient way of carrying your riches. Valuable gems increase your score if you bring them with you when you exit. .pg Other small rocks are also categorized as gems, but they are much less valuable. All rocks, however, can be used as projectile weapons (if you have a sling). In the most desperate of cases, you can still throw them by hand. .hn 2 Large rocks (`\`') .pg Statues and boulders are not particularly useful, and are generally heavy. It is rumored that some statues are not what they seem. .pg Very large humanoids (giants and their ilk) have been known to use boulders as weapons. .hn 2 Gold (`$') .pg Gold adds to your score, and you can buy things in shops with it. There are a number of monsters in the dungeon that may be influenced by the amount of gold you are carrying (shopkeepers aside). .hn 1 Conduct .pg As if winning NetHack were not difficult enough, certain players seek to challenge themselves by imposing restrictions on the way they play the game. The game automatically tracks some of these challenges, which can be checked at any time with the #conduct command or at the end of the game. When you perform an action which breaks a challenge, it will no longer be listed. This gives players extra ``bragging rights'' for winning the game with these challenges. Note that it is perfectly acceptable to win the game without resorting to these restrictions and that it is unusual for players to adhere to challenges the first time they win the game. .pg Several of the challenges are related to eating behavior. The most difficult of these is the foodless challenge. Although creatures can survive long periods of time without food, there is a physiological need for water; thus there is no restriction on drinking beverages, even if they provide some minor food benefits. Calling upon your god for help with starvation does not violate any food challenges either. .pg A strict vegan diet is one which avoids any food derived from animals. The primary source of nutrition is fruits and vegetables. The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are also considered to be vegetable matter. Certain human food is prepared without animal products; namely, lembas wafers, cram rations, food rations (gunyoki), K-rations, and C-rations. Metal or another normally indigestible material eaten while polymorphed into a creature that can digest it is also considered vegan food. Note however that eating such items still counts against foodless conduct. .pg Vegetarians do not eat animals; however, they are less selective about eating animal byproducts than vegans. In addition to the vegan items listed above, they may eat any kind of pudding (`P') other than the black puddings, eggs and food made from eggs (fortune cookies and pancakes), food made with milk (cream pies and candy bars), and lumps of royal jelly. Monks are expected to observe a vegetarian diet. .pg Eating any kind of meat violates the vegetarian, vegan, and foodless conducts. This includes tripe rations, the corpses or tins of any monsters not mentioned above, and the various other chunks of meat found in the dungeon. Swallowing and digesting a monster while polymorphed is treated as if you ate the creature's corpse. Eating leather, dragon hide, or bone items while polymorphed into a creature that can digest it, or eating monster brains while polymorphed into a mind flayer, is considered eating an animal, although wax is only an animal byproduct. .pg Regardless of conduct, there will be some items which are indigestible, and others which are hazardous to eat. Using a swallow-and-digest attack against a monster is equivalent to eating the monster's corpse. Please note that the term ``vegan'' is used here only in the context of diet. You are still free to choose not to use or wear items derived from animals (e.g. leather, dragon hide, bone, horns, coral), but the game will not keep track of this for you. Also note that ``milky'' potions may be a translucent white, but they do not contain milk, so they are compatible with a vegan diet. Slime molds or player-defined ``fruits'', although they could be anything from ``cherries'' to ``pork chops'', are also assumed to be vegan. .pg An atheist is one who rejects religion. This means that you cannot #pray, #offer sacrifices to any god, #turn undead, or #chat with a priest. Particularly selective readers may argue that playing Monk or Priest characters should violate this conduct; that is a choice left to the player. Offering the Amulet of Yendor to your god is necessary to win the game and is not counted against this conduct. You are also not penalized for being spoken to by an angry god, priest(ess), or other religious figure; a true atheist would hear the words but attach no special meaning to them. .pg Most players fight with a wielded weapon (or tool intended to be wielded as a weapon). Another challenge is to win the game without using such a wielded weapon. You are still permitted to throw, fire, and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. .pg In NetHack, a pacifist refuses to cause the death of any other monster (i.e. if you would get experience for the death). This is a particularly difficult challenge, although it is still possible to gain experience by other means. .pg An illiterate character cannot read or write. This includes reading a scroll, spellbook, fortune cookie message, or t-shirt; writing a scroll; or making an engraving of anything other than a single ``x'' (the traditional signature of an illiterate person). Reading an engraving, or any item that is absolutely necessary to win the game, is not counted against this conduct. The identity of scrolls and spellbooks (and knowledge of spells) in your starting inventory is assumed to be learned from your teachers prior to the start of the game and isn't counted. .pg There are several other challenges tracked by the game. It is possible to eliminate one or more species of monsters by genocide; playing without this feature is considered a challenge. When the game offers you an opportunity to genocide monsters, you may respond with the monster type ``none'' if you want to decline. You can change the form of an item into another item of the same type (``polypiling'') or the form of your own body into another creature (``polyself'') by wand, spell, or potion of polymorph; avoiding these effects are each considered challenges. Polymorphing monsters, including pets, does not break either of these challenges. Finally, you may sometimes receive wishes; a game without an attempt to wish for any items is a challenge, as is a game without wishing for an artifact (even if the artifact immediately disappears). When the game offers you an opportunity to make a wish for an item, you may choose ``nothing'' if you want to decline. .hn 1 Options .pg Due to variations in personal tastes and conceptions of how NetHack should do things, there are options you can set to change how NetHack behaves. .hn 2 Setting the options .pg Options may be set in a number of ways. Within the game, the `O' command allows you to view all options and change most of them. You can also set options automatically by placing them in the NETHACKOPTIONS environment variable or in a configuration file. Some versions of NetHack also have front-end programs that allow you to set options before starting the game. .hn 2 Using the NETHACKOPTIONS environment variable .pg The NETHACKOPTIONS variable is a comma-separated list of initial values for the various options. Some can only be turned on or off. You turn one of these on by adding the name of the option to the list, and turn it off by typing a `!' or ``no'' before the name. Others take a character string as a value. You can set string options by typing the option name, a colon or equals sign, and then the value of the string. The value is terminated by the next comma or the end of string. .pg For example, to set up an environment variable so that ``autoquiver'' is on, ``autopickup'' is off, the name is set to ``Blue Meanie'', and the fruit is set to ``papaya'', you would enter the command .sd % \fBsetenv NETHACKOPTIONS "autoquiver,\e!autopickup,name:Blue Meanie,fruit:papaya"\fP .ed in \fIcsh\fP (note the need to escape the ! since it's special to the shell), or .sd $ \fBNETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya"\fP $ \fBexport NETHACKOPTIONS\fP .ed in \fIsh\fP or \fIksh\fP. .hn 2 Using a configuration file .pg Any line in the configuration file starting with `#' is treated as a comment. Any line in the configuration file starting with ``OPTIONS='' may be filled out with options in the same syntax as in NETHACKOPTIONS. Any line starting with ``DUNGEON='', ``EFFECTS='', ``MONSTERS='', ``OBJECTS='', ``TRAPS='', or ``BOULDER='' is taken as defining the corresponding .op dungeon, .op effects, .op monsters, .op objects .op traps or .op boulder option in a different syntax, a sequence of decimal numbers giving the character position in the current font to be used in displaying each entry. A zero in any entry in such a sequence leaves the display of that entry unchanged; this feature is not available using the option syntax. Such a sequence can be continued to multiple lines by putting a `\e' at the end of each line to be continued. .pg If your copy of the game included the compile time AUTOPICKUP_EXCEPTIONS option, then any line starting with ``AUTOPICKUP_EXCEPTION='' is taken as defining an exception to the .op pickup_types option. There is a section of this Guidebook that discusses that. .pg The default name of the configuration file varies on different operating systems, but NETHACKOPTIONS can also be set to the full name of a file you want to use (possibly preceded by an `@'). .hn 2 Customization options .pg Here are explanations of what the various options do. Character strings that are too long may be truncated. Some of the options listed may be inactive in your dungeon. .lp align Your starting alignment (align:lawful, align:neutral, or align:chaotic). You may specify just the first letter. The default is to randomly pick an appropriate alignment. Cannot be set with the `O' command. .lp autodig Automatically dig if you are wielding a digging tool and moving into a place that can be dug (default false). .lp "autopickup " Automatically pick up things onto which you move (default on). See .op pickup_types to refine the behavior. .lp "autoquiver " This option controls what happens when you attempt the `f' (fire) command with an empty quiver. When true, the computer will fill your quiver with some suitable weapon. Note that it will not take into account the blessed/cursed status, enchantment, damage, or quality of the weapon; you are free to manually fill your quiver with the `Q' command instead. If no weapon is found or the option is false, the `t' (throw) command is executed instead. (default false) .lp boulder Set the character used to display boulders (default is rock class symbol). .lp catname Name your starting cat (ex. ``catname:Morris''). Cannot be set with the `O' command. .lp character Pick your type of character (ex. ``character:Monk''); synonym for ``role''. See ``name'' for an alternate method of specifying your role. Normally only the first letter of the value is examined; the string ``random'' is an exception. .lp checkpoint Save game state after each level change, for possible recovery after program crash (default on). .lp checkspace Check free disk space before writing files to disk (default on). You may have to turn this off if you have more than 2 GB free space on the partition used for your save and level files. Only applies when MFLOPPY was defined during compilation. .lp cmdassist Have the game provide some additional command assistance for new players if it detects some anticipated mistakes (default on). .lp "confirm " Have user confirm attacks on pets, shopkeepers, and other peaceable creatures (default on). .lp DECgraphics Use a predefined selection of characters from the DEC VT-xxx/DEC Rainbow/ANSI line-drawing character set to display the dungeon/effects/traps instead of having to define a full graphics set yourself (default off). This option also sets up proper handling of graphics characters for such terminals, so you should specify it when appropriate even if you override the selections with your own graphics strings. .lp disclose Controls options for disclosing various information when the game ends (defaults to all possibilities being disclosed). The possibilities are: .sd .si i - disclose your inventory. a - disclose your attributes. v - summarize monsters that have been vanquished. g - list monster species that have been genocided. c - display your conduct. .ei .ed Each disclosure possibility can optionally be preceded by a prefix which let you refine how it behaves. Here are the valid prefixes: .sd .si y - prompt you and default to yes on the prompt. n - prompt you and default to no on the prompt. + - disclose it without prompting. - - do not disclose it and do not prompt. .ei .ed (ex. ``disclose:yi na +v -g -c'') The example sets .op inventory to prompt and default to yes, .op attributes to prompt and default to no, .op vanquished to disclose without prompting, .op genocided to not disclose and not to prompt, .op conduct to not disclose and not to prompt. Note that the vanquished monsters list includes all monsters killed by traps and each other as well as by you. .lp dogname Name your starting dog (ex. ``dogname:Fang''). Cannot be set with the `O' command. .lp dungeon Set the graphics symbols for displaying the dungeon (default \&``\ |--------||.-|++##.##<><>_|\e\e#{}.}..##\ #}''). The .op dungeon option should be followed by a string of 1-41 characters to be used instead of the default map-drawing characters. The dungeon map will use the characters you specify instead of the default symbols, and default symbols for any you do not specify. Remember that you may need to escape some of these characters on a command line if they are special to your shell. Note that NetHack escape-processes this option string in conventional C fashion. This means that `\e' is a prefix to take the following character literally. Thus `\e' needs to be represented as `\e\e'. The special escape form `\em' switches on the meta bit in the following character, and the `^' prefix causes the following character to be treated as a control character. The order of the symbols is: solid rock, vertical wall, horizontal wall, upper left corner, upper right corner, lower left corner, lower right corner, cross wall, upward T wall, downward T wall, leftward T wall, rightward T wall, no door, vertical open door, horizontal open door, vertical closed door, horizontal closed door, iron bars, tree, floor of a room, dark corridor, lit corridor, stairs up, stairs down, ladder up, ladder down, altar, grave, throne, kitchen sink, fountain, pool or moat, ice, lava, vertical lowered drawbridge, horizontal lowered drawbridge, vertical raised drawbridge, horizontal raised drawbridge, air, cloud, under water. You might want to use `+' for the corners and T walls for a more aesthetic, boxier display. Note that in the next release, new symbols may be added, or the present ones rearranged. Cannot be set with the `O' command. .lp effects Set the graphics symbols for displaying special effects (default \&``|-\e\e/*!)(0#@*/-\e\e||\e\e-//-\e\e|\ |\e\e-/''). The .op effects option should be followed by a string of 1-29 characters to be used instead of the default special-effects characters. This string is subjected to the same processing as the .op dungeon option. The order of the symbols is: vertical beam, horizontal beam, left slant, right slant, digging beam, camera flash beam, left boomerang, right boomerang, four glyphs giving the sequence for magic resistance displays, the eight surrounding glyphs for swallowed display, nine glyphs for explosions. An explosion consists of three rows (top, middle, and bottom) of three characters. The explosion is centered in the center of this 3 by 3 array. Note that in the next release, new symbols may be added, or the present ones rearranged. Cannot be set with the `O' command. .lp extmenu Changes the extended commands interface to pop-up a menu of available commands. It is keystroke compatible with the traditional interface except that it does not require that you hit Enter. It is implemented only by the tty port (default off), when the game has been compiled to support tty graphics. .lp female An obsolete synonym for ``gender:female''. Cannot be set with the `O' command. .lp fixinv An object's inventory letter sticks to it when it's dropped (default on). If this is off, dropping an object shifts all the remaining inventory letters. .lp "fruit " Name a fruit after something you enjoy eating (ex. ``fruit:mango'') (default ``slime mold''). Basically a nostalgic whimsy that NetHack uses from time to time. You should set this to something you find more appetizing than slime mold. Apples, oranges, pears, bananas, and melons already exist in NetHack, so don't use those. .lp gender Your starting gender (gender:male or gender:female). You may specify just the first letter. Although you can still denote your gender using the ``male'' and ``female'' options, the ``gender'' option will take precedence. The default is to randomly pick an appropriate gender. Cannot be set with the `O' command. .lp help If more information is available for an object looked at with the `/' command, ask if you want to see it (default on). Turning help off makes just looking at things faster, since you aren't interrupted with the ``More info?'' prompt, but it also means that you might miss some interesting and/or important information. .lp horsename Name your starting horse (ex. ``horsename:Trigger''). Cannot be set with the `O' command. .lp IBMgraphics Use a predefined selection of IBM extended ASCII characters to display the dungeon/effects/traps instead of having to define a full graphics set yourself (default off). This option also sets up proper handling of graphics characters for such terminals, so you should specify it when appropriate even if you override the selections with your own graphics strings. .lp ignintr Ignore interrupt signals, including breaks (default off). .lp legacy Display an introductory message when starting the game (default on). .lp lit_corridor Show corridor squares seen by night vision or a light source held by your character as lit (default off). .lp lootabc Use the old `a', `b', and `c' keyboard shortcuts when looting, rather than the mnemonics `o', `i', and `b' (default off). .lp "mail " Enable mail delivery during the game (default on). .lp "male " An obsolete synonym for ``gender:male''. Cannot be set with the `O' command. .lp menustyle Controls the interface used when you need to choose various objects (in response to the Drop command, for instance). The value specified should be the first letter of one of the following: traditional, combination, partial, or full. Traditional was the only interface available for earlier versions; it consists of a prompt for object class characters, followed by an object-by-object prompt for all items matching the selected object class(es). Combination starts with a prompt for object class(es) of interest, but then displays a menu of matching objects rather than prompting one-by-one. Partial skips the object class filtering and immediately displays a menu of all objects. Full displays a menu of object classes rather than a character prompt, and then a menu of matching objects for selection. .lp menu_deselect_all Menu character accelerator to deselect all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default '-'. .lp menu_deselect_page Menu character accelerator to deselect all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default '\e'. .lp menu_first_page Menu character accelerator to jump to the first page in a menu. Implemented by the Amiga, Gem and tty ports. Default '^'. .lp menu_headings Controls how the headings in a menu are highlighted. Values are 'bold', 'inverse', or 'underline'. Not all ports can actually display all three types. .lp menu_invert_all Menu character accelerator to invert all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default '@'. .lp menu_invert_page Menu character accelerator to invert all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default '~'. .lp menu_last_page Menu character accelerator to jump to the last page in a menu. Implemented by the Amiga, Gem and tty ports. Default '|'. .lp menu_next_page Menu character accelerator to goto the next menu page. Implemented by the Amiga, Gem and tty ports. Default '>'. .lp menu_previous_page Menu character accelerator to goto the previous menu page. Implemented by the Amiga, Gem and tty ports. Default '<'. .lp menu_search Menu character accelerator to search for a menu item. Implemented by the Amiga, Gem and X11 ports. Default ':'. .lp menu_select_all Menu character accelerator to select all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default '.'. .lp menu_select_page Menu character accelerator to select all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default ','. .lp monsters Set the characters used to display monster classes (default ``abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@\ \'&;:~]''). This string is subjected to the same processing as the .op dungeon option. The order of the symbols is ant or other insect, blob, cockatrice, dog or other canine, eye or sphere, feline, gremlin, humanoid, imp or minor demon, jelly, kobold, leprechaun, mimic, nymph, orc, piercer, quadruped, rodent, arachnid or centipede, trapper or lurker above, horse or unicorn, vortex, worm, xan or other mythical/fantastic insect, light, zruty, angelic being, bat or bird, centaur, dragon, elemental, fungus or mold, gnome, giant humanoid, invisible monster, jabberwock, Keystone Kop, lich, mummy, naga, ogre, pudding or ooze, quantum mechanic, rust monster, snake, troll, umber hulk, vampire, wraith, xorn, apelike creature, zombie, human, ghost, golem, demon, sea monster, lizard, long worm tail, and mimic. Cannot be set with the `O' command. .lp msghistory The number of top line messages to save (and recall with ^P) (default 20). Cannot be set with the `O' command. .lp msg_window Allows you to change the way recalled messages are displayed. (It is currently implemented for tty only.) The possible values are: .sd .si s - single message (default, this was the behavior before 3.4.0). c - combination, two messages as `single', then as `full'. f - full window, oldest message first. r - full window, newest message first. .ei .ed For backward compatibility, no value needs to be specified (which defaults to `full'), or it can be negated (which defaults to `single'). .lp "name " Set your character's name (defaults to your user name). You can also set your character's role by appending a dash and one or more letters of the role (that is, by suffixing one of .op "-A -B -C -H -K -M -P -Ra -Ro -S -T -V -W" ). If .op "-@" is used for the role, then a random one will be automatically chosen. Cannot be set with the `O' command. .lp "news " Read the NetHack news file, if present (default on). Since the news is shown at the beginning of the game, there's no point in setting this with the `O' command. .lp "null " Send padding nulls to the terminal (default off). .lp number_pad Use the number keys to move instead of [yuhjklbn] (default 0 or off). (number_pad:2 invokes the old DOS behavior where `5' means `g', meta-`5' means `G', and meta-`0' means `I'.) .lp objects Set the characters used to display object classes (default ``])[="(%!?+/$*`0_.''). This string is subjected to the same processing as the .op dungeon option. The order of the symbols is illegal-object (should never be seen), weapon, armor, ring, amulet, tool, food, potion, scroll, spellbook, wand, gold, gem or rock, boulder or statue, iron ball, chain, and venom. Cannot be set with the `O' command. .lp packorder Specify the order to list object types in (default ``")[%?+!=/(*`0_''). The value of this option should be a string containing the symbols for the various object types. Any omitted types are filled in at the end from the previous order. .lp perm_invent If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that implement this feature. .lp pettype Specify the type of your initial pet, if you are playing a character class that uses multiple types of pets; or choose to have no initial pet at all. Possible values are ``cat'', ``dog'' and ``none''. Cannot be set with the `O' command. .lp pickup_burden When you pick up an item that would exceed this encumbrance level (Unburdened, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. (Default `S'). .lp pickup_types Specify the object types to be picked up when .op autopickup is on. Default is all types. If your copy of the game has the experimental compile time option AUTOPICKUP_EXCEPTIONS included, you may be able to use .op autopickup_exception configuration file lines to further refine .op autopickup behavior. .lp prayconfirm Prompt for confirmation before praying (default on). .lp pushweapon Using the `w' (wield) command when already wielding something pushes the old item into your alternate weapon slot (default off). .lp race Selects your race (for example, ``race:human''). Default is random. Cannot be set with the `O' command. .lp rest_on_space Make the space bar a synonym for the `.' (rest) command (default off). .lp "role " Pick your type of character (ex. ``role:Samurai''); synonym for ``character''. See ``name'' for an alternate method of specifying your role. Normally only the first letter of the value is examined; `r' is an exception with ``Rogue'', ``Ranger'', and ``random'' values. .lp runmode Controls the amount of screen updating for the map window when engaged in multi-turn movement (running via shift+direction or control+direction and so forth, or via the travel command or mouse click). The possible values are: .sd .si teleport - update the map after movement has finished; run - update the map after every seven or so steps; walk - update the map after each step; crawl - like walk, but pause briefly after each step. .ei .ed This option only affects the game's screen display, not the actual results of moving. The default is `run'; versions prior to 3.4.1 used `teleport' only. Whether or not the effect is noticeable will depend upon the window port used or on the type of terminal. .lp safe_pet Prevent you from (knowingly) attacking your pets (default on). .lp scores Control what parts of the score list you are shown at the end (ex. ``scores:5 top scores/4 around my score/own scores''). Only the first letter of each category (`t', `a', or `o') is necessary. .lp showexp Show your accumulated experience points on bottom line (default off). .lp showrace Display yourself as the glyph for your race, rather than the glyph for your role (default off). Note that this setting affects only the appearance of the display, not the way the game treats you. .lp showscore Show your approximate accumulated score on bottom line (default off). .lp "silent " Suppress terminal beeps (default on). .lp sortpack Sort the pack contents by type when displaying inventory (default on). .lp sound Enable messages about what your character hears (default on). Note that this has nothing to do with your computer's audio capabilities. This option is only partly under player control. The game toggles it off and on during and after sleep, for example. .lp sparkle Display a sparkly effect when a monster (including yourself) is hit by an attack to which it is resistant (default on). .lp standout Boldface monsters and ``\fB--More--\fP'' (default off). .lp suppress_alert This option may be set to a NetHack version level to suppress alert notification messages about feature changes for that and prior versions (ex. ``suppress_alert:3.3.1''). .lp "time " Show the elapsed game time in turns on bottom line (default off). .lp timed_delay When pausing momentarily for display effect, such as with explosions and moving objects, use a timer rather than sending extra characters to the screen. (Applies to ``tty'' interface only; ``X11'' interface always uses a timer based delay. The default is on if configured into the program.) .lp tombstone Draw a tombstone graphic upon your death (default on). .lp toptenwin Put the ending display in a NetHack window instead of on stdout (default off). Setting this option makes the score list visible when a windowing version of NetHack is started without a parent window, but it no longer leaves the score list around after game end on a terminal or emulating window. .lp traps Set the graphics symbols for displaying traps (default \&``^^^^^^^^^^^^^^^^^"^^^^''). The .op traps option should be followed by a string of 1-22 characters to be used instead of the default traps characters. This string is subjected to the same processing as the .op dungeon option. The order of the symbols is: arrow trap, dart trap, falling rock trap, squeaky board, bear trap, land mine, rolling boulder trap, sleeping gas trap, rust trap, fire trap, pit, spiked pit, hole, trap door, teleportation trap, level teleporter, magic portal, web, statue trap, magic trap, anti-magic field, polymorph trap. Cannot be set with the `O' command. .lp travel Allow the travel command (default on). Turning this option off will prevent the game from attempting unintended moves if you make inadvertent mouse clicks on the map window. .lp verbose Provide more commentary during the game (default on). .lp windowtype Select which windowing system to use, such as ``tty'' or ``X11'' (default depends on version). Cannot be set with the `O' command. .hn 2 Window Port Customization options .pg Here are explanations of the various options that are used to customize and change the characteristics of the windowtype that you have chosen. Character strings that are too long may be truncated. Not all window ports will adjust for all settings listed here. You can safely add any of these options to your config file, and if the window port is capable of adjusting to suit your preferences, it will attempt to do so. If it can't it will silently ignore it. You can find out if an option is supported by the window port that you are currently using by checking to see if it shows up in the Options list. Some options are dynamic and can be specified during the game with the `O' command. .lp align_message Where to align or place the message window (top, bottom, left, or right) .lp align_status Where to align or place the status window (top, bottom, left, or right). .lp ascii_map NetHack should display an ascii character map if it can. .lp color NetHack should display color if it can for different monsters, objects, and dungeon features .lp eight_bit_tty NetHack should pass eight-bit character values (for example, specified with the .op traps option) straight through to your terminal (default off). .lp font_map NetHack should use a font by the chosen name for the map window. .lp font_menu NetHack should use a font by the chosen name for menu windows. .lp font_message NetHack should use a font by the chosen name for the message window. .lp font_status NetHack should use a font by the chosen name for the status window. .lp font_text NetHack should use a font by the chosen name for text windows. .lp font_size_map NetHack should use this size font for the map window. .lp font_size_menu NetHack should use this size font for menu windows. .lp font_size_message NetHack should use this size font for the message window. .lp font_size_status NetHack should use this size font for the status window. .lp font_size_text NetHack should use this size font for text windows. .lp fullscreen NetHack should try and display on the entire screen rather than in a window. .lp hilite_pet Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a heart symbol near pets. .lp large_font NetHack should use a large font. .lp map_mode NetHack should display the map in the manner specified. .lp mouse_support Allow use of the mouse for input and travel. .lp player_selection NetHack should pop up dialog boxes, or use prompts for character selection. .lp popup_dialog NetHack should pop up dialog boxes for input. .lp preload_tiles NetHack should preload tiles into memory. For example, in the protected mode MSDOS version, control whether tiles get pre-loaded into RAM at the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. (default on). Cannot be set with the `O' command. .lp scroll_amount NetHack should scroll the display by this number of cells when the hero reaches the scroll_margin. .lp scroll_margin NetHack should scroll the display when the hero or cursor is this number of cells away from the edge of the window. .lp softkeyboard Display an onscreen keyboard. Handhelds are most likely to support this option. .lp splash_screen NetHack should display an opening splash screen when it starts up (default yes). .lp tiled_map NetHack should display a tiled map if it can. .lp tile_file Specify the name of an alternative tile file to override the default. .lp tile_height Specify the preferred height of each tile in a tile capable port. .lp tile_width Specify the preferred width of each tile in a tile capable port .lp use_inverse NetHack should display inverse when the game specifies it. .lp vary_msgcount NetHack should display this number of messages at a time in the message window. .lp windowcolors NetHack should display windows with the specified foreground/background colors if it can. .lp wraptext NetHack port should wrap long lines of text if they don't fit in the visible area of the window. .hn 2 Platform-specific Customization options .pg Here are explanations of options that are used by specific platforms or ports to customize and change the port behavior. .lp altkeyhandler Select an alternate keystroke handler dll to load (Win32 tty NetHack only). The name of the handler is specified without the .dll extension and without any path information. Cannot be set with the `O' command. .lp altmeta (default on, AMIGA NetHack only). .lp "BIOS " Use BIOS calls to update the screen display quickly and to read the keyboard (allowing the use of arrow keys to move) on machines with an IBM PC compatible BIOS ROM (default off, OS/2, PC, and ST NetHack only). .lp flush (default off, AMIGA NetHack only). .lp "MACgraphics" (default on, Mac NetHack only). .lp page_wait (default on, Mac NetHack only). .lp "rawio " Force raw (non-cbreak) mode for faster output and more bulletproof input (MS-DOS sometimes treats `^P' as a printer toggle without it) (default off, OS/2, PC, and ST NetHack only). Note: DEC Rainbows hang if this is turned on. Cannot be set with the `O' command. .lp soundcard (default on, PC NetHack only). Cannot be set with the `O' command. .lp subkeyvalue (Win32 tty NetHack only). May be used to alter the value of keystrokes that the operating system returns to NetHack to help compensate for international keyboard issues. OPTIONS=subkeyvalue:171/92 will return 92 to NetHack, if 171 was originally going to be returned. You can use multiple subkeyvalue statements in the config file if needed. Cannot be set with the `O' command. .lp video Set the video mode used (PC NetHack only). Values are `autodetect', `default', or `vga'. Setting `vga' (or `autodetect' with vga hardware present) will cause the game to display tiles. Cannot be set with the `O' command. .lp videocolors Set the color palette for PC systems using NO_TERMS (default 4-2-6-1-5-3-15-12-10-14-9-13-11, (PC NetHack only). The order of colors is red, green, brown, blue, magenta, cyan, bright.white, bright.red, bright.green, yellow, bright.blue, bright.magenta, and bright.cyan. Cannot be set with the `O' command. .lp videoshades Set the intensity level of the three gray scales available (default dark normal light, PC NetHack only). If the game display is difficult to read, try adjusting these scales; if this does not correct the problem, try !color. Cannot be set with the `O' command. .hn 2 Configuring autopickup exceptions .pg There is an experimental compile time option called AUTOPICKUP_EXCEPTIONS. If your copy of the game was built with that option defined, you can further refine the behavior of the .op autopickup option beyond what is available through the .op pickup_types option. .pg By placing .op autopickup_exception lines in your configuration file, you can define patterns to be checked when the game is about to autopickup something. .lp autopickup_exception Sets an exception to the .op pickup_types option. The .op autopickup_exception option should be followed by a string of 1-80 characters to be used as a pattern to match against the singular form of the description of an object at your location. .pg You may use the following special characters in a pattern: .sd .si *--- matches 0 or more characters. ?--- matches any single character. .ei .ed .pg In addition, some characters are treated specially if they occur as the first character in the string pattern, specifically: .sd .si < - always pickup an object that matches the pattern that follows. > - never pickup an object that matches the pattern that follows. .ei .ed .pg Can be set with the `O' command, but the setting is not preserved across saves and restores. .pg Here's a couple of examples of autopickup_exceptions: .sd .si autopickup_exception="<*arrow" autopickup_exception=">*corpse" autopickup_exception=">* cursed*" .ei .ed The first example above will result in autopickup of any type of arrow. The second example results in the exclusion of any corpse from autopickup. The last example results in the exclusion of items known to be cursed from autopickup. A `never pickup' rule takes precedence over an `always pickup' rule if both match. .hn 2 Configuring User Sounds .pg Some platforms allow you to define sound files to be played when a message that matches a user-defined pattern is delivered to the message window. At this time the Qt port and the win32tty and win32gui ports support the use of user sounds. .pg The following config file entries are relevant to mapping user sounds to messages: .lp SOUNDDIR The directory that houses the sound files to be played. .lp SOUND An entry that maps a sound file to a user-specified message pattern. Each SOUND entry is broken down into the following parts: .sd .si MESG - message window mapping (the only one supported in 3.4). pattern - the pattern to match. sound file - the sound file to play. volume - the volume to be set while playing the sound file. .ei .ed .pg The exact format for the pattern depends on whether the platform is built to use ``regular expressions'' or NetHack's own internal pattern matching facility. The ``regular expressions'' matching can be much more sophisticated than the internal NetHack pattern matching, but requires 3rd party libraries on some platforms. There are plenty of references available elsewhere for explaining ``regular expressions''. You can verify which pattern matching is used by your port with the #version command. .pg NetHack's internal pattern matching routine uses the following special characters in its pattern matching: .sd .si *--- matches 0 or more characters. ?--- matches any single character. .ei .ed .pg Here's an example of a sound mapping using NetHack's internal pattern matching facility: .sd SOUND=MESG "*chime of a cash register*" "gong.wav" 50 .ed specifies that any message with "chime of a cash register" contained in it will trigger the playing of "gong.wav". You can have multiple SOUND entries in your config file. .pg .hn 2 Configuring NetHack for Play by the Blind .pg NetHack can be set up to use only standard ASCII characters for making maps of the dungeons. This makes the MS-DOS versions of NetHack completely accessible to the blind who use speech and/or Braille access technologies. Players will require a good working knowledge of their screen-reader's review features, and will have to know how to navigate horizontally and vertically character by character. They will also find the search capabilities of their screen-readers to be quite valuable. Be certain to examine this Guidebook before playing so you have an idea what the screen layout is like. You'll also need to be able to locate the PC cursor. It is always where your character is located. Merely searching for an @-sign will not always find your character since there are other humanoids represented by the same sign. Your screen-reader should also have a function which gives you the row and column of your review cursor and the PC cursor. These co-ordinates are often useful in giving players a better sense of the overall location of items on the screen. .pg While it is not difficult for experienced users to edit the \fBdefaults.nh\fP file to accomplish this, novices may find this task somewhat daunting. Included in all official distributions of NetHack is a file called \fBNHAccess.nh\fP. Replacing \fBdefaults.nh\fP with this file will cause the game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings to better suit your preferences. Instructions on how to do this are included in the \fBNHAccess.nh\fP file itself. The most crucial settings to make the game accessible are: .pg .lp IBMgraphics Disable IBMgraphics by commenting out this option. .lp menustyle:traditional This will assist in the interface to speech synthesizers. .lp number_pad A lot of speech access programs use the number-pad to review the screen. If this is the case, disable the number_pad option and use the traditional Rogue-like commands. .lp "Character graphics" Comment out all character graphics sets found near the bottom of the \fBdefaults.nh\fP file. Most of these replace \fBNetHack\fP's default representation of the dungeon using standard ASCII characters with fancier characters from extended character sets, and these fancier characters can annoy screen-readers. .hn 1 Scoring .pg NetHack maintains a list of the top scores or scorers on your machine, depending on how it is set up. In the latter case, each account on the machine can post only one non-winning score on this list. If you score higher than someone else on this list, or better your previous score, you will be inserted in the proper place under your current name. How many scores are kept can also be set up when NetHack is compiled. .pg Your score is chiefly based upon how much experience you gained, how much loot you accumulated, how deep you explored, and how the game ended. If you quit the game, you escape with all of your gold intact. If, however, you get killed in the Mazes of Menace, the guild will only hear about 90% of your gold when your corpse is discovered (adventurers have been known to collect finder's fees). So, consider whether you want to take one last hit at that monster and possibly live, or quit and stop with whatever you have. If you quit, you keep all your gold, but if you swing and live, you might find more. .pg If you just want to see what the current top players/games list is, you can type \fBnethack -s all\fP on most versions. .hn 1 Explore mode .pg NetHack is an intricate and difficult game. Novices might falter in fear, aware of their ignorance of the means to survive. Well, fear not. Your dungeon may come equipped with an ``explore'' or ``discovery'' mode that enables you to keep old save files and cheat death, at the paltry cost of not getting on the high score list. .pg There are two ways of enabling explore mode. One is to start the game with the .op -X switch. The other is to issue the `X' command while already playing the game. The other benefits of explore mode are left for the trepid reader to discover. .hn Credits .pg The original \fIhack\fP game was modeled on the Berkeley .ux \fIrogue\fP game. Large portions of this paper were shamelessly cribbed from \fIA Guide to the Dungeons of Doom\fP, by Michael C. Toy and Kenneth C. R. C. Arnold. Small portions were adapted from \fIFurther Exploration of the Dungeons of Doom\fP, by Ken Arromdee. .pg NetHack is the product of literally dozens of people's work. Main events in the course of the game development are described below: .pg \fBJay Fenlason\fP wrote the original Hack, with help from \fBKenny Woodland\fP, \fBMike Thome\fP and \fBJon Payne\fP. .pg \fBAndries Brouwer\fP did a major re-write, transforming Hack into a very different game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for .ux machines to the Usenet. .pg \fBDon G. Kneller\fP ported Hack 1.0.3 to Microsoft C and MS-DOS, producing PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went on to produce at least four more versions (3.0, 3.2, 3.51, and 3.6). .pg \fBR. Black\fP ported PC HACK 3.51 to Lattice C and the Atari 520/1040ST, producing ST Hack 1.03. .pg \fBMike Stephenson\fP merged these various versions back together, incorporating many of the added features, and produced NetHack 1.4. He then coordinated a cast of thousands in enhancing and debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. .pg Later, Mike coordinated a major rewrite of the game, heading a team which included \fBKen Arromdee\fP, \fBJean-Christophe Collet\fP, \fBSteve Creps\fP, \fBEric Hendrickson\fP, \fBIzchak Miller\fP, \fBJohn Rupley\fP, \fBMike Threepoint\fP, and \fBJanet Walz\fP, to produce NetHack 3.0c. .pg NetHack 3.0 was ported to the Atari by \fBEric R. Smith\fP, to OS/2 by \fBTimo Hakulinen\fP, and to VMS by \fBDavid Gentzel\fP. The three of them and \fBKevin Darcy\fP later joined the main development team to produce subsequent revisions of 3.0. .pg \fBOlaf Seibert\fP ported NetHack 2.3 and 3.0 to the Amiga. \fBNorm Meluch\fP, \fBStephen Spackman\fP and \fBPierre Martineau\fP designed overlay code for PC NetHack 3.0. \fBJohnny Lee\fP ported NetHack 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. .pg Headed by \fBMike Stephenson\fP and coordinated by \fBIzchak Miller\fP and \fBJanet Walz\fP, the development team which now included \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJean-Christophe Collet\fP, \fBKevin Darcy\fP, \fBMatt Day\fP, \fBTimo Hakulinen\fP, \fBSteve Linhart\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBEric Raymond\fP, and \fBEric Smith\fP undertook a radical revision of 3.0. They re-structured the game's design, and re-wrote major parts of the code. They added multiple dungeons, a new display, special individual character quests, a new endgame and many other new features, and produced NetHack 3.1. .pg \fBKen Lorber\fP, \fBGregg Wonderly\fP and \fBGreg Olson\fP, with help from \fBRichard Addison\fP, \fBMike Passaretti\fP, and \fBOlaf Seibert\fP, developed NetHack 3.1 for the Amiga. .pg \fBNorm Meluch\fP and \fBKevin Smolkowski\fP, with help from \fBCarl Schelin\fP, \fBStephen Spackman\fP, \fBSteve VanDevender\fP, and \fBPaul Winner\fP, ported NetHack 3.1 to the PC. .pg \fBJon W{tte\fP and \fBHao-yang Wang\fP, with help from \fBRoss Brown\fP, \fBMike Engber\fP, \fBDavid Hairston\fP, \fBMichael Hamel\fP, \fBJonathan Handler\fP, \fBJohnny Lee\fP, \fBTim Lennan\fP, \fBRob Menke\fP, and \fBAndy Swanson\fP, developed NetHack 3.1 for the Macintosh, porting it for MPW. Building on their development, \fBBarton House\fP added a Think C port. .pg \fBTimo Hakulinen\fP ported NetHack 3.1 to OS/2. \fBEric Smith\fP ported NetHack 3.1 to the Atari. \fBPat Rankin\fP, with help from \fBJoshua Delahunty\fP, was responsible for the VMS version of NetHack 3.1. \fBMichael Allison\fP ported NetHack 3.1 to Windows NT. .pg \fBDean Luick\fP, with help from \fBDavid Cohrs\fP, developed NetHack 3.1 for X11. \fBWarwick Allison\fP wrote a tiled version of NetHack for the Atari; he later contributed the tiles to the DevTeam and tile support was then added to other platforms. .pg The 3.2 development team, comprised of \fBMichael Allison\fP, \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBSteve Creps\fP, \fBKevin Darcy\fP, \fBTimo Hakulinen\fP, \fBSteve Linhart\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBEric Smith\fP, \fBMike Stephenson\fP, \fBJanet Walz\fP, and \fBPaul Winner\fP, released version 3.2 in April of 1996. .pg Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all thirteen members of the original development team remained on the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2, one of the founding members of the development team, \fBDr. Izchak Miller\fP, was diagnosed with cancer and passed away. That release of the game was dedicated to him by the development and porting teams. .pg During the lifespan of NetHack 3.1 and 3.2, several enthusiasts of the game added their own modifications to the game and made these ``variants'' publicly available: .pg \fBTom Proudfoot\fP and \fBYuval Oren\fP created NetHack++, which was quickly renamed NetHack--. Working independently, \fBStephen White\fP wrote NetHack Plus. \fBTom Proudfoot\fP later merged NetHack Plus and his own NetHack-- to produce SLASH. \fBLarry Stewart-Zerba\fP and \fBWarwick Allison\fP improved the spell casting system with the Wizard Patch. \fBWarwick Allison\fP also ported NetHack to use the Qt interface. .pg \fBWarren Cheung\fP combined SLASH with the Wizard Patch to produce Slash'em, and with the help of \fBKevin Hugo\fP, added more features. Kevin later joined the DevTeam and incorporated the best of these ideas in NetHack 3.3. .pg The final update to 3.2 was the bug fix release 3.2.3, which was released simultaneously with 3.3.0 in December 1999 just in time for the Year 2000. .pg The 3.3 development team, consisting of \fBMichael Allison\fP, \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBSteve Creps\fP, \fBKevin Darcy\fP, \fBTimo Hakulinen\fP, \fBKevin Hugo\fP, \fBSteve Linhart\fP, \fBKen Lorber\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBEric Smith\fP, \fBMike Stephenson\fP, \fBJanet Walz\fP, and \fBPaul Winner\fP, released 3.3.0 in December 1999 and 3.3.1 in August of 2000. .pg Version 3.3 offered many firsts. It was the first version to separate race and profession. The Elf class was removed in preference to an elf race, and the races of dwarves, gnomes, and orcs made their first appearance in the game alongside the familiar human race. Monk and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, Wizards. It was also the first version to allow you to ride a steed, and was the first version to have a publicly available web-site listing all the bugs that had been discovered. Despite that constantly growing bug list, 3.3 proved stable enough to last for more than a year and a half. .pg The 3.4 development team initially consisted of \fBMichael Allison\fP, \fBKen Arromdee\fP, \fBDavid Cohrs\fP, \fBJessie Collet\fP, \fBKevin Hugo\fP, \fBKen Lorber\fP, \fBDean Luick\fP, \fBPat Rankin\fP, \fBMike Stephenson\fP, \fBJanet Walz\fP, and \fBPaul Winner\fP, with \fB Warwick Allison\fP joining just before the release of NetHack 3.4.0 in March 2002. .pg As with version 3.3, various people contributed to the game as a whole as well as supporting ports on the different platforms that NetHack runs on: .pg \fBPat Rankin\fP maintained 3.4 for VMS. .pg \fBMichael Allison\fP maintained NetHack 3.4 for the MS-DOS platform. \fBPaul Winner\fP and \fBYitzhak Sapir\fP provided encouragement. .pg \fBDean Luick\fP, \fBMark Modrall\fP, and \fBKevin Hugo\fP maintained and enhanced the Macintosh port of 3.4. .pg \fBMichael Allison\fP, \fBDavid Cohrs\fP, \fBAlex Kompel\fP, \fBDion Nicolaas\fP, and \fBYitzhak Sapir\fP maintained and enhanced 3.4 for the Microsoft Windows platform. \fBAlex Kompel\fP contributed a new graphical interface for the Windows port. \fBAlex Kompel\fP also contributed a Windows CE port for 3.4.1. .pg \fBRon Van Iwaarden\fP maintained 3.4 for OS/2. .pg \fBJanne Salmijarvi\fP and \fBTeemu Suikki\fP maintained and enhanced the Amiga port of 3.4 after \fBJanne Salmijarvi\fP resurrected it for 3.3.1. .pg \fBChristian ``Marvin'' Bressler\fP maintained 3.4 for the Atari after he resurrected it for 3.3.1. .pg There is a NetHack web site maintained by \fBKen Lorber\fP at http://www.nethack.org/. .pg - - - - - - - - - - .pg From time to time, some depraved individual out there in netland sends a particularly intriguing modification to help out with the game. The Gods of the Dungeon sometimes make note of the names of the worst of these miscreants in this, the list of Dungeoneers: .sd .TS S center; c c c. .\"TABLE_START Adam Aronow Izchak Miller Mike Stephenson Alex Kompel J. Ali Harlow Norm Meluch Andreas Dorn Janet Walz Olaf Seibert Andy Church Janne Salmijarvi Pasi Kallinen Andy Swanson Jean-Christophe Collet Pat Rankin Ari Huttunen Jochen Erwied Paul Winner Barton House John Kallen Pierre Martineau Benson I. Margulies John Rupley Ralf Brown Bill Dyer John S. Bien Ray Chason Boudewijn Waijers Johnny Lee Richard Addison Bruce Cox Jon W{tte Richard Beigel Bruce Holloway Jonathan Handler Richard P. Hughey Bruce Mewborne Joshua Delahunty Rob Menke Carl Schelin Keizo Yamamoto Robin Johnson Chris Russo Ken Arnold Roderick Schertler David Cohrs Ken Arromdee Roland McGrath David Damerell Ken Lorber Ron Van Iwaarden David Gentzel Ken Washikita Ronnen Miller David Hairston Kevin Darcy Ross Brown Dean Luick Kevin Hugo Sascha Wostmann Del Lamb Kevin Sitze Scott Bigham Deron Meranda Kevin Smolkowski Scott R. Turner Dion Nicolaas Kevin Sweet Stephen Spackman Dylan O'Donnell Lars Huttar Stephen White Eric Backus Malcolm Ryan Steve Creps Eric Hendrickson Mark Gooderum Steve Linhart Eric R. Smith Mark Modrall Steve VanDevender Eric S. Raymond Marvin Bressler Teemu Suikki Erik Andersen Matthew Day Tim Lennan Frederick Roeber Merlyn LeRoy Timo Hakulinen Gil Neiger Michael Allison Tom Almy Greg Laskin Michael Feir Tom West Greg Olson Michael Hamel Warren Cheung Gregg Wonderly Michael Sokolov Warwick Allison Hao-yang Wang Mike Engber Yitzhak Sapir Helge Hafting Mike Gallop Irina Rempt-Drijfhout Mike Passaretti .\"TABLE_END Do not delete this line. .TE .ed .\"Microsoft and MS-DOS are registered trademarks of Microsoft Corporation. .\"Lattice is a trademark of Lattice, Inc. .\"Atari and 1040ST are trademarks of Atari, Inc. .\"AMIGA is a trademark of Commodore-Amiga, Inc. .sm "Brand and product names are trademarks or registered trademarks \ of their respective holders." nethack-3.4.3/doc/Guidebook.tex0100644000000000000000000037130607764735041015063 0ustar rootroot\documentstyle[titlepage]{article} \textheight 220mm \textwidth 160mm \oddsidemargin 0mm \evensidemargin 0mm \topmargin 0mm \newcommand{\nd}{\noindent} \newcommand{\tb}[1]{\tt #1 \hfill} \newcommand{\bb}[1]{\bf #1 \hfill} \newcommand{\ib}[1]{\it #1 \hfill} \newcommand{\blist}[1] {\begin{list}{$\bullet$} {\leftmargin 30mm \topsep 2mm \partopsep 0mm \parsep 0mm \itemsep 1mm \labelwidth 28mm \labelsep 2mm #1}} \newcommand{\elist}{\end{list}} % this will make \tt underscores look better, but requires that % math subscripts will never be used in this document \catcode`\_=12 \begin{document} % % input file: guidebook.mn % $Revision: 1.61.2.19 $ $Date: 2003/12/03 03:00:50 $ % %.ds h0 " %.ds h1 %.ds h2 \% %.ds f0 " %.mt \title{\LARGE A Guide to the Mazes of Menace:\\ \Large Guidebook for {\it NetHack\/}} %.au \author{Eric S. Raymond\\ (Extensively edited and expanded for 3.4)} \date{December 2, 2003} \maketitle %.hn 1 \section{Introduction} %.pg Recently, you have begun to find yourself unfulfilled and distant in your daily occupation. Strange dreams of prospecting, stealing, crusading, and combat have haunted you in your sleep for many months, but you aren't sure of the reason. You wonder whether you have in fact been having those dreams all your life, and somehow managed to forget about them until now. Some nights you awaken suddenly and cry out, terrified at the vivid recollection of the strange and powerful creatures that seem to be lurking behind every corner of the dungeon in your dream. Could these details haunting your dreams be real? As each night passes, you feel the desire to enter the mysterious caverns near the ruins grow stronger. Each morning, however, you quickly put the idea out of your head as you recall the tales of those who entered the caverns before you and did not return. Eventually you can resist the yearning to seek out the fantastic place in your dreams no longer. After all, when other adventurers came back this way after spending time in the caverns, they usually seemed better off than when they passed through the first time. And who was to say that all of those who did not return had not just kept going? %.pg Asking around, you hear about a bauble, called the Amulet of Yendor by some, which, if you can find it, will bring you great wealth. One legend you were told even mentioned that the one who finds the amulet will be granted immortality by the gods. The amulet is rumored to be somewhere beyond the Valley of Gehennom, deep within the Mazes of Menace. Upon hearing the legends, you immediately realize that there is some profound and undiscovered reason that you are to descend into the caverns and seek out that amulet of which they spoke. Even if the rumors of the amulet's powers are untrue, you decide that you should at least be able to sell the tales of your adventures to the local minstrels for a tidy sum, especially if you encounter any of the terrifying and magical creatures of your dreams along the way. You spend one last night fortifying yourself at the local inn, becoming more and more depressed as you watch the odds of your success being posted on the inn's walls getting lower and lower. %.pg \nd In the morning you awake, collect your belongings, and set off for the dungeon. After several days of uneventful travel, you see the ancient ruins that mark the entrance to the Mazes of Menace. It is late at night, so you make camp at the entrance and spend the night sleeping under the open skies. In the morning, you gather your gear, eat what may be your last meal outside, and enter the dungeon\ldots %.hn 1 \section{What is going on here?} %.pg You have just begun a game of {\it NetHack}. Your goal is to grab as much treasure as you can, retrieve the Amulet of Yendor, and escape the Mazes of Menace alive. %.pg Your abilities and strengths for dealing with the hazards of adventure will vary with your background and training: %.pg % \blist{} \item[\bb{Archeologists}]% understand dungeons pretty well; this enables them to move quickly and sneak up on the local nasties. They start equipped with the tools for a proper scientific expedition. %.pg % \item[\bb{Barbarians}]% are warriors out of the hinterland, hardened to battle. They begin their quests with naught but uncommon strength, a trusty hauberk, and a great two-handed sword. %.pg % \item[\bb{Cavemen {\rm and} Cavewomen}] start with exceptional strength, but unfortunately, neolithic weapons. %.pg % \item[\bb{Healers}]% are wise in medicine and apothecary. They know the herbs and simples that can restore vitality, ease pain, anesthetize, and neutralize poisons; and with their instruments, they can divine a being's state of health or sickness. Their medical practice earns them quite reasonable amounts of money, with which they enter the dungeon. %.pg % \item[\bb{Knights}]% are distinguished from the common skirmisher by their devotion to the ideals of chivalry and by the surpassing excellence of their armor. %.pg % \item[\bb{Monks}]% are ascetics, who by rigorous practice of physical and mental disciplines have become capable of fighting as effectively without weapons as with. They wear no armor but make up for it with increased mobility. %.pg % \item[\bb{Priests {\rm and} Priestesses}]% are clerics militant, crusaders advancing the cause of righteousness with arms, armor, and arts thaumaturgic. Their ability to commune with deities via prayer occasionally extricates them from peril, but can also put them in it. %.pg % \item[\bb{Rangers}]% are most at home in the woods, and some say slightly out of place in a dungeon. They are, however, experts in archery as well as tracking and stealthy movement. %.pg % \item[\bb{Rogues}]% are agile and stealthy thieves, with knowledge of locks, traps, and poisons. Their advantage lies in surprise, which they employ to great advantage. %.pg % \item[\bb{Samurai}]% are the elite warriors of feudal Nippon. They are lightly armored and quick, and wear the % {\it dai-sho}, two swords of the deadliest keenness. %.pg % \item[\bb{Tourists}]% start out with lots of gold (suitable for shopping with), a credit card, lots of food, some maps, and an expensive camera. Most monsters don't like being photographed. %.pg % \item[\bb{Valkyries}]% are hardy warrior women. Their upbringing in the harsh Northlands makes them strong, inures them to extremes of cold, and instills in them stealth and cunning. %.pg % \item[\bb{Wizards}]% start out with a knowledge of magic, a selection of magical items, and a particular affinity for dweomercraft. Although seemingly weak and easy to overcome at first sight, an experienced Wizard is a deadly foe. \elist %.pg You may also choose the race of your character: %.pg % \blist{} \item[\bb{Dwarves}]% are smaller than humans or elves, but are stocky and solid individuals. Dwarves' most notable trait is their great expertise in mining and metalwork. Dwarvish armor is said to be second in quality not even to the mithril armor of the Elves. %.pg % \item[\bb{Elves}]% are agile, quick, and perceptive; very little of what goes on will escape an Elf. The quality of Elven craftsmanship often gives them an advantage in arms and armor. %.pg % \item[\bb{Gnomes}]% are smaller than but generally similar to dwarves. Gnomes are known to be expert miners, and it is known that a secret underground mine complex built by this race exists within the Mazes of Menace, filled with both riches and danger. %.pg % \item[\bb{Humans}]% are by far the most common race of the surface world, and are thus the norm by which other races are often compared. Although they have no special abilities, they can succeed in any role. %.pg % \item[\bb{Orcs}]% are a cruel and barbaric race that hate every living thing (including other orcs). Above all others, Orcs hate Elves with a passion unequalled, and will go out of their way to kill one at any opportunity. The armor and weapons fashioned by the Orcs are typically of inferior quality. \elist %.hn 1 \section{What do all those things on the screen mean?} %.pg On the screen is kept a map of where you have been and what you have seen on the current dungeon level; as you explore more of the level, it appears on the screen in front of you. %.pg When {\it NetHack\/}'s ancestor {\it rogue\/} first appeared, its screen orientation was almost unique among computer fantasy games. Since then, screen orientation has become the norm rather than the exception; {\it NetHack\/} continues this fine tradition. Unlike text adventure games that accept commands in pseudo-English sentences and explain the results in words, {\it NetHack\/} commands are all one or two keystrokes and the results are displayed graphically on the screen. A minimum screen size of 24 lines by 80 columns is recommended; if the screen is larger, only a $21\times80$ section will be used for the map. %.pg {\it NetHack\/} can even be played by blind players, with the assistance of Braille readers or speech synthesisers. Instructions for configuring {\it NetHack\/} for the blind are included later in this document. %.pg {\it NetHack\/} generates a new dungeon every time you play it; even the authors still find it an entertaining and exciting game despite having won several times. %.pg {\it NetHack\/} offers a variety of display options. The options available to you will vary from port to port, depending on the capabilities of your hardware and software, and whether various compile-time options were enabled when your executable was created. The three possible display options are: a monochrome character interface, a color character interface, and a graphical interface using small pictures called tiles. The two character interfaces allow fonts with other characters to be substituted, but the default assignments use standard ASCII characters to represent everything. There is no difference between the various display options with respect to game play. Because we cannot reproduce the tiles or colors in the Guidebook, and because it is common to all ports, we will use the default ASCII characters from the monochrome character display when referring to things you might see on the screen during your game. %.pg In order to understand what is going on in {\it NetHack}, first you must understand what {\it NetHack\/} is doing with the screen. The {\it NetHack\/} screen replaces the ``You see \ldots'' descriptions of text adventure games. Figure 1 is a sample of what a {\it NetHack\/} screen might look like. The way the screen looks for you depends on your platform. \vbox{ \begin{verbatim} The bat bites! ------ |....| ---------- |.<..|####...@...$.| |....-# |...B....+ |....| |.d......| ------ -------|-- Player the Rambler St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15 Neutral Dlvl:1 $:0 HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak \end{verbatim} \begin{center} Figure 1 \end{center} } %.hn 2 \subsection*{The status lines (bottom)} %.pg The bottom two lines of the screen contain several cryptic pieces of information describing your current status. If either status line becomes longer than the width of the screen, you might not see all of it. Here are explanations of what the various status items mean (though your configuration may not have all the status items listed below): %.lp \blist{} \item[\bb{Rank}] Your character's name and professional ranking (based on the experience level, see below). %.lp \item[\bb{Strength}] A measure of your character's strength; one of your six basic attributes. A human character's attributes can range from 3 to 18 inclusive; non-humans may exceed these limits (occasionally you may get super-strengths of the form 18/xx, and magic can also cause attributes to exceed the normal limits). The higher your strength, the stronger you are. Strength affects how successfully you perform physical tasks, how much damage you do in combat, and how much loot you can carry. %.lp \item[\bb{Dexterity}] Dexterity affects your chances to hit in combat, to avoid traps, and do other tasks requiring agility or manipulation of objects. %.lp \item[\bb{Constitution}] Constitution affects your ability to recover from injuries and other strains on your stamina. %.lp \item[\bb{Intelligence}] Intelligence affects your ability to cast spells and read spellbooks. %.lp \item[\bb{Wisdom}] Wisdom comes from your practical experience (especially when dealing with magic). It affects your magical energy. %.lp \item[\bb{Charisma}] Charisma affects how certain creatures react toward you. In particular, it can affect the prices shopkeepers offer you. %.lp \item[\bb{Alignment}] % {\it Lawful}, {\it Neutral\/} or {\it Chaotic}. Often, Lawful is taken as good and Chaotic is evil, but legal and ethical do not always coincide. Your alignment influences how other monsters react toward you. Monsters of a like alignment are more likely to be non-aggressive, while those of an opposing alignment are more likely to be seriously offended at your presence. %.lp \item[\bb{Dungeon Level}] How deep you are in the dungeon. You start at level one and the number increases as you go deeper into the dungeon. Some levels are special, and are identified by a name and not a number. The Amulet of Yendor is reputed to be somewhere beneath the twentieth level. %.lp \item[\bb{Gold}] The number of gold pieces you are openly carrying. Gold which you have concealed in containers is not counted. %.lp \item[\bb{Hit Points}] Your current and maximum hit points. Hit points indicate how much damage you can take before you die. The more you get hit in a fight, the lower they get. You can regain hit points by resting, or by using certain magical items or spells. The number in parentheses is the maximum number your hit points can reach. %.lp \item[\bb{Power}] Spell points. This tells you how much mystic energy ({\it mana\/}) you have available for spell casting. Again, resting will regenerate the amount available. %.lp \item[\bb{Armor Class}] A measure of how effectively your armor stops blows from unfriendly creatures. The lower this number is, the more effective the armor; it is quite possible to have negative armor class. %.lp \item[\bb{Experience}] Your current experience level and experience points. As you adventure, you gain experience points. At certain experience point totals, you gain an experience level. The more experienced you are, the better you fight and withstand magical attacks. Many dungeons show only your experience level here. %.lp \item[\bb{Time}] The number of turns elapsed so far, displayed if you have the {\it time\/} option set. %.lp \item[\bb{Hunger Status}] Your current hunger status, ranging from % {\it Satiated\/} down to {\it Fainting}. If your hunger status is normal, it is not displayed. %.pg Additional status flags may appear after the hunger status: {\it Conf\/} when you're confused, {\it FoodPois\/} or {\it Ill\/} when sick, {\it Blind\/} when you can't see, {\it Stun\/} when stunned, and {\it Hallu\/} when hallucinating. \elist %.hn 2 \subsection*{The message line (top)} %.pg The top line of the screen is reserved for messages that describe things that are impossible to represent visually. If you see a ``{\tt --More--}'' on the top line, this means that {\it NetHack\/} has another message to display on the screen, but it wants to make certain that you've read the one that is there first. To read the next message, just press the space bar. %.hn 2 \subsection*{The map (rest of the screen)} %.pg The rest of the screen is the map of the level as you have explored it so far. Each symbol on the screen represents something. You can set various graphics options to change some of the symbols the game uses; otherwise, the game will use default symbols. Here is a list of what the default symbols mean: \blist{} %.lp \item[\tb{- {\rm and} |}] The walls of a room, or an open door. Or a grave ({\tt |}). %.lp \item[\tb{.}] The floor of a room, ice, or a doorless doorway. %.lp \item[\tb{\#}] A corridor, or iron bars, or a tree, or possibly a kitchen sink (if your dungeon has sinks), or a drawbridge. %.lp \item[\tb{>}] Stairs down: a way to the next level. %.lp \item[\tb{<}] Stairs up: a way to the previous level. %.lp \item[\tb{+}] A closed door, or a spellbook containing a spell you may be able to learn. %.lp \item[\tb{@}] Your character or a human. %.lp \item[\tb{\$}] A pile of gold. %.lp \item[\tb{\^}] A trap (once you have detected it). %.lp \item[\tb{)}] A weapon. %.lp \item[\tb{[}] A suit or piece of armor. %.lp \item[\tb{\%}] Something edible (not necessarily healthy). %.lp \item[\tb{?}] A scroll. %.lp \item[\tb{/}] A wand. %.lp \item[\tb{=}] A ring. %.lp \item[\tb{!}] A potion. %.lp \item[\tb{(}] A useful item (pick-axe, key, lamp \ldots). %.lp \item[\tb{"}] An amulet or a spider web. %.lp \item[\tb{*}] A gem or rock (possibly valuable, possibly worthless). %.lp \item[\tb{`}] A boulder or statue. %.lp \item[\tb{0}] An iron ball. %.lp \item[\tb{_}] An altar, or an iron chain. %.lp \item[\tb{\{}] A fountain. %.lp \item[\tb{\}}] A pool of water or moat or a pool of lava. %.lp \item[\tb{$\backslash$}] An opulent throne. %.lp \item[\tb{a-zA-Z {\rm \& other symbols}}] Letters and certain other symbols represent the various inhabitants of the Mazes of Menace. Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. %.lp \item[\tb{I}] This marks the last known location of an invisible or otherwise unseen monster. Note that the monster could have moved. The `F' and `m' commands may be useful here. \elist %.pg You need not memorize all these symbols; you can ask the game what any symbol represents with the `{\tt /}' command (see the next section for more info). %.hn 1 \section{Commands} %.pg Commands are initiated by typing one or two characters. Some commands, like ``{\tt search}'', do not require that any more information be collected by {\it NetHack\/}. Other commands might require additional information, for example a direction, or an object to be used. For those commands that require additional information, {\it NetHack\/} will present you with either a menu of choices, or with a command line prompt requesting information. Which you are presented with will depend chiefly on how you have set the `{\it menustyle\/}' option. %.pg For example, a common question in the form ``{\tt What do you want to use? [a-zA-Z\ ?*]}'', asks you to choose an object you are carrying. Here, ``{\tt a-zA-Z}'' are the inventory letters of your possible choices. Typing `{\tt ?}' gives you an inventory list of these items, so you can see what each letter refers to. In this example, there is also a `{\tt *}' indicating that you may choose an object not on the list, if you wanted to use something unexpected. Typing a `{\tt *}' lists your entire inventory, so you can see the inventory letters of every object you're carrying. Finally, if you change your mind and decide you don't want to do this command after all, you can press the `ESC' key to abort the command. %.pg You can put a number before some commands to repeat them that many times; for example, ``{\tt 10s}'' will search ten times. If you have the {\it number\_pad\/} option set, you must type `{\tt n}' to prefix a count, so the example above would be typed ``{\tt n10s}'' instead. Commands for which counts make no sense ignore them. In addition, movement commands can be prefixed for greater control (see below). To cancel a count or a prefix, press the `ESC' key. %.pg The list of commands is rather long, but it can be read at any time during the game through the `{\tt ?}' command, which accesses a menu of helpful texts. Here are the commands for your reference: \blist{} %.lp \item[\tb{?}] Help menu: display one of several help texts available. %.lp \item[\tb{/}] Tell what a symbol represents. You may choose to specify a location or type a symbol (or even a whole word) to explain. Specifying a location is done by moving the cursor to a particular spot on the map and then pressing one of `{\tt .}', `{\tt ,}', `{\tt ;}', or `{\tt :}'. `{\tt .}' will explain the symbol at the chosen location, conditionally check for ``{\tt More info?}'' depending upon whether the {\it help\/} option is on, and then you will be asked to pick another location; `{\tt ,}' will explain the symbol but skip any additional information; `{\tt ;}' will skip additional info and also not bother asking you to choose another location to examine; `{\tt :}' will show additional info, if any, without asking for confirmation. When picking a location, pressing the {\tt ESC} key will terminate this command, or pressing `{\tt ?}' will give a brief reminder about how it works. %.pg Specifying a name rather than a location always gives any additional information available about that name. %.lp \item[\tb{\&}] Tell what a command does. %.lp \item[\tb{<}] Go up to the previous level (if you are on a staircase or ladder). %.lp \item[\tb{>}] Go down to the next level (if you are on a staircase or ladder). %.lp \item[\tb{[yuhjklbn]}] Go one step in the direction indicated (see Figure 2). If you sense or remember a monster there, you will fight the monster instead. Only these one-step movement commands cause you to fight monsters; the others (below) are ``safe.'' %.sd \begin{center} \begin{tabular}{cc} \verb+ y k u + & \verb+ 7 8 9 +\\ \verb+ \ | / + & \verb+ \ | / +\\ \verb+ h- . -l + & \verb+ 4- . -6 +\\ \verb+ / | \ + & \verb+ / | \ +\\ \verb+ b j n + & \verb+ 1 2 3 +\\ & (if {\it number\_pad\/} set) \end{tabular} \end{center} %.ed \begin{center} Figure 2 \end{center} %.lp \item[\tb{[YUHJKLBN]}] Go in that direction until you hit a wall or run into something. %.lp \item[\tb{m[yuhjklbn]}] Prefix: move without picking up objects or fighting (even if you remember a monster there) %.lp \item[\tb{F[yuhjklbn]}] Prefix: fight a monster (even if you only guess one is there) %.lp \item[\tb{M[yuhjklbn]}] Prefix: Move far, no pickup. %.lp \item[\tb{g[yuhjklbn]}] Prefix: Move until something interesting is found. %.lp \item[\tb{G[yuhjklbn] {\rm or} [yuhjklbn]}] Prefix: Same as `{\tt g}', but forking of corridors is not considered interesting. %.lp \item[\tb{_}] Travel to a map location via a shortest-path algorithm. The shortest path is computed over map locations the hero knows about (e.g. seen or previously traversed). If there is no known path, a guess is made instead. Stops on most of the same conditions as the `G' command, but without picking up objects, similar to the `M' command. For ports with mouse support, the command is also invoked when a mouse-click takes place on a location other than the current position. %.lp \item[\tb{.}] Rest, do nothing for one turn. %.lp \item[\tb{a}] Apply (use) a tool (pick-axe, key, lamp \ldots). %.lp \item[\tb{A}] Remove one or more worn items, such as armor. Use `{\tt T}' (take off) to take off only one piece of armor or `{\tt R}' (remove) to take off only one accessory. %.lp \item[\tb{\^{}A}] Redo the previous command. %.lp \item[\tb{c}] Close a door. %.lp \item[\tb{C}] Call (name) an individual monster. %.lp \item[\tb{\^{}C}] Panic button. Quit the game. %.lp \item[\tb{d}] Drop something.\\ {\tt d7a} --- drop seven items of object {\it a}. %.lp \item[\tb{D}] Drop several things. In answer to the question ``{\tt What kinds of things do you want to drop? [!\%= BUCXaium]}'' you should type zero or more object symbols possibly followed by `{\tt a}' and/or `{\tt i}' and/or `{\tt u}' and/or `{\tt m}'. In addition, one or more of the blessed/uncursed/cursed groups may be typed.\\ %.sd %.si {\tt DB} --- drop all objects known to be blessed.\\ {\tt DU} --- drop all objects known to be uncursed.\\ {\tt DC} --- drop all objects known to be cursed.\\ {\tt DX} --- drop all objects of unknown B/U/C status.\\ {\tt Da} --- drop all objects, without asking for confirmation.\\ {\tt Di} --- examine your inventory before dropping anything.\\ {\tt Du} --- drop only unpaid objects (when in a shop).\\ {\tt Dm} --- use a menu to pick which object(s) to drop.\\ {\tt D\%u} --- drop only unpaid food. %.ei %.ed %.lp \item[\tb{\^{}D}] Kick something (usually a door). %.lp \item[\tb{e}] Eat food. %.lp % Make sure Elbereth is not hyphenated below, the exact spelling matters. % (Only specified here to parallel Guidebook.mn; use of \tt font implicity % prevents automatic hyphenation in TeX and LaTeX.) \hyphenation{Elbereth} %override the deduced syllable breaks \item[\tb{E}] Engrave a message on the floor. Engraving the word ``{\tt Elbereth}'' will cause most monsters to not attack you hand-to-hand (but if you attack, you will rub it out); this is often useful to give yourself a breather. (This feature may be compiled out of the game, so your version might not have it.)\\ %.sd %.si {\tt E-} --- write in the dust with your fingers. %.ei %.ed %.Ip \item[\tb{f}] Fire one of the objects placed in your quiver. You may select ammunition with a previous `{\tt Q}' command, or let the computer pick something appropriate if {\it autoquiver\/} is true. %.lp \item[\tb{i}] List your inventory (everything you're carrying). %.lp \item[\tb{I}] List selected parts of your inventory.\\ %.sd %.si {\tt I*} --- list all gems in inventory;\\ {\tt Iu} --- list all unpaid items;\\ {\tt Ix} --- list all used up items that are on your shopping bill;\\ {\tt I\$} --- count your money. %.ei %.ed %.lp \item[\tb{o}] Open a door. %.lp \item[\tb{O}] Set options. A menu showing the current option values will be displayed. You can change most values simply by selecting the menu entry for the given option (ie, by typing its letter or clicking upon it, depending on your user interface). For the non-boolean choices, a further menu or prompt will appear once you've closed this menu. The available options are listed later in this Guidebook. Options are usually set before the game rather than with the `{\tt O}' command; see the section on options below. %.lp \item[\tb{p}] Pay your shopping bill. %.lp \item[\tb{P}] Put on a ring or other accessory (amulet, blindfold). %.lp \item[\tb{\^{}P}] Repeat previous message. Subsequent {\tt \^{}P}'s repeat earlier messages. The behavior can be varied via the msg_window option. %.lp \item[\tb{q}] Quaff (drink) something (potion, water, etc). %.lp \item[\tb{Q}] Select an object for your quiver. You can then throw this using the `f' command. (In versions prior to 3.3 this was the command to quit the game, which has now been moved to `{\tt \#quit}'.) %.lp \item[\tb{r}] Read a scroll or spellbook. %.lp \item[\tb{R}] Remove an accessory (ring, amulet, etc). %.lp \item[\tb{\^{}R}] Redraw the screen. %.lp \item[\tb{s}] Search for secret doors and traps around you. It usually takes several tries to find something. %.lp \item[\tb{S}] Save (and suspend) the game. The game will be restored automatically the next time you play. %.lp \item[\tb{t}] Throw an object or shoot a projectile. %.lp \item[\tb{T}] Take off armor. %.lp \item[\tb{\^{}T}] Teleport, if you have the ability. %.lp \item[\tb{v}] Display version number. %.lp \item[\tb{V}] Display the game history. %.lp \item[\tb{w}] Wield weapon.\\ %.sd %.si {\tt w-} --- wield nothing, use your bare hands. %.ei %.ed %.lp \item[\tb{W}] Wear armor. %.lp \item[\tb{x}] Exchange your wielded weapon with the item in your alternate weapon slot. The latter is used as your secondary weapon when engaging in two-weapon combat. Note that if one of these slots is empty, the exchange still takes place. %.lp \item[\tb{X}] Enter explore (discovery) mode, explained in its own section later. %.lp \item[\tb{\^{}X}] Display your name, role, race, gender, and alignment as well as the various deities in your game. %.lp \item[\tb{z}] Zap a wand. To aim at yourself, use `{\tt .}' for the direction. %.lp \item[\tb{Z}] Zap (cast) a spell. To cast at yourself, use `{\tt .}' for the direction. %.lp \item[\tb{\^{}Z}] Suspend the game (UNIX versions with job control only). %.lp \item[\tb{:}] Look at what is here. %.lp \item[\tb{;}] Show what type of thing a visible symbol corresponds to. %.lp \item[\tb{,}] Pick up some things. May be preceded by `{\tt m}' to force a selection menu. %.lp \item[\tb{@}] Toggle the {\it autopickup\/} option on and off. %.lp \item[\tb{\^{}}] Ask for the type of a trap you found earlier. %.lp \item[\tb{)}] Tell what weapon you are wielding. %.lp \item[\tb{[}] Tell what armor you are wearing. %.lp \item[\tb{=}] Tell what rings you are wearing. %.lp \item[\tb{"}] Tell what amulet you are wearing. %.lp \item[\tb{(}] Tell what tools you are using. %.lp \item[\tb{*}] Tell what equipment you are using; combines the preceding five type-specific commands into one. %.lp \item[\tb{\$}] Count your gold pieces. %.lp \item[\tb{+}] List the spells you know. Using this command, you can also rearrange the order in which your spells are listed. They are shown via a menu, and if you select a spell in that menu, you'll be re-prompted for another spell to swap places with it, and then have opportunity to make further exchanges. %.lp \item[\tb{$\backslash$}] Show what types of objects have been discovered. %.lp \item[\tb{!}] Escape to a shell. %.lp \item[\tb{\#}] Perform an extended command. As you can see, the authors of {\it NetHack\/} used up all the letters, so this is a way to introduce the less frequently used commands. What extended commands are available depends on what features the game was compiled with. %.lp \item[\tb{\#adjust}] Adjust inventory letters (most useful when the {\it fixinv\/} option is ``on''). %.lp \item[\tb{\#chat}] Talk to someone. %.lp \item[\tb{\#conduct}] List which challenges you have adhered to. See the section below entitled ``Conduct'' for details. %.lp \item[\tb{\#dip}] Dip an object into something. %.lp \item[\tb{\#enhance}] Advance or check weapons and spell skills. %.lp \item[\tb{\#force}] Force a lock. %.lp \item[\tb{\#invoke}] Invoke an object's special powers. %.lp \item[\tb{\#jump}] Jump to another location. %.lp \item[\tb{\#loot}] Loot a box or bag on the floor beneath you, or the saddle from a horse standing next to you. %.lp \item[\tb{\#monster}] Use a monster's special ability (when polymorphed into monster form). %.lp \item[\tb{\#name}] Name an item or type of object. %.lp \item[\tb{\#offer}] Offer a sacrifice to the gods. %.lp \item[\tb{\#pray}] Pray to the gods for help. %.lp \item[\tb{\#quit}] Quit the program without saving your game. %.lp \item[\tb{\#ride}] Ride (or stop riding) a monster. %.lp \item[\tb{\#rub}] Rub a lamp or a stone. %.lp \item[\tb{\#sit}] Sit down. %.lp \item[\tb{\#turn}] Turn undead. %.lp \item[\tb{\#twoweapon}] Toggle two-weapon combat on or off. Note that you must use suitable weapons for this type of combat, or it will be automatically turned off. %.lp \item[\tb{\#untrap}] Untrap something (trap, door, or chest). %.lp \item[\tb{\#version}] Print compile time options for this version of {\it NetHack}. %.lp \item[\tb{\#wipe}] Wipe off your face. %.lp \item[\tb{\#?}] Help menu: get the list of available extended commands. \elist %.pg \nd If your keyboard has a meta key (which, when pressed in combination with another key, modifies it by setting the `meta' [8th, or `high'] bit), you can invoke many extended commands by meta-ing the first letter of the command. %- In {\it NT, OS/2, PC\/ {\rm and} ST NetHack}, %- the `Alt' key can be used in this fashion; %- on the Amiga set the {\it altmeta\/} option to get this behavior. In {\it NT, OS/2, {\rm and} PC NetHack}, the `Alt' key can be used in this fashion. \blist{} %.lp \item[\tb{M-?}] {\tt\#?} (not supported by all platforms) %.lp \item[\tb{M-2}] {\tt\#twoweapon} (unless the {\it number\_pad\/} option is enabled) %.lp \item[\tb{M-a}] {\tt\#adjust} %.lp \item[\tb{M-c}] {\tt\#chat} %.lp \item[\tb{M-d}] {\tt\#dip} %.lp \item[\tb{M-e}] {\tt\#enhance} %.lp \item[\tb{M-f}] {\tt\#force} %.lp \item[\tb{M-i}] {\tt\#invoke} %.lp \item[\tb{M-j}] {\tt\#jump} %.lp \item[\tb{M-l}] {\tt\#loot} %.lp \item[\tb{M-m}] {\tt\#monster} %.lp \item[\tb{M-n}] {\tt\#name} %.lp \item[\tb{M-o}] {\tt\#offer} %.lp \item[\tb{M-p}] {\tt\#pray} %.Ip \item[\tb{M-q}] {\tt\#quit} %.lp \item[\tb{M-r}] {\tt\#rub} %.lp \item[\tb{M-s}] {\tt\#sit} %.lp \item[\tb{M-t}] {\tt\#turn} %.lp \item[\tb{M-u}] {\tt\#untrap} %.lp \item[\tb{M-v}] {\tt\#version} %.lp \item[\tb{M-w}] {\tt\#wipe} \elist %.pg \nd If the {\it number\_pad\/} option is on, some additional letter commands are available: \blist{} %.lp \item[\tb{h}] Help menu: display one of several help texts available, like ``{\tt ?}''. %.lp \item[\tb{j}] Jump to another location. Same as ``{\tt \#jump}'' or ``{\tt M-j}''. %.lp \item[\tb{k}] Kick something (usually a door). Same as `{\tt \^{}D}'. %.lp \item[\tb{l}] Loot a box or bag on the floor beneath you, or the saddle from a horse standing next to you. Same as ``{\tt \#loot}'' or ``{\tt M-l}''. %.lp \item[\tb{N}] Name an object or type of object. Same as ``{\tt \#name}'' or ``{\tt M-n}''. %.lp \item[\tb{u}] Untrap a trap, door, or chest. Same as ``{\tt \#untrap}'' or ``{\tt M-u}''. \elist %.hn 1 \section{Rooms and corridors} %.pg Rooms and corridors in the dungeon are either lit or dark. Any lit areas within your line of sight will be displayed; dark areas are only displayed if they are within one space of you. Walls and corridors remain on the map as you explore them. %.pg Secret corridors are hidden. You can find them with the `{\tt s}' (search) command. %.hn 2 \subsection*{Doorways} %.pg Doorways connect rooms and corridors. Some doorways have no doors; you can walk right through. Others have doors in them, which may be open, closed, or locked. To open a closed door, use the `{\tt o}' (open) command; to close it again, use the `{\tt c}' (close) command. %.pg You can get through a locked door by using a tool to pick the lock with the `{\tt a}' (apply) command, or by kicking it open with the `{\tt \^{}D}' (kick) command. %.pg Open doors cannot be entered diagonally; you must approach them straight on, horizontally or vertically. Doorways without doors are not restricted in this fashion. %.pg Doors can be useful for shutting out monsters. Most monsters cannot open doors, although a few don't need to (ex.\ ghosts can walk through doors). %.pg Secret doors are hidden. You can find them with the `{\tt s}' (search) command. Once found they are in all ways equivalent to normal doors. %.hn 2 \subsection*{Traps (`{\tt \^{}}')} %.pg There are traps throughout the dungeon to snare the unwary delver. For example, you may suddenly fall into a pit and be stuck for a few turns trying to climb out. Traps don't appear on your map until you see one triggered by moving onto it, see something fall into it, or you discover it with the `{\tt s}' (search) command. Monsters can fall prey to traps, too, which can be a very useful defensive strategy. %.pg There is a special pre-mapped branch of the dungeon based on the classic computer game ``{\tt Sokoban}.'' The goal is to push the boulders into the pits or holes. With careful foresight, it is possible to complete all of the levels according to the traditional rules of Sokoban. Some allowances are permitted in case the player gets stuck; however, they will lower your luck. \subsection*{Stairs (`{\tt <}', `{\tt >}')} %.pg In general, each level in the dungeon will have a staircase going up (`{\tt <}') to the previous level and another going down (`{\tt >}') to the next level. There are some exceptions though. For instance, fairly early in the dungeon you will find a level with two down staircases, one continuing into the dungeon and the other branching into an area known as the Gnomish Mines. Those mines eventually hit a dead end, so after exploring them (if you choose to do so), you'll need to climb back up to the main dungeon. %.pg When you traverse a set of stairs, or trigger a trap which sends you to another level, the level you're leaving will be deactivated and stored in a file on disk. If you're moving to a previously visited level, it will be loaded from its file on disk and reactivated. If you're moving to a level which has not yet been visited, it will be created (from scratch for most random levels, from a template for some ``special'' levels, or loaded from the remains of an earlier game for a ``bones'' level as briefly described below). Monsters are only active on the current level; those on other levels are essentially placed into stasis. %.pg Ordinarily when you climb a set of stairs, you will arrive on the corresponding staircase at your destination. However, pets (see below) and some other monsters will follow along if they're close enough when you travel up or down stairs, and occasionally one of these creatures will displace you during the climb. When that occurs, the pet or other monster will arrive on the staircase and you will end up nearby. \subsection*{Ladders (`{\tt <}', `{\tt >}')} %.pg Ladders serve the same purpose as staircases, and the two types of inter-level connections are nearly indistinguishable during game play. %.hn 2 \subsection*{Shops and shopping} %.pg Occasionally you will run across a room with a shopkeeper near the door and many items lying on the floor. You can buy items by picking them up and then using the `{\tt p}' command. You can inquire about the price of an item prior to picking it up by using the ``{\tt \#chat}'' command while standing on it. Using an item prior to paying for it will incur a charge, and the shopkeeper won't allow you to leave the shop until you have paid any debt you owe. %.pg You can sell items to a shopkeeper by dropping them to the floor while inside a shop. You will either be offered an amount of gold and asked whether you're willing to sell, or you'll be told that the shopkeeper isn't interested (generally, your item needs to be compatible with the type of merchandise carried by the shop). %.pg If you drop something in a shop by accident, the shopkeeper will usually claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. %.pg Shopkeepers sometimes run out of money. When that happens, you'll be offered credit instead of gold when you try to sell something. Credit can be used to pay for purchases, but it is only good in the shop where it was obtained; other shopkeepers won't honor it. (If you happen to find a ``credit card'' in the dungeon, don't bother trying to use it in shops; shopkeepers will not accept it.) %.pg The {\tt \$} command, which reports the amount of gold you are carrying (in inventory, not inside bags or boxes), will also show current shop debt or credit, if any. The {\tt Iu} command lists unpaid items (those which still belong to the shop) if you are carrying any. The {\tt Ix} command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. %.hn 3 \subsubsection*{Shop idiosyncracies} %.pg Several aspects of shop behavior might be unexpected. \begin{itemize} % note: a bullet is the default item label so we could omit [$\bullet$] here %.lp \(bu 2 \item[$\bullet$] The price of a given item can vary due to a variety of factors. %.lp \(bu 2 \item[$\bullet$] A shopkeeper treats the spot immediately inside the door as if it were outside the shop. %.lp \(bu 2 \item[$\bullet$] While the shopkeeper watches you like a hawk, he will generally ignore any other customers. %.lp \(bu 2 \item[$\bullet$] If a shop is ``closed for inventory'', it will not open of its own accord. %.lp \(bu 2 \item[$\bullet$] Shops do not get restocked with new items, regardless of inventory depletion. \end{itemize} %.hn 1 \section{Monsters} %.pg Monsters you cannot see are not displayed on the screen. Beware! You may suddenly come upon one in a dark place. Some magic items can help you locate them before they locate you (which some monsters can do very well). %.pg The commands `{\tt /}' and `{\tt ;}' may be used to obtain information about those monsters who are displayed on the screen. The command `{\tt C}' allows you to assign a name to a monster, which may be useful to help distinguish one from another when multiple monsters are present. Assigning a name which is just a space will remove any prior name. %.pg The extended command ``{\tt \#chat}'' can be used to interact with an adjacent monster. There is no actual dialog (in other words, you don't get to choose what you'll say), but chatting with some monsters such as a shopkeeper or the Oracle of Delphi can produce useful results. %.hn 2 \subsection*{Fighting} %.pg If you see a monster and you wish to fight it, just attempt to walk into it. Many monsters you find will mind their own business unless you attack them. Some of them are very dangerous when angered. Remember: discretion is the better part of valor. %.pg If you can't see a monster (if it is invisible, or if you are blinded), the symbol `I' will be shown when you learn of its presence. If you attempt to walk into it, you will try to fight it just like a monster that you can see; of course, if the monster has moved, you will attack empty air. If you guess that the monster has moved and you don't wish to fight, you can use the `m' command to move without fighting; likewise, if you don't remember a monster but want to try fighting anyway, you can use the `F' command. %.hn 2 \subsection*{Your pet} %.pg You start the game with a little dog (`{\tt d}'), cat (`{\tt f}'), or pony (`{\tt u}'), which follows you about the dungeon and fights monsters with you. Like you, your pet needs food to survive. It usually feeds itself on fresh carrion and other meats. If you're worried about it or want to train it, you can feed it, too, by throwing it food. A properly trained pet can be very useful under certain circumstances. %.pg Your pet also gains experience from killing monsters, and can grow over time, gaining hit points and doing more damage. Initially, your pet may even be better at killing things than you, which makes pets useful for low-level characters. %.pg Your pet will follow you up and down staircases if it is next to you when you move. Otherwise your pet will be stranded and may become wild. Similarly, when you trigger certain types of traps which alter your location (for instance, a trap door which drops you to a lower dungeon level), any adjacent pet will accompany you and any non-adjacent pet will be left behind. Your pet may trigger such traps itself; you will not be carried along with it even if adjacent at the time. %.hn 2 \subsection*{Steeds} %.pg Some types of creatures in the dungeon can actually be ridden if you have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer has had to resort to magic and wizardry in order to forge the alliance. Once you do have the beast under your control however, you can easily climb in and out of the saddle with the `{\tt \#ride}' command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. %.pg Riding skill is managed by the `{\tt \#enhance}' command. See the section on Weapon proficiency for more information about that. %.hn 2 \subsection*{Bones levels} %.pg You may encounter the shades and corpses of other adventurers (or even former incarnations of yourself!) and their personal effects. Ghosts are hard to kill, but easy to avoid, since they're slow and do little damage. You can plunder the deceased adventurer's possessions; however, they are likely to be cursed. Beware of whatever killed the former player; it is probably still lurking around, gloating over its last victory. %.hn 1 \section{Objects} %.pg When you find something in the dungeon, it is common to want to pick it up. In {\it NetHack}, this is accomplished automatically by walking over the object (unless you turn off the {\it autopickup\/} option (see below), or move with the `{\tt m}' prefix (see above)), or manually by using the `{\tt ,}' command. %.pg If you're carrying too many items, {\it NetHack\/} will tell you so and you won't be able to pick up anything more. Otherwise, it will add the object(s) to your pack and tell you what you just picked up. %.pg As you add items to your inventory, you also add the weight of that object to your load. The amount that you can carry depends on your strength and your constitution. The stronger you are, the less the additional load will affect you. There comes a point, though, when the weight of all of that stuff you are carrying around with you through the dungeon will encumber you. Your reactions will get slower and you'll burn calories faster, requiring food more frequently to cope with it. Eventually, you'll be so overloaded that you'll either have to discard some of what you're carrying or collapse under its weight. %.pg NetHack will tell you how badly you have loaded yourself. The symbols `Burdened', `Stressed', `Strained', `Overtaxed' and `Overloaded' are displayed on the bottom line display to indicate your condition. %.pg When you pick up an object, it is assigned an inventory letter. Many commands that operate on objects must ask you to find out which object you want to use. When {\it NetHack\/} asks you to choose a particular object you are carrying, you are usually presented with a list of inventory letters to choose from (see Commands, above). %.pg Some objects, such as weapons, are easily differentiated. Others, like scrolls and potions, are given descriptions which vary according to type. During a game, any two objects with the same description are the same type. However, the descriptions will vary from game to game. %.pg When you use one of these objects, if its effect is obvious, {\it NetHack\/} will remember what it is for you. If its effect isn't extremely obvious, you will be asked what you want to call this type of object so you will recognize it later. You can also use the ``{\tt \#name}'' command for the same purpose at any time, to name all objects of a particular type or just an individual object. When you use ``{\tt \#name}'' on an object which has already been named, specifying a space as the value will remove the prior name instead of assigning a new one. %.hn 2 \subsection*{Curses and Blessings} %.pg Any object that you find may be cursed, even if the object is otherwise helpful. The most common effect of a curse is being stuck with (and to) the item. Cursed weapons weld themselves to your hand when wielded, so you cannot unwield them. Any cursed item you wear is not removable by ordinary means. In addition, cursed arms and armor usually, but not always, bear negative enchantments that make them less effective in combat. Other cursed objects may act poorly or detrimentally in other ways. %.pg Objects can also be blessed. Blessed items usually work better or more beneficially than normal uncursed items. For example, a blessed weapon will do more damage against demons. %.pg There are magical means of bestowing or removing curses upon objects, so even if you are stuck with one, you can still have the curse lifted and the item removed. Priests and Priestesses have an innate sensitivity to this property in any object, so they can more easily avoid cursed objects than other character roles. %.pg An item with unknown status will be reported in your inventory with no prefix. An item which you know the state of will be distinguished in your inventory by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the description of the item. %.hn 2 \subsection*{Weapons (`{\tt )}')} %.pg Given a chance, most monsters in the Mazes of Menace will gratuitously try to kill you. You need weapons for self-defense (killing them first). Without a weapon, you do only 1--2 hit points of damage (plus bonuses, if any). Monk characters are an exception; they normally do much more damage with bare hands than they do with weapons. %.pg There are wielded weapons, like maces and swords, and thrown weapons, like arrows and spears. To hit monsters with a weapon, you must wield it and attack them, or throw it at them. You can simply elect to throw a spear. To shoot an arrow, you should first wield a bow, then throw the arrow. Crossbows shoot crossbow bolts. Slings hurl rocks and (other) stones (like gems). %.pg Enchanted weapons have a ``plus'' (or ``to hit enhancement'' which can be either positive or negative) that adds to your chance to hit and the damage you do to a monster. The only way to determine a weapon's enchantment is to have it magically identified somehow. Most weapons are subject to some type of damage like rust. Such ``erosion'' damage can be repaired. %.pg The chance that an attack will successfully hit a monster, and the amount of damage such a hit will do, depends upon many factors. Among them are: type of weapon, quality of weapon (enchantment and/or erosion), experience level, strength, dexterity, encumbrance, and proficiency (see below). The monster's armor class---a general defense rating, not necessarily due to wearing of armor---is a factor too; also, some monsters are particularly vulnerable to certain types of weapons. %.pg Many weapons can be wielded in one hand; some require both hands. When wielding a two-handed weapon, you can not wear a shield, and vice versa. When wielding a one-handed weapon, you can have another weapon ready to use by setting things up with the `{\tt x}' command, which exchanges your primary (the one being wielded) and alternate weapons. And if you have proficiency in the ``two weapon combat'' skill, you may wield both weapons simultaneously as primary and secondary; use the `{\tt \#twoweapon}' extended command to engage or disengage that. Only some types of characters (barbarians, for instance) have the necessary skill available. Even with that skill, using two weapons at once incurs a penalty in the chance to hit your target compared to using just one weapon at a time. %.pg There might be times when you'd rather not wield any weapon at all. To accomplish that, wield `{\tt -}', or else use the `{\tt A}' command which allows you to unwield the current weapon in addition to taking off other worn items. %.pg Those of you in the audience who are AD\&D players, be aware that each weapon which existed in AD\&D does roughly the same damage to monsters in {\it NetHack}. Some of the more obscure weapons (such as the % {\it aklys}, {\it lucern hammer}, and {\it bec-de-corbin\/}) are defined in an appendix to {\it Unearthed Arcana}, an AD\&D supplement. %.pg The commands to use weapons are `{\tt w}' (wield), `{\tt t}' (throw), `{\tt f}' (fire, an alternative way of throwing), `{\tt Q}' (quiver), `{\tt x}' (exchange), `{\tt \#twoweapon}', and `{\tt \#enhance}' (see below). %.hn 3 \subsection*{Throwing and shooting} %.pg You can throw just about anything via the `{\tt t}' command. It will prompt for the item to throw; picking `{\tt ?}' will list things in your inventory which are considered likely to be thrown, or picking `{\tt *}' will list your entire inventory. After you've chosen what to throw, you will be prompted for a direction rather than for a specific target. The distance something can be thrown depends mainly on the type of object and your strength. Arrows can be thrown by hand, but can be thrown much farther and will be more likely to hit when thrown while you are wielding a bow. %.pg You can simplify the throwing operation by using the `{\tt Q}' command to select your preferred ``missile'', then using the `{\tt f}' command to throw it. You'll be prompted for a direction as above, but you don't have to specify which item to throw each time you use `{\tt f}'. There is also an option, {\it autoquiver}, which has {\it NetHack\/} choose another item to automatically fill your quiver when the inventory slot used for `{\tt Q}' runs out. %.pg Some characters have the ability to fire a volley of multiple items in a single turn. Knowing how to load several rounds of ammunition at once---or hold several missiles in your hand---and still hit a target is not an easy task. Rangers are among those who are adept at this task, as are those with a high level of proficiency in the relevant weapon skill (in bow skill if you're wielding one to shoot arrows, in crossbow skill if you're wielding one to shoot bolts, or in sling skill if you're wielding one to shoot stones). The number of items that the character has a chance to fire varies from turn to turn. You can explicitly limit the number of shots by using a numeric prefix before the `{\tt t}' or `{\tt f}' command. For example, ``{\tt 2f}'' (or ``{\tt n2f}'' if using {\it number\_pad\/} mode) would ensure that at most 2 arrows are shot even if you could have fired 3. If you specify a larger number than would have been shot (``{\tt 4f}'' in this example), you'll just end up shooting the same number (3, here) as if no limit had been specified. Once the volley is in motion, all of the items will travel in the same direction; if the first ones kill a monster, the others can still continue beyond that spot. %.hn 3 \subsection*{Weapon proficiency} %.pg You will have varying degrees of skill in the weapons available. Weapon proficiency, or weapon skills, affect how well you can use particular types of weapons, and you'll be able to improve your skills as you progress through a game, depending on your role, your experience level, and use of the weapons. %.pg For the purposes of proficiency, weapons have been divided up into various groups such as daggers, broadswords, and polearms. Each role has a limit on what level of proficiency a character can achieve for each group. For instance, wizards can become highly skilled in daggers or staves but not in swords or bows. %.pg The `{\tt \#enhance}' extended command is used to review current weapons proficiency (also spell proficiency) and to choose which skill(s) to improve when you've used one or more skills enough to become eligible to do so. The skill rankings are ``none'' (sometimes also referred to as ``restricted'', because you won't be able to advance), ``unskilled'', ``basic'', ``skilled'', and ``expert''. Restricted skills simply will not appear in the list shown by `{\tt \#enhance}'. (Divine intervention might unrestrict a particular skill, in which case it will start at unskilled and be limited to basic.) Some characters can enhance their barehanded combat or martial arts skill beyond expert to ``master'' or ``grand master''. %.pg Use of a weapon in which you're restricted or unskilled will incur a modest penalty in the chance to hit a monster and also in the amount of damage done when you do hit; at basic level, there is no penalty or bonus; at skilled level, you receive a modest bonus in the chance to hit and amount of damage done; at expert level, the bonus is higher. A successful hit has a chance to boost your training towards the next skill level (unless you've already reached the limit for this skill). Once such training reaches the threshold for that next level, you'll be told that you feel more confident in your skills. At that point you can use `{\tt \#enhance}' to increase one or more skills. Such skills are not increased automatically because there is a limit to your total overall skills, so you need to actively choose which skills to enhance and which to ignore. %.hn 2 \subsection*{Armor (`{\tt [}')} %.pg Lots of unfriendly things lurk about; you need armor to protect yourself from their blows. Some types of armor offer better protection than others. Your armor class is a measure of this protection. Armor class (AC) is measured as in AD\&D, with 10 being the equivalent of no armor, and lower numbers meaning better armor. Each suit of armor which exists in AD\&D gives the same protection in {\it NetHack}. Here is an (incomplete) list of the armor classes provided by various suits of armor: \begin{center} \begin{tabular}{lllll} dragon scale mail & 1 & \makebox[20mm]{} & plate mail & 3\\ crystal plate mail & 3 & & bronze plate mail & 4\\ splint mail & 4 & & banded mail & 4\\ dwarvish mithril-coat & 4 & & elven mithril-coat & 5\\ chain mail & 5 & & orcish chain mail & 6\\ scale mail & 6 & & studded leather armor & 7\\ ring mail & 7 & & orcish ring mail & 8\\ leather armor & 8 & & leather jacket & 9\\ no armor & 10 \end{tabular} \end{center} %.pg \nd You can also wear other pieces of armor (ex.\ helmets, boots, shields, cloaks) to lower your armor class even further, but you can only wear one item of each category (one suit of armor, one cloak, one helmet, one shield, and so on) at a time. %.pg If a piece of armor is enchanted, its armor protection will be better (or worse) than normal, and its ``plus'' (or minus) will subtract from your armor class. For example, a +1 chain mail would give you better protection than normal chain mail, lowering your armor class one unit further to 4. When you put on a piece of armor, you immediately find out the armor class and any ``plusses'' it provides. Cursed pieces of armor usually have negative enchantments (minuses) in addition to being unremovable. %.pg Many types of armor are subject to some kind of damage like rust. Such damage can be repaired. Some types of armor may inhibit spell casting. %.pg The commands to use armor are `{\tt W}' (wear) and `{\tt T}' (take off). The `{\tt A}' command can also be used to take off armor as well as other worn items. %.hn 2 \subsection*{Food (`{\tt \%}')} %.pg Food is necessary to survive. If you go too long without eating you will faint, and eventually die of starvation. Some types of food will spoil, and become unhealthy to eat, if not protected. Food stored in ice boxes or tins (``cans'') will usually stay fresh, but ice boxes are heavy, and tins take a while to open. %.pg When you kill monsters, they usually leave corpses which are also ``food.'' Many, but not all, of these are edible; some also give you special powers when you eat them. A good rule of thumb is ``you are what you eat.'' %.pg Some character roles and some monsters are vegetarian. Vegetarian monsters will typically never eat animal corpses, while vegetarian players can, but with some rather unpleasant side-effects. %.pg You can name one food item after something you like to eat with the {\it fruit\/} option. %.pg The command to eat food is `{\tt e}'. %.hn 2 \subsection*{Scrolls (`{\tt ?}')} %.pg Scrolls are labeled with various titles, probably chosen by ancient wizards for their amusement value (ex.\ ``READ ME,'' or ``THANX MAUD'' backwards). Scrolls disappear after you read them (except for blank ones, without magic spells on them). %.pg One of the most useful of these is the % {\it scroll of identify}, which can be used to determine what another object is, whether it is cursed or blessed, and how many uses it has left. Some objects of subtle enchantment are difficult to identify without these. %.pg A mail daemon may run up and deliver mail to you as a % {\it scroll of mail} (on versions compiled with this feature). To use this feature on versions where {\it NetHack\/} mail delivery is triggered by electronic mail appearing in your system mailbox, you must let {\it NetHack\/} know where to look for new mail by setting the ``MAIL'' environment variable to the file name of your mailbox. You may also want to set the ``MAILREADER'' environment variable to the file name of your favorite reader, so {\it NetHack\/} can shell to it when you read the scroll. On versions of {\it NetHack\/} where mail is randomly generated internal to the game, these environment variables are ignored. You can disable the mail daemon by turning off the {\it mail\/} option. %.pg The command to read a scroll is `{\tt r}'. %.hn 2 \subsection*{Potions (`{\tt !}')} %.pg Potions are distinguished by the color of the liquid inside the flask. They disappear after you quaff them. %.pg Clear potions are potions of water. Sometimes these are blessed or cursed, resulting in holy or unholy water. Holy water is the bane of the undead, so potions of holy water are good things to throw (`{\tt t}') at them. It is also sometimes very useful to dip (``{\tt \#dip}'') an object into a potion. %.pg The command to drink a potion is `{\tt q}' (quaff). %.hn 2 \subsection*{Wands (`{\tt /}')} %.pg Magic wands usually have multiple magical charges. Some wands are directional---you must give a direction in which to zap them. You can also zap them at yourself (just give a `{\tt .}' or `{\tt s}' for the direction). Be warned, however, for this is often unwise. Other wands are nondirectional---they don't require a direction. The number of charges in a wand is random and decreases by one whenever you use it. %.pg When the number of charges left in a wand becomes zero, attempts to use the wand will usually result in nothing happening. Occasionally, however, it may be possible to squeeze the last few mana points from an otherwise spent wand, destroying it in the process. A wand may be recharged by using suitable magic, but doing so runs the risk of causing it to explode. The chance for such an explosion starts out very small and increases each time the wand is recharged. %.pg In a truly desperate situation, when your back is up against the wall, you might decide to go for broke and break your wand. This is not for the faint of heart. Doing so will almost certainly cause a catastrophic release of magical energies. %.pg When you have fully identified a particular wand, inventory display will include additional information in parentheses: the number of times it has been recharged followed by a colon and then by its current number of charges. A current charge count of {\tt -1} is a special case indicating that the wand has been cancelled. %.pg The command to use a wand is `{\tt z}' (zap). To break one, use the `{\tt a}' (apply) command. %.hn 2 \subsection*{Rings (`{\tt =}')} %.pg Rings are very useful items, since they are relatively permanent magic, unlike the usually fleeting effects of potions, scrolls, and wands. %.pg Putting on a ring activates its magic. You can wear only two rings, one on each ring finger. %.pg Most rings also cause you to grow hungry more rapidly, the rate varying with the type of ring. %.pg The commands to use rings are `{\tt P}' (put on) and `{\tt R}' (remove). %.hn 2 \subsection*{Spellbooks (`{\tt +}')} %.pg Spellbooks are tomes of mighty magic. When studied with the `{\tt r}' (read) command, they transfer to the reader the knowledge of a spell (and therefore eventually become unreadable) --- unless the attempt backfires. Reading a cursed spellbook or one with mystic runes beyond your ken can be harmful to your health! %.pg A spell (even when learned) can also backfire when you cast it. If you attempt to cast a spell well above your experience level, or if you have little skill with the appropriate spell type, or cast it at a time when your luck is particularly bad, you can end up wasting both the energy and the time required in casting. %.pg Casting a spell calls forth magical energies and focuses them with your naked mind. Some of the magical energy released comes from within you, and casting several spells in a row may tire you. Casting of spells also requires practice. With practice, your skill in each category of spell casting will improve. Over time, however, your memory of each spell will dim, and you will need to relearn it. %.pg Some spells are directional---you must give a direction in which to cast them. You can also cast them at yourself (just give a `{\tt .}' or `{\tt s}' for the direction). Be warned, however, for this is often unwise. Other spells are nondirectional---they don't require a direction. %.pg Just as weapons are divided into groups in which a character can become proficient (to varying degrees), spells are similarly grouped. Successfully casting a spell exercises the skill group; sufficient skill may increase the potency of the spell and reduce the risk of spell failure. Skill slots are shared with weapons skills. (See also the section on ``Weapon proficiency''.) %.pg Casting a spell also requires flexible movement, and wearing various types of armor may interfere with that. %.pg The command to read a spellbook is the same as for scrolls, `{\tt r}' (read). The `{\tt +}' command lists your current spells, their levels, categories, and chances for failure. The `{\tt Z}' (cast) command casts a spell. %.hn 2 \subsection*{Tools (`{\tt (}')} %.pg Tools are miscellaneous objects with various purposes. Some tools have a limited number of uses, akin to wand charges. For example, lamps burn out after a while. Other tools are containers, which objects can be placed into or taken out of. %.pg The command to use tools is `{\tt a}' (apply). %.hn 3 \subsection*{Containers} %.pg You may encounter bags, boxes, and chests in your travels. A tool of this sort can be opened with the ``{\tt \#loot}'' extended command when you are standing on top of it (that is, on the same floor spot), or with the `{\tt a}' (apply) command when you are carrying it. However, chests are often locked, and are in any case unwieldy objects. You must set one down before unlocking it by using a key or lock-picking tool with the `{\tt a}' (apply) command, by kicking it with the `{\tt \^{}D}' command, or by using a weapon to force the lock with the ``{\tt \#force}'' extended command. %.pg Some chests are trapped, causing nasty things to happen when you unlock or open them. You can check for and try to deactivate traps with the ``{\tt \#untrap}'' extended command. %.hn 2 \subsection*{Amulets (`{\tt "}')} %.pg Amulets are very similar to rings, and often more powerful. Like rings, amulets have various magical properties, some beneficial, some harmful, which are activated by putting them on. %.pg Only one amulet may be worn at a time, around your neck. %.pg The commands to use amulets are the same as for rings, `{\tt P}' (put on) and `{\tt R}' (remove). %.hn 2 \subsection*{Gems (`{\tt *}')} %.pg Some gems are valuable, and can be sold for a lot of gold. They are also a far more efficient way of carrying your riches. Valuable gems increase your score if you bring them with you when you exit. %.pg Other small rocks are also categorized as gems, but they are much less valuable. All rocks, however, can be used as projectile weapons (if you have a sling). In the most desperate of cases, you can still throw them by hand. %.hn 2 \subsection*{Large rocks (`{\tt `}')} %.pg Statues and boulders are not particularly useful, and are generally heavy. It is rumored that some statues are not what they seem. %.pg Very large humanoids (giants and their ilk) have been known to use boulders as weapons. %.hn 2 \subsection*{Gold (`{\tt \$}')} %.pg Gold adds to your score, and you can buy things in shops with it. There are a number of monsters in the dungeon that may be influenced by the amount of gold you are carrying (shopkeepers aside). %.hn 1 \section{Conduct} %.pg As if winning {\it NetHack\/} were not difficult enough, certain players seek to challenge themselves by imposing restrictions on the way they play the game. The game automatically tracks some of these challenges, which can be checked at any time with the {\tt \#conduct} command or at the end of the game. When you perform an action which breaks a challenge, it will no longer be listed. This gives players extra ``bragging rights'' for winning the game with these challenges. Note that it is perfectly acceptable to win the game without resorting to these restrictions and that it is unusual for players to adhere to challenges the first time they win the game. %.pg Several of the challenges are related to eating behavior. The most difficult of these is the foodless challenge. Although creatures can survive long periods of time without food, there is a physiological need for water; thus there is no restriction on drinking beverages, even if they provide some minor food benefits. Calling upon your god for help with starvation does not violate any food challenges either. %.pg A strict vegan diet is one which avoids any food derived from animals. The primary source of nutrition is fruits and vegetables. The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are also considered to be vegetable matter. Certain human food is prepared without animal products; namely, lembas wafers, cram rations, food rations (gunyoki), K-rations, and C-rations. Metal or another normally indigestible material eaten while polymorphed into a creature that can digest it is also considered vegan food. Note however that eating such items still counts against foodless conduct. %.pg Vegetarians do not eat animals; however, they are less selective about eating animal byproducts than vegans. In addition to the vegan items listed above, they may eat any kind of pudding (`P') other than the black puddings, eggs and food made from eggs (fortune cookies and pancakes), food made with milk (cream pies and candy bars), and lumps of royal jelly. Monks are expected to observe a vegetarian diet. %.pg Eating any kind of meat violates the vegetarian, vegan, and foodless conducts. This includes tripe rations, the corpses or tins of any monsters not mentioned above, and the various other chunks of meat found in the dungeon. Swallowing and digesting a monster while polymorphed is treated as if you ate the creature's corpse. Eating leather, dragon hide, or bone items while polymorphed into a creature that can digest it, or eating monster brains while polymorphed into a mind flayer, is considered eating an animal, although wax is only an animal byproduct. %.pg Regardless of conduct, there will be some items which are indigestible, and others which are hazardous to eat. Using a swallow-and-digest attack against a monster is equivalent to eating the monster's corpse. Please note that the term ``vegan'' is used here only in the context of diet. You are still free to choose not to use or wear items derived from animals (e.g. leather, dragon hide, bone, horns, coral), but the game will not keep track of this for you. Also note that ``milky'' potions may be a translucent white, but they do not contain milk, so they are compatible with a vegan diet. Slime molds or player-defined ``fruits'', although they could be anything from ``cherries'' to ``pork chops'', are also assumed to be vegan. %.pg An atheist is one who rejects religion. This means that you cannot {\tt \#pray}, {\tt \#offer} sacrifices to any god, {\tt \#turn} undead, or {\tt \#chat} with a priest. Particularly selective readers may argue that playing Monk or Priest characters should violate this conduct; that is a choice left to the player. Offering the Amulet of Yendor to your god is necessary to win the game and is not counted against this conduct. You are also not penalized for being spoken to by an angry god, priest(ess), or other religious figure; a true atheist would hear the words but attach no special meaning to them. %.pg Most players fight with a wielded weapon (or tool intended to be wielded as a weapon). Another challenge is to win the game without using such a wielded weapon. You are still permitted to throw, fire, and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. %.pg In {\it NetHack\/}, a pacifist refuses to cause the death of any other monster (i.e. if you would get experience for the death). This is a particularly difficult challenge, although it is still possible to gain experience by other means. %.pg An illiterate character cannot read or write. This includes reading a scroll, spellbook, fortune cookie message, or t-shirt; writing a scroll; or making an engraving of anything other than a single ``x'' (the traditional signature of an illiterate person). Reading an engraving, or any item that is absolutely necessary to win the game, is not counted against this conduct. The identity of scrolls and spellbooks (and knowledge of spells) in your starting inventory is assumed to be learned from your teachers prior to the start of the game and isn't counted. %.pg There are several other challenges tracked by the game. It is possible to eliminate one or more species of monsters by genocide; playing without this feature is considered a challenge. When the game offers you an opportunity to genocide monsters, you may respond with the monster type ``none'' if you want to decline. You can change the form of an item into another item of the same type (``polypiling'') or the form of your own body into another creature (``polyself'') by wand, spell, or potion of polymorph; avoiding these effects are each considered challenges. Polymorphing monsters, including pets, does not break either of these challenges. Finally, you may sometimes receive wishes; a game without an attempt to wish for any items is a challenge, as is a game without wishing for an artifact (even if the artifact immediately disappears). When the game offers you an opportunity to make a wish for an item, you may choose ``nothing'' if you want to decline. %.hn 1 \section{Options} %.pg Due to variations in personal tastes and conceptions of how {\it NetHack\/} should do things, there are options you can set to change how {\it NetHack\/} behaves. %.hn 2 \subsection*{Setting the options} %.pg Options may be set in a number of ways. Within the game, the `{\tt O}' command allows you to view all options and change most of them. You can also set options automatically by placing them in the ``NETHACKOPTIONS'' environment variable or in a configuration file. Some versions of {\it NetHack\/} also have front-end programs that allow you to set options before starting the game. %.hn 2 \subsection*{Using the NETHACKOPTIONS environment variable} %.pg The NETHACKOPTIONS variable is a comma-separated list of initial values for the various options. Some can only be turned on or off. You turn one of these on by adding the name of the option to the list, and turn it off by typing a `{\tt !}' or ``{\tt no}'' before the name. Others take a character string as a value. You can set string options by typing the option name, a colon or equals sign, and then the value of the string. The value is terminated by the next comma or the end of string. %.pg For example, to set up an environment variable so that {\it autoquiver\/} is on, {\it autopickup\/} is off, the {\it name\/} is set to ``Blue Meanie'', and the {\it fruit\/} is set to ``papaya'', you would enter the command %.sd \begin{verbatim} setenv NETHACKOPTIONS "autoquiver,\!autopickup,name:Blue Meanie,fruit:papaya" \end{verbatim} %.ed \nd in {\it csh} (note the need to escape the ! since it's special to the shell), or %.sd \begin{verbatim} NETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya" export NETHACKOPTIONS \end{verbatim} %.ed \nd in {\it sh\/} or {\it ksh}. %.hn 2 \subsection*{Using a configuration file} %.pg Any line in the configuration file starting with `{\tt \#}' is treated as a comment. Any line in the configuration file starting with ``{\tt OPTIONS=}'' may be filled out with options in the same syntax as in NETHACKOPTIONS. Any line starting with ``{\tt DUNGEON=}'', ``{\tt EFFECTS=}'', ``{\tt MONSTERS=}'', ``{\tt OBJECTS=}'', ``{\tt TRAPS=}'', or ``{\tt BOULDER=}'' is taken as defining the corresponding {\it dungeon}, {\it effects}, {\it monsters}, {\it objects}, {\it traps\/} or {\it boulder\/} option in a different syntax, a sequence of decimal numbers giving the character position in the current font to be used in displaying each entry. A zero in any entry in such a sequence leaves the display of that entry unchanged; this feature is not available using the option syntax. Such a sequence can be continued to multiple lines by putting a `{\tt \verb+\+}' at the end of each line to be continued. %.pg If your copy of the game included the compile time AUTOPICKUP\_EXCEPTIONS option, then any line starting with ``{\tt AUTOPICKUP\_EXCEPTION=}'' is taken as defining an exception to the ``{\tt pickup\_types}'' option. There is a section of this Guidebook that discusses that. %.pg The default name of the configuration file varies on different operating systems, but NETHACKOPTIONS can also be set to the full name of a file you want to use (possibly preceded by an `{\tt @}'). %.hn 2 \subsection*{Customization options} %.pg Here are explanations of what the various options do. Character strings that are too long may be truncated. Some of the options listed may be inactive in your dungeon. \blist{} %.lp \item[\ib{align}] Your starting alignment ({\tt align:lawful}, {\tt align:neutral}, or {\tt align:chaotic}). You may specify just the first letter. The default is to randomly pick an appropriate alignment. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{autodig}] Automatically dig if you are wielding a digging tool and moving into a place that can be dug (default false). %.lp \item[\ib{autopickup}] Automatically pick up things onto which you move (default on). See ``{\it pickup\_types\/}'' to refine the behavior. %.lp \item[\ib{autoquiver}] This option controls what happens when you attempt the `f' (fire) command with an empty quiver. When true, the computer will fill your quiver with some suitable weapon. Note that it will not take into account the blessed/cursed status, enchantment, damage, or quality of the weapon; you are free to manually fill your quiver with the `Q' command instead. If no weapon is found or the option is false, the `t' (throw) command is executed instead. (default false) %.lp \item[\ib{boulder}] Set the character used to display boulders (default is rock class symbol). %.lp \item[\ib{catname}] Name your starting cat (ex.\ ``{\tt catname:Morris}''). Cannot be set with the `{\tt O}' command. %.lp character \item[\ib{character}] Pick your type of character (ex.\ ``{\tt character:Monk}''); synonym for ``{\it role\/}''. See ``{\it name\/}'' for an alternate method of specifying your role. Normally only the first letter of the value is examined; the string ``{\tt random}'' is an exception. %.lp \item[\ib{checkpoint}] Save game state after each level change, for possible recovery after program crash (default on). %.lp \item[\ib{checkspace}] Check free disk space before writing files to disk (default on). You may have to turn this off if you have more than 2 GB free space on the partition used for your save and level files. Only applies when MFLOPPY was defined during compilation. %.lp \item[\ib{cmdassist}] Have the game provide some additional command assistance for new players if it detects some anticipated mistakes (default on). %.lp \item[\ib{confirm}] Have user confirm attacks on pets, shopkeepers, and other peaceable creatures (default on). %.lp \item[\ib{DECgraphics}] Use a predefined selection of characters from the DEC VT-xxx/DEC Rainbow/ANSI line-drawing character set to display the dungeon/effects/traps instead of having to define a full graphics set yourself (default off). This option also sets up proper handling of graphics characters for such terminals, so you should specify it when appropriate even if you override the selections with your own graphics strings. %.lp \item[\ib{disclose}] Controls options for disclosing various information when the game ends (defaults to all possibilities being disclosed). The possibilities are: %.sd %.si {\tt i} --- disclose your inventory.\\ {\tt a} --- disclose your attributes.\\ {\tt v} --- summarize monsters that have been vanquished.\\ {\tt g} --- list monster species that have been genocided.\\ {\tt c} --- display your conduct. %.ei %.ed Each disclosure possibility can optionally be preceded by a prefix which let you refine how it behaves. Here are the valid prefixes: %.sd %.si {\tt y} --- prompt you and default to yes on the prompt.\\ {\tt n} --- prompt you and default to no on the prompt.\\ {\tt +} --- disclose it without prompting.\\ {\tt -} --- do not disclose it and do not prompt. %.ei %.ed (ex.\ ``{\tt disclose:yi na +v -g -c}'') The example sets {\it inventory\/} to {\it prompt\/} and default to {\it yes\/}, {\it attributes\/} to {\it prompt\/} and default to {\it no\/}, {\it vanquished\/} to {\it disclose without prompting\/}, {\it genocided\/} to {\it not disclose\/} and not to {\it prompt\/}, and {\it conduct\/} to {\it not disclose\/} and not to {\it prompt\/}. Note that the vanquished monsters list includes all monsters killed by traps and each other as well as by you. %.lp \item[\ib{dogname}] Name your starting dog (ex.\ ``{\tt dogname:Fang}''). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{dungeon}] Set the graphics symbols for displaying the dungeon (default ``\verb& |--------||.-|++##& \verb&.##<><>_|\\#{}.}..## #}&''). The {\it dungeon\/} option should be followed by a string of 1--41 characters to be used instead of the default map-drawing characters. The dungeon map will use the characters you specify instead of the default symbols, and default symbols for any you do not specify. Remember that you may need to escape some of these characters on a command line if they are special to your shell. Note that {\it NetHack\/} escape-processes this option string in conventional C fashion. This means that `\verb+\+' is a prefix to take the following character literally. Thus `\verb+\+' needs to be represented as `\verb+\\+'. The special escape form `\verb+\m+' switches on the meta bit in the following character, and the `{\tt \^{}}' prefix causes the following character to be treated as a control character. The order of the symbols is: solid rock, vertical wall, horizontal wall, upper left corner, upper right corner, lower left corner, lower right corner, cross wall, upward T wall, downward T wall, leftward T wall, rightward T wall, no door, vertical open door, horizontal open door, vertical closed door, horizontal closed door, iron bars, tree, floor of a room, dark corridor, lit corridor, stairs up, stairs down, ladder up, ladder down, altar, grave, throne, kitchen sink, fountain, pool or moat, ice, lava, vertical lowered drawbridge, horizontal lowered drawbridge, vertical raised drawbridge, horizontal raised drawbridge, air, cloud, under water. You might want to use `{\tt +}' for the corners and T walls for a more aesthetic, boxier display. Note that in the next release, new symbols may be added, or the present ones rearranged. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{effects}] Set the graphics symbols for displaying special effects (default ``\verb&|-\\/*!)(0#@*/-\\& \verb&||\\-//-\\| |\\-/&''). The {\it effects\/} option should be followed by a string of 1--29 characters to be used instead of the default special-effects characters. This string is subjected to the same processing as the {\it dungeon\/} option. The order of the symbols is: vertical beam, horizontal beam, left slant, right slant, digging beam, camera flash beam, left boomerang, right boomerang, four glyphs giving the sequence for magic resistance displays, the eight surrounding glyphs for swallowed display, nine glyphs for explosions. An explosion consists of three rows (top, middle, and bottom) of three characters. The explosion is centered in the center of this $3 \times 3$ array. Note that in the next release, new symbols may be added, or the present ones rearranged. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{extmenu}] Changes the extended commands interface to pop-up a menu of available commands. It is keystroke compatible with the traditional interface except that it does not require that you hit Enter. It is implemented only by the tty port (default off), when the game has been compiled to support tty graphics. %.lp \item[\ib{female}] An obsolete synonym for ``{\tt gender:female}''. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{fixinv}] An object's inventory letter sticks to it when it's dropped (default on). If this is off, dropping an object shifts all the remaining inventory letters. %.lp \item[\ib{fruit}] Name a fruit after something you enjoy eating (ex.\ ``{\tt fruit:mango}'') (default ``{\tt slime mold}''). Basically a nostalgic whimsy that {\it NetHack\/} uses from time to time. You should set this to something you find more appetizing than slime mold. Apples, oranges, pears, bananas, and melons already exist in {\it NetHack}, so don't use those. %.Ip \item[\ib{gender}] Your starting gender ({\tt gender:male} or {\tt gender:female}). You may specify just the first letter. Although you can still denote your gender using the ``{\tt male}'' and ``{\tt female}'' options, the ``{\tt gender}'' option will take precedence. The default is to randomly pick an appropriate gender. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{help}] If more information is available for an object looked at with the `{\tt /}' command, ask if you want to see it (default on). Turning help off makes just looking at things faster, since you aren't interrupted with the ``{\tt More info?}'' prompt, but it also means that you might miss some interesting and/or important information. %.lp \item[\ib{horsename}] Name your starting horse (ex.\ ``{\tt horsename:Trigger}''). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{IBMgraphics}] Use a predefined selection of IBM extended ASCII characters to display the dungeon/effects/traps instead of having to define a full graphics set yourself (default off). This option also sets up proper handling of graphics characters for such terminals, so you should specify it when appropriate even if you override the selections with your own graphics strings. %.lp \item[\ib{ignintr}] Ignore interrupt signals, including breaks (default off). %.lp \item[\ib{legacy}] Display an introductory message when starting the game (default on). %.lp \item[\ib{lit\_corridor}] Show corridor squares seen by night vision or a light source held by your character as lit (default off). %.lp \item[\ib{lootabc}] Use the old `{\tt a}', `{\tt b}', and `{\tt c}' keyboard shortcuts when looting, rather than the mnemonics `{\tt o}', `{\tt i}', and `{\tt b}' (default off). %.lp \item[\ib{mail}] Enable mail delivery during the game (default on). %.lp \item[\ib{male}] An obsolete synonym for ``{\tt gender:male}''. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{menustyle}] Controls the interface used when you need to choose various objects (in response to the Drop command, for instance). The value specified should be the first letter of one of the following: traditional, combination, partial, or full. Traditional was the only interface available for earlier versions; it consists of a prompt for object class characters, followed by an object-by-object prompt for all items matching the selected object class(es). Combination starts with a prompt for object class(es) of interest, but then displays a menu of matching objects rather than prompting one-by-one. Partial skips the object class filtering and immediately displays a menu of all objects. Full displays a menu of object classes rather than a character prompt, and then a menu of matching objects for selection. \item[\ib{menu\_deselect\_all}] Menu character accelerator to deselect all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default `-'. \item[\ib{menu\_deselect\_page}] Menu character accelerator to deselect all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default `\verb+\+'. \item[\ib{menu\_first\_page}] Menu character accelerator to jump to the first page in a menu. Implemented by the Amiga, Gem and tty ports. Default `\verb+^+'. \item[\ib{menu\_headings}] Controls how the headings in a menu are highlighted. Values are ``{\tt bold}'', ``{\tt inverse}'', or ``{\tt underline}''. Not all ports can actually display all three types. \item[\ib{menu\_invert\_all}] Menu character accelerator to invert all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default `@'. \item[\ib{menu\_invert\_page}] Menu character accelerator to invert all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default `\verb+~+'. \item[\ib{menu\_last\_page}] Menu character accelerator to jump to the last page in a menu. Implemented by the Amiga, Gem and tty ports. Default `\verb+|+'. \item[\ib{menu\_next\_page}] Menu character accelerator to goto the next menu page. Implemented by the Amiga, Gem and tty ports. Default `\verb+>+'. \item[\ib{menu\_previous\_page}] Menu character accelerator to goto the previous menu page. Implemented by the Amiga, Gem and tty ports. Default `\verb+<+'. \item[\ib{menu\_search}] Menu character accelerator to search for a menu item. Implemented by the Amiga, Gem and X11 ports. Default `:'. \item[\ib{menu\_select\_all}] Menu character accelerator to select all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default `.'. \item[\ib{menu\_select\_page}] Menu character accelerator to select all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default `,'. %.lp \item[\ib{monsters}] Set the characters used to display monster classes (default ``\verb+abcdefghijklmnopqrstuv+ \verb+wxyzABCDEFGHIJKLMNOPQRSTUVWXYZ@ '&;:~]+''). This string is subjected to the same processing as the {\it dungeon\/} option. The order of the symbols is ant or other insect, blob, cockatrice, dog or other canine, eye or sphere, feline, gremlin, humanoid, imp or minor demon, jelly, kobold, leprechaun, mimic, nymph, orc, piercer, quadruped, rodent, arachnid or centipede, trapper or lurker above, horse or unicorn, vortex, worm, xan or other mythical/fantastic insect, light, zruty, angelic being, bat or bird, centaur, dragon, elemental, fungus or mold, gnome, giant humanoid, invisible monster, jabberwock, Keystone Kop, lich, mummy, naga, ogre, pudding or ooze, quantum mechanic, rust monster, snake, troll, umber hulk, vampire, wraith, xorn, apelike creature, zombie, human, ghost, golem, demon, sea monster, lizard, long worm tail, and mimic. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{msghistory}] The number of top line messages to save (and recall with `{\tt \^{}P}') (default 20). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{msg\_window}] Allows you to change the way recalled messages are displayed. (It is currently implemented for tty only.) The possible values are: %.sd %.si {\tt s} --- single message (default, this was the behavior before 3.4.0).\\ {\tt c} --- combination, two messages as {\it single\/}, then as {\it full\/}.\\ {\tt f} --- full window, oldest message first.\\ {\tt r} --- full window, newest message first. %.ei %.ed For backward compatibility, no value needs to be specified (which defaults to {\it full\/}), or it can be negated (which defaults to {\it single\/}). %.lp \item[\ib{name}] Set your character's name (defaults to your user name). You can also set your character's role by appending a dash and one or more letters of the role (that is, by suffixing one of ``{\tt -A -B -C -H -K -M -P -Ra -Ro -S -T -V -W}''). If ``{\tt -@}'' is used for the role, then a random one will be automatically chosen. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{news}] Read the {\it NetHack\/} news file, if present (default on). Since the news is shown at the beginning of the game, there's no point in setting this with the `{\tt O}' command. %.lp \item[\ib{null}] Send padding nulls to the terminal (default off). %.lp \item[\ib{number\_pad}] Use the number keys to move instead of {\tt [yuhjklbn]} (default 0 or off). (number\_pad:2 invokes the old DOS behavior where `{\tt 5}' means `{\tt g}', meta-`{\tt 5}' means `{\tt G}', and meta-`{\tt 0}' means `{\tt I}'.) %.lp \item[\ib{objects}] Set the characters used to display object classes (default ``\verb&])[="(%!?+/$*`0_.&''). This string is subjected to the same processing as the {\it dungeon\/} option. The order of the symbols is illegal-object (should never be seen), weapon, armor, ring, amulet, tool, food, potion, scroll, spellbook, wand, gold, gem or rock, boulder or statue, iron ball, chain, and venom. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{packorder}] Specify the order to list object types in (default ``\verb&")[%?+!=/(*`0_&''). The value of this option should be a string containing the symbols for the various object types. Any omitted types are filled in at the end from the previous order. %.lp \item[\ib{perm\_invent}] If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that implement this feature. %.lp \item[\ib{pettype}] Specify the type of your initial pet, if you are playing a character class that uses multiple types of pets; or choose to have no initial pet at all. Possible values are ``{\tt cat}'', ``{\tt dog}'' and ``{\tt none}''. Cannot be set with the `{\tt O}' command. %.Ip \item[\ib{pickup\_burden}] When you pick up an item that would exceed this encumbrance level (Unburdened, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. (Default `S'). %.lp \item[\ib{pickup\_types}] Specify the object types to be picked up when ``{\it autopickup\/}'' is on. Default is all types. If your copy of the game has the experimental compile time option AUTOPICKUP\_EXCEPTIONS included, you may be able to use ``{\it autopickup\_exception\/}'' configuration file lines to further refine ``{\it autopickup\/}'' behavior. %.lp \item[\ib{prayconfirm}] Prompt for confirmation before praying (default on). %.lp \item[\ib{pushweapon}] Using the `w' (wield) command when already wielding something pushes the old item into your alternate weapon slot (default off). %.Ip \item[\ib{race}] Selects your race (for example, ``{\tt race:human}''). Default is random. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{rest\_on\_space}] Make the space bar a synonym for the `{\tt .}' (rest) command (default off). %.lp \item[\ib{role}] Pick your type of character (ex.\ ``{\tt role:Samurai}''); synonym for ``{\it character\/}''. See ``{\it name\/}'' for an alternate method of specifying your role. Normally only the first letter of the value is examined; `r' is an exception with ``{\tt Rogue}'', {\tt Ranger}'', and ``{\tt random}'' values. %.lp \item[\ib{runmode}] Controls the amount of screen updating for the map window when engaged in multi-turn movement (running via {\tt shift}+direction or {\tt control}+direction and so forth, or via the travel command or mouse click). The possible values are: %.sd %.si {\tt teleport} --- update the map after movement has finished;\\ {\tt run} --- update the map after every seven or so steps;\\ {\tt walk} --- update the map after each step;\\ {\tt crawl} --- like {\it walk\/}, but pause briefly after each step. %.ei %.ed This option only affects the game's screen display, not the actual results of moving. The default is {\it run\/}; versions prior to 3.4.1 used {\it teleport\/} only. Whether or not the effect is noticeable will depend upon the window port used or on the type of terminal. %.lp \item[\ib{safe\_pet}] Prevent you from (knowingly) attacking your pets (default on). %.lp \item[\ib{scores}] Control what parts of the score list you are shown at the end (ex.\ ``{\tt scores:5top scores/4around my score/own scores}''). Only the first letter of each category (`{\tt t}', `{\tt a}' or `{\tt o}') is necessary. %.lp \item[\ib{showexp}] Show your accumulated experience points on bottom line (default off). %.lp \item[\ib{showrace}] Display yourself as the glyph for your race, rather than the glyph for your role (default off). Note that this setting affects only the appearance of the display, not the way the game treats you. %.lp \item[\ib{showscore}] Show your approximate accumulated score on bottom line (default off). %.lp \item[\ib{silent}] Suppress terminal beeps (default on). %.lp \item[\ib{sortpack}] Sort the pack contents by type when displaying inventory (default on). %.lp \item[\ib{sound}] Enable messages about what your character hears (default on). Note that this has nothing to do with your computer's audio capabilities. This option is only partly under player control. The game toggles it off and on during and after sleep, for example. %.lp \item[\ib{standout}] Boldface monsters and ``{\tt --More--}'' (default off). %.lp \item[\ib{sparkle}] Display a sparkly effect when a monster (including yourself) is hit by an attack to which it is resistant (default on). %.lp \item[\ib{suppress\_alert}] This option may be set to a NetHack version level to suppress alert notification messages about feature changes for that and prior versions (ex.\ ``{\tt suppress\_alert:3.3.1}'') %.lp \item[\ib{time}] Show the elapsed game time in turns on bottom line (default off). %.lp \item[\ib{timed\_delay}] When pausing momentarily for display effect, such as with explosions and moving objects, use a timer rather than sending extra characters to the screen. (Applies to ``tty'' interface only; ``X11'' interface always uses a timer based delay. The default is on if configured into the program.) %.lp \item[\ib{tombstone}] Draw a tombstone graphic upon your death (default on). %.lp \item[\ib{toptenwin}] Put the ending display in a NetHack window instead of on stdout (default off). Setting this option makes the score list visible when a windowing version of NetHack is started without a parent window, but it no longer leaves the score list around after game end on a terminal or emulating window. %.lp \item[\ib{traps}] Set the graphics symbols for displaying traps (default ``\verb&^^^^^^^^^^^^^^^^^"^^^^&''). The {\it traps\/} option should be followed by a string of 1--22 characters to be used instead of the default traps characters. This string is subjected to the same processing as the {\it dungeon\/} option. The order of the symbols is: arrow trap, dart trap, falling rock trap, squeaky board, bear trap, land mine, rolling boulder trap, sleeping gas trap, rust trap, fire trap, pit, spiked pit, hole, trap door, teleportation trap, level teleporter, magic portal, web, statue trap, magic trap, anti-magic field, polymorph trap. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{travel}] Allow the travel command (default on). Turning this option off will prevent the game from attempting unintended moves if you make inadvertent mouse clicks on the map window. %.lp \item[\ib{verbose}] Provide more commentary during the game (default on). %.lp \item[\ib{windowtype}] Select which windowing system to use, such as ``{\tt tty}'' or ``{\tt X11}'' (default depends on version). Cannot be set with the `{\tt O}' command. \elist %.hn 2 \subsection*{Window Port Customization options} %.pg Here are explanations of the various options that are used to customize and change the characteristics of the windowtype that you have chosen. Character strings that are too long may be truncated. Not all window ports will adjust for all settings listed here. You can safely add any of these options to your config file, and if the window port is capable of adjusting to suit your preferences, it will attempt to do so. If it can't it will silently ignore it. You can find out if an option is supported by the window port that you are currently using by checking to see if it shows up in the Options list. Some options are dynamic and can be specified during the game with the `{\tt O}' command. \blist{} %.lp \item[\ib{align\_message}] Where to align or place the message window (top, bottom, left, or right) %.lp \item[\ib{align\_status}] Where to align or place the status window (top, bottom, left, or right). %.lp \item[\ib{ascii\_map}] NetHack should display an ascii map if it can. %.lp \item[\ib{color}] NetHack should display color if it can for different monsters, objects, and dungeon features %.lp \item[\ib{eight\_bit\_tty}] Pass eight-bit character values (for example, specified with the {\it traps \/} option) straight through to your terminal (default off). %.lp \item[\ib{font\_map}] NetHack should use a font by the chosen name for the map window. %.lp \item[\ib{font\_menu}] NetHack should use a font by the chosen name for menu windows. %.lp \item[\ib{font\_message}] NetHack should use a font by the chosen name for the message window. %.lp \item[\ib{font\_status}] NetHack should use a font by the chosen name for the status window. %.lp \item[\ib{font\_text}] NetHack should use a font by the chosen name for text windows. %.lp \item[\ib{font\_size\_map}] NetHack should use this size font for the map window. %.lp \item[\ib{font\_size\_menu}] NetHack should use this size font for menu windows. %.lp \item[\ib{font\_size\_message}] NetHack should use this size font for the message window. %.lp \item[\ib{font\_size\_status}] NetHack should use this size font for the status window. %.lp \item[\ib{font\_size\_text}] NetHack should use this size font for text windows. %.lp \item[\ib{fullscreen}] NetHack should try and display on the entire screen rather than in a window. %.lp \item[\ib{hilite\_pet}] Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a heart symbol near pets. %.lp \item[\ib{large\_font}] NetHack should use a large font. %.lp \item[\ib{map\_mode}] NetHack should display the map in the manner specified. %.lp \item[\ib{mouse\_support}] Allow use of the mouse for input and travel. %.lp \item[\ib{player\_selection}] NetHack should pop up dialog boxes or use prompts for character selection. %.lp \item[\ib{popup\_dialog}] NetHack should pop up dialog boxes for input. %.lp \item[\ib{preload\_tiles}] NetHack should preload tiles into memory. For example, in the protected mode MSDOS version, control whether tiles get pre-loaded into RAM at the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. (default on). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{scroll\_amount}] NetHack should scroll the display by this number of cells when the hero reaches the scroll\_margin. %.lp \item[\ib{scroll\_margin}] NetHack should scroll the display when the hero or cursor is this number of cells away from the edge of the window. %.lp \item[\ib{softkeyboard}] Display an onscreen keyboard. Handhelds are most likely to support this option. %.lp \item[\ib{splash\_screen}] NetHack should display an opening splash screen when it starts up (default yes). %.lp \item[\ib{tiled\_map}] NetHack should display a tiled map if it can. %.lp \item[\ib{tile\_file}] Specify the name of an alternative tile file to override the default. %.lp \item[\ib{tile\_height}] Specify the preferred height of each tile in a tile capable port. %.lp \item[\ib{tile\_width}] Specify the preferred width of each tile in a tile capable port %.lp \item[\ib{use\_inverse}] NetHack should display inverse when the game specifies it. %.lp \item[\ib{vary\_msgcount}] NetHack should display this number of messages at a time in the message window. %.lp \item[\ib{windowcolors}] NetHack should display windows with the specified foreground/background colors if it can. %.lp \item[\ib{wraptext}] NetHack port should wrap long lines of text if they don't fit in the visible area of the window. \elist %.hn 2 \subsection*{Platform-specific Customization options} %.pg Here are explanations of options that are used by specific platforms or ports to customize and change the port behavior. \blist{} %.lp \item[\ib{altkeyhandler}] Select an alternate keystroke handler dll to load ({\it Win32 tty\/ NetHack\/} only). The name of the handler is specified without the .dll extension and without any path information. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{altmeta}] (default on, {\it Amiga NetHack \/} only). %.lp \item[\ib{BIOS}] Use BIOS calls to update the screen display quickly and to read the keyboard (allowing the use of arrow keys to move) on machines with an IBM PC compatible BIOS ROM (default off, {\it OS/2, PC\/ {\rm and} ST NetHack\/} only). %.lp \item[\ib{flush}] (default off, {\it Amiga NetHack \/} only). %.lp \item[\ib{Macgraphics}] (default on, {\it Mac NetHack \/} only). %.lp \item[\ib{page\_wait}] (default off, {\it Mac NetHack \/} only). %.lp \item[\ib{rawio}] Force raw (non-cbreak) mode for faster output and more bulletproof input (MS-DOS sometimes treats `{\tt \^{}P}' as a printer toggle without it) (default off, {\it OS/2, PC\/ {\rm and} ST NetHack\/} only). Note: DEC Rainbows hang if this is turned on. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{soundcard}] (default off, {\it PC NetHack \/} only). Cannot be set with the `{\tt O}' command. %.lp \item[\ib{subkeyvalue}] ({\it Win32 tty NetHack \/} only). May be used to alter the value of keystrokes that the operating system returns to NetHack to help compensate for international keyboard issues. OPTIONS=subkeyvalue:171/92 will return 92 to NetHack, if 171 was originally going to be returned. You can use multiple subkeyvalue statements in the config file if needed. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{video}] Set the video mode used ({\it PC\/ NetHack\/} only). Values are {\it autodetect\/}, {\it default\/}, or {\it vga\/}. Setting {\it vga\/} (or {\it autodetect\/} with vga hardware present) will cause the game to display tiles. Cannot be set with the `{\tt O}' command. %.lp \item[\ib{videocolors}] \begin{sloppypar} Set the color palette for PC systems using NO\_TERMS (default 4-2-6-1-5-3-15-12-10-14-9-13-11, {\it PC\/ NetHack\/} only). The order of colors is red, green, brown, blue, magenta, cyan, bright.white, bright.red, bright.green, yellow, bright.blue, bright.magenta, and bright.cyan. Cannot be set with the `{\tt O}' command. \end{sloppypar} %.lp \item[\ib{videoshades}] Set the intensity level of the three gray scales available (default dark normal light, {\it PC\/ NetHack\/} only). If the game display is difficult to read, try adjusting these scales; if this does not correct the problem, try {\tt !color}. Cannot be set with the `{\tt O}' command. \elist %.lp %.hn 2 \subsection*{Configuring autopickup exceptions} %.pg There is an experimental compile time option called AUTOPICKUP_EXCEPTIONS. If your copy of the game was built with that option defined, you can further refine the behavior of the ``{\tt autopickup}'' option beyond what is available through the ``{\tt pickup\_types}'' option. %.pg By placing ``{\tt autopickup\_exception}'' lines in your configuration file, you can define patterns to be checked when the game is about to autopickup something. \blist{} %.lp \item[\ib{autopickup\_exception}] Sets an exception to the `{\it pickup\_types}' option. The {\it autopickup\_exception\/} option should be followed by a string of 1--80 characters to be used as a pattern to match against the singular form of the description of an object at your location. %.pg You may use the following special characters in a pattern: \begin{verbatim} *--- matches 0 or more characters. ?--- matches any single character. \end{verbatim} In addition, some characters are treated specially if they occur as the first character in the specified string pattern, specifically: %.sd %.si {\tt <} --- always pickup an object that matches the pattern that follows.\\ {\tt >} --- never pickup an object that matches the pattern that follows. %.ei %.ed Can be set with the `{\tt O}' command, but the setting is not preserved across saves and restores. \elist %.pg Here's a couple of examples of autopickup\_exceptions: \begin{verbatim} autopickup_exception="<*arrow" autopickup_exception=">*corpse" autopickup_exception=">* cursed*" \end{verbatim} The first example above will result in autopickup of any type of arrow. The second example results in the exclusion of any corpse from autopickup. The last example results in the exclusion of items known to be cursed from autopickup. A `never pickup' rule takes precedence over an `always pickup' rule if both match. %.lp %.hn 2 \subsection*{Configuring User Sounds} %.pg Some platforms allow you to define sound files to be played when a message that matches a user-defined pattern is delivered to the message window. At this time the Qt port and the win32tty and win32gui ports support the use of user sounds. %.pg The following config file entries are relevant to mapping user sounds to messages: \blist{} %.lp \item[\ib{SOUNDDIR}] The directory that houses the sound files to be played. %.lp \item[\ib{SOUND}] An entry that maps a sound file to a user-specified message pattern. Each SOUND entry is broken down into the following parts: %.sd %.si {\tt MESG } --- message window mapping (the only one supported in 3.4).\\ {\tt pattern } --- the pattern to match.\\ {\tt sound file} --- the sound file to play.\\ {\tt volume } --- the volume to be set while playing the sound file. %.ei %.ed \elist %.pg The exact format for the pattern depends on whether the platform is built to use {\it regular expressions \/} or NetHack's own internal pattern matching facility. The {\it regular expressions \/} matching can be much more sophisticated than the internal NetHack pattern matching, but requires 3rd party libraries on some platforms. There are plenty of references available elsewhere for explaining {\it regular expressions \/}. You can verify which pattern matching is used by your port with the \#version command. %.pg NetHack's internal pattern matching routine uses the following special characters in its pattern matching: \begin{verbatim} *--- matches 0 or more characters. ?--- matches any single character. \end{verbatim} %.pg Here's an example of a sound mapping using NetHack's internal pattern matching facility: \begin{verbatim} SOUND=MESG "*chime of a cash register*" "gong.wav" 50 \end{verbatim} specifies that any message with "chime of a cash register" contained in it will trigger the playing of "gong.wav". You can have multiple SOUND entries in your config file. %.lp %.hn 2 \subsection*{Configuring NetHack for Play by the Blind} %.pg NetHack can be set up to use only standard ASCII characters for making maps of the dungeons. This makes the MS-DOS versions of NetHack completely accessible to the blind who use speech and/or Braille access technologies. Players will require a good working knowledge of their screen-reader's review features, and will have to know how to navigate horizontally and vertically character by character. They will also find the search capabilities of their screen-readers to be quite valuable. Be certain to examine this Guidebook before playing so you have an idea what the screen layout is like. You'll also need to be able to locate the PC cursor. It is always where your character is located. Merely searching for an @-sign will not always find your character since there are other humanoids represented by the same sign. Your screen-reader should also have a function which gives you the row and column of your review cursor and the PC cursor. These co-ordinates are often useful in giving players a better sense of the overall location of items on the screen. %.pg While it is not difficult for experienced users to edit the {\it defaults.nh\/} file to accomplish this, novices may find this task somewhat daunting. Included in all official distributions of NetHack is a file called {\it NHAccess.nh\/}. Replacing {\it defaults.nh\/} with this file will cause the game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings to better suit your preferences. Instructions on how to do this are included in the {\it NHAccess.nh\/} file itself. The most crucial settings to make the game accessible are: %.pg \blist{} %.lp \item[\ib{IBMgraphics}] Disable IBMgraphics by commenting out this option. %.lp \item[\ib{menustyle:traditional}] This will assist in the interface to speech synthesizers. %.lp \item[\ib{number\_pad}] A lot of speech access programs use the number-pad to review the screen. If this is the case, disable the number\_pad option and use the traditional Rogue-like commands. %.lp \item[\ib{Character graphics}] Comment out all character graphics sets found near the bottom of the {\it defaults.nh\/} file. Most of these replace {\it NetHack\/}'s default representation of the dungeon using standard ASCII characters with fancier characters from extended character sets, and these fancier characters can annoy screen-readers. \elist %.hn 1 \section{Scoring} %.pg {\it NetHack\/} maintains a list of the top scores or scorers on your machine, depending on how it is set up. In the latter case, each account on the machine can post only one non-winning score on this list. If you score higher than someone else on this list, or better your previous score, you will be inserted in the proper place under your current name. How many scores are kept can also be set up when {\it NetHack\/} is compiled. %.pg Your score is chiefly based upon how much experience you gained, how much loot you accumulated, how deep you explored, and how the game ended. If you quit the game, you escape with all of your gold intact. If, however, you get killed in the Mazes of Menace, the guild will only hear about 90\,\% of your gold when your corpse is discovered (adventurers have been known to collect finder's fees). So, consider whether you want to take one last hit at that monster and possibly live, or quit and stop with whatever you have. If you quit, you keep all your gold, but if you swing and live, you might find more. %.pg If you just want to see what the current top players/games list is, you can type \begin{verbatim} nethack -s all \end{verbatim} on most versions. %.hn 1 \section{Explore mode} %.pg {\it NetHack\/} is an intricate and difficult game. Novices might falter in fear, aware of their ignorance of the means to survive. Well, fear not. Your dungeon may come equipped with an ``explore'' or ``discovery'' mode that enables you to keep old save files and cheat death, at the paltry cost of not getting on the high score list. %.pg There are two ways of enabling explore mode. One is to start the game with the {\tt -X} switch. The other is to issue the `{\tt X}' command while already playing the game. The other benefits of explore mode are left for the trepid reader to discover. %.hn \section{Credits} %.pg The original % {\it hack\/} game was modeled on the Berkeley %.ux UNIX {\it rogue\/} game. Large portions of this paper were shamelessly cribbed from % {\it A Guide to the Dungeons of Doom}, by Michael C. Toy and Kenneth C. R. C. Arnold. Small portions were adapted from {\it Further Exploration of the Dungeons of Doom}, by Ken Arromdee. %.pg {\it NetHack\/} is the product of literally dozens of people's work. Main events in the course of the game development are described below: %.pg \bigskip \nd {\it Jay Fenlason\/} wrote the original {\it Hack\/} with help from {\it Kenny Woodland}, {\it Mike Thome}, and {\it Jon Payne}. %.pg \medskip \nd {\it Andries Brouwer\/} did a major re-write, transforming {\it Hack\/} into a very different game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for UNIX machines to the Usenet. %.pg \medskip \nd {\it Don G. Kneller\/} ported {\it Hack\/} 1.0.3 to Microsoft C and MS-DOS, producing {\it PC Hack\/} 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went on to produce at least four more versions (3.0, 3.2, 3.51, and 3.6). %.pg \medskip \nd {\it R. Black\/} ported {\it PC Hack\/} 3.51 to Lattice C and the Atari 520/1040ST, producing {\it ST Hack\/} 1.03. %.pg \medskip \nd {\it Mike Stephenson\/} merged these various versions back together, incorporating many of the added features, and produced {\it NetHack\/} version 1.4. He then coordinated a cast of thousands in enhancing and debugging {\it NetHack\/} 1.4 and released {\it NetHack\/} versions 2.2 and 2.3. %.pg \medskip \nd Later, Mike coordinated a major rewrite of the game, heading a team which included {\it Ken Arromdee}, {\it Jean-Christophe Collet}, {\it Steve Creps}, {\it Eric Hendrickson}, {\it Izchak Miller}, {\it Eric S. Raymond}, {\it John Rupley}, {\it Mike Threepoint}, and {\it Janet Walz}, to produce {\it NetHack\/} 3.0c. %.pg \medskip \nd {\it NetHack\/} 3.0 was ported to the Atari by {\it Eric R. Smith}, to OS/2 by {\it Timo Hakulinen}, and to VMS by {\it David Gentzel}. The three of them and {\it Kevin Darcy\/} later joined the main development team to produce subsequent revisions of 3.0. %.pg \medskip \nd {\it Olaf Seibert\/} ported {\it NetHack\/} 2.3 and 3.0 to the Amiga. {\it Norm Meluch}, {\it Stephen Spackman\/} and {\it Pierre Martineau\/} designed overlay code for {\it PC NetHack\/} 3.0. {\it Johnny Lee\/} ported {\it NetHack\/} 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. %.pg \medskip \nd Headed by {\it Mike Stephenson\/} and coordinated by {\it Izchak Miller\/} and {\it Janet Walz}, the development team which now included {\it Ken Arromdee}, {\it David Cohrs}, {\it Jean-Christophe Collet}, {\it Kevin Darcy}, {\it Matt Day}, {\it Timo Hakulinen}, {\it Steve Linhart}, {\it Dean Luick}, {\it Pat Rankin}, {\it Eric Raymond}, and {\it Eric Smith\/} undertook a radical revision of 3.0. They re-structured the game's design, and re-wrote major parts of the code. They added multiple dungeons, a new display, special individual character quests, a new endgame and many other new features, and produced {\it NetHack\/} 3.1. %.pg \medskip \nd {\it Ken Lorber}, {\it Gregg Wonderly\/} and {\it Greg Olson}, with help from {\it Richard Addison}, {\it Mike Passaretti}, and {\it Olaf Seibert}, developed {\it NetHack\/} 3.1 for the Amiga. %.pg \medskip \nd {\it Norm Meluch\/} and {\it Kevin Smolkowski}, with help from {\it Carl Schelin}, {\it Stephen Spackman}, {\it Steve VanDevender}, and {\it Paul Winner}, ported {\it NetHack\/} 3.1 to the PC. %.pg \medskip \nd {\it Jon W\{tte} and {\it Hao-yang Wang}, with help from {\it Ross Brown}, {\it Mike Engber}, {\it David Hairston}, {\it Michael Hamel}, {\it Jonathan Handler}, {\it Johnny Lee}, {\it Tim Lennan}, {\it Rob Menke}, and {\it Andy Swanson}, developed {\it NetHack\/} 3.1 for the Macintosh, porting it for MPW. Building on their development, {\it Barton House} added a Think C port. %.pg \medskip \nd {\it Timo Hakulinen\/} ported {\it NetHack\/} 3.1 to OS/2. {\it Eric Smith\/} ported {\it NetHack\/} 3.1 to the Atari. {\it Pat Rankin}, with help from {\it Joshua Delahunty}, was responsible for the VMS version of {\it NetHack\/} 3.1. {\it Michael Allison} ported {\it NetHack\/} 3.1 to Windows NT. %.pg \medskip \nd {\it Dean Luick}, with help from {\it David Cohrs}, developed {\it NetHack\/} 3.1 for X11. {\it Warwick Allison} wrote a tiled version of NetHack for the Atari; he later contributed the tiles to the DevTeam and tile support was then added to other platforms. %.pg \medskip \nd The 3.2 development team, comprised of {\it Michael Allison}, {\it Ken Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Steve Creps}, {\it Kevin Darcy}, {\it Timo Hakulinen}, {\it Steve Linhart}, {\it Dean Luick}, {\it Pat Rankin}, {\it Eric Smith}, {\it Mike Stephenson}, {\it Janet Walz}, and {\it Paul Winner}, released version 3.2 in April of 1996. %.pg \medskip \nd Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all thirteen members of the original development team remained on the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2, one of the founding members of the development team, {\it Dr. Izchak Miller}, was diagnosed with cancer and passed away. That release of the game was dedicated to him by the development and porting teams. %.pg \medskip During the lifespan of {\it NetHack\/} 3.1 and 3.2, several enthusiasts of the game added their own modifications to the game and made these ``variants'' publicly available: %.pg \medskip {\it Tom Proudfoot} and {\it Yuval Oren} created {\it NetHack++}, which was quickly renamed {\it NetHack$--$}. Working independently, {\it Stephen White} wrote {\it NetHack Plus}. {\it Tom Proudfoot} later merged {\it NetHack Plus} and his own {\it NetHack$--$} to produce {\it SLASH}. {\it Larry Stewart-Zerba} and {\it Warwick Allison} improved the spell casting system with the Wizard Patch. {\it Warwick Allison} also ported NetHack to use the Qt interface. %.pg \medskip {\it Warren Cheung} combined {\it SLASH} with the Wizard Patch to produce {\it Slash'em\/}, and with the help of {\it Kevin Hugo}, added more features. Kevin later joined the DevTeam and incorporated the best of these ideas into NetHack 3.3. %.pg \medskip The final update to 3.2 was the bug fix release 3.2.3, which was released simultaneously with 3.3.0 in December 1999 just in time for the Year 2000. %.pg \medskip The 3.3 development team, consisting of {\it Michael Allison}, {\it Ken Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Steve Creps}, {\it Kevin Darcy}, {\it Timo Hakulinen}, {\it Kevin Hugo}, {\it Steve Linhart}, {\it Ken Lorber}, {\it Dean Luick}, {\it Pat Rankin}, {\it Eric Smith}, {\it Mike Stephenson}, {\it Janet Walz}, and {\it Paul Winner}, released 3.3.0 in December 1999 and 3.3.1 in August of 2000. %.pg \medskip Version 3.3 offered many firsts. It was the first version to separate race and profession. The Elf class was removed in preference to an elf race, and the races of dwarves, gnomes, and orcs made their first appearance in the game alongside the familiar human race. Monk and Ranger roles joined Archeologists, Barbarians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, Wizards. It was also the first version to allow you to ride a steed, and was the first version to have a publicly available web-site listing all the bugs that had been discovered. Despite that constantly growing bug list, 3.3 proved stable enough to last for more than a year and a half. %.pg \medskip The 3.4 development team initially consisted of {\it Michael Allison}, {\it Ken Arromdee}, {\it David Cohrs}, {\it Jessie Collet}, {\it Kevin Hugo}, {\it Ken Lorber}, {\it Dean Luick}, {\it Pat Rankin}, {\it Mike Stephenson}, {\it Janet Walz}, and {\it Paul Winner}, with {\it Warwick Allison} joining just before the release of NetHack 3.4.0 in March 2002. %.pg \medskip As with version 3.3, various people contributed to the game as a whole as well as supporting ports on the different platforms that {\it NetHack\/} runs on: %.pg \medskip \nd{\it Pat Rankin} maintained 3.4 for VMS. %.pg \medskip \nd {\it Michael Allison} maintained NetHack 3.4 for the MS-DOS platform. {\it Paul Winner} and {\it Yitzhak Sapir} provided encouragement. %.pg \medskip \nd {\it Dean Luick}, {\it Mark Modrall}, and {\it Kevin Hugo} maintained and enhanced the Macintosh port of 3.4. %.pg \medskip \nd {\it Michael Allison}, {\it David Cohrs}, {\it Alex Kompel}, {\it Dion Nicolaas}, and {\it Yitzhak Sapir} maintained and enhanced 3.4 for the Microsoft Windows platform. {\it Alex Kompel} contributed a new graphical interface for the Windows port. {\it Alex Kompel} also contributed a Windows CE port for 3.4.1. %.pg \medskip \nd {\it Ron Van Iwaarden} maintained 3.4 for OS/2. %.pg \medskip \nd {\it Janne Salmij\"{a}rvi} and {\it Teemu Suikki} maintained and enhanced the Amiga port of 3.4 after {\it Janne Salmij\"{a}rvi} resurrected it for 3.3.1. %.pg \medskip \nd {\it Christian ``Marvin'' Bressler} maintained 3.4 for the Atari after he resurrected it for 3.3.1. %.pg \medskip \nd There is a NetHack web site maintained by {\it Ken Lorber} at http:{\tt /}{\tt /}www.nethack.org{\tt /}. %.pg \bigskip \nd From time to time, some depraved individual out there in netland sends a particularly intriguing modification to help out with the game. The Gods of the Dungeon sometimes make note of the names of the worst of these miscreants in this, the list of Dungeoneers: %.sd \begin{center} \begin{tabular}{lll} %TABLE_START Adam Aronow & Izchak Miller & Mike Stephenson\\ Alex Kompel & J. Ali Harlow & Norm Meluch\\ Andreas Dorn & Janet Walz & Olaf Seibert\\ Andy Church & Janne Salmij\"{a}rvi & Pasi Kallinen\\ Andy Swanson & Jean-Christophe Collet & Pat Rankin\\ Ari Huttunen & Jochen Erwied & Paul Winner\\ Barton House & John Kallen & Pierre Martineau\\ Benson I. Margulies & John Rupley & Ralf Brown\\ Bill Dyer & John S. Bien & Ray Chason\\ Boudewijn Waijers & Johnny Lee & Richard Addison\\ Bruce Cox & Jon W\{tte & Richard Beigel\\ Bruce Holloway & Jonathan Handler & Richard P. Hughey\\ Bruce Mewborne & Joshua Delahunty & Rob Menke\\ Carl Schelin & Keizo Yamamoto & Robin Johnson\\ Chris Russo & Ken Arnold & Roderick Schertler\\ David Cohrs & Ken Arromdee & Roland McGrath\\ David Damerell & Ken Lorber & Ron Van Iwaarden\\ David Gentzel & Ken Washikita & Ronnen Miller\\ David Hairston & Kevin Darcy & Ross Brown\\ Dean Luick & Kevin Hugo & Sascha Wostmann\\ Del Lamb & Kevin Sitze & Scott Bigham\\ Deron Meranda & Kevin Smolkowski & Scott R. Turner\\ Dion Nicolaas & Kevin Sweet & Stephen Spackman\\ Dylan O'Donnell & Lars Huttar & Stephen White\\ Eric Backus & Malcolm Ryan & Steve Creps\\ Eric Hendrickson & Mark Gooderum & Steve Linhart\\ Eric R. Smith & Mark Modrall & Steve VanDevender\\ Eric S. Raymond & Marvin Bressler & Teemu Suikki\\ Erik Andersen & Matthew Day & Tim Lennan\\ Frederick Roeber & Merlyn LeRoy & Timo Hakulinen\\ Gil Neiger & Michael Allison & Tom Almy\\ Greg Laskin & Michael Feir & Tom West\\ Greg Olson & Michael Hamel & Warren Cheung\\ Gregg Wonderly & Michael Sokolov & Warwick Allison\\ Hao-yang Wang & Mike Engber & Yitzhak Sapir\\ Helge Hafting & Mike Gallop\\ Irina Rempt-Drijfhout & Mike Passaretti %TABLE_END Do not delete this line. \end{tabular} \end{center} %.ed %\vfill %\begin{flushleft} %\small %Microsoft and MS-DOS are registered trademarks of Microsoft Corporation.\\ %%%Don't need next line if a UNIX macro automatically inserts footnotes. %UNIX is a registered trademark of AT\&T.\\ %Lattice is a trademark of Lattice, Inc.\\ %Atari and 1040ST are trademarks of Atari, Inc.\\ %AMIGA is a trademark of Commodore-Amiga, Inc.\\ %%.sm %Brand and product names are trademarks or registered trademarks %of their respective holders. %\end{flushleft} \end{document} nethack-3.4.3/doc/Guidebook.txt0100644000000000000000000045143307764735041015102 0ustar rootroot A Guide to the Mazes of Menace (Guidebook for NetHack) Eric S. Raymond (Extensively edited and expanded for 3.4) 1. Introduction Recently, you have begun to find yourself unfulfilled and distant in your daily occupation. Strange dreams of prospecting, steal- ing, crusading, and combat have haunted you in your sleep for many months, but you aren't sure of the reason. You wonder whether you have in fact been having those dreams all your life, and somehow managed to forget about them until now. Some nights you awaken suddenly and cry out, terrified at the vivid recollec- tion of the strange and powerful creatures that seem to be lurk- ing behind every corner of the dungeon in your dream. Could these details haunting your dreams be real? As each night pass- es, you feel the desire to enter the mysterious caverns near the ruins grow stronger. Each morning, however, you quickly put the idea out of your head as you recall the tales of those who en- tered the caverns before you and did not return. Eventually you can resist the yearning to seek out the fantastic place in your dreams no longer. After all, when other adventurers came back this way after spending time in the caverns, they usually seemed better off than when they passed through the first time. And who was to say that all of those who did not return had not just kept going? Asking around, you hear about a bauble, called the Amulet of Yendor by some, which, if you can find it, will bring you great wealth. One legend you were told even mentioned that the one who finds the amulet will be granted immortality by the gods. The amulet is rumored to be somewhere beyond the Valley of Gehennom, deep within the Mazes of Menace. Upon hearing the legends, you immediately realize that there is some profound and undiscovered reason that you are to descend into the caverns and seek out that amulet of which they spoke. Even if the rumors of the amulet's powers are untrue, you decide that you should at least be able to sell the tales of your adventures to the local minstrels for a tidy sum, especially if you encounter any of the terrifying and magical creatures of your dreams along the way. You spend one last night fortifying yourself at the local inn, becoming more and more depressed as you watch the odds of your success being posted on the inn's walls getting lower and lower. NetHack Guidebook 1 NetHack Guidebook 2 In the morning you awake, collect your belongings, and set off for the dungeon. After several days of uneventful travel, you see the ancient ruins that mark the entrance to the Mazes of Menace. It is late at night, so you make camp at the entrance and spend the night sleeping under the open skies. In the morn- ing, you gather your gear, eat what may be your last meal out- side, and enter the dungeon... 2. What is going on here? You have just begun a game of NetHack. Your goal is to grab as much treasure as you can, retrieve the Amulet of Yendor, and escape the Mazes of Menace alive. Your abilities and strengths for dealing with the hazards of adventure will vary with your background and training: Archeologists understand dungeons pretty well; this enables them to move quickly and sneak up on the local nasties. They start equipped with the tools for a proper scientific expedition. Barbarians are warriors out of the hinterland, hardened to battle. They begin their quests with naught but uncommon strength, a trusty hauberk, and a great two-handed sword. Cavemen and Cavewomen start with exceptional strength but, unfortunately, with neolithic weapons. Healers are wise in medicine and apothecary. They know the herbs and simples that can restore vitality, ease pain, anes- thetize, and neutralize poisons; and with their instruments, they can divine a being's state of health or sickness. Their medical practice earns them quite reasonable amounts of money, with which they enter the dungeon. Knights are distinguished from the common skirmisher by their devotion to the ideals of chivalry and by the surpassing excellence of their armor. Monks are ascetics, who by rigorous practice of physical and mental disciplines have become capable of fighting as effectively without weapons as with. They wear no armor but make up for it with increased mobility. Priests and Priestesses are clerics militant, crusaders ad- vancing the cause of righteousness with arms, armor, and arts thaumaturgic. Their ability to commune with deities via prayer occasionally extricates them from peril, but can also put them in it. Rangers are most at home in the woods, and some say slightly out of place in a dungeon. They are, however, experts in archery as well as tracking and stealthy movement. NetHack 3.4 December 2, 2003 NetHack Guidebook 3 Rogues are agile and stealthy thieves, with knowledge of locks, traps, and poisons. Their advantage lies in surprise, which they employ to great advantage. Samurai are the elite warriors of feudal Nippon. They are lightly armored and quick, and wear the dai-sho, two swords of the deadliest keenness. Tourists start out with lots of gold (suitable for shopping with), a credit card, lots of food, some maps, and an expensive camera. Most monsters don't like being photographed. Valkyries are hardy warrior women. Their upbringing in the harsh Northlands makes them strong, inures them to extremes of cold, and instills in them stealth and cunning. Wizards start out with a knowledge of magic, a selection of magical items, and a particular affinity for dweomercraft. Al- though seemingly weak and easy to overcome at first sight, an ex- perienced Wizard is a deadly foe. You may also choose the race of your character: Dwarves are smaller than humans or elves, but are stocky and solid individuals. Dwarves' most notable trait is their great expertise in mining and metalwork. Dwarvish armor is said to be second in quality not even to the mithril armor of the Elves. Elves are agile, quick, and perceptive; very little of what goes on will escape an Elf. The quality of Elven craftsmanship often gives them an advantage in arms and armor. Gnomes are smaller than but generally similar to dwarves. Gnomes are known to be expert miners, and it is known that a se- cret underground mine complex built by this race exists within the Mazes of Menace, filled with both riches and danger. Humans are by far the most common race of the surface world, and are thus the norm by which other races are often compared. Although they have no special abilities, they can succeed in any role. Orcs are a cruel and barbaric race that hate every living thing (including other orcs). Above all others, Orcs hate Elves with a passion unequalled, and will go out of their way to kill one at any opportunity. The armor and weapons fashioned by the Orcs are typically of inferior quality. 3. What do all those things on the screen mean? On the screen is kept a map of where you have been and what you have seen on the current dungeon level; as you explore more of the level, it appears on the screen in front of you. NetHack 3.4 December 2, 2003 NetHack Guidebook 4 When NetHack's ancestor rogue first appeared, its screen orientation was almost unique among computer fantasy games. Since then, screen orientation has become the norm rather than the exception; NetHack continues this fine tradition. Unlike text adventure games that accept commands in pseudo-English sen- tences and explain the results in words, NetHack commands are all one or two keystrokes and the results are displayed graphically on the screen. A minimum screen size of 24 lines by 80 columns is recommended; if the screen is larger, only a 21x80 section will be used for the map. NetHack can even be played by blind players, with the assis- tance of Braille readers or speech synthesisers. Instructions for configuring NetHack for the blind are included later in this document. NetHack generates a new dungeon every time you play it; even the authors still find it an entertaining and exciting game de- spite having won several times. NetHack offers a variety of display options. The options available to you will vary from port to port, depending on the capabilities of your hardware and software, and whether various compile-time options were enabled when your executable was creat- ed. The three possible display options are: a monochrome charac- ter interface, a color character interface, and a graphical in- terface using small pictures called tiles. The two character in- terfaces allow fonts with other characters to be substituted, but the default assignments use standard ASCII characters to repre- sent everything. There is no difference between the various dis- play options with respect to game play. Because we cannot repro- duce the tiles or colors in the Guidebook, and because it is com- mon to all ports, we will use the default ASCII characters from the monochrome character display when referring to things you might see on the screen during your game. In order to understand what is going on in NetHack, first you must understand what NetHack is doing with the screen. The NetHack screen replaces the ``You see ...'' descriptions of text adventure games. Figure 1 is a sample of what a NetHack screen might look like. The way the screen looks for you depends on your platform. -------------------------------------------------------------------- The bat bites! ------ |....| ---------- |.<..|####...@...$.| |....-# |...B....+ |....| |.d......| ------ -------|-- NetHack 3.4 December 2, 2003 NetHack Guidebook 5 Player the Rambler St:12 Dx:7 Co:18 In:11 Wi:9 Ch:15 Neutral Dlvl:1 $:0 HP:9(12) Pw:3(3) AC:10 Exp:1/19 T:257 Weak -------------------------------------------------------------------- Figure 1 3.1. The status lines (bottom) The bottom two lines of the screen contain several cryptic pieces of information describing your current status. If either status line becomes longer than the width of the screen, you might not see all of it. Here are explanations of what the vari- ous status items mean (though your configuration may not have all the status items listed below): Rank Your character's name and professional ranking (based on the experience level, see below). Strength A measure of your character's strength; one of your six ba- sic attributes. A human character's attributes can range from 3 to 18 inclusive; non-humans may exceed these limits (occasionally you may get super-strengths of the form 18/xx, and magic can also cause attributes to exceed the normal limits). The higher your strength, the stronger you are. Strength affects how successfully you perform physical tasks, how much damage you do in combat, and how much loot you can carry. Dexterity Dexterity affects your chances to hit in combat, to avoid traps, and do other tasks requiring agility or manipulation of objects. Constitution Constitution affects your ability to recover from injuries and other strains on your stamina. Intelligence Intelligence affects your ability to cast spells and read spellbooks. Wisdom Wisdom comes from your practical experience (especially when dealing with magic). It affects your magical energy. Charisma Charisma affects how certain creatures react toward you. In particular, it can affect the prices shopkeepers offer you. NetHack 3.4 December 2, 2003 NetHack Guidebook 6 Alignment Lawful, Neutral, or Chaotic. Often, Lawful is taken as good and Chaotic as evil, but legal and ethical do not always co- incide. Your alignment influences how other monsters react toward you. Monsters of a like alignment are more likely to be non-aggressive, while those of an opposing alignment are more likely to be seriously offended at your presence. Dungeon Level How deep you are in the dungeon. You start at level one and the number increases as you go deeper into the dungeon. Some levels are special, and are identified by a name and not a number. The Amulet of Yendor is reputed to be some- where beneath the twentieth level. Gold The number of gold pieces you are openly carrying. Gold which you have concealed in containers is not counted. Hit Points Your current and maximum hit points. Hit points indicate how much damage you can take before you die. The more you get hit in a fight, the lower they get. You can regain hit points by resting, or by using certain magical items or spells. The number in parentheses is the maximum number your hit points can reach. Power Spell points. This tells you how much mystic energy (mana) you have available for spell casting. Again, resting will regenerate the amount available. Armor Class A measure of how effectively your armor stops blows from un- friendly creatures. The lower this number is, the more ef- fective the armor; it is quite possible to have negative ar- mor class. Experience Your current experience level and experience points. As you adventure, you gain experience points. At certain experi- ence point totals, you gain an experience level. The more experienced you are, the better you fight and withstand mag- ical attacks. Many dungeons show only your experience level here. Time The number of turns elapsed so far, displayed if you have the time option set. Hunger status Your current hunger status, ranging from Satiated down to Fainting. If your hunger status is normal, it is not dis- played. NetHack 3.4 December 2, 2003 NetHack Guidebook 7 Additional status flags may appear after the hunger status: Conf when you're confused, FoodPois or Ill when sick, Blind when you can't see, Stun when stunned, and Hallu when hallucinating. 3.2. The message line (top) The top line of the screen is reserved for messages that de- scribe things that are impossible to represent visually. If you see a ``--More--'' on the top line, this means that NetHack has another message to display on the screen, but it wants to make certain that you've read the one that is there first. To read the next message, just press the space bar. 3.3. The map (rest of the screen) The rest of the screen is the map of the level as you have explored it so far. Each symbol on the screen represents some- thing. You can set various graphics options to change some of the symbols the game uses; otherwise, the game will use default symbols. Here is a list of what the default symbols mean: - and | The walls of a room, or an open door. Or a grave (|). . The floor of a room, ice, or a doorless doorway. # A corridor, or iron bars, or a tree, or possibly a kitchen sink (if your dungeon has sinks), or a drawbridge. > Stairs down: a way to the next level. < Stairs up: a way to the previous level. + A closed door, or a spellbook containing a spell you may be able to learn. @ Your character or a human. $ A pile of gold. ^ A trap (once you have detected it). ) A weapon. [ A suit or piece of armor. % Something edible (not necessarily healthy). ? A scroll. / A wand. = A ring. NetHack 3.4 December 2, 2003 NetHack Guidebook 8 ! A potion. ( A useful item (pick-axe, key, lamp...). " An amulet or a spider web. * A gem or rock (possibly valuable, possibly worthless). ` A boulder or statue. 0 An iron ball. _ An altar, or an iron chain. { A fountain. } A pool of water or moat or a pool of lava. \ An opulent throne. a-zA-Z and other symbols Letters and certain other symbols represent the various in- habitants of the Mazes of Menace. Watch out, they can be nasty and vicious. Sometimes, however, they can be helpful. I This marks the last known location of an invisible or other- wise unseen monster. Note that the monster could have moved. The 'F' and 'm' commands may be useful here. You need not memorize all these symbols; you can ask the game what any symbol represents with the `/' command (see the next section for more info). 4. Commands Commands are initiated by typing one or two characters. Some commands, like ``search'', do not require that any more in- formation be collected by NetHack. Other commands might require additional information, for example a direction, or an object to be used. For those commands that require additional information, NetHack will present you with either a menu of choices or with a command line prompt requesting information. Which you are pre- sented with will depend chiefly on how you have set the menustyle option. For example, a common question, in the form ``What do you want to use? [a-zA-Z ?*]'', asks you to choose an object you are carrying. Here, ``a-zA-Z'' are the inventory letters of your possible choices. Typing `?' gives you an inventory list of these items, so you can see what each letter refers to. In this example, there is also a `*' indicating that you may choose an object not on the list, if you wanted to use something unexpect- ed. Typing a `*' lists your entire inventory, so you can see the NetHack 3.4 December 2, 2003 NetHack Guidebook 9 inventory letters of every object you're carrying. Finally, if you change your mind and decide you don't want to do this command after all, you can press the ESC key to abort the command. You can put a number before some commands to repeat them that many times; for example, ``10s'' will search ten times. If you have the number_pad option set, you must type `n' to prefix a count, so the example above would be typed ``n10s'' instead. Commands for which counts make no sense ignore them. In addi- tion, movement commands can be prefixed for greater control (see below). To cancel a count or a prefix, press the ESC key. The list of commands is rather long, but it can be read at any time during the game through the `?' command, which accesses a menu of helpful texts. Here are the commands for your refer- ence: ? Help menu: display one of several help texts available. / Tell what a symbol represents. You may choose to specify a location or type a symbol (or even a whole word) to explain. Specifying a location is done by moving the cursor to a par- ticular spot on the map and then pressing one of `.', `,', `;', or `:'. `.' will explain the symbol at the chosen lo- cation, conditionally check for ``More info?'' depending up- on whether the help option is on, and then you will be asked to pick another location; `,' will explain the symbol but skip any additional information; `;' will skip additional info and also not bother asking you to choose another loca- tion to examine; `:' will show additional info, if any, without asking for confirmation. When picking a location, pressing the ESC key will terminate this command, or press- ing `?' will give a brief reminder about how it works. Specifying a name rather than a location always gives any additional information available about that name. & Tell what a command does. < Go up to the previous level (if you are on a staircase or ladder). > Go down to the next level (if you are on a staircase or lad- der). [yuhjklbn] Go one step in the direction indicated (see Figure 2). If you sense or remember a monster there, you will fight the monster instead. Only these one-step movement commands cause you to fight monsters; the others (below) are ``safe.'' NetHack 3.4 December 2, 2003 NetHack Guidebook 10 y k u 7 8 9 \ | / \ | / h- . -l 4- . -6 / | \ / | \ b j n 1 2 3 (if number_pad is set) Figure 2 [YUHJKLBN] Go in that direction until you hit a wall or run into some- thing. m[yuhjklbn] Prefix: move without picking up objects or fighting (even if you remember a monster there) F[yuhjklbn] Prefix: fight a monster (even if you only guess one is there) M[yuhjklbn] Prefix: move far, no pickup. g[yuhjklbn] Prefix: move until something interesting is found. G[yuhjklbn] or [yuhjklbn] Prefix: same as `g', but forking of corridors is not con- sidered interesting. _ Travel to a map location via a shortest-path algorithm. The shortest path is computed over map locations the hero knows about (e.g. seen or previously traversed). If there is no known path, a guess is made instead. Stops on most of the same conditions as the `G' command, but without picking up objects, similar to the `M' command. For ports with mouse support, the command is also invoked when a mouse-click takes place on a location other than the current position. . Rest, do nothing for one turn. a Apply (use) a tool (pick-axe, key, lamp...). A Remove one or more worn items, such as armor. Use `T' (take off) to take off only one piece of armor or `R' (remove) to take off only one accessory. ^A Redo the previous command. c Close a door. NetHack 3.4 December 2, 2003 NetHack Guidebook 11 C Call (name) an individual monster. ^C Panic button. Quit the game. d Drop something. Ex. ``d7a'' means drop seven items of ob- ject a. D Drop several things. In answer to the question ``What kinds of things do you want to drop? [!%= BUCXaium]'' you should type zero or more object symbols possibly followed by `a' and/or `i' and/or `u' and/or `m'. In addition, one or more of the blessed/uncursed/cursed groups may be typed. DB - drop all objects known to be blessed. DU - drop all objects known to be uncursed. DC - drop all objects known to be cursed. DX - drop all objects of unknown B/U/C status. Da - drop all objects, without asking for confirmation. Di - examine your inventory before dropping anything. Du - drop only unpaid objects (when in a shop). Dm - use a menu to pick which object(s) to drop. D%u - drop only unpaid food. ^D Kick something (usually a door). e Eat food. E Engrave a message on the floor. Engraving the word ``Elbereth'' will cause most monsters to not attack you hand-to-hand (but if you attack, you will rub it out); this is often useful to give yourself a breather. (This feature may be compiled out of the game, so your version might not have it.) E- - write in the dust with your fingers. f Fire one of the objects placed in your quiver. You may se- lect ammunition with a previous `Q' command, or let the com- puter pick something appropriate if autoquiver is true. i List your inventory (everything you're carrying). I List selected parts of your inventory. I* - list all gems in inventory; Iu - list all unpaid items; Ix - list all used up items that are on your shopping bill; I$ - count your money. o Open a door. O Set options. A menu showing the current option values will be displayed. You can change most values simply by select- ing the menu entry for the given option (ie, by typing its NetHack 3.4 December 2, 2003 NetHack Guidebook 12 letter or clicking upon it, depending on your user inter- face). For the non-boolean choices, a further menu or prompt will appear once you've closed this menu. The avail- able options are listed later in this Guidebook. Options are usually set before the game rather than with the `O' command; see the section on options below. p Pay your shopping bill. P Put on a ring or other accessory (amulet, blindfold). ^P Repeat previous message. Subsequent ^P's repeat earlier messages. The behavior can be varied via the msg_window op- tion. q Quaff (drink) something (potion, water, etc). Q Select an object for your quiver. You can then throw this using the `f' command. (In versions prior to 3.3 this was the command to quit the game, which has now been moved to `#quit'.) r Read a scroll or spellbook. R Remove an accessory (ring, amulet, etc). ^R Redraw the screen. s Search for secret doors and traps around you. It usually takes several tries to find something. S Save (and suspend) the game. The game will be restored au- tomatically the next time you play. t Throw an object or shoot a projectile. T Take off armor. ^T Teleport, if you have the ability. v Display version number. V Display the game history. w Wield weapon. w- - wield nothing, use your bare hands. W Wear armor. x Exchange your wielded weapon with the item in your alternate weapon slot. The latter is used as your secondary weapon when engaging in two-weapon combat. Note that if one of these slots is empty, the exchange still takes place. NetHack 3.4 December 2, 2003 NetHack Guidebook 13 X Enter explore (discovery) mode, explained in its own section later. ^X Display your name, role, race, gender, and alignment as well as the various deities in your game. z Zap a wand. To aim at yourself, use `.' for the direction. Z Zap (cast) a spell. To cast at yourself, use `.' for the direction. ^Z Suspend the game (UNIX(R) versions with job control only). : Look at what is here. ; Show what type of thing a visible symbol corresponds to. , Pick up some things. May be preceded by `m' to force a se- lection menu. @ Toggle the autopickup option on and off. ^ Ask for the type of a trap you found earlier. ) Tell what weapon you are wielding. [ Tell what armor you are wearing. = Tell what rings you are wearing. " Tell what amulet you are wearing. ( Tell what tools you are using. * Tell what equipment you are using; combines the preceding five type-specific commands into one. $ Count your gold pieces. + List the spells you know. Using this command, you can also rearrange the order in which your spells are listed. They are shown via a menu, and if you select a spell in that menu, you'll be re-prompted for another spell to swap places with it, and then have opportunity to make further ex- changes. \ Show what types of objects have been discovered. ! Escape to a shell. __________ (R)UNIX is a registered trademark of AT&T. NetHack 3.4 December 2, 2003 NetHack Guidebook 14 # Perform an extended command. As you can see, the authors of NetHack used up all the letters, so this is a way to intro- duce the less frequently used commands. What extended com- mands are available depends on what features the game was compiled with. #adjust Adjust inventory letters (most useful when the fixinv option is ``on''). #chat Talk to someone. #conduct List which challenges you have adhered to. See the section below entitled ``Conduct'' for details. #dip Dip an object into something. #enhance Advance or check weapons and spell skills. #force Force a lock. #invoke Invoke an object's special powers. #jump Jump to another location. #loot Loot a box or bag on the floor beneath you, or the saddle from a horse standing next to you. #monster Use a monster's special ability (when polymorphed into mon- ster form). #name Name an item or type of object. #offer Offer a sacrifice to the gods. #pray Pray to the gods for help. #quit Quit the program without saving your game. #ride Ride (or stop riding) a monster. NetHack 3.4 December 2, 2003 NetHack Guidebook 15 #rub Rub a lamp or a stone. #sit Sit down. #turn Turn undead. #twoweapon Toggle two-weapon combat on or off. Note that you must use suitable weapons for this type of combat, or it will be au- tomatically turned off. #untrap Untrap something (trap, door, or chest). #version Print compile time options for this version of NetHack. #wipe Wipe off your face. #? Help menu: get the list of available extended commands. If your keyboard has a meta key (which, when pressed in com- bination with another key, modifies it by setting the `meta' [8th, or `high'] bit), you can invoke many extended commands by meta-ing the first letter of the command. In NT, OS/2, and PC NetHack, the `Alt' key can be used in this fashion. M-? #? (not supported by all platforms) M-2 #twoweapon (unless the number_pad option is enabled) M-a #adjust M-c #chat M-d #dip M-e #enhance M-f #force M-i #invoke M-j #jump M-l #loot M-m #monster M-n #name NetHack 3.4 December 2, 2003 NetHack Guidebook 16 M-o #offer M-p #pray M-q #quit M-r #rub M-s #sit M-t #turn M-u #untrap M-v #version M-w #wipe If the number_pad option is on, some additional letter com- mands are available: h Help menu: display one of several help texts available, like ``?''. j Jump to another location. Same as ``#jump'' or ``M-j''. k Kick something (usually a door). Same as `^D'. l Loot a box or bag on the floor beneath you, or the saddle from a horse standing next to you. Same as ``#loot'' or ``M-l''. N Name an item or type of object. Same as ``#name'' or ``M- n''. u Untrap a trap, door, or chest. Same as ``#untrap'' or ``M- u''. 5. Rooms and corridors Rooms and corridors in the dungeon are either lit or dark. Any lit areas within your line of sight will be displayed; dark areas are only displayed if they are within one space of you. Walls and corridors remain on the map as you explore them. Secret corridors are hidden. You can find them with the `s' (search) command. 5.1. Doorways Doorways connect rooms and corridors. Some doorways have no doors; you can walk right through. Others have doors in them, which may be open, closed, or locked. To open a closed door, use NetHack 3.4 December 2, 2003 NetHack Guidebook 17 the `o' (open) command; to close it again, use the `c' (close) command. You can get through a locked door by using a tool to pick the lock with the `a' (apply) command, or by kicking it open with the `^D' (kick) command. Open doors cannot be entered diagonally; you must approach them straight on, horizontally or vertically. Doorways without doors are not restricted in this fashion. Doors can be useful for shutting out monsters. Most mon- sters cannot open doors, although a few don't need to (ex. ghosts can walk through doors). Secret doors are hidden. You can find them with the `s' (search) command. Once found they are in all ways equivalent to normal doors. 5.2. Traps (`^') There are traps throughout the dungeon to snare the unwary delver. For example, you may suddenly fall into a pit and be stuck for a few turns trying to climb out. Traps don't appear on your map until you see one triggered by moving onto it, see some- thing fall into it, or you discover it with the `s' (search) com- mand. Monsters can fall prey to traps, too, which can be a very useful defensive strategy. There is a special pre-mapped branch of the dungeon based on the classic computer game ``Sokoban.'' The goal is to push the boulders into the pits or holes. With careful foresight, it is possible to complete all of the levels according to the tradi- tional rules of Sokoban. Some allowances are permitted in case the player gets stuck; however, they will lower your luck. 5.3. Stairs (`<', `>') In general, each level in the dungeon will have a staircase going up (`<') to the previous level and another going down (`>') to the next level. There are some exceptions though. For in- stance, fairly early in the dungeon you will find a level with two down staircases, one continuing into the dungeon and the oth- er branching into an area known as the Gnomish Mines. Those mines eventually hit a dead end, so after exploring them (if you choose to do so), you'll need to climb back up to the main dun- geon. When you traverse a set of stairs, or trigger a trap which sends you to another level, the level you're leaving will be de- activated and stored in a file on disk. If you're moving to a previously visited level, it will be loaded from its file on disk and reactivated. If you're moving to a level which has not yet been visited, it will be created (from scratch for most random NetHack 3.4 December 2, 2003 NetHack Guidebook 18 levels, from a template for some ``special'' levels, or loaded from the remains of an earlier game for a ``bones'' level as briefly described below). Monsters are only active on the cur- rent level; those on other levels are essentially placed into stasis. Ordinarily when you climb a set of stairs, you will arrive on the corresponding staircase at your destination. However, pets (see below) and some other monsters will follow along if they're close enough when you travel up or down stairs, and occa- sionally one of these creatures will displace you during the climb. When that occurs, the pet or other monster will arrive on the staircase and you will end up nearby. 5.4. Ladders (`<', `>') Ladders serve the same purpose as staircases, and the two types of inter-level connections are nearly indistinguishable during game play. 5.5. Shops and shopping Occasionally you will run across a room with a shopkeeper near the door and many items lying on the floor. You can buy items by picking them up and then using the `p' command. You can inquire about the price of an item prior to picking it up by us- ing the ``#chat'' command while standing on it. Using an item prior to paying for it will incur a charge, and the shopkeeper won't allow you to leave the shop until you have paid any debt you owe. You can sell items to a shopkeeper by dropping them to the floor while inside a shop. You will either be offered an amount of gold and asked whether you're willing to sell, or you'll be told that the shopkeeper isn't interested (generally, your item needs to be compatible with the type of merchandise carried by the shop). If you drop something in a shop by accident, the shopkeeper will usually claim ownership without offering any compensation. You'll have to buy it back if you want to reclaim it. Shopkeepers sometimes run out of money. When that happens, you'll be offered credit instead of gold when you try to sell something. Credit can be used to pay for purchases, but it is only good in the shop where it was obtained; other shopkeepers won't honor it. (If you happen to find a "credit card" in the dungeon, don't bother trying to use it in shops; shopkeepers will not accept it.) The `$' command, which reports the amount of gold you are carrying (in inventory, not inside bags or boxes), will also show current shop debt or credit, if any. The `Iu' command lists un- paid items (those which still belong to the shop) if you are NetHack 3.4 December 2, 2003 NetHack Guidebook 19 carrying any. The `Ix' command shows an inventory-like display of any unpaid items which have been used up, along with other shop fees, if any. 5.5.1. Shop idiosyncracies Several aspects of shop behavior might be unexpected. * The price of a given item can vary due to a variety of factors. * A shopkeeper treats the spot immediately inside the door as if it were outside the shop. * While the shopkeeper watches you like a hawk, he will generally ignore any other customers. * If a shop is "closed for inventory", it will not open of its own accord. * Shops do not get restocked with new items, regardless of inven- tory depletion. 6. Monsters Monsters you cannot see are not displayed on the screen. Beware! You may suddenly come upon one in a dark place. Some magic items can help you locate them before they locate you (which some monsters can do very well). The commands `/' and `;' may be used to obtain information about those monsters who are displayed on the screen. The com- mand `C' allows you to assign a name to a monster, which may be useful to help distinguish one from another when multiple mon- sters are present. Assigning a name which is just a space will remove any prior name. The extended command ``#chat'' can be used to interact with an adjacent monster. There is no actual dialog (in other words, you don't get to choose what you'll say), but chatting with some monsters such as a shopkeeper or the Oracle of Delphi can produce useful results. 6.1. Fighting If you see a monster and you wish to fight it, just attempt to walk into it. Many monsters you find will mind their own business unless you attack them. Some of them are very dangerous when angered. Remember: discretion is the better part of valor. If you can't see a monster (if it is invisible, or if you are blinded), the symbol `I' will be shown when you learn of its presence. If you attempt to walk into it, you will try to fight it just like a monster that you can see; of course, if the NetHack 3.4 December 2, 2003 NetHack Guidebook 20 monster has moved, you will attack empty air. If you guess that the monster has moved and you don't wish to fight, you can use the `m' command to move without fighting; likewise, if you don't remember a monster but want to try fighting anyway, you can use the `F' command. 6.2. Your pet You start the game with a little dog (`d'), cat (`f'), or pony (`u'), which follows you about the dungeon and fights mon- sters with you. Like you, your pet needs food to survive. It usually feeds itself on fresh carrion and other meats. If you're worried about it or want to train it, you can feed it, too, by throwing it food. A properly trained pet can be very useful un- der certain circumstances. Your pet also gains experience from killing monsters, and can grow over time, gaining hit points and doing more damage. Initially, your pet may even be better at killing things than you, which makes pets useful for low-level characters. Your pet will follow you up and down staircases if it is next to you when you move. Otherwise your pet will be stranded and may become wild. Similarly, when you trigger certain types of traps which alter your location (for instance, a trap door which drops you to a lower dungeon level), any adjacent pet will accompany you and any non-adjacent pet will be left behind. Your pet may trigger such traps itself; you will not be carried along with it even if adjacent at the time. 6.3. Steeds Some types of creatures in the dungeon can actually be rid- den if you have the right equipment and skill. Convincing a wild beast to let you saddle it up is difficult to say the least. Many a dungeoneer has had to resort to magic and wizardry in or- der to forge the alliance. Once you do have the beast under your control however, you can easily climb in and out of the saddle with the `#ride' command. Lead the beast around the dungeon when riding, in the same manner as you would move yourself. It is the beast that you will see displayed on the map. Riding skill is managed by the `#enhance' command. See the section on Weapon proficiency for more information about that. 6.4. Bones levels You may encounter the shades and corpses of other adventur- ers (or even former incarnations of yourself!) and their personal effects. Ghosts are hard to kill, but easy to avoid, since they're slow and do little damage. You can plunder the deceased adventurer's possessions; however, they are likely to be cursed. Beware of whatever killed the former player; it is probably still lurking around, gloating over its last victory. NetHack 3.4 December 2, 2003 NetHack Guidebook 21 7. Objects When you find something in the dungeon, it is common to want to pick it up. In NetHack, this is accomplished automatically by walking over the object (unless you turn off the autopickup op- tion (see below), or move with the `m' prefix (see above)), or manually by using the `,' command. If you're carrying too many items, NetHack will tell you so and you won't be able to pick up anything more. Otherwise, it will add the object(s) to your pack and tell you what you just picked up. As you add items to your inventory, you also add the weight of that object to your load. The amount that you can carry de- pends on your strength and your constitution. The stronger you are, the less the additional load will affect you. There comes a point, though, when the weight of all of that stuff you are car- rying around with you through the dungeon will encumber you. Your reactions will get slower and you'll burn calories faster, requiring food more frequently to cope with it. Eventually, you'll be so overloaded that you'll either have to discard some of what you're carrying or collapse under its weight. NetHack will tell you how badly you have loaded yourself. The symbols `Burdened', `Stressed', `Strained', `Overtaxed' and `Overloaded' are displayed on the bottom line display to indicate your condition. When you pick up an object, it is assigned an inventory let- ter. Many commands that operate on objects must ask you to find out which object you want to use. When NetHack asks you to choose a particular object you are carrying, you are usually pre- sented with a list of inventory letters to choose from (see Com- mands, above). Some objects, such as weapons, are easily differentiated. Others, like scrolls and potions, are given descriptions which vary according to type. During a game, any two objects with the same description are the same type. However, the descriptions will vary from game to game. When you use one of these objects, if its effect is obvious, NetHack will remember what it is for you. If its effect isn't extremely obvious, you will be asked what you want to call this type of object so you will recognize it later. You can also use the ``#name'' command for the same purpose at any time, to name all objects of a particular type or just an individual object. When you use ``#name'' on an object which has already been named, specifying a space as the value will remove the prior name in- stead of assigning a new one. NetHack 3.4 December 2, 2003 NetHack Guidebook 22 7.1. Curses and Blessings Any object that you find may be cursed, even if the object is otherwise helpful. The most common effect of a curse is being stuck with (and to) the item. Cursed weapons weld themselves to your hand when wielded, so you cannot unwield them. Any cursed item you wear is not removable by ordinary means. In addition, cursed arms and armor usually, but not always, bear negative en- chantments that make them less effective in combat. Other cursed objects may act poorly or detrimentally in other ways. Objects can also be blessed. Blessed items usually work better or more beneficially than normal uncursed items. For ex- ample, a blessed weapon will do more damage against demons. There are magical means of bestowing or removing curses upon objects, so even if you are stuck with one, you can still have the curse lifted and the item removed. Priests and Priestesses have an innate sensitivity to this property in any object, so they can more easily avoid cursed objects than other character roles. An item with unknown status will be reported in your inven- tory with no prefix. An item which you know the state of will be distinguished in your inventory by the presence of the word ``cursed'', ``uncursed'' or ``blessed'' in the description of the item. 7.2. Weapons (`)') Given a chance, most monsters in the Mazes of Menace will gratuitously try to kill you. You need weapons for self-defense (killing them first). Without a weapon, you do only 1-2 hit points of damage (plus bonuses, if any). Monk characters are an exception; they normally do much more damage with bare hands than they do with weapons. There are wielded weapons, like maces and swords, and thrown weapons, like arrows and spears. To hit monsters with a weapon, you must wield it and attack them, or throw it at them. You can simply elect to throw a spear. To shoot an arrow, you should first wield a bow, then throw the arrow. Crossbows shoot cross- bow bolts. Slings hurl rocks and (other) stones (like gems). Enchanted weapons have a ``plus'' (or ``to hit enhancement'' which can be either positive or negative) that adds to your chance to hit and the damage you do to a monster. The only way to determine a weapon's enchantment is to have it magically iden- tified somehow. Most weapons are subject to some type of damage like rust. Such ``erosion'' damage can be repaired. The chance that an attack will successfully hit a monster, and the amount of damage such a hit will do, depends upon many factors. Among them are: type of weapon, quality of weapon NetHack 3.4 December 2, 2003 NetHack Guidebook 23 (enchantment and/or erosion), experience level, strength, dexter- ity, encumbrance, and proficiency (see below). The monster's ar- mor class - a general defense rating, not necessarily due to wearing of armor - is a factor too; also, some monsters are par- ticularly vulnerable to certain types of weapons. Many weapons can be wielded in one hand; some require both hands. When wielding a two-handed weapon, you can not wear a shield, and vice versa. When wielding a one-handed weapon, you can have another weapon ready to use by setting things up with the `x' command, which exchanges your primary (the one being wielded) and alternate weapons. And if you have proficiency in the ``two weapon combat'' skill, you may wield both weapons si- multaneously as primary and secondary; use the `#twoweapon' ex- tended command to engage or disengage that. Only some types of characters (barbarians, for instance) have the necessary skill available. Even with that skill, using two weapons at once in- curs a penalty in the chance to hit your target compared to using just one weapon at a time. There might be times when you'd rather not wield any weapon at all. To accomplish that, wield `-', or else use the `A' com- mand which allows you to unwield the current weapon in addition to taking off other worn items. Those of you in the audience who are AD&D players, be aware that each weapon which existed in AD&D does roughly the same dam- age to monsters in NetHack. Some of the more obscure weapons (such as the aklys, lucern hammer, and bec-de-corbin) are defined in an appendix to Unearthed Arcana, an AD&D supplement. The commands to use weapons are `w' (wield), `t' (throw), `f' (fire, an alternative way of throwing), `Q' (quiver), `x' (exchange), `#twoweapon', and `#enhance' (see below). 7.2.1. Throwing and shooting You can throw just about anything via the `t' command. It will prompt for the item to throw; picking `?' will list things in your inventory which are considered likely to be thrown, or picking `*' will list your entire inventory. After you've chosen what to throw, you will be prompted for a direction rather than for a specific target. The distance something can be thrown de- pends mainly on the type of object and your strength. Arrows can be thrown by hand, but can be thrown much farther and will be more likely to hit when thrown while you are wielding a bow. You can simplify the throwing operation by using the `Q' command to select your preferred ``missile'', then using the `f' command to throw it. You'll be prompted for a direction as above, but you don't have to specify which item to throw each time you use `f'. There is also an option, autoquiver, which has NetHack choose another item to automatically fill your quiver when the inventory slot used for `Q' runs out. NetHack 3.4 December 2, 2003 NetHack Guidebook 24 Some characters have the ability to fire a volley of multi- ple items in a single turn. Knowing how to load several rounds of ammunition at once -- or hold several missiles in your hand -- and still hit a target is not an easy task. Rangers are among those who are adept at this task, as are those with a high level of proficiency in the relevant weapon skill (in bow skill if you're wielding one to shoot arrows, in crossbow skill if you're wielding one to shoot bolts, or in sling skill if you're wielding one to shoot stones). The number of items that the character has a chance to fire varies from turn to turn. You can explicitly limit the number of shots by using a numeric prefix before the `t' or `f' command. For example, ``2f'' (or ``n2f'' if using number_pad mode) would ensure that at most 2 arrows are shot even if you could have fired 3. If you specify a larger number than would have been shot (``4f'' in this example), you'll just end up shooting the same number (3, here) as if no limit had been speci- fied. Once the volley is in motion, all of the items will travel in the same direction; if the first ones kill a monster, the oth- ers can still continue beyond that spot. 7.2.2. Weapon proficiency You will have varying degrees of skill in the weapons avail- able. Weapon proficiency, or weapon skills, affect how well you can use particular types of weapons, and you'll be able to im- prove your skills as you progress through a game, depending on your role, your experience level, and use of the weapons. For the purposes of proficiency, weapons have been divided up into various groups such as daggers, broadswords, and polearms. Each role has a limit on what level of proficiency a character can achieve for each group. For instance, wizards can become highly skilled in daggers or staves but not in swords or bows. The `#enhance' extended command is used to review current weapons proficiency (also spell proficiency) and to choose which skill(s) to improve when you've used one or more skills enough to become eligible to do so. The skill rankings are ``none'' (some- times also referred to as ``restricted'', because you won't be able to advance), ``unskilled'', ``basic'', ``skilled'', and ``expert''. Restricted skills simply will not appear in the list shown by `#enhance'. (Divine intervention might unrestrict a particular skill, in which case it will start at unskilled and be limited to basic.) Some characters can enhance their barehanded combat or martial arts skill beyond expert to ``master'' or ``grand master''. Use of a weapon in which you're restricted or unskilled will incur a modest penalty in the chance to hit a monster and also in the amount of damage done when you do hit; at basic level, there is no penalty or bonus; at skilled level, you receive a modest bonus in the chance to hit and amount of damage done; at expert level, the bonus is higher. A successful hit has a chance to NetHack 3.4 December 2, 2003 NetHack Guidebook 25 boost your training towards the next skill level (unless you've already reached the limit for this skill). Once such training reaches the threshold for that next level, you'll be told that you feel more confident in your skills. At that point you can use `#enhance' to increase one or more skills. Such skills are not increased automatically because there is a limit to your to- tal overall skills, so you need to actively choose which skills to enhance and which to ignore. 7.3. Armor (`[') Lots of unfriendly things lurk about; you need armor to pro- tect yourself from their blows. Some types of armor offer better protection than others. Your armor class is a measure of this protection. Armor class (AC) is measured as in AD&D, with 10 be- ing the equivalent of no armor, and lower numbers meaning better armor. Each suit of armor which exists in AD&D gives the same protection in NetHack. Here is an (incomplete) list of the armor classes provided by various suits of armor: dragon scale mail 1 plate mail 3 crystal plate mail 3 bronze plate mail 4 splint mail 4 banded mail 4 dwarvish mithril-coat 4 elven mithril-coat 5 chain mail 5 orcish chain mail 6 scale mail 6 studded leather armor 7 ring mail 7 orcish ring mail 8 leather armor 8 leather jacket 9 no armor 10 You can also wear other pieces of armor (ex. helmets, boots, shields, cloaks) to lower your armor class even further, but you can only wear one item of each category (one suit of armor, one cloak, one helmet, one shield, and so on) at a time. If a piece of armor is enchanted, its armor protection will be better (or worse) than normal, and its ``plus'' (or minus) will subtract from your armor class. For example, a +1 chain mail would give you better protection than normal chain mail, lowering your armor class one unit further to 4. When you put on a piece of armor, you immediately find out the armor class and any ``plusses'' it provides. Cursed pieces of armor usually have negative enchantments (minuses) in addition to being unremovable. Many types of armor are subject to some kind of damage like rust. Such damage can be repaired. Some types of armor may NetHack 3.4 December 2, 2003 NetHack Guidebook 26 inhibit spell casting. The commands to use armor are `W' (wear) and `T' (take off). The `A' command can also be used to take off armor as well as other worn items. 7.4. Food (`%') Food is necessary to survive. If you go too long without eating you will faint, and eventually die of starvation. Some types of food will spoil, and become unhealthy to eat, if not protected. Food stored in ice boxes or tins (``cans'') will usu- ally stay fresh, but ice boxes are heavy, and tins take a while to open. When you kill monsters, they usually leave corpses which are also ``food.'' Many, but not all, of these are edible; some also give you special powers when you eat them. A good rule of thumb is ``you are what you eat.'' Some character roles and some monsters are vegetarian. Veg- etarian monsters will typically never eat animal corpses, while vegetarian players can, but with some rather unpleasant side-ef- fects. You can name one food item after something you like to eat with the fruit option. The command to eat food is `e'. 7.5. Scrolls (`?') Scrolls are labeled with various titles, probably chosen by ancient wizards for their amusement value (ex. ``READ ME,'' or ``THANX MAUD'' backwards). Scrolls disappear after you read them (except for blank ones, without magic spells on them). One of the most useful of these is the scroll of identify, which can be used to determine what another object is, whether it is cursed or blessed, and how many uses it has left. Some ob- jects of subtle enchantment are difficult to identify without these. A mail daemon may run up and deliver mail to you as a scroll of mail (on versions compiled with this feature). To use this feature on versions where NetHack mail delivery is triggered by electronic mail appearing in your system mailbox, you must let NetHack know where to look for new mail by setting the ``MAIL'' environment variable to the file name of your mailbox. You may also want to set the ``MAILREADER'' environment variable to the file name of your favorite reader, so NetHack can shell to it when you read the scroll. On versions of NetHack where mail is randomly generated internal to the game, these environment vari- ables are ignored. You can disable the mail daemon by turning NetHack 3.4 December 2, 2003 NetHack Guidebook 27 off the mail option. The command to read a scroll is `r'. 7.6. Potions (`!') Potions are distinguished by the color of the liquid inside the flask. They disappear after you quaff them. Clear potions are potions of water. Sometimes these are blessed or cursed, resulting in holy or unholy water. Holy water is the bane of the undead, so potions of holy water are good things to throw (`t') at them. It is also sometimes very useful to dip (``#dip'') an object into a potion. The command to drink a potion is `q' (quaff). 7.7. Wands (`/') Magic wands usually have multiple magical charges. Some wands are directional--you must give a direction in which to zap them. You can also zap them at yourself (just give a `.' or `s' for the direction). Be warned, however, for this is often unwise. Other wands are nondirectional--they don't require a direction. The number of charges in a wand is random and decreases by one whenever you use it. When the number of charges left in a wand becomes zero, at- tempts to use the wand will usually result in nothing happening. Occasionally, however, it may be possible to squeeze the last few mana points from an otherwise spent wand, destroying it in the process. A wand may be recharged by using suitable magic, but doing so runs the risk of causing it to explode. The chance for such an explosion starts out very small and increases each time the wand is recharged. In a truly desperate situation, when your back is up against the wall, you might decide to go for broke and break your wand. This is not for the faint of heart. Doing so will almost cer- tainly cause a catastrophic release of magical energies. When you have fully identified a particular wand, inventory display will include additional information in parentheses: the number of times it has been recharged followed by a colon and then by its current number of charges. A current charge count of -1 is a special case indicating that the wand has been cancelled. The command to use a wand is `z' (zap). To break one, use the `a' (apply) command. 7.8. Rings (`=') Rings are very useful items, since they are relatively per- manent magic, unlike the usually fleeting effects of potions, NetHack 3.4 December 2, 2003 NetHack Guidebook 28 scrolls, and wands. Putting on a ring activates its magic. You can wear only two rings, one on each ring finger. Most rings also cause you to grow hungry more rapidly, the rate varying with the type of ring. The commands to use rings are `P' (put on) and `R' (remove). 7.9. Spellbooks (`+') Spellbooks are tomes of mighty magic. When studied with the `r' (read) command, they transfer to the reader the knowledge of a spell (and therefore eventually become unreadable) -- unless the attempt backfires. Reading a cursed spellbook or one with mystic runes beyond your ken can be harmful to your health! A spell (even when learned) can also backfire when you cast it. If you attempt to cast a spell well above your experience level, or if you have little skill with the appropriate spell type, or cast it at a time when your luck is particularly bad, you can end up wasting both the energy and the time required in casting. Casting a spell calls forth magical energies and focuses them with your naked mind. Some of the magical energy released comes from within you, and casting several spells in a row may tire you. Casting of spells also requires practice. With prac- tice, your skill in each category of spell casting will improve. Over time, however, your memory of each spell will dim, and you will need to relearn it. Some spells are directional--you must give a direction in which to cast them. You can also cast them at yourself (just give a `.' or `s' for the direction). Be warned, however, for this is often unwise. Other spells are nondirectional--they don't require a direction. Just as weapons are divided into groups in which a character can become proficient (to varying degrees), spells are similarly grouped. Successfully casting a spell exercises the skill group; sufficient skill may increase the potency of the spell and reduce the risk of spell failure. Skill slots are shared with weapons skills. (See also the section on ``Weapon proficiency''.) Casting a spell also requires flexible movement, and wearing various types of armor may interfere with that. The command to read a spellbook is the same as for scrolls, `r' (read). The `+' command lists your current spells, their levels, categories, and chances for failure. The `Z' (cast) com- mand casts a spell. NetHack 3.4 December 2, 2003 NetHack Guidebook 29 7.10. Tools (`(') Tools are miscellaneous objects with various purposes. Some tools have a limited number of uses, akin to wand charges. For example, lamps burn out after a while. Other tools are contain- ers, which objects can be placed into or taken out of. The command to use tools is `a' (apply). 7.10.1. Containers You may encounter bags, boxes, and chests in your travels. A tool of this sort can be opened with the ``#loot'' extended command when you are standing on top of it (that is, on the same floor spot), or with the `a' (apply) command when you are carry- ing it. However, chests are often locked, and are in any case unwieldy objects. You must set one down before unlocking it by using a key or lock-picking tool with the `a' (apply) command, by kicking it with the `^D' command, or by using a weapon to force the lock with the ``#force'' extended command. Some chests are trapped, causing nasty things to happen when you unlock or open them. You can check for and try to deactivate traps with the ``#untrap'' extended command. 7.11. Amulets (`"') Amulets are very similar to rings, and often more powerful. Like rings, amulets have various magical properties, some benefi- cial, some harmful, which are activated by putting them on. Only one amulet may be worn at a time, around your neck. The commands to use amulets are the same as for rings, `P' (put on) and `R' (remove). 7.12. Gems (`*') Some gems are valuable, and can be sold for a lot of gold. They are also a far more efficient way of carrying your riches. Valuable gems increase your score if you bring them with you when you exit. Other small rocks are also categorized as gems, but they are much less valuable. All rocks, however, can be used as projec- tile weapons (if you have a sling). In the most desperate of cases, you can still throw them by hand. 7.13. Large rocks (``') Statues and boulders are not particularly useful, and are generally heavy. It is rumored that some statues are not what they seem. NetHack 3.4 December 2, 2003 NetHack Guidebook 30 Very large humanoids (giants and their ilk) have been known to use boulders as weapons. 7.14. Gold (`$') Gold adds to your score, and you can buy things in shops with it. There are a number of monsters in the dungeon that may be influenced by the amount of gold you are carrying (shopkeepers aside). 8. Conduct As if winning NetHack were not difficult enough, certain players seek to challenge themselves by imposing restrictions on the way they play the game. The game automatically tracks some of these challenges, which can be checked at any time with the #conduct command or at the end of the game. When you perform an action which breaks a challenge, it will no longer be listed. This gives players extra ``bragging rights'' for winning the game with these challenges. Note that it is perfectly acceptable to win the game without resorting to these restrictions and that it is unusual for players to adhere to challenges the first time they win the game. Several of the challenges are related to eating behavior. The most difficult of these is the foodless challenge. Although creatures can survive long periods of time without food, there is a physiological need for water; thus there is no restriction on drinking beverages, even if they provide some minor food bene- fits. Calling upon your god for help with starvation does not violate any food challenges either. A strict vegan diet is one which avoids any food derived from animals. The primary source of nutrition is fruits and veg- etables. The corpses and tins of blobs (`b'), jellies (`j'), and fungi (`F') are also considered to be vegetable matter. Certain human food is prepared without animal products; namely, lembas wafers, cram rations, food rations (gunyoki), K-rations, and C- rations. Metal or another normally indigestible material eaten while polymorphed into a creature that can digest it is also con- sidered vegan food. Note however that eating such items still counts against foodless conduct. Vegetarians do not eat animals; however, they are less se- lective about eating animal byproducts than vegans. In addition to the vegan items listed above, they may eat any kind of pudding (`P') other than the black puddings, eggs and food made from eggs (fortune cookies and pancakes), food made with milk (cream pies and candy bars), and lumps of royal jelly. Monks are expected to observe a vegetarian diet. Eating any kind of meat violates the vegetarian, vegan, and foodless conducts. This includes tripe rations, the corpses or NetHack 3.4 December 2, 2003 NetHack Guidebook 31 tins of any monsters not mentioned above, and the various other chunks of meat found in the dungeon. Swallowing and digesting a monster while polymorphed is treated as if you ate the creature's corpse. Eating leather, dragon hide, or bone items while poly- morphed into a creature that can digest it, or eating monster brains while polymorphed into a mind flayer, is considered eating an animal, although wax is only an animal byproduct. Regardless of conduct, there will be some items which are indigestible, and others which are hazardous to eat. Using a swallow-and-digest attack against a monster is equivalent to eat- ing the monster's corpse. Please note that the term ``vegan'' is used here only in the context of diet. You are still free to choose not to use or wear items derived from animals (e.g. leather, dragon hide, bone, horns, coral), but the game will not keep track of this for you. Also note that ``milky'' potions may be a translucent white, but they do not contain milk, so they are compatible with a vegan diet. Slime molds or player-defined ``fruits'', although they could be anything from ``cherries'' to ``pork chops'', are also assumed to be vegan. An atheist is one who rejects religion. This means that you cannot #pray, #offer sacrifices to any god, #turn undead, or #chat with a priest. Particularly selective readers may argue that playing Monk or Priest characters should violate this con- duct; that is a choice left to the player. Offering the Amulet of Yendor to your god is necessary to win the game and is not counted against this conduct. You are also not penalized for be- ing spoken to by an angry god, priest(ess), or other religious figure; a true atheist would hear the words but attach no special meaning to them. Most players fight with a wielded weapon (or tool intended to be wielded as a weapon). Another challenge is to win the game without using such a wielded weapon. You are still permitted to throw, fire, and kick weapons; use a wand, spell, or other type of item; or fight with your hands and feet. In NetHack, a pacifist refuses to cause the death of any other monster (i.e. if you would get experience for the death). This is a particularly difficult challenge, although it is still possible to gain experience by other means. An illiterate character cannot read or write. This includes reading a scroll, spellbook, fortune cookie message, or t-shirt; writing a scroll; or making an engraving of anything other than a single ``x'' (the traditional signature of an illiterate person). Reading an engraving, or any item that is absolutely necessary to win the game, is not counted against this conduct. The identity of scrolls and spellbooks (and knowledge of spells) in your starting inventory is assumed to be learned from your teachers prior to the start of the game and isn't counted. NetHack 3.4 December 2, 2003 NetHack Guidebook 32 There are several other challenges tracked by the game. It is possible to eliminate one or more species of monsters by geno- cide; playing without this feature is considered a challenge. When the game offers you an opportunity to genocide monsters, you may respond with the monster type ``none'' if you want to de- cline. You can change the form of an item into another item of the same type (``polypiling'') or the form of your own body into another creature (``polyself'') by wand, spell, or potion of polymorph; avoiding these effects are each considered challenges. Polymorphing monsters, including pets, does not break either of these challenges. Finally, you may sometimes receive wishes; a game without an attempt to wish for any items is a challenge, as is a game without wishing for an artifact (even if the artifact immediately disappears). When the game offers you an opportunity to make a wish for an item, you may choose ``nothing'' if you want to decline. 9. Options Due to variations in personal tastes and conceptions of how NetHack should do things, there are options you can set to change how NetHack behaves. 9.1. Setting the options Options may be set in a number of ways. Within the game, the `O' command allows you to view all options and change most of them. You can also set options automatically by placing them in the NETHACKOPTIONS environment variable or in a configuration file. Some versions of NetHack also have front-end programs that allow you to set options before starting the game. 9.2. Using the NETHACKOPTIONS environment variable The NETHACKOPTIONS variable is a comma-separated list of initial values for the various options. Some can only be turned on or off. You turn one of these on by adding the name of the option to the list, and turn it off by typing a `!' or ``no'' be- fore the name. Others take a character string as a value. You can set string options by typing the option name, a colon or equals sign, and then the value of the string. The value is ter- minated by the next comma or the end of string. For example, to set up an environment variable so that ``au- toquiver'' is on, ``autopickup'' is off, the name is set to ``Blue Meanie'', and the fruit is set to ``papaya'', you would enter the command % setenv NETHACKOPTIONS "autoquiver,\!autopickup,name:Blue Meanie,fruit:papaya" in csh (note the need to escape the ! since it's special to the shell), or NetHack 3.4 December 2, 2003 NetHack Guidebook 33 $ NETHACKOPTIONS="autoquiver,!autopickup,name:Blue Meanie,fruit:papaya" $ export NETHACKOPTIONS in sh or ksh. 9.3. Using a configuration file Any line in the configuration file starting with `#' is treated as a comment. Any line in the configuration file start- ing with ``OPTIONS='' may be filled out with options in the same syntax as in NETHACKOPTIONS. Any line starting with ``DUN- GEON='', ``EFFECTS='', ``MONSTERS='', ``OBJECTS='', ``TRAPS='', or ``BOULDER='' is taken as defining the corresponding dungeon, effects, monsters, objects traps or boulder option in a different syntax, a sequence of decimal numbers giving the character posi- tion in the current font to be used in displaying each entry. A zero in any entry in such a sequence leaves the display of that entry unchanged; this feature is not available using the option syntax. Such a sequence can be continued to multiple lines by putting a `\' at the end of each line to be continued. If your copy of the game included the compile time AUTOPICK- UP_EXCEPTIONS option, then any line starting with ``AUTOPICK- UP_EXCEPTION='' is taken as defining an exception to the pick- up_types option. There is a section of this Guidebook that dis- cusses that. The default name of the configuration file varies on differ- ent operating systems, but NETHACKOPTIONS can also be set to the full name of a file you want to use (possibly preceded by an `@'). 9.4. Customization options Here are explanations of what the various options do. Char- acter strings that are too long may be truncated. Some of the options listed may be inactive in your dungeon. align Your starting alignment (align:lawful, align:neutral, or align:chaotic). You may specify just the first letter. The default is to randomly pick an appropriate alignment. Cannot be set with the `O' command. autodig Automatically dig if you are wielding a digging tool and moving into a place that can be dug (default false). autopickup Automatically pick up things onto which you move (default on). See pickup_types to refine the behavior. autoquiver This option controls what happens when you attempt the `f' NetHack 3.4 December 2, 2003 NetHack Guidebook 34 (fire) command with an empty quiver. When true, the computer will fill your quiver with some suitable weapon. Note that it will not take into account the blessed/cursed status, enchant- ment, damage, or quality of the weapon; you are free to manual- ly fill your quiver with the `Q' command instead. If no weapon is found or the option is false, the `t' (throw) command is ex- ecuted instead. (default false) boulder Set the character used to display boulders (default is rock class symbol). catname Name your starting cat (ex. ``catname:Morris''). Cannot be set with the `O' command. character Pick your type of character (ex. ``character:Monk''); synonym for ``role''. See ``name'' for an alternate method of specify- ing your role. Normally only the first letter of the value is examined; the string ``random'' is an exception. checkpoint Save game state after each level change, for possible recovery after program crash (default on). checkspace Check free disk space before writing files to disk (default on). You may have to turn this off if you have more than 2 GB free space on the partition used for your save and level files. Only applies when MFLOPPY was defined during compilation. cmdassist Have the game provide some additional command assistance for new players if it detects some anticipated mistakes (default on). confirm Have user confirm attacks on pets, shopkeepers, and other peaceable creatures (default on). DECgraphics Use a predefined selection of characters from the DEC VT- xxx/DEC Rainbow/ANSI line-drawing character set to display the dungeon/effects/traps instead of having to define a full graph- ics set yourself (default off). This option also sets up prop- er handling of graphics characters for such terminals, so you should specify it when appropriate even if you override the se- lections with your own graphics strings. disclose Controls options for disclosing various information when the game ends (defaults to all possibilities being disclosed). The possibilities are: NetHack 3.4 December 2, 2003 NetHack Guidebook 35 i - disclose your inventory. a - disclose your attributes. v - summarize monsters that have been vanquished. g - list monster species that have been genocided. c - display your conduct. Each disclosure possibility can optionally be preceded by a prefix which let you refine how it behaves. Here are the valid prefixes: y - prompt you and default to yes on the prompt. n - prompt you and default to no on the prompt. + - disclose it without prompting. - - do not disclose it and do not prompt. (ex. ``disclose:yi na +v -g -c'') The example sets inventory to prompt and default to yes, attributes to prompt and default to no, vanquished to disclose without prompting, genocided to not disclose and not to prompt, conduct to not disclose and not to prompt. Note that the vanquished monsters list includes all monsters killed by traps and each other as well as by you. dogname Name your starting dog (ex. ``dogname:Fang''). Cannot be set with the `O' command. dungeon Set the graphics symbols for displaying the dungeon (default `` |--------||.-|++##.##<><>_|\\#{}.}..## #}''). The dungeon option should be followed by a string of 1-41 characters to be used instead of the default map-drawing characters. The dun- geon map will use the characters you specify instead of the de- fault symbols, and default symbols for any you do not specify. Remember that you may need to escape some of these characters on a command line if they are special to your shell. Note that NetHack escape-processes this option string in con- ventional C fashion. This means that `\' is a prefix to take the following character literally. Thus `\' needs to be repre- sented as `\\'. The special escape form `\m' switches on the meta bit in the following character, and the `^' prefix causes the following character to be treated as a control character. The order of the symbols is: solid rock, vertical wall, hori- zontal wall, upper left corner, upper right corner, lower left corner, lower right corner, cross wall, upward T wall, downward T wall, leftward T wall, rightward T wall, no door, vertical open door, horizontal open door, vertical closed door, horizon- tal closed door, iron bars, tree, floor of a room, dark corri- dor, lit corridor, stairs up, stairs down, ladder up, ladder down, altar, grave, throne, kitchen sink, fountain, pool or moat, ice, lava, vertical lowered drawbridge, horizontal low- ered drawbridge, vertical raised drawbridge, horizontal raised drawbridge, air, cloud, under water. NetHack 3.4 December 2, 2003 NetHack Guidebook 36 You might want to use `+' for the corners and T walls for a more aesthetic, boxier display. Note that in the next release, new symbols may be added, or the present ones rearranged. Cannot be set with the `O' command. effects Set the graphics symbols for displaying special effects (de- fault ``|-\\/*!)(0#@*/-\\||\\-//-\\| |\\-/''). The effects op- tion should be followed by a string of 1-29 characters to be used instead of the default special-effects characters. This string is subjected to the same processing as the dungeon op- tion. The order of the symbols is: vertical beam, horizontal beam, left slant, right slant, digging beam, camera flash beam, left boomerang, right boomerang, four glyphs giving the sequence for magic resistance displays, the eight surrounding glyphs for swallowed display, nine glyphs for explosions. An explosion consists of three rows (top, middle, and bottom) of three char- acters. The explosion is centered in the center of this 3 by 3 array. Note that in the next release, new symbols may be added, or the present ones rearranged. Cannot be set with the `O' command. extmenu Changes the extended commands interface to pop-up a menu of available commands. It is keystroke compatible with the tradi- tional interface except that it does not require that you hit Enter. It is implemented only by the tty port (default off), when the game has been compiled to support tty graphics. female An obsolete synonym for ``gender:female''. Cannot be set with the `O' command. fixinv An object's inventory letter sticks to it when it's dropped (default on). If this is off, dropping an object shifts all the remaining inventory letters. fruit Name a fruit after something you enjoy eating (ex. ``fruit:man- go'') (default ``slime mold''). Basically a nostalgic whimsy that NetHack uses from time to time. You should set this to something you find more appetizing than slime mold. Apples, oranges, pears, bananas, and melons already exist in NetHack, so don't use those. gender Your starting gender (gender:male or gender:female). You may NetHack 3.4 December 2, 2003 NetHack Guidebook 37 specify just the first letter. Although you can still denote your gender using the ``male'' and ``female'' options, the ``gender'' option will take precedence. The default is to ran- domly pick an appropriate gender. Cannot be set with the `O' command. help If more information is available for an object looked at with the `/' command, ask if you want to see it (default on). Turn- ing help off makes just looking at things faster, since you aren't interrupted with the ``More info?'' prompt, but it also means that you might miss some interesting and/or important in- formation. horsename Name your starting horse (ex. ``horsename:Trigger''). Cannot be set with the `O' command. IBMgraphics Use a predefined selection of IBM extended ASCII characters to display the dungeon/effects/traps instead of having to define a full graphics set yourself (default off). This option also sets up proper handling of graphics characters for such termi- nals, so you should specify it when appropriate even if you override the selections with your own graphics strings. ignintr Ignore interrupt signals, including breaks (default off). legacy Display an introductory message when starting the game (default on). lit_corridor Show corridor squares seen by night vision or a light source held by your character as lit (default off). lootabc Use the old `a', `b', and `c' keyboard shortcuts when looting, rather than the mnemonics `o', `i', and `b' (default off). mail Enable mail delivery during the game (default on). male An obsolete synonym for ``gender:male''. Cannot be set with the `O' command. menustyle Controls the interface used when you need to choose various ob- jects (in response to the Drop command, for instance). The value specified should be the first letter of one of the fol- lowing: traditional, combination, partial, or full. Tradi- tional was the only interface available for earlier versions; NetHack 3.4 December 2, 2003 NetHack Guidebook 38 it consists of a prompt for object class characters, followed by an object-by-object prompt for all items matching the se- lected object class(es). Combination starts with a prompt for object class(es) of interest, but then displays a menu of matching objects rather than prompting one-by-one. Partial skips the object class filtering and immediately displays a menu of all objects. Full displays a menu of object classes rather than a character prompt, and then a menu of matching ob- jects for selection. menu_deselect_all Menu character accelerator to deselect all items in a menu. Implemented by the Amiga, Gem, X11 and tty ports. Default '-'. menu_deselect_page Menu character accelerator to deselect all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. De- fault '\'. menu_first_page Menu character accelerator to jump to the first page in a menu. Implemented by the Amiga, Gem and tty ports. Default '^'. menu_headings Controls how the headings in a menu are highlighted. Values are 'bold', 'inverse', or 'underline'. Not all ports can actu- ally display all three types. menu_invert_all Menu character accelerator to invert all items in a menu. Im- plemented by the Amiga, Gem, X11 and tty ports. Default '@'. menu_invert_page Menu character accelerator to invert all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default '~'. menu_last_page Menu character accelerator to jump to the last page in a menu. Implemented by the Amiga, Gem and tty ports. Default '|'. menu_next_page Menu character accelerator to goto the next menu page. Imple- mented by the Amiga, Gem and tty ports. Default '>'. menu_previous_page Menu character accelerator to goto the previous menu page. Im- plemented by the Amiga, Gem and tty ports. Default '<'. menu_search Menu character accelerator to search for a menu item. Imple- mented by the Amiga, Gem and X11 ports. Default ':'. NetHack 3.4 December 2, 2003 NetHack Guidebook 39 menu_select_all Menu character accelerator to select all items in a menu. Im- plemented by the Amiga, Gem, X11 and tty ports. Default '.'. menu_select_page Menu character accelerator to select all items on this page of a menu. Implemented by the Amiga, Gem and tty ports. Default ','. monsters Set the characters used to display monster classes (default ``abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTU- VWXYZ@ '&;:~]''). This string is subjected to the same pro- cessing as the dungeon option. The order of the symbols is ant or other insect, blob, cockatrice, dog or other canine, eye or sphere, feline, gremlin, humanoid, imp or minor demon, jelly, kobold, leprechaun, mimic, nymph, orc, piercer, quadruped, ro- dent, arachnid or centipede, trapper or lurker above, horse or unicorn, vortex, worm, xan or other mythical/fantastic insect, light, zruty, angelic being, bat or bird, centaur, dragon, ele- mental, fungus or mold, gnome, giant humanoid, invisible mon- ster, jabberwock, Keystone Kop, lich, mummy, naga, ogre, pud- ding or ooze, quantum mechanic, rust monster, snake, troll, um- ber hulk, vampire, wraith, xorn, apelike creature, zombie, hu- man, ghost, golem, demon, sea monster, lizard, long worm tail, and mimic. Cannot be set with the `O' command. msghistory The number of top line messages to save (and recall with ^P) (default 20). Cannot be set with the `O' command. msg_window Allows you to change the way recalled messages are displayed. (It is currently implemented for tty only.) The possible val- ues are: s - single message (default, this was the behavior before 3.4.0). c - combination, two messages as `single', then as `full'. f - full window, oldest message first. r - full window, newest message first. For backward compatibility, no value needs to be specified (which defaults to `full'), or it can be negated (which de- faults to `single'). name Set your character's name (defaults to your user name). You can also set your character's role by appending a dash and one or more letters of the role (that is, by suffixing one of -A -B -C -H -K -M -P -Ra -Ro -S -T -V -W). If -@ is used for the role, then a random one will be automatically chosen. Cannot be set with the `O' command. NetHack 3.4 December 2, 2003 NetHack Guidebook 40 news Read the NetHack news file, if present (default on). Since the news is shown at the beginning of the game, there's no point in setting this with the `O' command. null Send padding nulls to the terminal (default off). number_pad Use the number keys to move instead of [yuhjklbn] (default 0 or off). (number_pad:2 invokes the old DOS behavior where `5' means `g', meta-`5' means `G', and meta-`0' means `I'.) objects Set the characters used to display object classes (default ``])[="(%!?+/$*`0_.''). This string is subjected to the same processing as the dungeon option. The order of the symbols is illegal-object (should never be seen), weapon, armor, ring, amulet, tool, food, potion, scroll, spellbook, wand, gold, gem or rock, boulder or statue, iron ball, chain, and venom. Can- not be set with the `O' command. packorder Specify the order to list object types in (default ``")[%?+!=/(*`0_''). The value of this option should be a string containing the symbols for the various object types. Any omitted types are filled in at the end from the previous order. perm_invent If true, always display your current inventory in a window. This only makes sense for windowing system interfaces that im- plement this feature. pettype Specify the type of your initial pet, if you are playing a character class that uses multiple types of pets; or choose to have no initial pet at all. Possible values are ``cat'', ``dog'' and ``none''. Cannot be set with the `O' command. pickup_burden When you pick up an item that would exceed this encumbrance level (Unburdened, Burdened, streSsed, straiNed, overTaxed, or overLoaded), you will be asked if you want to continue. (De- fault `S'). pickup_types Specify the object types to be picked up when autopickup is on. Default is all types. If your copy of the game has the experi- mental compile time option AUTOPICKUP_EXCEPTIONS included, you may be able to use autopickup_exception configuration file lines to further refine autopickup behavior. NetHack 3.4 December 2, 2003 NetHack Guidebook 41 prayconfirm Prompt for confirmation before praying (default on). pushweapon Using the `w' (wield) command when already wielding something pushes the old item into your alternate weapon slot (default off). race Selects your race (for example, ``race:human''). Default is random. Cannot be set with the `O' command. rest_on_space Make the space bar a synonym for the `.' (rest) command (de- fault off). role Pick your type of character (ex. ``role:Samurai''); synonym for ``character''. See ``name'' for an alternate method of speci- fying your role. Normally only the first letter of the value is examined; `r' is an exception with ``Rogue'', ``Ranger'', and ``random'' values. runmode Controls the amount of screen updating for the map window when engaged in multi-turn movement (running via shift+direction or control+direction and so forth, or via the travel command or mouse click). The possible values are: teleport - update the map after movement has finished; run - update the map after every seven or so steps; walk - update the map after each step; crawl - like walk, but pause briefly after each step. This option only affects the game's screen display, not the ac- tual results of moving. The default is `run'; versions prior to 3.4.1 used `teleport' only. Whether or not the effect is noticeable will depend upon the window port used or on the type of terminal. safe_pet Prevent you from (knowingly) attacking your pets (default on). scores Control what parts of the score list you are shown at the end (ex. ``scores:5 top scores/4 around my score/own scores''). Only the first letter of each category (`t', `a', or `o') is necessary. showexp Show your accumulated experience points on bottom line (default off). NetHack 3.4 December 2, 2003 NetHack Guidebook 42 showrace Display yourself as the glyph for your race, rather than the glyph for your role (default off). Note that this setting af- fects only the appearance of the display, not the way the game treats you. showscore Show your approximate accumulated score on bottom line (default off). silent Suppress terminal beeps (default on). sortpack Sort the pack contents by type when displaying inventory (de- fault on). sound Enable messages about what your character hears (default on). Note that this has nothing to do with your computer's audio ca- pabilities. This option is only partly under player control. The game toggles it off and on during and after sleep, for ex- ample. sparkle Display a sparkly effect when a monster (including yourself) is hit by an attack to which it is resistant (default on). standout Boldface monsters and ``--More--'' (default off). suppress_alert This option may be set to a NetHack version level to suppress alert notification messages about feature changes for that and prior versions (ex. ``suppress_alert:3.3.1''). time Show the elapsed game time in turns on bottom line (default off). timed_delay When pausing momentarily for display effect, such as with ex- plosions and moving objects, use a timer rather than sending extra characters to the screen. (Applies to ``tty'' interface only; ``X11'' interface always uses a timer based delay. The default is on if configured into the program.) tombstone Draw a tombstone graphic upon your death (default on). toptenwin Put the ending display in a NetHack window instead of on stdout (default off). Setting this option makes the score list visi- ble when a windowing version of NetHack is started without a NetHack 3.4 December 2, 2003 NetHack Guidebook 43 parent window, but it no longer leaves the score list around after game end on a terminal or emulating window. traps Set the graphics symbols for displaying traps (default ``^^^^^^^^^^^^^^^^^"^^^^''). The traps option should be fol- lowed by a string of 1-22 characters to be used instead of the default traps characters. This string is subjected to the same processing as the dungeon option. The order of the symbols is: arrow trap, dart trap, falling rock trap, squeaky board, bear trap, land mine, rolling boulder trap, sleeping gas trap, rust trap, fire trap, pit, spiked pit, hole, trap door, teleportation trap, level teleporter, magic portal, web, statue trap, magic trap, anti-magic field, poly- morph trap. Cannot be set with the `O' command. travel Allow the travel command (default on). Turning this option off will prevent the game from attempting unintended moves if you make inadvertent mouse clicks on the map window. verbose Provide more commentary during the game (default on). windowtype Select which windowing system to use, such as ``tty'' or ``X11'' (default depends on version). Cannot be set with the `O' command. 9.5. Window Port Customization options Here are explanations of the various options that are used to customize and change the characteristics of the windowtype that you have chosen. Character strings that are too long may be truncated. Not all window ports will adjust for all settings listed here. You can safely add any of these options to your config file, and if the window port is capable of adjusting to suit your preferences, it will attempt to do so. If it can't it will silently ignore it. You can find out if an option is sup- ported by the window port that you are currently using by check- ing to see if it shows up in the Options list. Some options are dynamic and can be specified during the game with the `O' com- mand. align_message Where to align or place the message window (top, bottom, left, or right) align_status Where to align or place the status window (top, bottom, left, or right). NetHack 3.4 December 2, 2003 NetHack Guidebook 44 ascii_map NetHack should display an ascii character map if it can. color NetHack should display color if it can for different monsters, objects, and dungeon features eight_bit_tty NetHack should pass eight-bit character values (for example, specified with the traps option) straight through to your ter- minal (default off). font_map NetHack should use a font by the chosen name for the map win- dow. font_menu NetHack should use a font by the chosen name for menu windows. font_message NetHack should use a font by the chosen name for the message window. font_status NetHack should use a font by the chosen name for the status window. font_text NetHack should use a font by the chosen name for text windows. font_size_map NetHack should use this size font for the map window. font_size_menu NetHack should use this size font for menu windows. font_size_message NetHack should use this size font for the message window. font_size_status NetHack should use this size font for the status window. font_size_text NetHack should use this size font for text windows. fullscreen NetHack should try and display on the entire screen rather than in a window. hilite_pet Visually distinguish pets from similar animals (default off). The behavior of this option depends on the type of windowing you use. In text windowing, text highlighting or inverse video is often used; with tiles, generally displays a heart symbol NetHack 3.4 December 2, 2003 NetHack Guidebook 45 near pets. large_font NetHack should use a large font. map_mode NetHack should display the map in the manner specified. mouse_support Allow use of the mouse for input and travel. player_selection NetHack should pop up dialog boxes, or use prompts for charac- ter selection. popup_dialog NetHack should pop up dialog boxes for input. preload_tiles NetHack should preload tiles into memory. For example, in the protected mode MSDOS version, control whether tiles get pre- loaded into RAM at the start of the game. Doing so enhances performance of the tile graphics, but uses more memory. (de- fault on). Cannot be set with the `O' command. scroll_amount NetHack should scroll the display by this number of cells when the hero reaches the scroll_margin. scroll_margin NetHack should scroll the display when the hero or cursor is this number of cells away from the edge of the window. softkeyboard Display an onscreen keyboard. Handhelds are most likely to support this option. splash_screen NetHack should display an opening splash screen when it starts up (default yes). tiled_map NetHack should display a tiled map if it can. tile_file Specify the name of an alternative tile file to override the default. tile_height Specify the preferred height of each tile in a tile capable port. tile_width Specify the preferred width of each tile in a tile capable port NetHack 3.4 December 2, 2003 NetHack Guidebook 46 use_inverse NetHack should display inverse when the game specifies it. vary_msgcount NetHack should display this number of messages at a time in the message window. windowcolors NetHack should display windows with the specified fore- ground/background colors if it can. wraptext NetHack port should wrap long lines of text if they don't fit in the visible area of the window. 9.6. Platform-specific Customization options Here are explanations of options that are used by specific platforms or ports to customize and change the port behavior. altkeyhandler Select an alternate keystroke handler dll to load (Win32 tty NetHack only). The name of the handler is specified without the .dll extension and without any path information. Cannot be set with the `O' command. altmeta (default on, AMIGA NetHack only). BIOS Use BIOS calls to update the screen display quickly and to read the keyboard (allowing the use of arrow keys to move) on ma- chines with an IBM PC compatible BIOS ROM (default off, OS/2, PC, and ST NetHack only). flush (default off, AMIGA NetHack only). MACgraphics (default on, Mac NetHack only). page_wait (default on, Mac NetHack only). rawio Force raw (non-cbreak) mode for faster output and more bullet- proof input (MS-DOS sometimes treats `^P' as a printer toggle without it) (default off, OS/2, PC, and ST NetHack only). Note: DEC Rainbows hang if this is turned on. Cannot be set with the `O' command. soundcard (default on, PC NetHack only). Cannot be set with the `O' com- mand. NetHack 3.4 December 2, 2003 NetHack Guidebook 47 subkeyvalue (Win32 tty NetHack only). May be used to alter the value of keystrokes that the operating system returns to NetHack to help compensate for international keyboard issues. OPTIONS=subkey- value:171/92 will return 92 to NetHack, if 171 was originally going to be returned. You can use multiple subkeyvalue state- ments in the config file if needed. Cannot be set with the `O' command. video Set the video mode used (PC NetHack only). Values are `autode- tect', `default', or `vga'. Setting `vga' (or `autodetect' with vga hardware present) will cause the game to display tiles. Cannot be set with the `O' command. videocolors Set the color palette for PC systems using NO_TERMS (default 4-2-6-1-5-3-15-12-10-14-9-13-11, (PC NetHack only). The order of colors is red, green, brown, blue, magenta, cyan, bright.white, bright.red, bright.green, yellow, bright.blue, bright.magenta, and bright.cyan. Cannot be set with the `O' command. videoshades Set the intensity level of the three gray scales available (de- fault dark normal light, PC NetHack only). If the game display is difficult to read, try adjusting these scales; if this does not correct the problem, try !color. Cannot be set with the `O' command. 9.7. Configuring autopickup exceptions There is an experimental compile time option called AU- TOPICKUP_EXCEPTIONS. If your copy of the game was built with that option defined, you can further refine the behavior of the autopickup option beyond what is available through the pick- up_types option. By placing autopickup_exception lines in your configuration file, you can define patterns to be checked when the game is about to autopickup something. autopickup_exception Sets an exception to the pickup_types option. The autopick- up_exception option should be followed by a string of 1-80 characters to be used as a pattern to match against the singu- lar form of the description of an object at your location. You may use the following special characters in a pattern: *--- matches 0 or more characters. ?--- matches any single character. NetHack 3.4 December 2, 2003 NetHack Guidebook 48 In addition, some characters are treated specially if they occur as the first character in the string pattern, specifically: < - always pickup an object that matches the pattern that follows. > - never pickup an object that matches the pattern that follows. Can be set with the `O' command, but the setting is not pre- served across saves and restores. Here's a couple of examples of autopickup_exceptions: autopickup_exception="<*arrow" autopickup_exception=">*corpse" autopickup_exception=">* cursed*" The first example above will result in autopickup of any type of arrow. The second example results in the exclusion of any corpse from autopickup. The last example results in the exclusion of items known to be cursed from autopickup. A `never pickup' rule takes precedence over an `always pickup' rule if both match. 9.8. Configuring User Sounds Some platforms allow you to define sound files to be played when a message that matches a user-defined pattern is delivered to the message window. At this time the Qt port and the win32tty and win32gui ports support the use of user sounds. The following config file entries are relevant to mapping user sounds to messages: SOUNDDIR The directory that houses the sound files to be played. SOUND An entry that maps a sound file to a user-specified message pattern. Each SOUND entry is broken down into the following parts: MESG - message window mapping (the only one supported in 3.4). pattern - the pattern to match. sound file - the sound file to play. volume - the volume to be set while playing the sound file. The exact format for the pattern depends on whether the platform is built to use ``regular expressions'' or NetHack's own internal pattern matching facility. The ``regular expressions'' matching can be much more sophisticated than the internal NetHack pattern matching, but requires 3rd party libraries on some plat- forms. There are plenty of references available elsewhere for explaining ``regular expressions''. You can verify which pattern matching is used by your port with the #version command. NetHack 3.4 December 2, 2003 NetHack Guidebook 49 NetHack's internal pattern matching routine uses the follow- ing special characters in its pattern matching: *--- matches 0 or more characters. ?--- matches any single character. Here's an example of a sound mapping using NetHack's inter- nal pattern matching facility: SOUND=MESG "*chime of a cash register*" "gong.wav" 50 specifies that any message with "chime of a cash register" con- tained in it will trigger the playing of "gong.wav". You can have multiple SOUND entries in your config file. 9.9. Configuring NetHack for Play by the Blind NetHack can be set up to use only standard ASCII characters for making maps of the dungeons. This makes the MS-DOS versions of NetHack completely accessible to the blind who use speech and/or Braille access technologies. Players will require a good working knowledge of their screen-reader's review features, and will have to know how to navigate horizontally and vertically character by character. They will also find the search capabili- ties of their screen-readers to be quite valuable. Be certain to examine this Guidebook before playing so you have an idea what the screen layout is like. You'll also need to be able to locate the PC cursor. It is always where your character is located. Merely searching for an @-sign will not always find your charac- ter since there are other humanoids represented by the same sign. Your screen-reader should also have a function which gives you the row and column of your review cursor and the PC cursor. These co-ordinates are often useful in giving players a better sense of the overall location of items on the screen. While it is not difficult for experienced users to edit the defaults.nh file to accomplish this, novices may find this task somewhat daunting. Included in all official distributions of NetHack is a file called NHAccess.nh. Replacing defaults.nh with this file will cause the game to run in a manner accessible to the blind. After you have gained some experience with the game and with editing files, you may want to alter settings to better suit your preferences. Instructions on how to do this are includ- ed in the NHAccess.nh file itself. The most crucial settings to make the game accessible are: IBMgraphics Disable IBMgraphics by commenting out this option. menustyle:traditional This will assist in the interface to speech synthesizers. number_pad A lot of speech access programs use the number-pad to review NetHack 3.4 December 2, 2003 NetHack Guidebook 50 the screen. If this is the case, disable the number_pad option and use the traditional Rogue-like commands. Character graphics Comment out all character graphics sets found near the bottom of the defaults.nh file. Most of these replace NetHack's de- fault representation of the dungeon using standard ASCII char- acters with fancier characters from extended character sets, and these fancier characters can annoy screen-readers. 10. Scoring NetHack maintains a list of the top scores or scorers on your machine, depending on how it is set up. In the latter case, each account on the machine can post only one non-winning score on this list. If you score higher than someone else on this list, or better your previous score, you will be inserted in the proper place under your current name. How many scores are kept can also be set up when NetHack is compiled. Your score is chiefly based upon how much experience you gained, how much loot you accumulated, how deep you explored, and how the game ended. If you quit the game, you escape with all of your gold intact. If, however, you get killed in the Mazes of Menace, the guild will only hear about 90% of your gold when your corpse is discovered (adventurers have been known to collect finder's fees). So, consider whether you want to take one last hit at that monster and possibly live, or quit and stop with whatever you have. If you quit, you keep all your gold, but if you swing and live, you might find more. If you just want to see what the current top players/games list is, you can type nethack -s all on most versions. 11. Explore mode NetHack is an intricate and difficult game. Novices might falter in fear, aware of their ignorance of the means to survive. Well, fear not. Your dungeon may come equipped with an ``ex- plore'' or ``discovery'' mode that enables you to keep old save files and cheat death, at the paltry cost of not getting on the high score list. There are two ways of enabling explore mode. One is to start the game with the -X switch. The other is to issue the `X' command while already playing the game. The other benefits of explore mode are left for the trepid reader to discover. 12. Credits The original hack game was modeled on the Berkeley UNIX rogue game. Large portions of this paper were shamelessly NetHack 3.4 December 2, 2003 NetHack Guidebook 51 cribbed from A Guide to the Dungeons of Doom, by Michael C. Toy and Kenneth C. R. C. Arnold. Small portions were adapted from Further Exploration of the Dungeons of Doom, by Ken Arromdee. NetHack is the product of literally dozens of people's work. Main events in the course of the game development are described below: Jay Fenlason wrote the original Hack, with help from Kenny Woodland, Mike Thome and Jon Payne. Andries Brouwer did a major re-write, transforming Hack into a very different game, and published (at least) three versions (1.0.1, 1.0.2, and 1.0.3) for UNIX machines to the Usenet. Don G. Kneller ported Hack 1.0.3 to Microsoft C and MS-DOS, producing PC HACK 1.01e, added support for DEC Rainbow graphics in version 1.03g, and went on to produce at least four more ver- sions (3.0, 3.2, 3.51, and 3.6). R. Black ported PC HACK 3.51 to Lattice C and the Atari 520/1040ST, producing ST Hack 1.03. Mike Stephenson merged these various versions back together, incorporating many of the added features, and produced NetHack 1.4. He then coordinated a cast of thousands in enhancing and debugging NetHack 1.4 and released NetHack versions 2.2 and 2.3. Later, Mike coordinated a major rewrite of the game, heading a team which included Ken Arromdee, Jean-Christophe Collet, Steve Creps, Eric Hendrickson, Izchak Miller, John Rupley, Mike Threep- oint, and Janet Walz, to produce NetHack 3.0c. NetHack 3.0 was ported to the Atari by Eric R. Smith, to OS/2 by Timo Hakulinen, and to VMS by David Gentzel. The three of them and Kevin Darcy later joined the main development team to produce subsequent revisions of 3.0. Olaf Seibert ported NetHack 2.3 and 3.0 to the Amiga. Norm Meluch, Stephen Spackman and Pierre Martineau designed overlay code for PC NetHack 3.0. Johnny Lee ported NetHack 3.0 to the Macintosh. Along with various other Dungeoneers, they continued to enhance the PC, Macintosh, and Amiga ports through the later revisions of 3.0. Headed by Mike Stephenson and coordinated by Izchak Miller and Janet Walz, the development team which now included Ken Ar- romdee, David Cohrs, Jean-Christophe Collet, Kevin Darcy, Matt Day, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Raymond, and Eric Smith undertook a radical revision of 3.0. They re-structured the game's design, and re-wrote major parts of the code. They added multiple dungeons, a new display, special individual character quests, a new endgame and many other new NetHack 3.4 December 2, 2003 NetHack Guidebook 52 features, and produced NetHack 3.1. Ken Lorber, Gregg Wonderly and Greg Olson, with help from Richard Addison, Mike Passaretti, and Olaf Seibert, developed NetHack 3.1 for the Amiga. Norm Meluch and Kevin Smolkowski, with help from Carl Sche- lin, Stephen Spackman, Steve VanDevender, and Paul Winner, ported NetHack 3.1 to the PC. Jon W{tte and Hao-yang Wang, with help from Ross Brown, Mike Engber, David Hairston, Michael Hamel, Jonathan Handler, Johnny Lee, Tim Lennan, Rob Menke, and Andy Swanson, developed NetHack 3.1 for the Macintosh, porting it for MPW. Building on their de- velopment, Barton House added a Think C port. Timo Hakulinen ported NetHack 3.1 to OS/2. Eric Smith port- ed NetHack 3.1 to the Atari. Pat Rankin, with help from Joshua Delahunty, was responsible for the VMS version of NetHack 3.1. Michael Allison ported NetHack 3.1 to Windows NT. Dean Luick, with help from David Cohrs, developed NetHack 3.1 for X11. Warwick Allison wrote a tiled version of NetHack for the Atari; he later contributed the tiles to the DevTeam and tile support was then added to other platforms. The 3.2 development team, comprised of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Steve Linhart, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, released version 3.2 in April of 1996. Version 3.2 marked the tenth anniversary of the formation of the development team. In a testament to their dedication to the game, all thirteen members of the original development team re- mained on the team at the start of work on that release. During the interval between the release of 3.1.3 and 3.2, one of the founding members of the development team, Dr. Izchak Miller, was diagnosed with cancer and passed away. That release of the game was dedicated to him by the development and porting teams. During the lifespan of NetHack 3.1 and 3.2, several enthusi- asts of the game added their own modifications to the game and made these ``variants'' publicly available: Tom Proudfoot and Yuval Oren created NetHack++, which was quickly renamed NetHack--. Working independently, Stephen White wrote NetHack Plus. Tom Proudfoot later merged NetHack Plus and his own NetHack-- to produce SLASH. Larry Stewart-Zerba and War- wick Allison improved the spell casting system with the Wizard Patch. Warwick Allison also ported NetHack to use the Qt inter- face. NetHack 3.4 December 2, 2003 NetHack Guidebook 53 Warren Cheung combined SLASH with the Wizard Patch to pro- duce Slash'em, and with the help of Kevin Hugo, added more fea- tures. Kevin later joined the DevTeam and incorporated the best of these ideas in NetHack 3.3. The final update to 3.2 was the bug fix release 3.2.3, which was released simultaneously with 3.3.0 in December 1999 just in time for the Year 2000. The 3.3 development team, consisting of Michael Allison, Ken Arromdee, David Cohrs, Jessie Collet, Steve Creps, Kevin Darcy, Timo Hakulinen, Kevin Hugo, Steve Linhart, Ken Lorber, Dean Luick, Pat Rankin, Eric Smith, Mike Stephenson, Janet Walz, and Paul Winner, released 3.3.0 in December 1999 and 3.3.1 in August of 2000. Version 3.3 offered many firsts. It was the first version to separate race and profession. The Elf class was removed in pref- erence to an elf race, and the races of dwarves, gnomes, and orcs made their first appearance in the game alongside the familiar human race. Monk and Ranger roles joined Archeologists, Barbar- ians, Cavemen, Healers, Knights, Priests, Rogues, Samurai, Tourists, Valkyries and of course, Wizards. It was also the first version to allow you to ride a steed, and was the first version to have a publicly available web-site listing all the bugs that had been discovered. Despite that constantly growing bug list, 3.3 proved stable enough to last for more than a year and a half. The 3.4 development team initially consisted of Michael Al- lison, Ken Arromdee, David Cohrs, Jessie Collet, Kevin Hugo, Ken Lorber, Dean Luick, Pat Rankin, Mike Stephenson, Janet Walz, and Paul Winner, with Warwick Allison joining just before the re- lease of NetHack 3.4.0 in March 2002. As with version 3.3, various people contributed to the game as a whole as well as supporting ports on the different platforms that NetHack runs on: Pat Rankin maintained 3.4 for VMS. Michael Allison maintained NetHack 3.4 for the MS-DOS plat- form. Paul Winner and Yitzhak Sapir provided encouragement. Dean Luick, Mark Modrall, and Kevin Hugo maintained and en- hanced the Macintosh port of 3.4. Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, and Yitzhak Sapir maintained and enhanced 3.4 for the Microsoft Windows platform. Alex Kompel contributed a new graphical inter- face for the Windows port. Alex Kompel also contributed a Win- dows CE port for 3.4.1. NetHack 3.4 December 2, 2003 NetHack Guidebook 54 Ron Van Iwaarden maintained 3.4 for OS/2. Janne Salmijarvi and Teemu Suikki maintained and enhanced the Amiga port of 3.4 after Janne Salmijarvi resurrected it for 3.3.1. Christian ``Marvin'' Bressler maintained 3.4 for the Atari after he resurrected it for 3.3.1. There is a NetHack web site maintained by Ken Lorber at http://www.nethack.org/. - - - - - - - - - - From time to time, some depraved individual out there in netland sends a particularly intriguing modification to help out with the game. The Gods of the Dungeon sometimes make note of the names of the worst of these miscreants in this, the list of Dungeoneers: NetHack 3.4 December 2, 2003 NetHack Guidebook 55 Adam Aronow Izchak Miller Mike Stephenson Alex Kompel J. Ali Harlow Norm Meluch Andreas Dorn Janet Walz Olaf Seibert Andy Church Janne Salmijarvi Pasi Kallinen Andy Swanson Jean-Christophe Collet Pat Rankin Ari Huttunen Jochen Erwied Paul Winner Barton House John Kallen Pierre Martineau Benson I. Margulies John Rupley Ralf Brown Bill Dyer John S. Bien Ray Chason Boudewijn Waijers Johnny Lee Richard Addison Bruce Cox Jon W{tte Richard Beigel Bruce Holloway Jonathan Handler Richard P. Hughey Bruce Mewborne Joshua Delahunty Rob Menke Carl Schelin Keizo Yamamoto Robin Johnson Chris Russo Ken Arnold Roderick Schertler David Cohrs Ken Arromdee Roland McGrath David Damerell Ken Lorber Ron Van Iwaarden David Gentzel Ken Washikita Ronnen Miller David Hairston Kevin Darcy Ross Brown Dean Luick Kevin Hugo Sascha Wostmann Del Lamb Kevin Sitze Scott Bigham Deron Meranda Kevin Smolkowski Scott R. Turner Dion Nicolaas Kevin Sweet Stephen Spackman Dylan O'Donnell Lars Huttar Stephen White Eric Backus Malcolm Ryan Steve Creps Eric Hendrickson Mark Gooderum Steve Linhart Eric R. Smith Mark Modrall Steve VanDevender Eric S. Raymond Marvin Bressler Teemu Suikki Erik Andersen Matthew Day Tim Lennan Frederick Roeber Merlyn LeRoy Timo Hakulinen Gil Neiger Michael Allison Tom Almy Greg Laskin Michael Feir Tom West Greg Olson Michael Hamel Warren Cheung Gregg Wonderly Michael Sokolov Warwick Allison Hao-yang Wang Mike Engber Yitzhak Sapir Helge Hafting Mike Gallop Irina Rempt-Drijfhout Mike Passaretti Brand and product names are trademarks or registered trademarks of their respective holders. NetHack 3.4 December 2, 2003 nethack-3.4.3/doc/dgn_comp.60100644000000000000000000001575407764735041014310 0ustar rootroot.TH DGN_COMP 6 "12 Dec 1995" .UC 4 .SH NAME dgn_comp \- NetHack dungeon compiler .SH SYNOPSIS .B dgn_comp [ .I file ] .PP If no arguments are given, it reads standard input. .SH DESCRIPTION .PP .I Dgn_comp is a dungeon compiler for NetHack version 3.2 and higher. It takes a description file as an argument and produces a dungeon "script" that is to be loaded by NetHack at runtime. .PP The purpose of this tool is to provide NetHack administrators and implementors with a convenient way to create a custom dungeon for the game, without having to recompile the entire world. .SH GRAMMAR .PP DUNGEON: .B name .B bonesmarker ( .B base , .B rand ) [ .B %age ] .PP where .B name is the dungeon name, .B bonesmarker is a letter for marking bones files, ( .B base , .B rand ) is the number of levels, and .B %age is its percentage chance of being generated (if absent, 100% chance). DESCRIPTION: .B tag .PP where .B tag is currently one of .BR HELLISH , .BR MAZELIKE , or .BR ROGUELIKE . ALIGNMENT | LEVALIGN: [ .B lawful | .B neutral | .B chaotic | .B unaligned ] .PP gives the alignment of the dungeon/level (default is unaligned). ENTRY: .B level .PP the dungeon entry point. The dungeon connection attaches at this level of the given dungeon. If the value of .B level is negative, the entry level is calculated from the bottom of the dungeon, with -1 being the last level. If this line is not present in a dungeon description, the entry level defaults to 1. PROTOFILE: .B name .PP the prototypical name for dungeon level files in this dungeon. For example, the PROTOFILE name for the dungeon .I Vlad's Tower is .IR tower . LEVEL: .B name .B bonesmarker @ ( .B base , .B rand ) [ .B %age ] .PP where .B name is the level name, .B bonesmarker is a letter for marking bones files, ( .B base , .B rand ) is the location and .B %age is the generation percentage, as above. RNDLEVEL: .B name .B bonesmarker @ ( .B base , .B rand ) [ .B %age ] .B rndlevs .PP where .B name is the level name, .B bonesmarker is a letter for marking bones files, ( .B base , .B rand ) is the location, .B %age is the generation percentage, as above, and .B rndlevs is the number of similar levels available to choose from. CHAINLEVEL: .B name .B bonesmarker .B prev_name + ( .B base , .B rand ) [ .B %age ] .PP where .B name is the level name, .B bonesmarker is a letter for marking bones files, .B prev_name is the name of a level defined previously, ( .B base , .B rand ) is the .I offset from the level being chained from, and .B %age is the generation percentage. RNDCHAINLEVEL: .B name .B bonesmarker .B prev_name + ( .B base , .B rand ) [ .B %age ] .B rndlevs .PP where .B name is the level name, .B bonesmarker is a letter for marking bones files, .B prev_name is the name of a level defined previously, ( .B base , .B rand ) is the .I offset from the level being chained from, .B %age is the generation percentage, and .B rndlevs is the number of similar levels available to choose from. LEVELDESC: .B type .PP where .B type is the level type, (see DESCRIPTION, above). The .B type is used to override any pre-set value used to describe the entire dungeon, for this level only. BRANCH: .B name @ ( .B base , .B rand ) [ .B stair | .B no_up | .B no_down | .B portal ] [ .B up | .B down ] .PP where .B name is the name of the dungeon to branch to, and ( .B base , .B rand ) is the location of the branch. The last two optional arguments are the branch type and branch direction. The type of a branch can be a two-way stair connection, a one-way stair connection, or a magic portal. A one-way stair is described by the types .B no_up and .B no_down which specify which stair direction is missing. The default branch type is .BR stair . The direction for a stair can be either up or down; direction is not applicable to portals. The default direction is .BR down . CHAINBRANCH: .B name .B prev_name + ( .B base , .B rand ) [ .B stair | .B no_up | .B no_down | .B portal ] [ .B up | .B down ] .PP where .B name is the name of the dungeon to branch to, .B prev_name is the name of a previously defined .B level and ( .B base , .B rand ) is the .I offset from the level being chained from. The optional branch type and direction are the same as described above. .SH GENERIC RULES .PP Each dungeon must have a unique .B bonesmarker , and each special level must have a .B bonesmarker unique within its dungeon (letters may be reused in different dungeons). If the .B bonesmarker has the special value "none", no bones files will be created for that level or dungeon. .PP The value .B base may be in the range of 1 to .B MAXLEVEL (as defined in .I global.h ). .PP The value .B rand may be in the range of -1 to .BR MAXLEVEL . .PP If .B rand is -1 it will be replaced with the value (num_dunlevs(dungeon) - base) during the load process (ie. from here to the end of the dungeon). .PP If .B rand is 0 the level is located absolutely at .BR base . .PP Branches don't have a probability. Dungeons do. If a dungeon fails to be generated during load, all its levels and branches are skipped. .PP No level or branch may be chained from a level with a percentage generation probability. This is to prevent non-resolution during the load. In addition, no branch may be made from a dungeon with a percentage generation probability for the same reason. .PP As a general rule using the dungeon compiler: .PP If a dungeon has a .B protofile name associated with it .RI ( eg. .BR tower ) that file will be used. .PP If a special level is present, it will override the above rule and the appropriate file will be loaded. .PP If neither of the above are present, the standard generator will take over and make a "normal" level. .PP A level alignment, if present, will override the alignment of the dungeon that it exists within. .SH EXAMPLE .PP Here is the current syntax of the dungeon compiler's "language": .LP .nf .ta +8n +8n +8n # # The dungeon description file for the "standard" original # 3.0 NetHack. # DUNGEON: "The Dungeons of Doom" "D" (25, 5) LEVEL: "rogue" "none" @ (15, 4) LEVEL: "oracle" "none" @ (5, 7) LEVEL: "bigroom" "B" @ (12, 3) 15 LEVEL: "medusa" "none" @ (20, 5) CHAINLEVEL: "castle" "medusa" + (1, 4) CHAINBRANCH: "Hell" "castle" + (0, 0) no_down BRANCH: "The Astral Plane" @ (1, 0) no_down up DUNGEON: "Hell" "H" (25, 5) DESCRIPTION: mazelike DESCRIPTION: hellish BRANCH: "Vlad's Tower" @ (13, 5) up LEVEL: "wizard" "none" @ (15, 10) LEVEL: "fakewiz" "A" @ (5, 5) LEVEL: "fakewiz" "B" @ (10, 5) LEVEL: "fakewiz" "C" @ (15, 5) LEVEL: "fakewiz" "D" @ (20, 5) LEVEL: "fakewiz" "E" @ (25, 5) DUNGEON: "Vlad's Tower" "T" (3, 0) PROTOFILE: "tower" DESCRIPTION: mazelike ENTRY: -1 DUNGEON: "The Astral Plane" "A" (1, 0) DESCRIPTION: mazelike PROTOFILE: "endgame" .fi .PP .I NOTES: .br Lines beginning with '#' are considered comments. .br A special level must be explicitly aligned. The alignment of the dungeon it is in only applies to non-special levels within that dungeon. .SH AUTHOR .PP M. Stephenson (from the level compiler by Jean-Christophe Collet). .SH "SEE ALSO" .PP lev_comp(6), nethack(6) .SH BUGS .PP Probably infinite. nethack-3.4.3/doc/dgn_comp.txt0100644000000000000000000002045407764735041014753 0ustar rootroot DGN_COMP(6) 1995 DGN_COMP(6) NAME dgn_comp - NetHack dungeon compiler SYNOPSIS dgn_comp [ file ] If no arguments are given, it reads standard input. DESCRIPTION Dgn_comp is a dungeon compiler for NetHack version 3.2 and higher. It takes a description file as an argument and pro- duces a dungeon "script" that is to be loaded by NetHack at runtime. The purpose of this tool is to provide NetHack administra- tors and implementors with a convenient way to create a cus- tom dungeon for the game, without having to recompile the entire world. GRAMMAR DUNGEON: name bonesmarker ( base , rand ) [ %age ] where name is the dungeon name, bonesmarker is a letter for marking bones files, ( base , rand ) is the number of lev- els, and %age is its percentage chance of being generated (if absent, 100% chance). DESCRIPTION: tag where tag is currently one of HELLISH, MAZELIKE, or ROGUE- LIKE. ALIGNMENT | LEVALIGN: [ lawful | neutral | chaotic | unaligned ] gives the alignment of the dungeon/level (default is unaligned). ENTRY: level the dungeon entry point. The dungeon connection attaches at this level of the given dungeon. If the value of level is negative, the entry level is calculated from the bottom of the dungeon, with -1 being the last level. If this line is not present in a dungeon description, the entry level defaults to 1. PROTOFILE: name the prototypical name for dungeon level files in this dungeon. For example, the PROTOFILE name for the dungeon Vlad's Tower is tower. Dec Last change: 12 1 DGN_COMP(6) 1995 DGN_COMP(6) LEVEL: name bonesmarker @ ( base , rand ) [ %age ] where name is the level name, bonesmarker is a letter for marking bones files, ( base , rand ) is the location and %age is the generation percentage, as above. RNDLEVEL: name bonesmarker @ ( base , rand ) [ %age ] rndlevs where name is the level name, bonesmarker is a letter for marking bones files, ( base , rand ) is the location, %age is the generation percentage, as above, and rndlevs is the number of similar levels available to choose from. CHAINLEVEL: name bonesmarker prev_name + ( base , rand ) [ %age ] where name is the level name, bonesmarker is a letter for marking bones files, prev_name is the name of a level defined previously, ( base , rand ) is the offset from the level being chained from, and %age is the generation percen- tage. RNDCHAINLEVEL: name bonesmarker prev_name + ( base , rand ) [ %age ] rndlevs where name is the level name, bonesmarker is a letter for marking bones files, prev_name is the name of a level defined previously, ( base , rand ) is the offset from the level being chained from, %age is the generation percentage, and rndlevs is the number of similar levels available to choose from. LEVELDESC: type where type is the level type, (see DESCRIPTION, above). The type is used to override any pre-set value used to describe the entire dungeon, for this level only. BRANCH: name @ ( base , rand ) [ stair | no_up | no_down | portal ] [ up | down ] where name is the name of the dungeon to branch to, and ( base , rand ) is the location of the branch. The last two optional arguments are the branch type and branch direction. The type of a branch can be a two-way stair connection, a one-way stair connection, or a magic portal. A one-way stair is described by the types no_up and no_down which specify which stair direction is missing. The default branch type is stair. The direction for a stair can be either up or down; direction is not applicable to portals. The default direction is down. Dec Last change: 12 2 DGN_COMP(6) 1995 DGN_COMP(6) CHAINBRANCH: name prev_name + ( base , rand ) [ stair | no_up | no_down | portal ] [ up | down ] where name is the name of the dungeon to branch to, prev_name is the name of a previously defined level and ( base , rand ) is the offset from the level being chained from. The optional branch type and direction are the same as described above. GENERIC RULES Each dungeon must have a unique bonesmarker , and each spe- cial level must have a bonesmarker unique within its dungeon (letters may be reused in different dungeons). If the bonesmarker has the special value "none", no bones files will be created for that level or dungeon. The value base may be in the range of 1 to MAXLEVEL (as defined in global.h ). The value rand may be in the range of -1 to MAXLEVEL. If rand is -1 it will be replaced with the value (num_dunlevs(dungeon) - base) during the load process (ie. from here to the end of the dungeon). If rand is 0 the level is located absolutely at base. Branches don't have a probability. Dungeons do. If a dungeon fails to be generated during load, all its levels and branches are skipped. No level or branch may be chained from a level with a per- centage generation probability. This is to prevent non- resolution during the load. In addition, no branch may be made from a dungeon with a percentage generation probability for the same reason. As a general rule using the dungeon compiler: If a dungeon has a protofile name associated with it (eg. tower) that file will be used. If a special level is present, it will override the above rule and the appropriate file will be loaded. If neither of the above are present, the standard generator will take over and make a "normal" level. A level alignment, if present, will override the alignment of the dungeon that it exists within. Dec Last change: 12 3 DGN_COMP(6) 1995 DGN_COMP(6) EXAMPLE Here is the current syntax of the dungeon compiler's "language": # # The dungeon description file for the "standard" original # 3.0 NetHack. # DUNGEON: "The Dungeons of Doom" "D" (25, 5) LEVEL: "rogue" "none" @ (15, 4) LEVEL: "oracle" "none" @ (5, 7) LEVEL: "bigroom" "B" @ (12, 3) 15 LEVEL: "medusa" "none" @ (20, 5) CHAINLEVEL: "castle" "medusa" + (1, 4) CHAINBRANCH: "Hell" "castle" + (0, 0) no_down BRANCH: "The Astral Plane" @ (1, 0) no_down up DUNGEON: "Hell" "H" (25, 5) DESCRIPTION: mazelike DESCRIPTION: hellish BRANCH: "Vlad's Tower" @ (13, 5) up LEVEL: "wizard" "none" @ (15, 10) LEVEL: "fakewiz" "A" @ (5, 5) LEVEL: "fakewiz" "B" @ (10, 5) LEVEL: "fakewiz" "C" @ (15, 5) LEVEL: "fakewiz" "D" @ (20, 5) LEVEL: "fakewiz" "E" @ (25, 5) DUNGEON: "Vlad's Tower" "T" (3, 0) PROTOFILE: "tower" DESCRIPTION: mazelike ENTRY: -1 DUNGEON: "The Astral Plane" "A" (1, 0) DESCRIPTION: mazelike PROTOFILE: "endgame" NOTES: Lines beginning with '#' are considered comments. A special level must be explicitly aligned. The alignment of the dungeon it is in only applies to non-special levels within that dungeon. AUTHOR M. Stephenson (from the level compiler by Jean-Christophe Collet). SEE ALSO lev_comp(6), nethack(6) Dec Last change: 12 4 DGN_COMP(6) 1995 DGN_COMP(6) BUGS Probably infinite. Dec Last change: 12 5 nethack-3.4.3/doc/dlb.60100644000000000000000000000356507764735041013260 0ustar rootroot.TH DLB 6 "28 Oct 1993" .UC 4 .SH NAME dlb \- NetHack data librarian .SH SYNOPSIS .B dlb { .B xct } [ .B vfIC ] arguments... [ .B files... ] .SH DESCRIPTION .PP .I Dlb is a file archiving tool in the spirit (and tradition) of tar for NetHack version 3.1 and higher. It is used to maintain the archive files from which NetHack reads special level files and other read-only information. Note that like tar the command and option specifiers are specified as a continuous string and are followed by any arguments required in the same order as the option specifiers. .PP This facility is optional and may be excluded during NetHack configuration. .SH COMMANDS The .B x command causes .I dlb to extract the contents of the archive into the current directory. .PP The .B c command causes .I dlb to create a new archive from files in the current directory. .PP The .B t command lists the files in the archive. .SH OPTIONS AND ARGUMENTS .DT .ta \w'f archive\ \ \ 'u v verbose output .br .sp 1 f archive specify the archive. Default if f not specified is LIBFILE (usually the nhdat file in the playground). .br .sp 1 I lfile specify the file containing the list of files to put in to or extract from the archive if no files are listed on the command line. Default for archive creation if no files are listed is LIBLISTFILE. .br .sp 1 C dir change directory. Changes directory before trying to read any files (including the archive and the lfile). .br .SH EXAMPLES Create the default archive from the default file list: .br dlb c .sp 1 List the contents of the archive 'foo': .br dlb tf foo .SH AUTHOR .PP Kenneth Lorber .SH "SEE ALSO" .PP nethack(6), tar(1) .SH BUGS .PP Not a good tar emulation; - does not mean stdin or stdout. Should include an optional compression facility. Not all read-only files for NetHack can be read out of an archive; examining the source is the only way to know which files can be. nethack-3.4.3/doc/dlb.txt0100644000000000000000000000440207764735041013721 0ustar rootroot DLB(6) 1993 DLB(6) NAME dlb - NetHack data librarian SYNOPSIS dlb { xct } [ vfIC ] arguments... [ files... ] DESCRIPTION Dlb is a file archiving tool in the spirit (and tradition) of tar for NetHack version 3.1 and higher. It is used to maintain the archive files from which NetHack reads special level files and other read-only information. Note that like tar the command and option specifiers are specified as a continuous string and are followed by any arguments required in the same order as the option specifiers. This facility is optional and may be excluded during NetHack configuration. COMMANDS The x command causes dlb to extract the contents of the archive into the current directory. The c command causes dlb to create a new archive from files in the current directory. The t command lists the files in the archive. OPTIONS AND ARGUMENTS v verbose output f archive specify the archive. Default if f not specified is LIBFILE (usually the nhdat file in the playground). I lfile specify the file containing the list of files to put in to or extract from the archive if no files are listed on the command line. Default for archive creation if no files are listed is LIBLISTFILE. C dir change directory. Changes directory before try- ing to read any files (including the archive and the lfile). EXAMPLES Create the default archive from the default file list: dlb c List the contents of the archive 'foo': dlb tf foo AUTHOR Kenneth Lorber Oct Last change: 28 1 DLB(6) 1993 DLB(6) SEE ALSO nethack(6), tar(1) BUGS Not a good tar emulation; - does not mean stdin or stdout. Should include an optional compression facility. Not all read-only files for NetHack can be read out of an archive; examining the source is the only way to know which files can be. Oct Last change: 28 2 nethack-3.4.3/doc/fixes22.00100644000000000000000000003456007764735041013772 0ustar rootroot NetHack Fixes List Revision 2.2 Fixes and Modified Features --------------------------- Guidebook.mn New file "Guide to the Mazes of Menace". By Eric Raymond. Guidebook A file for preparation using the "mn" macros supplied with the 2.11 news release, as well as an ascii version of the same. NetHack.cnf Sample configuration file for the PC. (creps@silver) Makefiles Corrected problem in which the linking was done on build and (unix/xenix) on install. (Contributed by Janet Walz - walz@mimsy) Makefile.att Added a makefile for the AT&T Unix PC using shared libraries. (Contributed by ahby@umn-cs) Makefile.pc Streamlined compilation of main.o, tty.o, and unix.o Makefile.tcc (Contributed by polder@cs.vu.nl). data.base deletion of duplicate lines and spelling fixes. (sweet@scubed) invent.c REDO problem with "What do you want to..." text fixed. down stairway identification fixed. Alloc "buf" to allow for variable length HI/HE. (tom@uw-warp) engrave.c Correction to "feel" code. (mike@genat) Corrected switch for message determination. (patrickm@hpisof0) BURN'ed engravings made un-erasable again. (kyrimis@princeton) pri.c Added colour highliting functions (sweet@scubed) prisym.c changed "symbol.room" to "ROOM_SYM" (one I missed) (Ralf.Brown@b.gp.cs.cmu.edu) Changed "dirlet()" to return an int. (maartenj@cs.vu.nl) msdos.c Changed "symbol" to "showsyms" (Ralf.Brown@b.gp.cs.cmu.edu) Fixed up REDO & IBMBIOS stuff. (Kevin Sweet - sweet@scubed) do.c Dropping gold asked for only when gold posessed. (walz@mimsy) Potential unsigned value problem fixed (u.ucreamed) Added leash dropping code. (maartenj@cs.vu.nl) Blind modifications for blindfolding. (eric@snark) Value wrap fixed for u.ucreamed fight.c Dog's name now used in hitting avoidence message. (walz@mimsy) Variable initialization fixed w.r.t. #ifdef / #else. (Reported by Erwin Unruh - unruh@infbs) Added giant rats and kobolds back into code. (sweet@scubed) spell.c Potential unsigned value problem fixed (u.ulevel). Typos corrected. (Tom May - tom@uw-warp) Blind modifications for blindfolding. (eric@snark) shk.c "inshop" crash bug corrected (many sources). extern declaration of carrying() moved to avoid a Turbo-C type mismatch msg. (Ralf.Brown@b.gp.cs.cmu.edu) Added new "online()" which executes faster. (tom@uw-warp) Blind modifications for blindfolding. (eric@snark) Added item pricing shopkeeper talk. (Idea from a hacked up 1.0.1 source sent in by michael@stb) Cleaned up Kops code. (sweet@scubed) mhitu.c Argument mismatches fixed. (walz@mimsy) Scorpion/spider mixup fix. (William LeFebvre - phil@rice.edu) Blind modifications for blindfolding. (eric@snark) potion.c Argument mismatch fixed. (walz@mimsy) Blind modifications for blindfolding. (eric@snark) Poison handling made more dependant on poison resistance. (From an idea by Steve Creps - creps@silver) mklev.c Fixed up installation of vamp traps. (sweet@scubed) makemon.c Monster creation location bug fixed. (walz@mimsy) Monster creation crash fixed. (many sources) Monster posessions bug fixed. (S. Wrammerfors stewr@obelix) Added giant rats and kobolds back into code. (sweet@scubed) hack.c "Elbereth" effectiveness increased under "HARD" option to be reasonable. (walz@mimsy) Declaration of "register struct monst *m_at()" fixed. (many) Typo fixed. (tom@uw-warp) Fixed scroll of scare monster pickup problems (and giveaway) (polder@cs.vu.nl) Documentation modifications for blindfolding. (eric@snark) ioctl.c ioctl call for SET changed to function properly under unixtty.c Sys V R3 mods. (tom@uw-warp) decl.c in_doagain initialized. (many sources) wield.c Ability to remove cursed weapons w. w- removed. (many sources) options.c Major rewrite of options help. Now uses pager. (mike@genat) Rewrote GRAPHICS setup. (maartenj@cs.vu.nl) Allowed reassignment of inventory order #ifdef DGK (polder@cs.vu.nl) pray.c Fixed mk_obj of spellbook under all conditions to make book if "SPELLS" defined, and scroll otherwise. (unruh@infbs) Fixed typo in "gods angry" text. (tom@uw-warp) Fixed blessing code. (Simon Brown - simon@its63b) Blind modifications for blindfolding. (eric@snark) zap.c Potion of invis. breakage message improved. (unruh@infbs) Added WAN_PROBING to "zapyourself". Changed "dirlet()" to return an int. (maartenj@cs.vu.nl) Fixed cancellation code to work properly on wands (spe set to -1 instead of 0) this means no infinite wands of wishing. (Ron Wessels - ron@utcsri) Fixed bug in "buzz()" causing crash when destroying a trapper from inside with a wand/spell. (mike@genat) Added fcn to destroy wands with zero charges. (sweet@scubed) pcmain.c Added a routine to zero out the fileinfo array in order to prevent crashes on level change. (ralf@b.gp.cs.cmu.edu) Added chdir to HACKDIR before looking for .CNF file. Added call "uptodate(savefile)". (polder@cs.vu.nl) pager.c changed "cornline()" to use xputs for HI/HE. (tom@uw-warp) added choice for dowhatis() to allow letter or cursor object selection. (polder@cs.vu.nl) cmd.c Added ^W (wish) and ^I (ident-all) commands for WIZARD-mode. (Paul Polderman - polder@cs.vu.nl) Added "Z" as alternate to "# cast" (Eric Raymond - eric@snark) u_init.c Expanded a tab which didn't show in raw mode. Changed trobj.trotyp to "unsigned short" to avoid >255 problems. (Maarten Jan Huisjes - maartenj@cs.vu.nl) Removed wand of wishing from WIZARD's inventory (due to the above cmd additions). (polder@cs.vu.nl) Fixed declaration of leash. (simon@its63b) Beefed up Wizard class. Added Wakizashi for Samurai. Added holy water for Priest(ess)es. Modifications to provide blindfolds. (eric@snark) end.c changed inventory identification on death to list form. (polder@cs.vu.nl) added hallucination effects to done_in_by() added posession of amulet flag for scoreboard (sweet@scubed) wizard.c corrected "nasties" decl. (maartenj@cs.vu.nl) Blind modifications for blindfolding. (eric@snark) do_wear.c Prot. from shape changers logic fixed. (maartenj@cs.vu.nl) lev.c Prot. from shape changers logic fixed. (maartenj@cs.vu.nl) mon.c Inserted cast to fix compiler warning. (maartenj@cs.vu.nl) Nymphs now leave potions of object detection when killed. Kops now don't leave treasure behind. (sweet@scubed) topl.c Changed size of "toplines" to avoid overflow in "parseoptions" when help is asked for. (probably n/a) (maartenj@cs.vu.nl) topten.c Added longer death descriptions, including name of shopkeeper who killed character. (many sources) termcap.c Changed allocation of HI/HO for copying SI/SO to allow room for null. (maartenj@cs.vu.nl) Added PCHack 3.61 termcap stuff. Added colour highliting code. (sweet@scubed) version.c Expanded a tab for rawmode io. (maartenj@cs.vu.nl) objnam.c Allow the WIZARD to wish for really excessive objects. (polder@cs.vu.nl) makedefs.c Added "freopen" which works (MSC 4.0 drops first couple of lines). Solves missing #define AMULET... problem. (Nathan Glasser - nathan@mit-eddie) rnd.c Changed around random number generation: BSD uses "random()". (Paul Eggert - eggert@grand) SYSV uses "lrand48()". (mike@genat from above) eat.c Changed "choke()" code to waste food rather than choke on it #ifndef HARD. (Allan Pratt - apratt@atari) Blind modifications for blindfolding. (eric@snark) objects.h added blindfold object (tool). (eric@snark) you.h changed Blind/BLIND to Blinded/Blinded added Blindfolded/BLINDFOLDED redefined Blind in terms of above parameters. (eric@snark) apply.c added blindfold code. (eric@snark) timeout.c Blind modifications for blindfolding. (eric@snark) sit.c Blind modifications for blindfolding. (eric@snark) trap.c Blind modifications for blindfolding. (eric@snark) Level teleportation to hell fixed so that it will not do so unless character has Fire_resistance. (many sources) Added polymorph trap. (many sources) monmove.c added check on presence of "fobj" before atl() call to avoid potential segmentation problem with ROCKMOLE. (Reported by Doug Rudoff - doug@wiley) various files Fixed typos. Also converted British English words to American English for uniformity. (Original list of typos submitted by Steve Creps - creps@silver) New Features ------------ 1) New flags in "config.h" (some of these were included in 1.4f): COM_COMPL Command line completion by John S. Bien GRAPHICS Funky screen character support (Eric S. Raymond) HACKOPTIONS Support DGK-style HACKOPTIONS processing (ESR) RPH Various hacks by Richard P. Hughey KJSMODS Various changes made by Kevin Sweet BVH Additions by Bruce Holloway In addition, in an MSDOS enviornment, when GRAPHICS is defined: MSDOSCOLOR Colour highlighting of monsters, etc. Of the above, I haven't tested HACKOPTIONS and MSDOSCOLOR. If you find bugs in these, send me the reports. 2) New objects: blindfold - allows you to avoid the gaze of a Floating Eye and to use your telepathy on command if you have it. mirror - scares monsters if you use it on them (and other uses). ring of polymorph - (usually cursed) forces random polymorphs. ring of polymorph control - prevents system shock and allows choice of creature to polymorph into. 3) New Files: - A new set of documentation, the "Guidebook to the Mazes of Menace" has been supplied by Eric S. Raymond. The guidebook is written for nroff using the "mn" macro set supplied with Bnews 2.11 or greater. Since not everyone has these macros, I have run the guidebook through nroff, and supplied it in flat ascii format as well. [Moderator's note: because of past problems, I ran the formatted version through "col -b" before passing it on to remove ^H's, etc. -br] - A copy of "HACK.CNF" which has been renamed "NetHack.cnf" was supplied by Steve Creps. The file decl.c has been updated to reflect this change. - A new "Makefile" for the AT&T Unix machines has been added. - I was hoping to get documentation on "NANSI.SYS" as well, but got no responses to the mail I sent the author, direct and via Bill Randle at tekred. As per usual, I will gladly publish any relevant documentation I get. 4) Major game changes: - Shop generation has been significantly changed. A new structure has been introduced which allows shops (except the "general" type) to have up to three different types of object inside. There is also a new "distribution pattern" parameter which tells the generation code how to lay out the shop (this is preliminary to the addition of two new types of shop, the temple and barracks - more on this later). - Shopkeepers will now tell you how much they expect for each object you pick up. This gives you the ability to haggle with the merchant in question by dropping and picking up objects until you are more or less satisfied with the price. I have re-written "getprice()" in shk.c in an attempt to make sure that you cannot actually sell any particular object for more than the shopkeeper will charge for it. - Another change to shopkeepers has them potentially getting angry if you stay beside them after not paying your bill. Each they time they ask you to pay up, there is a chance they will decide they don't like people who don't pay... - A new monster, the hydra, has been added (as you have probably seen on the net). I haven't had much chance to test out this feature of the game. Mirrors have also been added, and seem to work quite well. - Changes have been made to the object ocurrence chances in objects.h, so that the relatively rare tools, etc. have at least a 1% chance of showing up. - Throwing and zapping code has been modified so that there is a chance that said can be done through a doorway. Bolts can still bounce however... - The infamous and dreaded makemon() bug has been eliminated. In addition to this, "r"ats and "K"obolds have been added back into the game. "K"ops no longer leave treasure (just what they were carrying, plus maybe a club or whistle). - Two new "super"swords have been added. They are the katana named "Snickersnee" which is +5 on damage (due to sharpness), and the long sword "Excalibur" which is +rnd(10) to hit, +5 on damage, and has a couple of other features I won't go into right now. The only way for a character to get "Excalibur" is as a gift from someone. You cannot write the word "Excalibur" on things for some reason... - There have been two additions to disallow infinite wand charges. First of all, wands with less than zero charges will automatically turn to dust (thanks to Kevin Sweet). Next, a wand of cancellation will set the number of charges in the wand to -1, which will make it forever useless, (thanks to Ron Wessels). 5) Minor game changes: - The fountain code has been tightened slightly so you can no longer dip objects into a fountain or drink from one while you are floating in mid-air due to levitation. - Teleporting to hell via a teleportation trap will no longer occur if the character does not have fire resistance. I found this just too arbitrary a way to die (and so did several other people who com- plained about it). - A new trap, the "polymorph" trap has been added by Richard Hughey. It's inclusion is dependant on having "KAA" defined. - In wizard mode, the wizard player has infinite wishes, and the ability to instantly identify everything (s)he is carrying. The wizard player is also no longer limited by the standard multiple / bonus res- trictions on objects wished for. - Random number generation has been changed around to make it (I hope) more unpredictable. - A large number of typos have been fixed, and all of the British spellings converted to American. I would like to see a shell script to allow conversion back (or something like that) in the future. - I have done a "make depend" for the makefiles to reflect a slight restructuring in the order of inclusion of header files. 6) Future additions: - Steve Creps is working on "barracks" and "soldier" code which is now ready for addition. I have added the "soldier" side into the game, but haven't really tested it. Steve will be adding the "barracks" section in and sending me the resulting patches. There will be a minor (read patch) release as soon as he can get the code integrated into this release and sent up here to me. - There are also several other new room projects in the works which should be able to be included in that minor release, along with any bug reports that are made in the interim. nethack-3.4.3/doc/fixes30.00100644000000000000000000002133607764735041013766 0ustar rootroot$RCSfile: fixes30.0,v $ $Revision: 1.1.2.2 $ $Date: 2003/05/11 15:10:00 $ [This is a partial list supplied by Ken Arromdee long after the fact] General Fixes and Modified Features ----------------------------------- dropping a weapon, then picking it up while blind causes it to become unidentified but it remains that way after your vision returns when blind and feeling the floor, the objects then on the floor should have their characteristics become unknown zapping a wand of probing at yourself works, however using a stethoscope on yourself does not trolls that come back to life don't retain their names if you look at what is on the ground and there is more than a screenful, quantities are not printed (i.e. "food rations") if pickup was off and you moved onto a spot with both engraving and objects, you got told what the engraving was twice if a Keystone Kop threw a pie and the pie hit a shopkeeper, the shopkeeper became angry "two handed sword" is spelled with and without a hyphen in various places trying to descend stairs while levitating gives a message where "You're" is misspelled as "Your" the 'V' command gives a history that is not quite correct; it wasn't Ken Arromdee that merged PC Hack and Unix Hack; rather, PC Hack was derived from Unix Hack by Don Kneller. It was (I think) Mike Stephenson who merged the many Hack versions. the uranium wand gets described as "an" uranium wand potions which have been both called and identified have the called instead of the identified name printed out status line at the bottom of the screen is formatted strangely for the first 10 moves; after 10 moves it becomes normal if you polymorph yourself into a rockmole, you are unable to dig through rock a stethoscope or wand of probing, used on a monster, printed out a format with spaces in it (such as %-3d instead of %d) causing such messages to be longer than necessary the number printed out for damage by stethoscope or wand of probing is completely incorrect sometimes your dog would turn into a bat (retaining the same name and tameness) when saving and restoring,going down and back up and in bones levels ghosts on bones levels are replaced by little dogs if you are polymorphed and drink a potion of healing which raises your maximum monster hit points, your current hit points only are raised, so you may have (for instance) 37 out of 36 hit points when you pick up something from a shop, the message is something like "For you, kind sir, only 5 for this " on systems where pointer is not the same size as integer removing a leash from a dog produces garbage, and also can sometimes crash the game when the Wizard is mentioned, you get garbage if you tame a wild dog, and then try to hit it, the safe-attack routine says "You stop to avoid hitting .", or sometimes garbage when you are invisible but can see invisible, drinking at a fountain which dries up causes your symbol to be erased from the screen. pushing an enormous rock onto a teleport trap deletes it instead of teleporting it sometimes returning to human form from a polymorph would leave you with only 1 current hit point left sometimes polymorphing would leave you with an 18/** strength if you used a stethoscope on a wall and a creature moved into the revealed door before you did, when creature moved off, the door was replaced by a wall symbol again, until you walked through it playing a game with fountain symbols set to one character, and restoring it using a configuration file having them set to a different character, leaves the fountain symbols as the old character problem with food poisoning and blindness where you could end up permanently blind, not even reversible by healing etc. you could not wish for a C-ration or K-ration due to lowercase conversion zapping a wand of death at yourself, and the death touch of a demon prince, killed you even if you were polymorphed into an undead, but bouncing death rays didn't if you threw an object in a shop, it landed on the floor still unpaid zapping a wand of cancellation at yourself turned all your objects to -1 instead of +0; -1 was only needed for wands (since cancelling wands to +0 allowed a sneaky way of getting infinite wishes) #remove command is incorrectly described as removing a cursed object, but it actually removes only iron balls at least some messages given for special abilities when you are polymorphed printed out the monster type even if you were blind wishing for a scroll of mail, with MAIL undefined, is permitted but reading the scroll gave an "impossible" error message; change it to read: "This seems to be junk mail directed to the finder of the Eye of Larn." if you were blind, effects of scrolls, et al, still said things such as "Your mace glows green for a moment," "Your left ring glows white" the message "The xan pricks your ___ leg" still mentions the type of monster (xan) when you are blind polymorphing could change your gender, but when the game ended you were still described as a "Cave-man" or "Priest" instead of "Cave-woman" or "Priestess" if you got rocks by using a pick-axe on an enormous rock, the rocks started out blessed if you escaped from a shop by throwing your iron ball to the exit, the ball would stay unpaid any object thrown in a shop stayed unpaid, and you had to pick the object up again and then drop it for it to become paid if you were invisible but could see invisible, when you drank from a fountain that dried up, your symbol got erased from the screen several times colors were mentioned (i.e. black glows when you pray too much) but the colors weren't always changed for hallucination if punished and your chain and 1 other object is on the floor, you get asked if you want to pick up a specific type of object, and the chain is given as one of the possible objects if you polymorph into a "new man", your energy points never change trolls, when killed, can leave bodies or objects, but they should always leave bodies so they can regenerate back to life, whether or not they left objects demon prince demanding bribe gets randomly relocated instead of being placed next to you if you polymorph another tool into a magic marker, the marker always starts out dried out hallucination has the problem that if you do something which takes no time, the monsters still change if you tried drinking at a fountain while levitating, you got asked if you wanted to drink, and then you weren't allowed to do it, and the fountain could still dry up if you were fire resistant and a magic trap produced a tower of flame, you also get a second message (a shiver...) when restoring a game, if there was an error, your saved game still vanishd for some errors pets were always referred to as "him" in the leash code stethoscope in the up or down direction while swallowed referred to "floor" and "ceiling" instead of to the monster that swallowed you if you could not save a game, the screen cleared and you were told to "Continue or Quit", but if you typed C, the game thought you just gave it a Call command you could get told "that spellbook was a mimic" even if mimic was on a wall if you were turning to stone and you polymorphed yourself into a 'c', you still died from the stoning if you interrupted the program before it finished loading a saved game, you were asked if you want your possessions identified "ctmp" was mistakenly used in MHITU.C when being hit by a rust monster rusting your helmet but it should have been "!mtmp->mcan" Platform- and/or Interface-Specific Fixes ----------------------------------------- PC: often the same character class, and same player name, will end up getting 2 scores on the high score list PC: if your name contained a period and you were playing on a PC, you would have problems saving games since your save-file name still contained 2 periods and would thus be illegal; change periods to underscores when figuring out what the save file should be called PC: if you polymorphed into a "new man", and changed your name, when you saved your game the game was still saved under a filename derived from your old name, and to restore that game you had to specify your old name General New Features -------------------- when polymorphed into a giant you are now able to pick up and throw rocks by giving infinite carrying capacity give the Healer a pair of gloves (the most logical piece of armor for a physician to start out with) give the Healer a lot of money to start with (doctors are supposedly rich, you see) have the Healer start out with the healing, cure blindness spells already known create a "trial mode", similar to Wizard Mode where you get a wand of wishing with charges and you can't get on the high score list if you are standing on a trapdoor and you type a '>' symbol, print "You jump down the hole." and go down to the next level nethack-3.4.3/doc/fixes31.10100644000000000000000000001357507764735041013776 0ustar rootrootMakefile.utl vs. GNU make (*_lex.o needs explicit *_lex.c dependency) defining MAKE in more makefiles (symptom is "sh: makedefs: not found") finding test in makefiles (needs shell meta-char, >/dev/null or || exit 1) splitter hunk sizes with SAS 6.x (wouldn't fit on floppy) OpenWindows 2.x documentation (?) ',' and ';' in help files, including Guidebook Guidebook date (nroff and pre-processed versions) VMS options syntax (config file description omitted "OPTIONS=" requirement) phase of moon for Mac and MSDOS ports -- revert to old, portable phase of moon code polymorphing into bees (divide by zero core dump, reported as floating point error on Sparcs) monster throwing boulder into pool could free object twice candle burn-out accessing free'd object while traversing list (Mac core dump) inappropriate candle merging (lit with unlit) several levelflags (fountains, etc.) not being handled on special levels subrooms[] not initialized coredump on messed DEFAULT_WIN_SYS deleting lock.0 files on early quit number_pad/mouse coexistence jumping onto doors or boulders tombstone gold neglected gold in containers, although score was correct initial gold record neglected gold in containers reeling monsters leaving ghosts (missing newsym) display getobj prompt for non-REDO packorder option parsing inconsisent option parsing with IBM vs. IBMg, etc. throwing Mjollnir at adjacent hard things causes panic/core dump throwing at ghosts in walls left objects stuck in walls throwing unpaid objects in shops (donated to player by shk) Shopkeeper administration out of order (buying group of used up items) pricing chains, uball, or other nocharge objects, when they couldn't be sold knocking uball down a hole by dropping another object caused crash kicking monsters while levitating (core dump if monster "reels" or killed) kicking empty space while levitating could give free move (recoil) panic when nurse is fixing your damage and disappears core dump 'D'ropping everything with gold but no inventory (null pointer access) core dump using getpos() "move to feature" response when map shows something covering furniture (displayed glyph leads to invalid subscript use) deity gender reference in opening legacy message makeplural() said "poisoned yas" instead of "poisoned ya" zapping on entry to water left trails allow level teleports to be cancelled excess choking when eating corpses funny death message (or coredump) when you choke on a tin of spinach after partially eating something else Magicbane expulsion confused cutworm() charging for several overlooked items (mainly magical instruments) taming a sticking monster (e.g mimic) wouldn't set you free panic when tinning while standing on stairs with a full pack and object drops zapping down into ice with wand of digging (core dump) rust monsters wouldn't ever hurt armor, even non-rustproof armor. conversely, unrustable things rusted. mysterious rust damage on damp levels (improper object chain traversal when any item landed in pool after being thrown or dropped) very eroded nonrustable/corrodable/flammable objects displayed as "very +0..." map window wasn't being initialized correctly, causing some 'a'filled screens using magic marker with full pack leaves you with an item in the '#' slot spellbook merging caused multiple books to fade away when you re-read them enough times Master of Thieves in Tourist quest not created with Bell of Opening, making game virtually un-winnable could wish for quest items If an eel managed to drown you, it would say "Drowned by a drowning" stop making bones from non-branch portal levels reading blank scrolls exercised wisdom inverted use of crystal ball "vision in unclear" feedback message special room entry messages (shop welcome) given before level change map update limbless blobs like gelatinous cubes could not pick up The level compiler missed first level flag if more than one was specified. The level compiler accumulated level flags when compiling multiple files. make the 32-bit monster flags fields unsigned long rather than just long mksobj() created gold a factor of 10 too light indefinite articles in quest text Alt-n didn't execute #name on some ports, made Alt-? do #? correct tense and grammar of various messages obsolete oracle about using mirror to locate Wizard & Medusa removed Nurses would zap you with wands, et al, instead of healing you Shopkeepers residence was sometimes wrong on bones level, esp. in the minetown Some zaps, esp. by monsters, at the map edge could cause core dumps panic relmon bug possible when #turn'ing multiple monsters at once it wasn't possible to get underwater when polymorphed to a swimmer total digestion wasn't working lycanthropy could change sex interrupting dosinkring() allowed free ring identification killing some hostile humans (like Croesus and priests) lost telepathy, etc. tty specific: long input lines and improved interrupt handling X11: NetHack.ad: "*map*grey" should be "*map*gray" X11: NetHack.ad: remove excess quotes HPs and X (SYSV conflict caused by X11 headers) Handle WM_DELETE_WINDOW protocol in X11 window-port. X11 popups are now positioned so that the cursor is bottom center. Both X11 fonts now have a pool symbol that coveres the whole rectangle. X11_getlin will now allow empty strings to be returned. X11: implement score in the status window. X11: make displaying experience optional. X11: position getline and yn popups center,bottom instead of center,center. X11: autofocus mode made more reliable at program startup X11: number of objects removed from containers could wrap negative X11: allow translation tables X11: initial window would "sweep" shut and reopen micros: save and restore progress reports weren't appearing during save and restore (they would appear immediately afterwards) also error messages from dots aimed off right edge of screen Atari: colors were not properly set in medium resolution Atari: terminal size was set incorrectly after a ^Z OS/2: HPFS support was incomplete nethack-3.4.3/doc/fixes31.20100644000000000000000000001306007764735041013764 0ustar rootrootrevived barbarians didn't gain levels from potions pets wouldn't keep their armor or weapons (blessed figurine of Archon) avoid "rot" v. "burn" damage for organics identify +/- known rings/armor as "uncursed" loop through identification as long as additional "charges" are available successive disease attacks made you less sick, also make nurses cure sickness NO_MAILREADER non-mail daemon message fix make fortune cookies, pancakes yellow and lightning white cavemen were red while cavewomen and all other characters were "domestic" monsters might not change color when growing up redisplay cancelled objects in case their color changed (potions, spellbooks) ask if you want to play heard passtune add: make ^T intrinsic teleports use magical energy don't encase the Amulet (or invocation tools) inside cockatrice induced statues fix eating taking 1 turn less than number necessary, cheating you of nutrition fix inventory to avoid % in user-supplied names [pline(xprname())] fix crash when #force destroys unpaid chest in shop fix crash when movement reaches edge of screen on rogue level fix crash when two items in a row vanish from magic bag set bknown when Priests see item, fixing missing checks elsewhere set alignment of priest's quest artifact to match priest's starting alignment if the Mitre of Holiness gets stolen by the Wizard, reset int & wis stats always unlock quest stairs whenever leader acknowledges quest completion make mysterious force which locks quest stairs block objects as well as player duplicate shopkeeper names were possible on town level trying to rename shopkeepers left dangling pointers credit balance can prevent Kop summoning when player leaves shop suddenly suppress several shopkeeper messages (and buy|sell) is shk is asleep|paralyzed using charged objects ((engrave) wands, horns of plenty, etc.) in shops was free don't double bill for food eaten off shop floor (multi-turn to eat only) fix to prevent unpaid objects differing only in price from merging (only in inventory; they're not "unpaid" any more when dropped, so might merge) missing #ifdef SOUNDS in vault.c inconsistent MFLOPPY/MICRO use of dotcnt for saving add: wands of striking break potions add: directional healing spells add: pickup_types option, pickup -> autopickup disclosure option takes optional string value; killed counts and genocide list give better message when trying to set options which are compiled out add: hungry pets make begging noises centaurs and mariliths could wear inappropriate armor remove Medusa's tail and give her wings separate creatures that don't breathe from creatures that can breathe water you can't choke if you don't breathe Fort Knox eels were placed outside moat jellies for Juiblex, not Jabberwocks don't heal while praying, so that gods are more likely to heal you fix fireballs burning fire resistant players floating eyes could paralyze monsters indefinitely fix monster sleep/wakeup induced my musical instruments players hit by wands of sleep get chance to wake up when attacked by monster iron balls keep their "very heavy" weight fix vorpal blade/long worm misses allow monsters to kill players with vorpal blade and tsurugi fix objects falling through trapdoors; "shipping destination"'s overloaded use of obj coordinates could cause bogus screen update attempt (y >= ROWNO) prevent bad argument to rnl() from prayer_done() when praying in gehennom display message when boulder is pushed into pit avoid monsters deciding displaced or invisible characters were off the screen kicking embedded objects loose would break fobj chain (-> freeobj() panic) when using the cursor to look at remote objects, if the target object is embedded in something, mention that fact dropping gold inside a monster -> freeobj() panic gold picked up by pets wasn't in mgold and thus didn't show up on probing fix "stop *opening* the lock" even when you were locking it succubus stealing ring of adornment caused crash if she already had one monsters created by monster reading create monster didn't appear for scroll ID monsters explicitly casting spells of sleep or cold had messages reversed elf character could get impossible("snow boots not found?") stepping onto ice accept gray/grey except for spellbooks keep monsters from teleporting on no-teleport levels don't allow digging of trapdoors on the three wizard levels don't allow digging down (including drum of earthquake) to destroy portals fix digging down from within walls and solid rock; monsters could enter the resulting trapdoor/pit, but players couldn't fix digging down while flying; don't fall through destroy any engraving if a hole is dug down thru it, or ice it's in gets melted change many hardcoded "floor"s and a few "ground"s to use actual surface type fix blessed unicorn horn's restore ability feature (strength gain when weak) underwater: prevent turbulence from placing character inside solid wall underwater: suppress "you inhale water" message when removing amulet of magical breathing if you're polymorphed into a swimmer or nonbreather when using the 'A' command to take off armor from underneath other armor, account for time needed to take off and put back on outer garment(s) don't create doors over pits and trap doors when using a wand of locking fix mapping when you drop objects while following the guard out of a vault X11: some status didn't show up after restore UNIX: fix potential security hole accessing file through NETHACKOPTIONS setuid VMS: disable installed privileges when assigning i/o channel to terminal, opening termcap, or accessing user-specified config file Amiga: invalid showscore and numberpad options inserted by frontend nethack-3.4.3/doc/fixes31.30100644000000000000000000000232107764735041013763 0ustar rootrootavoid divide by zero crash for eggs produced from horn of plenty prevent monsters from eating the invocation tools or Rider corpses make artifacts much less likely to be destroyed fix freezing lava in front a raised drawbridge fix digging pits in front of raised drawbridge; improve digging next to pools since random teleports have no --More-- prompt, have them purge REDO data to avoid repeating previous command before noticing changed context make magic portals function for monsters make numerous priest blessings increasingly rare, with an upper limit fix missing quotation marks in quest speech prevent monsters like killer bees from opening tins add: keep track of # player deaths, save game start time in struct u don't used "uncursed" with gold in containers in ending inventory display PC: Fix black/gray/white display problem X11: set input text portion of the dialog box so it is the width of the box X11: fix message window seperator redraw problem (thanks to Ivan D. Brawley ) VMS: avoid false "trickery" detection for bonesX#.##;1 levels VMS: prevent display of really long broadcast messages from clobbering stack VMS: prevent endless input loop upon remote terminal disconnect nethack-3.4.3/doc/fixes32.00100644000000000000000000005144707764735041013776 0ustar rootrootprotect the Amulet and invocation tools from being destroyed when a disintegrated monster's inventory gets deleted prevent the Amulet and invocation tools from being buried, similar to box behavior (Book of the Dead would rot away as paper when buried) don't let polymorphed players eat any of the invocation tools pets are no longer highlighted when hallucinating keep glass gems from shattering in chests return errors from dgn_comp and lev_comp when called for fix hallucinated fruit juice message fix several monsters conveying inappropriate resistances fix misspellings of "Assassins' Guild" and "Minion of Huhetotl" set personal name flag for Pelias and Thoth Amon; clear it for Chromatic Dragon don't say "Picking the lock..." when using a skeleton key give feedback when applying key to current location but no boxes are present can't manipulate floor locks (chests) while levitating don't crash onto sink if permanently levitating due to eating a ring avoid resuming interrupted lock operation on chest that's been polymorphed wide-angle disintegration Beams O' Wrath disintegrate non-resistant shields and armor don't access zapped wand after it's been destroyed by divine lightning bolt separate graphics symbols for each trap, differently-colored traps allow wishes for greased objects, correct wishes for "poisoned rustproof" objects damage was calculated incorrectly when hitting with statues and boulders allow digging to finish when digging statues embedded in undiggable walls list identified invocation tools as "the item" instead of "a item" ignore rknown for unerodable objects when determining if it's fully identified flush output after eating mimic so '$' appears right away update botl for spell power after ^T or #invoke of "energy boost" artifact correct hunger check when casting spells correct various messages fix deliberately jumping into Stronghold trap doors make random level changes while escaping with Amulet more equitable when mysterious force randomly picks a location on the current level, send player into Wizard's tower if and only if already inside that tower any level change from one tower level to another preserves occupancy state mysterious force won't kick in when using portal to go up into Wizard's tower avoid "bad cursor position" situation when mystery force or cursed gain level potion causes level change within the Wizard's tower don't allow the Wizard to be resurrected on the Astral level only list "likely" objects when prompting for what to #invoke reset encumbrance and movement rate during successful prayer, in case it cures lycanthropy prevent cursed weapon that slips when thrown by monster from embedding in stone ki-rin is not humanoid all elves can see invisible gain intrinisics from eating amulets lose divine protection by killing co-aligned priests or converting alignment have quest leader check for absolute alignment as well as for piousness fix tombstone message when dying from kicking door while levitating bite, &c. attacks on displaced images said "swings wildly and misses" calculate score before creating bones, otherwise gold in bags gets overlooked Unique monsters no longer placed in bones files for blessed genocide, don't report failure for other classes' quest monsters could get both compressed and uncompressed explore mode save files ZEROCOMP's bwrite ignored possibility of write failure mimics imitating fruit caused "Bad fruit #0" on help commands fix off by one bug in level teleport trap destination for monsters if g.cube eats a non-empty container, engulf contents rather than devour them allow wizard to use blessed genocide of '*' to wipe out all monsters on level when digging a hole in ice, don't describe it as digging in the "floor" and unearth any objects buried there even when it refills with water when digging in a pit trap which ends up filling with water instead of becoming trap door, remove the trap; likewise for overflowing fountains can't dig pits under drawbridge portcullis; break bridge if hole would be made can't dig while caught in a web don't "swing your pick-axe through thin air" if target location is a web mark webs as seen when "monster is caught in a web" message is given whirly monsters pass through webs; some huge monsters tear them Sting cuts through webs have shk use plural if called for when referring to player's pick-axe(s) fix price stated by shk when picking up container holding merged items fix price stated by shk for #chat when standing on a container don't adjust food price due to hunger when player is selling, only when buying don't double bill shop corpses turned into tins don't make mundane objects known when they're outside the shk's expertise change to have shks possibly identify items sold for credit just like for cash when player sells something to broke shk for credit, don't offer more for it in credit than will be charged for it if player buys the item back when selling items in shop, don't try to adjust message/prompt based on COLNO when dying in shop entrance, make sure inventory in bones data is placed all the way inside the shop, hence owned by the shk make shk notice when shop door destroyed by wand or spell or digging downward reset unpaid objects if shk poly'd into jumpy monster teleports out of shop fix handling for shop objects kicked or thrown from one shop into another and for shop objects hit by cancellation beam add potions of oil; lamps can be refilled with them dipping rusty weapons in potions of oil removes rust allowing drinking from surrounding water if you are underwater fix non-merging potions of water due to water damage's incompatible dilution fix mon-merging scrolls of blank paper due to SCR_SCARE_MONSTER's spe usage fix D(ropping) subset of wielded darts,&c (worn mask got out of synch) fix #adjust merging wielded darts,&c into non-wielded ones allow #adjust when fixinv option disabled fix getobj's '?' help displaying one item when fixinv option disabled don't give characters with maxed out luck complete immunity to water damage don't allow AC -17 or better to provide invulnerability to zap attacks kicking cockatrices while barefooted will stone you change to inhibit displacement from operating through solid walls fix mblinded assignment for monsters hit by potion fumes give runesword same damage adjustments as broadsword extra verbosity for attacks caused by Stormbringer allow ghosts to step on garlic don't let vampires step on altars don't let monsters jump into polymorph traps covered by boulders, unless they can carry such, pass through, or squeeze under giants polymorphed into something else must drop any boulders being carried giants in pits become untrapped if a boulder is pushed in prevent traps from being generated on ladders don't "detect trigger hidden in soil" for previously detected land mine exploding and crashing doors wake up nearby monsters factor rings of increase damage into kicking damage handle omitted case for ball movement that would leave chain in odd position returning to stairs on top row of map is valid (fixes rogue quest bug) avoid giving "sad feeling" message for pet if lifesaving prevents its death don't rot away Rider's corpse if something is standing on it at revival time kill any engulfer (including poly'd player) trying to digest a Rider give Riders non-zero nutritional value so tinning kit doesn't ignore them save & restore u.usick_cause properly an eating pet can continue & finish eating while you're off its level fix object names: "a Dark One corpse", "statue of a Wizard of Yendor" killer_format: poisoned "by Pestilence", not "by a Pestilence"; ditto Juiblex killer prefix might be wrong after having been life-saved fix to avoid "invisible invisible {Priest|Minion of Whoever}" on tombstone fix bug with cold-resistant monsters attacking jellies (etc.) fix possible panics when restoring while swallowed or held when taming, make holder/swallower let go even if it just becomes peaceful reset area of visibility when hurtling backwards from recoil while levitating don't let hostile monsters who follow up/down stairs share final ascension add bodypart(HAIR) to correct some inappropriate messages display monsters inventory (if any) when mon zapped with wand of probing display inventory of encased items in statues zapped with wand of probing display inventory of buried items below, by zapping wand of probing downwards set dknown bit for all objects hit by probing beam add ceiling function to alter the ceiling messages appropriately fix 3.1.2's fix for reseting certain class-specific artifact properties add selection menus to pickup and some apply functions pre-menu container interface: don't let "%a" select all objects if no food is present; make user's " a" become "A" instead wake up monsters hit by potions thrown by other monsters suppress vault hint messages if player is in the vault make lev_comp check full object and monster names ([ring of] "protection" in objects[] was matching "protection from shape changers" in .des file) guarantee that stairs down from Juiblex swamp level always get created [sometimes got impossible("couldn't place lregion type 0")] prevent a three room level which has the stairs to the mines from also having a special room [so that those stairs can't end up placed in a shop] allow quest nemeses and other invocation tool guardians to wield artifacts Mitre of Holiness is not a weapon don't give "heat and smoke are gone" message when entering Vlad's tower if arriving from somewhere other than Gehennom (portal via W's quest arti) when a wielded cockatrice corpse rots away, set `unweapon' so that further combat will elicit "bashing with gloved hands" message fix behaviour of wielded eggs (breaking, stoning, etc) tiny chance for "queen bee" eggs, rather than always killer bee eggs change Tourist quest home base to Ankh-Morpork prevent activated statue traps from creating hidden monsters handle activated statue being the only object poly'd player is hiding under prevent reference to unseen underwater object when hiding monster attacks don't pluralize name when smelling opened tin of unique monster's meat make tins of unique monster's meat be empty in bones file don't leave a corpse in bones file if killed by disintegration breath don't leave a corpse when monsters disintegrate other monsters any food could be tinned (yielding giant ant meat) when corpse in inventory destroy all boulders in invocation area when creating stairs down to sanctum boulders landing on previously seen trapdoors will plug them instead of falling through or settling on top boulders on ice which gets melted will fill pool as if dropped don't let dead or sleeping priests give temple greetings chatting wakes up sleeping priests don't exercise wisdom when making prediscovered objects known during init don't generate any generic giants (mummy/zombie placeholder) on castle level pets and g.cubes will polymorph if they eat chameleon corpses slippery ice (temporary fumbling) only lasts until the next move avoid leash limbo if quest leader ejects you while leashed pet's not adjacent (ditto other unconventional level changes, like W's quest artifact) release attached leash if poly'd player eats it crash fix: handle other forms of monster-induced level change besides quest ejection (swallower expels onto portal, level teleporter, trap door) fix magic mapping of previously mapped maze walls dug away out of view assorted drawbridge fixes (kill credit, auto-pickup, drown survival handling) passtune becomes fully known once successfully played wiping out engravings leaves partial letters wipe random letters of trap engravings ("ad aerarium", "Vlad was here") eating wolfsbane while in werecritter form rehumanizes in addition to purifying don't penalize player (shop charges in general; bad luck for mirror) when a monster breaks something with a wand of striking when loading bones, keep track of unique monsters to avoid their duplication don't allow a demon prince to summon two copies of a unique demon lord enlightenment luck display ("extra", "reduced") did not agree with actual luck avoid duplicate spellbooks in character's initial inventory (affects priest) fix pets moving reluctantly onto cursed objects can't #loot while overtaxed time passes when items disappear on use of a cursed bag of holding #offer cannot convert or destroy an unaligned altar MUSEr's reflecting shield or amulet shouldn't become known when not seen fix check for wearing shield when monsters wield two-handed weapons don't restrict MUSE scimitar usage to strong monsters make dwarves less eager to switch back and forth between weapon and pick-axe clip swallow display at left & right map borders prevent recoil [hurtle() while levitating] when caught in a trap downward zap which freezes water or lava shouldn't bounce back up Vorpal Blade: don't let damage penalty (very low strength, negatively charged ring of increase damage) prevent beheaded monster from dying make sure player polymorphed into jabberwock is vulnerable to beheading make sure that when "The fiery blade burns the shade!" that it actually does damage (double-damage for non-silver must do at least 1hp damage) prevent divide by zero crash when hitting tame shade with non-silver weapon don't lose alignment when throwing gems to/at peaceful unicorns don't apply grease to worn armor if it's covered by other armor fix unnaming monsters via `C ' fix calling object types via `#name n ' fix off by one problem when shuffling some descriptions (scroll label "KIRJE" and "thick" spellbook never used; breathing amulet always "octagonal") exploding land mines can scatter or destroy objects at the trap location add rolling boulder traps try harder to make monster hit point and level gain avoid anomalous losses reduce odds of undead corpses on castle level and priest quest home level, to make it harder to lure wraiths to more favorable spot can't polymorph large piles of rocks into gems hit point gain from nurse healing throttled substantially make cursed bells be much less effective as instruments of abuse fully implement object charges for Bell of Opening allow '%' as destination on rogue level when specifying position by map feature fire traps can burn up scrolls and spellbooks on the floor fix inverted cancellation check for AD_SLOW and AD_DREN damage bullwhips can be applied to disarm monsters and hero bullwhips can be applied by hero to haul themself out of a pit ensure that thrown potions hit their mark if you are swallowed attempting to engrave on an altar causes altar_wrath differentiate between a hole and a trapdoor, digging always makes a hole check the right hit point values when polymorphed and encumbered improve guard behaviour in vaults when player is blind prevent dwarves from digging while wielding cursed weapons displacing a pet mimic unhides it '(' shows the proper tools as in use improve shk's handling of pick-axe damage and taming aging of items in ice boxes left in bones files fix genocide of '@' while polymorphed add gender to some unique monsters disallow digging down while phasing through non-diggable walls general fixes to various message sequencing problems prevent shopkeeper names from showing up while you are hallucinating prevent paralyzed pets from picking up items jellies for Juiblex, not Jabberwocks (done properly this time) rust monsters can't eat rustproofed objects general fixes to inventory merging of items monster inventory undergoes merging too; potentially affects probing and theft monsters ignore items they want to pick up that are on 'Elbereth' bows wielded by monsters now do proper (low) damage even nymphs may not pick up rider corpses treat cockatrice corpses in multiple item piles the same as one item piles "PACKORDER" feedback incorrect on parsing failure you can no longer choke on liquid stethoscope on secret doors displays properly when blind monster-hurled potions no longer produce quaff messages (or djinn) giant eels now hide with mundetected, not invisibility eels on the plane of water don't hide and aren't negatively impacted by being out of water don't give the big point bonus for eels if player is wearing breathing amulet fix display bug (newsym after Wait! message) temple priests now wear their cloaks Orcus is no longer peaceful (had been made so by bad bribery check) 'uskin' save and restore done properly don't improperly adjust int & wis for stolen non-worn P quest artifact don't allow Vorpal Blade to behead a monster when it swallowed you golems are not living and don't "die" in messages fix "Rocky solidifies. Now it's Rocky!" polymorphing into a flesh golem, which gets petrified by turning into a stone golem, now works when stoned correct "killed by a died" allow the Wizard to come back and harass at his next reincarnation time even if he's been left alive on some other level (fixes "paralysis" cheat) make monsters subject to "mysterious force" in Gehnnom while climbing stairs with the Amulet, so that once the Wizard has stolen it, his retreat when wounded doesn't become an easy way to carry it up changing attributes immediately checks encumber messages confused monsters get confused SCR_TELEPORTATION effects fixed "choked on eating too rich a meal" kicked objects won't stop at stairs if they don't fall general fixes to stealing from monster carrying cockatrice corpse a nymph who polymorphs herself while you're frozen during a multi-turn armor theft can't complete the theft if transformed into non-stealer monster consistent corpse probability no matter what killed monster (also removes a loophole allowing permanent rider death) MUSE monsters no longer wield weapon same as (not better than) current one incubi/succubi have hands, not claws make #jump be ineffective on air and water levels allow multiple sickness causes; vomiting only cures those involving food #prayer reward: give books for not-yet-known spells preference to known ones marker use no longer uses wishing interface, fixing several obscure bugs archeologists' and rogues' initial sack starts out empty candelabra "has now" 7 candles fixed. kicked objects would set dknown when the kick caused an injury, even though safely kicked objects wouldn't make cloaks subject to burning make exposed shirts subject to burning and rotting; greased ones defend against wrap attacks all types of fire damage affect worn armor [adds explosions, fire traps, and zapping yourself to previously handled zap/breath attacks by monsters] for explosions, destroy carried objects before killing player [affects bones] replace triggered land mine with pit before doing damage [bones] black dragon breath no longer referred to as "death" instead of disintegration don't make ring of gain strength known when gauntlets of power mask its effect can't have "slippery minor currents" or similar silly nohands body parts proper support for polymorphed players using wrap attacks cannibalism reduces luck as well as causing aggravation picking up an item which will merge works even when all 52 slots in use moving through diagonal openings checks how much you're carrying, not how much free space you have left monsters have same restrictions as players moving through diagonal openings picking up subset of heavy group works for picking one and gets feedback right taking subset of heavy merged group out of containers works the same as picking up subset of heavy merged group from floor when putting gold into containers, don't count its weight twice, thereby messing up the status line's encumbrance feedback fix the option parser's handling of attempting to negate string values teleporting a monster on a trap with a magic whistle sets the trap off iron ball dragging no longer confuses autopickup cumulative temporary intrinsic increments can't spill over into permanent bits eating food shouldn't give messages for intermediate states don't make wand of death become known after casting finger of death at yourself ignore case when checking artifacts against wish- or #name-specified name ignore confusion when reading scrolls of mail exploding runes for spellbook read failure doesn't imply that book explodes divine rescue from strangling destroys worn amulet of strangulation boulders pushed on level teleporters will level teleport; also, make one random level teleport function to keep all level teleports consistent MSDOS: add fake mail daemon MSDOS: add VGA tiles to tty port VMS: switch to lint-free, non-GPL'd termcap support code X11: map behind popup edges was occasionally not refreshed X11: allow permanent inventory window X11: when using tiles, highlight pets with "heart" overlay (should be changed to honor the `hilite_pet' run-time option) X11: click-in-message-windows crash fixed tty: fix panic when freeing endwin tty: fix behavior when recalled text needs to wrap beyond top line tty: allow selection from single line "help menu" (getobj's '?' response) tty: don't format data.base with hardcoded tabs that are ugly on non-tty ports tty: get rid of extra NHW_MENU space (improperly added when the menu was longer than the screen) tty: fix repeated "who are you?" prompting at game startup nethack-3.4.3/doc/fixes32.10100644000000000000000000001654507764735041013777 0ustar rootrootGeneral Fixes and Modified Features ----------------------------------- give invocation message when teleporting onto invocation position flying players with water breathing may retrieve things from water remove message inconsistently assuming players can be mindless monsters wear best armor (not first armor) and may switch armors god doesn't give "strayed" message when your god is angry but a different god is the one giving the message divine wrath can hit engulfer if you are swallowed plug minor topten and oracle memory leaks monster throwing must allow for 0 damage (cream pies, non-silver vs. shades) break drawbridge if wand of striking is zapped down at open bridge or either up or down at its portcullis wand of striking zapped at ceiling might cause a rock to drop (like digging) wand of striking hitting a secret door with expose and break it zapping {teleportation,cancellation,make invisible,polymorph} down affects any existing engraving similarly to writing with such wands monsters may use fire horns and frost horns Guidebook.mn now formats backslashes correctly when using GNU groff tools Add missing trident case to weapon type categorization. Fix weapon proficiency handling for missiles. accept "armour" spelling again for marker use (when writing was disconnected from wishing, this got lost) restrict writing scrolls and books by description give better feedback for some writing results whirly/wall-passing monsters should not be immune to falling rocks relearn spellbook even when spell already known (object amnesia fix) objects that have been called something but not ID'd are subject to amnesia ask what to call unknown spellbook which crumbles to dust when mis-read bullwhip only tries to get you out of a pit when you're in a pit humanoids, gnomes, and ogres now eat; fungi and jellies don't centaurs, giants, and various others can respond to #chat potion of paralysis doesn't inherit prior nomovemsg #naming a nameable artifact when the object already had a name of the same length didn't create an artifact applying unID'd potion of oil is possible even not carrying any other items eligible to be applied make potion of oil become known after lighting it via apply fix remaining inconsistency which allowed diluted water don't let breaking a wand of digging on castle level produce holes, just pits make Nazgul's sleep gas actually put victims temporarily to sleep applying a carried, unlocked, trapped chest will set off the trap explosion due to #untrap failure on trapped door destroys it shouldn't hear curse/bless status of unseen scroll being read by monster give some variation in the amount of time it takes a corpse to rot away breakable objects hitting the ceiling or the hero's head will now break undead turning now gives credit to player for destroyed monsters undead turning now brings dead eggs back to hatchable status code added to support hatching of all eggs in a merged group of eggs fix display updating at egg's former location when floor egg hatches fix learning of egg type for hatched eggs statue traps created with monster inventory inside them probing shows contents of everything with contents, not just statues spells of healing and extra healing don't make target monster angry use cornuthaum cancellation factor can't kick underwater objects from land or vice versa objects falling through holes/trapdoors to random destinations obey arrival restrictions imposed by special levels being bare-handed counts as wrong projector when throwing projectiles reduce the range that Mjollnir can be thrown keep Medusa from continuing to move after she's been killed by reflection of her own gaze (fixes relmon panic) medusa's reflected gaze won't affect it if it has amulet/shield of reflection eating amulet of strangulation can choke when not satiated; also not gluttony intelligent pets hold onto one pick-axe and one unicorn horn keep exploding boulders from land mines from hitting you with "a rocks" objects carried by migrating monsters have no location more robust parsing of user-supplied option names; trailing characters matter don't generate spellbooks inside statues of tiny monsters treat Medusa level statues as petrified monsters (can't be stone-resistant, and have inventory) Medusa doesn't gaze more than once per round data.base: eliminate duplication of Orcrist/goblin king entry handle luck conferring artifacts correctly (both inventory and enlightenment) prevent arming land mines and bear traps in various inappropriate locations prevent easy shop exit by having shopkeeper disarm and pick up trap objects oilskin cloaks allow defender to slip away from grabbing attacker make reading the cursed Book of the Dead riskier enchanting stat-affecting armor now identifies it fix crash caused by specifying "pickup_types" without a value in config file or NETHACKOPTIONS (avoid attempt to use menu prior to interface init) kicking at empty lit corridor with lit_corridor enabled doesn't redraw as unlit when starting out with an oil lamp, make pre-discovered potions of oil show up in the discoveries list so that their varying description is available being crowned Hand of Elbereth enables minimal longsword proficiency even when Excalibur isn't bestowed bare-handed and martial arts weapon skill rankings use names instead of numbers Platform- and/or Interface-Specific Fixes ----------------------------------------- tty: reduce alloc/free activity done for message history tty: windowtype:unsupported_value pauses between listing allowed value(s) and proceding under default interface X11: free allocated memory during pre-exit cleanup X11: display help when DLB is enabled X11: fix popup inventory window shown for 'i' response to "what type of object?" prompt with menustyle={T,C} DLB: avoid excessive fseek calls (major performance hit for MSDOS) MFLOPPY: wasn't safe to enter endgame! traps, timers, and other level- specific data ended up being inherited from level 1 MSDOS: now can re-enter game after chdir'ing in shell from "!" MSDOS: fix it so -H allows starting a healer game, rather than usage statement MSDOS: display cursor during input prompts, not just when in the map MSDOS: fix several cursor-related glitches when moving the display MSDOS: prevent the use of F3,F4, and F5 before the map window is ready MSDOS: make flags.BIOS and flags.rawio the default when VGA tiles are used TERMINFO: colors were wrong for some systems, such as Linux Amiga: count substitute tiles properly MAC: avoid MW 68K struct copy optimization bug (in all developer releases up to and including DR9) by adjusting our structures so it doesn't occur MAC: fix crash when trying to drag scrollbar MAC: add UPP setup for UserItem FrameItem() MAC: boost partitions to 2M minimum General New Features -------------------- #qualifications command eliminated; subsumed into #enhance OEXTRA temporary compile-time option menu support for group accelerators to choose objects by class lev_comp supports specification of percentage chance for monsters and objects wielding Sunsword provides protection from light-induced blindness interactive setting of options via menu (Per Liboriussen, liborius@daimi.aau.dk) Platform- and/or Interface-Specific New Features ------------------------------------------------ MSDOS: Add support for preloading all tiles in protected mode environments MSDOS: Add support and initial tty Makefile for yet another compiler (Symantec) BeOS: preliminary support for new BeBox platform; initially tty only nethack-3.4.3/doc/fixes32.20100644000000000000000000001654307764735041013776 0ustar rootrootGeneral Fixes and Modified Features ----------------------------------- make `recover' work with the additional element of version info added in 3.2.1 floating eyes cannot escape down stairs and ladders do not use body_part() inappropriately when snatching monster's weapon fix feedback for a confused long worm attacking itself avoid converting locked secret door into closed+locked normal door; doors should be flagged as either locked or closed but not both kicking a locked secret door mustn't yield an open normal door fixes for dipping weapons into potions of oil fix crash triggered when knocking off worn blindfold by applying cursed towel update screen display for vault guard picking up gold from fake corridor Chromatic Dragon was missing appropriate resistances for orange (sleep) and yellow (acid + stoning) dragons when triggering a chest trap, clear the trap flag immediately [bones fodder] when a boulder gets pushed into a pit where a monster is trapped, immediately redisplay the monster after giving messages rings of hunger dropped in sinks should have an effect even if player is blind player #offering a cockatrice corpse must pass a touch check hitting a rust monster with a pick-axe, iron ball, or chain will trigger rust damage to the weapon; ditto for rust traps when wielding such items cosmetic martial arts and bare-handed changes to skill arrays in u_init.c gain or lose weapon skill slots appropriately when polymorph into new person fix crash occuring when self-hit by uncaught boomerang when delivering a pline message during level change, don't display areas of the new level using line-of-sight data from the old one heavy iron balls may be thrown multiple spaces (presumably they roll), restoring old ball behavior get rid of "non-null minvent despite MM_NOINVENT" warning prevent a negative damage adjustment from boosting a target monster's HP give "bashing" message when first attacking something with unconventional wielded items besides just throwing weapons and non-weapon tools when restoring, reset weapon so that "bashing" message can be given again hole traps in bones data shouldn't be marked as unseen when carrying 52 items, don't check shop goods for mergability with invent because it will give false matches, yielding non-gold in slot '#' kicking a cockatrice corpse is now as dangerous as kicking a live cockatrice fix set_apparxy() crash when the Wizard returns via migrating monster list monster wearing armor is protected from disintegration breath like player monster wearing amulet of life saving survives disintegration breath greased helmets will block AD_DRIN attacks get rid of ancient check for welded weapons, which arbitrarily named or didn't name the weapon for no particular reason. levitation: sitting makes you tumble, kicking requires bracing empty bag of tricks won't cause bag of holding to explode prevent "force bolt" from hitting false match on *orc* data.base entry prevent "{wand,scroll,spellbook} of light" from matching "* light" entry non-confused genocide of player should not kill by "genocidal confusion" re-word message for monster grasping already-wielded unicorn horn fix various killer reasons when pushing boulders, make sure current is always top object at its location always clear unpaid items off shop bill when shk is teleported away, even if shk was already angry don't let broken wand of digging create traps at locations which already have traps (prevent it from turning a hole into a pit) don't give messages about unseen objects falling down holes fix to prevent kicked objects which stop on holes/downstairs from becoming unattached from any object list don't let flying creatures set off a rolling boulder trap fix to prevent seeing into a room by kicking an undiscovered locked secret door from outside account for case of monster throwing gem at PC unicorn schedule repair for shop door smashed by big monster update status line for energy used when "you fail to cast the spell correctly" polymorphed character will mimic gold after eating mimic corpse fix relmon panic when bashing weak undead with wielded potion of holy water holy and unholy water can trigger transformation in werecritters call update_inventory() when discovering or undiscovering (call " ") an object fix goto_level panic: if quest leader seals portal, delete portal trap from quest home level as well as from main dungeon's branch level [possible return to quest via 'W' quest artifact] prefix quest leader and/or nemesis name with "the" when appropriate at run-time rather than using hard-coded text in quest.txt fix endgame crash caused by string overflow when formatting priest|minion names dokick.c compiles when WEAPON_SKILLS is disabled burning objects go out when kicked monsters with arms but not legs (salamander, marilith) can't kick knights can't jump while poly'd into anything without legs try harder to get names for corpses of unique monsters right very high dexterity doesn't guarantee a hit for thrown potions and eggs blinding ammo thrown from inside an engulfer can't blind it monsters going through endgame portals arrive in same area as the player instead of ending up at the portal to the next level treat most of the moat on fakewiz levels as outside the special central area, so that falling or wading into the water and auto-teleporting out of it can't strand the character inside the room monsters created by animating a named figurine will inherit that name prevent possible player-controlled creation of unique monsters via tossing statues of such onto statue trap locations activating a statue trap with wand or pick-axe won't discard statue contents cursed non-weapons can't slip when thrown, as it was in 3.1.x don't reveal patron deity of high priests with the 'C' command's prompt two flags structures now, flags and iflags, the latter not saved with the game object name prefix buffer wasn't big enough for biggest possible case negatively enchanted weapons thrown by monsters could do negative damage prevent xorns from phazing through walls on astral level live Wizard won't teleport to your level if he's carrying the Amulet can't use 'C' to give the Wizard a name fix charging for shop goods broken via striking/force bolt prevent disintegration breath from destroying Famine and Pestilence and from triggering impossible("monster with zero hp?") for Death prevent attached ball and/or chain from becoming part of iron golem formed during polypiling (ball & chain movement later accessed freed memory, which either crashed or got "remove_object: obj not on floor" panic) Platform- and/or Interface-Specific Fixes ----------------------------------------- Mac: update `mrecover' Mac: handle `-@' character name suffix for explicitly requesting random role msdos: suppress tiles on rogue level when restoring games that were saved there tty: support group accelerators for PICK_ONE menus tty: after at a yn() prompt, don't blindly accept the character used to get back to the prompt as the yn() result [could trigger impossible("invalid sell response")] Unix+tty: guard against problems with delay_output,TRUE/FALSE macros X11: fix group accelerators and support them for PICK_ONE menus X11: implement tty-style counts for menu selections X11: proper pop-up placement with old-style window managers (eg X11R6 twm) General New Features -------------------- Platform- and/or Interface-Specific New Features ------------------------------------------------ nethack-3.4.3/doc/fixes32.30100644000000000000000000000323007764735041013764 0ustar rootrootGeneral Fixes and Modified Features ----------------------------------- Y2K fix: use 4 digit year values for the dates in the score file updated COPYRIGHT_BANNER_A to reflect year of release prevent "late" pline calls from triggering a crash when the RIP window was displayed at end of game (observed when bones file rename failure under Win95 was reported to wizard mode users) being punished on the Plane of Water doesn't trigger a panic when air bubbles try to move the ball&chain or you around avoid rn2(0) divide by 0 for empty inventory when trying to crawl out of water don't let randomly placed monsters on special levels prevent explicitly placed monsters who target that location from being created (a web trap's spider resulted in no quest nemesis) don't let randomly placed stairs on special levels be covered by explicitly placed features such as fountains pager: guard against '%' in output from being treated as a printf formatting directive (using '/' or ';' to look at food yields "% blah blah") prayer result of ``escape from solid rock'' isn't inhibited by teleport restrictions (attempting to fix all troubles got stuck in a loop) report "file empty?" rather than "version mismatch" when that's the reason why a data file fails its validation check drum of earthquake can't destroy the high altars Platform- and/or Interface-Specific Fixes ----------------------------------------- micro (assorted): readmail()--don't show fake mail text when blind; also, update the "report bugs to" message to specify msdos: fix missing $(INCL) in dependency in djgpp Makefile mac: Will only dispatch events if the window system is initialized nethack-3.4.3/doc/fixes33.00100644000000000000000000005173207764735041013774 0ustar rootrootGeneral Fixes and Modified Features ----------------------------------- objects falling down a level don't cause everything at destination to scatter randomize visible trap glyphs during hallucination don't match statue entry when looking up statue trap [after trap detection] do match statue entry when looking up "statue of a " when foo happens to precede statue in the database; likewise for figurines initialize random number generator before processing user configuration file (random role selection always selected tourist) support "character:X" and "role:X" in NETHACKOPTIONS as well as in config file allow colon as an alternative to equals sign for `OPTIONS:whatever' and equals sign as an alternative to colon for `pickup_types=?!="$' make rndexp (blessed gain level) be safe for 16 bit integer configurations don't add player's weapon proficiency bonus for weapon attacks by monsters create quest artifact crystal balls with 5 charges instead of 0 store ghost names in the same manner as other monster names (fix pet bug) boost kobold shaman level to 2 (was 1, too low to ever cast a spell) boost ogre king level to 9 (was 7, same as ogre lord) throwing quest artifact to quest leader won't cause anger; also, artifact will be caught and thrown back instead of being explicitly ignored boost level of fake players in endgame to match their rank titles don't lose odd hit points (integer division truncation) when splitting HP for cloned monsters update status line when cloning yourself halves your hit points suppress clone's initial inventory for poly'd player just as for monsters update the documention describing the O command polyself: immediately update vision when reverting to human from eyeless form use right pronoun when a mind flayer's attack is blocked by a monster's helmet tins of lizard meat are never rotten, just like the corresponding corpses tattered capes should not match ape entry in database booze should not match ooze entry in database lowered drawbridge should not match werecritter entry lengthen option file line length to 4*BUFSZ make zaps of death at polymorphed players work properly change way invisibility works, add remembered invis monsters and 'F' command don't list pick-axe and unicorn horn as likely candidates for charging give more accurate message when nymph steals multi-turn armor from female char fix splitting merged group of wielded weapons for menu mode version of #loot if a buried container rots away, bury rather than destroy any contents the 'W'ear command now only shows armor you can actually wear at this instant, instead of all armor you're not currently wearing wishing for a genocided monster egg gets a dead egg, not a generic egg "Unfortunately it is still genocided" printed only if monster is in range (particularly important for lifesaved monster genocided off-level). message for monster growing into genocided monster only printed if in range include number of attached candles when formatting candelabrum's name support attaching already lit candles to candelabrum range of candlelight varies with number of candles dropping ring of hunger onto sink won't falsely claim that undestroyed objects like the Amulet have vanished winged gargoyle can't wear body armor self probing and stethoscope display speed with same detail as enlightenment throwing attacks can trigger reprisals similar to hand-to-hand and zap attacks 'A' now works in dropping like when picking up make setting bear traps and land mines be a multi-turn occupation make lava be properly lit on special levels add orig.female flag to handle E quest monster situation clean up inconsistent quest text in initial legacy message, use "goddess" when appropriate allow FIRSTNEMESIS message to actually be printed taking a peaceful monster's weapon with applied bullwhip will anger victim applying an unpaid magic lamp will charge a low lighting fee instead of the djinni release fee teleporting a Rider will usually bring it near you instead of sending it away Riders can open locked doors without a key, just like the Wizard Riders, angels, and elves won't avoid stepping on Elbereth/scare monster when deciding where to walk Riders and angels will ignore the sanctuary effect of temples mind flayers cannot suck out brains by hitting long worm tails don't ignore object age when #offering a partially eaten corpse inability to pick up is not as general as nolimbs (blobs may pick up with pseudopods and purple worms by swallowing) wishing for a magic lamp produces an oil lamp, not a no-charges, possibly lit, magic lamp blobs may not ooze under doors if their inventory can't be squeezed through peaceful/tame monsters will not use bullwhips on the player ghosts were not inheriting player gender in bones files cannot wish for tins of untinnable (due to insubstantiality) monsters flying monsters cannot fall down stairs prevent divine retribution from destroying a wand which is being broken fix resuming to read a spellbook which has become blank since the prior read attempt got interrupted make recharging cancelled wands behave like recharging other cancelled objects prevent "late" pline calls from triggering a crash when the RIP window was displayed at end of game (observed when bones file rename failure under Win95 was reported to wizard mode users) cannot shatter soft weapons (whips, rubber hoses) being punished on the Plane of Water doesn't trigger a panic when air bubbles try to move the ball&chain or you around seen-invisible monsters are consistently visible but transparent, rather than looking like normal monsters kicked object message for hitting another object no longer claims it "stops" kicked object hits objects (plural) if quan>1 but there is nothing else there kicking an object which is embedded in a closed door behaves like one in rock can't kick object out of a known pit, but could when pit hadn't been seen yet pets, shopkeepers, unique monsters, trolls, and Riders retain their characteristics when killed and brought back to life being polymorphed into a black light makes you hallucination resistant don't attempt to perform panic save if the game is already over don't leave old game's timers, light sources, and shop data in place if aborted restore attempt reverts to starting new game [eventual panic] Magicbane carried by mplayers has a lower enchantment than other artifacts if pets take longer to untame than to starve, make them go wild anyway split up erosion to allow both rust and acid (or fire and rot) rust/fire/corrosion/rot now work in all cases (monster/monster, monster/you) upon arrival to quest, mark return portal as seen can't be blinded by light while asleep can't put boulders or big statues into containers engulfers which engulf a pile engulf 'several objects' polyself: use right set of hit points for hunger and strength loss polyself: likewise when checking for troubles during prayer polyself: stop mimicking gold immediately if shape change occurs polyself: change monster type when sex change occurs for succubus or incubus Y2K fix: use 4 digit year values for the dates in the score file when changing levels, update the screen to show the new level sooner when changing levels, a monster might displace you from the stairs upon arrival petrify polymorphed player who has protected hands but is using a non-hand attack on a cockatrice fix bug where barehanded AT_WEAP by polymorphed player on cockatrice worked prevent multiple purchases of clairvoyance at temple from overflowing the intrinsic's timed subfield and becoming permanent when cursed, greased or oilskin cloak might fail to protect against grabbing when any corpse wielded by a monster rots away, unwield it to avoid "bad monster weapon restore" hallucination affects priest and minion names don't try to make the word "aklys" singular bullwhip can't yank welded weapon from target eroded T-shirts now display the eroded shirt text consistently fix "killed by kicking something weird" when kicking a fountain disallow fruit names whose prefixes are valid for food (uncursed, numbers, etc.) properly handle wishing for fruits which start with other prefixes avoid rn2(0) divide by 0 for empty inventory when trying to crawl out of water don't let randomly placed monsters on special levels prevent explicitly placed monsters who target that location from being created (a web trap's spider resulted in no quest nemesis) don't let randomly placed stairs on special levels be covered by explicitly placed features such as fountains substitute random monsters when special level monsters have been genocided fix intrinsic blockage by worn items so that wielding a mummy wrapping or cornuthaum won't have the same special effect as wearing one magic markers created via polymorphing tools are flagged as being recharged unseen rust monster eating messages, and make tame rust monsters consistent with wild ones with regard to rustproofed items pager: guard against '%' in output from being treated as a printf formatting directive (using '/' or ';' to look at food yields "% blah blah") getpos: support shifted movement letters in number_pad as per help text getpos: properly truncate diagonal movements at map edge using #name to call an object type something could be used to distinguish fake amulet of yendor (appeared in discoveries list) from real (didn't) upon quest completion, leader now IDs quest artifact and also tells player that Bell of Opening is necessary if character doesn't already have it remove unwanted quote marks from quest message R 70 make polymorphed objects be likely to retain magic state: non-magic items usually yield other non-magic items, magic items yield magic ones make artifact mirrors unlikely to break when used to hit monsters make sure that nemeses don't leave corpses if the message says there's no body fix wizard-mode problem with generating Master of Thieves (was singularizing it) allow weapon-using monsters who ignore gems to throw darts make flint stones be the preferred ammo for sling wielding monsters gaining/losing telepathy via polymorph (i.e. mind flayer) redisplays monsters prayer result of ``escape from solid rock'' isn't inhibited by teleport restrictions (attempting to fix all troubles got stuck in a loop) fix surviving level teleport to a negative destination from somewhere other than the main dungeon (was corrupting the level maps) surviving level teleport to a negative destination ("you float down to earth") escapes the dungeon instead of arriving on level 1 dying due to level teleport directly to heaven won't leave bones kicking shades with blessed boots, punching with blessed gloves or when wearing silver rings, does the appropriate damage to them add artifacts to ending score and display prevent used objects like scrolls and potions which immediately cause the character's death from remaining in final inventory (disclosure+bones) blessed genocide of '@' will list the player's role during genocide disclosure moved skill definitions to their own file (skills.h) and embedded them in the object table. increased the maximum number of branches supported by dgn_comp. increased the number of characters permitted in a role name. the number of bits available for properties are expanded. water demons should not chat about being freed. since hallucinating players see monsters constantly change anyway, don't print message when werecritter changes artifacts which do fire/cold/electric damage to their targets can destroy carried objects which are susceptible to that type of damage some artifacts are now unaligned in order to be more accessible to all types of characters wizard mode ^F command reveals floor traps along with the map pager: '/' was not finding data.base entries for shopkeepers, mimics, or race/role spit when picking from the screen small monsters like hobbits and gnome zombies couldn't wear cloaks/wraps make sure non-erodable objects aren't eroded or erodeproof (could happen by wishing or object polymorph) consistently let iron non-weapons rust, etc. handle more spelling variations ("boots of speed",&c) when granting wishes fix 3.2.0 change which flags the castle and priest quest levels as graveyards when stepping on a spot where "there are several objects here" (so many objects that they aren't automatically shown to the user), report any dungeon feature such as stairs just like when there are fewer objects report "file empty?" rather than "version mismatch" when that's the reason why a data file fails its validation check to-hit bonuses don't accumulate for monsters with multiple weapon attacks skill definitions moved to skills.h skills are stored in the objects[] table. intrinsics and extrinsics are now >32 bit number of roles no longer limited to 26 letters renamed typename() to obj_typename() add "You hear a nearby zap" when monster is close fixed a bug that would print of "a Book of the Dead" instead of "The" fixed a bug so there is no delay when a rolling boulder trap is triggered completely out of sight fixed emergency_disrobe() so it will drop gold fixed a missing case that occurs (rarely) when praying during a full moon and your god is very pleased ask for confirmation before praying; no more accidental Alt-P more guilt messages when you do something which lowers alignment mplayers get more suitable equipment for their role allow spaces before = in the options file dragon scales/scale mail of all colors now work when worn by monsters (in 3.2.x, only gray conferred any special benefit) when shopkeeper takes cash from dead player's corpse, clear `been robbed' status if there's enough gold to cover the amount so that next player who loads level as bones data won't start out owing money merged scrolls of scare monster crumble to dust together, matching the existing feedback (was destroying one and leaving the rest) properly disallow wishing for venom and allow wishing for iron balls by class drum of earthquake can't destroy the high altars potion of oil can't be ignited while underwater zapping a wand of digging upwards while underwater won't dislodge a rock from the ceiling add "born" field so monster extinction limits the number created, not killed allow "okonomiyaki", etc. to pluralize properly (Ranma 1/2 is popular) fix off-by-one bug that disabled the check to see if you tried to name your fruit after a previously existing corpse or egg avoid a "glorkum" message if an object conveying a warning is stolen before the warning message is delivered flags.made_amulet flag was never being set make sure proper message is given when tinning cockatrice while a flesh golem fix punctuation on cancelled cobra's dry rattle message leash cannot choke monsters that do not breathe rothes are now brown, harder to confuse with much more powerful grey quadrupeds defer level change for every schedule_goto() call, not just while monsters are moving (player's move could cause an engulfer to expel character onto a level changing trap, then attempt to access stale monster and possibly trigger relmon panic or crash) fix obscure worm bug which did not consider the tail tip to be visible. Bug produced "You miss it" on 3.2 and a blatantly obvious 'I' in prerelease 3.3. water prayer: treat already blessed potions as `other' rather than as `water' water prayer: potions being blessed glow light blue rather than amber; hallucination affects the color seen when changed potions glow fix Death/Sandman #9 joke (should be 8) and make sure the message can be seen zapping Death with wand of death multiple times could cause hit points to wrap when pet attacks monster that attacks back, be sure it's in range (could be a worm attacked on the tail) Platform- and/or Interface-Specific Fixes ----------------------------------------- micro: -uwizard-{class} counts as -uwizard when allowing debug mode micro (assorted): readmail()--don't show fake mail text when blind; also, update the "report bugs to" message to specify devteam@nethack.org msdos: fix overlay separations in weapon.c msdos: fix problem breaking compile without REINCARNATION msdos: fix dependency in djgpp Makefile (wintty.c -> hack.h) tty: try to use terminfo sgr0 (aka termcap me) attribute to turn off all text attributes, instead of just using "rmso" (aka "se") attribute. tty: change name of nethack's termcap.h to be tcap.h tty: ^P at a long prompt printed an extra newline (and then wrapped oddly) tty: get repeat to work properly on extended commands tty/ASCIIGRAPH: rogue level uses PC Rogue colors and symbols nt: in TTY port, non-English keyboard layouts that depended on AltGr-+ sequence were getting "Unknown command 'M-\'" for '\','@','$','{','[',']','}'. tty and X11: avoid crashing trying to display long (>128 char) menu items X11: avoid setuid install problems by changing uid to real uid while opening the X11 connection. unix: compress/uncompress detects failure of the compressor, such as for filesystem full or missing compressor, and no longer deletes the valid file. In the uncompress case, such as uncompressing the save file, a message is generated as well. dlb: handle situation where lseek(,,SEEK_END) doesn't yield the size of the contents of a file (specifically, VMS "variable length" record format) vms: install.com couldn't handle the `copy readonly files' step when DLB wasn't enabled mac: added unix tty-ish menu flexability mac: stoped using OLDROUTINENAMES mac: added dlb support mac: Increased the maximum number of menu items, so the inventory won't get cut off at the bottom. mac: Changed the behavior of Cmd-Q so it uses the new #quit command. mac: Will only dispatch events if the window system is initialized. This fixes a bug that would crash the system if the user had an invalid option in the NetHack Defaults file. mac: Added an appropriate message when eating an apple. mac: Change the askname dialog for the new role patch. mac: Add a gray background to all dialogs. mac: Replace some improper calls to InitCursor(). mac: Remove a whole bunch of unused code. mac: Added Balloon Help messages. mac: Pop-up menus display the 3-letter file code instead of a single letter. mac: Pop-up menus and text item have a 3-dimensional look. General New Features -------------------- incorporate the "wizard patch" `#quit' command added `*' command added; displays inventory of all equipment currently in use add Stone To Flesh spell wands eventually explode if rechaged too many times show IDed Amulet of Yendor + invocation tools in own section of discoveries list; likewise for IDed artifacts add infravision add Eyes of the Overworld add lenses split players race from role in life cursed figurines cam spontaneously transform when carried `in_use' struct obj field is unconditional rather than just #if !NO_SIGNAL add the secondary weapon slot, e(x)change command, #twoweapon command, and "pushweapon" option. add the quiver slot, (Q)uiver command, (f)ire command, and "autoquiver" option (defaults to false). add the "pickup_burden" option which controls when the user is asked for confirmation when picking up an item. pole-weapons can be applied at a distance, and similarly used by monsters. '/' command's pick-a-location input (getpos) supports shortcuts to bypass the "more info?" prompt; ':' for '.'+'y', ',' for '.'+'n', ';' for ','+ESC monsters can throw cockatrice eggs at players prayer trouble "stuck in wall" takes boulders into consideration crysknives can be "fixed" vampires now #chat back new monsters: chickatrice,pyrolisk,fox,coyote,winter wolf cub,dingo, gas spore,flaming sphere,shocking sphere,lynx,panther,raven, glass piercer,mastodon,woodchuck,centipede,master mind flayer, pony,horse,warhorse,silver dragon,lichen,storm giant,arch-lich, dwarf mummy,green slime,disenchanter,monkey,dwarf zombie,ghoul, paper golem, gold golem,glass golem,prisoner,jellyfish,piranha, shark new objects: amulet of unchanging,silver dagger,silver spear, silver dragon scales/mail,robe,alchemy smock,kicking boots, kelp frond,eucalyptus leaf,scroll of earth,spell of drain life, potion of acid,potion of full healing,potion of polymorph, potion of sleeping,ring of free action,ring of gain constitution, ring of increase accuracy,ring of slow digestion,grappling hook, ring of sustain ability,wand of enlightenment,saddle,various gems add Monk role the old Elf role is replaced by the Ranger add Human, Elf, Dwarf, Gnome, and Orc races add multishot ammunition add graves, iron bars, trees, and arboreal levels dwarvish mattocks can be used to dig add leprechaun, cockatrice, and anthole special rooms add the Sokoban dungeon implement talking artifacts members of the clergy (aligned/high/player priests and monks) are generated with a robe instead of chain mail. new tin of meat types tinning kits and cameras have charges blessed magic mapping detects secret doors starting spells are known at start of game pre-discoveries are listed with an * voluntary challenges with #conduct add a funny message when eating tridents and flint stones allow debug-mode level teleport to the sanctum some #monster commands now consume energy trees can be kicked as a possible source of fruit Wile E. Coyote references when using '/' on a coyote Platform- and/or Interface-Specific New Features ------------------------------------------------ WinNT: implement mail support WinNT: console mouse support added to TTY port nethack-3.4.3/doc/fixes33.10100644000000000000000000006164207764735041013776 0ustar rootrootGeneral Fixes and Modified Features ----------------------------------- discarding a tin without eating should not count towards food conduct expand 'nethack.cnf' in dat/help to include new names on some platforms using 'C' to name a steed produces a "pony tail" stopping reading a spellbook when "too much to comprehend" left in_use set conduct: eating meat{ball,stick,ring,huge chunk} counts as eating meat don't select gems--aside from rocks and known glass or flint--via autoquiver skilled slingers can shoot multiple rocks with one shot, like other archers orcs shooting orcish arrows from orcish bows get multishot bonus, like elves have 'Q' offer gems/stones as likely quiver candidates when wielding a sling 'Q' command--don't offer tools as likely quiver candidates spell hunger effect for wizards of high intelligence was not computed correctly fix "killed by the [master] mind flayer" bug redisplay correct trap glyphs when hallucination ends monsters under Conflict cannot attack other monsters that are already dead monsters that steal gold from monsters should teleport fix mummy wrappings worn by monsters to block invisibility applying a weapon or wieldable tool would sometimes give spurious messages about two-weapon combat applying a weapon or wieldable tool might not always end two-weapon combat receiving a divine gift artifact while wielding two weapons would unrestrict two-weapon skill instead of the skill for the artifact's type throwing and kicking while wielding two weapons exercised two-weapon skill when wielding two weapons, ')' command should show both giants cannot "easily pick up" boulders on the Sokoban level W command would let you wear an arbitrary item in your body armor slot if that was empty & uncovered and you carried extra armor for any filled slot W command would list entire inventory if you answered '?' to the "what do you want to wear?" prompt when all unworn armor couldn't be worn #looting and applying containers with menustyle != traditional would do bad things if you split a merged stack in quiver or secondary weapon slot save/restore while mounted or stuck could cause a game crash or other errors baby gray dragons should not be visible to infravision dying from a failed saddle attempt should name the monster without using hallucination spurious "Bummer, you've hit the ground" when hallucinating and dismounting constitution of <3 and >18 (possible in 3.3 because the ring of gain constitution was added) was not handled properly potion and wand of invisibility (on yourself) should not print message if you are already invisible, even if you can see invisible reviving tame monsters ended up tame but not peaceful and would attack you wishing for "rotproof" item is recognized as synonym for erodeproof your pair of boots "are" not affected when kicking rust monster should be "is" use article "a", not "an", with "eucalyptus leaf" fix crash if reviving troll has been genocided shouldn't see candles flicker when blind gas clouds use cloud symbol unchanging suppresses amulet of change, intrinsic lost by life-saving missing lucern hammer, silver dagger, silver spear in monster weapons buckled boots are brown Scorpius and centipedes are not web-makers race placeholders are M2_NOPOLY Monk species/leader/guardians are M1_HERBIVORE leader/nemesis flags fixed with |= instead of = freezing spheres won't leave corpses artifacts should add to ending score even if they are inside a bag being killed by a gas spore should not be treated as burning (most noticeable problem was that the death message did not include "killed by") remove a double period from "Caught himself in his own fireball.." automatic dog names restricted to dogs chatting with a monster that teleports after the chat (succubus, bribable demon) would put an 'I' symbol at the monster's destination stethoscope/probing should reveal identity of invisible monster, not use "it" wand of probing zapped at 'I' square with no monster should clear the 'I' cursed potion of invisibility drunk by monster should reveal 'I' kicked monster that evades kick by moving to unseen square should not leave 'I' in original position of monster closing a door on an invisible monster reveals the 'I' gas spores are recognized as having passive damage for purposes of pet attack since iron armor can now corrode, don't call all corroded armor "bronze armor" properly handle attacking a black pudding with a corrodeable weapon do not print "You still cannot see" when blind and removing lenses remove possibility of crashes when unseen monster engulfs items object shattered by wand should use plural verb when object is plural don't anger monsters when hitting them with invisibility or helpful unholy water for initial inventory, don't give out spellbooks in restricted spell skills for tourists' initial inventory, put darts in quiver rather than wield them artifact discoveries sometimes showed undiscovered object types (for example, Snickersnee as "katana" when katana was still known as "samurai sword") "iron bars" singularization exception should not also catch "candy bars" if a monster kills a monster by throwing acid, don't credit the kill to you leave two-weapon combat mode if either weapon is stolen or otherwise unwielded use worse of (two weapon skill, current weapon skill) when figuring skill bonuses and penaltys while fighting with two weapons never give back-stabbing or weapon-shattering bonus when using two weapons engulfing monster will not engulf your pony while you are riding arch-lich usually starts with an athame or quarterstaff do not say that "an" Asmodeus reads a scroll '?' command--short options help sometimes included garbage output '?' command--longer options help omitted several recent options eating an amulet of restful sleep now works properly getting hit by a potion of sleeping now works properly sleeping is reported by enlightenment detect unseen / secret door detection refreshes unseen monster (`I') glyphs monsters won't pick up objects in water (especially kelp) unseen check for monsters in explosions fixed "petrified by an " silver arrows cost a little more than other arrows javelin back in its own class dipping weapons in potion of oil now works properly freed prisoners become peaceful monk titles shortened so they aren't cut off elven Priests get their starting musical instrument you can now correctly ride centaurs fixed steed getting teleported (e.g. by Quantum mechanic) fix stethoscope/probing speed reporting, and slowing attack on player blessed detect monsters increments (not sets) the timeout, and produces a message if no monsters are on the level put "Elbereth" under the sokoban prize so that monsters don't eat it a weak race can still have a high strength if polymorphed into a strong monster make dingos non barking canines suppress zap up/down message for stone to flesh on non-stone levels fix missing spaces on sokoban level that made level impossible without cheating use case-insensitive comparison for wishing (needed for Master Key of Thievery) avoid commas in the player name because they confuse the record file note Sliming when using probing/stethoscope on yourself fix inconsistency: reflecting medusa's gaze while invisible didn't work, reflecting floating eye's gaze did Medusa should not drink potion of invisibility (the code only checked for wands) restore confirmation prompt for kicking pets and peaceful monsters ask for confirmation about kicking steed when kicking while mounted converting secondary weapon into an artifact (naming, dipping) stops #twoweapon a fully ID'd object converted into an artifact is no longer fully ID'd polymorphing an object by dipping in potion while inside a shop will only anger the shopkeeper if the object is shop merchandize make {wand,spellbook,potion} of polymorph immune to being polymorphed turning undead should count as calling on a deity for purposes of conduct fix "monster trail" problem caused by reading a scroll of magic mapping while engulfed don't give Slow_digestion-related message when non-digesting engulfer expels you vary vampire's chat responses according to time of day, tameness, and player form added fish_parts to mbodypart/body_part fixed do-while loop test criteria in create_mplayers() fix crash if reviving troll has been completely drained by Stormbringer, et al a stinking cloud should not kill a monster more than once player stops riding when nymph steals saddle don't ask for name for eaten ring of slow digestion if already identified don't let engulfed lifesaved monster beat you up while supposedly being totally digested lev_comp: honor class in OBJECT entries (user's '+',"identify" made scroll) fix uninitialized buffer/unprintable characters error when eggs hatch accept "aluminium" as variant spelling for "aluminum" don't die from lava while praying correctly display gems for the final score even when blinded throwing a boomerang from {wielded,secondary,quiver} weapon slot will have it be restored to that slot if caught upon return don't allow iron balls to pass through iron bars fix "What weird role is this? (E)" for names taken from 3.2.x score records make spell of jumping work properly when restricted in escape spells save traits of petrified monsters; animated statues are like revived corpses unmoving monsters seen by infrared are removed from/displayed on the screen when they leave/enter direct line-of-sight Sting and Orcrist get their anti-orc bonus against orc player characters buffer overrun caused by many long names in a single message polymorph can't indirectly transform scrolls of mail into blank scrolls via paper golem creation don't let savebones() name a ghost without checking for sufficient space don't report "killed by ghost of Foo called Foo" on tombstone or in record when breaking create monster wands, don't place monsters inside solid rock don't allow tainted cockatrice corpses to prevent stoning if you eat one oil isn't seen as dimly glowing if you're blind properly consider hallucination and blindness when printing sliming messages don't allow the player to jump through iron bars or walls (the latter only when wearing the Eyes of the Overworld) don't allow the player to hurtle through iron bars work around race condition between breaking a wand of teleportation, teleport control and autopickup rust traps should affect scrolls lev_comp returns error if level cannot be fully written out blank scrolls/spellbooks don't count as reading material fix seduction attacks to treat characters polymorphed into golems as neuter chaotic sacrificing on a chaotic altar may crash if demon creation fails failed demon summoning might cause monsndx panic avoid possible crash when casting fireball spell while engulfed or near the edge of the map prevent observation of dust clouds in rogue level doorways when blind cans of grease will no longer rust skip already dead monsters when scanning the full monster list; avoids monsndx panic and other potential trouble skip already dead shopkeepers when checking for tended shops level teleport high in the air while lifesaved should result in an escape the "stoned" flag wasn't reset when a monster was lifesaved from turning to stone, so the next monster you killed would always turn to stone wooden harp is not a magical object player characters got left at 10 when "normal" speed was increased to 12 time it takes a monster to change armor doesn't depend on whether you see it character can't be totally digested on first turn of being swallowed level 25 engulfer would trigger divide by 0 crash via evaluating rnd(0) wielded egg that hatched wasn't cleaning up worn objects and might cause crash mirror shouldn't show location of unseen monsters cloth headwear was being reported as leather when fire damaged modify moveloop so that time (moves) is not relative to the player's speed fix moveloop to account for player not accumulating enough movement points to move in a turn -- this fixes the reported "time is wrong when burdened" problem monsters should not teleport on levels that disallow teleportation consider existing poison resistance when printing message while eating don't allow various spells/effects to turn monsters into genocided species don't crash on abusing guardian angel (accessing edog) call useupall() rather than useup() for organic items burned by lava revive any Rider corpse which gets teleported wishing for gold should affect conduct gold detection should detect gold golems grease should affect the secondary weapon in two-weapon mode falling drawbridge, eating cockatrice eggs, delayed self-genocide all caused monsters to be fully named instead of using "it". change the You_hear message if hero is asleep various inventory changes did not immediately update when perm_invent was set avoid crash when multiple, cascading explosions occur pets are no longer permanently weakened by a brush with starvation doeat() doesn't leave rotten food half-set-up for resumption don't allow trying to resume eating a revived rider corpse shopkeepers, priests and peaceful monsters should get angry when you cast stinking cloud on them when crowning a neutral wizard who knows finger of death but isn't carrying its spellbook, don't drop his weapon (crash likely) similar greased and non-greased objects would merge together into one stack monster reading scroll of earth may be allowed an extra attack change message for failed attempt to mount steed while punished fix multi-shot throwing for darts and shuriken update monster multi-shot throwing to match player throwing prevent inappropriate use of "lungs" in creatures that have none change several instances of 'pline("The ' to 'pline_The("' monk characters kick as characters rather than as kicking monsters fix kicking shades by character polymorphed into kicking monster fix articles in some Sokoban trap messages and eliminate some superfluous messages restoring with damaged subroom shops on non-current level could dereference stale shk pointer prevent removal of levitation in sokoban pits from causing you to "float gently to the ground" peaceful/tame mindflayer now mindblasts hostile monsters and vice versa (the check was backwards) fix suppression of stone-to-flesh on unique monster statues kill player when drain life induces negative HPs rumors used as engravings should not refer to fortune cookies magic-resistant players/monsters unhurt by monsters zapping wands of striking fix time problem where disrobing took too long saddle that comes with a knight's initial horse should be known to player iron golems are sensitive to more ways of getting wet with water prevent odd contents of initial tourist tins and eggs (the contents were mostly from the quest level, producing many cave spider eggs) breaking a wielded wand doesn't leave it wielded if nymph hits monster on first attack and teleports away, suppress second attack kicking a mimic should reveal its presence using 'F' command on a pet with safepet should not produce "thin air" message polymorphing into slime or fire creature removes Slimed; becoming a new man resets the Slimed timer throwing cockatrice corpse barehanded should stone the player avoid "petrified by petrification" on tombstone avoid "turning into green slime" on tombstone (KILLED_BY didn't work if Slimed) since unchanging prevents sliming, make it reset any sliming already present avoid "You turn into a female succubus" redundancy player hit by potion of acid should take damage like monster "You are protected" in enlightenment display should include u.uspellprot chameleons that change into a non-moving, non-attacking form shouldn't get stuck fix bug where monsters didn't wield bow (etc.) before shooting arrows (etc.) medium size is too large for giant bats (it allows leaving plate mails when killed) player polymorphed to a ghoul resists sickness just like a ghoul monster player in werecritter beast form shouldn't polymorph into "human" player wearing scales of genocided dragon was getting duplicate "you feel dragon-ish" messages when polymorphing fix luck timeout for full moon and friday 13th monsters must wield polearms before using them, just like players when saving bones data, shopkeepers will claim dropped objects inside shops pets will now wear objects they pick up pets will now wield pick-axes when necessary limbless pets are no longer able to carry objects monsters cannot consider a mattock for digging if they are wearing a shield avoid a case where monsters keep switching between pick-axe and weapon override hallucination when reporting pets that ascended or escaped with player avoid duplicate pickup() calls when landing after falling through a hole added squeaky board traps to Lord Surtur's lair entrances cursed lenses no longer considered a major problem by deity prevent "seeing an image of someone stalking you" when Blind disallow potion of polymorph / ring of polymorph control starting combo disallow starting with blank paper tools shouldn't charge beyond 127 charges getting money from a fountain should set the looted flag pole-weapons won't bash and will advance skill when on steed blessed genocide of polymorphed unchanging player should kill picking up nothing should take no time quiver command should take no time potions should not be autoquivered as worthless glass players should not get double-billed when using or altering items silver dragons should have same resistance as other dragons golems should be un (reverse-)genocidable player should get blamed for destroying Minetown fountains by Excalibur dipping player should not get blamed for others destroying Minetown fountains digesting ghosts and shades as a purple worm should be nonvegan but vegetarian eating brains as a mind flayer should be nonvegetarian eating eggs should be nonvegan but vegetarian eating tripe, meat sticks, chunks of meat should be nonvegetarian headstones now implemented through engraving luck penalty for the remaining forms of "creative NetHacking" in sokoban don't penalize a turn if player cancels #ride direction Ranger quest is no longer a rip-off of the old Elf quest several Hello() messages were inappropriate for various monsters storm giants should talk monk leader and guardians should use clerical spells monks shouldn't start with scrolls of enchant weapon movement rate when saddled was miscalculated items under lava shouldn't been seen or picked up clicking in status line during `/' shouldn't cause getpos error huge chunk of meat should count as dogfood "Pardon me" when moving directly into peaceful monster shouldn't glow amulet and save life of digested monsters " gets angry!" only when you can see the square "Never hit with a wielded weapon" conduct should only count weapons and weptools lynxes should not have cold attacks Naming a specific object asks "What do you want to name *this* ___" "Having fun sitting on the floor" shouldn't over fountain "ball lightning" changed to "ball of lightning" "poisoned by a poisoned crude arrow" should be "killed by a poisoned orcish arrow" shouldn't see invisible monsters oozing under a door fix apostrophe for invisible seen-invisible crumbling-to-dust liches amulet of change when polymorphed into single-gender monster could produce inconsistent role name for Priest(ess) and Cave(wo)man prevent Fire Brand from "burning" a water elemental snatching cockatrice corpse gloveless by applying bullwhip will now stone inventory description of wielded two-handed weapon uses "weapon in hands" inventory description of secondary weapon explicitly lists it as non-wielded to reduce confusion about two weapon combat Bell of Opening removes attached iron ball when performing opening magic chatting to a monster who responds with "I'm trapped" reveals the trap Make tmp_at() work when called in the midst of a previous tmp_at() sequence Make the messages for attempting to wear lenses over a blindfold more clear Prevent buffer overflow when reading engravings that are BUFSZ in length paralyzation message on steed should not say your feet are frozen to the floor avoid buffer overflows and associated security problems from getenv(), program name, and user name Platform- and/or Interface-Specific Fixes ----------------------------------------- Mac: legacy message was being truncated Mac: black background left mess on backspace Mac: backgrounds set too early on game startup Mac: tty window positions not remembered after move Mac: tty window turned B&W when moved to bottom of screen Mac: tty quit command fixed Mac: remnants of previous hunger status now cleared MFLOPPY: add checkspace option to avoid problems with >2GB free space MSDOS: fix clearlocks() to look for the right file names, and not LEVELS.* (MFLOPPY only) MSDOS: remove djgpp stuff from the Microsoft C Makefile MSDOS: change NetHack.cnf to defaults.nh in NHAccess.nh comments MSDOS: add missing files to gcc 'make spotless' NT: WIN32 specific code in tty_nh_poskey() was missing the necessary code to clear window flags so after hitting ESC messages that should have displayed did not Linux: set MAILPATH properly Linux: don't use control characters on Rogue level with IBM graphics DEC UNIX: set MAILPATH properly, type lex functions properly, avoid conflict with curses over naming Qt: remove intermediate files on 'make spotless' Qt: modify makefile to allow use with BSD make and FreeBSD Qt: have player selection dialog come up when name specified Qt: use default menu accelerators and allow remapping X11: fix memory leaks is reading from dialogs X11, tty: avoid crashing when displaying empty menus, as from 'i' with perm_invent and no inventory tty: when given the choice of ANSI color (AF) vs standard color (Sf), choose ANSI since there is some disagreement as to the correct color order for Sf, but no such disagreement for AF. tty: add workaround for termcap misfeature in some Linux distributions which affects DECgraphics display Amiga: minimal functionality restored Amiga: recover created empty (and unused) save.info files Amiga: ^P works properly Amiga: windowcreating modified for better adaptivity Amiga: changed from intuition menus to gadtools menus Amiga: changed default colors in tilemode to those of gfxfile Amiga: window backfill works Amiga: playerselection adopted from tty-port Amiga: linesplitting in msg/inv/menu windows fixed Amiga: obey user configured pens in nethack.cnf Atari: tty port rescued from oblivion, Gem windowing added General New Features -------------------- gold/glass golems, glass piercers now resist acid added sharks, piranha, jellyfish, prisoners, and iron bars to special levels piranha can appear in swamp rooms hero falls off steed when fumbling or falling down stairs artifacts speak when applied engraving "x" is not literacy demons and vampires engrave in blood shopkeepers don't like riding customers can #chat down to steed own race in Gnomish Mines replaced with random monsters differentiate between light/gaze-induced blindness and other causes of blindness yellow dragon scale mail provides acid resistance polymorphed player digests engulf victims more slowly if Slow_digestion Conflict now affects steed's desire to keep its rider undead turning of bones level player corpse causes ghost to reunite with the corpse control-x in regular mode displays name, role, race, gender, and your deities. wizard mode can wish for pools of lava pythons now have infravision to emulate real pythons heat sense organ M-2 added as a shortcut for #twoweapon general file location mechanism you can choose to #loot the saddle from something now message changes for silver dragon scale mail glowing silver and pit vipers falling into pits support explicit `race=random', `alignment=random', and `gender=random' in startup options manes now grow up into lemures potions of healing and sickness affect Pestilence in the opposite way to their effect on other monsters introduction of a new method of warning where you sense the danger level of monsters on the level by displaying it at the monster's location introduction of a new method of warning for specific monsters the way Sting does for Orcs; you sense their presence anywhere on the current level artifacts can belong to specific races and won't be given as gift when "hated" Archeologists get a penalty for breaking "historic" statues hatching eggs in male player's inventory have chance of "Daddy?" steeds affected by more types of wands zapped down opening/knock versus steed drops saddle unwearing your steed's saddle (e.g. stolen, opening) causes dismount yet another funny message when whipping a horse corpse yet another funny message when mounting when hallucinating Bell, Book, and Candelabrum added to final score like artifacts new keywords coaligned and noncoaligned for altars (and monsters/priests) in special level descriptions quest start levels get coaligned altars if their roles have multiple alignments, and goal levels get noncoaligned altars ice vortices and freezing spheres are infravisible Platform- and/or Interface-Specific New Features ------------------------------------------------ X11, tty, Amiga: offer for player selection only choices consistent with those already made by config file/command line (e.g., only offer roles that are compatible with specified race) tty: eight_bit_tty option Amiga: implement menu_* accelerators and counting mac: the "record" file is created if it does not exist nethack-3.4.3/doc/fixes34.00100644000000000000000000010642407764735041013774 0ustar rootrootGeneral Fixes and Modified Features ----------------------------------- prevent an extraneous selection prompt when a role with only a single possible gender, race, or align is specified be consistent with the use of twice and thrice in end of game reports use "kill" vs "destroy" more consistently looting bag of tricks on the floor doesn't then prompt for direction suppress "the" in "you kill the poor Fido" iron bars added to the Dark One's prison shouldn't be able to #loot without hands level compiler can specify cockatrice nests, leprechaun halls, antholes fix level compiler to allow specifying golems via '\'' in MONSTER directives fix bug where excalibur blasted lawful non-Knights unification of the strings "he"/"him"/"his" conflict caused vanishing vault guards to be killed with player getting credit/blame (also dmonsfree warning for double removal from map) monsters' conflict resistance check was unintentionally being affected by character's experience level stone-to-flesh was accessing freed memory, passing bad map coordinates to newsym that might be harmless but could trigger a crash prevent spurious "placing steed on map?" impossibles during save/restore prevent real "placing steed on map?" impossibility [sic] when creating bones dropping secondary or quivered weapon to lighten load in order to crawl out of water left the item flagged as still worn if #adjust combined two or more of main weapon, alternate weapon, and quiver the resulting stack would be flagged as worn in multiple slots and eventually trigger "Setworn: mask = ##." impossibility remove curse operated on secondary weapon even though it wasn't wielded update conduct immediately when eating corpses (character killed by eating poisonous corpse as first meal was described as "strict vegan") fix problem with amulets of change when polymorphed into succubus/incubus YAFM for pit fiends/pit vipers and pits should require seeing the monster woodchucks, cockatrices, and vampire bats should eat specifying a non-numeric value for amount when donating to temple priest or bribing demon prince produced random result mastodons can tear through webs praying on wrong deity's altar cursed holy water but ignored uncursed water polymorphed player's gaze now works properly as a pyrolisk fix "You drop the Wizard of Yendor's corpse into Wizard of Yendor's interior." make sure status line gets updated when turning-into-slime state changes when eating green slime, don't reset slime countdown if already infected stop current activity when you noticed you're turning into slime message given when displacing an unnamed pet into a polymorph trapped referred to it by its new monster type rather than by what you displaced player killed by ghoul turns into one in the bones file slings are not made of wood for post-amnesia deja vu messages, use "seems" rather than "looks" when blind avoid encumberance messages during startup attribute adjusting even a wumpus cannot escape the pits in Sokoban when a steed dies in a shop, don't charge for the saddle shopkeeper did not charge for use of an unpaid camera shopkeeper did not charge for items burned by breaking a wand of fire shopkeeper should charge when you transmute a potion shk notices if you use a grappling hook to remove an item from the shop adjust robbed shopkeeper's feedback when he or she plunders hero's corpse avoid giving away which monsters are saddled while hallucinating when polymorphed into a herbivorous monster, you should prefer vegan "corpses" when polymorphed into a hider, stop hiding after picking up the last object at a location throwing a wielded, returning weapon should not disable twoweapon mode monster should not wield cockatrice corpse without gloves on sharks have thick skin better message when killed by drinking a potion of sickness from a sink telepathically detected monsters will be described by name if they try to attack praying character taking cockatrice from or putting it into a container should stone you if you are unprotected don't fall into pits (or other traps) twice when dismounting fix two weapon combat bonus/penalty to avoid "weapon_hit_bonus: bad skill 2" unicorns were at a disadvantage on a noteleport level missing a cockatrice when polymorphed into a weapon-using monster but fighting hand-to-hand would stone the player eliminate ghoul creation abuse when engraving on a headstone loss of levitation due to a sink will result in touching a wielded cockatrice corpse, just like falling down stairs while burdened falling into a sink when constitution is greater than 20 won't raise hit points stinking cloud should not affect migrating monsters, causes dmonsfree error only display message about monster using a weapon against another monster if you can see the monster don't count artifact amulets (wizard's quest artifact) twice in final score prevent pets from picking up Rider corpses when polymorphed into a centaur, don't keep kicking monsters after they die when throwing at a monster that you see with infravision, don't say "it" avoid "the arrow misses the mimic" which left the mimic concealed #sit while water walking over a submerged object should sit on the water's surface rather than on that unreachable object suppress extra "the" when printing the names of certain mplayers do not try to engulf green slimes (same as for cockatrices) trying to eat the brains of a green slime is now properly handled for players monsters touching cockatrices check boots for feet and nothing for tentacles if being petrified, don't disable messages from further petrify attacks trap detection would generally not find trapped doors avoid spurious done eating message after choking and vomiting attribute distribution for several player types did not add up monsters shouldn't try to eat green slime as a cure for stoning lighting of arboreal levels should not be stopped by trees need to recalculate visible locations immediately when monster blinds player monsters shouldn't see through walls because player wears Eyes of the Overworld when pricing glass the same as valuable gems, be sure to use gems of same color nymph stealing armor from a fainted player should wake the player ensure status line updates when you stop running when time is shown repairing a trap in a shop doorway must replace the broken door or wall as well sleeping steed cannot climb stairs/ladders can't change levels when mounted on a steed which is carrying the Amulet more artifacts granted by a deity are rustproof monster name feedback when using the m movement prefix allowed player to distinguish between peaceful and hostile monsters while hallucinating scrolls should not fade when hitting rust monsters, only from rust traps blank scrolls should not fade even from rust traps can't eat or #offer food off the floor under circumstances other than encumbrance where you couldn't have picked it up off the floor first ensure correct message after passive freeze attack by gelatinous cube avoid buffer overwrite when several weapons slip from your hands at once prevent portal placement on Ranger quest from stranding player in left margin avoid crash when a trouble gets fixed before you finish praying sensed hidden monsters should fight back when attacked mindless monsters won't be grateful after unsuccessful #untrap attempts turning affects your religious conduct, even if your god does not help you rolling boulder trap's boulder will knock another one that it collides with into motion in its place make it harder to abuse detect monster and confusion spells prevent D[a from producing odd message sequence in (c)ombination mode avoid messages like "the silver bell" after being drained by mind flayer after polymorph, actually drop both weapons when a message says this happened curb unicorn horn creation abuse by limiting the chance of a unicorn leaving one if it has been revived accept -p and -r options with nethack -s, as documented avoid printing "spellbook of" Book of the Dead in list of discoveries eating non-food items made of leather or other animal parts now violates vegan/vegetarian conduct use correct skill when throwing something while in twoweapon mode secondary weapon can rust when hitting a rustmonster in twoweapon mode extra healing spell cures monster's blindness add missing quest message for throwing the quest artifact to the Monk leader pits, arrow and dart traps, webs, polymorph traps and sleeping gas traps can affect the steed allow game restoration while polymorphed and your race is genocided ensure that crysknives revert to worm teeth, even in containers do not print gas spore's name if you cannot see a gas spore explosion cursed two-handed weapons now keep you from changing body armor trapped pets cannot follow you to another level no corpse when unchanging hero dies while polymorphed into a G_NOCORPSE monster A-removing armour under cursed stuff no longer fails silently grease protects gloves from contact poison on books items picked up from an abandoned shop sometimes wouldn't merge with other compatible items in inventory ("no charge" bit wasn't being cleared) prevent cut-off death message by increasing DTHSZ check to not control teleports when unconscious should now work properly if armor the hero is donning is stolen or seduced off, attributes can be left permanently mis-adjusted ensure a message is printed in all non-obvious cases where a monster flees a fleeing monster that is holding you always results in a "get released" message ensure a monster flees for at least one "turn" explosion type can now be one of dark, noxious, muddy, wet, magical, fiery, or frosty flying (jumping or throwing recoil) over some traps (magic portals, fire traps) will now trigger the trap displacement does not work through walls you can't trip and fall or trip over rocks while riding reduce the chances of a monkey successfully stealing armor you are wearing monkeys can't steal cursed items that you're unable to remove or attached iron ball or items too heavy for them to carry trapped doors are not always detected after returning to a previous level trap detection sometimes showed non-trap locations to be traps eucalyptus was never chosen in random tree fruits due to an off-by-one bug allow knights to pursue and attack thieving monkeys without alignment penalty gaining levitation while over on sink causes an immediate fall quest leader should avoid leaving the quest start level voluntarily blind Medusa cannot gaze prevent dipping attached iron ball or embedded dragon scales into a potion of polymorph from confusing the game about what items are in use should not be able to cut down trees on Ranger quest start level arrow traps are not currently intended to shoot poisoned arrows fall off the horse if you mimic a pile of gold while riding martial attacks will not remove monsters from traps and will cause monsters to set off traps they land on while reeling/staggering prevent topten from using alloc after alloc failure Nazgul and erinyes are nopoly to ensure their numbers are never exceeded "player-@" randomly selects a race and "player -@" randomly selects everything that is not specified prevent spurious "quest portal already gone" when you use an artifact to return to the quest after being previously expelled prevent limbless shopkeepers from "leaping" and "grabbing" your backpack by changing the messages that you get prevent panic when riding while punished and falling down the stairs armor class shouldn't wrap from very negative to very positive searching should only credit you with finding an undetected monster if you couldn't sense it or spot it already monsters should not generally lose invisibility when polymorphing monster must have eyes or breathe to be affected by potion vapors stop dungeon file open failure from causing vision-related crash wishing for {statue,figurine,corpse} of long worm tail yields long worm instead chatting to an arbitrary shopkeeper (not a petrified one) who was created via statue animation produced strange results Yeenoghu's confusion attack is not a touch of death an eating steed should not be able to go up or down stairs, etc. you don't feel "great" when recovering with a unicorn horn but Slimed; also, make the same check for potions that make you feel "great" avoid panic during player-as-demon demon summoning when no demon is available change "Ouch! You bump into a door" message when riding prevent voluntary dismount of steed from passing you through walls in tight spots prevent throwing boulders, boxes, and chests and medium-to-large corpses and statues through iron bars only living eggs which touch cockatrices get turned to stone since monsters already refuse to zap empty wands, they shouldn't pick them up after praying, try to give a spellbook for which the player is not restricted after #dipping your weapon in hand or quiver into a potion of polymorph, leave it where it was message from rust trap states "robe" instead of "cloak" when applicable gas spore explosions were affecting your human hitpoints even if you were polyd and consequently you did not rehumanize prevent "You attack empty water" when attacking a spot on land while underwater prevent spurious "But you aren't drowning. You touch bottom." message when removing an amulet of magical breathing as an amphibious creature fix message given when a monster tries to disarm your multiple welded daggers with a bullwhip camera flash no longer stops at invisible monster monsters inside a stinking cloud should be blinded, just like the hero is vault guard shouldn't initiate conversation with you when you're hidden adult wolves are not small but lynxes are small turn off vision during a save operation to prevent impossible() from triggering a crash rolling boulder trap's boulder susceptible to land mines and teleport traps polymorphing below level 1 should kill player (needed to fix max-HP abuse) prevent "obj not free" panic when shopkeeper cannot get to a thrown pick-axe give feedback if Sokoban prevents polymorphed player from passing through walls eliminate Wounded_legs enlightenment message when riding since it refers to the steed's legs, not the hero's adjust the fumbling pick-axe message to reflect that the steed's legs got damaged, not the hero's quaffing a noncursed potion of speed no longer heals the steed's wounded legs prevent mounting of steed when you have Wounded_legs to prevent abuse; dismount does an unconditional healing of Wounded_legs during the Wounded_legs context switch wounded legs on a steed doesn't count as a prayer trouble wounded legs on a steed doesn't abuse dexterity make wounded legs gained by falling off a steed consistent (dexterity loss) land mines while mounted should hurt the steed self-genocide while sitting on a throne should not refer to scroll of genocide eating dogfood or fixing a squeaky board conveys experience but didn't check for gaining a new level demon bribes are 4x larger than they should be for co-aligned players specific monster warning no longer reveals the true monster name when you use the '/' command while hallucinating start_corpse_timeout() now takes corpse age into consideration rather than always assuming a fresh corpse, thus fixing potential icebox abuse player on an immediate diagonal from a monster reading a scroll of earth should be affected, just like monsters in similar locations objects that fall from monster's minvent as a result of monster polymorph are not polymorphed, consistent with items that remain in minvent quaffing a potion of gain ability while wearing ring of sustain ability displayed no message and identified the potion monsters still with WAITFORU strategy should not follow up/downstairs messages should reflect the fact that the Eyes of the Overworld mask the effects of blindness Amulet of life saving should save you from sickness that will kick in this turn player should stop waiting when a monster uses a polearm from a distance avoid stone-to-flesh blood pooling message when zapping ice and not stone when polymorphed into a silent creature, do not "pronounce" scroll formula ensure hilite turns off immediately when pet stops being tame hitting with a polearm counts as hitting with a weapon for conduct traps detected while blind and levitating were not displayed when a mind flayer uses its mind attack, it should wake the victim shapechangers restored from disk would no longer change shape allow "tame" prefix when using the wizmode C-g command to create new monster(s) display a more appropriate name for a high priestess when using ;/ commands change "The water elemental is on fire" to "The water elemental is boiling" blind, cancelled or nonseen invisible Medusa cannot gaze at other monsters fix impossible when spinning web on falling rock, rolling boulder and fire traps rust monsters can only eat items made of rustable material wands of fire are no longer flammable no matter what material they are displacing you pet into a trap which kills it affects killer conduct pets can now be displaced in untended shops only show lit walls if, like doors, the position next to them is lit too charge for an unpaid weapon used for engraving shopkeeper should charge for unpaid balls and used candles in containers when swallowed you could drop or throw a cockatrice corpse into a monster's stomach without stoning it despite the guaranteed hit steed would often not respond to an attack, even if you didn't move that turn after stepping in a polymorph trap, a monster may pick up the wrong items breaking an unpaid wand of teleportation wouldn't result in the proper charge next_shkp() was used inconsistently, potentially triggering an endless loop chaotic wizards usually get a spellbook when crowned, just like neutral ones monk quest: fix the two inaccessible chambers on the locate level rogue quest: fix the four inaccessible chambers on the home level; link the two inaccessible chambers on the locate level and provide a means of escaping from them; on the goal level, link most chambers together, resulting in just four disconnected regions, and force stairs to be in a different region from the nemesis angels can fly under #twoweapon fix it so that only Stormbringer carries out the blood-thirsty attacks, not both booby-trapped doors shouldn't make you stagger if you're riding encumbrance exertion checks should happen each time player moves mksobj_at: add way to suppress the chance of a new object being an artifact steed should be the one caught in a bear trap, even if player is polymorphed use a more appropriate message than "being held" when using < or > while swallowed or engulfed on stairs stinking cloud isn't useless and shouldn't be excluded from initial inventory shopkeeper will not try to buy food you are eating when inventory is full don't duplicate any gold inside containers when saving bones data can't tell between acid and holy/unholy water that burns like acid tame stuck monsters should release you after regaining their senses engraving Elbereth exercises wisdom, engraving anything else does not artifact bows get any special attack bonus added to missile to-hit roll monsters with gaze attacks should not try to blind the hero with potions players polymorphed into umber hulks should not try to eat boulders in Sokoban when a monster uses up a partially eaten food item, cleanup was not performed temple priests shouldn't be created with two robes give some quest leaders and nemeses equipment appropriate for their class mis-engraving "X" or "x" shouldn't violate illiterate conduct Heart of Ahriman now explicitly does double damage prevent NO_ATTK artifacts from accidentally doing double damage player polymorphed into monster that loses hp out of water should lose hp too make sure that all leashed monsters get released when bones data is saved eating a ring of levitation doesn't confer permanent intrinsic levitation silver hating monster using a bullwhip shouldn't snatch silver weapons into its inventory fracturing one of several boulders at a location should not unblock vision don't hide stairs, thrones, &c under spider webs when creating levels rediscovering forgotten object types behaved differently depending upon whether they had user assigned names at the time of amnesia taming while engulfed is limited to the engulfer restore blindness resistance to Archons if a shk is polymorphed into monster form which has Wizard-style tactics, don't let him teleport to the stairs if he's inside his shop when the player digs a hole through a shop's floor, don't let shopkeeper wander out of that shop while multi-turn digging is in progress don't protect alternate weapon and quivered objects against being taken by shk who grabs your pack when you dig a hole through his shop floor add missing break to POT_WATER case in potionbreath() keep monster from forgetting its weapon is cursed every other round multiple shot throwing stops immediately whenever you hurtle backwards don't panic if being billed for a burning or other timed object food that makes a monster peaceful should not re-anger it at the same time abusing a leashed pet could result in a leashed peaceful monster couldn't unleash steed while mounted trying and failing to wield an item could leave current weapon flagged as both "weapon in hand" and "alternate weapon" when `pushweapon' option is set handle OBJ_CONTAINED case for corpse revival so that trolls can revive from inside containers eating one of several merged partly eaten food items should take nutrition from only one of them coyote names should not disable printing of "tame" or "peaceful" Eyes of the Overworld protect from stun effect of Archon's radiance attack give feedback when putting on or taking off the Eyes of the Overworld causes blindness state to be toggled avoid spurious "you can see again" when temporary blindness being overridden by the Eyes of the Overworld times out removing blindfold or lenses via 'A(' gives same results as via 'R' make blindness with just 1 turn remaining be a candicate for repair by unicorn horn and healing potions/spells healing potions/spells shouldn't fix being creamed make pie throwing and venom spitting by the player be consistent with the effects of those attacks by monsters offering & tinning corpses on altars should work even while riding It was possible to faint after eating a fortune cookie and still read the fortune's text despite being unconscious when filling a pit containing a vortex, a surviving vortex gets untrapped teleporting no longer moves the iron ball to under you if that's not necessary; prevents odd ball movement when crawling out of water monsters now prefer to wear speed boots over other boots prevent crash when loading a special level specifying a mimic using m_object prevent crashes caused by dropping or shipping quivered or secondary weapons don't trigger spurious encumbrance messages on last turn of a multi-turn meal prevent food being restored to untouched status if interrupted while eating troll revival shouldn't increment the troll creation counter breaking mirrors and your eggs should be bad luck when kicking chests as well as throwing vampires should be G_NOCORPSE so you can't wish for them glass objects should break when thrown, just like when kicked in chests rocks/gems shouldn't be hard to throw by hand because they are ammo avoid all cases where splitting an object would result in two objects being quivered, wielded or otherwise having its owornflag set allow 'a' prompt when dropping many objects in shop for credit (Wingnut) monsters who get polymorphed while wearing dragon armor turn into dragons shape changers can't be killed by system shock when hit by polymorph Chromatic Dragon has silver scales too (she reflects) being killed when wishing for an artifact should retain that item in bones data the drain life spell should not wipe out engravings (especially not using a function that requires you to be able to reach the floor) monsters who can cast undirected spells don't need to be in combat with you to do so messages consistent for all monster spells monsters casting spells at your displaced image now set mspec_used monsters without ranged spells don't print curse messages for ranged spells going down to floor using > should set Heart of Ahriman invocation timeout riding a steed into water kills the steed if it cannot swim, with penalties gaze attacks now stop occupation proper death message when killed by "plain" high priest don't conceal the identity of Moloch's high priest blessed full healing can't recover levels lost when polymorphing into new man blessed full healing can recover at most half of other lost levels golden glow when praying will recover lost level if blessed full healing could gaining a level while polymorphed increases current monst hit points as well as latent human (or whatever) hit points pets should not try to go after food that they can't reach monsters shouldn't use wands of digging in Sokoban objects dropped in or travelling across lava pools can take damage monsters that enter lava can take damage eating an unpaid tin should calculate cost before not after eating spells shouldn't do negative damage when reading spellbooks, don't "continue studying" wrong book if original one gets destroyed after previous reading attempt has been interrupted correctly handle polymorphed quest leader swallowing zombies/mummies whole makes you sick, like when eating them normally impose additional teleport restrictions on the no-teleport Plane of Air landmines set off by pushed boulders have same effects as stepping on them secret corridor detected out of vision range is still displayed (prevents bug where wand of secret door detection found nothing but still identified) getobj can now see user-specified count when using inventory to make selection scalpel is stainless steel (i.e. METAL) not regular steel (IRON) eggs, potions & other breakables may break when they fall down stairs hurtling via grappling hook does not apply effects of destination location consider vortexes to be nonliving dragons have scales, not fur if player teleports a monster while swallowed on a noteleport level, the player should not teleport along with the monster prefixes that can appear in any order when wishing should include +/- and empty don't allow untrapping of adjacent traps in locations you can't move to summoning should summon any alignment if summoner's base alignment is A_NONE when dipping unicorn horn in potion, the potion might change bless status, so set bknown to FALSE grammar fixes such as "Eyes of the Overworld resists" and others score bonus was missing from scrolls of identify and fire make wands of speed or slow monster known if their effect on monsters is observed; likewise for speed boots gold detection "materially poor" message inappropriate if you have hidden_gold() cannot reflect back an invisible umber hulk or medusa's attack monsters with M3_WANTSBOOK often couldn't move in the Wizard-level Vlad should want the Candelabrum if you float_down on a trap in which you're already trapped, don't retrap applying whip toward hidden mimic displays mimic name before "Wait!" message stealing a container didn't multiply cost of stolen contained objects by quan halve air elemental damage to compensate for side effect of speed system strengthen Death; weaken Famine, Pestilence, and Demogorgon pet purple worms get nutrition from engulfing attack throwing an artifact upwards will trigger artifact hit effects when it falls being hit by Fire Brand stops the turning-into-slime process monsters hitting other monsters can split puddings with weapons be consistent with checking for iron weapons when splitting puddings prevent corpses of undead creatures just killed by undead turning from being instantly revived by the same undead turning attack allow fake player monsters to handle artifacts that don't match alignment/role chaotic monsters can use Stormbringer; lawful monsters can use Excalibur No "corridor disappears" message if Vault guard dies off-level slip while mounting and levitating at will should not cause damage if you see a monster jump into a trap in a secret corridor, it's not secret fixed a few places where unblock_point wasn't called but should have been cloned monsters should have the same name and tameness as the original you should stop eating (etc.) if a monster attacks you and misses half physical damage should apply to gas spores iron bars should affect wall corner wallification potion of polymorph shouldn't be identified if object being dipped into it ends up as the same type of object after polymorphing don't slap against the floor while riding and eating bad food got rid of "nori" (since it doesn't really translate "kelp frond" accurately) engraving in fog-covered location on in the Wizard quest said you engraved in air, not dust dipping non-weapons into burning potions of oil had no effect dipping arrows into burning potions resulted in rust damage Platform- and/or Interface-Specific Fixes ----------------------------------------- amiga: random crashes when opening menu window in fontmode eliminated amiga: proper action taken (cancel) when closing the menu window with closegadget or escape amiga: allow #/altmeta combination on foreign keymaps amiga: prevent plname[] overflow from askname() amiga: prevent writing outside basewindow (bottom) amiga: tilemode tombstone corrected on cybergfx screen amiga: don't clutter levels/ with foo.0 when quitting at playerselection micro: prevent a guaranteed impossible() if we ever have more than (COLNO - 1) levels in the game micro: fix out of bounds memory modification for file opens via PATH msdos: placeholder tiles accepted by the thin tile builder tiles: use pixel-accurate grid bug tile for grid bugs tty: correctly dismiss 1-line menus tty: clear screen before version incompatibility message so it doesn't just print the message overwriting previous screen text tty: pet was not always hilited tty: don't crash if the news file is present but empty unix/tty: give user a chance to see any error produced by (de)compression win32/tty: menus can take advantage of consoles larger than 80x25 win32/tty: add support for inverse attribute Gnome: workaround for GTK+ attempts to disallow setgid executables Qt: honor user preferences in startup dialog X11: map not displayed in color when using X11 windowtype w/o tiles X11: viewport scrolling could scroll the the wrong place with resized window X11: allow extra space added to map widget to be removed if widget shrinks X11: general solution to the problem that the meaning of font height varies among different implementations of X11 X11: make "slow" mode the default since it seems to be very prevalent General New Features -------------------- added travel command via '_' or mouse click config file processing detects multiple use of the same OPTION and prints a warning when it does make the player selection prompt more explicit in the information that it is going to request remove curse now operates on cursed leashes that are in active use give feedback when shooting/throwing more than one missile at a time monsters can now deliberately eat dead lizards to cure confusion general warning now allows you to attack unseen monsters, as long as you can see the warning glyph on the screen wand of fire & fireballs now burn webs wand of locking / wizard lock zapped down will close and remove trap doors exploding monsters wake nearby monsters various mindless, sphere monsters no longer need to breath sleeping gas no longer affects nonbreathing monsters vault guard doesn't notice you if you're mimicking gold good chance of untrapping monsters and pets caught in webs if you are polymorphed into a spider, and extremely small chance even if not stamina affects ability to throw heavy things objects merge in containers wishing for "nothing" yields no object and preserves wishless conduct genociding "none" destroys no monsters and preserves genocideless conduct coyote id naming shows only the true latin name if coyote is cancelled xorns can "speak" and can smell valuable metal if you find a trap but there is too much clutter to see it, have the game display it temporarily until a keypress rename the Wizard of Balance to Neferet the Green double the number of messages that apprentices/guards utter, with 5 for before the quest, and 5 after wizard mode ^G command can create monster by class, not just by name wizard mode ^G command takes a count kicking a sleeping/paralyzed steed now causes special effects allow overriding of the default boulder symbol via BOULDER option blessed scroll of detect food provides you with a one time ability to recognize food that may be harmful to you wizard mode WIZKIT config file option added to ease adding items to starting inventory for a debug session helping a sleeping/frozen monster from a trap might wake/unfreeze monster if the hero comes upon an obviously trapped monster the trap is considered seen thrown weapons that hit are now subject to passive damage locomotion-specific use of words, rather than just using "stagger" if you come upon a physically trapped, visible monster, you see the trap too, without searching for it allow looking and pickup inside monster's stomach or interior when swallowed add body_part(STOMACH) pets like tame nymphs, et al, now only steal non-cursed items monks usually get a spellbook rather than a weapon when crowned blessed gold detection now detects anything made of gold, not just coins, including candelabrum and gold rings new T-shirt messages from Scott Bigham option to get rid of resistance 'sparkle' (shieldeffect) (Scott Bigham) option for autodig (Malcolm Ryan) glowing Sunsword (inspired by Slashem) msg_window option for ^P in TTY mode (Jay Tilton) ninjas should get multishot bonus with yumi and ya (Dylan O'Donnell) put prisoners in the Dark One's dungeon (Dylan O'Donnell) touchstones; Archeologists start with one add leather cloak so soldiers don't have elven cloaks add Tom Friedetzky's BUC-patch with some alterations to the original add wizard #poly and #levelchange (originally levelgain; Dylan O'Donnell), add Jason Short's additional lenses use patch add new Gnomish Mines levels from Kelly Bailey's patch add Ken Arnold's patch to show unpaid item prices in inventory jousting by players wielding a lance while riding Knights start with lance rather than spear can start game without a pet via pettype:none (Dylan O'Donnell) allow disclose options to be more finally tuned, including being able to specify the default response for being prompted debug mode SPLEVTYPE environment variable to choose specific levels from when there are random selections artifacts have individual prices new window-port preference options added, and some existing options moved into the window-port preferences section made each of the end disclosure options customizable to "prompt;default no", "prompt;default yes", "show it without prompt", and "don't show it and don't prompt" add female role level names "Medica ossium", "Magistra", "Chevaliere", "Dame" more feedback about skill advancement from #enhance command USER_SOUNDS compilation option to enable use of SOUND and SOUNDDIR variables in the config file for user-specified sound clips for user-specified, regex-based message patterns resistance does not protect inventory from artifacts (cold vs Frost Brand,&c) phrase the prompts for P and R commands using "put on" and "remove" as the actions rather than repeating W and T commands' "wear" and "take off" dipping candles, et al, into burning potions lights them Platform- and/or Interface-Specific New Features ------------------------------------------------ amiga: screenmode requester amiga: 16 color font mode mac: command-key shortcuts in the player selection dialog vms: default compiler configuration in sys/vms/Makefile.* switched to DEC C win32: new graphical port contribution by Alex Kompel nethack-3.4.3/doc/fixes34.10100644000000000000000000007104507764735041013775 0ustar rootroot$RCSfile: fixes34.1,v $ $Revision: 1.331 $ $Date: 2003/02/20 00:19:46 $ General Fixes and Modified Features ----------------------------------- prevent panic() obj_not_free when pushing a boulder over a landmine there was no feedback when successfully hitting shock resistant monsters with Mjollnir via hand-to-hand attack unbought single-bite food eaten in shops was not billed properly charge for shop contents inside "no charge" containers add wishing for "nothing" and genociding "none" to the conduct section of the Guidebook allow both wishing and genocide to accept either "none" or "nothing" when the player wants to decline left word in format string in get_wet() causing "The spellbook fadefades" two bad wizkit items in a row shouldn't make the user hit space many times kicking thrones no longer loosens rocks wall symbol not replaced when digging while blind and levitating increment FQN_NUMBUF from 2 to 3 to prevent premature reuse of a buffer that caused a level creation error to be reported as a lock file error print regular death message when leashed, mounted steed dies of starvation fix more funny messages, new and old restore the behavior of bumping into closed doors when moving while impaired fix iron ball cases that could put the chain in solid rock discovering a mimic on a closed door location should not unblock the location don't drop corpse when a monster kills another monster on an inaccessible location (i.e. behave like xkilled behaves) half-physical-damage from gas spore explosion should only affect you Sunsword didn't stop glowing when hero killed a monster wielding it mimics caught in explosions with messages printed about them are discovered let lev_comp and dgn_comp accept optional carriage return character prior to the terminating newline in special level and dungeon description files Wizard of Yendor will start harassing you after the invocation if you've managed to get that far without ever killing him characters polymorphed into centaurs can't wear boots if an unknown rolling boulder trap kills a monster, you shouldn't be a murderer touchstone entry in data.base specific message for engraving headstone with wand of digging wielded/quivered chained ball should be unwielded when thrown polymorphing into a form that cannot twoweapon should immediately disable twoweapon mode; likewise when reverting from a monster form which can use two weapons to a normal form which can't taking partial count of merged objects from a container while your pack was full split the object and did not re-merge animal_parts are not always appropriate for ravens prevent panic if tombstone window cannot be created clarify travel command behavior in the Guidebook touch_artifact checks needed when snagging w/bullwhip and stealing cannot trip over submerged objects if you're water walking wand of striking was not identified if it activated a statue trap cannot sacrifice while you're swallowed player polymorphed into an eel cannot drown breathless/amphibious monsters avoid dmonsfree impossible message due to migrating a dead monster via mhurtle causing the monster to end up in a hole or other trap avoid temporary disappearing Burdened message due to updating status line midway thru in_container don't credit player's wisdom when makelevel creates random Elbereth engravings reduce insect/monster creation from monster spells and limit chain summons avoid "couldn't place lregion type 5" warning when arriving at Plane of Fire avoid crash due to delayed poly or were change no longer being valid ensure that Priest's ability to recognize B/U/C is considered in B/U/C menus can't push boulders through iron bars; traps can't roll such through either; likewise for objects thrown by monsters thrown objects susceptible to breaking might do so when they hit iron bars assorted monsters can pass through iron bars; ditto for polymorphed character attempting to dig iron bars will wake nearby monsters instead of yielding "you swing your pick-axe through thin air" autodig won't accept iron bars as candidate location allow knight to retaliate for all thefts except those "you gladly hand over..." randomize starting position on goal level for M, P, and S quests prevent the Wizard of Yendor from displacing the high priest of Moloch out of the Sanctum's temple ATR_BOLD on spell menu header travel command should restrict its shortest paths to areas of the map the hero knows about or might reasonably guess non-altar prayer should limit god action, not maximize it potions of acid explode, not dilute, so make water_damage behave this way lookat monster notes if you see monster is trapped don't crash when angry shopkeeper re-enters the shop and you pick up something monsters with WAITFORU strategy should act if successfully attacked by non-damaging attacks (e.g. seduction, rust damage) don't summon kops if credit covers cost of unpaid goods taken out of shop update swallowed display immediately if an engulfing monster polymorphs into another engulfing monster undo xname FAKE_AMULET_OF_YENDOR AD_DRIN check, the_unique_obj checks this case axes should chop trees; picks shouldn't chance to aim grappling hook when skilled or better level limit of monsters like naga hatchlings should be high enough to grow up scroll of enchant weapon will become discovered when read in some cases don't crash when using lookat on a boulder an BOULDER sym is unique attaching a single candle to fill candelabrum's last slot gave message with poor grammar: "The candelabrum now has seven candle attached." vault guards won't ask who you are if you're unconscious or paralyzed monsters should not repeatedly try to teleport on noteleport levels crocodiles legs are not designed for kicking open doors, chests, et al. walls of one of the luckstone locations in minend-3 were diggable minetn-6 could place downstairs in a cut-off location corpses in bones files don't retain their role characteristic boulder was not displayed if blind and discovered with a monster known via ESP behind it don't claim that statue comes to life if the monster it turns into is invisible fix goodpos() so worm segments don't get placed on top of each other (causing a possible display problem if the worm is cut in two) fix fountain noises on some special levels (castle, valk home, various mines) disallow mounting a trapped steed to avoid inappropriate trap effects #chat with meditating monster will rouse it suppress redundant message when stoning effect transforms a golem clear worn bits of any object grabbed by shopkeeper to avoid extract_nobj panic looting any container on a location should suppress looting nearby monsters give more specific message when forbidden role attempts to use twoweapon mode avoid double billing if #loot causes a shop's bag of holding to explode when polymorphed, player killing a paper or straw golem via fire damage would kill the golem twice, resulting in an impossible error usually stop mimicing if you polymorph while using #monster mimic capability under !GOLDOBJ, gold shouldn't disappear if you try to throw it at yourself under !GOLDOBJ, remove temp gold from inventory during restore Staff of Aesculapius did not always cure sliming correct singularization of fungi, liches, vortices prevent "remove_object: obj not on floor" panic for iron ball placement if riding while punished leads to a fall off steed when changing levels specifying -D (or -X) to enter explore mode while restarting from a save file was lost in the restore process fix crash when using lookat on an known invisible monster with monster syms set prevent getting stuck in infinite loop when using wizard mode #levelchange command to reduce level while having level-drain resistance naming an already wielded elven dagger "Sting" activates warning against orcs naming either of the wielded weapons unintentionally ends two-weapon combat Various nemesis monsters must resist stoning so their death messages make sense don't call DEBUG impossible in rn2 when a level 0 monster tries to cast a spell GOLDOBJ: don't call money2mon with 0 zero when killed by shopkeeper headstone writing was using the adjective "weird" when engraving with a wand of digging. don't report "you were riding" if you die as a result of dismounting allow #untrapping of chests that are co-located with floor traps and hero unmap "I" symbols when searching while blind and levitating monsters that are frozen or sleeping cannot be grateful for untrapping grammar of blessed-detection eating warning messages when eating 1 of N objects message for charging for items lost in a cursed magic bag wasn't always shown dropping gold on an altar printed no message and didn't change gnostic conduct don't allow cursed daggers thrown by monsters to go thru closed doors hero polymorphed into an exploding monster should explode when attacking thin air, just like the monster itself don't mark holes/trapdoors as seen if you levitate over them while blind player polymorphed as rust monster would lose gold in inventory by attempting to eat it, even though the eat failed no messages were printed when dowaterdemon or dowaternymph failed to create a monster doe to the G_GONE check knights should be able to avenge attacks from covetous monsters eating various rotten food items would not break vegan/vegetarian conduct unaligned special levels should inherit alignment from the dungeon Samurai quest was missing several doors Cancelled while polymorphed and Unchanging should provide feedback stone to flesh on a statue with contents would lose the contents if a monster was on the same location as the statue steed movement would use your speed if walking step by step kicking a known, unseen monster would sometimes leave behind an extra I symbol applying a lance against a long worm could cause an impossible a knight applying a lance did not do a caitiff check blessed gain level when already at level 30 won't reduce experience points keep counting spell skill exercise even after expert status is reached when a fountain dries up or a throne vanishes, make sure it really happens allow player to name polymorph potion if nothing seems to happen avoid crash when drinking a potion causes the hero to float up over a fire trap, for example, which might try to destroy the in-use potion in some situations, if hero stood still, a hostile dwarf would switch back and forth between weapon and pick-axe and never move uncontrolled teleports did not handle leashed pets minetown fountain warnings shouldn't prevent finding gems/coins in fountain order of container and objects was different for mazelike and roomfilled levels minetown guards only enforce town rules inside the town proper electric damage heals hero polymorphed into flesh golem rather than iron golem fix bug preventing wishing for bear traps (not beartrap objects) in debug mode be notified about cessation of hallucinations even if blind and the time when using '/' to examine multiple map items in succession, don't mislabel some with "or a splash of venom" after having looked at a '.' item martial arts kick that knocks a monster into a trap would result in warning "dmonsfree: 1 removed doesn't match 2 pending" if the trap was fatal if you can't see or sense a monster when it dies, don't set dknown on corpse effect of wearing or removing the Eyes of the Overworld took effect on the next move, but should take effect immediately. dragon scale mail is magic armor invoking or applying an artifact must pass a touch_artifact check document 'D'rop BUCX behavior in the Guidebook remove levitation boots over a portal, the portal teleport is delayed until your next command is typed. armor vs cursed two-handed weapon anomalies: with 'T', couldn't remove armor, but with 'A', could remove it, and with 'W', could put it on don't print ape data.base description for other words that end in "ape" prevent crash after animating a statue via stone_to_flesh by avoiding use of the obj in newsym() after it was deleted print "magic spreads" message when eating ring of increase damage, etc. grammar tid: "The looking glass miss the ." fix wishing for "looking glass" and " glass" Archeologists suffer same alignment penalty for statue destruction by stone_to_flesh as they do by other means of statue destruction being unable to see a vault guard doesn't prevent him from arriving in town, secret doors should be called "wall", not "fountain" in town, watch should not allow trees to be cut down cancel chat direction cancels the chat prevent "the mimic looks better" on an unrecognized mimic hit with healing spell after forcefighting a concealed lurker, the lurker wouldn't fight back when polymorphed into a hider, cease hiding during level changes let mind flayer grow up into master mind flayer; also giant/sewer rat and cave/large spider engulfing green slime as a purple worm was causing stoning not sliming zero entries in DUNGEON, MONSTERS, et al, of config file are now treated as preserving the default rather than being ignored enlightenment: don't misreport polymorphed lycanthrope as "in beast form" remove TIMED_DELAY from the features checked for version compatibility rolling boulder hitting monster stuck in pit should stop even when mon survives don't see chest trap gas colors while Blind adjust fruit name in potion juice messages if it has the form "foo of bar" wielded camera passes harmlessly through shade reading spellbooks while confused should allow tearing the book Breaking wand of digging dug through rock which should be undiggable. Breaking wand of digging near shop walls wouldn't anger the shopkeeper Shop walls wouldn't be restored if there were pits in the way. If there were a hole outside a shop, you could kick stuff out of the door into the hole without the shopkeeper noticing. curing hallucination while wielding Grayswandir should print a message removing unowned pick-axe from container in shop gave inappropriate message don't let monster end up with more current HP than max HP after life drain make sure that missing file trickery in wizard mode which is discovered during level change doesn't try to keep going after discarding current level contribution by Adam Wozniak adds several const & changes some char* to char[] fix impossible when hitting/jousting a monster causes it to be killed twice fix a GOLDOBJ crash/hang in take_gold() that could be triggered by reading a cursed spellbook, or by sitting on a throne kicking a tree could produce 0 to 4 killer bees but it should have been 1 to 5 mounting a steed allowed hero to make moves that would otherwise be disallowed including mounting diagonally in a shop doorway monsters lose intrinsic speed when pertrified if you have converted, the quest leader banishes you instead of asking you to come back later, and tells you that you won't succeed without Bell don't state that "you narrowly avoid losing all chance" message if you try to put on a helm of opposite alignment in the quest after converting fix enlightenment feedback for bonus or penalty on damage and chance to hit effects of purple worms consuming special monsters is now more consistent across eating, digesting and dropped corpses while engulfed avoid "you finish disrobing" when disarming via the 'A' command make sure corpses and statues which remember monster attributes don't keep ones that were conferred by no longer worn items (mainly speed boots) elevate the trouble priority of any cursed item which is preventing removal of a ring of levitation starving pets will eat more aggressively when a pet starves to death, say so instead of just "Fido dies." starved pet raised from dead shouldn't immediately starve again skilled spell of detected treasure wasn't acting like blessed potion of object detection (from Roderick Schertler) fix end of game attribute disclosure for levitation negated by sink kicking a box embedded in a wall will knock it free rather than bust it open stop running or travelling if the vibrating square message is triggered show correct gender in ^X display when polymorphed into non-humanoid form for wizard and explore modes, skip second screen of ^X output when first screen is cancelled by ESC for wizard mode, override confusion when using ^F to reveal map polyself into minotaur causes hard headgear to fall off with multiple leashes in use, 2nd had 50/50 chance of having unbounded length GOLDOBJ: coins aren't subject to curses/blesses and don't need identification can no longer activate a figurine while engulfed can't use figurines to get too many erinyes or Nazgul include currently wielded weapon among the list of likely choices for 'w' likewise for currently quivered ammo among choices for 'Q' only include unknown gems as likely choices when applying known touchstone prevent mbodypart() from returning animal parts for lights removing a ring might relearn what it is after amnesia sleeping shopkeeper shouldn't talk to digging player give more specific feedback when dipping unicorn horns into potions can see self via infravision or ESP or monster detection when invisible class genocide that killed polymorphed self while `Unchanging' reported incomplete cause of death and possibly left rest of class in bones class genocide of @ by human or elf character polymorphed into non-@ gave "you feel dead inside" message twice unskilled rider who can't reach items on floor also can't dip into moat or pool from flying steed when summoning nasty monsters, use new monster's type to decide if they can be placed on boulders, et al, not the summoning monster's type don't display the "intones:" prefix when !soundok since the message suffix won't be displayed in this case document "sound" option in Guidebook destroy traps that are buried by boulders dropped in water renamed debug commands: light sources -> lightsources, monpoly_control -> monpolycontrol, poly -> polyself detect attempt to swap places with big pet through narrow opening stinking clouds in bones files do not get their ttl set reasonably stinking clouds in bones files may incorrectly set player_inside breaking wand of digging on a drawbridge shouldn't dig/hole a pit in the bridge avoid mimicking gold when the character has the Unchanging attribute handle polearm wielded prior to mounting the same as one wielded while mounted, and one still used after dismounting like one wielded while not mounted non-lawful angels don't chat using lawful messages and shouldn't summon lawful help cancelled yellow lights should not explode against other monsters, as well as not exploding against you becoming confused, eg from nausia, while reading a spellbook should result in the usual confusion effects teleports should not be controlled if you're stunned, confusion should have some effect on your ability to control level teleports vault wall repair should remove traps subsequently created at affected spots don't reveal deity name when a high priest(ess) gives temple entry greeting for ordinary remove curse, don't uncurse quivered object unless it is suitable to be used as a quivered weapon (ammo or missile) salamanders have no legs and cannot ride all objects carried by a monster who's hit by a polymorph zap are protected from that zap, not just worn armor which falls off due to shape change sparkle option for display effects was ignored on explosions level teleport while on a sleeping steed caused panic and possible crash breaking wand of digging causing a shopkeeper to fall left unpaid items unpaid use get_adjacent_loc() rather than getdir() directly for some things where you want to ensure valid adjacent coordinates are returned minor experience calculation tweaks level telporting out of the dungeon while carrying unpaid shop goods would trigger "not on any bill" warnings during final inventory disclosure only hard helmets protect against falling piercers don't crash teleporting out of a monster while engulfed, punished but not carrying the ball web breaking should consider steed strength and other characteristics various missing or inappropriate "killed by" death messages second attack for two-weapon combat will miss if first knocks target away jousting effect no longer occurs every time riding character hits with lance skeletons should be able to wear the armor they're created with bouncing zaps should not bounce around the edge of closed doors mimics that are detected but not seen should not display as their mimiced form when the detection ends not all cavemen are human, so avoid using human in quest messages tengu is singular and plural, some rumors were incorrect don't let leader or nemesis be renamed non-moving monster are not affected by liquid 'A' command wouldn't remove cursed item from quiver or alternate weapon slot 'A' command behaved differently depending on menustyle when non-weapons were present in the quiver or alternate weapon inventory slots most cases of the hero dropping things need to check for dropping on an altar zapping undiggable trees with wand or spell of dig gave feedback about rock being able to see invisible shouldn't cause you to not notice when potion or spell of invisibility wears off can't successfully bribe a demon who happens to be carrying the Amulet while over water, killing a monster that had engulfed you does not result in the usual water effects removing a ring of levitation while engulfed should not invoke spoteffects feedback from invoking Orb of Detection was sometimes misleading or wrong ranger quest artifact (Longbow of Diana) confers reflection when wielded by monsters like it does for the player avoid discrepancies in size and associated armor-wearing ability between wizard gnome player and same player polymorphed into gnomish wizard by forcing newman() if poly-target matches your_race() add missing data.base entries for caveman, healer, monk, priest, and samurai allow "grey spellbook" as alternative spelling of "gray spellbook" handle attacks by cancelled monsters more consistently armor worn by monsters might negate some magic attacks like it does for hero give feedback and discovery when visible monster puts on cloak of invisibility really add artifacts inside carried containers to final score (3.3.1 fix displayed them them but didn't include any points for them) drop alternate weapon to terminate twoweapon combat if the alternate weapon gets cursed restore monster creation sanity checks to wizard mode ^G command prevent recoil from hurtling you through narrow areas that you wouldn't be able to move through intentionally grammar in cause of death when killed by slipping while mounting named steed ensure `m'enu is still an available traditional menu choice for menu-upon-request even when there is only one class of object present engraving on headstone will appropriately dull your weapon certain types of golems should not "catch fire" so adjust the messages no longer need to manually examine inventory after regaining sight in order to give a type name to an object picked up while blind when adding an object to inventory, it is possible for it to becomed both wielded and quivered if it merges with weapon and autoquiver is enabled include rocks as likely candidates for quivering if alternate weapon is a sling Asmodeus fails an is_armed() check, so code in m_initweap() to give him wands of fire and cold never got called; move the code to m_initinv() #rub would wield the target tool even when already being worn as eyewear monks lose their to-hit bonus for bare-handed attacking if wearing a shield fix case on leading character in "Crunched in the head..." in ball.c using travel mode to move next to a known trap and then trying to step onto that trap required an extra step; the first one ended up as a no-op punished with ball and chain on the same floor square as a trapped chest when it exploded resulted in panic "remove_object: obj not on floor" see_monsters() wasn't called when you lost the innate warning intrinsic due to level loss xorns sink if the drawbridge they're standing on is raised applying figurines to an adjacent spot over water does drowning checks fix sequencing of Magicbane's hit messages avoid buffer overflow from long or too many -s params wake up first if trying to crawl out of water while asleep while waiting, don't try to change into were form when already in were form steed should remember traps encountered while mounted killing shopkeeper by throwing unpaid things would result in "item not on bill" impossible error choking pet to death with cursed leash incurs various pet-killing penalties wielding Werebane prevents catching lycanthropy via monster attack (but not via eating, nor does it cure an existing case) character inflicted with lycanthropy is vulnerable to Werebane when in human/elf/&c form as well as when in beast form shopkeeper could get angry without remembering the customer name any object held by ghost during recorporealization would cease to exist including the Amulet of Yendor harassing monsters will be less likely to teleport to your location while they're running away from you randomize warning symbols during hallucination Platform- and/or Interface-Specific Fixes ----------------------------------------- wince: added Windows CE port from Alex Kompel win32: win32 build no longer defines MICRO win32: allow error save files to be generated win32: strip illegal file name characters from plname and replace with '_' win32: don't let recover build a save file out of level files belonging to an active NetHack.exe or NetHackw.exe process win32,winCE: SELF_RECOVER to let NetHack itself recover aborted games win32gui: make error() work; it was essentially non-operative in 3.4.0 win32gui: fix alignment of columns in menu windows win32gui: Window menu File|Save worked during #quit disclosure processing win32gui: make mswin_yn_function() case insensitive like the tty version win32gui: In msg window, gray out lines that are old and concatenate msgs win32gui: --More-- prompt if there are more messages than can fit this turn win32gui: flicker reduction because clear_nhwindow no longer redraws window win32gui: A caret bug was fixed win32gui: fix bug that caused two lines too many to be drawn on each paint win32gui: last line no longer highlighted win32gui: reduce the number of popups and support for !popup win32tty: honour the use_inverse option and default to ATR_BOLD if disabled win32tty: respond only to mouse clicks not mouse movement win32tty: allow ^C to abort the game at the "Who are you?" prompt win32tty: fix truncated score list win32tty: prevent ALT+CTRL from sending NUL to core with the meta bit set win32tty: international keyboard handling improved by letting ToAscii() generate input char based on VK and state of shift and caps lock Gnome: add support for non-square tiles Gnome: destroy main game windows correctly Gnome: Dylan Alex Simon's port of KDE-style worn window Gnome: Dylan Alex Simon's port of KDE-style hero cursor color Gnome/Linux: more portable getres*id workaround X11: restore support for non-square tiles when USE_XPM is defined X11: getlin dialog got steadily narrower each time it was used msdos: compiling without NO_TERMS resulted in a link-time error msdos: reworked Makefile.GCC to get rid of need to duplicate source files msdos,win32: stop doing chdir when NOCWD_ASSUMPTIONS is defined tty: remove #define DEBUG that forced debug behavior in production builds tty: correctly handle an empty TERM environment variable tty: don't lose messages when ESC has canceled their display tty: clear topl after pickup_burden prompt tty: support terms where turning off inverse video turns off color too tty: object selection at --More-- prompt after '?' didn't work anymore tty: ext command autocomplete now lets you enter auto-completed characters non-tty: silently ignore tty msg_window option to allow sharing of config file unix: install recover command into GAMEDIR by default vms: prevent error() from indirectly triggering hangup save during forced exit General New Features -------------------- lootabc option runmode option showrace option travel option cmdassist option to provide additional error feedback for some commands mouse_support wincap option scroll_amount wincap option to adjust how many cells to scroll at scroll_margin debug mode: #panic routine to test panic() and panic save file generation a new PANICLOG optional file to log the reason for panic and impossible messages added validate_prefix_locations() for early directory prefix validation fire traps are particularly bad for paper and straw golems cream pies can be 'a'pplied to cause direct temporary blindness eating newt corpse or tin of same can boost magical energy (Malcolm Ryan) applying a eucalyptus leaf produces a whistle effect (Malcolm Ryan) hobbits can wear elven mithril-coats eating mimics now has an hallucination effect prefix pickup command with 'm' to force menu of all objects present provide feedback which states the correct command when players try to use 'R' or 'P' for armour, or use 'W' or 'T' for accessories optional #portdebug wizard mode command to invoke port-specific debug routines nethack-3.4.3/doc/fixes34.20100644000000000000000000002441707764735041013777 0ustar rootroot$RCSfile: fixes34.2,v $ $Revision: 1.2.2.130 $ $Date: 2003/08/26 15:13:56 $ General Fixes and Modified Features ----------------------------------- avoid panic when secondary weapon is cursed while generating bones level don't crash when applying a figurine, candle, or bell that gets used up grammar bits two invisible monsters hitting one another should not be visible if only one monster in a monster-vs-monster fight is visible, show an I symbol for the other one whether it is an attacker or defender display "It" and not "The invisible " when an invisible pet eats food. include a hint about expected input when prompting for musical notes don't report "program initialization failed" if a panic occurs after the game is over include statue contents in end of game inventory disclosure treat handlessness as a major problem when deciding prayer outcome perform artifact touch checks when putting on accessories missing noun in message when horns pierce through your helmet don't use hcolor() for trapped chest gases when you aren't hallucinating the age of a potion of oil from a bones file wasn't being handled correctly putting gold in a container on the shop floor wasn't credited the way gold already in the container when dropped was credited avoid integer division rounding error when calculating carrying capacity don't lock/unlock a door while in a pit, to be consistent with door opening infravision should not make invisible player "visible" (it doesn't for monsters) Perseus statue should always be male charge correctly when breaking multiple objects with the same zap, avoids a dopay: not to shopkeeper impossible clean up funny lighting on the healer locate level allow all tame monsters that eat to consider food thrown to them the screen display wasn't always up to date after map topology changes jumping over a sokobon pit would result in the player next to, not in, the pit don't let arrow, rock or dart traps provide an infinite number of objects make enhanced ammo harder to break to make lesser number last longer dropping from height or throwing a normal container may damage contents some Magicbane messages treated "erinys" as plural initialize artifacts before processing $WIZKIT clean up inconsistency between various places quaff is documented is_damageable was using is_rottable incorrectly charge for use of an unpaid tinning kit avoid impossible when water freezes while hero is hiding under water avoid impossible after eating the object the hero is hiding under failed attempt to eat floor gold while polymorphed would lose the gold running that stops for closed doors should stop at mimics mimicking closed doors allow wishing for magenta potions (ignoring the rank name 'mage') fix an uninitialized memory access in non-quick dolookup fix were changing message that wasn't being displayed immediate encumbrance feedback when removing gauntlets of power make deliberately flying down the Castle's trap doors consistent with falling give more explicit feedback for exploding bag of holding help display for "list of game options" misformats runmode and scroll_amount pit created by land mine explosion doesn't start out concealed update map display sooner when pushed boulder triggers land mine explosion prevent several QBUFSZ sized buffers from overflowing and triggering fatal errors inside window port prompt routines make sure that leashed monsters are released prior to shopkeeper inheriting dead character's inventory attaching long named candle to long named candelabrum caused buffer overflow when polymorhed, only hand/weapon attack on disenchanter should result in damage to weapon, gloves, etc. killer should say "the" when choking on unique monster's corpse allow applying polearm on monster you can see via infravision killer reason shouldn't use "a" or "an" prefix for multiple projectiles scattered by land mine explosion killer reason for named missile could end up with garbage instead of the name make killer reason for various poisioning deaths be more consistent poison missiles were unintentionally more likely to inflict "deadly poison" than in pre-3.4.1 releases provide feedback when going invisible after eating a stalker killer on tombstone had no prefix for starvation/exhaustion case ensure proper message ordering for boulder trap messages clean up data set by join_map that is overlaid by MAPs on special levels clarify disclose option default in opthelp, and support "all" as old help said add more calls to update_inventory as the inventory changes don't charge for items picked up from monster's interior while swallowed choking while eating non-food always called the food "quick snack" short swords are not throwing weapons several sit-in-trap cases were unreachable curse candelabrum in bones, like other similar artifacts detecting a trap in a chest while confused should not exercise wisdom any golem statue hit with stone-to-flesh spell animates as flesh golem correct invalid startup gender selection can no longer untrap floor containers during unskilled riding can no longer easily set land mines and bear traps during unskilled riding refine cmdassist handling for armor vs accessories prevent monsters from level teleporting out of the quest into the main dungeon prevent monsters from level teleporting into the Sanctum prior to invocation "m," command sequence would let you see all objects at a location even when they included a cockatrice corpse which hero was unequipped to handle use correct pronoun for unique monsters hostile monsters who follow you between levels won't do so if they're fleeing options for font_size for map, menu, message, status, and text all had the same description of "the size of the map font" in options.c when dismounting by choice and unimpaired, try not to land in a known trap when jousting a pudding into a polymorh trap, it was possible to end up with two of the new type of monster don't allow polymorphed player to web over the stairs geographical shopkeeper updates stethoscope use should be free the first time it's use per player move travel command caches last position to make non-mouse less painful update pit trapped time when polymorphing to or from a monster that passes_walls show artifact hit message which affect the monster that swallowed the hero revived pet corpse from bones file should not be loyal to current player finding a statue trap you are about to dig should stop your occupation try to keep saddle at the same location as the steed corpse never display I symbol on the mounted hero/steed location pit digging is no longer stopped by a sleeping monster next to you ensure mksobj() always attaches timer to corpse, even if called with init FALSE only charge for eating one stacked tin, not all at once add flag to makemon() to allow monster to be created adjacent to the supplied coordinates if there is already a monster at the target location stone-to-flesh of spot with multiple statues can animate more than one use of stethoscope now deliberately impacted when hero is engulfed by whirly monster but fixed so it can sometimes work on your steed there too typos fixed in data.base add looting freehand() check to able_to_loot() to prevent opening container only to be told that you can't loot anything Schroedinger's Cat could be placed at wrong location when its box is carried travel while polymorphed into a grid bug should not move diagonally refine cmdassist handling for grid bugs when casting force bolt spell while engulfed go ahead and use the engulfers name in the hit message rather than "it" a fog cloud shouldn't pummel you with debris do not let an attached iron ball drag the hero through a location that the hero could not move normally hero's appearance should change immediately after mimicing completes avoid some uses of "it" in killer messages avoid "singular of null?" warning for info lookup of obscure user input there was no check for iron bars in dokick() so it defaulted to "empty space" if you couldn't see the rat created in a sink for some reason other than blindness, you would get "Eek there's it in the sink." digging a pit while stuck in the floor should always free the player quest guardians can no longer be created via stone-to-flesh on their statue stone-to-flesh no longer silently ignored by a statue of a unique monster wishing for quest guardian corpse now gives a generic corpse of the species prevent quest guardians from other classes from talking to you as if they were your quest guardian wake up shopkeeper if a shop transaction is attempted while he's immobilized statues created from monsters remember more monster attributes Platform- and/or Interface-Specific Fixes ----------------------------------------- Gnome: compilation problems on Redhat 7.2 and 8.0 unix: Makefile.utl would put OBJDIR objects in the wrong directory vms: create an empty paniclog file during playground installation win32tty: add subkeyvalue option to alter key values; Finnish keyboard fix win32tty: distinguish between black/gray/white (by Quietust) win32gui: prevent male Valkyrie and other incorrect startup settings win32gui: allow numeric quantity count on item selection during loot win32: some code in files.c was incorrectly assuming that a file descriptor return value of 0 from open() was invalid but it could be valid on win32gui where stdin, stdout, stderr aren't open; now it correctly checks for return value < 0 from open() tiles: high priest tile had a couple bad pixels tiles: bad pixels in Croesus and Yeenoghu tiles FreeBSD: incorrect srandom declaration unix: don't autosave if hangup occurs after game is over linux: add example use of nroff on recent Linux distros linux: use random() by default instead of lrand48() OpenBSD: time() prototype and correct default Mail program Gnome: compilation problems on Solaris unix: better error message for .nethackrc access problems vms: during installation, warn if dlb file creation or non-dlb playground setup is missing expected data files General New Features -------------------- debug mode level teleport menu via '?' Platform- and/or Interface-Specific New Features ------------------------------------------------ win32tty: keystroke handlers can be dynamically loaded to assist in resolving internationalization issues win32tty: add Ray Chason's code for international keyboard handling Solaris (and other SystemV variants): TIMED_DELAY support X11: NetHack.ad is now installed and used w/o user intervention nethack-3.4.3/doc/fixes34.30100644000000000000000000002006607764735041013774 0ustar rootroot$RCSfile: fixes34.3,v $ $Revision: 1.1.2.99 $ $Date: 2003/12/06 14:07:57 $ General Fixes and Modified Features ----------------------------------- monster draining the player using Stormbringer decreased monster's hitpoints polymorphing to a flaming sphere should cure slime like other flaming monsters grammar, spelling and other typos wishing for student corpse yielded a valkyrie one, not an archeologist one fix typo in bustling town down stairs declaration you could exceed the limits on nazgul and erinys counts via bones files fix inconsistency where you can't kick something out of a pit, but you can escape the pit and still pick it up; items are now assumed to be at the bottom of pit room cleanup, eg on Bustling Town, could incorrectly truncate room bounds for rooms that become L shared due to partial overlap with the MAP approaching Medusa while having reflection+invisibility+esp would cause her to turn herself to stone if you happened to be blind at the time Master Kaen's death message was not appropriate missing fountain tag in minend-3 do not pacify shopkeeper when the hero enters a shop if that hero previously angered the shopkeeper without ever visibly entering the shop attempting to place migrating monsters onto a monster-saturated level no longer triggers impossible() open_levelfile_exclusively() was showing the return value -1 in a panic message, even though that was the only possible value; show errno instead it was inappropriate to have a ghost "appear" in desecrated temple when you were blind and without telepathy accept wish for "grey spell book" not just "grey spellbook" do not double credit when putting gold into an unpaid container manes are nonliving poles and grappling hook worked thru walls when wearing Eyes of the Overworld more tweaks to fog cloud behavior when dismounting by choice and unimpaired, try not to land on a boulder casting stone-to-flesh on self while wielding a statue caused problems add tab support to menu strings for control-x minimal_enlightenment() if the monster that a statue represents is not made of flesh then don't allow stone_to_flesh to animate it, make a meatball instead attempting to saddle a cockatrice while wearing gloves shouldn't stone you kicking a closed drawbridge and dieing should not say "kicking a wall" cannot get blessed potions from sink, remove unreachable message couldn't insert gold into a container using full menu style if no other objects in inventory unless compiling with GOLDOBJ nagas eat always have warriors on the Valkyrie quest be female be more consistent with sounds when dropping into water surface() returns "bottom" when Underwater bill for all discarded, opened tins monsters that cannot pick things up cannot throw things either eating an amulet of unchanging un-changes you Vlad won't waste time trying to use wand of digging in his own tower non-weapon iron objects should rust when dipped in fountains since iron weapons rust suppress "turn to flee" message if monster is mfrozen don't silently interrupt monster's hold on you if Levitation/Flying ends while over water you could specifiy '~' with crystal ball and have it try to detect monsters, but it never revealed anything; show the entire long worm now allow a crystal ball to detect ghosts-and-shades via space key, and display the results using detected_mon_to_glyph() so that they show up in inverse video allow a crystal ball to detect boulders using the user-defined boulder symbol allow a crystal ball to detect mimics via ']' prevent boulder option from accepting a symbol that matches a monster symbol traveling while standing on a trap would sometime step in the wrong direction avoid traveling into water/lava, using usual running rules unchanging iron golem would still rehumanize in a rust trap fix an impossible rndmonst: bad `mndx' bug pets should not try to go after objects that they can't reach cutting a shopkeeper polymorphed in to a long worm would generate strange messages and could cause a crash reading a cursed scroll of light in a corridor wouldn't display correctly if lit_corridor option was disabled barbarians can become export in short sword skill samurai are now limited to master in martial arts skill; barbarians and cavemen are now limited to master in bare-handed combat skill tweak messages when werefoo summons help when polymorphed into a quantum mechanic, it was possible to jump into the water on a no teleport level and instinctively teleport when polymorphed into a quantum mechanic on a no teleport level and swallowed, no feedback was given when you teleported the swallower away allow Conflict-resistant monsters to respond to conflict attacks rather than sitting there and taking the attacks until they die prefer herbivorous stone-to-flesh message when hero is a vegitarian try even harder to avoid incorrect map display while changing levels no "freaked" message by exploding black light, unless you really are sleeping monster could respond to attacks by other monsters sleeping shopkeeper responds to various events without waking rotting corpses grammar fix allow successful teleport to more locations on debug mode level teleport menu trapped monster repeatedly switched between ranged and hand-to-hand weapon silver items such as wands avoided all the silver checks in hmon_hitmon() resuming an interrupted 'A' command could cause crash if pending worn item(s) were stolen or destroyed resuming interrupted 'A' sometimes ended with "You finished disrobing" twice when you're asleep you shouldn't "notice" monsters that have become undetected must be able to reach floor in order to use stethoscope on corpse or statue fix a few coordinate (y,y) -> (x,y) typos in apply.c, mon.c, and wizard.c killing a long worm on a drawbridge could produce a panic prevent "see it drop from your pack" when figurine monster becomes undetected attempting to drop a subset of a stack of multiple cursed loadstones could corrupt inventory or cause a crash "miss" message was missing for thrown or kicked gold not caught by a monster prevent recursive impossible() and panic() calls from leading to a stack overflow tainted meat didn't invoke cannibalism shopkeepers can't act as porters for the Amulet dismissed monsters can't remove special items from play Platform- and/or Interface-Specific Fixes ----------------------------------------- win32tty: fix visible CRLF characters during lockfile error message win32tty: switch to low level console routines win32tty: refrain from cursor movement until an input is pending (M. Lehotay) win32tty: distinguish blue, bright blue, cyan, and bright cyan (Nicholas Webb) win32tty: fix hanging problem when you ctrl-C at "Who are you?" prompt win32gui: you couldn't specify an alignment in defaults.nh and have it stick win32gui: allow race/gender/alignment selections beyond those specified in defaults.nh, while still honoring defaults.nh choices unix: don't define errno if NHSTDC unix: save file permissions could be wrong in explore/debug mode X11: avoid a possible crash when using window manger to close a player selection window Gnome: add Quiver menu item, fix outdated Quit menu item Gnome: key values on unsigned char platform could fail to compare correctly Gnome: real extended command menu so all extended commands can be entered Gnome: ignore interrupts to avoid infinite loop in gnome library tty: avoid crash displaying quit inventory if inventory was already displayed tty: use "bold" in menu heading if available and requested tty: differentiate between default unlit and lit corridor symbols winCE: ensure orphaned lockfile is always deleted on single-user handhelds General New Features -------------------- bones file compatibility info is now written into the dat/options file extend autodig to work downwards via '>' make attribute that is used to distinguish headings in a menu configurable add experimental build option AUTOPICKUP_EXCEPTIONS for filtering pickup of items by pattern matching against their doname() description include version number in paniclog entries add a section on "shops and shopping" to the Guidebook Platform- and/or Interface-Specific New Features ------------------------------------------------ nethack-3.4.3/doc/lev_comp.60100644000000000000000000002460007764735041014314 0ustar rootroot.TH LEV_COMP 6 "16 May 1996" .UC 4 .SH NAME lev_comp \- NetHack special levels compiler .SH SYNOPSIS .B lev_comp [ .B \-w ] [ .I files ] .PP If no arguments are given, it reads standard input. .SH DESCRIPTION .PP .I Lev_comp is a special level compiler for NetHack version 3.2 and higher. It takes description files as arguments and produces level files that can be loaded by NetHack at runtime. .PP The purpose of this tool is to provide NetHack administrators and implementors with a convenient way for adding special levels to the game, or modifying existing ones, without having to recompile the entire world. .PP The .B \-w option causes .I lev_comp to perform extra checks on the level and display extra warnings, however these warnings are sometimes superfluous, so they are not normally displayed. .SH GRAMMAR .PP .LP .nf .ta +8n +8n +8n +8n file : /* nothing */ | levels ; levels : level | level levels ; level : maze_level | room_level ; maze_level : maze_def flags lev_init messages regions ; room_level : level_def flags lev_init messages rreg_init rooms corridors_def ; level_def : LEVEL_ID ':' string ; lev_init : /* nothing */ | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled ; walled : BOOLEAN | RANDOM_TYPE ; flags : /* nothing */ | FLAGS_ID ':' flag_list ; flag_list : FLAG_TYPE ',' flag_list | FLAG_TYPE ; messages : /* nothing */ | message messages ; message : MESSAGE_ID ':' STRING ; rreg_init : /* nothing */ | rreg_init init_rreg ; init_rreg : RANDOM_OBJECTS_ID ':' object_list | RANDOM_MONSTERS_ID ':' monster_list ; rooms : /* Nothing - dummy room for use with INIT_MAP */ | roomlist ; roomlist : aroom | aroom roomlist ; corridors_def : random_corridors | corridors ; random_corridors: RAND_CORRIDOR_ID ; corridors : /* nothing */ | corridors corridor ; corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec | CORRIDOR_ID ':' corr_spec ',' INTEGER ; corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')' ; aroom : room_def room_details | subroom_def room_details ; subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill ; room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill ; roomfill : /* nothing */ | ',' BOOLEAN ; room_pos : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; subroom_pos : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; room_align : '(' h_justif ',' v_justif ')' | RANDOM_TYPE ; room_size : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; room_details : /* nothing */ | room_details room_detail ; room_detail : room_name | room_chance | room_door | monster_detail | object_detail | trap_detail | altar_detail | fountain_detail | sink_detail | pool_detail | gold_detail | engraving_detail | stair_detail ; room_name : NAME_ID ':' string ; room_chance : CHANCE_ID ':' INTEGER ; room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos ; secret : BOOLEAN | RANDOM_TYPE ; door_wall : DIRECTION | RANDOM_TYPE ; door_pos : INTEGER | RANDOM_TYPE ; maze_def : MAZE_ID ':' string ',' filling ; filling : CHAR | RANDOM_TYPE ; regions : aregion | aregion regions ; aregion : map_definition reg_init map_details ; map_definition : NOMAP_ID | map_geometry MAP_ID ; map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif ; h_justif : LEFT_OR_RIGHT | CENTER ; v_justif : TOP_OR_BOT | CENTER ; reg_init : /* nothing */ | reg_init init_reg ; init_reg : RANDOM_OBJECTS_ID ':' object_list | RANDOM_PLACES_ID ':' place_list | RANDOM_MONSTERS_ID ':' monster_list ; object_list : object | object ',' object_list ; monster_list : monster | monster ',' monster_list ; place_list : place | place ',' place_list ; map_details : /* nothing */ | map_details map_detail ; map_detail : monster_detail | object_detail | door_detail | trap_detail | drawbridge_detail | region_detail | stair_region | portal_region | teleprt_region | branch_region | altar_detail | fountain_detail | mazewalk_detail | wallify_detail | ladder_detail | stair_detail | gold_detail | engraving_detail | diggable_detail | passwall_detail ; monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate monster_infos ; monster_infos : /* nothing */ | monster_infos monster_info ; monster_info : ',' string | ',' MON_ATTITUDE | ',' MON_ALERTNESS | ',' alignment | ',' MON_APPEARANCE string ; object_detail : OBJECT_ID object_desc | COBJECT_ID object_desc ; object_desc : chance ':' object_c ',' o_name ',' object_where object_infos ; object_where : coordinate | CONTAINED ; object_infos : /* nothing */ | ',' curse_state ',' monster_id ',' enchantment optional_name | ',' curse_state ',' enchantment optional_name | ',' monster_id ',' enchantment optional_name ; curse_state : RANDOM_TYPE | CURSE_TYPE ; monster_id : STRING ; enchantment : RANDOM_TYPE | INTEGER ; optional_name : /* nothing */ | ',' NONE | ',' STRING ; door_detail : DOOR_ID ':' door_state ',' coordinate ; trap_detail : TRAP_ID chance ':' trap_name ',' coordinate ; drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state ; mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION ; wallify_detail : WALLIFY_ID ; ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN ; stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN ; stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN ; portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' string ; teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail ; branch_region : BRANCH_ID ':' lev_region ',' lev_region ; teleprt_detail : /* empty */ | ',' UP_OR_DOWN ; lev_region : region | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' ; fountain_detail : FOUNTAIN_ID ':' coordinate ; sink_detail : SINK_ID ':' coordinate ; pool_detail : POOL_ID ':' coordinate ; diggable_detail : NON_DIGGABLE_ID ':' region ; passwall_detail : NON_PASSWALL_ID ':' region ; region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled ; altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type ; gold_detail : GOLD_ID ':' amount ',' coordinate ; engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string ; monster_c : monster | RANDOM_TYPE | m_register ; object_c : object | RANDOM_TYPE | o_register ; m_name : string | RANDOM_TYPE ; o_name : string | RANDOM_TYPE ; trap_name : string | RANDOM_TYPE ; room_type : string | RANDOM_TYPE ; prefilled : /* empty */ | ',' FILLING | ',' FILLING ',' BOOLEAN ; coordinate : coord | p_register | RANDOM_TYPE ; door_state : DOOR_STATE | RANDOM_TYPE ; light_state : LIGHT_STATE | RANDOM_TYPE ; alignment : ALIGNMENT | a_register | RANDOM_TYPE ; altar_type : ALTAR_TYPE | RANDOM_TYPE ; p_register : P_REGISTER '[' INTEGER ']' ; o_register : O_REGISTER '[' INTEGER ']' ; m_register : M_REGISTER '[' INTEGER ']' ; a_register : A_REGISTER '[' INTEGER ']' ; place : coord ; monster : CHAR ; object : CHAR ; string : STRING ; amount : INTEGER | RANDOM_TYPE ; chance : /* empty */ | PERCENT ; engraving_type : ENGRAVING_TYPE | RANDOM_TYPE ; coord : '(' INTEGER ',' INTEGER ')' ; region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' ; .fi .PP .I NOTE: .br Lines beginning with '#' are considered comments. .PP The contents of a "MAP" description of a maze is a rectangle showing the exact level map that should be used for the given part of a maze. Each character in the map corresponds to a location on the screen. Different location types are denoted using different ASCII characters. The following characters are recognized. To give an idea of how these are used, see the EXAMPLE, below. The maximum size of a map is normally 76 columns by 21 rows. .LP .nf .ta +8n +8n +8n \&'-' horizontal wall \&'|' vertical wall \&'+' a doorway (state is specified in a DOOR declaration) \&'A' open air \&'B' boundary room location (for bounding unwalled irregular regions) \&'C' cloudy air \&'I' ice \&'S' a secret door \&'H' a secret corridor \&'{' a fountain \&'\\' a throne \&'K' a sink (if SINKS is defined, else a room location) \&'}' a part of a moat or other deep water \&'P' a pool \&'L' lava \&'W' water (yes, different from a pool) \&'T' a tree \&'F' iron bars \&'#' a corridor \&'.' a normal room location (unlit unless lit in a REGION declaration) \&' ' stone .fi .SH EXAMPLE .PP Here is an example of a description file (a very simple one): .LP .nf .ta +8n +8n +8n MAZE : "fortress", random GEOMETRY : center , center MAP }}}}}}}}} }}}|-|}}} }}|-.-|}} }|-...-|} }|.....|} }|-...-|} }}|-.-|}} }}}|-|}}} }}}}}}}}} ENDMAP MONSTER: '@', "Wizard of Yendor", (4,4) OBJECT: '"', "Amulet of Yendor", (4,4) # a hell hound flanking the Wiz on a random side RANDOM_PLACES: (4,3), (4,5), (3,4), (5,4) MONSTER: 'd', "hell hound", place[0] # a chest on another random side OBJECT: '(', "chest", place[1] # a sack on a random side, with a diamond and maybe a ruby in it CONTAINER: '(', "sack", place[2] OBJECT: '*', "diamond", contained OBJECT[50%]: '*', "ruby", contained # a random dragon somewhere MONSTER: 'D', random, random # 3 out of 4 chance for a random trap in the EAST end TRAP[75%]: random, (6,4) # an electric eel below the SOUTH end MONSTER: ';', "electric eel", (4,8) # make the walls non-diggable NON_DIGGABLE: (0,0,8,8) TELEPORT_REGION: levregion(0,0,79,20), (0,0,8,8) .fi .PP This example will produce a file named "fortress" that can be integrated into one of the numerous mazes of the game. .PP Note especially the final, TELEPORT_REGION specification. This says that level teleports or other non-stairway arrivals on this level can land anywhere on the level except the area of the map. This shows the use of the ``levregion'' prefix allowed in certain region specifications. Normally, regions apply only to the most recent MAP specification, but when prefixed with ``levregion'', one can refer to any area of the level, regardless of the placement of the current MAP in the level. .SH AUTHOR .PP Jean-Christophe Collet, David Cohrs. .SH "SEE ALSO" .PP dgn_comp(6), nethack(6) .SH BUGS .PP Probably infinite. Most importantly, still needs additional bounds checking. nethack-3.4.3/doc/lev_comp.txt0100644000000000000000000004253507764735041014775 0ustar rootroot LEV_COMP(6) 1996 LEV_COMP(6) NAME lev_comp - NetHack special levels compiler SYNOPSIS lev_comp [ -w ] [ files ] If no arguments are given, it reads standard input. DESCRIPTION Lev_comp is a special level compiler for NetHack version 3.2 and higher. It takes description files as arguments and produces level files that can be loaded by NetHack at run- time. The purpose of this tool is to provide NetHack administra- tors and implementors with a convenient way for adding spe- cial levels to the game, or modifying existing ones, without having to recompile the entire world. The -w option causes lev_comp to perform extra checks on the level and display extra warnings, however these warnings are sometimes superfluous, so they are not normally displayed. GRAMMAR file : /* nothing */ | levels ; levels : level | level levels ; level : maze_level | room_level ; maze_level : maze_def flags lev_init messages regions ; room_level : level_def flags lev_init messages rreg_init rooms corridors_def ; level_def : LEVEL_ID ':' string ; lev_init : /* nothing */ | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled ; walled : BOOLEAN | RANDOM_TYPE May Last change: 16 1 LEV_COMP(6) 1996 LEV_COMP(6) ; flags : /* nothing */ | FLAGS_ID ':' flag_list ; flag_list : FLAG_TYPE ',' flag_list | FLAG_TYPE ; messages : /* nothing */ | message messages ; message : MESSAGE_ID ':' STRING ; rreg_init : /* nothing */ | rreg_init init_rreg ; init_rreg : RANDOM_OBJECTS_ID ':' object_list | RANDOM_MONSTERS_ID ':' monster_list ; rooms : /* Nothing - dummy room for use with INIT_MAP */ | roomlist ; roomlist : aroom | aroom roomlist ; corridors_def : random_corridors | corridors ; random_corridors: RAND_CORRIDOR_ID ; corridors : /* nothing */ | corridors corridor ; corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec | CORRIDOR_ID ':' corr_spec ',' INTEGER ; corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')' ; aroom : room_def room_details May Last change: 16 2 LEV_COMP(6) 1996 LEV_COMP(6) | subroom_def room_details ; subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill ; room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill ; roomfill : /* nothing */ | ',' BOOLEAN ; room_pos : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; subroom_pos : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; room_align : '(' h_justif ',' v_justif ')' | RANDOM_TYPE ; room_size : '(' INTEGER ',' INTEGER ')' | RANDOM_TYPE ; room_details : /* nothing */ | room_details room_detail ; room_detail : room_name | room_chance | room_door | monster_detail | object_detail | trap_detail | altar_detail | fountain_detail | sink_detail | pool_detail | gold_detail | engraving_detail | stair_detail ; room_name : NAME_ID ':' string ; room_chance : CHANCE_ID ':' INTEGER May Last change: 16 3 LEV_COMP(6) 1996 LEV_COMP(6) ; room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos ; secret : BOOLEAN | RANDOM_TYPE ; door_wall : DIRECTION | RANDOM_TYPE ; door_pos : INTEGER | RANDOM_TYPE ; maze_def : MAZE_ID ':' string ',' filling ; filling : CHAR | RANDOM_TYPE ; regions : aregion | aregion regions ; aregion : map_definition reg_init map_details ; map_definition : NOMAP_ID | map_geometry MAP_ID ; map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif ; h_justif : LEFT_OR_RIGHT | CENTER ; v_justif : TOP_OR_BOT | CENTER ; reg_init : /* nothing */ | reg_init init_reg ; init_reg : RANDOM_OBJECTS_ID ':' object_list | RANDOM_PLACES_ID ':' place_list May Last change: 16 4 LEV_COMP(6) 1996 LEV_COMP(6) | RANDOM_MONSTERS_ID ':' monster_list ; object_list : object | object ',' object_list ; monster_list : monster | monster ',' monster_list ; place_list : place | place ',' place_list ; map_details : /* nothing */ | map_details map_detail ; map_detail : monster_detail | object_detail | door_detail | trap_detail | drawbridge_detail | region_detail | stair_region | portal_region | teleprt_region | branch_region | altar_detail | fountain_detail | mazewalk_detail | wallify_detail | ladder_detail | stair_detail | gold_detail | engraving_detail | diggable_detail | passwall_detail ; monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate monster_infos ; monster_infos : /* nothing */ | monster_infos monster_info ; monster_info : ',' string | ',' MON_ATTITUDE | ',' MON_ALERTNESS May Last change: 16 5 LEV_COMP(6) 1996 LEV_COMP(6) | ',' alignment | ',' MON_APPEARANCE string ; object_detail : OBJECT_ID object_desc | COBJECT_ID object_desc ; object_desc : chance ':' object_c ',' o_name ',' object_where object_infos ; object_where : coordinate | CONTAINED ; object_infos : /* nothing */ | ',' curse_state ',' monster_id ',' enchantment optional_name | ',' curse_state ',' enchantment optional_name | ',' monster_id ',' enchantment optional_name ; curse_state : RANDOM_TYPE | CURSE_TYPE ; monster_id : STRING ; enchantment : RANDOM_TYPE | INTEGER ; optional_name : /* nothing */ | ',' NONE | ',' STRING ; door_detail : DOOR_ID ':' door_state ',' coordinate ; trap_detail : TRAP_ID chance ':' trap_name ',' coordinate ; drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state ; mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION ; wallify_detail : WALLIFY_ID ; May Last change: 16 6 LEV_COMP(6) 1996 LEV_COMP(6) ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN ; stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN ; stair_region : STAIR_ID ':' lev_region ',' lev_region ',' UP_OR_DOWN ; portal_region : PORTAL_ID ':' lev_region ',' lev_region ',' string ; teleprt_region : TELEPRT_ID ':' lev_region ',' lev_region teleprt_detail ; branch_region : BRANCH_ID ':' lev_region ',' lev_region ; teleprt_detail : /* empty */ | ',' UP_OR_DOWN ; lev_region : region | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' ; fountain_detail : FOUNTAIN_ID ':' coordinate ; sink_detail : SINK_ID ':' coordinate ; pool_detail : POOL_ID ':' coordinate ; diggable_detail : NON_DIGGABLE_ID ':' region ; passwall_detail : NON_PASSWALL_ID ':' region ; region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled ; altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type ; gold_detail : GOLD_ID ':' amount ',' coordinate ; engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string ; May Last change: 16 7 LEV_COMP(6) 1996 LEV_COMP(6) monster_c : monster | RANDOM_TYPE | m_register ; object_c : object | RANDOM_TYPE | o_register ; m_name : string | RANDOM_TYPE ; o_name : string | RANDOM_TYPE ; trap_name : string | RANDOM_TYPE ; room_type : string | RANDOM_TYPE ; prefilled : /* empty */ | ',' FILLING | ',' FILLING ',' BOOLEAN ; coordinate : coord | p_register | RANDOM_TYPE ; door_state : DOOR_STATE | RANDOM_TYPE ; light_state : LIGHT_STATE | RANDOM_TYPE ; alignment : ALIGNMENT | a_register | RANDOM_TYPE ; altar_type : ALTAR_TYPE | RANDOM_TYPE ; May Last change: 16 8 LEV_COMP(6) 1996 LEV_COMP(6) p_register : P_REGISTER '[' INTEGER ']' ; o_register : O_REGISTER '[' INTEGER ']' ; m_register : M_REGISTER '[' INTEGER ']' ; a_register : A_REGISTER '[' INTEGER ']' ; place : coord ; monster : CHAR ; object : CHAR ; string : STRING ; amount : INTEGER | RANDOM_TYPE ; chance : /* empty */ | PERCENT ; engraving_type : ENGRAVING_TYPE | RANDOM_TYPE ; coord : '(' INTEGER ',' INTEGER ')' ; region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' ; NOTE: Lines beginning with '#' are considered comments. The contents of a "MAP" description of a maze is a rectangle showing the exact level map that should be used for the given part of a maze. Each character in the map corresponds to a location on the screen. Different location types are denoted using different ASCII characters. The following characters are recognized. To give an idea of how these are used, see the EXAMPLE, below. The maximum size of a map is May Last change: 16 9 LEV_COMP(6) 1996 LEV_COMP(6) normally 76 columns by 21 rows. '-' horizontal wall '|' vertical wall '+' a doorway (state is specified in a DOOR declaration) 'A' open air 'B' boundary room location (for bounding unwalled irregular regions) 'C' cloudy air 'I' ice 'S' a secret door 'H' a secret corridor '{' a fountain '\' a throne 'K' a sink (if SINKS is defined, else a room location) '}' a part of a moat or other deep water 'P' a pool 'L' lava 'W' water (yes, different from a pool) 'T' a tree 'F' iron bars '#' a corridor '.' a normal room location (unlit unless lit in a REGION declaration) ' ' stone EXAMPLE Here is an example of a description file (a very simple one): MAZE : "fortress", random GEOMETRY : center , center MAP }}}}}}}}} }}}|-|}}} }}|-.-|}} }|-...-|} }|.....|} }|-...-|} }}|-.-|}} }}}|-|}}} }}}}}}}}} ENDMAP MONSTER: '@', "Wizard of Yendor", (4,4) OBJECT: '"', "Amulet of Yendor", (4,4) # a hell hound flanking the Wiz on a random side RANDOM_PLACES: (4,3), (4,5), (3,4), (5,4) MONSTER: 'd', "hell hound", place[0] # a chest on another random side OBJECT: '(', "chest", place[1] # a sack on a random side, with a diamond and maybe a ruby in it CONTAINER: '(', "sack", place[2] OBJECT: '*', "diamond", contained OBJECT[50%]: '*', "ruby", contained May Last change: 16 10 LEV_COMP(6) 1996 LEV_COMP(6) # a random dragon somewhere MONSTER: 'D', random, random # 3 out of 4 chance for a random trap in the EAST end TRAP[75%]: random, (6,4) # an electric eel below the SOUTH end MONSTER: ';', "electric eel", (4,8) # make the walls non-diggable NON_DIGGABLE: (0,0,8,8) TELEPORT_REGION: levregion(0,0,79,20), (0,0,8,8) This example will produce a file named "fortress" that can be integrated into one of the numerous mazes of the game. Note especially the final, TELEPORT_REGION specification. This says that level teleports or other non-stairway arrivals on this level can land anywhere on the level except the area of the map. This shows the use of the ``levre- gion'' prefix allowed in certain region specifications. Normally, regions apply only to the most recent MAP specifi- cation, but when prefixed with ``levregion'', one can refer to any area of the level, regardless of the placement of the current MAP in the level. AUTHOR Jean-Christophe Collet, David Cohrs. SEE ALSO dgn_comp(6), nethack(6) BUGS Probably infinite. Most importantly, still needs additional bounds checking. May Last change: 16 11 nethack-3.4.3/doc/nethack.60100644000000000000000000001756307764735041014137 0ustar rootroot.TH NETHACK 6 "9 August 2002" .UC 4 .SH NAME nethack \- Exploring The Mazes of Menace .SH SYNOPSIS .na .hy 0 .B nethack [ .B \-d .I directory ] [ .B \-n ] [ .B \-p .I profession (role) ] [ .B \-r .I race ] [ .B \-[DX] ] [ .B \-u .I playername ] [ .B \-dec ] [ .B \-ibm ] .PP .B nethack [ .B \-d .I directory ] .B \-s [ .B \-v ] [ .B \-p .I profession (role) ] [ .B \-r .I race ] [ .I playernames ] .ad .hy 14 .SH DESCRIPTION .PP .I NetHack is a display oriented Dungeons & Dragons(tm) - like game. The standard tty display and command structure resemble rogue. .PP Other, more graphical display options exist if you are using either a PC, or an X11 interface. .PP To get started you really only need to know two commands. The command .B ? will give you a list of the available commands (as well as other information) and the command .B / will identify the things you see on the screen. .PP To win the game (as opposed to merely playing to beat other people's high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dungeon and get it out. Nobody has achieved this yet; anybody who does will probably go down in history as a hero among heros. .PP When the game ends, whether by your dying, quitting, or escaping from the caves, .I NetHack will give you (a fragment of) the list of top scorers. The scoring is based on many aspects of your behavior, but a rough estimate is obtained by taking the amount of gold you've found in the cave plus four times your (real) experience. Precious stones may be worth a lot of gold when brought to the exit. There is a 10% penalty for getting yourself killed. .PP The environment variable NETHACKOPTIONS can be used to initialize many run-time options. The ? command provides a description of these options and syntax. (The .B \-dec and .B \-ibm command line options are equivalent to the .B decgraphics and .B ibmgraphics run-time options described there, and are provided purely for convenience on systems supporting multiple types of terminals.) .PP Because the option list can be very long (particularly when specifying graphics characters), options may also be included in a configuration file. The default is located in your home directory and named .nethackrc on Unix systems. On other systems, the default may be different, usually NetHack.cnf. On DOS or Windows, the name is defaults.nh, while on the Macintosh or BeOS, it is NetHack Defaults. The configuration file's location may be specified by setting NETHACKOPTIONS to a string consisting of an @ character followed by the filename. .PP The .B \-u .I playername option supplies the answer to the question "Who are you?". It overrides any name from the options or configuration file, USER, LOGNAME, or getlogin(), which will otherwise be tried in order. If none of these provides a useful name, the player will be asked for one. Player names (in conjunction with uids) are used to identify save files, so you can have several saved games under different names. Conversely, you must use the appropriate player name to restore a saved game. .PP A .I playername suffix can be used to specify the profession, race, alignment and/or gender of the character. The full syntax of the playername that includes a suffix is "name-ppp-rrr-aaa-ggg". "ppp" are at least the first three letters of the profession (this can also be specified using a separate .B \-p .I profession option). "rrr" are at least the first three letters of the character's race (this can also be specified using a separate .B \-r .I race option). "aaa" are at last the first three letters of the character's alignment, and "ggg" are at least the first three letters of the character's gender. Any of the parts of the suffix may be left out. .PP .B \-p .I profession can be used to determine the character role. You can specify either the male or female name for the character role, or the first three characters of the role as an abbreviation. .B "\-p \@" has been retained to explicitly request that a random role be chosen. It may need to be quoted with a backslash (\\@) if @ is the "kill" character (see "stty") for the terminal, in order to prevent the current input line from being cleared. .PP Likewise, .B \-r .I race can be used to explicitly request that a race be chosen. .PP Leaving out any of these characteristics will result in you being prompted during the game startup for the information. .PP .PP The .B \-s option alone will print out the list of your scores on the current version. An immediately following .B \-v reports on all versions present in the score file. The .B \-s may also be followed by arguments .B \-p and .B \-r to print the scores of particular roles and races only. It may also be followed by one or more player names to print the scores of the players mentioned, by 'all' to print out all scores, or by a number to print that many top scores. .PP The .B \-n option suppresses printing of any news from the game administrator. .PP The .B \-D or .B \-X option will start the game in a special non-scoring discovery mode. .B \-D will, if the player is the game administrator, start in debugging (wizard) mode instead. .PP The .B \-d option, which must be the first argument if it appears, supplies a directory which is to serve as the playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). This option is usually only useful to the game administrator. The playground must contain several auxiliary files such as help files, the list of top scorers, and a subdirectory .I save where games are saved. .SH AUTHORS .PP Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the original hack, very much like rogue (but full of bugs). .PP Andries Brouwer continuously deformed their sources into an entirely different game. .PP Mike Stephenson has continued the perversion of sources, adding various warped character classes and sadistic traps with the help of many strange people who reside in that place between the worlds, the Usenet Zone. A number of these miscreants are immortalized in the historical roll of dishonor and various other places. .PP The resulting mess is now called NetHack, to denote its development by the Usenet. Andries Brouwer has made this request for the distinction, as he may eventually release a new version of his own. .SH FILES .PP All files are in the playground, normally /usr/games/lib/nethackdir. If DLB was defined during the compile, the data files and special levels will be inside a larger file, normally nhdat, instead of being separate files. .br .DT .ta \w'cmdhelp, opthelp, wizhelp\ \ \ 'u nethack The program itself. .br data, oracles, rumors Data files used by NetHack. .br options, quest.dat More data files. .br help, hh Help data files. .br cmdhelp, opthelp, wizhelp More help data files. .br *.lev Predefined special levels. .br dungeon Control file for special levels. .br history A short history of NetHack. .br license Rules governing redistribution. .br record The list of top scorers. .br logfile An extended list of games .br played. .br xlock.nnn Description of a dungeon level. .br perm Lock file for xlock.dd. .br bonesDD.nn Descriptions of the ghost and .br belongings of a deceased .br adventurer. .br save A subdirectory containing the .br saved games. .SH ENVIRONMENT .DT .ta \w'HACKPAGER or PAGER\ \ \ 'u USER or LOGNAME Your login name. .br HOME Your home directory. .br SHELL Your shell. .br TERM The type of your terminal. .br HACKPAGER or PAGER Replacement for default pager. .br MAIL Mailbox file. .br MAILREADER Replacement for default reader .br (probably /bin/mail or /usr/ucb/mail). .br NETHACKDIR Playground. .br NETHACKOPTIONS String predefining several NetHack .br options. .br In addition, SHOPTYPE is used in debugging (wizard) mode. .SH "SEE ALSO" .PP dgn_comp(6), lev_comp(6), recover(6) .SH BUGS .PP Probably infinite. .PP Dungeons & Dragons is a Trademark of Wizards of the Coast, Inc. nethack-3.4.3/doc/nethack.txt0100644000000000000000000002246007764735041014601 0ustar rootrootNETHACK(6) NETHACK(6) NAME nethack - Exploring The Mazes of Menace SYNOPSIS nethack [ -d directory ] [ -n ] [ -p profession (role) ] [ -r race ] [ -[DX] ] [ -u playername ] [ -dec ] [ -ibm ] nethack [ -d directory ] -s [ -v ] [ -p profession (role) ] [ -r race ] [ playernames ] DESCRIPTION NetHack is a display oriented Dungeons & Dragons(tm) - like game. The standard tty display and command structure resemble rogue. Other, more graphical display options exist if you are using either a PC, or an X11 interface. To get started you really only need to know two commands. The command ? will give you a list of the available com- mands (as well as other information) and the command / will identify the things you see on the screen. To win the game (as opposed to merely playing to beat other people's high scores) you must locate the Amulet of Yendor which is somewhere below the 20th level of the dun- geon and get it out. Nobody has achieved this yet; any- body who does will probably go down in history as a hero among heros. When the game ends, whether by your dying, quitting, or escaping from the caves, NetHack will give you (a fragment of) the list of top scorers. The scoring is based on many aspects of your behavior, but a rough estimate is obtained by taking the amount of gold you've found in the cave plus four times your (real) experience. Precious stones may be worth a lot of gold when brought to the exit. There is a 10% penalty for getting yourself killed. The environment variable NETHACKOPTIONS can be used to initialize many run-time options. The ? command provides a description of these options and syntax. (The -dec and -ibm command line options are equivalent to the decgraph- ics and ibmgraphics run-time options described there, and are provided purely for convenience on systems supporting multiple types of terminals.) Because the option list can be very long (particularly when specifying graphics characters), options may also be included in a configuration file. The default is located in your home directory and named .nethackrc on Unix sys- tems. On other systems, the default may be different, usually NetHack.cnf. On DOS or Windows, the name is defaults.nh, while on the Macintosh or BeOS, it is NetHack Defaults. The configuration file's location may be speci- fied by setting NETHACKOPTIONS to a string consisting of an @ character followed by the filename. The -u playername option supplies the answer to the ques- tion "Who are you?". It overrides any name from the options or configuration file, USER, LOGNAME, or getlo- gin(), which will otherwise be tried in order. If none of these provides a useful name, the player will be asked for one. Player names (in conjunction with uids) are used to identify save files, so you can have several saved games under different names. Conversely, you must use the appropriate player name to restore a saved game. A playername suffix can be used to specify the profession, race, alignment and/or gender of the character. The full syntax of the playername that includes a suffix is "name- ppp-rrr-aaa-ggg". "ppp" are at least the first three let- ters of the profession (this can also be specified using a separate -p profession option). "rrr" are at least the first three letters of the character's race (this can also be specified using a separate -r race option). "aaa" are at last the first three letters of the character's align- ment, and "ggg" are at least the first three letters of the character's gender. Any of the parts of the suffix may be left out. -p profession can be used to determine the character role. You can specify either the male or female name for the character role, or the first three characters of the role as an abbreviation. -p @ has been retained to explicitly request that a random role be chosen. It may need to be quoted with a backslash (\@) if @ is the "kill" character (see "stty") for the terminal, in order to prevent the current input line from being cleared. Likewise, -r race can be used to explicitly request that a race be chosen. Leaving out any of these characteristics will result in you being prompted during the game startup for the infor- mation. The -s option alone will print out the list of your scores on the current version. An immediately following -v reports on all versions present in the score file. The -s may also be followed by arguments -p and -r to print the scores of particular roles and races only. It may also be followed by one or more player names to print the scores of the players mentioned, by 'all' to print out all scores, or by a number to print that many top scores. The -n option suppresses printing of any news from the game administrator. The -D or -X option will start the game in a special non- scoring discovery mode. -D will, if the player is the game administrator, start in debugging (wizard) mode instead. The -d option, which must be the first argument if it appears, supplies a directory which is to serve as the playground. It overrides the value from NETHACKDIR, HACK- DIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). This option is usually only useful to the game administra- tor. The playground must contain several auxiliary files such as help files, the list of top scorers, and a subdi- rectory save where games are saved. AUTHORS Jay Fenlason (+ Kenny Woodland, Mike Thome and Jon Payne) wrote the original hack, very much like rogue (but full of bugs). Andries Brouwer continuously deformed their sources into an entirely different game. Mike Stephenson has continued the perversion of sources, adding various warped character classes and sadistic traps with the help of many strange people who reside in that place between the worlds, the Usenet Zone. A number of these miscreants are immortalized in the historical roll of dishonor and various other places. The resulting mess is now called NetHack, to denote its development by the Usenet. Andries Brouwer has made this request for the distinction, as he may eventually release a new version of his own. FILES All files are in the playground, normally /usr/games/lib/nethackdir. If DLB was defined during the compile, the data files and special levels will be inside a larger file, normally nhdat, instead of being separate files. nethack The program itself. data, oracles, rumors Data files used by NetHack. options, quest.dat More data files. help, hh Help data files. cmdhelp, opthelp, wizhelp More help data files. *.lev Predefined special levels. dungeon Control file for special lev- els. history A short history of NetHack. license Rules governing redistribu- tion. record The list of top scorers. logfile An extended list of games played. xlock.nnn Description of a dungeon level. perm Lock file for xlock.dd. bonesDD.nn Descriptions of the ghost and belongings of a deceased adventurer. save A subdirectory containing the saved games. ENVIRONMENT USER or LOGNAME Your login name. HOME Your home directory. SHELL Your shell. TERM The type of your terminal. HACKPAGER or PAGER Replacement for default pager. MAIL Mailbox file. MAILREADER Replacement for default reader (probably /bin/mail or /usr/ucb/mail). NETHACKDIR Playground. NETHACKOPTIONS String predefining several NetHack options. In addition, SHOPTYPE is used in debugging (wizard) mode. SEE ALSO dgn_comp(6), lev_comp(6), recover(6) BUGS Probably infinite. Dungeons & Dragons is a Trademark of Wizards of the Coast, Inc. 9 August 2002 NETHACK(6) nethack-3.4.3/doc/recover.60100644000000000000000000000705707764735041014164 0ustar rootroot.TH RECOVER 6 "9 January 1993" .UC 4 .SH NAME recover \- recover a NetHack game interrupted by disaster .SH SYNOPSIS .B recover [ .B \-d .I directory ] .I "base1 base2" ... .SH DESCRIPTION .PP Occasionally, a NetHack game will be interrupted by disaster when the game or the system crashes. Prior to NetHack v3.1, these games were lost because various information like the player's inventory was kept only in memory. Now, all pertinent information can be written out to disk, so such games can be recovered at the point of the last level change. .PP The .I base options tell .I recover which files to process. Each base option specifies recovery of a separate game. .PP The .B \-d option, which must be the first argument if it appears, supplies a directory which is the NetHack playground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). .PP For recovery to be possible, .I nethack must have been compiled with the INSURANCE option, and the run-time option .I checkpoint must also have been on. NetHack normally writes out files for levels as the player leaves them, so they will be ready for return visits. When checkpointing, NetHack also writes out the level entered and the current game state on every level change. This naturally slows level changes down somewhat. .PP The level file names are of the form base.nn, where nn is an internal bookkeeping number for the level. The file base.0 is used for game identity, locking, and, when checkpointing, for the game state. Various OSes use different strategies for constructing the base name. Microcomputers use the character name, possibly truncated and modified to be a legal filename on that system. Multi-user systems use the (modified) character name prefixed by a user number to avoid conflicts, or "xlock" if the number of concurrent players is being limited. It may be necessary to look in the playground to find the correct base name of the interrupted game. .I recover will transform these level files into a save file of the same name as .I nethack would have used. .PP Since .I recover must be able to read and delete files from the playground and create files in the save directory, it has interesting interactions with game security. Giving ordinary players access to .I recover through setuid or setgid is tantamount to leaving the playground world-writable, with respect to both cheating and messing up other players. For a single-user system, this of course does not change anything, so some of the microcomputer ports install .I recover by default. .PP For a multi-user system, the game administrator may want to arrange for all .0 files in the playground to be fed to recover when the host machine boots, and handle game crashes individually. If the user population is sufficiently trustworthy, .I recover can be installed with the same permissions the .I nethack executable has. In either case, .I recover is easily compiled from the distribution utility directory. .SH NOTES .PP Like .I nethack itself, .I recover will overwrite existing savefiles of the same name. Savefiles created by .I recover are uncompressed; they may be compressed afterwards if desired, but even a compression-using .I nethack will find them in the uncompressed form. .SH "SEE ALSO" nethack(6) .SH BUGS .PP .I recover makes no attempt to find out if a base name specifies a game in progress. If multiple machines share a playground, this would be impossible to determine. .PP .I recover should be taught to use the nethack playground locking mechanism to avoid conflicts. nethack-3.4.3/doc/recover.txt0100644000000000000000000001020407764735041014622 0ustar rootroot RECOVER(6) 1993 RECOVER(6) NAME recover - recover a NetHack game interrupted by disaster SYNOPSIS recover [ -d directory ] base1 base2 ... DESCRIPTION Occasionally, a NetHack game will be interrupted by disaster when the game or the system crashes. Prior to NetHack v3.1, these games were lost because various information like the player's inventory was kept only in memory. Now, all per- tinent information can be written out to disk, so such games can be recovered at the point of the last level change. The base options tell recover which files to process. Each base option specifies recovery of a separate game. The -d option, which must be the first argument if it appears, supplies a directory which is the NetHack play- ground. It overrides the value from NETHACKDIR, HACKDIR, or the directory specified by the game administrator during compilation (usually /usr/games/lib/nethackdir). For recovery to be possible, nethack must have been compiled with the INSURANCE option, and the run-time option check- point must also have been on. NetHack normally writes out files for levels as the player leaves them, so they will be ready for return visits. When checkpointing, NetHack also writes out the level entered and the current game state on every level change. This naturally slows level changes down somewhat. The level file names are of the form base.nn, where nn is an internal bookkeeping number for the level. The file base.0 is used for game identity, locking, and, when checkpointing, for the game state. Various OSes use different strategies for constructing the base name. Microcomputers use the character name, possibly truncated and modified to be a legal filename on that system. Multi-user systems use the (modified) character name prefixed by a user number to avoid conflicts, or "xlock" if the number of concurrent players is being limited. It may be necessary to look in the play- ground to find the correct base name of the interrupted game. recover will transform these level files into a save file of the same name as nethack would have used. Since recover must be able to read and delete files from the playground and create files in the save directory, it has interesting interactions with game security. Giving ordi- nary players access to recover through setuid or setgid is tantamount to leaving the playground world-writable, with respect to both cheating and messing up other players. For January Last change: 9 1 RECOVER(6) 1993 RECOVER(6) a single-user system, this of course does not change any- thing, so some of the microcomputer ports install recover by default. For a multi-user system, the game administrator may want to arrange for all .0 files in the playground to be fed to recover when the host machine boots, and handle game crashes individually. If the user population is sufficiently trustworthy, recover can be installed with the same permis- sions the nethack executable has. In either case, recover is easily compiled from the distribution utility directory. NOTES Like nethack itself, recover will overwrite existing save- files of the same name. Savefiles created by recover are uncompressed; they may be compressed afterwards if desired, but even a compression-using nethack will find them in the uncompressed form. SEE ALSO nethack(6) BUGS recover makes no attempt to find out if a base name speci- fies a game in progress. If multiple machines share a play- ground, this would be impossible to determine. recover should be taught to use the nethack playground lock- ing mechanism to avoid conflicts. January Last change: 9 2 nethack-3.4.3/doc/tmac.n0100644000000000000000000006101207764735041013522 0ustar rootroot\" @(#)$Id: tmac.n,v 1.3 2000/02/02 18:49:05 dean Exp $ .\" The News macro package .\" .\" This is the macro package that is used to format news documents. It .\" was written because many sites do not have one of the -mm or -ms pack- .\" ages that the documents use. This is NOT compatible with EITHER, but .\" (I hope) will become the standard for all news documents (man pages .\" excepted, since everyone seems to have -man.) .\" .\" This package was written using only the "NROFF/TROFF Users' Guide", .\" and therefore if you can run NROFF/TROFF, you can legitimately use .\" this package. However, because NROFF/TROFF are proprietary programs, .\" I cannot place this package in the public domain. This should not .\" matter, because if you legitimately have NROFF/TROFF, you have the .\" documentation; if not, you can't run off the documentation anyway. .\" .\" This package may be circulated freely with the news documentation; it .\" may not be sold, but is to be distributed with the unformatted news .\" documents. However, the name of the author and the place at which it .\" was written (in the author's own time, of course) are not to be .\" removed from the package regardless of how it is modified or altered. .\" Further, please do not distribute this package if you make any changes .\" because I don't want to get bug reports of macros I haven't written; .\" if you have a goodie you want me to add, send it to me and we'll talk. .\" (I really do like feedback!) I'd really appreciate your cooperation. .\" .\" Author: Matt Bishop .\" Research Institute for Advanced Computer Science .\" Mail Stop 230-5 .\" NASA Ames Research Center .\" Moffett Field, CA 94035 .\" .\" version 1.0 September 28, 1985 mab@riacs.arpa .\" initial version .\" version 1.1 October 25, 1985 mab@riacs.arpa .\" fixed an incredibly obscure footnote bug (that occurred twice in .\" the news documentation!) which put footnoted words on one page .\" and the footnote on the next if the word was in the next-to-last .\" or last line; commented it, and generally cleaned up .\" Version 1.2 October 27, 1985 mab@riacs.arpa .\" Added a few more comments and a check to keep footnotes lined up .\" with the bottom margin. .\" Version 1.3 February 12, 1986 mab@riacs.arpa .\" Added an error check to catch unmatched ef's and ed's .\" Version 1.4 December 29, 1986 mab@riacs.edu .\" Changed footnote for ux, pd, and vx macros and added a string .\" for rg ("Registered Trademark") .\" Version 1.5 January 2, 1989 Matt.Bishop@dartmouth.edu .\" Minor modifications for nroff compatibility .\" Version 1.6 March 15, 1989 Matt.Bishop@dartmouth.edu .\" ..!bear.dartmouth.edu!bishop .\" Fixed a bug in footnote handling (again, sigh ...) This one .\" occurred when the the "fo" trap position was reset just beneath .\" the current line; the footnote overflow trap would kick in and .\" never be closed. .\" .\" .\" ********** .\" these preserve and restore various things .\" they are used to shorten other macros .de yf \" restore fonts .ft \\n(f2 \" previous font .ft \\n(f1 \" current font .. .de yi \" restore indents 'in \\n(i2u \" previous indent 'in \\n(i1u \" current indent .. .de ys \" restore point sizes .ps \\n(s2 \" previous point size .ps \\n(s1 \" current point size .. .de yv \" restore vertical spacings .vs \\n(v2u \" previous vertical spacing .vs \\n(v1u \" current vertical spacing .. .de ya \" restore everything .yf \" restore fonts .yi \" restore indents .ys \" restore point sizes .yv \" restore vertical spacing .. .de zf \" preserve fonts .nr f1 \\n(.f \" current font .ft \" switch to previous font .nr f2 \\n(.f \" previous font .ft \" back to current font .. .de zi \" preserve indents .nr i1 \\n(.iu \" current indent 'in \" switch to previous indent .nr i2 \\n(.iu \" previous indent 'in \" back to current indent .. .de zs \" preserve point sizes .nr s1 \\n(.su \" current point size .ps \" switch to previous point size .nr s2 \\n(.su \" previous point size .ps \" back to current point size .. .de zv \" preserve vertical spacings .nr v1 \\n(.vu \" current vertical spacing .vs \" switch to previous vertical spacing .nr v2 \\n(.vu \" previous vertical spacing .vs \" back to current vertical spacing .. .de za \" save everything .zf \" save fonts .zi \" save indents .zs \" save point sizes .zv \" save vertical spacings .. .\" ********** .\" these actually print the header and footer titles .\" they are defined separately from the "hd" and "fo" macros .\" to make user redefinition easy .de pt \" print header title . \" omit header on first page .if \\n%>1 \{\ ' sp |\\$1u \" move to proper position . ft 1 \" change to default font . ps \\n(ps \" change to default point size . vs \\n(vs \" change to default spacing . tl '\\*(h0'\\*(h1'\\*(h2' \" center title . vs \" restore current vertical spacing . ps \" restore current point size . ft \" restore current font .\} .. .de pf \" print footer title .ft 1 \" change to default font .ps \\n(ps \" change to default point size .vs \\n(vs \" change to default spacing .ie \\n%=1 .tl '\\*(h0'\\*(h1'\\*(h2' \" on first page, print the header here .el .tl '\\*(f0'\\*(f1'\\*(f2' \" on other pages, print the footer .vs \" restore current vertical spacing .ps \" restore current point size .ft \" restore current font .. .\" ********** .\" these are the top of page (header) and bottom of page (footer) macros .\" they don't actually print anything, just call the right macros .de hd \" header -- do top of page processing .if t .if \\n(cm .tl '\(rn''' \" drop cut mark if needed .pt \\n(ttu \" print header .nr fc 0 1 \" init footnote count .nr fs \\n(.pu-\\n(bmu-1u \" if any footnotes, start print here .nr fp 0-\\n(bmu \" reset current footer place .ch fo -\\n(bmu \" reset footer trap .if \\n(dn .fz \" put leftover footnotes st bottom .ya \" restore font, etc. 'sp |\\n(tmu \" move to top of body .ns \" don't allow any more space .. .de fo \" footer -- do bottom of page processing .za \" save font, etc. .rs \" you want motions here .nr dn 0 \" clobber diversion size register .if \\n(fc .fd \" now print the footnotes, if any 'bp \" force out page .. .\" ********** .\" these are the footnote macros .\" here's an overview: .\" Footnotes are processed in environment #1, which is initialized .\" at the bottom of this package. When "fn" is called, nroff/troff .\" switches to this environment. The body of the footnote is saved .\" in the diversion "tf" (for "temporary footnote"), so you will .\" NEVER spring a trap during the first reading of a footnote. When .\" "ef" ("end footnote") is called, the diversion is closed. If .\" this is the first footnote on the page (ie, the number register .\" "fc" is 1), and the footnote height (plus the height of 1 line) .\" crosses the bottom margin, you get the footnoted word on one .\" page and the footnote on the other. In this case we just call .\" "fo" manually (taking case it cannot be re-invoked on the same .\" page!) If this situation does not occur, we just adjust the .\" footer trap's position upwards (we'll get to how far in a min- .\" ute); if this puts the trap above the current line, we reposi- .\" tion the trap just beneath the current line to be sure of trig- .\" triggering it once the current line is forced out. .\" To reposition the footer trap, we proceed as follows. Because .\" the trap may be sprung in the middle of a line, it is possible .\" that the footnote will not fit on the page (regardless of where .\" on the page the footnoted word occurs -- really!) if we move the .\" trap up by the size of the footnote diversion "tf". So, we .\" fudge things a little bit -- for the first footnote on each page .\" we move the footer trap up 1 extra line ("line" being 1v in env- .\" ironment #0). Unless the point size and vertical spacing are .\" increased between the first footnote and the footer trap's being .\" sprung, this will keep the footnotes on the same page as the .\" footnoted word. But as there may be now as much as 1v of space .\" between the footnote and the bottom margin, which looks HIDEOUS, .\" we use the number register "fs" to mark where the footer trap .\" would REALLY go, and just space to it when it comes time to put .\" out the footnotes. .de fd \" dump footnotes .nr gs 1v \" get a measure of 1 line in env #0 .ev 1 \" switch to footnote environment .nr gs +2v \" min of 2 lines of footnotes . \" if the number register ns > 0, . \" the last text line may contain a . \" footnote that is too big to fit; . \" this checks for such a note and . \" if so, forces the footnote into . \" the "fy" diversion that carries . \" it onto the next text page .ie (\\n(nsu>0)&(\\n(gsu>=\\n(.tu) 'sp \\n(gsu \" be sure you can get it down .el .if \\n(fsu>\\n(nlu 'sp \\n(fsu-\\n(nlu \" move to footnote start position 'nf \" don't reprocess footnotes 'in 0 \" don't indent them any more either .tf \" drop text of footnotes .rm tf .if '\\n(.z'fy' .di \" end overflow diversion, if any .nr fc 0 \" re-init footnote count .ev \" return to usual environment .. .de fn \" start footnote . \" look for nested footnotes -- ILLEGAL .ie \\n(if>0 .er "footnote within footnote" .el .da tf \" append footnote to footnote diversion .nr if +1 \" increment level of footnoting .nr fc +1 \" one more footnote on this page .if \\n(fc=1 .nr fp -1v \" The reason for this "fudge factor" . \" is that there is no way to force . \" NROFF/TROFF to invoke a macro at . \" the end of each line. At times, . \" the trap boundary will not match up . \" with the bottom of a line, so the . \" "fo" trap which is set at 2320 may . \" not be triggered until 2340 -- and . \" then the footnote won't fit. This . \" gives some slack so the footnote is . \" more likely to fit. *sigh* .ev 1 \" enter footnote environment .if \\n(fc=1 .fs \" drop separator if first footnote .br \" flush out any previous line in footnote .fi \" process footnote in fill mode .. .de ef \" end footnote .br \" flush out the line in footnote .ie \\n(if<=0 .er "end footnote has no corresponding begin footnote" .el \{\ . nr if -1 \" decrement level of footnoting . nr fg 2v \" remember this for repositioning fo . ev \" back to usual environment . if \\n(if=0 \{\ . di \" end of footnote proper . nr fp -\\n(dnu \" "fo" will be moved at least up this far . nr fs -\\n(dnu \" increase size of footnote . ch fo \\n(fpu \" reposition "fo" trap (first guess) . \" the first part of the "ie" clause . \" is taken in the special case . \" described above . ie (\\n(fc=1)&((\\n(nlu+1v+\\n(fgu)>=(\\n(.pu-\\n(bmu)) \{\ . nr ns \\n(dnu \" suppress footnote separator . \" since this footnote contains it . \" keep "fo" from being invoked twice . ch fo \\n(.pu+1i . fo \" force the page out AT ONCE . nr ns 0 \" re-enable footnote separator . \} . \" footnote won't fit completely . \" invoke the footer trap but . \" don't worry about the footnote . \" separator (it's already there) . el .if (\\n(nlu+1v)>=(\\n(.pu+\\n(fpu) \{\ . \" as before we must reposition the . \" "fo" trap to prevent "fo" from . \" being invoked twice . ch fo \\n(.pu+1i . fo \" force the page out AT ONCE . \} . \} .\} .. .de fs \" drop footnote separator . \" only if not already dropped .if \\n(ns=0 \l'1i' .nr ns 0 \" in case footnotes are over 1 page long .. .de fx \" process footnote overflow .if \\n(fc .di fy \" stuff them in the right place .. .de fz \" deposit footnote overflow .fn \" treat it as a footnote .nf \" it's already been processed .in 0 \" and indented .fy \" "fx" put it here .ef \" end the footnote .. .\" ********** .\" the ones after here are user-invoked (like "fn" and "ef" above) .\" title, author, etc. .de mt \" main title \& .sp |\\n(mtu \" space .ft 3 \" in bold .ps \\n(ps+2p \" large point size and .vs \\n(vs+2p \" vertical spacing .ce 1000 \" center the title .nr t2 1 \" space it .. .de au \" author .nr t2 0 \" spacing here .sp 2v \" space .ft 2 \" in italics .ps \\n(ps \" usual point size and .vs \\n(vs \" vertical spacing .ce 1000 \" center the name(s) .. .de ai \" author's institution .if \\n(t2 .sp 2v \" space after a title .nr t2 0 \" institution .ft 2 \" in italics .ps \\n(ps \" usual point size and .vs \\n(vs \" vertical spacing .ce 1000 \" center the name(s) .. .de bt \" begin text macro .nr t2 0 \" hold it here .nr it +1 \" mark as called .ce 0 \" end any centering .sn 3v \" a little bit of space .. .\" paragraph .de si \" start indented section .nr lo \\n(lm \" remember the current level .nr lm +1 \" go to the next level .ie '\\$1'' .nr l\\n(lm \\n(l\\n(lo+5n \" if no arg, indent 5n .el .nr l\\n(lm \\$1n \" otherwise, indent that much .. .de ei \" end indent .nr lm -1 \" down one level .if \\n(lm<0 .nr lm 0 \" make sure you don't go too far .. .de pg \" plain old paragraph .if !\\n(it .bt \" end the title and such .sn \\n(pdu \" inter-paragraph spacing .ft 1 \" reset a few things (paranoia) . \" these ONLY if not in footnote .ie \\n(if=0 \{\ . ps \\n(ps \" reset point size . vs \\n(vs \" reset vertical spacing . ne 1v+\\n(.Vu \" slightly more than 1 line .\} .el \{\ . ps \\n(ps-2p \" reset point size . vs \\n(vs-2p \" reset vertical spacing .\} .in \\n(l\\n(lmu \" stop any indenting .ce 0 \" stop any centering .if !'\\$1'L' .if !'\\$1'l' .ti +\\n(piu \" indent the sucker .. .de lp \" labelled paragraph .pg l \" reset paragraph .if \\n(.$>1 .nr li \\$2n \" if indent given use it .in +\\n(liu \" indent for paragraph .ti -\\n(liu \" force first line NOT to indent .ta +\\n(liu \" for the label \&\\$1\t\c .if \\w'\\$1'u>=(\\n(l\\n(lmu+\\n(liu) .br \" don't overwrite .. .\" The following two macros (hu & hn) have been modified for ELM usage. .\" If the macros have text as part of the macro call, the text will be .\" increased in size by two points. After printing the text, the font .\" will be returned to normal, otherwise the font will be left bold. .\" .\" section .de hu \" header, unnumbered . \" format: .hu [text] .if !\\n(it .bt \" end the title and such .br \" force out previous line .b .ie \\n(hP .ps \\n(hP .el .ps \\n(ps .ie \\n(hv .vs \\n(hv .el .vs \\n(vs .in \\n(l\\n(lmu \" stop any indenting .sn \\n(hsu \" inter-section spacing .ne 3v+\\n(.Vu \" slightly more than 3 lines .fi \" process the text, too .if \\n(.$>=1 \{\ .ps +2 \\$1 .\} .if \\n(.$>=2 \\$2 .if \\n(.$>=3 \\$3 .if \\n(.$>=4 \\$4 .if \\n(.$>=5 \\$5 .if \\n(.$>=6 \\$6 .if \\n(.$>=7 \\$7 .if \\n(.$>=8 \\$8 .if \\n(.$=9 \\$9 .if \\n(.$>=1 \{\ .ps -2 .br .ft 1 .\} .. .de hn \" header, numbered . \" format: .hn [level] [text] .if !\\n(it .bt \" end the title and such .br \" force out previous line .b .ie \\n(hP .ps \\n(hP .el .ps \\n(ps .ie \\n(hv .vs \\n(hv .el .vs \\n(vs .in \\n(l\\n(lmu \" stop any indenting .sn \\n(hsu \" inter-section spacing .ne 3v+\\n(.Vu \" slightly more than 3 lines .fi \" process the text, too .ie !'\\$1'' .nr hn \\$1 .el .nr hn 1 .ie \\n(hn>0 .nr hn -1 .el .nr hn 0 .ie \\n(hn=0 \{\ . nr h0 +1 \" add 1 to main section header . nr h1 0 \" zap remaining section numbers . nr h2 0 \" zap remaining section numbers . nr h3 0 \" zap remaining section numbers .ie \\n(.$>=2 \{\ .ps +2 \\n(h0. .ps -2 .\} .el \\n(h0. .\} .el .ie \\n(hn=1 \{\ . nr h1 +1 \" add 1 to the section header . nr h2 0 \" zap remaining section numbers . nr h3 0 \" zap remaining section numbers .ie \\n(.$>=2 \{\ .ps +2 \\n(h0.\\n(h1. .ps -2 .\} .el \\n(h0.\\n(h1. .\} .el .ie \\n(hn=2 \{\ . nr h2 +1 \" add 1 to the section header . nr h3 0 \" zap remaining section numbers .ie \\n(.$>=2 \{\ .ps +2 \\n(h0.\\n(h1.\\n(h2. .ps -2 .\} .el \\n(h0.\\n(h1.\\n(h2. .\} .el \{\ . nr h3 +1 \" add 1 to the section number .ie \\n(.$>=2 \{\ .ps +2 \\n(h0.\\n(h1.\\n(h2.\\n(h3. .ps -2 .\} .el \\n(h0.\\n(h1.\\n(h2.\\n(h3. .\} .if \\n(.$>=2 \{\ .ps +2 \\$2 .\} .if \\n(.$>=3 \\$3 .if \\n(.$>=4 \\$4 .if \\n(.$>=5 \\$5 .if \\n(.$>=6 \\$6 .if \\n(.$>=7 \\$7 .if \\n(.$>=8 \\$8 .if \\n(.$>=9 \\$9 .if \\n(.$>=2 \{\ .br .ft 1 .ps -2 .\} .. .\" displays (no floats, thank God!) .de sd \" start display . \" look for nested displays -- ILLEGAL .ie \\n(id>0 .er "display within display" .el \{\ . ie '\\$1'c' .nr sf 1 \" center the sucker . el .nr sf 0 \" don't center it .\} .sn \\n(pdu \" a little bit of space .ev 2 \" switch to display environment .nf \" what you type is what you get .if \\n(id=0 .di dd \" start saving text .rs \" don't eat leading space .nr id +1 \" increment level of display .. .de ed \" end display .br \" flush line .ie \\n(id<=0 .er "end display has no corresponding begin display" .el \{\ . nr id -1 \" decrement level of display . if \\n(id=0 \{\ . di \" end diversion . fi \" resume filling . in -\\n(piu \" dedent . ev \" pop environment . ne \\n(dnu \" be sure you have room . nf \" don't reprocess display . rs \" don't eat leading space . zi \" save indents . ie \\n(sf .in (\\n(llu-\\n(dlu)/2u \" center on the line length . el .in +\\n(piu \" indent the sucker . dd \" drop display . yi \" restore indents . \} .\} .fi \" resume filling .sn \\n(pdu \" a little bit of space .. .\" ********** .\" fonts -- if argument(s), apply only to first .de b \" bold (font 3) .ie \\n(.$>0 \\&\\$3\\f3\\$1\\fP\\$2 .el .ft 3 .. .de i \" italics (font 2) .ie \\n(.$>0 \\&\\$3\\f2\\$1\\fP\\$2 .el .ft 2 .. .de r \" roman (font 1) .ft 1 \" just restore it .. .de bi \" bold italics (embolden font 2) \\&\\$3\c \\kb\\f2\\$1\\fP\\h'|\\nbu+2u'\\f2\\$1\\fP\\$2 .. .\" ********** .\" point sizes -- if argument(s), apply only to first .de sm \" reduce point size by 2 .ie \\n(.$>0 \\&\\$3\\s-2\\$1\\s0\\$2 .el .ps -2 .. .de is \" increase point size by 2 .ie \\n(.$>0 \\&\\$3\\s+2\\$1\\s0\\$2 .el .ps +2 .. .de nl \" return to normal size .ps \\n(ps \" just reset the point size .. .\" ********** .\" handy force space/inhibit more space macros .de sn \" space, then turn on nospace mode .sp \\$1 \" space .ns \" ignore any more space requests .. .de sr \" force out space .rs \" turn on spacing mode .sp \\$1 \" space .. .\" ********** .\" end of text and error macros .de et \" end of text macro . \" this: (1) flushes rest of line . \" (2) trips the footer, taking . \" care of footnotes .sp \\n(.pu . \" check for open displays or footnotes .if \\n(id>0 .er "unfinished display" .if \\n(if>0 .er "unfinished footnote" . \" this one means an -mn bug (*sigh*) .if !'\\n(.z'' .er "diversion \\n(.z not closed" .. .de er \" print error message . \" flag it as an error .ds ws "** ERROR ** . \" if you have it, give the file name .if !'\\*(.f'' .as ws " file \\*(.f, . \" put out the line number .as ws " line \\n(.c . \" and finally the error message .tm \\*(ws: \\$1 .. .\" ********** .\" macros in this section are VERY specific to the news documentation .de pa \" protocol appellation (darn names!) \\&\\$3\\f2\\$1\\fP\\$2 .. .de ng \" news group name \\&\\$3\\f3\\$1\\fP\\$2 .. .de cn \" computer name \\&\\$3\\f2\\$1\\fP\\$2 .. .de hf \" header field \\&\\$3\\*(lq\\$1\\*(rq\\$2 .. .de cf \" contents of field \\&\\$3\\*(lq\\$1\\*(rq\\$2 .. .de qc \" quote control char (command) \\&\\$3\\f3<\\s-2\\$1\\s0>\\fP\\$2 .. .de qp \" quote printing char (command) \\&\\$3\\f3\\$1\\fP\\$2 .. .de op \" option \\&\\$3\\f3\\$1\\fP\\$2 .. .\" ********** .\" trademarked names .de pd \" print "PDP-11" .ie \\n(p1 \\&\\$2\\s-1PDP\\s0-11\\$1 .el \{\ . nr p1 +1 \" mark footnote as dropped \\&\\$2\\s-1PDP\\s0-11\\*(rg\\$1 . fn \" put out the footnote \\&\\*(rgPDP-11 is a registered trademark of Digital Equipment Corporation. . ef \" short and sweet ... .\} .. .de ux \" print "UNIX" .ie \\n(ux \\&\\$2\\s-1UNIX\\s0\\$1 .el \{\ . nr ux +1 \" mark footnote as dropped \\&\\$2\\s-1UNIX\\s0\\*(rg\\$1 . fn \" put out the footnote \\&\\*(rgUNIX is a registered trademark of AT&T. . ef \" short and sweet ... .\} .. .de vx \" print "VAX" .ie \\n(vx \\&\\$2\\s-1VAX\\s0\\$1 .el \{\ . nr vx +1 \" mark footnote as dropped \\&\\$2\\s-1VAX\\s0\\*(rg\\$1 . fn \" put out the footnote \\&\\*(rgVAX is a trademark of Digital Equipment Corporation. . ef \" short and sweet ... .\} .. .\" ********** .\" set up string and number registers . \" set up for the date .if \n(mo=1 .ds mo January .if \n(mo=2 .ds mo February .if \n(mo=3 .ds mo March .if \n(mo=4 .ds mo April .if \n(mo=5 .ds mo May .if \n(mo=6 .ds mo June .if \n(mo=7 .ds mo July .if \n(mo=8 .ds mo August .if \n(mo=9 .ds mo September .if \n(mo=10 .ds mo October .if \n(mo=11 .ds mo November .if \n(mo=12 .ds mo December .nr Yr \n(yr+1900 .ds dy "\*(mo \n(dy, \n(Yr .if \n(dw=1 .ds dw Sunday .if \n(dw=2 .ds dw Monday .if \n(dw=3 .ds dw Tuesday .if \n(dw=4 .ds dw Wednesday .if \n(dw=5 .ds dw Thursday .if \n(dw=6 .ds dw Friday .if \n(dw=7 .ds dw Saturday . \" NROFF dependencies .if n \{\ . \" string registers . ds rg (R) . ds lq "" . ds rq "" . ds f1 "\*(dy . \" number registers . nr hs 1v \" space before section header . nr pd 1v \" inter-paragraph spacing . nr bm 1.0i \" height of bottom margin .\} . \" NROFF dependencies .if t \{\ . \" string registers . ds rg \\u\\s-2\\(rg\\s0\\d . ds lq `` . ds rq '' . \" number registers . nr hs 1v \" space before section header . nr pd 0.3v \" inter-paragraph spacing . nr bm 1.0i+1v \" height of bottom margin (wacky laser) .\} . \" these are the same for [NT]ROFF .ds dg \(dg .ds vr "News Version B2.11 .ds pv "News macros 1.5 .ds h1 - % - .nr bt 0.5i+1v \" bottom of page to footer .nr cm 0 \" no cut marks .nr fc 0 1 \" init footnote count .nr fl 5.5i \" footnote line length .nr fp 0-\n(bmu \" fo macro trap location .nr h0 0 \" init section header level 0 .nr h1 0 \" init section header level 1 .nr h2 0 \" init section header level 2 .nr h3 0 \" init section header level 3 .nr id 0 \" 1 in display .nr if 0 \" 1 in keep .nr it 0 \" 1 when beyond title, etc. .nr li 5n \" indent for labelled paragraph .nr ll 6.5i \" line length .nr lm 0 \" left margin .nr l0 0 \" first indent level .nr mt 1.5i+1v \" title goes down this far .nr pi 5n \" regular paragraph indent .nr po 1.0i \" page offset .nr ps 10 \" point size .nr tm 1.0i \" height of top margin .nr tt 0.5i-0.5v \" top of page to header .nr p1 0 \" no PDP-TM message yet .nr ux 0 \" no UNIX-TM message yet .nr vx 0 \" no VAX-TM message yet .nr vs 12 \" vertical spacing .\" set things up .\" DSINC changes for XROFF .nr f1 1 .nr f2 1 .nr s1 10 .nr s2 10 .nr v1 12 .nr v2 12 .ps 10 .vs 12 .\" DSINC end changes for XROFF .po \n(pou \" set page offset .ps \n(ps \" set previous, current .ps \n(ps \" point sizes .vs \n(vs \" set previous, current .vs \n(vs \" vertical spacings .ll \n(llu \" set line length .lt \n(llu \" set title line length .ev 1 \" *** footnote environment .ps \n(ps-2p \" set previous, current .ps \n(ps-2p \" point sizes .vs \n(vs-2p \" set previous, current .vs \n(vs-2p \" vertical spacings .ll \n(flu \" set line length .lt \n(flu \" set title line length .ev \" *** pop environment .ev 2 \" *** footnote environment .ps \n(ps \" set previous, current .ps \n(ps \" point sizes .vs \n(vs \" set previous, current .vs \n(vs \" vertical spacings .ll \n(llu \" set line length .lt \n(llu \" set title line length .ev \" *** pop environment .\" now set internal registers (for the first header section) .nr f1 \n(.f \" saved font #1 .nr f2 \n(.f \" saved font #2 .nr s1 \n(.s \" saved point size #1 .nr s2 \n(.s \" saved point size #2 .nr v1 \n(.v \" saved vertical spacing #1 .nr v2 \n(.v \" saved vertical spacing #2 .\" install traps .wh 0i hd \" position header trap .wh -\n(bmu fo \" position footer trap .wh \n(.pu+1i fx \" put footnote overflow trap here .ch fx -\n(bmu \" move it over fo .wh -\n(btu pf \" print the bottom margin here .em et \" at end of file, call et .\" couple of miscellaneous requests .bd S 3 3 \" embolden special font chars if B .hy 2 \" don't hyphenate last lines nethack-3.4.3/doc/window.doc0100644000000000000000000011537507764735041014431 0ustar rootrootIntroduction This file documents the support for various windowing systems in NetHack. The support is through a standard interface, separating the main NetHack code from window-system specific code. The implementation supports multiple window systems in the same binary. Even if you only wish to support one window-port on your port, you will need to follow the instructions in Section IX to get a compilable binary. Contents: I. Window Types and Terminology II. Interface Specification III. Global variables IV. WINCAP preferences support V. New or respecified common, high level routines VI. Helper routines VII. Game startup VIII. Conventions IX. Implementation and Multi-window support I. Window Types and Terminology There are 5 basic window types, used to call create_nhwindow(): NHW_MESSAGE (top line) NHW_STATUS (bottom lines) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) The tty window-port also uses NHW_BASE (the base display) internally. NHW_MENU windows can be used for either menu or text display. Their basic feature is that for the tty-port, if the window is small enough, it appears in the corner of the tty display instead of overwriting the whole screen. The first call to add information to the window will decide if it is going to be used to display a menu or text. If start_menu() is called, then it will be used as a menu. If putstr() is called, it will be used as text. Once decided, there is no turning back. For the tty-port, if the data is too large for a single screen then the data is paged (with --more--) between pages. Only NHW_MENU type windows can be used for menus. NHW_TEXT windows are used to display a large amount of textual data. This is the type of window one would use for displaying a help file, for example. In the tty window-port, windows of type NHW_TEXT can page using the DEF_PAGER, if DEF_PAGER is defined. There exists an assumption that the font for text windows is monospaced. The help files are all formatted accordingly. "window" is always of type winid. This is currently implemented as an integer, but doesn't necessarily have to be done that way. There are a few fixed window names that are known throughout the code: WIN_MESSAGE (top line) WIN_STATUS (bottom lines) WIN_MAP (main dungeon) WIN_INVEN (inventory) Other windows are created and destroyed as needed. "Port" in this document refers to a CPU/OS/hardware platform (UNIX, MSDOS TOS, etc.) "window-port" refers to the windowing platform. This is orthogonal (e.g. UNIX might use either a tty window-port or an X11 window-port). II. Interface Specification All functions below are void unless otherwise noted. A. Low-level routines: raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. It need not recognize ASCII control characters. This is used during startup (before windowing system initialization -- maybe this means only error startup messages are raw), for error messages, and maybe other "msg" uses. E.g. updating status for micros (i.e, "saving"). raw_print_bold(str) -- Like raw_print(), but prints in bold/standout (if possible). curs(window, x, y) -- Next output to window will start at (x,y), also moves displayable cursor to (x,y). For backward compatibility, 1 <= x < cols, 0 <= y < rows, where cols and rows are the size of window. -- For variable sized windows, like the status window, the behavior when curs() is called outside the window's limits is unspecified. The mac port wraps to 0, with the status window being 2 lines high and 80 columns wide. -- Still used by curs_on_u(), status updates, screen locating (identify, teleport). -- NHW_MESSAGE, NHW_MENU and NHW_TEXT windows do not currently support curs in the tty window-port. putstr(window, attr, str) -- Print str on the window with the given attribute. Only printable ASCII characters (040-0126) must be supported. Multiple putstr()s are output on separate lines. Attributes can be one of ATR_NONE (or 0) ATR_ULINE ATR_BOLD ATR_BLINK ATR_INVERSE If a window-port does not support all of these, it may map unsupported attributes to a supported one (e.g. map them all to ATR_INVERSE). putstr() may compress spaces out of str, break str, or truncate str, if necessary for the display. Where putstr() breaks a line, it has to clear to end-of-line. -- putstr should be implemented such that if two putstr()s are done consecutively the user will see the first and then the second. In the tty port, pline() achieves this by calling more() or displaying both on the same line. get_nh_event() -- Does window event processing (e.g. exposure events). A noop for the tty and X window-ports. int nhgetch() -- Returns a single character input from the user. -- In the tty window-port, nhgetch() assumes that tgetch() will be the routine the OS provides to read a character. Returned character _must_ be non-zero and it must be non meta-zero too (zero with the meta-bit set). int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of CLICK_1 /* mouse click type 1 */ CLICK_2 /* mouse click type 2 */ The different click types can map to whatever the hardware supports. If no mouse is supported, this routine always returns a non-zero character. B. High-level routines: print_glyph(window, x, y, glyph) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in choices or default. If choices is NULL, all possible inputs are accepted and returned. This overrides everything else. The choices are expected to be in lower case. Entering ESC always maps to 'q', or 'n', in that order, if present in choices, otherwise it maps to default. Entering any other quit character (SPACE, RETURN, NEWLINE) maps to default. -- If the choices string contains ESC, then anything after it is an acceptable response, but the ESC and whatever follows is not included in the prompt. -- If the choices string contains a '#' then accept a count. Place this value in the global "yn_number" and return '#'. -- This uses the top line in the tty window-port, other ports might use a popup. -- If choices is NULL, all possible inputs are accepted and returned, preserving case (upper or lower.) This means that if the calling function needs an exact match, it must handle user input correctness itself. getlin(const char *ques, char *input) -- Prints ques as a prompt and reads a single line of text, up to a newline. The string entered is returned without the newline. ESC is used to cancel, in which case the string "\033\000" is returned. -- getlin() must call flush_screen(1) before doing anything. -- This uses the top line in the tty window-port, other ports might use a popup. -- getlin() can assume the input buffer is at least BUFSZ bytes in size and must truncate inputs to fit, including the nul character. int get_ext_cmd(void) -- Get an extended command in a window-port specific way. An index into extcmdlist[] is returned on a successful selection, -1 otherwise. player_selection() -- Do a window-port specific player type selection. If player_selection() offers a Quit option, it is its responsibility to clean up and terminate the process. You need to fill in pl_character[0]. display_file(str, boolean complain) -- Display the file named str. Complain about missing files iff complain is TRUE. update_inventory() -- Indicate to the window port that the inventory has been changed. -- Merely calls display_inventory() for window-ports that leave the window up, otherwise empty. doprev_message() -- Display previous messages. Used by the ^P command. -- On the tty-port this scrolls WIN_MESSAGE back one line. update_positionbar(char *features) -- Optional, POSITIONBAR must be defined. Provide some additional information for use in a horizontal position bar (most useful on clipped displays). Features is a series of char pairs. The first char in the pair is a symbol and the second char is the column where it is currently located. A '<' is used to mark an upstairs, a '>' for a downstairs, and an '@' for the current player location. A zero char marks the end of the list. C. Window Utility Routines init_nhwindows(int* argcp, char** argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. -- Any commandline arguments relevant to the windowport should be interpreted, and *argcp and *argv should be changed to remove those arguments. -- When the message window is created, the variable iflags.window_inited needs to be set to TRUE. Otherwise all plines() will be done via raw_print(). ** Why not have init_nhwindows() create all of the "standard" ** windows? Or at least all but WIN_INFO? -dean exit_nhwindows(str) -- Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. window = create_nhwindow(type) -- Create a window of type "type." clear_nhwindow(window) -- Clear the given window, when appropriate. display_nhwindow(window, boolean blocking) -- Display the window on the screen. If there is data pending for output in that window, it should be sent. If blocking is TRUE, display_nhwindow() will not return until the data has been displayed on the screen, and acknowledged by the user where appropriate. -- All calls are blocking in the tty window-port. -- Calling display_nhwindow(WIN_MESSAGE,???) will do a --more--, if necessary, in the tty window-port. destroy_nhwindow(window) -- Destroy will dismiss the window if the window has not already been dismissed. start_menu(window) -- Start using window as a menu. You must call start_menu() before add_menu(). After calling start_menu() you may not putstr() to the window. Only windows of type NHW_MENU may be used for menus. add_menu(windid window, int glyph, const anything identifier, char accelerator, char groupacc, int attr, char *str, boolean preselected) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable item is 0, the window system is free to select its own accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). Glyph is an optional glyph to accompany the line. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z], but there are a few exceptions such as the tty player selection code which uses '*'. -- It is expected that callers do not mix accelerator choices. Either all selectable items have an accelerator or let the window system pick them. Don't do both. -- Groupacc is a group accelerator. It may be any character outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with the menu command (or their user defined alises), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the menu is displayed, set preselected to TRUE. end_menu(window, prompt) -- Stop adding entries to the menu and flushes the window to the screen (brings to front?). Prompt is a prompt to give the user. If prompt is NULL, no prompt will be printed. ** This probably shouldn't flush the window any more (if ** it ever did). That should be select_menu's job. -dean int select_menu(windid window, int how, menu_item **selected) -- Return the number of items selected; 0 if none were chosen, -1 when explicitly cancelled. If items were selected, then selected is filled in with an allocated array of menu_item structures, one for each selected line. The caller must free this array when done with it. The "count" field of selected is a user supplied count. If the user did not supply a count, then the count field is filled with -1 (meaning all). A count of zero is equivalent to not being selected and should not be in the list. If no items were selected, then selected is NULL'ed out. How is the mode of the menu. Three valid values are PICK_NONE, PICK_ONE, and PICK_ANY, meaning: nothing is selectable, only one thing is selectable, and any number valid items may selected. If how is PICK_NONE, this function should never return anything but 0 or -1. -- You may call select_menu() on a window multiple times -- the menu is saved until start_menu() or destroy_nhwindow() is called on the window. -- Note that NHW_MENU windows need not have select_menu() called for them. There is no way of knowing whether select_menu() will be called for the window at create_nhwindow() time. char message_menu(char let, int how, const char *mesg) -- tty-specific hack to allow single line context-sensitive help to behave compatibly with multi-line help menus. -- This should only be called when a prompt is active; it sends `mesg' to the message window. For tty, it forces a --More-- prompt and enables `let' as a viable keystroke for dismissing that prompt, so that the original prompt can be answered from the message line "help menu". -- Return value is either `let', '\0' (no selection was made), or '\033' (explicit cancellation was requested). -- Interfaces which issue prompts and messages to separate windows typically won't need this functionality, so can substitute genl_message_menu (windows.c) instead. D. Misc. Routines make_sound(???) -- To be determined later. THIS IS CURRENTLY UN-IMPLEMENTED. nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] mark_synch() -- Don't go beyond this point in I/O on any channel until all channels are caught up to here. Can be an empty call for the moment wait_synch() -- Wait until all pending output is complete (*flush*() for streams goes here). -- May also deal with exposure events etc. so that the display is OK when return from wait_synch(). delay_output() -- Causes a visible delay of 50ms in the output. Conceptually, this is similar to wait_synch() followed by a nap(50ms), but allows asynchronous operation. askname() -- Ask the user for a player name. cliparound(x, y)-- Make sure that the user is more-or-less centered on the screen if the playing area is larger than the screen. -- This function is only defined if CLIPPING is defined. number_pad(state) -- Initialize the number pad to the given state. suspend_nhwindows(str) -- Prepare the window to be suspended. resume_nhwindows() -- Restore the windows after being suspended. start_screen() -- Only used on Unix tty ports, but must be declared for completeness. Sets up the tty to work in full-screen graphics mode. Look at win/tty/termcap.c for an example. If your window-port does not need this function just declare an empty function. end_screen() -- Only used on Unix tty ports, but must be declared for completeness. The complement of start_screen(). outrip(winid, int) -- The tombstone code. If you want the traditional code use genl_outrip for the value and check the #if in rip.c. preference_update(preference) -- The player has just changed one of the wincap preference settings, and the NetHack core is notifying your window port of that change. If your window-port is capable of dynamically adjusting to the change then it should do so. Your window-port will only be notified of a particular change if it indicated that it wants to be by setting the corresponding bit in the wincap mask. III. Global variables The following global variables are defined in decl.c and must be used by the window interface to the rest of NetHack. char toplines[BUFSZ] Contains the last message printed to the WIN_MESSAGE window, used by Norep(). winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN The four standard windows. char *AE, *AS; Checked in options.c to see if we should switch to DEC_GRAPHICS. It is #ifdefed VMS and UNIX. int LI, CO; Set in sys/unix/ioctl.c. The following appears to be Unix specific. Other ports using the tty window-port should also declare this variable in one of your sys/*.c files. short ospeed; Set and declared in sys/unix/unixtty.c (don't know about other sys files). The following global variable is defined in options.c. It equates a list of wincap option names with their associated bit-mask [see section IV WINCAP preferences support]. The array is zero-terminated. struct wc_Opt wc_options[]; One entry for each available WINCAP option. Each entry has a wc_name field and a wc_bit field. IV. WINCAP preferences support Starting with NetHack 3.4.0, the window interface was enhanced to provide a common way of setting window port user preferences from the config file, and from the command line for some settings. The wincap preference settings all have their underlying values stored in iflags fields. The names of the wincap related fields are all pre- fixed with wc_ or wc2_ to make it easy to identify them. Your window port can access the fields directly. Your window port identifies what options it will react to and support by setting bits in the window_procs wincap mask and/or wincap2 mask. See section IX for details of where the wincap masks reside. Two things control whether any preference setting appears in the 'O' command options menu during the game: 1. The option must be marked as being supported by having its bit set in the window_procs wincap or wincap2 mask. 2. The option must have its optflag field set to SET_IN_GAME in order to be able to set the option, or marked DISP_IN_GAME if you just want to reveal what the option is set to. Both conditions must be true to be able to see or set the option from within NetHack. The default values for the optflag field for all the options are hard-coded into the option in options.c. The default value for the wc_ options can be altered by calling set_wc_option_mod_status(optmask, status) The default value for the wc2_ options can be altered by calling set_wc2_option_mod_status(optmask, status) In each case, set the option modification status to one of SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME. The setting of any wincap or wincap2 option is handled by the NetHack core option processing code. You do not have to provide a parser in your window port, nor should you set the values for the iflags.wc_* and iflags.wc2_* fields directly within the port code. The port code should honor whatever values were put there by the core when processing options, either in the config file, or by the 'O' command. You may be wondering what values your window port will find in the iflags.wc_* and iflags.wc2_* fields for options that the user has not specified in his/her config file. Put another way, how does you port code tell if an option has not been set? The next paragraph explains that. If the core does not set an option, it will still be initialized to its default value. Those default values for the iflags.wc_* and iflags.wc_* fields are: o All boolean fields are initialized to the starting value specified for that option in the boolopt array in options.c. The window-port should respect that setting unless it has a very good reason for not doing so. o All int fields are initialized to zero. Zero is not a valid setting for any of the int options, so if your port code encounters a zero there, it can assume that the preference option was not specified. In that case, the window-port code should use a default setting that the port is comfortable with. It should write the default setting back into the iflags.wc_* field. That is the only time that your window-port could should update those fields. o All "char *" fields will be null pointers. Be sure to check for that in your window-port code before using such a pointer, or you'll end up triggering a nasty fault. Here are the wincap and wincap2 preference settings that your port can choose to support: wincap +--------------------+--------------------+--------------------+--------+ | | | iflags field | data | | player option | bit in wincap mask | for value | type | |--------------------+--------------------+--------------------+--------+ | align_message | WC_ALIGN_MESSAGE | wc_align_message |int | | align_status | WC_ALIGN_STATUS | wc_align_status |int | | ascii_map | WC_ASCII_MAP | wc_ascii_map |boolean | | color | WC_COLOR | wc_color |boolean | | eight_bit_tty | WC_EIGHT_BIT_IN | wc_eight_bit_input |boolean | | font_map | WC_FONT_MAP | wc_font_map |char * | | font_menu | WC_FONT_MENU | wc_font_menu |char * | | font_message | WC_FONT_MESSAGE | wc_font_message |char * | | font_status | WC_FONT_STATUS | wc_font_status |char * | | font_text | WC_FONT_TEXT | wc_font_text |char * | | font_size_map | WC_FONTSIZ_MAP | wc_fontsiz_map |int | | font_size_menu | WC_FONTSIZ_MENU | wc_fontsiz_menu |int | | font_size_message | WC_FONTSIZ_MESSAGE | wc_fontsiz_message |int | | font_size_status | WC_FONTSIZ_STATUS | wc_fontsiz_status |int | | font_size_text | WC_FONTSIZ_TEXT | wc_fontsiz_text |int | | hilite_pet | WC_HILITE_PET | wc_hilite_pet |boolean | | map_mode | WC_MAP_MODE | wc_map_mode |int | | player_selection | WC_PLAYER_SELECTION| wc_player_selection|int | | popup_dialog | WC_POPUP_DIALOG | wc_popup_dialog |boolean | | preload_tiles | WC_PRELOAD_TILES | wc_preload_tiles |boolean | | scroll_amount | WC_SCROLL_AMOUNT | wc_scroll_amount |int | | scroll_margin | WC_SCROLL_MARGIN | wc_scroll_margin |int | | splash_screen | WC_SPLASH_SCREEN | wc_splash_screen |boolean | | tiled_map | WC_TILED_MAP | wc_tiled_map |boolean | | tile_width | WC_TILE_WIDTH | wc_tile_width |int | | tile_height | WC_TILE_HEIGHT | wc_tile_height |int | | tile_file | WC_TILE_FILE | wc_tile_file |char * | | use_inverse | WC_INVERSE | wc_inverse |boolean | | vary_msgcount | WC_VARY_MSGCOUNT | wc_vary_msgcount |int | | windowcolors | WC_WINDOWCOLORS | wc_foregrnd_menu |char * | | | | wc_backgrnd_menu |char * | | | | wc_foregrnd_message|char * | | | | wc_backgrnd_message|char * | | | | wc_foregrnd_status |char * | | | | wc_backgrnd_status |char * | | | | wc_foregrnd_text |char * | | | | wc_backgrnd_text |char * | | mouse | WC_MOUSE_SUPPORT | wc_mouse_support |boolean | +--------------------+--------------------+--------------------+--------+ wincap2 +--------------------+--------------------+--------------------+--------+ | | | iflags field | data | | player option | bit in wincap mask | for value | type | |--------------------+--------------------+--------------------+--------+ | fullscreen | WC2_FULLSCREEN | wc2_fullscreen |boolean | | softkeyboard | WC2_SOFTKEYBOARD | wc2_softkeyboard |boolean | | wraptext | WC2_WRAPTEXT | wc2_wraptext |boolean | +--------------------+--------------------+--------------------+--------+ align_message -- where to place message window (top, bottom, left, right) align_status -- where to place status window (top, bottom, left, right). ascii_map -- port should display an ascii map if it can. color -- port should display color if it can. eight_bit_tty -- port should allow eight bit input. font_map -- port should use a font by this name for map window. font_menu -- port should use a font by this name for menu windows. font_message -- port should use a font by this name for message window. font_size_map -- port should use this size font for the map window. font_size_menu -- port should use this size font for menu windows. font_size_message -- port should use this size font for the message window. font_size_status-- port should use this size font for the status window. font_size_text -- port should use this size font for text windows. font_status -- port should use a font by this name for status window. font_text -- port should use a font by this name for text windows. fullscreen -- port should try to use the whole screen. hilite_pet -- port should mark pets in some special way on the map. map_mode -- port should display the map in the manner specified. player_selection -- dialog or prompts for choosing character. popup_dialog -- port should pop up dialog boxes for input. preload_tiles -- port should preload tiles into memory. scroll_amount -- scroll this amount when scroll_margin is reached. scroll_margin -- port should scroll the display when the hero or cursor is this number of cells away from the edge of the window. softkeyboard -- handhelds should display an on-screen keyboard if possible. splash_screen -- port should/should not display an opening splashscreen. tiled_map -- port should display a tiled map if it can. tile_width -- port should display tiles with this width or round to closest if it can. tile_height -- port should display tiles with this height or round to closest if it can. tile_file -- open this alternative tile file. The file name is likely to be window-port or platform specific. use_inverse -- port should display inverse when NetHack asks for it. vary_msgcount -- port should display this number of messages at a time in the message window. windowcolors -- port should use these colors for window foreground/background colors. Syntax: menu fore/back message fore/back status fore/back text fore/back wraptext -- port should wrap long lines of text if they don't fit in the visible area of the window mouse_support -- port should enable mouse support if possible Whenever one of these settings is adjusted, the port is notified of a change to the setting by calling the port's preference_update() routine. The port is only notified if it has indicated that it supports that option by setting the option's bit in the port's wincap mask. The port can choose to adjust for the change to an option that it receives notification about, or ignore it. The former approach is recommended. If you don't want to deal with a user-initiated setting change, then the port should call set_wc_option_mod_status(mask, SET_IN_FILE) to make the option invisible to the user. Functions available for the window port to call: set_wc_option_mod_status(optmask, status) -- Adjust the optflag field for a set of wincap options to specify whether the port wants the option to appear in the 'O' command options menu, The second parameter, "status" can be set to SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME (SET_IN_FILE implies that the option is completely hidden during the game). set_wc2_option_mod_status(optmask, status) -- Adjust the optflag field for a set of wincap2 options to specify whether the port wants the option to appear in the 'O' command options menu, The second parameter, "status" can be set to SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME (SET_IN_FILE implies that the option is completely hidden during the game). set_option_mod_status(optnam, status) -- Adjust the optflag field for one of the core options that is not part of the wincap suite. A port might use this to override the default initialization setting for status specified in options.c. Note that you have to specify the option by name and that you can only set one option per call unlike set_wc_option_mod_status(). Adding a new wincap option: To add a new wincap option, please follow all these steps: 1. Add the option to the wincap preference settings table above. Since wincap is full, your option will likely target wincap2 field. 2. Add the description to the paragraph below the chart. 3. Add the WC_ or WC2_ to the bit list in include/winprocs.h (in wincap2 if there is no room in wincap). 4. Add the wc_ or wc2_ field(s) to the iflags structure in flag.h. 5. Add the name and value to wc_options[] or wc2_options[] in options.c 6. Add an appropriate parser to parseoptions() in options.c. 7. Add code to display current value to get_compopt_value() in options.c. 8. Document the option in Guidebook.mn and Guidebook.tex. 9. Add the bit name to the OR'd values in your window port's winprocs struct wincap mask if your port supports the option. V. New or respecified common, high level routines These are not part of the interface, but mentioned here for your information. char display_inventory(lets, want_reply) -- Calls a start_menu()/add_menu()/select_menu() sequence. It returns the item selected, or '\0' if none is selected. Returns '\033' if the menu was canceled. raw_printf(str, ...) -- Like raw_print(), but accepts arguments like printf(). This routine processes the arguments and then calls raw_print(). -- The mac version #defines error raw_printf. I think this is a reasonable thing to do for most ports. pline(str, ...) -- Prints a string to WIN_MESSAGE using a printf() interface. It has the variants You(), Your(), Norep(), and others in pline.c which all use the same mechanism. pline() requires the variable "char toplines[]" be defined; Every putstr() on WIN_MESSAGE must copy str to toplines[] for use by Norep() and pline(). If the window system is not active (!iflags.window_inited) pline() uses raw_print(). VI. Helper Routines These are not part of the interface. They may be called by your window port routines to perform the desired task, instead of duplicating the necessary code in each window port. mapglyph(int glyph, int *ochar, int *ocolor, unsigned *special, int x, int y) -- Maps glyph at x,y to NetHack ascii character and color. If it represents something special such as a pet, that information is returned as set bits in "special." Usually called from the window port's print_glyph() routine. VII. Game startup The following is the general order in which calls from main() should be made, as they relate to the window system. The actual code may differ, but the order of the calls should be the same. choose_windows(DEFAULT_WINDOW_SYS) /* choose a default window system */ initoptions() /* read the resource file */ init_nhwindows() /* initialize the window system */ process_options(argc, argv) /* process command line options or equiv */ if(save file is present) { display_gamewindows() /* create & display the game windows */ dorestore() /* restore old game; pline()s are OK */ } else { player_selection() /* select a player type using a window */ display_gamewindows() /* create & display the game windows */ } pline("Hello, welcome..."); Choose_windows() is a common routine, and calling it in main() is necessary to initialize the function pointer table to _something_ so that calls to raw_print() will not fail. Choose_windows() should be called almost immediately upon entering main(). Look at unixmain.c for an example. Display_gamewindows() is a common routine that displays the three standard game windows (WIN_MESSAGE, WIN_MAP, and WIN_STATUS). It is normally called just before the "Hello, welcome" message. Process_options() is currently still unique to each port. There may be need in the future to make it possible to replace this on a per window-port basis. VIII. Conventions init_nhwindows() is expected to display a gee-whiz banner window, including the Copyright message. It is recommended that the COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B, and COPYRIGHT_BANNER_C macros from patchlevel.h be used for constructing the Copyright message. COPYRIGHT_BANNER_A is a quoted string that has the NetHack copyright declaration, COPYRIGHT_BANNER_B is a quoted string that states who the copyright belongs to, and COPYRIGHT_BANNER_C simply says "See License for details." Be sure to #include "patchlevel.h" to define these macros. Using the macros will prevent having to update the Copyright information in each window-port prior to each release. Ports (MSDOS, TOS, MAC, etc) _may_ use window-port specific routines in their port specific files, _AT_THEIR_OWN_RISK_. Since "port" and "window-port" are orthogonal, you make your "port" code less portable by using "window-port" specific routines. Every effort should be made to use window-port interface routines, unless there is something port specific that is better suited (e.g. msmsg() for MSDOS). The tty window-port is contained in win/tty, the X window port is contained in win/X11. The files in these directories contain _only_ window port code, and may be replaced completely by other window ports. IX. Implementation and Multi-window support NetHack 3.2 and higher support multiple window systems in the same binary. When writing a new window-port, you need to follow the following guidelines: 1) Pick a unique prefix to identify your window-port. For example, the tty window port uses "tty"; the X11 window-port uses "X11". 2) When declaring your interface function, precede the function names with your unique prefix. E.g: void tty_init_nhwindows() { /* code for initializing windows in the tty port */ } When calling window functions from within your port code, we suggest calling the prefixed version to avoid unnecessary overhead. However, you may safely call the non-prefixed version (e.g. putstr() rather than tty_putstr()) as long as you #include "hack.h". If you do not include hack.h and use the non-prefixed names, you will get compile or link-time errors. We also suggest declaring all functions and port-specific data with this prefix to avoid unexpected overlaps with other window-ports. The tty and X11 ports do not currently follow this suggestion, but do use separate non-overlapping convention for naming data and internal functions. 3) Declare a structure, "struct window_procs prefix_procs", (with your prefix instead of "prefix") and fill in names of all of your interface functions. The first entry in this structure is the name of your window-port, which should be the prefix. The second entry is the wincap mask that identifies what window port preference settings your port will react to and support. The other entries are the function addresses. Assuming that you followed the convention in (2), you can safely copy the structure definition from an existing window-port and just change the prefixes. That will guarantee that you get the order of your initializations correct (not all compilers will catch out-of-order function pointer declarations). 4) Add a #define to config.h identifying your window-port in the "Windowing systems" section. Follow the "prefix_GRAPHICS" convention for your window-port. 5) Add your prefix to the list of valid prefixes listed in the "Known systems are" comment. 6) Edit makedefs.c and add a string for your windowing system to window_opts inside an #ifdef prefix_GRAPHICS. 7) Edit windows.c and add an external reference to your prefix_procs inside an #ifdef prefix_GRAPHICS. Also add an entry to the win_choices structure for your window-port of the form: #ifdef prefix_GRAPHICS { &prefix_procs, prefix_init_function }, #endif The init_function is necessary for some compilers and systems to force correct linking. If your system does not need such massaging, you may put a null pointer here. You should declare prefix_procs and prefix_init_function as extern's in your win*.h file, and #include that file at the beginning of windows.c, also inside an #ifdef prefix_GRAPHICS. Some win*.h files are rather sensitive, and you might have to duplicate your prefix_procs and prefix_init_function's instead of including win*.h. The tty port includes wintty.h, the X11 port duplicates the declarations. 8) If your port uses Makefile.src, add the .c and .o files and an appropriate comment in the section on "WINSRC" and "WINOBJ". See Makefile.src for the style to use. If you don't use Makefile.src, we suggest using a similar convention for the make-equivalent used on your system. Also add your new source and binaries to WINSRC and WINOBJ (if you want the NetHack binary to include them, that is). 9) Look at your port's portmain.c (the file containing main()) and make sure that all of the calls match the the requirements laid out in Section VII. Now, proceed with compilation and installation as usual. Don't forget to edit Makefile.src (or its equivalent) and config.h to set the window-ports you want in your binary, the default window-port to use, and the .o's needed to build a valid game. One caveat. Unfortunately, if you incorrectly specify the DEFAULT_WINDOW_SYS, NetHack will dump core (or whatever) without printing any message, because raw_print() cannot function without first setting the window-port. nethack-3.4.3/include/0040755000000000000000000000000007764735121013277 5ustar rootrootnethack-3.4.3/include/align.h0100644000000000000000000000175607764735041014551 0ustar rootroot/* SCCS Id: @(#)align.h 3.4 1991/12/29 */ /* Copyright (c) Mike Stephenson, Izchak Miller 1991. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef ALIGN_H #define ALIGN_H typedef schar aligntyp; /* basic alignment type */ typedef struct align { /* alignment & record */ aligntyp type; int record; } align; /* bounds for "record" -- respect initial alignments of 10 */ #define ALIGNLIM (10L + (moves/200L)) #define A_NONE (-128) /* the value range of type */ #define A_CHAOTIC (-1) #define A_NEUTRAL 0 #define A_LAWFUL 1 #define A_COALIGNED 1 #define A_OPALIGNED (-1) #define AM_NONE 0 #define AM_CHAOTIC 1 #define AM_NEUTRAL 2 #define AM_LAWFUL 4 #define AM_MASK 7 #define AM_SPLEV_CO 3 #define AM_SPLEV_NONCO 7 #define Amask2align(x) ((aligntyp) ((!(x)) ? A_NONE \ : ((x) == AM_LAWFUL) ? A_LAWFUL : ((int)x) - 2)) #define Align2amask(x) (((x) == A_NONE) ? AM_NONE \ : ((x) == A_LAWFUL) ? AM_LAWFUL : (x) + 2) #endif /* ALIGN_H */ nethack-3.4.3/include/amiconf.h0100644000000000000000000001134607764735041015067 0ustar rootroot/* SCCS Id: @(#)amiconf.h 3.4 2000/01/12 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1990, 1991, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef AMICONF_H #define AMICONF_H #undef abs /* avoid using macro form of abs */ #ifndef __SASC_60 # undef min /* this gets redefined */ # undef max /* this gets redefined */ #endif #include /* get time_t defined before use! */ #ifdef __SASC_60 /* since SAS can prevent re-inclusion */ #include /* general things, including builtins */ #include #endif #ifdef AZTEC_50 #include # define AZTEC_C_WORKAROUND /* Bug which turns up in sounds.c. Bummer... */ # define NO_SIGNAL /* 5.0 signal handling doesn't like SIGINT... */ #endif #ifdef _DCC #include # define _SIZE_T # define DCC30_BUG /* A bitfield bug (from dog.c, others) in DICE 3.0. */ #endif #ifndef __GNUC__ typedef long off_t; #endif #define MICRO /* must be defined to allow some inclusions */ #define NOCWD_ASSUMPTIONS /* Allow paths to be specified for HACKDIR, LEVELDIR, SAVEDIR, BONESDIR, DATADIR, SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ /* data librarian defs */ #ifndef NOCWD_ASSUMPTIONS # define DLBFILE "NetHack:nhdat" /* main library */ # define DLBFILE2 "NetHack:nhsdat" /* sound library */ #else # define DLBFILE "nhdat" /* main library */ # define DLBFILE2 "nhsdat" /* sound library */ #endif #define FILENAME_CMP stricmp /* case insensitive */ #ifndef __SASC_60 # define O_BINARY 0 #endif /* Compile in New Intuition look for 2.0 */ #ifdef IDCMP_CLOSEWINDOW # ifndef INTUI_NEW_LOOK # define INTUI_NEW_LOOK 1 # endif #endif #define MFLOPPY /* You'll probably want this; provides assistance * for typical personal computer configurations */ #define RANDOM /* ### amidos.c ### */ extern void FDECL(nethack_exit, (int)); /* ### amiwbench.c ### */ extern void NDECL(ami_wbench_init); extern void NDECL(ami_wbench_args); extern int FDECL(ami_wbench_getsave, (int)); extern void FDECL(ami_wbench_unlink, (char *)); extern int FDECL(ami_wbench_iconsize, (char *)); extern void FDECL(ami_wbench_iconwrite, (char *)); extern int FDECL(ami_wbench_badopt, (const char *)); extern void NDECL(ami_wbench_cleanup); extern void FDECL(getlind, (const char *,char *,const char *)); /* ### winreq.c ### */ extern void amii_setpens(int); extern void FDECL(exit, (int)); extern void NDECL(CleanUp); extern void FDECL(Abort, (long)); extern int NDECL(getpid); extern char *FDECL(CopyFile, (const char *, const char *)); extern int NDECL(kbhit); extern int NDECL(WindowGetchar); extern void FDECL(ami_argset, (int *, char *[])); extern void FDECL(ami_mkargline, (int *, char **[])); extern void ami_wininit_data(void); #define FromWBench 0 /* A hint for compiler ... */ /* extern boolean FromWBench; /* how were we run? */ extern int ami_argc; extern char **ami_argv; #ifndef MICRO_H #include "micro.h" #endif #ifndef PCCONF_H #include "pcconf.h" /* remainder of stuff is almost same as the PC */ #endif #define remove(x) unlink(x) /* DICE wants rewind() to return void. We want it to return int. */ #if defined(_DCC) || defined(__GNUC__) # define rewind(f) fseek(f, 0, 0) #endif #ifdef AZTEC_C extern FILE *FDECL(freopen, (const char *, const char *, FILE *)); extern char *FDECL(gets, (char *)); #endif #define msmsg printf /* * If AZTEC_C we can't use the long cpath in vision.c.... */ #ifdef AZTEC_C # undef MACRO_CPATH #endif /* * (Possibly) configurable Amiga options: */ #define TEXTCOLOR /* Use colored monsters and objects */ #define HACKFONT /* Use special hack.font */ #define SHELL /* Have a shell escape command (!) */ #define MAIL /* Get mail at unexpected occasions */ #define DEFAULT_ICON "NetHack:default.icon" /* private icon */ #define AMIFLUSH /* toss typeahead (select flush in .cnf) */ /* #define OPT_DISPMAP /* enable fast_map option */ /* new window system options */ /* WRONG - AMIGA_INTUITION should go away */ #ifdef AMII_GRAPHICS # define AMIGA_INTUITION /* high power graphics interface (amii) */ #endif #define CHANGE_COLOR 1 #ifdef TEXTCOLOR # define DEPTH 6 /* Maximum depth of the screen allowed */ #else # define DEPTH 2 /* Four colors...sigh... */ #endif #define AMII_MAXCOLORS (1L< /* for time_t */ #include /* for lseek() */ /* could go in extern.h, under bemain.c (or something..) */ void regularize(char *); /* instead of including system.h... */ #include #include #include #endif /* BECONF_H */ nethack-3.4.3/include/bitmfile.h0100644000000000000000000000147707764735041015252 0ustar rootroot/****************************\ * Bitmap mit Farbtabelle als * * Graphik-Datei speichern * * Autor: Gabriel Schmidt * * (c} 1992 by MAXON-Computer * * -> Header-Datei * \****************************/ #ifndef H_TO_FILE #define H_TO_FILE /* #include */ #define UWORD unsigned short #define ULONG unsigned long #define UBYTE unsigned char #define XIMG_MAGIC 0x58494D47 typedef enum { IMG, XIMG } FILE_TYP; const char *get_file_ext(FILE_TYP typ); struct RGB { UWORD r, g, b; }; int bitmap_to_file(FILE_TYP typ, int ww, int wh, unsigned int pwx, unsigned int pwy, unsigned int planes, unsigned int colors, const char *filename, void (*get_color) (unsigned int colind, struct RGB *rgb) , void (*get_pixel) (int x, int y, unsigned int *colind) ) ; #endif nethack-3.4.3/include/color.h0100644000000000000000000000305007764735041014562 0ustar rootroot/* SCCS Id: @(#)color.h 3.4 1992/02/02 */ /* Copyright (c) Steve Linhart, Eric Raymond, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef COLOR_H #define COLOR_H /* * The color scheme used is tailored for an IBM PC. It consists of the * standard 8 colors, folowed by their bright counterparts. There are * exceptions, these are listed below. Bright black doesn't mean very * much, so it is used as the "default" foreground color of the screen. */ #define CLR_BLACK 0 #define CLR_RED 1 #define CLR_GREEN 2 #define CLR_BROWN 3 /* on IBM, low-intensity yellow is brown */ #define CLR_BLUE 4 #define CLR_MAGENTA 5 #define CLR_CYAN 6 #define CLR_GRAY 7 /* low-intensity white */ #define NO_COLOR 8 #define CLR_ORANGE 9 #define CLR_BRIGHT_GREEN 10 #define CLR_YELLOW 11 #define CLR_BRIGHT_BLUE 12 #define CLR_BRIGHT_MAGENTA 13 #define CLR_BRIGHT_CYAN 14 #define CLR_WHITE 15 #define CLR_MAX 16 /* The "half-way" point for tty based color systems. This is used in */ /* the tty color setup code. (IMHO, it should be removed - dean). */ #define BRIGHT 8 /* these can be configured */ #define HI_OBJ CLR_MAGENTA #define HI_METAL CLR_CYAN #define HI_COPPER CLR_YELLOW #define HI_SILVER CLR_GRAY #define HI_GOLD CLR_YELLOW #define HI_LEATHER CLR_BROWN #define HI_CLOTH CLR_BROWN #define HI_ORGANIC CLR_BROWN #define HI_WOOD CLR_BROWN #define HI_PAPER CLR_WHITE #define HI_GLASS CLR_BRIGHT_CYAN #define HI_MINERAL CLR_GRAY #define DRAGON_SILVER CLR_BRIGHT_CYAN #define HI_ZAP CLR_BRIGHT_BLUE #endif /* COLOR_H */ nethack-3.4.3/include/config.h0100644000000000000000000002653407764735041014725 0ustar rootroot/* SCCS Id: @(#)config.h 3.4 2003/12/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef CONFIG_H /* make sure the compiler does not see the typedefs twice */ #define CONFIG_H /* * Section 1: Operating and window systems selection. * Select the version of the OS you are using. * For "UNIX" select BSD, ULTRIX, SYSV, or HPUX in unixconf.h. * A "VMS" option is not needed since the VMS C-compilers * provide it (no need to change sec#1, vmsconf.h handles it). */ #define UNIX /* delete if no fork(), exec() available */ /* #define MSDOS */ /* in case it's not auto-detected */ /* #define OS2 */ /* define for OS/2 */ /* #define TOS */ /* define for Atari ST/TT */ /* #define STUPID */ /* avoid some complicated expressions if your C compiler chokes on them */ /* #define MINIMAL_TERM */ /* if a terminal handles highlighting or tabs poorly, try this define, used in pager.c and termcap.c */ /* #define ULTRIX_CC20 */ /* define only if using cc v2.0 on a DECstation */ /* #define ULTRIX_PROTO */ /* define for Ultrix 4.0 (or higher) on a DECstation; * if you get compiler errors, don't define this. */ /* Hint: if you're not developing code, don't define ULTRIX_PROTO. */ #include "config1.h" /* should auto-detect MSDOS, MAC, AMIGA, and WIN32 */ /* Windowing systems... * Define all of those you want supported in your binary. * Some combinations make no sense. See the installation document. */ #define TTY_GRAPHICS /* good old tty based graphics */ /* #define X11_GRAPHICS */ /* X11 interface */ /* #define QT_GRAPHICS */ /* Qt interface */ /* #define GNOME_GRAPHICS */ /* Gnome interface */ /* #define MSWIN_GRAPHICS */ /* Windows NT, CE, Graphics */ /* * Define the default window system. This should be one that is compiled * into your system (see defines above). Known window systems are: * * tty, X11, mac, amii, BeOS, Qt, Gem, Gnome */ /* MAC also means MAC windows */ #ifdef MAC # ifndef AUX # define DEFAULT_WINDOW_SYS "mac" # endif #endif /* Amiga supports AMII_GRAPHICS and/or TTY_GRAPHICS */ #ifdef AMIGA # define AMII_GRAPHICS /* (optional) */ # define DEFAULT_WINDOW_SYS "amii" /* "amii", "amitile" or "tty" */ #endif /* Atari supports GEM_GRAPHICS and/or TTY_GRAPHICS */ #ifdef TOS # define GEM_GRAPHICS /* Atari GEM interface (optional) */ # define DEFAULT_WINDOW_SYS "Gem" /* "Gem" or "tty" */ #endif #ifdef __BEOS__ #define BEOS_GRAPHICS /* (optional) */ #define DEFAULT_WINDOW_SYS "BeOS" /* "tty" */ #ifndef HACKDIR /* override the default hackdir below */ # define HACKDIR "/boot/apps/NetHack" #endif #endif #ifdef QT_GRAPHICS # define DEFAULT_WC_TILED_MAP /* Default to tiles if users doesn't say wc_ascii_map */ # define USER_SOUNDS /* Use sounds */ # ifndef __APPLE__ # define USER_SOUNDS_REGEX # endif # define USE_XPM /* Use XPM format for images (required) */ # define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.ppm) */ # ifndef DEFAULT_WINDOW_SYS # define DEFAULT_WINDOW_SYS "Qt" # endif #endif #ifdef GNOME_GRAPHICS # define USE_XPM /* Use XPM format for images (required) */ # define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.ppm) */ # ifndef DEFAULT_WINDOW_SYS # define DEFAULT_WINDOW_SYS "Gnome" # endif #endif #ifdef MSWIN_GRAPHICS # ifdef TTY_GRAPHICS # undef TTY_GRAPHICS # endif # ifndef DEFAULT_WINDOW_SYS # define DEFAULT_WINDOW_SYS "mswin" # endif # define HACKDIR "\\nethack" #endif #ifndef DEFAULT_WINDOW_SYS # define DEFAULT_WINDOW_SYS "tty" #endif #ifdef X11_GRAPHICS /* * There are two ways that X11 tiles may be defined. (1) using a custom * format loaded by NetHack code, or (2) using the XPM format loaded by * the free XPM library. The second option allows you to then use other * programs to generate tiles files. For example, the PBMPlus tools * would allow: * xpmtoppm x11tiles_big.xpm */ /* # define USE_XPM */ /* Disable if you do not have the XPM library */ # ifdef USE_XPM # define GRAPHIC_TOMBSTONE /* Use graphical tombstone (rip.xpm) */ # endif #endif /* * Section 2: Some global parameters and filenames. * Commenting out WIZARD, LOGFILE, NEWS or PANICLOG removes that * feature from the game; otherwise set the appropriate wizard * name. LOGFILE, NEWS and PANICLOG refer to files in the * playground. */ #ifndef WIZARD /* allow for compile-time or Makefile changes */ # ifndef KR1ED # define WIZARD "wizard" /* the person allowed to use the -D option */ # else # define WIZARD # define WIZARD_NAME "wizard" # endif #endif #define LOGFILE "logfile" /* larger file for debugging purposes */ #define NEWS "news" /* the file containing the latest hack news */ #define PANICLOG "paniclog" /* log of panic and impossible events */ /* * If COMPRESS is defined, it should contain the full path name of your * 'compress' program. Defining INTERNAL_COMP causes NetHack to do * simpler byte-stream compression internally. Both COMPRESS and * INTERNAL_COMP create smaller bones/level/save files, but require * additional code and time. Currently, only UNIX fully implements * COMPRESS; other ports should be able to uncompress save files a * la unixmain.c if so inclined. * If you define COMPRESS, you must also define COMPRESS_EXTENSION * as the extension your compressor appends to filenames after * compression. */ #ifdef UNIX /* path and file name extension for compression program */ #define COMPRESS "/usr/bin/compress" /* Lempel-Ziv compression */ #define COMPRESS_EXTENSION ".Z" /* compress's extension */ /* An example of one alternative you might want to use: */ /* #define COMPRESS "/usr/local/bin/gzip" */ /* FSF gzip compression */ /* #define COMPRESS_EXTENSION ".gz" */ /* normal gzip extension */ #endif #ifndef COMPRESS # define INTERNAL_COMP /* control use of NetHack's compression routines */ #endif /* * Data librarian. Defining DLB places most of the support files into * a tar-like file, thus making a neater installation. See *conf.h * for detailed configuration. */ /* #define DLB */ /* not supported on all platforms */ /* * Defining INSURANCE slows down level changes, but allows games that * died due to program or system crashes to be resumed from the point * of the last level change, after running a utility program. */ #define INSURANCE /* allow crashed game recovery */ #ifndef MAC # define CHDIR /* delete if no chdir() available */ #endif #ifdef CHDIR /* * If you define HACKDIR, then this will be the default playground; * otherwise it will be the current directory. */ # ifndef HACKDIR # define HACKDIR "/usr/games/lib/nethackdir" # endif /* * Some system administrators are stupid enough to make Hack suid root * or suid daemon, where daemon has other powers besides that of reading or * writing Hack files. In such cases one should be careful with chdir's * since the user might create files in a directory of his choice. * Of course SECURE is meaningful only if HACKDIR is defined. */ /* #define SECURE */ /* do setuid(getuid()) after chdir() */ /* * If it is desirable to limit the number of people that can play Hack * simultaneously, define HACKDIR, SECURE and MAX_NR_OF_PLAYERS. * #define MAX_NR_OF_PLAYERS 6 */ #endif /* CHDIR */ /* * Section 3: Definitions that may vary with system type. * For example, both schar and uchar should be short ints on * the AT&T 3B2/3B5/etc. family. */ /* * Uncomment the following line if your compiler doesn't understand the * 'void' type (and thus would give all sorts of compile errors without * this definition). */ /* #define NOVOID */ /* define if no "void" data type. */ /* * Uncomment the following line if your compiler falsely claims to be * a standard C compiler (i.e., defines __STDC__ without cause). * Examples are Apollo's cc (in some versions) and possibly SCO UNIX's rcc. */ /* #define NOTSTDC */ /* define for lying compilers */ #include "tradstdc.h" /* * type schar: small signed integers (8 bits suffice) (eg. TOS) * * typedef char schar; * * will do when you have signed characters; otherwise use * * typedef short int schar; */ #ifdef AZTEC # define schar char #else typedef signed char schar; #endif /* * type uchar: small unsigned integers (8 bits suffice - but 7 bits do not) * * typedef unsigned char uchar; * * will be satisfactory if you have an "unsigned char" type; * otherwise use * * typedef unsigned short int uchar; */ #ifndef _AIX32 /* identical typedef in system file causes trouble */ typedef unsigned char uchar; #endif /* * Various structures have the option of using bitfields to save space. * If your C compiler handles bitfields well (e.g., it can initialize structs * containing bitfields), you can define BITFIELDS. Otherwise, the game will * allocate a separate character for each bitfield. (The bitfields used never * have more than 7 bits, and most are only 1 bit.) */ #define BITFIELDS /* Good bitfield handling */ /* #define STRNCMPI */ /* compiler/library has the strncmpi function */ /* * There are various choices for the NetHack vision system. There is a * choice of two algorithms with the same behavior. Defining VISION_TABLES * creates huge (60K) tables at compile time, drastically increasing data * size, but runs slightly faster than the alternate algorithm. (MSDOS in * particular cannot tolerate the increase in data size; other systems can * flip a coin weighted to local conditions.) * * If VISION_TABLES is not defined, things will be faster if you can use * MACRO_CPATH. Some cpps, however, cannot deal with the size of the * functions that have been macroized. */ /* #define VISION_TABLES */ /* use vision tables generated at compile time */ #ifndef VISION_TABLES # ifndef NO_MACRO_CPATH # define MACRO_CPATH /* use clear_path macros instead of functions */ # endif #endif /* * Section 4: THE FUN STUFF!!! * * Conditional compilation of special options are controlled here. * If you define the following flags, you will add not only to the * complexity of the game but also to the size of the load module. */ /* dungeon features */ #define SINKS /* Kitchen sinks - Janet Walz */ /* dungeon levels */ #define WALLIFIED_MAZE /* Fancy mazes - Jean-Christophe Collet */ #define REINCARNATION /* Special Rogue-like levels */ /* monsters & objects */ #define KOPS /* Keystone Kops by Scott R. Turner */ #define SEDUCE /* Succubi/incubi seduction, by KAA, suggested by IM */ #define STEED /* Riding steeds */ #define TOURIST /* Tourist players with cameras and Hawaiian shirts */ /* difficulty */ #define ELBERETH /* Engraving the E-word repels monsters */ /* I/O */ #define REDO /* support for redoing last command - DGK */ #if !defined(MAC) # define CLIPPING /* allow smaller screens -- ERS */ #endif #ifdef REDO # define DOAGAIN '\001' /* ^A, the "redo" key used in cmd.c and getline.c */ #endif #define EXP_ON_BOTL /* Show experience on bottom line */ /* #define SCORE_ON_BOTL */ /* added by Gary Erickson (erickson@ucivax) */ /* * Section 5: EXPERIMENTAL STUFF * * Conditional compilation of new or experimental options are controlled here. * Enable any of these at your own risk -- there are almost certainly * bugs left here. */ /*#define GOLDOBJ */ /* Gold is kept on obj chains - Helge Hafting */ /*#define AUTOPICKUP_EXCEPTIONS */ /* exceptions to autopickup */ /* End of Section 5 */ #include "global.h" /* Define everything else according to choices above */ #endif /* CONFIG_H */ nethack-3.4.3/include/config1.h0100644000000000000000000001061407764735041014776 0ustar rootroot/* SCCS Id: @(#)config1.h 3.4 1999/12/05 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef CONFIG1_H #define CONFIG1_H /* * MS DOS - compilers * * Microsoft C auto-defines MSDOS, * Borland C auto-defines __MSDOS__, * DJGPP auto-defines MSDOS. */ /* #define MSDOS */ /* use if not defined by compiler or cases below */ #ifdef __MSDOS__ /* for Borland C */ # ifndef MSDOS # define MSDOS # endif #endif #ifdef __TURBOC__ # define __MSC /* increase Borland C compatibility in libraries */ #endif #ifdef MSDOS # undef UNIX #endif /* * Mac Stuff. */ #ifdef macintosh /* Auto-defined symbol for MPW compilers (sc and mrc) */ # define MAC #endif #ifdef THINK_C /* Think C auto-defined symbol */ # define MAC # define NEED_VARARGS #endif #ifdef __MWERKS__ /* defined by Metrowerks' Codewarrior compiler */ # ifndef __BEOS__ /* BeOS */ # define MAC # endif # define NEED_VARARGS # define USE_STDARG #endif #if defined(MAC) || defined(__BEOS__) # define DLB # undef UNIX #endif #ifdef __BEOS__ # define NEED_VARARGS #endif /* * Amiga setup. */ #ifdef AZTEC_C /* Manx auto-defines this */ # ifdef MCH_AMIGA /* Manx auto-defines this for AMIGA */ # ifndef AMIGA #define AMIGA /* define for Commodore-Amiga */ # endif /* (SAS/C auto-defines AMIGA) */ #define AZTEC_50 /* define for version 5.0 of manx */ # endif #endif #ifdef __SASC_60 # define NEARDATA __near /* put some data close */ #else # ifdef _DCC # define NEARDATA __near /* put some data close */ # else # define NEARDATA # endif #endif #ifdef AMIGA # define NEED_VARARGS # undef UNIX # define DLB # define HACKDIR "NetHack:" # define NO_MACRO_CPATH #endif /* * Atari auto-detection */ #ifdef atarist # undef UNIX # ifndef TOS # define TOS # endif #else # ifdef __MINT__ # undef UNIX # ifndef TOS # define TOS # endif # endif #endif /* * Windows NT Autodetection */ #ifdef _WIN32_WCE #define WIN_CE # ifndef WIN32 # define WIN32 # endif #endif #ifdef WIN32 # undef UNIX # undef MSDOS # define NHSTDC # define USE_STDARG # define NEED_VARARGS #ifndef WIN_CE # define STRNCMPI # define STRCMPI #endif #endif #if defined(__linux__) && defined(__GNUC__) && !defined(_GNU_SOURCE) /* ensure _GNU_SOURCE is defined before including any system headers */ # define _GNU_SOURCE #endif #ifdef VMS /* really old compilers need special handling, detected here */ # undef UNIX # ifdef __DECC # ifndef __DECC_VER /* buggy early versions want widened prototypes */ # define NOTSTDC /* except when typedefs are involved */ # define USE_VARARGS # else # define NHSTDC # define USE_STDARG # define POSIX_TYPES # define _DECC_V4_SOURCE /* avoid some incompatible V5.x changes */ # endif # undef __HIDE_FORBIDDEN_NAMES /* need non-ANSI library support functions */ # else # ifdef VAXC /* must use CC/DEFINE=ANCIENT_VAXC for vaxc v2.2 or older */ # ifdef ANCIENT_VAXC /* vaxc v2.2 and earlier [lots of warnings to come] */ # define KR1ED /* simulate defined() */ # define USE_VARARGS # else /* vaxc v2.3,2.4,or 3.x, or decc in vaxc mode */ # if defined(USE_PROTOTYPES) /* this breaks 2.2 (*forces* use of ANCIENT)*/ # define __STDC__ 0 /* vaxc is not yet ANSI compliant, but close enough */ # define signed /* well, almost close enough */ #include # define UNWIDENED_PROTOTYPES # endif # define USE_STDARG # endif # endif /*VAXC*/ # endif /*__DECC*/ # ifdef VERYOLD_VMS /* v4.5 or earlier; no longer available for testing */ # define USE_OLDARGS /* is there, vprintf & vsprintf aren't */ # ifdef USE_VARARGS # undef USE_VARARGS # endif # ifdef USE_STDARG # undef USE_STDARG # endif # endif #endif /*VMS*/ #ifdef vax /* just in case someone thinks a DECstation is a vax. It's not, it's a mips */ # ifdef ULTRIX_PROTO # undef ULTRIX_PROTO # endif # ifdef ULTRIX_CC20 # undef ULTRIX_CC20 # endif #endif #ifdef KR1ED /* For compilers which cannot handle defined() */ #define defined(x) (-x-1 != -1) /* Because: * #define FOO => FOO={} => defined( ) => (-1 != - - 1) => 1 * #define FOO 1 or on command-line -DFOO * => defined(1) => (-1 != - 1 - 1) => 1 * if FOO isn't defined, FOO=0. But some compilers default to 0 instead of 1 * for -DFOO, oh well. * => defined(0) => (-1 != - 0 - 1) => 0 * * But: * defined("") => (-1 != - "" - 1) * [which is an unavoidable catastrophe.] */ #endif #endif /* CONFIG1_H */ nethack-3.4.3/include/coord.h0100644000000000000000000000043207764735041014553 0ustar rootroot/* SCCS Id: @(#)coord.h 3.4 1990/02/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef COORD_H #define COORD_H typedef struct nhcoord { xchar x,y; } coord; #endif /* COORD_H */ nethack-3.4.3/include/decl.h0100644000000000000000000002647107764735041014367 0ustar rootroot/* SCCS Id: @(#)decl.h 3.4 2001/12/10 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DECL_H #define DECL_H #define E extern E int NDECL((*occupation)); E int NDECL((*afternmv)); E const char *hname; E int hackpid; #if defined(UNIX) || defined(VMS) E int locknum; #endif #ifdef DEF_PAGER E char *catmore; #endif /* DEF_PAGER */ E char SAVEF[]; #ifdef MICRO E char SAVEP[]; #endif E NEARDATA int bases[MAXOCLASSES]; E NEARDATA int multi; #if 0 E NEARDATA int warnlevel; #endif E NEARDATA int nroom; E NEARDATA int nsubroom; E NEARDATA int occtime; #define WARNCOUNT 6 /* number of different warning levels */ E uchar warnsyms[WARNCOUNT]; E int x_maze_max, y_maze_max; E int otg_temp; #ifdef REDO E NEARDATA int in_doagain; #endif E struct dgn_topology { /* special dungeon levels for speed */ d_level d_oracle_level; d_level d_bigroom_level; /* unused */ #ifdef REINCARNATION d_level d_rogue_level; #endif d_level d_medusa_level; d_level d_stronghold_level; d_level d_valley_level; d_level d_wiz1_level; d_level d_wiz2_level; d_level d_wiz3_level; d_level d_juiblex_level; d_level d_orcus_level; d_level d_baalzebub_level; /* unused */ d_level d_asmodeus_level; /* unused */ d_level d_portal_level; /* only in goto_level() [do.c] */ d_level d_sanctum_level; d_level d_earth_level; d_level d_water_level; d_level d_fire_level; d_level d_air_level; d_level d_astral_level; xchar d_tower_dnum; xchar d_sokoban_dnum; xchar d_mines_dnum, d_quest_dnum; d_level d_qstart_level, d_qlocate_level, d_nemesis_level; d_level d_knox_level; } dungeon_topology; /* macros for accesing the dungeon levels by their old names */ #define oracle_level (dungeon_topology.d_oracle_level) #define bigroom_level (dungeon_topology.d_bigroom_level) #ifdef REINCARNATION #define rogue_level (dungeon_topology.d_rogue_level) #endif #define medusa_level (dungeon_topology.d_medusa_level) #define stronghold_level (dungeon_topology.d_stronghold_level) #define valley_level (dungeon_topology.d_valley_level) #define wiz1_level (dungeon_topology.d_wiz1_level) #define wiz2_level (dungeon_topology.d_wiz2_level) #define wiz3_level (dungeon_topology.d_wiz3_level) #define juiblex_level (dungeon_topology.d_juiblex_level) #define orcus_level (dungeon_topology.d_orcus_level) #define baalzebub_level (dungeon_topology.d_baalzebub_level) #define asmodeus_level (dungeon_topology.d_asmodeus_level) #define portal_level (dungeon_topology.d_portal_level) #define sanctum_level (dungeon_topology.d_sanctum_level) #define earth_level (dungeon_topology.d_earth_level) #define water_level (dungeon_topology.d_water_level) #define fire_level (dungeon_topology.d_fire_level) #define air_level (dungeon_topology.d_air_level) #define astral_level (dungeon_topology.d_astral_level) #define tower_dnum (dungeon_topology.d_tower_dnum) #define sokoban_dnum (dungeon_topology.d_sokoban_dnum) #define mines_dnum (dungeon_topology.d_mines_dnum) #define quest_dnum (dungeon_topology.d_quest_dnum) #define qstart_level (dungeon_topology.d_qstart_level) #define qlocate_level (dungeon_topology.d_qlocate_level) #define nemesis_level (dungeon_topology.d_nemesis_level) #define knox_level (dungeon_topology.d_knox_level) E NEARDATA stairway dnstair, upstair; /* stairs up and down */ #define xdnstair (dnstair.sx) #define ydnstair (dnstair.sy) #define xupstair (upstair.sx) #define yupstair (upstair.sy) E NEARDATA stairway dnladder, upladder; /* ladders up and down */ #define xdnladder (dnladder.sx) #define ydnladder (dnladder.sy) #define xupladder (upladder.sx) #define yupladder (upladder.sy) E NEARDATA stairway sstairs; E NEARDATA dest_area updest, dndest; /* level-change destination areas */ E NEARDATA coord inv_pos; E NEARDATA dungeon dungeons[]; E NEARDATA s_level *sp_levchn; #define dunlev_reached(x) (dungeons[(x)->dnum].dunlev_ureached) #include "quest.h" E struct q_score quest_status; E NEARDATA char pl_character[PL_CSIZ]; E NEARDATA char pl_race; /* character's race */ E NEARDATA char pl_fruit[PL_FSIZ]; E NEARDATA int current_fruit; E NEARDATA struct fruit *ffruit; E NEARDATA char tune[6]; #define MAXLINFO (MAXDUNGEON * MAXLEVEL) E struct linfo level_info[MAXLINFO]; E NEARDATA struct sinfo { int gameover; /* self explanatory? */ int stopprint; /* inhibit further end of game disclosure */ #if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32) int done_hup; /* SIGHUP or moral equivalent received * -- no more screen output */ #endif int something_worth_saving; /* in case of panic */ int panicking; /* `panic' is in progress */ #if defined(VMS) || defined(WIN32) int exiting; /* an exit handler is executing */ #endif int in_impossible; #ifdef PANICLOG int in_paniclog; #endif } program_state; E boolean restoring; E const char quitchars[]; E const char vowels[]; E const char ynchars[]; E const char ynqchars[]; E const char ynaqchars[]; E const char ynNaqchars[]; E NEARDATA long yn_number; E const char disclosure_options[]; E NEARDATA int smeq[]; E NEARDATA int doorindex; E NEARDATA char *save_cm; #define KILLED_BY_AN 0 #define KILLED_BY 1 #define NO_KILLER_PREFIX 2 E NEARDATA int killer_format; E const char *killer; E const char *delayed_killer; #ifdef GOLDOBJ E long done_money; #endif E char killer_buf[BUFSZ]; E const char *configfile; E NEARDATA char plname[PL_NSIZ]; E NEARDATA char dogname[]; E NEARDATA char catname[]; E NEARDATA char horsename[]; E char preferred_pet; E const char *occtxt; /* defined when occupation != NULL */ E const char *nomovemsg; E const char nul[]; E char lock[]; E const char sdir[], ndir[]; E const schar xdir[], ydir[], zdir[]; E NEARDATA schar tbx, tby; /* set in mthrowu.c */ E NEARDATA struct multishot { int n, i; short o; boolean s; } m_shot; E NEARDATA struct dig_info { /* apply.c, hack.c */ int effort; d_level level; coord pos; long lastdigtime; boolean down, chew, warned, quiet; } digging; E NEARDATA long moves, monstermoves; E NEARDATA long wailmsg; E NEARDATA boolean in_mklev; E NEARDATA boolean stoned; E NEARDATA boolean unweapon; E NEARDATA boolean mrg_to_wielded; E NEARDATA struct obj *current_wand; E NEARDATA boolean in_steed_dismounting; E const int shield_static[]; #include "spell.h" E NEARDATA struct spell spl_book[]; /* sized in decl.c */ #include "color.h" #ifdef TEXTCOLOR E const int zapcolors[]; #endif E const char def_oc_syms[MAXOCLASSES]; /* default class symbols */ E uchar oc_syms[MAXOCLASSES]; /* current class symbols */ E const char def_monsyms[MAXMCLASSES]; /* default class symbols */ E uchar monsyms[MAXMCLASSES]; /* current class symbols */ #include "obj.h" E NEARDATA struct obj *invent, *uarm, *uarmc, *uarmh, *uarms, *uarmg, *uarmf, #ifdef TOURIST *uarmu, /* under-wear, so to speak */ #endif *uskin, *uamul, *uleft, *uright, *ublindf, *uwep, *uswapwep, *uquiver; E NEARDATA struct obj *uchain; /* defined only when punished */ E NEARDATA struct obj *uball; E NEARDATA struct obj *migrating_objs; E NEARDATA struct obj *billobjs; E NEARDATA struct obj zeroobj; /* init'd and defined in decl.c */ #include "you.h" E NEARDATA struct you u; #include "onames.h" #ifndef PM_H /* (pm.h has already been included via youprop.h) */ #include "pm.h" #endif E NEARDATA struct monst youmonst; /* init'd and defined in decl.c */ E NEARDATA struct monst *mydogs, *migrating_mons; E NEARDATA struct mvitals { uchar born; uchar died; uchar mvflags; } mvitals[NUMMONS]; E NEARDATA struct c_color_names { const char *const c_black, *const c_amber, *const c_golden, *const c_light_blue,*const c_red, *const c_green, *const c_silver, *const c_blue, *const c_purple, *const c_white; } c_color_names; #define NH_BLACK c_color_names.c_black #define NH_AMBER c_color_names.c_amber #define NH_GOLDEN c_color_names.c_golden #define NH_LIGHT_BLUE c_color_names.c_light_blue #define NH_RED c_color_names.c_red #define NH_GREEN c_color_names.c_green #define NH_SILVER c_color_names.c_silver #define NH_BLUE c_color_names.c_blue #define NH_PURPLE c_color_names.c_purple #define NH_WHITE c_color_names.c_white /* The names of the colors used for gems, etc. */ E const char *c_obj_colors[]; E struct c_common_strings { const char *const c_nothing_happens, *const c_thats_enough_tries, *const c_silly_thing_to, *const c_shudder_for_moment, *const c_something, *const c_Something, *const c_You_can_move_again, *const c_Never_mind, *c_vision_clears, *const c_the_your[2]; } c_common_strings; #define nothing_happens c_common_strings.c_nothing_happens #define thats_enough_tries c_common_strings.c_thats_enough_tries #define silly_thing_to c_common_strings.c_silly_thing_to #define shudder_for_moment c_common_strings.c_shudder_for_moment #define something c_common_strings.c_something #define Something c_common_strings.c_Something #define You_can_move_again c_common_strings.c_You_can_move_again #define Never_mind c_common_strings.c_Never_mind #define vision_clears c_common_strings.c_vision_clears #define the_your c_common_strings.c_the_your /* material strings */ E const char *materialnm[]; /* Monster name articles */ #define ARTICLE_NONE 0 #define ARTICLE_THE 1 #define ARTICLE_A 2 #define ARTICLE_YOUR 3 /* Monster name suppress masks */ #define SUPPRESS_IT 0x01 #define SUPPRESS_INVISIBLE 0x02 #define SUPPRESS_HALLUCINATION 0x04 #define SUPPRESS_SADDLE 0x08 #define EXACT_NAME 0x0F /* Vision */ E NEARDATA boolean vision_full_recalc; /* TRUE if need vision recalc */ E NEARDATA char **viz_array; /* could see/in sight row pointers */ /* Window system stuff */ E NEARDATA winid WIN_MESSAGE, WIN_STATUS; E NEARDATA winid WIN_MAP, WIN_INVEN; E char toplines[]; #ifndef TCAP_H E struct tc_gbl_data { /* also declared in tcap.h */ char *tc_AS, *tc_AE; /* graphics start and end (tty font swapping) */ int tc_LI, tc_CO; /* lines and columns */ } tc_gbl_data; #define AS tc_gbl_data.tc_AS #define AE tc_gbl_data.tc_AE #define LI tc_gbl_data.tc_LI #define CO tc_gbl_data.tc_CO #endif /* xxxexplain[] is in drawing.c */ E const char * const monexplain[], invisexplain[], * const objexplain[], * const oclass_names[]; /* Some systems want to use full pathnames for some subsets of file names, * rather than assuming that they're all in the current directory. This * provides all the subclasses that seem reasonable, and sets up for all * prefixes being null. Port code can set those that it wants. */ #define HACKPREFIX 0 #define LEVELPREFIX 1 #define SAVEPREFIX 2 #define BONESPREFIX 3 #define DATAPREFIX 4 /* this one must match hardcoded value in dlb.c */ #define SCOREPREFIX 5 #define LOCKPREFIX 6 #define CONFIGPREFIX 7 #define TROUBLEPREFIX 8 #define PREFIX_COUNT 9 /* used in files.c; xxconf.h can override if needed */ # ifndef FQN_MAX_FILENAME #define FQN_MAX_FILENAME 512 # endif #if defined(NOCWD_ASSUMPTIONS) || defined(VAR_PLAYGROUND) /* the bare-bones stuff is unconditional above to simplify coding; for * ports that actually use prefixes, add some more localized things */ #define PREFIXES_IN_USE #endif E char *fqn_prefix[PREFIX_COUNT]; #ifdef PREFIXES_IN_USE E char *fqn_prefix_names[PREFIX_COUNT]; #endif #ifdef AUTOPICKUP_EXCEPTIONS struct autopickup_exception { char *pattern; boolean grab; struct autopickup_exception *next; }; #endif /* AUTOPICKUP_EXCEPTIONS */ #undef E #endif /* DECL_H */ nethack-3.4.3/include/def_os2.h0100644000000000000000000001023307764735041014766 0ustar rootroot/* SCCS Id: @(#)def_os2.h 3.4 1993/01/19 */ /* Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* * Only a small portion of all OS/2 defines are needed, so the * actual include files often need not be used. In fact, * including the full headers may stall the compile in DOS. */ #ifdef OS2_USESYSHEADERS # define INCL_NOPMAPI # define INCL_DOSFILEMGR # define INCL_DOS # define INCL_SUB #include #else typedef char CHAR; typedef void VOID; typedef unsigned char UCHAR; typedef unsigned short USHORT; typedef unsigned int UINT; typedef unsigned long ULONG; typedef unsigned char BYTE; # ifdef OS2_32BITAPI typedef unsigned long SHANDLE; typedef USHORT HKBD; typedef USHORT HVIO; # define CCHMAXPATHCOMP 256 # ifdef OS2_CSET2 # define API16 _Far16 _Pascal # define DAT16 # define API32 _System # define KbdGetStatus KBD16GETSTATUS # define KbdSetStatus KBD16SETSTATUS # define KbdCharIn KBD16CHARIN # define KbdPeek KBD16PEEK # define VioGetMode VIO16GETMODE # define VioSetCurPos VIO16SETCURPOS # else # define API16 # define DAT16 # define API32 # endif # define DAT # else /* OS2_32BITAPI */ typedef unsigned short SHANDLE; typedef SHANDLE HKBD; typedef SHANDLE HVIO; # define CCHMAXPATHCOMP 13 # ifdef OS2_MSC # define API16 pascal far # define DAT16 # endif # define DAT DAT16 # endif /* OS2_32BITAPI */ typedef USHORT * DAT16 PUSHORT; typedef BYTE * DAT16 PBYTE; typedef ULONG * DAT PULONG; typedef VOID * DAT PVOID; typedef SHANDLE HDIR; typedef HDIR * DAT PHDIR; typedef char * DAT16 PCH; typedef char * DAT PSZ; /* all supported compilers understand this */ # pragma pack(2) typedef struct { UCHAR chChar; UCHAR chScan; UCHAR fbStatus; UCHAR bNlsShift; USHORT fsState; ULONG time; } KBDKEYINFO; typedef KBDKEYINFO * DAT16 PKBDKEYINFO; /* File time and date types */ typedef struct { UINT twosecs : 5; UINT minutes : 6; UINT hours : 5; } FTIME; typedef struct { UINT day : 5; UINT month : 4; UINT year : 7; } FDATE; # ifdef OS2_32BITAPI typedef struct { ULONG oNextEntryOffset; FDATE fdateCreation; FTIME ftimeCreation; FDATE fdateLastAccess; FTIME ftimeLastAccess; FDATE fdateLastWrite; FTIME ftimeLastWrite; ULONG cbFile; ULONG cbFileAlloc; ULONG attrFile; UCHAR cchName; CHAR achName[CCHMAXPATHCOMP]; } FILEFINDBUF3; # else typedef struct { FDATE fdateCreation; FTIME ftimeCreation; FDATE fdateLastAccess; FTIME ftimeLastAccess; FDATE fdateLastWrite; FTIME ftimeLastWrite; ULONG cbFile; ULONG cbFileAlloc; USHORT attrFile; UCHAR cchName; CHAR achName[CCHMAXPATHCOMP]; } FILEFINDBUF; typedef FILEFINDBUF * DAT16 PFILEFINDBUF; # endif /* OS2_32BITAPI */ typedef struct { ULONG idFileSystem; ULONG cSectorUnit; ULONG cUnit; ULONG cUnitAvail; USHORT cbSector; } FSALLOCATE; typedef struct { USHORT cb; USHORT fsMask; USHORT chTurnAround; USHORT fsInterim; USHORT fsState; } KBDINFO; typedef KBDINFO * DAT16 PKBDINFO; typedef struct { USHORT cb; UCHAR fbType; UCHAR color; USHORT col; USHORT row; USHORT hres; USHORT vres; UCHAR fmt_ID; UCHAR attrib; ULONG buf_addr; ULONG buf_length; ULONG full_length; ULONG partial_length; PCH ext_data_addr; } VIOMODEINFO; typedef VIOMODEINFO * DAT16 PVIOMODEINFO; # pragma pack() /* OS2 API functions */ USHORT API16 KbdGetStatus(PKBDINFO, HKBD); USHORT API16 KbdSetStatus(PKBDINFO, HKBD); USHORT API16 KbdCharIn(PKBDKEYINFO, USHORT, HKBD); USHORT API16 KbdPeek(PKBDKEYINFO, HKBD); USHORT API16 VioGetMode(PVIOMODEINFO, HVIO); USHORT API16 VioSetCurPos(USHORT, USHORT, HVIO); # ifdef OS2_32BITAPI ULONG API32 DosQueryFSInfo(ULONG, ULONG, PVOID, ULONG); ULONG API32 DosFindFirst(PSZ, PHDIR, ULONG, PVOID, ULONG, PULONG, ULONG); ULONG API32 DosFindNext(HDIR, PVOID, ULONG, PULONG); ULONG API32 DosSetDefaultDisk(ULONG); # else USHORT API16 DosQFSInfo(USHORT, USHORT, PBYTE, USHORT); USHORT API16 DosFindFirst(PSZ, PHDIR, USHORT, PFILEFINDBUF, USHORT, PUSHORT, ULONG); USHORT API16 DosFindNext(HDIR, PFILEFINDBUF, USHORT, PUSHORT); USHORT API16 DosSelectDisk(USHORT); # endif /* OS2_32BITAPI */ #endif /* OS2_USESYSHEADERS */ nethack-3.4.3/include/dgn_file.h0100644000000000000000000000314207764735041015215 0ustar rootroot/* SCCS Id: @(#)dgn_file.h 3.4 1993/01/17 */ /* Copyright (c) 1989 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DGN_FILE_H #define DGN_FILE_H #ifndef ALIGN_H #include "align.h" #endif /* * Structures manipulated by the dungeon loader & compiler */ struct couple { short base, rand; }; struct tmpdungeon { char name[24], protoname[24]; struct couple lev; int flags, chance, levels, branches, entry_lev; /* entry level for this dungeon */ char boneschar; }; struct tmplevel { char name[24]; struct couple lev; int chance, rndlevs, chain, flags; char boneschar; }; struct tmpbranch { char name[24]; /* destination dungeon name */ struct couple lev; int chain; /* index into tmplevel array (chained branch)*/ int type; /* branch type (see below) */ int up; /* branch is up or down */ }; /* * Values for type for tmpbranch structure. */ #define TBR_STAIR 0 /* connection with both ends having a staircase */ #define TBR_NO_UP 1 /* connection with no up staircase */ #define TBR_NO_DOWN 2 /* connection with no down staircase */ #define TBR_PORTAL 3 /* portal connection */ /* * Flags that map into the dungeon flags bitfields. */ #define TOWN 1 /* levels only */ #define HELLISH 2 #define MAZELIKE 4 #define ROGUELIKE 8 #define D_ALIGN_NONE 0 #define D_ALIGN_CHAOTIC (AM_CHAOTIC << 4) #define D_ALIGN_NEUTRAL (AM_NEUTRAL << 4) #define D_ALIGN_LAWFUL (AM_LAWFUL << 4) #define D_ALIGN_MASK 0x70 /* * Max number of prototype levels and branches. */ #define LEV_LIMIT 50 #define BRANCH_LIMIT 32 #endif /* DGN_FILE_H */ nethack-3.4.3/include/display.h0100644000000000000000000003444507764735041015125 0ustar rootroot/* SCCS Id: @(#)display.h 3.4 1999/11/30 */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DISPLAY_H #define DISPLAY_H #ifndef VISION_H #include "vision.h" #endif #ifndef MONDATA_H #include "mondata.h" /* for mindless() */ #endif #ifndef INVISIBLE_OBJECTS #define vobj_at(x,y) (level.objects[x][y]) #endif /* * sensemon() * * Returns true if the hero can sense the given monster. This includes * monsters that are hiding or mimicing other monsters. */ #define tp_sensemon(mon) ( /* The hero can always sense a monster IF: */\ (!mindless(mon->data)) && /* 1. the monster has a brain to sense AND */\ ((Blind && Blind_telepat) || /* 2a. hero is blind and telepathic OR */\ /* 2b. hero is using a telepathy inducing */\ /* object and in range */\ (Unblind_telepat && \ (distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM)))) \ ) #define sensemon(mon) (tp_sensemon(mon) || Detect_monsters || MATCH_WARN_OF_MON(mon)) /* * mon_warning() is used to warn of any dangerous monsters in your * vicinity, and a glyph representing the warning level is displayed. */ #define mon_warning(mon) (Warning && !(mon)->mpeaceful && \ (distu((mon)->mx, (mon)->my) < 100) && \ (((int) ((mon)->m_lev / 4)) >= flags.warnlevel)) /* * mon_visible() * * Returns true if the hero can see the monster. It is assumed that the * hero can physically see the location of the monster. The function * vobj_at() returns a pointer to an object that the hero can see there. * Infravision is not taken into account. */ #define mon_visible(mon) ( /* The hero can see the monster */\ /* IF the monster */\ (!mon->minvis || See_invisible) && /* 1. is not invisible AND */\ (!mon->mundetected) && /* 2. not an undetected hider */\ (!(mon->mburied || u.uburied)) /* 3. neither you or it is buried */\ ) /* * see_with_infrared() * * This function is true if the player can see a monster using infravision. * The caller must check for invisibility (invisible monsters are also * invisible to infravision), because this is usually called from within * canseemon() or canspotmon() which already check that. */ #define see_with_infrared(mon) (!Blind && Infravision && infravisible(mon->data) && couldsee(mon->mx, mon->my)) /* * canseemon() * * This is the globally used canseemon(). It is not called within the display * routines. Like mon_visible(), but it checks to see if the hero sees the * location instead of assuming it. (And also considers worms.) */ #define canseemon(mon) ((mon->wormno ? worm_known(mon) : \ (cansee(mon->mx, mon->my) || see_with_infrared(mon))) \ && mon_visible(mon)) /* * canspotmon(mon) * * This function checks whether you can either see a monster or sense it by * telepathy, and is what you usually call for monsters about which nothing is * known. */ #define canspotmon(mon) \ (canseemon(mon) || sensemon(mon)) /* knowninvisible(mon) * This one checks to see if you know a monster is both there and invisible. * 1) If you can see the monster and have see invisible, it is assumed the * monster is transparent, but visible in some manner. (Earlier versions of * Nethack were really inconsistent on this.) * 2) If you can't see the monster, but can see its location and you have * telepathy that works when you can see, you can tell that there is a * creature in an apparently empty spot. * Infravision is not relevant; we assume that invisible monsters are also * invisible to infravision. */ #define knowninvisible(mon) \ (mtmp->minvis && \ ((cansee(mon->mx, mon->my) && (See_invisible || Detect_monsters)) || \ (!Blind && (HTelepat & ~INTRINSIC) && \ distu(mon->mx, mon->my) <= (BOLT_LIM * BOLT_LIM) \ ) \ ) \ ) /* * is_safepet(mon) * * A special case check used in attack() and domove(). Placing the * definition here is convenient. */ #define is_safepet(mon) \ (mon && mon->mtame && canspotmon(mon) && flags.safe_dog \ && !Confusion && !Hallucination && !Stunned) /* * canseeself() * senseself() * * This returns true if the hero can see her/himself. * * The u.uswallow check assumes that you can see yourself even if you are * invisible. If not, then we don't need the check. */ #define canseeself() (Blind || u.uswallow || (!Invisible && !u.uundetected)) #define senseself() (canseeself() || Unblind_telepat || Detect_monsters) /* * random_monster() * random_object() * random_trap() * * Respectively return a random monster, object, or trap number. */ #define random_monster() rn2(NUMMONS) #define random_object() rn1(NUM_OBJECTS-1,1) #define random_trap() rn1(TRAPNUM-1,1) /* * what_obj() * what_mon() * what_trap() * * If hallucinating, choose a random object/monster, otherwise, use the one * given. */ #define what_obj(obj) (Hallucination ? random_object() : obj) #define what_mon(mon) (Hallucination ? random_monster() : mon) #define what_trap(trp) (Hallucination ? random_trap() : trp) /* * covers_objects() * covers_traps() * * These routines are true if what is really at the given location will * "cover" any objects or traps that might be there. */ #define covers_objects(xx,yy) \ ((is_pool(xx,yy) && !Underwater) || (levl[xx][yy].typ == LAVAPOOL)) #define covers_traps(xx,yy) covers_objects(xx,yy) /* * tmp_at() control calls. */ #define DISP_BEAM (-1) /* Keep all glyphs showing & clean up at end. */ #define DISP_FLASH (-2) /* Clean up each glyph before displaying new one. */ #define DISP_ALWAYS (-3) /* Like flash, but still displayed if not visible. */ #define DISP_CHANGE (-4) /* Change glyph. */ #define DISP_END (-5) /* Clean up. */ #define DISP_FREEMEM (-6) /* Free all memory during exit only. */ /* Total number of cmap indices in the sheild_static[] array. */ #define SHIELD_COUNT 21 /* * display_self() * * Display the hero. It is assumed that all checks necessary to determine * _if_ the hero can be seen have already been done. */ #ifdef STEED #define maybe_display_usteed (u.usteed && mon_visible(u.usteed)) ? \ ridden_mon_to_glyph(u.usteed) : #else #define maybe_display_usteed /* empty */ #endif #define display_self() \ show_glyph(u.ux, u.uy, \ maybe_display_usteed /* else */ \ youmonst.m_ap_type == M_AP_NOTHING ? \ hero_glyph : \ youmonst.m_ap_type == M_AP_FURNITURE ? \ cmap_to_glyph(youmonst.mappearance) : \ youmonst.m_ap_type == M_AP_OBJECT ? \ objnum_to_glyph(youmonst.mappearance) : \ /* else M_AP_MONSTER */ monnum_to_glyph(youmonst.mappearance)) /* * A glyph is an abstraction that represents a _unique_ monster, object, * dungeon part, or effect. The uniqueness is important. For example, * It is not enough to have four (one for each "direction") zap beam glyphs, * we need a set of four for each beam type. Why go to so much trouble? * Because it is possible that any given window dependent display driver * [print_glyph()] can produce something different for each type of glyph. * That is, a beam of cold and a beam of fire would not only be different * colors, but would also be represented by different symbols. * * Glyphs are grouped for easy accessibility: * * monster Represents all the wild (not tame) monsters. Count: NUMMONS. * * pet Represents all of the tame monsters. Count: NUMMONS * * invisible Invisible monster placeholder. Count: 1 * * detect Represents all detected monsters. Count: NUMMONS * * corpse One for each monster. Count: NUMMONS * * ridden Represents all monsters being ridden. Count: NUMMONS * * object One for each object. Count: NUM_OBJECTS * * cmap One for each entry in the character map. The character map * is the dungeon features and other miscellaneous things. * Count: MAXPCHARS * * explosions A set of nine for each of the following seven explosion types: * dark, noxious, muddy, wet, magical, fiery, frosty. * The nine positions represent those surrounding the hero. * Count: MAXEXPCHARS * EXPL_MAX (EXPL_MAX is defined in hack.h) * * zap beam A set of four (there are four directions) for each beam type. * The beam type is shifted over 2 positions and the direction * is stored in the lower 2 bits. Count: NUM_ZAP << 2 * * swallow A set of eight for each monster. The eight positions rep- * resent those surrounding the hero. The monster number is * shifted over 3 positions and the swallow position is stored * in the lower three bits. Count: NUMMONS << 3 * * warning A set of six representing the different warning levels. * * The following are offsets used to convert to and from a glyph. */ #define NUM_ZAP 8 /* number of zap beam types */ #define GLYPH_MON_OFF 0 #define GLYPH_PET_OFF (NUMMONS + GLYPH_MON_OFF) #define GLYPH_INVIS_OFF (NUMMONS + GLYPH_PET_OFF) #define GLYPH_DETECT_OFF (1 + GLYPH_INVIS_OFF) #define GLYPH_BODY_OFF (NUMMONS + GLYPH_DETECT_OFF) #define GLYPH_RIDDEN_OFF (NUMMONS + GLYPH_BODY_OFF) #define GLYPH_OBJ_OFF (NUMMONS + GLYPH_RIDDEN_OFF) #define GLYPH_CMAP_OFF (NUM_OBJECTS + GLYPH_OBJ_OFF) #define GLYPH_EXPLODE_OFF ((MAXPCHARS - MAXEXPCHARS) + GLYPH_CMAP_OFF) #define GLYPH_ZAP_OFF ((MAXEXPCHARS * EXPL_MAX) + GLYPH_EXPLODE_OFF) #define GLYPH_SWALLOW_OFF ((NUM_ZAP << 2) + GLYPH_ZAP_OFF) #define GLYPH_WARNING_OFF ((NUMMONS << 3) + GLYPH_SWALLOW_OFF) #define MAX_GLYPH (WARNCOUNT + GLYPH_WARNING_OFF) #define NO_GLYPH MAX_GLYPH #define GLYPH_INVISIBLE GLYPH_INVIS_OFF #define warning_to_glyph(mwarnlev) ((mwarnlev)+GLYPH_WARNING_OFF) #define mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_MON_OFF) #define detected_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_DETECT_OFF) #define ridden_mon_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_RIDDEN_OFF) #define pet_to_glyph(mon) ((int) what_mon(monsndx((mon)->data))+GLYPH_PET_OFF) /* This has the unfortunate side effect of needing a global variable */ /* to store a result. 'otg_temp' is defined and declared in decl.{ch}. */ #define obj_to_glyph(obj) \ (Hallucination ? \ ((otg_temp = random_object()) == CORPSE ? \ random_monster() + GLYPH_BODY_OFF : \ otg_temp + GLYPH_OBJ_OFF) : \ ((obj)->otyp == CORPSE ? \ (int) (obj)->corpsenm + GLYPH_BODY_OFF : \ (int) (obj)->otyp + GLYPH_OBJ_OFF)) #define cmap_to_glyph(cmap_idx) ((int) (cmap_idx) + GLYPH_CMAP_OFF) #define explosion_to_glyph(expltype,idx) \ ((((expltype) * MAXEXPCHARS) + ((idx) - S_explode1)) + GLYPH_EXPLODE_OFF) #define trap_to_glyph(trap) \ cmap_to_glyph(trap_to_defsym(what_trap((trap)->ttyp))) /* Not affected by hallucination. Gives a generic body for CORPSE */ #define objnum_to_glyph(onum) ((int) (onum) + GLYPH_OBJ_OFF) #define monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_MON_OFF) #define detected_monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_DETECT_OFF) #define ridden_monnum_to_glyph(mnum) ((int) (mnum) + GLYPH_RIDDEN_OFF) #define petnum_to_glyph(mnum) ((int) (mnum) + GLYPH_PET_OFF) /* The hero's glyph when seen as a monster. */ #define hero_glyph \ monnum_to_glyph((Upolyd || !iflags.showrace) ? u.umonnum : \ (flags.female && urace.femalenum != NON_PM) ? urace.femalenum : \ urace.malenum) /* * Change the given glyph into it's given type. Note: * 1) Pets, detected, and ridden monsters are animals and are converted * to the proper monster number. * 2) Bodies are all mapped into the generic CORPSE object * 3) If handed a glyph out of range for the type, these functions * will return NO_GLYPH (see exception below) * 4) glyph_to_swallow() does not return a showsyms[] index, but an * offset from the first swallow symbol. If handed something * out of range, it will return zero (for lack of anything better * to return). */ #define glyph_to_mon(glyph) \ (glyph_is_normal_monster(glyph) ? ((glyph)-GLYPH_MON_OFF) : \ glyph_is_pet(glyph) ? ((glyph)-GLYPH_PET_OFF) : \ glyph_is_detected_monster(glyph) ? ((glyph)-GLYPH_DETECT_OFF) : \ glyph_is_ridden_monster(glyph) ? ((glyph)-GLYPH_RIDDEN_OFF) : \ NO_GLYPH) #define glyph_to_obj(glyph) \ (glyph_is_body(glyph) ? CORPSE : \ glyph_is_normal_object(glyph) ? ((glyph)-GLYPH_OBJ_OFF) : \ NO_GLYPH) #define glyph_to_trap(glyph) \ (glyph_is_trap(glyph) ? \ ((int) defsym_to_trap((glyph) - GLYPH_CMAP_OFF)) : \ NO_GLYPH) #define glyph_to_cmap(glyph) \ (glyph_is_cmap(glyph) ? ((glyph) - GLYPH_CMAP_OFF) : \ NO_GLYPH) #define glyph_to_swallow(glyph) \ (glyph_is_swallow(glyph) ? (((glyph) - GLYPH_SWALLOW_OFF) & 0x7) : \ 0) #define glyph_to_warning(glyph) \ (glyph_is_warning(glyph) ? ((glyph) - GLYPH_WARNING_OFF) : \ NO_GLYPH); /* * Return true if the given glyph is what we want. Note that bodies are * considered objects. */ #define glyph_is_monster(glyph) \ (glyph_is_normal_monster(glyph) \ || glyph_is_pet(glyph) \ || glyph_is_ridden_monster(glyph) \ || glyph_is_detected_monster(glyph)) #define glyph_is_normal_monster(glyph) \ ((glyph) >= GLYPH_MON_OFF && (glyph) < (GLYPH_MON_OFF+NUMMONS)) #define glyph_is_pet(glyph) \ ((glyph) >= GLYPH_PET_OFF && (glyph) < (GLYPH_PET_OFF+NUMMONS)) #define glyph_is_body(glyph) \ ((glyph) >= GLYPH_BODY_OFF && (glyph) < (GLYPH_BODY_OFF+NUMMONS)) #define glyph_is_ridden_monster(glyph) \ ((glyph) >= GLYPH_RIDDEN_OFF && (glyph) < (GLYPH_RIDDEN_OFF+NUMMONS)) #define glyph_is_detected_monster(glyph) \ ((glyph) >= GLYPH_DETECT_OFF && (glyph) < (GLYPH_DETECT_OFF+NUMMONS)) #define glyph_is_invisible(glyph) ((glyph) == GLYPH_INVISIBLE) #define glyph_is_normal_object(glyph) \ ((glyph) >= GLYPH_OBJ_OFF && (glyph) < (GLYPH_OBJ_OFF+NUM_OBJECTS)) #define glyph_is_object(glyph) \ (glyph_is_normal_object(glyph) \ || glyph_is_body(glyph)) #define glyph_is_trap(glyph) \ ((glyph) >= (GLYPH_CMAP_OFF+trap_to_defsym(1)) && \ (glyph) < (GLYPH_CMAP_OFF+trap_to_defsym(1)+TRAPNUM)) #define glyph_is_cmap(glyph) \ ((glyph) >= GLYPH_CMAP_OFF && (glyph) < (GLYPH_CMAP_OFF+MAXPCHARS)) #define glyph_is_swallow(glyph) \ ((glyph) >= GLYPH_SWALLOW_OFF && (glyph) < (GLYPH_SWALLOW_OFF+(NUMMONS << 3))) #define glyph_is_warning(glyph) \ ((glyph) >= GLYPH_WARNING_OFF && (glyph) < (GLYPH_WARNING_OFF + WARNCOUNT)) #endif /* DISPLAY_H */ nethack-3.4.3/include/dlb.h0100644000000000000000000000704207764735041014212 0ustar rootroot/* SCCS Id: @(#)dlb.h 3.4 1997/07/29 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DLB_H #define DLB_H /* definitions for data library */ #ifdef DLB /* implementations */ #ifdef MAC # define DLBRSRC /* use Mac resources */ #else # define DLBLIB /* use a set of external files */ #endif #ifdef DLBLIB /* directory structure in memory */ typedef struct dlb_directory { char *fname; /* file name as seen from calling code */ long foffset; /* offset in lib file to start of this file */ long fsize; /* file size */ char handling; /* how to handle the file (compression, etc) */ } libdir; /* information about each open library */ typedef struct dlb_library { FILE *fdata; /* opened data file */ long fmark; /* current file mark */ libdir *dir; /* directory of library file */ char *sspace; /* pointer to string space */ long nentries; /* # of files in directory */ long rev; /* dlb file revision */ long strsize; /* dlb file string size */ } library; /* library definitions */ # ifndef DLBFILE # define DLBFILE "nhdat" /* name of library */ # endif # ifndef FILENAME_CMP # define FILENAME_CMP strcmp /* case sensitive */ # endif #endif /* DLBLIB */ typedef struct dlb_handle { FILE *fp; /* pointer to an external file, use if non-null */ #ifdef DLBLIB library *lib; /* pointer to library structure */ long start; /* offset of start of file */ long size; /* size of file */ long mark; /* current file marker */ #endif #ifdef DLBRSRC int fd; /* HandleFile file descriptor */ #endif } dlb; #if defined(ULTRIX_PROTO) && !defined(__STDC__) /* buggy old Ultrix compiler wants this for the (*dlb_fread_proc) and (*dlb_fgets_proc) prototypes in struct dlb_procs (dlb.c); we'll use it in all the declarations for consistency */ #define DLB_P struct dlb_handle * #else #define DLB_P dlb * #endif boolean NDECL(dlb_init); void NDECL(dlb_cleanup); dlb *FDECL(dlb_fopen, (const char *,const char *)); int FDECL(dlb_fclose, (DLB_P)); int FDECL(dlb_fread, (char *,int,int,DLB_P)); int FDECL(dlb_fseek, (DLB_P,long,int)); char *FDECL(dlb_fgets, (char *,int,DLB_P)); int FDECL(dlb_fgetc, (DLB_P)); long FDECL(dlb_ftell, (DLB_P)); /* Resource DLB entry points */ #ifdef DLBRSRC boolean rsrc_dlb_init(void); void rsrc_dlb_cleanup(void); boolean rsrc_dlb_fopen(dlb *dp, const char *name, const char *mode); int rsrc_dlb_fclose(dlb *dp); int rsrc_dlb_fread(char *buf, int size, int quan, dlb *dp); int rsrc_dlb_fseek(dlb *dp, long pos, int whence); char *rsrc_dlb_fgets(char *buf, int len, dlb *dp); int rsrc_dlb_fgetc(dlb *dp); long rsrc_dlb_ftell(dlb *dp); #endif #else /* DLB */ # define dlb FILE # define dlb_init() # define dlb_cleanup() # define dlb_fopen fopen # define dlb_fclose fclose # define dlb_fread fread # define dlb_fseek fseek # define dlb_fgets fgets # define dlb_fgetc fgetc # define dlb_ftell ftell #endif /* DLB */ /* various other I/O stuff we don't want to replicate everywhere */ #ifndef SEEK_SET # define SEEK_SET 0 #endif #ifndef SEEK_CUR # define SEEK_CUR 1 #endif #ifndef SEEK_END # define SEEK_END 2 #endif #define RDTMODE "r" #if (defined(MSDOS) || defined(WIN32) || defined(TOS) || defined(OS2)) && defined(DLB) #define WRTMODE "w+b" #else #define WRTMODE "w+" #endif #if (defined(MICRO) && !defined(AMIGA)) || defined(THINK_C) || defined(__MWERKS__) || defined(WIN32) # define RDBMODE "rb" # define WRBMODE "w+b" #else # define RDBMODE "r" # define WRBMODE "w+" #endif #endif /* DLB_H */ nethack-3.4.3/include/dungeon.h0100644000000000000000000001440707764735041015113 0ustar rootroot/* SCCS Id: @(#)dungeon.h 3.4 1999/07/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef DUNGEON_H #define DUNGEON_H typedef struct d_flags { /* dungeon/level type flags */ Bitfield(town, 1); /* is this a town? (levels only) */ Bitfield(hellish, 1); /* is this part of hell? */ Bitfield(maze_like, 1); /* is this a maze? */ Bitfield(rogue_like, 1); /* is this an old-fashioned presentation? */ Bitfield(align, 3); /* dungeon alignment. */ Bitfield(unused, 1); /* etc... */ } d_flags; typedef struct d_level { /* basic dungeon level element */ xchar dnum; /* dungeon number */ xchar dlevel; /* level number */ } d_level; typedef struct s_level { /* special dungeon level element */ struct s_level *next; d_level dlevel; /* dungeon & level numbers */ char proto[15]; /* name of prototype file (eg. "tower") */ char boneid; /* character to id level in bones files */ uchar rndlevs; /* no. of randomly available similar levels */ d_flags flags; /* type flags */ } s_level; typedef struct stairway { /* basic stairway identifier */ xchar sx, sy; /* x / y location of the stair */ d_level tolev; /* where does it go */ char up; /* what type of stairway (up/down) */ } stairway; /* level region types */ #define LR_DOWNSTAIR 0 #define LR_UPSTAIR 1 #define LR_PORTAL 2 #define LR_BRANCH 3 #define LR_TELE 4 #define LR_UPTELE 5 #define LR_DOWNTELE 6 typedef struct dest_area { /* non-stairway level change indentifier */ xchar lx, ly; /* "lower" left corner (near [0,0]) */ xchar hx, hy; /* "upper" right corner (near [COLNO,ROWNO]) */ xchar nlx, nly; /* outline of invalid area */ xchar nhx, nhy; /* opposite corner of invalid area */ } dest_area; typedef struct dungeon { /* basic dungeon identifier */ char dname[24]; /* name of the dungeon (eg. "Hell") */ char proto[15]; /* name of prototype file (eg. "tower") */ char boneid; /* character to id dungeon in bones files */ d_flags flags; /* dungeon flags */ xchar entry_lev; /* entry level */ xchar num_dunlevs; /* number of levels in this dungeon */ xchar dunlev_ureached; /* how deep you have been in this dungeon */ int ledger_start, /* the starting depth in "real" terms */ depth_start; /* the starting depth in "logical" terms */ } dungeon; /* * A branch structure defines the connection between two dungeons. They * will be ordered by the dungeon number/level number of 'end1'. Ties * are resolved by 'end2'. 'Type' uses 'end1' arbitrarily as the primary * point. */ typedef struct branch { struct branch *next; /* next in the branch chain */ int id; /* branch identifier */ int type; /* type of branch */ d_level end1; /* "primary" end point */ d_level end2; /* other end point */ boolean end1_up; /* does end1 go up? */ } branch; /* branch types */ #define BR_STAIR 0 /* "Regular" connection, 2 staircases. */ #define BR_NO_END1 1 /* "Regular" connection. However, no stair from */ /* end1 to end2. There is a stair from end2 */ /* to end1. */ #define BR_NO_END2 2 /* "Regular" connection. However, no stair from */ /* end2 to end1. There is a stair from end1 */ /* to end2. */ #define BR_PORTAL 3 /* Connection by magic portals (traps) */ /* A particular dungeon contains num_dunlevs d_levels with dlevel 1.. * num_dunlevs. Ledger_start and depth_start are bases that are added * to the dlevel of a particular d_level to get the effective ledger_no * and depth for that d_level. * * Ledger_no is a bookkeeping number that gives a unique identifier for a * particular d_level (for level.?? files, e.g.). * * Depth corresponds to the number of floors below the surface. */ #define Is_astralevel(x) (on_level(x, &astral_level)) #define Is_earthlevel(x) (on_level(x, &earth_level)) #define Is_waterlevel(x) (on_level(x, &water_level)) #define Is_firelevel(x) (on_level(x, &fire_level)) #define Is_airlevel(x) (on_level(x, &air_level)) #define Is_medusa_level(x) (on_level(x, &medusa_level)) #define Is_oracle_level(x) (on_level(x, &oracle_level)) #define Is_valley(x) (on_level(x, &valley_level)) #define Is_juiblex_level(x) (on_level(x, &juiblex_level)) #define Is_asmo_level(x) (on_level(x, &asmodeus_level)) #define Is_baal_level(x) (on_level(x, &baalzebub_level)) #define Is_wiz1_level(x) (on_level(x, &wiz1_level)) #define Is_wiz2_level(x) (on_level(x, &wiz2_level)) #define Is_wiz3_level(x) (on_level(x, &wiz3_level)) #define Is_sanctum(x) (on_level(x, &sanctum_level)) #define Is_portal_level(x) (on_level(x, &portal_level)) #define Is_rogue_level(x) (on_level(x, &rogue_level)) #define Is_stronghold(x) (on_level(x, &stronghold_level)) #define Is_bigroom(x) (on_level(x, &bigroom_level)) #define Is_qstart(x) (on_level(x, &qstart_level)) #define Is_qlocate(x) (on_level(x, &qlocate_level)) #define Is_nemesis(x) (on_level(x, &nemesis_level)) #define Is_knox(x) (on_level(x, &knox_level)) #define In_sokoban(x) ((x)->dnum == sokoban_dnum) #define Inhell In_hell(&u.uz) /* now gehennom */ #define In_endgame(x) ((x)->dnum == astral_level.dnum) #define within_bounded_area(X,Y,LX,LY,HX,HY) \ ((X) >= (LX) && (X) <= (HX) && (Y) >= (LY) && (Y) <= (HY)) /* monster and object migration codes */ #define MIGR_NOWHERE (-1) /* failure flag for down_gate() */ #define MIGR_RANDOM 0 #define MIGR_APPROX_XY 1 /* approximate coordinates */ #define MIGR_EXACT_XY 2 /* specific coordinates */ #define MIGR_STAIRS_UP 3 #define MIGR_STAIRS_DOWN 4 #define MIGR_LADDER_UP 5 #define MIGR_LADDER_DOWN 6 #define MIGR_SSTAIRS 7 /* dungeon branch */ #define MIGR_PORTAL 8 /* magic portal */ #define MIGR_NEAR_PLAYER 9 /* mon: followers; obj: trap door */ /* level information (saved via ledger number) */ struct linfo { unsigned char flags; #define VISITED 0x01 /* hero has visited this level */ #define FORGOTTEN 0x02 /* hero will forget this level when reached */ #define LFILE_EXISTS 0x04 /* a level file exists for this level */ /* * Note: VISITED and LFILE_EXISTS are currently almost always set at the * same time. However they _mean_ different things. */ #ifdef MFLOPPY # define FROMPERM 1 /* for ramdisk use */ # define TOPERM 2 /* for ramdisk use */ # define ACTIVE 1 # define SWAPPED 2 int where; long time; long size; #endif /* MFLOPPY */ }; #endif /* DUNGEON_H */ nethack-3.4.3/include/edog.h0100644000000000000000000000174007764735041014366 0ustar rootroot/* SCCS Id: @(#)edog.h 3.4 1997/10/23 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef EDOG_H #define EDOG_H /* various types of food, the lower, the better liked. */ #define DOGFOOD 0 #define CADAVER 1 #define ACCFOOD 2 #define MANFOOD 3 #define APPORT 4 #define POISON 5 #define UNDEF 6 #define TABU 7 struct edog { long droptime; /* moment dog dropped object */ unsigned dropdist; /* dist of drpped obj from @ */ int apport; /* amount of training */ long whistletime; /* last time he whistled */ long hungrytime; /* will get hungry at this time */ coord ogoal; /* previous goal location */ int abuse; /* track abuses to this pet */ int revivals; /* count pet deaths */ int mhpmax_penalty; /* while starving, points reduced */ Bitfield(killed_by_u, 1); /* you attempted to kill him */ }; #define EDOG(mon) ((struct edog *)&(mon)->mextra[0]) #endif /* EDOG_H */ nethack-3.4.3/include/emin.h0100644000000000000000000000050507764735041014376 0ustar rootroot/* SCCS Id: @(#)emin.h 3.4 1997/05/01 */ /* Copyright (c) David Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef EMIN_H #define EMIN_H struct emin { aligntyp min_align; /* alignment of minion */ }; #define EMIN(mon) ((struct emin *)&(mon)->mextra[0]) #endif /* EMIN_H */ nethack-3.4.3/include/engrave.h0100644000000000000000000000135307764735041015077 0ustar rootroot/* SCCS Id: @(#)engrave.h 3.4 1991/07/31 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef ENGRAVE_H #define ENGRAVE_H struct engr { struct engr *nxt_engr; char *engr_txt; xchar engr_x, engr_y; unsigned engr_lth; /* for save & restore; not length of text */ long engr_time; /* moment engraving was (will be) finished */ xchar engr_type; #define DUST 1 #define ENGRAVE 2 #define BURN 3 #define MARK 4 #define ENGR_BLOOD 5 #define HEADSTONE 6 #define N_ENGRAVE 6 }; #define newengr(lth) (struct engr *)alloc((unsigned)(lth) + sizeof(struct engr)) #define dealloc_engr(engr) free((genericptr_t) (engr)) #endif /* ENGRAVE_H */ nethack-3.4.3/include/epri.h0100644000000000000000000000130707764735041014406 0ustar rootroot/* SCCS Id: @(#)epri.h 3.4 1997/05/01 */ /* Copyright (c) Izchak Miller, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef EPRI_H #define EPRI_H struct epri { aligntyp shralign; /* alignment of priest's shrine */ /* leave as first field to match emin */ schar shroom; /* index in rooms */ coord shrpos; /* position of shrine */ d_level shrlevel; /* level (& dungeon) of shrine */ }; #define EPRI(mon) ((struct epri *)&(mon)->mextra[0]) /* A priest without ispriest is a roaming priest without a shrine, so * the fields (except shralign, which becomes only the priest alignment) * are available for reuse. */ #define renegade shroom #endif /* EPRI_H */ nethack-3.4.3/include/eshk.h0100644000000000000000000000271507764735041014405 0ustar rootroot/* SCCS Id: @(#)eshk.h 3.4 1997/05/01 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef ESHK_H #define ESHK_H #define REPAIR_DELAY 5 /* minimum delay between shop damage & repair */ #define BILLSZ 200 struct bill_x { unsigned bo_id; boolean useup; long price; /* price per unit */ long bquan; /* amount used up */ }; struct eshk { long robbed; /* amount stolen by most recent customer */ long credit; /* amount credited to customer */ long debit; /* amount of debt for using unpaid items */ long loan; /* shop-gold picked (part of debit) */ int shoptype; /* the value of rooms[shoproom].rtype */ schar shoproom; /* index in rooms; set by inshop() */ schar unused; /* to force alignment for stupid compilers */ boolean following; /* following customer since he owes us sth */ boolean surcharge; /* angry shk inflates prices */ coord shk; /* usual position shopkeeper */ coord shd; /* position shop door */ d_level shoplevel; /* level (& dungeon) of his shop */ int billct; /* no. of entries of bill[] in use */ struct bill_x bill[BILLSZ]; struct bill_x *bill_p; int visitct; /* nr of visits by most recent customer */ char customer[PL_NSIZ]; /* most recent customer */ char shknam[PL_NSIZ]; }; #define ESHK(mon) ((struct eshk *)&(mon)->mextra[0]) #define NOTANGRY(mon) ((mon)->mpeaceful) #define ANGRY(mon) (!NOTANGRY(mon)) #endif /* ESHK_H */ nethack-3.4.3/include/extern.h0100644000000000000000000023402407764735041014760 0ustar rootroot/* SCCS Id: @(#)extern.h 3.4 2003/03/10 */ /* Copyright (c) Steve Creps, 1988. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef EXTERN_H #define EXTERN_H #define E extern /* ### alloc.c ### */ #if 0 E long *FDECL(alloc, (unsigned int)); #endif E char *FDECL(fmt_ptr, (const genericptr,char *)); /* This next pre-processor directive covers almost the entire file, * interrupted only occasionally to pick up specific functions as needed. */ #if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C) /* ### allmain.c ### */ E void NDECL(moveloop); E void NDECL(stop_occupation); E void NDECL(display_gamewindows); E void NDECL(newgame); E void FDECL(welcome, (BOOLEAN_P)); /* ### apply.c ### */ E int NDECL(doapply); E int NDECL(dorub); E int NDECL(dojump); E int FDECL(jump, (int)); E int NDECL(number_leashed); E void FDECL(o_unleash, (struct obj *)); E void FDECL(m_unleash, (struct monst *,BOOLEAN_P)); E void NDECL(unleash_all); E boolean NDECL(next_to_u); E struct obj *FDECL(get_mleash, (struct monst *)); E void FDECL(check_leash, (XCHAR_P,XCHAR_P)); E boolean FDECL(um_dist, (XCHAR_P,XCHAR_P,XCHAR_P)); E boolean FDECL(snuff_candle, (struct obj *)); E boolean FDECL(snuff_lit, (struct obj *)); E boolean FDECL(catch_lit, (struct obj *)); E void FDECL(use_unicorn_horn, (struct obj *)); E boolean FDECL(tinnable, (struct obj *)); E void NDECL(reset_trapset); E void FDECL(fig_transform, (genericptr_t, long)); E int FDECL(unfixable_trouble_count,(BOOLEAN_P)); /* ### artifact.c ### */ E void NDECL(init_artifacts); E void FDECL(save_artifacts, (int)); E void FDECL(restore_artifacts, (int)); E const char *FDECL(artiname, (int)); E struct obj *FDECL(mk_artifact, (struct obj *,ALIGNTYP_P)); E const char *FDECL(artifact_name, (const char *,short *)); E boolean FDECL(exist_artifact, (int,const char *)); E void FDECL(artifact_exists, (struct obj *,const char *,BOOLEAN_P)); E int NDECL(nartifact_exist); E boolean FDECL(spec_ability, (struct obj *,unsigned long)); E boolean FDECL(confers_luck, (struct obj *)); E boolean FDECL(arti_reflects, (struct obj *)); E boolean FDECL(restrict_name, (struct obj *,const char *)); E boolean FDECL(defends, (int,struct obj *)); E boolean FDECL(protects, (int,struct obj *)); E void FDECL(set_artifact_intrinsic, (struct obj *,BOOLEAN_P,long)); E int FDECL(touch_artifact, (struct obj *,struct monst *)); E int FDECL(spec_abon, (struct obj *,struct monst *)); E int FDECL(spec_dbon, (struct obj *,struct monst *,int)); E void FDECL(discover_artifact, (XCHAR_P)); E boolean FDECL(undiscovered_artifact, (XCHAR_P)); E int FDECL(disp_artifact_discoveries, (winid)); E boolean FDECL(artifact_hit, (struct monst *,struct monst *, struct obj *,int *,int)); E int NDECL(doinvoke); E void FDECL(arti_speak, (struct obj *)); E boolean FDECL(artifact_light, (struct obj *)); E long FDECL(spec_m2, (struct obj *)); E boolean FDECL(artifact_has_invprop, (struct obj *,UCHAR_P)); E long FDECL(arti_cost, (struct obj *)); /* ### attrib.c ### */ E boolean FDECL(adjattrib, (int,int,int)); E void FDECL(change_luck, (SCHAR_P)); E int FDECL(stone_luck, (BOOLEAN_P)); E void NDECL(set_moreluck); E void FDECL(gainstr, (struct obj *,int)); E void FDECL(losestr, (int)); E void NDECL(restore_attrib); E void FDECL(exercise, (int,BOOLEAN_P)); E void NDECL(exerchk); E void NDECL(reset_attribute_clock); E void FDECL(init_attr, (int)); E void NDECL(redist_attr); E void FDECL(adjabil, (int,int)); E int NDECL(newhp); E schar FDECL(acurr, (int)); E schar NDECL(acurrstr); E void FDECL(adjalign, (int)); /* ### ball.c ### */ E void NDECL(ballfall); E void NDECL(placebc); E void NDECL(unplacebc); E void FDECL(set_bc, (int)); E void FDECL(move_bc, (int,int,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); E boolean FDECL(drag_ball, (XCHAR_P,XCHAR_P, int *,xchar *,xchar *,xchar *,xchar *, boolean *,BOOLEAN_P)); E void FDECL(drop_ball, (XCHAR_P,XCHAR_P)); E void NDECL(drag_down); /* ### bones.c ### */ E boolean NDECL(can_make_bones); E void FDECL(savebones, (struct obj *)); E int NDECL(getbones); /* ### botl.c ### */ E int FDECL(xlev_to_rank, (int)); E int FDECL(title_to_mon, (const char *,int *,int *)); E void NDECL(max_rank_sz); #ifdef SCORE_ON_BOTL E long NDECL(botl_score); #endif E int FDECL(describe_level, (char *)); E const char *FDECL(rank_of, (int,SHORT_P,BOOLEAN_P)); E void NDECL(bot); /* ### cmd.c ### */ #ifdef USE_TRAMPOLI E int NDECL(doextcmd); E int NDECL(domonability); E int NDECL(doprev_message); E int NDECL(timed_occupation); E int NDECL(wiz_attributes); E int NDECL(enter_explore_mode); # ifdef WIZARD E int NDECL(wiz_detect); E int NDECL(wiz_genesis); E int NDECL(wiz_identify); E int NDECL(wiz_level_tele); E int NDECL(wiz_map); E int NDECL(wiz_where); E int NDECL(wiz_wish); # endif /* WIZARD */ #endif /* USE_TRAMPOLI */ E void NDECL(reset_occupations); E void FDECL(set_occupation, (int (*)(void),const char *,int)); #ifdef REDO E char NDECL(pgetchar); E void FDECL(pushch, (CHAR_P)); E void FDECL(savech, (CHAR_P)); #endif #ifdef WIZARD E void NDECL(add_debug_extended_commands); #endif /* WIZARD */ E void FDECL(rhack, (char *)); E int NDECL(doextlist); E int NDECL(extcmd_via_menu); E void FDECL(enlightenment, (int)); E void FDECL(show_conduct, (int)); E int FDECL(xytod, (SCHAR_P,SCHAR_P)); E void FDECL(dtoxy, (coord *,int)); E int FDECL(movecmd, (CHAR_P)); E int FDECL(getdir, (const char *)); E void NDECL(confdir); E int FDECL(isok, (int,int)); E int FDECL(get_adjacent_loc, (const char *, const char *, XCHAR_P, XCHAR_P, coord *)); E const char *FDECL(click_to_cmd, (int,int,int)); E char NDECL(readchar); #ifdef WIZARD E void NDECL(sanity_check); #endif E char FDECL(yn_function, (const char *, const char *, CHAR_P)); /* ### dbridge.c ### */ E boolean FDECL(is_pool, (int,int)); E boolean FDECL(is_lava, (int,int)); E boolean FDECL(is_ice, (int,int)); E int FDECL(is_drawbridge_wall, (int,int)); E boolean FDECL(is_db_wall, (int,int)); E boolean FDECL(find_drawbridge, (int *,int*)); E boolean FDECL(create_drawbridge, (int,int,int,BOOLEAN_P)); E void FDECL(open_drawbridge, (int,int)); E void FDECL(close_drawbridge, (int,int)); E void FDECL(destroy_drawbridge, (int,int)); /* ### decl.c ### */ E void NDECL(decl_init); /* ### detect.c ### */ E struct obj *FDECL(o_in, (struct obj*,CHAR_P)); E struct obj *FDECL(o_material, (struct obj*,unsigned)); E int FDECL(gold_detect, (struct obj *)); E int FDECL(food_detect, (struct obj *)); E int FDECL(object_detect, (struct obj *,int)); E int FDECL(monster_detect, (struct obj *,int)); E int FDECL(trap_detect, (struct obj *)); E const char *FDECL(level_distance, (d_level *)); E void FDECL(use_crystal_ball, (struct obj *)); E void NDECL(do_mapping); E void NDECL(do_vicinity_map); E void FDECL(cvt_sdoor_to_door, (struct rm *)); #ifdef USE_TRAMPOLI E void FDECL(findone, (int,int,genericptr_t)); E void FDECL(openone, (int,int,genericptr_t)); #endif E int NDECL(findit); E int NDECL(openit); E void FDECL(find_trap, (struct trap *)); E int FDECL(dosearch0, (int)); E int NDECL(dosearch); E void NDECL(sokoban_detect); /* ### dig.c ### */ E boolean NDECL(is_digging); #ifdef USE_TRAMPOLI E int NDECL(dig); #endif E int NDECL(holetime); E boolean FDECL(dig_check, (struct monst *, BOOLEAN_P, int, int)); E void FDECL(digactualhole, (int,int,struct monst *,int)); E boolean FDECL(dighole, (BOOLEAN_P)); E int FDECL(use_pick_axe, (struct obj *)); E int FDECL(use_pick_axe2, (struct obj *)); E boolean FDECL(mdig_tunnel, (struct monst *)); E void FDECL(watch_dig, (struct monst *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E void NDECL(zap_dig); E struct obj *FDECL(bury_an_obj, (struct obj *)); E void FDECL(bury_objs, (int,int)); E void FDECL(unearth_objs, (int,int)); E void FDECL(rot_organic, (genericptr_t, long)); E void FDECL(rot_corpse, (genericptr_t, long)); #if 0 E void FDECL(bury_monst, (struct monst *)); E void NDECL(bury_you); E void NDECL(unearth_you); E void NDECL(escape_tomb); E void FDECL(bury_obj, (struct obj *)); #endif /* ### display.c ### */ #ifdef INVISIBLE_OBJECTS E struct obj * FDECL(vobj_at, (XCHAR_P,XCHAR_P)); #endif /* INVISIBLE_OBJECTS */ E void FDECL(magic_map_background, (XCHAR_P,XCHAR_P,int)); E void FDECL(map_background, (XCHAR_P,XCHAR_P,int)); E void FDECL(map_trap, (struct trap *,int)); E void FDECL(map_object, (struct obj *,int)); E void FDECL(map_invisible, (XCHAR_P,XCHAR_P)); E void FDECL(unmap_object, (int,int)); E void FDECL(map_location, (int,int,int)); E void FDECL(feel_location, (XCHAR_P,XCHAR_P)); E void FDECL(newsym, (int,int)); E void FDECL(shieldeff, (XCHAR_P,XCHAR_P)); E void FDECL(tmp_at, (int,int)); E void FDECL(swallowed, (int)); E void FDECL(under_ground, (int)); E void FDECL(under_water, (int)); E void NDECL(see_monsters); E void NDECL(set_mimic_blocking); E void NDECL(see_objects); E void NDECL(see_traps); E void NDECL(curs_on_u); E int NDECL(doredraw); E void NDECL(docrt); E void FDECL(show_glyph, (int,int,int)); E void NDECL(clear_glyph_buffer); E void FDECL(row_refresh, (int,int,int)); E void NDECL(cls); E void FDECL(flush_screen, (int)); E int FDECL(back_to_glyph, (XCHAR_P,XCHAR_P)); E int FDECL(zapdir_to_glyph, (int,int,int)); E int FDECL(glyph_at, (XCHAR_P,XCHAR_P)); E void NDECL(set_wall_state); /* ### do.c ### */ #ifdef USE_TRAMPOLI E int FDECL(drop, (struct obj *)); E int NDECL(wipeoff); #endif E int NDECL(dodrop); E boolean FDECL(boulder_hits_pool, (struct obj *,int,int,BOOLEAN_P)); E boolean FDECL(flooreffects, (struct obj *,int,int,const char *)); E void FDECL(doaltarobj, (struct obj *)); E boolean FDECL(canletgo, (struct obj *,const char *)); E void FDECL(dropx, (struct obj *)); E void FDECL(dropy, (struct obj *)); E void FDECL(obj_no_longer_held, (struct obj *)); E int NDECL(doddrop); E int NDECL(dodown); E int NDECL(doup); #ifdef INSURANCE E void NDECL(save_currentstate); #endif E void FDECL(goto_level, (d_level *,BOOLEAN_P,BOOLEAN_P,BOOLEAN_P)); E void FDECL(schedule_goto, (d_level *,BOOLEAN_P,BOOLEAN_P,int, const char *,const char *)); E void NDECL(deferred_goto); E boolean FDECL(revive_corpse, (struct obj *)); E void FDECL(revive_mon, (genericptr_t, long)); E int NDECL(donull); E int NDECL(dowipe); E void FDECL(set_wounded_legs, (long,int)); E void NDECL(heal_legs); /* ### do_name.c ### */ E int FDECL(getpos, (coord *,BOOLEAN_P,const char *)); E struct monst *FDECL(christen_monst, (struct monst *,const char *)); E int NDECL(do_mname); E struct obj *FDECL(oname, (struct obj *,const char *)); E int NDECL(ddocall); E void FDECL(docall, (struct obj *)); E const char *NDECL(rndghostname); E char *FDECL(x_monnam, (struct monst *,int,const char *,int,BOOLEAN_P)); E char *FDECL(l_monnam, (struct monst *)); E char *FDECL(mon_nam, (struct monst *)); E char *FDECL(noit_mon_nam, (struct monst *)); E char *FDECL(Monnam, (struct monst *)); E char *FDECL(noit_Monnam, (struct monst *)); E char *FDECL(m_monnam, (struct monst *)); E char *FDECL(y_monnam, (struct monst *)); E char *FDECL(Adjmonnam, (struct monst *,const char *)); E char *FDECL(Amonnam, (struct monst *)); E char *FDECL(a_monnam, (struct monst *)); E char *FDECL(distant_monnam, (struct monst *,int,char *)); E const char *NDECL(rndmonnam); E const char *FDECL(hcolor, (const char *)); E const char *NDECL(rndcolor); #ifdef REINCARNATION E const char *NDECL(roguename); #endif E struct obj *FDECL(realloc_obj, (struct obj *, int, genericptr_t, int, const char *)); E char *FDECL(coyotename, (struct monst *,char *)); /* ### do_wear.c ### */ #ifdef USE_TRAMPOLI E int NDECL(Armor_on); E int NDECL(Boots_on); E int NDECL(Gloves_on); E int NDECL(Helmet_on); E int FDECL(select_off, (struct obj *)); E int NDECL(take_off); #endif E void FDECL(off_msg, (struct obj *)); E void NDECL(set_wear); E boolean FDECL(donning, (struct obj *)); E void NDECL(cancel_don); E int NDECL(Armor_off); E int NDECL(Armor_gone); E int NDECL(Helmet_off); E int NDECL(Gloves_off); E int NDECL(Boots_off); E int NDECL(Cloak_off); E int NDECL(Shield_off); #ifdef TOURIST E int NDECL(Shirt_off); #endif E void NDECL(Amulet_off); E void FDECL(Ring_on, (struct obj *)); E void FDECL(Ring_off, (struct obj *)); E void FDECL(Ring_gone, (struct obj *)); E void FDECL(Blindf_on, (struct obj *)); E void FDECL(Blindf_off, (struct obj *)); E int NDECL(dotakeoff); E int NDECL(doremring); E int FDECL(cursed, (struct obj *)); E int FDECL(armoroff, (struct obj *)); E int FDECL(canwearobj, (struct obj *, long *, BOOLEAN_P)); E int NDECL(dowear); E int NDECL(doputon); E void NDECL(find_ac); E void NDECL(glibr); E struct obj *FDECL(some_armor,(struct monst *)); E void FDECL(erode_armor, (struct monst *,BOOLEAN_P)); E struct obj *FDECL(stuck_ring, (struct obj *,int)); E struct obj *NDECL(unchanger); E void NDECL(reset_remarm); E int NDECL(doddoremarm); E int FDECL(destroy_arm, (struct obj *)); E void FDECL(adj_abon, (struct obj *,SCHAR_P)); /* ### dog.c ### */ E void FDECL(initedog, (struct monst *)); E struct monst *FDECL(make_familiar, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E struct monst *NDECL(makedog); E void NDECL(update_mlstmv); E void NDECL(losedogs); E void FDECL(mon_arrive, (struct monst *,BOOLEAN_P)); E void FDECL(mon_catchup_elapsed_time, (struct monst *,long)); E void FDECL(keepdogs, (BOOLEAN_P)); E void FDECL(migrate_to_level, (struct monst *,XCHAR_P,XCHAR_P,coord *)); E int FDECL(dogfood, (struct monst *,struct obj *)); E struct monst *FDECL(tamedog, (struct monst *,struct obj *)); E void FDECL(abuse_dog, (struct monst *)); E void FDECL(wary_dog, (struct monst *, BOOLEAN_P)); /* ### dogmove.c ### */ E int FDECL(dog_nutrition, (struct monst *,struct obj *)); E int FDECL(dog_eat, (struct monst *,struct obj *,int,int,BOOLEAN_P)); E int FDECL(dog_move, (struct monst *,int)); #ifdef USE_TRAMPOLI E void FDECL(wantdoor, (int,int,genericptr_t)); #endif /* ### dokick.c ### */ E boolean FDECL(ghitm, (struct monst *,struct obj *)); E void FDECL(container_impact_dmg, (struct obj *)); E int NDECL(dokick); E boolean FDECL(ship_object, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E void NDECL(obj_delivery); E schar FDECL(down_gate, (XCHAR_P,XCHAR_P)); E void FDECL(impact_drop, (struct obj *,XCHAR_P,XCHAR_P,XCHAR_P)); /* ### dothrow.c ### */ E int NDECL(dothrow); E int NDECL(dofire); E void FDECL(hitfloor, (struct obj *)); E void FDECL(hurtle, (int,int,int,BOOLEAN_P)); E void FDECL(mhurtle, (struct monst *,int,int,int)); E void FDECL(throwit, (struct obj *,long,BOOLEAN_P)); E int FDECL(omon_adj, (struct monst *,struct obj *,BOOLEAN_P)); E int FDECL(thitmonst, (struct monst *,struct obj *)); E int FDECL(hero_breaks, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E int FDECL(breaks, (struct obj *,XCHAR_P,XCHAR_P)); E boolean FDECL(breaktest, (struct obj *)); E boolean FDECL(walk_path, (coord *, coord *, boolean (*)(genericptr_t,int,int), genericptr_t)); E boolean FDECL(hurtle_step, (genericptr_t, int, int)); /* ### drawing.c ### */ #endif /* !MAKEDEFS_C && !LEV_LEX_C */ E int FDECL(def_char_to_objclass, (CHAR_P)); E int FDECL(def_char_to_monclass, (CHAR_P)); #if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C) E void FDECL(assign_graphics, (uchar *,int,int,int)); E void FDECL(switch_graphics, (int)); #ifdef REINCARNATION E void FDECL(assign_rogue_graphics, (BOOLEAN_P)); #endif /* ### dungeon.c ### */ E void FDECL(save_dungeon, (int,BOOLEAN_P,BOOLEAN_P)); E void FDECL(restore_dungeon, (int)); E void FDECL(insert_branch, (branch *,BOOLEAN_P)); E void NDECL(init_dungeons); E s_level *FDECL(find_level, (const char *)); E s_level *FDECL(Is_special, (d_level *)); E branch *FDECL(Is_branchlev, (d_level *)); E xchar FDECL(ledger_no, (d_level *)); E xchar NDECL(maxledgerno); E schar FDECL(depth, (d_level *)); E xchar FDECL(dunlev, (d_level *)); E xchar FDECL(dunlevs_in_dungeon, (d_level *)); E xchar FDECL(ledger_to_dnum, (XCHAR_P)); E xchar FDECL(ledger_to_dlev, (XCHAR_P)); E xchar FDECL(deepest_lev_reached, (BOOLEAN_P)); E boolean FDECL(on_level, (d_level *,d_level *)); E void FDECL(next_level, (BOOLEAN_P)); E void FDECL(prev_level, (BOOLEAN_P)); E void FDECL(u_on_newpos, (int,int)); E void NDECL(u_on_sstairs); E void NDECL(u_on_upstairs); E void NDECL(u_on_dnstairs); E boolean FDECL(On_stairs, (XCHAR_P,XCHAR_P)); E void FDECL(get_level, (d_level *,int)); E boolean FDECL(Is_botlevel, (d_level *)); E boolean FDECL(Can_fall_thru, (d_level *)); E boolean FDECL(Can_dig_down, (d_level *)); E boolean FDECL(Can_rise_up, (int,int,d_level *)); E boolean FDECL(In_quest, (d_level *)); E boolean FDECL(In_mines, (d_level *)); E branch *FDECL(dungeon_branch, (const char *)); E boolean FDECL(at_dgn_entrance, (const char *)); E boolean FDECL(In_hell, (d_level *)); E boolean FDECL(In_V_tower, (d_level *)); E boolean FDECL(On_W_tower_level, (d_level *)); E boolean FDECL(In_W_tower, (int,int,d_level *)); E void FDECL(find_hell, (d_level *)); E void FDECL(goto_hell, (BOOLEAN_P,BOOLEAN_P)); E void FDECL(assign_level, (d_level *,d_level *)); E void FDECL(assign_rnd_level, (d_level *,d_level *,int)); E int FDECL(induced_align, (int)); E boolean FDECL(Invocation_lev, (d_level *)); E xchar NDECL(level_difficulty); E schar FDECL(lev_by_name, (const char *)); #ifdef WIZARD E schar FDECL(print_dungeon, (BOOLEAN_P,schar *,xchar *)); #endif /* ### eat.c ### */ #ifdef USE_TRAMPOLI E int NDECL(eatmdone); E int NDECL(eatfood); E int NDECL(opentin); E int NDECL(unfaint); #endif E boolean FDECL(is_edible, (struct obj *)); E void NDECL(init_uhunger); E int NDECL(Hear_again); E void NDECL(reset_eat); E int NDECL(doeat); E void NDECL(gethungry); E void FDECL(morehungry, (int)); E void FDECL(lesshungry, (int)); E boolean NDECL(is_fainted); E void NDECL(reset_faint); E void NDECL(violated_vegetarian); #if 0 E void NDECL(sync_hunger); #endif E void FDECL(newuhs, (BOOLEAN_P)); E struct obj *FDECL(floorfood, (const char *,int)); E void NDECL(vomit); E int FDECL(eaten_stat, (int,struct obj *)); E void FDECL(food_disappears, (struct obj *)); E void FDECL(food_substitution, (struct obj *,struct obj *)); E void NDECL(fix_petrification); E void FDECL(consume_oeaten, (struct obj *,int)); E boolean FDECL(maybe_finished_meal, (BOOLEAN_P)); /* ### end.c ### */ E void FDECL(done1, (int)); E int NDECL(done2); #ifdef USE_TRAMPOLI E void FDECL(done_intr, (int)); #endif E void FDECL(done_in_by, (struct monst *)); #endif /* !MAKEDEFS_C && !LEV_LEX_C */ E void VDECL(panic, (const char *,...)) PRINTF_F(1,2); #if !defined(MAKEDEFS_C) && !defined(LEV_LEX_C) E void FDECL(done, (int)); E void FDECL(container_contents, (struct obj *,BOOLEAN_P,BOOLEAN_P)); E void FDECL(terminate, (int)); E int NDECL(num_genocides); /* ### engrave.c ### */ E char *FDECL(random_engraving, (char *)); E void FDECL(wipeout_text, (char *,int,unsigned)); E boolean NDECL(can_reach_floor); E const char *FDECL(surface, (int,int)); E const char *FDECL(ceiling, (int,int)); E struct engr *FDECL(engr_at, (XCHAR_P,XCHAR_P)); #ifdef ELBERETH E int FDECL(sengr_at, (const char *,XCHAR_P,XCHAR_P)); #endif E void FDECL(u_wipe_engr, (int)); E void FDECL(wipe_engr_at, (XCHAR_P,XCHAR_P,XCHAR_P)); E void FDECL(read_engr_at, (int,int)); E void FDECL(make_engr_at, (int,int,const char *,long,XCHAR_P)); E void FDECL(del_engr_at, (int,int)); E int NDECL(freehand); E int NDECL(doengrave); E void FDECL(save_engravings, (int,int)); E void FDECL(rest_engravings, (int)); E void FDECL(del_engr, (struct engr *)); E void FDECL(rloc_engr, (struct engr *)); E void FDECL(make_grave, (int,int,const char *)); /* ### exper.c ### */ E int FDECL(experience, (struct monst *,int)); E void FDECL(more_experienced, (int,int)); E void FDECL(losexp, (const char *)); E void NDECL(newexplevel); E void FDECL(pluslvl, (BOOLEAN_P)); E long FDECL(rndexp, (BOOLEAN_P)); /* ### explode.c ### */ E void FDECL(explode, (int,int,int,int,CHAR_P,int)); E long FDECL(scatter, (int, int, int, unsigned int, struct obj *)); E void FDECL(splatter_burning_oil, (int, int)); /* ### extralev.c ### */ #ifdef REINCARNATION E void NDECL(makeroguerooms); E void FDECL(corr, (int,int)); E void NDECL(makerogueghost); #endif /* ### files.c ### */ E char *FDECL(fname_encode, (const char *, CHAR_P, char *, char *, int)); E char *FDECL(fname_decode, (CHAR_P, char *, char *, int)); E const char *FDECL(fqname, (const char *, int, int)); E FILE *FDECL(fopen_datafile, (const char *,const char *,int)); E boolean FDECL(uptodate, (int,const char *)); E void FDECL(store_version, (int)); #ifdef MFLOPPY E void NDECL(set_lock_and_bones); #endif E void FDECL(set_levelfile_name, (char *,int)); E int FDECL(create_levelfile, (int,char *)); E int FDECL(open_levelfile, (int,char *)); E void FDECL(delete_levelfile, (int)); E void NDECL(clearlocks); E int FDECL(create_bonesfile, (d_level*,char **, char *)); #ifdef MFLOPPY E void NDECL(cancel_bonesfile); #endif E void FDECL(commit_bonesfile, (d_level *)); E int FDECL(open_bonesfile, (d_level*,char **)); E int FDECL(delete_bonesfile, (d_level*)); E void NDECL(compress_bonesfile); E void NDECL(set_savefile_name); #ifdef INSURANCE E void FDECL(save_savefile_name, (int)); #endif #if defined(WIZARD) && !defined(MICRO) E void NDECL(set_error_savefile); #endif E int NDECL(create_savefile); E int NDECL(open_savefile); E int NDECL(delete_savefile); E int NDECL(restore_saved_game); E void FDECL(compress, (const char *)); E void FDECL(uncompress, (const char *)); E boolean FDECL(lock_file, (const char *,int,int)); E void FDECL(unlock_file, (const char *)); #ifdef USER_SOUNDS E boolean FDECL(can_read_file, (const char *)); #endif E void FDECL(read_config_file, (const char *)); E void FDECL(check_recordfile, (const char *)); #if defined(WIZARD) E void NDECL(read_wizkit); #endif E void FDECL(paniclog, (const char *, const char *)); E int FDECL(validate_prefix_locations, (char *)); E char** NDECL(get_saved_games); E void FDECL(free_saved_games, (char**)); #ifdef SELF_RECOVER E boolean NDECL(recover_savefile); #endif #ifdef HOLD_LOCKFILE_OPEN E void NDECL(really_close); #endif /* ### fountain.c ### */ E void FDECL(floating_above, (const char *)); E void FDECL(dogushforth, (int)); # ifdef USE_TRAMPOLI E void FDECL(gush, (int,int,genericptr_t)); # endif E void FDECL(dryup, (XCHAR_P,XCHAR_P, BOOLEAN_P)); E void NDECL(drinkfountain); E void FDECL(dipfountain, (struct obj *)); #ifdef SINKS E void FDECL(breaksink, (int,int)); E void NDECL(drinksink); #endif /* ### hack.c ### */ E boolean FDECL(revive_nasty, (int,int,const char*)); E void FDECL(movobj, (struct obj *,XCHAR_P,XCHAR_P)); E boolean FDECL(may_dig, (XCHAR_P,XCHAR_P)); E boolean FDECL(may_passwall, (XCHAR_P,XCHAR_P)); E boolean FDECL(bad_rock, (struct permonst *,XCHAR_P,XCHAR_P)); E boolean FDECL(invocation_pos, (XCHAR_P,XCHAR_P)); E boolean FDECL(test_move, (int, int, int, int, int)); E void NDECL(domove); E void NDECL(invocation_message); E void FDECL(spoteffects, (BOOLEAN_P)); E char *FDECL(in_rooms, (XCHAR_P,XCHAR_P,int)); E boolean FDECL(in_town, (int,int)); E void FDECL(check_special_room, (BOOLEAN_P)); E int NDECL(dopickup); E void NDECL(lookaround); E int NDECL(monster_nearby); E void FDECL(nomul, (int)); E void FDECL(unmul, (const char *)); E void FDECL(losehp, (int,const char *,BOOLEAN_P)); E int NDECL(weight_cap); E int NDECL(inv_weight); E int NDECL(near_capacity); E int FDECL(calc_capacity, (int)); E int NDECL(max_capacity); E boolean FDECL(check_capacity, (const char *)); E int NDECL(inv_cnt); #ifdef GOLDOBJ E long FDECL(money_cnt, (struct obj *)); #endif /* ### hacklib.c ### */ E boolean FDECL(digit, (CHAR_P)); E boolean FDECL(letter, (CHAR_P)); E char FDECL(highc, (CHAR_P)); E char FDECL(lowc, (CHAR_P)); E char *FDECL(lcase, (char *)); E char *FDECL(upstart, (char *)); E char *FDECL(mungspaces, (char *)); E char *FDECL(eos, (char *)); E char *FDECL(strkitten, (char *,CHAR_P)); E char *FDECL(s_suffix, (const char *)); E char *FDECL(xcrypt, (const char *,char *)); E boolean FDECL(onlyspace, (const char *)); E char *FDECL(tabexpand, (char *)); E char *FDECL(visctrl, (CHAR_P)); E const char *FDECL(ordin, (int)); E char *FDECL(sitoa, (int)); E int FDECL(sgn, (int)); E int FDECL(rounddiv, (long,int)); E int FDECL(dist2, (int,int,int,int)); E int FDECL(distmin, (int,int,int,int)); E boolean FDECL(online2, (int,int,int,int)); E boolean FDECL(pmatch, (const char *,const char *)); #ifndef STRNCMPI E int FDECL(strncmpi, (const char *,const char *,int)); #endif #ifndef STRSTRI E char *FDECL(strstri, (const char *,const char *)); #endif E boolean FDECL(fuzzymatch, (const char *,const char *,const char *,BOOLEAN_P)); E void NDECL(setrandom); E int NDECL(getyear); #if 0 E char *FDECL(yymmdd, (time_t)); #endif E long FDECL(yyyymmdd, (time_t)); E int NDECL(phase_of_the_moon); E boolean NDECL(friday_13th); E int NDECL(night); E int NDECL(midnight); /* ### invent.c ### */ E void FDECL(assigninvlet, (struct obj *)); E struct obj *FDECL(merge_choice, (struct obj *,struct obj *)); E int FDECL(merged, (struct obj **,struct obj **)); #ifdef USE_TRAMPOLI E int FDECL(ckunpaid, (struct obj *)); #endif E void FDECL(addinv_core1, (struct obj *)); E void FDECL(addinv_core2, (struct obj *)); E struct obj *FDECL(addinv, (struct obj *)); E struct obj *FDECL(hold_another_object, (struct obj *,const char *,const char *,const char *)); E void FDECL(useupall, (struct obj *)); E void FDECL(useup, (struct obj *)); E void FDECL(consume_obj_charge, (struct obj *,BOOLEAN_P)); E void FDECL(freeinv_core, (struct obj *)); E void FDECL(freeinv, (struct obj *)); E void FDECL(delallobj, (int,int)); E void FDECL(delobj, (struct obj *)); E struct obj *FDECL(sobj_at, (int,int,int)); E struct obj *FDECL(carrying, (int)); E boolean NDECL(have_lizard); E struct obj *FDECL(o_on, (unsigned int,struct obj *)); E boolean FDECL(obj_here, (struct obj *,int,int)); E boolean NDECL(wearing_armor); E boolean FDECL(is_worn, (struct obj *)); E struct obj *FDECL(g_at, (int,int)); E struct obj *FDECL(mkgoldobj, (long)); E struct obj *FDECL(getobj, (const char *,const char *)); E int FDECL(ggetobj, (const char *,int (*)(OBJ_P),int,BOOLEAN_P,unsigned *)); E void FDECL(fully_identify_obj, (struct obj *)); E int FDECL(identify, (struct obj *)); E void FDECL(identify_pack, (int)); E int FDECL(askchain, (struct obj **,const char *,int,int (*)(OBJ_P), int (*)(OBJ_P),int,const char *)); E void FDECL(prinv, (const char *,struct obj *,long)); E char *FDECL(xprname, (struct obj *,const char *,CHAR_P,BOOLEAN_P,long,long)); E int NDECL(ddoinv); E char FDECL(display_inventory, (const char *,BOOLEAN_P)); E int FDECL(display_binventory, (int,int,BOOLEAN_P)); E struct obj *FDECL(display_cinventory,(struct obj *)); E struct obj *FDECL(display_minventory,(struct monst *,int,char *)); E int NDECL(dotypeinv); E const char *FDECL(dfeature_at, (int,int,char *)); E int FDECL(look_here, (int,BOOLEAN_P)); E int NDECL(dolook); E boolean FDECL(will_feel_cockatrice, (struct obj *,BOOLEAN_P)); E void FDECL(feel_cockatrice, (struct obj *,BOOLEAN_P)); E void FDECL(stackobj, (struct obj *)); E int NDECL(doprgold); E int NDECL(doprwep); E int NDECL(doprarm); E int NDECL(doprring); E int NDECL(dopramulet); E int NDECL(doprtool); E int NDECL(doprinuse); E void FDECL(useupf, (struct obj *,long)); E char *FDECL(let_to_name, (CHAR_P,BOOLEAN_P)); E void NDECL(free_invbuf); E void NDECL(reassign); E int NDECL(doorganize); E int FDECL(count_unpaid, (struct obj *)); E int FDECL(count_buc, (struct obj *,int)); E void FDECL(carry_obj_effects, (struct obj *)); E const char *FDECL(currency, (long)); E void FDECL(silly_thing, (const char *,struct obj *)); /* ### ioctl.c ### */ #if defined(UNIX) || defined(__BEOS__) E void NDECL(getwindowsz); E void NDECL(getioctls); E void NDECL(setioctls); # ifdef SUSPEND E int NDECL(dosuspend); # endif /* SUSPEND */ #endif /* UNIX || __BEOS__ */ /* ### light.c ### */ E void FDECL(new_light_source, (XCHAR_P, XCHAR_P, int, int, genericptr_t)); E void FDECL(del_light_source, (int, genericptr_t)); E void FDECL(do_light_sources, (char **)); E struct monst *FDECL(find_mid, (unsigned, unsigned)); E void FDECL(save_light_sources, (int, int, int)); E void FDECL(restore_light_sources, (int)); E void FDECL(relink_light_sources, (BOOLEAN_P)); E void FDECL(obj_move_light_source, (struct obj *, struct obj *)); E boolean NDECL(any_light_source); E void FDECL(snuff_light_source, (int, int)); E boolean FDECL(obj_sheds_light, (struct obj *)); E boolean FDECL(obj_is_burning, (struct obj *)); E void FDECL(obj_split_light_source, (struct obj *, struct obj *)); E void FDECL(obj_merge_light_sources, (struct obj *,struct obj *)); E int FDECL(candle_light_range, (struct obj *)); #ifdef WIZARD E int NDECL(wiz_light_sources); #endif /* ### lock.c ### */ #ifdef USE_TRAMPOLI E int NDECL(forcelock); E int NDECL(picklock); #endif E boolean FDECL(picking_lock, (int *,int *)); E boolean FDECL(picking_at, (int,int)); E void NDECL(reset_pick); E int FDECL(pick_lock, (struct obj *)); E int NDECL(doforce); E boolean FDECL(boxlock, (struct obj *,struct obj *)); E boolean FDECL(doorlock, (struct obj *,int,int)); E int NDECL(doopen); E int NDECL(doclose); #ifdef MAC /* These declarations are here because the main code calls them. */ /* ### macfile.c ### */ E int FDECL(maccreat, (const char *,long)); E int FDECL(macopen, (const char *,int,long)); E int FDECL(macclose, (int)); E int FDECL(macread, (int,void *,unsigned)); E int FDECL(macwrite, (int,void *,unsigned)); E long FDECL(macseek, (int,long,short)); E int FDECL(macunlink, (const char *)); /* ### macsnd.c ### */ E void FDECL(mac_speaker, (struct obj *,char *)); /* ### macunix.c ### */ E void FDECL(regularize, (char *)); E void NDECL(getlock); /* ### macwin.c ### */ E void FDECL(lock_mouse_cursor, (Boolean)); E int NDECL(SanePositions); /* ### mttymain.c ### */ E void FDECL(getreturn, (char *)); E void VDECL(msmsg, (const char *,...)); E void NDECL(gettty); E void NDECL(setftty); E void FDECL(settty, (const char *)); E int NDECL(tgetch); E void FDECL(cmov, (int x, int y)); E void FDECL(nocmov, (int x, int y)); #endif /* MAC */ /* ### mail.c ### */ #ifdef MAIL # ifdef UNIX E void NDECL(getmailstatus); # endif E void NDECL(ckmailstatus); E void FDECL(readmail, (struct obj *)); #endif /* MAIL */ /* ### makemon.c ### */ E boolean FDECL(is_home_elemental, (struct permonst *)); E struct monst *FDECL(clone_mon, (struct monst *,XCHAR_P,XCHAR_P)); E struct monst *FDECL(makemon, (struct permonst *,int,int,int)); E boolean FDECL(create_critters, (int,struct permonst *)); E struct permonst *NDECL(rndmonst); E void FDECL(reset_rndmonst, (int)); E struct permonst *FDECL(mkclass, (CHAR_P,int)); E int FDECL(adj_lev, (struct permonst *)); E struct permonst *FDECL(grow_up, (struct monst *,struct monst *)); E int FDECL(mongets, (struct monst *,int)); E int FDECL(golemhp, (int)); E boolean FDECL(peace_minded, (struct permonst *)); E void FDECL(set_malign, (struct monst *)); E void FDECL(set_mimic_sym, (struct monst *)); E int FDECL(mbirth_limit, (int)); E void FDECL(mimic_hit_msg, (struct monst *, SHORT_P)); #ifdef GOLDOBJ E void FDECL(mkmonmoney, (struct monst *, long)); #endif E void FDECL(bagotricks, (struct obj *)); E boolean FDECL(propagate, (int, BOOLEAN_P,BOOLEAN_P)); /* ### mapglyph.c ### */ E void FDECL(mapglyph, (int, int *, int *, unsigned *, int, int)); /* ### mcastu.c ### */ E int FDECL(castmu, (struct monst *,struct attack *,BOOLEAN_P,BOOLEAN_P)); E int FDECL(buzzmu, (struct monst *,struct attack *)); /* ### mhitm.c ### */ E int FDECL(fightm, (struct monst *)); E int FDECL(mattackm, (struct monst *,struct monst *)); E int FDECL(noattacks, (struct permonst *)); E int FDECL(sleep_monst, (struct monst *,int,int)); E void FDECL(slept_monst, (struct monst *)); E long FDECL(attk_protection, (int)); /* ### mhitu.c ### */ E const char *FDECL(mpoisons_subj, (struct monst *,struct attack *)); E void NDECL(u_slow_down); E struct monst *NDECL(cloneu); E void FDECL(expels, (struct monst *,struct permonst *,BOOLEAN_P)); E struct attack *FDECL(getmattk, (struct permonst *,int,int *,struct attack *)); E int FDECL(mattacku, (struct monst *)); E int FDECL(magic_negation, (struct monst *)); E int FDECL(gazemu, (struct monst *,struct attack *)); E void FDECL(mdamageu, (struct monst *,int)); E int FDECL(could_seduce, (struct monst *,struct monst *,struct attack *)); #ifdef SEDUCE E int FDECL(doseduce, (struct monst *)); #endif /* ### minion.c ### */ E void FDECL(msummon, (struct monst *)); E void FDECL(summon_minion, (ALIGNTYP_P,BOOLEAN_P)); E int FDECL(demon_talk, (struct monst *)); E long FDECL(bribe, (struct monst *)); E int FDECL(dprince, (ALIGNTYP_P)); E int FDECL(dlord, (ALIGNTYP_P)); E int NDECL(llord); E int FDECL(ndemon, (ALIGNTYP_P)); E int NDECL(lminion); /* ### mklev.c ### */ #ifdef USE_TRAMPOLI E int FDECL(do_comp, (genericptr_t,genericptr_t)); #endif E void NDECL(sort_rooms); E void FDECL(add_room, (int,int,int,int,BOOLEAN_P,SCHAR_P,BOOLEAN_P)); E void FDECL(add_subroom, (struct mkroom *,int,int,int,int, BOOLEAN_P,SCHAR_P,BOOLEAN_P)); E void NDECL(makecorridors); E void FDECL(add_door, (int,int,struct mkroom *)); E void NDECL(mklev); #ifdef SPECIALIZATION E void FDECL(topologize, (struct mkroom *,BOOLEAN_P)); #else E void FDECL(topologize, (struct mkroom *)); #endif E void FDECL(place_branch, (branch *,XCHAR_P,XCHAR_P)); E boolean FDECL(occupied, (XCHAR_P,XCHAR_P)); E int FDECL(okdoor, (XCHAR_P,XCHAR_P)); E void FDECL(dodoor, (int,int,struct mkroom *)); E void FDECL(mktrap, (int,int,struct mkroom *,coord*)); E void FDECL(mkstairs, (XCHAR_P,XCHAR_P,CHAR_P,struct mkroom *)); E void NDECL(mkinvokearea); /* ### mkmap.c ### */ void FDECL(flood_fill_rm, (int,int,int,BOOLEAN_P,BOOLEAN_P)); void FDECL(remove_rooms, (int,int,int,int)); /* ### mkmaze.c ### */ E void FDECL(wallification, (int,int,int,int)); E void FDECL(walkfrom, (int,int)); E void FDECL(makemaz, (const char *)); E void FDECL(mazexy, (coord *)); E void NDECL(bound_digging); E void FDECL(mkportal, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); E boolean FDECL(bad_location, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); E void FDECL(place_lregion, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P, XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P, XCHAR_P,d_level *)); E void NDECL(movebubbles); E void NDECL(water_friction); E void FDECL(save_waterlevel, (int,int)); E void FDECL(restore_waterlevel, (int)); E const char *FDECL(waterbody_name, (XCHAR_P,XCHAR_P)); /* ### mkobj.c ### */ E struct obj *FDECL(mkobj_at, (CHAR_P,int,int,BOOLEAN_P)); E struct obj *FDECL(mksobj_at, (int,int,int,BOOLEAN_P,BOOLEAN_P)); E struct obj *FDECL(mkobj, (CHAR_P,BOOLEAN_P)); E int NDECL(rndmonnum); E struct obj *FDECL(splitobj, (struct obj *,long)); E void FDECL(replace_object, (struct obj *,struct obj *)); E void FDECL(bill_dummy_object, (struct obj *)); E struct obj *FDECL(mksobj, (int,BOOLEAN_P,BOOLEAN_P)); E int FDECL(bcsign, (struct obj *)); E int FDECL(weight, (struct obj *)); E struct obj *FDECL(mkgold, (long,int,int)); E struct obj *FDECL(mkcorpstat, (int,struct monst *,struct permonst *,int,int,BOOLEAN_P)); E struct obj *FDECL(obj_attach_mid, (struct obj *, unsigned)); E struct monst *FDECL(get_mtraits, (struct obj *, BOOLEAN_P)); E struct obj *FDECL(mk_tt_object, (int,int,int)); E struct obj *FDECL(mk_named_object, (int,struct permonst *,int,int,const char *)); E struct obj *FDECL(rnd_treefruit_at, (int, int)); E void FDECL(start_corpse_timeout, (struct obj *)); E void FDECL(bless, (struct obj *)); E void FDECL(unbless, (struct obj *)); E void FDECL(curse, (struct obj *)); E void FDECL(uncurse, (struct obj *)); E void FDECL(blessorcurse, (struct obj *,int)); E boolean FDECL(is_flammable, (struct obj *)); E boolean FDECL(is_rottable, (struct obj *)); E void FDECL(place_object, (struct obj *,int,int)); E void FDECL(remove_object, (struct obj *)); E void FDECL(discard_minvent, (struct monst *)); E void FDECL(obj_extract_self, (struct obj *)); E void FDECL(extract_nobj, (struct obj *, struct obj **)); E void FDECL(extract_nexthere, (struct obj *, struct obj **)); E int FDECL(add_to_minv, (struct monst *, struct obj *)); E struct obj *FDECL(add_to_container, (struct obj *, struct obj *)); E void FDECL(add_to_migration, (struct obj *)); E void FDECL(add_to_buried, (struct obj *)); E void FDECL(dealloc_obj, (struct obj *)); E void FDECL(obj_ice_effects, (int, int, BOOLEAN_P)); E long FDECL(peek_at_iced_corpse_age, (struct obj *)); #ifdef WIZARD E void NDECL(obj_sanity_check); #endif /* ### mkroom.c ### */ E void FDECL(mkroom, (int)); E void FDECL(fill_zoo, (struct mkroom *)); E boolean FDECL(nexttodoor, (int,int)); E boolean FDECL(has_dnstairs, (struct mkroom *)); E boolean FDECL(has_upstairs, (struct mkroom *)); E int FDECL(somex, (struct mkroom *)); E int FDECL(somey, (struct mkroom *)); E boolean FDECL(inside_room, (struct mkroom *,XCHAR_P,XCHAR_P)); E boolean FDECL(somexy, (struct mkroom *,coord *)); E void FDECL(mkundead, (coord *,BOOLEAN_P,int)); E struct permonst *NDECL(courtmon); E void FDECL(save_rooms, (int)); E void FDECL(rest_rooms, (int)); E struct mkroom *FDECL(search_special, (SCHAR_P)); /* ### mon.c ### */ E int FDECL(undead_to_corpse, (int)); E int FDECL(genus, (int,int)); E int FDECL(pm_to_cham, (int)); E int FDECL(minliquid, (struct monst *)); E int NDECL(movemon); E int FDECL(meatmetal, (struct monst *)); E int FDECL(meatobj, (struct monst *)); E void FDECL(mpickgold, (struct monst *)); E boolean FDECL(mpickstuff, (struct monst *,const char *)); E int FDECL(curr_mon_load, (struct monst *)); E int FDECL(max_mon_load, (struct monst *)); E boolean FDECL(can_carry, (struct monst *,struct obj *)); E int FDECL(mfndpos, (struct monst *,coord *,long *,long)); E boolean FDECL(monnear, (struct monst *,int,int)); E void NDECL(dmonsfree); E int FDECL(mcalcmove, (struct monst*)); E void NDECL(mcalcdistress); E void FDECL(replmon, (struct monst *,struct monst *)); E void FDECL(relmon, (struct monst *)); E struct obj *FDECL(mlifesaver, (struct monst *)); E boolean FDECL(corpse_chance,(struct monst *,struct monst *,BOOLEAN_P)); E void FDECL(mondead, (struct monst *)); E void FDECL(mondied, (struct monst *)); E void FDECL(mongone, (struct monst *)); E void FDECL(monstone, (struct monst *)); E void FDECL(monkilled, (struct monst *,const char *,int)); E void FDECL(unstuck, (struct monst *)); E void FDECL(killed, (struct monst *)); E void FDECL(xkilled, (struct monst *,int)); E void FDECL(mon_to_stone, (struct monst*)); E void FDECL(mnexto, (struct monst *)); E boolean FDECL(mnearto, (struct monst *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E void FDECL(poisontell, (int)); E void FDECL(poisoned, (const char *,int,const char *,int)); E void FDECL(m_respond, (struct monst *)); E void FDECL(setmangry, (struct monst *)); E void FDECL(wakeup, (struct monst *)); E void NDECL(wake_nearby); E void FDECL(wake_nearto, (int,int,int)); E void FDECL(seemimic, (struct monst *)); E void NDECL(rescham); E void NDECL(restartcham); E void FDECL(restore_cham, (struct monst *)); E void FDECL(mon_animal_list, (BOOLEAN_P)); E int FDECL(newcham, (struct monst *,struct permonst *,BOOLEAN_P,BOOLEAN_P)); E int FDECL(can_be_hatched, (int)); E int FDECL(egg_type_from_parent, (int,BOOLEAN_P)); E boolean FDECL(dead_species, (int,BOOLEAN_P)); E void NDECL(kill_genocided_monsters); E void FDECL(golemeffects, (struct monst *,int,int)); E boolean FDECL(angry_guards, (BOOLEAN_P)); E void NDECL(pacify_guards); /* ### mondata.c ### */ E void FDECL(set_mon_data, (struct monst *,struct permonst *,int)); E struct attack *FDECL(attacktype_fordmg, (struct permonst *,int,int)); E boolean FDECL(attacktype, (struct permonst *,int)); E boolean FDECL(poly_when_stoned, (struct permonst *)); E boolean FDECL(resists_drli, (struct monst *)); E boolean FDECL(resists_magm, (struct monst *)); E boolean FDECL(resists_blnd, (struct monst *)); E boolean FDECL(can_blnd, (struct monst *,struct monst *,UCHAR_P,struct obj *)); E boolean FDECL(ranged_attk, (struct permonst *)); E boolean FDECL(hates_silver, (struct permonst *)); E boolean FDECL(passes_bars, (struct permonst *)); E boolean FDECL(can_track, (struct permonst *)); E boolean FDECL(breakarm, (struct permonst *)); E boolean FDECL(sliparm, (struct permonst *)); E boolean FDECL(sticks, (struct permonst *)); E int FDECL(num_horns, (struct permonst *)); /* E boolean FDECL(canseemon, (struct monst *)); */ E struct attack *FDECL(dmgtype_fromattack, (struct permonst *,int,int)); E boolean FDECL(dmgtype, (struct permonst *,int)); E int FDECL(max_passive_dmg, (struct monst *,struct monst *)); E int FDECL(monsndx, (struct permonst *)); E int FDECL(name_to_mon, (const char *)); E int FDECL(gender, (struct monst *)); E int FDECL(pronoun_gender, (struct monst *)); E boolean FDECL(levl_follower, (struct monst *)); E int FDECL(little_to_big, (int)); E int FDECL(big_to_little, (int)); E const char *FDECL(locomotion, (const struct permonst *,const char *)); E const char *FDECL(stagger, (const struct permonst *,const char *)); E const char *FDECL(on_fire, (struct permonst *,struct attack *)); E const struct permonst *FDECL(raceptr, (struct monst *)); /* ### monmove.c ### */ E boolean FDECL(itsstuck, (struct monst *)); E boolean FDECL(mb_trapped, (struct monst *)); E void FDECL(mon_regen, (struct monst *,BOOLEAN_P)); E int FDECL(dochugw, (struct monst *)); E boolean FDECL(onscary, (int,int,struct monst *)); E void FDECL(monflee, (struct monst *, int, BOOLEAN_P, BOOLEAN_P)); E int FDECL(dochug, (struct monst *)); E int FDECL(m_move, (struct monst *,int)); E boolean FDECL(closed_door, (int,int)); E boolean FDECL(accessible, (int,int)); E void FDECL(set_apparxy, (struct monst *)); E boolean FDECL(can_ooze, (struct monst *)); /* ### monst.c ### */ E void NDECL(monst_init); /* ### monstr.c ### */ E void NDECL(monstr_init); /* ### mplayer.c ### */ E struct monst *FDECL(mk_mplayer, (struct permonst *,XCHAR_P, XCHAR_P,BOOLEAN_P)); E void FDECL(create_mplayers, (int,BOOLEAN_P)); E void FDECL(mplayer_talk, (struct monst *)); #if defined(MICRO) || defined(WIN32) /* ### msdos.c,os2.c,tos.c,winnt.c ### */ # ifndef WIN32 E int NDECL(tgetch); # endif # ifndef TOS E char NDECL(switchar); # endif # ifndef __GO32__ E long FDECL(freediskspace, (char *)); # ifdef MSDOS E int FDECL(findfirst_file, (char *)); E int NDECL(findnext_file); E long FDECL(filesize_nh, (char *)); # else E int FDECL(findfirst, (char *)); E int NDECL(findnext); E long FDECL(filesize, (char *)); # endif /* MSDOS */ E char *NDECL(foundfile_buffer); # endif /* __GO32__ */ E void FDECL(chdrive, (char *)); # ifndef TOS E void NDECL(disable_ctrlP); E void NDECL(enable_ctrlP); # endif # if defined(MICRO) && !defined(WINNT) E void NDECL(get_scr_size); # ifndef TOS E void FDECL(gotoxy, (int,int)); # endif # endif # ifdef TOS E int FDECL(_copyfile, (char *,char *)); E int NDECL(kbhit); E void NDECL(set_colors); E void NDECL(restore_colors); # ifdef SUSPEND E int NDECL(dosuspend); # endif # endif /* TOS */ # ifdef WIN32 E char *FDECL(get_username, (int *)); E void FDECL(nt_regularize, (char *)); E int NDECL((*nt_kbhit)); E void FDECL(Delay, (int)); # endif /* WIN32 */ #endif /* MICRO || WIN32 */ /* ### mthrowu.c ### */ E int FDECL(thitu, (int,int,struct obj *,const char *)); E int FDECL(ohitmon, (struct monst *,struct obj *,int,BOOLEAN_P)); E void FDECL(thrwmu, (struct monst *)); E int FDECL(spitmu, (struct monst *,struct attack *)); E int FDECL(breamu, (struct monst *,struct attack *)); E boolean FDECL(linedup, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); E boolean FDECL(lined_up, (struct monst *)); E struct obj *FDECL(m_carrying, (struct monst *,int)); E void FDECL(m_useup, (struct monst *,struct obj *)); E void FDECL(m_throw, (struct monst *,int,int,int,int,int,struct obj *)); E boolean FDECL(hits_bars, (struct obj **,int,int,int,int)); /* ### muse.c ### */ E boolean FDECL(find_defensive, (struct monst *)); E int FDECL(use_defensive, (struct monst *)); E int FDECL(rnd_defensive_item, (struct monst *)); E boolean FDECL(find_offensive, (struct monst *)); #ifdef USE_TRAMPOLI E int FDECL(mbhitm, (struct monst *,struct obj *)); #endif E int FDECL(use_offensive, (struct monst *)); E int FDECL(rnd_offensive_item, (struct monst *)); E boolean FDECL(find_misc, (struct monst *)); E int FDECL(use_misc, (struct monst *)); E int FDECL(rnd_misc_item, (struct monst *)); E boolean FDECL(searches_for_item, (struct monst *,struct obj *)); E boolean FDECL(mon_reflects, (struct monst *,const char *)); E boolean FDECL(ureflects, (const char *,const char *)); E boolean FDECL(munstone, (struct monst *,BOOLEAN_P)); /* ### music.c ### */ E void NDECL(awaken_soldiers); E int FDECL(do_play_instrument, (struct obj *)); /* ### nhlan.c ### */ #ifdef LAN_FEATURES E void NDECL(init_lan_features); E char *NDECL(lan_username); # ifdef LAN_MAIL E boolean NDECL(lan_mail_check); E void FDECL(lan_mail_read, (struct obj *)); E void NDECL(lan_mail_init); E void NDECL(lan_mail_finish); E void NDECL(lan_mail_terminate); # endif #endif /* ### nttty.c ### */ #ifdef WIN32CON E void NDECL(get_scr_size); E int NDECL(nttty_kbhit); E void NDECL(nttty_open); E void NDECL(nttty_rubout); E int NDECL(tgetch); E int FDECL(ntposkey,(int *, int *, int *)); E void FDECL(set_output_mode, (int)); E void NDECL(synch_cursor); #endif /* ### o_init.c ### */ E void NDECL(init_objects); E int NDECL(find_skates); E void NDECL(oinit); E void FDECL(savenames, (int,int)); E void FDECL(restnames, (int)); E void FDECL(discover_object, (int,BOOLEAN_P,BOOLEAN_P)); E void FDECL(undiscover_object, (int)); E int NDECL(dodiscovered); /* ### objects.c ### */ E void NDECL(objects_init); /* ### objnam.c ### */ E char *FDECL(obj_typename, (int)); E char *FDECL(simple_typename, (int)); E boolean FDECL(obj_is_pname, (struct obj *)); E char *FDECL(distant_name, (struct obj *,char *(*)(OBJ_P))); E char *FDECL(fruitname, (BOOLEAN_P)); E char *FDECL(xname, (struct obj *)); E char *FDECL(mshot_xname, (struct obj *)); E boolean FDECL(the_unique_obj, (struct obj *obj)); E char *FDECL(doname, (struct obj *)); E boolean FDECL(not_fully_identified, (struct obj *)); E char *FDECL(corpse_xname, (struct obj *,BOOLEAN_P)); E char *FDECL(cxname, (struct obj *)); E char *FDECL(killer_xname, (struct obj *)); E const char *FDECL(singular, (struct obj *,char *(*)(OBJ_P))); E char *FDECL(an, (const char *)); E char *FDECL(An, (const char *)); E char *FDECL(The, (const char *)); E char *FDECL(the, (const char *)); E char *FDECL(aobjnam, (struct obj *,const char *)); E char *FDECL(Tobjnam, (struct obj *,const char *)); E char *FDECL(otense, (struct obj *,const char *)); E char *FDECL(vtense, (const char *,const char *)); E char *FDECL(Doname2, (struct obj *)); E char *FDECL(yname, (struct obj *)); E char *FDECL(Yname2, (struct obj *)); E char *FDECL(ysimple_name, (struct obj *)); E char *FDECL(Ysimple_name2, (struct obj *)); E char *FDECL(makeplural, (const char *)); E char *FDECL(makesingular, (const char *)); E struct obj *FDECL(readobjnam, (char *,struct obj *,BOOLEAN_P)); E int FDECL(rnd_class, (int,int)); E const char *FDECL(cloak_simple_name, (struct obj *)); E const char *FDECL(mimic_obj_name, (struct monst *)); /* ### options.c ### */ E boolean FDECL(match_optname, (const char *,const char *,int,BOOLEAN_P)); E void NDECL(initoptions); E void FDECL(parseoptions, (char *,BOOLEAN_P,BOOLEAN_P)); E int NDECL(doset); E int NDECL(dotogglepickup); E void NDECL(option_help); E void FDECL(next_opt, (winid,const char *)); E int FDECL(fruitadd, (char *)); E int FDECL(choose_classes_menu, (const char *,int,BOOLEAN_P,char *,char *)); E void FDECL(add_menu_cmd_alias, (CHAR_P, CHAR_P)); E char FDECL(map_menu_cmd, (CHAR_P)); E void FDECL(assign_warnings, (uchar *)); E char *FDECL(nh_getenv, (const char *)); E void FDECL(set_duplicate_opt_detection, (int)); E void FDECL(set_wc_option_mod_status, (unsigned long, int)); E void FDECL(set_wc2_option_mod_status, (unsigned long, int)); E void FDECL(set_option_mod_status, (const char *,int)); #ifdef AUTOPICKUP_EXCEPTIONS E int FDECL(add_autopickup_exception, (const char *)); E void NDECL(free_autopickup_exceptions); #endif /* AUTOPICKUP_EXCEPTIONS */ /* ### pager.c ### */ E int NDECL(dowhatis); E int NDECL(doquickwhatis); E int NDECL(doidtrap); E int NDECL(dowhatdoes); E char *FDECL(dowhatdoes_core,(CHAR_P, char *)); E int NDECL(dohelp); E int NDECL(dohistory); /* ### pcmain.c ### */ #if defined(MICRO) || defined(WIN32) # ifdef CHDIR E void FDECL(chdirx, (char *,BOOLEAN_P)); # endif /* CHDIR */ #endif /* MICRO || WIN32 */ /* ### pcsys.c ### */ #if defined(MICRO) || defined(WIN32) E void NDECL(flushout); E int NDECL(dosh); # ifdef MFLOPPY E void FDECL(eraseall, (const char *,const char *)); E void FDECL(copybones, (int)); E void NDECL(playwoRAMdisk); E int FDECL(saveDiskPrompt, (int)); E void NDECL(gameDiskPrompt); # endif E void FDECL(append_slash, (char *)); E void FDECL(getreturn, (const char *)); # ifndef AMIGA E void VDECL(msmsg, (const char *,...)); # endif E FILE *FDECL(fopenp, (const char *,const char *)); #endif /* MICRO || WIN32 */ /* ### pctty.c ### */ #if defined(MICRO) || defined(WIN32) E void NDECL(gettty); E void FDECL(settty, (const char *)); E void NDECL(setftty); E void VDECL(error, (const char *,...)); #if defined(TIMED_DELAY) && defined(_MSC_VER) E void FDECL(msleep, (unsigned)); #endif #endif /* MICRO || WIN32 */ /* ### pcunix.c ### */ #if defined(MICRO) E void FDECL(regularize, (char *)); #endif /* MICRO */ #if defined(PC_LOCKING) E void NDECL(getlock); #endif /* ### pickup.c ### */ #ifdef GOLDOBJ E int FDECL(collect_obj_classes, (char *,struct obj *,BOOLEAN_P,boolean FDECL((*),(OBJ_P)), int *)); #else E int FDECL(collect_obj_classes, (char *,struct obj *,BOOLEAN_P,BOOLEAN_P,boolean FDECL((*),(OBJ_P)), int *)); #endif E void FDECL(add_valid_menu_class, (int)); E boolean FDECL(allow_all, (struct obj *)); E boolean FDECL(allow_category, (struct obj *)); E boolean FDECL(is_worn_by_type, (struct obj *)); #ifdef USE_TRAMPOLI E int FDECL(ck_bag, (struct obj *)); E int FDECL(in_container, (struct obj *)); E int FDECL(out_container, (struct obj *)); #endif E int FDECL(pickup, (int)); E int FDECL(pickup_object, (struct obj *, long, BOOLEAN_P)); E int FDECL(query_category, (const char *, struct obj *, int, menu_item **, int)); E int FDECL(query_objlist, (const char *, struct obj *, int, menu_item **, int, boolean (*)(OBJ_P))); E struct obj *FDECL(pick_obj, (struct obj *)); E int NDECL(encumber_msg); E int NDECL(doloot); E int FDECL(use_container, (struct obj *,int)); E int FDECL(loot_mon, (struct monst *,int *,boolean *)); E const char *FDECL(safe_qbuf, (const char *,unsigned, const char *,const char *,const char *)); E boolean FDECL(is_autopickup_exception, (struct obj *, BOOLEAN_P)); /* ### pline.c ### */ E void VDECL(pline, (const char *,...)) PRINTF_F(1,2); E void VDECL(Norep, (const char *,...)) PRINTF_F(1,2); E void NDECL(free_youbuf); E void VDECL(You, (const char *,...)) PRINTF_F(1,2); E void VDECL(Your, (const char *,...)) PRINTF_F(1,2); E void VDECL(You_feel, (const char *,...)) PRINTF_F(1,2); E void VDECL(You_cant, (const char *,...)) PRINTF_F(1,2); E void VDECL(You_hear, (const char *,...)) PRINTF_F(1,2); E void VDECL(pline_The, (const char *,...)) PRINTF_F(1,2); E void VDECL(There, (const char *,...)) PRINTF_F(1,2); E void VDECL(verbalize, (const char *,...)) PRINTF_F(1,2); E void VDECL(raw_printf, (const char *,...)) PRINTF_F(1,2); E void VDECL(impossible, (const char *,...)) PRINTF_F(1,2); E const char *FDECL(align_str, (ALIGNTYP_P)); E void FDECL(mstatusline, (struct monst *)); E void NDECL(ustatusline); E void NDECL(self_invis_message); /* ### polyself.c ### */ E void NDECL(set_uasmon); E void NDECL(change_sex); E void FDECL(polyself, (BOOLEAN_P)); E int FDECL(polymon, (int)); E void NDECL(rehumanize); E int NDECL(dobreathe); E int NDECL(dospit); E int NDECL(doremove); E int NDECL(dospinweb); E int NDECL(dosummon); E int NDECL(dogaze); E int NDECL(dohide); E int NDECL(domindblast); E void FDECL(skinback, (BOOLEAN_P)); E const char *FDECL(mbodypart, (struct monst *,int)); E const char *FDECL(body_part, (int)); E int NDECL(poly_gender); E void FDECL(ugolemeffects, (int,int)); /* ### potion.c ### */ E void FDECL(set_itimeout, (long *,long)); E void FDECL(incr_itimeout, (long *,int)); E void FDECL(make_confused, (long,BOOLEAN_P)); E void FDECL(make_stunned, (long,BOOLEAN_P)); E void FDECL(make_blinded, (long,BOOLEAN_P)); E void FDECL(make_sick, (long, const char *, BOOLEAN_P,int)); E void FDECL(make_vomiting, (long,BOOLEAN_P)); E boolean FDECL(make_hallucinated, (long,BOOLEAN_P,long)); E int NDECL(dodrink); E int FDECL(dopotion, (struct obj *)); E int FDECL(peffects, (struct obj *)); E void FDECL(healup, (int,int,BOOLEAN_P,BOOLEAN_P)); E void FDECL(strange_feeling, (struct obj *,const char *)); E void FDECL(potionhit, (struct monst *,struct obj *,BOOLEAN_P)); E void FDECL(potionbreathe, (struct obj *)); E boolean FDECL(get_wet, (struct obj *)); E int NDECL(dodip); E void FDECL(djinni_from_bottle, (struct obj *)); E struct monst *FDECL(split_mon, (struct monst *,struct monst *)); E const char *NDECL(bottlename); /* ### pray.c ### */ #ifdef USE_TRAMPOLI E int NDECL(prayer_done); #endif E int NDECL(dosacrifice); E boolean FDECL(can_pray, (BOOLEAN_P)); E int NDECL(dopray); E const char *NDECL(u_gname); E int NDECL(doturn); E const char *NDECL(a_gname); E const char *FDECL(a_gname_at, (XCHAR_P x,XCHAR_P y)); E const char *FDECL(align_gname, (ALIGNTYP_P)); E const char *FDECL(halu_gname, (ALIGNTYP_P)); E const char *FDECL(align_gtitle, (ALIGNTYP_P)); E void FDECL(altar_wrath, (int,int)); /* ### priest.c ### */ E int FDECL(move_special, (struct monst *,BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P, XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); E char FDECL(temple_occupied, (char *)); E int FDECL(pri_move, (struct monst *)); E void FDECL(priestini, (d_level *,struct mkroom *,int,int,BOOLEAN_P)); E char *FDECL(priestname, (struct monst *,char *)); E boolean FDECL(p_coaligned, (struct monst *)); E struct monst *FDECL(findpriest, (CHAR_P)); E void FDECL(intemple, (int)); E void FDECL(priest_talk, (struct monst *)); E struct monst *FDECL(mk_roamer, (struct permonst *,ALIGNTYP_P, XCHAR_P,XCHAR_P,BOOLEAN_P)); E void FDECL(reset_hostility, (struct monst *)); E boolean FDECL(in_your_sanctuary, (struct monst *,XCHAR_P,XCHAR_P)); E void FDECL(ghod_hitsu, (struct monst *)); E void NDECL(angry_priest); E void NDECL(clearpriests); E void FDECL(restpriest, (struct monst *,BOOLEAN_P)); /* ### quest.c ### */ E void NDECL(onquest); E void NDECL(nemdead); E void NDECL(artitouch); E boolean NDECL(ok_to_quest); E void FDECL(leader_speaks, (struct monst *)); E void NDECL(nemesis_speaks); E void FDECL(quest_chat, (struct monst *)); E void FDECL(quest_talk, (struct monst *)); E void FDECL(quest_stat_check, (struct monst *)); E void FDECL(finish_quest, (struct obj *)); /* ### questpgr.c ### */ E void NDECL(load_qtlist); E void NDECL(unload_qtlist); E short FDECL(quest_info, (int)); E const char *NDECL(ldrname); E boolean FDECL(is_quest_artifact, (struct obj*)); E void FDECL(com_pager, (int)); E void FDECL(qt_pager, (int)); E struct permonst *NDECL(qt_montype); /* ### random.c ### */ #if defined(RANDOM) && !defined(__GO32__) /* djgpp has its own random */ E void FDECL(srandom, (unsigned)); E char *FDECL(initstate, (unsigned,char *,int)); E char *FDECL(setstate, (char *)); E long NDECL(random); #endif /* RANDOM */ /* ### read.c ### */ E int NDECL(doread); E boolean FDECL(is_chargeable, (struct obj *)); E void FDECL(recharge, (struct obj *,int)); E void FDECL(forget_objects, (int)); E void FDECL(forget_levels, (int)); E void NDECL(forget_traps); E void FDECL(forget_map, (int)); E int FDECL(seffects, (struct obj *)); #ifdef USE_TRAMPOLI E void FDECL(set_lit, (int,int,genericptr_t)); #endif E void FDECL(litroom, (BOOLEAN_P,struct obj *)); E void FDECL(do_genocide, (int)); E void FDECL(punish, (struct obj *)); E void NDECL(unpunish); E boolean FDECL(cant_create, (int *, BOOLEAN_P)); #ifdef WIZARD E boolean NDECL(create_particular); #endif /* ### rect.c ### */ E void NDECL(init_rect); E NhRect *FDECL(get_rect, (NhRect *)); E NhRect *NDECL(rnd_rect); E void FDECL(remove_rect, (NhRect *)); E void FDECL(add_rect, (NhRect *)); E void FDECL(split_rects, (NhRect *,NhRect *)); /* ## region.c ### */ E void NDECL(clear_regions); E void NDECL(run_regions); E boolean FDECL(in_out_region, (XCHAR_P,XCHAR_P)); E boolean FDECL(m_in_out_region, (struct monst *,XCHAR_P,XCHAR_P)); E void NDECL(update_player_regions); E void FDECL(update_monster_region, (struct monst *)); E NhRegion *FDECL(visible_region_at, (XCHAR_P,XCHAR_P)); E void FDECL(show_region, (NhRegion*, XCHAR_P, XCHAR_P)); E void FDECL(save_regions, (int,int)); E void FDECL(rest_regions, (int,BOOLEAN_P)); E NhRegion* FDECL(create_gas_cloud, (XCHAR_P, XCHAR_P, int, int)); /* ### restore.c ### */ E void FDECL(inven_inuse, (BOOLEAN_P)); E int FDECL(dorecover, (int)); E void FDECL(trickery, (char *)); E void FDECL(getlev, (int,int,XCHAR_P,BOOLEAN_P)); E void NDECL(minit); E boolean FDECL(lookup_id_mapping, (unsigned, unsigned *)); #ifdef ZEROCOMP E int FDECL(mread, (int,genericptr_t,unsigned int)); #else E void FDECL(mread, (int,genericptr_t,unsigned int)); #endif /* ### rip.c ### */ E void FDECL(genl_outrip, (winid,int)); /* ### rnd.c ### */ E int FDECL(rn2, (int)); E int FDECL(rnl, (int)); E int FDECL(rnd, (int)); E int FDECL(d, (int,int)); E int FDECL(rne, (int)); E int FDECL(rnz, (int)); /* ### role.c ### */ E boolean FDECL(validrole, (int)); E boolean FDECL(validrace, (int, int)); E boolean FDECL(validgend, (int, int, int)); E boolean FDECL(validalign, (int, int, int)); E int NDECL(randrole); E int FDECL(randrace, (int)); E int FDECL(randgend, (int, int)); E int FDECL(randalign, (int, int)); E int FDECL(str2role, (char *)); E int FDECL(str2race, (char *)); E int FDECL(str2gend, (char *)); E int FDECL(str2align, (char *)); E boolean FDECL(ok_role, (int, int, int, int)); E int FDECL(pick_role, (int, int, int, int)); E boolean FDECL(ok_race, (int, int, int, int)); E int FDECL(pick_race, (int, int, int, int)); E boolean FDECL(ok_gend, (int, int, int, int)); E int FDECL(pick_gend, (int, int, int, int)); E boolean FDECL(ok_align, (int, int, int, int)); E int FDECL(pick_align, (int, int, int, int)); E void NDECL(role_init); E void NDECL(rigid_role_checks); E void NDECL(plnamesuffix); E const char *FDECL(Hello, (struct monst *)); E const char *NDECL(Goodbye); E char *FDECL(build_plselection_prompt, (char *, int, int, int, int, int)); E char *FDECL(root_plselection_prompt, (char *, int, int, int, int, int)); /* ### rumors.c ### */ E char *FDECL(getrumor, (int,char *, BOOLEAN_P)); E void FDECL(outrumor, (int,int)); E void FDECL(outoracle, (BOOLEAN_P, BOOLEAN_P)); E void FDECL(save_oracles, (int,int)); E void FDECL(restore_oracles, (int)); E int FDECL(doconsult, (struct monst *)); /* ### save.c ### */ E int NDECL(dosave); #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32) E void FDECL(hangup, (int)); #endif E int NDECL(dosave0); #ifdef INSURANCE E void NDECL(savestateinlock); #endif #ifdef MFLOPPY E boolean FDECL(savelev, (int,XCHAR_P,int)); E boolean FDECL(swapin_file, (int)); E void NDECL(co_false); #else E void FDECL(savelev, (int,XCHAR_P,int)); #endif E void FDECL(bufon, (int)); E void FDECL(bufoff, (int)); E void FDECL(bflush, (int)); E void FDECL(bwrite, (int,genericptr_t,unsigned int)); E void FDECL(bclose, (int)); E void FDECL(savefruitchn, (int,int)); E void NDECL(free_dungeons); E void NDECL(freedynamicdata); /* ### shk.c ### */ #ifdef GOLDOBJ E long FDECL(money2mon, (struct monst *, long)); E void FDECL(money2u, (struct monst *, long)); #endif E char *FDECL(shkname, (struct monst *)); E void FDECL(shkgone, (struct monst *)); E void FDECL(set_residency, (struct monst *,BOOLEAN_P)); E void FDECL(replshk, (struct monst *,struct monst *)); E void FDECL(restshk, (struct monst *,BOOLEAN_P)); E char FDECL(inside_shop, (XCHAR_P,XCHAR_P)); E void FDECL(u_left_shop, (char *,BOOLEAN_P)); E void FDECL(remote_burglary, (XCHAR_P,XCHAR_P)); E void FDECL(u_entered_shop, (char *)); E boolean FDECL(same_price, (struct obj *,struct obj *)); E void NDECL(shopper_financial_report); E int FDECL(inhishop, (struct monst *)); E struct monst *FDECL(shop_keeper, (CHAR_P)); E boolean FDECL(tended_shop, (struct mkroom *)); E void FDECL(delete_contents, (struct obj *)); E void FDECL(obfree, (struct obj *,struct obj *)); E void FDECL(home_shk, (struct monst *,BOOLEAN_P)); E void FDECL(make_happy_shk, (struct monst *,BOOLEAN_P)); E void FDECL(hot_pursuit, (struct monst *)); E void FDECL(make_angry_shk, (struct monst *,XCHAR_P,XCHAR_P)); E int NDECL(dopay); E boolean FDECL(paybill, (int)); E void NDECL(finish_paybill); E struct obj *FDECL(find_oid, (unsigned)); E long FDECL(contained_cost, (struct obj *,struct monst *,long,BOOLEAN_P, BOOLEAN_P)); E long FDECL(contained_gold, (struct obj *)); E void FDECL(picked_container, (struct obj *)); E long FDECL(unpaid_cost, (struct obj *)); E void FDECL(addtobill, (struct obj *,BOOLEAN_P,BOOLEAN_P,BOOLEAN_P)); E void FDECL(splitbill, (struct obj *,struct obj *)); E void FDECL(subfrombill, (struct obj *,struct monst *)); E long FDECL(stolen_value, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P,BOOLEAN_P)); E void FDECL(sellobj_state, (int)); E void FDECL(sellobj, (struct obj *,XCHAR_P,XCHAR_P)); E int FDECL(doinvbill, (int)); E struct monst *FDECL(shkcatch, (struct obj *,XCHAR_P,XCHAR_P)); E void FDECL(add_damage, (XCHAR_P,XCHAR_P,long)); E int FDECL(repair_damage, (struct monst *,struct damage *,BOOLEAN_P)); E int FDECL(shk_move, (struct monst *)); E void FDECL(after_shk_move, (struct monst *)); E boolean FDECL(is_fshk, (struct monst *)); E void FDECL(shopdig, (int)); E void FDECL(pay_for_damage, (const char *,BOOLEAN_P)); E boolean FDECL(costly_spot, (XCHAR_P,XCHAR_P)); E struct obj *FDECL(shop_object, (XCHAR_P,XCHAR_P)); E void FDECL(price_quote, (struct obj *)); E void FDECL(shk_chat, (struct monst *)); E void FDECL(check_unpaid_usage, (struct obj *,BOOLEAN_P)); E void FDECL(check_unpaid, (struct obj *)); E void FDECL(costly_gold, (XCHAR_P,XCHAR_P,long)); E boolean FDECL(block_door, (XCHAR_P,XCHAR_P)); E boolean FDECL(block_entry, (XCHAR_P,XCHAR_P)); E char *FDECL(shk_your, (char *,struct obj *)); E char *FDECL(Shk_Your, (char *,struct obj *)); /* ### shknam.c ### */ E void FDECL(stock_room, (int,struct mkroom *)); E boolean FDECL(saleable, (struct monst *,struct obj *)); E int FDECL(get_shop_item, (int)); /* ### sit.c ### */ E void NDECL(take_gold); E int NDECL(dosit); E void NDECL(rndcurse); E void NDECL(attrcurse); /* ### sounds.c ### */ E void NDECL(dosounds); E const char *FDECL(growl_sound, (struct monst *)); E void FDECL(growl, (struct monst *)); E void FDECL(yelp, (struct monst *)); E void FDECL(whimper, (struct monst *)); E void FDECL(beg, (struct monst *)); E int NDECL(dotalk); #ifdef USER_SOUNDS E int FDECL(add_sound_mapping, (const char *)); E void FDECL(play_sound_for_message, (const char *)); #endif /* ### sys/msdos/sound.c ### */ #ifdef MSDOS E int FDECL(assign_soundcard, (char *)); #endif /* ### sp_lev.c ### */ E boolean FDECL(check_room, (xchar *,xchar *,xchar *,xchar *,BOOLEAN_P)); E boolean FDECL(create_room, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P, XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); E void FDECL(create_secret_door, (struct mkroom *,XCHAR_P)); E boolean FDECL(dig_corridor, (coord *,coord *,BOOLEAN_P,SCHAR_P,SCHAR_P)); E void FDECL(fill_room, (struct mkroom *,BOOLEAN_P)); E boolean FDECL(load_special, (const char *)); /* ### spell.c ### */ #ifdef USE_TRAMPOLI E int NDECL(learn); #endif E int FDECL(study_book, (struct obj *)); E void FDECL(book_disappears, (struct obj *)); E void FDECL(book_substitution, (struct obj *,struct obj *)); E void NDECL(age_spells); E int NDECL(docast); E int FDECL(spell_skilltype, (int)); E int FDECL(spelleffects, (int,BOOLEAN_P)); E void NDECL(losespells); E int NDECL(dovspell); E void FDECL(initialspell, (struct obj *)); /* ### steal.c ### */ #ifdef USE_TRAMPOLI E int NDECL(stealarm); #endif #ifdef GOLDOBJ E long FDECL(somegold, (long)); #else E long NDECL(somegold); #endif E void FDECL(stealgold, (struct monst *)); E void FDECL(remove_worn_item, (struct obj *,BOOLEAN_P)); E int FDECL(steal, (struct monst *, char *)); E int FDECL(mpickobj, (struct monst *,struct obj *)); E void FDECL(stealamulet, (struct monst *)); E void FDECL(mdrop_special_objs, (struct monst *)); E void FDECL(relobj, (struct monst *,int,BOOLEAN_P)); #ifdef GOLDOBJ E struct obj *FDECL(findgold, (struct obj *)); #endif /* ### steed.c ### */ #ifdef STEED E void NDECL(rider_cant_reach); E boolean FDECL(can_saddle, (struct monst *)); E int FDECL(use_saddle, (struct obj *)); E boolean FDECL(can_ride, (struct monst *)); E int NDECL(doride); E boolean FDECL(mount_steed, (struct monst *, BOOLEAN_P)); E void NDECL(exercise_steed); E void NDECL(kick_steed); E void FDECL(dismount_steed, (int)); E void FDECL(place_monster, (struct monst *,int,int)); #endif /* ### teleport.c ### */ E boolean FDECL(goodpos, (int,int,struct monst *,unsigned)); E boolean FDECL(enexto, (coord *,XCHAR_P,XCHAR_P,struct permonst *)); E boolean FDECL(enexto_core, (coord *,XCHAR_P,XCHAR_P,struct permonst *,unsigned)); E void FDECL(teleds, (int,int,BOOLEAN_P)); E boolean FDECL(safe_teleds, (BOOLEAN_P)); E boolean FDECL(teleport_pet, (struct monst *,BOOLEAN_P)); E void NDECL(tele); E int NDECL(dotele); E void NDECL(level_tele); E void FDECL(domagicportal, (struct trap *)); E void FDECL(tele_trap, (struct trap *)); E void FDECL(level_tele_trap, (struct trap *)); E void FDECL(rloc_to, (struct monst *,int,int)); E boolean FDECL(rloc, (struct monst *, BOOLEAN_P)); E boolean FDECL(tele_restrict, (struct monst *)); E void FDECL(mtele_trap, (struct monst *, struct trap *,int)); E int FDECL(mlevel_tele_trap, (struct monst *, struct trap *,BOOLEAN_P,int)); E void FDECL(rloco, (struct obj *)); E int NDECL(random_teleport_level); E boolean FDECL(u_teleport_mon, (struct monst *,BOOLEAN_P)); /* ### tile.c ### */ #ifdef USE_TILES E void FDECL(substitute_tiles, (d_level *)); #endif /* ### timeout.c ### */ E void NDECL(burn_away_slime); E void NDECL(nh_timeout); E void FDECL(fall_asleep, (int, BOOLEAN_P)); E void FDECL(attach_egg_hatch_timeout, (struct obj *)); E void FDECL(attach_fig_transform_timeout, (struct obj *)); E void FDECL(kill_egg, (struct obj *)); E void FDECL(hatch_egg, (genericptr_t, long)); E void FDECL(learn_egg_type, (int)); E void FDECL(burn_object, (genericptr_t, long)); E void FDECL(begin_burn, (struct obj *, BOOLEAN_P)); E void FDECL(end_burn, (struct obj *, BOOLEAN_P)); E void NDECL(do_storms); E boolean FDECL(start_timer, (long, SHORT_P, SHORT_P, genericptr_t)); E long FDECL(stop_timer, (SHORT_P, genericptr_t)); E void NDECL(run_timers); E void FDECL(obj_move_timers, (struct obj *, struct obj *)); E void FDECL(obj_split_timers, (struct obj *, struct obj *)); E void FDECL(obj_stop_timers, (struct obj *)); E boolean FDECL(obj_is_local, (struct obj *)); E void FDECL(save_timers, (int,int,int)); E void FDECL(restore_timers, (int,int,BOOLEAN_P,long)); E void FDECL(relink_timers, (BOOLEAN_P)); #ifdef WIZARD E int NDECL(wiz_timeout_queue); E void NDECL(timer_sanity_check); #endif /* ### topten.c ### */ E void FDECL(topten, (int)); E void FDECL(prscore, (int,char **)); E struct obj *FDECL(tt_oname, (struct obj *)); /* ### track.c ### */ E void NDECL(initrack); E void NDECL(settrack); E coord *FDECL(gettrack, (int,int)); /* ### trap.c ### */ E boolean FDECL(burnarmor,(struct monst *)); E boolean FDECL(rust_dmg, (struct obj *,const char *,int,BOOLEAN_P,struct monst *)); E void FDECL(grease_protect, (struct obj *,const char *,struct monst *)); E struct trap *FDECL(maketrap, (int,int,int)); E void FDECL(fall_through, (BOOLEAN_P)); E struct monst *FDECL(animate_statue, (struct obj *,XCHAR_P,XCHAR_P,int,int *)); E struct monst *FDECL(activate_statue_trap, (struct trap *,XCHAR_P,XCHAR_P,BOOLEAN_P)); E void FDECL(dotrap, (struct trap *, unsigned)); E void FDECL(seetrap, (struct trap *)); E int FDECL(mintrap, (struct monst *)); E void FDECL(instapetrify, (const char *)); E void FDECL(minstapetrify, (struct monst *,BOOLEAN_P)); E void FDECL(selftouch, (const char *)); E void FDECL(mselftouch, (struct monst *,const char *,BOOLEAN_P)); E void NDECL(float_up); E void FDECL(fill_pit, (int,int)); E int FDECL(float_down, (long, long)); E int FDECL(fire_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P,XCHAR_P,XCHAR_P)); E void FDECL(water_damage, (struct obj *,BOOLEAN_P,BOOLEAN_P)); E boolean NDECL(drown); E void FDECL(drain_en, (int)); E int NDECL(dountrap); E int FDECL(untrap, (BOOLEAN_P)); E boolean FDECL(chest_trap, (struct obj *,int,BOOLEAN_P)); E void FDECL(deltrap, (struct trap *)); E boolean FDECL(delfloortrap, (struct trap *)); E struct trap *FDECL(t_at, (int,int)); E void FDECL(b_trapped, (const char *,int)); E boolean NDECL(unconscious); E boolean NDECL(lava_effects); E void FDECL(blow_up_landmine, (struct trap *)); E int FDECL(launch_obj,(SHORT_P,int,int,int,int,int)); /* ### u_init.c ### */ E void NDECL(u_init); /* ### uhitm.c ### */ E void FDECL(hurtmarmor,(struct monst *,int)); E boolean FDECL(attack_checks, (struct monst *,struct obj *)); E void FDECL(check_caitiff, (struct monst *)); E schar FDECL(find_roll_to_hit, (struct monst *)); E boolean FDECL(attack, (struct monst *)); E boolean FDECL(hmon, (struct monst *,struct obj *,int)); E int FDECL(damageum, (struct monst *,struct attack *)); E void FDECL(missum, (struct monst *,struct attack *)); E int FDECL(passive, (struct monst *,BOOLEAN_P,int,UCHAR_P)); E void FDECL(passive_obj, (struct monst *,struct obj *,struct attack *)); E void FDECL(stumble_onto_mimic, (struct monst *)); E int FDECL(flash_hits_mon, (struct monst *,struct obj *)); /* ### unixmain.c ### */ #ifdef UNIX # ifdef PORT_HELP E void NDECL(port_help); # endif #endif /* UNIX */ /* ### unixtty.c ### */ #if defined(UNIX) || defined(__BEOS__) E void NDECL(gettty); E void FDECL(settty, (const char *)); E void NDECL(setftty); E void NDECL(intron); E void NDECL(introff); E void VDECL(error, (const char *,...)) PRINTF_F(1,2); #endif /* UNIX || __BEOS__ */ /* ### unixunix.c ### */ #ifdef UNIX E void NDECL(getlock); E void FDECL(regularize, (char *)); # if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV) E void FDECL(msleep, (unsigned)); # endif # ifdef SHELL E int NDECL(dosh); # endif /* SHELL */ # if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER) E int FDECL(child, (int)); # endif #endif /* UNIX */ /* ### unixres.c ### */ #ifdef UNIX # ifdef GNOME_GRAPHICS E int FDECL(hide_privileges, (BOOLEAN_P)); # endif #endif /* UNIX */ /* ### vault.c ### */ E boolean FDECL(grddead, (struct monst *)); E char FDECL(vault_occupied, (char *)); E void NDECL(invault); E int FDECL(gd_move, (struct monst *)); E void NDECL(paygd); E long NDECL(hidden_gold); E boolean NDECL(gd_sound); /* ### version.c ### */ E char *FDECL(version_string, (char *)); E char *FDECL(getversionstring, (char *)); E int NDECL(doversion); E int NDECL(doextversion); #ifdef MICRO E boolean FDECL(comp_times, (long)); #endif E boolean FDECL(check_version, (struct version_info *, const char *,BOOLEAN_P)); E unsigned long FDECL(get_feature_notice_ver, (char *)); E unsigned long NDECL(get_current_feature_ver); #ifdef RUNTIME_PORT_ID E void FDECL(append_port_id, (char *)); #endif /* ### video.c ### */ #ifdef MSDOS E int FDECL(assign_video, (char *)); # ifdef NO_TERMS E void NDECL(gr_init); E void NDECL(gr_finish); # endif E void FDECL(tileview,(BOOLEAN_P)); #endif #ifdef VIDEOSHADES E int FDECL(assign_videoshades, (char *)); E int FDECL(assign_videocolors, (char *)); #endif /* ### vis_tab.c ### */ #ifdef VISION_TABLES E void NDECL(vis_tab_init); #endif /* ### vision.c ### */ E void NDECL(vision_init); E int FDECL(does_block, (int,int,struct rm*)); E void NDECL(vision_reset); E void FDECL(vision_recalc, (int)); E void FDECL(block_point, (int,int)); E void FDECL(unblock_point, (int,int)); E boolean FDECL(clear_path, (int,int,int,int)); E void FDECL(do_clear_area, (int,int,int, void (*)(int,int,genericptr_t),genericptr_t)); #ifdef VMS /* ### vmsfiles.c ### */ E int FDECL(vms_link, (const char *,const char *)); E int FDECL(vms_unlink, (const char *)); E int FDECL(vms_creat, (const char *,unsigned int)); E int FDECL(vms_open, (const char *,int,unsigned int)); E boolean FDECL(same_dir, (const char *,const char *)); E int FDECL(c__translate, (int)); E char *FDECL(vms_basename, (const char *)); /* ### vmsmail.c ### */ E unsigned long NDECL(init_broadcast_trapping); E unsigned long NDECL(enable_broadcast_trapping); E unsigned long NDECL(disable_broadcast_trapping); # if 0 E struct mail_info *NDECL(parse_next_broadcast); # endif /*0*/ /* ### vmsmain.c ### */ E int FDECL(main, (int, char **)); # ifdef CHDIR E void FDECL(chdirx, (const char *,BOOLEAN_P)); # endif /* CHDIR */ /* ### vmsmisc.c ### */ E void NDECL(vms_abort); E void FDECL(vms_exit, (int)); /* ### vmstty.c ### */ E int NDECL(vms_getchar); E void NDECL(gettty); E void FDECL(settty, (const char *)); E void FDECL(shuttty, (const char *)); E void NDECL(setftty); E void NDECL(intron); E void NDECL(introff); E void VDECL(error, (const char *,...)) PRINTF_F(1,2); #ifdef TIMED_DELAY E void FDECL(msleep, (unsigned)); #endif /* ### vmsunix.c ### */ E void NDECL(getlock); E void FDECL(regularize, (char *)); E int NDECL(vms_getuid); E boolean FDECL(file_is_stmlf, (int)); E int FDECL(vms_define, (const char *,const char *,int)); E int FDECL(vms_putenv, (const char *)); E char *NDECL(verify_termcap); # if defined(CHDIR) || defined(SHELL) || defined(SECURE) E void NDECL(privoff); E void NDECL(privon); # endif # ifdef SHELL E int NDECL(dosh); # endif # if defined(SHELL) || defined(MAIL) E int FDECL(vms_doshell, (const char *,BOOLEAN_P)); # endif # ifdef SUSPEND E int NDECL(dosuspend); # endif #endif /* VMS */ /* ### weapon.c ### */ E int FDECL(hitval, (struct obj *,struct monst *)); E int FDECL(dmgval, (struct obj *,struct monst *)); E struct obj *FDECL(select_rwep, (struct monst *)); E struct obj *FDECL(select_hwep, (struct monst *)); E void FDECL(possibly_unwield, (struct monst *,BOOLEAN_P)); E int FDECL(mon_wield_item, (struct monst *)); E int NDECL(abon); E int NDECL(dbon); E int NDECL(enhance_weapon_skill); E void FDECL(unrestrict_weapon_skill, (int)); E void FDECL(use_skill, (int,int)); E void FDECL(add_weapon_skill, (int)); E void FDECL(lose_weapon_skill, (int)); E int FDECL(weapon_type, (struct obj *)); E int NDECL(uwep_skill_type); E int FDECL(weapon_hit_bonus, (struct obj *)); E int FDECL(weapon_dam_bonus, (struct obj *)); E void FDECL(skill_init, (const struct def_skill *)); /* ### were.c ### */ E void FDECL(were_change, (struct monst *)); E void FDECL(new_were, (struct monst *)); E int FDECL(were_summon, (struct permonst *,BOOLEAN_P,int *,char *)); E void NDECL(you_were); E void FDECL(you_unwere, (BOOLEAN_P)); /* ### wield.c ### */ E void FDECL(setuwep, (struct obj *)); E void FDECL(setuqwep, (struct obj *)); E void FDECL(setuswapwep, (struct obj *)); E int NDECL(dowield); E int NDECL(doswapweapon); E int NDECL(dowieldquiver); E boolean FDECL(wield_tool, (struct obj *,const char *)); E int NDECL(can_twoweapon); E void NDECL(drop_uswapwep); E int NDECL(dotwoweapon); E void NDECL(uwepgone); E void NDECL(uswapwepgone); E void NDECL(uqwepgone); E void NDECL(untwoweapon); E void FDECL(erode_obj, (struct obj *,BOOLEAN_P,BOOLEAN_P)); E int FDECL(chwepon, (struct obj *,int)); E int FDECL(welded, (struct obj *)); E void FDECL(weldmsg, (struct obj *)); E void FDECL(setmnotwielded, (struct monst *,struct obj *)); /* ### windows.c ### */ E void FDECL(choose_windows, (const char *)); E char FDECL(genl_message_menu, (CHAR_P,int,const char *)); E void FDECL(genl_preference_update, (const char *)); /* ### wizard.c ### */ E void NDECL(amulet); E int FDECL(mon_has_amulet, (struct monst *)); E int FDECL(mon_has_special, (struct monst *)); E int FDECL(tactics, (struct monst *)); E void NDECL(aggravate); E void NDECL(clonewiz); E int NDECL(pick_nasty); E int FDECL(nasty, (struct monst*)); E void NDECL(resurrect); E void NDECL(intervene); E void NDECL(wizdead); E void FDECL(cuss, (struct monst *)); /* ### worm.c ### */ E int NDECL(get_wormno); E void FDECL(initworm, (struct monst *,int)); E void FDECL(worm_move, (struct monst *)); E void FDECL(worm_nomove, (struct monst *)); E void FDECL(wormgone, (struct monst *)); E void FDECL(wormhitu, (struct monst *)); E void FDECL(cutworm, (struct monst *,XCHAR_P,XCHAR_P,struct obj *)); E void FDECL(see_wsegs, (struct monst *)); E void FDECL(detect_wsegs, (struct monst *,BOOLEAN_P)); E void FDECL(save_worm, (int,int)); E void FDECL(rest_worm, (int)); E void FDECL(place_wsegs, (struct monst *)); E void FDECL(remove_worm, (struct monst *)); E void FDECL(place_worm_tail_randomly, (struct monst *,XCHAR_P,XCHAR_P)); E int FDECL(count_wsegs, (struct monst *)); E boolean FDECL(worm_known, (struct monst *)); /* ### worn.c ### */ E void FDECL(setworn, (struct obj *,long)); E void FDECL(setnotworn, (struct obj *)); E void FDECL(mon_set_minvis, (struct monst *)); E void FDECL(mon_adjust_speed, (struct monst *,int,struct obj *)); E void FDECL(update_mon_intrinsics, (struct monst *,struct obj *,BOOLEAN_P,BOOLEAN_P)); E int FDECL(find_mac, (struct monst *)); E void FDECL(m_dowear, (struct monst *,BOOLEAN_P)); E struct obj *FDECL(which_armor, (struct monst *,long)); E void FDECL(mon_break_armor, (struct monst *,BOOLEAN_P)); E void FDECL(bypass_obj, (struct obj *)); E void NDECL(clear_bypasses); E int FDECL(racial_exception, (struct monst *, struct obj *)); /* ### write.c ### */ E int FDECL(dowrite, (struct obj *)); /* ### zap.c ### */ E int FDECL(bhitm, (struct monst *,struct obj *)); E void FDECL(probe_monster, (struct monst *)); E boolean FDECL(get_obj_location, (struct obj *,xchar *,xchar *,int)); E boolean FDECL(get_mon_location, (struct monst *,xchar *,xchar *,int)); E struct monst *FDECL(get_container_location, (struct obj *obj, int *, int *)); E struct monst *FDECL(montraits, (struct obj *,coord *)); E struct monst *FDECL(revive, (struct obj *)); E int FDECL(unturn_dead, (struct monst *)); E void FDECL(cancel_item, (struct obj *)); E boolean FDECL(drain_item, (struct obj *)); E struct obj *FDECL(poly_obj, (struct obj *, int)); E boolean FDECL(obj_resists, (struct obj *,int,int)); E boolean FDECL(obj_shudders, (struct obj *)); E void FDECL(do_osshock, (struct obj *)); E int FDECL(bhito, (struct obj *,struct obj *)); E int FDECL(bhitpile, (struct obj *,int (*)(OBJ_P,OBJ_P),int,int)); E int FDECL(zappable, (struct obj *)); E void FDECL(zapnodir, (struct obj *)); E int NDECL(dozap); E int FDECL(zapyourself, (struct obj *,BOOLEAN_P)); E boolean FDECL(cancel_monst, (struct monst *,struct obj *, BOOLEAN_P,BOOLEAN_P,BOOLEAN_P)); E void FDECL(weffects, (struct obj *)); E int NDECL(spell_damage_bonus); E const char *FDECL(exclam, (int force)); E void FDECL(hit, (const char *,struct monst *,const char *)); E void FDECL(miss, (const char *,struct monst *)); E struct monst *FDECL(bhit, (int,int,int,int,int (*)(MONST_P,OBJ_P), int (*)(OBJ_P,OBJ_P),struct obj *)); E struct monst *FDECL(boomhit, (int,int)); E int FDECL(burn_floor_paper, (int,int,BOOLEAN_P,BOOLEAN_P)); E void FDECL(buzz, (int,int,XCHAR_P,XCHAR_P,int,int)); E void FDECL(melt_ice, (XCHAR_P,XCHAR_P)); E int FDECL(zap_over_floor, (XCHAR_P,XCHAR_P,int,boolean *)); E void FDECL(fracture_rock, (struct obj *)); E boolean FDECL(break_statue, (struct obj *)); E void FDECL(destroy_item, (int,int)); E int FDECL(destroy_mitem, (struct monst *,int,int)); E int FDECL(resist, (struct monst *,CHAR_P,int,int)); E void NDECL(makewish); #endif /* !MAKEDEFS_C && !LEV_LEX_C */ #undef E #endif /* EXTERN_H */ nethack-3.4.3/include/flag.h0100644000000000000000000003127207764735041014364 0ustar rootroot/* SCCS Id: @(#)flag.h 3.4 2002/08/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* If you change the flag structure make sure you increment EDITLEVEL in */ /* patchlevel.h if needed. Changing the instance_flags structure does */ /* not require incrementing EDITLEVEL. */ #ifndef FLAG_H #define FLAG_H /* * Persistent flags that are saved and restored with the game. * */ struct flag { #ifdef AMIFLUSH boolean altmeta; /* use ALT keys as META */ boolean amiflush; /* kill typeahead */ #endif #ifdef MFLOPPY boolean asksavedisk; #endif boolean autodig; /* MRKR: Automatically dig */ boolean autoquiver; /* Automatically fill quiver */ boolean beginner; #ifdef MAIL boolean biff; /* enable checking for mail */ #endif boolean botl; /* partially redo status line */ boolean botlx; /* print an entirely new bottom line */ boolean confirm; /* confirm before hitting tame monsters */ boolean debug; /* in debugging mode */ #define wizard flags.debug boolean end_own; /* list all own scores */ boolean explore; /* in exploration mode */ #ifdef OPT_DISPMAP boolean fast_map; /* use optimized, less flexible map display */ #endif #define discover flags.explore boolean female; boolean forcefight; boolean friday13; /* it's Friday the 13th */ boolean help; /* look in data file for info about stuff */ boolean ignintr; /* ignore interrupts */ #ifdef INSURANCE boolean ins_chkpt; /* checkpoint as appropriate */ #endif boolean invlet_constant; /* let objects keep their inventory symbol */ boolean legacy; /* print game entry "story" */ boolean lit_corridor; /* show a dark corr as lit if it is in sight */ boolean made_amulet; boolean mon_moving; /* monsters' turn to move */ boolean move; boolean mv; boolean bypasses; /* bypass flag is set on at least one fobj */ boolean nap; /* `timed_delay' option for display effects */ boolean nopick; /* do not pickup objects (as when running) */ boolean null; /* OK to send nulls to the terminal */ #ifdef MAC boolean page_wait; /* put up a --More-- after a page of messages */ #endif boolean perm_invent; /* keep full inventories up until dismissed */ boolean pickup; /* whether you pickup or move and look */ boolean pushweapon; /* When wielding, push old weapon into second slot */ boolean rest_on_space; /* space means rest */ boolean safe_dog; /* give complete protection to the dog */ #ifdef EXP_ON_BOTL boolean showexp; /* show experience points */ #endif #ifdef SCORE_ON_BOTL boolean showscore; /* show score */ #endif boolean silent; /* whether the bell rings or not */ boolean sortpack; /* sorted inventory */ boolean soundok; /* ok to tell about sounds heard */ boolean sparkle; /* show "resisting" special FX (Scott Bigham) */ boolean standout; /* use standout for --More-- */ boolean time; /* display elapsed 'time' */ boolean tombstone; /* print tombstone */ boolean toptenwin; /* ending list in window instead of stdout */ boolean verbose; /* max battle info */ boolean prayconfirm; /* confirm before praying */ int end_top, end_around; /* describe desired score list */ unsigned ident; /* social security number for each monster */ unsigned moonphase; unsigned long suppress_alert; #define NEW_MOON 0 #define FULL_MOON 4 unsigned no_of_wizards; /* 0, 1 or 2 (wizard and his shadow) */ boolean travel; /* find way automatically to u.tx,u.ty */ unsigned run; /* 0: h (etc), 1: H (etc), 2: fh (etc) */ /* 3: FH, 4: ff+, 5: ff-, 6: FF+, 7: FF- */ /* 8: travel */ unsigned long warntype; /* warn_of_mon monster type M2 */ int warnlevel; int djinni_count, ghost_count; /* potion effect tuning */ int pickup_burden; /* maximum burden before prompt */ char inv_order[MAXOCLASSES]; char pickup_types[MAXOCLASSES]; #define NUM_DISCLOSURE_OPTIONS 5 #define DISCLOSE_PROMPT_DEFAULT_YES 'y' #define DISCLOSE_PROMPT_DEFAULT_NO 'n' #define DISCLOSE_YES_WITHOUT_PROMPT '+' #define DISCLOSE_NO_WITHOUT_PROMPT '-' char end_disclose[NUM_DISCLOSURE_OPTIONS + 1]; /* disclose various info upon exit */ char menu_style; /* User interface style setting */ #ifdef AMII_GRAPHICS int numcols; unsigned short amii_dripens[ 20 ]; /* DrawInfo Pens currently there are 13 in v39 */ AMII_COLOR_TYPE amii_curmap[ AMII_MAXCOLORS ]; /* colormap */ #endif /* KMH, role patch -- Variables used during startup. * * If the user wishes to select a role, race, gender, and/or alignment * during startup, the choices should be recorded here. This * might be specified through command-line options, environmental * variables, a popup dialog box, menus, etc. * * These values are each an index into an array. They are not * characters or letters, because that limits us to 26 roles. * They are not booleans, because someday someone may need a neuter * gender. Negative values are used to indicate that the user * hasn't yet specified that particular value. If you determine * that the user wants a random choice, then you should set an * appropriate random value; if you just left the negative value, * the user would be asked again! * * These variables are stored here because the u structure is * cleared during character initialization, and because the * flags structure is restored for saved games. Thus, we can * use the same parameters to build the role entry for both * new and restored games. * * These variables should not be referred to after the character * is initialized or restored (specifically, after role_init() * is called). */ int initrole; /* starting role (index into roles[]) */ int initrace; /* starting race (index into races[]) */ int initgend; /* starting gender (index into genders[]) */ int initalign; /* starting alignment (index into aligns[]) */ int randomall; /* randomly assign everything not specified */ int pantheon; /* deity selection for priest character */ }; /* * Flags that are set each time the game is started. * These are not saved with the game. * */ struct instance_flags { boolean cbreak; /* in cbreak mode, rogue format */ boolean DECgraphics; /* use DEC VT-xxx extended character set */ boolean echo; /* 1 to echo characters */ boolean IBMgraphics; /* use IBM extended character set */ unsigned msg_history; /* hint: # of top lines to save */ boolean num_pad; /* use numbers for movement commands */ boolean news; /* print news */ boolean window_inited; /* true if init_nhwindows() completed */ boolean vision_inited; /* true if vision is ready */ boolean menu_tab_sep; /* Use tabs to separate option menu fields */ boolean menu_requested; /* Flag for overloaded use of 'm' prefix * on some non-move commands */ uchar num_pad_mode; int menu_headings; /* ATR for menu headings */ int purge_monsters; /* # of dead monsters still on fmon list */ int *opt_booldup; /* for duplication of boolean opts in config file */ int *opt_compdup; /* for duplication of compound opts in config file */ uchar bouldersym; /* symbol for boulder display */ boolean travel1; /* first travel step */ coord travelcc; /* coordinates for travel_cache */ #ifdef WIZARD boolean sanity_check; /* run sanity checks */ boolean mon_polycontrol; /* debug: control monster polymorphs */ #endif #ifdef TTY_GRAPHICS char prevmsg_window; /* type of old message window to use */ boolean extmenu; /* extended commands use menu interface */ #endif #ifdef MFLOPPY boolean checkspace; /* check disk space before writing files */ /* (in iflags to allow restore after moving * to >2GB partition) */ #endif #ifdef MICRO boolean BIOS; /* use IBM or ST BIOS calls when appropriate */ #endif #if defined(MICRO) || defined(WIN32) boolean rawio; /* whether can use rawio (IOCTL call) */ #endif #ifdef MAC_GRAPHICS_ENV boolean MACgraphics; /* use Macintosh extended character set, as as defined in the special font HackFont */ unsigned use_stone; /* use the stone ppats */ #endif #if defined(MSDOS) || defined(WIN32) boolean hassound; /* has a sound card */ boolean usesound; /* use the sound card */ boolean usepcspeaker; /* use the pc speaker */ boolean tile_view; boolean over_view; boolean traditional_view; #endif #ifdef MSDOS boolean hasvga; /* has a vga adapter */ boolean usevga; /* use the vga adapter */ boolean grmode; /* currently in graphics mode */ #endif #ifdef LAN_FEATURES boolean lan_mail; /* mail is initialized */ boolean lan_mail_fetched; /* mail is awaiting display */ #endif /* * Window capability support. */ boolean wc_color; /* use color graphics */ boolean wc_hilite_pet; /* hilight pets */ boolean wc_ascii_map; /* show map using traditional ascii */ boolean wc_tiled_map; /* show map using tiles */ boolean wc_preload_tiles; /* preload tiles into memory */ int wc_tile_width; /* tile width */ int wc_tile_height; /* tile height */ char *wc_tile_file; /* name of tile file;overrides default */ boolean wc_inverse; /* use inverse video for some things */ int wc_align_status; /* status win at top|bot|right|left */ int wc_align_message; /* message win at top|bot|right|left */ int wc_vary_msgcount; /* show more old messages at a time */ char *wc_foregrnd_menu; /* points to foregrnd color name for menu win */ char *wc_backgrnd_menu; /* points to backgrnd color name for menu win */ char *wc_foregrnd_message; /* points to foregrnd color name for msg win */ char *wc_backgrnd_message; /* points to backgrnd color name for msg win */ char *wc_foregrnd_status; /* points to foregrnd color name for status win */ char *wc_backgrnd_status; /* points to backgrnd color name for status win */ char *wc_foregrnd_text; /* points to foregrnd color name for text win */ char *wc_backgrnd_text; /* points to backgrnd color name for text win */ char *wc_font_map; /* points to font name for the map win */ char *wc_font_message; /* points to font name for message win */ char *wc_font_status; /* points to font name for status win */ char *wc_font_menu; /* points to font name for menu win */ char *wc_font_text; /* points to font name for text win */ int wc_fontsiz_map; /* font size for the map win */ int wc_fontsiz_message; /* font size for the message window */ int wc_fontsiz_status; /* font size for the status window */ int wc_fontsiz_menu; /* font size for the menu window */ int wc_fontsiz_text; /* font size for text windows */ int wc_scroll_amount; /* scroll this amount at scroll_margin */ int wc_scroll_margin; /* scroll map when this far from the edge */ int wc_map_mode; /* specify map viewing options, mostly for backward compatibility */ int wc_player_selection; /* method of choosing character */ boolean wc_splash_screen; /* display an opening splash screen or not */ boolean wc_popup_dialog; /* put queries in pop up dialogs instead of in the message window */ boolean wc_eight_bit_input; /* allow eight bit input */ boolean wc_mouse_support; /* allow mouse support */ boolean wc2_fullscreen; /* run fullscreen */ boolean wc2_softkeyboard; /* use software keyboard */ boolean wc2_wraptext; /* wrap text */ boolean cmdassist; /* provide detailed assistance for some commands */ boolean obsolete; /* obsolete options can point at this, it isn't used */ /* Items which belong in flags, but are here to allow save compatibility */ boolean lootabc; /* use "a/b/c" rather than "o/i/b" when looting */ boolean showrace; /* show hero glyph by race rather than by role */ boolean travelcmd; /* allow travel command */ int runmode; /* update screen display during run moves */ #ifdef AUTOPICKUP_EXCEPTIONS struct autopickup_exception *autopickup_exceptions[2]; #define AP_LEAVE 0 #define AP_GRAB 1 #endif #ifdef WIN32CON #define MAX_ALTKEYHANDLER 25 char altkeyhandler[MAX_ALTKEYHANDLER]; #endif }; /* * Old deprecated names */ #ifdef TTY_GRAPHICS #define eight_bit_tty wc_eight_bit_input #endif #ifdef TEXTCOLOR #define use_color wc_color #endif #define hilite_pet wc_hilite_pet #define use_inverse wc_inverse #ifdef MAC_GRAPHICS_ENV #define large_font obsolete #endif #ifdef MAC #define popup_dialog wc_popup_dialog #endif #define preload_tiles wc_preload_tiles extern NEARDATA struct flag flags; extern NEARDATA struct instance_flags iflags; /* runmode options */ #define RUN_TPORT 0 /* don't update display until movement stops */ #define RUN_LEAP 1 /* update display every 7 steps */ #define RUN_STEP 2 /* update display every single step */ #define RUN_CRAWL 3 /* walk w/ extra delay after each update */ #endif /* FLAG_H */ nethack-3.4.3/include/func_tab.h0100644000000000000000000000076407764735041015236 0ustar rootroot/* SCCS Id: @(#)func_tab.h 3.4 1992/04/03 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef FUNC_TAB_H #define FUNC_TAB_H struct func_tab { char f_char; boolean can_if_buried; int NDECL((*f_funct)); const char *f_text; }; struct ext_func_tab { const char *ef_txt, *ef_desc; int NDECL((*ef_funct)); boolean can_if_buried; }; extern struct ext_func_tab extcmdlist[]; #endif /* FUNC_TAB_H */ nethack-3.4.3/include/gem_rsc.h0100644000000000000000000000542607764735041015074 0ustar rootroot/* resource set indices for GEM_RSC */ #define MENU 0 /* menu */ #define DOABOUT 12 /* STRING in tree MENU */ #define DOQUIT 30 /* STRING in tree MENU */ #define STATUSLINE 1 /* form/dialog */ #define GRABSTATUS 1 /* BOX in tree STATUSLINE */ #define MAPWIN 2 /* form/dialog */ #define MAPBOX 0 /* BOX in tree MAPWIN */ #define MAPCURSOR 1 /* IBOX in tree MAPWIN */ #define ABOUT 3 /* form/dialog */ #define FLYABOUT 0 /* BOX in tree ABOUT */ #define OKABOUT 1 /* BUTTON in tree ABOUT */ #define NETHACKIMG0 3 /* ICON in tree ABOUT */ #define LINES 4 /* form/dialog */ #define FLYLINES 0 /* BOX in tree LINES */ #define QLINE 1 /* BUTTON in tree LINES */ #define LINESLIST 2 /* USERDEF in tree LINES */ #define YNCHOICE 5 /* form/dialog */ #define FLYYNCHOICE 0 /* BOX in tree YNCHOICE */ #define YNPROMPT 1 /* TEXT in tree YNCHOICE */ #define SOMECHARS 2 /* BOX in tree YNCHOICE */ #define YN1 3 /* BUTTON in tree YNCHOICE */ #define YNN 53 /* BUTTON in tree YNCHOICE */ #define ANYCHAR 55 /* BOX in tree YNCHOICE */ #define CHOSENCH 56 /* FBOXTEXT in tree YNCHOICE */ #define COUNT 58 /* FBOXTEXT in tree YNCHOICE */ #define YNOK 59 /* BUTTON in tree YNCHOICE */ #define LINEGET 6 /* form/dialog */ #define FLYLINEGET 0 /* BOX in tree LINEGET */ #define LGPROMPT 1 /* TEXT in tree LINEGET */ #define LGREPLY 2 /* FBOXTEXT in tree LINEGET */ #define QLG 3 /* BUTTON in tree LINEGET */ #define LGOK 4 /* BUTTON in tree LINEGET */ #define DIRECTION 7 /* form/dialog */ #define FLYDIRECTION 0 /* BOX in tree DIRECTION */ #define DIR1 5 /* BOXTEXT in tree DIRECTION */ #define DIR9 21 /* BOXTEXT in tree DIRECTION */ #define DIRDOWN 23 /* BOXTEXT in tree DIRECTION */ #define DIRUP 25 /* BOXTEXT in tree DIRECTION */ #define MSGWIN 8 /* form/dialog */ #define UPMSG 1 /* BOXCHAR in tree MSGWIN */ #define GRABMSGWIN 2 /* BOX in tree MSGWIN */ #define DNMSG 3 /* BOXCHAR in tree MSGWIN */ #define MSGLINES 4 /* USERDEF in tree MSGWIN */ #define NAMEGET 9 /* form/dialog */ #define FLYNAMEGET 0 /* BOX in tree NAMEGET */ #define PLNAME 2 /* FBOXTEXT in tree NAMEGET */ #define NETHACKPICTURE 4 /* BOXTEXT in tree NAMEGET */ #define PAGER 10 /* form/dialog */ #define FLYPAGER 0 /* BOX in tree PAGER */ #define QPAGER 1 /* BUTTON in tree PAGER */ #define NHICON 11 /* form/dialog */ nethack-3.4.3/include/global.h0100644000000000000000000002107007764735041014706 0ustar rootroot/* SCCS Id: @(#)global.h 3.4 2003/08/31 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GLOBAL_H #define GLOBAL_H #include /* #define BETA */ /* if a beta-test copy [MRS] */ /* * Files expected to exist in the playground directory. */ #define RECORD "record" /* file containing list of topscorers */ #define HELP "help" /* file containing command descriptions */ #define SHELP "hh" /* abbreviated form of the same */ #define DEBUGHELP "wizhelp" /* file containing debug mode cmds */ #define RUMORFILE "rumors" /* file with fortune cookies */ #define ORACLEFILE "oracles" /* file with oracular information */ #define DATAFILE "data" /* file giving the meaning of symbols used */ #define CMDHELPFILE "cmdhelp" /* file telling what commands do */ #define HISTORY "history" /* file giving nethack's history */ #define LICENSE "license" /* file with license information */ #define OPTIONFILE "opthelp" /* file explaining runtime options */ #define OPTIONS_USED "options" /* compile-time options, for #version */ #define LEV_EXT ".lev" /* extension for special level files */ /* Assorted definitions that may depend on selections in config.h. */ /* * for DUMB preprocessor and compiler, e.g., cpp and pcc supplied * with Microport SysV/AT, which have small symbol tables; * DUMB if needed is defined in CFLAGS */ #ifdef DUMB #ifdef BITFIELDS #undef BITFIELDS #endif #ifndef STUPID #define STUPID #endif #endif /* DUMB */ /* * type xchar: small integers in the range 0 - 127, usually coordinates * although they are nonnegative they must not be declared unsigned * since otherwise comparisons with signed quantities are done incorrectly */ typedef schar xchar; #ifndef SKIP_BOOLEAN typedef xchar boolean; /* 0 or 1 */ #endif #ifndef TRUE /* defined in some systems' native include files */ #define TRUE ((boolean)1) #define FALSE ((boolean)0) #endif #ifndef STRNCMPI # ifndef __SASC_60 /* SAS/C already shifts to stricmp */ # define strcmpi(a,b) strncmpi((a),(b),-1) # endif #endif /* comment out to test effects of each #define -- these will probably * disappear eventually */ #ifdef INTERNAL_COMP # define RLECOMP /* run-length compression of levl array - JLee */ # define ZEROCOMP /* zero-run compression of everything - Olaf Seibert */ #endif /* #define SPECIALIZATION */ /* do "specialized" version of new topology */ #ifdef BITFIELDS #define Bitfield(x,n) unsigned x:n #else #define Bitfield(x,n) uchar x #endif #ifdef UNWIDENED_PROTOTYPES # define CHAR_P char # define SCHAR_P schar # define UCHAR_P uchar # define XCHAR_P xchar # define SHORT_P short #ifndef SKIP_BOOLEAN # define BOOLEAN_P boolean #endif # define ALIGNTYP_P aligntyp #else # ifdef WIDENED_PROTOTYPES # define CHAR_P int # define SCHAR_P int # define UCHAR_P int # define XCHAR_P int # define SHORT_P int # define BOOLEAN_P int # define ALIGNTYP_P int # endif #endif #if defined(ULTRIX_PROTO) && !defined(__STDC__) /* The ultrix 2.0 and 2.1 compilers (on Ultrix 4.0 and 4.2 respectively) can't * handle "struct obj *" constructs in prototypes. Their bugs are different, * but both seem to work if we put "void*" in the prototype instead. This * gives us minimal prototype checking but avoids the compiler bugs. * * OBJ_P and MONST_P should _only_ be used for declaring function pointers. */ #define OBJ_P void* #define MONST_P void* #else #define OBJ_P struct obj* #define MONST_P struct monst* #endif #define SIZE(x) (int)(sizeof(x) / sizeof(x[0])) /* A limit for some NetHack int variables. It need not, and for comparable * scoring should not, depend on the actual limit on integers for a * particular machine, although it is set to the minimum required maximum * signed integer for C (2^15 -1). */ #define LARGEST_INT 32767 #ifdef REDO #define Getchar pgetchar #endif #include "coord.h" /* * Automatic inclusions for the subsidiary files. * Please don't change the order. It does matter. */ #ifdef VMS #include "vmsconf.h" #endif #ifdef UNIX #include "unixconf.h" #endif #ifdef OS2 #include "os2conf.h" #endif #ifdef MSDOS #include "pcconf.h" #endif #ifdef TOS #include "tosconf.h" #endif #ifdef AMIGA #include "amiconf.h" #endif #ifdef MAC #include "macconf.h" #endif #ifdef __BEOS__ #include "beconf.h" #endif #ifdef WIN32 #ifdef WIN_CE #include "wceconf.h" #else #include "ntconf.h" #endif #endif /* Displayable name of this port; don't redefine if defined in *conf.h */ #ifndef PORT_ID # ifdef AMIGA # define PORT_ID "Amiga" # endif # ifdef MAC # define PORT_ID "Mac" # endif # ifdef MSDOS # ifdef PC9800 # define PORT_ID "PC-9800" # else # define PORT_ID "PC" # endif # ifdef DJGPP # define PORT_SUB_ID "djgpp" # else # ifdef OVERLAY # define PORT_SUB_ID "overlaid" # else # define PORT_SUB_ID "non-overlaid" # endif # endif # endif # ifdef OS2 # define PORT_ID "OS/2" # endif # ifdef TOS # define PORT_ID "ST" # endif # ifdef UNIX # define PORT_ID "Unix" # endif # ifdef VMS # define PORT_ID "VMS" # endif # ifdef WIN32 # define PORT_ID "Windows" # ifndef PORT_SUB_ID # ifdef MSWIN_GRAPHICS # define PORT_SUB_ID "graphical" # else # define PORT_SUB_ID "tty" # endif # endif # endif #endif #if defined(MICRO) #if !defined(AMIGA) && !defined(TOS) && !defined(OS2_HPFS) #define SHORT_FILENAMES /* filenames are 8.3 */ #endif #endif #ifdef VMS /* vms_exit() (sys/vms/vmsmisc.c) expects the non-VMS EXIT_xxx values below. * these definitions allow all systems to be treated uniformly, provided * main() routines do not terminate with return(), whose value is not * so massaged. */ # ifdef EXIT_SUCCESS # undef EXIT_SUCCESS # endif # ifdef EXIT_FAILURE # undef EXIT_FAILURE # endif #endif #ifndef EXIT_SUCCESS # define EXIT_SUCCESS 0 #endif #ifndef EXIT_FAILURE # define EXIT_FAILURE 1 #endif #if defined(X11_GRAPHICS) || defined(QT_GRAPHICS) || defined(GNOME_GRAPHICS) || defined(MSWIN_GRAPHICS) # ifndef USE_TILES # define USE_TILES /* glyph2tile[] will be available */ # endif #endif #if defined(AMII_GRAPHICS) || defined(GEM_GRAPHICS) # ifndef USE_TILES # define USE_TILES # endif #endif #define Sprintf (void) sprintf #define Strcat (void) strcat #define Strcpy (void) strcpy #ifdef NEED_VARARGS #define Vprintf (void) vprintf #define Vfprintf (void) vfprintf #define Vsprintf (void) vsprintf #endif /* primitive memory leak debugging; see alloc.c */ #ifdef MONITOR_HEAP extern long *FDECL(nhalloc, (unsigned int,const char *,int)); extern void FDECL(nhfree, (genericptr_t,const char *,int)); # ifndef __FILE__ # define __FILE__ "" # endif # ifndef __LINE__ # define __LINE__ 0 # endif # define alloc(a) nhalloc(a,__FILE__,(int)__LINE__) # define free(a) nhfree(a,__FILE__,(int)__LINE__) #else /* !MONITOR_HEAP */ extern long *FDECL(alloc, (unsigned int)); /* alloc.c */ #endif /* Used for consistency checks of various data files; declare it here so that utility programs which include config.h but not hack.h can see it. */ struct version_info { unsigned long incarnation; /* actual version number */ unsigned long feature_set; /* bitmask of config settings */ unsigned long entity_count; /* # of monsters and objects */ unsigned long struct_sizes; /* size of key structs */ }; /* * Configurable internal parameters. * * Please be very careful if you are going to change one of these. Any * changes in these parameters, unless properly done, can render the * executable inoperative. */ /* size of terminal screen is (at least) (ROWNO+3) by COLNO */ #define COLNO 80 #define ROWNO 21 #define MAXNROFROOMS 40 /* max number of rooms per level */ #define MAX_SUBROOMS 24 /* max # of subrooms in a given room */ #define DOORMAX 120 /* max number of doors per level */ #define BUFSZ 256 /* for getlin buffers */ #define QBUFSZ 128 /* for building question text */ #define TBUFSZ 300 /* toplines[] buffer max msg: 3 81char names */ /* plus longest prefix plus a few extra words */ #define PL_NSIZ 32 /* name of player, ghost, shopkeeper */ #define PL_CSIZ 32 /* sizeof pl_character */ #define PL_FSIZ 32 /* fruit name */ #define PL_PSIZ 63 /* player-given names for pets, other * monsters, objects */ #define MAXDUNGEON 16 /* current maximum number of dungeons */ #define MAXLEVEL 32 /* max number of levels in one dungeon */ #define MAXSTAIRS 1 /* max # of special stairways in a dungeon */ #define ALIGNWEIGHT 4 /* generation weight of alignment */ #define MAXULEV 30 /* max character experience level */ #define MAXMONNO 120 /* extinct monst after this number created */ #define MHPMAX 500 /* maximum monster hp */ #endif /* GLOBAL_H */ nethack-3.4.3/include/hack.h0100644000000000000000000002356607764735041014370 0ustar rootroot/* SCCS Id: @(#)hack.h 3.4 2001/04/12 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef HACK_H #define HACK_H #ifndef CONFIG_H #include "config.h" #endif /* For debugging beta code. */ #ifdef BETA #define Dpline pline #endif #define TELL 1 #define NOTELL 0 #define ON 1 #define OFF 0 #define BOLT_LIM 8 /* from this distance ranged attacks will be made */ #define MAX_CARR_CAP 1000 /* so that boulders can be heavier */ #define DUMMY { 0 } /* symbolic names for capacity levels */ #define UNENCUMBERED 0 #define SLT_ENCUMBER 1 /* Burdened */ #define MOD_ENCUMBER 2 /* Stressed */ #define HVY_ENCUMBER 3 /* Strained */ #define EXT_ENCUMBER 4 /* Overtaxed */ #define OVERLOADED 5 /* Overloaded */ /* Macros for how a rumor was delivered in outrumor() */ #define BY_ORACLE 0 #define BY_COOKIE 1 #define BY_PAPER 2 #define BY_OTHER 9 #ifdef STEED /* Macros for why you are no longer riding */ #define DISMOUNT_GENERIC 0 #define DISMOUNT_FELL 1 #define DISMOUNT_THROWN 2 #define DISMOUNT_POLY 3 #define DISMOUNT_ENGULFED 4 #define DISMOUNT_BONES 5 #define DISMOUNT_BYCHOICE 6 #endif /* Special returns from mapglyph() */ #define MG_CORPSE 0x01 #define MG_INVIS 0x02 #define MG_DETECT 0x04 #define MG_PET 0x08 #define MG_RIDDEN 0x10 /* sellobj_state() states */ #define SELL_NORMAL (0) #define SELL_DELIBERATE (1) #define SELL_DONTSELL (2) /* * This is the way the game ends. If these are rearranged, the arrays * in end.c and topten.c will need to be changed. Some parts of the * code assume that PANIC separates the deaths from the non-deaths. */ #define DIED 0 #define CHOKING 1 #define POISONING 2 #define STARVING 3 #define DROWNING 4 #define BURNING 5 #define DISSOLVED 6 #define CRUSHING 7 #define STONING 8 #define TURNED_SLIME 9 #define GENOCIDED 10 #define PANICKED 11 #define TRICKED 12 #define QUIT 13 #define ESCAPED 14 #define ASCENDED 15 #include "align.h" #include "dungeon.h" #include "monsym.h" #include "mkroom.h" #include "objclass.h" #include "youprop.h" #include "wintype.h" #include "decl.h" #include "timeout.h" NEARDATA extern coord bhitpos; /* place where throw or zap hits or stops */ /* types of calls to bhit() */ #define ZAPPED_WAND 0 #define THROWN_WEAPON 1 #define KICKED_WEAPON 2 #define FLASHED_LIGHT 3 #define INVIS_BEAM 4 #define MATCH_WARN_OF_MON(mon) (Warn_of_mon && flags.warntype && \ (flags.warntype & (mon)->data->mflags2)) #include "trap.h" #include "flag.h" #include "rm.h" #include "vision.h" #include "display.h" #include "engrave.h" #include "rect.h" #include "region.h" #ifdef USE_TRAMPOLI /* This doesn't belong here, but we have little choice */ #undef NDECL #define NDECL(f) f() #endif #include "extern.h" #include "winprocs.h" #ifdef USE_TRAMPOLI #include "wintty.h" #undef WINTTY_H #include "trampoli.h" #undef EXTERN_H #include "extern.h" #endif /* USE_TRAMPOLI */ #define NO_SPELL 0 /* flags to control makemon() */ #define NO_MM_FLAGS 0x00 /* use this rather than plain 0 */ #define NO_MINVENT 0x01 /* suppress minvent when creating mon */ #define MM_NOWAIT 0x02 /* don't set STRAT_WAITMASK flags */ #define MM_EDOG 0x04 /* add edog structure */ #define MM_EMIN 0x08 /* add emin structure */ #define MM_ANGRY 0x10 /* monster is created angry */ #define MM_NONAME 0x20 /* monster is not christened */ #define MM_NOCOUNTBIRTH 0x40 /* don't increment born counter (for revival) */ #define MM_IGNOREWATER 0x80 /* ignore water when positioning */ #define MM_ADJACENTOK 0x100 /* it is acceptable to use adjacent coordinates */ /* special mhpmax value when loading bones monster to flag as extinct or genocided */ #define DEFUNCT_MONSTER (-100) /* flags for special ggetobj status returns */ #define ALL_FINISHED 0x01 /* called routine already finished the job */ /* flags to control query_objlist() */ #define BY_NEXTHERE 0x1 /* follow objlist by nexthere field */ #define AUTOSELECT_SINGLE 0x2 /* if only 1 object, don't ask */ #define USE_INVLET 0x4 /* use object's invlet */ #define INVORDER_SORT 0x8 /* sort objects by packorder */ #define SIGNAL_NOMENU 0x10 /* return -1 rather than 0 if none allowed */ #define FEEL_COCKATRICE 0x20 /* engage cockatrice checks and react */ /* Flags to control query_category() */ /* BY_NEXTHERE used by query_category() too, so skip 0x01 */ #define UNPAID_TYPES 0x02 #define GOLD_TYPES 0x04 #define WORN_TYPES 0x08 #define ALL_TYPES 0x10 #define BILLED_TYPES 0x20 #define CHOOSE_ALL 0x40 #define BUC_BLESSED 0x80 #define BUC_CURSED 0x100 #define BUC_UNCURSED 0x200 #define BUC_UNKNOWN 0x400 #define BUC_ALLBKNOWN (BUC_BLESSED|BUC_CURSED|BUC_UNCURSED) #define ALL_TYPES_SELECTED -2 /* Flags to control find_mid() */ #define FM_FMON 0x01 /* search the fmon chain */ #define FM_MIGRATE 0x02 /* search the migrating monster chain */ #define FM_MYDOGS 0x04 /* search mydogs */ #define FM_EVERYWHERE (FM_FMON | FM_MIGRATE | FM_MYDOGS) /* Flags to control pick_[race,role,gend,align] routines in role.c */ #define PICK_RANDOM 0 #define PICK_RIGID 1 /* Flags to control dotrap() in trap.c */ #define NOWEBMSG 0x01 /* suppress stumble into web message */ #define FORCEBUNGLE 0x02 /* adjustments appropriate for bungling */ #define RECURSIVETRAP 0x04 /* trap changed into another type this same turn */ /* Flags to control test_move in hack.c */ #define DO_MOVE 0 /* really doing the move */ #define TEST_MOVE 1 /* test a normal move (move there next) */ #define TEST_TRAV 2 /* test a future travel location */ /*** some utility macros ***/ #define yn(query) yn_function(query,ynchars, 'n') #define ynq(query) yn_function(query,ynqchars, 'q') #define ynaq(query) yn_function(query,ynaqchars, 'y') #define nyaq(query) yn_function(query,ynaqchars, 'n') #define nyNaq(query) yn_function(query,ynNaqchars, 'n') #define ynNaq(query) yn_function(query,ynNaqchars, 'y') /* Macros for scatter */ #define VIS_EFFECTS 0x01 /* display visual effects */ #define MAY_HITMON 0x02 /* objects may hit monsters */ #define MAY_HITYOU 0x04 /* objects may hit you */ #define MAY_HIT (MAY_HITMON|MAY_HITYOU) #define MAY_DESTROY 0x08 /* objects may be destroyed at random */ #define MAY_FRACTURE 0x10 /* boulders & statues may fracture */ /* Macros for launching objects */ #define ROLL 0x01 /* the object is rolling */ #define FLING 0x02 /* the object is flying thru the air */ #define LAUNCH_UNSEEN 0x40 /* hero neither caused nor saw it */ #define LAUNCH_KNOWN 0x80 /* the hero caused this by explicit action */ /* Macros for explosion types */ #define EXPL_DARK 0 #define EXPL_NOXIOUS 1 #define EXPL_MUDDY 2 #define EXPL_WET 3 #define EXPL_MAGICAL 4 #define EXPL_FIERY 5 #define EXPL_FROSTY 6 #define EXPL_MAX 7 /* Macros for messages referring to hands, eyes, feet, etc... */ #define ARM 0 #define EYE 1 #define FACE 2 #define FINGER 3 #define FINGERTIP 4 #define FOOT 5 #define HAND 6 #define HANDED 7 #define HEAD 8 #define LEG 9 #define LIGHT_HEADED 10 #define NECK 11 #define SPINE 12 #define TOE 13 #define HAIR 14 #define BLOOD 15 #define LUNG 16 #define NOSE 17 #define STOMACH 18 /* Flags to control menus */ #define MENUTYPELEN sizeof("traditional ") #define MENU_TRADITIONAL 0 #define MENU_COMBINATION 1 #define MENU_PARTIAL 2 #define MENU_FULL 3 #define MENU_SELECTED TRUE #define MENU_UNSELECTED FALSE /* * Option flags * Each higher number includes the characteristics of the numbers * below it. */ #define SET_IN_FILE 0 /* config file option only */ #define SET_VIA_PROG 1 /* may be set via extern program, not seen in game */ #define DISP_IN_GAME 2 /* may be set via extern program, displayed in game */ #define SET_IN_GAME 3 /* may be set via extern program or set in the game */ #define FEATURE_NOTICE_VER(major,minor,patch) (((unsigned long)major << 24) | \ ((unsigned long)minor << 16) | \ ((unsigned long)patch << 8) | \ ((unsigned long)0)) #define FEATURE_NOTICE_VER_MAJ (flags.suppress_alert >> 24) #define FEATURE_NOTICE_VER_MIN (((unsigned long)(0x0000000000FF0000L & flags.suppress_alert)) >> 16) #define FEATURE_NOTICE_VER_PATCH (((unsigned long)(0x000000000000FF00L & flags.suppress_alert)) >> 8) #ifndef max #define max(a,b) ((a) > (b) ? (a) : (b)) #endif #ifndef min #define min(x,y) ((x) < (y) ? (x) : (y)) #endif #define plur(x) (((x) == 1) ? "" : "s") #define ARM_BONUS(obj) (objects[(obj)->otyp].a_ac + (obj)->spe \ - min((int)greatest_erosion(obj),objects[(obj)->otyp].a_ac)) #define makeknown(x) discover_object((x),TRUE,TRUE) #define distu(xx,yy) dist2((int)(xx),(int)(yy),(int)u.ux,(int)u.uy) #define onlineu(xx,yy) online2((int)(xx),(int)(yy),(int)u.ux,(int)u.uy) #define rn1(x,y) (rn2(x)+(y)) /* negative armor class is randomly weakened to prevent invulnerability */ #define AC_VALUE(AC) ((AC) >= 0 ? (AC) : -rnd(-(AC))) #if defined(MICRO) && !defined(__DJGPP__) #define getuid() 1 #define getlogin() ((char *)0) #endif /* MICRO */ #if defined(OVERLAY)&&(defined(OVL0)||defined(OVL1)||defined(OVL2)||defined(OVL3)||defined(OVLB)) # define USE_OVLx # define STATIC_DCL extern # define STATIC_OVL # ifdef OVLB # define STATIC_VAR # else # define STATIC_VAR extern # endif #else /* !OVERLAY || (!OVL0 && !OVL1 && !OVL2 && !OVL3 && !OVLB) */ # define STATIC_DCL static # define STATIC_OVL static # define STATIC_VAR static /* If not compiling an overlay, compile everything. */ # define OVL0 /* highest priority */ # define OVL1 # define OVL2 # define OVL3 /* lowest specified priority */ # define OVLB /* the base overlay segment */ #endif /* OVERLAY && (OVL0 || OVL1 || OVL2 || OVL3 || OVLB) */ /* Macro for a few items that are only static if we're not overlaid.... */ #if defined(USE_TRAMPOLI) || defined(USE_OVLx) # define STATIC_PTR #else # define STATIC_PTR static #endif /* The function argument to qsort() requires a particular * calling convention under WINCE which is not the default * in that environment. */ #if defined(WIN_CE) # define CFDECLSPEC __cdecl #else # define CFDECLSPEC #endif #endif /* HACK_H */ nethack-3.4.3/include/lev.h0100644000000000000000000000244207764735041014236 0ustar rootroot/* SCCS Id: @(#)lev.h 3.4 1994/03/18 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Common include file for save and restore routines */ #ifndef LEV_H #define LEV_H #define COUNT_SAVE 0x1 #define WRITE_SAVE 0x2 #define FREE_SAVE 0x4 /* operations of the various saveXXXchn & co. routines */ #define perform_bwrite(mode) ((mode) & (COUNT_SAVE|WRITE_SAVE)) #define release_data(mode) ((mode) & FREE_SAVE) /* The following are used in mkmaze.c */ struct container { struct container *next; xchar x, y; short what; genericptr_t list; }; #define CONS_OBJ 0 #define CONS_MON 1 #define CONS_HERO 2 #define CONS_TRAP 3 struct bubble { xchar x, y; /* coordinates of the upper left corner */ schar dx, dy; /* the general direction of the bubble's movement */ uchar *bm; /* pointer to the bubble bit mask */ struct bubble *prev, *next; /* need to traverse the list up and down */ struct container *cons; }; /* used in light.c */ typedef struct ls_t { struct ls_t *next; xchar x, y; /* source's position */ short range; /* source's current range */ short flags; short type; /* type of light source */ genericptr_t id; /* source's identifier */ } light_source; #endif /* LEV_H */ nethack-3.4.3/include/load_img.h0100644000000000000000000000324207764735041015222 0ustar rootroot /* ------------------------------------------- */ #define XIMG 0x58494D47 /* Header of GEM Image Files */ typedef struct IMG_HEADER{ short version; /* Img file format version (1) */ short length; /* Header length in words (8) */ short planes; /* Number of bit-planes (1) */ short pat_len; /* length of Patterns (2) */ short pix_w; /* Pixel width in 1/1000 mmm (372) */ short pix_h; /* Pixel height in 1/1000 mmm (372) */ short img_w; /* Pixels per line (=(x+7)/8 Bytes) */ short img_h; /* Total number of lines */ long magic; /* Contains "XIMG" if standard color */ short paltype; /* palette type (0=RGB (short each)) */ short *palette; /* palette etc. */ char *addr; /* Address for the depacked bit-planes */ } IMG_header; /* ------------------------------------------- */ /* error codes */ #define ERR_HEADER 1 #define ERR_ALLOC 2 #define ERR_FILE 3 #define ERR_DEPACK 4 #define ERR_COLOR 5 /* saves the current colorpalette with col colors in palette */ void get_colors(int handle, short *palette, int col); /* sets col colors from palette */ void img_set_colors(int handle,short *palette, int col); /* converts MFDB of size from standard to deviceformat (0 if succeded, else error). */ int convert(MFDB *, long ); /* transforms image in VDI-Device format */ int transform_img(MFDB *); /* Loads & depacks IMG (0 if succeded, else error). */ /* Bitplanes are one after another in address IMG_HEADER.addr. */ int depack_img(char *, IMG_header *); /* Halves IMG in Device-format, dest memory has to be allocated*/ int half_img(MFDB *,MFDB *); nethack-3.4.3/include/mac-carbon.h0100644000000000000000000000171507764735041015454 0ustar rootroot/* SCCS Id: @(#)mac-carbon.h 3.4 2003/06/01 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /* NetHack may be freely redistributed. See license for details. */ /* Compiler prefix file for the Macintosh Carbon port. * * IMPORTANT: This file is intended only as a compiler prefix * file and must NEVER be included by other source (.c or .h) * files. * * Usage for MacOS X Project Builder: * Project menu -> Edit Active Target '_target_' -> * target settings dialog -> Settings -> Simple View -> * GCC Compiler Settings -> * set "Prefix Header" to include/mac-carbon.h * * Usage for Metrowerks CodeWarrior: * Edit menu -> _target_ Settings -> Language Settings -> * C/C++ Language -> * set "Prefix File" to include/mac-carbon.h */ #define MAC #undef UNIX /* May already be defined by CodeWarrior as 0 or 1 */ #ifdef TARGET_API_MAC_CARBON # undef TARGET_API_MAC_CARBON #endif #define TARGET_API_MAC_CARBON 1 #define GCC_WARN nethack-3.4.3/include/mac-qt.h0100644000000000000000000000171107764735041014630 0ustar rootroot/* SCCS Id: @(#)mac-qt.h 3.4 2003/06/01 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /* NetHack may be freely redistributed. See license for details. */ /* Compiler prefix file for the Macintosh Qt port. * * IMPORTANT: This file is intended only as a compiler prefix * file and must NEVER be included by other source (.c or .h) * files. * * Usage for MacOS X Project Builder: * Project menu -> Edit Active Target '_target_' -> * target settings dialog -> Settings -> Simple View -> * GCC Compiler Settings -> * set "Prefix Header" to include/mac-qt.h * * Usage for Metrowerks CodeWarrior: * Edit menu -> _target_ Settings -> Language Settings -> * C/C++ Language -> * set "Prefix File" to include/mac-qt.h */ #undef MAC #define UNIX #define BSD /* May already be defined by CodeWarrior as 0 or 1 */ #ifdef TARGET_API_MAC_CARBON # undef TARGET_API_MAC_CARBON #endif #define TARGET_API_MAC_CARBON 0 #define GCC_WARN nethack-3.4.3/include/mac-term.h0100644000000000000000000000211107764735041015146 0ustar rootroot/* SCCS Id: @(#)mac-term.h 3.4 2003/06/01 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 2003. */ /* NetHack may be freely redistributed. See license for details. */ /* Compiler prefix file for the MacOS X Terminal.app port. * * IMPORTANT: This file is intended only as a compiler prefix * file and must NEVER be included by other source (.c or .h) * files. * * Usage for MacOS X Project Builder: * Project menu -> Edit Active Target '_target_' -> * target settings dialog -> Settings -> Simple View -> * GCC Compiler Settings -> * set "Prefix Header" to include/mac-term.h * * Usage for Metrowerks CodeWarrior: * Edit menu -> _target_ Settings -> Language Settings -> * C/C++ Language -> * set "Prefix File" to include/mac-term.h */ /* Stuff needed for the core of NetHack */ #undef MAC #define UNIX #define BSD #define __FreeBSD__ /* Darwin is based on FreeBSD */ #define GCC_WARN /* May already be defined by CodeWarrior as 0 or 1 */ #ifdef TARGET_API_MAC_CARBON # undef TARGET_API_MAC_CARBON #endif #define TARGET_API_MAC_CARBON 0 /* Not Carbon */ nethack-3.4.3/include/macconf.h0100644000000000000000000000577007764735041015065 0ustar rootroot/* SCCS Id: @(#)macconf.h 3.4 1999/10/25 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef MAC # ifndef MACCONF_H # define MACCONF_H /* * Compiler selection is based on the following symbols: * * __SC__ sc, a MPW 68k compiler * __MRC__ mrc, a MPW PowerPC compiler * THINK_C Think C compiler * __MWERKS__ Metrowerks' Codewarrior compiler * * We use these early in config.h to define some needed symbols, * including MAC. # # The Metrowerks compiler defines __STDC__ (which sets NHSTC) and uses # WIDENED_PROTOTYPES (defined if UNWIDENED_PROTOTYPES is undefined and # NHSTDC is defined). */ #ifndef __powerc # define MAC68K /* 68K mac (non-powerpc) */ #endif #ifndef TARGET_API_MAC_CARBON # define TARGET_API_MAC_CARBON 0 #endif #ifndef __MACH__ #define RANDOM #endif #define NO_SIGNAL /* You wouldn't believe our signals ... */ #define FILENAME 256 #define NO_TERMS /* For tty port (see wintty.h) */ #define TEXTCOLOR /* For Mac TTY interface */ #define CHANGE_COLOR /* Use these two includes instead of system.h. */ #include #include /* Uncomment this line if your headers don't already define off_t */ /*typedef long off_t;*/ #include /* for time_t */ /* * Try and keep the number of files here to an ABSOLUTE minimum ! * include the relevant files in the relevant .c files instead ! */ #if TARGET_API_MAC_CARBON /* Avoid including -- it has a conflicting expl() */ # define __FP__ # include #else # include #endif /* * We could use the PSN under sys 7 here ... * ...but it wouldn't matter... */ #define getpid() 1 #define getuid() 1 #define index strchr #define rindex strrchr #define Rand random extern void error(const char *,...); #if !defined(O_WRONLY) # ifdef __MWERKS__ # include # endif # include #endif /* * Don't redefine these Unix IO functions when making LevComp or DgnComp for * MPW. With MPW, we make them into MPW tools, which use unix IO. SPEC_LEV * and DGN_COMP are defined when compiling for LevComp and DgnComp respectively. */ #if !((defined(__SC__) || defined(__MRC__) || defined(__MACH__)) && (defined(SPEC_LEV) || defined(DGN_COMP))) # define creat maccreat # define open macopen # define close macclose # define read macread # define write macwrite # define lseek macseek #ifdef __MWERKS__ # define unlink _unlink #endif #endif #define YY_NEVER_INTERACTIVE 1 # define TEXT_TYPE 'TEXT' # define LEVL_TYPE 'LEVL' # define BONE_TYPE 'BONE' # define SAVE_TYPE 'SAVE' # define PREF_TYPE 'PREF' # define DATA_TYPE 'DATA' # define MAC_CREATOR 'nh31' /* Registered with DTS ! */ # define TEXT_CREATOR 'ttxt' /* Something the user can actually edit */ /* * Define PORT_HELP to be the name of the port-specfic help file. * This file is included into the resource fork of the application. */ #define PORT_HELP "MacHelp" #define MAC_GRAPHICS_ENV # endif /* ! MACCONF_H */ #endif /* MAC */ nethack-3.4.3/include/macpopup.h0100644000000000000000000000071507764735041015275 0ustar rootroot/* SCCS Id: @(#)macpopup.h 3.4 1999/10/25 */ /* Copyright (c) Nethack Develpment Team, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MACPOPUP_H # define MACPOPUP_H /* ### mmodal.c ### */ extern void FlashButton(DialogRef, short); extern char queued_resp(char *resp); extern char topl_yn_function(const char *query, const char *resp, char def); extern int get_line_from_key_queue(char *bufp); #endif /* MACPOPUP_H */ nethack-3.4.3/include/mactty.h0100644000000000000000000002531507764735041014755 0ustar rootroot/* SCCS Id: @(#)mactty.h 3.4 1993/03/01 */ /* Copyright (c) Jon W{tte 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* * This header is the supported external interface for the "tty" window * package. This package sports care-free handling of "dumb" tty windows * (preferrably using monospaced fonts) - it does NOT remember the strings * sent to it; rather, it uses an offscreen bitmap. * * For best performance, make sure it is aligned on a 32-pixel boundary * (or at least a 16-pixel one) in black & white. For 24bit color, * alignment doesn't matter, and for 8-bit color, alignment to every * fourth pixel is most efficient. * * (c) Copyright 1993 Jon W{tte */ /* * You should really not poke in the structures used by the tty window. * However, since it uses the wRefCon of windows (by calling GetWRefCon * and SetWRefCon) you lose that possibility. If you still want to store * information about a window, the FIRST location _pointed to_ by the * wRefCon will be a void * that you can use for whatever reasons. Don't * take the address of this variable and expect it to stay the same * across calls to the tty window. * * void * my_config_ptr = * ( void * * ) GetWRefCon ( tty_window ) ; */ /* * The library uses the window's port temporarily through SetPortBits; * that means you shouldn't do any funky things to the clipping region * etc. Actually, you shouldn't even resize the window, as that will clip * new drawing. * * Also, if you use this library under Pascal, remember that the string * passed to add_tty_string() is a "C" style string with NO length byte, * and a terminating zero byte at the end instead. */ #ifndef _H_tty_public # define _H_tty_public #undef red /* undef internal color const strings from decl */ #undef green #undef blue #if !TARGET_API_MAC_CARBON # include #endif /* * Error code returned when it's probably our fault, or * bad parameters. */ #define general_failure 1 /* * Base resource id's for window types */ #define WIN_BASE_RES 128 #define WIN_BASE_KIND 128 /* * Commonly used characters */ #define CHAR_ENTER ((char)3) #define CHAR_BELL ((char)7) #define CHAR_BS ((char)8) #define CHAR_LF ((char)10) #define CHAR_CR ((char)13) #define CHAR_ESC ((char)27) #define CHAR_BLANK ((char)32) #define CHAR_DELETE ((char)127) extern char game_active; /* flag to window rendering routines not to use ppat */ /* * If you want some fancy operations that not a normal TTY device normally * supports, use EXTENDED_SUPPORT. For frames, area erases and area scrolls, * plus bitmap graphics - RESOLUTION DEPENDENT, be sure to call * get_tty_metrics and use those limits. */ #define EXTENDED_SUPPORT 0 /* * if you print a lot of single characters, accumulating each one in a * clipping region will take too much time. Instead, define this, which * will clip in rects. */ #define CLIP_RECT_ONLY 1 typedef enum tty_attrib { /* * Flags relating to the general functioning of the window. * These flags are passed at create_tty time, and changing them * later will clear the screen. */ TTY_ATTRIB_FLAGS , /* * When using proportional fonts, this will place each character * separately, ensuring aligned columns (but looking ugly and taking * time) */ # define TA_MOVE_EACH_CHAR 1L /* * This means draw each change as it occurs instead of collecting the area * and draw it all at once at update_tty() - slower, but more reliable. */ # define TA_ALWAYS_REFRESH 2L /* * When reaching the right end, we either just stop drawing, or wrap to the * next line. */ # define TA_WRAP_AROUND 4L /* * Overstrike means that characters are added on top of each other; i e don't * clear the letter beneath. This is faster, using srcOr under QuickDraw */ # define TA_OVERSTRIKE 8L /* * We may want the window not to scroll when we reach the end line, * but stop drawing instead. */ # define TA_INHIBIT_VERT_SCROLL 16L /* * Foreground and background colors. These only affect characters * drawn by subsequent calls; not what's already there (but it does * affect clears) * On b/w screens these do nothing. */ TTY_ATTRIB_FOREGROUND , TTY_ATTRIB_BACKGROUND , # define TA_RGB_TO_TTY(r) ((((long)((r).red>>8)&0xff)<<16)+\ (((long)((r).green>>8)&0xff)<<8)+((long)((r).blue>>8)&0xff)) /* * Attributes relating to the cursor, and character set mappings */ TTY_ATTRIB_CURSOR , /* * Blinking cursor is more noticeable when it's idle */ # define TA_BLINKING_CURSOR 1L /* * When handling input, do we echo characters as they are typed? */ # define TA_ECHO_INPUT 2L /* * Do we return each character code separately, or map delete etc? Note * that non-raw input means getchar won't return anything until the user * has typed a return. */ # define TA_RAW_INPUT 4L /* * Do we print every character as it is (including BS, NL and CR!) or do * do we interpret characters such as NL, BS and CR? */ # define TA_RAW_OUTPUT 8L /* * When getting a NL, do we also move to the left? */ # define TA_NL_ADD_CR 16L /* * When getting a CR, do we also move down? */ # define TA_CR_ADD_NL 32L /* * Wait for input or return what we've got? */ # define TA_NONBLOCKING_IO 64L /* * Use this macro to cast a function pointer to a tty attribute; this will help * portability to systems where a function pointer doesn't fit in a long */ # define TA_ATTRIB_FUNC(x) ((long)(x)) /* * This symbolic constant is used to check the number of attributes */ TTY_NUMBER_ATTRIBUTES } tty_attrib ; /* * Character returned by end-of-file condition */ # define TTY_EOF -1 /* * Create the window according to a resource WIND template. * The window pointer pointed to by window should be NULL to * allocate the window record dynamically, or point to a * WindowRecord structure already allocated. * * Passing in_color means you have to be sure there's color support; * on the Mac, this means 32bit QuickDraw present, else it will * crash. Not passing in_color means everything's rendered in * black & white. */ extern short create_tty ( WindowPtr * window , short resource_id , Boolean in_color ) ; /* * Use init_tty_name or init_tty_number to initialize a window * once allocated by create_tty. Size parameters are in characters. */ extern short init_tty_number ( WindowPtr window , short font_number , short font_size , short x_size , short y_size ) ; /* * Close and deallocate a window and its data */ extern short destroy_tty ( WindowPtr window ) ; /* * Change the font and font size used in the window for drawing after * the calls are made. To change the coordinate system, be sure to call * force_tty_coordinate_system_recalc() - else it may look strange if * the new font doesn't match the old one. */ extern short set_tty_font_name (winid window_type , char * name ) ; extern short force_tty_coordinate_system_recalc ( WindowPtr window ) ; /* * Getting some metrics about the tty and its drawing. */ extern short get_tty_metrics ( WindowPtr window , short * x_size , short * y_size , short * x_size_pixels , short * y_size_pixels , short * font_number , short * font_size , short * char_width , short * row_height ) ; /* * The basic move cursor function. 0,0 is topleft. */ extern short move_tty_cursor ( WindowPtr window , short x_pos , short y_pos ) ; /* * Flush all changes done to a tty to the screen (see TA_ALWAYS_UPDATE above) */ extern short update_tty ( WindowPtr window ) ; /* * Add a character to the tty and update the cursor position */ extern short add_tty_char ( WindowPtr window , short character ) ; /* * Add a string of characters to the tty and update the cursor * position. The string is 0-terminated! */ extern short add_tty_string ( WindowPtr window , const char * string ) ; /* * Change or read an attribute of the tty. Note that some attribute changes * may clear the screen. See the above enum and defines for values. * Attributes can be both function pointers and special flag values. */ extern short get_tty_attrib ( WindowPtr window , tty_attrib attrib , long * value ) ; extern short set_tty_attrib ( WindowPtr window , tty_attrib attrib , long value ) ; /* * Scroll the actual TTY image, in characters, positive means up/left * scroll_tty ( my_tty , 0 , 1 ) means a linefeed. Is always carried out * directly, regardless of the wait-update setting. Does updates before * scrolling. */ extern short scroll_tty ( WindowPtr window , short delta_x , short delta_y ) ; /* * Erase the offscreen bitmap and move the cursor to 0,0. Re-init some window * values (font etc) Is always carried out directly on-screen, regardless of * the wait-for-update setting. Clears update area. */ extern short clear_tty ( WindowPtr window ) ; /* * Call this routine with a window (always _mt_window) and a time (usually * from most recent event) to determine if cursor in window should be blinked */ extern short blink_cursor ( WindowPtr window , long when ) ; /* * For screen dumps, open the printer port and call this function. Can be used * for clipboard as well (only for a PICT, though; this library doesn't concern * itself with characters, just bitmaps) */ extern short image_tty ( EventRecord *theEvent, WindowPtr window ) ; /* * For erasing just an area of characters */ extern short clear_tty_window ( WindowPtr window , short from_row , short from_col , short to_row , short to_col ) ; /* * get and set the invalid region of the main window */ extern short get_invalid_region (WindowPtr window, Rect *inval_rect); extern short set_invalid_region (WindowPtr window, Rect *inval_rect); /* * Now in macsnd.c, which seemed like a good place */ extern void tty_nhbell (); #if EXTENDED_SUPPORT /* * Various versions of delete character/s, insert line/s etc can be handled by * this general-purpose function. Negative num_ means delete, positive means * insert, and you can never be sure which of row and col operations come first * if you specify both... */ extern short mangle_tty_rows_columns ( WindowPtr window , short from_row , short num_rows , short from_col , short num_cols ) ; /* * For framing an area without using grahpics characters. * Note that the given limits are those used for framing, you should not * draw in them. frame_fatness should typically be 1-5, and may be clipped * if it is too large. */ extern short frame_tty_window ( WindowPtr window , short from_row , short from_col , short to_row , short to_col , short frame_fatness ) ; /* * For inverting specific characters after the fact. May look funny in color. */ extern short invert_tty_window ( WindowPtr window , short from_row , short from_col , short to_row , short to_col ) ; /* * For drawing lines on the tty - VERY DEVICE DEPENDENT. Use get_tty_metrics. */ extern short draw_tty_line ( WindowPtr window , short from_x , short from_y , short to_x , short to_y ) ; #endif /* EXTENDED_SUPPORT */ #endif /* _H_tty_public */ nethack-3.4.3/include/macwin.h0100644000000000000000000001444607764735041014735 0ustar rootroot/* SCCS Id: @(#)macwin.h 3.4 1996/01/15 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MACWIN_H # define MACWIN_H #undef red /* undef internal color const strings from decl */ #undef green #undef blue #ifndef __MACH__ #include #include #endif /* more headers */ #ifdef THINK_C #include /* for CtoPStr and PtoCStr */ #endif /* resources */ #define PLAYER_NAME_RES_ID 1001 /* fake some things if we don't have universal headers.. */ #if 0 /*ndef NewUserItemProc*/ typedef pascal void (*UserItemProcPtr)(WindowPtr theWindow, short itemNo); typedef UserItemProcPtr UserItemUPP; #define NewUserItemProc(p) (UserItemUPP)(p) typedef pascal void (*ControlActionProcPtr)(ControlHandle theControl, short partCode); typedef ControlActionProcPtr ControlActionUPP; #define NewControlActionProc(p) (ControlActionUPP)(p) typedef ModalFilterProcPtr ModalFilterUPP; #define DisposeRoutineDescriptor(p) #endif /* misc */ #ifdef __MWERKS__ # define ResumeProcPtr long /* for call to InitDialogs */ #endif /* working dirs structure */ typedef struct macdirs { Str32 dataName; short dataRefNum; long dataDirID; Str32 saveName; short saveRefNum; long saveDirID; Str32 levelName; short levelRefNum; long levelDirID; } MacDirs; typedef struct macflags { Bitfield (processes, 1); Bitfield (color, 1); Bitfield (folders, 1); Bitfield (tempMem, 1); Bitfield (help, 1); Bitfield (fsSpec, 1); Bitfield (trueType, 1); Bitfield (aux, 1); Bitfield (alias, 1); Bitfield (standardFile, 1); Bitfield (hasDebugger, 1); Bitfield (hasAE, 1); Bitfield (gotOpen, 1); } MacFlags; extern MacDirs theDirs; /* used in macfile.c */ extern MacFlags macFlags; /* * Mac windows */ #define NUM_MACWINDOWS 15 #define TEXT_BLOCK 512L /* Window constants */ #define kMapWindow 0 #define kStatusWindow 1 #define kMessageWindow 2 #define kTextWindow 3 #define kMenuWindow 4 #define kLastWindowKind kMenuWindow /* * This determines the minimum logical line length in text windows * That is; even if physical width is less, this is where line breaks * go at the minimum. 350 is about right for score lines with a * geneva 10 pt font. */ #define MIN_RIGHT 350 typedef struct { anything id; char accelerator; char groupAcc; short line; } MacMHMenuItem; typedef struct NhWindow { WindowPtr its_window; short font_number; short font_size; short char_width; short row_height; short ascent_height; short x_size; short y_size; short x_curs; short y_curs; short last_more_lin; /* Used by message window */ short save_lin; /* Used by message window */ short miSize; /* size of menu items arrays */ short miLen; /* number of menu items in array */ MacMHMenuItem **menuInfo; /* Used by menus (array handle) */ char menuChar; /* next menu accelerator to use */ short **menuSelected; /* list of selected elements from list */ short miSelLen; /* number of items selected */ short how; /* menu mode */ char drawn; Handle windowText; long windowTextLen; short scrollPos; ControlHandle scrollBar; } NhWindow; extern Boolean CheckNhWin(WindowPtr mac_win); #define NUM_STAT_ROWS 2 #define NUM_ROWS 22 #define NUM_COLS 80 /* We shouldn't use column 0 */ #define QUEUE_LEN 24 extern NhWindow * theWindows; extern struct window_procs mac_procs; #define NHW_BASE 0 extern winid BASE_WINDOW, WIN_MAP, WIN_MESSAGE, WIN_INVEN, WIN_STATUS; /* * External declarations for the window routines. */ #define E extern /* ### dprintf.c ### */ extern void dprintf (char *, ...); /* ### maccurs.c ### */ extern Boolean RetrievePosition (short, short *, short *); extern Boolean RetrieveSize (short, short, short, short *, short *); extern void SaveWindowPos (WindowPtr); extern void SaveWindowSize (WindowPtr); extern Boolean FDECL(RetrieveWinPos, (WindowPtr,short *,short *)); /* ### macerrs.c ### */ extern void showerror(char *,const char *); extern Boolean itworked(short); extern void mustwork(short); extern void attemptingto(char *); /* appear to be unused extern void comment(char *,long); extern void pushattemptingto(char *); extern void popattempt(void); */ /* ### macfile.c ### */ /* extern char *macgets(int fd, char *ptr, unsigned len); unused */ extern void FDECL(C2P,(const char *c, unsigned char *p)); extern void FDECL(P2C,(const unsigned char *p, char *c)); /* ### macmenu.c ### */ extern void DoMenuEvt (long); extern void InitMenuRes(void); extern void AdjustMenus(short); #define DimMenuBar() AdjustMenus(1) #define UndimMenuBar() AdjustMenus(0) /* ### macmain.c ### */ extern void FDECL (process_openfile, (short s_vol, long s_dir, Str255 fNm, OSType ft)); /* ### macwin.c ### */ extern void AddToKeyQueue(unsigned char, Boolean); extern unsigned char GetFromKeyQueue (void); void trans_num_keys (EventRecord *); extern void NDECL (InitMac); int FDECL (try_key_queue, (char *)); void FDECL (enter_topl_mode, (char *)); void FDECL (leave_topl_mode, (char *)); void FDECL (topl_set_resp, (char *, char)); Boolean FDECL (topl_key, (unsigned char, Boolean)); E void FDECL(HandleEvent, (EventRecord *)); /* used in mmodal.c */ extern void NDECL(port_help); extern Boolean small_screen; E void FDECL(mac_init_nhwindows, (int *, char **)); E void NDECL(mac_askname); E void NDECL(mac_get_nh_event); E void FDECL(mac_exit_nhwindows, (const char *)); E winid FDECL(mac_create_nhwindow, (int)); E void FDECL(mac_clear_nhwindow, (winid)); E void FDECL(mac_display_nhwindow, (winid, BOOLEAN_P)); E void FDECL(mac_destroy_nhwindow, (winid)); E void FDECL(mac_curs, (winid,int,int)); E void FDECL(mac_putstr, (winid, int, const char *)); E void FDECL(mac_start_menu, (winid)); E void FDECL(mac_add_menu, (winid,int,const anything *, CHAR_P,CHAR_P,int,const char *, BOOLEAN_P)); E void FDECL(mac_end_menu, (winid, const char *)); E int FDECL(mac_select_menu, (winid, int, menu_item **)); #ifdef CLIPPING E void FDECL(mac_cliparound, (int, int)); #endif E int NDECL(mac_nhgetch); E int FDECL(mac_nh_poskey, (int *, int *, int *)); E int NDECL(mac_doprev_message); E char FDECL(mac_yn_function, (const char *, const char *, CHAR_P)); E void FDECL(mac_getlin, (const char *,char *)); E int NDECL(mac_get_ext_cmd); E void FDECL(mac_number_pad, (int)); E void NDECL(mac_delay_output); #undef E #endif /* ! MACWIN_H */ nethack-3.4.3/include/mail.h0100644000000000000000000000125107764735041014367 0ustar rootroot/* SCCS Id: @(#)mail.h 3.4 1991/10/11 */ /* NetHack may be freely redistributed. See license for details. */ /* used by ckmailstatus() to pass information to the mail-daemon in newmail() */ #ifndef MAIL_H #define MAIL_H #define MSG_OTHER 0 /* catch-all; none of the below... */ #define MSG_MAIL 1 /* unimportant, uninteresting mail message */ #define MSG_CALL 2 /* annoying phone/talk/chat-type interruption */ struct mail_info { int message_typ; /* MSG_foo value */ const char *display_txt; /* text for daemon to verbalize */ const char *object_nam; /* text to tag object with */ const char *response_cmd; /* command to eventually execute */ }; #endif /* MAIL_H */ nethack-3.4.3/include/mfndpos.h0100644000000000000000000000226007764735041015114 0ustar rootroot/* SCCS Id: @(#)mfndpos.h 3.4 2002/04/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MFNDPOS_H #define MFNDPOS_H #define ALLOW_TRAPS 0x00020000L /* can enter traps */ #define ALLOW_U 0x00040000L /* can attack you */ #define ALLOW_M 0x00080000L /* can attack other monsters */ #define ALLOW_TM 0x00100000L /* can attack tame monsters */ #define ALLOW_ALL (ALLOW_U | ALLOW_M | ALLOW_TM | ALLOW_TRAPS) #define NOTONL 0x00200000L /* avoids direct line to player */ #define OPENDOOR 0x00400000L /* opens closed doors */ #define UNLOCKDOOR 0x00800000L /* unlocks locked doors */ #define BUSTDOOR 0x01000000L /* breaks any doors */ #define ALLOW_ROCK 0x02000000L /* pushes rocks */ #define ALLOW_WALL 0x04000000L /* walks thru walls */ #define ALLOW_DIG 0x08000000L /* digs */ #define ALLOW_BARS 0x10000000L /* may pass thru iron bars */ #define ALLOW_SANCT 0x20000000L /* enters temples */ #define ALLOW_SSM 0x40000000L /* ignores scare monster */ #ifdef NHSTDC #define NOGARLIC 0x80000000UL /* hates garlic */ #else #define NOGARLIC 0x80000000L /* hates garlic */ #endif #endif /* MFNDPOS_H */ nethack-3.4.3/include/micro.h0100644000000000000000000000072107764735041014557 0ustar rootroot/* SCCS Id: @(#)micro.h 3.4 1990/02/22 */ /* micro.h - function declarations for various microcomputers */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MICRO_H #define MICRO_H extern const char *alllevels, *allbones; extern char levels[], bones[], permbones[], hackdir[]; extern int ramdisk; #ifndef C #define C(c) (0x1f & (c)) #endif #ifndef M #define M(c) (((char)0x80) | (c)) #endif #define ABORT C('a') #endif /* MICRO_H */ nethack-3.4.3/include/mkroom.h0100644000000000000000000000756207764735041014764 0ustar rootroot/* SCCS Id: @(#)mkroom.h 3.4 1992/11/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MKROOM_H #define MKROOM_H /* mkroom.h - types and structures for room and shop initialization */ struct mkroom { schar lx,hx,ly,hy; /* usually xchar, but hx may be -1 */ schar rtype; /* type of room (zoo, throne, etc...) */ schar rlit; /* is the room lit ? */ schar doorct; /* door count */ schar fdoor; /* index for the first door of the room */ schar nsubrooms; /* number of subrooms */ boolean irregular; /* true if room is non-rectangular */ struct mkroom *sbrooms[MAX_SUBROOMS]; /* Subrooms pointers */ struct monst *resident; /* priest/shopkeeper/guard for this room */ }; struct shclass { const char *name; /* name of the shop type */ char symb; /* this identifies the shop type */ int prob; /* the shop type probability in % */ schar shdist; /* object placement type */ #define D_SCATTER 0 /* normal placement */ #define D_SHOP 1 /* shop-like placement */ #define D_TEMPLE 2 /* temple-like placement */ struct itp { int iprob; /* probability of an item type */ int itype; /* item type: if >=0 a class, if < 0 a specific item */ } iprobs[5]; const char * const *shknms; /* list of shopkeeper names for this type */ }; extern NEARDATA struct mkroom rooms[(MAXNROFROOMS+1)*2]; extern NEARDATA struct mkroom* subrooms; /* the normal rooms on the current level are described in rooms[0..n] for * some n= rooms && (x) < rooms + MAXNROFROOMS) #define IS_ROOM_INDEX(x) ((x) >= 0 && (x) < MAXNROFROOMS) #define IS_SUBROOM_PTR(x) ((x) >= subrooms && \ (x) < subrooms + MAXNROFROOMS) #define IS_SUBROOM_INDEX(x) ((x) > MAXNROFROOMS && (x) < (MAXNROFROOMS*2)) #define ROOM_INDEX(x) ((x) - rooms) #define SUBROOM_INDEX(x) ((x) - subrooms) #define IS_LAST_ROOM_PTR(x) (ROOM_INDEX(x) == nroom) #define IS_LAST_SUBROOM_PTR(x) (!nsubroom || SUBROOM_INDEX(x) == nsubroom) #endif /* MKROOM_H */ nethack-3.4.3/include/monattk.h0100644000000000000000000000775707764735041015143 0ustar rootroot/* SCCS Id: @(#)monattk.h 3.4 2002/03/24 */ /* NetHack may be freely redistributed. See license for details. */ /* Copyright 1988, M. Stephenson */ #ifndef MONATTK_H #define MONATTK_H /* Add new attack types below - ordering affects experience (exper.c). * Attacks > AT_BUTT are worth extra experience. */ #define AT_ANY (-1) /* fake attack; dmgtype_fromattack wildcard */ #define AT_NONE 0 /* passive monster (ex. acid blob) */ #define AT_CLAW 1 /* claw (punch, hit, etc.) */ #define AT_BITE 2 /* bite */ #define AT_KICK 3 /* kick */ #define AT_BUTT 4 /* head butt (ex. a unicorn) */ #define AT_TUCH 5 /* touches */ #define AT_STNG 6 /* sting */ #define AT_HUGS 7 /* crushing bearhug */ #define AT_SPIT 10 /* spits substance - ranged */ #define AT_ENGL 11 /* engulf (swallow or by a cloud) */ #define AT_BREA 12 /* breath - ranged */ #define AT_EXPL 13 /* explodes - proximity */ #define AT_BOOM 14 /* explodes when killed */ #define AT_GAZE 15 /* gaze - ranged */ #define AT_TENT 16 /* tentacles */ #define AT_WEAP 254 /* uses weapon */ #define AT_MAGC 255 /* uses magic spell(s) */ /* Add new damage types below. * * Note that 1-10 correspond to the types of attack used in buzz(). * Please don't disturb the order unless you rewrite the buzz() code. */ #define AD_ANY (-1) /* fake damage; attacktype_fordmg wildcard */ #define AD_PHYS 0 /* ordinary physical */ #define AD_MAGM 1 /* magic missiles */ #define AD_FIRE 2 /* fire damage */ #define AD_COLD 3 /* frost damage */ #define AD_SLEE 4 /* sleep ray */ #define AD_DISN 5 /* disintegration (death ray) */ #define AD_ELEC 6 /* shock damage */ #define AD_DRST 7 /* drains str (poison) */ #define AD_ACID 8 /* acid damage */ #define AD_SPC1 9 /* for extension of buzz() */ #define AD_SPC2 10 /* for extension of buzz() */ #define AD_BLND 11 /* blinds (yellow light) */ #define AD_STUN 12 /* stuns */ #define AD_SLOW 13 /* slows */ #define AD_PLYS 14 /* paralyses */ #define AD_DRLI 15 /* drains life levels (Vampire) */ #define AD_DREN 16 /* drains magic energy */ #define AD_LEGS 17 /* damages legs (xan) */ #define AD_STON 18 /* petrifies (Medusa, cockatrice) */ #define AD_STCK 19 /* sticks to you (mimic) */ #define AD_SGLD 20 /* steals gold (leppie) */ #define AD_SITM 21 /* steals item (nymphs) */ #define AD_SEDU 22 /* seduces & steals multiple items */ #define AD_TLPT 23 /* teleports you (Quantum Mech.) */ #define AD_RUST 24 /* rusts armour (Rust Monster)*/ #define AD_CONF 25 /* confuses (Umber Hulk) */ #define AD_DGST 26 /* digests opponent (trapper, etc.) */ #define AD_HEAL 27 /* heals opponent's wounds (nurse) */ #define AD_WRAP 28 /* special "stick" for eels */ #define AD_WERE 29 /* confers lycanthropy */ #define AD_DRDX 30 /* drains dexterity (quasit) */ #define AD_DRCO 31 /* drains constitution */ #define AD_DRIN 32 /* drains intelligence (mind flayer) */ #define AD_DISE 33 /* confers diseases */ #define AD_DCAY 34 /* decays organics (brown Pudding) */ #define AD_SSEX 35 /* Succubus seduction (extended) */ /* If no SEDUCE then same as AD_SEDU */ #define AD_HALU 36 /* causes hallucination */ #define AD_DETH 37 /* for Death only */ #define AD_PEST 38 /* for Pestilence only */ #define AD_FAMN 39 /* for Famine only */ #define AD_SLIM 40 /* turns you into green slime */ #define AD_ENCH 41 /* remove enchantment (disenchanter) */ #define AD_CORR 42 /* corrode armor (black pudding) */ #define AD_CLRC 240 /* random clerical spell */ #define AD_SPEL 241 /* random magic spell */ #define AD_RBRE 242 /* random breath weapon */ #define AD_SAMU 252 /* hits, may steal Amulet (Wizard) */ #define AD_CURS 253 /* random curse (ex. gremlin) */ /* * Monster to monster attacks. When a monster attacks another (mattackm), * any or all of the following can be returned. See mattackm() for more * details. */ #define MM_MISS 0x0 /* aggressor missed */ #define MM_HIT 0x1 /* aggressor hit defender */ #define MM_DEF_DIED 0x2 /* defender died */ #define MM_AGR_DIED 0x4 /* aggressor died */ #endif /* MONATTK_H */ nethack-3.4.3/include/mondata.h0100644000000000000000000002264707764735041015104 0ustar rootroot/* SCCS Id: @(#)mondata.h 3.4 2003/01/08 */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MONDATA_H #define MONDATA_H #define verysmall(ptr) ((ptr)->msize < MZ_SMALL) #define bigmonst(ptr) ((ptr)->msize >= MZ_LARGE) #define pm_resistance(ptr,typ) (((ptr)->mresists & (typ)) != 0) #define resists_fire(mon) (((mon)->mintrinsics & MR_FIRE) != 0) #define resists_cold(mon) (((mon)->mintrinsics & MR_COLD) != 0) #define resists_sleep(mon) (((mon)->mintrinsics & MR_SLEEP) != 0) #define resists_disint(mon) (((mon)->mintrinsics & MR_DISINT) != 0) #define resists_elec(mon) (((mon)->mintrinsics & MR_ELEC) != 0) #define resists_poison(mon) (((mon)->mintrinsics & MR_POISON) != 0) #define resists_acid(mon) (((mon)->mintrinsics & MR_ACID) != 0) #define resists_ston(mon) (((mon)->mintrinsics & MR_STONE) != 0) #define is_lminion(mon) (is_minion((mon)->data) && \ (mon)->data->maligntyp >= A_COALIGNED && \ ((mon)->data != &mons[PM_ANGEL] || \ EPRI(mon)->shralign > 0)) #define is_flyer(ptr) (((ptr)->mflags1 & M1_FLY) != 0L) #define is_floater(ptr) ((ptr)->mlet == S_EYE) #define is_clinger(ptr) (((ptr)->mflags1 & M1_CLING) != 0L) #define is_swimmer(ptr) (((ptr)->mflags1 & M1_SWIM) != 0L) #define breathless(ptr) (((ptr)->mflags1 & M1_BREATHLESS) != 0L) #define amphibious(ptr) (((ptr)->mflags1 & (M1_AMPHIBIOUS | M1_BREATHLESS)) != 0L) #define passes_walls(ptr) (((ptr)->mflags1 & M1_WALLWALK) != 0L) #define amorphous(ptr) (((ptr)->mflags1 & M1_AMORPHOUS) != 0L) #define noncorporeal(ptr) ((ptr)->mlet == S_GHOST) #define tunnels(ptr) (((ptr)->mflags1 & M1_TUNNEL) != 0L) #define needspick(ptr) (((ptr)->mflags1 & M1_NEEDPICK) != 0L) #define hides_under(ptr) (((ptr)->mflags1 & M1_CONCEAL) != 0L) #define is_hider(ptr) (((ptr)->mflags1 & M1_HIDE) != 0L) #define haseyes(ptr) (((ptr)->mflags1 & M1_NOEYES) == 0L) #define eyecount(ptr) (!haseyes(ptr) ? 0 : \ ((ptr) == &mons[PM_CYCLOPS] || \ (ptr) == &mons[PM_FLOATING_EYE]) ? 1 : 2) #define nohands(ptr) (((ptr)->mflags1 & M1_NOHANDS) != 0L) #define nolimbs(ptr) (((ptr)->mflags1 & M1_NOLIMBS) == M1_NOLIMBS) #define notake(ptr) (((ptr)->mflags1 & M1_NOTAKE) != 0L) #define has_head(ptr) (((ptr)->mflags1 & M1_NOHEAD) == 0L) #define has_horns(ptr) (num_horns(ptr) > 0) #define is_whirly(ptr) ((ptr)->mlet == S_VORTEX || \ (ptr) == &mons[PM_AIR_ELEMENTAL]) #define flaming(ptr) ((ptr) == &mons[PM_FIRE_VORTEX] || \ (ptr) == &mons[PM_FLAMING_SPHERE] || \ (ptr) == &mons[PM_FIRE_ELEMENTAL] || \ (ptr) == &mons[PM_SALAMANDER]) #define is_silent(ptr) ((ptr)->msound == MS_SILENT) #define unsolid(ptr) (((ptr)->mflags1 & M1_UNSOLID) != 0L) #define mindless(ptr) (((ptr)->mflags1 & M1_MINDLESS) != 0L) #define humanoid(ptr) (((ptr)->mflags1 & M1_HUMANOID) != 0L) #define is_animal(ptr) (((ptr)->mflags1 & M1_ANIMAL) != 0L) #define slithy(ptr) (((ptr)->mflags1 & M1_SLITHY) != 0L) #define is_wooden(ptr) ((ptr) == &mons[PM_WOOD_GOLEM]) #define thick_skinned(ptr) (((ptr)->mflags1 & M1_THICK_HIDE) != 0L) #define lays_eggs(ptr) (((ptr)->mflags1 & M1_OVIPAROUS) != 0L) #define regenerates(ptr) (((ptr)->mflags1 & M1_REGEN) != 0L) #define perceives(ptr) (((ptr)->mflags1 & M1_SEE_INVIS) != 0L) #define can_teleport(ptr) (((ptr)->mflags1 & M1_TPORT) != 0L) #define control_teleport(ptr) (((ptr)->mflags1 & M1_TPORT_CNTRL) != 0L) #define telepathic(ptr) ((ptr) == &mons[PM_FLOATING_EYE] || \ (ptr) == &mons[PM_MIND_FLAYER] || \ (ptr) == &mons[PM_MASTER_MIND_FLAYER]) #define is_armed(ptr) attacktype(ptr, AT_WEAP) #define acidic(ptr) (((ptr)->mflags1 & M1_ACID) != 0L) #define poisonous(ptr) (((ptr)->mflags1 & M1_POIS) != 0L) #define carnivorous(ptr) (((ptr)->mflags1 & M1_CARNIVORE) != 0L) #define herbivorous(ptr) (((ptr)->mflags1 & M1_HERBIVORE) != 0L) #define metallivorous(ptr) (((ptr)->mflags1 & M1_METALLIVORE) != 0L) #define polyok(ptr) (((ptr)->mflags2 & M2_NOPOLY) == 0L) #define is_undead(ptr) (((ptr)->mflags2 & M2_UNDEAD) != 0L) #define is_were(ptr) (((ptr)->mflags2 & M2_WERE) != 0L) #define is_elf(ptr) (((ptr)->mflags2 & M2_ELF) != 0L) #define is_dwarf(ptr) (((ptr)->mflags2 & M2_DWARF) != 0L) #define is_gnome(ptr) (((ptr)->mflags2 & M2_GNOME) != 0L) #define is_orc(ptr) (((ptr)->mflags2 & M2_ORC) != 0L) #define is_human(ptr) (((ptr)->mflags2 & M2_HUMAN) != 0L) #define your_race(ptr) (((ptr)->mflags2 & urace.selfmask) != 0L) #define is_bat(ptr) ((ptr) == &mons[PM_BAT] || \ (ptr) == &mons[PM_GIANT_BAT] || \ (ptr) == &mons[PM_VAMPIRE_BAT]) #define is_bird(ptr) ((ptr)->mlet == S_BAT && !is_bat(ptr)) #define is_giant(ptr) (((ptr)->mflags2 & M2_GIANT) != 0L) #define is_golem(ptr) ((ptr)->mlet == S_GOLEM) #define is_domestic(ptr) (((ptr)->mflags2 & M2_DOMESTIC) != 0L) #define is_demon(ptr) (((ptr)->mflags2 & M2_DEMON) != 0L) #define is_mercenary(ptr) (((ptr)->mflags2 & M2_MERC) != 0L) #define is_male(ptr) (((ptr)->mflags2 & M2_MALE) != 0L) #define is_female(ptr) (((ptr)->mflags2 & M2_FEMALE) != 0L) #define is_neuter(ptr) (((ptr)->mflags2 & M2_NEUTER) != 0L) #define is_wanderer(ptr) (((ptr)->mflags2 & M2_WANDER) != 0L) #define always_hostile(ptr) (((ptr)->mflags2 & M2_HOSTILE) != 0L) #define always_peaceful(ptr) (((ptr)->mflags2 & M2_PEACEFUL) != 0L) #define race_hostile(ptr) (((ptr)->mflags2 & urace.hatemask) != 0L) #define race_peaceful(ptr) (((ptr)->mflags2 & urace.lovemask) != 0L) #define extra_nasty(ptr) (((ptr)->mflags2 & M2_NASTY) != 0L) #define strongmonst(ptr) (((ptr)->mflags2 & M2_STRONG) != 0L) #define can_breathe(ptr) attacktype(ptr, AT_BREA) #define cantwield(ptr) (nohands(ptr) || verysmall(ptr)) #define could_twoweap(ptr) ((ptr)->mattk[1].aatyp == AT_WEAP) #define cantweararm(ptr) (breakarm(ptr) || sliparm(ptr)) #define throws_rocks(ptr) (((ptr)->mflags2 & M2_ROCKTHROW) != 0L) #define type_is_pname(ptr) (((ptr)->mflags2 & M2_PNAME) != 0L) #define is_lord(ptr) (((ptr)->mflags2 & M2_LORD) != 0L) #define is_prince(ptr) (((ptr)->mflags2 & M2_PRINCE) != 0L) #define is_ndemon(ptr) (is_demon(ptr) && \ (((ptr)->mflags2 & (M2_LORD|M2_PRINCE)) == 0L)) #define is_dlord(ptr) (is_demon(ptr) && is_lord(ptr)) #define is_dprince(ptr) (is_demon(ptr) && is_prince(ptr)) #define is_minion(ptr) ((ptr)->mflags2 & M2_MINION) #define likes_gold(ptr) (((ptr)->mflags2 & M2_GREEDY) != 0L) #define likes_gems(ptr) (((ptr)->mflags2 & M2_JEWELS) != 0L) #define likes_objs(ptr) (((ptr)->mflags2 & M2_COLLECT) != 0L || \ is_armed(ptr)) #define likes_magic(ptr) (((ptr)->mflags2 & M2_MAGIC) != 0L) #define webmaker(ptr) ((ptr) == &mons[PM_CAVE_SPIDER] || \ (ptr) == &mons[PM_GIANT_SPIDER]) #define is_unicorn(ptr) ((ptr)->mlet == S_UNICORN && likes_gems(ptr)) #define is_longworm(ptr) (((ptr) == &mons[PM_BABY_LONG_WORM]) || \ ((ptr) == &mons[PM_LONG_WORM]) || \ ((ptr) == &mons[PM_LONG_WORM_TAIL])) #define is_covetous(ptr) ((ptr->mflags3 & M3_COVETOUS)) #define infravision(ptr) ((ptr->mflags3 & M3_INFRAVISION)) #define infravisible(ptr) ((ptr->mflags3 & M3_INFRAVISIBLE)) #define is_mplayer(ptr) (((ptr) >= &mons[PM_ARCHEOLOGIST]) && \ ((ptr) <= &mons[PM_WIZARD])) #define is_rider(ptr) ((ptr) == &mons[PM_DEATH] || \ (ptr) == &mons[PM_FAMINE] || \ (ptr) == &mons[PM_PESTILENCE]) #define is_placeholder(ptr) ((ptr) == &mons[PM_ORC] || \ (ptr) == &mons[PM_GIANT] || \ (ptr) == &mons[PM_ELF] || \ (ptr) == &mons[PM_HUMAN]) /* return TRUE if the monster tends to revive */ #define is_reviver(ptr) (is_rider(ptr) || (ptr)->mlet == S_TROLL) /* this returns the light's range, or 0 if none; if we add more light emitting monsters, we'll likely have to add a new light range field to mons[] */ #define emits_light(ptr) (((ptr)->mlet == S_LIGHT || \ (ptr) == &mons[PM_FLAMING_SPHERE] || \ (ptr) == &mons[PM_SHOCKING_SPHERE] || \ (ptr) == &mons[PM_FIRE_VORTEX]) ? 1 : \ ((ptr) == &mons[PM_FIRE_ELEMENTAL]) ? 1 : 0) /* [note: the light ranges above were reduced to 1 for performance...] */ #define likes_lava(ptr) (ptr == &mons[PM_FIRE_ELEMENTAL] || \ ptr == &mons[PM_SALAMANDER]) #define pm_invisible(ptr) ((ptr) == &mons[PM_STALKER] || \ (ptr) == &mons[PM_BLACK_LIGHT]) /* could probably add more */ #define likes_fire(ptr) ((ptr) == &mons[PM_FIRE_VORTEX] || \ (ptr) == &mons[PM_FLAMING_SPHERE] || \ likes_lava(ptr)) #define touch_petrifies(ptr) ((ptr) == &mons[PM_COCKATRICE] || \ (ptr) == &mons[PM_CHICKATRICE]) #define is_mind_flayer(ptr) ((ptr) == &mons[PM_MIND_FLAYER] || \ (ptr) == &mons[PM_MASTER_MIND_FLAYER]) #define nonliving(ptr) (is_golem(ptr) || is_undead(ptr) || \ (ptr)->mlet == S_VORTEX || \ (ptr) == &mons[PM_MANES]) /* Used for conduct with corpses, tins, and digestion attacks */ /* G_NOCORPSE monsters might still be swallowed as a purple worm */ /* Maybe someday this could be in mflags... */ #define vegan(ptr) ((ptr)->mlet == S_BLOB || \ (ptr)->mlet == S_JELLY || \ (ptr)->mlet == S_FUNGUS || \ (ptr)->mlet == S_VORTEX || \ (ptr)->mlet == S_LIGHT || \ ((ptr)->mlet == S_ELEMENTAL && \ (ptr) != &mons[PM_STALKER]) || \ ((ptr)->mlet == S_GOLEM && \ (ptr) != &mons[PM_FLESH_GOLEM] && \ (ptr) != &mons[PM_LEATHER_GOLEM]) || \ noncorporeal(ptr)) #define vegetarian(ptr) (vegan(ptr) || \ ((ptr)->mlet == S_PUDDING && \ (ptr) != &mons[PM_BLACK_PUDDING])) #define befriend_with_obj(ptr, obj) ((obj)->oclass == FOOD_CLASS && \ is_domestic(ptr)) #endif /* MONDATA_H */ nethack-3.4.3/include/monflag.h0100644000000000000000000002154407764735041015077 0ustar rootroot/* SCCS Id: @(#)monflag.h 3.4 1996/05/04 */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MONFLAG_H #define MONFLAG_H #define MS_SILENT 0 /* makes no sound */ #define MS_BARK 1 /* if full moon, may howl */ #define MS_MEW 2 /* mews or hisses */ #define MS_ROAR 3 /* roars */ #define MS_GROWL 4 /* growls */ #define MS_SQEEK 5 /* squeaks, as a rodent */ #define MS_SQAWK 6 /* squawks, as a bird */ #define MS_HISS 7 /* hisses */ #define MS_BUZZ 8 /* buzzes (killer bee) */ #define MS_GRUNT 9 /* grunts (or speaks own language) */ #define MS_NEIGH 10 /* neighs, as an equine */ #define MS_WAIL 11 /* wails, as a tortured soul */ #define MS_GURGLE 12 /* gurgles, as liquid or through saliva */ #define MS_BURBLE 13 /* burbles (jabberwock) */ #define MS_ANIMAL 13 /* up to here are animal noises */ #define MS_SHRIEK 15 /* wakes up others */ #define MS_BONES 16 /* rattles bones (skeleton) */ #define MS_LAUGH 17 /* grins, smiles, giggles, and laughs */ #define MS_MUMBLE 18 /* says something or other */ #define MS_IMITATE 19 /* imitates others (leocrotta) */ #define MS_ORC MS_GRUNT /* intelligent brutes */ #define MS_HUMANOID 20 /* generic traveling companion */ #ifdef KOPS #define MS_ARREST 21 /* "Stop in the name of the law!" (Kops) */ #endif #define MS_SOLDIER 22 /* army and watchmen expressions */ #define MS_GUARD 23 /* "Please drop that gold and follow me." */ #define MS_DJINNI 24 /* "Thank you for freeing me!" */ #define MS_NURSE 25 /* "Take off your shirt, please." */ #define MS_SEDUCE 26 /* "Hello, sailor." (Nymphs) */ #define MS_VAMPIRE 27 /* vampiric seduction, Vlad's exclamations */ #define MS_BRIBE 28 /* asks for money, or berates you */ #define MS_CUSS 29 /* berates (demons) or intimidates (Wiz) */ #define MS_RIDER 30 /* astral level special monsters */ #define MS_LEADER 31 /* your class leader */ #define MS_NEMESIS 32 /* your nemesis */ #define MS_GUARDIAN 33 /* your leader's guards */ #define MS_SELL 34 /* demand payment, complain about shoplifters */ #define MS_ORACLE 35 /* do a consultation */ #define MS_PRIEST 36 /* ask for contribution; do cleansing */ #define MS_SPELL 37 /* spellcaster not matching any of the above */ #define MS_WERE 38 /* lycanthrope in human form */ #define MS_BOAST 39 /* giants */ #define MR_FIRE 0x01 /* resists fire */ #define MR_COLD 0x02 /* resists cold */ #define MR_SLEEP 0x04 /* resists sleep */ #define MR_DISINT 0x08 /* resists disintegration */ #define MR_ELEC 0x10 /* resists electricity */ #define MR_POISON 0x20 /* resists poison */ #define MR_ACID 0x40 /* resists acid */ #define MR_STONE 0x80 /* resists petrification */ /* other resistances: magic, sickness */ /* other conveyances: teleport, teleport control, telepathy */ /* individual resistances */ #define MR2_SEE_INVIS 0x0100 /* see invisible */ #define MR2_LEVITATE 0x0200 /* levitation */ #define MR2_WATERWALK 0x0400 /* water walking */ #define MR2_MAGBREATH 0x0800 /* magical breathing */ #define MR2_DISPLACED 0x1000 /* displaced */ #define MR2_STRENGTH 0x2000 /* gauntlets of power */ #define MR2_FUMBLING 0x4000 /* clumsy */ #define M1_FLY 0x00000001L /* can fly or float */ #define M1_SWIM 0x00000002L /* can traverse water */ #define M1_AMORPHOUS 0x00000004L /* can flow under doors */ #define M1_WALLWALK 0x00000008L /* can phase thru rock */ #define M1_CLING 0x00000010L /* can cling to ceiling */ #define M1_TUNNEL 0x00000020L /* can tunnel thru rock */ #define M1_NEEDPICK 0x00000040L /* needs pick to tunnel */ #define M1_CONCEAL 0x00000080L /* hides under objects */ #define M1_HIDE 0x00000100L /* mimics, blends in with ceiling */ #define M1_AMPHIBIOUS 0x00000200L /* can survive underwater */ #define M1_BREATHLESS 0x00000400L /* doesn't need to breathe */ #define M1_NOTAKE 0x00000800L /* cannot pick up objects */ #define M1_NOEYES 0x00001000L /* no eyes to gaze into or blind */ #define M1_NOHANDS 0x00002000L /* no hands to handle things */ #define M1_NOLIMBS 0x00006000L /* no arms/legs to kick/wear on */ #define M1_NOHEAD 0x00008000L /* no head to behead */ #define M1_MINDLESS 0x00010000L /* has no mind--golem, zombie, mold */ #define M1_HUMANOID 0x00020000L /* has humanoid head/arms/torso */ #define M1_ANIMAL 0x00040000L /* has animal body */ #define M1_SLITHY 0x00080000L /* has serpent body */ #define M1_UNSOLID 0x00100000L /* has no solid or liquid body */ #define M1_THICK_HIDE 0x00200000L /* has thick hide or scales */ #define M1_OVIPAROUS 0x00400000L /* can lay eggs */ #define M1_REGEN 0x00800000L /* regenerates hit points */ #define M1_SEE_INVIS 0x01000000L /* can see invisible creatures */ #define M1_TPORT 0x02000000L /* can teleport */ #define M1_TPORT_CNTRL 0x04000000L /* controls where it teleports to */ #define M1_ACID 0x08000000L /* acidic to eat */ #define M1_POIS 0x10000000L /* poisonous to eat */ #define M1_CARNIVORE 0x20000000L /* eats corpses */ #define M1_HERBIVORE 0x40000000L /* eats fruits */ #define M1_OMNIVORE 0x60000000L /* eats both */ #ifdef NHSTDC #define M1_METALLIVORE 0x80000000UL /* eats metal */ #else #define M1_METALLIVORE 0x80000000L /* eats metal */ #endif #define M2_NOPOLY 0x00000001L /* players mayn't poly into one */ #define M2_UNDEAD 0x00000002L /* is walking dead */ #define M2_WERE 0x00000004L /* is a lycanthrope */ #define M2_HUMAN 0x00000008L /* is a human */ #define M2_ELF 0x00000010L /* is an elf */ #define M2_DWARF 0x00000020L /* is a dwarf */ #define M2_GNOME 0x00000040L /* is a gnome */ #define M2_ORC 0x00000080L /* is an orc */ #define M2_DEMON 0x00000100L /* is a demon */ #define M2_MERC 0x00000200L /* is a guard or soldier */ #define M2_LORD 0x00000400L /* is a lord to its kind */ #define M2_PRINCE 0x00000800L /* is an overlord to its kind */ #define M2_MINION 0x00001000L /* is a minion of a deity */ #define M2_GIANT 0x00002000L /* is a giant */ #define M2_MALE 0x00010000L /* always male */ #define M2_FEMALE 0x00020000L /* always female */ #define M2_NEUTER 0x00040000L /* neither male nor female */ #define M2_PNAME 0x00080000L /* monster name is a proper name */ #define M2_HOSTILE 0x00100000L /* always starts hostile */ #define M2_PEACEFUL 0x00200000L /* always starts peaceful */ #define M2_DOMESTIC 0x00400000L /* can be tamed by feeding */ #define M2_WANDER 0x00800000L /* wanders randomly */ #define M2_STALK 0x01000000L /* follows you to other levels */ #define M2_NASTY 0x02000000L /* extra-nasty monster (more xp) */ #define M2_STRONG 0x04000000L /* strong (or big) monster */ #define M2_ROCKTHROW 0x08000000L /* throws boulders */ #define M2_GREEDY 0x10000000L /* likes gold */ #define M2_JEWELS 0x20000000L /* likes gems */ #define M2_COLLECT 0x40000000L /* picks up weapons and food */ #ifdef NHSTDC #define M2_MAGIC 0x80000000UL /* picks up magic items */ #else #define M2_MAGIC 0x80000000L /* picks up magic items */ #endif #define M3_WANTSAMUL 0x0001 /* would like to steal the amulet */ #define M3_WANTSBELL 0x0002 /* wants the bell */ #define M3_WANTSBOOK 0x0004 /* wants the book */ #define M3_WANTSCAND 0x0008 /* wants the candelabrum */ #define M3_WANTSARTI 0x0010 /* wants the quest artifact */ #define M3_WANTSALL 0x001f /* wants any major artifact */ #define M3_WAITFORU 0x0040 /* waits to see you or get attacked */ #define M3_CLOSE 0x0080 /* lets you close unless attacked */ #define M3_COVETOUS 0x001f /* wants something */ #define M3_WAITMASK 0x00c0 /* waiting... */ /* Infravision is currently implemented for players only */ #define M3_INFRAVISION 0x0100 /* has infravision */ #define M3_INFRAVISIBLE 0x0200 /* visible by infravision */ #define MZ_TINY 0 /* < 2' */ #define MZ_SMALL 1 /* 2-4' */ #define MZ_MEDIUM 2 /* 4-7' */ #define MZ_HUMAN MZ_MEDIUM /* human-sized */ #define MZ_LARGE 3 /* 7-12' */ #define MZ_HUGE 4 /* 12-25' */ #define MZ_GIGANTIC 7 /* off the scale */ /* Monster races -- must stay within ROLE_RACEMASK */ /* Eventually this may become its own field */ #define MH_HUMAN M2_HUMAN #define MH_ELF M2_ELF #define MH_DWARF M2_DWARF #define MH_GNOME M2_GNOME #define MH_ORC M2_ORC /* for mons[].geno (constant during game) */ #define G_UNIQ 0x1000 /* generated only once */ #define G_NOHELL 0x0800 /* not generated in "hell" */ #define G_HELL 0x0400 /* generated only in "hell" */ #define G_NOGEN 0x0200 /* generated only specially */ #define G_SGROUP 0x0080 /* appear in small groups normally */ #define G_LGROUP 0x0040 /* appear in large groups normally */ #define G_GENO 0x0020 /* can be genocided */ #define G_NOCORPSE 0x0010 /* no corpse left ever */ #define G_FREQ 0x0007 /* creation frequency mask */ /* for mvitals[].mvflags (variant during game), along with G_NOCORPSE */ #define G_KNOWN 0x0004 /* have been encountered */ #define G_GONE (G_GENOD|G_EXTINCT) #define G_GENOD 0x0002 /* have been genocided */ #define G_EXTINCT 0x0001 /* have been extinguished as population control */ #define MV_KNOWS_EGG 0x0008 /* player recognizes egg of this monster type */ #endif /* MONFLAG_H */ nethack-3.4.3/include/monst.h0100644000000000000000000001476707764735041014625 0ustar rootroot/* SCCS Id: @(#)monst.h 3.4 1999/01/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MONST_H #define MONST_H /* The weapon_check flag is used two ways: * 1) When calling mon_wield_item, is 2-6 depending on what is desired. * 2) Between calls to mon_wield_item, is 0 or 1 depending on whether or not * the weapon is known by the monster to be cursed (so it shouldn't bother * trying for another weapon). * I originally planned to also use 0 if the monster already had its best * weapon, to avoid the overhead of a call to mon_wield_item, but it turns out * that there are enough situations which might make a monster change its * weapon that this is impractical. --KAA */ # define NO_WEAPON_WANTED 0 # define NEED_WEAPON 1 # define NEED_RANGED_WEAPON 2 # define NEED_HTH_WEAPON 3 # define NEED_PICK_AXE 4 # define NEED_AXE 5 # define NEED_PICK_OR_AXE 6 /* The following flags are used for the second argument to display_minventory * in invent.c: * * MINV_NOLET If set, don't display inventory letters on monster's inventory. * MINV_ALL If set, display all items in monster's inventory, otherwise * just display wielded weapons and worn items. */ #define MINV_NOLET 0x01 #define MINV_ALL 0x02 #ifndef ALIGN_H #include "align.h" #endif struct monst { struct monst *nmon; struct permonst *data; unsigned m_id; short mnum; /* permanent monster index number */ short movement; /* movement points (derived from permonst definition and added effects */ uchar m_lev; /* adjusted difficulty level of monster */ aligntyp malign; /* alignment of this monster, relative to the player (positive = good to kill) */ xchar mx, my; xchar mux, muy; /* where the monster thinks you are */ #define MTSZ 4 coord mtrack[MTSZ]; /* monster track */ int mhp, mhpmax; unsigned mappearance; /* for undetected mimics and the wiz */ uchar m_ap_type; /* what mappearance is describing: */ #define M_AP_NOTHING 0 /* mappearance is unused -- monster appears as itself */ #define M_AP_FURNITURE 1 /* stairs, a door, an altar, etc. */ #define M_AP_OBJECT 2 /* an object */ #define M_AP_MONSTER 3 /* a monster */ schar mtame; /* level of tameness, implies peaceful */ unsigned short mintrinsics; /* low 8 correspond to mresists */ int mspec_used; /* monster's special ability attack timeout */ Bitfield(female,1); /* is female */ Bitfield(minvis,1); /* currently invisible */ Bitfield(invis_blkd,1); /* invisibility blocked */ Bitfield(perminvis,1); /* intrinsic minvis value */ Bitfield(cham,3); /* shape-changer */ /* note: lychanthropes are handled elsewhere */ #define CHAM_ORDINARY 0 /* not a shapechanger */ #define CHAM_CHAMELEON 1 /* animal */ #define CHAM_DOPPELGANGER 2 /* demi-human */ #define CHAM_SANDESTIN 3 /* demon */ #define CHAM_MAX_INDX CHAM_SANDESTIN Bitfield(mundetected,1); /* not seen in present hiding place */ /* implies one of M1_CONCEAL or M1_HIDE, * but not mimic (that is, snake, spider, * trapper, piercer, eel) */ Bitfield(mcan,1); /* has been cancelled */ Bitfield(mburied,1); /* has been buried */ Bitfield(mspeed,2); /* current speed */ Bitfield(permspeed,2); /* intrinsic mspeed value */ Bitfield(mrevived,1); /* has been revived from the dead */ Bitfield(mavenge,1); /* did something to deserve retaliation */ Bitfield(mflee,1); /* fleeing */ Bitfield(mfleetim,7); /* timeout for mflee */ Bitfield(mcansee,1); /* cansee 1, temp.blinded 0, blind 0 */ Bitfield(mblinded,7); /* cansee 0, temp.blinded n, blind 0 */ Bitfield(mcanmove,1); /* paralysis, similar to mblinded */ Bitfield(mfrozen,7); Bitfield(msleeping,1); /* asleep until woken */ Bitfield(mstun,1); /* stunned (off balance) */ Bitfield(mconf,1); /* confused */ Bitfield(mpeaceful,1); /* does not attack unprovoked */ Bitfield(mtrapped,1); /* trapped in a pit, web or bear trap */ Bitfield(mleashed,1); /* monster is on a leash */ Bitfield(isshk,1); /* is shopkeeper */ Bitfield(isminion,1); /* is a minion */ Bitfield(isgd,1); /* is guard */ Bitfield(ispriest,1); /* is a priest */ Bitfield(iswiz,1); /* is the Wizard of Yendor */ Bitfield(wormno,5); /* at most 31 worms on any level */ #define MAX_NUM_WORMS 32 /* should be 2^(wormno bitfield size) */ long mstrategy; /* for monsters with mflag3: current strategy */ #define STRAT_ARRIVE 0x40000000L /* just arrived on current level */ #define STRAT_WAITFORU 0x20000000L #define STRAT_CLOSE 0x10000000L #define STRAT_WAITMASK 0x30000000L #define STRAT_HEAL 0x08000000L #define STRAT_GROUND 0x04000000L #define STRAT_MONSTR 0x02000000L #define STRAT_PLAYER 0x01000000L #define STRAT_NONE 0x00000000L #define STRAT_STRATMASK 0x0f000000L #define STRAT_XMASK 0x00ff0000L #define STRAT_YMASK 0x0000ff00L #define STRAT_GOAL 0x000000ffL #define STRAT_GOALX(s) ((xchar)((s & STRAT_XMASK) >> 16)) #define STRAT_GOALY(s) ((xchar)((s & STRAT_YMASK) >> 8)) long mtrapseen; /* bitmap of traps we've been trapped in */ long mlstmv; /* for catching up with lost time */ #ifndef GOLDOBJ long mgold; #endif struct obj *minvent; struct obj *mw; long misc_worn_check; xchar weapon_check; uchar mnamelth; /* length of name (following mxlth) */ short mxlth; /* length of following data */ /* in order to prevent alignment problems mextra should be (or follow) a long int */ int meating; /* monster is eating timeout */ long mextra[1]; /* monster dependent info */ }; /* * Note that mextra[] may correspond to any of a number of structures, which * are indicated by some of the other fields. * isgd -> struct egd * ispriest -> struct epri * isshk -> struct eshk * isminion -> struct emin * (struct epri for roaming priests and angels, which is * compatible with emin for polymorph purposes) * mtame -> struct edog * (struct epri for guardian angels, which do not eat * or do other doggy things) * Since at most one structure can be indicated in this manner, it is not * possible to tame any creatures using the other structures (the only * exception being the guardian angels which are tame on creation). */ #define newmonst(xl) (struct monst *)alloc((unsigned)(xl) + sizeof(struct monst)) #define dealloc_monst(mon) free((genericptr_t)(mon)) /* these are in mspeed */ #define MSLOW 1 /* slow monster */ #define MFAST 2 /* speeded monster */ #define NAME(mtmp) (((char *)(mtmp)->mextra) + (mtmp)->mxlth) #define MON_WEP(mon) ((mon)->mw) #define MON_NOWEP(mon) ((mon)->mw = (struct obj *)0) #define DEADMONSTER(mon) ((mon)->mhp < 1) #endif /* MONST_H */ nethack-3.4.3/include/monsym.h0100644000000000000000000000636507764735041015002 0ustar rootroot/* SCCS Id: @(#)monsym.h 3.4 1992/10/18 */ /* Monster symbols and creation information rev 1.0 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MONSYM_H #define MONSYM_H /* * Monster classes. Below, are the corresponding default characters for * them. Monster class 0 is not used or defined so we can use it as a * NULL character. */ #define S_ANT 1 #define S_BLOB 2 #define S_COCKATRICE 3 #define S_DOG 4 #define S_EYE 5 #define S_FELINE 6 #define S_GREMLIN 7 #define S_HUMANOID 8 #define S_IMP 9 #define S_JELLY 10 #define S_KOBOLD 11 #define S_LEPRECHAUN 12 #define S_MIMIC 13 #define S_NYMPH 14 #define S_ORC 15 #define S_PIERCER 16 #define S_QUADRUPED 17 #define S_RODENT 18 #define S_SPIDER 19 #define S_TRAPPER 20 #define S_UNICORN 21 #define S_VORTEX 22 #define S_WORM 23 #define S_XAN 24 #define S_LIGHT 25 #define S_ZRUTY 26 #define S_ANGEL 27 #define S_BAT 28 #define S_CENTAUR 29 #define S_DRAGON 30 #define S_ELEMENTAL 31 #define S_FUNGUS 32 #define S_GNOME 33 #define S_GIANT 34 #define S_JABBERWOCK 36 #define S_KOP 37 #define S_LICH 38 #define S_MUMMY 39 #define S_NAGA 40 #define S_OGRE 41 #define S_PUDDING 42 #define S_QUANTMECH 43 #define S_RUSTMONST 44 #define S_SNAKE 45 #define S_TROLL 46 #define S_UMBER 47 #define S_VAMPIRE 48 #define S_WRAITH 49 #define S_XORN 50 #define S_YETI 51 #define S_ZOMBIE 52 #define S_HUMAN 53 #define S_GHOST 54 #define S_GOLEM 55 #define S_DEMON 56 #define S_EEL 57 #define S_LIZARD 58 #define S_WORM_TAIL 59 #define S_MIMIC_DEF 60 #define MAXMCLASSES 61 /* number of monster classes */ #if 0 /* moved to decl.h so that makedefs.c won't see them */ extern const char def_monsyms[MAXMCLASSES]; /* default class symbols */ extern uchar monsyms[MAXMCLASSES]; /* current class symbols */ #endif /* * Default characters for monsters. These correspond to the monster classes * above. */ #define DEF_ANT 'a' #define DEF_BLOB 'b' #define DEF_COCKATRICE 'c' #define DEF_DOG 'd' #define DEF_EYE 'e' #define DEF_FELINE 'f' #define DEF_GREMLIN 'g' #define DEF_HUMANOID 'h' #define DEF_IMP 'i' #define DEF_JELLY 'j' #define DEF_KOBOLD 'k' #define DEF_LEPRECHAUN 'l' #define DEF_MIMIC 'm' #define DEF_NYMPH 'n' #define DEF_ORC 'o' #define DEF_PIERCER 'p' #define DEF_QUADRUPED 'q' #define DEF_RODENT 'r' #define DEF_SPIDER 's' #define DEF_TRAPPER 't' #define DEF_UNICORN 'u' #define DEF_VORTEX 'v' #define DEF_WORM 'w' #define DEF_XAN 'x' #define DEF_LIGHT 'y' #define DEF_ZRUTY 'z' #define DEF_ANGEL 'A' #define DEF_BAT 'B' #define DEF_CENTAUR 'C' #define DEF_DRAGON 'D' #define DEF_ELEMENTAL 'E' #define DEF_FUNGUS 'F' #define DEF_GNOME 'G' #define DEF_GIANT 'H' #define DEF_JABBERWOCK 'J' #define DEF_KOP 'K' #define DEF_LICH 'L' #define DEF_MUMMY 'M' #define DEF_NAGA 'N' #define DEF_OGRE 'O' #define DEF_PUDDING 'P' #define DEF_QUANTMECH 'Q' #define DEF_RUSTMONST 'R' #define DEF_SNAKE 'S' #define DEF_TROLL 'T' #define DEF_UMBER 'U' #define DEF_VAMPIRE 'V' #define DEF_WRAITH 'W' #define DEF_XORN 'X' #define DEF_YETI 'Y' #define DEF_ZOMBIE 'Z' #define DEF_HUMAN '@' #define DEF_GHOST ' ' #define DEF_GOLEM '\'' #define DEF_DEMON '&' #define DEF_EEL ';' #define DEF_LIZARD ':' #define DEF_INVISIBLE 'I' #define DEF_WORM_TAIL '~' #define DEF_MIMIC_DEF ']' #endif /* MONSYM_H */ nethack-3.4.3/include/mttypriv.h0100644000000000000000000000234707764735041015352 0ustar rootroot/* SCCS Id: @(#)mttypriv.h 3.4 1993/03/01 */ /* Copyright (c) Jon W{tte 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains private structures used to implement the * tty windows - note that these structures may change between * minor releases! */ #ifndef _H_tty_private # define _H_tty_private # ifndef _H_tty_public #include "mactty.h" # endif #if !TARGET_API_MAC_CARBON # include # include # include #endif #define TA_TO_RGB(ta,rgb) (((rgb).red=(((ta)>>16)&0xff)*257),((rgb).green=(((ta)>>8)&0xff)*257),\ ((rgb).blue=((ta)&0xff)*257)),rgb typedef struct tty_record { WindowPtr its_window ; short font_number ; short font_size ; short char_width ; short row_height ; short ascent_height ; short x_size ; short y_size ; short x_curs ; short y_curs ; GWorldPtr its_window_world ; BitMap its_bits ; GrafPtr offscreen_port ; GWorldPtr offscreen_world ; #if CLIP_RECT_ONLY Rect invalid_rect ; #else RgnHandle invalid_part ; #endif long attribute [ TTY_NUMBER_ATTRIBUTES ] ; long last_cursor ; Boolean was_allocated ; Boolean curs_state ; Boolean uses_gworld ; } tty_record ; #endif /* _H_tty_private */ nethack-3.4.3/include/nhlan.h0100644000000000000000000000231507764735041014547 0ustar rootroot/* SCCS Id: @(#)nhlan.h 3.4 1997/04/12 */ /* Copyright (c) Michael Allison, 1997 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef NHLAN_H #define NHLAN_H /* * Here are the LAN features currently implemented: * LAN_MAIL Mail facility allowing receipt and * reading of mail. * LAN_SHARED_BONES Allows bones files to be stored on a * network share. (Does NOT imply compatibiliy * between unlike platforms) */ # ifdef LAN_FEATURES # ifdef LAN_MAIL #define MAIL #ifndef WIN32 #define MAILCKFREQ 50 #else /* * WIN32 port does the real mail lookups in a separate thread * and the NetHack core code really just checks a flag, * so that part of it can be done more often. The throttle * for how often the mail thread should contact the mail * system is controlled by MAILTHREADFREQ and is expressed * in milliseconds. */ #define MAILCKFREQ 5 #define MAILTHREADFREQ 50000 #endif #ifndef MAX_BODY_SIZE #define MAX_BODY_SIZE 1024 #endif struct lan_mail_struct { char sender[120]; char subject[120]; boolean body_in_ram; /* TRUE means body in memory not file */ char filename[_MAX_PATH]; char body[MAX_BODY_SIZE]; }; # endif # endif /*LAN_FEATURES*/ #endif /*NHLAN_H*/ nethack-3.4.3/include/ntconf.h0100644000000000000000000001326607764735041014745 0ustar rootroot/* SCCS Id: @(#)ntconf.h 3.4 2002/03/10 */ /* Copyright (c) NetHack PC Development Team 1993, 1994. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef NTCONF_H #define NTCONF_H /* #define SHELL /* nt use of pcsys routines caused a hang */ #define RANDOM /* have Berkeley random(3) */ #define TEXTCOLOR /* Color text */ #define EXEPATH /* Allow .exe location to be used as HACKDIR */ #define TRADITIONAL_GLYPHMAP /* Store glyph mappings at level change time */ #ifdef WIN32CON #define LAN_FEATURES /* Include code for lan-aware features. Untested in 3.4.0*/ #endif #define PC_LOCKING /* Prevent overwrites of aborted or in-progress games */ /* without first receiving confirmation. */ #define HOLD_LOCKFILE_OPEN /* Keep an exclusive lock on the .0 file */ #define SELF_RECOVER /* Allow the game itself to recover from an aborted game */ #define USER_SOUNDS /* * ----------------------------------------------------------------- * The remaining code shouldn't need modification. * ----------------------------------------------------------------- */ /* #define SHORT_FILENAMES /* All NT filesystems support long names now */ #ifdef MICRO #undef MICRO /* never define this! */ #endif #define NOCWD_ASSUMPTIONS /* Always define this. There are assumptions that it is defined for WIN32. Allow paths to be specified for HACKDIR, LEVELDIR, SAVEDIR, BONESDIR, DATADIR, SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ #define NO_TERMS #define ASCIIGRAPH #ifdef OPTIONS_USED #undef OPTIONS_USED #endif #ifdef MSWIN_GRAPHICS #define OPTIONS_USED "guioptions" #else #define OPTIONS_USED "ttyoptions" #endif #define OPTIONS_FILE OPTIONS_USED #define PORT_HELP "porthelp" #ifdef WIN32CON #define PORT_DEBUG /* include ability to debug international keyboard issues */ #endif /* Stuff to help the user with some common, yet significant errors */ #define INTERJECT_PANIC 0 #define INTERJECTION_TYPES (INTERJECT_PANIC + 1) extern void FDECL(interject_assistance, (int,int,genericptr_t,genericptr_t)); extern void FDECL(interject, (int)); /* The following is needed for prototypes of certain functions */ #if defined(_MSC_VER) #include /* Provides prototypes of exit(), spawn() */ #endif #include /* Provides prototypes of strncmpi(), etc. */ #ifdef STRNCMPI #define strncmpi(a,b,c) strnicmp(a,b,c) #endif #include #include #ifdef __BORLANDC__ #undef randomize #undef random #endif #define PATHLEN BUFSZ /* maximum pathlength */ #define FILENAME BUFSZ /* maximum filename length (conservative) */ #if defined(_MAX_PATH) && defined(_MAX_FNAME) # if (_MAX_PATH < BUFSZ) && (_MAX_FNAME < BUFSZ) #undef PATHLEN #undef FILENAME #define PATHLEN _MAX_PATH #define FILENAME _MAX_FNAME # endif #endif #define NO_SIGNAL #define index strchr #define rindex strrchr #include #define USE_STDARG #ifdef RANDOM /* Use the high quality random number routines. */ #define Rand() random() #else #define Rand() rand() #endif #define FCMASK 0660 /* file creation mask */ #define regularize nt_regularize #define HLOCK "NHPERM" #ifndef M #define M(c) ((char) (0x80 | (c))) /* #define M(c) ((c) - 128) */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif #if defined(DLB) #define FILENAME_CMP stricmp /* case insensitive */ #endif #if 0 extern char levels[], bones[], permbones[], #endif /* 0 */ /* this was part of the MICRO stuff in the past */ extern const char *alllevels, *allbones; extern char hackdir[]; #define ABORT C('a') #define getuid() 1 #define getlogin() ((char *)0) extern void NDECL(win32_abort); #ifdef WIN32CON extern void FDECL(nttty_preference_update, (const char *)); extern void NDECL(toggle_mouse_support); extern void FDECL(map_subkeyvalue, (char *)); extern void NDECL(load_keyboard_handler); #endif #include #ifndef __BORLANDC__ #include #include #else int _RTLENTRY _EXPFUNC access (const char _FAR *__path, int __amode); int _RTLENTRY _EXPFUNC _chdrive(int __drive); int _RTLENTRYF _EXPFUNC32 chdir( const char _FAR *__path ); char _FAR * _RTLENTRY _EXPFUNC getcwd( char _FAR *__buf, int __buflen ); int _RTLENTRY _EXPFUNC write (int __handle, const void _FAR *__buf, unsigned __len); int _RTLENTRY _EXPFUNC creat (const char _FAR *__path, int __amode); int _RTLENTRY _EXPFUNC close (int __handle); int _RTLENTRY _EXPFUNC _close (int __handle); int _RTLENTRY _EXPFUNC open (const char _FAR *__path, int __access,... /*unsigned mode*/); long _RTLENTRY _EXPFUNC lseek (int __handle, long __offset, int __fromwhere); int _RTLENTRY _EXPFUNC read (int __handle, void _FAR *__buf, unsigned __len); #endif #include #undef kbhit /* Use our special NT kbhit */ #define kbhit (*nt_kbhit) #ifdef LAN_FEATURES #define MAX_LAN_USERNAME 20 #define LAN_RO_PLAYGROUND /* not implemented in 3.3.0 */ #define LAN_SHARED_BONES /* not implemented in 3.3.0 */ #include "nhlan.h" #endif #ifndef alloca #define ALLOCA_HACK /* used in util/panic.c */ #endif #ifndef REDO #undef Getchar #define Getchar nhgetch #endif #ifdef _MSC_VER #if 0 #pragma warning(disable:4018) /* signed/unsigned mismatch */ #pragma warning(disable:4305) /* init, conv from 'const int' to 'char' */ #endif #pragma warning(disable:4761) /* integral size mismatch in arg; conv supp*/ #ifdef YYPREFIX #pragma warning(disable:4102) /* unreferenced label */ #endif #endif extern int FDECL(set_win32_option, (const char *, const char *)); #ifdef WIN32CON #define LEFTBUTTON FROM_LEFT_1ST_BUTTON_PRESSED #define RIGHTBUTTON RIGHTMOST_BUTTON_PRESSED #define MIDBUTTON FROM_LEFT_2ND_BUTTON_PRESSED #define MOUSEMASK (LEFTBUTTON | RIGHTBUTTON | MIDBUTTON) #endif /* WIN32CON */ #endif /* NTCONF_H */ nethack-3.4.3/include/obj.h0100644000000000000000000003034707764735041014227 0ustar rootroot/* SCCS Id: @(#)obj.h 3.4 2002/01/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef OBJ_H #define OBJ_H /* #define obj obj_nh */ /* uncomment for SCO UNIX, which has a conflicting * typedef for "obj" in */ union vptrs { struct obj *v_nexthere; /* floor location lists */ struct obj *v_ocontainer; /* point back to container */ struct monst *v_ocarry; /* point back to carrying monst */ }; struct obj { struct obj *nobj; union vptrs v; #define nexthere v.v_nexthere #define ocontainer v.v_ocontainer #define ocarry v.v_ocarry struct obj *cobj; /* contents list for containers */ unsigned o_id; xchar ox,oy; short otyp; /* object class number */ unsigned owt; long quan; /* number of items */ schar spe; /* quality of weapon, armor or ring (+ or -) number of charges for wand ( >= -1 ) marks your eggs, spinach tins royal coffers for a court ( == 2) tells which fruit a fruit is special for uball and amulet historic and gender for statues */ #define STATUE_HISTORIC 0x01 #define STATUE_MALE 0x02 #define STATUE_FEMALE 0x04 char oclass; /* object class */ char invlet; /* designation in inventory */ char oartifact; /* artifact array index */ xchar where; /* where the object thinks it is */ #define OBJ_FREE 0 /* object not attached to anything */ #define OBJ_FLOOR 1 /* object on floor */ #define OBJ_CONTAINED 2 /* object in a container */ #define OBJ_INVENT 3 /* object in the hero's inventory */ #define OBJ_MINVENT 4 /* object in a monster inventory */ #define OBJ_MIGRATING 5 /* object sent off to another level */ #define OBJ_BURIED 6 /* object buried */ #define OBJ_ONBILL 7 /* object on shk bill */ #define NOBJ_STATES 8 xchar timed; /* # of fuses (timers) attached to this obj */ Bitfield(cursed,1); Bitfield(blessed,1); Bitfield(unpaid,1); /* on some bill */ Bitfield(no_charge,1); /* if shk shouldn't charge for this */ Bitfield(known,1); /* exact nature known */ Bitfield(dknown,1); /* color or text known */ Bitfield(bknown,1); /* blessing or curse known */ Bitfield(rknown,1); /* rustproof or not known */ Bitfield(oeroded,2); /* rusted/burnt weapon/armor */ Bitfield(oeroded2,2); /* corroded/rotted weapon/armor */ #define greatest_erosion(otmp) (int)((otmp)->oeroded > (otmp)->oeroded2 ? (otmp)->oeroded : (otmp)->oeroded2) #define MAX_ERODE 3 #define orotten oeroded /* rotten food */ #define odiluted oeroded /* diluted potions */ #define norevive oeroded2 Bitfield(oerodeproof,1); /* erodeproof weapon/armor */ Bitfield(olocked,1); /* object is locked */ Bitfield(obroken,1); /* lock has been broken */ Bitfield(otrapped,1); /* container is trapped */ /* or accidental tripped rolling boulder trap */ #define opoisoned otrapped /* object (weapon) is coated with poison */ Bitfield(recharged,3); /* number of times it's been recharged */ Bitfield(lamplit,1); /* a light-source -- can be lit */ #ifdef INVISIBLE_OBJECTS Bitfield(oinvis,1); /* invisible */ #endif Bitfield(greased,1); /* covered with grease */ Bitfield(oattached,2); /* obj struct has special attachment */ #define OATTACHED_NOTHING 0 #define OATTACHED_MONST 1 /* monst struct in oextra */ #define OATTACHED_M_ID 2 /* monst id in oextra */ #define OATTACHED_UNUSED3 3 Bitfield(in_use,1); /* for magic items before useup items */ Bitfield(bypass,1); /* mark this as an object to be skipped by bhito() */ /* 6 free bits */ int corpsenm; /* type of corpse is mons[corpsenm] */ #define leashmon corpsenm /* gets m_id of attached pet */ #define spestudied corpsenm /* # of times a spellbook has been studied */ #define fromsink corpsenm /* a potion from a sink */ unsigned oeaten; /* nutrition left in food, if partly eaten */ long age; /* creation date */ uchar onamelth; /* length of name (following oxlth) */ short oxlth; /* length of following data */ /* in order to prevent alignment problems oextra should be (or follow) a long int */ long owornmask; long oextra[1]; /* used for name of ordinary objects - length is flexible; amount for tmp gold objects */ }; #define newobj(xl) (struct obj *)alloc((unsigned)(xl) + sizeof(struct obj)) #define ONAME(otmp) (((char *)(otmp)->oextra) + (otmp)->oxlth) /* Weapons and weapon-tools */ /* KMH -- now based on skill categories. Formerly: * #define is_sword(otmp) (otmp->oclass == WEAPON_CLASS && \ * objects[otmp->otyp].oc_wepcat == WEP_SWORD) * #define is_blade(otmp) (otmp->oclass == WEAPON_CLASS && \ * (objects[otmp->otyp].oc_wepcat == WEP_BLADE || \ * objects[otmp->otyp].oc_wepcat == WEP_SWORD)) * #define is_weptool(o) ((o)->oclass == TOOL_CLASS && \ * objects[(o)->otyp].oc_weptool) * #define is_multigen(otyp) (otyp <= SHURIKEN) * #define is_poisonable(otyp) (otyp <= BEC_DE_CORBIN) */ #define is_blade(otmp) (otmp->oclass == WEAPON_CLASS && \ objects[otmp->otyp].oc_skill >= P_DAGGER && \ objects[otmp->otyp].oc_skill <= P_SABER) #define is_axe(otmp) ((otmp->oclass == WEAPON_CLASS || \ otmp->oclass == TOOL_CLASS) && \ objects[otmp->otyp].oc_skill == P_AXE) #define is_pick(otmp) ((otmp->oclass == WEAPON_CLASS || \ otmp->oclass == TOOL_CLASS) && \ objects[otmp->otyp].oc_skill == P_PICK_AXE) #define is_sword(otmp) (otmp->oclass == WEAPON_CLASS && \ objects[otmp->otyp].oc_skill >= P_SHORT_SWORD && \ objects[otmp->otyp].oc_skill <= P_SABER) #define is_pole(otmp) ((otmp->oclass == WEAPON_CLASS || \ otmp->oclass == TOOL_CLASS) && \ (objects[otmp->otyp].oc_skill == P_POLEARMS || \ objects[otmp->otyp].oc_skill == P_LANCE)) #define is_spear(otmp) (otmp->oclass == WEAPON_CLASS && \ objects[otmp->otyp].oc_skill >= P_SPEAR && \ objects[otmp->otyp].oc_skill <= P_JAVELIN) #define is_launcher(otmp) (otmp->oclass == WEAPON_CLASS && \ objects[otmp->otyp].oc_skill >= P_BOW && \ objects[otmp->otyp].oc_skill <= P_CROSSBOW) #define is_ammo(otmp) ((otmp->oclass == WEAPON_CLASS || \ otmp->oclass == GEM_CLASS) && \ objects[otmp->otyp].oc_skill >= -P_CROSSBOW && \ objects[otmp->otyp].oc_skill <= -P_BOW) #define ammo_and_launcher(otmp,ltmp) \ (is_ammo(otmp) && (ltmp) && \ objects[(otmp)->otyp].oc_skill == -objects[(ltmp)->otyp].oc_skill) #define is_missile(otmp) ((otmp->oclass == WEAPON_CLASS || \ otmp->oclass == TOOL_CLASS) && \ objects[otmp->otyp].oc_skill >= -P_BOOMERANG && \ objects[otmp->otyp].oc_skill <= -P_DART) #define is_weptool(o) ((o)->oclass == TOOL_CLASS && \ objects[(o)->otyp].oc_skill != P_NONE) #define bimanual(otmp) ((otmp->oclass == WEAPON_CLASS || \ otmp->oclass == TOOL_CLASS) && \ objects[otmp->otyp].oc_bimanual) #define is_multigen(otmp) (otmp->oclass == WEAPON_CLASS && \ objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \ objects[otmp->otyp].oc_skill <= -P_BOW) #define is_poisonable(otmp) (otmp->oclass == WEAPON_CLASS && \ objects[otmp->otyp].oc_skill >= -P_SHURIKEN && \ objects[otmp->otyp].oc_skill <= -P_BOW) #define uslinging() (uwep && objects[uwep->otyp].oc_skill == P_SLING) /* Armor */ #define is_shield(otmp) (otmp->oclass == ARMOR_CLASS && \ objects[otmp->otyp].oc_armcat == ARM_SHIELD) #define is_helmet(otmp) (otmp->oclass == ARMOR_CLASS && \ objects[otmp->otyp].oc_armcat == ARM_HELM) #define is_boots(otmp) (otmp->oclass == ARMOR_CLASS && \ objects[otmp->otyp].oc_armcat == ARM_BOOTS) #define is_gloves(otmp) (otmp->oclass == ARMOR_CLASS && \ objects[otmp->otyp].oc_armcat == ARM_GLOVES) #define is_cloak(otmp) (otmp->oclass == ARMOR_CLASS && \ objects[otmp->otyp].oc_armcat == ARM_CLOAK) #define is_shirt(otmp) (otmp->oclass == ARMOR_CLASS && \ objects[otmp->otyp].oc_armcat == ARM_SHIRT) #define is_suit(otmp) (otmp->oclass == ARMOR_CLASS && \ objects[otmp->otyp].oc_armcat == ARM_SUIT) #define is_elven_armor(otmp) ((otmp)->otyp == ELVEN_LEATHER_HELM\ || (otmp)->otyp == ELVEN_MITHRIL_COAT\ || (otmp)->otyp == ELVEN_CLOAK\ || (otmp)->otyp == ELVEN_SHIELD\ || (otmp)->otyp == ELVEN_BOOTS) #define is_orcish_armor(otmp) ((otmp)->otyp == ORCISH_HELM\ || (otmp)->otyp == ORCISH_CHAIN_MAIL\ || (otmp)->otyp == ORCISH_RING_MAIL\ || (otmp)->otyp == ORCISH_CLOAK\ || (otmp)->otyp == URUK_HAI_SHIELD\ || (otmp)->otyp == ORCISH_SHIELD) #define is_dwarvish_armor(otmp) ((otmp)->otyp == DWARVISH_IRON_HELM\ || (otmp)->otyp == DWARVISH_MITHRIL_COAT\ || (otmp)->otyp == DWARVISH_CLOAK\ || (otmp)->otyp == DWARVISH_ROUNDSHIELD) #define is_gnomish_armor(otmp) (FALSE) /* Eggs and other food */ #define MAX_EGG_HATCH_TIME 200 /* longest an egg can remain unhatched */ #define stale_egg(egg) ((monstermoves - (egg)->age) > (2*MAX_EGG_HATCH_TIME)) #define ofood(o) ((o)->otyp == CORPSE || (o)->otyp == EGG || (o)->otyp == TIN) #define polyfodder(obj) (ofood(obj) && \ pm_to_cham((obj)->corpsenm) != CHAM_ORDINARY) #define mlevelgain(obj) (ofood(obj) && (obj)->corpsenm == PM_WRAITH) #define mhealup(obj) (ofood(obj) && (obj)->corpsenm == PM_NURSE) /* Containers */ #define carried(o) ((o)->where == OBJ_INVENT) #define mcarried(o) ((o)->where == OBJ_MINVENT) #define Has_contents(o) (/* (Is_container(o) || (o)->otyp == STATUE) && */ \ (o)->cobj != (struct obj *)0) #define Is_container(o) ((o)->otyp >= LARGE_BOX && (o)->otyp <= BAG_OF_TRICKS) #define Is_box(otmp) (otmp->otyp == LARGE_BOX || otmp->otyp == CHEST) #define Is_mbag(otmp) (otmp->otyp == BAG_OF_HOLDING || \ otmp->otyp == BAG_OF_TRICKS) /* dragon gear */ #define Is_dragon_scales(obj) ((obj)->otyp >= GRAY_DRAGON_SCALES && \ (obj)->otyp <= YELLOW_DRAGON_SCALES) #define Is_dragon_mail(obj) ((obj)->otyp >= GRAY_DRAGON_SCALE_MAIL && \ (obj)->otyp <= YELLOW_DRAGON_SCALE_MAIL) #define Is_dragon_armor(obj) (Is_dragon_scales(obj) || Is_dragon_mail(obj)) #define Dragon_scales_to_pm(obj) &mons[PM_GRAY_DRAGON + (obj)->otyp \ - GRAY_DRAGON_SCALES] #define Dragon_mail_to_pm(obj) &mons[PM_GRAY_DRAGON + (obj)->otyp \ - GRAY_DRAGON_SCALE_MAIL] #define Dragon_to_scales(pm) (GRAY_DRAGON_SCALES + (pm - mons)) /* Elven gear */ #define is_elven_weapon(otmp) ((otmp)->otyp == ELVEN_ARROW\ || (otmp)->otyp == ELVEN_SPEAR\ || (otmp)->otyp == ELVEN_DAGGER\ || (otmp)->otyp == ELVEN_SHORT_SWORD\ || (otmp)->otyp == ELVEN_BROADSWORD\ || (otmp)->otyp == ELVEN_BOW) #define is_elven_obj(otmp) (is_elven_armor(otmp) || is_elven_weapon(otmp)) /* Orcish gear */ #define is_orcish_obj(otmp) (is_orcish_armor(otmp)\ || (otmp)->otyp == ORCISH_ARROW\ || (otmp)->otyp == ORCISH_SPEAR\ || (otmp)->otyp == ORCISH_DAGGER\ || (otmp)->otyp == ORCISH_SHORT_SWORD\ || (otmp)->otyp == ORCISH_BOW) /* Dwarvish gear */ #define is_dwarvish_obj(otmp) (is_dwarvish_armor(otmp)\ || (otmp)->otyp == DWARVISH_SPEAR\ || (otmp)->otyp == DWARVISH_SHORT_SWORD\ || (otmp)->otyp == DWARVISH_MATTOCK) /* Gnomish gear */ #define is_gnomish_obj(otmp) (is_gnomish_armor(otmp)) /* Light sources */ #define Is_candle(otmp) (otmp->otyp == TALLOW_CANDLE || \ otmp->otyp == WAX_CANDLE) #define MAX_OIL_IN_FLASK 400 /* maximum amount of oil in a potion of oil */ /* MAGIC_LAMP intentionally excluded below */ /* age field of this is relative age rather than absolute */ #define age_is_relative(otmp) ((otmp)->otyp == BRASS_LANTERN\ || (otmp)->otyp == OIL_LAMP\ || (otmp)->otyp == CANDELABRUM_OF_INVOCATION\ || (otmp)->otyp == TALLOW_CANDLE\ || (otmp)->otyp == WAX_CANDLE\ || (otmp)->otyp == POT_OIL) /* object can be ignited */ #define ignitable(otmp) ((otmp)->otyp == BRASS_LANTERN\ || (otmp)->otyp == OIL_LAMP\ || (otmp)->otyp == CANDELABRUM_OF_INVOCATION\ || (otmp)->otyp == TALLOW_CANDLE\ || (otmp)->otyp == WAX_CANDLE\ || (otmp)->otyp == POT_OIL) /* special stones */ #define is_graystone(obj) ((obj)->otyp == LUCKSTONE || \ (obj)->otyp == LOADSTONE || \ (obj)->otyp == FLINT || \ (obj)->otyp == TOUCHSTONE) /* misc */ #ifdef KOPS #define is_flimsy(otmp) (objects[(otmp)->otyp].oc_material <= LEATHER || \ (otmp)->otyp == RUBBER_HOSE) #else #define is_flimsy(otmp) (objects[(otmp)->otyp].oc_material <= LEATHER) #endif /* helpers, simple enough to be macros */ #define is_plural(o) ((o)->quan > 1 || \ (o)->oartifact == ART_EYES_OF_THE_OVERWORLD) /* Flags for get_obj_location(). */ #define CONTAINED_TOO 0x1 #define BURIED_TOO 0x2 #endif /* OBJ_H */ nethack-3.4.3/include/objclass.h0100644000000000000000000001404007764735041015245 0ustar rootroot/* SCCS Id: @(#)objclass.h 3.4 1996/06/16 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef OBJCLASS_H #define OBJCLASS_H /* definition of a class of objects */ struct objclass { short oc_name_idx; /* index of actual name */ short oc_descr_idx; /* description when name unknown */ char * oc_uname; /* called by user */ Bitfield(oc_name_known,1); Bitfield(oc_merge,1); /* merge otherwise equal objects */ Bitfield(oc_uses_known,1); /* obj->known affects full decription */ /* otherwise, obj->dknown and obj->bknown */ /* tell all, and obj->known should always */ /* be set for proper merging behavior */ Bitfield(oc_pre_discovered,1); /* Already known at start of game; */ /* won't be listed as a discovery. */ Bitfield(oc_magic,1); /* inherently magical object */ Bitfield(oc_charged,1); /* may have +n or (n) charges */ Bitfield(oc_unique,1); /* special one-of-a-kind object */ Bitfield(oc_nowish,1); /* cannot wish for this object */ Bitfield(oc_big,1); #define oc_bimanual oc_big /* for weapons & tools used as weapons */ #define oc_bulky oc_big /* for armor */ Bitfield(oc_tough,1); /* hard gems/rings */ Bitfield(oc_dir,2); #define NODIR 1 /* for wands/spells: non-directional */ #define IMMEDIATE 2 /* directional */ #define RAY 3 /* zap beams */ #define PIERCE 1 /* for weapons & tools used as weapons */ #define SLASH 2 /* (latter includes iron ball & chain) */ #define WHACK 0 /*Bitfield(oc_subtyp,3);*/ /* Now too big for a bitfield... see below */ Bitfield(oc_material,5); #define LIQUID 1 /* currently only for venom */ #define WAX 2 #define VEGGY 3 /* foodstuffs */ #define FLESH 4 /* ditto */ #define PAPER 5 #define CLOTH 6 #define LEATHER 7 #define WOOD 8 #define BONE 9 #define DRAGON_HIDE 10 /* not leather! */ #define IRON 11 /* Fe - includes steel */ #define METAL 12 /* Sn, &c. */ #define COPPER 13 /* Cu - includes brass */ #define SILVER 14 /* Ag */ #define GOLD 15 /* Au */ #define PLATINUM 16 /* Pt */ #define MITHRIL 17 #define PLASTIC 18 #define GLASS 19 #define GEMSTONE 20 #define MINERAL 21 #define is_organic(otmp) (objects[otmp->otyp].oc_material <= WOOD) #define is_metallic(otmp) (objects[otmp->otyp].oc_material >= IRON && \ objects[otmp->otyp].oc_material <= MITHRIL) /* primary damage: fire/rust/--- */ /* is_flammable(otmp), is_rottable(otmp) in mkobj.c */ #define is_rustprone(otmp) (objects[otmp->otyp].oc_material == IRON) /* secondary damage: rot/acid/acid */ #define is_corrodeable(otmp) (objects[otmp->otyp].oc_material == COPPER || objects[otmp->otyp].oc_material == IRON) #define is_damageable(otmp) (is_rustprone(otmp) || is_flammable(otmp) || \ is_rottable(otmp) || is_corrodeable(otmp)) schar oc_subtyp; #define oc_skill oc_subtyp /* Skills of weapons, spellbooks, tools, gems */ #define oc_armcat oc_subtyp /* for armor */ #define ARM_SHIELD 1 /* needed for special wear function */ #define ARM_HELM 2 #define ARM_GLOVES 3 #define ARM_BOOTS 4 #define ARM_CLOAK 5 #define ARM_SHIRT 6 #define ARM_SUIT 0 uchar oc_oprop; /* property (invis, &c.) conveyed */ char oc_class; /* object class */ schar oc_delay; /* delay when using such an object */ uchar oc_color; /* color of the object */ short oc_prob; /* probability, used in mkobj() */ unsigned short oc_weight; /* encumbrance (1 cn = 0.1 lb.) */ short oc_cost; /* base cost in shops */ /* Check the AD&D rules! The FIRST is small monster damage. */ /* for weapons, and tools, rocks, and gems useful as weapons */ schar oc_wsdam, oc_wldam; /* max small/large monster damage */ schar oc_oc1, oc_oc2; #define oc_hitbon oc_oc1 /* weapons: "to hit" bonus */ #define a_ac oc_oc1 /* armor class, used in ARM_BONUS in do.c */ #define a_can oc_oc2 /* armor: used in mhitu.c */ #define oc_level oc_oc2 /* books: spell level */ unsigned short oc_nutrition; /* food value */ }; struct objdescr { const char *oc_name; /* actual name */ const char *oc_descr; /* description when name unknown */ }; extern NEARDATA struct objclass objects[]; extern NEARDATA struct objdescr obj_descr[]; /* * All objects have a class. Make sure that all classes have a corresponding * symbol below. */ #define RANDOM_CLASS 0 /* used for generating random objects */ #define ILLOBJ_CLASS 1 #define WEAPON_CLASS 2 #define ARMOR_CLASS 3 #define RING_CLASS 4 #define AMULET_CLASS 5 #define TOOL_CLASS 6 #define FOOD_CLASS 7 #define POTION_CLASS 8 #define SCROLL_CLASS 9 #define SPBOOK_CLASS 10 /* actually SPELL-book */ #define WAND_CLASS 11 #define COIN_CLASS 12 #define GEM_CLASS 13 #define ROCK_CLASS 14 #define BALL_CLASS 15 #define CHAIN_CLASS 16 #define VENOM_CLASS 17 #define MAXOCLASSES 18 #define ALLOW_COUNT (MAXOCLASSES+1) /* Can be used in the object class */ #define ALL_CLASSES (MAXOCLASSES+2) /* input to getobj(). */ #define ALLOW_NONE (MAXOCLASSES+3) /* */ #define BURNING_OIL (MAXOCLASSES+1) /* Can be used as input to explode. */ #define MON_EXPLODE (MAXOCLASSES+2) /* Exploding monster (e.g. gas spore) */ #if 0 /* moved to decl.h so that makedefs.c won't see them */ extern const char def_oc_syms[MAXOCLASSES]; /* default class symbols */ extern uchar oc_syms[MAXOCLASSES]; /* current class symbols */ #endif /* Default definitions of all object-symbols (must match classes above). */ #define ILLOBJ_SYM ']' /* also used for mimics */ #define WEAPON_SYM ')' #define ARMOR_SYM '[' #define RING_SYM '=' #define AMULET_SYM '"' #define TOOL_SYM '(' #define FOOD_SYM '%' #define POTION_SYM '!' #define SCROLL_SYM '?' #define SPBOOK_SYM '+' #define WAND_SYM '/' #define GOLD_SYM '$' #define GEM_SYM '*' #define ROCK_SYM '`' #define BALL_SYM '0' #define CHAIN_SYM '_' #define VENOM_SYM '.' struct fruit { char fname[PL_FSIZ]; int fid; struct fruit *nextf; }; #define newfruit() (struct fruit *)alloc(sizeof(struct fruit)) #define dealloc_fruit(rind) free((genericptr_t) (rind)) #define OBJ_NAME(obj) (obj_descr[(obj).oc_name_idx].oc_name) #define OBJ_DESCR(obj) (obj_descr[(obj).oc_descr_idx].oc_descr) #endif /* OBJCLASS_H */ nethack-3.4.3/include/os2conf.h0100644000000000000000000000454507764735041015027 0ustar rootroot/* SCCS Id: @(#)os2conf.h 3.4 1996/10/29 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993, 1996. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef OS2 #ifndef OS2CONF_H #define OS2CONF_H /* * Compiler configuration. Compiler may be * selected either here or in Makefile.os2. */ /* #define OS2_MSC /* Microsoft C 5.1 and 6.0 */ #define OS2_GCC /* GCC emx 0.8f */ /* #define OS2_CSET2 /* IBM C Set/2 (courtesy Jeff Urlwin) */ /* #define OS2_CSET2_VER_1 /* CSet/2 version selection */ /* #define OS2_CSET2_VER_2 /* - " - */ /* * System configuration. */ #define OS2_USESYSHEADERS /* use compiler's own system headers */ /* #define OS2_HPFS /* use OS/2 High Performance File System */ #if defined(OS2_GCC) || defined(OS2_CSET2) # define OS2_32BITAPI /* enable for compilation in OS/2 2.0 */ #endif /* * Other configurable options. Generally no * reason to touch the defaults, I think. */ /*#define MFLOPPY /* floppy and ramdisk support */ #define RANDOM /* Berkeley random(3) */ #define SHELL /* shell escape */ /* #define TERMLIB /* use termcap file */ #define ANSI_DEFAULT /* allows NetHack to run without termcap file */ #define TEXTCOLOR /* allow color */ /* * The remaining code shouldn't need modification. */ #ifdef MSDOS # undef MSDOS /* MSC autodefines this but we don't want it */ #endif #ifndef MICRO # define MICRO /* must be defined to allow some inclusions */ #endif #if !defined(TERMLIB) && !defined(ANSI_DEFAULT) # define ANSI_DEFAULT /* have to have one or the other */ #endif #define PATHLEN 260 /* maximum pathlength (HPFS) */ #define FILENAME 260 /* maximum filename length (HPFS) */ #ifndef MICRO_H #include "micro.h" /* necessary externs for [os_name].c */ #endif #ifndef SYSTEM_H #include "system.h" #endif #ifndef index #define index strchr #endif #ifndef rindex #define rindex strrchr #endif #include /* the high quality random number routines */ #ifdef RANDOM # define Rand() random() #else # define Rand() rand() #endif /* file creation mask */ #include #include #define FCMASK (S_IREAD | S_IWRITE) #include #ifdef __EMX__ #include #endif #ifndef REDO # undef Getchar # define Getchar nhgetch #endif void hangup(int i); #endif /* OS2CONF_H */ #endif /* OS2 */ nethack-3.4.3/include/patchlevel.h0100644000000000000000000003763607764735041015614 0ustar rootroot/* SCCS Id: @(#)patchlevel.h 3.4 2003/12/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* NetHack 3.4.3 */ #define VERSION_MAJOR 3 #define VERSION_MINOR 4 /* * PATCHLEVEL is updated for each release. */ #define PATCHLEVEL 3 /* * Incrementing EDITLEVEL can be used to force invalidation of old bones * and save files. */ #define EDITLEVEL 0 #define COPYRIGHT_BANNER_A \ "NetHack, Copyright 1985-2003" #define COPYRIGHT_BANNER_B \ " By Stichting Mathematisch Centrum and M. Stephenson." #define COPYRIGHT_BANNER_C \ " See license for details." /* * If two or more successive releases have compatible data files, define * this with the version number of the oldest such release so that the * new release will accept old save and bones files. The format is * 0xMMmmPPeeL * 0x = literal prefix "0x", MM = major version, mm = minor version, * PP = patch level, ee = edit level, L = literal suffix "L", * with all four numbers specified as two hexadecimal digits. */ #define VERSION_COMPATIBILITY 0x03040000L /* 3.4.0-0 */ /*****************************************************************************/ /* Version 3.4.x */ /* Patch 3, December 7, 2003 * Several dozen general bug fixes including at least one fatal bug * Correct several inconsistencies * Handle level completely filled with monsters better * Performance enhancements for win32tty port on Windows 98 and Me * win32gui player selection fixes * X11 player selection fixes, one of which could be fatal * Eliminated a gold-in-shop-container cheat * Include bones file version compatibility info in options file */ /* Patch 2, August 30, 2003 * Fix a fatal bug that caused a crash when applying figurine, candle, or * bell that gets used up * Fix a fatal bug that triggered a panic when your secondary weapon was * cursed during bones file creation * Several dozen general bug fixes * Fixed some Gnome compilation problems on Redhat 7.2 and 8.0 * Fixed a problem in the util Makefile * Use random() by default under linux instead of lrand48() * win32 tty adjustments and support for loading alternative key handlers */ /* Patch 1, February 22, 2003 * Fix a few fatal errors including one for reentering shops, one * involving land mines and boulders/statues, one for delayed * polymorph, and one from a chest trap exploding ball and chain * Fix a buffer overflow that could lead to security problems * Hundreds of general bug fixes * Several message and other glitches corrected * Travel command adjustments and ability to disable travel command * message recall window extensions (by Christian Cooper) * win32: some interface improvements * unix: improved tile support * gnome: some fixes, and some enhancements by Dylan Alex Simon * winCE: Windows CE port included (by Alex Kompel) */ /* * NetHack 3.4.0, March 20, 2002 * * Hundreds of general bug fixes including some for sliming, zapping, conduct, * and several more for riding * Eliminated a few potentially fatal bugs including one for stone-to-flesh, * trouble-fixing during prayer, riding down stairs while punished, * polyd player demon summoning, throwing digging tools into shops, and * a couple from having the vision system enabled at inappropriate times * Corrected some incorrect calculations in final scoring * Enhanced config file processing and alert to duplication of entries * Player selection prompt enhancements for TTY and X11 * Objects merge in containers * Wish for "nothing", and genocide "none" to preserve your conduct * Changes to Wizard quest * Added the travel command which works by mouse click or '_' command * Config file BOULDER option to specify the symbol for displaying boulders * Incorporate modified versions of several 3.3.1 patches that have been * in circulation in the NetHack community * New Gnomish Mines levels (courtesy Kelly Bailey) * Mac: command-key shortcuts in the player selection dialog * Amiga: screenmode requester, and several amiga specific bug fixes * Win32 graphical port contributed by Alex Kompel is now included */ /* Version 3.4 */ /*****************************************************************************/ /* Version 3.3.x */ /* Patch 1, August 9, 2000 * Many, many general fixes, including a number for riding, twoweapon, * and invisible monsters * A security fix for a couple of potentially exploitable buffer overflows * in previous versions * Redo Ranger quest * Introduction of differentiation between different causes of blindness * Overhaul of warning * Functionality restored to Amiga (courtesy Janne Salmijarvi) and Atari * (courtesy Christian "Marvin" Bressler) ports * Mac: multiple interface fixes * win32: fixed bug that caused messages to stop displaying after escape * tty: use ANSI color (AF) over standard color (Sf) when given the choice * several ports: offer for player selection only choices consistent with * those already made by config file/command line (e.g., only offer roles * that are compatible with specified race) */ /* * NetHack 3.3.0, December 10, 1999 * * Implement the differentiation of character class or role from the * character race. * Removal of the Elf class, in preference to the Elf as a race. * Introduction of Dwarves, Elves, Gnomes and Orcs as distinct races in * addition to the Human "norm". * Addition of the Monk and Ranger classes. * Integrate some of the features of several branch versions of the game, * notably NetHack--, NHplus, SLASH, and Slash'em. * Adopt "the wizard patch" spellcasting system. * Support for the Qt widget set. * Y2K fix: use 4 digit year values for the dates in the score file * updated COPYRIGHT_BANNER_A to reflect year of release. * Dozens of other bug fixes, and minor improvements. */ /* Version 3.3 */ /*****************************************************************************/ /* Version 3.2.x */ /* Patch 3, December 10, 1999 * Released simultaneously with 3.3.0 for the benefit of * ports and platforms that were unable to get working * versions of 3.3.0 ready prior to the year 2000. It * consisted of just a few bug fixes and offered no new * functionality changes over 3.2.2. * * Y2K fix: use 4 digit year values for the dates in the score file * updated COPYRIGHT_BANNER_A to reflect year of release * Fatal Mac bug removed * DOS Makefile problem removed * several bugs that could potentially trigger crashes removed */ /* Patch 2, December 10, 1996 * fix the `recover' utility * fix priest/minion name overflow which could cause Astral Plane crashes * avoid crash when hit by own thrown boomerang * " " " worn blindfold pushed off by applying cursed towel * handle returning live Wizard correctly in deep dungeon levels * don't occasionally display unseen areas of new levels during level change * other minor display fixes * fix several minor reason for death inconsistencies and shop bugs * high dexterity doesn't guarantee that thrown eggs & potions will hit * * Selected platform- or configuration-specific changes: * Mac: update `mrecover' * MSDOS: don't switch into tiles mode when resuming play on rogue level * tty: support object class characters for 'I' command in menu mode * Unix: work around several compilation problems * X11: as tty above, plus implement tty-style count handling in menus; * better window placement support for old window managers */ /* Patch 1, May 28, 1996 * eliminate `#qualifications'; fix weapon proficiency handling for missiles * keep Medusa from continuing to move after she's been killed by reflection * of her own gaze (fixes relmon panic) * make monsters a little smarter; assorted eating and chatting changes * fix object amnesia for spellbooks; fix Nazgul's sleep gas attack * fix bullwhip usage for case of having recently been in a trap * egg hatching fixes, oil potion fixes, magic marker fixes * support object class chars as selection accelerators for some menus * stricter parsing of run-time options at startup time * interactive setting of options via menu (courtesy Per Liboriussen) * * Selected platform- or configuration-specific changes: * Amiga: fix panic for tiles display in Gnomish mines * BeOS: preliminary support for new BeBox platform; initially tty only * DLB: avoid excessive fseek calls (major performance hit for MSDOS) * HPUX: workaround for gcc-2.6.3 bug adversely affecting monster generation * Mac: avoid MW 68K struct copy optimization bug which caused crashes; * fix dragging of scrollbar; boost partitions to 2MB minimum * MSDOS: wasn't safe to enter endgame for MFLOPPY configuration; * fix re-entry into game after "!" (shell escape) + chdir + EXIT; * F3/F4/F5 display interface swapping improvements; * add support for preloading all tiles in protected mode environment * TERMINFO: colors were wrong for some systems, such as Linux * X11: display help files properly */ /* * NetHack 3.2.0, April 11, 1996 * enhancements to the windowing systems including "tiles" or icons to * visually represent monsters and objects (courtesy Warwick Allison) * window based menu system introduced for inventory and selection * moving light sources besides the player * improved #untrap (courtesy Helge Hafting) * spellcasting logic changes to balance spellcasting towards magic-using * classes (courtesy Stephen White) * many, many bug fixes and abuse eliminations */ /* Version 3.2 */ /*****************************************************************************/ /* Version 3.1.x */ /* * Patch 3, July 12, 1993 * further revise Mac windowing and extend to Think C (courtesy * Barton House) * fix confusing black/gray/white display on some MSDOS hardware * remove fatal bugs dealing with horns of plenty and VMS bones levels, * as well as more minor ones */ /* * Patch 2, June 1, 1993 * add tty windowing to Mac and Amiga ports and revise native windowing * allow direct screen I/O for MS-DOS versions instead of going through * termcap routines (courtesy Michael Allison and Kevin Smolkowski) * changes for NEC PC-9800 and various termcap.zip fixes by Yamamoto Keizo * SYSV 386 music driver ported to 386BSD (courtesy Andrew Chernov) and * SCO UNIX (courtesy Andreas Arens) * enhanced pickup and disclosure options * removed fatal bugs dealing with cursed bags of holding, renaming * shopkeepers, objects falling through trapdoors on deep levels, * and kicking embedded objects loose, and many more minor ones */ /* * Patch 1, February 25, 1993 * add Windows NT console port (courtesy Michael Allison) * polishing of Amiga, Mac, and X11 windowing * fixing many small bugs, including the infamous 3.0 nurse relmon bug */ /* * NetHack 3.1.0, January 25, 1993 * many, many changes and bugfixes -- some of the highlights include: * display rewrite using line-of-sight vision * general window interface, with the ability to use multiple interfaces * in the same executable * intelligent monsters * enhanced dungeon mythology * branching dungeons with more special levels, quest dungeons, and * multi-level endgame * more artifacts and more uses for artifacts * generalization to multiple shops with damage repair * X11 interface * ability to recover crashed games * full rewrite of Macintosh port * Amiga splitter * directory rearrangement (dat, doc, sys, win, util) */ /* Version 3.1 */ /*****************************************************************************/ /* Version 3.0 */ /* * Patch 10, February 5, 1991 * extend overlay manager to multiple files for easier binary distribution * allow for more system and compiler variance * remove more small insects */ /* * Patch 9, June 26, 1990 * clear up some confusing documentation * smooth some more rough edges in various ports * and fix a couple more bugs */ /* * Patch 8, June 3, 1990 * further debug and refine Macintosh port * refine the overlay manager, rearrange the OVLx breakdown for better * efficiency, rename the overlay macros, and split off the overlay * instructions to Install.ovl * introduce NEARDATA for better Amiga efficiency * support for more VMS versions (courtesy Joshua Delahunty and Pat Rankin) * more const fixes * better support for common graphics (DEC VT and IBM) * and a number of simple fixes and consistency extensions */ /* * Patch 7, February 19, 1990 * refine overlay support to handle portions of .c files through OVLx * (courtesy above plus Kevin Smolkowski) * update and extend Amiga port and documentation (courtesy Richard Addison, * Jochen Erwied, Mark Gooderum, Ken Lorber, Greg Olson, Mike Passaretti, * and Gregg Wonderly) * refine and extend Macintosh port and documentation (courtesy Johnny Lee, * Kevin Sitze, Michael Sokolov, Andy Swanson, Jon Watte, and Tom West) * refine VMS documentation * continuing ANSIfication, this time of const usage * teach '/' about differences within monster classes * smarter eating code (yet again), death messages, and treatment of * non-animal monsters, monster unconsciousness, and naming * extended version command to give compilation options * and the usual bug fixes and hole plugs */ /* * Patch 6, November 19, 1989 * add overlay support for MS-DOS (courtesy Pierre Martineau, Stephen * Spackman, and Norm Meluch) * refine Macintosh port * different door states show as different symbols (courtesy Ari Huttunen) * smarter drawbridges (courtesy Kevin Darcy) * add CLIPPING and split INFERNO off HARD * further refine eating code wrt picking up and resumption * make first few levels easier, by adding :x monsters and increasing initial * attribute points and hitting probability * teach '/' about configurable symbols */ /* * Patch 5, October 15, 1989 * add support for Macintosh OS (courtesy Johnny Lee) * fix annoying dependency loop via new color.h file * allow interruption while eating -- general handling of partially eaten food * smarter treatment of iron balls (courtesy Kevin Darcy) * a handful of other bug fixes */ /* * Patch 4, September 27, 1989 * add support for VMS (courtesy David Gentzel) * move monster-on-floor references into functions and implement the new * lookup structure for both objects and monsters * extend the definitions of objects and monsters to provide "living color" * in the dungeon, instead of a single monster color * ifdef varargs usage to satisfy ANSI compilers * standardize on the color 'gray' * assorted bug fixes */ /* * Patch 3, September 6, 1989 * add war hammers and revise object prices * extend prototypes to ANSI compilers in addition to the previous MSDOS ones * move object-on-floor references into functions in preparation for planned * data structures to allow faster access and better colors * fix some more bugs, and extend the portability of things added in earlier * patches */ /* * Patch 2, August 16, 1989 * add support for OS/2 (courtesy Timo Hakulinen) * add a better makefile for MicroSoft C (courtesy Paul Gyugyi) * more accomodation of compilers and preprocessors * add better screen-size sensing * expand color use for PCs and introduce it for SVR3 UNIX machines * extend '/' to multiple identifications * allow meta key to be used to invoke extended commands * fix various minor bugs, and do further code cleaning */ /* * Patch 1, July 31, 1989 * add support for Atari TOS (courtesy Eric Smith) and Andrew File System * (courtesy Ralf Brown) * include the uuencoded version of termcap.arc for the MSDOS versions that * was included with 2.2 and 2.3 * make a number of simple changes to accommodate various compilers * fix a handful of bugs, and do some code cleaning elsewhere * add more instructions for new environments and things commonly done wrong */ /* * NetHack 3.0 baseline release, July, 1989 */ /* Version 3.0 */ /*****************************************************************************/ /*patchlevel.h*/ nethack-3.4.3/include/pcconf.h0100644000000000000000000002163007764735041014720 0ustar rootroot/* SCCS Id: @(#)pcconf.h 3.4 1995/10/11 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef PCCONF_H #define PCCONF_H #define MICRO /* always define this! */ #ifdef MSDOS /* some of this material is MS-DOS specific */ /* * Automatic Defines: * * __GO32__ is defined automatically by the djgpp port of gcc. * __DJGPP__ is defined automatically by djgpp version 2 and above. * _MSC_VER is defined automatically by Microsoft C. * __BORLANDC__ is defined automatically by Borland C. * __SC__ is defined automatically by Symantec C. * Note: 3.4.1 was not verified with Symantec C. */ /* * The following options are somewhat configurable depending on * your compiler. */ /* * For pre-V7.0 Microsoft Compilers only, manually define OVERLAY here. */ /*#define OVERLAY */ /* Manual overlay definition (MSC 6.0ax only) */ # ifndef __GO32__ #define MFLOPPY /* Support for floppy drives and ramdisks by dgk */ # endif # define SHELL /* via exec of COMMAND.COM */ # ifdef __BORLANDC__ #define PCMUSIC /* Music option, enable very basic pc speaker music notes */ # endif /* * Screen control options * * You may uncomment: * ANSI_DEFAULT * or TERMLIB * or ANSI_DEFAULT and TERMLIB * or NO_TERMS */ /* # define TERMLIB */ /* enable use of termcap file /etc/termcap */ /* or ./termcap for MSDOS (SAC) */ /* compile and link in Fred Fish's termcap library, */ /* enclosed in TERMCAP.ARC, to use this */ /* # define ANSI_DEFAULT */ /* allows NetHack to run without a ./termcap */ # define NO_TERMS /* Allows Nethack to run without ansi.sys by linking */ /* screen routines into the .exe */ # ifdef NO_TERMS /* if NO_TERMS select one screen package below */ #define SCREEN_BIOS /* Use bios calls for all screen control */ /* #define SCREEN_DJGPPFAST */ /* Use djgpp fast screen routines */ # endif /* # define PC9800 */ /* Allows NetHack to run on NEC PC-9800 machines */ /* Yamamoto Keizo */ /* * PC video hardware support options (for graphical tile support) * * You may uncomment any/all of the options below. * */ # ifndef SUPPRESS_GRAPHICS # if (defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST)) && !defined(PC9800) # ifdef USE_TILES #define SCREEN_VGA /* Include VGA graphics routines in the build */ # endif # endif # else # undef NO_TERMS # undef SCREEN_BIOS # undef SCREEN_DJGPPFAST # undef SCREEN_VGA # undef TERMLIB # define ANSI_DEFAULT # endif # define RANDOM /* have Berkeley random(3) */ # define MAIL /* Allows for fake mail daemon to deliver mail */ /* in the MSDOS version. (For AMIGA MAIL see */ /* amiconf.h). In the future this will be the */ /* hook for mail reader implementation. */ /* The following is needed for prototypes of certain functions */ #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__SC__) #include /* Provides prototypes of exit(), spawn() */ #endif #if defined(__BORLANDC__) && defined(STRNCMPI) #include /* Provides prototypes of strncmpi(), etc. */ #endif #if defined(__DJGPP__) #define _NAIVE_DOS_REGS #include #include /* Provides prototypes of strncmpi(), etc. */ # ifndef M #define M(c) ((char) (0x80 | (c))) # endif #endif /* * On the VMS and unix, this option controls whether a delay is done by * the clock, or whether it is done by excess output. On the PC, however, * there is always a clock to use for the delay. The TIMED_DELAY option * on MSDOS (without the termcap routines) is used to determine whether to * include the delay routines in the code (and thus, provides a compile time * method to turn off napping for visual effect). However, it is also used * in the music code to wait between different notes. So it is needed in that * case as well. * Whereas on the VMS and unix, flags.nap is a run-time option controlling * whether there is a delay by clock or by excess output, on MSDOS it is * simply a flag to turn on or off napping for visual effects at run-time. */ #define TIMED_DELAY /* enable the `timed_delay' run-time option */ # ifdef PCMUSIC #define TIMED_DELAY /* need it anyway */ # endif #define NOCWD_ASSUMPTIONS /* Allow paths to be specified for HACKDIR, LEVELDIR, SAVEDIR, BONESDIR, DATADIR, SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR. */ #endif /* MSDOS configuration stuff */ #define PATHLEN 64 /* maximum pathlength */ #define FILENAME 80 /* maximum filename length (conservative) */ #ifndef MICRO_H #include "micro.h" /* contains necessary externs for [os_name].c */ #endif /* =================================================== * The remaining code shouldn't need modification. */ #ifndef SYSTEM_H #include "system.h" #endif #ifdef __DJGPP__ #include /* close(), etc. */ /* lock() in io.h interferes with lock[] in decl.h */ #define lock djlock #include #undef lock #include /* kbhit() */ #define PC_LOCKING #define HOLD_LOCKFILE_OPEN #define SELF_RECOVER /* NetHack itself can recover games */ #endif # ifdef MSDOS # ifndef EXEPATH #define EXEPATH /* HACKDIR is .exe location if not explicitly defined */ # endif # endif # if defined(_MSC_VER) && defined(MSDOS) # if (_MSC_VER >= 700) && !defined(FUNCTION_LEVEL_LINKING) # ifndef MOVERLAY #define MOVERLAY /* Microsoft's MOVE overlay system (MSC >= 7.0) */ # endif # endif #define PC_LOCKING # endif /* Borland Stuff */ # if defined(__BORLANDC__) # if defined(__OVERLAY__) && !defined(VROOMM) /* __OVERLAY__ is automatically defined by Borland C if overlay option is on */ #define VROOMM /* Borland's VROOMM overlay system */ # endif # if !defined(STKSIZ) #define STKSIZ 5*1024 /* Use a default of 5K stack for Borland C */ /* This macro is used in any file that contains */ /* a main() function. */ # endif #define PC_LOCKING # endif #ifdef PC_LOCKING #define HLOCK "NHPERM" #endif #ifndef index # define index strchr #endif #ifndef rindex # define rindex strrchr #endif #ifndef AMIGA #include #endif #ifdef RANDOM /* Use the high quality random number routines. */ # define Rand() random() #else # define Rand() rand() #endif #ifndef TOS # define FCMASK 0660 /* file creation mask */ #endif #include #ifndef REDO # undef Getchar # define Getchar nhgetch #endif #ifdef MSDOS # define TEXTCOLOR /* */ # define PORT_HELP "msdoshlp.txt" /* msdos port specific help file */ #endif /* Sanity check, do not modify these blocks. */ /* OVERLAY must be defined with MOVERLAY or VROOMM */ #if (defined(MOVERLAY) || defined(VROOMM)) # ifndef OVERLAY # define OVERLAY # endif #endif #if defined(FUNCTION_LEVEL_LINKING) #define OVERLAY #define OVL0 #define OVL1 #define OVL2 #define OVL3 #define OVLB #endif #if defined(OVERLAY) && !defined(MOVERLAY) && !defined(VROOMM) && !defined(FUNCTION_LEVEL_LINKING) #define USE_TRAMPOLI #endif #if defined(MSDOS) && defined(NO_TERMS) # ifdef TERMLIB # if defined(_MSC_VER) || defined(__SC__) # pragma message("Warning -- TERMLIB defined with NO_TERMS in pcconf.h") # pragma message(" Forcing undef of TERMLIB") # endif #undef TERMLIB # endif # ifdef ANSI_DEFAULT # if defined(_MSC_VER) || defined(__SC__) # pragma message("Warning -- ANSI_DEFAULT defined with NO_TERMS in pcconf.h") # pragma message(" Forcing undef of ANSI_DEFAULT") # endif #undef ANSI_DEFAULT # endif /* only one screen package is allowed */ # if defined(SCREEN_BIOS) && defined(SCREEN_DJGPPFAST) # if defined(_MSC_VER) || defined(__SC__) # pragma message("Warning -- More than one screen package defined in pcconf.h") # endif # if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__SC__) # if defined(SCREEN_DJGPPFAST) # if defined(_MSC_VER) || defined(__SC__) # pragma message(" Forcing undef of SCREEN_DJGPPFAST") # endif #undef SCREEN_DJGPPFAST /* Can't use djgpp fast with other compilers anyway */ # endif # else /* djgpp C compiler */ # if defined(SCREEN_BIOS) #undef SCREEN_BIOS # endif # endif # endif # define ASCIIGRAPH # ifdef TEXTCOLOR # define VIDEOSHADES # endif /* SCREEN_8514, SCREEN_VESA are only placeholders presently - sub VGA instead */ # if defined(SCREEN_8514) || defined(SCREEN_VESA) # undef SCREEN_8514 # undef SCREEN_VESA # define SCREEN_VGA # endif /* Graphical tile sanity checks */ # ifdef SCREEN_VGA # define SIMULATE_CURSOR # define POSITIONBAR /* Select appropriate tile file format, and map size */ # define PLANAR_FILE # define SMALL_MAP # endif #endif /* End of sanity check block */ #if defined(MSDOS) && defined(DLB) #define FILENAME_CMP stricmp /* case insensitive */ #endif #ifdef MSC7_WARN /* define with cl /DMSC7_WARN */ #pragma warning(disable:4131) #endif #ifdef TIMED_DELAY # ifdef __DJGPP__ # define msleep(k) (void) usleep((k)*1000) # endif # ifdef __BORLANDC__ # define msleep(k) delay(k) # endif # ifdef __SC__ # define msleep(k) (void) usleep((long)((k)*1000)) # endif #endif #endif /* PCCONF_H */ nethack-3.4.3/include/permonst.h0100644000000000000000000000467507764735041015331 0ustar rootroot/* SCCS Id: @(#)permonst.h 3.4 1999/07/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef PERMONST_H #define PERMONST_H /* This structure covers all attack forms. * aatyp is the gross attack type (eg. claw, bite, breath, ...) * adtyp is the damage type (eg. physical, fire, cold, spell, ...) * damn is the number of hit dice of damage from the attack. * damd is the number of sides on each die. * * Some attacks can do no points of damage. Additionally, some can * have special effects *and* do damage as well. If damn and damd * are set, they may have a special meaning. For example, if set * for a blinding attack, they determine the amount of time blinded. */ struct attack { uchar aatyp; uchar adtyp, damn, damd; }; /* Max # of attacks for any given monster. */ #define NATTK 6 /* Weight of a human body */ #define WT_HUMAN 1450 #ifndef ALIGN_H #include "align.h" #endif #include "monattk.h" #include "monflag.h" struct permonst { const char *mname; /* full name */ char mlet; /* symbol */ schar mlevel, /* base monster level */ mmove, /* move speed */ ac, /* (base) armor class */ mr; /* (base) magic resistance */ aligntyp maligntyp; /* basic monster alignment */ unsigned short geno; /* creation/geno mask value */ struct attack mattk[NATTK]; /* attacks matrix */ unsigned short cwt, /* weight of corpse */ cnutrit; /* its nutritional value */ short pxlth; /* length of extension */ uchar msound; /* noise it makes (6 bits) */ uchar msize; /* physical size (3 bits) */ uchar mresists; /* resistances */ uchar mconveys; /* conveyed by eating */ unsigned long mflags1, /* boolean bitflags */ mflags2; /* more boolean bitflags */ unsigned short mflags3; /* yet more boolean bitflags */ # ifdef TEXTCOLOR uchar mcolor; /* color to use */ # endif }; extern NEARDATA struct permonst mons[]; /* the master list of monster types */ #define VERY_SLOW 3 #define SLOW_SPEED 9 #define NORMAL_SPEED 12 /* movement rates */ #define FAST_SPEED 15 #define VERY_FAST 24 #define NON_PM PM_PLAYERMON /* "not a monster" */ #define LOW_PM (NON_PM+1) /* first monster in mons[] */ #define SPECIAL_PM PM_LONG_WORM_TAIL /* [normal] < ~ < [special] */ /* mons[SPECIAL_PM] through mons[NUMMONS-1], inclusive, are never generated randomly and cannot be polymorphed into */ #endif /* PERMONST_H */ nethack-3.4.3/include/prop.h0100644000000000000000000001064007764735041014427 0ustar rootroot/* SCCS Id: @(#)prop.h 3.4 1999/07/07 */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #ifndef PROP_H #define PROP_H /*** What the properties are ***/ #define FIRE_RES 1 #define COLD_RES 2 #define SLEEP_RES 3 #define DISINT_RES 4 #define SHOCK_RES 5 #define POISON_RES 6 #define ACID_RES 7 #define STONE_RES 8 /* note: for the first eight properties, MR_xxx == (1 << (xxx_RES - 1)) */ #define ADORNED 9 #define REGENERATION 10 #define SEARCHING 11 #define SEE_INVIS 12 #define INVIS 13 #define TELEPORT 14 #define TELEPORT_CONTROL 15 #define POLYMORPH 16 #define POLYMORPH_CONTROL 17 #define LEVITATION 18 #define STEALTH 19 #define AGGRAVATE_MONSTER 20 #define CONFLICT 21 #define PROTECTION 22 #define PROT_FROM_SHAPE_CHANGERS 23 #define WARNING 24 #define TELEPAT 25 #define FAST 26 #define STUNNED 27 #define CONFUSION 28 #define SICK 29 #define BLINDED 30 #define SLEEPING 31 #define WOUNDED_LEGS 32 #define STONED 33 #define STRANGLED 34 #define HALLUC 35 #define HALLUC_RES 36 #define FUMBLING 37 #define JUMPING 38 #define WWALKING 39 #define HUNGER 40 #define GLIB 41 #define REFLECTING 42 #define LIFESAVED 43 #define ANTIMAGIC 44 #define DISPLACED 45 #define CLAIRVOYANT 46 #define VOMITING 47 #define ENERGY_REGENERATION 48 #define MAGICAL_BREATHING 49 #define HALF_SPDAM 50 #define HALF_PHDAM 51 #define SICK_RES 52 #define DRAIN_RES 53 #define WARN_UNDEAD 54 #define INVULNERABLE 55 #define FREE_ACTION 56 #define SWIMMING 57 #define SLIMED 58 #define FIXED_ABIL 59 #define FLYING 60 #define UNCHANGING 61 #define PASSES_WALLS 62 #define SLOW_DIGESTION 63 #define INFRAVISION 64 #define WARN_OF_MON 65 #define DETECT_MONSTERS 66 #define LAST_PROP (DETECT_MONSTERS) /*** Where the properties come from ***/ /* Definitions were moved here from obj.h and you.h */ struct prop { /*** Properties conveyed by objects ***/ long extrinsic; /* Armor */ # define W_ARM 0x00000001L /* Body armor */ # define W_ARMC 0x00000002L /* Cloak */ # define W_ARMH 0x00000004L /* Helmet/hat */ # define W_ARMS 0x00000008L /* Shield */ # define W_ARMG 0x00000010L /* Gloves/gauntlets */ # define W_ARMF 0x00000020L /* Footwear */ #ifdef TOURIST # define W_ARMU 0x00000040L /* Undershirt */ # define W_ARMOR (W_ARM | W_ARMC | W_ARMH | W_ARMS | W_ARMG | W_ARMF | W_ARMU) #else # define W_ARMOR (W_ARM | W_ARMC | W_ARMH | W_ARMS | W_ARMG | W_ARMF) #endif /* Weapons and artifacts */ # define W_WEP 0x00000100L /* Wielded weapon */ # define W_QUIVER 0x00000200L /* Quiver for (f)iring ammo */ # define W_SWAPWEP 0x00000400L /* Secondary weapon */ # define W_ART 0x00001000L /* Carrying artifact (not really worn) */ # define W_ARTI 0x00002000L /* Invoked artifact (not really worn) */ /* Amulets, rings, tools, and other items */ # define W_AMUL 0x00010000L /* Amulet */ # define W_RINGL 0x00020000L /* Left ring */ # define W_RINGR 0x00040000L /* Right ring */ # define W_RING (W_RINGL | W_RINGR) # define W_TOOL 0x00080000L /* Eyewear */ #ifdef STEED # define W_SADDLE 0x00100000L /* KMH -- For riding monsters */ #endif # define W_BALL 0x00200000L /* Punishment ball */ # define W_CHAIN 0x00400000L /* Punishment chain */ /*** Property is blocked by an object ***/ long blocked; /* Same assignments as extrinsic */ /*** Timeouts, permanent properties, and other flags ***/ long intrinsic; /* Timed properties */ # define TIMEOUT 0x00ffffffL /* Up to 16 million turns */ /* Permanent properties */ # define FROMEXPER 0x01000000L /* Gain/lose with experience, for role */ # define FROMRACE 0x02000000L /* Gain/lose with experience, for race */ # define FROMOUTSIDE 0x04000000L /* By corpses, prayer, thrones, etc. */ # define INTRINSIC (FROMOUTSIDE|FROMRACE|FROMEXPER) /* Control flags */ # define I_SPECIAL 0x10000000L /* Property is controllable */ }; /*** Definitions for backwards compatibility ***/ #define LEFT_RING W_RINGL #define RIGHT_RING W_RINGR #define LEFT_SIDE LEFT_RING #define RIGHT_SIDE RIGHT_RING #define BOTH_SIDES (LEFT_SIDE | RIGHT_SIDE) #define WORN_ARMOR W_ARM #define WORN_CLOAK W_ARMC #define WORN_HELMET W_ARMH #define WORN_SHIELD W_ARMS #define WORN_GLOVES W_ARMG #define WORN_BOOTS W_ARMF #define WORN_AMUL W_AMUL #define WORN_BLINDF W_TOOL #ifdef TOURIST #define WORN_SHIRT W_ARMU #endif #endif /* PROP_H */ nethack-3.4.3/include/qt_clust.h0100644000000000000000000000107007764735041015302 0ustar rootroot/* SCCS Id: @(#)qt_clust.h 3.4 1999/11/19 */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef clusterizer_H #define clusterizer_H #include class Clusterizer { public: Clusterizer(int maxclusters); ~Clusterizer(); void add(int x, int y); // 1x1 rectangle (point) void add(int x, int y, int w, int h); void add(const QRect& rect); void clear(); int clusters() { return count; } const QRect& operator[](int i); private: QRect* cluster; int count; const int max; }; #endif nethack-3.4.3/include/qt_kde0.h0100644000000000000000000000041507764735041014775 0ustar rootroot/* SCCS Id: @(#)qt_kde0.h 3.4 1999/11/19 */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef QT_DUMMYKDE #define QT_DUMMYKDE class KTopLevelWidget : public QMainWindow { Q_OBJECT }; #endif nethack-3.4.3/include/qt_win.h0100644000000000000000000004306107764735041014753 0ustar rootroot// SCCS Id: @(#)qt_win.h 3.4 1999/11/19 // Copyright (c) Warwick Allison, 1999. // NetHack may be freely redistributed. See license for details. // // Qt Binding for NetHack 3.4 // // Unfortunately, this doesn't use Qt as well as I would like, // primarily because NetHack is fundamentally a getkey-type // program rather than being event driven (hence the ugly key // and click buffer rather), but also because this is my first // major application of Qt. // #ifndef qt_win_h #define qt_win_h #define QT_CLEAN_NAMESPACE #include #include #include #include #include #if defined(QWS) #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include #if QT_VERSION >= 300 #include // Should stop using QTableView #define QTableView QtTableView #else #include #endif #include #include #ifdef KDE #include #include #endif #include "qt_clust.h" class QVBox; class QMenuBar; class QRadioButton; class NhPSListView; ////////////////////////////////////////////////////////////// // // The beautiful, abstracted and well-modelled classes... // ////////////////////////////////////////////////////////////// class NetHackQtGlyphs; class NetHackQtLineEdit : public QLineEdit { public: NetHackQtLineEdit(); NetHackQtLineEdit(QWidget* parent, const char* name); void fakeEvent(int key, int ascii, int state); }; class NetHackQtSettings : public QDialog { Q_OBJECT public: // Size of window - used to decide default sizes NetHackQtSettings(int width, int height); NetHackQtGlyphs& glyphs(); const QFont& normalFont(); const QFont& normalFixedFont(); const QFont& largeFont(); bool ynInMessages(); signals: void fontChanged(); void tilesChanged(); public slots: void toggleGlyphSize(); void setGlyphSize(bool); private: QSpinBox tilewidth; QSpinBox tileheight; QLabel widthlbl; QLabel heightlbl; QCheckBox whichsize; QSize othersize; QComboBox fontsize; QFont normal, normalfixed, large; NetHackQtGlyphs* theglyphs; private slots: void resizeTiles(); }; class NetHackQtKeyBuffer { public: NetHackQtKeyBuffer(); bool Empty() const; bool Full() const; void Put(int k, int ascii, int state); void Put(char a); void Put(const char* str); int GetKey(); int GetAscii(); int GetState(); int TopKey() const; int TopAscii() const; int TopState() const; private: enum { maxkey=64 }; int key[maxkey]; int ascii[maxkey]; int state[maxkey]; int in,out; }; class NetHackQtClickBuffer { public: NetHackQtClickBuffer(); bool Empty() const; bool Full() const; void Put(int x, int y, int mod); int NextX() const; int NextY() const; int NextMod() const; void Get(); private: enum { maxclick=64 }; struct ClickRec { int x,y,mod; } click[maxclick]; int in,out; }; class NetHackQtSavedGameSelector : public QDialog { public: NetHackQtSavedGameSelector(const char** saved); int choose(); }; class NetHackQtPlayerSelector : private QDialog { Q_OBJECT public: enum { R_None=-1, R_Quit=-2, R_Rand=-3 }; NetHackQtPlayerSelector(NetHackQtKeyBuffer&); protected: virtual void done(int); public slots: void Quit(); void Random(); void selectName(const QString& n); void selectRole(); void selectRace(); void setupOthers(); void selectGender(int); void selectAlignment(int); public: bool Choose(); private: NetHackQtKeyBuffer& keysource; NhPSListView* role; NhPSListView* race; QRadioButton **gender; QRadioButton **alignment; bool fully_specified_role; }; class NetHackQtStringRequestor : QDialog { private: QLabel prompt; NetHackQtLineEdit input; QPushButton* okay; QPushButton* cancel; NetHackQtKeyBuffer& keysource; virtual void done(int); public: NetHackQtStringRequestor(NetHackQtKeyBuffer&, const char* p,const char* cancelstr="Cancel"); void SetDefault(const char*); bool Get(char* buffer, int maxchar=80); virtual void resizeEvent(QResizeEvent*); }; class NetHackQtExtCmdRequestor : public QDialog { Q_OBJECT NetHackQtKeyBuffer& keysource; public: NetHackQtExtCmdRequestor(NetHackQtKeyBuffer& ks); int get(); private slots: void cancel(); void done(int i); }; class NetHackQtWindow { public: NetHackQtWindow(); virtual ~NetHackQtWindow(); virtual QWidget* Widget() =0; virtual void Clear(); virtual void Display(bool block); virtual bool Destroy(); virtual void CursorTo(int x,int y); virtual void PutStr(int attr, const char* text); virtual void StartMenu(); virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel); virtual void EndMenu(const char* prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); virtual void ClipAround(int x,int y); virtual void PrintGlyph(int x,int y,int glyph); virtual void UseRIP(int how); int nhid; }; class NetHackQtGlyphs { public: NetHackQtGlyphs(); int width() const { return size.width(); } int height() const { return size.height(); } void toggleSize(); void setSize(int w, int h); void drawGlyph(QPainter&, int glyph, int pixelx, int pixely); void drawCell(QPainter&, int glyph, int cellx, int celly); private: QImage img; QPixmap pm,pm1, pm2; QSize size; int tiles_per_row; }; class BlackScrollView : public QScrollView { public: BlackScrollView() { viewport()->setBackgroundColor(black); } }; class NetHackQtMapWindow : public QWidget, public NetHackQtWindow { Q_OBJECT private: NetHackQtClickBuffer& clicksink; unsigned short glyph[ROWNO][COLNO]; unsigned short& Glyph(int x, int y) { return glyph[y][x]; } QPoint cursor; BlackScrollView viewport; QPixmap pet_annotation; Clusterizer change; QFont *rogue_font; QString messages; QRect messages_rect; void Changed(int x,int y); signals: void resized(); private slots: void updateTiles(); void moveMessages(int x, int y); protected: virtual void paintEvent(QPaintEvent*); virtual void mousePressEvent(QMouseEvent*); public: NetHackQtMapWindow(NetHackQtClickBuffer& click_sink); ~NetHackQtMapWindow(); virtual QWidget* Widget(); virtual bool Destroy(); virtual void Clear(); virtual void Display(bool block); virtual void CursorTo(int x,int y); virtual void PutStr(int attr, const char* text); virtual void ClipAround(int x,int y); virtual void PrintGlyph(int x,int y,int glyph); void Scroll(int dx, int dy); // For messages void displayMessages(bool block); void putMessage(int attr, const char* text); void clearMessages(); void clickCursor(); }; class NetHackQtScrollText; class NetHackQtMessageWindow : QObject, public NetHackQtWindow { Q_OBJECT public: NetHackQtMessageWindow(); ~NetHackQtMessageWindow(); virtual QWidget* Widget(); virtual void Clear(); virtual void Display(bool block); virtual void PutStr(int attr, const char* text); void Scroll(int dx, int dy); void setMap(NetHackQtMapWindow*); private: NetHackQtScrollText* list; bool changed; NetHackQtMapWindow* map; private slots: void updateFont(); }; class NetHackQtLabelledIcon : public QWidget { public: NetHackQtLabelledIcon(QWidget* parent, const char* label); NetHackQtLabelledIcon(QWidget* parent, const char* label, const QPixmap& icon); enum { NoNum=-99999 }; void setLabel(const char*, bool lower=TRUE); // a string void setLabel(const char*, long, const char* tail=""); // a number void setLabel(const char*, long show_value, long comparative_value, const char* tail=""); void setIcon(const QPixmap&); virtual void setFont(const QFont&); void highlightWhenChanging(); void lowIsGood(); void dissipateHighlight(); virtual void show(); protected: void resizeEvent(QResizeEvent*); private: void initHighlight(); void setAlignments(); void highlight(const QPalette& highlight); void unhighlight(); bool low_is_good; int prev_value; int turn_count; /* last time the value changed */ QPalette hl_good; QPalette hl_bad; QLabel* label; QLabel* icon; }; class NetHackQtStatusWindow : QWidget, public NetHackQtWindow { Q_OBJECT public: NetHackQtStatusWindow(); virtual QWidget* Widget(); virtual void Clear(); virtual void Display(bool block); virtual void CursorTo(int x,int y); virtual void PutStr(int attr, const char* text); void fadeHighlighting(); protected: void resizeEvent(QResizeEvent*); private slots: void doUpdate(); private: enum { hilight_time=1 }; QPixmap p_str; QPixmap p_dex; QPixmap p_con; QPixmap p_int; QPixmap p_wis; QPixmap p_cha; QPixmap p_chaotic; QPixmap p_neutral; QPixmap p_lawful; QPixmap p_satiated; QPixmap p_hungry; QPixmap p_confused; QPixmap p_sick_fp; QPixmap p_sick_il; QPixmap p_blind; QPixmap p_stunned; QPixmap p_hallu; QPixmap p_encumber[5]; NetHackQtLabelledIcon name; NetHackQtLabelledIcon dlevel; NetHackQtLabelledIcon str; NetHackQtLabelledIcon dex; NetHackQtLabelledIcon con; NetHackQtLabelledIcon intel; NetHackQtLabelledIcon wis; NetHackQtLabelledIcon cha; NetHackQtLabelledIcon gold; NetHackQtLabelledIcon hp; NetHackQtLabelledIcon power; NetHackQtLabelledIcon ac; NetHackQtLabelledIcon level; NetHackQtLabelledIcon exp; NetHackQtLabelledIcon align; NetHackQtLabelledIcon time; NetHackQtLabelledIcon score; NetHackQtLabelledIcon hunger; NetHackQtLabelledIcon confused; NetHackQtLabelledIcon sick_fp; NetHackQtLabelledIcon sick_il; NetHackQtLabelledIcon blind; NetHackQtLabelledIcon stunned; NetHackQtLabelledIcon hallu; NetHackQtLabelledIcon encumber; QFrame hline1; QFrame hline2; QFrame hline3; int cursy; bool first_set; void nullOut(); void updateStats(); void checkTurnEvents(); }; class NetHackQtMenuDialog : public QDialog { Q_OBJECT public: NetHackQtMenuDialog(); void Accept(); void Reject(); void SetResult(int); virtual void done(int); protected: void resizeEvent(QResizeEvent*); signals: void Resized(); }; class NetHackQtMenuWindow : public QTableView, public NetHackQtWindow { Q_OBJECT public: NetHackQtMenuWindow(NetHackQtKeyBuffer&); ~NetHackQtMenuWindow(); virtual QWidget* Widget(); virtual void StartMenu(); virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel); virtual void EndMenu(const char* prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); public slots: void All(); void ChooseNone(); void Invert(); void Search(); void Layout(); void ToggleSelect(int); protected: virtual void keyPressEvent(QKeyEvent*); //virtual void mouseDoubleClickEvent(QMouseEvent*); virtual void mousePressEvent(QMouseEvent*); virtual void mouseReleaseEvent(QMouseEvent*); virtual void mouseMoveEvent(QMouseEvent*); virtual void focusOutEvent(QFocusEvent*); virtual void focusInEvent(QFocusEvent*); virtual void paintCell(QPainter*, int, int); virtual int cellWidth(int col); private: struct MenuItem { MenuItem(); ~MenuItem(); int glyph; ANY_P identifier; int attr; const char* str; int count; char ch; bool selected; bool Selectable() const { return identifier.a_void!=0; } }; QArray item; int itemcount; int str_width; bool str_fixed; int next_accel; NetHackQtKeyBuffer& keysource; NetHackQtMenuDialog* dialog; QPushButton* ok; QPushButton* cancel; QPushButton* all; QPushButton* none; QPushButton* invert; QPushButton* search; QLabel prompt; int how; bool has_glyphs; int pressed; bool was_sel; }; class NetHackQtTextListBox; class NetHackQtRIP : public QWidget { private: static QPixmap* pixmap; char** line; int riplines; public: NetHackQtRIP(QWidget* parent); void setLines(char** l, int n); protected: virtual void paintEvent(QPaintEvent* event); QSize sizeHint() const; }; class NetHackQtTextWindow : public QDialog, public NetHackQtWindow { Q_OBJECT public: NetHackQtTextWindow(NetHackQtKeyBuffer&); ~NetHackQtTextWindow(); virtual QWidget* Widget(); virtual void Clear(); virtual bool Destroy(); virtual void Display(bool block); virtual void PutStr(int attr, const char* text); virtual void UseRIP(int how); public slots: void Search(); protected: virtual void done(int); virtual void keyPressEvent(QKeyEvent*); private slots: void doUpdate(); private: NetHackQtKeyBuffer& keysource; bool use_rip; bool str_fixed; QPushButton ok; QPushButton search; NetHackQtTextListBox* lines; NetHackQtRIP rip; }; class NetHackQtMenuOrTextWindow : public NetHackQtWindow { private: NetHackQtWindow* actual; NetHackQtKeyBuffer& keysource; public: NetHackQtMenuOrTextWindow(NetHackQtKeyBuffer&); virtual QWidget* Widget(); // Text virtual void Clear(); virtual bool Destroy(); virtual void Display(bool block); virtual void PutStr(int attr, const char* text); // Menu virtual void StartMenu(); virtual void AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel); virtual void EndMenu(const char* prompt); virtual int SelectMenu(int how, MENU_ITEM_P **menu_list); }; class NetHackQtDelay : QObject { private: int msec; public: NetHackQtDelay(int ms); void wait(); virtual void timerEvent(QTimerEvent* timer); }; class NetHackQtInvUsageWindow : public QWidget { public: NetHackQtInvUsageWindow(QWidget* parent); virtual void paintEvent(QPaintEvent*); private: void drawWorn(QPainter& painter, obj*, int x, int y, bool canbe=TRUE); }; // This class is the main widget for NetHack // // It is a collection of Message, Map, and Status windows. In the current // version of nethack there is only one of each, and this class makes this // assumption, not showing itself until all are inserted. // // This class simply knows how to layout such children sensibly. // // Since it is only responsible for layout, the class does not // note the actual class of the windows. // #ifndef KDE #include "qt_kde0.h" #endif class NetHackQtMainWindow : public KTopLevelWidget { Q_OBJECT public: NetHackQtMainWindow(NetHackQtKeyBuffer&); void AddMessageWindow(NetHackQtMessageWindow* window); void AddMapWindow(NetHackQtMapWindow* window); void AddStatusWindow(NetHackQtStatusWindow* window); void RemoveWindow(NetHackQtWindow* window); void updateInventory(); void fadeHighlighting(); public slots: void doMenuItem(int); void doKeys(const QString&); protected: virtual void resizeEvent(QResizeEvent*); virtual void keyPressEvent(QKeyEvent*); virtual void keyReleaseEvent(QKeyEvent* event); virtual void closeEvent(QCloseEvent*); private slots: void layout(); void raiseMap(); void zoomMap(); void raiseMessages(); void raiseStatus(); private: void ShowIfReady(); #ifdef KDE KMenuBar* menubar; #else QMenuBar* menubar; #endif NetHackQtMessageWindow* message; NetHackQtMapWindow* map; NetHackQtStatusWindow* status; NetHackQtInvUsageWindow* invusage; NetHackQtKeyBuffer& keysink; QWidgetStack* stack; int dirkey; const char* *macro; }; class NetHackQtYnDialog : QDialog { Q_OBJECT private: const char* question; const char* choices; char def; NetHackQtKeyBuffer& keysource; protected: virtual void keyPressEvent(QKeyEvent*); virtual void done(int); private slots: void doneItem(int); public: NetHackQtYnDialog(NetHackQtKeyBuffer& keysource,const char*,const char*,char); char Exec(); }; #ifdef KDE #define NetHackQtBindBase KApplication #elif defined(QWS) #define NetHackQtBindBase QPEApplication #else #define NetHackQtBindBase QApplication #endif class NetHackQtBind : NetHackQtBindBase { private: // Single-instance preservation... NetHackQtBind(int& argc, char** argv); static NetHackQtBind* instance; static NetHackQtKeyBuffer keybuffer; static NetHackQtClickBuffer clickbuffer; static QWidget* splash; static NetHackQtMainWindow* main; public: static void qt_init_nhwindows(int* argc, char** argv); static void qt_player_selection(); static void qt_askname(); static void qt_get_nh_event(); static void qt_exit_nhwindows(const char *); static void qt_suspend_nhwindows(const char *); static void qt_resume_nhwindows(); static winid qt_create_nhwindow(int type); static void qt_clear_nhwindow(winid wid); static void qt_display_nhwindow(winid wid, BOOLEAN_P block); static void qt_destroy_nhwindow(winid wid); static void qt_curs(winid wid, int x, int y); static void qt_putstr(winid wid, int attr, const char *text); static void qt_display_file(const char *filename, BOOLEAN_P must_exist); static void qt_start_menu(winid wid); static void qt_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr, const char *str, BOOLEAN_P presel); static void qt_end_menu(winid wid, const char *prompt); static int qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list); static void qt_update_inventory(); static void qt_mark_synch(); static void qt_wait_synch(); static void qt_cliparound(int x, int y); static void qt_cliparound_window(winid wid, int x, int y); static void qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph); static void qt_raw_print(const char *str); static void qt_raw_print_bold(const char *str); static int qt_nhgetch(); static int qt_nh_poskey(int *x, int *y, int *mod); static void qt_nhbell(); static int qt_doprev_message(); static char qt_yn_function(const char *question, const char *choices, CHAR_P def); static void qt_getlin(const char *prompt, char *line); static int qt_get_ext_cmd(); static void qt_number_pad(int); static void qt_delay_output(); static void qt_start_screen(); static void qt_end_screen(); static void qt_outrip(winid wid, int how); static int qt_kbhit(); private: virtual bool notify(QObject *receiver, QEvent *event); }; #endif nethack-3.4.3/include/qt_xpms.h0100644000000000000000000013401107764735041015141 0ustar rootroot/* XPM */ static const char *blind_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 5 1", /* colors */ " c #000000", ". c None", "X c #909090", "o c #606060", "O c #303030", /* pixels */ "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "....ooooooooooooooooooooooooooooooooX...", ".... o...", ".... o...", ".... o...", ".... o...", "......o ..o ......", "......X O..X O......", "....... o... o......", ".......o ....o .......", "........O X.....O X.......", ".........O X.......O X........", "..........o OX.........o OX.........", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................" }; /* XPM */ static const char *cha_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ " c #F85848", ". c #949E9E", "X c #F8B090", "o c #E00028", "O c #D4D4D4", "+ c None", "@ c #B0B0B0", "# c #F82C24", "$ c #F89E6C", "% c #FF0000", "& c #909090", "* c #FFFFFF", "= c #CEAA90", "- c #DADAB6", /* pixels */ "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "+++++++++++++++=#%#=+=#%% ++++++++++++++", "++++++++++++++ %O%%%#%$$%o%=++++++++++++", "+++++++++++++# +#%%o%%o%%%%% +++++++++++", "+++++++++++ %%%%%%%%%%%%%%%%o#=+++++++++", "+++++++++ o%%%%%%%%%%%%%%%%%%%%# +++++++", "++++++ #%%%%%%o%%%o%%o%%o%o%%%%%o%o +++", "++=#%%o%%%#= =*+**O*+**O*+- = =%%%%#@+++", "++++ %=++*+*+**O****O****O*O*O*OO%=+++++", "+++++.%=OO+*O*OO****+****+*O*+O&%=@+++++", "++++++=%=*OO+**O**O*O**O*O*OO+$%=+++++++", "+++++++#% +*OOOO****+****@O+*#%=++++++++", "++++++++#%#*+**+O+OO+O+OOO*O#o#+++++++++", "+++++++++o% O**+****O****O*#%%=+++++++++", "+++++++++ %%#O*O****+****+ %o#++++++++++", "++++++++++o%% XO*O**O*O**#%%%+++++++++++", "++++++++++ %%%o%$-**+**$%%%%=+++++++++++", "+++++++++++o%%$X$%%%%%%#= o#++++++++++++", "++++++++++@ %%%o#O$$+$$$%%%=++++++++++++", "++++++++++++#o%%%%%%%%o%%%=@++++++++++++", "+++++++++++++ %%%%%%%%%%o=++++++++++++++", "+++++++++++++++= & & @++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ static const char *chaotic_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 9 1", /* colors */ " c #000000", ". c #5C7A7A", "X c None", "o c #B0B0B0", "O c #909090", "+ c #788C8C", "@ c #606060", "# c #FFFFFF", "$ c #303030", /* pixels */ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXX@$ @XXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXX$$+#X$ $XXXXXXXXXX", "XXXXXXXXXXXXXXXXXX@$#o @XXXXXXXXX", "XXXXXXXXXXXXXXXXXX$XX OXXXXXXXX", "XXXXXXXXXXXXXXXXX@ # $@$ $XXXXXXXX", "XXXXXXXXXXXXXXXXX@.+ $XXXO @XXXXXXX", "XXXXXXXXXXXXXXXXX O@ XXXXX@ @XXXXXXX", "XXXXXXXXXXXXXXXXX @O $XXXXX@$ @XXXXXXX", "XXXXXXXXXXXXXXXXX O+ @XXXXO++ @XXXXXXX", "XXXXXXXXXXXXXXXXX @+ $@OXO$#$ XXXXXXXX", "XXXXXXXXXXXXXXXXX O@ $ @$Xo $XXXXXXXX", "XXXXXXXXXXXXXXXXX +O $X##+ $XXXXXXXXX", "XXXXXXXXXXXXXXXXX +@ $XXXXXXXXXX", "XXXXXXXXXXXXXXXXX oO $XXXXXXXXXXX", "XXXXXXXXO@@@@@ +# $XXXXXXXXXXXX", "XXXXXXO +o########$ $@XXXXXXXXX", "XXXXXX +#+.$XXXXXXXX", "XXXXXX @O @XXXXXXX", "XXXXXX$ $@ $@@$ @XXXXXXX", "XXXXXXX@@@@XXXXXX + @XXXX@$ OXXXXXXX", "XXXXXXXXXXXXXXXX@ # @XXXXXXX@@OXXXXXXXX", "XXXXXXXXXXXXXXXX@.+ @XXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX$O@ XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX @O XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX #$ @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@ # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@ # OXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@.X XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX ++ XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX @+ XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX O@ @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX +O @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX$ OXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX@@OXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }; /* XPM */ static const char *cns_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ " c #000000", ". c #F85848", "X c #949E9E", "o c #F8B090", "O c #E00028", "+ c #7C3400", "@ c None", "# c #B0B0B0", "$ c #F82C24", "% c #F89E6C", "& c #FF0000", "* c #B64700", "= c #909090", "- c #788C8C", "; c #606060", ": c #C80050", "> c #CEAA90", ", c #303030", "< c #FFB691", /* pixels */ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@.oo.o$ ;@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@>.o.%%O,@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@$oo.o. ,@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@.oo$oo+ =@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@..o&oo$ ,@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@#.o.oo. =@.$%@@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o..oo& O.%ooo@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o.&%o.$oo%O++;@@@@@@@@@@@@", "@@@@@@@@@@@@@.o.+$%$o.@@@@@@@@@@@", "@@@@@@@@@@@@@.oo++o%$$ ,@@$.oo@@@@@@@@@@", "@@@@@@@@@@@@>.oo+Oo$o%.@@$oo..-@@@@@@@@@", "@@@@@@@@@@@@..o%;.o&%.$..o%O ++>@@@@@@@@", "@@@@@@@@@@@@>.$O:%o.O::::O* $oooo@@@@@@@", "@@@@@@@@@@@@::::::$$:OO&OO::oo%.;=@@@@@@", "@@@@@@@@@@@.::::::::O&&&&&O::++ ,@@@@@@", "@@@@@@@@@@>:::O&&OO&&&&&&&&:: ;@@@@@", "@@@@@@@@@@=::O&&&&&O:O&&&&&O: ,=@@@@@@@", "@@@@@@@@@@:::&&&&&&&&:&&&&&O: ;@@@@@@@@", "@@@@@@@@@@::O&&&&&&&&:&O&&&O:, ;@@@@@@@@", "@@@@@@@@@@::O&&&&O&O&OO&O&&O:+ ;@@@@@@@@", "@@@@@@@@@@::&&&O&&&&&O:&&&&O:, @@@@@@@@", "@@@@@@@@@@::O&&&&&O&&&:O&O&::+ @@@@@@@@", "@@@@@@@@@@::O&&O&&&&O&OO&&&:: @@@@@@@@", "@@@@@@@@@@=::O&&&&O&&&O:&&&:: @@@@@@@@", "@@@@@@@@@@.:::O&&O&&&&&:&OO:: @@@@@@@@", "@@@@@@@@@@@:::::&&&&O&O:&&O:, @@@@@@@@", "@@@@@@@@@@.>:::::O&&&&&:&&::+ ;@@@@@@@@", "@@@@@@@@@@>.<::::O&&O&O:&&:: @@@@@@@@@", "@@@@@@@@@@@.o%,:::O&&&O:&O:, @@@@@@@@@", "@@@@@@@@@@@$o. :::OO&OO&::, ;@@@@@@@@@", "@@@@@@@@@@@&o%+ ,::O&OO&O:: =@@@@@@@@@", "@@@@@@@@@@@.oo+ :::OO::: ,@@@@@@@@@@", "@@@@@@@@@@@..oO +::::: =@@@@@@@@@@", "@@@@@@@@@@@@.<.+ ,+, ,@@@@@@@@@@@", "@@@@@@@@@@@@Oo<+ @X, ,@@@@@@@@@@@@", "@@@@@@@@@@@@.%o$ @@@@@;, ;@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o., =@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" }; /* XPM */ static const char *confused_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO", "OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO", "OOOOOOOOOOO+=.=====.=++++===OO==+O=+OOOO", "OOOOOOOOOOO=+===.+=o==o===+&OoO======OOO", "OOOOOOOO+O+====OO+=o&&&&Oo==o&oO+==+=.O.", "OOOO+.+=+O==+&&o=oooOo&o&ooo=&oooO==O=+=", "OOOOOOOO++O===oo=oo&=&o&&oo=o==&o+==++==", "OOOOOOOO=o.=O====o&OO&o&oo&o&&oo=======O", "OOOOOOOo===+=O=O=ooO=ooooOOo=o&O=====OOO", "OOOOOOOOO+==+=======O=oo====O=o=O===+OOO", "OOOOOOOOO.=#=X=+====O========O======OOOO", "OOOOOOO.#Xo++.=#%====O==========OO==+OOO", "OOOOOO+Xo#+#+.#=.==X====+====O=+=+==+OOO", "OOOOO.+.+O===##.#=X.====oX##===o+OO.OOOO", "OOOOO#+####O#O##o.#+==#X#O#+...=OOo=+OOO", "OOOO++#o+#+X++++#.#O.#+#X.#+X+==+OO=oOOO", "OOOO#+.+..X+.##X++#++#..+XX#+##+..OOOOOO", "OOOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOO", "OOOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOO", "OOOOO#+#+.+++#++.+++##+X###+X+X##+**OOOO", "OOOOO#..#OO#+.##o###.+..++.+#X+#+#* @OOO", "OOOOO+#.#O+#+#O.+++.###+##++###+.#* $OOO", "OOOOOOXX+#+#+#o..X##++#+..##.#+### *OOO", "OOOOOOOX#.#X+#+#+#+.#+..+####%XX%% OOO", "OOOOOOOO.%%X.#+#+#.++#+#+#+.X++=.% *OOO", "OOOOOOOOO.* *##+#+.O####.+XX%%%%#% $OOO", "OOOOOOOOOOO. %X.+.#+++XXX=.+++#X $OOO", "OOOOOOOOOOOO.* %%X..#X%=.####%X* $OOO", "OOOOOOOOOOOOOO.$ *XX%%%=.#X%###=* OOOO", "OOOOOOOOOOOOOOOOOO+%%%=%%#.+.#=* @OOOO", "OOOOOOOOOOOOOOOOOOo=%%%==X##X%* OOOOO", "OOOOOOOOOOOOOOOOOOO+X%%%%X=%* @OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X *@OOOOOO", "OOOOOOOOOOOOOOOOOOOO=%%%X* *$$OOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+X%%= .OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOX%%% OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO" }; /* XPM */ static const char *dex_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ " c #000000", ". c #949E9E", "X c #F8B090", "o c #5C7A7A", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #B64700", "* c #909090", "= c #606060", "- c #CEAA90", "; c #DADAB6", ": c #303030", "> c #F86800", ", c #FFB691", "< c #F88C48", /* pixels */ "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "###############-%-######################", "##############-%X<-#####################", "#########-<<-#-%XX+==###################", "#########%,X< :<,X%@ :##################", "#########-XX%: @;X%+ *#################", "##########<,X& :<<%+: :#################", "######->+#-%%%: <,XX@ #################", "######%X%@ <,,& @XXX+ :++-#############", "######-: +XX+ #########", "#####+%%@@,X%<,XXXXXXX<:@XXX<: =########", "####$%XX< <,<,XX& ########", "#####$%<%X@%XXXX<%XX< =#######", "#######<;X%XXXXX<<,XXXXXX%,XXXXXXXXX%@ #######", "##########- c #788C8C", ", c #606060", "< c #406868", "1 c #C80050", "2 c #FFFFFF", "3 c #FFFF00", "4 c #00B6FF", "5 c #CEAA90", "6 c #DADAB6", "7 c #F86800", "8 c #FFB691", "9 c #6C91B6", "0 c #F88C48", "q c #0000FF", /* pixels */ "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$353333335*$$$$$$$$$$$$$$$", "$$$$$$$$$$$$*33333333#7@3335$$$$$$$$$$$$", "$$$$$$$$$65333333333@7777#333*$$$$$$$$$$", "$$$$$$$$$3333333333377777733333===%$$$$$", "$$$$$$$533333333333#7777777333%=====$$$$", "$$$$$$ #3333333333o>7777773330======%$$$", "$$$$5---O#33333o3944077777333*=======$$$", "$$$$-----O333333>4444.77333330======%$$$", "$$$ ---O--;3333344444443333333:====5$$$$", "$$$ O-----733333444444433333333 ==035$$$", "$$$3--O--O333333>44444>33333333333333$$$", "$$533---O33333333944493333#333333333356$", "$$33867733333o33333:o333333o3333333333$$", "$532+2233333#333333333333oooo3#3333333%$", "6522222+33333333333333333oooooo33o3333*$", "$+22+22263333333o3333333ooooooo333333356", "662222+2533333333333333#ooooooo33333333$", "$32+22223333o3#33333o333ooooooo3#333333%", "$33222233333333333#333333ooooo333333333$", "$33368333333333333330626*oooo#333333o33%", "%333335== 33oo333333222223#333333333333$", "$3333=====:ooooo333+22+2263333333.>o333%", "$5333=====oooooo33322222223333339444935$", "$*33 ====>ooooooo3362+222633333.44444>3$", "$%330====:ooooooo333222+23333334444444$$", "$$333177 =oooXoo#333*626333333;4444444$$", "$$53##777&3oooo3333333333333#--,444449$$", "$$$3;77777#3o333333333333333O---94449$$$", "$$%*@77777#33333333333333337O----O:o3$$$", "$$$5777777333 333333333333;---O-O73$$$$", "$$$$#7777730====#:.,33333333------3$$$$$", "$$$$$577333=====qqqq<0333333#O---35$$$$$", "$$$$$%53335====qqqqqq.33o333337735$$$$$$", "$$$$$$$533 ====qqqqqqq3333333333%$$$$$$$", "$$$$$$$$%33====qqqqqqq333333333%$$$$$$$$", "$$$$$$$$$$50===qqqqqq,3333333:$$$$$$$$$$", "$$$$$$$$$%6%5503,qqq<333#335%$$$$$$$$$$$", "$$$$$$$$$$$$$%$*53,03335o$%%$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$%$$+$$$$$$$$$$$$$$$" }; /* XPM */ static const char *hungry_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 15 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #CEAA90", "= c #DADAB6", "- c #303030", "; c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO========OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO=============OOOOOOOOOOOOO", "OO;XX;@OOOOO================OOOOOOOO;XOO", "OO;%-;$OOOO==================OOOOOOO;XOO", "OO;-%;$OOO========@$#@========OOOOO+;;$O", "OO;%-;$OO=======- -*======*OOOO.;;$O", "OO;-%;$O======* @====.$$&=====@OOO.;;$O", "OO;X%;$O====== -========*@=====*.OO+;;$O", "OO;;;X$o====* -==========@======$OO;;;$O", "OO+;;-+o====- =============o====#@O+;;$O", "OOO;%$O===== @=============&====*$O;;;$O", "OOO+%OO====@ ==============&=====-OO;;$O", "OOo;-Oo====$ ==============o&==== OO;;$O", "OOO+%OO====@ ==============&===== O+;;#O", "OOO;-Oo====$-==============&&==== O+;;-O", "OOO;;+O=====$*============&&====* OO;;%+", "OOO;;$o=====$.============&&====X-OO;;$O", "OOO;;$O======*.===&======&&=====-$=O;;$O", "OOO;;$Oo=====.==========&&=====* @O+;;$O", "OOO;;$OO=======oo=====&&&======$-OOO;;$O", "OOO;;$OOo=======&o&&&&&&======$ @OOO;;$O", "OOO;;$OOOO========&=&========* $OOOO;;$O", "OO+;;$OOOOo=================* -OOOOO#;$O", "OOO;;$OOOOO=*==============@ -=OOOOO;;$O", "OOO;;$OOOOOOO+*==========*- $OOOOOOO;;$O", "OOOX-$OOOOOOOO@X@*====*#- -.OOOOOOOOX-$O", "OOOOOOOOOOOOOO=*@$- -$.=OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOO=O==O=O=OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *hvy_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOO&&&&&&&&&&&&&&&.OOOOOOOOOOOOO", "OOOOOOOOOOOo==============X*OOOOOOOOOOOO", "OOOOOOOOOOoO===X====X=====X**OOOOOOOOOOO", "OOOOOOOOOO&============X===% $OOOOOOOOOO", "OOOOOOOOOoo===*%====***%===%* OOOOOOOOOO", "OOOOOOOOOoO==% %===* %==X* @OOOOOOOOO", "OOOOOOOOO&===% *==% X==**===% $OOOOOOOOO", "OOOOOOOOoo===% %==% ===% ===X OOOOOOOOO", "OOOOOOOOoO==== *== *==== *==X* @OOOOOOOO", "OOOOOOOO&===== %== %==== %===% $OOOOOOOO", "OOOOOOOoo===== *== *==== *===%* OOOOOOOO", "OOOOOOOoO===== %==% ===* ====X* @OOOOOOO", "OOOOOOO&===X== *==% X==**=====% $OOOOOOO", "OOOOOOoo===== *==* %=====X OOOOOOO", "OOOOOOoO=====*%%X===*%*X======%* @OOOOOO", "OOOOOOo====================X===* $OOOOOO", "OOOOOOO=%X%XXXX%XXXXXXXXX%X=%X% OOOOOO", "OOOOOOO.=********************** OOOOOO", "OOOOOOOOO OOOOOO", "OOOOOOOOO. @OOOOOO", "OOOOOOOOOOOoOOoOoOoOoOoOoOOoOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *int_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #303030", "* c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOO+#.X.##@#OOOOOOOOOOOOOOOOOO", "OOOOOOOO+##@X#O++.#+#.##OOOOOOOOOOOOOOOO", "OOOOOO+#Xo++#X#%#+##o#O#.#+OOOOOOOOOOOOO", "OOOOO.Xo#+#++##+.XX#..+.+..XOOOOOOOOOOOO", "OOOO++.+O.+O##+#.X###..OX#.+X+OOOOOOOOOO", "OOOO#+####O#O##o##+###X#+#+.#..OOOOOOOOO", "OOO.+#o+#+X++++#.#O+#+#X.#+X++X+OOOOOOOO", "OOO.+.+..X+.##X++#++#..+XX#+#X+..OOOOOOO", "OOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOOO", "OOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOOO", "OOOO#+#+.+++#++.+++##+X###+X+X##+&&OOOOO", "OOOO#..#OO#+.##o###.+..++.+#X+#+#& @OOOO", "OOOO.#.#O+#+#O.+++.###+##++###+.# $OOOO", "OOOOOXX+#+#+#o..X##++#+..##.#+### &OOOO", "OOOOOOX#.#X+#+#+#+.#+..+####XX%X% OOOO", "OOOOOOO.%%X.#+#+#.++#+#+#+.%++*+% &OOOO", "OOOOOOOO@& &##+#+.O####.+XXX%%%#% $OOOO", "OOOOOOOOOO. %X.+.#+++XXX*.+++#% $OOOO", "OOOOOOOOOOO@& %%X..#XXX.####%%& $OOOO", "OOOOOOOOOOOOO@$ &XX%%%*.#X%###*& OOOOO", "OOOOOOOOOOOOOOOOO+%%%*%%#.+.#*& @OOOOO", "OOOOOOOOOOOOOOOOOO*%%%*.X##XX& OOOOOO", "OOOOOOOOOOOOOOOOOOOX%%%%X*%& @OOOOOO", "OOOOOOOOOOOOOOOOOOOX%%%%% &@OOOOOOO", "OOOOOOOOOOOOOOOOOOO*%%%X& &$$OOOOOOOOO", "OOOOOOOOOOOOOOOOOOO+%%%* .OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO+*%%% OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%& $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+%%& $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOoOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *lawful_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 10 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #606060", "$ c #FFFFFF", "% c #303030", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOo$$$$$$oOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO$$o$$o$$$$$OOOOOOOOOO", "OOOOOOOOOOOOOOOOOOo$$$$$$$o$$ooOOOOOOOOO", "OOOOOOOOOOOOOOOOOO$o$$$o$$$$$$$oOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$$+ .o$$$$$oOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$+%OOOO$o$$$oOOOOOOO", "OOOOOOOOOOOOOOOOO$$o$X@OOOOo$$$ooOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$%OOOOOo$$$..OOOOOOO", "OOOOOOOOOOOOOOOOO$$$$@OOOOo$$oo##OOOOOOO", "OOOOOOOOOOOOOOOO+$$o$$ooOoo$$$o OOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$$$$o$$$$o#%OOOOOOOO", "OOOOOOOOOOOOOOOO+$$o$$o$$$$$o@%OOOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$$$$$o$o.%OOOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$o$$oo@#%OOOOOOOOOOO", "OOOOOOOOoooooo$$$$$$$$$$$% %OOOOOOOOOOOO", "OOOOOOO$$$$$$$$$$$$o$$o$$$$$$$oOOOOOOOOO", "OOOOOO$$$$$$$$$o$$$$$$$$$$$$o$$oOOOOOOOO", "OOOOOO$$o$ooooo##+o$$+##@oo$$$$$oOOOOOOO", "OOOOOOo$$#% %#$$$+%##%%#ooo$O#OOOOOOO", "OOOOOOOo@##OOOOO+$$$##OOOO#%%##%@OOOOOOO", "OOOOOOOOOOOOOOOOo$$$##OOOOOOO##@OOOOOOOO", "OOOOOOOOOOOOOOOOo$$o##OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+$$$o OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$o$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$o%@OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$o OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$$o OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$o##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$# @OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO.#@OOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *mod_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOo&&&&&&&&&oXOOOOOOOOOOOOOOO", "OOOOOOOOOOOO+&=========X%@OOOOOOOOOOOOOO", "OOOOOOOOOOOOO&=====X====% @OOOOOOOOOOOOO", "OOOOOOOOOOOOoO==X=======X* OOOOOOOOOOOOO", "OOOOOOOOOOOO&====*%*%*===* $OOOOOOOOOOOO", "OOOOOOOOOOO+&===X ===% *OOOOOOOOOOOO", "OOOOOOOOOOOoO===**=======X* OOOOOOOOOOOO", "OOOOOOOOOOO&===% %=======X% $OOOOOOOOOOO", "OOOOOOOOOOO&===% %*%%=====% *OOOOOOOOOOO", "OOOOOOOOOOoO===* ====X* OOOOOOOOOOO", "OOOOOOOOOO&=========* X===X% $OOOOOOOOOO", "OOOOOOOOO+&=========% *====% *OOOOOOOOOO", "OOOOOOOOOoO===% %=== %====%* OOOOOOOOOO", "OOOOOOOOO&====* *==X===% $OOOOOOOOO", "OOOOOOOOO&======*%*%X=======% *OOOOOOOOO", "OOOOOOOOOo==X===============% OOOOOOOOO", "OOOOOOOOO=XXXXXXXXXX%X%X%X%%% $OOOOOOOO", "OOOOOOOOOO=%**************** $OOOOOOOO", "OOOOOOOOOOO$ $OOOOOOOO", "OOOOOOOOOOOO* *OOOOOOOOO", "OOOOOOOOOOOOOoOOoOoOoOoOoOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *neutral_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #00B6FF", "= c #303030", "- c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO.------.OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO-+O&o.-----OOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+-&o--------.OOOOOOOOO", "OOOOOOOOOOOOOOOOOO-oo----------+OOOOOOOO", "OOOOOOOOOOOOOOOOO+-&--% #-------OOOOOOOO", "OOOOOOOOOOOOOOOOO-OO-X=OOO.-----+OOOOOOO", "OOOOOOOOOOOOOOOOO-oO-%#OOOO.-----OOOOOOO", "OOOOOOOOOOOOOOOOO--O-=OOOOO+---X#OOOOOOO", "OOOOOOOOOOOOOOOOO-oO-XOOOO+OO--=$OOOOOOO", "OOOOOOOOOOOOOOOOO-OO--++OO-&--- OOOOOOOO", "OOOOOOOOOOOOOOOOO-OO-----+oo--%=OOOOOOOO", "OOOOOOOOOOOOOOOOO--O--+o&&o--%=OOOOOOOOO", "OOOOOOOOOOOOOOOOO-oo*-------%=OOOOOOOOOO", "OOOOOOOOOOOOOOOOO-oO------%%=OOOOOOOOOOO", "OOOOOOOO+.+-+.---O&------= =OOOOOOOOOOOO", "OOOOOO+-oo&&&&&&&&------------.OOOOOOOOO", "OOOOOO---------------X-----O&Oo-OOOOOOOO", "OOOOOO---------%=%---%%=%----OO-.OOOOOOO", "OOOOOO---== =%---%=%%===----%XOOOOOOO", "OOOOOOO-#$%OOOOOO-+-%$OOOO%===%=@OOOOOOO", "OOOOOOOOOOOOOOOO.-&-=%OOOOOOO%%#OOOOOOOO", "OOOOOOOOOOOOOOOo-O+-%$OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-%%OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-%$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-=$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO--o-%$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+-&- .OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-Oo- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-OO%%OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-o-%$OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO---%$OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO--% #OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOX$@OOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *ovr_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOoO+=+OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOo=#===+OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo=.OO@X=OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo#OO* #X @OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+=.XX+=#* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO+=O=.=OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOO#.=+OO@ $OOOOOOOOOOOOOO", "OOOOOOOOOooooooooo&O.#+#XooooOOOOOOOOOOO", "OOOOOOOOO&OOoOoOoOOOOOOOOOoO%@OOOOOOOOOO", "OOOOOOOOoO==================X*@OOOOOOOOO", "OOOOOOOO&===================X% @OOOOOOOO", "OOOOOOOO&==%*%*%*%*%*%*%*%*==% *OOOOOOOO", "OOOOOOOoO==%*%%*%%*%%*%*%*%==X* OOOOOOOO", "OOOOOOO&======================* $OOOOOOO", "OOOOOO+&=== ===% *OOOOOOO", "OOOOOOoO======================X* OOOOOOO", "OOOOOO&=======================X% $OOOOOO", "OOOOOOo========================% *OOOOOO", "OOOOOoO===*%X=====%%======%%===X* OOOOOO", "OOOOO&==% %==% *==== %==* $OOOOO", "OOOOO&== *==**== **% *=X% %%* ==% *OOOOO", "OOOOoO==%%==* =* ===% == %=== %=X* OOOOO", "OOOO&=======% =**===% %X %X==* =X% $OOOO", "OOOO&======% %= %==== %% ====* ==% *OOOO", "OOOoO=====% *== *==== %* ====% ==X* OOOO", "OOO&====XX *===**===% X% X=== *===* $OOO", "OO+&====X *====* ===% == *=== %===% *OOO", "OOoO===% %*%*== *** %==% %** ====X* OOO", "OO&====% ==X *====* %====X% $OO", "OO&================================% *OO", "OOo===X============================% OO", "OO=XXXXXXXXXXXX%XXXX%X%X%XXXXX%X%X%% $O", "OOO=%****************************** $O", "OOOO$ $O", "OOOOO* *OO", "OOOOOOOOOOoOOoOOoOOoOOoOOoOOoOOoOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *pet_mark_xpm[] = { /* width height ncolors chars_per_pixel */ "8 7 2 1", /* colors */ ". c None", " c #FF0000", /* pixels */ "........", ".. . .", ". ", ". ", ".. .", "... ..", ".... ..." }; /* XPM */ static const char *pet_mark_small_xpm[] = { /* width height ncolors chars_per_pixel */ "5 5 2 1", /* colors */ ". c None", "X c #FF0000", /* pixels */ ".X.X.", "XXXXX", ".XXX.", "..X.." }; /* XPM */ static const char *satiated_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ " c #000000", ". c #949E9E", "X c #F8B090", "o c #5C7A7A", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #914700", "* c #B64700", "= c #909090", "- c #788C8C", "; c #606060", ": c #406868", "> c #FFFFFF", ", c #CEAA90", "< c #DADAB6", "1 c #303030", "2 c #FFB691", "3 c #6C91B6", "4 c #F88C48", /* pixels */ "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "################<<<<<<<<################", "##############<<<<<<<<<<$#$$$###########", "############<<<<<<<<<<$:31:3:###########", "###########<<<<<<%42<<#:3:133-##########", "##########<<<<<%<<;;=o$131:33;##########", "#########<<<<<<,1 ::31:33;,#########", "########<<<<<<, =<<<<.13:133;<=########", "########<<<%2, 1<<<<<<#333:33;<,=#######", "#######<<<3-=<33;<<@o######", "#######O<<<<<,#<<<<<<<<.3:<3-;<, =######", "########<<<<2<<<<<<<<<>#31<33o<11#######", "########O<<<<44<>O>>>>>#3:<3.;- =#######", "##########<<<4<<<<><><<$3:<331 ;<#######", "##########<<<<<<<%2<<<<$3:<33 1#########", "###########O,<<<<<<<<<<#31<331##########", "#############.<<<<<<<<<$3:133;##########", "##############=;=,<<<<,o 1;;=##########", "###############<=;1 1;=##############", "#################<# c #B64700", ", c #909090", "< c #788C8C", "1 c #606060", "2 c #406868", "3 c #FFFFFF", "4 c #CEAA90", "5 c #DADAB6", "6 c #303030", "7 c #F86800", "8 c #FFB691", "9 c #6C91B6", "0 c #F88C48", "q c #0000FF", /* pixels */ "****************************************", "*************#333333333#****************", "***********##33333#333333#**************", "**********#33333#33333#33*==************", "*********#33##33-;-3#3333399************", "********#33#33#3-@ 33333#33=.***********", "********#3*#33-;;;;;-33333#99***********", "*******#3*3333-;;;;@ 33#333#9=**********", "*******#333#33#3-;-33#*##33399**********", "******#3#3333333-@-#333#9933*9=*********", "******#333#33#3333333#333*9999=*********", "******#333333333#3#33333333*999*********", "******#3#33#33333333#33#3333#9=*********", "******#333334>&&:&&>::44,3#33#9*********", "******#33*::&41OOO6:4O 0::4433=*********", "******#3:>,0:O0O1O+O:OXO,O+2+OOo4<+1104:>:#*********", "******.&:1OOO,14X2O48:O80,440:,*********", "******4::>OOO%8-X4O4%O,84+O0X&>=********", "******.::>,O 99*X+<$,+.o*1O4&0:*********", "******>:0&4O5qq9#10OO3qq9,+X:1:*********", "****=>,,::,O4qq9X+O>O-qq9O2X0,>*********", "******4:>OOOO48882OOOO+4OOO07*4*********", "******4*,4OO+OXX3O5************", "*********=0%,OO,>:>>O +1OO4*************", "**********=%+OO:::1:::6+:7**************", "***********7&OO:O+O,O1OO+1**************", "***********40OO,O4:OOO11O<5*************", "**********=4 +O1O2+O2+O0O***************", "************72O+1+21-OOO%5**************", "************0%1OOOO+O+174***************", "*************%%O,OO1407-=***************", "**************-$>%0%:74*****************", "****************54044*=*****************", "*****************=*=********************" }; /* XPM */ static const char *sick_il_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ " c #F85848", ". c #949E9E", "X c #F8B090", "o c #E00028", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #FF0000", "* c #914700", "= c #B64700", "- c #909090", "; c #606060", ": c #FFFFFF", "> c #CEAA90", ", c #DADAB6", "< c #F86800", "1 c #FFB691", "2 c #6C91B6", "3 c #F88C48", "4 c #0000FF", /* pixels */ "########################################", "#############O:::::::::O################", "###########OO:::::O::::::O##############", "##########O:::::O:::::O::#$$############", "#########O::OO::%&%:O:::::22############", "########O::O::O:%o :::::O::$.###########", "########O:#O::%&&&&&%:::::O22###########", "#######O:#::::%&&&&o ::O:::O2$##########", "#######O:::O::O:%&%::O#OO:::22##########", "######O:O:::::::%o%O:::O22::#2$#########", "######O:::O::O:::::::O:::#2222$#########", "######O:::::::::O:O::::::::#222#########", "######O:O::O::::::::O::O::::O2$#########", "######O:::::>=@@=**=**>>-:O::O2#########", "######O::#**@3>%* ;=>=3;<@>>::$#########", "######O:** >=>XXXX1X >>+>%*%*;O#########", "######O3@*,X%XXXXXXX>X%XX >*=*O#########", "######.@@3XXXXXXXXXXXXXXX>X>3*-#########", "######>***>X% >XXXXX3XXXXXX%>*=>########", "######.***> 22#XXX<%X22#XXX@+;#########", "######=*3@X>O442OXX==%XX11111O1+%X111XX%<#>#########", "######.,;XXXXXX1O1X%3XXXXX%+3###########", "########3=XXXXXX:XXXXXXXXX+<>$##########", "########>+XXXXXX%-3->XXXX%+<############", "#########%3XXXXXX>- -%XXX%<%$###########", "#########$############", "##########+%XXXXXXXXXXXX%+<#############", "##########%3XXX>=****3XX%<%#############", "##########>+XXX**=3-*@3>3+##############", "###########<%XX >XX%X;%X3+##############", "###########%3XX>XX++XXXX<%$#############", "##########$>+XXXXXXXXXXX<###############", "############<%XXXXXXXXX3+###############", "###########$%+XXXXXXXX%<>###############", "#############++XXXXXX%<%$###############", "#############$%<<3333<%#################", "#################%3>>$##################", "#################$#$####################" }; /* XPM */ static const char *slt_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO&&&&&&&X @OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo======X*OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOoO======X**OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO&====X===% $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOoo==%* %==%* OOOOOOOOOOOOOO", "OOOOOOOOOOOOOoO=% % =X* @OOOOOOOOOOOOO", "OOOOOOOOOOOOO&==**==% %=% $OOOOOOOOOOOOO", "OOOOOOOOOOOOoo==%%==* %=X OOOOOOOOOOOOO", "OOOOOOOOOOOOoO=====* X==X* @OOOOOOOOOOOO", "OOOOOOOOOOOO&=====* %====% $OOOOOOOOOOOO", "OOOOOOOOOOOoo==== X=====%* OOOOOOOOOOOO", "OOOOOOOOOOOo+===* *%*%%==X* @OOOOOOOOOOO", "OOOOOOOOOOO&==== %===% $OOOOOOOOOOO", "OOOOOOOOOOO&==============% OOOOOOOOOOO", "OOOOOOOOOOO==============X% @OOOOOOOOOO", "OOOOOOOOOOO+%%%%%%%%%%%%%% $OOOOOOOOOO", "OOOOOOOOOOOOO% $OOOOOOOOOO", "OOOOOOOOOOOOO@ @OOOOOOOOOO", "OOOOOOOOOOOOOO@$$$$$$$$$$$$$@OOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static const char *str_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 17 1", /* colors */ " c #000000", ". c #F8B090", "X c #5C7A7A", "o c #F87A24", "O c #7C3400", "+ c None", "@ c #B0B0B0", "# c #F89E6C", "$ c #B64700", "% c #909090", "& c #606060", "* c #CEAA90", "= c #DADAB6", "- c #303030", "; c #F86800", ": c #FFB691", "> c #F88C48", /* pixels */ "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "+++++++++++++++++++*>*>#++++++++++++++++", "++++++++++++++++*#o>..*#o*++++++++++++++", "+++++++++++++++o#.#>.....o++++++++++++++", "+++++++++++++++;>;#.o.>..#$X++++++++++++", "+++++++++++++++o#>.o.>:...o %++++++++++", "++++++++++++++o##>>#o##>..#O -++++++++++", "++++++++++++++>#.oo#>..>...O ++++++++++", "++++++++++++++*o##.>>;o#...o ++++++++++", "+++++++++++++++*;o#........>- &+++++++++", "+++++++++++++++++#>>;o......O -+++++++++", "+++++++++++++++++@+@+o>.....$ +++++++++", "+++++++++++++++++++++*;.#...>- %++++++++", "++++++++++++++++++++++;>o....$ &++++++++", "++++++++++++++++++++++#>>....>- %+++++++", "+++++++++++++++++++++++;#>....; -+++++++", "+++++++++++++++++++++++o#>....>O %++++++", "+++++++++++++++++++++++*>o.....; -++++++", "+++++++++++++#>**+++++++;#.....>O %+++++", "+o#+++++++*o;>>>>o#+++++o##.....; -+++++", "+:#o*++++oo#..*..*>;*+++#>#.....>O %++++", "+:=#o#+*;>.:==:....#;*++@o.......; &++++", "+::..>;o#.=::::......o*++;.......>O ++++", "+.....#o.:.=:.........o#+;........$ ++++", "+......#o..:...........#o;>.......o &+++", "+........#..............*>o......:o- +++", "+..................#o>#...#o.......O +++", "+...............>o>#.......#>......O &++", "+..................................o -++", "+..................................> ++", "+..................................> ++", "+.................................#$ &+", "+................................>$ &+", "+..#>$o>#..............#>;>>>oOOO- ++", "+...#O OOOOO$>>>>>>>$OO %++", "+...o -&&++++", "+..#O -&&%++++++++++", "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ static const char *stunned_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #303030", "* c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOO&$OOOO@OOO@@OO@OOOOOOOOOOOOO", "OOOOOOOOOOO@& $OO@&&$$@ O@$$OOOOOOOOOOOO", "OOOOOOOOOOOO$$ @@@$ &&OOO@$OOOOOOOOOOOO", "OOOOOOOOOOOOO@@&$$$$&O$OO$O &@O@OOOOOOOO", "OOOOOO@@@@@@OO@$$O$&$@@OO& &&$O&OOOOOOO", "OOOOOO&&&& & $ &&@$ &O@$& &&&$ & $OOOOOO", "OOOOOO$&OO &&&$ $$ $& $$&$&&&OOOOOOO", "OOOOOO@@O@$ &+ # &O$$ $$&O@OOOOO", "OOOOOOOO@X%$ %& %% & && $$@@@@OOOO", "OOOOOOO+$$@+ &%%%&%& & &@OOO&&OOO", "OOOOOO.Xo%+ &&%%%%%&& & OO@$&&OOO", "OOOOO++ $$&&$ && %&%%& &O@&$&OOOO", "OOOOO####$ X&&& && &%& & &&OOOO", "OOOO++#.+## $&# %& & & &$ OOOO", "OOOO#+++.@&%&& &#&%& & $ @OOOOOO", "OOOO##....#+$#@%#& $%$&@&$$% & X##$@OOOO", "OOOO.+#+.+@#+#+$&$X#%&%.+& %&#++.$&OOOOO", "OOOOO#+#+.+++#$$%&++&X+X#&#+&+&##+ &OOOO", "OOOOO#..#OO#+@%#o##X.@..++.+$&+#+#& @OOO", "OOOOO+#.#O+#+#O@++@$$##+##++###+.#& $OOO", "OOOOOOXX+#+#+#o.@%&$++#+..##.#+### &OOO", "OOOOOOOX#.#X+#+#+##&#+..+####%XX%% OOO", "OOOOOOOO+%%X.#+#+#.++#+#+#+.X++*.% &OOO", "OOOOOOOOO@& &##+#+.O####.+XX%%%%#% $OOO", "OOOOOOOOOOO. %X.+.#+++XXX*.+++#X $OOO", "OOOOOOOOOOOO@& %%X..#X%#.####%X& $OOO", "OOOOOOOOOOOOOO@$ &XX%%%*.#X%###*& OOOO", "OOOOOOOOOOOOOOOOOO+%%%*%%#.+.#*& @OOOO", "OOOOOOOOOOOOOOOOOOO*%%%**X##X%& OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X*X& @OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X &@OOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%%X& &$$OOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+X%%* @OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOX%%& OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO.X%& $OOOOOOOOOOOOO" }; /* XPM */ static const char *wis_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c None", "O c #B0B0B0", "+ c #909090", "@ c #788C8C", "# c #606060", "$ c #406868", "% c #FFFFFF", "& c #303030", "* c #6C91B6", "= c #0000FF", /* pixels */ "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooo+#& &#oooooooooooooooooooo", "oooooooooooo+& #oooooooooooooooooo", "ooooooooooo+ &====&& &ooooooooooooooooo", "oooooooooo+ &==& ===%& +ooooooooooooooo", "ooooooooo+&%=== ===%%o&&oooooooooooooo", "oooooooo.&%%===& ===%o& #+ooooooooooo", "oooo&###&&%%*=======$#&ooo#& #+oooooooo", "ooooo###o+&X$=====& #oo##oooo+######oooo", "oooooooooooo######@oo##ooooooooooooooooo", "oooooooooooooOoOoOo##ooooooooooooooooooo", "ooooooooooooooooo+#+ooo+&#oooooooooooooo", "ooooooooooooooooooooooo#oooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo" }; nethack-3.4.3/include/qtext.h0100644000000000000000000000510707764735041014616 0ustar rootroot/* SCCS Id: @(#)qtext.h 3.4 1997/02/02 */ /* Copyright (c) Mike Stephenson 1991. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef QTEXT_H #define QTEXT_H #define N_HDR 16 /* Maximum number of categories */ /* (i.e., num roles + 1) */ #define LEN_HDR 3 /* Maximum length of a category name */ struct qtmsg { int msgnum; char delivery; long offset, size; }; #ifdef MAKEDEFS_C /***** MAKEDEFS *****/ #define N_MSG 100 /* arbitrary */ struct msghdr { int n_msg; struct qtmsg qt_msg[N_MSG]; }; struct qthdr { int n_hdr; char id[N_HDR][LEN_HDR]; long offset[N_HDR]; }; /* Error message macros */ #define CREC_IN_MSG "Control record encountered during message - line %d\n" #define DUP_MSG "Duplicate message number at line %d\n" #define END_NOT_IN_MSG "End record encountered before message - line %d\n" #define TEXT_NOT_IN_MSG "Text encountered outside message - line %d\n" #define UNREC_CREC "Unrecognized Control record at line %d\n" #define OUT_OF_HEADERS "Too many message types (line %d)\nAdjust N_HDR in qtext.h and recompile.\n" #define OUT_OF_MESSAGES "Too many messages in class (line %d)\nAdjust N_MSG in qtext.h and recompile.\n" #else /***** !MAKEDEFS *****/ struct qtlists { struct qtmsg *common, #if 0 /* UNUSED but available */ *chrace, #endif *chrole; }; /* * Quest message defines. Used in quest.c to trigger off "realistic" * dialogue to the player. */ #define QT_FIRSTTIME 1 #define QT_NEXTTIME 2 #define QT_OTHERTIME 3 #define QT_GUARDTALK 5 /* 5 random things guards say before quest */ #define QT_GUARDTALK2 10 /* 5 random things guards say after quest */ #define QT_FIRSTLEADER 15 #define QT_NEXTLEADER 16 #define QT_OTHERLEADER 17 #define QT_LASTLEADER 18 #define QT_BADLEVEL 19 #define QT_BADALIGN 20 #define QT_ASSIGNQUEST 21 #define QT_ENCOURAGE 25 /* 1-10 random encouragement messages */ #define QT_FIRSTLOCATE 35 #define QT_NEXTLOCATE 36 #define QT_FIRSTGOAL 40 #define QT_NEXTGOAL 41 #define QT_FIRSTNEMESIS 50 #define QT_NEXTNEMESIS 51 #define QT_OTHERNEMESIS 52 #define QT_NEMWANTSIT 53 /* you somehow got the artifact */ #define QT_DISCOURAGE 60 /* 1-10 random maledictive messages */ #define QT_GOTIT 70 #define QT_KILLEDNEM 80 #define QT_OFFEREDIT 81 #define QT_OFFEREDIT2 82 #define QT_POSTHANKS 90 #define QT_HASAMULET 91 /* * Message defines for common text used in maledictions. */ #define COMMON_ID "-" /* Common message id value */ #define QT_ANGELIC 10 #define QTN_ANGELIC 10 #define QT_DEMONIC 30 #define QTN_DEMONIC 20 #define QT_BANISHED 60 #endif /***** !MAKEDEFS *****/ #endif /* QTEXT_H */ nethack-3.4.3/include/qttableview.h0100644000000000000000000001466307764735041016007 0ustar rootroot/********************************************************************** ** $Id: qttableview.h,v 1.2 2002/03/09 03:13:13 jwalz Exp $ ** ** Definition of QtTableView class ** ** Created : 941115 ** ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. ** ** This file contains a class moved out of the Qt GUI Toolkit API. It ** may be used, distributed and modified without limitation. ** **********************************************************************/ #ifndef QTTABLEVIEW_H #define QTTABLEVIEW_H #ifndef QT_H #include #endif // QT_H #ifndef QT_NO_QTTABLEVIEW class QScrollBar; class QCornerSquare; class QtTableView : public QFrame { Q_OBJECT public: virtual void setBackgroundColor( const QColor & ); virtual void setPalette( const QPalette & ); void show(); void repaint( bool erase=TRUE ); void repaint( int x, int y, int w, int h, bool erase=TRUE ); void repaint( const QRect &, bool erase=TRUE ); protected: QtTableView( QWidget *parent=0, const char *name=0, WFlags f=0 ); ~QtTableView(); int numRows() const; virtual void setNumRows( int ); int numCols() const; virtual void setNumCols( int ); int topCell() const; virtual void setTopCell( int row ); int leftCell() const; virtual void setLeftCell( int col ); virtual void setTopLeftCell( int row, int col ); int xOffset() const; virtual void setXOffset( int ); int yOffset() const; virtual void setYOffset( int ); virtual void setOffset( int x, int y, bool updateScrBars = TRUE ); virtual int cellWidth( int col ); virtual int cellHeight( int row ); int cellWidth() const; int cellHeight() const; virtual void setCellWidth( int ); virtual void setCellHeight( int ); virtual int totalWidth(); virtual int totalHeight(); uint tableFlags() const; bool testTableFlags( uint f ) const; virtual void setTableFlags( uint f ); void clearTableFlags( uint f = ~0 ); bool autoUpdate() const; virtual void setAutoUpdate( bool ); void updateCell( int row, int column, bool erase=TRUE ); QRect cellUpdateRect() const; QRect viewRect() const; int lastRowVisible() const; int lastColVisible() const; bool rowIsVisible( int row ) const; bool colIsVisible( int col ) const; QScrollBar *verticalScrollBar() const; QScrollBar *horizontalScrollBar() const; private slots: void horSbValue( int ); void horSbSliding( int ); void horSbSlidingDone(); void verSbValue( int ); void verSbSliding( int ); void verSbSlidingDone(); protected: virtual void paintCell( QPainter *, int row, int col ) = 0; virtual void setupPainter( QPainter * ); void paintEvent( QPaintEvent * ); void resizeEvent( QResizeEvent * ); int findRow( int yPos ) const; int findCol( int xPos ) const; bool rowYPos( int row, int *yPos ) const; bool colXPos( int col, int *xPos ) const; int maxXOffset(); int maxYOffset(); int maxColOffset(); int maxRowOffset(); int minViewX() const; int minViewY() const; int maxViewX() const; int maxViewY() const; int viewWidth() const; int viewHeight() const; void scroll( int xPixels, int yPixels ); void updateScrollBars(); void updateTableSize(); private: void coverCornerSquare( bool ); void snapToGrid( bool horizontal, bool vertical ); virtual void setHorScrollBar( bool on, bool update = TRUE ); virtual void setVerScrollBar( bool on, bool update = TRUE ); void updateView(); int findRawRow( int yPos, int *cellMaxY, int *cellMinY = 0, bool goOutsideView = FALSE ) const; int findRawCol( int xPos, int *cellMaxX, int *cellMinX = 0, bool goOutsideView = FALSE ) const; int maxColsVisible() const; void updateScrollBars( uint ); void updateFrameSize(); void doAutoScrollBars(); void showOrHideScrollBars(); int nRows; int nCols; int xOffs, yOffs; int xCellOffs, yCellOffs; short xCellDelta, yCellDelta; short cellH, cellW; uint eraseInPaint : 1; uint verSliding : 1; uint verSnappingOff : 1; uint horSliding : 1; uint horSnappingOff : 1; uint coveringCornerSquare : 1; uint sbDirty : 8; uint inSbUpdate : 1; uint tFlags; QRect cellUpdateR; QScrollBar *vScrollBar; QScrollBar *hScrollBar; QCornerSquare *cornerSquare; private: // Disabled copy constructor and operator= #if defined(Q_DISABLE_COPY) QtTableView( const QtTableView & ); QtTableView &operator=( const QtTableView & ); #endif }; const uint Tbl_vScrollBar = 0x00000001; const uint Tbl_hScrollBar = 0x00000002; const uint Tbl_autoVScrollBar = 0x00000004; const uint Tbl_autoHScrollBar = 0x00000008; const uint Tbl_autoScrollBars = 0x0000000C; const uint Tbl_clipCellPainting = 0x00000100; const uint Tbl_cutCellsV = 0x00000200; const uint Tbl_cutCellsH = 0x00000400; const uint Tbl_cutCells = 0x00000600; const uint Tbl_scrollLastHCell = 0x00000800; const uint Tbl_scrollLastVCell = 0x00001000; const uint Tbl_scrollLastCell = 0x00001800; const uint Tbl_smoothHScrolling = 0x00002000; const uint Tbl_smoothVScrolling = 0x00004000; const uint Tbl_smoothScrolling = 0x00006000; const uint Tbl_snapToHGrid = 0x00008000; const uint Tbl_snapToVGrid = 0x00010000; const uint Tbl_snapToGrid = 0x00018000; inline int QtTableView::numRows() const { return nRows; } inline int QtTableView::numCols() const { return nCols; } inline int QtTableView::topCell() const { return yCellOffs; } inline int QtTableView::leftCell() const { return xCellOffs; } inline int QtTableView::xOffset() const { return xOffs; } inline int QtTableView::yOffset() const { return yOffs; } inline int QtTableView::cellHeight() const { return cellH; } inline int QtTableView::cellWidth() const { return cellW; } inline uint QtTableView::tableFlags() const { return tFlags; } inline bool QtTableView::testTableFlags( uint f ) const { return (tFlags & f) != 0; } inline QRect QtTableView::cellUpdateRect() const { return cellUpdateR; } inline bool QtTableView::autoUpdate() const { return isUpdatesEnabled(); } inline void QtTableView::repaint( bool erase ) { repaint( 0, 0, width(), height(), erase ); } inline void QtTableView::repaint( const QRect &r, bool erase ) { repaint( r.x(), r.y(), r.width(), r.height(), erase ); } inline void QtTableView::updateScrollBars() { updateScrollBars( 0 ); } #endif // QT_NO_QTTABLEVIEW #endif // QTTABLEVIEW_H nethack-3.4.3/include/quest.h0100644000000000000000000000324407764735041014612 0ustar rootroot/* SCCS Id: @(#)quest.h 3.4 1992/11/15 */ /* Copyright (c) Mike Stephenson 1991. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef QUEST_H #define QUEST_H struct q_score { /* Quest "scorecard" */ Bitfield(first_start,1); /* only set the first time */ Bitfield(met_leader,1); /* has met the leader */ Bitfield(not_ready,3); /* rejected due to alignment, etc. */ Bitfield(pissed_off,1); /* got the leader angry */ Bitfield(got_quest,1); /* got the quest assignment */ Bitfield(first_locate,1); /* only set the first time */ Bitfield(met_intermed,1); /* used if the locate is a person. */ Bitfield(got_final,1); /* got the final quest assignment */ Bitfield(made_goal,3); /* # of times on goal level */ Bitfield(met_nemesis,1); /* has met the nemesis before */ Bitfield(killed_nemesis,1); /* set when the nemesis is killed */ Bitfield(in_battle,1); /* set when nemesis fighting you */ Bitfield(cheater,1); /* set if cheating detected */ Bitfield(touched_artifact,1); /* for a special message */ Bitfield(offered_artifact,1); /* offered to leader */ Bitfield(got_thanks,1); /* final message from leader */ /* keep track of leader presence/absence even if leader is polymorphed, raised from dead, etc */ Bitfield(leader_is_dead,1); unsigned leader_m_id; }; #define MAX_QUEST_TRIES 7 /* exceed this and you "fail" */ #define MIN_QUEST_ALIGN 20 /* at least this align.record to start */ /* note: align 20 matches "pious" as reported by enlightenment (cmd.c) */ #define MIN_QUEST_LEVEL 14 /* at least this u.ulevel to start */ /* note: exp.lev. 14 is threshold level for 5th rank (class title, role.c) */ #endif /* QUEST_H */ nethack-3.4.3/include/rect.h0100644000000000000000000000043207764735041014402 0ustar rootroot/* SCCS Id: @(#)rect.h 3.4 1990/02/22 */ /* Copyright (c) 1990 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #ifndef RECT_H #define RECT_H typedef struct nhrect { xchar lx, ly; xchar hx, hy; } NhRect; #endif /* RECT_H */ nethack-3.4.3/include/region.h0100644000000000000000000000565107764735041014740 0ustar rootroot/* SCCS Id: @(#)region.h 3.4 2002/10/15 */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #ifndef REGION_H #define REGION_H /* generic callback function */ typedef boolean FDECL((*callback_proc), (genericptr_t, genericptr_t)); /* * Overload the old player_inside field with two values, coded in such * a way as to retain compatibility with 3.4.0 save and bones files; * this relies on the fact that nethack's `boolean' is really stored * in a `char' (or bigger type) rather than in a single bit. * * 3.4.1 save and bones files will be correct. * 3.4.0 save files restored under 3.4.1 will be correct. * 3.4.0 bones files used with 3.4.1 will continue to have the minor * 3.4.0 bug of falsely claiming that the current game's hero is * responsible for the dead former hero's stinking clouds. */ #define REG_HERO_INSIDE 1 #define REG_NOT_HEROS 2 #define hero_inside(r) ((unsigned)(r)->player_flags & REG_HERO_INSIDE) #define heros_fault(r) (!((unsigned)(r)->player_flags & REG_NOT_HEROS)) #define set_hero_inside(r) ((r)->player_flags |= REG_HERO_INSIDE) #define clear_hero_inside(r) ((r)->player_flags &= ~REG_HERO_INSIDE) #define set_heros_fault(r) ((r)->player_flags &= ~REG_NOT_HEROS) #define clear_heros_fault(r) ((r)->player_flags |= REG_NOT_HEROS) typedef struct { NhRect bounding_box; /* Bounding box of the region */ NhRect *rects; /* Rectangles composing the region */ short nrects; /* Number of rectangles */ boolean attach_2_u; /* Region attached to player ? */ unsigned int attach_2_m; /* Region attached to monster ? */ /*struct obj *attach_2_o;*/ /* Region attached to object ? UNUSED YET */ const char* enter_msg; /* Message when entering */ const char* leave_msg; /* Message when leaving */ short ttl; /* Time to live. -1 is forever */ short expire_f; /* Function to call when region's ttl expire */ short can_enter_f; /* Function to call to check wether the player can, or can not, enter the region */ short enter_f; /* Function to call when the player enters*/ short can_leave_f; /* Function to call to check wether the player can, or can not, leave the region */ short leave_f; /* Function to call when the player leaves */ short inside_f; /* Function to call every turn if player's inside */ boolean player_flags; /* (see above) */ unsigned int* monsters; /* Monsters currently inside this region */ short n_monst; /* Number of monsters inside this region */ short max_monst; /* Maximum number of monsters that can be listed without having to grow the array */ #define MONST_INC 5 /* Should probably do the same thing about objects */ boolean visible; /* Is the region visible ? */ int glyph; /* Which glyph to use if visible */ genericptr_t arg; /* Optional user argument (Ex: strength of force field, damage of a fire zone, ...*/ } NhRegion; #endif /* REGION_H */ nethack-3.4.3/include/rm.h0100644000000000000000000003470107764735041014071 0ustar rootroot/* SCCS Id: @(#)rm.h 3.4 1999/12/12 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef RM_H #define RM_H /* * The dungeon presentation graphics code and data structures were rewritten * and generalized for NetHack's release 2 by Eric S. Raymond (eric@snark) * building on Don G. Kneller's MS-DOS implementation. See drawing.c for * the code that permits the user to set the contents of the symbol structure. * * The door representation was changed by Ari Huttunen(ahuttune@niksula.hut.fi) */ /* * TLCORNER TDWALL TRCORNER * +- -+- -+ * | | | * * TRWALL CROSSWALL TLWALL HWALL * | | | * +- -+- -+ --- * | | | * * BLCORNER TUWALL BRCORNER VWALL * | | | | * +- -+- -+ | */ /* Level location types */ #define STONE 0 #define VWALL 1 #define HWALL 2 #define TLCORNER 3 #define TRCORNER 4 #define BLCORNER 5 #define BRCORNER 6 #define CROSSWALL 7 /* For pretty mazes and special levels */ #define TUWALL 8 #define TDWALL 9 #define TLWALL 10 #define TRWALL 11 #define DBWALL 12 #define TREE 13 /* KMH */ #define SDOOR 14 #define SCORR 15 #define POOL 16 #define MOAT 17 /* pool that doesn't boil, adjust messages */ #define WATER 18 #define DRAWBRIDGE_UP 19 #define LAVAPOOL 20 #define IRONBARS 21 /* KMH */ #define DOOR 22 #define CORR 23 #define ROOM 24 #define STAIRS 25 #define LADDER 26 #define FOUNTAIN 27 #define THRONE 28 #define SINK 29 #define GRAVE 30 #define ALTAR 31 #define ICE 32 #define DRAWBRIDGE_DOWN 33 #define AIR 34 #define CLOUD 35 #define MAX_TYPE 36 #define INVALID_TYPE 127 /* * Avoid using the level types in inequalities: * these types are subject to change. * Instead, use one of the macros below. */ #define IS_WALL(typ) ((typ) && (typ) <= DBWALL) #define IS_STWALL(typ) ((typ) <= DBWALL) /* STONE <= (typ) <= DBWALL */ #define IS_ROCK(typ) ((typ) < POOL) /* absolutely nonaccessible */ #define IS_DOOR(typ) ((typ) == DOOR) #define IS_TREE(typ) ((typ) == TREE || \ (level.flags.arboreal && (typ) == STONE)) #define ACCESSIBLE(typ) ((typ) >= DOOR) /* good position */ #define IS_ROOM(typ) ((typ) >= ROOM) /* ROOM, STAIRS, furniture.. */ #define ZAP_POS(typ) ((typ) >= POOL) #define SPACE_POS(typ) ((typ) > DOOR) #define IS_POOL(typ) ((typ) >= POOL && (typ) <= DRAWBRIDGE_UP) #define IS_THRONE(typ) ((typ) == THRONE) #define IS_FOUNTAIN(typ) ((typ) == FOUNTAIN) #define IS_SINK(typ) ((typ) == SINK) #define IS_GRAVE(typ) ((typ) == GRAVE) #define IS_ALTAR(typ) ((typ) == ALTAR) #define IS_DRAWBRIDGE(typ) ((typ) == DRAWBRIDGE_UP || (typ) == DRAWBRIDGE_DOWN) #define IS_FURNITURE(typ) ((typ) >= STAIRS && (typ) <= ALTAR) #define IS_AIR(typ) ((typ) == AIR || (typ) == CLOUD) #define IS_SOFT(typ) ((typ) == AIR || (typ) == CLOUD || IS_POOL(typ)) /* * The screen symbols may be the default or defined at game startup time. * See drawing.c for defaults. * Note: {ibm|dec}_graphics[] arrays (also in drawing.c) must be kept in synch. */ /* begin dungeon characters */ #define S_stone 0 #define S_vwall 1 #define S_hwall 2 #define S_tlcorn 3 #define S_trcorn 4 #define S_blcorn 5 #define S_brcorn 6 #define S_crwall 7 #define S_tuwall 8 #define S_tdwall 9 #define S_tlwall 10 #define S_trwall 11 #define S_ndoor 12 #define S_vodoor 13 #define S_hodoor 14 #define S_vcdoor 15 /* closed door, vertical wall */ #define S_hcdoor 16 /* closed door, horizontal wall */ #define S_bars 17 /* KMH -- iron bars */ #define S_tree 18 /* KMH */ #define S_room 19 #define S_corr 20 #define S_litcorr 21 #define S_upstair 22 #define S_dnstair 23 #define S_upladder 24 #define S_dnladder 25 #define S_altar 26 #define S_grave 27 #define S_throne 28 #define S_sink 29 #define S_fountain 30 #define S_pool 31 #define S_ice 32 #define S_lava 33 #define S_vodbridge 34 #define S_hodbridge 35 #define S_vcdbridge 36 /* closed drawbridge, vertical wall */ #define S_hcdbridge 37 /* closed drawbridge, horizontal wall */ #define S_air 38 #define S_cloud 39 #define S_water 40 /* end dungeon characters, begin traps */ #define S_arrow_trap 41 #define S_dart_trap 42 #define S_falling_rock_trap 43 #define S_squeaky_board 44 #define S_bear_trap 45 #define S_land_mine 46 #define S_rolling_boulder_trap 47 #define S_sleeping_gas_trap 48 #define S_rust_trap 49 #define S_fire_trap 50 #define S_pit 51 #define S_spiked_pit 52 #define S_hole 53 #define S_trap_door 54 #define S_teleportation_trap 55 #define S_level_teleporter 56 #define S_magic_portal 57 #define S_web 58 #define S_statue_trap 59 #define S_magic_trap 60 #define S_anti_magic_trap 61 #define S_polymorph_trap 62 /* end traps, begin special effects */ #define S_vbeam 63 /* The 4 zap beam symbols. Do NOT separate. */ #define S_hbeam 64 /* To change order or add, see function */ #define S_lslant 65 /* zapdir_to_glyph() in display.c. */ #define S_rslant 66 #define S_digbeam 67 /* dig beam symbol */ #define S_flashbeam 68 /* camera flash symbol */ #define S_boomleft 69 /* thrown boomerang, open left, e.g ')' */ #define S_boomright 70 /* thrown boomerand, open right, e.g. '(' */ #define S_ss1 71 /* 4 magic shield glyphs */ #define S_ss2 72 #define S_ss3 73 #define S_ss4 74 /* The 8 swallow symbols. Do NOT separate. To change order or add, see */ /* the function swallow_to_glyph() in display.c. */ #define S_sw_tl 75 /* swallow top left [1] */ #define S_sw_tc 76 /* swallow top center [2] Order: */ #define S_sw_tr 77 /* swallow top right [3] */ #define S_sw_ml 78 /* swallow middle left [4] 1 2 3 */ #define S_sw_mr 79 /* swallow middle right [6] 4 5 6 */ #define S_sw_bl 80 /* swallow bottom left [7] 7 8 9 */ #define S_sw_bc 81 /* swallow bottom center [8] */ #define S_sw_br 82 /* swallow bottom right [9] */ #define S_explode1 83 /* explosion top left */ #define S_explode2 84 /* explosion top center */ #define S_explode3 85 /* explosion top right Ex. */ #define S_explode4 86 /* explosion middle left */ #define S_explode5 87 /* explosion middle center /-\ */ #define S_explode6 88 /* explosion middle right |@| */ #define S_explode7 89 /* explosion bottom left \-/ */ #define S_explode8 90 /* explosion bottom center */ #define S_explode9 91 /* explosion bottom right */ /* end effects */ #define MAXPCHARS 92 /* maximum number of mapped characters */ #define MAXDCHARS 41 /* maximum of mapped dungeon characters */ #define MAXTCHARS 22 /* maximum of mapped trap characters */ #define MAXECHARS 29 /* maximum of mapped effects characters */ #define MAXEXPCHARS 9 /* number of explosion characters */ struct symdef { uchar sym; const char *explanation; #ifdef TEXTCOLOR uchar color; #endif }; extern const struct symdef defsyms[MAXPCHARS]; /* defaults */ extern uchar showsyms[MAXPCHARS]; extern const struct symdef def_warnsyms[WARNCOUNT]; /* * Graphics sets for display symbols */ #define ASCII_GRAPHICS 0 /* regular characters: '-', '+', &c */ #define IBM_GRAPHICS 1 /* PC graphic characters */ #define DEC_GRAPHICS 2 /* VT100 line drawing characters */ #define MAC_GRAPHICS 3 /* Macintosh drawing characters */ /* * The 5 possible states of doors */ #define D_NODOOR 0 #define D_BROKEN 1 #define D_ISOPEN 2 #define D_CLOSED 4 #define D_LOCKED 8 #define D_TRAPPED 16 /* * Some altars are considered as shrines, so we need a flag. */ #define AM_SHRINE 8 /* * Thrones should only be looted once. */ #define T_LOOTED 1 /* * Trees have more than one kick result. */ #define TREE_LOOTED 1 #define TREE_SWARM 2 /* * Fountains have limits, and special warnings. */ #define F_LOOTED 1 #define F_WARNED 2 #define FOUNTAIN_IS_WARNED(x,y) (levl[x][y].looted & F_WARNED) #define FOUNTAIN_IS_LOOTED(x,y) (levl[x][y].looted & F_LOOTED) #define SET_FOUNTAIN_WARNED(x,y) levl[x][y].looted |= F_WARNED; #define SET_FOUNTAIN_LOOTED(x,y) levl[x][y].looted |= F_LOOTED; #define CLEAR_FOUNTAIN_WARNED(x,y) levl[x][y].looted &= ~F_WARNED; #define CLEAR_FOUNTAIN_LOOTED(x,y) levl[x][y].looted &= ~F_LOOTED; /* * Doors are even worse :-) The special warning has a side effect * of instantly trapping the door, and if it was defined as trapped, * the guards consider that you have already been warned! */ #define D_WARNED 16 /* * Sinks have 3 different types of loot that shouldn't be abused */ #define S_LPUDDING 1 #define S_LDWASHER 2 #define S_LRING 4 /* * The four directions for a DrawBridge. */ #define DB_NORTH 0 #define DB_SOUTH 1 #define DB_EAST 2 #define DB_WEST 3 #define DB_DIR 3 /* mask for direction */ /* * What's under a drawbridge. */ #define DB_MOAT 0 #define DB_LAVA 4 #define DB_ICE 8 #define DB_FLOOR 16 #define DB_UNDER 28 /* mask for underneath */ /* * Wall information. */ #define WM_MASK 0x07 /* wall mode (bottom three bits) */ #define W_NONDIGGABLE 0x08 #define W_NONPASSWALL 0x10 /* * Ladders (in Vlad's tower) may be up or down. */ #define LA_UP 1 #define LA_DOWN 2 /* * Room areas may be iced pools */ #define ICED_POOL 8 #define ICED_MOAT 16 /* * The structure describing a coordinate position. * Before adding fields, remember that this will significantly affect * the size of temporary files and save files. */ struct rm { int glyph; /* what the hero thinks is there */ schar typ; /* what is really there */ uchar seenv; /* seen vector */ Bitfield(flags,5); /* extra information for typ */ Bitfield(horizontal,1); /* wall/door/etc is horiz. (more typ info) */ Bitfield(lit,1); /* speed hack for lit rooms */ Bitfield(waslit,1); /* remember if a location was lit */ Bitfield(roomno,6); /* room # for special rooms */ Bitfield(edge,1); /* marks boundaries for special rooms*/ }; /* * Add wall angle viewing by defining "modes" for each wall type. Each * mode describes which parts of a wall are finished (seen as as wall) * and which are unfinished (seen as rock). * * We use the bottom 3 bits of the flags field for the mode. This comes * in conflict with secret doors, but we avoid problems because until * a secret door becomes discovered, we know what sdoor's bottom three * bits are. * * The following should cover all of the cases. * * type mode Examples: R=rock, F=finished * ----- ---- ---------------------------- * WALL: 0 none hwall, mode 1 * 1 left/top (1/2 rock) RRR * 2 right/bottom (1/2 rock) --- * FFF * * CORNER: 0 none trcorn, mode 2 * 1 outer (3/4 rock) FFF * 2 inner (1/4 rock) F+- * F|R * * TWALL: 0 none tlwall, mode 3 * 1 long edge (1/2 rock) F|F * 2 bottom left (on a tdwall) -+F * 3 bottom right (on a tdwall) R|F * * CRWALL: 0 none crwall, mode 5 * 1 top left (1/4 rock) R|F * 2 top right (1/4 rock) -+- * 3 bottom left (1/4 rock) F|R * 4 bottom right (1/4 rock) * 5 top left & bottom right (1/2 rock) * 6 bottom left & top right (1/2 rock) */ #define WM_W_LEFT 1 /* vertical or horizontal wall */ #define WM_W_RIGHT 2 #define WM_W_TOP WM_W_LEFT #define WM_W_BOTTOM WM_W_RIGHT #define WM_C_OUTER 1 /* corner wall */ #define WM_C_INNER 2 #define WM_T_LONG 1 /* T wall */ #define WM_T_BL 2 #define WM_T_BR 3 #define WM_X_TL 1 /* cross wall */ #define WM_X_TR 2 #define WM_X_BL 3 #define WM_X_BR 4 #define WM_X_TLBR 5 #define WM_X_BLTR 6 /* * Seen vector values. The seen vector is an array of 8 bits, one for each * octant around a given center x: * * 0 1 2 * 7 x 3 * 6 5 4 * * In the case of walls, a single wall square can be viewed from 8 possible * directions. If we know the type of wall and the directions from which * it has been seen, then we can determine what it looks like to the hero. */ #define SV0 0x1 #define SV1 0x2 #define SV2 0x4 #define SV3 0x8 #define SV4 0x10 #define SV5 0x20 #define SV6 0x40 #define SV7 0x80 #define SVALL 0xFF #define doormask flags #define altarmask flags #define wall_info flags #define ladder flags #define drawbridgemask flags #define looted flags #define icedpool flags #define blessedftn horizontal /* a fountain that grants attribs */ #define disturbed horizontal /* a grave that has been disturbed */ struct damage { struct damage *next; long when, cost; coord place; schar typ; }; struct levelflags { uchar nfountains; /* number of fountains on level */ uchar nsinks; /* number of sinks on the level */ /* Several flags that give hints about what's on the level */ Bitfield(has_shop, 1); Bitfield(has_vault, 1); Bitfield(has_zoo, 1); Bitfield(has_court, 1); Bitfield(has_morgue, 1); Bitfield(has_beehive, 1); Bitfield(has_barracks, 1); Bitfield(has_temple, 1); Bitfield(has_swamp, 1); Bitfield(noteleport,1); Bitfield(hardfloor,1); Bitfield(nommap,1); Bitfield(hero_memory,1); /* hero has memory */ Bitfield(shortsighted,1); /* monsters are shortsighted */ Bitfield(graveyard,1); /* has_morgue, but remains set */ Bitfield(is_maze_lev,1); Bitfield(is_cavernous_lev,1); Bitfield(arboreal, 1); /* Trees replace rock */ }; typedef struct { struct rm locations[COLNO][ROWNO]; #ifndef MICROPORT_BUG struct obj *objects[COLNO][ROWNO]; struct monst *monsters[COLNO][ROWNO]; #else struct obj *objects[1][ROWNO]; char *yuk1[COLNO-1][ROWNO]; struct monst *monsters[1][ROWNO]; char *yuk2[COLNO-1][ROWNO]; #endif struct obj *objlist; struct obj *buriedobjlist; struct monst *monlist; struct damage *damagelist; struct levelflags flags; } dlevel_t; extern dlevel_t level; /* structure describing the current level */ /* * Macros for compatibility with old code. Someday these will go away. */ #define levl level.locations #define fobj level.objlist #define fmon level.monlist /* * Covert a trap number into the defsym graphics array. * Convert a defsym number into a trap number. * Assumes that arrow trap will always be the first trap. */ #define trap_to_defsym(t) (S_arrow_trap+(t)-1) #define defsym_to_trap(d) ((d)-S_arrow_trap+1) #define OBJ_AT(x,y) (level.objects[x][y] != (struct obj *)0) /* * Macros for encapsulation of level.monsters references. */ #define MON_AT(x,y) (level.monsters[x][y] != (struct monst *)0 && \ !(level.monsters[x][y])->mburied) #define MON_BURIED_AT(x,y) (level.monsters[x][y] != (struct monst *)0 && \ (level.monsters[x][y])->mburied) #ifndef STEED #define place_monster(m,x,y) ((m)->mx=(x),(m)->my=(y),\ level.monsters[(m)->mx][(m)->my]=(m)) #endif #define place_worm_seg(m,x,y) level.monsters[x][y] = m #define remove_monster(x,y) level.monsters[x][y] = (struct monst *)0 #define m_at(x,y) (MON_AT(x,y) ? level.monsters[x][y] : \ (struct monst *)0) #define m_buried_at(x,y) (MON_BURIED_AT(x,y) ? level.monsters[x][y] : \ (struct monst *)0) #endif /* RM_H */ nethack-3.4.3/include/skills.h0100644000000000000000000000745707764735041014764 0ustar rootroot/* SCCS Id: @(#)skills.h 3.4 1999/10/27 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SKILLS_H #define SKILLS_H /* Much of this code was taken from you.h. It is now * in a separate file so it can be included in objects.c. */ /* Code to denote that no skill is applicable */ #define P_NONE 0 /* Weapon Skills -- Stephen White * Order matters and are used in macros. * Positive values denote hand-to-hand weapons or launchers. * Negative values denote ammunition or missiles. * Update weapon.c if you ammend any skills. * Also used for oc_subtyp. */ #define P_DAGGER 1 #define P_KNIFE 2 #define P_AXE 3 #define P_PICK_AXE 4 #define P_SHORT_SWORD 5 #define P_BROAD_SWORD 6 #define P_LONG_SWORD 7 #define P_TWO_HANDED_SWORD 8 #define P_SCIMITAR 9 #define P_SABER 10 #define P_CLUB 11 /* Heavy-shafted bludgeon */ #define P_MACE 12 #define P_MORNING_STAR 13 /* Spiked bludgeon */ #define P_FLAIL 14 /* Two pieces hinged or chained together */ #define P_HAMMER 15 /* Heavy head on the end */ #define P_QUARTERSTAFF 16 /* Long-shafted bludgeon */ #define P_POLEARMS 17 #define P_SPEAR 18 #define P_JAVELIN 19 #define P_TRIDENT 20 #define P_LANCE 21 #define P_BOW 22 #define P_SLING 23 #define P_CROSSBOW 24 #define P_DART 25 #define P_SHURIKEN 26 #define P_BOOMERANG 27 #define P_WHIP 28 #define P_UNICORN_HORN 29 /* last weapon */ #define P_FIRST_WEAPON P_DAGGER #define P_LAST_WEAPON P_UNICORN_HORN /* Spell Skills added by Larry Stewart-Zerba */ #define P_ATTACK_SPELL 30 #define P_HEALING_SPELL 31 #define P_DIVINATION_SPELL 32 #define P_ENCHANTMENT_SPELL 33 #define P_CLERIC_SPELL 34 #define P_ESCAPE_SPELL 35 #define P_MATTER_SPELL 36 #define P_FIRST_SPELL P_ATTACK_SPELL #define P_LAST_SPELL P_MATTER_SPELL /* Other types of combat */ #define P_BARE_HANDED_COMBAT 37 #define P_MARTIAL_ARTS P_BARE_HANDED_COMBAT /* Role distinguishes */ #define P_TWO_WEAPON_COMBAT 38 /* Finally implemented */ #ifdef STEED #define P_RIDING 39 /* How well you control your steed */ #define P_LAST_H_TO_H P_RIDING #else #define P_LAST_H_TO_H P_TWO_WEAPON_COMBAT #endif #define P_FIRST_H_TO_H P_BARE_HANDED_COMBAT #define P_NUM_SKILLS (P_LAST_H_TO_H+1) /* These roles qualify for a martial arts bonus */ #define martial_bonus() (Role_if(PM_SAMURAI) || Role_if(PM_MONK)) /* * These are the standard weapon skill levels. It is important that * the lowest "valid" skill be be 1. The code calculates the * previous amount to practice by calling practice_needed_to_advance() * with the current skill-1. To work out for the UNSKILLED case, * a value of 0 needed. */ #define P_ISRESTRICTED 0 #define P_UNSKILLED 1 #define P_BASIC 2 #define P_SKILLED 3 #define P_EXPERT 4 #define P_MASTER 5 /* Unarmed combat/martial arts only */ #define P_GRAND_MASTER 6 /* Unarmed combat/martial arts only */ #define practice_needed_to_advance(level) ((level)*(level)*20) /* The hero's skill in various weapons. */ struct skills { xchar skill; xchar max_skill; unsigned short advance; }; #define P_SKILL(type) (u.weapon_skills[type].skill) #define P_MAX_SKILL(type) (u.weapon_skills[type].max_skill) #define P_ADVANCE(type) (u.weapon_skills[type].advance) #define P_RESTRICTED(type) (u.weapon_skills[type].skill == P_ISRESTRICTED) #define P_SKILL_LIMIT 60 /* Max number of skill advancements */ /* Initial skill matrix structure; used in u_init.c and weapon.c */ struct def_skill { xchar skill; xchar skmax; }; #endif /* SKILLS_H */ nethack-3.4.3/include/sp_lev.h0100644000000000000000000000766207764735041014751 0ustar rootroot/* SCCS Id: @(#)sp_lev.h 3.4 1996/05/08 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SP_LEV_H #define SP_LEV_H /* wall directions */ #define W_NORTH 1 #define W_SOUTH 2 #define W_EAST 4 #define W_WEST 8 #define W_ANY (W_NORTH|W_SOUTH|W_EAST|W_WEST) /* MAP limits */ #define MAP_X_LIM 76 #define MAP_Y_LIM 21 /* Per level flags */ #define NOTELEPORT 1 #define HARDFLOOR 2 #define NOMMAP 4 #define SHORTSIGHTED 8 #define ARBOREAL 16 /* special level types */ #define SP_LEV_ROOMS 1 #define SP_LEV_MAZE 2 /* * Structures manipulated by the special levels loader & compiler */ typedef union str_or_len { char *str; int len; } Str_or_Len; typedef struct { boolean init_present, padding; char fg, bg; boolean smoothed, joined; xchar lit, walled; } lev_init; typedef struct { xchar x, y, mask; } door; typedef struct { xchar wall, pos, secret, mask; } room_door; typedef struct { xchar x, y, chance, type; } trap; typedef struct { Str_or_Len name, appear_as; short id; aligntyp align; xchar x, y, chance, class, appear; schar peaceful, asleep; } monster; typedef struct { Str_or_Len name; int corpsenm; short id, spe; xchar x, y, chance, class, containment; schar curse_state; } object; typedef struct { xchar x, y; aligntyp align; xchar shrine; } altar; typedef struct { xchar x, y, dir, db_open; } drawbridge; typedef struct { xchar x, y, dir; } walk; typedef struct { xchar x1, y1, x2, y2; } digpos; typedef struct { xchar x, y, up; } lad; typedef struct { xchar x, y, up; } stair; typedef struct { xchar x1, y1, x2, y2; xchar rtype, rlit, rirreg; } region; /* values for rtype are defined in dungeon.h */ typedef struct { struct { xchar x1, y1, x2, y2; } inarea; struct { xchar x1, y1, x2, y2; } delarea; boolean in_islev, del_islev; xchar rtype, padding; Str_or_Len rname; } lev_region; typedef struct { xchar x, y; int amount; } gold; typedef struct { xchar x, y; Str_or_Len engr; xchar etype; } engraving; typedef struct { xchar x, y; } fountain; typedef struct { xchar x, y; } sink; typedef struct { xchar x, y; } pool; typedef struct { char halign, valign; char xsize, ysize; char **map; char nrobjects; char *robjects; char nloc; char *rloc_x; char *rloc_y; char nrmonst; char *rmonst; char nreg; region **regions; char nlreg; lev_region **lregions; char ndoor; door **doors; char ntrap; trap **traps; char nmonster; monster **monsters; char nobject; object **objects; char ndrawbridge; drawbridge **drawbridges; char nwalk; walk **walks; char ndig; digpos **digs; char npass; digpos **passs; char nlad; lad **lads; char nstair; stair **stairs; char naltar; altar **altars; char ngold; gold **golds; char nengraving; engraving **engravings; char nfountain; fountain **fountains; } mazepart; typedef struct { long flags; lev_init init_lev; schar filling; char numpart; mazepart **parts; } specialmaze; typedef struct _room { char *name; char *parent; xchar x, y, w, h; xchar xalign, yalign; xchar rtype, chance, rlit, filled; char ndoor; room_door **doors; char ntrap; trap **traps; char nmonster; monster **monsters; char nobject; object **objects; char naltar; altar **altars; char nstair; stair **stairs; char ngold; gold **golds; char nengraving; engraving **engravings; char nfountain; fountain **fountains; char nsink; sink **sinks; char npool; pool **pools; /* These three fields are only used when loading the level... */ int nsubroom; struct _room *subrooms[MAX_SUBROOMS]; struct mkroom *mkr; } room; typedef struct { struct { xchar room; xchar wall; xchar door; } src, dest; } corridor; /* used only by lev_comp */ typedef struct { long flags; lev_init init_lev; char nrobjects; char *robjects; char nrmonst; char *rmonst; xchar nroom; room **rooms; xchar ncorr; corridor **corrs; } splev; #endif /* SP_LEV_H */ nethack-3.4.3/include/spell.h0100644000000000000000000000114207764735041014563 0ustar rootroot/* SCCS Id: @(#)spell.h 3.4 1995/06/01 */ /* Copyright 1986, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SPELL_H #define SPELL_H struct spell { short sp_id; /* spell id (== object.otyp) */ xchar sp_lev; /* power level */ int sp_know; /* knowlege of spell */ }; /* levels of memory destruction with a scroll of amnesia */ #define ALL_MAP 0x1 #define ALL_SPELLS 0x2 #define decrnknow(spell) spl_book[spell].sp_know-- #define spellid(spell) spl_book[spell].sp_id #define spellknow(spell) spl_book[spell].sp_know #endif /* SPELL_H */ nethack-3.4.3/include/system.h0100644000000000000000000003612307764735041014777 0ustar rootroot/* SCCS Id: @(#)system.h 3.4 2001/12/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef SYSTEM_H #define SYSTEM_H #if !defined(__cplusplus) && !defined(__GO32__) #define E extern /* some old may not define off_t and size_t; if your system is * one of these, define them by hand below */ #if (defined(VMS) && !defined(__GNUC__)) || defined(MAC) #include #else # ifndef AMIGA #include # endif #endif #if (defined(MICRO) && !defined(TOS)) || defined(ANCIENT_VAXC) # if !defined(_SIZE_T) && !defined(__size_t) /* __size_t for CSet/2 */ # define _SIZE_T # if !((defined(MSDOS) || defined(OS2)) && defined(_SIZE_T_DEFINED)) /* MSC 5.1 */ # if !(defined(__GNUC__) && defined(AMIGA)) typedef unsigned int size_t; # endif # endif # endif #endif /* MICRO && !TOS */ #if defined(__TURBOC__) || defined(MAC) #include /* time_t is not in */ #endif #if defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC)) /* The Ultrix v3.0 seems to be very wrong. */ # define time_t long #endif #if defined(ULTRIX) || defined(VMS) # define off_t long #endif #if defined(AZTEC) || defined(THINKC4) || defined(__TURBOC__) typedef long off_t; #endif #endif /* !__cplusplus && !__GO32__ */ /* You may want to change this to fit your system, as this is almost * impossible to get right automatically. * This is the type of signal handling functions. */ #if !defined(OS2) && (defined(_MSC_VER) || defined(__TURBOC__) || defined(__SC__) || defined(WIN32)) # define SIG_RET_TYPE void (__cdecl *)(int) #endif #ifndef SIG_RET_TYPE # if defined(NHSTDC) || defined(POSIX_TYPES) || defined(OS2) || defined(__DECC) # define SIG_RET_TYPE void (*)() # endif #endif #ifndef SIG_RET_TYPE # if defined(ULTRIX) || defined(SUNOS4) || defined(SVR3) || defined(SVR4) /* SVR3 is defined automatically by some systems */ # define SIG_RET_TYPE void (*)() # endif #endif #ifndef SIG_RET_TYPE /* BSD, SIII, SVR2 and earlier, Sun3.5 and earlier */ # define SIG_RET_TYPE int (*)() #endif #if !defined(__cplusplus) && !defined(__GO32__) #if defined(BSD) || defined(ULTRIX) || defined(RANDOM) # ifdef random # undef random # endif # if !defined(__SC__) && !defined(LINUX) E long NDECL(random); # endif # if (!defined(SUNOS4) && !defined(bsdi) && !defined(__FreeBSD__)) || defined(RANDOM) E void FDECL(srandom, (unsigned int)); # else # if !defined(bsdi) && !defined(__FreeBSD__) E int FDECL(srandom, (unsigned int)); # endif # endif #else E long lrand48(); E void srand48(); #endif /* BSD || ULTRIX || RANDOM */ #if !defined(BSD) || defined(ultrix) /* real BSD wants all these to return int */ # ifndef MICRO E void FDECL(exit, (int)); # endif /* MICRO */ /* compensate for some CSet/2 bogosities */ # if defined(OS2_CSET2) && defined(OS2_CSET2_VER_2) # define open _open # define close _close # define read _read # define write _write # define lseek _lseek # define chdir _chdir # define getcwd _getcwd # define setmode _setmode # endif /* OS2_CSET2 && OS2_CSET2_VER_2 */ /* If flex thinks that we're not __STDC__ it declares free() to return int and we die. We must use __STDC__ instead of NHSTDC because the former is naturally what flex tests for. */ # if defined(__STDC__) || !defined(FLEX_SCANNER) # ifndef OS2_CSET2 # ifndef MONITOR_HEAP E void FDECL(free, (genericptr_t)); # endif # endif # endif #if !defined(__SASC_60) && !defined(_DCC) && !defined(__SC__) # if defined(AMIGA) && !defined(AZTEC_50) && !defined(__GNUC__) E int FDECL(perror, (const char *)); # else # if !(defined(ULTRIX_PROTO) && defined(__GNUC__)) E void FDECL(perror, (const char *)); # endif # endif #endif #endif #ifndef NeXT #ifdef POSIX_TYPES E void FDECL(qsort, (genericptr_t,size_t,size_t, int(*)(const genericptr,const genericptr))); #else # if defined(BSD) || defined(ULTRIX) E int qsort(); # else # if !defined(LATTICE) && !defined(AZTEC_50) E void FDECL(qsort, (genericptr_t,size_t,size_t, int(*)(const genericptr,const genericptr))); # endif # endif #endif #endif /* NeXT */ #ifndef __SASC_60 #if !defined(AZTEC_50) && !defined(__GNUC__) /* may already be defined */ # ifdef ULTRIX # ifdef ULTRIX_PROTO E int FDECL(lseek, (int,off_t,int)); # else E long FDECL(lseek, (int,off_t,int)); # endif /* Ultrix 3.0 man page mistakenly says it returns an int. */ E int FDECL(write, (int,char *,int)); E int FDECL(link, (const char *, const char*)); # else # ifndef bsdi E long FDECL(lseek, (int,long,int)); # endif # if defined(POSIX_TYPES) || defined(__TURBOC__) # ifndef bsdi E int FDECL(write, (int, const void *,unsigned)); # endif # else # ifndef __MWERKS__ /* metrowerks defines write via universal headers */ E int FDECL(write, (int,genericptr_t,unsigned)); # endif # endif # endif /* ULTRIX */ # ifdef OS2_CSET2 /* IBM CSet/2 */ # ifdef OS2_CSET2_VER_1 E int FDECL(unlink, (char *)); # else E int FDECL(unlink, (const char *)); /* prototype is ok in ver >= 2 */ # endif # else # ifndef __SC__ E int FDECL(unlink, (const char *)); # endif # endif #endif /* AZTEC_50 && __GNUC__ */ #ifdef MAC #ifndef __CONDITIONALMACROS__ /* universal headers */ E int FDECL(close, (int)); /* unistd.h */ E int FDECL(read, (int, char *, int)); /* unistd.h */ E int FDECL(chdir, (const char *)); /* unistd.h */ E char *FDECL(getcwd, (char *,int)); /* unistd.h */ #endif E int FDECL(open, (const char *,int)); #endif #if defined(MICRO) E int FDECL(close, (int)); #ifndef __EMX__ E int FDECL(read, (int,genericptr_t,unsigned int)); #endif E int FDECL(open, (const char *,int,...)); E int FDECL(dup2, (int, int)); E int FDECL(setmode, (int,int)); E int NDECL(kbhit); # if !defined(_DCC) # if defined(__TURBOC__) E int FDECL(chdir, (const char *)); # else # ifndef __EMX__ E int FDECL(chdir, (char *)); # endif # endif # ifndef __EMX__ E char *FDECL(getcwd, (char *,int)); # endif # endif /* !_DCC */ #endif #ifdef ULTRIX E int FDECL(close, (int)); E int FDECL(atoi, (const char *)); E int FDECL(chdir, (const char *)); # if !defined(ULTRIX_CC20) && !defined(__GNUC__) E int FDECL(chmod, (const char *,int)); E mode_t FDECL(umask, (int)); # endif E int FDECL(read, (int,genericptr_t,unsigned)); /* these aren't quite right, but this saves including lots of system files */ E int FDECL(stty, (int,genericptr_t)); E int FDECL(gtty, (int,genericptr_t)); E int FDECL(ioctl, (int, int, char*)); E int FDECL(isatty, (int)); /* 1==yes, 0==no, -1==error */ #include # if defined(ULTRIX_PROTO) || defined(__GNUC__) E int NDECL(fork); # else E long NDECL(fork); # endif #endif /* ULTRIX */ #ifdef VMS # ifndef abs E int FDECL(abs, (int)); # endif E int FDECL(atexit, (void (*)(void))); E int FDECL(atoi, (const char *)); E int FDECL(chdir, (const char *)); E int FDECL(chown, (const char *,unsigned,unsigned)); # ifdef __DECC_VER E int FDECL(chmod, (const char *,mode_t)); E mode_t FDECL(umask, (mode_t)); # else E int FDECL(chmod, (const char *,int)); E int FDECL(umask, (int)); # endif /* #include */ E int FDECL(close, (int)); E int VDECL(creat, (const char *,unsigned,...)); E int FDECL(delete, (const char *)); E int FDECL(fstat, ( /*_ int, stat_t * _*/ )); E int FDECL(isatty, (int)); /* 1==yes, 0==no, -1==error */ E long FDECL(lseek, (int,long,int)); E int VDECL(open, (const char *,int,unsigned,...)); E int FDECL(read, (int,genericptr_t,unsigned)); E int FDECL(rename, (const char *,const char *)); E int FDECL(stat, ( /*_ const char *,stat_t * _*/ )); E int FDECL(write, (int,const genericptr,unsigned)); #endif #endif /* __SASC_60 */ /* both old & new versions of Ultrix want these, but real BSD does not */ #ifdef ultrix E void abort(); E void bcopy(); # ifdef ULTRIX E int FDECL(system, (const char *)); # ifndef _UNISTD_H_ E int FDECL(execl, (const char *, ...)); # endif # endif #endif #ifdef MICRO E void NDECL(abort); E void FDECL(_exit, (int)); E int FDECL(system, (const char *)); #endif #if defined(HPUX) && !defined(_POSIX_SOURCE) E long NDECL(fork); #endif #ifdef POSIX_TYPES /* The POSIX string.h is required to define all the mem* and str* functions */ #include #else #if defined(SYSV) || defined(VMS) || defined(MAC) || defined(SUNOS4) # if defined(NHSTDC) || (defined(VMS) && !defined(ANCIENT_VAXC)) # if !defined(_AIX32) && !(defined(SUNOS4) && defined(__STDC__)) /* Solaris unbundled cc (acc) */ E int FDECL(memcmp, (const void *,const void *,size_t)); E void *FDECL(memcpy, (void *, const void *, size_t)); E void *FDECL(memset, (void *, int, size_t)); # endif # else # ifndef memcmp /* some systems seem to macro these back to b*() */ E int memcmp(); # endif # ifndef memcpy E char *memcpy(); # endif # ifndef memset E char *memset(); # endif # endif #else # ifdef HPUX E int FDECL(memcmp, (char *,char *,int)); E void *FDECL(memcpy, (char *,char *,int)); E void *FDECL(memset, (char*,int,int)); # endif #endif #endif /* POSIX_TYPES */ #if defined(MICRO) && !defined(LATTICE) # if defined(TOS) && defined(__GNUC__) E int FDECL(memcmp, (const void *,const void *,size_t)); E void *FDECL(memcpy, (void *,const void *,size_t)); E void *FDECL(memset, (void *,int,size_t)); # else # if defined(AZTEC_50) || defined(NHSTDC) || defined(WIN32) E int FDECL(memcmp, (const void *, const void *, size_t)); E void *FDECL(memcpy, (void *, const void *, size_t)); E void *FDECL(memset, (void *, int, size_t)); # else E int FDECL(memcmp, (char *,char *,unsigned int)); E char *FDECL(memcpy, (char *,char *,unsigned int)); E char *FDECL(memset, (char*,int,int)); # endif /* AZTEC_50 || NHSTDC */ # endif /* TOS */ #endif /* MICRO */ #if defined(BSD) && defined(ultrix) /* i.e., old versions of Ultrix */ E void sleep(); #endif #if defined(ULTRIX) || defined(SYSV) E unsigned sleep(); #endif #if defined(HPUX) E unsigned int FDECL(sleep, (unsigned int)); #endif #ifdef VMS E int FDECL(sleep, (unsigned)); #endif E char *FDECL(getenv, (const char *)); E char *getlogin(); #if defined(HPUX) && !defined(_POSIX_SOURCE) E long NDECL(getuid); E long NDECL(getgid); E long NDECL(getpid); #else # ifdef POSIX_TYPES E pid_t NDECL(getpid); E uid_t NDECL(getuid); E gid_t NDECL(getgid); # ifdef VMS E pid_t NDECL(getppid); # endif # else /*!POSIX_TYPES*/ # ifndef getpid /* Borland C defines getpid() as a macro */ E int NDECL(getpid); # endif # ifdef VMS E int NDECL(getppid); E unsigned NDECL(getuid); E unsigned NDECL(getgid); # endif # if defined(ULTRIX) && !defined(_UNISTD_H_) E unsigned NDECL(getuid); E unsigned NDECL(getgid); E int FDECL(setgid, (int)); E int FDECL(setuid, (int)); # endif # endif /*?POSIX_TYPES*/ #endif /*?(HPUX && !_POSIX_SOURCE)*/ /* add more architectures as needed */ #if defined(HPUX) #define seteuid(x) setreuid(-1, (x)); #endif /*# string(s).h #*/ #if !defined(_XtIntrinsic_h) && !defined(POSIX_TYPES) /* #includes ; so does defining POSIX_TYPES */ #if (defined(ULTRIX) || defined(NeXT)) && defined(__GNUC__) #include #else E char *FDECL(strcpy, (char *,const char *)); E char *FDECL(strncpy, (char *,const char *,size_t)); E char *FDECL(strcat, (char *,const char *)); E char *FDECL(strncat, (char *,const char *,size_t)); E char *FDECL(strpbrk, (const char *,const char *)); # if defined(SYSV) || defined(MICRO) || defined(MAC) || defined(VMS) || defined(HPUX) E char *FDECL(strchr, (const char *,int)); E char *FDECL(strrchr, (const char *,int)); # else /* BSD */ E char *FDECL(index, (const char *,int)); E char *FDECL(rindex, (const char *,int)); # endif E int FDECL(strcmp, (const char *,const char *)); E int FDECL(strncmp, (const char *,const char *,size_t)); # if defined(MICRO) || defined(MAC) || defined(VMS) E size_t FDECL(strlen, (const char *)); # else # ifdef HPUX E unsigned int FDECL(strlen, (char *)); # else # if !(defined(ULTRIX_PROTO) && defined(__GNUC__)) E int FDECL(strlen, (const char *)); # endif # endif /* HPUX */ # endif /* MICRO */ #endif /* ULTRIX */ #endif /* !_XtIntrinsic_h_ && !POSIX_TYPES */ #if defined(ULTRIX) && defined(__GNUC__) E char *FDECL(index, (const char *,int)); E char *FDECL(rindex, (const char *,int)); #endif /* Old varieties of BSD have char *sprintf(). * Newer varieties of BSD have int sprintf() but allow for the old char *. * Several varieties of SYSV and PC systems also have int sprintf(). * If your system doesn't agree with this breakdown, you may want to change * this declaration, especially if your machine treats the types differently. * If your system defines sprintf, et al, in stdio.h, add to the initial * #if. */ #if defined(ULTRIX) || defined(__DECC) || defined(__SASC_60) || defined(WIN32) #define SPRINTF_PROTO #endif #if (defined(SUNOS4) && defined(__STDC__)) || defined(_AIX32) #define SPRINTF_PROTO #endif #if defined(TOS) || defined(AZTEC_50) || defined(__sgi) || defined(__GNUC__) /* problem with prototype mismatches */ #define SPRINTF_PROTO #endif #if defined(__MWERKS__) || defined(__SC__) /* Metrowerks already has a prototype for sprintf() */ # define SPRINTF_PROTO #endif #ifndef SPRINTF_PROTO # if defined(POSIX_TYPES) || defined(DGUX) || defined(NeXT) || !defined(BSD) E int FDECL(sprintf, (char *,const char *,...)); # else # define OLD_SPRINTF E char *sprintf(); # endif #endif #ifdef SPRINTF_PROTO # undef SPRINTF_PROTO #endif #ifndef __SASC_60 #ifdef NEED_VARARGS # if defined(USE_STDARG) || defined(USE_VARARGS) # if !defined(SVR4) && !defined(apollo) # if !(defined(ULTRIX_PROTO) && defined(__GNUC__)) # if !(defined(SUNOS4) && defined(__STDC__)) /* Solaris unbundled cc (acc) */ E int FDECL(vsprintf, (char *, const char *, va_list)); E int FDECL(vfprintf, (FILE *, const char *, va_list)); E int FDECL(vprintf, (const char *, va_list)); # endif # endif # endif # else # define vprintf printf # define vfprintf fprintf # define vsprintf sprintf # endif #endif /* NEED_VARARGS */ #endif #ifdef MICRO E int FDECL(tgetent, (const char *,const char *)); E void FDECL(tputs, (const char *,int,int (*)())); E int FDECL(tgetnum, (const char *)); E int FDECL(tgetflag, (const char *)); E char *FDECL(tgetstr, (const char *,char **)); E char *FDECL(tgoto, (const char *,int,int)); #else # if ! (defined(HPUX) && defined(_POSIX_SOURCE)) E int FDECL(tgetent, (char *,const char *)); E void FDECL(tputs, (const char *,int,int (*)())); # endif E int FDECL(tgetnum, (const char *)); E int FDECL(tgetflag, (const char *)); E char *FDECL(tgetstr, (const char *,char **)); E char *FDECL(tgoto, (const char *,int,int)); #endif #ifdef ALLOC_C E genericptr_t FDECL(malloc, (size_t)); #endif /* time functions */ # ifndef LATTICE # if !(defined(ULTRIX_PROTO) && defined(__GNUC__)) E struct tm *FDECL(localtime, (const time_t *)); # endif # endif # if defined(ULTRIX) || (defined(BSD) && defined(POSIX_TYPES)) || defined(SYSV) || defined(MICRO) || defined(VMS) || defined(MAC) || (defined(HPUX) && defined(_POSIX_SOURCE)) E time_t FDECL(time, (time_t *)); # else E long FDECL(time, (time_t *)); # endif /* ULTRIX */ #ifdef VMS /* used in makedefs.c, but missing from gcc-vms's */ E char *FDECL(ctime, (const time_t *)); #endif #ifdef MICRO # ifdef abs # undef abs # endif E int FDECL(abs, (int)); # ifdef atoi # undef atoi # endif E int FDECL(atoi, (const char *)); #endif #undef E #endif /* !__cplusplus && !__GO32__ */ #endif /* SYSTEM_H */ nethack-3.4.3/include/tcap.h0100644000000000000000000000304307764735041014375 0ustar rootroot/* SCCS Id: @(#)tcap.h 3.4 1992/10/21 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1989. */ /* NetHack may be freely redistributed. See license for details. */ /* not named termcap.h because it may conflict with a system header */ #ifndef TCAP_H #define TCAP_H #ifndef MICRO # define TERMLIB /* include termcap code */ #endif /* might display need graphics code? */ #if !defined(AMIGA) && !defined(TOS) && !defined(MAC) # if defined(TERMLIB) || defined(OS2) || defined(MSDOS) # define ASCIIGRAPH # endif #endif #ifndef DECL_H extern struct tc_gbl_data { /* also declared in decl.h; defined in decl.c */ char *tc_AS, *tc_AE; /* graphics start and end (tty font swapping) */ int tc_LI, tc_CO; /* lines and columns */ } tc_gbl_data; #define AS tc_gbl_data.tc_AS #define AE tc_gbl_data.tc_AE #define LI tc_gbl_data.tc_LI #define CO tc_gbl_data.tc_CO #endif extern struct tc_lcl_data { /* defined and set up in termcap.c */ char *tc_CM, *tc_ND, *tc_CD; char *tc_HI, *tc_HE, *tc_US, *tc_UE; boolean tc_ul_hack; } tc_lcl_data; /* some curses.h declare CM etc. */ #define nh_CM tc_lcl_data.tc_CM #define nh_ND tc_lcl_data.tc_ND #define nh_CD tc_lcl_data.tc_CD #define nh_HI tc_lcl_data.tc_HI #define nh_HE tc_lcl_data.tc_HE #define nh_US tc_lcl_data.tc_US #define nh_UE tc_lcl_data.tc_UE #define ul_hack tc_lcl_data.tc_ul_hack extern short ospeed; /* set up in termcap.c */ #ifdef TEXTCOLOR # ifdef TOS extern const char *hilites[CLR_MAX]; # else extern NEARDATA char *hilites[CLR_MAX]; # endif #endif #endif /* TCAP_H */ nethack-3.4.3/include/tile2x11.h0100644000000000000000000000076307764735041015025 0ustar rootroot/* SCCS Id: @(#)tile2x11.h 3.4 1995/01/25 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef TILE2X11_H #define TILE2X11_H /* * Header for the x11 tile map. */ typedef struct { unsigned long version; unsigned long ncolors; unsigned long tile_width; unsigned long tile_height; unsigned long ntiles; unsigned long per_row; } x11_header; /* how wide each row in the tile file is, in tiles */ #define TILES_PER_ROW (40) #endif /* TILE2X11_H */ nethack-3.4.3/include/timeout.h0100644000000000000000000000264507764735041015143 0ustar rootroot/* SCCS Id: @(#)timeout.h 3.4 1999/02/13 */ /* Copyright 1994, Dean Luick */ /* NetHack may be freely redistributed. See license for details. */ #ifndef TIMEOUT_H #define TIMEOUT_H /* generic timeout function */ typedef void FDECL((*timeout_proc), (genericptr_t, long)); /* kind of timer */ #define TIMER_LEVEL 0 /* event specific to level */ #define TIMER_GLOBAL 1 /* event follows current play */ #define TIMER_OBJECT 2 /* event follows a object */ #define TIMER_MONSTER 3 /* event follows a monster */ /* save/restore timer ranges */ #define RANGE_LEVEL 0 /* save/restore timers staying on level */ #define RANGE_GLOBAL 1 /* save/restore timers following global play */ /* * Timeout functions. Add a define here, then put it in the table * in timeout.c. "One more level of indirection will fix everything." */ #define ROT_ORGANIC 0 /* for buried organics */ #define ROT_CORPSE 1 #define REVIVE_MON 2 #define BURN_OBJECT 3 #define HATCH_EGG 4 #define FIG_TRANSFORM 5 #define NUM_TIME_FUNCS 6 /* used in timeout.c */ typedef struct fe { struct fe *next; /* next item in chain */ long timeout; /* when we time out */ unsigned long tid; /* timer ID */ short kind; /* kind of use */ short func_index; /* what to call when we time out */ genericptr_t arg; /* pointer to timeout argument */ Bitfield (needs_fixup,1); /* does arg need to be patched? */ } timer_element; #endif /* TIMEOUT_H */ nethack-3.4.3/include/tosconf.h0100644000000000000000000000407507764735041015127 0ustar rootroot/* SCCS Id: @(#)tosconf.h 3.2 90/02/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef TOS #ifndef TOSCONF_H #define TOSCONF_H #define MICRO /* must be defined to allow some inclusions */ /* Adjust these options to suit your compiler. The default here is for GNU C with the MiNT library. */ /*#define NO_SIGNAL /* library doesn't support signals */ /*#define NO_FSTAT /* library doesn't have fstat() call */ #define MINT /* library supports MiNT extensions to TOS */ #ifdef __MINT__ #define MINT #endif #ifdef O_BINARY #define FCMASK O_BINARY #else #define FCMASK 0660 #define O_BINARY 0 #endif #ifdef UNIXDEBUG #define remove(x) unlink(x) #endif /* configurable options */ #define MFLOPPY /* floppy support */ #define RANDOM /* improved random numbers */ #define SHELL /* allow spawning of shell */ #define TERMLIB /* use termcap */ #define TEXTCOLOR /* allow color */ #define MAIL /* enable the fake maildemon */ #ifdef MINT #define SUSPEND /* allow suspending the game */ #endif #ifndef TERMLIB #define ANSI_DEFAULT /* use vt52 by default */ #endif #if defined(__GNUC__) || defined(__MINT__) /* actually, only more recent GNU C libraries have strcmpi * on the other hand, they're free -- if yours is out of * date, grab the most recent from atari.archive.umich.edu */ #define STRNCMPI #undef strcmpi extern int FDECL(strcmpi,(const char *, const char *)); extern int FDECL(strncmpi,(const char *, const char *, size_t)); #endif #include #include /* instead of including system.h from pcconf.h */ #include #include #include #define SIG_RET_TYPE __Sigfunc #define SYSTEM_H #ifndef MICRO_H #include "micro.h" #endif #ifndef PCCONF_H #include "pcconf.h" /* remainder of stuff is same as the PC */ #endif #ifdef TEXTCOLOR extern boolean colors_changed; /* in tos.c */ #endif #ifdef __GNUC__ #define GCC_BUG /* correct a gcc bug involving double for loops */ #endif #endif /* TOSCONF_H */ #endif /* TOS */ nethack-3.4.3/include/tradstdc.h0100644000000000000000000002005007764735041015253 0ustar rootroot/* SCCS Id: @(#)tradstdc.h 3.4 1993/05/30 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef TRADSTDC_H #define TRADSTDC_H #if defined(DUMB) && !defined(NOVOID) #define NOVOID #endif #ifdef NOVOID #define void int #endif /* * Borland C provides enough ANSI C compatibility in its Borland C++ * mode to warrant this. But it does not set __STDC__ unless it compiles * in its ANSI keywords only mode, which prevents use of and * far pointer use. */ #if (defined(__STDC__) || defined(__TURBOC__)) && !defined(NOTSTDC) #define NHSTDC #endif #if defined(ultrix) && defined(__STDC__) && !defined(__LANGUAGE_C) /* Ultrix seems to be in a constant state of flux. This check attempts to * set up ansi compatibility if it wasn't set up correctly by the compiler. */ #ifdef mips #define __mips mips #endif #ifdef LANGUAGE_C #define __LANGUAGE_C LANGUAGE_C #endif #endif /* * ANSI X3J11 detection. * Makes substitutes for compatibility with the old C standard. */ /* Decide how to handle variable parameter lists: * USE_STDARG means use the ANSI facilities (only ANSI compilers * should do this, and only if the library supports it). * USE_VARARGS means use the facilities. Again, this should only * be done if the library supports it. ANSI is *not* required for this. * Otherwise, the kludgy old methods are used. * The defaults are USE_STDARG for ANSI compilers, and USE_OLDARGS for * others. */ /* #define USE_VARARGS */ /* use instead of */ /* #define USE_OLDARGS */ /* don't use any variable argument facilites */ #if defined(apollo) /* Apollos have stdarg(3) but not stdarg.h */ # define USE_VARARGS #endif #if defined(NHSTDC) || defined(ULTRIX_PROTO) || defined(MAC) # if !defined(USE_VARARGS) && !defined(USE_OLDARGS) && !defined(USE_STDARG) # define USE_STDARG # endif #endif #ifdef NEED_VARARGS /* only define these if necessary */ #ifdef USE_STDARG #include # define VA_DECL(typ1,var1) (typ1 var1, ...) { va_list the_args; # define VA_DECL2(typ1,var1,typ2,var2) \ (typ1 var1, typ2 var2, ...) { va_list the_args; # define VA_INIT(var1,typ1) # define VA_NEXT(var1,typ1) var1 = va_arg(the_args, typ1) # define VA_ARGS the_args # define VA_START(x) va_start(the_args, x) # define VA_END() va_end(the_args) # if defined(ULTRIX_PROTO) && !defined(_VA_LIST_) # define _VA_LIST_ /* prevents multiple def in stdio.h */ # endif #else # ifdef USE_VARARGS #include # define VA_DECL(typ1,var1) (va_alist) va_dcl {\ va_list the_args; typ1 var1; # define VA_DECL2(typ1,var1,typ2,var2) (va_alist) va_dcl {\ va_list the_args; typ1 var1; typ2 var2; # define VA_ARGS the_args # define VA_START(x) va_start(the_args) # define VA_INIT(var1,typ1) var1 = va_arg(the_args, typ1) # define VA_NEXT(var1,typ1) var1 = va_arg(the_args,typ1) # define VA_END() va_end(the_args) # else # define VA_ARGS arg1,arg2,arg3,arg4,arg5,arg6,arg7,arg8,arg9 # define VA_DECL(typ1,var1) (var1,VA_ARGS) typ1 var1; \ char *arg1,*arg2,*arg3,*arg4,*arg5,*arg6,*arg7,*arg8,*arg9; { # define VA_DECL2(typ1,var1,typ2,var2) (var1,var2,VA_ARGS) \ typ1 var1; typ2 var2;\ char *arg1,*arg2,*arg3,*arg4,*arg5,*arg6,*arg7,*arg8,*arg9; { # define VA_START(x) # define VA_INIT(var1,typ1) # define VA_END() # endif #endif #endif /* NEED_VARARGS */ #if defined(NHSTDC) || defined(MSDOS) || defined(MAC) || defined(ULTRIX_PROTO) || defined(__BEOS__) /* * Used for robust ANSI parameter forward declarations: * int VDECL(sprintf, (char *, const char *, ...)); * * NDECL() is used for functions with zero arguments; * FDECL() is used for functions with a fixed number of arguments; * VDECL() is used for functions with a variable number of arguments. * Separate macros are needed because ANSI will mix old-style declarations * with prototypes, except in the case of varargs, and the OVERLAY-specific * trampoli.* mechanism conflicts with the ANSI <> syntax. */ # define NDECL(f) f(void) /* overridden later if USE_TRAMPOLI set */ # define FDECL(f,p) f p # if defined(MSDOS) || defined(USE_STDARG) # define VDECL(f,p) f p # else # define VDECL(f,p) f() # endif /* generic pointer, always a macro; genericptr_t is usually a typedef */ # define genericptr void * # if (defined(ULTRIX_PROTO) && !defined(__GNUC__)) || defined(OS2_CSET2) /* Cover for Ultrix on a DECstation with 2.0 compiler, which coredumps on * typedef void * genericptr_t; * extern void a(void(*)(int, genericptr_t)); * Using the #define is OK for other compiler versions too. */ /* And IBM CSet/2. The redeclaration of free hoses the compile. */ # define genericptr_t genericptr # else # if !defined(NHSTDC) && !defined(MAC) # define const # define signed # define volatile # endif # endif /* * Suppress `const' if necessary and not handled elsewhere. * Don't use `#if defined(xxx) && !defined(const)' * because some compilers choke on `defined(const)'. * This has been observed with Lattice, MPW, and High C. */ # if (defined(ULTRIX_PROTO) && !defined(NHSTDC)) || defined(apollo) /* the system header files don't use `const' properly */ # ifndef const # define const # endif # endif #else /* NHSTDC */ /* a "traditional" C compiler */ # define NDECL(f) f() # define FDECL(f,p) f() # define VDECL(f,p) f() # if defined(AMIGA) || defined(HPUX) || defined(POSIX_TYPES) || defined(__DECC) || defined(__BORLANDC__) # define genericptr void * # endif # ifndef genericptr # define genericptr char * # endif /* * Traditional C compilers don't have "signed", "const", or "volatile". */ # define signed # define const # define volatile #endif /* NHSTDC */ #ifndef genericptr_t typedef genericptr genericptr_t; /* (void *) or (char *) */ #endif /* * According to ANSI, prototypes for old-style declarations must widen the * arguments to int. However, the MSDOS compilers accept shorter arguments * (char, short, etc.) in prototypes and do typechecking with them. Therefore * this mess to allow the better typechecking while also allowing some * prototypes for the ANSI compilers so people quit trying to fix the * prototypes to match the standard and thus lose the typechecking. */ #if defined(MSDOS) && !defined(__GO32__) #define UNWIDENED_PROTOTYPES #endif #if defined(AMIGA) && !defined(AZTEC_50) #define UNWIDENED_PROTOTYPES #endif #if defined(macintosh) && (defined(__SC__) || defined(__MRC__)) #define WIDENED_PROTOTYPES #endif #if defined(__MWERKS__) && defined(__BEOS__) #define UNWIDENED_PROTOTYPES #endif #if defined(WIN32) #define UNWIDENED_PROTOTYPES #endif #if defined(ULTRIX_PROTO) && defined(ULTRIX_CC20) #define UNWIDENED_PROTOTYPES #endif #if defined(apollo) #define UNWIDENED_PROTOTYPES #endif #ifndef UNWIDENED_PROTOTYPES # if defined(NHSTDC) || defined(ULTRIX_PROTO) || defined(THINK_C) # define WIDENED_PROTOTYPES # endif #endif #if 0 /* The problem below is still the case through 4.0.5F, but the suggested * compiler flags in the Makefiles suppress the nasty messages, so we don't * need to be quite so drastic. */ #if defined(__sgi) && !defined(__GNUC__) /* * As of IRIX 4.0.1, /bin/cc claims to be an ANSI compiler, but it thinks * it's impossible for a prototype to match an old-style definition with * unwidened argument types. Thus, we have to turn off all NetHack * prototypes, and avoid declaring several system functions, since the system * include files have prototypes and the compiler also complains that * prototyped and unprototyped declarations don't match. */ # undef NDECL # undef FDECL # undef VDECL # define NDECL(f) f() # define FDECL(f,p) f() # define VDECL(f,p) f() #endif #endif /* MetaWare High-C defaults to unsigned chars */ /* AIX 3.2 needs this also */ #if defined(__HC__) || defined(_AIX32) # undef signed #endif /* * Allow gcc2 to check parameters of printf-like calls with -Wformat; * append this to a prototype declaration (see pline() in extern.h). */ #ifdef __GNUC__ # if __GNUC__ >= 2 #define PRINTF_F(f,v) __attribute__ ((format (printf, f, v))) # endif #endif #ifndef PRINTF_F #define PRINTF_F(f,v) #endif #endif /* TRADSTDC_H */ nethack-3.4.3/include/trampoli.h0100644000000000000000000001762707764735041015312 0ustar rootroot/* SCCS Id: @(#)trampoli.h 3.4 1995/06/01 */ /* Copyright (c) 1989, by Norm Meluch and Stephen Spackman */ /* NetHack may be freely redistributed. See license for details. */ #ifndef TRAMPOLI_H #define TRAMPOLI_H #ifdef USE_TRAMPOLI /* ### apply.c ### */ #define dig() dig_() #define doapply() doapply_() #define dojump() dojump_() #define dorub() dorub_() /* ### artifact.c ### */ #define doinvoke() doinvoke_() /* ### cmd.c ### */ #define doextcmd() doextcmd_() #define doextlist() doextlist_() #define domonability() domonability_() #define enter_explore_mode() enter_explore_mode_() #define doprev_message() doprev_message_() #define timed_occupation() timed_occupation_() #define wiz_attributes() wiz_attributes_() #ifdef WIZARD #define wiz_detect() wiz_detect_() #define wiz_genesis() wiz_genesis_() #define wiz_identify() wiz_identify_() #define wiz_level_tele() wiz_level_tele_() #define wiz_map() wiz_map_() #define wiz_where() wiz_where_() #define wiz_wish() wiz_wish_() #endif /* ### display.c ### */ #define doredraw() doredraw_() /* ### do.c ### */ #define doddrop() doddrop_() #define dodown() dodown_() #define dodrop() dodrop_() #define donull() donull_() #define doup() doup_() #define dowipe() dowipe_() #define drop(x) drop_(x) #define wipeoff() wipeoff_() /* ### do_name.c ### */ #define ddocall() ddocall_() #define do_mname() do_mname_() /* ### do_wear.c ### */ #define Armor_off() Armor_off_() #define Boots_off() Boots_off_() #define Gloves_off() Gloves_off_() #define Helmet_off() Helmet_off_() #define Armor_on() Armor_on_() #define Boots_on() Boots_on_() #define Gloves_on() Gloves_on_() #define Helmet_on() Helmet_on_() #define doddoremarm() doddoremarm_() #define doputon() doputon_() #define doremring() doremring_() #define dotakeoff() dotakeoff_() #define dowear() dowear_() #define select_off(x) select_off_(x) #define take_off() take_off_() /* ### dogmove.c ### */ #define wantdoor(x, y, dummy) wantdoor_(x, y, dummy) /* ### dokick.c ### */ #define dokick() dokick_() /* ### dothrow.c ### */ #define dothrow() dothrow_() /* ### eat.c ### */ #define Hear_again() Hear_again_() #define eatmdone() eatmdone_() #define doeat() doeat_() #define eatfood() eatfood_() #define opentin() opentin_() #define unfaint() unfaint_() /* ### end.c ### */ #define done1(sig) done1_(sig) #define done2() done2_() #define done_intr(sig) done_intr_(sig) #if defined(UNIX) || defined (VMS) || defined(__EMX__) #define done_hangup(sig) done_hangup_(sig) #endif /* ### engrave.c ### */ #define doengrave() doengrave_() /* ### fountain.c ### */ #define gush(x, y, poolcnt) gush_(x, y, poolcnt) /* ### hack.c ### */ #define dopickup() dopickup_() #define identify(x) identify_(x) /* ### invent.c ### */ #define ckunpaid(x) ckunpaid_(x) #define ddoinv() ddoinv_() #define dolook() dolook_() #define dopramulet() dopramulet_() #define doprarm() doprarm_() #define doprgold() doprgold_() #define doprring() doprring_() #define doprtool() doprtool_() #define doprwep() doprwep_() #define dotypeinv() dotypeinv_() #define doorganize() doorganize_() /* ### ioctl.c ### */ #ifdef UNIX # ifdef SUSPEND #define dosuspend() dosuspend_() # endif /* SUSPEND */ #endif /* UNIX */ /* ### lock.c ### */ #define doclose() doclose_() #define doforce() doforce_() #define doopen() doopen_() #define forcelock() forcelock_() #define picklock() picklock_() /* ### mklev.c ### */ #define do_comp(x, y) comp_(x, y) /* ### mondata.c ### */ /* See comment in trampoli.c before uncommenting canseemon. */ /* #define canseemon(x) canseemon_(x) */ /* ### muse.c ### */ #define mbhitm(x, y) mbhitm_(x, y) /* ### o_init.c ### */ #define dodiscovered() dodiscovered_() /* ### objnam.c ### */ #define doname(x) doname_(x) #define xname(x) xname_(x) /* ### options.c ### */ #define doset() doset_() #define dotogglepickup() dotogglepickup_() /* ### pager.c ### */ #define dohelp() dohelp_() #define dohistory() dohistory_() #ifdef UNIX #define intruph() intruph_() #endif /* UNIX */ #define dowhatdoes() dowhatdoes_() #define dowhatis() dowhatis_() #define doquickwhatis() doquickwhatis_() /* ### pcsys.c ### */ #ifdef SHELL #define dosh() dosh_() #endif /* SHELL */ /* ### pickup.c ### */ #define ck_bag(x) ck_bag_(x) #define doloot() doloot_() #define in_container(x) in_container_(x) #define out_container(x) out_container_(x) /* ### potion.c ### */ #define dodrink() dodrink_() #define dodip() dodip_() /* ### pray.c ### */ #define doturn() doturn_() #define dopray() dopray_() #define prayer_done() prayer_done_() #define dosacrifice() dosacrifice_() /* ### read.c ### */ #define doread() doread_() #define set_lit(x, y, val) set_lit_(x, y, val) /* ### rip.c ### */ #define genl_outrip(tmpwin, how) genl_outrip_(tmpwin, how) /* ### save.c ### */ #define dosave() dosave_() #if defined(UNIX) || defined (VMS) || defined(__EMX__) #define hangup(sig) hangup_(sig) #endif /* ### search.c ### */ #define doidtrap() doidtrap_() #define dosearch() dosearch_() #define findone(zx, zy, num) findone_(zx, zy, num) #define openone(zx, zy, num) openone_(zx, zy, num) /* ### shk.c ### */ #define dopay() dopay_() /* ### sit.c ### */ #define dosit() dosit_() /* ### sounds.c ### */ #define dotalk() dotalk_() /* ### spell.c ### */ #define learn() learn_() #define docast() docast_() #define dovspell() dovspell_() /* ### steal.c ### */ #define stealarm() stealarm_() /* ### trap.c ### */ #define dotele() dotele_() #define dountrap() dountrap_() #define float_down() float_down_() /* ### version.c ### */ #define doversion() doversion_() #define doextversion() doextversion_() /* ### wield.c ### */ #define dowield() dowield_() /* ### zap.c ### */ #define bhitm(x, y) bhitm_(x, y) #define bhito(x, y) bhito_(x, y) #define dozap() dozap_() /* ### getline.c ### */ #define tty_getlin(x,y) tty_getlin_(x,y) #define tty_get_ext_cmd() tty_get_ext_cmd_() /* ### termcap.c ### */ #define tty_nhbell() tty_nhbell_() #define tty_number_pad(x) tty_number_pad_(x) #define tty_delay_output() tty_delay_output_() #define tty_start_screen() tty_start_screen_() #define tty_end_screen() tty_end_screen_() /* ### topl.c ### */ #define tty_doprev_message() tty_doprev_message_() #define tty_yn_function(x,y,z) tty_yn_function_(x,y,z) /* ### wintty.c ### */ #define tty_init_nhwindows(x,y) tty_init_nhwindows_(x,y) #define tty_player_selection() tty_player_selection_() #define tty_askname() tty_askname_() #define tty_get_nh_event() tty_get_nh_event_() #define tty_exit_nhwindows(x) tty_exit_nhwindows_(x) #define tty_suspend_nhwindows(x) tty_suspend_nhwindows_(x) #define tty_resume_nhwindows() tty_resume_nhwindows_() #define tty_create_nhwindow(x) tty_create_nhwindow_(x) #define tty_clear_nhwindow(x) tty_clear_nhwindow_(x) #define tty_display_nhwindow(x,y) tty_display_nhwindow_(x,y) #define tty_destroy_nhwindow(x) tty_destroy_nhwindow_(x) #define tty_curs(x,y,z) tty_curs_(x,y,z) #define tty_putstr(x,y,z) tty_putstr_(x,y,z) #define tty_display_file(x,y) tty_display_file_(x,y) #define tty_start_menu(x) tty_start_menu_(x) #define tty_add_menu(a,b,c,d,e,f,g,h) tty_add_menu_(a,b,c,d,e,f,g,h) #define tty_end_menu(a,b) tty_end_menu_(a,b) #define tty_select_menu(a,b,c) tty_select_menu_(a,b,c) #define tty_update_inventory() tty_update_inventory_() #define tty_mark_synch() tty_mark_synch_() #define tty_wait_synch() tty_wait_synch_() #ifdef CLIPPING #define tty_cliparound(x,y) tty_cliparound_(x,y) #endif #ifdef POSITIONBAR #define tty_update_positionbar(x) tty_update_positionbar_(x) #endif #define tty_print_glyph(a,b,c,d) tty_print_glyph_(a,b,c,d) #define tty_raw_print(x) tty_raw_print_(x) #define tty_raw_print_bold(x) tty_raw_print_bold_(x) #define tty_nhgetch() tty_nhgetch_() #define tty_nh_poskey(x,y,z) tty_nh_poskey_(x,y,z) #endif /* USE_TRAMPOLI */ #endif /* TRAMPOLI_H */ nethack-3.4.3/include/trap.h0100644000000000000000000000406107764735041014415 0ustar rootroot/* SCCS Id: @(#)trap.h 3.4 2000/08/30 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* note for 3.1.0 and later: no longer manipulated by 'makedefs' */ #ifndef TRAP_H #define TRAP_H union vlaunchinfo { short v_launch_otyp; /* type of object to be triggered */ coord v_launch2; /* secondary launch point (for boulders) */ }; struct trap { struct trap *ntrap; xchar tx,ty; d_level dst; /* destination for portals */ coord launch; Bitfield(ttyp,5); Bitfield(tseen,1); Bitfield(once,1); Bitfield(madeby_u,1); /* So monsters may take offence when you trap them. Recognizing who made the trap isn't completely unreasonable, everybody has their own style. This flag is also needed when you untrap a monster. It would be too easy to make a monster peaceful if you could set a trap for it and then untrap it. */ union vlaunchinfo vl; #define launch_otyp vl.v_launch_otyp #define launch2 vl.v_launch2 }; extern struct trap *ftrap; #define newtrap() (struct trap *) alloc(sizeof(struct trap)) #define dealloc_trap(trap) free((genericptr_t) (trap)) /* reasons for statue animation */ #define ANIMATE_NORMAL 0 #define ANIMATE_SHATTER 1 #define ANIMATE_SPELL 2 /* reasons for animate_statue's failure */ #define AS_OK 0 /* didn't fail */ #define AS_NO_MON 1 /* makemon failed */ #define AS_MON_IS_UNIQUE 2 /* statue monster is unique */ /* Note: if adding/removing a trap, adjust trap_engravings[] in mklev.c */ /* unconditional traps */ #define NO_TRAP 0 #define ARROW_TRAP 1 #define DART_TRAP 2 #define ROCKTRAP 3 #define SQKY_BOARD 4 #define BEAR_TRAP 5 #define LANDMINE 6 #define ROLLING_BOULDER_TRAP 7 #define SLP_GAS_TRAP 8 #define RUST_TRAP 9 #define FIRE_TRAP 10 #define PIT 11 #define SPIKED_PIT 12 #define HOLE 13 #define TRAPDOOR 14 #define TELEP_TRAP 15 #define LEVEL_TELEP 16 #define MAGIC_PORTAL 17 #define WEB 18 #define STATUE_TRAP 19 #define MAGIC_TRAP 20 #define ANTI_MAGIC 21 #define POLY_TRAP 22 #define TRAPNUM 23 #endif /* TRAP_H */ nethack-3.4.3/include/unixconf.h0100644000000000000000000002540307764735041015303 0ustar rootroot/* SCCS Id: @(#)unixconf.h 3.4 1999/07/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef UNIX #ifndef UNIXCONF_H #define UNIXCONF_H /* * Some include files are in a different place under SYSV * BSD SYSV * * * * Some routines are called differently * index strchr * rindex strrchr * */ /* define exactly one of the following four choices */ /* #define BSD 1 */ /* define for 4.n/Free/Open/Net BSD */ /* also for relatives like SunOS 4.x, DG/UX, and */ /* older versions of Linux */ /* #define ULTRIX */ /* define for Ultrix v3.0 or higher (but not lower) */ /* Use BSD for < v3.0 */ /* "ULTRIX" not to be confused with "ultrix" */ #define SYSV /* define for System V, Solaris 2.x, newer versions */ /* of Linux */ /* #define HPUX */ /* Hewlett-Packard's Unix, version 6.5 or higher */ /* use SYSV for < v6.5 */ /* define any of the following that are appropriate */ #define SVR4 /* use in addition to SYSV for System V Release 4 */ /* including Solaris 2+ */ #define NETWORK /* if running on a networked system */ /* e.g. Suns sharing a playground through NFS */ /* #define SUNOS4 */ /* SunOS 4.x */ /* #define LINUX */ /* Another Unix clone */ /* #define CYGWIN32 */ /* Unix on Win32 -- use with case sensitive defines */ /* #define GENIX */ /* Yet Another Unix Clone */ /* #define HISX */ /* Bull Unix for XPS Machines */ /* #define BOS */ /* Bull Open Software - Unix for DPX/2 Machines */ /* #define UNIXPC */ /* use in addition to SYSV for AT&T 7300/3B1 */ /* #define AIX_31 */ /* In AIX 3.1 (IBM RS/6000) use BSD ioctl's to gain * job control (note that AIX is SYSV otherwise) * Also define this for AIX 3.2 */ #define TERMINFO /* uses terminfo rather than termcap */ /* Should be defined for most SYSV, SVR4 (including * Solaris 2+), HPUX, and Linux systems. In * particular, it should NOT be defined for the UNIXPC * unless you remove the use of the shared library in * the Makefile */ #define TEXTCOLOR /* Use System V r3.2 terminfo color support */ /* and/or ANSI color support on termcap systems */ /* and/or X11 color */ #define POSIX_JOB_CONTROL /* use System V / Solaris 2.x / POSIX job control */ /* (e.g., VSUSP) */ #define POSIX_TYPES /* use POSIX types for system calls and termios */ /* Define for many recent OS releases, including * those with specific defines (since types are * changing toward the standard from earlier chaos). * For example, platforms using the GNU libraries, * Linux, Solaris 2.x */ /* #define OPENWINBUG */ /* avoid a problem using OpenWindows 3.0 for X11 on SunOS 4.1.x, x>= 2. Do not define for other X11 implementations. */ /* #define PYRAMID_BUG */ /* avoid a bug on the Pyramid */ /* #define BSD_43_BUG */ /* for real 4.3BSD cc's without schain botch fix */ /* #define MICROPORT_BUG */ /* problems with large arrays in structs */ /* #define MICROPORT_286_BUG */ /* changes needed in termcap.c to get it to run with Microport Sys V/AT version 2.4. By Jay Maynard */ /* #define AIXPS_2BUG */ /* avoid a problem with little_to_big() optimization */ /* #define RANDOM */ /* if neither random/srandom nor lrand48/srand48 is available from your system */ /* see sys/unix/snd86unx.shr for more information on these */ /* #define UNIX386MUSIC */ /* play real music through speaker on systems with music driver installed */ /* #define VPIX_MUSIC */ /* play real music through speaker on systems with built-in VPIX support */ /* * The next two defines are intended mainly for the Andrew File System, * which does not allow hard links. If NO_FILE_LINKS is defined, lock files * will be created in LOCKDIR using open() instead of in the playground using * link(). * Ralf Brown, 7/26/89 (from v2.3 hack of 10/10/88) */ /* #define NO_FILE_LINKS */ /* if no hard links */ /* #define LOCKDIR "/usr/games/lib/nethackdir" */ /* where to put locks */ /* * If you want the static parts of your playground on a read-only file * system, define VAR_PLAYGROUND to be where the variable parts are kept. */ /* #define VAR_PLAYGROUND "/var/lib/games/nethack" */ /* * Define DEF_PAGER as your default pager, e.g. "/bin/cat" or "/usr/ucb/more" * If defined, it can be overridden by the environment variable PAGER. * Hack will use its internal pager if DEF_PAGER is not defined. * (This might be preferable for security reasons.) * #define DEF_PAGER ".../mydir/mypager" */ /* * Define PORT_HELP to be the name of the port-specfic help file. * This file is found in HACKDIR. * Normally, you shouldn't need to change this. * There is currently no port-specific help for Unix systems. */ /* #define PORT_HELP "Unixhelp" */ #ifdef TTY_GRAPHICS /* * To enable the `timed_delay' option for using a timer rather than extra * screen output when pausing for display effect. Requires that `msleep' * function be available (with time argument specified in milliseconds). * Various output devices can produce wildly varying delays when the * "extra output" method is used, but not all systems provide access to * a fine-grained timer. */ /* #define TIMED_DELAY */ /* usleep() */ #endif /* * If you define MAIL, then the player will be notified of new mail * when it arrives. If you also define DEF_MAILREADER then this will * be the default mail reader, and can be overridden by the environment * variable MAILREADER; otherwise an internal pager will be used. * A stat system call is done on the mailbox every MAILCKFREQ moves. */ #define MAIL /* Deliver mail during the game */ /* The Andrew Message System does mail a little differently from normal * UNIX. Mail is deposited in the user's own directory in ~/Mailbox * (another directory). MAILBOX is the element that will be added on to * the user's home directory path to generate the Mailbox path - just in * case other Andrew sites do it differently from CMU. * * dan lovinger * dl2n+@andrew.cmu.edu (dec 19 1989) */ /* #define AMS */ /* use Andrew message system for mail */ /* NO_MAILREADER is for kerberos authenticating filesystems where it is * essentially impossible to securely exec child processes, like mail * readers, when the game is running under a special token. * * dan */ /* #define NO_MAILREADER */ /* have mail daemon just tell player of mail */ #ifdef MAIL # if defined(BSD) || defined(ULTRIX) # ifdef AMS #define AMS_MAILBOX "/Mailbox" # else # if defined(__FreeBSD__) || defined(__OpenBSD__) #define DEF_MAILREADER "/usr/bin/mail" # else #define DEF_MAILREADER "/usr/ucb/Mail" # endif # endif #else # if (defined(SYSV) || defined(DGUX) || defined(HPUX)) && !defined(LINUX) # if defined(M_XENIX) #define DEF_MAILREADER "/usr/bin/mail" # else # ifdef __sgi #define DEF_MAILREADER "/usr/sbin/Mail" # else #define DEF_MAILREADER "/usr/bin/mailx" # endif # endif # else #define DEF_MAILREADER "/bin/mail" # endif #endif #define MAILCKFREQ 50 #endif /* MAIL */ #ifdef COMPRESS /* Some implementations of compress need a 'quiet' option. * If you've got one of these versions, put -q here. * You can also include any other strange options your compress needs. * If you have a normal compress, just leave it commented out. */ /* #define COMPRESS_OPTIONS "-q" */ #endif #define FCMASK 0660 /* file creation mask */ /* * The remainder of the file should not need to be changed. */ #ifdef _AUX_SOURCE # ifdef AUX /* gcc ? */ # define _SYSV_SOURCE # define _BSD_SOURCE #else # define AUX # endif #endif /* _AUX_SOURCE */ #if defined(LINUX) || defined(bsdi) # ifndef POSIX_TYPES # define POSIX_TYPES # endif # ifndef POSIX_JOB_CONTROL # define POSIX_JOB_CONTROL # endif #endif /* * BSD/ULTRIX systems are normally the only ones that can suspend processes. * Suspending NetHack processes cleanly should be easy to add to other systems * that have SIGTSTP in the Berkeley sense. Currently the only such systems * known to work are HPUX and AIX 3.1; other systems will probably require * tweaks to unixtty.c and ioctl.c. * * POSIX defines a slightly different type of job control, which should be * equivalent for NetHack's purposes. POSIX_JOB_CONTROL should work on * various recent SYSV versions (with possibly tweaks to unixtty.c again). */ #ifndef POSIX_JOB_CONTROL # if defined(BSD) || defined(ULTRIX) || defined(HPUX) || defined(AIX_31) # define BSD_JOB_CONTROL # else # if defined(SVR4) # define POSIX_JOB_CONTROL # endif # endif #endif #if defined(BSD_JOB_CONTROL) || defined(POSIX_JOB_CONTROL) || defined(AUX) #define SUSPEND /* let ^Z suspend the game */ #endif #if defined(BSD) || defined(ULTRIX) #include #else #include #endif #define HLOCK "perm" /* an empty file used for locking purposes */ #ifndef REDO #define Getchar nhgetch #endif #define tgetch getchar #define SHELL /* do not delete the '!' command */ #include "system.h" #if defined(POSIX_TYPES) || defined(__GNUC__) #include #include #endif #if defined(POSIX_TYPES) || defined(__GNUC__) || defined(BSD) || defined(ULTRIX) #include #endif #if defined(BSD) || defined(ULTRIX) # if !defined(DGUX) && !defined(SUNOS4) #define memcpy(d, s, n) bcopy(s, d, n) #define memcmp(s1, s2, n) bcmp(s2, s1, n) # endif # ifdef SUNOS4 #include # endif #else /* therefore SYSV */ # ifndef index /* some systems seem to do this for you */ #define index strchr # endif # ifndef rindex #define rindex strrchr # endif #endif /* Use the high quality random number routines. */ #if defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) || defined(RANDOM) || defined(__APPLE__) #define Rand() random() #else #define Rand() lrand48() #endif #ifdef TIMED_DELAY # if defined(SUNOS4) || defined(LINUX) || (defined(BSD) && !defined(ULTRIX)) # define msleep(k) usleep((k)*1000) # endif # ifdef ULTRIX # define msleep(k) napms(k) # endif #endif #ifdef hc /* older versions of the MetaWare High-C compiler define this */ # ifdef __HC__ # undef __HC__ # endif # define __HC__ hc # undef hc #endif #if defined(GNOME_GRAPHICS) #if defined(LINUX) # include # if defined(__NR_getresuid) && defined(__NR_getresgid) /* ie., >= v2.1.44 */ # define GETRES_SUPPORT # endif #else # if defined(BSD) || defined(SVR4) /* * [ALI] We assume that SVR4 means we can safely include syscall.h * (although it's really a BSDism). This is certainly true for Solaris 2.5, * Solaris 7, Solaris 8 and Compaq Tru64 5.1 * Later BSD systems will have the getresid system calls. */ # include # if (defined (SYS_getuid) || defined(SYS_getresuid)) && \ (defined(SYS_getgid) || defined(SYS_getresgid)) # define GETRES_SUPPORT # endif # endif /* BSD || SVR4 */ #endif /* LINUX */ #endif /* GNOME_GRAPHICS */ #endif /* UNIXCONF_H */ #endif /* UNIX */ nethack-3.4.3/include/vault.h0100644000000000000000000000143507764735041014604 0ustar rootroot/* SCCS Id: @(#)vault.h 3.4 1997/05/01 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef VAULT_H #define VAULT_H #define FCSIZ (ROWNO+COLNO) struct fakecorridor { xchar fx,fy,ftyp; }; struct egd { int fcbeg, fcend; /* fcend: first unused pos */ int vroom; /* room number of the vault */ xchar gdx, gdy; /* goal of guard's walk */ xchar ogx, ogy; /* guard's last position */ d_level gdlevel; /* level (& dungeon) guard was created in */ xchar warncnt; /* number of warnings to follow */ Bitfield(gddone,1); /* true iff guard has released player */ Bitfield(unused,7); struct fakecorridor fakecorr[FCSIZ]; }; #define EGD(mon) ((struct egd *)&(mon)->mextra[0]) #endif /* VAULT_H */ nethack-3.4.3/include/vision.h0100644000000000000000000000354707764735041014766 0ustar rootroot/* SCCS Id: @(#)vision.h 3.4 1995/01/26 */ /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef VISION_H #define VISION_H #if 0 /* (moved to decl.h) */ extern boolean vision_full_recalc; /* TRUE if need vision recalc */ extern char **viz_array; /* could see/in sight row pointers */ extern char *viz_rmin; /* min could see indices */ extern char *viz_rmax; /* max could see indices */ #endif #define COULD_SEE 0x1 /* location could be seen, if it were lit */ #define IN_SIGHT 0x2 /* location can be seen */ #define TEMP_LIT 0x4 /* location is temporarily lit */ /* * Light source sources */ #define LS_OBJECT 0 #define LS_MONSTER 1 /* * cansee() - Returns true if the hero can see the location. * * couldsee() - Returns true if the hero has a clear line of sight to * the location. */ #define cansee(x,y) (viz_array[y][x] & IN_SIGHT) #define couldsee(x,y) (viz_array[y][x] & COULD_SEE) #define templit(x,y) (viz_array[y][x] & TEMP_LIT) /* * The following assume the monster is not blind. * * m_cansee() - Returns true if the monster can see the given location. * * m_canseeu() - Returns true if the monster could see the hero. Assumes * that if the hero has a clear line of sight to the monster's * location and the hero is visible, then monster can see the * hero. */ #define m_cansee(mtmp,x2,y2) clear_path((mtmp)->mx,(mtmp)->my,(x2),(y2)) #define m_canseeu(m) ((!Invis || perceives((m)->data)) && \ !(Underwater || u.uburied || (m)->mburied) ? \ couldsee((m)->mx,(m)->my) : 0) /* * Circle information */ #define MAX_RADIUS 15 /* this is in points from the source */ /* Use this macro to get a list of distances of the edges (see vision.c). */ #define circle_ptr(z) (&circle_data[(int)circle_start[z]]) #endif /* VISION_H */ nethack-3.4.3/include/vmsconf.h0100644000000000000000000002011407764735041015117 0ustar rootroot/* SCCS Id: @(#)vmsconf.h 3.4 2003/05/19 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef VMS #ifndef VMSCONF_H #define VMSCONF_H /* * Edit these to choose values appropriate for your site. * WIZARD is the username allowed to use the debug option of nethack; no harm * is done by leaving it as a username that doesn't exist at your site. * HACKDIR can be overridden at run-time with the logical name HACKDIR, as in * $ define hackdir disk$users:[games.nethack] * Trailing NULs are present in the default values in order to make some * extra room for patching longer values into an existing executable. */ #define Local_WIZARD "NHWIZARD\0\0\0\0" #define Local_HACKDIR "DISK$USERS:[GAMES.NETHACK.3_4_X.PLAY]\0\0\0\0\0\0\0\0" /* * This section cleans up the stuff done in config.h so that it * shouldn't need to be modified. It's conservative so that if * config.h is actually edited, the changes won't impact us. */ #ifdef UNIX # undef UNIX #endif #ifdef HACKDIR # undef HACKDIR #endif #ifdef WIZARD # undef WIZARD #endif #ifdef WIZARD_NAME # undef WIZARD_NAME #endif #define HACKDIR Local_HACKDIR #ifndef KR1ED # define WIZARD Local_WIZARD # define WIZARD_NAME WIZARD #else # define WIZARD 1 # define WIZARD_NAME Local_WIZARD #endif /* filenames require punctuation to avoid redirection via logical names */ #undef RECORD #define RECORD "record;1" /* scoreboard file (retains high scores) */ #undef LOGFILE #define LOGFILE "logfile;0" /* optional file (records all games) */ #define HLOCK "perm;1" /* an empty file used for locking purposes */ /* want compression--for level & save files--performed within NetHack itself */ #ifdef COMPRESS # undef COMPRESS #endif #ifndef INTERNAL_COMP # define INTERNAL_COMP #endif /* * If nethack.exe will be installed with privilege so that the playground * won't need to be left unprotected, define SECURE to suppress a couple * of file protection fixups (protection of bones files and ownership of * save files). */ /* #define SECURE */ /* * Put the readonly data files into a single container rather than into * separate files in the playground directory. */ #define DLB /* use data librarian code */ /* * You may define TEXTCOLOR if your system has any terminals that recognize * ANSI color sequences of the form ``[#;#m'', where the first # is * a number between 40 and 47 represented background color, and the second * # is a number between 30 and 37 representing the foreground color. * GIGI terminals and DECterm windows on color VAXstations support these * color escape sequences, as do some 3rd party terminals and many micro * computers. */ /* #define TEXTCOLOR */ /* * If you define USE_QIO_INPUT, then you'll get raw characters from the * keyboard, not unlike those of the unix version of Nethack. This will * allow you to use the Escape key in normal gameplay, and the appropriate * control characters in Wizard mode. It will work most like the unix version. * It will also avoid "" being displayed when ^Y is pressed. * * Otherwise, the VMS SMG calls will be used. These calls block use of * the escape key, as well as certain control keys, so gameplay is not * the same, although the differences are fairly negligible. You must * then use a VTxxx function key or two s to give an ESC response. */ #define USE_QIO_INPUT /* use SYS$QIOW instead of SMG$READ_KEYSTROKE */ /* * Allow the user to decide whether to pause via timer or excess screen * output for various display effects like explosions and moving objects. */ #define TIMED_DELAY /* enable the `timed_delay' run-time option */ /* * If you define MAIL, then NetHack will capture incoming broadcast * messages such as "New mail from so-and-so" and "Print job completed," * and then deliver them to the player. For mail and phone broadcasts * a scroll of mail will be created, which when read will cause NetHack * to prompt the player for a command to spawn in order to respond. The * latter capability will not be available if SHELL is disabled below. * If you undefine MAIL, broadcasts will go straight to the terminal, * resulting in disruption of the screen display; use to redraw. */ #define MAIL /* enable broadcast trapping */ /* * SHELL enables the player to 'escape' into a spawned subprocess via * the '!' command. Logout or attach back to the parent to resume play. * If the player attaches back to NetHack, then a subsequent escape will * re-attach to the existing subprocess. Any such subprocess left over * at game exit will be deleted by an exit handler. * SUSPEND enables someone running NetHack in a subprocess to reconnect * to the parent process with the command; this is not very * close to Unix job control, but it's better than nothing. */ #define SHELL /* do not delete the '!' command */ #define SUSPEND /* don't delete the ^Z command, such as it is */ #define RANDOM /* use sys/share/random.c instead of vaxcrtl rand */ #define FCMASK 0660 /* file creation mask */ /* * The remainder of the file should not need to be changed. */ /* data librarian defs */ #ifdef DLB # define DLBFILE "nh-data.dlb" /* * Since we can do without case insensitive filename comparison, * avoid enabling it because that requires compiling and linking * src/hacklib into util/dlb_main. */ /* # define FILENAME_CMP strcmpi */ /* case insensitive */ #endif #if defined(VAXC) && !defined(ANCIENT_VAXC) # ifdef volatile # undef volatile # endif # ifdef const # undef const # endif #endif #ifdef __DECC # define STRICT_REF_DEF /* used in lev_main.c */ #endif #ifdef STRICT_REF_DEF # define DEFINE_OSPEED #endif #ifndef alloca /* bison generated foo_yacc.c might try to use alloca() */ # ifdef __GNUC__ # define alloca __builtin_alloca # else # define ALLOCA_HACK /* used in util/panic.c */ # endif #endif #ifdef _DECC_V4_SOURCE /* excludes some necessary typedefs when _DECC_V4_SOURCE is defined */ #include # ifndef __PID_T # define __PID_T typedef __pid_t pid_t; # endif # ifndef __UID_T # define __UID_T typedef __uid_t uid_t; # endif # ifndef __GID_T # define __GID_T typedef __gid_t gid_t; # endif # ifndef __MODE_T # define __MODE_T typedef __mode_t mode_t; # endif #endif /* _DECC_V4_SOURCE */ #include #if 0 /* is missing for old gcc versions; skip it to save time */ #include #else /* values needed from missing include file */ # define O_RDONLY 0 # define O_WRONLY 1 # define O_RDWR 2 # define O_CREAT 0x200 # define O_TRUNC 0x400 #endif #ifndef REDO # define Getchar nhgetch #endif #define tgetch vms_getchar #include "system.h" #define index strchr #define rindex strrchr /* Use the high quality random number routines. */ #if defined(RANDOM) #define Rand() random() /* VMS V7 adds these entry points to DECC$SHR; stick with the nethack-supplied code to avoid having to deal with version-specific conditionalized builds */ #define random nh_random #define srandom nh_srandom #define initstate nh_initstate #define setstate nh_setstate #else #define Rand() rand() #endif #ifndef __GNUC__ # ifndef bcopy #define bcopy(s,d,n) memcpy((d),(s),(n)) /* vaxcrtl */ # endif #endif #define abort() vms_abort() /* vmsmisc.c */ #define creat(f,m) vms_creat(f,m) /* vmsfiles.c */ #define exit(sts) vms_exit(sts) /* vmsmisc.c */ #define getuid() vms_getuid() /* vmsunix.c */ #define link(f1,f2) vms_link(f1,f2) /* vmsfiles.c */ #define open(f,k,m) vms_open(f,k,m) /* vmsfiles.c */ /* #define unlink(f0) vms_unlink(f0) /* vmsfiles.c */ #ifdef VERYOLD_VMS #define unlink(f0) delete(f0) /* vaxcrtl */ #else #define unlink(f0) remove(f0) /* vaxcrtl, decc$shr */ #endif #define C$$TRANSLATE(n) c__translate(n) /* vmsfiles.c */ /* VMS global names are case insensitive... */ #define An vms_an #define The vms_the #define Shk_Your vms_shk_your /* avoid global symbol in Alpha/VMS V1.5 STARLET library (link trouble) */ #define ospeed vms_ospeed /* used in several files which don't #include "extern.h" */ extern void FDECL(vms_exit, (int)); extern int FDECL(vms_open, (const char *,int,unsigned)); #endif /* VMSCONF_H */ #endif /* VMS */ nethack-3.4.3/include/wceconf.h0100644000000000000000000002346007764735041015077 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* Copyright (c) NetHack PC Development Team 1993, 1994. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WCECONF_H #define WCECONF_H #pragma warning(disable:4142) /* benign redefinition of type */ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers #include /* Detect the targe device */ #if defined(WIN32_PLATFORM_PSPC) # if _WIN32_WCE >= 300 # define WIN_CE_POCKETPC # else # define WIN_CE_PS2xx # endif #elif defined(WIN32_PLATFORM_HPCPRO) # define WIN_CE_HPCPRO #elif defined(WIN32_PLATFORM_WFSP) # define WIN_CE_SMARTPHONE #else # error "Unsupported Windows CE platform" #endif /* #define SHELL /* nt use of pcsys routines caused a hang */ #define RANDOM /* have Berkeley random(3) */ #define TEXTCOLOR /* Color text */ #define EXEPATH /* Allow .exe location to be used as HACKDIR */ #define TRADITIONAL_GLYPHMAP /* Store glyph mappings at level change time */ #define PC_LOCKING /* Prevent overwrites of aborted or in-progress games */ /* without first receiving confirmation. */ #define SELF_RECOVER /* Allow the game itself to recover from an aborted game */ #define NOTSTDC /* no strerror() */ #define USER_SOUNDS #define AUTOPICKUP_EXCEPTIONS /* * ----------------------------------------------------------------- * The remaining code shouldn't need modification. * ----------------------------------------------------------------- */ /* #define SHORT_FILENAMES /* All NT filesystems support long names now */ #ifdef MICRO #undef MICRO /* never define this! */ #endif #define NOCWD_ASSUMPTIONS /* Always define this. There are assumptions that it is defined for WIN32. Allow paths to be specified for HACKDIR, LEVELDIR, SAVEDIR, BONESDIR, DATADIR, SCOREDIR, LOCKDIR, CONFIGDIR, and TROUBLEDIR */ #define NO_TERMS #define ASCIIGRAPH #ifdef OPTIONS_USED #undef OPTIONS_USED #endif #ifdef MSWIN_GRAPHICS #define OPTIONS_USED "guioptions" #else #define OPTIONS_USED "ttyoptions" #endif #define OPTIONS_FILE OPTIONS_USED #define PORT_HELP "porthelp" #if defined(WIN_CE_POCKETPC) # define PORT_CE_PLATFORM "Pocket PC" #elif defined(WIN_CE_PS2xx) # define PORT_CE_PLATFORM "Palm-size PC 2.11" #elif defined(WIN_CE_HPCPRO) # define PORT_CE_PLATFORM "H/PC Pro 2.11" #elif defined(WIN_CE_SMARTPHONE) # define PORT_CE_PLATFORM "Smartphone 2002" #endif #if defined(ARM) # define PORT_CE_CPU "ARM" #elif defined(PPC) # define PORT_CE_CPU "PPC" #elif defined(ALPHA) # define PORT_CE_CPU "ALPHA" #elif defined(SH3) # define PORT_CE_CPU "SH3" #elif defined(SH4) # define PORT_CE_CPU "SH4" #elif defined(MIPS) # define PORT_CE_CPU "MIPS" #elif defined(X86) || defined(_X86_) # define PORT_CE_CPU "X86" #else # error Only ARM, PPC, ALPHA, SH3, SH4, MIPS and X86 supported #endif #define RUNTIME_PORT_ID /* trigger run-time port identification since Makedefs is bootstrapped on a cross-platform. */ #include /* Provides prototypes of strncmpi(), etc. */ #ifdef STRNCMPI #define strncmpi(a,b,c) _strnicmp(a,b,c) #endif #ifdef STRCMPI #define strcmpi(a,b) _stricmp(a,b) #define stricmp(a,b) _stricmp(a,b) #endif #include #define PATHLEN BUFSZ /* maximum pathlength */ #define FILENAME BUFSZ /* maximum filename length (conservative) */ #if defined(_MAX_PATH) && defined(_MAX_FNAME) # if (_MAX_PATH < BUFSZ) && (_MAX_FNAME < BUFSZ) #undef PATHLEN #undef FILENAME #define PATHLEN _MAX_PATH #define FILENAME _MAX_FNAME # endif #endif #define NO_SIGNAL #define index strchr #define rindex strrchr #define USE_STDARG #ifdef RANDOM /* Use the high quality random number routines. */ #define Rand() random() #else #define Rand() rand() #endif #define FCMASK 0660 /* file creation mask */ #define regularize nt_regularize #define HLOCK "NHPERM" #ifndef M #define M(c) ((char) (0x80 | (c))) /* #define M(c) ((c) - 128) */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif #if defined(DLB) #define FILENAME_CMP _stricmp /* case insensitive */ #endif #if 0 extern char levels[], bones[], permbones[], #endif /* 0 */ /* this was part of the MICRO stuff in the past */ extern const char *alllevels, *allbones; extern char hackdir[]; #define ABORT C('a') #define getuid() 1 #define getlogin() ((char *)0) extern void NDECL(win32_abort); #ifdef WIN32CON extern void FDECL(nttty_preference_update, (const char *)); extern void NDECL(toggle_mouse_support); #endif #ifndef alloca #define ALLOCA_HACK /* used in util/panic.c */ #endif #ifndef REDO #undef Getchar #define Getchar nhgetch #endif #ifdef _MSC_VER #if 0 #pragma warning(disable:4018) /* signed/unsigned mismatch */ #pragma warning(disable:4305) /* init, conv from 'const int' to 'char' */ #endif #pragma warning(disable:4761) /* integral size mismatch in arg; conv supp*/ #ifdef YYPREFIX #pragma warning(disable:4102) /* unreferenced label */ #endif #endif /* UNICODE stuff */ #define NHSTR_BUFSIZE 255 #ifdef UNICODE #define NH_W2A(w, a, cb) ( WideCharToMultiByte( \ CP_ACP, \ 0, \ (w), \ -1, \ (a), \ (cb), \ NULL, \ NULL), (a) ) #define NH_A2W(a, w, cb) ( MultiByteToWideChar( \ CP_ACP, \ 0, \ (a), \ -1, \ (w), \ (cb)), (w) ) #else #define NH_W2A(w, a, cb) (strncpy((a), (w), (cb))) #define NH_A2W(a, w, cb) (strncpy((w), (a), (cb))) #endif extern int FDECL(set_win32_option, (const char *, const char *)); /* * 3.4.3 addition - Stuff to help the user with some common, yet significant errors * Let's make it NOP for now */ #define interject_assistance(_1,_2,_3,_4) #define interject(_1) /* Missing definitions */ extern int mswin_have_input(); #define kbhit mswin_have_input #define getenv(a) ((char*)NULL) /* __stdio.h__ */ #define perror(a) #define freopen(a, b, c) fopen(a, b) extern int isatty(int); /* __time.h___ */ #ifndef _TIME_T_DEFINED typedef __int64 time_t; /* time value */ #define _TIME_T_DEFINED /* avoid multiple def's of time_t */ #endif #ifndef _TM_DEFINED struct tm { int tm_sec; /* seconds after the minute - [0,59] */ int tm_min; /* minutes after the hour - [0,59] */ int tm_hour; /* hours since midnight - [0,23] */ int tm_mday; /* day of the month - [1,31] */ int tm_mon; /* months since January - [0,11] */ int tm_year; /* years since 1900 */ int tm_wday; /* days since Sunday - [0,6] */ int tm_yday; /* days since January 1 - [0,365] */ int tm_isdst; /* daylight savings time flag - - NOT IMPLEMENTED */ }; #define _TM_DEFINED #endif extern struct tm * __cdecl localtime(const time_t *); extern time_t __cdecl time(time_t *); /* __stdio.h__ */ #ifndef BUFSIZ #define BUFSIZ 255 #endif #define rewind(stream) (void)fseek( stream, 0L, SEEK_SET ) /* __io.h__ */ typedef long off_t; extern int __cdecl close(int); extern int __cdecl creat(const char *, int); extern int __cdecl eof(int); extern long __cdecl lseek(int, long, int); extern int __cdecl open(const char *, int, ...); extern int __cdecl read(int, void *, unsigned int); extern int __cdecl unlink(const char *); extern int __cdecl write(int, const void *, unsigned int); extern int __cdecl rename(const char *, const char *); extern int __cdecl access(const char *, int); #ifdef DeleteFile #undef DeleteFile #endif #define DeleteFile(a) unlink(a) int chdir( const char *dirname ); extern char *getcwd( char *buffer, int maxlen ); /* __stdlib.h__ */ #define abort() (void)TerminateProcess(GetCurrentProcess(), 0) #ifndef strdup #define strdup _strdup #endif /* sys/stat.h */ #define S_IWRITE GENERIC_WRITE #define S_IREAD GENERIC_READ /* CE 2.xx is missing even more stuff */ #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) #define ZeroMemory(p, s) memset((p), 0, (s)) extern int __cdecl isupper(int c); extern int __cdecl isdigit(int c); extern int __cdecl isspace(int c); extern int __cdecl isprint(int c); extern char* __cdecl _strdup(const char* s); extern char* __cdecl strrchr( const char *string, int c ); extern int __cdecl _stricmp(const char* a, const char* b); extern FILE * __cdecl fopen(const char* filename, const char *mode); extern int __cdecl fscanf(FILE *f , const char *format, ...); extern int __cdecl fprintf(FILE *f , const char *format, ...); extern int __cdecl vfprintf(FILE* f, const char *format, va_list args); extern int __cdecl fgetc(FILE * f); extern char * __cdecl fgets(char *s, int size, FILE *f); extern int __cdecl printf(const char *format, ...); extern int __cdecl vprintf(const char *format, va_list args); extern int __cdecl puts(const char * s); extern FILE* __cdecl _getstdfilex(int desc); extern int __cdecl fclose(FILE * f); extern size_t __cdecl fread(void *p, size_t size, size_t count, FILE *f); extern size_t __cdecl fwrite(const void *p, size_t size, size_t count, FILE * f); extern int __cdecl fflush(FILE *f); extern int __cdecl feof(FILE *f); extern int __cdecl fseek(FILE *f, long offset, int from); extern long __cdecl ftell(FILE * f); #endif /* ARM - the processor; avoids conflict with ARM in hack.h */ # ifdef ARM # undef ARM # endif /* leave - Windows CE defines leave as part of exception handling (__leave) It confilicts with existing sources and since we don't use exceptions it is safe to undefine it */ # ifdef leave # undef leave # endif #endif /* WCECONF_H */ nethack-3.4.3/include/winGnome.h0100644000000000000000000000063707764735041015237 0ustar rootroot/* SCCS Id: @(#)winGnome.h 3.4. 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINGNOME_H #define WINGNOME_H #define E extern E struct window_procs Gnome_procs; #undef E #define NHW_WORN 6 extern winid WIN_WORN; #endif /* WINGNOME_H */ nethack-3.4.3/include/winX.h0100644000000000000000000003544307764735041014404 0ustar rootroot/* SCCS Id: @(#)winX.h 3.4 1996/08/18 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Definitions for the X11 window-port. See doc/window.doc for details on * the window interface. */ #ifndef WINX_H #define WINX_H #ifndef E #define E extern #endif #if defined(BOS) || defined(NHSTDC) #define DIMENSION_P int #else # ifdef WIDENED_PROTOTYPES #define DIMENSION_P unsigned int # else #define DIMENSION_P Dimension # endif #endif /* * Generic text buffer. */ #define START_SIZE 512 /* starting text buffer size */ struct text_buffer { char *text; int text_size; int text_last; int num_lines; }; /* * Information specific to a map window. */ struct text_map_info_t { unsigned char text[ROWNO][COLNO]; /* Actual displayed screen. */ #ifdef TEXTCOLOR unsigned char colors[ROWNO][COLNO]; /* Color of each character. */ GC color_gcs[CLR_MAX], /* GC for each color */ inv_color_gcs[CLR_MAX]; /* GC for each inverse color */ #define copy_gc color_gcs[NO_COLOR] #define inv_copy_gc inv_color_gcs[NO_COLOR] #else GC copy_gc, /* Drawing GC */ inv_copy_gc; /* Inverse drawing GC */ #endif }; struct tile_map_info_t { unsigned short glyphs[ROWNO][COLNO]; /* Saved glyph numbers. */ GC white_gc; GC black_gc; unsigned long image_width; /* dimensions of tile image */ unsigned long image_height; }; struct map_info_t { Dimension viewport_width, /* Saved viewport size, so we can */ viewport_height; /* clip to cursor on a resize. */ unsigned char t_start[ROWNO], /* Starting column for new info. */ t_stop[ROWNO]; /* Ending column for new info. */ int square_width, /* Saved font/tile information so */ square_height, /* we can calculate the correct */ square_ascent, /* placement of changes. */ square_lbearing; boolean is_tile; union { struct text_map_info_t *text_map; struct tile_map_info_t *tile_map; } mtype; }; /* * Information specific to a message window. */ struct line_element { struct line_element *next; char *line; /* char buffer */ int buf_length; /* length of buffer */ int str_length; /* length of string in buffer */ }; struct mesg_info_t { XFontStruct *fs; /* Font for the window. */ int num_lines; /* line count */ struct line_element *head; /* head of circular line queue */ struct line_element *line_here;/* current drawn line position */ struct line_element *last_pause;/* point to the line after the prev */ /* bottom of screen */ struct line_element *last_pause_head;/* pointer to head of previous */ /* turn */ GC gc; /* GC for text drawing */ int char_width, /* Saved font information so we can */ char_height, /* calculate the correct placement */ char_ascent, /* of changes. */ char_lbearing; Dimension viewport_width, /* Saved viewport size, so we can adjust */ viewport_height;/* the slider on a resize. */ Boolean dirty; /* Lines have been added to the window. */ }; /* * Information specific to a "text" status window. */ struct status_info_t { struct text_buffer text; /* Just a text buffer. */ }; /* * Information specific to a menu window. First a structure for each * menu entry, then the structure for each menu window. */ typedef struct x11_mi { struct x11_mi *next; anything identifier; /* Opaque type to identify this selection */ long pick_count; /* specific selection count; -1 if none */ char *str; /* The text of the item. */ int attr; /* Attribute for the line. */ boolean selected; /* Been selected? */ char selector; /* Char used to select this entry. */ char gselector; /* Group selector. */ } x11_menu_item; struct menu { x11_menu_item *base; /* Starting pointer for item list. */ x11_menu_item *last; /* End pointer for item list. */ const char *query; /* Query string. */ const char *gacc; /* Group accelerators. */ int count; /* Number of strings. */ String *list_pointer;/* String list. */ Boolean *sensitive; /* Active list. */ char curr_selector;/* Next keyboard accelerator to assign, */ /* if 0, then we're out. */ }; struct menu_info_t { struct menu curr_menu; /* Menu being displayed. */ struct menu new_menu; /* New menu being built. */ XFontStruct *fs; /* Font for the window. */ long menu_count; /* number entered by user */ Dimension line_height; /* Total height of a line of text. */ Dimension internal_height; /* Internal height between widget & border */ Dimension internal_width; /* Internal width between widget & border */ short how; /* Menu mode PICK_NONE, PICK_ONE, PICK_ANY */ boolean valid_widgets; /* TRUE if widgets have been created. */ boolean is_menu; /* Has been confirmed to being a menu window. */ boolean is_active; /* TRUE when waiting for user input. */ boolean is_up; /* TRUE when window is popped-up. */ boolean cancelled; /* Menu has been explicitly cancelled. */ boolean counting; /* true when menu_count has a valid value */ }; /* * Information specific to a text window. */ struct text_info_t { struct text_buffer text; XFontStruct *fs; /* Font for the text window. */ int max_width; /* Width of widest line so far. */ int extra_width, /* Sum of left and right border widths. */ extra_height; /* Sum of top and bottom border widths. */ boolean blocked; /* */ boolean destroy_on_ack; /* Destroy this window when acknowleged. */ #ifdef GRAPHIC_TOMBSTONE boolean is_rip; /* This window needs a tombstone. */ #endif }; /* * Basic window structure. */ struct xwindow { int type; /* type of nethack window */ Widget popup; /* direct parent of widget w or viewport */ Widget w; /* the widget that does things */ Dimension pixel_width; /* window size, in pixels */ Dimension pixel_height; int prevx, cursx; /* Cursor position, only used by */ int prevy, cursy; /* map and "plain" status windows.*/ union { struct map_info_t *Map_info; /* map window info */ struct mesg_info_t *Mesg_info; /* message window info */ struct status_info_t *Status_info; /* status window info */ struct menu_info_t *Menu_info; /* menu window info */ struct text_info_t *Text_info; /* menu window info */ } Win_info; boolean keep_window; }; /* Defines to use for the window information union. */ #define map_information Win_info.Map_info #define mesg_information Win_info.Mesg_info #define status_information Win_info.Status_info #define menu_information Win_info.Menu_info #define text_information Win_info.Text_info #define MAX_WINDOWS 20 /* max number of open windows */ #define NHW_NONE 0 /* Unallocated window type. Must be */ /* different from any other NHW_* type. */ #define NO_CLICK 0 /* No click occured on the map window. Must */ /* be different than CLICK_1 and CLICK_2. */ #define DEFAULT_MESSAGE_WIDTH 60/* width in chars of the message window */ #define DISPLAY_FILE_SIZE 35 /* Max number of lines in the default */ /* file display window. */ #define MAX_KEY_STRING 64 /* String size for converting a keypress */ /* event into a character(s) */ #define DEFAULT_LINES_DISPLAYED 12 /* # of lines displayed message window */ #define MAX_HISTORY 60 /* max history saved on message window */ /* Window variables (winX.c). */ E struct xwindow window_list[MAX_WINDOWS]; E XtAppContext app_context; /* context of application */ E Widget toplevel; /* toplevel widget */ E Atom wm_delete_window; /* delete window protocol */ E boolean exit_x_event; /* exit condition for event loop */ #define EXIT_ON_KEY_PRESS 0 /* valid values for exit_x_event */ #define EXIT_ON_KEY_OR_BUTTON_PRESS 1 #define EXIT_ON_EXIT 2 #define EXIT_ON_SENT_EVENT 3 E int click_x, click_y, click_button, updated_inventory; typedef struct { Boolean slow; Boolean autofocus; Boolean message_line; Boolean double_tile_size; /* double tile size */ String tile_file; /* name of file to open for tiles */ String icon; /* name of desired icon */ int message_lines; /* number of lines to attempt to show */ String pet_mark_bitmap; /* X11 bitmap file used to mark pets */ Pixel pet_mark_color; /* color of pet mark */ #ifdef GRAPHIC_TOMBSTONE String tombstone; /* name of XPM file for tombstone */ int tombtext_x; /* x-coord of center of first tombstone text */ int tombtext_y; /* y-coord of center of first tombstone text */ int tombtext_dx; /* x-displacement between tombstone line */ int tombtext_dy; /* y-displacement between tombstone line */ #endif } AppResources; E AppResources appResources; E void (*input_func)(); extern struct window_procs X11_procs; /* Check for an invalid window id. */ #define check_winid(window) \ if ((window) < 0 || (window) >= MAX_WINDOWS) { \ panic("illegal windid [%d] in %s at line %d", \ window, __FILE__, __LINE__); \ } /* ### dialogs.c ### */ E Widget FDECL(CreateDialog, (Widget, String, XtCallbackProc, XtCallbackProc)); E void FDECL(SetDialogPrompt,(Widget, String)); E String FDECL(GetDialogResponse,(Widget)); E void FDECL(SetDialogResponse,(Widget, String)); E void FDECL(positionpopup,(Widget,BOOLEAN_P)); /* ### winX.c ### */ E struct xwindow *FDECL(find_widget,(Widget)); E Boolean FDECL(nhApproxColor,(Screen*, Colormap, char*, XColor*)); E Dimension FDECL(nhFontHeight,(Widget)); E char FDECL(key_event_to_char,(XKeyEvent*)); E void FDECL(msgkey, (Widget, XtPointer, XEvent*)); E void FDECL(nh_XtPopup, (Widget, int, Widget)); E void FDECL(nh_XtPopdown, (Widget)); E void NDECL(win_X11_init); E void FDECL(nh_keyscroll, (Widget, XEvent*, String*, Cardinal*)); /* ### winmesg.c ### */ E void FDECL(set_message_slider, (struct xwindow*)); E void FDECL(create_message_window,(struct xwindow*, BOOLEAN_P, Widget)); E void FDECL(destroy_message_window,(struct xwindow*)); E void FDECL(display_message_window, (struct xwindow*)); E void FDECL(append_message,(struct xwindow*, const char*)); E void FDECL(set_last_pause, (struct xwindow*)); /* ### winmap.c ### */ E void NDECL(post_process_tiles); E void FDECL(check_cursor_visibility,(struct xwindow*)); E void FDECL(display_map_window,(struct xwindow*)); E void FDECL(clear_map_window,(struct xwindow*)); E void FDECL(map_input, (Widget, XEvent*, String*, Cardinal*)); E void FDECL(set_map_size,(struct xwindow*, DIMENSION_P, DIMENSION_P)); E void FDECL(create_map_window,(struct xwindow*, BOOLEAN_P, Widget)); E void FDECL(destroy_map_window,(struct xwindow*)); E int FDECL(x_event,(int)); /* ### winmenu.c ### */ E void FDECL(menu_delete, (Widget, XEvent*, String*, Cardinal*)); E void FDECL(menu_key,(Widget, XEvent*, String*, Cardinal*)); E void FDECL(create_menu_window,(struct xwindow*)); E void FDECL(destroy_menu_window,(struct xwindow*)); /* ### winmisc.c ### */ E void FDECL(ps_key,(Widget, XEvent*, String*, Cardinal*)); /* player selection action */ E void FDECL(race_key,(Widget, XEvent*, String*, Cardinal*)); /* race selection action */ E void FDECL(gend_key, (Widget,XEvent *,String *,Cardinal *)); /* gender */ E void FDECL(algn_key, (Widget,XEvent *,String *,Cardinal *)); /* alignment */ E void FDECL(ec_delete, (Widget, XEvent*, String*, Cardinal*)); E void FDECL(ec_key,(Widget, XEvent*, String*, Cardinal*)); /* extended command action */ /* ### winstatus.c ### */ E void FDECL(create_status_window,(struct xwindow*, BOOLEAN_P, Widget)); E void FDECL(destroy_status_window,(struct xwindow*)); E void FDECL(adjust_status,(struct xwindow*, const char*)); E void NDECL(null_out_status); E void NDECL(check_turn_events); /* ### wintext.c ### */ E void FDECL(delete_text, (Widget, XEvent*, String*, Cardinal*)); E void FDECL(dismiss_text,(Widget, XEvent*, String*, Cardinal*)); E void FDECL(key_dismiss_text,(Widget, XEvent*, String*, Cardinal*)); #ifdef GRAPHIC_TOMBSTONE E void FDECL(rip_dismiss_text,(Widget, XEvent*, String*, Cardinal*)); #endif E void FDECL(add_to_text_window,(struct xwindow*, int, const char*)); E void FDECL(display_text_window,(struct xwindow*, BOOLEAN_P)); E void FDECL(create_text_window,(struct xwindow*)); E void FDECL(destroy_text_window,(struct xwindow*)); E void FDECL(clear_text_window,(struct xwindow*)); E void FDECL(append_text_buffer,(struct text_buffer*, const char*, BOOLEAN_P)); /* text buffer routines */ E void FDECL(init_text_buffer,(struct text_buffer*)); E void FDECL(clear_text_buffer,(struct text_buffer*)); E void FDECL(free_text_buffer,(struct text_buffer*)); #ifdef GRAPHIC_TOMBSTONE E void FDECL(calculate_rip_text, (int)); #endif /* ### winval.c ### */ E Widget FDECL(create_value,(Widget, const char*)); E void FDECL(set_name,(Widget, char*)); E void FDECL(set_name_width,(Widget, int)); E int FDECL(get_name_width,(Widget)); E void FDECL(set_value,(Widget, const char*)); E void FDECL(set_value_width,(Widget, int)); E int FDECL(get_value_width,(Widget)); E void FDECL(hilight_value,(Widget)); E void FDECL(swap_fg_bg,(Widget)); /* external declarations */ E void FDECL(X11_init_nhwindows, (int *, char **)); E void NDECL(X11_player_selection); E void NDECL(X11_askname); E void NDECL(X11_get_nh_event) ; E void FDECL(X11_exit_nhwindows, (const char *)); E void FDECL(X11_suspend_nhwindows, (const char *)); E void NDECL(X11_resume_nhwindows); E winid FDECL(X11_create_nhwindow, (int)); E void FDECL(X11_clear_nhwindow, (winid)); E void FDECL(X11_display_nhwindow, (winid, BOOLEAN_P)); E void FDECL(X11_destroy_nhwindow, (winid)); E void FDECL(X11_curs, (winid,int,int)); E void FDECL(X11_putstr, (winid, int, const char *)); E void FDECL(X11_display_file, (const char *, BOOLEAN_P)); E void FDECL(X11_start_menu, (winid)); E void FDECL(X11_add_menu, (winid,int,const ANY_P *, CHAR_P, CHAR_P, int, const char *, BOOLEAN_P)); E void FDECL(X11_end_menu, (winid, const char *)); E int FDECL(X11_select_menu, (winid, int, MENU_ITEM_P **)); E void NDECL(X11_update_inventory); E void NDECL(X11_mark_synch); E void NDECL(X11_wait_synch); #ifdef CLIPPING E void FDECL(X11_cliparound, (int, int)); #endif E void FDECL(X11_print_glyph, (winid,XCHAR_P,XCHAR_P,int)); E void FDECL(X11_raw_print, (const char *)); E void FDECL(X11_raw_print_bold, (const char *)); E int NDECL(X11_nhgetch); E int FDECL(X11_nh_poskey, (int *, int *, int *)); E void NDECL(X11_nhbell); E int NDECL(X11_doprev_message); E char FDECL(X11_yn_function, (const char *, const char *, CHAR_P)); E void FDECL(X11_getlin, (const char *,char *)); E int NDECL(X11_get_ext_cmd); E void FDECL(X11_number_pad, (int)); E void NDECL(X11_delay_output); /* other defs that really should go away (they're tty specific) */ E void NDECL(X11_start_screen); E void NDECL(X11_end_screen); #ifdef GRAPHIC_TOMBSTONE E void FDECL(X11_outrip, (winid,int)); #else E void FDECL(genl_outrip, (winid,int)); #endif #endif /* WINX_H */ nethack-3.4.3/include/winami.h0100644000000000000000000001047607764735041014742 0ustar rootroot/* SCCS Id: @(#)winami.h 3.4 1993/01/17 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991. */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINAMI_H #define WINAMI_H #define MAXWINTAGS 5 /* * Information specific to a menu window. First a structure for each * menu entry, then the structure for each menu window. */ typedef struct amii_mi { struct amii_mi *next; anything identifier; /* Opaque type to identify this selection */ long glyph; /* Glyph for menu item */ long count; /* Object count */ char selected; /* Been selected? */ char selector; /* Char used to select this entry. */ char gselector; /* Group selector */ char canselect; /* Can user select this entry. */ char attr; /* Attribute for the line. */ char *str; /* The text of the item. */ } amii_menu_item; struct amii_menu { amii_menu_item *items; /* Starting pointer for item list. */ amii_menu_item *last; /* End pointer for item list. */ const char *query; /* Query string */ int count; /* Number of strings. */ char chr; /* Character to assign for accelerator */ }; /* descriptor for Amiga Intuition-based windows. If we decide to cope with * tty-style windows also, then things will need to change. */ /* per-window data */ struct amii_WinDesc { xchar type; /* type of window */ struct amii_menu menu; boolean active; /* true if window is active */ boolean wasup; /* true if menu/text window was already open */ short disprows; /* Rows displayed so far (used for paging in message win) */ xchar offx, offy; /* offset from topleft of display */ short vwx, vwy, vcx, vcy; /* View cursor location */ short rows, cols; /* dimensions */ short curx, cury; /* current cursor position */ short maxrow, maxcol; /* the maximum size used -- for INVEN wins */ /* maxcol is also used by WIN_MESSAGE for */ /* tracking the ^P command */ char **data; /* window data [row][column] */ menu_item *mi; /* Menu information */ char *resp; /* valid menu responses (for NHW_INVEN) */ char *canresp; /* cancel responses; 1st is the return value */ char *morestr; /* string to display instead of default */ /* amiga stuff */ struct Window *win; /* Intuition window pointer */ #ifdef INTUI_NEW_LOOK struct ExtNewWindow *newwin; /* NewWindow alloc'd */ #else struct NewWindow *newwin; /* ExtNewWindow alloc'd */ #endif #ifdef INTUI_NEW_LOOK struct TagItem wintags[ MAXWINTAGS ];/* Tag items for this window */ #else long wintags[ MAXWINTAGS*2 ]; #endif void *hook; /* Hook structure pointer for tiles version */ #define FLMAP_INGLYPH 1 /* An NHW_MAP window is in glyph mode */ #define FLMAP_CURSUP 2 /* An NHW_MAP window has the cursor displayed */ #define FLMAP_SKIP 4 #define FLMSG_FIRST 1 /* First message in the NHW_MESSAGE window for this turn */ long wflags; short cursx, cursy; /* Where the cursor is displayed at */ short curs_apen, /* Color cursor is displayed in */ curs_bpen; }; /* descriptor for intuition-based displays -- all the per-display data */ /* this is a generic thing - think of it as Screen level */ struct amii_DisplayDesc { /* we need this for Screen size (which will vary with display mode) */ uchar rows, cols; /* width & height of display in text units */ short xpix, ypix; /* width and height of display in pixels */ int toplin; /* flag for topl stuff */ int rawprint; /* number of raw_printed lines since synch */ winid lastwin; /* last window used for I/O */ }; typedef enum { WEUNK, WEKEY, WEMOUSE, WEMENU, } WETYPE; typedef struct WEVENT { WETYPE type; union { int key; struct { int x, y; int qual; } mouse; long menucode; } un; } WEVENT; #define MAXWIN 20 /* maximum number of windows, cop-out */ /* port specific variable declarations */ extern winid WIN_BASE; extern winid WIN_OVER; #define NHW_BASE 6 #define NHW_OVER 7 /* overview window */ extern struct amii_WinDesc *amii_wins[MAXWIN + 1]; extern struct amii_DisplayDesc *amiIDisplay; /* the Amiga Intuition descriptor */ extern char morc; /* last character typed to xwaitforspace */ extern char defmorestr[]; /* default --more-- prompt */ #endif /* WINAMI_H */ nethack-3.4.3/include/wingem.h0100644000000000000000000000713707764735041014744 0ustar rootroot/* SCCS Id: @(#)wingem.h 3.4 1999/12/10 */ /* Copyright (c) Christian Bressler, 1999 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINGEM_H #define WINGEM_H #define E extern /* menu structure */ typedef struct Gmi{ struct Gmi *Gmi_next; int Gmi_glyph; long Gmi_identifier; char Gmi_accelerator, Gmi_groupacc; int Gmi_attr; char *Gmi_str; long Gmi_count; int Gmi_selected; } Gem_menu_item; #define MAXWIN 20 /* maximum number of windows, cop-out */ extern struct window_procs Gem_procs; /* ### wingem1.c ### */ #ifdef CLIPPING E void NDECL(setclipped); #endif E void FDECL(docorner, (int, int)); E void NDECL(end_glyphout); E void FDECL(g_putch, (int)); E void NDECL(win_Gem_init); E int NDECL(mar_gem_init); E char NDECL(mar_ask_class); E char * NDECL(mar_ask_name); E int FDECL(mar_create_window, (int)); E void FDECL(mar_destroy_nhwindow, (int)); E void FDECL(mar_print_glyph, (int, int, int, int)); E void FDECL(mar_print_line, (int, int, int, char *)); E void FDECL(mar_set_message, (char *, char *, char *)); E Gem_menu_item *NDECL(mar_hol_inv); E void FDECL(mar_set_menu_type,(int)); E void NDECL(mar_reverse_menu); E void FDECL(mar_set_menu_title, (const char *)); E void NDECL(mar_set_accelerators); E void FDECL(mar_add_menu, (winid, Gem_menu_item *)); E void FDECL(mar_change_menu_2_text, (winid)); E void FDECL(mar_add_message, (const char *)); E void NDECL(mar_status_dirty); E int FDECL(mar_hol_win_type, (int)); E void NDECL(mar_clear_messagewin); E void FDECL(mar_set_no_glyph, (int)); E void NDECL(mar_map_curs_weiter); /* external declarations */ E void FDECL(Gem_init_nhwindows, (int *, char **)); E void NDECL(Gem_player_selection); E void NDECL(Gem_askname); E void NDECL(Gem_get_nh_event) ; E void FDECL(Gem_exit_nhwindows, (const char *)); E void FDECL(Gem_suspend_nhwindows, (const char *)); E void NDECL(Gem_resume_nhwindows); E winid FDECL(Gem_create_nhwindow, (int)); E void FDECL(Gem_clear_nhwindow, (winid)); E void FDECL(Gem_display_nhwindow, (winid, BOOLEAN_P)); E void FDECL(Gem_dismiss_nhwindow, (winid)); E void FDECL(Gem_destroy_nhwindow, (winid)); E void FDECL(Gem_curs, (winid,int,int)); E void FDECL(Gem_putstr, (winid, int, const char *)); E void FDECL(Gem_display_file, (const char *, BOOLEAN_P)); E void FDECL(Gem_start_menu, (winid)); E void FDECL(Gem_add_menu, (winid,int,const ANY_P *, CHAR_P,CHAR_P,int,const char *, BOOLEAN_P)); E void FDECL(Gem_end_menu, (winid, const char *)); E int FDECL(Gem_select_menu, (winid, int, MENU_ITEM_P **)); E char FDECL(Gem_message_menu, (CHAR_P,int,const char *)); E void NDECL(Gem_update_inventory); E void NDECL(Gem_mark_synch); E void NDECL(Gem_wait_synch); #ifdef CLIPPING E void FDECL(Gem_cliparound, (int, int)); #endif #ifdef POSITIONBAR E void FDECL(Gem_update_positionbar, (char *)); #endif E void FDECL(Gem_print_glyph, (winid,XCHAR_P,XCHAR_P,int)); E void FDECL(Gem_raw_print, (const char *)); E void FDECL(Gem_raw_print_bold, (const char *)); E int NDECL(Gem_nhgetch); E int FDECL(Gem_nh_poskey, (int *, int *, int *)); E void NDECL(Gem_nhbell); E int NDECL(Gem_doprev_message); E char FDECL(Gem_yn_function, (const char *, const char *, CHAR_P)); E void FDECL(Gem_getlin, (const char *,char *)); E int NDECL(Gem_get_ext_cmd); E void FDECL(Gem_number_pad, (int)); E void NDECL(Gem_delay_output); #ifdef CHANGE_COLOR E void FDECL(Gem_change_color,(int color,long rgb,int reverse)); E char * NDECL(Gem_get_color_string); #endif /* other defs that really should go away (they're tty specific) */ E void NDECL(Gem_start_screen); E void NDECL(Gem_end_screen); E void FDECL(genl_outrip, (winid,int)); #undef E #endif /* WINGEM_H */ nethack-3.4.3/include/winprocs.h0100644000000000000000000002303607764735041015316 0ustar rootroot/* SCCS Id: @(#)winprocs.h 3.4 2003/01/08 */ /* Copyright (c) David Cohrs, 1992 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINPROCS_H #define WINPROCS_H struct window_procs { const char *name; unsigned long wincap; /* window port capability options supported */ unsigned long wincap2; /* additional window port capability options supported */ void FDECL((*win_init_nhwindows), (int *, char **)); void NDECL((*win_player_selection)); void NDECL((*win_askname)); void NDECL((*win_get_nh_event)) ; void FDECL((*win_exit_nhwindows), (const char *)); void FDECL((*win_suspend_nhwindows), (const char *)); void NDECL((*win_resume_nhwindows)); winid FDECL((*win_create_nhwindow), (int)); void FDECL((*win_clear_nhwindow), (winid)); void FDECL((*win_display_nhwindow), (winid, BOOLEAN_P)); void FDECL((*win_destroy_nhwindow), (winid)); void FDECL((*win_curs), (winid,int,int)); void FDECL((*win_putstr), (winid, int, const char *)); void FDECL((*win_display_file), (const char *, BOOLEAN_P)); void FDECL((*win_start_menu), (winid)); void FDECL((*win_add_menu), (winid,int,const ANY_P *, CHAR_P,CHAR_P,int,const char *, BOOLEAN_P)); void FDECL((*win_end_menu), (winid, const char *)); int FDECL((*win_select_menu), (winid, int, MENU_ITEM_P **)); char FDECL((*win_message_menu), (CHAR_P,int,const char *)); void NDECL((*win_update_inventory)); void NDECL((*win_mark_synch)); void NDECL((*win_wait_synch)); #ifdef CLIPPING void FDECL((*win_cliparound), (int, int)); #endif #ifdef POSITIONBAR void FDECL((*win_update_positionbar), (char *)); #endif void FDECL((*win_print_glyph), (winid,XCHAR_P,XCHAR_P,int)); void FDECL((*win_raw_print), (const char *)); void FDECL((*win_raw_print_bold), (const char *)); int NDECL((*win_nhgetch)); int FDECL((*win_nh_poskey), (int *, int *, int *)); void NDECL((*win_nhbell)); int NDECL((*win_doprev_message)); char FDECL((*win_yn_function), (const char *, const char *, CHAR_P)); void FDECL((*win_getlin), (const char *,char *)); int NDECL((*win_get_ext_cmd)); void FDECL((*win_number_pad), (int)); void NDECL((*win_delay_output)); #ifdef CHANGE_COLOR void FDECL((*win_change_color), (int,long,int)); #ifdef MAC void FDECL((*win_change_background), (int)); short FDECL((*win_set_font_name), (winid, char *)); #endif char * NDECL((*win_get_color_string)); #endif /* other defs that really should go away (they're tty specific) */ void NDECL((*win_start_screen)); void NDECL((*win_end_screen)); void FDECL((*win_outrip), (winid,int)); void FDECL((*win_preference_update), (const char *)); }; extern NEARDATA struct window_procs windowprocs; /* * If you wish to only support one window system and not use procedure * pointers, add the appropriate #ifdef below. */ #define init_nhwindows (*windowprocs.win_init_nhwindows) #define player_selection (*windowprocs.win_player_selection) #define askname (*windowprocs.win_askname) #define get_nh_event (*windowprocs.win_get_nh_event) #define exit_nhwindows (*windowprocs.win_exit_nhwindows) #define suspend_nhwindows (*windowprocs.win_suspend_nhwindows) #define resume_nhwindows (*windowprocs.win_resume_nhwindows) #define create_nhwindow (*windowprocs.win_create_nhwindow) #define clear_nhwindow (*windowprocs.win_clear_nhwindow) #define display_nhwindow (*windowprocs.win_display_nhwindow) #define destroy_nhwindow (*windowprocs.win_destroy_nhwindow) #define curs (*windowprocs.win_curs) #define putstr (*windowprocs.win_putstr) #define display_file (*windowprocs.win_display_file) #define start_menu (*windowprocs.win_start_menu) #define add_menu (*windowprocs.win_add_menu) #define end_menu (*windowprocs.win_end_menu) #define select_menu (*windowprocs.win_select_menu) #define message_menu (*windowprocs.win_message_menu) #define update_inventory (*windowprocs.win_update_inventory) #define mark_synch (*windowprocs.win_mark_synch) #define wait_synch (*windowprocs.win_wait_synch) #ifdef CLIPPING #define cliparound (*windowprocs.win_cliparound) #endif #ifdef POSITIONBAR #define update_positionbar (*windowprocs.win_update_positionbar) #endif #define print_glyph (*windowprocs.win_print_glyph) #define raw_print (*windowprocs.win_raw_print) #define raw_print_bold (*windowprocs.win_raw_print_bold) #define nhgetch (*windowprocs.win_nhgetch) #define nh_poskey (*windowprocs.win_nh_poskey) #define nhbell (*windowprocs.win_nhbell) #define nh_doprev_message (*windowprocs.win_doprev_message) #define getlin (*windowprocs.win_getlin) #define get_ext_cmd (*windowprocs.win_get_ext_cmd) #define number_pad (*windowprocs.win_number_pad) #define delay_output (*windowprocs.win_delay_output) #ifdef CHANGE_COLOR #define change_color (*windowprocs.win_change_color) #ifdef MAC #define change_background (*windowprocs.win_change_background) #define set_font_name (*windowprocs.win_set_font_name) #endif #define get_color_string (*windowprocs.win_get_color_string) #endif /* 3.4.2: There is a real yn_function() in the core now, which does * some buffer length validation on the parameters prior to * invoking the window port routine. yn_function() is in cmd.c */ /* #define yn_function (*windowprocs.win_yn_function) */ /* other defs that really should go away (they're tty specific) */ #define start_screen (*windowprocs.win_start_screen) #define end_screen (*windowprocs.win_end_screen) #define outrip (*windowprocs.win_outrip) #define preference_update (*windowprocs.win_preference_update) /* * WINCAP * Window port preference capability bits. * Some day this might be better in its own wincap.h file. */ #define WC_COLOR 0x01L /* 01 Port can display things in color */ #define WC_HILITE_PET 0x02L /* 02 supports hilite pet */ #define WC_ASCII_MAP 0x04L /* 03 supports an ascii map */ #define WC_TILED_MAP 0x08L /* 04 supports a tiled map */ #define WC_PRELOAD_TILES 0x10L /* 05 supports pre-loading tiles */ #define WC_TILE_WIDTH 0x20L /* 06 prefer this width of tile */ #define WC_TILE_HEIGHT 0x40L /* 07 prefer this height of tile */ #define WC_TILE_FILE 0x80L /* 08 alternative tile file name */ #define WC_INVERSE 0x100L /* 09 Port supports inverse video */ #define WC_ALIGN_MESSAGE 0x200L /* 10 supports message alignmt top|b|l|r */ #define WC_ALIGN_STATUS 0x400L /* 11 supports status alignmt top|b|l|r */ #define WC_VARY_MSGCOUNT 0x800L /* 12 supports varying message window */ #define WC_FONT_MAP 0x1000L /* 13 supports specification of map win font */ #define WC_FONT_MESSAGE 0x2000L /* 14 supports specification of msg win font */ #define WC_FONT_STATUS 0x4000L /* 15 supports specification of sts win font */ #define WC_FONT_MENU 0x8000L /* 16 supports specification of mnu win font */ #define WC_FONT_TEXT 0x10000L /* 17 supports specification of txt win font */ #define WC_FONTSIZ_MAP 0x20000L /* 18 supports specification of map win font */ #define WC_FONTSIZ_MESSAGE 0x40000L /* 19 supports specification of msg win font */ #define WC_FONTSIZ_STATUS 0x80000L /* 20 supports specification of sts win font */ #define WC_FONTSIZ_MENU 0x100000L /* 21 supports specification of mnu win font */ #define WC_FONTSIZ_TEXT 0x200000L /* 22 supports specification of txt win font */ #define WC_SCROLL_MARGIN 0x400000L /* 23 supports setting scroll margin for map */ #define WC_SPLASH_SCREEN 0x800000L /* 24 supports display of splash screen */ #define WC_POPUP_DIALOG 0x1000000L /* 25 supports queries in pop dialogs */ #define WC_SCROLL_AMOUNT 0x2000000L /* 26 scroll this amount at scroll margin */ #define WC_EIGHT_BIT_IN 0x4000000L /* 27 8-bit character input */ #define WC_PERM_INVENT 0x8000000L /* 28 8-bit character input */ #define WC_MAP_MODE 0x10000000L /* 29 map_mode option */ #define WC_WINDOWCOLORS 0x20000000L /* 30 background color for message window */ #define WC_PLAYER_SELECTION 0x40000000L /* 31 background color for message window */ #define WC_MOUSE_SUPPORT 0x80000000L /* 32 mouse support */ /* no free bits */ #define WC2_FULLSCREEN 0x01L /* 01 display full screen */ #define WC2_SOFTKEYBOARD 0x02L /* 02 software keyboard */ #define WC2_WRAPTEXT 0x04L /* 04 wrap long lines of text */ /* 29 free bits */ #define ALIGN_LEFT 1 #define ALIGN_RIGHT 2 #define ALIGN_TOP 3 #define ALIGN_BOTTOM 4 /* player_selection */ #define VIA_DIALOG 0 #define VIA_PROMPTS 1 /* map_mode settings - deprecated */ #define MAP_MODE_TILES 0 #define MAP_MODE_ASCII4x6 1 #define MAP_MODE_ASCII6x8 2 #define MAP_MODE_ASCII8x8 3 #define MAP_MODE_ASCII16x8 4 #define MAP_MODE_ASCII7x12 5 #define MAP_MODE_ASCII8x12 6 #define MAP_MODE_ASCII16x12 7 #define MAP_MODE_ASCII12x16 8 #define MAP_MODE_ASCII10x18 9 #define MAP_MODE_ASCII_FIT_TO_SCREEN 10 #define MAP_MODE_TILES_FIT_TO_SCREEN 11 #if 0 #define WC_SND_SOUND 0x01L /* 01 Port has some sound capabilities */ #define WC_SND_SPEAKER 0x02L /* 02 Sound supported via built-in speaker */ #define WC_SND_STEREO 0x04L /* 03 Stereo sound supported */ #define WC_SND_RAW 0x08L /* 04 Raw sound supported */ #define WC_SND_WAVE 0x10L /* 05 Wave support */ #define WC_SND_MIDI 0x20L /* 06 Midi support */ /* 26 free bits */ #endif struct wc_Opt { const char *wc_name; unsigned long wc_bit; }; #endif /* WINPROCS_H */ nethack-3.4.3/include/wintty.h0100644000000000000000000001772607764735041015021 0ustar rootroot/* SCCS Id: @(#)wintty.h 3.4 1996/02/18 */ /* Copyright (c) David Cohrs, 1991,1992 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINTTY_H #define WINTTY_H #define E extern #ifndef WINDOW_STRUCTS #define WINDOW_STRUCTS /* menu structure */ typedef struct tty_mi { struct tty_mi *next; anything identifier; /* user identifier */ long count; /* user count */ char *str; /* description string (including accelerator) */ int attr; /* string attribute */ boolean selected; /* TRUE if selected by user */ char selector; /* keyboard accelerator */ char gselector; /* group accelerator */ } tty_menu_item; /* descriptor for tty-based windows */ struct WinDesc { int flags; /* window flags */ xchar type; /* type of window */ boolean active; /* true if window is active */ uchar offx, offy; /* offset from topleft of display */ short rows, cols; /* dimensions */ short curx, cury; /* current cursor position */ short maxrow, maxcol; /* the maximum size used -- for MENU wins */ /* maxcol is also used by WIN_MESSAGE for */ /* tracking the ^P command */ short *datlen; /* allocation size for *data */ char **data; /* window data [row][column] */ char *morestr; /* string to display instead of default */ tty_menu_item *mlist; /* menu information (MENU) */ tty_menu_item **plist; /* menu page pointers (MENU) */ short plist_size; /* size of allocated plist (MENU) */ short npages; /* number of pages in menu (MENU) */ short nitems; /* total number of items (MENU) */ short how; /* menu mode - pick 1 or N (MENU) */ char menu_ch; /* menu char (MENU) */ }; /* window flags */ #define WIN_CANCELLED 1 #define WIN_STOP 1 /* for NHW_MESSAGE; stops output */ /* descriptor for tty-based displays -- all the per-display data */ struct DisplayDesc { uchar rows, cols; /* width and height of tty display */ uchar curx, cury; /* current cursor position on the screen */ #ifdef TEXTCOLOR int color; /* current color */ #endif int attrs; /* attributes in effect */ int toplin; /* flag for topl stuff */ int rawprint; /* number of raw_printed lines since synch */ int inmore; /* non-zero if more() is active */ int inread; /* non-zero if reading a character */ int intr; /* non-zero if inread was interrupted */ winid lastwin; /* last window used for I/O */ char dismiss_more; /* extra character accepted at --More-- */ }; #endif /* WINDOW_STRUCTS */ #define MAXWIN 20 /* maximum number of windows, cop-out */ /* tty dependent window types */ #ifdef NHW_BASE #undef NHW_BASE #endif #define NHW_BASE 6 extern struct window_procs tty_procs; /* port specific variable declarations */ extern winid BASE_WINDOW; extern struct WinDesc *wins[MAXWIN]; extern struct DisplayDesc *ttyDisplay; /* the tty display descriptor */ extern char morc; /* last character typed to xwaitforspace */ extern char defmorestr[]; /* default --more-- prompt */ /* port specific external function references */ /* ### getline.c ### */ E void FDECL(xwaitforspace, (const char *)); /* ### termcap.c, video.c ### */ E void FDECL(tty_startup,(int*, int*)); #ifndef NO_TERMS E void NDECL(tty_shutdown); #endif #if defined(apollo) /* Apollos don't widen old-style function definitions properly -- they try to * be smart and use the prototype, or some such strangeness. So we have to * define UNWIDENDED_PROTOTYPES (in tradstdc.h), which makes CHAR_P below a * char. But the tputs termcap call was compiled as if xputc's argument * actually would be expanded. So here, we have to make an exception. */ E void FDECL(xputc, (int)); #else E void FDECL(xputc, (CHAR_P)); #endif E void FDECL(xputs, (const char *)); #if defined(SCREEN_VGA) || defined(SCREEN_8514) E void FDECL(xputg, (int, int, unsigned)); #endif E void NDECL(cl_end); E void NDECL(clear_screen); E void NDECL(home); E void NDECL(standoutbeg); E void NDECL(standoutend); # if 0 E void NDECL(revbeg); E void NDECL(boldbeg); E void NDECL(blinkbeg); E void NDECL(dimbeg); E void NDECL(m_end); # endif E void NDECL(backsp); E void NDECL(graph_on); E void NDECL(graph_off); E void NDECL(cl_eos); /* * termcap.c (or facsimiles in other ports) is the right place for doing * strange and arcane things such as outputting escape sequences to select * a color or whatever. wintty.c should concern itself with WHERE to put * stuff in a window. */ E void FDECL(term_start_attr,(int attr)); E void FDECL(term_end_attr,(int attr)); E void NDECL(term_start_raw_bold); E void NDECL(term_end_raw_bold); #ifdef TEXTCOLOR E void NDECL(term_end_color); E void FDECL(term_start_color,(int color)); E int FDECL(has_color,(int color)); #endif /* TEXTCOLOR */ /* ### topl.c ### */ E void FDECL(addtopl, (const char *)); E void NDECL(more); E void FDECL(update_topl, (const char *)); E void FDECL(putsyms, (const char*)); /* ### wintty.c ### */ #ifdef CLIPPING E void NDECL(setclipped); #endif E void FDECL(docorner, (int, int)); E void NDECL(end_glyphout); E void FDECL(g_putch, (int)); E void NDECL(win_tty_init); /* external declarations */ E void FDECL(tty_init_nhwindows, (int *, char **)); E void NDECL(tty_player_selection); E void NDECL(tty_askname); E void NDECL(tty_get_nh_event) ; E void FDECL(tty_exit_nhwindows, (const char *)); E void FDECL(tty_suspend_nhwindows, (const char *)); E void NDECL(tty_resume_nhwindows); E winid FDECL(tty_create_nhwindow, (int)); E void FDECL(tty_clear_nhwindow, (winid)); E void FDECL(tty_display_nhwindow, (winid, BOOLEAN_P)); E void FDECL(tty_dismiss_nhwindow, (winid)); E void FDECL(tty_destroy_nhwindow, (winid)); E void FDECL(tty_curs, (winid,int,int)); E void FDECL(tty_putstr, (winid, int, const char *)); E void FDECL(tty_display_file, (const char *, BOOLEAN_P)); E void FDECL(tty_start_menu, (winid)); E void FDECL(tty_add_menu, (winid,int,const ANY_P *, CHAR_P,CHAR_P,int,const char *, BOOLEAN_P)); E void FDECL(tty_end_menu, (winid, const char *)); E int FDECL(tty_select_menu, (winid, int, MENU_ITEM_P **)); E char FDECL(tty_message_menu, (CHAR_P,int,const char *)); E void NDECL(tty_update_inventory); E void NDECL(tty_mark_synch); E void NDECL(tty_wait_synch); #ifdef CLIPPING E void FDECL(tty_cliparound, (int, int)); #endif #ifdef POSITIONBAR E void FDECL(tty_update_positionbar, (char *)); #endif E void FDECL(tty_print_glyph, (winid,XCHAR_P,XCHAR_P,int)); E void FDECL(tty_raw_print, (const char *)); E void FDECL(tty_raw_print_bold, (const char *)); E int NDECL(tty_nhgetch); E int FDECL(tty_nh_poskey, (int *, int *, int *)); E void NDECL(tty_nhbell); E int NDECL(tty_doprev_message); E char FDECL(tty_yn_function, (const char *, const char *, CHAR_P)); E void FDECL(tty_getlin, (const char *,char *)); E int NDECL(tty_get_ext_cmd); E void FDECL(tty_number_pad, (int)); E void NDECL(tty_delay_output); #ifdef CHANGE_COLOR E void FDECL(tty_change_color,(int color,long rgb,int reverse)); #ifdef MAC E void FDECL(tty_change_background,(int white_or_black)); E short FDECL(set_tty_font_name, (winid, char *)); #endif E char * NDECL(tty_get_color_string); #endif /* other defs that really should go away (they're tty specific) */ E void NDECL(tty_start_screen); E void NDECL(tty_end_screen); E void FDECL(genl_outrip, (winid,int)); #ifdef NO_TERMS # ifdef MAC # ifdef putchar # undef putchar # undef putc # endif # define putchar term_putc # define fflush term_flush # define puts term_puts E int FDECL(term_putc, (int c)); E int FDECL(term_flush, (void *desc)); E int FDECL(term_puts, (const char *str)); # endif /* MAC */ # if defined(MSDOS) || defined(WIN32CON) # if defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST) || defined(WIN32CON) # undef putchar # undef putc # undef puts # define putchar(x) xputc(x) /* these are in video.c, nttty.c */ # define putc(x) xputc(x) # define puts(x) xputs(x) # endif/*SCREEN_BIOS || SCREEN_DJGPPFAST || WIN32CON */ # ifdef POSITIONBAR E void FDECL(video_update_positionbar, (char *)); # endif # endif/*MSDOS*/ #endif/*NO_TERMS*/ #undef E #endif /* WINTTY_H */ nethack-3.4.3/include/wintype.h0100644000000000000000000000345707764735041015156 0ustar rootroot/* SCCS Id: @(#)wintype.h 3.4 1996/02/18 */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINTYPE_H #define WINTYPE_H typedef int winid; /* a window identifier */ /* generic parameter - must not be any larger than a pointer */ typedef union any { genericptr_t a_void; struct obj *a_obj; int a_int; char a_char; schar a_schar; /* add types as needed */ } anything; #define ANY_P union any /* avoid typedef in prototypes */ /* (buggy old Ultrix compiler) */ /* menu return list */ typedef struct mi { anything item; /* identifier */ long count; /* count */ } menu_item; #define MENU_ITEM_P struct mi /* select_menu() "how" argument types */ #define PICK_NONE 0 /* user picks nothing (display only) */ #define PICK_ONE 1 /* only pick one */ #define PICK_ANY 2 /* can pick any amount */ /* window types */ /* any additional port specific types should be defined in win*.h */ #define NHW_MESSAGE 1 #define NHW_STATUS 2 #define NHW_MAP 3 #define NHW_MENU 4 #define NHW_TEXT 5 /* attribute types for putstr; the same as the ANSI value, for convenience */ #define ATR_NONE 0 #define ATR_BOLD 1 #define ATR_DIM 2 #define ATR_ULINE 4 #define ATR_BLINK 5 #define ATR_INVERSE 7 /* nh_poskey() modifier types */ #define CLICK_1 1 #define CLICK_2 2 /* invalid winid */ #define WIN_ERR ((winid) -1) /* menu window keyboard commands (may be mapped) */ #define MENU_FIRST_PAGE '^' #define MENU_LAST_PAGE '|' #define MENU_NEXT_PAGE '>' #define MENU_PREVIOUS_PAGE '<' #define MENU_SELECT_ALL '.' #define MENU_UNSELECT_ALL '-' #define MENU_INVERT_ALL '@' #define MENU_SELECT_PAGE ',' #define MENU_UNSELECT_PAGE '\\' #define MENU_INVERT_PAGE '~' #define MENU_SEARCH ':' #endif /* WINTYPE_H */ nethack-3.4.3/include/xwindow.h0100644000000000000000000000545307764735041015154 0ustar rootroot/* SCCS Id: @(#)xwindow.h 3.4 1992/03/07 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef _xwindow_h #define _xwindow_h /**************************************************************** * * Window widget * ****************************************************************/ /* Resources: Name Class RepType Default Value ---- ----- ------- ------------- background Background Pixel XtDefaultBackground border BorderColor Pixel XtDefaultForeground borderWidth BorderWidth Dimension 1 destroyCallback Callback Pointer NULL height Height Dimension 0 mappedWhenManaged MappedWhenManaged Boolean True sensitive Sensitive Boolean True width Width Dimension 0 x Position Position 0 y Position Position 0 rows Width Dimension 21 columns Height Dimension 80 foreground Color Pixel XtDefaultForeground black Color Pixel "black" red Color Pixel "red" green Color Pixel "pale green" brown Color Pixel "brown" blue Color Pixel "blue" magenta Color Pixel "magenta" cyan Color Pixel "light cyan" gray Color Pixel "gray" //no color// orange Color Pixel "orange" bright_green Color Pixel "green" yellow Color Pixel "yellow" bright_blue Color Pixel "royal blue" bright_magenta Color Pixel "violet" bright_cyan Color Pixel "cyan" white Color Pixel "white" font Font XFontStruct* XtDefaultFont exposeCallback Callback Callback NULL callback Callback Callback NULL resizeCallback Callback Callback NULL */ /* define any special resource names here that are not in */ #define XtNrows "rows" #define XtNcolumns "columns" #define XtNblack "black" #define XtNred "red" #define XtNgreen "green" #define XtNbrown "brown" #define XtNblue "blue" #define XtNmagenta "magenta" #define XtNcyan "cyan" #define XtNgray "gray" #define XtNorange "orange" #define XtNbright_green "bright_green" #define XtNyellow "yellow" #define XtNbright_blue "bright_blue" #define XtNbright_magenta "bright_magenta" #define XtNbright_cyan "bright_cyan" #define XtNwhite "white" #define XtNexposeCallback "exposeCallback" #define XtNresizeCallback "resizeCallback" extern XFontStruct *WindowFontStruct(/* Widget */); extern Font WindowFont(/* Widget */); #define XtCWindowResource "WindowResource" #define XtCRows "Rows" #define XtCColumns "Columns" /* declare specific WindowWidget class and instance datatypes */ typedef struct _WindowClassRec *WindowWidgetClass; typedef struct _WindowRec *WindowWidget; /* declare the class constant */ extern WidgetClass windowWidgetClass; #endif /* _xwindow_h */ nethack-3.4.3/include/xwindowp.h0100644000000000000000000000277007764735041015333 0ustar rootroot/* SCCS Id: @(#)xwindowp.h 3.4 1992/03/07 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ #ifndef _xwindowp_h #define _xwindowp_h #include "xwindow.h" #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif /* include superclass private header file */ #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif /* define unique representation types not found in */ #define XtRWindowResource "WindowResource" typedef struct { int empty; } WindowClassPart; typedef struct _WindowClassRec { CoreClassPart core_class; WindowClassPart window_class; } WindowClassRec; extern WindowClassRec windowClassRec; typedef struct { /* resources */ Dimension rows; Dimension columns; Pixel foreground; Pixel black; Pixel red; Pixel green; Pixel brown; Pixel blue; Pixel magenta; Pixel cyan; Pixel gray; Pixel orange; Pixel bright_green; Pixel yellow; Pixel bright_blue; Pixel bright_magenta; Pixel bright_cyan; Pixel white; XFontStruct *font; XtCallbackList expose_callback; XtCallbackList input_callback; XtCallbackList resize_callback; /* private state */ /* (none) */ } WindowPart; typedef struct _WindowRec { CorePart core; WindowPart window; } WindowRec; #endif /* _xwindowp_h */ nethack-3.4.3/include/you.h0100644000000000000000000003254607764735041014274 0ustar rootroot/* SCCS Id: @(#)you.h 3.4 2000/05/21 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef YOU_H #define YOU_H #include "attrib.h" #include "monst.h" #ifndef PROP_H #include "prop.h" /* (needed here for util/makedefs.c) */ #endif #include "skills.h" /*** Substructures ***/ struct RoleName { const char *m; /* name when character is male */ const char *f; /* when female; null if same as male */ }; struct RoleAdvance { /* "fix" is the fixed amount, "rnd" is the random amount */ xchar infix, inrnd; /* at character initialization */ xchar lofix, lornd; /* gained per level < urole.xlev */ xchar hifix, hirnd; /* gained per level >= urole.xlev */ }; struct u_have { Bitfield(amulet,1); /* carrying Amulet */ Bitfield(bell,1); /* carrying Bell */ Bitfield(book,1); /* carrying Book */ Bitfield(menorah,1); /* carrying Candelabrum */ Bitfield(questart,1); /* carrying the Quest Artifact */ Bitfield(unused,3); }; struct u_event { Bitfield(minor_oracle,1); /* received at least 1 cheap oracle */ Bitfield(major_oracle,1); /* " expensive oracle */ Bitfield(qcalled,1); /* called by Quest leader to do task */ Bitfield(qexpelled,1); /* expelled from the Quest dungeon */ Bitfield(qcompleted,1); /* successfully completed Quest task */ Bitfield(uheard_tune,2); /* 1=know about, 2=heard passtune */ Bitfield(uopened_dbridge,1); /* opened the drawbridge */ Bitfield(invoked,1); /* invoked Gate to the Sanctum level */ Bitfield(gehennom_entered,1); /* entered Gehennom via Valley */ #ifdef ELBERETH Bitfield(uhand_of_elbereth,2); /* became Hand of Elbereth */ #endif Bitfield(udemigod,1); /* killed the wiz */ Bitfield(ascended,1); /* has offered the Amulet */ }; /* KMH, conduct -- * These are voluntary challenges. Each field denotes the number of * times a challenge has been violated. */ struct u_conduct { /* number of times... */ long unvegetarian; /* eaten any animal */ long unvegan; /* ... or any animal byproduct */ long food; /* ... or any comestible */ long gnostic; /* used prayer, priest, or altar */ long weaphit; /* hit a monster with a weapon */ long killer; /* killed a monster yourself */ long literate; /* read something (other than BotD) */ long polypiles; /* polymorphed an object */ long polyselfs; /* transformed yourself */ long wishes; /* used a wish */ long wisharti; /* wished for an artifact */ /* genocides already listed at end of game */ }; /*** Unified structure containing role information ***/ struct Role { /*** Strings that name various things ***/ struct RoleName name; /* the role's name (from u_init.c) */ struct RoleName rank[9]; /* names for experience levels (from botl.c) */ const char *lgod, *ngod, *cgod; /* god names (from pray.c) */ const char *filecode; /* abbreviation for use in file names */ const char *homebase; /* quest leader's location (from questpgr.c) */ const char *intermed; /* quest intermediate goal (from questpgr.c) */ /*** Indices of important monsters and objects ***/ short malenum, /* index (PM_) as a male (botl.c) */ femalenum, /* ...or as a female (NON_PM == same) */ petnum, /* PM_ of preferred pet (NON_PM == random) */ ldrnum, /* PM_ of quest leader (questpgr.c) */ guardnum, /* PM_ of quest guardians (questpgr.c) */ neminum, /* PM_ of quest nemesis (questpgr.c) */ enemy1num, /* specific quest enemies (NON_PM == random) */ enemy2num; char enemy1sym, /* quest enemies by class (S_) */ enemy2sym; short questarti; /* index (ART_) of quest artifact (questpgr.c) */ /*** Bitmasks ***/ short allow; /* bit mask of allowed variations */ #define ROLE_RACEMASK 0x0ff8 /* allowable races */ #define ROLE_GENDMASK 0xf000 /* allowable genders */ #define ROLE_MALE 0x1000 #define ROLE_FEMALE 0x2000 #define ROLE_NEUTER 0x4000 #define ROLE_ALIGNMASK AM_MASK /* allowable alignments */ #define ROLE_LAWFUL AM_LAWFUL #define ROLE_NEUTRAL AM_NEUTRAL #define ROLE_CHAOTIC AM_CHAOTIC /*** Attributes (from attrib.c and exper.c) ***/ xchar attrbase[A_MAX]; /* lowest initial attributes */ xchar attrdist[A_MAX]; /* distribution of initial attributes */ struct RoleAdvance hpadv; /* hit point advancement */ struct RoleAdvance enadv; /* energy advancement */ xchar xlev; /* cutoff experience level */ xchar initrecord; /* initial alignment record */ /*** Spell statistics (from spell.c) ***/ int spelbase; /* base spellcasting penalty */ int spelheal; /* penalty (-bonus) for healing spells */ int spelshld; /* penalty for wearing any shield */ int spelarmr; /* penalty for wearing metal armour */ int spelstat; /* which stat (A_) is used */ int spelspec; /* spell (SPE_) the class excels at */ int spelsbon; /* penalty (-bonus) for that spell */ /*** Properties in variable-length arrays ***/ /* intrinsics (see attrib.c) */ /* initial inventory (see u_init.c) */ /* skills (see u_init.c) */ /*** Don't forget to add... ***/ /* quest leader, guardians, nemesis (monst.c) */ /* quest artifact (artilist.h) */ /* quest dungeon definition (dat/Xyz.dat) */ /* quest text (dat/quest.txt) */ /* dictionary entries (dat/data.bas) */ }; extern const struct Role roles[]; /* table of available roles */ extern struct Role urole; #define Role_if(X) (urole.malenum == (X)) #define Role_switch (urole.malenum) /* used during initialization for race, gender, and alignment as well as for character class */ #define ROLE_NONE (-1) #define ROLE_RANDOM (-2) /*** Unified structure specifying race information ***/ struct Race { /*** Strings that name various things ***/ const char *noun; /* noun ("human", "elf") */ const char *adj; /* adjective ("human", "elven") */ const char *coll; /* collective ("humanity", "elvenkind") */ const char *filecode; /* code for filenames */ struct RoleName individual; /* individual as a noun ("man", "elf") */ /*** Indices of important monsters and objects ***/ short malenum, /* PM_ as a male monster */ femalenum, /* ...or as a female (NON_PM == same) */ mummynum, /* PM_ as a mummy */ zombienum; /* PM_ as a zombie */ /*** Bitmasks ***/ short allow; /* bit mask of allowed variations */ short selfmask, /* your own race's bit mask */ lovemask, /* bit mask of always peaceful */ hatemask; /* bit mask of always hostile */ /*** Attributes ***/ xchar attrmin[A_MAX]; /* minimum allowable attribute */ xchar attrmax[A_MAX]; /* maximum allowable attribute */ struct RoleAdvance hpadv; /* hit point advancement */ struct RoleAdvance enadv; /* energy advancement */ #if 0 /* DEFERRED */ int nv_range; /* night vision range */ int xray_range; /* X-ray vision range */ #endif /*** Properties in variable-length arrays ***/ /* intrinsics (see attrib.c) */ /*** Don't forget to add... ***/ /* quest leader, guardians, nemesis (monst.c) */ /* quest dungeon definition (dat/Xyz.dat) */ /* quest text (dat/quest.txt) */ /* dictionary entries (dat/data.bas) */ }; extern const struct Race races[]; /* Table of available races */ extern struct Race urace; #define Race_if(X) (urace.malenum == (X)) #define Race_switch (urace.malenum) /*** Unified structure specifying gender information ***/ struct Gender { const char *adj; /* male/female/neuter */ const char *he; /* he/she/it */ const char *him; /* him/her/it */ const char *his; /* his/her/its */ const char *filecode; /* file code */ short allow; /* equivalent ROLE_ mask */ }; #define ROLE_GENDERS 2 /* number of permitted player genders */ /* increment to 3 if you allow neuter roles */ extern const struct Gender genders[]; /* table of available genders */ #define uhe() (genders[flags.female ? 1 : 0].he) #define uhim() (genders[flags.female ? 1 : 0].him) #define uhis() (genders[flags.female ? 1 : 0].his) #define mhe(mtmp) (genders[pronoun_gender(mtmp)].he) #define mhim(mtmp) (genders[pronoun_gender(mtmp)].him) #define mhis(mtmp) (genders[pronoun_gender(mtmp)].his) /*** Unified structure specifying alignment information ***/ struct Align { const char *noun; /* law/balance/chaos */ const char *adj; /* lawful/neutral/chaotic */ const char *filecode; /* file code */ short allow; /* equivalent ROLE_ mask */ aligntyp value; /* equivalent A_ value */ }; #define ROLE_ALIGNS 3 /* number of permitted player alignments */ extern const struct Align aligns[]; /* table of available alignments */ /*** Information about the player ***/ struct you { xchar ux, uy; schar dx, dy, dz; /* direction of move (or zap or ... ) */ schar di; /* direction of FF */ xchar tx, ty; /* destination of travel */ xchar ux0, uy0; /* initial position FF */ d_level uz, uz0; /* your level on this and the previous turn */ d_level utolev; /* level monster teleported you to, or uz */ uchar utotype; /* bitmask of goto_level() flags for utolev */ boolean umoved; /* changed map location (post-move) */ int last_str_turn; /* 0: none, 1: half turn, 2: full turn */ /* +: turn right, -: turn left */ int ulevel; /* 1 to MAXULEV */ int ulevelmax; unsigned utrap; /* trap timeout */ unsigned utraptype; /* defined if utrap nonzero */ #define TT_BEARTRAP 0 #define TT_PIT 1 #define TT_WEB 2 #define TT_LAVA 3 #define TT_INFLOOR 4 char urooms[5]; /* rooms (roomno + 3) occupied now */ char urooms0[5]; /* ditto, for previous position */ char uentered[5]; /* rooms (roomno + 3) entered this turn */ char ushops[5]; /* shop rooms (roomno + 3) occupied now */ char ushops0[5]; /* ditto, for previous position */ char ushops_entered[5]; /* ditto, shops entered this turn */ char ushops_left[5]; /* ditto, shops exited this turn */ int uhunger; /* refd only in eat.c and shk.c */ unsigned uhs; /* hunger state - see eat.c */ struct prop uprops[LAST_PROP+1]; unsigned umconf; char usick_cause[PL_PSIZ+20]; /* sizeof "unicorn horn named "+1 */ Bitfield(usick_type,2); #define SICK_VOMITABLE 0x01 #define SICK_NONVOMITABLE 0x02 #define SICK_ALL 0x03 /* These ranges can never be more than MAX_RANGE (vision.h). */ int nv_range; /* current night vision range */ int xray_range; /* current xray vision range */ /* * These variables are valid globally only when punished and blind. */ #define BC_BALL 0x01 /* bit mask for ball in 'bc_felt' below */ #define BC_CHAIN 0x02 /* bit mask for chain in 'bc_felt' below */ int bglyph; /* glyph under the ball */ int cglyph; /* glyph under the chain */ int bc_order; /* ball & chain order [see bc_order() in ball.c] */ int bc_felt; /* mask for ball/chain being felt */ int umonster; /* hero's "real" monster num */ int umonnum; /* current monster number */ int mh, mhmax, mtimedone; /* for polymorph-self */ struct attribs macurr, /* for monster attribs */ mamax; /* for monster attribs */ int ulycn; /* lycanthrope type */ unsigned ucreamed; unsigned uswldtim; /* time you have been swallowed */ Bitfield(uswallow,1); /* true if swallowed */ Bitfield(uinwater,1); /* if you're currently in water (only underwater possible currently) */ Bitfield(uundetected,1); /* if you're a hiding monster/piercer */ Bitfield(mfemale,1); /* saved human value of flags.female */ Bitfield(uinvulnerable,1); /* you're invulnerable (praying) */ Bitfield(uburied,1); /* you're buried */ Bitfield(uedibility,1); /* blessed food detection; sense unsafe food */ /* 1 free bit! */ unsigned udg_cnt; /* how long you have been demigod */ struct u_event uevent; /* certain events have happened */ struct u_have uhave; /* you're carrying special objects */ struct u_conduct uconduct; /* KMH, conduct */ struct attribs acurr, /* your current attributes (eg. str)*/ aexe, /* for gain/loss via "exercise" */ abon, /* your bonus attributes (eg. str) */ amax, /* your max attributes (eg. str) */ atemp, /* used for temporary loss/gain */ atime; /* used for loss/gain countdown */ align ualign; /* character alignment */ #define CONVERT 2 #define A_ORIGINAL 1 #define A_CURRENT 0 aligntyp ualignbase[CONVERT]; /* for ualign conversion record */ schar uluck, moreluck; /* luck and luck bonus */ #define Luck (u.uluck + u.moreluck) #define LUCKADD 3 /* added value when carrying luck stone */ #define LUCKMAX 10 /* on moonlit nights 11 */ #define LUCKMIN (-10) schar uhitinc; schar udaminc; schar uac; uchar uspellprot; /* protection by SPE_PROTECTION */ uchar usptime; /* #moves until uspellprot-- */ uchar uspmtime; /* #moves between uspellprot-- */ int uhp,uhpmax; int uen, uenmax; /* magical energy - M. Stephenson */ int ugangr; /* if the gods are angry at you */ int ugifts; /* number of artifacts bestowed */ int ublessed, ublesscnt; /* blessing/duration from #pray */ #ifndef GOLDOBJ long ugold, ugold0; #else long umoney0; #endif long uexp, urexp; long ucleansed; /* to record moves when player was cleansed */ long usleep; /* sleeping; monstermove you last started */ int uinvault; struct monst *ustuck; #ifdef STEED struct monst *usteed; long ugallop; int urideturns; #endif int umortality; /* how many times you died */ int ugrave_arise; /* you die and become something aside from a ghost */ time_t ubirthday; /* real world time when game began */ int weapon_slots; /* unused skill slots */ int skills_advanced; /* # of advances made so far */ xchar skill_record[P_SKILL_LIMIT]; /* skill advancements */ struct skills weapon_skills[P_NUM_SKILLS]; boolean twoweap; /* KMH -- Using two-weapon combat */ }; /* end of `struct you' */ #define Upolyd (u.umonnum != u.umonster) #endif /* YOU_H */ nethack-3.4.3/include/youprop.h0100644000000000000000000003110507764735041015163 0ustar rootroot/* SCCS Id: @(#)youprop.h 3.4 1999/07/02 */ /* Copyright (c) 1989 Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #ifndef YOUPROP_H #define YOUPROP_H #include "prop.h" #include "permonst.h" #include "mondata.h" #include "pm.h" /* KMH, intrinsics patch. * Reorganized and rewritten for >32-bit properties. * HXxx refers to intrinsic bitfields while in human form. * EXxx refers to extrinsic bitfields from worn objects. * BXxx refers to the cause of the property being blocked. * Xxx refers to any source, including polymorph forms. */ #define maybe_polyd(if_so,if_not) (Upolyd ? (if_so) : (if_not)) /*** Resistances to troubles ***/ /* With intrinsics and extrinsics */ #define HFire_resistance u.uprops[FIRE_RES].intrinsic #define EFire_resistance u.uprops[FIRE_RES].extrinsic #define Fire_resistance (HFire_resistance || EFire_resistance || \ resists_fire(&youmonst)) #define HCold_resistance u.uprops[COLD_RES].intrinsic #define ECold_resistance u.uprops[COLD_RES].extrinsic #define Cold_resistance (HCold_resistance || ECold_resistance || \ resists_cold(&youmonst)) #define HSleep_resistance u.uprops[SLEEP_RES].intrinsic #define ESleep_resistance u.uprops[SLEEP_RES].extrinsic #define Sleep_resistance (HSleep_resistance || ESleep_resistance || \ resists_sleep(&youmonst)) #define HDisint_resistance u.uprops[DISINT_RES].intrinsic #define EDisint_resistance u.uprops[DISINT_RES].extrinsic #define Disint_resistance (HDisint_resistance || EDisint_resistance || \ resists_disint(&youmonst)) #define HShock_resistance u.uprops[SHOCK_RES].intrinsic #define EShock_resistance u.uprops[SHOCK_RES].extrinsic #define Shock_resistance (HShock_resistance || EShock_resistance || \ resists_elec(&youmonst)) #define HPoison_resistance u.uprops[POISON_RES].intrinsic #define EPoison_resistance u.uprops[POISON_RES].extrinsic #define Poison_resistance (HPoison_resistance || EPoison_resistance || \ resists_poison(&youmonst)) #define HDrain_resistance u.uprops[DRAIN_RES].intrinsic #define EDrain_resistance u.uprops[DRAIN_RES].extrinsic #define Drain_resistance (HDrain_resistance || EDrain_resistance || \ resists_drli(&youmonst)) /* Intrinsics only */ #define HSick_resistance u.uprops[SICK_RES].intrinsic #define Sick_resistance (HSick_resistance || \ youmonst.data->mlet == S_FUNGUS || \ youmonst.data == &mons[PM_GHOUL] || \ defends(AD_DISE,uwep)) #define Invulnerable u.uprops[INVULNERABLE].intrinsic /* [Tom] */ /* Extrinsics only */ #define EAntimagic u.uprops[ANTIMAGIC].extrinsic #define Antimagic (EAntimagic || \ (Upolyd && resists_magm(&youmonst))) #define EAcid_resistance u.uprops[ACID_RES].extrinsic #define Acid_resistance (EAcid_resistance || resists_acid(&youmonst)) #define EStone_resistance u.uprops[STONE_RES].extrinsic #define Stone_resistance (EStone_resistance || resists_ston(&youmonst)) /*** Troubles ***/ /* Pseudo-property */ #define Punished (uball) /* Those implemented solely as timeouts (we use just intrinsic) */ #define HStun u.uprops[STUNNED].intrinsic #define Stunned (HStun || u.umonnum == PM_STALKER || \ youmonst.data->mlet == S_BAT) /* Note: birds will also be stunned */ #define HConfusion u.uprops[CONFUSION].intrinsic #define Confusion HConfusion #define Blinded u.uprops[BLINDED].intrinsic #define Blindfolded (ublindf && ublindf->otyp != LENSES) /* ...means blind because of a cover */ #define Blind ((Blinded || Blindfolded || !haseyes(youmonst.data)) && \ !(ublindf && ublindf->oartifact == ART_EYES_OF_THE_OVERWORLD)) /* ...the Eyes operate even when you really are blind or don't have any eyes */ #define Sick u.uprops[SICK].intrinsic #define Stoned u.uprops[STONED].intrinsic #define Strangled u.uprops[STRANGLED].intrinsic #define Vomiting u.uprops[VOMITING].intrinsic #define Glib u.uprops[GLIB].intrinsic #define Slimed u.uprops[SLIMED].intrinsic /* [Tom] */ /* Hallucination is solely a timeout; its resistance is extrinsic */ #define HHallucination u.uprops[HALLUC].intrinsic #define EHalluc_resistance u.uprops[HALLUC_RES].extrinsic #define Halluc_resistance (EHalluc_resistance || \ (Upolyd && dmgtype(youmonst.data, AD_HALU))) #define Hallucination (HHallucination && !Halluc_resistance) /* Timeout, plus a worn mask */ #define HFumbling u.uprops[FUMBLING].intrinsic #define EFumbling u.uprops[FUMBLING].extrinsic #define Fumbling (HFumbling || EFumbling) #define HWounded_legs u.uprops[WOUNDED_LEGS].intrinsic #define EWounded_legs u.uprops[WOUNDED_LEGS].extrinsic #define Wounded_legs (HWounded_legs || EWounded_legs) #define HSleeping u.uprops[SLEEPING].intrinsic #define ESleeping u.uprops[SLEEPING].extrinsic #define Sleeping (HSleeping || ESleeping) #define HHunger u.uprops[HUNGER].intrinsic #define EHunger u.uprops[HUNGER].extrinsic #define Hunger (HHunger || EHunger) /*** Vision and senses ***/ #define HSee_invisible u.uprops[SEE_INVIS].intrinsic #define ESee_invisible u.uprops[SEE_INVIS].extrinsic #define See_invisible (HSee_invisible || ESee_invisible || \ perceives(youmonst.data)) #define HTelepat u.uprops[TELEPAT].intrinsic #define ETelepat u.uprops[TELEPAT].extrinsic #define Blind_telepat (HTelepat || ETelepat || \ telepathic(youmonst.data)) #define Unblind_telepat (ETelepat) #define HWarning u.uprops[WARNING].intrinsic #define EWarning u.uprops[WARNING].extrinsic #define Warning (HWarning || EWarning) /* Warning for a specific type of monster */ #define HWarn_of_mon u.uprops[WARN_OF_MON].intrinsic #define EWarn_of_mon u.uprops[WARN_OF_MON].extrinsic #define Warn_of_mon (HWarn_of_mon || EWarn_of_mon) #define HUndead_warning u.uprops[WARN_UNDEAD].intrinsic #define Undead_warning (HUndead_warning) #define HSearching u.uprops[SEARCHING].intrinsic #define ESearching u.uprops[SEARCHING].extrinsic #define Searching (HSearching || ESearching) #define HClairvoyant u.uprops[CLAIRVOYANT].intrinsic #define EClairvoyant u.uprops[CLAIRVOYANT].extrinsic #define BClairvoyant u.uprops[CLAIRVOYANT].blocked #define Clairvoyant ((HClairvoyant || EClairvoyant) &&\ !BClairvoyant) #define HInfravision u.uprops[INFRAVISION].intrinsic #define EInfravision u.uprops[INFRAVISION].extrinsic #define Infravision (HInfravision || EInfravision || \ infravision(youmonst.data)) #define HDetect_monsters u.uprops[DETECT_MONSTERS].intrinsic #define EDetect_monsters u.uprops[DETECT_MONSTERS].extrinsic #define Detect_monsters (HDetect_monsters || EDetect_monsters) /*** Appearance and behavior ***/ #define Adornment u.uprops[ADORNED].extrinsic #define HInvis u.uprops[INVIS].intrinsic #define EInvis u.uprops[INVIS].extrinsic #define BInvis u.uprops[INVIS].blocked #define Invis ((HInvis || EInvis || \ pm_invisible(youmonst.data)) && !BInvis) #define Invisible (Invis && !See_invisible) /* Note: invisibility also hides inventory and steed */ #define EDisplaced u.uprops[DISPLACED].extrinsic #define Displaced EDisplaced #define HStealth u.uprops[STEALTH].intrinsic #define EStealth u.uprops[STEALTH].extrinsic #define BStealth u.uprops[STEALTH].blocked #define Stealth ((HStealth || EStealth) && !BStealth) #define HAggravate_monster u.uprops[AGGRAVATE_MONSTER].intrinsic #define EAggravate_monster u.uprops[AGGRAVATE_MONSTER].extrinsic #define Aggravate_monster (HAggravate_monster || EAggravate_monster) #define HConflict u.uprops[CONFLICT].intrinsic #define EConflict u.uprops[CONFLICT].extrinsic #define Conflict (HConflict || EConflict) /*** Transportation ***/ #define HJumping u.uprops[JUMPING].intrinsic #define EJumping u.uprops[JUMPING].extrinsic #define Jumping (HJumping || EJumping) #define HTeleportation u.uprops[TELEPORT].intrinsic #define ETeleportation u.uprops[TELEPORT].extrinsic #define Teleportation (HTeleportation || ETeleportation || \ can_teleport(youmonst.data)) #define HTeleport_control u.uprops[TELEPORT_CONTROL].intrinsic #define ETeleport_control u.uprops[TELEPORT_CONTROL].extrinsic #define Teleport_control (HTeleport_control || ETeleport_control || \ control_teleport(youmonst.data)) #define HLevitation u.uprops[LEVITATION].intrinsic #define ELevitation u.uprops[LEVITATION].extrinsic #define Levitation (HLevitation || ELevitation || \ is_floater(youmonst.data)) /* Can't touch surface, can't go under water; overrides all others */ #define Lev_at_will (((HLevitation & I_SPECIAL) != 0L || \ (ELevitation & W_ARTI) != 0L) && \ (HLevitation & ~(I_SPECIAL|TIMEOUT)) == 0L && \ (ELevitation & ~W_ARTI) == 0L && \ !is_floater(youmonst.data)) #define EFlying u.uprops[FLYING].extrinsic #ifdef STEED # define Flying (EFlying || is_flyer(youmonst.data) || \ (u.usteed && is_flyer(u.usteed->data))) #else # define Flying (EFlying || is_flyer(youmonst.data)) #endif /* May touch surface; does not override any others */ #define Wwalking (u.uprops[WWALKING].extrinsic && \ !Is_waterlevel(&u.uz)) /* Don't get wet, can't go under water; overrides others except levitation */ /* Wwalking is meaningless on water level */ #define HSwimming u.uprops[SWIMMING].intrinsic #define ESwimming u.uprops[SWIMMING].extrinsic /* [Tom] */ #ifdef STEED # define Swimming (HSwimming || ESwimming || \ is_swimmer(youmonst.data) || \ (u.usteed && is_swimmer(u.usteed->data))) #else # define Swimming (HSwimming || ESwimming || \ is_swimmer(youmonst.data)) #endif /* Get wet, don't go under water unless if amphibious */ #define HMagical_breathing u.uprops[MAGICAL_BREATHING].intrinsic #define EMagical_breathing u.uprops[MAGICAL_BREATHING].extrinsic #define Amphibious (HMagical_breathing || EMagical_breathing || \ amphibious(youmonst.data)) /* Get wet, may go under surface */ #define Breathless (HMagical_breathing || EMagical_breathing || \ breathless(youmonst.data)) #define Underwater (u.uinwater) /* Note that Underwater and u.uinwater are both used in code. The latter form is for later implementation of other in-water states, like swimming, wading, etc. */ #define HPasses_walls u.uprops[PASSES_WALLS].intrinsic #define EPasses_walls u.uprops[PASSES_WALLS].extrinsic #define Passes_walls (HPasses_walls || EPasses_walls || \ passes_walls(youmonst.data)) /*** Physical attributes ***/ #define HSlow_digestion u.uprops[SLOW_DIGESTION].intrinsic #define ESlow_digestion u.uprops[SLOW_DIGESTION].extrinsic #define Slow_digestion (HSlow_digestion || ESlow_digestion) /* KMH */ #define HHalf_spell_damage u.uprops[HALF_SPDAM].intrinsic #define EHalf_spell_damage u.uprops[HALF_SPDAM].extrinsic #define Half_spell_damage (HHalf_spell_damage || EHalf_spell_damage) #define HHalf_physical_damage u.uprops[HALF_PHDAM].intrinsic #define EHalf_physical_damage u.uprops[HALF_PHDAM].extrinsic #define Half_physical_damage (HHalf_physical_damage || EHalf_physical_damage) #define HRegeneration u.uprops[REGENERATION].intrinsic #define ERegeneration u.uprops[REGENERATION].extrinsic #define Regeneration (HRegeneration || ERegeneration || \ regenerates(youmonst.data)) #define HEnergy_regeneration u.uprops[ENERGY_REGENERATION].intrinsic #define EEnergy_regeneration u.uprops[ENERGY_REGENERATION].extrinsic #define Energy_regeneration (HEnergy_regeneration || EEnergy_regeneration) #define HProtection u.uprops[PROTECTION].intrinsic #define EProtection u.uprops[PROTECTION].extrinsic #define Protection (HProtection || EProtection) #define HProtection_from_shape_changers \ u.uprops[PROT_FROM_SHAPE_CHANGERS].intrinsic #define EProtection_from_shape_changers \ u.uprops[PROT_FROM_SHAPE_CHANGERS].extrinsic #define Protection_from_shape_changers \ (HProtection_from_shape_changers || \ EProtection_from_shape_changers) #define HPolymorph u.uprops[POLYMORPH].intrinsic #define EPolymorph u.uprops[POLYMORPH].extrinsic #define Polymorph (HPolymorph || EPolymorph) #define HPolymorph_control u.uprops[POLYMORPH_CONTROL].intrinsic #define EPolymorph_control u.uprops[POLYMORPH_CONTROL].extrinsic #define Polymorph_control (HPolymorph_control || EPolymorph_control) #define HUnchanging u.uprops[UNCHANGING].intrinsic #define EUnchanging u.uprops[UNCHANGING].extrinsic #define Unchanging (HUnchanging || EUnchanging) /* KMH */ #define HFast u.uprops[FAST].intrinsic #define EFast u.uprops[FAST].extrinsic #define Fast (HFast || EFast) #define Very_fast ((HFast & ~INTRINSIC) || EFast) #define EReflecting u.uprops[REFLECTING].extrinsic #define Reflecting (EReflecting || \ (youmonst.data == &mons[PM_SILVER_DRAGON])) #define Free_action u.uprops[FREE_ACTION].extrinsic /* [Tom] */ #define Fixed_abil u.uprops[FIXED_ABIL].extrinsic /* KMH */ #define Lifesaved u.uprops[LIFESAVED].extrinsic #endif /* YOUPROP_H */ nethack-3.4.3/src/0040755000000000000000000000000007764735121012443 5ustar rootrootnethack-3.4.3/src/allmain.c0100644000000000000000000003721207764735041014227 0ustar rootroot/* SCCS Id: @(#)allmain.c 3.4 2003/04/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* various code that was replicated in *main.c */ #include "hack.h" #ifndef NO_SIGNAL #include #endif #ifdef POSITIONBAR STATIC_DCL void NDECL(do_positionbar); #endif #ifdef OVL0 void moveloop() { #if defined(MICRO) || defined(WIN32) char ch; int abort_lev; #endif int moveamt = 0, wtcap = 0, change = 0; boolean didmove = FALSE, monscanmove = FALSE; flags.moonphase = phase_of_the_moon(); if(flags.moonphase == FULL_MOON) { You("are lucky! Full moon tonight."); change_luck(1); } else if(flags.moonphase == NEW_MOON) { pline("Be careful! New moon tonight."); } flags.friday13 = friday_13th(); if (flags.friday13) { pline("Watch out! Bad things can happen on Friday the 13th."); change_luck(-1); } initrack(); /* Note: these initializers don't do anything except guarantee that we're linked properly. */ decl_init(); monst_init(); monstr_init(); /* monster strengths */ objects_init(); #ifdef WIZARD if (wizard) add_debug_extended_commands(); #endif (void) encumber_msg(); /* in case they auto-picked up something */ u.uz0.dlevel = u.uz.dlevel; youmonst.movement = NORMAL_SPEED; /* give the hero some movement points */ for(;;) { get_nh_event(); #ifdef POSITIONBAR do_positionbar(); #endif didmove = flags.move; if(didmove) { /* actual time passed */ youmonst.movement -= NORMAL_SPEED; do { /* hero can't move this turn loop */ wtcap = encumber_msg(); flags.mon_moving = TRUE; do { monscanmove = movemon(); if (youmonst.movement > NORMAL_SPEED) break; /* it's now your turn */ } while (monscanmove); flags.mon_moving = FALSE; if (!monscanmove && youmonst.movement < NORMAL_SPEED) { /* both you and the monsters are out of steam this round */ /* set up for a new turn */ struct monst *mtmp; mcalcdistress(); /* adjust monsters' trap, blind, etc */ /* reallocate movement rations to monsters */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) mtmp->movement += mcalcmove(mtmp); if(!rn2(u.uevent.udemigod ? 25 : (depth(&u.uz) > depth(&stronghold_level)) ? 50 : 70)) (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS); /* calculate how much time passed. */ #ifdef STEED if (u.usteed && u.umoved) { /* your speed doesn't augment steed's speed */ moveamt = mcalcmove(u.usteed); } else #endif { moveamt = youmonst.data->mmove; if (Very_fast) { /* speed boots or potion */ /* average movement is 1.67 times normal */ moveamt += NORMAL_SPEED / 2; if (rn2(3) == 0) moveamt += NORMAL_SPEED / 2; } else if (Fast) { /* average movement is 1.33 times normal */ if (rn2(3) != 0) moveamt += NORMAL_SPEED / 2; } } switch (wtcap) { case UNENCUMBERED: break; case SLT_ENCUMBER: moveamt -= (moveamt / 4); break; case MOD_ENCUMBER: moveamt -= (moveamt / 2); break; case HVY_ENCUMBER: moveamt -= ((moveamt * 3) / 4); break; case EXT_ENCUMBER: moveamt -= ((moveamt * 7) / 8); break; default: break; } youmonst.movement += moveamt; if (youmonst.movement < 0) youmonst.movement = 0; settrack(); monstermoves++; moves++; /********************************/ /* once-per-turn things go here */ /********************************/ if (flags.bypasses) clear_bypasses(); if(Glib) glibr(); nh_timeout(); run_regions(); if (u.ublesscnt) u.ublesscnt--; if(flags.time && !flags.run) flags.botl = 1; /* One possible result of prayer is healing. Whether or * not you get healed depends on your current hit points. * If you are allowed to regenerate during the prayer, the * end-of-prayer calculation messes up on this. * Another possible result is rehumanization, which requires * that encumbrance and movement rate be recalculated. */ if (u.uinvulnerable) { /* for the moment at least, you're in tiptop shape */ wtcap = UNENCUMBERED; } else if (Upolyd && youmonst.data->mlet == S_EEL && !is_pool(u.ux,u.uy) && !Is_waterlevel(&u.uz)) { if (u.mh > 1) { u.mh--; flags.botl = 1; } else if (u.mh < 1) rehumanize(); } else if (Upolyd && u.mh < u.mhmax) { if (u.mh < 1) rehumanize(); else if (Regeneration || (wtcap < MOD_ENCUMBER && !(moves%20))) { flags.botl = 1; u.mh++; } } else if (u.uhp < u.uhpmax && (wtcap < MOD_ENCUMBER || !u.umoved || Regeneration)) { if (u.ulevel > 9 && !(moves % 3)) { int heal, Con = (int) ACURR(A_CON); if (Con <= 12) { heal = 1; } else { heal = rnd(Con); if (heal > u.ulevel-9) heal = u.ulevel-9; } flags.botl = 1; u.uhp += heal; if(u.uhp > u.uhpmax) u.uhp = u.uhpmax; } else if (Regeneration || (u.ulevel <= 9 && !(moves % ((MAXULEV+12) / (u.ulevel+2) + 1)))) { flags.botl = 1; u.uhp++; } } /* moving around while encumbered is hard work */ if (wtcap > MOD_ENCUMBER && u.umoved) { if(!(wtcap < EXT_ENCUMBER ? moves%30 : moves%10)) { if (Upolyd && u.mh > 1) { u.mh--; } else if (!Upolyd && u.uhp > 1) { u.uhp--; } else { You("pass out from exertion!"); exercise(A_CON, FALSE); fall_asleep(-10, FALSE); } } } if ((u.uen < u.uenmax) && ((wtcap < MOD_ENCUMBER && (!(moves%((MAXULEV + 8 - u.ulevel) * (Role_if(PM_WIZARD) ? 3 : 4) / 6)))) || Energy_regeneration)) { u.uen += rn1((int)(ACURR(A_WIS) + ACURR(A_INT)) / 15 + 1,1); if (u.uen > u.uenmax) u.uen = u.uenmax; flags.botl = 1; } if(!u.uinvulnerable) { if(Teleportation && !rn2(85)) { xchar old_ux = u.ux, old_uy = u.uy; tele(); if (u.ux != old_ux || u.uy != old_uy) { if (!next_to_u()) { check_leash(old_ux, old_uy); } #ifdef REDO /* clear doagain keystrokes */ pushch(0); savech(0); #endif } } /* delayed change may not be valid anymore */ if ((change == 1 && !Polymorph) || (change == 2 && u.ulycn == NON_PM)) change = 0; if(Polymorph && !rn2(100)) change = 1; else if (u.ulycn >= LOW_PM && !Upolyd && !rn2(80 - (20 * night()))) change = 2; if (change && !Unchanging) { if (multi >= 0) { if (occupation) stop_occupation(); else nomul(0); if (change == 1) polyself(FALSE); else you_were(); change = 0; } } } if(Searching && multi >= 0) (void) dosearch0(1); dosounds(); do_storms(); gethungry(); age_spells(); exerchk(); invault(); if (u.uhave.amulet) amulet(); if (!rn2(40+(int)(ACURR(A_DEX)*3))) u_wipe_engr(rnd(3)); if (u.uevent.udemigod && !u.uinvulnerable) { if (u.udg_cnt) u.udg_cnt--; if (!u.udg_cnt) { intervene(); u.udg_cnt = rn1(200, 50); } } restore_attrib(); /* underwater and waterlevel vision are done here */ if (Is_waterlevel(&u.uz)) movebubbles(); else if (Underwater) under_water(0); /* vision while buried done here */ else if (u.uburied) under_ground(0); /* when immobile, count is in turns */ if(multi < 0) { if (++multi == 0) { /* finished yet? */ unmul((char *)0); /* if unmul caused a level change, take it now */ if (u.utotype) deferred_goto(); } } } } while (youmonst.movement= 0 && occupation) { #if defined(MICRO) || defined(WIN32) abort_lev = 0; if (kbhit()) { if ((ch = Getchar()) == ABORT) abort_lev++; # ifdef REDO else pushch(ch); # endif /* REDO */ } if (!abort_lev && (*occupation)() == 0) #else if ((*occupation)() == 0) #endif occupation = 0; if( #if defined(MICRO) || defined(WIN32) abort_lev || #endif monster_nearby()) { stop_occupation(); reset_eat(); } #if defined(MICRO) || defined(WIN32) if (!(++occtime % 7)) display_nhwindow(WIN_MAP, FALSE); #endif continue; } if ((u.uhave.amulet || Clairvoyant) && !In_endgame(&u.uz) && !BClairvoyant && !(moves % 15) && !rn2(2)) do_vicinity_map(); if(u.utrap && u.utraptype == TT_LAVA) { if(!is_lava(u.ux,u.uy)) u.utrap = 0; else if (!u.uinvulnerable) { u.utrap -= 1<<8; if(u.utrap < 1<<8) { killer_format = KILLED_BY; killer = "molten lava"; You("sink below the surface and die."); done(DISSOLVED); } else if(didmove && !u.umoved) { Norep("You sink deeper into the lava."); u.utrap += rnd(4); } } } #ifdef WIZARD if (iflags.sanity_check) sanity_check(); #endif #ifdef CLIPPING /* just before rhack */ cliparound(u.ux, u.uy); #endif u.umoved = FALSE; if (multi > 0) { lookaround(); if (!multi) { /* lookaround may clear multi */ flags.move = 0; if (flags.time) flags.botl = 1; continue; } if (flags.mv) { if(multi < COLNO && !--multi) flags.travel = iflags.travel1 = flags.mv = flags.run = 0; domove(); } else { --multi; rhack(save_cm); } } else if (multi == 0) { #ifdef MAIL ckmailstatus(); #endif rhack((char *)0); } if (u.utotype) /* change dungeon level */ deferred_goto(); /* after rhack() */ /* !flags.move here: multiple movement command stopped */ else if (flags.time && (!flags.move || !flags.mv)) flags.botl = 1; if (vision_full_recalc) vision_recalc(0); /* vision! */ /* when running in non-tport mode, this gets done through domove() */ if ((!flags.run || iflags.runmode == RUN_TPORT) && (multi && (!flags.travel ? !(multi % 7) : !(moves % 7L)))) { if (flags.time && flags.run) flags.botl = 1; display_nhwindow(WIN_MAP, FALSE); } } } #endif /* OVL0 */ #ifdef OVL1 void stop_occupation() { if(occupation) { if (!maybe_finished_meal(TRUE)) You("stop %s.", occtxt); occupation = 0; flags.botl = 1; /* in case u.uhs changed */ /* fainting stops your occupation, there's no reason to sync. sync_hunger(); */ #ifdef REDO nomul(0); pushch(0); #endif } } #endif /* OVL1 */ #ifdef OVLB void display_gamewindows() { WIN_MESSAGE = create_nhwindow(NHW_MESSAGE); WIN_STATUS = create_nhwindow(NHW_STATUS); WIN_MAP = create_nhwindow(NHW_MAP); WIN_INVEN = create_nhwindow(NHW_MENU); #ifdef MAC /* * This _is_ the right place for this - maybe we will * have to split display_gamewindows into create_gamewindows * and show_gamewindows to get rid of this ifdef... */ if ( ! strcmp ( windowprocs . name , "mac" ) ) { SanePositions ( ) ; } #endif /* * The mac port is not DEPENDENT on the order of these * displays, but it looks a lot better this way... */ display_nhwindow(WIN_STATUS, FALSE); display_nhwindow(WIN_MESSAGE, FALSE); clear_glyph_buffer(); display_nhwindow(WIN_MAP, FALSE); } void newgame() { int i; #ifdef MFLOPPY gameDiskPrompt(); #endif flags.ident = 1; for (i = 0; i < NUMMONS; i++) mvitals[i].mvflags = mons[i].geno & G_NOCORPSE; init_objects(); /* must be before u_init() */ flags.pantheon = -1; /* role_init() will reset this */ role_init(); /* must be before init_dungeons(), u_init(), * and init_artifacts() */ init_dungeons(); /* must be before u_init() to avoid rndmonst() * creating odd monsters for any tins and eggs * in hero's initial inventory */ init_artifacts(); /* before u_init() in case $WIZKIT specifies * any artifacts */ u_init(); #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif #ifdef NEWS if(iflags.news) display_file(NEWS, FALSE); #endif load_qtlist(); /* load up the quest text info */ /* quest_init();*/ /* Now part of role_init() */ mklev(); u_on_upstairs(); vision_reset(); /* set up internals for level (after mklev) */ check_special_room(FALSE); flags.botlx = 1; /* Move the monster from under you or else * makedog() will fail when it calls makemon(). * - ucsfcgl!kneller */ if(MON_AT(u.ux, u.uy)) mnexto(m_at(u.ux, u.uy)); (void) makedog(); docrt(); if (flags.legacy) { flush_screen(1); com_pager(1); } #ifdef INSURANCE save_currentstate(); #endif program_state.something_worth_saving++; /* useful data now exists */ /* Success! */ welcome(TRUE); return; } /* show "welcome [back] to nethack" message at program startup */ void welcome(new_game) boolean new_game; /* false => restoring an old game */ { char buf[BUFSZ]; boolean currentgend = Upolyd ? u.mfemale : flags.female; /* * The "welcome back" message always describes your innate form * even when polymorphed or wearing a helm of opposite alignment. * Alignment is shown unconditionally for new games; for restores * it's only shown if it has changed from its original value. * Sex is shown for new games except when it is redundant; for * restores it's only shown if different from its original value. */ *buf = '\0'; if (new_game || u.ualignbase[A_ORIGINAL] != u.ualignbase[A_CURRENT]) Sprintf(eos(buf), " %s", align_str(u.ualignbase[A_ORIGINAL])); if (!urole.name.f && (new_game ? (urole.allow & ROLE_GENDMASK) == (ROLE_MALE|ROLE_FEMALE) : currentgend != flags.initgend)) Sprintf(eos(buf), " %s", genders[currentgend].adj); pline(new_game ? "%s %s, welcome to NetHack! You are a%s %s %s." : "%s %s, the%s %s %s, welcome back to NetHack!", Hello((struct monst *) 0), plname, buf, urace.adj, (currentgend && urole.name.f) ? urole.name.f : urole.name.m); } #ifdef POSITIONBAR STATIC_DCL void do_positionbar() { static char pbar[COLNO]; char *p; p = pbar; /* up stairway */ if (upstair.sx && (glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) == S_upstair || glyph_to_cmap(level.locations[upstair.sx][upstair.sy].glyph) == S_upladder)) { *p++ = '<'; *p++ = upstair.sx; } if (sstairs.sx && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == S_upstair || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == S_upladder)) { *p++ = '<'; *p++ = sstairs.sx; } /* down stairway */ if (dnstair.sx && (glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) == S_dnstair || glyph_to_cmap(level.locations[dnstair.sx][dnstair.sy].glyph) == S_dnladder)) { *p++ = '>'; *p++ = dnstair.sx; } if (sstairs.sx && (glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == S_dnstair || glyph_to_cmap(level.locations[sstairs.sx][sstairs.sy].glyph) == S_dnladder)) { *p++ = '>'; *p++ = sstairs.sx; } /* hero location */ if (u.ux) { *p++ = '@'; *p++ = u.ux; } /* fence post */ *p = 0; update_positionbar(pbar); } #endif #endif /* OVLB */ /*allmain.c*/ nethack-3.4.3/src/alloc.c0100644000000000000000000000631007764735041013677 0ustar rootroot/* SCCS Id: @(#)alloc.c 3.4 1995/10/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* to get the malloc() prototype from system.h */ #define ALLOC_C /* comment line for pre-compiled headers */ /* since this file is also used in auxiliary programs, don't include all the * function declarations for all of nethack */ #define EXTERN_H /* comment line for pre-compiled headers */ #include "config.h" #if defined(MONITOR_HEAP) || defined(WIZARD) char *FDECL(fmt_ptr, (const genericptr,char *)); #endif #ifdef MONITOR_HEAP #undef alloc #undef free extern void FDECL(free,(genericptr_t)); static void NDECL(heapmon_init); static FILE *heaplog = 0; static boolean tried_heaplog = FALSE; #endif long *FDECL(alloc,(unsigned int)); extern void VDECL(panic, (const char *,...)) PRINTF_F(1,2); long * alloc(lth) register unsigned int lth; { #ifdef LINT /* * a ridiculous definition, suppressing * "possible pointer alignment problem" for (long *) malloc() * from lint */ long dummy = ftell(stderr); if(lth) dummy = 0; /* make sure arg is used */ return(&dummy); #else register genericptr_t ptr; ptr = malloc(lth); #ifndef MONITOR_HEAP if (!ptr) panic("Memory allocation failure; cannot get %u bytes", lth); #endif return((long *) ptr); #endif } #if defined(MONITOR_HEAP) || defined(WIZARD) # if defined(MICRO) || defined(WIN32) /* we actually want to know which systems have an ANSI run-time library * to know which support the new %p format for printing pointers. * due to the presence of things like gcc, NHSTDC is not a good test. * so we assume microcomputers have all converted to ANSI and bigger * computers which may have older libraries give reasonable results with * the cast. */ # define MONITOR_PTR_FMT # endif # ifdef MONITOR_PTR_FMT # define PTR_FMT "%p" # define PTR_TYP genericptr_t # else # define PTR_FMT "%06lx" # define PTR_TYP unsigned long # endif /* format a pointer for display purposes; caller supplies the result buffer */ char * fmt_ptr(ptr, buf) const genericptr ptr; char *buf; { Sprintf(buf, PTR_FMT, (PTR_TYP)ptr); return buf; } #endif #ifdef MONITOR_HEAP /* If ${NH_HEAPLOG} is defined and we can create a file by that name, then we'll log the allocation and release information to that file. */ static void heapmon_init() { char *logname = getenv("NH_HEAPLOG"); if (logname && *logname) heaplog = fopen(logname, "w"); tried_heaplog = TRUE; } long * nhalloc(lth, file, line) unsigned int lth; const char *file; int line; { long *ptr = alloc(lth); char ptr_address[20]; if (!tried_heaplog) heapmon_init(); if (heaplog) (void) fprintf(heaplog, "+%5u %s %4d %s\n", lth, fmt_ptr((genericptr_t)ptr, ptr_address), line, file); /* potential panic in alloc() was deferred til here */ if (!ptr) panic("Cannot get %u bytes, line %d of %s", lth, line, file); return ptr; } void nhfree(ptr, file, line) genericptr_t ptr; const char *file; int line; { char ptr_address[20]; if (!tried_heaplog) heapmon_init(); if (heaplog) (void) fprintf(heaplog, "- %s %4d %s\n", fmt_ptr((genericptr_t)ptr, ptr_address), line, file); free(ptr); } #endif /* MONITOR_HEAP */ /*alloc.c*/ nethack-3.4.3/src/apply.c0100644000000000000000000023552207764735041013743 0ustar rootroot/* SCCS Id: @(#)apply.c 3.4 2003/11/18 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "edog.h" #ifdef OVLB static const char tools[] = { TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, 0 }; static const char tools_too[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS, WEAPON_CLASS, WAND_CLASS, GEM_CLASS, 0 }; #ifdef TOURIST STATIC_DCL int FDECL(use_camera, (struct obj *)); #endif STATIC_DCL int FDECL(use_towel, (struct obj *)); STATIC_DCL boolean FDECL(its_dead, (int,int,int *)); STATIC_DCL int FDECL(use_stethoscope, (struct obj *)); STATIC_DCL void FDECL(use_whistle, (struct obj *)); STATIC_DCL void FDECL(use_magic_whistle, (struct obj *)); STATIC_DCL void FDECL(use_leash, (struct obj *)); STATIC_DCL int FDECL(use_mirror, (struct obj *)); STATIC_DCL void FDECL(use_bell, (struct obj **)); STATIC_DCL void FDECL(use_candelabrum, (struct obj *)); STATIC_DCL void FDECL(use_candle, (struct obj **)); STATIC_DCL void FDECL(use_lamp, (struct obj *)); STATIC_DCL void FDECL(light_cocktail, (struct obj *)); STATIC_DCL void FDECL(use_tinning_kit, (struct obj *)); STATIC_DCL void FDECL(use_figurine, (struct obj **)); STATIC_DCL void FDECL(use_grease, (struct obj *)); STATIC_DCL void FDECL(use_trap, (struct obj *)); STATIC_DCL void FDECL(use_stone, (struct obj *)); STATIC_PTR int NDECL(set_trap); /* occupation callback */ STATIC_DCL int FDECL(use_whip, (struct obj *)); STATIC_DCL int FDECL(use_pole, (struct obj *)); STATIC_DCL int FDECL(use_cream_pie, (struct obj *)); STATIC_DCL int FDECL(use_grapple, (struct obj *)); STATIC_DCL int FDECL(do_break_wand, (struct obj *)); STATIC_DCL boolean FDECL(figurine_location_checks, (struct obj *, coord *, BOOLEAN_P)); STATIC_DCL boolean NDECL(uhave_graystone); STATIC_DCL void FDECL(add_class, (char *, CHAR_P)); #ifdef AMIGA void FDECL( amii_speaker, ( struct obj *, char *, int ) ); #endif static const char no_elbow_room[] = "don't have enough elbow-room to maneuver."; #ifdef TOURIST STATIC_OVL int use_camera(obj) struct obj *obj; { register struct monst *mtmp; if(Underwater) { pline("Using your camera underwater would void the warranty."); return(0); } if(!getdir((char *)0)) return(0); if (obj->spe <= 0) { pline(nothing_happens); return (1); } consume_obj_charge(obj, TRUE); if (obj->cursed && !rn2(2)) { (void) zapyourself(obj, TRUE); } else if (u.uswallow) { You("take a picture of %s %s.", s_suffix(mon_nam(u.ustuck)), mbodypart(u.ustuck, STOMACH)); } else if (u.dz) { You("take a picture of the %s.", (u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy)); } else if (!u.dx && !u.dy) { (void) zapyourself(obj, TRUE); } else if ((mtmp = bhit(u.dx, u.dy, COLNO, FLASHED_LIGHT, (int FDECL((*),(MONST_P,OBJ_P)))0, (int FDECL((*),(OBJ_P,OBJ_P)))0, obj)) != 0) { obj->ox = u.ux, obj->oy = u.uy; (void) flash_hits_mon(mtmp, obj); } return 1; } #endif STATIC_OVL int use_towel(obj) struct obj *obj; { if(!freehand()) { You("have no free %s!", body_part(HAND)); return 0; } else if (obj->owornmask) { You("cannot use it while you're wearing it!"); return 0; } else if (obj->cursed) { long old; switch (rn2(3)) { case 2: old = Glib; Glib += rn1(10, 3); Your("%s %s!", makeplural(body_part(HAND)), (old ? "are filthier than ever" : "get slimy")); return 1; case 1: if (!ublindf) { old = u.ucreamed; u.ucreamed += rn1(10, 3); pline("Yecch! Your %s %s gunk on it!", body_part(FACE), (old ? "has more" : "now has")); make_blinded(Blinded + (long)u.ucreamed - old, TRUE); } else { const char *what = (ublindf->otyp == LENSES) ? "lenses" : "blindfold"; if (ublindf->cursed) { You("push your %s %s.", what, rn2(2) ? "cock-eyed" : "crooked"); } else { struct obj *saved_ublindf = ublindf; You("push your %s off.", what); Blindf_off(ublindf); dropx(saved_ublindf); } } return 1; case 0: break; } } if (Glib) { Glib = 0; You("wipe off your %s.", makeplural(body_part(HAND))); return 1; } else if(u.ucreamed) { Blinded -= u.ucreamed; u.ucreamed = 0; if (!Blinded) { pline("You've got the glop off."); Blinded = 1; make_blinded(0L,TRUE); } else { Your("%s feels clean now.", body_part(FACE)); } return 1; } Your("%s and %s are already clean.", body_part(FACE), makeplural(body_part(HAND))); return 0; } /* maybe give a stethoscope message based on floor objects */ STATIC_OVL boolean its_dead(rx, ry, resp) int rx, ry, *resp; { struct obj *otmp; struct trap *ttmp; if (!can_reach_floor()) return FALSE; /* additional stethoscope messages from jyoung@apanix.apana.org.au */ if (Hallucination && sobj_at(CORPSE, rx, ry)) { /* (a corpse doesn't retain the monster's sex, so we're forced to use generic pronoun here) */ You_hear("a voice say, \"It's dead, Jim.\""); *resp = 1; return TRUE; } else if (Role_if(PM_HEALER) && ((otmp = sobj_at(CORPSE, rx, ry)) != 0 || (otmp = sobj_at(STATUE, rx, ry)) != 0)) { /* possibly should check uppermost {corpse,statue} in the pile if both types are present, but it's not worth the effort */ if (vobj_at(rx, ry)->otyp == STATUE) otmp = vobj_at(rx, ry); if (otmp->otyp == CORPSE) { You("determine that %s unfortunate being is dead.", (rx == u.ux && ry == u.uy) ? "this" : "that"); } else { ttmp = t_at(rx, ry); pline("%s appears to be in %s health for a statue.", The(mons[otmp->corpsenm].mname), (ttmp && ttmp->ttyp == STATUE_TRAP) ? "extraordinary" : "excellent"); } return TRUE; } return FALSE; } static const char hollow_str[] = "a hollow sound. This must be a secret %s!"; /* Strictly speaking it makes no sense for usage of a stethoscope to not take any time; however, unless it did, the stethoscope would be almost useless. As a compromise, one use per turn is free, another uses up the turn; this makes curse status have a tangible effect. */ STATIC_OVL int use_stethoscope(obj) register struct obj *obj; { static long last_used_move = -1; static short last_used_movement = 0; struct monst *mtmp; struct rm *lev; int rx, ry, res; boolean interference = (u.uswallow && is_whirly(u.ustuck->data) && !rn2(Role_if(PM_HEALER) ? 10 : 3)); if (nohands(youmonst.data)) { /* should also check for no ears and/or deaf */ You("have no hands!"); /* not `body_part(HAND)' */ return 0; } else if (!freehand()) { You("have no free %s.", body_part(HAND)); return 0; } if (!getdir((char *)0)) return 0; res = (moves == last_used_move) && (youmonst.movement == last_used_movement); last_used_move = moves; last_used_movement = youmonst.movement; #ifdef STEED if (u.usteed && u.dz > 0) { if (interference) { pline("%s interferes.", Monnam(u.ustuck)); mstatusline(u.ustuck); } else mstatusline(u.usteed); return res; } else #endif if (u.uswallow && (u.dx || u.dy || u.dz)) { mstatusline(u.ustuck); return res; } else if (u.uswallow && interference) { pline("%s interferes.", Monnam(u.ustuck)); mstatusline(u.ustuck); return res; } else if (u.dz) { if (Underwater) You_hear("faint splashing."); else if (u.dz < 0 || !can_reach_floor()) You_cant("reach the %s.", (u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy)); else if (its_dead(u.ux, u.uy, &res)) ; /* message already given */ else if (Is_stronghold(&u.uz)) You_hear("the crackling of hellfire."); else pline_The("%s seems healthy enough.", surface(u.ux,u.uy)); return res; } else if (obj->cursed && !rn2(2)) { You_hear("your heart beat."); return res; } if (Stunned || (Confusion && !rn2(5))) confdir(); if (!u.dx && !u.dy) { ustatusline(); return res; } rx = u.ux + u.dx; ry = u.uy + u.dy; if (!isok(rx,ry)) { You_hear("a faint typing noise."); return 0; } if ((mtmp = m_at(rx,ry)) != 0) { mstatusline(mtmp); if (mtmp->mundetected) { mtmp->mundetected = 0; if (cansee(rx,ry)) newsym(mtmp->mx,mtmp->my); } if (!canspotmon(mtmp)) map_invisible(rx,ry); return res; } if (glyph_is_invisible(levl[rx][ry].glyph)) { unmap_object(rx, ry); newsym(rx, ry); pline_The("invisible monster must have moved."); } lev = &levl[rx][ry]; switch(lev->typ) { case SDOOR: You_hear(hollow_str, "door"); cvt_sdoor_to_door(lev); /* ->typ = DOOR */ if (Blind) feel_location(rx,ry); else newsym(rx,ry); return res; case SCORR: You_hear(hollow_str, "passage"); lev->typ = CORR; unblock_point(rx,ry); if (Blind) feel_location(rx,ry); else newsym(rx,ry); return res; } if (!its_dead(rx, ry, &res)) You("hear nothing special."); /* not You_hear() */ return res; } static const char whistle_str[] = "produce a %s whistling sound."; STATIC_OVL void use_whistle(obj) struct obj *obj; { You(whistle_str, obj->cursed ? "shrill" : "high"); wake_nearby(); } STATIC_OVL void use_magic_whistle(obj) struct obj *obj; { register struct monst *mtmp, *nextmon; if(obj->cursed && !rn2(2)) { You("produce a high-pitched humming noise."); wake_nearby(); } else { int pet_cnt = 0; You(whistle_str, Hallucination ? "normal" : "strange"); for(mtmp = fmon; mtmp; mtmp = nextmon) { nextmon = mtmp->nmon; /* trap might kill mon */ if (DEADMONSTER(mtmp)) continue; if (mtmp->mtame) { if (mtmp->mtrapped) { /* no longer in previous trap (affects mintrap) */ mtmp->mtrapped = 0; fill_pit(mtmp->mx, mtmp->my); } mnexto(mtmp); if (canspotmon(mtmp)) ++pet_cnt; if (mintrap(mtmp) == 2) change_luck(-1); } } if (pet_cnt > 0) makeknown(obj->otyp); } } boolean um_dist(x,y,n) register xchar x, y, n; { return((boolean)(abs(u.ux - x) > n || abs(u.uy - y) > n)); } int number_leashed() { register int i = 0; register struct obj *obj; for(obj = invent; obj; obj = obj->nobj) if(obj->otyp == LEASH && obj->leashmon != 0) i++; return(i); } void o_unleash(otmp) /* otmp is about to be destroyed or stolen */ register struct obj *otmp; { register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->m_id == (unsigned)otmp->leashmon) mtmp->mleashed = 0; otmp->leashmon = 0; } void m_unleash(mtmp, feedback) /* mtmp is about to die, or become untame */ register struct monst *mtmp; boolean feedback; { register struct obj *otmp; if (feedback) { if (canseemon(mtmp)) pline("%s pulls free of %s leash!", Monnam(mtmp), mhis(mtmp)); else Your("leash falls slack."); } for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp->otyp == LEASH && otmp->leashmon == (int)mtmp->m_id) otmp->leashmon = 0; mtmp->mleashed = 0; } void unleash_all() /* player is about to die (for bones) */ { register struct obj *otmp; register struct monst *mtmp; for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp->otyp == LEASH) otmp->leashmon = 0; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) mtmp->mleashed = 0; } #define MAXLEASHED 2 /* ARGSUSED */ STATIC_OVL void use_leash(obj) struct obj *obj; { coord cc; register struct monst *mtmp; int spotmon; if(!obj->leashmon && number_leashed() >= MAXLEASHED) { You("cannot leash any more pets."); return; } if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return; if((cc.x == u.ux) && (cc.y == u.uy)) { #ifdef STEED if (u.usteed && u.dz > 0) { mtmp = u.usteed; spotmon = 1; goto got_target; } #endif pline("Leash yourself? Very funny..."); return; } if(!(mtmp = m_at(cc.x, cc.y))) { There("is no creature there."); return; } spotmon = canspotmon(mtmp); #ifdef STEED got_target: #endif if(!mtmp->mtame) { if(!spotmon) There("is no creature there."); else pline("%s %s leashed!", Monnam(mtmp), (!obj->leashmon) ? "cannot be" : "is not"); return; } if(!obj->leashmon) { if(mtmp->mleashed) { pline("This %s is already leashed.", spotmon ? l_monnam(mtmp) : "monster"); return; } You("slip the leash around %s%s.", spotmon ? "your " : "", l_monnam(mtmp)); mtmp->mleashed = 1; obj->leashmon = (int)mtmp->m_id; mtmp->msleeping = 0; return; } if(obj->leashmon != (int)mtmp->m_id) { pline("This leash is not attached to that creature."); return; } else { if(obj->cursed) { pline_The("leash would not come off!"); obj->bknown = TRUE; return; } mtmp->mleashed = 0; obj->leashmon = 0; You("remove the leash from %s%s.", spotmon ? "your " : "", l_monnam(mtmp)); } return; } struct obj * get_mleash(mtmp) /* assuming mtmp->mleashed has been checked */ register struct monst *mtmp; { register struct obj *otmp; otmp = invent; while(otmp) { if(otmp->otyp == LEASH && otmp->leashmon == (int)mtmp->m_id) return(otmp); otmp = otmp->nobj; } return((struct obj *)0); } #endif /* OVLB */ #ifdef OVL1 boolean next_to_u() { register struct monst *mtmp; register struct obj *otmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if(mtmp->mleashed) { if (distu(mtmp->mx,mtmp->my) > 2) mnexto(mtmp); if (distu(mtmp->mx,mtmp->my) > 2) { for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp->otyp == LEASH && otmp->leashmon == (int)mtmp->m_id) { if(otmp->cursed) return(FALSE); You_feel("%s leash go slack.", (number_leashed() > 1) ? "a" : "the"); mtmp->mleashed = 0; otmp->leashmon = 0; } } } } #ifdef STEED /* no pack mules for the Amulet */ if (u.usteed && mon_has_amulet(u.usteed)) return FALSE; #endif return(TRUE); } #endif /* OVL1 */ #ifdef OVL0 void check_leash(x, y) register xchar x, y; { register struct obj *otmp; register struct monst *mtmp; for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->otyp != LEASH || otmp->leashmon == 0) continue; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((int)mtmp->m_id == otmp->leashmon) break; } if (!mtmp) { impossible("leash in use isn't attached to anything?"); otmp->leashmon = 0; continue; } if (dist2(u.ux,u.uy,mtmp->mx,mtmp->my) > dist2(x,y,mtmp->mx,mtmp->my)) { if (!um_dist(mtmp->mx, mtmp->my, 3)) { ; /* still close enough */ } else if (otmp->cursed && !breathless(mtmp->data)) { if (um_dist(mtmp->mx, mtmp->my, 5) || (mtmp->mhp -= rnd(2)) <= 0) { long save_pacifism = u.uconduct.killer; Your("leash chokes %s to death!", mon_nam(mtmp)); /* hero might not have intended to kill pet, but that's the result of his actions; gain experience, lose pacifism, take alignment and luck hit, make corpse less likely to remain tame after revival */ xkilled(mtmp, 0); /* no "you kill it" message */ /* life-saving doesn't ordinarily reset this */ if (mtmp->mhp > 0) u.uconduct.killer = save_pacifism; } else { pline("%s chokes on the leash!", Monnam(mtmp)); /* tameness eventually drops to 1 here (never 0) */ if (mtmp->mtame && rn2(mtmp->mtame)) mtmp->mtame--; } } else { if (um_dist(mtmp->mx, mtmp->my, 5)) { pline("%s leash snaps loose!", s_suffix(Monnam(mtmp))); m_unleash(mtmp, FALSE); } else { You("pull on the leash."); if (mtmp->data->msound != MS_SILENT) switch (rn2(3)) { case 0: growl(mtmp); break; case 1: yelp(mtmp); break; default: whimper(mtmp); break; } } } } } } #endif /* OVL0 */ #ifdef OVLB #define WEAK 3 /* from eat.c */ static const char look_str[] = "look %s."; STATIC_OVL int use_mirror(obj) struct obj *obj; { register struct monst *mtmp; register char mlet; boolean vis; if(!getdir((char *)0)) return 0; if(obj->cursed && !rn2(2)) { if (!Blind) pline_The("mirror fogs up and doesn't reflect!"); return 1; } if(!u.dx && !u.dy && !u.dz) { if(!Blind && !Invisible) { if (u.umonnum == PM_FLOATING_EYE) { if (!Free_action) { pline(Hallucination ? "Yow! The mirror stares back!" : "Yikes! You've frozen yourself!"); nomul(-rnd((MAXULEV+6) - u.ulevel)); } else You("stiffen momentarily under your gaze."); } else if (youmonst.data->mlet == S_VAMPIRE) You("don't have a reflection."); else if (u.umonnum == PM_UMBER_HULK) { pline("Huh? That doesn't look like you!"); make_confused(HConfusion + d(3,4),FALSE); } else if (Hallucination) You(look_str, hcolor((char *)0)); else if (Sick) You(look_str, "peaked"); else if (u.uhs >= WEAK) You(look_str, "undernourished"); else You("look as %s as ever.", ACURR(A_CHA) > 14 ? (poly_gender()==1 ? "beautiful" : "handsome") : "ugly"); } else { You_cant("see your %s %s.", ACURR(A_CHA) > 14 ? (poly_gender()==1 ? "beautiful" : "handsome") : "ugly", body_part(FACE)); } return 1; } if(u.uswallow) { if (!Blind) You("reflect %s %s.", s_suffix(mon_nam(u.ustuck)), mbodypart(u.ustuck, STOMACH)); return 1; } if(Underwater) { You(Hallucination ? "give the fish a chance to fix their makeup." : "reflect the murky water."); return 1; } if(u.dz) { if (!Blind) You("reflect the %s.", (u.dz > 0) ? surface(u.ux,u.uy) : ceiling(u.ux,u.uy)); return 1; } mtmp = bhit(u.dx, u.dy, COLNO, INVIS_BEAM, (int FDECL((*),(MONST_P,OBJ_P)))0, (int FDECL((*),(OBJ_P,OBJ_P)))0, obj); if (!mtmp || !haseyes(mtmp->data)) return 1; vis = canseemon(mtmp); mlet = mtmp->data->mlet; if (mtmp->msleeping) { if (vis) pline ("%s is too tired to look at your mirror.", Monnam(mtmp)); } else if (!mtmp->mcansee) { if (vis) pline("%s can't see anything right now.", Monnam(mtmp)); /* some monsters do special things */ } else if (mlet == S_VAMPIRE || mlet == S_GHOST) { if (vis) pline ("%s doesn't have a reflection.", Monnam(mtmp)); } else if(!mtmp->mcan && !mtmp->minvis && mtmp->data == &mons[PM_MEDUSA]) { if (mon_reflects(mtmp, "The gaze is reflected away by %s %s!")) return 1; if (vis) pline("%s is turned to stone!", Monnam(mtmp)); stoned = TRUE; killed(mtmp); } else if(!mtmp->mcan && !mtmp->minvis && mtmp->data == &mons[PM_FLOATING_EYE]) { int tmp = d((int)mtmp->m_lev, (int)mtmp->data->mattk[0].damd); if (!rn2(4)) tmp = 120; if (vis) pline("%s is frozen by its reflection.", Monnam(mtmp)); else You_hear("%s stop moving.",something); mtmp->mcanmove = 0; if ( (int) mtmp->mfrozen + tmp > 127) mtmp->mfrozen = 127; else mtmp->mfrozen += tmp; } else if(!mtmp->mcan && !mtmp->minvis && mtmp->data == &mons[PM_UMBER_HULK]) { if (vis) pline ("%s confuses itself!", Monnam(mtmp)); mtmp->mconf = 1; } else if(!mtmp->mcan && !mtmp->minvis && (mlet == S_NYMPH || mtmp->data==&mons[PM_SUCCUBUS])) { if (vis) { pline ("%s admires herself in your mirror.", Monnam(mtmp)); pline ("She takes it!"); } else pline ("It steals your mirror!"); setnotworn(obj); /* in case mirror was wielded */ freeinv(obj); (void) mpickobj(mtmp,obj); if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); } else if (!is_unicorn(mtmp->data) && !humanoid(mtmp->data) && (!mtmp->minvis || perceives(mtmp->data)) && rn2(5)) { if (vis) pline("%s is frightened by its reflection.", Monnam(mtmp)); monflee(mtmp, d(2,4), FALSE, FALSE); } else if (!Blind) { if (mtmp->minvis && !See_invisible) ; else if ((mtmp->minvis && !perceives(mtmp->data)) || !haseyes(mtmp->data)) pline("%s doesn't seem to notice its reflection.", Monnam(mtmp)); else pline("%s ignores %s reflection.", Monnam(mtmp), mhis(mtmp)); } return 1; } STATIC_OVL void use_bell(optr) struct obj **optr; { register struct obj *obj = *optr; struct monst *mtmp; boolean wakem = FALSE, learno = FALSE, ordinary = (obj->otyp != BELL_OF_OPENING || !obj->spe), invoking = (obj->otyp == BELL_OF_OPENING && invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)); You("ring %s.", the(xname(obj))); if (Underwater || (u.uswallow && ordinary)) { #ifdef AMIGA amii_speaker( obj, "AhDhGqEqDhEhAqDqFhGw", AMII_MUFFLED_VOLUME ); #endif pline("But the sound is muffled."); } else if (invoking && ordinary) { /* needs to be recharged... */ pline("But it makes no sound."); learno = TRUE; /* help player figure out why */ } else if (ordinary) { #ifdef AMIGA amii_speaker( obj, "ahdhgqeqdhehaqdqfhgw", AMII_MUFFLED_VOLUME ); #endif if (obj->cursed && !rn2(4) && /* note: once any of them are gone, we stop all of them */ !(mvitals[PM_WOOD_NYMPH].mvflags & G_GONE) && !(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) && !(mvitals[PM_MOUNTAIN_NYMPH].mvflags & G_GONE) && (mtmp = makemon(mkclass(S_NYMPH, 0), u.ux, u.uy, NO_MINVENT)) != 0) { You("summon %s!", a_monnam(mtmp)); if (!obj_resists(obj, 93, 100)) { pline("%s shattered!", Tobjnam(obj, "have")); useup(obj); *optr = 0; } else switch (rn2(3)) { default: break; case 1: mon_adjust_speed(mtmp, 2, (struct obj *)0); break; case 2: /* no explanation; it just happens... */ nomovemsg = ""; nomul(-rnd(2)); break; } } wakem = TRUE; } else { /* charged Bell of Opening */ consume_obj_charge(obj, TRUE); if (u.uswallow) { if (!obj->cursed) (void) openit(); else pline(nothing_happens); } else if (obj->cursed) { coord mm; mm.x = u.ux; mm.y = u.uy; mkundead(&mm, FALSE, NO_MINVENT); wakem = TRUE; } else if (invoking) { pline("%s an unsettling shrill sound...", Tobjnam(obj, "issue")); #ifdef AMIGA amii_speaker( obj, "aefeaefeaefeaefeaefe", AMII_LOUDER_VOLUME ); #endif obj->age = moves; learno = TRUE; wakem = TRUE; } else if (obj->blessed) { int res = 0; #ifdef AMIGA amii_speaker( obj, "ahahahDhEhCw", AMII_SOFT_VOLUME ); #endif if (uchain) { unpunish(); res = 1; } res += openit(); switch (res) { case 0: pline(nothing_happens); break; case 1: pline("%s opens...", Something); learno = TRUE; break; default: pline("Things open around you..."); learno = TRUE; break; } } else { /* uncursed */ #ifdef AMIGA amii_speaker( obj, "AeFeaeFeAefegw", AMII_OKAY_VOLUME ); #endif if (findit() != 0) learno = TRUE; else pline(nothing_happens); } } /* charged BofO */ if (learno) { makeknown(BELL_OF_OPENING); obj->known = 1; } if (wakem) wake_nearby(); } STATIC_OVL void use_candelabrum(obj) register struct obj *obj; { const char *s = (obj->spe != 1) ? "candles" : "candle"; if(Underwater) { You("cannot make fire under water."); return; } if(obj->lamplit) { You("snuff the %s.", s); end_burn(obj, TRUE); return; } if(obj->spe <= 0) { pline("This %s has no %s.", xname(obj), s); return; } if(u.uswallow || obj->cursed) { if (!Blind) pline_The("%s %s for a moment, then %s.", s, vtense(s, "flicker"), vtense(s, "die")); return; } if(obj->spe < 7) { There("%s only %d %s in %s.", vtense(s, "are"), obj->spe, s, the(xname(obj))); if (!Blind) pline("%s lit. %s dimly.", obj->spe == 1 ? "It is" : "They are", Tobjnam(obj, "shine")); } else { pline("%s's %s burn%s", The(xname(obj)), s, (Blind ? "." : " brightly!")); } if (!invocation_pos(u.ux, u.uy)) { pline_The("%s %s being rapidly consumed!", s, vtense(s, "are")); obj->age /= 2; } else { if(obj->spe == 7) { if (Blind) pline("%s a strange warmth!", Tobjnam(obj, "radiate")); else pline("%s with a strange light!", Tobjnam(obj, "glow")); } obj->known = 1; } begin_burn(obj, FALSE); } STATIC_OVL void use_candle(optr) struct obj **optr; { register struct obj *obj = *optr; register struct obj *otmp; const char *s = (obj->quan != 1) ? "candles" : "candle"; char qbuf[QBUFSZ]; if(u.uswallow) { You(no_elbow_room); return; } if(Underwater) { pline("Sorry, fire and water don't mix."); return; } otmp = carrying(CANDELABRUM_OF_INVOCATION); if(!otmp || otmp->spe == 7) { use_lamp(obj); return; } Sprintf(qbuf, "Attach %s", the(xname(obj))); Sprintf(eos(qbuf), " to %s?", safe_qbuf(qbuf, sizeof(" to ?"), the(xname(otmp)), the(simple_typename(otmp->otyp)), "it")); if(yn(qbuf) == 'n') { if (!obj->lamplit) You("try to light %s...", the(xname(obj))); use_lamp(obj); return; } else { if ((long)otmp->spe + obj->quan > 7L) obj = splitobj(obj, 7L - (long)otmp->spe); else *optr = 0; You("attach %ld%s %s to %s.", obj->quan, !otmp->spe ? "" : " more", s, the(xname(otmp))); if (!otmp->spe || otmp->age > obj->age) otmp->age = obj->age; otmp->spe += (int)obj->quan; if (otmp->lamplit && !obj->lamplit) pline_The("new %s magically %s!", s, vtense(s, "ignite")); else if (!otmp->lamplit && obj->lamplit) pline("%s out.", (obj->quan > 1L) ? "They go" : "It goes"); if (obj->unpaid) verbalize("You %s %s, you bought %s!", otmp->lamplit ? "burn" : "use", (obj->quan > 1L) ? "them" : "it", (obj->quan > 1L) ? "them" : "it"); if (obj->quan < 7L && otmp->spe == 7) pline("%s now has seven%s candles attached.", The(xname(otmp)), otmp->lamplit ? " lit" : ""); /* candelabrum's light range might increase */ if (otmp->lamplit) obj_merge_light_sources(otmp, otmp); /* candles are no longer a separate light source */ if (obj->lamplit) end_burn(obj, TRUE); /* candles are now gone */ useupall(obj); } } boolean snuff_candle(otmp) /* call in drop, throw, and put in box, etc. */ register struct obj *otmp; { register boolean candle = Is_candle(otmp); if ((candle || otmp->otyp == CANDELABRUM_OF_INVOCATION) && otmp->lamplit) { char buf[BUFSZ]; xchar x, y; register boolean many = candle ? otmp->quan > 1L : otmp->spe > 1; (void) get_obj_location(otmp, &x, &y, 0); if (otmp->where == OBJ_MINVENT ? cansee(x,y) : !Blind) pline("%s %scandle%s flame%s extinguished.", Shk_Your(buf, otmp), (candle ? "" : "candelabrum's "), (many ? "s'" : "'s"), (many ? "s are" : " is")); end_burn(otmp, TRUE); return(TRUE); } return(FALSE); } /* called when lit lamp is hit by water or put into a container or you've been swallowed by a monster; obj might be in transit while being thrown or dropped so don't assume that its location is valid */ boolean snuff_lit(obj) struct obj *obj; { xchar x, y; if (obj->lamplit) { if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN || obj->otyp == POT_OIL) { (void) get_obj_location(obj, &x, &y, 0); if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind) pline("%s %s out!", Yname2(obj), otense(obj, "go")); end_burn(obj, TRUE); return TRUE; } if (snuff_candle(obj)) return TRUE; } return FALSE; } /* Called when potentially lightable object is affected by fire_damage(). Return TRUE if object was lit and FALSE otherwise --ALI */ boolean catch_lit(obj) struct obj *obj; { xchar x, y; if (!obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj))) { if ((obj->otyp == MAGIC_LAMP || obj->otyp == CANDELABRUM_OF_INVOCATION) && obj->spe == 0) return FALSE; else if (obj->otyp != MAGIC_LAMP && obj->age == 0) return FALSE; if (!get_obj_location(obj, &x, &y, 0)) return FALSE; if (obj->otyp == CANDELABRUM_OF_INVOCATION && obj->cursed) return FALSE; if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN) && obj->cursed && !rn2(2)) return FALSE; if (obj->where == OBJ_MINVENT ? cansee(x,y) : !Blind) pline("%s %s light!", Yname2(obj), otense(obj, "catch")); if (obj->otyp == POT_OIL) makeknown(obj->otyp); if (obj->unpaid && costly_spot(u.ux, u.uy) && (obj->where == OBJ_INVENT)) { /* if it catches while you have it, then it's your tough luck */ check_unpaid(obj); verbalize("That's in addition to the cost of %s %s, of course.", Yname2(obj), obj->quan == 1 ? "itself" : "themselves"); bill_dummy_object(obj); } begin_burn(obj, FALSE); return TRUE; } return FALSE; } STATIC_OVL void use_lamp(obj) struct obj *obj; { char buf[BUFSZ]; if(Underwater) { pline("This is not a diving lamp."); return; } if(obj->lamplit) { if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN) pline("%s lamp is now off.", Shk_Your(buf, obj)); else You("snuff out %s.", yname(obj)); end_burn(obj, TRUE); return; } /* magic lamps with an spe == 0 (wished for) cannot be lit */ if ((!Is_candle(obj) && obj->age == 0) || (obj->otyp == MAGIC_LAMP && obj->spe == 0)) { if (obj->otyp == BRASS_LANTERN) Your("lamp has run out of power."); else pline("This %s has no oil.", xname(obj)); return; } if (obj->cursed && !rn2(2)) { pline("%s for a moment, then %s.", Tobjnam(obj, "flicker"), otense(obj, "die")); } else { if(obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN) { check_unpaid(obj); pline("%s lamp is now on.", Shk_Your(buf, obj)); } else { /* candle(s) */ pline("%s flame%s %s%s", s_suffix(Yname2(obj)), plur(obj->quan), otense(obj, "burn"), Blind ? "." : " brightly!"); if (obj->unpaid && costly_spot(u.ux, u.uy) && obj->age == 20L * (long)objects[obj->otyp].oc_cost) { const char *ithem = obj->quan > 1L ? "them" : "it"; verbalize("You burn %s, you bought %s!", ithem, ithem); bill_dummy_object(obj); } } begin_burn(obj, FALSE); } } STATIC_OVL void light_cocktail(obj) struct obj *obj; /* obj is a potion of oil */ { char buf[BUFSZ]; if (u.uswallow) { You(no_elbow_room); return; } if (obj->lamplit) { You("snuff the lit potion."); end_burn(obj, TRUE); /* * Free & add to re-merge potion. This will average the * age of the potions. Not exactly the best solution, * but its easy. */ freeinv(obj); (void) addinv(obj); return; } else if (Underwater) { There("is not enough oxygen to sustain a fire."); return; } You("light %s potion.%s", shk_your(buf, obj), Blind ? "" : " It gives off a dim light."); if (obj->unpaid && costly_spot(u.ux, u.uy)) { /* Normally, we shouldn't both partially and fully charge * for an item, but (Yendorian Fuel) Taxes are inevitable... */ check_unpaid(obj); verbalize("That's in addition to the cost of the potion, of course."); bill_dummy_object(obj); } makeknown(obj->otyp); if (obj->quan > 1L) { obj = splitobj(obj, 1L); begin_burn(obj, FALSE); /* burn before free to get position */ obj_extract_self(obj); /* free from inv */ /* shouldn't merge */ obj = hold_another_object(obj, "You drop %s!", doname(obj), (const char *)0); } else begin_burn(obj, FALSE); } static NEARDATA const char cuddly[] = { TOOL_CLASS, GEM_CLASS, 0 }; int dorub() { struct obj *obj = getobj(cuddly, "rub"); if (obj && obj->oclass == GEM_CLASS) { if (is_graystone(obj)) { use_stone(obj); return 1; } else { pline("Sorry, I don't know how to use that."); return 0; } } if (!obj || !wield_tool(obj, "rub")) return 0; /* now uwep is obj */ if (uwep->otyp == MAGIC_LAMP) { if (uwep->spe > 0 && !rn2(3)) { check_unpaid_usage(uwep, TRUE); /* unusual item use */ djinni_from_bottle(uwep); makeknown(MAGIC_LAMP); uwep->otyp = OIL_LAMP; uwep->spe = 0; /* for safety */ uwep->age = rn1(500,1000); if (uwep->lamplit) begin_burn(uwep, TRUE); update_inventory(); } else if (rn2(2) && !Blind) You("see a puff of smoke."); else pline(nothing_happens); } else if (obj->otyp == BRASS_LANTERN) { /* message from Adventure */ pline("Rubbing the electric lamp is not particularly rewarding."); pline("Anyway, nothing exciting happens."); } else pline(nothing_happens); return 1; } int dojump() { /* Physical jump */ return jump(0); } int jump(magic) int magic; /* 0=Physical, otherwise skill level */ { coord cc; if (!magic && (nolimbs(youmonst.data) || slithy(youmonst.data))) { /* normally (nolimbs || slithy) implies !Jumping, but that isn't necessarily the case for knights */ You_cant("jump; you have no legs!"); return 0; } else if (!magic && !Jumping) { You_cant("jump very far."); return 0; } else if (u.uswallow) { if (magic) { You("bounce around a little."); return 1; } pline("You've got to be kidding!"); return 0; } else if (u.uinwater) { if (magic) { You("swish around a little."); return 1; } pline("This calls for swimming, not jumping!"); return 0; } else if (u.ustuck) { if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) { You("pull free from %s.", mon_nam(u.ustuck)); u.ustuck = 0; return 1; } if (magic) { You("writhe a little in the grasp of %s!", mon_nam(u.ustuck)); return 1; } You("cannot escape from %s!", mon_nam(u.ustuck)); return 0; } else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) { if (magic) { You("flail around a little."); return 1; } You("don't have enough traction to jump."); return 0; } else if (!magic && near_capacity() > UNENCUMBERED) { You("are carrying too much to jump!"); return 0; } else if (!magic && (u.uhunger <= 100 || ACURR(A_STR) < 6)) { You("lack the strength to jump!"); return 0; } else if (Wounded_legs) { long wl = (Wounded_legs & BOTH_SIDES); const char *bp = body_part(LEG); if (wl == BOTH_SIDES) bp = makeplural(bp); #ifdef STEED if (u.usteed) pline("%s is in no shape for jumping.", Monnam(u.usteed)); else #endif Your("%s%s %s in no shape for jumping.", (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right " : "", bp, (wl == BOTH_SIDES) ? "are" : "is"); return 0; } #ifdef STEED else if (u.usteed && u.utrap) { pline("%s is stuck in a trap.", Monnam(u.usteed)); return (0); } #endif pline("Where do you want to jump?"); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the desired position") < 0) return 0; /* user pressed ESC */ if (!magic && !(HJumping & ~INTRINSIC) && !EJumping && distu(cc.x, cc.y) != 5) { /* The Knight jumping restriction still applies when riding a * horse. After all, what shape is the knight piece in chess? */ pline("Illegal move!"); return 0; } else if (distu(cc.x, cc.y) > (magic ? 6+magic*3 : 9)) { pline("Too far!"); return 0; } else if (!cansee(cc.x, cc.y)) { You("cannot see where to land!"); return 0; } else if (!isok(cc.x, cc.y)) { You("cannot jump there!"); return 0; } else { coord uc; int range, temp; if(u.utrap) switch(u.utraptype) { case TT_BEARTRAP: { register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; You("rip yourself free of the bear trap! Ouch!"); losehp(rnd(10), "jumping out of a bear trap", KILLED_BY); set_wounded_legs(side, rn1(1000,500)); break; } case TT_PIT: You("leap from the pit!"); break; case TT_WEB: You("tear the web apart as you pull yourself free!"); deltrap(t_at(u.ux,u.uy)); break; case TT_LAVA: You("pull yourself above the lava!"); u.utrap = 0; return 1; case TT_INFLOOR: You("strain your %s, but you're still stuck in the floor.", makeplural(body_part(LEG))); set_wounded_legs(LEFT_SIDE, rn1(10, 11)); set_wounded_legs(RIGHT_SIDE, rn1(10, 11)); return 1; } /* * Check the path from uc to cc, calling hurtle_step at each * location. The final position actually reached will be * in cc. */ uc.x = u.ux; uc.y = u.uy; /* calculate max(abs(dx), abs(dy)) as the range */ range = cc.x - uc.x; if (range < 0) range = -range; temp = cc.y - uc.y; if (temp < 0) temp = -temp; if (range < temp) range = temp; (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t)&range); /* A little Sokoban guilt... */ if (In_sokoban(&u.uz)) change_luck(-1); teleds(cc.x, cc.y, TRUE); nomul(-1); nomovemsg = ""; morehungry(rnd(25)); return 1; } } boolean tinnable(corpse) struct obj *corpse; { if (corpse->oeaten) return 0; if (!mons[corpse->corpsenm].cnutrit) return 0; return 1; } STATIC_OVL void use_tinning_kit(obj) register struct obj *obj; { register struct obj *corpse, *can; /* This takes only 1 move. If this is to be changed to take many * moves, we've got to deal with decaying corpses... */ if (obj->spe <= 0) { You("seem to be out of tins."); return; } if (!(corpse = floorfood("tin", 2))) return; if (corpse->oeaten) { You("cannot tin %s which is partly eaten.",something); return; } if (touch_petrifies(&mons[corpse->corpsenm]) && !Stone_resistance && !uarmg) { char kbuf[BUFSZ]; if (poly_when_stoned(youmonst.data)) You("tin %s without wearing gloves.", an(mons[corpse->corpsenm].mname)); else { pline("Tinning %s without wearing gloves is a fatal mistake...", an(mons[corpse->corpsenm].mname)); Sprintf(kbuf, "trying to tin %s without gloves", an(mons[corpse->corpsenm].mname)); } instapetrify(kbuf); } if (is_rider(&mons[corpse->corpsenm])) { (void) revive_corpse(corpse); verbalize("Yes... But War does not preserve its enemies..."); return; } if (mons[corpse->corpsenm].cnutrit == 0) { pline("That's too insubstantial to tin."); return; } consume_obj_charge(obj, TRUE); if ((can = mksobj(TIN, FALSE, FALSE)) != 0) { static const char you_buy_it[] = "You tin it, you bought it!"; can->corpsenm = corpse->corpsenm; can->cursed = obj->cursed; can->blessed = obj->blessed; can->owt = weight(can); can->known = 1; can->spe = -1; /* Mark tinned tins. No spinach allowed... */ if (carried(corpse)) { if (corpse->unpaid) verbalize(you_buy_it); useup(corpse); } else { if (costly_spot(corpse->ox, corpse->oy) && !corpse->no_charge) verbalize(you_buy_it); useupf(corpse, 1L); } can = hold_another_object(can, "You make, but cannot pick up, %s.", doname(can), (const char *)0); } else impossible("Tinning failed."); } void use_unicorn_horn(obj) struct obj *obj; { #define PROP_COUNT 6 /* number of properties we're dealing with */ #define ATTR_COUNT (A_MAX*3) /* number of attribute points we might fix */ int idx, val, val_limit, trouble_count, unfixable_trbl, did_prop, did_attr; int trouble_list[PROP_COUNT + ATTR_COUNT]; if (obj && obj->cursed) { long lcount = (long) rnd(100); switch (rn2(6)) { case 0: make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON),20), xname(obj), TRUE, SICK_NONVOMITABLE); break; case 1: make_blinded(Blinded + lcount, TRUE); break; case 2: if (!Confusion) You("suddenly feel %s.", Hallucination ? "trippy" : "confused"); make_confused(HConfusion + lcount, TRUE); break; case 3: make_stunned(HStun + lcount, TRUE); break; case 4: (void) adjattrib(rn2(A_MAX), -1, FALSE); break; case 5: (void) make_hallucinated(HHallucination + lcount, TRUE, 0L); break; } return; } /* * Entries in the trouble list use a very simple encoding scheme. */ #define prop2trbl(X) ((X) + A_MAX) #define attr2trbl(Y) (Y) #define prop_trouble(X) trouble_list[trouble_count++] = prop2trbl(X) #define attr_trouble(Y) trouble_list[trouble_count++] = attr2trbl(Y) trouble_count = unfixable_trbl = did_prop = did_attr = 0; /* collect property troubles */ if (Sick) prop_trouble(SICK); if (Blinded > (long)u.ucreamed) prop_trouble(BLINDED); if (HHallucination) prop_trouble(HALLUC); if (Vomiting) prop_trouble(VOMITING); if (HConfusion) prop_trouble(CONFUSION); if (HStun) prop_trouble(STUNNED); unfixable_trbl = unfixable_trouble_count(TRUE); /* collect attribute troubles */ for (idx = 0; idx < A_MAX; idx++) { val_limit = AMAX(idx); /* don't recover strength lost from hunger */ if (idx == A_STR && u.uhs >= WEAK) val_limit--; /* don't recover more than 3 points worth of any attribute */ if (val_limit > ABASE(idx) + 3) val_limit = ABASE(idx) + 3; for (val = ABASE(idx); val < val_limit; val++) attr_trouble(idx); /* keep track of unfixed trouble, for message adjustment below */ unfixable_trbl += (AMAX(idx) - val_limit); } if (trouble_count == 0) { pline(nothing_happens); return; } else if (trouble_count > 1) { /* shuffle */ int i, j, k; for (i = trouble_count - 1; i > 0; i--) if ((j = rn2(i + 1)) != i) { k = trouble_list[j]; trouble_list[j] = trouble_list[i]; trouble_list[i] = k; } } /* * Chances for number of troubles to be fixed * 0 1 2 3 4 5 6 7 * blessed: 22.7% 22.7% 19.5% 15.4% 10.7% 5.7% 2.6% 0.8% * uncursed: 35.4% 35.4% 22.9% 6.3% 0 0 0 0 */ val_limit = rn2( d(2, (obj && obj->blessed) ? 4 : 2) ); if (val_limit > trouble_count) val_limit = trouble_count; /* fix [some of] the troubles */ for (val = 0; val < val_limit; val++) { idx = trouble_list[val]; switch (idx) { case prop2trbl(SICK): make_sick(0L, (char *) 0, TRUE, SICK_ALL); did_prop++; break; case prop2trbl(BLINDED): make_blinded((long)u.ucreamed, TRUE); did_prop++; break; case prop2trbl(HALLUC): (void) make_hallucinated(0L, TRUE, 0L); did_prop++; break; case prop2trbl(VOMITING): make_vomiting(0L, TRUE); did_prop++; break; case prop2trbl(CONFUSION): make_confused(0L, TRUE); did_prop++; break; case prop2trbl(STUNNED): make_stunned(0L, TRUE); did_prop++; break; default: if (idx >= 0 && idx < A_MAX) { ABASE(idx) += 1; did_attr++; } else panic("use_unicorn_horn: bad trouble? (%d)", idx); break; } } if (did_attr) pline("This makes you feel %s!", (did_prop + did_attr) == (trouble_count + unfixable_trbl) ? "great" : "better"); else if (!did_prop) pline("Nothing seems to happen."); flags.botl = (did_attr || did_prop); #undef PROP_COUNT #undef ATTR_COUNT #undef prop2trbl #undef attr2trbl #undef prop_trouble #undef attr_trouble } /* * Timer callback routine: turn figurine into monster */ void fig_transform(arg, timeout) genericptr_t arg; long timeout; { struct obj *figurine = (struct obj *)arg; struct monst *mtmp; coord cc; boolean cansee_spot, silent, okay_spot; boolean redraw = FALSE; char monnambuf[BUFSZ], carriedby[BUFSZ]; if (!figurine) { #ifdef DEBUG pline("null figurine in fig_transform()"); #endif return; } silent = (timeout != monstermoves); /* happened while away */ okay_spot = get_obj_location(figurine, &cc.x, &cc.y, 0); if (figurine->where == OBJ_INVENT || figurine->where == OBJ_MINVENT) okay_spot = enexto(&cc, cc.x, cc.y, &mons[figurine->corpsenm]); if (!okay_spot || !figurine_location_checks(figurine,&cc, TRUE)) { /* reset the timer to try again later */ (void) start_timer((long)rnd(5000), TIMER_OBJECT, FIG_TRANSFORM, (genericptr_t)figurine); return; } cansee_spot = cansee(cc.x, cc.y); mtmp = make_familiar(figurine, cc.x, cc.y, TRUE); if (mtmp) { Sprintf(monnambuf, "%s",an(m_monnam(mtmp))); switch (figurine->where) { case OBJ_INVENT: if (Blind) You_feel("%s %s from your pack!", something, locomotion(mtmp->data,"drop")); else You("see %s %s out of your pack!", monnambuf, locomotion(mtmp->data,"drop")); break; case OBJ_FLOOR: if (cansee_spot && !silent) { You("suddenly see a figurine transform into %s!", monnambuf); redraw = TRUE; /* update figurine's map location */ } break; case OBJ_MINVENT: if (cansee_spot && !silent) { struct monst *mon; mon = figurine->ocarry; /* figurine carring monster might be invisible */ if (canseemon(figurine->ocarry)) { Sprintf(carriedby, "%s pack", s_suffix(a_monnam(mon))); } else if (is_pool(mon->mx, mon->my)) Strcpy(carriedby, "empty water"); else Strcpy(carriedby, "thin air"); You("see %s %s out of %s!", monnambuf, locomotion(mtmp->data, "drop"), carriedby); } break; #if 0 case OBJ_MIGRATING: break; #endif default: impossible("figurine came to life where? (%d)", (int)figurine->where); break; } } /* free figurine now */ obj_extract_self(figurine); obfree(figurine, (struct obj *)0); if (redraw) newsym(cc.x, cc.y); } STATIC_OVL boolean figurine_location_checks(obj, cc, quietly) struct obj *obj; coord *cc; boolean quietly; { xchar x,y; if (carried(obj) && u.uswallow) { if (!quietly) You("don't have enough room in here."); return FALSE; } x = cc->x; y = cc->y; if (!isok(x,y)) { if (!quietly) You("cannot put the figurine there."); return FALSE; } if (IS_ROCK(levl[x][y].typ) && !(passes_walls(&mons[obj->corpsenm]) && may_passwall(x,y))) { if (!quietly) You("cannot place a figurine in %s!", IS_TREE(levl[x][y].typ) ? "a tree" : "solid rock"); return FALSE; } if (sobj_at(BOULDER,x,y) && !passes_walls(&mons[obj->corpsenm]) && !throws_rocks(&mons[obj->corpsenm])) { if (!quietly) You("cannot fit the figurine on the boulder."); return FALSE; } return TRUE; } STATIC_OVL void use_figurine(optr) struct obj **optr; { register struct obj *obj = *optr; xchar x, y; coord cc; if (u.uswallow) { /* can't activate a figurine while swallowed */ if (!figurine_location_checks(obj, (coord *)0, FALSE)) return; } if(!getdir((char *)0)) { flags.move = multi = 0; return; } x = u.ux + u.dx; y = u.uy + u.dy; cc.x = x; cc.y = y; /* Passing FALSE arg here will result in messages displayed */ if (!figurine_location_checks(obj, &cc, FALSE)) return; You("%s and it transforms.", (u.dx||u.dy) ? "set the figurine beside you" : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || is_pool(cc.x, cc.y)) ? "release the figurine" : (u.dz < 0 ? "toss the figurine into the air" : "set the figurine on the ground")); (void) make_familiar(obj, cc.x, cc.y, FALSE); (void) stop_timer(FIG_TRANSFORM, (genericptr_t)obj); useup(obj); *optr = 0; } static NEARDATA const char lubricables[] = { ALL_CLASSES, ALLOW_NONE, 0 }; static NEARDATA const char need_to_remove_outer_armor[] = "need to remove your %s to grease your %s."; STATIC_OVL void use_grease(obj) struct obj *obj; { struct obj *otmp; char buf[BUFSZ]; if (Glib) { pline("%s from your %s.", Tobjnam(obj, "slip"), makeplural(body_part(FINGER))); dropx(obj); return; } if (obj->spe > 0) { if ((obj->cursed || Fumbling) && !rn2(2)) { consume_obj_charge(obj, TRUE); pline("%s from your %s.", Tobjnam(obj, "slip"), makeplural(body_part(FINGER))); dropx(obj); return; } otmp = getobj(lubricables, "grease"); if (!otmp) return; if ((otmp->owornmask & WORN_ARMOR) && uarmc) { Strcpy(buf, xname(uarmc)); You(need_to_remove_outer_armor, buf, xname(otmp)); return; } #ifdef TOURIST if ((otmp->owornmask & WORN_SHIRT) && (uarmc || uarm)) { Strcpy(buf, uarmc ? xname(uarmc) : ""); if (uarmc && uarm) Strcat(buf, " and "); Strcat(buf, uarm ? xname(uarm) : ""); You(need_to_remove_outer_armor, buf, xname(otmp)); return; } #endif consume_obj_charge(obj, TRUE); if (otmp != &zeroobj) { You("cover %s with a thick layer of grease.", yname(otmp)); otmp->greased = 1; if (obj->cursed && !nohands(youmonst.data)) { incr_itimeout(&Glib, rnd(15)); pline("Some of the grease gets all over your %s.", makeplural(body_part(HAND))); } } else { Glib += rnd(15); You("coat your %s with grease.", makeplural(body_part(FINGER))); } } else { if (obj->known) pline("%s empty.", Tobjnam(obj, "are")); else pline("%s to be empty.", Tobjnam(obj, "seem")); } update_inventory(); } static struct trapinfo { struct obj *tobj; xchar tx, ty; int time_needed; boolean force_bungle; } trapinfo; void reset_trapset() { trapinfo.tobj = 0; trapinfo.force_bungle = 0; } /* touchstones - by Ken Arnold */ STATIC_OVL void use_stone(tstone) struct obj *tstone; { struct obj *obj; boolean do_scratch; const char *streak_color, *choices; char stonebuf[QBUFSZ]; static const char scritch[] = "\"scritch, scritch\""; static const char allowall[3] = { COIN_CLASS, ALL_CLASSES, 0 }; static const char justgems[3] = { ALLOW_NONE, GEM_CLASS, 0 }; #ifndef GOLDOBJ struct obj goldobj; #endif /* in case it was acquired while blinded */ if (!Blind) tstone->dknown = 1; /* when the touchstone is fully known, don't bother listing extra junk as likely candidates for rubbing */ choices = (tstone->otyp == TOUCHSTONE && tstone->dknown && objects[TOUCHSTONE].oc_name_known) ? justgems : allowall; Sprintf(stonebuf, "rub on the stone%s", plur(tstone->quan)); if ((obj = getobj(choices, stonebuf)) == 0) return; #ifndef GOLDOBJ if (obj->oclass == COIN_CLASS) { u.ugold += obj->quan; /* keep botl up to date */ goldobj = *obj; dealloc_obj(obj); obj = &goldobj; } #endif if (obj == tstone && obj->quan == 1) { You_cant("rub %s on itself.", the(xname(obj))); return; } if (tstone->otyp == TOUCHSTONE && tstone->cursed && obj->oclass == GEM_CLASS && !is_graystone(obj) && !obj_resists(obj, 80, 100)) { if (Blind) pline("You feel something shatter."); else if (Hallucination) pline("Oh, wow, look at the pretty shards."); else pline("A sharp crack shatters %s%s.", (obj->quan > 1) ? "one of " : "", the(xname(obj))); #ifndef GOLDOBJ /* assert(obj != &goldobj); */ #endif useup(obj); return; } if (Blind) { pline(scritch); return; } else if (Hallucination) { pline("Oh wow, man: Fractals!"); return; } do_scratch = FALSE; streak_color = 0; switch (obj->oclass) { case GEM_CLASS: /* these have class-specific handling below */ case RING_CLASS: if (tstone->otyp != TOUCHSTONE) { do_scratch = TRUE; } else if (obj->oclass == GEM_CLASS && (tstone->blessed || (!tstone->cursed && (Role_if(PM_ARCHEOLOGIST) || Race_if(PM_GNOME))))) { makeknown(TOUCHSTONE); makeknown(obj->otyp); prinv((char *)0, obj, 0L); return; } else { /* either a ring or the touchstone was not effective */ if (objects[obj->otyp].oc_material == GLASS) { do_scratch = TRUE; break; } } streak_color = c_obj_colors[objects[obj->otyp].oc_color]; break; /* gem or ring */ default: switch (objects[obj->otyp].oc_material) { case CLOTH: pline("%s a little more polished now.", Tobjnam(tstone, "look")); return; case LIQUID: if (!obj->known) /* note: not "whetstone" */ You("must think this is a wetstone, do you?"); else pline("%s a little wetter now.", Tobjnam(tstone, "are")); return; case WAX: streak_color = "waxy"; break; /* okay even if not touchstone */ case WOOD: streak_color = "wooden"; break; /* okay even if not touchstone */ case GOLD: do_scratch = TRUE; /* scratching and streaks */ streak_color = "golden"; break; case SILVER: do_scratch = TRUE; /* scratching and streaks */ streak_color = "silvery"; break; default: /* Objects passing the is_flimsy() test will not scratch a stone. They will leave streaks on non-touchstones and touchstones alike. */ if (is_flimsy(obj)) streak_color = c_obj_colors[objects[obj->otyp].oc_color]; else do_scratch = (tstone->otyp != TOUCHSTONE); break; } break; /* default oclass */ } Sprintf(stonebuf, "stone%s", plur(tstone->quan)); if (do_scratch) pline("You make %s%sscratch marks on the %s.", streak_color ? streak_color : (const char *)"", streak_color ? " " : "", stonebuf); else if (streak_color) pline("You see %s streaks on the %s.", streak_color, stonebuf); else pline(scritch); return; } /* Place a landmine/bear trap. Helge Hafting */ STATIC_OVL void use_trap(otmp) struct obj *otmp; { int ttyp, tmp; const char *what = (char *)0; char buf[BUFSZ]; const char *occutext = "setting the trap"; if (nohands(youmonst.data)) what = "without hands"; else if (Stunned) what = "while stunned"; else if (u.uswallow) what = is_animal(u.ustuck->data) ? "while swallowed" : "while engulfed"; else if (Underwater) what = "underwater"; else if (Levitation) what = "while levitating"; else if (is_pool(u.ux, u.uy)) what = "in water"; else if (is_lava(u.ux, u.uy)) what = "in lava"; else if (On_stairs(u.ux, u.uy)) what = (u.ux == xdnladder || u.ux == xupladder) ? "on the ladder" : "on the stairs"; else if (IS_FURNITURE(levl[u.ux][u.uy].typ) || IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy) || t_at(u.ux, u.uy)) what = "here"; if (what) { You_cant("set a trap %s!",what); reset_trapset(); return; } ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP; if (otmp == trapinfo.tobj && u.ux == trapinfo.tx && u.uy == trapinfo.ty) { You("resume setting %s %s.", shk_your(buf, otmp), defsyms[trap_to_defsym(what_trap(ttyp))].explanation); set_occupation(set_trap, occutext, 0); return; } trapinfo.tobj = otmp; trapinfo.tx = u.ux, trapinfo.ty = u.uy; tmp = ACURR(A_DEX); trapinfo.time_needed = (tmp > 17) ? 2 : (tmp > 12) ? 3 : (tmp > 7) ? 4 : 5; if (Blind) trapinfo.time_needed *= 2; tmp = ACURR(A_STR); if (ttyp == BEAR_TRAP && tmp < 18) trapinfo.time_needed += (tmp > 12) ? 1 : (tmp > 7) ? 2 : 4; /*[fumbling and/or confusion and/or cursed object check(s) should be incorporated here instead of in set_trap]*/ #ifdef STEED if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { boolean chance; if (Fumbling || otmp->cursed) chance = (rnl(10) > 3); else chance = (rnl(10) > 5); You("aren't very skilled at reaching from %s.", mon_nam(u.usteed)); Sprintf(buf, "Continue your attempt to set %s?", the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); if(yn(buf) == 'y') { if (chance) { switch(ttyp) { case LANDMINE: /* set it off */ trapinfo.time_needed = 0; trapinfo.force_bungle = TRUE; break; case BEAR_TRAP: /* drop it without arming it */ reset_trapset(); You("drop %s!", the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); dropx(otmp); return; } } } else { reset_trapset(); return; } } #endif You("begin setting %s %s.", shk_your(buf, otmp), defsyms[trap_to_defsym(what_trap(ttyp))].explanation); set_occupation(set_trap, occutext, 0); return; } STATIC_PTR int set_trap() { struct obj *otmp = trapinfo.tobj; struct trap *ttmp; int ttyp; if (!otmp || !carried(otmp) || u.ux != trapinfo.tx || u.uy != trapinfo.ty) { /* ?? */ reset_trapset(); return 0; } if (--trapinfo.time_needed > 0) return 1; /* still busy */ ttyp = (otmp->otyp == LAND_MINE) ? LANDMINE : BEAR_TRAP; ttmp = maketrap(u.ux, u.uy, ttyp); if (ttmp) { ttmp->tseen = 1; ttmp->madeby_u = 1; newsym(u.ux, u.uy); /* if our hero happens to be invisible */ if (*in_rooms(u.ux,u.uy,SHOPBASE)) { add_damage(u.ux, u.uy, 0L); /* schedule removal */ } if (!trapinfo.force_bungle) You("finish arming %s.", the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); if (((otmp->cursed || Fumbling) && (rnl(10) > 5)) || trapinfo.force_bungle) dotrap(ttmp, (unsigned)(trapinfo.force_bungle ? FORCEBUNGLE : 0)); } else { /* this shouldn't happen */ Your("trap setting attempt fails."); } useup(otmp); reset_trapset(); return 0; } STATIC_OVL int use_whip(obj) struct obj *obj; { char buf[BUFSZ]; struct monst *mtmp; struct obj *otmp; int rx, ry, proficient, res = 0; const char *msg_slipsfree = "The bullwhip slips free."; const char *msg_snap = "Snap!"; if (obj != uwep) { if (!wield_tool(obj, "lash")) return 0; else res = 1; } if (!getdir((char *)0)) return res; if (Stunned || (Confusion && !rn2(5))) confdir(); rx = u.ux + u.dx; ry = u.uy + u.dy; mtmp = m_at(rx, ry); /* fake some proficiency checks */ proficient = 0; if (Role_if(PM_ARCHEOLOGIST)) ++proficient; if (ACURR(A_DEX) < 6) proficient--; else if (ACURR(A_DEX) >= 14) proficient += (ACURR(A_DEX) - 14); if (Fumbling) --proficient; if (proficient > 3) proficient = 3; if (proficient < 0) proficient = 0; if (u.uswallow && attack(u.ustuck)) { There("is not enough room to flick your bullwhip."); } else if (Underwater) { There("is too much resistance to flick your bullwhip."); } else if (u.dz < 0) { You("flick a bug off of the %s.",ceiling(u.ux,u.uy)); } else if ((!u.dx && !u.dy) || (u.dz > 0)) { int dam; #ifdef STEED /* Sometimes you hit your steed by mistake */ if (u.usteed && !rn2(proficient + 2)) { You("whip %s!", mon_nam(u.usteed)); kick_steed(); return 1; } #endif if (Levitation #ifdef STEED || u.usteed #endif ) { /* Have a shot at snaring something on the floor */ otmp = level.objects[u.ux][u.uy]; if (otmp && otmp->otyp == CORPSE && otmp->corpsenm == PM_HORSE) { pline("Why beat a dead horse?"); return 1; } if (otmp && proficient) { You("wrap your bullwhip around %s on the %s.", an(singular(otmp, xname)), surface(u.ux, u.uy)); if (rnl(6) || pickup_object(otmp, 1L, TRUE) < 1) pline(msg_slipsfree); return 1; } } dam = rnd(2) + dbon() + obj->spe; if (dam <= 0) dam = 1; You("hit your %s with your bullwhip.", body_part(FOOT)); Sprintf(buf, "killed %sself with %s bullwhip", uhim(), uhis()); losehp(dam, buf, NO_KILLER_PREFIX); flags.botl = 1; return 1; } else if ((Fumbling || Glib) && !rn2(5)) { pline_The("bullwhip slips out of your %s.", body_part(HAND)); dropx(obj); } else if (u.utrap && u.utraptype == TT_PIT) { /* * Assumptions: * * if you're in a pit * - you are attempting to get out of the pit * - or, if you are applying it towards a small * monster then it is assumed that you are * trying to hit it. * else if the monster is wielding a weapon * - you are attempting to disarm a monster * else * - you are attempting to hit the monster * * if you're confused (and thus off the mark) * - you only end up hitting. * */ const char *wrapped_what = (char *)0; if (mtmp) { if (bigmonst(mtmp->data)) { wrapped_what = strcpy(buf, mon_nam(mtmp)); } else if (proficient) { if (attack(mtmp)) return 1; else pline(msg_snap); } } if (!wrapped_what) { if (IS_FURNITURE(levl[rx][ry].typ)) wrapped_what = something; else if (sobj_at(BOULDER, rx, ry)) wrapped_what = "a boulder"; } if (wrapped_what) { coord cc; cc.x = rx; cc.y = ry; You("wrap your bullwhip around %s.", wrapped_what); if (proficient && rn2(proficient + 2)) { if (!mtmp || enexto(&cc, rx, ry, youmonst.data)) { You("yank yourself out of the pit!"); teleds(cc.x, cc.y, TRUE); u.utrap = 0; vision_full_recalc = 1; } } else { pline(msg_slipsfree); } if (mtmp) wakeup(mtmp); } else pline(msg_snap); } else if (mtmp) { if (!canspotmon(mtmp) && !glyph_is_invisible(levl[rx][ry].glyph)) { pline("A monster is there that you couldn't see."); map_invisible(rx, ry); } otmp = MON_WEP(mtmp); /* can be null */ if (otmp) { char onambuf[BUFSZ]; const char *mon_hand; boolean gotit = proficient && (!Fumbling || !rn2(10)); Strcpy(onambuf, cxname(otmp)); if (gotit) { mon_hand = mbodypart(mtmp, HAND); if (bimanual(otmp)) mon_hand = makeplural(mon_hand); } else mon_hand = 0; /* lint suppression */ You("wrap your bullwhip around %s %s.", s_suffix(mon_nam(mtmp)), onambuf); if (gotit && otmp->cursed) { pline("%s welded to %s %s%c", (otmp->quan == 1L) ? "It is" : "They are", mhis(mtmp), mon_hand, !otmp->bknown ? '!' : '.'); otmp->bknown = 1; gotit = FALSE; /* can't pull it free */ } if (gotit) { obj_extract_self(otmp); possibly_unwield(mtmp, FALSE); setmnotwielded(mtmp,otmp); switch (rn2(proficient + 1)) { case 2: /* to floor near you */ You("yank %s %s to the %s!", s_suffix(mon_nam(mtmp)), onambuf, surface(u.ux, u.uy)); place_object(otmp, u.ux, u.uy); stackobj(otmp); break; case 3: /* right to you */ #if 0 if (!rn2(25)) { /* proficient with whip, but maybe not so proficient at catching weapons */ int hitu, hitvalu; hitvalu = 8 + otmp->spe; hitu = thitu(hitvalu, dmgval(otmp, &youmonst), otmp, (char *)0); if (hitu) { pline_The("%s hits you as you try to snatch it!", the(onambuf)); } place_object(otmp, u.ux, u.uy); stackobj(otmp); break; } #endif /* 0 */ /* right into your inventory */ You("snatch %s %s!", s_suffix(mon_nam(mtmp)), onambuf); if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !uarmg && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { char kbuf[BUFSZ]; Sprintf(kbuf, "%s corpse", an(mons[otmp->corpsenm].mname)); pline("Snatching %s is a fatal mistake.", kbuf); instapetrify(kbuf); } otmp = hold_another_object(otmp, "You drop %s!", doname(otmp), (const char *)0); break; default: /* to floor beneath mon */ You("yank %s from %s %s!", the(onambuf), s_suffix(mon_nam(mtmp)), mon_hand); obj_no_longer_held(otmp); place_object(otmp, mtmp->mx, mtmp->my); stackobj(otmp); break; } } else { pline(msg_slipsfree); } wakeup(mtmp); } else { if (mtmp->m_ap_type && !Protection_from_shape_changers && !sensemon(mtmp)) stumble_onto_mimic(mtmp); else You("flick your bullwhip towards %s.", mon_nam(mtmp)); if (proficient) { if (attack(mtmp)) return 1; else pline(msg_snap); } } } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) { /* it must be air -- water checked above */ You("snap your whip through thin air."); } else { pline(msg_snap); } return 1; } static const char not_enough_room[] = "There's not enough room here to use that.", where_to_hit[] = "Where do you want to hit?", cant_see_spot[] = "won't hit anything if you can't see that spot.", cant_reach[] = "can't reach that spot from here."; /* Distance attacks by pole-weapons */ STATIC_OVL int use_pole (obj) struct obj *obj; { int res = 0, typ, max_range = 4, min_range = 4; coord cc; struct monst *mtmp; /* Are you allowed to use the pole? */ if (u.uswallow) { pline(not_enough_room); return (0); } if (obj != uwep) { if (!wield_tool(obj, "swing")) return(0); else res = 1; } /* assert(obj == uwep); */ /* Prompt for a location */ pline(where_to_hit); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the spot to hit") < 0) return 0; /* user pressed ESC */ /* Calculate range */ typ = uwep_skill_type(); if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4; else if (P_SKILL(typ) == P_SKILLED) max_range = 5; else max_range = 8; if (distu(cc.x, cc.y) > max_range) { pline("Too far!"); return (res); } else if (distu(cc.x, cc.y) < min_range) { pline("Too close!"); return (res); } else if (!cansee(cc.x, cc.y) && ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0 || !canseemon(mtmp))) { You(cant_see_spot); return (res); } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */ You(cant_reach); return res; } /* Attack the monster there */ if ((mtmp = m_at(cc.x, cc.y)) != (struct monst *)0) { int oldhp = mtmp->mhp; bhitpos = cc; check_caitiff(mtmp); (void) thitmonst(mtmp, uwep); /* check the monster's HP because thitmonst() doesn't return * an indication of whether it hit. Not perfect (what if it's a * non-silver weapon on a shade?) */ if (mtmp->mhp < oldhp) u.uconduct.weaphit++; } else /* Now you know that nothing is there... */ pline(nothing_happens); return (1); } STATIC_OVL int use_cream_pie(obj) struct obj *obj; { boolean wasblind = Blind; boolean wascreamed = u.ucreamed; boolean several = FALSE; if (obj->quan > 1L) { several = TRUE; obj = splitobj(obj, 1L); } if (Hallucination) You("give yourself a facial."); else pline("You immerse your %s in %s%s.", body_part(FACE), several ? "one of " : "", several ? makeplural(the(xname(obj))) : the(xname(obj))); if(can_blnd((struct monst*)0, &youmonst, AT_WEAP, obj)) { int blindinc = rnd(25); u.ucreamed += blindinc; make_blinded(Blinded + (long)blindinc, FALSE); if (!Blind || (Blind && wasblind)) pline("There's %ssticky goop all over your %s.", wascreamed ? "more " : "", body_part(FACE)); else /* Blind && !wasblind */ You_cant("see through all the sticky goop on your %s.", body_part(FACE)); } if (obj->unpaid) { verbalize("You used it, you bought it!"); bill_dummy_object(obj); } obj_extract_self(obj); delobj(obj); return(0); } STATIC_OVL int use_grapple (obj) struct obj *obj; { int res = 0, typ, max_range = 4, tohit; coord cc; struct monst *mtmp; struct obj *otmp; /* Are you allowed to use the hook? */ if (u.uswallow) { pline(not_enough_room); return (0); } if (obj != uwep) { if (!wield_tool(obj, "cast")) return(0); else res = 1; } /* assert(obj == uwep); */ /* Prompt for a location */ pline(where_to_hit); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the spot to hit") < 0) return 0; /* user pressed ESC */ /* Calculate range */ typ = uwep_skill_type(); if (typ == P_NONE || P_SKILL(typ) <= P_BASIC) max_range = 4; else if (P_SKILL(typ) == P_SKILLED) max_range = 5; else max_range = 8; if (distu(cc.x, cc.y) > max_range) { pline("Too far!"); return (res); } else if (!cansee(cc.x, cc.y)) { You(cant_see_spot); return (res); } else if (!couldsee(cc.x, cc.y)) { /* Eyes of the Overworld */ You(cant_reach); return res; } /* What do you want to hit? */ tohit = rn2(5); if (typ != P_NONE && P_SKILL(typ) >= P_SKILLED) { winid tmpwin = create_nhwindow(NHW_MENU); anything any; char buf[BUFSZ]; menu_item *selected; any.a_void = 0; /* set all bits to zero */ any.a_int = 1; /* use index+1 (cant use 0) as identifier */ start_menu(tmpwin); any.a_int++; Sprintf(buf, "an object on the %s", surface(cc.x, cc.y)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); any.a_int++; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "a monster", MENU_UNSELECTED); any.a_int++; Sprintf(buf, "the %s", surface(cc.x, cc.y)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); end_menu(tmpwin, "Aim for what?"); tohit = rn2(4); if (select_menu(tmpwin, PICK_ONE, &selected) > 0 && rn2(P_SKILL(typ) > P_SKILLED ? 20 : 2)) tohit = selected[0].item.a_int - 1; free((genericptr_t)selected); destroy_nhwindow(tmpwin); } /* What did you hit? */ switch (tohit) { case 0: /* Trap */ /* FIXME -- untrap needs to deal with non-adjacent traps */ break; case 1: /* Object */ if ((otmp = level.objects[cc.x][cc.y]) != 0) { You("snag an object from the %s!", surface(cc.x, cc.y)); (void) pickup_object(otmp, 1L, FALSE); /* If pickup fails, leave it alone */ newsym(cc.x, cc.y); return (1); } break; case 2: /* Monster */ if ((mtmp = m_at(cc.x, cc.y)) == (struct monst *)0) break; if (verysmall(mtmp->data) && !rn2(4) && enexto(&cc, u.ux, u.uy, (struct permonst *)0)) { You("pull in %s!", mon_nam(mtmp)); mtmp->mundetected = 0; rloc_to(mtmp, cc.x, cc.y); return (1); } else if ((!bigmonst(mtmp->data) && !strongmonst(mtmp->data)) || rn2(4)) { (void) thitmonst(mtmp, uwep); return (1); } /* FALL THROUGH */ case 3: /* Surface */ if (IS_AIR(levl[cc.x][cc.y].typ) || is_pool(cc.x, cc.y)) pline_The("hook slices through the %s.", surface(cc.x, cc.y)); else { You("are yanked toward the %s!", surface(cc.x, cc.y)); hurtle(sgn(cc.x-u.ux), sgn(cc.y-u.uy), 1, FALSE); spoteffects(TRUE); } return (1); default: /* Yourself (oops!) */ if (P_SKILL(typ) <= P_BASIC) { You("hook yourself!"); losehp(rn1(10,10), "a grappling hook", KILLED_BY); return (1); } break; } pline(nothing_happens); return (1); } #define BY_OBJECT ((struct monst *)0) /* return 1 if the wand is broken, hence some time elapsed */ STATIC_OVL int do_break_wand(obj) struct obj *obj; { static const char nothing_else_happens[] = "But nothing else happens..."; register int i, x, y; register struct monst *mon; int dmg, damage; boolean affects_objects; boolean shop_damage = FALSE; int expltype = EXPL_MAGICAL; char confirm[QBUFSZ], the_wand[BUFSZ], buf[BUFSZ]; Strcpy(the_wand, yname(obj)); Sprintf(confirm, "Are you really sure you want to break %s?", safe_qbuf("", sizeof("Are you really sure you want to break ?"), the_wand, ysimple_name(obj), "the wand")); if (yn(confirm) == 'n' ) return 0; if (nohands(youmonst.data)) { You_cant("break %s without hands!", the_wand); return 0; } else if (ACURR(A_STR) < 10) { You("don't have the strength to break %s!", the_wand); return 0; } pline("Raising %s high above your %s, you break it in two!", the_wand, body_part(HEAD)); /* [ALI] Do this first so that wand is removed from bill. Otherwise, * the freeinv() below also hides it from setpaid() which causes problems. */ if (obj->unpaid) { check_unpaid(obj); /* Extra charge for use */ bill_dummy_object(obj); } current_wand = obj; /* destroy_item might reset this */ freeinv(obj); /* hide it from destroy_item instead... */ setnotworn(obj); /* so we need to do this ourselves */ if (obj->spe <= 0) { pline(nothing_else_happens); goto discard_broken_wand; } obj->ox = u.ux; obj->oy = u.uy; dmg = obj->spe * 4; affects_objects = FALSE; switch (obj->otyp) { case WAN_WISHING: case WAN_NOTHING: case WAN_LOCKING: case WAN_PROBING: case WAN_ENLIGHTENMENT: case WAN_OPENING: case WAN_SECRET_DOOR_DETECTION: pline(nothing_else_happens); goto discard_broken_wand; case WAN_DEATH: case WAN_LIGHTNING: dmg *= 4; goto wanexpl; case WAN_FIRE: expltype = EXPL_FIERY; case WAN_COLD: if (expltype == EXPL_MAGICAL) expltype = EXPL_FROSTY; dmg *= 2; case WAN_MAGIC_MISSILE: wanexpl: explode(u.ux, u.uy, (obj->otyp - WAN_MAGIC_MISSILE), dmg, WAND_CLASS, expltype); makeknown(obj->otyp); /* explode described the effect */ goto discard_broken_wand; case WAN_STRIKING: /* we want this before the explosion instead of at the very end */ pline("A wall of force smashes down around you!"); dmg = d(1 + obj->spe,6); /* normally 2d12 */ case WAN_CANCELLATION: case WAN_POLYMORPH: case WAN_TELEPORTATION: case WAN_UNDEAD_TURNING: affects_objects = TRUE; break; default: break; } /* magical explosion and its visual effect occur before specific effects */ explode(obj->ox, obj->oy, 0, rnd(dmg), WAND_CLASS, EXPL_MAGICAL); /* this makes it hit us last, so that we can see the action first */ for (i = 0; i <= 8; i++) { bhitpos.x = x = obj->ox + xdir[i]; bhitpos.y = y = obj->oy + ydir[i]; if (!isok(x,y)) continue; if (obj->otyp == WAN_DIGGING) { if(dig_check(BY_OBJECT, FALSE, x, y)) { if (IS_WALL(levl[x][y].typ) || IS_DOOR(levl[x][y].typ)) { /* normally, pits and holes don't anger guards, but they * do if it's a wall or door that's being dug */ watch_dig((struct monst *)0, x, y, TRUE); if (*in_rooms(x,y,SHOPBASE)) shop_damage = TRUE; } digactualhole(x, y, BY_OBJECT, (rn2(obj->spe) < 3 || !Can_dig_down(&u.uz)) ? PIT : HOLE); } continue; } else if(obj->otyp == WAN_CREATE_MONSTER) { /* u.ux,u.uy creates it near you--x,y might create it in rock */ (void) makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS); continue; } else { if (x == u.ux && y == u.uy) { /* teleport objects first to avoid race with tele control and autopickup. Other wand/object effects handled after possible wand damage is assessed */ if (obj->otyp == WAN_TELEPORTATION && affects_objects && level.objects[x][y]) { (void) bhitpile(obj, bhito, x, y); if (flags.botl) bot(); /* potion effects */ } damage = zapyourself(obj, FALSE); if (damage) { Sprintf(buf, "killed %sself by breaking a wand", uhim()); losehp(damage, buf, NO_KILLER_PREFIX); } if (flags.botl) bot(); /* blindness */ } else if ((mon = m_at(x, y)) != 0) { (void) bhitm(mon, obj); /* if (flags.botl) bot(); */ } if (affects_objects && level.objects[x][y]) { (void) bhitpile(obj, bhito, x, y); if (flags.botl) bot(); /* potion effects */ } } } /* Note: if player fell thru, this call is a no-op. Damage is handled in digactualhole in that case */ if (shop_damage) pay_for_damage("dig into", FALSE); if (obj->otyp == WAN_LIGHT) litroom(TRUE, obj); /* only needs to be done once */ discard_broken_wand: obj = current_wand; /* [see dozap() and destroy_item()] */ current_wand = 0; if (obj) delobj(obj); nomul(0); return 1; } STATIC_OVL boolean uhave_graystone() { register struct obj *otmp; for(otmp = invent; otmp; otmp = otmp->nobj) if(is_graystone(otmp)) return TRUE; return FALSE; } STATIC_OVL void add_class(cl, class) char *cl; char class; { char tmp[2]; tmp[0] = class; tmp[1] = '\0'; Strcat(cl, tmp); } int doapply() { struct obj *obj; register int res = 1; char class_list[MAXOCLASSES+2]; if(check_capacity((char *)0)) return (0); if (carrying(POT_OIL) || uhave_graystone()) Strcpy(class_list, tools_too); else Strcpy(class_list, tools); if (carrying(CREAM_PIE) || carrying(EUCALYPTUS_LEAF)) add_class(class_list, FOOD_CLASS); obj = getobj(class_list, "use or apply"); if(!obj) return 0; if (obj->oartifact && !touch_artifact(obj, &youmonst)) return 1; /* evading your grasp costs a turn; just be grateful that you don't drop it as well */ if (obj->oclass == WAND_CLASS) return do_break_wand(obj); switch(obj->otyp){ case BLINDFOLD: case LENSES: if (obj == ublindf) { if (!cursed(obj)) Blindf_off(obj); } else if (!ublindf) Blindf_on(obj); else You("are already %s.", ublindf->otyp == TOWEL ? "covered by a towel" : ublindf->otyp == BLINDFOLD ? "wearing a blindfold" : "wearing lenses"); break; case CREAM_PIE: res = use_cream_pie(obj); break; case BULLWHIP: res = use_whip(obj); break; case GRAPPLING_HOOK: res = use_grapple(obj); break; case LARGE_BOX: case CHEST: case ICE_BOX: case SACK: case BAG_OF_HOLDING: case OILSKIN_SACK: res = use_container(obj, 1); break; case BAG_OF_TRICKS: bagotricks(obj); break; case CAN_OF_GREASE: use_grease(obj); break; case LOCK_PICK: #ifdef TOURIST case CREDIT_CARD: #endif case SKELETON_KEY: (void) pick_lock(obj); break; case PICK_AXE: case DWARVISH_MATTOCK: res = use_pick_axe(obj); break; case TINNING_KIT: use_tinning_kit(obj); break; case LEASH: use_leash(obj); break; #ifdef STEED case SADDLE: res = use_saddle(obj); break; #endif case MAGIC_WHISTLE: use_magic_whistle(obj); break; case TIN_WHISTLE: use_whistle(obj); break; case EUCALYPTUS_LEAF: /* MRKR: Every Australian knows that a gum leaf makes an */ /* excellent whistle, especially if your pet is a */ /* tame kangaroo named Skippy. */ if (obj->blessed) { use_magic_whistle(obj); /* sometimes the blessing will be worn off */ if (!rn2(49)) { if (!Blind) { char buf[BUFSZ]; pline("%s %s %s.", Shk_Your(buf, obj), aobjnam(obj, "glow"), hcolor("brown")); obj->bknown = 1; } unbless(obj); } } else { use_whistle(obj); } break; case STETHOSCOPE: res = use_stethoscope(obj); break; case MIRROR: res = use_mirror(obj); break; case BELL: case BELL_OF_OPENING: use_bell(&obj); break; case CANDELABRUM_OF_INVOCATION: use_candelabrum(obj); break; case WAX_CANDLE: case TALLOW_CANDLE: use_candle(&obj); break; case OIL_LAMP: case MAGIC_LAMP: case BRASS_LANTERN: use_lamp(obj); break; case POT_OIL: light_cocktail(obj); break; #ifdef TOURIST case EXPENSIVE_CAMERA: res = use_camera(obj); break; #endif case TOWEL: res = use_towel(obj); break; case CRYSTAL_BALL: use_crystal_ball(obj); break; case MAGIC_MARKER: res = dowrite(obj); break; case TIN_OPENER: if(!carrying(TIN)) { You("have no tin to open."); goto xit; } You("cannot open a tin without eating or discarding its contents."); if(flags.verbose) pline("In order to eat, use the 'e' command."); if(obj != uwep) pline("Opening the tin will be much easier if you wield the tin opener."); goto xit; case FIGURINE: use_figurine(&obj); break; case UNICORN_HORN: use_unicorn_horn(obj); break; case WOODEN_FLUTE: case MAGIC_FLUTE: case TOOLED_HORN: case FROST_HORN: case FIRE_HORN: case WOODEN_HARP: case MAGIC_HARP: case BUGLE: case LEATHER_DRUM: case DRUM_OF_EARTHQUAKE: res = do_play_instrument(obj); break; case HORN_OF_PLENTY: /* not a musical instrument */ if (obj->spe > 0) { struct obj *otmp; const char *what; consume_obj_charge(obj, TRUE); if (!rn2(13)) { otmp = mkobj(POTION_CLASS, FALSE); if (objects[otmp->otyp].oc_magic) do { otmp->otyp = rnd_class(POT_BOOZE, POT_WATER); } while (otmp->otyp == POT_SICKNESS); what = "A potion"; } else { otmp = mkobj(FOOD_CLASS, FALSE); if (otmp->otyp == FOOD_RATION && !rn2(7)) otmp->otyp = LUMP_OF_ROYAL_JELLY; what = "Some food"; } pline("%s spills out.", what); otmp->blessed = obj->blessed; otmp->cursed = obj->cursed; otmp->owt = weight(otmp); otmp = hold_another_object(otmp, u.uswallow ? "Oops! %s out of your reach!" : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || levl[u.ux][u.uy].typ < IRONBARS || levl[u.ux][u.uy].typ >= ICE) ? "Oops! %s away from you!" : "Oops! %s to the floor!", The(aobjnam(otmp, "slip")), (const char *)0); makeknown(HORN_OF_PLENTY); } else pline(nothing_happens); break; case LAND_MINE: case BEARTRAP: use_trap(obj); break; case FLINT: case LUCKSTONE: case LOADSTONE: case TOUCHSTONE: use_stone(obj); break; default: /* Pole-weapons can strike at a distance */ if (is_pole(obj)) { res = use_pole(obj); break; } else if (is_pick(obj) || is_axe(obj)) { res = use_pick_axe(obj); break; } pline("Sorry, I don't know how to use that."); xit: nomul(0); return 0; } if (res && obj && obj->oartifact) arti_speak(obj); nomul(0); return res; } /* Keep track of unfixable troubles for purposes of messages saying you feel * great. */ int unfixable_trouble_count(is_horn) boolean is_horn; { int unfixable_trbl = 0; if (Stoned) unfixable_trbl++; if (Strangled) unfixable_trbl++; if (Wounded_legs #ifdef STEED && !u.usteed #endif ) unfixable_trbl++; if (Slimed) unfixable_trbl++; /* lycanthropy is not desirable, but it doesn't actually make you feel bad */ /* we'll assume that intrinsic stunning from being a bat/stalker doesn't make you feel bad */ if (!is_horn) { if (Confusion) unfixable_trbl++; if (Sick) unfixable_trbl++; if (HHallucination) unfixable_trbl++; if (Vomiting) unfixable_trbl++; if (HStun) unfixable_trbl++; } return unfixable_trbl; } #endif /* OVLB */ /*apply.c*/ nethack-3.4.3/src/artifact.c0100644000000000000000000012330407764735041014405 0ustar rootroot/* SCCS Id: @(#)artifact.c 3.4 2003/08/11 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "artifact.h" #ifdef OVLB #include "artilist.h" #else STATIC_DCL struct artifact artilist[]; #endif /* * Note: both artilist[] and artiexist[] have a dummy element #0, * so loops over them should normally start at #1. The primary * exception is the save & restore code, which doesn't care about * the contents, just the total size. */ extern boolean notonhead; /* for long worms */ #define get_artifact(o) \ (((o)&&(o)->oartifact) ? &artilist[(int) (o)->oartifact] : 0) STATIC_DCL int FDECL(spec_applies, (const struct artifact *,struct monst *)); STATIC_DCL int FDECL(arti_invoke, (struct obj*)); STATIC_DCL boolean FDECL(Mb_hit, (struct monst *magr,struct monst *mdef, struct obj *,int *,int,BOOLEAN_P,char *)); /* The amount added to the victim's total hit points to insure that the victim will be killed even after damage bonus/penalty adjustments. Most such penalties are small, and 200 is plenty; the exception is half physical damage. 3.3.1 and previous versions tried to use a very large number to account for this case; now, we just compute the fatal damage by adding it to 2 times the total hit points instead of 1 time. Note: this will still break if they have more than about half the number of hit points that will fit in a 15 bit integer. */ #define FATAL_DAMAGE_MODIFIER 200 #ifndef OVLB STATIC_DCL int spec_dbon_applies; STATIC_DCL xchar artidisco[NROFARTIFACTS]; #else /* OVLB */ /* coordinate effects from spec_dbon() with messages in artifact_hit() */ STATIC_OVL int spec_dbon_applies = 0; /* flags including which artifacts have already been created */ static boolean artiexist[1+NROFARTIFACTS+1]; /* and a discovery list for them (no dummy first entry here) */ STATIC_OVL xchar artidisco[NROFARTIFACTS]; STATIC_DCL void NDECL(hack_artifacts); STATIC_DCL boolean FDECL(attacks, (int,struct obj *)); /* handle some special cases; must be called after u_init() */ STATIC_OVL void hack_artifacts() { struct artifact *art; int alignmnt = aligns[flags.initalign].value; /* Fix up the alignments of "gift" artifacts */ for (art = artilist+1; art->otyp; art++) if (art->role == Role_switch && art->alignment != A_NONE) art->alignment = alignmnt; /* Excalibur can be used by any lawful character, not just knights */ if (!Role_if(PM_KNIGHT)) artilist[ART_EXCALIBUR].role = NON_PM; /* Fix up the quest artifact */ if (urole.questarti) { artilist[urole.questarti].alignment = alignmnt; artilist[urole.questarti].role = Role_switch; } return; } /* zero out the artifact existence list */ void init_artifacts() { (void) memset((genericptr_t) artiexist, 0, sizeof artiexist); (void) memset((genericptr_t) artidisco, 0, sizeof artidisco); hack_artifacts(); } void save_artifacts(fd) int fd; { bwrite(fd, (genericptr_t) artiexist, sizeof artiexist); bwrite(fd, (genericptr_t) artidisco, sizeof artidisco); } void restore_artifacts(fd) int fd; { mread(fd, (genericptr_t) artiexist, sizeof artiexist); mread(fd, (genericptr_t) artidisco, sizeof artidisco); hack_artifacts(); /* redo non-saved special cases */ } const char * artiname(artinum) int artinum; { if (artinum <= 0 || artinum > NROFARTIFACTS) return(""); return(artilist[artinum].name); } /* Make an artifact. If a specific alignment is specified, then an object of the appropriate alignment is created from scratch, or 0 is returned if none is available. (If at least one aligned artifact has already been given, then unaligned ones also become eligible for this.) If no alignment is given, then 'otmp' is converted into an artifact of matching type, or returned as-is if that's not possible. For the 2nd case, caller should use ``obj = mk_artifact(obj, A_NONE);'' for the 1st, ``obj = mk_artifact((struct obj *)0, some_alignment);''. */ struct obj * mk_artifact(otmp, alignment) struct obj *otmp; /* existing object; ignored if alignment specified */ aligntyp alignment; /* target alignment, or A_NONE */ { const struct artifact *a; int n, m; boolean by_align = (alignment != A_NONE); short o_typ = (by_align || !otmp) ? 0 : otmp->otyp; boolean unique = !by_align && otmp && objects[o_typ].oc_unique; short eligible[NROFARTIFACTS]; /* gather eligible artifacts */ for (n = 0, a = artilist+1, m = 1; a->otyp; a++, m++) if ((!by_align ? a->otyp == o_typ : (a->alignment == alignment || (a->alignment == A_NONE && u.ugifts > 0))) && (!(a->spfx & SPFX_NOGEN) || unique) && !artiexist[m]) { if (by_align && a->race != NON_PM && race_hostile(&mons[a->race])) continue; /* skip enemies' equipment */ else if (by_align && Role_if(a->role)) goto make_artif; /* 'a' points to the desired one */ else eligible[n++] = m; } if (n) { /* found at least one candidate */ m = eligible[rn2(n)]; /* [0..n-1] */ a = &artilist[m]; /* make an appropriate object if necessary, then christen it */ make_artif: if (by_align) otmp = mksobj((int)a->otyp, TRUE, FALSE); otmp = oname(otmp, a->name); otmp->oartifact = m; artiexist[m] = TRUE; } else { /* nothing appropriate could be found; return the original object */ if (by_align) otmp = 0; /* (there was no original object) */ } return otmp; } /* * Returns the full name (with articles and correct capitalization) of an * artifact named "name" if one exists, or NULL, it not. * The given name must be rather close to the real name for it to match. * The object type of the artifact is returned in otyp if the return value * is non-NULL. */ const char* artifact_name(name, otyp) const char *name; short *otyp; { register const struct artifact *a; register const char *aname; if(!strncmpi(name, "the ", 4)) name += 4; for (a = artilist+1; a->otyp; a++) { aname = a->name; if(!strncmpi(aname, "the ", 4)) aname += 4; if(!strcmpi(name, aname)) { *otyp = a->otyp; return a->name; } } return (char *)0; } boolean exist_artifact(otyp, name) register int otyp; register const char *name; { register const struct artifact *a; register boolean *arex; if (otyp && *name) for (a = artilist+1,arex = artiexist+1; a->otyp; a++,arex++) if ((int) a->otyp == otyp && !strcmp(a->name, name)) return *arex; return FALSE; } void artifact_exists(otmp, name, mod) register struct obj *otmp; register const char *name; register boolean mod; { register const struct artifact *a; if (otmp && *name) for (a = artilist+1; a->otyp; a++) if (a->otyp == otmp->otyp && !strcmp(a->name, name)) { register int m = a - artilist; otmp->oartifact = (char)(mod ? m : 0); otmp->age = 0; if(otmp->otyp == RIN_INCREASE_DAMAGE) otmp->spe = 0; artiexist[m] = mod; break; } return; } int nartifact_exist() { int a = 0; int n = SIZE(artiexist); while(n > 1) if(artiexist[--n]) a++; return a; } #endif /* OVLB */ #ifdef OVL0 boolean spec_ability(otmp, abil) struct obj *otmp; unsigned long abil; { const struct artifact *arti = get_artifact(otmp); return((boolean)(arti && (arti->spfx & abil))); } /* used so that callers don't need to known about SPFX_ codes */ boolean confers_luck(obj) struct obj *obj; { /* might as well check for this too */ if (obj->otyp == LUCKSTONE) return TRUE; return (obj->oartifact && spec_ability(obj, SPFX_LUCK)); } /* used to check whether a monster is getting reflection from an artifact */ boolean arti_reflects(obj) struct obj *obj; { const struct artifact *arti = get_artifact(obj); if (arti) { /* while being worn */ if ((obj->owornmask & ~W_ART) && (arti->spfx & SPFX_REFLECT)) return TRUE; /* just being carried */ if (arti->cspfx & SPFX_REFLECT) return TRUE; } return FALSE; } #endif /* OVL0 */ #ifdef OVLB boolean restrict_name(otmp, name) /* returns 1 if name is restricted for otmp->otyp */ register struct obj *otmp; register const char *name; { register const struct artifact *a; register const char *aname; if (!*name) return FALSE; if (!strncmpi(name, "the ", 4)) name += 4; /* Since almost every artifact is SPFX_RESTR, it doesn't cost us much to do the string comparison before the spfx check. Bug fix: don't name multiple elven daggers "Sting". */ for (a = artilist+1; a->otyp; a++) { if (a->otyp != otmp->otyp) continue; aname = a->name; if (!strncmpi(aname, "the ", 4)) aname += 4; if (!strcmp(aname, name)) return ((boolean)((a->spfx & (SPFX_NOGEN|SPFX_RESTR)) != 0 || otmp->quan > 1L)); } return FALSE; } STATIC_OVL boolean attacks(adtyp, otmp) register int adtyp; register struct obj *otmp; { register const struct artifact *weap; if ((weap = get_artifact(otmp)) != 0) return((boolean)(weap->attk.adtyp == adtyp)); return FALSE; } boolean defends(adtyp, otmp) register int adtyp; register struct obj *otmp; { register const struct artifact *weap; if ((weap = get_artifact(otmp)) != 0) return((boolean)(weap->defn.adtyp == adtyp)); return FALSE; } /* used for monsters */ boolean protects(adtyp, otmp) int adtyp; struct obj *otmp; { register const struct artifact *weap; if ((weap = get_artifact(otmp)) != 0) return (boolean)(weap->cary.adtyp == adtyp); return FALSE; } /* * a potential artifact has just been worn/wielded/picked-up or * unworn/unwielded/dropped. Pickup/drop only set/reset the W_ART mask. */ void set_artifact_intrinsic(otmp,on,wp_mask) register struct obj *otmp; boolean on; long wp_mask; { long *mask = 0; register const struct artifact *oart = get_artifact(otmp); uchar dtyp; long spfx; if (!oart) return; /* effects from the defn field */ dtyp = (wp_mask != W_ART) ? oart->defn.adtyp : oart->cary.adtyp; if (dtyp == AD_FIRE) mask = &EFire_resistance; else if (dtyp == AD_COLD) mask = &ECold_resistance; else if (dtyp == AD_ELEC) mask = &EShock_resistance; else if (dtyp == AD_MAGM) mask = &EAntimagic; else if (dtyp == AD_DISN) mask = &EDisint_resistance; else if (dtyp == AD_DRST) mask = &EPoison_resistance; if (mask && wp_mask == W_ART && !on) { /* find out if some other artifact also confers this intrinsic */ /* if so, leave the mask alone */ register struct obj* obj; for(obj = invent; obj; obj = obj->nobj) if(obj != otmp && obj->oartifact) { register const struct artifact *art = get_artifact(obj); if(art->cary.adtyp == dtyp) { mask = (long *) 0; break; } } } if (mask) { if (on) *mask |= wp_mask; else *mask &= ~wp_mask; } /* intrinsics from the spfx field; there could be more than one */ spfx = (wp_mask != W_ART) ? oart->spfx : oart->cspfx; if(spfx && wp_mask == W_ART && !on) { /* don't change any spfx also conferred by other artifacts */ register struct obj* obj; for(obj = invent; obj; obj = obj->nobj) if(obj != otmp && obj->oartifact) { register const struct artifact *art = get_artifact(obj); spfx &= ~art->cspfx; } } if (spfx & SPFX_SEARCH) { if(on) ESearching |= wp_mask; else ESearching &= ~wp_mask; } if (spfx & SPFX_HALRES) { /* make_hallucinated must (re)set the mask itself to get * the display right */ /* restoring needed because this is the only artifact intrinsic * that can print a message--need to guard against being printed * when restoring a game */ (void) make_hallucinated((long)!on, restoring ? FALSE : TRUE, wp_mask); } if (spfx & SPFX_ESP) { if(on) ETelepat |= wp_mask; else ETelepat &= ~wp_mask; see_monsters(); } if (spfx & SPFX_STLTH) { if (on) EStealth |= wp_mask; else EStealth &= ~wp_mask; } if (spfx & SPFX_REGEN) { if (on) ERegeneration |= wp_mask; else ERegeneration &= ~wp_mask; } if (spfx & SPFX_TCTRL) { if (on) ETeleport_control |= wp_mask; else ETeleport_control &= ~wp_mask; } if (spfx & SPFX_WARN) { if (spec_m2(otmp)) { if (on) { EWarn_of_mon |= wp_mask; flags.warntype |= spec_m2(otmp); } else { EWarn_of_mon &= ~wp_mask; flags.warntype &= ~spec_m2(otmp); } see_monsters(); } else { if (on) EWarning |= wp_mask; else EWarning &= ~wp_mask; } } if (spfx & SPFX_EREGEN) { if (on) EEnergy_regeneration |= wp_mask; else EEnergy_regeneration &= ~wp_mask; } if (spfx & SPFX_HSPDAM) { if (on) EHalf_spell_damage |= wp_mask; else EHalf_spell_damage &= ~wp_mask; } if (spfx & SPFX_HPHDAM) { if (on) EHalf_physical_damage |= wp_mask; else EHalf_physical_damage &= ~wp_mask; } if (spfx & SPFX_XRAY) { /* this assumes that no one else is using xray_range */ if (on) u.xray_range = 3; else u.xray_range = -1; vision_full_recalc = 1; } if ((spfx & SPFX_REFLECT) && (wp_mask & W_WEP)) { if (on) EReflecting |= wp_mask; else EReflecting &= ~wp_mask; } if(wp_mask == W_ART && !on && oart->inv_prop) { /* might have to turn off invoked power too */ if (oart->inv_prop <= LAST_PROP && (u.uprops[oart->inv_prop].extrinsic & W_ARTI)) (void) arti_invoke(otmp); } } /* * creature (usually player) tries to touch (pick up or wield) an artifact obj. * Returns 0 if the object refuses to be touched. * This routine does not change any object chains. * Ignores such things as gauntlets, assuming the artifact is not * fooled by such trappings. */ int touch_artifact(obj,mon) struct obj *obj; struct monst *mon; { register const struct artifact *oart = get_artifact(obj); boolean badclass, badalign, self_willed, yours; if(!oart) return 1; yours = (mon == &youmonst); /* all quest artifacts are self-willed; it this ever changes, `badclass' will have to be extended to explicitly include quest artifacts */ self_willed = ((oart->spfx & SPFX_INTEL) != 0); if (yours) { badclass = self_willed && ((oart->role != NON_PM && !Role_if(oart->role)) || (oart->race != NON_PM && !Race_if(oart->race))); badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE && (oart->alignment != u.ualign.type || u.ualign.record < 0); } else if (!is_covetous(mon->data) && !is_mplayer(mon->data)) { badclass = self_willed && oart->role != NON_PM && oart != &artilist[ART_EXCALIBUR]; badalign = (oart->spfx & SPFX_RESTR) && oart->alignment != A_NONE && (oart->alignment != sgn(mon->data->maligntyp)); } else { /* an M3_WANTSxxx monster or a fake player */ /* special monsters trying to take the Amulet, invocation tools or quest item can touch anything except for `spec_applies' artifacts */ badclass = badalign = FALSE; } /* weapons which attack specific categories of monsters are bad for them even if their alignments happen to match */ if (!badalign && (oart->spfx & SPFX_DBONUS) != 0) { struct artifact tmp; tmp = *oart; tmp.spfx &= SPFX_DBONUS; badalign = !!spec_applies(&tmp, mon); } if (((badclass || badalign) && self_willed) || (badalign && (!yours || !rn2(4)))) { int dmg; char buf[BUFSZ]; if (!yours) return 0; You("are blasted by %s power!", s_suffix(the(xname(obj)))); dmg = d((Antimagic ? 2 : 4), (self_willed ? 10 : 4)); Sprintf(buf, "touching %s", oart->name); losehp(dmg, buf, KILLED_BY); exercise(A_WIS, FALSE); } /* can pick it up unless you're totally non-synch'd with the artifact */ if (badclass && badalign && self_willed) { if (yours) pline("%s your grasp!", Tobjnam(obj, "evade")); return 0; } return 1; } #endif /* OVLB */ #ifdef OVL1 /* decide whether an artifact's special attacks apply against mtmp */ STATIC_OVL int spec_applies(weap, mtmp) register const struct artifact *weap; struct monst *mtmp; { struct permonst *ptr; boolean yours; if(!(weap->spfx & (SPFX_DBONUS | SPFX_ATTK))) return(weap->attk.adtyp == AD_PHYS); yours = (mtmp == &youmonst); ptr = mtmp->data; if (weap->spfx & SPFX_DMONS) { return (ptr == &mons[(int)weap->mtype]); } else if (weap->spfx & SPFX_DCLAS) { return (weap->mtype == (unsigned long)ptr->mlet); } else if (weap->spfx & SPFX_DFLAG1) { return ((ptr->mflags1 & weap->mtype) != 0L); } else if (weap->spfx & SPFX_DFLAG2) { return ((ptr->mflags2 & weap->mtype) || (yours && ((!Upolyd && (urace.selfmask & weap->mtype)) || ((weap->mtype & M2_WERE) && u.ulycn >= LOW_PM)))); } else if (weap->spfx & SPFX_DALIGN) { return yours ? (u.ualign.type != weap->alignment) : (ptr->maligntyp == A_NONE || sgn(ptr->maligntyp) != weap->alignment); } else if (weap->spfx & SPFX_ATTK) { struct obj *defending_weapon = (yours ? uwep : MON_WEP(mtmp)); if (defending_weapon && defending_weapon->oartifact && defends((int)weap->attk.adtyp, defending_weapon)) return FALSE; switch(weap->attk.adtyp) { case AD_FIRE: return !(yours ? Fire_resistance : resists_fire(mtmp)); case AD_COLD: return !(yours ? Cold_resistance : resists_cold(mtmp)); case AD_ELEC: return !(yours ? Shock_resistance : resists_elec(mtmp)); case AD_MAGM: case AD_STUN: return !(yours ? Antimagic : (rn2(100) < ptr->mr)); case AD_DRST: return !(yours ? Poison_resistance : resists_poison(mtmp)); case AD_DRLI: return !(yours ? Drain_resistance : resists_drli(mtmp)); case AD_STON: return !(yours ? Stone_resistance : resists_ston(mtmp)); default: impossible("Weird weapon special attack."); } } return(0); } /* return the M2 flags of monster that an artifact's special attacks apply against */ long spec_m2(otmp) struct obj *otmp; { register const struct artifact *artifact = get_artifact(otmp); if (artifact) return artifact->mtype; return 0L; } /* special attack bonus */ int spec_abon(otmp, mon) struct obj *otmp; struct monst *mon; { register const struct artifact *weap = get_artifact(otmp); /* no need for an extra check for `NO_ATTK' because this will always return 0 for any artifact which has that attribute */ if (weap && weap->attk.damn && spec_applies(weap, mon)) return rnd((int)weap->attk.damn); return 0; } /* special damage bonus */ int spec_dbon(otmp, mon, tmp) struct obj *otmp; struct monst *mon; int tmp; { register const struct artifact *weap = get_artifact(otmp); if (!weap || (weap->attk.adtyp == AD_PHYS && /* check for `NO_ATTK' */ weap->attk.damn == 0 && weap->attk.damd == 0)) spec_dbon_applies = FALSE; else spec_dbon_applies = spec_applies(weap, mon); if (spec_dbon_applies) return weap->attk.damd ? rnd((int)weap->attk.damd) : max(tmp,1); return 0; } /* add identified artifact to discoveries list */ void discover_artifact(m) xchar m; { int i; /* look for this artifact in the discoveries list; if we hit an empty slot then it's not present, so add it */ for (i = 0; i < NROFARTIFACTS; i++) if (artidisco[i] == 0 || artidisco[i] == m) { artidisco[i] = m; return; } /* there is one slot per artifact, so we should never reach the end without either finding the artifact or an empty slot... */ impossible("couldn't discover artifact (%d)", (int)m); } /* used to decide whether an artifact has been fully identified */ boolean undiscovered_artifact(m) xchar m; { int i; /* look for this artifact in the discoveries list; if we hit an empty slot then it's undiscovered */ for (i = 0; i < NROFARTIFACTS; i++) if (artidisco[i] == m) return FALSE; else if (artidisco[i] == 0) break; return TRUE; } /* display a list of discovered artifacts; return their count */ int disp_artifact_discoveries(tmpwin) winid tmpwin; /* supplied by dodiscover() */ { int i, m, otyp; char buf[BUFSZ]; for (i = 0; i < NROFARTIFACTS; i++) { if (artidisco[i] == 0) break; /* empty slot implies end of list */ if (i == 0) putstr(tmpwin, iflags.menu_headings, "Artifacts"); m = artidisco[i]; otyp = artilist[m].otyp; Sprintf(buf, " %s [%s %s]", artiname(m), align_str(artilist[m].alignment), simple_typename(otyp)); putstr(tmpwin, 0, buf); } return i; } #endif /* OVL1 */ #ifdef OVLB /* * Magicbane's intrinsic magic is incompatible with normal * enchantment magic. Thus, its effects have a negative * dependence on spe. Against low mr victims, it typically * does "double athame" damage, 2d4. Occasionally, it will * cast unbalancing magic which effectively averages out to * 4d4 damage (3d4 against high mr victims), for spe = 0. * * Prior to 3.4.1, the cancel (aka purge) effect always * included the scare effect too; now it's one or the other. * Likewise, the stun effect won't be combined with either * of those two; it will be chosen separately or possibly * used as a fallback when scare or cancel fails. * * [Historical note: a change to artifact_hit() for 3.4.0 * unintentionally made all of Magicbane's special effects * be blocked if the defender successfully saved against a * stun attack. As of 3.4.1, those effects can occur but * will be slightly less likely than they were in 3.3.x.] */ #define MB_MAX_DIEROLL 8 /* rolls above this aren't magical */ static const char * const mb_verb[2][4] = { { "probe", "stun", "scare", "cancel" }, { "prod", "amaze", "tickle", "purge" }, }; #define MB_INDEX_PROBE 0 #define MB_INDEX_STUN 1 #define MB_INDEX_SCARE 2 #define MB_INDEX_CANCEL 3 /* called when someone is being hit by Magicbane */ STATIC_OVL boolean Mb_hit(magr, mdef, mb, dmgptr, dieroll, vis, hittee) struct monst *magr, *mdef; /* attacker and defender */ struct obj *mb; /* Magicbane */ int *dmgptr; /* extra damage target will suffer */ int dieroll; /* d20 that has already scored a hit */ boolean vis; /* whether the action can be seen */ char *hittee; /* target's name: "you" or mon_nam(mdef) */ { struct permonst *old_uasmon; const char *verb; boolean youattack = (magr == &youmonst), youdefend = (mdef == &youmonst), resisted = FALSE, do_stun, do_confuse, result; int attack_indx, scare_dieroll = MB_MAX_DIEROLL / 2; result = FALSE; /* no message given yet */ /* the most severe effects are less likely at higher enchantment */ if (mb->spe >= 3) scare_dieroll /= (1 << (mb->spe / 3)); /* if target successfully resisted the artifact damage bonus, reduce overall likelihood of the assorted special effects */ if (!spec_dbon_applies) dieroll += 1; /* might stun even when attempting a more severe effect, but in that case it will only happen if the other effect fails; extra damage will apply regardless; 3.4.1: sometimes might just probe even when it hasn't been enchanted */ do_stun = (max(mb->spe,0) < rn2(spec_dbon_applies ? 11 : 7)); /* the special effects also boost physical damage; increments are generally cumulative, but since the stun effect is based on a different criterium its damage might not be included; the base damage is either 1d4 (athame) or 2d4 (athame+spec_dbon) depending on target's resistance check against AD_STUN (handled by caller) [note that a successful save against AD_STUN doesn't actually prevent the target from ending up stunned] */ attack_indx = MB_INDEX_PROBE; *dmgptr += rnd(4); /* (2..3)d4 */ if (do_stun) { attack_indx = MB_INDEX_STUN; *dmgptr += rnd(4); /* (3..4)d4 */ } if (dieroll <= scare_dieroll) { attack_indx = MB_INDEX_SCARE; *dmgptr += rnd(4); /* (3..5)d4 */ } if (dieroll <= (scare_dieroll / 2)) { attack_indx = MB_INDEX_CANCEL; *dmgptr += rnd(4); /* (4..6)d4 */ } /* give the hit message prior to inflicting the effects */ verb = mb_verb[!!Hallucination][attack_indx]; if (youattack || youdefend || vis) { result = TRUE; pline_The("magic-absorbing blade %s %s!", vtense((const char *)0, verb), hittee); /* assume probing has some sort of noticeable feedback even if it is being done by one monster to another */ if (attack_indx == MB_INDEX_PROBE && !canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); } /* now perform special effects */ switch (attack_indx) { case MB_INDEX_CANCEL: old_uasmon = youmonst.data; /* No mdef->mcan check: even a cancelled monster can be polymorphed * into a golem, and the "cancel" effect acts as if some magical * energy remains in spellcasting defenders to be absorbed later. */ if (!cancel_monst(mdef, mb, youattack, FALSE, FALSE)) { resisted = TRUE; } else { do_stun = FALSE; if (youdefend) { if (youmonst.data != old_uasmon) *dmgptr = 0; /* rehumanized, so no more damage */ if (u.uenmax > 0) { You("lose magical energy!"); u.uenmax--; if (u.uen > 0) u.uen--; flags.botl = 1; } } else { if (mdef->data == &mons[PM_CLAY_GOLEM]) mdef->mhp = 1; /* cancelled clay golems will die */ if (youattack && attacktype(mdef->data, AT_MAGC)) { You("absorb magical energy!"); u.uenmax++; u.uen++; flags.botl = 1; } } } break; case MB_INDEX_SCARE: if (youdefend) { if (Antimagic) { resisted = TRUE; } else { nomul(-3); nomovemsg = ""; if (magr && magr == u.ustuck && sticks(youmonst.data)) { u.ustuck = (struct monst *)0; You("release %s!", mon_nam(magr)); } } } else { if (rn2(2) && resist(mdef, WEAPON_CLASS, 0, NOTELL)) resisted = TRUE; else monflee(mdef, 3, FALSE, (mdef->mhp > *dmgptr)); } if (!resisted) do_stun = FALSE; break; case MB_INDEX_STUN: do_stun = TRUE; /* (this is redundant...) */ break; case MB_INDEX_PROBE: if (youattack && (mb->spe == 0 || !rn2(3 * abs(mb->spe)))) { pline_The("%s is insightful.", verb); /* pre-damage status */ probe_monster(mdef); } break; } /* stun if that was selected and a worse effect didn't occur */ if (do_stun) { if (youdefend) make_stunned((HStun + 3), FALSE); else mdef->mstun = 1; /* avoid extra stun message below if we used mb_verb["stun"] above */ if (attack_indx == MB_INDEX_STUN) do_stun = FALSE; } /* lastly, all this magic can be confusing... */ do_confuse = !rn2(12); if (do_confuse) { if (youdefend) make_confused(HConfusion + 4, FALSE); else mdef->mconf = 1; } if (youattack || youdefend || vis) { (void) upstart(hittee); /* capitalize */ if (resisted) { pline("%s %s!", hittee, vtense(hittee, "resist")); shieldeff(youdefend ? u.ux : mdef->mx, youdefend ? u.uy : mdef->my); } if ((do_stun || do_confuse) && flags.verbose) { char buf[BUFSZ]; buf[0] = '\0'; if (do_stun) Strcat(buf, "stunned"); if (do_stun && do_confuse) Strcat(buf, " and "); if (do_confuse) Strcat(buf, "confused"); pline("%s %s %s%c", hittee, vtense(hittee, "are"), buf, (do_stun && do_confuse) ? '!' : '.'); } } return result; } /* Function used when someone attacks someone else with an artifact * weapon. Only adds the special (artifact) damage, and returns a 1 if it * did something special (in which case the caller won't print the normal * hit message). This should be called once upon every artifact attack; * dmgval() no longer takes artifact bonuses into account. Possible * extension: change the killer so that when an orc kills you with * Stormbringer it's "killed by Stormbringer" instead of "killed by an orc". */ boolean artifact_hit(magr, mdef, otmp, dmgptr, dieroll) struct monst *magr, *mdef; struct obj *otmp; int *dmgptr; int dieroll; /* needed for Magicbane and vorpal blades */ { boolean youattack = (magr == &youmonst); boolean youdefend = (mdef == &youmonst); boolean vis = (!youattack && magr && cansee(magr->mx, magr->my)) || (!youdefend && cansee(mdef->mx, mdef->my)) || (youattack && u.uswallow && mdef == u.ustuck && !Blind); boolean realizes_damage; const char *wepdesc; static const char you[] = "you"; char hittee[BUFSZ]; Strcpy(hittee, youdefend ? you : mon_nam(mdef)); /* The following takes care of most of the damage, but not all-- * the exception being for level draining, which is specially * handled. Messages are done in this function, however. */ *dmgptr += spec_dbon(otmp, mdef, *dmgptr); if (youattack && youdefend) { impossible("attacking yourself with weapon?"); return FALSE; } realizes_damage = (youdefend || vis || /* feel the effect even if not seen */ (youattack && mdef == u.ustuck)); /* the four basic attacks: fire, cold, shock and missiles */ if (attacks(AD_FIRE, otmp)) { if (realizes_damage) pline_The("fiery blade %s %s%c", !spec_dbon_applies ? "hits" : (mdef->data == &mons[PM_WATER_ELEMENTAL]) ? "vaporizes part of" : "burns", hittee, !spec_dbon_applies ? '.' : '!'); if (!rn2(4)) (void) destroy_mitem(mdef, POTION_CLASS, AD_FIRE); if (!rn2(4)) (void) destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); if (!rn2(7)) (void) destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); if (youdefend && Slimed) burn_away_slime(); return realizes_damage; } if (attacks(AD_COLD, otmp)) { if (realizes_damage) pline_The("ice-cold blade %s %s%c", !spec_dbon_applies ? "hits" : "freezes", hittee, !spec_dbon_applies ? '.' : '!'); if (!rn2(4)) (void) destroy_mitem(mdef, POTION_CLASS, AD_COLD); return realizes_damage; } if (attacks(AD_ELEC, otmp)) { if (realizes_damage) pline_The("massive hammer hits%s %s%c", !spec_dbon_applies ? "" : "! Lightning strikes", hittee, !spec_dbon_applies ? '.' : '!'); if (!rn2(5)) (void) destroy_mitem(mdef, RING_CLASS, AD_ELEC); if (!rn2(5)) (void) destroy_mitem(mdef, WAND_CLASS, AD_ELEC); return realizes_damage; } if (attacks(AD_MAGM, otmp)) { if (realizes_damage) pline_The("imaginary widget hits%s %s%c", !spec_dbon_applies ? "" : "! A hail of magic missiles strikes", hittee, !spec_dbon_applies ? '.' : '!'); return realizes_damage; } if (attacks(AD_STUN, otmp) && dieroll <= MB_MAX_DIEROLL) { /* Magicbane's special attacks (possibly modifies hittee[]) */ return Mb_hit(magr, mdef, otmp, dmgptr, dieroll, vis, hittee); } if (!spec_dbon_applies) { /* since damage bonus didn't apply, nothing more to do; no further attacks have side-effects on inventory */ return FALSE; } /* We really want "on a natural 20" but Nethack does it in */ /* reverse from AD&D. */ if (spec_ability(otmp, SPFX_BEHEAD)) { if (otmp->oartifact == ART_TSURUGI_OF_MURAMASA && dieroll == 1) { wepdesc = "The razor-sharp blade"; /* not really beheading, but so close, why add another SPFX */ if (youattack && u.uswallow && mdef == u.ustuck) { You("slice %s wide open!", mon_nam(mdef)); *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; return TRUE; } if (!youdefend) { /* allow normal cutworm() call to add extra damage */ if(notonhead) return FALSE; if (bigmonst(mdef->data)) { if (youattack) You("slice deeply into %s!", mon_nam(mdef)); else if (vis) pline("%s cuts deeply into %s!", Monnam(magr), hittee); *dmgptr *= 2; return TRUE; } *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; pline("%s cuts %s in half!", wepdesc, mon_nam(mdef)); otmp->dknown = TRUE; return TRUE; } else { if (bigmonst(youmonst.data)) { pline("%s cuts deeply into you!", magr ? Monnam(magr) : wepdesc); *dmgptr *= 2; return TRUE; } /* Players with negative AC's take less damage instead * of just not getting hit. We must add a large enough * value to the damage so that this reduction in * damage does not prevent death. */ *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER; pline("%s cuts you in half!", wepdesc); otmp->dknown = TRUE; return TRUE; } } else if (otmp->oartifact == ART_VORPAL_BLADE && (dieroll == 1 || mdef->data == &mons[PM_JABBERWOCK])) { static const char * const behead_msg[2] = { "%s beheads %s!", "%s decapitates %s!" }; if (youattack && u.uswallow && mdef == u.ustuck) return FALSE; wepdesc = artilist[ART_VORPAL_BLADE].name; if (!youdefend) { if (!has_head(mdef->data) || notonhead || u.uswallow) { if (youattack) pline("Somehow, you miss %s wildly.", mon_nam(mdef)); else if (vis) pline("Somehow, %s misses wildly.", mon_nam(magr)); *dmgptr = 0; return ((boolean)(youattack || vis)); } if (noncorporeal(mdef->data) || amorphous(mdef->data)) { pline("%s slices through %s %s.", wepdesc, s_suffix(mon_nam(mdef)), mbodypart(mdef,NECK)); return TRUE; } *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, mon_nam(mdef)); otmp->dknown = TRUE; return TRUE; } else { if (!has_head(youmonst.data)) { pline("Somehow, %s misses you wildly.", magr ? mon_nam(magr) : wepdesc); *dmgptr = 0; return TRUE; } if (noncorporeal(youmonst.data) || amorphous(youmonst.data)) { pline("%s slices through your %s.", wepdesc, body_part(NECK)); return TRUE; } *dmgptr = 2 * (Upolyd ? u.mh : u.uhp) + FATAL_DAMAGE_MODIFIER; pline(behead_msg[rn2(SIZE(behead_msg))], wepdesc, "you"); otmp->dknown = TRUE; /* Should amulets fall off? */ return TRUE; } } } if (spec_ability(otmp, SPFX_DRLI)) { if (!youdefend) { if (vis) { if(otmp->oartifact == ART_STORMBRINGER) pline_The("%s blade draws the life from %s!", hcolor(NH_BLACK), mon_nam(mdef)); else pline("%s draws the life from %s!", The(distant_name(otmp, xname)), mon_nam(mdef)); } if (mdef->m_lev == 0) { *dmgptr = 2 * mdef->mhp + FATAL_DAMAGE_MODIFIER; } else { int drain = rnd(8); *dmgptr += drain; mdef->mhpmax -= drain; mdef->m_lev--; drain /= 2; if (drain) healup(drain, 0, FALSE, FALSE); } return vis; } else { /* youdefend */ int oldhpmax = u.uhpmax; if (Blind) You_feel("an %s drain your life!", otmp->oartifact == ART_STORMBRINGER ? "unholy blade" : "object"); else if (otmp->oartifact == ART_STORMBRINGER) pline_The("%s blade drains your life!", hcolor(NH_BLACK)); else pline("%s drains your life!", The(distant_name(otmp, xname))); losexp("life drainage"); if (magr && magr->mhp < magr->mhpmax) { magr->mhp += (oldhpmax - u.uhpmax)/2; if (magr->mhp > magr->mhpmax) magr->mhp = magr->mhpmax; } return TRUE; } } return FALSE; } static NEARDATA const char recharge_type[] = { ALLOW_COUNT, ALL_CLASSES, 0 }; static NEARDATA const char invoke_types[] = { ALL_CLASSES, 0 }; /* #invoke: an "ugly check" filters out most objects */ int doinvoke() { register struct obj *obj; obj = getobj(invoke_types, "invoke"); if (!obj) return 0; if (obj->oartifact && !touch_artifact(obj, &youmonst)) return 1; return arti_invoke(obj); } STATIC_OVL int arti_invoke(obj) register struct obj *obj; { register const struct artifact *oart = get_artifact(obj); if(!oart || !oart->inv_prop) { if(obj->otyp == CRYSTAL_BALL) use_crystal_ball(obj); else pline(nothing_happens); return 1; } if(oart->inv_prop > LAST_PROP) { /* It's a special power, not "just" a property */ if(obj->age > monstermoves) { /* the artifact is tired :-) */ You_feel("that %s %s ignoring you.", the(xname(obj)), otense(obj, "are")); /* and just got more so; patience is essential... */ obj->age += (long) d(3,10); return 1; } obj->age = monstermoves + rnz(100); switch(oart->inv_prop) { case TAMING: { struct obj pseudo; pseudo = zeroobj; /* neither cursed nor blessed */ pseudo.otyp = SCR_TAMING; (void) seffects(&pseudo); break; } case HEALING: { int healamt = (u.uhpmax + 1 - u.uhp) / 2; long creamed = (long)u.ucreamed; if (Upolyd) healamt = (u.mhmax + 1 - u.mh) / 2; if (healamt || Sick || Slimed || Blinded > creamed) You_feel("better."); else goto nothing_special; if (healamt > 0) { if (Upolyd) u.mh += healamt; else u.uhp += healamt; } if(Sick) make_sick(0L,(char *)0,FALSE,SICK_ALL); if(Slimed) Slimed = 0L; if (Blinded > creamed) make_blinded(creamed, FALSE); flags.botl = 1; break; } case ENERGY_BOOST: { int epboost = (u.uenmax + 1 - u.uen) / 2; if (epboost > 120) epboost = 120; /* arbitrary */ else if (epboost < 12) epboost = u.uenmax - u.uen; if(epboost) { You_feel("re-energized."); u.uen += epboost; flags.botl = 1; } else goto nothing_special; break; } case UNTRAP: { if(!untrap(TRUE)) { obj->age = 0; /* don't charge for changing their mind */ return 0; } break; } case CHARGE_OBJ: { struct obj *otmp = getobj(recharge_type, "charge"); boolean b_effect; if (!otmp) { obj->age = 0; return 0; } b_effect = obj->blessed && (Role_switch == oart->role || !oart->role); recharge(otmp, b_effect ? 1 : obj->cursed ? -1 : 0); update_inventory(); break; } case LEV_TELE: level_tele(); break; case CREATE_PORTAL: { int i, num_ok_dungeons, last_ok_dungeon = 0; d_level newlev; extern int n_dgns; /* from dungeon.c */ winid tmpwin = create_nhwindow(NHW_MENU); anything any; any.a_void = 0; /* set all bits to zero */ start_menu(tmpwin); /* use index+1 (cant use 0) as identifier */ for (i = num_ok_dungeons = 0; i < n_dgns; i++) { if (!dungeons[i].dunlev_ureached) continue; any.a_int = i+1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, dungeons[i].dname, MENU_UNSELECTED); num_ok_dungeons++; last_ok_dungeon = i; } end_menu(tmpwin, "Open a portal to which dungeon?"); if (num_ok_dungeons > 1) { /* more than one entry; display menu for choices */ menu_item *selected; int n; n = select_menu(tmpwin, PICK_ONE, &selected); if (n <= 0) { destroy_nhwindow(tmpwin); goto nothing_special; } i = selected[0].item.a_int - 1; free((genericptr_t)selected); } else i = last_ok_dungeon; /* also first & only OK dungeon */ destroy_nhwindow(tmpwin); /* * i is now index into dungeon structure for the new dungeon. * Find the closest level in the given dungeon, open * a use-once portal to that dungeon and go there. * The closest level is either the entry or dunlev_ureached. */ newlev.dnum = i; if(dungeons[i].depth_start >= depth(&u.uz)) newlev.dlevel = dungeons[i].entry_lev; else newlev.dlevel = dungeons[i].dunlev_ureached; if(u.uhave.amulet || In_endgame(&u.uz) || In_endgame(&newlev) || newlev.dnum == u.uz.dnum) { You_feel("very disoriented for a moment."); } else { if(!Blind) You("are surrounded by a shimmering sphere!"); else You_feel("weightless for a moment."); goto_level(&newlev, FALSE, FALSE, FALSE); } break; } case ENLIGHTENING: enlightenment(0); break; case CREATE_AMMO: { struct obj *otmp = mksobj(ARROW, TRUE, FALSE); if (!otmp) goto nothing_special; otmp->blessed = obj->blessed; otmp->cursed = obj->cursed; otmp->bknown = obj->bknown; if (obj->blessed) { if (otmp->spe < 0) otmp->spe = 0; otmp->quan += rnd(10); } else if (obj->cursed) { if (otmp->spe > 0) otmp->spe = 0; } else otmp->quan += rnd(5); otmp->owt = weight(otmp); otmp = hold_another_object(otmp, "Suddenly %s out.", aobjnam(otmp, "fall"), (const char *)0); break; } } } else { long eprop = (u.uprops[oart->inv_prop].extrinsic ^= W_ARTI), iprop = u.uprops[oart->inv_prop].intrinsic; boolean on = (eprop & W_ARTI) != 0; /* true if invoked prop just set */ if(on && obj->age > monstermoves) { /* the artifact is tired :-) */ u.uprops[oart->inv_prop].extrinsic ^= W_ARTI; You_feel("that %s %s ignoring you.", the(xname(obj)), otense(obj, "are")); /* can't just keep repeatedly trying */ obj->age += (long) d(3,10); return 1; } else if(!on) { /* when turning off property, determine downtime */ /* arbitrary for now until we can tune this -dlc */ obj->age = monstermoves + rnz(100); } if ((eprop & ~W_ARTI) || iprop) { nothing_special: /* you had the property from some other source too */ if (carried(obj)) You_feel("a surge of power, but nothing seems to happen."); return 1; } switch(oart->inv_prop) { case CONFLICT: if(on) You_feel("like a rabble-rouser."); else You_feel("the tension decrease around you."); break; case LEVITATION: if(on) { float_up(); spoteffects(FALSE); } else (void) float_down(I_SPECIAL|TIMEOUT, W_ARTI); break; case INVIS: if (BInvis || Blind) goto nothing_special; newsym(u.ux, u.uy); if (on) Your("body takes on a %s transparency...", Hallucination ? "normal" : "strange"); else Your("body seems to unfade..."); break; } } return 1; } /* WAC return TRUE if artifact is always lit */ boolean artifact_light(obj) struct obj *obj; { return (get_artifact(obj) && obj->oartifact == ART_SUNSWORD); } /* KMH -- Talking artifacts are finally implemented */ void arti_speak(obj) struct obj *obj; { register const struct artifact *oart = get_artifact(obj); const char *line; char buf[BUFSZ]; /* Is this a speaking artifact? */ if (!oart || !(oart->spfx & SPFX_SPEAK)) return; line = getrumor(bcsign(obj), buf, TRUE); if (!*line) line = "NetHack rumors file closed for renovation."; pline("%s:", Tobjnam(obj, "whisper")); verbalize("%s", line); return; } boolean artifact_has_invprop(otmp, inv_prop) struct obj *otmp; uchar inv_prop; { const struct artifact *arti = get_artifact(otmp); return((boolean)(arti && (arti->inv_prop == inv_prop))); } /* Return the price sold to the hero of a given artifact or unique item */ long arti_cost(otmp) struct obj *otmp; { if (!otmp->oartifact) return ((long)objects[otmp->otyp].oc_cost); else if (artilist[(int) otmp->oartifact].cost) return (artilist[(int) otmp->oartifact].cost); else return (100L * (long)objects[otmp->otyp].oc_cost); } #endif /* OVLB */ /*artifact.c*/ nethack-3.4.3/src/attrib.c0100644000000000000000000004375107764735041014104 0ustar rootroot/* SCCS Id: @(#)attrib.c 3.4 2002/10/07 */ /* Copyright 1988, 1989, 1990, 1992, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* attribute modification routines. */ #include "hack.h" /* #define DEBUG */ /* uncomment for debugging info */ #ifdef OVLB /* part of the output on gain or loss of attribute */ static const char * const plusattr[] = { "strong", "smart", "wise", "agile", "tough", "charismatic" }, * const minusattr[] = { "weak", "stupid", "foolish", "clumsy", "fragile", "repulsive" }; static const struct innate { schar ulevel; long *ability; const char *gainstr, *losestr; } arc_abil[] = { { 1, &(HStealth), "", "" }, { 1, &(HFast), "", "" }, { 10, &(HSearching), "perceptive", "" }, { 0, 0, 0, 0 } }, bar_abil[] = { { 1, &(HPoison_resistance), "", "" }, { 7, &(HFast), "quick", "slow" }, { 15, &(HStealth), "stealthy", "" }, { 0, 0, 0, 0 } }, cav_abil[] = { { 7, &(HFast), "quick", "slow" }, { 15, &(HWarning), "sensitive", "" }, { 0, 0, 0, 0 } }, hea_abil[] = { { 1, &(HPoison_resistance), "", "" }, { 15, &(HWarning), "sensitive", "" }, { 0, 0, 0, 0 } }, kni_abil[] = { { 7, &(HFast), "quick", "slow" }, { 0, 0, 0, 0 } }, mon_abil[] = { { 1, &(HFast), "", "" }, { 1, &(HSleep_resistance), "", "" }, { 1, &(HSee_invisible), "", "" }, { 3, &(HPoison_resistance), "healthy", "" }, { 5, &(HStealth), "stealthy", "" }, { 7, &(HWarning), "sensitive", "" }, { 9, &(HSearching), "perceptive", "unaware" }, { 11, &(HFire_resistance), "cool", "warmer" }, { 13, &(HCold_resistance), "warm", "cooler" }, { 15, &(HShock_resistance), "insulated", "conductive" }, { 17, &(HTeleport_control), "controlled","uncontrolled" }, { 0, 0, 0, 0 } }, pri_abil[] = { { 15, &(HWarning), "sensitive", "" }, { 20, &(HFire_resistance), "cool", "warmer" }, { 0, 0, 0, 0 } }, ran_abil[] = { { 1, &(HSearching), "", "" }, { 7, &(HStealth), "stealthy", "" }, { 15, &(HSee_invisible), "", "" }, { 0, 0, 0, 0 } }, rog_abil[] = { { 1, &(HStealth), "", "" }, { 10, &(HSearching), "perceptive", "" }, { 0, 0, 0, 0 } }, sam_abil[] = { { 1, &(HFast), "", "" }, { 15, &(HStealth), "stealthy", "" }, { 0, 0, 0, 0 } }, tou_abil[] = { { 10, &(HSearching), "perceptive", "" }, { 20, &(HPoison_resistance), "hardy", "" }, { 0, 0, 0, 0 } }, val_abil[] = { { 1, &(HCold_resistance), "", "" }, { 1, &(HStealth), "", "" }, { 7, &(HFast), "quick", "slow" }, { 0, 0, 0, 0 } }, wiz_abil[] = { { 15, &(HWarning), "sensitive", "" }, { 17, &(HTeleport_control), "controlled","uncontrolled" }, { 0, 0, 0, 0 } }, /* Intrinsics conferred by race */ elf_abil[] = { { 4, &(HSleep_resistance), "awake", "tired" }, { 0, 0, 0, 0 } }, orc_abil[] = { { 1, &(HPoison_resistance), "", "" }, { 0, 0, 0, 0 } }; static long next_check = 600L; /* arbitrary first setting */ STATIC_DCL void NDECL(exerper); STATIC_DCL void FDECL(postadjabil, (long *)); /* adjust an attribute; return TRUE if change is made, FALSE otherwise */ boolean adjattrib(ndx, incr, msgflg) int ndx, incr; int msgflg; /* positive => no message, zero => message, and */ { /* negative => conditional (msg if change made) */ if (Fixed_abil || !incr) return FALSE; if ((ndx == A_INT || ndx == A_WIS) && uarmh && uarmh->otyp == DUNCE_CAP) { if (msgflg == 0) Your("cap constricts briefly, then relaxes again."); return FALSE; } if (incr > 0) { if ((AMAX(ndx) >= ATTRMAX(ndx)) && (ACURR(ndx) >= AMAX(ndx))) { if (msgflg == 0 && flags.verbose) pline("You're already as %s as you can get.", plusattr[ndx]); ABASE(ndx) = AMAX(ndx) = ATTRMAX(ndx); /* just in case */ return FALSE; } ABASE(ndx) += incr; if(ABASE(ndx) > AMAX(ndx)) { incr = ABASE(ndx) - AMAX(ndx); AMAX(ndx) += incr; if(AMAX(ndx) > ATTRMAX(ndx)) AMAX(ndx) = ATTRMAX(ndx); ABASE(ndx) = AMAX(ndx); } } else { if (ABASE(ndx) <= ATTRMIN(ndx)) { if (msgflg == 0 && flags.verbose) pline("You're already as %s as you can get.", minusattr[ndx]); ABASE(ndx) = ATTRMIN(ndx); /* just in case */ return FALSE; } ABASE(ndx) += incr; if(ABASE(ndx) < ATTRMIN(ndx)) { incr = ABASE(ndx) - ATTRMIN(ndx); ABASE(ndx) = ATTRMIN(ndx); AMAX(ndx) += incr; if(AMAX(ndx) < ATTRMIN(ndx)) AMAX(ndx) = ATTRMIN(ndx); } } if (msgflg <= 0) You_feel("%s%s!", (incr > 1 || incr < -1) ? "very ": "", (incr > 0) ? plusattr[ndx] : minusattr[ndx]); flags.botl = 1; if (moves > 1 && (ndx == A_STR || ndx == A_CON)) (void)encumber_msg(); return TRUE; } void gainstr(otmp, incr) register struct obj *otmp; register int incr; { int num = 1; if(incr) num = incr; else { if(ABASE(A_STR) < 18) num = (rn2(4) ? 1 : rnd(6) ); else if (ABASE(A_STR) < STR18(85)) num = rnd(10); } (void) adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num, TRUE); } void losestr(num) /* may kill you; cause may be poison or monster like 'a' */ register int num; { int ustr = ABASE(A_STR) - num; while(ustr < 3) { ++ustr; --num; if (Upolyd) { u.mh -= 6; u.mhmax -= 6; } else { u.uhp -= 6; u.uhpmax -= 6; } } (void) adjattrib(A_STR, -num, TRUE); } void change_luck(n) register schar n; { u.uluck += n; if (u.uluck < 0 && u.uluck < LUCKMIN) u.uluck = LUCKMIN; if (u.uluck > 0 && u.uluck > LUCKMAX) u.uluck = LUCKMAX; } int stone_luck(parameter) boolean parameter; /* So I can't think up of a good name. So sue me. --KAA */ { register struct obj *otmp; register long bonchance = 0; for (otmp = invent; otmp; otmp = otmp->nobj) if (confers_luck(otmp)) { if (otmp->cursed) bonchance -= otmp->quan; else if (otmp->blessed) bonchance += otmp->quan; else if (parameter) bonchance += otmp->quan; } return sgn((int)bonchance); } /* there has just been an inventory change affecting a luck-granting item */ void set_moreluck() { int luckbon = stone_luck(TRUE); if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0; else if (luckbon >= 0) u.moreluck = LUCKADD; else u.moreluck = -LUCKADD; } #endif /* OVLB */ #ifdef OVL1 void restore_attrib() { int i; for(i = 0; i < A_MAX; i++) { /* all temporary losses/gains */ if(ATEMP(i) && ATIME(i)) { if(!(--(ATIME(i)))) { /* countdown for change */ ATEMP(i) += ATEMP(i) > 0 ? -1 : 1; if(ATEMP(i)) /* reset timer */ ATIME(i) = 100 / ACURR(A_CON); } } } (void)encumber_msg(); } #endif /* OVL1 */ #ifdef OVLB #define AVAL 50 /* tune value for exercise gains */ void exercise(i, inc_or_dec) int i; boolean inc_or_dec; { #ifdef DEBUG pline("Exercise:"); #endif if (i == A_INT || i == A_CHA) return; /* can't exercise these */ /* no physical exercise while polymorphed; the body's temporary */ if (Upolyd && i != A_WIS) return; if(abs(AEXE(i)) < AVAL) { /* * Law of diminishing returns (Part I): * * Gain is harder at higher attribute values. * 79% at "3" --> 0% at "18" * Loss is even at all levels (50%). * * Note: *YES* ACURR is the right one to use. */ AEXE(i) += (inc_or_dec) ? (rn2(19) > ACURR(i)) : -rn2(2); #ifdef DEBUG pline("%s, %s AEXE = %d", (i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" : (i == A_DEX) ? "Dex" : "Con", (inc_or_dec) ? "inc" : "dec", AEXE(i)); #endif } if (moves > 0 && (i == A_STR || i == A_CON)) (void)encumber_msg(); } /* hunger values - from eat.c */ #define SATIATED 0 #define NOT_HUNGRY 1 #define HUNGRY 2 #define WEAK 3 #define FAINTING 4 #define FAINTED 5 #define STARVED 6 STATIC_OVL void exerper() { if(!(moves % 10)) { /* Hunger Checks */ int hs = (u.uhunger > 1000) ? SATIATED : (u.uhunger > 150) ? NOT_HUNGRY : (u.uhunger > 50) ? HUNGRY : (u.uhunger > 0) ? WEAK : FAINTING; #ifdef DEBUG pline("exerper: Hunger checks"); #endif switch (hs) { case SATIATED: exercise(A_DEX, FALSE); if (Role_if(PM_MONK)) exercise(A_WIS, FALSE); break; case NOT_HUNGRY: exercise(A_CON, TRUE); break; case WEAK: exercise(A_STR, FALSE); if (Role_if(PM_MONK)) /* fasting */ exercise(A_WIS, TRUE); break; case FAINTING: case FAINTED: exercise(A_CON, FALSE); break; } /* Encumberance Checks */ #ifdef DEBUG pline("exerper: Encumber checks"); #endif switch (near_capacity()) { case MOD_ENCUMBER: exercise(A_STR, TRUE); break; case HVY_ENCUMBER: exercise(A_STR, TRUE); exercise(A_DEX, FALSE); break; case EXT_ENCUMBER: exercise(A_DEX, FALSE); exercise(A_CON, FALSE); break; } } /* status checks */ if(!(moves % 5)) { #ifdef DEBUG pline("exerper: Status checks"); #endif if ((HClairvoyant & (INTRINSIC|TIMEOUT)) && !BClairvoyant) exercise(A_WIS, TRUE); if (HRegeneration) exercise(A_STR, TRUE); if(Sick || Vomiting) exercise(A_CON, FALSE); if(Confusion || Hallucination) exercise(A_WIS, FALSE); if((Wounded_legs #ifdef STEED && !u.usteed #endif ) || Fumbling || HStun) exercise(A_DEX, FALSE); } } void exerchk() { int i, mod_val; /* Check out the periodic accumulations */ exerper(); #ifdef DEBUG if(moves >= next_check) pline("exerchk: ready to test. multi = %d.", multi); #endif /* Are we ready for a test? */ if(moves >= next_check && !multi) { #ifdef DEBUG pline("exerchk: testing."); #endif /* * Law of diminishing returns (Part II): * * The effects of "exercise" and "abuse" wear * off over time. Even if you *don't* get an * increase/decrease, you lose some of the * accumulated effects. */ for(i = 0; i < A_MAX; AEXE(i++) /= 2) { if(ABASE(i) >= 18 || !AEXE(i)) continue; if(i == A_INT || i == A_CHA) continue;/* can't exercise these */ #ifdef DEBUG pline("exerchk: testing %s (%d).", (i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" : (i == A_DEX) ? "Dex" : "Con", AEXE(i)); #endif /* * Law of diminishing returns (Part III): * * You don't *always* gain by exercising. * [MRS 92/10/28 - Treat Wisdom specially for balance.] */ if(rn2(AVAL) > ((i != A_WIS) ? abs(AEXE(i)*2/3) : abs(AEXE(i)))) continue; mod_val = sgn(AEXE(i)); #ifdef DEBUG pline("exerchk: changing %d.", i); #endif if(adjattrib(i, mod_val, -1)) { #ifdef DEBUG pline("exerchk: changed %d.", i); #endif /* if you actually changed an attrib - zero accumulation */ AEXE(i) = 0; /* then print an explanation */ switch(i) { case A_STR: You((mod_val >0) ? "must have been exercising." : "must have been abusing your body."); break; case A_WIS: You((mod_val >0) ? "must have been very observant." : "haven't been paying attention."); break; case A_DEX: You((mod_val >0) ? "must have been working on your reflexes." : "haven't been working on reflexes lately."); break; case A_CON: You((mod_val >0) ? "must be leading a healthy life-style." : "haven't been watching your health."); break; } } } next_check += rn1(200,800); #ifdef DEBUG pline("exerchk: next check at %ld.", next_check); #endif } } /* next_check will otherwise have its initial 600L after a game restore */ void reset_attribute_clock() { if (moves > 600L) next_check = moves + rn1(50,800); } void init_attr(np) register int np; { register int i, x, tryct; for(i = 0; i < A_MAX; i++) { ABASE(i) = AMAX(i) = urole.attrbase[i]; ATEMP(i) = ATIME(i) = 0; np -= urole.attrbase[i]; } tryct = 0; while(np > 0 && tryct < 100) { x = rn2(100); for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++) ; if(i >= A_MAX) continue; /* impossible */ if(ABASE(i) >= ATTRMAX(i)) { tryct++; continue; } tryct = 0; ABASE(i)++; AMAX(i)++; np--; } tryct = 0; while(np < 0 && tryct < 100) { /* for redistribution */ x = rn2(100); for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++) ; if(i >= A_MAX) continue; /* impossible */ if(ABASE(i) <= ATTRMIN(i)) { tryct++; continue; } tryct = 0; ABASE(i)--; AMAX(i)--; np++; } } void redist_attr() { register int i, tmp; for(i = 0; i < A_MAX; i++) { if (i==A_INT || i==A_WIS) continue; /* Polymorphing doesn't change your mind */ tmp = AMAX(i); AMAX(i) += (rn2(5)-2); if (AMAX(i) > ATTRMAX(i)) AMAX(i) = ATTRMAX(i); if (AMAX(i) < ATTRMIN(i)) AMAX(i) = ATTRMIN(i); ABASE(i) = ABASE(i) * AMAX(i) / tmp; /* ABASE(i) > ATTRMAX(i) is impossible */ if (ABASE(i) < ATTRMIN(i)) ABASE(i) = ATTRMIN(i); } (void)encumber_msg(); } STATIC_OVL void postadjabil(ability) long *ability; { if (!ability) return; if (ability == &(HWarning) || ability == &(HSee_invisible)) see_monsters(); } void adjabil(oldlevel,newlevel) int oldlevel, newlevel; { register const struct innate *abil, *rabil; long mask = FROMEXPER; switch (Role_switch) { case PM_ARCHEOLOGIST: abil = arc_abil; break; case PM_BARBARIAN: abil = bar_abil; break; case PM_CAVEMAN: abil = cav_abil; break; case PM_HEALER: abil = hea_abil; break; case PM_KNIGHT: abil = kni_abil; break; case PM_MONK: abil = mon_abil; break; case PM_PRIEST: abil = pri_abil; break; case PM_RANGER: abil = ran_abil; break; case PM_ROGUE: abil = rog_abil; break; case PM_SAMURAI: abil = sam_abil; break; #ifdef TOURIST case PM_TOURIST: abil = tou_abil; break; #endif case PM_VALKYRIE: abil = val_abil; break; case PM_WIZARD: abil = wiz_abil; break; default: abil = 0; break; } switch (Race_switch) { case PM_ELF: rabil = elf_abil; break; case PM_ORC: rabil = orc_abil; break; case PM_HUMAN: case PM_DWARF: case PM_GNOME: default: rabil = 0; break; } while (abil || rabil) { long prevabil; /* Have we finished with the intrinsics list? */ if (!abil || !abil->ability) { /* Try the race intrinsics */ if (!rabil || !rabil->ability) break; abil = rabil; rabil = 0; mask = FROMRACE; } prevabil = *(abil->ability); if(oldlevel < abil->ulevel && newlevel >= abil->ulevel) { /* Abilities gained at level 1 can never be lost * via level loss, only via means that remove _any_ * sort of ability. A "gain" of such an ability from * an outside source is devoid of meaning, so we set * FROMOUTSIDE to avoid such gains. */ if (abil->ulevel == 1) *(abil->ability) |= (mask|FROMOUTSIDE); else *(abil->ability) |= mask; if(!(*(abil->ability) & INTRINSIC & ~mask)) { if(*(abil->gainstr)) You_feel("%s!", abil->gainstr); } } else if (oldlevel >= abil->ulevel && newlevel < abil->ulevel) { *(abil->ability) &= ~mask; if(!(*(abil->ability) & INTRINSIC)) { if(*(abil->losestr)) You_feel("%s!", abil->losestr); else if(*(abil->gainstr)) You_feel("less %s!", abil->gainstr); } } if (prevabil != *(abil->ability)) /* it changed */ postadjabil(abil->ability); abil++; } if (oldlevel > 0) { if (newlevel > oldlevel) add_weapon_skill(newlevel - oldlevel); else lose_weapon_skill(oldlevel - newlevel); } } int newhp() { int hp, conplus; if (u.ulevel == 0) { /* Initialize hit points */ hp = urole.hpadv.infix + urace.hpadv.infix; if (urole.hpadv.inrnd > 0) hp += rnd(urole.hpadv.inrnd); if (urace.hpadv.inrnd > 0) hp += rnd(urace.hpadv.inrnd); /* Initialize alignment stuff */ u.ualign.type = aligns[flags.initalign].value; u.ualign.record = urole.initrecord; return hp; } else { if (u.ulevel < urole.xlev) { hp = urole.hpadv.lofix + urace.hpadv.lofix; if (urole.hpadv.lornd > 0) hp += rnd(urole.hpadv.lornd); if (urace.hpadv.lornd > 0) hp += rnd(urace.hpadv.lornd); } else { hp = urole.hpadv.hifix + urace.hpadv.hifix; if (urole.hpadv.hirnd > 0) hp += rnd(urole.hpadv.hirnd); if (urace.hpadv.hirnd > 0) hp += rnd(urace.hpadv.hirnd); } } if (ACURR(A_CON) <= 3) conplus = -2; else if (ACURR(A_CON) <= 6) conplus = -1; else if (ACURR(A_CON) <= 14) conplus = 0; else if (ACURR(A_CON) <= 16) conplus = 1; else if (ACURR(A_CON) == 17) conplus = 2; else if (ACURR(A_CON) == 18) conplus = 3; else conplus = 4; hp += conplus; return((hp <= 0) ? 1 : hp); } #endif /* OVLB */ #ifdef OVL0 schar acurr(x) int x; { register int tmp = (u.abon.a[x] + u.atemp.a[x] + u.acurr.a[x]); if (x == A_STR) { if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER) return(125); #ifdef WIN32_BUG else return(x=((tmp >= 125) ? 125 : (tmp <= 3) ? 3 : tmp)); #else else return((schar)((tmp >= 125) ? 125 : (tmp <= 3) ? 3 : tmp)); #endif } else if (x == A_CHA) { if (tmp < 18 && (youmonst.data->mlet == S_NYMPH || u.umonnum==PM_SUCCUBUS || u.umonnum == PM_INCUBUS)) return 18; } else if (x == A_INT || x == A_WIS) { /* yes, this may raise int/wis if player is sufficiently * stupid. there are lower levels of cognition than "dunce". */ if (uarmh && uarmh->otyp == DUNCE_CAP) return(6); } #ifdef WIN32_BUG return(x=((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp)); #else return((schar)((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp)); #endif } /* condense clumsy ACURR(A_STR) value into value that fits into game formulas */ schar acurrstr() { register int str = ACURR(A_STR); if (str <= 18) return((schar)str); if (str <= 121) return((schar)(19 + str / 50)); /* map to 19-21 */ else return((schar)(str - 100)); } #endif /* OVL0 */ #ifdef OVL2 /* avoid possible problems with alignment overflow, and provide a centralized * location for any future alignment limits */ void adjalign(n) register int n; { register int newalign = u.ualign.record + n; if(n < 0) { if(newalign < u.ualign.record) u.ualign.record = newalign; } else if(newalign > u.ualign.record) { u.ualign.record = newalign; if(u.ualign.record > ALIGNLIM) u.ualign.record = ALIGNLIM; } } #endif /* OVL2 */ /*attrib.c*/ nethack-3.4.3/src/ball.c0100644000000000000000000005400507764735041013523 0ustar rootroot/* SCCS Id: @(#)ball.c 3.4 2003/02/03 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Ball & Chain =============================================================*/ #include "hack.h" STATIC_DCL int NDECL(bc_order); STATIC_DCL void NDECL(litter); void ballfall() { boolean gets_hit; gets_hit = (((uball->ox != u.ux) || (uball->oy != u.uy)) && ((uwep == uball)? FALSE : (boolean)rn2(5))); if (carried(uball)) { pline("Startled, you drop the iron ball."); if (uwep == uball) setuwep((struct obj *)0); if (uswapwep == uball) setuswapwep((struct obj *)0); if (uquiver == uball) setuqwep((struct obj *)0);; if (uwep != uball) freeinv(uball); } if(gets_hit){ int dmg = rn1(7,25); pline_The("iron ball falls on your %s.", body_part(HEAD)); if (uarmh) { if(is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); dmg = 3; } else if (flags.verbose) Your("%s does not protect you.", xname(uarmh)); } losehp(dmg, "crunched in the head by an iron ball", NO_KILLER_PREFIX); } } /* * To make this work, we have to mess with the hero's mind. The rules for * ball&chain are: * * 1. If the hero can see them, fine. * 2. If the hero can't see either, it isn't seen. * 3. If either is felt it is seen. * 4. If either is felt and moved, it disappears. * * If the hero can see, then when a move is done, the ball and chain are * first picked up, the positions under them are corrected, then they * are moved after the hero moves. Not too bad. * * If the hero is blind, then she can "feel" the ball and/or chain at any * time. However, when the hero moves, the felt ball and/or chain become * unfelt and whatever was felt "under" the ball&chain appears. Pretty * nifty, but it requires that the ball&chain "remember" what was under * them --- i.e. they pick-up glyphs when they are felt and drop them when * moved (and felt). When swallowed, the ball&chain are pulled completely * off of the dungeon, but are still on the object chain. They are placed * under the hero when she is expelled. */ /* * from you.h * int u.bglyph glyph under the ball * int u.cglyph glyph under the chain * int u.bc_felt mask for ball/chain being felt * #define BC_BALL 0x01 bit mask in u.bc_felt for ball * #define BC_CHAIN 0x02 bit mask in u.bc_felt for chain * int u.bc_order ball & chain order * * u.bc_felt is also manipulated in display.c and read.c, the others only * in this file. None of these variables are valid unless the player is * Blind. */ /* values for u.bc_order */ #define BCPOS_DIFFER 0 /* ball & chain at different positions */ #define BCPOS_CHAIN 1 /* chain on top of ball */ #define BCPOS_BALL 2 /* ball on top of chain */ /* * Place the ball & chain under the hero. Make sure that the ball & chain * variables are set (actually only needed when blind, but what the heck). * It is assumed that when this is called, the ball and chain are NOT * attached to the object list. * * Should not be called while swallowed. */ void placebc() { if (!uchain || !uball) { impossible("Where are your ball and chain?"); return; } (void) flooreffects(uchain, u.ux, u.uy, ""); /* chain might rust */ if (carried(uball)) /* the ball is carried */ u.bc_order = BCPOS_DIFFER; else { /* ball might rust -- already checked when carried */ (void) flooreffects(uball, u.ux, u.uy, ""); place_object(uball, u.ux, u.uy); u.bc_order = BCPOS_CHAIN; } place_object(uchain, u.ux, u.uy); u.bglyph = u.cglyph = levl[u.ux][u.uy].glyph; /* pick up glyph */ newsym(u.ux,u.uy); } void unplacebc() { if (u.uswallow) return; /* ball&chain not placed while swallowed */ if (!carried(uball)) { obj_extract_self(uball); if (Blind && (u.bc_felt & BC_BALL)) /* drop glyph */ levl[uball->ox][uball->oy].glyph = u.bglyph; newsym(uball->ox,uball->oy); } obj_extract_self(uchain); if (Blind && (u.bc_felt & BC_CHAIN)) /* drop glyph */ levl[uchain->ox][uchain->oy].glyph = u.cglyph; newsym(uchain->ox,uchain->oy); u.bc_felt = 0; /* feel nothing */ } /* * Return the stacking of the hero's ball & chain. This assumes that the * hero is being punished. */ STATIC_OVL int bc_order() { struct obj *obj; if (uchain->ox != uball->ox || uchain->oy != uball->oy || carried(uball) || u.uswallow) return BCPOS_DIFFER; for (obj = level.objects[uball->ox][uball->oy]; obj; obj = obj->nexthere) { if (obj == uchain) return BCPOS_CHAIN; if (obj == uball) return BCPOS_BALL; } impossible("bc_order: ball&chain not in same location!"); return BCPOS_DIFFER; } /* * set_bc() * * The hero is either about to go blind or already blind and just punished. * Set up the ball and chain variables so that the ball and chain are "felt". */ void set_bc(already_blind) int already_blind; { int ball_on_floor = !carried(uball); u.bc_order = bc_order(); /* get the order */ u.bc_felt = ball_on_floor ? BC_BALL|BC_CHAIN : BC_CHAIN; /* felt */ if (already_blind || u.uswallow) { u.cglyph = u.bglyph = levl[u.ux][u.uy].glyph; return; } /* * Since we can still see, remove the ball&chain and get the glyph that * would be beneath them. Then put the ball&chain back. This is pretty * disgusting, but it will work. */ remove_object(uchain); if (ball_on_floor) remove_object(uball); newsym(uchain->ox, uchain->oy); u.cglyph = levl[uchain->ox][uchain->oy].glyph; if (u.bc_order == BCPOS_DIFFER) { /* different locations */ place_object(uchain, uchain->ox, uchain->oy); newsym(uchain->ox, uchain->oy); if (ball_on_floor) { newsym(uball->ox, uball->oy); /* see under ball */ u.bglyph = levl[uball->ox][uball->oy].glyph; place_object(uball, uball->ox, uball->oy); newsym(uball->ox, uball->oy); /* restore ball */ } } else { u.bglyph = u.cglyph; if (u.bc_order == BCPOS_CHAIN) { place_object(uball, uball->ox, uball->oy); place_object(uchain, uchain->ox, uchain->oy); } else { place_object(uchain, uchain->ox, uchain->oy); place_object(uball, uball->ox, uball->oy); } newsym(uball->ox, uball->oy); } } /* * move_bc() * * Move the ball and chain. This is called twice for every move. The first * time to pick up the ball and chain before the move, the second time to * place the ball and chain after the move. If the ball is carried, this * function should never have BC_BALL as part of its control. * * Should not be called while swallowed. */ void move_bc(before, control, ballx, bally, chainx, chainy) int before, control; xchar ballx, bally, chainx, chainy; /* only matter !before */ { if (Blind) { /* * The hero is blind. Time to work hard. The ball and chain that * are attached to the hero are very special. The hero knows that * they are attached, so when they move, the hero knows that they * aren't at the last position remembered. This is complicated * by the fact that the hero can "feel" the surrounding locations * at any time, hence, making one or both of them show up again. * So, we have to keep track of which is felt at any one time and * act accordingly. */ if (!before) { if ((control & BC_CHAIN) && (control & BC_BALL)) { /* * Both ball and chain moved. If felt, drop glyph. */ if (u.bc_felt & BC_BALL) levl[uball->ox][uball->oy].glyph = u.bglyph; if (u.bc_felt & BC_CHAIN) levl[uchain->ox][uchain->oy].glyph = u.cglyph; u.bc_felt = 0; /* Pick up glyph at new location. */ u.bglyph = levl[ballx][bally].glyph; u.cglyph = levl[chainx][chainy].glyph; movobj(uball,ballx,bally); movobj(uchain,chainx,chainy); } else if (control & BC_BALL) { if (u.bc_felt & BC_BALL) { if (u.bc_order == BCPOS_DIFFER) { /* ball by itself */ levl[uball->ox][uball->oy].glyph = u.bglyph; } else if (u.bc_order == BCPOS_BALL) { if (u.bc_felt & BC_CHAIN) { /* know chain is there */ map_object(uchain, 0); } else { levl[uball->ox][uball->oy].glyph = u.bglyph; } } u.bc_felt &= ~BC_BALL; /* no longer feel the ball */ } /* Pick up glyph at new position. */ u.bglyph = (ballx != chainx || bally != chainy) ? levl[ballx][bally].glyph : u.cglyph; movobj(uball,ballx,bally); } else if (control & BC_CHAIN) { if (u.bc_felt & BC_CHAIN) { if (u.bc_order == BCPOS_DIFFER) { levl[uchain->ox][uchain->oy].glyph = u.cglyph; } else if (u.bc_order == BCPOS_CHAIN) { if (u.bc_felt & BC_BALL) { map_object(uball, 0); } else { levl[uchain->ox][uchain->oy].glyph = u.cglyph; } } u.bc_felt &= ~BC_CHAIN; } /* Pick up glyph at new position. */ u.cglyph = (ballx != chainx || bally != chainy) ? levl[chainx][chainy].glyph : u.bglyph; movobj(uchain,chainx,chainy); } u.bc_order = bc_order(); /* reset the order */ } } else { /* * The hero is not blind. To make this work correctly, we need to * pick up the ball and chain before the hero moves, then put them * in their new positions after the hero moves. */ if (before) { if (!control) { /* * Neither ball nor chain is moving, so remember which was * on top until !before. Use the variable u.bc_order * since it is only valid when blind. */ u.bc_order = bc_order(); } remove_object(uchain); newsym(uchain->ox, uchain->oy); if (!carried(uball)) { remove_object(uball); newsym(uball->ox, uball->oy); } } else { int on_floor = !carried(uball); if ((control & BC_CHAIN) || (!control && u.bc_order == BCPOS_CHAIN)) { /* If the chain moved or nothing moved & chain on top. */ if (on_floor) place_object(uball, ballx, bally); place_object(uchain, chainx, chainy); /* chain on top */ } else { place_object(uchain, chainx, chainy); if (on_floor) place_object(uball, ballx, bally); /* ball on top */ } newsym(chainx, chainy); if (on_floor) newsym(ballx, bally); } } } /* return TRUE if the caller needs to place the ball and chain down again * * Should not be called while swallowed. Should be called before movement, * because we might want to move the ball or chain to the hero's old position. * * It is called if we are moving. It is also called if we are teleporting * *if* the ball doesn't move and we thus must drag the chain. It is not * called for ordinary teleportation. * * allow_drag is only used in the ugly special case where teleporting must * drag the chain, while an identical-looking movement must drag both the ball * and chain. */ boolean drag_ball(x, y, bc_control, ballx, bally, chainx, chainy, cause_delay, allow_drag) xchar x, y; int *bc_control; xchar *ballx, *bally, *chainx, *chainy; boolean *cause_delay; boolean allow_drag; { struct trap *t = (struct trap *)0; boolean already_in_rock; *ballx = uball->ox; *bally = uball->oy; *chainx = uchain->ox; *chainy = uchain->oy; *bc_control = 0; *cause_delay = FALSE; if (dist2(x, y, uchain->ox, uchain->oy) <= 2) { /* nothing moved */ move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); return TRUE; } /* only need to move the chain? */ if (carried(uball) || distmin(x, y, uball->ox, uball->oy) <= 2) { xchar oldchainx = uchain->ox, oldchainy = uchain->oy; *bc_control = BC_CHAIN; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); if (carried(uball)) { /* move chain only if necessary */ if (distmin(x, y, uchain->ox, uchain->oy) > 1) { *chainx = u.ux; *chainy = u.uy; } return TRUE; } #define CHAIN_IN_MIDDLE(chx, chy) \ (distmin(x, y, chx, chy) <= 1 && distmin(chx, chy, uball->ox, uball->oy) <= 1) #define IS_CHAIN_ROCK(x,y) \ (IS_ROCK(levl[x][y].typ) || (IS_DOOR(levl[x][y].typ) && \ (levl[x][y].doormask & (D_CLOSED|D_LOCKED)))) /* Don't ever move the chain into solid rock. If we have to, then instead * undo the move_bc() and jump to the drag ball code. Note that this also * means the "cannot carry and drag" message will not appear, since unless we * moved at least two squares there is no possibility of the chain position * being in solid rock. */ #define SKIP_TO_DRAG { *chainx = oldchainx; *chainy = oldchainy; \ move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); \ goto drag; } if (IS_CHAIN_ROCK(u.ux, u.uy) || IS_CHAIN_ROCK(*chainx, *chainy) || IS_CHAIN_ROCK(uball->ox, uball->oy)) already_in_rock = TRUE; else already_in_rock = FALSE; switch(dist2(x, y, uball->ox, uball->oy)) { /* two spaces diagonal from ball, move chain inbetween */ case 8: *chainx = (uball->ox + x)/2; *chainy = (uball->oy + y)/2; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; /* player is distance 2/1 from ball; move chain to one of the * two spaces between * @ * __ * 0 */ case 5: { xchar tempx, tempy, tempx2, tempy2; /* find position closest to current position of chain */ /* no effect if current position is already OK */ if (abs(x - uball->ox) == 1) { tempx = x; tempx2 = uball->ox; tempy = tempy2 = (uball->oy + y)/2; } else { tempx = tempx2 = (uball->ox + x)/2; tempy = y; tempy2 = uball->oy; } if (IS_CHAIN_ROCK(tempx, tempy) && !IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { if (allow_drag) { /* Avoid pathological case *if* not teleporting: * 0 0_ * _X move northeast -----> X@ * @ */ if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && dist2(x, y, tempx, tempy) == 1) SKIP_TO_DRAG; /* Avoid pathological case *if* not teleporting: * 0 0 * _X move east -----> X_ * @ @ */ if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && dist2(x, y, tempx, tempy) == 2) SKIP_TO_DRAG; } *chainx = tempx2; *chainy = tempy2; } else if (!IS_CHAIN_ROCK(tempx, tempy) && IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { if (allow_drag) { if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 5 && dist2(x, y, tempx2, tempy2) == 1) SKIP_TO_DRAG; if (dist2(u.ux, u.uy, uball->ox, uball->oy) == 4 && dist2(x, y, tempx2, tempy2) == 2) SKIP_TO_DRAG; } *chainx = tempx; *chainy = tempy; } else if (IS_CHAIN_ROCK(tempx, tempy) && IS_CHAIN_ROCK(tempx2, tempy2) && !already_in_rock) { SKIP_TO_DRAG; } else if (dist2(tempx, tempy, uchain->ox, uchain->oy) < dist2(tempx2, tempy2, uchain->ox, uchain->oy) || ((dist2(tempx, tempy, uchain->ox, uchain->oy) == dist2(tempx2, tempy2, uchain->ox, uchain->oy)) && rn2(2))) { *chainx = tempx; *chainy = tempy; } else { *chainx = tempx2; *chainy = tempy2; } break; } /* ball is two spaces horizontal or vertical from player; move*/ /* chain inbetween *unless* current chain position is OK */ case 4: if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) break; *chainx = (x + uball->ox)/2; *chainy = (y + uball->oy)/2; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; /* ball is one space diagonal from player. Check for the * following special case: * @ * _ moving southwest becomes @_ * 0 0 * (This will also catch teleporting that happens to resemble * this case, but oh well.) Otherwise fall through. */ case 2: if (dist2(x, y, uball->ox, uball->oy) == 2 && dist2(x, y, uchain->ox, uchain->oy) == 4) { if (uchain->oy == y) *chainx = uball->ox; else *chainy = uball->oy; if (IS_CHAIN_ROCK(*chainx, *chainy) && !already_in_rock) SKIP_TO_DRAG; break; } /* fall through */ case 1: case 0: /* do nothing if possible */ if (CHAIN_IN_MIDDLE(uchain->ox, uchain->oy)) break; /* otherwise try to drag chain to player's old position */ if (CHAIN_IN_MIDDLE(u.ux, u.uy)) { *chainx = u.ux; *chainy = u.uy; break; } /* otherwise use player's new position (they must have teleported, for this to happen) */ *chainx = x; *chainy = y; break; default: impossible("bad chain movement"); break; } #undef SKIP_TO_DRAG #undef IS_CHAIN_ROCK #undef CHAIN_IN_MIDDLE return TRUE; } drag: if (near_capacity() > SLT_ENCUMBER && dist2(x, y, u.ux, u.uy) <= 2) { You("cannot %sdrag the heavy iron ball.", invent ? "carry all that and also " : ""); nomul(0); return FALSE; } if ((is_pool(uchain->ox, uchain->oy) && /* water not mere continuation of previous water */ (levl[uchain->ox][uchain->oy].typ == POOL || !is_pool(uball->ox, uball->oy) || levl[uball->ox][uball->oy].typ == POOL)) || ((t = t_at(uchain->ox, uchain->oy)) && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == HOLE || t->ttyp == TRAPDOOR)) ) { if (Levitation) { You_feel("a tug from the iron ball."); if (t) t->tseen = 1; } else { struct monst *victim; You("are jerked back by the iron ball!"); if ((victim = m_at(uchain->ox, uchain->oy)) != 0) { int tmp; tmp = -2 + Luck + find_mac(victim); tmp += omon_adj(victim, uball, TRUE); if (tmp >= rnd(20)) (void) hmon(victim,uball,1); else miss(xname(uball), victim); } /* now check again in case mon died */ if (!m_at(uchain->ox, uchain->oy)) { u.ux = uchain->ox; u.uy = uchain->oy; newsym(u.ux0, u.uy0); } nomul(0); *bc_control = BC_BALL; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); *ballx = uchain->ox; *bally = uchain->oy; move_bc(0, *bc_control, *ballx, *bally, *chainx, *chainy); spoteffects(TRUE); return FALSE; } } *bc_control = BC_BALL|BC_CHAIN; move_bc(1, *bc_control, *ballx, *bally, *chainx, *chainy); if (dist2(x, y, u.ux, u.uy) > 2) { /* Awful case: we're still in range of the ball, so we thought we * could only move the chain, but it turned out that the target * square for the chain was rock, so we had to drag it instead. * But we can't drag it either, because we teleported and are more * than one square from our old position. Revert to the teleport * behavior. */ *ballx = *chainx = x; *bally = *chainy = y; } else { *ballx = uchain->ox; *bally = uchain->oy; *chainx = u.ux; *chainy = u.uy; } *cause_delay = TRUE; return TRUE; } /* * drop_ball() * * The punished hero drops or throws her iron ball. If the hero is * blind, we must reset the order and glyph. Check for side effects. * This routine expects the ball to be already placed. * * Should not be called while swallowed. */ void drop_ball(x, y) xchar x, y; { if (Blind) { u.bc_order = bc_order(); /* get the order */ /* pick up glyph */ u.bglyph = (u.bc_order) ? u.cglyph : levl[x][y].glyph; } if (x != u.ux || y != u.uy) { struct trap *t; const char *pullmsg = "The ball pulls you out of the %s!"; if (u.utrap && u.utraptype != TT_INFLOOR) { switch(u.utraptype) { case TT_PIT: pline(pullmsg, "pit"); break; case TT_WEB: pline(pullmsg, "web"); pline_The("web is destroyed!"); deltrap(t_at(u.ux,u.uy)); break; case TT_LAVA: pline(pullmsg, "lava"); break; case TT_BEARTRAP: { register long side = rn2(3) ? LEFT_SIDE : RIGHT_SIDE; pline(pullmsg, "bear trap"); set_wounded_legs(side, rn1(1000, 500)); #ifdef STEED if (!u.usteed) #endif { Your("%s %s is severely damaged.", (side == LEFT_SIDE) ? "left" : "right", body_part(LEG)); losehp(2, "leg damage from being pulled out of a bear trap", KILLED_BY); } break; } } u.utrap = 0; fill_pit(u.ux, u.uy); } u.ux0 = u.ux; u.uy0 = u.uy; if (!Levitation && !MON_AT(x, y) && !u.utrap && (is_pool(x, y) || ((t = t_at(x, y)) && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == TRAPDOOR || t->ttyp == HOLE)))) { u.ux = x; u.uy = y; } else { u.ux = x - u.dx; u.uy = y - u.dy; } vision_full_recalc = 1; /* hero has moved, recalculate vision later */ if (Blind) { /* drop glyph under the chain */ if (u.bc_felt & BC_CHAIN) levl[uchain->ox][uchain->oy].glyph = u.cglyph; u.bc_felt = 0; /* feel nothing */ /* pick up new glyph */ u.cglyph = (u.bc_order) ? u.bglyph : levl[u.ux][u.uy].glyph; } movobj(uchain,u.ux,u.uy); /* has a newsym */ if (Blind) { u.bc_order = bc_order(); } newsym(u.ux0,u.uy0); /* clean up old position */ if (u.ux0 != u.ux || u.uy0 != u.uy) { spoteffects(TRUE); if (In_sokoban(&u.uz)) change_luck(-1); /* Sokoban guilt */ } } } STATIC_OVL void litter() { struct obj *otmp = invent, *nextobj; int capacity = weight_cap(); while (otmp) { nextobj = otmp->nobj; if ((otmp != uball) && (rnd(capacity) <= (int)otmp->owt)) { if (canletgo(otmp, "")) { Your("%s you down the stairs.", aobjnam(otmp, "follow")); dropx(otmp); } } otmp = nextobj; } } void drag_down() { boolean forward; uchar dragchance = 3; /* * Assume that the ball falls forward if: * * a) the character is wielding it, or * b) the character has both hands available to hold it (i.e. is * not wielding any weapon), or * c) (perhaps) it falls forward out of his non-weapon hand */ forward = carried(uball) && (uwep == uball || !uwep || !rn2(3)); if (carried(uball)) You("lose your grip on the iron ball."); if (forward) { if(rn2(6)) { pline_The("iron ball drags you downstairs!"); losehp(rnd(6), "dragged downstairs by an iron ball", NO_KILLER_PREFIX); litter(); } } else { if(rn2(2)) { pline_The("iron ball smacks into you!"); losehp(rnd(20), "iron ball collision", KILLED_BY_AN); exercise(A_STR, FALSE); dragchance -= 2; } if( (int) dragchance >= rnd(6)) { pline_The("iron ball drags you downstairs!"); losehp(rnd(3), "dragged downstairs by an iron ball", NO_KILLER_PREFIX); exercise(A_STR, FALSE); litter(); } } } /*ball.c*/ nethack-3.4.3/src/bones.c0100644000000000000000000003142307764735041013716 0ustar rootroot/* SCCS Id: @(#)bones.c 3.4 2003/09/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" extern char bones[]; /* from files.c */ #ifdef MFLOPPY extern long bytes_counted; #endif STATIC_DCL boolean FDECL(no_bones_level, (d_level *)); STATIC_DCL void FDECL(goodfruit, (int)); STATIC_DCL void FDECL(resetobjs,(struct obj *,BOOLEAN_P)); STATIC_DCL void FDECL(drop_upon_death, (struct monst *, struct obj *)); STATIC_OVL boolean no_bones_level(lev) d_level *lev; { extern d_level save_dlevel; /* in do.c */ s_level *sptr; if (ledger_no(&save_dlevel)) assign_level(lev, &save_dlevel); return (boolean)(((sptr = Is_special(lev)) != 0 && !sptr->boneid) || !dungeons[lev->dnum].boneid /* no bones on the last or multiway branch levels */ /* in any dungeon (level 1 isn't multiway). */ || Is_botlevel(lev) || (Is_branchlev(lev) && lev->dlevel > 1) /* no bones in the invocation level */ || (In_hell(lev) && lev->dlevel == dunlevs_in_dungeon(lev) - 1) ); } /* Call this function for each fruit object saved in the bones level: it marks * that particular type of fruit as existing (the marker is that that type's * ID is positive instead of negative). This way, when we later save the * chain of fruit types, we know to only save the types that exist. */ STATIC_OVL void goodfruit(id) int id; { register struct fruit *f; for(f=ffruit; f; f=f->nextf) { if(f->fid == -id) { f->fid = id; return; } } } STATIC_OVL void resetobjs(ochain,restore) struct obj *ochain; boolean restore; { struct obj *otmp; for (otmp = ochain; otmp; otmp = otmp->nobj) { if (otmp->cobj) resetobjs(otmp->cobj,restore); if (((otmp->otyp != CORPSE || otmp->corpsenm < SPECIAL_PM) && otmp->otyp != STATUE) && (!otmp->oartifact || (restore && (exist_artifact(otmp->otyp, ONAME(otmp)) || is_quest_artifact(otmp))))) { otmp->oartifact = 0; otmp->onamelth = 0; *ONAME(otmp) = '\0'; } else if (otmp->oartifact && restore) artifact_exists(otmp,ONAME(otmp),TRUE); if (!restore) { /* do not zero out o_ids for ghost levels anymore */ if(objects[otmp->otyp].oc_uses_known) otmp->known = 0; otmp->dknown = otmp->bknown = 0; otmp->rknown = 0; otmp->invlet = 0; otmp->no_charge = 0; if (otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe); #ifdef MAIL else if (otmp->otyp == SCR_MAIL) otmp->spe = 1; #endif else if (otmp->otyp == EGG) otmp->spe = 0; else if (otmp->otyp == TIN) { /* make tins of unique monster's meat be empty */ if (otmp->corpsenm >= LOW_PM && (mons[otmp->corpsenm].geno & G_UNIQ)) otmp->corpsenm = NON_PM; } else if (otmp->otyp == AMULET_OF_YENDOR) { /* no longer the real Amulet */ otmp->otyp = FAKE_AMULET_OF_YENDOR; curse(otmp); } else if (otmp->otyp == CANDELABRUM_OF_INVOCATION) { if (otmp->lamplit) end_burn(otmp, TRUE); otmp->otyp = WAX_CANDLE; otmp->age = 50L; /* assume used */ if (otmp->spe > 0) otmp->quan = (long)otmp->spe; otmp->spe = 0; otmp->owt = weight(otmp); curse(otmp); } else if (otmp->otyp == BELL_OF_OPENING) { otmp->otyp = BELL; curse(otmp); } else if (otmp->otyp == SPE_BOOK_OF_THE_DEAD) { otmp->otyp = SPE_BLANK_PAPER; curse(otmp); } } } } STATIC_OVL void drop_upon_death(mtmp, cont) struct monst *mtmp; struct obj *cont; { struct obj *otmp; uswapwep = 0; /* ensure curse() won't cause swapwep to drop twice */ while ((otmp = invent) != 0) { obj_extract_self(otmp); obj_no_longer_held(otmp); otmp->owornmask = 0; /* lamps don't go out when dropped */ if ((cont || artifact_light(otmp)) && obj_is_burning(otmp)) end_burn(otmp, TRUE); /* smother in statue */ if(otmp->otyp == SLIME_MOLD) goodfruit(otmp->spe); if(rn2(5)) curse(otmp); if (mtmp) (void) add_to_minv(mtmp, otmp); else if (cont) (void) add_to_container(cont, otmp); else place_object(otmp, u.ux, u.uy); } #ifndef GOLDOBJ if(u.ugold) { long ugold = u.ugold; if (mtmp) mtmp->mgold = ugold; else if (cont) (void) add_to_container(cont, mkgoldobj(ugold)); else (void)mkgold(ugold, u.ux, u.uy); u.ugold = ugold; /* undo mkgoldobj()'s removal */ } #endif if (cont) cont->owt = weight(cont); } /* check whether bones are feasible */ boolean can_make_bones() { register struct trap *ttmp; if (ledger_no(&u.uz) <= 0 || ledger_no(&u.uz) > maxledgerno()) return FALSE; if (no_bones_level(&u.uz)) return FALSE; /* no bones for specific levels */ if (u.uswallow) { return FALSE; /* no bones when swallowed */ } if (!Is_branchlev(&u.uz)) { /* no bones on non-branches with portals */ for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) if (ttmp->ttyp == MAGIC_PORTAL) return FALSE; } if(depth(&u.uz) <= 0 || /* bulletproofing for endgame */ (!rn2(1 + (depth(&u.uz)>>2)) /* fewer ghosts on low levels */ #ifdef WIZARD && !wizard #endif )) return FALSE; /* don't let multiple restarts generate multiple copies of objects * in bones files */ if (discover) return FALSE; return TRUE; } /* save bones and possessions of a deceased adventurer */ void savebones(corpse) struct obj *corpse; { int fd, x, y; struct trap *ttmp; struct monst *mtmp; struct permonst *mptr; struct fruit *f; char c, *bonesid; char whynot[BUFSZ]; /* caller has already checked `can_make_bones()' */ clear_bypasses(); fd = open_bonesfile(&u.uz, &bonesid); if (fd >= 0) { (void) close(fd); compress_bonesfile(); #ifdef WIZARD if (wizard) { if (yn("Bones file already exists. Replace it?") == 'y') { if (delete_bonesfile(&u.uz)) goto make_bones; else pline("Cannot unlink old bones."); } } #endif return; } #ifdef WIZARD make_bones: #endif unleash_all(); /* in case these characters are not in their home bases */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; mptr = mtmp->data; if (mtmp->iswiz || mptr == &mons[PM_MEDUSA] || mptr->msound == MS_NEMESIS || mptr->msound == MS_LEADER || mptr == &mons[PM_VLAD_THE_IMPALER]) mongone(mtmp); } #ifdef STEED if (u.usteed) dismount_steed(DISMOUNT_BONES); #endif dmonsfree(); /* discard dead or gone monsters */ /* mark all fruits as nonexistent; when we come to them we'll mark * them as existing (using goodfruit()) */ for(f=ffruit; f; f=f->nextf) f->fid = -f->fid; /* check iron balls separately--maybe they're not carrying it */ if (uball) uball->owornmask = uchain->owornmask = 0; /* dispose of your possessions, usually cursed */ if (u.ugrave_arise == (NON_PM - 1)) { struct obj *otmp; /* embed your possessions in your statue */ otmp = mk_named_object(STATUE, &mons[u.umonnum], u.ux, u.uy, plname); drop_upon_death((struct monst *)0, otmp); if (!otmp) return; /* couldn't make statue */ mtmp = (struct monst *)0; } else if (u.ugrave_arise < LOW_PM) { /* drop everything */ drop_upon_death((struct monst *)0, (struct obj *)0); /* trick makemon() into allowing monster creation * on your location */ in_mklev = TRUE; mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, MM_NONAME); in_mklev = FALSE; if (!mtmp) return; mtmp = christen_monst(mtmp, plname); if (corpse) (void) obj_attach_mid(corpse, mtmp->m_id); } else { /* give your possessions to the monster you become */ in_mklev = TRUE; mtmp = makemon(&mons[u.ugrave_arise], u.ux, u.uy, NO_MM_FLAGS); in_mklev = FALSE; if (!mtmp) { drop_upon_death((struct monst *)0, (struct obj *)0); return; } mtmp = christen_monst(mtmp, plname); newsym(u.ux, u.uy); Your("body rises from the dead as %s...", an(mons[u.ugrave_arise].mname)); display_nhwindow(WIN_MESSAGE, FALSE); drop_upon_death(mtmp, (struct obj *)0); m_dowear(mtmp, TRUE); } if (mtmp) { mtmp->m_lev = (u.ulevel ? u.ulevel : 1); mtmp->mhp = mtmp->mhpmax = u.uhpmax; mtmp->female = flags.female; mtmp->msleeping = 1; } for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { resetobjs(mtmp->minvent,FALSE); /* do not zero out m_ids for bones levels any more */ mtmp->mlstmv = 0L; if(mtmp->mtame) mtmp->mtame = mtmp->mpeaceful = 0; } for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { ttmp->madeby_u = 0; ttmp->tseen = (ttmp->ttyp == HOLE); } resetobjs(fobj,FALSE); resetobjs(level.buriedobjlist, FALSE); /* Hero is no longer on the map. */ u.ux = u.uy = 0; /* Clear all memory from the level. */ for(x=0; x freediskspace(bones)) { /* not enough room */ # ifdef WIZARD if (wizard) pline("Insufficient space to create bones file."); # endif (void) close(fd); cancel_bonesfile(); return; } co_false(); /* make sure stuff before savelev() gets written */ } #endif /* MFLOPPY */ store_version(fd); bwrite(fd, (genericptr_t) &c, sizeof c); bwrite(fd, (genericptr_t) bonesid, (unsigned) c); /* DD.nnn */ savefruitchn(fd, WRITE_SAVE | FREE_SAVE); update_mlstmv(); /* update monsters for eventual restoration */ savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE); bclose(fd); commit_bonesfile(&u.uz); compress_bonesfile(); } int getbones() { register int fd; register int ok; char c, *bonesid, oldbonesid[10]; if(discover) /* save bones files for real games */ return(0); /* wizard check added by GAN 02/05/87 */ if(rn2(3) /* only once in three times do we find bones */ #ifdef WIZARD && !wizard #endif ) return(0); if(no_bones_level(&u.uz)) return(0); fd = open_bonesfile(&u.uz, &bonesid); if (fd < 0) return(0); if ((ok = uptodate(fd, bones)) == 0) { #ifdef WIZARD if (!wizard) #endif pline("Discarding unuseable bones; no need to panic..."); } else { #ifdef WIZARD if(wizard) { if(yn("Get bones?") == 'n') { (void) close(fd); compress_bonesfile(); return(0); } } #endif mread(fd, (genericptr_t) &c, sizeof c); /* length incl. '\0' */ mread(fd, (genericptr_t) oldbonesid, (unsigned) c); /* DD.nnn */ if (strcmp(bonesid, oldbonesid) != 0) { char errbuf[BUFSZ]; Sprintf(errbuf, "This is bones level '%s', not '%s'!", oldbonesid, bonesid); #ifdef WIZARD if (wizard) { pline("%s", errbuf); ok = FALSE; /* won't die of trickery */ } #endif trickery(errbuf); } else { register struct monst *mtmp; getlev(fd, 0, 0, TRUE); /* Note that getlev() now keeps tabs on unique * monsters such as demon lords, and tracks the * birth counts of all species just as makemon() * does. If a bones monster is extinct or has been * subject to genocide, their mhpmax will be * set to the magic DEFUNCT_MONSTER cookie value. */ for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (mtmp->mhpmax == DEFUNCT_MONSTER) { #if defined(DEBUG) && defined(WIZARD) if (wizard) pline("Removing defunct monster %s from bones.", mtmp->data->mname); #endif mongone(mtmp); } else /* to correctly reset named artifacts on the level */ resetobjs(mtmp->minvent,TRUE); } resetobjs(fobj,TRUE); resetobjs(level.buriedobjlist,TRUE); } } (void) close(fd); #ifdef WIZARD if(wizard) { if(yn("Unlink bones?") == 'n') { compress_bonesfile(); return(ok); } } #endif if (!delete_bonesfile(&u.uz)) { /* When N games try to simultaneously restore the same * bones file, N-1 of them will fail to delete it * (the first N-1 under AmigaDOS, the last N-1 under UNIX). * So no point in a mysterious message for a normal event * -- just generate a new level for those N-1 games. */ /* pline("Cannot unlink bones."); */ return(0); } return(ok); } /*bones.c*/ nethack-3.4.3/src/botl.c0100644000000000000000000001632707764735041013556 0ustar rootroot/* SCCS Id: @(#)botl.c 3.4 1996/07/15 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef OVL0 extern const char *hu_stat[]; /* defined in eat.c */ const char * const enc_stat[] = { "", "Burdened", "Stressed", "Strained", "Overtaxed", "Overloaded" }; STATIC_DCL void NDECL(bot1); STATIC_DCL void NDECL(bot2); #endif /* OVL0 */ /* MAXCO must hold longest uncompressed status line, and must be larger * than COLNO * * longest practical second status line at the moment is * Astral Plane $:12345 HP:700(700) Pw:111(111) AC:-127 Xp:30/123456789 * T:123456 Satiated Conf FoodPois Ill Blind Stun Hallu Overloaded * -- or somewhat over 130 characters */ #if COLNO <= 140 #define MAXCO 160 #else #define MAXCO (COLNO+20) #endif #ifndef OVLB STATIC_DCL int mrank_sz; #else /* OVLB */ STATIC_OVL NEARDATA int mrank_sz = 0; /* loaded by max_rank_sz (from u_init) */ #endif /* OVLB */ STATIC_DCL const char *NDECL(rank); #ifdef OVL1 /* convert experience level (1..30) to rank index (0..8) */ int xlev_to_rank(xlev) int xlev; { return (xlev <= 2) ? 0 : (xlev <= 30) ? ((xlev + 2) / 4) : 8; } #if 0 /* not currently needed */ /* convert rank index (0..8) to experience level (1..30) */ int rank_to_xlev(rank) int rank; { return (rank <= 0) ? 1 : (rank <= 8) ? ((rank * 4) - 2) : 30; } #endif const char * rank_of(lev, monnum, female) int lev; short monnum; boolean female; { register struct Role *role; register int i; /* Find the role */ for (role = (struct Role *) roles; role->name.m; role++) if (monnum == role->malenum || monnum == role->femalenum) break; if (!role->name.m) role = &urole; /* Find the rank */ for (i = xlev_to_rank((int)lev); i >= 0; i--) { if (female && role->rank[i].f) return (role->rank[i].f); if (role->rank[i].m) return (role->rank[i].m); } /* Try the role name, instead */ if (female && role->name.f) return (role->name.f); else if (role->name.m) return (role->name.m); return ("Player"); } STATIC_OVL const char * rank() { return(rank_of(u.ulevel, Role_switch, flags.female)); } int title_to_mon(str, rank_indx, title_length) const char *str; int *rank_indx, *title_length; { register int i, j; /* Loop through each of the roles */ for (i = 0; roles[i].name.m; i++) for (j = 0; j < 9; j++) { if (roles[i].rank[j].m && !strncmpi(str, roles[i].rank[j].m, strlen(roles[i].rank[j].m))) { if (rank_indx) *rank_indx = j; if (title_length) *title_length = strlen(roles[i].rank[j].m); return roles[i].malenum; } if (roles[i].rank[j].f && !strncmpi(str, roles[i].rank[j].f, strlen(roles[i].rank[j].f))) { if (rank_indx) *rank_indx = j; if (title_length) *title_length = strlen(roles[i].rank[j].f); return ((roles[i].femalenum != NON_PM) ? roles[i].femalenum : roles[i].malenum); } } return NON_PM; } #endif /* OVL1 */ #ifdef OVLB void max_rank_sz() { register int i, r, maxr = 0; for (i = 0; i < 9; i++) { if (urole.rank[i].m && (r = strlen(urole.rank[i].m)) > maxr) maxr = r; if (urole.rank[i].f && (r = strlen(urole.rank[i].f)) > maxr) maxr = r; } mrank_sz = maxr; return; } #endif /* OVLB */ #ifdef OVL0 #ifdef SCORE_ON_BOTL long botl_score() { int deepest = deepest_lev_reached(FALSE); #ifndef GOLDOBJ long ugold = u.ugold + hidden_gold(); if ((ugold -= u.ugold0) < 0L) ugold = 0L; return ugold + u.urexp + (long)(50 * (deepest - 1)) #else long umoney = money_cnt(invent) + hidden_gold(); if ((umoney -= u.umoney0) < 0L) umoney = 0L; return umoney + u.urexp + (long)(50 * (deepest - 1)) #endif + (long)(deepest > 30 ? 10000 : deepest > 20 ? 1000*(deepest - 20) : 0); } #endif STATIC_OVL void bot1() { char newbot1[MAXCO]; register char *nb; register int i,j; Strcpy(newbot1, plname); if('a' <= newbot1[0] && newbot1[0] <= 'z') newbot1[0] += 'A'-'a'; newbot1[10] = 0; Sprintf(nb = eos(newbot1)," the "); if (Upolyd) { char mbot[BUFSZ]; int k = 0; Strcpy(mbot, mons[u.umonnum].mname); while(mbot[k] != 0) { if ((k == 0 || (k > 0 && mbot[k-1] == ' ')) && 'a' <= mbot[k] && mbot[k] <= 'z') mbot[k] += 'A' - 'a'; k++; } Sprintf(nb = eos(nb), mbot); } else Sprintf(nb = eos(nb), rank()); Sprintf(nb = eos(nb)," "); i = mrank_sz + 15; j = (nb + 2) - newbot1; /* aka strlen(newbot1) but less computation */ if((i - j) > 0) Sprintf(nb = eos(nb),"%*s", i-j, " "); /* pad with spaces */ if (ACURR(A_STR) > 18) { if (ACURR(A_STR) > STR18(100)) Sprintf(nb = eos(nb),"St:%2d ",ACURR(A_STR)-100); else if (ACURR(A_STR) < STR18(100)) Sprintf(nb = eos(nb), "St:18/%02d ",ACURR(A_STR)-18); else Sprintf(nb = eos(nb),"St:18/** "); } else Sprintf(nb = eos(nb), "St:%-1d ",ACURR(A_STR)); Sprintf(nb = eos(nb), "Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d", ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA)); Sprintf(nb = eos(nb), (u.ualign.type == A_CHAOTIC) ? " Chaotic" : (u.ualign.type == A_NEUTRAL) ? " Neutral" : " Lawful"); #ifdef SCORE_ON_BOTL if (flags.showscore) Sprintf(nb = eos(nb), " S:%ld", botl_score()); #endif curs(WIN_STATUS, 1, 0); putstr(WIN_STATUS, 0, newbot1); } /* provide the name of the current level for display by various ports */ int describe_level(buf) char *buf; { int ret = 1; /* TODO: Add in dungeon name */ if (Is_knox(&u.uz)) Sprintf(buf, "%s ", dungeons[u.uz.dnum].dname); else if (In_quest(&u.uz)) Sprintf(buf, "Home %d ", dunlev(&u.uz)); else if (In_endgame(&u.uz)) Sprintf(buf, Is_astralevel(&u.uz) ? "Astral Plane " : "End Game "); else { /* ports with more room may expand this one */ Sprintf(buf, "Dlvl:%-2d ", depth(&u.uz)); ret = 0; } return ret; } STATIC_OVL void bot2() { char newbot2[MAXCO]; register char *nb; int hp, hpmax; int cap = near_capacity(); hp = Upolyd ? u.mh : u.uhp; hpmax = Upolyd ? u.mhmax : u.uhpmax; if(hp < 0) hp = 0; (void) describe_level(newbot2); Sprintf(nb = eos(newbot2), "%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[COIN_CLASS], #ifndef GOLDOBJ u.ugold, #else money_cnt(invent), #endif hp, hpmax, u.uen, u.uenmax, u.uac); if (Upolyd) Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel); #ifdef EXP_ON_BOTL else if(flags.showexp) Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel,u.uexp); #endif else Sprintf(nb = eos(nb), " Exp:%u", u.ulevel); if(flags.time) Sprintf(nb = eos(nb), " T:%ld", moves); if(strcmp(hu_stat[u.uhs], " ")) { Sprintf(nb = eos(nb), " "); Strcat(newbot2, hu_stat[u.uhs]); } if(Confusion) Sprintf(nb = eos(nb), " Conf"); if(Sick) { if (u.usick_type & SICK_VOMITABLE) Sprintf(nb = eos(nb), " FoodPois"); if (u.usick_type & SICK_NONVOMITABLE) Sprintf(nb = eos(nb), " Ill"); } if(Blind) Sprintf(nb = eos(nb), " Blind"); if(Stunned) Sprintf(nb = eos(nb), " Stun"); if(Hallucination) Sprintf(nb = eos(nb), " Hallu"); if(Slimed) Sprintf(nb = eos(nb), " Slime"); if(cap > UNENCUMBERED) Sprintf(nb = eos(nb), " %s", enc_stat[cap]); curs(WIN_STATUS, 1, 1); putstr(WIN_STATUS, 0, newbot2); } void bot() { bot1(); bot2(); flags.botl = flags.botlx = 0; } #endif /* OVL0 */ /*botl.c*/ nethack-3.4.3/src/cmd.c0100644000000000000000000020765607764735041013370 0ustar rootroot/* SCCS Id: @(#)cmd.c 3.4 2003/02/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "func_tab.h" /* #define DEBUG */ /* uncomment for debugging */ /* * Some systems may have getchar() return EOF for various reasons, and * we should not quit before seeing at least NR_OF_EOFS consecutive EOFs. */ #if defined(SYSV) || defined(DGUX) || defined(HPUX) #define NR_OF_EOFS 20 #endif #define CMD_TRAVEL (char)0x90 #ifdef DEBUG /* * only one "wiz_debug_cmd" routine should be available (in whatever * module you are trying to debug) or things are going to get rather * hard to link :-) */ extern int NDECL(wiz_debug_cmd); #endif #ifdef DUMB /* stuff commented out in extern.h, but needed here */ extern int NDECL(doapply); /**/ extern int NDECL(dorub); /**/ extern int NDECL(dojump); /**/ extern int NDECL(doextlist); /**/ extern int NDECL(dodrop); /**/ extern int NDECL(doddrop); /**/ extern int NDECL(dodown); /**/ extern int NDECL(doup); /**/ extern int NDECL(donull); /**/ extern int NDECL(dowipe); /**/ extern int NDECL(do_mname); /**/ extern int NDECL(ddocall); /**/ extern int NDECL(dotakeoff); /**/ extern int NDECL(doremring); /**/ extern int NDECL(dowear); /**/ extern int NDECL(doputon); /**/ extern int NDECL(doddoremarm); /**/ extern int NDECL(dokick); /**/ extern int NDECL(dofire); /**/ extern int NDECL(dothrow); /**/ extern int NDECL(doeat); /**/ extern int NDECL(done2); /**/ extern int NDECL(doengrave); /**/ extern int NDECL(dopickup); /**/ extern int NDECL(ddoinv); /**/ extern int NDECL(dotypeinv); /**/ extern int NDECL(dolook); /**/ extern int NDECL(doprgold); /**/ extern int NDECL(doprwep); /**/ extern int NDECL(doprarm); /**/ extern int NDECL(doprring); /**/ extern int NDECL(dopramulet); /**/ extern int NDECL(doprtool); /**/ extern int NDECL(dosuspend); /**/ extern int NDECL(doforce); /**/ extern int NDECL(doopen); /**/ extern int NDECL(doclose); /**/ extern int NDECL(dosh); /**/ extern int NDECL(dodiscovered); /**/ extern int NDECL(doset); /**/ extern int NDECL(dotogglepickup); /**/ extern int NDECL(dowhatis); /**/ extern int NDECL(doquickwhatis); /**/ extern int NDECL(dowhatdoes); /**/ extern int NDECL(dohelp); /**/ extern int NDECL(dohistory); /**/ extern int NDECL(doloot); /**/ extern int NDECL(dodrink); /**/ extern int NDECL(dodip); /**/ extern int NDECL(dosacrifice); /**/ extern int NDECL(dopray); /**/ extern int NDECL(doturn); /**/ extern int NDECL(doredraw); /**/ extern int NDECL(doread); /**/ extern int NDECL(dosave); /**/ extern int NDECL(dosearch); /**/ extern int NDECL(doidtrap); /**/ extern int NDECL(dopay); /**/ extern int NDECL(dosit); /**/ extern int NDECL(dotalk); /**/ extern int NDECL(docast); /**/ extern int NDECL(dovspell); /**/ extern int NDECL(dotele); /**/ extern int NDECL(dountrap); /**/ extern int NDECL(doversion); /**/ extern int NDECL(doextversion); /**/ extern int NDECL(doswapweapon); /**/ extern int NDECL(dowield); /**/ extern int NDECL(dowieldquiver); /**/ extern int NDECL(dozap); /**/ extern int NDECL(doorganize); /**/ #endif /* DUMB */ #ifdef OVL1 static int NDECL((*timed_occ_fn)); #endif /* OVL1 */ STATIC_PTR int NDECL(doprev_message); STATIC_PTR int NDECL(timed_occupation); STATIC_PTR int NDECL(doextcmd); STATIC_PTR int NDECL(domonability); STATIC_PTR int NDECL(dotravel); # ifdef WIZARD STATIC_PTR int NDECL(wiz_wish); STATIC_PTR int NDECL(wiz_identify); STATIC_PTR int NDECL(wiz_map); STATIC_PTR int NDECL(wiz_genesis); STATIC_PTR int NDECL(wiz_where); STATIC_PTR int NDECL(wiz_detect); STATIC_PTR int NDECL(wiz_panic); STATIC_PTR int NDECL(wiz_polyself); STATIC_PTR int NDECL(wiz_level_tele); STATIC_PTR int NDECL(wiz_level_change); STATIC_PTR int NDECL(wiz_show_seenv); STATIC_PTR int NDECL(wiz_show_vision); STATIC_PTR int NDECL(wiz_mon_polycontrol); STATIC_PTR int NDECL(wiz_show_wmodes); #if defined(__BORLANDC__) && !defined(_WIN32) extern void FDECL(show_borlandc_stats, (winid)); #endif #ifdef DEBUG_MIGRATING_MONS STATIC_PTR int NDECL(wiz_migrate_mons); #endif STATIC_DCL void FDECL(count_obj, (struct obj *, long *, long *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(obj_chain, (winid, const char *, struct obj *, long *, long *)); STATIC_DCL void FDECL(mon_invent_chain, (winid, const char *, struct monst *, long *, long *)); STATIC_DCL void FDECL(mon_chain, (winid, const char *, struct monst *, long *, long *)); STATIC_DCL void FDECL(contained, (winid, const char *, long *, long *)); STATIC_PTR int NDECL(wiz_show_stats); # ifdef PORT_DEBUG STATIC_DCL int NDECL(wiz_port_debug); # endif # endif STATIC_PTR int NDECL(enter_explore_mode); STATIC_PTR int NDECL(doattributes); STATIC_PTR int NDECL(doconduct); /**/ STATIC_PTR boolean NDECL(minimal_enlightenment); #ifdef OVLB STATIC_DCL void FDECL(enlght_line, (const char *,const char *,const char *)); STATIC_DCL char *FDECL(enlght_combatinc, (const char *,int,int,char *)); #ifdef UNIX static void NDECL(end_of_input); #endif #endif /* OVLB */ static const char* readchar_queue=""; STATIC_DCL char *NDECL(parse); STATIC_DCL boolean FDECL(help_dir, (CHAR_P,const char *)); #ifdef OVL1 STATIC_PTR int doprev_message() { return nh_doprev_message(); } /* Count down by decrementing multi */ STATIC_PTR int timed_occupation() { (*timed_occ_fn)(); if (multi > 0) multi--; return multi > 0; } /* If you have moved since initially setting some occupations, they * now shouldn't be able to restart. * * The basic rule is that if you are carrying it, you can continue * since it is with you. If you are acting on something at a distance, * your orientation to it must have changed when you moved. * * The exception to this is taking off items, since they can be taken * off in a number of ways in the intervening time, screwing up ordering. * * Currently: Take off all armor. * Picking Locks / Forcing Chests. * Setting traps. */ void reset_occupations() { reset_remarm(); reset_pick(); reset_trapset(); } /* If a time is given, use it to timeout this function, otherwise the * function times out by its own means. */ void set_occupation(fn, txt, xtime) int NDECL((*fn)); const char *txt; int xtime; { if (xtime) { occupation = timed_occupation; timed_occ_fn = fn; } else occupation = fn; occtxt = txt; occtime = 0; return; } #ifdef REDO static char NDECL(popch); /* Provide a means to redo the last command. The flag `in_doagain' is set * to true while redoing the command. This flag is tested in commands that * require additional input (like `throw' which requires a thing and a * direction), and the input prompt is not shown. Also, while in_doagain is * TRUE, no keystrokes can be saved into the saveq. */ #define BSIZE 20 static char pushq[BSIZE], saveq[BSIZE]; static NEARDATA int phead, ptail, shead, stail; static char popch() { /* If occupied, return '\0', letting tgetch know a character should * be read from the keyboard. If the character read is not the * ABORT character (as checked in pcmain.c), that character will be * pushed back on the pushq. */ if (occupation) return '\0'; if (in_doagain) return(char)((shead != stail) ? saveq[stail++] : '\0'); else return(char)((phead != ptail) ? pushq[ptail++] : '\0'); } char pgetchar() { /* curtesy of aeb@cwi.nl */ register int ch; if(!(ch = popch())) ch = nhgetch(); return((char)ch); } /* A ch == 0 resets the pushq */ void pushch(ch) char ch; { if (!ch) phead = ptail = 0; if (phead < BSIZE) pushq[phead++] = ch; return; } /* A ch == 0 resets the saveq. Only save keystrokes when not * replaying a previous command. */ void savech(ch) char ch; { if (!in_doagain) { if (!ch) phead = ptail = shead = stail = 0; else if (shead < BSIZE) saveq[shead++] = ch; } return; } #endif /* REDO */ #endif /* OVL1 */ #ifdef OVLB STATIC_PTR int doextcmd() /* here after # - now read a full-word command */ { int idx, retval; /* keep repeating until we don't run help or quit */ do { idx = get_ext_cmd(); if (idx < 0) return 0; /* quit */ retval = (*extcmdlist[idx].ef_funct)(); } while (extcmdlist[idx].ef_funct == doextlist); return retval; } int doextlist() /* here after #? - now list all full-word commands */ { register const struct ext_func_tab *efp; char buf[BUFSZ]; winid datawin; datawin = create_nhwindow(NHW_TEXT); putstr(datawin, 0, ""); putstr(datawin, 0, " Extended Commands List"); putstr(datawin, 0, ""); putstr(datawin, 0, " Press '#', then type:"); putstr(datawin, 0, ""); for(efp = extcmdlist; efp->ef_txt; efp++) { Sprintf(buf, " %-15s - %s.", efp->ef_txt, efp->ef_desc); putstr(datawin, 0, buf); } display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); return 0; } #ifdef TTY_GRAPHICS #define MAX_EXT_CMD 40 /* Change if we ever have > 40 ext cmds */ /* * This is currently used only by the tty port and is * controlled via runtime option 'extmenu' */ int extcmd_via_menu() /* here after # - now show pick-list of possible commands */ { const struct ext_func_tab *efp; menu_item *pick_list = (menu_item *)0; winid win; anything any; const struct ext_func_tab *choices[MAX_EXT_CMD]; char buf[BUFSZ]; char cbuf[QBUFSZ], prompt[QBUFSZ], fmtstr[20]; int i, n, nchoices, acount; int ret, biggest; int accelerator, prevaccelerator; int matchlevel = 0; ret = 0; cbuf[0] = '\0'; biggest = 0; while (!ret) { i = n = 0; accelerator = 0; any.a_void = 0; /* populate choices */ for(efp = extcmdlist; efp->ef_txt; efp++) { if (!matchlevel || !strncmp(efp->ef_txt, cbuf, matchlevel)) { choices[i++] = efp; if ((int)strlen(efp->ef_desc) > biggest) { biggest = strlen(efp->ef_desc); Sprintf(fmtstr,"%%-%ds", biggest + 15); } #ifdef DEBUG if (i >= MAX_EXT_CMD - 2) { impossible("Exceeded %d extended commands in doextcmd() menu", MAX_EXT_CMD - 2); return 0; } #endif } } choices[i] = (struct ext_func_tab *)0; nchoices = i; /* if we're down to one, we have our selection so get out of here */ if (nchoices == 1) { for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++) if (!strncmpi(extcmdlist[i].ef_txt, cbuf, matchlevel)) { ret = i; break; } break; } /* otherwise... */ win = create_nhwindow(NHW_MENU); start_menu(win); prevaccelerator = 0; acount = 0; for(i = 0; choices[i]; ++i) { accelerator = choices[i]->ef_txt[matchlevel]; if (accelerator != prevaccelerator || nchoices < (ROWNO - 3)) { if (acount) { /* flush the extended commands for that letter already in buf */ Sprintf(buf, fmtstr, prompt); any.a_char = prevaccelerator; add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE); acount = 0; } } prevaccelerator = accelerator; if (!acount || nchoices < (ROWNO - 3)) { Sprintf(prompt, "%s [%s]", choices[i]->ef_txt, choices[i]->ef_desc); } else if (acount == 1) { Sprintf(prompt, "%s or %s", choices[i-1]->ef_txt, choices[i]->ef_txt); } else { Strcat(prompt," or "); Strcat(prompt, choices[i]->ef_txt); } ++acount; } if (acount) { /* flush buf */ Sprintf(buf, fmtstr, prompt); any.a_char = prevaccelerator; add_menu(win, NO_GLYPH, &any, any.a_char, 0, ATR_NONE, buf, FALSE); } Sprintf(prompt, "Extended Command: %s", cbuf); end_menu(win, prompt); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); if (n==1) { if (matchlevel > (QBUFSZ - 2)) { free((genericptr_t)pick_list); #ifdef DEBUG impossible("Too many characters (%d) entered in extcmd_via_menu()", matchlevel); #endif ret = -1; } else { cbuf[matchlevel++] = pick_list[0].item.a_char; cbuf[matchlevel] = '\0'; free((genericptr_t)pick_list); } } else { if (matchlevel) { ret = 0; matchlevel = 0; } else ret = -1; } } return ret; } #endif /* #monster command - use special monster ability while polymorphed */ STATIC_PTR int domonability() { if (can_breathe(youmonst.data)) return dobreathe(); else if (attacktype(youmonst.data, AT_SPIT)) return dospit(); else if (youmonst.data->mlet == S_NYMPH) return doremove(); else if (attacktype(youmonst.data, AT_GAZE)) return dogaze(); else if (is_were(youmonst.data)) return dosummon(); else if (webmaker(youmonst.data)) return dospinweb(); else if (is_hider(youmonst.data)) return dohide(); else if (is_mind_flayer(youmonst.data)) return domindblast(); else if (u.umonnum == PM_GREMLIN) { if(IS_FOUNTAIN(levl[u.ux][u.uy].typ)) { if (split_mon(&youmonst, (struct monst *)0)) dryup(u.ux, u.uy, TRUE); } else There("is no fountain here."); } else if (is_unicorn(youmonst.data)) { use_unicorn_horn((struct obj *)0); return 1; } else if (youmonst.data->msound == MS_SHRIEK) { You("shriek."); if(u.uburied) pline("Unfortunately sound does not carry well through rock."); else aggravate(); } else if (Upolyd) pline("Any special ability you may have is purely reflexive."); else You("don't have a special ability in your normal form!"); return 0; } STATIC_PTR int enter_explore_mode() { if(!discover && !wizard) { pline("Beware! From explore mode there will be no return to normal game."); if (yn("Do you want to enter explore mode?") == 'y') { clear_nhwindow(WIN_MESSAGE); You("are now in non-scoring explore mode."); discover = TRUE; } else { clear_nhwindow(WIN_MESSAGE); pline("Resuming normal game."); } } return 0; } #ifdef WIZARD /* ^W command - wish for something */ STATIC_PTR int wiz_wish() /* Unlimited wishes for debug mode by Paul Polderman */ { if (wizard) { boolean save_verbose = flags.verbose; flags.verbose = FALSE; makewish(); flags.verbose = save_verbose; (void) encumber_msg(); } else pline("Unavailable command '^W'."); return 0; } /* ^I command - identify hero's inventory */ STATIC_PTR int wiz_identify() { if (wizard) identify_pack(0); else pline("Unavailable command '^I'."); return 0; } /* ^F command - reveal the level map and any traps on it */ STATIC_PTR int wiz_map() { if (wizard) { struct trap *t; long save_Hconf = HConfusion, save_Hhallu = HHallucination; HConfusion = HHallucination = 0L; for (t = ftrap; t != 0; t = t->ntrap) { t->tseen = 1; map_trap(t, TRUE); } do_mapping(); HConfusion = save_Hconf; HHallucination = save_Hhallu; } else pline("Unavailable command '^F'."); return 0; } /* ^G command - generate monster(s); a count prefix will be honored */ STATIC_PTR int wiz_genesis() { if (wizard) (void) create_particular(); else pline("Unavailable command '^G'."); return 0; } /* ^O command - display dungeon layout */ STATIC_PTR int wiz_where() { if (wizard) (void) print_dungeon(FALSE, (schar *)0, (xchar *)0); else pline("Unavailable command '^O'."); return 0; } /* ^E command - detect unseen (secret doors, traps, hidden monsters) */ STATIC_PTR int wiz_detect() { if(wizard) (void) findit(); else pline("Unavailable command '^E'."); return 0; } /* ^V command - level teleport */ STATIC_PTR int wiz_level_tele() { if (wizard) level_tele(); else pline("Unavailable command '^V'."); return 0; } /* #monpolycontrol command - choose new form for shapechangers, polymorphees */ STATIC_PTR int wiz_mon_polycontrol() { iflags.mon_polycontrol = !iflags.mon_polycontrol; pline("Monster polymorph control is %s.", iflags.mon_polycontrol ? "on" : "off"); return 0; } /* #levelchange command - adjust hero's experience level */ STATIC_PTR int wiz_level_change() { char buf[BUFSZ]; int newlevel; int ret; getlin("To what experience level do you want to be set?", buf); (void)mungspaces(buf); if (buf[0] == '\033' || buf[0] == '\0') ret = 0; else ret = sscanf(buf, "%d", &newlevel); if (ret != 1) { pline(Never_mind); return 0; } if (newlevel == u.ulevel) { You("are already that experienced."); } else if (newlevel < u.ulevel) { if (u.ulevel == 1) { You("are already as inexperienced as you can get."); return 0; } if (newlevel < 1) newlevel = 1; while (u.ulevel > newlevel) losexp("#levelchange"); } else { if (u.ulevel >= MAXULEV) { You("are already as experienced as you can get."); return 0; } if (newlevel > MAXULEV) newlevel = MAXULEV; while (u.ulevel < newlevel) pluslvl(FALSE); } u.ulevelmax = u.ulevel; return 0; } /* #panic command - test program's panic handling */ STATIC_PTR int wiz_panic() { if (yn("Do you want to call panic() and end your game?") == 'y') panic("crash test."); return 0; } /* #polyself command - change hero's form */ STATIC_PTR int wiz_polyself() { polyself(TRUE); return 0; } /* #seenv command */ STATIC_PTR int wiz_show_seenv() { winid win; int x, y, v, startx, stopx, curx; char row[COLNO+1]; win = create_nhwindow(NHW_TEXT); /* * Each seenv description takes up 2 characters, so center * the seenv display around the hero. */ startx = max(1, u.ux-(COLNO/4)); stopx = min(startx+(COLNO/2), COLNO); /* can't have a line exactly 80 chars long */ if (stopx - startx == COLNO/2) startx++; for (y = 0; y < ROWNO; y++) { for (x = startx, curx = 0; x < stopx; x++, curx += 2) { if (x == u.ux && y == u.uy) { row[curx] = row[curx+1] = '@'; } else { v = levl[x][y].seenv & 0xff; if (v == 0) row[curx] = row[curx+1] = ' '; else Sprintf(&row[curx], "%02x", v); } } /* remove trailing spaces */ for (x = curx-1; x >= 0; x--) if (row[x] != ' ') break; row[x+1] = '\0'; putstr(win, 0, row); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } /* #vision command */ STATIC_PTR int wiz_show_vision() { winid win; int x, y, v; char row[COLNO+1]; win = create_nhwindow(NHW_TEXT); Sprintf(row, "Flags: 0x%x could see, 0x%x in sight, 0x%x temp lit", COULD_SEE, IN_SIGHT, TEMP_LIT); putstr(win, 0, row); putstr(win, 0, ""); for (y = 0; y < ROWNO; y++) { for (x = 1; x < COLNO; x++) { if (x == u.ux && y == u.uy) row[x] = '@'; else { v = viz_array[y][x]; /* data access should be hidden */ if (v == 0) row[x] = ' '; else row[x] = '0' + viz_array[y][x]; } } /* remove trailing spaces */ for (x = COLNO-1; x >= 1; x--) if (row[x] != ' ') break; row[x+1] = '\0'; putstr(win, 0, &row[1]); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } /* #wmode command */ STATIC_PTR int wiz_show_wmodes() { winid win; int x,y; char row[COLNO+1]; struct rm *lev; win = create_nhwindow(NHW_TEXT); for (y = 0; y < ROWNO; y++) { for (x = 0; x < COLNO; x++) { lev = &levl[x][y]; if (x == u.ux && y == u.uy) row[x] = '@'; else if (IS_WALL(lev->typ) || lev->typ == SDOOR) row[x] = '0' + (lev->wall_info & WM_MASK); else if (lev->typ == CORR) row[x] = '#'; else if (IS_ROOM(lev->typ) || IS_DOOR(lev->typ)) row[x] = '.'; else row[x] = 'x'; } row[COLNO] = '\0'; putstr(win, 0, row); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } #endif /* WIZARD */ /* -enlightenment and conduct- */ static winid en_win; static const char You_[] = "You ", are[] = "are ", were[] = "were ", have[] = "have ", had[] = "had ", can[] = "can ", could[] = "could "; static const char have_been[] = "have been ", have_never[] = "have never ", never[] = "never "; #define enl_msg(prefix,present,past,suffix) \ enlght_line(prefix, final ? past : present, suffix) #define you_are(attr) enl_msg(You_,are,were,attr) #define you_have(attr) enl_msg(You_,have,had,attr) #define you_can(attr) enl_msg(You_,can,could,attr) #define you_have_been(goodthing) enl_msg(You_,have_been,were,goodthing) #define you_have_never(badthing) enl_msg(You_,have_never,never,badthing) #define you_have_X(something) enl_msg(You_,have,(const char *)"",something) static void enlght_line(start, middle, end) const char *start, *middle, *end; { char buf[BUFSZ]; Sprintf(buf, "%s%s%s.", start, middle, end); putstr(en_win, 0, buf); } /* format increased damage or chance to hit */ static char * enlght_combatinc(inctyp, incamt, final, outbuf) const char *inctyp; int incamt, final; char *outbuf; { char numbuf[24]; const char *modif, *bonus; if (final #ifdef WIZARD || wizard #endif ) { Sprintf(numbuf, "%s%d", (incamt > 0) ? "+" : "", incamt); modif = (const char *) numbuf; } else { int absamt = abs(incamt); if (absamt <= 3) modif = "small"; else if (absamt <= 6) modif = "moderate"; else if (absamt <= 12) modif = "large"; else modif = "huge"; } bonus = (incamt > 0) ? "bonus" : "penalty"; /* "bonus to hit" vs "damage bonus" */ if (!strcmp(inctyp, "damage")) { const char *ctmp = inctyp; inctyp = bonus; bonus = ctmp; } Sprintf(outbuf, "%s %s %s", an(modif), bonus, inctyp); return outbuf; } void enlightenment(final) int final; /* 0 => still in progress; 1 => over, survived; 2 => dead */ { int ltmp; char buf[BUFSZ]; en_win = create_nhwindow(NHW_MENU); putstr(en_win, 0, final ? "Final Attributes:" : "Current Attributes:"); putstr(en_win, 0, ""); #ifdef ELBERETH if (u.uevent.uhand_of_elbereth) { static const char * const hofe_titles[3] = { "the Hand of Elbereth", "the Envoy of Balance", "the Glory of Arioch" }; you_are(hofe_titles[u.uevent.uhand_of_elbereth - 1]); } #endif /* note: piousness 20 matches MIN_QUEST_ALIGN (quest.h) */ if (u.ualign.record >= 20) you_are("piously aligned"); else if (u.ualign.record > 13) you_are("devoutly aligned"); else if (u.ualign.record > 8) you_are("fervently aligned"); else if (u.ualign.record > 3) you_are("stridently aligned"); else if (u.ualign.record == 3) you_are("aligned"); else if (u.ualign.record > 0) you_are("haltingly aligned"); else if (u.ualign.record == 0) you_are("nominally aligned"); else if (u.ualign.record >= -3) you_have("strayed"); else if (u.ualign.record >= -8) you_have("sinned"); else you_have("transgressed"); #ifdef WIZARD if (wizard) { Sprintf(buf, " %d", u.ualign.record); enl_msg("Your alignment ", "is", "was", buf); } #endif /*** Resistances to troubles ***/ if (Fire_resistance) you_are("fire resistant"); if (Cold_resistance) you_are("cold resistant"); if (Sleep_resistance) you_are("sleep resistant"); if (Disint_resistance) you_are("disintegration-resistant"); if (Shock_resistance) you_are("shock resistant"); if (Poison_resistance) you_are("poison resistant"); if (Drain_resistance) you_are("level-drain resistant"); if (Sick_resistance) you_are("immune to sickness"); if (Antimagic) you_are("magic-protected"); if (Acid_resistance) you_are("acid resistant"); if (Stone_resistance) you_are("petrification resistant"); if (Invulnerable) you_are("invulnerable"); if (u.uedibility) you_can("recognize detrimental food"); /*** Troubles ***/ if (Halluc_resistance) enl_msg("You resist", "", "ed", " hallucinations"); if (final) { if (Hallucination) you_are("hallucinating"); if (Stunned) you_are("stunned"); if (Confusion) you_are("confused"); if (Blinded) you_are("blinded"); if (Sick) { if (u.usick_type & SICK_VOMITABLE) you_are("sick from food poisoning"); if (u.usick_type & SICK_NONVOMITABLE) you_are("sick from illness"); } } if (Stoned) you_are("turning to stone"); if (Slimed) you_are("turning into slime"); if (Strangled) you_are((u.uburied) ? "buried" : "being strangled"); if (Glib) { Sprintf(buf, "slippery %s", makeplural(body_part(FINGER))); you_have(buf); } if (Fumbling) enl_msg("You fumble", "", "d", ""); if (Wounded_legs #ifdef STEED && !u.usteed #endif ) { Sprintf(buf, "wounded %s", makeplural(body_part(LEG))); you_have(buf); } #if defined(WIZARD) && defined(STEED) if (Wounded_legs && u.usteed && wizard) { Strcpy(buf, x_monnam(u.usteed, ARTICLE_YOUR, (char *)0, SUPPRESS_SADDLE | SUPPRESS_HALLUCINATION, FALSE)); *buf = highc(*buf); enl_msg(buf, " has", " had", " wounded legs"); } #endif if (Sleeping) enl_msg("You ", "fall", "fell", " asleep"); if (Hunger) enl_msg("You hunger", "", "ed", " rapidly"); /*** Vision and senses ***/ if (See_invisible) enl_msg(You_, "see", "saw", " invisible"); if (Blind_telepat) you_are("telepathic"); if (Warning) you_are("warned"); if (Warn_of_mon && flags.warntype) { Sprintf(buf, "aware of the presence of %s", (flags.warntype & M2_ORC) ? "orcs" : (flags.warntype & M2_DEMON) ? "demons" : something); you_are(buf); } if (Undead_warning) you_are("warned of undead"); if (Searching) you_have("automatic searching"); if (Clairvoyant) you_are("clairvoyant"); if (Infravision) you_have("infravision"); if (Detect_monsters) you_are("sensing the presence of monsters"); if (u.umconf) you_are("going to confuse monsters"); /*** Appearance and behavior ***/ if (Adornment) { int adorn = 0; if(uleft && uleft->otyp == RIN_ADORNMENT) adorn += uleft->spe; if(uright && uright->otyp == RIN_ADORNMENT) adorn += uright->spe; if (adorn < 0) you_are("poorly adorned"); else you_are("adorned"); } if (Invisible) you_are("invisible"); else if (Invis) you_are("invisible to others"); /* ordinarily "visible" is redundant; this is a special case for the situation when invisibility would be an expected attribute */ else if ((HInvis || EInvis || pm_invisible(youmonst.data)) && BInvis) you_are("visible"); if (Displaced) you_are("displaced"); if (Stealth) you_are("stealthy"); if (Aggravate_monster) enl_msg("You aggravate", "", "d", " monsters"); if (Conflict) enl_msg("You cause", "", "d", " conflict"); /*** Transportation ***/ if (Jumping) you_can("jump"); if (Teleportation) you_can("teleport"); if (Teleport_control) you_have("teleport control"); if (Lev_at_will) you_are("levitating, at will"); else if (Levitation) you_are("levitating"); /* without control */ else if (Flying) you_can("fly"); if (Wwalking) you_can("walk on water"); if (Swimming) you_can("swim"); if (Breathless) you_can("survive without air"); else if (Amphibious) you_can("breathe water"); if (Passes_walls) you_can("walk through walls"); #ifdef STEED /* If you die while dismounting, u.usteed is still set. Since several * places in the done() sequence depend on u.usteed, just detect this * special case. */ if (u.usteed && (final < 2 || strcmp(killer, "riding accident"))) { Sprintf(buf, "riding %s", y_monnam(u.usteed)); you_are(buf); } #endif if (u.uswallow) { Sprintf(buf, "swallowed by %s", a_monnam(u.ustuck)); #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%u)", u.uswldtim); #endif you_are(buf); } else if (u.ustuck) { Sprintf(buf, "%s %s", (Upolyd && sticks(youmonst.data)) ? "holding" : "held by", a_monnam(u.ustuck)); you_are(buf); } /*** Physical attributes ***/ if (u.uhitinc) you_have(enlght_combatinc("to hit", u.uhitinc, final, buf)); if (u.udaminc) you_have(enlght_combatinc("damage", u.udaminc, final, buf)); if (Slow_digestion) you_have("slower digestion"); if (Regeneration) enl_msg("You regenerate", "", "d", ""); if (u.uspellprot || Protection) { int prot = 0; if(uleft && uleft->otyp == RIN_PROTECTION) prot += uleft->spe; if(uright && uright->otyp == RIN_PROTECTION) prot += uright->spe; if (HProtection & INTRINSIC) prot += u.ublessed; prot += u.uspellprot; if (prot < 0) you_are("ineffectively protected"); else you_are("protected"); } if (Protection_from_shape_changers) you_are("protected from shape changers"); if (Polymorph) you_are("polymorphing"); if (Polymorph_control) you_have("polymorph control"); if (u.ulycn >= LOW_PM) { Strcpy(buf, an(mons[u.ulycn].mname)); you_are(buf); } if (Upolyd) { if (u.umonnum == u.ulycn) Strcpy(buf, "in beast form"); else Sprintf(buf, "polymorphed into %s", an(youmonst.data->mname)); #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%d)", u.mtimedone); #endif you_are(buf); } if (Unchanging) you_can("not change from your current form"); if (Fast) you_are(Very_fast ? "very fast" : "fast"); if (Reflecting) you_have("reflection"); if (Free_action) you_have("free action"); if (Fixed_abil) you_have("fixed abilities"); if (Lifesaved) enl_msg("Your life ", "will be", "would have been", " saved"); if (u.twoweap) you_are("wielding two weapons at once"); /*** Miscellany ***/ if (Luck) { ltmp = abs((int)Luck); Sprintf(buf, "%s%slucky", ltmp >= 10 ? "extremely " : ltmp >= 5 ? "very " : "", Luck < 0 ? "un" : ""); #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%d)", Luck); #endif you_are(buf); } #ifdef WIZARD else if (wizard) enl_msg("Your luck ", "is", "was", " zero"); #endif if (u.moreluck > 0) you_have("extra luck"); else if (u.moreluck < 0) you_have("reduced luck"); if (carrying(LUCKSTONE) || stone_luck(TRUE)) { ltmp = stone_luck(FALSE); if (ltmp <= 0) enl_msg("Bad luck ", "does", "did", " not time out for you"); if (ltmp >= 0) enl_msg("Good luck ", "does", "did", " not time out for you"); } if (u.ugangr) { Sprintf(buf, " %sangry with you", u.ugangr > 6 ? "extremely " : u.ugangr > 3 ? "very " : ""); #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%d)", u.ugangr); #endif enl_msg(u_gname(), " is", " was", buf); } else /* * We need to suppress this when the game is over, because death * can change the value calculated by can_pray(), potentially * resulting in a false claim that you could have prayed safely. */ if (!final) { #if 0 /* "can [not] safely pray" vs "could [not] have safely prayed" */ Sprintf(buf, "%s%ssafely pray%s", can_pray(FALSE) ? "" : "not ", final ? "have " : "", final ? "ed" : ""); #else Sprintf(buf, "%ssafely pray", can_pray(FALSE) ? "" : "not "); #endif #ifdef WIZARD if (wizard) Sprintf(eos(buf), " (%d)", u.ublesscnt); #endif you_can(buf); } { const char *p; buf[0] = '\0'; if (final < 2) { /* still in progress, or quit/escaped/ascended */ p = "survived after being killed "; switch (u.umortality) { case 0: p = !final ? (char *)0 : "survived"; break; case 1: Strcpy(buf, "once"); break; case 2: Strcpy(buf, "twice"); break; case 3: Strcpy(buf, "thrice"); break; default: Sprintf(buf, "%d times", u.umortality); break; } } else { /* game ended in character's death */ p = "are dead"; switch (u.umortality) { case 0: impossible("dead without dying?"); case 1: break; /* just "are dead" */ default: Sprintf(buf, " (%d%s time!)", u.umortality, ordin(u.umortality)); break; } } if (p) enl_msg(You_, "have been killed ", p, buf); } display_nhwindow(en_win, TRUE); destroy_nhwindow(en_win); return; } /* * Courtesy function for non-debug, non-explorer mode players * to help refresh them about who/what they are. * Returns FALSE if menu cancelled (dismissed with ESC), TRUE otherwise. */ STATIC_OVL boolean minimal_enlightenment() { winid tmpwin; menu_item *selected; anything any; int genidx, n; char buf[BUFSZ], buf2[BUFSZ]; static const char untabbed_fmtstr[] = "%-15s: %-12s"; static const char untabbed_deity_fmtstr[] = "%-17s%s"; static const char tabbed_fmtstr[] = "%s:\t%-12s"; static const char tabbed_deity_fmtstr[] = "%s\t%s"; static const char *fmtstr; static const char *deity_fmtstr; fmtstr = iflags.menu_tab_sep ? tabbed_fmtstr : untabbed_fmtstr; deity_fmtstr = iflags.menu_tab_sep ? tabbed_deity_fmtstr : untabbed_deity_fmtstr; any.a_void = 0; buf[0] = buf2[0] = '\0'; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Starting", FALSE); /* Starting name, race, role, gender */ Sprintf(buf, fmtstr, "name", plname); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "race", urace.noun); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "role", (flags.initgend && urole.name.f) ? urole.name.f : urole.name.m); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf, fmtstr, "gender", genders[flags.initgend].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Starting alignment */ Sprintf(buf, fmtstr, "alignment", align_str(u.ualignbase[A_ORIGINAL])); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Current name, race, role, gender */ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Current", FALSE); Sprintf(buf, fmtstr, "race", Upolyd ? youmonst.data->mname : urace.noun); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); if (Upolyd) { Sprintf(buf, fmtstr, "role (base)", (u.mfemale && urole.name.f) ? urole.name.f : urole.name.m); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } else { Sprintf(buf, fmtstr, "role", (flags.female && urole.name.f) ? urole.name.f : urole.name.m); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } /* don't want poly_gender() here; it forces `2' for non-humanoids */ genidx = is_neuter(youmonst.data) ? 2 : flags.female; Sprintf(buf, fmtstr, "gender", genders[genidx].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); if (Upolyd && (int)u.mfemale != genidx) { Sprintf(buf, fmtstr, "gender (base)", genders[u.mfemale].adj); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); } /* Current alignment */ Sprintf(buf, fmtstr, "alignment", align_str(u.ualign.type)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); /* Deity list */ add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", FALSE); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Deities", FALSE); Sprintf(buf2, deity_fmtstr, align_gname(A_CHAOTIC), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_CHAOTIC) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_CHAOTIC) ? " (s)" : (u.ualign.type == A_CHAOTIC) ? " (c)" : ""); Sprintf(buf, fmtstr, "Chaotic", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf2, deity_fmtstr, align_gname(A_NEUTRAL), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_NEUTRAL) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_NEUTRAL) ? " (s)" : (u.ualign.type == A_NEUTRAL) ? " (c)" : ""); Sprintf(buf, fmtstr, "Neutral", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); Sprintf(buf2, deity_fmtstr, align_gname(A_LAWFUL), (u.ualignbase[A_ORIGINAL] == u.ualign.type && u.ualign.type == A_LAWFUL) ? " (s,c)" : (u.ualignbase[A_ORIGINAL] == A_LAWFUL) ? " (s)" : (u.ualign.type == A_LAWFUL) ? " (c)" : ""); Sprintf(buf, fmtstr, "Lawful", buf2); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, FALSE); end_menu(tmpwin, "Base Attributes"); n = select_menu(tmpwin, PICK_NONE, &selected); destroy_nhwindow(tmpwin); return (n != -1); } STATIC_PTR int doattributes() { if (!minimal_enlightenment()) return 0; if (wizard || discover) enlightenment(0); return 0; } /* KMH, #conduct * (shares enlightenment's tense handling) */ STATIC_PTR int doconduct() { show_conduct(0); return 0; } void show_conduct(final) int final; { char buf[BUFSZ]; int ngenocided; /* Create the conduct window */ en_win = create_nhwindow(NHW_MENU); putstr(en_win, 0, "Voluntary challenges:"); putstr(en_win, 0, ""); if (!u.uconduct.food) enl_msg(You_, "have gone", "went", " without food"); /* But beverages are okay */ else if (!u.uconduct.unvegan) you_have_X("followed a strict vegan diet"); else if (!u.uconduct.unvegetarian) you_have_been("vegetarian"); if (!u.uconduct.gnostic) you_have_been("an atheist"); if (!u.uconduct.weaphit) you_have_never("hit with a wielded weapon"); #ifdef WIZARD else if (wizard) { Sprintf(buf, "used a wielded weapon %ld time%s", u.uconduct.weaphit, plur(u.uconduct.weaphit)); you_have_X(buf); } #endif if (!u.uconduct.killer) you_have_been("a pacifist"); if (!u.uconduct.literate) you_have_been("illiterate"); #ifdef WIZARD else if (wizard) { Sprintf(buf, "read items or engraved %ld time%s", u.uconduct.literate, plur(u.uconduct.literate)); you_have_X(buf); } #endif ngenocided = num_genocides(); if (ngenocided == 0) { you_have_never("genocided any monsters"); } else { Sprintf(buf, "genocided %d type%s of monster%s", ngenocided, plur(ngenocided), plur(ngenocided)); you_have_X(buf); } if (!u.uconduct.polypiles) you_have_never("polymorphed an object"); #ifdef WIZARD else if (wizard) { Sprintf(buf, "polymorphed %ld item%s", u.uconduct.polypiles, plur(u.uconduct.polypiles)); you_have_X(buf); } #endif if (!u.uconduct.polyselfs) you_have_never("changed form"); #ifdef WIZARD else if (wizard) { Sprintf(buf, "changed form %ld time%s", u.uconduct.polyselfs, plur(u.uconduct.polyselfs)); you_have_X(buf); } #endif if (!u.uconduct.wishes) you_have_X("used no wishes"); else { Sprintf(buf, "used %ld wish%s", u.uconduct.wishes, (u.uconduct.wishes > 1L) ? "es" : ""); you_have_X(buf); if (!u.uconduct.wisharti) enl_msg(You_, "have not wished", "did not wish", " for any artifacts"); } /* Pop up the window and wait for a key */ display_nhwindow(en_win, TRUE); destroy_nhwindow(en_win); } #endif /* OVLB */ #ifdef OVL1 #ifndef M # ifndef NHSTDC # define M(c) (0x80 | (c)) # else # define M(c) ((c) - 128) # endif /* NHSTDC */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif static const struct func_tab cmdlist[] = { {C('d'), FALSE, dokick}, /* "D" is for door!...? Msg is in dokick.c */ #ifdef WIZARD {C('e'), TRUE, wiz_detect}, {C('f'), TRUE, wiz_map}, {C('g'), TRUE, wiz_genesis}, {C('i'), TRUE, wiz_identify}, #endif {C('l'), TRUE, doredraw}, /* if number_pad is set */ #ifdef WIZARD {C('o'), TRUE, wiz_where}, #endif {C('p'), TRUE, doprev_message}, {C('r'), TRUE, doredraw}, {C('t'), TRUE, dotele}, #ifdef WIZARD {C('v'), TRUE, wiz_level_tele}, {C('w'), TRUE, wiz_wish}, #endif {C('x'), TRUE, doattributes}, #ifdef SUSPEND {C('z'), TRUE, dosuspend}, #endif {'a', FALSE, doapply}, {'A', FALSE, doddoremarm}, {M('a'), TRUE, doorganize}, /* 'b', 'B' : go sw */ {'c', FALSE, doclose}, {'C', TRUE, do_mname}, {M('c'), TRUE, dotalk}, {'d', FALSE, dodrop}, {'D', FALSE, doddrop}, {M('d'), FALSE, dodip}, {'e', FALSE, doeat}, {'E', FALSE, doengrave}, {M('e'), TRUE, enhance_weapon_skill}, {'f', FALSE, dofire}, /* 'F' : fight (one time) */ {M('f'), FALSE, doforce}, /* 'g', 'G' : multiple go */ /* 'h', 'H' : go west */ {'h', TRUE, dohelp}, /* if number_pad is set */ {'i', TRUE, ddoinv}, {'I', TRUE, dotypeinv}, /* Robert Viduya */ {M('i'), TRUE, doinvoke}, /* 'j', 'J', 'k', 'K', 'l', 'L', 'm', 'M', 'n', 'N' : move commands */ {'j', FALSE, dojump}, /* if number_pad is on */ {M('j'), FALSE, dojump}, {'k', FALSE, dokick}, /* if number_pad is on */ {'l', FALSE, doloot}, /* if number_pad is on */ {M('l'), FALSE, doloot}, /* 'n' prefixes a count if number_pad is on */ {M('m'), TRUE, domonability}, {'N', TRUE, ddocall}, /* if number_pad is on */ {M('n'), TRUE, ddocall}, {M('N'), TRUE, ddocall}, {'o', FALSE, doopen}, {'O', TRUE, doset}, {M('o'), FALSE, dosacrifice}, {'p', FALSE, dopay}, {'P', FALSE, doputon}, {M('p'), TRUE, dopray}, {'q', FALSE, dodrink}, {'Q', FALSE, dowieldquiver}, {M('q'), TRUE, done2}, {'r', FALSE, doread}, {'R', FALSE, doremring}, {M('r'), FALSE, dorub}, {'s', TRUE, dosearch, "searching"}, {'S', TRUE, dosave}, {M('s'), FALSE, dosit}, {'t', FALSE, dothrow}, {'T', FALSE, dotakeoff}, {M('t'), TRUE, doturn}, /* 'u', 'U' : go ne */ {'u', FALSE, dountrap}, /* if number_pad is on */ {M('u'), FALSE, dountrap}, {'v', TRUE, doversion}, {'V', TRUE, dohistory}, {M('v'), TRUE, doextversion}, {'w', FALSE, dowield}, {'W', FALSE, dowear}, {M('w'), FALSE, dowipe}, {'x', FALSE, doswapweapon}, {'X', TRUE, enter_explore_mode}, /* 'y', 'Y' : go nw */ {'z', FALSE, dozap}, {'Z', TRUE, docast}, {'<', FALSE, doup}, {'>', FALSE, dodown}, {'/', TRUE, dowhatis}, {'&', TRUE, dowhatdoes}, {'?', TRUE, dohelp}, {M('?'), TRUE, doextlist}, #ifdef SHELL {'!', TRUE, dosh}, #endif {'.', TRUE, donull, "waiting"}, {' ', TRUE, donull, "waiting"}, {',', FALSE, dopickup}, {':', TRUE, dolook}, {';', TRUE, doquickwhatis}, {'^', TRUE, doidtrap}, {'\\', TRUE, dodiscovered}, /* Robert Viduya */ {'@', TRUE, dotogglepickup}, {M('2'), FALSE, dotwoweapon}, {WEAPON_SYM, TRUE, doprwep}, {ARMOR_SYM, TRUE, doprarm}, {RING_SYM, TRUE, doprring}, {AMULET_SYM, TRUE, dopramulet}, {TOOL_SYM, TRUE, doprtool}, {'*', TRUE, doprinuse}, /* inventory of all equipment in use */ {GOLD_SYM, TRUE, doprgold}, {SPBOOK_SYM, TRUE, dovspell}, /* Mike Stephenson */ {'#', TRUE, doextcmd}, {'_', TRUE, dotravel}, {0,0,0,0} }; struct ext_func_tab extcmdlist[] = { {"adjust", "adjust inventory letters", doorganize, TRUE}, {"chat", "talk to someone", dotalk, TRUE}, /* converse? */ {"conduct", "list which challenges you have adhered to", doconduct, TRUE}, {"dip", "dip an object into something", dodip, FALSE}, {"enhance", "advance or check weapons skills", enhance_weapon_skill, TRUE}, {"force", "force a lock", doforce, FALSE}, {"invoke", "invoke an object's powers", doinvoke, TRUE}, {"jump", "jump to a location", dojump, FALSE}, {"loot", "loot a box on the floor", doloot, FALSE}, {"monster", "use a monster's special ability", domonability, TRUE}, {"name", "name an item or type of object", ddocall, TRUE}, {"offer", "offer a sacrifice to the gods", dosacrifice, FALSE}, {"pray", "pray to the gods for help", dopray, TRUE}, {"quit", "exit without saving current game", done2, TRUE}, #ifdef STEED {"ride", "ride (or stop riding) a monster", doride, FALSE}, #endif {"rub", "rub a lamp or a stone", dorub, FALSE}, {"sit", "sit down", dosit, FALSE}, {"turn", "turn undead", doturn, TRUE}, {"twoweapon", "toggle two-weapon combat", dotwoweapon, FALSE}, {"untrap", "untrap something", dountrap, FALSE}, {"version", "list compile time options for this version of NetHack", doextversion, TRUE}, {"wipe", "wipe off your face", dowipe, FALSE}, {"?", "get this list of extended commands", doextlist, TRUE}, #if defined(WIZARD) /* * There must be a blank entry here for every entry in the table * below. */ {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, #ifdef DEBUG_MIGRATING_MONS {(char *)0, (char *)0, donull, TRUE}, #endif {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, #ifdef PORT_DEBUG {(char *)0, (char *)0, donull, TRUE}, #endif {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, {(char *)0, (char *)0, donull, TRUE}, #ifdef DEBUG {(char *)0, (char *)0, donull, TRUE}, #endif {(char *)0, (char *)0, donull, TRUE}, #endif {(char *)0, (char *)0, donull, TRUE} /* sentinel */ }; #if defined(WIZARD) static const struct ext_func_tab debug_extcmdlist[] = { {"levelchange", "change experience level", wiz_level_change, TRUE}, {"lightsources", "show mobile light sources", wiz_light_sources, TRUE}, #ifdef DEBUG_MIGRATING_MONS {"migratemons", "migrate n random monsters", wiz_migrate_mons, TRUE}, #endif {"monpolycontrol", "control monster polymorphs", wiz_mon_polycontrol, TRUE}, {"panic", "test panic routine (fatal to game)", wiz_panic, TRUE}, {"polyself", "polymorph self", wiz_polyself, TRUE}, #ifdef PORT_DEBUG {"portdebug", "wizard port debug command", wiz_port_debug, TRUE}, #endif {"seenv", "show seen vectors", wiz_show_seenv, TRUE}, {"stats", "show memory statistics", wiz_show_stats, TRUE}, {"timeout", "look at timeout queue", wiz_timeout_queue, TRUE}, {"vision", "show vision array", wiz_show_vision, TRUE}, #ifdef DEBUG {"wizdebug", "wizard debug command", wiz_debug_cmd, TRUE}, #endif {"wmode", "show wall modes", wiz_show_wmodes, TRUE}, {(char *)0, (char *)0, donull, TRUE} }; /* * Insert debug commands into the extended command list. This function * assumes that the last entry will be the help entry. * * You must add entries in ext_func_tab every time you add one to the * debug_extcmdlist(). */ void add_debug_extended_commands() { int i, j, k, n; /* count the # of help entries */ for (n = 0; extcmdlist[n].ef_txt[0] != '?'; n++) ; for (i = 0; debug_extcmdlist[i].ef_txt; i++) { for (j = 0; j < n; j++) if (strcmp(debug_extcmdlist[i].ef_txt, extcmdlist[j].ef_txt) < 0) break; /* insert i'th debug entry into extcmdlist[j], pushing down */ for (k = n; k >= j; --k) extcmdlist[k+1] = extcmdlist[k]; extcmdlist[j] = debug_extcmdlist[i]; n++; /* now an extra entry */ } } static const char template[] = "%-18s %4ld %6ld"; static const char count_str[] = " count bytes"; static const char separator[] = "------------------ ----- ------"; STATIC_OVL void count_obj(chain, total_count, total_size, top, recurse) struct obj *chain; long *total_count; long *total_size; boolean top; boolean recurse; { long count, size; struct obj *obj; for (count = size = 0, obj = chain; obj; obj = obj->nobj) { if (top) { count++; size += sizeof(struct obj) + obj->oxlth + obj->onamelth; } if (recurse && obj->cobj) count_obj(obj->cobj, total_count, total_size, TRUE, TRUE); } *total_count += count; *total_size += size; } STATIC_OVL void obj_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct obj *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; count_obj(chain, &count, &size, TRUE, FALSE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL void mon_invent_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct monst *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; struct monst *mon; for (mon = chain; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, TRUE, FALSE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL void contained(win, src, total_count, total_size) winid win; const char *src; long *total_count; long *total_size; { char buf[BUFSZ]; long count = 0, size = 0; struct monst *mon; count_obj(invent, &count, &size, FALSE, TRUE); count_obj(fobj, &count, &size, FALSE, TRUE); count_obj(level.buriedobjlist, &count, &size, FALSE, TRUE); count_obj(migrating_objs, &count, &size, FALSE, TRUE); /* DEADMONSTER check not required in this loop since they have no inventory */ for (mon = fmon; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, FALSE, TRUE); for (mon = migrating_mons; mon; mon = mon->nmon) count_obj(mon->minvent, &count, &size, FALSE, TRUE); *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } STATIC_OVL void mon_chain(win, src, chain, total_count, total_size) winid win; const char *src; struct monst *chain; long *total_count; long *total_size; { char buf[BUFSZ]; long count, size; struct monst *mon; for (count = size = 0, mon = chain; mon; mon = mon->nmon) { count++; size += sizeof(struct monst) + mon->mxlth + mon->mnamelth; } *total_count += count; *total_size += size; Sprintf(buf, template, src, count, size); putstr(win, 0, buf); } /* * Display memory usage of all monsters and objects on the level. */ static int wiz_show_stats() { char buf[BUFSZ]; winid win; long total_obj_size = 0, total_obj_count = 0; long total_mon_size = 0, total_mon_count = 0; win = create_nhwindow(NHW_TEXT); putstr(win, 0, "Current memory statistics:"); putstr(win, 0, ""); Sprintf(buf, "Objects, size %d", (int) sizeof(struct obj)); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, count_str); obj_chain(win, "invent", invent, &total_obj_count, &total_obj_size); obj_chain(win, "fobj", fobj, &total_obj_count, &total_obj_size); obj_chain(win, "buried", level.buriedobjlist, &total_obj_count, &total_obj_size); obj_chain(win, "migrating obj", migrating_objs, &total_obj_count, &total_obj_size); mon_invent_chain(win, "minvent", fmon, &total_obj_count,&total_obj_size); mon_invent_chain(win, "migrating minvent", migrating_mons, &total_obj_count, &total_obj_size); contained(win, "contained", &total_obj_count, &total_obj_size); putstr(win, 0, separator); Sprintf(buf, template, "Total", total_obj_count, total_obj_size); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, ""); Sprintf(buf, "Monsters, size %d", (int) sizeof(struct monst)); putstr(win, 0, buf); putstr(win, 0, ""); mon_chain(win, "fmon", fmon, &total_mon_count, &total_mon_size); mon_chain(win, "migrating", migrating_mons, &total_mon_count, &total_mon_size); putstr(win, 0, separator); Sprintf(buf, template, "Total", total_mon_count, total_mon_size); putstr(win, 0, buf); #if defined(__BORLANDC__) && !defined(_WIN32) show_borlandc_stats(win); #endif display_nhwindow(win, FALSE); destroy_nhwindow(win); return 0; } void sanity_check() { obj_sanity_check(); timer_sanity_check(); } #ifdef DEBUG_MIGRATING_MONS static int wiz_migrate_mons() { int mcount = 0; char inbuf[BUFSZ]; struct permonst *ptr; struct monst *mtmp; d_level tolevel; getlin("How many random monsters to migrate? [0]", inbuf); if (*inbuf == '\033') return 0; mcount = atoi(inbuf); if (mcount < 0 || mcount > (COLNO * ROWNO) || Is_botlevel(&u.uz)) return 0; while (mcount > 0) { if (Is_stronghold(&u.uz)) assign_level(&tolevel, &valley_level); else get_level(&tolevel, depth(&u.uz) + 1); ptr = rndmonst(); mtmp = makemon(ptr, 0, 0, NO_MM_FLAGS); if (mtmp) migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *)0); mcount--; } return 0; } #endif #endif /* WIZARD */ #define unctrl(c) ((c) <= C('z') ? (0x60 | (c)) : (c)) #define unmeta(c) (0x7f & (c)) void rhack(cmd) register char *cmd; { boolean do_walk, do_rush, prefix_seen, bad_command, firsttime = (cmd == 0); iflags.menu_requested = FALSE; if (firsttime) { flags.nopick = 0; cmd = parse(); } if (*cmd == '\033') { flags.move = FALSE; return; } #ifdef REDO if (*cmd == DOAGAIN && !in_doagain && saveq[0]) { in_doagain = TRUE; stail = 0; rhack((char *)0); /* read and execute command */ in_doagain = FALSE; return; } /* Special case of *cmd == ' ' handled better below */ if(!*cmd || *cmd == (char)0377) #else if(!*cmd || *cmd == (char)0377 || (!flags.rest_on_space && *cmd == ' ')) #endif { nhbell(); flags.move = FALSE; return; /* probably we just had an interrupt */ } if (iflags.num_pad && iflags.num_pad_mode == 1) { /* This handles very old inconsistent DOS/Windows behaviour * in a new way: earlier, the keyboard handler mapped these, * which caused counts to be strange when entered from the * number pad. Now do not map them until here. */ switch (*cmd) { case '5': *cmd = 'g'; break; case M('5'): *cmd = 'G'; break; case M('0'): *cmd = 'I'; break; } } /* handle most movement commands */ do_walk = do_rush = prefix_seen = FALSE; flags.travel = iflags.travel1 = 0; switch (*cmd) { case 'g': if (movecmd(cmd[1])) { flags.run = 2; do_rush = TRUE; } else prefix_seen = TRUE; break; case '5': if (!iflags.num_pad) break; /* else FALLTHRU */ case 'G': if (movecmd(lowc(cmd[1]))) { flags.run = 3; do_rush = TRUE; } else prefix_seen = TRUE; break; case '-': if (!iflags.num_pad) break; /* else FALLTHRU */ /* Effects of movement commands and invisible monsters: * m: always move onto space (even if 'I' remembered) * F: always attack space (even if 'I' not remembered) * normal movement: attack if 'I', move otherwise */ case 'F': if (movecmd(cmd[1])) { flags.forcefight = 1; do_walk = TRUE; } else prefix_seen = TRUE; break; case 'm': if (movecmd(cmd[1]) || u.dz) { flags.run = 0; flags.nopick = 1; if (!u.dz) do_walk = TRUE; else cmd[0] = cmd[1]; /* "m<" or "m>" */ } else prefix_seen = TRUE; break; case 'M': if (movecmd(lowc(cmd[1]))) { flags.run = 1; flags.nopick = 1; do_rush = TRUE; } else prefix_seen = TRUE; break; case '0': if (!iflags.num_pad) break; (void)ddoinv(); /* a convenience borrowed from the PC */ flags.move = FALSE; multi = 0; return; case CMD_TRAVEL: if (iflags.travelcmd) { flags.travel = 1; iflags.travel1 = 1; flags.run = 8; flags.nopick = 1; do_rush = TRUE; break; } /*FALLTHRU*/ default: if (movecmd(*cmd)) { /* ordinary movement */ flags.run = 0; /* only matters here if it was 8 */ do_walk = TRUE; } else if (movecmd(iflags.num_pad ? unmeta(*cmd) : lowc(*cmd))) { flags.run = 1; do_rush = TRUE; } else if (movecmd(unctrl(*cmd))) { flags.run = 3; do_rush = TRUE; } break; } /* some special prefix handling */ /* overload 'm' prefix for ',' to mean "request a menu" */ if (prefix_seen && cmd[1] == ',') { iflags.menu_requested = TRUE; ++cmd; } if (do_walk) { if (multi) flags.mv = TRUE; domove(); flags.forcefight = 0; return; } else if (do_rush) { if (firsttime) { if (!multi) multi = max(COLNO,ROWNO); u.last_str_turn = 0; } flags.mv = TRUE; domove(); return; } else if (prefix_seen && cmd[1] == '\033') { /* */ /* don't report "unknown command" for change of heart... */ bad_command = FALSE; } else if (*cmd == ' ' && !flags.rest_on_space) { bad_command = TRUE; /* skip cmdlist[] loop */ /* handle all other commands */ } else { register const struct func_tab *tlist; int res, NDECL((*func)); for (tlist = cmdlist; tlist->f_char; tlist++) { if ((*cmd & 0xff) != (tlist->f_char & 0xff)) continue; if (u.uburied && !tlist->can_if_buried) { You_cant("do that while you are buried!"); res = 0; } else { /* we discard 'const' because some compilers seem to have trouble with the pointer passed to set_occupation() */ func = ((struct func_tab *)tlist)->f_funct; if (tlist->f_text && !occupation && multi) set_occupation(func, tlist->f_text, multi); res = (*func)(); /* perform the command */ } if (!res) { flags.move = FALSE; multi = 0; } return; } /* if we reach here, cmd wasn't found in cmdlist[] */ bad_command = TRUE; } if (bad_command) { char expcmd[10]; register char *cp = expcmd; while (*cmd && (int)(cp - expcmd) < (int)(sizeof expcmd - 3)) { if (*cmd >= 040 && *cmd < 0177) { *cp++ = *cmd++; } else if (*cmd & 0200) { *cp++ = 'M'; *cp++ = '-'; *cp++ = *cmd++ &= ~0200; } else { *cp++ = '^'; *cp++ = *cmd++ ^ 0100; } } *cp = '\0'; if (!prefix_seen || !iflags.cmdassist || !help_dir(0, "Invalid direction key!")) Norep("Unknown command '%s'.", expcmd); } /* didn't move */ flags.move = FALSE; multi = 0; return; } int xytod(x, y) /* convert an x,y pair into a direction code */ schar x, y; { register int dd; for(dd = 0; dd < 8; dd++) if(x == xdir[dd] && y == ydir[dd]) return dd; return -1; } void dtoxy(cc,dd) /* convert a direction code into an x,y pair */ coord *cc; register int dd; { cc->x = xdir[dd]; cc->y = ydir[dd]; return; } int movecmd(sym) /* also sets u.dz, but returns false for <> */ char sym; { register const char *dp; register const char *sdp; if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */ u.dz = 0; if(!(dp = index(sdp, sym))) return 0; u.dx = xdir[dp-sdp]; u.dy = ydir[dp-sdp]; u.dz = zdir[dp-sdp]; if (u.dx && u.dy && u.umonnum == PM_GRID_BUG) { u.dx = u.dy = 0; return 0; } return !u.dz; } /* * uses getdir() but unlike getdir() it specifically * produces coordinates using the direction from getdir() * and verifies that those coordinates are ok. * * If the call to getdir() returns 0, Never_mind is displayed. * If the resulting coordinates are not okay, emsg is displayed. * * Returns non-zero if coordinates in cc are valid. */ int get_adjacent_loc(prompt,emsg,x,y,cc) const char *prompt, *emsg; xchar x,y; coord *cc; { xchar new_x, new_y; if (!getdir(prompt)) { pline(Never_mind); return 0; } new_x = x + u.dx; new_y = y + u.dy; if (cc && isok(new_x,new_y)) { cc->x = new_x; cc->y = new_y; } else { if (emsg) pline(emsg); return 0; } return 1; } int getdir(s) const char *s; { char dirsym; #ifdef REDO if(in_doagain || *readchar_queue) dirsym = readchar(); else #endif dirsym = yn_function ((s && *s != '^') ? s : "In what direction?", (char *)0, '\0'); #ifdef REDO savech(dirsym); #endif if(dirsym == '.' || dirsym == 's') u.dx = u.dy = u.dz = 0; else if(!movecmd(dirsym) && !u.dz) { boolean did_help = FALSE; if(!index(quitchars, dirsym)) { if (iflags.cmdassist) { did_help = help_dir((s && *s == '^') ? dirsym : 0, "Invalid direction key!"); } if (!did_help) pline("What a strange direction!"); } return 0; } if(!u.dz && (Stunned || (Confusion && !rn2(5)))) confdir(); return 1; } STATIC_OVL boolean help_dir(sym, msg) char sym; const char *msg; { char ctrl; winid win; static const char wiz_only_list[] = "EFGIOVW"; char buf[BUFSZ], buf2[BUFSZ], *expl; win = create_nhwindow(NHW_TEXT); if (!win) return FALSE; if (msg) { Sprintf(buf, "cmdassist: %s", msg); putstr(win, 0, buf); putstr(win, 0, ""); } if (letter(sym)) { sym = highc(sym); ctrl = (sym - 'A') + 1; if ((expl = dowhatdoes_core(ctrl, buf2)) && (!index(wiz_only_list, sym) #ifdef WIZARD || wizard #endif )) { Sprintf(buf, "Are you trying to use ^%c%s?", sym, index(wiz_only_list, sym) ? "" : " as specified in the Guidebook"); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, expl); putstr(win, 0, ""); putstr(win, 0, "To use that command, you press"); Sprintf(buf, "the key, and the <%c> key at the same time.", sym); putstr(win, 0, buf); putstr(win, 0, ""); } } if (iflags.num_pad && u.umonnum == PM_GRID_BUG) { putstr(win, 0, "Valid direction keys in your current form (with number_pad on) are:"); putstr(win, 0, " 8 "); putstr(win, 0, " | "); putstr(win, 0, " 4- . -6"); putstr(win, 0, " | "); putstr(win, 0, " 2 "); } else if (u.umonnum == PM_GRID_BUG) { putstr(win, 0, "Valid direction keys in your current form are:"); putstr(win, 0, " k "); putstr(win, 0, " | "); putstr(win, 0, " h- . -l"); putstr(win, 0, " | "); putstr(win, 0, " j "); } else if (iflags.num_pad) { putstr(win, 0, "Valid direction keys (with number_pad on) are:"); putstr(win, 0, " 7 8 9"); putstr(win, 0, " \\ | / "); putstr(win, 0, " 4- . -6"); putstr(win, 0, " / | \\ "); putstr(win, 0, " 1 2 3"); } else { putstr(win, 0, "Valid direction keys are:"); putstr(win, 0, " y k u"); putstr(win, 0, " \\ | / "); putstr(win, 0, " h- . -l"); putstr(win, 0, " / | \\ "); putstr(win, 0, " b j n"); }; putstr(win, 0, ""); putstr(win, 0, " < up"); putstr(win, 0, " > down"); putstr(win, 0, " . direct at yourself"); putstr(win, 0, ""); putstr(win, 0, "(Suppress this message with !cmdassist in config file.)"); display_nhwindow(win, FALSE); destroy_nhwindow(win); return TRUE; } #endif /* OVL1 */ #ifdef OVLB void confdir() { register int x = (u.umonnum == PM_GRID_BUG) ? 2*rn2(4) : rn2(8); u.dx = xdir[x]; u.dy = ydir[x]; return; } #endif /* OVLB */ #ifdef OVL0 int isok(x,y) register int x, y; { /* x corresponds to curx, so x==1 is the first column. Ach. %% */ return x >= 1 && x <= COLNO-1 && y >= 0 && y <= ROWNO-1; } static NEARDATA int last_multi; /* * convert a MAP window position into a movecmd */ const char * click_to_cmd(x, y, mod) int x, y, mod; { int dir; static char cmd[4]; cmd[1]=0; x -= u.ux; y -= u.uy; if (iflags.travelcmd) { if (abs(x) <= 1 && abs(y) <= 1 ) { x = sgn(x), y = sgn(y); } else { u.tx = u.ux+x; u.ty = u.uy+y; cmd[0] = CMD_TRAVEL; return cmd; } if(x == 0 && y == 0) { /* here */ if(IS_FOUNTAIN(levl[u.ux][u.uy].typ) || IS_SINK(levl[u.ux][u.uy].typ)) { cmd[0]=mod == CLICK_1 ? 'q' : M('d'); return cmd; } else if(IS_THRONE(levl[u.ux][u.uy].typ)) { cmd[0]=M('s'); return cmd; } else if((u.ux == xupstair && u.uy == yupstair) || (u.ux == sstairs.sx && u.uy == sstairs.sy && sstairs.up) || (u.ux == xupladder && u.uy == yupladder)) { return "<"; } else if((u.ux == xdnstair && u.uy == ydnstair) || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up) || (u.ux == xdnladder && u.uy == ydnladder)) { return ">"; } else if(OBJ_AT(u.ux, u.uy)) { cmd[0] = Is_container(level.objects[u.ux][u.uy]) ? M('l') : ','; return cmd; } else { return "."; /* just rest */ } } /* directional commands */ dir = xytod(x, y); if (!m_at(u.ux+x, u.uy+y) && !test_move(u.ux, u.uy, x, y, TEST_MOVE)) { cmd[1] = (iflags.num_pad ? ndir[dir] : sdir[dir]); cmd[2] = 0; if (IS_DOOR(levl[u.ux+x][u.uy+y].typ)) { /* slight assistance to the player: choose kick/open for them */ if (levl[u.ux+x][u.uy+y].doormask & D_LOCKED) { cmd[0] = C('d'); return cmd; } if (levl[u.ux+x][u.uy+y].doormask & D_CLOSED) { cmd[0] = 'o'; return cmd; } } if (levl[u.ux+x][u.uy+y].typ <= SCORR) { cmd[0] = 's'; cmd[1] = 0; return cmd; } } } else { /* convert without using floating point, allowing sloppy clicking */ if(x > 2*abs(y)) x = 1, y = 0; else if(y > 2*abs(x)) x = 0, y = 1; else if(x < -2*abs(y)) x = -1, y = 0; else if(y < -2*abs(x)) x = 0, y = -1; else x = sgn(x), y = sgn(y); if(x == 0 && y == 0) /* map click on player to "rest" command */ return "."; dir = xytod(x, y); } /* move, attack, etc. */ cmd[1] = 0; if(mod == CLICK_1) { cmd[0] = (iflags.num_pad ? ndir[dir] : sdir[dir]); } else { cmd[0] = (iflags.num_pad ? M(ndir[dir]) : (sdir[dir] - 'a' + 'A')); /* run command */ } return cmd; } STATIC_OVL char * parse() { #ifdef LINT /* static char in_line[COLNO]; */ char in_line[COLNO]; #else static char in_line[COLNO]; #endif register int foo; boolean prezero = FALSE; multi = 0; flags.move = 1; flush_screen(1); /* Flush screen buffer. Put the cursor on the hero. */ if (!iflags.num_pad || (foo = readchar()) == 'n') for (;;) { foo = readchar(); if (foo >= '0' && foo <= '9') { multi = 10 * multi + foo - '0'; if (multi < 0 || multi >= LARGEST_INT) multi = LARGEST_INT; if (multi > 9) { clear_nhwindow(WIN_MESSAGE); Sprintf(in_line, "Count: %d", multi); pline(in_line); mark_synch(); } last_multi = multi; if (!multi && foo == '0') prezero = TRUE; } else break; /* not a digit */ } if (foo == '\033') { /* esc cancels count (TH) */ clear_nhwindow(WIN_MESSAGE); multi = last_multi = 0; # ifdef REDO } else if (foo == DOAGAIN || in_doagain) { multi = last_multi; } else { last_multi = multi; savech(0); /* reset input queue */ savech((char)foo); # endif } if (multi) { multi--; save_cm = in_line; } else { save_cm = (char *)0; } in_line[0] = foo; in_line[1] = '\0'; if (foo == 'g' || foo == 'G' || foo == 'm' || foo == 'M' || foo == 'F' || (iflags.num_pad && (foo == '5' || foo == '-'))) { foo = readchar(); #ifdef REDO savech((char)foo); #endif in_line[1] = foo; in_line[2] = 0; } clear_nhwindow(WIN_MESSAGE); if (prezero) in_line[0] = '\033'; return(in_line); } #endif /* OVL0 */ #ifdef OVLB #ifdef UNIX static void end_of_input() { #ifndef NOSAVEONHANGUP if (!program_state.done_hup++ && program_state.something_worth_saving) (void) dosave0(); #endif exit_nhwindows((char *)0); clearlocks(); terminate(EXIT_SUCCESS); } #endif #endif /* OVLB */ #ifdef OVL0 char readchar() { register int sym; int x = u.ux, y = u.uy, mod = 0; if ( *readchar_queue ) sym = *readchar_queue++; else #ifdef REDO sym = in_doagain ? Getchar() : nh_poskey(&x, &y, &mod); #else sym = Getchar(); #endif #ifdef UNIX # ifdef NR_OF_EOFS if (sym == EOF) { register int cnt = NR_OF_EOFS; /* * Some SYSV systems seem to return EOFs for various reasons * (?like when one hits break or for interrupted systemcalls?), * and we must see several before we quit. */ do { clearerr(stdin); /* omit if clearerr is undefined */ sym = Getchar(); } while (--cnt && sym == EOF); } # endif /* NR_OF_EOFS */ if (sym == EOF) end_of_input(); #endif /* UNIX */ if(sym == 0) { /* click event */ readchar_queue = click_to_cmd(x, y, mod); sym = *readchar_queue++; } return((char) sym); } STATIC_PTR int dotravel() { /* Keyboard travel command */ static char cmd[2]; coord cc; if (!iflags.travelcmd) return 0; cmd[1]=0; cc.x = iflags.travelcc.x; cc.y = iflags.travelcc.y; if (cc.x == -1 && cc.y == -1) { /* No cached destination, start attempt from current position */ cc.x = u.ux; cc.y = u.uy; } pline("Where do you want to travel to?"); if (getpos(&cc, TRUE, "the desired destination") < 0) { /* user pressed ESC */ return 0; } iflags.travelcc.x = u.tx = cc.x; iflags.travelcc.y = u.ty = cc.y; cmd[0] = CMD_TRAVEL; readchar_queue = cmd; return 0; } #ifdef PORT_DEBUG # ifdef WIN32CON extern void NDECL(win32con_debug_keystrokes); extern void NDECL(win32con_handler_info); # endif int wiz_port_debug() { int n, k; winid win; anything any; int item = 'a'; int num_menu_selections; struct menu_selection_struct { char *menutext; void NDECL((*fn)); } menu_selections[] = { #ifdef WIN32CON {"test win32 keystrokes", win32con_debug_keystrokes}, {"show keystroke handler information", win32con_handler_info}, #endif {(char *)0, (void NDECL((*)))0} /* array terminator */ }; num_menu_selections = SIZE(menu_selections) - 1; if (num_menu_selections > 0) { menu_item *pick_list; win = create_nhwindow(NHW_MENU); start_menu(win); for (k=0; k < num_menu_selections; ++k) { any.a_int = k+1; add_menu(win, NO_GLYPH, &any, item++, 0, ATR_NONE, menu_selections[k].menutext, MENU_UNSELECTED); } end_menu(win, "Which port debugging feature?"); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); if (n > 0) { n = pick_list[0].item.a_int - 1; free((genericptr_t) pick_list); /* execute the function */ (*menu_selections[n].fn)(); } } else pline("No port-specific debug capability defined."); return 0; } # endif /*PORT_DEBUG*/ #endif /* OVL0 */ #ifdef OVLB /* * Parameter validator for generic yes/no function to prevent * the core from sending too long a prompt string to the * window port causing a buffer overflow there. */ char yn_function(query,resp, def) const char *query,*resp; char def; { char qbuf[QBUFSZ]; unsigned truncspot, reduction = sizeof(" [N] ?") + 1; if (resp) reduction += strlen(resp) + sizeof(" () "); if (strlen(query) < (QBUFSZ - reduction)) return (*windowprocs.win_yn_function)(query, resp, def); paniclog("Query truncated: ", query); reduction += sizeof("..."); truncspot = QBUFSZ - reduction; (void) strncpy(qbuf, query, (int)truncspot); qbuf[truncspot] = '\0'; Strcat(qbuf,"..."); return (*windowprocs.win_yn_function)(qbuf, resp, def); } #endif /*cmd.c*/ nethack-3.4.3/src/dbridge.c0100644000000000000000000005521707764735041014217 0ustar rootroot/* SCCS Id: @(#)dbridge.c 3.4 2003/02/08 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the drawbridge manipulation (create, open, close, * destroy). * * Added comprehensive monster-handling, and the "entity" structure to * deal with players as well. - 11/89 */ #include "hack.h" #ifdef OVLB STATIC_DCL void FDECL(get_wall_for_db, (int *, int *)); STATIC_DCL struct entity *FDECL(e_at, (int, int)); STATIC_DCL void FDECL(m_to_e, (struct monst *, int, int, struct entity *)); STATIC_DCL void FDECL(u_to_e, (struct entity *)); STATIC_DCL void FDECL(set_entity, (int, int, struct entity *)); STATIC_DCL const char *FDECL(e_nam, (struct entity *)); #ifdef D_DEBUG static const char *FDECL(Enam, (struct entity *)); /* unused */ #endif STATIC_DCL const char *FDECL(E_phrase, (struct entity *, const char *)); STATIC_DCL boolean FDECL(e_survives_at, (struct entity *, int, int)); STATIC_DCL void FDECL(e_died, (struct entity *, int, int)); STATIC_DCL boolean FDECL(automiss, (struct entity *)); STATIC_DCL boolean FDECL(e_missed, (struct entity *, BOOLEAN_P)); STATIC_DCL boolean FDECL(e_jumps, (struct entity *)); STATIC_DCL void FDECL(do_entity, (struct entity *)); #endif /* OVLB */ #ifdef OVL0 boolean is_pool(x,y) int x,y; { schar ltyp; if (!isok(x,y)) return FALSE; ltyp = levl[x][y].typ; if (ltyp == POOL || ltyp == MOAT || ltyp == WATER) return TRUE; if (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT) return TRUE; return FALSE; } boolean is_lava(x,y) int x,y; { schar ltyp; if (!isok(x,y)) return FALSE; ltyp = levl[x][y].typ; if (ltyp == LAVAPOOL || (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_LAVA)) return TRUE; return FALSE; } boolean is_ice(x,y) int x,y; { schar ltyp; if (!isok(x,y)) return FALSE; ltyp = levl[x][y].typ; if (ltyp == ICE || (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE)) return TRUE; return FALSE; } #endif /* OVL0 */ #ifdef OVL1 /* * We want to know whether a wall (or a door) is the portcullis (passageway) * of an eventual drawbridge. * * Return value: the direction of the drawbridge. */ int is_drawbridge_wall(x,y) int x,y; { struct rm *lev; lev = &levl[x][y]; if (lev->typ != DOOR && lev->typ != DBWALL) return (-1); if (IS_DRAWBRIDGE(levl[x+1][y].typ) && (levl[x+1][y].drawbridgemask & DB_DIR) == DB_WEST) return (DB_WEST); if (IS_DRAWBRIDGE(levl[x-1][y].typ) && (levl[x-1][y].drawbridgemask & DB_DIR) == DB_EAST) return (DB_EAST); if (IS_DRAWBRIDGE(levl[x][y-1].typ) && (levl[x][y-1].drawbridgemask & DB_DIR) == DB_SOUTH) return (DB_SOUTH); if (IS_DRAWBRIDGE(levl[x][y+1].typ) && (levl[x][y+1].drawbridgemask & DB_DIR) == DB_NORTH) return (DB_NORTH); return (-1); } /* * Use is_db_wall where you want to verify that a * drawbridge "wall" is UP in the location x, y * (instead of UP or DOWN, as with is_drawbridge_wall). */ boolean is_db_wall(x,y) int x,y; { return((boolean)( levl[x][y].typ == DBWALL )); } /* * Return true with x,y pointing to the drawbridge if x,y initially indicate * a drawbridge or drawbridge wall. */ boolean find_drawbridge(x,y) int *x,*y; { int dir; if (IS_DRAWBRIDGE(levl[*x][*y].typ)) return TRUE; dir = is_drawbridge_wall(*x,*y); if (dir >= 0) { switch(dir) { case DB_NORTH: (*y)++; break; case DB_SOUTH: (*y)--; break; case DB_EAST: (*x)--; break; case DB_WEST: (*x)++; break; } return TRUE; } return FALSE; } #endif /* OVL1 */ #ifdef OVLB /* * Find the drawbridge wall associated with a drawbridge. */ STATIC_OVL void get_wall_for_db(x,y) int *x,*y; { switch (levl[*x][*y].drawbridgemask & DB_DIR) { case DB_NORTH: (*y)--; break; case DB_SOUTH: (*y)++; break; case DB_EAST: (*x)++; break; case DB_WEST: (*x)--; break; } } /* * Creation of a drawbridge at pos x,y. * dir is the direction. * flag must be put to TRUE if we want the drawbridge to be opened. */ boolean create_drawbridge(x,y,dir,flag) int x,y,dir; boolean flag; { int x2,y2; boolean horiz; boolean lava = levl[x][y].typ == LAVAPOOL; /* assume initialized map */ x2 = x; y2 = y; switch(dir) { case DB_NORTH: horiz = TRUE; y2--; break; case DB_SOUTH: horiz = TRUE; y2++; break; case DB_EAST: horiz = FALSE; x2++; break; default: impossible("bad direction in create_drawbridge"); /* fall through */ case DB_WEST: horiz = FALSE; x2--; break; } if (!IS_WALL(levl[x2][y2].typ)) return(FALSE); if (flag) { /* We want the bridge open */ levl[x][y].typ = DRAWBRIDGE_DOWN; levl[x2][y2].typ = DOOR; levl[x2][y2].doormask = D_NODOOR; } else { levl[x][y].typ = DRAWBRIDGE_UP; levl[x2][y2].typ = DBWALL; /* Drawbridges are non-diggable. */ levl[x2][y2].wall_info = W_NONDIGGABLE; } levl[x][y].horizontal = !horiz; levl[x2][y2].horizontal = horiz; levl[x][y].drawbridgemask = dir; if(lava) levl[x][y].drawbridgemask |= DB_LAVA; return(TRUE); } struct entity { struct monst *emon; /* youmonst for the player */ struct permonst *edata; /* must be non-zero for record to be valid */ int ex, ey; }; #define ENTITIES 2 static NEARDATA struct entity occupants[ENTITIES]; STATIC_OVL struct entity * e_at(x, y) int x, y; { int entitycnt; for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) if ((occupants[entitycnt].edata) && (occupants[entitycnt].ex == x) && (occupants[entitycnt].ey == y)) break; #ifdef D_DEBUG pline("entitycnt = %d", entitycnt); wait_synch(); #endif return((entitycnt == ENTITIES)? (struct entity *)0 : &(occupants[entitycnt])); } STATIC_OVL void m_to_e(mtmp, x, y, etmp) struct monst *mtmp; int x, y; struct entity *etmp; { etmp->emon = mtmp; if (mtmp) { etmp->ex = x; etmp->ey = y; if (mtmp->wormno && (x != mtmp->mx || y != mtmp->my)) etmp->edata = &mons[PM_LONG_WORM_TAIL]; else etmp->edata = mtmp->data; } else etmp->edata = (struct permonst *)0; } STATIC_OVL void u_to_e(etmp) struct entity *etmp; { etmp->emon = &youmonst; etmp->ex = u.ux; etmp->ey = u.uy; etmp->edata = youmonst.data; } STATIC_OVL void set_entity(x, y, etmp) int x, y; struct entity *etmp; { if ((x == u.ux) && (y == u.uy)) u_to_e(etmp); else if (MON_AT(x, y)) m_to_e(m_at(x, y), x, y, etmp); else etmp->edata = (struct permonst *)0; } #define is_u(etmp) (etmp->emon == &youmonst) #define e_canseemon(etmp) (is_u(etmp) ? (boolean)TRUE : canseemon(etmp->emon)) /* * e_strg is a utility routine which is not actually in use anywhere, since * the specialized routines below suffice for all current purposes. */ /* #define e_strg(etmp, func) (is_u(etmp)? (char *)0 : func(etmp->emon)) */ STATIC_OVL const char * e_nam(etmp) struct entity *etmp; { return(is_u(etmp)? "you" : mon_nam(etmp->emon)); } #ifdef D_DEBUG /* * Enam is another unused utility routine: E_phrase is preferable. */ static const char * Enam(etmp) struct entity *etmp; { return(is_u(etmp)? "You" : Monnam(etmp->emon)); } #endif /* D_DEBUG */ /* * Generates capitalized entity name, makes 2nd -> 3rd person conversion on * verb, where necessary. */ STATIC_OVL const char * E_phrase(etmp, verb) struct entity *etmp; const char *verb; { static char wholebuf[80]; Strcpy(wholebuf, is_u(etmp) ? "You" : Monnam(etmp->emon)); if (!*verb) return(wholebuf); Strcat(wholebuf, " "); if (is_u(etmp)) Strcat(wholebuf, verb); else Strcat(wholebuf, vtense((char *)0, verb)); return(wholebuf); } /* * Simple-minded "can it be here?" routine */ STATIC_OVL boolean e_survives_at(etmp, x, y) struct entity *etmp; int x, y; { if (noncorporeal(etmp->edata)) return(TRUE); if (is_pool(x, y)) return (boolean)((is_u(etmp) && (Wwalking || Amphibious || Swimming || Flying || Levitation)) || is_swimmer(etmp->edata) || is_flyer(etmp->edata) || is_floater(etmp->edata)); /* must force call to lava_effects in e_died if is_u */ if (is_lava(x, y)) return (boolean)((is_u(etmp) && (Levitation || Flying)) || likes_lava(etmp->edata) || is_flyer(etmp->edata)); if (is_db_wall(x, y)) return((boolean)(is_u(etmp) ? Passes_walls : passes_walls(etmp->edata))); return(TRUE); } STATIC_OVL void e_died(etmp, dest, how) struct entity *etmp; int dest, how; { if (is_u(etmp)) { if (how == DROWNING) { killer = 0; /* drown() sets its own killer */ (void) drown(); } else if (how == BURNING) { killer = 0; /* lava_effects() sets its own killer */ (void) lava_effects(); } else { coord xy; /* use more specific killer if specified */ if (!killer) { killer_format = KILLED_BY_AN; killer = "falling drawbridge"; } done(how); /* So, you didn't die */ if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { if (enexto(&xy, etmp->ex, etmp->ey, etmp->edata)) { pline("A %s force teleports you away...", Hallucination ? "normal" : "strange"); teleds(xy.x, xy.y, FALSE); } /* otherwise on top of the drawbridge is the * only viable spot in the dungeon, so stay there */ } } /* we might have crawled out of the moat to survive */ etmp->ex = u.ux, etmp->ey = u.uy; } else { int entitycnt; killer = 0; /* fake "digested to death" damage-type suppresses corpse */ #define mk_message(dest) ((dest & 1) ? "" : (char *)0) #define mk_corpse(dest) ((dest & 2) ? AD_DGST : AD_PHYS) /* if monsters are moving, one of them caused the destruction */ if (flags.mon_moving) monkilled(etmp->emon, mk_message(dest), mk_corpse(dest)); else /* you caused it */ xkilled(etmp->emon, dest); etmp->edata = (struct permonst *)0; /* dead long worm handling */ for (entitycnt = 0; entitycnt < ENTITIES; entitycnt++) { if (etmp != &(occupants[entitycnt]) && etmp->emon == occupants[entitycnt].emon) occupants[entitycnt].edata = (struct permonst *)0; } #undef mk_message #undef mk_corpse } } /* * These are never directly affected by a bridge or portcullis. */ STATIC_OVL boolean automiss(etmp) struct entity *etmp; { return (boolean)((is_u(etmp) ? Passes_walls : passes_walls(etmp->edata)) || noncorporeal(etmp->edata)); } /* * Does falling drawbridge or portcullis miss etmp? */ STATIC_OVL boolean e_missed(etmp, chunks) struct entity *etmp; boolean chunks; { int misses; #ifdef D_DEBUG if (chunks) pline("Do chunks miss?"); #endif if (automiss(etmp)) return(TRUE); if (is_flyer(etmp->edata) && (is_u(etmp)? !Sleeping : (etmp->emon->mcanmove && !etmp->emon->msleeping))) /* flying requires mobility */ misses = 5; /* out of 8 */ else if (is_floater(etmp->edata) || (is_u(etmp) && Levitation)) /* doesn't require mobility */ misses = 3; else if (chunks && is_pool(etmp->ex, etmp->ey)) misses = 2; /* sitting ducks */ else misses = 0; if (is_db_wall(etmp->ex, etmp->ey)) misses -= 3; /* less airspace */ #ifdef D_DEBUG pline("Miss chance = %d (out of 8)", misses); #endif return((boolean)((misses >= rnd(8))? TRUE : FALSE)); } /* * Can etmp jump from death? */ STATIC_OVL boolean e_jumps(etmp) struct entity *etmp; { int tmp = 4; /* out of 10 */ if (is_u(etmp)? (Sleeping || Fumbling) : (!etmp->emon->mcanmove || etmp->emon->msleeping || !etmp->edata->mmove || etmp->emon->wormno)) return(FALSE); if (is_u(etmp)? Confusion : etmp->emon->mconf) tmp -= 2; if (is_u(etmp)? Stunned : etmp->emon->mstun) tmp -= 3; if (is_db_wall(etmp->ex, etmp->ey)) tmp -= 2; /* less room to maneuver */ #ifdef D_DEBUG pline("%s to jump (%d chances in 10)", E_phrase(etmp, "try"), tmp); #endif return((boolean)((tmp >= rnd(10))? TRUE : FALSE)); } STATIC_OVL void do_entity(etmp) struct entity *etmp; { int newx, newy, at_portcullis, oldx, oldy; boolean must_jump = FALSE, relocates = FALSE, e_inview; struct rm *crm; if (!etmp->edata) return; e_inview = e_canseemon(etmp); oldx = etmp->ex; oldy = etmp->ey; at_portcullis = is_db_wall(oldx, oldy); crm = &levl[oldx][oldy]; if (automiss(etmp) && e_survives_at(etmp, oldx, oldy)) { if (e_inview && (at_portcullis || IS_DRAWBRIDGE(crm->typ))) pline_The("%s passes through %s!", at_portcullis ? "portcullis" : "drawbridge", e_nam(etmp)); if (is_u(etmp)) spoteffects(FALSE); return; } if (e_missed(etmp, FALSE)) { if (at_portcullis) pline_The("portcullis misses %s!", e_nam(etmp)); #ifdef D_DEBUG else pline_The("drawbridge misses %s!", e_nam(etmp)); #endif if (e_survives_at(etmp, oldx, oldy)) return; else { #ifdef D_DEBUG pline("Mon can't survive here"); #endif if (at_portcullis) must_jump = TRUE; else relocates = TRUE; /* just ride drawbridge in */ } } else { if (crm->typ == DRAWBRIDGE_DOWN) { pline("%s crushed underneath the drawbridge.", E_phrase(etmp, "are")); /* no jump */ e_died(etmp, e_inview? 3 : 2, CRUSHING);/* no corpse */ return; /* Note: Beyond this point, we know we're */ } /* not at an opened drawbridge, since all */ must_jump = TRUE; /* *missable* creatures survive on the */ } /* square, and all the unmissed ones die. */ if (must_jump) { if (at_portcullis) { if (e_jumps(etmp)) { relocates = TRUE; #ifdef D_DEBUG pline("Jump succeeds!"); #endif } else { if (e_inview) pline("%s crushed by the falling portcullis!", E_phrase(etmp, "are")); else if (flags.soundok) You_hear("a crushing sound."); e_died(etmp, e_inview? 3 : 2, CRUSHING); /* no corpse */ return; } } else { /* tries to jump off bridge to original square */ relocates = !e_jumps(etmp); #ifdef D_DEBUG pline("Jump %s!", (relocates)? "fails" : "succeeds"); #endif } } /* * Here's where we try to do relocation. Assumes that etmp is not arriving * at the portcullis square while the drawbridge is falling, since this square * would be inaccessible (i.e. etmp started on drawbridge square) or * unnecessary (i.e. etmp started here) in such a situation. */ #ifdef D_DEBUG pline("Doing relocation."); #endif newx = oldx; newy = oldy; (void)find_drawbridge(&newx, &newy); if ((newx == oldx) && (newy == oldy)) get_wall_for_db(&newx, &newy); #ifdef D_DEBUG pline("Checking new square for occupancy."); #endif if (relocates && (e_at(newx, newy))) { /* * Standoff problem: one or both entities must die, and/or both switch * places. Avoid infinite recursion by checking first whether the other * entity is staying put. Clean up if we happen to move/die in recursion. */ struct entity *other; other = e_at(newx, newy); #ifdef D_DEBUG pline("New square is occupied by %s", e_nam(other)); #endif if (e_survives_at(other, newx, newy) && automiss(other)) { relocates = FALSE; /* "other" won't budge */ #ifdef D_DEBUG pline("%s suicide.", E_phrase(etmp, "commit")); #endif } else { #ifdef D_DEBUG pline("Handling %s", e_nam(other)); #endif while ((e_at(newx, newy) != 0) && (e_at(newx, newy) != etmp)) do_entity(other); #ifdef D_DEBUG pline("Checking existence of %s", e_nam(etmp)); wait_synch(); #endif if (e_at(oldx, oldy) != etmp) { #ifdef D_DEBUG pline("%s moved or died in recursion somewhere", E_phrase(etmp, "have")); wait_synch(); #endif return; } } } if (relocates && !e_at(newx, newy)) {/* if e_at() entity = worm tail */ #ifdef D_DEBUG pline("Moving %s", e_nam(etmp)); #endif if (!is_u(etmp)) { remove_monster(etmp->ex, etmp->ey); place_monster(etmp->emon, newx, newy); update_monster_region(etmp->emon); } else { u.ux = newx; u.uy = newy; } etmp->ex = newx; etmp->ey = newy; e_inview = e_canseemon(etmp); } #ifdef D_DEBUG pline("Final disposition of %s", e_nam(etmp)); wait_synch(); #endif if (is_db_wall(etmp->ex, etmp->ey)) { #ifdef D_DEBUG pline("%s in portcullis chamber", E_phrase(etmp, "are")); wait_synch(); #endif if (e_inview) { if (is_u(etmp)) { You("tumble towards the closed portcullis!"); if (automiss(etmp)) You("pass through it!"); else pline_The("drawbridge closes in..."); } else pline("%s behind the drawbridge.", E_phrase(etmp, "disappear")); } if (!e_survives_at(etmp, etmp->ex, etmp->ey)) { killer_format = KILLED_BY_AN; killer = "closing drawbridge"; e_died(etmp, 0, CRUSHING); /* no message */ return; } #ifdef D_DEBUG pline("%s in here", E_phrase(etmp, "survive")); #endif } else { #ifdef D_DEBUG pline("%s on drawbridge square", E_phrase(etmp, "are")); #endif if (is_pool(etmp->ex, etmp->ey) && !e_inview) if (flags.soundok) You_hear("a splash."); if (e_survives_at(etmp, etmp->ex, etmp->ey)) { if (e_inview && !is_flyer(etmp->edata) && !is_floater(etmp->edata)) pline("%s from the bridge.", E_phrase(etmp, "fall")); return; } #ifdef D_DEBUG pline("%s cannot survive on the drawbridge square",Enam(etmp)); #endif if (is_pool(etmp->ex, etmp->ey) || is_lava(etmp->ex, etmp->ey)) if (e_inview && !is_u(etmp)) { /* drown() will supply msgs if nec. */ boolean lava = is_lava(etmp->ex, etmp->ey); if (Hallucination) pline("%s the %s and disappears.", E_phrase(etmp, "drink"), lava ? "lava" : "moat"); else pline("%s into the %s.", E_phrase(etmp, "fall"), lava ? "lava" : "moat"); } killer_format = NO_KILLER_PREFIX; killer = "fell from a drawbridge"; e_died(etmp, e_inview ? 3 : 2, /* CRUSHING is arbitrary */ (is_pool(etmp->ex, etmp->ey)) ? DROWNING : (is_lava(etmp->ex, etmp->ey)) ? BURNING : CRUSHING); /*no corpse*/ return; } } /* * Close the drawbridge located at x,y */ void close_drawbridge(x,y) int x,y; { register struct rm *lev1, *lev2; struct trap *t; int x2, y2; lev1 = &levl[x][y]; if (lev1->typ != DRAWBRIDGE_DOWN) return; x2 = x; y2 = y; get_wall_for_db(&x2,&y2); if (cansee(x,y) || cansee(x2,y2)) You("see a drawbridge %s up!", (((u.ux == x || u.uy == y) && !Underwater) || distu(x2,y2) < distu(x,y)) ? "coming" : "going"); lev1->typ = DRAWBRIDGE_UP; lev2 = &levl[x2][y2]; lev2->typ = DBWALL; switch (lev1->drawbridgemask & DB_DIR) { case DB_NORTH: case DB_SOUTH: lev2->horizontal = TRUE; break; case DB_WEST: case DB_EAST: lev2->horizontal = FALSE; break; } lev2->wall_info = W_NONDIGGABLE; set_entity(x, y, &(occupants[0])); set_entity(x2, y2, &(occupants[1])); do_entity(&(occupants[0])); /* Do set_entity after first */ set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tail */ do_entity(&(occupants[1])); if(OBJ_AT(x,y) && flags.soundok) You_hear("smashing and crushing."); (void) revive_nasty(x,y,(char *)0); (void) revive_nasty(x2,y2,(char *)0); delallobj(x, y); delallobj(x2, y2); if ((t = t_at(x, y)) != 0) deltrap(t); if ((t = t_at(x2, y2)) != 0) deltrap(t); newsym(x, y); newsym(x2, y2); block_point(x2,y2); /* vision */ } /* * Open the drawbridge located at x,y */ void open_drawbridge(x,y) int x,y; { register struct rm *lev1, *lev2; struct trap *t; int x2, y2; lev1 = &levl[x][y]; if (lev1->typ != DRAWBRIDGE_UP) return; x2 = x; y2 = y; get_wall_for_db(&x2,&y2); if (cansee(x,y) || cansee(x2,y2)) You("see a drawbridge %s down!", (distu(x2,y2) < distu(x,y)) ? "going" : "coming"); lev1->typ = DRAWBRIDGE_DOWN; lev2 = &levl[x2][y2]; lev2->typ = DOOR; lev2->doormask = D_NODOOR; set_entity(x, y, &(occupants[0])); set_entity(x2, y2, &(occupants[1])); do_entity(&(occupants[0])); /* do set_entity after first */ set_entity(x2, y2, &(occupants[1])); /* do_entity for worm tails */ do_entity(&(occupants[1])); (void) revive_nasty(x,y,(char *)0); delallobj(x, y); if ((t = t_at(x, y)) != 0) deltrap(t); if ((t = t_at(x2, y2)) != 0) deltrap(t); newsym(x, y); newsym(x2, y2); unblock_point(x2,y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; } /* * Let's destroy the drawbridge located at x,y */ void destroy_drawbridge(x,y) int x,y; { register struct rm *lev1, *lev2; struct trap *t; int x2, y2; boolean e_inview; struct entity *etmp1 = &(occupants[0]), *etmp2 = &(occupants[1]); lev1 = &levl[x][y]; if (!IS_DRAWBRIDGE(lev1->typ)) return; x2 = x; y2 = y; get_wall_for_db(&x2,&y2); lev2 = &levl[x2][y2]; if ((lev1->drawbridgemask & DB_UNDER) == DB_MOAT || (lev1->drawbridgemask & DB_UNDER) == DB_LAVA) { struct obj *otmp; boolean lava = (lev1->drawbridgemask & DB_UNDER) == DB_LAVA; if (lev1->typ == DRAWBRIDGE_UP) { if (cansee(x2,y2)) pline_The("portcullis of the drawbridge falls into the %s!", lava ? "lava" : "moat"); else if (flags.soundok) You_hear("a loud *SPLASH*!"); } else { if (cansee(x,y)) pline_The("drawbridge collapses into the %s!", lava ? "lava" : "moat"); else if (flags.soundok) You_hear("a loud *SPLASH*!"); } lev1->typ = lava ? LAVAPOOL : MOAT; lev1->drawbridgemask = 0; if ((otmp = sobj_at(BOULDER,x,y)) != 0) { obj_extract_self(otmp); (void) flooreffects(otmp,x,y,"fall"); } } else { if (cansee(x,y)) pline_The("drawbridge disintegrates!"); else You_hear("a loud *CRASH*!"); lev1->typ = ((lev1->drawbridgemask & DB_ICE) ? ICE : ROOM); lev1->icedpool = ((lev1->drawbridgemask & DB_ICE) ? ICED_MOAT : 0); } wake_nearto(x, y, 500); lev2->typ = DOOR; lev2->doormask = D_NODOOR; if ((t = t_at(x, y)) != 0) deltrap(t); if ((t = t_at(x2, y2)) != 0) deltrap(t); newsym(x,y); newsym(x2,y2); if (!does_block(x2,y2,lev2)) unblock_point(x2,y2); /* vision */ if (Is_stronghold(&u.uz)) u.uevent.uopened_dbridge = TRUE; set_entity(x2, y2, etmp2); /* currently only automissers can be here */ if (etmp2->edata) { e_inview = e_canseemon(etmp2); if (!automiss(etmp2)) { if (e_inview) pline("%s blown apart by flying debris.", E_phrase(etmp2, "are")); killer_format = KILLED_BY_AN; killer = "exploding drawbridge"; e_died(etmp2, e_inview? 3 : 2, CRUSHING); /*no corpse*/ } /* nothing which is vulnerable can survive this */ } set_entity(x, y, etmp1); if (etmp1->edata) { e_inview = e_canseemon(etmp1); if (e_missed(etmp1, TRUE)) { #ifdef D_DEBUG pline("%s spared!", E_phrase(etmp1, "are")); #endif } else { if (e_inview) { if (!is_u(etmp1) && Hallucination) pline("%s into some heavy metal!", E_phrase(etmp1, "get")); else pline("%s hit by a huge chunk of metal!", E_phrase(etmp1, "are")); } else { if (flags.soundok && !is_u(etmp1) && !is_pool(x,y)) You_hear("a crushing sound."); #ifdef D_DEBUG else pline("%s from shrapnel", E_phrase(etmp1, "die")); #endif } killer_format = KILLED_BY_AN; killer = "collapsing drawbridge"; e_died(etmp1, e_inview? 3 : 2, CRUSHING); /*no corpse*/ if(lev1->typ == MOAT) do_entity(etmp1); } } } #endif /* OVLB */ /*dbridge.c*/ nethack-3.4.3/src/decl.c0100644000000000000000000002122307764735041013514 0ustar rootroot/* SCCS Id: @(#)decl.c 3.2 2001/12/10 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" int NDECL((*afternmv)); int NDECL((*occupation)); /* from xxxmain.c */ const char *hname = 0; /* name of the game (argv[0] of main) */ int hackpid = 0; /* current process id */ #if defined(UNIX) || defined(VMS) int locknum = 0; /* max num of simultaneous users */ #endif #ifdef DEF_PAGER char *catmore = 0; /* default pager */ #endif NEARDATA int bases[MAXOCLASSES] = DUMMY; NEARDATA int multi = 0; #if 0 NEARDATA int warnlevel = 0; /* used by movemon and dochugw */ #endif NEARDATA int nroom = 0; NEARDATA int nsubroom = 0; NEARDATA int occtime = 0; int x_maze_max, y_maze_max; /* initialized in main, used in mkmaze.c */ int otg_temp; /* used by object_to_glyph() [otg] */ #ifdef REDO NEARDATA int in_doagain = 0; #endif /* * The following structure will be initialized at startup time with * the level numbers of some "important" things in the game. */ struct dgn_topology dungeon_topology = {DUMMY}; #include "quest.h" struct q_score quest_status = DUMMY; NEARDATA int smeq[MAXNROFROOMS+1] = DUMMY; NEARDATA int doorindex = 0; NEARDATA char *save_cm = 0; NEARDATA int killer_format = 0; const char *killer = 0; const char *delayed_killer = 0; #ifdef GOLDOBJ NEARDATA long done_money = 0; #endif char killer_buf[BUFSZ] = DUMMY; const char *nomovemsg = 0; const char nul[40] = DUMMY; /* contains zeros */ NEARDATA char plname[PL_NSIZ] = DUMMY; /* player name */ NEARDATA char pl_character[PL_CSIZ] = DUMMY; NEARDATA char pl_race = '\0'; NEARDATA char pl_fruit[PL_FSIZ] = DUMMY; NEARDATA int current_fruit = 0; NEARDATA struct fruit *ffruit = (struct fruit *)0; NEARDATA char tune[6] = DUMMY; const char *occtxt = DUMMY; const char quitchars[] = " \r\n\033"; const char vowels[] = "aeiouAEIOU"; const char ynchars[] = "yn"; const char ynqchars[] = "ynq"; const char ynaqchars[] = "ynaq"; const char ynNaqchars[] = "yn#aq"; NEARDATA long yn_number = 0L; const char disclosure_options[] = "iavgc"; #if defined(MICRO) || defined(WIN32) char hackdir[PATHLEN]; /* where rumors, help, record are */ # ifdef MICRO char levels[PATHLEN]; /* where levels are */ # endif #endif /* MICRO || WIN32 */ #ifdef MFLOPPY char permbones[PATHLEN]; /* where permanent copy of bones go */ int ramdisk = FALSE; /* whether to copy bones to levels or not */ int saveprompt = TRUE; const char *alllevels = "levels.*"; const char *allbones = "bones*.*"; #endif struct linfo level_info[MAXLINFO]; NEARDATA struct sinfo program_state; /* 'rogue'-like direction commands (cmd.c) */ const char sdir[] = "hykulnjb><"; const char ndir[] = "47896321><"; /* number pad mode */ const schar xdir[10] = { -1,-1, 0, 1, 1, 1, 0,-1, 0, 0 }; const schar ydir[10] = { 0,-1,-1,-1, 0, 1, 1, 1, 0, 0 }; const schar zdir[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1,-1 }; NEARDATA schar tbx = 0, tby = 0; /* mthrowu: target */ /* for xname handling of multiple shot missile volleys: number of shots, index of current one, validity check, shoot vs throw */ NEARDATA struct multishot m_shot = { 0, 0, STRANGE_OBJECT, FALSE }; NEARDATA struct dig_info digging; NEARDATA dungeon dungeons[MAXDUNGEON]; /* ini'ed by init_dungeon() */ NEARDATA s_level *sp_levchn; NEARDATA stairway upstair = { 0, 0 }, dnstair = { 0, 0 }; NEARDATA stairway upladder = { 0, 0 }, dnladder = { 0, 0 }; NEARDATA stairway sstairs = { 0, 0 }; NEARDATA dest_area updest = { 0, 0, 0, 0, 0, 0, 0, 0 }; NEARDATA dest_area dndest = { 0, 0, 0, 0, 0, 0, 0, 0 }; NEARDATA coord inv_pos = { 0, 0 }; NEARDATA boolean in_mklev = FALSE; NEARDATA boolean stoned = FALSE; /* done to monsters hit by 'c' */ NEARDATA boolean unweapon = FALSE; NEARDATA boolean mrg_to_wielded = FALSE; /* weapon picked is merged with wielded one */ NEARDATA struct obj *current_wand = 0; /* wand currently zapped/applied */ NEARDATA boolean in_steed_dismounting = FALSE; NEARDATA coord bhitpos = DUMMY; NEARDATA coord doors[DOORMAX] = {DUMMY}; NEARDATA struct mkroom rooms[(MAXNROFROOMS+1)*2] = {DUMMY}; NEARDATA struct mkroom* subrooms = &rooms[MAXNROFROOMS+1]; struct mkroom *upstairs_room, *dnstairs_room, *sstairs_room; dlevel_t level; /* level map */ struct trap *ftrap = (struct trap *)0; NEARDATA struct monst youmonst = DUMMY; NEARDATA struct flag flags = DUMMY; NEARDATA struct instance_flags iflags = DUMMY; NEARDATA struct you u = DUMMY; NEARDATA struct obj *invent = (struct obj *)0, *uwep = (struct obj *)0, *uarm = (struct obj *)0, *uswapwep = (struct obj *)0, *uquiver = (struct obj *)0, /* quiver */ #ifdef TOURIST *uarmu = (struct obj *)0, /* under-wear, so to speak */ #endif *uskin = (struct obj *)0, /* dragon armor, if a dragon */ *uarmc = (struct obj *)0, *uarmh = (struct obj *)0, *uarms = (struct obj *)0, *uarmg = (struct obj *)0, *uarmf = (struct obj *)0, *uamul = (struct obj *)0, *uright = (struct obj *)0, *uleft = (struct obj *)0, *ublindf = (struct obj *)0, *uchain = (struct obj *)0, *uball = (struct obj *)0; #ifdef TEXTCOLOR /* * This must be the same order as used for buzz() in zap.c. */ const int zapcolors[NUM_ZAP] = { HI_ZAP, /* 0 - missile */ CLR_ORANGE, /* 1 - fire */ CLR_WHITE, /* 2 - frost */ HI_ZAP, /* 3 - sleep */ CLR_BLACK, /* 4 - death */ CLR_WHITE, /* 5 - lightning */ CLR_YELLOW, /* 6 - poison gas */ CLR_GREEN, /* 7 - acid */ }; #endif /* text color */ const int shield_static[SHIELD_COUNT] = { S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, /* 7 per row */ S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, S_ss1, S_ss2, S_ss3, S_ss2, S_ss1, S_ss2, S_ss4, }; NEARDATA struct spell spl_book[MAXSPELL + 1] = {DUMMY}; NEARDATA long moves = 1L, monstermoves = 1L; /* These diverge when player is Fast */ NEARDATA long wailmsg = 0L; /* objects that are moving to another dungeon level */ NEARDATA struct obj *migrating_objs = (struct obj *)0; /* objects not yet paid for */ NEARDATA struct obj *billobjs = (struct obj *)0; /* used to zero all elements of a struct obj */ NEARDATA struct obj zeroobj = DUMMY; /* originally from dog.c */ NEARDATA char dogname[PL_PSIZ] = DUMMY; NEARDATA char catname[PL_PSIZ] = DUMMY; NEARDATA char horsename[PL_PSIZ] = DUMMY; char preferred_pet; /* '\0', 'c', 'd', 'n' (none) */ /* monsters that went down/up together with @ */ NEARDATA struct monst *mydogs = (struct monst *)0; /* monsters that are moving to another dungeon level */ NEARDATA struct monst *migrating_mons = (struct monst *)0; NEARDATA struct mvitals mvitals[NUMMONS]; NEARDATA struct c_color_names c_color_names = { "black", "amber", "golden", "light blue", "red", "green", "silver", "blue", "purple", "white" }; const char *c_obj_colors[] = { "black", /* CLR_BLACK */ "red", /* CLR_RED */ "green", /* CLR_GREEN */ "brown", /* CLR_BROWN */ "blue", /* CLR_BLUE */ "magenta", /* CLR_MAGENTA */ "cyan", /* CLR_CYAN */ "gray", /* CLR_GRAY */ "transparent", /* no_color */ "orange", /* CLR_ORANGE */ "bright green", /* CLR_BRIGHT_GREEN */ "yellow", /* CLR_YELLOW */ "bright blue", /* CLR_BRIGHT_BLUE */ "bright magenta", /* CLR_BRIGHT_MAGENTA */ "bright cyan", /* CLR_BRIGHT_CYAN */ "white", /* CLR_WHITE */ }; struct c_common_strings c_common_strings = { "Nothing happens.", "That's enough tries!", "That is a silly thing to %s.", "shudder for a moment.", "something", "Something", "You can move again.", "Never mind.", "vision quickly clears.", {"the", "your"} }; /* NOTE: the order of these words exactly corresponds to the order of oc_material values #define'd in objclass.h. */ const char *materialnm[] = { "mysterious", "liquid", "wax", "organic", "flesh", "paper", "cloth", "leather", "wooden", "bone", "dragonhide", "iron", "metal", "copper", "silver", "gold", "platinum", "mithril", "plastic", "glass", "gemstone", "stone" }; /* Vision */ NEARDATA boolean vision_full_recalc = 0; NEARDATA char **viz_array = 0;/* used in cansee() and couldsee() macros */ /* Global windowing data, defined here for multi-window-system support */ NEARDATA winid WIN_MESSAGE = WIN_ERR, WIN_STATUS = WIN_ERR; NEARDATA winid WIN_MAP = WIN_ERR, WIN_INVEN = WIN_ERR; char toplines[TBUFSZ]; /* Windowing stuff that's really tty oriented, but present for all ports */ struct tc_gbl_data tc_gbl_data = { 0,0, 0,0 }; /* AS,AE, LI,CO */ char *fqn_prefix[PREFIX_COUNT] = { (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0 }; #ifdef PREFIXES_IN_USE char *fqn_prefix_names[PREFIX_COUNT] = { "hackdir", "leveldir", "savedir", "bonesdir", "datadir", "scoredir", "lockdir", "configdir", "troubledir" }; #endif /* dummy routine used to force linkage */ void decl_init() { return; } /*decl.c*/ nethack-3.4.3/src/detect.c0100644000000000000000000010357507764735041014070 0ustar rootroot/* SCCS Id: @(#)detect.c 3.4 2003/08/13 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * Detection routines, including crystal ball, magic mapping, and search * command. */ #include "hack.h" #include "artifact.h" extern boolean known; /* from read.c */ STATIC_DCL void FDECL(do_dknown_of, (struct obj *)); STATIC_DCL boolean FDECL(check_map_spot, (int,int,CHAR_P,unsigned)); STATIC_DCL boolean FDECL(clear_stale_map, (CHAR_P,unsigned)); STATIC_DCL void FDECL(sense_trap, (struct trap *,XCHAR_P,XCHAR_P,int)); STATIC_DCL void FDECL(show_map_spot, (int,int)); STATIC_PTR void FDECL(findone,(int,int,genericptr_t)); STATIC_PTR void FDECL(openone,(int,int,genericptr_t)); /* Recursively search obj for an object in class oclass and return 1st found */ struct obj * o_in(obj, oclass) struct obj* obj; char oclass; { register struct obj* otmp; struct obj *temp; if (obj->oclass == oclass) return obj; if (Has_contents(obj)) { for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (otmp->oclass == oclass) return otmp; else if (Has_contents(otmp) && (temp = o_in(otmp, oclass))) return temp; } return (struct obj *) 0; } /* Recursively search obj for an object made of specified material and return 1st found */ struct obj * o_material(obj, material) struct obj* obj; unsigned material; { register struct obj* otmp; struct obj *temp; if (objects[obj->otyp].oc_material == material) return obj; if (Has_contents(obj)) { for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (objects[otmp->otyp].oc_material == material) return otmp; else if (Has_contents(otmp) && (temp = o_material(otmp, material))) return temp; } return (struct obj *) 0; } STATIC_OVL void do_dknown_of(obj) struct obj *obj; { struct obj *otmp; obj->dknown = 1; if (Has_contents(obj)) { for(otmp = obj->cobj; otmp; otmp = otmp->nobj) do_dknown_of(otmp); } } /* Check whether the location has an outdated object displayed on it. */ STATIC_OVL boolean check_map_spot(x, y, oclass, material) int x, y; register char oclass; unsigned material; { register int glyph; register struct obj *otmp; register struct monst *mtmp; glyph = glyph_at(x,y); if (glyph_is_object(glyph)) { /* there's some object shown here */ if (oclass == ALL_CLASSES) { return((boolean)( !(level.objects[x][y] || /* stale if nothing here */ ((mtmp = m_at(x,y)) != 0 && ( #ifndef GOLDOBJ mtmp->mgold || #endif mtmp->minvent))))); } else { if (material && objects[glyph_to_obj(glyph)].oc_material == material) { /* the object shown here is of interest because material matches */ for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (o_material(otmp, GOLD)) return FALSE; /* didn't find it; perhaps a monster is carrying it */ if ((mtmp = m_at(x,y)) != 0) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (o_material(otmp, GOLD)) return FALSE; } /* detection indicates removal of this object from the map */ return TRUE; } if (oclass && objects[glyph_to_obj(glyph)].oc_class == oclass) { /* the object shown here is of interest because its class matches */ for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (o_in(otmp, oclass)) return FALSE; /* didn't find it; perhaps a monster is carrying it */ #ifndef GOLDOBJ if ((mtmp = m_at(x,y)) != 0) { if (oclass == COIN_CLASS && mtmp->mgold) return FALSE; else for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (o_in(otmp, oclass)) return FALSE; } #else if ((mtmp = m_at(x,y)) != 0) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (o_in(otmp, oclass)) return FALSE; } #endif /* detection indicates removal of this object from the map */ return TRUE; } } } return FALSE; } /* When doing detection, remove stale data from the map display (corpses rotted away, objects carried away by monsters, etc) so that it won't reappear after the detection has completed. Return true if noticeable change occurs. */ STATIC_OVL boolean clear_stale_map(oclass, material) register char oclass; unsigned material; { register int zx, zy; register boolean change_made = FALSE; for (zx = 1; zx < COLNO; zx++) for (zy = 0; zy < ROWNO; zy++) if (check_map_spot(zx, zy, oclass,material)) { unmap_object(zx, zy); change_made = TRUE; } return change_made; } /* look for gold, on the floor or in monsters' possession */ int gold_detect(sobj) register struct obj *sobj; { register struct obj *obj; register struct monst *mtmp; int uw = u.uinwater; struct obj *temp; boolean stale; known = stale = clear_stale_map(COIN_CLASS, (unsigned)(sobj->blessed ? GOLD : 0)); /* look for gold carried by monsters (might be in a container) */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; /* probably not needed in this case but... */ #ifndef GOLDOBJ if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) { #else if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { #endif known = TRUE; goto outgoldmap; /* skip further searching */ } else for (obj = mtmp->minvent; obj; obj = obj->nobj) if (sobj->blessed && o_material(obj, GOLD)) { known = TRUE; goto outgoldmap; } else if (o_in(obj, COIN_CLASS)) { known = TRUE; goto outgoldmap; /* skip further searching */ } } /* look for gold objects */ for (obj = fobj; obj; obj = obj->nobj) { if (sobj->blessed && o_material(obj, GOLD)) { known = TRUE; if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap; } else if (o_in(obj, COIN_CLASS)) { known = TRUE; if (obj->ox != u.ux || obj->oy != u.uy) goto outgoldmap; } } if (!known) { /* no gold found on floor or monster's inventory. adjust message if you have gold in your inventory */ if (sobj) { char buf[BUFSZ]; if (youmonst.data == &mons[PM_GOLD_GOLEM]) { Sprintf(buf, "You feel like a million %s!", currency(2L)); } else if (hidden_gold() || #ifndef GOLDOBJ u.ugold) #else money_cnt(invent)) #endif Strcpy(buf, "You feel worried about your future financial situation."); else Strcpy(buf, "You feel materially poor."); strange_feeling(sobj, buf); } return(1); } /* only under me - no separate display required */ if (stale) docrt(); You("notice some gold between your %s.", makeplural(body_part(FOOT))); return(0); outgoldmap: cls(); u.uinwater = 0; /* Discover gold locations. */ for (obj = fobj; obj; obj = obj->nobj) { if (sobj->blessed && (temp = o_material(obj, GOLD))) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; } map_object(temp,1); } else if ((temp = o_in(obj, COIN_CLASS))) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; } map_object(temp,1); } } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; /* probably overkill here */ #ifndef GOLDOBJ if (mtmp->mgold || monsndx(mtmp->data) == PM_GOLD_GOLEM) { #else if (findgold(mtmp->minvent) || monsndx(mtmp->data) == PM_GOLD_GOLEM) { #endif struct obj gold; gold.otyp = GOLD_PIECE; gold.ox = mtmp->mx; gold.oy = mtmp->my; map_object(&gold,1); } else for (obj = mtmp->minvent; obj; obj = obj->nobj) if (sobj->blessed && (temp = o_material(obj, GOLD))) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp,1); break; } else if ((temp = o_in(obj, COIN_CLASS))) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp,1); break; } } newsym(u.ux,u.uy); You_feel("very greedy, and sense gold!"); exercise(A_WIS, TRUE); display_nhwindow(WIN_MAP, TRUE); docrt(); u.uinwater = uw; if (Underwater) under_water(2); if (u.uburied) under_ground(2); return(0); } /* returns 1 if nothing was detected */ /* returns 0 if something was detected */ int food_detect(sobj) register struct obj *sobj; { register struct obj *obj; register struct monst *mtmp; register int ct = 0, ctu = 0; boolean confused = (Confusion || (sobj && sobj->cursed)), stale; char oclass = confused ? POTION_CLASS : FOOD_CLASS; const char *what = confused ? something : "food"; int uw = u.uinwater; stale = clear_stale_map(oclass, 0); for (obj = fobj; obj; obj = obj->nobj) if (o_in(obj, oclass)) { if (obj->ox == u.ux && obj->oy == u.uy) ctu++; else ct++; } for (mtmp = fmon; mtmp && !ct; mtmp = mtmp->nmon) { /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */ for (obj = mtmp->minvent; obj; obj = obj->nobj) if (o_in(obj, oclass)) { ct++; break; } } if (!ct && !ctu) { known = stale && !confused; if (stale) { docrt(); You("sense a lack of %s nearby.", what); if (sobj && sobj->blessed) { if (!u.uedibility) Your("%s starts to tingle.", body_part(NOSE)); u.uedibility = 1; } } else if (sobj) { char buf[BUFSZ]; Sprintf(buf, "Your %s twitches%s.", body_part(NOSE), (sobj->blessed && !u.uedibility) ? " then starts to tingle" : ""); if (sobj->blessed && !u.uedibility) { boolean savebeginner = flags.beginner; /* prevent non-delivery of */ flags.beginner = FALSE; /* message */ strange_feeling(sobj, buf); flags.beginner = savebeginner; u.uedibility = 1; } else strange_feeling(sobj, buf); } return !stale; } else if (!ct) { known = TRUE; You("%s %s nearby.", sobj ? "smell" : "sense", what); if (sobj && sobj->blessed) { if (!u.uedibility) pline("Your %s starts to tingle.", body_part(NOSE)); u.uedibility = 1; } } else { struct obj *temp; known = TRUE; cls(); u.uinwater = 0; for (obj = fobj; obj; obj = obj->nobj) if ((temp = o_in(obj, oclass)) != 0) { if (temp != obj) { temp->ox = obj->ox; temp->oy = obj->oy; } map_object(temp,1); } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) /* no DEADMONSTER(mtmp) check needed since dmons never have inventory */ for (obj = mtmp->minvent; obj; obj = obj->nobj) if ((temp = o_in(obj, oclass)) != 0) { temp->ox = mtmp->mx; temp->oy = mtmp->my; map_object(temp,1); break; /* skip rest of this monster's inventory */ } newsym(u.ux,u.uy); if (sobj) { if (sobj->blessed) { Your("%s %s to tingle and you smell %s.", body_part(NOSE), u.uedibility ? "continues" : "starts", what); u.uedibility = 1; } else Your("%s tingles and you smell %s.", body_part(NOSE), what); } else You("sense %s.", what); display_nhwindow(WIN_MAP, TRUE); exercise(A_WIS, TRUE); docrt(); u.uinwater = uw; if (Underwater) under_water(2); if (u.uburied) under_ground(2); } return(0); } /* * Used for scrolls, potions, spells, and crystal balls. Returns: * * 1 - nothing was detected * 0 - something was detected */ int object_detect(detector, class) struct obj *detector; /* object doing the detecting */ int class; /* an object class, 0 for all */ { register int x, y; char stuff[BUFSZ]; int is_cursed = (detector && detector->cursed); int do_dknown = (detector && (detector->oclass == POTION_CLASS || detector->oclass == SPBOOK_CLASS) && detector->blessed); int ct = 0, ctu = 0; register struct obj *obj, *otmp = (struct obj *)0; register struct monst *mtmp; int uw = u.uinwater; int sym, boulder = 0; if (class < 0 || class >= MAXOCLASSES) { impossible("object_detect: illegal class %d", class); class = 0; } /* Special boulder symbol check - does the class symbol happen * to match iflags.bouldersym which is a user-defined? * If so, that means we aren't sure what they really wanted to * detect. Rather than trump anything, show both possibilities. * We can exclude checking the buried obj chain for boulders below. */ sym = class ? def_oc_syms[class] : 0; if (sym && iflags.bouldersym && sym == iflags.bouldersym) boulder = ROCK_CLASS; if (Hallucination || (Confusion && class == SCROLL_CLASS)) Strcpy(stuff, something); else Strcpy(stuff, class ? oclass_names[class] : "objects"); if (boulder && class != ROCK_CLASS) Strcat(stuff, " and/or large stones"); if (do_dknown) for(obj = invent; obj; obj = obj->nobj) do_dknown_of(obj); for (obj = fobj; obj; obj = obj->nobj) { if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) { if (obj->ox == u.ux && obj->oy == u.uy) ctu++; else ct++; } if (do_dknown) do_dknown_of(obj); } for (obj = level.buriedobjlist; obj; obj = obj->nobj) { if (!class || o_in(obj, class)) { if (obj->ox == u.ux && obj->oy == u.uy) ctu++; else ct++; } if (do_dknown) do_dknown_of(obj); } for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) { if ((!class && !boulder) || o_in(obj, class) || o_in(obj, boulder)) ct++; if (do_dknown) do_dknown_of(obj); } if ((is_cursed && mtmp->m_ap_type == M_AP_OBJECT && (!class || class == objects[mtmp->mappearance].oc_class)) || #ifndef GOLDOBJ (mtmp->mgold && (!class || class == COIN_CLASS))) { #else (findgold(mtmp->minvent) && (!class || class == COIN_CLASS))) { #endif ct++; break; } } if (!clear_stale_map(!class ? ALL_CLASSES : class, 0) && !ct) { if (!ctu) { if (detector) strange_feeling(detector, "You feel a lack of something."); return 1; } You("sense %s nearby.", stuff); return 0; } cls(); u.uinwater = 0; /* * Map all buried objects first. */ for (obj = level.buriedobjlist; obj; obj = obj->nobj) if (!class || (otmp = o_in(obj, class))) { if (class) { if (otmp != obj) { otmp->ox = obj->ox; otmp->oy = obj->oy; } map_object(otmp, 1); } else map_object(obj, 1); } /* * If we are mapping all objects, map only the top object of a pile or * the first object in a monster's inventory. Otherwise, go looking * for a matching object class and display the first one encountered * at each location. * * Objects on the floor override buried objects. */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) for (obj = level.objects[x][y]; obj; obj = obj->nexthere) if ((!class && !boulder) || (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) { if (class || boulder) { if (otmp != obj) { otmp->ox = obj->ox; otmp->oy = obj->oy; } map_object(otmp, 1); } else map_object(obj, 1); break; } /* Objects in the monster's inventory override floor objects. */ for (mtmp = fmon ; mtmp ; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) if ((!class && !boulder) || (otmp = o_in(obj, class)) || (otmp = o_in(obj, boulder))) { if (!class && !boulder) otmp = obj; otmp->ox = mtmp->mx; /* at monster location */ otmp->oy = mtmp->my; map_object(otmp, 1); break; } /* Allow a mimic to override the detected objects it is carrying. */ if (is_cursed && mtmp->m_ap_type == M_AP_OBJECT && (!class || class == objects[mtmp->mappearance].oc_class)) { struct obj temp; temp.otyp = mtmp->mappearance; /* needed for obj_to_glyph() */ temp.ox = mtmp->mx; temp.oy = mtmp->my; temp.corpsenm = PM_TENGU; /* if mimicing a corpse */ map_object(&temp, 1); #ifndef GOLDOBJ } else if (mtmp->mgold && (!class || class == COIN_CLASS)) { #else } else if (findgold(mtmp->minvent) && (!class || class == COIN_CLASS)) { #endif struct obj gold; gold.otyp = GOLD_PIECE; gold.ox = mtmp->mx; gold.oy = mtmp->my; map_object(&gold, 1); } } newsym(u.ux,u.uy); You("detect the %s of %s.", ct ? "presence" : "absence", stuff); display_nhwindow(WIN_MAP, TRUE); /* * What are we going to do when the hero does an object detect while blind * and the detected object covers a known pool? */ docrt(); /* this will correctly reset vision */ u.uinwater = uw; if (Underwater) under_water(2); if (u.uburied) under_ground(2); return 0; } /* * Used by: crystal balls, potions, fountains * * Returns 1 if nothing was detected. * Returns 0 if something was detected. */ int monster_detect(otmp, mclass) register struct obj *otmp; /* detecting object (if any) */ int mclass; /* monster class, 0 for all */ { register struct monst *mtmp; int mcnt = 0; /* Note: This used to just check fmon for a non-zero value * but in versions since 3.3.0 fmon can test TRUE due to the * presence of dmons, so we have to find at least one * with positive hit-points to know for sure. */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp)) { mcnt++; break; } if (!mcnt) { if (otmp) strange_feeling(otmp, Hallucination ? "You get the heebie jeebies." : "You feel threatened."); return 1; } else { boolean woken = FALSE; cls(); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (!mclass || mtmp->data->mlet == mclass || (mtmp->data == &mons[PM_LONG_WORM] && mclass == S_WORM_TAIL)) if (mtmp->mx > 0) { if (mclass && def_monsyms[mclass] == ' ') show_glyph(mtmp->mx,mtmp->my, detected_mon_to_glyph(mtmp)); else show_glyph(mtmp->mx,mtmp->my,mon_to_glyph(mtmp)); /* don't be stingy - display entire worm */ if (mtmp->data == &mons[PM_LONG_WORM]) detect_wsegs(mtmp,0); } if (otmp && otmp->cursed && (mtmp->msleeping || !mtmp->mcanmove)) { mtmp->msleeping = mtmp->mfrozen = 0; mtmp->mcanmove = 1; woken = TRUE; } } display_self(); You("sense the presence of monsters."); if (woken) pline("Monsters sense the presence of you."); display_nhwindow(WIN_MAP, TRUE); docrt(); if (Underwater) under_water(2); if (u.uburied) under_ground(2); } return 0; } STATIC_OVL void sense_trap(trap, x, y, src_cursed) struct trap *trap; xchar x, y; int src_cursed; { if (Hallucination || src_cursed) { struct obj obj; /* fake object */ if (trap) { obj.ox = trap->tx; obj.oy = trap->ty; } else { obj.ox = x; obj.oy = y; } obj.otyp = (src_cursed) ? GOLD_PIECE : random_object(); obj.corpsenm = random_monster(); /* if otyp == CORPSE */ map_object(&obj,1); } else if (trap) { map_trap(trap,1); trap->tseen = 1; } else { struct trap temp_trap; /* fake trap */ temp_trap.tx = x; temp_trap.ty = y; temp_trap.ttyp = BEAR_TRAP; /* some kind of trap */ map_trap(&temp_trap,1); } } /* the detections are pulled out so they can */ /* also be used in the crystal ball routine */ /* returns 1 if nothing was detected */ /* returns 0 if something was detected */ int trap_detect(sobj) register struct obj *sobj; /* sobj is null if crystal ball, *scroll if gold detection scroll */ { register struct trap *ttmp; register struct obj *obj; register int door; int uw = u.uinwater; boolean found = FALSE; coord cc; for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { if (ttmp->tx != u.ux || ttmp->ty != u.uy) goto outtrapmap; else found = TRUE; } for (obj = fobj; obj; obj = obj->nobj) { if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped) { if (obj->ox != u.ux || obj->oy != u.uy) goto outtrapmap; else found = TRUE; } } for (door = 0; door < doorindex; door++) { cc = doors[door]; if (levl[cc.x][cc.y].doormask & D_TRAPPED) { if (cc.x != u.ux || cc.y != u.uy) goto outtrapmap; else found = TRUE; } } if (!found) { char buf[42]; Sprintf(buf, "Your %s stop itching.", makeplural(body_part(TOE))); strange_feeling(sobj,buf); return(1); } /* traps exist, but only under me - no separate display required */ Your("%s itch.", makeplural(body_part(TOE))); return(0); outtrapmap: cls(); u.uinwater = 0; for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) sense_trap(ttmp, 0, 0, sobj && sobj->cursed); for (obj = fobj; obj; obj = obj->nobj) if ((obj->otyp==LARGE_BOX || obj->otyp==CHEST) && obj->otrapped) sense_trap((struct trap *)0, obj->ox, obj->oy, sobj && sobj->cursed); for (door = 0; door < doorindex; door++) { cc = doors[door]; if (levl[cc.x][cc.y].doormask & D_TRAPPED) sense_trap((struct trap *)0, cc.x, cc.y, sobj && sobj->cursed); } newsym(u.ux,u.uy); You_feel("%s.", sobj && sobj->cursed ? "very greedy" : "entrapped"); display_nhwindow(WIN_MAP, TRUE); docrt(); u.uinwater = uw; if (Underwater) under_water(2); if (u.uburied) under_ground(2); return(0); } const char * level_distance(where) d_level *where; { register schar ll = depth(&u.uz) - depth(where); register boolean indun = (u.uz.dnum == where->dnum); if (ll < 0) { if (ll < (-8 - rn2(3))) if (!indun) return "far away"; else return "far below"; else if (ll < -1) if (!indun) return "away below you"; else return "below you"; else if (!indun) return "in the distance"; else return "just below"; } else if (ll > 0) { if (ll > (8 + rn2(3))) if (!indun) return "far away"; else return "far above"; else if (ll > 1) if (!indun) return "away above you"; else return "above you"; else if (!indun) return "in the distance"; else return "just above"; } else if (!indun) return "in the distance"; else return "near you"; } static const struct { const char *what; d_level *where; } level_detects[] = { { "Delphi", &oracle_level }, { "Medusa's lair", &medusa_level }, { "a castle", &stronghold_level }, { "the Wizard of Yendor's tower", &wiz1_level }, }; void use_crystal_ball(obj) struct obj *obj; { char ch; int oops; if (Blind) { pline("Too bad you can't see %s.", the(xname(obj))); return; } oops = (rnd(20) > ACURR(A_INT) || obj->cursed); if (oops && (obj->spe > 0)) { switch (rnd(obj->oartifact ? 4 : 5)) { case 1 : pline("%s too much to comprehend!", Tobjnam(obj, "are")); break; case 2 : pline("%s you!", Tobjnam(obj, "confuse")); make_confused(HConfusion + rnd(100),FALSE); break; case 3 : if (!resists_blnd(&youmonst)) { pline("%s your vision!", Tobjnam(obj, "damage")); make_blinded(Blinded + rnd(100),FALSE); if (!Blind) Your(vision_clears); } else { pline("%s your vision.", Tobjnam(obj, "assault")); You("are unaffected!"); } break; case 4 : pline("%s your mind!", Tobjnam(obj, "zap")); (void) make_hallucinated(HHallucination + rnd(100),FALSE,0L); break; case 5 : pline("%s!", Tobjnam(obj, "explode")); useup(obj); obj = 0; /* it's gone */ losehp(rnd(30), "exploding crystal ball", KILLED_BY_AN); break; } if (obj) consume_obj_charge(obj, TRUE); return; } if (Hallucination) { if (!obj->spe) { pline("All you see is funky %s haze.", hcolor((char *)0)); } else { switch(rnd(6)) { case 1 : You("grok some groovy globs of incandescent lava."); break; case 2 : pline("Whoa! Psychedelic colors, %s!", poly_gender() == 1 ? "babe" : "dude"); break; case 3 : pline_The("crystal pulses with sinister %s light!", hcolor((char *)0)); break; case 4 : You("see goldfish swimming above fluorescent rocks."); break; case 5 : You("see tiny snowflakes spinning around a miniature farmhouse."); break; default: pline("Oh wow... like a kaleidoscope!"); break; } consume_obj_charge(obj, TRUE); } return; } /* read a single character */ if (flags.verbose) You("may look for an object or monster symbol."); ch = yn_function("What do you look for?", (char *)0, '\0'); /* Don't filter out ' ' here; it has a use */ if ((ch != def_monsyms[S_GHOST]) && index(quitchars,ch)) { if (flags.verbose) pline(Never_mind); return; } You("peer into %s...", the(xname(obj))); nomul(-rnd(10)); nomovemsg = ""; if (obj->spe <= 0) pline_The("vision is unclear."); else { int class; int ret = 0; makeknown(CRYSTAL_BALL); consume_obj_charge(obj, TRUE); /* special case: accept ']' as synonym for mimic * we have to do this before the def_char_to_objclass check */ if (ch == DEF_MIMIC_DEF) ch = DEF_MIMIC; if ((class = def_char_to_objclass(ch)) != MAXOCLASSES) ret = object_detect((struct obj *)0, class); else if ((class = def_char_to_monclass(ch)) != MAXMCLASSES) ret = monster_detect((struct obj *)0, class); else if (iflags.bouldersym && (ch == iflags.bouldersym)) ret = object_detect((struct obj *)0, ROCK_CLASS); else switch(ch) { case '^': ret = trap_detect((struct obj *)0); break; default: { int i = rn2(SIZE(level_detects)); You("see %s, %s.", level_detects[i].what, level_distance(level_detects[i].where)); } ret = 0; break; } if (ret) { if (!rn2(100)) /* make them nervous */ You("see the Wizard of Yendor gazing out at you."); else pline_The("vision is unclear."); } } return; } STATIC_OVL void show_map_spot(x, y) register int x, y; { register struct rm *lev; if (Confusion && rn2(7)) return; lev = &levl[x][y]; lev->seenv = SVALL; /* Secret corridors are found, but not secret doors. */ if (lev->typ == SCORR) { lev->typ = CORR; unblock_point(x,y); } /* if we don't remember an object or trap there, map it */ if (lev->typ == ROOM ? (glyph_is_cmap(lev->glyph) && !glyph_is_trap(lev->glyph) && glyph_to_cmap(lev->glyph) != ROOM) : (!glyph_is_object(lev->glyph) && !glyph_is_trap(lev->glyph))) { if (level.flags.hero_memory) { magic_map_background(x,y,0); newsym(x,y); /* show it, if not blocked */ } else { magic_map_background(x,y,1); /* display it */ } } } void do_mapping() { register int zx, zy; int uw = u.uinwater; u.uinwater = 0; for (zx = 1; zx < COLNO; zx++) for (zy = 0; zy < ROWNO; zy++) show_map_spot(zx, zy); exercise(A_WIS, TRUE); u.uinwater = uw; if (!level.flags.hero_memory || Underwater) { flush_screen(1); /* flush temp screen */ display_nhwindow(WIN_MAP, TRUE); /* wait */ docrt(); } } void do_vicinity_map() { register int zx, zy; int lo_y = (u.uy-5 < 0 ? 0 : u.uy-5), hi_y = (u.uy+6 > ROWNO ? ROWNO : u.uy+6), lo_x = (u.ux-9 < 1 ? 1 : u.ux-9), /* avoid column 0 */ hi_x = (u.ux+10 > COLNO ? COLNO : u.ux+10); for (zx = lo_x; zx < hi_x; zx++) for (zy = lo_y; zy < hi_y; zy++) show_map_spot(zx, zy); if (!level.flags.hero_memory || Underwater) { flush_screen(1); /* flush temp screen */ display_nhwindow(WIN_MAP, TRUE); /* wait */ docrt(); } } /* convert a secret door into a normal door */ void cvt_sdoor_to_door(lev) struct rm *lev; { int newmask = lev->doormask & ~WM_MASK; #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) /* rogue didn't have doors, only doorways */ newmask = D_NODOOR; else #endif /* newly exposed door is closed */ if (!(newmask & D_LOCKED)) newmask |= D_CLOSED; lev->typ = DOOR; lev->doormask = newmask; } STATIC_PTR void findone(zx,zy,num) int zx,zy; genericptr_t num; { register struct trap *ttmp; register struct monst *mtmp; if(levl[zx][zy].typ == SDOOR) { cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */ magic_map_background(zx, zy, 0); newsym(zx, zy); (*(int*)num)++; } else if(levl[zx][zy].typ == SCORR) { levl[zx][zy].typ = CORR; unblock_point(zx,zy); magic_map_background(zx, zy, 0); newsym(zx, zy); (*(int*)num)++; } else if ((ttmp = t_at(zx, zy)) != 0) { if(!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) { ttmp->tseen = 1; newsym(zx,zy); (*(int*)num)++; } } else if ((mtmp = m_at(zx, zy)) != 0) { if(mtmp->m_ap_type) { seemimic(mtmp); (*(int*)num)++; } if (mtmp->mundetected && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) { mtmp->mundetected = 0; newsym(zx, zy); (*(int*)num)++; } if (!canspotmon(mtmp) && !glyph_is_invisible(levl[zx][zy].glyph)) map_invisible(zx, zy); } else if (glyph_is_invisible(levl[zx][zy].glyph)) { unmap_object(zx, zy); newsym(zx, zy); (*(int*)num)++; } } STATIC_PTR void openone(zx,zy,num) int zx,zy; genericptr_t num; { register struct trap *ttmp; register struct obj *otmp; if(OBJ_AT(zx, zy)) { for(otmp = level.objects[zx][zy]; otmp; otmp = otmp->nexthere) { if(Is_box(otmp) && otmp->olocked) { otmp->olocked = 0; (*(int*)num)++; } } /* let it fall to the next cases. could be on trap. */ } if(levl[zx][zy].typ == SDOOR || (levl[zx][zy].typ == DOOR && (levl[zx][zy].doormask & (D_CLOSED|D_LOCKED)))) { if(levl[zx][zy].typ == SDOOR) cvt_sdoor_to_door(&levl[zx][zy]); /* .typ = DOOR */ if(levl[zx][zy].doormask & D_TRAPPED) { if(distu(zx, zy) < 3) b_trapped("door", 0); else Norep("You %s an explosion!", cansee(zx, zy) ? "see" : (flags.soundok ? "hear" : "feel the shock of")); wake_nearto(zx, zy, 11*11); levl[zx][zy].doormask = D_NODOOR; } else levl[zx][zy].doormask = D_ISOPEN; unblock_point(zx, zy); newsym(zx, zy); (*(int*)num)++; } else if(levl[zx][zy].typ == SCORR) { levl[zx][zy].typ = CORR; unblock_point(zx, zy); newsym(zx, zy); (*(int*)num)++; } else if ((ttmp = t_at(zx, zy)) != 0) { if (!ttmp->tseen && ttmp->ttyp != STATUE_TRAP) { ttmp->tseen = 1; newsym(zx,zy); (*(int*)num)++; } } else if (find_drawbridge(&zx, &zy)) { /* make sure it isn't an open drawbridge */ open_drawbridge(zx, zy); (*(int*)num)++; } } int findit() /* returns number of things found */ { int num = 0; if(u.uswallow) return(0); do_clear_area(u.ux, u.uy, BOLT_LIM, findone, (genericptr_t) &num); return(num); } int openit() /* returns number of things found and opened */ { int num = 0; if(u.uswallow) { if (is_animal(u.ustuck->data)) { if (Blind) pline("Its mouth opens!"); else pline("%s opens its mouth!", Monnam(u.ustuck)); } expels(u.ustuck, u.ustuck->data, TRUE); return(-1); } do_clear_area(u.ux, u.uy, BOLT_LIM, openone, (genericptr_t) &num); return(num); } void find_trap(trap) struct trap *trap; { int tt = what_trap(trap->ttyp); boolean cleared = FALSE; trap->tseen = 1; exercise(A_WIS, TRUE); if (Blind) feel_location(trap->tx, trap->ty); else newsym(trap->tx, trap->ty); if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) { /* There's too much clutter to see your find otherwise */ cls(); map_trap(trap, 1); display_self(); cleared = TRUE; } You("find %s.", an(defsyms[trap_to_defsym(tt)].explanation)); if (cleared) { display_nhwindow(WIN_MAP, TRUE); /* wait */ docrt(); } } int dosearch0(aflag) register int aflag; { #ifdef GCC_BUG /* some versions of gcc seriously muck up nested loops. if you get strange crashes while searching in a version compiled with gcc, try putting #define GCC_BUG in *conf.h (or adding -DGCC_BUG to CFLAGS in the makefile). */ volatile xchar x, y; #else register xchar x, y; #endif register struct trap *trap; register struct monst *mtmp; if(u.uswallow) { if (!aflag) pline("What are you looking for? The exit?"); } else { int fund = (uwep && uwep->oartifact && spec_ability(uwep, SPFX_SEARCH)) ? uwep->spe : 0; if (ublindf && ublindf->otyp == LENSES && !Blind) fund += 2; /* JDS: lenses help searching */ if (fund > 5) fund = 5; for(x = u.ux-1; x < u.ux+2; x++) for(y = u.uy-1; y < u.uy+2; y++) { if(!isok(x,y)) continue; if(x != u.ux || y != u.uy) { if (Blind && !aflag) feel_location(x,y); if(levl[x][y].typ == SDOOR) { if(rnl(7-fund)) continue; cvt_sdoor_to_door(&levl[x][y]); /* .typ = DOOR */ exercise(A_WIS, TRUE); nomul(0); if (Blind && !aflag) feel_location(x,y); /* make sure it shows up */ else newsym(x,y); } else if(levl[x][y].typ == SCORR) { if(rnl(7-fund)) continue; levl[x][y].typ = CORR; unblock_point(x,y); /* vision */ exercise(A_WIS, TRUE); nomul(0); newsym(x,y); } else { /* Be careful not to find anything in an SCORR or SDOOR */ if((mtmp = m_at(x, y)) && !aflag) { if(mtmp->m_ap_type) { seemimic(mtmp); find: exercise(A_WIS, TRUE); if (!canspotmon(mtmp)) { if (glyph_is_invisible(levl[x][y].glyph)) { /* found invisible monster in a square * which already has an 'I' in it. * Logically, this should still take * time and lead to a return(1), but if * we did that the player would keep * finding the same monster every turn. */ continue; } else { You_feel("an unseen monster!"); map_invisible(x, y); } } else if (!sensemon(mtmp)) You("find %s.", a_monnam(mtmp)); return(1); } if(!canspotmon(mtmp)) { if (mtmp->mundetected && (is_hider(mtmp->data) || mtmp->data->mlet == S_EEL)) mtmp->mundetected = 0; newsym(x,y); goto find; } } /* see if an invisible monster has moved--if Blind, * feel_location() already did it */ if (!aflag && !mtmp && !Blind && glyph_is_invisible(levl[x][y].glyph)) { unmap_object(x,y); newsym(x,y); } if ((trap = t_at(x,y)) && !trap->tseen && !rnl(8)) { nomul(0); if (trap->ttyp == STATUE_TRAP) { if (activate_statue_trap(trap, x, y, FALSE)) exercise(A_WIS, TRUE); return(1); } else { find_trap(trap); } } } } } } return(1); } int dosearch() { return(dosearch0(0)); } /* Pre-map the sokoban levels */ void sokoban_detect() { register int x, y; register struct trap *ttmp; register struct obj *obj; /* Map the background and boulders */ for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) { levl[x][y].seenv = SVALL; levl[x][y].waslit = TRUE; map_background(x, y, 1); for (obj = level.objects[x][y]; obj; obj = obj->nexthere) if (obj->otyp == BOULDER) map_object(obj, 1); } /* Map the traps */ for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { ttmp->tseen = 1; map_trap(ttmp, 1); } } /*detect.c*/ nethack-3.4.3/src/dig.c0100644000000000000000000012552307764735041013360 0ustar rootroot/* SCCS Id: @(#)dig.c 3.4 2003/03/23 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "edog.h" /* #define DEBUG */ /* turn on for diagnostics */ #ifdef OVLB static NEARDATA boolean did_dig_msg; STATIC_DCL boolean NDECL(rm_waslit); STATIC_DCL void FDECL(mkcavepos, (XCHAR_P,XCHAR_P,int,BOOLEAN_P,BOOLEAN_P)); STATIC_DCL void FDECL(mkcavearea, (BOOLEAN_P)); STATIC_DCL int FDECL(dig_typ, (struct obj *,XCHAR_P,XCHAR_P)); STATIC_DCL int NDECL(dig); STATIC_DCL schar FDECL(fillholetyp, (int, int)); STATIC_DCL void NDECL(dig_up_grave); /* Indices returned by dig_typ() */ #define DIGTYP_UNDIGGABLE 0 #define DIGTYP_ROCK 1 #define DIGTYP_STATUE 2 #define DIGTYP_BOULDER 3 #define DIGTYP_DOOR 4 #define DIGTYP_TREE 5 STATIC_OVL boolean rm_waslit() { register xchar x, y; if(levl[u.ux][u.uy].typ == ROOM && levl[u.ux][u.uy].waslit) return(TRUE); for(x = u.ux-2; x < u.ux+3; x++) for(y = u.uy-1; y < u.uy+2; y++) if(isok(x,y) && levl[x][y].waslit) return(TRUE); return(FALSE); } /* Change level topology. Messes with vision tables and ignores things like * boulders in the name of a nice effect. Vision will get fixed up again * immediately after the effect is complete. */ STATIC_OVL void mkcavepos(x, y, dist, waslit, rockit) xchar x,y; int dist; boolean waslit, rockit; { register struct rm *lev; if(!isok(x,y)) return; lev = &levl[x][y]; if(rockit) { register struct monst *mtmp; if(IS_ROCK(lev->typ)) return; if(t_at(x, y)) return; /* don't cover the portal */ if ((mtmp = m_at(x, y)) != 0) /* make sure crucial monsters survive */ if(!passes_walls(mtmp->data)) (void) rloc(mtmp, FALSE); } else if(lev->typ == ROOM) return; unblock_point(x,y); /* make sure vision knows this location is open */ /* fake out saved state */ lev->seenv = 0; lev->doormask = 0; if(dist < 3) lev->lit = (rockit ? FALSE : TRUE); if(waslit) lev->waslit = (rockit ? FALSE : TRUE); lev->horizontal = FALSE; viz_array[y][x] = (dist < 3 ) ? (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */ COULD_SEE; lev->typ = (rockit ? STONE : ROOM); if(dist >= 3) impossible("mkcavepos called with dist %d", dist); if(Blind) feel_location(x, y); else newsym(x,y); } STATIC_OVL void mkcavearea(rockit) register boolean rockit; { int dist; xchar xmin = u.ux, xmax = u.ux; xchar ymin = u.uy, ymax = u.uy; register xchar i; register boolean waslit = rm_waslit(); if(rockit) pline("Crash! The ceiling collapses around you!"); else pline("A mysterious force %s cave around you!", (levl[u.ux][u.uy].typ == CORR) ? "creates a" : "extends the"); display_nhwindow(WIN_MESSAGE, TRUE); for(dist = 1; dist <= 2; dist++) { xmin--; xmax++; /* top and bottom */ if(dist < 2) { /* the area is wider that it is high */ ymin--; ymax++; for(i = xmin+1; i < xmax; i++) { mkcavepos(i, ymin, dist, waslit, rockit); mkcavepos(i, ymax, dist, waslit, rockit); } } /* left and right */ for(i = ymin; i <= ymax; i++) { mkcavepos(xmin, i, dist, waslit, rockit); mkcavepos(xmax, i, dist, waslit, rockit); } flush_screen(1); /* make sure the new glyphs shows up */ delay_output(); } if(!rockit && levl[u.ux][u.uy].typ == CORR) { levl[u.ux][u.uy].typ = ROOM; if(waslit) levl[u.ux][u.uy].waslit = TRUE; newsym(u.ux, u.uy); /* in case player is invisible */ } vision_full_recalc = 1; /* everything changed */ } /* When digging into location , what are you actually digging into? */ STATIC_OVL int dig_typ(otmp, x, y) struct obj *otmp; xchar x, y; { boolean ispick = is_pick(otmp); return (ispick && sobj_at(STATUE, x, y) ? DIGTYP_STATUE : ispick && sobj_at(BOULDER, x, y) ? DIGTYP_BOULDER : closed_door(x, y) ? DIGTYP_DOOR : IS_TREE(levl[x][y].typ) ? (ispick ? DIGTYP_UNDIGGABLE : DIGTYP_TREE) : ispick && IS_ROCK(levl[x][y].typ) && (!level.flags.arboreal || IS_WALL(levl[x][y].typ)) ? DIGTYP_ROCK : DIGTYP_UNDIGGABLE); } boolean is_digging() { if (occupation == dig) { return TRUE; } return FALSE; } #define BY_YOU (&youmonst) #define BY_OBJECT ((struct monst *)0) boolean dig_check(madeby, verbose, x, y) struct monst *madeby; boolean verbose; int x, y; { struct trap *ttmp = t_at(x, y); const char *verb = (madeby == BY_YOU && uwep && is_axe(uwep)) ? "chop" : "dig in"; if (On_stairs(x, y)) { if (x == xdnladder || x == xupladder) { if(verbose) pline_The("ladder resists your effort."); } else if(verbose) pline_The("stairs are too hard to %s.", verb); return(FALSE); } else if (IS_THRONE(levl[x][y].typ) && madeby != BY_OBJECT) { if(verbose) pline_The("throne is too hard to break apart."); return(FALSE); } else if (IS_ALTAR(levl[x][y].typ) && (madeby != BY_OBJECT || Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) { if(verbose) pline_The("altar is too hard to break apart."); return(FALSE); } else if (Is_airlevel(&u.uz)) { if(verbose) You("cannot %s thin air.", verb); return(FALSE); } else if (Is_waterlevel(&u.uz)) { if(verbose) pline_The("water splashes and subsides."); return(FALSE); } else if ((IS_ROCK(levl[x][y].typ) && levl[x][y].typ != SDOOR && (levl[x][y].wall_info & W_NONDIGGABLE) != 0) || (ttmp && (ttmp->ttyp == MAGIC_PORTAL || !Can_dig_down(&u.uz)))) { if(verbose) pline_The("%s here is too hard to %s.", surface(x,y), verb); return(FALSE); } else if (sobj_at(BOULDER, x, y)) { if(verbose) There("isn't enough room to %s here.", verb); return(FALSE); } else if (madeby == BY_OBJECT && /* the block against existing traps is mainly to prevent broken wands from turning holes into pits */ (ttmp || is_pool(x,y) || is_lava(x,y))) { /* digging by player handles pools separately */ return FALSE; } return(TRUE); } STATIC_OVL int dig() { register struct rm *lev; register xchar dpx = digging.pos.x, dpy = digging.pos.y; register boolean ispick = uwep && is_pick(uwep); const char *verb = (!uwep || is_pick(uwep)) ? "dig into" : "chop through"; lev = &levl[dpx][dpy]; /* perhaps a nymph stole your pick-axe while you were busy digging */ /* or perhaps you teleported away */ if (u.uswallow || !uwep || (!ispick && !is_axe(uwep)) || !on_level(&digging.level, &u.uz) || ((digging.down ? (dpx != u.ux || dpy != u.uy) : (distu(dpx,dpy) > 2)))) return(0); if (digging.down) { if(!dig_check(BY_YOU, TRUE, u.ux, u.uy)) return(0); } else { /* !digging.down */ if (IS_TREE(lev->typ) && !may_dig(dpx,dpy) && dig_typ(uwep, dpx, dpy) == DIGTYP_TREE) { pline("This tree seems to be petrified."); return(0); } if (IS_ROCK(lev->typ) && !may_dig(dpx,dpy) && dig_typ(uwep, dpx, dpy) == DIGTYP_ROCK) { pline("This wall is too hard to %s.", verb); return(0); } } if(Fumbling && !rn2(3)) { switch(rn2(3)) { case 0: if(!welded(uwep)) { You("fumble and drop your %s.", xname(uwep)); dropx(uwep); } else { #ifdef STEED if (u.usteed) Your("%s %s and %s %s!", xname(uwep), otense(uwep, "bounce"), otense(uwep, "hit"), mon_nam(u.usteed)); else #endif pline("Ouch! Your %s %s and %s you!", xname(uwep), otense(uwep, "bounce"), otense(uwep, "hit")); set_wounded_legs(RIGHT_SIDE, 5 + rnd(5)); } break; case 1: pline("Bang! You hit with the broad side of %s!", the(xname(uwep))); break; default: Your("swing misses its mark."); break; } return(0); } digging.effort += 10 + rn2(5) + abon() + uwep->spe - greatest_erosion(uwep) + u.udaminc; if (Race_if(PM_DWARF)) digging.effort *= 2; if (digging.down) { register struct trap *ttmp; if (digging.effort > 250) { (void) dighole(FALSE); (void) memset((genericptr_t)&digging, 0, sizeof digging); return(0); /* done with digging */ } if (digging.effort <= 50 || ((ttmp = t_at(dpx,dpy)) != 0 && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT || ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE))) return(1); if (IS_ALTAR(lev->typ)) { altar_wrath(dpx, dpy); angry_priest(); } if (dighole(TRUE)) { /* make pit at */ digging.level.dnum = 0; digging.level.dlevel = -1; } return(0); } if (digging.effort > 100) { register const char *digtxt, *dmgtxt = (const char*) 0; register struct obj *obj; register boolean shopedge = *in_rooms(dpx, dpy, SHOPBASE); if ((obj = sobj_at(STATUE, dpx, dpy)) != 0) { if (break_statue(obj)) digtxt = "The statue shatters."; else /* it was a statue trap; break_statue() * printed a message and updated the screen */ digtxt = (char *)0; } else if ((obj = sobj_at(BOULDER, dpx, dpy)) != 0) { struct obj *bobj; fracture_rock(obj); if ((bobj = sobj_at(BOULDER, dpx, dpy)) != 0) { /* another boulder here, restack it to the top */ obj_extract_self(bobj); place_object(bobj, dpx, dpy); } digtxt = "The boulder falls apart."; } else if (lev->typ == STONE || lev->typ == SCORR || IS_TREE(lev->typ)) { if(Is_earthlevel(&u.uz)) { if(uwep->blessed && !rn2(3)) { mkcavearea(FALSE); goto cleanup; } else if((uwep->cursed && !rn2(4)) || (!uwep->blessed && !rn2(6))) { mkcavearea(TRUE); goto cleanup; } } if (IS_TREE(lev->typ)) { digtxt = "You cut down the tree."; lev->typ = ROOM; if (!rn2(5)) (void) rnd_treefruit_at(dpx, dpy); } else { digtxt = "You succeed in cutting away some rock."; lev->typ = CORR; } } else if(IS_WALL(lev->typ)) { if(shopedge) { add_damage(dpx, dpy, 10L * ACURRSTR); dmgtxt = "damage"; } if (level.flags.is_maze_lev) { lev->typ = ROOM; } else if (level.flags.is_cavernous_lev && !in_town(dpx, dpy)) { lev->typ = CORR; } else { lev->typ = DOOR; lev->doormask = D_NODOOR; } digtxt = "You make an opening in the wall."; } else if(lev->typ == SDOOR) { cvt_sdoor_to_door(lev); /* ->typ = DOOR */ digtxt = "You break through a secret door!"; if(!(lev->doormask & D_TRAPPED)) lev->doormask = D_BROKEN; } else if(closed_door(dpx, dpy)) { digtxt = "You break through the door."; if(shopedge) { add_damage(dpx, dpy, 400L); dmgtxt = "break"; } if(!(lev->doormask & D_TRAPPED)) lev->doormask = D_BROKEN; } else return(0); /* statue or boulder got taken */ if(!does_block(dpx,dpy,&levl[dpx][dpy])) unblock_point(dpx,dpy); /* vision: can see through */ if(Blind) feel_location(dpx, dpy); else newsym(dpx, dpy); if(digtxt && !digging.quiet) pline(digtxt); /* after newsym */ if(dmgtxt) pay_for_damage(dmgtxt, FALSE); if(Is_earthlevel(&u.uz) && !rn2(3)) { register struct monst *mtmp; switch(rn2(2)) { case 0: mtmp = makemon(&mons[PM_EARTH_ELEMENTAL], dpx, dpy, NO_MM_FLAGS); break; default: mtmp = makemon(&mons[PM_XORN], dpx, dpy, NO_MM_FLAGS); break; } if(mtmp) pline_The("debris from your digging comes to life!"); } if(IS_DOOR(lev->typ) && (lev->doormask & D_TRAPPED)) { lev->doormask = D_NODOOR; b_trapped("door", 0); newsym(dpx, dpy); } cleanup: digging.lastdigtime = moves; digging.quiet = FALSE; digging.level.dnum = 0; digging.level.dlevel = -1; return(0); } else { /* not enough effort has been spent yet */ static const char *const d_target[6] = { "", "rock", "statue", "boulder", "door", "tree" }; int dig_target = dig_typ(uwep, dpx, dpy); if (IS_WALL(lev->typ) || dig_target == DIGTYP_DOOR) { if(*in_rooms(dpx, dpy, SHOPBASE)) { pline("This %s seems too hard to %s.", IS_DOOR(lev->typ) ? "door" : "wall", verb); return(0); } } else if (!IS_ROCK(lev->typ) && dig_target == DIGTYP_ROCK) return(0); /* statue or boulder got taken */ if(!did_dig_msg) { You("hit the %s with all your might.", d_target[dig_target]); did_dig_msg = TRUE; } } return(1); } /* When will hole be finished? Very rough indication used by shopkeeper. */ int holetime() { if(occupation != dig || !*u.ushops) return(-1); return ((250 - digging.effort) / 20); } /* Return typ of liquid to fill a hole with, or ROOM, if no liquid nearby */ STATIC_OVL schar fillholetyp(x,y) int x, y; { register int x1, y1; int lo_x = max(1,x-1), hi_x = min(x+1,COLNO-1), lo_y = max(0,y-1), hi_y = min(y+1,ROWNO-1); int pool_cnt = 0, moat_cnt = 0, lava_cnt = 0; for (x1 = lo_x; x1 <= hi_x; x1++) for (y1 = lo_y; y1 <= hi_y; y1++) if (levl[x1][y1].typ == POOL) pool_cnt++; else if (levl[x1][y1].typ == MOAT || (levl[x1][y1].typ == DRAWBRIDGE_UP && (levl[x1][y1].drawbridgemask & DB_UNDER) == DB_MOAT)) moat_cnt++; else if (levl[x1][y1].typ == LAVAPOOL || (levl[x1][y1].typ == DRAWBRIDGE_UP && (levl[x1][y1].drawbridgemask & DB_UNDER) == DB_LAVA)) lava_cnt++; pool_cnt /= 3; /* not as much liquid as the others */ if (lava_cnt > moat_cnt + pool_cnt && rn2(lava_cnt + 1)) return LAVAPOOL; else if (moat_cnt > 0 && rn2(moat_cnt + 1)) return MOAT; else if (pool_cnt > 0 && rn2(pool_cnt + 1)) return POOL; else return ROOM; } void digactualhole(x, y, madeby, ttyp) register int x, y; struct monst *madeby; int ttyp; { struct obj *oldobjs, *newobjs; register struct trap *ttmp; char surface_type[BUFSZ]; struct rm *lev = &levl[x][y]; boolean shopdoor; struct monst *mtmp = m_at(x, y); /* may be madeby */ boolean madeby_u = (madeby == BY_YOU); boolean madeby_obj = (madeby == BY_OBJECT); boolean at_u = (x == u.ux) && (y == u.uy); boolean wont_fall = Levitation || Flying; if (u.utrap && u.utraptype == TT_INFLOOR) u.utrap = 0; /* these furniture checks were in dighole(), but wand breaking bypasses that routine and calls us directly */ if (IS_FOUNTAIN(lev->typ)) { dogushforth(FALSE); SET_FOUNTAIN_WARNED(x,y); /* force dryup */ dryup(x, y, madeby_u); return; #ifdef SINKS } else if (IS_SINK(lev->typ)) { breaksink(x, y); return; #endif } else if (lev->typ == DRAWBRIDGE_DOWN || (is_drawbridge_wall(x, y) >= 0)) { int bx = x, by = y; /* if under the portcullis, the bridge is adjacent */ (void) find_drawbridge(&bx, &by); destroy_drawbridge(bx, by); return; } if (ttyp != PIT && !Can_dig_down(&u.uz)) { impossible("digactualhole: can't dig %s on this level.", defsyms[trap_to_defsym(ttyp)].explanation); ttyp = PIT; } /* maketrap() might change it, also, in this situation, surface() returns an inappropriate string for a grave */ if (IS_GRAVE(lev->typ)) Strcpy(surface_type, "grave"); else Strcpy(surface_type, surface(x,y)); shopdoor = IS_DOOR(lev->typ) && *in_rooms(x, y, SHOPBASE); oldobjs = level.objects[x][y]; ttmp = maketrap(x, y, ttyp); if (!ttmp) return; newobjs = level.objects[x][y]; ttmp->tseen = (madeby_u || cansee(x,y)); ttmp->madeby_u = madeby_u; newsym(ttmp->tx,ttmp->ty); if (ttyp == PIT) { if(madeby_u) { You("dig a pit in the %s.", surface_type); if (shopdoor) pay_for_damage("ruin", FALSE); } else if (!madeby_obj && canseemon(madeby)) pline("%s digs a pit in the %s.", Monnam(madeby), surface_type); else if (cansee(x, y) && flags.verbose) pline("A pit appears in the %s.", surface_type); if(at_u) { if (!wont_fall) { if (!Passes_walls) u.utrap = rn1(4,2); u.utraptype = TT_PIT; vision_full_recalc = 1; /* vision limits change */ } else u.utrap = 0; if (oldobjs != newobjs) /* something unearthed */ (void) pickup(1); /* detects pit */ } else if(mtmp) { if(is_flyer(mtmp->data) || is_floater(mtmp->data)) { if(canseemon(mtmp)) pline("%s %s over the pit.", Monnam(mtmp), (is_flyer(mtmp->data)) ? "flies" : "floats"); } else if(mtmp != madeby) (void) mintrap(mtmp); } } else { /* was TRAPDOOR now a HOLE*/ if(madeby_u) You("dig a hole through the %s.", surface_type); else if(!madeby_obj && canseemon(madeby)) pline("%s digs a hole through the %s.", Monnam(madeby), surface_type); else if(cansee(x, y) && flags.verbose) pline("A hole appears in the %s.", surface_type); if (at_u) { if (!u.ustuck && !wont_fall && !next_to_u()) { You("are jerked back by your pet!"); wont_fall = TRUE; } /* Floor objects get a chance of falling down. The case where * the hero does NOT fall down is treated here. The case * where the hero does fall down is treated in goto_level(). */ if (u.ustuck || wont_fall) { if (newobjs) impact_drop((struct obj *)0, x, y, 0); if (oldobjs != newobjs) (void) pickup(1); if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE); } else { d_level newlevel; if (*u.ushops && madeby_u) shopdig(1); /* shk might snatch pack */ /* handle earlier damage, eg breaking wand of digging */ else if (!madeby_u) pay_for_damage("dig into", TRUE); You("fall through..."); /* Earlier checks must ensure that the destination * level exists and is in the present dungeon. */ newlevel.dnum = u.uz.dnum; newlevel.dlevel = u.uz.dlevel + 1; goto_level(&newlevel, FALSE, TRUE, FALSE); /* messages for arriving in special rooms */ spoteffects(FALSE); } } else { if (shopdoor && madeby_u) pay_for_damage("ruin", FALSE); if (newobjs) impact_drop((struct obj *)0, x, y, 0); if (mtmp) { /*[don't we need special sokoban handling here?]*/ if (is_flyer(mtmp->data) || is_floater(mtmp->data) || mtmp->data == &mons[PM_WUMPUS] || (mtmp->wormno && count_wsegs(mtmp) > 5) || mtmp->data->msize >= MZ_HUGE) return; if (mtmp == u.ustuck) /* probably a vortex */ return; /* temporary? kludge */ if (teleport_pet(mtmp, FALSE)) { d_level tolevel; if (Is_stronghold(&u.uz)) { assign_level(&tolevel, &valley_level); } else if (Is_botlevel(&u.uz)) { if (canseemon(mtmp)) pline("%s avoids the trap.", Monnam(mtmp)); return; } else { get_level(&tolevel, depth(&u.uz) + 1); } if (mtmp->isshk) make_angry_shk(mtmp, 0, 0); migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *)0); } } } } } /* return TRUE if digging succeeded, FALSE otherwise */ boolean dighole(pit_only) boolean pit_only; { register struct trap *ttmp = t_at(u.ux, u.uy); struct rm *lev = &levl[u.ux][u.uy]; struct obj *boulder_here; schar typ; boolean nohole = !Can_dig_down(&u.uz); if ((ttmp && (ttmp->ttyp == MAGIC_PORTAL || nohole)) || (IS_ROCK(lev->typ) && lev->typ != SDOOR && (lev->wall_info & W_NONDIGGABLE) != 0)) { pline_The("%s here is too hard to dig in.", surface(u.ux,u.uy)); } else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) { pline_The("%s sloshes furiously for a moment, then subsides.", is_lava(u.ux, u.uy) ? "lava" : "water"); wake_nearby(); /* splashing */ } else if (lev->typ == DRAWBRIDGE_DOWN || (is_drawbridge_wall(u.ux, u.uy) >= 0)) { /* drawbridge_down is the platform crossing the moat when the bridge is extended; drawbridge_wall is the open "doorway" or closed "door" where the portcullis/mechanism is located */ if (pit_only) { pline_The("drawbridge seems too hard to dig through."); return FALSE; } else { int x = u.ux, y = u.uy; /* if under the portcullis, the bridge is adjacent */ (void) find_drawbridge(&x, &y); destroy_drawbridge(x, y); return TRUE; } } else if ((boulder_here = sobj_at(BOULDER, u.ux, u.uy)) != 0) { if (ttmp && (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) && rn2(2)) { pline_The("boulder settles into the pit."); ttmp->ttyp = PIT; /* crush spikes */ } else { /* * digging makes a hole, but the boulder immediately * fills it. Final outcome: no hole, no boulder. */ pline("KADOOM! The boulder falls in!"); (void) delfloortrap(ttmp); } delobj(boulder_here); return TRUE; } else if (IS_GRAVE(lev->typ)) { digactualhole(u.ux, u.uy, BY_YOU, PIT); dig_up_grave(); return TRUE; } else if (lev->typ == DRAWBRIDGE_UP) { /* must be floor or ice, other cases handled above */ /* dig "pit" and let fluid flow in (if possible) */ typ = fillholetyp(u.ux,u.uy); if (typ == ROOM) { /* * We can't dig a hole here since that will destroy * the drawbridge. The following is a cop-out. --dlc */ pline_The("%s here is too hard to dig in.", surface(u.ux, u.uy)); return FALSE; } lev->drawbridgemask &= ~DB_UNDER; lev->drawbridgemask |= (typ == LAVAPOOL) ? DB_LAVA : DB_MOAT; liquid_flow: if (ttmp) (void) delfloortrap(ttmp); /* if any objects were frozen here, they're released now */ unearth_objs(u.ux, u.uy); pline("As you dig, the hole fills with %s!", typ == LAVAPOOL ? "lava" : "water"); if (!Levitation && !Flying) { if (typ == LAVAPOOL) (void) lava_effects(); else if (!Wwalking) (void) drown(); } return TRUE; /* the following two are here for the wand of digging */ } else if (IS_THRONE(lev->typ)) { pline_The("throne is too hard to break apart."); } else if (IS_ALTAR(lev->typ)) { pline_The("altar is too hard to break apart."); } else { typ = fillholetyp(u.ux,u.uy); if (typ != ROOM) { lev->typ = typ; goto liquid_flow; } /* finally we get to make a hole */ if (nohole || pit_only) digactualhole(u.ux, u.uy, BY_YOU, PIT); else digactualhole(u.ux, u.uy, BY_YOU, HOLE); return TRUE; } return FALSE; } STATIC_OVL void dig_up_grave() { struct obj *otmp; /* Grave-robbing is frowned upon... */ exercise(A_WIS, FALSE); if (Role_if(PM_ARCHEOLOGIST)) { adjalign(-sgn(u.ualign.type)*3); You_feel("like a despicable grave-robber!"); } else if (Role_if(PM_SAMURAI)) { adjalign(-sgn(u.ualign.type)); You("disturb the honorable dead!"); } else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) { adjalign(-sgn(u.ualign.type)); You("have violated the sanctity of this grave!"); } switch (rn2(5)) { case 0: case 1: You("unearth a corpse."); if (!!(otmp = mk_tt_object(CORPSE, u.ux, u.uy))) otmp->age -= 100; /* this is an *OLD* corpse */; break; case 2: if (!Blind) pline(Hallucination ? "Dude! The living dead!" : "The grave's owner is very upset!"); (void) makemon(mkclass(S_ZOMBIE,0), u.ux, u.uy, NO_MM_FLAGS); break; case 3: if (!Blind) pline(Hallucination ? "I want my mummy!" : "You've disturbed a tomb!"); (void) makemon(mkclass(S_MUMMY,0), u.ux, u.uy, NO_MM_FLAGS); break; default: /* No corpse */ pline_The("grave seems unused. Strange...."); break; } levl[u.ux][u.uy].typ = ROOM; del_engr_at(u.ux, u.uy); newsym(u.ux,u.uy); return; } int use_pick_axe(obj) struct obj *obj; { boolean ispick; char dirsyms[12]; char qbuf[QBUFSZ]; register char *dsp = dirsyms; register int rx, ry; int res = 0; register const char *sdp, *verb; if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */ /* Check tool */ if (obj != uwep) { if (!wield_tool(obj, "swing")) return 0; else res = 1; } ispick = is_pick(obj); verb = ispick ? "dig" : "chop"; if (u.utrap && u.utraptype == TT_WEB) { pline("%s you can't %s while entangled in a web.", /* res==0 => no prior message; res==1 => just got "You now wield a pick-axe." message */ !res ? "Unfortunately," : "But", verb); return res; } while(*sdp) { (void) movecmd(*sdp); /* sets u.dx and u.dy and u.dz */ rx = u.ux + u.dx; ry = u.uy + u.dy; /* Include down even with axe, so we have at least one direction */ if (u.dz > 0 || (u.dz == 0 && isok(rx, ry) && dig_typ(obj, rx, ry) != DIGTYP_UNDIGGABLE)) *dsp++ = *sdp; sdp++; } *dsp = 0; Sprintf(qbuf, "In what direction do you want to %s? [%s]", verb, dirsyms); if(!getdir(qbuf)) return(res); return(use_pick_axe2(obj)); } /* MRKR: use_pick_axe() is split in two to allow autodig to bypass */ /* the "In what direction do you want to dig?" query. */ /* use_pick_axe2() uses the existing u.dx, u.dy and u.dz */ int use_pick_axe2(obj) struct obj *obj; { register int rx, ry; register struct rm *lev; int dig_target; boolean ispick = is_pick(obj); const char *verbing = ispick ? "digging" : "chopping"; if (u.uswallow && attack(u.ustuck)) { ; /* return(1) */ } else if (Underwater) { pline("Turbulence torpedoes your %s attempts.", verbing); } else if(u.dz < 0) { if(Levitation) You("don't have enough leverage."); else You_cant("reach the %s.",ceiling(u.ux,u.uy)); } else if(!u.dx && !u.dy && !u.dz) { char buf[BUFSZ]; int dam; dam = rnd(2) + dbon() + obj->spe; if (dam <= 0) dam = 1; You("hit yourself with %s.", yname(uwep)); Sprintf(buf, "%s own %s", uhis(), OBJ_NAME(objects[obj->otyp])); losehp(dam, buf, KILLED_BY); flags.botl=1; return(1); } else if(u.dz == 0) { if(Stunned || (Confusion && !rn2(5))) confdir(); rx = u.ux + u.dx; ry = u.uy + u.dy; if(!isok(rx, ry)) { pline("Clash!"); return(1); } lev = &levl[rx][ry]; if(MON_AT(rx, ry) && attack(m_at(rx, ry))) return(1); dig_target = dig_typ(obj, rx, ry); if (dig_target == DIGTYP_UNDIGGABLE) { /* ACCESSIBLE or POOL */ struct trap *trap = t_at(rx, ry); if (trap && trap->ttyp == WEB) { if (!trap->tseen) { seetrap(trap); There("is a spider web there!"); } Your("%s entangled in the web.", aobjnam(obj, "become")); /* you ought to be able to let go; tough luck */ /* (maybe `move_into_trap()' would be better) */ nomul(-d(2,2)); nomovemsg = "You pull free."; } else if (lev->typ == IRONBARS) { pline("Clang!"); wake_nearby(); } else if (IS_TREE(lev->typ)) You("need an axe to cut down a tree."); else if (IS_ROCK(lev->typ)) You("need a pick to dig rock."); else if (!ispick && (sobj_at(STATUE, rx, ry) || sobj_at(BOULDER, rx, ry))) { boolean vibrate = !rn2(3); pline("Sparks fly as you whack the %s.%s", sobj_at(STATUE, rx, ry) ? "statue" : "boulder", vibrate ? " The axe-handle vibrates violently!" : ""); if (vibrate) losehp(2, "axing a hard object", KILLED_BY); } else You("swing your %s through thin air.", aobjnam(obj, (char *)0)); } else { static const char * const d_action[6] = { "swinging", "digging", "chipping the statue", "hitting the boulder", "chopping at the door", "cutting the tree" }; did_dig_msg = FALSE; digging.quiet = FALSE; if (digging.pos.x != rx || digging.pos.y != ry || !on_level(&digging.level, &u.uz) || digging.down) { if (flags.autodig && dig_target == DIGTYP_ROCK && !digging.down && digging.pos.x == u.ux && digging.pos.y == u.uy && (moves <= digging.lastdigtime+2 && moves >= digging.lastdigtime)) { /* avoid messages if repeated autodigging */ did_dig_msg = TRUE; digging.quiet = TRUE; } digging.down = digging.chew = FALSE; digging.warned = FALSE; digging.pos.x = rx; digging.pos.y = ry; assign_level(&digging.level, &u.uz); digging.effort = 0; if (!digging.quiet) You("start %s.", d_action[dig_target]); } else { You("%s %s.", digging.chew ? "begin" : "continue", d_action[dig_target]); digging.chew = FALSE; } set_occupation(dig, verbing, 0); } } else if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) { /* it must be air -- water checked above */ You("swing your %s through thin air.", aobjnam(obj, (char *)0)); } else if (!can_reach_floor()) { You_cant("reach the %s.", surface(u.ux,u.uy)); } else if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) { /* Monsters which swim also happen not to be able to dig */ You("cannot stay under%s long enough.", is_pool(u.ux, u.uy) ? "water" : " the lava"); } else if (!ispick) { Your("%s merely scratches the %s.", aobjnam(obj, (char *)0), surface(u.ux,u.uy)); u_wipe_engr(3); } else { if (digging.pos.x != u.ux || digging.pos.y != u.uy || !on_level(&digging.level, &u.uz) || !digging.down) { digging.chew = FALSE; digging.down = TRUE; digging.warned = FALSE; digging.pos.x = u.ux; digging.pos.y = u.uy; assign_level(&digging.level, &u.uz); digging.effort = 0; You("start %s downward.", verbing); if (*u.ushops) shopdig(0); } else You("continue %s downward.", verbing); did_dig_msg = FALSE; set_occupation(dig, verbing, 0); } return(1); } /* * Town Watchmen frown on damage to the town walls, trees or fountains. * It's OK to dig holes in the ground, however. * If mtmp is assumed to be a watchman, a watchman is found if mtmp == 0 * zap == TRUE if wand/spell of digging, FALSE otherwise (chewing) */ void watch_dig(mtmp, x, y, zap) struct monst *mtmp; xchar x, y; boolean zap; { struct rm *lev = &levl[x][y]; if (in_town(x, y) && (closed_door(x, y) || lev->typ == SDOOR || IS_WALL(lev->typ) || IS_FOUNTAIN(lev->typ) || IS_TREE(lev->typ))) { if (!mtmp) { for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->data == &mons[PM_WATCHMAN] || mtmp->data == &mons[PM_WATCH_CAPTAIN]) && mtmp->mcansee && m_canseeu(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) break; } } if (mtmp) { if(zap || digging.warned) { verbalize("Halt, vandal! You're under arrest!"); (void) angry_guards(!(flags.soundok)); } else { const char *str; if (IS_DOOR(lev->typ)) str = "door"; else if (IS_TREE(lev->typ)) str = "tree"; else if (IS_ROCK(lev->typ)) str = "wall"; else str = "fountain"; verbalize("Hey, stop damaging that %s!", str); digging.warned = TRUE; } if (is_digging()) stop_occupation(); } } } #endif /* OVLB */ #ifdef OVL0 /* Return TRUE if monster died, FALSE otherwise. Called from m_move(). */ boolean mdig_tunnel(mtmp) register struct monst *mtmp; { register struct rm *here; int pile = rnd(12); here = &levl[mtmp->mx][mtmp->my]; if (here->typ == SDOOR) cvt_sdoor_to_door(here); /* ->typ = DOOR */ /* Eats away door if present & closed or locked */ if (closed_door(mtmp->mx, mtmp->my)) { if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); unblock_point(mtmp->mx, mtmp->my); /* vision */ if (here->doormask & D_TRAPPED) { here->doormask = D_NODOOR; if (mb_trapped(mtmp)) { /* mtmp is killed */ newsym(mtmp->mx, mtmp->my); return TRUE; } } else { if (!rn2(3) && flags.verbose) /* not too often.. */ You_feel("an unexpected draft."); here->doormask = D_BROKEN; } newsym(mtmp->mx, mtmp->my); return FALSE; } else if (!IS_ROCK(here->typ) && !IS_TREE(here->typ)) /* no dig */ return FALSE; /* Only rock, trees, and walls fall through to this point. */ if ((here->wall_info & W_NONDIGGABLE) != 0) { impossible("mdig_tunnel: %s at (%d,%d) is undiggable", (IS_WALL(here->typ) ? "wall" : "stone"), (int) mtmp->mx, (int) mtmp->my); return FALSE; /* still alive */ } if (IS_WALL(here->typ)) { /* KMH -- Okay on arboreal levels (room walls are still stone) */ if (flags.soundok && flags.verbose && !rn2(5)) You_hear("crashing rock."); if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); if (level.flags.is_maze_lev) { here->typ = ROOM; } else if (level.flags.is_cavernous_lev && !in_town(mtmp->mx, mtmp->my)) { here->typ = CORR; } else { here->typ = DOOR; here->doormask = D_NODOOR; } } else if (IS_TREE(here->typ)) { here->typ = ROOM; if (pile && pile < 5) (void) rnd_treefruit_at(mtmp->mx, mtmp->my); } else { here->typ = CORR; if (pile && pile < 5) (void) mksobj_at((pile == 1) ? BOULDER : ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); } newsym(mtmp->mx, mtmp->my); if (!sobj_at(BOULDER, mtmp->mx, mtmp->my)) unblock_point(mtmp->mx, mtmp->my); /* vision */ return FALSE; } #endif /* OVL0 */ #ifdef OVL3 /* digging via wand zap or spell cast */ void zap_dig() { struct rm *room; struct monst *mtmp; struct obj *otmp; int zx, zy, digdepth; boolean shopdoor, shopwall, maze_dig; /* * Original effect (approximately): * from CORR: dig until we pierce a wall * from ROOM: pierce wall and dig until we reach * an ACCESSIBLE place. * Currently: dig for digdepth positions; * also down on request of Lennart Augustsson. */ if (u.uswallow) { mtmp = u.ustuck; if (!is_whirly(mtmp->data)) { if (is_animal(mtmp->data)) You("pierce %s %s wall!", s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH)); mtmp->mhp = 1; /* almost dead */ expels(mtmp, mtmp->data, !is_animal(mtmp->data)); } return; } /* swallowed */ if (u.dz) { if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater) { if (u.dz < 0 || On_stairs(u.ux, u.uy)) { if (On_stairs(u.ux, u.uy)) pline_The("beam bounces off the %s and hits the %s.", (u.ux == xdnladder || u.ux == xupladder) ? "ladder" : "stairs", ceiling(u.ux, u.uy)); You("loosen a rock from the %s.", ceiling(u.ux, u.uy)); pline("It falls on your %s!", body_part(HEAD)); losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6), "falling rock", KILLED_BY_AN); otmp = mksobj_at(ROCK, u.ux, u.uy, FALSE, FALSE); if (otmp) { (void)xname(otmp); /* set dknown, maybe bknown */ stackobj(otmp); } newsym(u.ux, u.uy); } else { watch_dig((struct monst *)0, u.ux, u.uy, TRUE); (void) dighole(FALSE); } } return; } /* up or down */ /* normal case: digging across the level */ shopdoor = shopwall = FALSE; maze_dig = level.flags.is_maze_lev && !Is_earthlevel(&u.uz); zx = u.ux + u.dx; zy = u.uy + u.dy; digdepth = rn1(18, 8); tmp_at(DISP_BEAM, cmap_to_glyph(S_digbeam)); while (--digdepth >= 0) { if (!isok(zx,zy)) break; room = &levl[zx][zy]; tmp_at(zx,zy); delay_output(); /* wait a little bit */ if (closed_door(zx, zy) || room->typ == SDOOR) { if (*in_rooms(zx,zy,SHOPBASE)) { add_damage(zx, zy, 400L); shopdoor = TRUE; } if (room->typ == SDOOR) room->typ = DOOR; else if (cansee(zx, zy)) pline_The("door is razed!"); watch_dig((struct monst *)0, zx, zy, TRUE); room->doormask = D_NODOOR; unblock_point(zx,zy); /* vision */ digdepth -= 2; if (maze_dig) break; } else if (maze_dig) { if (IS_WALL(room->typ)) { if (!(room->wall_info & W_NONDIGGABLE)) { if (*in_rooms(zx,zy,SHOPBASE)) { add_damage(zx, zy, 200L); shopwall = TRUE; } room->typ = ROOM; unblock_point(zx,zy); /* vision */ } else if (!Blind) pline_The("wall glows then fades."); break; } else if (IS_TREE(room->typ)) { /* check trees before stone */ if (!(room->wall_info & W_NONDIGGABLE)) { room->typ = ROOM; unblock_point(zx,zy); /* vision */ } else if (!Blind) pline_The("tree shudders but is unharmed."); break; } else if (room->typ == STONE || room->typ == SCORR) { if (!(room->wall_info & W_NONDIGGABLE)) { room->typ = CORR; unblock_point(zx,zy); /* vision */ } else if (!Blind) pline_The("rock glows then fades."); break; } } else if (IS_ROCK(room->typ)) { if (!may_dig(zx,zy)) break; if (IS_WALL(room->typ) || room->typ == SDOOR) { if (*in_rooms(zx,zy,SHOPBASE)) { add_damage(zx, zy, 200L); shopwall = TRUE; } watch_dig((struct monst *)0, zx, zy, TRUE); if (level.flags.is_cavernous_lev && !in_town(zx, zy)) { room->typ = CORR; } else { room->typ = DOOR; room->doormask = D_NODOOR; } digdepth -= 2; } else if (IS_TREE(room->typ)) { room->typ = ROOM; digdepth -= 2; } else { /* IS_ROCK but not IS_WALL or SDOOR */ room->typ = CORR; digdepth--; } unblock_point(zx,zy); /* vision */ } zx += u.dx; zy += u.dy; } /* while */ tmp_at(DISP_END,0); /* closing call */ if (shopdoor || shopwall) pay_for_damage(shopdoor ? "destroy" : "dig into", FALSE); return; } /* move objects from fobj/nexthere lists to buriedobjlist, keeping position */ /* information */ struct obj * bury_an_obj(otmp) struct obj *otmp; { struct obj *otmp2; boolean under_ice; #ifdef DEBUG pline("bury_an_obj: %s", xname(otmp)); #endif if (otmp == uball) unpunish(); /* after unpunish(), or might get deallocated chain */ otmp2 = otmp->nexthere; /* * obj_resists(,0,0) prevents Rider corpses from being buried. * It also prevents The Amulet and invocation tools from being * buried. Since they can't be confined to bags and statues, * it makes sense that they can't be buried either, even though * the real reason there (direct accessibility when carried) is * completely different. */ if (otmp == uchain || obj_resists(otmp, 0, 0)) return(otmp2); if (otmp->otyp == LEASH && otmp->leashmon != 0) o_unleash(otmp); if (otmp->lamplit && otmp->otyp != POT_OIL) end_burn(otmp, TRUE); obj_extract_self(otmp); under_ice = is_ice(otmp->ox, otmp->oy); if (otmp->otyp == ROCK && !under_ice) { /* merges into burying material */ obfree(otmp, (struct obj *)0); return(otmp2); } /* * Start a rot on organic material. Not corpses -- they * are already handled. */ if (otmp->otyp == CORPSE) { ; /* should cancel timer if under_ice */ } else if ((under_ice ? otmp->oclass == POTION_CLASS : is_organic(otmp)) && !obj_resists(otmp, 5, 95)) { (void) start_timer((under_ice ? 0L : 250L) + (long)rnd(250), TIMER_OBJECT, ROT_ORGANIC, (genericptr_t)otmp); } add_to_buried(otmp); return(otmp2); } void bury_objs(x, y) int x, y; { struct obj *otmp, *otmp2; #ifdef DEBUG if(level.objects[x][y] != (struct obj *)0) pline("bury_objs: at %d, %d", x, y); #endif for (otmp = level.objects[x][y]; otmp; otmp = otmp2) otmp2 = bury_an_obj(otmp); /* don't expect any engravings here, but just in case */ del_engr_at(x, y); newsym(x, y); } /* move objects from buriedobjlist to fobj/nexthere lists */ void unearth_objs(x, y) int x, y; { struct obj *otmp, *otmp2; #ifdef DEBUG pline("unearth_objs: at %d, %d", x, y); #endif for (otmp = level.buriedobjlist; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->ox == x && otmp->oy == y) { obj_extract_self(otmp); if (otmp->timed) (void) stop_timer(ROT_ORGANIC, (genericptr_t)otmp); place_object(otmp, x, y); stackobj(otmp); } } del_engr_at(x, y); newsym(x, y); } /* * The organic material has rotted away while buried. As an expansion, * we could add add partial damage. A damage count is kept in the object * and every time we are called we increment the count and reschedule another * timeout. Eventually the object rots away. * * This is used by buried objects other than corpses. When a container rots * away, any contents become newly buried objects. */ /* ARGSUSED */ void rot_organic(arg, timeout) genericptr_t arg; long timeout; /* unused */ { struct obj *obj = (struct obj *) arg; while (Has_contents(obj)) { /* We don't need to place contained object on the floor first, but we do need to update its map coordinates. */ obj->cobj->ox = obj->ox, obj->cobj->oy = obj->oy; /* Everything which can be held in a container can also be buried, so bury_an_obj's use of obj_extract_self insures that Has_contents(obj) will eventually become false. */ (void)bury_an_obj(obj->cobj); } obj_extract_self(obj); obfree(obj, (struct obj *) 0); } /* * Called when a corpse has rotted completely away. */ void rot_corpse(arg, timeout) genericptr_t arg; long timeout; /* unused */ { xchar x = 0, y = 0; struct obj *obj = (struct obj *) arg; boolean on_floor = obj->where == OBJ_FLOOR, in_invent = obj->where == OBJ_INVENT; if (on_floor) { x = obj->ox; y = obj->oy; } else if (in_invent) { if (flags.verbose) { char *cname = corpse_xname(obj, FALSE); Your("%s%s %s away%c", obj == uwep ? "wielded " : nul, cname, otense(obj, "rot"), obj == uwep ? '!' : '.'); } if (obj == uwep) { uwepgone(); /* now bare handed */ stop_occupation(); } else if (obj == uswapwep) { uswapwepgone(); stop_occupation(); } else if (obj == uquiver) { uqwepgone(); stop_occupation(); } } else if (obj->where == OBJ_MINVENT && obj->owornmask) { if (obj == MON_WEP(obj->ocarry)) { setmnotwielded(obj->ocarry,obj); MON_NOWEP(obj->ocarry); } } rot_organic(arg, timeout); if (on_floor) newsym(x, y); else if (in_invent) update_inventory(); } #if 0 void bury_monst(mtmp) struct monst *mtmp; { #ifdef DEBUG pline("bury_monst: %s", mon_nam(mtmp)); #endif if(canseemon(mtmp)) { if(is_flyer(mtmp->data) || is_floater(mtmp->data)) { pline_The("%s opens up, but %s is not swallowed!", surface(mtmp->mx, mtmp->my), mon_nam(mtmp)); return; } else pline_The("%s opens up and swallows %s!", surface(mtmp->mx, mtmp->my), mon_nam(mtmp)); } mtmp->mburied = TRUE; wakeup(mtmp); /* at least give it a chance :-) */ newsym(mtmp->mx, mtmp->my); } void bury_you() { #ifdef DEBUG pline("bury_you"); #endif if (!Levitation && !Flying) { if(u.uswallow) You_feel("a sensation like falling into a trap!"); else pline_The("%s opens beneath you and you fall in!", surface(u.ux, u.uy)); u.uburied = TRUE; if(!Strangled && !Breathless) Strangled = 6; under_ground(1); } } void unearth_you() { #ifdef DEBUG pline("unearth_you"); #endif u.uburied = FALSE; under_ground(0); if(!uamul || uamul->otyp != AMULET_OF_STRANGULATION) Strangled = 0; vision_recalc(0); } void escape_tomb() { #ifdef DEBUG pline("escape_tomb"); #endif if ((Teleportation || can_teleport(youmonst.data)) && (Teleport_control || rn2(3) < Luck+2)) { You("attempt a teleport spell."); (void) dotele(); /* calls unearth_you() */ } else if(u.uburied) { /* still buried after 'port attempt */ boolean good; if(amorphous(youmonst.data) || Passes_walls || noncorporeal(youmonst.data) || unsolid(youmonst.data) || (tunnels(youmonst.data) && !needspick(youmonst.data))) { You("%s up through the %s.", (tunnels(youmonst.data) && !needspick(youmonst.data)) ? "try to tunnel" : (amorphous(youmonst.data)) ? "ooze" : "phase", surface(u.ux, u.uy)); if(tunnels(youmonst.data) && !needspick(youmonst.data)) good = dighole(TRUE); else good = TRUE; if(good) unearth_you(); } } } void bury_obj(otmp) struct obj *otmp; { #ifdef DEBUG pline("bury_obj"); #endif if(cansee(otmp->ox, otmp->oy)) pline_The("objects on the %s tumble into a hole!", surface(otmp->ox, otmp->oy)); bury_objs(otmp->ox, otmp->oy); } #endif #ifdef DEBUG int wiz_debug_cmd() /* in this case, bury everything at your loc and around */ { int x, y; for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) if (isok(x,y)) bury_objs(x,y); return 0; } #endif /* DEBUG */ #endif /* OVL3 */ /*dig.c*/ nethack-3.4.3/src/display.c0100644000000000000000000016775007764735041014272 0ustar rootroot/* SCCS Id: @(#)display.c 3.4 2003/02/19 */ /* Copyright (c) Dean Luick, with acknowledgements to Kevin Darcy */ /* and Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ /* * THE NEW DISPLAY CODE * * The old display code has been broken up into three parts: vision, display, * and drawing. Vision decides what locations can and cannot be physically * seen by the hero. Display decides _what_ is displayed at a given location. * Drawing decides _how_ to draw a monster, fountain, sword, etc. * * The display system uses information from the vision system to decide * what to draw at a given location. The routines for the vision system * can be found in vision.c and vision.h. The routines for display can * be found in this file (display.c) and display.h. The drawing routines * are part of the window port. See doc/window.doc for the drawing * interface. * * The display system deals with an abstraction called a glyph. Anything * that could possibly be displayed has a unique glyph identifier. * * What is seen on the screen is a combination of what the hero remembers * and what the hero currently sees. Objects and dungeon features (walls * doors, etc) are remembered when out of sight. Monsters and temporary * effects are not remembered. Each location on the level has an * associated glyph. This is the hero's _memory_ of what he or she has * seen there before. * * Display rules: * * If the location is in sight, display in order: * visible (or sensed) monsters * visible objects * known traps * background * * If the location is out of sight, display in order: * sensed monsters (telepathy) * memory * * * * Here is a list of the major routines in this file to be used externally: * * newsym * * Possibly update the screen location (x,y). This is the workhorse routine. * It is always correct --- where correct means following the in-sight/out- * of-sight rules. **Most of the code should use this routine.** This * routine updates the map and displays monsters. * * * map_background * map_object * map_trap * map_invisible * unmap_object * * If you absolutely must override the in-sight/out-of-sight rules, there * are two possibilities. First, you can mess with vision to force the * location in sight then use newsym(), or you can use the map_* routines. * The first has not been tried [no need] and the second is used in the * detect routines --- detect object, magic mapping, etc. The map_* * routines *change* what the hero remembers. All changes made by these * routines will be sticky --- they will survive screen redraws. Do *not* * use these for things that only temporarily change the screen. These * routines are also used directly by newsym(). unmap_object is used to * clear a remembered object when/if detection reveals it isn't there. * * * show_glyph * * This is direct (no processing in between) buffered access to the screen. * Temporary screen effects are run through this and its companion, * flush_screen(). There is yet a lower level routine, print_glyph(), * but this is unbuffered and graphic dependent (i.e. it must be surrounded * by graphic set-up and tear-down routines). Do not use print_glyph(). * * * see_monsters * see_objects * see_traps * * These are only used when something affects all of the monsters or * objects or traps. For objects and traps, the only thing is hallucination. * For monsters, there are hallucination and changing from/to blindness, etc. * * * tmp_at * * This is a useful interface for displaying temporary items on the screen. * Its interface is different than previously, so look at it carefully. * * * * Parts of the rm structure that are used: * * typ - What is really there. * glyph - What the hero remembers. This will never be a monster. * Monsters "float" above this. * lit - True if the position is lit. An optimization for * lit/unlit rooms. * waslit - True if the position was *remembered* as lit. * seenv - A vector of bits representing the directions from which the * hero has seen this position. The vector's primary use is * determining how walls are seen. E.g. a wall sometimes looks * like stone on one side, but is seen as a wall from the other. * Other uses are for unmapping detected objects and felt * locations, where we need to know if the hero has ever * seen the location. * flags - Additional information for the typ field. Different for * each typ. * horizontal - Indicates whether the wall or door is horizontal or * vertical. */ #include "hack.h" #include "region.h" STATIC_DCL void FDECL(display_monster,(XCHAR_P,XCHAR_P,struct monst *,int,XCHAR_P)); STATIC_DCL int FDECL(swallow_to_glyph, (int, int)); STATIC_DCL void FDECL(display_warning,(struct monst *)); STATIC_DCL int FDECL(check_pos, (int, int, int)); #ifdef WA_VERBOSE STATIC_DCL boolean FDECL(more_than_one, (int, int, int, int, int)); #endif STATIC_DCL int FDECL(set_twall, (int,int, int,int, int,int, int,int)); STATIC_DCL int FDECL(set_wall, (int, int, int)); STATIC_DCL int FDECL(set_corn, (int,int, int,int, int,int, int,int)); STATIC_DCL int FDECL(set_crosswall, (int, int)); STATIC_DCL void FDECL(set_seenv, (struct rm *, int, int, int, int)); STATIC_DCL void FDECL(t_warn, (struct rm *)); STATIC_DCL int FDECL(wall_angle, (struct rm *)); #ifdef INVISIBLE_OBJECTS /* * vobj_at() * * Returns a pointer to an object if the hero can see an object at the * given location. This takes care of invisible objects. NOTE, this * assumes that the hero is not blind and on top of the object pile. * It does NOT take into account that the location is out of sight, or, * say, one can see blessed, etc. */ struct obj * vobj_at(x,y) xchar x,y; { register struct obj *obj = level.objects[x][y]; while (obj) { if (!obj->oinvis || See_invisible) return obj; obj = obj->nexthere; } return ((struct obj *) 0); } #endif /* else vobj_at() is defined in display.h */ /* * magic_map_background() * * This function is similar to map_background (see below) except we pay * attention to and correct unexplored, lit ROOM and CORR spots. */ void magic_map_background(x, y, show) xchar x,y; int show; { int glyph = back_to_glyph(x,y); /* assumes hero can see x,y */ struct rm *lev = &levl[x][y]; /* * Correct for out of sight lit corridors and rooms that the hero * doesn't remember as lit. */ if (!cansee(x,y) && !lev->waslit) { /* Floor spaces are dark if unlit. Corridors are dark if unlit. */ if (lev->typ == ROOM && glyph == cmap_to_glyph(S_room)) glyph = cmap_to_glyph(S_stone); else if (lev->typ == CORR && glyph == cmap_to_glyph(S_litcorr)) glyph = cmap_to_glyph(S_corr); } if (level.flags.hero_memory) lev->glyph = glyph; if (show) show_glyph(x,y, glyph); } /* * The routines map_background(), map_object(), and map_trap() could just * as easily be: * * map_glyph(x,y,glyph,show) * * Which is called with the xx_to_glyph() in the call. Then I can get * rid of 3 routines that don't do very much anyway. And then stop * having to create fake objects and traps. However, I am reluctant to * make this change. */ /* FIXME: some of these use xchars for x and y, and some use ints. Make * this consistent. */ /* * map_background() * * Make the real background part of our map. This routine assumes that * the hero can physically see the location. Update the screen if directed. */ void map_background(x, y, show) register xchar x,y; register int show; { register int glyph = back_to_glyph(x,y); if (level.flags.hero_memory) levl[x][y].glyph = glyph; if (show) show_glyph(x,y, glyph); } /* * map_trap() * * Map the trap and print it out if directed. This routine assumes that the * hero can physically see the location. */ void map_trap(trap, show) register struct trap *trap; register int show; { register int x = trap->tx, y = trap->ty; register int glyph = trap_to_glyph(trap); if (level.flags.hero_memory) levl[x][y].glyph = glyph; if (show) show_glyph(x, y, glyph); } /* * map_object() * * Map the given object. This routine assumes that the hero can physically * see the location of the object. Update the screen if directed. */ void map_object(obj, show) register struct obj *obj; register int show; { register int x = obj->ox, y = obj->oy; register int glyph = obj_to_glyph(obj); if (level.flags.hero_memory) levl[x][y].glyph = glyph; if (show) show_glyph(x, y, glyph); } /* * map_invisible() * * Make the hero remember that a square contains an invisible monster. * This is a special case in that the square will continue to be displayed * this way even when the hero is close enough to see it. To get rid of * this and display the square's actual contents, use unmap_object() followed * by newsym() if necessary. */ void map_invisible(x, y) register xchar x, y; { if (x != u.ux || y != u.uy) { /* don't display I at hero's location */ if (level.flags.hero_memory) levl[x][y].glyph = GLYPH_INVISIBLE; show_glyph(x, y, GLYPH_INVISIBLE); } } /* * unmap_object() * * Remove something from the map when the hero realizes it's not there any * more. Replace it with background or known trap, but not with any other * If this is used for detection, a full screen update is imminent anyway; * if this is used to get rid of an invisible monster notation, we might have * to call newsym(). */ void unmap_object(x, y) register int x, y; { register struct trap *trap; if (!level.flags.hero_memory) return; if ((trap = t_at(x,y)) != 0 && trap->tseen && !covers_traps(x,y)) map_trap(trap, 0); else if (levl[x][y].seenv) { struct rm *lev = &levl[x][y]; map_background(x, y, 0); /* turn remembered dark room squares dark */ if (!lev->waslit && lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM) lev->glyph = cmap_to_glyph(S_stone); } else levl[x][y].glyph = cmap_to_glyph(S_stone); /* default val */ } /* * map_location() * * Make whatever at this location show up. This is only for non-living * things. This will not handle feeling invisible objects correctly. * * Internal to display.c, this is a #define for speed. */ #define _map_location(x,y,show) \ { \ register struct obj *obj; \ register struct trap *trap; \ \ if ((obj = vobj_at(x,y)) && !covers_objects(x,y)) \ map_object(obj,show); \ else if ((trap = t_at(x,y)) && trap->tseen && !covers_traps(x,y)) \ map_trap(trap,show); \ else \ map_background(x,y,show); \ } void map_location(x,y,show) int x, y, show; { _map_location(x,y,show); } #define DETECTED 2 #define PHYSICALLY_SEEN 1 #define is_worm_tail(mon) ((mon) && ((x != (mon)->mx) || (y != (mon)->my))) /* * display_monster() * * Note that this is *not* a map_XXXX() function! Monsters sort of float * above everything. * * Yuck. Display body parts by recognizing that the display position is * not the same as the monster position. Currently the only body part is * a worm tail. * */ STATIC_OVL void display_monster(x, y, mon, sightflags, worm_tail) register xchar x, y; /* display position */ register struct monst *mon; /* monster to display */ int sightflags; /* 1 if the monster is physically seen */ /* 2 if detected using Detect_monsters */ register xchar worm_tail; /* mon is actually a worm tail */ { register boolean mon_mimic = (mon->m_ap_type != M_AP_NOTHING); register int sensed = mon_mimic && (Protection_from_shape_changers || sensemon(mon)); /* * We must do the mimic check first. If the mimic is mimicing something, * and the location is in sight, we have to change the hero's memory * so that when the position is out of sight, the hero remembers what * the mimic was mimicing. */ if (mon_mimic && (sightflags == PHYSICALLY_SEEN)) { switch (mon->m_ap_type) { default: impossible("display_monster: bad m_ap_type value [ = %d ]", (int) mon->m_ap_type); case M_AP_NOTHING: show_glyph(x, y, mon_to_glyph(mon)); break; case M_AP_FURNITURE: { /* * This is a poor man's version of map_background(). I can't * use map_background() because we are overriding what is in * the 'typ' field. Maybe have map_background()'s parameters * be (x,y,glyph) instead of just (x,y). * * mappearance is currently set to an S_ index value in * makemon.c. */ register int glyph = cmap_to_glyph(mon->mappearance); levl[x][y].glyph = glyph; if (!sensed) show_glyph(x,y, glyph); break; } case M_AP_OBJECT: { struct obj obj; /* Make a fake object to send */ /* to map_object(). */ obj.ox = x; obj.oy = y; obj.otyp = mon->mappearance; obj.corpsenm = PM_TENGU; /* if mimicing a corpse */ map_object(&obj,!sensed); break; } case M_AP_MONSTER: show_glyph(x,y, monnum_to_glyph(what_mon((int)mon->mappearance))); break; } } /* If the mimic is unsucessfully mimicing something, display the monster */ if (!mon_mimic || sensed) { int num; /* [ALI] Only use detected glyphs when monster wouldn't be * visible by any other means. */ if (sightflags == DETECTED) { if (worm_tail) num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); else num = detected_mon_to_glyph(mon); } else if (mon->mtame && !Hallucination) { if (worm_tail) num = petnum_to_glyph(PM_LONG_WORM_TAIL); else num = pet_to_glyph(mon); } else { if (worm_tail) num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); else num = mon_to_glyph(mon); } show_glyph(x,y,num); } } /* * display_warning() * * This is also *not* a map_XXXX() function! Monster warnings float * above everything just like monsters do, but only if the monster * is not showing. * * Do not call for worm tails. */ STATIC_OVL void display_warning(mon) register struct monst *mon; { int x = mon->mx, y = mon->my; int wl = (int) (mon->m_lev / 4); int glyph; if (mon_warning(mon)) { if (wl > WARNCOUNT - 1) wl = WARNCOUNT - 1; /* 3.4.1: this really ought to be rn2(WARNCOUNT), but value "0" isn't handled correctly by the what_is routine so avoid it */ if (Hallucination) wl = rn1(WARNCOUNT-1,1); glyph = warning_to_glyph(wl); } else if (MATCH_WARN_OF_MON(mon)) { glyph = mon_to_glyph(mon); } else { impossible("display_warning did not match warning type?"); return; } show_glyph(x, y, glyph); } /* * feel_location() * * Feel the given location. This assumes that the hero is blind and that * the given position is either the hero's or one of the eight squares * adjacent to the hero (except for a boulder push). * If an invisible monster has gone away, that will be discovered. If an * invisible monster has appeared, this will _not_ be discovered since * searching only finds one monster per turn so we must check that separately. */ void feel_location(x, y) xchar x, y; { struct rm *lev = &(levl[x][y]); struct obj *boulder; register struct monst *mon; /* If the hero's memory of an invisible monster is accurate, we want to keep * him from detecting the same monster over and over again on each turn. * We must return (so we don't erase the monster). (We must also, in the * search function, be sure to skip over previously detected 'I's.) */ if (glyph_is_invisible(levl[x][y].glyph) && m_at(x,y)) return; /* The hero can't feel non pool locations while under water. */ if (Underwater && !Is_waterlevel(&u.uz) && ! is_pool(x,y)) return; /* Set the seen vector as if the hero had seen it. It doesn't matter */ /* if the hero is levitating or not. */ set_seenv(lev, u.ux, u.uy, x, y); if (Levitation && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) { /* * Levitation Rules. It is assumed that the hero can feel the state * of the walls around herself and can tell if she is in a corridor, * room, or doorway. Boulders are felt because they are large enough. * Anything else is unknown because the hero can't reach the ground. * This makes things difficult. * * Check (and display) in order: * * + Stone, walls, and closed doors. * + Boulders. [see a boulder before a doorway] * + Doors. * + Room/water positions * + Everything else (hallways!) */ if (IS_ROCK(lev->typ) || (IS_DOOR(lev->typ) && (lev->doormask & (D_LOCKED | D_CLOSED)))) { map_background(x, y, 1); } else if ((boulder = sobj_at(BOULDER,x,y)) != 0) { map_object(boulder, 1); } else if (IS_DOOR(lev->typ)) { map_background(x, y, 1); } else if (IS_ROOM(lev->typ) || IS_POOL(lev->typ)) { /* * An open room or water location. Normally we wouldn't touch * this, but we have to get rid of remembered boulder symbols. * This will only occur in rare occations when the hero goes * blind and doesn't find a boulder where expected (something * came along and picked it up). We know that there is not a * boulder at this location. Show fountains, pools, etc. * underneath if already seen. Otherwise, show the appropriate * floor symbol. * * Similarly, if the hero digs a hole in a wall or feels a location * that used to contain an unseen monster. In these cases, * there's no reason to assume anything was underneath, so * just show the appropriate floor symbol. If something was * embedded in the wall, the glyph will probably already * reflect that. Don't change the symbol in this case. * * This isn't quite correct. If the boulder was on top of some * other objects they should be seen once the boulder is removed. * However, we have no way of knowing that what is there now * was there then. So we let the hero have a lapse of memory. * We could also just display what is currently on the top of the * object stack (if anything). */ if (lev->glyph == objnum_to_glyph(BOULDER)) { if (lev->typ != ROOM && lev->seenv) { map_background(x, y, 1); } else { lev->glyph = lev->waslit ? cmap_to_glyph(S_room) : cmap_to_glyph(S_stone); show_glyph(x,y,lev->glyph); } } else if ((lev->glyph >= cmap_to_glyph(S_stone) && lev->glyph < cmap_to_glyph(S_room)) || glyph_is_invisible(levl[x][y].glyph)) { lev->glyph = lev->waslit ? cmap_to_glyph(S_room) : cmap_to_glyph(S_stone); show_glyph(x,y,lev->glyph); } } else { /* We feel it (I think hallways are the only things left). */ map_background(x, y, 1); /* Corridors are never felt as lit (unless remembered that way) */ /* (lit_corridor only). */ if (lev->typ == CORR && lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); } } else { _map_location(x, y, 1); if (Punished) { /* * A ball or chain is only felt if it is first on the object * location list. Otherwise, we need to clear the felt bit --- * something has been dropped on the ball/chain. If the bit is * not cleared, then when the ball/chain is moved it will drop * the wrong glyph. */ if (uchain->ox == x && uchain->oy == y) { if (level.objects[x][y] == uchain) u.bc_felt |= BC_CHAIN; else u.bc_felt &= ~BC_CHAIN; /* do not feel the chain */ } if (!carried(uball) && uball->ox == x && uball->oy == y) { if (level.objects[x][y] == uball) u.bc_felt |= BC_BALL; else u.bc_felt &= ~BC_BALL; /* do not feel the ball */ } } /* Floor spaces are dark if unlit. Corridors are dark if unlit. */ if (lev->typ == ROOM && lev->glyph == cmap_to_glyph(S_room) && !lev->waslit) show_glyph(x,y, lev->glyph = cmap_to_glyph(S_stone)); else if (lev->typ == CORR && lev->glyph == cmap_to_glyph(S_litcorr) && !lev->waslit) show_glyph(x,y, lev->glyph = cmap_to_glyph(S_corr)); } /* draw monster on top if we can sense it */ if ((x != u.ux || y != u.uy) && (mon = m_at(x,y)) && sensemon(mon)) display_monster(x, y, mon, (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)) ? PHYSICALLY_SEEN : DETECTED, is_worm_tail(mon)); } /* * newsym() * * Possibly put a new glyph at the given location. */ void newsym(x,y) register int x,y; { register struct monst *mon; register struct rm *lev = &(levl[x][y]); register int see_it; register xchar worm_tail; if (in_mklev) return; /* only permit updating the hero when swallowed */ if (u.uswallow) { if (x == u.ux && y == u.uy) display_self(); return; } if (Underwater && !Is_waterlevel(&u.uz)) { /* don't do anything unless (x,y) is an adjacent underwater position */ int dx, dy; if (!is_pool(x,y)) return; dx = x - u.ux; if (dx < 0) dx = -dx; dy = y - u.uy; if (dy < 0) dy = -dy; if (dx > 1 || dy > 1) return; } /* Can physically see the location. */ if (cansee(x,y)) { NhRegion* reg = visible_region_at(x,y); /* * Don't use templit here: E.g. * * lev->waslit = !!(lev->lit || templit(x,y)); * * Otherwise we have the "light pool" problem, where non-permanently * lit areas just out of sight stay remembered as lit. They should * re-darken. * * Perhaps ALL areas should revert to their "unlit" look when * out of sight. */ lev->waslit = (lev->lit!=0); /* remember lit condition */ if (reg != NULL && ACCESSIBLE(lev->typ)) { show_region(reg,x,y); return; } if (x == u.ux && y == u.uy) { if (senseself()) { _map_location(x,y,0); /* map *under* self */ display_self(); } else /* we can see what is there */ _map_location(x,y,1); } else { mon = m_at(x,y); worm_tail = is_worm_tail(mon); see_it = mon && (worm_tail ? (!mon->minvis || See_invisible) : (mon_visible(mon)) || tp_sensemon(mon) || MATCH_WARN_OF_MON(mon)); if (mon && (see_it || (!worm_tail && Detect_monsters))) { if (mon->mtrapped) { struct trap *trap = t_at(x, y); int tt = trap ? trap->ttyp : NO_TRAP; /* if monster is in a physical trap, you see the trap too */ if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT ||tt == WEB) { trap->tseen = TRUE; } } _map_location(x,y,0); /* map under the monster */ /* also gets rid of any invisibility glyph */ display_monster(x, y, mon, see_it ? PHYSICALLY_SEEN : DETECTED, worm_tail); } else if (mon && mon_warning(mon) && !is_worm_tail(mon)) display_warning(mon); else if (glyph_is_invisible(levl[x][y].glyph)) map_invisible(x, y); else _map_location(x,y,1); /* map the location */ } } /* Can't see the location. */ else { if (x == u.ux && y == u.uy) { feel_location(u.ux, u.uy); /* forces an update */ if (senseself()) display_self(); } else if ((mon = m_at(x,y)) && ((see_it = (tp_sensemon(mon) || MATCH_WARN_OF_MON(mon) || (see_with_infrared(mon) && mon_visible(mon)))) || Detect_monsters) && !is_worm_tail(mon)) { /* Monsters are printed every time. */ /* This also gets rid of any invisibility glyph */ display_monster(x, y, mon, see_it ? 0 : DETECTED, 0); } else if ((mon = m_at(x,y)) && mon_warning(mon) && !is_worm_tail(mon)) { display_warning(mon); } /* * If the location is remembered as being both dark (waslit is false) * and lit (glyph is a lit room or lit corridor) then it was either: * * (1) A dark location that the hero could see through night * vision. * * (2) Darkened while out of the hero's sight. This can happen * when cursed scroll of light is read. * * In either case, we have to manually correct the hero's memory to * match waslit. Deciding when to change waslit is non-trivial. * * Note: If flags.lit_corridor is set, then corridors act like room * squares. That is, they light up if in night vision range. * If flags.lit_corridor is not set, then corridors will * remain dark unless lit by a light spell and may darken * again, as discussed above. * * These checks and changes must be here and not in back_to_glyph(). * They are dependent on the position being out of sight. */ else if (!lev->waslit) { if (lev->glyph == cmap_to_glyph(S_litcorr) && lev->typ == CORR) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_corr)); else if (lev->glyph == cmap_to_glyph(S_room) && lev->typ == ROOM) show_glyph(x, y, lev->glyph = cmap_to_glyph(S_stone)); else goto show_mem; } else { show_mem: show_glyph(x, y, lev->glyph); } } } #undef is_worm_tail /* * shieldeff() * * Put magic shield pyrotechnics at the given location. This *could* be * pulled into a platform dependent routine for fancier graphics if desired. */ void shieldeff(x,y) xchar x,y; { register int i; if (!flags.sparkle) return; if (cansee(x,y)) { /* Don't see anything if can't see the location */ for (i = 0; i < SHIELD_COUNT; i++) { show_glyph(x, y, cmap_to_glyph(shield_static[i])); flush_screen(1); /* make sure the glyph shows up */ delay_output(); } newsym(x,y); /* restore the old information */ } } /* * tmp_at() * * Temporarily place glyphs on the screen. Do not call delay_output(). It * is up to the caller to decide if it wants to wait [presently, everyone * but explode() wants to delay]. * * Call: * (DISP_BEAM, glyph) open, initialize glyph * (DISP_FLASH, glyph) open, initialize glyph * (DISP_ALWAYS, glyph) open, initialize glyph * (DISP_CHANGE, glyph) change glyph * (DISP_END, 0) close & clean up (second argument doesn't * matter) * (DISP_FREEMEM, 0) only used to prevent memory leak during * exit) * (x, y) display the glyph at the location * * DISP_BEAM - Display the given glyph at each location, but do not erase * any until the close call. * DISP_FLASH - Display the given glyph at each location, but erase the * previous location's glyph. * DISP_ALWAYS- Like DISP_FLASH, but vision is not taken into account. */ static struct tmp_glyph { coord saved[COLNO]; /* previously updated positions */ int sidx; /* index of next unused slot in saved[] */ int style; /* either DISP_BEAM or DISP_FLASH or DISP_ALWAYS */ int glyph; /* glyph to use when printing */ struct tmp_glyph *prev; } tgfirst; void tmp_at(x, y) int x, y; { static struct tmp_glyph *tglyph = (struct tmp_glyph *)0; struct tmp_glyph *tmp; switch (x) { case DISP_BEAM: case DISP_FLASH: case DISP_ALWAYS: if (!tglyph) tmp = &tgfirst; else /* nested effect; we need dynamic memory */ tmp = (struct tmp_glyph *)alloc(sizeof (struct tmp_glyph)); tmp->prev = tglyph; tglyph = tmp; tglyph->sidx = 0; tglyph->style = x; tglyph->glyph = y; flush_screen(0); /* flush buffered glyphs */ return; case DISP_FREEMEM: /* in case game ends with tmp_at() in progress */ while (tglyph) { tmp = tglyph->prev; if (tglyph != &tgfirst) free((genericptr_t)tglyph); tglyph = tmp; } return; default: break; } if (!tglyph) panic("tmp_at: tglyph not initialized"); switch (x) { case DISP_CHANGE: tglyph->glyph = y; break; case DISP_END: if (tglyph->style == DISP_BEAM) { register int i; /* Erase (reset) from source to end */ for (i = 0; i < tglyph->sidx; i++) newsym(tglyph->saved[i].x, tglyph->saved[i].y); } else { /* DISP_FLASH or DISP_ALWAYS */ if (tglyph->sidx) /* been called at least once */ newsym(tglyph->saved[0].x, tglyph->saved[0].y); } /* tglyph->sidx = 0; -- about to be freed, so not necessary */ tmp = tglyph->prev; if (tglyph != &tgfirst) free((genericptr_t)tglyph); tglyph = tmp; break; default: /* do it */ if (tglyph->style == DISP_BEAM) { if (!cansee(x,y)) break; /* save pos for later erasing */ tglyph->saved[tglyph->sidx].x = x; tglyph->saved[tglyph->sidx].y = y; tglyph->sidx += 1; } else { /* DISP_FLASH/ALWAYS */ if (tglyph->sidx) { /* not first call, so reset previous pos */ newsym(tglyph->saved[0].x, tglyph->saved[0].y); tglyph->sidx = 0; /* display is presently up to date */ } if (!cansee(x,y) && tglyph->style != DISP_ALWAYS) break; tglyph->saved[0].x = x; tglyph->saved[0].y = y; tglyph->sidx = 1; } show_glyph(x, y, tglyph->glyph); /* show it */ flush_screen(0); /* make sure it shows up */ break; } /* end case */ } /* * swallowed() * * The hero is swallowed. Show a special graphics sequence for this. This * bypasses all of the display routines and messes with buffered screen * directly. This method works because both vision and display check for * being swallowed. */ void swallowed(first) int first; { static xchar lastx, lasty; /* last swallowed position */ int swallower, left_ok, rght_ok; if (first) cls(); else { register int x, y; /* Clear old location */ for (y = lasty-1; y <= lasty+1; y++) for (x = lastx-1; x <= lastx+1; x++) if (isok(x,y)) show_glyph(x,y,cmap_to_glyph(S_stone)); } swallower = monsndx(u.ustuck->data); /* assume isok(u.ux,u.uy) */ left_ok = isok(u.ux-1,u.uy); rght_ok = isok(u.ux+1,u.uy); /* * Display the hero surrounded by the monster's stomach. */ if(isok(u.ux, u.uy-1)) { if (left_ok) show_glyph(u.ux-1, u.uy-1, swallow_to_glyph(swallower, S_sw_tl)); show_glyph(u.ux , u.uy-1, swallow_to_glyph(swallower, S_sw_tc)); if (rght_ok) show_glyph(u.ux+1, u.uy-1, swallow_to_glyph(swallower, S_sw_tr)); } if (left_ok) show_glyph(u.ux-1, u.uy , swallow_to_glyph(swallower, S_sw_ml)); display_self(); if (rght_ok) show_glyph(u.ux+1, u.uy , swallow_to_glyph(swallower, S_sw_mr)); if(isok(u.ux, u.uy+1)) { if (left_ok) show_glyph(u.ux-1, u.uy+1, swallow_to_glyph(swallower, S_sw_bl)); show_glyph(u.ux , u.uy+1, swallow_to_glyph(swallower, S_sw_bc)); if (rght_ok) show_glyph(u.ux+1, u.uy+1, swallow_to_glyph(swallower, S_sw_br)); } /* Update the swallowed position. */ lastx = u.ux; lasty = u.uy; } /* * under_water() * * Similar to swallowed() in operation. Shows hero when underwater * except when in water level. Special routines exist for that. */ void under_water(mode) int mode; { static xchar lastx, lasty; static boolean dela; register int x, y; /* swallowing has a higher precedence than under water */ if (Is_waterlevel(&u.uz) || u.uswallow) return; /* full update */ if (mode == 1 || dela) { cls(); dela = FALSE; } /* delayed full update */ else if (mode == 2) { dela = TRUE; return; } /* limited update */ else { for (y = lasty-1; y <= lasty+1; y++) for (x = lastx-1; x <= lastx+1; x++) if (isok(x,y)) show_glyph(x,y,cmap_to_glyph(S_stone)); } for (x = u.ux-1; x <= u.ux+1; x++) for (y = u.uy-1; y <= u.uy+1; y++) if (isok(x,y) && is_pool(x,y)) { if (Blind && !(x == u.ux && y == u.uy)) show_glyph(x,y,cmap_to_glyph(S_stone)); else newsym(x,y); } lastx = u.ux; lasty = u.uy; } /* * under_ground() * * Very restricted display. You can only see yourself. */ void under_ground(mode) int mode; { static boolean dela; /* swallowing has a higher precedence than under ground */ if (u.uswallow) return; /* full update */ if (mode == 1 || dela) { cls(); dela = FALSE; } /* delayed full update */ else if (mode == 2) { dela = TRUE; return; } /* limited update */ else newsym(u.ux,u.uy); } /* ========================================================================= */ /* * Loop through all of the monsters and update them. Called when: * + going blind & telepathic * + regaining sight & telepathic * + getting and losing infravision * + hallucinating * + doing a full screen redraw * + see invisible times out or a ring of see invisible is taken off * + when a potion of see invisible is quaffed or a ring of see * invisible is put on * + gaining telepathy when blind [givit() in eat.c, pleased() in pray.c] * + losing telepathy while blind [xkilled() in mon.c, attrcurse() in * sit.c] */ void see_monsters() { register struct monst *mon; for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; newsym(mon->mx,mon->my); if (mon->wormno) see_wsegs(mon); } #ifdef STEED /* when mounted, hero's location gets caught by monster loop */ if (!u.usteed) #endif newsym(u.ux, u.uy); } /* * Block/unblock light depending on what a mimic is mimicing and if it's * invisible or not. Should be called only when the state of See_invisible * changes. */ void set_mimic_blocking() { register struct monst *mon; for (mon = fmon; mon; mon = mon->nmon) { if (DEADMONSTER(mon)) continue; if (mon->minvis && ((mon->m_ap_type == M_AP_FURNITURE && (mon->mappearance == S_vcdoor || mon->mappearance == S_hcdoor)) || (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) { if(See_invisible) block_point(mon->mx, mon->my); else unblock_point(mon->mx, mon->my); } } } /* * Loop through all of the object *locations* and update them. Called when * + hallucinating. */ void see_objects() { register struct obj *obj; for(obj = fobj; obj; obj = obj->nobj) if (vobj_at(obj->ox,obj->oy) == obj) newsym(obj->ox, obj->oy); } /* * Update hallucinated traps. */ void see_traps() { struct trap *trap; int glyph; for (trap = ftrap; trap; trap = trap->ntrap) { glyph = glyph_at(trap->tx, trap->ty); if (glyph_is_trap(glyph)) newsym(trap->tx, trap->ty); } } /* * Put the cursor on the hero. Flush all accumulated glyphs before doing it. */ void curs_on_u() { flush_screen(1); /* Flush waiting glyphs & put cursor on hero */ } int doredraw() { docrt(); return 0; } void docrt() { register int x,y; register struct rm *lev; if (!u.ux) return; /* display isn't ready yet */ if (u.uswallow) { swallowed(1); return; } if (Underwater && !Is_waterlevel(&u.uz)) { under_water(1); return; } if (u.uburied) { under_ground(1); return; } /* shut down vision */ vision_recalc(2); /* * This routine assumes that cls() does the following: * + fills the physical screen with the symbol for rock * + clears the glyph buffer */ cls(); /* display memory */ for (x = 1; x < COLNO; x++) { lev = &levl[x][0]; for (y = 0; y < ROWNO; y++, lev++) if (lev->glyph != cmap_to_glyph(S_stone)) show_glyph(x,y,lev->glyph); } /* see what is to be seen */ vision_recalc(0); /* overlay with monsters */ see_monsters(); flags.botlx = 1; /* force a redraw of the bottom line */ } /* ========================================================================= */ /* Glyph Buffering (3rd screen) ============================================ */ typedef struct { xchar new; /* perhaps move this bit into the rm strucure. */ int glyph; } gbuf_entry; static gbuf_entry gbuf[ROWNO][COLNO]; static char gbuf_start[ROWNO]; static char gbuf_stop[ROWNO]; /* * Store the glyph in the 3rd screen for later flushing. */ void show_glyph(x,y,glyph) int x, y, glyph; { /* * Check for bad positions and glyphs. */ if (!isok(x, y)) { const char *text; int offset; /* column 0 is invalid, but it's often used as a flag, so ignore it */ if (x == 0) return; /* * This assumes an ordering of the offsets. See display.h for * the definition. */ if (glyph >= GLYPH_WARNING_OFF) { /* a warning */ text = "warning"; offset = glyph - GLYPH_WARNING_OFF; } else if (glyph >= GLYPH_SWALLOW_OFF) { /* swallow border */ text = "swallow border"; offset = glyph - GLYPH_SWALLOW_OFF; } else if (glyph >= GLYPH_ZAP_OFF) { /* zap beam */ text = "zap beam"; offset = glyph - GLYPH_ZAP_OFF; } else if (glyph >= GLYPH_EXPLODE_OFF) { /* explosion */ text = "explosion"; offset = glyph - GLYPH_EXPLODE_OFF; } else if (glyph >= GLYPH_CMAP_OFF) { /* cmap */ text = "cmap_index"; offset = glyph - GLYPH_CMAP_OFF; } else if (glyph >= GLYPH_OBJ_OFF) { /* object */ text = "object"; offset = glyph - GLYPH_OBJ_OFF; } else if (glyph >= GLYPH_RIDDEN_OFF) { /* ridden mon */ text = "ridden mon"; offset = glyph - GLYPH_RIDDEN_OFF; } else if (glyph >= GLYPH_BODY_OFF) { /* a corpse */ text = "corpse"; offset = glyph - GLYPH_BODY_OFF; } else if (glyph >= GLYPH_DETECT_OFF) { /* detected mon */ text = "detected mon"; offset = glyph - GLYPH_DETECT_OFF; } else if (glyph >= GLYPH_INVIS_OFF) { /* invisible mon */ text = "invisible mon"; offset = glyph - GLYPH_INVIS_OFF; } else if (glyph >= GLYPH_PET_OFF) { /* a pet */ text = "pet"; offset = glyph - GLYPH_PET_OFF; } else { /* a monster */ text = "monster"; offset = glyph; } impossible("show_glyph: bad pos %d %d with glyph %d [%s %d].", x, y, glyph, text, offset); return; } if (glyph >= MAX_GLYPH) { impossible("show_glyph: bad glyph %d [max %d] at (%d,%d).", glyph, MAX_GLYPH, x, y); return; } if (gbuf[y][x].glyph != glyph) { gbuf[y][x].glyph = glyph; gbuf[y][x].new = 1; if (gbuf_start[y] > x) gbuf_start[y] = x; if (gbuf_stop[y] < x) gbuf_stop[y] = x; } } /* * Reset the changed glyph borders so that none of the 3rd screen has * changed. */ #define reset_glyph_bbox() \ { \ int i; \ \ for (i = 0; i < ROWNO; i++) { \ gbuf_start[i] = COLNO-1; \ gbuf_stop[i] = 0; \ } \ } static gbuf_entry nul_gbuf = { 0, cmap_to_glyph(S_stone) }; /* * Turn the 3rd screen into stone. */ void clear_glyph_buffer() { register int x, y; register gbuf_entry *gptr; for (y = 0; y < ROWNO; y++) { gptr = &gbuf[y][0]; for (x = COLNO; x; x--) { *gptr++ = nul_gbuf; } } reset_glyph_bbox(); } /* * Assumes that the indicated positions are filled with S_stone glyphs. */ void row_refresh(start,stop,y) int start,stop,y; { register int x; for (x = start; x <= stop; x++) if (gbuf[y][x].glyph != cmap_to_glyph(S_stone)) print_glyph(WIN_MAP,x,y,gbuf[y][x].glyph); } void cls() { display_nhwindow(WIN_MESSAGE, FALSE); /* flush messages */ flags.botlx = 1; /* force update of botl window */ clear_nhwindow(WIN_MAP); /* clear physical screen */ clear_glyph_buffer(); /* this is sort of an extra effort, but OK */ } /* * Synch the third screen with the display. */ void flush_screen(cursor_on_u) int cursor_on_u; { /* Prevent infinite loops on errors: * flush_screen->print_glyph->impossible->pline->flush_screen */ static boolean flushing = 0; static boolean delay_flushing = 0; register int x,y; if (cursor_on_u == -1) delay_flushing = !delay_flushing; if (delay_flushing) return; if (flushing) return; /* if already flushing then return */ flushing = 1; for (y = 0; y < ROWNO; y++) { register gbuf_entry *gptr = &gbuf[y][x = gbuf_start[y]]; for (; x <= gbuf_stop[y]; gptr++, x++) if (gptr->new) { print_glyph(WIN_MAP,x,y,gptr->glyph); gptr->new = 0; } } if (cursor_on_u) curs(WIN_MAP, u.ux,u.uy); /* move cursor to the hero */ display_nhwindow(WIN_MAP, FALSE); reset_glyph_bbox(); flushing = 0; if(flags.botl || flags.botlx) bot(); } /* ========================================================================= */ /* * back_to_glyph() * * Use the information in the rm structure at the given position to create * a glyph of a background. * * I had to add a field in the rm structure (horizontal) so that we knew * if open doors and secret doors were horizontal or vertical. Previously, * the screen symbol had the horizontal/vertical information set at * level generation time. * * I used the 'ladder' field (really doormask) for deciding if stairwells * were up or down. I didn't want to check the upstairs and dnstairs * variables. */ int back_to_glyph(x,y) xchar x,y; { int idx; struct rm *ptr = &(levl[x][y]); switch (ptr->typ) { case SCORR: case STONE: idx = level.flags.arboreal ? S_tree : S_stone; break; case ROOM: idx = S_room; break; case CORR: idx = (ptr->waslit || flags.lit_corridor) ? S_litcorr : S_corr; break; case HWALL: case VWALL: case TLCORNER: case TRCORNER: case BLCORNER: case BRCORNER: case CROSSWALL: case TUWALL: case TDWALL: case TLWALL: case TRWALL: case SDOOR: idx = ptr->seenv ? wall_angle(ptr) : S_stone; break; case DOOR: if (ptr->doormask) { if (ptr->doormask & D_BROKEN) idx = S_ndoor; else if (ptr->doormask & D_ISOPEN) idx = (ptr->horizontal) ? S_hodoor : S_vodoor; else /* else is closed */ idx = (ptr->horizontal) ? S_hcdoor : S_vcdoor; } else idx = S_ndoor; break; case IRONBARS: idx = S_bars; break; case TREE: idx = S_tree; break; case POOL: case MOAT: idx = S_pool; break; case STAIRS: idx = (ptr->ladder & LA_DOWN) ? S_dnstair : S_upstair; break; case LADDER: idx = (ptr->ladder & LA_DOWN) ? S_dnladder : S_upladder; break; case FOUNTAIN: idx = S_fountain; break; case SINK: idx = S_sink; break; case ALTAR: idx = S_altar; break; case GRAVE: idx = S_grave; break; case THRONE: idx = S_throne; break; case LAVAPOOL: idx = S_lava; break; case ICE: idx = S_ice; break; case AIR: idx = S_air; break; case CLOUD: idx = S_cloud; break; case WATER: idx = S_water; break; case DBWALL: idx = (ptr->horizontal) ? S_hcdbridge : S_vcdbridge; break; case DRAWBRIDGE_UP: switch(ptr->drawbridgemask & DB_UNDER) { case DB_MOAT: idx = S_pool; break; case DB_LAVA: idx = S_lava; break; case DB_ICE: idx = S_ice; break; case DB_FLOOR: idx = S_room; break; default: impossible("Strange db-under: %d", ptr->drawbridgemask & DB_UNDER); idx = S_room; /* something is better than nothing */ break; } break; case DRAWBRIDGE_DOWN: idx = (ptr->horizontal) ? S_hodbridge : S_vodbridge; break; default: impossible("back_to_glyph: unknown level type [ = %d ]",ptr->typ); idx = S_room; break; } return cmap_to_glyph(idx); } /* * swallow_to_glyph() * * Convert a monster number and a swallow location into the correct glyph. * If you don't want a patchwork monster while hallucinating, decide on * a random monster in swallowed() and don't use what_mon() here. */ STATIC_OVL int swallow_to_glyph(mnum, loc) int mnum; int loc; { if (loc < S_sw_tl || S_sw_br < loc) { impossible("swallow_to_glyph: bad swallow location"); loc = S_sw_br; } return ((int) (what_mon(mnum)<<3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF; } /* * zapdir_to_glyph() * * Change the given zap direction and beam type into a glyph. Each beam * type has four glyphs, one for each of the symbols below. The order of * the zap symbols [0-3] as defined in rm.h are: * * | S_vbeam ( 0, 1) or ( 0,-1) * - S_hbeam ( 1, 0) or (-1, 0) * \ S_lslant ( 1, 1) or (-1,-1) * / S_rslant (-1, 1) or ( 1,-1) */ int zapdir_to_glyph(dx, dy, beam_type) register int dx, dy; int beam_type; { if (beam_type >= NUM_ZAP) { impossible("zapdir_to_glyph: illegal beam type"); beam_type = 0; } dx = (dx == dy) ? 2 : (dx && dy) ? 3 : dx ? 1 : 0; return ((int) ((beam_type << 2) | dx)) + GLYPH_ZAP_OFF; } /* * Utility routine for dowhatis() used to find out the glyph displayed at * the location. This isn't necessarily the same as the glyph in the levl * structure, so we must check the "third screen". */ int glyph_at(x, y) xchar x,y; { if(x < 0 || y < 0 || x >= COLNO || y >= ROWNO) return cmap_to_glyph(S_room); /* XXX */ return gbuf[y][x].glyph; } /* ------------------------------------------------------------------------- */ /* Wall Angle -------------------------------------------------------------- */ /*#define WA_VERBOSE*/ /* give (x,y) locations for all "bad" spots */ #ifdef WA_VERBOSE static const char *FDECL(type_to_name, (int)); static void FDECL(error4, (int,int,int,int,int,int)); static int bad_count[MAX_TYPE]; /* count of positions flagged as bad */ static const char *type_names[MAX_TYPE] = { "STONE", "VWALL", "HWALL", "TLCORNER", "TRCORNER", "BLCORNER", "BRCORNER", "CROSSWALL", "TUWALL", "TDWALL", "TLWALL", "TRWALL", "DBWALL", "SDOOR", "SCORR", "POOL", "MOAT", "WATER", "DRAWBRIDGE_UP","LAVAPOOL", "DOOR", "CORR", "ROOM", "STAIRS", "LADDER", "FOUNTAIN", "THRONE", "SINK", "ALTAR", "ICE", "DRAWBRIDGE_DOWN","AIR", "CLOUD" }; static const char * type_to_name(type) int type; { return (type < 0 || type > MAX_TYPE) ? "unknown" : type_names[type]; } static void error4(x, y, a, b, c, dd) int x, y, a, b, c, dd; { pline("set_wall_state: %s @ (%d,%d) %s%s%s%s", type_to_name(levl[x][y].typ), x, y, a ? "1":"", b ? "2":"", c ? "3":"", dd ? "4":""); bad_count[levl[x][y].typ]++; } #endif /* WA_VERBOSE */ /* * Return 'which' if position is implies an unfinshed exterior. Return * zero otherwise. Unfinished implies outer area is rock or a corridor. * * Things that are ambigious: lava */ STATIC_OVL int check_pos(x, y, which) int x, y, which; { int type; if (!isok(x,y)) return which; type = levl[x][y].typ; if (IS_ROCK(type) || type == CORR || type == SCORR) return which; return 0; } /* Return TRUE if more than one is non-zero. */ /*ARGSUSED*/ #ifdef WA_VERBOSE STATIC_OVL boolean more_than_one(x, y, a, b, c) int x, y, a, b, c; { if ((a && (b|c)) || (b && (a|c)) || (c && (a|b))) { error4(x,y,a,b,c,0); return TRUE; } return FALSE; } #else #define more_than_one(x, y, a, b, c) (((a) && ((b)|(c))) || ((b) && ((a)|(c))) || ((c) && ((a)|(b)))) #endif /* Return the wall mode for a T wall. */ STATIC_OVL int set_twall(x0,y0, x1,y1, x2,y2, x3,y3) int x0,y0, x1,y1, x2,y2, x3,y3; { int wmode, is_1, is_2, is_3; is_1 = check_pos(x1, y1, WM_T_LONG); is_2 = check_pos(x2, y2, WM_T_BL); is_3 = check_pos(x3, y3, WM_T_BR); if (more_than_one(x0, y0, is_1, is_2, is_3)) { wmode = 0; } else { wmode = is_1 + is_2 + is_3; } return wmode; } /* Return wall mode for a horizontal or vertical wall. */ STATIC_OVL int set_wall(x, y, horiz) int x, y, horiz; { int wmode, is_1, is_2; if (horiz) { is_1 = check_pos(x,y-1, WM_W_TOP); is_2 = check_pos(x,y+1, WM_W_BOTTOM); } else { is_1 = check_pos(x-1,y, WM_W_LEFT); is_2 = check_pos(x+1,y, WM_W_RIGHT); } if (more_than_one(x, y, is_1, is_2, 0)) { wmode = 0; } else { wmode = is_1 + is_2; } return wmode; } /* Return a wall mode for a corner wall. (x4,y4) is the "inner" position. */ STATIC_OVL int set_corn(x1,y1, x2,y2, x3,y3, x4,y4) int x1, y1, x2, y2, x3, y3, x4, y4; { int wmode, is_1, is_2, is_3, is_4; is_1 = check_pos(x1, y1, 1); is_2 = check_pos(x2, y2, 1); is_3 = check_pos(x3, y3, 1); is_4 = check_pos(x4, y4, 1); /* inner location */ /* * All 4 should not be true. So if the inner location is rock, * use it. If all of the outer 3 are true, use outer. We currently * can't cover the case where only part of the outer is rock, so * we just say that all the walls are finished (if not overridden * by the inner section). */ if (is_4) { wmode = WM_C_INNER; } else if (is_1 && is_2 && is_3) wmode = WM_C_OUTER; else wmode = 0; /* finished walls on all sides */ return wmode; } /* Return mode for a crosswall. */ STATIC_OVL int set_crosswall(x, y) int x, y; { int wmode, is_1, is_2, is_3, is_4; is_1 = check_pos(x-1, y-1, 1); is_2 = check_pos(x+1, y-1, 1); is_3 = check_pos(x+1, y+1, 1); is_4 = check_pos(x-1, y+1, 1); wmode = is_1+is_2+is_3+is_4; if (wmode > 1) { if (is_1 && is_3 && (is_2+is_4 == 0)) { wmode = WM_X_TLBR; } else if (is_2 && is_4 && (is_1+is_3 == 0)) { wmode = WM_X_BLTR; } else { #ifdef WA_VERBOSE error4(x,y,is_1,is_2,is_3,is_4); #endif wmode = 0; } } else if (is_1) wmode = WM_X_TL; else if (is_2) wmode = WM_X_TR; else if (is_3) wmode = WM_X_BR; else if (is_4) wmode = WM_X_BL; return wmode; } /* Called from mklev. Scan the level and set the wall modes. */ void set_wall_state() { int x, y; int wmode; struct rm *lev; #ifdef WA_VERBOSE for (x = 0; x < MAX_TYPE; x++) bad_count[x] = 0; #endif for (x = 0; x < COLNO; x++) for (lev = &levl[x][0], y = 0; y < ROWNO; y++, lev++) { switch (lev->typ) { case SDOOR: wmode = set_wall(x, y, (int) lev->horizontal); break; case VWALL: wmode = set_wall(x, y, 0); break; case HWALL: wmode = set_wall(x, y, 1); break; case TDWALL: wmode = set_twall(x,y, x,y-1, x-1,y+1, x+1,y+1); break; case TUWALL: wmode = set_twall(x,y, x,y+1, x+1,y-1, x-1,y-1); break; case TLWALL: wmode = set_twall(x,y, x+1,y, x-1,y-1, x-1,y+1); break; case TRWALL: wmode = set_twall(x,y, x-1,y, x+1,y+1, x+1,y-1); break; case TLCORNER: wmode = set_corn(x-1,y-1, x,y-1, x-1,y, x+1,y+1); break; case TRCORNER: wmode = set_corn(x,y-1, x+1,y-1, x+1,y, x-1,y+1); break; case BLCORNER: wmode = set_corn(x,y+1, x-1,y+1, x-1,y, x+1,y-1); break; case BRCORNER: wmode = set_corn(x+1,y, x+1,y+1, x,y+1, x-1,y-1); break; case CROSSWALL: wmode = set_crosswall(x, y); break; default: wmode = -1; /* don't set wall info */ break; } if (wmode >= 0) lev->wall_info = (lev->wall_info & ~WM_MASK) | wmode; } #ifdef WA_VERBOSE /* check if any bad positions found */ for (x = y = 0; x < MAX_TYPE; x++) if (bad_count[x]) { if (y == 0) { y = 1; /* only print once */ pline("set_wall_type: wall mode problems with: "); } pline("%s %d;", type_names[x], bad_count[x]); } #endif /* WA_VERBOSE */ } /* ------------------------------------------------------------------------- */ /* This matrix is used here and in vision.c. */ unsigned char seenv_matrix[3][3] = { {SV2, SV1, SV0}, {SV3, SVALL, SV7}, {SV4, SV5, SV6} }; #define sign(z) ((z) < 0 ? -1 : ((z) > 0 ? 1 : 0)) /* Set the seen vector of lev as if seen from (x0,y0) to (x,y). */ STATIC_OVL void set_seenv(lev, x0, y0, x, y) struct rm *lev; int x0, y0, x, y; /* from, to */ { int dx = x-x0, dy = y0-y; lev->seenv |= seenv_matrix[sign(dy)+1][sign(dx)+1]; } /* ------------------------------------------------------------------------- */ /* T wall types, one for each row in wall_matrix[][]. */ #define T_d 0 #define T_l 1 #define T_u 2 #define T_r 3 /* * These are the column names of wall_matrix[][]. They are the "results" * of a tdwall pattern match. All T walls are rotated so they become * a tdwall. Then we do a single pattern match, but return the * correct result for the original wall by using different rows for * each of the wall types. */ #define T_stone 0 #define T_tlcorn 1 #define T_trcorn 2 #define T_hwall 3 #define T_tdwall 4 static const int wall_matrix[4][5] = { { S_stone, S_tlcorn, S_trcorn, S_hwall, S_tdwall }, /* tdwall */ { S_stone, S_trcorn, S_brcorn, S_vwall, S_tlwall }, /* tlwall */ { S_stone, S_brcorn, S_blcorn, S_hwall, S_tuwall }, /* tuwall */ { S_stone, S_blcorn, S_tlcorn, S_vwall, S_trwall }, /* trwall */ }; /* Cross wall types, one for each "solid" quarter. Rows of cross_matrix[][]. */ #define C_bl 0 #define C_tl 1 #define C_tr 2 #define C_br 3 /* * These are the column names for cross_matrix[][]. They express results * in C_br (bottom right) terms. All crosswalls with a single solid * quarter are rotated so the solid section is at the bottom right. * We pattern match on that, but return the correct result depending * on which row we'ere looking at. */ #define C_trcorn 0 #define C_brcorn 1 #define C_blcorn 2 #define C_tlwall 3 #define C_tuwall 4 #define C_crwall 5 static const int cross_matrix[4][6] = { { S_brcorn, S_blcorn, S_tlcorn, S_tuwall, S_trwall, S_crwall }, { S_blcorn, S_tlcorn, S_trcorn, S_trwall, S_tdwall, S_crwall }, { S_tlcorn, S_trcorn, S_brcorn, S_tdwall, S_tlwall, S_crwall }, { S_trcorn, S_brcorn, S_blcorn, S_tlwall, S_tuwall, S_crwall }, }; /* Print out a T wall warning and all interesting info. */ STATIC_OVL void t_warn(lev) struct rm *lev; { static const char warn_str[] = "wall_angle: %s: case %d: seenv = 0x%x"; const char *wname; if (lev->typ == TUWALL) wname = "tuwall"; else if (lev->typ == TLWALL) wname = "tlwall"; else if (lev->typ == TRWALL) wname = "trwall"; else if (lev->typ == TDWALL) wname = "tdwall"; else wname = "unknown"; impossible(warn_str, wname, lev->wall_info & WM_MASK, (unsigned int) lev->seenv); } /* * Return the correct graphics character index using wall type, wall mode, * and the seen vector. It is expected that seenv is non zero. * * All T-wall vectors are rotated to be TDWALL. All single crosswall * blocks are rotated to bottom right. All double crosswall are rotated * to W_X_BLTR. All results are converted back. * * The only way to understand this is to take out pen and paper and * draw diagrams. See rm.h for more details on the wall modes and * seen vector (SV). */ STATIC_OVL int wall_angle(lev) struct rm *lev; { register unsigned int seenv = lev->seenv & 0xff; const int *row; int col, idx; #define only(sv, bits) (((sv) & (bits)) && ! ((sv) & ~(bits))) switch (lev->typ) { case TUWALL: row = wall_matrix[T_u]; seenv = (seenv >> 4 | seenv << 4) & 0xff;/* rotate to tdwall */ goto do_twall; case TLWALL: row = wall_matrix[T_l]; seenv = (seenv >> 2 | seenv << 6) & 0xff;/* rotate to tdwall */ goto do_twall; case TRWALL: row = wall_matrix[T_r]; seenv = (seenv >> 6 | seenv << 2) & 0xff;/* rotate to tdwall */ goto do_twall; case TDWALL: row = wall_matrix[T_d]; do_twall: switch (lev->wall_info & WM_MASK) { case 0: if (seenv == SV4) { col = T_tlcorn; } else if (seenv == SV6) { col = T_trcorn; } else if (seenv & (SV3|SV5|SV7) || ((seenv & SV4) && (seenv & SV6))) { col = T_tdwall; } else if (seenv & (SV0|SV1|SV2)) { col = (seenv & (SV4|SV6) ? T_tdwall : T_hwall); } else { t_warn(lev); col = T_stone; } break; case WM_T_LONG: if (seenv & (SV3|SV4) && !(seenv & (SV5|SV6|SV7))) { col = T_tlcorn; } else if (seenv&(SV6|SV7) && !(seenv&(SV3|SV4|SV5))) { col = T_trcorn; } else if ((seenv & SV5) || ((seenv & (SV3|SV4)) && (seenv & (SV6|SV7)))) { col = T_tdwall; } else { /* only SV0|SV1|SV2 */ if (! only(seenv, SV0|SV1|SV2) ) t_warn(lev); col = T_stone; } break; case WM_T_BL: #if 0 /* older method, fixed */ if (only(seenv, SV4|SV5)) { col = T_tlcorn; } else if ((seenv & (SV0|SV1|SV2)) && only(seenv, SV0|SV1|SV2|SV6|SV7)) { col = T_hwall; } else if (seenv & SV3 || ((seenv & (SV0|SV1|SV2)) && (seenv & (SV4|SV5)))) { col = T_tdwall; } else { if (seenv != SV6) t_warn(lev); col = T_stone; } #endif /* 0 */ if (only(seenv, SV4|SV5)) col = T_tlcorn; else if ((seenv & (SV0|SV1|SV2|SV7)) && !(seenv & (SV3|SV4|SV5))) col = T_hwall; else if (only(seenv, SV6)) col = T_stone; else col = T_tdwall; break; case WM_T_BR: #if 0 /* older method, fixed */ if (only(seenv, SV5|SV6)) { col = T_trcorn; } else if ((seenv & (SV0|SV1|SV2)) && only(seenv, SV0|SV1|SV2|SV3|SV4)) { col = T_hwall; } else if (seenv & SV7 || ((seenv & (SV0|SV1|SV2)) && (seenv & (SV5|SV6)))) { col = T_tdwall; } else { if (seenv != SV4) t_warn(lev); col = T_stone; } #endif /* 0 */ if (only(seenv, SV5|SV6)) col = T_trcorn; else if ((seenv & (SV0|SV1|SV2|SV3)) && !(seenv & (SV5|SV6|SV7))) col = T_hwall; else if (only(seenv, SV4)) col = T_stone; else col = T_tdwall; break; default: impossible("wall_angle: unknown T wall mode %d", lev->wall_info & WM_MASK); col = T_stone; break; } idx = row[col]; break; case SDOOR: if (lev->horizontal) goto horiz; /* fall through */ case VWALL: switch (lev->wall_info & WM_MASK) { case 0: idx = seenv ? S_vwall : S_stone; break; case 1: idx = seenv & (SV1|SV2|SV3|SV4|SV5) ? S_vwall : S_stone; break; case 2: idx = seenv & (SV0|SV1|SV5|SV6|SV7) ? S_vwall : S_stone; break; default: impossible("wall_angle: unknown vwall mode %d", lev->wall_info & WM_MASK); idx = S_stone; break; } break; case HWALL: horiz: switch (lev->wall_info & WM_MASK) { case 0: idx = seenv ? S_hwall : S_stone; break; case 1: idx = seenv & (SV3|SV4|SV5|SV6|SV7) ? S_hwall : S_stone; break; case 2: idx = seenv & (SV0|SV1|SV2|SV3|SV7) ? S_hwall : S_stone; break; default: impossible("wall_angle: unknown hwall mode %d", lev->wall_info & WM_MASK); idx = S_stone; break; } break; #define set_corner(idx, lev, which, outer, inner, name) \ switch ((lev)->wall_info & WM_MASK) { \ case 0: idx = which; break; \ case WM_C_OUTER: idx = seenv & (outer) ? which : S_stone; break; \ case WM_C_INNER: idx = seenv & ~(inner) ? which : S_stone; break; \ default: \ impossible("wall_angle: unknown %s mode %d", name, \ (lev)->wall_info & WM_MASK); \ idx = S_stone; \ break; \ } case TLCORNER: set_corner(idx, lev, S_tlcorn, (SV3|SV4|SV5), SV4, "tlcorn"); break; case TRCORNER: set_corner(idx, lev, S_trcorn, (SV5|SV6|SV7), SV6, "trcorn"); break; case BLCORNER: set_corner(idx, lev, S_blcorn, (SV1|SV2|SV3), SV2, "blcorn"); break; case BRCORNER: set_corner(idx, lev, S_brcorn, (SV7|SV0|SV1), SV0, "brcorn"); break; case CROSSWALL: switch (lev->wall_info & WM_MASK) { case 0: if (seenv == SV0) idx = S_brcorn; else if (seenv == SV2) idx = S_blcorn; else if (seenv == SV4) idx = S_tlcorn; else if (seenv == SV6) idx = S_trcorn; else if (!(seenv & ~(SV0|SV1|SV2)) && (seenv & SV1 || seenv == (SV0|SV2))) idx = S_tuwall; else if (!(seenv & ~(SV2|SV3|SV4)) && (seenv & SV3 || seenv == (SV2|SV4))) idx = S_trwall; else if (!(seenv & ~(SV4|SV5|SV6)) && (seenv & SV5 || seenv == (SV4|SV6))) idx = S_tdwall; else if (!(seenv & ~(SV0|SV6|SV7)) && (seenv & SV7 || seenv == (SV0|SV6))) idx = S_tlwall; else idx = S_crwall; break; case WM_X_TL: row = cross_matrix[C_tl]; seenv = (seenv >> 4 | seenv << 4) & 0xff; goto do_crwall; case WM_X_TR: row = cross_matrix[C_tr]; seenv = (seenv >> 6 | seenv << 2) & 0xff; goto do_crwall; case WM_X_BL: row = cross_matrix[C_bl]; seenv = (seenv >> 2 | seenv << 6) & 0xff; goto do_crwall; case WM_X_BR: row = cross_matrix[C_br]; do_crwall: if (seenv == SV4) idx = S_stone; else { seenv = seenv & ~SV4; /* strip SV4 */ if (seenv == SV0) { col = C_brcorn; } else if (seenv & (SV2|SV3)) { if (seenv & (SV5|SV6|SV7)) col = C_crwall; else if (seenv & (SV0|SV1)) col = C_tuwall; else col = C_blcorn; } else if (seenv & (SV5|SV6)) { if (seenv & (SV1|SV2|SV3)) col = C_crwall; else if (seenv & (SV0|SV7)) col = C_tlwall; else col = C_trcorn; } else if (seenv & SV1) { col = seenv & SV7 ? C_crwall : C_tuwall; } else if (seenv & SV7) { col = seenv & SV1 ? C_crwall : C_tlwall; } else { impossible( "wall_angle: bottom of crwall check"); col = C_crwall; } idx = row[col]; } break; case WM_X_TLBR: if ( only(seenv, SV1|SV2|SV3) ) idx = S_blcorn; else if ( only(seenv, SV5|SV6|SV7) ) idx = S_trcorn; else if ( only(seenv, SV0|SV4) ) idx = S_stone; else idx = S_crwall; break; case WM_X_BLTR: if ( only(seenv, SV0|SV1|SV7) ) idx = S_brcorn; else if ( only(seenv, SV3|SV4|SV5) ) idx = S_tlcorn; else if ( only(seenv, SV2|SV6) ) idx = S_stone; else idx = S_crwall; break; default: impossible("wall_angle: unknown crosswall mode"); idx = S_stone; break; } break; default: impossible("wall_angle: unexpected wall type %d", lev->typ); idx = S_stone; } return idx; } /*display.c*/ nethack-3.4.3/src/dlb.c0100644000000000000000000003051407764735041013351 0ustar rootroot/* SCCS Id: @(#)dlb.c 3.4 1997/07/29 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #include "dlb.h" #ifdef __DJGPP__ #include #endif #define DATAPREFIX 4 #ifdef DLB /* * Data librarian. Present a STDIO-like interface to NetHack while * multiplexing on one or more "data libraries". If a file is not found * in a given library, look for it outside the libraries. */ typedef struct dlb_procs { boolean NDECL((*dlb_init_proc)); void NDECL((*dlb_cleanup_proc)); boolean FDECL((*dlb_fopen_proc), (DLB_P,const char *,const char *)); int FDECL((*dlb_fclose_proc), (DLB_P)); int FDECL((*dlb_fread_proc), (char *,int,int,DLB_P)); int FDECL((*dlb_fseek_proc), (DLB_P,long,int)); char *FDECL((*dlb_fgets_proc), (char *,int,DLB_P)); int FDECL((*dlb_fgetc_proc), (DLB_P)); long FDECL((*dlb_ftell_proc), (DLB_P)); } dlb_procs_t; /* without extern.h via hack.h, these haven't been declared for us */ extern FILE *FDECL(fopen_datafile, (const char *,const char *,int)); #ifdef DLBLIB /* * Library Implementation: * * When initialized, we open all library files and read in their tables * of contents. The library files stay open all the time. When * a open is requested, the libraries' directories are searched. If * successful, we return a descriptor that contains the library, file * size, and current file mark. This descriptor is used for all * successive calls. * * The ability to open more than one library is supported but used * only in the Amiga port (the second library holds the sound files). * For Unix, the idea would be to split the NetHack library * into text and binary parts, where the text version could be shared. */ #define MAX_LIBS 4 static library dlb_libs[MAX_LIBS]; static boolean FDECL(readlibdir,(library *lp)); static boolean FDECL(find_file,(const char *name, library **lib, long *startp, long *sizep)); static boolean NDECL(lib_dlb_init); static void NDECL(lib_dlb_cleanup); static boolean FDECL(lib_dlb_fopen,(dlb *, const char *, const char *)); static int FDECL(lib_dlb_fclose,(dlb *)); static int FDECL(lib_dlb_fread,(char *, int, int, dlb *)); static int FDECL(lib_dlb_fseek,(dlb *, long, int)); static char *FDECL(lib_dlb_fgets,(char *, int, dlb *)); static int FDECL(lib_dlb_fgetc,(dlb *)); static long FDECL(lib_dlb_ftell,(dlb *)); /* not static because shared with dlb_main.c */ boolean FDECL(open_library,(const char *lib_name, library *lp)); void FDECL(close_library,(library *lp)); /* without extern.h via hack.h, these haven't been declared for us */ extern char *FDECL(eos, (char *)); /* * Read the directory out of the library. Return 1 if successful, * 0 if it failed. * * NOTE: An improvement of the file structure should be the file * size as part of the directory entry or perhaps in place of the * offset -- the offset can be calculated by a running tally of * the sizes. * * Library file structure: * * HEADER: * %3ld library FORMAT revision (currently rev 1) * %1c space * %8ld # of files in archive (includes 1 for directory) * %1c space * %8ld size of allocation for string space for directory names * %1c space * %8ld library offset - sanity check - lseek target for start of first file * %1c space * %8ld size - sanity check - byte size of complete archive file * * followed by one DIRECTORY entry for each file in the archive, including * the directory itself: * %1c handling information (compression, etc.) Always ' ' in rev 1. * %s file name * %1c space * %8ld offset in archive file of start of this file * %c newline * * followed by the contents of the files */ #define DLB_MIN_VERS 1 /* min library version readable by this code */ #define DLB_MAX_VERS 1 /* max library version readable by this code */ /* * Read the directory from the library file. This will allocate and * fill in our globals. The file pointer is reset back to position * zero. If any part fails, leave nothing that needs to be deallocated. * * Return TRUE on success, FALSE on failure. */ static boolean readlibdir(lp) library *lp; /* library pointer to fill in */ { int i; char *sp; long liboffset, totalsize; if (fscanf(lp->fdata, "%ld %ld %ld %ld %ld\n", &lp->rev,&lp->nentries,&lp->strsize,&liboffset,&totalsize) != 5) return FALSE; if (lp->rev > DLB_MAX_VERS || lp->rev < DLB_MIN_VERS) return FALSE; lp->dir = (libdir *) alloc(lp->nentries * sizeof(libdir)); lp->sspace = (char *) alloc(lp->strsize); /* read in each directory entry */ for (i = 0, sp = lp->sspace; i < lp->nentries; i++) { lp->dir[i].fname = sp; if (fscanf(lp->fdata, "%c%s %ld\n", &lp->dir[i].handling, sp, &lp->dir[i].foffset) != 3) { free((genericptr_t) lp->dir); free((genericptr_t) lp->sspace); lp->dir = (libdir *) 0; lp->sspace = (char *) 0; return FALSE; } sp = eos(sp) + 1; } /* calculate file sizes using offset information */ for (i = 0; i < lp->nentries; i++) { if (i == lp->nentries - 1) lp->dir[i].fsize = totalsize - lp->dir[i].foffset; else lp->dir[i].fsize = lp->dir[i+1].foffset - lp->dir[i].foffset; } (void) fseek(lp->fdata, 0L, SEEK_SET); /* reset back to zero */ lp->fmark = 0; return TRUE; } /* * Look for the file in our directory structure. Return 1 if successful, * 0 if not found. Fill in the size and starting position. */ static boolean find_file(name, lib, startp, sizep) const char *name; library **lib; long *startp, *sizep; { int i, j; library *lp; for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) { lp = &dlb_libs[i]; for (j = 0; j < lp->nentries; j++) { if (FILENAME_CMP(name, lp->dir[j].fname) == 0) { *lib = lp; *startp = lp->dir[j].foffset; *sizep = lp->dir[j].fsize; return TRUE; } } } *lib = (library *) 0; *startp = *sizep = 0; return FALSE; } /* * Open the library of the given name and fill in the given library * structure. Return TRUE if successful, FALSE otherwise. */ boolean open_library(lib_name, lp) const char *lib_name; library *lp; { boolean status = FALSE; lp->fdata = fopen_datafile(lib_name, RDBMODE, DATAPREFIX); if (lp->fdata) { if (readlibdir(lp)) { status = TRUE; } else { (void) fclose(lp->fdata); lp->fdata = (FILE *) 0; } } return status; } void close_library(lp) library *lp; { (void) fclose(lp->fdata); free((genericptr_t) lp->dir); free((genericptr_t) lp->sspace); (void) memset((char *)lp, 0, sizeof(library)); } /* * Open the library file once using stdio. Keep it open, but * keep track of the file position. */ static boolean lib_dlb_init() { /* zero out array */ (void) memset((char *)&dlb_libs[0], 0, sizeof(dlb_libs)); /* To open more than one library, add open library calls here. */ if (!open_library(DLBFILE, &dlb_libs[0])) return FALSE; #ifdef DLBFILE2 if (!open_library(DLBFILE2, &dlb_libs[1])) { close_library(&dlb_libs[0]); return FALSE; } #endif return TRUE; } static void lib_dlb_cleanup() { int i; /* close the data file(s) */ for (i = 0; i < MAX_LIBS && dlb_libs[i].fdata; i++) close_library(&dlb_libs[i]); } static boolean lib_dlb_fopen(dp, name, mode) dlb *dp; const char *name, *mode; { long start, size; library *lp; /* look up file in directory */ if (find_file(name, &lp, &start, &size)) { dp->lib = lp; dp->start = start; dp->size = size; dp->mark = 0; return TRUE; } return FALSE; /* failed */ } static int lib_dlb_fclose(dp) dlb *dp; { /* nothing needs to be done */ return 0; } static int lib_dlb_fread(buf, size, quan, dp) char *buf; int size, quan; dlb *dp; { long pos, nread, nbytes; /* make sure we don't read into the next file */ if ((dp->size - dp->mark) < (size * quan)) quan = (dp->size - dp->mark) / size; if (quan == 0) return 0; pos = dp->start + dp->mark; if (dp->lib->fmark != pos) { fseek(dp->lib->fdata, pos, SEEK_SET); /* check for error??? */ dp->lib->fmark = pos; } nread = fread(buf, size, quan, dp->lib->fdata); nbytes = nread * size; dp->mark += nbytes; dp->lib->fmark += nbytes; return nread; } static int lib_dlb_fseek(dp, pos, whence) dlb *dp; long pos; int whence; { long curpos; switch (whence) { case SEEK_CUR: curpos = dp->mark + pos; break; case SEEK_END: curpos = dp->size - pos; break; default: /* set */ curpos = pos; break; } if (curpos < 0) curpos = 0; if (curpos > dp->size) curpos = dp->size; dp->mark = curpos; return 0; } static char * lib_dlb_fgets(buf, len, dp) char *buf; int len; dlb *dp; { int i; char *bp, c = 0; if (len <= 0) return buf; /* sanity check */ /* return NULL on EOF */ if (dp->mark >= dp->size) return (char *) 0; len--; /* save room for null */ for (i = 0, bp = buf; i < len && dp->mark < dp->size && c != '\n'; i++, bp++) { if (dlb_fread(bp, 1, 1, dp) <= 0) break; /* EOF or error */ c = *bp; } *bp = '\0'; #if defined(MSDOS) || defined(WIN32) if ((bp = index(buf, '\r')) != 0) { *bp++ = '\n'; *bp = '\0'; } #endif return buf; } static int lib_dlb_fgetc(dp) dlb *dp; { char c; if (lib_dlb_fread(&c, 1, 1, dp) != 1) return EOF; return (int) c; } static long lib_dlb_ftell(dp) dlb *dp; { return dp->mark; } const dlb_procs_t lib_dlb_procs = { lib_dlb_init, lib_dlb_cleanup, lib_dlb_fopen, lib_dlb_fclose, lib_dlb_fread, lib_dlb_fseek, lib_dlb_fgets, lib_dlb_fgetc, lib_dlb_ftell }; #endif /* DLBLIB */ #ifdef DLBRSRC const dlb_procs_t rsrc_dlb_procs = { rsrc_dlb_init, rsrc_dlb_cleanup, rsrc_dlb_fopen, rsrc_dlb_fclose, rsrc_dlb_fread, rsrc_dlb_fseek, rsrc_dlb_fgets, rsrc_dlb_fgetc, rsrc_dlb_ftell }; #endif /* Global wrapper functions ------------------------------------------------ */ #define do_dlb_init (*dlb_procs->dlb_init_proc) #define do_dlb_cleanup (*dlb_procs->dlb_cleanup_proc) #define do_dlb_fopen (*dlb_procs->dlb_fopen_proc) #define do_dlb_fclose (*dlb_procs->dlb_fclose_proc) #define do_dlb_fread (*dlb_procs->dlb_fread_proc) #define do_dlb_fseek (*dlb_procs->dlb_fseek_proc) #define do_dlb_fgets (*dlb_procs->dlb_fgets_proc) #define do_dlb_fgetc (*dlb_procs->dlb_fgetc_proc) #define do_dlb_ftell (*dlb_procs->dlb_ftell_proc) static const dlb_procs_t *dlb_procs; static boolean dlb_initialized = FALSE; boolean dlb_init() { if (!dlb_initialized) { #ifdef DLBLIB dlb_procs = &lib_dlb_procs; #endif #ifdef DLBRSRC dlb_procs = &rsrc_dlb_procs; #endif if (dlb_procs) dlb_initialized = do_dlb_init(); } return dlb_initialized; } void dlb_cleanup() { if (dlb_initialized) { do_dlb_cleanup(); dlb_initialized = FALSE; } } dlb * dlb_fopen(name, mode) const char *name, *mode; { FILE *fp; dlb *dp; if (!dlb_initialized) return (dlb *) 0; dp = (dlb *) alloc(sizeof(dlb)); if (do_dlb_fopen(dp, name, mode)) dp->fp = (FILE *) 0; else if ((fp = fopen_datafile(name, mode, DATAPREFIX)) != 0) dp->fp = fp; else { /* can't find anything */ free((genericptr_t) dp); dp = (dlb *) 0; } return dp; } int dlb_fclose(dp) dlb *dp; { int ret = 0; if (dlb_initialized) { if (dp->fp) ret = fclose(dp->fp); else ret = do_dlb_fclose(dp); free((genericptr_t) dp); } return ret; } int dlb_fread(buf, size, quan, dp) char *buf; int size, quan; dlb *dp; { if (!dlb_initialized || size <= 0 || quan <= 0) return 0; if (dp->fp) return (int) fread(buf, size, quan, dp->fp); return do_dlb_fread(buf, size, quan, dp); } int dlb_fseek(dp, pos, whence) dlb *dp; long pos; int whence; { if (!dlb_initialized) return EOF; if (dp->fp) return fseek(dp->fp, pos, whence); return do_dlb_fseek(dp, pos, whence); } char * dlb_fgets(buf, len, dp) char *buf; int len; dlb *dp; { if (!dlb_initialized) return (char *) 0; if (dp->fp) return fgets(buf, len, dp->fp); return do_dlb_fgets(buf, len, dp); } int dlb_fgetc(dp) dlb *dp; { if (!dlb_initialized) return EOF; if (dp->fp) return fgetc(dp->fp); return do_dlb_fgetc(dp); } long dlb_ftell(dp) dlb *dp; { if (!dlb_initialized) return 0; if (dp->fp) return ftell(dp->fp); return do_dlb_ftell(dp); } #endif /* DLB */ /*dlb.c*/ nethack-3.4.3/src/do.c0100644000000000000000000013167307764735041013222 0ustar rootroot/* SCCS Id: @(#)do.c 3.4 2003/12/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Contains code for 'd', 'D' (drop), '>', '<' (up, down) */ #include "hack.h" #include "lev.h" #ifdef SINKS # ifdef OVLB STATIC_DCL void FDECL(trycall, (struct obj *)); # endif /* OVLB */ STATIC_DCL void FDECL(dosinkring, (struct obj *)); #endif /* SINKS */ STATIC_PTR int FDECL(drop, (struct obj *)); STATIC_PTR int NDECL(wipeoff); #ifdef OVL0 STATIC_DCL int FDECL(menu_drop, (int)); #endif #ifdef OVL2 STATIC_DCL int NDECL(currentlevel_rewrite); STATIC_DCL void NDECL(final_level); /* static boolean FDECL(badspot, (XCHAR_P,XCHAR_P)); */ #endif #ifdef OVLB static NEARDATA const char drop_types[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, 0 }; /* 'd' command: drop one inventory item */ int dodrop() { #ifndef GOLDOBJ int result, i = (invent || u.ugold) ? 0 : (SIZE(drop_types) - 1); #else int result, i = (invent) ? 0 : (SIZE(drop_types) - 1); #endif if (*u.ushops) sellobj_state(SELL_DELIBERATE); result = drop(getobj(&drop_types[i], "drop")); if (*u.ushops) sellobj_state(SELL_NORMAL); reset_occupations(); return result; } #endif /* OVLB */ #ifdef OVL0 /* Called when a boulder is dropped, thrown, or pushed. If it ends up * in a pool, it either fills the pool up or sinks away. In either case, * it's gone for good... If the destination is not a pool, returns FALSE. */ boolean boulder_hits_pool(otmp, rx, ry, pushing) struct obj *otmp; register int rx, ry; boolean pushing; { if (!otmp || otmp->otyp != BOULDER) impossible("Not a boulder?"); else if (!Is_waterlevel(&u.uz) && (is_pool(rx,ry) || is_lava(rx,ry))) { boolean lava = is_lava(rx,ry), fills_up; const char *what = waterbody_name(rx,ry); schar ltyp = levl[rx][ry].typ; int chance = rn2(10); /* water: 90%; lava: 10% */ fills_up = lava ? chance == 0 : chance != 0; if (fills_up) { struct trap *ttmp = t_at(rx, ry); if (ltyp == DRAWBRIDGE_UP) { levl[rx][ry].drawbridgemask &= ~DB_UNDER; /* clear lava */ levl[rx][ry].drawbridgemask |= DB_FLOOR; } else levl[rx][ry].typ = ROOM; if (ttmp) (void) delfloortrap(ttmp); bury_objs(rx, ry); newsym(rx,ry); if (pushing) { You("push %s into the %s.", the(xname(otmp)), what); if (flags.verbose && !Blind) pline("Now you can cross it!"); /* no splashing in this case */ } } if (!fills_up || !pushing) { /* splashing occurs */ if (!u.uinwater) { if (pushing ? !Blind : cansee(rx,ry)) { There("is a large splash as %s %s the %s.", the(xname(otmp)), fills_up? "fills":"falls into", what); } else if (flags.soundok) You_hear("a%s splash.", lava ? " sizzling" : ""); wake_nearto(rx, ry, 40); } if (fills_up && u.uinwater && distu(rx,ry) == 0) { u.uinwater = 0; docrt(); vision_full_recalc = 1; You("find yourself on dry land again!"); } else if (lava && distu(rx,ry) <= 2) { You("are hit by molten lava%c", Fire_resistance ? '.' : '!'); burn_away_slime(); losehp(d((Fire_resistance ? 1 : 3), 6), "molten lava", KILLED_BY); } else if (!fills_up && flags.verbose && (pushing ? !Blind : cansee(rx,ry))) pline("It sinks without a trace!"); } /* boulder is now gone */ if (pushing) delobj(otmp); else obfree(otmp, (struct obj *)0); return TRUE; } return FALSE; } /* Used for objects which sometimes do special things when dropped; must be * called with the object not in any chain. Returns TRUE if the object goes * away. */ boolean flooreffects(obj,x,y,verb) struct obj *obj; int x,y; const char *verb; { struct trap *t; struct monst *mtmp; if (obj->where != OBJ_FREE) panic("flooreffects: obj not free"); /* make sure things like water_damage() have no pointers to follow */ obj->nobj = obj->nexthere = (struct obj *)0; if (obj->otyp == BOULDER && boulder_hits_pool(obj, x, y, FALSE)) return TRUE; else if (obj->otyp == BOULDER && (t = t_at(x,y)) != 0 && (t->ttyp==PIT || t->ttyp==SPIKED_PIT || t->ttyp==TRAPDOOR || t->ttyp==HOLE)) { if (((mtmp = m_at(x, y)) && mtmp->mtrapped) || (u.utrap && u.ux == x && u.uy == y)) { if (*verb) pline_The("boulder %s into the pit%s.", vtense((const char *)0, verb), (mtmp) ? "" : " with you"); if (mtmp) { if (!passes_walls(mtmp->data) && !throws_rocks(mtmp->data)) { if (hmon(mtmp, obj, TRUE) && !is_whirly(mtmp->data)) return FALSE; /* still alive */ } mtmp->mtrapped = 0; } else { if (!Passes_walls && !throws_rocks(youmonst.data)) { losehp(rnd(15), "squished under a boulder", NO_KILLER_PREFIX); return FALSE; /* player remains trapped */ } else u.utrap = 0; } } if (*verb) { if (Blind) { if ((x == u.ux) && (y == u.uy)) You_hear("a CRASH! beneath you."); else You_hear("the boulder %s.", verb); } else if (cansee(x, y)) { pline_The("boulder %s%s.", t->tseen ? "" : "triggers and ", t->ttyp == TRAPDOOR ? "plugs a trap door" : t->ttyp == HOLE ? "plugs a hole" : "fills a pit"); } } deltrap(t); obfree(obj, (struct obj *)0); bury_objs(x, y); newsym(x,y); return TRUE; } else if (is_lava(x, y)) { return fire_damage(obj, FALSE, FALSE, x, y); } else if (is_pool(x, y)) { /* Reasonably bulky objects (arbitrary) splash when dropped. * If you're floating above the water even small things make noise. * Stuff dropped near fountains always misses */ if ((Blind || (Levitation || Flying)) && flags.soundok && ((x == u.ux) && (y == u.uy))) { if (!Underwater) { if (weight(obj) > 9) { pline("Splash!"); } else if (Levitation || Flying) { pline("Plop!"); } } map_background(x, y, 0); newsym(x, y); } water_damage(obj, FALSE, FALSE); } else if (u.ux == x && u.uy == y && (!u.utrap || u.utraptype != TT_PIT) && (t = t_at(x,y)) != 0 && t->tseen && (t->ttyp==PIT || t->ttyp==SPIKED_PIT)) { /* you escaped a pit and are standing on the precipice */ if (Blind && flags.soundok) You_hear("%s %s downwards.", The(xname(obj)), otense(obj, "tumble")); else pline("%s %s into %s pit.", The(xname(obj)), otense(obj, "tumble"), the_your[t->madeby_u]); } return FALSE; } #endif /* OVL0 */ #ifdef OVLB void doaltarobj(obj) /* obj is an object dropped on an altar */ register struct obj *obj; { if (Blind) return; /* KMH, conduct */ u.uconduct.gnostic++; if ((obj->blessed || obj->cursed) && obj->oclass != COIN_CLASS) { There("is %s flash as %s %s the altar.", an(hcolor(obj->blessed ? NH_AMBER : NH_BLACK)), doname(obj), otense(obj, "hit")); if (!Hallucination) obj->bknown = 1; } else { pline("%s %s on the altar.", Doname2(obj), otense(obj, "land")); obj->bknown = 1; } } #ifdef SINKS STATIC_OVL void trycall(obj) register struct obj *obj; { if(!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) docall(obj); } STATIC_OVL void dosinkring(obj) /* obj is a ring being dropped over a kitchen sink */ register struct obj *obj; { register struct obj *otmp,*otmp2; register boolean ideed = TRUE; You("drop %s down the drain.", doname(obj)); obj->in_use = TRUE; /* block free identification via interrupt */ switch(obj->otyp) { /* effects that can be noticed without eyes */ case RIN_SEARCHING: You("thought your %s got lost in the sink, but there it is!", xname(obj)); goto giveback; case RIN_SLOW_DIGESTION: pline_The("ring is regurgitated!"); giveback: obj->in_use = FALSE; dropx(obj); trycall(obj); return; case RIN_LEVITATION: pline_The("sink quivers upward for a moment."); break; case RIN_POISON_RESISTANCE: You("smell rotten %s.", makeplural(fruitname(FALSE))); break; case RIN_AGGRAVATE_MONSTER: pline("Several flies buzz angrily around the sink."); break; case RIN_SHOCK_RESISTANCE: pline("Static electricity surrounds the sink."); break; case RIN_CONFLICT: You_hear("loud noises coming from the drain."); break; case RIN_SUSTAIN_ABILITY: /* KMH */ pline_The("water flow seems fixed."); break; case RIN_GAIN_STRENGTH: pline_The("water flow seems %ser now.", (obj->spe<0) ? "weak" : "strong"); break; case RIN_GAIN_CONSTITUTION: pline_The("water flow seems %ser now.", (obj->spe<0) ? "less" : "great"); break; case RIN_INCREASE_ACCURACY: /* KMH */ pline_The("water flow %s the drain.", (obj->spe<0) ? "misses" : "hits"); break; case RIN_INCREASE_DAMAGE: pline_The("water's force seems %ser now.", (obj->spe<0) ? "small" : "great"); break; case RIN_HUNGER: ideed = FALSE; for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (otmp != uball && otmp != uchain && !obj_resists(otmp, 1, 99)) { if (!Blind) { pline("Suddenly, %s %s from the sink!", doname(otmp), otense(otmp, "vanish")); ideed = TRUE; } delobj(otmp); } } break; case MEAT_RING: /* Not the same as aggravate monster; besides, it's obvious. */ pline("Several flies buzz around the sink."); break; default: ideed = FALSE; break; } if(!Blind && !ideed && obj->otyp != RIN_HUNGER) { ideed = TRUE; switch(obj->otyp) { /* effects that need eyes */ case RIN_ADORNMENT: pline_The("faucets flash brightly for a moment."); break; case RIN_REGENERATION: pline_The("sink looks as good as new."); break; case RIN_INVISIBILITY: You("don't see anything happen to the sink."); break; case RIN_FREE_ACTION: You("see the ring slide right down the drain!"); break; case RIN_SEE_INVISIBLE: You("see some air in the sink."); break; case RIN_STEALTH: pline_The("sink seems to blend into the floor for a moment."); break; case RIN_FIRE_RESISTANCE: pline_The("hot water faucet flashes brightly for a moment."); break; case RIN_COLD_RESISTANCE: pline_The("cold water faucet flashes brightly for a moment."); break; case RIN_PROTECTION_FROM_SHAPE_CHAN: pline_The("sink looks nothing like a fountain."); break; case RIN_PROTECTION: pline_The("sink glows %s for a moment.", hcolor((obj->spe<0) ? NH_BLACK : NH_SILVER)); break; case RIN_WARNING: pline_The("sink glows %s for a moment.", hcolor(NH_WHITE)); break; case RIN_TELEPORTATION: pline_The("sink momentarily vanishes."); break; case RIN_TELEPORT_CONTROL: pline_The("sink looks like it is being beamed aboard somewhere."); break; case RIN_POLYMORPH: pline_The("sink momentarily looks like a fountain."); break; case RIN_POLYMORPH_CONTROL: pline_The("sink momentarily looks like a regularly erupting geyser."); break; } } if(ideed) trycall(obj); else You_hear("the ring bouncing down the drainpipe."); if (!rn2(20)) { pline_The("sink backs up, leaving %s.", doname(obj)); obj->in_use = FALSE; dropx(obj); } else useup(obj); } #endif #endif /* OVLB */ #ifdef OVL0 /* some common tests when trying to drop or throw items */ boolean canletgo(obj,word) register struct obj *obj; register const char *word; { if(obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)){ if (*word) Norep("You cannot %s %s you are wearing.",word, something); return(FALSE); } if (obj->otyp == LOADSTONE && obj->cursed) { /* getobj() kludge sets corpsenm to user's specified count when refusing to split a stack of cursed loadstones */ if (*word) { /* getobj() ignores a count for throwing since that is implicitly forced to be 1; replicate its kludge... */ if (!strcmp(word, "throw") && obj->quan > 1L) obj->corpsenm = 1; pline("For some reason, you cannot %s%s the stone%s!", word, obj->corpsenm ? " any of" : "", plur(obj->quan)); } obj->corpsenm = 0; /* reset */ obj->bknown = 1; return(FALSE); } if (obj->otyp == LEASH && obj->leashmon != 0) { if (*word) pline_The("leash is tied around your %s.", body_part(HAND)); return(FALSE); } #ifdef STEED if (obj->owornmask & W_SADDLE) { if (*word) You("cannot %s %s you are sitting on.", word, something); return (FALSE); } #endif return(TRUE); } STATIC_PTR int drop(obj) register struct obj *obj; { if(!obj) return(0); if(!canletgo(obj,"drop")) return(0); if(obj == uwep) { if(welded(uwep)) { weldmsg(obj); return(0); } setuwep((struct obj *)0); } if(obj == uquiver) { setuqwep((struct obj *)0); } if (obj == uswapwep) { setuswapwep((struct obj *)0); } if (u.uswallow) { /* barrier between you and the floor */ if(flags.verbose) { char buf[BUFSZ]; /* doname can call s_suffix, reusing its buffer */ Strcpy(buf, s_suffix(mon_nam(u.ustuck))); You("drop %s into %s %s.", doname(obj), buf, mbodypart(u.ustuck, STOMACH)); } } else { #ifdef SINKS if((obj->oclass == RING_CLASS || obj->otyp == MEAT_RING) && IS_SINK(levl[u.ux][u.uy].typ)) { dosinkring(obj); return(1); } #endif if (!can_reach_floor()) { if(flags.verbose) You("drop %s.", doname(obj)); #ifndef GOLDOBJ if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj); #else /* Ensure update when we drop gold objects */ if (obj->oclass == COIN_CLASS) flags.botl = 1; freeinv(obj); #endif hitfloor(obj); return(1); } if (!IS_ALTAR(levl[u.ux][u.uy].typ) && flags.verbose) You("drop %s.", doname(obj)); } dropx(obj); return(1); } /* Called in several places - may produce output */ /* eg ship_object() and dropy() -> sellobj() both produce output */ void dropx(obj) register struct obj *obj; { #ifndef GOLDOBJ if (obj->oclass != COIN_CLASS || obj == invent) freeinv(obj); #else /* Ensure update when we drop gold objects */ if (obj->oclass == COIN_CLASS) flags.botl = 1; freeinv(obj); #endif if (!u.uswallow) { if (ship_object(obj, u.ux, u.uy, FALSE)) return; if (IS_ALTAR(levl[u.ux][u.uy].typ)) doaltarobj(obj); /* set bknown */ } dropy(obj); } void dropy(obj) register struct obj *obj; { if (obj == uwep) setuwep((struct obj *)0); if (obj == uquiver) setuqwep((struct obj *)0); if (obj == uswapwep) setuswapwep((struct obj *)0); if (!u.uswallow && flooreffects(obj,u.ux,u.uy,"drop")) return; /* uswallow check done by GAN 01/29/87 */ if(u.uswallow) { boolean could_petrify = FALSE; boolean could_poly = FALSE; boolean could_slime = FALSE; boolean could_grow = FALSE; boolean could_heal = FALSE; if (obj != uball) { /* mon doesn't pick up ball */ if (obj->otyp == CORPSE) { could_petrify = touch_petrifies(&mons[obj->corpsenm]); could_poly = polyfodder(obj); could_slime = (obj->corpsenm == PM_GREEN_SLIME); could_grow = (obj->corpsenm == PM_WRAITH); could_heal = (obj->corpsenm == PM_NURSE); } (void) mpickobj(u.ustuck,obj); if (is_animal(u.ustuck->data)) { if (could_poly || could_slime) { (void) newcham(u.ustuck, could_poly ? (struct permonst *)0 : &mons[PM_GREEN_SLIME], FALSE, could_slime); delobj(obj); /* corpse is digested */ } else if (could_petrify) { minstapetrify(u.ustuck, TRUE); /* Don't leave a cockatrice corpse in a statue */ if (!u.uswallow) delobj(obj); } else if (could_grow) { (void) grow_up(u.ustuck, (struct monst *)0); delobj(obj); /* corpse is digested */ } else if (could_heal) { u.ustuck->mhp = u.ustuck->mhpmax; delobj(obj); /* corpse is digested */ } } } } else { place_object(obj, u.ux, u.uy); if (obj == uball) drop_ball(u.ux,u.uy); else sellobj(obj, u.ux, u.uy); stackobj(obj); if(Blind && Levitation) map_object(obj, 0); newsym(u.ux,u.uy); /* remap location under self */ } } /* things that must change when not held; recurse into containers. Called for both player and monsters */ void obj_no_longer_held(obj) struct obj *obj; { if (!obj) { return; } else if ((Is_container(obj) || obj->otyp == STATUE) && obj->cobj) { struct obj *contents; for(contents=obj->cobj; contents; contents=contents->nobj) obj_no_longer_held(contents); } switch(obj->otyp) { case CRYSKNIFE: /* KMH -- Fixed crysknives have only 10% chance of reverting */ /* only changes when not held by player or monster */ if (!obj->oerodeproof || !rn2(10)) { obj->otyp = WORM_TOOTH; obj->oerodeproof = 0; } break; } } /* 'D' command: drop several things */ int doddrop() { int result = 0; add_valid_menu_class(0); /* clear any classes already there */ if (*u.ushops) sellobj_state(SELL_DELIBERATE); if (flags.menu_style != MENU_TRADITIONAL || (result = ggetobj("drop", drop, 0, FALSE, (unsigned *)0)) < -1) result = menu_drop(result); if (*u.ushops) sellobj_state(SELL_NORMAL); reset_occupations(); return result; } /* Drop things from the hero's inventory, using a menu. */ STATIC_OVL int menu_drop(retry) int retry; { int n, i, n_dropped = 0; long cnt; struct obj *otmp, *otmp2; #ifndef GOLDOBJ struct obj *u_gold = 0; #endif menu_item *pick_list; boolean all_categories = TRUE; boolean drop_everything = FALSE; #ifndef GOLDOBJ if (u.ugold) { /* Hack: gold is not in the inventory, so make a gold object and put it at the head of the inventory list. */ u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */ u_gold->in_use = TRUE; u.ugold = u_gold->quan; /* put the gold back */ assigninvlet(u_gold); /* might end up as NOINVSYM */ u_gold->nobj = invent; invent = u_gold; } #endif if (retry) { all_categories = (retry == -2); } else if (flags.menu_style == MENU_FULL) { all_categories = FALSE; n = query_category("Drop what type of items?", invent, UNPAID_TYPES | ALL_TYPES | CHOOSE_ALL | BUC_BLESSED | BUC_CURSED | BUC_UNCURSED | BUC_UNKNOWN, &pick_list, PICK_ANY); if (!n) goto drop_done; for (i = 0; i < n; i++) { if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) all_categories = TRUE; else if (pick_list[i].item.a_int == 'A') drop_everything = TRUE; else add_valid_menu_class(pick_list[i].item.a_int); } free((genericptr_t) pick_list); } else if (flags.menu_style == MENU_COMBINATION) { unsigned ggoresults = 0; all_categories = FALSE; /* Gather valid classes via traditional NetHack method */ i = ggetobj("drop", drop, 0, TRUE, &ggoresults); if (i == -2) all_categories = TRUE; if (ggoresults & ALL_FINISHED) { n_dropped = i; goto drop_done; } } if (drop_everything) { for(otmp = invent; otmp; otmp = otmp2) { otmp2 = otmp->nobj; n_dropped += drop(otmp); } } else { /* should coordinate with perm invent, maybe not show worn items */ n = query_objlist("What would you like to drop?", invent, USE_INVLET|INVORDER_SORT, &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); if (n > 0) { for (i = 0; i < n; i++) { otmp = pick_list[i].item.a_obj; cnt = pick_list[i].count; if (cnt < otmp->quan) { if (welded(otmp)) { ; /* don't split */ } else if (otmp->otyp == LOADSTONE && otmp->cursed) { /* same kludge as getobj(), for canletgo()'s use */ otmp->corpsenm = (int) cnt; /* don't split */ } else { #ifndef GOLDOBJ if (otmp->oclass == COIN_CLASS) (void) splitobj(otmp, otmp->quan - cnt); else #endif otmp = splitobj(otmp, cnt); } } n_dropped += drop(otmp); } free((genericptr_t) pick_list); } } drop_done: #ifndef GOLDOBJ if (u_gold && invent && invent->oclass == COIN_CLASS) { /* didn't drop [all of] it */ u_gold = invent; invent = u_gold->nobj; u_gold->in_use = FALSE; dealloc_obj(u_gold); update_inventory(); } #endif return n_dropped; } #endif /* OVL0 */ #ifdef OVL2 /* on a ladder, used in goto_level */ static NEARDATA boolean at_ladder = FALSE; int dodown() { struct trap *trap = 0; boolean stairs_down = ((u.ux == xdnstair && u.uy == ydnstair) || (u.ux == sstairs.sx && u.uy == sstairs.sy && !sstairs.up)), ladder_down = (u.ux == xdnladder && u.uy == ydnladder); #ifdef STEED if (u.usteed && !u.usteed->mcanmove) { pline("%s won't move!", Monnam(u.usteed)); return(0); } else if (u.usteed && u.usteed->meating) { pline("%s is still eating.", Monnam(u.usteed)); return(0); } else #endif if (Levitation) { if ((HLevitation & I_SPECIAL) || (ELevitation & W_ARTI)) { /* end controlled levitation */ if (ELevitation & W_ARTI) { struct obj *obj; for(obj = invent; obj; obj = obj->nobj) { if (obj->oartifact && artifact_has_invprop(obj,LEVITATION)) { if (obj->age < monstermoves) obj->age = monstermoves + rnz(100); else obj->age += rnz(100); } } } if (float_down(I_SPECIAL|TIMEOUT, W_ARTI)) return (1); /* came down, so moved */ } floating_above(stairs_down ? "stairs" : ladder_down ? "ladder" : surface(u.ux, u.uy)); return (0); /* didn't move */ } if (!stairs_down && !ladder_down) { if (!(trap = t_at(u.ux,u.uy)) || (trap->ttyp != TRAPDOOR && trap->ttyp != HOLE) || !Can_fall_thru(&u.uz) || !trap->tseen) { if (flags.autodig && !flags.nopick && uwep && is_pick(uwep)) { return use_pick_axe2(uwep); } else { You_cant("go down here."); return(0); } } } if(u.ustuck) { You("are %s, and cannot go down.", !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); return(1); } if (on_level(&valley_level, &u.uz) && !u.uevent.gehennom_entered) { You("are standing at the gate to Gehennom."); pline("Unspeakable cruelty and harm lurk down there."); if (yn("Are you sure you want to enter?") != 'y') return(0); else pline("So be it."); u.uevent.gehennom_entered = 1; /* don't ask again */ } if(!next_to_u()) { You("are held back by your pet!"); return(0); } if (trap) You("%s %s.", locomotion(youmonst.data, "jump"), trap->ttyp == HOLE ? "down the hole" : "through the trap door"); if (trap && Is_stronghold(&u.uz)) { goto_hell(FALSE, TRUE); } else { at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); next_level(!trap); at_ladder = FALSE; } return(1); } int doup() { if( (u.ux != xupstair || u.uy != yupstair) && (!xupladder || u.ux != xupladder || u.uy != yupladder) && (!sstairs.sx || u.ux != sstairs.sx || u.uy != sstairs.sy || !sstairs.up) ) { You_cant("go up here."); return(0); } #ifdef STEED if (u.usteed && !u.usteed->mcanmove) { pline("%s won't move!", Monnam(u.usteed)); return(0); } else if (u.usteed && u.usteed->meating) { pline("%s is still eating.", Monnam(u.usteed)); return(0); } else #endif if(u.ustuck) { You("are %s, and cannot go up.", !u.uswallow ? "being held" : is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); return(1); } if(near_capacity() > SLT_ENCUMBER) { /* No levitation check; inv_weight() already allows for it */ Your("load is too heavy to climb the %s.", levl[u.ux][u.uy].typ == STAIRS ? "stairs" : "ladder"); return(1); } if(ledger_no(&u.uz) == 1) { if (yn("Beware, there will be no return! Still climb?") != 'y') return(0); } if(!next_to_u()) { You("are held back by your pet!"); return(0); } at_ladder = (boolean) (levl[u.ux][u.uy].typ == LADDER); prev_level(TRUE); at_ladder = FALSE; return(1); } d_level save_dlevel = {0, 0}; /* check that we can write out the current level */ STATIC_OVL int currentlevel_rewrite() { register int fd; char whynot[BUFSZ]; /* since level change might be a bit slow, flush any buffered screen * output (like "you fall through a trap door") */ mark_synch(); fd = create_levelfile(ledger_no(&u.uz), whynot); if (fd < 0) { /* * This is not quite impossible: e.g., we may have * exceeded our quota. If that is the case then we * cannot leave this level, and cannot save either. * Another possibility is that the directory was not * writable. */ pline("%s", whynot); return -1; } #ifdef MFLOPPY if (!savelev(fd, ledger_no(&u.uz), COUNT_SAVE)) { (void) close(fd); delete_levelfile(ledger_no(&u.uz)); pline("NetHack is out of disk space for making levels!"); You("can save, quit, or continue playing."); return -1; } #endif return fd; } #ifdef INSURANCE void save_currentstate() { int fd; if (flags.ins_chkpt) { /* write out just-attained level, with pets and everything */ fd = currentlevel_rewrite(); if(fd < 0) return; bufon(fd); savelev(fd,ledger_no(&u.uz), WRITE_SAVE); bclose(fd); } /* write out non-level state */ savestateinlock(); } #endif /* static boolean badspot(x, y) register xchar x, y; { return((levl[x][y].typ != ROOM && levl[x][y].typ != AIR && levl[x][y].typ != CORR) || MON_AT(x, y)); } */ void goto_level(newlevel, at_stairs, falling, portal) d_level *newlevel; boolean at_stairs, falling, portal; { int fd, l_idx; xchar new_ledger; boolean cant_go_back, up = (depth(newlevel) < depth(&u.uz)), newdungeon = (u.uz.dnum != newlevel->dnum), was_in_W_tower = In_W_tower(u.ux, u.uy, &u.uz), familiar = FALSE; boolean new = FALSE; /* made a new level? */ struct monst *mtmp; char whynot[BUFSZ]; if (dunlev(newlevel) > dunlevs_in_dungeon(newlevel)) newlevel->dlevel = dunlevs_in_dungeon(newlevel); if (newdungeon && In_endgame(newlevel)) { /* 1st Endgame Level !!! */ if (u.uhave.amulet) assign_level(newlevel, &earth_level); else return; } new_ledger = ledger_no(newlevel); if (new_ledger <= 0) done(ESCAPED); /* in fact < 0 is impossible */ /* If you have the amulet and are trying to get out of Gehennom, going * up a set of stairs sometimes does some very strange things! * Biased against law and towards chaos, but not nearly as strongly * as it used to be (prior to 3.2.0). * Odds: old new * "up" L N C "up" L N C * +1 75.0 75.0 75.0 +1 75.0 75.0 75.0 * 0 0.0 12.5 25.0 0 6.25 8.33 12.5 * -1 8.33 4.17 0.0 -1 6.25 8.33 12.5 * -2 8.33 4.17 0.0 -2 6.25 8.33 0.0 * -3 8.33 4.17 0.0 -3 6.25 0.0 0.0 */ if (Inhell && up && u.uhave.amulet && !newdungeon && !portal && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)-3)) { if (!rn2(4)) { int odds = 3 + (int)u.ualign.type, /* 2..4 */ diff = odds <= 1 ? 0 : rn2(odds); /* paranoia */ if (diff != 0) { assign_rnd_level(newlevel, &u.uz, diff); /* if inside the tower, stay inside */ if (was_in_W_tower && !On_W_tower_level(newlevel)) diff = 0; } if (diff == 0) assign_level(newlevel, &u.uz); new_ledger = ledger_no(newlevel); pline("A mysterious force momentarily surrounds you..."); if (on_level(newlevel, &u.uz)) { (void) safe_teleds(FALSE); (void) next_to_u(); return; } else at_stairs = at_ladder = FALSE; } } /* Prevent the player from going past the first quest level unless * (s)he has been given the go-ahead by the leader. */ if (on_level(&u.uz, &qstart_level) && !newdungeon && !ok_to_quest()) { pline("A mysterious force prevents you from descending."); return; } if (on_level(newlevel, &u.uz)) return; /* this can happen */ fd = currentlevel_rewrite(); if (fd < 0) return; if (falling) /* assuming this is only trap door or hole */ impact_drop((struct obj *)0, u.ux, u.uy, newlevel->dlevel); check_special_room(TRUE); /* probably was a trap door */ if (Punished) unplacebc(); u.utrap = 0; /* needed in level_tele */ fill_pit(u.ux, u.uy); u.ustuck = 0; /* idem */ u.uinwater = 0; u.uundetected = 0; /* not hidden, even if means are available */ keepdogs(FALSE); if (u.uswallow) /* idem */ u.uswldtim = u.uswallow = 0; /* * We no longer see anything on the level. Make sure that this * follows u.uswallow set to null since uswallow overrides all * normal vision. */ vision_recalc(2); /* * Save the level we're leaving. If we're entering the endgame, * we can get rid of all existing levels because they cannot be * reached any more. We still need to use savelev()'s cleanup * for the level being left, to recover dynamic memory in use and * to avoid dangling timers and light sources. */ cant_go_back = (newdungeon && In_endgame(newlevel)); if (!cant_go_back) { update_mlstmv(); /* current monsters are becoming inactive */ bufon(fd); /* use buffered output */ } savelev(fd, ledger_no(&u.uz), cant_go_back ? FREE_SAVE : (WRITE_SAVE | FREE_SAVE)); bclose(fd); if (cant_go_back) { /* discard unreachable levels; keep #0 */ for (l_idx = maxledgerno(); l_idx > 0; --l_idx) delete_levelfile(l_idx); } #ifdef REINCARNATION if (Is_rogue_level(newlevel) || Is_rogue_level(&u.uz)) assign_rogue_graphics(Is_rogue_level(newlevel)); #endif #ifdef USE_TILES substitute_tiles(newlevel); #endif assign_level(&u.uz0, &u.uz); assign_level(&u.uz, newlevel); assign_level(&u.utolev, newlevel); u.utotype = 0; if (dunlev_reached(&u.uz) < dunlev(&u.uz)) dunlev_reached(&u.uz) = dunlev(&u.uz); reset_rndmonst(NON_PM); /* u.uz change affects monster generation */ /* set default level change destination areas */ /* the special level code may override these */ (void) memset((genericptr_t) &updest, 0, sizeof updest); (void) memset((genericptr_t) &dndest, 0, sizeof dndest); if (!(level_info[new_ledger].flags & LFILE_EXISTS)) { /* entering this level for first time; make it now */ if (level_info[new_ledger].flags & (FORGOTTEN|VISITED)) { impossible("goto_level: returning to discarded level?"); level_info[new_ledger].flags &= ~(FORGOTTEN|VISITED); } mklev(); new = TRUE; /* made the level */ } else { /* returning to previously visited level; reload it */ fd = open_levelfile(new_ledger, whynot); if (fd < 0) { pline("%s", whynot); pline("Probably someone removed it."); killer = whynot; done(TRICKED); /* we'll reach here if running in wizard mode */ error("Cannot continue this game."); } minit(); /* ZEROCOMP */ getlev(fd, hackpid, new_ledger, FALSE); (void) close(fd); } /* do this prior to level-change pline messages */ vision_reset(); /* clear old level's line-of-sight */ vision_full_recalc = 0; /* don't let that reenable vision yet */ flush_screen(-1); /* ensure all map flushes are postponed */ if (portal && !In_endgame(&u.uz)) { /* find the portal on the new level */ register struct trap *ttrap; for (ttrap = ftrap; ttrap; ttrap = ttrap->ntrap) if (ttrap->ttyp == MAGIC_PORTAL) break; if (!ttrap) panic("goto_level: no corresponding portal!"); seetrap(ttrap); u_on_newpos(ttrap->tx, ttrap->ty); } else if (at_stairs && !In_endgame(&u.uz)) { if (up) { if (at_ladder) { u_on_newpos(xdnladder, ydnladder); } else { if (newdungeon) { if (Is_stronghold(&u.uz)) { register xchar x, y; do { x = (COLNO - 2 - rnd(5)); y = rn1(ROWNO - 4, 3); } while(occupied(x, y) || IS_WALL(levl[x][y].typ)); u_on_newpos(x, y); } else u_on_sstairs(); } else u_on_dnstairs(); } /* Remove bug which crashes with levitation/punishment KAA */ if (Punished && !Levitation) { pline("With great effort you climb the %s.", at_ladder ? "ladder" : "stairs"); } else if (at_ladder) You("climb up the ladder."); } else { /* down */ if (at_ladder) { u_on_newpos(xupladder, yupladder); } else { if (newdungeon) u_on_sstairs(); else u_on_upstairs(); } if (u.dz && Flying) You("fly down along the %s.", at_ladder ? "ladder" : "stairs"); else if (u.dz && (near_capacity() > UNENCUMBERED || Punished || Fumbling)) { You("fall down the %s.", at_ladder ? "ladder" : "stairs"); if (Punished) { drag_down(); if (carried(uball)) { if (uwep == uball) setuwep((struct obj *)0); if (uswapwep == uball) setuswapwep((struct obj *)0); if (uquiver == uball) setuqwep((struct obj *)0); freeinv(uball); } } #ifdef STEED /* falling off steed has its own losehp() call */ if (u.usteed) dismount_steed(DISMOUNT_FELL); else #endif losehp(rnd(3), "falling downstairs", KILLED_BY); selftouch("Falling, you"); } else if (u.dz && at_ladder) You("climb down the ladder."); } } else { /* trap door or level_tele or In_endgame */ if (was_in_W_tower && On_W_tower_level(&u.uz)) /* Stay inside the Wizard's tower when feasible. */ /* Note: up vs down doesn't really matter in this case. */ place_lregion(dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy, 0,0, 0,0, LR_DOWNTELE, (d_level *) 0); else if (up) place_lregion(updest.lx, updest.ly, updest.hx, updest.hy, updest.nlx, updest.nly, updest.nhx, updest.nhy, LR_UPTELE, (d_level *) 0); else place_lregion(dndest.lx, dndest.ly, dndest.hx, dndest.hy, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy, LR_DOWNTELE, (d_level *) 0); if (falling) { if (Punished) ballfall(); selftouch("Falling, you"); } } if (Punished) placebc(); obj_delivery(); /* before killing geno'd monsters' eggs */ losedogs(); kill_genocided_monsters(); /* for those wiped out while in limbo */ /* * Expire all timers that have gone off while away. Must be * after migrating monsters and objects are delivered * (losedogs and obj_delivery). */ run_timers(); initrack(); if ((mtmp = m_at(u.ux, u.uy)) != 0 #ifdef STEED && mtmp != u.usteed #endif ) { /* There's a monster at your target destination; it might be one which accompanied you--see mon_arrive(dogmove.c)--or perhaps it was already here. Randomly move you to an adjacent spot or else the monster to any nearby location. Prior to 3.3.0 the latter was done unconditionally. */ coord cc; if (!rn2(2) && enexto(&cc, u.ux, u.uy, youmonst.data) && distu(cc.x, cc.y) <= 2) u_on_newpos(cc.x, cc.y); /*[maybe give message here?]*/ else mnexto(mtmp); if ((mtmp = m_at(u.ux, u.uy)) != 0) { impossible("mnexto failed (do.c)?"); (void) rloc(mtmp, FALSE); } } /* initial movement of bubbles just before vision_recalc */ if (Is_waterlevel(&u.uz)) movebubbles(); if (level_info[new_ledger].flags & FORGOTTEN) { forget_map(ALL_MAP); /* forget the map */ forget_traps(); /* forget all traps too */ familiar = TRUE; level_info[new_ledger].flags &= ~FORGOTTEN; } /* Reset the screen. */ vision_reset(); /* reset the blockages */ docrt(); /* does a full vision recalc */ flush_screen(-1); /* * Move all plines beyond the screen reset. */ /* give room entrance message, if any */ check_special_room(FALSE); /* Check whether we just entered Gehennom. */ if (!In_hell(&u.uz0) && Inhell) { if (Is_valley(&u.uz)) { You("arrive at the Valley of the Dead..."); pline_The("odor of burnt flesh and decay pervades the air."); #ifdef MICRO display_nhwindow(WIN_MESSAGE, FALSE); #endif You_hear("groans and moans everywhere."); } else pline("It is hot here. You smell smoke..."); } if (familiar) { static const char * const fam_msgs[4] = { "You have a sense of deja vu.", "You feel like you've been here before.", "This place %s familiar...", 0 /* no message */ }; static const char * const halu_fam_msgs[4] = { "Whoa! Everything %s different.", "You are surrounded by twisty little passages, all alike.", "Gee, this %s like uncle Conan's place...", 0 /* no message */ }; const char *mesg; char buf[BUFSZ]; int which = rn2(4); if (Hallucination) mesg = halu_fam_msgs[which]; else mesg = fam_msgs[which]; if (mesg && index(mesg, '%')) { Sprintf(buf, mesg, !Blind ? "looks" : "seems"); mesg = buf; } if (mesg) pline(mesg); } #ifdef REINCARNATION if (new && Is_rogue_level(&u.uz)) You("enter what seems to be an older, more primitive world."); #endif /* Final confrontation */ if (In_endgame(&u.uz) && newdungeon && u.uhave.amulet) resurrect(); if (newdungeon && In_V_tower(&u.uz) && In_hell(&u.uz0)) pline_The("heat and smoke are gone."); /* the message from your quest leader */ if (!In_quest(&u.uz0) && at_dgn_entrance("The Quest") && !(u.uevent.qexpelled || u.uevent.qcompleted || quest_status.leader_is_dead)) { if (u.uevent.qcalled) { com_pager(Role_if(PM_ROGUE) ? 4 : 3); } else { com_pager(2); u.uevent.qcalled = TRUE; } } /* once Croesus is dead, his alarm doesn't work any more */ if (Is_knox(&u.uz) && (new || !mvitals[PM_CROESUS].died)) { You("penetrated a high security area!"); pline("An alarm sounds!"); for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp) && mtmp->msleeping) mtmp->msleeping = 0; } if (on_level(&u.uz, &astral_level)) final_level(); else onquest(); assign_level(&u.uz0, &u.uz); /* reset u.uz0 */ #ifdef INSURANCE save_currentstate(); #endif /* assume this will always return TRUE when changing level */ (void) in_out_region(u.ux, u.uy); (void) pickup(1); } STATIC_OVL void final_level() { struct monst *mtmp; struct obj *otmp; coord mm; int i; /* reset monster hostility relative to player */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp)) reset_hostility(mtmp); /* create some player-monsters */ create_mplayers(rn1(4, 3), TRUE); /* create a guardian angel next to player, if worthy */ if (Conflict) { pline( "A voice booms: \"Thy desire for conflict shall be fulfilled!\""); for (i = rnd(4); i > 0; --i) { mm.x = u.ux; mm.y = u.uy; if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type, mm.x, mm.y, FALSE); } } else if (u.ualign.record > 8) { /* fervent */ pline("A voice whispers: \"Thou hast been worthy of me!\""); mm.x = u.ux; mm.y = u.uy; if (enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) { if ((mtmp = mk_roamer(&mons[PM_ANGEL], u.ualign.type, mm.x, mm.y, TRUE)) != 0) { if (!Blind) pline("An angel appears near you."); else You_feel("the presence of a friendly angel near you."); /* guardian angel -- the one case mtame doesn't * imply an edog structure, so we don't want to * call tamedog(). */ mtmp->mtame = 10; /* make him strong enough vs. endgame foes */ mtmp->m_lev = rn1(8,15); mtmp->mhp = mtmp->mhpmax = d((int)mtmp->m_lev,10) + 30 + rnd(30); if ((otmp = select_hwep(mtmp)) == 0) { otmp = mksobj(SILVER_SABER, FALSE, FALSE); if (mpickobj(mtmp, otmp)) panic("merged weapon?"); } bless(otmp); if (otmp->spe < 4) otmp->spe += rnd(4); if ((otmp = which_armor(mtmp, W_ARMS)) == 0 || otmp->otyp != SHIELD_OF_REFLECTION) { (void) mongets(mtmp, AMULET_OF_REFLECTION); m_dowear(mtmp, TRUE); } } } } } static char *dfr_pre_msg = 0, /* pline() before level change */ *dfr_post_msg = 0; /* pline() after level change */ /* change levels at the end of this turn, after monsters finish moving */ void schedule_goto(tolev, at_stairs, falling, portal_flag, pre_msg, post_msg) d_level *tolev; boolean at_stairs, falling; int portal_flag; const char *pre_msg, *post_msg; { int typmask = 0100; /* non-zero triggers `deferred_goto' */ /* destination flags (`goto_level' args) */ if (at_stairs) typmask |= 1; if (falling) typmask |= 2; if (portal_flag) typmask |= 4; if (portal_flag < 0) typmask |= 0200; /* flag for portal removal */ u.utotype = typmask; /* destination level */ assign_level(&u.utolev, tolev); if (pre_msg) dfr_pre_msg = strcpy((char *)alloc(strlen(pre_msg) + 1), pre_msg); if (post_msg) dfr_post_msg = strcpy((char *)alloc(strlen(post_msg)+1), post_msg); } /* handle something like portal ejection */ void deferred_goto() { if (!on_level(&u.uz, &u.utolev)) { d_level dest; int typmask = u.utotype; /* save it; goto_level zeroes u.utotype */ assign_level(&dest, &u.utolev); if (dfr_pre_msg) pline(dfr_pre_msg); goto_level(&dest, !!(typmask&1), !!(typmask&2), !!(typmask&4)); if (typmask & 0200) { /* remove portal */ struct trap *t = t_at(u.ux, u.uy); if (t) { deltrap(t); newsym(u.ux, u.uy); } } if (dfr_post_msg) pline(dfr_post_msg); } u.utotype = 0; /* our caller keys off of this */ if (dfr_pre_msg) free((genericptr_t)dfr_pre_msg), dfr_pre_msg = 0; if (dfr_post_msg) free((genericptr_t)dfr_post_msg), dfr_post_msg = 0; } #endif /* OVL2 */ #ifdef OVL3 /* * Return TRUE if we created a monster for the corpse. If successful, the * corpse is gone. */ boolean revive_corpse(corpse) struct obj *corpse; { struct monst *mtmp, *mcarry; boolean is_uwep, chewed; xchar where; char *cname, cname_buf[BUFSZ]; struct obj *container = (struct obj *)0; int container_where = 0; where = corpse->where; is_uwep = corpse == uwep; cname = eos(strcpy(cname_buf, "bite-covered ")); Strcpy(cname, corpse_xname(corpse, TRUE)); mcarry = (where == OBJ_MINVENT) ? corpse->ocarry : 0; if (where == OBJ_CONTAINED) { struct monst *mtmp2 = (struct monst *)0; container = corpse->ocontainer; mtmp2 = get_container_location(container, &container_where, (int *)0); /* container_where is the outermost container's location even if nested */ if (container_where == OBJ_MINVENT && mtmp2) mcarry = mtmp2; } mtmp = revive(corpse); /* corpse is gone if successful */ if (mtmp) { chewed = (mtmp->mhp < mtmp->mhpmax); if (chewed) cname = cname_buf; /* include "bite-covered" prefix */ switch (where) { case OBJ_INVENT: if (is_uwep) pline_The("%s writhes out of your grasp!", cname); else You_feel("squirming in your backpack!"); break; case OBJ_FLOOR: if (cansee(mtmp->mx, mtmp->my)) pline("%s rises from the dead!", chewed ? Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); break; case OBJ_MINVENT: /* probably a nymph's */ if (cansee(mtmp->mx, mtmp->my)) { if (canseemon(mcarry)) pline("Startled, %s drops %s as it revives!", mon_nam(mcarry), an(cname)); else pline("%s suddenly appears!", chewed ? Adjmonnam(mtmp, "bite-covered") : Monnam(mtmp)); } break; case OBJ_CONTAINED: if (container_where == OBJ_MINVENT && cansee(mtmp->mx, mtmp->my) && mcarry && canseemon(mcarry) && container) { char sackname[BUFSZ]; Sprintf(sackname, "%s %s", s_suffix(mon_nam(mcarry)), xname(container)); pline("%s writhes out of %s!", Amonnam(mtmp), sackname); } else if (container_where == OBJ_INVENT && container) { char sackname[BUFSZ]; Strcpy(sackname, an(xname(container))); pline("%s %s out of %s in your pack!", Blind ? Something : Amonnam(mtmp), locomotion(mtmp->data,"writhes"), sackname); } else if (container_where == OBJ_FLOOR && container && cansee(mtmp->mx, mtmp->my)) { char sackname[BUFSZ]; Strcpy(sackname, an(xname(container))); pline("%s escapes from %s!", Amonnam(mtmp), sackname); } break; default: /* we should be able to handle the other cases... */ impossible("revive_corpse: lost corpse @ %d", where); break; } return TRUE; } return FALSE; } /* Revive the corpse via a timeout. */ /*ARGSUSED*/ void revive_mon(arg, timeout) genericptr_t arg; long timeout; { struct obj *body = (struct obj *) arg; /* if we succeed, the corpse is gone, otherwise, rot it away */ if (!revive_corpse(body)) { if (is_rider(&mons[body->corpsenm])) You_feel("less hassled."); (void) start_timer(250L - (monstermoves-body->age), TIMER_OBJECT, ROT_CORPSE, arg); } } int donull() { return(1); /* Do nothing, but let other things happen */ } #endif /* OVL3 */ #ifdef OVLB STATIC_PTR int wipeoff() { if(u.ucreamed < 4) u.ucreamed = 0; else u.ucreamed -= 4; if (Blinded < 4) Blinded = 0; else Blinded -= 4; if (!Blinded) { pline("You've got the glop off."); u.ucreamed = 0; Blinded = 1; make_blinded(0L,TRUE); return(0); } else if (!u.ucreamed) { Your("%s feels clean now.", body_part(FACE)); return(0); } return(1); /* still busy */ } int dowipe() { if(u.ucreamed) { static NEARDATA char buf[39]; Sprintf(buf, "wiping off your %s", body_part(FACE)); set_occupation(wipeoff, buf, 0); /* Not totally correct; what if they change back after now * but before they're finished wiping? */ return(1); } Your("%s is already clean.", body_part(FACE)); return(1); } void set_wounded_legs(side, timex) register long side; register int timex; { /* KMH -- STEED * If you are riding, your steed gets the wounded legs instead. * You still call this function, but don't lose hp. * Caller is also responsible for adjusting messages. */ if(!Wounded_legs) { ATEMP(A_DEX)--; flags.botl = 1; } if(!Wounded_legs || (HWounded_legs & TIMEOUT)) HWounded_legs = timex; EWounded_legs = side; (void)encumber_msg(); } void heal_legs() { if(Wounded_legs) { if (ATEMP(A_DEX) < 0) { ATEMP(A_DEX)++; flags.botl = 1; } #ifdef STEED if (!u.usteed) #endif { /* KMH, intrinsics patch */ if((EWounded_legs & BOTH_SIDES) == BOTH_SIDES) { Your("%s feel somewhat better.", makeplural(body_part(LEG))); } else { Your("%s feels somewhat better.", body_part(LEG)); } } HWounded_legs = EWounded_legs = 0; } (void)encumber_msg(); } #endif /* OVLB */ /*do.c*/ nethack-3.4.3/src/do_name.c0100644000000000000000000006723107764735041014220 0ustar rootroot/* SCCS Id: @(#)do_name.c 3.4 2003/01/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef OVLB STATIC_DCL void FDECL(do_oname, (struct obj *)); static void FDECL(getpos_help, (BOOLEAN_P,const char *)); extern const char what_is_an_unknown_object[]; /* from pager.c */ /* the response for '?' help request in getpos() */ static void getpos_help(force, goal) boolean force; const char *goal; { char sbuf[BUFSZ]; boolean doing_what_is; winid tmpwin = create_nhwindow(NHW_MENU); Sprintf(sbuf, "Use [%s] to move the cursor to %s.", iflags.num_pad ? "2468" : "hjkl", goal); putstr(tmpwin, 0, sbuf); putstr(tmpwin, 0, "Use [HJKL] to move the cursor 8 units at a time."); putstr(tmpwin, 0, "Or enter a background symbol (ex. <)."); /* disgusting hack; the alternate selection characters work for any getpos call, but they only matter for dowhatis (and doquickwhatis) */ doing_what_is = (goal == what_is_an_unknown_object); Sprintf(sbuf, "Type a .%s when you are at the right place.", doing_what_is ? " or , or ; or :" : ""); putstr(tmpwin, 0, sbuf); if (!force) putstr(tmpwin, 0, "Type Space or Escape when you're done."); putstr(tmpwin, 0, ""); display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); } int getpos(cc, force, goal) coord *cc; boolean force; const char *goal; { int result = 0; int cx, cy, i, c; int sidx, tx, ty; boolean msg_given = TRUE; /* clear message window by default */ static const char pick_chars[] = ".,;:"; const char *cp; const char *sdp; if(iflags.num_pad) sdp = ndir; else sdp = sdir; /* DICE workaround */ if (flags.verbose) { pline("(For instructions type a ?)"); msg_given = TRUE; } cx = cc->x; cy = cc->y; #ifdef CLIPPING cliparound(cx, cy); #endif curs(WIN_MAP, cx,cy); flush_screen(0); #ifdef MAC lock_mouse_cursor(TRUE); #endif for (;;) { c = nh_poskey(&tx, &ty, &sidx); if (c == '\033') { cx = cy = -10; msg_given = TRUE; /* force clear */ result = -1; break; } if(c == 0) { if (!isok(tx, ty)) continue; /* a mouse click event, just assign and return */ cx = tx; cy = ty; break; } if ((cp = index(pick_chars, c)) != 0) { /* '.' => 0, ',' => 1, ';' => 2, ':' => 3 */ result = cp - pick_chars; break; } for (i = 0; i < 8; i++) { int dx, dy; if (sdp[i] == c) { /* a normal movement letter or digit */ dx = xdir[i]; dy = ydir[i]; } else if (sdir[i] == lowc((char)c)) { /* a shifted movement letter */ dx = 8 * xdir[i]; dy = 8 * ydir[i]; } else continue; /* truncate at map edge; diagonal moves complicate this... */ if (cx + dx < 1) { dy -= sgn(dy) * (1 - (cx + dx)); dx = 1 - cx; /* so that (cx+dx == 1) */ } else if (cx + dx > COLNO-1) { dy += sgn(dy) * ((COLNO-1) - (cx + dx)); dx = (COLNO-1) - cx; } if (cy + dy < 0) { dx -= sgn(dx) * (0 - (cy + dy)); dy = 0 - cy; /* so that (cy+dy == 0) */ } else if (cy + dy > ROWNO-1) { dx += sgn(dx) * ((ROWNO-1) - (cy + dy)); dy = (ROWNO-1) - cy; } cx += dx; cy += dy; goto nxtc; } if(c == '?'){ getpos_help(force, goal); } else { if (!index(quitchars, c)) { char matching[MAXPCHARS]; int pass, lo_x, lo_y, hi_x, hi_y, k = 0; (void)memset((genericptr_t)matching, 0, sizeof matching); for (sidx = 1; sidx < MAXPCHARS; sidx++) if (c == defsyms[sidx].sym || c == (int)showsyms[sidx]) matching[sidx] = (char) ++k; if (k) { for (pass = 0; pass <= 1; pass++) { /* pass 0: just past current pos to lower right; pass 1: upper left corner to current pos */ lo_y = (pass == 0) ? cy : 0; hi_y = (pass == 0) ? ROWNO - 1 : cy; for (ty = lo_y; ty <= hi_y; ty++) { lo_x = (pass == 0 && ty == lo_y) ? cx + 1 : 1; hi_x = (pass == 1 && ty == hi_y) ? cx : COLNO - 1; for (tx = lo_x; tx <= hi_x; tx++) { k = levl[tx][ty].glyph; if (glyph_is_cmap(k) && matching[glyph_to_cmap(k)]) { cx = tx, cy = ty; if (msg_given) { clear_nhwindow(WIN_MESSAGE); msg_given = FALSE; } goto nxtc; } } /* column */ } /* row */ } /* pass */ pline("Can't find dungeon feature '%c'.", c); msg_given = TRUE; goto nxtc; } else { pline("Unknown direction: '%s' (%s).", visctrl((char)c), !force ? "aborted" : iflags.num_pad ? "use 2468 or ." : "use hjkl or ."); msg_given = TRUE; } /* k => matching */ } /* !quitchars */ if (force) goto nxtc; pline("Done."); msg_given = FALSE; /* suppress clear */ cx = -1; cy = 0; result = 0; /* not -1 */ break; } nxtc: ; #ifdef CLIPPING cliparound(cx, cy); #endif curs(WIN_MAP,cx,cy); flush_screen(0); } #ifdef MAC lock_mouse_cursor(FALSE); #endif if (msg_given) clear_nhwindow(WIN_MESSAGE); cc->x = cx; cc->y = cy; return result; } struct monst * christen_monst(mtmp, name) struct monst *mtmp; const char *name; { int lth; struct monst *mtmp2; char buf[PL_PSIZ]; /* dogname & catname are PL_PSIZ arrays; object names have same limit */ lth = *name ? (int)(strlen(name) + 1) : 0; if(lth > PL_PSIZ){ lth = PL_PSIZ; name = strncpy(buf, name, PL_PSIZ - 1); buf[PL_PSIZ - 1] = '\0'; } if (lth == mtmp->mnamelth) { /* don't need to allocate a new monst struct */ if (lth) Strcpy(NAME(mtmp), name); return mtmp; } mtmp2 = newmonst(mtmp->mxlth + lth); *mtmp2 = *mtmp; (void) memcpy((genericptr_t)mtmp2->mextra, (genericptr_t)mtmp->mextra, mtmp->mxlth); mtmp2->mnamelth = lth; if (lth) Strcpy(NAME(mtmp2), name); replmon(mtmp,mtmp2); return(mtmp2); } int do_mname() { char buf[BUFSZ]; coord cc; register int cx,cy; register struct monst *mtmp; char qbuf[QBUFSZ]; if (Hallucination) { You("would never recognize it anyway."); return 0; } cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, FALSE, "the monster you want to name") < 0 || (cx = cc.x) < 0) return 0; cy = cc.y; if (cx == u.ux && cy == u.uy) { #ifdef STEED if (u.usteed && canspotmon(u.usteed)) mtmp = u.usteed; else { #endif pline("This %s creature is called %s and cannot be renamed.", ACURR(A_CHA) > 14 ? (flags.female ? "beautiful" : "handsome") : "ugly", plname); return(0); #ifdef STEED } #endif } else mtmp = m_at(cx, cy); if (!mtmp || (!sensemon(mtmp) && (!(cansee(cx,cy) || see_with_infrared(mtmp)) || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT || (mtmp->minvis && !See_invisible)))) { pline("I see no monster there."); return(0); } /* special case similar to the one in lookat() */ (void) distant_monnam(mtmp, ARTICLE_THE, buf); Sprintf(qbuf, "What do you want to call %s?", buf); getlin(qbuf,buf); if(!*buf || *buf == '\033') return(0); /* strip leading and trailing spaces; unnames monster if all spaces */ (void)mungspaces(buf); if (mtmp->data->geno & G_UNIQ) pline("%s doesn't like being called names!", Monnam(mtmp)); else (void) christen_monst(mtmp, buf); return(0); } /* * This routine changes the address of obj. Be careful not to call it * when there might be pointers around in unknown places. For now: only * when obj is in the inventory. */ STATIC_OVL void do_oname(obj) register struct obj *obj; { char buf[BUFSZ], qbuf[QBUFSZ]; const char *aname; short objtyp; Sprintf(qbuf, "What do you want to name %s %s?", is_plural(obj) ? "these" : "this", xname(obj)); getlin(qbuf, buf); if(!*buf || *buf == '\033') return; /* strip leading and trailing spaces; unnames item if all spaces */ (void)mungspaces(buf); /* relax restrictions over proper capitalization for artifacts */ if ((aname = artifact_name(buf, &objtyp)) != 0 && objtyp == obj->otyp) Strcpy(buf, aname); if (obj->oartifact) { pline_The("artifact seems to resist the attempt."); return; } else if (restrict_name(obj, buf) || exist_artifact(obj->otyp, buf)) { int n = rn2((int)strlen(buf)); register char c1, c2; c1 = lowc(buf[n]); do c2 = 'a' + rn2('z'-'a'); while (c1 == c2); buf[n] = (buf[n] == c1) ? c2 : highc(c2); /* keep same case */ pline("While engraving your %s slips.", body_part(HAND)); display_nhwindow(WIN_MESSAGE, FALSE); You("engrave: \"%s\".",buf); } obj = oname(obj, buf); } /* * Allocate a new and possibly larger storage space for an obj. */ struct obj * realloc_obj(obj, oextra_size, oextra_src, oname_size, name) struct obj *obj; int oextra_size; /* storage to allocate for oextra */ genericptr_t oextra_src; int oname_size; /* size of name string + 1 (null terminator) */ const char *name; { struct obj *otmp; otmp = newobj(oextra_size + oname_size); *otmp = *obj; /* the cobj pointer is copied to otmp */ if (oextra_size) { if (oextra_src) (void) memcpy((genericptr_t)otmp->oextra, oextra_src, oextra_size); } else { otmp->oattached = OATTACHED_NOTHING; } otmp->oxlth = oextra_size; otmp->onamelth = oname_size; otmp->timed = 0; /* not timed, yet */ otmp->lamplit = 0; /* ditto */ /* __GNUC__ note: if the assignment of otmp->onamelth immediately precedes this `if' statement, a gcc bug will miscompile the test on vax (`insv' instruction used to store bitfield does not set condition codes, but optimizer behaves as if it did). gcc-2.7.2.1 finally fixed this. */ if (oname_size) { if (name) Strcpy(ONAME(otmp), name); } if (obj->owornmask) { boolean save_twoweap = u.twoweap; /* unwearing the old instance will clear dual-wield mode if this object is either of the two weapons */ setworn((struct obj *)0, obj->owornmask); setworn(otmp, otmp->owornmask); u.twoweap = save_twoweap; } /* replace obj with otmp */ replace_object(obj, otmp); /* fix ocontainer pointers */ if (Has_contents(obj)) { struct obj *inside; for(inside = obj->cobj; inside; inside = inside->nobj) inside->ocontainer = otmp; } /* move timers and light sources from obj to otmp */ if (obj->timed) obj_move_timers(obj, otmp); if (obj->lamplit) obj_move_light_source(obj, otmp); /* objects possibly being manipulated by multi-turn occupations which have been interrupted but might be subsequently resumed */ if (obj->oclass == FOOD_CLASS) food_substitution(obj, otmp); /* eat food or open tin */ else if (obj->oclass == SPBOOK_CLASS) book_substitution(obj, otmp); /* read spellbook */ /* obfree(obj, otmp); now unnecessary: no pointers on bill */ dealloc_obj(obj); /* let us hope nobody else saved a pointer */ return otmp; } struct obj * oname(obj, name) struct obj *obj; const char *name; { int lth; char buf[PL_PSIZ]; lth = *name ? (int)(strlen(name) + 1) : 0; if (lth > PL_PSIZ) { lth = PL_PSIZ; name = strncpy(buf, name, PL_PSIZ - 1); buf[PL_PSIZ - 1] = '\0'; } /* If named artifact exists in the game, do not create another. * Also trying to create an artifact shouldn't de-artifact * it (e.g. Excalibur from prayer). In this case the object * will retain its current name. */ if (obj->oartifact || (lth && exist_artifact(obj->otyp, name))) return obj; if (lth == obj->onamelth) { /* no need to replace entire object */ if (lth) Strcpy(ONAME(obj), name); } else { obj = realloc_obj(obj, obj->oxlth, (genericptr_t)obj->oextra, lth, name); } if (lth) artifact_exists(obj, name, TRUE); if (obj->oartifact) { /* can't dual-wield with artifact as secondary weapon */ if (obj == uswapwep) untwoweapon(); /* activate warning if you've just named your weapon "Sting" */ if (obj == uwep) set_artifact_intrinsic(obj, TRUE, W_WEP); } if (carried(obj)) update_inventory(); return obj; } static NEARDATA const char callable[] = { SCROLL_CLASS, POTION_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS, GEM_CLASS, SPBOOK_CLASS, ARMOR_CLASS, TOOL_CLASS, 0 }; int ddocall() { register struct obj *obj; #ifdef REDO char ch; #endif char allowall[2]; switch( #ifdef REDO ch = #endif ynq("Name an individual object?")) { case 'q': break; case 'y': #ifdef REDO savech(ch); #endif allowall[0] = ALL_CLASSES; allowall[1] = '\0'; obj = getobj(allowall, "name"); if(obj) do_oname(obj); break; default : #ifdef REDO savech(ch); #endif obj = getobj(callable, "call"); if (obj) { /* behave as if examining it in inventory; this might set dknown if it was picked up while blind and the hero can now see */ (void) xname(obj); if (!obj->dknown) { You("would never recognize another one."); return 0; } docall(obj); } break; } return 0; } void docall(obj) register struct obj *obj; { char buf[BUFSZ], qbuf[QBUFSZ]; struct obj otemp; register char **str1; if (!obj->dknown) return; /* probably blind */ otemp = *obj; otemp.quan = 1L; otemp.onamelth = 0; otemp.oxlth = 0; if (objects[otemp.otyp].oc_class == POTION_CLASS && otemp.fromsink) /* kludge, meaning it's sink water */ Sprintf(qbuf,"Call a stream of %s fluid:", OBJ_DESCR(objects[otemp.otyp])); else Sprintf(qbuf, "Call %s:", an(xname(&otemp))); getlin(qbuf, buf); if(!*buf || *buf == '\033') return; /* clear old name */ str1 = &(objects[obj->otyp].oc_uname); if(*str1) free((genericptr_t)*str1); /* strip leading and trailing spaces; uncalls item if all spaces */ (void)mungspaces(buf); if (!*buf) { if (*str1) { /* had name, so possibly remove from disco[] */ /* strip name first, for the update_inventory() call from undiscover_object() */ *str1 = (char *)0; undiscover_object(obj->otyp); } } else { *str1 = strcpy((char *) alloc((unsigned)strlen(buf)+1), buf); discover_object(obj->otyp, FALSE, TRUE); /* possibly add to disco[] */ } } #endif /*OVLB*/ #ifdef OVL0 static const char * const ghostnames[] = { /* these names should have length < PL_NSIZ */ /* Capitalize the names for aesthetics -dgk */ "Adri", "Andries", "Andreas", "Bert", "David", "Dirk", "Emile", "Frans", "Fred", "Greg", "Hether", "Jay", "John", "Jon", "Karnov", "Kay", "Kenny", "Kevin", "Maud", "Michiel", "Mike", "Peter", "Robert", "Ron", "Tom", "Wilmar", "Nick Danger", "Phoenix", "Jiro", "Mizue", "Stephan", "Lance Braccus", "Shadowhawk" }; /* ghost names formerly set by x_monnam(), now by makemon() instead */ const char * rndghostname() { return rn2(7) ? ghostnames[rn2(SIZE(ghostnames))] : (const char *)plname; } /* Monster naming functions: * x_monnam is the generic monster-naming function. * seen unseen detected named * mon_nam: the newt it the invisible orc Fido * noit_mon_nam:the newt (as if detected) the invisible orc Fido * l_monnam: newt it invisible orc dog called fido * Monnam: The newt It The invisible orc Fido * noit_Monnam: The newt (as if detected) The invisible orc Fido * Adjmonnam: The poor newt It The poor invisible orc The poor Fido * Amonnam: A newt It An invisible orc Fido * a_monnam: a newt it an invisible orc Fido * m_monnam: newt xan orc Fido * y_monnam: your newt your xan your invisible orc Fido */ /* Bug: if the monster is a priest or shopkeeper, not every one of these * options works, since those are special cases. */ char * x_monnam(mtmp, article, adjective, suppress, called) register struct monst *mtmp; int article; /* ARTICLE_NONE, ARTICLE_THE, ARTICLE_A: obvious * ARTICLE_YOUR: "your" on pets, "the" on everything else * * If the monster would be referred to as "it" or if the monster has a name * _and_ there is no adjective, "invisible", "saddled", etc., override this * and always use no article. */ const char *adjective; int suppress; /* SUPPRESS_IT, SUPPRESS_INVISIBLE, SUPPRESS_HALLUCINATION, SUPPRESS_SADDLE. * EXACT_NAME: combination of all the above */ boolean called; { #ifdef LINT /* static char buf[BUFSZ]; */ char buf[BUFSZ]; #else static char buf[BUFSZ]; #endif struct permonst *mdat = mtmp->data; boolean do_hallu, do_invis, do_it, do_saddle; boolean name_at_start, has_adjectives; char *bp; if (program_state.gameover) suppress |= SUPPRESS_HALLUCINATION; if (article == ARTICLE_YOUR && !mtmp->mtame) article = ARTICLE_THE; do_hallu = Hallucination && !(suppress & SUPPRESS_HALLUCINATION); do_invis = mtmp->minvis && !(suppress & SUPPRESS_INVISIBLE); do_it = !canspotmon(mtmp) && article != ARTICLE_YOUR && !program_state.gameover && #ifdef STEED mtmp != u.usteed && #endif !(u.uswallow && mtmp == u.ustuck) && !(suppress & SUPPRESS_IT); do_saddle = !(suppress & SUPPRESS_SADDLE); buf[0] = 0; /* unseen monsters, etc. Use "it" */ if (do_it) { Strcpy(buf, "it"); return buf; } /* priests and minions: don't even use this function */ if (mtmp->ispriest || mtmp->isminion) { char priestnambuf[BUFSZ]; char *name; long save_prop = EHalluc_resistance; unsigned save_invis = mtmp->minvis; /* when true name is wanted, explicitly block Hallucination */ if (!do_hallu) EHalluc_resistance = 1L; if (!do_invis) mtmp->minvis = 0; name = priestname(mtmp, priestnambuf); EHalluc_resistance = save_prop; mtmp->minvis = save_invis; if (article == ARTICLE_NONE && !strncmp(name, "the ", 4)) name += 4; return strcpy(buf, name); } /* Shopkeepers: use shopkeeper name. For normal shopkeepers, just * "Asidonhopo"; for unusual ones, "Asidonhopo the invisible * shopkeeper" or "Asidonhopo the blue dragon". If hallucinating, * none of this applies. */ if (mtmp->isshk && !do_hallu) { if (adjective && article == ARTICLE_THE) { /* pathological case: "the angry Asidonhopo the blue dragon" sounds silly */ Strcpy(buf, "the "); Strcat(strcat(buf, adjective), " "); Strcat(buf, shkname(mtmp)); return buf; } Strcat(buf, shkname(mtmp)); if (mdat == &mons[PM_SHOPKEEPER] && !do_invis) return buf; Strcat(buf, " the "); if (do_invis) Strcat(buf, "invisible "); Strcat(buf, mdat->mname); return buf; } /* Put the adjectives in the buffer */ if (adjective) Strcat(strcat(buf, adjective), " "); if (do_invis) Strcat(buf, "invisible "); #ifdef STEED if (do_saddle && (mtmp->misc_worn_check & W_SADDLE) && !Blind && !Hallucination) Strcat(buf, "saddled "); #endif if (buf[0] != 0) has_adjectives = TRUE; else has_adjectives = FALSE; /* Put the actual monster name or type into the buffer now */ /* Be sure to remember whether the buffer starts with a name */ if (do_hallu) { Strcat(buf, rndmonnam()); name_at_start = FALSE; } else if (mtmp->mnamelth) { char *name = NAME(mtmp); if (mdat == &mons[PM_GHOST]) { Sprintf(eos(buf), "%s ghost", s_suffix(name)); name_at_start = TRUE; } else if (called) { Sprintf(eos(buf), "%s called %s", mdat->mname, name); name_at_start = (boolean)type_is_pname(mdat); } else if (is_mplayer(mdat) && (bp = strstri(name, " the ")) != 0) { /* the */ char pbuf[BUFSZ]; Strcpy(pbuf, name); pbuf[bp - name + 5] = '\0'; /* adjectives right after " the " */ if (has_adjectives) Strcat(pbuf, buf); Strcat(pbuf, bp + 5); /* append the rest of the name */ Strcpy(buf, pbuf); article = ARTICLE_NONE; name_at_start = TRUE; } else { Strcat(buf, name); name_at_start = TRUE; } } else if (is_mplayer(mdat) && !In_endgame(&u.uz)) { char pbuf[BUFSZ]; Strcpy(pbuf, rank_of((int)mtmp->m_lev, monsndx(mdat), (boolean)mtmp->female)); Strcat(buf, lcase(pbuf)); name_at_start = FALSE; } else { Strcat(buf, mdat->mname); name_at_start = (boolean)type_is_pname(mdat); } if (name_at_start && (article == ARTICLE_YOUR || !has_adjectives)) { if (mdat == &mons[PM_WIZARD_OF_YENDOR]) article = ARTICLE_THE; else article = ARTICLE_NONE; } else if ((mdat->geno & G_UNIQ) && article == ARTICLE_A) { article = ARTICLE_THE; } { char buf2[BUFSZ]; switch(article) { case ARTICLE_YOUR: Strcpy(buf2, "your "); Strcat(buf2, buf); Strcpy(buf, buf2); return buf; case ARTICLE_THE: Strcpy(buf2, "the "); Strcat(buf2, buf); Strcpy(buf, buf2); return buf; case ARTICLE_A: return(an(buf)); case ARTICLE_NONE: default: return buf; } } } #endif /* OVL0 */ #ifdef OVLB char * l_monnam(mtmp) register struct monst *mtmp; { return(x_monnam(mtmp, ARTICLE_NONE, (char *)0, mtmp->mnamelth ? SUPPRESS_SADDLE : 0, TRUE)); } #endif /* OVLB */ #ifdef OVL0 char * mon_nam(mtmp) register struct monst *mtmp; { return(x_monnam(mtmp, ARTICLE_THE, (char *)0, mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE)); } /* print the name as if mon_nam() was called, but assume that the player * can always see the monster--used for probing and for monsters aggravating * the player with a cursed potion of invisibility */ char * noit_mon_nam(mtmp) register struct monst *mtmp; { return(x_monnam(mtmp, ARTICLE_THE, (char *)0, mtmp->mnamelth ? (SUPPRESS_SADDLE|SUPPRESS_IT) : SUPPRESS_IT, FALSE)); } char * Monnam(mtmp) register struct monst *mtmp; { register char *bp = mon_nam(mtmp); *bp = highc(*bp); return(bp); } char * noit_Monnam(mtmp) register struct monst *mtmp; { register char *bp = noit_mon_nam(mtmp); *bp = highc(*bp); return(bp); } /* monster's own name */ char * m_monnam(mtmp) struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_NONE, (char *)0, EXACT_NAME, FALSE); } /* pet name: "your little dog" */ char * y_monnam(mtmp) struct monst *mtmp; { int prefix, suppression_flag; prefix = mtmp->mtame ? ARTICLE_YOUR : ARTICLE_THE; suppression_flag = (mtmp->mnamelth #ifdef STEED /* "saddled" is redundant when mounted */ || mtmp == u.usteed #endif ) ? SUPPRESS_SADDLE : 0; return x_monnam(mtmp, prefix, (char *)0, suppression_flag, FALSE); } #endif /* OVL0 */ #ifdef OVLB char * Adjmonnam(mtmp, adj) register struct monst *mtmp; register const char *adj; { register char *bp = x_monnam(mtmp, ARTICLE_THE, adj, mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE); *bp = highc(*bp); return(bp); } char * a_monnam(mtmp) register struct monst *mtmp; { return x_monnam(mtmp, ARTICLE_A, (char *)0, mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE); } char * Amonnam(mtmp) register struct monst *mtmp; { register char *bp = a_monnam(mtmp); *bp = highc(*bp); return(bp); } /* used for monster ID by the '/', ';', and 'C' commands to block remote identification of the endgame altars via their attending priests */ char * distant_monnam(mon, article, outbuf) struct monst *mon; int article; /* only ARTICLE_NONE and ARTICLE_THE are handled here */ char *outbuf; { /* high priest(ess)'s identity is concealed on the Astral Plane, unless you're adjacent (overridden for hallucination which does its own obfuscation) */ if (mon->data == &mons[PM_HIGH_PRIEST] && !Hallucination && Is_astralevel(&u.uz) && distu(mon->mx, mon->my) > 2) { Strcpy(outbuf, article == ARTICLE_THE ? "the " : ""); Strcat(outbuf, mon->female ? "high priestess" : "high priest"); } else { Strcpy(outbuf, x_monnam(mon, article, (char *)0, 0, TRUE)); } return outbuf; } static const char * const bogusmons[] = { "jumbo shrimp", "giant pigmy", "gnu", "killer penguin", "giant cockroach", "giant slug", "maggot", "pterodactyl", "tyrannosaurus rex", "basilisk", "beholder", "nightmare", "efreeti", "marid", "rot grub", "bookworm", "master lichen", "shadow", "hologram", "jester", "attorney", "sleazoid", "killer tomato", "amazon", "robot", "battlemech", "rhinovirus", "harpy", "lion-dog", "rat-ant", "Y2K bug", /* misc. */ "grue", "Christmas-tree monster", "luck sucker", "paskald", "brogmoid", "dornbeast", /* Quendor (Zork, &c.) */ "Ancient Multi-Hued Dragon", "Evil Iggy", /* Moria */ "emu", "kestrel", "xeroc", "venus flytrap", /* Rogue */ "creeping coins", /* Wizardry */ "hydra", "siren", /* Greek legend */ "killer bunny", /* Monty Python */ "rodent of unusual size", /* The Princess Bride */ "Smokey the bear", /* "Only you can prevent forest fires!" */ "Luggage", /* Discworld */ "Ent", /* Lord of the Rings */ "tangle tree", "nickelpede", "wiggle", /* Xanth */ "white rabbit", "snark", /* Lewis Carroll */ "pushmi-pullyu", /* Dr. Doolittle */ "smurf", /* The Smurfs */ "tribble", "Klingon", "Borg", /* Star Trek */ "Ewok", /* Star Wars */ "Totoro", /* Tonari no Totoro */ "ohmu", /* Nausicaa */ "youma", /* Sailor Moon */ "nyaasu", /* Pokemon (Meowth) */ "Godzilla", "King Kong", /* monster movies */ "earthquake beast", /* old L of SH */ "Invid", /* Robotech */ "Terminator", /* The Terminator */ "boomer", /* Bubblegum Crisis */ "Dalek", /* Dr. Who ("Exterminate!") */ "microscopic space fleet", "Ravenous Bugblatter Beast of Traal", /* HGttG */ "teenage mutant ninja turtle", /* TMNT */ "samurai rabbit", /* Usagi Yojimbo */ "aardvark", /* Cerebus */ "Audrey II", /* Little Shop of Horrors */ "witch doctor", "one-eyed one-horned flying purple people eater", /* 50's rock 'n' roll */ "Barney the dinosaur", /* saccharine kiddy TV */ "Morgoth", /* Angband */ "Vorlon", /* Babylon 5 */ "questing beast", /* King Arthur */ "Predator", /* Movie */ "mother-in-law" /* common pest */ }; /* Return a random monster name, for hallucination. * KNOWN BUG: May be a proper name (Godzilla, Barney), may not * (the Terminator, a Dalek). There's no elegant way to deal * with this without radically modifying the calling functions. */ const char * rndmonnam() { int name; do { name = rn1(SPECIAL_PM + SIZE(bogusmons) - LOW_PM, LOW_PM); } while (name < SPECIAL_PM && (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN))); if (name >= SPECIAL_PM) return bogusmons[name - SPECIAL_PM]; return mons[name].mname; } #ifdef REINCARNATION const char * roguename() /* Name of a Rogue player */ { char *i, *opts; if ((opts = nh_getenv("ROGUEOPTS")) != 0) { for (i = opts; *i; i++) if (!strncmp("name=",i,5)) { char *j; if ((j = index(i+5,',')) != 0) *j = (char)0; return i+5; } } return rn2(3) ? (rn2(2) ? "Michael Toy" : "Kenneth Arnold") : "Glenn Wichman"; } #endif /* REINCARNATION */ #endif /* OVLB */ #ifdef OVL2 static NEARDATA const char * const hcolors[] = { "ultraviolet", "infrared", "bluish-orange", "reddish-green", "dark white", "light black", "sky blue-pink", "salty", "sweet", "sour", "bitter", "striped", "spiral", "swirly", "plaid", "checkered", "argyle", "paisley", "blotchy", "guernsey-spotted", "polka-dotted", "square", "round", "triangular", "cabernet", "sangria", "fuchsia", "wisteria", "lemon-lime", "strawberry-banana", "peppermint", "romantic", "incandescent" }; const char * hcolor(colorpref) const char *colorpref; { return (Hallucination || !colorpref) ? hcolors[rn2(SIZE(hcolors))] : colorpref; } /* return a random real color unless hallucinating */ const char * rndcolor() { int k = rn2(CLR_MAX); return Hallucination ? hcolor((char *)0) : (k == NO_COLOR) ? "colorless" : c_obj_colors[k]; } /* Aliases for road-runner nemesis */ static const char * const coynames[] = { "Carnivorous Vulgaris","Road-Runnerus Digestus", "Eatibus Anythingus" ,"Famishus-Famishus", "Eatibus Almost Anythingus","Eatius Birdius", "Famishius Fantasticus","Eternalii Famishiis", "Famishus Vulgarus","Famishius Vulgaris Ingeniusi", "Eatius-Slobbius","Hardheadipus Oedipus", "Carnivorous Slobbius","Hard-Headipus Ravenus", "Evereadii Eatibus","Apetitius Giganticus", "Hungrii Flea-Bagius","Overconfidentii Vulgaris", "Caninus Nervous Rex","Grotesques Appetitus", "Nemesis Riduclii","Canis latrans" }; char * coyotename(mtmp, buf) struct monst *mtmp; char *buf; { if (mtmp && buf) { Sprintf(buf, "%s - %s", x_monnam(mtmp, ARTICLE_NONE, (char *)0, 0, TRUE), mtmp->mcan ? coynames[SIZE(coynames)-1] : coynames[rn2(SIZE(coynames)-1)]); } return buf; } #endif /* OVL2 */ /*do_name.c*/ nethack-3.4.3/src/do_wear.c0100644000000000000000000015513307764735041014235 0ustar rootroot/* SCCS Id: @(#)do_wear.c 3.4 2003/11/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifndef OVLB STATIC_DCL long takeoff_mask, taking_off; #else /* OVLB */ STATIC_OVL NEARDATA long takeoff_mask = 0L; static NEARDATA long taking_off = 0L; static NEARDATA int todelay; static boolean cancelled_don = FALSE; static NEARDATA const char see_yourself[] = "see yourself"; static NEARDATA const char unknown_type[] = "Unknown type of %s (%d)"; static NEARDATA const char c_armor[] = "armor", c_suit[] = "suit", #ifdef TOURIST c_shirt[] = "shirt", #endif c_cloak[] = "cloak", c_gloves[] = "gloves", c_boots[] = "boots", c_helmet[] = "helmet", c_shield[] = "shield", c_weapon[] = "weapon", c_sword[] = "sword", c_axe[] = "axe", c_that_[] = "that"; static NEARDATA const long takeoff_order[] = { WORN_BLINDF, W_WEP, WORN_SHIELD, WORN_GLOVES, LEFT_RING, RIGHT_RING, WORN_CLOAK, WORN_HELMET, WORN_AMUL, WORN_ARMOR, #ifdef TOURIST WORN_SHIRT, #endif WORN_BOOTS, W_SWAPWEP, W_QUIVER, 0L }; STATIC_DCL void FDECL(on_msg, (struct obj *)); STATIC_PTR int NDECL(Armor_on); STATIC_PTR int NDECL(Boots_on); STATIC_DCL int NDECL(Cloak_on); STATIC_PTR int NDECL(Helmet_on); STATIC_PTR int NDECL(Gloves_on); STATIC_PTR int NDECL(Shield_on); #ifdef TOURIST STATIC_PTR int NDECL(Shirt_on); #endif STATIC_DCL void NDECL(Amulet_on); STATIC_DCL void FDECL(Ring_off_or_gone, (struct obj *, BOOLEAN_P)); STATIC_PTR int FDECL(select_off, (struct obj *)); STATIC_DCL struct obj *NDECL(do_takeoff); STATIC_PTR int NDECL(take_off); STATIC_DCL int FDECL(menu_remarm, (int)); STATIC_DCL void FDECL(already_wearing, (const char*)); STATIC_DCL void FDECL(already_wearing2, (const char*, const char*)); void off_msg(otmp) register struct obj *otmp; { if(flags.verbose) You("were wearing %s.", doname(otmp)); } /* for items that involve no delay */ STATIC_OVL void on_msg(otmp) register struct obj *otmp; { if (flags.verbose) { char how[BUFSZ]; how[0] = '\0'; if (otmp->otyp == TOWEL) Sprintf(how, " around your %s", body_part(HEAD)); You("are now wearing %s%s.", obj_is_pname(otmp) ? the(xname(otmp)) : an(xname(otmp)), how); } } /* * The Type_on() functions should be called *after* setworn(). * The Type_off() functions call setworn() themselves. */ STATIC_PTR int Boots_on() { long oldprop = u.uprops[objects[uarmf->otyp].oc_oprop].extrinsic & ~WORN_BOOTS; switch(uarmf->otyp) { case LOW_BOOTS: case IRON_SHOES: case HIGH_BOOTS: case JUMPING_BOOTS: case KICKING_BOOTS: break; case WATER_WALKING_BOOTS: if (u.uinwater) spoteffects(TRUE); break; case SPEED_BOOTS: /* Speed boots are still better than intrinsic speed, */ /* though not better than potion speed */ if (!oldprop && !(HFast & TIMEOUT)) { makeknown(uarmf->otyp); You_feel("yourself speed up%s.", (oldprop || HFast) ? " a bit more" : ""); } break; case ELVEN_BOOTS: if (!oldprop && !HStealth && !BStealth) { makeknown(uarmf->otyp); You("walk very quietly."); } break; case FUMBLE_BOOTS: if (!oldprop && !(HFumbling & ~TIMEOUT)) incr_itimeout(&HFumbling, rnd(20)); break; case LEVITATION_BOOTS: if (!oldprop && !HLevitation) { makeknown(uarmf->otyp); float_up(); spoteffects(FALSE); } break; default: impossible(unknown_type, c_boots, uarmf->otyp); } return 0; } int Boots_off() { int otyp = uarmf->otyp; long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_BOOTS; takeoff_mask &= ~W_ARMF; /* For levitation, float_down() returns if Levitation, so we * must do a setworn() _before_ the levitation case. */ setworn((struct obj *)0, W_ARMF); switch (otyp) { case SPEED_BOOTS: if (!Very_fast && !cancelled_don) { makeknown(otyp); You_feel("yourself slow down%s.", Fast ? " a bit" : ""); } break; case WATER_WALKING_BOOTS: if (is_pool(u.ux,u.uy) && !Levitation && !Flying && !is_clinger(youmonst.data) && !cancelled_don) { makeknown(otyp); /* make boots known in case you survive the drowning */ spoteffects(TRUE); } break; case ELVEN_BOOTS: if (!oldprop && !HStealth && !BStealth && !cancelled_don) { makeknown(otyp); You("sure are noisy."); } break; case FUMBLE_BOOTS: if (!oldprop && !(HFumbling & ~TIMEOUT)) HFumbling = EFumbling = 0; break; case LEVITATION_BOOTS: if (!oldprop && !HLevitation && !cancelled_don) { (void) float_down(0L, 0L); makeknown(otyp); } break; case LOW_BOOTS: case IRON_SHOES: case HIGH_BOOTS: case JUMPING_BOOTS: case KICKING_BOOTS: break; default: impossible(unknown_type, c_boots, otyp); } cancelled_don = FALSE; return 0; } STATIC_OVL int Cloak_on() { long oldprop = u.uprops[objects[uarmc->otyp].oc_oprop].extrinsic & ~WORN_CLOAK; switch(uarmc->otyp) { case ELVEN_CLOAK: case CLOAK_OF_PROTECTION: case CLOAK_OF_DISPLACEMENT: makeknown(uarmc->otyp); break; case ORCISH_CLOAK: case DWARVISH_CLOAK: case CLOAK_OF_MAGIC_RESISTANCE: case ROBE: case LEATHER_CLOAK: break; case MUMMY_WRAPPING: /* Note: it's already being worn, so we have to cheat here. */ if ((HInvis || EInvis || pm_invisible(youmonst.data)) && !Blind) { newsym(u.ux,u.uy); You("can %s!", See_invisible ? "no longer see through yourself" : see_yourself); } break; case CLOAK_OF_INVISIBILITY: /* since cloak of invisibility was worn, we know mummy wrapping wasn't, so no need to check `oldprop' against blocked */ if (!oldprop && !HInvis && !Blind) { makeknown(uarmc->otyp); newsym(u.ux,u.uy); pline("Suddenly you can%s yourself.", See_invisible ? " see through" : "not see"); } break; case OILSKIN_CLOAK: pline("%s very tightly.", Tobjnam(uarmc, "fit")); break; /* Alchemy smock gives poison _and_ acid resistance */ case ALCHEMY_SMOCK: EAcid_resistance |= WORN_CLOAK; break; default: impossible(unknown_type, c_cloak, uarmc->otyp); } return 0; } int Cloak_off() { int otyp = uarmc->otyp; long oldprop = u.uprops[objects[otyp].oc_oprop].extrinsic & ~WORN_CLOAK; takeoff_mask &= ~W_ARMC; /* For mummy wrapping, taking it off first resets `Invisible'. */ setworn((struct obj *)0, W_ARMC); switch (otyp) { case ELVEN_CLOAK: case ORCISH_CLOAK: case DWARVISH_CLOAK: case CLOAK_OF_PROTECTION: case CLOAK_OF_MAGIC_RESISTANCE: case CLOAK_OF_DISPLACEMENT: case OILSKIN_CLOAK: case ROBE: case LEATHER_CLOAK: break; case MUMMY_WRAPPING: if (Invis && !Blind) { newsym(u.ux,u.uy); You("can %s.", See_invisible ? "see through yourself" : "no longer see yourself"); } break; case CLOAK_OF_INVISIBILITY: if (!oldprop && !HInvis && !Blind) { makeknown(CLOAK_OF_INVISIBILITY); newsym(u.ux,u.uy); pline("Suddenly you can %s.", See_invisible ? "no longer see through yourself" : see_yourself); } break; /* Alchemy smock gives poison _and_ acid resistance */ case ALCHEMY_SMOCK: EAcid_resistance &= ~WORN_CLOAK; break; default: impossible(unknown_type, c_cloak, otyp); } return 0; } STATIC_PTR int Helmet_on() { switch(uarmh->otyp) { case FEDORA: case HELMET: case DENTED_POT: case ELVEN_LEATHER_HELM: case DWARVISH_IRON_HELM: case ORCISH_HELM: case HELM_OF_TELEPATHY: break; case HELM_OF_BRILLIANCE: adj_abon(uarmh, uarmh->spe); break; case CORNUTHAUM: /* people think marked wizards know what they're talking * about, but it takes trained arrogance to pull it off, * and the actual enchantment of the hat is irrelevant. */ ABON(A_CHA) += (Role_if(PM_WIZARD) ? 1 : -1); flags.botl = 1; makeknown(uarmh->otyp); break; case HELM_OF_OPPOSITE_ALIGNMENT: if (u.ualign.type == A_NEUTRAL) u.ualign.type = rn2(2) ? A_CHAOTIC : A_LAWFUL; else u.ualign.type = -(u.ualign.type); u.ublessed = 0; /* lose your god's protection */ /* makeknown(uarmh->otyp); -- moved below, after xname() */ /*FALLTHRU*/ case DUNCE_CAP: if (!uarmh->cursed) { if (Blind) pline("%s for a moment.", Tobjnam(uarmh, "vibrate")); else pline("%s %s for a moment.", Tobjnam(uarmh, "glow"), hcolor(NH_BLACK)); curse(uarmh); } flags.botl = 1; /* reveal new alignment or INT & WIS */ if (Hallucination) { pline("My brain hurts!"); /* Monty Python's Flying Circus */ } else if (uarmh->otyp == DUNCE_CAP) { You_feel("%s.", /* track INT change; ignore WIS */ ACURR(A_INT) <= (ABASE(A_INT) + ABON(A_INT) + ATEMP(A_INT)) ? "like sitting in a corner" : "giddy"); } else { Your("mind oscillates briefly."); makeknown(HELM_OF_OPPOSITE_ALIGNMENT); } break; default: impossible(unknown_type, c_helmet, uarmh->otyp); } return 0; } int Helmet_off() { takeoff_mask &= ~W_ARMH; switch(uarmh->otyp) { case FEDORA: case HELMET: case DENTED_POT: case ELVEN_LEATHER_HELM: case DWARVISH_IRON_HELM: case ORCISH_HELM: break; case DUNCE_CAP: flags.botl = 1; break; case CORNUTHAUM: if (!cancelled_don) { ABON(A_CHA) += (Role_if(PM_WIZARD) ? -1 : 1); flags.botl = 1; } break; case HELM_OF_TELEPATHY: /* need to update ability before calling see_monsters() */ setworn((struct obj *)0, W_ARMH); see_monsters(); return 0; case HELM_OF_BRILLIANCE: if (!cancelled_don) adj_abon(uarmh, -uarmh->spe); break; case HELM_OF_OPPOSITE_ALIGNMENT: u.ualign.type = u.ualignbase[A_CURRENT]; u.ublessed = 0; /* lose the other god's protection */ flags.botl = 1; break; default: impossible(unknown_type, c_helmet, uarmh->otyp); } setworn((struct obj *)0, W_ARMH); cancelled_don = FALSE; return 0; } STATIC_PTR int Gloves_on() { long oldprop = u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES; switch(uarmg->otyp) { case LEATHER_GLOVES: break; case GAUNTLETS_OF_FUMBLING: if (!oldprop && !(HFumbling & ~TIMEOUT)) incr_itimeout(&HFumbling, rnd(20)); break; case GAUNTLETS_OF_POWER: makeknown(uarmg->otyp); flags.botl = 1; /* taken care of in attrib.c */ break; case GAUNTLETS_OF_DEXTERITY: adj_abon(uarmg, uarmg->spe); break; default: impossible(unknown_type, c_gloves, uarmg->otyp); } return 0; } int Gloves_off() { long oldprop = u.uprops[objects[uarmg->otyp].oc_oprop].extrinsic & ~WORN_GLOVES; takeoff_mask &= ~W_ARMG; switch(uarmg->otyp) { case LEATHER_GLOVES: break; case GAUNTLETS_OF_FUMBLING: if (!oldprop && !(HFumbling & ~TIMEOUT)) HFumbling = EFumbling = 0; break; case GAUNTLETS_OF_POWER: makeknown(uarmg->otyp); flags.botl = 1; /* taken care of in attrib.c */ break; case GAUNTLETS_OF_DEXTERITY: if (!cancelled_don) adj_abon(uarmg, -uarmg->spe); break; default: impossible(unknown_type, c_gloves, uarmg->otyp); } setworn((struct obj *)0, W_ARMG); cancelled_don = FALSE; (void) encumber_msg(); /* immediate feedback for GoP */ /* Prevent wielding cockatrice when not wearing gloves */ if (uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm])) { char kbuf[BUFSZ]; You("wield the %s in your bare %s.", corpse_xname(uwep, TRUE), makeplural(body_part(HAND))); Strcpy(kbuf, an(corpse_xname(uwep, TRUE))); instapetrify(kbuf); uwepgone(); /* life-saved still doesn't allow touching cockatrice */ } /* KMH -- ...or your secondary weapon when you're wielding it */ if (u.twoweap && uswapwep && uswapwep->otyp == CORPSE && touch_petrifies(&mons[uswapwep->corpsenm])) { char kbuf[BUFSZ]; You("wield the %s in your bare %s.", corpse_xname(uswapwep, TRUE), body_part(HAND)); Strcpy(kbuf, an(corpse_xname(uswapwep, TRUE))); instapetrify(kbuf); uswapwepgone(); /* lifesaved still doesn't allow touching cockatrice */ } return 0; } STATIC_OVL int Shield_on() { /* switch (uarms->otyp) { case SMALL_SHIELD: case ELVEN_SHIELD: case URUK_HAI_SHIELD: case ORCISH_SHIELD: case DWARVISH_ROUNDSHIELD: case LARGE_SHIELD: case SHIELD_OF_REFLECTION: break; default: impossible(unknown_type, c_shield, uarms->otyp); } */ return 0; } int Shield_off() { takeoff_mask &= ~W_ARMS; /* switch (uarms->otyp) { case SMALL_SHIELD: case ELVEN_SHIELD: case URUK_HAI_SHIELD: case ORCISH_SHIELD: case DWARVISH_ROUNDSHIELD: case LARGE_SHIELD: case SHIELD_OF_REFLECTION: break; default: impossible(unknown_type, c_shield, uarms->otyp); } */ setworn((struct obj *)0, W_ARMS); return 0; } #ifdef TOURIST STATIC_OVL int Shirt_on() { /* switch (uarmu->otyp) { case HAWAIIAN_SHIRT: case T_SHIRT: break; default: impossible(unknown_type, c_shirt, uarmu->otyp); } */ return 0; } int Shirt_off() { takeoff_mask &= ~W_ARMU; /* switch (uarmu->otyp) { case HAWAIIAN_SHIRT: case T_SHIRT: break; default: impossible(unknown_type, c_shirt, uarmu->otyp); } */ setworn((struct obj *)0, W_ARMU); return 0; } #endif /*TOURIST*/ /* This must be done in worn.c, because one of the possible intrinsics conferred * is fire resistance, and we have to immediately set HFire_resistance in worn.c * since worn.c will check it before returning. */ STATIC_PTR int Armor_on() { return 0; } int Armor_off() { takeoff_mask &= ~W_ARM; setworn((struct obj *)0, W_ARM); cancelled_don = FALSE; return 0; } /* The gone functions differ from the off functions in that if you die from * taking it off and have life saving, you still die. */ int Armor_gone() { takeoff_mask &= ~W_ARM; setnotworn(uarm); cancelled_don = FALSE; return 0; } STATIC_OVL void Amulet_on() { switch(uamul->otyp) { case AMULET_OF_ESP: case AMULET_OF_LIFE_SAVING: case AMULET_VERSUS_POISON: case AMULET_OF_REFLECTION: case AMULET_OF_MAGICAL_BREATHING: case FAKE_AMULET_OF_YENDOR: break; case AMULET_OF_UNCHANGING: if (Slimed) { Slimed = 0; flags.botl = 1; } break; case AMULET_OF_CHANGE: { int orig_sex = poly_gender(); if (Unchanging) break; change_sex(); /* Don't use same message as polymorph */ if (orig_sex != poly_gender()) { makeknown(AMULET_OF_CHANGE); You("are suddenly very %s!", flags.female ? "feminine" : "masculine"); flags.botl = 1; } else /* already polymorphed into single-gender monster; only changed the character's base sex */ You("don't feel like yourself."); pline_The("amulet disintegrates!"); if (orig_sex == poly_gender() && uamul->dknown && !objects[AMULET_OF_CHANGE].oc_name_known && !objects[AMULET_OF_CHANGE].oc_uname) docall(uamul); useup(uamul); break; } case AMULET_OF_STRANGULATION: makeknown(AMULET_OF_STRANGULATION); pline("It constricts your throat!"); Strangled = 6; break; case AMULET_OF_RESTFUL_SLEEP: HSleeping = rnd(100); break; case AMULET_OF_YENDOR: break; } } void Amulet_off() { takeoff_mask &= ~W_AMUL; switch(uamul->otyp) { case AMULET_OF_ESP: /* need to update ability before calling see_monsters() */ setworn((struct obj *)0, W_AMUL); see_monsters(); return; case AMULET_OF_LIFE_SAVING: case AMULET_VERSUS_POISON: case AMULET_OF_REFLECTION: case AMULET_OF_CHANGE: case AMULET_OF_UNCHANGING: case FAKE_AMULET_OF_YENDOR: break; case AMULET_OF_MAGICAL_BREATHING: if (Underwater) { /* HMagical_breathing must be set off before calling drown() */ setworn((struct obj *)0, W_AMUL); if (!breathless(youmonst.data) && !amphibious(youmonst.data) && !Swimming) { You("suddenly inhale an unhealthy amount of water!"); (void) drown(); } return; } break; case AMULET_OF_STRANGULATION: if (Strangled) { You("can breathe more easily!"); Strangled = 0; } break; case AMULET_OF_RESTFUL_SLEEP: setworn((struct obj *)0, W_AMUL); if (!ESleeping) HSleeping = 0; return; case AMULET_OF_YENDOR: break; } setworn((struct obj *)0, W_AMUL); return; } void Ring_on(obj) register struct obj *obj; { long oldprop = u.uprops[objects[obj->otyp].oc_oprop].extrinsic; int old_attrib, which; if (obj == uwep) setuwep((struct obj *) 0); if (obj == uswapwep) setuswapwep((struct obj *) 0); if (obj == uquiver) setuqwep((struct obj *) 0); /* only mask out W_RING when we don't have both left and right rings of the same type */ if ((oldprop & W_RING) != W_RING) oldprop &= ~W_RING; switch(obj->otyp){ case RIN_TELEPORTATION: case RIN_REGENERATION: case RIN_SEARCHING: case RIN_STEALTH: case RIN_HUNGER: case RIN_AGGRAVATE_MONSTER: case RIN_POISON_RESISTANCE: case RIN_FIRE_RESISTANCE: case RIN_COLD_RESISTANCE: case RIN_SHOCK_RESISTANCE: case RIN_CONFLICT: case RIN_TELEPORT_CONTROL: case RIN_POLYMORPH: case RIN_POLYMORPH_CONTROL: case RIN_FREE_ACTION: case RIN_SLOW_DIGESTION: case RIN_SUSTAIN_ABILITY: case MEAT_RING: break; case RIN_WARNING: see_monsters(); break; case RIN_SEE_INVISIBLE: /* can now see invisible monsters */ set_mimic_blocking(); /* do special mimic handling */ see_monsters(); #ifdef INVISIBLE_OBJECTS see_objects(); #endif if (Invis && !oldprop && !HSee_invisible && !perceives(youmonst.data) && !Blind) { newsym(u.ux,u.uy); pline("Suddenly you are transparent, but there!"); makeknown(RIN_SEE_INVISIBLE); } break; case RIN_INVISIBILITY: if (!oldprop && !HInvis && !BInvis && !Blind) { makeknown(RIN_INVISIBILITY); newsym(u.ux,u.uy); self_invis_message(); } break; case RIN_LEVITATION: if (!oldprop && !HLevitation) { float_up(); makeknown(RIN_LEVITATION); spoteffects(FALSE); /* for sinks */ } break; case RIN_GAIN_STRENGTH: which = A_STR; goto adjust_attrib; case RIN_GAIN_CONSTITUTION: which = A_CON; goto adjust_attrib; case RIN_ADORNMENT: which = A_CHA; adjust_attrib: old_attrib = ACURR(which); ABON(which) += obj->spe; if (ACURR(which) != old_attrib || (objects[obj->otyp].oc_name_known && old_attrib != 25 && old_attrib != 3)) { flags.botl = 1; makeknown(obj->otyp); obj->known = 1; update_inventory(); } break; case RIN_INCREASE_ACCURACY: /* KMH */ u.uhitinc += obj->spe; break; case RIN_INCREASE_DAMAGE: u.udaminc += obj->spe; break; case RIN_PROTECTION_FROM_SHAPE_CHAN: rescham(); break; case RIN_PROTECTION: if (obj->spe || objects[RIN_PROTECTION].oc_name_known) { flags.botl = 1; makeknown(RIN_PROTECTION); obj->known = 1; update_inventory(); } break; } } STATIC_OVL void Ring_off_or_gone(obj,gone) register struct obj *obj; boolean gone; { long mask = (obj->owornmask & W_RING); int old_attrib, which; takeoff_mask &= ~mask; if(!(u.uprops[objects[obj->otyp].oc_oprop].extrinsic & mask)) impossible("Strange... I didn't know you had that ring."); if(gone) setnotworn(obj); else setworn((struct obj *)0, obj->owornmask); switch(obj->otyp) { case RIN_TELEPORTATION: case RIN_REGENERATION: case RIN_SEARCHING: case RIN_STEALTH: case RIN_HUNGER: case RIN_AGGRAVATE_MONSTER: case RIN_POISON_RESISTANCE: case RIN_FIRE_RESISTANCE: case RIN_COLD_RESISTANCE: case RIN_SHOCK_RESISTANCE: case RIN_CONFLICT: case RIN_TELEPORT_CONTROL: case RIN_POLYMORPH: case RIN_POLYMORPH_CONTROL: case RIN_FREE_ACTION: case RIN_SLOW_DIGESTION: case RIN_SUSTAIN_ABILITY: case MEAT_RING: break; case RIN_WARNING: see_monsters(); break; case RIN_SEE_INVISIBLE: /* Make invisible monsters go away */ if (!See_invisible) { set_mimic_blocking(); /* do special mimic handling */ see_monsters(); #ifdef INVISIBLE_OBJECTS see_objects(); #endif } if (Invisible && !Blind) { newsym(u.ux,u.uy); pline("Suddenly you cannot see yourself."); makeknown(RIN_SEE_INVISIBLE); } break; case RIN_INVISIBILITY: if (!Invis && !BInvis && !Blind) { newsym(u.ux,u.uy); Your("body seems to unfade%s.", See_invisible ? " completely" : ".."); makeknown(RIN_INVISIBILITY); } break; case RIN_LEVITATION: (void) float_down(0L, 0L); if (!Levitation) makeknown(RIN_LEVITATION); break; case RIN_GAIN_STRENGTH: which = A_STR; goto adjust_attrib; case RIN_GAIN_CONSTITUTION: which = A_CON; goto adjust_attrib; case RIN_ADORNMENT: which = A_CHA; adjust_attrib: old_attrib = ACURR(which); ABON(which) -= obj->spe; if (ACURR(which) != old_attrib) { flags.botl = 1; makeknown(obj->otyp); obj->known = 1; update_inventory(); } break; case RIN_INCREASE_ACCURACY: /* KMH */ u.uhitinc -= obj->spe; break; case RIN_INCREASE_DAMAGE: u.udaminc -= obj->spe; break; case RIN_PROTECTION: /* might have forgotten it due to amnesia */ if (obj->spe) { flags.botl = 1; makeknown(RIN_PROTECTION); obj->known = 1; update_inventory(); } case RIN_PROTECTION_FROM_SHAPE_CHAN: /* If you're no longer protected, let the chameleons * change shape again -dgk */ restartcham(); break; } } void Ring_off(obj) struct obj *obj; { Ring_off_or_gone(obj,FALSE); } void Ring_gone(obj) struct obj *obj; { Ring_off_or_gone(obj,TRUE); } void Blindf_on(otmp) register struct obj *otmp; { boolean already_blind = Blind, changed = FALSE; if (otmp == uwep) setuwep((struct obj *) 0); if (otmp == uswapwep) setuswapwep((struct obj *) 0); if (otmp == uquiver) setuqwep((struct obj *) 0); setworn(otmp, W_TOOL); on_msg(otmp); if (Blind && !already_blind) { changed = TRUE; if (flags.verbose) You_cant("see any more."); /* set ball&chain variables before the hero goes blind */ if (Punished) set_bc(0); } else if (already_blind && !Blind) { changed = TRUE; /* "You are now wearing the Eyes of the Overworld." */ You("can see!"); } if (changed) { /* blindness has just been toggled */ if (Blind_telepat || Infravision) see_monsters(); vision_full_recalc = 1; /* recalc vision limits */ flags.botl = 1; } } void Blindf_off(otmp) register struct obj *otmp; { boolean was_blind = Blind, changed = FALSE; takeoff_mask &= ~W_TOOL; setworn((struct obj *)0, otmp->owornmask); off_msg(otmp); if (Blind) { if (was_blind) { /* "still cannot see" makes no sense when removing lenses since they can't have been the cause of your blindness */ if (otmp->otyp != LENSES) You("still cannot see."); } else { changed = TRUE; /* !was_blind */ /* "You were wearing the Eyes of the Overworld." */ You_cant("see anything now!"); /* set ball&chain variables before the hero goes blind */ if (Punished) set_bc(0); } } else if (was_blind) { changed = TRUE; /* !Blind */ You("can see again."); } if (changed) { /* blindness has just been toggled */ if (Blind_telepat || Infravision) see_monsters(); vision_full_recalc = 1; /* recalc vision limits */ flags.botl = 1; } } /* called in main to set intrinsics of worn start-up items */ void set_wear() { #ifdef TOURIST if (uarmu) (void) Shirt_on(); #endif if (uarm) (void) Armor_on(); if (uarmc) (void) Cloak_on(); if (uarmf) (void) Boots_on(); if (uarmg) (void) Gloves_on(); if (uarmh) (void) Helmet_on(); if (uarms) (void) Shield_on(); } /* check whether the target object is currently being put on (or taken off) */ boolean donning(otmp) /* also checks for doffing */ register struct obj *otmp; { /* long what = (occupation == take_off) ? taking_off : 0L; */ long what = taking_off; /* if nonzero, occupation is implied */ boolean result = FALSE; if (otmp == uarm) result = (afternmv == Armor_on || afternmv == Armor_off || what == WORN_ARMOR); #ifdef TOURIST else if (otmp == uarmu) result = (afternmv == Shirt_on || afternmv == Shirt_off || what == WORN_SHIRT); #endif else if (otmp == uarmc) result = (afternmv == Cloak_on || afternmv == Cloak_off || what == WORN_CLOAK); else if (otmp == uarmf) result = (afternmv == Boots_on || afternmv == Boots_off || what == WORN_BOOTS); else if (otmp == uarmh) result = (afternmv == Helmet_on || afternmv == Helmet_off || what == WORN_HELMET); else if (otmp == uarmg) result = (afternmv == Gloves_on || afternmv == Gloves_off || what == WORN_GLOVES); else if (otmp == uarms) result = (afternmv == Shield_on || afternmv == Shield_off || what == WORN_SHIELD); return result; } void cancel_don() { /* the piece of armor we were donning/doffing has vanished, so stop * wasting time on it (and don't dereference it when donning would * otherwise finish) */ cancelled_don = (afternmv == Boots_on || afternmv == Helmet_on || afternmv == Gloves_on || afternmv == Armor_on); afternmv = 0; nomovemsg = (char *)0; multi = 0; todelay = 0; taking_off = 0L; } static NEARDATA const char clothes[] = {ARMOR_CLASS, 0}; static NEARDATA const char accessories[] = {RING_CLASS, AMULET_CLASS, TOOL_CLASS, FOOD_CLASS, 0}; /* the 'T' command */ int dotakeoff() { register struct obj *otmp = (struct obj *)0; int armorpieces = 0; #define MOREARM(x) if (x) { armorpieces++; otmp = x; } MOREARM(uarmh); MOREARM(uarms); MOREARM(uarmg); MOREARM(uarmf); if (uarmc) { armorpieces++; otmp = uarmc; } else if (uarm) { armorpieces++; otmp = uarm; #ifdef TOURIST } else if (uarmu) { armorpieces++; otmp = uarmu; #endif } if (!armorpieces) { /* assert( GRAY_DRAGON_SCALES > YELLOW_DRAGON_SCALE_MAIL ); */ if (uskin) pline_The("%s merged with your skin!", uskin->otyp >= GRAY_DRAGON_SCALES ? "dragon scales are" : "dragon scale mail is"); else pline("Not wearing any armor.%s", (iflags.cmdassist && (uleft || uright || uamul || ublindf)) ? " Use 'R' command to remove accessories." : ""); return 0; } if (armorpieces > 1) otmp = getobj(clothes, "take off"); if (otmp == 0) return(0); if (!(otmp->owornmask & W_ARMOR)) { You("are not wearing that."); return(0); } /* note: the `uskin' case shouldn't be able to happen here; dragons can't wear any armor so will end up with `armorpieces == 0' above */ if (otmp == uskin || ((otmp == uarm) && uarmc) #ifdef TOURIST || ((otmp == uarmu) && (uarmc || uarm)) #endif ) { You_cant("take that off."); return 0; } reset_remarm(); /* clear takeoff_mask and taking_off */ (void) select_off(otmp); if (!takeoff_mask) return 0; reset_remarm(); /* armoroff() doesn't use takeoff_mask */ (void) armoroff(otmp); return(1); } /* the 'R' command */ int doremring() { register struct obj *otmp = 0; int Accessories = 0; #define MOREACC(x) if (x) { Accessories++; otmp = x; } MOREACC(uleft); MOREACC(uright); MOREACC(uamul); MOREACC(ublindf); if(!Accessories) { pline("Not wearing any accessories.%s", (iflags.cmdassist && (uarm || uarmc || #ifdef TOURIST uarmu || #endif uarms || uarmh || uarmg || uarmf)) ? " Use 'T' command to take off armor." : ""); return(0); } if (Accessories != 1) otmp = getobj(accessories, "remove"); if(!otmp) return(0); if(!(otmp->owornmask & (W_RING | W_AMUL | W_TOOL))) { You("are not wearing that."); return(0); } reset_remarm(); /* clear takeoff_mask and taking_off */ (void) select_off(otmp); if (!takeoff_mask) return 0; reset_remarm(); /* not used by Ring_/Amulet_/Blindf_off() */ if (otmp == uright || otmp == uleft) { /* Sometimes we want to give the off_msg before removing and * sometimes after; for instance, "you were wearing a moonstone * ring (on right hand)" is desired but "you were wearing a * square amulet (being worn)" is not because of the redundant * "being worn". */ off_msg(otmp); Ring_off(otmp); } else if (otmp == uamul) { Amulet_off(); off_msg(otmp); } else if (otmp == ublindf) { Blindf_off(otmp); /* does its own off_msg */ } else { impossible("removing strange accessory?"); } return(1); } /* Check if something worn is cursed _and_ unremovable. */ int cursed(otmp) register struct obj *otmp; { /* Curses, like chickens, come home to roost. */ if((otmp == uwep) ? welded(otmp) : (int)otmp->cursed) { You("can't. %s cursed.", (is_boots(otmp) || is_gloves(otmp) || otmp->quan > 1L) ? "They are" : "It is"); otmp->bknown = TRUE; return(1); } return(0); } int armoroff(otmp) register struct obj *otmp; { register int delay = -objects[otmp->otyp].oc_delay; if(cursed(otmp)) return(0); if(delay) { nomul(delay); if (is_helmet(otmp)) { nomovemsg = "You finish taking off your helmet."; afternmv = Helmet_off; } else if (is_gloves(otmp)) { nomovemsg = "You finish taking off your gloves."; afternmv = Gloves_off; } else if (is_boots(otmp)) { nomovemsg = "You finish taking off your boots."; afternmv = Boots_off; } else { nomovemsg = "You finish taking off your suit."; afternmv = Armor_off; } } else { /* Be warned! We want off_msg after removing the item to * avoid "You were wearing ____ (being worn)." However, an * item which grants fire resistance might cause some trouble * if removed in Hell and lifesaving puts it back on; in this * case the message will be printed at the wrong time (after * the messages saying you died and were lifesaved). Luckily, * no cloak, shield, or fast-removable armor grants fire * resistance, so we can safely do the off_msg afterwards. * Rings do grant fire resistance, but for rings we want the * off_msg before removal anyway so there's no problem. Take * care in adding armors granting fire resistance; this code * might need modification. * 3.2 (actually 3.1 even): this comment is obsolete since * fire resistance is not needed for Gehennom. */ if(is_cloak(otmp)) (void) Cloak_off(); else if(is_shield(otmp)) (void) Shield_off(); else setworn((struct obj *)0, otmp->owornmask & W_ARMOR); off_msg(otmp); } takeoff_mask = taking_off = 0L; return(1); } STATIC_OVL void already_wearing(cc) const char *cc; { You("are already wearing %s%c", cc, (cc == c_that_) ? '!' : '.'); } STATIC_OVL void already_wearing2(cc1, cc2) const char *cc1, *cc2; { You_cant("wear %s because you're wearing %s there already.", cc1, cc2); } /* * canwearobj checks to see whether the player can wear a piece of armor * * inputs: otmp (the piece of armor) * noisy (if TRUE give error messages, otherwise be quiet about it) * output: mask (otmp's armor type) */ int canwearobj(otmp,mask,noisy) struct obj *otmp; long *mask; boolean noisy; { int err = 0; const char *which; which = is_cloak(otmp) ? c_cloak : #ifdef TOURIST is_shirt(otmp) ? c_shirt : #endif is_suit(otmp) ? c_suit : 0; if (which && cantweararm(youmonst.data) && /* same exception for cloaks as used in m_dowear() */ (which != c_cloak || youmonst.data->msize != MZ_SMALL) && (racial_exception(&youmonst, otmp) < 1)) { if (noisy) pline_The("%s will not fit on your body.", which); return 0; } else if (otmp->owornmask & W_ARMOR) { if (noisy) already_wearing(c_that_); return 0; } if (welded(uwep) && bimanual(uwep) && (is_suit(otmp) #ifdef TOURIST || is_shirt(otmp) #endif )) { if (noisy) You("cannot do that while holding your %s.", is_sword(uwep) ? c_sword : c_weapon); return 0; } if (is_helmet(otmp)) { if (uarmh) { if (noisy) already_wearing(an(c_helmet)); err++; } else if (Upolyd && has_horns(youmonst.data) && !is_flimsy(otmp)) { /* (flimsy exception matches polyself handling) */ if (noisy) pline_The("%s won't fit over your horn%s.", c_helmet, plur(num_horns(youmonst.data))); err++; } else *mask = W_ARMH; } else if (is_shield(otmp)) { if (uarms) { if (noisy) already_wearing(an(c_shield)); err++; } else if (uwep && bimanual(uwep)) { if (noisy) You("cannot wear a shield while wielding a two-handed %s.", is_sword(uwep) ? c_sword : (uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon); err++; } else if (u.twoweap) { if (noisy) You("cannot wear a shield while wielding two weapons."); err++; } else *mask = W_ARMS; } else if (is_boots(otmp)) { if (uarmf) { if (noisy) already_wearing(c_boots); err++; } else if (Upolyd && slithy(youmonst.data)) { if (noisy) You("have no feet..."); /* not body_part(FOOT) */ err++; } else if (Upolyd && youmonst.data->mlet == S_CENTAUR) { /* break_armor() pushes boots off for centaurs, so don't let dowear() put them back on... */ if (noisy) pline("You have too many hooves to wear %s.", c_boots); /* makeplural(body_part(FOOT)) yields "rear hooves" which sounds odd */ err++; } else if (u.utrap && (u.utraptype == TT_BEARTRAP || u.utraptype == TT_INFLOOR)) { if (u.utraptype == TT_BEARTRAP) { if (noisy) Your("%s is trapped!", body_part(FOOT)); } else { if (noisy) Your("%s are stuck in the %s!", makeplural(body_part(FOOT)), surface(u.ux, u.uy)); } err++; } else *mask = W_ARMF; } else if (is_gloves(otmp)) { if (uarmg) { if (noisy) already_wearing(c_gloves); err++; } else if (welded(uwep)) { if (noisy) You("cannot wear gloves over your %s.", is_sword(uwep) ? c_sword : c_weapon); err++; } else *mask = W_ARMG; #ifdef TOURIST } else if (is_shirt(otmp)) { if (uarm || uarmc || uarmu) { if (uarmu) { if (noisy) already_wearing(an(c_shirt)); } else { if (noisy) You_cant("wear that over your %s.", (uarm && !uarmc) ? c_armor : cloak_simple_name(uarmc)); } err++; } else *mask = W_ARMU; #endif } else if (is_cloak(otmp)) { if (uarmc) { if (noisy) already_wearing(an(cloak_simple_name(uarmc))); err++; } else *mask = W_ARMC; } else if (is_suit(otmp)) { if (uarmc) { if (noisy) You("cannot wear armor over a %s.", cloak_simple_name(uarmc)); err++; } else if (uarm) { if (noisy) already_wearing("some armor"); err++; } else *mask = W_ARM; } else { /* getobj can't do this after setting its allow_all flag; that happens if you have armor for slots that are covered up or extra armor for slots that are filled */ if (noisy) silly_thing("wear", otmp); err++; } /* Unnecessary since now only weapons and special items like pick-axes get * welded to your hand, not armor if (welded(otmp)) { if (!err++) { if (noisy) weldmsg(otmp); } } */ return !err; } /* the 'W' command */ int dowear() { struct obj *otmp; int delay; long mask = 0; /* cantweararm checks for suits of armor */ /* verysmall or nohands checks for shields, gloves, etc... */ if ((verysmall(youmonst.data) || nohands(youmonst.data))) { pline("Don't even bother."); return(0); } otmp = getobj(clothes, "wear"); if(!otmp) return(0); if (!canwearobj(otmp,&mask,TRUE)) return(0); if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) return 1; /* costs a turn even though it didn't get worn */ if (otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT && qstart_level.dnum == u.uz.dnum) { /* in quest */ if (u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL]) You("narrowly avoid losing all chance at your goal."); else /* converted */ You("are suddenly overcome with shame and change your mind."); u.ublessed = 0; /* lose your god's protection */ makeknown(otmp->otyp); flags.botl = 1; return 1; } otmp->known = TRUE; if(otmp == uwep) setuwep((struct obj *)0); if (otmp == uswapwep) setuswapwep((struct obj *) 0); if (otmp == uquiver) setuqwep((struct obj *) 0); setworn(otmp, mask); delay = -objects[otmp->otyp].oc_delay; if(delay){ nomul(delay); if(is_boots(otmp)) afternmv = Boots_on; if(is_helmet(otmp)) afternmv = Helmet_on; if(is_gloves(otmp)) afternmv = Gloves_on; if(otmp == uarm) afternmv = Armor_on; nomovemsg = "You finish your dressing maneuver."; } else { if(is_cloak(otmp)) (void) Cloak_on(); if (is_shield(otmp)) (void) Shield_on(); #ifdef TOURIST if (is_shirt(otmp)) (void) Shirt_on(); #endif on_msg(otmp); } takeoff_mask = taking_off = 0L; return(1); } int doputon() { register struct obj *otmp; long mask = 0L; if(uleft && uright && uamul && ublindf) { Your("%s%s are full, and you're already wearing an amulet and %s.", humanoid(youmonst.data) ? "ring-" : "", makeplural(body_part(FINGER)), ublindf->otyp==LENSES ? "some lenses" : "a blindfold"); return(0); } otmp = getobj(accessories, "put on"); if(!otmp) return(0); if(otmp->owornmask & (W_RING | W_AMUL | W_TOOL)) { already_wearing(c_that_); return(0); } if(welded(otmp)) { weldmsg(otmp); return(0); } if(otmp == uwep) setuwep((struct obj *)0); if(otmp == uswapwep) setuswapwep((struct obj *) 0); if(otmp == uquiver) setuqwep((struct obj *) 0); if(otmp->oclass == RING_CLASS || otmp->otyp == MEAT_RING) { if(nolimbs(youmonst.data)) { You("cannot make the ring stick to your body."); return(0); } if(uleft && uright){ There("are no more %s%s to fill.", humanoid(youmonst.data) ? "ring-" : "", makeplural(body_part(FINGER))); return(0); } if(uleft) mask = RIGHT_RING; else if(uright) mask = LEFT_RING; else do { char qbuf[QBUFSZ]; char answer; Sprintf(qbuf, "Which %s%s, Right or Left?", humanoid(youmonst.data) ? "ring-" : "", body_part(FINGER)); if(!(answer = yn_function(qbuf, "rl", '\0'))) return(0); switch(answer){ case 'l': case 'L': mask = LEFT_RING; break; case 'r': case 'R': mask = RIGHT_RING; break; } } while(!mask); if (uarmg && uarmg->cursed) { uarmg->bknown = TRUE; You("cannot remove your gloves to put on the ring."); return(0); } if (welded(uwep) && bimanual(uwep)) { /* welded will set bknown */ You("cannot free your weapon hands to put on the ring."); return(0); } if (welded(uwep) && mask==RIGHT_RING) { /* welded will set bknown */ You("cannot free your weapon hand to put on the ring."); return(0); } if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) return 1; /* costs a turn even though it didn't get worn */ setworn(otmp, mask); Ring_on(otmp); } else if (otmp->oclass == AMULET_CLASS) { if(uamul) { already_wearing("an amulet"); return(0); } if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) return 1; setworn(otmp, W_AMUL); if (otmp->otyp == AMULET_OF_CHANGE) { Amulet_on(); /* Don't do a prinv() since the amulet is now gone */ return(1); } Amulet_on(); } else { /* it's a blindfold, towel, or lenses */ if (ublindf) { if (ublindf->otyp == TOWEL) Your("%s is already covered by a towel.", body_part(FACE)); else if (ublindf->otyp == BLINDFOLD) { if (otmp->otyp == LENSES) already_wearing2("lenses", "a blindfold"); else already_wearing("a blindfold"); } else if (ublindf->otyp == LENSES) { if (otmp->otyp == BLINDFOLD) already_wearing2("a blindfold", "some lenses"); else already_wearing("some lenses"); } else already_wearing(something); /* ??? */ return(0); } if (otmp->otyp != BLINDFOLD && otmp->otyp != TOWEL && otmp->otyp != LENSES) { You_cant("wear that!"); return(0); } if (otmp->oartifact && !touch_artifact(otmp, &youmonst)) return 1; Blindf_on(otmp); return(1); } if (is_worn(otmp)) prinv((char *)0, otmp, 0L); return(1); } #endif /* OVLB */ #ifdef OVL0 void find_ac() { int uac = mons[u.umonnum].ac; if(uarm) uac -= ARM_BONUS(uarm); if(uarmc) uac -= ARM_BONUS(uarmc); if(uarmh) uac -= ARM_BONUS(uarmh); if(uarmf) uac -= ARM_BONUS(uarmf); if(uarms) uac -= ARM_BONUS(uarms); if(uarmg) uac -= ARM_BONUS(uarmg); #ifdef TOURIST if(uarmu) uac -= ARM_BONUS(uarmu); #endif if(uleft && uleft->otyp == RIN_PROTECTION) uac -= uleft->spe; if(uright && uright->otyp == RIN_PROTECTION) uac -= uright->spe; if (HProtection & INTRINSIC) uac -= u.ublessed; uac -= u.uspellprot; if (uac < -128) uac = -128; /* u.uac is an schar */ if(uac != u.uac){ u.uac = uac; flags.botl = 1; } } #endif /* OVL0 */ #ifdef OVLB void glibr() { register struct obj *otmp; int xfl = 0; boolean leftfall, rightfall; const char *otherwep = 0; leftfall = (uleft && !uleft->cursed && (!uwep || !welded(uwep) || !bimanual(uwep))); rightfall = (uright && !uright->cursed && (!welded(uwep))); if (!uarmg && (leftfall || rightfall) && !nolimbs(youmonst.data)) { /* changed so cursed rings don't fall off, GAN 10/30/86 */ Your("%s off your %s.", (leftfall && rightfall) ? "rings slip" : "ring slips", (leftfall && rightfall) ? makeplural(body_part(FINGER)) : body_part(FINGER)); xfl++; if (leftfall) { otmp = uleft; Ring_off(uleft); dropx(otmp); } if (rightfall) { otmp = uright; Ring_off(uright); dropx(otmp); } } otmp = uswapwep; if (u.twoweap && otmp) { otherwep = is_sword(otmp) ? c_sword : makesingular(oclass_names[(int)otmp->oclass]); Your("%s %sslips from your %s.", otherwep, xfl ? "also " : "", makeplural(body_part(HAND))); setuswapwep((struct obj *)0); xfl++; if (otmp->otyp != LOADSTONE || !otmp->cursed) dropx(otmp); } otmp = uwep; if (otmp && !welded(otmp)) { const char *thiswep; /* nice wording if both weapons are the same type */ thiswep = is_sword(otmp) ? c_sword : makesingular(oclass_names[(int)otmp->oclass]); if (otherwep && strcmp(thiswep, otherwep)) otherwep = 0; /* changed so cursed weapons don't fall, GAN 10/30/86 */ Your("%s%s %sslips from your %s.", otherwep ? "other " : "", thiswep, xfl ? "also " : "", makeplural(body_part(HAND))); setuwep((struct obj *)0); if (otmp->otyp != LOADSTONE || !otmp->cursed) dropx(otmp); } } struct obj * some_armor(victim) struct monst *victim; { register struct obj *otmph, *otmp; otmph = (victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC); if (!otmph) otmph = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM); #ifdef TOURIST if (!otmph) otmph = (victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU); #endif otmp = (victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH); if(otmp && (!otmph || !rn2(4))) otmph = otmp; otmp = (victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG); if(otmp && (!otmph || !rn2(4))) otmph = otmp; otmp = (victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF); if(otmp && (!otmph || !rn2(4))) otmph = otmp; otmp = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS); if(otmp && (!otmph || !rn2(4))) otmph = otmp; return(otmph); } /* erode some arbitrary armor worn by the victim */ void erode_armor(victim, acid_dmg) struct monst *victim; boolean acid_dmg; { struct obj *otmph = some_armor(victim); if (otmph && (otmph != uarmf)) { erode_obj(otmph, acid_dmg, FALSE); if (carried(otmph)) update_inventory(); } } /* used for praying to check and fix levitation trouble */ struct obj * stuck_ring(ring, otyp) struct obj *ring; int otyp; { if (ring != uleft && ring != uright) { impossible("stuck_ring: neither left nor right?"); return (struct obj *)0; } if (ring && ring->otyp == otyp) { /* reasons ring can't be removed match those checked by select_off(); limbless case has extra checks because ordinarily it's temporary */ if (nolimbs(youmonst.data) && uamul && uamul->otyp == AMULET_OF_UNCHANGING && uamul->cursed) return uamul; if (welded(uwep) && (ring == uright || bimanual(uwep))) return uwep; if (uarmg && uarmg->cursed) return uarmg; if (ring->cursed) return ring; } /* either no ring or not right type or nothing prevents its removal */ return (struct obj *)0; } /* also for praying; find worn item that confers "Unchanging" attribute */ struct obj * unchanger() { if (uamul && uamul->otyp == AMULET_OF_UNCHANGING) return uamul; return 0; } /* occupation callback for 'A' */ STATIC_PTR int select_off(otmp) register struct obj *otmp; { struct obj *why; char buf[BUFSZ]; if (!otmp) return 0; *buf = '\0'; /* lint suppresion */ /* special ring checks */ if (otmp == uright || otmp == uleft) { if (nolimbs(youmonst.data)) { pline_The("ring is stuck."); return 0; } why = 0; /* the item which prevents ring removal */ if (welded(uwep) && (otmp == uright || bimanual(uwep))) { Sprintf(buf, "free a weapon %s", body_part(HAND)); why = uwep; } else if (uarmg && uarmg->cursed) { Sprintf(buf, "take off your %s", c_gloves); why = uarmg; } if (why) { You("cannot %s to remove the ring.", buf); why->bknown = TRUE; return 0; } } /* special glove checks */ if (otmp == uarmg) { if (welded(uwep)) { You("are unable to take off your %s while wielding that %s.", c_gloves, is_sword(uwep) ? c_sword : c_weapon); uwep->bknown = TRUE; return 0; } else if (Glib) { You_cant("take off the slippery %s with your slippery %s.", c_gloves, makeplural(body_part(FINGER))); return 0; } } /* special boot checks */ if (otmp == uarmf) { if (u.utrap && u.utraptype == TT_BEARTRAP) { pline_The("bear trap prevents you from pulling your %s out.", body_part(FOOT)); return 0; } else if (u.utrap && u.utraptype == TT_INFLOOR) { You("are stuck in the %s, and cannot pull your %s out.", surface(u.ux, u.uy), makeplural(body_part(FOOT))); return 0; } } /* special suit and shirt checks */ if (otmp == uarm #ifdef TOURIST || otmp == uarmu #endif ) { why = 0; /* the item which prevents disrobing */ if (uarmc && uarmc->cursed) { Sprintf(buf, "remove your %s", cloak_simple_name(uarmc)); why = uarmc; #ifdef TOURIST } else if (otmp == uarmu && uarm && uarm->cursed) { Sprintf(buf, "remove your %s", c_suit); why = uarm; #endif } else if (welded(uwep) && bimanual(uwep)) { Sprintf(buf, "release your %s", is_sword(uwep) ? c_sword : (uwep->otyp == BATTLE_AXE) ? c_axe : c_weapon); why = uwep; } if (why) { You("cannot %s to take off %s.", buf, the(xname(otmp))); why->bknown = TRUE; return 0; } } /* basic curse check */ if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) { ; /* some items can be removed even when cursed */ } else { /* otherwise, this is fundamental */ if (cursed(otmp)) return 0; } if(otmp == uarm) takeoff_mask |= WORN_ARMOR; else if(otmp == uarmc) takeoff_mask |= WORN_CLOAK; else if(otmp == uarmf) takeoff_mask |= WORN_BOOTS; else if(otmp == uarmg) takeoff_mask |= WORN_GLOVES; else if(otmp == uarmh) takeoff_mask |= WORN_HELMET; else if(otmp == uarms) takeoff_mask |= WORN_SHIELD; #ifdef TOURIST else if(otmp == uarmu) takeoff_mask |= WORN_SHIRT; #endif else if(otmp == uleft) takeoff_mask |= LEFT_RING; else if(otmp == uright) takeoff_mask |= RIGHT_RING; else if(otmp == uamul) takeoff_mask |= WORN_AMUL; else if(otmp == ublindf) takeoff_mask |= WORN_BLINDF; else if(otmp == uwep) takeoff_mask |= W_WEP; else if(otmp == uswapwep) takeoff_mask |= W_SWAPWEP; else if(otmp == uquiver) takeoff_mask |= W_QUIVER; else impossible("select_off: %s???", doname(otmp)); return(0); } STATIC_OVL struct obj * do_takeoff() { register struct obj *otmp = (struct obj *)0; if (taking_off == W_WEP) { if(!cursed(uwep)) { setuwep((struct obj *) 0); You("are empty %s.", body_part(HANDED)); u.twoweap = FALSE; } } else if (taking_off == W_SWAPWEP) { setuswapwep((struct obj *) 0); You("no longer have a second weapon readied."); u.twoweap = FALSE; } else if (taking_off == W_QUIVER) { setuqwep((struct obj *) 0); You("no longer have ammunition readied."); } else if (taking_off == WORN_ARMOR) { otmp = uarm; if(!cursed(otmp)) (void) Armor_off(); } else if (taking_off == WORN_CLOAK) { otmp = uarmc; if(!cursed(otmp)) (void) Cloak_off(); } else if (taking_off == WORN_BOOTS) { otmp = uarmf; if(!cursed(otmp)) (void) Boots_off(); } else if (taking_off == WORN_GLOVES) { otmp = uarmg; if(!cursed(otmp)) (void) Gloves_off(); } else if (taking_off == WORN_HELMET) { otmp = uarmh; if(!cursed(otmp)) (void) Helmet_off(); } else if (taking_off == WORN_SHIELD) { otmp = uarms; if(!cursed(otmp)) (void) Shield_off(); #ifdef TOURIST } else if (taking_off == WORN_SHIRT) { otmp = uarmu; if (!cursed(otmp)) (void) Shirt_off(); #endif } else if (taking_off == WORN_AMUL) { otmp = uamul; if(!cursed(otmp)) Amulet_off(); } else if (taking_off == LEFT_RING) { otmp = uleft; if(!cursed(otmp)) Ring_off(uleft); } else if (taking_off == RIGHT_RING) { otmp = uright; if(!cursed(otmp)) Ring_off(uright); } else if (taking_off == WORN_BLINDF) { if (!cursed(ublindf)) Blindf_off(ublindf); } else impossible("do_takeoff: taking off %lx", taking_off); return(otmp); } static const char *disrobing = ""; STATIC_PTR int take_off() { register int i; register struct obj *otmp; if (taking_off) { if (todelay > 0) { todelay--; return(1); /* still busy */ } else { if ((otmp = do_takeoff())) off_msg(otmp); } takeoff_mask &= ~taking_off; taking_off = 0L; } for(i = 0; takeoff_order[i]; i++) if(takeoff_mask & takeoff_order[i]) { taking_off = takeoff_order[i]; break; } otmp = (struct obj *) 0; todelay = 0; if (taking_off == 0L) { You("finish %s.", disrobing); return 0; } else if (taking_off == W_WEP) { todelay = 1; } else if (taking_off == W_SWAPWEP) { todelay = 1; } else if (taking_off == W_QUIVER) { todelay = 1; } else if (taking_off == WORN_ARMOR) { otmp = uarm; /* If a cloak is being worn, add the time to take it off and put * it back on again. Kludge alert! since that time is 0 for all * known cloaks, add 1 so that it actually matters... */ if (uarmc) todelay += 2 * objects[uarmc->otyp].oc_delay + 1; } else if (taking_off == WORN_CLOAK) { otmp = uarmc; } else if (taking_off == WORN_BOOTS) { otmp = uarmf; } else if (taking_off == WORN_GLOVES) { otmp = uarmg; } else if (taking_off == WORN_HELMET) { otmp = uarmh; } else if (taking_off == WORN_SHIELD) { otmp = uarms; #ifdef TOURIST } else if (taking_off == WORN_SHIRT) { otmp = uarmu; /* add the time to take off and put back on armor and/or cloak */ if (uarm) todelay += 2 * objects[uarm->otyp].oc_delay; if (uarmc) todelay += 2 * objects[uarmc->otyp].oc_delay + 1; #endif } else if (taking_off == WORN_AMUL) { todelay = 1; } else if (taking_off == LEFT_RING) { todelay = 1; } else if (taking_off == RIGHT_RING) { todelay = 1; } else if (taking_off == WORN_BLINDF) { todelay = 2; } else { impossible("take_off: taking off %lx", taking_off); return 0; /* force done */ } if (otmp) todelay += objects[otmp->otyp].oc_delay; /* Since setting the occupation now starts the counter next move, that * would always produce a delay 1 too big per item unless we subtract * 1 here to account for it. */ if (todelay > 0) todelay--; set_occupation(take_off, disrobing, 0); return(1); /* get busy */ } /* clear saved context to avoid inappropriate resumption of interrupted 'A' */ void reset_remarm() { taking_off = takeoff_mask = 0L; disrobing = nul; } /* the 'A' command -- remove multiple worn items */ int doddoremarm() { int result = 0; if (taking_off || takeoff_mask) { You("continue %s.", disrobing); set_occupation(take_off, disrobing, 0); return 0; } else if (!uwep && !uswapwep && !uquiver && !uamul && !ublindf && !uleft && !uright && !wearing_armor()) { You("are not wearing anything."); return 0; } add_valid_menu_class(0); /* reset */ if (flags.menu_style != MENU_TRADITIONAL || (result = ggetobj("take off", select_off, 0, FALSE, (unsigned *)0)) < -1) result = menu_remarm(result); if (takeoff_mask) { /* default activity for armor and/or accessories, possibly combined with weapons */ disrobing = "disrobing"; /* specific activity when handling weapons only */ if (!(takeoff_mask & ~(W_WEP|W_SWAPWEP|W_QUIVER))) disrobing = "disarming"; (void) take_off(); } /* The time to perform the command is already completely accounted for * in take_off(); if we return 1, that would add an extra turn to each * disrobe. */ return 0; } STATIC_OVL int menu_remarm(retry) int retry; { int n, i = 0; menu_item *pick_list; boolean all_worn_categories = TRUE; if (retry) { all_worn_categories = (retry == -2); } else if (flags.menu_style == MENU_FULL) { all_worn_categories = FALSE; n = query_category("What type of things do you want to take off?", invent, WORN_TYPES|ALL_TYPES, &pick_list, PICK_ANY); if (!n) return 0; for (i = 0; i < n; i++) { if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) all_worn_categories = TRUE; else add_valid_menu_class(pick_list[i].item.a_int); } free((genericptr_t) pick_list); } else if (flags.menu_style == MENU_COMBINATION) { all_worn_categories = FALSE; if (ggetobj("take off", select_off, 0, TRUE, (unsigned *)0) == -2) all_worn_categories = TRUE; } n = query_objlist("What do you want to take off?", invent, SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT, &pick_list, PICK_ANY, all_worn_categories ? is_worn : is_worn_by_type); if (n > 0) { for (i = 0; i < n; i++) (void) select_off(pick_list[i].item.a_obj); free((genericptr_t) pick_list); } else if (n < 0 && flags.menu_style != MENU_COMBINATION) { There("is nothing else you can remove or unwield."); } return 0; } /* hit by destroy armor scroll/black dragon breath/monster spell */ int destroy_arm(atmp) register struct obj *atmp; { register struct obj *otmp; #define DESTROY_ARM(o) ((otmp = (o)) != 0 && \ (!atmp || atmp == otmp) && \ (!obj_resists(otmp, 0, 90))) if (DESTROY_ARM(uarmc)) { if (donning(otmp)) cancel_don(); Your("%s crumbles and turns to dust!", cloak_simple_name(uarmc)); (void) Cloak_off(); useup(otmp); } else if (DESTROY_ARM(uarm)) { if (donning(otmp)) cancel_don(); Your("armor turns to dust and falls to the %s!", surface(u.ux,u.uy)); (void) Armor_gone(); useup(otmp); #ifdef TOURIST } else if (DESTROY_ARM(uarmu)) { if (donning(otmp)) cancel_don(); Your("shirt crumbles into tiny threads and falls apart!"); (void) Shirt_off(); useup(otmp); #endif } else if (DESTROY_ARM(uarmh)) { if (donning(otmp)) cancel_don(); Your("helmet turns to dust and is blown away!"); (void) Helmet_off(); useup(otmp); } else if (DESTROY_ARM(uarmg)) { if (donning(otmp)) cancel_don(); Your("gloves vanish!"); (void) Gloves_off(); useup(otmp); selftouch("You"); } else if (DESTROY_ARM(uarmf)) { if (donning(otmp)) cancel_don(); Your("boots disintegrate!"); (void) Boots_off(); useup(otmp); } else if (DESTROY_ARM(uarms)) { if (donning(otmp)) cancel_don(); Your("shield crumbles away!"); (void) Shield_off(); useup(otmp); } else { return 0; /* could not destroy anything */ } #undef DESTROY_ARM stop_occupation(); return(1); } void adj_abon(otmp, delta) register struct obj *otmp; register schar delta; { if (uarmg && uarmg == otmp && otmp->otyp == GAUNTLETS_OF_DEXTERITY) { if (delta) { makeknown(uarmg->otyp); ABON(A_DEX) += (delta); } flags.botl = 1; } if (uarmh && uarmh == otmp && otmp->otyp == HELM_OF_BRILLIANCE) { if (delta) { makeknown(uarmh->otyp); ABON(A_INT) += (delta); ABON(A_WIS) += (delta); } flags.botl = 1; } } #endif /* OVLB */ /*do_wear.c*/ nethack-3.4.3/src/dog.c0100644000000000000000000006526507764735041013374 0ustar rootroot/* SCCS Id: @(#)dog.c 3.4 2002/09/08 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "edog.h" #ifdef OVLB STATIC_DCL int NDECL(pet_type); void initedog(mtmp) register struct monst *mtmp; { mtmp->mtame = is_domestic(mtmp->data) ? 10 : 5; mtmp->mpeaceful = 1; mtmp->mavenge = 0; set_malign(mtmp); /* recalc alignment now that it's tamed */ mtmp->mleashed = 0; mtmp->meating = 0; EDOG(mtmp)->droptime = 0; EDOG(mtmp)->dropdist = 10000; EDOG(mtmp)->apport = 10; EDOG(mtmp)->whistletime = 0; EDOG(mtmp)->hungrytime = 1000 + monstermoves; EDOG(mtmp)->ogoal.x = -1; /* force error if used before set */ EDOG(mtmp)->ogoal.y = -1; EDOG(mtmp)->abuse = 0; EDOG(mtmp)->revivals = 0; EDOG(mtmp)->mhpmax_penalty = 0; EDOG(mtmp)->killed_by_u = 0; } STATIC_OVL int pet_type() { if (urole.petnum != NON_PM) return (urole.petnum); else if (preferred_pet == 'c') return (PM_KITTEN); else if (preferred_pet == 'd') return (PM_LITTLE_DOG); else return (rn2(2) ? PM_KITTEN : PM_LITTLE_DOG); } struct monst * make_familiar(otmp,x,y,quietly) register struct obj *otmp; xchar x, y; boolean quietly; { struct permonst *pm; struct monst *mtmp = 0; int chance, trycnt = 100; do { if (otmp) { /* figurine; otherwise spell */ int mndx = otmp->corpsenm; pm = &mons[mndx]; /* activating a figurine provides one way to exceed the maximum number of the target critter created--unless it has a special limit (erinys, Nazgul) */ if ((mvitals[mndx].mvflags & G_EXTINCT) && mbirth_limit(mndx) != MAXMONNO) { if (!quietly) /* have just been given "You the figurine and it transforms." message */ pline("... into a pile of dust."); break; /* mtmp is null */ } } else if (!rn2(3)) { pm = &mons[pet_type()]; } else { pm = rndmonst(); if (!pm) { if (!quietly) There("seems to be nothing available for a familiar."); break; } } mtmp = makemon(pm, x, y, MM_EDOG|MM_IGNOREWATER); if (otmp && !mtmp) { /* monster was genocided or square occupied */ if (!quietly) pline_The("figurine writhes and then shatters into pieces!"); break; } } while (!mtmp && --trycnt > 0); if (!mtmp) return (struct monst *)0; if (is_pool(mtmp->mx, mtmp->my) && minliquid(mtmp)) return (struct monst *)0; initedog(mtmp); mtmp->msleeping = 0; if (otmp) { /* figurine; resulting monster might not become a pet */ chance = rn2(10); /* 0==tame, 1==peaceful, 2==hostile */ if (chance > 2) chance = otmp->blessed ? 0 : !otmp->cursed ? 1 : 2; /* 0,1,2: b=80%,10,10; nc=10%,80,10; c=10%,10,80 */ if (chance > 0) { mtmp->mtame = 0; /* not tame after all */ if (chance == 2) { /* hostile (cursed figurine) */ if (!quietly) You("get a bad feeling about this."); mtmp->mpeaceful = 0; set_malign(mtmp); } } /* if figurine has been named, give same name to the monster */ if (otmp->onamelth) mtmp = christen_monst(mtmp, ONAME(otmp)); } set_malign(mtmp); /* more alignment changes */ newsym(mtmp->mx, mtmp->my); /* must wield weapon immediately since pets will otherwise drop it */ if (mtmp->mtame && attacktype(mtmp->data, AT_WEAP)) { mtmp->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(mtmp); } return mtmp; } struct monst * makedog() { register struct monst *mtmp; #ifdef STEED register struct obj *otmp; #endif const char *petname; int pettype; static int petname_used = 0; if (preferred_pet == 'n') return((struct monst *) 0); pettype = pet_type(); if (pettype == PM_LITTLE_DOG) petname = dogname; else if (pettype == PM_PONY) petname = horsename; else petname = catname; /* default pet names */ if (!*petname && pettype == PM_LITTLE_DOG) { /* All of these names were for dogs. */ if(Role_if(PM_CAVEMAN)) petname = "Slasher"; /* The Warrior */ if(Role_if(PM_SAMURAI)) petname = "Hachi"; /* Shibuya Station */ if(Role_if(PM_BARBARIAN)) petname = "Idefix"; /* Obelix */ if(Role_if(PM_RANGER)) petname = "Sirius"; /* Orion's dog */ } mtmp = makemon(&mons[pettype], u.ux, u.uy, MM_EDOG); if(!mtmp) return((struct monst *) 0); /* pets were genocided */ #ifdef STEED /* Horses already wear a saddle */ if (pettype == PM_PONY && !!(otmp = mksobj(SADDLE, TRUE, FALSE))) { if (mpickobj(mtmp, otmp)) panic("merged saddle?"); mtmp->misc_worn_check |= W_SADDLE; otmp->dknown = otmp->bknown = otmp->rknown = 1; otmp->owornmask = W_SADDLE; otmp->leashmon = mtmp->m_id; update_mon_intrinsics(mtmp, otmp, TRUE, TRUE); } #endif if (!petname_used++ && *petname) mtmp = christen_monst(mtmp, petname); initedog(mtmp); return(mtmp); } /* record `last move time' for all monsters prior to level save so that mon_arrive() can catch up for lost time when they're restored later */ void update_mlstmv() { struct monst *mon; /* monst->mlstmv used to be updated every time `monst' actually moved, but that is no longer the case so we just do a blanket assignment */ for (mon = fmon; mon; mon = mon->nmon) if (!DEADMONSTER(mon)) mon->mlstmv = monstermoves; } void losedogs() { register struct monst *mtmp, *mtmp0 = 0, *mtmp2; while ((mtmp = mydogs) != 0) { mydogs = mtmp->nmon; mon_arrive(mtmp, TRUE); } for(mtmp = migrating_mons; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (mtmp->mux == u.uz.dnum && mtmp->muy == u.uz.dlevel) { if(mtmp == migrating_mons) migrating_mons = mtmp->nmon; else mtmp0->nmon = mtmp->nmon; mon_arrive(mtmp, FALSE); } else mtmp0 = mtmp; } } /* called from resurrect() in addition to losedogs() */ void mon_arrive(mtmp, with_you) struct monst *mtmp; boolean with_you; { struct trap *t; xchar xlocale, ylocale, xyloc, xyflags, wander; int num_segs; mtmp->nmon = fmon; fmon = mtmp; if (mtmp->isshk) set_residency(mtmp, FALSE); num_segs = mtmp->wormno; /* baby long worms have no tail so don't use is_longworm() */ if ((mtmp->data == &mons[PM_LONG_WORM]) && #ifdef DCC30_BUG (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) #else (mtmp->wormno = get_wormno()) != 0) #endif { initworm(mtmp, num_segs); /* tail segs are not yet initialized or displayed */ } else mtmp->wormno = 0; /* some monsters might need to do something special upon arrival _after_ the current level has been fully set up; see dochug() */ mtmp->mstrategy |= STRAT_ARRIVE; /* make sure mnexto(rloc_to(set_apparxy())) doesn't use stale data */ mtmp->mux = u.ux, mtmp->muy = u.uy; xyloc = mtmp->mtrack[0].x; xyflags = mtmp->mtrack[0].y; xlocale = mtmp->mtrack[1].x; ylocale = mtmp->mtrack[1].y; mtmp->mtrack[0].x = mtmp->mtrack[0].y = 0; mtmp->mtrack[1].x = mtmp->mtrack[1].y = 0; #ifdef STEED if (mtmp == u.usteed) return; /* don't place steed on the map */ #endif if (with_you) { /* When a monster accompanies you, sometimes it will arrive at your intended destination and you'll end up next to that spot. This code doesn't control the final outcome; goto_level(do.c) decides who ends up at your target spot when there is a monster there too. */ if (!MON_AT(u.ux, u.uy) && !rn2(mtmp->mtame ? 10 : mtmp->mpeaceful ? 5 : 2)) rloc_to(mtmp, u.ux, u.uy); else mnexto(mtmp); return; } /* * The monster arrived on this level independently of the player. * Its coordinate fields were overloaded for use as flags that * specify its final destination. */ if (mtmp->mlstmv < monstermoves - 1L) { /* heal monster for time spent in limbo */ long nmv = monstermoves - 1L - mtmp->mlstmv; mon_catchup_elapsed_time(mtmp, nmv); mtmp->mlstmv = monstermoves - 1L; /* let monster move a bit on new level (see placement code below) */ wander = (xchar) min(nmv, 8); } else wander = 0; switch (xyloc) { case MIGR_APPROX_XY: /* {x,y}locale set above */ break; case MIGR_EXACT_XY: wander = 0; break; case MIGR_NEAR_PLAYER: xlocale = u.ux, ylocale = u.uy; break; case MIGR_STAIRS_UP: xlocale = xupstair, ylocale = yupstair; break; case MIGR_STAIRS_DOWN: xlocale = xdnstair, ylocale = ydnstair; break; case MIGR_LADDER_UP: xlocale = xupladder, ylocale = yupladder; break; case MIGR_LADDER_DOWN: xlocale = xdnladder, ylocale = ydnladder; break; case MIGR_SSTAIRS: xlocale = sstairs.sx, ylocale = sstairs.sy; break; case MIGR_PORTAL: if (In_endgame(&u.uz)) { /* there is no arrival portal for endgame levels */ /* BUG[?]: for simplicity, this code relies on the fact that we know that the current endgame levels always build upwards and never have any exclusion subregion inside their TELEPORT_REGION settings. */ xlocale = rn1(updest.hx - updest.lx + 1, updest.lx); ylocale = rn1(updest.hy - updest.ly + 1, updest.ly); break; } /* find the arrival portal */ for (t = ftrap; t; t = t->ntrap) if (t->ttyp == MAGIC_PORTAL) break; if (t) { xlocale = t->tx, ylocale = t->ty; break; } else { impossible("mon_arrive: no corresponding portal?"); } /*FALLTHRU*/ default: case MIGR_RANDOM: xlocale = ylocale = 0; break; } if (xlocale && wander) { /* monster moved a bit; pick a nearby location */ /* mnearto() deals w/stone, et al */ char *r = in_rooms(xlocale, ylocale, 0); if (r && *r) { coord c; /* somexy() handles irregular rooms */ if (somexy(&rooms[*r - ROOMOFFSET], &c)) xlocale = c.x, ylocale = c.y; else xlocale = ylocale = 0; } else { /* not in a room */ int i, j; i = max(1, xlocale - wander); j = min(COLNO-1, xlocale + wander); xlocale = rn1(j - i, i); i = max(0, ylocale - wander); j = min(ROWNO-1, ylocale + wander); ylocale = rn1(j - i, i); } } /* moved a bit */ mtmp->mx = 0; /*(already is 0)*/ mtmp->my = xyflags; if (xlocale) (void) mnearto(mtmp, xlocale, ylocale, FALSE); else { if (!rloc(mtmp,TRUE)) { /* * Failed to place migrating monster, * probably because the level is full. * Dump the monster's cargo and leave the monster dead. */ struct obj *obj, *corpse; while ((obj = mtmp->minvent) != 0) { obj_extract_self(obj); obj_no_longer_held(obj); if (obj->owornmask & W_WEP) setmnotwielded(mtmp,obj); obj->owornmask = 0L; if (xlocale && ylocale) place_object(obj, xlocale, ylocale); else { rloco(obj); get_obj_location(obj, &xlocale, &ylocale, 0); } } corpse = mkcorpstat(CORPSE, (struct monst *)0, mtmp->data, xlocale, ylocale, FALSE); #ifndef GOLDOBJ if (mtmp->mgold) { if (xlocale == 0 && ylocale == 0 && corpse) { (void) get_obj_location(corpse, &xlocale, &ylocale, 0); (void) mkgold(mtmp->mgold, xlocale, ylocale); } mtmp->mgold = 0L; } #endif mongone(mtmp); } } } /* heal monster for time spent elsewhere */ void mon_catchup_elapsed_time(mtmp, nmv) struct monst *mtmp; long nmv; /* number of moves */ { int imv = 0; /* avoid zillions of casts and lint warnings */ #if defined(DEBUG) || defined(BETA) if (nmv < 0L) { /* crash likely... */ panic("catchup from future time?"); /*NOTREACHED*/ return; } else if (nmv == 0L) { /* safe, but should'nt happen */ impossible("catchup from now?"); } else #endif if (nmv >= LARGEST_INT) /* paranoia */ imv = LARGEST_INT - 1; else imv = (int)nmv; /* might stop being afraid, blind or frozen */ /* set to 1 and allow final decrement in movemon() */ if (mtmp->mblinded) { if (imv >= (int) mtmp->mblinded) mtmp->mblinded = 1; else mtmp->mblinded -= imv; } if (mtmp->mfrozen) { if (imv >= (int) mtmp->mfrozen) mtmp->mfrozen = 1; else mtmp->mfrozen -= imv; } if (mtmp->mfleetim) { if (imv >= (int) mtmp->mfleetim) mtmp->mfleetim = 1; else mtmp->mfleetim -= imv; } /* might recover from temporary trouble */ if (mtmp->mtrapped && rn2(imv + 1) > 40/2) mtmp->mtrapped = 0; if (mtmp->mconf && rn2(imv + 1) > 50/2) mtmp->mconf = 0; if (mtmp->mstun && rn2(imv + 1) > 10/2) mtmp->mstun = 0; /* might finish eating or be able to use special ability again */ if (imv > mtmp->meating) mtmp->meating = 0; else mtmp->meating -= imv; if (imv > mtmp->mspec_used) mtmp->mspec_used = 0; else mtmp->mspec_used -= imv; /* reduce tameness for every 150 moves you are separated */ if (mtmp->mtame) { int wilder = (imv + 75) / 150; if (mtmp->mtame > wilder) mtmp->mtame -= wilder; /* less tame */ else if (mtmp->mtame > rn2(wilder)) mtmp->mtame = 0; /* untame */ else mtmp->mtame = mtmp->mpeaceful = 0; /* hostile! */ } /* check to see if it would have died as a pet; if so, go wild instead * of dying the next time we call dog_move() */ if (mtmp->mtame && !mtmp->isminion && (carnivorous(mtmp->data) || herbivorous(mtmp->data))) { struct edog *edog = EDOG(mtmp); if ((monstermoves > edog->hungrytime + 500 && mtmp->mhp < 3) || (monstermoves > edog->hungrytime + 750)) mtmp->mtame = mtmp->mpeaceful = 0; } if (!mtmp->mtame && mtmp->mleashed) { /* leashed monsters should always be with hero, consequently never losing any time to be accounted for later */ impossible("catching up for leashed monster?"); m_unleash(mtmp, FALSE); } /* recover lost hit points */ if (!regenerates(mtmp->data)) imv /= 20; if (mtmp->mhp + imv >= mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; else mtmp->mhp += imv; } #endif /* OVLB */ #ifdef OVL2 /* called when you move to another level */ void keepdogs(pets_only) boolean pets_only; /* true for ascension or final escape */ { register struct monst *mtmp, *mtmp2; register struct obj *obj; int num_segs; boolean stay_behind; for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (pets_only && !mtmp->mtame) continue; if (((monnear(mtmp, u.ux, u.uy) && levl_follower(mtmp)) || #ifdef STEED (mtmp == u.usteed) || #endif /* the wiz will level t-port from anywhere to chase the amulet; if you don't have it, will chase you only if in range. -3. */ (u.uhave.amulet && mtmp->iswiz)) && ((!mtmp->msleeping && mtmp->mcanmove) #ifdef STEED /* eg if level teleport or new trap, steed has no control to avoid following */ || (mtmp == u.usteed) #endif ) /* monster won't follow if it hasn't noticed you yet */ && !(mtmp->mstrategy & STRAT_WAITFORU)) { stay_behind = FALSE; if (mtmp->mtame && mtmp->meating) { if (canseemon(mtmp)) pline("%s is still eating.", Monnam(mtmp)); stay_behind = TRUE; } else if (mon_has_amulet(mtmp)) { if (canseemon(mtmp)) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); stay_behind = TRUE; } else if (mtmp->mtame && mtmp->mtrapped) { if (canseemon(mtmp)) pline("%s is still trapped.", Monnam(mtmp)); stay_behind = TRUE; } #ifdef STEED if (mtmp == u.usteed) stay_behind = FALSE; #endif if (stay_behind) { if (mtmp->mleashed) { pline("%s leash suddenly comes loose.", humanoid(mtmp->data) ? (mtmp->female ? "Her" : "His") : "Its"); m_unleash(mtmp, FALSE); } continue; } if (mtmp->isshk) set_residency(mtmp, TRUE); if (mtmp->wormno) { register int cnt; /* NOTE: worm is truncated to # segs = max wormno size */ cnt = count_wsegs(mtmp); num_segs = min(cnt, MAX_NUM_WORMS - 1); wormgone(mtmp); } else num_segs = 0; /* set minvent's obj->no_charge to 0 */ for(obj = mtmp->minvent; obj; obj = obj->nobj) { if (Has_contents(obj)) picked_container(obj); /* does the right thing */ obj->no_charge = 0; } relmon(mtmp); newsym(mtmp->mx,mtmp->my); mtmp->mx = mtmp->my = 0; /* avoid mnexto()/MON_AT() problem */ mtmp->wormno = num_segs; mtmp->mlstmv = monstermoves; mtmp->nmon = mydogs; mydogs = mtmp; } else if (mtmp->iswiz) { /* we want to be able to find him when his next resurrection chance comes up, but have him resume his present location if player returns to this level before that time */ migrate_to_level(mtmp, ledger_no(&u.uz), MIGR_EXACT_XY, (coord *)0); } else if (mtmp->mleashed) { /* this can happen if your quest leader ejects you from the "home" level while a leashed pet isn't next to you */ pline("%s leash goes slack.", s_suffix(Monnam(mtmp))); m_unleash(mtmp, FALSE); } } } #endif /* OVL2 */ #ifdef OVLB void migrate_to_level(mtmp, tolev, xyloc, cc) register struct monst *mtmp; xchar tolev; /* destination level */ xchar xyloc; /* MIGR_xxx destination xy location: */ coord *cc; /* optional destination coordinates */ { register struct obj *obj; d_level new_lev; xchar xyflags; int num_segs = 0; /* count of worm segments */ if (mtmp->isshk) set_residency(mtmp, TRUE); if (mtmp->wormno) { register int cnt; /* **** NOTE: worm is truncated to # segs = max wormno size **** */ cnt = count_wsegs(mtmp); num_segs = min(cnt, MAX_NUM_WORMS - 1); wormgone(mtmp); } /* set minvent's obj->no_charge to 0 */ for(obj = mtmp->minvent; obj; obj = obj->nobj) { if (Has_contents(obj)) picked_container(obj); /* does the right thing */ obj->no_charge = 0; } if (mtmp->mleashed) { mtmp->mtame--; m_unleash(mtmp, TRUE); } relmon(mtmp); mtmp->nmon = migrating_mons; migrating_mons = mtmp; newsym(mtmp->mx,mtmp->my); new_lev.dnum = ledger_to_dnum((xchar)tolev); new_lev.dlevel = ledger_to_dlev((xchar)tolev); /* overload mtmp->[mx,my], mtmp->[mux,muy], and mtmp->mtrack[] as */ /* destination codes (setup flag bits before altering mx or my) */ xyflags = (depth(&new_lev) < depth(&u.uz)); /* 1 => up */ if (In_W_tower(mtmp->mx, mtmp->my, &u.uz)) xyflags |= 2; mtmp->wormno = num_segs; mtmp->mlstmv = monstermoves; mtmp->mtrack[1].x = cc ? cc->x : mtmp->mx; mtmp->mtrack[1].y = cc ? cc->y : mtmp->my; mtmp->mtrack[0].x = xyloc; mtmp->mtrack[0].y = xyflags; mtmp->mux = new_lev.dnum; mtmp->muy = new_lev.dlevel; mtmp->mx = mtmp->my = 0; /* this implies migration */ } #endif /* OVLB */ #ifdef OVL1 /* return quality of food; the lower the better */ /* fungi will eat even tainted food */ int dogfood(mon,obj) struct monst *mon; register struct obj *obj; { boolean carni = carnivorous(mon->data); boolean herbi = herbivorous(mon->data); struct permonst *fptr = &mons[obj->corpsenm]; boolean starving; if (is_quest_artifact(obj) || obj_resists(obj, 0, 95)) return (obj->cursed ? TABU : APPORT); switch(obj->oclass) { case FOOD_CLASS: if (obj->otyp == CORPSE && ((touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon)) || is_rider(fptr))) return TABU; /* Ghouls only eat old corpses... yum! */ if (mon->data == &mons[PM_GHOUL]) return (obj->otyp == CORPSE && peek_at_iced_corpse_age(obj) + 50L <= monstermoves) ? DOGFOOD : TABU; if (!carni && !herbi) return (obj->cursed ? UNDEF : APPORT); /* a starving pet will eat almost anything */ starving = (mon->mtame && !mon->isminion && EDOG(mon)->mhpmax_penalty); switch (obj->otyp) { case TRIPE_RATION: case MEATBALL: case MEAT_RING: case MEAT_STICK: case HUGE_CHUNK_OF_MEAT: return (carni ? DOGFOOD : MANFOOD); case EGG: if (touch_petrifies(&mons[obj->corpsenm]) && !resists_ston(mon)) return POISON; return (carni ? CADAVER : MANFOOD); case CORPSE: if ((peek_at_iced_corpse_age(obj) + 50L <= monstermoves && obj->corpsenm != PM_LIZARD && obj->corpsenm != PM_LICHEN && mon->data->mlet != S_FUNGUS) || (acidic(&mons[obj->corpsenm]) && !resists_acid(mon)) || (poisonous(&mons[obj->corpsenm]) && !resists_poison(mon))) return POISON; else if (vegan(fptr)) return (herbi ? CADAVER : MANFOOD); else return (carni ? CADAVER : MANFOOD); case CLOVE_OF_GARLIC: return (is_undead(mon->data) ? TABU : ((herbi || starving) ? ACCFOOD : MANFOOD)); case TIN: return (metallivorous(mon->data) ? ACCFOOD : MANFOOD); case APPLE: case CARROT: return (herbi ? DOGFOOD : starving ? ACCFOOD : MANFOOD); case BANANA: return ((mon->data->mlet == S_YETI) ? DOGFOOD : ((herbi || starving) ? ACCFOOD : MANFOOD)); default: if (starving) return ACCFOOD; return (obj->otyp > SLIME_MOLD ? (carni ? ACCFOOD : MANFOOD) : (herbi ? ACCFOOD : MANFOOD)); } default: if (obj->otyp == AMULET_OF_STRANGULATION || obj->otyp == RIN_SLOW_DIGESTION) return TABU; if (hates_silver(mon->data) && objects[obj->otyp].oc_material == SILVER) return(TABU); if (mon->data == &mons[PM_GELATINOUS_CUBE] && is_organic(obj)) return(ACCFOOD); if (metallivorous(mon->data) && is_metallic(obj) && (is_rustprone(obj) || mon->data != &mons[PM_RUST_MONSTER])) { /* Non-rustproofed ferrous based metals are preferred. */ return((is_rustprone(obj) && !obj->oerodeproof) ? DOGFOOD : ACCFOOD); } if(!obj->cursed && obj->oclass != BALL_CLASS && obj->oclass != CHAIN_CLASS) return(APPORT); /* fall into next case */ case ROCK_CLASS: return(UNDEF); } } #endif /* OVL1 */ #ifdef OVLB struct monst * tamedog(mtmp, obj) register struct monst *mtmp; register struct obj *obj; { register struct monst *mtmp2; /* The Wiz, Medusa and the quest nemeses aren't even made peaceful. */ if (mtmp->iswiz || mtmp->data == &mons[PM_MEDUSA] || (mtmp->data->mflags3 & M3_WANTSARTI)) return((struct monst *)0); /* worst case, at least it'll be peaceful. */ mtmp->mpeaceful = 1; set_malign(mtmp); if(flags.moonphase == FULL_MOON && night() && rn2(6) && obj && mtmp->data->mlet == S_DOG) return((struct monst *)0); /* If we cannot tame it, at least it's no longer afraid. */ mtmp->mflee = 0; mtmp->mfleetim = 0; /* make grabber let go now, whether it becomes tame or not */ if (mtmp == u.ustuck) { if (u.uswallow) expels(mtmp, mtmp->data, TRUE); else if (!(Upolyd && sticks(youmonst.data))) unstuck(mtmp); } /* feeding it treats makes it tamer */ if (mtmp->mtame && obj) { int tasty; if (mtmp->mcanmove && !mtmp->mconf && !mtmp->meating && ((tasty = dogfood(mtmp, obj)) == DOGFOOD || (tasty <= ACCFOOD && EDOG(mtmp)->hungrytime <= monstermoves))) { /* pet will "catch" and eat this thrown food */ if (canseemon(mtmp)) { boolean big_corpse = (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM && mons[obj->corpsenm].msize > mtmp->data->msize); pline("%s catches %s%s", Monnam(mtmp), the(xname(obj)), !big_corpse ? "." : ", or vice versa!"); } else if (cansee(mtmp->mx,mtmp->my)) pline("%s.", Tobjnam(obj, "stop")); /* dog_eat expects a floor object */ place_object(obj, mtmp->mx, mtmp->my); (void) dog_eat(mtmp, obj, mtmp->mx, mtmp->my, FALSE); /* eating might have killed it, but that doesn't matter here; a non-null result suppresses "miss" message for thrown food and also implies that the object has been deleted */ return mtmp; } else return (struct monst *)0; } if (mtmp->mtame || !mtmp->mcanmove || /* monsters with conflicting structures cannot be tamed */ mtmp->isshk || mtmp->isgd || mtmp->ispriest || mtmp->isminion || is_covetous(mtmp->data) || is_human(mtmp->data) || (is_demon(mtmp->data) && !is_demon(youmonst.data)) || (obj && dogfood(mtmp, obj) >= MANFOOD)) return (struct monst *)0; if (mtmp->m_id == quest_status.leader_m_id) return((struct monst *)0); /* make a new monster which has the pet extension */ mtmp2 = newmonst(sizeof(struct edog) + mtmp->mnamelth); *mtmp2 = *mtmp; mtmp2->mxlth = sizeof(struct edog); if (mtmp->mnamelth) Strcpy(NAME(mtmp2), NAME(mtmp)); initedog(mtmp2); replmon(mtmp, mtmp2); /* `mtmp' is now obsolete */ if (obj) { /* thrown food */ /* defer eating until the edog extension has been set up */ place_object(obj, mtmp2->mx, mtmp2->my); /* put on floor */ /* devour the food (might grow into larger, genocided monster) */ if (dog_eat(mtmp2, obj, mtmp2->mx, mtmp2->my, TRUE) == 2) return mtmp2; /* oops, it died... */ /* `obj' is now obsolete */ } newsym(mtmp2->mx, mtmp2->my); if (attacktype(mtmp2->data, AT_WEAP)) { mtmp2->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(mtmp2); } return(mtmp2); } /* * Called during pet revival or pet life-saving. * If you killed the pet, it revives wild. * If you abused the pet a lot while alive, it revives wild. * If you abused the pet at all while alive, it revives untame. * If the pet wasn't abused and was very tame, it might revive tame. */ void wary_dog(mtmp, was_dead) struct monst *mtmp; boolean was_dead; { struct edog *edog; boolean quietly = was_dead; mtmp->meating = 0; if (!mtmp->mtame) return; edog = !mtmp->isminion ? EDOG(mtmp) : 0; /* if monster was starving when it died, undo that now */ if (edog && edog->mhpmax_penalty) { mtmp->mhpmax += edog->mhpmax_penalty; mtmp->mhp += edog->mhpmax_penalty; /* heal it */ edog->mhpmax_penalty = 0; } if (edog && (edog->killed_by_u == 1 || edog->abuse > 2)) { mtmp->mpeaceful = mtmp->mtame = 0; if (edog->abuse >= 0 && edog->abuse < 10) if (!rn2(edog->abuse + 1)) mtmp->mpeaceful = 1; if(!quietly && cansee(mtmp->mx, mtmp->my)) { if (haseyes(youmonst.data)) { if (haseyes(mtmp->data)) pline("%s %s to look you in the %s.", Monnam(mtmp), mtmp->mpeaceful ? "seems unable" : "refuses", body_part(EYE)); else pline("%s avoids your gaze.", Monnam(mtmp)); } } } else { /* chance it goes wild anyway - Pet Semetary */ if (!rn2(mtmp->mtame)) { mtmp->mpeaceful = mtmp->mtame = 0; } } if (!mtmp->mtame) { newsym(mtmp->mx, mtmp->my); /* a life-saved monster might be leashed; don't leave it that way if it's no longer tame */ if (mtmp->mleashed) m_unleash(mtmp, TRUE); } /* if its still a pet, start a clean pet-slate now */ if (edog && mtmp->mtame) { edog->revivals++; edog->killed_by_u = 0; edog->abuse = 0; edog->ogoal.x = edog->ogoal.y = -1; if (was_dead || edog->hungrytime < monstermoves + 500L) edog->hungrytime = monstermoves + 500L; if (was_dead) { edog->droptime = 0L; edog->dropdist = 10000; edog->whistletime = 0L; edog->apport = 5; } /* else lifesaved, so retain current values */ } } void abuse_dog(mtmp) struct monst *mtmp; { if (!mtmp->mtame) return; if (Aggravate_monster || Conflict) mtmp->mtame /=2; else mtmp->mtame--; if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->abuse++; if (!mtmp->mtame && mtmp->mleashed) m_unleash(mtmp, TRUE); /* don't make a sound if pet is in the middle of leaving the level */ /* newsym isn't necessary in this case either */ if (mtmp->mx != 0) { if (mtmp->mtame && rn2(mtmp->mtame)) yelp(mtmp); else growl(mtmp); /* give them a moment's worry */ if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my); } } #endif /* OVLB */ /*dog.c*/ nethack-3.4.3/src/dogmove.c0100644000000000000000000006063707764735041014261 0ustar rootroot/* SCCS Id: @(#)dogmove.c 3.4 2002/09/10 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mfndpos.h" #include "edog.h" extern boolean notonhead; #ifdef OVL0 STATIC_DCL boolean FDECL(dog_hunger,(struct monst *,struct edog *)); STATIC_DCL int FDECL(dog_invent,(struct monst *,struct edog *,int)); STATIC_DCL int FDECL(dog_goal,(struct monst *,struct edog *,int,int,int)); STATIC_DCL struct obj *FDECL(DROPPABLES, (struct monst *)); STATIC_DCL boolean FDECL(can_reach_location,(struct monst *,XCHAR_P,XCHAR_P, XCHAR_P,XCHAR_P)); STATIC_DCL boolean FDECL(could_reach_item,(struct monst *, XCHAR_P,XCHAR_P)); STATIC_OVL struct obj * DROPPABLES(mon) register struct monst *mon; { register struct obj *obj; struct obj *wep = MON_WEP(mon); boolean item1 = FALSE, item2 = FALSE; if (is_animal(mon->data) || mindless(mon->data)) item1 = item2 = TRUE; if (!tunnels(mon->data) || !needspick(mon->data)) item1 = TRUE; for(obj = mon->minvent; obj; obj = obj->nobj) { if (!item1 && is_pick(obj) && (obj->otyp != DWARVISH_MATTOCK || !which_armor(mon, W_ARMS))) { item1 = TRUE; continue; } if (!item2 && obj->otyp == UNICORN_HORN && !obj->cursed) { item2 = TRUE; continue; } if (!obj->owornmask && obj != wep) return obj; } return (struct obj *)0; } static NEARDATA const char nofetch[] = { BALL_CLASS, CHAIN_CLASS, ROCK_CLASS, 0 }; #endif /* OVL0 */ STATIC_OVL boolean FDECL(cursed_object_at, (int, int)); STATIC_VAR xchar gtyp, gx, gy; /* type and position of dog's current goal */ STATIC_PTR void FDECL(wantdoor, (int, int, genericptr_t)); #ifdef OVLB STATIC_OVL boolean cursed_object_at(x, y) int x, y; { struct obj *otmp; for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (otmp->cursed) return TRUE; return FALSE; } int dog_nutrition(mtmp, obj) struct monst *mtmp; struct obj *obj; { int nutrit; /* * It is arbitrary that the pet takes the same length of time to eat * as a human, but gets more nutritional value. */ if (obj->oclass == FOOD_CLASS) { if(obj->otyp == CORPSE) { mtmp->meating = 3 + (mons[obj->corpsenm].cwt >> 6); nutrit = mons[obj->corpsenm].cnutrit; } else { mtmp->meating = objects[obj->otyp].oc_delay; nutrit = objects[obj->otyp].oc_nutrition; } switch(mtmp->data->msize) { case MZ_TINY: nutrit *= 8; break; case MZ_SMALL: nutrit *= 6; break; default: case MZ_MEDIUM: nutrit *= 5; break; case MZ_LARGE: nutrit *= 4; break; case MZ_HUGE: nutrit *= 3; break; case MZ_GIGANTIC: nutrit *= 2; break; } if(obj->oeaten) { mtmp->meating = eaten_stat(mtmp->meating, obj); nutrit = eaten_stat(nutrit, obj); } } else if (obj->oclass == COIN_CLASS) { mtmp->meating = (int)(obj->quan/2000) + 1; if (mtmp->meating < 0) mtmp->meating = 1; nutrit = (int)(obj->quan/20); if (nutrit < 0) nutrit = 0; } else { /* Unusual pet such as gelatinous cube eating odd stuff. * meating made consistent with wild monsters in mon.c. * nutrit made consistent with polymorphed player nutrit in * eat.c. (This also applies to pets eating gold.) */ mtmp->meating = obj->owt/20 + 1; nutrit = 5*objects[obj->otyp].oc_nutrition; } return nutrit; } /* returns 2 if pet dies, otherwise 1 */ int dog_eat(mtmp, obj, x, y, devour) register struct monst *mtmp; register struct obj * obj; int x, y; boolean devour; { register struct edog *edog = EDOG(mtmp); boolean poly = FALSE, grow = FALSE, heal = FALSE; int nutrit; if(edog->hungrytime < monstermoves) edog->hungrytime = monstermoves; nutrit = dog_nutrition(mtmp, obj); poly = polyfodder(obj); grow = mlevelgain(obj); heal = mhealup(obj); if (devour) { if (mtmp->meating > 1) mtmp->meating /= 2; if (nutrit > 1) nutrit = (nutrit * 3) / 4; } edog->hungrytime += nutrit; mtmp->mconf = 0; if (edog->mhpmax_penalty) { /* no longer starving */ mtmp->mhpmax += edog->mhpmax_penalty; edog->mhpmax_penalty = 0; } if (mtmp->mflee && mtmp->mfleetim > 1) mtmp->mfleetim /= 2; if (mtmp->mtame < 20) mtmp->mtame++; if (x != mtmp->mx || y != mtmp->my) { /* moved & ate on same turn */ newsym(x, y); newsym(mtmp->mx, mtmp->my); } if (is_pool(x, y) && !Underwater) { /* Don't print obj */ /* TODO: Reveal presence of sea monster (especially sharks) */ } else /* hack: observe the action if either new or old location is in view */ /* However, invisible monsters should still be "it" even though out of sight locations should not. */ if (cansee(x, y) || cansee(mtmp->mx, mtmp->my)) pline("%s %s %s.", mon_visible(mtmp) ? noit_Monnam(mtmp) : "It", devour ? "devours" : "eats", (obj->oclass == FOOD_CLASS) ? singular(obj, doname) : doname(obj)); /* It's a reward if it's DOGFOOD and the player dropped/threw it. */ /* We know the player had it if invlet is set -dlc */ if(dogfood(mtmp,obj) == DOGFOOD && obj->invlet) #ifdef LINT edog->apport = 0; #else edog->apport += (int)(200L/ ((long)edog->dropdist + monstermoves - edog->droptime)); #endif if (mtmp->data == &mons[PM_RUST_MONSTER] && obj->oerodeproof) { /* The object's rustproofing is gone now */ obj->oerodeproof = 0; mtmp->mstun = 1; if (canseemon(mtmp) && flags.verbose) { pline("%s spits %s out in disgust!", Monnam(mtmp), distant_name(obj,doname)); } } else if (obj == uball) { unpunish(); delobj(obj); } else if (obj == uchain) unpunish(); else if (obj->quan > 1L && obj->oclass == FOOD_CLASS) { obj->quan--; obj->owt = weight(obj); } else delobj(obj); if (poly) { (void) newcham(mtmp, (struct permonst *)0, FALSE, cansee(mtmp->mx, mtmp->my)); } /* limit "instant" growth to prevent potential abuse */ if (grow && (int) mtmp->m_lev < (int)mtmp->data->mlevel + 15) { if (!grow_up(mtmp, (struct monst *)0)) return 2; } if (heal) mtmp->mhp = mtmp->mhpmax; return 1; } #endif /* OVLB */ #ifdef OVL0 /* hunger effects -- returns TRUE on starvation */ STATIC_OVL boolean dog_hunger(mtmp, edog) register struct monst *mtmp; register struct edog *edog; { if (monstermoves > edog->hungrytime + 500) { if (!carnivorous(mtmp->data) && !herbivorous(mtmp->data)) { edog->hungrytime = monstermoves + 500; /* but not too high; it might polymorph */ } else if (!edog->mhpmax_penalty) { /* starving pets are limited in healing */ int newmhpmax = mtmp->mhpmax / 3; mtmp->mconf = 1; edog->mhpmax_penalty = mtmp->mhpmax - newmhpmax; mtmp->mhpmax = newmhpmax; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; if (mtmp->mhp < 1) goto dog_died; if (cansee(mtmp->mx, mtmp->my)) pline("%s is confused from hunger.", Monnam(mtmp)); else if (couldsee(mtmp->mx, mtmp->my)) beg(mtmp); else You_feel("worried about %s.", y_monnam(mtmp)); stop_occupation(); } else if (monstermoves > edog->hungrytime + 750 || mtmp->mhp < 1) { dog_died: if (mtmp->mleashed #ifdef STEED && mtmp != u.usteed #endif ) Your("leash goes slack."); else if (cansee(mtmp->mx, mtmp->my)) pline("%s starves.", Monnam(mtmp)); else You_feel("%s for a moment.", Hallucination ? "bummed" : "sad"); mondied(mtmp); return(TRUE); } } return(FALSE); } /* do something with object (drop, pick up, eat) at current position * returns 1 if object eaten (since that counts as dog's move), 2 if died */ STATIC_OVL int dog_invent(mtmp, edog, udist) register struct monst *mtmp; register struct edog *edog; int udist; { register int omx, omy; struct obj *obj; if (mtmp->msleeping || !mtmp->mcanmove) return(0); omx = mtmp->mx; omy = mtmp->my; /* if we are carrying sth then we drop it (perhaps near @) */ /* Note: if apport == 1 then our behaviour is independent of udist */ /* Use udist+1 so steed won't cause divide by zero */ #ifndef GOLDOBJ if(DROPPABLES(mtmp) || mtmp->mgold) { #else if(DROPPABLES(mtmp)) { #endif if (!rn2(udist+1) || !rn2(edog->apport)) if(rn2(10) < edog->apport){ relobj(mtmp, (int)mtmp->minvis, TRUE); if(edog->apport > 1) edog->apport--; edog->dropdist = udist; /* hpscdi!jon */ edog->droptime = monstermoves; } } else { if((obj=level.objects[omx][omy]) && !index(nofetch,obj->oclass) #ifdef MAIL && obj->otyp != SCR_MAIL #endif ){ int edible = dogfood(mtmp, obj); if ((edible <= CADAVER || /* starving pet is more aggressive about eating */ (edog->mhpmax_penalty && edible == ACCFOOD)) && could_reach_item(mtmp, obj->ox, obj->oy)) return dog_eat(mtmp, obj, omx, omy, FALSE); if(can_carry(mtmp, obj) && !obj->cursed && could_reach_item(mtmp, obj->ox, obj->oy)) { if(rn2(20) < edog->apport+3) { if (rn2(udist) || !rn2(edog->apport)) { if (cansee(omx, omy) && flags.verbose) pline("%s picks up %s.", Monnam(mtmp), distant_name(obj, doname)); obj_extract_self(obj); newsym(omx,omy); (void) mpickobj(mtmp,obj); if (attacktype(mtmp->data, AT_WEAP) && mtmp->weapon_check == NEED_WEAPON) { mtmp->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(mtmp); } m_dowear(mtmp, FALSE); } } } } } return 0; } /* set dog's goal -- gtyp, gx, gy * returns -1/0/1 (dog's desire to approach player) or -2 (abort move) */ STATIC_OVL int dog_goal(mtmp, edog, after, udist, whappr) register struct monst *mtmp; struct edog *edog; int after, udist, whappr; { register int omx, omy; boolean in_masters_sight, dog_has_minvent; register struct obj *obj; xchar otyp; int appr; #ifdef STEED /* Steeds don't move on their own will */ if (mtmp == u.usteed) return (-2); #endif omx = mtmp->mx; omy = mtmp->my; in_masters_sight = couldsee(omx, omy); dog_has_minvent = (DROPPABLES(mtmp) != 0); if (!edog || mtmp->mleashed) { /* he's not going anywhere... */ gtyp = APPORT; gx = u.ux; gy = u.uy; } else { #define DDIST(x,y) (dist2(x,y,omx,omy)) #define SQSRCHRADIUS 5 int min_x, max_x, min_y, max_y; register int nx, ny; gtyp = UNDEF; /* no goal as yet */ gx = gy = 0; /* suppress 'used before set' message */ if ((min_x = omx - SQSRCHRADIUS) < 1) min_x = 1; if ((max_x = omx + SQSRCHRADIUS) >= COLNO) max_x = COLNO - 1; if ((min_y = omy - SQSRCHRADIUS) < 0) min_y = 0; if ((max_y = omy + SQSRCHRADIUS) >= ROWNO) max_y = ROWNO - 1; /* nearby food is the first choice, then other objects */ for (obj = fobj; obj; obj = obj->nobj) { nx = obj->ox; ny = obj->oy; if (nx >= min_x && nx <= max_x && ny >= min_y && ny <= max_y) { otyp = dogfood(mtmp, obj); /* skip inferior goals */ if (otyp > gtyp || otyp == UNDEF) continue; /* avoid cursed items unless starving */ if (cursed_object_at(nx, ny) && !(edog->mhpmax_penalty && otyp < MANFOOD)) continue; /* skip completely unreacheable goals */ if (!could_reach_item(mtmp, nx, ny) || !can_reach_location(mtmp, mtmp->mx, mtmp->my, nx, ny)) continue; if (otyp < MANFOOD) { if (otyp < gtyp || DDIST(nx,ny) < DDIST(gx,gy)) { gx = nx; gy = ny; gtyp = otyp; } } else if(gtyp == UNDEF && in_masters_sight && !dog_has_minvent && (!levl[omx][omy].lit || levl[u.ux][u.uy].lit) && (otyp == MANFOOD || m_cansee(mtmp, nx, ny)) && edog->apport > rn2(8) && can_carry(mtmp,obj)) { gx = nx; gy = ny; gtyp = APPORT; } } } } /* follow player if appropriate */ if (gtyp == UNDEF || (gtyp != DOGFOOD && gtyp != APPORT && monstermoves < edog->hungrytime)) { gx = u.ux; gy = u.uy; if (after && udist <= 4 && gx == u.ux && gy == u.uy) return(-2); appr = (udist >= 9) ? 1 : (mtmp->mflee) ? -1 : 0; if (udist > 1) { if (!IS_ROOM(levl[u.ux][u.uy].typ) || !rn2(4) || whappr || (dog_has_minvent && rn2(edog->apport))) appr = 1; } /* if you have dog food it'll follow you more closely */ if (appr == 0) { obj = invent; while (obj) { if(dogfood(mtmp, obj) == DOGFOOD) { appr = 1; break; } obj = obj->nobj; } } } else appr = 1; /* gtyp != UNDEF */ if(mtmp->mconf) appr = 0; #define FARAWAY (COLNO + 2) /* position outside screen */ if (gx == u.ux && gy == u.uy && !in_masters_sight) { register coord *cp; cp = gettrack(omx,omy); if (cp) { gx = cp->x; gy = cp->y; if(edog) edog->ogoal.x = 0; } else { /* assume master hasn't moved far, and reuse previous goal */ if(edog && edog->ogoal.x && ((edog->ogoal.x != omx) || (edog->ogoal.y != omy))) { gx = edog->ogoal.x; gy = edog->ogoal.y; edog->ogoal.x = 0; } else { int fardist = FARAWAY * FARAWAY; gx = gy = FARAWAY; /* random */ do_clear_area(omx, omy, 9, wantdoor, (genericptr_t)&fardist); /* here gx == FARAWAY e.g. when dog is in a vault */ if (gx == FARAWAY || (gx == omx && gy == omy)) { gx = u.ux; gy = u.uy; } else if(edog) { edog->ogoal.x = gx; edog->ogoal.y = gy; } } } } else if(edog) { edog->ogoal.x = 0; } return appr; } /* return 0 (no move), 1 (move) or 2 (dead) */ int dog_move(mtmp, after) register struct monst *mtmp; register int after; /* this is extra fast monster movement */ { int omx, omy; /* original mtmp position */ int appr, whappr, udist; int i, j, k; register struct edog *edog = EDOG(mtmp); struct obj *obj = (struct obj *) 0; xchar otyp; boolean has_edog, cursemsg[9], do_eat = FALSE; xchar nix, niy; /* position mtmp is (considering) moving to */ register int nx, ny; /* temporary coordinates */ xchar cnt, uncursedcnt, chcnt; int chi = -1, nidist, ndist; coord poss[9]; long info[9], allowflags; #define GDIST(x,y) (dist2(x,y,gx,gy)) /* * Tame Angels have isminion set and an ispriest structure instead of * an edog structure. Fortunately, guardian Angels need not worry * about mundane things like eating and fetching objects, and can * spend all their energy defending the player. (They are the only * monsters with other structures that can be tame.) */ has_edog = !mtmp->isminion; omx = mtmp->mx; omy = mtmp->my; if (has_edog && dog_hunger(mtmp, edog)) return(2); /* starved */ udist = distu(omx,omy); #ifdef STEED /* Let steeds eat and maybe throw rider during Conflict */ if (mtmp == u.usteed) { if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { dismount_steed(DISMOUNT_THROWN); return (1); } udist = 1; } else #endif /* maybe we tamed him while being swallowed --jgm */ if (!udist) return(0); nix = omx; /* set before newdogpos */ niy = omy; cursemsg[0] = FALSE; /* lint suppression */ info[0] = 0; /* ditto */ if (has_edog) { j = dog_invent(mtmp, edog, udist); if (j == 2) return 2; /* died */ else if (j == 1) goto newdogpos; /* eating something */ whappr = (monstermoves - edog->whistletime < 5); } else whappr = 0; appr = dog_goal(mtmp, has_edog ? edog : (struct edog *)0, after, udist, whappr); if (appr == -2) return(0); allowflags = ALLOW_M | ALLOW_TRAPS | ALLOW_SSM | ALLOW_SANCT; if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK | ALLOW_WALL); if (passes_bars(mtmp->data)) allowflags |= ALLOW_BARS; if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; if (Conflict && !resist(mtmp, RING_CLASS, 0, 0)) { allowflags |= ALLOW_U; if (!has_edog) { coord mm; /* Guardian angel refuses to be conflicted; rather, * it disappears, angrily, and sends in some nasties */ if (canspotmon(mtmp)) { pline("%s rebukes you, saying:", Monnam(mtmp)); verbalize("Since you desire conflict, have some more!"); } mongone(mtmp); i = rnd(4); while(i--) { mm.x = u.ux; mm.y = u.uy; if(enexto(&mm, mm.x, mm.y, &mons[PM_ANGEL])) (void) mk_roamer(&mons[PM_ANGEL], u.ualign.type, mm.x, mm.y, FALSE); } return(2); } } if (!Conflict && !mtmp->mconf && mtmp == u.ustuck && !sticks(youmonst.data)) { unstuck(mtmp); /* swallowed case handled above */ You("get released!"); } if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; } if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; cnt = mfndpos(mtmp, poss, info, allowflags); /* Normally dogs don't step on cursed items, but if they have no * other choice they will. This requires checking ahead of time * to see how many uncursed item squares are around. */ uncursedcnt = 0; for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; if (MON_AT(nx,ny) && !(info[i] & ALLOW_M)) continue; if (cursed_object_at(nx, ny)) continue; uncursedcnt++; } chcnt = 0; chi = -1; nidist = GDIST(nix,niy); for (i = 0; i < cnt; i++) { nx = poss[i].x; ny = poss[i].y; cursemsg[i] = FALSE; /* if leashed, we drag him along. */ if (mtmp->mleashed && distu(nx, ny) > 4) continue; /* if a guardian, try to stay close by choice */ if (!has_edog && (j = distu(nx, ny)) > 16 && j >= udist) continue; if ((info[i] & ALLOW_M) && MON_AT(nx, ny)) { int mstatus; register struct monst *mtmp2 = m_at(nx,ny); if ((int)mtmp2->m_lev >= (int)mtmp->m_lev+2 || (mtmp2->data == &mons[PM_FLOATING_EYE] && rn2(10) && mtmp->mcansee && haseyes(mtmp->data) && mtmp2->mcansee && (perceives(mtmp->data) || !mtmp2->minvis)) || (mtmp2->data==&mons[PM_GELATINOUS_CUBE] && rn2(10)) || (max_passive_dmg(mtmp2, mtmp) >= mtmp->mhp) || ((mtmp->mhp*4 < mtmp->mhpmax || mtmp2->data->msound == MS_GUARDIAN || mtmp2->data->msound == MS_LEADER) && mtmp2->mpeaceful && !Conflict) || (touch_petrifies(mtmp2->data) && !resists_ston(mtmp))) continue; if (after) return(0); /* hit only once each move */ notonhead = 0; mstatus = mattackm(mtmp, mtmp2); /* aggressor (pet) died */ if (mstatus & MM_AGR_DIED) return 2; if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4) && mtmp2->mlstmv != monstermoves && !onscary(mtmp->mx, mtmp->my, mtmp2) && /* monnear check needed: long worms hit on tail */ monnear(mtmp2, mtmp->mx, mtmp->my)) { mstatus = mattackm(mtmp2, mtmp); /* return attack */ if (mstatus & MM_DEF_DIED) return 2; } return 0; } { /* Dog avoids harmful traps, but perhaps it has to pass one * in order to follow player. (Non-harmful traps do not * have ALLOW_TRAPS in info[].) The dog only avoids the * trap if you've seen it, unlike enemies who avoid traps * if they've seen some trap of that type sometime in the * past. (Neither behavior is really realistic.) */ struct trap *trap; if ((info[i] & ALLOW_TRAPS) && (trap = t_at(nx,ny))) { if (mtmp->mleashed) { if (flags.soundok) whimper(mtmp); } else /* 1/40 chance of stepping on it anyway, in case * it has to pass one to follow the player... */ if (trap->tseen && rn2(40)) continue; } } /* dog eschews cursed objects, but likes dog food */ /* (minion isn't interested; `cursemsg' stays FALSE) */ if (has_edog) for (obj = level.objects[nx][ny]; obj; obj = obj->nexthere) { if (obj->cursed) cursemsg[i] = TRUE; else if ((otyp = dogfood(mtmp, obj)) < MANFOOD && (otyp < ACCFOOD || edog->hungrytime <= monstermoves)) { /* Note: our dog likes the food so much that he * might eat it even when it conceals a cursed object */ nix = nx; niy = ny; chi = i; do_eat = TRUE; cursemsg[i] = FALSE; /* not reluctant */ goto newdogpos; } } /* didn't find something to eat; if we saw a cursed item and aren't being forced to walk on it, usually keep looking */ if (cursemsg[i] && !mtmp->mleashed && uncursedcnt > 0 && rn2(13 * uncursedcnt)) continue; /* lessen the chance of backtracking to previous position(s) */ k = has_edog ? uncursedcnt : cnt; for (j = 0; j < MTSZ && j < k - 1; j++) if (nx == mtmp->mtrack[j].x && ny == mtmp->mtrack[j].y) if (rn2(MTSZ * (k - j))) goto nxti; j = ((ndist = GDIST(nx,ny)) - nidist) * appr; if ((j == 0 && !rn2(++chcnt)) || j < 0 || (j > 0 && !whappr && ((omx == nix && omy == niy && !rn2(3)) || !rn2(12)) )) { nix = nx; niy = ny; nidist = ndist; if(j < 0) chcnt = 0; chi = i; } nxti: ; } newdogpos: if (nix != omx || niy != omy) { struct obj *mw_tmp; if (info[chi] & ALLOW_U) { if (mtmp->mleashed) { /* play it safe */ pline("%s breaks loose of %s leash!", Monnam(mtmp), mhis(mtmp)); m_unleash(mtmp, FALSE); } (void) mattacku(mtmp); return(0); } if (!m_in_out_region(mtmp, nix, niy)) return 1; if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) || closed_door(nix, niy)) && mtmp->weapon_check != NO_WEAPON_WANTED && tunnels(mtmp->data) && needspick(mtmp->data)) { if (closed_door(nix, niy)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_PICK_OR_AXE; } else if (IS_TREE(levl[nix][niy].typ)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_AXE; } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { mtmp->weapon_check = NEED_PICK_AXE; } if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp)) return 0; } /* insert a worm_move() if worms ever begin to eat things */ remove_monster(omx, omy); place_monster(mtmp, nix, niy); if (cursemsg[chi] && (cansee(omx,omy) || cansee(nix,niy))) pline("%s moves only reluctantly.", Monnam(mtmp)); for (j=MTSZ-1; j>0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; mtmp->mtrack[0].x = omx; mtmp->mtrack[0].y = omy; /* We have to know if the pet's gonna do a combined eat and * move before moving it, but it can't eat until after being * moved. Thus the do_eat flag. */ if (do_eat) { if (dog_eat(mtmp, obj, omx, omy, FALSE) == 2) return 2; } } else if (mtmp->mleashed && distu(omx, omy) > 4) { /* an incredible kludge, but the only way to keep pooch near * after it spends time eating or in a trap, etc. */ coord cc; nx = sgn(omx - u.ux); ny = sgn(omy - u.uy); cc.x = u.ux + nx; cc.y = u.uy + ny; if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; i = xytod(nx, ny); for (j = (i + 7)%8; j < (i + 1)%8; j++) { dtoxy(&cc, j); if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; } for (j = (i + 6)%8; j < (i + 2)%8; j++) { dtoxy(&cc, j); if (goodpos(cc.x, cc.y, mtmp, 0)) goto dognext; } cc.x = mtmp->mx; cc.y = mtmp->my; dognext: if (!m_in_out_region(mtmp, nix, niy)) return 1; remove_monster(mtmp->mx, mtmp->my); place_monster(mtmp, cc.x, cc.y); newsym(cc.x,cc.y); set_apparxy(mtmp); } return(1); } /* check if a monster could pick up objects from a location */ STATIC_OVL boolean could_reach_item(mon, nx, ny) struct monst *mon; xchar nx, ny; { if ((!is_pool(nx,ny) || is_swimmer(mon->data)) && (!is_lava(nx,ny) || likes_lava(mon->data)) && (!sobj_at(BOULDER,nx,ny) || throws_rocks(mon->data))) return TRUE; return FALSE; } /* Hack to prevent a dog from being endlessly stuck near an object that * it can't reach, such as caught in a teleport scroll niche. It recursively * checks to see if the squares in between are good. The checking could be a * little smarter; a full check would probably be useful in m_move() too. * Since the maximum food distance is 5, this should never be more than 5 calls * deep. */ STATIC_OVL boolean can_reach_location(mon, mx, my, fx, fy) struct monst *mon; xchar mx, my, fx, fy; { int i, j; int dist; if (mx == fx && my == fy) return TRUE; if (!isok(mx, my)) return FALSE; /* should not happen */ dist = dist2(mx, my, fx, fy); for(i=mx-1; i<=mx+1; i++) { for(j=my-1; j<=my+1; j++) { if (!isok(i, j)) continue; if (dist2(i, j, fx, fy) >= dist) continue; if (IS_ROCK(levl[i][j].typ) && !passes_walls(mon->data) && (!may_dig(i,j) || !tunnels(mon->data))) continue; if (IS_DOOR(levl[i][j].typ) && (levl[i][j].doormask & (D_CLOSED | D_LOCKED))) continue; if (!could_reach_item(mon, i, j)) continue; if (can_reach_location(mon, i, j, fx, fy)) return TRUE; } } return FALSE; } #endif /* OVL0 */ #ifdef OVLB /*ARGSUSED*/ /* do_clear_area client */ STATIC_PTR void wantdoor(x, y, distance) int x, y; genericptr_t distance; { int ndist; if (*(int*)distance > (ndist = distu(x, y))) { gx = x; gy = y; *(int*)distance = ndist; } } #endif /* OVLB */ /*dogmove.c*/ nethack-3.4.3/src/dokick.c0100644000000000000000000012222507764735041014055 0ustar rootroot/* SCCS Id: @(#)dokick.c 3.4 2003/12/04 */ /* Copyright (c) Izchak Miller, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "eshk.h" #define is_bigfoot(x) ((x) == &mons[PM_SASQUATCH]) #define martial() (martial_bonus() || is_bigfoot(youmonst.data) || \ (uarmf && uarmf->otyp == KICKING_BOOTS)) static NEARDATA struct rm *maploc; static NEARDATA const char *gate_str; extern boolean notonhead; /* for long worms */ STATIC_DCL void FDECL(kickdmg, (struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(kick_monster, (XCHAR_P, XCHAR_P)); STATIC_DCL int FDECL(kick_object, (XCHAR_P, XCHAR_P)); STATIC_DCL char *FDECL(kickstr, (char *)); STATIC_DCL void FDECL(otransit_msg, (struct obj *, BOOLEAN_P, long)); STATIC_DCL void FDECL(drop_to, (coord *,SCHAR_P)); static NEARDATA struct obj *kickobj; static const char kick_passes_thru[] = "kick passes harmlessly through"; STATIC_OVL void kickdmg(mon, clumsy) register struct monst *mon; register boolean clumsy; { register int mdx, mdy; register int dmg = ( ACURRSTR + ACURR(A_DEX) + ACURR(A_CON) )/ 15; int kick_skill = P_NONE; int blessed_foot_damage = 0; boolean trapkilled = FALSE; if (uarmf && uarmf->otyp == KICKING_BOOTS) dmg += 5; /* excessive wt affects dex, so it affects dmg */ if (clumsy) dmg /= 2; /* kicking a dragon or an elephant will not harm it */ if (thick_skinned(mon->data)) dmg = 0; /* attacking a shade is useless */ if (mon->data == &mons[PM_SHADE]) dmg = 0; if ((is_undead(mon->data) || is_demon(mon->data)) && uarmf && uarmf->blessed) blessed_foot_damage = 1; if (mon->data == &mons[PM_SHADE] && !blessed_foot_damage) { pline_The("%s.", kick_passes_thru); /* doesn't exercise skill or abuse alignment or frighten pet, and shades have no passive counterattack */ return; } if(mon->m_ap_type) seemimic(mon); check_caitiff(mon); /* squeeze some guilt feelings... */ if(mon->mtame) { abuse_dog(mon); if (mon->mtame) monflee(mon, (dmg ? rnd(dmg) : 1), FALSE, FALSE); else mon->mflee = 0; } if (dmg > 0) { /* convert potential damage to actual damage */ dmg = rnd(dmg); if (martial()) { if (dmg > 1) kick_skill = P_MARTIAL_ARTS; dmg += rn2(ACURR(A_DEX)/2 + 1); } /* a good kick exercises your dex */ exercise(A_DEX, TRUE); } if (blessed_foot_damage) dmg += rnd(4); if (uarmf) dmg += uarmf->spe; dmg += u.udaminc; /* add ring(s) of increase damage */ if (dmg > 0) mon->mhp -= dmg; if (mon->mhp > 0 && martial() && !bigmonst(mon->data) && !rn2(3) && mon->mcanmove && mon != u.ustuck && !mon->mtrapped) { /* see if the monster has a place to move into */ mdx = mon->mx + u.dx; mdy = mon->my + u.dy; if(goodpos(mdx, mdy, mon, 0)) { pline("%s reels from the blow.", Monnam(mon)); if (m_in_out_region(mon, mdx, mdy)) { remove_monster(mon->mx, mon->my); newsym(mon->mx, mon->my); place_monster(mon, mdx, mdy); newsym(mon->mx, mon->my); set_apparxy(mon); if (mintrap(mon) == 2) trapkilled = TRUE; } } } (void) passive(mon, TRUE, mon->mhp > 0, AT_KICK); if (mon->mhp <= 0 && !trapkilled) killed(mon); /* may bring up a dialog, so put this after all messages */ if (kick_skill != P_NONE) /* exercise proficiency */ use_skill(kick_skill, 1); } STATIC_OVL void kick_monster(x, y) register xchar x, y; { register boolean clumsy = FALSE; register struct monst *mon = m_at(x, y); register int i, j; bhitpos.x = x; bhitpos.y = y; if (attack_checks(mon, (struct obj *)0)) return; setmangry(mon); /* Kick attacks by kicking monsters are normal attacks, not special. * This is almost always worthless, since you can either take one turn * and do all your kicks, or else take one turn and attack the monster * normally, getting all your attacks _including_ all your kicks. * If you have >1 kick attack, you get all of them. */ if (Upolyd && attacktype(youmonst.data, AT_KICK)) { struct attack *uattk; int sum; schar tmp = find_roll_to_hit(mon); for (i = 0; i < NATTK; i++) { /* first of two kicks might have provoked counterattack that has incapacitated the hero (ie, floating eye) */ if (multi < 0) break; uattk = &youmonst.data->mattk[i]; /* we only care about kicking attacks here */ if (uattk->aatyp != AT_KICK) continue; if (mon->data == &mons[PM_SHADE] && (!uarmf || !uarmf->blessed)) { /* doesn't matter whether it would have hit or missed, and shades have no passive counterattack */ Your("%s %s.", kick_passes_thru, mon_nam(mon)); break; /* skip any additional kicks */ } else if (tmp > rnd(20)) { You("kick %s.", mon_nam(mon)); sum = damageum(mon, uattk); (void)passive(mon, (boolean)(sum > 0), (sum != 2), AT_KICK); if (sum == 2) break; /* Defender died */ } else { missum(mon, uattk); (void)passive(mon, 0, 1, AT_KICK); } } return; } if(Levitation && !rn2(3) && verysmall(mon->data) && !is_flyer(mon->data)) { pline("Floating in the air, you miss wildly!"); exercise(A_DEX, FALSE); (void) passive(mon, FALSE, 1, AT_KICK); return; } i = -inv_weight(); j = weight_cap(); if(i < (j*3)/10) { if(!rn2((i < j/10) ? 2 : (i < j/5) ? 3 : 4)) { if(martial() && !rn2(2)) goto doit; Your("clumsy kick does no damage."); (void) passive(mon, FALSE, 1, AT_KICK); return; } if(i < j/10) clumsy = TRUE; else if(!rn2((i < j/5) ? 2 : 3)) clumsy = TRUE; } if(Fumbling) clumsy = TRUE; else if(uarm && objects[uarm->otyp].oc_bulky && ACURR(A_DEX) < rnd(25)) clumsy = TRUE; doit: You("kick %s.", mon_nam(mon)); if(!rn2(clumsy ? 3 : 4) && (clumsy || !bigmonst(mon->data)) && mon->mcansee && !mon->mtrapped && !thick_skinned(mon->data) && mon->data->mlet != S_EEL && haseyes(mon->data) && mon->mcanmove && !mon->mstun && !mon->mconf && !mon->msleeping && mon->data->mmove >= 12) { if(!nohands(mon->data) && !rn2(martial() ? 5 : 3)) { pline("%s blocks your %skick.", Monnam(mon), clumsy ? "clumsy " : ""); (void) passive(mon, FALSE, 1, AT_KICK); return; } else { mnexto(mon); if(mon->mx != x || mon->my != y) { if(glyph_is_invisible(levl[x][y].glyph)) { unmap_object(x, y); newsym(x, y); } pline("%s %s, %s evading your %skick.", Monnam(mon), (can_teleport(mon->data) ? "teleports" : is_floater(mon->data) ? "floats" : is_flyer(mon->data) ? "swoops" : (nolimbs(mon->data) || slithy(mon->data)) ? "slides" : "jumps"), clumsy ? "easily" : "nimbly", clumsy ? "clumsy " : ""); (void) passive(mon, FALSE, 1, AT_KICK); return; } } } kickdmg(mon, clumsy); } /* * Return TRUE if caught (the gold taken care of), FALSE otherwise. * The gold object is *not* attached to the fobj chain! */ boolean ghitm(mtmp, gold) register struct monst *mtmp; register struct obj *gold; { boolean msg_given = FALSE; if(!likes_gold(mtmp->data) && !mtmp->isshk && !mtmp->ispriest && !is_mercenary(mtmp->data)) { wakeup(mtmp); } else if (!mtmp->mcanmove) { /* too light to do real damage */ if (canseemon(mtmp)) { pline_The("%s harmlessly %s %s.", xname(gold), otense(gold, "hit"), mon_nam(mtmp)); msg_given = TRUE; } } else { #ifdef GOLDOBJ long value = gold->quan * objects[gold->otyp].oc_cost; #endif mtmp->msleeping = 0; mtmp->meating = 0; if(!rn2(4)) setmangry(mtmp); /* not always pleasing */ /* greedy monsters catch gold */ if (cansee(mtmp->mx, mtmp->my)) pline("%s catches the gold.", Monnam(mtmp)); #ifndef GOLDOBJ mtmp->mgold += gold->quan; #endif if (mtmp->isshk) { long robbed = ESHK(mtmp)->robbed; if (robbed) { #ifndef GOLDOBJ robbed -= gold->quan; #else robbed -= value; #endif if (robbed < 0) robbed = 0; pline_The("amount %scovers %s recent losses.", !robbed ? "" : "partially ", mhis(mtmp)); ESHK(mtmp)->robbed = robbed; if(!robbed) make_happy_shk(mtmp, FALSE); } else { if(mtmp->mpeaceful) { #ifndef GOLDOBJ ESHK(mtmp)->credit += gold->quan; #else ESHK(mtmp)->credit += value; #endif You("have %ld %s in credit.", ESHK(mtmp)->credit, currency(ESHK(mtmp)->credit)); } else verbalize("Thanks, scum!"); } } else if (mtmp->ispriest) { if (mtmp->mpeaceful) verbalize("Thank you for your contribution."); else verbalize("Thanks, scum!"); } else if (is_mercenary(mtmp->data)) { long goldreqd = 0L; if (rn2(3)) { if (mtmp->data == &mons[PM_SOLDIER]) goldreqd = 100L; else if (mtmp->data == &mons[PM_SERGEANT]) goldreqd = 250L; else if (mtmp->data == &mons[PM_LIEUTENANT]) goldreqd = 500L; else if (mtmp->data == &mons[PM_CAPTAIN]) goldreqd = 750L; if (goldreqd) { #ifndef GOLDOBJ if (gold->quan > goldreqd + (u.ugold + u.ulevel*rn2(5))/ACURR(A_CHA)) #else if (value > goldreqd + (money_cnt(invent) + u.ulevel*rn2(5))/ACURR(A_CHA)) #endif mtmp->mpeaceful = TRUE; } } if (mtmp->mpeaceful) verbalize("That should do. Now beat it!"); else verbalize("That's not enough, coward!"); } #ifndef GOLDOBJ dealloc_obj(gold); #else add_to_minv(mtmp, gold); #endif return TRUE; } if (!msg_given) miss(xname(gold), mtmp); return FALSE; } /* container is kicked, dropped, thrown or otherwise impacted by player. * Assumes container is on floor. Checks contents for possible damage. */ void container_impact_dmg(obj) struct obj *obj; { struct monst *shkp; struct obj *otmp, *otmp2; long loss = 0L; boolean costly, insider; xchar x = obj->ox, y = obj->oy; /* only consider normal containers */ if (!Is_container(obj) || Is_mbag(obj)) return; costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && costly_spot(x, y)); insider = (*u.ushops && inside_shop(u.ux, u.uy) && *in_rooms(x, y, SHOPBASE) == *u.ushops); for (otmp = obj->cobj; otmp; otmp = otmp2) { const char *result = (char *)0; otmp2 = otmp->nobj; if (objects[otmp->otyp].oc_material == GLASS && otmp->oclass != GEM_CLASS && !obj_resists(otmp, 33, 100)) { result = "shatter"; } else if (otmp->otyp == EGG && !rn2(3)) { result = "cracking"; } if (result) { if (otmp->otyp == MIRROR) change_luck(-2); /* eggs laid by you. penalty is -1 per egg, max 5, * but it's always exactly 1 that breaks */ if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM) change_luck(-1); You_hear("a muffled %s.", result); if (costly) loss += stolen_value(otmp, x, y, (boolean)shkp->mpeaceful, TRUE); if (otmp->quan > 1L) useup(otmp); else { obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); } } } if (costly && loss) { if (!insider) { You("caused %ld %s worth of damage!", loss, currency(loss)); make_angry_shk(shkp, x, y); } else { You("owe %s %ld %s for objects destroyed.", mon_nam(shkp), loss, currency(loss)); } } } STATIC_OVL int kick_object(x, y) xchar x, y; { int range; register struct monst *mon, *shkp; struct trap *trap; char bhitroom; boolean costly, isgold, slide = FALSE; /* if a pile, the "top" object gets kicked */ kickobj = level.objects[x][y]; /* kickobj should always be set due to conditions of call */ if(!kickobj || kickobj->otyp == BOULDER || kickobj == uball || kickobj == uchain) return(0); if ((trap = t_at(x,y)) != 0 && (((trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && !Passes_walls) || trap->ttyp == WEB)) { if (!trap->tseen) find_trap(trap); You_cant("kick %s that's in a %s!", something, Hallucination ? "tizzy" : (trap->ttyp == WEB) ? "web" : "pit"); return 1; } if(Fumbling && !rn2(3)) { Your("clumsy kick missed."); return(1); } if(kickobj->otyp == CORPSE && touch_petrifies(&mons[kickobj->corpsenm]) && !Stone_resistance && !uarmf) { char kbuf[BUFSZ]; You("kick the %s with your bare %s.", corpse_xname(kickobj, TRUE), makeplural(body_part(FOOT))); if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { You("turn to stone..."); killer_format = KILLED_BY; /* KMH -- otmp should be kickobj */ Sprintf(kbuf, "kicking %s without boots", an(corpse_xname(kickobj, TRUE))); killer = kbuf; done(STONING); } } /* range < 2 means the object will not move. */ /* maybe dexterity should also figure here. */ range = (int)((ACURRSTR)/2 - kickobj->owt/40); if(martial()) range += rnd(3); if (is_pool(x, y)) { /* you're in the water too; significantly reduce range */ range = range / 3 + 1; /* {1,2}=>1, {3,4,5}=>2, {6,7,8}=>3 */ } else { if (is_ice(x, y)) range += rnd(3), slide = TRUE; if (kickobj->greased) range += rnd(3), slide = TRUE; } /* Mjollnir is magically too heavy to kick */ if(kickobj->oartifact == ART_MJOLLNIR) range = 1; /* see if the object has a place to move into */ if(!ZAP_POS(levl[x+u.dx][y+u.dy].typ) || closed_door(x+u.dx, y+u.dy)) range = 1; costly = ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) && costly_spot(x, y)); isgold = (kickobj->oclass == COIN_CLASS); if (IS_ROCK(levl[x][y].typ) || closed_door(x, y)) { if ((!martial() && rn2(20) > ACURR(A_DEX)) || IS_ROCK(levl[u.ux][u.uy].typ) || closed_door(u.ux, u.uy)) { if (Blind) pline("It doesn't come loose."); else pline("%s %sn't come loose.", The(distant_name(kickobj, xname)), otense(kickobj, "do")); return (!rn2(3) || martial()); } if (Blind) pline("It comes loose."); else pline("%s %s loose.", The(distant_name(kickobj, xname)), otense(kickobj, "come")); obj_extract_self(kickobj); newsym(x, y); if (costly && (!costly_spot(u.ux, u.uy) || !index(u.urooms, *in_rooms(x, y, SHOPBASE)))) addtobill(kickobj, FALSE, FALSE, FALSE); if (!flooreffects(kickobj, u.ux, u.uy, "fall")) { place_object(kickobj, u.ux, u.uy); stackobj(kickobj); newsym(u.ux, u.uy); } return 1; } /* a box gets a chance of breaking open here */ if(Is_box(kickobj)) { boolean otrp = kickobj->otrapped; if(range < 2) pline("THUD!"); container_impact_dmg(kickobj); if (kickobj->olocked) { if (!rn2(5) || (martial() && !rn2(2))) { You("break open the lock!"); kickobj->olocked = 0; kickobj->obroken = 1; if (otrp) (void) chest_trap(kickobj, LEG, FALSE); return(1); } } else { if (!rn2(3) || (martial() && !rn2(2))) { pline_The("lid slams open, then falls shut."); if (otrp) (void) chest_trap(kickobj, LEG, FALSE); return(1); } } if(range < 2) return(1); /* else let it fall through to the next cases... */ } /* fragile objects should not be kicked */ if (hero_breaks(kickobj, kickobj->ox, kickobj->oy, FALSE)) return 1; /* too heavy to move. range is calculated as potential distance from * player, so range == 2 means the object may move up to one square * from its current position */ if(range < 2 || (isgold && kickobj->quan > 300L)) { if(!Is_box(kickobj)) pline("Thump!"); return(!rn2(3) || martial()); } if (kickobj->quan > 1L && !isgold) kickobj = splitobj(kickobj, 1L); if (slide && !Blind) pline("Whee! %s %s across the %s.", Doname2(kickobj), otense(kickobj, "slide"), surface(x,y)); obj_extract_self(kickobj); (void) snuff_candle(kickobj); newsym(x, y); mon = bhit(u.dx, u.dy, range, KICKED_WEAPON, (int FDECL((*),(MONST_P,OBJ_P)))0, (int FDECL((*),(OBJ_P,OBJ_P)))0, kickobj); if(mon) { if (mon->isshk && kickobj->where == OBJ_MINVENT && kickobj->ocarry == mon) return 1; /* alert shk caught it */ notonhead = (mon->mx != bhitpos.x || mon->my != bhitpos.y); if (isgold ? ghitm(mon, kickobj) : /* caught? */ thitmonst(mon, kickobj)) /* hit && used up? */ return(1); } /* the object might have fallen down a hole */ if (kickobj->where == OBJ_MIGRATING) { if (costly) { if(isgold) costly_gold(x, y, kickobj->quan); else (void)stolen_value(kickobj, x, y, (boolean)shkp->mpeaceful, FALSE); } return 1; } bhitroom = *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE); if (costly && (!costly_spot(bhitpos.x, bhitpos.y) || *in_rooms(x, y, SHOPBASE) != bhitroom)) { if(isgold) costly_gold(x, y, kickobj->quan); else (void)stolen_value(kickobj, x, y, (boolean)shkp->mpeaceful, FALSE); } if(flooreffects(kickobj,bhitpos.x,bhitpos.y,"fall")) return(1); place_object(kickobj, bhitpos.x, bhitpos.y); stackobj(kickobj); newsym(kickobj->ox, kickobj->oy); return(1); } STATIC_OVL char * kickstr(buf) char *buf; { const char *what; if (kickobj) what = distant_name(kickobj,doname); else if (IS_DOOR(maploc->typ)) what = "a door"; else if (IS_TREE(maploc->typ)) what = "a tree"; else if (IS_STWALL(maploc->typ)) what = "a wall"; else if (IS_ROCK(maploc->typ)) what = "a rock"; else if (IS_THRONE(maploc->typ)) what = "a throne"; else if (IS_FOUNTAIN(maploc->typ)) what = "a fountain"; else if (IS_GRAVE(maploc->typ)) what = "a headstone"; #ifdef SINKS else if (IS_SINK(maploc->typ)) what = "a sink"; #endif else if (IS_ALTAR(maploc->typ)) what = "an altar"; else if (IS_DRAWBRIDGE(maploc->typ)) what = "a drawbridge"; else if (maploc->typ == STAIRS) what = "the stairs"; else if (maploc->typ == LADDER) what = "a ladder"; else if (maploc->typ == IRONBARS) what = "an iron bar"; else what = "something weird"; return strcat(strcpy(buf, "kicking "), what); } int dokick() { int x, y; int avrg_attrib; register struct monst *mtmp; boolean no_kick = FALSE; char buf[BUFSZ]; if (nolimbs(youmonst.data) || slithy(youmonst.data)) { You("have no legs to kick with."); no_kick = TRUE; } else if (verysmall(youmonst.data)) { You("are too small to do any kicking."); no_kick = TRUE; #ifdef STEED } else if (u.usteed) { if (yn_function("Kick your steed?", ynchars, 'y') == 'y') { You("kick %s.", mon_nam(u.usteed)); kick_steed(); return 1; } else { return 0; } #endif } else if (Wounded_legs) { /* note: jump() has similar code */ long wl = (EWounded_legs & BOTH_SIDES); const char *bp = body_part(LEG); if (wl == BOTH_SIDES) bp = makeplural(bp); Your("%s%s %s in no shape for kicking.", (wl == LEFT_SIDE) ? "left " : (wl == RIGHT_SIDE) ? "right " : "", bp, (wl == BOTH_SIDES) ? "are" : "is"); no_kick = TRUE; } else if (near_capacity() > SLT_ENCUMBER) { Your("load is too heavy to balance yourself for a kick."); no_kick = TRUE; } else if (youmonst.data->mlet == S_LIZARD) { Your("legs cannot kick effectively."); no_kick = TRUE; } else if (u.uinwater && !rn2(2)) { Your("slow motion kick doesn't hit anything."); no_kick = TRUE; } else if (u.utrap) { switch (u.utraptype) { case TT_PIT: pline("There's not enough room to kick down here."); break; case TT_WEB: case TT_BEARTRAP: You_cant("move your %s!", body_part(LEG)); break; default: break; } no_kick = TRUE; } if (no_kick) { /* ignore direction typed before player notices kick failed */ display_nhwindow(WIN_MESSAGE, TRUE); /* --More-- */ return 0; } if(!getdir((char *)0)) return(0); if(!u.dx && !u.dy) return(0); x = u.ux + u.dx; y = u.uy + u.dy; /* KMH -- Kicking boots always succeed */ if (uarmf && uarmf->otyp == KICKING_BOOTS) avrg_attrib = 99; else avrg_attrib = (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3; if(u.uswallow) { switch(rn2(3)) { case 0: You_cant("move your %s!", body_part(LEG)); break; case 1: if (is_animal(u.ustuck->data)) { pline("%s burps loudly.", Monnam(u.ustuck)); break; } default: Your("feeble kick has no effect."); break; } return(1); } if (Levitation) { int xx, yy; xx = u.ux - u.dx; yy = u.uy - u.dy; /* doors can be opened while levitating, so they must be * reachable for bracing purposes * Possible extension: allow bracing against stuff on the side? */ if (isok(xx,yy) && !IS_ROCK(levl[xx][yy].typ) && !IS_DOOR(levl[xx][yy].typ) && (!Is_airlevel(&u.uz) || !OBJ_AT(xx,yy))) { You("have nothing to brace yourself against."); return(0); } } wake_nearby(); u_wipe_engr(2); maploc = &levl[x][y]; /* The next five tests should stay in */ /* their present order: monsters, pools, */ /* objects, non-doors, doors. */ if(MON_AT(x, y)) { struct permonst *mdat; mtmp = m_at(x, y); mdat = mtmp->data; if (!mtmp->mpeaceful || !canspotmon(mtmp)) flags.forcefight = TRUE; /* attack even if invisible */ kick_monster(x, y); flags.forcefight = FALSE; /* see comment in attack_checks() */ if (!DEADMONSTER(mtmp) && !canspotmon(mtmp) && /* check x and y; a monster that evades your kick by jumping to an unseen square doesn't leave an I behind */ mtmp->mx == x && mtmp->my == y && !glyph_is_invisible(levl[x][y].glyph) && !(u.uswallow && mtmp == u.ustuck)) map_invisible(x, y); if((Is_airlevel(&u.uz) || Levitation) && flags.move) { int range; range = ((int)youmonst.data->cwt + (weight_cap() + inv_weight())); if (range < 1) range = 1; /* divide by zero avoidance */ range = (3*(int)mdat->cwt) / range; if(range < 1) range = 1; hurtle(-u.dx, -u.dy, range, TRUE); } return(1); } if (glyph_is_invisible(levl[x][y].glyph)) { unmap_object(x, y); newsym(x, y); } if (is_pool(x, y) ^ !!u.uinwater) { /* objects normally can't be removed from water by kicking */ You("splash some water around."); return 1; } kickobj = (struct obj *)0; if (OBJ_AT(x, y) && (!Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || sobj_at(BOULDER,x,y))) { if(kick_object(x, y)) { if(Is_airlevel(&u.uz)) hurtle(-u.dx, -u.dy, 1, TRUE); /* assume it's light */ return(1); } goto ouch; } if(!IS_DOOR(maploc->typ)) { if(maploc->typ == SDOOR) { if(!Levitation && rn2(30) < avrg_attrib) { cvt_sdoor_to_door(maploc); /* ->typ = DOOR */ pline("Crash! %s a secret door!", /* don't "kick open" when it's locked unless it also happens to be trapped */ (maploc->doormask & (D_LOCKED|D_TRAPPED)) == D_LOCKED ? "Your kick uncovers" : "You kick open"); exercise(A_DEX, TRUE); if(maploc->doormask & D_TRAPPED) { maploc->doormask = D_NODOOR; b_trapped("door", FOOT); } else if (maploc->doormask != D_NODOOR && !(maploc->doormask & D_LOCKED)) maploc->doormask = D_ISOPEN; if (Blind) feel_location(x,y); /* we know it's gone */ else newsym(x,y); if (maploc->doormask == D_ISOPEN || maploc->doormask == D_NODOOR) unblock_point(x,y); /* vision */ return(1); } else goto ouch; } if(maploc->typ == SCORR) { if(!Levitation && rn2(30) < avrg_attrib) { pline("Crash! You kick open a secret passage!"); exercise(A_DEX, TRUE); maploc->typ = CORR; if (Blind) feel_location(x,y); /* we know it's gone */ else newsym(x,y); unblock_point(x,y); /* vision */ return(1); } else goto ouch; } if(IS_THRONE(maploc->typ)) { register int i; if(Levitation) goto dumb; if((Luck < 0 || maploc->doormask) && !rn2(3)) { maploc->typ = ROOM; maploc->doormask = 0; /* don't leave loose ends.. */ (void) mkgold((long)rnd(200), x, y); if (Blind) pline("CRASH! You destroy it."); else { pline("CRASH! You destroy the throne."); newsym(x, y); } exercise(A_DEX, TRUE); return(1); } else if(Luck > 0 && !rn2(3) && !maploc->looted) { (void) mkgold((long) rn1(201, 300), x, y); i = Luck + 1; if(i > 6) i = 6; while(i--) (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE-1), x, y, FALSE, TRUE); if (Blind) You("kick %s loose!", something); else { You("kick loose some ornamental coins and gems!"); newsym(x, y); } /* prevent endless milking */ maploc->looted = T_LOOTED; return(1); } else if (!rn2(4)) { if(dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz)) { fall_through(FALSE); return(1); } else goto ouch; } goto ouch; } if(IS_ALTAR(maploc->typ)) { if(Levitation) goto dumb; You("kick %s.",(Blind ? something : "the altar")); if(!rn2(3)) goto ouch; altar_wrath(x, y); exercise(A_DEX, TRUE); return(1); } if(IS_FOUNTAIN(maploc->typ)) { if(Levitation) goto dumb; You("kick %s.",(Blind ? something : "the fountain")); if(!rn2(3)) goto ouch; /* make metal boots rust */ if(uarmf && rn2(3)) if (!rust_dmg(uarmf, "metal boots", 1, FALSE, &youmonst)) { Your("boots get wet."); /* could cause short-lived fumbling here */ } exercise(A_DEX, TRUE); return(1); } if(IS_GRAVE(maploc->typ) || maploc->typ == IRONBARS) goto ouch; if(IS_TREE(maploc->typ)) { struct obj *treefruit; /* nothing, fruit or trouble? 75:23.5:1.5% */ if (rn2(3)) { if ( !rn2(6) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE) ) You_hear("a low buzzing."); /* a warning */ goto ouch; } if (rn2(15) && !(maploc->looted & TREE_LOOTED) && (treefruit = rnd_treefruit_at(x, y))) { long nfruit = 8L-rnl(7), nfall; short frtype = treefruit->otyp; treefruit->quan = nfruit; if (is_plural(treefruit)) pline("Some %s fall from the tree!", xname(treefruit)); else pline("%s falls from the tree!", An(xname(treefruit))); nfall = scatter(x,y,2,MAY_HIT,treefruit); if (nfall != nfruit) { /* scatter left some in the tree, but treefruit * may not refer to the correct object */ treefruit = mksobj(frtype, TRUE, FALSE); treefruit->quan = nfruit-nfall; pline("%ld %s got caught in the branches.", nfruit-nfall, xname(treefruit)); dealloc_obj(treefruit); } exercise(A_DEX, TRUE); exercise(A_WIS, TRUE); /* discovered a new food source! */ newsym(x, y); maploc->looted |= TREE_LOOTED; return(1); } else if (!(maploc->looted & TREE_SWARM)) { int cnt = rnl(4) + 2; int made = 0; coord mm; mm.x = x; mm.y = y; while (cnt--) { if (enexto(&mm, mm.x, mm.y, &mons[PM_KILLER_BEE]) && makemon(&mons[PM_KILLER_BEE], mm.x, mm.y, MM_ANGRY)) made++; } if ( made ) pline("You've attracted the tree's former occupants!"); else You("smell stale honey."); maploc->looted |= TREE_SWARM; return(1); } goto ouch; } #ifdef SINKS if(IS_SINK(maploc->typ)) { int gend = poly_gender(); short washerndx = (gend == 1 || (gend == 2 && rn2(2))) ? PM_INCUBUS : PM_SUCCUBUS; if(Levitation) goto dumb; if(rn2(5)) { if(flags.soundok) pline("Klunk! The pipes vibrate noisily."); else pline("Klunk!"); exercise(A_DEX, TRUE); return(1); } else if(!(maploc->looted & S_LPUDDING) && !rn2(3) && !(mvitals[PM_BLACK_PUDDING].mvflags & G_GONE)) { if (Blind) You_hear("a gushing sound."); else pline("A %s ooze gushes up from the drain!", hcolor(NH_BLACK)); (void) makemon(&mons[PM_BLACK_PUDDING], x, y, NO_MM_FLAGS); exercise(A_DEX, TRUE); newsym(x,y); maploc->looted |= S_LPUDDING; return(1); } else if(!(maploc->looted & S_LDWASHER) && !rn2(3) && !(mvitals[washerndx].mvflags & G_GONE)) { /* can't resist... */ pline("%s returns!", (Blind ? Something : "The dish washer")); if (makemon(&mons[washerndx], x, y, NO_MM_FLAGS)) newsym(x,y); maploc->looted |= S_LDWASHER; exercise(A_DEX, TRUE); return(1); } else if(!rn2(3)) { pline("Flupp! %s.", (Blind ? "You hear a sloshing sound" : "Muddy waste pops up from the drain")); if(!(maploc->looted & S_LRING)) { /* once per sink */ if (!Blind) You("see a ring shining in its midst."); (void) mkobj_at(RING_CLASS, x, y, TRUE); newsym(x, y); exercise(A_DEX, TRUE); exercise(A_WIS, TRUE); /* a discovery! */ maploc->looted |= S_LRING; } return(1); } goto ouch; } #endif if (maploc->typ == STAIRS || maploc->typ == LADDER || IS_STWALL(maploc->typ)) { if(!IS_STWALL(maploc->typ) && maploc->ladder == LA_DOWN) goto dumb; ouch: pline("Ouch! That hurts!"); exercise(A_DEX, FALSE); exercise(A_STR, FALSE); if (Blind) feel_location(x,y); /* we know we hit it */ if (is_drawbridge_wall(x,y) >= 0) { pline_The("drawbridge is unaffected."); /* update maploc to refer to the drawbridge */ (void) find_drawbridge(&x,&y); maploc = &levl[x][y]; } if(!rn2(3)) set_wounded_legs(RIGHT_SIDE, 5 + rnd(5)); losehp(rnd(ACURR(A_CON) > 15 ? 3 : 5), kickstr(buf), KILLED_BY); if(Is_airlevel(&u.uz) || Levitation) hurtle(-u.dx, -u.dy, rn1(2,4), TRUE); /* assume it's heavy */ return(1); } goto dumb; } if(maploc->doormask == D_ISOPEN || maploc->doormask == D_BROKEN || maploc->doormask == D_NODOOR) { dumb: exercise(A_DEX, FALSE); if (martial() || ACURR(A_DEX) >= 16 || rn2(3)) { You("kick at empty space."); if (Blind) feel_location(x,y); } else { pline("Dumb move! You strain a muscle."); exercise(A_STR, FALSE); set_wounded_legs(RIGHT_SIDE, 5 + rnd(5)); } if ((Is_airlevel(&u.uz) || Levitation) && rn2(2)) { hurtle(-u.dx, -u.dy, 1, TRUE); return 1; /* you moved, so use up a turn */ } return(0); } /* not enough leverage to kick open doors while levitating */ if(Levitation) goto ouch; exercise(A_DEX, TRUE); /* door is known to be CLOSED or LOCKED */ if(rnl(35) < avrg_attrib + (!martial() ? 0 : ACURR(A_DEX))) { boolean shopdoor = *in_rooms(x, y, SHOPBASE) ? TRUE : FALSE; /* break the door */ if(maploc->doormask & D_TRAPPED) { if (flags.verbose) You("kick the door."); exercise(A_STR, FALSE); maploc->doormask = D_NODOOR; b_trapped("door", FOOT); } else if(ACURR(A_STR) > 18 && !rn2(5) && !shopdoor) { pline("As you kick the door, it shatters to pieces!"); exercise(A_STR, TRUE); maploc->doormask = D_NODOOR; } else { pline("As you kick the door, it crashes open!"); exercise(A_STR, TRUE); maploc->doormask = D_BROKEN; } if (Blind) feel_location(x,y); /* we know we broke it */ else newsym(x,y); unblock_point(x,y); /* vision */ if (shopdoor) { add_damage(x, y, 400L); pay_for_damage("break", FALSE); } if (in_town(x, y)) for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if((mtmp->data == &mons[PM_WATCHMAN] || mtmp->data == &mons[PM_WATCH_CAPTAIN]) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) { if (canspotmon(mtmp)) pline("%s yells:", Amonnam(mtmp)); else You_hear("someone yell:"); verbalize("Halt, thief! You're under arrest!"); (void) angry_guards(FALSE); break; } } } else { if (Blind) feel_location(x,y); /* we know we hit it */ exercise(A_STR, TRUE); pline("WHAMMM!!!"); if (in_town(x, y)) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->data == &mons[PM_WATCHMAN] || mtmp->data == &mons[PM_WATCH_CAPTAIN]) && mtmp->mpeaceful && couldsee(mtmp->mx, mtmp->my)) { if (canspotmon(mtmp)) pline("%s yells:", Amonnam(mtmp)); else You_hear("someone yell:"); if(levl[x][y].looted & D_WARNED) { verbalize("Halt, vandal! You're under arrest!"); (void) angry_guards(FALSE); } else { verbalize("Hey, stop damaging that door!"); levl[x][y].looted |= D_WARNED; } break; } } } return(1); } STATIC_OVL void drop_to(cc, loc) coord *cc; schar loc; { /* cover all the MIGR_xxx choices generated by down_gate() */ switch (loc) { case MIGR_RANDOM: /* trap door or hole */ if (Is_stronghold(&u.uz)) { cc->x = valley_level.dnum; cc->y = valley_level.dlevel; break; } else if (In_endgame(&u.uz) || Is_botlevel(&u.uz)) { cc->y = cc->x = 0; break; } /* else fall to the next cases */ case MIGR_STAIRS_UP: case MIGR_LADDER_UP: cc->x = u.uz.dnum; cc->y = u.uz.dlevel + 1; break; case MIGR_SSTAIRS: cc->x = sstairs.tolev.dnum; cc->y = sstairs.tolev.dlevel; break; default: case MIGR_NOWHERE: /* y==0 means "nowhere", in which case x doesn't matter */ cc->y = cc->x = 0; break; } } void impact_drop(missile, x, y, dlev) struct obj *missile; xchar x, y, dlev; { schar toloc; register struct obj *obj, *obj2; register struct monst *shkp; long oct, dct, price, debit, robbed; boolean angry, costly, isrock; coord cc; if(!OBJ_AT(x, y)) return; toloc = down_gate(x, y); drop_to(&cc, toloc); if (!cc.y) return; if (dlev) { /* send objects next to player falling through trap door. * checked in obj_delivery(). */ toloc = MIGR_NEAR_PLAYER; cc.y = dlev; } costly = costly_spot(x, y); price = debit = robbed = 0L; angry = FALSE; shkp = (struct monst *) 0; /* if 'costly', we must keep a record of ESHK(shkp) before * it undergoes changes through the calls to stolen_value. * the angry bit must be reset, if needed, in this fn, since * stolen_value is called under the 'silent' flag to avoid * unsavory pline repetitions. */ if(costly) { if ((shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) != 0) { debit = ESHK(shkp)->debit; robbed = ESHK(shkp)->robbed; angry = !shkp->mpeaceful; } } isrock = (missile && missile->otyp == ROCK); oct = dct = 0L; for(obj = level.objects[x][y]; obj; obj = obj2) { obj2 = obj->nexthere; if(obj == missile) continue; /* number of objects in the pile */ oct += obj->quan; if(obj == uball || obj == uchain) continue; /* boulders can fall too, but rarely & never due to rocks */ if((isrock && obj->otyp == BOULDER) || rn2(obj->otyp == BOULDER ? 30 : 3)) continue; obj_extract_self(obj); if(costly) { price += stolen_value(obj, x, y, (costly_spot(u.ux, u.uy) && index(u.urooms, *in_rooms(x, y, SHOPBASE))), TRUE); /* set obj->no_charge to 0 */ if (Has_contents(obj)) picked_container(obj); /* does the right thing */ if (obj->oclass != COIN_CLASS) obj->no_charge = 0; } add_to_migration(obj); obj->ox = cc.x; obj->oy = cc.y; obj->owornmask = (long)toloc; /* number of fallen objects */ dct += obj->quan; } if (dct && cansee(x,y)) { /* at least one object fell */ const char *what = (dct == 1L ? "object falls" : "objects fall"); if (missile) pline("From the impact, %sother %s.", dct == oct ? "the " : dct == 1L ? "an" : "", what); else if (oct == dct) pline("%s adjacent %s %s.", dct == 1L ? "The" : "All the", what, gate_str); else pline("%s adjacent %s %s.", dct == 1L ? "One of the" : "Some of the", dct == 1L ? "objects falls" : what, gate_str); } if(costly && shkp && price) { if(ESHK(shkp)->robbed > robbed) { You("removed %ld %s worth of goods!", price, currency(price)); if(cansee(shkp->mx, shkp->my)) { if(ESHK(shkp)->customer[0] == 0) (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ); if(angry) pline("%s is infuriated!", Monnam(shkp)); else pline("\"%s, you are a thief!\"", plname); } else You_hear("a scream, \"Thief!\""); hot_pursuit(shkp); (void) angry_guards(FALSE); return; } if(ESHK(shkp)->debit > debit) { long amt = (ESHK(shkp)->debit - debit); You("owe %s %ld %s for goods lost.", Monnam(shkp), amt, currency(amt)); } } } /* NOTE: ship_object assumes otmp was FREED from fobj or invent. * is the point of drop. otmp is _not_ an resident: * otmp is either a kicked, dropped, or thrown object. */ boolean ship_object(otmp, x, y, shop_floor_obj) xchar x, y; struct obj *otmp; boolean shop_floor_obj; { schar toloc; xchar ox, oy; coord cc; struct obj *obj; struct trap *t; boolean nodrop, unpaid, container, impact = FALSE; long n = 0L; if (!otmp) return(FALSE); if ((toloc = down_gate(x, y)) == MIGR_NOWHERE) return(FALSE); drop_to(&cc, toloc); if (!cc.y) return(FALSE); /* objects other than attached iron ball always fall down ladder, but have a chance of staying otherwise */ nodrop = (otmp == uball) || (otmp == uchain) || (toloc != MIGR_LADDER_UP && rn2(3)); container = Has_contents(otmp); unpaid = (otmp->unpaid || (container && count_unpaid(otmp->cobj))); if(OBJ_AT(x, y)) { for(obj = level.objects[x][y]; obj; obj = obj->nexthere) if(obj != otmp) n += obj->quan; if(n) impact = TRUE; } /* boulders never fall through trap doors, but they might knock other things down before plugging the hole */ if (otmp->otyp == BOULDER && ((t = t_at(x, y)) != 0) && (t->ttyp == TRAPDOOR || t->ttyp == HOLE)) { if (impact) impact_drop(otmp, x, y, 0); return FALSE; /* let caller finish the drop */ } if (cansee(x, y)) otransit_msg(otmp, nodrop, n); if (nodrop) { if (impact) impact_drop(otmp, x, y, 0); return(FALSE); } if(unpaid || shop_floor_obj) { if(unpaid) { subfrombill(otmp, shop_keeper(*u.ushops)); (void)stolen_value(otmp, u.ux, u.uy, TRUE, FALSE); } else { ox = otmp->ox; oy = otmp->oy; (void)stolen_value(otmp, ox, oy, (costly_spot(u.ux, u.uy) && index(u.urooms, *in_rooms(ox, oy, SHOPBASE))), FALSE); } /* set otmp->no_charge to 0 */ if(container) picked_container(otmp); /* happens to do the right thing */ if(otmp->oclass != COIN_CLASS) otmp->no_charge = 0; } if (otmp == uwep) setuwep((struct obj *)0); if (otmp == uquiver) setuqwep((struct obj *)0); if (otmp == uswapwep) setuswapwep((struct obj *)0); /* some things break rather than ship */ if (breaktest(otmp)) { const char *result; if (objects[otmp->otyp].oc_material == GLASS #ifdef TOURIST || otmp->otyp == EXPENSIVE_CAMERA #endif ) { if (otmp->otyp == MIRROR) change_luck(-2); result = "crash"; } else { /* penalty for breaking eggs laid by you */ if (otmp->otyp == EGG && otmp->spe && otmp->corpsenm >= LOW_PM) change_luck((schar) -min(otmp->quan, 5L)); result = "splat"; } You_hear("a muffled %s.",result); obj_extract_self(otmp); obfree(otmp, (struct obj *) 0); return TRUE; } add_to_migration(otmp); otmp->ox = cc.x; otmp->oy = cc.y; otmp->owornmask = (long)toloc; /* boulder from rolling boulder trap, no longer part of the trap */ if (otmp->otyp == BOULDER) otmp->otrapped = 0; if(impact) { /* the objs impacted may be in a shop other than * the one in which the hero is located. another * check for a shk is made in impact_drop. it is, e.g., * possible to kick/throw an object belonging to one * shop into another shop through a gap in the wall, * and cause objects belonging to the other shop to * fall down a trap door--thereby getting two shopkeepers * angry at the hero in one shot. */ impact_drop(otmp, x, y, 0); newsym(x,y); } return(TRUE); } void obj_delivery() { register struct obj *otmp, *otmp2; register int nx, ny; long where; for (otmp = migrating_objs; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->ox != u.uz.dnum || otmp->oy != u.uz.dlevel) continue; obj_extract_self(otmp); where = otmp->owornmask; /* destination code */ otmp->owornmask = 0L; switch ((int)where) { case MIGR_STAIRS_UP: nx = xupstair, ny = yupstair; break; case MIGR_LADDER_UP: nx = xupladder, ny = yupladder; break; case MIGR_SSTAIRS: nx = sstairs.sx, ny = sstairs.sy; break; case MIGR_NEAR_PLAYER: nx = u.ux, ny = u.uy; break; default: case MIGR_RANDOM: nx = ny = 0; break; } if (nx > 0) { place_object(otmp, nx, ny); stackobj(otmp); (void)scatter(nx, ny, rnd(2), 0, otmp); } else { /* random location */ /* set dummy coordinates because there's no current position for rloco() to update */ otmp->ox = otmp->oy = 0; rloco(otmp); } } } STATIC_OVL void otransit_msg(otmp, nodrop, num) register struct obj *otmp; register boolean nodrop; long num; { char obuf[BUFSZ]; Sprintf(obuf, "%s%s", (otmp->otyp == CORPSE && type_is_pname(&mons[otmp->corpsenm])) ? "" : "The ", xname(otmp)); if(num) { /* means: other objects are impacted */ Sprintf(eos(obuf), " %s %s object%s", otense(otmp, "hit"), num == 1L ? "another" : "other", num > 1L ? "s" : ""); if(nodrop) Sprintf(eos(obuf), "."); else Sprintf(eos(obuf), " and %s %s.", otense(otmp, "fall"), gate_str); pline("%s", obuf); } else if(!nodrop) pline("%s %s %s.", obuf, otense(otmp, "fall"), gate_str); } /* migration destination for objects which fall down to next level */ schar down_gate(x, y) xchar x, y; { struct trap *ttmp; gate_str = 0; /* this matches the player restriction in goto_level() */ if (on_level(&u.uz, &qstart_level) && !ok_to_quest()) return MIGR_NOWHERE; if ((xdnstair == x && ydnstair == y) || (sstairs.sx == x && sstairs.sy == y && !sstairs.up)) { gate_str = "down the stairs"; return (xdnstair == x && ydnstair == y) ? MIGR_STAIRS_UP : MIGR_SSTAIRS; } if (xdnladder == x && ydnladder == y) { gate_str = "down the ladder"; return MIGR_LADDER_UP; } if (((ttmp = t_at(x, y)) != 0 && ttmp->tseen) && (ttmp->ttyp == TRAPDOOR || ttmp->ttyp == HOLE)) { gate_str = (ttmp->ttyp == TRAPDOOR) ? "through the trap door" : "through the hole"; return MIGR_RANDOM; } return MIGR_NOWHERE; } /*dokick.c*/ nethack-3.4.3/src/dothrow.c0100644000000000000000000014155407764735041014305 0ustar rootroot/* SCCS Id: @(#)dothrow.c 3.4 2003/12/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* Contains code for 't' (throw) */ #include "hack.h" #include "edog.h" STATIC_DCL int FDECL(throw_obj, (struct obj *,int)); STATIC_DCL void NDECL(autoquiver); STATIC_DCL int FDECL(gem_accept, (struct monst *, struct obj *)); STATIC_DCL void FDECL(tmiss, (struct obj *, struct monst *)); STATIC_DCL int FDECL(throw_gold, (struct obj *)); STATIC_DCL void FDECL(check_shop_obj, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P)); STATIC_DCL void FDECL(breakobj, (struct obj *,XCHAR_P,XCHAR_P,BOOLEAN_P,BOOLEAN_P)); STATIC_DCL void FDECL(breakmsg, (struct obj *,BOOLEAN_P)); STATIC_DCL boolean FDECL(toss_up,(struct obj *, BOOLEAN_P)); STATIC_DCL boolean FDECL(throwing_weapon, (struct obj *)); STATIC_DCL void FDECL(sho_obj_return_to_u, (struct obj *obj)); STATIC_DCL boolean FDECL(mhurtle_step, (genericptr_t,int,int)); static NEARDATA const char toss_objs[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, WEAPON_CLASS, 0 }; /* different default choices when wielding a sling (gold must be included) */ static NEARDATA const char bullets[] = { ALLOW_COUNT, COIN_CLASS, ALL_CLASSES, GEM_CLASS, 0 }; struct obj *thrownobj = 0; /* tracks an object until it lands */ extern boolean notonhead; /* for long worms */ /* Throw the selected object, asking for direction */ STATIC_OVL int throw_obj(obj, shotlimit) struct obj *obj; int shotlimit; { struct obj *otmp; int multishot = 1; schar skill; long wep_mask; boolean twoweap; /* ask "in what direction?" */ #ifndef GOLDOBJ if (!getdir((char *)0)) { if (obj->oclass == COIN_CLASS) { u.ugold += obj->quan; flags.botl = 1; dealloc_obj(obj); } return(0); } if(obj->oclass == COIN_CLASS) return(throw_gold(obj)); #else if (!getdir((char *)0)) { /* obj might need to be merged back into the singular gold object */ freeinv(obj); addinv(obj); return(0); } /* Throwing money is usually for getting rid of it when a leprechaun approaches, or for bribing an oncoming angry monster. So throw the whole object. If the money is in quiver, throw one coin at a time, possibly using a sling. */ if(obj->oclass == COIN_CLASS && obj != uquiver) return(throw_gold(obj)); #endif if(!canletgo(obj,"throw")) return(0); if (obj->oartifact == ART_MJOLLNIR && obj != uwep) { pline("%s must be wielded before it can be thrown.", The(xname(obj))); return(0); } if ((obj->oartifact == ART_MJOLLNIR && ACURR(A_STR) < STR19(25)) || (obj->otyp == BOULDER && !throws_rocks(youmonst.data))) { pline("It's too heavy."); return(1); } if(!u.dx && !u.dy && !u.dz) { You("cannot throw an object at yourself."); return(0); } u_wipe_engr(2); if (!uarmg && !Stone_resistance && (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm]))) { You("throw the %s corpse with your bare %s.", mons[obj->corpsenm].mname, body_part(HAND)); Sprintf(killer_buf, "%s corpse", an(mons[obj->corpsenm].mname)); instapetrify(killer_buf); } if (welded(obj)) { weldmsg(obj); return 1; } /* Multishot calculations */ skill = objects[obj->otyp].oc_skill; if ((ammo_and_launcher(obj, uwep) || skill == P_DAGGER || skill == -P_DART || skill == -P_SHURIKEN) && !(Confusion || Stunned)) { /* Bonus if the player is proficient in this weapon... */ switch (P_SKILL(weapon_type(obj))) { default: break; /* No bonus */ case P_SKILLED: multishot++; break; case P_EXPERT: multishot += 2; break; } /* ...or is using a special weapon for their role... */ switch (Role_switch) { case PM_RANGER: multishot++; break; case PM_ROGUE: if (skill == P_DAGGER) multishot++; break; case PM_SAMURAI: if (obj->otyp == YA && uwep && uwep->otyp == YUMI) multishot++; break; default: break; /* No bonus */ } /* ...or using their race's special bow */ switch (Race_switch) { case PM_ELF: if (obj->otyp == ELVEN_ARROW && uwep && uwep->otyp == ELVEN_BOW) multishot++; break; case PM_ORC: if (obj->otyp == ORCISH_ARROW && uwep && uwep->otyp == ORCISH_BOW) multishot++; break; default: break; /* No bonus */ } } if ((long)multishot > obj->quan) multishot = (int)obj->quan; multishot = rnd(multishot); if (shotlimit > 0 && multishot > shotlimit) multishot = shotlimit; m_shot.s = ammo_and_launcher(obj,uwep) ? TRUE : FALSE; /* give a message if shooting more than one, or if player attempted to specify a count */ if (multishot > 1 || shotlimit > 0) { /* "You shoot N arrows." or "You throw N daggers." */ You("%s %d %s.", m_shot.s ? "shoot" : "throw", multishot, /* (might be 1 if player gave shotlimit) */ (multishot == 1) ? singular(obj, xname) : xname(obj)); } wep_mask = obj->owornmask; m_shot.o = obj->otyp; m_shot.n = multishot; for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) { twoweap = u.twoweap; /* split this object off from its slot if necessary */ if (obj->quan > 1L) { otmp = splitobj(obj, 1L); } else { otmp = obj; if (otmp->owornmask) remove_worn_item(otmp, FALSE); } freeinv(otmp); throwit(otmp, wep_mask, twoweap); } m_shot.n = m_shot.i = 0; m_shot.o = STRANGE_OBJECT; m_shot.s = FALSE; return 1; } int dothrow() { register struct obj *obj; int shotlimit; /* * Since some characters shoot multiple missiles at one time, * allow user to specify a count prefix for 'f' or 't' to limit * number of items thrown (to avoid possibly hitting something * behind target after killing it, or perhaps to conserve ammo). * * Prior to 3.3.0, command ``3t'' meant ``t(shoot) t(shoot) t(shoot)'' * and took 3 turns. Now it means ``t(shoot at most 3 missiles)''. */ /* kludge to work around parse()'s pre-decrement of `multi' */ shotlimit = (multi || save_cm) ? multi + 1 : 0; multi = 0; /* reset; it's been used up */ if (notake(youmonst.data)) { You("are physically incapable of throwing anything."); return 0; } if(check_capacity((char *)0)) return(0); obj = getobj(uslinging() ? bullets : toss_objs, "throw"); /* it is also possible to throw food */ /* (or jewels, or iron balls... ) */ if (!obj) return(0); return throw_obj(obj, shotlimit); } /* KMH -- Automatically fill quiver */ /* Suggested by Jeffrey Bay */ static void autoquiver() { struct obj *otmp, *oammo = 0, *omissile = 0, *omisc = 0, *altammo = 0; if (uquiver) return; /* Scan through the inventory */ for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->owornmask || otmp->oartifact || !otmp->dknown) { ; /* Skip it */ } else if (otmp->otyp == ROCK || /* seen rocks or known flint or known glass */ (objects[otmp->otyp].oc_name_known && otmp->otyp == FLINT) || (objects[otmp->otyp].oc_name_known && otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material == GLASS)) { if (uslinging()) oammo = otmp; else if (ammo_and_launcher(otmp, uswapwep)) altammo = otmp; else if (!omisc) omisc = otmp; } else if (otmp->oclass == GEM_CLASS) { ; /* skip non-rock gems--they're ammo but player has to select them explicitly */ } else if (is_ammo(otmp)) { if (ammo_and_launcher(otmp, uwep)) /* Ammo matched with launcher (bow and arrow, crossbow and bolt) */ oammo = otmp; else if (ammo_and_launcher(otmp, uswapwep)) altammo = otmp; else /* Mismatched ammo (no better than an ordinary weapon) */ omisc = otmp; } else if (is_missile(otmp)) { /* Missile (dart, shuriken, etc.) */ omissile = otmp; } else if (otmp->oclass == WEAPON_CLASS && throwing_weapon(otmp)) { /* Ordinary weapon */ if (objects[otmp->otyp].oc_skill == P_DAGGER && !omissile) omissile = otmp; else omisc = otmp; } } /* Pick the best choice */ if (oammo) setuqwep(oammo); else if (omissile) setuqwep(omissile); else if (altammo) setuqwep(altammo); else if (omisc) setuqwep(omisc); return; } /* Throw from the quiver */ int dofire() { int shotlimit; if (notake(youmonst.data)) { You("are physically incapable of doing that."); return 0; } if(check_capacity((char *)0)) return(0); if (!uquiver) { if (!flags.autoquiver) { /* Don't automatically fill the quiver */ You("have no ammunition readied!"); return(dothrow()); } autoquiver(); if (!uquiver) { You("have nothing appropriate for your quiver!"); return(dothrow()); } else { You("fill your quiver:"); prinv((char *)0, uquiver, 0L); } } /* * Since some characters shoot multiple missiles at one time, * allow user to specify a count prefix for 'f' or 't' to limit * number of items thrown (to avoid possibly hitting something * behind target after killing it, or perhaps to conserve ammo). * * The number specified can never increase the number of missiles. * Using ``5f'' when the shooting skill (plus RNG) dictates launch * of 3 projectiles will result in 3 being shot, not 5. */ /* kludge to work around parse()'s pre-decrement of `multi' */ shotlimit = (multi || save_cm) ? multi + 1 : 0; multi = 0; /* reset; it's been used up */ return throw_obj(uquiver, shotlimit); } /* * Object hits floor at hero's feet. Called from drop() and throwit(). */ void hitfloor(obj) register struct obj *obj; { if (IS_SOFT(levl[u.ux][u.uy].typ) || u.uinwater) { dropy(obj); return; } if (IS_ALTAR(levl[u.ux][u.uy].typ)) doaltarobj(obj); else pline("%s hit%s the %s.", Doname2(obj), (obj->quan == 1L) ? "s" : "", surface(u.ux,u.uy)); if (hero_breaks(obj, u.ux, u.uy, TRUE)) return; if (ship_object(obj, u.ux, u.uy, FALSE)) return; dropy(obj); if (!u.uswallow) container_impact_dmg(obj); } /* * Walk a path from src_cc to dest_cc, calling a proc for each location * except the starting one. If the proc returns FALSE, stop walking * and return FALSE. If stopped early, dest_cc will be the location * before the failed callback. */ boolean walk_path(src_cc, dest_cc, check_proc, arg) coord *src_cc; coord *dest_cc; boolean FDECL((*check_proc), (genericptr_t, int, int)); genericptr_t arg; { int x, y, dx, dy, x_change, y_change, err, i, prev_x, prev_y; boolean keep_going = TRUE; /* Use Bresenham's Line Algorithm to walk from src to dest */ dx = dest_cc->x - src_cc->x; dy = dest_cc->y - src_cc->y; prev_x = x = src_cc->x; prev_y = y = src_cc->y; if (dx < 0) { x_change = -1; dx = -dx; } else x_change = 1; if (dy < 0) { y_change = -1; dy = -dy; } else y_change = 1; i = err = 0; if (dx < dy) { while (i++ < dy) { prev_x = x; prev_y = y; y += y_change; err += dx; if (err >= dy) { x += x_change; err -= dy; } /* check for early exit condition */ if (!(keep_going = (*check_proc)(arg, x, y))) break; } } else { while (i++ < dx) { prev_x = x; prev_y = y; x += x_change; err += dy; if (err >= dx) { y += y_change; err -= dx; } /* check for early exit condition */ if (!(keep_going = (*check_proc)(arg, x, y))) break; } } if (keep_going) return TRUE; /* successful */ dest_cc->x = prev_x; dest_cc->y = prev_y; return FALSE; } /* * Single step for the hero flying through the air from jumping, flying, * etc. Called from hurtle() and jump() via walk_path(). We expect the * argument to be a pointer to an integer -- the range -- which is * used in the calculation of points off if we hit something. * * Bumping into monsters won't cause damage but will wake them and make * them angry. Auto-pickup isn't done, since you don't have control over * your movements at the time. * * Possible additions/changes: * o really attack monster if we hit one * o set stunned if we hit a wall or door * o reset nomul when we stop * o creepy feeling if pass through monster (if ever implemented...) * o bounce off walls * o let jumps go over boulders */ boolean hurtle_step(arg, x, y) genericptr_t arg; int x, y; { int ox, oy, *range = (int *)arg; struct obj *obj; struct monst *mon; boolean may_pass = TRUE; struct trap *ttmp; if (!isok(x,y)) { You_feel("the spirits holding you back."); return FALSE; } else if (!in_out_region(x, y)) { return FALSE; } else if (*range == 0) { return FALSE; /* previous step wants to stop now */ } if (!Passes_walls || !(may_pass = may_passwall(x, y))) { if (IS_ROCK(levl[x][y].typ) || closed_door(x,y)) { const char *s; pline("Ouch!"); if (IS_TREE(levl[x][y].typ)) s = "bumping into a tree"; else if (IS_ROCK(levl[x][y].typ)) s = "bumping into a wall"; else s = "bumping into a door"; losehp(rnd(2+*range), s, KILLED_BY); return FALSE; } if (levl[x][y].typ == IRONBARS) { You("crash into some iron bars. Ouch!"); losehp(rnd(2+*range), "crashing into iron bars", KILLED_BY); return FALSE; } if ((obj = sobj_at(BOULDER,x,y)) != 0) { You("bump into a %s. Ouch!", xname(obj)); losehp(rnd(2+*range), "bumping into a boulder", KILLED_BY); return FALSE; } if (!may_pass) { /* did we hit a no-dig non-wall position? */ You("smack into something!"); losehp(rnd(2+*range), "touching the edge of the universe", KILLED_BY); return FALSE; } if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) { boolean too_much = (invent && (inv_weight() + weight_cap() > 600)); /* Move at a diagonal. */ if (bigmonst(youmonst.data) || too_much) { You("%sget forcefully wedged into a crevice.", too_much ? "and all your belongings " : ""); losehp(rnd(2+*range), "wedging into a narrow crevice", KILLED_BY); return FALSE; } } } if ((mon = m_at(x, y)) != 0) { You("bump into %s.", a_monnam(mon)); wakeup(mon); return FALSE; } if ((u.ux - x) && (u.uy - y) && bad_rock(youmonst.data,u.ux,y) && bad_rock(youmonst.data,x,u.uy)) { /* Move at a diagonal. */ if (In_sokoban(&u.uz)) { You("come to an abrupt halt!"); return FALSE; } } ox = u.ux; oy = u.uy; u.ux = x; u.uy = y; newsym(ox, oy); /* update old position */ vision_recalc(1); /* update for new position */ flush_screen(1); /* FIXME: * Each trap should really trigger on the recoil if * it would trigger during normal movement. However, * not all the possible side-effects of this are * tested [as of 3.4.0] so we trigger those that * we have tested, and offer a message for the * ones that we have not yet tested. */ if ((ttmp = t_at(x, y)) != 0) { if (ttmp->ttyp == MAGIC_PORTAL) { dotrap(ttmp,0); return FALSE; } else if (ttmp->ttyp == FIRE_TRAP) { dotrap(ttmp,0); } else if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT || ttmp->ttyp == HOLE || ttmp->ttyp == TRAPDOOR) && In_sokoban(&u.uz)) { /* Air currents overcome the recoil */ dotrap(ttmp,0); *range = 0; return TRUE; } else { if (ttmp->tseen) You("pass right over %s %s.", (ttmp->ttyp == ARROW_TRAP) ? "an" : "a", defsyms[trap_to_defsym(ttmp->ttyp)].explanation); } } if (--*range < 0) /* make sure our range never goes negative */ *range = 0; if (*range != 0) delay_output(); return TRUE; } STATIC_OVL boolean mhurtle_step(arg, x, y) genericptr_t arg; int x, y; { struct monst *mon = (struct monst *)arg; /* TODO: Treat walls, doors, iron bars, pools, lava, etc. specially * rather than just stopping before. */ if (goodpos(x, y, mon, 0) && m_in_out_region(mon, x, y)) { remove_monster(mon->mx, mon->my); newsym(mon->mx, mon->my); place_monster(mon, x, y); newsym(mon->mx, mon->my); set_apparxy(mon); (void) mintrap(mon); return TRUE; } return FALSE; } /* * The player moves through the air for a few squares as a result of * throwing or kicking something. * * dx and dy should be the direction of the hurtle, not of the original * kick or throw and be only. */ void hurtle(dx, dy, range, verbose) int dx, dy, range; boolean verbose; { coord uc, cc; /* The chain is stretched vertically, so you shouldn't be able to move * very far diagonally. The premise that you should be able to move one * spot leads to calculations that allow you to only move one spot away * from the ball, if you are levitating over the ball, or one spot * towards the ball, if you are at the end of the chain. Rather than * bother with all of that, assume that there is no slack in the chain * for diagonal movement, give the player a message and return. */ if(Punished && !carried(uball)) { You_feel("a tug from the iron ball."); nomul(0); return; } else if (u.utrap) { You("are anchored by the %s.", u.utraptype == TT_WEB ? "web" : u.utraptype == TT_LAVA ? "lava" : u.utraptype == TT_INFLOOR ? surface(u.ux,u.uy) : "trap"); nomul(0); return; } /* make sure dx and dy are [-1,0,1] */ dx = sgn(dx); dy = sgn(dy); if(!range || (!dx && !dy) || u.ustuck) return; /* paranoia */ nomul(-range); if (verbose) You("%s in the opposite direction.", range > 1 ? "hurtle" : "float"); /* if we're in the midst of shooting multiple projectiles, stop */ if (m_shot.i < m_shot.n) { /* last message before hurtling was "you shoot N arrows" */ You("stop %sing after the first %s.", m_shot.s ? "shoot" : "throw", m_shot.s ? "shot" : "toss"); m_shot.n = m_shot.i; /* make current shot be the last */ } if (In_sokoban(&u.uz)) change_luck(-1); /* Sokoban guilt */ uc.x = u.ux; uc.y = u.uy; /* this setting of cc is only correct if dx and dy are [-1,0,1] only */ cc.x = u.ux + (dx * range); cc.y = u.uy + (dy * range); (void) walk_path(&uc, &cc, hurtle_step, (genericptr_t)&range); } /* Move a monster through the air for a few squares. */ void mhurtle(mon, dx, dy, range) struct monst *mon; int dx, dy, range; { coord mc, cc; /* At the very least, debilitate the monster */ mon->movement = 0; mon->mstun = 1; /* Is the monster stuck or too heavy to push? * (very large monsters have too much inertia, even floaters and flyers) */ if (mon->data->msize >= MZ_HUGE || mon == u.ustuck || mon->mtrapped) return; /* Make sure dx and dy are [-1,0,1] */ dx = sgn(dx); dy = sgn(dy); if(!range || (!dx && !dy)) return; /* paranoia */ /* Send the monster along the path */ mc.x = mon->mx; mc.y = mon->my; cc.x = mon->mx + (dx * range); cc.y = mon->my + (dy * range); (void) walk_path(&mc, &cc, mhurtle_step, (genericptr_t)mon); return; } STATIC_OVL void check_shop_obj(obj, x, y, broken) register struct obj *obj; register xchar x, y; register boolean broken; { struct monst *shkp = shop_keeper(*u.ushops); if(!shkp) return; if(broken) { if (obj->unpaid) { (void)stolen_value(obj, u.ux, u.uy, (boolean)shkp->mpeaceful, FALSE); subfrombill(obj, shkp); } obj->no_charge = 1; return; } if (!costly_spot(x, y) || *in_rooms(x, y, SHOPBASE) != *u.ushops) { /* thrown out of a shop or into a different shop */ if (obj->unpaid) { (void)stolen_value(obj, u.ux, u.uy, (boolean)shkp->mpeaceful, FALSE); subfrombill(obj, shkp); } } else { if (costly_spot(u.ux, u.uy) && costly_spot(x, y)) { if(obj->unpaid) subfrombill(obj, shkp); else if(!(x == shkp->mx && y == shkp->my)) sellobj(obj, x, y); } } } /* * Hero tosses an object upwards with appropriate consequences. * * Returns FALSE if the object is gone. */ STATIC_OVL boolean toss_up(obj, hitsroof) struct obj *obj; boolean hitsroof; { const char *almost; /* note: obj->quan == 1 */ if (hitsroof) { if (breaktest(obj)) { pline("%s hits the %s.", Doname2(obj), ceiling(u.ux, u.uy)); breakmsg(obj, !Blind); breakobj(obj, u.ux, u.uy, TRUE, TRUE); return FALSE; } almost = ""; } else { almost = " almost"; } pline("%s%s hits the %s, then falls back on top of your %s.", Doname2(obj), almost, ceiling(u.ux,u.uy), body_part(HEAD)); /* object now hits you */ if (obj->oclass == POTION_CLASS) { potionhit(&youmonst, obj, TRUE); } else if (breaktest(obj)) { int otyp = obj->otyp, ocorpsenm = obj->corpsenm; int blindinc; /* need to check for blindness result prior to destroying obj */ blindinc = (otyp == CREAM_PIE || otyp == BLINDING_VENOM) && /* AT_WEAP is ok here even if attack type was AT_SPIT */ can_blnd(&youmonst, &youmonst, AT_WEAP, obj) ? rnd(25) : 0; breakmsg(obj, !Blind); breakobj(obj, u.ux, u.uy, TRUE, TRUE); obj = 0; /* it's now gone */ switch (otyp) { case EGG: if (touch_petrifies(&mons[ocorpsenm]) && !uarmh && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) goto petrify; case CREAM_PIE: case BLINDING_VENOM: pline("You've got it all over your %s!", body_part(FACE)); if (blindinc) { if (otyp == BLINDING_VENOM && !Blind) pline("It blinds you!"); u.ucreamed += blindinc; make_blinded(Blinded + (long)blindinc, FALSE); if (!Blind) Your(vision_clears); } break; default: break; } return FALSE; } else { /* neither potion nor other breaking object */ boolean less_damage = uarmh && is_metallic(uarmh), artimsg = FALSE; int dmg = dmgval(obj, &youmonst); if (obj->oartifact) /* need a fake die roll here; rn1(18,2) avoids 1 and 20 */ artimsg = artifact_hit((struct monst *)0, &youmonst, obj, &dmg, rn1(18,2)); if (!dmg) { /* probably wasn't a weapon; base damage on weight */ dmg = (int) obj->owt / 100; if (dmg < 1) dmg = 1; else if (dmg > 6) dmg = 6; if (youmonst.data == &mons[PM_SHADE] && objects[obj->otyp].oc_material != SILVER) dmg = 0; } if (dmg > 1 && less_damage) dmg = 1; if (dmg > 0) dmg += u.udaminc; if (dmg < 0) dmg = 0; /* beware negative rings of increase damage */ if (Half_physical_damage) dmg = (dmg + 1) / 2; if (uarmh) { if (less_damage && dmg < (Upolyd ? u.mh : u.uhp)) { if (!artimsg) pline("Fortunately, you are wearing a hard helmet."); } else if (flags.verbose && !(obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm]))) Your("%s does not protect you.", xname(uarmh)); } else if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) { if (!Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { petrify: killer_format = KILLED_BY; killer = "elementary physics"; /* "what goes up..." */ You("turn to stone."); if (obj) dropy(obj); /* bypass most of hitfloor() */ done(STONING); return obj ? TRUE : FALSE; } } hitfloor(obj); losehp(dmg, "falling object", KILLED_BY_AN); } return TRUE; } /* return true for weapon meant to be thrown; excludes ammo */ STATIC_OVL boolean throwing_weapon(obj) struct obj *obj; { return (is_missile(obj) || is_spear(obj) || /* daggers and knife (excludes scalpel) */ (is_blade(obj) && !is_sword(obj) && (objects[obj->otyp].oc_dir & PIERCE)) || /* special cases [might want to add AXE] */ obj->otyp == WAR_HAMMER || obj->otyp == AKLYS); } /* the currently thrown object is returning to you (not for boomerangs) */ STATIC_OVL void sho_obj_return_to_u(obj) struct obj *obj; { /* might already be our location (bounced off a wall) */ if (bhitpos.x != u.ux || bhitpos.y != u.uy) { int x = bhitpos.x - u.dx, y = bhitpos.y - u.dy; tmp_at(DISP_FLASH, obj_to_glyph(obj)); while(x != u.ux || y != u.uy) { tmp_at(x, y); delay_output(); x -= u.dx; y -= u.dy; } tmp_at(DISP_END, 0); } } void throwit(obj, wep_mask, twoweap) register struct obj *obj; long wep_mask; /* used to re-equip returning boomerang */ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ { register struct monst *mon; register int range, urange; boolean impaired = (Confusion || Stunned || Blind || Hallucination || Fumbling); if ((obj->cursed || obj->greased) && (u.dx || u.dy) && !rn2(7)) { boolean slipok = TRUE; if (ammo_and_launcher(obj, uwep)) pline("%s!", Tobjnam(obj, "misfire")); else { /* only slip if it's greased or meant to be thrown */ if (obj->greased || throwing_weapon(obj)) /* BUG: this message is grammatically incorrect if obj has a plural name; greased gloves or boots for instance. */ pline("%s as you throw it!", Tobjnam(obj, "slip")); else slipok = FALSE; } if (slipok) { u.dx = rn2(3)-1; u.dy = rn2(3)-1; if (!u.dx && !u.dy) u.dz = 1; impaired = TRUE; } } if ((u.dx || u.dy || (u.dz < 1)) && calc_capacity((int)obj->owt) > SLT_ENCUMBER && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax) : (u.uhp < 10 && u.uhp != u.uhpmax)) && obj->owt > (unsigned)((Upolyd ? u.mh : u.uhp) * 2) && !Is_airlevel(&u.uz)) { You("have so little stamina, %s drops from your grasp.", the(xname(obj))); exercise(A_CON, FALSE); u.dx = u.dy = 0; u.dz = 1; } thrownobj = obj; if(u.uswallow) { mon = u.ustuck; bhitpos.x = mon->mx; bhitpos.y = mon->my; } else if(u.dz) { if (u.dz < 0 && Role_if(PM_VALKYRIE) && obj->oartifact == ART_MJOLLNIR && !impaired) { pline("%s the %s and returns to your hand!", Tobjnam(obj, "hit"), ceiling(u.ux,u.uy)); obj = addinv(obj); (void) encumber_msg(); setuwep(obj); u.twoweap = twoweap; } else if (u.dz < 0 && !Is_airlevel(&u.uz) && !Underwater && !Is_waterlevel(&u.uz)) { (void) toss_up(obj, rn2(5)); } else { hitfloor(obj); } thrownobj = (struct obj*)0; return; } else if(obj->otyp == BOOMERANG && !Underwater) { if(Is_airlevel(&u.uz) || Levitation) hurtle(-u.dx, -u.dy, 1, TRUE); mon = boomhit(u.dx, u.dy); if(mon == &youmonst) { /* the thing was caught */ exercise(A_DEX, TRUE); obj = addinv(obj); (void) encumber_msg(); if (wep_mask && !(obj->owornmask & wep_mask)) { setworn(obj, wep_mask); u.twoweap = twoweap; } thrownobj = (struct obj*)0; return; } } else { urange = (int)(ACURRSTR)/2; /* balls are easy to throw or at least roll */ /* also, this insures the maximum range of a ball is greater * than 1, so the effects from throwing attached balls are * actually possible */ if (obj->otyp == HEAVY_IRON_BALL) range = urange - (int)(obj->owt/100); else range = urange - (int)(obj->owt/40); if (obj == uball) { if (u.ustuck) range = 1; else if (range >= 5) range = 5; } if (range < 1) range = 1; if (is_ammo(obj)) { if (ammo_and_launcher(obj, uwep)) range++; else if (obj->oclass != GEM_CLASS) range /= 2; } if (Is_airlevel(&u.uz) || Levitation) { /* action, reaction... */ urange -= range; if(urange < 1) urange = 1; range -= urange; if(range < 1) range = 1; } if (obj->otyp == BOULDER) range = 20; /* you must be giant */ else if (obj->oartifact == ART_MJOLLNIR) range = (range + 1) / 2; /* it's heavy */ else if (obj == uball && u.utrap && u.utraptype == TT_INFLOOR) range = 1; if (Underwater) range = 1; mon = bhit(u.dx, u.dy, range, THROWN_WEAPON, (int FDECL((*),(MONST_P,OBJ_P)))0, (int FDECL((*),(OBJ_P,OBJ_P)))0, obj); /* have to do this after bhit() so u.ux & u.uy are correct */ if(Is_airlevel(&u.uz) || Levitation) hurtle(-u.dx, -u.dy, urange, TRUE); } if (mon) { boolean obj_gone; if (mon->isshk && obj->where == OBJ_MINVENT && obj->ocarry == mon) { thrownobj = (struct obj*)0; return; /* alert shk caught it */ } (void) snuff_candle(obj); notonhead = (bhitpos.x != mon->mx || bhitpos.y != mon->my); obj_gone = thitmonst(mon, obj); /* Monster may have been tamed; this frees old mon */ mon = m_at(bhitpos.x, bhitpos.y); /* [perhaps this should be moved into thitmonst or hmon] */ if (mon && mon->isshk && (!inside_shop(u.ux, u.uy) || !index(in_rooms(mon->mx, mon->my, SHOPBASE), *u.ushops))) hot_pursuit(mon); if (obj_gone) return; } if (u.uswallow) { /* ball is not picked up by monster */ if (obj != uball) (void) mpickobj(u.ustuck,obj); } else { /* the code following might become part of dropy() */ if (obj->oartifact == ART_MJOLLNIR && Role_if(PM_VALKYRIE) && rn2(100)) { /* we must be wearing Gauntlets of Power to get here */ sho_obj_return_to_u(obj); /* display its flight */ if (!impaired && rn2(100)) { pline("%s to your hand!", Tobjnam(obj, "return")); obj = addinv(obj); (void) encumber_msg(); setuwep(obj); u.twoweap = twoweap; if(cansee(bhitpos.x, bhitpos.y)) newsym(bhitpos.x,bhitpos.y); } else { int dmg = rn2(2); if (!dmg) { pline(Blind ? "%s lands %s your %s." : "%s back to you, landing %s your %s.", Blind ? Something : Tobjnam(obj, "return"), Levitation ? "beneath" : "at", makeplural(body_part(FOOT))); } else { dmg += rnd(3); pline(Blind ? "%s your %s!" : "%s back toward you, hitting your %s!", Tobjnam(obj, Blind ? "hit" : "fly"), body_part(ARM)); (void) artifact_hit((struct monst *)0, &youmonst, obj, &dmg, 0); losehp(dmg, xname(obj), obj_is_pname(obj) ? KILLED_BY : KILLED_BY_AN); } if (ship_object(obj, u.ux, u.uy, FALSE)) { thrownobj = (struct obj*)0; return; } dropy(obj); } thrownobj = (struct obj*)0; return; } if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ) && breaktest(obj)) { tmp_at(DISP_FLASH, obj_to_glyph(obj)); tmp_at(bhitpos.x, bhitpos.y); delay_output(); tmp_at(DISP_END, 0); breakmsg(obj, cansee(bhitpos.x, bhitpos.y)); breakobj(obj, bhitpos.x, bhitpos.y, TRUE, TRUE); return; } if(flooreffects(obj,bhitpos.x,bhitpos.y,"fall")) return; obj_no_longer_held(obj); if (mon && mon->isshk && is_pick(obj)) { if (cansee(bhitpos.x, bhitpos.y)) pline("%s snatches up %s.", Monnam(mon), the(xname(obj))); if(*u.ushops) check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE); (void) mpickobj(mon, obj); /* may merge and free obj */ thrownobj = (struct obj*)0; return; } (void) snuff_candle(obj); if (!mon && ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) { thrownobj = (struct obj*)0; return; } thrownobj = (struct obj*)0; place_object(obj, bhitpos.x, bhitpos.y); if(*u.ushops && obj != uball) check_shop_obj(obj, bhitpos.x, bhitpos.y, FALSE); stackobj(obj); if (obj == uball) drop_ball(bhitpos.x, bhitpos.y); if (cansee(bhitpos.x, bhitpos.y)) newsym(bhitpos.x,bhitpos.y); if (obj_sheds_light(obj)) vision_full_recalc = 1; if (!IS_SOFT(levl[bhitpos.x][bhitpos.y].typ)) container_impact_dmg(obj); } } /* an object may hit a monster; various factors adjust the chance of hitting */ int omon_adj(mon, obj, mon_notices) struct monst *mon; struct obj *obj; boolean mon_notices; { int tmp = 0; /* size of target affects the chance of hitting */ tmp += (mon->data->msize - MZ_MEDIUM); /* -2..+5 */ /* sleeping target is more likely to be hit */ if (mon->msleeping) { tmp += 2; if (mon_notices) mon->msleeping = 0; } /* ditto for immobilized target */ if (!mon->mcanmove || !mon->data->mmove) { tmp += 4; if (mon_notices && mon->data->mmove && !rn2(10)) { mon->mcanmove = 1; mon->mfrozen = 0; } } /* some objects are more likely to hit than others */ switch (obj->otyp) { case HEAVY_IRON_BALL: if (obj != uball) tmp += 2; break; case BOULDER: tmp += 6; break; default: if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) tmp += hitval(obj, mon); break; } return tmp; } /* thrown object misses target monster */ STATIC_OVL void tmiss(obj, mon) struct obj *obj; struct monst *mon; { const char *missile = mshot_xname(obj); /* If the target can't be seen or doesn't look like a valid target, avoid "the arrow misses it," or worse, "the arrows misses the mimic." An attentive player will still notice that this is different from an arrow just landing short of any target (no message in that case), so will realize that there is a valid target here anyway. */ if (!canseemon(mon) || (mon->m_ap_type && mon->m_ap_type != M_AP_MONSTER)) pline("%s %s.", The(missile), otense(obj, "miss")); else miss(missile, mon); if (!rn2(3)) wakeup(mon); return; } #define quest_arti_hits_leader(obj,mon) \ (obj->oartifact && is_quest_artifact(obj) && (mon->data->msound == MS_LEADER)) /* * Object thrown by player arrives at monster's location. * Return 1 if obj has disappeared or otherwise been taken care of, * 0 if caller must take care of it. */ int thitmonst(mon, obj) register struct monst *mon; register struct obj *obj; { register int tmp; /* Base chance to hit */ register int disttmp; /* distance modifier */ int otyp = obj->otyp; boolean guaranteed_hit = (u.uswallow && mon == u.ustuck); /* Differences from melee weapons: * * Dex still gives a bonus, but strength does not. * Polymorphed players lacking attacks may still throw. * There's a base -1 to hit. * No bonuses for fleeing or stunned targets (they don't dodge * melee blows as readily, but dodging arrows is hard anyway). * Not affected by traps, etc. * Certain items which don't in themselves do damage ignore tmp. * Distance and monster size affect chance to hit. */ tmp = -1 + Luck + find_mac(mon) + u.uhitinc + maybe_polyd(youmonst.data->mlevel, u.ulevel); if (ACURR(A_DEX) < 4) tmp -= 3; else if (ACURR(A_DEX) < 6) tmp -= 2; else if (ACURR(A_DEX) < 8) tmp -= 1; else if (ACURR(A_DEX) >= 14) tmp += (ACURR(A_DEX) - 14); /* Modify to-hit depending on distance; but keep it sane. * Polearms get a distance penalty even when wielded; it's * hard to hit at a distance. */ disttmp = 3 - distmin(u.ux, u.uy, mon->mx, mon->my); if(disttmp < -4) disttmp = -4; tmp += disttmp; /* gloves are a hinderance to proper use of bows */ if (uarmg && uwep && objects[uwep->otyp].oc_skill == P_BOW) { switch (uarmg->otyp) { case GAUNTLETS_OF_POWER: /* metal */ tmp -= 2; break; case GAUNTLETS_OF_FUMBLING: tmp -= 3; break; case LEATHER_GLOVES: case GAUNTLETS_OF_DEXTERITY: break; default: impossible("Unknown type of gloves (%d)", uarmg->otyp); break; } } tmp += omon_adj(mon, obj, TRUE); if (is_orc(mon->data) && maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) tmp++; if (guaranteed_hit) { tmp += 1000; /* Guaranteed hit */ } if (obj->oclass == GEM_CLASS && is_unicorn(mon->data)) { if (mon->mtame) { pline("%s catches and drops %s.", Monnam(mon), the(xname(obj))); return 0; } else { pline("%s catches %s.", Monnam(mon), the(xname(obj))); return gem_accept(mon, obj); } } /* don't make game unwinnable if naive player throws artifact at leader.... */ if (quest_arti_hits_leader(obj, mon)) { /* not wakeup(), which angers non-tame monsters */ mon->msleeping = 0; mon->mstrategy &= ~STRAT_WAITMASK; if (mon->mcanmove) { pline("%s catches %s.", Monnam(mon), the(xname(obj))); if (mon->mpeaceful) { boolean next2u = monnear(mon, u.ux, u.uy); finish_quest(obj); /* acknowledge quest completion */ pline("%s %s %s back to you.", Monnam(mon), (next2u ? "hands" : "tosses"), the(xname(obj))); if (!next2u) sho_obj_return_to_u(obj); obj = addinv(obj); /* back into your inventory */ (void) encumber_msg(); } else { /* angry leader caught it and isn't returning it */ (void) mpickobj(mon, obj); } return 1; /* caller doesn't need to place it */ } return(0); } if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) { if (is_ammo(obj)) { if (!ammo_and_launcher(obj, uwep)) { tmp -= 4; } else { tmp += uwep->spe - greatest_erosion(uwep); tmp += weapon_hit_bonus(uwep); if (uwep->oartifact) tmp += spec_abon(uwep, mon); /* * Elves and Samurais are highly trained w/bows, * especially their own special types of bow. * Polymorphing won't make you a bow expert. */ if ((Race_if(PM_ELF) || Role_if(PM_SAMURAI)) && (!Upolyd || your_race(youmonst.data)) && objects[uwep->otyp].oc_skill == P_BOW) { tmp++; if (Race_if(PM_ELF) && uwep->otyp == ELVEN_BOW) tmp++; else if (Role_if(PM_SAMURAI) && uwep->otyp == YUMI) tmp++; } } } else { if (otyp == BOOMERANG) /* arbitrary */ tmp += 4; else if (throwing_weapon(obj)) /* meant to be thrown */ tmp += 2; else /* not meant to be thrown */ tmp -= 2; /* we know we're dealing with a weapon or weptool handled by WEAPON_SKILLS once ammo objects have been excluded */ tmp += weapon_hit_bonus(obj); } if (tmp >= rnd(20)) { if (hmon(mon,obj,1)) { /* mon still alive */ cutworm(mon, bhitpos.x, bhitpos.y, obj); } exercise(A_DEX, TRUE); /* projectiles other than magic stones sometimes disappear when thrown */ if (objects[otyp].oc_skill < P_NONE && objects[otyp].oc_skill > -P_BOOMERANG && !objects[otyp].oc_magic) { /* we were breaking 2/3 of everything unconditionally. * we still don't want anything to survive unconditionally, * but we need ammo to stay around longer on average. */ int broken, chance; chance = 3 + greatest_erosion(obj) - obj->spe; if (chance > 1) broken = rn2(chance); else broken = !rn2(4); if (obj->blessed && !rnl(4)) broken = 0; if (broken) { if (*u.ushops) check_shop_obj(obj, bhitpos.x,bhitpos.y, TRUE); obfree(obj, (struct obj *)0); return 1; } } passive_obj(mon, obj, (struct attack *)0); } else { tmiss(obj, mon); } } else if (otyp == HEAVY_IRON_BALL) { exercise(A_STR, TRUE); if (tmp >= rnd(20)) { int was_swallowed = guaranteed_hit; exercise(A_DEX, TRUE); if (!hmon(mon,obj,1)) { /* mon killed */ if (was_swallowed && !u.uswallow && obj == uball) return 1; /* already did placebc() */ } } else { tmiss(obj, mon); } } else if (otyp == BOULDER) { exercise(A_STR, TRUE); if (tmp >= rnd(20)) { exercise(A_DEX, TRUE); (void) hmon(mon,obj,1); } else { tmiss(obj, mon); } } else if ((otyp == EGG || otyp == CREAM_PIE || otyp == BLINDING_VENOM || otyp == ACID_VENOM) && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) { (void) hmon(mon, obj, 1); return 1; /* hmon used it up */ } else if (obj->oclass == POTION_CLASS && (guaranteed_hit || ACURR(A_DEX) > rnd(25))) { potionhit(mon, obj, TRUE); return 1; } else if (befriend_with_obj(mon->data, obj) || (mon->mtame && dogfood(mon, obj) <= ACCFOOD)) { if (tamedog(mon, obj)) return 1; /* obj is gone */ else { /* not tmiss(), which angers non-tame monsters */ miss(xname(obj), mon); mon->msleeping = 0; mon->mstrategy &= ~STRAT_WAITMASK; } } else if (guaranteed_hit) { /* this assumes that guaranteed_hit is due to swallowing */ wakeup(mon); if (obj->otyp == CORPSE && touch_petrifies(&mons[obj->corpsenm])) { if (is_animal(u.ustuck->data)) { minstapetrify(u.ustuck, TRUE); /* Don't leave a cockatrice corpse available in a statue */ if (!u.uswallow) { delobj(obj); return 1; } } } pline("%s into %s %s.", Tobjnam(obj, "vanish"), s_suffix(mon_nam(mon)), is_animal(u.ustuck->data) ? "entrails" : "currents"); } else { tmiss(obj, mon); } return 0; } STATIC_OVL int gem_accept(mon, obj) register struct monst *mon; register struct obj *obj; { char buf[BUFSZ]; boolean is_buddy = sgn(mon->data->maligntyp) == sgn(u.ualign.type); boolean is_gem = objects[obj->otyp].oc_material == GEMSTONE; int ret = 0; static NEARDATA const char nogood[] = " is not interested in your junk."; static NEARDATA const char acceptgift[] = " accepts your gift."; static NEARDATA const char maybeluck[] = " hesitatingly"; static NEARDATA const char noluck[] = " graciously"; static NEARDATA const char addluck[] = " gratefully"; Strcpy(buf,Monnam(mon)); mon->mpeaceful = 1; mon->mavenge = 0; /* object properly identified */ if(obj->dknown && objects[obj->otyp].oc_name_known) { if(is_gem) { if(is_buddy) { Strcat(buf,addluck); change_luck(5); } else { Strcat(buf,maybeluck); change_luck(rn2(7)-3); } } else { Strcat(buf,nogood); goto nopick; } /* making guesses */ } else if(obj->onamelth || objects[obj->otyp].oc_uname) { if(is_gem) { if(is_buddy) { Strcat(buf,addluck); change_luck(2); } else { Strcat(buf,maybeluck); change_luck(rn2(3)-1); } } else { Strcat(buf,nogood); goto nopick; } /* value completely unknown to @ */ } else { if(is_gem) { if(is_buddy) { Strcat(buf,addluck); change_luck(1); } else { Strcat(buf,maybeluck); change_luck(rn2(3)-1); } } else { Strcat(buf,noluck); } } Strcat(buf,acceptgift); if(*u.ushops) check_shop_obj(obj, mon->mx, mon->my, TRUE); (void) mpickobj(mon, obj); /* may merge and free obj */ ret = 1; nopick: if(!Blind) pline("%s", buf); if (!tele_restrict(mon)) (void) rloc(mon, FALSE); return(ret); } /* * Comments about the restructuring of the old breaks() routine. * * There are now three distinct phases to object breaking: * breaktest() - which makes the check/decision about whether the * object is going to break. * breakmsg() - which outputs a message about the breakage, * appropriate for that particular object. Should * only be called after a positve breaktest(). * on the object and, if it going to be called, * it must be called before calling breakobj(). * Calling breakmsg() is optional. * breakobj() - which actually does the breakage and the side-effects * of breaking that particular object. This should * only be called after a positive breaktest() on the * object. * * Each of the above routines is currently static to this source module. * There are two routines callable from outside this source module which * perform the routines above in the correct sequence. * * hero_breaks() - called when an object is to be broken as a result * of something that the hero has done. (throwing it, * kicking it, etc.) * breaks() - called when an object is to be broken for some * reason other than the hero doing something to it. */ /* * The hero causes breakage of an object (throwing, dropping it, etc.) * Return 0 if the object didn't break, 1 if the object broke. */ int hero_breaks(obj, x, y, from_invent) struct obj *obj; xchar x, y; /* object location (ox, oy may not be right) */ boolean from_invent; /* thrown or dropped by player; maybe on shop bill */ { boolean in_view = !Blind; if (!breaktest(obj)) return 0; breakmsg(obj, in_view); breakobj(obj, x, y, TRUE, from_invent); return 1; } /* * The object is going to break for a reason other than the hero doing * something to it. * Return 0 if the object doesn't break, 1 if the object broke. */ int breaks(obj, x, y) struct obj *obj; xchar x, y; /* object location (ox, oy may not be right) */ { boolean in_view = Blind ? FALSE : cansee(x, y); if (!breaktest(obj)) return 0; breakmsg(obj, in_view); breakobj(obj, x, y, FALSE, FALSE); return 1; } /* * Unconditionally break an object. Assumes all resistance checks * and break messages have been delivered prior to getting here. */ STATIC_OVL void breakobj(obj, x, y, hero_caused, from_invent) struct obj *obj; xchar x, y; /* object location (ox, oy may not be right) */ boolean hero_caused; /* is this the hero's fault? */ boolean from_invent; { switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) { case MIRROR: if (hero_caused) change_luck(-2); break; case POT_WATER: /* really, all potions */ if (obj->otyp == POT_OIL && obj->lamplit) { splatter_burning_oil(x,y); } else if (distu(x,y) <= 2) { if (!breathless(youmonst.data) || haseyes(youmonst.data)) { if (obj->otyp != POT_WATER) { if (!breathless(youmonst.data)) /* [what about "familiar odor" when known?] */ You("smell a peculiar odor..."); else { int numeyes = eyecount(youmonst.data); Your("%s water%s.", (numeyes == 1) ? body_part(EYE) : makeplural(body_part(EYE)), (numeyes == 1) ? "s" : ""); } } potionbreathe(obj); } } /* monster breathing isn't handled... [yet?] */ break; case EGG: /* breaking your own eggs is bad luck */ if (hero_caused && obj->spe && obj->corpsenm >= LOW_PM) change_luck((schar) -min(obj->quan, 5L)); break; } if (hero_caused) { if (from_invent) { if (*u.ushops) check_shop_obj(obj, x, y, TRUE); } else if (!obj->no_charge && costly_spot(x, y)) { /* it is assumed that the obj is a floor-object */ char *o_shop = in_rooms(x, y, SHOPBASE); struct monst *shkp = shop_keeper(*o_shop); if (shkp) { /* (implies *o_shop != '\0') */ static NEARDATA long lastmovetime = 0L; static NEARDATA boolean peaceful_shk = FALSE; /* We want to base shk actions on her peacefulness at start of this turn, so that "simultaneous" multiple breakage isn't drastically worse than single breakage. (ought to be done via ESHK) */ if (moves != lastmovetime) peaceful_shk = shkp->mpeaceful; if (stolen_value(obj, x, y, peaceful_shk, FALSE) > 0L && (*o_shop != u.ushops[0] || !inside_shop(u.ux, u.uy)) && moves != lastmovetime) make_angry_shk(shkp, x, y); lastmovetime = moves; } } } delobj(obj); } /* * Check to see if obj is going to break, but don't actually break it. * Return 0 if the object isn't going to break, 1 if it is. */ boolean breaktest(obj) struct obj *obj; { if (obj_resists(obj, 1, 99)) return 0; if (objects[obj->otyp].oc_material == GLASS && !obj->oartifact && obj->oclass != GEM_CLASS) return 1; switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) { #ifdef TOURIST case EXPENSIVE_CAMERA: #endif case POT_WATER: /* really, all potions */ case EGG: case CREAM_PIE: case MELON: case ACID_VENOM: case BLINDING_VENOM: return 1; default: return 0; } } STATIC_OVL void breakmsg(obj, in_view) struct obj *obj; boolean in_view; { const char *to_pieces; to_pieces = ""; switch (obj->oclass == POTION_CLASS ? POT_WATER : obj->otyp) { default: /* glass or crystal wand */ if (obj->oclass != WAND_CLASS) impossible("breaking odd object?"); case CRYSTAL_PLATE_MAIL: case LENSES: case MIRROR: case CRYSTAL_BALL: #ifdef TOURIST case EXPENSIVE_CAMERA: #endif to_pieces = " into a thousand pieces"; /*FALLTHRU*/ case POT_WATER: /* really, all potions */ if (!in_view) You_hear("%s shatter!", something); else pline("%s shatter%s%s!", Doname2(obj), (obj->quan==1) ? "s" : "", to_pieces); break; case EGG: case MELON: pline("Splat!"); break; case CREAM_PIE: if (in_view) pline("What a mess!"); break; case ACID_VENOM: case BLINDING_VENOM: pline("Splash!"); break; } } STATIC_OVL int throw_gold(obj) struct obj *obj; { int range, odx, ody; #ifndef GOLDOBJ long zorks = obj->quan; #endif register struct monst *mon; if(!u.dx && !u.dy && !u.dz) { #ifndef GOLDOBJ u.ugold += obj->quan; flags.botl = 1; dealloc_obj(obj); #endif You("cannot throw gold at yourself."); return(0); } #ifdef GOLDOBJ freeinv(obj); #endif if(u.uswallow) { pline(is_animal(u.ustuck->data) ? "%s in the %s's entrails." : "%s into %s.", #ifndef GOLDOBJ "The gold disappears", mon_nam(u.ustuck)); u.ustuck->mgold += zorks; dealloc_obj(obj); #else "The money disappears", mon_nam(u.ustuck)); add_to_minv(u.ustuck, obj); #endif return(1); } if(u.dz) { if (u.dz < 0 && !Is_airlevel(&u.uz) && !Underwater && !Is_waterlevel(&u.uz)) { pline_The("gold hits the %s, then falls back on top of your %s.", ceiling(u.ux,u.uy), body_part(HEAD)); /* some self damage? */ if(uarmh) pline("Fortunately, you are wearing a helmet!"); } bhitpos.x = u.ux; bhitpos.y = u.uy; } else { /* consistent with range for normal objects */ range = (int)((ACURRSTR)/2 - obj->owt/40); /* see if the gold has a place to move into */ odx = u.ux + u.dx; ody = u.uy + u.dy; if(!ZAP_POS(levl[odx][ody].typ) || closed_door(odx, ody)) { bhitpos.x = u.ux; bhitpos.y = u.uy; } else { mon = bhit(u.dx, u.dy, range, THROWN_WEAPON, (int FDECL((*),(MONST_P,OBJ_P)))0, (int FDECL((*),(OBJ_P,OBJ_P)))0, obj); if(mon) { if (ghitm(mon, obj)) /* was it caught? */ return 1; } else { if(ship_object(obj, bhitpos.x, bhitpos.y, FALSE)) return 1; } } } if(flooreffects(obj,bhitpos.x,bhitpos.y,"fall")) return(1); if(u.dz > 0) pline_The("gold hits the %s.", surface(bhitpos.x,bhitpos.y)); place_object(obj,bhitpos.x,bhitpos.y); if(*u.ushops) sellobj(obj, bhitpos.x, bhitpos.y); stackobj(obj); newsym(bhitpos.x,bhitpos.y); return(1); } /*dothrow.c*/ nethack-3.4.3/src/drawing.c0100644000000000000000000006276207764735041014255 0ustar rootroot/* SCCS Id: @(#)drawing.c 3.4 1999/12/02 */ /* Copyright (c) NetHack Development Team 1992. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "tcap.h" /* Relevent header information in rm.h and objclass.h. */ #ifdef C #undef C #endif #ifdef TEXTCOLOR #define C(n) n #else #define C(n) #endif #define g_FILLER(symbol) 0 uchar oc_syms[MAXOCLASSES] = DUMMY; /* the current object display symbols */ uchar showsyms[MAXPCHARS] = DUMMY; /* the current feature display symbols */ uchar monsyms[MAXMCLASSES] = DUMMY; /* the current monster display symbols */ uchar warnsyms[WARNCOUNT] = DUMMY; /* the current warning display symbols */ /* Default object class symbols. See objclass.h. */ const char def_oc_syms[MAXOCLASSES] = { /* 0*/ '\0', /* placeholder for the "random class" */ ILLOBJ_SYM, WEAPON_SYM, ARMOR_SYM, RING_SYM, /* 5*/ AMULET_SYM, TOOL_SYM, FOOD_SYM, POTION_SYM, SCROLL_SYM, /*10*/ SPBOOK_SYM, WAND_SYM, GOLD_SYM, GEM_SYM, ROCK_SYM, /*15*/ BALL_SYM, CHAIN_SYM, VENOM_SYM }; const char invisexplain[] = "remembered, unseen, creature"; /* Object descriptions. Used in do_look(). */ const char * const objexplain[] = { /* these match def_oc_syms, above */ /* 0*/ 0, "strange object", "weapon", "suit or piece of armor", "ring", /* 5*/ "amulet", "useful item (pick-axe, key, lamp...)", "piece of food", "potion", "scroll", /*10*/ "spellbook", "wand", "pile of coins", "gem or rock", "boulder or statue", /*15*/ "iron ball", "iron chain", "splash of venom" }; /* Object class names. Used in object_detect(). */ const char * const oclass_names[] = { /* 0*/ 0, "illegal objects", "weapons", "armor", "rings", /* 5*/ "amulets", "tools", "food", "potions", "scrolls", /*10*/ "spellbooks", "wands", "coins", "rocks", "large stones", /*15*/ "iron balls", "chains", "venoms" }; /* Default monster class symbols. See monsym.h. */ const char def_monsyms[MAXMCLASSES] = { '\0', /* holder */ DEF_ANT, DEF_BLOB, DEF_COCKATRICE, DEF_DOG, DEF_EYE, DEF_FELINE, DEF_GREMLIN, DEF_HUMANOID, DEF_IMP, DEF_JELLY, /* 10 */ DEF_KOBOLD, DEF_LEPRECHAUN, DEF_MIMIC, DEF_NYMPH, DEF_ORC, DEF_PIERCER, DEF_QUADRUPED, DEF_RODENT, DEF_SPIDER, DEF_TRAPPER, /* 20 */ DEF_UNICORN, DEF_VORTEX, DEF_WORM, DEF_XAN, DEF_LIGHT, DEF_ZRUTY, DEF_ANGEL, DEF_BAT, DEF_CENTAUR, DEF_DRAGON, /* 30 */ DEF_ELEMENTAL, DEF_FUNGUS, DEF_GNOME, DEF_GIANT, '\0', DEF_JABBERWOCK, DEF_KOP, DEF_LICH, DEF_MUMMY, DEF_NAGA, /* 40 */ DEF_OGRE, DEF_PUDDING, DEF_QUANTMECH, DEF_RUSTMONST, DEF_SNAKE, DEF_TROLL, DEF_UMBER, DEF_VAMPIRE, DEF_WRAITH, DEF_XORN, /* 50 */ DEF_YETI, DEF_ZOMBIE, DEF_HUMAN, DEF_GHOST, DEF_GOLEM, DEF_DEMON, DEF_EEL, DEF_LIZARD, DEF_WORM_TAIL, DEF_MIMIC_DEF, /* 60 */ }; /* The explanations below are also used when the user gives a string * for blessed genocide, so no text should wholly contain any later * text. They should also always contain obvious names (eg. cat/feline). */ const char * const monexplain[MAXMCLASSES] = { 0, "ant or other insect", "blob", "cockatrice", "dog or other canine", "eye or sphere", "cat or other feline", "gremlin", "humanoid", "imp or minor demon", "jelly", "kobold", "leprechaun", "mimic", "nymph", "orc", "piercer", "quadruped", "rodent", "arachnid or centipede", "trapper or lurker above", "unicorn or horse", "vortex", "worm", "xan or other mythical/fantastic insect", "light", "zruty", "angelic being", "bat or bird", "centaur", "dragon", "elemental", "fungus or mold", "gnome", "giant humanoid", 0, "jabberwock", "Keystone Kop", "lich", "mummy", "naga", "ogre", "pudding or ooze", "quantum mechanic", "rust monster or disenchanter", "snake", "troll", "umber hulk", "vampire", "wraith", "xorn", "apelike creature", "zombie", "human or elf", "ghost", "golem", "major demon", "sea monster", "lizard", "long worm tail", "mimic" }; const struct symdef def_warnsyms[WARNCOUNT] = { {'0', "unknown creature causing you worry", C(CLR_WHITE)}, /* white warning */ {'1', "unknown creature causing you concern", C(CLR_RED)}, /* pink warning */ {'2', "unknown creature causing you anxiety", C(CLR_RED)}, /* red warning */ {'3', "unknown creature causing you disquiet", C(CLR_RED)}, /* ruby warning */ {'4', "unknown creature causing you alarm", C(CLR_MAGENTA)}, /* purple warning */ {'5', "unknown creature causing you dread", C(CLR_BRIGHT_MAGENTA)} /* black warning */ }; /* * Default screen symbols with explanations and colors. * Note: {ibm|dec|mac}_graphics[] arrays also depend on this symbol order. */ const struct symdef defsyms[MAXPCHARS] = { /* 0*/ {' ', "dark part of a room",C(NO_COLOR)}, /* stone */ {'|', "wall", C(CLR_GRAY)}, /* vwall */ {'-', "wall", C(CLR_GRAY)}, /* hwall */ {'-', "wall", C(CLR_GRAY)}, /* tlcorn */ {'-', "wall", C(CLR_GRAY)}, /* trcorn */ {'-', "wall", C(CLR_GRAY)}, /* blcorn */ {'-', "wall", C(CLR_GRAY)}, /* brcorn */ {'-', "wall", C(CLR_GRAY)}, /* crwall */ {'-', "wall", C(CLR_GRAY)}, /* tuwall */ {'-', "wall", C(CLR_GRAY)}, /* tdwall */ /*10*/ {'|', "wall", C(CLR_GRAY)}, /* tlwall */ {'|', "wall", C(CLR_GRAY)}, /* trwall */ {'.', "doorway", C(CLR_GRAY)}, /* ndoor */ {'-', "open door", C(CLR_BROWN)}, /* vodoor */ {'|', "open door", C(CLR_BROWN)}, /* hodoor */ {'+', "closed door", C(CLR_BROWN)}, /* vcdoor */ {'+', "closed door", C(CLR_BROWN)}, /* hcdoor */ {'#', "iron bars", C(HI_METAL)}, /* bars */ {'#', "tree", C(CLR_GREEN)}, /* tree */ {'.', "floor of a room",C(CLR_GRAY)}, /* room */ /*20*/ {'#', "corridor", C(CLR_GRAY)}, /* dark corr */ {'#', "lit corridor", C(CLR_GRAY)}, /* lit corr (see mapglyph.c) */ {'<', "staircase up", C(CLR_GRAY)}, /* upstair */ {'>', "staircase down", C(CLR_GRAY)}, /* dnstair */ {'<', "ladder up", C(CLR_BROWN)}, /* upladder */ {'>', "ladder down", C(CLR_BROWN)}, /* dnladder */ {'_', "altar", C(CLR_GRAY)}, /* altar */ {'|', "grave", C(CLR_GRAY)}, /* grave */ {'\\', "opulent throne",C(HI_GOLD)}, /* throne */ #ifdef SINKS {'#', "sink", C(CLR_GRAY)}, /* sink */ #else {'#', "", C(CLR_GRAY)}, /* sink */ #endif /*30*/ {'{', "fountain", C(CLR_BLUE)}, /* fountain */ {'}', "water", C(CLR_BLUE)}, /* pool */ {'.', "ice", C(CLR_CYAN)}, /* ice */ {'}', "molten lava", C(CLR_RED)}, /* lava */ {'.', "lowered drawbridge",C(CLR_BROWN)}, /* vodbridge */ {'.', "lowered drawbridge",C(CLR_BROWN)}, /* hodbridge */ {'#', "raised drawbridge",C(CLR_BROWN)},/* vcdbridge */ {'#', "raised drawbridge",C(CLR_BROWN)},/* hcdbridge */ {' ', "air", C(CLR_CYAN)}, /* open air */ {'#', "cloud", C(CLR_GRAY)}, /* [part of] a cloud */ /*40*/ {'}', "water", C(CLR_BLUE)}, /* under water */ {'^', "arrow trap", C(HI_METAL)}, /* trap */ {'^', "dart trap", C(HI_METAL)}, /* trap */ {'^', "falling rock trap",C(CLR_GRAY)}, /* trap */ {'^', "squeaky board", C(CLR_BROWN)}, /* trap */ {'^', "bear trap", C(HI_METAL)}, /* trap */ {'^', "land mine", C(CLR_RED)}, /* trap */ {'^', "rolling boulder trap", C(CLR_GRAY)}, /* trap */ {'^', "sleeping gas trap",C(HI_ZAP)}, /* trap */ {'^', "rust trap", C(CLR_BLUE)}, /* trap */ /*50*/ {'^', "fire trap", C(CLR_ORANGE)}, /* trap */ {'^', "pit", C(CLR_BLACK)}, /* trap */ {'^', "spiked pit", C(CLR_BLACK)}, /* trap */ {'^', "hole", C(CLR_BROWN)}, /* trap */ {'^', "trap door", C(CLR_BROWN)}, /* trap */ {'^', "teleportation trap", C(CLR_MAGENTA)}, /* trap */ {'^', "level teleporter", C(CLR_MAGENTA)}, /* trap */ {'^', "magic portal", C(CLR_BRIGHT_MAGENTA)}, /* trap */ {'"', "web", C(CLR_GRAY)}, /* web */ {'^', "statue trap", C(CLR_GRAY)}, /* trap */ /*60*/ {'^', "magic trap", C(HI_ZAP)}, /* trap */ {'^', "anti-magic field", C(HI_ZAP)}, /* trap */ {'^', "polymorph trap", C(CLR_BRIGHT_GREEN)}, /* trap */ {'|', "wall", C(CLR_GRAY)}, /* vbeam */ {'-', "wall", C(CLR_GRAY)}, /* hbeam */ {'\\',"wall", C(CLR_GRAY)}, /* lslant */ {'/', "wall", C(CLR_GRAY)}, /* rslant */ {'*', "", C(CLR_WHITE)}, /* dig beam */ {'!', "", C(CLR_WHITE)}, /* camera flash beam */ {')', "", C(HI_WOOD)}, /* boomerang open left */ /*70*/ {'(', "", C(HI_WOOD)}, /* boomerang open right */ {'0', "", C(HI_ZAP)}, /* 4 magic shield symbols */ {'#', "", C(HI_ZAP)}, {'@', "", C(HI_ZAP)}, {'*', "", C(HI_ZAP)}, {'/', "", C(CLR_GREEN)}, /* swallow top left */ {'-', "", C(CLR_GREEN)}, /* swallow top center */ {'\\', "", C(CLR_GREEN)}, /* swallow top right */ {'|', "", C(CLR_GREEN)}, /* swallow middle left */ {'|', "", C(CLR_GREEN)}, /* swallow middle right */ /*80*/ {'\\', "", C(CLR_GREEN)}, /* swallow bottom left */ {'-', "", C(CLR_GREEN)}, /* swallow bottom center*/ {'/', "", C(CLR_GREEN)}, /* swallow bottom right */ {'/', "", C(CLR_ORANGE)}, /* explosion top left */ {'-', "", C(CLR_ORANGE)}, /* explosion top center */ {'\\', "", C(CLR_ORANGE)}, /* explosion top right */ {'|', "", C(CLR_ORANGE)}, /* explosion middle left */ {' ', "", C(CLR_ORANGE)}, /* explosion middle center*/ {'|', "", C(CLR_ORANGE)}, /* explosion middle right */ {'\\', "", C(CLR_ORANGE)}, /* explosion bottom left */ /*90*/ {'-', "", C(CLR_ORANGE)}, /* explosion bottom center*/ {'/', "", C(CLR_ORANGE)}, /* explosion bottom right */ /* * Note: Additions to this array should be reflected in the * {ibm,dec,mac}_graphics[] arrays below. */ }; #undef C #ifdef ASCIIGRAPH #ifdef PC9800 void NDECL((*ibmgraphics_mode_callback)) = 0; /* set in tty_start_screen() */ #endif /* PC9800 */ static uchar ibm_graphics[MAXPCHARS] = { /* 0*/ g_FILLER(S_stone), 0xb3, /* S_vwall: meta-3, vertical rule */ 0xc4, /* S_hwall: meta-D, horizontal rule */ 0xda, /* S_tlcorn: meta-Z, top left corner */ 0xbf, /* S_trcorn: meta-?, top right corner */ 0xc0, /* S_blcorn: meta-@, bottom left */ 0xd9, /* S_brcorn: meta-Y, bottom right */ 0xc5, /* S_crwall: meta-E, cross */ 0xc1, /* S_tuwall: meta-A, T up */ 0xc2, /* S_tdwall: meta-B, T down */ /*10*/ 0xb4, /* S_tlwall: meta-4, T left */ 0xc3, /* S_trwall: meta-C, T right */ 0xfa, /* S_ndoor: meta-z, centered dot */ 0xfe, /* S_vodoor: meta-~, small centered square */ 0xfe, /* S_hodoor: meta-~, small centered square */ g_FILLER(S_vcdoor), g_FILLER(S_hcdoor), 240, /* S_bars: equivalence symbol */ 241, /* S_tree: plus or minus symbol */ 0xfa, /* S_room: meta-z, centered dot */ /*20*/ 0xb0, /* S_corr: meta-0, light shading */ 0xb1, /* S_litcorr: meta-1, medium shading */ g_FILLER(S_upstair), g_FILLER(S_dnstair), g_FILLER(S_upladder), g_FILLER(S_dnladder), g_FILLER(S_altar), g_FILLER(S_grave), g_FILLER(S_throne), g_FILLER(S_sink), /*30*/ 0xf4, /* S_fountain: meta-t, integral top half */ 0xf7, /* S_pool: meta-w, approx. equals */ 0xfa, /* S_ice: meta-z, centered dot */ 0xf7, /* S_lava: meta-w, approx. equals */ 0xfa, /* S_vodbridge: meta-z, centered dot */ 0xfa, /* S_hodbridge: meta-z, centered dot */ g_FILLER(S_vcdbridge), g_FILLER(S_hcdbridge), g_FILLER(S_air), g_FILLER(S_cloud), /*40*/ 0xf7, /* S_water: meta-w, approx. equals */ g_FILLER(S_arrow_trap), g_FILLER(S_dart_trap), g_FILLER(S_falling_rock_trap), g_FILLER(S_squeaky_board), g_FILLER(S_bear_trap), g_FILLER(S_land_mine), g_FILLER(S_rolling_boulder_trap), g_FILLER(S_sleeping_gas_trap), g_FILLER(S_rust_trap), /*50*/ g_FILLER(S_fire_trap), g_FILLER(S_pit), g_FILLER(S_spiked_pit), g_FILLER(S_hole), g_FILLER(S_trap_door), g_FILLER(S_teleportation_trap), g_FILLER(S_level_teleporter), g_FILLER(S_magic_portal), g_FILLER(S_web), g_FILLER(S_statue_trap), /*60*/ g_FILLER(S_magic_trap), g_FILLER(S_anti_magic_trap), g_FILLER(S_polymorph_trap), 0xb3, /* S_vbeam: meta-3, vertical rule */ 0xc4, /* S_hbeam: meta-D, horizontal rule */ g_FILLER(S_lslant), g_FILLER(S_rslant), g_FILLER(S_digbeam), g_FILLER(S_flashbeam), g_FILLER(S_boomleft), /*70*/ g_FILLER(S_boomright), g_FILLER(S_ss1), g_FILLER(S_ss2), g_FILLER(S_ss3), g_FILLER(S_ss4), g_FILLER(S_sw_tl), g_FILLER(S_sw_tc), g_FILLER(S_sw_tr), 0xb3, /* S_sw_ml: meta-3, vertical rule */ 0xb3, /* S_sw_mr: meta-3, vertical rule */ /*80*/ g_FILLER(S_sw_bl), g_FILLER(S_sw_bc), g_FILLER(S_sw_br), g_FILLER(S_explode1), g_FILLER(S_explode2), g_FILLER(S_explode3), 0xb3, /* S_explode4: meta-3, vertical rule */ g_FILLER(S_explode5), 0xb3, /* S_explode6: meta-3, vertical rule */ g_FILLER(S_explode7), /*90*/ g_FILLER(S_explode8), g_FILLER(S_explode9) }; #endif /* ASCIIGRAPH */ #ifdef TERMLIB void NDECL((*decgraphics_mode_callback)) = 0; /* set in tty_start_screen() */ static uchar dec_graphics[MAXPCHARS] = { /* 0*/ g_FILLER(S_stone), 0xf8, /* S_vwall: meta-x, vertical rule */ 0xf1, /* S_hwall: meta-q, horizontal rule */ 0xec, /* S_tlcorn: meta-l, top left corner */ 0xeb, /* S_trcorn: meta-k, top right corner */ 0xed, /* S_blcorn: meta-m, bottom left */ 0xea, /* S_brcorn: meta-j, bottom right */ 0xee, /* S_crwall: meta-n, cross */ 0xf6, /* S_tuwall: meta-v, T up */ 0xf7, /* S_tdwall: meta-w, T down */ /*10*/ 0xf5, /* S_tlwall: meta-u, T left */ 0xf4, /* S_trwall: meta-t, T right */ 0xfe, /* S_ndoor: meta-~, centered dot */ 0xe1, /* S_vodoor: meta-a, solid block */ 0xe1, /* S_hodoor: meta-a, solid block */ g_FILLER(S_vcdoor), g_FILLER(S_hcdoor), 0xfb, /* S_bars: meta-{, small pi */ 0xe7, /* S_tree: meta-g, plus-or-minus */ 0xfe, /* S_room: meta-~, centered dot */ /*20*/ g_FILLER(S_corr), g_FILLER(S_litcorr), g_FILLER(S_upstair), g_FILLER(S_dnstair), 0xf9, /* S_upladder: meta-y, greater-than-or-equals */ 0xfa, /* S_dnladder: meta-z, less-than-or-equals */ g_FILLER(S_altar), /* 0xc3, \E)3: meta-C, dagger */ g_FILLER(S_grave), g_FILLER(S_throne), g_FILLER(S_sink), /*30*/ g_FILLER(S_fountain), /* 0xdb, \E)3: meta-[, integral top half */ 0xe0, /* S_pool: meta-\, diamond */ 0xfe, /* S_ice: meta-~, centered dot */ 0xe0, /* S_lava: meta-\, diamond */ 0xfe, /* S_vodbridge: meta-~, centered dot */ 0xfe, /* S_hodbridge: meta-~, centered dot */ g_FILLER(S_vcdbridge), g_FILLER(S_hcdbridge), g_FILLER(S_air), g_FILLER(S_cloud), /*40*/ 0xe0, /* S_water: meta-\, diamond */ g_FILLER(S_arrow_trap), g_FILLER(S_dart_trap), g_FILLER(S_falling_rock_trap), g_FILLER(S_squeaky_board), g_FILLER(S_bear_trap), g_FILLER(S_land_mine), g_FILLER(S_rolling_boulder_trap), g_FILLER(S_sleeping_gas_trap), g_FILLER(S_rust_trap), /*50*/ g_FILLER(S_fire_trap), g_FILLER(S_pit), g_FILLER(S_spiked_pit), g_FILLER(S_hole), g_FILLER(S_trap_door), g_FILLER(S_teleportation_trap), g_FILLER(S_level_teleporter), g_FILLER(S_magic_portal), g_FILLER(S_web), /* 0xbd, \E)3: meta-=, int'l currency */ g_FILLER(S_statue_trap), /*60*/ g_FILLER(S_magic_trap), g_FILLER(S_anti_magic_trap), g_FILLER(S_polymorph_trap), 0xf8, /* S_vbeam: meta-x, vertical rule */ 0xf1, /* S_hbeam: meta-q, horizontal rule */ g_FILLER(S_lslant), g_FILLER(S_rslant), g_FILLER(S_digbeam), g_FILLER(S_flashbeam), g_FILLER(S_boomleft), /*70*/ g_FILLER(S_boomright), g_FILLER(S_ss1), g_FILLER(S_ss2), g_FILLER(S_ss3), g_FILLER(S_ss4), g_FILLER(S_sw_tl), 0xef, /* S_sw_tc: meta-o, high horizontal line */ g_FILLER(S_sw_tr), 0xf8, /* S_sw_ml: meta-x, vertical rule */ 0xf8, /* S_sw_mr: meta-x, vertical rule */ /*80*/ g_FILLER(S_sw_bl), 0xf3, /* S_sw_bc: meta-s, low horizontal line */ g_FILLER(S_sw_br), g_FILLER(S_explode1), 0xef, /* S_explode2: meta-o, high horizontal line */ g_FILLER(S_explode3), 0xf8, /* S_explode4: meta-x, vertical rule */ g_FILLER(S_explode5), 0xf8, /* S_explode6: meta-x, vertical rule */ g_FILLER(S_explode7), /*90*/ 0xf3, /* S_explode8: meta-s, low horizontal line */ g_FILLER(S_explode9) }; #endif /* TERMLIB */ #ifdef MAC_GRAPHICS_ENV static uchar mac_graphics[MAXPCHARS] = { /* 0*/ g_FILLER(S_stone), 0xba, /* S_vwall */ 0xcd, /* S_hwall */ 0xc9, /* S_tlcorn */ 0xbb, /* S_trcorn */ 0xc8, /* S_blcorn */ 0xbc, /* S_brcorn */ 0xce, /* S_crwall */ 0xca, /* S_tuwall */ 0xcb, /* S_tdwall */ /*10*/ 0xb9, /* S_tlwall */ 0xcc, /* S_trwall */ 0xb0, /* S_ndoor */ 0xee, /* S_vodoor */ 0xee, /* S_hodoor */ 0xef, /* S_vcdoor */ 0xef, /* S_hcdoor */ 0xf0, /* S_bars: equivalency symbol */ 0xf1, /* S_tree: plus-or-minus */ g_FILLER(S_Room), /*20*/ 0xB0, /* S_corr */ g_FILLER(S_litcorr), g_FILLER(S_upstair), g_FILLER(S_dnstair), g_FILLER(S_upladder), g_FILLER(S_dnladder), g_FILLER(S_altar), 0xef, /* S_grave: same as open door */ g_FILLER(S_throne), g_FILLER(S_sink), /*30*/ g_FILLER(S_fountain), 0xe0, /* S_pool */ g_FILLER(S_ice), g_FILLER(S_lava), g_FILLER(S_vodbridge), g_FILLER(S_hodbridge), g_FILLER(S_vcdbridge), g_FILLER(S_hcdbridge), g_FILLER(S_air), g_FILLER(S_cloud), /*40*/ g_FILLER(S_water), g_FILLER(S_arrow_trap), g_FILLER(S_dart_trap), g_FILLER(S_falling_rock_trap), g_FILLER(S_squeaky_board), g_FILLER(S_bear_trap), g_FILLER(S_land_mine), g_FILLER(S_rolling_boulder_trap), g_FILLER(S_sleeping_gas_trap), g_FILLER(S_rust_trap), /*50*/ g_FILLER(S_fire_trap), g_FILLER(S_pit), g_FILLER(S_spiked_pit), g_FILLER(S_hole), g_FILLER(S_trap_door), g_FILLER(S_teleportation_trap), g_FILLER(S_level_teleporter), g_FILLER(S_magic_portal), g_FILLER(S_web), g_FILLER(S_statue_trap), /*60*/ g_FILLER(S_magic_trap), g_FILLER(S_anti_magic_trap), g_FILLER(S_polymorph_trap), g_FILLER(S_vbeam), g_FILLER(S_hbeam), g_FILLER(S_lslant), g_FILLER(S_rslant), g_FILLER(S_digbeam), g_FILLER(S_flashbeam), g_FILLER(S_boomleft), /*70*/ g_FILLER(S_boomright), g_FILLER(S_ss1), g_FILLER(S_ss2), g_FILLER(S_ss3), g_FILLER(S_ss4), g_FILLER(S_sw_tl), g_FILLER(S_sw_tc), g_FILLER(S_sw_tr), g_FILLER(S_sw_ml), g_FILLER(S_sw_mr), /*80*/ g_FILLER(S_sw_bl), g_FILLER(S_sw_bc), g_FILLER(S_sw_br), g_FILLER(S_explode1), g_FILLER(S_explode2), g_FILLER(S_explode3), g_FILLER(S_explode4), g_FILLER(S_explode5), g_FILLER(S_explode6), g_FILLER(S_explode7), /*90*/ g_FILLER(S_explode8), g_FILLER(S_explode9) }; #endif /* MAC_GRAPHICS_ENV */ #ifdef PC9800 void NDECL((*ascgraphics_mode_callback)) = 0; /* set in tty_start_screen() */ #endif /* * Convert the given character to an object class. If the character is not * recognized, then MAXOCLASSES is returned. Used in detect.c invent.c, * options.c, pickup.c, sp_lev.c, and lev_main.c. */ int def_char_to_objclass(ch) char ch; { int i; for (i = 1; i < MAXOCLASSES; i++) if (ch == def_oc_syms[i]) break; return i; } /* * Convert a character into a monster class. This returns the _first_ * match made. If there are are no matches, return MAXMCLASSES. */ int def_char_to_monclass(ch) char ch; { int i; for (i = 1; i < MAXMCLASSES; i++) if (def_monsyms[i] == ch) break; return i; } void assign_graphics(graph_chars, glth, maxlen, offset) register uchar *graph_chars; int glth, maxlen, offset; { register int i; for (i = 0; i < maxlen; i++) showsyms[i+offset] = (((i < glth) && graph_chars[i]) ? graph_chars[i] : defsyms[i+offset].sym); } void switch_graphics(gr_set_flag) int gr_set_flag; { switch (gr_set_flag) { default: case ASCII_GRAPHICS: assign_graphics((uchar *)0, 0, MAXPCHARS, 0); #ifdef PC9800 if (ascgraphics_mode_callback) (*ascgraphics_mode_callback)(); #endif break; #ifdef ASCIIGRAPH case IBM_GRAPHICS: /* * Use the nice IBM Extended ASCII line-drawing characters (codepage 437). * * OS/2 defaults to a multilingual character set (codepage 850, corresponding * to the ISO 8859 character set. We should probably do a VioSetCp() call to * set the codepage to 437. */ iflags.IBMgraphics = TRUE; iflags.DECgraphics = FALSE; assign_graphics(ibm_graphics, SIZE(ibm_graphics), MAXPCHARS, 0); #ifdef PC9800 if (ibmgraphics_mode_callback) (*ibmgraphics_mode_callback)(); #endif break; #endif /* ASCIIGRAPH */ #ifdef TERMLIB case DEC_GRAPHICS: /* * Use the VT100 line drawing character set. */ iflags.DECgraphics = TRUE; iflags.IBMgraphics = FALSE; assign_graphics(dec_graphics, SIZE(dec_graphics), MAXPCHARS, 0); if (decgraphics_mode_callback) (*decgraphics_mode_callback)(); break; #endif /* TERMLIB */ #ifdef MAC_GRAPHICS_ENV case MAC_GRAPHICS: assign_graphics(mac_graphics, SIZE(mac_graphics), MAXPCHARS, 0); break; #endif } return; } #ifdef REINCARNATION /* * saved display symbols for objects & features. */ static uchar save_oc_syms[MAXOCLASSES] = DUMMY; static uchar save_showsyms[MAXPCHARS] = DUMMY; static uchar save_monsyms[MAXPCHARS] = DUMMY; static const uchar r_oc_syms[MAXOCLASSES] = { /* 0*/ '\0', ILLOBJ_SYM, WEAPON_SYM, ']', /* armor */ RING_SYM, /* 5*/ ',', /* amulet */ TOOL_SYM, ':', /* food */ POTION_SYM, SCROLL_SYM, /*10*/ SPBOOK_SYM, WAND_SYM, GEM_SYM, /* gold -- yes it's the same as gems */ GEM_SYM, ROCK_SYM, /*15*/ BALL_SYM, CHAIN_SYM, VENOM_SYM }; # ifdef ASCIIGRAPH /* Rogue level graphics. Under IBM graphics mode, use the symbols that were * used for Rogue on the IBM PC. Unfortunately, this can't be completely * done because some of these are control characters--armor and rings under * DOS, and a whole bunch of them under Linux. Use the TTY Rogue characters * for those cases. */ static const uchar IBM_r_oc_syms[MAXOCLASSES] = { /* a la EPYX Rogue */ /* 0*/ '\0', ILLOBJ_SYM, # if defined(MSDOS) || defined(OS2) || ( defined(WIN32) && !defined(MSWIN_GRAPHICS) ) 0x18, /* weapon: up arrow */ /* 0x0a, */ ARMOR_SYM, /* armor: Vert rect with o */ /* 0x09, */ RING_SYM, /* ring: circle with arrow */ /* 5*/ 0x0c, /* amulet: "female" symbol */ TOOL_SYM, 0x05, /* food: club (as in cards) */ 0xad, /* potion: upside down '!' */ 0x0e, /* scroll: musical note */ /*10*/ SPBOOK_SYM, 0xe7, /* wand: greek tau */ 0x0f, /* gold: yes it's the same as gems */ 0x0f, /* gems: fancy '*' */ # else ')', /* weapon */ ARMOR_SYM, /* armor */ RING_SYM, /* ring */ /* 5*/ ',', /* amulet */ TOOL_SYM, ':', /* food */ 0xad, /* potion: upside down '!' */ SCROLL_SYM, /* scroll */ /*10*/ SPBOOK_SYM, 0xe7, /* wand: greek tau */ GEM_SYM, /* gold: yes it's the same as gems */ GEM_SYM, /* gems */ # endif ROCK_SYM, /*15*/ BALL_SYM, CHAIN_SYM, VENOM_SYM }; # endif /* ASCIIGRAPH */ void assign_rogue_graphics(is_rlevel) boolean is_rlevel; { /* Adjust graphics display characters on Rogue levels */ if (is_rlevel) { register int i; (void) memcpy((genericptr_t)save_showsyms, (genericptr_t)showsyms, sizeof showsyms); (void) memcpy((genericptr_t)save_oc_syms, (genericptr_t)oc_syms, sizeof oc_syms); (void) memcpy((genericptr_t)save_monsyms, (genericptr_t)monsyms, sizeof monsyms); /* Use a loop: char != uchar on some machines. */ for (i = 0; i < MAXMCLASSES; i++) monsyms[i] = def_monsyms[i]; # if defined(ASCIIGRAPH) && !defined(MSWIN_GRAPHICS) if (iflags.IBMgraphics # if defined(USE_TILES) && defined(MSDOS) && !iflags.grmode # endif ) monsyms[S_HUMAN] = 0x01; /* smiley face */ # endif for (i = 0; i < MAXPCHARS; i++) showsyms[i] = defsyms[i].sym; /* * Some day if these rogue showsyms get much more extensive than this, * we may want to create r_showsyms, and IBM_r_showsyms arrays to hold * all of this info and to simply initialize it via a for() loop like r_oc_syms. */ # ifdef ASCIIGRAPH if (!iflags.IBMgraphics # if defined(USE_TILES) && defined(MSDOS) || iflags.grmode # endif ) { # endif showsyms[S_vodoor] = showsyms[S_hodoor] = showsyms[S_ndoor] = '+'; showsyms[S_upstair] = showsyms[S_dnstair] = '%'; # ifdef ASCIIGRAPH } else { /* a la EPYX Rogue */ showsyms[S_vwall] = 0xba; /* all walls now use */ showsyms[S_hwall] = 0xcd; /* double line graphics */ showsyms[S_tlcorn] = 0xc9; showsyms[S_trcorn] = 0xbb; showsyms[S_blcorn] = 0xc8; showsyms[S_brcorn] = 0xbc; showsyms[S_crwall] = 0xce; showsyms[S_tuwall] = 0xca; showsyms[S_tdwall] = 0xcb; showsyms[S_tlwall] = 0xb9; showsyms[S_trwall] = 0xcc; showsyms[S_ndoor] = 0xce; showsyms[S_vodoor] = 0xce; showsyms[S_hodoor] = 0xce; showsyms[S_room] = 0xfa; /* centered dot */ showsyms[S_corr] = 0xb1; showsyms[S_litcorr] = 0xb2; showsyms[S_upstair] = 0xf0; /* Greek Xi */ showsyms[S_dnstair] = 0xf0; #ifndef MSWIN_GRAPHICS showsyms[S_arrow_trap] = 0x04; /* diamond (cards) */ showsyms[S_dart_trap] = 0x04; showsyms[S_falling_rock_trap] = 0x04; showsyms[S_squeaky_board] = 0x04; showsyms[S_bear_trap] = 0x04; showsyms[S_land_mine] = 0x04; showsyms[S_rolling_boulder_trap] = 0x04; showsyms[S_sleeping_gas_trap] = 0x04; showsyms[S_rust_trap] = 0x04; showsyms[S_fire_trap] = 0x04; showsyms[S_pit] = 0x04; showsyms[S_spiked_pit] = 0x04; showsyms[S_hole] = 0x04; showsyms[S_trap_door] = 0x04; showsyms[S_teleportation_trap] = 0x04; showsyms[S_level_teleporter] = 0x04; showsyms[S_magic_portal] = 0x04; showsyms[S_web] = 0x04; showsyms[S_statue_trap] = 0x04; showsyms[S_magic_trap] = 0x04; showsyms[S_anti_magic_trap] = 0x04; showsyms[S_polymorph_trap] = 0x04; #endif } #endif /* ASCIIGRAPH */ for (i = 0; i < MAXOCLASSES; i++) { #ifdef ASCIIGRAPH if (iflags.IBMgraphics # if defined(USE_TILES) && defined(MSDOS) && !iflags.grmode # endif ) oc_syms[i] = IBM_r_oc_syms[i]; else #endif /* ASCIIGRAPH */ oc_syms[i] = r_oc_syms[i]; } #if defined(MSDOS) && defined(USE_TILES) if (iflags.grmode) tileview(FALSE); #endif } else { (void) memcpy((genericptr_t)showsyms, (genericptr_t)save_showsyms, sizeof showsyms); (void) memcpy((genericptr_t)oc_syms, (genericptr_t)save_oc_syms, sizeof oc_syms); (void) memcpy((genericptr_t)monsyms, (genericptr_t)save_monsyms, sizeof monsyms); #if defined(MSDOS) && defined(USE_TILES) if (iflags.grmode) tileview(TRUE); #endif } } #endif /* REINCARNATION */ /*drawing.c*/ nethack-3.4.3/src/dungeon.c0100644000000000000000000013467507764735041014264 0ustar rootroot/* SCCS Id: @(#)dungeon.c 3.4 1999/10/30 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dgn_file.h" #include "dlb.h" #ifdef OVL1 #define DUNGEON_FILE "dungeon" #define X_START "x-strt" #define X_LOCATE "x-loca" #define X_GOAL "x-goal" struct proto_dungeon { struct tmpdungeon tmpdungeon[MAXDUNGEON]; struct tmplevel tmplevel[LEV_LIMIT]; s_level *final_lev[LEV_LIMIT]; /* corresponding level pointers */ struct tmpbranch tmpbranch[BRANCH_LIMIT]; int start; /* starting index of current dungeon sp levels */ int n_levs; /* number of tmplevel entries */ int n_brs; /* number of tmpbranch entries */ }; int n_dgns; /* number of dungeons (used here, */ /* and mklev.c) */ static branch *branches = (branch *) 0; /* dungeon branch list */ struct lchoice { int idx; schar lev[MAXLINFO]; schar playerlev[MAXLINFO]; xchar dgn[MAXLINFO]; char menuletter; }; static void FDECL(Fread, (genericptr_t, int, int, dlb *)); STATIC_DCL xchar FDECL(dname_to_dnum, (const char *)); STATIC_DCL int FDECL(find_branch, (const char *, struct proto_dungeon *)); STATIC_DCL xchar FDECL(parent_dnum, (const char *, struct proto_dungeon *)); STATIC_DCL int FDECL(level_range, (XCHAR_P,int,int,int,struct proto_dungeon *,int *)); STATIC_DCL xchar FDECL(parent_dlevel, (const char *, struct proto_dungeon *)); STATIC_DCL int FDECL(correct_branch_type, (struct tmpbranch *)); STATIC_DCL branch *FDECL(add_branch, (int, int, struct proto_dungeon *)); STATIC_DCL void FDECL(add_level, (s_level *)); STATIC_DCL void FDECL(init_level, (int,int,struct proto_dungeon *)); STATIC_DCL int FDECL(possible_places, (int, boolean *, struct proto_dungeon *)); STATIC_DCL xchar FDECL(pick_level, (boolean *, int)); STATIC_DCL boolean FDECL(place_level, (int, struct proto_dungeon *)); #ifdef WIZARD STATIC_DCL const char *FDECL(br_string, (int)); STATIC_DCL void FDECL(print_branch, (winid, int, int, int, BOOLEAN_P, struct lchoice *)); #endif #ifdef DEBUG #define DD dungeons[i] STATIC_DCL void NDECL(dumpit); STATIC_OVL void dumpit() { int i; s_level *x; branch *br; for(i = 0; i < n_dgns; i++) { fprintf(stderr, "\n#%d \"%s\" (%s):\n", i, DD.dname, DD.proto); fprintf(stderr, " num_dunlevs %d, dunlev_ureached %d\n", DD.num_dunlevs, DD.dunlev_ureached); fprintf(stderr, " depth_start %d, ledger_start %d\n", DD.depth_start, DD.ledger_start); fprintf(stderr, " flags:%s%s%s\n", DD.flags.rogue_like ? " rogue_like" : "", DD.flags.maze_like ? " maze_like" : "", DD.flags.hellish ? " hellish" : ""); getchar(); } fprintf(stderr,"\nSpecial levels:\n"); for(x = sp_levchn; x; x = x->next) { fprintf(stderr, "%s (%d): ", x->proto, x->rndlevs); fprintf(stderr, "on %d, %d; ", x->dlevel.dnum, x->dlevel.dlevel); fprintf(stderr, "flags:%s%s%s%s\n", x->flags.rogue_like ? " rogue_like" : "", x->flags.maze_like ? " maze_like" : "", x->flags.hellish ? " hellish" : "", x->flags.town ? " town" : ""); getchar(); } fprintf(stderr,"\nBranches:\n"); for (br = branches; br; br = br->next) { fprintf(stderr, "%d: %s, end1 %d %d, end2 %d %d, %s\n", br->id, br->type == BR_STAIR ? "stair" : br->type == BR_NO_END1 ? "no end1" : br->type == BR_NO_END2 ? "no end2" : br->type == BR_PORTAL ? "portal" : "unknown", br->end1.dnum, br->end1.dlevel, br->end2.dnum, br->end2.dlevel, br->end1_up ? "end1 up" : "end1 down"); } getchar(); fprintf(stderr,"\nDone\n"); getchar(); } #endif /* Save the dungeon structures. */ void save_dungeon(fd, perform_write, free_data) int fd; boolean perform_write, free_data; { branch *curr, *next; int count; if (perform_write) { bwrite(fd, (genericptr_t) &n_dgns, sizeof n_dgns); bwrite(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns); bwrite(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology); bwrite(fd, (genericptr_t) tune, sizeof tune); for (count = 0, curr = branches; curr; curr = curr->next) count++; bwrite(fd, (genericptr_t) &count, sizeof(count)); for (curr = branches; curr; curr = curr->next) bwrite(fd, (genericptr_t) curr, sizeof (branch)); count = maxledgerno(); bwrite(fd, (genericptr_t) &count, sizeof count); bwrite(fd, (genericptr_t) level_info, (unsigned)count * sizeof (struct linfo)); bwrite(fd, (genericptr_t) &inv_pos, sizeof inv_pos); } if (free_data) { for (curr = branches; curr; curr = next) { next = curr->next; free((genericptr_t) curr); } branches = 0; } } /* Restore the dungeon structures. */ void restore_dungeon(fd) int fd; { branch *curr, *last; int count, i; mread(fd, (genericptr_t) &n_dgns, sizeof(n_dgns)); mread(fd, (genericptr_t) dungeons, sizeof(dungeon) * (unsigned)n_dgns); mread(fd, (genericptr_t) &dungeon_topology, sizeof dungeon_topology); mread(fd, (genericptr_t) tune, sizeof tune); last = branches = (branch *) 0; mread(fd, (genericptr_t) &count, sizeof(count)); for (i = 0; i < count; i++) { curr = (branch *) alloc(sizeof(branch)); mread(fd, (genericptr_t) curr, sizeof(branch)); curr->next = (branch *) 0; if (last) last->next = curr; else branches = curr; last = curr; } mread(fd, (genericptr_t) &count, sizeof(count)); if (count >= MAXLINFO) panic("level information count larger (%d) than allocated size", count); mread(fd, (genericptr_t) level_info, (unsigned)count*sizeof(struct linfo)); mread(fd, (genericptr_t) &inv_pos, sizeof inv_pos); } static void Fread(ptr, size, nitems, stream) genericptr_t ptr; int size, nitems; dlb *stream; { int cnt; if((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) { panic( "Premature EOF on dungeon description file!\r\nExpected %d bytes - got %d.", (size * nitems), (size * cnt)); terminate(EXIT_FAILURE); } } STATIC_OVL xchar dname_to_dnum(s) const char *s; { xchar i; for (i = 0; i < n_dgns; i++) if (!strcmp(dungeons[i].dname, s)) return i; panic("Couldn't resolve dungeon number for name \"%s\".", s); /*NOT REACHED*/ return (xchar)0; } s_level * find_level(s) const char *s; { s_level *curr; for(curr = sp_levchn; curr; curr = curr->next) if (!strcmpi(s, curr->proto)) break; return curr; } /* Find the branch that links the named dungeon. */ STATIC_OVL int find_branch(s, pd) const char *s; /* dungeon name */ struct proto_dungeon *pd; { int i; if (pd) { for (i = 0; i < pd->n_brs; i++) if (!strcmp(pd->tmpbranch[i].name, s)) break; if (i == pd->n_brs) panic("find_branch: can't find %s", s); } else { /* support for level tport by name */ branch *br; const char *dnam; for (br = branches; br; br = br->next) { dnam = dungeons[br->end2.dnum].dname; if (!strcmpi(dnam, s) || (!strncmpi(dnam, "The ", 4) && !strcmpi(dnam + 4, s))) break; } i = br ? ((ledger_no(&br->end1) << 8) | ledger_no(&br->end2)) : -1; } return i; } /* * Find the "parent" by searching the prototype branch list for the branch * listing, then figuring out to which dungeon it belongs. */ STATIC_OVL xchar parent_dnum(s, pd) const char *s; /* dungeon name */ struct proto_dungeon *pd; { int i; xchar pdnum; i = find_branch(s, pd); /* * Got branch, now find parent dungeon. Stop if we have reached * "this" dungeon (if we haven't found it by now it is an error). */ for (pdnum = 0; strcmp(pd->tmpdungeon[pdnum].name, s); pdnum++) if ((i -= pd->tmpdungeon[pdnum].branches) < 0) return(pdnum); panic("parent_dnum: couldn't resolve branch."); /*NOT REACHED*/ return (xchar)0; } /* * Return a starting point and number of successive positions a level * or dungeon entrance can occupy. * * Note: This follows the acouple (instead of the rcouple) rules for a * negative random component (rand < 0). These rules are found * in dgn_comp.y. The acouple [absolute couple] section says that * a negative random component means from the (adjusted) base to the * end of the dungeon. */ STATIC_OVL int level_range(dgn, base, rand, chain, pd, adjusted_base) xchar dgn; int base, rand, chain; struct proto_dungeon *pd; int *adjusted_base; { int lmax = dungeons[dgn].num_dunlevs; if (chain >= 0) { /* relative to a special level */ s_level *levtmp = pd->final_lev[chain]; if (!levtmp) panic("level_range: empty chain level!"); base += levtmp->dlevel.dlevel; } else { /* absolute in the dungeon */ /* from end of dungeon */ if (base < 0) base = (lmax + base + 1); } if (base < 1 || base > lmax) panic("level_range: base value out of range"); *adjusted_base = base; if (rand == -1) { /* from base to end of dungeon */ return (lmax - base + 1); } else if (rand) { /* make sure we don't run off the end of the dungeon */ return (((base + rand - 1) > lmax) ? lmax-base+1 : rand); } /* else only one choice */ return 1; } STATIC_OVL xchar parent_dlevel(s, pd) const char *s; struct proto_dungeon *pd; { int i, j, num, base, dnum = parent_dnum(s, pd); branch *curr; i = find_branch(s, pd); num = level_range(dnum, pd->tmpbranch[i].lev.base, pd->tmpbranch[i].lev.rand, pd->tmpbranch[i].chain, pd, &base); /* KMH -- Try our best to find a level without an existing branch */ i = j = rn2(num); do { if (++i >= num) i = 0; for (curr = branches; curr; curr = curr->next) if ((curr->end1.dnum == dnum && curr->end1.dlevel == base+i) || (curr->end2.dnum == dnum && curr->end2.dlevel == base+i)) break; } while (curr && i != j); return (base + i); } /* Convert from the temporary branch type to the dungeon branch type. */ STATIC_OVL int correct_branch_type(tbr) struct tmpbranch *tbr; { switch (tbr->type) { case TBR_STAIR: return BR_STAIR; case TBR_NO_UP: return tbr->up ? BR_NO_END1 : BR_NO_END2; case TBR_NO_DOWN: return tbr->up ? BR_NO_END2 : BR_NO_END1; case TBR_PORTAL: return BR_PORTAL; } impossible("correct_branch_type: unknown branch type"); return BR_STAIR; } /* * Add the given branch to the branch list. The branch list is ordered * by end1 dungeon and level followed by end2 dungeon and level. If * extract_first is true, then the branch is already part of the list * but needs to be repositioned. */ void insert_branch(new_branch, extract_first) branch *new_branch; boolean extract_first; { branch *curr, *prev; long new_val, curr_val, prev_val; if (extract_first) { for (prev = 0, curr = branches; curr; prev = curr, curr = curr->next) if (curr == new_branch) break; if (!curr) panic("insert_branch: not found"); if (prev) prev->next = curr->next; else branches = curr->next; } new_branch->next = (branch *) 0; /* Convert the branch into a unique number so we can sort them. */ #define branch_val(bp) \ ((((long)(bp)->end1.dnum * (MAXLEVEL+1) + \ (long)(bp)->end1.dlevel) * (MAXDUNGEON+1) * (MAXLEVEL+1)) + \ ((long)(bp)->end2.dnum * (MAXLEVEL+1) + (long)(bp)->end2.dlevel)) /* * Insert the new branch into the correct place in the branch list. */ prev = (branch *) 0; prev_val = -1; new_val = branch_val(new_branch); for (curr = branches; curr; prev_val = curr_val, prev = curr, curr = curr->next) { curr_val = branch_val(curr); if (prev_val < new_val && new_val <= curr_val) break; } if (prev) { new_branch->next = curr; prev->next = new_branch; } else { new_branch->next = branches; branches = new_branch; } } /* Add a dungeon branch to the branch list. */ STATIC_OVL branch * add_branch(dgn, child_entry_level, pd) int dgn; int child_entry_level; struct proto_dungeon *pd; { static int branch_id = 0; int branch_num; branch *new_branch; branch_num = find_branch(dungeons[dgn].dname,pd); new_branch = (branch *) alloc(sizeof(branch)); new_branch->next = (branch *) 0; new_branch->id = branch_id++; new_branch->type = correct_branch_type(&pd->tmpbranch[branch_num]); new_branch->end1.dnum = parent_dnum(dungeons[dgn].dname, pd); new_branch->end1.dlevel = parent_dlevel(dungeons[dgn].dname, pd); new_branch->end2.dnum = dgn; new_branch->end2.dlevel = child_entry_level; new_branch->end1_up = pd->tmpbranch[branch_num].up ? TRUE : FALSE; insert_branch(new_branch, FALSE); return new_branch; } /* * Add new level to special level chain. Insert it in level order with the * other levels in this dungeon. This assumes that we are never given a * level that has a dungeon number less than the dungeon number of the * last entry. */ STATIC_OVL void add_level(new_lev) s_level *new_lev; { s_level *prev, *curr; prev = (s_level *) 0; for (curr = sp_levchn; curr; curr = curr->next) { if (curr->dlevel.dnum == new_lev->dlevel.dnum && curr->dlevel.dlevel > new_lev->dlevel.dlevel) break; prev = curr; } if (!prev) { new_lev->next = sp_levchn; sp_levchn = new_lev; } else { new_lev->next = curr; prev->next = new_lev; } } STATIC_OVL void init_level(dgn, proto_index, pd) int dgn, proto_index; struct proto_dungeon *pd; { s_level *new_level; struct tmplevel *tlevel = &pd->tmplevel[proto_index]; pd->final_lev[proto_index] = (s_level *) 0; /* no "real" level */ #ifdef WIZARD if (!wizard) #endif if (tlevel->chance <= rn2(100)) return; pd->final_lev[proto_index] = new_level = (s_level *) alloc(sizeof(s_level)); /* load new level with data */ Strcpy(new_level->proto, tlevel->name); new_level->boneid = tlevel->boneschar; new_level->dlevel.dnum = dgn; new_level->dlevel.dlevel = 0; /* for now */ new_level->flags.town = !!(tlevel->flags & TOWN); new_level->flags.hellish = !!(tlevel->flags & HELLISH); new_level->flags.maze_like = !!(tlevel->flags & MAZELIKE); new_level->flags.rogue_like = !!(tlevel->flags & ROGUELIKE); new_level->flags.align = ((tlevel->flags & D_ALIGN_MASK) >> 4); if (!new_level->flags.align) new_level->flags.align = ((pd->tmpdungeon[dgn].flags & D_ALIGN_MASK) >> 4); new_level->rndlevs = tlevel->rndlevs; new_level->next = (s_level *) 0; } STATIC_OVL int possible_places(idx, map, pd) int idx; /* prototype index */ boolean *map; /* array MAXLEVEL+1 in length */ struct proto_dungeon *pd; { int i, start, count; s_level *lev = pd->final_lev[idx]; /* init level possibilities */ for (i = 0; i <= MAXLEVEL; i++) map[i] = FALSE; /* get base and range and set those entried to true */ count = level_range(lev->dlevel.dnum, pd->tmplevel[idx].lev.base, pd->tmplevel[idx].lev.rand, pd->tmplevel[idx].chain, pd, &start); for (i = start; i < start+count; i++) map[i] = TRUE; /* mark off already placed levels */ for (i = pd->start; i < idx; i++) { if (pd->final_lev[i] && map[pd->final_lev[i]->dlevel.dlevel]) { map[pd->final_lev[i]->dlevel.dlevel] = FALSE; --count; } } return count; } /* Pick the nth TRUE entry in the given boolean array. */ STATIC_OVL xchar pick_level(map, nth) boolean *map; /* an array MAXLEVEL+1 in size */ int nth; { int i; for (i = 1; i <= MAXLEVEL; i++) if (map[i] && !nth--) return (xchar) i; panic("pick_level: ran out of valid levels"); return 0; } #ifdef DDEBUG static void FDECL(indent,(int)); static void indent(d) int d; { while (d-- > 0) fputs(" ", stderr); } #endif /* * Place a level. First, find the possible places on a dungeon map * template. Next pick one. Then try to place the next level. If * sucessful, we're done. Otherwise, try another (and another) until * all possible places have been tried. If all possible places have * been exausted, return false. */ STATIC_OVL boolean place_level(proto_index, pd) int proto_index; struct proto_dungeon *pd; { boolean map[MAXLEVEL+1]; /* valid levels are 1..MAXLEVEL inclusive */ s_level *lev; int npossible; #ifdef DDEBUG int i; #endif if (proto_index == pd->n_levs) return TRUE; /* at end of proto levels */ lev = pd->final_lev[proto_index]; /* No level created for this prototype, goto next. */ if (!lev) return place_level(proto_index+1, pd); npossible = possible_places(proto_index, map, pd); for (; npossible; --npossible) { lev->dlevel.dlevel = pick_level(map, rn2(npossible)); #ifdef DDEBUG indent(proto_index-pd->start); fprintf(stderr,"%s: trying %d [ ", lev->proto, lev->dlevel.dlevel); for (i = 1; i <= MAXLEVEL; i++) if (map[i]) fprintf(stderr,"%d ", i); fprintf(stderr,"]\n"); #endif if (place_level(proto_index+1, pd)) return TRUE; map[lev->dlevel.dlevel] = FALSE; /* this choice didn't work */ } #ifdef DDEBUG indent(proto_index-pd->start); fprintf(stderr,"%s: failed\n", lev->proto); #endif return FALSE; } struct level_map { const char *lev_name; d_level *lev_spec; } level_map[] = { { "air", &air_level }, { "asmodeus", &asmodeus_level }, { "astral", &astral_level }, { "baalz", &baalzebub_level }, { "bigroom", &bigroom_level }, { "castle", &stronghold_level }, { "earth", &earth_level }, { "fakewiz1", &portal_level }, { "fire", &fire_level }, { "juiblex", &juiblex_level }, { "knox", &knox_level }, { "medusa", &medusa_level }, { "oracle", &oracle_level }, { "orcus", &orcus_level }, #ifdef REINCARNATION { "rogue", &rogue_level }, #endif { "sanctum", &sanctum_level }, { "valley", &valley_level }, { "water", &water_level }, { "wizard1", &wiz1_level }, { "wizard2", &wiz2_level }, { "wizard3", &wiz3_level }, { X_START, &qstart_level }, { X_LOCATE, &qlocate_level }, { X_GOAL, &nemesis_level }, { "", (d_level *)0 } }; void init_dungeons() /* initialize the "dungeon" structs */ { dlb *dgn_file; register int i, cl = 0, cb = 0; register s_level *x; struct proto_dungeon pd; struct level_map *lev_map; struct version_info vers_info; pd.n_levs = pd.n_brs = 0; dgn_file = dlb_fopen(DUNGEON_FILE, RDBMODE); if (!dgn_file) { char tbuf[BUFSZ]; Sprintf(tbuf, "Cannot open dungeon description - \"%s", DUNGEON_FILE); #ifdef DLBRSRC /* using a resource from the executable */ Strcat(tbuf, "\" resource!"); #else /* using a file or DLB file */ # if defined(DLB) Strcat(tbuf, "\" from "); # ifdef PREFIXES_IN_USE Strcat(tbuf, "\n\""); if (fqn_prefix[DATAPREFIX]) Strcat(tbuf, fqn_prefix[DATAPREFIX]); # else Strcat(tbuf, "\""); # endif Strcat(tbuf, DLBFILE); # endif Strcat(tbuf, "\" file!"); #endif #ifdef WIN32 interject_assistance(1, INTERJECT_PANIC, (genericptr_t)tbuf, (genericptr_t)fqn_prefix[DATAPREFIX]); #endif panic(tbuf); } /* validate the data's version against the program's version */ Fread((genericptr_t) &vers_info, sizeof vers_info, 1, dgn_file); /* we'd better clear the screen now, since when error messages come from * check_version() they will be printed using pline(), which doesn't * mix with the raw messages that might be already on the screen */ if (iflags.window_inited) clear_nhwindow(WIN_MAP); if (!check_version(&vers_info, DUNGEON_FILE, TRUE)) panic("Dungeon description not valid."); /* * Read in each dungeon and transfer the results to the internal * dungeon arrays. */ sp_levchn = (s_level *) 0; Fread((genericptr_t)&n_dgns, sizeof(int), 1, dgn_file); if (n_dgns >= MAXDUNGEON) panic("init_dungeons: too many dungeons"); for (i = 0; i < n_dgns; i++) { Fread((genericptr_t)&pd.tmpdungeon[i], sizeof(struct tmpdungeon), 1, dgn_file); #ifdef WIZARD if(!wizard) #endif if(pd.tmpdungeon[i].chance && (pd.tmpdungeon[i].chance <= rn2(100))) { int j; /* skip over any levels or branches */ for(j = 0; j < pd.tmpdungeon[i].levels; j++) Fread((genericptr_t)&pd.tmplevel[cl], sizeof(struct tmplevel), 1, dgn_file); for(j = 0; j < pd.tmpdungeon[i].branches; j++) Fread((genericptr_t)&pd.tmpbranch[cb], sizeof(struct tmpbranch), 1, dgn_file); n_dgns--; i--; continue; } Strcpy(dungeons[i].dname, pd.tmpdungeon[i].name); Strcpy(dungeons[i].proto, pd.tmpdungeon[i].protoname); dungeons[i].boneid = pd.tmpdungeon[i].boneschar; if(pd.tmpdungeon[i].lev.rand) dungeons[i].num_dunlevs = (xchar)rn1(pd.tmpdungeon[i].lev.rand, pd.tmpdungeon[i].lev.base); else dungeons[i].num_dunlevs = (xchar)pd.tmpdungeon[i].lev.base; if(!i) { dungeons[i].ledger_start = 0; dungeons[i].depth_start = 1; dungeons[i].dunlev_ureached = 1; } else { dungeons[i].ledger_start = dungeons[i-1].ledger_start + dungeons[i-1].num_dunlevs; dungeons[i].dunlev_ureached = 0; } dungeons[i].flags.hellish = !!(pd.tmpdungeon[i].flags & HELLISH); dungeons[i].flags.maze_like = !!(pd.tmpdungeon[i].flags & MAZELIKE); dungeons[i].flags.rogue_like = !!(pd.tmpdungeon[i].flags & ROGUELIKE); dungeons[i].flags.align = ((pd.tmpdungeon[i].flags & D_ALIGN_MASK) >> 4); /* * Set the entry level for this dungeon. The pd.tmpdungeon entry * value means: * < 0 from bottom (-1 == bottom level) * 0 default (top) * > 0 actual level (1 = top) * * Note that the entry_lev field in the dungeon structure is * redundant. It is used only here and in print_dungeon(). */ if (pd.tmpdungeon[i].entry_lev < 0) { dungeons[i].entry_lev = dungeons[i].num_dunlevs + pd.tmpdungeon[i].entry_lev + 1; if (dungeons[i].entry_lev <= 0) dungeons[i].entry_lev = 1; } else if (pd.tmpdungeon[i].entry_lev > 0) { dungeons[i].entry_lev = pd.tmpdungeon[i].entry_lev; if (dungeons[i].entry_lev > dungeons[i].num_dunlevs) dungeons[i].entry_lev = dungeons[i].num_dunlevs; } else { /* default */ dungeons[i].entry_lev = 1; /* defaults to top level */ } if (i) { /* set depth */ branch *br; schar from_depth; boolean from_up; br = add_branch(i, dungeons[i].entry_lev, &pd); /* Get the depth of the connecting end. */ if (br->end1.dnum == i) { from_depth = depth(&br->end2); from_up = !br->end1_up; } else { from_depth = depth(&br->end1); from_up = br->end1_up; } /* * Calculate the depth of the top of the dungeon via * its branch. First, the depth of the entry point: * * depth of branch from "parent" dungeon * + -1 or 1 depending on a up or down stair or * 0 if portal * * Followed by the depth of the top of the dungeon: * * - (entry depth - 1) * * We'll say that portals stay on the same depth. */ dungeons[i].depth_start = from_depth + (br->type == BR_PORTAL ? 0 : (from_up ? -1 : 1)) - (dungeons[i].entry_lev - 1); } /* this is redundant - it should have been flagged by dgn_comp */ if(dungeons[i].num_dunlevs > MAXLEVEL) dungeons[i].num_dunlevs = MAXLEVEL; pd.start = pd.n_levs; /* save starting point */ pd.n_levs += pd.tmpdungeon[i].levels; if (pd.n_levs > LEV_LIMIT) panic("init_dungeon: too many special levels"); /* * Read in the prototype special levels. Don't add generated * special levels until they are all placed. */ for(; cl < pd.n_levs; cl++) { Fread((genericptr_t)&pd.tmplevel[cl], sizeof(struct tmplevel), 1, dgn_file); init_level(i, cl, &pd); } /* * Recursively place the generated levels for this dungeon. This * routine will attempt all possible combinations before giving * up. */ if (!place_level(pd.start, &pd)) panic("init_dungeon: couldn't place levels"); #ifdef DDEBUG fprintf(stderr, "--- end of dungeon %d ---\n", i); fflush(stderr); getchar(); #endif for (; pd.start < pd.n_levs; pd.start++) if (pd.final_lev[pd.start]) add_level(pd.final_lev[pd.start]); pd.n_brs += pd.tmpdungeon[i].branches; if (pd.n_brs > BRANCH_LIMIT) panic("init_dungeon: too many branches"); for(; cb < pd.n_brs; cb++) Fread((genericptr_t)&pd.tmpbranch[cb], sizeof(struct tmpbranch), 1, dgn_file); } (void) dlb_fclose(dgn_file); for (i = 0; i < 5; i++) tune[i] = 'A' + rn2(7); tune[5] = 0; /* * Find most of the special levels and dungeons so we can access their * locations quickly. */ for (lev_map = level_map; lev_map->lev_name[0]; lev_map++) { x = find_level(lev_map->lev_name); if (x) { assign_level(lev_map->lev_spec, &x->dlevel); if (!strncmp(lev_map->lev_name, "x-", 2)) { /* This is where the name substitution on the * levels of the quest dungeon occur. */ Sprintf(x->proto, "%s%s", urole.filecode, &lev_map->lev_name[1]); } else if (lev_map->lev_spec == &knox_level) { branch *br; /* * Kludge to allow floating Knox entrance. We * specify a floating entrance by the fact that * its entrance (end1) has a bogus dnum, namely * n_dgns. */ for (br = branches; br; br = br->next) if (on_level(&br->end2, &knox_level)) break; if (br) br->end1.dnum = n_dgns; /* adjust the branch's position on the list */ insert_branch(br, TRUE); } } } /* * I hate hardwiring these names. :-( */ quest_dnum = dname_to_dnum("The Quest"); sokoban_dnum = dname_to_dnum("Sokoban"); mines_dnum = dname_to_dnum("The Gnomish Mines"); tower_dnum = dname_to_dnum("Vlad's Tower"); /* one special fixup for dummy surface level */ if ((x = find_level("dummy")) != 0) { i = x->dlevel.dnum; /* the code above puts earth one level above dungeon level #1, making the dummy level overlay level 1; but the whole reason for having the dummy level is to make earth have depth -1 instead of 0, so adjust the start point to shift endgame up */ if (dunlevs_in_dungeon(&x->dlevel) > 1 - dungeons[i].depth_start) dungeons[i].depth_start -= 1; /* TO DO: strip "dummy" out all the way here, so that it's hidden from feedback. */ } #ifdef DEBUG dumpit(); #endif } xchar dunlev(lev) /* return the level number for lev in *this* dungeon */ d_level *lev; { return(lev->dlevel); } xchar dunlevs_in_dungeon(lev) /* return the lowest level number for *this* dungeon*/ d_level *lev; { return(dungeons[lev->dnum].num_dunlevs); } xchar deepest_lev_reached(noquest) /* return the lowest level explored in the game*/ boolean noquest; { /* this function is used for three purposes: to provide a factor * of difficulty in monster generation; to provide a factor of * difficulty in experience calculations (botl.c and end.c); and * to insert the deepest level reached in the game in the topten * display. the 'noquest' arg switch is required for the latter. * * from the player's point of view, going into the Quest is _not_ * going deeper into the dungeon -- it is going back "home", where * the dungeon starts at level 1. given the setup in dungeon.def, * the depth of the Quest (thought of as starting at level 1) is * never lower than the level of entry into the Quest, so we exclude * the Quest from the topten "deepest level reached" display * calculation. _However_ the Quest is a difficult dungeon, so we * include it in the factor of difficulty calculations. */ register int i; d_level tmp; register schar ret = 0; for(i = 0; i < n_dgns; i++) { if((tmp.dlevel = dungeons[i].dunlev_ureached) == 0) continue; if(!strcmp(dungeons[i].dname, "The Quest") && noquest) continue; tmp.dnum = i; if(depth(&tmp) > ret) ret = depth(&tmp); } return((xchar) ret); } /* return a bookkeeping level number for purpose of comparisons and * save/restore */ xchar ledger_no(lev) d_level *lev; { return((xchar)(lev->dlevel + dungeons[lev->dnum].ledger_start)); } /* * The last level in the bookkeeping list of level is the bottom of the last * dungeon in the dungeons[] array. * * Maxledgerno() -- which is the max number of levels in the bookkeeping * list, should not be confused with dunlevs_in_dungeon(lev) -- which * returns the max number of levels in lev's dungeon, and both should * not be confused with deepest_lev_reached() -- which returns the lowest * depth visited by the player. */ xchar maxledgerno() { return (xchar) (dungeons[n_dgns-1].ledger_start + dungeons[n_dgns-1].num_dunlevs); } /* return the dungeon that this ledgerno exists in */ xchar ledger_to_dnum(ledgerno) xchar ledgerno; { register int i; /* find i such that (i->base + 1) <= ledgerno <= (i->base + i->count) */ for (i = 0; i < n_dgns; i++) if (dungeons[i].ledger_start < ledgerno && ledgerno <= dungeons[i].ledger_start + dungeons[i].num_dunlevs) return (xchar)i; panic("level number out of range [ledger_to_dnum(%d)]", (int)ledgerno); /*NOT REACHED*/ return (xchar)0; } /* return the level of the dungeon this ledgerno exists in */ xchar ledger_to_dlev(ledgerno) xchar ledgerno; { return((xchar)(ledgerno - dungeons[ledger_to_dnum(ledgerno)].ledger_start)); } #endif /* OVL1 */ #ifdef OVL0 /* returns the depth of a level, in floors below the surface */ /* (note levels in different dungeons can have the same depth). */ schar depth(lev) d_level *lev; { return((schar)( dungeons[lev->dnum].depth_start + lev->dlevel - 1)); } boolean on_level(lev1, lev2) /* are "lev1" and "lev2" actually the same? */ d_level *lev1, *lev2; { return((boolean)((lev1->dnum == lev2->dnum) && (lev1->dlevel == lev2->dlevel))); } #endif /* OVL0 */ #ifdef OVL1 /* is this level referenced in the special level chain? */ s_level * Is_special(lev) d_level *lev; { s_level *levtmp; for (levtmp = sp_levchn; levtmp; levtmp = levtmp->next) if (on_level(lev, &levtmp->dlevel)) return(levtmp); return((s_level *)0); } /* * Is this a multi-dungeon branch level? If so, return a pointer to the * branch. Otherwise, return null. */ branch * Is_branchlev(lev) d_level *lev; { branch *curr; for (curr = branches; curr; curr = curr->next) { if (on_level(lev, &curr->end1) || on_level(lev, &curr->end2)) return curr; } return (branch *) 0; } /* goto the next level (or appropriate dungeon) */ void next_level(at_stairs) boolean at_stairs; { if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) { /* Taking a down dungeon branch. */ goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE); } else { /* Going down a stairs or jump in a trap door. */ d_level newlevel; newlevel.dnum = u.uz.dnum; newlevel.dlevel = u.uz.dlevel + 1; goto_level(&newlevel, at_stairs, !at_stairs, FALSE); } } /* goto the previous level (or appropriate dungeon) */ void prev_level(at_stairs) boolean at_stairs; { if (at_stairs && u.ux == sstairs.sx && u.uy == sstairs.sy) { /* Taking an up dungeon branch. */ /* KMH -- Upwards branches are okay if not level 1 */ /* (Just make sure it doesn't go above depth 1) */ if(!u.uz.dnum && u.uz.dlevel == 1 && !u.uhave.amulet) done(ESCAPED); else goto_level(&sstairs.tolev, at_stairs, FALSE, FALSE); } else { /* Going up a stairs or rising through the ceiling. */ d_level newlevel; newlevel.dnum = u.uz.dnum; newlevel.dlevel = u.uz.dlevel - 1; goto_level(&newlevel, at_stairs, FALSE, FALSE); } } void u_on_newpos(x, y) int x, y; { u.ux = x; u.uy = y; #ifdef CLIPPING cliparound(u.ux, u.uy); #endif #ifdef STEED /* ridden steed always shares hero's location */ if (u.usteed) u.usteed->mx = u.ux, u.usteed->my = u.uy; #endif } void u_on_sstairs() { /* place you on the special staircase */ if (sstairs.sx) { u_on_newpos(sstairs.sx, sstairs.sy); } else { /* code stolen from goto_level */ int trycnt = 0; xchar x, y; #ifdef DEBUG pline("u_on_sstairs: picking random spot"); #endif #define badspot(x,y) ((levl[x][y].typ != ROOM && levl[x][y].typ != CORR) || MON_AT(x, y)) do { x = rnd(COLNO-1); y = rn2(ROWNO); if (!badspot(x, y)) { u_on_newpos(x, y); return; } } while (++trycnt <= 500); panic("u_on_sstairs: could not relocate player!"); #undef badspot } } void u_on_upstairs() /* place you on upstairs (or special equivalent) */ { if (xupstair) { u_on_newpos(xupstair, yupstair); } else u_on_sstairs(); } void u_on_dnstairs() /* place you on dnstairs (or special equivalent) */ { if (xdnstair) { u_on_newpos(xdnstair, ydnstair); } else u_on_sstairs(); } boolean On_stairs(x, y) xchar x, y; { return((boolean)((x == xupstair && y == yupstair) || (x == xdnstair && y == ydnstair) || (x == xdnladder && y == ydnladder) || (x == xupladder && y == yupladder) || (x == sstairs.sx && y == sstairs.sy))); } boolean Is_botlevel(lev) d_level *lev; { return((boolean)(lev->dlevel == dungeons[lev->dnum].num_dunlevs)); } boolean Can_dig_down(lev) d_level *lev; { return((boolean)(!level.flags.hardfloor && !Is_botlevel(lev) && !Invocation_lev(lev))); } /* * Like Can_dig_down (above), but also allows falling through on the * stronghold level. Normally, the bottom level of a dungeon resists * both digging and falling. */ boolean Can_fall_thru(lev) d_level *lev; { return((boolean)(Can_dig_down(lev) || Is_stronghold(lev))); } /* * True if one can rise up a level (e.g. cursed gain level). * This happens on intermediate dungeon levels or on any top dungeon * level that has a stairwell style branch to the next higher dungeon. * Checks for amulets and such must be done elsewhere. */ boolean Can_rise_up(x, y, lev) int x, y; d_level *lev; { /* can't rise up from inside the top of the Wizard's tower */ /* KMH -- or in sokoban */ if (In_endgame(lev) || In_sokoban(lev) || (Is_wiz1_level(lev) && In_W_tower(x, y, lev))) return FALSE; return (boolean)(lev->dlevel > 1 || (dungeons[lev->dnum].entry_lev == 1 && ledger_no(lev) != 1 && sstairs.sx && sstairs.up)); } /* * It is expected that the second argument of get_level is a depth value, * either supplied by the user (teleport control) or randomly generated. * But more than one level can be at the same depth. If the target level * is "above" the present depth location, get_level must trace "up" from * the player's location (through the ancestors dungeons) the dungeon * within which the target level is located. With only one exception * which does not pass through this routine (see level_tele), teleporting * "down" is confined to the current dungeon. At present, level teleport * in dungeons that build up is confined within them. */ void get_level(newlevel, levnum) d_level *newlevel; int levnum; { branch *br; xchar dgn = u.uz.dnum; if (levnum <= 0) { /* can only currently happen in endgame */ levnum = u.uz.dlevel; } else if (levnum > dungeons[dgn].depth_start + dungeons[dgn].num_dunlevs - 1) { /* beyond end of dungeon, jump to last level */ levnum = dungeons[dgn].num_dunlevs; } else { /* The desired level is in this dungeon or a "higher" one. */ /* * Branch up the tree until we reach a dungeon that contains the * levnum. */ if (levnum < dungeons[dgn].depth_start) { do { /* * Find the parent dungeon of this dungeon. * * This assumes that end2 is always the "child" and it is * unique. */ for (br = branches; br; br = br->next) if (br->end2.dnum == dgn) break; if (!br) panic("get_level: can't find parent dungeon"); dgn = br->end1.dnum; } while (levnum < dungeons[dgn].depth_start); } /* We're within the same dungeon; calculate the level. */ levnum = levnum - dungeons[dgn].depth_start + 1; } newlevel->dnum = dgn; newlevel->dlevel = levnum; } #endif /* OVL1 */ #ifdef OVL0 boolean In_quest(lev) /* are you in the quest dungeon? */ d_level *lev; { return((boolean)(lev->dnum == quest_dnum)); } #endif /* OVL0 */ #ifdef OVL1 boolean In_mines(lev) /* are you in the mines dungeon? */ d_level *lev; { return((boolean)(lev->dnum == mines_dnum)); } /* * Return the branch for the given dungeon. * * This function assumes: * + This is not called with "Dungeons of Doom". * + There is only _one_ branch to a given dungeon. * + Field end2 is the "child" dungeon. */ branch * dungeon_branch(s) const char *s; { branch *br; xchar dnum; dnum = dname_to_dnum(s); /* Find the branch that connects to dungeon i's branch. */ for (br = branches; br; br = br->next) if (br->end2.dnum == dnum) break; if (!br) panic("dgn_entrance: can't find entrance to %s", s); return br; } /* * This returns true if the hero is on the same level as the entrance to * the named dungeon. * * Called from do.c and mklev.c. * * Assumes that end1 is always the "parent". */ boolean at_dgn_entrance(s) const char *s; { branch *br; br = dungeon_branch(s); return((boolean)(on_level(&u.uz, &br->end1) ? TRUE : FALSE)); } boolean In_V_tower(lev) /* is `lev' part of Vlad's tower? */ d_level *lev; { return((boolean)(lev->dnum == tower_dnum)); } boolean On_W_tower_level(lev) /* is `lev' a level containing the Wizard's tower? */ d_level *lev; { return (boolean)(Is_wiz1_level(lev) || Is_wiz2_level(lev) || Is_wiz3_level(lev)); } boolean In_W_tower(x, y, lev) /* is of `lev' inside the Wizard's tower? */ int x, y; d_level *lev; { if (!On_W_tower_level(lev)) return FALSE; /* * Both of the exclusion regions for arriving via level teleport * (from above or below) define the tower's boundary. * assert( updest.nIJ == dndest.nIJ for I={l|h},J={x|y} ); */ if (dndest.nlx > 0) return (boolean)within_bounded_area(x, y, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy); else impossible("No boundary for Wizard's Tower?"); return FALSE; } #endif /* OVL1 */ #ifdef OVL0 boolean In_hell(lev) /* are you in one of the Hell levels? */ d_level *lev; { return((boolean)(dungeons[lev->dnum].flags.hellish)); } #endif /* OVL0 */ #ifdef OVL1 void find_hell(lev) /* sets *lev to be the gateway to Gehennom... */ d_level *lev; { lev->dnum = valley_level.dnum; lev->dlevel = 1; } void goto_hell(at_stairs, falling) /* go directly to hell... */ boolean at_stairs, falling; { d_level lev; find_hell(&lev); goto_level(&lev, at_stairs, falling, FALSE); } void assign_level(dest, src) /* equivalent to dest = source */ d_level *dest, *src; { dest->dnum = src->dnum; dest->dlevel = src->dlevel; } void assign_rnd_level(dest, src, range) /* dest = src + rn1(range) */ d_level *dest, *src; int range; { dest->dnum = src->dnum; dest->dlevel = src->dlevel + ((range > 0) ? rnd(range) : -rnd(-range)) ; if(dest->dlevel > dunlevs_in_dungeon(dest)) dest->dlevel = dunlevs_in_dungeon(dest); else if(dest->dlevel < 1) dest->dlevel = 1; } #endif /* OVL1 */ #ifdef OVL0 int induced_align(pct) int pct; { s_level *lev = Is_special(&u.uz); aligntyp al; if (lev && lev->flags.align) if(rn2(100) < pct) return(lev->flags.align); if(dungeons[u.uz.dnum].flags.align) if(rn2(100) < pct) return(dungeons[u.uz.dnum].flags.align); al = rn2(3) - 1; return(Align2amask(al)); } #endif /* OVL0 */ #ifdef OVL1 boolean Invocation_lev(lev) d_level *lev; { return((boolean)(In_hell(lev) && lev->dlevel == (dungeons[lev->dnum].num_dunlevs - 1))); } /* use instead of depth() wherever a degree of difficulty is made * dependent on the location in the dungeon (eg. monster creation). */ xchar level_difficulty() { if (In_endgame(&u.uz)) return((xchar)(depth(&sanctum_level) + u.ulevel/2)); else if (u.uhave.amulet) return(deepest_lev_reached(FALSE)); else return((xchar) depth(&u.uz)); } /* Take one word and try to match it to a level. * Recognized levels are as shown by print_dungeon(). */ schar lev_by_name(nam) const char *nam; { schar lev = 0; s_level *slev; d_level dlev; const char *p; int idx, idxtoo; char buf[BUFSZ]; /* allow strings like "the oracle level" to find "oracle" */ if (!strncmpi(nam, "the ", 4)) nam += 4; if ((p = strstri(nam, " level")) != 0 && p == eos((char*)nam) - 6) { nam = strcpy(buf, nam); *(eos(buf) - 6) = '\0'; } /* hell is the old name, and wouldn't match; gehennom would match its branch, yielding the castle level instead of the valley of the dead */ if (!strcmpi(nam, "gehennom") || !strcmpi(nam, "hell")) { if (In_V_tower(&u.uz)) nam = " to Vlad's tower"; /* branch to... */ else nam = "valley"; } if ((slev = find_level(nam)) != 0) { dlev = slev->dlevel; idx = ledger_no(&dlev); if ((dlev.dnum == u.uz.dnum || /* within same branch, or else main dungeon <-> gehennom */ (u.uz.dnum == valley_level.dnum && dlev.dnum == medusa_level.dnum) || (u.uz.dnum == medusa_level.dnum && dlev.dnum == valley_level.dnum)) && ( /* either wizard mode or else seen and not forgotten */ #ifdef WIZARD wizard || #endif (level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED)) { lev = depth(&slev->dlevel); } } else { /* not a specific level; try branch names */ idx = find_branch(nam, (struct proto_dungeon *)0); /* " to Xyzzy" */ if (idx < 0 && (p = strstri(nam, " to ")) != 0) idx = find_branch(p + 4, (struct proto_dungeon *)0); if (idx >= 0) { idxtoo = (idx >> 8) & 0x00FF; idx &= 0x00FF; if ( /* either wizard mode, or else _both_ sides of branch seen */ #ifdef WIZARD wizard || #endif ((level_info[idx].flags & (FORGOTTEN|VISITED)) == VISITED && (level_info[idxtoo].flags & (FORGOTTEN|VISITED)) == VISITED)) { if (ledger_to_dnum(idxtoo) == u.uz.dnum) idx = idxtoo; dlev.dnum = ledger_to_dnum(idx); dlev.dlevel = ledger_to_dlev(idx); lev = depth(&dlev); } } } return lev; } #ifdef WIZARD /* Convert a branch type to a string usable by print_dungeon(). */ STATIC_OVL const char * br_string(type) int type; { switch (type) { case BR_PORTAL: return "Portal"; case BR_NO_END1: return "Connection"; case BR_NO_END2: return "One way stair"; case BR_STAIR: return "Stair"; } return " (unknown)"; } /* Print all child branches between the lower and upper bounds. */ STATIC_OVL void print_branch(win, dnum, lower_bound, upper_bound, bymenu, lchoices) winid win; int dnum; int lower_bound; int upper_bound; boolean bymenu; struct lchoice *lchoices; { branch *br; char buf[BUFSZ]; anything any; /* This assumes that end1 is the "parent". */ for (br = branches; br; br = br->next) { if (br->end1.dnum == dnum && lower_bound < br->end1.dlevel && br->end1.dlevel <= upper_bound) { Sprintf(buf," %s to %s: %d", br_string(br->type), dungeons[br->end2.dnum].dname, depth(&br->end1)); if (bymenu) { lchoices->lev[lchoices->idx] = br->end1.dlevel; lchoices->dgn[lchoices->idx] = br->end1.dnum; lchoices->playerlev[lchoices->idx] = depth(&br->end1); any.a_void = 0; any.a_int = lchoices->idx + 1; add_menu(win, NO_GLYPH, &any, lchoices->menuletter, 0, ATR_NONE, buf, MENU_UNSELECTED); if (lchoices->menuletter == 'z') lchoices->menuletter = 'A'; else lchoices->menuletter++; lchoices->idx++; } else putstr(win, 0, buf); } } } /* Print available dungeon information. */ schar print_dungeon(bymenu, rlev, rdgn) boolean bymenu; schar *rlev; xchar *rdgn; { int i, last_level, nlev; char buf[BUFSZ]; boolean first; s_level *slev; dungeon *dptr; branch *br; anything any; struct lchoice lchoices; winid win = create_nhwindow(NHW_MENU); if (bymenu) { start_menu(win); lchoices.idx = 0; lchoices.menuletter = 'a'; } for (i = 0, dptr = dungeons; i < n_dgns; i++, dptr++) { nlev = dptr->num_dunlevs; if (nlev > 1) Sprintf(buf, "%s: levels %d to %d", dptr->dname, dptr->depth_start, dptr->depth_start + nlev - 1); else Sprintf(buf, "%s: level %d", dptr->dname, dptr->depth_start); /* Most entrances are uninteresting. */ if (dptr->entry_lev != 1) { if (dptr->entry_lev == nlev) Strcat(buf, ", entrance from below"); else Sprintf(eos(buf), ", entrance on %d", dptr->depth_start + dptr->entry_lev - 1); } if (bymenu) { any.a_void = 0; add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, buf, MENU_UNSELECTED); } else putstr(win, 0, buf); /* * Circle through the special levels to find levels that are in * this dungeon. */ for (slev = sp_levchn, last_level = 0; slev; slev = slev->next) { if (slev->dlevel.dnum != i) continue; /* print any branches before this level */ print_branch(win, i, last_level, slev->dlevel.dlevel, bymenu, &lchoices); Sprintf(buf, " %s: %d", slev->proto, depth(&slev->dlevel)); if (Is_stronghold(&slev->dlevel)) Sprintf(eos(buf), " (tune %s)", tune); if (bymenu) { /* If other floating branches are added, this will need to change */ if (i != knox_level.dnum) { lchoices.lev[lchoices.idx] = slev->dlevel.dlevel; lchoices.dgn[lchoices.idx] = i; } else { lchoices.lev[lchoices.idx] = depth(&slev->dlevel); lchoices.dgn[lchoices.idx] = 0; } lchoices.playerlev[lchoices.idx] = depth(&slev->dlevel); any.a_void = 0; any.a_int = lchoices.idx + 1; add_menu(win, NO_GLYPH, &any, lchoices.menuletter, 0, ATR_NONE, buf, MENU_UNSELECTED); if (lchoices.menuletter == 'z') lchoices.menuletter = 'A'; else lchoices.menuletter++; lchoices.idx++; } else putstr(win, 0, buf); last_level = slev->dlevel.dlevel; } /* print branches after the last special level */ print_branch(win, i, last_level, MAXLEVEL, bymenu, &lchoices); } /* Print out floating branches (if any). */ for (first = TRUE, br = branches; br; br = br->next) { if (br->end1.dnum == n_dgns) { if (first) { if (!bymenu) { putstr(win, 0, ""); putstr(win, 0, "Floating branches"); } first = FALSE; } Sprintf(buf, " %s to %s", br_string(br->type), dungeons[br->end2.dnum].dname); if (!bymenu) putstr(win, 0, buf); } } if (bymenu) { int n; menu_item *selected; int idx; end_menu(win, "Level teleport to where:"); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n > 0) { idx = selected[0].item.a_int - 1; free((genericptr_t)selected); if (rlev && rdgn) { *rlev = lchoices.lev[idx]; *rdgn = lchoices.dgn[idx]; return lchoices.playerlev[idx]; } } return 0; } /* I hate searching for the invocation pos while debugging. -dean */ if (Invocation_lev(&u.uz)) { putstr(win, 0, ""); Sprintf(buf, "Invocation position @ (%d,%d), hero @ (%d,%d)", inv_pos.x, inv_pos.y, u.ux, u.uy); putstr(win, 0, buf); } /* * The following is based on the assumption that the inter-level portals * created by the level compiler (not the dungeon compiler) only exist * one per level (currently true, of course). */ else if (Is_earthlevel(&u.uz) || Is_waterlevel(&u.uz) || Is_firelevel(&u.uz) || Is_airlevel(&u.uz)) { struct trap *trap; for (trap = ftrap; trap; trap = trap->ntrap) if (trap->ttyp == MAGIC_PORTAL) break; putstr(win, 0, ""); if (trap) Sprintf(buf, "Portal @ (%d,%d), hero @ (%d,%d)", trap->tx, trap->ty, u.ux, u.uy); else Sprintf(buf, "No portal found."); putstr(win, 0, buf); } display_nhwindow(win, TRUE); destroy_nhwindow(win); return 0; } #endif /* WIZARD */ #endif /* OVL1 */ /*dungeon.c*/ nethack-3.4.3/src/eat.c0100644000000000000000000021346307764735041013367 0ustar rootroot/* SCCS Id: @(#)eat.c 3.4 2003/02/13 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* #define DEBUG */ /* uncomment to enable new eat code debugging */ #ifdef DEBUG # ifdef WIZARD #define debugpline if (wizard) pline # else #define debugpline pline # endif #endif STATIC_PTR int NDECL(eatmdone); STATIC_PTR int NDECL(eatfood); STATIC_PTR void FDECL(costly_tin, (const char*)); STATIC_PTR int NDECL(opentin); STATIC_PTR int NDECL(unfaint); #ifdef OVLB STATIC_DCL const char *FDECL(food_xname, (struct obj *,BOOLEAN_P)); STATIC_DCL void FDECL(choke, (struct obj *)); STATIC_DCL void NDECL(recalc_wt); STATIC_DCL struct obj *FDECL(touchfood, (struct obj *)); STATIC_DCL void NDECL(do_reset_eat); STATIC_DCL void FDECL(done_eating, (BOOLEAN_P)); STATIC_DCL void FDECL(cprefx, (int)); STATIC_DCL int FDECL(intrinsic_possible, (int,struct permonst *)); STATIC_DCL void FDECL(givit, (int,struct permonst *)); STATIC_DCL void FDECL(cpostfx, (int)); STATIC_DCL void FDECL(start_tin, (struct obj *)); STATIC_DCL int FDECL(eatcorpse, (struct obj *)); STATIC_DCL void FDECL(start_eating, (struct obj *)); STATIC_DCL void FDECL(fprefx, (struct obj *)); STATIC_DCL void FDECL(accessory_has_effect, (struct obj *)); STATIC_DCL void FDECL(fpostfx, (struct obj *)); STATIC_DCL int NDECL(bite); STATIC_DCL int FDECL(edibility_prompts, (struct obj *)); STATIC_DCL int FDECL(rottenfood, (struct obj *)); STATIC_DCL void NDECL(eatspecial); STATIC_DCL void FDECL(eataccessory, (struct obj *)); STATIC_DCL const char *FDECL(foodword, (struct obj *)); STATIC_DCL boolean FDECL(maybe_cannibal, (int,BOOLEAN_P)); char msgbuf[BUFSZ]; #endif /* OVLB */ /* hunger texts used on bottom line (each 8 chars long) */ #define SATIATED 0 #define NOT_HUNGRY 1 #define HUNGRY 2 #define WEAK 3 #define FAINTING 4 #define FAINTED 5 #define STARVED 6 /* also used to see if you're allowed to eat cats and dogs */ #define CANNIBAL_ALLOWED() (Role_if(PM_CAVEMAN) || Race_if(PM_ORC)) #ifndef OVLB STATIC_DCL NEARDATA const char comestibles[]; STATIC_DCL NEARDATA const char allobj[]; STATIC_DCL boolean force_save_hs; #else STATIC_OVL NEARDATA const char comestibles[] = { FOOD_CLASS, 0 }; /* Gold must come first for getobj(). */ STATIC_OVL NEARDATA const char allobj[] = { COIN_CLASS, WEAPON_CLASS, ARMOR_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS, AMULET_CLASS, FOOD_CLASS, TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, SPBOOK_CLASS, 0 }; STATIC_OVL boolean force_save_hs = FALSE; const char *hu_stat[] = { "Satiated", " ", "Hungry ", "Weak ", "Fainting", "Fainted ", "Starved " }; #endif /* OVLB */ #ifdef OVL1 /* * Decide whether a particular object can be eaten by the possibly * polymorphed character. Not used for monster checks. */ boolean is_edible(obj) register struct obj *obj; { /* protect invocation tools but not Rider corpses (handled elsewhere)*/ /* if (obj->oclass != FOOD_CLASS && obj_resists(obj, 0, 0)) */ if (objects[obj->otyp].oc_unique) return FALSE; /* above also prevents the Amulet from being eaten, so we must never allow fake amulets to be eaten either [which is already the case] */ if (metallivorous(youmonst.data) && is_metallic(obj) && (youmonst.data != &mons[PM_RUST_MONSTER] || is_rustprone(obj))) return TRUE; if (u.umonnum == PM_GELATINOUS_CUBE && is_organic(obj) && /* [g.cubes can eat containers and retain all contents as engulfed items, but poly'd player can't do that] */ !Has_contents(obj)) return TRUE; /* return((boolean)(!!index(comestibles, obj->oclass))); */ return (boolean)(obj->oclass == FOOD_CLASS); } #endif /* OVL1 */ #ifdef OVLB void init_uhunger() { u.uhunger = 900; u.uhs = NOT_HUNGRY; } static const struct { const char *txt; int nut; } tintxts[] = { {"deep fried", 60}, {"pickled", 40}, {"soup made from", 20}, {"pureed", 500}, #define ROTTEN_TIN 4 {"rotten", -50}, #define HOMEMADE_TIN 5 {"homemade", 50}, {"stir fried", 80}, {"candied", 100}, {"boiled", 50}, {"dried", 55}, {"szechuan", 70}, #define FRENCH_FRIED_TIN 11 {"french fried", 40}, {"sauteed", 95}, {"broiled", 80}, {"smoked", 50}, {"", 0} }; #define TTSZ SIZE(tintxts) static NEARDATA struct { struct obj *tin; int usedtime, reqtime; } tin; static NEARDATA struct { struct obj *piece; /* the thing being eaten, or last thing that * was partially eaten, unless that thing was * a tin, which uses the tin structure above, * in which case this should be 0 */ /* doeat() initializes these when piece is valid */ int usedtime, /* turns spent eating */ reqtime; /* turns required to eat */ int nmod; /* coded nutrition per turn */ Bitfield(canchoke,1); /* was satiated at beginning */ /* start_eating() initializes these */ Bitfield(fullwarn,1); /* have warned about being full */ Bitfield(eating,1); /* victual currently being eaten */ Bitfield(doreset,1); /* stop eating at end of turn */ } victual; static char *eatmbuf = 0; /* set by cpostfx() */ STATIC_PTR int eatmdone() /* called after mimicing is over */ { /* release `eatmbuf' */ if (eatmbuf) { if (nomovemsg == eatmbuf) nomovemsg = 0; free((genericptr_t)eatmbuf), eatmbuf = 0; } /* update display */ if (youmonst.m_ap_type) { youmonst.m_ap_type = M_AP_NOTHING; newsym(u.ux,u.uy); } return 0; } /* ``[the(] singular(food, xname) [)]'' with awareness of unique monsters */ STATIC_OVL const char * food_xname(food, the_pfx) struct obj *food; boolean the_pfx; { const char *result; int mnum = food->corpsenm; if (food->otyp == CORPSE && (mons[mnum].geno & G_UNIQ)) { /* grab xname()'s modifiable return buffer for our own use */ char *bufp = xname(food); Sprintf(bufp, "%s%s corpse", (the_pfx && !type_is_pname(&mons[mnum])) ? "the " : "", s_suffix(mons[mnum].mname)); result = bufp; } else { /* the ordinary case */ result = singular(food, xname); if (the_pfx) result = the(result); } return result; } /* Created by GAN 01/28/87 * Amended by AKP 09/22/87: if not hard, don't choke, just vomit. * Amended by 3. 06/12/89: if not hard, sometimes choke anyway, to keep risk. * 11/10/89: if hard, rarely vomit anyway, for slim chance. */ STATIC_OVL void choke(food) /* To a full belly all food is bad. (It.) */ register struct obj *food; { /* only happens if you were satiated */ if (u.uhs != SATIATED) { if (!food || food->otyp != AMULET_OF_STRANGULATION) return; } else if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL) { adjalign(-1); /* gluttony is unchivalrous */ You_feel("like a glutton!"); } exercise(A_CON, FALSE); if (Breathless || (!Strangled && !rn2(20))) { /* choking by eating AoS doesn't involve stuffing yourself */ if (food && food->otyp == AMULET_OF_STRANGULATION) { You("choke, but recover your composure."); return; } You("stuff yourself and then vomit voluminously."); morehungry(1000); /* you just got *very* sick! */ nomovemsg = 0; vomit(); } else { killer_format = KILLED_BY_AN; /* * Note all "killer"s below read "Choked on %s" on the * high score list & tombstone. So plan accordingly. */ if(food) { You("choke over your %s.", foodword(food)); if (food->oclass == COIN_CLASS) { killer = "a very rich meal"; } else { killer = food_xname(food, FALSE); if (food->otyp == CORPSE && (mons[food->corpsenm].geno & G_UNIQ)) { if (!type_is_pname(&mons[food->corpsenm])) killer = the(killer); killer_format = KILLED_BY; } } } else { You("choke over it."); killer = "quick snack"; } You("die..."); done(CHOKING); } } /* modify object wt. depending on time spent consuming it */ STATIC_OVL void recalc_wt() { struct obj *piece = victual.piece; #ifdef DEBUG debugpline("Old weight = %d", piece->owt); debugpline("Used time = %d, Req'd time = %d", victual.usedtime, victual.reqtime); #endif piece->owt = weight(piece); #ifdef DEBUG debugpline("New weight = %d", piece->owt); #endif } void reset_eat() /* called when eating interrupted by an event */ { /* we only set a flag here - the actual reset process is done after * the round is spent eating. */ if(victual.eating && !victual.doreset) { #ifdef DEBUG debugpline("reset_eat..."); #endif victual.doreset = TRUE; } return; } STATIC_OVL struct obj * touchfood(otmp) register struct obj *otmp; { if (otmp->quan > 1L) { if(!carried(otmp)) (void) splitobj(otmp, otmp->quan - 1L); else otmp = splitobj(otmp, 1L); #ifdef DEBUG debugpline("split object,"); #endif } if (!otmp->oeaten) { if(((!carried(otmp) && costly_spot(otmp->ox, otmp->oy) && !otmp->no_charge) || otmp->unpaid)) { /* create a dummy duplicate to put on bill */ verbalize("You bit it, you bought it!"); bill_dummy_object(otmp); } otmp->oeaten = (otmp->otyp == CORPSE ? mons[otmp->corpsenm].cnutrit : objects[otmp->otyp].oc_nutrition); } if (carried(otmp)) { freeinv(otmp); if (inv_cnt() >= 52) { sellobj_state(SELL_DONTSELL); dropy(otmp); sellobj_state(SELL_NORMAL); } else { otmp->oxlth++; /* hack to prevent merge */ otmp = addinv(otmp); otmp->oxlth--; } } return(otmp); } /* When food decays, in the middle of your meal, we don't want to dereference * any dangling pointers, so set it to null (which should still trigger * do_reset_eat() at the beginning of eatfood()) and check for null pointers * in do_reset_eat(). */ void food_disappears(obj) register struct obj *obj; { if (obj == victual.piece) victual.piece = (struct obj *)0; if (obj->timed) obj_stop_timers(obj); } /* renaming an object usually results in it having a different address; so the sequence start eating/opening, get interrupted, name the food, resume eating/opening would restart from scratch */ void food_substitution(old_obj, new_obj) struct obj *old_obj, *new_obj; { if (old_obj == victual.piece) victual.piece = new_obj; if (old_obj == tin.tin) tin.tin = new_obj; } STATIC_OVL void do_reset_eat() { #ifdef DEBUG debugpline("do_reset_eat..."); #endif if (victual.piece) { victual.piece = touchfood(victual.piece); recalc_wt(); } victual.fullwarn = victual.eating = victual.doreset = FALSE; /* Do not set canchoke to FALSE; if we continue eating the same object * we need to know if canchoke was set when they started eating it the * previous time. And if we don't continue eating the same object * canchoke always gets recalculated anyway. */ stop_occupation(); newuhs(FALSE); } STATIC_PTR int eatfood() /* called each move during eating process */ { if(!victual.piece || (!carried(victual.piece) && !obj_here(victual.piece, u.ux, u.uy))) { /* maybe it was stolen? */ do_reset_eat(); return(0); } if(!victual.eating) return(0); if(++victual.usedtime <= victual.reqtime) { if(bite()) return(0); return(1); /* still busy */ } else { /* done */ done_eating(TRUE); return(0); } } STATIC_OVL void done_eating(message) boolean message; { victual.piece->in_use = TRUE; occupation = 0; /* do this early, so newuhs() knows we're done */ newuhs(FALSE); if (nomovemsg) { if (message) pline(nomovemsg); nomovemsg = 0; } else if (message) You("finish eating %s.", food_xname(victual.piece, TRUE)); if(victual.piece->otyp == CORPSE) cpostfx(victual.piece->corpsenm); else fpostfx(victual.piece); if (carried(victual.piece)) useup(victual.piece); else useupf(victual.piece, 1L); victual.piece = (struct obj *) 0; victual.fullwarn = victual.eating = victual.doreset = FALSE; } STATIC_OVL boolean maybe_cannibal(pm, allowmsg) int pm; boolean allowmsg; { if (!CANNIBAL_ALLOWED() && your_race(&mons[pm])) { if (allowmsg) { if (Upolyd) You("have a bad feeling deep inside."); You("cannibal! You will regret this!"); } HAggravate_monster |= FROMOUTSIDE; change_luck(-rn1(4,2)); /* -5..-2 */ return TRUE; } return FALSE; } STATIC_OVL void cprefx(pm) register int pm; { (void) maybe_cannibal(pm,TRUE); if (touch_petrifies(&mons[pm]) || pm == PM_MEDUSA) { if (!Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { Sprintf(killer_buf, "tasting %s meat", mons[pm].mname); killer_format = KILLED_BY; killer = killer_buf; You("turn to stone."); done(STONING); if (victual.piece) victual.eating = FALSE; return; /* lifesaved */ } } switch(pm) { case PM_LITTLE_DOG: case PM_DOG: case PM_LARGE_DOG: case PM_KITTEN: case PM_HOUSECAT: case PM_LARGE_CAT: if (!CANNIBAL_ALLOWED()) { You_feel("that eating the %s was a bad idea.", mons[pm].mname); HAggravate_monster |= FROMOUTSIDE; } break; case PM_LIZARD: if (Stoned) fix_petrification(); break; case PM_DEATH: case PM_PESTILENCE: case PM_FAMINE: { char buf[BUFSZ]; pline("Eating that is instantly fatal."); Sprintf(buf, "unwisely ate the body of %s", mons[pm].mname); killer = buf; killer_format = NO_KILLER_PREFIX; done(DIED); /* It so happens that since we know these monsters */ /* cannot appear in tins, victual.piece will always */ /* be what we want, which is not generally true. */ if (revive_corpse(victual.piece)) victual.piece = (struct obj *)0; return; } case PM_GREEN_SLIME: if (!Slimed && !Unchanging && !flaming(youmonst.data) && youmonst.data != &mons[PM_GREEN_SLIME]) { You("don't feel very well."); Slimed = 10L; flags.botl = 1; } /* Fall through */ default: if (acidic(&mons[pm]) && Stoned) fix_petrification(); break; } } void fix_petrification() { Stoned = 0; delayed_killer = 0; if (Hallucination) pline("What a pity - you just ruined a future piece of %sart!", ACURR(A_CHA) > 15 ? "fine " : ""); else You_feel("limber!"); } /* * If you add an intrinsic that can be gotten by eating a monster, add it * to intrinsic_possible() and givit(). (It must already be in prop.h to * be an intrinsic property.) * It would be very easy to make the intrinsics not try to give you one * that you already had by checking to see if you have it in * intrinsic_possible() instead of givit(). */ /* intrinsic_possible() returns TRUE iff a monster can give an intrinsic. */ STATIC_OVL int intrinsic_possible(type, ptr) int type; register struct permonst *ptr; { switch (type) { case FIRE_RES: #ifdef DEBUG if (ptr->mconveys & MR_FIRE) { debugpline("can get fire resistance"); return(TRUE); } else return(FALSE); #else return(ptr->mconveys & MR_FIRE); #endif case SLEEP_RES: #ifdef DEBUG if (ptr->mconveys & MR_SLEEP) { debugpline("can get sleep resistance"); return(TRUE); } else return(FALSE); #else return(ptr->mconveys & MR_SLEEP); #endif case COLD_RES: #ifdef DEBUG if (ptr->mconveys & MR_COLD) { debugpline("can get cold resistance"); return(TRUE); } else return(FALSE); #else return(ptr->mconveys & MR_COLD); #endif case DISINT_RES: #ifdef DEBUG if (ptr->mconveys & MR_DISINT) { debugpline("can get disintegration resistance"); return(TRUE); } else return(FALSE); #else return(ptr->mconveys & MR_DISINT); #endif case SHOCK_RES: /* shock (electricity) resistance */ #ifdef DEBUG if (ptr->mconveys & MR_ELEC) { debugpline("can get shock resistance"); return(TRUE); } else return(FALSE); #else return(ptr->mconveys & MR_ELEC); #endif case POISON_RES: #ifdef DEBUG if (ptr->mconveys & MR_POISON) { debugpline("can get poison resistance"); return(TRUE); } else return(FALSE); #else return(ptr->mconveys & MR_POISON); #endif case TELEPORT: #ifdef DEBUG if (can_teleport(ptr)) { debugpline("can get teleport"); return(TRUE); } else return(FALSE); #else return(can_teleport(ptr)); #endif case TELEPORT_CONTROL: #ifdef DEBUG if (control_teleport(ptr)) { debugpline("can get teleport control"); return(TRUE); } else return(FALSE); #else return(control_teleport(ptr)); #endif case TELEPAT: #ifdef DEBUG if (telepathic(ptr)) { debugpline("can get telepathy"); return(TRUE); } else return(FALSE); #else return(telepathic(ptr)); #endif default: return(FALSE); } /*NOTREACHED*/ } /* givit() tries to give you an intrinsic based on the monster's level * and what type of intrinsic it is trying to give you. */ STATIC_OVL void givit(type, ptr) int type; register struct permonst *ptr; { register int chance; #ifdef DEBUG debugpline("Attempting to give intrinsic %d", type); #endif /* some intrinsics are easier to get than others */ switch (type) { case POISON_RES: if ((ptr == &mons[PM_KILLER_BEE] || ptr == &mons[PM_SCORPION]) && !rn2(4)) chance = 1; else chance = 15; break; case TELEPORT: chance = 10; break; case TELEPORT_CONTROL: chance = 12; break; case TELEPAT: chance = 1; break; default: chance = 15; break; } if (ptr->mlevel <= rn2(chance)) return; /* failed die roll */ switch (type) { case FIRE_RES: #ifdef DEBUG debugpline("Trying to give fire resistance"); #endif if(!(HFire_resistance & FROMOUTSIDE)) { You(Hallucination ? "be chillin'." : "feel a momentary chill."); HFire_resistance |= FROMOUTSIDE; } break; case SLEEP_RES: #ifdef DEBUG debugpline("Trying to give sleep resistance"); #endif if(!(HSleep_resistance & FROMOUTSIDE)) { You_feel("wide awake."); HSleep_resistance |= FROMOUTSIDE; } break; case COLD_RES: #ifdef DEBUG debugpline("Trying to give cold resistance"); #endif if(!(HCold_resistance & FROMOUTSIDE)) { You_feel("full of hot air."); HCold_resistance |= FROMOUTSIDE; } break; case DISINT_RES: #ifdef DEBUG debugpline("Trying to give disintegration resistance"); #endif if(!(HDisint_resistance & FROMOUTSIDE)) { You_feel(Hallucination ? "totally together, man." : "very firm."); HDisint_resistance |= FROMOUTSIDE; } break; case SHOCK_RES: /* shock (electricity) resistance */ #ifdef DEBUG debugpline("Trying to give shock resistance"); #endif if(!(HShock_resistance & FROMOUTSIDE)) { if (Hallucination) You_feel("grounded in reality."); else Your("health currently feels amplified!"); HShock_resistance |= FROMOUTSIDE; } break; case POISON_RES: #ifdef DEBUG debugpline("Trying to give poison resistance"); #endif if(!(HPoison_resistance & FROMOUTSIDE)) { You_feel(Poison_resistance ? "especially healthy." : "healthy."); HPoison_resistance |= FROMOUTSIDE; } break; case TELEPORT: #ifdef DEBUG debugpline("Trying to give teleport"); #endif if(!(HTeleportation & FROMOUTSIDE)) { You_feel(Hallucination ? "diffuse." : "very jumpy."); HTeleportation |= FROMOUTSIDE; } break; case TELEPORT_CONTROL: #ifdef DEBUG debugpline("Trying to give teleport control"); #endif if(!(HTeleport_control & FROMOUTSIDE)) { You_feel(Hallucination ? "centered in your personal space." : "in control of yourself."); HTeleport_control |= FROMOUTSIDE; } break; case TELEPAT: #ifdef DEBUG debugpline("Trying to give telepathy"); #endif if(!(HTelepat & FROMOUTSIDE)) { You_feel(Hallucination ? "in touch with the cosmos." : "a strange mental acuity."); HTelepat |= FROMOUTSIDE; /* If blind, make sure monsters show up. */ if (Blind) see_monsters(); } break; default: #ifdef DEBUG debugpline("Tried to give an impossible intrinsic"); #endif break; } } STATIC_OVL void cpostfx(pm) /* called after completely consuming a corpse */ register int pm; { register int tmp = 0; boolean catch_lycanthropy = FALSE; /* in case `afternmv' didn't get called for previously mimicking gold, clean up now to avoid `eatmbuf' memory leak */ if (eatmbuf) (void)eatmdone(); switch(pm) { case PM_NEWT: /* MRKR: "eye of newt" may give small magical energy boost */ if (rn2(3) || 3 * u.uen <= 2 * u.uenmax) { int old_uen = u.uen; u.uen += rnd(3); if (u.uen > u.uenmax) { if (!rn2(3)) u.uenmax++; u.uen = u.uenmax; } if (old_uen != u.uen) { You_feel("a mild buzz."); flags.botl = 1; } } break; case PM_WRAITH: pluslvl(FALSE); break; case PM_HUMAN_WERERAT: catch_lycanthropy = TRUE; u.ulycn = PM_WERERAT; break; case PM_HUMAN_WEREJACKAL: catch_lycanthropy = TRUE; u.ulycn = PM_WEREJACKAL; break; case PM_HUMAN_WEREWOLF: catch_lycanthropy = TRUE; u.ulycn = PM_WEREWOLF; break; case PM_NURSE: if (Upolyd) u.mh = u.mhmax; else u.uhp = u.uhpmax; flags.botl = 1; break; case PM_STALKER: if(!Invis) { set_itimeout(&HInvis, (long)rn1(100, 50)); if (!Blind && !BInvis) self_invis_message(); } else { if (!(HInvis & INTRINSIC)) You_feel("hidden!"); HInvis |= FROMOUTSIDE; HSee_invisible |= FROMOUTSIDE; } newsym(u.ux, u.uy); /* fall into next case */ case PM_YELLOW_LIGHT: /* fall into next case */ case PM_GIANT_BAT: make_stunned(HStun + 30,FALSE); /* fall into next case */ case PM_BAT: make_stunned(HStun + 30,FALSE); break; case PM_GIANT_MIMIC: tmp += 10; /* fall into next case */ case PM_LARGE_MIMIC: tmp += 20; /* fall into next case */ case PM_SMALL_MIMIC: tmp += 20; if (youmonst.data->mlet != S_MIMIC && !Unchanging) { char buf[BUFSZ]; You_cant("resist the temptation to mimic %s.", Hallucination ? "an orange" : "a pile of gold"); #ifdef STEED /* A pile of gold can't ride. */ if (u.usteed) dismount_steed(DISMOUNT_FELL); #endif nomul(-tmp); Sprintf(buf, Hallucination ? "You suddenly dread being peeled and mimic %s again!" : "You now prefer mimicking %s again.", an(Upolyd ? youmonst.data->mname : urace.noun)); eatmbuf = strcpy((char *) alloc(strlen(buf) + 1), buf); nomovemsg = eatmbuf; afternmv = eatmdone; /* ??? what if this was set before? */ youmonst.m_ap_type = M_AP_OBJECT; youmonst.mappearance = Hallucination ? ORANGE : GOLD_PIECE; newsym(u.ux,u.uy); curs_on_u(); /* make gold symbol show up now */ display_nhwindow(WIN_MAP, TRUE); } break; case PM_QUANTUM_MECHANIC: Your("velocity suddenly seems very uncertain!"); if (HFast & INTRINSIC) { HFast &= ~INTRINSIC; You("seem slower."); } else { HFast |= FROMOUTSIDE; You("seem faster."); } break; case PM_LIZARD: if (HStun > 2) make_stunned(2L,FALSE); if (HConfusion > 2) make_confused(2L,FALSE); break; case PM_CHAMELEON: case PM_DOPPELGANGER: /* case PM_SANDESTIN: */ if (!Unchanging) { You_feel("a change coming over you."); polyself(FALSE); } break; case PM_MIND_FLAYER: case PM_MASTER_MIND_FLAYER: if (ABASE(A_INT) < ATTRMAX(A_INT)) { if (!rn2(2)) { pline("Yum! That was real brain food!"); (void) adjattrib(A_INT, 1, FALSE); break; /* don't give them telepathy, too */ } } else { pline("For some reason, that tasted bland."); } /* fall through to default case */ default: { register struct permonst *ptr = &mons[pm]; int i, count; if (dmgtype(ptr, AD_STUN) || dmgtype(ptr, AD_HALU) || pm == PM_VIOLET_FUNGUS) { pline ("Oh wow! Great stuff!"); make_hallucinated(HHallucination + 200,FALSE,0L); } if(is_giant(ptr)) gainstr((struct obj *)0, 0); /* Check the monster for all of the intrinsics. If this * monster can give more than one, pick one to try to give * from among all it can give. * * If a monster can give 4 intrinsics then you have * a 1/1 * 1/2 * 2/3 * 3/4 = 1/4 chance of getting the first, * a 1/2 * 2/3 * 3/4 = 1/4 chance of getting the second, * a 1/3 * 3/4 = 1/4 chance of getting the third, * and a 1/4 chance of getting the fourth. * * And now a proof by induction: * it works for 1 intrinsic (1 in 1 of getting it) * for 2 you have a 1 in 2 chance of getting the second, * otherwise you keep the first * for 3 you have a 1 in 3 chance of getting the third, * otherwise you keep the first or the second * for n+1 you have a 1 in n+1 chance of getting the (n+1)st, * otherwise you keep the previous one. * Elliott Kleinrock, October 5, 1990 */ count = 0; /* number of possible intrinsics */ tmp = 0; /* which one we will try to give */ for (i = 1; i <= LAST_PROP; i++) { if (intrinsic_possible(i, ptr)) { count++; /* a 1 in count chance of replacing the old * one with this one, and a count-1 in count * chance of keeping the old one. (note * that 1 in 1 and 0 in 1 are what we want * for the first one */ if (!rn2(count)) { #ifdef DEBUG debugpline("Intrinsic %d replacing %d", i, tmp); #endif tmp = i; } } } /* if any found try to give them one */ if (count) givit(tmp, ptr); } break; } if (catch_lycanthropy && defends(AD_WERE, uwep)) { if (!touch_artifact(uwep, &youmonst)) { dropx(uwep); uwepgone(); } } return; } void violated_vegetarian() { u.uconduct.unvegetarian++; if (Role_if(PM_MONK)) { You_feel("guilty."); adjalign(-1); } return; } /* common code to check and possibly charge for 1 context.tin.tin, * will split() context.tin.tin if necessary */ STATIC_PTR void costly_tin(verb) const char* verb; /* if 0, the verb is "open" */ { if(((!carried(tin.tin) && costly_spot(tin.tin->ox, tin.tin->oy) && !tin.tin->no_charge) || tin.tin->unpaid)) { verbalize("You %s it, you bought it!", verb ? verb : "open"); if(tin.tin->quan > 1L) tin.tin = splitobj(tin.tin, 1L); bill_dummy_object(tin.tin); } } STATIC_PTR int opentin() /* called during each move whilst opening a tin */ { register int r; const char *what; int which; if(!carried(tin.tin) && !obj_here(tin.tin, u.ux, u.uy)) /* perhaps it was stolen? */ return(0); /* %% probably we should use tinoid */ if(tin.usedtime++ >= 50) { You("give up your attempt to open the tin."); return(0); } if(tin.usedtime < tin.reqtime) return(1); /* still busy */ if(tin.tin->otrapped || (tin.tin->cursed && tin.tin->spe != -1 && !rn2(8))) { b_trapped("tin", 0); costly_tin("destroyed"); goto use_me; } You("succeed in opening the tin."); if(tin.tin->spe != 1) { if (tin.tin->corpsenm == NON_PM) { pline("It turns out to be empty."); tin.tin->dknown = tin.tin->known = TRUE; costly_tin((const char*)0); goto use_me; } r = tin.tin->cursed ? ROTTEN_TIN : /* always rotten if cursed */ (tin.tin->spe == -1) ? HOMEMADE_TIN : /* player made it */ rn2(TTSZ-1); /* else take your pick */ if (r == ROTTEN_TIN && (tin.tin->corpsenm == PM_LIZARD || tin.tin->corpsenm == PM_LICHEN)) r = HOMEMADE_TIN; /* lizards don't rot */ else if (tin.tin->spe == -1 && !tin.tin->blessed && !rn2(7)) r = ROTTEN_TIN; /* some homemade tins go bad */ which = 0; /* 0=>plural, 1=>as-is, 2=>"the" prefix */ if (Hallucination) { what = rndmonnam(); } else { what = mons[tin.tin->corpsenm].mname; if (mons[tin.tin->corpsenm].geno & G_UNIQ) which = type_is_pname(&mons[tin.tin->corpsenm]) ? 1 : 2; } if (which == 0) what = makeplural(what); pline("It smells like %s%s.", (which == 2) ? "the " : "", what); if (yn("Eat it?") == 'n') { if (!Hallucination) tin.tin->dknown = tin.tin->known = TRUE; if (flags.verbose) You("discard the open tin."); costly_tin((const char*)0); goto use_me; } /* in case stop_occupation() was called on previous meal */ victual.piece = (struct obj *)0; victual.fullwarn = victual.eating = victual.doreset = FALSE; You("consume %s %s.", tintxts[r].txt, mons[tin.tin->corpsenm].mname); /* KMH, conduct */ u.uconduct.food++; if (!vegan(&mons[tin.tin->corpsenm])) u.uconduct.unvegan++; if (!vegetarian(&mons[tin.tin->corpsenm])) violated_vegetarian(); tin.tin->dknown = tin.tin->known = TRUE; cprefx(tin.tin->corpsenm); cpostfx(tin.tin->corpsenm); /* charge for one at pre-eating cost */ costly_tin((const char*)0); /* check for vomiting added by GAN 01/16/87 */ if(tintxts[r].nut < 0) make_vomiting((long)rn1(15,10), FALSE); else lesshungry(tintxts[r].nut); if(r == 0 || r == FRENCH_FRIED_TIN) { /* Assume !Glib, because you can't open tins when Glib. */ incr_itimeout(&Glib, rnd(15)); pline("Eating deep fried food made your %s very slippery.", makeplural(body_part(FINGER))); } } else { if (tin.tin->cursed) pline("It contains some decaying%s%s substance.", Blind ? "" : " ", Blind ? "" : hcolor(NH_GREEN)); else pline("It contains spinach."); if (yn("Eat it?") == 'n') { if (!Hallucination && !tin.tin->cursed) tin.tin->dknown = tin.tin->known = TRUE; if (flags.verbose) You("discard the open tin."); costly_tin((const char*)0); goto use_me; } tin.tin->dknown = tin.tin->known = TRUE; costly_tin((const char*)0); if (!tin.tin->cursed) pline("This makes you feel like %s!", Hallucination ? "Swee'pea" : "Popeye"); lesshungry(600); gainstr(tin.tin, 0); u.uconduct.food++; } use_me: if (carried(tin.tin)) useup(tin.tin); else useupf(tin.tin, 1L); tin.tin = (struct obj *) 0; return(0); } STATIC_OVL void start_tin(otmp) /* called when starting to open a tin */ register struct obj *otmp; { register int tmp; if (metallivorous(youmonst.data)) { You("bite right into the metal tin..."); tmp = 1; } else if (nolimbs(youmonst.data)) { You("cannot handle the tin properly to open it."); return; } else if (otmp->blessed) { pline_The("tin opens like magic!"); tmp = 1; } else if(uwep) { switch(uwep->otyp) { case TIN_OPENER: tmp = 1; break; case DAGGER: case SILVER_DAGGER: case ELVEN_DAGGER: case ORCISH_DAGGER: case ATHAME: case CRYSKNIFE: tmp = 3; break; case PICK_AXE: case AXE: tmp = 6; break; default: goto no_opener; } pline("Using your %s you try to open the tin.", aobjnam(uwep, (char *)0)); } else { no_opener: pline("It is not so easy to open this tin."); if(Glib) { pline_The("tin slips from your %s.", makeplural(body_part(FINGER))); if(otmp->quan > 1L) { otmp = splitobj(otmp, 1L); } if (carried(otmp)) dropx(otmp); else stackobj(otmp); return; } tmp = rn1(1 + 500/((int)(ACURR(A_DEX) + ACURRSTR)), 10); } tin.reqtime = tmp; tin.usedtime = 0; tin.tin = otmp; set_occupation(opentin, "opening the tin", 0); return; } int Hear_again() /* called when waking up after fainting */ { flags.soundok = 1; return 0; } /* called on the "first bite" of rotten food */ STATIC_OVL int rottenfood(obj) struct obj *obj; { pline("Blecch! Rotten %s!", foodword(obj)); if(!rn2(4)) { if (Hallucination) You_feel("rather trippy."); else You_feel("rather %s.", body_part(LIGHT_HEADED)); make_confused(HConfusion + d(2,4),FALSE); } else if(!rn2(4) && !Blind) { pline("Everything suddenly goes dark."); make_blinded((long)d(2,10),FALSE); if (!Blind) Your(vision_clears); } else if(!rn2(3)) { const char *what, *where; if (!Blind) what = "goes", where = "dark"; else if (Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)) what = "you lose control of", where = "yourself"; else what = "you slap against the", where = #ifdef STEED (u.usteed) ? "saddle" : #endif surface(u.ux,u.uy); pline_The("world spins and %s %s.", what, where); flags.soundok = 0; nomul(-rnd(10)); nomovemsg = "You are conscious again."; afternmv = Hear_again; return(1); } return(0); } STATIC_OVL int eatcorpse(otmp) /* called when a corpse is selected as food */ register struct obj *otmp; { int tp = 0, mnum = otmp->corpsenm; long rotted = 0L; boolean uniq = !!(mons[mnum].geno & G_UNIQ); int retcode = 0; boolean stoneable = (touch_petrifies(&mons[mnum]) && !Stone_resistance && !poly_when_stoned(youmonst.data)); /* KMH, conduct */ if (!vegan(&mons[mnum])) u.uconduct.unvegan++; if (!vegetarian(&mons[mnum])) violated_vegetarian(); if (mnum != PM_LIZARD && mnum != PM_LICHEN) { long age = peek_at_iced_corpse_age(otmp); rotted = (monstermoves - age)/(10L + rn2(20)); if (otmp->cursed) rotted += 2L; else if (otmp->blessed) rotted -= 2L; } if (mnum != PM_ACID_BLOB && !stoneable && rotted > 5L) { boolean cannibal = maybe_cannibal(mnum, FALSE); pline("Ulch - that %s was tainted%s!", mons[mnum].mlet == S_FUNGUS ? "fungoid vegetation" : !vegetarian(&mons[mnum]) ? "meat" : "protoplasm", cannibal ? " cannibal" : ""); if (Sick_resistance) { pline("It doesn't seem at all sickening, though..."); } else { char buf[BUFSZ]; long sick_time; sick_time = (long) rn1(10, 10); /* make sure new ill doesn't result in improvement */ if (Sick && (sick_time > Sick)) sick_time = (Sick > 1L) ? Sick - 1L : 1L; if (!uniq) Sprintf(buf, "rotted %s", corpse_xname(otmp,TRUE)); else Sprintf(buf, "%s%s rotted corpse", !type_is_pname(&mons[mnum]) ? "the " : "", s_suffix(mons[mnum].mname)); make_sick(sick_time, buf, TRUE, SICK_VOMITABLE); } if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); return(2); } else if (acidic(&mons[mnum]) && !Acid_resistance) { tp++; You("have a very bad case of stomach acid."); /* not body_part() */ losehp(rnd(15), "acidic corpse", KILLED_BY_AN); } else if (poisonous(&mons[mnum]) && rn2(5)) { tp++; pline("Ecch - that must have been poisonous!"); if(!Poison_resistance) { losestr(rnd(4)); losehp(rnd(15), "poisonous corpse", KILLED_BY_AN); } else You("seem unaffected by the poison."); /* now any corpse left too long will make you mildly ill */ } else if ((rotted > 5L || (rotted > 3L && rn2(5))) && !Sick_resistance) { tp++; You_feel("%ssick.", (Sick) ? "very " : ""); losehp(rnd(8), "cadaver", KILLED_BY_AN); } /* delay is weight dependent */ victual.reqtime = 3 + (mons[mnum].cwt >> 6); if (!tp && mnum != PM_LIZARD && mnum != PM_LICHEN && (otmp->orotten || !rn2(7))) { if (rottenfood(otmp)) { otmp->orotten = TRUE; (void)touchfood(otmp); retcode = 1; } if (!mons[otmp->corpsenm].cnutrit) { /* no nutrution: rots away, no message if you passed out */ if (!retcode) pline_The("corpse rots away completely."); if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); retcode = 2; } if (!retcode) consume_oeaten(otmp, 2); /* oeaten >>= 2 */ } else { pline("%s%s %s!", !uniq ? "This " : !type_is_pname(&mons[mnum]) ? "The " : "", food_xname(otmp, FALSE), (vegan(&mons[mnum]) ? (!carnivorous(youmonst.data) && herbivorous(youmonst.data)) : (carnivorous(youmonst.data) && !herbivorous(youmonst.data))) ? "is delicious" : "tastes terrible"); } return(retcode); } STATIC_OVL void start_eating(otmp) /* called as you start to eat */ register struct obj *otmp; { #ifdef DEBUG debugpline("start_eating: %lx (victual = %lx)", otmp, victual.piece); debugpline("reqtime = %d", victual.reqtime); debugpline("(original reqtime = %d)", objects[otmp->otyp].oc_delay); debugpline("nmod = %d", victual.nmod); debugpline("oeaten = %d", otmp->oeaten); #endif victual.fullwarn = victual.doreset = FALSE; victual.eating = TRUE; if (otmp->otyp == CORPSE) { cprefx(victual.piece->corpsenm); if (!victual.piece || !victual.eating) { /* rider revived, or died and lifesaved */ return; } } if (bite()) return; if (++victual.usedtime >= victual.reqtime) { /* print "finish eating" message if they just resumed -dlc */ done_eating(victual.reqtime > 1 ? TRUE : FALSE); return; } Sprintf(msgbuf, "eating %s", food_xname(otmp, TRUE)); set_occupation(eatfood, msgbuf, 0); } /* * called on "first bite" of (non-corpse) food. * used for non-rotten non-tin non-corpse food */ STATIC_OVL void fprefx(otmp) struct obj *otmp; { switch(otmp->otyp) { case FOOD_RATION: if(u.uhunger <= 200) pline(Hallucination ? "Oh wow, like, superior, man!" : "That food really hit the spot!"); else if(u.uhunger <= 700) pline("That satiated your %s!", body_part(STOMACH)); break; case TRIPE_RATION: if (carnivorous(youmonst.data) && !humanoid(youmonst.data)) pline("That tripe ration was surprisingly good!"); else if (maybe_polyd(is_orc(youmonst.data), Race_if(PM_ORC))) pline(Hallucination ? "Tastes great! Less filling!" : "Mmm, tripe... not bad!"); else { pline("Yak - dog food!"); more_experienced(1,0); newexplevel(); /* not cannibalism, but we use similar criteria for deciding whether to be sickened by this meal */ if (rn2(2) && !CANNIBAL_ALLOWED()) make_vomiting((long)rn1(victual.reqtime, 14), FALSE); } break; case MEATBALL: case MEAT_STICK: case HUGE_CHUNK_OF_MEAT: case MEAT_RING: goto give_feedback; /* break; */ case CLOVE_OF_GARLIC: if (is_undead(youmonst.data)) { make_vomiting((long)rn1(victual.reqtime, 5), FALSE); break; } /* Fall through otherwise */ default: if (otmp->otyp==SLIME_MOLD && !otmp->cursed && otmp->spe == current_fruit) pline("My, that was a %s %s!", Hallucination ? "primo" : "yummy", singular(otmp, xname)); else #ifdef UNIX if (otmp->otyp == APPLE || otmp->otyp == PEAR) { if (!Hallucination) pline("Core dumped."); else { /* This is based on an old Usenet joke, a fake a.out manual page */ int x = rnd(100); if (x <= 75) pline("Segmentation fault -- core dumped."); else if (x <= 99) pline("Bus error -- core dumped."); else pline("Yo' mama -- core dumped."); } } else #endif #ifdef MAC /* KMH -- Why should Unix have all the fun? */ if (otmp->otyp == APPLE) { pline("Delicious! Must be a Macintosh!"); } else #endif if (otmp->otyp == EGG && stale_egg(otmp)) { pline("Ugh. Rotten egg."); /* perhaps others like it */ make_vomiting(Vomiting+d(10,4), TRUE); } else give_feedback: pline("This %s is %s", singular(otmp, xname), otmp->cursed ? (Hallucination ? "grody!" : "terrible!") : (otmp->otyp == CRAM_RATION || otmp->otyp == K_RATION || otmp->otyp == C_RATION) ? "bland." : Hallucination ? "gnarly!" : "delicious!"); break; } } STATIC_OVL void accessory_has_effect(otmp) struct obj *otmp; { pline("Magic spreads through your body as you digest the %s.", otmp->oclass == RING_CLASS ? "ring" : "amulet"); } STATIC_OVL void eataccessory(otmp) struct obj *otmp; { int typ = otmp->otyp; long oldprop; /* Note: rings are not so common that this is unbalancing. */ /* (How often do you even _find_ 3 rings of polymorph in a game?) */ oldprop = u.uprops[objects[typ].oc_oprop].intrinsic; if (otmp == uleft || otmp == uright) { Ring_gone(otmp); if (u.uhp <= 0) return; /* died from sink fall */ } otmp->known = otmp->dknown = 1; /* by taste */ if (!rn2(otmp->oclass == RING_CLASS ? 3 : 5)) { switch (otmp->otyp) { default: if (!objects[typ].oc_oprop) break; /* should never happen */ if (!(u.uprops[objects[typ].oc_oprop].intrinsic & FROMOUTSIDE)) accessory_has_effect(otmp); u.uprops[objects[typ].oc_oprop].intrinsic |= FROMOUTSIDE; switch (typ) { case RIN_SEE_INVISIBLE: set_mimic_blocking(); see_monsters(); if (Invis && !oldprop && !ESee_invisible && !perceives(youmonst.data) && !Blind) { newsym(u.ux,u.uy); pline("Suddenly you can see yourself."); makeknown(typ); } break; case RIN_INVISIBILITY: if (!oldprop && !EInvis && !BInvis && !See_invisible && !Blind) { newsym(u.ux,u.uy); Your("body takes on a %s transparency...", Hallucination ? "normal" : "strange"); makeknown(typ); } break; case RIN_PROTECTION_FROM_SHAPE_CHAN: rescham(); break; case RIN_LEVITATION: /* undo the `.intrinsic |= FROMOUTSIDE' done above */ u.uprops[LEVITATION].intrinsic = oldprop; if (!Levitation) { float_up(); incr_itimeout(&HLevitation, d(10,20)); makeknown(typ); } break; } break; case RIN_ADORNMENT: accessory_has_effect(otmp); if (adjattrib(A_CHA, otmp->spe, -1)) makeknown(typ); break; case RIN_GAIN_STRENGTH: accessory_has_effect(otmp); if (adjattrib(A_STR, otmp->spe, -1)) makeknown(typ); break; case RIN_GAIN_CONSTITUTION: accessory_has_effect(otmp); if (adjattrib(A_CON, otmp->spe, -1)) makeknown(typ); break; case RIN_INCREASE_ACCURACY: accessory_has_effect(otmp); u.uhitinc += otmp->spe; break; case RIN_INCREASE_DAMAGE: accessory_has_effect(otmp); u.udaminc += otmp->spe; break; case RIN_PROTECTION: accessory_has_effect(otmp); HProtection |= FROMOUTSIDE; u.ublessed += otmp->spe; flags.botl = 1; break; case RIN_FREE_ACTION: /* Give sleep resistance instead */ if (!(HSleep_resistance & FROMOUTSIDE)) accessory_has_effect(otmp); if (!Sleep_resistance) You_feel("wide awake."); HSleep_resistance |= FROMOUTSIDE; break; case AMULET_OF_CHANGE: accessory_has_effect(otmp); makeknown(typ); change_sex(); You("are suddenly very %s!", flags.female ? "feminine" : "masculine"); flags.botl = 1; break; case AMULET_OF_UNCHANGING: /* un-change: it's a pun */ if (!Unchanging && Upolyd) { accessory_has_effect(otmp); makeknown(typ); rehumanize(); } break; case AMULET_OF_STRANGULATION: /* bad idea! */ /* no message--this gives no permanent effect */ choke(otmp); break; case AMULET_OF_RESTFUL_SLEEP: /* another bad idea! */ if (!(HSleeping & FROMOUTSIDE)) accessory_has_effect(otmp); HSleeping = FROMOUTSIDE | rnd(100); break; case RIN_SUSTAIN_ABILITY: case AMULET_OF_LIFE_SAVING: case AMULET_OF_REFLECTION: /* nice try */ /* can't eat Amulet of Yendor or fakes, * and no oc_prop even if you could -3. */ break; } } } STATIC_OVL void eatspecial() /* called after eating non-food */ { register struct obj *otmp = victual.piece; /* lesshungry wants an occupation to handle choke messages correctly */ set_occupation(eatfood, "eating non-food", 0); lesshungry(victual.nmod); occupation = 0; victual.piece = (struct obj *)0; victual.eating = 0; if (otmp->oclass == COIN_CLASS) { #ifdef GOLDOBJ if (carried(otmp)) useupall(otmp); #else if (otmp->where == OBJ_FREE) dealloc_obj(otmp); #endif else useupf(otmp, otmp->quan); return; } if (otmp->oclass == POTION_CLASS) { otmp->quan++; /* dopotion() does a useup() */ (void)dopotion(otmp); } if (otmp->oclass == RING_CLASS || otmp->oclass == AMULET_CLASS) eataccessory(otmp); else if (otmp->otyp == LEASH && otmp->leashmon) o_unleash(otmp); /* KMH -- idea by "Tommy the Terrorist" */ if ((otmp->otyp == TRIDENT) && !otmp->cursed) { pline(Hallucination ? "Four out of five dentists agree." : "That was pure chewing satisfaction!"); exercise(A_WIS, TRUE); } if ((otmp->otyp == FLINT) && !otmp->cursed) { pline("Yabba-dabba delicious!"); exercise(A_CON, TRUE); } if (otmp == uwep && otmp->quan == 1L) uwepgone(); if (otmp == uquiver && otmp->quan == 1L) uqwepgone(); if (otmp == uswapwep && otmp->quan == 1L) uswapwepgone(); if (otmp == uball) unpunish(); if (otmp == uchain) unpunish(); /* but no useup() */ else if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); } /* NOTE: the order of these words exactly corresponds to the order of oc_material values #define'd in objclass.h. */ static const char *foodwords[] = { "meal", "liquid", "wax", "food", "meat", "paper", "cloth", "leather", "wood", "bone", "scale", "metal", "metal", "metal", "silver", "gold", "platinum", "mithril", "plastic", "glass", "rich food", "stone" }; STATIC_OVL const char * foodword(otmp) register struct obj *otmp; { if (otmp->oclass == FOOD_CLASS) return "food"; if (otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material == GLASS && otmp->dknown) makeknown(otmp->otyp); return foodwords[objects[otmp->otyp].oc_material]; } STATIC_OVL void fpostfx(otmp) /* called after consuming (non-corpse) food */ register struct obj *otmp; { switch(otmp->otyp) { case SPRIG_OF_WOLFSBANE: if (u.ulycn >= LOW_PM || is_were(youmonst.data)) you_unwere(TRUE); break; case CARROT: make_blinded((long)u.ucreamed,TRUE); break; case FORTUNE_COOKIE: outrumor(bcsign(otmp), BY_COOKIE); if (!Blind) u.uconduct.literate++; break; case LUMP_OF_ROYAL_JELLY: /* This stuff seems to be VERY healthy! */ gainstr(otmp, 1); if (Upolyd) { u.mh += otmp->cursed ? -rnd(20) : rnd(20); if (u.mh > u.mhmax) { if (!rn2(17)) u.mhmax++; u.mh = u.mhmax; } else if (u.mh <= 0) { rehumanize(); } } else { u.uhp += otmp->cursed ? -rnd(20) : rnd(20); if (u.uhp > u.uhpmax) { if(!rn2(17)) u.uhpmax++; u.uhp = u.uhpmax; } else if (u.uhp <= 0) { killer_format = KILLED_BY_AN; killer = "rotten lump of royal jelly"; done(POISONING); } } if(!otmp->cursed) heal_legs(); break; case EGG: if (touch_petrifies(&mons[otmp->corpsenm])) { if (!Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { if (!Stoned) Stoned = 5; killer_format = KILLED_BY_AN; Sprintf(killer_buf, "%s egg", mons[otmp->corpsenm].mname); delayed_killer = killer_buf; } } break; case EUCALYPTUS_LEAF: if (Sick && !otmp->cursed) make_sick(0L, (char *)0, TRUE, SICK_ALL); if (Vomiting && !otmp->cursed) make_vomiting(0L, TRUE); break; } return; } /* * return 0 if the food was not dangerous. * return 1 if the food was dangerous and you chose to stop. * return 2 if the food was dangerous and you chose to eat it anyway. */ STATIC_OVL int edibility_prompts(otmp) struct obj *otmp; { /* blessed food detection granted you a one-use ability to detect food that is unfit for consumption or dangerous and avoid it. */ char buf[BUFSZ], foodsmell[BUFSZ], it_or_they[QBUFSZ], eat_it_anyway[QBUFSZ]; boolean cadaver = (otmp->otyp == CORPSE), stoneorslime = FALSE; int material = objects[otmp->otyp].oc_material, mnum = otmp->corpsenm; long rotted = 0L; Strcpy(foodsmell, Tobjnam(otmp, "smell")); Strcpy(it_or_they, (otmp->quan == 1L) ? "it" : "they"); Sprintf(eat_it_anyway, "Eat %s anyway?", (otmp->quan == 1L) ? "it" : "one"); if (cadaver || otmp->otyp == EGG || otmp->otyp == TIN) { /* These checks must match those in eatcorpse() */ stoneorslime = (touch_petrifies(&mons[mnum]) && !Stone_resistance && !poly_when_stoned(youmonst.data)); if (mnum == PM_GREEN_SLIME) stoneorslime = (!Unchanging && !flaming(youmonst.data) && youmonst.data != &mons[PM_GREEN_SLIME]); if (cadaver && mnum != PM_LIZARD && mnum != PM_LICHEN) { long age = peek_at_iced_corpse_age(otmp); /* worst case rather than random in this calculation to force prompt */ rotted = (monstermoves - age)/(10L + 0 /* was rn2(20) */); if (otmp->cursed) rotted += 2L; else if (otmp->blessed) rotted -= 2L; } } /* * These problems with food should be checked in * order from most detrimental to least detrimental. */ if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && !Sick_resistance) { /* Tainted meat */ Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (stoneorslime) { Sprintf(buf, "%s like %s could be something very dangerous! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (otmp->orotten || (cadaver && rotted > 3L)) { /* Rotten */ Sprintf(buf, "%s like %s could be rotten! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (cadaver && poisonous(&mons[mnum]) && !Poison_resistance) { /* poisonous */ Sprintf(buf, "%s like %s might be poisonous! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (cadaver && !vegetarian(&mons[mnum]) && !u.uconduct.unvegetarian && Role_if(PM_MONK)) { Sprintf(buf, "%s unhealthy. %s", foodsmell, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (cadaver && acidic(&mons[mnum]) && !Acid_resistance) { Sprintf(buf, "%s rather acidic. %s", foodsmell, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (Upolyd && u.umonnum == PM_RUST_MONSTER && is_metallic(otmp) && otmp->oerodeproof) { Sprintf(buf, "%s disgusting to you right now. %s", foodsmell, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } /* * Breaks conduct, but otherwise safe. */ if (!u.uconduct.unvegan && ((material == LEATHER || material == BONE || material == DRAGON_HIDE || material == WAX) || (cadaver && !vegan(&mons[mnum])))) { Sprintf(buf, "%s foul and unfamiliar to you. %s", foodsmell, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (!u.uconduct.unvegetarian && ((material == LEATHER || material == BONE || material == DRAGON_HIDE) || (cadaver && !vegetarian(&mons[mnum])))) { Sprintf(buf, "%s unfamiliar to you. %s", foodsmell, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } if (cadaver && mnum != PM_ACID_BLOB && rotted > 5L && Sick_resistance) { /* Tainted meat with Sick_resistance */ Sprintf(buf, "%s like %s could be tainted! %s", foodsmell, it_or_they, eat_it_anyway); if (yn_function(buf,ynchars,'n')=='n') return 1; else return 2; } return 0; } int doeat() /* generic "eat" command funtion (see cmd.c) */ { register struct obj *otmp; int basenutrit; /* nutrition of full item */ boolean dont_start = FALSE; if (Strangled) { pline("If you can't breathe air, how can you consume solids?"); return 0; } if (!(otmp = floorfood("eat", 0))) return 0; if (check_capacity((char *)0)) return 0; if (u.uedibility) { int res = edibility_prompts(otmp); if (res) { Your("%s stops tingling and your sense of smell returns to normal.", body_part(NOSE)); u.uedibility = 0; if (res == 1) return 0; } } /* We have to make non-foods take 1 move to eat, unless we want to * do ridiculous amounts of coding to deal with partly eaten plate * mails, players who polymorph back to human in the middle of their * metallic meal, etc.... */ if (!is_edible(otmp)) { You("cannot eat that!"); return 0; } else if ((otmp->owornmask & (W_ARMOR|W_TOOL|W_AMUL #ifdef STEED |W_SADDLE #endif )) != 0) { /* let them eat rings */ You_cant("eat %s you're wearing.", something); return 0; } if (is_metallic(otmp) && u.umonnum == PM_RUST_MONSTER && otmp->oerodeproof) { otmp->rknown = TRUE; if (otmp->quan > 1L) { if(!carried(otmp)) (void) splitobj(otmp, otmp->quan - 1L); else otmp = splitobj(otmp, 1L); } pline("Ulch - That %s was rustproofed!", xname(otmp)); /* The regurgitated object's rustproofing is gone now */ otmp->oerodeproof = 0; make_stunned(HStun + rn2(10), TRUE); You("spit %s out onto the %s.", the(xname(otmp)), surface(u.ux, u.uy)); if (carried(otmp)) { freeinv(otmp); dropy(otmp); } stackobj(otmp); return 1; } /* KMH -- Slow digestion is... indigestible */ if (otmp->otyp == RIN_SLOW_DIGESTION) { pline("This ring is indigestible!"); (void) rottenfood(otmp); if (otmp->dknown && !objects[otmp->otyp].oc_name_known && !objects[otmp->otyp].oc_uname) docall(otmp); return (1); } if (otmp->oclass != FOOD_CLASS) { int material; victual.reqtime = 1; victual.piece = otmp; /* Don't split it, we don't need to if it's 1 move */ victual.usedtime = 0; victual.canchoke = (u.uhs == SATIATED); /* Note: gold weighs 1 pt. for each 1000 pieces (see */ /* pickup.c) so gold and non-gold is consistent. */ if (otmp->oclass == COIN_CLASS) basenutrit = ((otmp->quan > 200000L) ? 2000 : (int)(otmp->quan/100L)); else if(otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) basenutrit = weight(otmp); /* oc_nutrition is usually weight anyway */ else basenutrit = objects[otmp->otyp].oc_nutrition; victual.nmod = basenutrit; victual.eating = TRUE; /* needed for lesshungry() */ material = objects[otmp->otyp].oc_material; if (material == LEATHER || material == BONE || material == DRAGON_HIDE) { u.uconduct.unvegan++; violated_vegetarian(); } else if (material == WAX) u.uconduct.unvegan++; u.uconduct.food++; if (otmp->cursed) (void) rottenfood(otmp); if (otmp->oclass == WEAPON_CLASS && otmp->opoisoned) { pline("Ecch - that must have been poisonous!"); if(!Poison_resistance) { losestr(rnd(4)); losehp(rnd(15), xname(otmp), KILLED_BY_AN); } else You("seem unaffected by the poison."); } else if (!otmp->cursed) pline("This %s is delicious!", otmp->oclass == COIN_CLASS ? foodword(otmp) : singular(otmp, xname)); eatspecial(); return 1; } if(otmp == victual.piece) { /* If they weren't able to choke, they don't suddenly become able to * choke just because they were interrupted. On the other hand, if * they were able to choke before, if they lost food it's possible * they shouldn't be able to choke now. */ if (u.uhs != SATIATED) victual.canchoke = FALSE; victual.piece = touchfood(otmp); You("resume your meal."); start_eating(victual.piece); return(1); } /* nothing in progress - so try to find something. */ /* tins are a special case */ /* tins must also check conduct separately in case they're discarded */ if(otmp->otyp == TIN) { start_tin(otmp); return(1); } /* KMH, conduct */ u.uconduct.food++; victual.piece = otmp = touchfood(otmp); victual.usedtime = 0; /* Now we need to calculate delay and nutritional info. * The base nutrition calculated here and in eatcorpse() accounts * for normal vs. rotten food. The reqtime and nutrit values are * then adjusted in accordance with the amount of food left. */ if(otmp->otyp == CORPSE) { int tmp = eatcorpse(otmp); if (tmp == 2) { /* used up */ victual.piece = (struct obj *)0; return(1); } else if (tmp) dont_start = TRUE; /* if not used up, eatcorpse sets up reqtime and may modify * oeaten */ } else { /* No checks for WAX, LEATHER, BONE, DRAGON_HIDE. These are * all handled in the != FOOD_CLASS case, above */ switch (objects[otmp->otyp].oc_material) { case FLESH: u.uconduct.unvegan++; if (otmp->otyp != EGG) { violated_vegetarian(); } break; default: if (otmp->otyp == PANCAKE || otmp->otyp == FORTUNE_COOKIE || /* eggs */ otmp->otyp == CREAM_PIE || otmp->otyp == CANDY_BAR || /* milk */ otmp->otyp == LUMP_OF_ROYAL_JELLY) u.uconduct.unvegan++; break; } victual.reqtime = objects[otmp->otyp].oc_delay; if (otmp->otyp != FORTUNE_COOKIE && (otmp->cursed || (((monstermoves - otmp->age) > (int) otmp->blessed ? 50:30) && (otmp->orotten || !rn2(7))))) { if (rottenfood(otmp)) { otmp->orotten = TRUE; dont_start = TRUE; } consume_oeaten(otmp, 1); /* oeaten >>= 1 */ } else fprefx(otmp); } /* re-calc the nutrition */ if (otmp->otyp == CORPSE) basenutrit = mons[otmp->corpsenm].cnutrit; else basenutrit = objects[otmp->otyp].oc_nutrition; #ifdef DEBUG debugpline("before rounddiv: victual.reqtime == %d", victual.reqtime); debugpline("oeaten == %d, basenutrit == %d", otmp->oeaten, basenutrit); #endif victual.reqtime = (basenutrit == 0 ? 0 : rounddiv(victual.reqtime * (long)otmp->oeaten, basenutrit)); #ifdef DEBUG debugpline("after rounddiv: victual.reqtime == %d", victual.reqtime); #endif /* calculate the modulo value (nutrit. units per round eating) * note: this isn't exact - you actually lose a little nutrition * due to this method. * TODO: add in a "remainder" value to be given at the end of the * meal. */ if (victual.reqtime == 0 || otmp->oeaten == 0) /* possible if most has been eaten before */ victual.nmod = 0; else if ((int)otmp->oeaten >= victual.reqtime) victual.nmod = -((int)otmp->oeaten / victual.reqtime); else victual.nmod = victual.reqtime % otmp->oeaten; victual.canchoke = (u.uhs == SATIATED); if (!dont_start) start_eating(otmp); return(1); } /* Take a single bite from a piece of food, checking for choking and * modifying usedtime. Returns 1 if they choked and survived, 0 otherwise. */ STATIC_OVL int bite() { if(victual.canchoke && u.uhunger >= 2000) { choke(victual.piece); return 1; } if (victual.doreset) { do_reset_eat(); return 0; } force_save_hs = TRUE; if(victual.nmod < 0) { lesshungry(-victual.nmod); consume_oeaten(victual.piece, victual.nmod); /* -= -nmod */ } else if(victual.nmod > 0 && (victual.usedtime % victual.nmod)) { lesshungry(1); consume_oeaten(victual.piece, -1); /* -= 1 */ } force_save_hs = FALSE; recalc_wt(); return 0; } #endif /* OVLB */ #ifdef OVL0 void gethungry() /* as time goes by - called by moveloop() and domove() */ { if (u.uinvulnerable) return; /* you don't feel hungrier */ if ((!u.usleep || !rn2(10)) /* slow metabolic rate while asleep */ && (carnivorous(youmonst.data) || herbivorous(youmonst.data)) && !Slow_digestion) u.uhunger--; /* ordinary food consumption */ if (moves % 2) { /* odd turns */ /* Regeneration uses up food, unless due to an artifact */ if (HRegeneration || ((ERegeneration & (~W_ART)) && (ERegeneration != W_WEP || !uwep->oartifact))) u.uhunger--; if (near_capacity() > SLT_ENCUMBER) u.uhunger--; } else { /* even turns */ if (Hunger) u.uhunger--; /* Conflict uses up food too */ if (HConflict || (EConflict & (~W_ARTI))) u.uhunger--; /* +0 charged rings don't do anything, so don't affect hunger */ /* Slow digestion still uses ring hunger */ switch ((int)(moves % 20)) { /* note: use even cases only */ case 4: if (uleft && (uleft->spe || !objects[uleft->otyp].oc_charged)) u.uhunger--; break; case 8: if (uamul) u.uhunger--; break; case 12: if (uright && (uright->spe || !objects[uright->otyp].oc_charged)) u.uhunger--; break; case 16: if (u.uhave.amulet) u.uhunger--; break; default: break; } } newuhs(TRUE); } #endif /* OVL0 */ #ifdef OVLB void morehungry(num) /* called after vomiting and after performing feats of magic */ register int num; { u.uhunger -= num; newuhs(TRUE); } void lesshungry(num) /* called after eating (and after drinking fruit juice) */ register int num; { /* See comments in newuhs() for discussion on force_save_hs */ boolean iseating = (occupation == eatfood) || force_save_hs; #ifdef DEBUG debugpline("lesshungry(%d)", num); #endif u.uhunger += num; if(u.uhunger >= 2000) { if (!iseating || victual.canchoke) { if (iseating) { choke(victual.piece); reset_eat(); } else choke(occupation == opentin ? tin.tin : (struct obj *)0); /* no reset_eat() */ } } else { /* Have lesshungry() report when you're nearly full so all eating * warns when you're about to choke. */ if (u.uhunger >= 1500) { if (!victual.eating || (victual.eating && !victual.fullwarn)) { pline("You're having a hard time getting all of it down."); nomovemsg = "You're finally finished."; if (!victual.eating) multi = -2; else { victual.fullwarn = TRUE; if (victual.canchoke && victual.reqtime > 1) { /* a one-gulp food will not survive a stop */ if (yn_function("Stop eating?",ynchars,'y')=='y') { reset_eat(); nomovemsg = (char *)0; } } } } } } newuhs(FALSE); } STATIC_PTR int unfaint() { (void) Hear_again(); if(u.uhs > FAINTING) u.uhs = FAINTING; stop_occupation(); flags.botl = 1; return 0; } #endif /* OVLB */ #ifdef OVL0 boolean is_fainted() { return((boolean)(u.uhs == FAINTED)); } void reset_faint() /* call when a faint must be prematurely terminated */ { if(is_fainted()) nomul(0); } #if 0 void sync_hunger() { if(is_fainted()) { flags.soundok = 0; nomul(-10+(u.uhunger/10)); nomovemsg = "You regain consciousness."; afternmv = unfaint; } } #endif void newuhs(incr) /* compute and comment on your (new?) hunger status */ boolean incr; { unsigned newhs; static unsigned save_hs; static boolean saved_hs = FALSE; int h = u.uhunger; newhs = (h > 1000) ? SATIATED : (h > 150) ? NOT_HUNGRY : (h > 50) ? HUNGRY : (h > 0) ? WEAK : FAINTING; /* While you're eating, you may pass from WEAK to HUNGRY to NOT_HUNGRY. * This should not produce the message "you only feel hungry now"; * that message should only appear if HUNGRY is an endpoint. Therefore * we check to see if we're in the middle of eating. If so, we save * the first hunger status, and at the end of eating we decide what * message to print based on the _entire_ meal, not on each little bit. */ /* It is normally possible to check if you are in the middle of a meal * by checking occupation == eatfood, but there is one special case: * start_eating() can call bite() for your first bite before it * sets the occupation. * Anyone who wants to get that case to work _without_ an ugly static * force_save_hs variable, feel free. */ /* Note: If you become a certain hunger status in the middle of the * meal, and still have that same status at the end of the meal, * this will incorrectly print the associated message at the end of * the meal instead of the middle. Such a case is currently * impossible, but could become possible if a message for SATIATED * were added or if HUNGRY and WEAK were separated by a big enough * gap to fit two bites. */ if (occupation == eatfood || force_save_hs) { if (!saved_hs) { save_hs = u.uhs; saved_hs = TRUE; } u.uhs = newhs; return; } else { if (saved_hs) { u.uhs = save_hs; saved_hs = FALSE; } } if(newhs == FAINTING) { if(is_fainted()) newhs = FAINTED; if(u.uhs <= WEAK || rn2(20-u.uhunger/10) >= 19) { if(!is_fainted() && multi >= 0 /* %% */) { /* stop what you're doing, then faint */ stop_occupation(); You("faint from lack of food."); flags.soundok = 0; nomul(-10+(u.uhunger/10)); nomovemsg = "You regain consciousness."; afternmv = unfaint; newhs = FAINTED; } } else if(u.uhunger < -(int)(200 + 20*ACURR(A_CON))) { u.uhs = STARVED; flags.botl = 1; bot(); You("die from starvation."); killer_format = KILLED_BY; killer = "starvation"; done(STARVING); /* if we return, we lifesaved, and that calls newuhs */ return; } } if(newhs != u.uhs) { if(newhs >= WEAK && u.uhs < WEAK) losestr(1); /* this may kill you -- see below */ else if(newhs < WEAK && u.uhs >= WEAK) losestr(-1); switch(newhs){ case HUNGRY: if (Hallucination) { You((!incr) ? "now have a lesser case of the munchies." : "are getting the munchies."); } else You((!incr) ? "only feel hungry now." : (u.uhunger < 145) ? "feel hungry." : "are beginning to feel hungry."); if (incr && occupation && (occupation != eatfood && occupation != opentin)) stop_occupation(); break; case WEAK: if (Hallucination) pline((!incr) ? "You still have the munchies." : "The munchies are interfering with your motor capabilities."); else if (incr && (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE))) pline("%s needs food, badly!", (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m : "Elf"); else You((!incr) ? "feel weak now." : (u.uhunger < 45) ? "feel weak." : "are beginning to feel weak."); if (incr && occupation && (occupation != eatfood && occupation != opentin)) stop_occupation(); break; } u.uhs = newhs; flags.botl = 1; bot(); if ((Upolyd ? u.mh : u.uhp) < 1) { You("die from hunger and exhaustion."); killer_format = KILLED_BY; killer = "exhaustion"; done(STARVING); return; } } } #endif /* OVL0 */ #ifdef OVLB /* Returns an object representing food. Object may be either on floor or * in inventory. */ struct obj * floorfood(verb,corpsecheck) /* get food from floor or pack */ const char *verb; int corpsecheck; /* 0, no check, 1, corpses, 2, tinnable corpses */ { register struct obj *otmp; char qbuf[QBUFSZ]; char c; boolean feeding = (!strcmp(verb, "eat")); /* if we can't touch floor objects then use invent food only */ if (!can_reach_floor() || #ifdef STEED (feeding && u.usteed) || /* can't eat off floor while riding */ #endif ((is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) && (Wwalking || is_clinger(youmonst.data) || (Flying && !Breathless)))) goto skipfloor; if (feeding && metallivorous(youmonst.data)) { struct obj *gold; struct trap *ttmp = t_at(u.ux, u.uy); if (ttmp && ttmp->tseen && ttmp->ttyp == BEAR_TRAP) { /* If not already stuck in the trap, perhaps there should be a chance to becoming trapped? Probably not, because then the trap would just get eaten on the _next_ turn... */ Sprintf(qbuf, "There is a bear trap here (%s); eat it?", (u.utrap && u.utraptype == TT_BEARTRAP) ? "holding you" : "armed"); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { u.utrap = u.utraptype = 0; deltrap(ttmp); return mksobj(BEARTRAP, TRUE, FALSE); } else if (c == 'q') { return (struct obj *)0; } } if (youmonst.data != &mons[PM_RUST_MONSTER] && (gold = g_at(u.ux, u.uy)) != 0) { if (gold->quan == 1L) Sprintf(qbuf, "There is 1 gold piece here; eat it?"); else Sprintf(qbuf, "There are %ld gold pieces here; eat them?", gold->quan); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { return gold; } else if (c == 'q') { return (struct obj *)0; } } } /* Is there some food (probably a heavy corpse) here on the ground? */ for (otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { if(corpsecheck ? (otmp->otyp==CORPSE && (corpsecheck == 1 || tinnable(otmp))) : feeding ? (otmp->oclass != COIN_CLASS && is_edible(otmp)) : otmp->oclass==FOOD_CLASS) { Sprintf(qbuf, "There %s %s here; %s %s?", otense(otmp, "are"), doname(otmp), verb, (otmp->quan == 1L) ? "it" : "one"); if((c = yn_function(qbuf,ynqchars,'n')) == 'y') return(otmp); else if(c == 'q') return((struct obj *) 0); } } skipfloor: /* We cannot use ALL_CLASSES since that causes getobj() to skip its * "ugly checks" and we need to check for inedible items. */ otmp = getobj(feeding ? (const char *)allobj : (const char *)comestibles, verb); if (corpsecheck && otmp) if (otmp->otyp != CORPSE || (corpsecheck == 2 && !tinnable(otmp))) { You_cant("%s that!", verb); return (struct obj *)0; } return otmp; } /* Side effects of vomiting */ /* added nomul (MRS) - it makes sense, you're too busy being sick! */ void vomit() /* A good idea from David Neves */ { make_sick(0L, (char *) 0, TRUE, SICK_VOMITABLE); nomul(-2); } int eaten_stat(base, obj) register int base; register struct obj *obj; { long uneaten_amt, full_amount; uneaten_amt = (long)obj->oeaten; full_amount = (obj->otyp == CORPSE) ? (long)mons[obj->corpsenm].cnutrit : (long)objects[obj->otyp].oc_nutrition; if (uneaten_amt > full_amount) { impossible( "partly eaten food (%ld) more nutritious than untouched food (%ld)", uneaten_amt, full_amount); uneaten_amt = full_amount; } base = (int)(full_amount ? (long)base * uneaten_amt / full_amount : 0L); return (base < 1) ? 1 : base; } /* reduce obj's oeaten field, making sure it never hits or passes 0 */ void consume_oeaten(obj, amt) struct obj *obj; int amt; { /* * This is a hack to try to squelch several long standing mystery * food bugs. A better solution would be to rewrite the entire * victual handling mechanism from scratch using a less complex * model. Alternatively, this routine could call done_eating() * or food_disappears() but its callers would need revisions to * cope with victual.piece unexpectedly going away. * * Multi-turn eating operates by setting the food's oeaten field * to its full nutritional value and then running a counter which * independently keeps track of whether there is any food left. * The oeaten field can reach exactly zero on the last turn, and * the object isn't removed from inventory until the next turn * when the "you finish eating" message gets delivered, so the * food would be restored to the status of untouched during that * interval. This resulted in unexpected encumbrance messages * at the end of a meal (if near enough to a threshold) and would * yield full food if there was an interruption on the critical * turn. Also, there have been reports over the years of food * becoming massively heavy or producing unlimited satiation; * this would occur if reducing oeaten via subtraction attempted * to drop it below 0 since its unsigned type would produce a * huge positive value instead. So far, no one has figured out * _why_ that inappropriate subtraction might sometimes happen. */ if (amt > 0) { /* bit shift to divide the remaining amount of food */ obj->oeaten >>= amt; } else { /* simple decrement; value is negative so we actually add it */ if ((int) obj->oeaten > -amt) obj->oeaten += amt; else obj->oeaten = 0; } if (obj->oeaten == 0) { if (obj == victual.piece) /* always true unless wishing... */ victual.reqtime = victual.usedtime; /* no bites left */ obj->oeaten = 1; /* smallest possible positive value */ } } #endif /* OVLB */ #ifdef OVL1 /* called when eatfood occupation has been interrupted, or in the case of theft, is about to be interrupted */ boolean maybe_finished_meal(stopping) boolean stopping; { /* in case consume_oeaten() has decided that the food is all gone */ if (occupation == eatfood && victual.usedtime >= victual.reqtime) { if (stopping) occupation = 0; /* for do_reset_eat */ (void) eatfood(); /* calls done_eating() to use up victual.piece */ return TRUE; } return FALSE; } #endif /* OVL1 */ /*eat.c*/ nethack-3.4.3/src/end.c0100644000000000000000000007265107764735041013366 0ustar rootroot/* SCCS Id: @(#)end.c 3.4 2003/03/10 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #define NEED_VARARGS /* comment line for pre-compiled headers */ #include "hack.h" #include "eshk.h" #ifndef NO_SIGNAL #include #endif #include "dlb.h" /* these probably ought to be generated by makedefs, like LAST_GEM */ #define FIRST_GEM DILITHIUM_CRYSTAL #define FIRST_AMULET AMULET_OF_ESP #define LAST_AMULET AMULET_OF_YENDOR struct valuable_data { long count; int typ; }; static struct valuable_data gems[LAST_GEM+1 - FIRST_GEM + 1], /* 1 extra for glass */ amulets[LAST_AMULET+1 - FIRST_AMULET]; static struct val_list { struct valuable_data *list; int size; } valuables[] = { { gems, sizeof gems / sizeof *gems }, { amulets, sizeof amulets / sizeof *amulets }, { 0, 0 } }; #ifndef NO_SIGNAL STATIC_PTR void FDECL(done_intr, (int)); # if defined(UNIX) || defined(VMS) || defined (__EMX__) static void FDECL(done_hangup, (int)); # endif #endif STATIC_DCL void FDECL(disclose,(int,BOOLEAN_P)); STATIC_DCL void FDECL(get_valuables, (struct obj *)); STATIC_DCL void FDECL(sort_valuables, (struct valuable_data *,int)); STATIC_DCL void FDECL(artifact_score, (struct obj *,BOOLEAN_P,winid)); STATIC_DCL void FDECL(savelife, (int)); STATIC_DCL void FDECL(list_vanquished, (CHAR_P,BOOLEAN_P)); STATIC_DCL void FDECL(list_genocided, (CHAR_P,BOOLEAN_P)); STATIC_DCL boolean FDECL(should_query_disclose_option, (int,char *)); #if defined(__BEOS__) || defined(MICRO) || defined(WIN32) || defined(OS2) extern void FDECL(nethack_exit,(int)); #else #define nethack_exit exit #endif #define done_stopprint program_state.stopprint #ifdef AMIGA # define NH_abort() Abort(0) #else # ifdef SYSV # define NH_abort() (void) abort() # else # ifdef WIN32 # define NH_abort() win32_abort() # else # define NH_abort() abort() # endif # endif #endif /* * The order of these needs to match the macros in hack.h. */ static NEARDATA const char *deaths[] = { /* the array of death */ "died", "choked", "poisoned", "starvation", "drowning", "burning", "dissolving under the heat and pressure", "crushed", "turned to stone", "turned into slime", "genocided", "panic", "trickery", "quit", "escaped", "ascended" }; static NEARDATA const char *ends[] = { /* "when you..." */ "died", "choked", "were poisoned", "starved", "drowned", "burned", "dissolved in the lava", "were crushed", "turned to stone", "turned into slime", "were genocided", "panicked", "were tricked", "quit", "escaped", "ascended" }; extern const char * const killed_by_prefix[]; /* from topten.c */ /*ARGSUSED*/ void done1(sig_unused) /* called as signal() handler, so sent at least one arg */ int sig_unused; { #ifndef NO_SIGNAL (void) signal(SIGINT,SIG_IGN); #endif if(flags.ignintr) { #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif clear_nhwindow(WIN_MESSAGE); curs_on_u(); wait_synch(); if(multi > 0) nomul(0); } else { (void)done2(); } } /* "#quit" command or keyboard interrupt */ int done2() { if(yn("Really quit?") == 'n') { #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif clear_nhwindow(WIN_MESSAGE); curs_on_u(); wait_synch(); if(multi > 0) nomul(0); if(multi == 0) { u.uinvulnerable = FALSE; /* avoid ctrl-C bug -dlc */ u.usleep = 0; } return 0; } #if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE)) if(wizard) { int c; # ifdef VMS const char *tmp = "Enter debugger?"; # else # ifdef LATTICE const char *tmp = "Create SnapShot?"; # else const char *tmp = "Dump core?"; # endif # endif if ((c = ynq(tmp)) == 'y') { (void) signal(SIGINT, (SIG_RET_TYPE) done1); exit_nhwindows((char *)0); NH_abort(); } else if (c == 'q') done_stopprint++; } #endif #ifndef LINT done(QUIT); #endif return 0; } #ifndef NO_SIGNAL /*ARGSUSED*/ STATIC_PTR void done_intr(sig_unused) /* called as signal() handler, so sent at least one arg */ int sig_unused; { done_stopprint++; (void) signal(SIGINT, SIG_IGN); # if defined(UNIX) || defined(VMS) (void) signal(SIGQUIT, SIG_IGN); # endif return; } # if defined(UNIX) || defined(VMS) || defined(__EMX__) static void done_hangup(sig) /* signal() handler */ int sig; { program_state.done_hup++; (void)signal(SIGHUP, SIG_IGN); done_intr(sig); return; } # endif #endif /* NO_SIGNAL */ void done_in_by(mtmp) register struct monst *mtmp; { char buf[BUFSZ]; boolean distorted = (boolean)(Hallucination && canspotmon(mtmp)); You("die..."); mark_synch(); /* flush buffered screen output */ buf[0] = '\0'; killer_format = KILLED_BY_AN; /* "killed by the high priest of Crom" is okay, "killed by the high priest" alone isn't */ if ((mtmp->data->geno & G_UNIQ) != 0 && !(mtmp->data == &mons[PM_HIGH_PRIEST] && !mtmp->ispriest)) { if (!type_is_pname(mtmp->data)) Strcat(buf, "the "); killer_format = KILLED_BY; } /* _the_ ghost of Dudley */ if (mtmp->data == &mons[PM_GHOST] && mtmp->mnamelth) { Strcat(buf, "the "); killer_format = KILLED_BY; } if (mtmp->minvis) Strcat(buf, "invisible "); if (distorted) Strcat(buf, "hallucinogen-distorted "); if(mtmp->data == &mons[PM_GHOST]) { Strcat(buf, "ghost"); if (mtmp->mnamelth) Sprintf(eos(buf), " of %s", NAME(mtmp)); } else if(mtmp->isshk) { Sprintf(eos(buf), "%s %s, the shopkeeper", (mtmp->female ? "Ms." : "Mr."), shkname(mtmp)); killer_format = KILLED_BY; } else if (mtmp->ispriest || mtmp->isminion) { /* m_monnam() suppresses "the" prefix plus "invisible", and it overrides the effect of Hallucination on priestname() */ killer = m_monnam(mtmp); Strcat(buf, killer); } else { Strcat(buf, mtmp->data->mname); if (mtmp->mnamelth) Sprintf(eos(buf), " called %s", NAME(mtmp)); } if (multi) Strcat(buf, ", while helpless"); killer = buf; if (mtmp->data->mlet == S_WRAITH) u.ugrave_arise = PM_WRAITH; else if (mtmp->data->mlet == S_MUMMY && urace.mummynum != NON_PM) u.ugrave_arise = urace.mummynum; else if (mtmp->data->mlet == S_VAMPIRE && Race_if(PM_HUMAN)) u.ugrave_arise = PM_VAMPIRE; else if (mtmp->data == &mons[PM_GHOUL]) u.ugrave_arise = PM_GHOUL; if (u.ugrave_arise >= LOW_PM && (mvitals[u.ugrave_arise].mvflags & G_GENOD)) u.ugrave_arise = NON_PM; if (touch_petrifies(mtmp->data)) done(STONING); else done(DIED); return; } #if defined(WIN32) #define NOTIFY_NETHACK_BUGS #endif /*VARARGS1*/ void panic VA_DECL(const char *, str) VA_START(str); VA_INIT(str, char *); if (program_state.panicking++) NH_abort(); /* avoid loops - this should never happen*/ if (iflags.window_inited) { raw_print("\r\nOops..."); wait_synch(); /* make sure all pending output gets flushed */ exit_nhwindows((char *)0); iflags.window_inited = 0; /* they're gone; force raw_print()ing */ } raw_print(program_state.gameover ? "Postgame wrapup disrupted." : !program_state.something_worth_saving ? "Program initialization has failed." : "Suddenly, the dungeon collapses."); #if defined(WIZARD) && !defined(MICRO) # if defined(NOTIFY_NETHACK_BUGS) if (!wizard) raw_printf("Report the following error to \"%s\".", "nethack-bugs@nethack.org"); else if (program_state.something_worth_saving) raw_print("\nError save file being written.\n"); # else if (!wizard) raw_printf("Report error to \"%s\"%s.", # ifdef WIZARD_NAME /*(KR1ED)*/ WIZARD_NAME, # else WIZARD, # endif !program_state.something_worth_saving ? "" : " and it may be possible to rebuild."); # endif if (program_state.something_worth_saving) { set_error_savefile(); (void) dosave0(); } #endif { char buf[BUFSZ]; Vsprintf(buf,str,VA_ARGS); raw_print(buf); paniclog("panic", buf); } #ifdef WIN32 interject(INTERJECT_PANIC); #endif #if defined(WIZARD) && (defined(UNIX) || defined(VMS) || defined(LATTICE) || defined(WIN32)) if (wizard) NH_abort(); /* generate core dump */ #endif VA_END(); done(PANICKED); } STATIC_OVL boolean should_query_disclose_option(category, defquery) int category; char *defquery; { int idx; char *dop = index(disclosure_options, category); if (dop && defquery) { idx = dop - disclosure_options; if (idx < 0 || idx > (NUM_DISCLOSURE_OPTIONS - 1)) { impossible( "should_query_disclose_option: bad disclosure index %d %c", idx, category); *defquery = DISCLOSE_PROMPT_DEFAULT_YES; return TRUE; } if (flags.end_disclose[idx] == DISCLOSE_YES_WITHOUT_PROMPT) { *defquery = 'y'; return FALSE; } else if (flags.end_disclose[idx] == DISCLOSE_NO_WITHOUT_PROMPT) { *defquery = 'n'; return FALSE; } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_YES) { *defquery = 'y'; return TRUE; } else if (flags.end_disclose[idx] == DISCLOSE_PROMPT_DEFAULT_NO) { *defquery = 'n'; return TRUE; } } if (defquery) impossible("should_query_disclose_option: bad category %c", category); else impossible("should_query_disclose_option: null defquery"); return TRUE; } STATIC_OVL void disclose(how,taken) int how; boolean taken; { char c = 0, defquery; char qbuf[QBUFSZ]; boolean ask; if (invent) { if(taken) Sprintf(qbuf,"Do you want to see what you had when you %s?", (how == QUIT) ? "quit" : "died"); else Strcpy(qbuf,"Do you want your possessions identified?"); ask = should_query_disclose_option('i', &defquery); if (!done_stopprint) { c = ask ? yn_function(qbuf, ynqchars, defquery) : defquery; if (c == 'y') { struct obj *obj; for (obj = invent; obj; obj = obj->nobj) { makeknown(obj->otyp); obj->known = obj->bknown = obj->dknown = obj->rknown = 1; } (void) display_inventory((char *)0, TRUE); container_contents(invent, TRUE, TRUE); } if (c == 'q') done_stopprint++; } } ask = should_query_disclose_option('a', &defquery); if (!done_stopprint) { c = ask ? yn_function("Do you want to see your attributes?", ynqchars, defquery) : defquery; if (c == 'y') enlightenment(how >= PANICKED ? 1 : 2); /* final */ if (c == 'q') done_stopprint++; } ask = should_query_disclose_option('v', &defquery); if (!done_stopprint) list_vanquished(defquery, ask); ask = should_query_disclose_option('g', &defquery); if (!done_stopprint) list_genocided(defquery, ask); ask = should_query_disclose_option('c', &defquery); if (!done_stopprint) { c = ask ? yn_function("Do you want to see your conduct?", ynqchars, defquery) : defquery; if (c == 'y') show_conduct(how >= PANICKED ? 1 : 2); if (c == 'q') done_stopprint++; } } /* try to get the player back in a viable state after being killed */ STATIC_OVL void savelife(how) int how; { u.uswldtim = 0; u.uhp = u.uhpmax; if (u.uhunger < 500) { u.uhunger = 500; newuhs(FALSE); } /* cure impending doom of sickness hero won't have time to fix */ if ((Sick & TIMEOUT) == 1) { u.usick_type = 0; Sick = 0; } if (how == CHOKING) init_uhunger(); nomovemsg = "You survived that attempt on your life."; flags.move = 0; if(multi > 0) multi = 0; else multi = -1; if(u.utrap && u.utraptype == TT_LAVA) u.utrap = 0; flags.botl = 1; u.ugrave_arise = NON_PM; HUnchanging = 0L; curs_on_u(); } /* * Get valuables from the given list. Revised code: the list always remains * intact. */ STATIC_OVL void get_valuables(list) struct obj *list; /* inventory or container contents */ { register struct obj *obj; register int i; /* find amulets and gems, ignoring all artifacts */ for (obj = list; obj; obj = obj->nobj) if (Has_contents(obj)) { get_valuables(obj->cobj); } else if (obj->oartifact) { continue; } else if (obj->oclass == AMULET_CLASS) { i = obj->otyp - FIRST_AMULET; if (!amulets[i].count) { amulets[i].count = obj->quan; amulets[i].typ = obj->otyp; } else amulets[i].count += obj->quan; /* always adds one */ } else if (obj->oclass == GEM_CLASS && obj->otyp < LUCKSTONE) { i = min(obj->otyp, LAST_GEM + 1) - FIRST_GEM; if (!gems[i].count) { gems[i].count = obj->quan; gems[i].typ = obj->otyp; } else gems[i].count += obj->quan; } return; } /* * Sort collected valuables, most frequent to least. We could just * as easily use qsort, but we don't care about efficiency here. */ STATIC_OVL void sort_valuables(list, size) struct valuable_data list[]; int size; /* max value is less than 20 */ { register int i, j; struct valuable_data ltmp; /* move greater quantities to the front of the list */ for (i = 1; i < size; i++) { if (list[i].count == 0) continue; /* empty slot */ ltmp = list[i]; /* structure copy */ for (j = i; j > 0; --j) if (list[j-1].count >= ltmp.count) break; else { list[j] = list[j-1]; } list[j] = ltmp; } return; } /* called twice; first to calculate total, then to list relevant items */ STATIC_OVL void artifact_score(list, counting, endwin) struct obj *list; boolean counting; /* true => add up points; false => display them */ winid endwin; { char pbuf[BUFSZ]; struct obj *otmp; long value, points; short dummy; /* object type returned by artifact_name() */ for (otmp = list; otmp; otmp = otmp->nobj) { if (otmp->oartifact || otmp->otyp == BELL_OF_OPENING || otmp->otyp == SPE_BOOK_OF_THE_DEAD || otmp->otyp == CANDELABRUM_OF_INVOCATION) { value = arti_cost(otmp); /* zorkmid value */ points = value * 5 / 2; /* score value */ if (counting) { u.urexp += points; } else { makeknown(otmp->otyp); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; /* assumes artifacts don't have quan > 1 */ Sprintf(pbuf, "%s%s (worth %ld %s and %ld points)", the_unique_obj(otmp) ? "The " : "", otmp->oartifact ? artifact_name(xname(otmp), &dummy) : OBJ_NAME(objects[otmp->otyp]), value, currency(value), points); putstr(endwin, 0, pbuf); } } if (Has_contents(otmp)) artifact_score(otmp->cobj, counting, endwin); } } /* Be careful not to call panic from here! */ void done(how) int how; { boolean taken; char kilbuf[BUFSZ], pbuf[BUFSZ]; winid endwin = WIN_ERR; boolean bones_ok, have_windows = iflags.window_inited; struct obj *corpse = (struct obj *)0; long umoney; if (how == TRICKED) { if (killer) { paniclog("trickery", killer); killer = 0; } #ifdef WIZARD if (wizard) { You("are a very tricky wizard, it seems."); return; } #endif } /* kilbuf: used to copy killer in case it comes from something like * xname(), which would otherwise get overwritten when we call * xname() when listing possessions * pbuf: holds Sprintf'd output for raw_print and putstr */ if (how == ASCENDED || (!killer && how == GENOCIDED)) killer_format = NO_KILLER_PREFIX; /* Avoid killed by "a" burning or "a" starvation */ if (!killer && (how == STARVING || how == BURNING)) killer_format = KILLED_BY; Strcpy(kilbuf, (!killer || how >= PANICKED ? deaths[how] : killer)); killer = kilbuf; if (how < PANICKED) u.umortality++; if (Lifesaved && (how <= GENOCIDED)) { pline("But wait..."); makeknown(AMULET_OF_LIFE_SAVING); Your("medallion %s!", !Blind ? "begins to glow" : "feels warm"); if (how == CHOKING) You("vomit ..."); You_feel("much better!"); pline_The("medallion crumbles to dust!"); if (uamul) useup(uamul); (void) adjattrib(A_CON, -1, TRUE); if(u.uhpmax <= 0) u.uhpmax = 10; /* arbitrary */ savelife(how); if (how == GENOCIDED) pline("Unfortunately you are still genocided..."); else { killer = 0; killer_format = 0; return; } } if (( #ifdef WIZARD wizard || #endif discover) && (how <= GENOCIDED)) { if(yn("Die?") == 'y') goto die; pline("OK, so you don't %s.", (how == CHOKING) ? "choke" : "die"); if(u.uhpmax <= 0) u.uhpmax = u.ulevel * 8; /* arbitrary */ savelife(how); killer = 0; killer_format = 0; return; } /* * The game is now over... */ die: program_state.gameover = 1; /* in case of a subsequent panic(), there's no point trying to save */ program_state.something_worth_saving = 0; /* render vision subsystem inoperative */ iflags.vision_inited = 0; /* might have been killed while using a disposable item, so make sure it's gone prior to inventory disclosure and creation of bones data */ inven_inuse(TRUE); /* Sometimes you die on the first move. Life's not fair. * On those rare occasions you get hosed immediately, go out * smiling... :-) -3. */ if (moves <= 1 && how < PANICKED) /* You die... --More-- */ pline("Do not pass go. Do not collect 200 %s.", currency(200L)); if (have_windows) wait_synch(); /* flush screen output */ #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done_intr); # if defined(UNIX) || defined(VMS) || defined (__EMX__) (void) signal(SIGQUIT, (SIG_RET_TYPE) done_intr); (void) signal(SIGHUP, (SIG_RET_TYPE) done_hangup); # endif #endif /* NO_SIGNAL */ bones_ok = (how < GENOCIDED) && can_make_bones(); if (how == TURNED_SLIME) u.ugrave_arise = PM_GREEN_SLIME; if (bones_ok && u.ugrave_arise < LOW_PM) { /* corpse gets burnt up too */ if (how == BURNING) u.ugrave_arise = (NON_PM - 2); /* leave no corpse */ else if (how == STONING) u.ugrave_arise = (NON_PM - 1); /* statue instead of corpse */ else if (u.ugrave_arise == NON_PM && !(mvitals[u.umonnum].mvflags & G_NOCORPSE)) { int mnum = u.umonnum; if (!Upolyd) { /* Base corpse on race when not poly'd since original * u.umonnum is based on role, and all role monsters * are human. */ mnum = (flags.female && urace.femalenum != NON_PM) ? urace.femalenum : urace.malenum; } corpse = mk_named_object(CORPSE, &mons[mnum], u.ux, u.uy, plname); Sprintf(pbuf, "%s, %s%s", plname, killer_format == NO_KILLER_PREFIX ? "" : killed_by_prefix[how], killer_format == KILLED_BY_AN ? an(killer) : killer); make_grave(u.ux, u.uy, pbuf); } } if (how == QUIT) { killer_format = NO_KILLER_PREFIX; if (u.uhp < 1) { how = DIED; u.umortality++; /* skipped above when how==QUIT */ /* note that killer is pointing at kilbuf */ Strcpy(kilbuf, "quit while already on Charon's boat"); } } if (how == ESCAPED || how == PANICKED) killer_format = NO_KILLER_PREFIX; if (how != PANICKED) { /* these affect score and/or bones, but avoid them during panic */ taken = paybill((how == ESCAPED) ? -1 : (how != QUIT)); paygd(); clearpriests(); } else taken = FALSE; /* lint; assert( !bones_ok ); */ clearlocks(); if (have_windows) display_nhwindow(WIN_MESSAGE, FALSE); if (strcmp(flags.end_disclose, "none") && how != PANICKED) disclose(how, taken); /* finish_paybill should be called after disclosure but before bones */ if (bones_ok && taken) finish_paybill(); /* calculate score, before creating bones [container gold] */ { long tmp; int deepest = deepest_lev_reached(FALSE); #ifndef GOLDOBJ umoney = u.ugold; tmp = u.ugold0; #else umoney = money_cnt(invent); tmp = u.umoney0; #endif umoney += hidden_gold(); /* accumulate gold from containers */ tmp = umoney - tmp; /* net gain */ if (tmp < 0L) tmp = 0L; if (how < PANICKED) tmp -= tmp / 10L; u.urexp += tmp; u.urexp += 50L * (long)(deepest - 1); if (deepest > 20) u.urexp += 1000L * (long)((deepest > 30) ? 10 : deepest - 20); if (how == ASCENDED) u.urexp *= 2L; } if (bones_ok) { #ifdef WIZARD if (!wizard || yn("Save bones?") == 'y') #endif savebones(corpse); /* corpse may be invalid pointer now so ensure that it isn't used again */ corpse = (struct obj *)0; } /* update gold for the rip output, which can't use hidden_gold() (containers will be gone by then if bones just got saved...) */ #ifndef GOLDOBJ u.ugold = umoney; #else done_money = umoney; #endif /* clean up unneeded windows */ if (have_windows) { wait_synch(); display_nhwindow(WIN_MESSAGE, TRUE); destroy_nhwindow(WIN_MAP); destroy_nhwindow(WIN_STATUS); destroy_nhwindow(WIN_MESSAGE); WIN_MESSAGE = WIN_STATUS = WIN_MAP = WIN_ERR; if(!done_stopprint || flags.tombstone) endwin = create_nhwindow(NHW_TEXT); if (how < GENOCIDED && flags.tombstone && endwin != WIN_ERR) outrip(endwin, how); } else done_stopprint = 1; /* just avoid any more output */ /* changing kilbuf really changes killer. we do it this way because killer is declared a (const char *) */ if (u.uhave.amulet) Strcat(kilbuf, " (with the Amulet)"); else if (how == ESCAPED) { if (Is_astralevel(&u.uz)) /* offered Amulet to wrong deity */ Strcat(kilbuf, " (in celestial disgrace)"); else if (carrying(FAKE_AMULET_OF_YENDOR)) Strcat(kilbuf, " (with a fake Amulet)"); /* don't bother counting to see whether it should be plural */ } if (!done_stopprint) { Sprintf(pbuf, "%s %s the %s...", Goodbye(), plname, how != ASCENDED ? (const char *) ((flags.female && urole.name.f) ? urole.name.f : urole.name.m) : (const char *) (flags.female ? "Demigoddess" : "Demigod")); putstr(endwin, 0, pbuf); putstr(endwin, 0, ""); } if (how == ESCAPED || how == ASCENDED) { register struct monst *mtmp; register struct obj *otmp; register struct val_list *val; register int i; for (val = valuables; val->list; val++) for (i = 0; i < val->size; i++) { val->list[i].count = 0L; } get_valuables(invent); /* add points for collected valuables */ for (val = valuables; val->list; val++) for (i = 0; i < val->size; i++) if (val->list[i].count != 0L) u.urexp += val->list[i].count * (long)objects[val->list[i].typ].oc_cost; /* count the points for artifacts */ artifact_score(invent, TRUE, endwin); keepdogs(TRUE); viz_array[0][0] |= IN_SIGHT; /* need visibility for naming */ mtmp = mydogs; if (!done_stopprint) Strcpy(pbuf, "You"); if (mtmp) { while (mtmp) { if (!done_stopprint) Sprintf(eos(pbuf), " and %s", mon_nam(mtmp)); if (mtmp->mtame) u.urexp += mtmp->mhp; mtmp = mtmp->nmon; } if (!done_stopprint) putstr(endwin, 0, pbuf); pbuf[0] = '\0'; } else { if (!done_stopprint) Strcat(pbuf, " "); } if (!done_stopprint) { Sprintf(eos(pbuf), "%s with %ld point%s,", how==ASCENDED ? "went to your reward" : "escaped from the dungeon", u.urexp, plur(u.urexp)); putstr(endwin, 0, pbuf); } if (!done_stopprint) artifact_score(invent, FALSE, endwin); /* list artifacts */ /* list valuables here */ for (val = valuables; val->list; val++) { sort_valuables(val->list, val->size); for (i = 0; i < val->size && !done_stopprint; i++) { int typ = val->list[i].typ; long count = val->list[i].count; if (count == 0L) continue; if (objects[typ].oc_class != GEM_CLASS || typ <= LAST_GEM) { otmp = mksobj(typ, FALSE, FALSE); makeknown(otmp->otyp); otmp->known = 1; /* for fake amulets */ otmp->dknown = 1; /* seen it (blindness fix) */ otmp->onamelth = 0; otmp->quan = count; Sprintf(pbuf, "%8ld %s (worth %ld %s),", count, xname(otmp), count * (long)objects[typ].oc_cost, currency(2L)); obfree(otmp, (struct obj *)0); } else { Sprintf(pbuf, "%8ld worthless piece%s of colored glass,", count, plur(count)); } putstr(endwin, 0, pbuf); } } } else if (!done_stopprint) { /* did not escape or ascend */ if (u.uz.dnum == 0 && u.uz.dlevel <= 0) { /* level teleported out of the dungeon; `how' is DIED, due to falling or to "arriving at heaven prematurely" */ Sprintf(pbuf, "You %s beyond the confines of the dungeon", (u.uz.dlevel < 0) ? "passed away" : ends[how]); } else { /* more conventional demise */ const char *where = dungeons[u.uz.dnum].dname; if (Is_astralevel(&u.uz)) where = "The Astral Plane"; Sprintf(pbuf, "You %s in %s", ends[how], where); if (!In_endgame(&u.uz) && !Is_knox(&u.uz)) Sprintf(eos(pbuf), " on dungeon level %d", In_quest(&u.uz) ? dunlev(&u.uz) : depth(&u.uz)); } Sprintf(eos(pbuf), " with %ld point%s,", u.urexp, plur(u.urexp)); putstr(endwin, 0, pbuf); } if (!done_stopprint) { Sprintf(pbuf, "and %ld piece%s of gold, after %ld move%s.", umoney, plur(umoney), moves, plur(moves)); putstr(endwin, 0, pbuf); } if (!done_stopprint) { Sprintf(pbuf, "You were level %d with a maximum of %d hit point%s when you %s.", u.ulevel, u.uhpmax, plur(u.uhpmax), ends[how]); putstr(endwin, 0, pbuf); putstr(endwin, 0, ""); } if (!done_stopprint) display_nhwindow(endwin, TRUE); if (endwin != WIN_ERR) destroy_nhwindow(endwin); /* "So when I die, the first thing I will see in Heaven is a * score list?" */ if (flags.toptenwin) { topten(how); if (have_windows) exit_nhwindows((char *)0); } else { if (have_windows) exit_nhwindows((char *)0); topten(how); } if(done_stopprint) { raw_print(""); raw_print(""); } terminate(EXIT_SUCCESS); } void container_contents(list, identified, all_containers) struct obj *list; boolean identified, all_containers; { register struct obj *box, *obj; char buf[BUFSZ]; for (box = list; box; box = box->nobj) { if (Is_container(box) || box->otyp == STATUE) { if (box->otyp == BAG_OF_TRICKS) { continue; /* wrong type of container */ } else if (box->cobj) { winid tmpwin = create_nhwindow(NHW_MENU); Sprintf(buf, "Contents of %s:", the(xname(box))); putstr(tmpwin, 0, buf); putstr(tmpwin, 0, ""); for (obj = box->cobj; obj; obj = obj->nobj) { if (identified) { makeknown(obj->otyp); obj->known = obj->bknown = obj->dknown = obj->rknown = 1; } putstr(tmpwin, 0, doname(obj)); } display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); if (all_containers) container_contents(box->cobj, identified, TRUE); } else { pline("%s empty.", Tobjnam(box, "are")); display_nhwindow(WIN_MESSAGE, FALSE); } } if (!all_containers) break; } } /* should be called with either EXIT_SUCCESS or EXIT_FAILURE */ void terminate(status) int status; { #ifdef MAC getreturn("to exit"); #endif /* don't bother to try to release memory if we're in panic mode, to avoid trouble in case that happens to be due to memory problems */ if (!program_state.panicking) { freedynamicdata(); dlb_cleanup(); } nethack_exit(status); } STATIC_OVL void list_vanquished(defquery, ask) char defquery; boolean ask; { register int i, lev; int ntypes = 0, max_lev = 0, nkilled; long total_killed = 0L; char c; winid klwin; char buf[BUFSZ]; /* get totals first */ for (i = LOW_PM; i < NUMMONS; i++) { if (mvitals[i].died) ntypes++; total_killed += (long)mvitals[i].died; if (mons[i].mlevel > max_lev) max_lev = mons[i].mlevel; } /* vanquished creatures list; * includes all dead monsters, not just those killed by the player */ if (ntypes != 0) { c = ask ? yn_function("Do you want an account of creatures vanquished?", ynqchars, defquery) : defquery; if (c == 'q') done_stopprint++; if (c == 'y') { klwin = create_nhwindow(NHW_MENU); putstr(klwin, 0, "Vanquished creatures:"); putstr(klwin, 0, ""); /* countdown by monster "toughness" */ for (lev = max_lev; lev >= 0; lev--) for (i = LOW_PM; i < NUMMONS; i++) if (mons[i].mlevel == lev && (nkilled = mvitals[i].died) > 0) { if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) { Sprintf(buf, "%s%s", !type_is_pname(&mons[i]) ? "The " : "", mons[i].mname); if (nkilled > 1) { switch (nkilled) { case 2: Sprintf(eos(buf)," (twice)"); break; case 3: Sprintf(eos(buf)," (thrice)"); break; default: Sprintf(eos(buf)," (%d time%s)", nkilled, plur(nkilled)); break; } } } else { /* trolls or undead might have come back, but we don't keep track of that */ if (nkilled == 1) Strcpy(buf, an(mons[i].mname)); else Sprintf(buf, "%d %s", nkilled, makeplural(mons[i].mname)); } putstr(klwin, 0, buf); } /* * if (Hallucination) * putstr(klwin, 0, "and a partridge in a pear tree"); */ if (ntypes > 1) { putstr(klwin, 0, ""); Sprintf(buf, "%ld creatures vanquished.", total_killed); putstr(klwin, 0, buf); } display_nhwindow(klwin, TRUE); destroy_nhwindow(klwin); } } } /* number of monster species which have been genocided */ int num_genocides() { int i, n = 0; for (i = LOW_PM; i < NUMMONS; ++i) if (mvitals[i].mvflags & G_GENOD) ++n; return n; } STATIC_OVL void list_genocided(defquery, ask) char defquery; boolean ask; { register int i; int ngenocided; char c; winid klwin; char buf[BUFSZ]; ngenocided = num_genocides(); /* genocided species list */ if (ngenocided != 0) { c = ask ? yn_function("Do you want a list of species genocided?", ynqchars, defquery) : defquery; if (c == 'q') done_stopprint++; if (c == 'y') { klwin = create_nhwindow(NHW_MENU); putstr(klwin, 0, "Genocided species:"); putstr(klwin, 0, ""); for (i = LOW_PM; i < NUMMONS; i++) if (mvitals[i].mvflags & G_GENOD) { if ((mons[i].geno & G_UNIQ) && i != PM_HIGH_PRIEST) Sprintf(buf, "%s%s", !type_is_pname(&mons[i]) ? "" : "the ", mons[i].mname); else Strcpy(buf, makeplural(mons[i].mname)); putstr(klwin, 0, buf); } putstr(klwin, 0, ""); Sprintf(buf, "%d species genocided.", ngenocided); putstr(klwin, 0, buf); display_nhwindow(klwin, TRUE); destroy_nhwindow(klwin); } } } /*end.c*/ nethack-3.4.3/src/engrave.c0100644000000000000000000007763007764735041014251 0ustar rootroot/* SCCS Id: @(#)engrave.c 3.4 2001/11/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #include STATIC_VAR NEARDATA struct engr *head_engr; #ifdef OVLB /* random engravings */ static const char *random_mesg[] = { "Elbereth", /* trap engravings */ "Vlad was here", "ad aerarium", /* take-offs and other famous engravings */ "Owlbreath", "Galadriel", "Kilroy was here", "A.S. ->", "<- A.S.", /* Journey to the Center of the Earth */ "You won't get it up the steps", /* Adventure */ "Lasciate ogni speranza o voi ch'entrate.", /* Inferno */ "Well Come", /* Prisoner */ "We apologize for the inconvenience.", /* So Long... */ "See you next Wednesday", /* Thriller */ "notary sojak", /* Smokey Stover */ "For a good time call 8?7-5309", "Please don't feed the animals.", /* Various zoos around the world */ "Madam, in Eden, I'm Adam.", /* A palindrome */ "Two thumbs up!", /* Siskel & Ebert */ "Hello, World!", /* The First C Program */ #ifdef MAIL "You've got mail!", /* AOL */ #endif "As if!", /* Clueless */ }; char * random_engraving(outbuf) char *outbuf; { const char *rumor; /* a random engraving may come from the "rumors" file, or from the list above */ if (!rn2(4) || !(rumor = getrumor(0, outbuf, TRUE)) || !*rumor) Strcpy(outbuf, random_mesg[rn2(SIZE(random_mesg))]); wipeout_text(outbuf, (int)(strlen(outbuf) / 4), 0); return outbuf; } /* Partial rubouts for engraving characters. -3. */ static const struct { char wipefrom; const char * wipeto; } rubouts[] = { {'A', "^"}, {'B', "Pb["}, {'C', "("}, {'D', "|)["}, {'E', "|FL[_"}, {'F', "|-"}, {'G', "C("}, {'H', "|-"}, {'I', "|"}, {'K', "|<"}, {'L', "|_"}, {'M', "|"}, {'N', "|\\"}, {'O', "C("}, {'P', "F"}, {'Q', "C("}, {'R', "PF"}, {'T', "|"}, {'U', "J"}, {'V', "/\\"}, {'W', "V/\\"}, {'Z', "/"}, {'b', "|"}, {'d', "c|"}, {'e', "c"}, {'g', "c"}, {'h', "n"}, {'j', "i"}, {'k', "|"}, {'l', "|"}, {'m', "nr"}, {'n', "r"}, {'o', "c"}, {'q', "c"}, {'w', "v"}, {'y', "v"}, {':', "."}, {';', ","}, {'0', "C("}, {'1', "|"}, {'6', "o"}, {'7', "/"}, {'8', "3o"} }; void wipeout_text(engr, cnt, seed) char *engr; int cnt; unsigned seed; /* for semi-controlled randomization */ { char *s; int i, j, nxt, use_rubout, lth = (int)strlen(engr); if (lth && cnt > 0) { while (cnt--) { /* pick next character */ if (!seed) { /* random */ nxt = rn2(lth); use_rubout = rn2(4); } else { /* predictable; caller can reproduce the same sequence by supplying the same arguments later, or a pseudo-random sequence by varying any of them */ nxt = seed % lth; seed *= 31, seed %= (BUFSZ-1); use_rubout = seed & 3; } s = &engr[nxt]; if (*s == ' ') continue; /* rub out unreadable & small punctuation marks */ if (index("?.,'`-|_", *s)) { *s = ' '; continue; } if (!use_rubout) i = SIZE(rubouts); else for (i = 0; i < SIZE(rubouts); i++) if (*s == rubouts[i].wipefrom) { /* * Pick one of the substitutes at random. */ if (!seed) j = rn2(strlen(rubouts[i].wipeto)); else { seed *= 31, seed %= (BUFSZ-1); j = seed % (strlen(rubouts[i].wipeto)); } *s = rubouts[i].wipeto[j]; break; } /* didn't pick rubout; use '?' for unreadable character */ if (i == SIZE(rubouts)) *s = '?'; } } /* trim trailing spaces */ while (lth && engr[lth-1] == ' ') engr[--lth] = 0; } boolean can_reach_floor() { return (boolean)(!u.uswallow && #ifdef STEED /* Restricted/unskilled riders can't reach the floor */ !(u.usteed && P_SKILL(P_RIDING) < P_BASIC) && #endif (!Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz))); } #endif /* OVLB */ #ifdef OVL0 const char * surface(x, y) register int x, y; { register struct rm *lev = &levl[x][y]; if ((x == u.ux) && (y == u.uy) && u.uswallow && is_animal(u.ustuck->data)) return "maw"; else if (IS_AIR(lev->typ) && Is_airlevel(&u.uz)) return "air"; else if (is_pool(x,y)) return (Underwater && !Is_waterlevel(&u.uz)) ? "bottom" : "water"; else if (is_ice(x,y)) return "ice"; else if (is_lava(x,y)) return "lava"; else if (lev->typ == DRAWBRIDGE_DOWN) return "bridge"; else if(IS_ALTAR(levl[x][y].typ)) return "altar"; else if(IS_GRAVE(levl[x][y].typ)) return "headstone"; else if(IS_FOUNTAIN(levl[x][y].typ)) return "fountain"; else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) || IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR) return "floor"; else return "ground"; } const char * ceiling(x, y) register int x, y; { register struct rm *lev = &levl[x][y]; const char *what; /* other room types will no longer exist when we're interested -- * see check_special_room() */ if (*in_rooms(x,y,VAULT)) what = "vault's ceiling"; else if (*in_rooms(x,y,TEMPLE)) what = "temple's ceiling"; else if (*in_rooms(x,y,SHOPBASE)) what = "shop's ceiling"; else if (IS_AIR(lev->typ)) what = "sky"; else if (Underwater) what = "water's surface"; else if ((IS_ROOM(lev->typ) && !Is_earthlevel(&u.uz)) || IS_WALL(lev->typ) || IS_DOOR(lev->typ) || lev->typ == SDOOR) what = "ceiling"; else what = "rock above"; return what; } struct engr * engr_at(x, y) xchar x, y; { register struct engr *ep = head_engr; while(ep) { if(x == ep->engr_x && y == ep->engr_y) return(ep); ep = ep->nxt_engr; } return((struct engr *) 0); } #ifdef ELBERETH /* Decide whether a particular string is engraved at a specified * location; a case-insensitive substring match used. * Ignore headstones, in case the player names herself "Elbereth". */ int sengr_at(s, x, y) const char *s; xchar x, y; { register struct engr *ep = engr_at(x,y); return (ep && ep->engr_type != HEADSTONE && ep->engr_time <= moves && strstri(ep->engr_txt, s) != 0); } #endif /* ELBERETH */ #endif /* OVL0 */ #ifdef OVL2 void u_wipe_engr(cnt) register int cnt; { if (can_reach_floor()) wipe_engr_at(u.ux, u.uy, cnt); } #endif /* OVL2 */ #ifdef OVL1 void wipe_engr_at(x,y,cnt) register xchar x,y,cnt; { register struct engr *ep = engr_at(x,y); /* Headstones are indelible */ if(ep && ep->engr_type != HEADSTONE){ if(ep->engr_type != BURN || is_ice(x,y)) { if(ep->engr_type != DUST && ep->engr_type != ENGR_BLOOD) { cnt = rn2(1 + 50/(cnt+1)) ? 0 : 1; } wipeout_text(ep->engr_txt, (int)cnt, 0); while(ep->engr_txt[0] == ' ') ep->engr_txt++; if(!ep->engr_txt[0]) del_engr(ep); } } } #endif /* OVL1 */ #ifdef OVL2 void read_engr_at(x,y) register int x,y; { register struct engr *ep = engr_at(x,y); register int sensed = 0; char buf[BUFSZ]; /* Sensing an engraving does not require sight, * nor does it necessarily imply comprehension (literacy). */ if(ep && ep->engr_txt[0]) { switch(ep->engr_type) { case DUST: if(!Blind) { sensed = 1; pline("%s is written here in the %s.", Something, is_ice(x,y) ? "frost" : "dust"); } break; case ENGRAVE: case HEADSTONE: if (!Blind || can_reach_floor()) { sensed = 1; pline("%s is engraved here on the %s.", Something, surface(x,y)); } break; case BURN: if (!Blind || can_reach_floor()) { sensed = 1; pline("Some text has been %s into the %s here.", is_ice(x,y) ? "melted" : "burned", surface(x,y)); } break; case MARK: if(!Blind) { sensed = 1; pline("There's some graffiti on the %s here.", surface(x,y)); } break; case ENGR_BLOOD: /* "It's a message! Scrawled in blood!" * "What's it say?" * "It says... `See you next Wednesday.'" -- Thriller */ if(!Blind) { sensed = 1; You("see a message scrawled in blood here."); } break; default: impossible("%s is written in a very strange way.", Something); sensed = 1; } if (sensed) { char *et; unsigned maxelen = BUFSZ - sizeof("You feel the words: \"\". "); if (strlen(ep->engr_txt) > maxelen) { (void) strncpy(buf, ep->engr_txt, (int)maxelen); buf[maxelen] = '\0'; et = buf; } else et = ep->engr_txt; You("%s: \"%s\".", (Blind) ? "feel the words" : "read", et); if(flags.run > 1) nomul(0); } } } #endif /* OVL2 */ #ifdef OVLB void make_engr_at(x,y,s,e_time,e_type) register int x,y; register const char *s; register long e_time; register xchar e_type; { register struct engr *ep; if ((ep = engr_at(x,y)) != 0) del_engr(ep); ep = newengr(strlen(s) + 1); ep->nxt_engr = head_engr; head_engr = ep; ep->engr_x = x; ep->engr_y = y; ep->engr_txt = (char *)(ep + 1); Strcpy(ep->engr_txt, s); /* engraving Elbereth shows wisdom */ if (!in_mklev && !strcmp(s, "Elbereth")) exercise(A_WIS, TRUE); ep->engr_time = e_time; ep->engr_type = e_type > 0 ? e_type : rnd(N_ENGRAVE-1); ep->engr_lth = strlen(s) + 1; } /* delete any engraving at location */ void del_engr_at(x, y) int x, y; { register struct engr *ep = engr_at(x, y); if (ep) del_engr(ep); } /* * freehand - returns true if player has a free hand */ int freehand() { return(!uwep || !welded(uwep) || (!bimanual(uwep) && (!uarms || !uarms->cursed))); /* if ((uwep && bimanual(uwep)) || (uwep && uarms)) return(0); else return(1);*/ } static NEARDATA const char styluses[] = { ALL_CLASSES, ALLOW_NONE, TOOL_CLASS, WEAPON_CLASS, WAND_CLASS, GEM_CLASS, RING_CLASS, 0 }; /* Mohs' Hardness Scale: * 1 - Talc 6 - Orthoclase * 2 - Gypsum 7 - Quartz * 3 - Calcite 8 - Topaz * 4 - Fluorite 9 - Corundum * 5 - Apatite 10 - Diamond * * Since granite is a igneous rock hardness ~ 7, anything >= 8 should * probably be able to scratch the rock. * Devaluation of less hard gems is not easily possible because obj struct * does not contain individual oc_cost currently. 7/91 * * steel - 5-8.5 (usu. weapon) * diamond - 10 * jade - 5-6 (nephrite) * ruby - 9 (corundum) * turquoise - 5-6 * sapphire - 9 (corundum) * opal - 5-6 * topaz - 8 * glass - ~5.5 * emerald - 7.5-8 (beryl) * dilithium - 4-5?? * aquamarine - 7.5-8 (beryl) * iron - 4-5 * garnet - 7.25 (var. 6.5-8) * fluorite - 4 * agate - 7 (quartz) * brass - 3-4 * amethyst - 7 (quartz) * gold - 2.5-3 * jasper - 7 (quartz) * silver - 2.5-3 * onyx - 7 (quartz) * copper - 2.5-3 * moonstone - 6 (orthoclase) * amber - 2-2.5 */ /* return 1 if action took 1 (or more) moves, 0 if error or aborted */ int doengrave() { boolean dengr = FALSE; /* TRUE if we wipe out the current engraving */ boolean doblind = FALSE;/* TRUE if engraving blinds the player */ boolean doknown = FALSE;/* TRUE if we identify the stylus */ boolean eow = FALSE; /* TRUE if we are overwriting oep */ boolean jello = FALSE; /* TRUE if we are engraving in slime */ boolean ptext = TRUE; /* TRUE if we must prompt for engrave text */ boolean teleengr =FALSE;/* TRUE if we move the old engraving */ boolean zapwand = FALSE;/* TRUE if we remove a wand charge */ xchar type = DUST; /* Type of engraving made */ char buf[BUFSZ]; /* Buffer for final/poly engraving text */ char ebuf[BUFSZ]; /* Buffer for initial engraving text */ char qbuf[QBUFSZ]; /* Buffer for query text */ char post_engr_text[BUFSZ]; /* Text displayed after engraving prompt */ const char *everb; /* Present tense of engraving type */ const char *eloc; /* Where the engraving is (ie dust/floor/...) */ char *sp; /* Place holder for space count of engr text */ int len; /* # of nonspace chars of new engraving text */ int maxelen; /* Max allowable length of engraving text */ struct engr *oep = engr_at(u.ux,u.uy); /* The current engraving */ struct obj *otmp; /* Object selected with which to engrave */ char *writer; multi = 0; /* moves consumed */ nomovemsg = (char *)0; /* occupation end message */ buf[0] = (char)0; ebuf[0] = (char)0; post_engr_text[0] = (char)0; maxelen = BUFSZ - 1; if (is_demon(youmonst.data) || youmonst.data->mlet == S_VAMPIRE) type = ENGR_BLOOD; /* Can the adventurer engrave at all? */ if(u.uswallow) { if (is_animal(u.ustuck->data)) { pline("What would you write? \"Jonah was here\"?"); return(0); } else if (is_whirly(u.ustuck->data)) { You_cant("reach the %s.", surface(u.ux,u.uy)); return(0); } else jello = TRUE; } else if (is_lava(u.ux, u.uy)) { You_cant("write on the lava!"); return(0); } else if (is_pool(u.ux,u.uy) || IS_FOUNTAIN(levl[u.ux][u.uy].typ)) { You_cant("write on the water!"); return(0); } if(Is_airlevel(&u.uz) || Is_waterlevel(&u.uz)/* in bubble */) { You_cant("write in thin air!"); return(0); } if (cantwield(youmonst.data)) { You_cant("even hold anything!"); return(0); } if (check_capacity((char *)0)) return (0); /* One may write with finger, or weapon, or wand, or..., or... * Edited by GAN 10/20/86 so as not to change weapon wielded. */ otmp = getobj(styluses, "write with"); if(!otmp) return(0); /* otmp == zeroobj if fingers */ if (otmp == &zeroobj) writer = makeplural(body_part(FINGER)); else writer = xname(otmp); /* There's no reason you should be able to write with a wand * while both your hands are tied up. */ if (!freehand() && otmp != uwep && !otmp->owornmask) { You("have no free %s to write with!", body_part(HAND)); return(0); } if (jello) { You("tickle %s with your %s.", mon_nam(u.ustuck), writer); Your("message dissolves..."); return(0); } if (otmp->oclass != WAND_CLASS && !can_reach_floor()) { You_cant("reach the %s!", surface(u.ux,u.uy)); return(0); } if (IS_ALTAR(levl[u.ux][u.uy].typ)) { You("make a motion towards the altar with your %s.", writer); altar_wrath(u.ux, u.uy); return(0); } if (IS_GRAVE(levl[u.ux][u.uy].typ)) { if (otmp == &zeroobj) { /* using only finger */ You("would only make a small smudge on the %s.", surface(u.ux, u.uy)); return(0); } else if (!levl[u.ux][u.uy].disturbed) { You("disturb the undead!"); levl[u.ux][u.uy].disturbed = 1; (void) makemon(&mons[PM_GHOUL], u.ux, u.uy, NO_MM_FLAGS); exercise(A_WIS, FALSE); return(1); } } /* SPFX for items */ switch (otmp->oclass) { default: case AMULET_CLASS: case CHAIN_CLASS: case POTION_CLASS: case COIN_CLASS: break; case RING_CLASS: /* "diamond" rings and others should work */ case GEM_CLASS: /* diamonds & other hard gems should work */ if (objects[otmp->otyp].oc_tough) { type = ENGRAVE; break; } break; case ARMOR_CLASS: if (is_boots(otmp)) { type = DUST; break; } /* fall through */ /* Objects too large to engrave with */ case BALL_CLASS: case ROCK_CLASS: You_cant("engrave with such a large object!"); ptext = FALSE; break; /* Objects too silly to engrave with */ case FOOD_CLASS: case SCROLL_CLASS: case SPBOOK_CLASS: Your("%s would get %s.", xname(otmp), is_ice(u.ux,u.uy) ? "all frosty" : "too dirty"); ptext = FALSE; break; case RANDOM_CLASS: /* This should mean fingers */ break; /* The charge is removed from the wand before prompting for * the engraving text, because all kinds of setup decisions * and pre-engraving messages are based upon knowing what type * of engraving the wand is going to do. Also, the player * will have potentially seen "You wrest .." message, and * therefore will know they are using a charge. */ case WAND_CLASS: if (zappable(otmp)) { check_unpaid(otmp); zapwand = TRUE; if (Levitation) ptext = FALSE; switch (otmp->otyp) { /* DUST wands */ default: break; /* NODIR wands */ case WAN_LIGHT: case WAN_SECRET_DOOR_DETECTION: case WAN_CREATE_MONSTER: case WAN_WISHING: case WAN_ENLIGHTENMENT: zapnodir(otmp); break; /* IMMEDIATE wands */ /* If wand is "IMMEDIATE", remember to affect the * previous engraving even if turning to dust. */ case WAN_STRIKING: Strcpy(post_engr_text, "The wand unsuccessfully fights your attempt to write!" ); break; case WAN_SLOW_MONSTER: if (!Blind) { Sprintf(post_engr_text, "The bugs on the %s slow down!", surface(u.ux, u.uy)); } break; case WAN_SPEED_MONSTER: if (!Blind) { Sprintf(post_engr_text, "The bugs on the %s speed up!", surface(u.ux, u.uy)); } break; case WAN_POLYMORPH: if(oep) { if (!Blind) { type = (xchar)0; /* random */ (void) random_engraving(buf); } dengr = TRUE; } break; case WAN_NOTHING: case WAN_UNDEAD_TURNING: case WAN_OPENING: case WAN_LOCKING: case WAN_PROBING: break; /* RAY wands */ case WAN_MAGIC_MISSILE: ptext = TRUE; if (!Blind) { Sprintf(post_engr_text, "The %s is riddled by bullet holes!", surface(u.ux, u.uy)); } break; /* can't tell sleep from death - Eric Backus */ case WAN_SLEEP: case WAN_DEATH: if (!Blind) { Sprintf(post_engr_text, "The bugs on the %s stop moving!", surface(u.ux, u.uy)); } break; case WAN_COLD: if (!Blind) Strcpy(post_engr_text, "A few ice cubes drop from the wand."); if(!oep || (oep->engr_type != BURN)) break; case WAN_CANCELLATION: case WAN_MAKE_INVISIBLE: if (oep && oep->engr_type != HEADSTONE) { if (!Blind) pline_The("engraving on the %s vanishes!", surface(u.ux,u.uy)); dengr = TRUE; } break; case WAN_TELEPORTATION: if (oep && oep->engr_type != HEADSTONE) { if (!Blind) pline_The("engraving on the %s vanishes!", surface(u.ux,u.uy)); teleengr = TRUE; } break; /* type = ENGRAVE wands */ case WAN_DIGGING: ptext = TRUE; type = ENGRAVE; if(!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of digging!", xname(otmp)); doknown = TRUE; } if (!Blind) Strcpy(post_engr_text, IS_GRAVE(levl[u.ux][u.uy].typ) ? "Chips fly out from the headstone." : is_ice(u.ux,u.uy) ? "Ice chips fly up from the ice surface!" : "Gravel flies up from the floor."); else Strcpy(post_engr_text, "You hear drilling!"); break; /* type = BURN wands */ case WAN_FIRE: ptext = TRUE; type = BURN; if(!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of fire!", xname(otmp)); doknown = TRUE; } Strcpy(post_engr_text, Blind ? "You feel the wand heat up." : "Flames fly from the wand."); break; case WAN_LIGHTNING: ptext = TRUE; type = BURN; if(!objects[otmp->otyp].oc_name_known) { if (flags.verbose) pline("This %s is a wand of lightning!", xname(otmp)); doknown = TRUE; } if (!Blind) { Strcpy(post_engr_text, "Lightning arcs from the wand."); doblind = TRUE; } else Strcpy(post_engr_text, "You hear crackling!"); break; /* type = MARK wands */ /* type = ENGR_BLOOD wands */ } } else /* end if zappable */ if (!can_reach_floor()) { You_cant("reach the %s!", surface(u.ux,u.uy)); return(0); } break; case WEAPON_CLASS: if (is_blade(otmp)) { if ((int)otmp->spe > -3) type = ENGRAVE; else Your("%s too dull for engraving.", aobjnam(otmp,"are")); } break; case TOOL_CLASS: if(otmp == ublindf) { pline( "That is a bit difficult to engrave with, don't you think?"); return(0); } switch (otmp->otyp) { case MAGIC_MARKER: if (otmp->spe <= 0) Your("marker has dried out."); else type = MARK; break; case TOWEL: /* Can't really engrave with a towel */ ptext = FALSE; if (oep) if ((oep->engr_type == DUST ) || (oep->engr_type == ENGR_BLOOD) || (oep->engr_type == MARK )) { if (!Blind) You("wipe out the message here."); else Your("%s %s %s.", xname(otmp), otense(otmp, "get"), is_ice(u.ux,u.uy) ? "frosty" : "dusty"); dengr = TRUE; } else Your("%s can't wipe out this engraving.", xname(otmp)); else Your("%s %s %s.", xname(otmp), otense(otmp, "get"), is_ice(u.ux,u.uy) ? "frosty" : "dusty"); break; default: break; } break; case VENOM_CLASS: #ifdef WIZARD if (wizard) { pline("Writing a poison pen letter??"); break; } #endif case ILLOBJ_CLASS: impossible("You're engraving with an illegal object!"); break; } if (IS_GRAVE(levl[u.ux][u.uy].typ)) { if (type == ENGRAVE || type == 0) type = HEADSTONE; else { /* ensures the "cannot wipe out" case */ type = DUST; dengr = FALSE; teleengr = FALSE; buf[0] = (char)0; } } /* End of implement setup */ /* Identify stylus */ if (doknown) { makeknown(otmp->otyp); more_experienced(0,10); } if (teleengr) { rloc_engr(oep); oep = (struct engr *)0; } if (dengr) { del_engr(oep); oep = (struct engr *)0; } /* Something has changed the engraving here */ if (*buf) { make_engr_at(u.ux, u.uy, buf, moves, type); pline_The("engraving now reads: \"%s\".", buf); ptext = FALSE; } if (zapwand && (otmp->spe < 0)) { pline("%s %sturns to dust.", The(xname(otmp)), Blind ? "" : "glows violently, then "); if (!IS_GRAVE(levl[u.ux][u.uy].typ)) You("are not going to get anywhere trying to write in the %s with your dust.", is_ice(u.ux,u.uy) ? "frost" : "dust"); useup(otmp); ptext = FALSE; } if (!ptext) { /* Early exit for some implements. */ if (otmp->oclass == WAND_CLASS && !can_reach_floor()) You_cant("reach the %s!", surface(u.ux,u.uy)); return(1); } /* Special effects should have deleted the current engraving (if * possible) by now. */ if (oep) { register char c = 'n'; /* Give player the choice to add to engraving. */ if (type == HEADSTONE) { /* no choice, only append */ c = 'y'; } else if ( (type == oep->engr_type) && (!Blind || (oep->engr_type == BURN) || (oep->engr_type == ENGRAVE)) ) { c = yn_function("Do you want to add to the current engraving?", ynqchars, 'y'); if (c == 'q') { pline(Never_mind); return(0); } } if (c == 'n' || Blind) { if( (oep->engr_type == DUST) || (oep->engr_type == ENGR_BLOOD) || (oep->engr_type == MARK) ) { if (!Blind) { You("wipe out the message that was %s here.", ((oep->engr_type == DUST) ? "written in the dust" : ((oep->engr_type == ENGR_BLOOD) ? "scrawled in blood" : "written"))); del_engr(oep); oep = (struct engr *)0; } else /* Don't delete engr until after we *know* we're engraving */ eow = TRUE; } else if ( (type == DUST) || (type == MARK) || (type == ENGR_BLOOD) ) { You( "cannot wipe out the message that is %s the %s here.", oep->engr_type == BURN ? (is_ice(u.ux,u.uy) ? "melted into" : "burned into") : "engraved in", surface(u.ux,u.uy)); return(1); } else if ( (type != oep->engr_type) || (c == 'n') ) { if (!Blind || can_reach_floor()) You("will overwrite the current message."); eow = TRUE; } } } eloc = surface(u.ux,u.uy); switch(type){ default: everb = (oep && !eow ? "add to the weird writing on" : "write strangely on"); break; case DUST: everb = (oep && !eow ? "add to the writing in" : "write in"); eloc = is_ice(u.ux,u.uy) ? "frost" : "dust"; break; case HEADSTONE: everb = (oep && !eow ? "add to the epitaph on" : "engrave on"); break; case ENGRAVE: everb = (oep && !eow ? "add to the engraving in" : "engrave in"); break; case BURN: everb = (oep && !eow ? ( is_ice(u.ux,u.uy) ? "add to the text melted into" : "add to the text burned into") : ( is_ice(u.ux,u.uy) ? "melt into" : "burn into")); break; case MARK: everb = (oep && !eow ? "add to the graffiti on" : "scribble on"); break; case ENGR_BLOOD: everb = (oep && !eow ? "add to the scrawl on" : "scrawl on"); break; } /* Tell adventurer what is going on */ if (otmp != &zeroobj) You("%s the %s with %s.", everb, eloc, doname(otmp)); else You("%s the %s with your %s.", everb, eloc, makeplural(body_part(FINGER))); /* Prompt for engraving! */ Sprintf(qbuf,"What do you want to %s the %s here?", everb, eloc); getlin(qbuf, ebuf); /* Count the actual # of chars engraved not including spaces */ len = strlen(ebuf); for (sp = ebuf; *sp; sp++) if (isspace(*sp)) len -= 1; if (len == 0 || index(ebuf, '\033')) { if (zapwand) { if (!Blind) pline("%s, then %s.", Tobjnam(otmp, "glow"), otense(otmp, "fade")); return(1); } else { pline(Never_mind); return(0); } } /* A single `x' is the traditional signature of an illiterate person */ if (len != 1 || (!index(ebuf, 'x') && !index(ebuf, 'X'))) u.uconduct.literate++; /* Mix up engraving if surface or state of mind is unsound. Note: this won't add or remove any spaces. */ for (sp = ebuf; *sp; sp++) { if (isspace(*sp)) continue; if (((type == DUST || type == ENGR_BLOOD) && !rn2(25)) || (Blind && !rn2(11)) || (Confusion && !rn2(7)) || (Stunned && !rn2(4)) || (Hallucination && !rn2(2))) *sp = ' ' + rnd(96 - 2); /* ASCII '!' thru '~' (excludes ' ' and DEL) */ } /* Previous engraving is overwritten */ if (eow) { del_engr(oep); oep = (struct engr *)0; } /* Figure out how long it took to engrave, and if player has * engraved too much. */ switch(type){ default: multi = -(len/10); if (multi) nomovemsg = "You finish your weird engraving."; break; case DUST: multi = -(len/10); if (multi) nomovemsg = "You finish writing in the dust."; break; case HEADSTONE: case ENGRAVE: multi = -(len/10); if ((otmp->oclass == WEAPON_CLASS) && ((otmp->otyp != ATHAME) || otmp->cursed)) { multi = -len; maxelen = ((otmp->spe + 3) * 2) + 1; /* -2 = 3, -1 = 5, 0 = 7, +1 = 9, +2 = 11 * Note: this does not allow a +0 anything (except * an athame) to engrave "Elbereth" all at once. * However, you could now engrave "Elb", then * "ere", then "th". */ Your("%s dull.", aobjnam(otmp, "get")); if (otmp->unpaid) { struct monst *shkp = shop_keeper(*u.ushops); if (shkp) { You("damage it, you pay for it!"); bill_dummy_object(otmp); } } if (len > maxelen) { multi = -maxelen; otmp->spe = -3; } else if (len > 1) otmp->spe -= len >> 1; else otmp->spe -= 1; /* Prevent infinite engraving */ } else if ( (otmp->oclass == RING_CLASS) || (otmp->oclass == GEM_CLASS) ) multi = -len; if (multi) nomovemsg = "You finish engraving."; break; case BURN: multi = -(len/10); if (multi) nomovemsg = is_ice(u.ux,u.uy) ? "You finish melting your message into the ice.": "You finish burning your message into the floor."; break; case MARK: multi = -(len/10); if ((otmp->oclass == TOOL_CLASS) && (otmp->otyp == MAGIC_MARKER)) { maxelen = (otmp->spe) * 2; /* one charge / 2 letters */ if (len > maxelen) { Your("marker dries out."); otmp->spe = 0; multi = -(maxelen/10); } else if (len > 1) otmp->spe -= len >> 1; else otmp->spe -= 1; /* Prevent infinite grafitti */ } if (multi) nomovemsg = "You finish defacing the dungeon."; break; case ENGR_BLOOD: multi = -(len/10); if (multi) nomovemsg = "You finish scrawling."; break; } /* Chop engraving down to size if necessary */ if (len > maxelen) { for (sp = ebuf; (maxelen && *sp); sp++) if (!isspace(*sp)) maxelen--; if (!maxelen && *sp) { *sp = (char)0; if (multi) nomovemsg = "You cannot write any more."; You("only are able to write \"%s\"", ebuf); } } /* Add to existing engraving */ if (oep) Strcpy(buf, oep->engr_txt); (void) strncat(buf, ebuf, (BUFSZ - (int)strlen(buf) - 1)); make_engr_at(u.ux, u.uy, buf, (moves - multi), type); if (post_engr_text[0]) pline(post_engr_text); if (doblind && !resists_blnd(&youmonst)) { You("are blinded by the flash!"); make_blinded((long)rnd(50),FALSE); if (!Blind) Your(vision_clears); } return(1); } void save_engravings(fd, mode) int fd, mode; { register struct engr *ep = head_engr; register struct engr *ep2; unsigned no_more_engr = 0; while (ep) { ep2 = ep->nxt_engr; if (ep->engr_lth && ep->engr_txt[0] && perform_bwrite(mode)) { bwrite(fd, (genericptr_t)&(ep->engr_lth), sizeof(ep->engr_lth)); bwrite(fd, (genericptr_t)ep, sizeof(struct engr) + ep->engr_lth); } if (release_data(mode)) dealloc_engr(ep); ep = ep2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t)&no_more_engr, sizeof no_more_engr); if (release_data(mode)) head_engr = 0; } void rest_engravings(fd) int fd; { register struct engr *ep; unsigned lth; head_engr = 0; while(1) { mread(fd, (genericptr_t) <h, sizeof(unsigned)); if(lth == 0) return; ep = newengr(lth); mread(fd, (genericptr_t) ep, sizeof(struct engr) + lth); ep->nxt_engr = head_engr; head_engr = ep; ep->engr_txt = (char *) (ep + 1); /* Andreas Bormann */ /* mark as finished for bones levels -- no problem for * normal levels as the player must have finished engraving * to be able to move again */ ep->engr_time = moves; } } void del_engr(ep) register struct engr *ep; { if (ep == head_engr) { head_engr = ep->nxt_engr; } else { register struct engr *ept; for (ept = head_engr; ept; ept = ept->nxt_engr) if (ept->nxt_engr == ep) { ept->nxt_engr = ep->nxt_engr; break; } if (!ept) { impossible("Error in del_engr?"); return; } } dealloc_engr(ep); } /* randomly relocate an engraving */ void rloc_engr(ep) struct engr *ep; { int tx, ty, tryct = 200; do { if (--tryct < 0) return; tx = rn1(COLNO-3,2); ty = rn2(ROWNO); } while (engr_at(tx, ty) || !goodpos(tx, ty, (struct monst *)0, 0)); ep->engr_x = tx; ep->engr_y = ty; } /* Epitaphs for random headstones */ static const char *epitaphs[] = { "Rest in peace", "R.I.P.", "Rest In Pieces", "Note -- there are NO valuable items in this grave", "1994-1995. The Longest-Lived Hacker Ever", "The Grave of the Unknown Hacker", "We weren't sure who this was, but we buried him here anyway", "Sparky -- he was a very good dog", "Beware of Electric Third Rail", "Made in Taiwan", "Og friend. Og good dude. Og died. Og now food", "Beetlejuice Beetlejuice Beetlejuice", "Look out below!", "Please don't dig me up. I'm perfectly happy down here. -- Resident", "Postman, please note forwarding address: Gehennom, Asmodeus's Fortress, fifth lemure on the left", "Mary had a little lamb/Its fleece was white as snow/When Mary was in trouble/The lamb was first to go", "Be careful, or this could happen to you!", "Soon you'll join this fellow in hell! -- the Wizard of Yendor", "Caution! This grave contains toxic waste", "Sum quod eris", "Here lies an Atheist, all dressed up and no place to go", "Here lies Ezekiel, age 102. The good die young.", "Here lies my wife: Here let her lie! Now she's at rest and so am I.", "Here lies Johnny Yeast. Pardon me for not rising.", "He always lied while on the earth and now he's lying in it", "I made an ash of myself", "Soon ripe. Soon rotten. Soon gone. But not forgotten.", "Here lies the body of Jonathan Blake. Stepped on the gas instead of the brake.", "Go away!" }; /* Create a headstone at the given location. * The caller is responsible for newsym(x, y). */ void make_grave(x, y, str) int x, y; const char *str; { /* Can we put a grave here? */ if ((levl[x][y].typ != ROOM && levl[x][y].typ != GRAVE) || t_at(x,y)) return; /* Make the grave */ levl[x][y].typ = GRAVE; /* Engrave the headstone */ if (!str) str = epitaphs[rn2(SIZE(epitaphs))]; del_engr_at(x, y); make_engr_at(x, y, str, 0L, HEADSTONE); return; } #endif /* OVLB */ /*engrave.c*/ nethack-3.4.3/src/exper.c0100644000000000000000000001512207764735041013731 0ustar rootroot/* SCCS Id: @(#)exper.c 3.4 2002/11/20 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL long FDECL(newuexp, (int)); STATIC_DCL int FDECL(enermod, (int)); STATIC_OVL long newuexp(lev) int lev; { if (lev < 10) return (10L * (1L << lev)); if (lev < 20) return (10000L * (1L << (lev - 10))); return (10000000L * ((long)(lev - 19))); } STATIC_OVL int enermod(en) int en; { switch (Role_switch) { case PM_PRIEST: case PM_WIZARD: return(2 * en); case PM_HEALER: case PM_KNIGHT: return((3 * en) / 2); case PM_BARBARIAN: case PM_VALKYRIE: return((3 * en) / 4); default: return (en); } } int experience(mtmp, nk) /* return # of exp points for mtmp after nk killed */ register struct monst *mtmp; register int nk; #if defined(macintosh) && (defined(__SC__) || defined(__MRC__)) # pragma unused(nk) #endif { register struct permonst *ptr = mtmp->data; int i, tmp, tmp2; tmp = 1 + mtmp->m_lev * mtmp->m_lev; /* For higher ac values, give extra experience */ if ((i = find_mac(mtmp)) < 3) tmp += (7 - i) * ((i < 0) ? 2 : 1); /* For very fast monsters, give extra experience */ if (ptr->mmove > NORMAL_SPEED) tmp += (ptr->mmove > (3*NORMAL_SPEED/2)) ? 5 : 3; /* For each "special" attack type give extra experience */ for(i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].aatyp; if(tmp2 > AT_BUTT) { if(tmp2 == AT_WEAP) tmp += 5; else if(tmp2 == AT_MAGC) tmp += 10; else tmp += 3; } } /* For each "special" damage type give extra experience */ for(i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].adtyp; if(tmp2 > AD_PHYS && tmp2 < AD_BLND) tmp += 2*mtmp->m_lev; else if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_SLIM)) tmp += 50; else if(tmp != AD_PHYS) tmp += mtmp->m_lev; /* extra heavy damage bonus */ if((int)(ptr->mattk[i].damd * ptr->mattk[i].damn) > 23) tmp += mtmp->m_lev; if (tmp2 == AD_WRAP && ptr->mlet == S_EEL && !Amphibious) tmp += 1000; } /* For certain "extra nasty" monsters, give even more */ if (extra_nasty(ptr)) tmp += (7 * mtmp->m_lev); /* For higher level monsters, an additional bonus is given */ if(mtmp->m_lev > 8) tmp += 50; #ifdef MAIL /* Mail daemons put up no fight. */ if(mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1; #endif return(tmp); } void more_experienced(exp, rexp) register int exp, rexp; { u.uexp += exp; u.urexp += 4*exp + rexp; if(exp #ifdef SCORE_ON_BOTL || flags.showscore #endif ) flags.botl = 1; if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000)) flags.beginner = 0; } void losexp(drainer) /* e.g., hit by drain life attack */ const char *drainer; /* cause of death, if drain should be fatal */ { register int num; #ifdef WIZARD /* override life-drain resistance when handling an explicit wizard mode request to reduce level; never fatal though */ if (drainer && !strcmp(drainer, "#levelchange")) drainer = 0; else #endif if (resists_drli(&youmonst)) return; if (u.ulevel > 1) { pline("%s level %d.", Goodbye(), u.ulevel--); /* remove intrinsic abilities */ adjabil(u.ulevel + 1, u.ulevel); reset_rndmonst(NON_PM); /* new monster selection */ } else { if (drainer) { killer_format = KILLED_BY; killer = drainer; done(DIED); } /* no drainer or lifesaved */ u.uexp = 0; } num = newhp(); u.uhpmax -= num; if (u.uhpmax < 1) u.uhpmax = 1; u.uhp -= num; if (u.uhp < 1) u.uhp = 1; else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax; if (u.ulevel < urole.xlev) num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd, urole.enadv.lofix + urace.enadv.lofix); else num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd, urole.enadv.hifix + urace.enadv.hifix); num = enermod(num); /* M. Stephenson */ u.uenmax -= num; if (u.uenmax < 0) u.uenmax = 0; u.uen -= num; if (u.uen < 0) u.uen = 0; else if (u.uen > u.uenmax) u.uen = u.uenmax; if (u.uexp > 0) u.uexp = newuexp(u.ulevel) - 1; flags.botl = 1; } /* * Make experience gaining similar to AD&D(tm), whereby you can at most go * up by one level at a time, extra expr possibly helping you along. * After all, how much real experience does one get shooting a wand of death * at a dragon created with a wand of polymorph?? */ void newexplevel() { if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel)) pluslvl(TRUE); } void pluslvl(incr) boolean incr; /* true iff via incremental experience growth */ { /* (false for potion of gain level) */ register int num; if (!incr) You_feel("more experienced."); num = newhp(); u.uhpmax += num; u.uhp += num; if (Upolyd) { num = rnd(8); u.mhmax += num; u.mh += num; } if (u.ulevel < urole.xlev) num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd, urole.enadv.lofix + urace.enadv.lofix); else num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd, urole.enadv.hifix + urace.enadv.hifix); num = enermod(num); /* M. Stephenson */ u.uenmax += num; u.uen += num; if (u.ulevel < MAXULEV) { if (incr) { long tmp = newuexp(u.ulevel + 1); if (u.uexp >= tmp) u.uexp = tmp - 1; } else { u.uexp = newuexp(u.ulevel); } ++u.ulevel; if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel; pline("Welcome to experience level %d.", u.ulevel); adjabil(u.ulevel - 1, u.ulevel); /* give new intrinsics */ reset_rndmonst(NON_PM); /* new monster selection */ } flags.botl = 1; } /* compute a random amount of experience points suitable for the hero's experience level: base number of points needed to reach the current level plus a random portion of what it takes to get to the next level */ long rndexp(gaining) boolean gaining; /* gaining XP via potion vs setting XP for polyself */ { long minexp, maxexp, diff, factor, result; minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1); maxexp = newuexp(u.ulevel); diff = maxexp - minexp, factor = 1L; /* make sure that `diff' is an argument which rn2() can handle */ while (diff >= (long)LARGEST_INT) diff /= 2L, factor *= 2L; result = minexp + factor * (long)rn2((int)diff); /* 3.4.1: if already at level 30, add to current experience points rather than to threshold needed to reach the current level; otherwise blessed potions of gain level can result in lowering the experience points instead of raising them */ if (u.ulevel == MAXULEV && gaining) { result += (u.uexp - minexp); /* avoid wrapping (over 400 blessed potions needed for that...) */ if (result < u.uexp) result = u.uexp; } return result; } /*exper.c*/ nethack-3.4.3/src/explode.c0100644000000000000000000004007207764735041014250 0ustar rootroot/* SCCS Id: @(#)explode.c 3.4 2002/11/10 */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef OVL0 /* Note: Arrays are column first, while the screen is row first */ static int expl[3][3] = { { S_explode1, S_explode4, S_explode7 }, { S_explode2, S_explode5, S_explode8 }, { S_explode3, S_explode6, S_explode9 } }; /* Note: I had to choose one of three possible kinds of "type" when writing * this function: a wand type (like in zap.c), an adtyp, or an object type. * Wand types get complex because they must be converted to adtyps for * determining such things as fire resistance. Adtyps get complex in that * they don't supply enough information--was it a player or a monster that * did it, and with a wand, spell, or breath weapon? Object types share both * these disadvantages.... */ void explode(x, y, type, dam, olet, expltype) int x, y; int type; /* the same as in zap.c */ int dam; char olet; int expltype; { int i, j, k, damu = dam; boolean starting = 1; boolean visible, any_shield; int uhurt = 0; /* 0=unhurt, 1=items damaged, 2=you and items damaged */ const char *str; int idamres, idamnonres; struct monst *mtmp; uchar adtyp; int explmask[3][3]; /* 0=normal explosion, 1=do shieldeff, 2=do nothing */ boolean shopdamage = FALSE; boolean generic = FALSE; if (olet == WAND_CLASS) /* retributive strike */ switch (Role_switch) { case PM_PRIEST: case PM_MONK: case PM_WIZARD: damu /= 5; break; case PM_HEALER: case PM_KNIGHT: damu /= 2; break; default: break; } if (olet == MON_EXPLODE) { str = killer; killer = 0; /* set again later as needed */ adtyp = AD_PHYS; } else switch (abs(type) % 10) { case 0: str = "magical blast"; adtyp = AD_MAGM; break; case 1: str = olet == BURNING_OIL ? "burning oil" : olet == SCROLL_CLASS ? "tower of flame" : "fireball"; adtyp = AD_FIRE; break; case 2: str = "ball of cold"; adtyp = AD_COLD; break; case 4: str = (olet == WAND_CLASS) ? "death field" : "disintegration field"; adtyp = AD_DISN; break; case 5: str = "ball of lightning"; adtyp = AD_ELEC; break; case 6: str = "poison gas cloud"; adtyp = AD_DRST; break; case 7: str = "splash of acid"; adtyp = AD_ACID; break; default: impossible("explosion base type %d?", type); return; } any_shield = visible = FALSE; for (i=0; i<3; i++) for (j=0; j<3; j++) { if (!isok(i+x-1, j+y-1)) { explmask[i][j] = 2; continue; } else explmask[i][j] = 0; if (i+x-1 == u.ux && j+y-1 == u.uy) { switch(adtyp) { case AD_PHYS: explmask[i][j] = 0; break; case AD_MAGM: explmask[i][j] = !!Antimagic; break; case AD_FIRE: explmask[i][j] = !!Fire_resistance; break; case AD_COLD: explmask[i][j] = !!Cold_resistance; break; case AD_DISN: explmask[i][j] = (olet == WAND_CLASS) ? !!(nonliving(youmonst.data) || is_demon(youmonst.data)) : !!Disint_resistance; break; case AD_ELEC: explmask[i][j] = !!Shock_resistance; break; case AD_DRST: explmask[i][j] = !!Poison_resistance; break; case AD_ACID: explmask[i][j] = !!Acid_resistance; break; default: impossible("explosion type %d?", adtyp); break; } } /* can be both you and mtmp if you're swallowed */ mtmp = m_at(i+x-1, j+y-1); #ifdef STEED if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy) mtmp = u.usteed; #endif if (mtmp) { if (mtmp->mhp < 1) explmask[i][j] = 2; else switch(adtyp) { case AD_PHYS: break; case AD_MAGM: explmask[i][j] |= resists_magm(mtmp); break; case AD_FIRE: explmask[i][j] |= resists_fire(mtmp); break; case AD_COLD: explmask[i][j] |= resists_cold(mtmp); break; case AD_DISN: explmask[i][j] |= (olet == WAND_CLASS) ? (nonliving(mtmp->data) || is_demon(mtmp->data)) : resists_disint(mtmp); break; case AD_ELEC: explmask[i][j] |= resists_elec(mtmp); break; case AD_DRST: explmask[i][j] |= resists_poison(mtmp); break; case AD_ACID: explmask[i][j] |= resists_acid(mtmp); break; default: impossible("explosion type %d?", adtyp); break; } } if (mtmp && cansee(i+x-1,j+y-1) && !canspotmon(mtmp)) map_invisible(i+x-1, j+y-1); else if (!mtmp && glyph_is_invisible(levl[i+x-1][j+y-1].glyph)) { unmap_object(i+x-1, j+y-1); newsym(i+x-1, j+y-1); } if (cansee(i+x-1, j+y-1)) visible = TRUE; if (explmask[i][j] == 1) any_shield = TRUE; } if (visible) { /* Start the explosion */ for (i=0; i<3; i++) for (j=0; j<3; j++) { if (explmask[i][j] == 2) continue; tmp_at(starting ? DISP_BEAM : DISP_CHANGE, explosion_to_glyph(expltype,expl[i][j])); tmp_at(i+x-1, j+y-1); starting = 0; } curs_on_u(); /* will flush screen and output */ if (any_shield && flags.sparkle) { /* simulate shield effect */ for (k = 0; k < SHIELD_COUNT; k++) { for (i=0; i<3; i++) for (j=0; j<3; j++) { if (explmask[i][j] == 1) /* * Bypass tmp_at() and send the shield glyphs * directly to the buffered screen. tmp_at() * will clean up the location for us later. */ show_glyph(i+x-1, j+y-1, cmap_to_glyph(shield_static[k])); } curs_on_u(); /* will flush screen and output */ delay_output(); } /* Cover last shield glyph with blast symbol. */ for (i=0; i<3; i++) for (j=0; j<3; j++) { if (explmask[i][j] == 1) show_glyph(i+x-1,j+y-1, explosion_to_glyph(expltype, expl[i][j])); } } else { /* delay a little bit. */ delay_output(); delay_output(); } tmp_at(DISP_END, 0); /* clear the explosion */ } else { if (olet == MON_EXPLODE) { str = "explosion"; generic = TRUE; } if (flags.soundok) You_hear("a blast."); } if (dam) for (i=0; i<3; i++) for (j=0; j<3; j++) { if (explmask[i][j] == 2) continue; if (i+x-1 == u.ux && j+y-1 == u.uy) uhurt = (explmask[i][j] == 1) ? 1 : 2; idamres = idamnonres = 0; if (type >= 0) (void)zap_over_floor((xchar)(i+x-1), (xchar)(j+y-1), type, &shopdamage); mtmp = m_at(i+x-1, j+y-1); #ifdef STEED if (!mtmp && i+x-1 == u.ux && j+y-1 == u.uy) mtmp = u.usteed; #endif if (!mtmp) continue; if (u.uswallow && mtmp == u.ustuck) { if (is_animal(u.ustuck->data)) pline("%s gets %s!", Monnam(u.ustuck), (adtyp == AD_FIRE) ? "heartburn" : (adtyp == AD_COLD) ? "chilly" : (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ? "irradiated by pure energy" : "perforated") : (adtyp == AD_ELEC) ? "shocked" : (adtyp == AD_DRST) ? "poisoned" : (adtyp == AD_ACID) ? "an upset stomach" : "fried"); else pline("%s gets slightly %s!", Monnam(u.ustuck), (adtyp == AD_FIRE) ? "toasted" : (adtyp == AD_COLD) ? "chilly" : (adtyp == AD_DISN) ? ((olet == WAND_CLASS) ? "overwhelmed by pure energy" : "perforated") : (adtyp == AD_ELEC) ? "shocked" : (adtyp == AD_DRST) ? "intoxicated" : (adtyp == AD_ACID) ? "burned" : "fried"); } else if (cansee(i+x-1, j+y-1)) { if(mtmp->m_ap_type) seemimic(mtmp); pline("%s is caught in the %s!", Monnam(mtmp), str); } idamres += destroy_mitem(mtmp, SCROLL_CLASS, (int) adtyp); idamres += destroy_mitem(mtmp, SPBOOK_CLASS, (int) adtyp); idamnonres += destroy_mitem(mtmp, POTION_CLASS, (int) adtyp); idamnonres += destroy_mitem(mtmp, WAND_CLASS, (int) adtyp); idamnonres += destroy_mitem(mtmp, RING_CLASS, (int) adtyp); if (explmask[i][j] == 1) { golemeffects(mtmp, (int) adtyp, dam + idamres); mtmp->mhp -= idamnonres; } else { /* call resist with 0 and do damage manually so 1) we can * get out the message before doing the damage, and 2) we can * call mondied, not killed, if it's not your blast */ int mdam = dam; if (resist(mtmp, olet, 0, FALSE)) { if (cansee(i+x-1,j+y-1)) pline("%s resists the %s!", Monnam(mtmp), str); mdam = dam/2; } if (mtmp == u.ustuck) mdam *= 2; if (resists_cold(mtmp) && adtyp == AD_FIRE) mdam *= 2; else if (resists_fire(mtmp) && adtyp == AD_COLD) mdam *= 2; mtmp->mhp -= mdam; mtmp->mhp -= (idamres + idamnonres); } if (mtmp->mhp <= 0) { /* KMH -- Don't blame the player for pets killing gas spores */ if (!flags.mon_moving) killed(mtmp); else monkilled(mtmp, "", (int)adtyp); } else if (!flags.mon_moving) setmangry(mtmp); } /* Do your injury last */ if (uhurt) { if ((type >= 0 || adtyp == AD_PHYS) && /* gas spores */ flags.verbose && olet != SCROLL_CLASS) You("are caught in the %s!", str); /* do property damage first, in case we end up leaving bones */ if (adtyp == AD_FIRE) burn_away_slime(); if (Invulnerable) { damu = 0; You("are unharmed!"); } else if (Half_physical_damage && adtyp == AD_PHYS) damu = (damu+1) / 2; if (adtyp == AD_FIRE) (void) burnarmor(&youmonst); destroy_item(SCROLL_CLASS, (int) adtyp); destroy_item(SPBOOK_CLASS, (int) adtyp); destroy_item(POTION_CLASS, (int) adtyp); destroy_item(RING_CLASS, (int) adtyp); destroy_item(WAND_CLASS, (int) adtyp); ugolemeffects((int) adtyp, damu); if (uhurt == 2) { if (Upolyd) u.mh -= damu; else u.uhp -= damu; flags.botl = 1; } if (u.uhp <= 0 || (Upolyd && u.mh <= 0)) { if (Upolyd) { rehumanize(); } else { if (olet == MON_EXPLODE) { /* killer handled by caller */ if (str != killer_buf && !generic) Strcpy(killer_buf, str); killer_format = KILLED_BY_AN; } else if (type >= 0 && olet != SCROLL_CLASS) { killer_format = NO_KILLER_PREFIX; Sprintf(killer_buf, "caught %sself in %s own %s", uhim(), uhis(), str); } else if (!strncmpi(str,"tower of flame", 8) || !strncmpi(str,"fireball", 8)) { killer_format = KILLED_BY_AN; Strcpy(killer_buf, str); } else { killer_format = KILLED_BY; Strcpy(killer_buf, str); } killer = killer_buf; /* Known BUG: BURNING suppresses corpse in bones data, but done does not handle killer reason correctly */ done((adtyp == AD_FIRE) ? BURNING : DIED); } } exercise(A_STR, FALSE); } if (shopdamage) { pay_for_damage(adtyp == AD_FIRE ? "burn away" : adtyp == AD_COLD ? "shatter" : adtyp == AD_DISN ? "disintegrate" : "destroy", FALSE); } /* explosions are noisy */ i = dam * dam; if (i < 50) i = 50; /* in case random damage is very small */ wake_nearto(x, y, i); } #endif /* OVL0 */ #ifdef OVL1 struct scatter_chain { struct scatter_chain *next; /* pointer to next scatter item */ struct obj *obj; /* pointer to the object */ xchar ox; /* location of */ xchar oy; /* item */ schar dx; /* direction of */ schar dy; /* travel */ int range; /* range of object */ boolean stopped; /* flag for in-motion/stopped */ }; /* * scflags: * VIS_EFFECTS Add visual effects to display * MAY_HITMON Objects may hit monsters * MAY_HITYOU Objects may hit hero * MAY_HIT Objects may hit you or monsters * MAY_DESTROY Objects may be destroyed at random * MAY_FRACTURE Stone objects can be fractured (statues, boulders) */ /* returns number of scattered objects */ long scatter(sx,sy,blastforce,scflags, obj) int sx,sy; /* location of objects to scatter */ int blastforce; /* force behind the scattering */ unsigned int scflags; struct obj *obj; /* only scatter this obj */ { register struct obj *otmp; register int tmp; int farthest = 0; uchar typ; long qtmp; boolean used_up; boolean individual_object = obj ? TRUE : FALSE; struct monst *mtmp; struct scatter_chain *stmp, *stmp2 = 0; struct scatter_chain *schain = (struct scatter_chain *)0; long total = 0L; while ((otmp = individual_object ? obj : level.objects[sx][sy]) != 0) { if (otmp->quan > 1L) { qtmp = otmp->quan - 1; if (qtmp > LARGEST_INT) qtmp = LARGEST_INT; qtmp = (long)rnd((int)qtmp); otmp = splitobj(otmp, qtmp); } else { obj = (struct obj *)0; /* all used */ } obj_extract_self(otmp); used_up = FALSE; /* 9 in 10 chance of fracturing boulders or statues */ if ((scflags & MAY_FRACTURE) && ((otmp->otyp == BOULDER) || (otmp->otyp == STATUE)) && rn2(10)) { if (otmp->otyp == BOULDER) { pline("%s apart.", Tobjnam(otmp, "break")); fracture_rock(otmp); place_object(otmp, sx, sy); if ((otmp = sobj_at(BOULDER, sx, sy)) != 0) { /* another boulder here, restack it to the top */ obj_extract_self(otmp); place_object(otmp, sx, sy); } } else { struct trap *trap; if ((trap = t_at(sx,sy)) && trap->ttyp == STATUE_TRAP) deltrap(trap); pline("%s.", Tobjnam(otmp, "crumble")); (void) break_statue(otmp); place_object(otmp, sx, sy); /* put fragments on floor */ } used_up = TRUE; /* 1 in 10 chance of destruction of obj; glass, egg destruction */ } else if ((scflags & MAY_DESTROY) && (!rn2(10) || (objects[otmp->otyp].oc_material == GLASS || otmp->otyp == EGG))) { if (breaks(otmp, (xchar)sx, (xchar)sy)) used_up = TRUE; } if (!used_up) { stmp = (struct scatter_chain *) alloc(sizeof(struct scatter_chain)); stmp->next = (struct scatter_chain *)0; stmp->obj = otmp; stmp->ox = sx; stmp->oy = sy; tmp = rn2(8); /* get the direction */ stmp->dx = xdir[tmp]; stmp->dy = ydir[tmp]; tmp = blastforce - (otmp->owt/40); if (tmp < 1) tmp = 1; stmp->range = rnd(tmp); /* anywhere up to that determ. by wt */ if (farthest < stmp->range) farthest = stmp->range; stmp->stopped = FALSE; if (!schain) schain = stmp; else stmp2->next = stmp; stmp2 = stmp; } } while (farthest-- > 0) { for (stmp = schain; stmp; stmp = stmp->next) { if ((stmp->range-- > 0) && (!stmp->stopped)) { bhitpos.x = stmp->ox + stmp->dx; bhitpos.y = stmp->oy + stmp->dy; typ = levl[bhitpos.x][bhitpos.y].typ; if(!isok(bhitpos.x, bhitpos.y)) { bhitpos.x -= stmp->dx; bhitpos.y -= stmp->dy; stmp->stopped = TRUE; } else if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) { bhitpos.x -= stmp->dx; bhitpos.y -= stmp->dy; stmp->stopped = TRUE; } else if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { if (scflags & MAY_HITMON) { stmp->range--; if (ohitmon(mtmp, stmp->obj, 1, FALSE)) { stmp->obj = (struct obj *)0; stmp->stopped = TRUE; } } } else if (bhitpos.x==u.ux && bhitpos.y==u.uy) { if (scflags & MAY_HITYOU) { int hitvalu, hitu; if (multi) nomul(0); hitvalu = 8 + stmp->obj->spe; if (bigmonst(youmonst.data)) hitvalu++; hitu = thitu(hitvalu, dmgval(stmp->obj, &youmonst), stmp->obj, (char *)0); if (hitu) { stmp->range -= 3; stop_occupation(); } } } else { if (scflags & VIS_EFFECTS) { /* tmp_at(bhitpos.x, bhitpos.y); */ /* delay_output(); */ } } stmp->ox = bhitpos.x; stmp->oy = bhitpos.y; } } } for (stmp = schain; stmp; stmp = stmp2) { int x,y; stmp2 = stmp->next; x = stmp->ox; y = stmp->oy; if (stmp->obj) { if ( x!=sx || y!=sy ) total += stmp->obj->quan; place_object(stmp->obj, x, y); stackobj(stmp->obj); } free((genericptr_t)stmp); newsym(x,y); } return total; } /* * Splatter burning oil from x,y to the surrounding area. * * This routine should really take a how and direction parameters. * The how is how it was caused, e.g. kicked verses thrown. The * direction is which way to spread the flaming oil. Different * "how"s would give different dispersal patterns. For example, * kicking a burning flask will splatter differently from a thrown * flask hitting the ground. * * For now, just perform a "regular" explosion. */ void splatter_burning_oil(x, y) int x, y; { /* ZT_SPELL(ZT_FIRE) = ZT_SPELL(AD_FIRE-1) = 10+(2-1) = 11 */ #define ZT_SPELL_O_FIRE 11 /* value kludge, see zap.c */ explode(x, y, ZT_SPELL_O_FIRE, d(4,4), BURNING_OIL, EXPL_FIERY); } #endif /* OVL1 */ /*explode.c*/ nethack-3.4.3/src/extralev.c0100644000000000000000000002121207764735041014435 0ustar rootroot/* SCCS Id: @(#)extralev.c 3.4 2001/09/06 */ /* Copyright 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ /* * Support code for "rogue"-style level. */ #include "hack.h" #ifdef REINCARNATION struct rogueroom { xchar rlx, rly; xchar dx, dy; boolean real; uchar doortable; int nroom; /* Only meaningful for "real" rooms */ }; #define UP 1 #define DOWN 2 #define LEFT 4 #define RIGHT 8 static NEARDATA struct rogueroom r[3][3]; STATIC_DCL void FDECL(roguejoin,(int,int,int,int,int)); STATIC_DCL void FDECL(roguecorr,(int,int,int)); STATIC_DCL void FDECL(miniwalk,(int,int)); STATIC_OVL void roguejoin(x1,y1,x2,y2, horiz) int x1,y1,x2,y2; int horiz; { register int x,y,middle; #ifndef MAX #define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif if (horiz) { middle = x1 + rn2(x2-x1+1); for(x=MIN(x1,middle); x<=MAX(x1,middle); x++) corr(x, y1); for(y=MIN(y1,y2); y<=MAX(y1,y2); y++) corr(middle,y); for(x=MIN(middle,x2); x<=MAX(middle,x2); x++) corr(x, y2); } else { middle = y1 + rn2(y2-y1+1); for(y=MIN(y1,middle); y<=MAX(y1,middle); y++) corr(x1, y); for(x=MIN(x1,x2); x<=MAX(x1,x2); x++) corr(x, middle); for(y=MIN(middle,y2); y<=MAX(middle,y2); y++) corr(x2,y); } } STATIC_OVL void roguecorr(x, y, dir) int x,y,dir; { register int fromx, fromy, tox, toy; if (dir==DOWN) { r[x][y].doortable &= ~DOWN; if (!r[x][y].real) { fromx = r[x][y].rlx; fromy = r[x][y].rly; fromx += 1 + 26*x; fromy += 7*y; } else { fromx = r[x][y].rlx + rn2(r[x][y].dx); fromy = r[x][y].rly + r[x][y].dy; fromx += 1 + 26*x; fromy += 7*y; if (!IS_WALL(levl[fromx][fromy].typ)) impossible("down: no wall at %d,%d?",fromx, fromy); dodoor(fromx, fromy, &rooms[r[x][y].nroom]); levl[fromx][fromy].doormask = D_NODOOR; fromy++; } if(y >= 2) { impossible("down door from %d,%d going nowhere?",x,y); return; } y++; r[x][y].doortable &= ~UP; if (!r[x][y].real) { tox = r[x][y].rlx; toy = r[x][y].rly; tox += 1 + 26*x; toy += 7*y; } else { tox = r[x][y].rlx + rn2(r[x][y].dx); toy = r[x][y].rly - 1; tox += 1 + 26*x; toy += 7*y; if (!IS_WALL(levl[tox][toy].typ)) impossible("up: no wall at %d,%d?",tox,toy); dodoor(tox, toy, &rooms[r[x][y].nroom]); levl[tox][toy].doormask = D_NODOOR; toy--; } roguejoin(fromx, fromy, tox, toy, FALSE); return; } else if (dir == RIGHT) { r[x][y].doortable &= ~RIGHT; if (!r[x][y].real) { fromx = r[x][y].rlx; fromy = r[x][y].rly; fromx += 1 + 26*x; fromy += 7*y; } else { fromx = r[x][y].rlx + r[x][y].dx; fromy = r[x][y].rly + rn2(r[x][y].dy); fromx += 1 + 26*x; fromy += 7*y; if (!IS_WALL(levl[fromx][fromy].typ)) impossible("down: no wall at %d,%d?",fromx, fromy); dodoor(fromx, fromy, &rooms[r[x][y].nroom]); levl[fromx][fromy].doormask = D_NODOOR; fromx++; } if(x >= 2) { impossible("right door from %d,%d going nowhere?",x,y); return; } x++; r[x][y].doortable &= ~LEFT; if (!r[x][y].real) { tox = r[x][y].rlx; toy = r[x][y].rly; tox += 1 + 26*x; toy += 7*y; } else { tox = r[x][y].rlx - 1; toy = r[x][y].rly + rn2(r[x][y].dy); tox += 1 + 26*x; toy += 7*y; if (!IS_WALL(levl[tox][toy].typ)) impossible("left: no wall at %d,%d?",tox,toy); dodoor(tox, toy, &rooms[r[x][y].nroom]); levl[tox][toy].doormask = D_NODOOR; tox--; } roguejoin(fromx, fromy, tox, toy, TRUE); return; } else impossible("corridor in direction %d?",dir); } /* Modified walkfrom() from mkmaze.c */ STATIC_OVL void miniwalk(x, y) int x,y; { register int q, dir; int dirs[4]; while(1) { q = 0; #define doorhere (r[x][y].doortable) if (x>0 && (!(doorhere & LEFT)) && (!r[x-1][y].doortable || !rn2(10))) dirs[q++] = 0; if (x<2 && (!(doorhere & RIGHT)) && (!r[x+1][y].doortable || !rn2(10))) dirs[q++] = 1; if (y>0 && (!(doorhere & UP)) && (!r[x][y-1].doortable || !rn2(10))) dirs[q++] = 2; if (y<2 && (!(doorhere & DOWN)) && (!r[x][y+1].doortable || !rn2(10))) dirs[q++] = 3; /* Rogue levels aren't just 3 by 3 mazes; they have some extra * connections, thus that 1/10 chance */ if (!q) return; dir = dirs[rn2(q)]; switch(dir) { /* Move in direction */ case 0: doorhere |= LEFT; x--; doorhere |= RIGHT; break; case 1: doorhere |= RIGHT; x++; doorhere |= LEFT; break; case 2: doorhere |= UP; y--; doorhere |= DOWN; break; case 3: doorhere |= DOWN; y++; doorhere |= UP; break; } miniwalk(x,y); } } void makeroguerooms() { register int x,y; /* Rogue levels are structured 3 by 3, with each section containing * a room or an intersection. The minimum width is 2 each way. * One difference between these and "real" Rogue levels: real Rogue * uses 24 rows and NetHack only 23. So we cheat a bit by making the * second row of rooms not as deep. * * Each normal space has 6/7 rows and 25 columns in which a room may * actually be placed. Walls go from rows 0-5/6 and columns 0-24. * Not counting walls, the room may go in * rows 1-5 and columns 1-23 (numbering starting at 0). A room * coordinate of this type may be converted to a level coordinate * by adding 1+28*x to the column, and 7*y to the row. (The 1 * is because column 0 isn't used [we only use 1-78]). * Room height may be 2-4 (2-5 on last row), length 2-23 (not * counting walls) */ #define here r[x][y] nroom = 0; for(y=0; y<3; y++) for(x=0; x<3; x++) { /* Note: we want to insure at least 1 room. So, if the * first 8 are all dummies, force the last to be a room. */ if (!rn2(5) && (nroom || (x<2 && y<2))) { /* Arbitrary: dummy rooms may only go where real * ones do. */ here.real = FALSE; here.rlx = rn1(22, 2); here.rly = rn1((y==2)?4:3, 2); } else { here.real = TRUE; here.dx = rn1(22, 2); /* 2-23 long, plus walls */ here.dy = rn1((y==2)?4:3, 2); /* 2-5 high, plus walls */ /* boundaries of room floor */ here.rlx = rnd(23 - here.dx + 1); here.rly = rnd(((y==2) ? 5 : 4)- here.dy + 1); nroom++; } here.doortable = 0; } miniwalk(rn2(3), rn2(3)); nroom = 0; for(y=0; y<3; y++) for(x=0; x<3; x++) { if (here.real) { /* Make a room */ int lowx, lowy, hix, hiy; r[x][y].nroom = nroom; smeq[nroom] = nroom; lowx = 1 + 26*x + here.rlx; lowy = 7*y + here.rly; hix = 1 + 26*x + here.rlx + here.dx - 1; hiy = 7*y + here.rly + here.dy - 1; /* Strictly speaking, it should be lit only if above * level 10, but since Rogue rooms are only * encountered below level 10, use !rn2(7). */ add_room(lowx, lowy, hix, hiy, (boolean) !rn2(7), OROOM, FALSE); } } /* Now, add connecting corridors. */ for(y=0; y<3; y++) for(x=0; x<3; x++) { if (here.doortable & DOWN) roguecorr(x, y, DOWN); if (here.doortable & RIGHT) roguecorr(x, y, RIGHT); if (here.doortable & LEFT) impossible ("left end of %d, %d never connected?",x,y); if (here.doortable & UP) impossible ("up end of %d, %d never connected?",x,y); } } void corr(x,y) int x, y; { if (rn2(50)) { levl[x][y].typ = CORR; } else { levl[x][y].typ = SCORR; } } void makerogueghost() { register struct monst *ghost; struct obj *ghostobj; struct mkroom *croom; int x,y; if (!nroom) return; /* Should never happen */ croom = &rooms[rn2(nroom)]; x = somex(croom); y = somey(croom); if (!(ghost = makemon(&mons[PM_GHOST], x, y, NO_MM_FLAGS))) return; ghost->msleeping = 1; ghost = christen_monst(ghost, roguename()); if (rn2(4)) { ghostobj = mksobj_at(FOOD_RATION, x, y, FALSE, FALSE); ghostobj->quan = (long) rnd(7); ghostobj->owt = weight(ghostobj); } if (rn2(2)) { ghostobj = mksobj_at(MACE, x, y, FALSE, FALSE); ghostobj->spe = rnd(3); if (rn2(4)) curse(ghostobj); } else { ghostobj = mksobj_at(TWO_HANDED_SWORD, x, y, FALSE, FALSE); ghostobj->spe = rnd(5) - 2; if (rn2(4)) curse(ghostobj); } ghostobj = mksobj_at(BOW, x, y, FALSE, FALSE); ghostobj->spe = 1; if (rn2(4)) curse(ghostobj); ghostobj = mksobj_at(ARROW, x, y, FALSE, FALSE); ghostobj->spe = 0; ghostobj->quan = (long) rn1(10,25); ghostobj->owt = weight(ghostobj); if (rn2(4)) curse(ghostobj); if (rn2(2)) { ghostobj = mksobj_at(RING_MAIL, x, y, FALSE, FALSE); ghostobj->spe = rn2(3); if (!rn2(3)) ghostobj->oerodeproof = TRUE; if (rn2(4)) curse(ghostobj); } else { ghostobj = mksobj_at(PLATE_MAIL, x, y, FALSE, FALSE); ghostobj->spe = rnd(5) - 2; if (!rn2(3)) ghostobj->oerodeproof = TRUE; if (rn2(4)) curse(ghostobj); } if (rn2(2)) { ghostobj = mksobj_at(FAKE_AMULET_OF_YENDOR, x, y, TRUE, FALSE); ghostobj->known = TRUE; } } #endif /* REINCARNATION */ /*extralev.c*/ nethack-3.4.3/src/files.c0100644000000000000000000016324507764735041013722 0ustar rootroot/* SCCS Id: @(#)files.c 3.4 2003/11/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" #ifdef TTY_GRAPHICS #include "wintty.h" /* more() */ #endif #include #if !defined(MAC) && !defined(O_WRONLY) && !defined(AZTEC_C) #include #endif #include #ifdef _MSC_VER /* MSC 6.0 defines errno quite differently */ # if (_MSC_VER >= 600) # define SKIP_ERRNO # endif #else # ifdef NHSTDC # define SKIP_ERRNO # endif #endif #ifndef SKIP_ERRNO # ifdef _DCC const # endif extern int errno; #endif #if defined(UNIX) && defined(QT_GRAPHICS) #include #endif #if defined(UNIX) || defined(VMS) #include #endif #if defined(MSDOS) || defined(OS2) || defined(TOS) || defined(WIN32) # ifndef GNUDOS #include # else #include # endif #endif #ifndef O_BINARY /* used for micros, no-op for others */ # define O_BINARY 0 #endif #ifdef PREFIXES_IN_USE #define FQN_NUMBUF 4 static char fqn_filename_buffer[FQN_NUMBUF][FQN_MAX_FILENAME]; #endif #if !defined(MFLOPPY) && !defined(VMS) && !defined(WIN32) char bones[] = "bonesnn.xxx"; char lock[PL_NSIZ+14] = "1lock"; /* long enough for uid+name+.99 */ #else # if defined(MFLOPPY) char bones[FILENAME]; /* pathname of bones files */ char lock[FILENAME]; /* pathname of level files */ # endif # if defined(VMS) char bones[] = "bonesnn.xxx;1"; char lock[PL_NSIZ+17] = "1lock"; /* long enough for _uid+name+.99;1 */ # endif # if defined(WIN32) char bones[] = "bonesnn.xxx"; char lock[PL_NSIZ+25]; /* long enough for username+-+name+.99 */ # endif #endif #if defined(UNIX) || defined(__BEOS__) #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */ #else # ifdef VMS #define SAVESIZE (PL_NSIZ + 22) /* [.save]player.e;1 */ # else # if defined(WIN32) #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */ # else #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */ # endif # endif #endif char SAVEF[SAVESIZE]; /* holds relative path of save file from playground */ #ifdef MICRO char SAVEP[SAVESIZE]; /* holds path of directory for save file */ #endif #ifdef HOLD_LOCKFILE_OPEN struct level_ftrack { int init; int fd; /* file descriptor for level file */ int oflag; /* open flags */ boolean nethack_thinks_it_is_open; /* Does NetHack think it's open? */ } lftrack; # if defined(WIN32) #include # endif #endif /*HOLD_LOCKFILE_OPEN*/ #ifdef WIZARD #define WIZKIT_MAX 128 static char wizkit[WIZKIT_MAX]; STATIC_DCL FILE *NDECL(fopen_wizkit_file); #endif #ifdef AMIGA extern char PATH[]; /* see sys/amiga/amidos.c */ extern char bbs_id[]; static int lockptr; # ifdef __SASC_60 #include # endif #include extern void FDECL(amii_set_text_font, ( char *, int )); #endif #if defined(WIN32) || defined(MSDOS) static int lockptr; # ifdef MSDOS #define Delay(a) msleep(a) # endif #define Close close #ifndef WIN_CE #define DeleteFile unlink #endif #endif #ifdef MAC # define unlink macunlink #endif #ifdef USER_SOUNDS extern char *sounddir; #endif extern int n_dgns; /* from dungeon.c */ STATIC_DCL char *FDECL(set_bonesfile_name, (char *,d_level*)); STATIC_DCL char *NDECL(set_bonestemp_name); #ifdef COMPRESS STATIC_DCL void FDECL(redirect, (const char *,const char *,FILE *,BOOLEAN_P)); STATIC_DCL void FDECL(docompress_file, (const char *,BOOLEAN_P)); #endif STATIC_DCL char *FDECL(make_lockname, (const char *,char *)); STATIC_DCL FILE *FDECL(fopen_config_file, (const char *)); STATIC_DCL int FDECL(get_uchars, (FILE *,char *,char *,uchar *,BOOLEAN_P,int,const char *)); int FDECL(parse_config_line, (FILE *,char *,char *,char *)); #ifdef NOCWD_ASSUMPTIONS STATIC_DCL void FDECL(adjust_prefix, (char *, int)); #endif #ifdef SELF_RECOVER STATIC_DCL boolean FDECL(copy_bytes, (int, int)); #endif #ifdef HOLD_LOCKFILE_OPEN STATIC_DCL int FDECL(open_levelfile_exclusively, (const char *, int, int)); #endif /* * fname_encode() * * Args: * legal zero-terminated list of acceptable file name characters * quotechar lead-in character used to quote illegal characters as hex digits * s string to encode * callerbuf buffer to house result * bufsz size of callerbuf * * Notes: * The hex digits 0-9 and A-F are always part of the legal set due to * their use in the encoding scheme, even if not explicitly included in 'legal'. * * Sample: * The following call: * (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", * '%', "This is a % test!", buf, 512); * results in this encoding: * "This%20is%20a%20%25%20test%21" */ char * fname_encode(legal, quotechar, s, callerbuf, bufsz) const char *legal; char quotechar; char *s, *callerbuf; int bufsz; { char *sp, *op; int cnt = 0; static char hexdigits[] = "0123456789ABCDEF"; sp = s; op = callerbuf; *op = '\0'; while (*sp) { /* Do we have room for one more character or encoding? */ if ((bufsz - cnt) <= 4) return callerbuf; if (*sp == quotechar) { (void)sprintf(op, "%c%02X", quotechar, *sp); op += 3; cnt += 3; } else if ((index(legal, *sp) != 0) || (index(hexdigits, *sp) != 0)) { *op++ = *sp; *op = '\0'; cnt++; } else { (void)sprintf(op,"%c%02X", quotechar, *sp); op += 3; cnt += 3; } sp++; } return callerbuf; } /* * fname_decode() * * Args: * quotechar lead-in character used to quote illegal characters as hex digits * s string to decode * callerbuf buffer to house result * bufsz size of callerbuf */ char * fname_decode(quotechar, s, callerbuf, bufsz) char quotechar; char *s, *callerbuf; int bufsz; { char *sp, *op; int k,calc,cnt = 0; static char hexdigits[] = "0123456789ABCDEF"; sp = s; op = callerbuf; *op = '\0'; calc = 0; while (*sp) { /* Do we have room for one more character? */ if ((bufsz - cnt) <= 2) return callerbuf; if (*sp == quotechar) { sp++; for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break; if (k >= 16) return callerbuf; /* impossible, so bail */ calc = k << 4; sp++; for (k=0; k < 16; ++k) if (*sp == hexdigits[k]) break; if (k >= 16) return callerbuf; /* impossible, so bail */ calc += k; sp++; *op++ = calc; *op = '\0'; } else { *op++ = *sp++; *op = '\0'; } cnt++; } return callerbuf; } #ifndef PREFIXES_IN_USE /*ARGSUSED*/ #endif const char * fqname(basename, whichprefix, buffnum) const char *basename; int whichprefix, buffnum; { #ifndef PREFIXES_IN_USE return basename; #else if (!basename || whichprefix < 0 || whichprefix >= PREFIX_COUNT) return basename; if (!fqn_prefix[whichprefix]) return basename; if (buffnum < 0 || buffnum >= FQN_NUMBUF) { impossible("Invalid fqn_filename_buffer specified: %d", buffnum); buffnum = 0; } if (strlen(fqn_prefix[whichprefix]) + strlen(basename) >= FQN_MAX_FILENAME) { impossible("fqname too long: %s + %s", fqn_prefix[whichprefix], basename); return basename; /* XXX */ } Strcpy(fqn_filename_buffer[buffnum], fqn_prefix[whichprefix]); return strcat(fqn_filename_buffer[buffnum], basename); #endif } /* reasonbuf must be at least BUFSZ, supplied by caller */ /*ARGSUSED*/ int validate_prefix_locations(reasonbuf) char *reasonbuf; { #if defined(NOCWD_ASSUMPTIONS) FILE *fp; const char *filename; int prefcnt, failcount = 0; char panicbuf1[BUFSZ], panicbuf2[BUFSZ], *details; if (reasonbuf) reasonbuf[0] = '\0'; for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) { /* don't test writing to configdir or datadir; they're readonly */ if (prefcnt == CONFIGPREFIX || prefcnt == DATAPREFIX) continue; filename = fqname("validate", prefcnt, 3); if ((fp = fopen(filename, "w"))) { fclose(fp); (void) unlink(filename); } else { if (reasonbuf) { if (failcount) Strcat(reasonbuf,", "); Strcat(reasonbuf, fqn_prefix_names[prefcnt]); } /* the paniclog entry gets the value of errno as well */ Sprintf(panicbuf1,"Invalid %s", fqn_prefix_names[prefcnt]); #if defined (NHSTDC) && !defined(NOTSTDC) if (!(details = strerror(errno))) #endif details = ""; Sprintf(panicbuf2,"\"%s\", (%d) %s", fqn_prefix[prefcnt], errno, details); paniclog(panicbuf1, panicbuf2); failcount++; } } if (failcount) return 0; else #endif return 1; } /* fopen a file, with OS-dependent bells and whistles */ /* NOTE: a simpler version of this routine also exists in util/dlb_main.c */ FILE * fopen_datafile(filename, mode, prefix) const char *filename, *mode; int prefix; { FILE *fp; filename = fqname(filename, prefix, prefix == TROUBLEPREFIX ? 3 : 0); #ifdef VMS /* essential to have punctuation, to avoid logical names */ { char tmp[BUFSIZ]; if (!index(filename, '.') && !index(filename, ';')) filename = strcat(strcpy(tmp, filename), ";0"); fp = fopen(filename, mode, "mbc=16"); } #else fp = fopen(filename, mode); #endif return fp; } /* ---------- BEGIN LEVEL FILE HANDLING ----------- */ #ifdef MFLOPPY /* Set names for bones[] and lock[] */ void set_lock_and_bones() { if (!ramdisk) { Strcpy(levels, permbones); Strcpy(bones, permbones); } append_slash(permbones); append_slash(levels); #ifdef AMIGA strncat(levels, bbs_id, PATHLEN); #endif append_slash(bones); Strcat(bones, "bonesnn.*"); Strcpy(lock, levels); #ifndef AMIGA Strcat(lock, alllevels); #endif return; } #endif /* MFLOPPY */ /* Construct a file name for a level-type file, which is of the form * something.level (with any old level stripped off). * This assumes there is space on the end of 'file' to append * a two digit number. This is true for 'level' * but be careful if you use it for other things -dgk */ void set_levelfile_name(file, lev) char *file; int lev; { char *tf; tf = rindex(file, '.'); if (!tf) tf = eos(file); Sprintf(tf, ".%d", lev); #ifdef VMS Strcat(tf, ";1"); #endif return; } int create_levelfile(lev, errbuf) int lev; char errbuf[]; { int fd; const char *fq_lock; if (errbuf) *errbuf = '\0'; set_levelfile_name(lock, lev); fq_lock = fqname(lock, LEVELPREFIX, 0); #if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already * exists and is currently longer. */ # ifdef HOLD_LOCKFILE_OPEN if (lev == 0) fd = open_levelfile_exclusively(fq_lock, lev, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY); else # endif fd = open(fq_lock, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); #else # ifdef MAC fd = maccreat(fq_lock, LEVL_TYPE); # else fd = creat(fq_lock, FCMASK); # endif #endif /* MICRO || WIN32 */ if (fd >= 0) level_info[lev].flags |= LFILE_EXISTS; else if (errbuf) /* failure explanation */ Sprintf(errbuf, "Cannot create file \"%s\" for level %d (errno %d).", lock, lev, errno); return fd; } int open_levelfile(lev, errbuf) int lev; char errbuf[]; { int fd; const char *fq_lock; if (errbuf) *errbuf = '\0'; set_levelfile_name(lock, lev); fq_lock = fqname(lock, LEVELPREFIX, 0); #ifdef MFLOPPY /* If not currently accessible, swap it in. */ if (level_info[lev].where != ACTIVE) swapin_file(lev); #endif #ifdef MAC fd = macopen(fq_lock, O_RDONLY | O_BINARY, LEVL_TYPE); #else # ifdef HOLD_LOCKFILE_OPEN if (lev == 0) fd = open_levelfile_exclusively(fq_lock, lev, O_RDONLY | O_BINARY ); else # endif fd = open(fq_lock, O_RDONLY | O_BINARY, 0); #endif /* for failure, return an explanation that our caller can use; settle for `lock' instead of `fq_lock' because the latter might end up being too big for nethack's BUFSZ */ if (fd < 0 && errbuf) Sprintf(errbuf, "Cannot open file \"%s\" for level %d (errno %d).", lock, lev, errno); return fd; } void delete_levelfile(lev) int lev; { /* * Level 0 might be created by port specific code that doesn't * call create_levfile(), so always assume that it exists. */ if (lev == 0 || (level_info[lev].flags & LFILE_EXISTS)) { set_levelfile_name(lock, lev); #ifdef HOLD_LOCKFILE_OPEN if (lev == 0) really_close(); #endif (void) unlink(fqname(lock, LEVELPREFIX, 0)); level_info[lev].flags &= ~LFILE_EXISTS; } } void clearlocks() { #if !defined(PC_LOCKING) && defined(MFLOPPY) && !defined(AMIGA) eraseall(levels, alllevels); if (ramdisk) eraseall(permbones, alllevels); #else register int x; # if defined(UNIX) || defined(VMS) (void) signal(SIGHUP, SIG_IGN); # endif /* can't access maxledgerno() before dungeons are created -dlc */ for (x = (n_dgns ? maxledgerno() : 0); x >= 0; x--) delete_levelfile(x); /* not all levels need be present */ #endif } #ifdef HOLD_LOCKFILE_OPEN STATIC_OVL int open_levelfile_exclusively(name, lev, oflag) const char *name; int lev, oflag; { int reslt, fd; if (!lftrack.init) { lftrack.init = 1; lftrack.fd = -1; } if (lftrack.fd >= 0) { /* check for compatible access */ if (lftrack.oflag == oflag) { fd = lftrack.fd; reslt = lseek(fd, 0L, SEEK_SET); if (reslt == -1L) panic("open_levelfile_exclusively: lseek failed %d", errno); lftrack.nethack_thinks_it_is_open = TRUE; } else { really_close(); fd = sopen(name, oflag,SH_DENYRW, FCMASK); lftrack.fd = fd; lftrack.oflag = oflag; lftrack.nethack_thinks_it_is_open = TRUE; } } else { fd = sopen(name, oflag,SH_DENYRW, FCMASK); lftrack.fd = fd; lftrack.oflag = oflag; if (fd >= 0) lftrack.nethack_thinks_it_is_open = TRUE; } return fd; } void really_close() { int fd = lftrack.fd; lftrack.nethack_thinks_it_is_open = FALSE; lftrack.fd = -1; lftrack.oflag = 0; (void)_close(fd); return; } int close(fd) int fd; { if (lftrack.fd == fd) { really_close(); /* close it, but reopen it to hold it */ fd = open_levelfile(0, (char *)0); lftrack.nethack_thinks_it_is_open = FALSE; return 0; } return _close(fd); } #endif /* ---------- END LEVEL FILE HANDLING ----------- */ /* ---------- BEGIN BONES FILE HANDLING ----------- */ /* set up "file" to be file name for retrieving bones, and return a * bonesid to be read/written in the bones file. */ STATIC_OVL char * set_bonesfile_name(file, lev) char *file; d_level *lev; { s_level *sptr; char *dptr; Sprintf(file, "bon%c%s", dungeons[lev->dnum].boneid, In_quest(lev) ? urole.filecode : "0"); dptr = eos(file); if ((sptr = Is_special(lev)) != 0) Sprintf(dptr, ".%c", sptr->boneid); else Sprintf(dptr, ".%d", lev->dlevel); #ifdef VMS Strcat(dptr, ";1"); #endif return(dptr-2); } /* set up temporary file name for writing bones, to avoid another game's * trying to read from an uncompleted bones file. we want an uncontentious * name, so use one in the namespace reserved for this game's level files. * (we are not reading or writing level files while writing bones files, so * the same array may be used instead of copying.) */ STATIC_OVL char * set_bonestemp_name() { char *tf; tf = rindex(lock, '.'); if (!tf) tf = eos(lock); Sprintf(tf, ".bn"); #ifdef VMS Strcat(tf, ";1"); #endif return lock; } int create_bonesfile(lev, bonesid, errbuf) d_level *lev; char **bonesid; char errbuf[]; { const char *file; int fd; if (errbuf) *errbuf = '\0'; *bonesid = set_bonesfile_name(bones, lev); file = set_bonestemp_name(); file = fqname(file, BONESPREFIX, 0); #if defined(MICRO) || defined(WIN32) /* Use O_TRUNC to force the file to be shortened if it already * exists and is currently longer. */ fd = open(file, O_WRONLY |O_CREAT | O_TRUNC | O_BINARY, FCMASK); #else # ifdef MAC fd = maccreat(file, BONE_TYPE); # else fd = creat(file, FCMASK); # endif #endif if (fd < 0 && errbuf) /* failure explanation */ Sprintf(errbuf, "Cannot create bones \"%s\", id %s (errno %d).", lock, *bonesid, errno); # if defined(VMS) && !defined(SECURE) /* Re-protect bones file with world:read+write+execute+delete access. umask() doesn't seem very reliable; also, vaxcrtl won't let us set delete access without write access, which is what's really wanted. Can't simply create it with the desired protection because creat ANDs the mask with the user's default protection, which usually denies some or all access to world. */ (void) chmod(file, FCMASK | 007); /* allow other users full access */ # endif /* VMS && !SECURE */ return fd; } #ifdef MFLOPPY /* remove partial bonesfile in process of creation */ void cancel_bonesfile() { const char *tempname; tempname = set_bonestemp_name(); tempname = fqname(tempname, BONESPREFIX, 0); (void) unlink(tempname); } #endif /* MFLOPPY */ /* move completed bones file to proper name */ void commit_bonesfile(lev) d_level *lev; { const char *fq_bones, *tempname; int ret; (void) set_bonesfile_name(bones, lev); fq_bones = fqname(bones, BONESPREFIX, 0); tempname = set_bonestemp_name(); tempname = fqname(tempname, BONESPREFIX, 1); #if (defined(SYSV) && !defined(SVR4)) || defined(GENIX) /* old SYSVs don't have rename. Some SVR3's may, but since they * also have link/unlink, it doesn't matter. :-) */ (void) unlink(fq_bones); ret = link(tempname, fq_bones); ret += unlink(tempname); #else ret = rename(tempname, fq_bones); #endif #ifdef WIZARD if (wizard && ret != 0) pline("couldn't rename %s to %s.", tempname, fq_bones); #endif } int open_bonesfile(lev, bonesid) d_level *lev; char **bonesid; { const char *fq_bones; int fd; *bonesid = set_bonesfile_name(bones, lev); fq_bones = fqname(bones, BONESPREFIX, 0); uncompress(fq_bones); /* no effect if nonexistent */ #ifdef MAC fd = macopen(fq_bones, O_RDONLY | O_BINARY, BONE_TYPE); #else fd = open(fq_bones, O_RDONLY | O_BINARY, 0); #endif return fd; } int delete_bonesfile(lev) d_level *lev; { (void) set_bonesfile_name(bones, lev); return !(unlink(fqname(bones, BONESPREFIX, 0)) < 0); } /* assume we're compressing the recently read or created bonesfile, so the * file name is already set properly */ void compress_bonesfile() { compress(fqname(bones, BONESPREFIX, 0)); } /* ---------- END BONES FILE HANDLING ----------- */ /* ---------- BEGIN SAVE FILE HANDLING ----------- */ /* set savefile name in OS-dependent manner from pre-existing plname, * avoiding troublesome characters */ void set_savefile_name() { #if defined(WIN32) char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; #endif #ifdef VMS Sprintf(SAVEF, "[.save]%d%s", getuid(), plname); regularize(SAVEF+7); Strcat(SAVEF, ";1"); #else # if defined(MICRO) Strcpy(SAVEF, SAVEP); # ifdef AMIGA strncat(SAVEF, bbs_id, PATHLEN); # endif { int i = strlen(SAVEP); # ifdef AMIGA /* plname has to share space with SAVEP and ".sav" */ (void)strncat(SAVEF, plname, FILENAME - i - 4); # else (void)strncat(SAVEF, plname, 8); # endif regularize(SAVEF+i); } Strcat(SAVEF, ".sav"); # else # if defined(WIN32) /* Obtain the name of the logged on user and incorporate * it into the name. */ Sprintf(fnamebuf, "%s-%s", get_username(0), plname); (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', fnamebuf, encodedfnamebuf, BUFSZ); Sprintf(SAVEF, "%s.NetHack-saved-game", encodedfnamebuf); # else Sprintf(SAVEF, "save/%d%s", (int)getuid(), plname); regularize(SAVEF+5); /* avoid . or / in name */ # endif /* WIN32 */ # endif /* MICRO */ #endif /* VMS */ } #ifdef INSURANCE void save_savefile_name(fd) int fd; { (void) write(fd, (genericptr_t) SAVEF, sizeof(SAVEF)); } #endif #if defined(WIZARD) && !defined(MICRO) /* change pre-existing savefile name to indicate an error savefile */ void set_error_savefile() { # ifdef VMS { char *semi_colon = rindex(SAVEF, ';'); if (semi_colon) *semi_colon = '\0'; } Strcat(SAVEF, ".e;1"); # else # ifdef MAC Strcat(SAVEF, "-e"); # else Strcat(SAVEF, ".e"); # endif # endif } #endif /* create save file, overwriting one if it already exists */ int create_savefile() { const char *fq_save; int fd; fq_save = fqname(SAVEF, SAVEPREFIX, 0); #if defined(MICRO) || defined(WIN32) fd = open(fq_save, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); #else # ifdef MAC fd = maccreat(fq_save, SAVE_TYPE); # else fd = creat(fq_save, FCMASK); # endif # if defined(VMS) && !defined(SECURE) /* Make sure the save file is owned by the current process. That's the default for non-privileged users, but for priv'd users the file will be owned by the directory's owner instead of the user. */ # ifdef getuid /*(see vmsunix.c)*/ # undef getuid # endif (void) chown(fq_save, getuid(), getgid()); # endif /* VMS && !SECURE */ #endif /* MICRO */ return fd; } /* open savefile for reading */ int open_savefile() { const char *fq_save; int fd; fq_save = fqname(SAVEF, SAVEPREFIX, 0); #ifdef MAC fd = macopen(fq_save, O_RDONLY | O_BINARY, SAVE_TYPE); #else fd = open(fq_save, O_RDONLY | O_BINARY, 0); #endif return fd; } /* delete savefile */ int delete_savefile() { (void) unlink(fqname(SAVEF, SAVEPREFIX, 0)); return 0; /* for restore_saved_game() (ex-xxxmain.c) test */ } /* try to open up a save file and prepare to restore it */ int restore_saved_game() { const char *fq_save; int fd; set_savefile_name(); #ifdef MFLOPPY if (!saveDiskPrompt(1)) return -1; #endif /* MFLOPPY */ fq_save = fqname(SAVEF, SAVEPREFIX, 0); uncompress(fq_save); if ((fd = open_savefile()) < 0) return fd; if (!uptodate(fd, fq_save)) { (void) close(fd), fd = -1; (void) delete_savefile(); } return fd; } #if defined(UNIX) && defined(QT_GRAPHICS) /*ARGSUSED*/ static char* plname_from_file(filename) const char* filename; { #ifdef STORE_PLNAME_IN_FILE int fd; char* result = 0; Strcpy(SAVEF,filename); #ifdef COMPRESS_EXTENSION SAVEF[strlen(SAVEF)-strlen(COMPRESS_EXTENSION)] = '\0'; #endif uncompress(SAVEF); if ((fd = open_savefile()) >= 0) { if (uptodate(fd, filename)) { char tplname[PL_NSIZ]; mread(fd, (genericptr_t) tplname, PL_NSIZ); result = strdup(tplname); } (void) close(fd); } compress(SAVEF); return result; #else # if defined(UNIX) && defined(QT_GRAPHICS) /* Name not stored in save file, so we have to extract it from the filename, which loses information (eg. "/", "_", and "." characters are lost. */ int k; int uid; char name[64]; /* more than PL_NSIZ */ #ifdef COMPRESS_EXTENSION #define EXTSTR COMPRESS_EXTENSION #else #define EXTSTR "" #endif if ( sscanf( filename, "%*[^/]/%d%63[^.]" EXTSTR, &uid, name ) == 2 ) { #undef EXTSTR /* "_" most likely means " ", which certainly looks nicer */ for (k=0; name[k]; k++) if ( name[k]=='_' ) name[k]=' '; return strdup(name); } else # endif { return 0; } #endif } #endif /* defined(UNIX) && defined(QT_GRAPHICS) */ char** get_saved_games() { #if defined(UNIX) && defined(QT_GRAPHICS) int myuid=getuid(); struct dirent **namelist; int n = scandir("save", &namelist, 0, alphasort);; if ( n > 0 ) { int i,j=0; char** result = (char**)alloc((n+1)*sizeof(char*)); /* at most */ for (i=0; id_name, "%d%63s", &uid, name ) == 2 ) { if ( uid == myuid ) { char filename[BUFSZ]; char* r; Sprintf(filename,"save/%d%s",uid,name); r = plname_from_file(filename); if ( r ) result[j++] = r; } } } result[j++] = 0; return result; } else #endif { return 0; } } void free_saved_games(saved) char** saved; { if ( saved ) { int i=0; while (saved[i]) free((genericptr_t)saved[i++]); free((genericptr_t)saved); } } /* ---------- END SAVE FILE HANDLING ----------- */ /* ---------- BEGIN FILE COMPRESSION HANDLING ----------- */ #ifdef COMPRESS STATIC_OVL void redirect(filename, mode, stream, uncomp) const char *filename, *mode; FILE *stream; boolean uncomp; { if (freopen(filename, mode, stream) == (FILE *)0) { (void) fprintf(stderr, "freopen of %s for %scompress failed\n", filename, uncomp ? "un" : ""); terminate(EXIT_FAILURE); } } /* * using system() is simpler, but opens up security holes and causes * problems on at least Interactive UNIX 3.0.1 (SVR3.2), where any * setuid is renounced by /bin/sh, so the files cannot be accessed. * * cf. child() in unixunix.c. */ STATIC_OVL void docompress_file(filename, uncomp) const char *filename; boolean uncomp; { char cfn[80]; FILE *cf; const char *args[10]; # ifdef COMPRESS_OPTIONS char opts[80]; # endif int i = 0; int f; # ifdef TTY_GRAPHICS boolean istty = !strncmpi(windowprocs.name, "tty", 3); # endif Strcpy(cfn, filename); # ifdef COMPRESS_EXTENSION Strcat(cfn, COMPRESS_EXTENSION); # endif /* when compressing, we know the file exists */ if (uncomp) { if ((cf = fopen(cfn, RDBMODE)) == (FILE *)0) return; (void) fclose(cf); } args[0] = COMPRESS; if (uncomp) args[++i] = "-d"; /* uncompress */ # ifdef COMPRESS_OPTIONS { /* we can't guarantee there's only one additional option, sigh */ char *opt; boolean inword = FALSE; Strcpy(opts, COMPRESS_OPTIONS); opt = opts; while (*opt) { if ((*opt == ' ') || (*opt == '\t')) { if (inword) { *opt = '\0'; inword = FALSE; } } else if (!inword) { args[++i] = opt; inword = TRUE; } opt++; } } # endif args[++i] = (char *)0; # ifdef TTY_GRAPHICS /* If we don't do this and we are right after a y/n question *and* * there is an error message from the compression, the 'y' or 'n' can * end up being displayed after the error message. */ if (istty) mark_synch(); # endif f = fork(); if (f == 0) { /* child */ # ifdef TTY_GRAPHICS /* any error messages from the compression must come out after * the first line, because the more() to let the user read * them will have to clear the first line. This should be * invisible if there are no error messages. */ if (istty) raw_print(""); # endif /* run compressor without privileges, in case other programs * have surprises along the line of gzip once taking filenames * in GZIP. */ /* assume all compressors will compress stdin to stdout * without explicit filenames. this is true of at least * compress and gzip, those mentioned in config.h. */ if (uncomp) { redirect(cfn, RDBMODE, stdin, uncomp); redirect(filename, WRBMODE, stdout, uncomp); } else { redirect(filename, RDBMODE, stdin, uncomp); redirect(cfn, WRBMODE, stdout, uncomp); } (void) setgid(getgid()); (void) setuid(getuid()); (void) execv(args[0], (char *const *) args); perror((char *)0); (void) fprintf(stderr, "Exec to %scompress %s failed.\n", uncomp ? "un" : "", filename); terminate(EXIT_FAILURE); } else if (f == -1) { perror((char *)0); pline("Fork to %scompress %s failed.", uncomp ? "un" : "", filename); return; } (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); (void) wait((int *)&i); (void) signal(SIGINT, (SIG_RET_TYPE) done1); # ifdef WIZARD if (wizard) (void) signal(SIGQUIT, SIG_DFL); # endif if (i == 0) { /* (un)compress succeeded: remove file left behind */ if (uncomp) (void) unlink(cfn); else (void) unlink(filename); } else { /* (un)compress failed; remove the new, bad file */ if (uncomp) { raw_printf("Unable to uncompress %s", filename); (void) unlink(filename); } else { /* no message needed for compress case; life will go on */ (void) unlink(cfn); } #ifdef TTY_GRAPHICS /* Give them a chance to read any error messages from the * compression--these would go to stdout or stderr and would get * overwritten only in tty mode. It's still ugly, since the * messages are being written on top of the screen, but at least * the user can read them. */ if (istty) { clear_nhwindow(WIN_MESSAGE); more(); /* No way to know if this is feasible */ /* doredraw(); */ } #endif } } #endif /* COMPRESS */ /* compress file */ void compress(filename) const char *filename; { #ifndef COMPRESS #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) # pragma unused(filename) #endif #else docompress_file(filename, FALSE); #endif } /* uncompress file if it exists */ void uncompress(filename) const char *filename; { #ifndef COMPRESS #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) # pragma unused(filename) #endif #else docompress_file(filename, TRUE); #endif } /* ---------- END FILE COMPRESSION HANDLING ----------- */ /* ---------- BEGIN FILE LOCKING HANDLING ----------- */ static int nesting = 0; #ifdef NO_FILE_LINKS /* implies UNIX */ static int lockfd; /* for lock_file() to pass to unlock_file() */ #endif #define HUP if (!program_state.done_hup) STATIC_OVL char * make_lockname(filename, lockname) const char *filename; char *lockname; { #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) # pragma unused(filename,lockname) return (char*)0; #else # if defined(UNIX) || defined(VMS) || defined(AMIGA) || defined(WIN32) || defined(MSDOS) # ifdef NO_FILE_LINKS Strcpy(lockname, LOCKDIR); Strcat(lockname, "/"); Strcat(lockname, filename); # else Strcpy(lockname, filename); # endif # ifdef VMS { char *semi_colon = rindex(lockname, ';'); if (semi_colon) *semi_colon = '\0'; } Strcat(lockname, ".lock;1"); # else Strcat(lockname, "_lock"); # endif return lockname; # else lockname[0] = '\0'; return (char*)0; # endif /* UNIX || VMS || AMIGA || WIN32 || MSDOS */ #endif } /* lock a file */ boolean lock_file(filename, whichprefix, retryct) const char *filename; int whichprefix; int retryct; { #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) # pragma unused(filename, retryct) #endif char locknambuf[BUFSZ]; const char *lockname; nesting++; if (nesting > 1) { impossible("TRIED TO NEST LOCKS"); return TRUE; } lockname = make_lockname(filename, locknambuf); filename = fqname(filename, whichprefix, 0); #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */ lockname = fqname(lockname, LOCKPREFIX, 2); #endif #if defined(UNIX) || defined(VMS) # ifdef NO_FILE_LINKS while ((lockfd = open(lockname, O_RDWR|O_CREAT|O_EXCL, 0666)) == -1) { # else while (link(filename, lockname) == -1) { # endif register int errnosv = errno; switch (errnosv) { /* George Barbanis */ case EEXIST: if (retryct--) { HUP raw_printf( "Waiting for access to %s. (%d retries left).", filename, retryct); # if defined(SYSV) || defined(ULTRIX) || defined(VMS) (void) # endif sleep(1); } else { HUP (void) raw_print("I give up. Sorry."); HUP raw_printf("Perhaps there is an old %s around?", lockname); nesting--; return FALSE; } break; case ENOENT: HUP raw_printf("Can't find file %s to lock!", filename); nesting--; return FALSE; case EACCES: HUP raw_printf("No write permission to lock %s!", filename); nesting--; return FALSE; # ifdef VMS /* c__translate(vmsfiles.c) */ case EPERM: /* could be misleading, but usually right */ HUP raw_printf("Can't lock %s due to directory protection.", filename); nesting--; return FALSE; # endif default: HUP perror(lockname); HUP raw_printf( "Cannot lock %s for unknown reason (%d).", filename, errnosv); nesting--; return FALSE; } } #endif /* UNIX || VMS */ #if defined(AMIGA) || defined(WIN32) || defined(MSDOS) # ifdef AMIGA #define OPENFAILURE(fd) (!fd) lockptr = 0; # else #define OPENFAILURE(fd) (fd < 0) lockptr = -1; # endif while (--retryct && OPENFAILURE(lockptr)) { # if defined(WIN32) && !defined(WIN_CE) lockptr = sopen(lockname, O_RDWR|O_CREAT, SH_DENYRW, S_IWRITE); # else (void)DeleteFile(lockname); /* in case dead process was here first */ # ifdef AMIGA lockptr = Open(lockname,MODE_NEWFILE); # else lockptr = open(lockname, O_RDWR|O_CREAT|O_EXCL, S_IWRITE); # endif # endif if (OPENFAILURE(lockptr)) { raw_printf("Waiting for access to %s. (%d retries left).", filename, retryct); Delay(50); } } if (!retryct) { raw_printf("I give up. Sorry."); nesting--; return FALSE; } #endif /* AMIGA || WIN32 || MSDOS */ return TRUE; } #ifdef VMS /* for unlock_file, use the unlink() routine in vmsunix.c */ # ifdef unlink # undef unlink # endif # define unlink(foo) vms_unlink(foo) #endif /* unlock file, which must be currently locked by lock_file */ void unlock_file(filename) const char *filename; #if defined(macintosh) && (defined(__SC__) || defined(__MRC__)) # pragma unused(filename) #endif { char locknambuf[BUFSZ]; const char *lockname; if (nesting == 1) { lockname = make_lockname(filename, locknambuf); #ifndef NO_FILE_LINKS /* LOCKDIR should be subsumed by LOCKPREFIX */ lockname = fqname(lockname, LOCKPREFIX, 2); #endif #if defined(UNIX) || defined(VMS) if (unlink(lockname) < 0) HUP raw_printf("Can't unlink %s.", lockname); # ifdef NO_FILE_LINKS (void) close(lockfd); # endif #endif /* UNIX || VMS */ #if defined(AMIGA) || defined(WIN32) || defined(MSDOS) if (lockptr) Close(lockptr); DeleteFile(lockname); lockptr = 0; #endif /* AMIGA || WIN32 || MSDOS */ } nesting--; } /* ---------- END FILE LOCKING HANDLING ----------- */ /* ---------- BEGIN CONFIG FILE HANDLING ----------- */ const char *configfile = #ifdef UNIX ".nethackrc"; #else # if defined(MAC) || defined(__BEOS__) "NetHack Defaults"; # else # if defined(MSDOS) || defined(WIN32) "defaults.nh"; # else "NetHack.cnf"; # endif # endif #endif #ifdef MSDOS /* conflict with speed-dial under windows * for XXX.cnf file so support of NetHack.cnf * is for backward compatibility only. * Preferred name (and first tried) is now defaults.nh but * the game will try the old name if there * is no defaults.nh. */ const char *backward_compat_configfile = "nethack.cnf"; #endif #ifndef MFLOPPY #define fopenp fopen #endif STATIC_OVL FILE * fopen_config_file(filename) const char *filename; { FILE *fp; #if defined(UNIX) || defined(VMS) char tmp_config[BUFSZ]; char *envp; #endif /* "filename" is an environment variable, so it should hang around */ /* if set, it is expected to be a full path name (if relevant) */ if (filename) { #ifdef UNIX if (access(filename, 4) == -1) { /* 4 is R_OK on newer systems */ /* nasty sneaky attempt to read file through * NetHack's setuid permissions -- this is the only * place a file name may be wholly under the player's * control */ raw_printf("Access to %s denied (%d).", filename, errno); wait_synch(); /* fall through to standard names */ } else #endif if ((fp = fopenp(filename, "r")) != (FILE *)0) { configfile = filename; return(fp); #if defined(UNIX) || defined(VMS) } else { /* access() above probably caught most problems for UNIX */ raw_printf("Couldn't open requested config file %s (%d).", filename, errno); wait_synch(); /* fall through to standard names */ #endif } } #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) if ((fp = fopenp(fqname(configfile, CONFIGPREFIX, 0), "r")) != (FILE *)0) return(fp); # ifdef MSDOS else if ((fp = fopenp(fqname(backward_compat_configfile, CONFIGPREFIX, 0), "r")) != (FILE *)0) return(fp); # endif #else /* constructed full path names don't need fqname() */ # ifdef VMS if ((fp = fopenp(fqname("nethackini", CONFIGPREFIX, 0), "r")) != (FILE *)0) { configfile = "nethackini"; return(fp); } if ((fp = fopenp("sys$login:nethack.ini", "r")) != (FILE *)0) { configfile = "nethack.ini"; return(fp); } envp = nh_getenv("HOME"); if (!envp) Strcpy(tmp_config, "NetHack.cnf"); else Sprintf(tmp_config, "%s%s", envp, "NetHack.cnf"); if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) return(fp); # else /* should be only UNIX left */ envp = nh_getenv("HOME"); if (!envp) Strcpy(tmp_config, configfile); else Sprintf(tmp_config, "%s/%s", envp, configfile); if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) return(fp); # if defined(__APPLE__) /* try an alternative */ if (envp) { Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults"); if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) return(fp); Sprintf(tmp_config, "%s/%s", envp, "Library/Preferences/NetHack Defaults.txt"); if ((fp = fopenp(tmp_config, "r")) != (FILE *)0) return(fp); } # endif if (errno != ENOENT) { char *details; /* e.g., problems when setuid NetHack can't search home * directory restricted to user */ #if defined (NHSTDC) && !defined(NOTSTDC) if ((details = strerror(errno)) == 0) #endif details = ""; raw_printf("Couldn't open default config file %s %s(%d).", tmp_config, details, errno); wait_synch(); } # endif #endif return (FILE *)0; } /* * Retrieve a list of integers from a file into a uchar array. * * NOTE: zeros are inserted unless modlist is TRUE, in which case the list * location is unchanged. Callers must handle zeros if modlist is FALSE. */ STATIC_OVL int get_uchars(fp, buf, bufp, list, modlist, size, name) FILE *fp; /* input file pointer */ char *buf; /* read buffer, must be of size BUFSZ */ char *bufp; /* current pointer */ uchar *list; /* return list */ boolean modlist; /* TRUE: list is being modified in place */ int size; /* return list size */ const char *name; /* name of option for error message */ { unsigned int num = 0; int count = 0; boolean havenum = FALSE; while (1) { switch(*bufp) { case ' ': case '\0': case '\t': case '\n': if (havenum) { /* if modifying in place, don't insert zeros */ if (num || !modlist) list[count] = num; count++; num = 0; havenum = FALSE; } if (count == size || !*bufp) return count; bufp++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': havenum = TRUE; num = num*10 + (*bufp-'0'); bufp++; break; case '\\': if (fp == (FILE *)0) goto gi_error; do { if (!fgets(buf, BUFSZ, fp)) goto gi_error; } while (buf[0] == '#'); bufp = buf; break; default: gi_error: raw_printf("Syntax error in %s", name); wait_synch(); return count; } } /*NOTREACHED*/ } #ifdef NOCWD_ASSUMPTIONS STATIC_OVL void adjust_prefix(bufp, prefixid) char *bufp; int prefixid; { char *ptr; if (!bufp) return; /* Backward compatibility, ignore trailing ;n */ if ((ptr = index(bufp, ';')) != 0) *ptr = '\0'; if (strlen(bufp) > 0) { fqn_prefix[prefixid] = (char *)alloc(strlen(bufp)+2); Strcpy(fqn_prefix[prefixid], bufp); append_slash(fqn_prefix[prefixid]); } } #endif #define match_varname(INP,NAM,LEN) match_optname(INP, NAM, LEN, TRUE) /*ARGSUSED*/ int parse_config_line(fp, buf, tmp_ramdisk, tmp_levels) FILE *fp; char *buf; char *tmp_ramdisk; char *tmp_levels; { #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) # pragma unused(tmp_ramdisk,tmp_levels) #endif char *bufp, *altp; uchar translate[MAXPCHARS]; int len; if (*buf == '#') return 1; /* remove trailing whitespace */ bufp = eos(buf); while (--bufp > buf && isspace(*bufp)) continue; if (bufp <= buf) return 1; /* skip all-blank lines */ else *(bufp + 1) = '\0'; /* terminate line */ /* find the '=' or ':' */ bufp = index(buf, '='); altp = index(buf, ':'); if (!bufp || (altp && altp < bufp)) bufp = altp; if (!bufp) return 0; /* skip whitespace between '=' and value */ do { ++bufp; } while (isspace(*bufp)); /* Go through possible variables */ /* some of these (at least LEVELS and SAVE) should now set the * appropriate fqn_prefix[] rather than specialized variables */ if (match_varname(buf, "OPTIONS", 4)) { parseoptions(bufp, TRUE, TRUE); if (plname[0]) /* If a name was given */ plnamesuffix(); /* set the character class */ #ifdef AUTOPICKUP_EXCEPTIONS } else if (match_varname(buf, "AUTOPICKUP_EXCEPTION", 5)) { add_autopickup_exception(bufp); #endif #ifdef NOCWD_ASSUMPTIONS } else if (match_varname(buf, "HACKDIR", 4)) { adjust_prefix(bufp, HACKPREFIX); } else if (match_varname(buf, "LEVELDIR", 4) || match_varname(buf, "LEVELS", 4)) { adjust_prefix(bufp, LEVELPREFIX); } else if (match_varname(buf, "SAVEDIR", 4)) { adjust_prefix(bufp, SAVEPREFIX); } else if (match_varname(buf, "BONESDIR", 5)) { adjust_prefix(bufp, BONESPREFIX); } else if (match_varname(buf, "DATADIR", 4)) { adjust_prefix(bufp, DATAPREFIX); } else if (match_varname(buf, "SCOREDIR", 4)) { adjust_prefix(bufp, SCOREPREFIX); } else if (match_varname(buf, "LOCKDIR", 4)) { adjust_prefix(bufp, LOCKPREFIX); } else if (match_varname(buf, "CONFIGDIR", 4)) { adjust_prefix(bufp, CONFIGPREFIX); } else if (match_varname(buf, "TROUBLEDIR", 4)) { adjust_prefix(bufp, TROUBLEPREFIX); #else /*NOCWD_ASSUMPTIONS*/ # ifdef MICRO } else if (match_varname(buf, "HACKDIR", 4)) { (void) strncpy(hackdir, bufp, PATHLEN-1); # ifdef MFLOPPY } else if (match_varname(buf, "RAMDISK", 3)) { /* The following ifdef is NOT in the wrong * place. For now, we accept and silently * ignore RAMDISK */ # ifndef AMIGA (void) strncpy(tmp_ramdisk, bufp, PATHLEN-1); # endif # endif } else if (match_varname(buf, "LEVELS", 4)) { (void) strncpy(tmp_levels, bufp, PATHLEN-1); } else if (match_varname(buf, "SAVE", 4)) { # ifdef MFLOPPY extern int saveprompt; # endif char *ptr; if ((ptr = index(bufp, ';')) != 0) { *ptr = '\0'; # ifdef MFLOPPY if (*(ptr+1) == 'n' || *(ptr+1) == 'N') { saveprompt = FALSE; } # endif } # ifdef MFLOPPY else saveprompt = flags.asksavedisk; # endif (void) strncpy(SAVEP, bufp, SAVESIZE-1); append_slash(SAVEP); # endif /* MICRO */ #endif /*NOCWD_ASSUMPTIONS*/ } else if (match_varname(buf, "NAME", 4)) { (void) strncpy(plname, bufp, PL_NSIZ-1); plnamesuffix(); } else if (match_varname(buf, "ROLE", 4) || match_varname(buf, "CHARACTER", 4)) { if ((len = str2role(bufp)) >= 0) flags.initrole = len; } else if (match_varname(buf, "DOGNAME", 3)) { (void) strncpy(dogname, bufp, PL_PSIZ-1); } else if (match_varname(buf, "CATNAME", 3)) { (void) strncpy(catname, bufp, PL_PSIZ-1); } else if (match_varname(buf, "BOULDER", 3)) { (void) get_uchars(fp, buf, bufp, &iflags.bouldersym, TRUE, 1, "BOULDER"); } else if (match_varname(buf, "GRAPHICS", 4)) { len = get_uchars(fp, buf, bufp, translate, FALSE, MAXPCHARS, "GRAPHICS"); assign_graphics(translate, len, MAXPCHARS, 0); } else if (match_varname(buf, "DUNGEON", 4)) { len = get_uchars(fp, buf, bufp, translate, FALSE, MAXDCHARS, "DUNGEON"); assign_graphics(translate, len, MAXDCHARS, 0); } else if (match_varname(buf, "TRAPS", 4)) { len = get_uchars(fp, buf, bufp, translate, FALSE, MAXTCHARS, "TRAPS"); assign_graphics(translate, len, MAXTCHARS, MAXDCHARS); } else if (match_varname(buf, "EFFECTS", 4)) { len = get_uchars(fp, buf, bufp, translate, FALSE, MAXECHARS, "EFFECTS"); assign_graphics(translate, len, MAXECHARS, MAXDCHARS+MAXTCHARS); } else if (match_varname(buf, "OBJECTS", 3)) { /* oc_syms[0] is the RANDOM object, unused */ (void) get_uchars(fp, buf, bufp, &(oc_syms[1]), TRUE, MAXOCLASSES-1, "OBJECTS"); } else if (match_varname(buf, "MONSTERS", 3)) { /* monsyms[0] is unused */ (void) get_uchars(fp, buf, bufp, &(monsyms[1]), TRUE, MAXMCLASSES-1, "MONSTERS"); } else if (match_varname(buf, "WARNINGS", 5)) { (void) get_uchars(fp, buf, bufp, translate, FALSE, WARNCOUNT, "WARNINGS"); assign_warnings(translate); #ifdef WIZARD } else if (match_varname(buf, "WIZKIT", 6)) { (void) strncpy(wizkit, bufp, WIZKIT_MAX-1); #endif #ifdef AMIGA } else if (match_varname(buf, "FONT", 4)) { char *t; if( t = strchr( buf+5, ':' ) ) { *t = 0; amii_set_text_font( buf+5, atoi( t + 1 ) ); *t = ':'; } } else if (match_varname(buf, "PATH", 4)) { (void) strncpy(PATH, bufp, PATHLEN-1); } else if (match_varname(buf, "DEPTH", 5)) { extern int amii_numcolors; int val = atoi( bufp ); amii_numcolors = 1L << min( DEPTH, val ); } else if (match_varname(buf, "DRIPENS", 7)) { int i, val; char *t; for (i = 0, t = strtok(bufp, ",/"); t != (char *)0; i < 20 && (t = strtok((char*)0, ",/")), ++i) { sscanf(t, "%d", &val ); flags.amii_dripens[i] = val; } } else if (match_varname(buf, "SCREENMODE", 10 )) { extern long amii_scrnmode; if (!stricmp(bufp,"req")) amii_scrnmode = 0xffffffff; /* Requester */ else if( sscanf(bufp, "%x", &amii_scrnmode) != 1 ) amii_scrnmode = 0; } else if (match_varname(buf, "MSGPENS", 7)) { extern int amii_msgAPen, amii_msgBPen; char *t = strtok(bufp, ",/"); if( t ) { sscanf(t, "%d", &amii_msgAPen); if( t = strtok((char*)0, ",/") ) sscanf(t, "%d", &amii_msgBPen); } } else if (match_varname(buf, "TEXTPENS", 8)) { extern int amii_textAPen, amii_textBPen; char *t = strtok(bufp, ",/"); if( t ) { sscanf(t, "%d", &amii_textAPen); if( t = strtok((char*)0, ",/") ) sscanf(t, "%d", &amii_textBPen); } } else if (match_varname(buf, "MENUPENS", 8)) { extern int amii_menuAPen, amii_menuBPen; char *t = strtok(bufp, ",/"); if( t ) { sscanf(t, "%d", &amii_menuAPen); if( t = strtok((char*)0, ",/") ) sscanf(t, "%d", &amii_menuBPen); } } else if (match_varname(buf, "STATUSPENS", 10)) { extern int amii_statAPen, amii_statBPen; char *t = strtok(bufp, ",/"); if( t ) { sscanf(t, "%d", &amii_statAPen); if( t = strtok((char*)0, ",/") ) sscanf(t, "%d", &amii_statBPen); } } else if (match_varname(buf, "OTHERPENS", 9)) { extern int amii_otherAPen, amii_otherBPen; char *t = strtok(bufp, ",/"); if( t ) { sscanf(t, "%d", &amii_otherAPen); if( t = strtok((char*)0, ",/") ) sscanf(t, "%d", &amii_otherBPen); } } else if (match_varname(buf, "PENS", 4)) { extern unsigned short amii_init_map[ AMII_MAXCOLORS ]; int i; char *t; for (i = 0, t = strtok(bufp, ",/"); i < AMII_MAXCOLORS && t != (char *)0; t = strtok((char *)0, ",/"), ++i) { sscanf(t, "%hx", &amii_init_map[i]); } amii_setpens( amii_numcolors = i ); } else if (match_varname(buf, "FGPENS", 6)) { extern int foreg[ AMII_MAXCOLORS ]; int i; char *t; for (i = 0, t = strtok(bufp, ",/"); i < AMII_MAXCOLORS && t != (char *)0; t = strtok((char *)0, ",/"), ++i) { sscanf(t, "%d", &foreg[i]); } } else if (match_varname(buf, "BGPENS", 6)) { extern int backg[ AMII_MAXCOLORS ]; int i; char *t; for (i = 0, t = strtok(bufp, ",/"); i < AMII_MAXCOLORS && t != (char *)0; t = strtok((char *)0, ",/"), ++i) { sscanf(t, "%d", &backg[i]); } #endif #ifdef USER_SOUNDS } else if (match_varname(buf, "SOUNDDIR", 8)) { sounddir = (char *)strdup(bufp); } else if (match_varname(buf, "SOUND", 5)) { add_sound_mapping(bufp); #endif #ifdef QT_GRAPHICS /* These should move to wc_ options */ } else if (match_varname(buf, "QT_TILEWIDTH", 12)) { extern char *qt_tilewidth; if (qt_tilewidth == NULL) qt_tilewidth=(char *)strdup(bufp); } else if (match_varname(buf, "QT_TILEHEIGHT", 13)) { extern char *qt_tileheight; if (qt_tileheight == NULL) qt_tileheight=(char *)strdup(bufp); } else if (match_varname(buf, "QT_FONTSIZE", 11)) { extern char *qt_fontsize; if (qt_fontsize == NULL) qt_fontsize=(char *)strdup(bufp); } else if (match_varname(buf, "QT_COMPACT", 10)) { extern int qt_compact_mode; qt_compact_mode = atoi(bufp); #endif } else return 0; return 1; } #ifdef USER_SOUNDS boolean can_read_file(filename) const char *filename; { return (access(filename, 4) == 0); } #endif /* USER_SOUNDS */ void read_config_file(filename) const char *filename; { #define tmp_levels (char *)0 #define tmp_ramdisk (char *)0 #if defined(MICRO) || defined(WIN32) #undef tmp_levels char tmp_levels[PATHLEN]; # ifdef MFLOPPY # ifndef AMIGA #undef tmp_ramdisk char tmp_ramdisk[PATHLEN]; # endif # endif #endif char buf[4*BUFSZ]; FILE *fp; if (!(fp = fopen_config_file(filename))) return; #if defined(MICRO) || defined(WIN32) # ifdef MFLOPPY # ifndef AMIGA tmp_ramdisk[0] = 0; # endif # endif tmp_levels[0] = 0; #endif /* begin detection of duplicate configfile options */ set_duplicate_opt_detection(1); while (fgets(buf, 4*BUFSZ, fp)) { if (!parse_config_line(fp, buf, tmp_ramdisk, tmp_levels)) { raw_printf("Bad option line: \"%.50s\"", buf); wait_synch(); } } (void) fclose(fp); /* turn off detection of duplicate configfile options */ set_duplicate_opt_detection(0); #if defined(MICRO) && !defined(NOCWD_ASSUMPTIONS) /* should be superseded by fqn_prefix[] */ # ifdef MFLOPPY Strcpy(permbones, tmp_levels); # ifndef AMIGA if (tmp_ramdisk[0]) { Strcpy(levels, tmp_ramdisk); if (strcmp(permbones, levels)) /* if not identical */ ramdisk = TRUE; } else # endif /* AMIGA */ Strcpy(levels, tmp_levels); Strcpy(bones, levels); # endif /* MFLOPPY */ #endif /* MICRO */ return; } #ifdef WIZARD STATIC_OVL FILE * fopen_wizkit_file() { FILE *fp; #if defined(VMS) || defined(UNIX) char tmp_wizkit[BUFSZ]; #endif char *envp; envp = nh_getenv("WIZKIT"); if (envp && *envp) (void) strncpy(wizkit, envp, WIZKIT_MAX - 1); if (!wizkit[0]) return (FILE *)0; #ifdef UNIX if (access(wizkit, 4) == -1) { /* 4 is R_OK on newer systems */ /* nasty sneaky attempt to read file through * NetHack's setuid permissions -- this is a * place a file name may be wholly under the player's * control */ raw_printf("Access to %s denied (%d).", wizkit, errno); wait_synch(); /* fall through to standard names */ } else #endif if ((fp = fopenp(wizkit, "r")) != (FILE *)0) { return(fp); #if defined(UNIX) || defined(VMS) } else { /* access() above probably caught most problems for UNIX */ raw_printf("Couldn't open requested config file %s (%d).", wizkit, errno); wait_synch(); #endif } #if defined(MICRO) || defined(MAC) || defined(__BEOS__) || defined(WIN32) if ((fp = fopenp(fqname(wizkit, CONFIGPREFIX, 0), "r")) != (FILE *)0) return(fp); #else # ifdef VMS envp = nh_getenv("HOME"); if (envp) Sprintf(tmp_wizkit, "%s%s", envp, wizkit); else Sprintf(tmp_wizkit, "%s%s", "sys$login:", wizkit); if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *)0) return(fp); # else /* should be only UNIX left */ envp = nh_getenv("HOME"); if (envp) Sprintf(tmp_wizkit, "%s/%s", envp, wizkit); else Strcpy(tmp_wizkit, wizkit); if ((fp = fopenp(tmp_wizkit, "r")) != (FILE *)0) return(fp); else if (errno != ENOENT) { /* e.g., problems when setuid NetHack can't search home * directory restricted to user */ raw_printf("Couldn't open default wizkit file %s (%d).", tmp_wizkit, errno); wait_synch(); } # endif #endif return (FILE *)0; } void read_wizkit() { FILE *fp; char *ep, buf[BUFSZ]; struct obj *otmp; boolean bad_items = FALSE, skip = FALSE; if (!wizard || !(fp = fopen_wizkit_file())) return; while (fgets(buf, (int)(sizeof buf), fp)) { ep = index(buf, '\n'); if (skip) { /* in case previous line was too long */ if (ep) skip = FALSE; /* found newline; next line is normal */ } else { if (!ep) skip = TRUE; /* newline missing; discard next fgets */ else *ep = '\0'; /* remove newline */ if (buf[0]) { otmp = readobjnam(buf, (struct obj *)0, FALSE); if (otmp) { if (otmp != &zeroobj) otmp = addinv(otmp); } else { /* .60 limits output line width to 79 chars */ raw_printf("Bad wizkit item: \"%.60s\"", buf); bad_items = TRUE; } } } } if (bad_items) wait_synch(); (void) fclose(fp); return; } #endif /*WIZARD*/ /* ---------- END CONFIG FILE HANDLING ----------- */ /* ---------- BEGIN SCOREBOARD CREATION ----------- */ /* verify that we can write to the scoreboard file; if not, try to create one */ void check_recordfile(dir) const char *dir; { #if (defined(macintosh) && (defined(__SC__) || defined(__MRC__))) || defined(__MWERKS__) # pragma unused(dir) #endif const char *fq_record; int fd; #if defined(UNIX) || defined(VMS) fq_record = fqname(RECORD, SCOREPREFIX, 0); fd = open(fq_record, O_RDWR, 0); if (fd >= 0) { # ifdef VMS /* must be stream-lf to use UPDATE_RECORD_IN_PLACE */ if (!file_is_stmlf(fd)) { raw_printf( "Warning: scoreboard file %s is not in stream_lf format", fq_record); wait_synch(); } # endif (void) close(fd); /* RECORD is accessible */ } else if ((fd = open(fq_record, O_CREAT|O_RDWR, FCMASK)) >= 0) { (void) close(fd); /* RECORD newly created */ # if defined(VMS) && !defined(SECURE) /* Re-protect RECORD with world:read+write+execute+delete access. */ (void) chmod(fq_record, FCMASK | 007); # endif /* VMS && !SECURE */ } else { raw_printf("Warning: cannot write scoreboard file %s", fq_record); wait_synch(); } #endif /* !UNIX && !VMS */ #if defined(MICRO) || defined(WIN32) char tmp[PATHLEN]; # ifdef OS2_CODEVIEW /* explicit path on opening for OS/2 */ /* how does this work when there isn't an explicit path or fopenp * for later access to the file via fopen_datafile? ? */ (void) strncpy(tmp, dir, PATHLEN - 1); tmp[PATHLEN-1] = '\0'; if ((strlen(tmp) + 1 + strlen(RECORD)) < (PATHLEN - 1)) { append_slash(tmp); Strcat(tmp, RECORD); } fq_record = tmp; # else Strcpy(tmp, RECORD); fq_record = fqname(RECORD, SCOREPREFIX, 0); # endif if ((fd = open(fq_record, O_RDWR)) < 0) { /* try to create empty record */ # if defined(AZTEC_C) || defined(_DCC) || (defined(__GNUC__) && defined(__AMIGA__)) /* Aztec doesn't use the third argument */ /* DICE doesn't like it */ if ((fd = open(fq_record, O_CREAT|O_RDWR)) < 0) { # else if ((fd = open(fq_record, O_CREAT|O_RDWR, S_IREAD|S_IWRITE)) < 0) { # endif raw_printf("Warning: cannot write record %s", tmp); wait_synch(); } else (void) close(fd); } else /* open succeeded */ (void) close(fd); #else /* MICRO || WIN32*/ # ifdef MAC /* Create the "record" file, if necessary */ fq_record = fqname(RECORD, SCOREPREFIX, 0); fd = macopen (fq_record, O_RDWR | O_CREAT, TEXT_TYPE); if (fd != -1) macclose (fd); # endif /* MAC */ #endif /* MICRO || WIN32*/ } /* ---------- END SCOREBOARD CREATION ----------- */ /* ---------- BEGIN PANIC/IMPOSSIBLE LOG ----------- */ /*ARGSUSED*/ void paniclog(type, reason) const char *type; /* panic, impossible, trickery */ const char *reason; /* explanation */ { #ifdef PANICLOG FILE *lfile; char buf[BUFSZ]; if (!program_state.in_paniclog) { program_state.in_paniclog = 1; lfile = fopen_datafile(PANICLOG, "a", TROUBLEPREFIX); if (lfile) { (void) fprintf(lfile, "%s %08ld: %s %s\n", version_string(buf), yyyymmdd((time_t)0L), type, reason); (void) fclose(lfile); } program_state.in_paniclog = 0; } #endif /* PANICLOG */ return; } /* ---------- END PANIC/IMPOSSIBLE LOG ----------- */ #ifdef SELF_RECOVER /* ---------- BEGIN INTERNAL RECOVER ----------- */ boolean recover_savefile() { int gfd, lfd, sfd; int lev, savelev, hpid; xchar levc; struct version_info version_data; int processed[256]; char savename[SAVESIZE], errbuf[BUFSZ]; for (lev = 0; lev < 256; lev++) processed[lev] = 0; /* level 0 file contains: * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created * and game state */ gfd = open_levelfile(0, errbuf); if (gfd < 0) { raw_printf("%s\n", errbuf); return FALSE; } if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { raw_printf( "\nCheckpoint data incompletely written or subsequently clobbered. Recovery impossible."); (void)close(gfd); return FALSE; } if (read(gfd, (genericptr_t) &savelev, sizeof(savelev)) != sizeof(savelev)) { raw_printf("\nCheckpointing was not in effect for %s -- recovery impossible.\n", lock); (void)close(gfd); return FALSE; } if ((read(gfd, (genericptr_t) savename, sizeof savename) != sizeof savename) || (read(gfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data)) { raw_printf("\nError reading %s -- can't recover.\n", lock); (void)close(gfd); return FALSE; } /* save file should contain: * version info * current level (including pets) * (non-level-based) game state * other levels */ set_savefile_name(); sfd = create_savefile(); if (sfd < 0) { raw_printf("\nCannot recover savefile %s.\n", SAVEF); (void)close(gfd); return FALSE; } lfd = open_levelfile(savelev, errbuf); if (lfd < 0) { raw_printf("\n%s\n", errbuf); (void)close(gfd); (void)close(sfd); delete_savefile(); return FALSE; } if (write(sfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) { raw_printf("\nError writing %s; recovery failed.", SAVEF); (void)close(gfd); (void)close(sfd); delete_savefile(); return FALSE; } if (!copy_bytes(lfd, sfd)) { (void) close(lfd); (void) close(sfd); delete_savefile(); return FALSE; } (void)close(lfd); processed[savelev] = 1; if (!copy_bytes(gfd, sfd)) { (void) close(lfd); (void) close(sfd); delete_savefile(); return FALSE; } (void)close(gfd); processed[0] = 1; for (lev = 1; lev < 256; lev++) { /* level numbers are kept in xchars in save.c, so the * maximum level number (for the endlevel) must be < 256 */ if (lev != savelev) { lfd = open_levelfile(lev, (char *)0); if (lfd >= 0) { /* any or all of these may not exist */ levc = (xchar) lev; write(sfd, (genericptr_t) &levc, sizeof(levc)); if (!copy_bytes(lfd, sfd)) { (void) close(lfd); (void) close(sfd); delete_savefile(); return FALSE; } (void)close(lfd); processed[lev] = 1; } } } (void)close(sfd); #ifdef HOLD_LOCKFILE_OPEN really_close(); #endif /* * We have a successful savefile! * Only now do we erase the level files. */ for (lev = 0; lev < 256; lev++) { if (processed[lev]) { const char *fq_lock; set_levelfile_name(lock, lev); fq_lock = fqname(lock, LEVELPREFIX, 3); (void) unlink(fq_lock); } } return TRUE; } boolean copy_bytes(ifd, ofd) int ifd, ofd; { char buf[BUFSIZ]; int nfrom, nto; do { nfrom = read(ifd, buf, BUFSIZ); nto = write(ofd, buf, nfrom); if (nto != nfrom) return FALSE; } while (nfrom == BUFSIZ); return TRUE; } /* ---------- END INTERNAL RECOVER ----------- */ #endif /*SELF_RECOVER*/ /*files.c*/ nethack-3.4.3/src/fountain.c0100644000000000000000000003577707764735041014453 0ustar rootroot/* SCCS Id: @(#)fountain.c 3.4 2003/03/23 */ /* Copyright Scott R. Turner, srt@ucla, 10/27/86 */ /* NetHack may be freely redistributed. See license for details. */ /* Code for drinking from fountains. */ #include "hack.h" STATIC_DCL void NDECL(dowatersnakes); STATIC_DCL void NDECL(dowaterdemon); STATIC_DCL void NDECL(dowaternymph); STATIC_PTR void FDECL(gush, (int,int,genericptr_t)); STATIC_DCL void NDECL(dofindgem); void floating_above(what) const char *what; { You("are floating high above the %s.", what); } STATIC_OVL void dowatersnakes() /* Fountain of snakes! */ { register int num = rn1(5,2); struct monst *mtmp; if (!(mvitals[PM_WATER_MOCCASIN].mvflags & G_GONE)) { if (!Blind) pline("An endless stream of %s pours forth!", Hallucination ? makeplural(rndmonnam()) : "snakes"); else You_hear("%s hissing!", something); while(num-- > 0) if((mtmp = makemon(&mons[PM_WATER_MOCCASIN], u.ux, u.uy, NO_MM_FLAGS)) && t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } else pline_The("fountain bubbles furiously for a moment, then calms."); } STATIC_OVL void dowaterdemon() /* Water demon */ { register struct monst *mtmp; if(!(mvitals[PM_WATER_DEMON].mvflags & G_GONE)) { if((mtmp = makemon(&mons[PM_WATER_DEMON],u.ux,u.uy, NO_MM_FLAGS))) { if (!Blind) You("unleash %s!", a_monnam(mtmp)); else You_feel("the presence of evil."); /* Give those on low levels a (slightly) better chance of survival */ if (rnd(100) > (80 + level_difficulty())) { pline("Grateful for %s release, %s grants you a wish!", mhis(mtmp), mhe(mtmp)); makewish(); mongone(mtmp); } else if (t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } } else pline_The("fountain bubbles furiously for a moment, then calms."); } STATIC_OVL void dowaternymph() /* Water Nymph */ { register struct monst *mtmp; if(!(mvitals[PM_WATER_NYMPH].mvflags & G_GONE) && (mtmp = makemon(&mons[PM_WATER_NYMPH],u.ux,u.uy, NO_MM_FLAGS))) { if (!Blind) You("attract %s!", a_monnam(mtmp)); else You_hear("a seductive voice."); mtmp->msleeping = 0; if (t_at(mtmp->mx, mtmp->my)) (void) mintrap(mtmp); } else if (!Blind) pline("A large bubble rises to the surface and pops."); else You_hear("a loud pop."); } void dogushforth(drinking) /* Gushing forth along LOS from (u.ux, u.uy) */ int drinking; { int madepool = 0; do_clear_area(u.ux, u.uy, 7, gush, (genericptr_t)&madepool); if (!madepool) { if (drinking) Your("thirst is quenched."); else pline("Water sprays all over you."); } } STATIC_PTR void gush(x, y, poolcnt) int x, y; genericptr_t poolcnt; { register struct monst *mtmp; register struct trap *ttmp; if (((x+y)%2) || (x == u.ux && y == u.uy) || (rn2(1 + distmin(u.ux, u.uy, x, y))) || (levl[x][y].typ != ROOM) || (sobj_at(BOULDER, x, y)) || nexttodoor(x, y)) return; if ((ttmp = t_at(x, y)) != 0 && !delfloortrap(ttmp)) return; if (!((*(int *)poolcnt)++)) pline("Water gushes forth from the overflowing fountain!"); /* Put a pool at x, y */ levl[x][y].typ = POOL; /* No kelp! */ del_engr_at(x, y); water_damage(level.objects[x][y], FALSE, TRUE); if ((mtmp = m_at(x, y)) != 0) (void) minliquid(mtmp); else newsym(x,y); } STATIC_OVL void dofindgem() /* Find a gem in the sparkling waters. */ { if (!Blind) You("spot a gem in the sparkling waters!"); else You_feel("a gem here!"); (void) mksobj_at(rnd_class(DILITHIUM_CRYSTAL, LUCKSTONE-1), u.ux, u.uy, FALSE, FALSE); SET_FOUNTAIN_LOOTED(u.ux,u.uy); newsym(u.ux, u.uy); exercise(A_WIS, TRUE); /* a discovery! */ } void dryup(x, y, isyou) xchar x, y; boolean isyou; { if (IS_FOUNTAIN(levl[x][y].typ) && (!rn2(3) || FOUNTAIN_IS_WARNED(x,y))) { if(isyou && in_town(x, y) && !FOUNTAIN_IS_WARNED(x,y)) { struct monst *mtmp; SET_FOUNTAIN_WARNED(x,y); /* Warn about future fountain use. */ for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->data == &mons[PM_WATCHMAN] || mtmp->data == &mons[PM_WATCH_CAPTAIN]) && couldsee(mtmp->mx, mtmp->my) && mtmp->mpeaceful) { pline("%s yells:", Amonnam(mtmp)); verbalize("Hey, stop using that fountain!"); break; } } /* You can see or hear this effect */ if(!mtmp) pline_The("flow reduces to a trickle."); return; } #ifdef WIZARD if (isyou && wizard) { if (yn("Dry up fountain?") == 'n') return; } #endif /* replace the fountain with ordinary floor */ levl[x][y].typ = ROOM; levl[x][y].looted = 0; levl[x][y].blessedftn = 0; if (cansee(x,y)) pline_The("fountain dries up!"); /* The location is seen if the hero/monster is invisible */ /* or felt if the hero is blind. */ newsym(x, y); level.flags.nfountains--; if(isyou && in_town(x, y)) (void) angry_guards(FALSE); } } void drinkfountain() { /* What happens when you drink from a fountain? */ register boolean mgkftn = (levl[u.ux][u.uy].blessedftn == 1); register int fate = rnd(30); if (Levitation) { floating_above("fountain"); return; } if (mgkftn && u.uluck >= 0 && fate >= 10) { int i, ii, littleluck = (u.uluck < 4); pline("Wow! This makes you feel great!"); /* blessed restore ability */ for (ii = 0; ii < A_MAX; ii++) if (ABASE(ii) < AMAX(ii)) { ABASE(ii) = AMAX(ii); flags.botl = 1; } /* gain ability, blessed if "natural" luck is high */ i = rn2(A_MAX); /* start at a random attribute */ for (ii = 0; ii < A_MAX; ii++) { if (adjattrib(i, 1, littleluck ? -1 : 0) && littleluck) break; if (++i >= A_MAX) i = 0; } display_nhwindow(WIN_MESSAGE, FALSE); pline("A wisp of vapor escapes the fountain..."); exercise(A_WIS, TRUE); levl[u.ux][u.uy].blessedftn = 0; return; } if (fate < 10) { pline_The("cool draught refreshes you."); u.uhunger += rnd(10); /* don't choke on water */ newuhs(FALSE); if(mgkftn) return; } else { switch (fate) { case 19: /* Self-knowledge */ You_feel("self-knowledgeable..."); display_nhwindow(WIN_MESSAGE, FALSE); enlightenment(0); exercise(A_WIS, TRUE); pline_The("feeling subsides."); break; case 20: /* Foul water */ pline_The("water is foul! You gag and vomit."); morehungry(rn1(20, 11)); vomit(); break; case 21: /* Poisonous */ pline_The("water is contaminated!"); if (Poison_resistance) { pline( "Perhaps it is runoff from the nearby %s farm.", fruitname(FALSE)); losehp(rnd(4),"unrefrigerated sip of juice", KILLED_BY_AN); break; } losestr(rn1(4,3)); losehp(rnd(10),"contaminated water", KILLED_BY); exercise(A_CON, FALSE); break; case 22: /* Fountain of snakes! */ dowatersnakes(); break; case 23: /* Water demon */ dowaterdemon(); break; case 24: /* Curse an item */ { register struct obj *obj; pline("This water's no good!"); morehungry(rn1(20, 11)); exercise(A_CON, FALSE); for(obj = invent; obj ; obj = obj->nobj) if (!rn2(5)) curse(obj); break; } case 25: /* See invisible */ if (Blind) { if (Invisible) { You("feel transparent."); } else { You("feel very self-conscious."); pline("Then it passes."); } } else { You("see an image of someone stalking you."); pline("But it disappears."); } HSee_invisible |= FROMOUTSIDE; newsym(u.ux,u.uy); exercise(A_WIS, TRUE); break; case 26: /* See Monsters */ (void) monster_detect((struct obj *)0, 0); exercise(A_WIS, TRUE); break; case 27: /* Find a gem in the sparkling waters. */ if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) { dofindgem(); break; } case 28: /* Water Nymph */ dowaternymph(); break; case 29: /* Scare */ { register struct monst *mtmp; pline("This water gives you bad breath!"); for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(!DEADMONSTER(mtmp)) monflee(mtmp, 0, FALSE, FALSE); } break; case 30: /* Gushing forth in this room */ dogushforth(TRUE); break; default: pline("This tepid water is tasteless."); break; } } dryup(u.ux, u.uy, TRUE); } void dipfountain(obj) register struct obj *obj; { if (Levitation) { floating_above("fountain"); return; } /* Don't grant Excalibur when there's more than one object. */ /* (quantity could be > 1 if merged daggers got polymorphed) */ if (obj->otyp == LONG_SWORD && obj->quan == 1L && u.ulevel >= 5 && !rn2(6) && !obj->oartifact && !exist_artifact(LONG_SWORD, artiname(ART_EXCALIBUR))) { if (u.ualign.type != A_LAWFUL) { /* Ha! Trying to cheat her. */ pline("A freezing mist rises from the water and envelopes the sword."); pline_The("fountain disappears!"); curse(obj); if (obj->spe > -6 && !rn2(3)) obj->spe--; obj->oerodeproof = FALSE; exercise(A_WIS, FALSE); } else { /* The lady of the lake acts! - Eric Backus */ /* Be *REAL* nice */ pline("From the murky depths, a hand reaches up to bless the sword."); pline("As the hand retreats, the fountain disappears!"); obj = oname(obj, artiname(ART_EXCALIBUR)); discover_artifact(ART_EXCALIBUR); bless(obj); obj->oeroded = obj->oeroded2 = 0; obj->oerodeproof = TRUE; exercise(A_WIS, TRUE); } update_inventory(); levl[u.ux][u.uy].typ = ROOM; levl[u.ux][u.uy].looted = 0; newsym(u.ux, u.uy); level.flags.nfountains--; if(in_town(u.ux, u.uy)) (void) angry_guards(FALSE); return; } else if (get_wet(obj) && !rn2(2)) return; /* Acid and water don't mix */ if (obj->otyp == POT_ACID) { useup(obj); return; } switch (rnd(30)) { case 16: /* Curse the item */ curse(obj); break; case 17: case 18: case 19: case 20: /* Uncurse the item */ if(obj->cursed) { if (!Blind) pline_The("water glows for a moment."); uncurse(obj); } else { pline("A feeling of loss comes over you."); } break; case 21: /* Water Demon */ dowaterdemon(); break; case 22: /* Water Nymph */ dowaternymph(); break; case 23: /* an Endless Stream of Snakes */ dowatersnakes(); break; case 24: /* Find a gem */ if (!FOUNTAIN_IS_LOOTED(u.ux,u.uy)) { dofindgem(); break; } case 25: /* Water gushes forth */ dogushforth(FALSE); break; case 26: /* Strange feeling */ pline("A strange tingling runs up your %s.", body_part(ARM)); break; case 27: /* Strange feeling */ You_feel("a sudden chill."); break; case 28: /* Strange feeling */ pline("An urge to take a bath overwhelms you."); #ifndef GOLDOBJ if (u.ugold > 10) { u.ugold -= somegold() / 10; You("lost some of your gold in the fountain!"); CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy); exercise(A_WIS, FALSE); } #else { long money = money_cnt(invent); struct obj *otmp; if (money > 10) { /* Amount to loose. Might get rounded up as fountains don't pay change... */ money = somegold(money) / 10; for (otmp = invent; otmp && money > 0; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) { int denomination = objects[otmp->otyp].oc_cost; long coin_loss = (money + denomination - 1) / denomination; coin_loss = min(coin_loss, otmp->quan); otmp->quan -= coin_loss; money -= coin_loss * denomination; if (!otmp->quan) delobj(otmp); } You("lost some of your money in the fountain!"); CLEAR_FOUNTAIN_LOOTED(u.ux,u.uy); exercise(A_WIS, FALSE); } } #endif break; case 29: /* You see coins */ /* We make fountains have more coins the closer you are to the * surface. After all, there will have been more people going * by. Just like a shopping mall! Chris Woodbury */ if (FOUNTAIN_IS_LOOTED(u.ux,u.uy)) break; SET_FOUNTAIN_LOOTED(u.ux,u.uy); (void) mkgold((long) (rnd((dunlevs_in_dungeon(&u.uz)-dunlev(&u.uz)+1)*2)+5), u.ux, u.uy); if (!Blind) pline("Far below you, you see coins glistening in the water."); exercise(A_WIS, TRUE); newsym(u.ux,u.uy); break; } update_inventory(); dryup(u.ux, u.uy, TRUE); } #ifdef SINKS void breaksink(x,y) int x, y; { if(cansee(x,y) || (x == u.ux && y == u.uy)) pline_The("pipes break! Water spurts out!"); level.flags.nsinks--; levl[x][y].doormask = 0; levl[x][y].typ = FOUNTAIN; level.flags.nfountains++; newsym(x,y); } void drinksink() { struct obj *otmp; struct monst *mtmp; if (Levitation) { floating_above("sink"); return; } switch(rn2(20)) { case 0: You("take a sip of very cold water."); break; case 1: You("take a sip of very warm water."); break; case 2: You("take a sip of scalding hot water."); if (Fire_resistance) pline("It seems quite tasty."); else losehp(rnd(6), "sipping boiling water", KILLED_BY); break; case 3: if (mvitals[PM_SEWER_RAT].mvflags & G_GONE) pline_The("sink seems quite dirty."); else { mtmp = makemon(&mons[PM_SEWER_RAT], u.ux, u.uy, NO_MM_FLAGS); if (mtmp) pline("Eek! There's %s in the sink!", (Blind || !canspotmon(mtmp)) ? "something squirmy" : a_monnam(mtmp)); } break; case 4: do { otmp = mkobj(POTION_CLASS,FALSE); if (otmp->otyp == POT_WATER) { obfree(otmp, (struct obj *)0); otmp = (struct obj *) 0; } } while(!otmp); otmp->cursed = otmp->blessed = 0; pline("Some %s liquid flows from the faucet.", Blind ? "odd" : hcolor(OBJ_DESCR(objects[otmp->otyp]))); otmp->dknown = !(Blind || Hallucination); otmp->quan++; /* Avoid panic upon useup() */ otmp->fromsink = 1; /* kludge for docall() */ (void) dopotion(otmp); obfree(otmp, (struct obj *)0); break; case 5: if (!(levl[u.ux][u.uy].looted & S_LRING)) { You("find a ring in the sink!"); (void) mkobj_at(RING_CLASS, u.ux, u.uy, TRUE); levl[u.ux][u.uy].looted |= S_LRING; exercise(A_WIS, TRUE); newsym(u.ux,u.uy); } else pline("Some dirty water backs up in the drain."); break; case 6: breaksink(u.ux,u.uy); break; case 7: pline_The("water moves as though of its own will!"); if ((mvitals[PM_WATER_ELEMENTAL].mvflags & G_GONE) || !makemon(&mons[PM_WATER_ELEMENTAL], u.ux, u.uy, NO_MM_FLAGS)) pline("But it quiets down."); break; case 8: pline("Yuk, this water tastes awful."); more_experienced(1,0); newexplevel(); break; case 9: pline("Gaggg... this tastes like sewage! You vomit."); morehungry(rn1(30-ACURR(A_CON), 11)); vomit(); break; case 10: pline("This water contains toxic wastes!"); if (!Unchanging) { You("undergo a freakish metamorphosis!"); polyself(FALSE); } break; /* more odd messages --JJB */ case 11: You_hear("clanking from the pipes..."); break; case 12: You_hear("snatches of song from among the sewers..."); break; case 19: if (Hallucination) { pline("From the murky drain, a hand reaches up... --oops--"); break; } default: You("take a sip of %s water.", rn2(3) ? (rn2(2) ? "cold" : "warm") : "hot"); } } #endif /* SINKS */ /*fountain.c*/ nethack-3.4.3/src/hack.c0100644000000000000000000016653707764735041013535 0ustar rootroot/* SCCS Id: @(#)hack.c 3.4 2003/04/30 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef OVL1 STATIC_DCL void NDECL(maybe_wail); #endif /*OVL1*/ STATIC_DCL int NDECL(moverock); STATIC_DCL int FDECL(still_chewing,(XCHAR_P,XCHAR_P)); #ifdef SINKS STATIC_DCL void NDECL(dosinkfall); #endif STATIC_DCL boolean FDECL(findtravelpath, (BOOLEAN_P)); STATIC_DCL boolean FDECL(monstinroom, (struct permonst *,int)); STATIC_DCL void FDECL(move_update, (BOOLEAN_P)); #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE) #ifdef OVL2 boolean revive_nasty(x, y, msg) int x,y; const char *msg; { register struct obj *otmp, *otmp2; struct monst *mtmp; coord cc; boolean revived = FALSE; for(otmp = level.objects[x][y]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (otmp->otyp == CORPSE && (is_rider(&mons[otmp->corpsenm]) || otmp->corpsenm == PM_WIZARD_OF_YENDOR)) { /* move any living monster already at that location */ if((mtmp = m_at(x,y)) && enexto(&cc, x, y, mtmp->data)) rloc_to(mtmp, cc.x, cc.y); if(msg) Norep("%s", msg); revived = revive_corpse(otmp); } } /* this location might not be safe, if not, move revived monster */ if (revived) { mtmp = m_at(x,y); if (mtmp && !goodpos(x, y, mtmp, 0) && enexto(&cc, x, y, mtmp->data)) { rloc_to(mtmp, cc.x, cc.y); } /* else impossible? */ } return (revived); } STATIC_OVL int moverock() { register xchar rx, ry, sx, sy; register struct obj *otmp; register struct trap *ttmp; register struct monst *mtmp; sx = u.ux + u.dx, sy = u.uy + u.dy; /* boulder starting position */ while ((otmp = sobj_at(BOULDER, sx, sy)) != 0) { /* make sure that this boulder is visible as the top object */ if (otmp != level.objects[sx][sy]) movobj(otmp, sx, sy); rx = u.ux + 2 * u.dx; /* boulder destination position */ ry = u.uy + 2 * u.dy; nomul(0); if (Levitation || Is_airlevel(&u.uz)) { if (Blind) feel_location(sx, sy); You("don't have enough leverage to push %s.", the(xname(otmp))); /* Give them a chance to climb over it? */ return -1; } if (verysmall(youmonst.data) #ifdef STEED && !u.usteed #endif ) { if (Blind) feel_location(sx, sy); pline("You're too small to push that %s.", xname(otmp)); goto cannot_push; } if (isok(rx,ry) && !IS_ROCK(levl[rx][ry].typ) && levl[rx][ry].typ != IRONBARS && (!IS_DOOR(levl[rx][ry].typ) || !(u.dx && u.dy) || ( #ifdef REINCARNATION !Is_rogue_level(&u.uz) && #endif (levl[rx][ry].doormask & ~D_BROKEN) == D_NODOOR)) && !sobj_at(BOULDER, rx, ry)) { ttmp = t_at(rx, ry); mtmp = m_at(rx, ry); /* KMH -- Sokoban doesn't let you push boulders diagonally */ if (In_sokoban(&u.uz) && u.dx && u.dy) { if (Blind) feel_location(sx,sy); pline("%s won't roll diagonally on this %s.", The(xname(otmp)), surface(sx, sy)); goto cannot_push; } if (revive_nasty(rx, ry, "You sense movement on the other side.")) return (-1); if (mtmp && !noncorporeal(mtmp->data) && (!mtmp->mtrapped || !(ttmp && ((ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT))))) { if (Blind) feel_location(sx, sy); if (canspotmon(mtmp)) pline("There's %s on the other side.", a_monnam(mtmp)); else { You_hear("a monster behind %s.", the(xname(otmp))); map_invisible(rx, ry); } if (flags.verbose) pline("Perhaps that's why %s cannot move it.", #ifdef STEED u.usteed ? y_monnam(u.usteed) : #endif "you"); goto cannot_push; } if (ttmp) switch(ttmp->ttyp) { case LANDMINE: if (rn2(10)) { obj_extract_self(otmp); place_object(otmp, rx, ry); unblock_point(sx, sy); newsym(sx, sy); pline("KAABLAMM!!! %s %s land mine.", Tobjnam(otmp, "trigger"), ttmp->madeby_u ? "your" : "a"); blow_up_landmine(ttmp); /* if the boulder remains, it should fill the pit */ fill_pit(u.ux, u.uy); if (cansee(rx,ry)) newsym(rx,ry); continue; } break; case SPIKED_PIT: case PIT: obj_extract_self(otmp); /* vision kludge to get messages right; the pit will temporarily be seen even if this is one among multiple boulders */ if (!Blind) viz_array[ry][rx] |= IN_SIGHT; if (!flooreffects(otmp, rx, ry, "fall")) { place_object(otmp, rx, ry); } if (mtmp && !Blind) newsym(rx, ry); continue; case HOLE: case TRAPDOOR: if (Blind) pline("Kerplunk! You no longer feel %s.", the(xname(otmp))); else pline("%s%s and %s a %s in the %s!", Tobjnam(otmp, (ttmp->ttyp == TRAPDOOR) ? "trigger" : "fall"), (ttmp->ttyp == TRAPDOOR) ? nul : " into", otense(otmp, "plug"), (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole", surface(rx, ry)); deltrap(ttmp); delobj(otmp); bury_objs(rx, ry); if (cansee(rx,ry)) newsym(rx,ry); continue; case LEVEL_TELEP: case TELEP_TRAP: #ifdef STEED if (u.usteed) pline("%s pushes %s and suddenly it disappears!", upstart(y_monnam(u.usteed)), the(xname(otmp))); else #endif You("push %s and suddenly it disappears!", the(xname(otmp))); if (ttmp->ttyp == TELEP_TRAP) rloco(otmp); else { int newlev = random_teleport_level(); d_level dest; if (newlev == depth(&u.uz) || In_endgame(&u.uz)) continue; obj_extract_self(otmp); add_to_migration(otmp); get_level(&dest, newlev); otmp->ox = dest.dnum; otmp->oy = dest.dlevel; otmp->owornmask = (long)MIGR_RANDOM; } seetrap(ttmp); continue; } if (closed_door(rx, ry)) goto nopushmsg; if (boulder_hits_pool(otmp, rx, ry, TRUE)) continue; /* * Re-link at top of fobj chain so that pile order is preserved * when level is restored. */ if (otmp != fobj) { remove_object(otmp); place_object(otmp, otmp->ox, otmp->oy); } { #ifdef LINT /* static long lastmovetime; */ long lastmovetime; lastmovetime = 0; #else /* note: reset to zero after save/restore cycle */ static NEARDATA long lastmovetime; #endif #ifdef STEED if (!u.usteed) { #endif if (moves > lastmovetime+2 || moves < lastmovetime) pline("With %s effort you move %s.", throws_rocks(youmonst.data) ? "little" : "great", the(xname(otmp))); exercise(A_STR, TRUE); #ifdef STEED } else pline("%s moves %s.", upstart(y_monnam(u.usteed)), the(xname(otmp))); #endif lastmovetime = moves; } /* Move the boulder *after* the message. */ if (glyph_is_invisible(levl[rx][ry].glyph)) unmap_object(rx, ry); movobj(otmp, rx, ry); /* does newsym(rx,ry) */ if (Blind) { feel_location(rx,ry); feel_location(sx, sy); } else { newsym(sx, sy); } } else { nopushmsg: #ifdef STEED if (u.usteed) pline("%s tries to move %s, but cannot.", upstart(y_monnam(u.usteed)), the(xname(otmp))); else #endif You("try to move %s, but in vain.", the(xname(otmp))); if (Blind) feel_location(sx, sy); cannot_push: if (throws_rocks(youmonst.data)) { #ifdef STEED if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { You("aren't skilled enough to %s %s from %s.", (flags.pickup && !In_sokoban(&u.uz)) ? "pick up" : "push aside", the(xname(otmp)), y_monnam(u.usteed)); } else #endif { pline("However, you can easily %s.", (flags.pickup && !In_sokoban(&u.uz)) ? "pick it up" : "push it aside"); if (In_sokoban(&u.uz)) change_luck(-1); /* Sokoban guilt */ break; } break; } if ( #ifdef STEED !u.usteed && #endif (((!invent || inv_weight() <= -850) && (!u.dx || !u.dy || (IS_ROCK(levl[u.ux][sy].typ) && IS_ROCK(levl[sx][u.uy].typ)))) || verysmall(youmonst.data))) { pline("However, you can squeeze yourself into a small opening."); if (In_sokoban(&u.uz)) change_luck(-1); /* Sokoban guilt */ break; } else return (-1); } } return (0); } /* * still_chewing() * * Chew on a wall, door, or boulder. Returns TRUE if still eating, FALSE * when done. */ STATIC_OVL int still_chewing(x,y) xchar x, y; { struct rm *lev = &levl[x][y]; struct obj *boulder = sobj_at(BOULDER,x,y); const char *digtxt = (char *)0, *dmgtxt = (char *)0; if (digging.down) /* not continuing previous dig (w/ pick-axe) */ (void) memset((genericptr_t)&digging, 0, sizeof digging); if (!boulder && IS_ROCK(lev->typ) && !may_dig(x,y)) { You("hurt your teeth on the %s.", IS_TREE(lev->typ) ? "tree" : "hard stone"); nomul(0); return 1; } else if (digging.pos.x != x || digging.pos.y != y || !on_level(&digging.level, &u.uz)) { digging.down = FALSE; digging.chew = TRUE; digging.warned = FALSE; digging.pos.x = x; digging.pos.y = y; assign_level(&digging.level, &u.uz); /* solid rock takes more work & time to dig through */ digging.effort = (IS_ROCK(lev->typ) && !IS_TREE(lev->typ) ? 30 : 60) + u.udaminc; You("start chewing %s %s.", (boulder || IS_TREE(lev->typ)) ? "on a" : "a hole in the", boulder ? "boulder" : IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : "door"); watch_dig((struct monst *)0, x, y, FALSE); return 1; } else if ((digging.effort += (30 + u.udaminc)) <= 100) { if (flags.verbose) You("%s chewing on the %s.", digging.chew ? "continue" : "begin", boulder ? "boulder" : IS_TREE(lev->typ) ? "tree" : IS_ROCK(lev->typ) ? "rock" : "door"); digging.chew = TRUE; watch_dig((struct monst *)0, x, y, FALSE); return 1; } /* Okay, you've chewed through something */ u.uconduct.food++; u.uhunger += rnd(20); if (boulder) { delobj(boulder); /* boulder goes bye-bye */ You("eat the boulder."); /* yum */ /* * The location could still block because of * 1. More than one boulder * 2. Boulder stuck in a wall/stone/door. * * [perhaps use does_block() below (from vision.c)] */ if (IS_ROCK(lev->typ) || closed_door(x,y) || sobj_at(BOULDER,x,y)) { block_point(x,y); /* delobj will unblock the point */ /* reset dig state */ (void) memset((genericptr_t)&digging, 0, sizeof digging); return 1; } } else if (IS_WALL(lev->typ)) { if (*in_rooms(x, y, SHOPBASE)) { add_damage(x, y, 10L * ACURRSTR); dmgtxt = "damage"; } digtxt = "chew a hole in the wall."; if (level.flags.is_maze_lev) { lev->typ = ROOM; } else if (level.flags.is_cavernous_lev && !in_town(x, y)) { lev->typ = CORR; } else { lev->typ = DOOR; lev->doormask = D_NODOOR; } } else if (IS_TREE(lev->typ)) { digtxt = "chew through the tree."; lev->typ = ROOM; } else if (lev->typ == SDOOR) { if (lev->doormask & D_TRAPPED) { lev->doormask = D_NODOOR; b_trapped("secret door", 0); } else { digtxt = "chew through the secret door."; lev->doormask = D_BROKEN; } lev->typ = DOOR; } else if (IS_DOOR(lev->typ)) { if (*in_rooms(x, y, SHOPBASE)) { add_damage(x, y, 400L); dmgtxt = "break"; } if (lev->doormask & D_TRAPPED) { lev->doormask = D_NODOOR; b_trapped("door", 0); } else { digtxt = "chew through the door."; lev->doormask = D_BROKEN; } } else { /* STONE or SCORR */ digtxt = "chew a passage through the rock."; lev->typ = CORR; } unblock_point(x, y); /* vision */ newsym(x, y); if (digtxt) You(digtxt); /* after newsym */ if (dmgtxt) pay_for_damage(dmgtxt, FALSE); (void) memset((genericptr_t)&digging, 0, sizeof digging); return 0; } #endif /* OVL2 */ #ifdef OVLB void movobj(obj, ox, oy) register struct obj *obj; register xchar ox, oy; { /* optimize by leaving on the fobj chain? */ remove_object(obj); newsym(obj->ox, obj->oy); place_object(obj, ox, oy); newsym(ox, oy); } #ifdef SINKS static NEARDATA const char fell_on_sink[] = "fell onto a sink"; STATIC_OVL void dosinkfall() { register struct obj *obj; if (is_floater(youmonst.data) || (HLevitation & FROMOUTSIDE)) { You("wobble unsteadily for a moment."); } else { long save_ELev = ELevitation, save_HLev = HLevitation; /* fake removal of levitation in advance so that final disclosure will be right in case this turns out to be fatal; fortunately the fact that rings and boots are really still worn has no effect on bones data */ ELevitation = HLevitation = 0L; You("crash to the floor!"); losehp(rn1(8, 25 - (int)ACURR(A_CON)), fell_on_sink, NO_KILLER_PREFIX); exercise(A_DEX, FALSE); selftouch("Falling, you"); for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) if (obj->oclass == WEAPON_CLASS || is_weptool(obj)) { You("fell on %s.", doname(obj)); losehp(rnd(3), fell_on_sink, NO_KILLER_PREFIX); exercise(A_CON, FALSE); } ELevitation = save_ELev; HLevitation = save_HLev; } ELevitation &= ~W_ARTI; HLevitation &= ~(I_SPECIAL|TIMEOUT); HLevitation++; if(uleft && uleft->otyp == RIN_LEVITATION) { obj = uleft; Ring_off(obj); off_msg(obj); } if(uright && uright->otyp == RIN_LEVITATION) { obj = uright; Ring_off(obj); off_msg(obj); } if(uarmf && uarmf->otyp == LEVITATION_BOOTS) { obj = uarmf; (void)Boots_off(); off_msg(obj); } HLevitation--; } #endif boolean may_dig(x,y) register xchar x,y; /* intended to be called only on ROCKs */ { return (boolean)(!(IS_STWALL(levl[x][y].typ) && (levl[x][y].wall_info & W_NONDIGGABLE))); } boolean may_passwall(x,y) register xchar x,y; { return (boolean)(!(IS_STWALL(levl[x][y].typ) && (levl[x][y].wall_info & W_NONPASSWALL))); } #endif /* OVLB */ #ifdef OVL1 boolean bad_rock(mdat,x,y) struct permonst *mdat; register xchar x,y; { return((boolean) ((In_sokoban(&u.uz) && sobj_at(BOULDER,x,y)) || (IS_ROCK(levl[x][y].typ) && (!tunnels(mdat) || needspick(mdat) || !may_dig(x,y)) && !(passes_walls(mdat) && may_passwall(x,y))))); } boolean invocation_pos(x, y) xchar x, y; { return((boolean)(Invocation_lev(&u.uz) && x == inv_pos.x && y == inv_pos.y)); } #endif /* OVL1 */ #ifdef OVL3 /* return TRUE if (dx,dy) is an OK place to move * mode is one of DO_MOVE, TEST_MOVE or TEST_TRAV */ boolean test_move(ux, uy, dx, dy, mode) int ux, uy, dx, dy; int mode; { int x = ux+dx; int y = uy+dy; register struct rm *tmpr = &levl[x][y]; register struct rm *ust; /* * Check for physical obstacles. First, the place we are going. */ if (IS_ROCK(tmpr->typ) || tmpr->typ == IRONBARS) { if (Blind && mode == DO_MOVE) feel_location(x,y); if (Passes_walls && may_passwall(x,y)) { ; /* do nothing */ } else if (tmpr->typ == IRONBARS) { if (!(Passes_walls || passes_bars(youmonst.data))) return FALSE; } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { /* Eat the rock. */ if (mode == DO_MOVE && still_chewing(x,y)) return FALSE; } else if (flags.autodig && !flags.run && !flags.nopick && uwep && is_pick(uwep)) { /* MRKR: Automatic digging when wielding the appropriate tool */ if (mode == DO_MOVE) (void) use_pick_axe2(uwep); return FALSE; } else { if (mode == DO_MOVE) { if (Is_stronghold(&u.uz) && is_db_wall(x,y)) pline_The("drawbridge is up!"); if (Passes_walls && !may_passwall(x,y) && In_sokoban(&u.uz)) pline_The("Sokoban walls resist your ability."); } return FALSE; } } else if (IS_DOOR(tmpr->typ)) { if (closed_door(x,y)) { if (Blind && mode == DO_MOVE) feel_location(x,y); if (Passes_walls) ; /* do nothing */ else if (can_ooze(&youmonst)) { if (mode == DO_MOVE) You("ooze under the door."); } else if (tunnels(youmonst.data) && !needspick(youmonst.data)) { /* Eat the door. */ if (mode == DO_MOVE && still_chewing(x,y)) return FALSE; } else { if (mode == DO_MOVE) { if (amorphous(youmonst.data)) You("try to ooze under the door, but can't squeeze your possessions through."); else if (x == ux || y == uy) { if (Blind || Stunned || ACURR(A_DEX) < 10 || Fumbling) { #ifdef STEED if (u.usteed) { You_cant("lead %s through that closed door.", y_monnam(u.usteed)); } else #endif { pline("Ouch! You bump into a door."); exercise(A_DEX, FALSE); } } else pline("That door is closed."); } } else if (mode == TEST_TRAV) goto testdiag; return FALSE; } } else { testdiag: if (dx && dy && !Passes_walls && ((tmpr->doormask & ~D_BROKEN) #ifdef REINCARNATION || Is_rogue_level(&u.uz) #endif || block_door(x,y))) { /* Diagonal moves into a door are not allowed. */ if (Blind && mode == DO_MOVE) feel_location(x,y); return FALSE; } } } if (dx && dy && bad_rock(youmonst.data,ux,y) && bad_rock(youmonst.data,x,uy)) { /* Move at a diagonal. */ if (In_sokoban(&u.uz)) { if (mode == DO_MOVE) You("cannot pass that way."); return FALSE; } if (bigmonst(youmonst.data)) { if (mode == DO_MOVE) Your("body is too large to fit through."); return FALSE; } if (invent && (inv_weight() + weight_cap() > 600)) { if (mode == DO_MOVE) You("are carrying too much to get through."); return FALSE; } } /* Pick travel path that does not require crossing a trap. * Avoid water and lava using the usual running rules. * (but not u.ux/u.uy because findtravelpath walks toward u.ux/u.uy) */ if (flags.run == 8 && mode != DO_MOVE && (x != u.ux || y != u.uy)) { struct trap* t = t_at(x, y); if ((t && t->tseen) || (!Levitation && !Flying && !is_clinger(youmonst.data) && (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv)) return FALSE; } ust = &levl[ux][uy]; /* Now see if other things block our way . . */ if (dx && dy && !Passes_walls && (IS_DOOR(ust->typ) && ((ust->doormask & ~D_BROKEN) #ifdef REINCARNATION || Is_rogue_level(&u.uz) #endif || block_entry(x, y)) )) { /* Can't move at a diagonal out of a doorway with door. */ return FALSE; } if (sobj_at(BOULDER,x,y) && (In_sokoban(&u.uz) || !Passes_walls)) { if (!(Blind || Hallucination) && (flags.run >= 2) && mode != TEST_TRAV) return FALSE; if (mode == DO_MOVE) { /* tunneling monsters will chew before pushing */ if (tunnels(youmonst.data) && !needspick(youmonst.data) && !In_sokoban(&u.uz)) { if (still_chewing(x,y)) return FALSE; } else if (moverock() < 0) return FALSE; } else if (mode == TEST_TRAV) { struct obj* obj; /* don't pick two boulders in a row, unless there's a way thru */ if (sobj_at(BOULDER,ux,uy) && !In_sokoban(&u.uz)) { if (!Passes_walls && !(tunnels(youmonst.data) && !needspick(youmonst.data)) && !carrying(PICK_AXE) && !carrying(DWARVISH_MATTOCK) && !((obj = carrying(WAN_DIGGING)) && !objects[obj->otyp].oc_name_known)) return FALSE; } } /* assume you'll be able to push it when you get there... */ } /* OK, it is a legal place to move. */ return TRUE; } /* * Find a path from the destination (u.tx,u.ty) back to (u.ux,u.uy). * A shortest path is returned. If guess is TRUE, consider various * inaccessible locations as valid intermediate path points. * Returns TRUE if a path was found. */ static boolean findtravelpath(guess) boolean guess; { /* if travel to adjacent, reachable location, use normal movement rules */ if (!guess && iflags.travel1 && distmin(u.ux, u.uy, u.tx, u.ty) == 1) { flags.run = 0; if (test_move(u.ux, u.uy, u.tx-u.ux, u.ty-u.uy, TEST_MOVE)) { u.dx = u.tx-u.ux; u.dy = u.ty-u.uy; nomul(0); iflags.travelcc.x = iflags.travelcc.y = -1; return TRUE; } flags.run = 8; } if (u.tx != u.ux || u.ty != u.uy) { xchar travel[COLNO][ROWNO]; xchar travelstepx[2][COLNO*ROWNO]; xchar travelstepy[2][COLNO*ROWNO]; xchar tx, ty, ux, uy; int n = 1; /* max offset in travelsteps */ int set = 0; /* two sets current and previous */ int radius = 1; /* search radius */ int i; /* If guessing, first find an "obvious" goal location. The obvious * goal is the position the player knows of, or might figure out * (couldsee) that is closest to the target on a straight path. */ if (guess) { tx = u.ux; ty = u.uy; ux = u.tx; uy = u.ty; } else { tx = u.tx; ty = u.ty; ux = u.ux; uy = u.uy; } noguess: (void) memset((genericptr_t)travel, 0, sizeof(travel)); travelstepx[0][0] = tx; travelstepy[0][0] = ty; while (n != 0) { int nn = 0; for (i = 0; i < n; i++) { int dir; int x = travelstepx[set][i]; int y = travelstepy[set][i]; static int ordered[] = { 0, 2, 4, 6, 1, 3, 5, 7 }; /* no diagonal movement for grid bugs */ int dirmax = u.umonnum == PM_GRID_BUG ? 4 : 8; for (dir = 0; dir < dirmax; ++dir) { int nx = x+xdir[ordered[dir]]; int ny = y+ydir[ordered[dir]]; if (!isok(nx, ny)) continue; if ((!Passes_walls && !can_ooze(&youmonst) && closed_door(x, y)) || sobj_at(BOULDER, x, y)) { /* closed doors and boulders usually * cause a delay, so prefer another path */ if (travel[x][y] > radius-3) { travelstepx[1-set][nn] = x; travelstepy[1-set][nn] = y; /* don't change travel matrix! */ nn++; continue; } } if (test_move(x, y, nx-x, ny-y, TEST_TRAV) && (levl[nx][ny].seenv || (!Blind && couldsee(nx, ny)))) { if (nx == ux && ny == uy) { if (!guess) { u.dx = x-ux; u.dy = y-uy; if (x == u.tx && y == u.ty) { nomul(0); /* reset run so domove run checks work */ flags.run = 8; iflags.travelcc.x = iflags.travelcc.y = -1; } return TRUE; } } else if (!travel[nx][ny]) { travelstepx[1-set][nn] = nx; travelstepy[1-set][nn] = ny; travel[nx][ny] = radius; nn++; } } } } n = nn; set = 1-set; radius++; } /* if guessing, find best location in travel matrix and go there */ if (guess) { int px = tx, py = ty; /* pick location */ int dist, nxtdist, d2, nd2; dist = distmin(ux, uy, tx, ty); d2 = dist2(ux, uy, tx, ty); for (tx = 1; tx < COLNO; ++tx) for (ty = 0; ty < ROWNO; ++ty) if (travel[tx][ty]) { nxtdist = distmin(ux, uy, tx, ty); if (nxtdist == dist && couldsee(tx, ty)) { nd2 = dist2(ux, uy, tx, ty); if (nd2 < d2) { /* prefer non-zigzag path */ px = tx; py = ty; d2 = nd2; } } else if (nxtdist < dist && couldsee(tx, ty)) { px = tx; py = ty; dist = nxtdist; d2 = dist2(ux, uy, tx, ty); } } if (px == u.ux && py == u.uy) { /* no guesses, just go in the general direction */ u.dx = sgn(u.tx - u.ux); u.dy = sgn(u.ty - u.uy); if (test_move(u.ux, u.uy, u.dx, u.dy, TEST_MOVE)) return TRUE; goto found; } tx = px; ty = py; ux = u.ux; uy = u.uy; set = 0; n = radius = 1; guess = FALSE; goto noguess; } return FALSE; } found: u.dx = 0; u.dy = 0; nomul(0); return FALSE; } void domove() { register struct monst *mtmp; register struct rm *tmpr; register xchar x,y; struct trap *trap; int wtcap; boolean on_ice; xchar chainx, chainy, ballx, bally; /* ball&chain new positions */ int bc_control; /* control for ball&chain */ boolean cause_delay = FALSE; /* dragging ball will skip a move */ const char *predicament; u_wipe_engr(rnd(5)); if (flags.travel) { if (!findtravelpath(FALSE)) (void) findtravelpath(TRUE); iflags.travel1 = 0; } if(((wtcap = near_capacity()) >= OVERLOADED || (wtcap > SLT_ENCUMBER && (Upolyd ? (u.mh < 5 && u.mh != u.mhmax) : (u.uhp < 10 && u.uhp != u.uhpmax)))) && !Is_airlevel(&u.uz)) { if(wtcap < OVERLOADED) { You("don't have enough stamina to move."); exercise(A_CON, FALSE); } else You("collapse under your load."); nomul(0); return; } if(u.uswallow) { u.dx = u.dy = 0; u.ux = x = u.ustuck->mx; u.uy = y = u.ustuck->my; mtmp = u.ustuck; } else { if (Is_airlevel(&u.uz) && rn2(4) && !Levitation && !Flying) { switch(rn2(3)) { case 0: You("tumble in place."); exercise(A_DEX, FALSE); break; case 1: You_cant("control your movements very well."); break; case 2: pline("It's hard to walk in thin air."); exercise(A_DEX, TRUE); break; } return; } /* check slippery ice */ on_ice = !Levitation && is_ice(u.ux, u.uy); if (on_ice) { static int skates = 0; if (!skates) skates = find_skates(); if ((uarmf && uarmf->otyp == skates) || resists_cold(&youmonst) || Flying || is_floater(youmonst.data) || is_clinger(youmonst.data) || is_whirly(youmonst.data)) on_ice = FALSE; else if (!rn2(Cold_resistance ? 3 : 2)) { HFumbling |= FROMOUTSIDE; HFumbling &= ~TIMEOUT; HFumbling += 1; /* slip on next move */ } } if (!on_ice && (HFumbling & FROMOUTSIDE)) HFumbling &= ~FROMOUTSIDE; x = u.ux + u.dx; y = u.uy + u.dy; if(Stunned || (Confusion && !rn2(5))) { register int tries = 0; do { if(tries++ > 50) { nomul(0); return; } confdir(); x = u.ux + u.dx; y = u.uy + u.dy; } while(!isok(x, y) || bad_rock(youmonst.data, x, y)); } /* turbulence might alter your actual destination */ if (u.uinwater) { water_friction(); if (!u.dx && !u.dy) { nomul(0); return; } x = u.ux + u.dx; y = u.uy + u.dy; } if(!isok(x, y)) { nomul(0); return; } if (((trap = t_at(x, y)) && trap->tseen) || (Blind && !Levitation && !Flying && !is_clinger(youmonst.data) && (is_pool(x, y) || is_lava(x, y)) && levl[x][y].seenv)) { if(flags.run >= 2) { nomul(0); flags.move = 0; return; } else nomul(0); } if (u.ustuck && (x != u.ustuck->mx || y != u.ustuck->my)) { if (distu(u.ustuck->mx, u.ustuck->my) > 2) { /* perhaps it fled (or was teleported or ... ) */ u.ustuck = 0; } else if (sticks(youmonst.data)) { /* When polymorphed into a sticking monster, * u.ustuck means it's stuck to you, not you to it. */ You("release %s.", mon_nam(u.ustuck)); u.ustuck = 0; } else { /* If holder is asleep or paralyzed: * 37.5% chance of getting away, * 12.5% chance of waking/releasing it; * otherwise: * 7.5% chance of getting away. * [strength ought to be a factor] * If holder is tame and there is no conflict, * guaranteed escape. */ switch (rn2(!u.ustuck->mcanmove ? 8 : 40)) { case 0: case 1: case 2: pull_free: You("pull free from %s.", mon_nam(u.ustuck)); u.ustuck = 0; break; case 3: if (!u.ustuck->mcanmove) { /* it's free to move on next turn */ u.ustuck->mfrozen = 1; u.ustuck->msleeping = 0; } /*FALLTHRU*/ default: if (u.ustuck->mtame && !Conflict && !u.ustuck->mconf) goto pull_free; You("cannot escape from %s!", mon_nam(u.ustuck)); nomul(0); return; } } } mtmp = m_at(x,y); if (mtmp) { /* Don't attack if you're running, and can see it */ /* We should never get here if forcefight */ if (flags.run && ((!Blind && mon_visible(mtmp) && ((mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT) || Protection_from_shape_changers)) || sensemon(mtmp))) { nomul(0); flags.move = 0; return; } } } u.ux0 = u.ux; u.uy0 = u.uy; bhitpos.x = x; bhitpos.y = y; tmpr = &levl[x][y]; /* attack monster */ if(mtmp) { nomul(0); /* only attack if we know it's there */ /* or if we used the 'F' command to fight blindly */ /* or if it hides_under, in which case we call attack() to print * the Wait! message. * This is different from ceiling hiders, who aren't handled in * attack(). */ /* If they used a 'm' command, trying to move onto a monster * prints the below message and wastes a turn. The exception is * if the monster is unseen and the player doesn't remember an * invisible monster--then, we fall through to attack() and * attack_check(), which still wastes a turn, but prints a * different message and makes the player remember the monster. */ if(flags.nopick && (canspotmon(mtmp) || glyph_is_invisible(levl[x][y].glyph))){ if(mtmp->m_ap_type && !Protection_from_shape_changers && !sensemon(mtmp)) stumble_onto_mimic(mtmp); else if (mtmp->mpeaceful && !Hallucination) pline("Pardon me, %s.", m_monnam(mtmp)); else You("move right into %s.", mon_nam(mtmp)); return; } if(flags.forcefight || !mtmp->mundetected || sensemon(mtmp) || ((hides_under(mtmp->data) || mtmp->data->mlet == S_EEL) && !is_safepet(mtmp))){ gethungry(); if(wtcap >= HVY_ENCUMBER && moves%3) { if (Upolyd && u.mh > 1) { u.mh--; } else if (!Upolyd && u.uhp > 1) { u.uhp--; } else { You("pass out from exertion!"); exercise(A_CON, FALSE); fall_asleep(-10, FALSE); } } if(multi < 0) return; /* we just fainted */ /* try to attack; note that it might evade */ /* also, we don't attack tame when _safepet_ */ if(attack(mtmp)) return; } } /* specifying 'F' with no monster wastes a turn */ if (flags.forcefight || /* remembered an 'I' && didn't use a move command */ (glyph_is_invisible(levl[x][y].glyph) && !flags.nopick)) { boolean expl = (Upolyd && attacktype(youmonst.data, AT_EXPL)); char buf[BUFSZ]; Sprintf(buf,"a vacant spot on the %s", surface(x,y)); You("%s %s.", expl ? "explode at" : "attack", !Underwater ? "thin air" : is_pool(x,y) ? "empty water" : buf); unmap_object(x, y); /* known empty -- remove 'I' if present */ newsym(x, y); nomul(0); if (expl) { u.mh = -1; /* dead in the current form */ rehumanize(); } return; } if (glyph_is_invisible(levl[x][y].glyph)) { unmap_object(x, y); newsym(x, y); } /* not attacking an animal, so we try to move */ #ifdef STEED if (u.usteed && !u.usteed->mcanmove && (u.dx || u.dy)) { pline("%s won't move!", upstart(y_monnam(u.usteed))); nomul(0); return; } else #endif if(!youmonst.data->mmove) { You("are rooted %s.", Levitation || Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) ? "in place" : "to the ground"); nomul(0); return; } if(u.utrap) { if(u.utraptype == TT_PIT) { if (!rn2(2) && sobj_at(BOULDER, u.ux, u.uy)) { Your("%s gets stuck in a crevice.", body_part(LEG)); display_nhwindow(WIN_MESSAGE, FALSE); clear_nhwindow(WIN_MESSAGE); You("free your %s.", body_part(LEG)); } else if (!(--u.utrap)) { You("%s to the edge of the pit.", (In_sokoban(&u.uz) && Levitation) ? "struggle against the air currents and float" : #ifdef STEED u.usteed ? "ride" : #endif "crawl"); fill_pit(u.ux, u.uy); vision_full_recalc = 1; /* vision limits change */ } else if (flags.verbose) { #ifdef STEED if (u.usteed) Norep("%s is still in a pit.", upstart(y_monnam(u.usteed))); else #endif Norep( (Hallucination && !rn2(5)) ? "You've fallen, and you can't get up." : "You are still in a pit." ); } } else if (u.utraptype == TT_LAVA) { if(flags.verbose) { predicament = "stuck in the lava"; #ifdef STEED if (u.usteed) Norep("%s is %s.", upstart(y_monnam(u.usteed)), predicament); else #endif Norep("You are %s.", predicament); } if(!is_lava(x,y)) { u.utrap--; if((u.utrap & 0xff) == 0) { #ifdef STEED if (u.usteed) You("lead %s to the edge of the lava.", y_monnam(u.usteed)); else #endif You("pull yourself to the edge of the lava."); u.utrap = 0; } } u.umoved = TRUE; } else if (u.utraptype == TT_WEB) { if(uwep && uwep->oartifact == ART_STING) { u.utrap = 0; pline("Sting cuts through the web!"); return; } if(--u.utrap) { if(flags.verbose) { predicament = "stuck to the web"; #ifdef STEED if (u.usteed) Norep("%s is %s.", upstart(y_monnam(u.usteed)), predicament); else #endif Norep("You are %s.", predicament); } } else { #ifdef STEED if (u.usteed) pline("%s breaks out of the web.", upstart(y_monnam(u.usteed))); else #endif You("disentangle yourself."); } } else if (u.utraptype == TT_INFLOOR) { if(--u.utrap) { if(flags.verbose) { predicament = "stuck in the"; #ifdef STEED if (u.usteed) Norep("%s is %s %s.", upstart(y_monnam(u.usteed)), predicament, surface(u.ux, u.uy)); else #endif Norep("You are %s %s.", predicament, surface(u.ux, u.uy)); } } else { #ifdef STEED if (u.usteed) pline("%s finally wiggles free.", upstart(y_monnam(u.usteed))); else #endif You("finally wiggle free."); } } else { if(flags.verbose) { predicament = "caught in a bear trap"; #ifdef STEED if (u.usteed) Norep("%s is %s.", upstart(y_monnam(u.usteed)), predicament); else #endif Norep("You are %s.", predicament); } if((u.dx && u.dy) || !rn2(5)) u.utrap--; } return; } if (!test_move(u.ux, u.uy, x-u.ux, y-u.uy, DO_MOVE)) { flags.move = 0; nomul(0); return; } /* Move ball and chain. */ if (Punished) if (!drag_ball(x,y, &bc_control, &ballx, &bally, &chainx, &chainy, &cause_delay, TRUE)) return; /* Check regions entering/leaving */ if (!in_out_region(x,y)) return; /* now move the hero */ mtmp = m_at(x, y); u.ux += u.dx; u.uy += u.dy; #ifdef STEED /* Move your steed, too */ if (u.usteed) { u.usteed->mx = u.ux; u.usteed->my = u.uy; exercise_steed(); } #endif /* * If safepet at destination then move the pet to the hero's * previous location using the same conditions as in attack(). * there are special extenuating circumstances: * (1) if the pet dies then your god angers, * (2) if the pet gets trapped then your god may disapprove, * (3) if the pet was already trapped and you attempt to free it * not only do you encounter the trap but you may frighten your * pet causing it to go wild! moral: don't abuse this privilege. * * Ceiling-hiding pets are skipped by this section of code, to * be caught by the normal falling-monster code. */ if (is_safepet(mtmp) && !(is_hider(mtmp->data) && mtmp->mundetected)) { /* if trapped, there's a chance the pet goes wild */ if (mtmp->mtrapped) { if (!rn2(mtmp->mtame)) { mtmp->mtame = mtmp->mpeaceful = mtmp->msleeping = 0; if (mtmp->mleashed) m_unleash(mtmp, TRUE); growl(mtmp); } else { yelp(mtmp); } } mtmp->mundetected = 0; if (mtmp->m_ap_type) seemimic(mtmp); else if (!mtmp->mtame) newsym(mtmp->mx, mtmp->my); if (mtmp->mtrapped && (trap = t_at(mtmp->mx, mtmp->my)) != 0 && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT) && sobj_at(BOULDER, trap->tx, trap->ty)) { /* can't swap places with pet pinned in a pit by a boulder */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ } else if (u.ux0 != x && u.uy0 != y && bad_rock(mtmp->data, x, u.uy0) && bad_rock(mtmp->data, u.ux0, y) && (bigmonst(mtmp->data) || (curr_mon_load(mtmp) > 600))) { /* can't swap places when pet won't fit thru the opening */ u.ux = u.ux0, u.uy = u.uy0; /* didn't move after all */ You("stop. %s won't fit through.", upstart(y_monnam(mtmp))); } else { char pnambuf[BUFSZ]; /* save its current description in case of polymorph */ Strcpy(pnambuf, y_monnam(mtmp)); mtmp->mtrapped = 0; remove_monster(x, y); place_monster(mtmp, u.ux0, u.uy0); /* check for displacing it into pools and traps */ switch (minliquid(mtmp) ? 2 : mintrap(mtmp)) { case 0: You("%s %s.", mtmp->mtame ? "displaced" : "frightened", pnambuf); break; case 1: /* trapped */ case 3: /* changed levels */ /* there's already been a trap message, reinforce it */ abuse_dog(mtmp); adjalign(-3); break; case 2: /* it may have drowned or died. that's no way to * treat a pet! your god gets angry. */ if (rn2(4)) { You_feel("guilty about losing your pet like this."); u.ugangr++; adjalign(-15); } /* you killed your pet by direct action. * minliquid and mintrap don't know to do this */ u.uconduct.killer++; break; default: pline("that's strange, unknown mintrap result!"); break; } } } reset_occupations(); if (flags.run) { if ( flags.run < 8 ) if (IS_DOOR(tmpr->typ) || IS_ROCK(tmpr->typ) || IS_FURNITURE(tmpr->typ)) nomul(0); } if (hides_under(youmonst.data)) u.uundetected = OBJ_AT(u.ux, u.uy); else if (youmonst.data->mlet == S_EEL) u.uundetected = is_pool(u.ux, u.uy) && !Is_waterlevel(&u.uz); else if (u.dx || u.dy) u.uundetected = 0; /* * Mimics (or whatever) become noticeable if they move and are * imitating something that doesn't move. We could extend this * to non-moving monsters... */ if ((u.dx || u.dy) && (youmonst.m_ap_type == M_AP_OBJECT || youmonst.m_ap_type == M_AP_FURNITURE)) youmonst.m_ap_type = M_AP_NOTHING; check_leash(u.ux0,u.uy0); if(u.ux0 != u.ux || u.uy0 != u.uy) { u.umoved = TRUE; /* Clean old position -- vision_recalc() will print our new one. */ newsym(u.ux0,u.uy0); /* Since the hero has moved, adjust what can be seen/unseen. */ vision_recalc(1); /* Do the work now in the recover time. */ invocation_message(); } if (Punished) /* put back ball and chain */ move_bc(0,bc_control,ballx,bally,chainx,chainy); spoteffects(TRUE); /* delay next move because of ball dragging */ /* must come after we finished picking up, in spoteffects() */ if (cause_delay) { nomul(-2); nomovemsg = ""; } if (flags.run && iflags.runmode != RUN_TPORT) { /* display every step or every 7th step depending upon mode */ if (iflags.runmode != RUN_LEAP || !(moves % 7L)) { if (flags.time) flags.botl = 1; curs_on_u(); delay_output(); if (iflags.runmode == RUN_CRAWL) { delay_output(); delay_output(); delay_output(); delay_output(); } } } } void invocation_message() { /* a special clue-msg when on the Invocation position */ if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { char buf[BUFSZ]; struct obj *otmp = carrying(CANDELABRUM_OF_INVOCATION); nomul(0); /* stop running or travelling */ #ifdef STEED if (u.usteed) Sprintf(buf, "beneath %s", y_monnam(u.usteed)); else #endif if (Levitation || Flying) Strcpy(buf, "beneath you"); else Sprintf(buf, "under your %s", makeplural(body_part(FOOT))); You_feel("a strange vibration %s.", buf); if (otmp && otmp->spe == 7 && otmp->lamplit) pline("%s %s!", The(xname(otmp)), Blind ? "throbs palpably" : "glows with a strange light"); } } #endif /* OVL3 */ #ifdef OVL2 void spoteffects(pick) boolean pick; { register struct monst *mtmp; if(u.uinwater) { int was_underwater; if (!is_pool(u.ux,u.uy)) { if (Is_waterlevel(&u.uz)) You("pop into an air bubble."); else if (is_lava(u.ux, u.uy)) You("leave the water..."); /* oops! */ else You("are on solid %s again.", is_ice(u.ux, u.uy) ? "ice" : "land"); } else if (Is_waterlevel(&u.uz)) goto stillinwater; else if (Levitation) You("pop out of the water like a cork!"); else if (Flying) You("fly out of the water."); else if (Wwalking) You("slowly rise above the surface."); else goto stillinwater; was_underwater = Underwater && !Is_waterlevel(&u.uz); u.uinwater = 0; /* leave the water */ if (was_underwater) { /* restore vision */ docrt(); vision_full_recalc = 1; } } stillinwater:; if (!Levitation && !u.ustuck && !Flying) { /* limit recursive calls through teleds() */ if (is_pool(u.ux, u.uy) || is_lava(u.ux, u.uy)) { #ifdef STEED if (u.usteed && !is_flyer(u.usteed->data) && !is_floater(u.usteed->data) && !is_clinger(u.usteed->data)) { dismount_steed(Underwater ? DISMOUNT_FELL : DISMOUNT_GENERIC); /* dismount_steed() -> float_down() -> pickup() */ if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz)) pick = FALSE; } else #endif if (is_lava(u.ux, u.uy)) { if (lava_effects()) return; } else if (!Wwalking && drown()) return; } } check_special_room(FALSE); #ifdef SINKS if(IS_SINK(levl[u.ux][u.uy].typ) && Levitation) dosinkfall(); #endif if (!in_steed_dismounting) { /* if dismounting, we'll check again later */ struct trap *trap = t_at(u.ux, u.uy); boolean pit; pit = (trap && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)); if (trap && pit) dotrap(trap, 0); /* fall into pit */ if (pick) (void) pickup(1); if (trap && !pit) dotrap(trap, 0); /* fall into arrow trap, etc. */ } if((mtmp = m_at(u.ux, u.uy)) && !u.uswallow) { mtmp->mundetected = mtmp->msleeping = 0; switch(mtmp->data->mlet) { case S_PIERCER: pline("%s suddenly drops from the %s!", Amonnam(mtmp), ceiling(u.ux,u.uy)); if(mtmp->mtame) /* jumps to greet you, not attack */ ; else if(uarmh && is_metallic(uarmh)) pline("Its blow glances off your helmet."); else if (u.uac + 3 <= rnd(20)) You("are almost hit by %s!", x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE)); else { int dmg; You("are hit by %s!", x_monnam(mtmp, ARTICLE_A, "falling", 0, TRUE)); dmg = d(4,6); if(Half_physical_damage) dmg = (dmg+1) / 2; mdamageu(mtmp, dmg); } break; default: /* monster surprises you. */ if(mtmp->mtame) pline("%s jumps near you from the %s.", Amonnam(mtmp), ceiling(u.ux,u.uy)); else if(mtmp->mpeaceful) { You("surprise %s!", Blind && !sensemon(mtmp) ? something : a_monnam(mtmp)); mtmp->mpeaceful = 0; } else pline("%s attacks you by surprise!", Amonnam(mtmp)); break; } mnexto(mtmp); /* have to move the monster */ } } STATIC_OVL boolean monstinroom(mdat,roomno) struct permonst *mdat; int roomno; { register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(!DEADMONSTER(mtmp) && mtmp->data == mdat && index(in_rooms(mtmp->mx, mtmp->my, 0), roomno + ROOMOFFSET)) return(TRUE); return(FALSE); } char * in_rooms(x, y, typewanted) register xchar x, y; register int typewanted; { static char buf[5]; char rno, *ptr = &buf[4]; int typefound, min_x, min_y, max_x, max_y_offset, step; register struct rm *lev; #define goodtype(rno) (!typewanted || \ ((typefound = rooms[rno - ROOMOFFSET].rtype) == typewanted) || \ ((typewanted == SHOPBASE) && (typefound > SHOPBASE))) \ switch (rno = levl[x][y].roomno) { case NO_ROOM: return(ptr); case SHARED: step = 2; break; case SHARED_PLUS: step = 1; break; default: /* i.e. a regular room # */ if (goodtype(rno)) *(--ptr) = rno; return(ptr); } min_x = x - 1; max_x = x + 1; if (x < 1) min_x += step; else if (x >= COLNO) max_x -= step; min_y = y - 1; max_y_offset = 2; if (min_y < 0) { min_y += step; max_y_offset -= step; } else if ((min_y + max_y_offset) >= ROWNO) max_y_offset -= step; for (x = min_x; x <= max_x; x += step) { lev = &levl[x][min_y]; y = 0; if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno) && goodtype(rno)) *(--ptr) = rno; y += step; if (y > max_y_offset) continue; if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno) && goodtype(rno)) *(--ptr) = rno; y += step; if (y > max_y_offset) continue; if (((rno = lev[y].roomno) >= ROOMOFFSET) && !index(ptr, rno) && goodtype(rno)) *(--ptr) = rno; } return(ptr); } /* is (x,y) in a town? */ boolean in_town(x, y) register int x, y; { s_level *slev = Is_special(&u.uz); register struct mkroom *sroom; boolean has_subrooms = FALSE; if (!slev || !slev->flags.town) return FALSE; /* * See if (x,y) is in a room with subrooms, if so, assume it's the * town. If there are no subrooms, the whole level is in town. */ for (sroom = &rooms[0]; sroom->hx > 0; sroom++) { if (sroom->nsubrooms > 0) { has_subrooms = TRUE; if (inside_room(sroom, x, y)) return TRUE; } } return !has_subrooms; } STATIC_OVL void move_update(newlev) register boolean newlev; { char *ptr1, *ptr2, *ptr3, *ptr4; Strcpy(u.urooms0, u.urooms); Strcpy(u.ushops0, u.ushops); if (newlev) { u.urooms[0] = '\0'; u.uentered[0] = '\0'; u.ushops[0] = '\0'; u.ushops_entered[0] = '\0'; Strcpy(u.ushops_left, u.ushops0); return; } Strcpy(u.urooms, in_rooms(u.ux, u.uy, 0)); for (ptr1 = &u.urooms[0], ptr2 = &u.uentered[0], ptr3 = &u.ushops[0], ptr4 = &u.ushops_entered[0]; *ptr1; ptr1++) { if (!index(u.urooms0, *ptr1)) *(ptr2++) = *ptr1; if (IS_SHOP(*ptr1 - ROOMOFFSET)) { *(ptr3++) = *ptr1; if (!index(u.ushops0, *ptr1)) *(ptr4++) = *ptr1; } } *ptr2 = '\0'; *ptr3 = '\0'; *ptr4 = '\0'; /* filter u.ushops0 -> u.ushops_left */ for (ptr1 = &u.ushops0[0], ptr2 = &u.ushops_left[0]; *ptr1; ptr1++) if (!index(u.ushops, *ptr1)) *(ptr2++) = *ptr1; *ptr2 = '\0'; } void check_special_room(newlev) register boolean newlev; { register struct monst *mtmp; char *ptr; move_update(newlev); if (*u.ushops0) u_left_shop(u.ushops_left, newlev); if (!*u.uentered && !*u.ushops_entered) /* implied by newlev */ return; /* no entrance messages necessary */ /* Did we just enter a shop? */ if (*u.ushops_entered) u_entered_shop(u.ushops_entered); for (ptr = &u.uentered[0]; *ptr; ptr++) { register int roomno = *ptr - ROOMOFFSET, rt = rooms[roomno].rtype; /* Did we just enter some other special room? */ /* vault.c insists that a vault remain a VAULT, * and temples should remain TEMPLEs, * but everything else gives a message only the first time */ switch (rt) { case ZOO: pline("Welcome to David's treasure zoo!"); break; case SWAMP: pline("It %s rather %s down here.", Blind ? "feels" : "looks", Blind ? "humid" : "muddy"); break; case COURT: You("enter an opulent throne room!"); break; case LEPREHALL: You("enter a leprechaun hall!"); break; case MORGUE: if(midnight()) { const char *run = locomotion(youmonst.data, "Run"); pline("%s away! %s away!", run, run); } else You("have an uncanny feeling..."); break; case BEEHIVE: You("enter a giant beehive!"); break; case COCKNEST: You("enter a disgusting nest!"); break; case ANTHOLE: You("enter an anthole!"); break; case BARRACKS: if(monstinroom(&mons[PM_SOLDIER], roomno) || monstinroom(&mons[PM_SERGEANT], roomno) || monstinroom(&mons[PM_LIEUTENANT], roomno) || monstinroom(&mons[PM_CAPTAIN], roomno)) You("enter a military barracks!"); else You("enter an abandoned barracks."); break; case DELPHI: if(monstinroom(&mons[PM_ORACLE], roomno)) verbalize("%s, %s, welcome to Delphi!", Hello((struct monst *) 0), plname); break; case TEMPLE: intemple(roomno + ROOMOFFSET); /* fall through */ default: rt = 0; } if (rt != 0) { rooms[roomno].rtype = OROOM; if (!search_special(rt)) { /* No more room of that type */ switch(rt) { case COURT: level.flags.has_court = 0; break; case SWAMP: level.flags.has_swamp = 0; break; case MORGUE: level.flags.has_morgue = 0; break; case ZOO: level.flags.has_zoo = 0; break; case BARRACKS: level.flags.has_barracks = 0; break; case TEMPLE: level.flags.has_temple = 0; break; case BEEHIVE: level.flags.has_beehive = 0; break; } } if (rt == COURT || rt == SWAMP || rt == MORGUE || rt == ZOO) for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp) && !Stealth && !rn2(3)) mtmp->msleeping = 0; } } return; } #endif /* OVL2 */ #ifdef OVLB int dopickup() { int count; struct trap *traphere = t_at(u.ux, u.uy); /* awful kludge to work around parse()'s pre-decrement */ count = (multi || (save_cm && *save_cm == ',')) ? multi + 1 : 0; multi = 0; /* always reset */ /* uswallow case added by GAN 01/29/87 */ if(u.uswallow) { if (!u.ustuck->minvent) { if (is_animal(u.ustuck->data)) { You("pick up %s tongue.", s_suffix(mon_nam(u.ustuck))); pline("But it's kind of slimy, so you drop it."); } else You("don't %s anything in here to pick up.", Blind ? "feel" : "see"); return(1); } else { int tmpcount = -count; return loot_mon(u.ustuck, &tmpcount, (boolean *)0); } } if(is_pool(u.ux, u.uy)) { if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data) || (Flying && !Breathless)) { You("cannot dive into the water to pick things up."); return(0); } else if (!Underwater) { You_cant("even see the bottom, let alone pick up %s.", something); return(0); } } if (is_lava(u.ux, u.uy)) { if (Wwalking || is_floater(youmonst.data) || is_clinger(youmonst.data) || (Flying && !Breathless)) { You_cant("reach the bottom to pick things up."); return(0); } else if (!likes_lava(youmonst.data)) { You("would burn to a crisp trying to pick things up."); return(0); } } if(!OBJ_AT(u.ux, u.uy)) { There("is nothing here to pick up."); return(0); } if (!can_reach_floor()) { #ifdef STEED if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) You("aren't skilled enough to reach from %s.", y_monnam(u.usteed)); else #endif You("cannot reach the %s.", surface(u.ux,u.uy)); return(0); } if (traphere && traphere->tseen) { /* Allow pickup from holes and trap doors that you escaped from * because that stuff is teetering on the edge just like you, but * not pits, because there is an elevation discrepancy with stuff * in pits. */ if ((traphere->ttyp == PIT || traphere->ttyp == SPIKED_PIT) && (!u.utrap || (u.utrap && u.utraptype != TT_PIT))) { You("cannot reach the bottom of the pit."); return(0); } } return (pickup(-count)); } #endif /* OVLB */ #ifdef OVL2 /* stop running if we see something interesting */ /* turn around a corner if that is the only way we can proceed */ /* do not turn left or right twice */ void lookaround() { register int x, y, i, x0 = 0, y0 = 0, m0 = 1, i0 = 9; register int corrct = 0, noturn = 0; register struct monst *mtmp; register struct trap *trap; /* Grid bugs stop if trying to move diagonal, even if blind. Maybe */ /* they polymorphed while in the middle of a long move. */ if (u.umonnum == PM_GRID_BUG && u.dx && u.dy) { nomul(0); return; } if(Blind || flags.run == 0) return; for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++) { if(!isok(x,y)) continue; if(u.umonnum == PM_GRID_BUG && x != u.ux && y != u.uy) continue; if(x == u.ux && y == u.uy) continue; if((mtmp = m_at(x,y)) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT && (!mtmp->minvis || See_invisible) && !mtmp->mundetected) { if((flags.run != 1 && !mtmp->mtame) || (x == u.ux+u.dx && y == u.uy+u.dy)) goto stop; } if (levl[x][y].typ == STONE) continue; if (x == u.ux-u.dx && y == u.uy-u.dy) continue; if (IS_ROCK(levl[x][y].typ) || (levl[x][y].typ == ROOM) || IS_AIR(levl[x][y].typ)) continue; else if (closed_door(x,y) || (mtmp && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor))) { if(x != u.ux && y != u.uy) continue; if(flags.run != 1) goto stop; goto bcorr; } else if (levl[x][y].typ == CORR) { bcorr: if(levl[u.ux][u.uy].typ != ROOM) { if(flags.run == 1 || flags.run == 3 || flags.run == 8) { i = dist2(x,y,u.ux+u.dx,u.uy+u.dy); if(i > 2) continue; if(corrct == 1 && dist2(x,y,x0,y0) != 1) noturn = 1; if(i < i0) { i0 = i; x0 = x; y0 = y; m0 = mtmp ? 1 : 0; } } corrct++; } continue; } else if ((trap = t_at(x,y)) && trap->tseen) { if(flags.run == 1) goto bcorr; /* if you must */ if(x == u.ux+u.dx && y == u.uy+u.dy) goto stop; continue; } else if (is_pool(x,y) || is_lava(x,y)) { /* water and lava only stop you if directly in front, and stop * you even if you are running */ if(!Levitation && !Flying && !is_clinger(youmonst.data) && x == u.ux+u.dx && y == u.uy+u.dy) /* No Wwalking check; otherwise they'd be able * to test boots by trying to SHIFT-direction * into a pool and seeing if the game allowed it */ goto stop; continue; } else { /* e.g. objects or trap or stairs */ if(flags.run == 1) goto bcorr; if(flags.run == 8) continue; if(mtmp) continue; /* d */ if(((x == u.ux - u.dx) && (y != u.uy + u.dy)) || ((y == u.uy - u.dy) && (x != u.ux + u.dx))) continue; } stop: nomul(0); return; } /* end for loops */ if(corrct > 1 && flags.run == 2) goto stop; if((flags.run == 1 || flags.run == 3 || flags.run == 8) && !noturn && !m0 && i0 && (corrct == 1 || (corrct == 2 && i0 == 1))) { /* make sure that we do not turn too far */ if(i0 == 2) { if(u.dx == y0-u.uy && u.dy == u.ux-x0) i = 2; /* straight turn right */ else i = -2; /* straight turn left */ } else if(u.dx && u.dy) { if((u.dx == u.dy && y0 == u.uy) || (u.dx != u.dy && y0 != u.uy)) i = -1; /* half turn left */ else i = 1; /* half turn right */ } else { if((x0-u.ux == y0-u.uy && !u.dy) || (x0-u.ux != y0-u.uy && u.dy)) i = 1; /* half turn right */ else i = -1; /* half turn left */ } i += u.last_str_turn; if(i <= 2 && i >= -2) { u.last_str_turn = i; u.dx = x0-u.ux; u.dy = y0-u.uy; } } } /* something like lookaround, but we are not running */ /* react only to monsters that might hit us */ int monster_nearby() { register int x,y; register struct monst *mtmp; /* Also see the similar check in dochugw() in monmove.c */ for(x = u.ux-1; x <= u.ux+1; x++) for(y = u.uy-1; y <= u.uy+1; y++) { if(!isok(x,y)) continue; if(x == u.ux && y == u.uy) continue; if((mtmp = m_at(x,y)) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT && (!mtmp->mpeaceful || Hallucination) && (!is_hider(mtmp->data) || !mtmp->mundetected) && !noattacks(mtmp->data) && mtmp->mcanmove && !mtmp->msleeping && /* aplvax!jcn */ !onscary(u.ux, u.uy, mtmp) && canspotmon(mtmp)) return(1); } return(0); } void nomul(nval) register int nval; { if(multi < nval) return; /* This is a bug fix by ab@unido */ u.uinvulnerable = FALSE; /* Kludge to avoid ctrl-C bug -dlc */ u.usleep = 0; multi = nval; flags.travel = iflags.travel1 = flags.mv = flags.run = 0; } /* called when a non-movement, multi-turn action has completed */ void unmul(msg_override) const char *msg_override; { multi = 0; /* caller will usually have done this already */ if (msg_override) nomovemsg = msg_override; else if (!nomovemsg) nomovemsg = You_can_move_again; if (*nomovemsg) pline(nomovemsg); nomovemsg = 0; u.usleep = 0; if (afternmv) (*afternmv)(); afternmv = 0; } #endif /* OVL2 */ #ifdef OVL1 STATIC_OVL void maybe_wail() { static short powers[] = { TELEPORT, SEE_INVIS, POISON_RES, COLD_RES, SHOCK_RES, FIRE_RES, SLEEP_RES, DISINT_RES, TELEPORT_CONTROL, STEALTH, FAST, INVIS }; if (moves <= wailmsg + 50) return; wailmsg = moves; if (Role_if(PM_WIZARD) || Race_if(PM_ELF) || Role_if(PM_VALKYRIE)) { const char *who; int i, powercnt; who = (Role_if(PM_WIZARD) || Role_if(PM_VALKYRIE)) ? urole.name.m : "Elf"; if (u.uhp == 1) { pline("%s is about to die.", who); } else { for (i = 0, powercnt = 0; i < SIZE(powers); ++i) if (u.uprops[powers[i]].intrinsic & INTRINSIC) ++powercnt; pline(powercnt >= 4 ? "%s, all your powers will be lost..." : "%s, your life force is running out.", who); } } else { You_hear(u.uhp == 1 ? "the wailing of the Banshee..." : "the howling of the CwnAnnwn..."); } } void losehp(n, knam, k_format) register int n; register const char *knam; boolean k_format; { if (Upolyd) { u.mh -= n; if (u.mhmax < u.mh) u.mhmax = u.mh; flags.botl = 1; if (u.mh < 1) rehumanize(); else if (n > 0 && u.mh*10 < u.mhmax && Unchanging) maybe_wail(); return; } u.uhp -= n; if(u.uhp > u.uhpmax) u.uhpmax = u.uhp; /* perhaps n was negative */ flags.botl = 1; if(u.uhp < 1) { killer_format = k_format; killer = knam; /* the thing that killed you */ You("die..."); done(DIED); } else if (n > 0 && u.uhp*10 < u.uhpmax) { maybe_wail(); } } int weight_cap() { register long carrcap; carrcap = 25*(ACURRSTR + ACURR(A_CON)) + 50; if (Upolyd) { /* consistent with can_carry() in mon.c */ if (youmonst.data->mlet == S_NYMPH) carrcap = MAX_CARR_CAP; else if (!youmonst.data->cwt) carrcap = (carrcap * (long)youmonst.data->msize) / MZ_HUMAN; else if (!strongmonst(youmonst.data) || (strongmonst(youmonst.data) && (youmonst.data->cwt > WT_HUMAN))) carrcap = (carrcap * (long)youmonst.data->cwt / WT_HUMAN); } if (Levitation || Is_airlevel(&u.uz) /* pugh@cornell */ #ifdef STEED || (u.usteed && strongmonst(u.usteed->data)) #endif ) carrcap = MAX_CARR_CAP; else { if(carrcap > MAX_CARR_CAP) carrcap = MAX_CARR_CAP; if (!Flying) { if(EWounded_legs & LEFT_SIDE) carrcap -= 100; if(EWounded_legs & RIGHT_SIDE) carrcap -= 100; } if (carrcap < 0) carrcap = 0; } return((int) carrcap); } static int wc; /* current weight_cap(); valid after call to inv_weight() */ /* returns how far beyond the normal capacity the player is currently. */ /* inv_weight() is negative if the player is below normal capacity. */ int inv_weight() { register struct obj *otmp = invent; register int wt = 0; #ifndef GOLDOBJ /* when putting stuff into containers, gold is inserted at the head of invent for easier manipulation by askchain & co, but it's also retained in u.ugold in order to keep the status line accurate; we mustn't add its weight in twice under that circumstance */ wt = (otmp && otmp->oclass == COIN_CLASS) ? 0 : (int)((u.ugold + 50L) / 100L); #endif while (otmp) { #ifndef GOLDOBJ if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data)) #else if (otmp->oclass == COIN_CLASS) wt += (int)(((long)otmp->quan + 50L) / 100L); else if (otmp->otyp != BOULDER || !throws_rocks(youmonst.data)) #endif wt += otmp->owt; otmp = otmp->nobj; } wc = weight_cap(); return (wt - wc); } /* * Returns 0 if below normal capacity, or the number of "capacity units" * over the normal capacity the player is loaded. Max is 5. */ int calc_capacity(xtra_wt) int xtra_wt; { int cap, wt = inv_weight() + xtra_wt; if (wt <= 0) return UNENCUMBERED; if (wc <= 1) return OVERLOADED; cap = (wt*2 / wc) + 1; return min(cap, OVERLOADED); } int near_capacity() { return calc_capacity(0); } int max_capacity() { int wt = inv_weight(); return (wt - (2 * wc)); } boolean check_capacity(str) const char *str; { if(near_capacity() >= EXT_ENCUMBER) { if(str) pline(str); else You_cant("do that while carrying so much stuff."); return 1; } return 0; } #endif /* OVL1 */ #ifdef OVLB int inv_cnt() { register struct obj *otmp = invent; register int ct = 0; while(otmp){ ct++; otmp = otmp->nobj; } return(ct); } #ifdef GOLDOBJ /* Counts the money in an object chain. */ /* Intended use is for your or some monsters inventory, */ /* now that u.gold/m.gold is gone.*/ /* Counting money in a container might be possible too. */ long money_cnt(otmp) struct obj *otmp; { while(otmp) { /* Must change when silver & copper is implemented: */ if (otmp->oclass == COIN_CLASS) return otmp->quan; otmp = otmp->nobj; } return 0; } #endif #endif /* OVLB */ /*hack.c*/ nethack-3.4.3/src/hacklib.c0100644000000000000000000003377107764735041014215 0ustar rootroot/* SCCS Id: @(#)hacklib.c 3.4 2002/12/13 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) Robert Patrick Rankin, 1991 */ /* NetHack may be freely redistributed. See license for details. */ /* We could include only config.h, except for the overlay definitions... */ #include "hack.h" /*= Assorted 'small' utility routines. They're virtually independent of NetHack, except that rounddiv may call panic(). return type routine name argument type(s) boolean digit (char) boolean letter (char) char highc (char) char lowc (char) char * lcase (char *) char * upstart (char *) char * mungspaces (char *) char * eos (char *) char * strkitten (char *,char) char * s_suffix (const char *) char * xcrypt (const char *, char *) boolean onlyspace (const char *) char * tabexpand (char *) char * visctrl (char) const char * ordin (int) char * sitoa (int) int sgn (int) int rounddiv (long, int) int distmin (int, int, int, int) int dist2 (int, int, int, int) boolean online2 (int, int) boolean pmatch (const char *, const char *) int strncmpi (const char *, const char *, int) char * strstri (const char *, const char *) boolean fuzzymatch (const char *,const char *,const char *,boolean) void setrandom (void) int getyear (void) char * yymmdd (time_t) long yyyymmdd (time_t) int phase_of_the_moon (void) boolean friday_13th (void) int night (void) int midnight (void) =*/ #ifdef LINT # define Static /* pacify lint */ #else # define Static static #endif #ifdef OVLB boolean digit(c) /* is 'c' a digit? */ char c; { return((boolean)('0' <= c && c <= '9')); } boolean letter(c) /* is 'c' a letter? note: '@' classed as letter */ char c; { return((boolean)(('@' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))); } #endif /* OVLB */ #ifdef OVL1 char highc(c) /* force 'c' into uppercase */ char c; { return((char)(('a' <= c && c <= 'z') ? (c & ~040) : c)); } char lowc(c) /* force 'c' into lowercase */ char c; { return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c)); } #endif /* OVL1 */ #ifdef OVLB char * lcase(s) /* convert a string into all lowercase */ char *s; { register char *p; for (p = s; *p; p++) if ('A' <= *p && *p <= 'Z') *p |= 040; return s; } char * upstart(s) /* convert first character of a string to uppercase */ char *s; { if (s) *s = highc(*s); return s; } /* remove excess whitespace from a string buffer (in place) */ char * mungspaces(bp) char *bp; { register char c, *p, *p2; boolean was_space = TRUE; for (p = p2 = bp; (c = *p) != '\0'; p++) { if (c == '\t') c = ' '; if (c != ' ' || !was_space) *p2++ = c; was_space = (c == ' '); } if (was_space && p2 > bp) p2--; *p2 = '\0'; return bp; } #endif /* OVLB */ #ifdef OVL0 char * eos(s) /* return the end of a string (pointing at '\0') */ register char *s; { while (*s) s++; /* s += strlen(s); */ return s; } /* strcat(s, {c,'\0'}); */ char * strkitten(s, c) /* append a character to a string (in place) */ char *s; char c; { char *p = eos(s); *p++ = c; *p = '\0'; return s; } char * s_suffix(s) /* return a name converted to possessive */ const char *s; { Static char buf[BUFSZ]; Strcpy(buf, s); if(!strcmpi(buf, "it")) Strcat(buf, "s"); else if(*(eos(buf)-1) == 's') Strcat(buf, "'"); else Strcat(buf, "'s"); return buf; } char * xcrypt(str, buf) /* trivial text encryption routine (see makedefs) */ const char *str; char *buf; { register const char *p; register char *q; register int bitmask; for (bitmask = 1, p = str, q = buf; *p; q++) { *q = *p++; if (*q & (32|64)) *q ^= bitmask; if ((bitmask <<= 1) >= 32) bitmask = 1; } *q = '\0'; return buf; } #endif /* OVL0 */ #ifdef OVL2 boolean onlyspace(s) /* is a string entirely whitespace? */ const char *s; { for (; *s; s++) if (*s != ' ' && *s != '\t') return FALSE; return TRUE; } #endif /* OVL2 */ #ifdef OVLB char * tabexpand(sbuf) /* expand tabs into proper number of spaces */ char *sbuf; { char buf[BUFSZ]; register char *bp, *s = sbuf; register int idx; if (!*s) return sbuf; /* warning: no bounds checking performed */ for (bp = buf, idx = 0; *s; s++) if (*s == '\t') { do *bp++ = ' '; while (++idx % 8); } else { *bp++ = *s; idx++; } *bp = 0; return strcpy(sbuf, buf); } char * visctrl(c) /* make a displayable string from a character */ char c; { Static char ccc[3]; c &= 0177; ccc[2] = '\0'; if (c < 040) { ccc[0] = '^'; ccc[1] = c | 0100; /* letter */ } else if (c == 0177) { ccc[0] = '^'; ccc[1] = c & ~0100; /* '?' */ } else { ccc[0] = c; /* printable character */ ccc[1] = '\0'; } return ccc; } #endif /* OVLB */ #ifdef OVL2 const char * ordin(n) /* return the ordinal suffix of a number */ int n; /* note: should be non-negative */ { register int dd = n % 10; return (dd == 0 || dd > 3 || (n % 100) / 10 == 1) ? "th" : (dd == 1) ? "st" : (dd == 2) ? "nd" : "rd"; } #endif /* OVL2 */ #ifdef OVL1 char * sitoa(n) /* make a signed digit string from a number */ int n; { Static char buf[13]; Sprintf(buf, (n < 0) ? "%d" : "+%d", n); return buf; } int sgn(n) /* return the sign of a number: -1, 0, or 1 */ int n; { return (n < 0) ? -1 : (n != 0); } #endif /* OVL1 */ #ifdef OVLB int rounddiv(x, y) /* calculate x/y, rounding as appropriate */ long x; int y; { int r, m; int divsgn = 1; if (y == 0) panic("division by zero in rounddiv"); else if (y < 0) { divsgn = -divsgn; y = -y; } if (x < 0) { divsgn = -divsgn; x = -x; } r = x / y; m = x % y; if (2*m >= y) r++; return divsgn * r; } #endif /* OVLB */ #ifdef OVL0 int distmin(x0, y0, x1, y1) /* distance between two points, in moves */ int x0, y0, x1, y1; { register int dx = x0 - x1, dy = y0 - y1; if (dx < 0) dx = -dx; if (dy < 0) dy = -dy; /* The minimum number of moves to get from (x0,y0) to (x1,y1) is the : larger of the [absolute value of the] two deltas. */ return (dx < dy) ? dy : dx; } int dist2(x0, y0, x1, y1) /* square of euclidean distance between pair of pts */ int x0, y0, x1, y1; { register int dx = x0 - x1, dy = y0 - y1; return dx * dx + dy * dy; } boolean online2(x0, y0, x1, y1) /* are two points lined up (on a straight line)? */ int x0, y0, x1, y1; { int dx = x0 - x1, dy = y0 - y1; /* If either delta is zero then they're on an orthogonal line, * else if the deltas are equal (signs ignored) they're on a diagonal. */ return((boolean)(!dy || !dx || (dy == dx) || (dy + dx == 0))); /* (dy == -dx) */ } #endif /* OVL0 */ #ifdef OVLB boolean pmatch(patrn, strng) /* match a string against a pattern */ const char *patrn, *strng; { char s, p; /* : Simple pattern matcher: '*' matches 0 or more characters, '?' matches : any single character. Returns TRUE if 'strng' matches 'patrn'. */ pmatch_top: s = *strng++; p = *patrn++; /* get next chars and pre-advance */ if (!p) /* end of pattern */ return((boolean)(s == '\0')); /* matches iff end of string too */ else if (p == '*') /* wildcard reached */ return((boolean)((!*patrn || pmatch(patrn, strng-1)) ? TRUE : s ? pmatch(patrn-1, strng) : FALSE)); else if (p != s && (p != '?' || !s)) /* check single character */ return FALSE; /* doesn't match */ else /* return pmatch(patrn, strng); */ goto pmatch_top; /* optimize tail recursion */ } #endif /* OVLB */ #ifdef OVL2 #ifndef STRNCMPI int strncmpi(s1, s2, n) /* case insensitive counted string comparison */ register const char *s1, *s2; register int n; /*(should probably be size_t, which is usually unsigned)*/ { /*{ aka strncasecmp }*/ register char t1, t2; while (n--) { if (!*s2) return (*s1 != 0); /* s1 >= s2 */ else if (!*s1) return -1; /* s1 < s2 */ t1 = lowc(*s1++); t2 = lowc(*s2++); if (t1 != t2) return (t1 > t2) ? 1 : -1; } return 0; /* s1 == s2 */ } #endif /* STRNCMPI */ #endif /* OVL2 */ #ifdef OVLB #ifndef STRSTRI char * strstri(str, sub) /* case insensitive substring search */ const char *str; const char *sub; { register const char *s1, *s2; register int i, k; # define TABSIZ 0x20 /* 0x40 would be case-sensitive */ char tstr[TABSIZ], tsub[TABSIZ]; /* nibble count tables */ # if 0 assert( (TABSIZ & ~(TABSIZ-1)) == TABSIZ ); /* must be exact power of 2 */ assert( &lowc != 0 ); /* can't be unsafe macro */ # endif /* special case: empty substring */ if (!*sub) return (char *) str; /* do some useful work while determining relative lengths */ for (i = 0; i < TABSIZ; i++) tstr[i] = tsub[i] = 0; /* init */ for (k = 0, s1 = str; *s1; k++) tstr[*s1++ & (TABSIZ-1)]++; for ( s2 = sub; *s2; --k) tsub[*s2++ & (TABSIZ-1)]++; /* evaluate the info we've collected */ if (k < 0) return (char *) 0; /* sub longer than str, so can't match */ for (i = 0; i < TABSIZ; i++) /* does sub have more 'x's than str? */ if (tsub[i] > tstr[i]) return (char *) 0; /* match not possible */ /* now actually compare the substring repeatedly to parts of the string */ for (i = 0; i <= k; i++) { s1 = &str[i]; s2 = sub; while (lowc(*s1++) == lowc(*s2++)) if (!*s2) return (char *) &str[i]; /* full match */ } return (char *) 0; /* not found */ } #endif /* STRSTRI */ /* compare two strings for equality, ignoring the presence of specified characters (typically whitespace) and possibly ignoring case */ boolean fuzzymatch(s1, s2, ignore_chars, caseblind) const char *s1, *s2; const char *ignore_chars; boolean caseblind; { register char c1, c2; do { while ((c1 = *s1++) != '\0' && index(ignore_chars, c1) != 0) continue; while ((c2 = *s2++) != '\0' && index(ignore_chars, c2) != 0) continue; if (!c1 || !c2) break; /* stop when end of either string is reached */ if (caseblind) { c1 = lowc(c1); c2 = lowc(c2); } } while (c1 == c2); /* match occurs only when the end of both strings has been reached */ return (boolean)(!c1 && !c2); } #endif /* OVLB */ #ifdef OVL2 /* * Time routines * * The time is used for: * - seed for rand() * - year on tombstone and yyyymmdd in record file * - phase of the moon (various monsters react to NEW_MOON or FULL_MOON) * - night and midnight (the undead are dangerous at midnight) * - determination of what files are "very old" */ #if defined(AMIGA) && !defined(AZTEC_C) && !defined(__SASC_60) && !defined(_DCC) && !defined(__GNUC__) extern struct tm *FDECL(localtime,(time_t *)); #endif static struct tm *NDECL(getlt); void setrandom() { /* the types are different enough here that sweeping the different * routine names into one via #defines is even more confusing */ #ifdef RANDOM /* srandom() from sys/share/random.c */ srandom((unsigned int) time((time_t *)0)); #else # if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) /* system srandom() */ # if defined(BSD) && !defined(POSIX_TYPES) # if defined(SUNOS4) (void) # endif srandom((int) time((long *)0)); # else srandom((int) time((time_t *)0)); # endif # else # ifdef UNIX /* system srand48() */ srand48((long) time((time_t *)0)); # else /* poor quality system routine */ srand((int) time((time_t *)0)); # endif # endif #endif } static struct tm * getlt() { time_t date; #if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *)(&date)); #else (void) time(&date); #endif #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES)) return(localtime((long *)(&date))); #else return(localtime(&date)); #endif } int getyear() { return(1900 + getlt()->tm_year); } #if 0 /* This routine is no longer used since in 2000 it will yield "100mmdd". */ char * yymmdd(date) time_t date; { Static char datestr[10]; struct tm *lt; if (date == 0) lt = getlt(); else #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || defined(BSD) lt = localtime((long *)(&date)); #else lt = localtime(&date); #endif Sprintf(datestr, "%02d%02d%02d", lt->tm_year, lt->tm_mon + 1, lt->tm_mday); return(datestr); } #endif long yyyymmdd(date) time_t date; { long datenum; struct tm *lt; if (date == 0) lt = getlt(); else #if (defined(ULTRIX) && !(defined(ULTRIX_PROTO) || defined(NHSTDC))) || (defined(BSD) && !defined(POSIX_TYPES)) lt = localtime((long *)(&date)); #else lt = localtime(&date); #endif /* just in case somebody's localtime supplies (year % 100) rather than the expected (year - 1900) */ if (lt->tm_year < 70) datenum = (long)lt->tm_year + 2000L; else datenum = (long)lt->tm_year + 1900L; /* yyyy --> yyyymm */ datenum = datenum * 100L + (long)(lt->tm_mon + 1); /* yyyymm --> yyyymmdd */ datenum = datenum * 100L + (long)lt->tm_mday; return datenum; } /* * moon period = 29.53058 days ~= 30, year = 365.2422 days * days moon phase advances on first day of year compared to preceding year * = 365.2422 - 12*29.53058 ~= 11 * years in Metonic cycle (time until same phases fall on the same days of * the month) = 18.6 ~= 19 * moon phase on first day of year (epact) ~= (11*(year%19) + 29) % 30 * (29 as initial condition) * current phase in days = first day phase + days elapsed in year * 6 moons ~= 177 days * 177 ~= 8 reported phases * 22 * + 11/22 for rounding */ int phase_of_the_moon() /* 0-7, with 0: new, 4: full */ { register struct tm *lt = getlt(); register int epact, diy, goldn; diy = lt->tm_yday; goldn = (lt->tm_year % 19) + 1; epact = (11 * goldn + 18) % 30; if ((epact == 25 && goldn > 11) || epact == 24) epact++; return( (((((diy + epact) * 6) + 11) % 177) / 22) & 7 ); } boolean friday_13th() { register struct tm *lt = getlt(); return((boolean)(lt->tm_wday == 5 /* friday */ && lt->tm_mday == 13)); } int night() { register int hour = getlt()->tm_hour; return(hour < 6 || hour > 21); } int midnight() { return(getlt()->tm_hour == 0); } #endif /* OVL2 */ /*hacklib.c*/ nethack-3.4.3/src/invent.c0100644000000000000000000023172107764735041014116 0ustar rootroot/* SCCS Id: @(#)invent.c 3.4 2003/12/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #define NOINVSYM '#' #define CONTAINED_SYM '>' /* designator for inside a container */ #ifdef OVL1 STATIC_DCL void NDECL(reorder_invent); STATIC_DCL boolean FDECL(mergable,(struct obj *,struct obj *)); STATIC_DCL void FDECL(invdisp_nothing, (const char *,const char *)); STATIC_DCL boolean FDECL(worn_wield_only, (struct obj *)); STATIC_DCL boolean FDECL(only_here, (struct obj *)); #endif /* OVL1 */ STATIC_DCL void FDECL(compactify,(char *)); STATIC_DCL boolean FDECL(taking_off, (const char *)); STATIC_DCL boolean FDECL(putting_on, (const char *)); STATIC_PTR int FDECL(ckunpaid,(struct obj *)); STATIC_PTR int FDECL(ckvalidcat,(struct obj *)); static char FDECL(display_pickinv, (const char *,BOOLEAN_P, long *)); #ifdef OVLB STATIC_DCL boolean FDECL(this_type_only, (struct obj *)); STATIC_DCL void NDECL(dounpaid); STATIC_DCL struct obj *FDECL(find_unpaid,(struct obj *,struct obj **)); STATIC_DCL void FDECL(menu_identify, (int)); STATIC_DCL boolean FDECL(tool_in_use, (struct obj *)); #endif /* OVLB */ STATIC_DCL char FDECL(obj_to_let,(struct obj *)); #ifdef OVLB static int lastinvnr = 51; /* 0 ... 51 (never saved&restored) */ #ifdef WIZARD /* wizards can wish for venom, which will become an invisible inventory * item without this. putting it in inv_order would mean venom would * suddenly become a choice for all the inventory-class commands, which * would probably cause mass confusion. the test for inventory venom * is only WIZARD and not wizard because the wizard can leave venom lying * around on a bones level for normal players to find. */ static char venom_inv[] = { VENOM_CLASS, 0 }; /* (constant) */ #endif void assigninvlet(otmp) register struct obj *otmp; { boolean inuse[52]; register int i; register struct obj *obj; #ifdef GOLDOBJ /* There is only one of these in inventory... */ if (otmp->oclass == COIN_CLASS) { otmp->invlet = GOLD_SYM; return; } #endif for(i = 0; i < 52; i++) inuse[i] = FALSE; for(obj = invent; obj; obj = obj->nobj) if(obj != otmp) { i = obj->invlet; if('a' <= i && i <= 'z') inuse[i - 'a'] = TRUE; else if('A' <= i && i <= 'Z') inuse[i - 'A' + 26] = TRUE; if(i == otmp->invlet) otmp->invlet = 0; } if((i = otmp->invlet) && (('a' <= i && i <= 'z') || ('A' <= i && i <= 'Z'))) return; for(i = lastinvnr+1; i != lastinvnr; i++) { if(i == 52) { i = -1; continue; } if(!inuse[i]) break; } otmp->invlet = (inuse[i] ? NOINVSYM : (i < 26) ? ('a'+i) : ('A'+i-26)); lastinvnr = i; } #endif /* OVLB */ #ifdef OVL1 /* note: assumes ASCII; toggling a bit puts lowercase in front of uppercase */ #define inv_rank(o) ((o)->invlet ^ 040) /* sort the inventory; used by addinv() and doorganize() */ STATIC_OVL void reorder_invent() { struct obj *otmp, *prev, *next; boolean need_more_sorting; do { /* * We expect at most one item to be out of order, so this * isn't nearly as inefficient as it may first appear. */ need_more_sorting = FALSE; for (otmp = invent, prev = 0; otmp; ) { next = otmp->nobj; if (next && inv_rank(next) < inv_rank(otmp)) { need_more_sorting = TRUE; if (prev) prev->nobj = next; else invent = next; otmp->nobj = next->nobj; next->nobj = otmp; prev = next; } else { prev = otmp; otmp = next; } } } while (need_more_sorting); } #undef inv_rank /* scan a list of objects to see whether another object will merge with one of them; used in pickup.c when all 52 inventory slots are in use, to figure out whether another object could still be picked up */ struct obj * merge_choice(objlist, obj) struct obj *objlist, *obj; { struct monst *shkp; int save_nocharge; if (obj->otyp == SCR_SCARE_MONSTER) /* punt on these */ return (struct obj *)0; /* if this is an item on the shop floor, the attributes it will have when carried are different from what they are now; prevent that from eliciting an incorrect result from mergable() */ save_nocharge = obj->no_charge; if (objlist == invent && obj->where == OBJ_FLOOR && (shkp = shop_keeper(inside_shop(obj->ox, obj->oy))) != 0) { if (obj->no_charge) obj->no_charge = 0; /* A billable object won't have its `unpaid' bit set, so would erroneously seem to be a candidate to merge with a similar ordinary object. That's no good, because once it's really picked up, it won't merge after all. It might merge with another unpaid object, but we can't check that here (depends too much upon shk's bill) and if it doesn't merge it would end up in the '#' overflow inventory slot, so reject it now. */ else if (inhishop(shkp)) return (struct obj *)0; } while (objlist) { if (mergable(objlist, obj)) break; objlist = objlist->nobj; } obj->no_charge = save_nocharge; return objlist; } /* merge obj with otmp and delete obj if types agree */ int merged(potmp, pobj) struct obj **potmp, **pobj; { register struct obj *otmp = *potmp, *obj = *pobj; if(mergable(otmp, obj)) { /* Approximate age: we do it this way because if we were to * do it "accurately" (merge only when ages are identical) * we'd wind up never merging any corpses. * otmp->age = otmp->age*(1-proportion) + obj->age*proportion; * * Don't do the age manipulation if lit. We would need * to stop the burn on both items, then merge the age, * then restart the burn. */ if (!obj->lamplit) otmp->age = ((otmp->age*otmp->quan) + (obj->age*obj->quan)) / (otmp->quan + obj->quan); otmp->quan += obj->quan; #ifdef GOLDOBJ /* temporary special case for gold objects!!!! */ #endif if (otmp->oclass == COIN_CLASS) otmp->owt = weight(otmp); else otmp->owt += obj->owt; if(!otmp->onamelth && obj->onamelth) otmp = *potmp = oname(otmp, ONAME(obj)); obj_extract_self(obj); /* really should merge the timeouts */ if (obj->lamplit) obj_merge_light_sources(obj, otmp); if (obj->timed) obj_stop_timers(obj); /* follows lights */ /* fixup for `#adjust' merging wielded darts, daggers, &c */ if (obj->owornmask && carried(otmp)) { long wmask = otmp->owornmask | obj->owornmask; /* Both the items might be worn in competing slots; merger preference (regardless of which is which): primary weapon + alternate weapon -> primary weapon; primary weapon + quiver -> primary weapon; alternate weapon + quiver -> alternate weapon. (Prior to 3.3.0, it was not possible for the two stacks to be worn in different slots and `obj' didn't need to be unworn when merging.) */ if (wmask & W_WEP) wmask = W_WEP; else if (wmask & W_SWAPWEP) wmask = W_SWAPWEP; else if (wmask & W_QUIVER) wmask = W_QUIVER; else { impossible("merging strangely worn items (%lx)", wmask); wmask = otmp->owornmask; } if ((otmp->owornmask & ~wmask) != 0L) setnotworn(otmp); setworn(otmp, wmask); setnotworn(obj); } #if 0 /* (this should not be necessary, since items already in a monster's inventory don't ever get merged into other objects [only vice versa]) */ else if (obj->owornmask && mcarried(otmp)) { if (obj == MON_WEP(otmp->ocarry)) { MON_WEP(otmp->ocarry) = otmp; otmp->owornmask = W_WEP; } } #endif /*0*/ obfree(obj,otmp); /* free(obj), bill->otmp */ return(1); } return 0; } /* Adjust hero intrinsics as if this object was being added to the hero's inventory. Called _before_ the object has been added to the hero's inventory. This is called when adding objects to the hero's inventory normally (via addinv) or when an object in the hero's inventory has been polymorphed in-place. It may be valid to merge this code with with addinv_core2(). */ void addinv_core1(obj) struct obj *obj; { if (obj->oclass == COIN_CLASS) { #ifndef GOLDOBJ u.ugold += obj->quan; #else flags.botl = 1; #endif } else if (obj->otyp == AMULET_OF_YENDOR) { if (u.uhave.amulet) impossible("already have amulet?"); u.uhave.amulet = 1; } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) { if (u.uhave.menorah) impossible("already have candelabrum?"); u.uhave.menorah = 1; } else if (obj->otyp == BELL_OF_OPENING) { if (u.uhave.bell) impossible("already have silver bell?"); u.uhave.bell = 1; } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { if (u.uhave.book) impossible("already have the book?"); u.uhave.book = 1; } else if (obj->oartifact) { if (is_quest_artifact(obj)) { if (u.uhave.questart) impossible("already have quest artifact?"); u.uhave.questart = 1; artitouch(); } set_artifact_intrinsic(obj, 1, W_ART); } } /* Adjust hero intrinsics as if this object was being added to the hero's inventory. Called _after_ the object has been added to the hero's inventory. This is called when adding objects to the hero's inventory normally (via addinv) or when an object in the hero's inventory has been polymorphed in-place. */ void addinv_core2(obj) struct obj *obj; { if (confers_luck(obj)) { /* new luckstone must be in inventory by this point * for correct calculation */ set_moreluck(); } } /* Add obj to the hero's inventory. Make sure the object is "free". Adjust hero attributes as necessary. */ struct obj * addinv(obj) struct obj *obj; { struct obj *otmp, *prev; if (obj->where != OBJ_FREE) panic("addinv: obj not free"); obj->no_charge = 0; /* not meaningful for invent */ addinv_core1(obj); #ifndef GOLDOBJ /* if handed gold, we're done */ if (obj->oclass == COIN_CLASS) return obj; #endif /* merge if possible; find end of chain in the process */ for (prev = 0, otmp = invent; otmp; prev = otmp, otmp = otmp->nobj) if (merged(&otmp, &obj)) { obj = otmp; goto added; } /* didn't merge, so insert into chain */ if (flags.invlet_constant || !prev) { if (flags.invlet_constant) assigninvlet(obj); obj->nobj = invent; /* insert at beginning */ invent = obj; if (flags.invlet_constant) reorder_invent(); } else { prev->nobj = obj; /* insert at end */ obj->nobj = 0; } obj->where = OBJ_INVENT; added: addinv_core2(obj); carry_obj_effects(obj); /* carrying affects the obj */ update_inventory(); return(obj); } /* * Some objects are affected by being carried. * Make those adjustments here. Called _after_ the object * has been added to the hero's or monster's inventory, * and after hero's intrinsics have been updated. */ void carry_obj_effects(obj) struct obj *obj; { /* Cursed figurines can spontaneously transform when carried. */ if (obj->otyp == FIGURINE) { if (obj->cursed && obj->corpsenm != NON_PM && !dead_species(obj->corpsenm,TRUE)) { attach_fig_transform_timeout(obj); } } } #endif /* OVL1 */ #ifdef OVLB /* Add an item to the inventory unless we're fumbling or it refuses to be * held (via touch_artifact), and give a message. * If there aren't any free inventory slots, we'll drop it instead. * If both success and failure messages are NULL, then we're just doing the * fumbling/slot-limit checking for a silent grab. In any case, * touch_artifact will print its own messages if they are warranted. */ struct obj * hold_another_object(obj, drop_fmt, drop_arg, hold_msg) struct obj *obj; const char *drop_fmt, *drop_arg, *hold_msg; { char buf[BUFSZ]; if (!Blind) obj->dknown = 1; /* maximize mergibility */ if (obj->oartifact) { /* place_object may change these */ boolean crysknife = (obj->otyp == CRYSKNIFE); int oerode = obj->oerodeproof; boolean wasUpolyd = Upolyd; /* in case touching this object turns out to be fatal */ place_object(obj, u.ux, u.uy); if (!touch_artifact(obj, &youmonst)) { obj_extract_self(obj); /* remove it from the floor */ dropy(obj); /* now put it back again :-) */ return obj; } else if (wasUpolyd && !Upolyd) { /* loose your grip if you revert your form */ if (drop_fmt) pline(drop_fmt, drop_arg); obj_extract_self(obj); dropy(obj); return obj; } obj_extract_self(obj); if (crysknife) { obj->otyp = CRYSKNIFE; obj->oerodeproof = oerode; } } if (Fumbling) { if (drop_fmt) pline(drop_fmt, drop_arg); dropy(obj); } else { long oquan = obj->quan; int prev_encumbr = near_capacity(); /* before addinv() */ /* encumbrance only matters if it would now become worse than max( current_value, stressed ) */ if (prev_encumbr < MOD_ENCUMBER) prev_encumbr = MOD_ENCUMBER; /* addinv() may redraw the entire inventory, overwriting drop_arg when it comes from something like doname() */ if (drop_arg) drop_arg = strcpy(buf, drop_arg); obj = addinv(obj); if (inv_cnt() > 52 || ((obj->otyp != LOADSTONE || !obj->cursed) && near_capacity() > prev_encumbr)) { if (drop_fmt) pline(drop_fmt, drop_arg); /* undo any merge which took place */ if (obj->quan > oquan) obj = splitobj(obj, oquan); dropx(obj); } else { if (flags.autoquiver && !uquiver && !obj->owornmask && (is_missile(obj) || ammo_and_launcher(obj, uwep) || ammo_and_launcher(obj, uswapwep))) setuqwep(obj); if (hold_msg || drop_fmt) prinv(hold_msg, obj, oquan); } } return obj; } /* useup() all of an item regardless of its quantity */ void useupall(obj) struct obj *obj; { setnotworn(obj); freeinv(obj); obfree(obj, (struct obj *)0); /* deletes contents also */ } void useup(obj) register struct obj *obj; { /* Note: This works correctly for containers because they */ /* (containers) don't merge. */ if (obj->quan > 1L) { obj->in_use = FALSE; /* no longer in use */ obj->quan--; obj->owt = weight(obj); update_inventory(); } else { useupall(obj); } } /* use one charge from an item and possibly incur shop debt for it */ void consume_obj_charge(obj, maybe_unpaid) struct obj *obj; boolean maybe_unpaid; /* false if caller handles shop billing */ { if (maybe_unpaid) check_unpaid(obj); obj->spe -= 1; if (obj->known) update_inventory(); } #endif /* OVLB */ #ifdef OVL3 /* Adjust hero's attributes as if this object was being removed from the hero's inventory. This should only be called from freeinv() and where we are polymorphing an object already in the hero's inventory. Should think of a better name... */ void freeinv_core(obj) struct obj *obj; { if (obj->oclass == COIN_CLASS) { #ifndef GOLDOBJ u.ugold -= obj->quan; obj->in_use = FALSE; #endif flags.botl = 1; return; } else if (obj->otyp == AMULET_OF_YENDOR) { if (!u.uhave.amulet) impossible("don't have amulet?"); u.uhave.amulet = 0; } else if (obj->otyp == CANDELABRUM_OF_INVOCATION) { if (!u.uhave.menorah) impossible("don't have candelabrum?"); u.uhave.menorah = 0; } else if (obj->otyp == BELL_OF_OPENING) { if (!u.uhave.bell) impossible("don't have silver bell?"); u.uhave.bell = 0; } else if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { if (!u.uhave.book) impossible("don't have the book?"); u.uhave.book = 0; } else if (obj->oartifact) { if (is_quest_artifact(obj)) { if (!u.uhave.questart) impossible("don't have quest artifact?"); u.uhave.questart = 0; } set_artifact_intrinsic(obj, 0, W_ART); } if (obj->otyp == LOADSTONE) { curse(obj); } else if (confers_luck(obj)) { set_moreluck(); flags.botl = 1; } else if (obj->otyp == FIGURINE && obj->timed) { (void) stop_timer(FIG_TRANSFORM, (genericptr_t) obj); } } /* remove an object from the hero's inventory */ void freeinv(obj) register struct obj *obj; { extract_nobj(obj, &invent); freeinv_core(obj); update_inventory(); } void delallobj(x, y) int x, y; { struct obj *otmp, *otmp2; for (otmp = level.objects[x][y]; otmp; otmp = otmp2) { if (otmp == uball) unpunish(); /* after unpunish(), or might get deallocated chain */ otmp2 = otmp->nexthere; if (otmp == uchain) continue; delobj(otmp); } } #endif /* OVL3 */ #ifdef OVL2 /* destroy object in fobj chain (if unpaid, it remains on the bill) */ void delobj(obj) register struct obj *obj; { boolean update_map; if (obj->otyp == AMULET_OF_YENDOR || obj->otyp == CANDELABRUM_OF_INVOCATION || obj->otyp == BELL_OF_OPENING || obj->otyp == SPE_BOOK_OF_THE_DEAD) { /* player might be doing something stupid, but we * can't guarantee that. assume special artifacts * are indestructible via drawbridges, and exploding * chests, and golem creation, and ... */ return; } update_map = (obj->where == OBJ_FLOOR); obj_extract_self(obj); if (update_map) newsym(obj->ox, obj->oy); obfree(obj, (struct obj *) 0); /* frees contents also */ } #endif /* OVL2 */ #ifdef OVL0 struct obj * sobj_at(n,x,y) register int n, x, y; { register struct obj *otmp; for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if(otmp->otyp == n) return(otmp); return((struct obj *)0); } #endif /* OVL0 */ #ifdef OVLB struct obj * carrying(type) register int type; { register struct obj *otmp; for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp->otyp == type) return(otmp); return((struct obj *) 0); } const char * currency(amount) long amount; { if (amount == 1L) return "zorkmid"; else return "zorkmids"; } boolean have_lizard() { register struct obj *otmp; for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp->otyp == CORPSE && otmp->corpsenm == PM_LIZARD) return(TRUE); return(FALSE); } struct obj * o_on(id, objchn) unsigned int id; register struct obj *objchn; { struct obj *temp; while(objchn) { if(objchn->o_id == id) return(objchn); if (Has_contents(objchn) && (temp = o_on(id,objchn->cobj))) return temp; objchn = objchn->nobj; } return((struct obj *) 0); } boolean obj_here(obj, x, y) register struct obj *obj; int x, y; { register struct obj *otmp; for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if(obj == otmp) return(TRUE); return(FALSE); } #endif /* OVLB */ #ifdef OVL2 struct obj * g_at(x,y) register int x, y; { register struct obj *obj = level.objects[x][y]; while(obj) { if (obj->oclass == COIN_CLASS) return obj; obj = obj->nexthere; } return((struct obj *)0); } #endif /* OVL2 */ #ifdef OVLB #ifndef GOLDOBJ /* Make a gold object from the hero's gold. */ struct obj * mkgoldobj(q) register long q; { register struct obj *otmp; otmp = mksobj(GOLD_PIECE, FALSE, FALSE); u.ugold -= q; otmp->quan = q; otmp->owt = weight(otmp); flags.botl = 1; return(otmp); } #endif #endif /* OVLB */ #ifdef OVL1 STATIC_OVL void compactify(buf) register char *buf; /* compact a string of inventory letters by dashing runs of letters */ { register int i1 = 1, i2 = 1; register char ilet, ilet1, ilet2; ilet2 = buf[0]; ilet1 = buf[1]; buf[++i2] = buf[++i1]; ilet = buf[i1]; while(ilet) { if(ilet == ilet1+1) { if(ilet1 == ilet2+1) buf[i2 - 1] = ilet1 = '-'; else if(ilet2 == '-') { buf[i2 - 1] = ++ilet1; buf[i2] = buf[++i1]; ilet = buf[i1]; continue; } } ilet2 = ilet1; ilet1 = ilet; buf[++i2] = buf[++i1]; ilet = buf[i1]; } } /* match the prompt for either 'T' or 'R' command */ STATIC_OVL boolean taking_off(action) const char *action; { return !strcmp(action, "take off") || !strcmp(action, "remove"); } /* match the prompt for either 'W' or 'P' command */ STATIC_OVL boolean putting_on(action) const char *action; { return !strcmp(action, "wear") || !strcmp(action, "put on"); } /* * getobj returns: * struct obj *xxx: object to do something with. * (struct obj *) 0 error return: no object. * &zeroobj explicitly no object (as in w-). #ifdef GOLDOBJ !!!! test if gold can be used in unusual ways (eaten etc.) !!!! may be able to remove "usegold" #endif */ struct obj * getobj(let,word) register const char *let,*word; { register struct obj *otmp; register char ilet; char buf[BUFSZ], qbuf[QBUFSZ]; char lets[BUFSZ], altlets[BUFSZ], *ap; register int foo = 0; register char *bp = buf; xchar allowcnt = 0; /* 0, 1 or 2 */ #ifndef GOLDOBJ boolean allowgold = FALSE; /* can't use gold because they don't have any */ #endif boolean usegold = FALSE; /* can't use gold because its illegal */ boolean allowall = FALSE; boolean allownone = FALSE; boolean useboulder = FALSE; xchar foox = 0; long cnt; boolean prezero = FALSE; long dummymask; if(*let == ALLOW_COUNT) let++, allowcnt = 1; #ifndef GOLDOBJ if(*let == COIN_CLASS) let++, usegold = TRUE, allowgold = (u.ugold ? TRUE : FALSE); #else if(*let == COIN_CLASS) let++, usegold = TRUE; #endif /* Equivalent of an "ugly check" for gold */ if (usegold && !strcmp(word, "eat") && (!metallivorous(youmonst.data) || youmonst.data == &mons[PM_RUST_MONSTER])) #ifndef GOLDOBJ usegold = allowgold = FALSE; #else usegold = FALSE; #endif if(*let == ALL_CLASSES) let++, allowall = TRUE; if(*let == ALLOW_NONE) let++, allownone = TRUE; /* "ugly check" for reading fortune cookies, part 1 */ /* The normal 'ugly check' keeps the object on the inventory list. * We don't want to do that for shirts/cookies, so the check for * them is handled a bit differently (and also requires that we set * allowall in the caller) */ if(allowall && !strcmp(word, "read")) allowall = FALSE; /* another ugly check: show boulders (not statues) */ if(*let == WEAPON_CLASS && !strcmp(word, "throw") && throws_rocks(youmonst.data)) useboulder = TRUE; if(allownone) *bp++ = '-'; #ifndef GOLDOBJ if(allowgold) *bp++ = def_oc_syms[COIN_CLASS]; #endif if(bp > buf && bp[-1] == '-') *bp++ = ' '; ap = altlets; ilet = 'a'; for (otmp = invent; otmp; otmp = otmp->nobj) { if (!flags.invlet_constant) #ifdef GOLDOBJ if (otmp->invlet != GOLD_SYM) /* don't reassign this */ #endif otmp->invlet = ilet; /* reassign() */ if (!*let || index(let, otmp->oclass) #ifdef GOLDOBJ || (usegold && otmp->invlet == GOLD_SYM) #endif || (useboulder && otmp->otyp == BOULDER) ) { register int otyp = otmp->otyp; bp[foo++] = otmp->invlet; /* ugly check: remove inappropriate things */ if ((taking_off(word) && (!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) || (otmp==uarm && uarmc) #ifdef TOURIST || (otmp==uarmu && (uarm || uarmc)) #endif )) || (putting_on(word) && (otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))) /* already worn */ #if 0 /* 3.4.1 -- include currently wielded weapon among the choices */ || (!strcmp(word, "wield") && (otmp->owornmask & W_WEP)) #endif || (!strcmp(word, "ready") && (otmp == uwep || (otmp == uswapwep && u.twoweap))) ) { foo--; foox++; } /* Second ugly check; unlike the first it won't trigger an * "else" in "you don't have anything else to ___". */ else if ((putting_on(word) && ((otmp->oclass == FOOD_CLASS && otmp->otyp != MEAT_RING) || (otmp->oclass == TOOL_CLASS && otyp != BLINDFOLD && otyp != TOWEL && otyp != LENSES))) || (!strcmp(word, "wield") && (otmp->oclass == TOOL_CLASS && !is_weptool(otmp))) || (!strcmp(word, "eat") && !is_edible(otmp)) || (!strcmp(word, "sacrifice") && (otyp != CORPSE && otyp != AMULET_OF_YENDOR && otyp != FAKE_AMULET_OF_YENDOR)) || (!strcmp(word, "write with") && (otmp->oclass == TOOL_CLASS && otyp != MAGIC_MARKER && otyp != TOWEL)) || (!strcmp(word, "tin") && (otyp != CORPSE || !tinnable(otmp))) || (!strcmp(word, "rub") && ((otmp->oclass == TOOL_CLASS && otyp != OIL_LAMP && otyp != MAGIC_LAMP && otyp != BRASS_LANTERN) || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) || (!strncmp(word, "rub on the stone", 16) && *let == GEM_CLASS && /* using known touchstone */ otmp->dknown && objects[otyp].oc_name_known) || ((!strcmp(word, "use or apply") || !strcmp(word, "untrap with")) && /* Picks, axes, pole-weapons, bullwhips */ ((otmp->oclass == WEAPON_CLASS && !is_pick(otmp) && !is_axe(otmp) && !is_pole(otmp) && otyp != BULLWHIP) || (otmp->oclass == POTION_CLASS && /* only applicable potion is oil, and it will only be offered as a choice when already discovered */ (otyp != POT_OIL || !otmp->dknown || !objects[POT_OIL].oc_name_known)) || (otmp->oclass == FOOD_CLASS && otyp != CREAM_PIE && otyp != EUCALYPTUS_LEAF) || (otmp->oclass == GEM_CLASS && !is_graystone(otmp)))) || (!strcmp(word, "invoke") && (!otmp->oartifact && !objects[otyp].oc_unique && (otyp != FAKE_AMULET_OF_YENDOR || otmp->known) && otyp != CRYSTAL_BALL && /* #invoke synonym for apply */ /* note: presenting the possibility of invoking non-artifact mirrors and/or lamps is a simply a cruel deception... */ otyp != MIRROR && otyp != MAGIC_LAMP && (otyp != OIL_LAMP || /* don't list known oil lamp */ (otmp->dknown && objects[OIL_LAMP].oc_name_known)))) || (!strcmp(word, "untrap with") && (otmp->oclass == TOOL_CLASS && otyp != CAN_OF_GREASE)) || (!strcmp(word, "charge") && !is_chargeable(otmp)) ) foo--; /* ugly check for unworn armor that can't be worn */ else if (putting_on(word) && *let == ARMOR_CLASS && !canwearobj(otmp, &dummymask, FALSE)) { foo--; allowall = TRUE; *ap++ = otmp->invlet; } } else { /* "ugly check" for reading fortune cookies, part 2 */ if ((!strcmp(word, "read") && (otmp->otyp == FORTUNE_COOKIE #ifdef TOURIST || otmp->otyp == T_SHIRT #endif ))) allowall = TRUE; } if(ilet == 'z') ilet = 'A'; else ilet++; } bp[foo] = 0; if(foo == 0 && bp > buf && bp[-1] == ' ') *--bp = 0; Strcpy(lets, bp); /* necessary since we destroy buf */ if(foo > 5) /* compactify string */ compactify(bp); *ap = '\0'; #ifndef GOLDOBJ if(!foo && !allowall && !allowgold && !allownone) { #else if(!foo && !allowall && !allownone) { #endif You("don't have anything %sto %s.", foox ? "else " : "", word); return((struct obj *)0); } for(;;) { cnt = 0; if (allowcnt == 2) allowcnt = 1; /* abort previous count */ if(!buf[0]) { Sprintf(qbuf, "What do you want to %s? [*]", word); } else { Sprintf(qbuf, "What do you want to %s? [%s or ?*]", word, buf); } #ifdef REDO if (in_doagain) ilet = readchar(); else #endif ilet = yn_function(qbuf, (char *)0, '\0'); if(ilet == '0') prezero = TRUE; while(digit(ilet) && allowcnt) { #ifdef REDO if (ilet != '?' && ilet != '*') savech(ilet); #endif cnt = 10*cnt + (ilet - '0'); allowcnt = 2; /* signal presence of cnt */ ilet = readchar(); } if(digit(ilet)) { pline("No count allowed with this command."); continue; } if(index(quitchars,ilet)) { if(flags.verbose) pline(Never_mind); return((struct obj *)0); } if(ilet == '-') { return(allownone ? &zeroobj : (struct obj *) 0); } if(ilet == def_oc_syms[COIN_CLASS]) { if (!usegold) { if (!strncmp(word, "rub on ", 7)) { /* the dangers of building sentences... */ You("cannot rub gold%s.", word + 3); } else { You("cannot %s gold.", word); } return(struct obj *)0; #ifndef GOLDOBJ } else if (!allowgold) { You("are not carrying any gold."); return(struct obj *)0; #endif } if(cnt == 0 && prezero) return((struct obj *)0); /* Historic note: early Nethack had a bug which was * first reported for Larn, where trying to drop 2^32-n * gold pieces was allowed, and did interesting things * to your money supply. The LRS is the tax bureau * from Larn. */ if(cnt < 0) { pline_The("LRS would be very interested to know you have that much."); return(struct obj *)0; } #ifndef GOLDOBJ if(!(allowcnt == 2 && cnt < u.ugold)) cnt = u.ugold; return(mkgoldobj(cnt)); #endif } if(ilet == '?' || ilet == '*') { char *allowed_choices = (ilet == '?') ? lets : (char *)0; long ctmp = 0; if (ilet == '?' && !*lets && *altlets) allowed_choices = altlets; ilet = display_pickinv(allowed_choices, TRUE, allowcnt ? &ctmp : (long *)0); if(!ilet) continue; if (allowcnt && ctmp >= 0) { cnt = ctmp; if (!cnt) prezero = TRUE; allowcnt = 2; } if(ilet == '\033') { if(flags.verbose) pline(Never_mind); return((struct obj *)0); } /* they typed a letter (not a space) at the prompt */ } if(allowcnt == 2 && !strcmp(word,"throw")) { /* permit counts for throwing gold, but don't accept * counts for other things since the throw code will * split off a single item anyway */ #ifdef GOLDOBJ if (ilet != def_oc_syms[COIN_CLASS]) #endif allowcnt = 1; if(cnt == 0 && prezero) return((struct obj *)0); if(cnt > 1) { You("can only throw one item at a time."); continue; } } #ifdef GOLDOBJ flags.botl = 1; /* May have changed the amount of money */ #endif #ifdef REDO savech(ilet); #endif for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp->invlet == ilet) break; if(!otmp) { You("don't have that object."); #ifdef REDO if (in_doagain) return((struct obj *) 0); #endif continue; } else if (cnt < 0 || otmp->quan < cnt) { You("don't have that many! You have only %ld.", otmp->quan); #ifdef REDO if (in_doagain) return((struct obj *) 0); #endif continue; } break; } if(!allowall && let && !index(let,otmp->oclass) #ifdef GOLDOBJ && !(usegold && otmp->oclass == COIN_CLASS) #endif ) { silly_thing(word, otmp); return((struct obj *)0); } if(allowcnt == 2) { /* cnt given */ if(cnt == 0) return (struct obj *)0; if(cnt != otmp->quan) { /* don't split a stack of cursed loadstones */ if (otmp->otyp == LOADSTONE && otmp->cursed) /* kludge for canletgo()'s can't-drop-this message */ otmp->corpsenm = (int) cnt; else otmp = splitobj(otmp, cnt); } } return(otmp); } void silly_thing(word, otmp) const char *word; struct obj *otmp; { const char *s1, *s2, *s3, *what; int ocls = otmp->oclass, otyp = otmp->otyp; s1 = s2 = s3 = 0; /* check for attempted use of accessory commands ('P','R') on armor and for corresponding armor commands ('W','T') on accessories */ if (ocls == ARMOR_CLASS) { if (!strcmp(word, "put on")) s1 = "W", s2 = "wear", s3 = ""; else if (!strcmp(word, "remove")) s1 = "T", s2 = "take", s3 = " off"; } else if ((ocls == RING_CLASS || otyp == MEAT_RING) || ocls == AMULET_CLASS || (otyp == BLINDFOLD || otyp == TOWEL || otyp == LENSES)) { if (!strcmp(word, "wear")) s1 = "P", s2 = "put", s3 = " on"; else if (!strcmp(word, "take off")) s1 = "R", s2 = "remove", s3 = ""; } if (s1) { what = "that"; /* quantity for armor and accessory objects is always 1, but some things should be referred to as plural */ if (otyp == LENSES || is_gloves(otmp) || is_boots(otmp)) what = "those"; pline("Use the '%s' command to %s %s%s.", s1, s2, what, s3); } else { pline(silly_thing_to, word); } } #endif /* OVL1 */ #ifdef OVLB STATIC_PTR int ckvalidcat(otmp) register struct obj *otmp; { /* use allow_category() from pickup.c */ return((int)allow_category(otmp)); } STATIC_PTR int ckunpaid(otmp) register struct obj *otmp; { return((int)(otmp->unpaid)); } boolean wearing_armor() { return((boolean)(uarm || uarmc || uarmf || uarmg || uarmh || uarms #ifdef TOURIST || uarmu #endif )); } boolean is_worn(otmp) register struct obj *otmp; { return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | #ifdef STEED W_SADDLE | #endif W_WEP | W_SWAPWEP | W_QUIVER)))); } static NEARDATA const char removeables[] = { ARMOR_CLASS, WEAPON_CLASS, RING_CLASS, AMULET_CLASS, TOOL_CLASS, 0 }; /* interactive version of getobj - used for Drop, Identify and */ /* Takeoff (A). Return the number of times fn was called successfully */ /* If combo is TRUE, we just use this to get a category list */ int ggetobj(word, fn, mx, combo, resultflags) const char *word; int FDECL((*fn),(OBJ_P)), mx; boolean combo; /* combination menu flag */ unsigned *resultflags; { int FDECL((*ckfn),(OBJ_P)) = (int FDECL((*),(OBJ_P))) 0; boolean FDECL((*filter),(OBJ_P)) = (boolean FDECL((*),(OBJ_P))) 0; boolean takeoff, ident, allflag, m_seen; int itemcount; #ifndef GOLDOBJ int oletct, iletct, allowgold, unpaid, oc_of_sym; #else int oletct, iletct, unpaid, oc_of_sym; #endif char sym, *ip, olets[MAXOCLASSES+5], ilets[MAXOCLASSES+5]; char extra_removeables[3+1]; /* uwep,uswapwep,uquiver */ char buf[BUFSZ], qbuf[QBUFSZ]; if (resultflags) *resultflags = 0; #ifndef GOLDOBJ allowgold = (u.ugold && !strcmp(word, "drop")) ? 1 : 0; #endif takeoff = ident = allflag = m_seen = FALSE; #ifndef GOLDOBJ if(!invent && !allowgold){ #else if(!invent){ #endif You("have nothing to %s.", word); return(0); } add_valid_menu_class(0); /* reset */ if (taking_off(word)) { takeoff = TRUE; filter = is_worn; } else if (!strcmp(word, "identify")) { ident = TRUE; filter = not_fully_identified; } iletct = collect_obj_classes(ilets, invent, FALSE, #ifndef GOLDOBJ (allowgold != 0), #endif filter, &itemcount); unpaid = count_unpaid(invent); if (ident && !iletct) { return -1; /* no further identifications */ } else if (!takeoff && (unpaid || invent)) { ilets[iletct++] = ' '; if (unpaid) ilets[iletct++] = 'u'; if (count_buc(invent, BUC_BLESSED)) ilets[iletct++] = 'B'; if (count_buc(invent, BUC_UNCURSED)) ilets[iletct++] = 'U'; if (count_buc(invent, BUC_CURSED)) ilets[iletct++] = 'C'; if (count_buc(invent, BUC_UNKNOWN)) ilets[iletct++] = 'X'; if (invent) ilets[iletct++] = 'a'; } else if (takeoff && invent) { ilets[iletct++] = ' '; } ilets[iletct++] = 'i'; if (!combo) ilets[iletct++] = 'm'; /* allow menu presentation on request */ ilets[iletct] = '\0'; for (;;) { Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]", word, ilets); getlin(qbuf, buf); if (buf[0] == '\033') return(0); if (index(buf, 'i')) { if (display_inventory((char *)0, TRUE) == '\033') return 0; } else break; } extra_removeables[0] = '\0'; if (takeoff) { /* arbitrary types of items can be placed in the weapon slots [any duplicate entries in extra_removeables[] won't matter] */ if (uwep) (void)strkitten(extra_removeables, uwep->oclass); if (uswapwep) (void)strkitten(extra_removeables, uswapwep->oclass); if (uquiver) (void)strkitten(extra_removeables, uquiver->oclass); } ip = buf; olets[oletct = 0] = '\0'; while ((sym = *ip++) != '\0') { if (sym == ' ') continue; oc_of_sym = def_char_to_objclass(sym); if (takeoff && oc_of_sym != MAXOCLASSES) { if (index(extra_removeables, oc_of_sym)) { ; /* skip rest of takeoff checks */ } else if (!index(removeables, oc_of_sym)) { pline("Not applicable."); return 0; } else if (oc_of_sym == ARMOR_CLASS && !wearing_armor()) { You("are not wearing any armor."); return 0; } else if (oc_of_sym == WEAPON_CLASS && !uwep && !uswapwep && !uquiver) { You("are not wielding anything."); return 0; } else if (oc_of_sym == RING_CLASS && !uright && !uleft) { You("are not wearing rings."); return 0; } else if (oc_of_sym == AMULET_CLASS && !uamul) { You("are not wearing an amulet."); return 0; } else if (oc_of_sym == TOOL_CLASS && !ublindf) { You("are not wearing a blindfold."); return 0; } } if (oc_of_sym == COIN_CLASS && !combo) { #ifndef GOLDOBJ if (allowgold == 1) (*fn)(mkgoldobj(u.ugold)); else if (!u.ugold) You("have no gold."); allowgold = 2; #else flags.botl = 1; #endif } else if (sym == 'a') { allflag = TRUE; } else if (sym == 'A') { /* same as the default */ ; } else if (sym == 'u') { add_valid_menu_class('u'); ckfn = ckunpaid; } else if (sym == 'B') { add_valid_menu_class('B'); ckfn = ckvalidcat; } else if (sym == 'U') { add_valid_menu_class('U'); ckfn = ckvalidcat; } else if (sym == 'C') { add_valid_menu_class('C'); ckfn = ckvalidcat; } else if (sym == 'X') { add_valid_menu_class('X'); ckfn = ckvalidcat; } else if (sym == 'm') { m_seen = TRUE; } else if (oc_of_sym == MAXOCLASSES) { You("don't have any %c's.", sym); } else if (oc_of_sym != VENOM_CLASS) { /* suppress venom */ if (!index(olets, oc_of_sym)) { add_valid_menu_class(oc_of_sym); olets[oletct++] = oc_of_sym; olets[oletct] = 0; } } } if (m_seen) return (allflag || (!oletct && ckfn != ckunpaid)) ? -2 : -3; else if (flags.menu_style != MENU_TRADITIONAL && combo && !allflag) return 0; #ifndef GOLDOBJ else if (allowgold == 2 && !oletct) return 1; /* you dropped gold (or at least tried to) */ else { #else else /*!!!! if (allowgold == 2 && !oletct) !!!! return 1; you dropped gold (or at least tried to) !!!! test gold dropping else*/ { #endif int cnt = askchain(&invent, olets, allflag, fn, ckfn, mx, word); /* * askchain() has already finished the job in this case * so set a special flag to convey that back to the caller * so that it won't continue processing. * Fix for bug C331-1 reported by Irina Rempt-Drijfhout. */ if (combo && allflag && resultflags) *resultflags |= ALL_FINISHED; return cnt; } } /* * Walk through the chain starting at objchn and ask for all objects * with olet in olets (if nonNULL) and satisfying ckfn (if nonnull) * whether the action in question (i.e., fn) has to be performed. * If allflag then no questions are asked. Max gives the max nr of * objects to be treated. Return the number of objects treated. */ int askchain(objchn, olets, allflag, fn, ckfn, mx, word) struct obj **objchn; register int allflag, mx; register const char *olets, *word; /* olets is an Obj Class char array */ register int FDECL((*fn),(OBJ_P)), FDECL((*ckfn),(OBJ_P)); { struct obj *otmp, *otmp2, *otmpo; register char sym, ilet; register int cnt = 0, dud = 0, tmp; boolean takeoff, nodot, ident, ininv; char qbuf[QBUFSZ]; takeoff = taking_off(word); ident = !strcmp(word, "identify"); nodot = (!strcmp(word, "nodot") || !strcmp(word, "drop") || ident || takeoff); ininv = (*objchn == invent); /* Changed so the askchain is interrogated in the order specified. * For example, if a person specifies =/ then first all rings will be * asked about followed by all wands -dgk */ nextclass: ilet = 'a'-1; if (*objchn && (*objchn)->oclass == COIN_CLASS) ilet--; /* extra iteration */ for (otmp = *objchn; otmp; otmp = otmp2) { if(ilet == 'z') ilet = 'A'; else ilet++; otmp2 = otmp->nobj; if (olets && *olets && otmp->oclass != *olets) continue; if (takeoff && !is_worn(otmp)) continue; if (ident && !not_fully_identified(otmp)) continue; if (ckfn && !(*ckfn)(otmp)) continue; if (!allflag) { Strcpy(qbuf, !ininv ? doname(otmp) : xprname(otmp, (char *)0, ilet, !nodot, 0L, 0L)); Strcat(qbuf, "?"); sym = (takeoff || ident || otmp->quan < 2L) ? nyaq(qbuf) : nyNaq(qbuf); } else sym = 'y'; otmpo = otmp; if (sym == '#') { /* Number was entered; split the object unless it corresponds to 'none' or 'all'. 2 special cases: cursed loadstones and welded weapons (eg, multiple daggers) will remain as merged unit; done to avoid splitting an object that won't be droppable (even if we're picking up rather than dropping). */ if (!yn_number) sym = 'n'; else { sym = 'y'; if (yn_number < otmp->quan && !welded(otmp) && (!otmp->cursed || otmp->otyp != LOADSTONE)) { otmp = splitobj(otmp, yn_number); } } } switch(sym){ case 'a': allflag = 1; case 'y': tmp = (*fn)(otmp); if(tmp < 0) { if (otmp != otmpo) { /* split occurred, merge again */ (void) merged(&otmpo, &otmp); } goto ret; } cnt += tmp; if(--mx == 0) goto ret; case 'n': if(nodot) dud++; default: break; case 'q': /* special case for seffects() */ if (ident) cnt = -1; goto ret; } } if (olets && *olets && *++olets) goto nextclass; if(!takeoff && (dud || cnt)) pline("That was all."); else if(!dud && !cnt) pline("No applicable objects."); ret: return(cnt); } /* * Object identification routines: */ /* make an object actually be identified; no display updating */ void fully_identify_obj(otmp) struct obj *otmp; { makeknown(otmp->otyp); if (otmp->oartifact) discover_artifact((xchar)otmp->oartifact); otmp->known = otmp->dknown = otmp->bknown = otmp->rknown = 1; if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) learn_egg_type(otmp->corpsenm); } /* ggetobj callback routine; identify an object and give immediate feedback */ int identify(otmp) struct obj *otmp; { fully_identify_obj(otmp); prinv((char *)0, otmp, 0L); return 1; } /* menu of unidentified objects; select and identify up to id_limit of them */ STATIC_OVL void menu_identify(id_limit) int id_limit; { menu_item *pick_list; int n, i, first = 1; char buf[BUFSZ]; /* assumptions: id_limit > 0 and at least one unID'd item is present */ while (id_limit) { Sprintf(buf, "What would you like to identify %s?", first ? "first" : "next"); n = query_objlist(buf, invent, SIGNAL_NOMENU|USE_INVLET|INVORDER_SORT, &pick_list, PICK_ANY, not_fully_identified); if (n > 0) { if (n > id_limit) n = id_limit; for (i = 0; i < n; i++, id_limit--) (void) identify(pick_list[i].item.a_obj); free((genericptr_t) pick_list); mark_synch(); /* Before we loop to pop open another menu */ } else { if (n < 0) pline("That was all."); id_limit = 0; /* Stop now */ } first = 0; } } /* dialog with user to identify a given number of items; 0 means all */ void identify_pack(id_limit) int id_limit; { struct obj *obj, *the_obj; int n, unid_cnt; unid_cnt = 0; the_obj = 0; /* if unid_cnt ends up 1, this will be it */ for (obj = invent; obj; obj = obj->nobj) if (not_fully_identified(obj)) ++unid_cnt, the_obj = obj; if (!unid_cnt) { You("have already identified all of your possessions."); } else if (!id_limit) { /* identify everything */ if (unid_cnt == 1) { (void) identify(the_obj); } else { /* TODO: use fully_identify_obj and cornline/menu/whatever here */ for (obj = invent; obj; obj = obj->nobj) if (not_fully_identified(obj)) (void) identify(obj); } } else { /* identify up to `id_limit' items */ n = 0; if (flags.menu_style == MENU_TRADITIONAL) do { n = ggetobj("identify", identify, id_limit, FALSE, (unsigned *)0); if (n < 0) break; /* quit or no eligible items */ } while ((id_limit -= n) > 0); if (n == 0 || n < -1) menu_identify(id_limit); } update_inventory(); } #endif /* OVLB */ #ifdef OVL2 STATIC_OVL char obj_to_let(obj) /* should of course only be called for things in invent */ register struct obj *obj; { #ifndef GOLDOBJ if (obj->oclass == COIN_CLASS) return GOLD_SYM; #endif if (!flags.invlet_constant) { obj->invlet = NOINVSYM; reassign(); } return obj->invlet; } /* * Print the indicated quantity of the given object. If quan == 0L then use * the current quantity. */ void prinv(prefix, obj, quan) const char *prefix; register struct obj *obj; long quan; { if (!prefix) prefix = ""; pline("%s%s%s", prefix, *prefix ? " " : "", xprname(obj, (char *)0, obj_to_let(obj), TRUE, 0L, quan)); } #endif /* OVL2 */ #ifdef OVL1 char * xprname(obj, txt, let, dot, cost, quan) struct obj *obj; const char *txt; /* text to print instead of obj */ char let; /* inventory letter */ boolean dot; /* append period; (dot && cost => Iu) */ long cost; /* cost (for inventory of unpaid or expended items) */ long quan; /* if non-0, print this quantity, not obj->quan */ { #ifdef LINT /* handle static char li[BUFSZ]; */ char li[BUFSZ]; #else static char li[BUFSZ]; #endif boolean use_invlet = flags.invlet_constant && let != CONTAINED_SYM; long savequan = 0; if (quan && obj) { savequan = obj->quan; obj->quan = quan; } /* * If let is: * * Then obj == null and we are printing a total amount. * > Then the object is contained and doesn't have an inventory letter. */ if (cost != 0 || let == '*') { /* if dot is true, we're doing Iu, otherwise Ix */ Sprintf(li, "%c - %-45s %6ld %s", (dot && use_invlet ? obj->invlet : let), (txt ? txt : doname(obj)), cost, currency(cost)); #ifndef GOLDOBJ } else if (obj && obj->oclass == COIN_CLASS) { Sprintf(li, "%ld gold piece%s%s", obj->quan, plur(obj->quan), (dot ? "." : "")); #endif } else { /* ordinary inventory display or pickup message */ Sprintf(li, "%c - %s%s", (use_invlet ? obj->invlet : let), (txt ? txt : doname(obj)), (dot ? "." : "")); } if (savequan) obj->quan = savequan; return li; } #endif /* OVL1 */ #ifdef OVLB /* the 'i' command */ int ddoinv() { (void) display_inventory((char *)0, FALSE); return 0; } /* * find_unpaid() * * Scan the given list of objects. If last_found is NULL, return the first * unpaid object found. If last_found is not NULL, then skip over unpaid * objects until last_found is reached, then set last_found to NULL so the * next unpaid object is returned. This routine recursively follows * containers. */ STATIC_OVL struct obj * find_unpaid(list, last_found) struct obj *list, **last_found; { struct obj *obj; while (list) { if (list->unpaid) { if (*last_found) { /* still looking for previous unpaid object */ if (list == *last_found) *last_found = (struct obj *) 0; } else return (*last_found = list); } if (Has_contents(list)) { if ((obj = find_unpaid(list->cobj, last_found)) != 0) return obj; } list = list->nobj; } return (struct obj *) 0; } /* * Internal function used by display_inventory and getobj that can display * inventory and return a count as well as a letter. If out_cnt is not null, * any count returned from the menu selection is placed here. */ static char display_pickinv(lets, want_reply, out_cnt) register const char *lets; boolean want_reply; long* out_cnt; { struct obj *otmp; char ilet, ret; char *invlet = flags.inv_order; int n, classcount; winid win; /* windows being used */ static winid local_win = WIN_ERR; /* window for partial menus */ anything any; menu_item *selected; /* overriden by global flag */ if (flags.perm_invent) { win = (lets && *lets) ? local_win : WIN_INVEN; /* create the first time used */ if (win == WIN_ERR) win = local_win = create_nhwindow(NHW_MENU); } else win = WIN_INVEN; /* Exit early if no inventory -- but keep going if we are doing a permanent inventory update. We need to keep going so the permanent inventory window updates itself to remove the last item(s) dropped. One down side: the addition of the exception for permanent inventory window updates _can_ pop the window up when it's not displayed -- even if it's empty -- because we don't know at this level if its up or not. This may not be an issue if empty checks are done before hand and the call to here is short circuited away. */ if (!invent && !(flags.perm_invent && !lets && !want_reply)) { #ifndef GOLDOBJ pline("Not carrying anything%s.", u.ugold ? " except gold" : ""); #else pline("Not carrying anything."); #endif return 0; } /* oxymoron? temporarily assign permanent inventory letters */ if (!flags.invlet_constant) reassign(); if (lets && strlen(lets) == 1) { /* when only one item of interest, use pline instead of menus; we actually use a fake message-line menu in order to allow the user to perform selection at the --More-- prompt for tty */ ret = '\0'; for (otmp = invent; otmp; otmp = otmp->nobj) { if (otmp->invlet == lets[0]) { ret = message_menu(lets[0], want_reply ? PICK_ONE : PICK_NONE, xprname(otmp, (char *)0, lets[0], TRUE, 0L, 0L)); if (out_cnt) *out_cnt = -1L; /* select all */ break; } } return ret; } start_menu(win); nextclass: classcount = 0; any.a_void = 0; /* set all bits to zero */ for(otmp = invent; otmp; otmp = otmp->nobj) { ilet = otmp->invlet; if(!lets || !*lets || index(lets, ilet)) { if (!flags.sortpack || otmp->oclass == *invlet) { if (flags.sortpack && !classcount) { any.a_void = 0; /* zero */ add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, let_to_name(*invlet, FALSE), MENU_UNSELECTED); classcount++; } any.a_char = ilet; add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE, doname(otmp), MENU_UNSELECTED); } } } if (flags.sortpack) { if (*++invlet) goto nextclass; #ifdef WIZARD if (--invlet != venom_inv) { invlet = venom_inv; goto nextclass; } #endif } end_menu(win, (char *) 0); n = select_menu(win, want_reply ? PICK_ONE : PICK_NONE, &selected); if (n > 0) { ret = selected[0].item.a_char; if (out_cnt) *out_cnt = selected[0].count; free((genericptr_t)selected); } else ret = !n ? '\0' : '\033'; /* cancelled */ return ret; } /* * If lets == NULL or "", list all objects in the inventory. Otherwise, * list all objects with object classes that match the order in lets. * * Returns the letter identifier of a selected item, or 0 if nothing * was selected. */ char display_inventory(lets, want_reply) register const char *lets; boolean want_reply; { return display_pickinv(lets, want_reply, (long *)0); } /* * Returns the number of unpaid items within the given list. This includes * contained objects. */ int count_unpaid(list) struct obj *list; { int count = 0; while (list) { if (list->unpaid) count++; if (Has_contents(list)) count += count_unpaid(list->cobj); list = list->nobj; } return count; } /* * Returns the number of items with b/u/c/unknown within the given list. * This does NOT include contained objects. */ int count_buc(list, type) struct obj *list; int type; { int count = 0; while (list) { if (Role_if(PM_PRIEST)) list->bknown = TRUE; switch(type) { case BUC_BLESSED: if (list->oclass != COIN_CLASS && list->bknown && list->blessed) count++; break; case BUC_CURSED: if (list->oclass != COIN_CLASS && list->bknown && list->cursed) count++; break; case BUC_UNCURSED: if (list->oclass != COIN_CLASS && list->bknown && !list->blessed && !list->cursed) count++; break; case BUC_UNKNOWN: if (list->oclass != COIN_CLASS && !list->bknown) count++; break; default: impossible("need count of curse status %d?", type); return 0; } list = list->nobj; } return count; } STATIC_OVL void dounpaid() { winid win; struct obj *otmp, *marker; register char ilet; char *invlet = flags.inv_order; int classcount, count, num_so_far; int save_unpaid = 0; /* lint init */ long cost, totcost; count = count_unpaid(invent); if (count == 1) { marker = (struct obj *) 0; otmp = find_unpaid(invent, &marker); /* see if the unpaid item is in the top level inventory */ for (marker = invent; marker; marker = marker->nobj) if (marker == otmp) break; pline("%s", xprname(otmp, distant_name(otmp, doname), marker ? otmp->invlet : CONTAINED_SYM, TRUE, unpaid_cost(otmp), 0L)); return; } win = create_nhwindow(NHW_MENU); cost = totcost = 0; num_so_far = 0; /* count of # printed so far */ if (!flags.invlet_constant) reassign(); do { classcount = 0; for (otmp = invent; otmp; otmp = otmp->nobj) { ilet = otmp->invlet; if (otmp->unpaid) { if (!flags.sortpack || otmp->oclass == *invlet) { if (flags.sortpack && !classcount) { putstr(win, 0, let_to_name(*invlet, TRUE)); classcount++; } totcost += cost = unpaid_cost(otmp); /* suppress "(unpaid)" suffix */ save_unpaid = otmp->unpaid; otmp->unpaid = 0; putstr(win, 0, xprname(otmp, distant_name(otmp, doname), ilet, TRUE, cost, 0L)); otmp->unpaid = save_unpaid; num_so_far++; } } } } while (flags.sortpack && (*++invlet)); if (count > num_so_far) { /* something unpaid is contained */ if (flags.sortpack) putstr(win, 0, let_to_name(CONTAINED_SYM, TRUE)); /* * Search through the container objects in the inventory for * unpaid items. The top level inventory items have already * been listed. */ for (otmp = invent; otmp; otmp = otmp->nobj) { if (Has_contents(otmp)) { marker = (struct obj *) 0; /* haven't found any */ while (find_unpaid(otmp->cobj, &marker)) { totcost += cost = unpaid_cost(marker); save_unpaid = marker->unpaid; marker->unpaid = 0; /* suppress "(unpaid)" suffix */ putstr(win, 0, xprname(marker, distant_name(marker, doname), CONTAINED_SYM, TRUE, cost, 0L)); marker->unpaid = save_unpaid; } } } } putstr(win, 0, ""); putstr(win, 0, xprname((struct obj *)0, "Total:", '*', FALSE, totcost, 0L)); display_nhwindow(win, FALSE); destroy_nhwindow(win); } /* query objlist callback: return TRUE if obj type matches "this_type" */ static int this_type; STATIC_OVL boolean this_type_only(obj) struct obj *obj; { return (obj->oclass == this_type); } /* the 'I' command */ int dotypeinv() { char c = '\0'; int n, i = 0; char *extra_types, types[BUFSZ]; int class_count, oclass, unpaid_count, itemcount; boolean billx = *u.ushops && doinvbill(0); menu_item *pick_list; boolean traditional = TRUE; const char *prompt = "What type of object do you want an inventory of?"; #ifndef GOLDOBJ if (!invent && !u.ugold && !billx) { #else if (!invent && !billx) { #endif You("aren't carrying anything."); return 0; } unpaid_count = count_unpaid(invent); if (flags.menu_style != MENU_TRADITIONAL) { if (flags.menu_style == MENU_FULL || flags.menu_style == MENU_PARTIAL) { traditional = FALSE; i = UNPAID_TYPES; if (billx) i |= BILLED_TYPES; n = query_category(prompt, invent, i, &pick_list, PICK_ONE); if (!n) return 0; this_type = c = pick_list[0].item.a_int; free((genericptr_t) pick_list); } } if (traditional) { /* collect a list of classes of objects carried, for use as a prompt */ types[0] = 0; class_count = collect_obj_classes(types, invent, FALSE, #ifndef GOLDOBJ (u.ugold != 0), #endif (boolean FDECL((*),(OBJ_P))) 0, &itemcount); if (unpaid_count) { Strcat(types, "u"); class_count++; } if (billx) { Strcat(types, "x"); class_count++; } /* add everything not already included; user won't see these */ extra_types = eos(types); *extra_types++ = '\033'; if (!unpaid_count) *extra_types++ = 'u'; if (!billx) *extra_types++ = 'x'; *extra_types = '\0'; /* for index() */ for (i = 0; i < MAXOCLASSES; i++) if (!index(types, def_oc_syms[i])) { *extra_types++ = def_oc_syms[i]; *extra_types = '\0'; } if(class_count > 1) { c = yn_function(prompt, types, '\0'); #ifdef REDO savech(c); #endif if(c == '\0') { clear_nhwindow(WIN_MESSAGE); return 0; } } else { /* only one thing to itemize */ if (unpaid_count) c = 'u'; else if (billx) c = 'x'; else c = types[0]; } } if (c == 'x') { if (billx) (void) doinvbill(1); else pline("No used-up objects on your shopping bill."); return 0; } if (c == 'u') { if (unpaid_count) dounpaid(); else You("are not carrying any unpaid objects."); return 0; } if (traditional) { oclass = def_char_to_objclass(c); /* change to object class */ if (oclass == COIN_CLASS) { return doprgold(); } else if (index(types, c) > index(types, '\033')) { You("have no such objects."); return 0; } this_type = oclass; } if (query_objlist((char *) 0, invent, (flags.invlet_constant ? USE_INVLET : 0)|INVORDER_SORT, &pick_list, PICK_NONE, this_type_only) > 0) free((genericptr_t)pick_list); return 0; } /* return a string describing the dungeon feature at if there is one worth mentioning at that location; otherwise null */ const char * dfeature_at(x, y, buf) int x, y; char *buf; { struct rm *lev = &levl[x][y]; int ltyp = lev->typ, cmap = -1; const char *dfeature = 0; static char altbuf[BUFSZ]; if (IS_DOOR(ltyp)) { switch (lev->doormask) { case D_NODOOR: cmap = S_ndoor; break; /* "doorway" */ case D_ISOPEN: cmap = S_vodoor; break; /* "open door" */ case D_BROKEN: dfeature = "broken door"; break; default: cmap = S_vcdoor; break; /* "closed door" */ } /* override door description for open drawbridge */ if (is_drawbridge_wall(x, y) >= 0) dfeature = "open drawbridge portcullis", cmap = -1; } else if (IS_FOUNTAIN(ltyp)) cmap = S_fountain; /* "fountain" */ else if (IS_THRONE(ltyp)) cmap = S_throne; /* "opulent throne" */ else if (is_lava(x,y)) cmap = S_lava; /* "molten lava" */ else if (is_ice(x,y)) cmap = S_ice; /* "ice" */ else if (is_pool(x,y)) dfeature = "pool of water"; #ifdef SINKS else if (IS_SINK(ltyp)) cmap = S_sink; /* "sink" */ #endif else if (IS_ALTAR(ltyp)) { Sprintf(altbuf, "altar to %s (%s)", a_gname(), align_str(Amask2align(lev->altarmask & ~AM_SHRINE))); dfeature = altbuf; } else if ((x == xupstair && y == yupstair) || (x == sstairs.sx && y == sstairs.sy && sstairs.up)) cmap = S_upstair; /* "staircase up" */ else if ((x == xdnstair && y == ydnstair) || (x == sstairs.sx && y == sstairs.sy && !sstairs.up)) cmap = S_dnstair; /* "staircase down" */ else if (x == xupladder && y == yupladder) cmap = S_upladder; /* "ladder up" */ else if (x == xdnladder && y == ydnladder) cmap = S_dnladder; /* "ladder down" */ else if (ltyp == DRAWBRIDGE_DOWN) cmap = S_vodbridge; /* "lowered drawbridge" */ else if (ltyp == DBWALL) cmap = S_vcdbridge; /* "raised drawbridge" */ else if (IS_GRAVE(ltyp)) cmap = S_grave; /* "grave" */ else if (ltyp == TREE) cmap = S_tree; /* "tree" */ else if (ltyp == IRONBARS) dfeature = "set of iron bars"; if (cmap >= 0) dfeature = defsyms[cmap].explanation; if (dfeature) Strcpy(buf, dfeature); return dfeature; } /* look at what is here; if there are many objects (5 or more), don't show them unless obj_cnt is 0 */ int look_here(obj_cnt, picked_some) int obj_cnt; /* obj_cnt > 0 implies that autopickup is in progess */ boolean picked_some; { struct obj *otmp; struct trap *trap; const char *verb = Blind ? "feel" : "see"; const char *dfeature = (char *)0; char fbuf[BUFSZ], fbuf2[BUFSZ]; winid tmpwin; boolean skip_objects = (obj_cnt >= 5), felt_cockatrice = FALSE; if (u.uswallow && u.ustuck) { struct monst *mtmp = u.ustuck; Sprintf(fbuf, "Contents of %s %s", s_suffix(mon_nam(mtmp)), mbodypart(mtmp, STOMACH)); /* Skip "Contents of " by using fbuf index 12 */ You("%s to %s what is lying in %s.", Blind ? "try" : "look around", verb, &fbuf[12]); otmp = mtmp->minvent; if (otmp) { for ( ; otmp; otmp = otmp->nobj) { /* If swallower is an animal, it should have become stone but... */ if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); } if (Blind) Strcpy(fbuf, "You feel"); Strcat(fbuf,":"); (void) display_minventory(mtmp, MINV_ALL, fbuf); } else { You("%s no objects here.", verb); } return(!!Blind); } if (!skip_objects && (trap = t_at(u.ux,u.uy)) && trap->tseen) There("is %s here.", an(defsyms[trap_to_defsym(trap->ttyp)].explanation)); otmp = level.objects[u.ux][u.uy]; dfeature = dfeature_at(u.ux, u.uy, fbuf2); if (dfeature && !strcmp(dfeature, "pool of water") && Underwater) dfeature = 0; if (Blind) { boolean drift = Is_airlevel(&u.uz) || Is_waterlevel(&u.uz); if (dfeature && !strncmp(dfeature, "altar ", 6)) { /* don't say "altar" twice, dfeature has more info */ You("try to feel what is here."); } else { You("try to feel what is %s%s.", drift ? "floating here" : "lying here on the ", drift ? "" : surface(u.ux, u.uy)); } if (dfeature && !drift && !strcmp(dfeature, surface(u.ux,u.uy))) dfeature = 0; /* ice already identifed */ if (!can_reach_floor()) { pline("But you can't reach it!"); return(0); } } if (dfeature) Sprintf(fbuf, "There is %s here.", an(dfeature)); if (!otmp || is_lava(u.ux,u.uy) || (is_pool(u.ux,u.uy) && !Underwater)) { if (dfeature) pline(fbuf); read_engr_at(u.ux, u.uy); /* Eric Backus */ if (!skip_objects && (Blind || !dfeature)) You("%s no objects here.", verb); return(!!Blind); } /* we know there is something here */ if (skip_objects) { if (dfeature) pline(fbuf); read_engr_at(u.ux, u.uy); /* Eric Backus */ There("are %s%s objects here.", (obj_cnt <= 10) ? "several" : "many", picked_some ? " more" : ""); } else if (!otmp->nexthere) { /* only one object */ if (dfeature) pline(fbuf); read_engr_at(u.ux, u.uy); /* Eric Backus */ #ifdef INVISIBLE_OBJECTS if (otmp->oinvis && !See_invisible) verb = "feel"; #endif You("%s here %s.", verb, doname(otmp)); if (otmp->otyp == CORPSE) feel_cockatrice(otmp, FALSE); } else { display_nhwindow(WIN_MESSAGE, FALSE); tmpwin = create_nhwindow(NHW_MENU); if(dfeature) { putstr(tmpwin, 0, fbuf); putstr(tmpwin, 0, ""); } putstr(tmpwin, 0, Blind ? "Things that you feel here:" : "Things that are here:"); for ( ; otmp; otmp = otmp->nexthere) { if (otmp->otyp == CORPSE && will_feel_cockatrice(otmp, FALSE)) { char buf[BUFSZ]; felt_cockatrice = TRUE; Strcpy(buf, doname(otmp)); Strcat(buf, "..."); putstr(tmpwin, 0, buf); break; } putstr(tmpwin, 0, doname(otmp)); } display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); if (felt_cockatrice) feel_cockatrice(otmp, FALSE); read_engr_at(u.ux, u.uy); /* Eric Backus */ } return(!!Blind); } /* explicilty look at what is here, including all objects */ int dolook() { return look_here(0, FALSE); } boolean will_feel_cockatrice(otmp, force_touch) struct obj *otmp; boolean force_touch; { if ((Blind || force_touch) && !uarmg && !Stone_resistance && (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]))) return TRUE; return FALSE; } void feel_cockatrice(otmp, force_touch) struct obj *otmp; boolean force_touch; { char kbuf[BUFSZ]; if (will_feel_cockatrice(otmp, force_touch)) { if(poly_when_stoned(youmonst.data)) You("touched the %s corpse with your bare %s.", mons[otmp->corpsenm].mname, makeplural(body_part(HAND))); else pline("Touching the %s corpse is a fatal mistake...", mons[otmp->corpsenm].mname); Sprintf(kbuf, "%s corpse", an(mons[otmp->corpsenm].mname)); instapetrify(kbuf); } } #endif /* OVLB */ #ifdef OVL1 void stackobj(obj) struct obj *obj; { struct obj *otmp; for(otmp = level.objects[obj->ox][obj->oy]; otmp; otmp = otmp->nexthere) if(otmp != obj && merged(&obj,&otmp)) break; return; } STATIC_OVL boolean mergable(otmp, obj) /* returns TRUE if obj & otmp can be merged */ register struct obj *otmp, *obj; { if (obj->otyp != otmp->otyp) return FALSE; #ifdef GOLDOBJ /* coins of the same kind will always merge */ if (obj->oclass == COIN_CLASS) return TRUE; #endif if (obj->unpaid != otmp->unpaid || obj->spe != otmp->spe || obj->dknown != otmp->dknown || (obj->bknown != otmp->bknown && !Role_if(PM_PRIEST)) || obj->cursed != otmp->cursed || obj->blessed != otmp->blessed || obj->no_charge != otmp->no_charge || obj->obroken != otmp->obroken || obj->otrapped != otmp->otrapped || obj->lamplit != otmp->lamplit || #ifdef INVISIBLE_OBJECTS obj->oinvis != otmp->oinvis || #endif obj->greased != otmp->greased || obj->oeroded != otmp->oeroded || obj->oeroded2 != otmp->oeroded2 || obj->bypass != otmp->bypass) return(FALSE); if ((obj->oclass==WEAPON_CLASS || obj->oclass==ARMOR_CLASS) && (obj->oerodeproof!=otmp->oerodeproof || obj->rknown!=otmp->rknown)) return FALSE; if (obj->oclass == FOOD_CLASS && (obj->oeaten != otmp->oeaten || obj->orotten != otmp->orotten)) return(FALSE); if (obj->otyp == CORPSE || obj->otyp == EGG || obj->otyp == TIN) { if (obj->corpsenm != otmp->corpsenm) return FALSE; } /* hatching eggs don't merge; ditto for revivable corpses */ if ((obj->otyp == EGG && (obj->timed || otmp->timed)) || (obj->otyp == CORPSE && otmp->corpsenm >= LOW_PM && is_reviver(&mons[otmp->corpsenm]))) return FALSE; /* allow candle merging only if their ages are close */ /* see begin_burn() for a reference for the magic "25" */ if (Is_candle(obj) && obj->age/25 != otmp->age/25) return(FALSE); /* burning potions of oil never merge */ if (obj->otyp == POT_OIL && obj->lamplit) return FALSE; /* don't merge surcharged item with base-cost item */ if (obj->unpaid && !same_price(obj, otmp)) return FALSE; /* if they have names, make sure they're the same */ if ( (obj->onamelth != otmp->onamelth && ((obj->onamelth && otmp->onamelth) || obj->otyp == CORPSE) ) || (obj->onamelth && otmp->onamelth && strncmp(ONAME(obj), ONAME(otmp), (int)obj->onamelth))) return FALSE; /* for the moment, any additional information is incompatible */ if (obj->oxlth || otmp->oxlth) return FALSE; if(obj->oartifact != otmp->oartifact) return FALSE; if(obj->known == otmp->known || !objects[otmp->otyp].oc_uses_known) { return((boolean)(objects[obj->otyp].oc_merge)); } else return(FALSE); } int doprgold() { /* the messages used to refer to "carrying gold", but that didn't take containers into account */ #ifndef GOLDOBJ if(!u.ugold) Your("wallet is empty."); else Your("wallet contains %ld gold piece%s.", u.ugold, plur(u.ugold)); #else long umoney = money_cnt(invent); if(!umoney) Your("wallet is empty."); else Your("wallet contains %ld %s.", umoney, currency(umoney)); #endif shopper_financial_report(); return 0; } #endif /* OVL1 */ #ifdef OVLB int doprwep() { if (!uwep) { You("are empty %s.", body_part(HANDED)); } else { prinv((char *)0, uwep, 0L); if (u.twoweap) prinv((char *)0, uswapwep, 0L); } return 0; } int doprarm() { if(!wearing_armor()) You("are not wearing any armor."); else { #ifdef TOURIST char lets[8]; #else char lets[7]; #endif register int ct = 0; #ifdef TOURIST if(uarmu) lets[ct++] = obj_to_let(uarmu); #endif if(uarm) lets[ct++] = obj_to_let(uarm); if(uarmc) lets[ct++] = obj_to_let(uarmc); if(uarmh) lets[ct++] = obj_to_let(uarmh); if(uarms) lets[ct++] = obj_to_let(uarms); if(uarmg) lets[ct++] = obj_to_let(uarmg); if(uarmf) lets[ct++] = obj_to_let(uarmf); lets[ct] = 0; (void) display_inventory(lets, FALSE); } return 0; } int doprring() { if(!uleft && !uright) You("are not wearing any rings."); else { char lets[3]; register int ct = 0; if(uleft) lets[ct++] = obj_to_let(uleft); if(uright) lets[ct++] = obj_to_let(uright); lets[ct] = 0; (void) display_inventory(lets, FALSE); } return 0; } int dopramulet() { if (!uamul) You("are not wearing an amulet."); else prinv((char *)0, uamul, 0L); return 0; } STATIC_OVL boolean tool_in_use(obj) struct obj *obj; { if ((obj->owornmask & (W_TOOL #ifdef STEED | W_SADDLE #endif )) != 0L) return TRUE; if (obj->oclass != TOOL_CLASS) return FALSE; return (boolean)(obj == uwep || obj->lamplit || (obj->otyp == LEASH && obj->leashmon)); } int doprtool() { struct obj *otmp; int ct = 0; char lets[52+1]; for (otmp = invent; otmp; otmp = otmp->nobj) if (tool_in_use(otmp)) lets[ct++] = obj_to_let(otmp); lets[ct] = '\0'; if (!ct) You("are not using any tools."); else (void) display_inventory(lets, FALSE); return 0; } /* '*' command; combines the ')' + '[' + '=' + '"' + '(' commands; show inventory of all currently wielded, worn, or used objects */ int doprinuse() { struct obj *otmp; int ct = 0; char lets[52+1]; for (otmp = invent; otmp; otmp = otmp->nobj) if (is_worn(otmp) || tool_in_use(otmp)) lets[ct++] = obj_to_let(otmp); lets[ct] = '\0'; if (!ct) You("are not wearing or wielding anything."); else (void) display_inventory(lets, FALSE); return 0; } /* * uses up an object that's on the floor, charging for it as necessary */ void useupf(obj, numused) register struct obj *obj; long numused; { register struct obj *otmp; boolean at_u = (obj->ox == u.ux && obj->oy == u.uy); /* burn_floor_paper() keeps an object pointer that it tries to * useupf() multiple times, so obj must survive if plural */ if (obj->quan > numused) otmp = splitobj(obj, numused); else otmp = obj; if(costly_spot(otmp->ox, otmp->oy)) { if(index(u.urooms, *in_rooms(otmp->ox, otmp->oy, 0))) addtobill(otmp, FALSE, FALSE, FALSE); else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE); } delobj(otmp); if (at_u && u.uundetected && hides_under(youmonst.data)) u.uundetected = OBJ_AT(u.ux, u.uy); } #endif /* OVLB */ #ifdef OVL1 /* * Conversion from a class to a string for printing. * This must match the object class order. */ STATIC_VAR NEARDATA const char *names[] = { 0, "Illegal objects", "Weapons", "Armor", "Rings", "Amulets", "Tools", "Comestibles", "Potions", "Scrolls", "Spellbooks", "Wands", "Coins", "Gems", "Boulders/Statues", "Iron balls", "Chains", "Venoms" }; static NEARDATA const char oth_symbols[] = { CONTAINED_SYM, '\0' }; static NEARDATA const char *oth_names[] = { "Bagged/Boxed items" }; static NEARDATA char *invbuf = (char *)0; static NEARDATA unsigned invbufsiz = 0; char * let_to_name(let,unpaid) char let; boolean unpaid; { const char *class_name; const char *pos; int oclass = (let >= 1 && let < MAXOCLASSES) ? let : 0; unsigned len; if (oclass) class_name = names[oclass]; else if ((pos = index(oth_symbols, let)) != 0) class_name = oth_names[pos - oth_symbols]; else class_name = names[0]; len = strlen(class_name) + (unpaid ? sizeof "unpaid_" : sizeof ""); if (len > invbufsiz) { if (invbuf) free((genericptr_t)invbuf); invbufsiz = len + 10; /* add slop to reduce incremental realloc */ invbuf = (char *) alloc(invbufsiz); } if (unpaid) Strcat(strcpy(invbuf, "Unpaid "), class_name); else Strcpy(invbuf, class_name); return invbuf; } void free_invbuf() { if (invbuf) free((genericptr_t)invbuf), invbuf = (char *)0; invbufsiz = 0; } #endif /* OVL1 */ #ifdef OVLB void reassign() { register int i; register struct obj *obj; for(obj = invent, i = 0; obj; obj = obj->nobj, i++) obj->invlet = (i < 26) ? ('a'+i) : ('A'+i-26); lastinvnr = i; } #endif /* OVLB */ #ifdef OVL1 int doorganize() /* inventory organizer by Del Lamb */ { struct obj *obj, *otmp; register int ix, cur; register char let; char alphabet[52+1], buf[52+1]; char qbuf[QBUFSZ]; char allowall[2]; const char *adj_type; if (!flags.invlet_constant) reassign(); /* get a pointer to the object the user wants to organize */ allowall[0] = ALL_CLASSES; allowall[1] = '\0'; if (!(obj = getobj(allowall,"adjust"))) return(0); /* initialize the list with all upper and lower case letters */ for (let = 'a', ix = 0; let <= 'z';) alphabet[ix++] = let++; for (let = 'A', ix = 26; let <= 'Z';) alphabet[ix++] = let++; alphabet[52] = 0; /* blank out all the letters currently in use in the inventory */ /* except those that will be merged with the selected object */ for (otmp = invent; otmp; otmp = otmp->nobj) if (otmp != obj && !mergable(otmp,obj)) { if (otmp->invlet <= 'Z') alphabet[(otmp->invlet) - 'A' + 26] = ' '; else alphabet[(otmp->invlet) - 'a'] = ' '; } /* compact the list by removing all the blanks */ for (ix = cur = 0; ix <= 52; ix++) if (alphabet[ix] != ' ') buf[cur++] = alphabet[ix]; /* and by dashing runs of letters */ if(cur > 5) compactify(buf); /* get new letter to use as inventory letter */ for (;;) { Sprintf(qbuf, "Adjust letter to what [%s]?",buf); let = yn_function(qbuf, (char *)0, '\0'); if(index(quitchars,let)) { pline(Never_mind); return(0); } if (let == '@' || !letter(let)) pline("Select an inventory slot letter."); else break; } /* change the inventory and print the resulting item */ adj_type = "Moving:"; /* * don't use freeinv/addinv to avoid double-touching artifacts, * dousing lamps, losing luck, cursing loadstone, etc. */ extract_nobj(obj, &invent); for (otmp = invent; otmp;) if (merged(&otmp,&obj)) { adj_type = "Merging:"; obj = otmp; otmp = otmp->nobj; extract_nobj(obj, &invent); } else { if (otmp->invlet == let) { adj_type = "Swapping:"; otmp->invlet = obj->invlet; } otmp = otmp->nobj; } /* inline addinv (assuming flags.invlet_constant and !merged) */ obj->invlet = let; obj->nobj = invent; /* insert at beginning */ obj->where = OBJ_INVENT; invent = obj; reorder_invent(); prinv(adj_type, obj, 0L); update_inventory(); return(0); } /* common to display_minventory and display_cinventory */ STATIC_OVL void invdisp_nothing(hdr, txt) const char *hdr, *txt; { winid win; anything any; menu_item *selected; any.a_void = 0; win = create_nhwindow(NHW_MENU); start_menu(win); add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, hdr, MENU_UNSELECTED); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, txt, MENU_UNSELECTED); end_menu(win, (char *)0); if (select_menu(win, PICK_NONE, &selected) > 0) free((genericptr_t)selected); destroy_nhwindow(win); return; } /* query_objlist callback: return things that could possibly be worn/wielded */ STATIC_OVL boolean worn_wield_only(obj) struct obj *obj; { return (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS || obj->oclass == AMULET_CLASS || obj->oclass == RING_CLASS || obj->oclass == TOOL_CLASS); } /* * Display a monster's inventory. * Returns a pointer to the object from the monster's inventory selected * or NULL if nothing was selected. * * By default, only worn and wielded items are displayed. The caller * can pick one. Modifier flags are: * * MINV_NOLET - nothing selectable * MINV_ALL - display all inventory */ struct obj * display_minventory(mon, dflags, title) register struct monst *mon; int dflags; char *title; { struct obj *ret; #ifndef GOLDOBJ struct obj m_gold; #endif char tmp[QBUFSZ]; int n; menu_item *selected = 0; #ifndef GOLDOBJ int do_all = (dflags & MINV_ALL) != 0, do_gold = (do_all && mon->mgold); #else int do_all = (dflags & MINV_ALL) != 0; #endif Sprintf(tmp,"%s %s:", s_suffix(noit_Monnam(mon)), do_all ? "possessions" : "armament"); #ifndef GOLDOBJ if (do_all ? (mon->minvent || mon->mgold) #else if (do_all ? (mon->minvent != 0) #endif : (mon->misc_worn_check || MON_WEP(mon))) { /* Fool the 'weapon in hand' routine into * displaying 'weapon in claw', etc. properly. */ youmonst.data = mon->data; #ifndef GOLDOBJ if (do_gold) { /* * Make temporary gold object and insert at the head of * the mon's inventory. We can get away with using a * stack variable object because monsters don't carry * gold in their inventory, so it won't merge. */ m_gold = zeroobj; m_gold.otyp = GOLD_PIECE; m_gold.oclass = COIN_CLASS; m_gold.quan = mon->mgold; m_gold.dknown = 1; m_gold.where = OBJ_FREE; /* we had better not merge and free this object... */ if (add_to_minv(mon, &m_gold)) panic("display_minventory: static object freed."); } #endif n = query_objlist(title ? title : tmp, mon->minvent, INVORDER_SORT, &selected, (dflags & MINV_NOLET) ? PICK_NONE : PICK_ONE, do_all ? allow_all : worn_wield_only); #ifndef GOLDOBJ if (do_gold) obj_extract_self(&m_gold); #endif set_uasmon(); } else { invdisp_nothing(title ? title : tmp, "(none)"); n = 0; } if (n > 0) { ret = selected[0].item.a_obj; free((genericptr_t)selected); #ifndef GOLDOBJ /* * Unfortunately, we can't return a pointer to our temporary * gold object. We'll have to work out a scheme where this * can happen. Maybe even put gold in the inventory list... */ if (ret == &m_gold) ret = (struct obj *) 0; #endif } else ret = (struct obj *) 0; return ret; } /* * Display the contents of a container in inventory style. * Currently, this is only used for statues, via wand of probing. */ struct obj * display_cinventory(obj) register struct obj *obj; { struct obj *ret; char tmp[QBUFSZ]; int n; menu_item *selected = 0; Sprintf(tmp,"Contents of %s:", doname(obj)); if (obj->cobj) { n = query_objlist(tmp, obj->cobj, INVORDER_SORT, &selected, PICK_NONE, allow_all); } else { invdisp_nothing(tmp, "(empty)"); n = 0; } if (n > 0) { ret = selected[0].item.a_obj; free((genericptr_t)selected); } else ret = (struct obj *) 0; return ret; } /* query objlist callback: return TRUE if obj is at given location */ static coord only; STATIC_OVL boolean only_here(obj) struct obj *obj; { return (obj->ox == only.x && obj->oy == only.y); } /* * Display a list of buried items in inventory style. Return a non-zero * value if there were items at that spot. * * Currently, this is only used with a wand of probing zapped downwards. */ int display_binventory(x, y, as_if_seen) int x, y; boolean as_if_seen; { struct obj *obj; menu_item *selected = 0; int n; /* count # of objects here */ for (n = 0, obj = level.buriedobjlist; obj; obj = obj->nobj) if (obj->ox == x && obj->oy == y) { if (as_if_seen) obj->dknown = 1; n++; } if (n) { only.x = x; only.y = y; if (query_objlist("Things that are buried here:", level.buriedobjlist, INVORDER_SORT, &selected, PICK_NONE, only_here) > 0) free((genericptr_t)selected); only.x = only.y = 0; } return n; } #endif /* OVL1 */ /*invent.c*/ nethack-3.4.3/src/light.c0100644000000000000000000004152307764735041013721 0ustar rootroot/* SCCS Id: @(#)light.c 3.4 1997/04/10 */ /* Copyright (c) Dean Luick, 1994 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" /* for checking save modes */ /* * Mobile light sources. * * This implementation minimizes memory at the expense of extra * recalculations. * * Light sources are "things" that have a physical position and range. * They have a type, which gives us information about them. Currently * they are only attached to objects and monsters. Note well: the * polymorphed-player handling assumes that both youmonst.m_id and * youmonst.mx will always remain 0. * * Light sources, like timers, either follow game play (RANGE_GLOBAL) or * stay on a level (RANGE_LEVEL). Light sources are unique by their * (type, id) pair. For light sources attached to objects, this id * is a pointer to the object. * * The major working function is do_light_sources(). It is called * when the vision system is recreating its "could see" array. Here * we add a flag (TEMP_LIT) to the array for all locations that are lit * via a light source. The bad part of this is that we have to * re-calculate the LOS of each light source every time the vision * system runs. Even if the light sources and any topology (vision blocking * positions) have not changed. The good part is that no extra memory * is used, plus we don't have to figure out how far the sources have moved, * or if the topology has changed. * * The structure of the save/restore mechanism is amazingly similar to * the timer save/restore. This is because they both have the same * principals of having pointers into objects that must be recalculated * across saves and restores. */ #ifdef OVL3 /* flags */ #define LSF_SHOW 0x1 /* display the light source */ #define LSF_NEEDS_FIXUP 0x2 /* need oid fixup */ static light_source *light_base = 0; STATIC_DCL void FDECL(write_ls, (int, light_source *)); STATIC_DCL int FDECL(maybe_write_ls, (int, int, BOOLEAN_P)); /* imported from vision.c, for small circles */ extern char circle_data[]; extern char circle_start[]; /* Create a new light source. */ void new_light_source(x, y, range, type, id) xchar x, y; int range, type; genericptr_t id; { light_source *ls; if (range > MAX_RADIUS || range < 1) { impossible("new_light_source: illegal range %d", range); return; } ls = (light_source *) alloc(sizeof(light_source)); ls->next = light_base; ls->x = x; ls->y = y; ls->range = range; ls->type = type; ls->id = id; ls->flags = 0; light_base = ls; vision_full_recalc = 1; /* make the source show up */ } /* * Delete a light source. This assumes only one light source is attached * to an object at a time. */ void del_light_source(type, id) int type; genericptr_t id; { light_source *curr, *prev; genericptr_t tmp_id; /* need to be prepared for dealing a with light source which has only been partially restored during a level change (in particular: chameleon vs prot. from shape changers) */ switch (type) { case LS_OBJECT: tmp_id = (genericptr_t)(((struct obj *)id)->o_id); break; case LS_MONSTER: tmp_id = (genericptr_t)(((struct monst *)id)->m_id); break; default: tmp_id = 0; break; } for (prev = 0, curr = light_base; curr; prev = curr, curr = curr->next) { if (curr->type != type) continue; if (curr->id == ((curr->flags & LSF_NEEDS_FIXUP) ? tmp_id : id)) { if (prev) prev->next = curr->next; else light_base = curr->next; free((genericptr_t)curr); vision_full_recalc = 1; return; } } impossible("del_light_source: not found type=%d, id=0x%lx", type, (long)id); } /* Mark locations that are temporarily lit via mobile light sources. */ void do_light_sources(cs_rows) char **cs_rows; { int x, y, min_x, max_x, max_y, offset; char *limits; short at_hero_range = 0; light_source *ls; char *row; for (ls = light_base; ls; ls = ls->next) { ls->flags &= ~LSF_SHOW; /* * Check for moved light sources. It may be possible to * save some effort if an object has not moved, but not in * the current setup -- we need to recalculate for every * vision recalc. */ if (ls->type == LS_OBJECT) { if (get_obj_location((struct obj *) ls->id, &ls->x, &ls->y, 0)) ls->flags |= LSF_SHOW; } else if (ls->type == LS_MONSTER) { if (get_mon_location((struct monst *) ls->id, &ls->x, &ls->y, 0)) ls->flags |= LSF_SHOW; } /* minor optimization: don't bother with duplicate light sources */ /* at hero */ if (ls->x == u.ux && ls->y == u.uy) { if (at_hero_range >= ls->range) ls->flags &= ~LSF_SHOW; else at_hero_range = ls->range; } if (ls->flags & LSF_SHOW) { /* * Walk the points in the circle and see if they are * visible from the center. If so, mark'em. * * Kevin's tests indicated that doing this brute-force * method is faster for radius <= 3 (or so). */ limits = circle_ptr(ls->range); if ((max_y = (ls->y + ls->range)) >= ROWNO) max_y = ROWNO-1; if ((y = (ls->y - ls->range)) < 0) y = 0; for (; y <= max_y; y++) { row = cs_rows[y]; offset = limits[abs(y - ls->y)]; if ((min_x = (ls->x - offset)) < 0) min_x = 0; if ((max_x = (ls->x + offset)) >= COLNO) max_x = COLNO-1; if (ls->x == u.ux && ls->y == u.uy) { /* * If the light source is located at the hero, then * we can use the COULD_SEE bits already calcualted * by the vision system. More importantly than * this optimization, is that it allows the vision * system to correct problems with clear_path(). * The function clear_path() is a simple LOS * path checker that doesn't go out of its way * make things look "correct". The vision system * does this. */ for (x = min_x; x <= max_x; x++) if (row[x] & COULD_SEE) row[x] |= TEMP_LIT; } else { for (x = min_x; x <= max_x; x++) if ((ls->x == x && ls->y == y) || clear_path((int)ls->x, (int) ls->y, x, y)) row[x] |= TEMP_LIT; } } } } } /* (mon->mx == 0) implies migrating */ #define mon_is_local(mon) ((mon)->mx > 0) struct monst * find_mid(nid, fmflags) unsigned nid; unsigned fmflags; { struct monst *mtmp; if (!nid) return &youmonst; if (fmflags & FM_FMON) for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp) && mtmp->m_id == nid) return mtmp; if (fmflags & FM_MIGRATE) for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == nid) return mtmp; if (fmflags & FM_MYDOGS) for (mtmp = mydogs; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == nid) return mtmp; return (struct monst *) 0; } /* Save all light sources of the given range. */ void save_light_sources(fd, mode, range) int fd, mode, range; { int count, actual, is_global; light_source **prev, *curr; if (perform_bwrite(mode)) { count = maybe_write_ls(fd, range, FALSE); bwrite(fd, (genericptr_t) &count, sizeof count); actual = maybe_write_ls(fd, range, TRUE); if (actual != count) panic("counted %d light sources, wrote %d! [range=%d]", count, actual, range); } if (release_data(mode)) { for (prev = &light_base; (curr = *prev) != 0; ) { if (!curr->id) { impossible("save_light_sources: no id! [range=%d]", range); is_global = 0; } else switch (curr->type) { case LS_OBJECT: is_global = !obj_is_local((struct obj *)curr->id); break; case LS_MONSTER: is_global = !mon_is_local((struct monst *)curr->id); break; default: is_global = 0; impossible("save_light_sources: bad type (%d) [range=%d]", curr->type, range); break; } /* if global and not doing local, or vice versa, remove it */ if (is_global ^ (range == RANGE_LEVEL)) { *prev = curr->next; free((genericptr_t)curr); } else { prev = &(*prev)->next; } } } } /* * Pull in the structures from disk, but don't recalculate the object * pointers. */ void restore_light_sources(fd) int fd; { int count; light_source *ls; /* restore elements */ mread(fd, (genericptr_t) &count, sizeof count); while (count-- > 0) { ls = (light_source *) alloc(sizeof(light_source)); mread(fd, (genericptr_t) ls, sizeof(light_source)); ls->next = light_base; light_base = ls; } } /* Relink all lights that are so marked. */ void relink_light_sources(ghostly) boolean ghostly; { char which; unsigned nid; light_source *ls; for (ls = light_base; ls; ls = ls->next) { if (ls->flags & LSF_NEEDS_FIXUP) { if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { if (ghostly) { if (!lookup_id_mapping((unsigned)ls->id, &nid)) impossible("relink_light_sources: no id mapping"); } else nid = (unsigned) ls->id; if (ls->type == LS_OBJECT) { which = 'o'; ls->id = (genericptr_t) find_oid(nid); } else { which = 'm'; ls->id = (genericptr_t) find_mid(nid, FM_EVERYWHERE); } if (!ls->id) impossible("relink_light_sources: cant find %c_id %d", which, nid); } else impossible("relink_light_sources: bad type (%d)", ls->type); ls->flags &= ~LSF_NEEDS_FIXUP; } } } /* * Part of the light source save routine. Count up the number of light * sources that would be written. If write_it is true, actually write * the light source out. */ STATIC_OVL int maybe_write_ls(fd, range, write_it) int fd, range; boolean write_it; { int count = 0, is_global; light_source *ls; for (ls = light_base; ls; ls = ls->next) { if (!ls->id) { impossible("maybe_write_ls: no id! [range=%d]", range); continue; } switch (ls->type) { case LS_OBJECT: is_global = !obj_is_local((struct obj *)ls->id); break; case LS_MONSTER: is_global = !mon_is_local((struct monst *)ls->id); break; default: is_global = 0; impossible("maybe_write_ls: bad type (%d) [range=%d]", ls->type, range); break; } /* if global and not doing local, or vice versa, count it */ if (is_global ^ (range == RANGE_LEVEL)) { count++; if (write_it) write_ls(fd, ls); } } return count; } /* Write a light source structure to disk. */ STATIC_OVL void write_ls(fd, ls) int fd; light_source *ls; { genericptr_t arg_save; struct obj *otmp; struct monst *mtmp; if (ls->type == LS_OBJECT || ls->type == LS_MONSTER) { if (ls->flags & LSF_NEEDS_FIXUP) bwrite(fd, (genericptr_t)ls, sizeof(light_source)); else { /* replace object pointer with id for write, then put back */ arg_save = ls->id; if (ls->type == LS_OBJECT) { otmp = (struct obj *)ls->id; ls->id = (genericptr_t)otmp->o_id; #ifdef DEBUG if (find_oid((unsigned)ls->id) != otmp) panic("write_ls: can't find obj #%u!", (unsigned)ls->id); #endif } else { /* ls->type == LS_MONSTER */ mtmp = (struct monst *)ls->id; ls->id = (genericptr_t)mtmp->m_id; #ifdef DEBUG if (find_mid((unsigned)ls->id, FM_EVERYWHERE) != mtmp) panic("write_ls: can't find mon #%u!", (unsigned)ls->id); #endif } ls->flags |= LSF_NEEDS_FIXUP; bwrite(fd, (genericptr_t)ls, sizeof(light_source)); ls->id = arg_save; ls->flags &= ~LSF_NEEDS_FIXUP; } } else { impossible("write_ls: bad type (%d)", ls->type); } } /* Change light source's ID from src to dest. */ void obj_move_light_source(src, dest) struct obj *src, *dest; { light_source *ls; for (ls = light_base; ls; ls = ls->next) if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src) ls->id = (genericptr_t) dest; src->lamplit = 0; dest->lamplit = 1; } /* return true if there exist any light sources */ boolean any_light_source() { return light_base != (light_source *) 0; } /* * Snuff an object light source if at (x,y). This currently works * only for burning light sources. */ void snuff_light_source(x, y) int x, y; { light_source *ls; struct obj *obj; for (ls = light_base; ls; ls = ls->next) /* Is this position check valid??? Can I assume that the positions will always be correct because the objects would have been updated with the last vision update? [Is that recent enough???] */ if (ls->type == LS_OBJECT && ls->x == x && ls->y == y) { obj = (struct obj *) ls->id; if (obj_is_burning(obj)) { /* The only way to snuff Sunsword is to unwield it. Darkness * scrolls won't affect it. (If we got here because it was * dropped or thrown inside a monster, this won't matter anyway * because it will go out when dropped.) */ if (artifact_light(obj)) continue; end_burn(obj, obj->otyp != MAGIC_LAMP); /* * The current ls element has just been removed (and * ls->next is now invalid). Return assuming that there * is only one light source attached to each object. */ return; } } } /* Return TRUE if object sheds any light at all. */ boolean obj_sheds_light(obj) struct obj *obj; { /* so far, only burning objects shed light */ return obj_is_burning(obj); } /* Return TRUE if sheds light AND will be snuffed by end_burn(). */ boolean obj_is_burning(obj) struct obj *obj; { return (obj->lamplit && (obj->otyp == MAGIC_LAMP || ignitable(obj) || artifact_light(obj))); } /* copy the light source(s) attachted to src, and attach it/them to dest */ void obj_split_light_source(src, dest) struct obj *src, *dest; { light_source *ls, *new_ls; for (ls = light_base; ls; ls = ls->next) if (ls->type == LS_OBJECT && ls->id == (genericptr_t) src) { /* * Insert the new source at beginning of list. This will * never interfere us walking down the list - we are already * past the insertion point. */ new_ls = (light_source *) alloc(sizeof(light_source)); *new_ls = *ls; if (Is_candle(src)) { /* split candles may emit less light than original group */ ls->range = candle_light_range(src); new_ls->range = candle_light_range(dest); vision_full_recalc = 1; /* in case range changed */ } new_ls->id = (genericptr_t) dest; new_ls->next = light_base; light_base = new_ls; dest->lamplit = 1; /* now an active light source */ } } /* light source `src' has been folded into light source `dest'; used for merging lit candles and adding candle(s) to lit candelabrum */ void obj_merge_light_sources(src, dest) struct obj *src, *dest; { light_source *ls; /* src == dest implies adding to candelabrum */ if (src != dest) end_burn(src, TRUE); /* extinguish candles */ for (ls = light_base; ls; ls = ls->next) if (ls->type == LS_OBJECT && ls->id == (genericptr_t) dest) { ls->range = candle_light_range(dest); vision_full_recalc = 1; /* in case range changed */ break; } } /* Candlelight is proportional to the number of candles; minimum range is 2 rather than 1 for playability. */ int candle_light_range(obj) struct obj *obj; { int radius; if (obj->otyp == CANDELABRUM_OF_INVOCATION) { /* * The special candelabrum emits more light than the * corresponding number of candles would. * 1..3 candles, range 2 (minimum range); * 4..6 candles, range 3 (normal lamp range); * 7 candles, range 4 (bright). */ radius = (obj->spe < 4) ? 2 : (obj->spe < 7) ? 3 : 4; } else if (Is_candle(obj)) { /* * Range is incremented by powers of 7 so that it will take * wizard mode quantities of candles to get more light than * from a lamp, without imposing an arbitrary limit. * 1..6 candles, range 2; * 7..48 candles, range 3; * 49..342 candles, range 4; &c. */ long n = obj->quan; radius = 1; /* always incremented at least once */ do { radius++; n /= 7L; } while (n > 0L); } else { /* we're only called for lit candelabrum or candles */ /* impossible("candlelight for %d?", obj->otyp); */ radius = 3; /* lamp's value */ } return radius; } #ifdef WIZARD extern char *FDECL(fmt_ptr, (const genericptr, char *)); /* from alloc.c */ int wiz_light_sources() { winid win; char buf[BUFSZ], arg_address[20]; light_source *ls; win = create_nhwindow(NHW_MENU); /* corner text window */ if (win == WIN_ERR) return 0; Sprintf(buf, "Mobile light sources: hero @ (%2d,%2d)", u.ux, u.uy); putstr(win, 0, buf); putstr(win, 0, ""); if (light_base) { putstr(win, 0, "location range flags type id"); putstr(win, 0, "-------- ----- ------ ---- -------"); for (ls = light_base; ls; ls = ls->next) { Sprintf(buf, " %2d,%2d %2d 0x%04x %s %s", ls->x, ls->y, ls->range, ls->flags, (ls->type == LS_OBJECT ? "obj" : ls->type == LS_MONSTER ? (mon_is_local((struct monst *)ls->id) ? "mon" : ((struct monst *)ls->id == &youmonst) ? "you" : "") : /* migrating monster */ "???"), fmt_ptr(ls->id, arg_address)); putstr(win, 0, buf); } } else putstr(win, 0, ""); display_nhwindow(win, FALSE); destroy_nhwindow(win); return 0; } #endif /* WIZARD */ #endif /* OVL3 */ /*light.c*/ nethack-3.4.3/src/lock.c0100644000000000000000000005557607764735041013557 0ustar rootroot/* SCCS Id: @(#)lock.c 3.4 2000/02/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_PTR int NDECL(picklock); STATIC_PTR int NDECL(forcelock); /* at most one of `door' and `box' should be non-null at any given time */ STATIC_VAR NEARDATA struct xlock_s { struct rm *door; struct obj *box; int picktyp, chance, usedtime; } xlock; #ifdef OVLB STATIC_DCL const char *NDECL(lock_action); STATIC_DCL boolean FDECL(obstructed,(int,int)); STATIC_DCL void FDECL(chest_shatter_msg, (struct obj *)); boolean picking_lock(x, y) int *x, *y; { if (occupation == picklock) { *x = u.ux + u.dx; *y = u.uy + u.dy; return TRUE; } else { *x = *y = 0; return FALSE; } } boolean picking_at(x, y) int x, y; { return (boolean)(occupation == picklock && xlock.door == &levl[x][y]); } /* produce an occupation string appropriate for the current activity */ STATIC_OVL const char * lock_action() { /* "unlocking"+2 == "locking" */ static const char *actions[] = { /* [0] */ "unlocking the door", /* [1] */ "unlocking the chest", /* [2] */ "unlocking the box", /* [3] */ "picking the lock" }; /* if the target is currently unlocked, we're trying to lock it now */ if (xlock.door && !(xlock.door->doormask & D_LOCKED)) return actions[0]+2; /* "locking the door" */ else if (xlock.box && !xlock.box->olocked) return xlock.box->otyp == CHEST ? actions[1]+2 : actions[2]+2; /* otherwise we're trying to unlock it */ else if (xlock.picktyp == LOCK_PICK) return actions[3]; /* "picking the lock" */ #ifdef TOURIST else if (xlock.picktyp == CREDIT_CARD) return actions[3]; /* same as lock_pick */ #endif else if (xlock.door) return actions[0]; /* "unlocking the door" */ else return xlock.box->otyp == CHEST ? actions[1] : actions[2]; } STATIC_PTR int picklock() /* try to open/close a lock */ { if (xlock.box) { if((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) { return((xlock.usedtime = 0)); /* you or it moved */ } } else { /* door */ if(xlock.door != &(levl[u.ux+u.dx][u.uy+u.dy])) { return((xlock.usedtime = 0)); /* you moved */ } switch (xlock.door->doormask) { case D_NODOOR: pline("This doorway has no door."); return((xlock.usedtime = 0)); case D_ISOPEN: You("cannot lock an open door."); return((xlock.usedtime = 0)); case D_BROKEN: pline("This door is broken."); return((xlock.usedtime = 0)); } } if (xlock.usedtime++ >= 50 || nohands(youmonst.data)) { You("give up your attempt at %s.", lock_action()); exercise(A_DEX, TRUE); /* even if you don't succeed */ return((xlock.usedtime = 0)); } if(rn2(100) >= xlock.chance) return(1); /* still busy */ You("succeed in %s.", lock_action()); if (xlock.door) { if(xlock.door->doormask & D_TRAPPED) { b_trapped("door", FINGER); xlock.door->doormask = D_NODOOR; unblock_point(u.ux+u.dx, u.uy+u.dy); if (*in_rooms(u.ux+u.dx, u.uy+u.dy, SHOPBASE)) add_damage(u.ux+u.dx, u.uy+u.dy, 0L); newsym(u.ux+u.dx, u.uy+u.dy); } else if (xlock.door->doormask & D_LOCKED) xlock.door->doormask = D_CLOSED; else xlock.door->doormask = D_LOCKED; } else { xlock.box->olocked = !xlock.box->olocked; if(xlock.box->otrapped) (void) chest_trap(xlock.box, FINGER, FALSE); } exercise(A_DEX, TRUE); return((xlock.usedtime = 0)); } STATIC_PTR int forcelock() /* try to force a locked chest */ { register struct obj *otmp; if((xlock.box->ox != u.ux) || (xlock.box->oy != u.uy)) return((xlock.usedtime = 0)); /* you or it moved */ if (xlock.usedtime++ >= 50 || !uwep || nohands(youmonst.data)) { You("give up your attempt to force the lock."); if(xlock.usedtime >= 50) /* you made the effort */ exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE); return((xlock.usedtime = 0)); } if(xlock.picktyp) { /* blade */ if(rn2(1000-(int)uwep->spe) > (992-greatest_erosion(uwep)*10) && !uwep->cursed && !obj_resists(uwep, 0, 99)) { /* for a +0 weapon, probability that it survives an unsuccessful * attempt to force the lock is (.992)^50 = .67 */ pline("%sour %s broke!", (uwep->quan > 1L) ? "One of y" : "Y", xname(uwep)); useup(uwep); You("give up your attempt to force the lock."); exercise(A_DEX, TRUE); return((xlock.usedtime = 0)); } } else /* blunt */ wake_nearby(); /* due to hammering on the container */ if(rn2(100) >= xlock.chance) return(1); /* still busy */ You("succeed in forcing the lock."); xlock.box->olocked = 0; xlock.box->obroken = 1; if(!xlock.picktyp && !rn2(3)) { struct monst *shkp; boolean costly; long loss = 0L; costly = (*u.ushops && costly_spot(u.ux, u.uy)); shkp = costly ? shop_keeper(*u.ushops) : 0; pline("In fact, you've totally destroyed %s.", the(xname(xlock.box))); /* Put the contents on ground at the hero's feet. */ while ((otmp = xlock.box->cobj) != 0) { obj_extract_self(otmp); if(!rn2(3) || otmp->oclass == POTION_CLASS) { chest_shatter_msg(otmp); if (costly) loss += stolen_value(otmp, u.ux, u.uy, (boolean)shkp->mpeaceful, TRUE); if (otmp->quan == 1L) { obfree(otmp, (struct obj *) 0); continue; } useup(otmp); } if (xlock.box->otyp == ICE_BOX && otmp->otyp == CORPSE) { otmp->age = monstermoves - otmp->age; /* actual age */ start_corpse_timeout(otmp); } place_object(otmp, u.ux, u.uy); stackobj(otmp); } if (costly) loss += stolen_value(xlock.box, u.ux, u.uy, (boolean)shkp->mpeaceful, TRUE); if(loss) You("owe %ld %s for objects destroyed.", loss, currency(loss)); delobj(xlock.box); } exercise((xlock.picktyp) ? A_DEX : A_STR, TRUE); return((xlock.usedtime = 0)); } #endif /* OVLB */ #ifdef OVL0 void reset_pick() { xlock.usedtime = xlock.chance = xlock.picktyp = 0; xlock.door = 0; xlock.box = 0; } #endif /* OVL0 */ #ifdef OVLB int pick_lock(pick) /* pick a lock with a given object */ register struct obj *pick; { int picktyp, c, ch; coord cc; struct rm *door; struct obj *otmp; char qbuf[QBUFSZ]; picktyp = pick->otyp; /* check whether we're resuming an interrupted previous attempt */ if (xlock.usedtime && picktyp == xlock.picktyp) { static char no_longer[] = "Unfortunately, you can no longer %s %s."; if (nohands(youmonst.data)) { const char *what = (picktyp == LOCK_PICK) ? "pick" : "key"; #ifdef TOURIST if (picktyp == CREDIT_CARD) what = "card"; #endif pline(no_longer, "hold the", what); reset_pick(); return 0; } else if (xlock.box && !can_reach_floor()) { pline(no_longer, "reach the", "lock"); reset_pick(); return 0; } else { const char *action = lock_action(); You("resume your attempt at %s.", action); set_occupation(picklock, action, 0); return(1); } } if(nohands(youmonst.data)) { You_cant("hold %s -- you have no hands!", doname(pick)); return(0); } if((picktyp != LOCK_PICK && #ifdef TOURIST picktyp != CREDIT_CARD && #endif picktyp != SKELETON_KEY)) { impossible("picking lock with object %d?", picktyp); return(0); } ch = 0; /* lint suppression */ if(!get_adjacent_loc((char *)0, "Invalid location!", u.ux, u.uy, &cc)) return 0; if (cc.x == u.ux && cc.y == u.uy) { /* pick lock on a container */ const char *verb; boolean it; int count; if (u.dz < 0) { There("isn't any sort of lock up %s.", Levitation ? "here" : "there"); return 0; } else if (is_lava(u.ux, u.uy)) { pline("Doing that would probably melt your %s.", xname(pick)); return 0; } else if (is_pool(u.ux, u.uy) && !Underwater) { pline_The("water has no lock."); return 0; } count = 0; c = 'n'; /* in case there are no boxes here */ for(otmp = level.objects[cc.x][cc.y]; otmp; otmp = otmp->nexthere) if (Is_box(otmp)) { ++count; if (!can_reach_floor()) { You_cant("reach %s from up here.", the(xname(otmp))); return 0; } it = 0; if (otmp->obroken) verb = "fix"; else if (!otmp->olocked) verb = "lock", it = 1; else if (picktyp != LOCK_PICK) verb = "unlock", it = 1; else verb = "pick"; Sprintf(qbuf, "There is %s here, %s %s?", safe_qbuf("", sizeof("There is here, unlock its lock?"), doname(otmp), an(simple_typename(otmp->otyp)), "a box"), verb, it ? "it" : "its lock"); c = ynq(qbuf); if(c == 'q') return(0); if(c == 'n') continue; if (otmp->obroken) { You_cant("fix its broken lock with %s.", doname(pick)); return 0; } #ifdef TOURIST else if (picktyp == CREDIT_CARD && !otmp->olocked) { /* credit cards are only good for unlocking */ You_cant("do that with %s.", doname(pick)); return 0; } #endif switch(picktyp) { #ifdef TOURIST case CREDIT_CARD: ch = ACURR(A_DEX) + 20*Role_if(PM_ROGUE); break; #endif case LOCK_PICK: ch = 4*ACURR(A_DEX) + 25*Role_if(PM_ROGUE); break; case SKELETON_KEY: ch = 75 + ACURR(A_DEX); break; default: ch = 0; } if(otmp->cursed) ch /= 2; xlock.picktyp = picktyp; xlock.box = otmp; xlock.door = 0; break; } if (c != 'y') { if (!count) There("doesn't seem to be any sort of lock here."); return(0); /* decided against all boxes */ } } else { /* pick the lock in a door */ struct monst *mtmp; if (u.utrap && u.utraptype == TT_PIT) { You_cant("reach over the edge of the pit."); return(0); } door = &levl[cc.x][cc.y]; if ((mtmp = m_at(cc.x, cc.y)) && canseemon(mtmp) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT) { #ifdef TOURIST if (picktyp == CREDIT_CARD && (mtmp->isshk || mtmp->data == &mons[PM_ORACLE])) verbalize("No checks, no credit, no problem."); else #endif pline("I don't think %s would appreciate that.", mon_nam(mtmp)); return(0); } if(!IS_DOOR(door->typ)) { if (is_drawbridge_wall(cc.x,cc.y) >= 0) You("%s no lock on the drawbridge.", Blind ? "feel" : "see"); else You("%s no door there.", Blind ? "feel" : "see"); return(0); } switch (door->doormask) { case D_NODOOR: pline("This doorway has no door."); return(0); case D_ISOPEN: You("cannot lock an open door."); return(0); case D_BROKEN: pline("This door is broken."); return(0); default: #ifdef TOURIST /* credit cards are only good for unlocking */ if(picktyp == CREDIT_CARD && !(door->doormask & D_LOCKED)) { You_cant("lock a door with a credit card."); return(0); } #endif Sprintf(qbuf,"%sock it?", (door->doormask & D_LOCKED) ? "Unl" : "L" ); c = yn(qbuf); if(c == 'n') return(0); switch(picktyp) { #ifdef TOURIST case CREDIT_CARD: ch = 2*ACURR(A_DEX) + 20*Role_if(PM_ROGUE); break; #endif case LOCK_PICK: ch = 3*ACURR(A_DEX) + 30*Role_if(PM_ROGUE); break; case SKELETON_KEY: ch = 70 + ACURR(A_DEX); break; default: ch = 0; } xlock.door = door; xlock.box = 0; } } flags.move = 0; xlock.chance = ch; xlock.picktyp = picktyp; xlock.usedtime = 0; set_occupation(picklock, lock_action(), 0); return(1); } int doforce() /* try to force a chest with your weapon */ { register struct obj *otmp; register int c, picktyp; char qbuf[QBUFSZ]; if(!uwep || /* proper type test */ (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep) && uwep->oclass != ROCK_CLASS) || (objects[uwep->otyp].oc_skill < P_DAGGER) || (objects[uwep->otyp].oc_skill > P_LANCE) || uwep->otyp == FLAIL || uwep->otyp == AKLYS #ifdef KOPS || uwep->otyp == RUBBER_HOSE #endif ) { You_cant("force anything without a %sweapon.", (uwep) ? "proper " : ""); return(0); } picktyp = is_blade(uwep); if(xlock.usedtime && xlock.box && picktyp == xlock.picktyp) { You("resume your attempt to force the lock."); set_occupation(forcelock, "forcing the lock", 0); return(1); } /* A lock is made only for the honest man, the thief will break it. */ xlock.box = (struct obj *)0; for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) if(Is_box(otmp)) { if (otmp->obroken || !otmp->olocked) { There("is %s here, but its lock is already %s.", doname(otmp), otmp->obroken ? "broken" : "unlocked"); continue; } Sprintf(qbuf,"There is %s here, force its lock?", safe_qbuf("", sizeof("There is here, force its lock?"), doname(otmp), an(simple_typename(otmp->otyp)), "a box")); c = ynq(qbuf); if(c == 'q') return(0); if(c == 'n') continue; if(picktyp) You("force your %s into a crack and pry.", xname(uwep)); else You("start bashing it with your %s.", xname(uwep)); xlock.box = otmp; xlock.chance = objects[uwep->otyp].oc_wldam * 2; xlock.picktyp = picktyp; xlock.usedtime = 0; break; } if(xlock.box) set_occupation(forcelock, "forcing the lock", 0); else You("decide not to force the issue."); return(1); } int doopen() /* try to open a door */ { coord cc; register struct rm *door; struct monst *mtmp; if (nohands(youmonst.data)) { You_cant("open anything -- you have no hands!"); return 0; } if (u.utrap && u.utraptype == TT_PIT) { You_cant("reach over the edge of the pit."); return 0; } if(!get_adjacent_loc((char *)0, (char *)0, u.ux, u.uy, &cc)) return(0); if((cc.x == u.ux) && (cc.y == u.uy)) return(0); if ((mtmp = m_at(cc.x,cc.y)) && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp); return(1); } door = &levl[cc.x][cc.y]; if(!IS_DOOR(door->typ)) { if (is_db_wall(cc.x,cc.y)) { There("is no obvious way to open the drawbridge."); return(0); } You("%s no door there.", Blind ? "feel" : "see"); return(0); } if (!(door->doormask & D_CLOSED)) { const char *mesg; switch (door->doormask) { case D_BROKEN: mesg = " is broken"; break; case D_NODOOR: mesg = "way has no door"; break; case D_ISOPEN: mesg = " is already open"; break; default: mesg = " is locked"; break; } pline("This door%s.", mesg); if (Blind) feel_location(cc.x,cc.y); return(0); } if(verysmall(youmonst.data)) { pline("You're too small to pull the door open."); return(0); } /* door is known to be CLOSED */ if (rnl(20) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) { pline_The("door opens."); if(door->doormask & D_TRAPPED) { b_trapped("door", FINGER); door->doormask = D_NODOOR; if (*in_rooms(cc.x, cc.y, SHOPBASE)) add_damage(cc.x, cc.y, 0L); } else door->doormask = D_ISOPEN; if (Blind) feel_location(cc.x,cc.y); /* the hero knows she opened it */ else newsym(cc.x,cc.y); unblock_point(cc.x,cc.y); /* vision: new see through there */ } else { exercise(A_STR, TRUE); pline_The("door resists!"); } return(1); } STATIC_OVL boolean obstructed(x,y) register int x, y; { register struct monst *mtmp = m_at(x, y); if(mtmp && mtmp->m_ap_type != M_AP_FURNITURE) { if (mtmp->m_ap_type == M_AP_OBJECT) goto objhere; pline("%s stands in the way!", !canspotmon(mtmp) ? "Some creature" : Monnam(mtmp)); if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); return(TRUE); } if (OBJ_AT(x, y)) { objhere: pline("%s's in the way.", Something); return(TRUE); } return(FALSE); } int doclose() /* try to close a door */ { register int x, y; register struct rm *door; struct monst *mtmp; if (nohands(youmonst.data)) { You_cant("close anything -- you have no hands!"); return 0; } if (u.utrap && u.utraptype == TT_PIT) { You_cant("reach over the edge of the pit."); return 0; } if(!getdir((char *)0)) return(0); x = u.ux + u.dx; y = u.uy + u.dy; if((x == u.ux) && (y == u.uy)) { You("are in the way!"); return(1); } if ((mtmp = m_at(x,y)) && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp); return(1); } door = &levl[x][y]; if(!IS_DOOR(door->typ)) { if (door->typ == DRAWBRIDGE_DOWN) There("is no obvious way to close the drawbridge."); else You("%s no door there.", Blind ? "feel" : "see"); return(0); } if(door->doormask == D_NODOOR) { pline("This doorway has no door."); return(0); } if(obstructed(x, y)) return(0); if(door->doormask == D_BROKEN) { pline("This door is broken."); return(0); } if(door->doormask & (D_CLOSED | D_LOCKED)) { pline("This door is already closed."); return(0); } if(door->doormask == D_ISOPEN) { if(verysmall(youmonst.data) #ifdef STEED && !u.usteed #endif ) { pline("You're too small to push the door closed."); return(0); } if ( #ifdef STEED u.usteed || #endif rn2(25) < (ACURRSTR+ACURR(A_DEX)+ACURR(A_CON))/3) { pline_The("door closes."); door->doormask = D_CLOSED; if (Blind) feel_location(x,y); /* the hero knows she closed it */ else newsym(x,y); block_point(x,y); /* vision: no longer see there */ } else { exercise(A_STR, TRUE); pline_The("door resists!"); } } return(1); } boolean /* box obj was hit with spell effect otmp */ boxlock(obj, otmp) /* returns true if something happened */ register struct obj *obj, *otmp; /* obj *is* a box */ { register boolean res = 0; switch(otmp->otyp) { case WAN_LOCKING: case SPE_WIZARD_LOCK: if (!obj->olocked) { /* lock it; fix if broken */ pline("Klunk!"); obj->olocked = 1; obj->obroken = 0; res = 1; } /* else already closed and locked */ break; case WAN_OPENING: case SPE_KNOCK: if (obj->olocked) { /* unlock; couldn't be broken */ pline("Klick!"); obj->olocked = 0; res = 1; } else /* silently fix if broken */ obj->obroken = 0; break; case WAN_POLYMORPH: case SPE_POLYMORPH: /* maybe start unlocking chest, get interrupted, then zap it; we must avoid any attempt to resume unlocking it */ if (xlock.box == obj) reset_pick(); break; } return res; } boolean /* Door/secret door was hit with spell effect otmp */ doorlock(otmp,x,y) /* returns true if something happened */ struct obj *otmp; int x, y; { register struct rm *door = &levl[x][y]; boolean res = TRUE; int loudness = 0; const char *msg = (const char *)0; const char *dustcloud = "A cloud of dust"; const char *quickly_dissipates = "quickly dissipates"; if (door->typ == SDOOR) { switch (otmp->otyp) { case WAN_OPENING: case SPE_KNOCK: case WAN_STRIKING: case SPE_FORCE_BOLT: door->typ = DOOR; door->doormask = D_CLOSED | (door->doormask & D_TRAPPED); newsym(x,y); if (cansee(x,y)) pline("A door appears in the wall!"); if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) return TRUE; break; /* striking: continue door handling below */ case WAN_LOCKING: case SPE_WIZARD_LOCK: default: return FALSE; } } switch(otmp->otyp) { case WAN_LOCKING: case SPE_WIZARD_LOCK: #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) { boolean vis = cansee(x,y); /* Can't have real locking in Rogue, so just hide doorway */ if (vis) pline("%s springs up in the older, more primitive doorway.", dustcloud); else You_hear("a swoosh."); if (obstructed(x,y)) { if (vis) pline_The("cloud %s.",quickly_dissipates); return FALSE; } block_point(x, y); door->typ = SDOOR; if (vis) pline_The("doorway vanishes!"); newsym(x,y); return TRUE; } #endif if (obstructed(x,y)) return FALSE; /* Don't allow doors to close over traps. This is for pits */ /* & trap doors, but is it ever OK for anything else? */ if (t_at(x,y)) { /* maketrap() clears doormask, so it should be NODOOR */ pline( "%s springs up in the doorway, but %s.", dustcloud, quickly_dissipates); return FALSE; } switch (door->doormask & ~D_TRAPPED) { case D_CLOSED: msg = "The door locks!"; break; case D_ISOPEN: msg = "The door swings shut, and locks!"; break; case D_BROKEN: msg = "The broken door reassembles and locks!"; break; case D_NODOOR: msg = "A cloud of dust springs up and assembles itself into a door!"; break; default: res = FALSE; break; } block_point(x, y); door->doormask = D_LOCKED | (door->doormask & D_TRAPPED); newsym(x,y); break; case WAN_OPENING: case SPE_KNOCK: if (door->doormask & D_LOCKED) { msg = "The door unlocks!"; door->doormask = D_CLOSED | (door->doormask & D_TRAPPED); } else res = FALSE; break; case WAN_STRIKING: case SPE_FORCE_BOLT: if (door->doormask & (D_LOCKED | D_CLOSED)) { if (door->doormask & D_TRAPPED) { if (MON_AT(x, y)) (void) mb_trapped(m_at(x,y)); else if (flags.verbose) { if (cansee(x,y)) pline("KABOOM!! You see a door explode."); else if (flags.soundok) You_hear("a distant explosion."); } door->doormask = D_NODOOR; unblock_point(x,y); newsym(x,y); loudness = 40; break; } door->doormask = D_BROKEN; if (flags.verbose) { if (cansee(x,y)) pline_The("door crashes open!"); else if (flags.soundok) You_hear("a crashing sound."); } unblock_point(x,y); newsym(x,y); /* force vision recalc before printing more messages */ if (vision_full_recalc) vision_recalc(0); loudness = 20; } else res = FALSE; break; default: impossible("magic (%d) attempted on door.", otmp->otyp); break; } if (msg && cansee(x,y)) pline(msg); if (loudness > 0) { /* door was destroyed */ wake_nearto(x, y, loudness); if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); } if (res && picking_at(x, y)) { /* maybe unseen monster zaps door you're unlocking */ stop_occupation(); reset_pick(); } return res; } STATIC_OVL void chest_shatter_msg(otmp) struct obj *otmp; { const char *disposition; const char *thing; long save_Blinded; if (otmp->oclass == POTION_CLASS) { You("%s %s shatter!", Blind ? "hear" : "see", an(bottlename())); if (!breathless(youmonst.data) || haseyes(youmonst.data)) potionbreathe(otmp); return; } /* We have functions for distant and singular names, but not one */ /* which does _both_... */ save_Blinded = Blinded; Blinded = 1; thing = singular(otmp, xname); Blinded = save_Blinded; switch (objects[otmp->otyp].oc_material) { case PAPER: disposition = "is torn to shreds"; break; case WAX: disposition = "is crushed"; break; case VEGGY: disposition = "is pulped"; break; case FLESH: disposition = "is mashed"; break; case GLASS: disposition = "shatters"; break; case WOOD: disposition = "splinters to fragments"; break; default: disposition = "is destroyed"; break; } pline("%s %s!", An(thing), disposition); } #endif /* OVLB */ /*lock.c*/ nethack-3.4.3/src/mail.c0100644000000000000000000003763107764735041013541 0ustar rootroot/* SCCS Id: @(#)mail.c 3.4 2002/01/13 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef MAIL #include "mail.h" /* * Notify user when new mail has arrived. Idea by Merlyn Leroy. * * The mail daemon can move with less than usual restraint. It can: * - move diagonally from a door * - use secret and closed doors * - run through a monster ("Gangway!", etc.) * - run over pools & traps * * Possible extensions: * - Open the file MAIL and do fstat instead of stat for efficiency. * (But sh uses stat, so this cannot be too bad.) * - Examine the mail and produce a scroll of mail named "From somebody". * - Invoke MAILREADER in such a way that only this single letter is read. * - Do something to the text when the scroll is enchanted or cancelled. * - Make the daemon always appear at a stairwell, and have it find a * path to the hero. * * Note by Olaf Seibert: On the Amiga, we usually don't get mail. So we go * through most of the effects at 'random' moments. * Note by Paul Winner: The MSDOS port also 'fakes' the mail daemon at * random intervals. */ STATIC_DCL boolean FDECL(md_start,(coord *)); STATIC_DCL boolean FDECL(md_stop,(coord *, coord *)); STATIC_DCL boolean FDECL(md_rush,(struct monst *,int,int)); STATIC_DCL void FDECL(newmail, (struct mail_info *)); extern char *viz_rmin, *viz_rmax; /* line-of-sight limits (vision.c) */ #ifdef OVL0 # if !defined(UNIX) && !defined(VMS) && !defined(LAN_MAIL) int mustgetmail = -1; # endif #endif /* OVL0 */ #ifdef OVLB # ifdef UNIX #include #include /* DON'T trust all Unices to declare getpwuid() in */ # if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX) # if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__)) /* DO trust all SVR4 to typedef uid_t in (probably to a long) */ # if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX) extern struct passwd *FDECL(getpwuid,(uid_t)); # else extern struct passwd *FDECL(getpwuid,(int)); # endif # endif # endif static struct stat omstat,nmstat; static char *mailbox = (char *)0; static long laststattime; # if !defined(MAILPATH) && defined(AMS) /* Just a placeholder for AMS */ # define MAILPATH "/dev/null" # endif # if !defined(MAILPATH) && (defined(LINUX) || defined(__osf__)) # define MAILPATH "/var/spool/mail/" # endif # if !defined(MAILPATH) && defined(__FreeBSD__) # define MAILPATH "/var/mail/" # endif # if !defined(MAILPATH) && (defined(BSD) || defined(ULTRIX)) # define MAILPATH "/usr/spool/mail/" # endif # if !defined(MAILPATH) && (defined(SYSV) || defined(HPUX)) # define MAILPATH "/usr/mail/" # endif void getmailstatus() { if(!mailbox && !(mailbox = nh_getenv("MAIL"))) { # ifdef MAILPATH # ifdef AMS struct passwd ppasswd; (void) memcpy(&ppasswd, getpwuid(getuid()), sizeof(struct passwd)); if (ppasswd.pw_dir) { mailbox = (char *) alloc((unsigned) strlen(ppasswd.pw_dir)+sizeof(AMS_MAILBOX)); Strcpy(mailbox, ppasswd.pw_dir); Strcat(mailbox, AMS_MAILBOX); } else return; # else const char *pw_name = getpwuid(getuid())->pw_name; mailbox = (char *) alloc(sizeof(MAILPATH)+strlen(pw_name)); Strcpy(mailbox, MAILPATH); Strcat(mailbox, pw_name); # endif /* AMS */ # else return; # endif } if(stat(mailbox, &omstat)){ # ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=\"%s\".", mailbox); mailbox = 0; # else omstat.st_mtime = 0; # endif } } # endif /* UNIX */ #endif /* OVLB */ #ifdef OVL0 /* * Pick coordinates for a starting position for the mail daemon. Called * from newmail() and newphone(). */ STATIC_OVL boolean md_start(startp) coord *startp; { coord testcc; /* scratch coordinates */ int row; /* current row we are checking */ int lax; /* if TRUE, pick a position in sight. */ int dd; /* distance to current point */ int max_distance; /* max distance found so far */ /* * If blind and not telepathic, then it doesn't matter what we pick --- * the hero is not going to see it anyway. So pick a nearby position. */ if (Blind && !Blind_telepat) { if (!enexto(startp, u.ux, u.uy, (struct permonst *) 0)) return FALSE; /* no good posiitons */ return TRUE; } /* * Arrive at an up or down stairwell if it is in line of sight from the * hero. */ if (couldsee(upstair.sx, upstair.sy)) { startp->x = upstair.sx; startp->y = upstair.sy; return TRUE; } if (couldsee(dnstair.sx, dnstair.sy)) { startp->x = dnstair.sx; startp->y = dnstair.sy; return TRUE; } /* * Try to pick a location out of sight next to the farthest position away * from the hero. If this fails, try again, just picking the farthest * position that could be seen. What we really ought to be doing is * finding a path from a stairwell... * * The arrays viz_rmin[] and viz_rmax[] are set even when blind. These * are the LOS limits for each row. */ lax = 0; /* be picky */ max_distance = -1; retry: for (row = 0; row < ROWNO; row++) { if (viz_rmin[row] < viz_rmax[row]) { /* There are valid positions on this row. */ dd = distu(viz_rmin[row],row); if (dd > max_distance) { if (lax) { max_distance = dd; startp->y = row; startp->x = viz_rmin[row]; } else if (enexto(&testcc, (xchar)viz_rmin[row], row, (struct permonst *) 0) && !cansee(testcc.x, testcc.y) && couldsee(testcc.x, testcc.y)) { max_distance = dd; *startp = testcc; } } dd = distu(viz_rmax[row],row); if (dd > max_distance) { if (lax) { max_distance = dd; startp->y = row; startp->x = viz_rmax[row]; } else if (enexto(&testcc, (xchar)viz_rmax[row], row, (struct permonst *) 0) && !cansee(testcc.x,testcc.y) && couldsee(testcc.x, testcc.y)) { max_distance = dd; *startp = testcc; } } } } if (max_distance < 0) { if (!lax) { lax = 1; /* just find a position */ goto retry; } return FALSE; } return TRUE; } /* * Try to choose a stopping point as near as possible to the starting * position while still adjacent to the hero. If all else fails, try * enexto(). Use enexto() as a last resort because enexto() chooses * its point randomly, which is not what we want. */ STATIC_OVL boolean md_stop(stopp, startp) coord *stopp; /* stopping position (we fill it in) */ coord *startp; /* starting positon (read only) */ { int x, y, distance, min_distance = -1; for (x = u.ux-1; x <= u.ux+1; x++) for (y = u.uy-1; y <= u.uy+1; y++) { if (!isok(x, y) || (x == u.ux && y == u.uy)) continue; if (ACCESSIBLE(levl[x][y].typ) && !MON_AT(x,y)) { distance = dist2(x,y,startp->x,startp->y); if (min_distance < 0 || distance < min_distance || (distance == min_distance && rn2(2))) { stopp->x = x; stopp->y = y; min_distance = distance; } } } /* If we didn't find a good spot, try enexto(). */ if (min_distance < 0 && !enexto(stopp, u.ux, u.uy, &mons[PM_MAIL_DAEMON])) return FALSE; return TRUE; } /* Let the mail daemon have a larger vocabulary. */ static NEARDATA const char *mail_text[] = { "Gangway!", "Look out!", "Pardon me!" }; #define md_exclamations() (mail_text[rn2(3)]) /* * Make the mail daemon run through the dungeon. The daemon will run over * any monsters that are in its path, but will replace them later. Return * FALSE if the md gets stuck in a position where there is a monster. Return * TRUE otherwise. */ STATIC_OVL boolean md_rush(md,tx,ty) struct monst *md; register int tx, ty; /* destination of mail daemon */ { struct monst *mon; /* displaced monster */ register int dx, dy; /* direction counters */ int fx = md->mx, fy = md->my; /* current location */ int nfx = fx, nfy = fy, /* new location */ d1, d2; /* shortest distances */ /* * It is possible that the monster at (fx,fy) is not the md when: * the md rushed the hero and failed, and is now starting back. */ if (m_at(fx, fy) == md) { remove_monster(fx, fy); /* pick up from orig position */ newsym(fx, fy); } /* * At the beginning and exit of this loop, md is not placed in the * dungeon. */ while (1) { /* Find a good location next to (fx,fy) closest to (tx,ty). */ d1 = dist2(fx,fy,tx,ty); for (dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++) if ((dx || dy) && isok(fx+dx,fy+dy) && !IS_STWALL(levl[fx+dx][fy+dy].typ)) { d2 = dist2(fx+dx,fy+dy,tx,ty); if (d2 < d1) { d1 = d2; nfx = fx+dx; nfy = fy+dy; } } /* Break if the md couldn't find a new position. */ if (nfx == fx && nfy == fy) break; fx = nfx; /* this is our new position */ fy = nfy; /* Break if the md reaches its destination. */ if (fx == tx && fy == ty) break; if ((mon = m_at(fx,fy)) != 0) /* save monster at this position */ verbalize(md_exclamations()); else if (fx == u.ux && fy == u.uy) verbalize("Excuse me."); place_monster(md,fx,fy); /* put md down */ newsym(fx,fy); /* see it */ flush_screen(0); /* make sure md shows up */ delay_output(); /* wait a little bit */ /* Remove md from the dungeon. Restore original mon, if necessary. */ if (mon) { if ((mon->mx != fx) || (mon->my != fy)) place_worm_seg(mon, fx, fy); else place_monster(mon, fx, fy); } else remove_monster(fx, fy); newsym(fx,fy); } /* * Check for a monster at our stopping position (this is possible, but * very unlikely). If one exists, then have the md leave in disgust. */ if ((mon = m_at(fx, fy)) != 0) { place_monster(md, fx, fy); /* display md with text below */ newsym(fx, fy); verbalize("This place's too crowded. I'm outta here."); if ((mon->mx != fx) || (mon->my != fy)) /* put mon back */ place_worm_seg(mon, fx, fy); else place_monster(mon, fx, fy); newsym(fx, fy); return FALSE; } place_monster(md, fx, fy); /* place at final spot */ newsym(fx, fy); flush_screen(0); delay_output(); /* wait a little bit */ return TRUE; } /* Deliver a scroll of mail. */ /*ARGSUSED*/ STATIC_OVL void newmail(info) struct mail_info *info; { struct monst *md; coord start, stop; boolean message_seen = FALSE; /* Try to find good starting and stopping places. */ if (!md_start(&start) || !md_stop(&stop,&start)) goto give_up; /* Make the daemon. Have it rush towards the hero. */ if (!(md = makemon(&mons[PM_MAIL_DAEMON], start.x, start.y, NO_MM_FLAGS))) goto give_up; if (!md_rush(md, stop.x, stop.y)) goto go_back; message_seen = TRUE; verbalize("%s, %s! %s.", Hello(md), plname, info->display_txt); if (info->message_typ) { struct obj *obj = mksobj(SCR_MAIL, FALSE, FALSE); if (distu(md->mx,md->my) > 2) verbalize("Catch!"); display_nhwindow(WIN_MESSAGE, FALSE); if (info->object_nam) { obj = oname(obj, info->object_nam); if (info->response_cmd) { /*(hide extension of the obj name)*/ int namelth = info->response_cmd - info->object_nam - 1; if ( namelth <= 0 || namelth >= (int) obj->onamelth ) impossible("mail delivery screwed up"); else *(ONAME(obj) + namelth) = '\0'; /* Note: renaming object will discard the hidden command. */ } } obj = hold_another_object(obj, "Oops!", (const char *)0, (const char *)0); } /* zip back to starting location */ go_back: (void) md_rush(md, start.x, start.y); mongone(md); /* deliver some classes of messages even if no daemon ever shows up */ give_up: if (!message_seen && info->message_typ == MSG_OTHER) pline("Hark! \"%s.\"", info->display_txt); } # if !defined(UNIX) && !defined(VMS) && !defined(LAN_MAIL) void ckmailstatus() { if (u.uswallow || !flags.biff) return; if (mustgetmail < 0) { #if defined(AMIGA) || defined(MSDOS) || defined(TOS) mustgetmail=(moves<2000)?(100+rn2(2000)):(2000+rn2(3000)); #endif return; } if (--mustgetmail <= 0) { static struct mail_info deliver = {MSG_MAIL,"I have some mail for you",0,0}; newmail(&deliver); mustgetmail = -1; } } /*ARGSUSED*/ void readmail(otmp) struct obj *otmp; { static char *junk[] = { "Please disregard previous letter.", "Welcome to NetHack.", #ifdef AMIGA "Only Amiga makes it possible.", "CATS have all the answers.", #endif "Report bugs to .", "Invitation: Visit the NetHack web site at http://www.nethack.org!" }; if (Blind) { pline("Unfortunately you cannot see what it says."); } else pline("It reads: \"%s\"", junk[rn2(SIZE(junk))]); } # endif /* !UNIX && !VMS && !LAN_MAIL */ # ifdef UNIX void ckmailstatus() { if(!mailbox || u.uswallow || !flags.biff # ifdef MAILCKFREQ || moves < laststattime + MAILCKFREQ # endif ) return; laststattime = moves; if(stat(mailbox, &nmstat)){ # ifdef PERMANENT_MAILBOX pline("Cannot get status of MAIL=\"%s\" anymore.", mailbox); mailbox = 0; # else nmstat.st_mtime = 0; # endif } else if(nmstat.st_mtime > omstat.st_mtime) { if (nmstat.st_size) { static struct mail_info deliver = { # ifndef NO_MAILREADER MSG_MAIL, "I have some mail for you", # else /* suppress creation and delivery of scroll of mail */ MSG_OTHER, "You have some mail in the outside world", # endif 0, 0 }; newmail(&deliver); } getmailstatus(); /* might be too late ... */ } } /*ARGSUSED*/ void readmail(otmp) struct obj *otmp; { # ifdef DEF_MAILREADER /* This implies that UNIX is defined */ register const char *mr = 0; display_nhwindow(WIN_MESSAGE, FALSE); if(!(mr = nh_getenv("MAILREADER"))) mr = DEF_MAILREADER; if(child(1)){ (void) execl(mr, mr, (char *)0); terminate(EXIT_FAILURE); } # else # ifndef AMS /* AMS mailboxes are directories */ display_file(mailbox, TRUE); # endif /* AMS */ # endif /* DEF_MAILREADER */ /* get new stat; not entirely correct: there is a small time window where we do not see new mail */ getmailstatus(); } # endif /* UNIX */ # ifdef VMS extern NDECL(struct mail_info *parse_next_broadcast); volatile int broadcasts = 0; void ckmailstatus() { struct mail_info *brdcst; if (u.uswallow || !flags.biff) return; while (broadcasts > 0) { /* process all trapped broadcasts [until] */ broadcasts--; if ((brdcst = parse_next_broadcast()) != 0) { newmail(brdcst); break; /* only handle one real message at a time */ } } } void readmail(otmp) struct obj *otmp; { # ifdef SHELL /* can't access mail reader without spawning subprocess */ const char *txt, *cmd; char *p, buf[BUFSZ], qbuf[BUFSZ]; int len; /* there should be a command hidden beyond the object name */ txt = otmp->onamelth ? ONAME(otmp) : ""; len = strlen(txt); cmd = (len + 1 < otmp->onamelth) ? txt + len + 1 : (char *) 0; if (!cmd || !*cmd) cmd = "SPAWN"; Sprintf(qbuf, "System command (%s)", cmd); getlin(qbuf, buf); if (*buf != '\033') { for (p = eos(buf); p > buf; *p = '\0') if (*--p != ' ') break; /* strip trailing spaces */ if (*buf) cmd = buf; /* use user entered command */ if (!strcmpi(cmd, "SPAWN") || !strcmp(cmd, "!")) cmd = (char *) 0; /* interactive escape */ vms_doshell(cmd, TRUE); (void) sleep(1); } # endif /* SHELL */ } # endif /* VMS */ # ifdef LAN_MAIL void ckmailstatus() { static int laststattime = 0; if(u.uswallow || !flags.biff # ifdef MAILCKFREQ || moves < laststattime + MAILCKFREQ # endif ) return; laststattime = moves; if (lan_mail_check()) { static struct mail_info deliver = { # ifndef NO_MAILREADER MSG_MAIL, "I have some mail for you", # else /* suppress creation and delivery of scroll of mail */ MSG_OTHER, "You have some mail in the outside world", # endif 0, 0 }; newmail(&deliver); } } /*ARGSUSED*/ void readmail(otmp) struct obj *otmp; { lan_mail_read(otmp); } # endif /* LAN_MAIL */ #endif /* OVL0 */ #endif /* MAIL */ /*mail.c*/ nethack-3.4.3/src/makemon.c0100644000000000000000000014662007764735041014245 0ustar rootroot/* SCCS Id: @(#)makemon.c 3.4 2003/09/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "epri.h" #include "emin.h" #include "edog.h" #ifdef REINCARNATION #include #endif STATIC_VAR NEARDATA struct monst zeromonst; /* this assumes that a human quest leader or nemesis is an archetype of the corresponding role; that isn't so for some roles (tourist for instance) but is for the priests and monks we use it for... */ #define quest_mon_represents_role(mptr,role_pm) \ (mptr->mlet == S_HUMAN && Role_if(role_pm) && \ (mptr->msound == MS_LEADER || mptr->msound == MS_NEMESIS)) #ifdef OVL0 STATIC_DCL boolean FDECL(uncommon, (int)); STATIC_DCL int FDECL(align_shift, (struct permonst *)); #endif /* OVL0 */ STATIC_DCL boolean FDECL(wrong_elem_type, (struct permonst *)); STATIC_DCL void FDECL(m_initgrp,(struct monst *,int,int,int)); STATIC_DCL void FDECL(m_initthrow,(struct monst *,int,int)); STATIC_DCL void FDECL(m_initweap,(struct monst *)); #ifdef OVL1 STATIC_DCL void FDECL(m_initinv,(struct monst *)); #endif /* OVL1 */ extern const int monstr[]; #define m_initsgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 3) #define m_initlgrp(mtmp, x, y) m_initgrp(mtmp, x, y, 10) #define toostrong(monindx, lev) (monstr[monindx] > lev) #define tooweak(monindx, lev) (monstr[monindx] < lev) #ifdef OVLB boolean is_home_elemental(ptr) register struct permonst *ptr; { if (ptr->mlet == S_ELEMENTAL) switch (monsndx(ptr)) { case PM_AIR_ELEMENTAL: return Is_airlevel(&u.uz); case PM_FIRE_ELEMENTAL: return Is_firelevel(&u.uz); case PM_EARTH_ELEMENTAL: return Is_earthlevel(&u.uz); case PM_WATER_ELEMENTAL: return Is_waterlevel(&u.uz); } return FALSE; } /* * Return true if the given monster cannot exist on this elemental level. */ STATIC_OVL boolean wrong_elem_type(ptr) register struct permonst *ptr; { if (ptr->mlet == S_ELEMENTAL) { return((boolean)(!is_home_elemental(ptr))); } else if (Is_earthlevel(&u.uz)) { /* no restrictions? */ } else if (Is_waterlevel(&u.uz)) { /* just monsters that can swim */ if(!is_swimmer(ptr)) return TRUE; } else if (Is_firelevel(&u.uz)) { if (!pm_resistance(ptr,MR_FIRE)) return TRUE; } else if (Is_airlevel(&u.uz)) { if(!(is_flyer(ptr) && ptr->mlet != S_TRAPPER) && !is_floater(ptr) && !amorphous(ptr) && !noncorporeal(ptr) && !is_whirly(ptr)) return TRUE; } return FALSE; } STATIC_OVL void m_initgrp(mtmp, x, y, n) /* make a group just like mtmp */ register struct monst *mtmp; register int x, y, n; { coord mm; register int cnt = rnd(n); struct monst *mon; #if defined(__GNUC__) && (defined(HPUX) || defined(DGUX)) /* There is an unresolved problem with several people finding that * the game hangs eating CPU; if interrupted and restored, the level * will be filled with monsters. Of those reports giving system type, * there were two DG/UX and two HP-UX, all using gcc as the compiler. * hcroft@hpopb1.cern.ch, using gcc 2.6.3 on HP-UX, says that the * problem went away for him and another reporter-to-newsgroup * after adding this debugging code. This has almost got to be a * compiler bug, but until somebody tracks it down and gets it fixed, * might as well go with the "but it went away when I tried to find * it" code. */ int cnttmp,cntdiv; cnttmp = cnt; # ifdef DEBUG pline("init group call x=%d,y=%d,n=%d,cnt=%d.", x, y, n, cnt); # endif cntdiv = ((u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1); #endif /* Tuning: cut down on swarming at low character levels [mrs] */ cnt /= (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1; #if defined(__GNUC__) && (defined(HPUX) || defined(DGUX)) if (cnt != (cnttmp/cntdiv)) { pline("cnt=%d using %d, cnttmp=%d, cntdiv=%d", cnt, (u.ulevel < 3) ? 4 : (u.ulevel < 5) ? 2 : 1, cnttmp, cntdiv); } #endif if(!cnt) cnt++; #if defined(__GNUC__) && (defined(HPUX) || defined(DGUX)) if (cnt < 0) cnt = 1; if (cnt > 10) cnt = 10; #endif mm.x = x; mm.y = y; while(cnt--) { if (peace_minded(mtmp->data)) continue; /* Don't create groups of peaceful monsters since they'll get * in our way. If the monster has a percentage chance so some * are peaceful and some are not, the result will just be a * smaller group. */ if (enexto(&mm, mm.x, mm.y, mtmp->data)) { mon = makemon(mtmp->data, mm.x, mm.y, NO_MM_FLAGS); mon->mpeaceful = FALSE; mon->mavenge = 0; set_malign(mon); /* Undo the second peace_minded() check in makemon(); if the * monster turned out to be peaceful the first time we * didn't create it at all; we don't want a second check. */ } } } STATIC_OVL void m_initthrow(mtmp,otyp,oquan) struct monst *mtmp; int otyp,oquan; { register struct obj *otmp; otmp = mksobj(otyp, TRUE, FALSE); otmp->quan = (long) rn1(oquan, 3); otmp->owt = weight(otmp); if (otyp == ORCISH_ARROW) otmp->opoisoned = TRUE; (void) mpickobj(mtmp, otmp); } #endif /* OVLB */ #ifdef OVL2 STATIC_OVL void m_initweap(mtmp) register struct monst *mtmp; { register struct permonst *ptr = mtmp->data; register int mm = monsndx(ptr); struct obj *otmp; #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) return; #endif /* * first a few special cases: * * giants get a boulder to throw sometimes. * ettins get clubs * kobolds get darts to throw * centaurs get some sort of bow & arrows or bolts * soldiers get all sorts of things. * kops get clubs & cream pies. */ switch (ptr->mlet) { case S_GIANT: if (rn2(2)) (void)mongets(mtmp, (mm != PM_ETTIN) ? BOULDER : CLUB); break; case S_HUMAN: if(is_mercenary(ptr)) { int w1 = 0, w2 = 0; switch (mm) { case PM_WATCHMAN: case PM_SOLDIER: if (!rn2(3)) { w1 = rn1(BEC_DE_CORBIN - PARTISAN + 1, PARTISAN); w2 = rn2(2) ? DAGGER : KNIFE; } else w1 = rn2(2) ? SPEAR : SHORT_SWORD; break; case PM_SERGEANT: w1 = rn2(2) ? FLAIL : MACE; break; case PM_LIEUTENANT: w1 = rn2(2) ? BROADSWORD : LONG_SWORD; break; case PM_CAPTAIN: case PM_WATCH_CAPTAIN: w1 = rn2(2) ? LONG_SWORD : SILVER_SABER; break; default: if (!rn2(4)) w1 = DAGGER; if (!rn2(7)) w2 = SPEAR; break; } if (w1) (void)mongets(mtmp, w1); if (!w2 && w1 != DAGGER && !rn2(4)) w2 = KNIFE; if (w2) (void)mongets(mtmp, w2); } else if (is_elf(ptr)) { if (rn2(2)) (void) mongets(mtmp, rn2(2) ? ELVEN_MITHRIL_COAT : ELVEN_CLOAK); if (rn2(2)) (void)mongets(mtmp, ELVEN_LEATHER_HELM); else if (!rn2(4)) (void)mongets(mtmp, ELVEN_BOOTS); if (rn2(2)) (void)mongets(mtmp, ELVEN_DAGGER); switch (rn2(3)) { case 0: if (!rn2(4)) (void)mongets(mtmp, ELVEN_SHIELD); if (rn2(3)) (void)mongets(mtmp, ELVEN_SHORT_SWORD); (void)mongets(mtmp, ELVEN_BOW); m_initthrow(mtmp, ELVEN_ARROW, 12); break; case 1: (void)mongets(mtmp, ELVEN_BROADSWORD); if (rn2(2)) (void)mongets(mtmp, ELVEN_SHIELD); break; case 2: if (rn2(2)) { (void)mongets(mtmp, ELVEN_SPEAR); (void)mongets(mtmp, ELVEN_SHIELD); } break; } if (mm == PM_ELVENKING) { if (rn2(3) || (in_mklev && Is_earthlevel(&u.uz))) (void)mongets(mtmp, PICK_AXE); if (!rn2(50)) (void)mongets(mtmp, CRYSTAL_BALL); } } else if (ptr->msound == MS_PRIEST || quest_mon_represents_role(ptr,PM_PRIEST)) { otmp = mksobj(MACE, FALSE, FALSE); if(otmp) { otmp->spe = rnd(3); if(!rn2(2)) curse(otmp); (void) mpickobj(mtmp, otmp); } } break; case S_ANGEL: { int spe2; /* create minion stuff; can't use mongets */ otmp = mksobj(LONG_SWORD, FALSE, FALSE); /* maybe make it special */ if (!rn2(20) || is_lord(ptr)) otmp = oname(otmp, artiname( rn2(2) ? ART_DEMONBANE : ART_SUNSWORD)); bless(otmp); otmp->oerodeproof = TRUE; spe2 = rn2(4); otmp->spe = max(otmp->spe, spe2); (void) mpickobj(mtmp, otmp); otmp = mksobj(!rn2(4) || is_lord(ptr) ? SHIELD_OF_REFLECTION : LARGE_SHIELD, FALSE, FALSE); otmp->cursed = FALSE; otmp->oerodeproof = TRUE; otmp->spe = 0; (void) mpickobj(mtmp, otmp); } break; case S_HUMANOID: if (mm == PM_HOBBIT) { switch (rn2(3)) { case 0: (void)mongets(mtmp, DAGGER); break; case 1: (void)mongets(mtmp, ELVEN_DAGGER); break; case 2: (void)mongets(mtmp, SLING); break; } if (!rn2(10)) (void)mongets(mtmp, ELVEN_MITHRIL_COAT); if (!rn2(10)) (void)mongets(mtmp, DWARVISH_CLOAK); } else if (is_dwarf(ptr)) { if (rn2(7)) (void)mongets(mtmp, DWARVISH_CLOAK); if (rn2(7)) (void)mongets(mtmp, IRON_SHOES); if (!rn2(4)) { (void)mongets(mtmp, DWARVISH_SHORT_SWORD); /* note: you can't use a mattock with a shield */ if (rn2(2)) (void)mongets(mtmp, DWARVISH_MATTOCK); else { (void)mongets(mtmp, AXE); (void)mongets(mtmp, DWARVISH_ROUNDSHIELD); } (void)mongets(mtmp, DWARVISH_IRON_HELM); if (!rn2(3)) (void)mongets(mtmp, DWARVISH_MITHRIL_COAT); } else { (void)mongets(mtmp, !rn2(3) ? PICK_AXE : DAGGER); } } break; # ifdef KOPS case S_KOP: /* create Keystone Kops with cream pies to * throw. As suggested by KAA. [MRS] */ if (!rn2(4)) m_initthrow(mtmp, CREAM_PIE, 2); if (!rn2(3)) (void)mongets(mtmp,(rn2(2)) ? CLUB : RUBBER_HOSE); break; # endif case S_ORC: if(rn2(2)) (void)mongets(mtmp, ORCISH_HELM); switch (mm != PM_ORC_CAPTAIN ? mm : rn2(2) ? PM_MORDOR_ORC : PM_URUK_HAI) { case PM_MORDOR_ORC: if(!rn2(3)) (void)mongets(mtmp, SCIMITAR); if(!rn2(3)) (void)mongets(mtmp, ORCISH_SHIELD); if(!rn2(3)) (void)mongets(mtmp, KNIFE); if(!rn2(3)) (void)mongets(mtmp, ORCISH_CHAIN_MAIL); break; case PM_URUK_HAI: if(!rn2(3)) (void)mongets(mtmp, ORCISH_CLOAK); if(!rn2(3)) (void)mongets(mtmp, ORCISH_SHORT_SWORD); if(!rn2(3)) (void)mongets(mtmp, IRON_SHOES); if(!rn2(3)) { (void)mongets(mtmp, ORCISH_BOW); m_initthrow(mtmp, ORCISH_ARROW, 12); } if(!rn2(3)) (void)mongets(mtmp, URUK_HAI_SHIELD); break; default: if (mm != PM_ORC_SHAMAN && rn2(2)) (void)mongets(mtmp, (mm == PM_GOBLIN || rn2(2) == 0) ? ORCISH_DAGGER : SCIMITAR); } break; case S_OGRE: if (!rn2(mm == PM_OGRE_KING ? 3 : mm == PM_OGRE_LORD ? 6 : 12)) (void) mongets(mtmp, BATTLE_AXE); else (void) mongets(mtmp, CLUB); break; case S_TROLL: if (!rn2(2)) switch (rn2(4)) { case 0: (void)mongets(mtmp, RANSEUR); break; case 1: (void)mongets(mtmp, PARTISAN); break; case 2: (void)mongets(mtmp, GLAIVE); break; case 3: (void)mongets(mtmp, SPETUM); break; } break; case S_KOBOLD: if (!rn2(4)) m_initthrow(mtmp, DART, 12); break; case S_CENTAUR: if (rn2(2)) { if(ptr == &mons[PM_FOREST_CENTAUR]) { (void)mongets(mtmp, BOW); m_initthrow(mtmp, ARROW, 12); } else { (void)mongets(mtmp, CROSSBOW); m_initthrow(mtmp, CROSSBOW_BOLT, 12); } } break; case S_WRAITH: (void)mongets(mtmp, KNIFE); (void)mongets(mtmp, LONG_SWORD); break; case S_ZOMBIE: if (!rn2(4)) (void)mongets(mtmp, LEATHER_ARMOR); if (!rn2(4)) (void)mongets(mtmp, (rn2(3) ? KNIFE : SHORT_SWORD)); break; case S_LIZARD: if (mm == PM_SALAMANDER) (void)mongets(mtmp, (rn2(7) ? SPEAR : rn2(3) ? TRIDENT : STILETTO)); break; case S_DEMON: switch (mm) { case PM_BALROG: (void)mongets(mtmp, BULLWHIP); (void)mongets(mtmp, BROADSWORD); break; case PM_ORCUS: (void)mongets(mtmp, WAN_DEATH); /* the Wand of Orcus */ break; case PM_HORNED_DEVIL: (void)mongets(mtmp, rn2(4) ? TRIDENT : BULLWHIP); break; case PM_DISPATER: (void)mongets(mtmp, WAN_STRIKING); break; case PM_YEENOGHU: (void)mongets(mtmp, FLAIL); break; } /* prevent djinnis and mail daemons from leaving objects when * they vanish */ if (!is_demon(ptr)) break; /* fall thru */ /* * Now the general case, Some chance of getting some type * of weapon for "normal" monsters. Certain special types * of monsters will get a bonus chance or different selections. */ default: { int bias; bias = is_lord(ptr) + is_prince(ptr) * 2 + extra_nasty(ptr); switch(rnd(14 - (2 * bias))) { case 1: if(strongmonst(ptr)) (void) mongets(mtmp, BATTLE_AXE); else m_initthrow(mtmp, DART, 12); break; case 2: if(strongmonst(ptr)) (void) mongets(mtmp, TWO_HANDED_SWORD); else { (void) mongets(mtmp, CROSSBOW); m_initthrow(mtmp, CROSSBOW_BOLT, 12); } break; case 3: (void) mongets(mtmp, BOW); m_initthrow(mtmp, ARROW, 12); break; case 4: if(strongmonst(ptr)) (void) mongets(mtmp, LONG_SWORD); else m_initthrow(mtmp, DAGGER, 3); break; case 5: if(strongmonst(ptr)) (void) mongets(mtmp, LUCERN_HAMMER); else (void) mongets(mtmp, AKLYS); break; default: break; } } break; } if ((int) mtmp->m_lev > rn2(75)) (void) mongets(mtmp, rnd_offensive_item(mtmp)); } #endif /* OVL2 */ #ifdef OVL1 #ifdef GOLDOBJ /* * Makes up money for monster's inventory. * This will change with silver & copper coins */ void mkmonmoney(mtmp, amount) struct monst *mtmp; long amount; { struct obj *gold = mksobj(GOLD_PIECE, FALSE, FALSE); gold->quan = amount; add_to_minv(mtmp, gold); } #endif STATIC_OVL void m_initinv(mtmp) register struct monst *mtmp; { register int cnt; register struct obj *otmp; register struct permonst *ptr = mtmp->data; #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) return; #endif /* * Soldiers get armour & rations - armour approximates their ac. * Nymphs may get mirror or potion of object detection. */ switch(ptr->mlet) { case S_HUMAN: if(is_mercenary(ptr)) { register int mac; switch(monsndx(ptr)) { case PM_GUARD: mac = -1; break; case PM_SOLDIER: mac = 3; break; case PM_SERGEANT: mac = 0; break; case PM_LIEUTENANT: mac = -2; break; case PM_CAPTAIN: mac = -3; break; case PM_WATCHMAN: mac = 3; break; case PM_WATCH_CAPTAIN: mac = -2; break; default: impossible("odd mercenary %d?", monsndx(ptr)); mac = 0; break; } if (mac < -1 && rn2(5)) mac += 7 + mongets(mtmp, (rn2(5)) ? PLATE_MAIL : CRYSTAL_PLATE_MAIL); else if (mac < 3 && rn2(5)) mac += 6 + mongets(mtmp, (rn2(3)) ? SPLINT_MAIL : BANDED_MAIL); else if (rn2(5)) mac += 3 + mongets(mtmp, (rn2(3)) ? RING_MAIL : STUDDED_LEATHER_ARMOR); else mac += 2 + mongets(mtmp, LEATHER_ARMOR); if (mac < 10 && rn2(3)) mac += 1 + mongets(mtmp, HELMET); else if (mac < 10 && rn2(2)) mac += 1 + mongets(mtmp, DENTED_POT); if (mac < 10 && rn2(3)) mac += 1 + mongets(mtmp, SMALL_SHIELD); else if (mac < 10 && rn2(2)) mac += 2 + mongets(mtmp, LARGE_SHIELD); if (mac < 10 && rn2(3)) mac += 1 + mongets(mtmp, LOW_BOOTS); else if (mac < 10 && rn2(2)) mac += 2 + mongets(mtmp, HIGH_BOOTS); if (mac < 10 && rn2(3)) mac += 1 + mongets(mtmp, LEATHER_GLOVES); else if (mac < 10 && rn2(2)) mac += 1 + mongets(mtmp, LEATHER_CLOAK); if(ptr != &mons[PM_GUARD] && ptr != &mons[PM_WATCHMAN] && ptr != &mons[PM_WATCH_CAPTAIN]) { if (!rn2(3)) (void) mongets(mtmp, K_RATION); if (!rn2(2)) (void) mongets(mtmp, C_RATION); if (ptr != &mons[PM_SOLDIER] && !rn2(3)) (void) mongets(mtmp, BUGLE); } else if (ptr == &mons[PM_WATCHMAN] && rn2(3)) (void) mongets(mtmp, TIN_WHISTLE); } else if (ptr == &mons[PM_SHOPKEEPER]) { (void) mongets(mtmp,SKELETON_KEY); switch (rn2(4)) { /* MAJOR fall through ... */ case 0: (void) mongets(mtmp, WAN_MAGIC_MISSILE); case 1: (void) mongets(mtmp, POT_EXTRA_HEALING); case 2: (void) mongets(mtmp, POT_HEALING); case 3: (void) mongets(mtmp, WAN_STRIKING); } } else if (ptr->msound == MS_PRIEST || quest_mon_represents_role(ptr,PM_PRIEST)) { (void) mongets(mtmp, rn2(7) ? ROBE : rn2(3) ? CLOAK_OF_PROTECTION : CLOAK_OF_MAGIC_RESISTANCE); (void) mongets(mtmp, SMALL_SHIELD); #ifndef GOLDOBJ mtmp->mgold = (long)rn1(10,20); #else mkmonmoney(mtmp,(long)rn1(10,20)); #endif } else if (quest_mon_represents_role(ptr,PM_MONK)) { (void) mongets(mtmp, rn2(11) ? ROBE : CLOAK_OF_MAGIC_RESISTANCE); } break; case S_NYMPH: if(!rn2(2)) (void) mongets(mtmp, MIRROR); if(!rn2(2)) (void) mongets(mtmp, POT_OBJECT_DETECTION); break; case S_GIANT: if (ptr == &mons[PM_MINOTAUR]) { if (!rn2(3) || (in_mklev && Is_earthlevel(&u.uz))) (void) mongets(mtmp, WAN_DIGGING); } else if (is_giant(ptr)) { for (cnt = rn2((int)(mtmp->m_lev / 2)); cnt; cnt--) { otmp = mksobj(rnd_class(DILITHIUM_CRYSTAL,LUCKSTONE-1), FALSE, FALSE); otmp->quan = (long) rn1(2, 3); otmp->owt = weight(otmp); (void) mpickobj(mtmp, otmp); } } break; case S_WRAITH: if (ptr == &mons[PM_NAZGUL]) { otmp = mksobj(RIN_INVISIBILITY, FALSE, FALSE); curse(otmp); (void) mpickobj(mtmp, otmp); } break; case S_LICH: if (ptr == &mons[PM_MASTER_LICH] && !rn2(13)) (void)mongets(mtmp, (rn2(7) ? ATHAME : WAN_NOTHING)); else if (ptr == &mons[PM_ARCH_LICH] && !rn2(3)) { otmp = mksobj(rn2(3) ? ATHAME : QUARTERSTAFF, TRUE, rn2(13) ? FALSE : TRUE); if (otmp->spe < 2) otmp->spe = rnd(3); if (!rn2(4)) otmp->oerodeproof = 1; (void) mpickobj(mtmp, otmp); } break; case S_MUMMY: if (rn2(7)) (void)mongets(mtmp, MUMMY_WRAPPING); break; case S_QUANTMECH: if (!rn2(20)) { otmp = mksobj(LARGE_BOX, FALSE, FALSE); otmp->spe = 1; /* flag for special box */ otmp->owt = weight(otmp); (void) mpickobj(mtmp, otmp); } break; case S_LEPRECHAUN: #ifndef GOLDOBJ mtmp->mgold = (long) d(level_difficulty(), 30); #else mkmonmoney(mtmp, (long) d(level_difficulty(), 30)); #endif break; case S_DEMON: /* moved here from m_initweap() because these don't have AT_WEAP so m_initweap() is not called for them */ if (ptr == &mons[PM_ICE_DEVIL] && !rn2(4)) { (void)mongets(mtmp, SPEAR); } else if (ptr == &mons[PM_ASMODEUS]) { (void)mongets(mtmp, WAN_COLD); (void)mongets(mtmp, WAN_FIRE); } break; default: break; } /* ordinary soldiers rarely have access to magic (or gold :-) */ if (ptr == &mons[PM_SOLDIER] && rn2(13)) return; if ((int) mtmp->m_lev > rn2(50)) (void) mongets(mtmp, rnd_defensive_item(mtmp)); if ((int) mtmp->m_lev > rn2(100)) (void) mongets(mtmp, rnd_misc_item(mtmp)); #ifndef GOLDOBJ if (likes_gold(ptr) && !mtmp->mgold && !rn2(5)) mtmp->mgold = (long) d(level_difficulty(), mtmp->minvent ? 5 : 10); #else if (likes_gold(ptr) && !findgold(mtmp->minvent) && !rn2(5)) mkmonmoney(mtmp, (long) d(level_difficulty(), mtmp->minvent ? 5 : 10)); #endif } /* Note: for long worms, always call cutworm (cutworm calls clone_mon) */ struct monst * clone_mon(mon, x, y) struct monst *mon; xchar x, y; /* clone's preferred location or 0 (near mon) */ { coord mm; struct monst *m2; /* may be too weak or have been extinguished for population control */ if (mon->mhp <= 1 || (mvitals[monsndx(mon->data)].mvflags & G_EXTINCT)) return (struct monst *)0; if (x == 0) { mm.x = mon->mx; mm.y = mon->my; if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y)) return (struct monst *)0; } else if (!isok(x, y)) { return (struct monst *)0; /* paranoia */ } else { mm.x = x; mm.y = y; if (MON_AT(mm.x, mm.y)) { if (!enexto(&mm, mm.x, mm.y, mon->data) || MON_AT(mm.x, mm.y)) return (struct monst *)0; } } m2 = newmonst(0); *m2 = *mon; /* copy condition of old monster */ m2->nmon = fmon; fmon = m2; m2->m_id = flags.ident++; if (!m2->m_id) m2->m_id = flags.ident++; /* ident overflowed */ m2->mx = mm.x; m2->my = mm.y; m2->minvent = (struct obj *) 0; /* objects don't clone */ m2->mleashed = FALSE; #ifndef GOLDOBJ m2->mgold = 0L; #endif /* Max HP the same, but current HP halved for both. The caller * might want to override this by halving the max HP also. * When current HP is odd, the original keeps the extra point. */ m2->mhpmax = mon->mhpmax; m2->mhp = mon->mhp / 2; mon->mhp -= m2->mhp; /* since shopkeepers and guards will only be cloned if they've been * polymorphed away from their original forms, the clone doesn't have * room for the extra information. we also don't want two shopkeepers * around for the same shop. */ if (mon->isshk) m2->isshk = FALSE; if (mon->isgd) m2->isgd = FALSE; if (mon->ispriest) m2->ispriest = FALSE; m2->mxlth = 0; place_monster(m2, m2->mx, m2->my); if (emits_light(m2->data)) new_light_source(m2->mx, m2->my, emits_light(m2->data), LS_MONSTER, (genericptr_t)m2); if (m2->mnamelth) { m2->mnamelth = 0; /* or it won't get allocated */ m2 = christen_monst(m2, NAME(mon)); } else if (mon->isshk) { m2 = christen_monst(m2, shkname(mon)); } /* not all clones caused by player are tame or peaceful */ if (!flags.mon_moving) { if (mon->mtame) m2->mtame = rn2(max(2 + u.uluck, 2)) ? mon->mtame : 0; else if (mon->mpeaceful) m2->mpeaceful = rn2(max(2 + u.uluck, 2)) ? 1 : 0; } newsym(m2->mx,m2->my); /* display the new monster */ if (m2->mtame) { struct monst *m3; if (mon->isminion) { m3 = newmonst(sizeof(struct epri) + mon->mnamelth); *m3 = *m2; m3->mxlth = sizeof(struct epri); if (m2->mnamelth) Strcpy(NAME(m3), NAME(m2)); *(EPRI(m3)) = *(EPRI(mon)); replmon(m2, m3); m2 = m3; } else { /* because m2 is a copy of mon it is tame but not init'ed. * however, tamedog will not re-tame a tame dog, so m2 * must be made non-tame to get initialized properly. */ m2->mtame = 0; if ((m3 = tamedog(m2, (struct obj *)0)) != 0) { m2 = m3; *(EDOG(m2)) = *(EDOG(mon)); } } } set_malign(m2); return m2; } /* * Propagate a species * * Once a certain number of monsters are created, don't create any more * at random (i.e. make them extinct). The previous (3.2) behavior was * to do this when a certain number had _died_, which didn't make * much sense. * * Returns FALSE propagation unsuccessful * TRUE propagation successful */ boolean propagate(mndx, tally, ghostly) int mndx; boolean tally; boolean ghostly; { boolean result; uchar lim = mbirth_limit(mndx); boolean gone = (mvitals[mndx].mvflags & G_GONE); /* genocided or extinct */ result = (((int) mvitals[mndx].born < lim) && !gone) ? TRUE : FALSE; /* if it's unique, don't ever make it again */ if (mons[mndx].geno & G_UNIQ) mvitals[mndx].mvflags |= G_EXTINCT; if (mvitals[mndx].born < 255 && tally && (!ghostly || (ghostly && result))) mvitals[mndx].born++; if ((int) mvitals[mndx].born >= lim && !(mons[mndx].geno & G_NOGEN) && !(mvitals[mndx].mvflags & G_EXTINCT)) { #if defined(DEBUG) && defined(WIZARD) if (wizard) pline("Automatically extinguished %s.", makeplural(mons[mndx].mname)); #endif mvitals[mndx].mvflags |= G_EXTINCT; reset_rndmonst(mndx); } return result; } /* * called with [x,y] = coordinates; * [0,0] means anyplace * [u.ux,u.uy] means: near player (if !in_mklev) * * In case we make a monster group, only return the one at [x,y]. */ struct monst * makemon(ptr, x, y, mmflags) register struct permonst *ptr; register int x, y; register int mmflags; { register struct monst *mtmp; int mndx, mcham, ct, mitem, xlth; boolean anymon = (!ptr); boolean byyou = (x == u.ux && y == u.uy); boolean allow_minvent = ((mmflags & NO_MINVENT) == 0); boolean countbirth = ((mmflags & MM_NOCOUNTBIRTH) == 0); unsigned gpflags = (mmflags & MM_IGNOREWATER) ? MM_IGNOREWATER : 0; /* if caller wants random location, do it here */ if(x == 0 && y == 0) { int tryct = 0; /* careful with bigrooms */ struct monst fakemon; fakemon.data = ptr; /* set up for goodpos */ do { x = rn1(COLNO-3,2); y = rn2(ROWNO); } while(!goodpos(x, y, ptr ? &fakemon : (struct monst *)0, gpflags) || (!in_mklev && tryct++ < 50 && cansee(x, y))); } else if (byyou && !in_mklev) { coord bypos; if(enexto_core(&bypos, u.ux, u.uy, ptr, gpflags)) { x = bypos.x; y = bypos.y; } else return((struct monst *)0); } /* Does monster already exist at the position? */ if(MON_AT(x, y)) { if ((mmflags & MM_ADJACENTOK) != 0) { coord bypos; if(enexto_core(&bypos, x, y, ptr, gpflags)) { x = bypos.x; y = bypos.y; } else return((struct monst *) 0); } else return((struct monst *) 0); } if(ptr){ mndx = monsndx(ptr); /* if you are to make a specific monster and it has already been genocided, return */ if (mvitals[mndx].mvflags & G_GENOD) return((struct monst *) 0); #if defined(WIZARD) && defined(DEBUG) if (wizard && (mvitals[mndx].mvflags & G_EXTINCT)) pline("Explicitly creating extinct monster %s.", mons[mndx].mname); #endif } else { /* make a random (common) monster that can survive here. * (the special levels ask for random monsters at specific * positions, causing mass drowning on the medusa level, * for instance.) */ int tryct = 0; /* maybe there are no good choices */ struct monst fakemon; do { if(!(ptr = rndmonst())) { #ifdef DEBUG pline("Warning: no monster."); #endif return((struct monst *) 0); /* no more monsters! */ } fakemon.data = ptr; /* set up for goodpos */ } while(!goodpos(x, y, &fakemon, gpflags) && tryct++ < 50); mndx = monsndx(ptr); } (void) propagate(mndx, countbirth, FALSE); xlth = ptr->pxlth; if (mmflags & MM_EDOG) xlth += sizeof(struct edog); else if (mmflags & MM_EMIN) xlth += sizeof(struct emin); mtmp = newmonst(xlth); *mtmp = zeromonst; /* clear all entries in structure */ (void)memset((genericptr_t)mtmp->mextra, 0, xlth); mtmp->nmon = fmon; fmon = mtmp; mtmp->m_id = flags.ident++; if (!mtmp->m_id) mtmp->m_id = flags.ident++; /* ident overflowed */ set_mon_data(mtmp, ptr, 0); if (mtmp->data->msound == MS_LEADER) quest_status.leader_m_id = mtmp->m_id; mtmp->mxlth = xlth; mtmp->mnum = mndx; mtmp->m_lev = adj_lev(ptr); if (is_golem(ptr)) { mtmp->mhpmax = mtmp->mhp = golemhp(mndx); } else if (is_rider(ptr)) { /* We want low HP, but a high mlevel so they can attack well */ mtmp->mhpmax = mtmp->mhp = d(10,8); } else if (ptr->mlevel > 49) { /* "special" fixed hp monster * the hit points are encoded in the mlevel in a somewhat strange * way to fit in the 50..127 positive range of a signed character * above the 1..49 that indicate "normal" monster levels */ mtmp->mhpmax = mtmp->mhp = 2*(ptr->mlevel - 6); mtmp->m_lev = mtmp->mhp / 4; /* approximation */ } else if (ptr->mlet == S_DRAGON && mndx >= PM_GRAY_DRAGON) { /* adult dragons */ mtmp->mhpmax = mtmp->mhp = (int) (In_endgame(&u.uz) ? (8 * mtmp->m_lev) : (4 * mtmp->m_lev + d((int)mtmp->m_lev, 4))); } else if (!mtmp->m_lev) { mtmp->mhpmax = mtmp->mhp = rnd(4); } else { mtmp->mhpmax = mtmp->mhp = d((int)mtmp->m_lev, 8); if (is_home_elemental(ptr)) mtmp->mhpmax = (mtmp->mhp *= 3); } if (is_female(ptr)) mtmp->female = TRUE; else if (is_male(ptr)) mtmp->female = FALSE; else mtmp->female = rn2(2); /* ignored for neuters */ if (In_sokoban(&u.uz) && !mindless(ptr)) /* know about traps here */ mtmp->mtrapseen = (1L << (PIT - 1)) | (1L << (HOLE - 1)); if (ptr->msound == MS_LEADER) /* leader knows about portal */ mtmp->mtrapseen |= (1L << (MAGIC_PORTAL-1)); place_monster(mtmp, x, y); mtmp->mcansee = mtmp->mcanmove = TRUE; mtmp->mpeaceful = (mmflags & MM_ANGRY) ? FALSE : peace_minded(ptr); switch(ptr->mlet) { case S_MIMIC: set_mimic_sym(mtmp); break; case S_SPIDER: case S_SNAKE: if(in_mklev) if(x && y) (void) mkobj_at(0, x, y, TRUE); if(hides_under(ptr) && OBJ_AT(x, y)) mtmp->mundetected = TRUE; break; case S_LIGHT: case S_ELEMENTAL: if (mndx == PM_STALKER || mndx == PM_BLACK_LIGHT) { mtmp->perminvis = TRUE; mtmp->minvis = TRUE; } break; case S_EEL: if (is_pool(x, y)) mtmp->mundetected = TRUE; break; case S_LEPRECHAUN: mtmp->msleeping = 1; break; case S_JABBERWOCK: case S_NYMPH: if (rn2(5) && !u.uhave.amulet) mtmp->msleeping = 1; break; case S_ORC: if (Race_if(PM_ELF)) mtmp->mpeaceful = FALSE; break; case S_UNICORN: if (is_unicorn(ptr) && sgn(u.ualign.type) == sgn(ptr->maligntyp)) mtmp->mpeaceful = TRUE; break; case S_BAT: if (Inhell && is_bat(ptr)) mon_adjust_speed(mtmp, 2, (struct obj *)0); break; } if ((ct = emits_light(mtmp->data)) > 0) new_light_source(mtmp->mx, mtmp->my, ct, LS_MONSTER, (genericptr_t)mtmp); mitem = 0; /* extra inventory item for this monster */ if ((mcham = pm_to_cham(mndx)) != CHAM_ORDINARY) { /* If you're protected with a ring, don't create * any shape-changing chameleons -dgk */ if (Protection_from_shape_changers) mtmp->cham = CHAM_ORDINARY; else { mtmp->cham = mcham; (void) newcham(mtmp, rndmonst(), FALSE, FALSE); } } else if (mndx == PM_WIZARD_OF_YENDOR) { mtmp->iswiz = TRUE; flags.no_of_wizards++; if (flags.no_of_wizards == 1 && Is_earthlevel(&u.uz)) mitem = SPE_DIG; } else if (mndx == PM_DJINNI) { flags.djinni_count++; } else if (mndx == PM_GHOST) { flags.ghost_count++; if (!(mmflags & MM_NONAME)) mtmp = christen_monst(mtmp, rndghostname()); } else if (mndx == PM_VLAD_THE_IMPALER) { mitem = CANDELABRUM_OF_INVOCATION; } else if (mndx == PM_CROESUS) { mitem = TWO_HANDED_SWORD; } else if (ptr->msound == MS_NEMESIS) { mitem = BELL_OF_OPENING; } else if (mndx == PM_PESTILENCE) { mitem = POT_SICKNESS; } if (mitem && allow_minvent) (void) mongets(mtmp, mitem); if(in_mklev) { if(((is_ndemon(ptr)) || (mndx == PM_WUMPUS) || (mndx == PM_LONG_WORM) || (mndx == PM_GIANT_EEL)) && !u.uhave.amulet && rn2(5)) mtmp->msleeping = TRUE; } else { if(byyou) { newsym(mtmp->mx,mtmp->my); set_apparxy(mtmp); } } if(is_dprince(ptr) && ptr->msound == MS_BRIBE) { mtmp->mpeaceful = mtmp->minvis = mtmp->perminvis = 1; mtmp->mavenge = 0; if (uwep && uwep->oartifact == ART_EXCALIBUR) mtmp->mpeaceful = mtmp->mtame = FALSE; } #ifndef DCC30_BUG if (mndx == PM_LONG_WORM && (mtmp->wormno = get_wormno()) != 0) #else /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the * same expression. */ if (mndx == PM_LONG_WORM && (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) #endif { /* we can now create worms with tails - 11/91 */ initworm(mtmp, rn2(5)); if (count_wsegs(mtmp)) place_worm_tail_randomly(mtmp, x, y); } set_malign(mtmp); /* having finished peaceful changes */ if(anymon) { if ((ptr->geno & G_SGROUP) && rn2(2)) { m_initsgrp(mtmp, mtmp->mx, mtmp->my); } else if (ptr->geno & G_LGROUP) { if(rn2(3)) m_initlgrp(mtmp, mtmp->mx, mtmp->my); else m_initsgrp(mtmp, mtmp->mx, mtmp->my); } } if (allow_minvent) { if(is_armed(ptr)) m_initweap(mtmp); /* equip with weapons / armor */ m_initinv(mtmp); /* add on a few special items incl. more armor */ m_dowear(mtmp, TRUE); } else { /* no initial inventory is allowed */ if (mtmp->minvent) discard_minvent(mtmp); mtmp->minvent = (struct obj *)0; /* caller expects this */ } if ((ptr->mflags3 & M3_WAITMASK) && !(mmflags & MM_NOWAIT)) { if (ptr->mflags3 & M3_WAITFORU) mtmp->mstrategy |= STRAT_WAITFORU; if (ptr->mflags3 & M3_CLOSE) mtmp->mstrategy |= STRAT_CLOSE; } if (!in_mklev) newsym(mtmp->mx,mtmp->my); /* make sure the mon shows up */ return(mtmp); } int mbirth_limit(mndx) int mndx; { /* assert(MAXMONNO < 255); */ return (mndx == PM_NAZGUL ? 9 : mndx == PM_ERINYS ? 3 : MAXMONNO); } /* used for wand/scroll/spell of create monster */ /* returns TRUE iff you know monsters have been created */ boolean create_critters(cnt, mptr) int cnt; struct permonst *mptr; /* usually null; used for confused reading */ { coord c; int x, y; struct monst *mon; boolean known = FALSE; #ifdef WIZARD boolean ask = wizard; #endif while (cnt--) { #ifdef WIZARD if (ask) { if (create_particular()) { known = TRUE; continue; } else ask = FALSE; /* ESC will shut off prompting */ } #endif x = u.ux, y = u.uy; /* if in water, try to encourage an aquatic monster by finding and then specifying another wet location */ if (!mptr && u.uinwater && enexto(&c, x, y, &mons[PM_GIANT_EEL])) x = c.x, y = c.y; mon = makemon(mptr, x, y, NO_MM_FLAGS); if (mon && canspotmon(mon)) known = TRUE; } return known; } #endif /* OVL1 */ #ifdef OVL0 STATIC_OVL boolean uncommon(mndx) int mndx; { if (mons[mndx].geno & (G_NOGEN | G_UNIQ)) return TRUE; if (mvitals[mndx].mvflags & G_GONE) return TRUE; if (Inhell) return(mons[mndx].maligntyp > A_NEUTRAL); else return((mons[mndx].geno & G_HELL) != 0); } /* * shift the probability of a monster's generation by * comparing the dungeon alignment and monster alignment. * return an integer in the range of 0-5. */ STATIC_OVL int align_shift(ptr) register struct permonst *ptr; { static NEARDATA long oldmoves = 0L; /* != 1, starting value of moves */ static NEARDATA s_level *lev; register int alshift; if(oldmoves != moves) { lev = Is_special(&u.uz); oldmoves = moves; } switch((lev) ? lev->flags.align : dungeons[u.uz.dnum].flags.align) { default: /* just in case */ case AM_NONE: alshift = 0; break; case AM_LAWFUL: alshift = (ptr->maligntyp+20)/(2*ALIGNWEIGHT); break; case AM_NEUTRAL: alshift = (20 - abs(ptr->maligntyp))/ALIGNWEIGHT; break; case AM_CHAOTIC: alshift = (-(ptr->maligntyp-20))/(2*ALIGNWEIGHT); break; } return alshift; } static NEARDATA struct { int choice_count; char mchoices[SPECIAL_PM]; /* value range is 0..127 */ } rndmonst_state = { -1, {0} }; /* select a random monster type */ struct permonst * rndmonst() { register struct permonst *ptr; register int mndx, ct; if (u.uz.dnum == quest_dnum && rn2(7) && (ptr = qt_montype()) != 0) return ptr; if (rndmonst_state.choice_count < 0) { /* need to recalculate */ int zlevel, minmlev, maxmlev; boolean elemlevel; #ifdef REINCARNATION boolean upper; #endif rndmonst_state.choice_count = 0; /* look for first common monster */ for (mndx = LOW_PM; mndx < SPECIAL_PM; mndx++) { if (!uncommon(mndx)) break; rndmonst_state.mchoices[mndx] = 0; } if (mndx == SPECIAL_PM) { /* evidently they've all been exterminated */ #ifdef DEBUG pline("rndmonst: no common mons!"); #endif return (struct permonst *)0; } /* else `mndx' now ready for use below */ zlevel = level_difficulty(); /* determine the level of the weakest monster to make. */ minmlev = zlevel / 6; /* determine the level of the strongest monster to make. */ maxmlev = (zlevel + u.ulevel) / 2; #ifdef REINCARNATION upper = Is_rogue_level(&u.uz); #endif elemlevel = In_endgame(&u.uz) && !Is_astralevel(&u.uz); /* * Find out how many monsters exist in the range we have selected. */ /* (`mndx' initialized above) */ for ( ; mndx < SPECIAL_PM; mndx++) { ptr = &mons[mndx]; rndmonst_state.mchoices[mndx] = 0; if (tooweak(mndx, minmlev) || toostrong(mndx, maxmlev)) continue; #ifdef REINCARNATION if (upper && !isupper(def_monsyms[(int)(ptr->mlet)])) continue; #endif if (elemlevel && wrong_elem_type(ptr)) continue; if (uncommon(mndx)) continue; if (Inhell && (ptr->geno & G_NOHELL)) continue; ct = (int)(ptr->geno & G_FREQ) + align_shift(ptr); if (ct < 0 || ct > 127) panic("rndmonst: bad count [#%d: %d]", mndx, ct); rndmonst_state.choice_count += ct; rndmonst_state.mchoices[mndx] = (char)ct; } /* * Possible modification: if choice_count is "too low", * expand minmlev..maxmlev range and try again. */ } /* choice_count+mchoices[] recalc */ if (rndmonst_state.choice_count <= 0) { /* maybe no common mons left, or all are too weak or too strong */ #ifdef DEBUG Norep("rndmonst: choice_count=%d", rndmonst_state.choice_count); #endif return (struct permonst *)0; } /* * Now, select a monster at random. */ ct = rnd(rndmonst_state.choice_count); for (mndx = LOW_PM; mndx < SPECIAL_PM; mndx++) if ((ct -= (int)rndmonst_state.mchoices[mndx]) <= 0) break; if (mndx == SPECIAL_PM || uncommon(mndx)) { /* shouldn't happen */ impossible("rndmonst: bad `mndx' [#%d]", mndx); return (struct permonst *)0; } return &mons[mndx]; } /* called when you change level (experience or dungeon depth) or when monster species can no longer be created (genocide or extinction) */ void reset_rndmonst(mndx) int mndx; /* particular species that can no longer be created */ { /* cached selection info is out of date */ if (mndx == NON_PM) { rndmonst_state.choice_count = -1; /* full recalc needed */ } else if (mndx < SPECIAL_PM) { rndmonst_state.choice_count -= rndmonst_state.mchoices[mndx]; rndmonst_state.mchoices[mndx] = 0; } /* note: safe to ignore extinction of unique monsters */ } #endif /* OVL0 */ #ifdef OVL1 /* The routine below is used to make one of the multiple types * of a given monster class. The second parameter specifies a * special casing bit mask to allow the normal genesis * masks to be deactivated. Returns 0 if no monsters * in that class can be made. */ struct permonst * mkclass(class,spc) char class; int spc; { register int first, last, num = 0; int maxmlev, mask = (G_NOGEN | G_UNIQ) & ~spc; maxmlev = level_difficulty() >> 1; if(class < 1 || class >= MAXMCLASSES) { impossible("mkclass called with bad class!"); return((struct permonst *) 0); } /* Assumption #1: monsters of a given class are contiguous in the * mons[] array. */ for (first = LOW_PM; first < SPECIAL_PM; first++) if (mons[first].mlet == class) break; if (first == SPECIAL_PM) return (struct permonst *) 0; for (last = first; last < SPECIAL_PM && mons[last].mlet == class; last++) if (!(mvitals[last].mvflags & G_GONE) && !(mons[last].geno & mask) && !is_placeholder(&mons[last])) { /* consider it */ if(num && toostrong(last, maxmlev) && monstr[last] != monstr[last-1] && rn2(2)) break; num += mons[last].geno & G_FREQ; } if(!num) return((struct permonst *) 0); /* Assumption #2: monsters of a given class are presented in ascending * order of strength. */ for(num = rnd(num); num > 0; first++) if (!(mvitals[first].mvflags & G_GONE) && !(mons[first].geno & mask) && !is_placeholder(&mons[first])) { /* skew towards lower value monsters at lower exp. levels */ num -= mons[first].geno & G_FREQ; if (num && adj_lev(&mons[first]) > (u.ulevel*2)) { /* but not when multiple monsters are same level */ if (mons[first].mlevel != mons[first+1].mlevel) num--; } } first--; /* correct an off-by-one error */ return(&mons[first]); } int adj_lev(ptr) /* adjust strength of monsters based on u.uz and u.ulevel */ register struct permonst *ptr; { int tmp, tmp2; if (ptr == &mons[PM_WIZARD_OF_YENDOR]) { /* does not depend on other strengths, but does get stronger * every time he is killed */ tmp = ptr->mlevel + mvitals[PM_WIZARD_OF_YENDOR].died; if (tmp > 49) tmp = 49; return tmp; } if((tmp = ptr->mlevel) > 49) return(50); /* "special" demons/devils */ tmp2 = (level_difficulty() - tmp); if(tmp2 < 0) tmp--; /* if mlevel > u.uz decrement tmp */ else tmp += (tmp2 / 5); /* else increment 1 per five diff */ tmp2 = (u.ulevel - ptr->mlevel); /* adjust vs. the player */ if(tmp2 > 0) tmp += (tmp2 / 4); /* level as well */ tmp2 = (3 * ((int) ptr->mlevel))/ 2; /* crude upper limit */ if (tmp2 > 49) tmp2 = 49; /* hard upper limit */ return((tmp > tmp2) ? tmp2 : (tmp > 0 ? tmp : 0)); /* 0 lower limit */ } #endif /* OVL1 */ #ifdef OVLB struct permonst * grow_up(mtmp, victim) /* `mtmp' might "grow up" into a bigger version */ struct monst *mtmp, *victim; { int oldtype, newtype, max_increase, cur_increase, lev_limit, hp_threshold; struct permonst *ptr = mtmp->data; /* monster died after killing enemy but before calling this function */ /* currently possible if killing a gas spore */ if (mtmp->mhp <= 0) return ((struct permonst *)0); /* note: none of the monsters with special hit point calculations have both little and big forms */ oldtype = monsndx(ptr); newtype = little_to_big(oldtype); if (newtype == PM_PRIEST && mtmp->female) newtype = PM_PRIESTESS; /* growth limits differ depending on method of advancement */ if (victim) { /* killed a monster */ /* * The HP threshold is the maximum number of hit points for the * current level; once exceeded, a level will be gained. * Possible bug: if somehow the hit points are already higher * than that, monster will gain a level without any increase in HP. */ hp_threshold = mtmp->m_lev * 8; /* normal limit */ if (!mtmp->m_lev) hp_threshold = 4; else if (is_golem(ptr)) /* strange creatures */ hp_threshold = ((mtmp->mhpmax / 10) + 1) * 10 - 1; else if (is_home_elemental(ptr)) hp_threshold *= 3; lev_limit = 3 * (int)ptr->mlevel / 2; /* same as adj_lev() */ /* If they can grow up, be sure the level is high enough for that */ if (oldtype != newtype && mons[newtype].mlevel > lev_limit) lev_limit = (int)mons[newtype].mlevel; /* number of hit points to gain; unlike for the player, we put the limit at the bottom of the next level rather than the top */ max_increase = rnd((int)victim->m_lev + 1); if (mtmp->mhpmax + max_increase > hp_threshold + 1) max_increase = max((hp_threshold + 1) - mtmp->mhpmax, 0); cur_increase = (max_increase > 1) ? rn2(max_increase) : 0; } else { /* a gain level potion or wraith corpse; always go up a level unless already at maximum (49 is hard upper limit except for demon lords, who start at 50 and can't go any higher) */ max_increase = cur_increase = rnd(8); hp_threshold = 0; /* smaller than `mhpmax + max_increase' */ lev_limit = 50; /* recalc below */ } mtmp->mhpmax += max_increase; mtmp->mhp += cur_increase; if (mtmp->mhpmax <= hp_threshold) return ptr; /* doesn't gain a level */ if (is_mplayer(ptr)) lev_limit = 30; /* same as player */ else if (lev_limit < 5) lev_limit = 5; /* arbitrary */ else if (lev_limit > 49) lev_limit = (ptr->mlevel > 49 ? 50 : 49); if ((int)++mtmp->m_lev >= mons[newtype].mlevel && newtype != oldtype) { ptr = &mons[newtype]; if (mvitals[newtype].mvflags & G_GENOD) { /* allow G_EXTINCT */ if (sensemon(mtmp)) pline("As %s grows up into %s, %s %s!", mon_nam(mtmp), an(ptr->mname), mhe(mtmp), nonliving(ptr) ? "expires" : "dies"); set_mon_data(mtmp, ptr, -1); /* keep mvitals[] accurate */ mondied(mtmp); return (struct permonst *)0; } set_mon_data(mtmp, ptr, 1); /* preserve intrinsics */ newsym(mtmp->mx, mtmp->my); /* color may change */ lev_limit = (int)mtmp->m_lev; /* never undo increment */ } /* sanity checks */ if ((int)mtmp->m_lev > lev_limit) { mtmp->m_lev--; /* undo increment */ /* HP might have been allowed to grow when it shouldn't */ if (mtmp->mhpmax == hp_threshold + 1) mtmp->mhpmax--; } if (mtmp->mhpmax > 50*8) mtmp->mhpmax = 50*8; /* absolute limit */ if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; return ptr; } #endif /* OVLB */ #ifdef OVL1 int mongets(mtmp, otyp) register struct monst *mtmp; register int otyp; { register struct obj *otmp; int spe; if (!otyp) return 0; otmp = mksobj(otyp, TRUE, FALSE); if (otmp) { if (mtmp->data->mlet == S_DEMON) { /* demons never get blessed objects */ if (otmp->blessed) curse(otmp); } else if(is_lminion(mtmp)) { /* lawful minions don't get cursed, bad, or rusting objects */ otmp->cursed = FALSE; if(otmp->spe < 0) otmp->spe = 0; otmp->oerodeproof = TRUE; } else if(is_mplayer(mtmp->data) && is_sword(otmp)) { otmp->spe = (3 + rn2(4)); } if(otmp->otyp == CANDELABRUM_OF_INVOCATION) { otmp->spe = 0; otmp->age = 0L; otmp->lamplit = FALSE; otmp->blessed = otmp->cursed = FALSE; } else if (otmp->otyp == BELL_OF_OPENING) { otmp->blessed = otmp->cursed = FALSE; } else if (otmp->otyp == SPE_BOOK_OF_THE_DEAD) { otmp->blessed = FALSE; otmp->cursed = TRUE; } /* leaders don't tolerate inferior quality battle gear */ if (is_prince(mtmp->data)) { if (otmp->oclass == WEAPON_CLASS && otmp->spe < 1) otmp->spe = 1; else if (otmp->oclass == ARMOR_CLASS && otmp->spe < 0) otmp->spe = 0; } spe = otmp->spe; (void) mpickobj(mtmp, otmp); /* might free otmp */ return(spe); } else return(0); } #endif /* OVL1 */ #ifdef OVLB int golemhp(type) int type; { switch(type) { case PM_STRAW_GOLEM: return 20; case PM_PAPER_GOLEM: return 20; case PM_ROPE_GOLEM: return 30; case PM_LEATHER_GOLEM: return 40; case PM_GOLD_GOLEM: return 40; case PM_WOOD_GOLEM: return 50; case PM_FLESH_GOLEM: return 40; case PM_CLAY_GOLEM: return 50; case PM_STONE_GOLEM: return 60; case PM_GLASS_GOLEM: return 60; case PM_IRON_GOLEM: return 80; default: return 0; } } #endif /* OVLB */ #ifdef OVL1 /* * Alignment vs. yours determines monster's attitude to you. * ( some "animal" types are co-aligned, but also hungry ) */ boolean peace_minded(ptr) register struct permonst *ptr; { aligntyp mal = ptr->maligntyp, ual = u.ualign.type; if (always_peaceful(ptr)) return TRUE; if (always_hostile(ptr)) return FALSE; if (ptr->msound == MS_LEADER || ptr->msound == MS_GUARDIAN) return TRUE; if (ptr->msound == MS_NEMESIS) return FALSE; if (race_peaceful(ptr)) return TRUE; if (race_hostile(ptr)) return FALSE; /* the monster is hostile if its alignment is different from the * player's */ if (sgn(mal) != sgn(ual)) return FALSE; /* Negative monster hostile to player with Amulet. */ if (mal < A_NEUTRAL && u.uhave.amulet) return FALSE; /* minions are hostile to players that have strayed at all */ if (is_minion(ptr)) return((boolean)(u.ualign.record >= 0)); /* Last case: a chance of a co-aligned monster being * hostile. This chance is greater if the player has strayed * (u.ualign.record negative) or the monster is not strongly aligned. */ return((boolean)(!!rn2(16 + (u.ualign.record < -15 ? -15 : u.ualign.record)) && !!rn2(2 + abs(mal)))); } /* Set malign to have the proper effect on player alignment if monster is * killed. Negative numbers mean it's bad to kill this monster; positive * numbers mean it's good. Since there are more hostile monsters than * peaceful monsters, the penalty for killing a peaceful monster should be * greater than the bonus for killing a hostile monster to maintain balance. * Rules: * it's bad to kill peaceful monsters, potentially worse to kill always- * peaceful monsters * it's never bad to kill a hostile monster, although it may not be good */ void set_malign(mtmp) struct monst *mtmp; { schar mal = mtmp->data->maligntyp; boolean coaligned; if (mtmp->ispriest || mtmp->isminion) { /* some monsters have individual alignments; check them */ if (mtmp->ispriest) mal = EPRI(mtmp)->shralign; else if (mtmp->isminion) mal = EMIN(mtmp)->min_align; /* unless alignment is none, set mal to -5,0,5 */ /* (see align.h for valid aligntyp values) */ if(mal != A_NONE) mal *= 5; } coaligned = (sgn(mal) == sgn(u.ualign.type)); if (mtmp->data->msound == MS_LEADER) { mtmp->malign = -20; } else if (mal == A_NONE) { if (mtmp->mpeaceful) mtmp->malign = 0; else mtmp->malign = 20; /* really hostile */ } else if (always_peaceful(mtmp->data)) { int absmal = abs(mal); if (mtmp->mpeaceful) mtmp->malign = -3*max(5,absmal); else mtmp->malign = 3*max(5,absmal); /* renegade */ } else if (always_hostile(mtmp->data)) { int absmal = abs(mal); if (coaligned) mtmp->malign = 0; else mtmp->malign = max(5,absmal); } else if (coaligned) { int absmal = abs(mal); if (mtmp->mpeaceful) mtmp->malign = -3*max(3,absmal); else /* renegade */ mtmp->malign = max(3,absmal); } else /* not coaligned and therefore hostile */ mtmp->malign = abs(mal); } #endif /* OVL1 */ #ifdef OVLB static NEARDATA char syms[] = { MAXOCLASSES, MAXOCLASSES+1, RING_CLASS, WAND_CLASS, WEAPON_CLASS, FOOD_CLASS, COIN_CLASS, SCROLL_CLASS, POTION_CLASS, ARMOR_CLASS, AMULET_CLASS, TOOL_CLASS, ROCK_CLASS, GEM_CLASS, SPBOOK_CLASS, S_MIMIC_DEF, S_MIMIC_DEF, S_MIMIC_DEF, }; void set_mimic_sym(mtmp) /* KAA, modified by ERS */ register struct monst *mtmp; { int typ, roomno, rt; unsigned appear, ap_type; int s_sym; struct obj *otmp; int mx, my; if (!mtmp) return; mx = mtmp->mx; my = mtmp->my; typ = levl[mx][my].typ; /* only valid for INSIDE of room */ roomno = levl[mx][my].roomno - ROOMOFFSET; if (roomno >= 0) rt = rooms[roomno].rtype; #ifdef SPECIALIZATION else if (IS_ROOM(typ)) rt = OROOM, roomno = 0; #endif else rt = 0; /* roomno < 0 case for GCC_WARN */ if (OBJ_AT(mx, my)) { ap_type = M_AP_OBJECT; appear = level.objects[mx][my]->otyp; } else if (IS_DOOR(typ) || IS_WALL(typ) || typ == SDOOR || typ == SCORR) { ap_type = M_AP_FURNITURE; /* * If there is a wall to the left that connects to this * location, then the mimic mimics a horizontal closed door. * This does not allow doors to be in corners of rooms. */ if (mx != 0 && (levl[mx-1][my].typ == HWALL || levl[mx-1][my].typ == TLCORNER || levl[mx-1][my].typ == TRWALL || levl[mx-1][my].typ == BLCORNER || levl[mx-1][my].typ == TDWALL || levl[mx-1][my].typ == CROSSWALL|| levl[mx-1][my].typ == TUWALL )) appear = S_hcdoor; else appear = S_vcdoor; if(!mtmp->minvis || See_invisible) block_point(mx,my); /* vision */ } else if (level.flags.is_maze_lev && rn2(2)) { ap_type = M_AP_OBJECT; appear = STATUE; } else if (roomno < 0) { ap_type = M_AP_OBJECT; appear = BOULDER; if(!mtmp->minvis || See_invisible) block_point(mx,my); /* vision */ } else if (rt == ZOO || rt == VAULT) { ap_type = M_AP_OBJECT; appear = GOLD_PIECE; } else if (rt == DELPHI) { if (rn2(2)) { ap_type = M_AP_OBJECT; appear = STATUE; } else { ap_type = M_AP_FURNITURE; appear = S_fountain; } } else if (rt == TEMPLE) { ap_type = M_AP_FURNITURE; appear = S_altar; /* * We won't bother with beehives, morgues, barracks, throne rooms * since they shouldn't contain too many mimics anyway... */ } else if (rt >= SHOPBASE) { s_sym = get_shop_item(rt - SHOPBASE); if (s_sym < 0) { ap_type = M_AP_OBJECT; appear = -s_sym; } else { if (s_sym == RANDOM_CLASS) s_sym = syms[rn2((int)sizeof(syms)-2) + 2]; goto assign_sym; } } else { s_sym = syms[rn2((int)sizeof(syms))]; assign_sym: if (s_sym >= MAXOCLASSES) { ap_type = M_AP_FURNITURE; appear = s_sym == MAXOCLASSES ? S_upstair : S_dnstair; } else if (s_sym == COIN_CLASS) { ap_type = M_AP_OBJECT; appear = GOLD_PIECE; } else { ap_type = M_AP_OBJECT; if (s_sym == S_MIMIC_DEF) { appear = STRANGE_OBJECT; } else { otmp = mkobj( (char) s_sym, FALSE ); appear = otmp->otyp; /* make sure container contents are free'ed */ obfree(otmp, (struct obj *) 0); } } } mtmp->m_ap_type = ap_type; mtmp->mappearance = appear; } /* release a monster from a bag of tricks */ void bagotricks(bag) struct obj *bag; { if (!bag || bag->otyp != BAG_OF_TRICKS) { impossible("bad bag o' tricks"); } else if (bag->spe < 1) { pline(nothing_happens); } else { boolean gotone = FALSE; int cnt = 1; consume_obj_charge(bag, TRUE); if (!rn2(23)) cnt += rn1(7, 1); while (cnt-- > 0) { if (makemon((struct permonst *)0, u.ux, u.uy, NO_MM_FLAGS)) gotone = TRUE; } if (gotone) makeknown(BAG_OF_TRICKS); } } #endif /* OVLB */ /*makemon.c*/ nethack-3.4.3/src/mapglyph.c0100644000000000000000000001577207764735041014442 0ustar rootroot/* SCCS Id: @(#)mapglyph.c 3.4 2003/01/08 */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #if defined(TTY_GRAPHICS) #include "wintty.h" /* for prototype of has_color() only */ #endif #include "color.h" #define HI_DOMESTIC CLR_WHITE /* monst.c */ int explcolors[] = { CLR_BLACK, /* dark */ CLR_GREEN, /* noxious */ CLR_BROWN, /* muddy */ CLR_BLUE, /* wet */ CLR_MAGENTA, /* magical */ CLR_ORANGE, /* fiery */ CLR_WHITE, /* frosty */ }; #if !defined(TTY_GRAPHICS) #define has_color(n) TRUE #endif #ifdef TEXTCOLOR #define zap_color(n) color = iflags.use_color ? zapcolors[n] : NO_COLOR #define cmap_color(n) color = iflags.use_color ? defsyms[n].color : NO_COLOR #define obj_color(n) color = iflags.use_color ? objects[n].oc_color : NO_COLOR #define mon_color(n) color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define invis_color(n) color = NO_COLOR #define pet_color(n) color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define warn_color(n) color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR #define explode_color(n) color = iflags.use_color ? explcolors[n] : NO_COLOR # if defined(REINCARNATION) && defined(ASCIIGRAPH) # define ROGUE_COLOR # endif #else /* no text color */ #define zap_color(n) #define cmap_color(n) #define obj_color(n) #define mon_color(n) #define invis_color(n) #define pet_color(c) #define warn_color(n) #define explode_color(n) #endif #ifdef ROGUE_COLOR # if defined(USE_TILES) && defined(MSDOS) #define HAS_ROGUE_IBM_GRAPHICS (iflags.IBMgraphics && !iflags.grmode && \ Is_rogue_level(&u.uz)) # else #define HAS_ROGUE_IBM_GRAPHICS (iflags.IBMgraphics && Is_rogue_level(&u.uz)) # endif #endif /*ARGSUSED*/ void mapglyph(glyph, ochar, ocolor, ospecial, x, y) int glyph, *ocolor, x, y; int *ochar; unsigned *ospecial; { register int offset; #if defined(TEXTCOLOR) || defined(ROGUE_COLOR) int color = NO_COLOR; #endif uchar ch; unsigned special = 0; /* * Map the glyph back to a character and color. * * Warning: For speed, this makes an assumption on the order of * offsets. The order is set in display.h. */ if ((offset = (glyph - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */ ch = warnsyms[offset]; # ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS) color = NO_COLOR; else # endif warn_color(offset); } else if ((offset = (glyph - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */ /* see swallow_to_glyph() in display.c */ ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) color = NO_COLOR; else #endif mon_color(offset >> 3); } else if ((offset = (glyph - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */ /* see zapdir_to_glyph() in display.c */ ch = showsyms[S_vbeam + (offset & 0x3)]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) color = NO_COLOR; else #endif zap_color((offset >> 2)); } else if ((offset = (glyph - GLYPH_EXPLODE_OFF)) >= 0) { /* explosion */ ch = showsyms[(offset % MAXEXPCHARS) + S_explode1]; explode_color(offset / MAXEXPCHARS); } else if ((offset = (glyph - GLYPH_CMAP_OFF)) >= 0) { /* cmap */ ch = showsyms[offset]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) { if (offset >= S_vwall && offset <= S_hcdoor) color = CLR_BROWN; else if (offset >= S_arrow_trap && offset <= S_polymorph_trap) color = CLR_MAGENTA; else if (offset == S_corr || offset == S_litcorr) color = CLR_GRAY; else if (offset >= S_room && offset <= S_water) color = CLR_GREEN; else color = NO_COLOR; } else #endif #ifdef TEXTCOLOR /* provide a visible difference if normal and lit corridor * use the same symbol */ if (iflags.use_color && offset == S_litcorr && ch == showsyms[S_corr]) color = CLR_WHITE; else #endif cmap_color(offset); } else if ((offset = (glyph - GLYPH_OBJ_OFF)) >= 0) { /* object */ if (offset == BOULDER && iflags.bouldersym) ch = iflags.bouldersym; else ch = oc_syms[(int)objects[offset].oc_class]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) { switch(objects[offset].oc_class) { case COIN_CLASS: color = CLR_YELLOW; break; case FOOD_CLASS: color = CLR_RED; break; default: color = CLR_BRIGHT_BLUE; break; } } else #endif obj_color(offset); } else if ((offset = (glyph - GLYPH_RIDDEN_OFF)) >= 0) { /* mon ridden */ ch = monsyms[(int)mons[offset].mlet]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS) /* This currently implies that the hero is here -- monsters */ /* don't ride (yet...). Should we set it to yellow like in */ /* the monster case below? There is no equivalent in rogue. */ color = NO_COLOR; /* no need to check iflags.use_color */ else #endif mon_color(offset); special |= MG_RIDDEN; } else if ((offset = (glyph - GLYPH_BODY_OFF)) >= 0) { /* a corpse */ ch = oc_syms[(int)objects[CORPSE].oc_class]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) color = CLR_RED; else #endif mon_color(offset); special |= MG_CORPSE; } else if ((offset = (glyph - GLYPH_DETECT_OFF)) >= 0) { /* mon detect */ ch = monsyms[(int)mons[offset].mlet]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS) color = NO_COLOR; /* no need to check iflags.use_color */ else #endif mon_color(offset); /* Disabled for now; anyone want to get reverse video to work? */ /* is_reverse = TRUE; */ special |= MG_DETECT; } else if ((offset = (glyph - GLYPH_INVIS_OFF)) >= 0) { /* invisible */ ch = DEF_INVISIBLE; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS) color = NO_COLOR; /* no need to check iflags.use_color */ else #endif invis_color(offset); special |= MG_INVIS; } else if ((offset = (glyph - GLYPH_PET_OFF)) >= 0) { /* a pet */ ch = monsyms[(int)mons[offset].mlet]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS) color = NO_COLOR; /* no need to check iflags.use_color */ else #endif pet_color(offset); special |= MG_PET; } else { /* a monster */ ch = monsyms[(int)mons[glyph].mlet]; #ifdef ROGUE_COLOR if (HAS_ROGUE_IBM_GRAPHICS && iflags.use_color) { if (x == u.ux && y == u.uy) /* actually player should be yellow-on-gray if in a corridor */ color = CLR_YELLOW; else color = NO_COLOR; } else #endif { mon_color(glyph); /* special case the hero for `showrace' option */ #ifdef TEXTCOLOR if (iflags.use_color && x == u.ux && y == u.uy && iflags.showrace && !Upolyd) color = HI_DOMESTIC; #endif } } #ifdef TEXTCOLOR /* Turn off color if no color defined, or rogue level w/o PC graphics. */ # ifdef REINCARNATION # ifdef ASCIIGRAPH if (!has_color(color) || (Is_rogue_level(&u.uz) && !HAS_ROGUE_IBM_GRAPHICS)) # else if (!has_color(color) || Is_rogue_level(&u.uz)) # endif # else if (!has_color(color)) # endif color = NO_COLOR; #endif *ochar = (int)ch; *ospecial = special; #ifdef TEXTCOLOR *ocolor = color; #endif return; } /*mapglyph.c*/ nethack-3.4.3/src/mcastu.c0100644000000000000000000005225207764735041014107 0ustar rootroot/* SCCS Id: @(#)mcastu.c 3.4 2003/01/08 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* monster mage spells */ #define MGC_PSI_BOLT 0 #define MGC_CURE_SELF 1 #define MGC_HASTE_SELF 2 #define MGC_STUN_YOU 3 #define MGC_DISAPPEAR 4 #define MGC_WEAKEN_YOU 5 #define MGC_DESTRY_ARMR 6 #define MGC_CURSE_ITEMS 7 #define MGC_AGGRAVATION 8 #define MGC_SUMMON_MONS 9 #define MGC_CLONE_WIZ 10 #define MGC_DEATH_TOUCH 11 /* monster cleric spells */ #define CLC_OPEN_WOUNDS 0 #define CLC_CURE_SELF 1 #define CLC_CONFUSE_YOU 2 #define CLC_PARALYZE 3 #define CLC_BLIND_YOU 4 #define CLC_INSECTS 5 #define CLC_CURSE_ITEMS 6 #define CLC_LIGHTNING 7 #define CLC_FIRE_PILLAR 8 #define CLC_GEYSER 9 STATIC_DCL void FDECL(cursetxt,(struct monst *,BOOLEAN_P)); STATIC_DCL int FDECL(choose_magic_spell, (int)); STATIC_DCL int FDECL(choose_clerical_spell, (int)); STATIC_DCL void FDECL(cast_wizard_spell,(struct monst *, int,int)); STATIC_DCL void FDECL(cast_cleric_spell,(struct monst *, int,int)); STATIC_DCL boolean FDECL(is_undirected_spell,(unsigned int,int)); STATIC_DCL boolean FDECL(spell_would_be_useless,(struct monst *,unsigned int,int)); #ifdef OVL0 extern const char * const flash_types[]; /* from zap.c */ /* feedback when frustrated monster couldn't cast a spell */ STATIC_OVL void cursetxt(mtmp, undirected) struct monst *mtmp; boolean undirected; { if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) { const char *point_msg; /* spellcasting monsters are impolite */ if (undirected) point_msg = "all around, then curses"; else if ((Invis && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) || (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == STRANGE_OBJECT) || u.uundetected) point_msg = "and curses in your general direction"; else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) point_msg = "and curses at your displaced image"; else point_msg = "at you, then curses"; pline("%s points %s.", Monnam(mtmp), point_msg); } else if ((!(moves % 4) || !rn2(4))) { if (flags.soundok) Norep("You hear a mumbled curse."); } } #endif /* OVL0 */ #ifdef OVLB /* convert a level based random selection into a specific mage spell; inappropriate choices will be screened out by spell_would_be_useless() */ STATIC_OVL int choose_magic_spell(spellval) int spellval; { switch (spellval) { case 22: case 21: case 20: return MGC_DEATH_TOUCH; case 19: case 18: return MGC_CLONE_WIZ; case 17: case 16: case 15: return MGC_SUMMON_MONS; case 14: case 13: return MGC_AGGRAVATION; case 12: case 11: case 10: return MGC_CURSE_ITEMS; case 9: case 8: return MGC_DESTRY_ARMR; case 7: case 6: return MGC_WEAKEN_YOU; case 5: case 4: return MGC_DISAPPEAR; case 3: return MGC_STUN_YOU; case 2: return MGC_HASTE_SELF; case 1: return MGC_CURE_SELF; case 0: default: return MGC_PSI_BOLT; } } /* convert a level based random selection into a specific cleric spell */ STATIC_OVL int choose_clerical_spell(spellnum) int spellnum; { switch (spellnum) { case 13: return CLC_GEYSER; case 12: return CLC_FIRE_PILLAR; case 11: return CLC_LIGHTNING; case 10: case 9: return CLC_CURSE_ITEMS; case 8: return CLC_INSECTS; case 7: case 6: return CLC_BLIND_YOU; case 5: case 4: return CLC_PARALYZE; case 3: case 2: return CLC_CONFUSE_YOU; case 1: return CLC_CURE_SELF; case 0: default: return CLC_OPEN_WOUNDS; } } /* return values: * 1: successful spell * 0: unsuccessful spell */ int castmu(mtmp, mattk, thinks_it_foundyou, foundyou) register struct monst *mtmp; register struct attack *mattk; boolean thinks_it_foundyou; boolean foundyou; { int dmg, ml = mtmp->m_lev; int ret; int spellnum = 0; /* Three cases: * -- monster is attacking you. Search for a useful spell. * -- monster thinks it's attacking you. Search for a useful spell, * without checking for undirected. If the spell found is directed, * it fails with cursetxt() and loss of mspec_used. * -- monster isn't trying to attack. Select a spell once. Don't keep * searching; if that spell is not useful (or if it's directed), * return and do something else. * Since most spells are directed, this means that a monster that isn't * attacking casts spells only a small portion of the time that an * attacking monster does. */ if ((mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) && ml) { int cnt = 40; do { spellnum = rn2(ml); if (mattk->adtyp == AD_SPEL) spellnum = choose_magic_spell(spellnum); else spellnum = choose_clerical_spell(spellnum); /* not trying to attack? don't allow directed spells */ if (!thinks_it_foundyou) { if (!is_undirected_spell(mattk->adtyp, spellnum) || spell_would_be_useless(mtmp, mattk->adtyp, spellnum)) { if (foundyou) impossible("spellcasting monster found you and doesn't know it?"); return 0; } break; } } while(--cnt > 0 && spell_would_be_useless(mtmp, mattk->adtyp, spellnum)); if (cnt == 0) return 0; } /* monster unable to cast spells? */ if(mtmp->mcan || mtmp->mspec_used || !ml) { cursetxt(mtmp, is_undirected_spell(mattk->adtyp, spellnum)); return(0); } if (mattk->adtyp == AD_SPEL || mattk->adtyp == AD_CLRC) { mtmp->mspec_used = 10 - mtmp->m_lev; if (mtmp->mspec_used < 2) mtmp->mspec_used = 2; } /* monster can cast spells, but is casting a directed spell at the wrong place? If so, give a message, and return. Do this *after* penalizing mspec_used. */ if (!foundyou && thinks_it_foundyou && !is_undirected_spell(mattk->adtyp, spellnum)) { pline("%s casts a spell at %s!", canseemon(mtmp) ? Monnam(mtmp) : "Something", levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water" : "thin air"); return(0); } nomul(0); if(rn2(ml*10) < (mtmp->mconf ? 100 : 20)) { /* fumbled attack */ if (canseemon(mtmp) && flags.soundok) pline_The("air crackles around %s.", mon_nam(mtmp)); return(0); } if (canspotmon(mtmp) || !is_undirected_spell(mattk->adtyp, spellnum)) { pline("%s casts a spell%s!", canspotmon(mtmp) ? Monnam(mtmp) : "Something", is_undirected_spell(mattk->adtyp, spellnum) ? "" : (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? " at a spot near you" : (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) ? " at your displaced image" : " at you"); } /* * As these are spells, the damage is related to the level * of the monster casting the spell. */ if (!foundyou) { dmg = 0; if (mattk->adtyp != AD_SPEL && mattk->adtyp != AD_CLRC) { impossible( "%s casting non-hand-to-hand version of hand-to-hand spell %d?", Monnam(mtmp), mattk->adtyp); return(0); } } else if (mattk->damd) dmg = d((int)((ml/2) + mattk->damn), (int)mattk->damd); else dmg = d((int)((ml/2) + 1), 6); if (Half_spell_damage) dmg = (dmg+1) / 2; ret = 1; switch (mattk->adtyp) { case AD_FIRE: pline("You're enveloped in flames."); if(Fire_resistance) { shieldeff(u.ux, u.uy); pline("But you resist the effects."); dmg = 0; } burn_away_slime(); break; case AD_COLD: pline("You're covered in frost."); if(Cold_resistance) { shieldeff(u.ux, u.uy); pline("But you resist the effects."); dmg = 0; } break; case AD_MAGM: You("are hit by a shower of missiles!"); if(Antimagic) { shieldeff(u.ux, u.uy); pline_The("missiles bounce off!"); dmg = 0; } else dmg = d((int)mtmp->m_lev/2 + 1,6); break; case AD_SPEL: /* wizard spell */ case AD_CLRC: /* clerical spell */ { if (mattk->adtyp == AD_SPEL) cast_wizard_spell(mtmp, dmg, spellnum); else cast_cleric_spell(mtmp, dmg, spellnum); dmg = 0; /* done by the spell casting functions */ break; } } if(dmg) mdamageu(mtmp, dmg); return(ret); } /* monster wizard and cleric spellcasting functions */ /* If dmg is zero, then the monster is not casting at you. If the monster is intentionally not casting at you, we have previously called spell_would_be_useless() and spellnum should always be a valid undirected spell. If you modify either of these, be sure to change is_undirected_spell() and spell_would_be_useless(). */ STATIC_OVL void cast_wizard_spell(mtmp, dmg, spellnum) struct monst *mtmp; int dmg; int spellnum; { if (dmg == 0 && !is_undirected_spell(AD_SPEL, spellnum)) { impossible("cast directed wizard spell (%d) with dmg=0?", spellnum); return; } switch (spellnum) { case MGC_DEATH_TOUCH: pline("Oh no, %s's using the touch of death!", mhe(mtmp)); if (nonliving(youmonst.data) || is_demon(youmonst.data)) { You("seem no deader than before."); } else if (!Antimagic && rn2(mtmp->m_lev) > 12) { if (Hallucination) { You("have an out of body experience."); } else { killer_format = KILLED_BY_AN; killer = "touch of death"; done(DIED); } } else { if (Antimagic) shieldeff(u.ux, u.uy); pline("Lucky for you, it didn't work!"); } dmg = 0; break; case MGC_CLONE_WIZ: if (mtmp->iswiz && flags.no_of_wizards == 1) { pline("Double Trouble..."); clonewiz(); dmg = 0; } else impossible("bad wizard cloning?"); break; case MGC_SUMMON_MONS: { int count; count = nasty(mtmp); /* summon something nasty */ if (mtmp->iswiz) verbalize("Destroy the thief, my pet%s!", plur(count)); else { const char *mappear = (count == 1) ? "A monster appears" : "Monsters appear"; /* messages not quite right if plural monsters created but only a single monster is seen */ if (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around a spot near you!", mappear); else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s around your displaced image!", mappear); else pline("%s from nowhere!", mappear); } dmg = 0; break; } case MGC_AGGRAVATION: You_feel("that monsters are aware of your presence."); aggravate(); dmg = 0; break; case MGC_CURSE_ITEMS: You_feel("as if you need some help."); rndcurse(); dmg = 0; break; case MGC_DESTRY_ARMR: if (Antimagic) { shieldeff(u.ux, u.uy); pline("A field of force surrounds you!"); } else if (!destroy_arm(some_armor(&youmonst))) { Your("skin itches."); } dmg = 0; break; case MGC_WEAKEN_YOU: /* drain strength */ if (Antimagic) { shieldeff(u.ux, u.uy); You_feel("momentarily weakened."); } else { You("suddenly feel weaker!"); dmg = mtmp->m_lev - 6; if (Half_spell_damage) dmg = (dmg + 1) / 2; losestr(rnd(dmg)); if (u.uhp < 1) done_in_by(mtmp); } dmg = 0; break; case MGC_DISAPPEAR: /* makes self invisible */ if (!mtmp->minvis && !mtmp->invis_blkd) { if (canseemon(mtmp)) pline("%s suddenly %s!", Monnam(mtmp), !See_invisible ? "disappears" : "becomes transparent"); mon_set_minvis(mtmp); dmg = 0; } else impossible("no reason for monster to cast disappear spell?"); break; case MGC_STUN_YOU: if (Antimagic || Free_action) { shieldeff(u.ux, u.uy); if (!Stunned) You_feel("momentarily disoriented."); make_stunned(1L, FALSE); } else { You(Stunned ? "struggle to keep your balance." : "reel..."); dmg = d(ACURR(A_DEX) < 12 ? 6 : 4, 4); if (Half_spell_damage) dmg = (dmg + 1) / 2; make_stunned(HStun + dmg, FALSE); } dmg = 0; break; case MGC_HASTE_SELF: mon_adjust_speed(mtmp, 1, (struct obj *)0); dmg = 0; break; case MGC_CURE_SELF: if (mtmp->mhp < mtmp->mhpmax) { if (canseemon(mtmp)) pline("%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ if ((mtmp->mhp += d(3,6)) > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; dmg = 0; } break; case MGC_PSI_BOLT: /* prior to 3.4.0 Antimagic was setting the damage to 1--this made the spell virtually harmless to players with magic res. */ if (Antimagic) { shieldeff(u.ux, u.uy); dmg = (dmg + 1) / 2; } if (dmg <= 5) You("get a slight %sache.", body_part(HEAD)); else if (dmg <= 10) Your("brain is on fire!"); else if (dmg <= 20) Your("%s suddenly aches painfully!", body_part(HEAD)); else Your("%s suddenly aches very painfully!", body_part(HEAD)); break; default: impossible("mcastu: invalid magic spell (%d)", spellnum); dmg = 0; break; } if (dmg) mdamageu(mtmp, dmg); } STATIC_OVL void cast_cleric_spell(mtmp, dmg, spellnum) struct monst *mtmp; int dmg; int spellnum; { if (dmg == 0 && !is_undirected_spell(AD_CLRC, spellnum)) { impossible("cast directed cleric spell (%d) with dmg=0?", spellnum); return; } switch (spellnum) { case CLC_GEYSER: /* this is physical damage, not magical damage */ pline("A sudden geyser slams into you from nowhere!"); dmg = d(8, 6); if (Half_physical_damage) dmg = (dmg + 1) / 2; break; case CLC_FIRE_PILLAR: pline("A pillar of fire strikes all around you!"); if (Fire_resistance) { shieldeff(u.ux, u.uy); dmg = 0; } else dmg = d(8, 6); if (Half_spell_damage) dmg = (dmg + 1) / 2; burn_away_slime(); (void) burnarmor(&youmonst); destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); (void) burn_floor_paper(u.ux, u.uy, TRUE, FALSE); break; case CLC_LIGHTNING: { boolean reflects; pline("A bolt of lightning strikes down at you from above!"); reflects = ureflects("It bounces off your %s%s.", ""); if (reflects || Shock_resistance) { shieldeff(u.ux, u.uy); dmg = 0; if (reflects) break; } else dmg = d(8, 6); if (Half_spell_damage) dmg = (dmg + 1) / 2; destroy_item(WAND_CLASS, AD_ELEC); destroy_item(RING_CLASS, AD_ELEC); break; } case CLC_CURSE_ITEMS: You_feel("as if you need some help."); rndcurse(); dmg = 0; break; case CLC_INSECTS: { /* Try for insects, and if there are none left, go for (sticks to) snakes. -3. */ struct permonst *pm = mkclass(S_ANT,0); struct monst *mtmp2 = (struct monst *)0; char let = (pm ? S_ANT : S_SNAKE); boolean success; int i; coord bypos; int quan; quan = (mtmp->m_lev < 2) ? 1 : rnd((int)mtmp->m_lev / 2); if (quan < 3) quan = 3; success = pm ? TRUE : FALSE; for (i = 0; i <= quan; i++) { if (!enexto(&bypos, mtmp->mux, mtmp->muy, mtmp->data)) break; if ((pm = mkclass(let,0)) != 0 && (mtmp2 = makemon(pm, bypos.x, bypos.y, NO_MM_FLAGS)) != 0) { success = TRUE; mtmp2->msleeping = mtmp2->mpeaceful = mtmp2->mtame = 0; set_malign(mtmp2); } } /* Not quite right: * -- message doesn't always make sense for unseen caster (particularly * the first message) * -- message assumes plural monsters summoned (non-plural should be * very rare, unlike in nasty()) * -- message assumes plural monsters seen */ if (!success) pline("%s casts at a clump of sticks, but nothing happens.", Monnam(mtmp)); else if (let == S_SNAKE) pline("%s transforms a clump of sticks into snakes!", Monnam(mtmp)); else if (Invisible && !perceives(mtmp->data) && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s summons insects around a spot near you!", Monnam(mtmp)); else if (Displaced && (mtmp->mux != u.ux || mtmp->muy != u.uy)) pline("%s summons insects around your displaced image!", Monnam(mtmp)); else pline("%s summons insects!", Monnam(mtmp)); dmg = 0; break; } case CLC_BLIND_YOU: /* note: resists_blnd() doesn't apply here */ if (!Blinded) { int num_eyes = eyecount(youmonst.data); pline("Scales cover your %s!", (num_eyes == 1) ? body_part(EYE) : makeplural(body_part(EYE))); make_blinded(Half_spell_damage ? 100L : 200L, FALSE); if (!Blind) Your(vision_clears); dmg = 0; } else impossible("no reason for monster to cast blindness spell?"); break; case CLC_PARALYZE: if (Antimagic || Free_action) { shieldeff(u.ux, u.uy); if (multi >= 0) You("stiffen briefly."); nomul(-1); } else { if (multi >= 0) You("are frozen in place!"); dmg = 4 + (int)mtmp->m_lev; if (Half_spell_damage) dmg = (dmg + 1) / 2; nomul(-dmg); } dmg = 0; break; case CLC_CONFUSE_YOU: if (Antimagic) { shieldeff(u.ux, u.uy); You_feel("momentarily dizzy."); } else { boolean oldprop = !!Confusion; dmg = (int)mtmp->m_lev; if (Half_spell_damage) dmg = (dmg + 1) / 2; make_confused(HConfusion + dmg, TRUE); if (Hallucination) You_feel("%s!", oldprop ? "trippier" : "trippy"); else You_feel("%sconfused!", oldprop ? "more " : ""); } dmg = 0; break; case CLC_CURE_SELF: if (mtmp->mhp < mtmp->mhpmax) { if (canseemon(mtmp)) pline("%s looks better.", Monnam(mtmp)); /* note: player healing does 6d4; this used to do 1d8 */ if ((mtmp->mhp += d(3,6)) > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; dmg = 0; } break; case CLC_OPEN_WOUNDS: if (Antimagic) { shieldeff(u.ux, u.uy); dmg = (dmg + 1) / 2; } if (dmg <= 5) Your("skin itches badly for a moment."); else if (dmg <= 10) pline("Wounds appear on your body!"); else if (dmg <= 20) pline("Severe wounds appear on your body!"); else Your("body is covered with painful wounds!"); break; default: impossible("mcastu: invalid clerical spell (%d)", spellnum); dmg = 0; break; } if (dmg) mdamageu(mtmp, dmg); } STATIC_DCL boolean is_undirected_spell(adtyp, spellnum) unsigned int adtyp; int spellnum; { if (adtyp == AD_SPEL) { switch (spellnum) { case MGC_CLONE_WIZ: case MGC_SUMMON_MONS: case MGC_AGGRAVATION: case MGC_DISAPPEAR: case MGC_HASTE_SELF: case MGC_CURE_SELF: return TRUE; default: break; } } else if (adtyp == AD_CLRC) { switch (spellnum) { case CLC_INSECTS: case CLC_CURE_SELF: return TRUE; default: break; } } return FALSE; } /* Some spells are useless under some circumstances. */ STATIC_DCL boolean spell_would_be_useless(mtmp, adtyp, spellnum) struct monst *mtmp; unsigned int adtyp; int spellnum; { /* Some spells don't require the player to really be there and can be cast * by the monster when you're invisible, yet still shouldn't be cast when * the monster doesn't even think you're there. * This check isn't quite right because it always uses your real position. * We really want something like "if the monster could see mux, muy". */ boolean mcouldseeu = couldsee(mtmp->mx, mtmp->my); if (adtyp == AD_SPEL) { /* aggravate monsters, etc. won't be cast by peaceful monsters */ if (mtmp->mpeaceful && (spellnum == MGC_AGGRAVATION || spellnum == MGC_SUMMON_MONS || spellnum == MGC_CLONE_WIZ)) return TRUE; /* haste self when already fast */ if (mtmp->permspeed == MFAST && spellnum == MGC_HASTE_SELF) return TRUE; /* invisibility when already invisible */ if ((mtmp->minvis || mtmp->invis_blkd) && spellnum == MGC_DISAPPEAR) return TRUE; /* peaceful monster won't cast invisibility if you can't see invisible, same as when monsters drink potions of invisibility. This doesn't really make a lot of sense, but lets the player avoid hitting peaceful monsters by mistake */ if (mtmp->mpeaceful && !See_invisible && spellnum == MGC_DISAPPEAR) return TRUE; /* healing when already healed */ if (mtmp->mhp == mtmp->mhpmax && spellnum == MGC_CURE_SELF) return TRUE; /* don't summon monsters if it doesn't think you're around */ if (!mcouldseeu && (spellnum == MGC_SUMMON_MONS || (!mtmp->iswiz && spellnum == MGC_CLONE_WIZ))) return TRUE; if ((!mtmp->iswiz || flags.no_of_wizards > 1) && spellnum == MGC_CLONE_WIZ) return TRUE; } else if (adtyp == AD_CLRC) { /* summon insects/sticks to snakes won't be cast by peaceful monsters */ if (mtmp->mpeaceful && spellnum == CLC_INSECTS) return TRUE; /* healing when already healed */ if (mtmp->mhp == mtmp->mhpmax && spellnum == CLC_CURE_SELF) return TRUE; /* don't summon insects if it doesn't think you're around */ if (!mcouldseeu && spellnum == CLC_INSECTS) return TRUE; /* blindness spell on blinded player */ if (Blinded && spellnum == CLC_BLIND_YOU) return TRUE; } return FALSE; } #endif /* OVLB */ #ifdef OVL0 /* convert 1..10 to 0..9; add 10 for second group (spell casting) */ #define ad_to_typ(k) (10 + (int)k - 1) int buzzmu(mtmp, mattk) /* monster uses spell (ranged) */ register struct monst *mtmp; register struct attack *mattk; { /* don't print constant stream of curse messages for 'normal' spellcasting monsters at range */ if (mattk->adtyp > AD_SPC2) return(0); if (mtmp->mcan) { cursetxt(mtmp, FALSE); return(0); } if(lined_up(mtmp) && rn2(3)) { nomul(0); if(mattk->adtyp && (mattk->adtyp < 11)) { /* no cf unsigned >0 */ if(canseemon(mtmp)) pline("%s zaps you with a %s!", Monnam(mtmp), flash_types[ad_to_typ(mattk->adtyp)]); buzz(-ad_to_typ(mattk->adtyp), (int)mattk->damn, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); } else impossible("Monster spell %d cast", mattk->adtyp-1); } return(1); } #endif /* OVL0 */ /*mcastu.c*/ nethack-3.4.3/src/mhitm.c0100644000000000000000000011666407764735041013741 0ustar rootroot/* SCCS Id: @(#)mhitm.c 3.4 2003/01/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "artifact.h" #include "edog.h" extern boolean notonhead; #ifdef OVLB static NEARDATA boolean vis, far_noise; static NEARDATA long noisetime; static NEARDATA struct obj *otmp; static const char brief_feeling[] = "have a %s feeling for a moment, then it passes."; STATIC_DCL char *FDECL(mon_nam_too, (char *,struct monst *,struct monst *)); STATIC_DCL void FDECL(mrustm, (struct monst *, struct monst *, struct obj *)); STATIC_DCL int FDECL(hitmm, (struct monst *,struct monst *,struct attack *)); STATIC_DCL int FDECL(gazemm, (struct monst *,struct monst *,struct attack *)); STATIC_DCL int FDECL(gulpmm, (struct monst *,struct monst *,struct attack *)); STATIC_DCL int FDECL(explmm, (struct monst *,struct monst *,struct attack *)); STATIC_DCL int FDECL(mdamagem, (struct monst *,struct monst *,struct attack *)); STATIC_DCL void FDECL(mswingsm, (struct monst *, struct monst *, struct obj *)); STATIC_DCL void FDECL(noises,(struct monst *,struct attack *)); STATIC_DCL void FDECL(missmm,(struct monst *,struct monst *,struct attack *)); STATIC_DCL int FDECL(passivemm, (struct monst *, struct monst *, BOOLEAN_P, int)); /* Needed for the special case of monsters wielding vorpal blades (rare). * If we use this a lot it should probably be a parameter to mdamagem() * instead of a global variable. */ static int dieroll; /* returns mon_nam(mon) relative to other_mon; normal name unless they're the same, in which case the reference is to {him|her|it} self */ STATIC_OVL char * mon_nam_too(outbuf, mon, other_mon) char *outbuf; struct monst *mon, *other_mon; { Strcpy(outbuf, mon_nam(mon)); if (mon == other_mon) switch (pronoun_gender(mon)) { case 0: Strcpy(outbuf, "himself"); break; case 1: Strcpy(outbuf, "herself"); break; default: Strcpy(outbuf, "itself"); break; } return outbuf; } STATIC_OVL void noises(magr, mattk) register struct monst *magr; register struct attack *mattk; { boolean farq = (distu(magr->mx, magr->my) > 15); if(flags.soundok && (farq != far_noise || moves-noisetime > 10)) { far_noise = farq; noisetime = moves; You_hear("%s%s.", (mattk->aatyp == AT_EXPL) ? "an explosion" : "some noises", farq ? " in the distance" : ""); } } STATIC_OVL void missmm(magr, mdef, mattk) register struct monst *magr, *mdef; struct attack *mattk; { const char *fmt; char buf[BUFSZ], mdef_name[BUFSZ]; if (vis) { if (!canspotmon(magr)) map_invisible(magr->mx, magr->my); if (!canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); if (mdef->m_ap_type) seemimic(mdef); if (magr->m_ap_type) seemimic(magr); fmt = (could_seduce(magr,mdef,mattk) && !magr->mcan) ? "%s pretends to be friendly to" : "%s misses"; Sprintf(buf, fmt, Monnam(magr)); pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr)); } else noises(magr, mattk); } /* * fightm() -- fight some other monster * * Returns: * 0 - Monster did nothing. * 1 - If the monster made an attack. The monster might have died. * * There is an exception to the above. If mtmp has the hero swallowed, * then we report that the monster did nothing so it will continue to * digest the hero. */ int fightm(mtmp) /* have monsters fight each other */ register struct monst *mtmp; { register struct monst *mon, *nmon; int result, has_u_swallowed; #ifdef LINT nmon = 0; #endif /* perhaps the monster will resist Conflict */ if(resist(mtmp, RING_CLASS, 0, 0)) return(0); if(u.ustuck == mtmp) { /* perhaps we're holding it... */ if(itsstuck(mtmp)) return(0); } has_u_swallowed = (u.uswallow && (mtmp == u.ustuck)); for(mon = fmon; mon; mon = nmon) { nmon = mon->nmon; if(nmon == mtmp) nmon = mtmp->nmon; /* Be careful to ignore monsters that are already dead, since we * might be calling this before we've cleaned them up. This can * happen if the monster attacked a cockatrice bare-handedly, for * instance. */ if(mon != mtmp && !DEADMONSTER(mon)) { if(monnear(mtmp,mon->mx,mon->my)) { if(!u.uswallow && (mtmp == u.ustuck)) { if(!rn2(4)) { pline("%s releases you!", Monnam(mtmp)); u.ustuck = 0; } else break; } /* mtmp can be killed */ bhitpos.x = mon->mx; bhitpos.y = mon->my; notonhead = 0; result = mattackm(mtmp,mon); if (result & MM_AGR_DIED) return 1; /* mtmp died */ /* * If mtmp has the hero swallowed, lie and say there * was no attack (this allows mtmp to digest the hero). */ if (has_u_swallowed) return 0; /* Allow attacked monsters a chance to hit back. Primarily * to allow monsters that resist conflict to respond. */ if ((result & MM_HIT) && !(result & MM_DEF_DIED) && rn2(4) && mon->movement >= NORMAL_SPEED) { mon->movement -= NORMAL_SPEED; notonhead = 0; (void) mattackm(mon, mtmp); /* return attack */ } return ((result & MM_HIT) ? 1 : 0); } } } return 0; } /* * mattackm() -- a monster attacks another monster. * * This function returns a result bitfield: * * --------- aggressor died * / ------- defender died * / / ----- defender was hit * / / / * x x x * * 0x4 MM_AGR_DIED * 0x2 MM_DEF_DIED * 0x1 MM_HIT * 0x0 MM_MISS * * Each successive attack has a lower probability of hitting. Some rely on the * success of previous attacks. ** this doen't seem to be implemented -dl ** * * In the case of exploding monsters, the monster dies as well. */ int mattackm(magr, mdef) register struct monst *magr,*mdef; { int i, /* loop counter */ tmp, /* amour class difference */ strike, /* hit this attack */ attk, /* attack attempted this time */ struck = 0, /* hit at least once */ res[NATTK]; /* results of all attacks */ struct attack *mattk, alt_attk; struct permonst *pa, *pd; if (!magr || !mdef) return(MM_MISS); /* mike@genat */ if (!magr->mcanmove || magr->msleeping) return(MM_MISS); pa = magr->data; pd = mdef->data; /* Grid bugs cannot attack at an angle. */ if (pa == &mons[PM_GRID_BUG] && magr->mx != mdef->mx && magr->my != mdef->my) return(MM_MISS); /* Calculate the armour class differential. */ tmp = find_mac(mdef) + magr->m_lev; if (mdef->mconf || !mdef->mcanmove || mdef->msleeping) { tmp += 4; mdef->msleeping = 0; } /* undetect monsters become un-hidden if they are attacked */ if (mdef->mundetected) { mdef->mundetected = 0; newsym(mdef->mx, mdef->my); if(canseemon(mdef) && !sensemon(mdef)) { if (u.usleep) You("dream of %s.", (mdef->data->geno & G_UNIQ) ? a_monnam(mdef) : makeplural(m_monnam(mdef))); else pline("Suddenly, you notice %s.", a_monnam(mdef)); } } /* Elves hate orcs. */ if (is_elf(pa) && is_orc(pd)) tmp++; /* Set up the visibility of action */ vis = (cansee(magr->mx,magr->my) && cansee(mdef->mx,mdef->my) && (canspotmon(magr) || canspotmon(mdef))); /* Set flag indicating monster has moved this turn. Necessary since a * monster might get an attack out of sequence (i.e. before its move) in * some cases, in which case this still counts as its move for the round * and it shouldn't move again. */ magr->mlstmv = monstermoves; /* Now perform all attacks for the monster. */ for (i = 0; i < NATTK; i++) { res[i] = MM_MISS; mattk = getmattk(pa, i, res, &alt_attk); otmp = (struct obj *)0; attk = 1; switch (mattk->aatyp) { case AT_WEAP: /* "hand to hand" attacks */ if (magr->weapon_check == NEED_WEAPON || !MON_WEP(magr)) { magr->weapon_check = NEED_HTH_WEAPON; if (mon_wield_item(magr) != 0) return 0; } possibly_unwield(magr, FALSE); otmp = MON_WEP(magr); if (otmp) { if (vis) mswingsm(magr, mdef, otmp); tmp += hitval(otmp, mdef); } /* fall through */ case AT_CLAW: case AT_KICK: case AT_BITE: case AT_STNG: case AT_TUCH: case AT_BUTT: case AT_TENT: /* Nymph that teleported away on first attack? */ if (distmin(magr->mx,magr->my,mdef->mx,mdef->my) > 1) return MM_MISS; /* Monsters won't attack cockatrices physically if they * have a weapon instead. This instinct doesn't work for * players, or under conflict or confusion. */ if (!magr->mconf && !Conflict && otmp && mattk->aatyp != AT_WEAP && touch_petrifies(mdef->data)) { strike = 0; break; } dieroll = rnd(20 + i); strike = (tmp > dieroll); /* KMH -- don't accumulate to-hit bonuses */ if (otmp) tmp -= hitval(otmp, mdef); if (strike) { res[i] = hitmm(magr, mdef, mattk); if((mdef->data == &mons[PM_BLACK_PUDDING] || mdef->data == &mons[PM_BROWN_PUDDING]) && otmp && objects[otmp->otyp].oc_material == IRON && mdef->mhp > 1 && !mdef->mcan) { if (clone_mon(mdef, 0, 0)) { if (vis) { char buf[BUFSZ]; Strcpy(buf, Monnam(mdef)); pline("%s divides as %s hits it!", buf, mon_nam(magr)); } } } } else missmm(magr, mdef, mattk); break; case AT_HUGS: /* automatic if prev two attacks succeed */ strike = (i >= 2 && res[i-1] == MM_HIT && res[i-2] == MM_HIT); if (strike) res[i] = hitmm(magr, mdef, mattk); break; case AT_GAZE: strike = 0; /* will not wake up a sleeper */ res[i] = gazemm(magr, mdef, mattk); break; case AT_EXPL: res[i] = explmm(magr, mdef, mattk); if (res[i] == MM_MISS) { /* cancelled--no attack */ strike = 0; attk = 0; } else strike = 1; /* automatic hit */ break; case AT_ENGL: #ifdef STEED if (u.usteed && (mdef == u.usteed)) { strike = 0; break; } #endif /* Engulfing attacks are directed at the hero if * possible. -dlc */ if (u.uswallow && magr == u.ustuck) strike = 0; else { if ((strike = (tmp > rnd(20+i)))) res[i] = gulpmm(magr, mdef, mattk); else missmm(magr, mdef, mattk); } break; default: /* no attack */ strike = 0; attk = 0; break; } if (attk && !(res[i] & MM_AGR_DIED)) res[i] = passivemm(magr, mdef, strike, res[i] & MM_DEF_DIED); if (res[i] & MM_DEF_DIED) return res[i]; /* * Wake up the defender. NOTE: this must follow the check * to see if the defender died. We don't want to modify * unallocated monsters! */ if (strike) mdef->msleeping = 0; if (res[i] & MM_AGR_DIED) return res[i]; /* return if aggressor can no longer attack */ if (!magr->mcanmove || magr->msleeping) return res[i]; if (res[i] & MM_HIT) struck = 1; /* at least one hit */ } return(struck ? MM_HIT : MM_MISS); } /* Returns the result of mdamagem(). */ STATIC_OVL int hitmm(magr, mdef, mattk) register struct monst *magr,*mdef; struct attack *mattk; { if(vis){ int compat; char buf[BUFSZ], mdef_name[BUFSZ]; if (!canspotmon(magr)) map_invisible(magr->mx, magr->my); if (!canspotmon(mdef)) map_invisible(mdef->mx, mdef->my); if(mdef->m_ap_type) seemimic(mdef); if(magr->m_ap_type) seemimic(magr); if((compat = could_seduce(magr,mdef,mattk)) && !magr->mcan) { Sprintf(buf, "%s %s", Monnam(magr), mdef->mcansee ? "smiles at" : "talks to"); pline("%s %s %s.", buf, mon_nam(mdef), compat == 2 ? "engagingly" : "seductively"); } else { char magr_name[BUFSZ]; Strcpy(magr_name, Monnam(magr)); switch (mattk->aatyp) { case AT_BITE: Sprintf(buf,"%s bites", magr_name); break; case AT_STNG: Sprintf(buf,"%s stings", magr_name); break; case AT_BUTT: Sprintf(buf,"%s butts", magr_name); break; case AT_TUCH: Sprintf(buf,"%s touches", magr_name); break; case AT_TENT: Sprintf(buf, "%s tentacles suck", s_suffix(magr_name)); break; case AT_HUGS: if (magr != u.ustuck) { Sprintf(buf,"%s squeezes", magr_name); break; } default: Sprintf(buf,"%s hits", magr_name); } pline("%s %s.", buf, mon_nam_too(mdef_name, mdef, magr)); } } else noises(magr, mattk); return(mdamagem(magr, mdef, mattk)); } /* Returns the same values as mdamagem(). */ STATIC_OVL int gazemm(magr, mdef, mattk) register struct monst *magr, *mdef; struct attack *mattk; { char buf[BUFSZ]; if(vis) { Sprintf(buf,"%s gazes at", Monnam(magr)); pline("%s %s...", buf, mon_nam(mdef)); } if (magr->mcan || !magr->mcansee || (magr->minvis && !perceives(mdef->data)) || !mdef->mcansee || mdef->msleeping) { if(vis) pline("but nothing happens."); return(MM_MISS); } /* call mon_reflects 2x, first test, then, if visible, print message */ if (magr->data == &mons[PM_MEDUSA] && mon_reflects(mdef, (char *)0)) { if (canseemon(mdef)) (void) mon_reflects(mdef, "The gaze is reflected away by %s %s."); if (mdef->mcansee) { if (mon_reflects(magr, (char *)0)) { if (canseemon(magr)) (void) mon_reflects(magr, "The gaze is reflected away by %s %s."); return (MM_MISS); } if (mdef->minvis && !perceives(magr->data)) { if (canseemon(magr)) { pline("%s doesn't seem to notice that %s gaze was reflected.", Monnam(magr), mhis(magr)); } return (MM_MISS); } if (canseemon(magr)) pline("%s is turned to stone!", Monnam(magr)); monstone(magr); if (magr->mhp > 0) return (MM_MISS); return (MM_AGR_DIED); } } return(mdamagem(magr, mdef, mattk)); } /* Returns the same values as mattackm(). */ STATIC_OVL int gulpmm(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; { xchar ax, ay, dx, dy; int status; char buf[BUFSZ]; struct obj *obj; if (mdef->data->msize >= MZ_HUGE) return MM_MISS; if (vis) { Sprintf(buf,"%s swallows", Monnam(magr)); pline("%s %s.", buf, mon_nam(mdef)); } for (obj = mdef->minvent; obj; obj = obj->nobj) (void) snuff_lit(obj); /* * All of this maniuplation is needed to keep the display correct. * There is a flush at the next pline(). */ ax = magr->mx; ay = magr->my; dx = mdef->mx; dy = mdef->my; /* * Leave the defender in the monster chain at it's current position, * but don't leave it on the screen. Move the agressor to the def- * ender's position. */ remove_monster(ax, ay); place_monster(magr, dx, dy); newsym(ax,ay); /* erase old position */ newsym(dx,dy); /* update new position */ status = mdamagem(magr, mdef, mattk); if ((status & MM_AGR_DIED) && (status & MM_DEF_DIED)) { ; /* both died -- do nothing */ } else if (status & MM_DEF_DIED) { /* defender died */ /* * Note: remove_monster() was called in relmon(), wiping out * magr from level.monsters[mdef->mx][mdef->my]. We need to * put it back and display it. -kd */ place_monster(magr, dx, dy); newsym(dx, dy); } else if (status & MM_AGR_DIED) { /* agressor died */ place_monster(mdef, dx, dy); newsym(dx, dy); } else { /* both alive, put them back */ if (cansee(dx, dy)) pline("%s is regurgitated!", Monnam(mdef)); place_monster(magr, ax, ay); place_monster(mdef, dx, dy); newsym(ax, ay); newsym(dx, dy); } return status; } STATIC_OVL int explmm(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; { int result; if (magr->mcan) return MM_MISS; if(cansee(magr->mx, magr->my)) pline("%s explodes!", Monnam(magr)); else noises(magr, mattk); result = mdamagem(magr, mdef, mattk); /* Kill off agressor if it didn't die. */ if (!(result & MM_AGR_DIED)) { mondead(magr); if (magr->mhp > 0) return result; /* life saved */ result |= MM_AGR_DIED; } if (magr->mtame) /* give this one even if it was visible */ You(brief_feeling, "melancholy"); return result; } /* * See comment at top of mattackm(), for return values. */ STATIC_OVL int mdamagem(magr, mdef, mattk) register struct monst *magr, *mdef; register struct attack *mattk; { struct obj *obj; char buf[BUFSZ]; struct permonst *pa = magr->data, *pd = mdef->data; int armpro, num, tmp = d((int)mattk->damn, (int)mattk->damd); boolean cancelled; if (touch_petrifies(pd) && !resists_ston(magr)) { long protector = attk_protection((int)mattk->aatyp), wornitems = magr->misc_worn_check; /* wielded weapon gives same protection as gloves here */ if (otmp != 0) wornitems |= W_ARMG; if (protector == 0L || (protector != ~0L && (wornitems & protector) != protector)) { if (poly_when_stoned(pa)) { mon_to_stone(magr); return MM_HIT; /* no damage during the polymorph */ } if (vis) pline("%s turns to stone!", Monnam(magr)); monstone(magr); if (magr->mhp > 0) return 0; else if (magr->mtame && !vis) You(brief_feeling, "peculiarly sad"); return MM_AGR_DIED; } } /* cancellation factor is the same as when attacking the hero */ armpro = magic_negation(mdef); cancelled = magr->mcan || !((rn2(3) >= armpro) || !rn2(50)); switch(mattk->adtyp) { case AD_DGST: /* eating a Rider or its corpse is fatal */ if (is_rider(mdef->data)) { if (vis) pline("%s %s!", Monnam(magr), mdef->data == &mons[PM_FAMINE] ? "belches feebly, shrivels up and dies" : mdef->data == &mons[PM_PESTILENCE] ? "coughs spasmodically and collapses" : "vomits violently and drops dead"); mondied(magr); if (magr->mhp > 0) return 0; /* lifesaved */ else if (magr->mtame && !vis) You(brief_feeling, "queasy"); return MM_AGR_DIED; } if(flags.verbose && flags.soundok) verbalize("Burrrrp!"); tmp = mdef->mhp; /* Use up amulet of life saving */ if (!!(obj = mlifesaver(mdef))) m_useup(mdef, obj); /* Is a corpse for nutrition possible? It may kill magr */ if (!corpse_chance(mdef, magr, TRUE) || magr->mhp < 1) break; /* Pets get nutrition from swallowing monster whole. * No nutrition from G_NOCORPSE monster, eg, undead. * DGST monsters don't die from undead corpses */ num = monsndx(mdef->data); if (magr->mtame && !magr->isminion && !(mvitals[num].mvflags & G_NOCORPSE)) { struct obj *virtualcorpse = mksobj(CORPSE, FALSE, FALSE); int nutrit; virtualcorpse->corpsenm = num; virtualcorpse->owt = weight(virtualcorpse); nutrit = dog_nutrition(magr, virtualcorpse); dealloc_obj(virtualcorpse); /* only 50% nutrition, 25% of normal eating time */ if (magr->meating > 1) magr->meating = (magr->meating+3)/4; if (nutrit > 1) nutrit /= 2; EDOG(magr)->hungrytime += nutrit; } break; case AD_STUN: if (magr->mcan) break; if (canseemon(mdef)) pline("%s %s for a moment.", Monnam(mdef), makeplural(stagger(mdef->data, "stagger"))); mdef->mstun = 1; goto physical; case AD_LEGS: if (magr->mcan) { tmp = 0; break; } goto physical; case AD_WERE: case AD_HEAL: case AD_PHYS: physical: if (mattk->aatyp == AT_KICK && thick_skinned(pd)) { tmp = 0; } else if(mattk->aatyp == AT_WEAP) { if(otmp) { if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) goto do_stone; tmp += dmgval(otmp, mdef); if (otmp->oartifact) { (void)artifact_hit(magr,mdef, otmp, &tmp, dieroll); if (mdef->mhp <= 0) return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } if (tmp) mrustm(magr, mdef, otmp); } } else if (magr->data == &mons[PM_PURPLE_WORM] && mdef->data == &mons[PM_SHRIEKER]) { /* hack to enhance mm_aggression(); we don't want purple worm's bite attack to kill a shrieker because then it won't swallow the corpse; but if the target survives, the subsequent engulf attack should accomplish that */ if (tmp >= mdef->mhp) tmp = mdef->mhp - 1; } break; case AD_FIRE: if (cancelled) { tmp = 0; break; } if (vis) pline("%s is %s!", Monnam(mdef), on_fire(mdef->data, mattk)); if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) { if (vis) pline("%s burns completely!", Monnam(mdef)); mondied(mdef); if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) pline("May %s roast in peace.", mon_nam(mdef)); return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); if (resists_fire(mdef)) { if (vis) pline_The("fire doesn't seem to burn %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); golemeffects(mdef, AD_FIRE, tmp); tmp = 0; } /* only potions damage resistant players in destroy_item */ tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); break; case AD_COLD: if (cancelled) { tmp = 0; break; } if (vis) pline("%s is covered in frost!", Monnam(mdef)); if (resists_cold(mdef)) { if (vis) pline_The("frost doesn't seem to chill %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); golemeffects(mdef, AD_COLD, tmp); tmp = 0; } tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD); break; case AD_ELEC: if (cancelled) { tmp = 0; break; } if (vis) pline("%s gets zapped!", Monnam(mdef)); tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); if (resists_elec(mdef)) { if (vis) pline_The("zap doesn't shock %s!", mon_nam(mdef)); shieldeff(mdef->mx, mdef->my); golemeffects(mdef, AD_ELEC, tmp); tmp = 0; } /* only rings damage resistant players in destroy_item */ tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC); break; case AD_ACID: if (magr->mcan) { tmp = 0; break; } if (resists_acid(mdef)) { if (vis) pline("%s is covered in acid, but it seems harmless.", Monnam(mdef)); tmp = 0; } else if (vis) { pline("%s is covered in acid!", Monnam(mdef)); pline("It burns %s!", mon_nam(mdef)); } if (!rn2(30)) erode_armor(mdef, TRUE); if (!rn2(6)) erode_obj(MON_WEP(mdef), TRUE, TRUE); break; case AD_RUST: if (magr->mcan) break; if (pd == &mons[PM_IRON_GOLEM]) { if (vis) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) pline("May %s rust in peace.", mon_nam(mdef)); return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } hurtmarmor(mdef, AD_RUST); mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_CORR: if (magr->mcan) break; hurtmarmor(mdef, AD_CORR); mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_DCAY: if (magr->mcan) break; if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) { if (vis) pline("%s falls to pieces!", Monnam(mdef)); mondied(mdef); if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) pline("May %s rot in peace.", mon_nam(mdef)); return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } hurtmarmor(mdef, AD_DCAY); mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; break; case AD_STON: if (magr->mcan) break; do_stone: /* may die from the acid if it eats a stone-curing corpse */ if (munstone(mdef, FALSE)) goto post_stone; if (poly_when_stoned(pd)) { mon_to_stone(mdef); tmp = 0; break; } if (!resists_ston(mdef)) { if (vis) pline("%s turns to stone!", Monnam(mdef)); monstone(mdef); post_stone: if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "peculiarly sad"); return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } tmp = (mattk->adtyp == AD_STON ? 0 : 1); break; case AD_TLPT: if (!cancelled && tmp < mdef->mhp && !tele_restrict(mdef)) { char mdef_Monnam[BUFSZ]; /* save the name before monster teleports, otherwise we'll get "it" in the suddenly disappears message */ if (vis) Strcpy(mdef_Monnam, Monnam(mdef)); mdef->mstrategy &= ~STRAT_WAITFORU; (void) rloc(mdef, FALSE); if (vis && !canspotmon(mdef) #ifdef STEED && mdef != u.usteed #endif ) pline("%s suddenly disappears!", mdef_Monnam); } break; case AD_SLEE: if (!cancelled && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) { if (vis) { Strcpy(buf, Monnam(mdef)); pline("%s is put to sleep by %s.", buf, mon_nam(magr)); } mdef->mstrategy &= ~STRAT_WAITFORU; slept_monst(mdef); } break; case AD_PLYS: if(!cancelled && mdef->mcanmove) { if (vis) { Strcpy(buf, Monnam(mdef)); pline("%s is frozen by %s.", buf, mon_nam(magr)); } mdef->mcanmove = 0; mdef->mfrozen = rnd(10); mdef->mstrategy &= ~STRAT_WAITFORU; } break; case AD_SLOW: if (!cancelled && mdef->mspeed != MSLOW) { unsigned int oldspeed = mdef->mspeed; mon_adjust_speed(mdef, -1, (struct obj *)0); mdef->mstrategy &= ~STRAT_WAITFORU; if (mdef->mspeed != oldspeed && vis) pline("%s slows down.", Monnam(mdef)); } break; case AD_CONF: /* Since confusing another monster doesn't have a real time * limit, setting spec_used would not really be right (though * we still should check for it). */ if (!magr->mcan && !mdef->mconf && !magr->mspec_used) { if (vis) pline("%s looks confused.", Monnam(mdef)); mdef->mconf = 1; mdef->mstrategy &= ~STRAT_WAITFORU; } break; case AD_BLND: if (can_blnd(magr, mdef, mattk->aatyp, (struct obj*)0)) { register unsigned rnd_tmp; if (vis && mdef->mcansee) pline("%s is blinded.", Monnam(mdef)); rnd_tmp = d((int)mattk->damn, (int)mattk->damd); if ((rnd_tmp += mdef->mblinded) > 127) rnd_tmp = 127; mdef->mblinded = rnd_tmp; mdef->mcansee = 0; mdef->mstrategy &= ~STRAT_WAITFORU; } tmp = 0; break; case AD_HALU: if (!magr->mcan && haseyes(pd) && mdef->mcansee) { if (vis) pline("%s looks %sconfused.", Monnam(mdef), mdef->mconf ? "more " : ""); mdef->mconf = 1; mdef->mstrategy &= ~STRAT_WAITFORU; } tmp = 0; break; case AD_CURS: if (!night() && (pa == &mons[PM_GREMLIN])) break; if (!magr->mcan && !rn2(10)) { mdef->mcan = 1; /* cancelled regardless of lifesave */ mdef->mstrategy &= ~STRAT_WAITFORU; if (is_were(pd) && pd->mlet != S_HUMAN) were_change(mdef); if (pd == &mons[PM_CLAY_GOLEM]) { if (vis) { pline("Some writing vanishes from %s head!", s_suffix(mon_nam(mdef))); pline("%s is destroyed!", Monnam(mdef)); } mondied(mdef); if (mdef->mhp > 0) return 0; else if (mdef->mtame && !vis) You(brief_feeling, "strangely sad"); return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } if (flags.soundok) { if (!vis) You_hear("laughter."); else pline("%s chuckles.", Monnam(magr)); } } break; case AD_SGLD: tmp = 0; #ifndef GOLDOBJ if (magr->mcan || !mdef->mgold) break; /* technically incorrect; no check for stealing gold from * between mdef's feet... */ magr->mgold += mdef->mgold; mdef->mgold = 0; #else if (magr->mcan) break; /* technically incorrect; no check for stealing gold from * between mdef's feet... */ { struct obj *gold = findgold(mdef->minvent); if (!gold) break; obj_extract_self(gold); add_to_minv(magr, gold); } #endif mdef->mstrategy &= ~STRAT_WAITFORU; if (vis) { Strcpy(buf, Monnam(magr)); pline("%s steals some gold from %s.", buf, mon_nam(mdef)); } if (!tele_restrict(magr)) { (void) rloc(magr, FALSE); if (vis && !canspotmon(magr)) pline("%s suddenly disappears!", buf); } break; case AD_DRLI: if (!cancelled && !rn2(3) && !resists_drli(mdef)) { tmp = d(2,6); if (vis) pline("%s suddenly seems weaker!", Monnam(mdef)); mdef->mhpmax -= tmp; if (mdef->m_lev == 0) tmp = mdef->mhp; else mdef->m_lev--; /* Automatic kill if drained past level 0 */ } break; #ifdef SEDUCE case AD_SSEX: #endif case AD_SITM: /* for now these are the same */ case AD_SEDU: if (magr->mcan) break; /* find an object to steal, non-cursed if magr is tame */ for (obj = mdef->minvent; obj; obj = obj->nobj) if (!magr->mtame || !obj->cursed) break; if (obj) { char onambuf[BUFSZ], mdefnambuf[BUFSZ]; /* make a special x_monnam() call that never omits the saddle, and save it for later messages */ Strcpy(mdefnambuf, x_monnam(mdef, ARTICLE_THE, (char *)0, 0, FALSE)); otmp = obj; #ifdef STEED if (u.usteed == mdef && otmp == which_armor(mdef, W_SADDLE)) /* "You can no longer ride ." */ dismount_steed(DISMOUNT_POLY); #endif obj_extract_self(otmp); if (otmp->owornmask) { mdef->misc_worn_check &= ~otmp->owornmask; if (otmp->owornmask & W_WEP) setmnotwielded(mdef,otmp); otmp->owornmask = 0L; update_mon_intrinsics(mdef, otmp, FALSE, FALSE); } /* add_to_minv() might free otmp [if it merges] */ if (vis) Strcpy(onambuf, doname(otmp)); (void) add_to_minv(magr, otmp); if (vis) { Strcpy(buf, Monnam(magr)); pline("%s steals %s from %s!", buf, onambuf, mdefnambuf); } possibly_unwield(mdef, FALSE); mdef->mstrategy &= ~STRAT_WAITFORU; mselftouch(mdef, (const char *)0, FALSE); if (mdef->mhp <= 0) return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); if (magr->data->mlet == S_NYMPH && !tele_restrict(magr)) { (void) rloc(magr, FALSE); if (vis && !canspotmon(magr)) pline("%s suddenly disappears!", buf); } } tmp = 0; break; case AD_DRST: case AD_DRDX: case AD_DRCO: if (!cancelled && !rn2(8)) { if (vis) pline("%s %s was poisoned!", s_suffix(Monnam(magr)), mpoisons_subj(magr, mattk)); if (resists_poison(mdef)) { if (vis) pline_The("poison doesn't seem to affect %s.", mon_nam(mdef)); } else { if (rn2(10)) tmp += rn1(10,6); else { if (vis) pline_The("poison was deadly..."); tmp = mdef->mhp; } } } break; case AD_DRIN: if (notonhead || !has_head(pd)) { if (vis) pline("%s doesn't seem harmed.", Monnam(mdef)); /* Not clear what to do for green slimes */ tmp = 0; break; } if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) { if (vis) { Strcpy(buf, s_suffix(Monnam(mdef))); pline("%s helmet blocks %s attack to %s head.", buf, s_suffix(mon_nam(magr)), mhis(mdef)); } break; } if (vis) pline("%s brain is eaten!", s_suffix(Monnam(mdef))); if (mindless(pd)) { if (vis) pline("%s doesn't notice.", Monnam(mdef)); break; } tmp += rnd(10); /* fakery, since monsters lack INT scores */ if (magr->mtame && !magr->isminion) { EDOG(magr)->hungrytime += rnd(60); magr->mconf = 0; } if (tmp >= mdef->mhp && vis) pline("%s last thought fades away...", s_suffix(Monnam(mdef))); break; case AD_SLIM: if (cancelled) break; /* physical damage only */ if (!rn2(4) && !flaming(mdef->data) && mdef->data != &mons[PM_GREEN_SLIME]) { (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, vis); mdef->mstrategy &= ~STRAT_WAITFORU; tmp = 0; } break; case AD_STCK: if (cancelled) tmp = 0; break; case AD_WRAP: /* monsters cannot grab one another, it's too hard */ if (magr->mcan) tmp = 0; break; case AD_ENCH: /* there's no msomearmor() function, so just do damage */ /* if (cancelled) break; */ break; default: tmp = 0; break; } if(!tmp) return(MM_MISS); if((mdef->mhp -= tmp) < 1) { if (m_at(mdef->mx, mdef->my) == magr) { /* see gulpmm() */ remove_monster(mdef->mx, mdef->my); mdef->mhp = 1; /* otherwise place_monster will complain */ place_monster(mdef, mdef->mx, mdef->my); mdef->mhp = 0; } monkilled(mdef, "", (int)mattk->adtyp); if (mdef->mhp > 0) return 0; /* mdef lifesaved */ if (mattk->adtyp == AD_DGST) { /* various checks similar to dog_eat and meatobj. * after monkilled() to provide better message ordering */ if (mdef->cham != CHAM_ORDINARY) { (void) newcham(magr, (struct permonst *)0, FALSE, TRUE); } else if (mdef->data == &mons[PM_GREEN_SLIME]) { (void) newcham(magr, &mons[PM_GREEN_SLIME], FALSE, TRUE); } else if (mdef->data == &mons[PM_WRAITH]) { (void) grow_up(magr, (struct monst *)0); /* don't grow up twice */ return (MM_DEF_DIED | (magr->mhp > 0 ? 0 : MM_AGR_DIED)); } else if (mdef->data == &mons[PM_NURSE]) { magr->mhp = magr->mhpmax; } } return (MM_DEF_DIED | (grow_up(magr,mdef) ? 0 : MM_AGR_DIED)); } return(MM_HIT); } #endif /* OVLB */ #ifdef OVL0 int noattacks(ptr) /* returns 1 if monster doesn't attack */ struct permonst *ptr; { int i; for(i = 0; i < NATTK; i++) if(ptr->mattk[i].aatyp) return(0); return(1); } /* `mon' is hit by a sleep attack; return 1 if it's affected, 0 otherwise */ int sleep_monst(mon, amt, how) struct monst *mon; int amt, how; { if (resists_sleep(mon) || (how >= 0 && resist(mon, (char)how, 0, NOTELL))) { shieldeff(mon->mx, mon->my); } else if (mon->mcanmove) { amt += (int) mon->mfrozen; if (amt > 0) { /* sleep for N turns */ mon->mcanmove = 0; mon->mfrozen = min(amt, 127); } else { /* sleep until awakened */ mon->msleeping = 1; } return 1; } return 0; } /* sleeping grabber releases, engulfer doesn't; don't use for paralysis! */ void slept_monst(mon) struct monst *mon; { if ((mon->msleeping || !mon->mcanmove) && mon == u.ustuck && !sticks(youmonst.data) && !u.uswallow) { pline("%s grip relaxes.", s_suffix(Monnam(mon))); unstuck(mon); } } #endif /* OVL0 */ #ifdef OVLB STATIC_OVL void mrustm(magr, mdef, obj) register struct monst *magr, *mdef; register struct obj *obj; { boolean is_acid; if (!magr || !mdef || !obj) return; /* just in case */ if (dmgtype(mdef->data, AD_CORR)) is_acid = TRUE; else if (dmgtype(mdef->data, AD_RUST)) is_acid = FALSE; else return; if (!mdef->mcan && (is_acid ? is_corrodeable(obj) : is_rustprone(obj)) && (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) { if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) { if (cansee(mdef->mx, mdef->my) && flags.verbose) pline("%s weapon is not affected.", s_suffix(Monnam(magr))); if (obj->greased && !rn2(2)) obj->greased = 0; } else { if (cansee(mdef->mx, mdef->my)) { pline("%s %s%s!", s_suffix(Monnam(magr)), aobjnam(obj, (is_acid ? "corrode" : "rust")), (is_acid ? obj->oeroded2 : obj->oeroded) ? " further" : ""); } if (is_acid) obj->oeroded2++; else obj->oeroded++; } } } STATIC_OVL void mswingsm(magr, mdef, otemp) register struct monst *magr, *mdef; register struct obj *otemp; { char buf[BUFSZ]; if (!flags.verbose || Blind || !mon_visible(magr)) return; Strcpy(buf, mon_nam(mdef)); pline("%s %s %s %s at %s.", Monnam(magr), (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings", mhis(magr), singular(otemp, xname), buf); } /* * Passive responses by defenders. Does not replicate responses already * handled above. Returns same values as mattackm. */ STATIC_OVL int passivemm(magr,mdef,mhit,mdead) register struct monst *magr, *mdef; boolean mhit; int mdead; { register struct permonst *mddat = mdef->data; register struct permonst *madat = magr->data; char buf[BUFSZ]; int i, tmp; for(i = 0; ; i++) { if(i >= NATTK) return (mdead | mhit); /* no passive attacks */ if(mddat->mattk[i].aatyp == AT_NONE) break; } if (mddat->mattk[i].damn) tmp = d((int)mddat->mattk[i].damn, (int)mddat->mattk[i].damd); else if(mddat->mattk[i].damd) tmp = d((int)mddat->mlevel+1, (int)mddat->mattk[i].damd); else tmp = 0; /* These affect the enemy even if defender killed */ switch(mddat->mattk[i].adtyp) { case AD_ACID: if (mhit && !rn2(2)) { Strcpy(buf, Monnam(magr)); if(canseemon(magr)) pline("%s is splashed by %s acid!", buf, s_suffix(mon_nam(mdef))); if (resists_acid(magr)) { if(canseemon(magr)) pline("%s is not affected.", Monnam(magr)); tmp = 0; } } else tmp = 0; goto assess_dmg; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ if (mhit && !mdef->mcan && otmp) { (void) drain_item(otmp); /* No message */ } break; default: break; } if (mdead || mdef->mcan) return (mdead|mhit); /* These affect the enemy only if defender is still alive */ if (rn2(3)) switch(mddat->mattk[i].adtyp) { case AD_PLYS: /* Floating eye */ if (tmp > 127) tmp = 127; if (mddat == &mons[PM_FLOATING_EYE]) { if (!rn2(4)) tmp = 127; if (magr->mcansee && haseyes(madat) && mdef->mcansee && (perceives(madat) || !mdef->minvis)) { Sprintf(buf, "%s gaze is reflected by %%s %%s.", s_suffix(mon_nam(mdef))); if (mon_reflects(magr, canseemon(magr) ? buf : (char *)0)) return(mdead|mhit); Strcpy(buf, Monnam(magr)); if(canseemon(magr)) pline("%s is frozen by %s gaze!", buf, s_suffix(mon_nam(mdef))); magr->mcanmove = 0; magr->mfrozen = tmp; return (mdead|mhit); } } else { /* gelatinous cube */ Strcpy(buf, Monnam(magr)); if(canseemon(magr)) pline("%s is frozen by %s.", buf, mon_nam(mdef)); magr->mcanmove = 0; magr->mfrozen = tmp; return (mdead|mhit); } return 1; case AD_COLD: if (resists_cold(magr)) { if (canseemon(magr)) { pline("%s is mildly chilly.", Monnam(magr)); golemeffects(magr, AD_COLD, tmp); } tmp = 0; break; } if(canseemon(magr)) pline("%s is suddenly very cold!", Monnam(magr)); mdef->mhp += tmp / 2; if (mdef->mhpmax < mdef->mhp) mdef->mhpmax = mdef->mhp; if (mdef->mhpmax > ((int) (mdef->m_lev+1) * 8)) (void)split_mon(mdef, magr); break; case AD_STUN: if (!magr->mstun) { magr->mstun = 1; if (canseemon(magr)) pline("%s %s...", Monnam(magr), makeplural(stagger(magr->data, "stagger"))); } tmp = 0; break; case AD_FIRE: if (resists_fire(magr)) { if (canseemon(magr)) { pline("%s is mildly warmed.", Monnam(magr)); golemeffects(magr, AD_FIRE, tmp); } tmp = 0; break; } if(canseemon(magr)) pline("%s is suddenly very hot!", Monnam(magr)); break; case AD_ELEC: if (resists_elec(magr)) { if (canseemon(magr)) { pline("%s is mildly tingled.", Monnam(magr)); golemeffects(magr, AD_ELEC, tmp); } tmp = 0; break; } if(canseemon(magr)) pline("%s is jolted with electricity!", Monnam(magr)); break; default: tmp = 0; break; } else tmp = 0; assess_dmg: if((magr->mhp -= tmp) <= 0) { monkilled(magr, "", (int)mddat->mattk[i].adtyp); return (mdead | mhit | MM_AGR_DIED); } return (mdead | mhit); } /* "aggressive defense"; what type of armor prevents specified attack from touching its target? */ long attk_protection(aatyp) int aatyp; { long w_mask = 0L; switch (aatyp) { case AT_NONE: case AT_SPIT: case AT_EXPL: case AT_BOOM: case AT_GAZE: case AT_BREA: case AT_MAGC: w_mask = ~0L; /* special case; no defense needed */ break; case AT_CLAW: case AT_TUCH: case AT_WEAP: w_mask = W_ARMG; /* caller needs to check for weapon */ break; case AT_KICK: w_mask = W_ARMF; break; case AT_BUTT: w_mask = W_ARMH; break; case AT_HUGS: w_mask = (W_ARMC|W_ARMG); /* attacker needs both to be protected */ break; case AT_BITE: case AT_STNG: case AT_ENGL: case AT_TENT: default: w_mask = 0L; /* no defense available */ break; } return w_mask; } #endif /* OVLB */ /*mhitm.c*/ nethack-3.4.3/src/mhitu.c0100644000000000000000000021571407764735041013745 0ustar rootroot/* SCCS Id: @(#)mhitu.c 3.4 2003/11/26 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "artifact.h" STATIC_VAR NEARDATA struct obj *otmp; STATIC_DCL void FDECL(urustm, (struct monst *, struct obj *)); # ifdef OVL1 STATIC_DCL boolean FDECL(u_slip_free, (struct monst *,struct attack *)); STATIC_DCL int FDECL(passiveum, (struct permonst *,struct monst *,struct attack *)); # endif /* OVL1 */ #ifdef OVLB # ifdef SEDUCE STATIC_DCL void FDECL(mayberem, (struct obj *, const char *)); # endif #endif /* OVLB */ STATIC_DCL boolean FDECL(diseasemu, (struct permonst *)); STATIC_DCL int FDECL(hitmu, (struct monst *,struct attack *)); STATIC_DCL int FDECL(gulpmu, (struct monst *,struct attack *)); STATIC_DCL int FDECL(explmu, (struct monst *,struct attack *,BOOLEAN_P)); STATIC_DCL void FDECL(missmu,(struct monst *,BOOLEAN_P,struct attack *)); STATIC_DCL void FDECL(mswings,(struct monst *,struct obj *)); STATIC_DCL void FDECL(wildmiss, (struct monst *,struct attack *)); STATIC_DCL void FDECL(hurtarmor,(int)); STATIC_DCL void FDECL(hitmsg,(struct monst *,struct attack *)); /* See comment in mhitm.c. If we use this a lot it probably should be */ /* changed to a parameter to mhitu. */ static int dieroll; #ifdef OVL1 STATIC_OVL void hitmsg(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { int compat; /* Note: if opposite gender, "seductively" */ /* If same gender, "engagingly" for nymph, normal msg for others */ if((compat = could_seduce(mtmp, &youmonst, mattk)) && !mtmp->mcan && !mtmp->mspec_used) { pline("%s %s you %s.", Monnam(mtmp), Blind ? "talks to" : "smiles at", compat == 2 ? "engagingly" : "seductively"); } else switch (mattk->aatyp) { case AT_BITE: pline("%s bites!", Monnam(mtmp)); break; case AT_KICK: pline("%s kicks%c", Monnam(mtmp), thick_skinned(youmonst.data) ? '.' : '!'); break; case AT_STNG: pline("%s stings!", Monnam(mtmp)); break; case AT_BUTT: pline("%s butts!", Monnam(mtmp)); break; case AT_TUCH: pline("%s touches you!", Monnam(mtmp)); break; case AT_TENT: pline("%s tentacles suck you!", s_suffix(Monnam(mtmp))); break; case AT_EXPL: case AT_BOOM: pline("%s explodes!", Monnam(mtmp)); break; default: pline("%s hits!", Monnam(mtmp)); } } STATIC_OVL void missmu(mtmp, nearmiss, mattk) /* monster missed you */ register struct monst *mtmp; register boolean nearmiss; register struct attack *mattk; { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); if(could_seduce(mtmp, &youmonst, mattk) && !mtmp->mcan) pline("%s pretends to be friendly.", Monnam(mtmp)); else { if (!flags.verbose || !nearmiss) pline("%s misses.", Monnam(mtmp)); else pline("%s just misses!", Monnam(mtmp)); } stop_occupation(); } STATIC_OVL void mswings(mtmp, otemp) /* monster swings obj */ register struct monst *mtmp; register struct obj *otemp; { if (!flags.verbose || Blind || !mon_visible(mtmp)) return; pline("%s %s %s %s.", Monnam(mtmp), (objects[otemp->otyp].oc_dir & PIERCE) ? "thrusts" : "swings", mhis(mtmp), singular(otemp, xname)); } /* return how a poison attack was delivered */ const char * mpoisons_subj(mtmp, mattk) struct monst *mtmp; struct attack *mattk; { if (mattk->aatyp == AT_WEAP) { struct obj *mwep = (mtmp == &youmonst) ? uwep : MON_WEP(mtmp); /* "Foo's attack was poisoned." is pretty lame, but at least it's better than "sting" when not a stinging attack... */ return (!mwep || !mwep->opoisoned) ? "attack" : "weapon"; } else { return (mattk->aatyp == AT_TUCH) ? "contact" : (mattk->aatyp == AT_GAZE) ? "gaze" : (mattk->aatyp == AT_BITE) ? "bite" : "sting"; } } /* called when your intrinsic speed is taken away */ void u_slow_down() { HFast = 0L; if (!Fast) You("slow down."); else /* speed boots */ Your("quickness feels less natural."); exercise(A_DEX, FALSE); } #endif /* OVL1 */ #ifdef OVLB STATIC_OVL void wildmiss(mtmp, mattk) /* monster attacked your displaced image */ register struct monst *mtmp; register struct attack *mattk; { int compat; /* no map_invisible() -- no way to tell where _this_ is coming from */ if (!flags.verbose) return; if (!cansee(mtmp->mx, mtmp->my)) return; /* maybe it's attacking an image around the corner? */ compat = (mattk->adtyp == AD_SEDU || mattk->adtyp == AD_SSEX) && could_seduce(mtmp, &youmonst, (struct attack *)0); if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) { const char *swings = mattk->aatyp == AT_BITE ? "snaps" : mattk->aatyp == AT_KICK ? "kicks" : (mattk->aatyp == AT_STNG || mattk->aatyp == AT_BUTT || nolimbs(mtmp->data)) ? "lunges" : "swings"; if (compat) pline("%s tries to touch you and misses!", Monnam(mtmp)); else switch(rn2(3)) { case 0: pline("%s %s wildly and misses!", Monnam(mtmp), swings); break; case 1: pline("%s attacks a spot beside you.", Monnam(mtmp)); break; case 2: pline("%s strikes at %s!", Monnam(mtmp), levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water" : "thin air"); break; default:pline("%s %s wildly!", Monnam(mtmp), swings); break; } } else if (Displaced) { if (compat) pline("%s smiles %s at your %sdisplaced image...", Monnam(mtmp), compat == 2 ? "engagingly" : "seductively", Invis ? "invisible " : ""); else pline("%s strikes at your %sdisplaced image and misses you!", /* Note: if you're both invisible and displaced, * only monsters which see invisible will attack your * displaced image, since the displaced image is also * invisible. */ Monnam(mtmp), Invis ? "invisible " : ""); } else if (Underwater) { /* monsters may miss especially on water level where bubbles shake the player here and there */ if (compat) pline("%s reaches towards your distorted image.",Monnam(mtmp)); else pline("%s is fooled by water reflections and misses!",Monnam(mtmp)); } else impossible("%s attacks you without knowing your location?", Monnam(mtmp)); } void expels(mtmp, mdat, message) register struct monst *mtmp; register struct permonst *mdat; /* if mtmp is polymorphed, mdat != mtmp->data */ boolean message; { if (message) { if (is_animal(mdat)) You("get regurgitated!"); else { char blast[40]; register int i; blast[0] = '\0'; for(i = 0; i < NATTK; i++) if(mdat->mattk[i].aatyp == AT_ENGL) break; if (mdat->mattk[i].aatyp != AT_ENGL) impossible("Swallower has no engulfing attack?"); else { if (is_whirly(mdat)) { switch (mdat->mattk[i].adtyp) { case AD_ELEC: Strcpy(blast, " in a shower of sparks"); break; case AD_COLD: Strcpy(blast, " in a blast of frost"); break; } } else Strcpy(blast, " with a squelch"); You("get expelled from %s%s!", mon_nam(mtmp), blast); } } } unstuck(mtmp); /* ball&chain returned in unstuck() */ mnexto(mtmp); newsym(u.ux,u.uy); spoteffects(TRUE); /* to cover for a case where mtmp is not in a next square */ if(um_dist(mtmp->mx,mtmp->my,1)) pline("Brrooaa... You land hard at some distance."); } #endif /* OVLB */ #ifdef OVL0 /* select a monster's next attack, possibly substituting for its usual one */ struct attack * getmattk(mptr, indx, prev_result, alt_attk_buf) struct permonst *mptr; int indx, prev_result[]; struct attack *alt_attk_buf; { struct attack *attk = &mptr->mattk[indx]; /* prevent a monster with two consecutive disease or hunger attacks from hitting with both of them on the same turn; if the first has already hit, switch to a stun attack for the second */ if (indx > 0 && prev_result[indx - 1] > 0 && (attk->adtyp == AD_DISE || attk->adtyp == AD_PEST || attk->adtyp == AD_FAMN) && attk->adtyp == mptr->mattk[indx - 1].adtyp) { *alt_attk_buf = *attk; attk = alt_attk_buf; attk->adtyp = AD_STUN; } return attk; } /* * mattacku: monster attacks you * returns 1 if monster dies (e.g. "yellow light"), 0 otherwise * Note: if you're displaced or invisible the monster might attack the * wrong position... * Assumption: it's attacking you or an empty square; if there's another * monster which it attacks by mistake, the caller had better * take care of it... */ int mattacku(mtmp) register struct monst *mtmp; { struct attack *mattk, alt_attk; int i, j, tmp, sum[NATTK]; struct permonst *mdat = mtmp->data; boolean ranged = (distu(mtmp->mx, mtmp->my) > 3); /* Is it near you? Affects your actions */ boolean range2 = !monnear(mtmp, mtmp->mux, mtmp->muy); /* Does it think it's near you? Affects its actions */ boolean foundyou = (mtmp->mux==u.ux && mtmp->muy==u.uy); /* Is it attacking you or your image? */ boolean youseeit = canseemon(mtmp); /* Might be attacking your image around the corner, or * invisible, or you might be blind.... */ if(!ranged) nomul(0); if(mtmp->mhp <= 0 || (Underwater && !is_swimmer(mtmp->data))) return(0); /* If swallowed, can only be affected by u.ustuck */ if(u.uswallow) { if(mtmp != u.ustuck) return(0); u.ustuck->mux = u.ux; u.ustuck->muy = u.uy; range2 = 0; foundyou = 1; if(u.uinvulnerable) return (0); /* stomachs can't hurt you! */ } #ifdef STEED else if (u.usteed) { if (mtmp == u.usteed) /* Your steed won't attack you */ return (0); /* Orcs like to steal and eat horses and the like */ if (!rn2(is_orc(mtmp->data) ? 2 : 4) && distu(mtmp->mx, mtmp->my) <= 2) { /* Attack your steed instead */ i = mattackm(mtmp, u.usteed); if ((i & MM_AGR_DIED)) return (1); if (i & MM_DEF_DIED || u.umoved) return (0); /* Let your steed retaliate */ return (!!(mattackm(u.usteed, mtmp) & MM_DEF_DIED)); } } #endif if (u.uundetected && !range2 && foundyou && !u.uswallow) { u.uundetected = 0; if (is_hider(youmonst.data)) { coord cc; /* maybe we need a unexto() function? */ struct obj *obj; You("fall from the %s!", ceiling(u.ux,u.uy)); if (enexto(&cc, u.ux, u.uy, youmonst.data)) { remove_monster(mtmp->mx, mtmp->my); newsym(mtmp->mx,mtmp->my); place_monster(mtmp, u.ux, u.uy); if(mtmp->wormno) worm_move(mtmp); teleds(cc.x, cc.y, TRUE); set_apparxy(mtmp); newsym(u.ux,u.uy); } else { pline("%s is killed by a falling %s (you)!", Monnam(mtmp), youmonst.data->mname); killed(mtmp); newsym(u.ux,u.uy); if (mtmp->mhp > 0) return 0; else return 1; } if (youmonst.data->mlet != S_PIERCER) return(0); /* trappers don't attack */ obj = which_armor(mtmp, WORN_HELMET); if (obj && is_metallic(obj)) { Your("blow glances off %s helmet.", s_suffix(mon_nam(mtmp))); } else { if (3 + find_mac(mtmp) <= rnd(20)) { pline("%s is hit by a falling piercer (you)!", Monnam(mtmp)); if ((mtmp->mhp -= d(3,6)) < 1) killed(mtmp); } else pline("%s is almost hit by a falling piercer (you)!", Monnam(mtmp)); } } else { if (!youseeit) pline("It tries to move where you are hiding."); else { /* Ugly kludge for eggs. The message is phrased so as * to be directed at the monster, not the player, * which makes "laid by you" wrong. For the * parallelism to work, we can't rephrase it, so we * zap the "laid by you" momentarily instead. */ struct obj *obj = level.objects[u.ux][u.uy]; if (obj || (youmonst.data->mlet == S_EEL && is_pool(u.ux, u.uy))) { int save_spe = 0; /* suppress warning */ if (obj) { save_spe = obj->spe; if (obj->otyp == EGG) obj->spe = 0; } if (youmonst.data->mlet == S_EEL) pline("Wait, %s! There's a hidden %s named %s there!", m_monnam(mtmp), youmonst.data->mname, plname); else pline("Wait, %s! There's a %s named %s hiding under %s!", m_monnam(mtmp), youmonst.data->mname, plname, doname(level.objects[u.ux][u.uy])); if (obj) obj->spe = save_spe; } else impossible("hiding under nothing?"); } newsym(u.ux,u.uy); } return(0); } if (youmonst.data->mlet == S_MIMIC && youmonst.m_ap_type && !range2 && foundyou && !u.uswallow) { if (!youseeit) pline("It gets stuck on you."); else pline("Wait, %s! That's a %s named %s!", m_monnam(mtmp), youmonst.data->mname, plname); u.ustuck = mtmp; youmonst.m_ap_type = M_AP_NOTHING; youmonst.mappearance = 0; newsym(u.ux,u.uy); return(0); } /* player might be mimicking an object */ if (youmonst.m_ap_type == M_AP_OBJECT && !range2 && foundyou && !u.uswallow) { if (!youseeit) pline("%s %s!", Something, (likes_gold(mtmp->data) && youmonst.mappearance == GOLD_PIECE) ? "tries to pick you up" : "disturbs you"); else pline("Wait, %s! That %s is really %s named %s!", m_monnam(mtmp), mimic_obj_name(&youmonst), an(mons[u.umonnum].mname), plname); if (multi < 0) { /* this should always be the case */ char buf[BUFSZ]; Sprintf(buf, "You appear to be %s again.", Upolyd ? (const char *) an(youmonst.data->mname) : (const char *) "yourself"); unmul(buf); /* immediately stop mimicking */ } return 0; } /* Work out the armor class differential */ tmp = AC_VALUE(u.uac) + 10; /* tmp ~= 0 - 20 */ tmp += mtmp->m_lev; if(multi < 0) tmp += 4; if((Invis && !perceives(mdat)) || !mtmp->mcansee) tmp -= 2; if(mtmp->mtrapped) tmp -= 2; if(tmp <= 0) tmp = 1; /* make eels visible the moment they hit/miss us */ if(mdat->mlet == S_EEL && mtmp->minvis && cansee(mtmp->mx,mtmp->my)) { mtmp->minvis = 0; newsym(mtmp->mx,mtmp->my); } /* Special demon handling code */ if(!mtmp->cham && is_demon(mdat) && !range2 && mtmp->data != &mons[PM_BALROG] && mtmp->data != &mons[PM_SUCCUBUS] && mtmp->data != &mons[PM_INCUBUS]) if(!mtmp->mcan && !rn2(13)) msummon(mtmp); /* Special lycanthrope handling code */ if(!mtmp->cham && is_were(mdat) && !range2) { if(is_human(mdat)) { if(!rn2(5 - (night() * 2)) && !mtmp->mcan) new_were(mtmp); } else if(!rn2(30) && !mtmp->mcan) new_were(mtmp); mdat = mtmp->data; if(!rn2(10) && !mtmp->mcan) { int numseen, numhelp; char buf[BUFSZ], genericwere[BUFSZ]; Strcpy(genericwere, "creature"); numhelp = were_summon(mdat, FALSE, &numseen, genericwere); if (youseeit) { pline("%s summons help!", Monnam(mtmp)); if (numhelp > 0) { if (numseen == 0) You_feel("hemmed in."); } else pline("But none comes."); } else { const char *from_nowhere; if (flags.soundok) { pline("%s %s!", Something, makeplural(growl_sound(mtmp))); from_nowhere = ""; } else from_nowhere = " from nowhere"; if (numhelp > 0) { if (numseen < 1) You_feel("hemmed in."); else { if (numseen == 1) Sprintf(buf, "%s appears", an(genericwere)); else Sprintf(buf, "%s appear", makeplural(genericwere)); pline("%s%s!", upstart(buf), from_nowhere); } } /* else no help came; but you didn't know it tried */ } } } if(u.uinvulnerable) { /* monsters won't attack you */ if(mtmp == u.ustuck) pline("%s loosens its grip slightly.", Monnam(mtmp)); else if(!range2) { if (youseeit || sensemon(mtmp)) pline("%s starts to attack you, but pulls back.", Monnam(mtmp)); else You_feel("%s move nearby.", something); } return (0); } /* Unlike defensive stuff, don't let them use item _and_ attack. */ if(find_offensive(mtmp)) { int foo = use_offensive(mtmp); if (foo != 0) return(foo==1); } for(i = 0; i < NATTK; i++) { sum[i] = 0; mattk = getmattk(mdat, i, sum, &alt_attk); if (u.uswallow && (mattk->aatyp != AT_ENGL)) continue; switch(mattk->aatyp) { case AT_CLAW: /* "hand to hand" attacks */ case AT_KICK: case AT_BITE: case AT_STNG: case AT_TUCH: case AT_BUTT: case AT_TENT: if(!range2 && (!MON_WEP(mtmp) || mtmp->mconf || Conflict || !touch_petrifies(youmonst.data))) { if (foundyou) { if(tmp > (j = rnd(20+i))) { if (mattk->aatyp != AT_KICK || !thick_skinned(youmonst.data)) sum[i] = hitmu(mtmp, mattk); } else missmu(mtmp, (tmp == j), mattk); } else wildmiss(mtmp, mattk); } break; case AT_HUGS: /* automatic if prev two attacks succeed */ /* Note: if displaced, prev attacks never succeeded */ if((!range2 && i>=2 && sum[i-1] && sum[i-2]) || mtmp == u.ustuck) sum[i]= hitmu(mtmp, mattk); break; case AT_GAZE: /* can affect you either ranged or not */ /* Medusa gaze already operated through m_respond in * dochug(); don't gaze more than once per round. */ if (mdat != &mons[PM_MEDUSA]) sum[i] = gazemu(mtmp, mattk); break; case AT_EXPL: /* automatic hit if next to, and aimed at you */ if(!range2) sum[i] = explmu(mtmp, mattk, foundyou); break; case AT_ENGL: if (!range2) { if(foundyou) { if(u.uswallow || tmp > (j = rnd(20+i))) { /* Force swallowing monster to be * displayed even when player is * moving away */ flush_screen(1); sum[i] = gulpmu(mtmp, mattk); } else { missmu(mtmp, (tmp == j), mattk); } } else if (is_animal(mtmp->data)) { pline("%s gulps some air!", Monnam(mtmp)); } else { if (youseeit) pline("%s lunges forward and recoils!", Monnam(mtmp)); else You_hear("a %s nearby.", is_whirly(mtmp->data) ? "rushing noise" : "splat"); } } break; case AT_BREA: if(range2) sum[i] = breamu(mtmp, mattk); /* Note: breamu takes care of displacement */ break; case AT_SPIT: if(range2) sum[i] = spitmu(mtmp, mattk); /* Note: spitmu takes care of displacement */ break; case AT_WEAP: if(range2) { #ifdef REINCARNATION if (!Is_rogue_level(&u.uz)) #endif thrwmu(mtmp); } else { int hittmp = 0; /* Rare but not impossible. Normally the monster * wields when 2 spaces away, but it can be * teleported or whatever.... */ if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) { mtmp->weapon_check = NEED_HTH_WEAPON; /* mon_wield_item resets weapon_check as * appropriate */ if (mon_wield_item(mtmp) != 0) break; } if (foundyou) { otmp = MON_WEP(mtmp); if(otmp) { hittmp = hitval(otmp, &youmonst); tmp += hittmp; mswings(mtmp, otmp); } if(tmp > (j = dieroll = rnd(20+i))) sum[i] = hitmu(mtmp, mattk); else missmu(mtmp, (tmp == j), mattk); /* KMH -- Don't accumulate to-hit bonuses */ if (otmp) tmp -= hittmp; } else wildmiss(mtmp, mattk); } break; case AT_MAGC: if (range2) sum[i] = buzzmu(mtmp, mattk); else { if (foundyou) sum[i] = castmu(mtmp, mattk, TRUE, TRUE); else sum[i] = castmu(mtmp, mattk, TRUE, FALSE); } break; default: /* no attack */ break; } if(flags.botl) bot(); /* give player a chance of waking up before dying -kaa */ if(sum[i] == 1) { /* successful attack */ if (u.usleep && u.usleep < monstermoves && !rn2(10)) { multi = -1; nomovemsg = "The combat suddenly awakens you."; } } if(sum[i] == 2) return 1; /* attacker dead */ if(sum[i] == 3) break; /* attacker teleported, no more attacks */ /* sum[i] == 0: unsuccessful attack */ } return(0); } #endif /* OVL0 */ #ifdef OVLB /* * helper function for some compilers that have trouble with hitmu */ STATIC_OVL void hurtarmor(attk) int attk; { int hurt; switch(attk) { /* 0 is burning, which we should never be called with */ case AD_RUST: hurt = 1; break; case AD_CORR: hurt = 3; break; default: hurt = 2; break; } /* What the following code does: it keeps looping until it * finds a target for the rust monster. * Head, feet, etc... not covered by metal, or covered by * rusty metal, are not targets. However, your body always * is, no matter what covers it. */ while (1) { switch(rn2(5)) { case 0: if (!uarmh || !rust_dmg(uarmh, xname(uarmh), hurt, FALSE, &youmonst)) continue; break; case 1: if (uarmc) { (void)rust_dmg(uarmc, xname(uarmc), hurt, TRUE, &youmonst); break; } /* Note the difference between break and continue; * break means it was hit and didn't rust; continue * means it wasn't a target and though it didn't rust * something else did. */ if (uarm) (void)rust_dmg(uarm, xname(uarm), hurt, TRUE, &youmonst); #ifdef TOURIST else if (uarmu) (void)rust_dmg(uarmu, xname(uarmu), hurt, TRUE, &youmonst); #endif break; case 2: if (!uarms || !rust_dmg(uarms, xname(uarms), hurt, FALSE, &youmonst)) continue; break; case 3: if (!uarmg || !rust_dmg(uarmg, xname(uarmg), hurt, FALSE, &youmonst)) continue; break; case 4: if (!uarmf || !rust_dmg(uarmf, xname(uarmf), hurt, FALSE, &youmonst)) continue; break; } break; /* Out of while loop */ } } #endif /* OVLB */ #ifdef OVL1 STATIC_OVL boolean diseasemu(mdat) struct permonst *mdat; { if (Sick_resistance) { You_feel("a slight illness."); return FALSE; } else { make_sick(Sick ? Sick/3L + 1L : (long)rn1(ACURR(A_CON), 20), mdat->mname, TRUE, SICK_NONVOMITABLE); return TRUE; } } /* check whether slippery clothing protects from hug or wrap attack */ STATIC_OVL boolean u_slip_free(mtmp, mattk) struct monst *mtmp; struct attack *mattk; { struct obj *obj = (uarmc ? uarmc : uarm); #ifdef TOURIST if (!obj) obj = uarmu; #endif if (mattk->adtyp == AD_DRIN) obj = uarmh; /* if your cloak/armor is greased, monster slips off; this protection might fail (33% chance) when the armor is cursed */ if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) && (!obj->cursed || rn2(3))) { pline("%s %s your %s %s!", Monnam(mtmp), (mattk->adtyp == AD_WRAP) ? "slips off of" : "grabs you, but cannot hold onto", obj->greased ? "greased" : "slippery", /* avoid "slippery slippery cloak" for undiscovered oilskin cloak */ (obj->greased || objects[obj->otyp].oc_name_known) ? xname(obj) : cloak_simple_name(obj)); if (obj->greased && !rn2(2)) { pline_The("grease wears off."); obj->greased = 0; update_inventory(); } return TRUE; } return FALSE; } /* armor that sufficiently covers the body might be able to block magic */ int magic_negation(mon) struct monst *mon; { struct obj *armor; int armpro = 0; armor = (mon == &youmonst) ? uarm : which_armor(mon, W_ARM); if (armor && armpro < objects[armor->otyp].a_can) armpro = objects[armor->otyp].a_can; armor = (mon == &youmonst) ? uarmc : which_armor(mon, W_ARMC); if (armor && armpro < objects[armor->otyp].a_can) armpro = objects[armor->otyp].a_can; armor = (mon == &youmonst) ? uarmh : which_armor(mon, W_ARMH); if (armor && armpro < objects[armor->otyp].a_can) armpro = objects[armor->otyp].a_can; /* armor types for shirt, gloves, shoes, and shield don't currently provide any magic cancellation but we might as well be complete */ #ifdef TOURIST armor = (mon == &youmonst) ? uarmu : which_armor(mon, W_ARMU); if (armor && armpro < objects[armor->otyp].a_can) armpro = objects[armor->otyp].a_can; #endif armor = (mon == &youmonst) ? uarmg : which_armor(mon, W_ARMG); if (armor && armpro < objects[armor->otyp].a_can) armpro = objects[armor->otyp].a_can; armor = (mon == &youmonst) ? uarmf : which_armor(mon, W_ARMF); if (armor && armpro < objects[armor->otyp].a_can) armpro = objects[armor->otyp].a_can; armor = (mon == &youmonst) ? uarms : which_armor(mon, W_ARMS); if (armor && armpro < objects[armor->otyp].a_can) armpro = objects[armor->otyp].a_can; #ifdef STEED /* this one is really a stretch... */ armor = (mon == &youmonst) ? 0 : which_armor(mon, W_SADDLE); if (armor && armpro < objects[armor->otyp].a_can) armpro = objects[armor->otyp].a_can; #endif return armpro; } /* * hitmu: monster hits you * returns 2 if monster dies (e.g. "yellow light"), 1 otherwise * 3 if the monster lives but teleported/paralyzed, so it can't keep * attacking you */ STATIC_OVL int hitmu(mtmp, mattk) register struct monst *mtmp; register struct attack *mattk; { register struct permonst *mdat = mtmp->data; register int uncancelled, ptmp; int dmg, armpro, permdmg; char buf[BUFSZ]; struct permonst *olduasmon = youmonst.data; int res; if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); /* If the monster is undetected & hits you, you should know where * the attack came from. */ if(mtmp->mundetected && (hides_under(mdat) || mdat->mlet == S_EEL)) { mtmp->mundetected = 0; if (!(Blind ? Blind_telepat : Unblind_telepat)) { struct obj *obj; const char *what; if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) { if (Blind && !obj->dknown) what = something; else if (is_pool(mtmp->mx, mtmp->my) && !Underwater) what = "the water"; else what = doname(obj); pline("%s was hidden under %s!", Amonnam(mtmp), what); } newsym(mtmp->mx, mtmp->my); } } /* First determine the base damage done */ dmg = d((int)mattk->damn, (int)mattk->damd); if(is_undead(mdat) && midnight()) dmg += d((int)mattk->damn, (int)mattk->damd); /* extra damage */ /* Next a cancellation factor */ /* Use uncancelled when the cancellation factor takes into account certain * armor's special magic protection. Otherwise just use !mtmp->mcan. */ armpro = magic_negation(&youmonst); uncancelled = !mtmp->mcan && ((rn2(3) >= armpro) || !rn2(50)); permdmg = 0; /* Now, adjust damages via resistances or specific attacks */ switch(mattk->adtyp) { case AD_PHYS: if (mattk->aatyp == AT_HUGS && !sticks(youmonst.data)) { if(!u.ustuck && rn2(2)) { if (u_slip_free(mtmp, mattk)) { dmg = 0; } else { u.ustuck = mtmp; pline("%s grabs you!", Monnam(mtmp)); } } else if(u.ustuck == mtmp) { exercise(A_STR, FALSE); You("are being %s.", (mtmp->data == &mons[PM_ROPE_GOLEM]) ? "choked" : "crushed"); } } else { /* hand to hand weapon */ if(mattk->aatyp == AT_WEAP && otmp) { if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])) { dmg = 1; pline("%s hits you with the %s corpse.", Monnam(mtmp), mons[otmp->corpsenm].mname); if (!Stoned) goto do_stone; } dmg += dmgval(otmp, &youmonst); if (dmg <= 0) dmg = 1; if (!(otmp->oartifact && artifact_hit(mtmp, &youmonst, otmp, &dmg,dieroll))) hitmsg(mtmp, mattk); if (!dmg) break; if (u.mh > 1 && u.mh > ((u.uac>0) ? dmg : dmg+u.uac) && objects[otmp->otyp].oc_material == IRON && (u.umonnum==PM_BLACK_PUDDING || u.umonnum==PM_BROWN_PUDDING)) { /* This redundancy necessary because you have to * take the damage _before_ being cloned. */ if (u.uac < 0) dmg += u.uac; if (dmg < 1) dmg = 1; if (dmg > 1) exercise(A_STR, FALSE); u.mh -= dmg; flags.botl = 1; dmg = 0; if(cloneu()) You("divide as %s hits you!",mon_nam(mtmp)); } urustm(mtmp, otmp); } else if (mattk->aatyp != AT_TUCH || dmg != 0 || mtmp != u.ustuck) hitmsg(mtmp, mattk); } break; case AD_DISE: hitmsg(mtmp, mattk); if (!diseasemu(mdat)) dmg = 0; break; case AD_FIRE: hitmsg(mtmp, mattk); if (uncancelled) { pline("You're %s!", on_fire(youmonst.data, mattk)); if (youmonst.data == &mons[PM_STRAW_GOLEM] || youmonst.data == &mons[PM_PAPER_GOLEM]) { You("roast!"); /* KMH -- this is okay with unchanging */ rehumanize(); break; } else if (Fire_resistance) { pline_The("fire doesn't feel hot!"); dmg = 0; } if((int) mtmp->m_lev > rn2(20)) destroy_item(SCROLL_CLASS, AD_FIRE); if((int) mtmp->m_lev > rn2(20)) destroy_item(POTION_CLASS, AD_FIRE); if((int) mtmp->m_lev > rn2(25)) destroy_item(SPBOOK_CLASS, AD_FIRE); burn_away_slime(); } else dmg = 0; break; case AD_COLD: hitmsg(mtmp, mattk); if (uncancelled) { pline("You're covered in frost!"); if (Cold_resistance) { pline_The("frost doesn't seem cold!"); dmg = 0; } if((int) mtmp->m_lev > rn2(20)) destroy_item(POTION_CLASS, AD_COLD); } else dmg = 0; break; case AD_ELEC: hitmsg(mtmp, mattk); if (uncancelled) { You("get zapped!"); if (Shock_resistance) { pline_The("zap doesn't shock you!"); dmg = 0; } if((int) mtmp->m_lev > rn2(20)) destroy_item(WAND_CLASS, AD_ELEC); if((int) mtmp->m_lev > rn2(20)) destroy_item(RING_CLASS, AD_ELEC); } else dmg = 0; break; case AD_SLEE: hitmsg(mtmp, mattk); if (uncancelled && multi >= 0 && !rn2(5)) { if (Sleep_resistance) break; fall_asleep(-rnd(10), TRUE); if (Blind) You("are put to sleep!"); else You("are put to sleep by %s!", mon_nam(mtmp)); } break; case AD_BLND: if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) { if (!Blind) pline("%s blinds you!", Monnam(mtmp)); make_blinded(Blinded+(long)dmg,FALSE); if (!Blind) Your(vision_clears); } dmg = 0; break; case AD_DRST: ptmp = A_STR; goto dopois; case AD_DRDX: ptmp = A_DEX; goto dopois; case AD_DRCO: ptmp = A_CON; dopois: hitmsg(mtmp, mattk); if (uncancelled && !rn2(8)) { Sprintf(buf, "%s %s", s_suffix(Monnam(mtmp)), mpoisons_subj(mtmp, mattk)); poisoned(buf, ptmp, mdat->mname, 30); } break; case AD_DRIN: hitmsg(mtmp, mattk); if (defends(AD_DRIN, uwep) || !has_head(youmonst.data)) { You("don't seem harmed."); /* Not clear what to do for green slimes */ break; } if (u_slip_free(mtmp,mattk)) break; if (uarmh && rn2(8)) { /* not body_part(HEAD) */ Your("helmet blocks the attack to your head."); break; } if (Half_physical_damage) dmg = (dmg+1) / 2; mdamageu(mtmp, dmg); if (!uarmh || uarmh->otyp != DUNCE_CAP) { Your("brain is eaten!"); /* No such thing as mindless players... */ if (ABASE(A_INT) <= ATTRMIN(A_INT)) { int lifesaved = 0; struct obj *wore_amulet = uamul; while(1) { /* avoid looping on "die(y/n)?" */ if (lifesaved && (discover || wizard)) { if (wore_amulet && !uamul) { /* used up AMULET_OF_LIFE_SAVING; still subject to dying from brainlessness */ wore_amulet = 0; } else { /* explicitly chose not to die; arbitrarily boost intelligence */ ABASE(A_INT) = ATTRMIN(A_INT) + 2; You_feel("like a scarecrow."); break; } } if (lifesaved) pline("Unfortunately your brain is still gone."); else Your("last thought fades away."); killer = "brainlessness"; killer_format = KILLED_BY; done(DIED); lifesaved++; } } } /* adjattrib gives dunce cap message when appropriate */ (void) adjattrib(A_INT, -rnd(2), FALSE); forget_levels(25); /* lose memory of 25% of levels */ forget_objects(25); /* lose memory of 25% of objects */ exercise(A_WIS, FALSE); break; case AD_PLYS: hitmsg(mtmp, mattk); if (uncancelled && multi >= 0 && !rn2(3)) { if (Free_action) { You("momentarily stiffen."); } else { if (Blind) You("are frozen!"); else You("are frozen by %s!", mon_nam(mtmp)); nomovemsg = 0; /* default: "you can move again" */ nomul(-rnd(10)); exercise(A_DEX, FALSE); } } break; case AD_DRLI: hitmsg(mtmp, mattk); if (uncancelled && !rn2(3) && !Drain_resistance) { losexp("life drainage"); } break; case AD_LEGS: { register long side = rn2(2) ? RIGHT_SIDE : LEFT_SIDE; const char *sidestr = (side == RIGHT_SIDE) ? "right" : "left"; /* This case is too obvious to ignore, but Nethack is not in * general very good at considering height--most short monsters * still _can_ attack you when you're flying or mounted. * [FIXME: why can't a flying attacker overcome this?] */ if ( #ifdef STEED u.usteed || #endif Levitation || Flying) { pline("%s tries to reach your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); dmg = 0; } else if (mtmp->mcan) { pline("%s nuzzles against your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); dmg = 0; } else { if (uarmf) { if (rn2(2) && (uarmf->otyp == LOW_BOOTS || uarmf->otyp == IRON_SHOES)) pline("%s pricks the exposed part of your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); else if (!rn2(5)) pline("%s pricks through your %s boot!", Monnam(mtmp), sidestr); else { pline("%s scratches your %s boot!", Monnam(mtmp), sidestr); dmg = 0; break; } } else pline("%s pricks your %s %s!", Monnam(mtmp), sidestr, body_part(LEG)); set_wounded_legs(side, rnd(60-ACURR(A_DEX))); exercise(A_STR, FALSE); exercise(A_DEX, FALSE); } break; } case AD_STON: /* cockatrice */ hitmsg(mtmp, mattk); if(!rn2(3)) { if (mtmp->mcan) { if (flags.soundok) You_hear("a cough from %s!", mon_nam(mtmp)); } else { if (flags.soundok) You_hear("%s hissing!", s_suffix(mon_nam(mtmp))); if(!rn2(10) || (flags.moonphase == NEW_MOON && !have_lizard())) { do_stone: if (!Stoned && !Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { Stoned = 5; delayed_killer = mtmp->data->mname; if (mtmp->data->geno & G_UNIQ) { if (!type_is_pname(mtmp->data)) { static char kbuf[BUFSZ]; /* "the" buffer may be reallocated */ Strcpy(kbuf, the(delayed_killer)); delayed_killer = kbuf; } killer_format = KILLED_BY; } else killer_format = KILLED_BY_AN; return(1); /* You("turn to stone..."); */ /* done_in_by(mtmp); */ } } } } break; case AD_STCK: hitmsg(mtmp, mattk); if (uncancelled && !u.ustuck && !sticks(youmonst.data)) u.ustuck = mtmp; break; case AD_WRAP: if ((!mtmp->mcan || u.ustuck == mtmp) && !sticks(youmonst.data)) { if (!u.ustuck && !rn2(10)) { if (u_slip_free(mtmp, mattk)) { dmg = 0; } else { pline("%s swings itself around you!", Monnam(mtmp)); u.ustuck = mtmp; } } else if(u.ustuck == mtmp) { if (is_pool(mtmp->mx,mtmp->my) && !Swimming && !Amphibious) { boolean moat = (levl[mtmp->mx][mtmp->my].typ != POOL) && (levl[mtmp->mx][mtmp->my].typ != WATER) && !Is_medusa_level(&u.uz) && !Is_waterlevel(&u.uz); pline("%s drowns you...", Monnam(mtmp)); killer_format = KILLED_BY_AN; Sprintf(buf, "%s by %s", moat ? "moat" : "pool of water", an(mtmp->data->mname)); killer = buf; done(DROWNING); } else if(mattk->aatyp == AT_HUGS) You("are being crushed."); } else { dmg = 0; if(flags.verbose) pline("%s brushes against your %s.", Monnam(mtmp), body_part(LEG)); } } else dmg = 0; break; case AD_WERE: hitmsg(mtmp, mattk); if (uncancelled && !rn2(4) && u.ulycn == NON_PM && !Protection_from_shape_changers && !defends(AD_WERE,uwep)) { You_feel("feverish."); exercise(A_CON, FALSE); u.ulycn = monsndx(mdat); } break; case AD_SGLD: hitmsg(mtmp, mattk); if (youmonst.data->mlet == mdat->mlet) break; if(!mtmp->mcan) stealgold(mtmp); break; case AD_SITM: /* for now these are the same */ case AD_SEDU: if (is_animal(mtmp->data)) { hitmsg(mtmp, mattk); if (mtmp->mcan) break; /* Continue below */ } else if (dmgtype(youmonst.data, AD_SEDU) #ifdef SEDUCE || dmgtype(youmonst.data, AD_SSEX) #endif ) { pline("%s %s.", Monnam(mtmp), mtmp->minvent ? "brags about the goods some dungeon explorer provided" : "makes some remarks about how difficult theft is lately"); if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); return 3; } else if (mtmp->mcan) { if (!Blind) { pline("%s tries to %s you, but you seem %s.", Adjmonnam(mtmp, "plain"), flags.female ? "charm" : "seduce", flags.female ? "unaffected" : "uninterested"); } if(rn2(3)) { if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); return 3; } break; } buf[0] = '\0'; switch (steal(mtmp, buf)) { case -1: return 2; case 0: break; default: if (!is_animal(mtmp->data) && !tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); if (is_animal(mtmp->data) && *buf) { if (canseemon(mtmp)) pline("%s tries to %s away with %s.", Monnam(mtmp), locomotion(mtmp->data, "run"), buf); } monflee(mtmp, 0, FALSE, FALSE); return 3; } break; #ifdef SEDUCE case AD_SSEX: if(could_seduce(mtmp, &youmonst, mattk) == 1 && !mtmp->mcan) if (doseduce(mtmp)) return 3; break; #endif case AD_SAMU: hitmsg(mtmp, mattk); /* when the Wiz hits, 1/20 steals the amulet */ if (u.uhave.amulet || u.uhave.bell || u.uhave.book || u.uhave.menorah || u.uhave.questart) /* carrying the Quest Artifact */ if (!rn2(20)) stealamulet(mtmp); break; case AD_TLPT: hitmsg(mtmp, mattk); if (uncancelled) { if(flags.verbose) Your("position suddenly seems very uncertain!"); tele(); } break; case AD_RUST: hitmsg(mtmp, mattk); if (mtmp->mcan) break; if (u.umonnum == PM_IRON_GOLEM) { You("rust!"); /* KMH -- this is okay with unchanging */ rehumanize(); break; } hurtarmor(AD_RUST); break; case AD_CORR: hitmsg(mtmp, mattk); if (mtmp->mcan) break; hurtarmor(AD_CORR); break; case AD_DCAY: hitmsg(mtmp, mattk); if (mtmp->mcan) break; if (u.umonnum == PM_WOOD_GOLEM || u.umonnum == PM_LEATHER_GOLEM) { You("rot!"); /* KMH -- this is okay with unchanging */ rehumanize(); break; } hurtarmor(AD_DCAY); break; case AD_HEAL: /* a cancelled nurse is just an ordinary monster */ if (mtmp->mcan) { hitmsg(mtmp, mattk); break; } if(!uwep #ifdef TOURIST && !uarmu #endif && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf) { boolean goaway = FALSE; pline("%s hits! (I hope you don't mind.)", Monnam(mtmp)); if (Upolyd) { u.mh += rnd(7); if (!rn2(7)) { /* no upper limit necessary; effect is temporary */ u.mhmax++; if (!rn2(13)) goaway = TRUE; } if (u.mh > u.mhmax) u.mh = u.mhmax; } else { u.uhp += rnd(7); if (!rn2(7)) { /* hard upper limit via nurse care: 25 * ulevel */ if (u.uhpmax < 5 * u.ulevel + d(2 * u.ulevel, 10)) u.uhpmax++; if (!rn2(13)) goaway = TRUE; } if (u.uhp > u.uhpmax) u.uhp = u.uhpmax; } if (!rn2(3)) exercise(A_STR, TRUE); if (!rn2(3)) exercise(A_CON, TRUE); if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL); flags.botl = 1; if (goaway) { mongone(mtmp); return 2; } else if (!rn2(33)) { if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); monflee(mtmp, d(3, 6), TRUE, FALSE); return 3; } dmg = 0; } else { if (Role_if(PM_HEALER)) { if (flags.soundok && !(moves % 5)) verbalize("Doc, I can't help you unless you cooperate."); dmg = 0; } else hitmsg(mtmp, mattk); } break; case AD_CURS: hitmsg(mtmp, mattk); if(!night() && mdat == &mons[PM_GREMLIN]) break; if(!mtmp->mcan && !rn2(10)) { if (flags.soundok) { if (Blind) You_hear("laughter."); else pline("%s chuckles.", Monnam(mtmp)); } if (u.umonnum == PM_CLAY_GOLEM) { pline("Some writing vanishes from your head!"); /* KMH -- this is okay with unchanging */ rehumanize(); break; } attrcurse(); } break; case AD_STUN: hitmsg(mtmp, mattk); if(!mtmp->mcan && !rn2(4)) { make_stunned(HStun + dmg, TRUE); dmg /= 2; } break; case AD_ACID: hitmsg(mtmp, mattk); if (!mtmp->mcan && !rn2(3)) if (Acid_resistance) { pline("You're covered in acid, but it seems harmless."); dmg = 0; } else { pline("You're covered in acid! It burns!"); exercise(A_STR, FALSE); } else dmg = 0; break; case AD_SLOW: hitmsg(mtmp, mattk); if (uncancelled && HFast && !defends(AD_SLOW, uwep) && !rn2(4)) u_slow_down(); break; case AD_DREN: hitmsg(mtmp, mattk); if (uncancelled && !rn2(4)) drain_en(dmg); dmg = 0; break; case AD_CONF: hitmsg(mtmp, mattk); if(!mtmp->mcan && !rn2(4) && !mtmp->mspec_used) { mtmp->mspec_used = mtmp->mspec_used + (dmg + rn2(6)); if(Confusion) You("are getting even more confused."); else You("are getting confused."); make_confused(HConfusion + dmg, FALSE); } dmg = 0; break; case AD_DETH: pline("%s reaches out with its deadly touch.", Monnam(mtmp)); if (is_undead(youmonst.data)) { /* Still does normal damage */ pline("Was that the touch of death?"); break; } switch (rn2(20)) { case 19: case 18: case 17: if (!Antimagic) { killer_format = KILLED_BY_AN; killer = "touch of death"; done(DIED); dmg = 0; break; } /* else FALLTHRU */ default: /* case 16: ... case 5: */ You_feel("your life force draining away..."); permdmg = 1; /* actual damage done below */ break; case 4: case 3: case 2: case 1: case 0: if (Antimagic) shieldeff(u.ux, u.uy); pline("Lucky for you, it didn't work!"); dmg = 0; break; } break; case AD_PEST: pline("%s reaches out, and you feel fever and chills.", Monnam(mtmp)); (void) diseasemu(mdat); /* plus the normal damage */ break; case AD_FAMN: pline("%s reaches out, and your body shrivels.", Monnam(mtmp)); exercise(A_CON, FALSE); if (!is_fainted()) morehungry(rn1(40,40)); /* plus the normal damage */ break; case AD_SLIM: hitmsg(mtmp, mattk); if (!uncancelled) break; if (flaming(youmonst.data)) { pline_The("slime burns away!"); dmg = 0; } else if (Unchanging || youmonst.data == &mons[PM_GREEN_SLIME]) { You("are unaffected."); dmg = 0; } else if (!Slimed) { You("don't feel very well."); Slimed = 10L; flags.botl = 1; killer_format = KILLED_BY_AN; delayed_killer = mtmp->data->mname; } else pline("Yuck!"); break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ hitmsg(mtmp, mattk); /* uncancelled is sufficient enough; please don't make this attack less frequent */ if (uncancelled) { struct obj *obj = some_armor(&youmonst); if (drain_item(obj)) { Your("%s less effective.", aobjnam(obj, "seem")); } } break; default: dmg = 0; break; } if(u.uhp < 1) done_in_by(mtmp); /* Negative armor class reduces damage done instead of fully protecting * against hits. */ if (dmg && u.uac < 0) { dmg -= rnd(-u.uac); if (dmg < 1) dmg = 1; } if(dmg) { if (Half_physical_damage /* Mitre of Holiness */ || (Role_if(PM_PRIEST) && uarmh && is_quest_artifact(uarmh) && (is_undead(mtmp->data) || is_demon(mtmp->data)))) dmg = (dmg+1) / 2; if (permdmg) { /* Death's life force drain */ int lowerlimit, *hpmax_p; /* * Apply some of the damage to permanent hit points: * polymorphed 100% against poly'd hpmax * hpmax > 25*lvl 100% against normal hpmax * hpmax > 10*lvl 50..100% * hpmax > 5*lvl 25..75% * otherwise 0..50% * Never reduces hpmax below 1 hit point per level. */ permdmg = rn2(dmg / 2 + 1); if (Upolyd || u.uhpmax > 25 * u.ulevel) permdmg = dmg; else if (u.uhpmax > 10 * u.ulevel) permdmg += dmg / 2; else if (u.uhpmax > 5 * u.ulevel) permdmg += dmg / 4; if (Upolyd) { hpmax_p = &u.mhmax; /* [can't use youmonst.m_lev] */ lowerlimit = min((int)youmonst.data->mlevel, u.ulevel); } else { hpmax_p = &u.uhpmax; lowerlimit = u.ulevel; } if (*hpmax_p - permdmg > lowerlimit) *hpmax_p -= permdmg; else if (*hpmax_p > lowerlimit) *hpmax_p = lowerlimit; else /* unlikely... */ ; /* already at or below minimum threshold; do nothing */ flags.botl = 1; } mdamageu(mtmp, dmg); } if (dmg) res = passiveum(olduasmon, mtmp, mattk); else res = 1; stop_occupation(); return res; } #endif /* OVL1 */ #ifdef OVLB STATIC_OVL int gulpmu(mtmp, mattk) /* monster swallows you, or damage if u.uswallow */ register struct monst *mtmp; register struct attack *mattk; { struct trap *t = t_at(u.ux, u.uy); int tmp = d((int)mattk->damn, (int)mattk->damd); int tim_tmp; register struct obj *otmp2; int i; if (!u.uswallow) { /* swallows you */ if (youmonst.data->msize >= MZ_HUGE) return(0); if ((t && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT))) && sobj_at(BOULDER, u.ux, u.uy)) return(0); if (Punished) unplacebc(); /* ball&chain go away */ remove_monster(mtmp->mx, mtmp->my); mtmp->mtrapped = 0; /* no longer on old trap */ place_monster(mtmp, u.ux, u.uy); u.ustuck = mtmp; newsym(mtmp->mx,mtmp->my); #ifdef STEED if (is_animal(mtmp->data) && u.usteed) { char buf[BUFSZ]; /* Too many quirks presently if hero and steed * are swallowed. Pretend purple worms don't * like horses for now :-) */ Strcpy(buf, mon_nam(u.usteed)); pline ("%s lunges forward and plucks you off %s!", Monnam(mtmp), buf); dismount_steed(DISMOUNT_ENGULFED); } else #endif pline("%s engulfs you!", Monnam(mtmp)); stop_occupation(); reset_occupations(); /* behave as if you had moved */ if (u.utrap) { You("are released from the %s!", u.utraptype==TT_WEB ? "web" : "trap"); u.utrap = 0; } i = number_leashed(); if (i > 0) { const char *s = (i > 1) ? "leashes" : "leash"; pline_The("%s %s loose.", s, vtense(s, "snap")); unleash_all(); } if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) { minstapetrify(mtmp, TRUE); if (mtmp->mhp > 0) return 0; else return 2; } display_nhwindow(WIN_MESSAGE, FALSE); vision_recalc(2); /* hero can't see anything */ u.uswallow = 1; /* u.uswldtim always set > 1 */ tim_tmp = 25 - (int)mtmp->m_lev; if (tim_tmp > 0) tim_tmp = rnd(tim_tmp) / 2; else if (tim_tmp < 0) tim_tmp = -(rnd(-tim_tmp) / 2); tim_tmp += -u.uac + 10; u.uswldtim = (unsigned)((tim_tmp < 2) ? 2 : tim_tmp); swallowed(1); for (otmp2 = invent; otmp2; otmp2 = otmp2->nobj) (void) snuff_lit(otmp2); } if (mtmp != u.ustuck) return(0); if (u.uswldtim > 0) u.uswldtim -= 1; switch(mattk->adtyp) { case AD_DGST: if (Slow_digestion) { /* Messages are handled below */ u.uswldtim = 0; tmp = 0; } else if (u.uswldtim == 0) { pline("%s totally digests you!", Monnam(mtmp)); tmp = u.uhp; if (Half_physical_damage) tmp *= 2; /* sorry */ } else { pline("%s%s digests you!", Monnam(mtmp), (u.uswldtim == 2) ? " thoroughly" : (u.uswldtim == 1) ? " utterly" : ""); exercise(A_STR, FALSE); } break; case AD_PHYS: if (mtmp->data == &mons[PM_FOG_CLOUD]) { You("are laden with moisture and %s", flaming(youmonst.data) ? "are smoldering out!" : Breathless ? "find it mildly uncomfortable." : amphibious(youmonst.data) ? "feel comforted." : "can barely breathe!"); /* NB: Amphibious includes Breathless */ if (Amphibious && !flaming(youmonst.data)) tmp = 0; } else { You("are pummeled with debris!"); exercise(A_STR, FALSE); } break; case AD_ACID: if (Acid_resistance) { You("are covered with a seemingly harmless goo."); tmp = 0; } else { if (Hallucination) pline("Ouch! You've been slimed!"); else You("are covered in slime! It burns!"); exercise(A_STR, FALSE); } break; case AD_BLND: if (can_blnd(mtmp, &youmonst, mattk->aatyp, (struct obj*)0)) { if(!Blind) { You_cant("see in here!"); make_blinded((long)tmp,FALSE); if (!Blind) Your(vision_clears); } else /* keep him blind until disgorged */ make_blinded(Blinded+1,FALSE); } tmp = 0; break; case AD_ELEC: if(!mtmp->mcan && rn2(2)) { pline_The("air around you crackles with electricity."); if (Shock_resistance) { shieldeff(u.ux, u.uy); You("seem unhurt."); ugolemeffects(AD_ELEC,tmp); tmp = 0; } } else tmp = 0; break; case AD_COLD: if(!mtmp->mcan && rn2(2)) { if (Cold_resistance) { shieldeff(u.ux, u.uy); You_feel("mildly chilly."); ugolemeffects(AD_COLD,tmp); tmp = 0; } else You("are freezing to death!"); } else tmp = 0; break; case AD_FIRE: if(!mtmp->mcan && rn2(2)) { if (Fire_resistance) { shieldeff(u.ux, u.uy); You_feel("mildly hot."); ugolemeffects(AD_FIRE,tmp); tmp = 0; } else You("are burning to a crisp!"); burn_away_slime(); } else tmp = 0; break; case AD_DISE: if (!diseasemu(mtmp->data)) tmp = 0; break; default: tmp = 0; break; } if (Half_physical_damage) tmp = (tmp+1) / 2; mdamageu(mtmp, tmp); if (tmp) stop_occupation(); if (touch_petrifies(youmonst.data) && !resists_ston(mtmp)) { pline("%s very hurriedly %s you!", Monnam(mtmp), is_animal(mtmp->data)? "regurgitates" : "expels"); expels(mtmp, mtmp->data, FALSE); } else if (!u.uswldtim || youmonst.data->msize >= MZ_HUGE) { You("get %s!", is_animal(mtmp->data)? "regurgitated" : "expelled"); if (flags.verbose && (is_animal(mtmp->data) || (dmgtype(mtmp->data, AD_DGST) && Slow_digestion))) pline("Obviously %s doesn't like your taste.", mon_nam(mtmp)); expels(mtmp, mtmp->data, FALSE); } return(1); } STATIC_OVL int explmu(mtmp, mattk, ufound) /* monster explodes in your face */ register struct monst *mtmp; register struct attack *mattk; boolean ufound; { if (mtmp->mcan) return(0); if (!ufound) pline("%s explodes at a spot in %s!", canseemon(mtmp) ? Monnam(mtmp) : "It", levl[mtmp->mux][mtmp->muy].typ == WATER ? "empty water" : "thin air"); else { register int tmp = d((int)mattk->damn, (int)mattk->damd); register boolean not_affected = defends((int)mattk->adtyp, uwep); hitmsg(mtmp, mattk); switch (mattk->adtyp) { case AD_COLD: not_affected |= Cold_resistance; goto common; case AD_FIRE: not_affected |= Fire_resistance; goto common; case AD_ELEC: not_affected |= Shock_resistance; common: if (!not_affected) { if (ACURR(A_DEX) > rnd(20)) { You("duck some of the blast."); tmp = (tmp+1) / 2; } else { if (flags.verbose) You("get blasted!"); } if (mattk->adtyp == AD_FIRE) burn_away_slime(); if (Half_physical_damage) tmp = (tmp+1) / 2; mdamageu(mtmp, tmp); } break; case AD_BLND: not_affected = resists_blnd(&youmonst); if (!not_affected) { /* sometimes you're affected even if it's invisible */ if (mon_visible(mtmp) || (rnd(tmp /= 2) > u.ulevel)) { You("are blinded by a blast of light!"); make_blinded((long)tmp, FALSE); if (!Blind) Your(vision_clears); } else if (flags.verbose) You("get the impression it was not terribly bright."); } break; case AD_HALU: not_affected |= Blind || (u.umonnum == PM_BLACK_LIGHT || u.umonnum == PM_VIOLET_FUNGUS || dmgtype(youmonst.data, AD_STUN)); if (!not_affected) { boolean chg; if (!Hallucination) You("are caught in a blast of kaleidoscopic light!"); chg = make_hallucinated(HHallucination + (long)tmp,FALSE,0L); You("%s.", chg ? "are freaked out" : "seem unaffected"); } break; default: break; } if (not_affected) { You("seem unaffected by it."); ugolemeffects((int)mattk->adtyp, tmp); } } mondead(mtmp); wake_nearto(mtmp->mx, mtmp->my, 7*7); if (mtmp->mhp > 0) return(0); return(2); /* it dies */ } int gazemu(mtmp, mattk) /* monster gazes at you */ register struct monst *mtmp; register struct attack *mattk; { switch(mattk->adtyp) { case AD_STON: if (mtmp->mcan || !mtmp->mcansee) { if (!canseemon(mtmp)) break; /* silently */ pline("%s %s.", Monnam(mtmp), (mtmp->data == &mons[PM_MEDUSA] && mtmp->mcan) ? "doesn't look all that ugly" : "gazes ineffectually"); break; } if (Reflecting && couldsee(mtmp->mx, mtmp->my) && mtmp->data == &mons[PM_MEDUSA]) { /* hero has line of sight to Medusa and she's not blind */ boolean useeit = canseemon(mtmp); if (useeit) (void) ureflects("%s gaze is reflected by your %s.", s_suffix(Monnam(mtmp))); if (mon_reflects(mtmp, !useeit ? (char *)0 : "The gaze is reflected away by %s %s!")) break; if (!m_canseeu(mtmp)) { /* probably you're invisible */ if (useeit) pline( "%s doesn't seem to notice that %s gaze was reflected.", Monnam(mtmp), mhis(mtmp)); break; } if (useeit) pline("%s is turned to stone!", Monnam(mtmp)); stoned = TRUE; killed(mtmp); if (mtmp->mhp > 0) break; return 2; } if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && !Stone_resistance) { You("meet %s gaze.", s_suffix(mon_nam(mtmp))); stop_occupation(); if(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) break; You("turn to stone..."); killer_format = KILLED_BY; killer = mtmp->data->mname; done(STONING); } break; case AD_CONF: if(!mtmp->mcan && canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) { int conf = d(3,4); mtmp->mspec_used = mtmp->mspec_used + (conf + rn2(6)); if(!Confusion) pline("%s gaze confuses you!", s_suffix(Monnam(mtmp))); else You("are getting more and more confused."); make_confused(HConfusion + conf, FALSE); stop_occupation(); } break; case AD_STUN: if(!mtmp->mcan && canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) { int stun = d(2,6); mtmp->mspec_used = mtmp->mspec_used + (stun + rn2(6)); pline("%s stares piercingly at you!", Monnam(mtmp)); make_stunned(HStun + stun, TRUE); stop_occupation(); } break; case AD_BLND: if (!mtmp->mcan && canseemon(mtmp) && !resists_blnd(&youmonst) && distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) { int blnd = d((int)mattk->damn, (int)mattk->damd); You("are blinded by %s radiance!", s_suffix(mon_nam(mtmp))); make_blinded((long)blnd,FALSE); stop_occupation(); /* not blind at this point implies you're wearing the Eyes of the Overworld; make them block this particular stun attack too */ if (!Blind) Your(vision_clears); else make_stunned((long)d(1,3),TRUE); } break; case AD_FIRE: if (!mtmp->mcan && canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && !mtmp->mspec_used && rn2(5)) { int dmg = d(2,6); pline("%s attacks you with a fiery gaze!", Monnam(mtmp)); stop_occupation(); if (Fire_resistance) { pline_The("fire doesn't feel hot!"); dmg = 0; } burn_away_slime(); if ((int) mtmp->m_lev > rn2(20)) destroy_item(SCROLL_CLASS, AD_FIRE); if ((int) mtmp->m_lev > rn2(20)) destroy_item(POTION_CLASS, AD_FIRE); if ((int) mtmp->m_lev > rn2(25)) destroy_item(SPBOOK_CLASS, AD_FIRE); if (dmg) mdamageu(mtmp, dmg); } break; #ifdef PM_BEHOLDER /* work in progress */ case AD_SLEE: if(!mtmp->mcan && canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my) && mtmp->mcansee && multi >= 0 && !rn2(5) && !Sleep_resistance) { fall_asleep(-rnd(10), TRUE); pline("%s gaze makes you very sleepy...", s_suffix(Monnam(mtmp))); } break; case AD_SLOW: if(!mtmp->mcan && canseemon(mtmp) && mtmp->mcansee && (HFast & (INTRINSIC|TIMEOUT)) && !defends(AD_SLOW, uwep) && !rn2(4)) u_slow_down(); stop_occupation(); break; #endif default: impossible("Gaze attack %d?", mattk->adtyp); break; } return(0); } #endif /* OVLB */ #ifdef OVL1 void mdamageu(mtmp, n) /* mtmp hits you for n points damage */ register struct monst *mtmp; register int n; { flags.botl = 1; if (Upolyd) { u.mh -= n; if (u.mh < 1) rehumanize(); } else { u.uhp -= n; if(u.uhp < 1) done_in_by(mtmp); } } #endif /* OVL1 */ #ifdef OVLB STATIC_OVL void urustm(mon, obj) register struct monst *mon; register struct obj *obj; { boolean vis; boolean is_acid; if (!mon || !obj) return; /* just in case */ if (dmgtype(youmonst.data, AD_CORR)) is_acid = TRUE; else if (dmgtype(youmonst.data, AD_RUST)) is_acid = FALSE; else return; vis = cansee(mon->mx, mon->my); if ((is_acid ? is_corrodeable(obj) : is_rustprone(obj)) && (is_acid ? obj->oeroded2 : obj->oeroded) < MAX_ERODE) { if (obj->greased || obj->oerodeproof || (obj->blessed && rn2(3))) { if (vis) pline("Somehow, %s weapon is not affected.", s_suffix(mon_nam(mon))); if (obj->greased && !rn2(2)) obj->greased = 0; } else { if (vis) pline("%s %s%s!", s_suffix(Monnam(mon)), aobjnam(obj, (is_acid ? "corrode" : "rust")), (is_acid ? obj->oeroded2 : obj->oeroded) ? " further" : ""); if (is_acid) obj->oeroded2++; else obj->oeroded++; } } } #endif /* OVLB */ #ifdef OVL1 int could_seduce(magr,mdef,mattk) struct monst *magr, *mdef; struct attack *mattk; /* returns 0 if seduction impossible, * 1 if fine, * 2 if wrong gender for nymph */ { register struct permonst *pagr; boolean agrinvis, defperc; xchar genagr, gendef; if (is_animal(magr->data)) return (0); if(magr == &youmonst) { pagr = youmonst.data; agrinvis = (Invis != 0); genagr = poly_gender(); } else { pagr = magr->data; agrinvis = magr->minvis; genagr = gender(magr); } if(mdef == &youmonst) { defperc = (See_invisible != 0); gendef = poly_gender(); } else { defperc = perceives(mdef->data); gendef = gender(mdef); } if(agrinvis && !defperc #ifdef SEDUCE && mattk && mattk->adtyp != AD_SSEX #endif ) return 0; if(pagr->mlet != S_NYMPH && ((pagr != &mons[PM_INCUBUS] && pagr != &mons[PM_SUCCUBUS]) #ifdef SEDUCE || (mattk && mattk->adtyp != AD_SSEX) #endif )) return 0; if(genagr == 1 - gendef) return 1; else return (pagr->mlet == S_NYMPH) ? 2 : 0; } #endif /* OVL1 */ #ifdef OVLB #ifdef SEDUCE /* Returns 1 if monster teleported */ int doseduce(mon) register struct monst *mon; { register struct obj *ring, *nring; boolean fem = (mon->data == &mons[PM_SUCCUBUS]); /* otherwise incubus */ char qbuf[QBUFSZ]; if (mon->mcan || mon->mspec_used) { pline("%s acts as though %s has got a %sheadache.", Monnam(mon), mhe(mon), mon->mcan ? "severe " : ""); return 0; } if (unconscious()) { pline("%s seems dismayed at your lack of response.", Monnam(mon)); return 0; } if (Blind) pline("It caresses you..."); else You_feel("very attracted to %s.", mon_nam(mon)); for(ring = invent; ring; ring = nring) { nring = ring->nobj; if (ring->otyp != RIN_ADORNMENT) continue; if (fem) { if (rn2(20) < ACURR(A_CHA)) { Sprintf(qbuf, "\"That %s looks pretty. May I have it?\"", safe_qbuf("",sizeof("\"That looks pretty. May I have it?\""), xname(ring), simple_typename(ring->otyp), "ring")); makeknown(RIN_ADORNMENT); if (yn(qbuf) == 'n') continue; } else pline("%s decides she'd like your %s, and takes it.", Blind ? "She" : Monnam(mon), xname(ring)); makeknown(RIN_ADORNMENT); if (ring==uleft || ring==uright) Ring_gone(ring); if (ring==uwep) setuwep((struct obj *)0); if (ring==uswapwep) setuswapwep((struct obj *)0); if (ring==uquiver) setuqwep((struct obj *)0); freeinv(ring); (void) mpickobj(mon,ring); } else { char buf[BUFSZ]; if (uleft && uright && uleft->otyp == RIN_ADORNMENT && uright->otyp==RIN_ADORNMENT) break; if (ring==uleft || ring==uright) continue; if (rn2(20) < ACURR(A_CHA)) { Sprintf(qbuf,"\"That %s looks pretty. Would you wear it for me?\"", safe_qbuf("", sizeof("\"That looks pretty. Would you wear it for me?\""), xname(ring), simple_typename(ring->otyp), "ring")); makeknown(RIN_ADORNMENT); if (yn(qbuf) == 'n') continue; } else { pline("%s decides you'd look prettier wearing your %s,", Blind ? "He" : Monnam(mon), xname(ring)); pline("and puts it on your finger."); } makeknown(RIN_ADORNMENT); if (!uright) { pline("%s puts %s on your right %s.", Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND)); setworn(ring, RIGHT_RING); } else if (!uleft) { pline("%s puts %s on your left %s.", Blind ? "He" : Monnam(mon), the(xname(ring)), body_part(HAND)); setworn(ring, LEFT_RING); } else if (uright && uright->otyp != RIN_ADORNMENT) { Strcpy(buf, xname(uright)); pline("%s replaces your %s with your %s.", Blind ? "He" : Monnam(mon), buf, xname(ring)); Ring_gone(uright); setworn(ring, RIGHT_RING); } else if (uleft && uleft->otyp != RIN_ADORNMENT) { Strcpy(buf, xname(uleft)); pline("%s replaces your %s with your %s.", Blind ? "He" : Monnam(mon), buf, xname(ring)); Ring_gone(uleft); setworn(ring, LEFT_RING); } else impossible("ring replacement"); Ring_on(ring); prinv((char *)0, ring, 0L); } } if (!uarmc && !uarmf && !uarmg && !uarms && !uarmh #ifdef TOURIST && !uarmu #endif ) pline("%s murmurs sweet nothings into your ear.", Blind ? (fem ? "She" : "He") : Monnam(mon)); else pline("%s murmurs in your ear, while helping you undress.", Blind ? (fem ? "She" : "He") : Monnam(mon)); mayberem(uarmc, cloak_simple_name(uarmc)); if(!uarmc) mayberem(uarm, "suit"); mayberem(uarmf, "boots"); if(!uwep || !welded(uwep)) mayberem(uarmg, "gloves"); mayberem(uarms, "shield"); mayberem(uarmh, "helmet"); #ifdef TOURIST if(!uarmc && !uarm) mayberem(uarmu, "shirt"); #endif if (uarm || uarmc) { verbalize("You're such a %s; I wish...", flags.female ? "sweet lady" : "nice guy"); if (!tele_restrict(mon)) (void) rloc(mon, FALSE); return 1; } if (u.ualign.type == A_CHAOTIC) adjalign(1); /* by this point you have discovered mon's identity, blind or not... */ pline("Time stands still while you and %s lie in each other's arms...", noit_mon_nam(mon)); if (rn2(35) > ACURR(A_CHA) + ACURR(A_INT)) { /* Don't bother with mspec_used here... it didn't get tired! */ pline("%s seems to have enjoyed it more than you...", noit_Monnam(mon)); switch (rn2(5)) { case 0: You_feel("drained of energy."); u.uen = 0; u.uenmax -= rnd(Half_physical_damage ? 5 : 10); exercise(A_CON, FALSE); if (u.uenmax < 0) u.uenmax = 0; break; case 1: You("are down in the dumps."); (void) adjattrib(A_CON, -1, TRUE); exercise(A_CON, FALSE); flags.botl = 1; break; case 2: Your("senses are dulled."); (void) adjattrib(A_WIS, -1, TRUE); exercise(A_WIS, FALSE); flags.botl = 1; break; case 3: if (!resists_drli(&youmonst)) { You_feel("out of shape."); losexp("overexertion"); } else { You("have a curious feeling..."); } break; case 4: { int tmp; You_feel("exhausted."); exercise(A_STR, FALSE); tmp = rn1(10, 6); if(Half_physical_damage) tmp = (tmp+1) / 2; losehp(tmp, "exhaustion", KILLED_BY); break; } } } else { mon->mspec_used = rnd(100); /* monster is worn out */ You("seem to have enjoyed it more than %s...", noit_mon_nam(mon)); switch (rn2(5)) { case 0: You_feel("raised to your full potential."); exercise(A_CON, TRUE); u.uen = (u.uenmax += rnd(5)); break; case 1: You_feel("good enough to do it again."); (void) adjattrib(A_CON, 1, TRUE); exercise(A_CON, TRUE); flags.botl = 1; break; case 2: You("will always remember %s...", noit_mon_nam(mon)); (void) adjattrib(A_WIS, 1, TRUE); exercise(A_WIS, TRUE); flags.botl = 1; break; case 3: pline("That was a very educational experience."); pluslvl(FALSE); exercise(A_WIS, TRUE); break; case 4: You_feel("restored to health!"); u.uhp = u.uhpmax; if (Upolyd) u.mh = u.mhmax; exercise(A_STR, TRUE); flags.botl = 1; break; } } if (mon->mtame) /* don't charge */ ; else if (rn2(20) < ACURR(A_CHA)) { pline("%s demands that you pay %s, but you refuse...", noit_Monnam(mon), Blind ? (fem ? "her" : "him") : mhim(mon)); } else if (u.umonnum == PM_LEPRECHAUN) pline("%s tries to take your money, but fails...", noit_Monnam(mon)); else { #ifndef GOLDOBJ long cost; if (u.ugold > (long)LARGEST_INT - 10L) cost = (long) rnd(LARGEST_INT) + 500L; else cost = (long) rnd((int)u.ugold + 10) + 500L; if (mon->mpeaceful) { cost /= 5L; if (!cost) cost = 1L; } if (cost > u.ugold) cost = u.ugold; if (!cost) verbalize("It's on the house!"); else { pline("%s takes %ld %s for services rendered!", noit_Monnam(mon), cost, currency(cost)); u.ugold -= cost; mon->mgold += cost; flags.botl = 1; } #else long cost; long umoney = money_cnt(invent); if (umoney > (long)LARGEST_INT - 10L) cost = (long) rnd(LARGEST_INT) + 500L; else cost = (long) rnd((int)umoney + 10) + 500L; if (mon->mpeaceful) { cost /= 5L; if (!cost) cost = 1L; } if (cost > umoney) cost = umoney; if (!cost) verbalize("It's on the house!"); else { pline("%s takes %ld %s for services rendered!", noit_Monnam(mon), cost, currency(cost)); money2mon(mon, cost); flags.botl = 1; } #endif } if (!rn2(25)) mon->mcan = 1; /* monster is worn out */ if (!tele_restrict(mon)) (void) rloc(mon, FALSE); return 1; } STATIC_OVL void mayberem(obj, str) register struct obj *obj; const char *str; { char qbuf[QBUFSZ]; if (!obj || !obj->owornmask) return; if (rn2(20) < ACURR(A_CHA)) { Sprintf(qbuf,"\"Shall I remove your %s, %s?\"", str, (!rn2(2) ? "lover" : !rn2(2) ? "dear" : "sweetheart")); if (yn(qbuf) == 'n') return; } else { char hairbuf[BUFSZ]; Sprintf(hairbuf, "let me run my fingers through your %s", body_part(HAIR)); verbalize("Take off your %s; %s.", str, (obj == uarm) ? "let's get a little closer" : (obj == uarmc || obj == uarms) ? "it's in the way" : (obj == uarmf) ? "let me rub your feet" : (obj == uarmg) ? "they're too clumsy" : #ifdef TOURIST (obj == uarmu) ? "let me massage you" : #endif /* obj == uarmh */ hairbuf); } remove_worn_item(obj, TRUE); } #endif /* SEDUCE */ #endif /* OVLB */ #ifdef OVL1 STATIC_OVL int passiveum(olduasmon,mtmp,mattk) struct permonst *olduasmon; register struct monst *mtmp; register struct attack *mattk; { int i, tmp; for (i = 0; ; i++) { if (i >= NATTK) return 1; if (olduasmon->mattk[i].aatyp == AT_NONE || olduasmon->mattk[i].aatyp == AT_BOOM) break; } if (olduasmon->mattk[i].damn) tmp = d((int)olduasmon->mattk[i].damn, (int)olduasmon->mattk[i].damd); else if(olduasmon->mattk[i].damd) tmp = d((int)olduasmon->mlevel+1, (int)olduasmon->mattk[i].damd); else tmp = 0; /* These affect the enemy even if you were "killed" (rehumanized) */ switch(olduasmon->mattk[i].adtyp) { case AD_ACID: if (!rn2(2)) { pline("%s is splashed by your acid!", Monnam(mtmp)); if (resists_acid(mtmp)) { pline("%s is not affected.", Monnam(mtmp)); tmp = 0; } } else tmp = 0; if (!rn2(30)) erode_armor(mtmp, TRUE); if (!rn2(6)) erode_obj(MON_WEP(mtmp), TRUE, TRUE); goto assess_dmg; case AD_STON: /* cockatrice */ { long protector = attk_protection((int)mattk->aatyp), wornitems = mtmp->misc_worn_check; /* wielded weapon gives same protection as gloves here */ if (MON_WEP(mtmp) != 0) wornitems |= W_ARMG; if (!resists_ston(mtmp) && (protector == 0L || (protector != ~0L && (wornitems & protector) != protector))) { if (poly_when_stoned(mtmp->data)) { mon_to_stone(mtmp); return (1); } pline("%s turns to stone!", Monnam(mtmp)); stoned = 1; xkilled(mtmp, 0); if (mtmp->mhp > 0) return 1; return 2; } return 1; } case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ if (otmp) { (void) drain_item(otmp); /* No message */ } return (1); default: break; } if (!Upolyd) return 1; /* These affect the enemy only if you are still a monster */ if (rn2(3)) switch(youmonst.data->mattk[i].adtyp) { case AD_PHYS: if (youmonst.data->mattk[i].aatyp == AT_BOOM) { You("explode!"); /* KMH, balance patch -- this is okay with unchanging */ rehumanize(); goto assess_dmg; } break; case AD_PLYS: /* Floating eye */ if (tmp > 127) tmp = 127; if (u.umonnum == PM_FLOATING_EYE) { if (!rn2(4)) tmp = 127; if (mtmp->mcansee && haseyes(mtmp->data) && rn2(3) && (perceives(mtmp->data) || !Invis)) { if (Blind) pline("As a blind %s, you cannot defend yourself.", youmonst.data->mname); else { if (mon_reflects(mtmp, "Your gaze is reflected by %s %s.")) return 1; pline("%s is frozen by your gaze!", Monnam(mtmp)); mtmp->mcanmove = 0; mtmp->mfrozen = tmp; return 3; } } } else { /* gelatinous cube */ pline("%s is frozen by you.", Monnam(mtmp)); mtmp->mcanmove = 0; mtmp->mfrozen = tmp; return 3; } return 1; case AD_COLD: /* Brown mold or blue jelly */ if (resists_cold(mtmp)) { shieldeff(mtmp->mx, mtmp->my); pline("%s is mildly chilly.", Monnam(mtmp)); golemeffects(mtmp, AD_COLD, tmp); tmp = 0; break; } pline("%s is suddenly very cold!", Monnam(mtmp)); u.mh += tmp / 2; if (u.mhmax < u.mh) u.mhmax = u.mh; if (u.mhmax > ((youmonst.data->mlevel+1) * 8)) (void)split_mon(&youmonst, mtmp); break; case AD_STUN: /* Yellow mold */ if (!mtmp->mstun) { mtmp->mstun = 1; pline("%s %s.", Monnam(mtmp), makeplural(stagger(mtmp->data, "stagger"))); } tmp = 0; break; case AD_FIRE: /* Red mold */ if (resists_fire(mtmp)) { shieldeff(mtmp->mx, mtmp->my); pline("%s is mildly warm.", Monnam(mtmp)); golemeffects(mtmp, AD_FIRE, tmp); tmp = 0; break; } pline("%s is suddenly very hot!", Monnam(mtmp)); break; case AD_ELEC: if (resists_elec(mtmp)) { shieldeff(mtmp->mx, mtmp->my); pline("%s is slightly tingled.", Monnam(mtmp)); golemeffects(mtmp, AD_ELEC, tmp); tmp = 0; break; } pline("%s is jolted with your electricity!", Monnam(mtmp)); break; default: tmp = 0; break; } else tmp = 0; assess_dmg: if((mtmp->mhp -= tmp) <= 0) { pline("%s dies!", Monnam(mtmp)); xkilled(mtmp,0); if (mtmp->mhp > 0) return 1; return 2; } return 1; } #endif /* OVL1 */ #ifdef OVLB #include "edog.h" struct monst * cloneu() { register struct monst *mon; int mndx = monsndx(youmonst.data); if (u.mh <= 1) return(struct monst *)0; if (mvitals[mndx].mvflags & G_EXTINCT) return(struct monst *)0; mon = makemon(youmonst.data, u.ux, u.uy, NO_MINVENT|MM_EDOG); mon = christen_monst(mon, plname); initedog(mon); mon->m_lev = youmonst.data->mlevel; mon->mhpmax = u.mhmax; mon->mhp = u.mh / 2; u.mh -= mon->mhp; flags.botl = 1; return(mon); } #endif /* OVLB */ /*mhitu.c*/ nethack-3.4.3/src/minion.c0100644000000000000000000001722407764735041014104 0ustar rootroot/* SCCS Id: @(#)minion.c 3.4 2003/01/09 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "emin.h" #include "epri.h" void msummon(mon) /* mon summons a monster */ struct monst *mon; { register struct permonst *ptr; register int dtype = NON_PM, cnt = 0; aligntyp atyp; struct monst *mtmp; if (mon) { ptr = mon->data; atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp); if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST] || mon->data == &mons[PM_ANGEL]) atyp = EPRI(mon)->shralign; } else { ptr = &mons[PM_WIZARD_OF_YENDOR]; atyp = (ptr->maligntyp==A_NONE) ? A_NONE : sgn(ptr->maligntyp); } if (is_dprince(ptr) || (ptr == &mons[PM_WIZARD_OF_YENDOR])) { dtype = (!rn2(20)) ? dprince(atyp) : (!rn2(4)) ? dlord(atyp) : ndemon(atyp); cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1; } else if (is_dlord(ptr)) { dtype = (!rn2(50)) ? dprince(atyp) : (!rn2(20)) ? dlord(atyp) : ndemon(atyp); cnt = (!rn2(4) && is_ndemon(&mons[dtype])) ? 2 : 1; } else if (is_ndemon(ptr)) { dtype = (!rn2(20)) ? dlord(atyp) : (!rn2(6)) ? ndemon(atyp) : monsndx(ptr); cnt = 1; } else if (is_lminion(mon)) { dtype = (is_lord(ptr) && !rn2(20)) ? llord() : (is_lord(ptr) || !rn2(6)) ? lminion() : monsndx(ptr); cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1; } else if (ptr == &mons[PM_ANGEL]) { /* non-lawful angels can also summon */ if (!rn2(6)) { switch (atyp) { /* see summon_minion */ case A_NEUTRAL: dtype = PM_AIR_ELEMENTAL + rn2(4); break; case A_CHAOTIC: case A_NONE: dtype = ndemon(atyp); break; } } else { dtype = PM_ANGEL; } cnt = (!rn2(4) && !is_lord(&mons[dtype])) ? 2 : 1; } if (dtype == NON_PM) return; /* sanity checks */ if (cnt > 1 && (mons[dtype].geno & G_UNIQ)) cnt = 1; /* * If this daemon is unique and being re-summoned (the only way we * could get this far with an extinct dtype), try another. */ if (mvitals[dtype].mvflags & G_GONE) { dtype = ndemon(atyp); if (dtype == NON_PM) return; } while (cnt > 0) { mtmp = makemon(&mons[dtype], u.ux, u.uy, NO_MM_FLAGS); if (mtmp && (dtype == PM_ANGEL)) { /* alignment should match the summoner */ EPRI(mtmp)->shralign = atyp; } cnt--; } } void summon_minion(alignment, talk) aligntyp alignment; boolean talk; { register struct monst *mon; int mnum; switch ((int)alignment) { case A_LAWFUL: mnum = lminion(); break; case A_NEUTRAL: mnum = PM_AIR_ELEMENTAL + rn2(4); break; case A_CHAOTIC: case A_NONE: mnum = ndemon(alignment); break; default: impossible("unaligned player?"); mnum = ndemon(A_NONE); break; } if (mnum == NON_PM) { mon = 0; } else if (mons[mnum].pxlth == 0) { struct permonst *pm = &mons[mnum]; mon = makemon(pm, u.ux, u.uy, MM_EMIN); if (mon) { mon->isminion = TRUE; EMIN(mon)->min_align = alignment; } } else if (mnum == PM_ANGEL) { mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS); if (mon) { mon->isminion = TRUE; EPRI(mon)->shralign = alignment; /* always A_LAWFUL here */ } } else mon = makemon(&mons[mnum], u.ux, u.uy, NO_MM_FLAGS); if (mon) { if (talk) { pline_The("voice of %s booms:", align_gname(alignment)); verbalize("Thou shalt pay for thy indiscretion!"); if (!Blind) pline("%s appears before you.", Amonnam(mon)); } mon->mpeaceful = FALSE; /* don't call set_malign(); player was naughty */ } } #define Athome (Inhell && !mtmp->cham) int demon_talk(mtmp) /* returns 1 if it won't attack. */ register struct monst *mtmp; { long cash, demand, offer; if (uwep && uwep->oartifact == ART_EXCALIBUR) { pline("%s looks very angry.", Amonnam(mtmp)); mtmp->mpeaceful = mtmp->mtame = 0; set_malign(mtmp); newsym(mtmp->mx, mtmp->my); return 0; } /* Slight advantage given. */ if (is_dprince(mtmp->data) && mtmp->minvis) { mtmp->minvis = mtmp->perminvis = 0; if (!Blind) pline("%s appears before you.", Amonnam(mtmp)); newsym(mtmp->mx,mtmp->my); } if (youmonst.data->mlet == S_DEMON) { /* Won't blackmail their own. */ pline("%s says, \"Good hunting, %s.\"", Amonnam(mtmp), flags.female ? "Sister" : "Brother"); if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); return(1); } #ifndef GOLDOBJ cash = u.ugold; #else cash = money_cnt(invent); #endif demand = (cash * (rnd(80) + 20 * Athome)) / (100 * (1 + (sgn(u.ualign.type) == sgn(mtmp->data->maligntyp)))); if (!demand) { /* you have no gold */ mtmp->mpeaceful = 0; set_malign(mtmp); return 0; } else { /* make sure that the demand is unmeetable if the monster has the Amulet, preventing monster from being satisified and removed from the game (along with said Amulet...) */ if (mon_has_amulet(mtmp)) demand = cash + (long)rn1(1000,40); pline("%s demands %ld %s for safe passage.", Amonnam(mtmp), demand, currency(demand)); if ((offer = bribe(mtmp)) >= demand) { pline("%s vanishes, laughing about cowardly mortals.", Amonnam(mtmp)); } else if (offer > 0L && (long)rnd(40) > (demand - offer)) { pline("%s scowls at you menacingly, then vanishes.", Amonnam(mtmp)); } else { pline("%s gets angry...", Amonnam(mtmp)); mtmp->mpeaceful = 0; set_malign(mtmp); return 0; } } mongone(mtmp); return(1); } long bribe(mtmp) struct monst *mtmp; { char buf[BUFSZ]; long offer; #ifdef GOLDOBJ long umoney = money_cnt(invent); #endif getlin("How much will you offer?", buf); if (sscanf(buf, "%ld", &offer) != 1) offer = 0L; /*Michael Paddon -- fix for negative offer to monster*/ /*JAR880815 - */ if (offer < 0L) { You("try to shortchange %s, but fumble.", mon_nam(mtmp)); return 0L; } else if (offer == 0L) { You("refuse."); return 0L; #ifndef GOLDOBJ } else if (offer >= u.ugold) { You("give %s all your gold.", mon_nam(mtmp)); offer = u.ugold; } else { You("give %s %ld %s.", mon_nam(mtmp), offer, currency(offer)); } u.ugold -= offer; mtmp->mgold += offer; #else } else if (offer >= umoney) { You("give %s all your gold.", mon_nam(mtmp)); offer = umoney; } else { You("give %s %ld %s.", mon_nam(mtmp), offer, currency(offer)); } (void) money2mon(mtmp, offer); #endif flags.botl = 1; return(offer); } int dprince(atyp) aligntyp atyp; { int tryct, pm; for (tryct = 0; tryct < 20; tryct++) { pm = rn1(PM_DEMOGORGON + 1 - PM_ORCUS, PM_ORCUS); if (!(mvitals[pm].mvflags & G_GONE) && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp))) return(pm); } return(dlord(atyp)); /* approximate */ } int dlord(atyp) aligntyp atyp; { int tryct, pm; for (tryct = 0; tryct < 20; tryct++) { pm = rn1(PM_YEENOGHU + 1 - PM_JUIBLEX, PM_JUIBLEX); if (!(mvitals[pm].mvflags & G_GONE) && (atyp == A_NONE || sgn(mons[pm].maligntyp) == sgn(atyp))) return(pm); } return(ndemon(atyp)); /* approximate */ } /* create lawful (good) lord */ int llord() { if (!(mvitals[PM_ARCHON].mvflags & G_GONE)) return(PM_ARCHON); return(lminion()); /* approximate */ } int lminion() { int tryct; struct permonst *ptr; for (tryct = 0; tryct < 20; tryct++) { ptr = mkclass(S_ANGEL,0); if (ptr && !is_lord(ptr)) return(monsndx(ptr)); } return NON_PM; } int ndemon(atyp) aligntyp atyp; { int tryct; struct permonst *ptr; for (tryct = 0; tryct < 20; tryct++) { ptr = mkclass(S_DEMON, 0); if (ptr && is_ndemon(ptr) && (atyp == A_NONE || sgn(ptr->maligntyp) == sgn(atyp))) return(monsndx(ptr)); } return NON_PM; } /*minion.c*/ nethack-3.4.3/src/mklev.c0100644000000000000000000011673707764735041013742 0ustar rootroot/* SCCS Id: @(#)mklev.c 3.4 2001/11/29 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* #define DEBUG */ /* uncomment to enable code debugging */ #ifdef DEBUG # ifdef WIZARD #define debugpline if (wizard) pline # else #define debugpline pline # endif #endif /* for UNIX, Rand #def'd to (long)lrand48() or (long)random() */ /* croom->lx etc are schar (width <= int), so % arith ensures that */ /* conversion of result to int is reasonable */ STATIC_DCL void FDECL(mkfount,(int,struct mkroom *)); #ifdef SINKS STATIC_DCL void FDECL(mksink,(struct mkroom *)); #endif STATIC_DCL void FDECL(mkaltar,(struct mkroom *)); STATIC_DCL void FDECL(mkgrave,(struct mkroom *)); STATIC_DCL void NDECL(makevtele); STATIC_DCL void NDECL(clear_level_structures); STATIC_DCL void NDECL(makelevel); STATIC_DCL void NDECL(mineralize); STATIC_DCL boolean FDECL(bydoor,(XCHAR_P,XCHAR_P)); STATIC_DCL struct mkroom *FDECL(find_branch_room, (coord *)); STATIC_DCL struct mkroom *FDECL(pos_to_room, (XCHAR_P, XCHAR_P)); STATIC_DCL boolean FDECL(place_niche,(struct mkroom *,int*,int*,int*)); STATIC_DCL void FDECL(makeniche,(int)); STATIC_DCL void NDECL(make_niches); STATIC_PTR int FDECL( CFDECLSPEC do_comp,(const genericptr,const genericptr)); STATIC_DCL void FDECL(dosdoor,(XCHAR_P,XCHAR_P,struct mkroom *,int)); STATIC_DCL void FDECL(join,(int,int,BOOLEAN_P)); STATIC_DCL void FDECL(do_room_or_subroom, (struct mkroom *,int,int,int,int, BOOLEAN_P,SCHAR_P,BOOLEAN_P,BOOLEAN_P)); STATIC_DCL void NDECL(makerooms); STATIC_DCL void FDECL(finddpos,(coord *,XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P)); STATIC_DCL void FDECL(mkinvpos, (XCHAR_P,XCHAR_P,int)); STATIC_DCL void FDECL(mk_knox_portal, (XCHAR_P,XCHAR_P)); #define create_vault() create_room(-1, -1, 2, 2, -1, -1, VAULT, TRUE) #define init_vault() vault_x = -1 #define do_vault() (vault_x != -1) static xchar vault_x, vault_y; boolean goldseen; static boolean made_branch; /* used only during level creation */ /* Args must be (const genericptr) so that qsort will always be happy. */ STATIC_PTR int CFDECLSPEC do_comp(vx,vy) const genericptr vx; const genericptr vy; { #ifdef LINT /* lint complains about possible pointer alignment problems, but we know that vx and vy are always properly aligned. Hence, the following bogus definition: */ return (vx == vy) ? 0 : -1; #else register const struct mkroom *x, *y; x = (const struct mkroom *)vx; y = (const struct mkroom *)vy; if(x->lx < y->lx) return(-1); return(x->lx > y->lx); #endif /* LINT */ } STATIC_OVL void finddpos(cc, xl,yl,xh,yh) coord *cc; xchar xl,yl,xh,yh; { register xchar x, y; x = (xl == xh) ? xl : (xl + rn2(xh-xl+1)); y = (yl == yh) ? yl : (yl + rn2(yh-yl+1)); if(okdoor(x, y)) goto gotit; for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++) if(okdoor(x, y)) goto gotit; for(x = xl; x <= xh; x++) for(y = yl; y <= yh; y++) if(IS_DOOR(levl[x][y].typ) || levl[x][y].typ == SDOOR) goto gotit; /* cannot find something reasonable -- strange */ x = xl; y = yh; gotit: cc->x = x; cc->y = y; return; } void sort_rooms() { #if defined(SYSV) || defined(DGUX) qsort((genericptr_t) rooms, (unsigned)nroom, sizeof(struct mkroom), do_comp); #else qsort((genericptr_t) rooms, nroom, sizeof(struct mkroom), do_comp); #endif } STATIC_OVL void do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, is_room) register struct mkroom *croom; int lowx, lowy; register int hix, hiy; boolean lit; schar rtype; boolean special; boolean is_room; { register int x, y; struct rm *lev; /* locations might bump level edges in wall-less rooms */ /* add/subtract 1 to allow for edge locations */ if(!lowx) lowx++; if(!lowy) lowy++; if(hix >= COLNO-1) hix = COLNO-2; if(hiy >= ROWNO-1) hiy = ROWNO-2; if(lit) { for(x = lowx-1; x <= hix+1; x++) { lev = &levl[x][max(lowy-1,0)]; for(y = lowy-1; y <= hiy+1; y++) lev++->lit = 1; } croom->rlit = 1; } else croom->rlit = 0; croom->lx = lowx; croom->hx = hix; croom->ly = lowy; croom->hy = hiy; croom->rtype = rtype; croom->doorct = 0; /* if we're not making a vault, doorindex will still be 0 * if we are, we'll have problems adding niches to the previous room * unless fdoor is at least doorindex */ croom->fdoor = doorindex; croom->irregular = FALSE; croom->nsubrooms = 0; croom->sbrooms[0] = (struct mkroom *) 0; if (!special) { for(x = lowx-1; x <= hix+1; x++) for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) { levl[x][y].typ = HWALL; levl[x][y].horizontal = 1; /* For open/secret doors. */ } for(x = lowx-1; x <= hix+1; x += (hix-lowx+2)) for(y = lowy; y <= hiy; y++) { levl[x][y].typ = VWALL; levl[x][y].horizontal = 0; /* For open/secret doors. */ } for(x = lowx; x <= hix; x++) { lev = &levl[x][lowy]; for(y = lowy; y <= hiy; y++) lev++->typ = ROOM; } if (is_room) { levl[lowx-1][lowy-1].typ = TLCORNER; levl[hix+1][lowy-1].typ = TRCORNER; levl[lowx-1][hiy+1].typ = BLCORNER; levl[hix+1][hiy+1].typ = BRCORNER; } else { /* a subroom */ wallification(lowx-1, lowy-1, hix+1, hiy+1); } } } void add_room(lowx, lowy, hix, hiy, lit, rtype, special) register int lowx, lowy, hix, hiy; boolean lit; schar rtype; boolean special; { register struct mkroom *croom; croom = &rooms[nroom]; do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, (boolean) TRUE); croom++; croom->hx = -1; nroom++; } void add_subroom(proom, lowx, lowy, hix, hiy, lit, rtype, special) struct mkroom *proom; register int lowx, lowy, hix, hiy; boolean lit; schar rtype; boolean special; { register struct mkroom *croom; croom = &subrooms[nsubroom]; do_room_or_subroom(croom, lowx, lowy, hix, hiy, lit, rtype, special, (boolean) FALSE); proom->sbrooms[proom->nsubrooms++] = croom; croom++; croom->hx = -1; nsubroom++; } STATIC_OVL void makerooms() { boolean tried_vault = FALSE; /* make rooms until satisfied */ /* rnd_rect() will returns 0 if no more rects are available... */ while(nroom < MAXNROFROOMS && rnd_rect()) { if(nroom >= (MAXNROFROOMS/6) && rn2(2) && !tried_vault) { tried_vault = TRUE; if (create_vault()) { vault_x = rooms[nroom].lx; vault_y = rooms[nroom].ly; rooms[nroom].hx = -1; } } else if (!create_room(-1, -1, -1, -1, -1, -1, OROOM, -1)) return; } return; } STATIC_OVL void join(a,b,nxcor) register int a, b; boolean nxcor; { coord cc,tt, org, dest; register xchar tx, ty, xx, yy; register struct mkroom *croom, *troom; register int dx, dy; croom = &rooms[a]; troom = &rooms[b]; /* find positions cc and tt for doors in croom and troom and direction for a corridor between them */ if(troom->hx < 0 || croom->hx < 0 || doorindex >= DOORMAX) return; if(troom->lx > croom->hx) { dx = 1; dy = 0; xx = croom->hx+1; tx = troom->lx-1; finddpos(&cc, xx, croom->ly, xx, croom->hy); finddpos(&tt, tx, troom->ly, tx, troom->hy); } else if(troom->hy < croom->ly) { dy = -1; dx = 0; yy = croom->ly-1; finddpos(&cc, croom->lx, yy, croom->hx, yy); ty = troom->hy+1; finddpos(&tt, troom->lx, ty, troom->hx, ty); } else if(troom->hx < croom->lx) { dx = -1; dy = 0; xx = croom->lx-1; tx = troom->hx+1; finddpos(&cc, xx, croom->ly, xx, croom->hy); finddpos(&tt, tx, troom->ly, tx, troom->hy); } else { dy = 1; dx = 0; yy = croom->hy+1; ty = troom->ly-1; finddpos(&cc, croom->lx, yy, croom->hx, yy); finddpos(&tt, troom->lx, ty, troom->hx, ty); } xx = cc.x; yy = cc.y; tx = tt.x - dx; ty = tt.y - dy; if(nxcor && levl[xx+dx][yy+dy].typ) return; if (okdoor(xx,yy) || !nxcor) dodoor(xx,yy,croom); org.x = xx+dx; org.y = yy+dy; dest.x = tx; dest.y = ty; if (!dig_corridor(&org, &dest, nxcor, level.flags.arboreal ? ROOM : CORR, STONE)) return; /* we succeeded in digging the corridor */ if (okdoor(tt.x, tt.y) || !nxcor) dodoor(tt.x, tt.y, troom); if(smeq[a] < smeq[b]) smeq[b] = smeq[a]; else smeq[a] = smeq[b]; } void makecorridors() { int a, b, i; boolean any = TRUE; for(a = 0; a < nroom-1; a++) { join(a, a+1, FALSE); if(!rn2(50)) break; /* allow some randomness */ } for(a = 0; a < nroom-2; a++) if(smeq[a] != smeq[a+2]) join(a, a+2, FALSE); for(a = 0; any && a < nroom; a++) { any = FALSE; for(b = 0; b < nroom; b++) if(smeq[a] != smeq[b]) { join(a, b, FALSE); any = TRUE; } } if(nroom > 2) for(i = rn2(nroom) + 4; i; i--) { a = rn2(nroom); b = rn2(nroom-2); if(b >= a) b += 2; join(a, b, TRUE); } } void add_door(x,y,aroom) register int x, y; register struct mkroom *aroom; { register struct mkroom *broom; register int tmp; aroom->doorct++; broom = aroom+1; if(broom->hx < 0) tmp = doorindex; else for(tmp = doorindex; tmp > broom->fdoor; tmp--) doors[tmp] = doors[tmp-1]; doorindex++; doors[tmp].x = x; doors[tmp].y = y; for( ; broom->hx >= 0; broom++) broom->fdoor++; } STATIC_OVL void dosdoor(x,y,aroom,type) register xchar x, y; register struct mkroom *aroom; register int type; { boolean shdoor = ((*in_rooms(x, y, SHOPBASE))? TRUE : FALSE); if(!IS_WALL(levl[x][y].typ)) /* avoid SDOORs on already made doors */ type = DOOR; levl[x][y].typ = type; if(type == DOOR) { if(!rn2(3)) { /* is it a locked door, closed, or a doorway? */ if(!rn2(5)) levl[x][y].doormask = D_ISOPEN; else if(!rn2(6)) levl[x][y].doormask = D_LOCKED; else levl[x][y].doormask = D_CLOSED; if (levl[x][y].doormask != D_ISOPEN && !shdoor && level_difficulty() >= 5 && !rn2(25)) levl[x][y].doormask |= D_TRAPPED; } else #ifdef STUPID if (shdoor) levl[x][y].doormask = D_ISOPEN; else levl[x][y].doormask = D_NODOOR; #else levl[x][y].doormask = (shdoor ? D_ISOPEN : D_NODOOR); #endif if(levl[x][y].doormask & D_TRAPPED) { struct monst *mtmp; if (level_difficulty() >= 9 && !rn2(5) && !((mvitals[PM_SMALL_MIMIC].mvflags & G_GONE) && (mvitals[PM_LARGE_MIMIC].mvflags & G_GONE) && (mvitals[PM_GIANT_MIMIC].mvflags & G_GONE))) { /* make a mimic instead */ levl[x][y].doormask = D_NODOOR; mtmp = makemon(mkclass(S_MIMIC,0), x, y, NO_MM_FLAGS); if (mtmp) set_mimic_sym(mtmp); } } /* newsym(x,y); */ } else { /* SDOOR */ if(shdoor || !rn2(5)) levl[x][y].doormask = D_LOCKED; else levl[x][y].doormask = D_CLOSED; if(!shdoor && level_difficulty() >= 4 && !rn2(20)) levl[x][y].doormask |= D_TRAPPED; } add_door(x,y,aroom); } STATIC_OVL boolean place_niche(aroom,dy,xx,yy) register struct mkroom *aroom; int *dy, *xx, *yy; { coord dd; if(rn2(2)) { *dy = 1; finddpos(&dd, aroom->lx, aroom->hy+1, aroom->hx, aroom->hy+1); } else { *dy = -1; finddpos(&dd, aroom->lx, aroom->ly-1, aroom->hx, aroom->ly-1); } *xx = dd.x; *yy = dd.y; return((boolean)((isok(*xx,*yy+*dy) && levl[*xx][*yy+*dy].typ == STONE) && (isok(*xx,*yy-*dy) && !IS_POOL(levl[*xx][*yy-*dy].typ) && !IS_FURNITURE(levl[*xx][*yy-*dy].typ)))); } /* there should be one of these per trap, in the same order as trap.h */ static NEARDATA const char *trap_engravings[TRAPNUM] = { (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, /* 14..16: trap door, teleport, level-teleport */ "Vlad was here", "ad aerarium", "ad aerarium", (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, }; STATIC_OVL void makeniche(trap_type) int trap_type; { register struct mkroom *aroom; register struct rm *rm; register int vct = 8; int dy, xx, yy; register struct trap *ttmp; if(doorindex < DOORMAX) while(vct--) { aroom = &rooms[rn2(nroom)]; if(aroom->rtype != OROOM) continue; /* not an ordinary room */ if(aroom->doorct == 1 && rn2(5)) continue; if(!place_niche(aroom,&dy,&xx,&yy)) continue; rm = &levl[xx][yy+dy]; if(trap_type || !rn2(4)) { rm->typ = SCORR; if(trap_type) { if((trap_type == HOLE || trap_type == TRAPDOOR) && !Can_fall_thru(&u.uz)) trap_type = ROCKTRAP; ttmp = maketrap(xx, yy+dy, trap_type); if (ttmp) { if (trap_type != ROCKTRAP) ttmp->once = 1; if (trap_engravings[trap_type]) { make_engr_at(xx, yy-dy, trap_engravings[trap_type], 0L, DUST); wipe_engr_at(xx, yy-dy, 5); /* age it a little */ } } } dosdoor(xx, yy, aroom, SDOOR); } else { rm->typ = CORR; if(rn2(7)) dosdoor(xx, yy, aroom, rn2(5) ? SDOOR : DOOR); else { if (!level.flags.noteleport) (void) mksobj_at(SCR_TELEPORTATION, xx, yy+dy, TRUE, FALSE); if (!rn2(3)) (void) mkobj_at(0, xx, yy+dy, TRUE); } } return; } } STATIC_OVL void make_niches() { register int ct = rnd((nroom>>1) + 1), dep = depth(&u.uz); boolean ltptr = (!level.flags.noteleport && dep > 15), vamp = (dep > 5 && dep < 25); while(ct--) { if (ltptr && !rn2(6)) { ltptr = FALSE; makeniche(LEVEL_TELEP); } else if (vamp && !rn2(6)) { vamp = FALSE; makeniche(TRAPDOOR); } else makeniche(NO_TRAP); } } STATIC_OVL void makevtele() { makeniche(TELEP_TRAP); } /* clear out various globals that keep information on the current level. * some of this is only necessary for some types of levels (maze, normal, * special) but it's easier to put it all in one place than make sure * each type initializes what it needs to separately. */ STATIC_OVL void clear_level_structures() { static struct rm zerorm = { cmap_to_glyph(S_stone), 0, 0, 0, 0, 0, 0, 0, 0 }; register int x,y; register struct rm *lev; for(x=0; xproto); return; } else if (dungeons[u.uz.dnum].proto[0]) { makemaz(""); return; } else if (In_mines(&u.uz)) { makemaz("minefill"); return; } else if (In_quest(&u.uz)) { char fillname[9]; s_level *loc_lev; Sprintf(fillname, "%s-loca", urole.filecode); loc_lev = find_level(fillname); Sprintf(fillname, "%s-fil", urole.filecode); Strcat(fillname, (u.uz.dlevel < loc_lev->dlevel.dlevel) ? "a" : "b"); makemaz(fillname); return; } else if(In_hell(&u.uz) || (rn2(5) && u.uz.dnum == medusa_level.dnum && depth(&u.uz) > depth(&medusa_level))) { makemaz(""); return; } } /* otherwise, fall through - it's a "regular" level. */ #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) { makeroguerooms(); makerogueghost(); } else #endif makerooms(); sort_rooms(); /* construct stairs (up and down in different rooms if possible) */ croom = &rooms[rn2(nroom)]; if (!Is_botlevel(&u.uz)) mkstairs(somex(croom), somey(croom), 0, croom); /* down */ if (nroom > 1) { troom = croom; croom = &rooms[rn2(nroom-1)]; if (croom == troom) croom++; } if (u.uz.dlevel != 1) { xchar sx, sy; do { sx = somex(croom); sy = somey(croom); } while(occupied(sx, sy)); mkstairs(sx, sy, 1, croom); /* up */ } branchp = Is_branchlev(&u.uz); /* possible dungeon branch */ room_threshold = branchp ? 4 : 3; /* minimum number of rooms needed to allow a random special room */ #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) goto skip0; #endif makecorridors(); make_niches(); /* make a secret treasure vault, not connected to the rest */ if(do_vault()) { xchar w,h; #ifdef DEBUG debugpline("trying to make a vault..."); #endif w = 1; h = 1; if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) { fill_vault: add_room(vault_x, vault_y, vault_x+w, vault_y+h, TRUE, VAULT, FALSE); level.flags.has_vault = 1; ++room_threshold; fill_room(&rooms[nroom - 1], FALSE); mk_knox_portal(vault_x+w, vault_y+h); if(!level.flags.noteleport && !rn2(3)) makevtele(); } else if(rnd_rect() && create_vault()) { vault_x = rooms[nroom].lx; vault_y = rooms[nroom].ly; if (check_room(&vault_x, &w, &vault_y, &h, TRUE)) goto fill_vault; else rooms[nroom].hx = -1; } } { register int u_depth = depth(&u.uz); #ifdef WIZARD if(wizard && nh_getenv("SHOPTYPE")) mkroom(SHOPBASE); else #endif if (u_depth > 1 && u_depth < depth(&medusa_level) && nroom >= room_threshold && rn2(u_depth) < 3) mkroom(SHOPBASE); else if (u_depth > 4 && !rn2(6)) mkroom(COURT); else if (u_depth > 5 && !rn2(8) && !(mvitals[PM_LEPRECHAUN].mvflags & G_GONE)) mkroom(LEPREHALL); else if (u_depth > 6 && !rn2(7)) mkroom(ZOO); else if (u_depth > 8 && !rn2(5)) mkroom(TEMPLE); else if (u_depth > 9 && !rn2(5) && !(mvitals[PM_KILLER_BEE].mvflags & G_GONE)) mkroom(BEEHIVE); else if (u_depth > 11 && !rn2(6)) mkroom(MORGUE); else if (u_depth > 12 && !rn2(8)) mkroom(ANTHOLE); else if (u_depth > 14 && !rn2(4) && !(mvitals[PM_SOLDIER].mvflags & G_GONE)) mkroom(BARRACKS); else if (u_depth > 15 && !rn2(6)) mkroom(SWAMP); else if (u_depth > 16 && !rn2(8) && !(mvitals[PM_COCKATRICE].mvflags & G_GONE)) mkroom(COCKNEST); } #ifdef REINCARNATION skip0: #endif /* Place multi-dungeon branch. */ place_branch(branchp, 0, 0); /* for each room: put things inside */ for(croom = rooms; croom->hx > 0; croom++) { if(croom->rtype != OROOM) continue; /* put a sleeping monster inside */ /* Note: monster may be on the stairs. This cannot be avoided: maybe the player fell through a trap door while a monster was on the stairs. Conclusion: we have to check for monsters on the stairs anyway. */ if(u.uhave.amulet || !rn2(3)) { x = somex(croom); y = somey(croom); tmonst = makemon((struct permonst *) 0, x,y,NO_MM_FLAGS); if (tmonst && tmonst->data == &mons[PM_GIANT_SPIDER] && !occupied(x, y)) (void) maketrap(x, y, WEB); } /* put traps and mimics inside */ goldseen = FALSE; x = 8 - (level_difficulty()/6); if (x <= 1) x = 2; while (!rn2(x)) mktrap(0,0,croom,(coord*)0); if (!goldseen && !rn2(3)) (void) mkgold(0L, somex(croom), somey(croom)); #ifdef REINCARNATION if(Is_rogue_level(&u.uz)) goto skip_nonrogue; #endif if(!rn2(10)) mkfount(0,croom); #ifdef SINKS if(!rn2(60)) mksink(croom); #endif if(!rn2(60)) mkaltar(croom); x = 80 - (depth(&u.uz) * 2); if (x < 2) x = 2; if(!rn2(x)) mkgrave(croom); /* put statues inside */ if(!rn2(20)) (void) mkcorpstat(STATUE, (struct monst *)0, (struct permonst *)0, somex(croom), somey(croom), TRUE); /* put box/chest inside; * 40% chance for at least 1 box, regardless of number * of rooms; about 5 - 7.5% for 2 boxes, least likely * when few rooms; chance for 3 or more is neglible. */ if(!rn2(nroom * 5 / 2)) (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, somex(croom), somey(croom), TRUE, FALSE); /* maybe make some graffiti */ if(!rn2(27 + 3 * abs(depth(&u.uz)))) { char buf[BUFSZ]; const char *mesg = random_engraving(buf); if (mesg) { do { x = somex(croom); y = somey(croom); } while(levl[x][y].typ != ROOM && !rn2(40)); if (!(IS_POOL(levl[x][y].typ) || IS_FURNITURE(levl[x][y].typ))) make_engr_at(x, y, mesg, 0L, MARK); } } #ifdef REINCARNATION skip_nonrogue: #endif if(!rn2(3)) { (void) mkobj_at(0, somex(croom), somey(croom), TRUE); tryct = 0; while(!rn2(5)) { if(++tryct > 100) { impossible("tryct overflow4"); break; } (void) mkobj_at(0, somex(croom), somey(croom), TRUE); } } } } /* * Place deposits of minerals (gold and misc gems) in the stone * surrounding the rooms on the map. * Also place kelp in water. */ STATIC_OVL void mineralize() { s_level *sp; struct obj *otmp; int goldprob, gemprob, x, y, cnt; /* Place kelp, except on the plane of water */ if (In_endgame(&u.uz)) return; for (x = 2; x < (COLNO - 2); x++) for (y = 1; y < (ROWNO - 1); y++) if ((levl[x][y].typ == POOL && !rn2(10)) || (levl[x][y].typ == MOAT && !rn2(30))) (void) mksobj_at(KELP_FROND, x, y, TRUE, FALSE); /* determine if it is even allowed; almost all special levels are excluded */ if (In_hell(&u.uz) || In_V_tower(&u.uz) || #ifdef REINCARNATION Is_rogue_level(&u.uz) || #endif level.flags.arboreal || ((sp = Is_special(&u.uz)) != 0 && !Is_oracle_level(&u.uz) && (!In_mines(&u.uz) || sp->flags.town) )) return; /* basic level-related probabilities */ goldprob = 20 + depth(&u.uz) / 3; gemprob = goldprob / 4; /* mines have ***MORE*** goodies - otherwise why mine? */ if (In_mines(&u.uz)) { goldprob *= 2; gemprob *= 3; } else if (In_quest(&u.uz)) { goldprob /= 4; gemprob /= 6; } /* * Seed rock areas with gold and/or gems. * We use fairly low level object handling to avoid unnecessary * overhead from placing things in the floor chain prior to burial. */ for (x = 2; x < (COLNO - 2); x++) for (y = 1; y < (ROWNO - 1); y++) if (levl[x][y+1].typ != STONE) { /* spot not eligible */ y += 2; /* next two spots aren't eligible either */ } else if (levl[x][y].typ != STONE) { /* this spot not eligible */ y += 1; /* next spot isn't eligible either */ } else if (!(levl[x][y].wall_info & W_NONDIGGABLE) && levl[x][y-1].typ == STONE && levl[x+1][y-1].typ == STONE && levl[x-1][y-1].typ == STONE && levl[x+1][y].typ == STONE && levl[x-1][y].typ == STONE && levl[x+1][y+1].typ == STONE && levl[x-1][y+1].typ == STONE) { if (rn2(1000) < goldprob) { if ((otmp = mksobj(GOLD_PIECE, FALSE, FALSE)) != 0) { otmp->ox = x, otmp->oy = y; otmp->quan = 1L + rnd(goldprob * 3); otmp->owt = weight(otmp); if (!rn2(3)) add_to_buried(otmp); else place_object(otmp, x, y); } } if (rn2(1000) < gemprob) { for (cnt = rnd(2 + dunlev(&u.uz) / 3); cnt > 0; cnt--) if ((otmp = mkobj(GEM_CLASS, FALSE)) != 0) { if (otmp->otyp == ROCK) { dealloc_obj(otmp); /* discard it */ } else { otmp->ox = x, otmp->oy = y; if (!rn2(3)) add_to_buried(otmp); else place_object(otmp, x, y); } } } } } void mklev() { struct mkroom *croom; if(getbones()) return; in_mklev = TRUE; makelevel(); bound_digging(); mineralize(); in_mklev = FALSE; /* has_morgue gets cleared once morgue is entered; graveyard stays set (graveyard might already be set even when has_morgue is clear [see fixup_special()], so don't update it unconditionally) */ if (level.flags.has_morgue) level.flags.graveyard = 1; if (!level.flags.is_maze_lev) { for (croom = &rooms[0]; croom != &rooms[nroom]; croom++) #ifdef SPECIALIZATION topologize(croom, FALSE); #else topologize(croom); #endif } set_wall_state(); } void #ifdef SPECIALIZATION topologize(croom, do_ordinary) register struct mkroom *croom; boolean do_ordinary; #else topologize(croom) register struct mkroom *croom; #endif { register int x, y, roomno = (croom - rooms) + ROOMOFFSET; register int lowx = croom->lx, lowy = croom->ly; register int hix = croom->hx, hiy = croom->hy; #ifdef SPECIALIZATION register schar rtype = croom->rtype; #endif register int subindex, nsubrooms = croom->nsubrooms; /* skip the room if already done; i.e. a shop handled out of order */ /* also skip if this is non-rectangular (it _must_ be done already) */ if ((int) levl[lowx][lowy].roomno == roomno || croom->irregular) return; #ifdef SPECIALIZATION # ifdef REINCARNATION if (Is_rogue_level(&u.uz)) do_ordinary = TRUE; /* vision routine helper */ # endif if ((rtype != OROOM) || do_ordinary) #endif { /* do innards first */ for(x = lowx; x <= hix; x++) for(y = lowy; y <= hiy; y++) #ifdef SPECIALIZATION if (rtype == OROOM) levl[x][y].roomno = NO_ROOM; else #endif levl[x][y].roomno = roomno; /* top and bottom edges */ for(x = lowx-1; x <= hix+1; x++) for(y = lowy-1; y <= hiy+1; y += (hiy-lowy+2)) { levl[x][y].edge = 1; if (levl[x][y].roomno) levl[x][y].roomno = SHARED; else levl[x][y].roomno = roomno; } /* sides */ for(x = lowx-1; x <= hix+1; x += (hix-lowx+2)) for(y = lowy; y <= hiy; y++) { levl[x][y].edge = 1; if (levl[x][y].roomno) levl[x][y].roomno = SHARED; else levl[x][y].roomno = roomno; } } /* subrooms */ for (subindex = 0; subindex < nsubrooms; subindex++) #ifdef SPECIALIZATION topologize(croom->sbrooms[subindex], (rtype != OROOM)); #else topologize(croom->sbrooms[subindex]); #endif } /* Find an unused room for a branch location. */ STATIC_OVL struct mkroom * find_branch_room(mp) coord *mp; { struct mkroom *croom = 0; if (nroom == 0) { mazexy(mp); /* already verifies location */ } else { /* not perfect - there may be only one stairway */ if(nroom > 2) { int tryct = 0; do croom = &rooms[rn2(nroom)]; while((croom == dnstairs_room || croom == upstairs_room || croom->rtype != OROOM) && (++tryct < 100)); } else croom = &rooms[rn2(nroom)]; do { if (!somexy(croom, mp)) impossible("Can't place branch!"); } while(occupied(mp->x, mp->y) || (levl[mp->x][mp->y].typ != CORR && levl[mp->x][mp->y].typ != ROOM)); } return croom; } /* Find the room for (x,y). Return null if not in a room. */ STATIC_OVL struct mkroom * pos_to_room(x, y) xchar x, y; { int i; struct mkroom *curr; for (curr = rooms, i = 0; i < nroom; curr++, i++) if (inside_room(curr, x, y)) return curr;; return (struct mkroom *) 0; } /* If given a branch, randomly place a special stair or portal. */ void place_branch(br, x, y) branch *br; /* branch to place */ xchar x, y; /* location */ { coord m; d_level *dest; boolean make_stairs; struct mkroom *br_room; /* * Return immediately if there is no branch to make or we have * already made one. This routine can be called twice when * a special level is loaded that specifies an SSTAIR location * as a favored spot for a branch. */ if (!br || made_branch) return; if (!x) { /* find random coordinates for branch */ br_room = find_branch_room(&m); x = m.x; y = m.y; } else { br_room = pos_to_room(x, y); } if (on_level(&br->end1, &u.uz)) { /* we're on end1 */ make_stairs = br->type != BR_NO_END1; dest = &br->end2; } else { /* we're on end2 */ make_stairs = br->type != BR_NO_END2; dest = &br->end1; } if (br->type == BR_PORTAL) { mkportal(x, y, dest->dnum, dest->dlevel); } else if (make_stairs) { sstairs.sx = x; sstairs.sy = y; sstairs.up = (char) on_level(&br->end1, &u.uz) ? br->end1_up : !br->end1_up; assign_level(&sstairs.tolev, dest); sstairs_room = br_room; levl[x][y].ladder = sstairs.up ? LA_UP : LA_DOWN; levl[x][y].typ = STAIRS; } /* * Set made_branch to TRUE even if we didn't make a stairwell (i.e. * make_stairs is false) since there is currently only one branch * per level, if we failed once, we're going to fail again on the * next call. */ made_branch = TRUE; } STATIC_OVL boolean bydoor(x, y) register xchar x, y; { register int typ; if (isok(x+1, y)) { typ = levl[x+1][y].typ; if (IS_DOOR(typ) || typ == SDOOR) return TRUE; } if (isok(x-1, y)) { typ = levl[x-1][y].typ; if (IS_DOOR(typ) || typ == SDOOR) return TRUE; } if (isok(x, y+1)) { typ = levl[x][y+1].typ; if (IS_DOOR(typ) || typ == SDOOR) return TRUE; } if (isok(x, y-1)) { typ = levl[x][y-1].typ; if (IS_DOOR(typ) || typ == SDOOR) return TRUE; } return FALSE; } /* see whether it is allowable to create a door at [x,y] */ int okdoor(x,y) register xchar x, y; { register boolean near_door = bydoor(x, y); return((levl[x][y].typ == HWALL || levl[x][y].typ == VWALL) && doorindex < DOORMAX && !near_door); } void dodoor(x,y,aroom) register int x, y; register struct mkroom *aroom; { if(doorindex >= DOORMAX) { impossible("DOORMAX exceeded?"); return; } dosdoor(x,y,aroom,rn2(8) ? DOOR : SDOOR); } boolean occupied(x, y) register xchar x, y; { return((boolean)(t_at(x, y) || IS_FURNITURE(levl[x][y].typ) || is_lava(x,y) || is_pool(x,y) || invocation_pos(x,y) )); } /* make a trap somewhere (in croom if mazeflag = 0 && !tm) */ /* if tm != null, make trap at that location */ void mktrap(num, mazeflag, croom, tm) register int num, mazeflag; register struct mkroom *croom; coord *tm; { register int kind; coord m; /* no traps in pools */ if (tm && is_pool(tm->x,tm->y)) return; if (num > 0 && num < TRAPNUM) { kind = num; #ifdef REINCARNATION } else if (Is_rogue_level(&u.uz)) { switch (rn2(7)) { default: kind = BEAR_TRAP; break; /* 0 */ case 1: kind = ARROW_TRAP; break; case 2: kind = DART_TRAP; break; case 3: kind = TRAPDOOR; break; case 4: kind = PIT; break; case 5: kind = SLP_GAS_TRAP; break; case 6: kind = RUST_TRAP; break; } #endif } else if (Inhell && !rn2(5)) { /* bias the frequency of fire traps in Gehennom */ kind = FIRE_TRAP; } else { unsigned lvl = level_difficulty(); do { kind = rnd(TRAPNUM-1); /* reject "too hard" traps */ switch (kind) { case MAGIC_PORTAL: kind = NO_TRAP; break; case ROLLING_BOULDER_TRAP: case SLP_GAS_TRAP: if (lvl < 2) kind = NO_TRAP; break; case LEVEL_TELEP: if (lvl < 5 || level.flags.noteleport) kind = NO_TRAP; break; case SPIKED_PIT: if (lvl < 5) kind = NO_TRAP; break; case LANDMINE: if (lvl < 6) kind = NO_TRAP; break; case WEB: if (lvl < 7) kind = NO_TRAP; break; case STATUE_TRAP: case POLY_TRAP: if (lvl < 8) kind = NO_TRAP; break; case FIRE_TRAP: if (!Inhell) kind = NO_TRAP; break; case TELEP_TRAP: if (level.flags.noteleport) kind = NO_TRAP; break; case HOLE: /* make these much less often than other traps */ if (rn2(7)) kind = NO_TRAP; break; } } while (kind == NO_TRAP); } if ((kind == TRAPDOOR || kind == HOLE) && !Can_fall_thru(&u.uz)) kind = ROCKTRAP; if (tm) m = *tm; else { register int tryct = 0; boolean avoid_boulder = (kind == PIT || kind == SPIKED_PIT || kind == TRAPDOOR || kind == HOLE); do { if (++tryct > 200) return; if (mazeflag) mazexy(&m); else if (!somexy(croom,&m)) return; } while (occupied(m.x, m.y) || (avoid_boulder && sobj_at(BOULDER, m.x, m.y))); } (void) maketrap(m.x, m.y, kind); if (kind == WEB) (void) makemon(&mons[PM_GIANT_SPIDER], m.x, m.y, NO_MM_FLAGS); } void mkstairs(x, y, up, croom) xchar x, y; char up; struct mkroom *croom; { if (!x) { impossible("mkstairs: bogus stair attempt at <%d,%d>", x, y); return; } /* * We can't make a regular stair off an end of the dungeon. This * attempt can happen when a special level is placed at an end and * has an up or down stair specified in its description file. */ if ((dunlev(&u.uz) == 1 && up) || (dunlev(&u.uz) == dunlevs_in_dungeon(&u.uz) && !up)) return; if(up) { xupstair = x; yupstair = y; upstairs_room = croom; } else { xdnstair = x; ydnstair = y; dnstairs_room = croom; } levl[x][y].typ = STAIRS; levl[x][y].ladder = up ? LA_UP : LA_DOWN; } STATIC_OVL void mkfount(mazeflag,croom) register int mazeflag; register struct mkroom *croom; { coord m; register int tryct = 0; do { if(++tryct > 200) return; if(mazeflag) mazexy(&m); else if (!somexy(croom, &m)) return; } while(occupied(m.x, m.y) || bydoor(m.x, m.y)); /* Put a fountain at m.x, m.y */ levl[m.x][m.y].typ = FOUNTAIN; /* Is it a "blessed" fountain? (affects drinking from fountain) */ if(!rn2(7)) levl[m.x][m.y].blessedftn = 1; level.flags.nfountains++; } #ifdef SINKS STATIC_OVL void mksink(croom) register struct mkroom *croom; { coord m; register int tryct = 0; do { if(++tryct > 200) return; if (!somexy(croom, &m)) return; } while(occupied(m.x, m.y) || bydoor(m.x, m.y)); /* Put a sink at m.x, m.y */ levl[m.x][m.y].typ = SINK; level.flags.nsinks++; } #endif /* SINKS */ STATIC_OVL void mkaltar(croom) register struct mkroom *croom; { coord m; register int tryct = 0; aligntyp al; if (croom->rtype != OROOM) return; do { if(++tryct > 200) return; if (!somexy(croom, &m)) return; } while (occupied(m.x, m.y) || bydoor(m.x, m.y)); /* Put an altar at m.x, m.y */ levl[m.x][m.y].typ = ALTAR; /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */ al = rn2((int)A_LAWFUL+2) - 1; levl[m.x][m.y].altarmask = Align2amask( al ); } static void mkgrave(croom) struct mkroom *croom; { coord m; register int tryct = 0; register struct obj *otmp; boolean dobell = !rn2(10); if(croom->rtype != OROOM) return; do { if(++tryct > 200) return; if (!somexy(croom, &m)) return; } while (occupied(m.x, m.y) || bydoor(m.x, m.y)); /* Put a grave at m.x, m.y */ make_grave(m.x, m.y, dobell ? "Saved by the bell!" : (char *) 0); /* Possibly fill it with objects */ if (!rn2(3)) (void) mkgold(0L, m.x, m.y); for (tryct = rn2(5); tryct; tryct--) { otmp = mkobj(RANDOM_CLASS, TRUE); if (!otmp) return; curse(otmp); otmp->ox = m.x; otmp->oy = m.y; add_to_buried(otmp); } /* Leave a bell, in case we accidentally buried someone alive */ if (dobell) (void) mksobj_at(BELL, m.x, m.y, TRUE, FALSE); return; } /* maze levels have slightly different constraints from normal levels */ #define x_maze_min 2 #define y_maze_min 2 /* * Major level transmutation: add a set of stairs (to the Sanctum) after * an earthquake that leaves behind a a new topology, centered at inv_pos. * Assumes there are no rooms within the invocation area and that inv_pos * is not too close to the edge of the map. Also assume the hero can see, * which is guaranteed for normal play due to the fact that sight is needed * to read the Book of the Dead. */ void mkinvokearea() { int dist; xchar xmin = inv_pos.x, xmax = inv_pos.x; xchar ymin = inv_pos.y, ymax = inv_pos.y; register xchar i; pline_The("floor shakes violently under you!"); pline_The("walls around you begin to bend and crumble!"); display_nhwindow(WIN_MESSAGE, TRUE); mkinvpos(xmin, ymin, 0); /* middle, before placing stairs */ for(dist = 1; dist < 7; dist++) { xmin--; xmax++; /* top and bottom */ if(dist != 3) { /* the area is wider that it is high */ ymin--; ymax++; for(i = xmin+1; i < xmax; i++) { mkinvpos(i, ymin, dist); mkinvpos(i, ymax, dist); } } /* left and right */ for(i = ymin; i <= ymax; i++) { mkinvpos(xmin, i, dist); mkinvpos(xmax, i, dist); } flush_screen(1); /* make sure the new glyphs shows up */ delay_output(); } You("are standing at the top of a stairwell leading down!"); mkstairs(u.ux, u.uy, 0, (struct mkroom *)0); /* down */ newsym(u.ux, u.uy); vision_full_recalc = 1; /* everything changed */ } /* Change level topology. Boulders in the vicinity are eliminated. * Temporarily overrides vision in the name of a nice effect. */ STATIC_OVL void mkinvpos(x,y,dist) xchar x,y; int dist; { struct trap *ttmp; struct obj *otmp; boolean make_rocks; register struct rm *lev = &levl[x][y]; /* clip at existing map borders if necessary */ if (!within_bounded_area(x, y, x_maze_min + 1, y_maze_min + 1, x_maze_max - 1, y_maze_max - 1)) { /* only outermost 2 columns and/or rows may be truncated due to edge */ if (dist < (7 - 2)) panic("mkinvpos: <%d,%d> (%d) off map edge!", x, y, dist); return; } /* clear traps */ if ((ttmp = t_at(x,y)) != 0) deltrap(ttmp); /* clear boulders; leave some rocks for non-{moat|trap} locations */ make_rocks = (dist != 1 && dist != 4 && dist != 5) ? TRUE : FALSE; while ((otmp = sobj_at(BOULDER, x, y)) != 0) { if (make_rocks) { fracture_rock(otmp); make_rocks = FALSE; /* don't bother with more rocks */ } else { obj_extract_self(otmp); obfree(otmp, (struct obj *)0); } } unblock_point(x,y); /* make sure vision knows this location is open */ /* fake out saved state */ lev->seenv = 0; lev->doormask = 0; if(dist < 6) lev->lit = TRUE; lev->waslit = TRUE; lev->horizontal = FALSE; viz_array[y][x] = (dist < 6 ) ? (IN_SIGHT|COULD_SEE) : /* short-circuit vision recalc */ COULD_SEE; switch(dist) { case 1: /* fire traps */ if (is_pool(x,y)) break; lev->typ = ROOM; ttmp = maketrap(x, y, FIRE_TRAP); if (ttmp) ttmp->tseen = TRUE; break; case 0: /* lit room locations */ case 2: case 3: case 6: /* unlit room locations */ lev->typ = ROOM; break; case 4: /* pools (aka a wide moat) */ case 5: lev->typ = MOAT; /* No kelp! */ break; default: impossible("mkinvpos called with dist %d", dist); break; } /* display new value of position; could have a monster/object on it */ newsym(x,y); } /* * The portal to Ludios is special. The entrance can only occur within a * vault in the main dungeon at a depth greater than 10. The Ludios branch * structure reflects this by having a bogus "source" dungeon: the value * of n_dgns (thus, Is_branchlev() will never find it). * * Ludios will remain isolated until the branch is corrected by this function. */ STATIC_OVL void mk_knox_portal(x, y) xchar x, y; { extern int n_dgns; /* from dungeon.c */ d_level *source; branch *br; schar u_depth; br = dungeon_branch("Fort Ludios"); if (on_level(&knox_level, &br->end1)) { source = &br->end2; } else { /* disallow Knox branch on a level with one branch already */ if(Is_branchlev(&u.uz)) return; source = &br->end1; } /* Already set or 2/3 chance of deferring until a later level. */ if (source->dnum < n_dgns || (rn2(3) #ifdef WIZARD && !wizard #endif )) return; if (! (u.uz.dnum == oracle_level.dnum /* in main dungeon */ && !at_dgn_entrance("The Quest") /* but not Quest's entry */ && (u_depth = depth(&u.uz)) > 10 /* beneath 10 */ && u_depth < depth(&medusa_level))) /* and above Medusa */ return; /* Adjust source to be current level and re-insert branch. */ *source = u.uz; insert_branch(br, TRUE); #ifdef DEBUG pline("Made knox portal."); #endif place_branch(br, x, y); } /*mklev.c*/ nethack-3.4.3/src/mkmap.c0100644000000000000000000003042407764735041013715 0ustar rootroot/* SCCS Id: @(#)mkmap.c 3.4 1996/05/23 */ /* Copyright (c) J. C. Collet, M. Stephenson and D. Cohrs, 1992 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "sp_lev.h" #define HEIGHT (ROWNO - 1) #define WIDTH (COLNO - 2) STATIC_DCL void FDECL(init_map,(SCHAR_P)); STATIC_DCL void FDECL(init_fill,(SCHAR_P,SCHAR_P)); STATIC_DCL schar FDECL(get_map,(int,int,SCHAR_P)); STATIC_DCL void FDECL(pass_one,(SCHAR_P,SCHAR_P)); STATIC_DCL void FDECL(pass_two,(SCHAR_P,SCHAR_P)); STATIC_DCL void FDECL(pass_three,(SCHAR_P,SCHAR_P)); STATIC_DCL void NDECL(wallify_map); STATIC_DCL void FDECL(join_map,(SCHAR_P,SCHAR_P)); STATIC_DCL void FDECL(finish_map,(SCHAR_P,SCHAR_P,XCHAR_P,XCHAR_P)); STATIC_DCL void FDECL(remove_room,(unsigned)); void FDECL(mkmap, (lev_init *)); char *new_locations; int min_rx, max_rx, min_ry, max_ry; /* rectangle bounds for regions */ static int n_loc_filled; STATIC_OVL void init_map(bg_typ) schar bg_typ; { register int i,j; for(i=1; i WIDTH || row >= HEIGHT) return bg_typ; return levl[col][row].typ; } static int dirs[16] = { -1, -1 /**/, -1, 0 /**/, -1, 1 /**/, 0, -1 /**/, 0, 1 /**/, 1, -1 /**/, 1, 0 /**/, 1, 1}; STATIC_OVL void pass_one(bg_typ, fg_typ) schar bg_typ, fg_typ; { register int i,j; short count, dr; for(i=2; i<=WIDTH; i++) for(j=1; j 0 && (anyroom ? IS_ROOM(levl[sx][sy].typ) : levl[sx][sy].typ == fg_typ) && (int) levl[sx][sy].roomno != rmno) sx--; sx++; /* compensate for extra decrement */ /* assume sx,sy is valid */ if(sx < min_rx) min_rx = sx; if(sy < min_ry) min_ry = sy; for(i=sx; i<=WIDTH && levl[i][sy].typ == fg_typ; i++) { levl[i][sy].roomno = rmno; levl[i][sy].lit = lit; if(anyroom) { /* add walls to room as well */ register int ii,jj; for(ii= (i == sx ? i-1 : i); ii <= i+1; ii++) for(jj = sy-1; jj <= sy+1; jj++) if(isok(ii,jj) && (IS_WALL(levl[ii][jj].typ) || IS_DOOR(levl[ii][jj].typ))) { levl[ii][jj].edge = 1; if(lit) levl[ii][jj].lit = lit; if ((int) levl[ii][jj].roomno != rmno) levl[ii][jj].roomno = SHARED; } } n_loc_filled++; } nx = i; if(isok(sx,sy-1)) { for(i=sx; isx || isok(i-1,sy-1)) && levl[i-1][sy-1].typ == fg_typ) { if ((int) levl[i-1][sy-1].roomno != rmno) flood_fill_rm(i-1,sy-1,rmno,lit,anyroom); } if((isx || isok(i-1,sy+1)) && levl[i-1][sy+1].typ == fg_typ) { if ((int) levl[i-1][sy+1].roomno != rmno) flood_fill_rm(i-1,sy+1,rmno,lit,anyroom); } if((i max_rx) max_rx = nx - 1; /* nx is just past valid region */ if(sy > max_ry) max_ry = sy; } /* * If we have drawn a map without walls, this allows us to * auto-magically wallify it. Taken from lev_main.c. */ STATIC_OVL void wallify_map() { int x, y, xx, yy; for(x = 1; x < COLNO; x++) for(y = 0; y < ROWNO; y++) if(levl[x][y].typ == STONE) { for(yy = y - 1; yy <= y+1; yy++) for(xx = x - 1; xx <= x+1; xx++) if(isok(xx,yy) && levl[xx][yy].typ == ROOM) { if(yy != y) levl[x][y].typ = HWALL; else levl[x][y].typ = VWALL; } } } STATIC_OVL void join_map(bg_typ, fg_typ) schar bg_typ, fg_typ; { register struct mkroom *croom, *croom2; register int i, j; int sx, sy; coord sm, em; /* first, use flood filling to find all of the regions that need joining */ for(i=2; i<=WIDTH; i++) for(j=1; j 3) { add_room(min_rx, min_ry, max_rx, max_ry, FALSE, OROOM, TRUE); rooms[nroom-1].irregular = TRUE; if(nroom >= (MAXNROFROOMS*2)) goto joinm; } else { /* * it's a tiny hole; erase it from the map to avoid * having the player end up here with no way out. */ for(sx = min_rx; sx<=max_rx; sx++) for(sy = min_ry; sy<=max_ry; sy++) if ((int) levl[sx][sy].roomno == nroom + ROOMOFFSET) { levl[sx][sy].typ = bg_typ; levl[sx][sy].roomno = NO_ROOM; } } } } joinm: /* * Ok, now we can actually join the regions with fg_typ's. * The rooms are already sorted due to the previous loop, * so don't call sort_rooms(), which can screw up the roomno's * validity in the levl structure. */ for(croom = &rooms[0], croom2 = croom + 1; croom2 < &rooms[nroom]; ) { /* pick random starting and end locations for "corridor" */ if(!somexy(croom, &sm) || !somexy(croom2, &em)) { /* ack! -- the level is going to be busted */ /* arbitrarily pick centers of both rooms and hope for the best */ impossible("No start/end room loc in join_map."); sm.x = croom->lx + ((croom->hx - croom->lx) / 2); sm.y = croom->ly + ((croom->hy - croom->ly) / 2); em.x = croom2->lx + ((croom2->hx - croom2->lx) / 2); em.y = croom2->ly + ((croom2->hy - croom2->ly) / 2); } (void) dig_corridor(&sm, &em, FALSE, fg_typ, bg_typ); /* choose next region to join */ /* only increment croom if croom and croom2 are non-overlapping */ if(croom2->lx > croom->hx || ((croom2->ly > croom->hy || croom2->hy < croom->ly) && rn2(3))) { croom = croom2; } croom2++; /* always increment the next room */ } } STATIC_OVL void finish_map(fg_typ, bg_typ, lit, walled) schar fg_typ, bg_typ; boolean lit, walled; { int i, j; if(walled) wallify_map(); if(lit) { for(i=1; i= 0; --i) { croom = &rooms[i]; if (croom->hx < lx || croom->lx >= hx || croom->hy < ly || croom->ly >= hy) continue; /* no overlap */ if (croom->lx < lx || croom->hx >= hx || croom->ly < ly || croom->hy >= hy) { /* partial overlap */ /* TODO: ensure remaining parts of room are still joined */ if (!croom->irregular) impossible("regular room in joined map"); } else { /* total overlap, remove the room */ remove_room((unsigned)i); } } } /* * Remove roomno from the rooms array, decrementing nroom. Also updates * all level roomno values of affected higher numbered rooms. Assumes * level structure contents corresponding to roomno have already been reset. * Currently handles only the removal of rooms that have no subrooms. */ STATIC_OVL void remove_room(roomno) unsigned roomno; { struct mkroom *croom = &rooms[roomno]; struct mkroom *maxroom = &rooms[--nroom]; int i, j; unsigned oroomno; if (croom != maxroom) { /* since the order in the array only matters for making corridors, * copy the last room over the one being removed on the assumption * that corridors have already been dug. */ (void) memcpy((genericptr_t)croom, (genericptr_t)maxroom, sizeof(struct mkroom)); /* since maxroom moved, update affected level roomno values */ oroomno = nroom + ROOMOFFSET; roomno += ROOMOFFSET; for (i = croom->lx; i <= croom->hx; ++i) for (j = croom->ly; j <= croom->hy; ++j) { if (levl[i][j].roomno == oroomno) levl[i][j].roomno = roomno; } } maxroom->hx = -1; /* just like add_room */ } #define N_P1_ITER 1 /* tune map generation via this value */ #define N_P2_ITER 1 /* tune map generation via this value */ #define N_P3_ITER 2 /* tune map smoothing via this value */ void mkmap(init_lev) lev_init *init_lev; { schar bg_typ = init_lev->bg, fg_typ = init_lev->fg; boolean smooth = init_lev->smoothed, join = init_lev->joined; xchar lit = init_lev->lit, walled = init_lev->walled; int i; if(lit < 0) lit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? 1 : 0; new_locations = (char *)alloc((WIDTH+1) * HEIGHT); init_map(bg_typ); init_fill(bg_typ, fg_typ); for(i = 0; i < N_P1_ITER; i++) pass_one(bg_typ, fg_typ); for(i = 0; i < N_P2_ITER; i++) pass_two(bg_typ, fg_typ); if(smooth) for(i = 0; i < N_P3_ITER; i++) pass_three(bg_typ, fg_typ); if(join) join_map(bg_typ, fg_typ); finish_map(fg_typ, bg_typ, (boolean)lit, (boolean)walled); /* a walled, joined level is cavernous, not mazelike -dlc */ if (walled && join) { level.flags.is_maze_lev = FALSE; level.flags.is_cavernous_lev = TRUE; } free(new_locations); } /*mkmap.c*/ nethack-3.4.3/src/mkmaze.c0100644000000000000000000010723407764735041014100 0ustar rootroot/* SCCS Id: @(#)mkmaze.c 3.4 2002/04/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "sp_lev.h" #include "lev.h" /* save & restore info */ /* from sp_lev.c, for fixup_special() */ extern char *lev_message; extern lev_region *lregions; extern int num_lregions; STATIC_DCL boolean FDECL(iswall,(int,int)); STATIC_DCL boolean FDECL(iswall_or_stone,(int,int)); STATIC_DCL boolean FDECL(is_solid,(int,int)); STATIC_DCL int FDECL(extend_spine, (int [3][3], int, int, int)); STATIC_DCL boolean FDECL(okay,(int,int,int)); STATIC_DCL void FDECL(maze0xy,(coord *)); STATIC_DCL boolean FDECL(put_lregion_here,(XCHAR_P,XCHAR_P,XCHAR_P, XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,BOOLEAN_P,d_level *)); STATIC_DCL void NDECL(fixup_special); STATIC_DCL void FDECL(move, (int *,int *,int)); STATIC_DCL void NDECL(setup_waterlevel); STATIC_DCL void NDECL(unsetup_waterlevel); STATIC_OVL boolean iswall(x,y) int x,y; { register int type; if (!isok(x,y)) return FALSE; type = levl[x][y].typ; return (IS_WALL(type) || IS_DOOR(type) || type == SDOOR || type == IRONBARS); } STATIC_OVL boolean iswall_or_stone(x,y) int x,y; { register int type; /* out of bounds = stone */ if (!isok(x,y)) return TRUE; type = levl[x][y].typ; return (type == STONE || IS_WALL(type) || IS_DOOR(type) || type == SDOOR || type == IRONBARS); } /* return TRUE if out of bounds, wall or rock */ STATIC_OVL boolean is_solid(x,y) int x, y; { return (!isok(x,y) || IS_STWALL(levl[x][y].typ)); } /* * Return 1 (not TRUE - we're doing bit vectors here) if we want to extend * a wall spine in the (dx,dy) direction. Return 0 otherwise. * * To extend a wall spine in that direction, first there must be a wall there. * Then, extend a spine unless the current position is surrounded by walls * in the direction given by (dx,dy). E.g. if 'x' is our location, 'W' * a wall, '.' a room, 'a' anything (we don't care), and our direction is * (0,1) - South or down - then: * * a a a * W x W This would not extend a spine from x down * W W W (a corridor of walls is formed). * * a a a * W x W This would extend a spine from x down. * . W W */ STATIC_OVL int extend_spine(locale, wall_there, dx, dy) int locale[3][3]; int wall_there, dx, dy; { int spine, nx, ny; nx = 1 + dx; ny = 1 + dy; if (wall_there) { /* wall in that direction */ if (dx) { if (locale[ 1][0] && locale[ 1][2] && /* EW are wall/stone */ locale[nx][0] && locale[nx][2]) { /* diag are wall/stone */ spine = 0; } else { spine = 1; } } else { /* dy */ if (locale[0][ 1] && locale[2][ 1] && /* NS are wall/stone */ locale[0][ny] && locale[2][ny]) { /* diag are wall/stone */ spine = 0; } else { spine = 1; } } } else { spine = 0; } return spine; } /* * Wall cleanup. This function has two purposes: (1) remove walls that * are totally surrounded by stone - they are redundant. (2) correct * the types so that they extend and connect to each other. */ void wallification(x1, y1, x2, y2) int x1, y1, x2, y2; { uchar type; register int x,y; struct rm *lev; int bits; int locale[3][3]; /* rock or wall status surrounding positions */ /* * Value 0 represents a free-standing wall. It could be anything, * so even though this table says VWALL, we actually leave whatever * typ was there alone. */ static xchar spine_array[16] = { VWALL, HWALL, HWALL, HWALL, VWALL, TRCORNER, TLCORNER, TDWALL, VWALL, BRCORNER, BLCORNER, TUWALL, VWALL, TLWALL, TRWALL, CROSSWALL }; /* sanity check on incoming variables */ if (x1<0 || x2>=COLNO || x1>x2 || y1<0 || y2>=ROWNO || y1>y2) panic("wallification: bad bounds (%d,%d) to (%d,%d)",x1,y1,x2,y2); /* Step 1: change walls surrounded by rock to rock. */ for(x = x1; x <= x2; x++) for(y = y1; y <= y2; y++) { lev = &levl[x][y]; type = lev->typ; if (IS_WALL(type) && type != DBWALL) { if (is_solid(x-1,y-1) && is_solid(x-1,y ) && is_solid(x-1,y+1) && is_solid(x, y-1) && is_solid(x, y+1) && is_solid(x+1,y-1) && is_solid(x+1,y ) && is_solid(x+1,y+1)) lev->typ = STONE; } } /* * Step 2: set the correct wall type. We can't combine steps * 1 and 2 into a single sweep because we depend on knowing if * the surrounding positions are stone. */ for(x = x1; x <= x2; x++) for(y = y1; y <= y2; y++) { lev = &levl[x][y]; type = lev->typ; if ( !(IS_WALL(type) && type != DBWALL)) continue; /* set the locations TRUE if rock or wall or out of bounds */ locale[0][0] = iswall_or_stone(x-1,y-1); locale[1][0] = iswall_or_stone( x,y-1); locale[2][0] = iswall_or_stone(x+1,y-1); locale[0][1] = iswall_or_stone(x-1, y); locale[2][1] = iswall_or_stone(x+1, y); locale[0][2] = iswall_or_stone(x-1,y+1); locale[1][2] = iswall_or_stone( x,y+1); locale[2][2] = iswall_or_stone(x+1,y+1); /* determine if wall should extend to each direction NSEW */ bits = (extend_spine(locale, iswall(x,y-1), 0, -1) << 3) | (extend_spine(locale, iswall(x,y+1), 0, 1) << 2) | (extend_spine(locale, iswall(x+1,y), 1, 0) << 1) | extend_spine(locale, iswall(x-1,y), -1, 0); /* don't change typ if wall is free-standing */ if (bits) lev->typ = spine_array[bits]; } } STATIC_OVL boolean okay(x,y,dir) int x,y; register int dir; { move(&x,&y,dir); move(&x,&y,dir); if(x<3 || y<3 || x>x_maze_max || y>y_maze_max || levl[x][y].typ != 0) return(FALSE); return(TRUE); } STATIC_OVL void maze0xy(cc) /* find random starting point for maze generation */ coord *cc; { cc->x = 3 + 2*rn2((x_maze_max>>1) - 1); cc->y = 3 + 2*rn2((y_maze_max>>1) - 1); return; } /* * Bad if: * pos is occupied OR * pos is inside restricted region (lx,ly,hx,hy) OR * NOT (pos is corridor and a maze level OR pos is a room OR pos is air) */ boolean bad_location(x, y, lx, ly, hx, hy) xchar x, y; xchar lx, ly, hx, hy; { return((boolean)(occupied(x, y) || within_bounded_area(x,y, lx,ly, hx,hy) || !((levl[x][y].typ == CORR && level.flags.is_maze_lev) || levl[x][y].typ == ROOM || levl[x][y].typ == AIR))); } /* pick a location in area (lx, ly, hx, hy) but not in (nlx, nly, nhx, nhy) */ /* and place something (based on rtype) in that region */ void place_lregion(lx, ly, hx, hy, nlx, nly, nhx, nhy, rtype, lev) xchar lx, ly, hx, hy; xchar nlx, nly, nhx, nhy; xchar rtype; d_level *lev; { int trycnt; boolean oneshot; xchar x, y; if(!lx) { /* default to whole level */ /* * if there are rooms and this a branch, let place_branch choose * the branch location (to avoid putting branches in corridors). */ if(rtype == LR_BRANCH && nroom) { place_branch(Is_branchlev(&u.uz), 0, 0); return; } lx = 1; hx = COLNO-1; ly = 1; hy = ROWNO-1; } /* first a probabilistic approach */ oneshot = (lx == hx && ly == hy); for (trycnt = 0; trycnt < 200; trycnt++) { x = rn1((hx - lx) + 1, lx); y = rn1((hy - ly) + 1, ly); if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)) return; } /* then a deterministic one */ oneshot = TRUE; for (x = lx; x <= hx; x++) for (y = ly; y <= hy; y++) if (put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev)) return; impossible("Couldn't place lregion type %d!", rtype); } STATIC_OVL boolean put_lregion_here(x,y,nlx,nly,nhx,nhy,rtype,oneshot,lev) xchar x, y; xchar nlx, nly, nhx, nhy; xchar rtype; boolean oneshot; d_level *lev; { if (bad_location(x, y, nlx, nly, nhx, nhy)) { if (!oneshot) { return FALSE; /* caller should try again */ } else { /* Must make do with the only location possible; avoid failure due to a misplaced trap. It might still fail if there's a dungeon feature here. */ struct trap *t = t_at(x,y); if (t && t->ttyp != MAGIC_PORTAL) deltrap(t); if (bad_location(x, y, nlx, nly, nhx, nhy)) return FALSE; } } switch (rtype) { case LR_TELE: case LR_UPTELE: case LR_DOWNTELE: /* "something" means the player in this case */ if(MON_AT(x, y)) { /* move the monster if no choice, or just try again */ if(oneshot) (void) rloc(m_at(x,y), FALSE); else return(FALSE); } u_on_newpos(x, y); break; case LR_PORTAL: mkportal(x, y, lev->dnum, lev->dlevel); break; case LR_DOWNSTAIR: case LR_UPSTAIR: mkstairs(x, y, (char)rtype, (struct mkroom *)0); break; case LR_BRANCH: place_branch(Is_branchlev(&u.uz), x, y); break; } return(TRUE); } static boolean was_waterlevel; /* ugh... this shouldn't be needed */ /* this is special stuff that the level compiler cannot (yet) handle */ STATIC_OVL void fixup_special() { register lev_region *r = lregions; struct d_level lev; register int x, y; struct mkroom *croom; boolean added_branch = FALSE; if (was_waterlevel) { was_waterlevel = FALSE; u.uinwater = 0; unsetup_waterlevel(); } else if (Is_waterlevel(&u.uz)) { level.flags.hero_memory = 0; was_waterlevel = TRUE; /* water level is an odd beast - it has to be set up before calling place_lregions etc. */ setup_waterlevel(); } for(x = 0; x < num_lregions; x++, r++) { switch(r->rtype) { case LR_BRANCH: added_branch = TRUE; goto place_it; case LR_PORTAL: if(*r->rname.str >= '0' && *r->rname.str <= '9') { /* "chutes and ladders" */ lev = u.uz; lev.dlevel = atoi(r->rname.str); } else { s_level *sp = find_level(r->rname.str); lev = sp->dlevel; } /* fall into... */ case LR_UPSTAIR: case LR_DOWNSTAIR: place_it: place_lregion(r->inarea.x1, r->inarea.y1, r->inarea.x2, r->inarea.y2, r->delarea.x1, r->delarea.y1, r->delarea.x2, r->delarea.y2, r->rtype, &lev); break; case LR_TELE: case LR_UPTELE: case LR_DOWNTELE: /* save the region outlines for goto_level() */ if(r->rtype == LR_TELE || r->rtype == LR_UPTELE) { updest.lx = r->inarea.x1; updest.ly = r->inarea.y1; updest.hx = r->inarea.x2; updest.hy = r->inarea.y2; updest.nlx = r->delarea.x1; updest.nly = r->delarea.y1; updest.nhx = r->delarea.x2; updest.nhy = r->delarea.y2; } if(r->rtype == LR_TELE || r->rtype == LR_DOWNTELE) { dndest.lx = r->inarea.x1; dndest.ly = r->inarea.y1; dndest.hx = r->inarea.x2; dndest.hy = r->inarea.y2; dndest.nlx = r->delarea.x1; dndest.nly = r->delarea.y1; dndest.nhx = r->delarea.x2; dndest.nhy = r->delarea.y2; } /* place_lregion gets called from goto_level() */ break; } if (r->rname.str) free((genericptr_t) r->rname.str), r->rname.str = 0; } /* place dungeon branch if not placed above */ if (!added_branch && Is_branchlev(&u.uz)) { place_lregion(0,0,0,0,0,0,0,0,LR_BRANCH,(d_level *)0); } /* KMH -- Sokoban levels */ if(In_sokoban(&u.uz)) sokoban_detect(); /* Still need to add some stuff to level file */ if (Is_medusa_level(&u.uz)) { struct obj *otmp; int tryct; croom = &rooms[0]; /* only one room on the medusa level */ for (tryct = rnd(4); tryct; tryct--) { x = somex(croom); y = somey(croom); if (goodpos(x, y, (struct monst *)0, 0)) { otmp = mk_tt_object(STATUE, x, y); while (otmp && (poly_when_stoned(&mons[otmp->corpsenm]) || pm_resistance(&mons[otmp->corpsenm],MR_STONE))) { otmp->corpsenm = rndmonnum(); otmp->owt = weight(otmp); } } } if (rn2(2)) otmp = mk_tt_object(STATUE, somex(croom), somey(croom)); else /* Medusa statues don't contain books */ otmp = mkcorpstat(STATUE, (struct monst *)0, (struct permonst *)0, somex(croom), somey(croom), FALSE); if (otmp) { while (pm_resistance(&mons[otmp->corpsenm],MR_STONE) || poly_when_stoned(&mons[otmp->corpsenm])) { otmp->corpsenm = rndmonnum(); otmp->owt = weight(otmp); } } } else if(Is_wiz1_level(&u.uz)) { croom = search_special(MORGUE); create_secret_door(croom, W_SOUTH|W_EAST|W_WEST); } else if(Is_knox(&u.uz)) { /* using an unfilled morgue for rm id */ croom = search_special(MORGUE); /* avoid inappropriate morgue-related messages */ level.flags.graveyard = level.flags.has_morgue = 0; croom->rtype = OROOM; /* perhaps it should be set to VAULT? */ /* stock the main vault */ for(x = croom->lx; x <= croom->hx; x++) for(y = croom->ly; y <= croom->hy; y++) { (void) mkgold((long) rn1(300, 600), x, y); if (!rn2(3) && !is_pool(x,y)) (void)maketrap(x, y, rn2(3) ? LANDMINE : SPIKED_PIT); } } else if (Role_if(PM_PRIEST) && In_quest(&u.uz)) { /* less chance for undead corpses (lured from lower morgues) */ level.flags.graveyard = 1; } else if (Is_stronghold(&u.uz)) { level.flags.graveyard = 1; } else if(Is_sanctum(&u.uz)) { croom = search_special(TEMPLE); create_secret_door(croom, W_ANY); } else if(on_level(&u.uz, &orcus_level)) { register struct monst *mtmp, *mtmp2; /* it's a ghost town, get rid of shopkeepers */ for(mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if(mtmp->isshk) mongone(mtmp); } } if(lev_message) { char *str, *nl; for(str = lev_message; (nl = index(str, '\n')) != 0; str = nl+1) { *nl = '\0'; pline("%s", str); } if(*str) pline("%s", str); free((genericptr_t)lev_message); lev_message = 0; } if (lregions) free((genericptr_t) lregions), lregions = 0; num_lregions = 0; } void makemaz(s) register const char *s; { int x,y; char protofile[20]; s_level *sp = Is_special(&u.uz); coord mm; if(*s) { if(sp && sp->rndlevs) Sprintf(protofile, "%s-%d", s, rnd((int) sp->rndlevs)); else Strcpy(protofile, s); } else if(*(dungeons[u.uz.dnum].proto)) { if(dunlevs_in_dungeon(&u.uz) > 1) { if(sp && sp->rndlevs) Sprintf(protofile, "%s%d-%d", dungeons[u.uz.dnum].proto, dunlev(&u.uz), rnd((int) sp->rndlevs)); else Sprintf(protofile, "%s%d", dungeons[u.uz.dnum].proto, dunlev(&u.uz)); } else if(sp && sp->rndlevs) { Sprintf(protofile, "%s-%d", dungeons[u.uz.dnum].proto, rnd((int) sp->rndlevs)); } else Strcpy(protofile, dungeons[u.uz.dnum].proto); } else Strcpy(protofile, ""); #ifdef WIZARD /* SPLEVTYPE format is "level-choice,level-choice"... */ if (wizard && *protofile && sp && sp->rndlevs) { char *ep = getenv("SPLEVTYPE"); /* not nh_getenv */ if (ep) { /* rindex always succeeds due to code in prior block */ int len = (rindex(protofile, '-') - protofile) + 1; while (ep && *ep) { if (!strncmp(ep, protofile, len)) { int pick = atoi(ep + len); /* use choice only if valid */ if (pick > 0 && pick <= (int) sp->rndlevs) Sprintf(protofile + len, "%d", pick); break; } else { ep = index(ep, ','); if (ep) ++ep; } } } } #endif if(*protofile) { Strcat(protofile, LEV_EXT); if(load_special(protofile)) { fixup_special(); /* some levels can end up with monsters on dead mon list, including light source monsters */ dmonsfree(); return; /* no mazification right now */ } impossible("Couldn't load \"%s\" - making a maze.", protofile); } level.flags.is_maze_lev = TRUE; #ifndef WALLIFIED_MAZE for(x = 2; x < x_maze_max; x++) for(y = 2; y < y_maze_max; y++) levl[x][y].typ = STONE; #else for(x = 2; x <= x_maze_max; x++) for(y = 2; y <= y_maze_max; y++) levl[x][y].typ = ((x % 2) && (y % 2)) ? STONE : HWALL; #endif maze0xy(&mm); walkfrom((int) mm.x, (int) mm.y); /* put a boulder at the maze center */ (void) mksobj_at(BOULDER, (int) mm.x, (int) mm.y, TRUE, FALSE); #ifdef WALLIFIED_MAZE wallification(2, 2, x_maze_max, y_maze_max); #endif mazexy(&mm); mkstairs(mm.x, mm.y, 1, (struct mkroom *)0); /* up */ if (!Invocation_lev(&u.uz)) { mazexy(&mm); mkstairs(mm.x, mm.y, 0, (struct mkroom *)0); /* down */ } else { /* choose "vibrating square" location */ #define x_maze_min 2 #define y_maze_min 2 /* * Pick a position where the stairs down to Moloch's Sanctum * level will ultimately be created. At that time, an area * will be altered: walls removed, moat and traps generated, * boulders destroyed. The position picked here must ensure * that that invocation area won't extend off the map. * * We actually allow up to 2 squares around the usual edge of * the area to get truncated; see mkinvokearea(mklev.c). */ #define INVPOS_X_MARGIN (6 - 2) #define INVPOS_Y_MARGIN (5 - 2) #define INVPOS_DISTANCE 11 int x_range = x_maze_max - x_maze_min - 2*INVPOS_X_MARGIN - 1, y_range = y_maze_max - y_maze_min - 2*INVPOS_Y_MARGIN - 1; #ifdef DEBUG if (x_range <= INVPOS_X_MARGIN || y_range <= INVPOS_Y_MARGIN || (x_range * y_range) <= (INVPOS_DISTANCE * INVPOS_DISTANCE)) panic("inv_pos: maze is too small! (%d x %d)", x_maze_max, y_maze_max); #endif inv_pos.x = inv_pos.y = 0; /*{occupied() => invocation_pos()}*/ do { x = rn1(x_range, x_maze_min + INVPOS_X_MARGIN + 1); y = rn1(y_range, y_maze_min + INVPOS_Y_MARGIN + 1); /* we don't want it to be too near the stairs, nor to be on a spot that's already in use (wall|trap) */ } while (x == xupstair || y == yupstair || /*(direct line)*/ abs(x - xupstair) == abs(y - yupstair) || distmin(x, y, xupstair, yupstair) <= INVPOS_DISTANCE || !SPACE_POS(levl[x][y].typ) || occupied(x, y)); inv_pos.x = x; inv_pos.y = y; #undef INVPOS_X_MARGIN #undef INVPOS_Y_MARGIN #undef INVPOS_DISTANCE #undef x_maze_min #undef y_maze_min } /* place branch stair or portal */ place_branch(Is_branchlev(&u.uz), 0, 0); for(x = rn1(8,11); x; x--) { mazexy(&mm); (void) mkobj_at(rn2(2) ? GEM_CLASS : 0, mm.x, mm.y, TRUE); } for(x = rn1(10,2); x; x--) { mazexy(&mm); (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE); } for (x = rn2(3); x; x--) { mazexy(&mm); (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS); } for(x = rn1(5,7); x; x--) { mazexy(&mm); (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS); } for(x = rn1(6,7); x; x--) { mazexy(&mm); (void) mkgold(0L,mm.x,mm.y); } for(x = rn1(6,7); x; x--) mktrap(0,1,(struct mkroom *) 0, (coord*) 0); } #ifdef MICRO /* Make the mazewalk iterative by faking a stack. This is needed to * ensure the mazewalk is successful in the limited stack space of * the program. This iterative version uses the minimum amount of stack * that is totally safe. */ void walkfrom(x,y) int x,y; { #define CELLS (ROWNO * COLNO) / 4 /* a maze cell is 4 squares */ char mazex[CELLS + 1], mazey[CELLS + 1]; /* char's are OK */ int q, a, dir, pos; int dirs[4]; pos = 1; mazex[pos] = (char) x; mazey[pos] = (char) y; while (pos) { x = (int) mazex[pos]; y = (int) mazey[pos]; if(!IS_DOOR(levl[x][y].typ)) { /* might still be on edge of MAP, so don't overwrite */ #ifndef WALLIFIED_MAZE levl[x][y].typ = CORR; #else levl[x][y].typ = ROOM; #endif levl[x][y].flags = 0; } q = 0; for (a = 0; a < 4; a++) if(okay(x, y, a)) dirs[q++]= a; if (!q) pos--; else { dir = dirs[rn2(q)]; move(&x, &y, dir); #ifndef WALLIFIED_MAZE levl[x][y].typ = CORR; #else levl[x][y].typ = ROOM; #endif move(&x, &y, dir); pos++; if (pos > CELLS) panic("Overflow in walkfrom"); mazex[pos] = (char) x; mazey[pos] = (char) y; } } } #else void walkfrom(x,y) int x,y; { register int q,a,dir; int dirs[4]; if(!IS_DOOR(levl[x][y].typ)) { /* might still be on edge of MAP, so don't overwrite */ #ifndef WALLIFIED_MAZE levl[x][y].typ = CORR; #else levl[x][y].typ = ROOM; #endif levl[x][y].flags = 0; } while(1) { q = 0; for(a = 0; a < 4; a++) if(okay(x,y,a)) dirs[q++]= a; if(!q) return; dir = dirs[rn2(q)]; move(&x,&y,dir); #ifndef WALLIFIED_MAZE levl[x][y].typ = CORR; #else levl[x][y].typ = ROOM; #endif move(&x,&y,dir); walkfrom(x,y); } } #endif /* MICRO */ STATIC_OVL void move(x,y,dir) register int *x, *y; register int dir; { switch(dir){ case 0: --(*y); break; case 1: (*x)++; break; case 2: (*y)++; break; case 3: --(*x); break; default: panic("move: bad direction"); } } void mazexy(cc) /* find random point in generated corridors, so we don't create items in moats, bunkers, or walls */ coord *cc; { int cpt=0; do { cc->x = 3 + 2*rn2((x_maze_max>>1) - 1); cc->y = 3 + 2*rn2((y_maze_max>>1) - 1); cpt++; } while (cpt < 100 && levl[cc->x][cc->y].typ != #ifdef WALLIFIED_MAZE ROOM #else CORR #endif ); if (cpt >= 100) { register int x, y; /* last try */ for (x = 0; x < (x_maze_max>>1) - 1; x++) for (y = 0; y < (y_maze_max>>1) - 1; y++) { cc->x = 3 + 2 * x; cc->y = 3 + 2 * y; if (levl[cc->x][cc->y].typ == #ifdef WALLIFIED_MAZE ROOM #else CORR #endif ) return; } panic("mazexy: can't find a place!"); } return; } void bound_digging() /* put a non-diggable boundary around the initial portion of a level map. * assumes that no level will initially put things beyond the isok() range. * * we can't bound unconditionally on the last line with something in it, * because that something might be a niche which was already reachable, * so the boundary would be breached * * we can't bound unconditionally on one beyond the last line, because * that provides a window of abuse for WALLIFIED_MAZE special levels */ { register int x,y; register unsigned typ; register struct rm *lev; boolean found, nonwall; int xmin,xmax,ymin,ymax; if(Is_earthlevel(&u.uz)) return; /* everything diggable here */ found = nonwall = FALSE; for(xmin=0; !found; xmin++) { lev = &levl[xmin][0]; for(y=0; y<=ROWNO-1; y++, lev++) { typ = lev->typ; if(typ != STONE) { found = TRUE; if(!IS_WALL(typ)) nonwall = TRUE; } } } xmin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1; if (xmin < 0) xmin = 0; found = nonwall = FALSE; for(xmax=COLNO-1; !found; xmax--) { lev = &levl[xmax][0]; for(y=0; y<=ROWNO-1; y++, lev++) { typ = lev->typ; if(typ != STONE) { found = TRUE; if(!IS_WALL(typ)) nonwall = TRUE; } } } xmax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1; if (xmax >= COLNO) xmax = COLNO-1; found = nonwall = FALSE; for(ymin=0; !found; ymin++) { lev = &levl[xmin][ymin]; for(x=xmin; x<=xmax; x++, lev += ROWNO) { typ = lev->typ; if(typ != STONE) { found = TRUE; if(!IS_WALL(typ)) nonwall = TRUE; } } } ymin -= (nonwall || !level.flags.is_maze_lev) ? 2 : 1; found = nonwall = FALSE; for(ymax=ROWNO-1; !found; ymax--) { lev = &levl[xmin][ymax]; for(x=xmin; x<=xmax; x++, lev += ROWNO) { typ = lev->typ; if(typ != STONE) { found = TRUE; if(!IS_WALL(typ)) nonwall = TRUE; } } } ymax += (nonwall || !level.flags.is_maze_lev) ? 2 : 1; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (y <= ymin || y >= ymax || x <= xmin || x >= xmax) { #ifdef DCC30_BUG lev = &levl[x][y]; lev->wall_info |= W_NONDIGGABLE; #else levl[x][y].wall_info |= W_NONDIGGABLE; #endif } } void mkportal(x, y, todnum, todlevel) register xchar x, y, todnum, todlevel; { /* a portal "trap" must be matched by a */ /* portal in the destination dungeon/dlevel */ register struct trap *ttmp = maketrap(x, y, MAGIC_PORTAL); if (!ttmp) { impossible("portal on top of portal??"); return; } #ifdef DEBUG pline("mkportal: at (%d,%d), to %s, level %d", x, y, dungeons[todnum].dname, todlevel); #endif ttmp->dst.dnum = todnum; ttmp->dst.dlevel = todlevel; return; } /* * Special waterlevel stuff in endgame (TH). * * Some of these functions would probably logically belong to some * other source files, but they are all so nicely encapsulated here. */ /* to ease the work of debuggers at this stage */ #define register #define CONS_OBJ 0 #define CONS_MON 1 #define CONS_HERO 2 #define CONS_TRAP 3 static struct bubble *bbubbles, *ebubbles; static struct trap *wportal; static int xmin, ymin, xmax, ymax; /* level boundaries */ /* bubble movement boundaries */ #define bxmin (xmin + 1) #define bymin (ymin + 1) #define bxmax (xmax - 1) #define bymax (ymax - 1) STATIC_DCL void NDECL(set_wportal); STATIC_DCL void FDECL(mk_bubble, (int,int,int)); STATIC_DCL void FDECL(mv_bubble, (struct bubble *,int,int,BOOLEAN_P)); void movebubbles() { static boolean up; register struct bubble *b; register int x, y, i, j; struct trap *btrap; static const struct rm water_pos = { cmap_to_glyph(S_water), WATER, 0, 0, 0, 0, 0, 0, 0 }; /* set up the portal the first time bubbles are moved */ if (!wportal) set_wportal(); vision_recalc(2); /* keep attached ball&chain separate from bubble objects */ if (Punished) unplacebc(); /* * Pick up everything inside of a bubble then fill all bubble * locations. */ for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) { if (b->cons) panic("movebubbles: cons != null"); for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++) for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++) if (b->bm[j + 2] & (1 << i)) { if (!isok(x,y)) { impossible("movebubbles: bad pos (%d,%d)", x,y); continue; } /* pick up objects, monsters, hero, and traps */ if (OBJ_AT(x,y)) { struct obj *olist = (struct obj *) 0, *otmp; struct container *cons = (struct container *) alloc(sizeof(struct container)); while ((otmp = level.objects[x][y]) != 0) { remove_object(otmp); otmp->ox = otmp->oy = 0; otmp->nexthere = olist; olist = otmp; } cons->x = x; cons->y = y; cons->what = CONS_OBJ; cons->list = (genericptr_t) olist; cons->next = b->cons; b->cons = cons; } if (MON_AT(x,y)) { struct monst *mon = m_at(x,y); struct container *cons = (struct container *) alloc(sizeof(struct container)); cons->x = x; cons->y = y; cons->what = CONS_MON; cons->list = (genericptr_t) mon; cons->next = b->cons; b->cons = cons; if(mon->wormno) remove_worm(mon); else remove_monster(x, y); newsym(x,y); /* clean up old position */ mon->mx = mon->my = 0; } if (!u.uswallow && x == u.ux && y == u.uy) { struct container *cons = (struct container *) alloc(sizeof(struct container)); cons->x = x; cons->y = y; cons->what = CONS_HERO; cons->list = (genericptr_t) 0; cons->next = b->cons; b->cons = cons; } if ((btrap = t_at(x,y)) != 0) { struct container *cons = (struct container *) alloc(sizeof(struct container)); cons->x = x; cons->y = y; cons->what = CONS_TRAP; cons->list = (genericptr_t) btrap; cons->next = b->cons; b->cons = cons; } levl[x][y] = water_pos; block_point(x,y); } } /* * Every second time traverse down. This is because otherwise * all the junk that changes owners when bubbles overlap * would eventually end up in the last bubble in the chain. */ up = !up; for (b = up ? bbubbles : ebubbles; b; b = up ? b->next : b->prev) { register int rx = rn2(3), ry = rn2(3); mv_bubble(b,b->dx + 1 - (!b->dx ? rx : (rx ? 1 : 0)), b->dy + 1 - (!b->dy ? ry : (ry ? 1 : 0)), FALSE); } /* put attached ball&chain back */ if (Punished) placebc(); vision_full_recalc = 1; } /* when moving in water, possibly (1 in 3) alter the intended destination */ void water_friction() { register int x, y, dx, dy; register boolean eff = FALSE; if (Swimming && rn2(4)) return; /* natural swimmers have advantage */ if (u.dx && !rn2(!u.dy ? 3 : 6)) { /* 1/3 chance or half that */ /* cancel delta x and choose an arbitrary delta y value */ x = u.ux; do { dy = rn2(3) - 1; /* -1, 0, 1 */ y = u.uy + dy; } while (dy && (!isok(x,y) || !is_pool(x,y))); u.dx = 0; u.dy = dy; eff = TRUE; } else if (u.dy && !rn2(!u.dx ? 3 : 5)) { /* 1/3 or 1/5*(5/6) */ /* cancel delta y and choose an arbitrary delta x value */ y = u.uy; do { dx = rn2(3) - 1; /* -1 .. 1 */ x = u.ux + dx; } while (dx && (!isok(x,y) || !is_pool(x,y))); u.dy = 0; u.dx = dx; eff = TRUE; } if (eff) pline("Water turbulence affects your movements."); } void save_waterlevel(fd, mode) int fd, mode; { register struct bubble *b; if (!Is_waterlevel(&u.uz)) return; if (perform_bwrite(mode)) { int n = 0; for (b = bbubbles; b; b = b->next) ++n; bwrite(fd, (genericptr_t)&n, sizeof (int)); bwrite(fd, (genericptr_t)&xmin, sizeof (int)); bwrite(fd, (genericptr_t)&ymin, sizeof (int)); bwrite(fd, (genericptr_t)&xmax, sizeof (int)); bwrite(fd, (genericptr_t)&ymax, sizeof (int)); for (b = bbubbles; b; b = b->next) bwrite(fd, (genericptr_t)b, sizeof (struct bubble)); } if (release_data(mode)) unsetup_waterlevel(); } void restore_waterlevel(fd) register int fd; { register struct bubble *b = (struct bubble *)0, *btmp; register int i; int n; if (!Is_waterlevel(&u.uz)) return; set_wportal(); mread(fd,(genericptr_t)&n,sizeof(int)); mread(fd,(genericptr_t)&xmin,sizeof(int)); mread(fd,(genericptr_t)&ymin,sizeof(int)); mread(fd,(genericptr_t)&xmax,sizeof(int)); mread(fd,(genericptr_t)&ymax,sizeof(int)); for (i = 0; i < n; i++) { btmp = b; b = (struct bubble *)alloc(sizeof(struct bubble)); mread(fd,(genericptr_t)b,sizeof(struct bubble)); if (bbubbles) { btmp->next = b; b->prev = btmp; } else { bbubbles = b; b->prev = (struct bubble *)0; } mv_bubble(b,0,0,TRUE); } ebubbles = b; b->next = (struct bubble *)0; was_waterlevel = TRUE; } const char *waterbody_name(x, y) xchar x,y; { register struct rm *lev; schar ltyp; if (!isok(x,y)) return "drink"; /* should never happen */ lev = &levl[x][y]; ltyp = lev->typ; if (is_lava(x,y)) return "lava"; else if (ltyp == ICE || (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_ICE)) return "ice"; else if (((ltyp != POOL) && (ltyp != WATER) && !Is_medusa_level(&u.uz) && !Is_waterlevel(&u.uz) && !Is_juiblex_level(&u.uz)) || (ltyp == DRAWBRIDGE_UP && (levl[x][y].drawbridgemask & DB_UNDER) == DB_MOAT)) return "moat"; else if ((ltyp != POOL) && (ltyp != WATER) && Is_juiblex_level(&u.uz)) return "swamp"; else if (ltyp == POOL) return "pool of water"; else return "water"; } STATIC_OVL void set_wportal() { /* there better be only one magic portal on water level... */ for (wportal = ftrap; wportal; wportal = wportal->ntrap) if (wportal->ttyp == MAGIC_PORTAL) return; impossible("set_wportal(): no portal!"); } STATIC_OVL void setup_waterlevel() { register int x, y; register int xskip, yskip; register int water_glyph = cmap_to_glyph(S_water); /* ouch, hardcoded... */ xmin = 3; ymin = 1; xmax = 78; ymax = 20; /* set hero's memory to water */ for (x = xmin; x <= xmax; x++) for (y = ymin; y <= ymax; y++) levl[x][y].glyph = water_glyph; /* make bubbles */ xskip = 10 + rn2(10); yskip = 4 + rn2(4); for (x = bxmin; x <= bxmax; x += xskip) for (y = bymin; y <= bymax; y += yskip) mk_bubble(x,y,rn2(7)); } STATIC_OVL void unsetup_waterlevel() { register struct bubble *b, *bb; /* free bubbles */ for (b = bbubbles; b; b = bb) { bb = b->next; free((genericptr_t)b); } bbubbles = ebubbles = (struct bubble *)0; } STATIC_OVL void mk_bubble(x,y,n) register int x, y, n; { /* * These bit masks make visually pleasing bubbles on a normal aspect * 25x80 terminal, which naturally results in them being mathematically * anything but symmetric. For this reason they cannot be computed * in situ, either. The first two elements tell the dimensions of * the bubble's bounding box. */ static uchar bm2[] = {2,1,0x3}, bm3[] = {3,2,0x7,0x7}, bm4[] = {4,3,0x6,0xf,0x6}, bm5[] = {5,3,0xe,0x1f,0xe}, bm6[] = {6,4,0x1e,0x3f,0x3f,0x1e}, bm7[] = {7,4,0x3e,0x7f,0x7f,0x3e}, bm8[] = {8,4,0x7e,0xff,0xff,0x7e}, *bmask[] = {bm2,bm3,bm4,bm5,bm6,bm7,bm8}; register struct bubble *b; if (x >= bxmax || y >= bymax) return; if (n >= SIZE(bmask)) { impossible("n too large (mk_bubble)"); n = SIZE(bmask) - 1; } b = (struct bubble *)alloc(sizeof(struct bubble)); if ((x + (int) bmask[n][0] - 1) > bxmax) x = bxmax - bmask[n][0] + 1; if ((y + (int) bmask[n][1] - 1) > bymax) y = bymax - bmask[n][1] + 1; b->x = x; b->y = y; b->dx = 1 - rn2(3); b->dy = 1 - rn2(3); b->bm = bmask[n]; b->cons = 0; if (!bbubbles) bbubbles = b; if (ebubbles) { ebubbles->next = b; b->prev = ebubbles; } else b->prev = (struct bubble *)0; b->next = (struct bubble *)0; ebubbles = b; mv_bubble(b,0,0,TRUE); } /* * The player, the portal and all other objects and monsters * float along with their associated bubbles. Bubbles may overlap * freely, and the contents may get associated with other bubbles in * the process. Bubbles are "sticky", meaning that if the player is * in the immediate neighborhood of one, he/she may get sucked inside. * This property also makes leaving a bubble slightly difficult. */ STATIC_OVL void mv_bubble(b,dx,dy,ini) register struct bubble *b; register int dx, dy; register boolean ini; { register int x, y, i, j, colli = 0; struct container *cons, *ctemp; /* move bubble */ if (dx < -1 || dx > 1 || dy < -1 || dy > 1) { /* pline("mv_bubble: dx = %d, dy = %d", dx, dy); */ dx = sgn(dx); dy = sgn(dy); } /* * collision with level borders? * 1 = horizontal border, 2 = vertical, 3 = corner */ if (b->x <= bxmin) colli |= 2; if (b->y <= bymin) colli |= 1; if ((int) (b->x + b->bm[0] - 1) >= bxmax) colli |= 2; if ((int) (b->y + b->bm[1] - 1) >= bymax) colli |= 1; if (b->x < bxmin) { pline("bubble xmin: x = %d, xmin = %d", b->x, bxmin); b->x = bxmin; } if (b->y < bymin) { pline("bubble ymin: y = %d, ymin = %d", b->y, bymin); b->y = bymin; } if ((int) (b->x + b->bm[0] - 1) > bxmax) { pline("bubble xmax: x = %d, xmax = %d", b->x + b->bm[0] - 1, bxmax); b->x = bxmax - b->bm[0] + 1; } if ((int) (b->y + b->bm[1] - 1) > bymax) { pline("bubble ymax: y = %d, ymax = %d", b->y + b->bm[1] - 1, bymax); b->y = bymax - b->bm[1] + 1; } /* bounce if we're trying to move off the border */ if (b->x == bxmin && dx < 0) dx = -dx; if (b->x + b->bm[0] - 1 == bxmax && dx > 0) dx = -dx; if (b->y == bymin && dy < 0) dy = -dy; if (b->y + b->bm[1] - 1 == bymax && dy > 0) dy = -dy; b->x += dx; b->y += dy; /* void positions inside bubble */ for (i = 0, x = b->x; i < (int) b->bm[0]; i++, x++) for (j = 0, y = b->y; j < (int) b->bm[1]; j++, y++) if (b->bm[j + 2] & (1 << i)) { levl[x][y].typ = AIR; levl[x][y].lit = 1; unblock_point(x,y); } /* replace contents of bubble */ for (cons = b->cons; cons; cons = ctemp) { ctemp = cons->next; cons->x += dx; cons->y += dy; switch(cons->what) { case CONS_OBJ: { struct obj *olist, *otmp; for (olist=(struct obj *)cons->list; olist; olist=otmp) { otmp = olist->nexthere; place_object(olist, cons->x, cons->y); } break; } case CONS_MON: { struct monst *mon = (struct monst *) cons->list; (void) mnearto(mon, cons->x, cons->y, TRUE); break; } case CONS_HERO: { int ux0 = u.ux, uy0 = u.uy; /* change u.ux0 and u.uy0? */ u.ux = cons->x; u.uy = cons->y; newsym(ux0, uy0); /* clean up old position */ if (MON_AT(cons->x, cons->y)) { mnexto(m_at(cons->x,cons->y)); } break; } case CONS_TRAP: { struct trap *btrap = (struct trap *) cons->list; btrap->tx = cons->x; btrap->ty = cons->y; break; } default: impossible("mv_bubble: unknown bubble contents"); break; } free((genericptr_t)cons); } b->cons = 0; /* boing? */ switch (colli) { case 1: b->dy = -b->dy; break; case 3: b->dy = -b->dy; /* fall through */ case 2: b->dx = -b->dx; break; default: /* sometimes alter direction for fun anyway (higher probability for stationary bubbles) */ if (!ini && ((b->dx || b->dy) ? !rn2(20) : !rn2(5))) { b->dx = 1 - rn2(3); b->dy = 1 - rn2(3); } } } /*mkmaze.c*/ nethack-3.4.3/src/mkobj.c0100644000000000000000000012275207764735041013720 0ustar rootroot/* SCCS Id: @(#)mkobj.c 3.4 2002/10/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "prop.h" STATIC_DCL void FDECL(mkbox_cnts,(struct obj *)); STATIC_DCL void FDECL(obj_timer_checks,(struct obj *, XCHAR_P, XCHAR_P, int)); #ifdef OVL1 STATIC_DCL void FDECL(container_weight, (struct obj *)); STATIC_DCL struct obj *FDECL(save_mtraits, (struct obj *, struct monst *)); #ifdef WIZARD STATIC_DCL const char *FDECL(where_name, (int)); STATIC_DCL void FDECL(check_contained, (struct obj *,const char *)); #endif #endif /* OVL1 */ extern struct obj *thrownobj; /* defined in dothrow.c */ /*#define DEBUG_EFFECTS*/ /* show some messages for debugging */ struct icp { int iprob; /* probability of an item type */ char iclass; /* item class */ }; #ifdef OVL1 const struct icp mkobjprobs[] = { {10, WEAPON_CLASS}, {10, ARMOR_CLASS}, {20, FOOD_CLASS}, { 8, TOOL_CLASS}, { 8, GEM_CLASS}, {16, POTION_CLASS}, {16, SCROLL_CLASS}, { 4, SPBOOK_CLASS}, { 4, WAND_CLASS}, { 3, RING_CLASS}, { 1, AMULET_CLASS} }; const struct icp boxiprobs[] = { {18, GEM_CLASS}, {15, FOOD_CLASS}, {18, POTION_CLASS}, {18, SCROLL_CLASS}, {12, SPBOOK_CLASS}, { 7, COIN_CLASS}, { 6, WAND_CLASS}, { 5, RING_CLASS}, { 1, AMULET_CLASS} }; #ifdef REINCARNATION const struct icp rogueprobs[] = { {12, WEAPON_CLASS}, {12, ARMOR_CLASS}, {22, FOOD_CLASS}, {22, POTION_CLASS}, {22, SCROLL_CLASS}, { 5, WAND_CLASS}, { 5, RING_CLASS} }; #endif const struct icp hellprobs[] = { {20, WEAPON_CLASS}, {20, ARMOR_CLASS}, {16, FOOD_CLASS}, {12, TOOL_CLASS}, {10, GEM_CLASS}, { 1, POTION_CLASS}, { 1, SCROLL_CLASS}, { 8, WAND_CLASS}, { 8, RING_CLASS}, { 4, AMULET_CLASS} }; struct obj * mkobj_at(let, x, y, artif) char let; int x, y; boolean artif; { struct obj *otmp; otmp = mkobj(let, artif); place_object(otmp, x, y); return(otmp); } struct obj * mksobj_at(otyp, x, y, init, artif) int otyp, x, y; boolean init, artif; { struct obj *otmp; otmp = mksobj(otyp, init, artif); place_object(otmp, x, y); return(otmp); } struct obj * mkobj(oclass, artif) char oclass; boolean artif; { int tprob, i, prob = rnd(1000); if(oclass == RANDOM_CLASS) { const struct icp *iprobs = #ifdef REINCARNATION (Is_rogue_level(&u.uz)) ? (const struct icp *)rogueprobs : #endif Inhell ? (const struct icp *)hellprobs : (const struct icp *)mkobjprobs; for(tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++); oclass = iprobs->iclass; } i = bases[(int)oclass]; while((prob -= objects[i].oc_prob) > 0) i++; if(objects[i].oc_class != oclass || !OBJ_NAME(objects[i])) panic("probtype error, oclass=%d i=%d", (int) oclass, i); return(mksobj(i, TRUE, artif)); } STATIC_OVL void mkbox_cnts(box) struct obj *box; { register int n; register struct obj *otmp; box->cobj = (struct obj *) 0; switch (box->otyp) { case ICE_BOX: n = 20; break; case CHEST: n = 5; break; case LARGE_BOX: n = 3; break; case SACK: case OILSKIN_SACK: /* initial inventory: sack starts out empty */ if (moves <= 1 && !in_mklev) { n = 0; break; } /*else FALLTHRU*/ case BAG_OF_HOLDING: n = 1; break; default: n = 0; break; } for (n = rn2(n+1); n > 0; n--) { if (box->otyp == ICE_BOX) { if (!(otmp = mksobj(CORPSE, TRUE, TRUE))) continue; /* Note: setting age to 0 is correct. Age has a different * from usual meaning for objects stored in ice boxes. -KAA */ otmp->age = 0L; if (otmp->timed) { (void) stop_timer(ROT_CORPSE, (genericptr_t)otmp); (void) stop_timer(REVIVE_MON, (genericptr_t)otmp); } } else { register int tprob; const struct icp *iprobs = boxiprobs; for (tprob = rnd(100); (tprob -= iprobs->iprob) > 0; iprobs++) ; if (!(otmp = mkobj(iprobs->iclass, TRUE))) continue; /* handle a couple of special cases */ if (otmp->oclass == COIN_CLASS) { /* 2.5 x level's usual amount; weight adjusted below */ otmp->quan = (long)(rnd(level_difficulty()+2) * rnd(75)); otmp->owt = weight(otmp); } else while (otmp->otyp == ROCK) { otmp->otyp = rnd_class(DILITHIUM_CRYSTAL, LOADSTONE); if (otmp->quan > 2L) otmp->quan = 1L; otmp->owt = weight(otmp); } if (box->otyp == BAG_OF_HOLDING) { if (Is_mbag(otmp)) { otmp->otyp = SACK; otmp->spe = 0; otmp->owt = weight(otmp); } else while (otmp->otyp == WAN_CANCELLATION) otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING); } } (void) add_to_container(box, otmp); } } int rndmonnum() /* select a random, common monster type */ { register struct permonst *ptr; register int i; /* Plan A: get a level-appropriate common monster */ ptr = rndmonst(); if (ptr) return(monsndx(ptr)); /* Plan B: get any common monster */ do { i = rn1(SPECIAL_PM - LOW_PM, LOW_PM); ptr = &mons[i]; } while((ptr->geno & G_NOGEN) || (!Inhell && (ptr->geno & G_HELL))); return(i); } /* * Split obj so that it gets size gets reduced by num. The quantity num is * put in the object structure delivered by this call. The returned object * has its wornmask cleared and is positioned just following the original * in the nobj chain (and nexthere chain when on the floor). */ struct obj * splitobj(obj, num) struct obj *obj; long num; { struct obj *otmp; if (obj->cobj || num <= 0L || obj->quan <= num) panic("splitobj"); /* can't split containers */ otmp = newobj(obj->oxlth + obj->onamelth); *otmp = *obj; /* copies whole structure */ otmp->o_id = flags.ident++; if (!otmp->o_id) otmp->o_id = flags.ident++; /* ident overflowed */ otmp->timed = 0; /* not timed, yet */ otmp->lamplit = 0; /* ditto */ otmp->owornmask = 0L; /* new object isn't worn */ obj->quan -= num; obj->owt = weight(obj); otmp->quan = num; otmp->owt = weight(otmp); /* -= obj->owt ? */ obj->nobj = otmp; /* Only set nexthere when on the floor, nexthere is also used */ /* as a back pointer to the container object when contained. */ if (obj->where == OBJ_FLOOR) obj->nexthere = otmp; if (obj->oxlth) (void)memcpy((genericptr_t)otmp->oextra, (genericptr_t)obj->oextra, obj->oxlth); if (obj->onamelth) (void)strncpy(ONAME(otmp), ONAME(obj), (int)obj->onamelth); if (obj->unpaid) splitbill(obj,otmp); if (obj->timed) obj_split_timers(obj, otmp); if (obj_sheds_light(obj)) obj_split_light_source(obj, otmp); return otmp; } /* * Insert otmp right after obj in whatever chain(s) it is on. Then extract * obj from the chain(s). This function does a literal swap. It is up to * the caller to provide a valid context for the swap. When done, obj will * still exist, but not on any chain. * * Note: Don't use use obj_extract_self() -- we are doing an in-place swap, * not actually moving something. */ void replace_object(obj, otmp) struct obj *obj; struct obj *otmp; { otmp->where = obj->where; switch (obj->where) { case OBJ_FREE: /* do nothing */ break; case OBJ_INVENT: otmp->nobj = obj->nobj; obj->nobj = otmp; extract_nobj(obj, &invent); break; case OBJ_CONTAINED: otmp->nobj = obj->nobj; otmp->ocontainer = obj->ocontainer; obj->nobj = otmp; extract_nobj(obj, &obj->ocontainer->cobj); break; case OBJ_MINVENT: otmp->nobj = obj->nobj; otmp->ocarry = obj->ocarry; obj->nobj = otmp; extract_nobj(obj, &obj->ocarry->minvent); break; case OBJ_FLOOR: otmp->nobj = obj->nobj; otmp->nexthere = obj->nexthere; otmp->ox = obj->ox; otmp->oy = obj->oy; obj->nobj = otmp; obj->nexthere = otmp; extract_nobj(obj, &fobj); extract_nexthere(obj, &level.objects[obj->ox][obj->oy]); break; default: panic("replace_object: obj position"); break; } } /* * Create a dummy duplicate to put on shop bill. The duplicate exists * only in the billobjs chain. This function is used when a shop object * is being altered, and a copy of the original is needed for billing * purposes. For example, when eating, where an interruption will yield * an object which is different from what it started out as; the "I x" * command needs to display the original object. * * The caller is responsible for checking otmp->unpaid and * costly_spot(u.ux, u.uy). This function will make otmp no charge. * * Note that check_unpaid_usage() should be used instead for partial * usage of an object. */ void bill_dummy_object(otmp) register struct obj *otmp; { register struct obj *dummy; if (otmp->unpaid) subfrombill(otmp, shop_keeper(*u.ushops)); dummy = newobj(otmp->oxlth + otmp->onamelth); *dummy = *otmp; dummy->where = OBJ_FREE; dummy->o_id = flags.ident++; if (!dummy->o_id) dummy->o_id = flags.ident++; /* ident overflowed */ dummy->timed = 0; if (otmp->oxlth) (void)memcpy((genericptr_t)dummy->oextra, (genericptr_t)otmp->oextra, otmp->oxlth); if (otmp->onamelth) (void)strncpy(ONAME(dummy), ONAME(otmp), (int)otmp->onamelth); if (Is_candle(dummy)) dummy->lamplit = 0; addtobill(dummy, FALSE, TRUE, TRUE); otmp->no_charge = 1; otmp->unpaid = 0; return; } #endif /* OVL1 */ #ifdef OVLB static const char dknowns[] = { WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS, SPBOOK_CLASS, WEAPON_CLASS, TOOL_CLASS, 0 }; struct obj * mksobj(otyp, init, artif) int otyp; boolean init; boolean artif; { int mndx, tryct; struct obj *otmp; char let = objects[otyp].oc_class; otmp = newobj(0); *otmp = zeroobj; otmp->age = monstermoves; otmp->o_id = flags.ident++; if (!otmp->o_id) otmp->o_id = flags.ident++; /* ident overflowed */ otmp->quan = 1L; otmp->oclass = let; otmp->otyp = otyp; otmp->where = OBJ_FREE; otmp->dknown = index(dknowns, let) ? 0 : 1; if ((otmp->otyp >= ELVEN_SHIELD && otmp->otyp <= ORCISH_SHIELD) || otmp->otyp == SHIELD_OF_REFLECTION) otmp->dknown = 0; if (!objects[otmp->otyp].oc_uses_known) otmp->known = 1; #ifdef INVISIBLE_OBJECTS otmp->oinvis = !rn2(1250); #endif if (init) switch (let) { case WEAPON_CLASS: otmp->quan = is_multigen(otmp) ? (long) rn1(6,6) : 1L; if(!rn2(11)) { otmp->spe = rne(3); otmp->blessed = rn2(2); } else if(!rn2(10)) { curse(otmp); otmp->spe = -rne(3); } else blessorcurse(otmp, 10); if (is_poisonable(otmp) && !rn2(100)) otmp->opoisoned = 1; if (artif && !rn2(20)) otmp = mk_artifact(otmp, (aligntyp)A_NONE); break; case FOOD_CLASS: otmp->oeaten = 0; switch(otmp->otyp) { case CORPSE: /* possibly overridden by mkcorpstat() */ tryct = 50; do otmp->corpsenm = undead_to_corpse(rndmonnum()); while ((mvitals[otmp->corpsenm].mvflags & G_NOCORPSE) && (--tryct > 0)); if (tryct == 0) { /* perhaps rndmonnum() only wants to make G_NOCORPSE monsters on this level; let's create an adventurer's corpse instead, then */ otmp->corpsenm = PM_HUMAN; } /* timer set below */ break; case EGG: otmp->corpsenm = NON_PM; /* generic egg */ if (!rn2(3)) for (tryct = 200; tryct > 0; --tryct) { mndx = can_be_hatched(rndmonnum()); if (mndx != NON_PM && !dead_species(mndx, TRUE)) { otmp->corpsenm = mndx; /* typed egg */ attach_egg_hatch_timeout(otmp); break; } } break; case TIN: otmp->corpsenm = NON_PM; /* empty (so far) */ if (!rn2(6)) otmp->spe = 1; /* spinach */ else for (tryct = 200; tryct > 0; --tryct) { mndx = undead_to_corpse(rndmonnum()); if (mons[mndx].cnutrit && !(mvitals[mndx].mvflags & G_NOCORPSE)) { otmp->corpsenm = mndx; break; } } blessorcurse(otmp, 10); break; case SLIME_MOLD: otmp->spe = current_fruit; break; case KELP_FROND: otmp->quan = (long) rnd(2); break; } if (otmp->otyp == CORPSE || otmp->otyp == MEAT_RING || otmp->otyp == KELP_FROND) break; /* fall into next case */ case GEM_CLASS: if (otmp->otyp == LOADSTONE) curse(otmp); else if (otmp->otyp == ROCK) otmp->quan = (long) rn1(6,6); else if (otmp->otyp != LUCKSTONE && !rn2(6)) otmp->quan = 2L; else otmp->quan = 1L; break; case TOOL_CLASS: switch(otmp->otyp) { case TALLOW_CANDLE: case WAX_CANDLE: otmp->spe = 1; otmp->age = 20L * /* 400 or 200 */ (long)objects[otmp->otyp].oc_cost; otmp->lamplit = 0; otmp->quan = 1L + (long)(rn2(2) ? rn2(7) : 0); blessorcurse(otmp, 5); break; case BRASS_LANTERN: case OIL_LAMP: otmp->spe = 1; otmp->age = (long) rn1(500,1000); otmp->lamplit = 0; blessorcurse(otmp, 5); break; case MAGIC_LAMP: otmp->spe = 1; otmp->lamplit = 0; blessorcurse(otmp, 2); break; case CHEST: case LARGE_BOX: otmp->olocked = !!(rn2(5)); otmp->otrapped = !(rn2(10)); case ICE_BOX: case SACK: case OILSKIN_SACK: case BAG_OF_HOLDING: mkbox_cnts(otmp); break; #ifdef TOURIST case EXPENSIVE_CAMERA: #endif case TINNING_KIT: case MAGIC_MARKER: otmp->spe = rn1(70,30); break; case CAN_OF_GREASE: otmp->spe = rnd(25); blessorcurse(otmp, 10); break; case CRYSTAL_BALL: otmp->spe = rnd(5); blessorcurse(otmp, 2); break; case HORN_OF_PLENTY: case BAG_OF_TRICKS: otmp->spe = rnd(20); break; case FIGURINE: { int tryct2 = 0; do otmp->corpsenm = rndmonnum(); while(is_human(&mons[otmp->corpsenm]) && tryct2++ < 30); blessorcurse(otmp, 4); break; } case BELL_OF_OPENING: otmp->spe = 3; break; case MAGIC_FLUTE: case MAGIC_HARP: case FROST_HORN: case FIRE_HORN: case DRUM_OF_EARTHQUAKE: otmp->spe = rn1(5,4); break; } break; case AMULET_CLASS: if (otmp->otyp == AMULET_OF_YENDOR) flags.made_amulet = TRUE; if(rn2(10) && (otmp->otyp == AMULET_OF_STRANGULATION || otmp->otyp == AMULET_OF_CHANGE || otmp->otyp == AMULET_OF_RESTFUL_SLEEP)) { curse(otmp); } else blessorcurse(otmp, 10); case VENOM_CLASS: case CHAIN_CLASS: case BALL_CLASS: break; case POTION_CLASS: if (otmp->otyp == POT_OIL) otmp->age = MAX_OIL_IN_FLASK; /* amount of oil */ /* fall through */ case SCROLL_CLASS: #ifdef MAIL if (otmp->otyp != SCR_MAIL) #endif blessorcurse(otmp, 4); break; case SPBOOK_CLASS: blessorcurse(otmp, 17); break; case ARMOR_CLASS: if(rn2(10) && (otmp->otyp == FUMBLE_BOOTS || otmp->otyp == LEVITATION_BOOTS || otmp->otyp == HELM_OF_OPPOSITE_ALIGNMENT || otmp->otyp == GAUNTLETS_OF_FUMBLING || !rn2(11))) { curse(otmp); otmp->spe = -rne(3); } else if(!rn2(10)) { otmp->blessed = rn2(2); otmp->spe = rne(3); } else blessorcurse(otmp, 10); if (artif && !rn2(40)) otmp = mk_artifact(otmp, (aligntyp)A_NONE); /* simulate lacquered armor for samurai */ if (Role_if(PM_SAMURAI) && otmp->otyp == SPLINT_MAIL && (moves <= 1 || In_quest(&u.uz))) { #ifdef UNIXPC /* optimizer bitfield bug */ otmp->oerodeproof = 1; otmp->rknown = 1; #else otmp->oerodeproof = otmp->rknown = 1; #endif } break; case WAND_CLASS: if(otmp->otyp == WAN_WISHING) otmp->spe = rnd(3); else otmp->spe = rn1(5, (objects[otmp->otyp].oc_dir == NODIR) ? 11 : 4); blessorcurse(otmp, 17); otmp->recharged = 0; /* used to control recharging */ break; case RING_CLASS: if(objects[otmp->otyp].oc_charged) { blessorcurse(otmp, 3); if(rn2(10)) { if(rn2(10) && bcsign(otmp)) otmp->spe = bcsign(otmp) * rne(3); else otmp->spe = rn2(2) ? rne(3) : -rne(3); } /* make useless +0 rings much less common */ if (otmp->spe == 0) otmp->spe = rn2(4) - rn2(3); /* negative rings are usually cursed */ if (otmp->spe < 0 && rn2(5)) curse(otmp); } else if(rn2(10) && (otmp->otyp == RIN_TELEPORTATION || otmp->otyp == RIN_POLYMORPH || otmp->otyp == RIN_AGGRAVATE_MONSTER || otmp->otyp == RIN_HUNGER || !rn2(9))) { curse(otmp); } break; case ROCK_CLASS: switch (otmp->otyp) { case STATUE: /* possibly overridden by mkcorpstat() */ otmp->corpsenm = rndmonnum(); if (!verysmall(&mons[otmp->corpsenm]) && rn2(level_difficulty()/2 + 10) > 10) (void) add_to_container(otmp, mkobj(SPBOOK_CLASS,FALSE)); } break; case COIN_CLASS: break; /* do nothing */ default: impossible("impossible mkobj %d, sym '%c'.", otmp->otyp, objects[otmp->otyp].oc_class); return (struct obj *)0; } /* Some things must get done (timers) even if init = 0 */ switch (otmp->otyp) { case CORPSE: start_corpse_timeout(otmp); break; } /* unique objects may have an associated artifact entry */ if (objects[otyp].oc_unique && !otmp->oartifact) otmp = mk_artifact(otmp, (aligntyp)A_NONE); otmp->owt = weight(otmp); return(otmp); } /* * Start a corpse decay or revive timer. * This takes the age of the corpse into consideration as of 3.4.0. */ void start_corpse_timeout(body) struct obj *body; { long when; /* rot away when this old */ long corpse_age; /* age of corpse */ int rot_adjust; short action; #define TAINT_AGE (50L) /* age when corpses go bad */ #define TROLL_REVIVE_CHANCE 37 /* 1/37 chance for 50 turns ~ 75% chance */ #define ROT_AGE (250L) /* age when corpses rot away */ /* lizards and lichen don't rot or revive */ if (body->corpsenm == PM_LIZARD || body->corpsenm == PM_LICHEN) return; action = ROT_CORPSE; /* default action: rot away */ rot_adjust = in_mklev ? 25 : 10; /* give some variation */ corpse_age = monstermoves - body->age; if (corpse_age > ROT_AGE) when = rot_adjust; else when = ROT_AGE - corpse_age; when += (long)(rnz(rot_adjust) - rot_adjust); if (is_rider(&mons[body->corpsenm])) { /* * Riders always revive. They have a 1/3 chance per turn * of reviving after 12 turns. Always revive by 500. */ action = REVIVE_MON; for (when = 12L; when < 500L; when++) if (!rn2(3)) break; } else if (mons[body->corpsenm].mlet == S_TROLL && !body->norevive) { long age; for (age = 2; age <= TAINT_AGE; age++) if (!rn2(TROLL_REVIVE_CHANCE)) { /* troll revives */ action = REVIVE_MON; when = age; break; } } if (body->norevive) body->norevive = 0; (void) start_timer(when, TIMER_OBJECT, action, (genericptr_t)body); } void bless(otmp) register struct obj *otmp; { #ifdef GOLDOBJ if (otmp->oclass == COIN_CLASS) return; #endif otmp->cursed = 0; otmp->blessed = 1; if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); else if (otmp->otyp == FIGURINE && otmp->timed) (void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp); return; } void unbless(otmp) register struct obj *otmp; { otmp->blessed = 0; if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); } void curse(otmp) register struct obj *otmp; { #ifdef GOLDOBJ if (otmp->oclass == COIN_CLASS) return; #endif otmp->blessed = 0; otmp->cursed = 1; /* welded two-handed weapon interferes with some armor removal */ if (otmp == uwep && bimanual(uwep)) reset_remarm(); /* rules at top of wield.c state that twoweapon cannot be done with cursed alternate weapon */ if (otmp == uswapwep && u.twoweap) drop_uswapwep(); /* some cursed items need immediate updating */ if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); else if (otmp->otyp == FIGURINE) { if (otmp->corpsenm != NON_PM && !dead_species(otmp->corpsenm,TRUE) && (carried(otmp) || mcarried(otmp))) attach_fig_transform_timeout(otmp); } return; } void uncurse(otmp) register struct obj *otmp; { otmp->cursed = 0; if (carried(otmp) && confers_luck(otmp)) set_moreluck(); else if (otmp->otyp == BAG_OF_HOLDING) otmp->owt = weight(otmp); else if (otmp->otyp == FIGURINE && otmp->timed) (void) stop_timer(FIG_TRANSFORM, (genericptr_t) otmp); return; } #endif /* OVLB */ #ifdef OVL1 void blessorcurse(otmp, chance) register struct obj *otmp; register int chance; { if(otmp->blessed || otmp->cursed) return; if(!rn2(chance)) { if(!rn2(2)) { curse(otmp); } else { bless(otmp); } } return; } #endif /* OVL1 */ #ifdef OVLB int bcsign(otmp) register struct obj *otmp; { return(!!otmp->blessed - !!otmp->cursed); } #endif /* OVLB */ #ifdef OVL0 /* * Calculate the weight of the given object. This will recursively follow * and calculate the weight of any containers. * * Note: It is possible to end up with an incorrect weight if some part * of the code messes with a contained object and doesn't update the * container's weight. */ int weight(obj) register struct obj *obj; { int wt = objects[obj->otyp].oc_weight; if (obj->otyp == LARGE_BOX && obj->spe == 1) /* Schroedinger's Cat */ wt += mons[PM_HOUSECAT].cwt; if (Is_container(obj) || obj->otyp == STATUE) { struct obj *contents; register int cwt = 0; if (obj->otyp == STATUE && obj->corpsenm >= LOW_PM) wt = (int)obj->quan * ((int)mons[obj->corpsenm].cwt * 3 / 2); for(contents=obj->cobj; contents; contents=contents->nobj) cwt += weight(contents); /* * The weight of bags of holding is calculated as the weight * of the bag plus the weight of the bag's contents modified * as follows: * * Bag status Weight of contents * ---------- ------------------ * cursed 2x * blessed x/4 + 1 * otherwise x/2 + 1 * * The macro DELTA_CWT in pickup.c also implements these * weight equations. * * Note: The above checks are performed in the given order. * this means that if an object is both blessed and * cursed (not supposed to happen), it will be treated * as cursed. */ if (obj->otyp == BAG_OF_HOLDING) cwt = obj->cursed ? (cwt * 2) : (1 + (cwt / (obj->blessed ? 4 : 2))); return wt + cwt; } if (obj->otyp == CORPSE && obj->corpsenm >= LOW_PM) { long long_wt = obj->quan * (long) mons[obj->corpsenm].cwt; wt = (long_wt > LARGEST_INT) ? LARGEST_INT : (int)long_wt; if (obj->oeaten) wt = eaten_stat(wt, obj); return wt; } else if (obj->oclass == FOOD_CLASS && obj->oeaten) { return eaten_stat((int)obj->quan * wt, obj); } else if (obj->oclass == COIN_CLASS) return (int)((obj->quan + 50L) / 100L); else if (obj->otyp == HEAVY_IRON_BALL && obj->owt != 0) return((int)(obj->owt)); /* kludge for "very" heavy iron ball */ return(wt ? wt*(int)obj->quan : ((int)obj->quan + 1)>>1); } static int treefruits[] = {APPLE,ORANGE,PEAR,BANANA,EUCALYPTUS_LEAF}; struct obj * rnd_treefruit_at(x,y) int x, y; { return mksobj_at(treefruits[rn2(SIZE(treefruits))], x, y, TRUE, FALSE); } #endif /* OVL0 */ #ifdef OVLB struct obj * mkgold(amount, x, y) long amount; int x, y; { register struct obj *gold = g_at(x,y); if (amount <= 0L) amount = (long)(1 + rnd(level_difficulty()+2) * rnd(30)); if (gold) { gold->quan += amount; } else { gold = mksobj_at(GOLD_PIECE, x, y, TRUE, FALSE); gold->quan = amount; } gold->owt = weight(gold); return (gold); } #endif /* OVLB */ #ifdef OVL1 /* return TRUE if the corpse has special timing */ #define special_corpse(num) (((num) == PM_LIZARD) \ || ((num) == PM_LICHEN) \ || (is_rider(&mons[num])) \ || (mons[num].mlet == S_TROLL)) /* * OEXTRA note: Passing mtmp causes mtraits to be saved * even if ptr passed as well, but ptr is always used for * the corpse type (corpsenm). That allows the corpse type * to be different from the original monster, * i.e. vampire -> human corpse * yet still allow restoration of the original monster upon * resurrection. */ struct obj * mkcorpstat(objtype, mtmp, ptr, x, y, init) int objtype; /* CORPSE or STATUE */ struct monst *mtmp; struct permonst *ptr; int x, y; boolean init; { register struct obj *otmp; if (objtype != CORPSE && objtype != STATUE) impossible("making corpstat type %d", objtype); if (x == 0 && y == 0) { /* special case - random placement */ otmp = mksobj(objtype, init, FALSE); if (otmp) rloco(otmp); } else otmp = mksobj_at(objtype, x, y, init, FALSE); if (otmp) { if (mtmp) { struct obj *otmp2; if (!ptr) ptr = mtmp->data; /* save_mtraits frees original data pointed to by otmp */ otmp2 = save_mtraits(otmp, mtmp); if (otmp2) otmp = otmp2; } /* use the corpse or statue produced by mksobj() as-is unless `ptr' is non-null */ if (ptr) { int old_corpsenm = otmp->corpsenm; otmp->corpsenm = monsndx(ptr); otmp->owt = weight(otmp); if (otmp->otyp == CORPSE && (special_corpse(old_corpsenm) || special_corpse(otmp->corpsenm))) { obj_stop_timers(otmp); start_corpse_timeout(otmp); } } } return(otmp); } /* * Attach a monster id to an object, to provide * a lasting association between the two. */ struct obj * obj_attach_mid(obj, mid) struct obj *obj; unsigned mid; { struct obj *otmp; int lth, namelth; if (!mid || !obj) return (struct obj *)0; lth = sizeof(mid); namelth = obj->onamelth ? strlen(ONAME(obj)) + 1 : 0; if (namelth) otmp = realloc_obj(obj, lth, (genericptr_t) &mid, namelth, ONAME(obj)); else { otmp = obj; otmp->oxlth = sizeof(mid); (void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&mid, sizeof(mid)); } if (otmp && otmp->oxlth) otmp->oattached = OATTACHED_M_ID; /* mark it */ return otmp; } static struct obj * save_mtraits(obj, mtmp) struct obj *obj; struct monst *mtmp; { struct obj *otmp; int lth, namelth; lth = sizeof(struct monst) + mtmp->mxlth + mtmp->mnamelth; namelth = obj->onamelth ? strlen(ONAME(obj)) + 1 : 0; otmp = realloc_obj(obj, lth, (genericptr_t) mtmp, namelth, ONAME(obj)); if (otmp && otmp->oxlth) { struct monst *mtmp2 = (struct monst *)otmp->oextra; if (mtmp->data) mtmp2->mnum = monsndx(mtmp->data); /* invalidate pointers */ /* m_id is needed to know if this is a revived quest leader */ /* but m_id must be cleared when loading bones */ mtmp2->nmon = (struct monst *)0; mtmp2->data = (struct permonst *)0; mtmp2->minvent = (struct obj *)0; otmp->oattached = OATTACHED_MONST; /* mark it */ } return otmp; } /* returns a pointer to a new monst structure based on * the one contained within the obj. */ struct monst * get_mtraits(obj, copyof) struct obj *obj; boolean copyof; { struct monst *mtmp = (struct monst *)0; struct monst *mnew = (struct monst *)0; if (obj->oxlth && obj->oattached == OATTACHED_MONST) mtmp = (struct monst *)obj->oextra; if (mtmp) { if (copyof) { int lth = mtmp->mxlth + mtmp->mnamelth; mnew = newmonst(lth); lth += sizeof(struct monst); (void) memcpy((genericptr_t)mnew, (genericptr_t)mtmp, lth); } else { /* Never insert this returned pointer into mon chains! */ mnew = mtmp; } } return mnew; } #endif /* OVL1 */ #ifdef OVLB /* make an object named after someone listed in the scoreboard file */ struct obj * mk_tt_object(objtype, x, y) int objtype; /* CORPSE or STATUE */ register int x, y; { register struct obj *otmp, *otmp2; boolean initialize_it; /* player statues never contain books */ initialize_it = (objtype != STATUE); if ((otmp = mksobj_at(objtype, x, y, initialize_it, FALSE)) != 0) { /* tt_oname will return null if the scoreboard is empty */ if ((otmp2 = tt_oname(otmp)) != 0) otmp = otmp2; } return(otmp); } /* make a new corpse or statue, uninitialized if a statue (i.e. no books) */ struct obj * mk_named_object(objtype, ptr, x, y, nm) int objtype; /* CORPSE or STATUE */ struct permonst *ptr; int x, y; const char *nm; { struct obj *otmp; otmp = mkcorpstat(objtype, (struct monst *)0, ptr, x, y, (boolean)(objtype != STATUE)); if (nm) otmp = oname(otmp, nm); return(otmp); } boolean is_flammable(otmp) register struct obj *otmp; { int otyp = otmp->otyp; int omat = objects[otyp].oc_material; if (objects[otyp].oc_oprop == FIRE_RES || otyp == WAN_FIRE) return FALSE; return((boolean)((omat <= WOOD && omat != LIQUID) || omat == PLASTIC)); } boolean is_rottable(otmp) register struct obj *otmp; { int otyp = otmp->otyp; return((boolean)(objects[otyp].oc_material <= WOOD && objects[otyp].oc_material != LIQUID)); } #endif /* OVLB */ #ifdef OVL1 /* * These routines maintain the single-linked lists headed in level.objects[][] * and threaded through the nexthere fields in the object-instance structure. */ /* put the object at the given location */ void place_object(otmp, x, y) register struct obj *otmp; int x, y; { register struct obj *otmp2 = level.objects[x][y]; if (otmp->where != OBJ_FREE) panic("place_object: obj not free"); obj_no_longer_held(otmp); if (otmp->otyp == BOULDER) block_point(x,y); /* vision */ /* obj goes under boulders */ if (otmp2 && (otmp2->otyp == BOULDER)) { otmp->nexthere = otmp2->nexthere; otmp2->nexthere = otmp; } else { otmp->nexthere = otmp2; level.objects[x][y] = otmp; } /* set the new object's location */ otmp->ox = x; otmp->oy = y; otmp->where = OBJ_FLOOR; /* add to floor chain */ otmp->nobj = fobj; fobj = otmp; if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } #define ON_ICE(a) ((a)->recharged) #define ROT_ICE_ADJUSTMENT 2 /* rotting on ice takes 2 times as long */ /* If ice was affecting any objects correct that now * Also used for starting ice effects too. [zap.c] */ void obj_ice_effects(x, y, do_buried) int x, y; boolean do_buried; { struct obj *otmp; for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) { if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } if (do_buried) { for (otmp = level.buriedobjlist; otmp; otmp = otmp->nobj) { if (otmp->ox == x && otmp->oy == y) { if (otmp->timed) obj_timer_checks(otmp, x, y, 0); } } } } /* * Returns an obj->age for a corpse object on ice, that would be the * actual obj->age if the corpse had just been lifted from the ice. * This is useful when just using obj->age in a check or calculation because * rot timers pertaining to the object don't have to be stopped and * restarted etc. */ long peek_at_iced_corpse_age(otmp) struct obj *otmp; { long age, retval = otmp->age; if (otmp->otyp == CORPSE && ON_ICE(otmp)) { /* Adjust the age; must be same as obj_timer_checks() for off ice*/ age = monstermoves - otmp->age; retval = otmp->age + (age / ROT_ICE_ADJUSTMENT); #ifdef DEBUG_EFFECTS pline_The("%s age has ice modifications:otmp->age = %ld, returning %ld.", s_suffix(doname(otmp)),otmp->age, retval); pline("Effective age of corpse: %ld.", monstermoves - retval); #endif } return retval; } STATIC_OVL void obj_timer_checks(otmp, x, y, force) struct obj *otmp; xchar x, y; int force; /* 0 = no force so do checks, <0 = force off, >0 force on */ { long tleft = 0L; short action = ROT_CORPSE; boolean restart_timer = FALSE; boolean on_floor = (otmp->where == OBJ_FLOOR); boolean buried = (otmp->where == OBJ_BURIED); /* Check for corpses just placed on or in ice */ if (otmp->otyp == CORPSE && (on_floor || buried) && is_ice(x,y)) { tleft = stop_timer(action, (genericptr_t)otmp); if (tleft == 0L) { action = REVIVE_MON; tleft = stop_timer(action, (genericptr_t)otmp); } if (tleft != 0L) { long age; tleft = tleft - monstermoves; /* mark the corpse as being on ice */ ON_ICE(otmp) = 1; #ifdef DEBUG_EFFECTS pline("%s is now on ice at %d,%d.", The(xname(otmp)),x,y); #endif /* Adjust the time remaining */ tleft *= ROT_ICE_ADJUSTMENT; restart_timer = TRUE; /* Adjust the age; must be same as in obj_ice_age() */ age = monstermoves - otmp->age; otmp->age = monstermoves - (age * ROT_ICE_ADJUSTMENT); } } /* Check for corpses coming off ice */ else if ((force < 0) || (otmp->otyp == CORPSE && ON_ICE(otmp) && ((on_floor && !is_ice(x,y)) || !on_floor))) { tleft = stop_timer(action, (genericptr_t)otmp); if (tleft == 0L) { action = REVIVE_MON; tleft = stop_timer(action, (genericptr_t)otmp); } if (tleft != 0L) { long age; tleft = tleft - monstermoves; ON_ICE(otmp) = 0; #ifdef DEBUG_EFFECTS pline("%s is no longer on ice at %d,%d.", The(xname(otmp)),x,y); #endif /* Adjust the remaining time */ tleft /= ROT_ICE_ADJUSTMENT; restart_timer = TRUE; /* Adjust the age */ age = monstermoves - otmp->age; otmp->age = otmp->age + (age / ROT_ICE_ADJUSTMENT); } } /* now re-start the timer with the appropriate modifications */ if (restart_timer) (void) start_timer(tleft, TIMER_OBJECT, action, (genericptr_t)otmp); } #undef ON_ICE #undef ROT_ICE_ADJUSTMENT void remove_object(otmp) register struct obj *otmp; { xchar x = otmp->ox; xchar y = otmp->oy; if (otmp->where != OBJ_FLOOR) panic("remove_object: obj not on floor"); if (otmp->otyp == BOULDER) unblock_point(x,y); /* vision */ extract_nexthere(otmp, &level.objects[x][y]); extract_nobj(otmp, &fobj); if (otmp->timed) obj_timer_checks(otmp,x,y,0); } /* throw away all of a monster's inventory */ void discard_minvent(mtmp) struct monst *mtmp; { struct obj *otmp; while ((otmp = mtmp->minvent) != 0) { obj_extract_self(otmp); obfree(otmp, (struct obj *)0); /* dealloc_obj() isn't sufficient */ } } /* * Free obj from whatever list it is on in preperation of deleting it or * moving it elsewhere. This will perform all high-level consequences * involved with removing the item. E.g. if the object is in the hero's * inventory and confers heat resistance, the hero will lose it. * * Object positions: * OBJ_FREE not on any list * OBJ_FLOOR fobj, level.locations[][] chains (use remove_object) * OBJ_CONTAINED cobj chain of container object * OBJ_INVENT hero's invent chain (use freeinv) * OBJ_MINVENT monster's invent chain * OBJ_MIGRATING migrating chain * OBJ_BURIED level.buriedobjs chain * OBJ_ONBILL on billobjs chain */ void obj_extract_self(obj) struct obj *obj; { switch (obj->where) { case OBJ_FREE: break; case OBJ_FLOOR: remove_object(obj); break; case OBJ_CONTAINED: extract_nobj(obj, &obj->ocontainer->cobj); container_weight(obj->ocontainer); break; case OBJ_INVENT: freeinv(obj); break; case OBJ_MINVENT: extract_nobj(obj, &obj->ocarry->minvent); break; case OBJ_MIGRATING: extract_nobj(obj, &migrating_objs); break; case OBJ_BURIED: extract_nobj(obj, &level.buriedobjlist); break; case OBJ_ONBILL: extract_nobj(obj, &billobjs); break; default: panic("obj_extract_self"); break; } } /* Extract the given object from the chain, following nobj chain. */ void extract_nobj(obj, head_ptr) struct obj *obj, **head_ptr; { struct obj *curr, *prev; curr = *head_ptr; for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nobj) { if (curr == obj) { if (prev) prev->nobj = curr->nobj; else *head_ptr = curr->nobj; break; } } if (!curr) panic("extract_nobj: object lost"); obj->where = OBJ_FREE; } /* * Extract the given object from the chain, following nexthere chain. * * This does not set obj->where, this function is expected to be called * in tandem with extract_nobj, which does set it. */ void extract_nexthere(obj, head_ptr) struct obj *obj, **head_ptr; { struct obj *curr, *prev; curr = *head_ptr; for (prev = (struct obj *) 0; curr; prev = curr, curr = curr->nexthere) { if (curr == obj) { if (prev) prev->nexthere = curr->nexthere; else *head_ptr = curr->nexthere; break; } } if (!curr) panic("extract_nexthere: object lost"); } /* * Add obj to mon's inventory. If obj is able to merge with something already * in the inventory, then the passed obj is deleted and 1 is returned. * Otherwise 0 is returned. */ int add_to_minv(mon, obj) struct monst *mon; struct obj *obj; { struct obj *otmp; if (obj->where != OBJ_FREE) panic("add_to_minv: obj not free"); /* merge if possible */ for (otmp = mon->minvent; otmp; otmp = otmp->nobj) if (merged(&otmp, &obj)) return 1; /* obj merged and then free'd */ /* else insert; don't bother forcing it to end of chain */ obj->where = OBJ_MINVENT; obj->ocarry = mon; obj->nobj = mon->minvent; mon->minvent = obj; return 0; /* obj on mon's inventory chain */ } /* * Add obj to container, make sure obj is "free". Returns (merged) obj. * The input obj may be deleted in the process. */ struct obj * add_to_container(container, obj) struct obj *container, *obj; { struct obj *otmp; if (obj->where != OBJ_FREE) panic("add_to_container: obj not free"); if (container->where != OBJ_INVENT && container->where != OBJ_MINVENT) obj_no_longer_held(obj); /* merge if possible */ for (otmp = container->cobj; otmp; otmp = otmp->nobj) if (merged(&otmp, &obj)) return (otmp); obj->where = OBJ_CONTAINED; obj->ocontainer = container; obj->nobj = container->cobj; container->cobj = obj; return (obj); } void add_to_migration(obj) struct obj *obj; { if (obj->where != OBJ_FREE) panic("add_to_migration: obj not free"); obj->where = OBJ_MIGRATING; obj->nobj = migrating_objs; migrating_objs = obj; } void add_to_buried(obj) struct obj *obj; { if (obj->where != OBJ_FREE) panic("add_to_buried: obj not free"); obj->where = OBJ_BURIED; obj->nobj = level.buriedobjlist; level.buriedobjlist = obj; } /* Recalculate the weight of this container and all of _its_ containers. */ STATIC_OVL void container_weight(container) struct obj *container; { container->owt = weight(container); if (container->where == OBJ_CONTAINED) container_weight(container->ocontainer); /* else if (container->where == OBJ_INVENT) recalculate load delay here ??? */ } /* * Deallocate the object. _All_ objects should be run through here for * them to be deallocated. */ void dealloc_obj(obj) struct obj *obj; { if (obj->where != OBJ_FREE) panic("dealloc_obj: obj not free"); /* free up any timers attached to the object */ if (obj->timed) obj_stop_timers(obj); /* * Free up any light sources attached to the object. * * We may want to just call del_light_source() without any * checks (requires a code change there). Otherwise this * list must track all objects that can have a light source * attached to it (and also requires lamplit to be set). */ if (obj_sheds_light(obj)) del_light_source(LS_OBJECT, (genericptr_t) obj); if (obj == thrownobj) thrownobj = (struct obj*)0; free((genericptr_t) obj); } #ifdef WIZARD /* Check all object lists for consistency. */ void obj_sanity_check() { int x, y; struct obj *obj; struct monst *mon; const char *mesg; char obj_address[20], mon_address[20]; /* room for formatted pointers */ mesg = "fobj sanity"; for (obj = fobj; obj; obj = obj->nobj) { if (obj->where != OBJ_FLOOR) { pline("%s obj %s %s@(%d,%d): %s\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), where_name(obj->where), obj->ox, obj->oy, doname(obj)); } check_contained(obj, mesg); } mesg = "location sanity"; for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) for (obj = level.objects[x][y]; obj; obj = obj->nexthere) if (obj->where != OBJ_FLOOR) { pline("%s obj %s %s@(%d,%d): %s\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), where_name(obj->where), obj->ox, obj->oy, doname(obj)); } mesg = "invent sanity"; for (obj = invent; obj; obj = obj->nobj) { if (obj->where != OBJ_INVENT) { pline("%s obj %s %s: %s\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), where_name(obj->where), doname(obj)); } check_contained(obj, mesg); } mesg = "migrating sanity"; for (obj = migrating_objs; obj; obj = obj->nobj) { if (obj->where != OBJ_MIGRATING) { pline("%s obj %s %s: %s\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), where_name(obj->where), doname(obj)); } check_contained(obj, mesg); } mesg = "buried sanity"; for (obj = level.buriedobjlist; obj; obj = obj->nobj) { if (obj->where != OBJ_BURIED) { pline("%s obj %s %s: %s\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), where_name(obj->where), doname(obj)); } check_contained(obj, mesg); } mesg = "bill sanity"; for (obj = billobjs; obj; obj = obj->nobj) { if (obj->where != OBJ_ONBILL) { pline("%s obj %s %s: %s\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), where_name(obj->where), doname(obj)); } /* shouldn't be a full container on the bill */ if (obj->cobj) { pline("%s obj %s contains %s! %s\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), something, doname(obj)); } } mesg = "minvent sanity"; for (mon = fmon; mon; mon = mon->nmon) for (obj = mon->minvent; obj; obj = obj->nobj) { if (obj->where != OBJ_MINVENT) { pline("%s obj %s %s: %s\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), where_name(obj->where), doname(obj)); } if (obj->ocarry != mon) { pline("%s obj %s (%s) not held by mon %s (%s)\n", mesg, fmt_ptr((genericptr_t)obj, obj_address), doname(obj), fmt_ptr((genericptr_t)mon, mon_address), mon_nam(mon)); } check_contained(obj, mesg); } } /* This must stay consistent with the defines in obj.h. */ static const char *obj_state_names[NOBJ_STATES] = { "free", "floor", "contained", "invent", "minvent", "migrating", "buried", "onbill" }; STATIC_OVL const char * where_name(where) int where; { return (where<0 || where>=NOBJ_STATES) ? "unknown" : obj_state_names[where]; } /* obj sanity check: check objs contained by container */ STATIC_OVL void check_contained(container, mesg) struct obj *container; const char *mesg; { struct obj *obj; char obj1_address[20], obj2_address[20]; for (obj = container->cobj; obj; obj = obj->nobj) { if (obj->where != OBJ_CONTAINED) pline("contained %s obj %s: %s\n", mesg, fmt_ptr((genericptr_t)obj, obj1_address), where_name(obj->where)); else if (obj->ocontainer != container) pline("%s obj %s not in container %s\n", mesg, fmt_ptr((genericptr_t)obj, obj1_address), fmt_ptr((genericptr_t)container, obj2_address)); } } #endif /* WIZARD */ #endif /* OVL1 */ /*mkobj.c*/ nethack-3.4.3/src/mkroom.c0100644000000000000000000004351507764735041014121 0ustar rootroot/* SCCS Id: @(#)mkroom.c 3.4 2001/09/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * Entry points: * mkroom() -- make and stock a room of a given type * nexttodoor() -- return TRUE if adjacent to a door * has_dnstairs() -- return TRUE if given room has a down staircase * has_upstairs() -- return TRUE if given room has an up staircase * courtmon() -- generate a court monster * save_rooms() -- save rooms into file fd * rest_rooms() -- restore rooms from file fd */ #include "hack.h" #ifdef OVLB STATIC_DCL boolean FDECL(isbig, (struct mkroom *)); STATIC_DCL struct mkroom * FDECL(pick_room,(BOOLEAN_P)); STATIC_DCL void NDECL(mkshop), FDECL(mkzoo,(int)), NDECL(mkswamp); STATIC_DCL void NDECL(mktemple); STATIC_DCL coord * FDECL(shrine_pos, (int)); STATIC_DCL struct permonst * NDECL(morguemon); STATIC_DCL struct permonst * NDECL(antholemon); STATIC_DCL struct permonst * NDECL(squadmon); STATIC_DCL void FDECL(save_room, (int,struct mkroom *)); STATIC_DCL void FDECL(rest_room, (int,struct mkroom *)); #endif /* OVLB */ #define sq(x) ((x)*(x)) extern const struct shclass shtypes[]; /* defined in shknam.c */ #ifdef OVLB STATIC_OVL boolean isbig(sroom) register struct mkroom *sroom; { register int area = (sroom->hx - sroom->lx + 1) * (sroom->hy - sroom->ly + 1); return((boolean)( area > 20 )); } void mkroom(roomtype) /* make and stock a room of a given type */ int roomtype; { if (roomtype >= SHOPBASE) mkshop(); /* someday, we should be able to specify shop type */ else switch(roomtype) { case COURT: mkzoo(COURT); break; case ZOO: mkzoo(ZOO); break; case BEEHIVE: mkzoo(BEEHIVE); break; case MORGUE: mkzoo(MORGUE); break; case BARRACKS: mkzoo(BARRACKS); break; case SWAMP: mkswamp(); break; case TEMPLE: mktemple(); break; case LEPREHALL: mkzoo(LEPREHALL); break; case COCKNEST: mkzoo(COCKNEST); break; case ANTHOLE: mkzoo(ANTHOLE); break; default: impossible("Tried to make a room of type %d.", roomtype); } } STATIC_OVL void mkshop() { register struct mkroom *sroom; int i = -1; #ifdef WIZARD char *ep = (char *)0; /* (init == lint suppression) */ /* first determine shoptype */ if(wizard){ #ifndef MAC ep = nh_getenv("SHOPTYPE"); if(ep){ if(*ep == 'z' || *ep == 'Z'){ mkzoo(ZOO); return; } if(*ep == 'm' || *ep == 'M'){ mkzoo(MORGUE); return; } if(*ep == 'b' || *ep == 'B'){ mkzoo(BEEHIVE); return; } if(*ep == 't' || *ep == 'T' || *ep == '\\'){ mkzoo(COURT); return; } if(*ep == 's' || *ep == 'S'){ mkzoo(BARRACKS); return; } if(*ep == 'a' || *ep == 'A'){ mkzoo(ANTHOLE); return; } if(*ep == 'c' || *ep == 'C'){ mkzoo(COCKNEST); return; } if(*ep == 'l' || *ep == 'L'){ mkzoo(LEPREHALL); return; } if(*ep == '_'){ mktemple(); return; } if(*ep == '}'){ mkswamp(); return; } for(i=0; shtypes[i].name; i++) if(*ep == def_oc_syms[(int)shtypes[i].symb]) goto gottype; if(*ep == 'g' || *ep == 'G') i = 0; else i = -1; } #endif } #ifndef MAC gottype: #endif #endif for(sroom = &rooms[0]; ; sroom++){ if(sroom->hx < 0) return; if(sroom - rooms >= nroom) { pline("rooms not closed by -1?"); return; } if(sroom->rtype != OROOM) continue; if(has_dnstairs(sroom) || has_upstairs(sroom)) continue; if( #ifdef WIZARD (wizard && ep && sroom->doorct != 0) || #endif sroom->doorct == 1) break; } if (!sroom->rlit) { int x, y; for(x = sroom->lx - 1; x <= sroom->hx + 1; x++) for(y = sroom->ly - 1; y <= sroom->hy + 1; y++) levl[x][y].lit = 1; sroom->rlit = 1; } if(i < 0) { /* shoptype not yet determined */ register int j; /* pick a shop type at random */ for (j = rnd(100), i = 0; (j -= shtypes[i].prob) > 0; i++) continue; /* big rooms cannot be wand or book shops, * - so make them general stores */ if(isbig(sroom) && (shtypes[i].symb == WAND_CLASS || shtypes[i].symb == SPBOOK_CLASS)) i = 0; } sroom->rtype = SHOPBASE + i; /* set room bits before stocking the shop */ #ifdef SPECIALIZATION topologize(sroom, FALSE); /* doesn't matter - this is a special room */ #else topologize(sroom); #endif /* stock the room with a shopkeeper and artifacts */ stock_room(i, sroom); } STATIC_OVL struct mkroom * pick_room(strict) register boolean strict; /* pick an unused room, preferably with only one door */ { register struct mkroom *sroom; register int i = nroom; for(sroom = &rooms[rn2(nroom)]; i--; sroom++) { if(sroom == &rooms[nroom]) sroom = &rooms[0]; if(sroom->hx < 0) return (struct mkroom *)0; if(sroom->rtype != OROOM) continue; if(!strict) { if(has_upstairs(sroom) || (has_dnstairs(sroom) && rn2(3))) continue; } else if(has_upstairs(sroom) || has_dnstairs(sroom)) continue; if(sroom->doorct == 1 || !rn2(5) #ifdef WIZARD || wizard #endif ) return sroom; } return (struct mkroom *)0; } STATIC_OVL void mkzoo(type) int type; { register struct mkroom *sroom; if ((sroom = pick_room(FALSE)) != 0) { sroom->rtype = type; fill_zoo(sroom); } } void fill_zoo(sroom) struct mkroom *sroom; { struct monst *mon; register int sx,sy,i; int sh, tx, ty, goldlim, type = sroom->rtype; int rmno = (sroom - rooms) + ROOMOFFSET; coord mm; #ifdef GCC_WARN tx = ty = goldlim = 0; #endif sh = sroom->fdoor; switch(type) { case COURT: if(level.flags.is_maze_lev) { for(tx = sroom->lx; tx <= sroom->hx; tx++) for(ty = sroom->ly; ty <= sroom->hy; ty++) if(IS_THRONE(levl[tx][ty].typ)) goto throne_placed; } i = 100; do { /* don't place throne on top of stairs */ (void) somexy(sroom, &mm); tx = mm.x; ty = mm.y; } while (occupied((xchar)tx, (xchar)ty) && --i > 0); throne_placed: /* TODO: try to ensure the enthroned monster is an M2_PRINCE */ break; case BEEHIVE: tx = sroom->lx + (sroom->hx - sroom->lx + 1)/2; ty = sroom->ly + (sroom->hy - sroom->ly + 1)/2; if(sroom->irregular) { /* center might not be valid, so put queen elsewhere */ if ((int) levl[tx][ty].roomno != rmno || levl[tx][ty].edge) { (void) somexy(sroom, &mm); tx = mm.x; ty = mm.y; } } break; case ZOO: case LEPREHALL: goldlim = 500 * level_difficulty(); break; } for(sx = sroom->lx; sx <= sroom->hx; sx++) for(sy = sroom->ly; sy <= sroom->hy; sy++) { if(sroom->irregular) { if ((int) levl[sx][sy].roomno != rmno || levl[sx][sy].edge || (sroom->doorct && distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1)) continue; } else if(!SPACE_POS(levl[sx][sy].typ) || (sroom->doorct && ((sx == sroom->lx && doors[sh].x == sx-1) || (sx == sroom->hx && doors[sh].x == sx+1) || (sy == sroom->ly && doors[sh].y == sy-1) || (sy == sroom->hy && doors[sh].y == sy+1)))) continue; /* don't place monster on explicitly placed throne */ if(type == COURT && IS_THRONE(levl[sx][sy].typ)) continue; mon = makemon( (type == COURT) ? courtmon() : (type == BARRACKS) ? squadmon() : (type == MORGUE) ? morguemon() : (type == BEEHIVE) ? (sx == tx && sy == ty ? &mons[PM_QUEEN_BEE] : &mons[PM_KILLER_BEE]) : (type == LEPREHALL) ? &mons[PM_LEPRECHAUN] : (type == COCKNEST) ? &mons[PM_COCKATRICE] : (type == ANTHOLE) ? antholemon() : (struct permonst *) 0, sx, sy, NO_MM_FLAGS); if(mon) { mon->msleeping = 1; if (type==COURT && mon->mpeaceful) { mon->mpeaceful = 0; set_malign(mon); } } switch(type) { case ZOO: case LEPREHALL: if(sroom->doorct) { int distval = dist2(sx,sy,doors[sh].x,doors[sh].y); i = sq(distval); } else i = goldlim; if(i >= goldlim) i = 5*level_difficulty(); goldlim -= i; (void) mkgold((long) rn1(i, 10), sx, sy); break; case MORGUE: if(!rn2(5)) (void) mk_tt_object(CORPSE, sx, sy); if(!rn2(10)) /* lots of treasure buried with dead */ (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy, TRUE, FALSE); if (!rn2(5)) make_grave(sx, sy, (char *)0); break; case BEEHIVE: if(!rn2(3)) (void) mksobj_at(LUMP_OF_ROYAL_JELLY, sx, sy, TRUE, FALSE); break; case BARRACKS: if(!rn2(20)) /* the payroll and some loot */ (void) mksobj_at((rn2(3)) ? LARGE_BOX : CHEST, sx, sy, TRUE, FALSE); break; case COCKNEST: if(!rn2(3)) { struct obj *sobj = mk_tt_object(STATUE, sx, sy); if (sobj) { for (i = rn2(5); i; i--) (void) add_to_container(sobj, mkobj(RANDOM_CLASS, FALSE)); sobj->owt = weight(sobj); } } break; case ANTHOLE: if(!rn2(3)) (void) mkobj_at(FOOD_CLASS, sx, sy, FALSE); break; } } switch (type) { case COURT: { struct obj *chest; levl[tx][ty].typ = THRONE; (void) somexy(sroom, &mm); (void) mkgold((long) rn1(50 * level_difficulty(),10), mm.x, mm.y); /* the royal coffers */ chest = mksobj_at(CHEST, mm.x, mm.y, TRUE, FALSE); chest->spe = 2; /* so it can be found later */ level.flags.has_court = 1; break; } case BARRACKS: level.flags.has_barracks = 1; break; case ZOO: level.flags.has_zoo = 1; break; case MORGUE: level.flags.has_morgue = 1; break; case SWAMP: level.flags.has_swamp = 1; break; case BEEHIVE: level.flags.has_beehive = 1; break; } } /* make a swarm of undead around mm */ void mkundead(mm, revive_corpses, mm_flags) coord *mm; boolean revive_corpses; int mm_flags; { int cnt = (level_difficulty() + 1)/10 + rnd(5); struct permonst *mdat; struct obj *otmp; coord cc; while (cnt--) { mdat = morguemon(); if (enexto(&cc, mm->x, mm->y, mdat) && (!revive_corpses || !(otmp = sobj_at(CORPSE, cc.x, cc.y)) || !revive(otmp))) (void) makemon(mdat, cc.x, cc.y, mm_flags); } level.flags.graveyard = TRUE; /* reduced chance for undead corpse */ } STATIC_OVL struct permonst * morguemon() { register int i = rn2(100), hd = rn2(level_difficulty()); if(hd > 10 && i < 10) return((Inhell || In_endgame(&u.uz)) ? mkclass(S_DEMON,0) : &mons[ndemon(A_NONE)]); if(hd > 8 && i > 85) return(mkclass(S_VAMPIRE,0)); return((i < 20) ? &mons[PM_GHOST] : (i < 40) ? &mons[PM_WRAITH] : mkclass(S_ZOMBIE,0)); } STATIC_OVL struct permonst * antholemon() { int mtyp; /* Same monsters within a level, different ones between levels */ switch ((level_difficulty() + ((long)u.ubirthday)) % 3) { default: mtyp = PM_GIANT_ANT; break; case 0: mtyp = PM_SOLDIER_ANT; break; case 1: mtyp = PM_FIRE_ANT; break; } return ((mvitals[mtyp].mvflags & G_GONE) ? (struct permonst *)0 : &mons[mtyp]); } STATIC_OVL void mkswamp() /* Michiel Huisjes & Fred de Wilde */ { register struct mkroom *sroom; register int sx,sy,i,eelct = 0; for(i=0; i<5; i++) { /* turn up to 5 rooms swampy */ sroom = &rooms[rn2(nroom)]; if(sroom->hx < 0 || sroom->rtype != OROOM || has_upstairs(sroom) || has_dnstairs(sroom)) continue; /* satisfied; make a swamp */ sroom->rtype = SWAMP; for(sx = sroom->lx; sx <= sroom->hx; sx++) for(sy = sroom->ly; sy <= sroom->hy; sy++) if(!OBJ_AT(sx, sy) && !MON_AT(sx, sy) && !t_at(sx,sy) && !nexttodoor(sx,sy)) { if((sx+sy)%2) { levl[sx][sy].typ = POOL; if(!eelct || !rn2(4)) { /* mkclass() won't do, as we might get kraken */ (void) makemon(rn2(5) ? &mons[PM_GIANT_EEL] : rn2(2) ? &mons[PM_PIRANHA] : &mons[PM_ELECTRIC_EEL], sx, sy, NO_MM_FLAGS); eelct++; } } else if(!rn2(4)) /* swamps tend to be moldy */ (void) makemon(mkclass(S_FUNGUS,0), sx, sy, NO_MM_FLAGS); } level.flags.has_swamp = 1; } } STATIC_OVL coord * shrine_pos(roomno) int roomno; { static coord buf; struct mkroom *troom = &rooms[roomno - ROOMOFFSET]; buf.x = troom->lx + ((troom->hx - troom->lx) / 2); buf.y = troom->ly + ((troom->hy - troom->ly) / 2); return(&buf); } STATIC_OVL void mktemple() { register struct mkroom *sroom; coord *shrine_spot; register struct rm *lev; if(!(sroom = pick_room(TRUE))) return; /* set up Priest and shrine */ sroom->rtype = TEMPLE; /* * In temples, shrines are blessed altars * located in the center of the room */ shrine_spot = shrine_pos((sroom - rooms) + ROOMOFFSET); lev = &levl[shrine_spot->x][shrine_spot->y]; lev->typ = ALTAR; lev->altarmask = induced_align(80); priestini(&u.uz, sroom, shrine_spot->x, shrine_spot->y, FALSE); lev->altarmask |= AM_SHRINE; level.flags.has_temple = 1; } boolean nexttodoor(sx,sy) register int sx, sy; { register int dx, dy; register struct rm *lev; for(dx = -1; dx <= 1; dx++) for(dy = -1; dy <= 1; dy++) { if(!isok(sx+dx, sy+dy)) continue; if(IS_DOOR((lev = &levl[sx+dx][sy+dy])->typ) || lev->typ == SDOOR) return(TRUE); } return(FALSE); } boolean has_dnstairs(sroom) register struct mkroom *sroom; { if (sroom == dnstairs_room) return TRUE; if (sstairs.sx && !sstairs.up) return((boolean)(sroom == sstairs_room)); return FALSE; } boolean has_upstairs(sroom) register struct mkroom *sroom; { if (sroom == upstairs_room) return TRUE; if (sstairs.sx && sstairs.up) return((boolean)(sroom == sstairs_room)); return FALSE; } #endif /* OVLB */ #ifdef OVL0 int somex(croom) register struct mkroom *croom; { return rn2(croom->hx-croom->lx+1) + croom->lx; } int somey(croom) register struct mkroom *croom; { return rn2(croom->hy-croom->ly+1) + croom->ly; } boolean inside_room(croom, x, y) struct mkroom *croom; xchar x, y; { return((boolean)(x >= croom->lx-1 && x <= croom->hx+1 && y >= croom->ly-1 && y <= croom->hy+1)); } boolean somexy(croom, c) struct mkroom *croom; coord *c; { int try_cnt = 0; int i; if (croom->irregular) { i = (croom - rooms) + ROOMOFFSET; while(try_cnt++ < 100) { c->x = somex(croom); c->y = somey(croom); if (!levl[c->x][c->y].edge && (int) levl[c->x][c->y].roomno == i) return TRUE; } /* try harder; exhaustively search until one is found */ for(c->x = croom->lx; c->x <= croom->hx; c->x++) for(c->y = croom->ly; c->y <= croom->hy; c->y++) if (!levl[c->x][c->y].edge && (int) levl[c->x][c->y].roomno == i) return TRUE; return FALSE; } if (!croom->nsubrooms) { c->x = somex(croom); c->y = somey(croom); return TRUE; } /* Check that coords doesn't fall into a subroom or into a wall */ while(try_cnt++ < 100) { c->x = somex(croom); c->y = somey(croom); if (IS_WALL(levl[c->x][c->y].typ)) continue; for(i=0 ; insubrooms;i++) if(inside_room(croom->sbrooms[i], c->x, c->y)) goto you_lose; break; you_lose: ; } if (try_cnt >= 100) return FALSE; return TRUE; } /* * Search for a special room given its type (zoo, court, etc...) * Special values : * - ANY_SHOP * - ANY_TYPE */ struct mkroom * search_special(type) schar type; { register struct mkroom *croom; for(croom = &rooms[0]; croom->hx >= 0; croom++) if((type == ANY_TYPE && croom->rtype != OROOM) || (type == ANY_SHOP && croom->rtype >= SHOPBASE) || croom->rtype == type) return croom; for(croom = &subrooms[0]; croom->hx >= 0; croom++) if((type == ANY_TYPE && croom->rtype != OROOM) || (type == ANY_SHOP && croom->rtype >= SHOPBASE) || croom->rtype == type) return croom; return (struct mkroom *) 0; } #endif /* OVL0 */ #ifdef OVLB struct permonst * courtmon() { int i = rn2(60) + rn2(3*level_difficulty()); if (i > 100) return(mkclass(S_DRAGON,0)); else if (i > 95) return(mkclass(S_GIANT,0)); else if (i > 85) return(mkclass(S_TROLL,0)); else if (i > 75) return(mkclass(S_CENTAUR,0)); else if (i > 60) return(mkclass(S_ORC,0)); else if (i > 45) return(&mons[PM_BUGBEAR]); else if (i > 30) return(&mons[PM_HOBGOBLIN]); else if (i > 15) return(mkclass(S_GNOME,0)); else return(mkclass(S_KOBOLD,0)); } #define NSTYPES (PM_CAPTAIN - PM_SOLDIER + 1) static struct { unsigned pm; unsigned prob; } squadprob[NSTYPES] = { {PM_SOLDIER, 80}, {PM_SERGEANT, 15}, {PM_LIEUTENANT, 4}, {PM_CAPTAIN, 1} }; STATIC_OVL struct permonst * squadmon() /* return soldier types. */ { int sel_prob, i, cpro, mndx; sel_prob = rnd(80+level_difficulty()); cpro = 0; for (i = 0; i < NSTYPES; i++) { cpro += squadprob[i].prob; if (cpro > sel_prob) { mndx = squadprob[i].pm; goto gotone; } } mndx = squadprob[rn2(NSTYPES)].pm; gotone: if (!(mvitals[mndx].mvflags & G_GONE)) return(&mons[mndx]); else return((struct permonst *) 0); } /* * save_room : A recursive function that saves a room and its subrooms * (if any). */ STATIC_OVL void save_room(fd, r) int fd; struct mkroom *r; { short i; /* * Well, I really should write only useful information instead * of writing the whole structure. That is I should not write * the subrooms pointers, but who cares ? */ bwrite(fd, (genericptr_t) r, sizeof(struct mkroom)); for(i=0; insubrooms; i++) save_room(fd, r->sbrooms[i]); } /* * save_rooms : Save all the rooms on disk! */ void save_rooms(fd) int fd; { short i; /* First, write the number of rooms */ bwrite(fd, (genericptr_t) &nroom, sizeof(nroom)); for(i=0; insubrooms; i++) { r->sbrooms[i] = &subrooms[nsubroom]; rest_room(fd, &subrooms[nsubroom]); subrooms[nsubroom++].resident = (struct monst *)0; } } /* * rest_rooms : That's for restoring rooms. Read the rooms structure from * the disk. */ void rest_rooms(fd) int fd; { short i; mread(fd, (genericptr_t) &nroom, sizeof(nroom)); nsubroom = 0; for(i = 0; i STATIC_DCL boolean FDECL(restrap,(struct monst *)); STATIC_DCL long FDECL(mm_aggression, (struct monst *,struct monst *)); #ifdef OVL2 STATIC_DCL int NDECL(pick_animal); STATIC_DCL int FDECL(select_newcham_form, (struct monst *)); STATIC_DCL void FDECL(kill_eggs, (struct obj *)); #endif #ifdef REINCARNATION #define LEVEL_SPECIFIC_NOCORPSE(mdat) \ (Is_rogue_level(&u.uz) || \ (level.flags.graveyard && is_undead(mdat) && rn2(3))) #else #define LEVEL_SPECIFIC_NOCORPSE(mdat) \ (level.flags.graveyard && is_undead(mdat) && rn2(3)) #endif #if 0 /* part of the original warning code which was replaced in 3.3.1 */ #ifdef OVL1 #define warnDelay 10 long lastwarntime; int lastwarnlev; const char *warnings[] = { "white", "pink", "red", "ruby", "purple", "black" }; STATIC_DCL void NDECL(warn_effects); #endif /* OVL1 */ #endif /* 0 */ #ifndef OVLB STATIC_VAR short cham_to_pm[]; #else STATIC_DCL struct obj *FDECL(make_corpse,(struct monst *)); STATIC_DCL void FDECL(m_detach, (struct monst *, struct permonst *)); STATIC_DCL void FDECL(lifesaved_monster, (struct monst *)); /* convert the monster index of an undead to its living counterpart */ int undead_to_corpse(mndx) int mndx; { switch (mndx) { case PM_KOBOLD_ZOMBIE: case PM_KOBOLD_MUMMY: mndx = PM_KOBOLD; break; case PM_DWARF_ZOMBIE: case PM_DWARF_MUMMY: mndx = PM_DWARF; break; case PM_GNOME_ZOMBIE: case PM_GNOME_MUMMY: mndx = PM_GNOME; break; case PM_ORC_ZOMBIE: case PM_ORC_MUMMY: mndx = PM_ORC; break; case PM_ELF_ZOMBIE: case PM_ELF_MUMMY: mndx = PM_ELF; break; case PM_VAMPIRE: case PM_VAMPIRE_LORD: #if 0 /* DEFERRED */ case PM_VAMPIRE_MAGE: #endif case PM_HUMAN_ZOMBIE: case PM_HUMAN_MUMMY: mndx = PM_HUMAN; break; case PM_GIANT_ZOMBIE: case PM_GIANT_MUMMY: mndx = PM_GIANT; break; case PM_ETTIN_ZOMBIE: case PM_ETTIN_MUMMY: mndx = PM_ETTIN; break; default: break; } return mndx; } /* Convert the monster index of some monsters (such as quest guardians) * to their generic species type. * * Return associated character class monster, rather than species * if mode is 1. */ int genus(mndx, mode) int mndx, mode; { switch (mndx) { /* Quest guardians */ case PM_STUDENT: mndx = mode ? PM_ARCHEOLOGIST : PM_HUMAN; break; case PM_CHIEFTAIN: mndx = mode ? PM_BARBARIAN : PM_HUMAN; break; case PM_NEANDERTHAL: mndx = mode ? PM_CAVEMAN : PM_HUMAN; break; case PM_ATTENDANT: mndx = mode ? PM_HEALER : PM_HUMAN; break; case PM_PAGE: mndx = mode ? PM_KNIGHT : PM_HUMAN; break; case PM_ABBOT: mndx = mode ? PM_MONK : PM_HUMAN; break; case PM_ACOLYTE: mndx = mode ? PM_PRIEST : PM_HUMAN; break; case PM_HUNTER: mndx = mode ? PM_RANGER : PM_HUMAN; break; case PM_THUG: mndx = mode ? PM_ROGUE : PM_HUMAN; break; case PM_ROSHI: mndx = mode ? PM_SAMURAI : PM_HUMAN; break; #ifdef TOURIST case PM_GUIDE: mndx = mode ? PM_TOURIST : PM_HUMAN; break; #endif case PM_APPRENTICE: mndx = mode ? PM_WIZARD : PM_HUMAN; break; case PM_WARRIOR: mndx = mode ? PM_VALKYRIE : PM_HUMAN; break; default: if (mndx >= LOW_PM && mndx < NUMMONS) { struct permonst *ptr = &mons[mndx]; if (is_human(ptr)) mndx = PM_HUMAN; else if (is_elf(ptr)) mndx = PM_ELF; else if (is_dwarf(ptr)) mndx = PM_DWARF; else if (is_gnome(ptr)) mndx = PM_GNOME; else if (is_orc(ptr)) mndx = PM_ORC; } break; } return mndx; } /* convert monster index to chameleon index */ int pm_to_cham(mndx) int mndx; { int mcham; switch (mndx) { case PM_CHAMELEON: mcham = CHAM_CHAMELEON; break; case PM_DOPPELGANGER: mcham = CHAM_DOPPELGANGER; break; case PM_SANDESTIN: mcham = CHAM_SANDESTIN; break; default: mcham = CHAM_ORDINARY; break; } return mcham; } /* convert chameleon index to monster index */ STATIC_VAR short cham_to_pm[] = { NON_PM, /* placeholder for CHAM_ORDINARY */ PM_CHAMELEON, PM_DOPPELGANGER, PM_SANDESTIN, }; /* for deciding whether corpse or statue will carry along full monster data */ #define KEEPTRAITS(mon) ((mon)->isshk || (mon)->mtame || \ ((mon)->data->geno & G_UNIQ) || \ is_reviver((mon)->data) || \ /* normally leader the will be unique, */ \ /* but he might have been polymorphed */ \ (mon)->m_id == quest_status.leader_m_id || \ /* special cancellation handling for these */ \ (dmgtype((mon)->data, AD_SEDU) || \ dmgtype((mon)->data, AD_SSEX))) /* Creates a monster corpse, a "special" corpse, or nothing if it doesn't * leave corpses. Monsters which leave "special" corpses should have * G_NOCORPSE set in order to prevent wishing for one, finding tins of one, * etc.... */ STATIC_OVL struct obj * make_corpse(mtmp) register struct monst *mtmp; { register struct permonst *mdat = mtmp->data; int num; struct obj *obj = (struct obj *)0; int x = mtmp->mx, y = mtmp->my; int mndx = monsndx(mdat); switch(mndx) { case PM_GRAY_DRAGON: case PM_SILVER_DRAGON: #if 0 /* DEFERRED */ case PM_SHIMMERING_DRAGON: #endif case PM_RED_DRAGON: case PM_ORANGE_DRAGON: case PM_WHITE_DRAGON: case PM_BLACK_DRAGON: case PM_BLUE_DRAGON: case PM_GREEN_DRAGON: case PM_YELLOW_DRAGON: /* Make dragon scales. This assumes that the order of the */ /* dragons is the same as the order of the scales. */ if (!rn2(mtmp->mrevived ? 20 : 3)) { num = GRAY_DRAGON_SCALES + monsndx(mdat) - PM_GRAY_DRAGON; obj = mksobj_at(num, x, y, FALSE, FALSE); obj->spe = 0; obj->cursed = obj->blessed = FALSE; } goto default_1; case PM_WHITE_UNICORN: case PM_GRAY_UNICORN: case PM_BLACK_UNICORN: if (mtmp->mrevived && rn2(20)) { if (canseemon(mtmp)) pline("%s recently regrown horn crumbles to dust.", s_suffix(Monnam(mtmp))); } else (void) mksobj_at(UNICORN_HORN, x, y, TRUE, FALSE); goto default_1; case PM_LONG_WORM: (void) mksobj_at(WORM_TOOTH, x, y, TRUE, FALSE); goto default_1; case PM_VAMPIRE: case PM_VAMPIRE_LORD: /* include mtmp in the mkcorpstat() call */ num = undead_to_corpse(mndx); obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, TRUE); obj->age -= 100; /* this is an *OLD* corpse */ break; case PM_KOBOLD_MUMMY: case PM_DWARF_MUMMY: case PM_GNOME_MUMMY: case PM_ORC_MUMMY: case PM_ELF_MUMMY: case PM_HUMAN_MUMMY: case PM_GIANT_MUMMY: case PM_ETTIN_MUMMY: case PM_KOBOLD_ZOMBIE: case PM_DWARF_ZOMBIE: case PM_GNOME_ZOMBIE: case PM_ORC_ZOMBIE: case PM_ELF_ZOMBIE: case PM_HUMAN_ZOMBIE: case PM_GIANT_ZOMBIE: case PM_ETTIN_ZOMBIE: num = undead_to_corpse(mndx); obj = mkcorpstat(CORPSE, mtmp, &mons[num], x, y, TRUE); obj->age -= 100; /* this is an *OLD* corpse */ break; case PM_IRON_GOLEM: num = d(2,6); while (num--) obj = mksobj_at(IRON_CHAIN, x, y, TRUE, FALSE); mtmp->mnamelth = 0; break; case PM_GLASS_GOLEM: num = d(2,4); /* very low chance of creating all glass gems */ while (num--) obj = mksobj_at((LAST_GEM + rnd(9)), x, y, TRUE, FALSE); mtmp->mnamelth = 0; break; case PM_CLAY_GOLEM: obj = mksobj_at(ROCK, x, y, FALSE, FALSE); obj->quan = (long)(rn2(20) + 50); obj->owt = weight(obj); mtmp->mnamelth = 0; break; case PM_STONE_GOLEM: obj = mkcorpstat(STATUE, (struct monst *)0, mdat, x, y, FALSE); break; case PM_WOOD_GOLEM: num = d(2,4); while(num--) { obj = mksobj_at(QUARTERSTAFF, x, y, TRUE, FALSE); } mtmp->mnamelth = 0; break; case PM_LEATHER_GOLEM: num = d(2,4); while(num--) obj = mksobj_at(LEATHER_ARMOR, x, y, TRUE, FALSE); mtmp->mnamelth = 0; break; case PM_GOLD_GOLEM: /* Good luck gives more coins */ obj = mkgold((long)(200 - rnl(101)), x, y); mtmp->mnamelth = 0; break; case PM_PAPER_GOLEM: num = rnd(4); while (num--) obj = mksobj_at(SCR_BLANK_PAPER, x, y, TRUE, FALSE); mtmp->mnamelth = 0; break; default_1: default: if (mvitals[mndx].mvflags & G_NOCORPSE) return (struct obj *)0; else /* preserve the unique traits of some creatures */ obj = mkcorpstat(CORPSE, KEEPTRAITS(mtmp) ? mtmp : 0, mdat, x, y, TRUE); break; } /* All special cases should precede the G_NOCORPSE check */ /* if polymorph or undead turning has killed this monster, prevent the same attack beam from hitting its corpse */ if (flags.bypasses) bypass_obj(obj); if (mtmp->mnamelth) obj = oname(obj, NAME(mtmp)); /* Avoid "It was hidden under a green mold corpse!" * during Blind combat. An unseen monster referred to as "it" * could be killed and leave a corpse. If a hider then hid * underneath it, you could be told the corpse type of a * monster that you never knew was there without this. * The code in hitmu() substitutes the word "something" * if the corpses obj->dknown is 0. */ if (Blind && !sensemon(mtmp)) obj->dknown = 0; #ifdef INVISIBLE_OBJECTS /* Invisible monster ==> invisible corpse */ obj->oinvis = mtmp->minvis; #endif stackobj(obj); newsym(x, y); return obj; } #endif /* OVLB */ #ifdef OVL1 #if 0 /* part of the original warning code which was replaced in 3.3.1 */ STATIC_OVL void warn_effects() { if (warnlevel == 100) { if(!Blind && uwep && (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) { Your("%s %s!", aobjnam(uwep, "glow"), hcolor(NH_LIGHT_BLUE)); lastwarnlev = warnlevel; lastwarntime = moves; } warnlevel = 0; return; } if (warnlevel >= SIZE(warnings)) warnlevel = SIZE(warnings)-1; if (!Blind && (warnlevel > lastwarnlev || moves > lastwarntime + warnDelay)) { const char *which, *what, *how; long rings = (EWarning & (LEFT_RING|RIGHT_RING)); if (rings) { what = Hallucination ? "mood ring" : "ring"; how = "glows"; /* singular verb */ if (rings == LEFT_RING) { which = "left "; } else if (rings == RIGHT_RING) { which = "right "; } else { /* both */ which = ""; what = (const char *) makeplural(what); how = "glow"; /* plural verb */ } Your("%s%s %s %s!", which, what, how, hcolor(warnings[warnlevel])); } else { if (Hallucination) Your("spider-sense is tingling..."); else You_feel("apprehensive as you sense a %s flash.", warnings[warnlevel]); } lastwarntime = moves; lastwarnlev = warnlevel; } } #endif /* 0 */ /* check mtmp and water/lava for compatibility, 0 (survived), 1 (died) */ int minliquid(mtmp) register struct monst *mtmp; { boolean inpool, inlava, infountain; inpool = is_pool(mtmp->mx,mtmp->my) && !is_flyer(mtmp->data) && !is_floater(mtmp->data); inlava = is_lava(mtmp->mx,mtmp->my) && !is_flyer(mtmp->data) && !is_floater(mtmp->data); infountain = IS_FOUNTAIN(levl[mtmp->mx][mtmp->my].typ); #ifdef STEED /* Flying and levitation keeps our steed out of the liquid */ /* (but not water-walking or swimming) */ if (mtmp == u.usteed && (Flying || Levitation)) return (0); #endif /* Gremlin multiplying won't go on forever since the hit points * keep going down, and when it gets to 1 hit point the clone * function will fail. */ if (mtmp->data == &mons[PM_GREMLIN] && (inpool || infountain) && rn2(3)) { if (split_mon(mtmp, (struct monst *)0)) dryup(mtmp->mx, mtmp->my, FALSE); if (inpool) water_damage(mtmp->minvent, FALSE, FALSE); return (0); } else if (mtmp->data == &mons[PM_IRON_GOLEM] && inpool && !rn2(5)) { int dam = d(2,6); if (cansee(mtmp->mx,mtmp->my)) pline("%s rusts.", Monnam(mtmp)); mtmp->mhp -= dam; if (mtmp->mhpmax > dam) mtmp->mhpmax -= dam; if (mtmp->mhp < 1) { mondead(mtmp); if (mtmp->mhp < 1) return (1); } water_damage(mtmp->minvent, FALSE, FALSE); return (0); } if (inlava) { /* * Lava effects much as water effects. Lava likers are able to * protect their stuff. Fire resistant monsters can only protect * themselves --ALI */ if (!is_clinger(mtmp->data) && !likes_lava(mtmp->data)) { if (!resists_fire(mtmp)) { if (cansee(mtmp->mx,mtmp->my)) pline("%s %s.", Monnam(mtmp), mtmp->data == &mons[PM_WATER_ELEMENTAL] ? "boils away" : "burns to a crisp"); mondead(mtmp); } else { if (--mtmp->mhp < 1) { if (cansee(mtmp->mx,mtmp->my)) pline("%s surrenders to the fire.", Monnam(mtmp)); mondead(mtmp); } else if (cansee(mtmp->mx,mtmp->my)) pline("%s burns slightly.", Monnam(mtmp)); } if (mtmp->mhp > 0) { (void) fire_damage(mtmp->minvent, FALSE, FALSE, mtmp->mx, mtmp->my); (void) rloc(mtmp, FALSE); return 0; } return (1); } } else if (inpool) { /* Most monsters drown in pools. flooreffects() will take care of * water damage to dead monsters' inventory, but survivors need to * be handled here. Swimmers are able to protect their stuff... */ if (!is_clinger(mtmp->data) && !is_swimmer(mtmp->data) && !amphibious(mtmp->data)) { if (cansee(mtmp->mx,mtmp->my)) { pline("%s drowns.", Monnam(mtmp)); } if (u.ustuck && u.uswallow && u.ustuck == mtmp) { /* This can happen after a purple worm plucks you off a flying steed while you are over water. */ pline("%s sinks as water rushes in and flushes you out.", Monnam(mtmp)); } mondead(mtmp); if (mtmp->mhp > 0) { (void) rloc(mtmp, FALSE); water_damage(mtmp->minvent, FALSE, FALSE); return 0; } return (1); } } else { /* but eels have a difficult time outside */ if (mtmp->data->mlet == S_EEL && !Is_waterlevel(&u.uz)) { if(mtmp->mhp > 1) mtmp->mhp--; monflee(mtmp, 2, FALSE, FALSE); } } return (0); } int mcalcmove(mon) struct monst *mon; { int mmove = mon->data->mmove; /* Note: MSLOW's `+ 1' prevents slowed speed 1 getting reduced to 0; * MFAST's `+ 2' prevents hasted speed 1 from becoming a no-op; * both adjustments have negligible effect on higher speeds. */ if (mon->mspeed == MSLOW) mmove = (2 * mmove + 1) / 3; else if (mon->mspeed == MFAST) mmove = (4 * mmove + 2) / 3; #ifdef STEED if (mon == u.usteed) { if (u.ugallop && flags.mv) { /* average movement is 1.50 times normal */ mmove = ((rn2(2) ? 4 : 5) * mmove) / 3; } } #endif return mmove; } /* actions that happen once per ``turn'', regardless of each individual monster's metabolism; some of these might need to be reclassified to occur more in proportion with movement rate */ void mcalcdistress() { struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; /* must check non-moving monsters once/turn in case * they managed to end up in liquid */ if (mtmp->data->mmove == 0) { if (vision_full_recalc) vision_recalc(0); if (minliquid(mtmp)) continue; } /* regenerate hit points */ mon_regen(mtmp, FALSE); /* possibly polymorph shapechangers and lycanthropes */ if (mtmp->cham && !rn2(6)) (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); were_change(mtmp); /* gradually time out temporary problems */ if (mtmp->mblinded && !--mtmp->mblinded) mtmp->mcansee = 1; if (mtmp->mfrozen && !--mtmp->mfrozen) mtmp->mcanmove = 1; if (mtmp->mfleetim && !--mtmp->mfleetim) mtmp->mflee = 0; /* FIXME: mtmp->mlstmv ought to be updated here */ } } int movemon() { register struct monst *mtmp, *nmtmp; register boolean somebody_can_move = FALSE; #if 0 /* part of the original warning code which was replaced in 3.3.1 */ warnlevel = 0; #endif /* Some of you may remember the former assertion here that because of deaths and other actions, a simple one-pass algorithm wasn't possible for movemon. Deaths are no longer removed to the separate list fdmon; they are simply left in the chain with hit points <= 0, to be cleaned up at the end of the pass. The only other actions which cause monsters to be removed from the chain are level migrations and losedogs(). I believe losedogs() is a cleanup routine not associated with monster movements, and monsters can only affect level migrations on themselves, not others (hence the fetching of nmon before moving the monster). Currently, monsters can jump into traps, read cursed scrolls of teleportation, and drink cursed potions of raise level to change levels. These are all reflexive at this point. Should one monster be able to level teleport another, this scheme would have problems. */ for(mtmp = fmon; mtmp; mtmp = nmtmp) { nmtmp = mtmp->nmon; /* Find a monster that we have not treated yet. */ if(DEADMONSTER(mtmp)) continue; if(mtmp->movement < NORMAL_SPEED) continue; mtmp->movement -= NORMAL_SPEED; if (mtmp->movement >= NORMAL_SPEED) somebody_can_move = TRUE; if (vision_full_recalc) vision_recalc(0); /* vision! */ if (minliquid(mtmp)) continue; if (is_hider(mtmp->data)) { /* unwatched mimics and piercers may hide again [MRS] */ if(restrap(mtmp)) continue; if(mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) continue; if(mtmp->mundetected) continue; } /* continue if the monster died fighting */ if (Conflict && !mtmp->iswiz && mtmp->mcansee) { /* Note: * Conflict does not take effect in the first round. * Therefore, A monster when stepping into the area will * get to swing at you. * * The call to fightm() must be _last_. The monster might * have died if it returns 1. */ if (couldsee(mtmp->mx,mtmp->my) && (distu(mtmp->mx,mtmp->my) <= BOLT_LIM*BOLT_LIM) && fightm(mtmp)) continue; /* mon might have died */ } if(dochugw(mtmp)) /* otherwise just move the monster */ continue; } #if 0 /* part of the original warning code which was replaced in 3.3.1 */ if(warnlevel > 0) warn_effects(); #endif if (any_light_source()) vision_full_recalc = 1; /* in case a mon moved with a light source */ dmonsfree(); /* remove all dead monsters */ /* a monster may have levteleported player -dlc */ if (u.utotype) { deferred_goto(); /* changed levels, so these monsters are dormant */ somebody_can_move = FALSE; } return somebody_can_move; } #endif /* OVL1 */ #ifdef OVLB #define mstoning(obj) (ofood(obj) && \ (touch_petrifies(&mons[(obj)->corpsenm]) || \ (obj)->corpsenm == PM_MEDUSA)) /* * Maybe eat a metallic object (not just gold). * Return value: 0 => nothing happened, 1 => monster ate something, * 2 => monster died (it must have grown into a genocided form, but * that can't happen at present because nothing which eats objects * has young and old forms). */ int meatmetal(mtmp) register struct monst *mtmp; { register struct obj *otmp; struct permonst *ptr; int poly, grow, heal, mstone; /* If a pet, eating is handled separately, in dog.c */ if (mtmp->mtame) return 0; /* Eats topmost metal object if it is there */ for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp->nexthere) { if (mtmp->data == &mons[PM_RUST_MONSTER] && !is_rustprone(otmp)) continue; if (is_metallic(otmp) && !obj_resists(otmp, 5, 95) && touch_artifact(otmp,mtmp)) { if (mtmp->data == &mons[PM_RUST_MONSTER] && otmp->oerodeproof) { if (canseemon(mtmp) && flags.verbose) { pline("%s eats %s!", Monnam(mtmp), distant_name(otmp,doname)); } /* The object's rustproofing is gone now */ otmp->oerodeproof = 0; mtmp->mstun = 1; if (canseemon(mtmp) && flags.verbose) { pline("%s spits %s out in disgust!", Monnam(mtmp), distant_name(otmp,doname)); } /* KMH -- Don't eat indigestible/choking objects */ } else if (otmp->otyp != AMULET_OF_STRANGULATION && otmp->otyp != RIN_SLOW_DIGESTION) { if (cansee(mtmp->mx,mtmp->my) && flags.verbose) pline("%s eats %s!", Monnam(mtmp), distant_name(otmp,doname)); else if (flags.soundok && flags.verbose) You_hear("a crunching sound."); mtmp->meating = otmp->owt/2 + 1; /* Heal up to the object's weight in hp */ if (mtmp->mhp < mtmp->mhpmax) { mtmp->mhp += objects[otmp->otyp].oc_weight; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; } if(otmp == uball) { unpunish(); delobj(otmp); } else if (otmp == uchain) { unpunish(); /* frees uchain */ } else { poly = polyfodder(otmp); grow = mlevelgain(otmp); heal = mhealup(otmp); mstone = mstoning(otmp); delobj(otmp); ptr = mtmp->data; if (poly) { if (newcham(mtmp, (struct permonst *)0, FALSE, FALSE)) ptr = mtmp->data; } else if (grow) { ptr = grow_up(mtmp, (struct monst *)0); } else if (mstone) { if (poly_when_stoned(ptr)) { mon_to_stone(mtmp); ptr = mtmp->data; } else if (!resists_ston(mtmp)) { if (canseemon(mtmp)) pline("%s turns to stone!", Monnam(mtmp)); monstone(mtmp); ptr = (struct permonst *)0; } } else if (heal) { mtmp->mhp = mtmp->mhpmax; } if (!ptr) return 2; /* it died */ } /* Left behind a pile? */ if (rnd(25) < 3) (void)mksobj_at(ROCK, mtmp->mx, mtmp->my, TRUE, FALSE); newsym(mtmp->mx, mtmp->my); return 1; } } } return 0; } int meatobj(mtmp) /* for gelatinous cubes */ register struct monst *mtmp; { register struct obj *otmp, *otmp2; struct permonst *ptr; int poly, grow, heal, count = 0, ecount = 0; char buf[BUFSZ]; buf[0] = '\0'; /* If a pet, eating is handled separately, in dog.c */ if (mtmp->mtame) return 0; /* Eats organic objects, including cloth and wood, if there */ /* Engulfs others, except huge rocks and metal attached to player */ for (otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (is_organic(otmp) && !obj_resists(otmp, 5, 95) && touch_artifact(otmp,mtmp)) { if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !resists_ston(mtmp)) continue; if (otmp->otyp == AMULET_OF_STRANGULATION || otmp->otyp == RIN_SLOW_DIGESTION) continue; ++count; if (cansee(mtmp->mx,mtmp->my) && flags.verbose) pline("%s eats %s!", Monnam(mtmp), distant_name(otmp, doname)); else if (flags.soundok && flags.verbose) You_hear("a slurping sound."); /* Heal up to the object's weight in hp */ if (mtmp->mhp < mtmp->mhpmax) { mtmp->mhp += objects[otmp->otyp].oc_weight; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; } if (Has_contents(otmp)) { register struct obj *otmp3; /* contents of eaten containers become engulfed; this is arbitrary, but otherwise g.cubes are too powerful */ while ((otmp3 = otmp->cobj) != 0) { obj_extract_self(otmp3); if (otmp->otyp == ICE_BOX && otmp3->otyp == CORPSE) { otmp3->age = monstermoves - otmp3->age; start_corpse_timeout(otmp3); } (void) mpickobj(mtmp, otmp3); } } poly = polyfodder(otmp); grow = mlevelgain(otmp); heal = mhealup(otmp); delobj(otmp); /* munch */ ptr = mtmp->data; if (poly) { if (newcham(mtmp, (struct permonst *)0, FALSE, FALSE)) ptr = mtmp->data; } else if (grow) { ptr = grow_up(mtmp, (struct monst *)0); } else if (heal) { mtmp->mhp = mtmp->mhpmax; } /* in case it polymorphed or died */ if (ptr != &mons[PM_GELATINOUS_CUBE]) return !ptr ? 2 : 1; } else if (otmp->oclass != ROCK_CLASS && otmp != uball && otmp != uchain) { ++ecount; if (ecount == 1) { Sprintf(buf, "%s engulfs %s.", Monnam(mtmp), distant_name(otmp,doname)); } else if (ecount == 2) Sprintf(buf, "%s engulfs several objects.", Monnam(mtmp)); obj_extract_self(otmp); (void) mpickobj(mtmp, otmp); /* slurp */ } /* Engulf & devour is instant, so don't set meating */ if (mtmp->minvis) newsym(mtmp->mx, mtmp->my); } if (ecount > 0) { if (cansee(mtmp->mx, mtmp->my) && flags.verbose && buf[0]) pline("%s", buf); else if (flags.soundok && flags.verbose) You_hear("%s slurping sound%s.", ecount == 1 ? "a" : "several", ecount == 1 ? "" : "s"); } return ((count > 0) || (ecount > 0)) ? 1 : 0; } void mpickgold(mtmp) register struct monst *mtmp; { register struct obj *gold; int mat_idx; if ((gold = g_at(mtmp->mx, mtmp->my)) != 0) { mat_idx = objects[gold->otyp].oc_material; #ifndef GOLDOBJ mtmp->mgold += gold->quan; delobj(gold); #else obj_extract_self(gold); add_to_minv(mtmp, gold); #endif if (cansee(mtmp->mx, mtmp->my) ) { if (flags.verbose && !mtmp->isgd) pline("%s picks up some %s.", Monnam(mtmp), mat_idx == GOLD ? "gold" : "money"); newsym(mtmp->mx, mtmp->my); } } } #endif /* OVLB */ #ifdef OVL2 boolean mpickstuff(mtmp, str) register struct monst *mtmp; register const char *str; { register struct obj *otmp, *otmp2; /* prevent shopkeepers from leaving the door of their shop */ if(mtmp->isshk && inhishop(mtmp)) return FALSE; for(otmp = level.objects[mtmp->mx][mtmp->my]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; /* Nymphs take everything. Most monsters don't pick up corpses. */ if (!str ? searches_for_item(mtmp,otmp) : !!(index(str, otmp->oclass))) { if (otmp->otyp == CORPSE && mtmp->data->mlet != S_NYMPH && /* let a handful of corpse types thru to can_carry() */ !touch_petrifies(&mons[otmp->corpsenm]) && otmp->corpsenm != PM_LIZARD && !acidic(&mons[otmp->corpsenm])) continue; if (!touch_artifact(otmp,mtmp)) continue; if (!can_carry(mtmp,otmp)) continue; if (is_pool(mtmp->mx,mtmp->my)) continue; #ifdef INVISIBLE_OBJECTS if (otmp->oinvis && !perceives(mtmp->data)) continue; #endif if (cansee(mtmp->mx,mtmp->my) && flags.verbose) pline("%s picks up %s.", Monnam(mtmp), (distu(mtmp->mx, mtmp->my) <= 5) ? doname(otmp) : distant_name(otmp, doname)); obj_extract_self(otmp); /* unblock point after extract, before pickup */ if (otmp->otyp == BOULDER) unblock_point(otmp->ox,otmp->oy); /* vision */ (void) mpickobj(mtmp, otmp); /* may merge and free otmp */ m_dowear(mtmp, FALSE); newsym(mtmp->mx, mtmp->my); return TRUE; /* pick only one object */ } } return FALSE; } #endif /* OVL2 */ #ifdef OVL0 int curr_mon_load(mtmp) register struct monst *mtmp; { register int curload = 0; register struct obj *obj; for(obj = mtmp->minvent; obj; obj = obj->nobj) { if(obj->otyp != BOULDER || !throws_rocks(mtmp->data)) curload += obj->owt; } return curload; } int max_mon_load(mtmp) register struct monst *mtmp; { register long maxload; /* Base monster carrying capacity is equal to human maximum * carrying capacity, or half human maximum if not strong. * (for a polymorphed player, the value used would be the * non-polymorphed carrying capacity instead of max/half max). * This is then modified by the ratio between the monster weights * and human weights. Corpseless monsters are given a capacity * proportional to their size instead of weight. */ if (!mtmp->data->cwt) maxload = (MAX_CARR_CAP * (long)mtmp->data->msize) / MZ_HUMAN; else if (!strongmonst(mtmp->data) || (strongmonst(mtmp->data) && (mtmp->data->cwt > WT_HUMAN))) maxload = (MAX_CARR_CAP * (long)mtmp->data->cwt) / WT_HUMAN; else maxload = MAX_CARR_CAP; /*strong monsters w/cwt <= WT_HUMAN*/ if (!strongmonst(mtmp->data)) maxload /= 2; if (maxload < 1) maxload = 1; return (int) maxload; } /* for restricting monsters' object-pickup */ boolean can_carry(mtmp,otmp) struct monst *mtmp; struct obj *otmp; { int otyp = otmp->otyp, newload = otmp->owt; struct permonst *mdat = mtmp->data; if (notake(mdat)) return FALSE; /* can't carry anything */ if (otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !(mtmp->misc_worn_check & W_ARMG) && !resists_ston(mtmp)) return FALSE; if (otyp == CORPSE && is_rider(&mons[otmp->corpsenm])) return FALSE; if (objects[otyp].oc_material == SILVER && hates_silver(mdat) && (otyp != BELL_OF_OPENING || !is_covetous(mdat))) return FALSE; #ifdef STEED /* Steeds don't pick up stuff (to avoid shop abuse) */ if (mtmp == u.usteed) return (FALSE); #endif if (mtmp->isshk) return(TRUE); /* no limit */ if (mtmp->mpeaceful && !mtmp->mtame) return(FALSE); /* otherwise players might find themselves obligated to violate * their alignment if the monster takes something they need */ /* special--boulder throwers carry unlimited amounts of boulders */ if (throws_rocks(mdat) && otyp == BOULDER) return(TRUE); /* nymphs deal in stolen merchandise, but not boulders or statues */ if (mdat->mlet == S_NYMPH) return (boolean)(otmp->oclass != ROCK_CLASS); if (curr_mon_load(mtmp) + newload > max_mon_load(mtmp)) return FALSE; return(TRUE); } /* return number of acceptable neighbour positions */ int mfndpos(mon, poss, info, flag) register struct monst *mon; coord *poss; /* coord poss[9] */ long *info; /* long info[9] */ long flag; { struct permonst *mdat = mon->data; register xchar x,y,nx,ny; register int cnt = 0; register uchar ntyp; uchar nowtyp; boolean wantpool,poolok,lavaok,nodiag; boolean rockok = FALSE, treeok = FALSE, thrudoor; int maxx, maxy; x = mon->mx; y = mon->my; nowtyp = levl[x][y].typ; nodiag = (mdat == &mons[PM_GRID_BUG]); wantpool = mdat->mlet == S_EEL; poolok = is_flyer(mdat) || is_clinger(mdat) || (is_swimmer(mdat) && !wantpool); lavaok = is_flyer(mdat) || is_clinger(mdat) || likes_lava(mdat); thrudoor = ((flag & (ALLOW_WALL|BUSTDOOR)) != 0L); if (flag & ALLOW_DIG) { struct obj *mw_tmp; /* need to be specific about what can currently be dug */ if (!needspick(mdat)) { rockok = treeok = TRUE; } else if ((mw_tmp = MON_WEP(mon)) && mw_tmp->cursed && mon->weapon_check == NO_WEAPON_WANTED) { rockok = is_pick(mw_tmp); treeok = is_axe(mw_tmp); } else { rockok = (m_carrying(mon, PICK_AXE) || (m_carrying(mon, DWARVISH_MATTOCK) && !which_armor(mon, W_ARMS))); treeok = (m_carrying(mon, AXE) || (m_carrying(mon, BATTLE_AXE) && !which_armor(mon, W_ARMS))); } thrudoor |= rockok || treeok; } nexttry: /* eels prefer the water, but if there is no water nearby, they will crawl over land */ if(mon->mconf) { flag |= ALLOW_ALL; flag &= ~NOTONL; } if(!mon->mcansee) flag |= ALLOW_SSM; maxx = min(x+1,COLNO-1); maxy = min(y+1,ROWNO-1); for(nx = max(1,x-1); nx <= maxx; nx++) for(ny = max(0,y-1); ny <= maxy; ny++) { if(nx == x && ny == y) continue; if(IS_ROCK(ntyp = levl[nx][ny].typ) && !((flag & ALLOW_WALL) && may_passwall(nx,ny)) && !((IS_TREE(ntyp) ? treeok : rockok) && may_dig(nx,ny))) continue; /* KMH -- Added iron bars */ if (ntyp == IRONBARS && !(flag & ALLOW_BARS)) continue; if(IS_DOOR(ntyp) && !amorphous(mdat) && ((levl[nx][ny].doormask & D_CLOSED && !(flag & OPENDOOR)) || (levl[nx][ny].doormask & D_LOCKED && !(flag & UNLOCKDOOR))) && !thrudoor) continue; if(nx != x && ny != y && (nodiag || #ifdef REINCARNATION ((IS_DOOR(nowtyp) && ((levl[x][y].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz))) || (IS_DOOR(ntyp) && ((levl[nx][ny].doormask & ~D_BROKEN) || Is_rogue_level(&u.uz)))) #else ((IS_DOOR(nowtyp) && (levl[x][y].doormask & ~D_BROKEN)) || (IS_DOOR(ntyp) && (levl[nx][ny].doormask & ~D_BROKEN))) #endif )) continue; if((is_pool(nx,ny) == wantpool || poolok) && (lavaok || !is_lava(nx,ny))) { int dispx, dispy; boolean monseeu = (mon->mcansee && (!Invis || perceives(mdat))); boolean checkobj = OBJ_AT(nx,ny); /* Displacement also displaces the Elbereth/scare monster, * as long as you are visible. */ if(Displaced && monseeu && (mon->mux==nx) && (mon->muy==ny)) { dispx = u.ux; dispy = u.uy; } else { dispx = nx; dispy = ny; } info[cnt] = 0; if ((checkobj || Displaced) && onscary(dispx, dispy, mon)) { if(!(flag & ALLOW_SSM)) continue; info[cnt] |= ALLOW_SSM; } if((nx == u.ux && ny == u.uy) || (nx == mon->mux && ny == mon->muy)) { if (nx == u.ux && ny == u.uy) { /* If it's right next to you, it found you, * displaced or no. We must set mux and muy * right now, so when we return we can tell * that the ALLOW_U means to attack _you_ and * not the image. */ mon->mux = u.ux; mon->muy = u.uy; } if(!(flag & ALLOW_U)) continue; info[cnt] |= ALLOW_U; } else { if(MON_AT(nx, ny)) { struct monst *mtmp2 = m_at(nx, ny); long mmflag = flag | mm_aggression(mon, mtmp2); if (!(mmflag & ALLOW_M)) continue; info[cnt] |= ALLOW_M; if (mtmp2->mtame) { if (!(mmflag & ALLOW_TM)) continue; info[cnt] |= ALLOW_TM; } } /* Note: ALLOW_SANCT only prevents movement, not */ /* attack, into a temple. */ if(level.flags.has_temple && *in_rooms(nx, ny, TEMPLE) && !*in_rooms(x, y, TEMPLE) && in_your_sanctuary((struct monst *)0, nx, ny)) { if(!(flag & ALLOW_SANCT)) continue; info[cnt] |= ALLOW_SANCT; } } if(checkobj && sobj_at(CLOVE_OF_GARLIC, nx, ny)) { if(flag & NOGARLIC) continue; info[cnt] |= NOGARLIC; } if(checkobj && sobj_at(BOULDER, nx, ny)) { if(!(flag & ALLOW_ROCK)) continue; info[cnt] |= ALLOW_ROCK; } if (monseeu && onlineu(nx,ny)) { if(flag & NOTONL) continue; info[cnt] |= NOTONL; } if (nx != x && ny != y && bad_rock(mdat, x, ny) && bad_rock(mdat, nx, y) && (bigmonst(mdat) || (curr_mon_load(mon) > 600))) continue; /* The monster avoids a particular type of trap if it's familiar * with the trap type. Pets get ALLOW_TRAPS and checking is * done in dogmove.c. In either case, "harmless" traps are * neither avoided nor marked in info[]. */ { register struct trap *ttmp = t_at(nx, ny); if(ttmp) { if(ttmp->ttyp >= TRAPNUM || ttmp->ttyp == 0) { impossible("A monster looked at a very strange trap of type %d.", ttmp->ttyp); continue; } if ((ttmp->ttyp != RUST_TRAP || mdat == &mons[PM_IRON_GOLEM]) && ttmp->ttyp != STATUE_TRAP && ((ttmp->ttyp != PIT && ttmp->ttyp != SPIKED_PIT && ttmp->ttyp != TRAPDOOR && ttmp->ttyp != HOLE) || (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) || In_sokoban(&u.uz)) && (ttmp->ttyp != SLP_GAS_TRAP || !resists_sleep(mon)) && (ttmp->ttyp != BEAR_TRAP || (mdat->msize > MZ_SMALL && !amorphous(mdat) && !is_flyer(mdat))) && (ttmp->ttyp != FIRE_TRAP || !resists_fire(mon)) && (ttmp->ttyp != SQKY_BOARD || !is_flyer(mdat)) && (ttmp->ttyp != WEB || (!amorphous(mdat) && !webmaker(mdat))) ) { if (!(flag & ALLOW_TRAPS)) { if (mon->mtrapseen & (1L << (ttmp->ttyp - 1))) continue; } info[cnt] |= ALLOW_TRAPS; } } } poss[cnt].x = nx; poss[cnt].y = ny; cnt++; } } if(!cnt && wantpool && !is_pool(x,y)) { wantpool = FALSE; goto nexttry; } return(cnt); } #endif /* OVL0 */ #ifdef OVL1 /* Monster against monster special attacks; for the specified monster combinations, this allows one monster to attack another adjacent one in the absence of Conflict. There is no provision for targetting other monsters; just hand to hand fighting when they happen to be next to each other. */ STATIC_OVL long mm_aggression(magr, mdef) struct monst *magr, /* monster that is currently deciding where to move */ *mdef; /* another monster which is next to it */ { /* supposedly purple worms are attracted to shrieking because they like to eat shriekers, so attack the latter when feasible */ if (magr->data == &mons[PM_PURPLE_WORM] && mdef->data == &mons[PM_SHRIEKER]) return ALLOW_M|ALLOW_TM; /* Various other combinations such as dog vs cat, cat vs rat, and elf vs orc have been suggested. For the time being we don't support those. */ return 0L; } boolean monnear(mon, x, y) register struct monst *mon; register int x,y; /* Is the square close enough for the monster to move or attack into? */ { register int distance = dist2(mon->mx, mon->my, x, y); if (distance==2 && mon->data==&mons[PM_GRID_BUG]) return 0; return((boolean)(distance < 3)); } /* really free dead monsters */ void dmonsfree() { struct monst **mtmp; int count = 0; for (mtmp = &fmon; *mtmp;) { if ((*mtmp)->mhp <= 0) { struct monst *freetmp = *mtmp; *mtmp = (*mtmp)->nmon; dealloc_monst(freetmp); count++; } else mtmp = &(*mtmp)->nmon; } if (count != iflags.purge_monsters) impossible("dmonsfree: %d removed doesn't match %d pending", count, iflags.purge_monsters); iflags.purge_monsters = 0; } #endif /* OVL1 */ #ifdef OVLB /* called when monster is moved to larger structure */ void replmon(mtmp, mtmp2) register struct monst *mtmp, *mtmp2; { struct obj *otmp; /* transfer the monster's inventory */ for (otmp = mtmp2->minvent; otmp; otmp = otmp->nobj) { #ifdef DEBUG if (otmp->where != OBJ_MINVENT || otmp->ocarry != mtmp) panic("replmon: minvent inconsistency"); #endif otmp->ocarry = mtmp2; } mtmp->minvent = 0; /* remove the old monster from the map and from `fmon' list */ relmon(mtmp); /* finish adding its replacement */ #ifdef STEED if (mtmp == u.usteed) ; else /* don't place steed onto the map */ #endif place_monster(mtmp2, mtmp2->mx, mtmp2->my); if (mtmp2->wormno) /* update level.monsters[wseg->wx][wseg->wy] */ place_wsegs(mtmp2); /* locations to mtmp2 not mtmp. */ if (emits_light(mtmp2->data)) { /* since this is so rare, we don't have any `mon_move_light_source' */ new_light_source(mtmp2->mx, mtmp2->my, emits_light(mtmp2->data), LS_MONSTER, (genericptr_t)mtmp2); /* here we rely on the fact that `mtmp' hasn't actually been deleted */ del_light_source(LS_MONSTER, (genericptr_t)mtmp); } mtmp2->nmon = fmon; fmon = mtmp2; if (u.ustuck == mtmp) u.ustuck = mtmp2; #ifdef STEED if (u.usteed == mtmp) u.usteed = mtmp2; #endif if (mtmp2->isshk) replshk(mtmp,mtmp2); /* discard the old monster */ dealloc_monst(mtmp); } /* release mon from display and monster list */ void relmon(mon) register struct monst *mon; { register struct monst *mtmp; if (fmon == (struct monst *)0) panic ("relmon: no fmon available."); remove_monster(mon->mx, mon->my); if(mon == fmon) fmon = fmon->nmon; else { for(mtmp = fmon; mtmp && mtmp->nmon != mon; mtmp = mtmp->nmon) ; if(mtmp) mtmp->nmon = mon->nmon; else panic("relmon: mon not in list."); } } /* remove effects of mtmp from other data structures */ STATIC_OVL void m_detach(mtmp, mptr) struct monst *mtmp; struct permonst *mptr; /* reflects mtmp->data _prior_ to mtmp's death */ { if (mtmp->mleashed) m_unleash(mtmp, FALSE); /* to prevent an infinite relobj-flooreffects-hmon-killed loop */ mtmp->mtrapped = 0; mtmp->mhp = 0; /* simplify some tests: force mhp to 0 */ relobj(mtmp, 0, FALSE); remove_monster(mtmp->mx, mtmp->my); if (emits_light(mptr)) del_light_source(LS_MONSTER, (genericptr_t)mtmp); newsym(mtmp->mx,mtmp->my); unstuck(mtmp); fill_pit(mtmp->mx, mtmp->my); if(mtmp->isshk) shkgone(mtmp); if(mtmp->wormno) wormgone(mtmp); iflags.purge_monsters++; } /* find the worn amulet of life saving which will save a monster */ struct obj * mlifesaver(mon) struct monst *mon; { if (!nonliving(mon->data)) { struct obj *otmp = which_armor(mon, W_AMUL); if (otmp && otmp->otyp == AMULET_OF_LIFE_SAVING) return otmp; } return (struct obj *)0; } STATIC_OVL void lifesaved_monster(mtmp) struct monst *mtmp; { struct obj *lifesave = mlifesaver(mtmp); if (lifesave) { /* not canseemon; amulets are on the head, so you don't want */ /* to show this for a long worm with only a tail visible. */ /* Nor do you check invisibility, because glowing and disinte- */ /* grating amulets are always visible. */ if (cansee(mtmp->mx, mtmp->my)) { pline("But wait..."); pline("%s medallion begins to glow!", s_suffix(Monnam(mtmp))); makeknown(AMULET_OF_LIFE_SAVING); if (attacktype(mtmp->data, AT_EXPL) || attacktype(mtmp->data, AT_BOOM)) pline("%s reconstitutes!", Monnam(mtmp)); else pline("%s looks much better!", Monnam(mtmp)); pline_The("medallion crumbles to dust!"); } m_useup(mtmp, lifesave); mtmp->mcanmove = 1; mtmp->mfrozen = 0; if (mtmp->mtame && !mtmp->isminion) { wary_dog(mtmp, FALSE); } if (mtmp->mhpmax <= 0) mtmp->mhpmax = 10; mtmp->mhp = mtmp->mhpmax; if (mvitals[monsndx(mtmp->data)].mvflags & G_GENOD) { if (cansee(mtmp->mx, mtmp->my)) pline("Unfortunately %s is still genocided...", mon_nam(mtmp)); } else return; } mtmp->mhp = 0; } void mondead(mtmp) register struct monst *mtmp; { struct permonst *mptr; int tmp; if(mtmp->isgd) { /* if we're going to abort the death, it *must* be before * the m_detach or there will be relmon problems later */ if(!grddead(mtmp)) return; } lifesaved_monster(mtmp); if (mtmp->mhp > 0) return; #ifdef STEED /* Player is thrown from his steed when it dies */ if (mtmp == u.usteed) dismount_steed(DISMOUNT_GENERIC); #endif mptr = mtmp->data; /* save this for m_detach() */ /* restore chameleon, lycanthropes to true form at death */ if (mtmp->cham) set_mon_data(mtmp, &mons[cham_to_pm[mtmp->cham]], -1); else if (mtmp->data == &mons[PM_WEREJACKAL]) set_mon_data(mtmp, &mons[PM_HUMAN_WEREJACKAL], -1); else if (mtmp->data == &mons[PM_WEREWOLF]) set_mon_data(mtmp, &mons[PM_HUMAN_WEREWOLF], -1); else if (mtmp->data == &mons[PM_WERERAT]) set_mon_data(mtmp, &mons[PM_HUMAN_WERERAT], -1); /* if MAXMONNO monsters of a given type have died, and it * can be done, extinguish that monster. * * mvitals[].died does double duty as total number of dead monsters * and as experience factor for the player killing more monsters. * this means that a dragon dying by other means reduces the * experience the player gets for killing a dragon directly; this * is probably not too bad, since the player likely finagled the * first dead dragon via ring of conflict or pets, and extinguishing * based on only player kills probably opens more avenues of abuse * for rings of conflict and such. */ tmp = monsndx(mtmp->data); if (mvitals[tmp].died < 255) mvitals[tmp].died++; /* if it's a (possibly polymorphed) quest leader, mark him as dead */ if (mtmp->m_id == quest_status.leader_m_id) quest_status.leader_is_dead = TRUE; #ifdef MAIL /* if the mail daemon dies, no more mail delivery. -3. */ if (tmp == PM_MAIL_DAEMON) mvitals[tmp].mvflags |= G_GENOD; #endif #ifdef KOPS if (mtmp->data->mlet == S_KOP) { /* Dead Kops may come back. */ switch(rnd(5)) { case 1: /* returns near the stairs */ (void) makemon(mtmp->data,xdnstair,ydnstair,NO_MM_FLAGS); break; case 2: /* randomly */ (void) makemon(mtmp->data,0,0,NO_MM_FLAGS); break; default: break; } } #endif if(mtmp->iswiz) wizdead(); if(mtmp->data->msound == MS_NEMESIS) nemdead(); if(glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) unmap_object(mtmp->mx, mtmp->my); m_detach(mtmp, mptr); } /* TRUE if corpse might be dropped, magr may die if mon was swallowed */ boolean corpse_chance(mon, magr, was_swallowed) struct monst *mon; struct monst *magr; /* killer, if swallowed */ boolean was_swallowed; /* digestion */ { struct permonst *mdat = mon->data; int i, tmp; if (mdat == &mons[PM_VLAD_THE_IMPALER] || mdat->mlet == S_LICH) { if (cansee(mon->mx, mon->my) && !was_swallowed) pline("%s body crumbles into dust.", s_suffix(Monnam(mon))); return FALSE; } /* Gas spores always explode upon death */ for(i = 0; i < NATTK; i++) { if (mdat->mattk[i].aatyp == AT_BOOM) { if (mdat->mattk[i].damn) tmp = d((int)mdat->mattk[i].damn, (int)mdat->mattk[i].damd); else if(mdat->mattk[i].damd) tmp = d((int)mdat->mlevel+1, (int)mdat->mattk[i].damd); else tmp = 0; if (was_swallowed && magr) { if (magr == &youmonst) { There("is an explosion in your %s!", body_part(STOMACH)); Sprintf(killer_buf, "%s explosion", s_suffix(mdat->mname)); if (Half_physical_damage) tmp = (tmp+1) / 2; losehp(tmp, killer_buf, KILLED_BY_AN); } else { if (flags.soundok) You_hear("an explosion."); magr->mhp -= tmp; if (magr->mhp < 1) mondied(magr); if (magr->mhp < 1) { /* maybe lifesaved */ if (canspotmon(magr)) pline("%s rips open!", Monnam(magr)); } else if (canseemon(magr)) pline("%s seems to have indigestion.", Monnam(magr)); } return FALSE; } Sprintf(killer_buf, "%s explosion", s_suffix(mdat->mname)); killer = killer_buf; killer_format = KILLED_BY_AN; explode(mon->mx, mon->my, -1, tmp, MON_EXPLODE, EXPL_NOXIOUS); return (FALSE); } } /* must duplicate this below check in xkilled() since it results in * creating no objects as well as no corpse */ if (LEVEL_SPECIFIC_NOCORPSE(mdat)) return FALSE; if (bigmonst(mdat) || mdat == &mons[PM_LIZARD] || is_golem(mdat) || is_mplayer(mdat) || is_rider(mdat)) return TRUE; return (boolean) (!rn2((int) (2 + ((int)(mdat->geno & G_FREQ)<2) + verysmall(mdat)))); } /* drop (perhaps) a cadaver and remove monster */ void mondied(mdef) register struct monst *mdef; { mondead(mdef); if (mdef->mhp > 0) return; /* lifesaved */ if (corpse_chance(mdef, (struct monst *)0, FALSE) && (accessible(mdef->mx, mdef->my) || is_pool(mdef->mx, mdef->my))) (void) make_corpse(mdef); } /* monster disappears, not dies */ void mongone(mdef) register struct monst *mdef; { mdef->mhp = 0; /* can skip some inventory bookkeeping */ #ifdef STEED /* Player is thrown from his steed when it disappears */ if (mdef == u.usteed) dismount_steed(DISMOUNT_GENERIC); #endif /* drop special items like the Amulet so that a dismissed Kop or nurse can't remove them from the game */ mdrop_special_objs(mdef); /* release rest of monster's inventory--it is removed from game */ discard_minvent(mdef); #ifndef GOLDOBJ mdef->mgold = 0L; #endif m_detach(mdef, mdef->data); } /* drop a statue or rock and remove monster */ void monstone(mdef) register struct monst *mdef; { struct obj *otmp, *obj, *oldminvent; xchar x = mdef->mx, y = mdef->my; boolean wasinside = FALSE; /* we have to make the statue before calling mondead, to be able to * put inventory in it, and we have to check for lifesaving before * making the statue.... */ lifesaved_monster(mdef); if (mdef->mhp > 0) return; mdef->mtrapped = 0; /* (see m_detach) */ if ((int)mdef->data->msize > MZ_TINY || !rn2(2 + ((int) (mdef->data->geno & G_FREQ) > 2))) { oldminvent = 0; /* some objects may end up outside the statue */ while ((obj = mdef->minvent) != 0) { obj_extract_self(obj); if (obj->owornmask) update_mon_intrinsics(mdef, obj, FALSE, TRUE); obj_no_longer_held(obj); if (obj->owornmask & W_WEP) setmnotwielded(mdef,obj); obj->owornmask = 0L; if (obj->otyp == BOULDER || #if 0 /* monsters don't carry statues */ (obj->otyp == STATUE && mons[obj->corpsenm].msize >= mdef->data->msize) || #endif obj_resists(obj, 0, 0)) { if (flooreffects(obj, x, y, "fall")) continue; place_object(obj, x, y); } else { if (obj->lamplit) end_burn(obj, TRUE); obj->nobj = oldminvent; oldminvent = obj; } } /* defer statue creation until after inventory removal so that saved monster traits won't retain any stale item-conferred attributes */ otmp = mkcorpstat(STATUE, KEEPTRAITS(mdef) ? mdef : 0, mdef->data, x, y, FALSE); if (mdef->mnamelth) otmp = oname(otmp, NAME(mdef)); while ((obj = oldminvent) != 0) { oldminvent = obj->nobj; (void) add_to_container(otmp, obj); } #ifndef GOLDOBJ if (mdef->mgold) { struct obj *au; au = mksobj(GOLD_PIECE, FALSE, FALSE); au->quan = mdef->mgold; au->owt = weight(au); (void) add_to_container(otmp, au); mdef->mgold = 0; } #endif /* Archeologists should not break unique statues */ if (mdef->data->geno & G_UNIQ) otmp->spe = 1; otmp->owt = weight(otmp); } else otmp = mksobj_at(ROCK, x, y, TRUE, FALSE); stackobj(otmp); /* mondead() already does this, but we must do it before the newsym */ if(glyph_is_invisible(levl[x][y].glyph)) unmap_object(x, y); if (cansee(x, y)) newsym(x,y); /* We don't currently trap the hero in the statue in this case but we could */ if (u.uswallow && u.ustuck == mdef) wasinside = TRUE; mondead(mdef); if (wasinside) { if (is_animal(mdef->data)) You("%s through an opening in the new %s.", locomotion(youmonst.data, "jump"), xname(otmp)); } } /* another monster has killed the monster mdef */ void monkilled(mdef, fltxt, how) register struct monst *mdef; const char *fltxt; int how; { boolean be_sad = FALSE; /* true if unseen pet is killed */ if ((mdef->wormno ? worm_known(mdef) : cansee(mdef->mx, mdef->my)) && fltxt) pline("%s is %s%s%s!", Monnam(mdef), nonliving(mdef->data) ? "destroyed" : "killed", *fltxt ? " by the " : "", fltxt ); else be_sad = (mdef->mtame != 0); /* no corpses if digested or disintegrated */ if(how == AD_DGST || how == -AD_RBRE) mondead(mdef); else mondied(mdef); if (be_sad && mdef->mhp <= 0) You("have a sad feeling for a moment, then it passes."); } void unstuck(mtmp) register struct monst *mtmp; { if(u.ustuck == mtmp) { if(u.uswallow){ u.ux = mtmp->mx; u.uy = mtmp->my; u.uswallow = 0; u.uswldtim = 0; if (Punished) placebc(); vision_full_recalc = 1; docrt(); } u.ustuck = 0; } } void killed(mtmp) register struct monst *mtmp; { xkilled(mtmp, 1); } /* the player has killed the monster mtmp */ void xkilled(mtmp, dest) register struct monst *mtmp; /* * Dest=1, normal; dest=0, don't print message; dest=2, don't drop corpse * either; dest=3, message but no corpse */ int dest; { register int tmp, x = mtmp->mx, y = mtmp->my; register struct permonst *mdat; int mndx; register struct obj *otmp; register struct trap *t; boolean redisp = FALSE; boolean wasinside = u.uswallow && (u.ustuck == mtmp); /* KMH, conduct */ u.uconduct.killer++; if (dest & 1) { const char *verb = nonliving(mtmp->data) ? "destroy" : "kill"; if (!wasinside && !canspotmon(mtmp)) You("%s it!", verb); else { You("%s %s!", verb, !mtmp->mtame ? mon_nam(mtmp) : x_monnam(mtmp, mtmp->mnamelth ? ARTICLE_NONE : ARTICLE_THE, "poor", mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE)); } } if (mtmp->mtrapped && (t = t_at(x, y)) != 0 && (t->ttyp == PIT || t->ttyp == SPIKED_PIT) && sobj_at(BOULDER, x, y)) dest |= 2; /* * Prevent corpses/treasure being created "on top" * of the boulder that is about to fall in. This is * out of order, but cannot be helped unless this * whole routine is rearranged. */ /* your pet knows who just killed it...watch out */ if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->killed_by_u = 1; /* dispose of monster and make cadaver */ if(stoned) monstone(mtmp); else mondead(mtmp); if (mtmp->mhp > 0) { /* monster lifesaved */ /* Cannot put the non-visible lifesaving message in * lifesaved_monster() since the message appears only when you * kill it (as opposed to visible lifesaving which always * appears). */ stoned = FALSE; if (!cansee(x,y)) pline("Maybe not..."); return; } mdat = mtmp->data; /* note: mondead can change mtmp->data */ mndx = monsndx(mdat); if (stoned) { stoned = FALSE; goto cleanup; } if((dest & 2) || LEVEL_SPECIFIC_NOCORPSE(mdat)) goto cleanup; #ifdef MAIL if(mdat == &mons[PM_MAIL_DAEMON]) { stackobj(mksobj_at(SCR_MAIL, x, y, FALSE, FALSE)); redisp = TRUE; } #endif if((!accessible(x, y) && !is_pool(x, y)) || (x == u.ux && y == u.uy)) { /* might be mimic in wall or corpse in lava or on player's spot */ redisp = TRUE; if(wasinside) spoteffects(TRUE); } else if(x != u.ux || y != u.uy) { /* might be here after swallowed */ if (!rn2(6) && !(mvitals[mndx].mvflags & G_NOCORPSE) #ifdef KOPS && mdat->mlet != S_KOP #endif ) { int typ; otmp = mkobj_at(RANDOM_CLASS, x, y, TRUE); /* Don't create large objects from small monsters */ typ = otmp->otyp; if (mdat->msize < MZ_HUMAN && typ != FOOD_RATION && typ != LEASH && typ != FIGURINE && (otmp->owt > 3 || objects[typ].oc_big /*oc_bimanual/oc_bulky*/ || is_spear(otmp) || is_pole(otmp) || typ == MORNING_STAR)) { delobj(otmp); } else redisp = TRUE; } /* Whether or not it always makes a corpse is, in theory, * different from whether or not the corpse is "special"; * if we want both, we have to specify it explicitly. */ if (corpse_chance(mtmp, (struct monst *)0, FALSE)) (void) make_corpse(mtmp); } if(redisp) newsym(x,y); cleanup: /* punish bad behaviour */ if(is_human(mdat) && (!always_hostile(mdat) && mtmp->malign <= 0) && (mndx < PM_ARCHEOLOGIST || mndx > PM_WIZARD) && u.ualign.type != A_CHAOTIC) { HTelepat &= ~INTRINSIC; change_luck(-2); You("murderer!"); if (Blind && !Blind_telepat) see_monsters(); /* Can't sense monsters any more. */ } if((mtmp->mpeaceful && !rn2(2)) || mtmp->mtame) change_luck(-1); if (is_unicorn(mdat) && sgn(u.ualign.type) == sgn(mdat->maligntyp)) { change_luck(-5); You_feel("guilty..."); } /* give experience points */ tmp = experience(mtmp, (int)mvitals[mndx].died + 1); more_experienced(tmp, 0); newexplevel(); /* will decide if you go up */ /* adjust alignment points */ if (mtmp->m_id == quest_status.leader_m_id) { /* REAL BAD! */ adjalign(-(u.ualign.record+(int)ALIGNLIM/2)); pline("That was %sa bad idea...", u.uevent.qcompleted ? "probably " : ""); } else if (mdat->msound == MS_NEMESIS) /* Real good! */ adjalign((int)(ALIGNLIM/4)); else if (mdat->msound == MS_GUARDIAN) { /* Bad */ adjalign(-(int)(ALIGNLIM/8)); if (!Hallucination) pline("That was probably a bad idea..."); else pline("Whoopsie-daisy!"); }else if (mtmp->ispriest) { adjalign((p_coaligned(mtmp)) ? -2 : 2); /* cancel divine protection for killing your priest */ if (p_coaligned(mtmp)) u.ublessed = 0; if (mdat->maligntyp == A_NONE) adjalign((int)(ALIGNLIM / 4)); /* BIG bonus */ } else if (mtmp->mtame) { adjalign(-15); /* bad!! */ /* your god is mighty displeased... */ if (!Hallucination) You_hear("the rumble of distant thunder..."); else You_hear("the studio audience applaud!"); } else if (mtmp->mpeaceful) adjalign(-5); /* malign was already adjusted for u.ualign.type and randomization */ adjalign(mtmp->malign); } /* changes the monster into a stone monster of the same type */ /* this should only be called when poly_when_stoned() is true */ void mon_to_stone(mtmp) register struct monst *mtmp; { if(mtmp->data->mlet == S_GOLEM) { /* it's a golem, and not a stone golem */ if(canseemon(mtmp)) pline("%s solidifies...", Monnam(mtmp)); if (newcham(mtmp, &mons[PM_STONE_GOLEM], FALSE, FALSE)) { if(canseemon(mtmp)) pline("Now it's %s.", an(mtmp->data->mname)); } else { if(canseemon(mtmp)) pline("... and returns to normal."); } } else impossible("Can't polystone %s!", a_monnam(mtmp)); } void mnexto(mtmp) /* Make monster mtmp next to you (if possible) */ struct monst *mtmp; { coord mm; #ifdef STEED if (mtmp == u.usteed) { /* Keep your steed in sync with you instead */ mtmp->mx = u.ux; mtmp->my = u.uy; return; } #endif if(!enexto(&mm, u.ux, u.uy, mtmp->data)) return; rloc_to(mtmp, mm.x, mm.y); return; } /* mnearto() * Put monster near (or at) location if possible. * Returns: * 1 - if a monster was moved from x, y to put mtmp at x, y. * 0 - in most cases. */ boolean mnearto(mtmp,x,y,move_other) register struct monst *mtmp; xchar x, y; boolean move_other; /* make sure mtmp gets to x, y! so move m_at(x, y) */ { struct monst *othermon = (struct monst *)0; xchar newx, newy; coord mm; if ((mtmp->mx == x) && (mtmp->my == y)) return(FALSE); if (move_other && (othermon = m_at(x, y))) { if (othermon->wormno) remove_worm(othermon); else remove_monster(x, y); } newx = x; newy = y; if (!goodpos(newx, newy, mtmp, 0)) { /* actually we have real problems if enexto ever fails. * migrating_mons that need to be placed will cause * no end of trouble. */ if (!enexto(&mm, newx, newy, mtmp->data)) return(FALSE); newx = mm.x; newy = mm.y; } rloc_to(mtmp, newx, newy); if (move_other && othermon) { othermon->mx = othermon->my = 0; (void) mnearto(othermon, x, y, FALSE); if ((othermon->mx != x) || (othermon->my != y)) return(TRUE); } return(FALSE); } static const char *poiseff[] = { " feel weaker", "r brain is on fire", "r judgement is impaired", "r muscles won't obey you", " feel very sick", " break out in hives" }; void poisontell(typ) int typ; { pline("You%s.", poiseff[typ]); } void poisoned(string, typ, pname, fatal) const char *string, *pname; int typ, fatal; { int i, plural, kprefix = KILLED_BY_AN; boolean thrown_weapon = (fatal < 0); if (thrown_weapon) fatal = -fatal; if(strcmp(string, "blast") && !thrown_weapon) { /* 'blast' has already given a 'poison gas' message */ /* so have "poison arrow", "poison dart", etc... */ plural = (string[strlen(string) - 1] == 's')? 1 : 0; /* avoid "The" Orcus's sting was poisoned... */ pline("%s%s %s poisoned!", isupper(*string) ? "" : "The ", string, plural ? "were" : "was"); } if(Poison_resistance) { if(!strcmp(string, "blast")) shieldeff(u.ux, u.uy); pline_The("poison doesn't seem to affect you."); return; } /* suppress killer prefix if it already has one */ if ((i = name_to_mon(pname)) >= LOW_PM && mons[i].geno & G_UNIQ) { kprefix = KILLED_BY; if (!type_is_pname(&mons[i])) pname = the(pname); } else if (!strncmpi(pname, "the ", 4) || !strncmpi(pname, "an ", 3) || !strncmpi(pname, "a ", 2)) { /*[ does this need a plural check too? ]*/ kprefix = KILLED_BY; } i = rn2(fatal + 20*thrown_weapon); if(i == 0 && typ != A_CHA) { u.uhp = -1; pline_The("poison was deadly..."); } else if(i <= 5) { /* Check that a stat change was made */ if (adjattrib(typ, thrown_weapon ? -1 : -rn1(3,3), 1)) pline("You%s!", poiseff[typ]); } else { i = thrown_weapon ? rnd(6) : rn1(10,6); if(Half_physical_damage) i = (i+1) / 2; losehp(i, pname, kprefix); } if(u.uhp < 1) { killer_format = kprefix; killer = pname; /* "Poisoned by a poisoned ___" is redundant */ done(strstri(pname, "poison") ? DIED : POISONING); } (void) encumber_msg(); } /* monster responds to player action; not the same as a passive attack */ /* assumes reason for response has been tested, and response _must_ be made */ void m_respond(mtmp) register struct monst *mtmp; { if(mtmp->data->msound == MS_SHRIEK) { if(flags.soundok) { pline("%s shrieks.", Monnam(mtmp)); stop_occupation(); } if (!rn2(10)) { if (!rn2(13)) (void) makemon(&mons[PM_PURPLE_WORM], 0, 0, NO_MM_FLAGS); else (void) makemon((struct permonst *)0, 0, 0, NO_MM_FLAGS); } aggravate(); } if(mtmp->data == &mons[PM_MEDUSA]) { register int i; for(i = 0; i < NATTK; i++) if(mtmp->data->mattk[i].aatyp == AT_GAZE) { (void) gazemu(mtmp, &mtmp->data->mattk[i]); break; } } } #endif /* OVLB */ #ifdef OVL2 void setmangry(mtmp) register struct monst *mtmp; { mtmp->mstrategy &= ~STRAT_WAITMASK; if(!mtmp->mpeaceful) return; if(mtmp->mtame) return; mtmp->mpeaceful = 0; if(mtmp->ispriest) { if(p_coaligned(mtmp)) adjalign(-5); /* very bad */ else adjalign(2); } else adjalign(-1); /* attacking peaceful monsters is bad */ if (couldsee(mtmp->mx, mtmp->my)) { if (humanoid(mtmp->data) || mtmp->isshk || mtmp->isgd) pline("%s gets angry!", Monnam(mtmp)); else if (flags.verbose && flags.soundok) growl(mtmp); } /* attacking your own quest leader will anger his or her guardians */ if (!flags.mon_moving && /* should always be the case here */ mtmp->data == &mons[quest_info(MS_LEADER)]) { struct monst *mon; struct permonst *q_guardian = &mons[quest_info(MS_GUARDIAN)]; int got_mad = 0; /* guardians will sense this attack even if they can't see it */ for (mon = fmon; mon; mon = mon->nmon) if (!DEADMONSTER(mon) && mon->data == q_guardian && mon->mpeaceful) { mon->mpeaceful = 0; if (canseemon(mon)) ++got_mad; } if (got_mad && !Hallucination) pline_The("%s appear%s to be angry too...", got_mad == 1 ? q_guardian->mname : makeplural(q_guardian->mname), got_mad == 1 ? "s" : ""); } } void wakeup(mtmp) register struct monst *mtmp; { mtmp->msleeping = 0; mtmp->meating = 0; /* assume there's no salvagable food left */ setmangry(mtmp); if(mtmp->m_ap_type) seemimic(mtmp); else if (flags.forcefight && !flags.mon_moving && mtmp->mundetected) { mtmp->mundetected = 0; newsym(mtmp->mx, mtmp->my); } } /* Wake up nearby monsters. */ void wake_nearby() { register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (!DEADMONSTER(mtmp) && distu(mtmp->mx,mtmp->my) < u.ulevel*20) { mtmp->msleeping = 0; if (mtmp->mtame && !mtmp->isminion) EDOG(mtmp)->whistletime = moves; } } } /* Wake up monsters near some particular location. */ void wake_nearto(x, y, distance) register int x, y, distance; { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (!DEADMONSTER(mtmp) && mtmp->msleeping && (distance == 0 || dist2(mtmp->mx, mtmp->my, x, y) < distance)) mtmp->msleeping = 0; } } /* NOTE: we must check for mimicry before calling this routine */ void seemimic(mtmp) register struct monst *mtmp; { unsigned old_app = mtmp->mappearance; uchar old_ap_type = mtmp->m_ap_type; mtmp->m_ap_type = M_AP_NOTHING; mtmp->mappearance = 0; /* * Discovered mimics don't block light. */ if (((old_ap_type == M_AP_FURNITURE && (old_app == S_hcdoor || old_app == S_vcdoor)) || (old_ap_type == M_AP_OBJECT && old_app == BOULDER)) && !does_block(mtmp->mx, mtmp->my, &levl[mtmp->mx][mtmp->my])) unblock_point(mtmp->mx, mtmp->my); newsym(mtmp->mx,mtmp->my); } /* force all chameleons to become normal */ void rescham() { register struct monst *mtmp; int mcham; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; mcham = (int) mtmp->cham; if (mcham) { mtmp->cham = CHAM_ORDINARY; (void) newcham(mtmp, &mons[cham_to_pm[mcham]], FALSE, FALSE); } if(is_were(mtmp->data) && mtmp->data->mlet != S_HUMAN) new_were(mtmp); if(mtmp->m_ap_type && cansee(mtmp->mx, mtmp->my)) { seemimic(mtmp); /* we pretend that the mimic doesn't */ /* know that it has been unmasked. */ mtmp->msleeping = 1; } } } /* Let the chameleons change again -dgk */ void restartcham() { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; mtmp->cham = pm_to_cham(monsndx(mtmp->data)); if (mtmp->data->mlet == S_MIMIC && mtmp->msleeping && cansee(mtmp->mx, mtmp->my)) { set_mimic_sym(mtmp); newsym(mtmp->mx,mtmp->my); } } } /* called when restoring a monster from a saved level; protection against shape-changing might be different now than it was at the time the level was saved. */ void restore_cham(mon) struct monst *mon; { int mcham; if (Protection_from_shape_changers) { mcham = (int) mon->cham; if (mcham) { mon->cham = CHAM_ORDINARY; (void) newcham(mon, &mons[cham_to_pm[mcham]], FALSE, FALSE); } else if (is_were(mon->data) && !is_human(mon->data)) { new_were(mon); } } else if (mon->cham == CHAM_ORDINARY) { mon->cham = pm_to_cham(monsndx(mon->data)); } } /* unwatched hiders may hide again; if so, a 1 is returned. */ STATIC_OVL boolean restrap(mtmp) register struct monst *mtmp; { if(mtmp->cham || mtmp->mcan || mtmp->m_ap_type || cansee(mtmp->mx, mtmp->my) || rn2(3) || (mtmp == u.ustuck) || (sensemon(mtmp) && distu(mtmp->mx, mtmp->my) <= 2)) return(FALSE); if(mtmp->data->mlet == S_MIMIC) { set_mimic_sym(mtmp); return(TRUE); } else if(levl[mtmp->mx][mtmp->my].typ == ROOM) { mtmp->mundetected = 1; return(TRUE); } return(FALSE); } short *animal_list = 0; /* list of PM values for animal monsters */ int animal_list_count; void mon_animal_list(construct) boolean construct; { if (construct) { short animal_temp[SPECIAL_PM]; int i, n; /* if (animal_list) impossible("animal_list already exists"); */ for (n = 0, i = LOW_PM; i < SPECIAL_PM; i++) if (is_animal(&mons[i])) animal_temp[n++] = i; /* if (n == 0) animal_temp[n++] = NON_PM; */ animal_list = (short *)alloc(n * sizeof *animal_list); (void) memcpy((genericptr_t)animal_list, (genericptr_t)animal_temp, n * sizeof *animal_list); animal_list_count = n; } else { /* release */ if (animal_list) free((genericptr_t)animal_list), animal_list = 0; animal_list_count = 0; } } STATIC_OVL int pick_animal() { if (!animal_list) mon_animal_list(TRUE); return animal_list[rn2(animal_list_count)]; } STATIC_OVL int select_newcham_form(mon) struct monst *mon; { int mndx = NON_PM; switch (mon->cham) { case CHAM_SANDESTIN: if (rn2(7)) mndx = pick_nasty(); break; case CHAM_DOPPELGANGER: if (!rn2(7)) mndx = pick_nasty(); else if (rn2(3)) mndx = rn1(PM_WIZARD - PM_ARCHEOLOGIST + 1, PM_ARCHEOLOGIST); break; case CHAM_CHAMELEON: if (!rn2(3)) mndx = pick_animal(); break; case CHAM_ORDINARY: { struct obj *m_armr = which_armor(mon, W_ARM); if (m_armr && Is_dragon_scales(m_armr)) mndx = Dragon_scales_to_pm(m_armr) - mons; else if (m_armr && Is_dragon_mail(m_armr)) mndx = Dragon_mail_to_pm(m_armr) - mons; } break; } #ifdef WIZARD /* For debugging only: allow control of polymorphed monster; not saved */ if (wizard && iflags.mon_polycontrol) { char pprompt[BUFSZ], buf[BUFSZ]; int tries = 0; do { Sprintf(pprompt, "Change %s into what kind of monster? [type the name]", mon_nam(mon)); getlin(pprompt,buf); mndx = name_to_mon(buf); if (mndx < LOW_PM) You("cannot polymorph %s into that.", mon_nam(mon)); else break; } while(++tries < 5); if (tries==5) pline(thats_enough_tries); } #endif /*WIZARD*/ if (mndx == NON_PM) mndx = rn1(SPECIAL_PM - LOW_PM, LOW_PM); return mndx; } /* make a chameleon look like a new monster; returns 1 if it actually changed */ int newcham(mtmp, mdat, polyspot, msg) struct monst *mtmp; struct permonst *mdat; boolean polyspot; /* change is the result of wand or spell of polymorph */ boolean msg; /* "The oldmon turns into a newmon!" */ { int mhp, hpn, hpd; int mndx, tryct; struct permonst *olddata = mtmp->data; char oldname[BUFSZ]; if (msg) { /* like Monnam() but never mention saddle */ Strcpy(oldname, x_monnam(mtmp, ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE)); oldname[0] = highc(oldname[0]); } /* mdat = 0 -> caller wants a random monster shape */ tryct = 0; if (mdat == 0) { while (++tryct <= 100) { mndx = select_newcham_form(mtmp); mdat = &mons[mndx]; if ((mvitals[mndx].mvflags & G_GENOD) != 0 || is_placeholder(mdat)) continue; /* polyok rules out all M2_PNAME and M2_WERE's; select_newcham_form might deliberately pick a player character type, so we can't arbitrarily rule out all human forms any more */ if (is_mplayer(mdat) || (!is_human(mdat) && polyok(mdat))) break; } if (tryct > 100) return 0; /* Should never happen */ } else if (mvitals[monsndx(mdat)].mvflags & G_GENOD) return(0); /* passed in mdat is genocided */ if(is_male(mdat)) { if(mtmp->female) mtmp->female = FALSE; } else if (is_female(mdat)) { if(!mtmp->female) mtmp->female = TRUE; } else if (!is_neuter(mdat)) { if(!rn2(10)) mtmp->female = !mtmp->female; } if (In_endgame(&u.uz) && is_mplayer(olddata)) { /* mplayers start out as "Foo the Bar", but some of the * titles are inappropriate when polymorphed, particularly * into the opposite sex. players don't use ranks when * polymorphed, so dropping the rank for mplayers seems * reasonable. */ char *p = index(NAME(mtmp), ' '); if (p) { *p = '\0'; mtmp->mnamelth = p - NAME(mtmp) + 1; } } if(mdat == mtmp->data) return(0); /* still the same monster */ if(mtmp->wormno) { /* throw tail away */ wormgone(mtmp); place_monster(mtmp, mtmp->mx, mtmp->my); } hpn = mtmp->mhp; hpd = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel; if(!hpd) hpd = 4; mtmp->m_lev = adj_lev(mdat); /* new monster level */ mhp = (mtmp->m_lev < 50) ? ((int)mtmp->m_lev)*8 : mdat->mlevel; if(!mhp) mhp = 4; /* new hp: same fraction of max as before */ #ifndef LINT mtmp->mhp = (int)(((long)hpn*(long)mhp)/(long)hpd); #endif if(mtmp->mhp < 0) mtmp->mhp = hpn; /* overflow */ /* Unlikely but not impossible; a 1HD creature with 1HP that changes into a 0HD creature will require this statement */ if (!mtmp->mhp) mtmp->mhp = 1; /* and the same for maximum hit points */ hpn = mtmp->mhpmax; #ifndef LINT mtmp->mhpmax = (int)(((long)hpn*(long)mhp)/(long)hpd); #endif if(mtmp->mhpmax < 0) mtmp->mhpmax = hpn; /* overflow */ if (!mtmp->mhpmax) mtmp->mhpmax = 1; /* take on the new form... */ set_mon_data(mtmp, mdat, 0); if (emits_light(olddata) != emits_light(mtmp->data)) { /* used to give light, now doesn't, or vice versa, or light's range has changed */ if (emits_light(olddata)) del_light_source(LS_MONSTER, (genericptr_t)mtmp); if (emits_light(mtmp->data)) new_light_source(mtmp->mx, mtmp->my, emits_light(mtmp->data), LS_MONSTER, (genericptr_t)mtmp); } if (!mtmp->perminvis || pm_invisible(olddata)) mtmp->perminvis = pm_invisible(mdat); mtmp->minvis = mtmp->invis_blkd ? 0 : mtmp->perminvis; if (!(hides_under(mdat) && OBJ_AT(mtmp->mx, mtmp->my)) && !(mdat->mlet == S_EEL && is_pool(mtmp->mx, mtmp->my))) mtmp->mundetected = 0; if (u.ustuck == mtmp) { if(u.uswallow) { if(!attacktype(mdat,AT_ENGL)) { /* Does mdat care? */ if (!noncorporeal(mdat) && !amorphous(mdat) && !is_whirly(mdat) && (mdat != &mons[PM_YELLOW_LIGHT])) { You("break out of %s%s!", mon_nam(mtmp), (is_animal(mdat)? "'s stomach" : "")); mtmp->mhp = 1; /* almost dead */ } expels(mtmp, olddata, FALSE); } else { /* update swallow glyphs for new monster */ swallowed(0); } } else if (!sticks(mdat) && !sticks(youmonst.data)) unstuck(mtmp); } #ifndef DCC30_BUG if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno()) != 0) { #else /* DICE 3.0 doesn't like assigning and comparing mtmp->wormno in the * same expression. */ if (mdat == &mons[PM_LONG_WORM] && (mtmp->wormno = get_wormno(), mtmp->wormno != 0)) { #endif /* we can now create worms with tails - 11/91 */ initworm(mtmp, rn2(5)); if (count_wsegs(mtmp)) place_worm_tail_randomly(mtmp, mtmp->mx, mtmp->my); } newsym(mtmp->mx,mtmp->my); if (msg) { uchar save_mnamelth = mtmp->mnamelth; mtmp->mnamelth = 0; pline("%s turns into %s!", oldname, mdat == &mons[PM_GREEN_SLIME] ? "slime" : x_monnam(mtmp, ARTICLE_A, (char*)0, SUPPRESS_SADDLE, FALSE)); mtmp->mnamelth = save_mnamelth; } possibly_unwield(mtmp, polyspot); /* might lose use of weapon */ mon_break_armor(mtmp, polyspot); if (!(mtmp->misc_worn_check & W_ARMG)) mselftouch(mtmp, "No longer petrify-resistant, ", !flags.mon_moving); m_dowear(mtmp, FALSE); /* This ought to re-test can_carry() on each item in the inventory * rather than just checking ex-giants & boulders, but that'd be * pretty expensive to perform. If implemented, then perhaps * minvent should be sorted in order to drop heaviest items first. */ /* former giants can't continue carrying boulders */ if (mtmp->minvent && !throws_rocks(mdat)) { register struct obj *otmp, *otmp2; for (otmp = mtmp->minvent; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (otmp->otyp == BOULDER) { /* this keeps otmp from being polymorphed in the same zap that the monster that held it is polymorphed */ if (polyspot) bypass_obj(otmp); obj_extract_self(otmp); /* probably ought to give some "drop" message here */ if (flooreffects(otmp, mtmp->mx, mtmp->my, "")) continue; place_object(otmp, mtmp->mx, mtmp->my); } } } return(1); } /* sometimes an egg will be special */ #define BREEDER_EGG (!rn2(77)) /* * Determine if the given monster number can be hatched from an egg. * Return the monster number to use as the egg's corpsenm. Return * NON_PM if the given monster can't be hatched. */ int can_be_hatched(mnum) int mnum; { /* ranger quest nemesis has the oviparous bit set, making it be possible to wish for eggs of that unique monster; turn such into ordinary eggs rather than forbidding them outright */ if (mnum == PM_SCORPIUS) mnum = PM_SCORPION; mnum = little_to_big(mnum); /* * Queen bees lay killer bee eggs (usually), but killer bees don't * grow into queen bees. Ditto for [winged-]gargoyles. */ if (mnum == PM_KILLER_BEE || mnum == PM_GARGOYLE || (lays_eggs(&mons[mnum]) && (BREEDER_EGG || (mnum != PM_QUEEN_BEE && mnum != PM_WINGED_GARGOYLE)))) return mnum; return NON_PM; } /* type of egg laid by #sit; usually matches parent */ int egg_type_from_parent(mnum, force_ordinary) int mnum; /* parent monster; caller must handle lays_eggs() check */ boolean force_ordinary; { if (force_ordinary || !BREEDER_EGG) { if (mnum == PM_QUEEN_BEE) mnum = PM_KILLER_BEE; else if (mnum == PM_WINGED_GARGOYLE) mnum = PM_GARGOYLE; } return mnum; } /* decide whether an egg of the indicated monster type is viable; */ /* also used to determine whether an egg or tin can be created... */ boolean dead_species(m_idx, egg) int m_idx; boolean egg; { /* * For monsters with both baby and adult forms, genociding either * form kills all eggs of that monster. Monsters with more than * two forms (small->large->giant mimics) are more or less ignored; * fortunately, none of them have eggs. Species extinction due to * overpopulation does not kill eggs. */ return (boolean) (m_idx >= LOW_PM && ((mvitals[m_idx].mvflags & G_GENOD) != 0 || (egg && (mvitals[big_to_little(m_idx)].mvflags & G_GENOD) != 0))); } /* kill off any eggs of genocided monsters */ STATIC_OVL void kill_eggs(obj_list) struct obj *obj_list; { struct obj *otmp; for (otmp = obj_list; otmp; otmp = otmp->nobj) if (otmp->otyp == EGG) { if (dead_species(otmp->corpsenm, TRUE)) { /* * It seems we could also just catch this when * it attempted to hatch, so we wouldn't have to * search all of the objlists.. or stop all * hatch timers based on a corpsenm. */ kill_egg(otmp); } #if 0 /* not used */ } else if (otmp->otyp == TIN) { if (dead_species(otmp->corpsenm, FALSE)) otmp->corpsenm = NON_PM; /* empty tin */ } else if (otmp->otyp == CORPSE) { if (dead_species(otmp->corpsenm, FALSE)) ; /* not yet implemented... */ #endif } else if (Has_contents(otmp)) { kill_eggs(otmp->cobj); } } /* kill all members of genocided species */ void kill_genocided_monsters() { struct monst *mtmp, *mtmp2; boolean kill_cham[CHAM_MAX_INDX+1]; int mndx; kill_cham[CHAM_ORDINARY] = FALSE; /* (this is mndx==0) */ for (mndx = 1; mndx <= CHAM_MAX_INDX; mndx++) kill_cham[mndx] = (mvitals[cham_to_pm[mndx]].mvflags & G_GENOD) != 0; /* * Called during genocide, and again upon level change. The latter * catches up with any migrating monsters as they finally arrive at * their intended destinations, so possessions get deposited there. * * Chameleon handling: * 1) if chameleons have been genocided, destroy them * regardless of current form; * 2) otherwise, force every chameleon which is imitating * any genocided species to take on a new form. */ for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; mndx = monsndx(mtmp->data); if ((mvitals[mndx].mvflags & G_GENOD) || kill_cham[mtmp->cham]) { if (mtmp->cham && !kill_cham[mtmp->cham]) (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); else mondead(mtmp); } if (mtmp->minvent) kill_eggs(mtmp->minvent); } kill_eggs(invent); kill_eggs(fobj); kill_eggs(level.buriedobjlist); } #endif /* OVL2 */ #ifdef OVLB void golemeffects(mon, damtype, dam) register struct monst *mon; int damtype, dam; { int heal = 0, slow = 0; if (mon->data == &mons[PM_FLESH_GOLEM]) { if (damtype == AD_ELEC) heal = dam / 6; else if (damtype == AD_FIRE || damtype == AD_COLD) slow = 1; } else if (mon->data == &mons[PM_IRON_GOLEM]) { if (damtype == AD_ELEC) slow = 1; else if (damtype == AD_FIRE) heal = dam; } else { return; } if (slow) { if (mon->mspeed != MSLOW) mon_adjust_speed(mon, -1, (struct obj *)0); } if (heal) { if (mon->mhp < mon->mhpmax) { mon->mhp += dam; if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; if (cansee(mon->mx, mon->my)) pline("%s seems healthier.", Monnam(mon)); } } } boolean angry_guards(silent) register boolean silent; { register struct monst *mtmp; register int ct = 0, nct = 0, sct = 0, slct = 0; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if((mtmp->data == &mons[PM_WATCHMAN] || mtmp->data == &mons[PM_WATCH_CAPTAIN]) && mtmp->mpeaceful) { ct++; if(cansee(mtmp->mx, mtmp->my) && mtmp->mcanmove) { if (distu(mtmp->mx, mtmp->my) == 2) nct++; else sct++; } if (mtmp->msleeping || mtmp->mfrozen) { slct++; mtmp->msleeping = mtmp->mfrozen = 0; } mtmp->mpeaceful = 0; } } if(ct) { if(!silent) { /* do we want pline msgs? */ if(slct) pline_The("guard%s wake%s up!", slct > 1 ? "s" : "", slct == 1 ? "s" : ""); if(nct || sct) { if(nct) pline_The("guard%s get%s angry!", nct == 1 ? "" : "s", nct == 1 ? "s" : ""); else if(!Blind) You("see %sangry guard%s approaching!", sct == 1 ? "an " : "", sct > 1 ? "s" : ""); } else if(flags.soundok) You_hear("the shrill sound of a guard's whistle."); } return(TRUE); } return(FALSE); } void pacify_guards() { register struct monst *mtmp; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (mtmp->data == &mons[PM_WATCHMAN] || mtmp->data == &mons[PM_WATCH_CAPTAIN]) mtmp->mpeaceful = 1; } } void mimic_hit_msg(mtmp, otyp) struct monst *mtmp; short otyp; { short ap = mtmp->mappearance; switch(mtmp->m_ap_type) { case M_AP_NOTHING: case M_AP_FURNITURE: case M_AP_MONSTER: break; case M_AP_OBJECT: if (otyp == SPE_HEALING || otyp == SPE_EXTRA_HEALING) { pline("%s seems a more vivid %s than before.", The(simple_typename(ap)), c_obj_colors[objects[ap].oc_color]); } break; } } #endif /* OVLB */ /*mon.c*/ nethack-3.4.3/src/mondata.c0100644000000000000000000004776507764735041014253 0ustar rootroot/* SCCS Id: @(#)mondata.c 3.4 2003/06/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "eshk.h" #include "epri.h" /* These routines provide basic data for any type of monster. */ #ifdef OVLB void set_mon_data(mon, ptr, flag) struct monst *mon; struct permonst *ptr; int flag; { mon->data = ptr; if (flag == -1) return; /* "don't care" */ if (flag == 1) mon->mintrinsics |= (ptr->mresists & 0x00FF); else mon->mintrinsics = (ptr->mresists & 0x00FF); return; } #endif /* OVLB */ #ifdef OVL0 struct attack * attacktype_fordmg(ptr, atyp, dtyp) struct permonst *ptr; int atyp, dtyp; { struct attack *a; for (a = &ptr->mattk[0]; a < &ptr->mattk[NATTK]; a++) if (a->aatyp == atyp && (dtyp == AD_ANY || a->adtyp == dtyp)) return a; return (struct attack *)0; } boolean attacktype(ptr, atyp) struct permonst *ptr; int atyp; { return attacktype_fordmg(ptr, atyp, AD_ANY) ? TRUE : FALSE; } #endif /* OVL0 */ #ifdef OVLB boolean poly_when_stoned(ptr) struct permonst *ptr; { return((boolean)(is_golem(ptr) && ptr != &mons[PM_STONE_GOLEM] && !(mvitals[PM_STONE_GOLEM].mvflags & G_GENOD))); /* allow G_EXTINCT */ } boolean resists_drli(mon) /* returns TRUE if monster is drain-life resistant */ struct monst *mon; { struct permonst *ptr = mon->data; struct obj *wep = ((mon == &youmonst) ? uwep : MON_WEP(mon)); return (boolean)(is_undead(ptr) || is_demon(ptr) || is_were(ptr) || ptr == &mons[PM_DEATH] || (wep && wep->oartifact && defends(AD_DRLI, wep))); } boolean resists_magm(mon) /* TRUE if monster is magic-missile resistant */ struct monst *mon; { struct permonst *ptr = mon->data; struct obj *o; /* as of 3.2.0: gray dragons, Angels, Oracle, Yeenoghu */ if (dmgtype(ptr, AD_MAGM) || ptr == &mons[PM_BABY_GRAY_DRAGON] || dmgtype(ptr, AD_RBRE)) /* Chromatic Dragon */ return TRUE; /* check for magic resistance granted by wielded weapon */ o = (mon == &youmonst) ? uwep : MON_WEP(mon); if (o && o->oartifact && defends(AD_MAGM, o)) return TRUE; /* check for magic resistance granted by worn or carried items */ o = (mon == &youmonst) ? invent : mon->minvent; for ( ; o; o = o->nobj) if ((o->owornmask && objects[o->otyp].oc_oprop == ANTIMAGIC) || (o->oartifact && protects(AD_MAGM, o))) return TRUE; return FALSE; } /* TRUE iff monster is resistant to light-induced blindness */ boolean resists_blnd(mon) struct monst *mon; { struct permonst *ptr = mon->data; boolean is_you = (mon == &youmonst); struct obj *o; if (is_you ? (Blind || u.usleep) : (mon->mblinded || !mon->mcansee || !haseyes(ptr) || /* BUG: temporary sleep sets mfrozen, but since paralysis does too, we can't check it */ mon->msleeping)) return TRUE; /* yellow light, Archon; !dust vortex, !cobra, !raven */ if (dmgtype_fromattack(ptr, AD_BLND, AT_EXPL) || dmgtype_fromattack(ptr, AD_BLND, AT_GAZE)) return TRUE; o = is_you ? uwep : MON_WEP(mon); if (o && o->oartifact && defends(AD_BLND, o)) return TRUE; o = is_you ? invent : mon->minvent; for ( ; o; o = o->nobj) if ((o->owornmask && objects[o->otyp].oc_oprop == BLINDED) || (o->oartifact && protects(AD_BLND, o))) return TRUE; return FALSE; } /* TRUE iff monster can be blinded by the given attack */ /* Note: may return TRUE when mdef is blind (e.g. new cream-pie attack) */ boolean can_blnd(magr, mdef, aatyp, obj) struct monst *magr; /* NULL == no specific aggressor */ struct monst *mdef; uchar aatyp; struct obj *obj; /* aatyp == AT_WEAP, AT_SPIT */ { boolean is_you = (mdef == &youmonst); boolean check_visor = FALSE; struct obj *o; const char *s; /* no eyes protect against all attacks for now */ if (!haseyes(mdef->data)) return FALSE; switch(aatyp) { case AT_EXPL: case AT_BOOM: case AT_GAZE: case AT_MAGC: case AT_BREA: /* assumed to be lightning */ /* light-based attacks may be cancelled or resisted */ if (magr && magr->mcan) return FALSE; return !resists_blnd(mdef); case AT_WEAP: case AT_SPIT: case AT_NONE: /* an object is used (thrown/spit/other) */ if (obj && (obj->otyp == CREAM_PIE)) { if (is_you && Blindfolded) return FALSE; } else if (obj && (obj->otyp == BLINDING_VENOM)) { /* all ublindf, including LENSES, protect, cream-pies too */ if (is_you && (ublindf || u.ucreamed)) return FALSE; check_visor = TRUE; } else if (obj && (obj->otyp == POT_BLINDNESS)) { return TRUE; /* no defense */ } else return FALSE; /* other objects cannot cause blindness yet */ if ((magr == &youmonst) && u.uswallow) return FALSE; /* can't affect eyes while inside monster */ break; case AT_ENGL: if (is_you && (Blindfolded || u.usleep || u.ucreamed)) return FALSE; if (!is_you && mdef->msleeping) return FALSE; break; case AT_CLAW: /* e.g. raven: all ublindf, including LENSES, protect */ if (is_you && ublindf) return FALSE; if ((magr == &youmonst) && u.uswallow) return FALSE; /* can't affect eyes while inside monster */ check_visor = TRUE; break; case AT_TUCH: case AT_STNG: /* some physical, blind-inducing attacks can be cancelled */ if (magr && magr->mcan) return FALSE; break; default: break; } /* check if wearing a visor (only checked if visor might help) */ if (check_visor) { o = (mdef == &youmonst) ? invent : mdef->minvent; for ( ; o; o = o->nobj) if ((o->owornmask & W_ARMH) && (s = OBJ_DESCR(objects[o->otyp])) != (char *)0 && !strcmp(s, "visored helmet")) return FALSE; } return TRUE; } #endif /* OVLB */ #ifdef OVL0 boolean ranged_attk(ptr) /* returns TRUE if monster can attack at range */ struct permonst *ptr; { register int i, atyp; long atk_mask = (1L << AT_BREA) | (1L << AT_SPIT) | (1L << AT_GAZE); /* was: (attacktype(ptr, AT_BREA) || attacktype(ptr, AT_WEAP) || attacktype(ptr, AT_SPIT) || attacktype(ptr, AT_GAZE) || attacktype(ptr, AT_MAGC)); but that's too slow -dlc */ for (i = 0; i < NATTK; i++) { atyp = ptr->mattk[i].aatyp; if (atyp >= AT_WEAP) return TRUE; /* assert(atyp < 32); */ if ((atk_mask & (1L << atyp)) != 0L) return TRUE; } return FALSE; } boolean hates_silver(ptr) register struct permonst *ptr; /* returns TRUE if monster is especially affected by silver weapons */ { return((boolean)(is_were(ptr) || ptr->mlet==S_VAMPIRE || is_demon(ptr) || ptr == &mons[PM_SHADE] || (ptr->mlet==S_IMP && ptr != &mons[PM_TENGU]))); } /* true iff the type of monster pass through iron bars */ boolean passes_bars(mptr) struct permonst *mptr; { return (boolean) (passes_walls(mptr) || amorphous(mptr) || is_whirly(mptr) || verysmall(mptr) || (slithy(mptr) && !bigmonst(mptr))); } #endif /* OVL0 */ #ifdef OVL1 boolean can_track(ptr) /* returns TRUE if monster can track well */ register struct permonst *ptr; { if (uwep && uwep->oartifact == ART_EXCALIBUR) return TRUE; else return((boolean)haseyes(ptr)); } #endif /* OVL1 */ #ifdef OVLB boolean sliparm(ptr) /* creature will slide out of armor */ register struct permonst *ptr; { return((boolean)(is_whirly(ptr) || ptr->msize <= MZ_SMALL || noncorporeal(ptr))); } boolean breakarm(ptr) /* creature will break out of armor */ register struct permonst *ptr; { return ((bigmonst(ptr) || (ptr->msize > MZ_SMALL && !humanoid(ptr)) || /* special cases of humanoids that cannot wear body armor */ ptr == &mons[PM_MARILITH] || ptr == &mons[PM_WINGED_GARGOYLE]) && !sliparm(ptr)); } #endif /* OVLB */ #ifdef OVL1 boolean sticks(ptr) /* creature sticks other creatures it hits */ register struct permonst *ptr; { return((boolean)(dmgtype(ptr,AD_STCK) || dmgtype(ptr,AD_WRAP) || attacktype(ptr,AT_HUGS))); } /* number of horns this type of monster has on its head */ int num_horns(ptr) struct permonst *ptr; { switch (monsndx(ptr)) { case PM_HORNED_DEVIL: /* ? "more than one" */ case PM_MINOTAUR: case PM_ASMODEUS: case PM_BALROG: return 2; case PM_WHITE_UNICORN: case PM_GRAY_UNICORN: case PM_BLACK_UNICORN: case PM_KI_RIN: return 1; default: break; } return 0; } struct attack * dmgtype_fromattack(ptr, dtyp, atyp) struct permonst *ptr; int dtyp, atyp; { struct attack *a; for (a = &ptr->mattk[0]; a < &ptr->mattk[NATTK]; a++) if (a->adtyp == dtyp && (atyp == AT_ANY || a->aatyp == atyp)) return a; return (struct attack *)0; } boolean dmgtype(ptr, dtyp) struct permonst *ptr; int dtyp; { return dmgtype_fromattack(ptr, dtyp, AT_ANY) ? TRUE : FALSE; } /* returns the maximum damage a defender can do to the attacker via * a passive defense */ int max_passive_dmg(mdef, magr) register struct monst *mdef, *magr; { int i, dmg = 0; uchar adtyp; for(i = 0; i < NATTK; i++) if(mdef->data->mattk[i].aatyp == AT_NONE || mdef->data->mattk[i].aatyp == AT_BOOM) { adtyp = mdef->data->mattk[i].adtyp; if ((adtyp == AD_ACID && !resists_acid(magr)) || (adtyp == AD_COLD && !resists_cold(magr)) || (adtyp == AD_FIRE && !resists_fire(magr)) || (adtyp == AD_ELEC && !resists_elec(magr)) || adtyp == AD_PHYS) { dmg = mdef->data->mattk[i].damn; if(!dmg) dmg = mdef->data->mlevel+1; dmg *= mdef->data->mattk[i].damd; } else dmg = 0; return dmg; } return 0; } #endif /* OVL1 */ #ifdef OVL0 int monsndx(ptr) /* return an index into the mons array */ struct permonst *ptr; { register int i; i = (int)(ptr - &mons[0]); if (i < LOW_PM || i >= NUMMONS) { /* ought to switch this to use `fmt_ptr' */ panic("monsndx - could not index monster (%lx)", (unsigned long)ptr); return NON_PM; /* will not get here */ } return(i); } #endif /* OVL0 */ #ifdef OVL1 int name_to_mon(in_str) const char *in_str; { /* Be careful. We must check the entire string in case it was * something such as "ettin zombie corpse". The calling routine * doesn't know about the "corpse" until the monster name has * already been taken off the front, so we have to be able to * read the name with extraneous stuff such as "corpse" stuck on * the end. * This causes a problem for names which prefix other names such * as "ettin" on "ettin zombie". In this case we want the _longest_ * name which exists. * This also permits plurals created by adding suffixes such as 's' * or 'es'. Other plurals must still be handled explicitly. */ register int i; register int mntmp = NON_PM; register char *s, *str, *term; char buf[BUFSZ]; int len, slen; str = strcpy(buf, in_str); if (!strncmp(str, "a ", 2)) str += 2; else if (!strncmp(str, "an ", 3)) str += 3; slen = strlen(str); term = str + slen; if ((s = strstri(str, "vortices")) != 0) Strcpy(s+4, "ex"); /* be careful with "ies"; "priest", "zombies" */ else if (slen > 3 && !strcmpi(term-3, "ies") && (slen < 7 || strcmpi(term-7, "zombies"))) Strcpy(term-3, "y"); /* luckily no monster names end in fe or ve with ves plurals */ else if (slen > 3 && !strcmpi(term-3, "ves")) Strcpy(term-3, "f"); slen = strlen(str); /* length possibly needs recomputing */ { static const struct alt_spl { const char* name; short pm_val; } names[] = { /* Alternate spellings */ { "grey dragon", PM_GRAY_DRAGON }, { "baby grey dragon", PM_BABY_GRAY_DRAGON }, { "grey unicorn", PM_GRAY_UNICORN }, { "grey ooze", PM_GRAY_OOZE }, { "gray-elf", PM_GREY_ELF }, /* Hyphenated names */ { "ki rin", PM_KI_RIN }, { "uruk hai", PM_URUK_HAI }, { "orc captain", PM_ORC_CAPTAIN }, { "woodland elf", PM_WOODLAND_ELF }, { "green elf", PM_GREEN_ELF }, { "grey elf", PM_GREY_ELF }, { "gray elf", PM_GREY_ELF }, { "elf lord", PM_ELF_LORD }, #if 0 /* OBSOLETE */ { "high elf", PM_HIGH_ELF }, #endif { "olog hai", PM_OLOG_HAI }, { "arch lich", PM_ARCH_LICH }, /* Some irregular plurals */ { "incubi", PM_INCUBUS }, { "succubi", PM_SUCCUBUS }, { "violet fungi", PM_VIOLET_FUNGUS }, { "homunculi", PM_HOMUNCULUS }, { "baluchitheria", PM_BALUCHITHERIUM }, { "lurkers above", PM_LURKER_ABOVE }, { "cavemen", PM_CAVEMAN }, { "cavewomen", PM_CAVEWOMAN }, { "djinn", PM_DJINNI }, { "mumakil", PM_MUMAK }, { "erinyes", PM_ERINYS }, /* falsely caught by -ves check above */ { "master of thief", PM_MASTER_OF_THIEVES }, /* end of list */ { 0, 0 } }; register const struct alt_spl *namep; for (namep = names; namep->name; namep++) if (!strncmpi(str, namep->name, (int)strlen(namep->name))) return namep->pm_val; } for (len = 0, i = LOW_PM; i < NUMMONS; i++) { register int m_i_len = strlen(mons[i].mname); if (m_i_len > len && !strncmpi(mons[i].mname, str, m_i_len)) { if (m_i_len == slen) return i; /* exact match */ else if (slen > m_i_len && (str[m_i_len] == ' ' || !strcmpi(&str[m_i_len], "s") || !strncmpi(&str[m_i_len], "s ", 2) || !strcmpi(&str[m_i_len], "'") || !strncmpi(&str[m_i_len], "' ", 2) || !strcmpi(&str[m_i_len], "'s") || !strncmpi(&str[m_i_len], "'s ", 3) || !strcmpi(&str[m_i_len], "es") || !strncmpi(&str[m_i_len], "es ", 3))) { mntmp = i; len = m_i_len; } } } if (mntmp == NON_PM) mntmp = title_to_mon(str, (int *)0, (int *)0); return mntmp; } #endif /* OVL1 */ #ifdef OVL2 /* returns 3 values (0=male, 1=female, 2=none) */ int gender(mtmp) register struct monst *mtmp; { if (is_neuter(mtmp->data)) return 2; return mtmp->female; } /* Like gender(), but lower animals and such are still "it". */ /* This is the one we want to use when printing messages. */ int pronoun_gender(mtmp) register struct monst *mtmp; { if (is_neuter(mtmp->data) || !canspotmon(mtmp)) return 2; return (humanoid(mtmp->data) || (mtmp->data->geno & G_UNIQ) || type_is_pname(mtmp->data)) ? (int)mtmp->female : 2; } #endif /* OVL2 */ #ifdef OVLB /* used for nearby monsters when you go to another level */ boolean levl_follower(mtmp) struct monst *mtmp; { /* monsters with the Amulet--even pets--won't follow across levels */ if (mon_has_amulet(mtmp)) return FALSE; /* some monsters will follow even while intending to flee from you */ if (mtmp->mtame || mtmp->iswiz || is_fshk(mtmp)) return TRUE; /* stalking types follow, but won't when fleeing unless you hold the Amulet */ return (boolean)((mtmp->data->mflags2 & M2_STALK) && (!mtmp->mflee || u.uhave.amulet)); } static const short grownups[][2] = { {PM_CHICKATRICE, PM_COCKATRICE}, {PM_LITTLE_DOG, PM_DOG}, {PM_DOG, PM_LARGE_DOG}, {PM_HELL_HOUND_PUP, PM_HELL_HOUND}, {PM_WINTER_WOLF_CUB, PM_WINTER_WOLF}, {PM_KITTEN, PM_HOUSECAT}, {PM_HOUSECAT, PM_LARGE_CAT}, {PM_PONY, PM_HORSE}, {PM_HORSE, PM_WARHORSE}, {PM_KOBOLD, PM_LARGE_KOBOLD}, {PM_LARGE_KOBOLD, PM_KOBOLD_LORD}, {PM_GNOME, PM_GNOME_LORD}, {PM_GNOME_LORD, PM_GNOME_KING}, {PM_DWARF, PM_DWARF_LORD}, {PM_DWARF_LORD, PM_DWARF_KING}, {PM_MIND_FLAYER, PM_MASTER_MIND_FLAYER}, {PM_ORC, PM_ORC_CAPTAIN}, {PM_HILL_ORC, PM_ORC_CAPTAIN}, {PM_MORDOR_ORC, PM_ORC_CAPTAIN}, {PM_URUK_HAI, PM_ORC_CAPTAIN}, {PM_SEWER_RAT, PM_GIANT_RAT}, {PM_CAVE_SPIDER, PM_GIANT_SPIDER}, {PM_OGRE, PM_OGRE_LORD}, {PM_OGRE_LORD, PM_OGRE_KING}, {PM_ELF, PM_ELF_LORD}, {PM_WOODLAND_ELF, PM_ELF_LORD}, {PM_GREEN_ELF, PM_ELF_LORD}, {PM_GREY_ELF, PM_ELF_LORD}, {PM_ELF_LORD, PM_ELVENKING}, {PM_LICH, PM_DEMILICH}, {PM_DEMILICH, PM_MASTER_LICH}, {PM_MASTER_LICH, PM_ARCH_LICH}, {PM_VAMPIRE, PM_VAMPIRE_LORD}, {PM_BAT, PM_GIANT_BAT}, {PM_BABY_GRAY_DRAGON, PM_GRAY_DRAGON}, {PM_BABY_SILVER_DRAGON, PM_SILVER_DRAGON}, #if 0 /* DEFERRED */ {PM_BABY_SHIMMERING_DRAGON, PM_SHIMMERING_DRAGON}, #endif {PM_BABY_RED_DRAGON, PM_RED_DRAGON}, {PM_BABY_WHITE_DRAGON, PM_WHITE_DRAGON}, {PM_BABY_ORANGE_DRAGON, PM_ORANGE_DRAGON}, {PM_BABY_BLACK_DRAGON, PM_BLACK_DRAGON}, {PM_BABY_BLUE_DRAGON, PM_BLUE_DRAGON}, {PM_BABY_GREEN_DRAGON, PM_GREEN_DRAGON}, {PM_BABY_YELLOW_DRAGON, PM_YELLOW_DRAGON}, {PM_RED_NAGA_HATCHLING, PM_RED_NAGA}, {PM_BLACK_NAGA_HATCHLING, PM_BLACK_NAGA}, {PM_GOLDEN_NAGA_HATCHLING, PM_GOLDEN_NAGA}, {PM_GUARDIAN_NAGA_HATCHLING, PM_GUARDIAN_NAGA}, {PM_SMALL_MIMIC, PM_LARGE_MIMIC}, {PM_LARGE_MIMIC, PM_GIANT_MIMIC}, {PM_BABY_LONG_WORM, PM_LONG_WORM}, {PM_BABY_PURPLE_WORM, PM_PURPLE_WORM}, {PM_BABY_CROCODILE, PM_CROCODILE}, {PM_SOLDIER, PM_SERGEANT}, {PM_SERGEANT, PM_LIEUTENANT}, {PM_LIEUTENANT, PM_CAPTAIN}, {PM_WATCHMAN, PM_WATCH_CAPTAIN}, {PM_ALIGNED_PRIEST, PM_HIGH_PRIEST}, {PM_STUDENT, PM_ARCHEOLOGIST}, {PM_ATTENDANT, PM_HEALER}, {PM_PAGE, PM_KNIGHT}, {PM_ACOLYTE, PM_PRIEST}, {PM_APPRENTICE, PM_WIZARD}, {PM_MANES,PM_LEMURE}, #ifdef KOPS {PM_KEYSTONE_KOP, PM_KOP_SERGEANT}, {PM_KOP_SERGEANT, PM_KOP_LIEUTENANT}, {PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN}, #endif {NON_PM,NON_PM} }; int little_to_big(montype) int montype; { #ifndef AIXPS2_BUG register int i; for (i = 0; grownups[i][0] >= LOW_PM; i++) if(montype == grownups[i][0]) return grownups[i][1]; return montype; #else /* AIX PS/2 C-compiler 1.1.1 optimizer does not like the above for loop, * and causes segmentation faults at runtime. (The problem does not * occur if -O is not used.) * lehtonen@cs.Helsinki.FI (Tapio Lehtonen) 28031990 */ int i; int monvalue; monvalue = montype; for (i = 0; grownups[i][0] >= LOW_PM; i++) if(montype == grownups[i][0]) monvalue = grownups[i][1]; return monvalue; #endif } int big_to_little(montype) int montype; { register int i; for (i = 0; grownups[i][0] >= LOW_PM; i++) if(montype == grownups[i][1]) return grownups[i][0]; return montype; } /* * Return the permonst ptr for the race of the monster. * Returns correct pointer for non-polymorphed and polymorphed * player. It does not return a pointer to player role character. */ const struct permonst * raceptr(mtmp) struct monst *mtmp; { if (mtmp == &youmonst && !Upolyd) return(&mons[urace.malenum]); else return(mtmp->data); } static const char *levitate[4] = { "float", "Float", "wobble", "Wobble" }; static const char *flys[4] = { "fly", "Fly", "flutter", "Flutter" }; static const char *flyl[4] = { "fly", "Fly", "stagger", "Stagger" }; static const char *slither[4] = { "slither", "Slither", "falter", "Falter" }; static const char *ooze[4] = { "ooze", "Ooze", "tremble", "Tremble" }; static const char *immobile[4] = { "wiggle", "Wiggle", "pulsate", "Pulsate" }; static const char *crawl[4] = { "crawl", "Crawl", "falter", "Falter" }; const char * locomotion(ptr, def) const struct permonst *ptr; const char *def; { int capitalize = (*def == highc(*def)); return ( is_floater(ptr) ? levitate[capitalize] : (is_flyer(ptr) && ptr->msize <= MZ_SMALL) ? flys[capitalize] : (is_flyer(ptr) && ptr->msize > MZ_SMALL) ? flyl[capitalize] : slithy(ptr) ? slither[capitalize] : amorphous(ptr) ? ooze[capitalize] : !ptr->mmove ? immobile[capitalize] : nolimbs(ptr) ? crawl[capitalize] : def ); } const char * stagger(ptr, def) const struct permonst *ptr; const char *def; { int capitalize = 2 + (*def == highc(*def)); return ( is_floater(ptr) ? levitate[capitalize] : (is_flyer(ptr) && ptr->msize <= MZ_SMALL) ? flys[capitalize] : (is_flyer(ptr) && ptr->msize > MZ_SMALL) ? flyl[capitalize] : slithy(ptr) ? slither[capitalize] : amorphous(ptr) ? ooze[capitalize] : !ptr->mmove ? immobile[capitalize] : nolimbs(ptr) ? crawl[capitalize] : def ); } /* return a phrase describing the effect of fire attack on a type of monster */ const char * on_fire(mptr, mattk) struct permonst *mptr; struct attack *mattk; { const char *what; switch (monsndx(mptr)) { case PM_FLAMING_SPHERE: case PM_FIRE_VORTEX: case PM_FIRE_ELEMENTAL: case PM_SALAMANDER: what = "already on fire"; break; case PM_WATER_ELEMENTAL: case PM_FOG_CLOUD: case PM_STEAM_VORTEX: what = "boiling"; break; case PM_ICE_VORTEX: case PM_GLASS_GOLEM: what = "melting"; break; case PM_STONE_GOLEM: case PM_CLAY_GOLEM: case PM_GOLD_GOLEM: case PM_AIR_ELEMENTAL: case PM_EARTH_ELEMENTAL: case PM_DUST_VORTEX: case PM_ENERGY_VORTEX: what = "heating up"; break; default: what = (mattk->aatyp == AT_HUGS) ? "being roasted" : "on fire"; break; } return what; } #endif /* OVLB */ /*mondata.c*/ nethack-3.4.3/src/monmove.c0100644000000000000000000012045507764735041014274 0ustar rootroot/* SCCS Id: @(#)monmove.c 3.4 2002/04/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mfndpos.h" #include "artifact.h" #include "epri.h" extern boolean notonhead; #ifdef OVL0 STATIC_DCL int FDECL(disturb,(struct monst *)); STATIC_DCL void FDECL(distfleeck,(struct monst *,int *,int *,int *)); STATIC_DCL int FDECL(m_arrival, (struct monst *)); STATIC_DCL void FDECL(watch_on_duty,(struct monst *)); #endif /* OVL0 */ #ifdef OVLB boolean /* TRUE : mtmp died */ mb_trapped(mtmp) register struct monst *mtmp; { if (flags.verbose) { if (cansee(mtmp->mx, mtmp->my)) pline("KABOOM!! You see a door explode."); else if (flags.soundok) You_hear("a distant explosion."); } wake_nearto(mtmp->mx, mtmp->my, 7*7); mtmp->mstun = 1; mtmp->mhp -= rnd(15); if(mtmp->mhp <= 0) { mondied(mtmp); if (mtmp->mhp > 0) /* lifesaved */ return(FALSE); else return(TRUE); } return(FALSE); } #endif /* OVLB */ #ifdef OVL0 STATIC_OVL void watch_on_duty(mtmp) register struct monst *mtmp; { int x, y; if(mtmp->mpeaceful && in_town(u.ux+u.dx, u.uy+u.dy) && mtmp->mcansee && m_canseeu(mtmp) && !rn2(3)) { if(picking_lock(&x, &y) && IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & D_LOCKED)) { if(couldsee(mtmp->mx, mtmp->my)) { pline("%s yells:", Amonnam(mtmp)); if(levl[x][y].looted & D_WARNED) { verbalize("Halt, thief! You're under arrest!"); (void) angry_guards(!(flags.soundok)); } else { verbalize("Hey, stop picking that lock!"); levl[x][y].looted |= D_WARNED; } stop_occupation(); } } else if (is_digging()) { /* chewing, wand/spell of digging are checked elsewhere */ watch_dig(mtmp, digging.pos.x, digging.pos.y, FALSE); } } } #endif /* OVL0 */ #ifdef OVL1 int dochugw(mtmp) register struct monst *mtmp; { register int x = mtmp->mx, y = mtmp->my; boolean already_saw_mon = !occupation ? 0 : canspotmon(mtmp); int rd = dochug(mtmp); #if 0 /* part of the original warning code which was replaced in 3.3.1 */ int dd; if(Warning && !rd && !mtmp->mpeaceful && (dd = distu(mtmp->mx,mtmp->my)) < distu(x,y) && dd < 100 && !canseemon(mtmp)) { /* Note: this assumes we only want to warn against the monster to * which the weapon does extra damage, as there is no "monster * which the weapon warns against" field. */ if (spec_ability(uwep, SPFX_WARN) && spec_dbon(uwep, mtmp, 1)) warnlevel = 100; else if ((int) (mtmp->m_lev / 4) > warnlevel) warnlevel = (mtmp->m_lev / 4); } #endif /* 0 */ /* a similar check is in monster_nearby() in hack.c */ /* check whether hero notices monster and stops current activity */ if (occupation && !rd && !Confusion && (!mtmp->mpeaceful || Hallucination) && /* it's close enough to be a threat */ distu(mtmp->mx,mtmp->my) <= (BOLT_LIM+1)*(BOLT_LIM+1) && /* and either couldn't see it before, or it was too far away */ (!already_saw_mon || !couldsee(x,y) || distu(x,y) > (BOLT_LIM+1)*(BOLT_LIM+1)) && /* can see it now, or sense it and would normally see it */ (canseemon(mtmp) || (sensemon(mtmp) && couldsee(mtmp->mx,mtmp->my))) && mtmp->mcanmove && !noattacks(mtmp->data) && !onscary(u.ux, u.uy, mtmp)) stop_occupation(); return(rd); } #endif /* OVL1 */ #ifdef OVL2 boolean onscary(x, y, mtmp) int x, y; struct monst *mtmp; { if (mtmp->isshk || mtmp->isgd || mtmp->iswiz || !mtmp->mcansee || mtmp->mpeaceful || mtmp->data->mlet == S_HUMAN || is_lminion(mtmp) || mtmp->data == &mons[PM_ANGEL] || is_rider(mtmp->data) || mtmp->data == &mons[PM_MINOTAUR]) return(FALSE); return (boolean)(sobj_at(SCR_SCARE_MONSTER, x, y) #ifdef ELBERETH || sengr_at("Elbereth", x, y) #endif || (mtmp->data->mlet == S_VAMPIRE && IS_ALTAR(levl[x][y].typ))); } #endif /* OVL2 */ #ifdef OVL0 /* regenerate lost hit points */ void mon_regen(mon, digest_meal) struct monst *mon; boolean digest_meal; { if (mon->mhp < mon->mhpmax && (moves % 20 == 0 || regenerates(mon->data))) mon->mhp++; if (mon->mspec_used) mon->mspec_used--; if (digest_meal) { if (mon->meating) mon->meating--; } } /* * Possibly awaken the given monster. Return a 1 if the monster has been * jolted awake. */ STATIC_OVL int disturb(mtmp) register struct monst *mtmp; { /* * + Ettins are hard to surprise. * + Nymphs, jabberwocks, and leprechauns do not easily wake up. * * Wake up if: * in direct LOS AND * within 10 squares AND * not stealthy or (mon is an ettin and 9/10) AND * (mon is not a nymph, jabberwock, or leprechaun) or 1/50 AND * Aggravate or mon is (dog or human) or * (1/7 and mon is not mimicing furniture or object) */ if(couldsee(mtmp->mx,mtmp->my) && distu(mtmp->mx,mtmp->my) <= 100 && (!Stealth || (mtmp->data == &mons[PM_ETTIN] && rn2(10))) && (!(mtmp->data->mlet == S_NYMPH || mtmp->data == &mons[PM_JABBERWOCK] #if 0 /* DEFERRED */ || mtmp->data == &mons[PM_VORPAL_JABBERWOCK] #endif || mtmp->data->mlet == S_LEPRECHAUN) || !rn2(50)) && (Aggravate_monster || (mtmp->data->mlet == S_DOG || mtmp->data->mlet == S_HUMAN) || (!rn2(7) && mtmp->m_ap_type != M_AP_FURNITURE && mtmp->m_ap_type != M_AP_OBJECT) )) { mtmp->msleeping = 0; return(1); } return(0); } /* monster begins fleeing for the specified time, 0 means untimed flee * if first, only adds fleetime if monster isn't already fleeing * if fleemsg, prints a message about new flight, otherwise, caller should */ void monflee(mtmp, fleetime, first, fleemsg) struct monst *mtmp; int fleetime; boolean first; boolean fleemsg; { if (u.ustuck == mtmp) { if (u.uswallow) expels(mtmp, mtmp->data, TRUE); else if (!sticks(youmonst.data)) { unstuck(mtmp); /* monster lets go when fleeing */ You("get released!"); } } if (!first || !mtmp->mflee) { /* don't lose untimed scare */ if (!fleetime) mtmp->mfleetim = 0; else if (!mtmp->mflee || mtmp->mfleetim) { fleetime += mtmp->mfleetim; /* ensure monster flees long enough to visibly stop fighting */ if (fleetime == 1) fleetime++; mtmp->mfleetim = min(fleetime, 127); } if (!mtmp->mflee && fleemsg && canseemon(mtmp) && !mtmp->mfrozen) pline("%s turns to flee!", (Monnam(mtmp))); mtmp->mflee = 1; } } STATIC_OVL void distfleeck(mtmp,inrange,nearby,scared) register struct monst *mtmp; int *inrange, *nearby, *scared; { int seescaryx, seescaryy; *inrange = (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= (BOLT_LIM * BOLT_LIM)); *nearby = *inrange && monnear(mtmp, mtmp->mux, mtmp->muy); /* Note: if your image is displaced, the monster sees the Elbereth * at your displaced position, thus never attacking your displaced * position, but possibly attacking you by accident. If you are * invisible, it sees the Elbereth at your real position, thus never * running into you by accident but possibly attacking the spot * where it guesses you are. */ if (!mtmp->mcansee || (Invis && !perceives(mtmp->data))) { seescaryx = mtmp->mux; seescaryy = mtmp->muy; } else { seescaryx = u.ux; seescaryy = u.uy; } *scared = (*nearby && (onscary(seescaryx, seescaryy, mtmp) || (!mtmp->mpeaceful && in_your_sanctuary(mtmp, 0, 0)))); if(*scared) { if (rn2(7)) monflee(mtmp, rnd(10), TRUE, TRUE); else monflee(mtmp, rnd(100), TRUE, TRUE); } } /* perform a special one-time action for a monster; returns -1 if nothing special happened, 0 if monster uses up its turn, 1 if monster is killed */ STATIC_OVL int m_arrival(mon) struct monst *mon; { mon->mstrategy &= ~STRAT_ARRIVE; /* always reset */ return -1; } /* returns 1 if monster died moving, 0 otherwise */ /* The whole dochugw/m_move/distfleeck/mfndpos section is serious spaghetti * code. --KAA */ int dochug(mtmp) register struct monst *mtmp; { register struct permonst *mdat; register int tmp=0; int inrange, nearby, scared; #ifdef GOLDOBJ struct obj *ygold = 0, *lepgold = 0; #endif /* Pre-movement adjustments */ mdat = mtmp->data; if (mtmp->mstrategy & STRAT_ARRIVE) { int res = m_arrival(mtmp); if (res >= 0) return res; } /* check for waitmask status change */ if ((mtmp->mstrategy & STRAT_WAITFORU) && (m_canseeu(mtmp) || mtmp->mhp < mtmp->mhpmax)) mtmp->mstrategy &= ~STRAT_WAITFORU; /* update quest status flags */ quest_stat_check(mtmp); if (!mtmp->mcanmove || (mtmp->mstrategy & STRAT_WAITMASK)) { if (Hallucination) newsym(mtmp->mx,mtmp->my); if (mtmp->mcanmove && (mtmp->mstrategy & STRAT_CLOSE) && !mtmp->msleeping && monnear(mtmp, u.ux, u.uy)) quest_talk(mtmp); /* give the leaders a chance to speak */ return(0); /* other frozen monsters can't do anything */ } /* there is a chance we will wake it */ if (mtmp->msleeping && !disturb(mtmp)) { if (Hallucination) newsym(mtmp->mx,mtmp->my); return(0); } /* not frozen or sleeping: wipe out texts written in the dust */ wipe_engr_at(mtmp->mx, mtmp->my, 1); /* confused monsters get unconfused with small probability */ if (mtmp->mconf && !rn2(50)) mtmp->mconf = 0; /* stunned monsters get un-stunned with larger probability */ if (mtmp->mstun && !rn2(10)) mtmp->mstun = 0; /* some monsters teleport */ if (mtmp->mflee && !rn2(40) && can_teleport(mdat) && !mtmp->iswiz && !level.flags.noteleport) { (void) rloc(mtmp, FALSE); return(0); } if (mdat->msound == MS_SHRIEK && !um_dist(mtmp->mx, mtmp->my, 1)) m_respond(mtmp); if (mdat == &mons[PM_MEDUSA] && couldsee(mtmp->mx, mtmp->my)) m_respond(mtmp); if (mtmp->mhp <= 0) return(1); /* m_respond gaze can kill medusa */ /* fleeing monsters might regain courage */ if (mtmp->mflee && !mtmp->mfleetim && mtmp->mhp == mtmp->mhpmax && !rn2(25)) mtmp->mflee = 0; set_apparxy(mtmp); /* Must be done after you move and before the monster does. The * set_apparxy() call in m_move() doesn't suffice since the variables * inrange, etc. all depend on stuff set by set_apparxy(). */ /* Monsters that want to acquire things */ /* may teleport, so do it before inrange is set */ if(is_covetous(mdat)) (void) tactics(mtmp); /* check distance and scariness of attacks */ distfleeck(mtmp,&inrange,&nearby,&scared); if(find_defensive(mtmp)) { if (use_defensive(mtmp) != 0) return 1; } else if(find_misc(mtmp)) { if (use_misc(mtmp) != 0) return 1; } /* Demonic Blackmail! */ if(nearby && mdat->msound == MS_BRIBE && mtmp->mpeaceful && !mtmp->mtame && !u.uswallow) { if (mtmp->mux != u.ux || mtmp->muy != u.uy) { pline("%s whispers at thin air.", cansee(mtmp->mux, mtmp->muy) ? Monnam(mtmp) : "It"); if (is_demon(youmonst.data)) { /* "Good hunting, brother" */ if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); } else { mtmp->minvis = mtmp->perminvis = 0; /* Why? For the same reason in real demon talk */ pline("%s gets angry!", Amonnam(mtmp)); mtmp->mpeaceful = 0; /* since no way is an image going to pay it off */ } } else if(demon_talk(mtmp)) return(1); /* you paid it off */ } /* the watch will look around and see if you are up to no good :-) */ if (mdat == &mons[PM_WATCHMAN] || mdat == &mons[PM_WATCH_CAPTAIN]) watch_on_duty(mtmp); else if (is_mind_flayer(mdat) && !rn2(20)) { struct monst *m2, *nmon = (struct monst *)0; if (canseemon(mtmp)) pline("%s concentrates.", Monnam(mtmp)); if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM) { You("sense a faint wave of psychic energy."); goto toofar; } pline("A wave of psychic energy pours over you!"); if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0))) pline("It feels quite soothing."); else { register boolean m_sen = sensemon(mtmp); if (m_sen || (Blind_telepat && rn2(2)) || !rn2(10)) { int dmg; pline("It locks on to your %s!", m_sen ? "telepathy" : Blind_telepat ? "latent telepathy" : "mind"); dmg = rnd(15); if (Half_spell_damage) dmg = (dmg+1) / 2; losehp(dmg, "psychic blast", KILLED_BY_AN); } } for(m2=fmon; m2; m2 = nmon) { nmon = m2->nmon; if (DEADMONSTER(m2)) continue; if (m2->mpeaceful == mtmp->mpeaceful) continue; if (mindless(m2->data)) continue; if (m2 == mtmp) continue; if ((telepathic(m2->data) && (rn2(2) || m2->mblinded)) || !rn2(10)) { if (cansee(m2->mx, m2->my)) pline("It locks on to %s.", mon_nam(m2)); m2->mhp -= rnd(15); if (m2->mhp <= 0) monkilled(m2, "", AD_DRIN); else m2->msleeping = 0; } } } toofar: /* If monster is nearby you, and has to wield a weapon, do so. This * costs the monster a move, of course. */ if((!mtmp->mpeaceful || Conflict) && inrange && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8 && attacktype(mdat, AT_WEAP)) { struct obj *mw_tmp; /* The scared check is necessary. Otherwise a monster that is * one square near the player but fleeing into a wall would keep * switching between pick-axe and weapon. If monster is stuck * in a trap, prefer ranged weapon (wielding is done in thrwmu). * This may cost the monster an attack, but keeps the monster * from switching back and forth if carrying both. */ mw_tmp = MON_WEP(mtmp); if (!(scared && mw_tmp && is_pick(mw_tmp)) && mtmp->weapon_check == NEED_WEAPON && !(mtmp->mtrapped && !nearby && select_rwep(mtmp))) { mtmp->weapon_check = NEED_HTH_WEAPON; if (mon_wield_item(mtmp) != 0) return(0); } } /* Now the actual movement phase */ #ifndef GOLDOBJ if(!nearby || mtmp->mflee || scared || mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) || (mdat->mlet == S_LEPRECHAUN && !u.ugold && (mtmp->mgold || rn2(2))) || #else if (mdat->mlet == S_LEPRECHAUN) { ygold = findgold(invent); lepgold = findgold(mtmp->minvent); } if(!nearby || mtmp->mflee || scared || mtmp->mconf || mtmp->mstun || (mtmp->minvis && !rn2(3)) || (mdat->mlet == S_LEPRECHAUN && !ygold && (lepgold || rn2(2))) || #endif (is_wanderer(mdat) && !rn2(4)) || (Conflict && !mtmp->iswiz) || (!mtmp->mcansee && !rn2(4)) || mtmp->mpeaceful) { /* Possibly cast an undirected spell if not attacking you */ /* note that most of the time castmu() will pick a directed spell and do nothing, so the monster moves normally */ /* arbitrary distance restriction to keep monster far away from you from having cast dozens of sticks-to-snakes or similar spells by the time you reach it */ if (dist2(mtmp->mx, mtmp->my, u.ux, u.uy) <= 49 && !mtmp->mspec_used) { struct attack *a; for (a = &mdat->mattk[0]; a < &mdat->mattk[NATTK]; a++) { if (a->aatyp == AT_MAGC && (a->adtyp == AD_SPEL || a->adtyp == AD_CLRC)) { if (castmu(mtmp, a, FALSE, FALSE)) { tmp = 3; break; } } } } tmp = m_move(mtmp, 0); distfleeck(mtmp,&inrange,&nearby,&scared); /* recalc */ switch (tmp) { case 0: /* no movement, but it can still attack you */ case 3: /* absolutely no movement */ /* for pets, case 0 and 3 are equivalent */ /* vault guard might have vanished */ if (mtmp->isgd && (mtmp->mhp < 1 || (mtmp->mx == 0 && mtmp->my == 0))) return 1; /* behave as if it died */ /* During hallucination, monster appearance should * still change - even if it doesn't move. */ if(Hallucination) newsym(mtmp->mx,mtmp->my); break; case 1: /* monster moved */ /* Maybe it stepped on a trap and fell asleep... */ if (mtmp->msleeping || !mtmp->mcanmove) return(0); if(!nearby && (ranged_attk(mdat) || find_offensive(mtmp))) break; else if(u.uswallow && mtmp == u.ustuck) { /* a monster that's digesting you can move at the * same time -dlc */ return(mattacku(mtmp)); } else return(0); /*NOTREACHED*/ break; case 2: /* monster died */ return(1); } } /* Now, attack the player if possible - one attack set per monst */ if (!mtmp->mpeaceful || (Conflict && !resist(mtmp, RING_CLASS, 0, 0))) { if(inrange && !noattacks(mdat) && u.uhp > 0 && !scared && tmp != 3) if(mattacku(mtmp)) return(1); /* monster died (e.g. exploded) */ if(mtmp->wormno) wormhitu(mtmp); } /* special speeches for quest monsters */ if (!mtmp->msleeping && mtmp->mcanmove && nearby) quest_talk(mtmp); /* extra emotional attack for vile monsters */ if (inrange && mtmp->data->msound == MS_CUSS && !mtmp->mpeaceful && couldsee(mtmp->mx, mtmp->my) && !mtmp->minvis && !rn2(5)) cuss(mtmp); return(tmp == 2); } static NEARDATA const char practical[] = { WEAPON_CLASS, ARMOR_CLASS, GEM_CLASS, FOOD_CLASS, 0 }; static NEARDATA const char magical[] = { AMULET_CLASS, POTION_CLASS, SCROLL_CLASS, WAND_CLASS, RING_CLASS, SPBOOK_CLASS, 0 }; static NEARDATA const char indigestion[] = { BALL_CLASS, ROCK_CLASS, 0 }; static NEARDATA const char boulder_class[] = { ROCK_CLASS, 0 }; static NEARDATA const char gem_class[] = { GEM_CLASS, 0 }; boolean itsstuck(mtmp) register struct monst *mtmp; { if (sticks(youmonst.data) && mtmp==u.ustuck && !u.uswallow) { pline("%s cannot escape from you!", Monnam(mtmp)); return(TRUE); } return(FALSE); } /* Return values: * 0: did not move, but can still attack and do other stuff. * 1: moved, possibly can attack. * 2: monster died. * 3: did not move, and can't do anything else either. */ int m_move(mtmp, after) register struct monst *mtmp; register int after; { register int appr; xchar gx,gy,nix,niy,chcnt; int chi; /* could be schar except for stupid Sun-2 compiler */ boolean likegold=0, likegems=0, likeobjs=0, likemagic=0, conceals=0; boolean likerock=0, can_tunnel=0; boolean can_open=0, can_unlock=0, doorbuster=0; boolean uses_items=0, setlikes=0; boolean avoid=FALSE; struct permonst *ptr; struct monst *mtoo; schar mmoved = 0; /* not strictly nec.: chi >= 0 will do */ long info[9]; long flag; int omx = mtmp->mx, omy = mtmp->my; struct obj *mw_tmp; if(mtmp->mtrapped) { int i = mintrap(mtmp); if(i >= 2) { newsym(mtmp->mx,mtmp->my); return(2); }/* it died */ if(i == 1) return(0); /* still in trap, so didn't move */ } ptr = mtmp->data; /* mintrap() can change mtmp->data -dlc */ if (mtmp->meating) { mtmp->meating--; return 3; /* still eating */ } if (hides_under(ptr) && OBJ_AT(mtmp->mx, mtmp->my) && rn2(10)) return 0; /* do not leave hiding place */ set_apparxy(mtmp); /* where does mtmp think you are? */ /* Not necessary if m_move called from this file, but necessary in * other calls of m_move (ex. leprechauns dodging) */ #ifdef REINCARNATION if (!Is_rogue_level(&u.uz)) #endif can_tunnel = tunnels(ptr); can_open = !(nohands(ptr) || verysmall(ptr)); can_unlock = ((can_open && m_carrying(mtmp, SKELETON_KEY)) || mtmp->iswiz || is_rider(ptr)); doorbuster = is_giant(ptr); if(mtmp->wormno) goto not_special; /* my dog gets special treatment */ if(mtmp->mtame) { mmoved = dog_move(mtmp, after); goto postmov; } /* likewise for shopkeeper */ if(mtmp->isshk) { mmoved = shk_move(mtmp); if(mmoved == -2) return(2); if(mmoved >= 0) goto postmov; mmoved = 0; /* follow player outside shop */ } /* and for the guard */ if(mtmp->isgd) { mmoved = gd_move(mtmp); if(mmoved == -2) return(2); if(mmoved >= 0) goto postmov; mmoved = 0; } /* and the acquisitive monsters get special treatment */ if(is_covetous(ptr)) { xchar tx = STRAT_GOALX(mtmp->mstrategy), ty = STRAT_GOALY(mtmp->mstrategy); struct monst *intruder = m_at(tx, ty); /* * if there's a monster on the object or in possesion of it, * attack it. */ if((dist2(mtmp->mx, mtmp->my, tx, ty) < 2) && intruder && (intruder != mtmp)) { notonhead = (intruder->mx != tx || intruder->my != ty); if(mattackm(mtmp, intruder) == 2) return(2); mmoved = 1; } else mmoved = 0; goto postmov; } /* and for the priest */ if(mtmp->ispriest) { mmoved = pri_move(mtmp); if(mmoved == -2) return(2); if(mmoved >= 0) goto postmov; mmoved = 0; } #ifdef MAIL if(ptr == &mons[PM_MAIL_DAEMON]) { if(flags.soundok && canseemon(mtmp)) verbalize("I'm late!"); mongone(mtmp); return(2); } #endif /* teleport if that lies in our nature */ if(ptr == &mons[PM_TENGU] && !rn2(5) && !mtmp->mcan && !tele_restrict(mtmp)) { if(mtmp->mhp < 7 || mtmp->mpeaceful || rn2(2)) (void) rloc(mtmp, FALSE); else mnexto(mtmp); mmoved = 1; goto postmov; } not_special: if(u.uswallow && !mtmp->mflee && u.ustuck != mtmp) return(1); omx = mtmp->mx; omy = mtmp->my; gx = mtmp->mux; gy = mtmp->muy; appr = mtmp->mflee ? -1 : 1; if (mtmp->mconf || (u.uswallow && mtmp == u.ustuck)) appr = 0; else { #ifdef GOLDOBJ struct obj *lepgold, *ygold; #endif boolean should_see = (couldsee(omx, omy) && (levl[gx][gy].lit || !levl[omx][omy].lit) && (dist2(omx, omy, gx, gy) <= 36)); if (!mtmp->mcansee || (should_see && Invis && !perceives(ptr) && rn2(11)) || (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == STRANGE_OBJECT) || u.uundetected || (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance == GOLD_PIECE && !likes_gold(ptr)) || (mtmp->mpeaceful && !mtmp->isshk) || /* allow shks to follow */ ((monsndx(ptr) == PM_STALKER || ptr->mlet == S_BAT || ptr->mlet == S_LIGHT) && !rn2(3))) appr = 0; if(monsndx(ptr) == PM_LEPRECHAUN && (appr == 1) && #ifndef GOLDOBJ (mtmp->mgold > u.ugold)) #else ( (lepgold = findgold(mtmp->minvent)) && (lepgold->quan > ((ygold = findgold(invent)) ? ygold->quan : 0L)) )) #endif appr = -1; if (!should_see && can_track(ptr)) { register coord *cp; cp = gettrack(omx,omy); if (cp) { gx = cp->x; gy = cp->y; } } } if ((!mtmp->mpeaceful || !rn2(10)) #ifdef REINCARNATION && (!Is_rogue_level(&u.uz)) #endif ) { boolean in_line = lined_up(mtmp) && (distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= (throws_rocks(youmonst.data) ? 20 : ACURRSTR/2+1) ); if (appr != 1 || !in_line) { /* Monsters in combat won't pick stuff up, avoiding the * situation where you toss arrows at it and it has nothing * better to do than pick the arrows up. */ register int pctload = (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp); /* look for gold or jewels nearby */ likegold = (likes_gold(ptr) && pctload < 95); likegems = (likes_gems(ptr) && pctload < 85); uses_items = (!mindless(ptr) && !is_animal(ptr) && pctload < 75); likeobjs = (likes_objs(ptr) && pctload < 75); likemagic = (likes_magic(ptr) && pctload < 85); likerock = (throws_rocks(ptr) && pctload < 50 && !In_sokoban(&u.uz)); conceals = hides_under(ptr); setlikes = TRUE; } } #define SQSRCHRADIUS 5 { register int minr = SQSRCHRADIUS; /* not too far away */ register struct obj *otmp; register int xx, yy; int oomx, oomy, lmx, lmy; /* cut down the search radius if it thinks character is closer. */ if(distmin(mtmp->mux, mtmp->muy, omx, omy) < SQSRCHRADIUS && !mtmp->mpeaceful) minr--; /* guards shouldn't get too distracted */ if(!mtmp->mpeaceful && is_mercenary(ptr)) minr = 1; if((likegold || likegems || likeobjs || likemagic || likerock || conceals) && (!*in_rooms(omx, omy, SHOPBASE) || (!rn2(25) && !mtmp->isshk))) { look_for_obj: oomx = min(COLNO-1, omx+minr); oomy = min(ROWNO-1, omy+minr); lmx = max(1, omx-minr); lmy = max(0, omy-minr); for(otmp = fobj; otmp; otmp = otmp->nobj) { /* monsters may pick rocks up, but won't go out of their way to grab them; this might hamper sling wielders, but it cuts down on move overhead by filtering out most common item */ if (otmp->otyp == ROCK) continue; xx = otmp->ox; yy = otmp->oy; /* Nymphs take everything. Most other creatures should not * pick up corpses except as a special case like in * searches_for_item(). We need to do this check in * mpickstuff() as well. */ if(xx >= lmx && xx <= oomx && yy >= lmy && yy <= oomy) { /* don't get stuck circling around an object that's underneath an immobile or hidden monster; paralysis victims excluded */ if ((mtoo = m_at(xx,yy)) != 0 && (mtoo->msleeping || mtoo->mundetected || (mtoo->mappearance && !mtoo->iswiz) || !mtoo->data->mmove)) continue; if(((likegold && otmp->oclass == COIN_CLASS) || (likeobjs && index(practical, otmp->oclass) && (otmp->otyp != CORPSE || (ptr->mlet == S_NYMPH && !is_rider(&mons[otmp->corpsenm])))) || (likemagic && index(magical, otmp->oclass)) || (uses_items && searches_for_item(mtmp, otmp)) || (likerock && otmp->otyp == BOULDER) || (likegems && otmp->oclass == GEM_CLASS && objects[otmp->otyp].oc_material != MINERAL) || (conceals && !cansee(otmp->ox,otmp->oy)) || (ptr == &mons[PM_GELATINOUS_CUBE] && !index(indigestion, otmp->oclass) && !(otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]))) ) && touch_artifact(otmp,mtmp)) { if(can_carry(mtmp,otmp) && (throws_rocks(ptr) || !sobj_at(BOULDER,xx,yy)) && (!is_unicorn(ptr) || objects[otmp->otyp].oc_material == GEMSTONE) && /* Don't get stuck circling an Elbereth */ !(onscary(xx, yy, mtmp))) { minr = distmin(omx,omy,xx,yy); oomx = min(COLNO-1, omx+minr); oomy = min(ROWNO-1, omy+minr); lmx = max(1, omx-minr); lmy = max(0, omy-minr); gx = otmp->ox; gy = otmp->oy; if (gx == omx && gy == omy) { mmoved = 3; /* actually unnecessary */ goto postmov; } } } } } } else if(likegold) { /* don't try to pick up anything else, but use the same loop */ uses_items = 0; likegems = likeobjs = likemagic = likerock = conceals = 0; goto look_for_obj; } if(minr < SQSRCHRADIUS && appr == -1) { if(distmin(omx,omy,mtmp->mux,mtmp->muy) <= 3) { gx = mtmp->mux; gy = mtmp->muy; } else appr = 1; } } /* don't tunnel if hostile and close enough to prefer a weapon */ if (can_tunnel && needspick(ptr) && ((!mtmp->mpeaceful || Conflict) && dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 8)) can_tunnel = FALSE; nix = omx; niy = omy; flag = 0L; if (mtmp->mpeaceful && (!Conflict || resist(mtmp, RING_CLASS, 0, 0))) flag |= (ALLOW_SANCT | ALLOW_SSM); else flag |= ALLOW_U; if (is_minion(ptr) || is_rider(ptr)) flag |= ALLOW_SANCT; /* unicorn may not be able to avoid hero on a noteleport level */ if (is_unicorn(ptr) && !level.flags.noteleport) flag |= NOTONL; if (passes_walls(ptr)) flag |= (ALLOW_WALL | ALLOW_ROCK); if (passes_bars(ptr)) flag |= ALLOW_BARS; if (can_tunnel) flag |= ALLOW_DIG; if (is_human(ptr) || ptr == &mons[PM_MINOTAUR]) flag |= ALLOW_SSM; if (is_undead(ptr) && ptr->mlet != S_GHOST) flag |= NOGARLIC; if (throws_rocks(ptr)) flag |= ALLOW_ROCK; if (can_open) flag |= OPENDOOR; if (can_unlock) flag |= UNLOCKDOOR; if (doorbuster) flag |= BUSTDOOR; { register int i, j, nx, ny, nearer; int jcnt, cnt; int ndist, nidist; register coord *mtrk; coord poss[9]; cnt = mfndpos(mtmp, poss, info, flag); chcnt = 0; jcnt = min(MTSZ, cnt-1); chi = -1; nidist = dist2(nix,niy,gx,gy); /* allow monsters be shortsighted on some levels for balance */ if(!mtmp->mpeaceful && level.flags.shortsighted && nidist > (couldsee(nix,niy) ? 144 : 36) && appr == 1) appr = 0; if (is_unicorn(ptr) && level.flags.noteleport) { /* on noteleport levels, perhaps we cannot avoid hero */ for(i = 0; i < cnt; i++) if(!(info[i] & NOTONL)) avoid=TRUE; } for(i=0; i < cnt; i++) { if (avoid && (info[i] & NOTONL)) continue; nx = poss[i].x; ny = poss[i].y; if (appr != 0) { mtrk = &mtmp->mtrack[0]; for(j=0; j < jcnt; mtrk++, j++) if(nx == mtrk->x && ny == mtrk->y) if(rn2(4*(cnt-j))) goto nxti; } nearer = ((ndist = dist2(nx,ny,gx,gy)) < nidist); if((appr == 1 && nearer) || (appr == -1 && !nearer) || (!appr && !rn2(++chcnt)) || !mmoved) { nix = nx; niy = ny; nidist = ndist; chi = i; mmoved = 1; } nxti: ; } } if(mmoved) { register int j; if (mmoved==1 && (u.ux != nix || u.uy != niy) && itsstuck(mtmp)) return(3); if (((IS_ROCK(levl[nix][niy].typ) && may_dig(nix,niy)) || closed_door(nix, niy)) && mmoved==1 && can_tunnel && needspick(ptr)) { if (closed_door(nix, niy)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_PICK_OR_AXE; } else if (IS_TREE(levl[nix][niy].typ)) { if (!(mw_tmp = MON_WEP(mtmp)) || !is_axe(mw_tmp)) mtmp->weapon_check = NEED_AXE; } else if (!(mw_tmp = MON_WEP(mtmp)) || !is_pick(mw_tmp)) { mtmp->weapon_check = NEED_PICK_AXE; } if (mtmp->weapon_check >= NEED_PICK_AXE && mon_wield_item(mtmp)) return(3); } /* If ALLOW_U is set, either it's trying to attack you, or it * thinks it is. In either case, attack this spot in preference to * all others. */ /* Actually, this whole section of code doesn't work as you'd expect. * Most attacks are handled in dochug(). It calls distfleeck(), which * among other things sets nearby if the monster is near you--and if * nearby is set, we never call m_move unless it is a special case * (confused, stun, etc.) The effect is that this ALLOW_U (and * mfndpos) has no effect for normal attacks, though it lets a confused * monster attack you by accident. */ if(info[chi] & ALLOW_U) { nix = mtmp->mux; niy = mtmp->muy; } if (nix == u.ux && niy == u.uy) { mtmp->mux = u.ux; mtmp->muy = u.uy; return(0); } /* The monster may attack another based on 1 of 2 conditions: * 1 - It may be confused. * 2 - It may mistake the monster for your (displaced) image. * Pets get taken care of above and shouldn't reach this code. * Conflict gets handled even farther away (movemon()). */ if((info[chi] & ALLOW_M) || (nix == mtmp->mux && niy == mtmp->muy)) { struct monst *mtmp2; int mstatus; mtmp2 = m_at(nix,niy); notonhead = mtmp2 && (nix != mtmp2->mx || niy != mtmp2->my); /* note: mstatus returns 0 if mtmp2 is nonexistent */ mstatus = mattackm(mtmp, mtmp2); if (mstatus & MM_AGR_DIED) /* aggressor died */ return 2; if ((mstatus & MM_HIT) && !(mstatus & MM_DEF_DIED) && rn2(4) && mtmp2->movement >= NORMAL_SPEED) { mtmp2->movement -= NORMAL_SPEED; notonhead = 0; mstatus = mattackm(mtmp2, mtmp); /* return attack */ if (mstatus & MM_DEF_DIED) return 2; } return 3; } if (!m_in_out_region(mtmp,nix,niy)) return 3; remove_monster(omx, omy); place_monster(mtmp, nix, niy); for(j = MTSZ-1; j > 0; j--) mtmp->mtrack[j] = mtmp->mtrack[j-1]; mtmp->mtrack[0].x = omx; mtmp->mtrack[0].y = omy; /* Place a segment at the old position. */ if (mtmp->wormno) worm_move(mtmp); } else { if(is_unicorn(ptr) && rn2(2) && !tele_restrict(mtmp)) { (void) rloc(mtmp, FALSE); return(1); } if(mtmp->wormno) worm_nomove(mtmp); } postmov: if(mmoved == 1 || mmoved == 3) { boolean canseeit = cansee(mtmp->mx, mtmp->my); if(mmoved == 1) { newsym(omx,omy); /* update the old position */ if (mintrap(mtmp) >= 2) { if(mtmp->mx) newsym(mtmp->mx,mtmp->my); return(2); /* it died */ } ptr = mtmp->data; /* open a door, or crash through it, if you can */ if(IS_DOOR(levl[mtmp->mx][mtmp->my].typ) && !passes_walls(ptr) /* doesn't need to open doors */ && !can_tunnel /* taken care of below */ ) { struct rm *here = &levl[mtmp->mx][mtmp->my]; boolean btrapped = (here->doormask & D_TRAPPED); if(here->doormask & (D_LOCKED|D_CLOSED) && amorphous(ptr)) { if (flags.verbose && canseemon(mtmp)) pline("%s %s under the door.", Monnam(mtmp), (ptr == &mons[PM_FOG_CLOUD] || ptr == &mons[PM_YELLOW_LIGHT]) ? "flows" : "oozes"); } else if(here->doormask & D_LOCKED && can_unlock) { if(btrapped) { here->doormask = D_NODOOR; newsym(mtmp->mx, mtmp->my); unblock_point(mtmp->mx,mtmp->my); /* vision */ if(mb_trapped(mtmp)) return(2); } else { if (flags.verbose) { if (canseeit) You("see a door unlock and open."); else if (flags.soundok) You_hear("a door unlock and open."); } here->doormask = D_ISOPEN; /* newsym(mtmp->mx, mtmp->my); */ unblock_point(mtmp->mx,mtmp->my); /* vision */ } } else if (here->doormask == D_CLOSED && can_open) { if(btrapped) { here->doormask = D_NODOOR; newsym(mtmp->mx, mtmp->my); unblock_point(mtmp->mx,mtmp->my); /* vision */ if(mb_trapped(mtmp)) return(2); } else { if (flags.verbose) { if (canseeit) You("see a door open."); else if (flags.soundok) You_hear("a door open."); } here->doormask = D_ISOPEN; /* newsym(mtmp->mx, mtmp->my); */ /* done below */ unblock_point(mtmp->mx,mtmp->my); /* vision */ } } else if (here->doormask & (D_LOCKED|D_CLOSED)) { /* mfndpos guarantees this must be a doorbuster */ if(btrapped) { here->doormask = D_NODOOR; newsym(mtmp->mx, mtmp->my); unblock_point(mtmp->mx,mtmp->my); /* vision */ if(mb_trapped(mtmp)) return(2); } else { if (flags.verbose) { if (canseeit) You("see a door crash open."); else if (flags.soundok) You_hear("a door crash open."); } if (here->doormask & D_LOCKED && !rn2(2)) here->doormask = D_NODOOR; else here->doormask = D_BROKEN; /* newsym(mtmp->mx, mtmp->my); */ /* done below */ unblock_point(mtmp->mx,mtmp->my); /* vision */ } /* if it's a shop door, schedule repair */ if (*in_rooms(mtmp->mx, mtmp->my, SHOPBASE)) add_damage(mtmp->mx, mtmp->my, 0L); } } else if (levl[mtmp->mx][mtmp->my].typ == IRONBARS) { if (flags.verbose && canseemon(mtmp)) Norep("%s %s %s the iron bars.", Monnam(mtmp), /* pluralization fakes verb conjugation */ makeplural(locomotion(ptr, "pass")), passes_walls(ptr) ? "through" : "between"); } /* possibly dig */ if (can_tunnel && mdig_tunnel(mtmp)) return(2); /* mon died (position already updated) */ /* set also in domove(), hack.c */ if (u.uswallow && mtmp == u.ustuck && (mtmp->mx != omx || mtmp->my != omy)) { /* If the monster moved, then update */ u.ux0 = u.ux; u.uy0 = u.uy; u.ux = mtmp->mx; u.uy = mtmp->my; swallowed(0); } else newsym(mtmp->mx,mtmp->my); } if(OBJ_AT(mtmp->mx, mtmp->my) && mtmp->mcanmove) { /* recompute the likes tests, in case we polymorphed * or if the "likegold" case got taken above */ if (setlikes) { register int pctload = (curr_mon_load(mtmp) * 100) / max_mon_load(mtmp); /* look for gold or jewels nearby */ likegold = (likes_gold(ptr) && pctload < 95); likegems = (likes_gems(ptr) && pctload < 85); uses_items = (!mindless(ptr) && !is_animal(ptr) && pctload < 75); likeobjs = (likes_objs(ptr) && pctload < 75); likemagic = (likes_magic(ptr) && pctload < 85); likerock = (throws_rocks(ptr) && pctload < 50 && !In_sokoban(&u.uz)); conceals = hides_under(ptr); } /* Maybe a rock mole just ate some metal object */ if (metallivorous(ptr)) { if (meatmetal(mtmp) == 2) return 2; /* it died */ } if(g_at(mtmp->mx,mtmp->my) && likegold) mpickgold(mtmp); /* Maybe a cube ate just about anything */ if (ptr == &mons[PM_GELATINOUS_CUBE]) { if (meatobj(mtmp) == 2) return 2; /* it died */ } if(!*in_rooms(mtmp->mx, mtmp->my, SHOPBASE) || !rn2(25)) { boolean picked = FALSE; if(likeobjs) picked |= mpickstuff(mtmp, practical); if(likemagic) picked |= mpickstuff(mtmp, magical); if(likerock) picked |= mpickstuff(mtmp, boulder_class); if(likegems) picked |= mpickstuff(mtmp, gem_class); if(uses_items) picked |= mpickstuff(mtmp, (char *)0); if(picked) mmoved = 3; } if(mtmp->minvis) { newsym(mtmp->mx, mtmp->my); if (mtmp->wormno) see_wsegs(mtmp); } } if(hides_under(ptr) || ptr->mlet == S_EEL) { /* Always set--or reset--mundetected if it's already hidden (just in case the object it was hiding under went away); usually set mundetected unless monster can't move. */ if (mtmp->mundetected || (mtmp->mcanmove && !mtmp->msleeping && rn2(5))) mtmp->mundetected = (ptr->mlet != S_EEL) ? OBJ_AT(mtmp->mx, mtmp->my) : (is_pool(mtmp->mx, mtmp->my) && !Is_waterlevel(&u.uz)); newsym(mtmp->mx, mtmp->my); } if (mtmp->isshk) { after_shk_move(mtmp); } } return(mmoved); } #endif /* OVL0 */ #ifdef OVL2 boolean closed_door(x, y) register int x, y; { return((boolean)(IS_DOOR(levl[x][y].typ) && (levl[x][y].doormask & (D_LOCKED | D_CLOSED)))); } boolean accessible(x, y) register int x, y; { return((boolean)(ACCESSIBLE(levl[x][y].typ) && !closed_door(x, y))); } #endif /* OVL2 */ #ifdef OVL0 /* decide where the monster thinks you are standing */ void set_apparxy(mtmp) register struct monst *mtmp; { boolean notseen, gotu; register int disp, mx = mtmp->mux, my = mtmp->muy; #ifdef GOLDOBJ long umoney = money_cnt(invent); #endif /* * do cheapest and/or most likely tests first */ /* pet knows your smell; grabber still has hold of you */ if (mtmp->mtame || mtmp == u.ustuck) goto found_you; /* monsters which know where you are don't suddenly forget, if you haven't moved away */ if (mx == u.ux && my == u.uy) goto found_you; notseen = (!mtmp->mcansee || (Invis && !perceives(mtmp->data))); /* add cases as required. eg. Displacement ... */ if (notseen || Underwater) { /* Xorns can smell valuable metal like gold, treat as seen */ if ((mtmp->data == &mons[PM_XORN]) && #ifndef GOLDOBJ u.ugold #else umoney #endif && !Underwater) disp = 0; else disp = 1; } else if (Displaced) { disp = couldsee(mx, my) ? 2 : 1; } else disp = 0; if (!disp) goto found_you; /* without something like the following, invis. and displ. are too powerful */ gotu = notseen ? !rn2(3) : Displaced ? !rn2(4) : FALSE; #if 0 /* this never worked as intended & isn't needed anyway */ /* If invis but not displaced, staying around gets you 'discovered' */ gotu |= (!Displaced && u.dx == 0 && u.dy == 0); #endif if (!gotu) { register int try_cnt = 0; do { if (++try_cnt > 200) goto found_you; /* punt */ mx = u.ux - disp + rn2(2*disp+1); my = u.uy - disp + rn2(2*disp+1); } while (!isok(mx,my) || (disp != 2 && mx == mtmp->mx && my == mtmp->my) || ((mx != u.ux || my != u.uy) && !passes_walls(mtmp->data) && (!ACCESSIBLE(levl[mx][my].typ) || (closed_door(mx, my) && !can_ooze(mtmp)))) || !couldsee(mx, my)); } else { found_you: mx = u.ux; my = u.uy; } mtmp->mux = mx; mtmp->muy = my; } boolean can_ooze(mtmp) struct monst *mtmp; { struct obj *chain, *obj; if (!amorphous(mtmp->data)) return FALSE; if (mtmp == &youmonst) { #ifndef GOLDOBJ if (u.ugold > 100L) return FALSE; #endif chain = invent; } else { #ifndef GOLDOBJ if (mtmp->mgold > 100L) return FALSE; #endif chain = mtmp->minvent; } for (obj = chain; obj; obj = obj->nobj) { int typ = obj->otyp; #ifdef GOLDOBJ if (typ == COIN_CLASS && obj->quan > 100L) return FALSE; #endif if (obj->oclass != GEM_CLASS && !(typ >= ARROW && typ <= BOOMERANG) && !(typ >= DAGGER && typ <= CRYSKNIFE) && typ != SLING && !is_cloak(obj) && typ != FEDORA && !is_gloves(obj) && typ != LEATHER_JACKET && #ifdef TOURIST typ != CREDIT_CARD && !is_shirt(obj) && #endif !(typ == CORPSE && verysmall(&mons[obj->corpsenm])) && typ != FORTUNE_COOKIE && typ != CANDY_BAR && typ != PANCAKE && typ != LEMBAS_WAFER && typ != LUMP_OF_ROYAL_JELLY && obj->oclass != AMULET_CLASS && obj->oclass != RING_CLASS && #ifdef WIZARD obj->oclass != VENOM_CLASS && #endif typ != SACK && typ != BAG_OF_HOLDING && typ != BAG_OF_TRICKS && !Is_candle(obj) && typ != OILSKIN_SACK && typ != LEASH && typ != STETHOSCOPE && typ != BLINDFOLD && typ != TOWEL && typ != TIN_WHISTLE && typ != MAGIC_WHISTLE && typ != MAGIC_MARKER && typ != TIN_OPENER && typ != SKELETON_KEY && typ != LOCK_PICK ) return FALSE; if (Is_container(obj) && obj->cobj) return FALSE; } return TRUE; } #endif /* OVL0 */ /*monmove.c*/ nethack-3.4.3/src/monst.c0100644000000000000000000043204607764735041013756 0ustar rootroot/* SCCS Id: @(#)monst.c 3.4 2000/07/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #include "permonst.h" #include "monsym.h" #include "dungeon.h" /* prerequisite for eshk,vault,epri */ #include "eshk.h" #include "vault.h" #include "epri.h" #define NO_ATTK {0,0,0,0} #define WT_ELF 800 #define WT_DRAGON 4500 #ifdef C #undef C #endif #ifdef TEXTCOLOR #include "color.h" #define C(color) color #define HI_DOMESTIC CLR_WHITE /* use for player + friendlies */ #define HI_LORD CLR_MAGENTA #else #define C(color) #endif void NDECL(monst_init); /* * Entry Format: (from permonst.h) * * name, symbol (S_* defines), * difficulty level, move rate, armor class, magic resistance, * alignment, creation/geno flags (G_* defines), * 6 * attack structs ( type , damage-type, # dice, # sides ), * weight (WT_* defines), nutritional value, extension length, * sounds made (MS_* defines), physical size (MZ_* defines), * resistances, resistances conferred (both MR_* defines), * 3 * flag bitmaps (M1_*, M2_*, and M3_* defines respectively) * symbol color (C(x) macro) */ #define MON(nam,sym,lvl,gen,atk,siz,mr1,mr2,flg1,flg2,flg3,col) \ {nam,sym,lvl,gen,atk,siz,mr1,mr2,flg1,flg2,flg3,C(col)} /* LVL() and SIZ() collect several fields to cut down on # of args for MON() */ #define LVL(lvl,mov,ac,mr,aln) lvl,mov,ac,mr,aln #define SIZ(wt,nut,pxl,snd,siz) wt,nut,pxl,snd,siz /* ATTK() and A() are to avoid braces and commas within args to MON() */ #define ATTK(at,ad,n,d) {at,ad,n,d} #define A(a1,a2,a3,a4,a5,a6) {a1,a2,a3,a4,a5,a6} /* * Rule #1: monsters of a given class are contiguous in the * mons[] array. * * Rule #2: monsters of a given class are presented in ascending * order of strength. * * Rule #3: monster frequency is included in the geno mask; * the frequency can be from 0 to 7. 0's will also * be skipped during generation. * * Rule #4: monster subclasses (e.g. giants) should be kept * together, unless it violates Rule 2. NOGEN monsters * won't violate Rule 2. * * Guidelines for color assignment: * * * Use the same color for all `growth stages' of a monster (ex. * little dog/big dog, baby naga/full-grown naga. * * * Use colors given in names wherever possible. If the class has `real' * members with strong color associations, use those. * * * Favor `cool' colors for cold-resistent monsters, `warm' ones for * fire-resistent ones. * * * Try to reserve purple (magenta) for powerful `ruler' monsters (queen * bee, kobold lord, &c.). * * * Subject to all these constraints, try to use color to make as many * distinctions as the / command (that is, within a monster letter * distinct names should map to distinct colors). * * The aim in assigning colors is to be consistent enough so a player can * become `intuitive' about them, deducing some or all of these rules * unconsciously. Use your common sense. */ #ifndef SPLITMON_2 NEARDATA struct permonst mons[] = { /* * ants */ MON("giant ant", S_ANT, LVL(2, 18, 3, 0, 0), (G_GENO|G_SGROUP|3), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, 0, MS_SILENT, MZ_TINY), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN), MON("killer bee", S_ANT, LVL(1, 18, -1, 0, 0), (G_GENO|G_LGROUP|2), A(ATTK(AT_STNG, AD_DRST, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1, 5, 0, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON, M1_ANIMAL|M1_FLY|M1_NOHANDS|M1_POIS, M2_HOSTILE|M2_FEMALE, 0, CLR_YELLOW), MON("soldier ant", S_ANT, LVL(3, 18, 3, 0, 0), (G_GENO|G_SGROUP|2), A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_DRST, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 5, 0, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_BLUE), MON("fire ant", S_ANT, LVL(3, 18, 3, 10, 0), (G_GENO|G_SGROUP|1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_BITE, AD_FIRE, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 10, 0, MS_SILENT, MZ_TINY), MR_FIRE, MR_FIRE, M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), MON("giant beetle", S_ANT, LVL(5, 6, 4, 0, 0), (G_GENO|3), A(ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, 0, MS_SILENT, MZ_LARGE), MR_POISON, MR_POISON, M1_ANIMAL|M1_NOHANDS|M1_POIS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_BLACK), MON("queen bee", S_ANT, LVL(9, 24, -4, 0, 0), (G_GENO|G_NOGEN), A(ATTK(AT_STNG, AD_DRST, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1, 5, 0, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON, M1_ANIMAL|M1_FLY|M1_NOHANDS|M1_OVIPAROUS|M1_POIS, M2_HOSTILE|M2_FEMALE|M2_PRINCE, 0, HI_LORD), /* * blobs */ MON("acid blob", S_BLOB, LVL(1, 3, 8, 0, 0), (G_GENO|2), A(ATTK(AT_NONE, AD_ACID, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 10, 0, MS_SILENT, MZ_TINY), MR_SLEEP|MR_POISON|MR_ACID|MR_STONE, MR_STONE, M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_ACID, M2_WANDER|M2_NEUTER, 0, CLR_GREEN), MON("quivering blob", S_BLOB, LVL(5, 1, 8, 0, 0), (G_GENO|2), A(ATTK(AT_TUCH, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 100, 0, MS_SILENT, MZ_SMALL), MR_SLEEP|MR_POISON, MR_POISON, M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS, M2_WANDER|M2_HOSTILE|M2_NEUTER, 0, CLR_WHITE), MON("gelatinous cube", S_BLOB, LVL(6, 6, 8, 0, 0), (G_GENO|2), A(ATTK(AT_TUCH, AD_PLYS, 2, 4), ATTK(AT_NONE, AD_PLYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 150, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_ACID|MR_STONE, MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP, M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_OMNIVORE|M1_ACID, M2_WANDER|M2_HOSTILE|M2_NEUTER, 0, CLR_CYAN), /* * cockatrice */ MON("chickatrice", S_COCKATRICE, LVL(4, 4, 8, 30, 0), (G_GENO|G_SGROUP|1), A(ATTK(AT_BITE, AD_PHYS, 1, 2), ATTK(AT_TUCH, AD_STON, 0, 0), ATTK(AT_NONE, AD_STON, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, 0, MS_HISS, MZ_TINY), MR_POISON|MR_STONE, MR_POISON|MR_STONE, M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("cockatrice", S_COCKATRICE, LVL(5, 6, 6, 30, 0), (G_GENO|5), A(ATTK(AT_BITE, AD_PHYS, 1, 3), ATTK(AT_TUCH, AD_STON, 0, 0), ATTK(AT_NONE, AD_STON, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, 0, MS_HISS, MZ_SMALL), MR_POISON|MR_STONE, MR_POISON|MR_STONE, M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE|M1_OVIPAROUS, M2_HOSTILE, M3_INFRAVISIBLE, CLR_YELLOW), MON("pyrolisk", S_COCKATRICE, LVL(6, 6, 6, 30, 0), (G_GENO|1), A(ATTK(AT_GAZE, AD_FIRE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, 0, MS_HISS, MZ_SMALL), MR_POISON|MR_FIRE, MR_POISON|MR_FIRE, M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE|M1_OVIPAROUS, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), /* * dogs & other canines */ MON("jackal", S_DOG, LVL(0, 12, 7, 0, 0), (G_GENO|G_SGROUP|3), A(ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, 0, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("fox", S_DOG, LVL(0, 15, 7, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, 0, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), MON("coyote", S_DOG, LVL(1, 12, 7, 0, 0), (G_GENO|G_SGROUP|1), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, 0, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("werejackal", S_DOG, LVL(2, 12, 7, 10, -7), (G_NOGEN|G_NOCORPSE), A(ATTK(AT_BITE, AD_WERE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 250, 0, MS_BARK, MZ_SMALL), MR_POISON, 0, M1_NOHANDS|M1_POIS|M1_REGEN|M1_CARNIVORE, M2_NOPOLY|M2_WERE|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("little dog", S_DOG, LVL(2, 18, 6, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(150, 150, 0, MS_BARK, MZ_SMALL), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("dog", S_DOG, LVL(4, 16, 5, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 1 ,6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 200, 0, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("large dog", S_DOG, LVL(6, 15, 4, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 250, 0, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_STRONG|M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("dingo", S_DOG, LVL(4, 16, 5, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 1 ,6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 200, 0, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_YELLOW), MON("wolf", S_DOG, LVL(5, 12, 4, 0, 0), (G_GENO|G_SGROUP|2), A(ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, 0, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("werewolf", S_DOG, LVL(5, 12, 4, 20, -7), (G_NOGEN|G_NOCORPSE), A(ATTK(AT_BITE, AD_WERE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, 0, MS_BARK, MZ_MEDIUM), MR_POISON, 0, M1_NOHANDS|M1_POIS|M1_REGEN|M1_CARNIVORE, M2_NOPOLY|M2_WERE|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("warg", S_DOG, LVL(7, 12, 4, 0, -5), (G_GENO|G_SGROUP|2), A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(850, 350, 0, MS_BARK, MZ_MEDIUM), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("winter wolf cub", S_DOG, LVL(5, 12, 4, 0, -5), (G_NOHELL|G_GENO|G_SGROUP|2), A(ATTK(AT_BITE, AD_PHYS, 1, 8), ATTK(AT_BREA, AD_COLD, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(250, 200, 0, MS_BARK, MZ_SMALL), MR_COLD, MR_COLD, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_CYAN), MON("winter wolf", S_DOG, LVL(7, 12, 4, 20, 0), (G_NOHELL|G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BREA, AD_COLD, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 300, 0, MS_BARK, MZ_LARGE), MR_COLD, MR_COLD, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG, 0, CLR_CYAN), MON("hell hound pup", S_DOG, LVL(7, 12, 4, 20, -5), (G_HELL|G_GENO|G_SGROUP|1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_BREA, AD_FIRE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, 0, MS_BARK, MZ_SMALL), MR_FIRE, MR_FIRE, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), MON("hell hound", S_DOG, LVL(12, 14, 2, 20, 0), (G_HELL|G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BREA, AD_FIRE, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_BARK, MZ_MEDIUM), MR_FIRE, MR_FIRE, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_RED), #ifdef CHARON MON("Cerberus", S_DOG, LVL(12, 10, 2, 20, -7), (G_HELL|G_UNIQ|1), A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 350, 0, MS_BARK, MZ_LARGE), MR_FIRE, MR_FIRE, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_NOPOLY|M2_HOSTILE|M2_STRONG|M2_PNAME|M2_MALE, M3_INFRAVISIBLE, CLR_RED), #endif /* * eyes */ MON("gas spore", S_EYE, LVL(1, 3, 10, 0, 0), (G_NOCORPSE|G_GENO|1), A(ATTK(AT_BOOM, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), 0, 0, M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS, M2_HOSTILE|M2_NEUTER, 0, CLR_GRAY), MON("floating eye", S_EYE, LVL(2, 1, 9, 10, 0), (G_GENO|5), A(ATTK(AT_NONE, AD_PLYS, 0,70), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), 0, 0, M1_FLY|M1_AMPHIBIOUS|M1_NOLIMBS|M1_NOHEAD|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_BLUE), MON("freezing sphere", S_EYE, LVL(6, 13, 4, 0, 0), (G_NOCORPSE|G_NOHELL|G_GENO|2), A(ATTK(AT_EXPL, AD_COLD, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), MR_COLD, MR_COLD, M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_WHITE), MON("flaming sphere", S_EYE, LVL(6, 13, 4, 0, 0), (G_NOCORPSE|G_GENO|2), A(ATTK(AT_EXPL, AD_FIRE, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), MR_FIRE, MR_FIRE, M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_RED), MON("shocking sphere", S_EYE, LVL(6, 13, 4, 0, 0), (G_NOCORPSE|G_GENO|2), A(ATTK(AT_EXPL, AD_ELEC, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), MR_ELEC, MR_ELEC, M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, HI_ZAP), #if 0 /* not yet implemented */ MON("beholder", S_EYE, LVL(6, 3, 4, 0, -10), (G_GENO|2), A(ATTK(AT_GAZE, AD_SLOW, 0, 0), ATTK(AT_GAZE, AD_SLEE, 2,25), ATTK(AT_GAZE, AD_DISN, 0, 0), ATTK(AT_GAZE, AD_STON, 0, 0), ATTK(AT_GAZE, AD_CNCL, 2, 4), ATTK(AT_BITE, AD_PHYS, 2, 4)), SIZ(10, 10, 0, MS_SILENT, MZ_SMALL), MR_COLD, 0, M1_FLY|M1_BREATHLESS|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS, M2_NOPOLY|M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_BROWN), #endif /* * felines */ MON("kitten", S_FELINE, LVL(2, 18, 6, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(150, 150, 0, MS_MEW, MZ_SMALL), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_WANDER|M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("housecat", S_FELINE, LVL(4, 16, 5, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, 0, MS_MEW, MZ_SMALL), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("jaguar", S_FELINE, LVL(4, 15, 6, 0, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("lynx", S_FELINE, LVL(5, 15, 6, 0, 0), (G_GENO|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_GROWL, MZ_SMALL), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,M2_HOSTILE, M3_INFRAVISIBLE, CLR_CYAN), MON("panther", S_FELINE, LVL(5, 15, 6, 0, 0), (G_GENO|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE,M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLACK), MON("large cat", S_FELINE, LVL(6, 15, 4, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(250, 250, 0, MS_MEW, MZ_SMALL), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_STRONG|M2_DOMESTIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("tiger", S_FELINE, LVL(6, 12, 6, 0, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_BITE, AD_PHYS, 1,10), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_YELLOW), /* * gremlins and gargoyles */ MON("gremlin", S_GREMLIN, LVL(5, 12, 2, 25, -9), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_CURS, 0, 0), NO_ATTK, NO_ATTK), SIZ(100, 20, 0, MS_LAUGH, MZ_SMALL), MR_POISON, MR_POISON, M1_SWIM|M1_HUMANOID|M1_POIS, M2_STALK, M3_INFRAVISIBLE, CLR_GREEN), MON("gargoyle", S_GREMLIN, LVL(6, 10, -4, 0, -9), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_BITE, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 200, 0, MS_GRUNT, MZ_HUMAN), MR_STONE, MR_STONE, M1_HUMANOID|M1_THICK_HIDE|M1_BREATHLESS, M2_HOSTILE|M2_STRONG, 0, CLR_BROWN), MON("winged gargoyle", S_GREMLIN, LVL(9, 15, -2, 0, -12), (G_GENO|1), A(ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_BITE, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 300, 0, MS_GRUNT, MZ_HUMAN), MR_STONE, MR_STONE, M1_FLY|M1_HUMANOID|M1_THICK_HIDE|M1_BREATHLESS|M1_OVIPAROUS, M2_LORD|M2_HOSTILE|M2_STRONG|M2_MAGIC, 0, HI_LORD), /* * humanoids */ MON("hobbit", S_HUMANOID, LVL(1, 9, 10, 0, 6), (G_GENO|2), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 200, 0, MS_HUMANOID, MZ_SMALL), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GREEN), MON("dwarf", S_HUMANOID, LVL(2, 6, 10, 10, 4), (G_GENO|3), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_DWARF|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("bugbear", S_HUMANOID, LVL(3, 9, 5, 0, -6), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1250, 250, 0, MS_GROWL, MZ_LARGE), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), MON("dwarf lord", S_HUMANOID, LVL(4, 6, 10, 10, 5), (G_GENO|2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE, M2_DWARF|M2_STRONG|M2_LORD|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE), MON("dwarf king", S_HUMANOID, LVL(6, 6, 10, 20, 6), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 300, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE, M2_DWARF|M2_STRONG|M2_PRINCE|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("mind flayer", S_HUMANOID, LVL(9, 12, 5, 90, -8), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), NO_ATTK, NO_ATTK), SIZ(1450, 400, 0, MS_HISS, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_FLY|M1_SEE_INVIS|M1_OMNIVORE, M2_HOSTILE|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_MAGENTA), MON("master mind flayer", S_HUMANOID, LVL(13, 12, 0, 90, -8), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1), ATTK(AT_TENT, AD_DRIN, 2, 1)), SIZ(1450, 400, 0, MS_HISS, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_FLY|M1_SEE_INVIS|M1_OMNIVORE, M2_HOSTILE|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_MAGENTA), /* * imps & other minor demons/devils */ MON("manes", S_IMP, LVL(1, 3, 7, 0, -7), (G_GENO|G_LGROUP|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, 0, MS_SILENT, MZ_SMALL), MR_SLEEP|MR_POISON, 0, M1_POIS, M2_HOSTILE|M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("homunculus", S_IMP, LVL(2, 12, 6, 10, -7), (G_GENO|2), A(ATTK(AT_BITE, AD_SLEE, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(60, 100, 0, MS_SILENT, MZ_TINY), MR_SLEEP|MR_POISON, MR_SLEEP|MR_POISON, M1_FLY|M1_POIS, M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GREEN), MON("imp", S_IMP, LVL(3, 12, 2, 20, -7), (G_GENO|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 10, 0, MS_CUSS, MZ_TINY), 0, 0, M1_REGEN, M2_WANDER|M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("lemure", S_IMP, LVL(3, 3, 7, 0, -7), (G_HELL|G_GENO|G_LGROUP|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(150, 100, 0, MS_SILENT, MZ_MEDIUM), MR_SLEEP|MR_POISON, MR_SLEEP, M1_POIS|M1_REGEN, M2_HOSTILE|M2_WANDER|M2_STALK|M2_NEUTER, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), MON("quasit", S_IMP, LVL(3, 15, 2, 20, -7), (G_GENO|2), A(ATTK(AT_CLAW, AD_DRDX, 1, 2), ATTK(AT_CLAW, AD_DRDX, 1, 2), ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_REGEN, M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE), MON("tengu", S_IMP, LVL(6, 13, 5, 30, 7), (G_GENO|3), A(ATTK(AT_BITE, AD_PHYS, 1, 7), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 200, 0, MS_SQAWK, MZ_SMALL), MR_POISON, MR_POISON, M1_TPORT|M1_TPORT_CNTRL, M2_STALK, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_CYAN), /* * jellies */ MON("blue jelly", S_JELLY, LVL(4, 0, 8, 10, 0), (G_GENO|2), A(ATTK(AT_NONE, AD_COLD, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 20, 0, MS_SILENT, MZ_MEDIUM), MR_COLD|MR_POISON, MR_COLD|MR_POISON, M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS |M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_BLUE), MON("spotted jelly", S_JELLY, LVL(5, 0, 8, 10, 0), (G_GENO|1), A(ATTK(AT_NONE, AD_ACID, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 20, 0, MS_SILENT, MZ_MEDIUM), MR_ACID|MR_STONE, 0, M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_ACID|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_GREEN), MON("ochre jelly", S_JELLY, LVL(6, 3, 8, 20, 0), (G_GENO|2), A(ATTK(AT_ENGL, AD_ACID, 3, 6), ATTK(AT_NONE, AD_ACID, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 20, 0, MS_SILENT, MZ_MEDIUM), MR_ACID|MR_STONE, 0, M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_ACID|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN), /* * kobolds */ MON("kobold", S_KOBOLD, LVL(0, 6, 10, 0, -2), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 100, 0, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID|M1_POIS|M1_OMNIVORE, M2_HOSTILE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), MON("large kobold", S_KOBOLD, LVL(1, 6, 10, 0, -3), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(450, 150, 0, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID|M1_POIS|M1_OMNIVORE, M2_HOSTILE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("kobold lord", S_KOBOLD, LVL(2, 6, 10, 0, -4), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 200, 0, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID|M1_POIS|M1_OMNIVORE, M2_HOSTILE|M2_LORD|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("kobold shaman", S_KOBOLD, LVL(2, 6, 6, 10, -4), (G_GENO|1), A(ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(450, 150, 0, MS_ORC, MZ_SMALL), MR_POISON, 0, M1_HUMANOID|M1_POIS|M1_OMNIVORE, M2_HOSTILE|M2_MAGIC, M3_INFRAVISIBLE|M3_INFRAVISION, HI_ZAP), /* * leprechauns */ MON("leprechaun", S_LEPRECHAUN, LVL(5, 15, 8, 20, 0), (G_GENO|4), A(ATTK(AT_CLAW, AD_SGLD, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(60, 30, 0, MS_LAUGH, MZ_TINY), 0, 0, M1_HUMANOID|M1_TPORT, M2_HOSTILE|M2_GREEDY, M3_INFRAVISIBLE, CLR_GREEN), /* * mimics */ MON("small mimic", S_MIMIC, LVL(7, 3, 7, 0, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 200, 0, MS_SILENT, MZ_MEDIUM), MR_ACID, 0, M1_BREATHLESS|M1_AMORPHOUS|M1_HIDE|M1_ANIMAL|M1_NOEYES| M1_NOHEAD|M1_NOLIMBS|M1_THICK_HIDE|M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN), MON("large mimic", S_MIMIC, LVL(8, 3, 7, 10, 0), (G_GENO|1), A(ATTK(AT_CLAW, AD_STCK, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 400, 0, MS_SILENT, MZ_LARGE), MR_ACID, 0, M1_CLING|M1_BREATHLESS|M1_AMORPHOUS|M1_HIDE|M1_ANIMAL|M1_NOEYES| M1_NOHEAD|M1_NOLIMBS|M1_THICK_HIDE|M1_CARNIVORE, M2_HOSTILE|M2_STRONG, 0, CLR_RED), MON("giant mimic", S_MIMIC, LVL(9, 3, 7, 20, 0), (G_GENO|1), A(ATTK(AT_CLAW, AD_STCK, 3, 6), ATTK(AT_CLAW, AD_STCK, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 500, 0, MS_SILENT, MZ_LARGE), MR_ACID, 0, M1_CLING|M1_BREATHLESS|M1_AMORPHOUS|M1_HIDE|M1_ANIMAL|M1_NOEYES| M1_NOHEAD|M1_NOLIMBS|M1_THICK_HIDE|M1_CARNIVORE, M2_HOSTILE|M2_STRONG, 0, HI_LORD), /* * nymphs */ MON("wood nymph", S_NYMPH, LVL(3, 12, 9, 20, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_TPORT, M2_HOSTILE|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE, CLR_GREEN), MON("water nymph", S_NYMPH, LVL(3, 12, 9, 20, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_TPORT|M1_SWIM, M2_HOSTILE|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), MON("mountain nymph", S_NYMPH, LVL(3, 12, 9, 20, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_CLAW, AD_SEDU, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_SEDUCE, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_TPORT, M2_HOSTILE|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE, CLR_BROWN), /* * orcs */ MON("goblin", S_ORC, LVL(0, 6, 10, 0, -3), (G_GENO|2), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 100, 0, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY), MON("hobgoblin", S_ORC, LVL(1, 9, 10, 0, -4), (G_GENO|2), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 200, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), /* plain "orc" for zombie corpses only; not created at random */ MON("orc", S_ORC, LVL(1, 9, 10, 0, -3), (G_GENO|G_NOGEN|G_LGROUP), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(850, 150, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("hill orc", S_ORC, LVL(2, 9, 10, 0, -4), (G_GENO|G_LGROUP|2), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 200, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_YELLOW), MON("Mordor orc", S_ORC, LVL(3, 5, 10, 0, -5), (G_GENO|G_LGROUP|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 200, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE), MON("Uruk-hai", S_ORC, LVL(3, 7, 10, 0, -4), (G_GENO|G_LGROUP|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 300, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLACK), MON("orc shaman", S_ORC, LVL(3, 9, 5, 10, -5), (G_GENO|1), A(ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 300, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_MAGIC, M3_INFRAVISIBLE|M3_INFRAVISION, HI_ZAP), MON("orc-captain", S_ORC, LVL(5, 5, 10, 0, -5), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1350, 350, 0, MS_ORC, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_ORC|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), /* * piercers */ MON("rock piercer", S_PIERCER, LVL(3, 1, 3, 0, 0), (G_GENO|4), A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, 0, MS_SILENT, MZ_SMALL), 0, 0, M1_CLING|M1_HIDE|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_CARNIVORE|M1_NOTAKE, M2_HOSTILE, 0, CLR_GRAY), MON("iron piercer", S_PIERCER, LVL(5, 1, 0, 0, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 300, 0, MS_SILENT, MZ_MEDIUM), 0, 0, M1_CLING|M1_HIDE|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_CARNIVORE|M1_NOTAKE, M2_HOSTILE, 0, CLR_CYAN), MON("glass piercer", S_PIERCER, LVL(7, 1, 0, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 300, 0, MS_SILENT, MZ_MEDIUM), MR_ACID, 0, M1_CLING|M1_HIDE|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_CARNIVORE|M1_NOTAKE, M2_HOSTILE, 0, CLR_WHITE), /* * quadrupeds */ MON("rothe", S_QUADRUPED, LVL(2, 9, 7, 0, 0), (G_GENO|G_SGROUP|4), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 100, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("mumak", S_QUADRUPED, LVL(5, 9, 0, 0, -2), (G_GENO|1), A(ATTK(AT_BUTT, AD_PHYS, 4,12), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 500, 0, MS_ROAR, MZ_LARGE), 0, 0, M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|M1_HERBIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY), MON("leocrotta", S_QUADRUPED, LVL(6, 18, 4, 10, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 500, 0, MS_IMITATE, MZ_LARGE), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_RED), MON("wumpus", S_QUADRUPED, LVL(8, 3, 2, 10, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 500, 0, MS_BURBLE, MZ_LARGE), 0, 0, M1_CLING|M1_ANIMAL|M1_NOHANDS|M1_OMNIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_CYAN), MON("titanothere", S_QUADRUPED, LVL(12, 12, 6, 0, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2650, 650, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|M1_HERBIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY), MON("baluchitherium", S_QUADRUPED, LVL(14, 12, 5, 0, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 5, 4), ATTK(AT_CLAW, AD_PHYS, 5, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(3800, 800, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|M1_HERBIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY), MON("mastodon", S_QUADRUPED, LVL(20, 12, 5, 0, 0), (G_GENO|1), A(ATTK(AT_BUTT, AD_PHYS, 4, 8), ATTK(AT_BUTT, AD_PHYS, 4, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(3800, 800, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS|M1_HERBIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_BLACK), /* * rodents */ MON("sewer rat", S_RODENT, LVL(0, 12, 7, 0, 0), (G_GENO|G_SGROUP|1), A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 12, 0, MS_SQEEK, MZ_TINY), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("giant rat", S_RODENT, LVL(1, 10, 7, 0, 0), (G_GENO|G_SGROUP|2), A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, 0, MS_SQEEK, MZ_TINY), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("rabid rat", S_RODENT, LVL(2, 12, 6, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_DRCO, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 5, 0, MS_SQEEK, MZ_TINY), MR_POISON, 0, M1_ANIMAL|M1_NOHANDS|M1_POIS|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("wererat", S_RODENT, LVL(2, 12, 6, 10, -7), (G_NOGEN|G_NOCORPSE), A(ATTK(AT_BITE, AD_WERE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(40, 30, 0, MS_SQEEK, MZ_TINY), MR_POISON, 0, M1_NOHANDS|M1_POIS|M1_REGEN|M1_CARNIVORE, M2_NOPOLY|M2_WERE|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("rock mole", S_RODENT, LVL(3, 3, 0, 20, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, 0, MS_SILENT, MZ_SMALL), 0, 0, M1_TUNNEL|M1_ANIMAL|M1_NOHANDS|M1_METALLIVORE, M2_HOSTILE|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE, CLR_GRAY), MON("woodchuck", S_RODENT, LVL(3, 3, 0, 20, 0), (G_NOGEN|G_GENO), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, 0, MS_SILENT, MZ_SMALL), 0, 0, M1_TUNNEL/*LOGGING*/|M1_ANIMAL|M1_NOHANDS|M1_SWIM|M1_HERBIVORE, /* In reality, they tunnel instead of cutting lumber. Oh, well. */ M2_WANDER|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), /* * spiders & scorpions (keep webmaker() in sync if new critters are added) */ MON("cave spider", S_SPIDER, LVL(1, 12, 3, 0, 0), (G_GENO|G_SGROUP|2), A(ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 50, 0, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, M1_CONCEAL|M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_GRAY), MON("centipede", S_SPIDER, LVL(2, 4, 3, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_DRST, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 50, 0, MS_SILENT, MZ_TINY), MR_POISON, MR_POISON, M1_CONCEAL|M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_YELLOW), MON("giant spider", S_SPIDER, LVL(5, 15, 4, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, 0, MS_SILENT, MZ_LARGE), MR_POISON, MR_POISON, M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG, 0, CLR_MAGENTA), MON("scorpion", S_SPIDER, LVL(5, 15, 3, 0, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 2), ATTK(AT_STNG, AD_DRST, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 100, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_CONCEAL|M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_RED), /* * trappers, lurkers, &c */ MON("lurker above", S_TRAPPER, LVL(10, 3, 3, 0, 0), (G_GENO|2), A(ATTK(AT_ENGL, AD_DGST, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 350, 0, MS_SILENT, MZ_HUGE), 0, 0, M1_HIDE|M1_FLY|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_CARNIVORE, M2_HOSTILE|M2_STALK|M2_STRONG, 0, CLR_GRAY), MON("trapper", S_TRAPPER, LVL(12, 3, 3, 0, 0), (G_GENO|2), A(ATTK(AT_ENGL, AD_DGST, 1,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 350, 0, MS_SILENT, MZ_HUGE), 0, 0, M1_HIDE|M1_ANIMAL|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_CARNIVORE, M2_HOSTILE|M2_STALK|M2_STRONG, 0, CLR_GREEN), /* * unicorns and horses */ MON("white unicorn", S_UNICORN, LVL(4, 24, 2, 70, 7), (G_GENO|2), A(ATTK(AT_BUTT, AD_PHYS, 1,12), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 300, 0, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON, M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_JEWELS, M3_INFRAVISIBLE, CLR_WHITE), MON("gray unicorn", S_UNICORN, LVL(4, 24, 2, 70, 0), (G_GENO|1), A(ATTK(AT_BUTT, AD_PHYS, 1,12), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 300, 0, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON, M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_JEWELS, M3_INFRAVISIBLE, CLR_GRAY), MON("black unicorn", S_UNICORN, LVL(4, 24, 2, 70, -7), (G_GENO|1), A(ATTK(AT_BUTT, AD_PHYS, 1,12), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 300, 0, MS_NEIGH, MZ_LARGE), MR_POISON, MR_POISON, M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_JEWELS, M3_INFRAVISIBLE, CLR_BLACK), MON("pony", S_UNICORN, LVL(3, 16, 6, 0, 0), (G_GENO|2), A(ATTK(AT_KICK, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1300, 250, 0, MS_NEIGH, MZ_MEDIUM), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_DOMESTIC, M3_INFRAVISIBLE, CLR_BROWN), MON("horse", S_UNICORN, LVL(5, 20, 5, 0, 0), (G_GENO|2), A(ATTK(AT_KICK, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 300, 0, MS_NEIGH, MZ_LARGE), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_DOMESTIC, M3_INFRAVISIBLE, CLR_BROWN), MON("warhorse", S_UNICORN, LVL(7, 24, 4, 0, 0), (G_GENO|2), A(ATTK(AT_KICK, AD_PHYS, 1, 10), ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1800, 350, 0, MS_NEIGH, MZ_LARGE), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_HERBIVORE, M2_WANDER|M2_STRONG|M2_DOMESTIC, M3_INFRAVISIBLE, CLR_BROWN), /* * vortices */ MON("fog cloud", S_VORTEX, LVL(3, 1, 0, 0, 0), (G_GENO|G_NOCORPSE|2), A(ATTK(AT_ENGL, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS| M1_AMORPHOUS|M1_UNSOLID, M2_HOSTILE|M2_NEUTER, 0, CLR_GRAY), MON("dust vortex", S_VORTEX, LVL(4, 20, 2, 30, 0), (G_GENO|G_NOCORPSE|2), A(ATTK(AT_ENGL, AD_BLND, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS, M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN), MON("ice vortex", S_VORTEX, LVL(5, 20, 2, 30, 0), (G_NOHELL|G_GENO|G_NOCORPSE|1), A(ATTK(AT_ENGL, AD_COLD, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_COLD|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_CYAN), MON("energy vortex", S_VORTEX, LVL(6, 20, 2, 30, 0), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_ENGL, AD_ELEC, 1, 6), ATTK(AT_ENGL, AD_DREN, 0, 0), ATTK(AT_NONE, AD_ELEC, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_ELEC|MR_SLEEP|MR_DISINT|MR_POISON|MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS| M1_UNSOLID, M2_HOSTILE|M2_NEUTER, 0, HI_ZAP), MON("steam vortex", S_VORTEX, LVL(7, 22, 2, 30, 0), (G_HELL|G_GENO|G_NOCORPSE|2), A(ATTK(AT_ENGL, AD_FIRE, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_FIRE|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS| M1_UNSOLID, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_BLUE), MON("fire vortex", S_VORTEX, LVL(8, 22, 2, 30, 0), (G_HELL|G_GENO|G_NOCORPSE|1), A(ATTK(AT_ENGL, AD_FIRE, 1,10), ATTK(AT_NONE, AD_FIRE, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_FIRE|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS| M1_UNSOLID, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW), /* * worms */ MON("baby long worm", S_WORM, LVL(8, 3, 5, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 250, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|M1_CARNIVORE|M1_NOTAKE, M2_HOSTILE, 0, CLR_BROWN), MON("baby purple worm", S_WORM, LVL(8, 3, 5, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 250, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_MAGENTA), MON("long worm", S_WORM, LVL(8, 3, 5, 10, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_SILENT, MZ_GIGANTIC), 0, 0, M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|M1_OVIPAROUS|M1_CARNIVORE|M1_NOTAKE, M2_HOSTILE|M2_STRONG|M2_NASTY, 0, CLR_BROWN), MON("purple worm", S_WORM, LVL(15, 9, 6, 20, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_PHYS, 2, 8), ATTK(AT_ENGL, AD_DGST, 1,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2700, 700, 0, MS_SILENT, MZ_GIGANTIC), 0, 0, M1_ANIMAL|M1_SLITHY|M1_NOLIMBS|M1_OVIPAROUS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY, 0, CLR_MAGENTA), /* * xan, &c */ MON("grid bug", S_XAN, LVL(0, 12, 9, 0, 0), (G_GENO|G_SGROUP|G_NOCORPSE|3), A(ATTK(AT_BITE, AD_ELEC, 1, 1), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(15, 10, 0, MS_BUZZ, MZ_TINY), MR_ELEC|MR_POISON, 0, M1_ANIMAL, M2_HOSTILE, M3_INFRAVISIBLE, CLR_MAGENTA), MON("xan", S_XAN, LVL(7, 18, -4, 0, 0), (G_GENO|3), A(ATTK(AT_STNG, AD_LEGS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 300, 0, MS_BUZZ, MZ_TINY), MR_POISON, MR_POISON, M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_POIS, M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), /* * lights */ MON("yellow light", S_LIGHT, LVL(3, 15, 0, 0, 0), (G_NOCORPSE|G_GENO|4), A(ATTK(AT_EXPL, AD_BLND, 10,20), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_SMALL), MR_FIRE|MR_COLD|MR_ELEC|MR_DISINT|MR_SLEEP|MR_POISON|MR_ACID| MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_UNSOLID|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW), MON("black light", S_LIGHT, LVL(5, 15, 0, 0, 0), (G_NOCORPSE|G_GENO|2), A(ATTK(AT_EXPL, AD_HALU, 10,12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_SMALL), MR_FIRE|MR_COLD|MR_ELEC|MR_DISINT|MR_SLEEP|MR_POISON|MR_ACID| MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_UNSOLID|M1_SEE_INVIS|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_BLACK), /* * zruty */ MON("zruty", S_ZRUTY, LVL(9, 8, 3, 0, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_BITE, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 600, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN), /* * Angels and other lawful minions */ MON("couatl", S_ANGEL, LVL(8, 10, 5, 30, 7), (G_NOHELL|G_SGROUP|G_NOCORPSE|1), A(ATTK(AT_BITE, AD_DRST, 2, 4), ATTK(AT_BITE, AD_PHYS, 1, 3), ATTK(AT_HUGS, AD_WRAP, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 400, 0, MS_HISS, MZ_LARGE), MR_POISON, 0, M1_FLY|M1_POIS, M2_MINION|M2_STALK|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GREEN), MON("Aleax", S_ANGEL, LVL(10, 8, 0, 30, 7), (G_NOHELL|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_IMITATE, MZ_HUMAN), MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0, M1_HUMANOID|M1_SEE_INVIS, M2_MINION|M2_STALK|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_YELLOW), MON("Angel", S_ANGEL, LVL(14, 10, -4, 55, 12), (G_NOHELL|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_MAGC, AD_MAGM, 2, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, sizeof(struct epri), MS_CUSS, MZ_HUMAN), MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0, M1_FLY|M1_HUMANOID|M1_SEE_INVIS, M2_NOPOLY|M2_MINION|M2_STALK|M2_STRONG|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_WHITE), MON("ki-rin", S_ANGEL, LVL(16, 18, -5, 90, 15), (G_NOHELL|G_NOCORPSE|1), A(ATTK(AT_KICK, AD_PHYS, 2, 4), ATTK(AT_KICK, AD_PHYS, 2, 4), ATTK(AT_BUTT, AD_PHYS, 3, 6), ATTK(AT_MAGC, AD_SPEL, 2, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NEIGH, MZ_LARGE), 0, 0, M1_FLY|M1_SEE_INVIS, M2_NOPOLY|M2_MINION|M2_STALK|M2_STRONG|M2_NASTY|M2_LORD, M3_INFRAVISIBLE|M3_INFRAVISION, HI_GOLD), MON("Archon", S_ANGEL, LVL(19, 16, -6, 80, 15), (G_NOHELL|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_GAZE, AD_BLND, 2, 6), ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_MAGC, AD_SPEL, 4, 6), NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_CUSS, MZ_LARGE), MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0, M1_FLY|M1_HUMANOID|M1_SEE_INVIS|M1_REGEN, M2_NOPOLY|M2_MINION|M2_STALK|M2_STRONG|M2_NASTY|M2_LORD| M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), /* * Bats */ MON("bat", S_BAT, LVL(0, 22, 8, 0, 0), (G_GENO|G_SGROUP|1), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 20, 0, MS_SQEEK, MZ_TINY), 0, 0, M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_WANDER, M3_INFRAVISIBLE, CLR_BROWN), MON("giant bat", S_BAT, LVL(2, 22, 7, 0, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, 0, MS_SQEEK, MZ_SMALL), 0, 0, M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_WANDER|M2_HOSTILE, M3_INFRAVISIBLE, CLR_RED), MON("raven", S_BAT, LVL(4, 20, 6, 0, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_BLND, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(40, 20, 0, MS_SQAWK, MZ_SMALL), 0, 0, M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_WANDER|M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLACK), MON("vampire bat", S_BAT, LVL(5, 20, 6, 0, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_DRST, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 20, 0, MS_SQEEK, MZ_SMALL), MR_SLEEP|MR_POISON, 0, M1_FLY|M1_ANIMAL|M1_NOHANDS|M1_POIS|M1_REGEN|M1_OMNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLACK), /* * Centaurs */ MON("plains centaur", S_CENTAUR, LVL(4, 18, 4, 0, 0), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 500, 0, MS_HUMANOID, MZ_LARGE), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_GREEDY|M2_COLLECT, M3_INFRAVISIBLE, CLR_BROWN), MON("forest centaur", S_CENTAUR, LVL(5, 18, 3, 10, -1), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2550, 600, 0, MS_HUMANOID, MZ_LARGE), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_GREEDY|M2_COLLECT, M3_INFRAVISIBLE, CLR_GREEN), MON("mountain centaur", S_CENTAUR, LVL(6, 20, 2, 10, -3), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1,10), ATTK(AT_KICK, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2550, 500, 0, MS_HUMANOID, MZ_LARGE), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_GREEDY|M2_COLLECT, M3_INFRAVISIBLE, CLR_CYAN), /* * Dragons */ /* The order of the dragons is VERY IMPORTANT. Quite a few * pieces of code depend on gray being first and yellow being last. * The code also depends on the *order* being the same as that for * dragon scale mail and dragon scales in objects.c. Baby dragons * cannot confer intrinsics, to avoid polyself/egg abuse. * * As reptiles, dragons are cold-blooded and thus aren't seen * with infravision. Red dragons are the exception. */ MON("baby gray dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_GRAY), MON("baby silver dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, DRAGON_SILVER), #if 0 /* DEFERRED */ MON("baby shimmering dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), 0, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_CYAN), #endif MON("baby red dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_FIRE, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, M3_INFRAVISIBLE, CLR_RED), MON("baby white dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_COLD, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_WHITE), MON("baby orange dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_SLEEP, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_ORANGE), MON("baby black dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_DISINT, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_BLACK), MON("baby blue dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_ELEC, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_BLUE), MON("baby green dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_POISON, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_POIS, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_GREEN), MON("baby yellow dragon", S_DRAGON, LVL(12, 9, 2, 10, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_ROAR, MZ_HUGE), MR_ACID|MR_STONE, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_ACID, M2_HOSTILE|M2_STRONG|M2_GREEDY|M2_JEWELS, 0, CLR_YELLOW), MON("gray dragon", S_DRAGON, LVL(15, 9, -1, 20, 4), (G_GENO|1), A(ATTK(AT_BREA, AD_MAGM, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), 0, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_GRAY), MON("silver dragon", S_DRAGON, LVL(15, 9, -1, 20, 4), (G_GENO|1), A(ATTK(AT_BREA, AD_COLD, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_COLD, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, DRAGON_SILVER), #if 0 /* DEFERRED */ MON("shimmering dragon", S_DRAGON, LVL(15, 9, -1, 20, 4), (G_GENO|1), A(ATTK(AT_BREA, AD_MAGM, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), 0, 0, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_CYAN), #endif MON("red dragon", S_DRAGON, LVL(15, 9, -1, 20, -4), (G_GENO|1), A(ATTK(AT_BREA, AD_FIRE, 6, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_FIRE, MR_FIRE, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, M3_INFRAVISIBLE, CLR_RED), MON("white dragon", S_DRAGON, LVL(15, 9, -1, 20, -5), (G_GENO|1), A(ATTK(AT_BREA, AD_COLD, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_COLD, MR_COLD, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_WHITE), MON("orange dragon", S_DRAGON, LVL(15, 9, -1, 20, 5), (G_GENO|1), A(ATTK(AT_BREA, AD_SLEE, 4,25), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_SLEEP, MR_SLEEP, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_ORANGE), MON("black dragon", S_DRAGON, LVL(15, 9, -1, 20, -6), (G_GENO|1), A(ATTK(AT_BREA, AD_DISN, 4,10), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_DISINT, MR_DISINT, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_BLACK), MON("blue dragon", S_DRAGON, LVL(15, 9, -1, 20, -7), (G_GENO|1), A(ATTK(AT_BREA, AD_ELEC, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_ELEC, MR_ELEC, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_BLUE), MON("green dragon", S_DRAGON, LVL(15, 9, -1, 20, 6), (G_GENO|1), A(ATTK(AT_BREA, AD_DRST, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_POISON, MR_POISON, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE|M1_POIS, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_GREEN), MON("yellow dragon", S_DRAGON, LVL(15, 9, -1, 20, 7), (G_GENO|1), A(ATTK(AT_BREA, AD_ACID, 4, 6), ATTK(AT_BITE, AD_PHYS, 3, 8), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_DRAGON, 1500, 0, MS_ROAR, MZ_GIGANTIC), MR_ACID|MR_STONE, MR_STONE, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_SEE_INVIS|M1_OVIPAROUS| M1_CARNIVORE|M1_ACID, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_GREEDY|M2_JEWELS|M2_MAGIC, 0, CLR_YELLOW), /* * Elementals */ MON("stalker", S_ELEMENTAL, LVL(8, 12, 3, 0, 0), (G_GENO|3), A(ATTK(AT_CLAW, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 400, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_FLY|M1_SEE_INVIS, M2_WANDER|M2_STALK|M2_HOSTILE|M2_STRONG, M3_INFRAVISION, CLR_WHITE), MON("air elemental", S_ELEMENTAL, LVL(8, 36, 2, 30, 0), (G_NOCORPSE|1), A(ATTK(AT_ENGL, AD_PHYS, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_POISON|MR_STONE, 0, M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_UNSOLID|M1_FLY, M2_STRONG|M2_NEUTER, 0, CLR_CYAN), MON("fire elemental", S_ELEMENTAL, LVL(8, 12, 2, 30, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_FIRE, 3, 6), ATTK(AT_NONE, AD_FIRE, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUGE), MR_FIRE|MR_POISON|MR_STONE, 0, M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_UNSOLID|M1_FLY|M1_NOTAKE, M2_STRONG|M2_NEUTER, M3_INFRAVISIBLE, CLR_YELLOW), MON("earth elemental", S_ELEMENTAL, LVL(8, 6, 2, 30, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 0, 0, MS_SILENT, MZ_HUGE), MR_FIRE|MR_COLD|MR_POISON|MR_STONE, 0, M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_BREATHLESS| M1_WALLWALK|M1_THICK_HIDE, M2_STRONG|M2_NEUTER, 0, CLR_BROWN), MON("water elemental", S_ELEMENTAL, LVL(8, 6, 2, 30, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 5, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2500, 0, 0, MS_SILENT, MZ_HUGE), MR_POISON|MR_STONE, 0, M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_AMPHIBIOUS|M1_SWIM, M2_STRONG|M2_NEUTER, 0, CLR_BLUE), /* * Fungi */ MON("lichen", S_FUNGUS, LVL(0, 1, 9, 0, 0), (G_GENO|4), A(ATTK(AT_TUCH, AD_STCK, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(20, 200, 0, MS_SILENT, MZ_SMALL), 0, 0, M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_BRIGHT_GREEN), MON("brown mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO|1), A(ATTK(AT_NONE, AD_COLD, 0, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 30, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_POISON, MR_COLD|MR_POISON, M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN), MON("yellow mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO|2), A(ATTK(AT_NONE, AD_STUN, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 30, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_POIS|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_YELLOW), MON("green mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO|1), A(ATTK(AT_NONE, AD_ACID, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 30, 0, MS_SILENT, MZ_SMALL), MR_ACID|MR_STONE, MR_STONE, M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_ACID|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_GREEN), MON("red mold", S_FUNGUS, LVL(1, 0, 9, 0, 0), (G_GENO|1), A(ATTK(AT_NONE, AD_FIRE, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 30, 0, MS_SILENT, MZ_SMALL), MR_FIRE|MR_POISON, MR_FIRE|MR_POISON, M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, M3_INFRAVISIBLE, CLR_RED), MON("shrieker", S_FUNGUS, LVL(3, 1, 7, 0, 0), (G_GENO|1), A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, 0, MS_SHRIEK, MZ_SMALL), MR_POISON, MR_POISON, M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_MAGENTA), MON("violet fungus", S_FUNGUS, LVL(3, 1, 7, 0, 0), (G_GENO|2), A(ATTK(AT_TUCH, AD_PHYS, 1, 4), ATTK(AT_TUCH, AD_STCK, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_BREATHLESS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD|M1_MINDLESS|M1_NOTAKE, M2_HOSTILE|M2_NEUTER, 0, CLR_MAGENTA), /* * Gnomes */ MON("gnome", S_GNOME, LVL(1, 6, 10, 4, 0), (G_GENO|G_SGROUP|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(650, 100, 0, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_GNOME|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), MON("gnome lord", S_GNOME, LVL(3, 8, 10, 4, 0), (G_GENO|2), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 120, 0, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_GNOME|M2_LORD|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE), MON("gnomish wizard", S_GNOME, LVL(3, 10, 4, 10, 0), (G_GENO|1), A(ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(700, 120, 0, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_GNOME|M2_MAGIC, M3_INFRAVISIBLE|M3_INFRAVISION, HI_ZAP), MON("gnome king", S_GNOME, LVL(5, 10, 10, 20, 0), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 150, 0, MS_ORC, MZ_SMALL), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_GNOME|M2_PRINCE|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), #ifdef SPLITMON_1 }; #endif #endif /* !SPLITMON_2 */ /* horrible kludge alert: * This is a compiler-specific kludge to allow the compilation of monst.o in * two pieces, by defining first SPLITMON_1 and then SPLITMON_2. The * resulting assembler files (monst1.s and monst2.s) are then run through * sed to change local symbols, concatenated together, and assembled to * produce monst.o. THIS ONLY WORKS WITH THE ATARI GCC, and should only * be done if you don't have enough memory to compile monst.o the "normal" * way. --ERS */ #ifndef SPLITMON_1 #ifdef SPLITMON_2 struct permonst _mons2[] = { #endif /* * giant Humanoids */ MON("giant", S_GIANT, LVL(6, 6, 0, 0, 2), (G_GENO|G_NOGEN|1), A(ATTK(AT_WEAP, AD_PHYS, 2,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), 0, 0, M1_HUMANOID|M1_CARNIVORE, M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("stone giant", S_GIANT, LVL(6, 6, 0, 0, 2), (G_GENO|G_SGROUP|1), A(ATTK(AT_WEAP, AD_PHYS, 2,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), 0, 0, M1_HUMANOID|M1_CARNIVORE, M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY), MON("hill giant", S_GIANT, LVL(8, 10, 6, 0, -2), (G_GENO|G_SGROUP|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2200, 700, 0, MS_BOAST, MZ_HUGE), 0, 0, M1_HUMANOID|M1_CARNIVORE, M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_CYAN), MON("fire giant", S_GIANT, LVL(9, 12, 4, 5, 2), (G_GENO|G_SGROUP|1), A(ATTK(AT_WEAP, AD_PHYS, 2,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), MR_FIRE, MR_FIRE, M1_HUMANOID|M1_CARNIVORE, M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_YELLOW), MON("frost giant", S_GIANT, LVL(10, 12, 3, 10, -3), (G_NOHELL|G_GENO|G_SGROUP|1), A(ATTK(AT_WEAP, AD_PHYS, 2,12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), MR_COLD, MR_COLD, M1_HUMANOID|M1_CARNIVORE, M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_WHITE), MON("storm giant", S_GIANT, LVL(16, 12, 3, 10, -3), (G_GENO|G_SGROUP|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 750, 0, MS_BOAST, MZ_HUGE), MR_ELEC, MR_ELEC, M1_HUMANOID|M1_CARNIVORE, M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_JEWELS, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE), MON("ettin", S_GIANT, LVL(10, 12, 3, 0, 0), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_WEAP, AD_PHYS, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 500, 0, MS_GRUNT, MZ_HUGE), 0, 0, M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), MON("titan", S_GIANT, LVL(16, 18, -3, 70, 9), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2300, 900, 0, MS_SPELL, MZ_HUGE), 0, 0, M1_FLY|M1_HUMANOID|M1_OMNIVORE, M2_STRONG|M2_ROCKTHROW|M2_NASTY|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_MAGENTA), MON("minotaur", S_GIANT, LVL(15, 15, 6, 0, 0), (G_GENO|G_NOGEN), A(ATTK(AT_CLAW, AD_PHYS, 3,10), ATTK(AT_CLAW, AD_PHYS, 3,10), ATTK(AT_BUTT, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 700, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), /* 'I' is a visual marker for all invisible monsters and must be unused */ /* * Jabberwock */ MON("jabberwock", S_JABBERWOCK, LVL(15, 12, -2, 50, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 2,10), ATTK(AT_BITE, AD_PHYS, 2,10), ATTK(AT_CLAW, AD_PHYS, 2,10), ATTK(AT_CLAW, AD_PHYS, 2,10), NO_ATTK, NO_ATTK), SIZ(1300, 600, 0, MS_BURBLE, MZ_LARGE), 0, 0, M1_ANIMAL|M1_FLY|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE, CLR_ORANGE), #if 0 /* DEFERRED */ MON("vorpal jabberwock", S_JABBERWOCK, LVL(20, 12, -2, 50, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 3, 10), ATTK(AT_BITE, AD_PHYS, 3, 10), ATTK(AT_CLAW, AD_PHYS, 3, 10), ATTK(AT_CLAW, AD_PHYS, 3, 10), NO_ATTK, NO_ATTK), SIZ(1300, 600, 0, MS_BURBLE, MZ_LARGE), 0, 0, M1_ANIMAL|M1_FLY|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE, HI_LORD), #endif #ifdef KOPS /* * Kops */ MON("Keystone Kop", S_KOP, LVL(1, 6, 10, 10, 9), (G_GENO|G_LGROUP|G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, 0, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID, M2_HUMAN|M2_WANDER|M2_HOSTILE|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), MON("Kop Sergeant", S_KOP, LVL(2, 8, 10, 10, 10), (G_GENO|G_SGROUP|G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, 0, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID, M2_HUMAN|M2_WANDER|M2_HOSTILE|M2_STRONG|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), MON("Kop Lieutenant", S_KOP, LVL(3, 10, 10, 20, 11), (G_GENO|G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, 0, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID, M2_HUMAN|M2_WANDER|M2_HOSTILE|M2_STRONG|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE, CLR_CYAN), MON("Kop Kaptain", S_KOP, LVL(4, 12, 10, 20, 12), (G_GENO|G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, 0, MS_ARREST, MZ_HUMAN), 0, 0, M1_HUMANOID, M2_HUMAN|M2_WANDER|M2_HOSTILE|M2_STRONG|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE, HI_LORD), #endif /* * Liches */ MON("lich", S_LICH, LVL(11, 6, 0, 30, -9), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_TUCH, AD_COLD, 1,10), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 100, 0, MS_MUMBLE, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, MR_COLD, M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN, M2_UNDEAD|M2_HOSTILE|M2_MAGIC, M3_INFRAVISION, CLR_BROWN), MON("demilich", S_LICH, LVL(14, 9, -2, 60, -12), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_TUCH, AD_COLD, 3, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 100, 0, MS_MUMBLE, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, MR_COLD, M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN, M2_UNDEAD|M2_HOSTILE|M2_MAGIC, M3_INFRAVISION, CLR_RED), MON("master lich", S_LICH, LVL(17, 9, -4, 90, -15), (G_HELL|G_GENO|G_NOCORPSE|1), A(ATTK(AT_TUCH, AD_COLD, 3, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 100, 0, MS_MUMBLE, MZ_HUMAN), MR_FIRE|MR_COLD|MR_SLEEP|MR_POISON, MR_FIRE|MR_COLD, M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN, M2_UNDEAD|M2_HOSTILE|M2_MAGIC, M3_WANTSBOOK|M3_INFRAVISION, HI_LORD), MON("arch-lich", S_LICH, LVL(25, 9, -6, 90, -15), (G_HELL|G_GENO|G_NOCORPSE|1), A(ATTK(AT_TUCH, AD_COLD, 5, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 100, 0, MS_MUMBLE, MZ_HUMAN), MR_FIRE|MR_COLD|MR_SLEEP|MR_ELEC|MR_POISON, MR_FIRE|MR_COLD, M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN, M2_UNDEAD|M2_HOSTILE|M2_MAGIC, M3_WANTSBOOK|M3_INFRAVISION, HI_LORD), /* * Mummies */ MON("kobold mummy", S_MUMMY, LVL(3, 8, 6, 20, -2), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_HOSTILE, M3_INFRAVISION, CLR_BROWN), MON("gnome mummy", S_MUMMY, LVL(4, 10, 6, 20, -3), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(650, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_HOSTILE|M2_GNOME, M3_INFRAVISION, CLR_RED), MON("orc mummy", S_MUMMY, LVL(5, 10, 5, 20, -4), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(850, 75, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_HOSTILE|M2_ORC|M2_GREEDY|M2_JEWELS, M3_INFRAVISION, CLR_GRAY), MON("dwarf mummy", S_MUMMY, LVL(5, 10, 5, 20, -4), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 150, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_HOSTILE|M2_DWARF|M2_GREEDY|M2_JEWELS, M3_INFRAVISION, CLR_RED), MON("elf mummy", S_MUMMY, LVL(6, 12, 4, 30, -5), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 175, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_HOSTILE|M2_ELF, M3_INFRAVISION, CLR_GREEN), MON("human mummy", S_MUMMY, LVL(6, 12, 4, 30, -5), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_HOSTILE, M3_INFRAVISION, CLR_GRAY), MON("ettin mummy", S_MUMMY, LVL(7, 12, 4, 30, -6), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 250, 0, MS_SILENT, MZ_HUGE), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_HOSTILE|M2_STRONG, M3_INFRAVISION, CLR_BLUE), MON("giant mummy", S_MUMMY, LVL(8, 14, 3, 30, -7), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2050, 375, 0, MS_SILENT, MZ_HUGE), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_HOSTILE|M2_GIANT|M2_STRONG|M2_JEWELS, M3_INFRAVISION, CLR_CYAN), /* * Nagas */ MON("red naga hatchling", S_NAGA, LVL(3, 10, 6, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 100, 0, MS_MUMBLE, MZ_LARGE), MR_FIRE|MR_POISON, MR_FIRE|MR_POISON, M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_NOTAKE|M1_OMNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_RED), MON("black naga hatchling", S_NAGA, LVL(3, 10, 6, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 100, 0, MS_MUMBLE, MZ_LARGE), MR_POISON|MR_ACID|MR_STONE, MR_POISON|MR_STONE, M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_ACID|M1_NOTAKE|M1_CARNIVORE, M2_STRONG, 0, CLR_BLACK), MON("golden naga hatchling", S_NAGA, LVL(3, 10, 6, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 100, 0, MS_MUMBLE, MZ_LARGE), MR_POISON, MR_POISON, M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_NOTAKE|M1_OMNIVORE, M2_STRONG, 0, HI_GOLD), MON("guardian naga hatchling", S_NAGA, LVL(3, 10, 6, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 100, 0, MS_MUMBLE, MZ_LARGE), MR_POISON, MR_POISON, M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_NOTAKE|M1_OMNIVORE, M2_STRONG, 0, CLR_GREEN), MON("red naga", S_NAGA, LVL(6, 12, 4, 0, -4), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_BREA, AD_FIRE, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2600, 400, 0, MS_MUMBLE, MZ_HUGE), MR_FIRE|MR_POISON, MR_FIRE|MR_POISON, M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_OVIPAROUS|M1_NOTAKE|M1_OMNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_RED), MON("black naga", S_NAGA, LVL(8, 14, 2, 10, 4), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_SPIT, AD_ACID, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2600, 400, 0, MS_MUMBLE, MZ_HUGE), MR_POISON|MR_ACID|MR_STONE, MR_POISON|MR_STONE, M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_OVIPAROUS|M1_ACID|M1_NOTAKE| M1_CARNIVORE, M2_STRONG, 0, CLR_BLACK), MON("golden naga", S_NAGA, LVL(10, 14, 2, 70, 5), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 2, 6), ATTK(AT_MAGC, AD_SPEL, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2600, 400, 0, MS_MUMBLE, MZ_HUGE), MR_POISON, MR_POISON, M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_OVIPAROUS|M1_NOTAKE|M1_OMNIVORE, M2_STRONG, 0, HI_GOLD), MON("guardian naga", S_NAGA, LVL(12, 16, 0, 50, 7), (G_GENO|1), A(ATTK(AT_BITE, AD_PLYS, 1, 6), ATTK(AT_SPIT, AD_DRST, 1, 6), ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2600, 400, 0, MS_MUMBLE, MZ_HUGE), MR_POISON, MR_POISON, M1_NOLIMBS|M1_SLITHY|M1_THICK_HIDE|M1_OVIPAROUS|M1_POIS|M1_NOTAKE| M1_OMNIVORE, M2_STRONG, 0, CLR_GREEN), /* * Ogres */ MON("ogre", S_OGRE, LVL(5, 10, 5, 0, -3), (G_SGROUP|G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 5), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1600, 500, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_CARNIVORE, M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), MON("ogre lord", S_OGRE, LVL(7, 12, 3, 30, -5), (G_GENO|2), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 700, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_CARNIVORE, M2_STRONG|M2_LORD|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("ogre king", S_OGRE, LVL(9, 14, 4, 60, -7), (G_GENO|2), A(ATTK(AT_WEAP, AD_PHYS, 3, 5), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 750, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_CARNIVORE, M2_STRONG|M2_PRINCE|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), /* * Puddings */ MON("gray ooze", S_PUDDING, LVL(3, 1, 8, 0, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_RUST, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, 0, MS_SILENT, MZ_MEDIUM), MR_FIRE|MR_COLD|MR_POISON|MR_ACID|MR_STONE, MR_FIRE|MR_COLD|MR_POISON, M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_OMNIVORE|M1_ACID, M2_HOSTILE|M2_NEUTER, 0, CLR_GRAY), MON("brown pudding", S_PUDDING, LVL(5, 3, 8, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_DCAY, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 250, 0, MS_SILENT, MZ_MEDIUM), MR_COLD|MR_ELEC|MR_POISON|MR_ACID|MR_STONE, MR_COLD|MR_ELEC|MR_POISON, M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_OMNIVORE|M1_ACID, M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN), MON("black pudding", S_PUDDING, LVL(10, 6, 6, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_CORR, 3, 8), ATTK(AT_NONE, AD_CORR, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 250, 0, MS_SILENT, MZ_LARGE), MR_COLD|MR_ELEC|MR_POISON|MR_ACID|MR_STONE, MR_COLD|MR_ELEC|MR_POISON, M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_OMNIVORE|M1_ACID, M2_HOSTILE|M2_NEUTER, 0, CLR_BLACK), MON("green slime", S_PUDDING, LVL(6, 6, 6, 0, 0), (G_HELL|G_GENO|1), A(ATTK(AT_TUCH, AD_SLIM, 1, 4), ATTK(AT_NONE, AD_SLIM, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 150, 0, MS_SILENT, MZ_LARGE), MR_COLD|MR_ELEC|MR_POISON|MR_ACID|MR_STONE, 0, M1_BREATHLESS|M1_AMORPHOUS|M1_NOEYES|M1_NOLIMBS|M1_NOHEAD| M1_MINDLESS|M1_OMNIVORE|M1_ACID|M1_POIS, M2_HOSTILE|M2_NEUTER, 0, CLR_GREEN), /* * Quantum mechanics */ MON("quantum mechanic", S_QUANTMECH, LVL(7, 12, 3, 10, 0), (G_GENO|3), A(ATTK(AT_CLAW, AD_TLPT, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 20, 0, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_OMNIVORE|M1_POIS|M1_TPORT, M2_HOSTILE, M3_INFRAVISIBLE, CLR_CYAN), /* * Rust monster or disenchanter */ MON("rust monster", S_RUSTMONST, LVL(5, 18, 2, 0, 0), (G_GENO|2), A(ATTK(AT_TUCH, AD_RUST, 0, 0), ATTK(AT_TUCH, AD_RUST, 0, 0), ATTK(AT_NONE, AD_RUST, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 250, 0, MS_SILENT, MZ_MEDIUM), 0, 0, M1_SWIM|M1_ANIMAL|M1_NOHANDS|M1_METALLIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BROWN), MON("disenchanter", S_RUSTMONST, LVL(12, 12, -10, 0, -3), (G_HELL|G_GENO|2), A(ATTK(AT_CLAW, AD_ENCH, 4, 4), ATTK(AT_NONE, AD_ENCH, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 200, 0, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL|M1_CARNIVORE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BLUE), /* * Snakes */ MON("garter snake", S_SNAKE, LVL(1, 8, 8, 0, 0), (G_LGROUP|G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(50, 60, 0, MS_HISS, MZ_TINY), 0, 0, M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_OVIPAROUS| M1_CARNIVORE|M1_NOTAKE, 0, 0, CLR_GREEN), MON("snake", S_SNAKE, LVL(4, 15, 3, 0, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_DRST, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 80, 0, MS_HISS, MZ_SMALL), MR_POISON, MR_POISON, M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_POIS| M1_OVIPAROUS|M1_CARNIVORE|M1_NOTAKE, M2_HOSTILE, 0, CLR_BROWN), MON("water moccasin", S_SNAKE, LVL(4, 15, 3, 0, 0), (G_GENO|G_NOGEN|G_LGROUP), A(ATTK(AT_BITE, AD_DRST, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(150, 80, 0, MS_HISS, MZ_SMALL), MR_POISON, MR_POISON, M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_POIS| M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE, M2_HOSTILE, 0, CLR_RED), MON("pit viper", S_SNAKE, LVL(6, 15, 2, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_DRST, 1, 4), ATTK(AT_BITE, AD_DRST, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 60, 0, MS_HISS, MZ_MEDIUM), MR_POISON, MR_POISON, M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_POIS| M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE, M2_HOSTILE, M3_INFRAVISION, CLR_BLUE), MON("python", S_SNAKE, LVL(6, 3, 5, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 1, 4), ATTK(AT_TUCH, AD_PHYS, 0, 0), ATTK(AT_HUGS, AD_WRAP, 1, 4), ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK), SIZ(250, 100, 0, MS_HISS, MZ_LARGE), 0, 0, M1_SWIM|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY| M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE, M2_HOSTILE|M2_STRONG, M3_INFRAVISION, CLR_MAGENTA), MON("cobra", S_SNAKE, LVL(6, 18, 2, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_DRST, 2, 4), ATTK(AT_SPIT, AD_BLND, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(250, 100, 0, MS_HISS, MZ_MEDIUM), MR_POISON, MR_POISON, M1_SWIM|M1_CONCEAL|M1_NOLIMBS|M1_ANIMAL|M1_SLITHY|M1_POIS| M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE, M2_HOSTILE, 0, CLR_BLUE), /* * Trolls */ MON("troll", S_TROLL, LVL(7, 12, 4, 0, -3), (G_GENO|2), A(ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_CLAW, AD_PHYS, 4, 2), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 350, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_REGEN|M1_CARNIVORE, M2_STRONG|M2_STALK|M2_HOSTILE, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), MON("ice troll", S_TROLL, LVL(9, 10, 2, 20, -3), (G_NOHELL|G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_COLD, 2, 6), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1000, 300, 0, MS_GRUNT, MZ_LARGE), MR_COLD, MR_COLD, M1_HUMANOID|M1_REGEN|M1_CARNIVORE, M2_STRONG|M2_STALK|M2_HOSTILE, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_WHITE), MON("rock troll", S_TROLL, LVL(9, 12, 0, 0, -3), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 300, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_REGEN|M1_CARNIVORE, M2_STRONG|M2_STALK|M2_HOSTILE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_CYAN), MON("water troll", S_TROLL, LVL(11, 14, 4, 40, -3), (G_NOGEN|G_GENO), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 350, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_REGEN|M1_CARNIVORE|M1_SWIM, M2_STRONG|M2_STALK|M2_HOSTILE, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE), MON("Olog-hai", S_TROLL, LVL(13, 12, -4, 0, -7), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 400, 0, MS_GRUNT, MZ_LARGE), 0, 0, M1_HUMANOID|M1_REGEN|M1_CARNIVORE, M2_STRONG|M2_STALK|M2_HOSTILE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), /* * Umber hulk */ MON("umber hulk", S_UMBER, LVL(9, 6, 2, 25, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_BITE, AD_PHYS, 2, 5), ATTK(AT_GAZE, AD_CONF, 0, 0), NO_ATTK, NO_ATTK), SIZ(1200, 500, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_TUNNEL|M1_CARNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN), /* * Vampires */ MON("vampire", S_VAMPIRE, LVL(10, 12, 1, 25, -8), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_DRLI, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0, M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE, CLR_RED), MON("vampire lord", S_VAMPIRE, LVL(12, 14, 0, 50, -9), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_DRLI, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0, M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_LORD|M2_MALE, M3_INFRAVISIBLE, CLR_BLUE), #if 0 /* DEFERRED */ MON("vampire mage", S_VAMPIRE, LVL(20, 14, -4, 50, -9), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_DRLI, 2, 8), ATTK(AT_BITE, AD_DRLI, 1, 8), ATTK(AT_MAGC, AD_SPEL, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0, M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_LORD|M2_MALE| M2_MAGIC, M3_INFRAVISIBLE, HI_ZAP), #endif MON("Vlad the Impaler", S_VAMPIRE, LVL(14, 18, -3, 80, -10), (G_NOGEN|G_NOCORPSE|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 10), ATTK(AT_BITE, AD_DRLI, 1, 10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_VAMPIRE, MZ_HUMAN), MR_SLEEP|MR_POISON, 0, M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_POIS|M1_REGEN, M2_NOPOLY|M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG| M2_NASTY|M2_PRINCE|M2_MALE, M3_WAITFORU|M3_WANTSCAND|M3_INFRAVISIBLE, HI_LORD), /* * Wraiths */ MON("barrow wight", S_WRAITH, LVL(3, 12, 5, 5, -3), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_DRLI, 0, 0), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1200, 0, 0, MS_SPELL, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_HUMANOID, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_COLLECT, 0, CLR_GRAY), MON("wraith", S_WRAITH, LVL(6, 12, 4, 15, -6), (G_GENO|2), A(ATTK(AT_TUCH, AD_DRLI, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_BREATHLESS|M1_FLY|M1_HUMANOID|M1_UNSOLID, M2_UNDEAD|M2_STALK|M2_HOSTILE, 0, CLR_BLACK), MON("Nazgul", S_WRAITH, LVL(13, 12, 0, 25, -17), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_DRLI, 1, 4), ATTK(AT_BREA, AD_SLEE, 2,25), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 0, 0, MS_SPELL, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_HUMANOID, M2_NOPOLY|M2_UNDEAD|M2_STALK|M2_STRONG|M2_HOSTILE|M2_MALE|M2_COLLECT, 0, HI_LORD), /* * Xorn */ MON("xorn", S_XORN, LVL(8, 9,-2, 20, 0), (G_GENO|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK), SIZ(1200, 700, 0, MS_ROAR, MZ_MEDIUM), MR_FIRE|MR_COLD|MR_STONE, MR_STONE, M1_BREATHLESS|M1_WALLWALK|M1_THICK_HIDE|M1_METALLIVORE, M2_HOSTILE|M2_STRONG, 0, CLR_BROWN), /* * Apelike beasts */ MON("monkey", S_YETI, LVL(2, 12, 6, 0, 0), (G_GENO|1), A(ATTK(AT_CLAW, AD_SITM, 0, 0), ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 50, 0, MS_GROWL, MZ_SMALL), 0, 0, M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, 0, M3_INFRAVISIBLE, CLR_GRAY), MON("ape", S_YETI, LVL(4, 12, 6, 0, 0), (G_GENO|G_SGROUP|2), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1100, 500, 0, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_BROWN), MON("owlbear", S_YETI, LVL(5, 12, 5, 0, 0), (G_GENO|3), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_HUGS, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 700, 0, MS_ROAR, MZ_LARGE), 0, 0, M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_HOSTILE|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE, CLR_BROWN), MON("yeti", S_YETI, LVL(5, 15, 6, 0, 0), (G_GENO|2), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1600, 700, 0, MS_GROWL, MZ_LARGE), MR_COLD, MR_COLD, M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_WHITE), MON("carnivorous ape", S_YETI, LVL(6, 12, 6, 0, 0), (G_GENO|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_HUGS, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1250, 550, 0, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL|M1_HUMANOID|M1_CARNIVORE, M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_BLACK), MON("sasquatch", S_YETI, LVL(7, 15, 6, 0, 2), (G_GENO|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_KICK, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1550, 750, 0, MS_GROWL, MZ_LARGE), 0, 0, M1_ANIMAL|M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_STRONG, M3_INFRAVISIBLE, CLR_GRAY), /* * Zombies */ MON("kobold zombie", S_ZOMBIE, LVL(0, 6, 10, 0, -2), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_STALK|M2_HOSTILE, M3_INFRAVISION, CLR_BROWN), MON("gnome zombie", S_ZOMBIE, LVL(1, 6, 10, 0, -2), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 5), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(650, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_GNOME, M3_INFRAVISION, CLR_BROWN), MON("orc zombie", S_ZOMBIE, LVL(2, 6, 9, 0, -3), (G_GENO|G_SGROUP|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(850, 75, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_ORC, M3_INFRAVISION, CLR_GRAY), MON("dwarf zombie", S_ZOMBIE, LVL(2, 6, 9, 0, -3), (G_GENO|G_SGROUP|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 150, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_DWARF, M3_INFRAVISION, CLR_RED), MON("elf zombie", S_ZOMBIE, LVL(3, 6, 9, 0, -3), (G_GENO|G_SGROUP|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 7), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 175, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_ELF, M3_INFRAVISION, CLR_GREEN), MON("human zombie", S_ZOMBIE, LVL(4, 6, 8, 0, -3), (G_GENO|G_SGROUP|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 200, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_UNDEAD|M2_STALK|M2_HOSTILE, M3_INFRAVISION, HI_DOMESTIC), MON("ettin zombie", S_ZOMBIE, LVL(6, 8, 6, 0, -4), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1,10), ATTK(AT_CLAW, AD_PHYS, 1,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1700, 250, 0, MS_SILENT, MZ_HUGE), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_STRONG, M3_INFRAVISION, CLR_BLUE), MON("giant zombie", S_ZOMBIE, LVL(8, 8, 6, 0, -4), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2050, 375, 0, MS_SILENT, MZ_HUGE), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_UNDEAD|M2_STALK|M2_HOSTILE|M2_GIANT|M2_STRONG, M3_INFRAVISION, CLR_CYAN), MON("ghoul", S_ZOMBIE, LVL(3, 6, 10, 0, -2), (G_GENO|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PLYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 50, 0, MS_SILENT, MZ_SMALL), MR_COLD|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_POIS, M2_UNDEAD|M2_WANDER|M2_HOSTILE, M3_INFRAVISION, CLR_BLACK), MON("skeleton", S_ZOMBIE, LVL(12, 8, 4, 0, 0), (G_NOCORPSE|G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_TUCH, AD_SLOW, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(300, 5, 0, MS_BONES, MZ_HUMAN), MR_COLD|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE, M2_UNDEAD|M2_WANDER|M2_HOSTILE|M2_STRONG|M2_COLLECT|M2_NASTY, M3_INFRAVISION, CLR_WHITE), /* * golems */ MON("straw golem", S_GOLEM, LVL(3, 12, 10, 0, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 2), ATTK(AT_CLAW, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_HOSTILE|M2_NEUTER, 0, CLR_YELLOW), MON("paper golem", S_GOLEM, LVL(3, 12, 10, 0, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(400, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_HOSTILE|M2_NEUTER, 0, HI_PAPER), MON("rope golem", S_GOLEM, LVL(4, 9, 8, 0, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_HUGS, AD_PHYS, 6, 1), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(450, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_HOSTILE|M2_NEUTER, 0, CLR_BROWN), MON("gold golem", S_GOLEM, LVL(5, 9, 6, 0, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 2, 3), ATTK(AT_CLAW, AD_PHYS, 2, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(450, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON|MR_ACID, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE, M2_HOSTILE|M2_NEUTER, 0, HI_GOLD), MON("leather golem", S_GOLEM, LVL(6, 6, 6, 0, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(800, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_HOSTILE|M2_NEUTER, 0, HI_LEATHER), MON("wood golem", S_GOLEM, LVL(7, 3, 4, 0, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(900, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE, M2_HOSTILE|M2_NEUTER, 0, HI_WOOD), MON("flesh golem", S_GOLEM, LVL(9, 8, 9, 30, 0), (1), A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1400, 600, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID, M2_HOSTILE|M2_STRONG, 0, CLR_RED), MON("clay golem", S_GOLEM, LVL(11, 7, 7, 40, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 3,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1550, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE, M2_HOSTILE|M2_STRONG, 0, CLR_BROWN), MON("stone golem", S_GOLEM, LVL(14, 6, 5, 50, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 3, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1900, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON|MR_STONE, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE, M2_HOSTILE|M2_STRONG, 0, CLR_GRAY), MON("glass golem", S_GOLEM, LVL(16, 6, 1, 50, 0), (G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1800, 0, 0, MS_SILENT, MZ_LARGE), MR_SLEEP|MR_POISON|MR_ACID, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE, M2_HOSTILE|M2_STRONG, 0, CLR_CYAN), MON("iron golem", S_GOLEM, LVL(18, 6, 3, 60, 0), (G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_BREA, AD_DRST, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2000, 0, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON, 0, M1_BREATHLESS|M1_MINDLESS|M1_HUMANOID|M1_THICK_HIDE|M1_POIS, M2_HOSTILE|M2_STRONG|M2_COLLECT, 0, HI_METAL), /* * humans, including elves and were-critters */ MON("human", S_HUMAN, LVL(0, 12, 10, 0, 0), G_NOGEN, /* for corpses */ A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("wererat", S_HUMAN, LVL(2, 12, 10, 10, -7), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_WERE, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_POIS|M1_REGEN|M1_OMNIVORE, M2_NOPOLY|M2_WERE|M2_HOSTILE|M2_HUMAN|M2_COLLECT, M3_INFRAVISIBLE, CLR_BROWN), MON("werejackal", S_HUMAN, LVL(2, 12, 10, 10, -7), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_WERE, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_POIS|M1_REGEN|M1_OMNIVORE, M2_NOPOLY|M2_WERE|M2_HOSTILE|M2_HUMAN|M2_COLLECT, M3_INFRAVISIBLE, CLR_RED), MON("werewolf", S_HUMAN, LVL(5, 12, 10, 20, -7), (1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_WERE, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_POIS|M1_REGEN|M1_OMNIVORE, M2_NOPOLY|M2_WERE|M2_HOSTILE|M2_HUMAN|M2_COLLECT, M3_INFRAVISIBLE, CLR_ORANGE), MON("elf", S_HUMAN, LVL(10, 12, 10, 2, -3), G_NOGEN, /* for corpses */ A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS, M2_NOPOLY|M2_ELF|M2_STRONG|M2_COLLECT, M3_INFRAVISION|M3_INFRAVISIBLE, HI_DOMESTIC), MON("Woodland-elf", S_HUMAN, LVL(4, 12, 10, 10, -5), (G_GENO|G_SGROUP|2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS, M2_ELF|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GREEN), MON("Green-elf", S_HUMAN, LVL(5, 12, 10, 10, -6), (G_GENO|G_SGROUP|2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS, M2_ELF|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BRIGHT_GREEN), MON("Grey-elf", S_HUMAN, LVL(6, 12, 10, 10, -7), (G_GENO|G_SGROUP|2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS, M2_ELF|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY), MON("elf-lord", S_HUMAN, LVL(8, 12, 10, 20, -9), (G_GENO|G_SGROUP|2), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS, M2_ELF|M2_STRONG|M2_LORD|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BRIGHT_BLUE), MON("Elvenking", S_HUMAN, LVL(9, 12, 10, 25, -10), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_HUMANOID, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS, M2_ELF|M2_STRONG|M2_PRINCE|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("doppelganger", S_HUMAN, LVL(9, 12, 5, 20, 0), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_IMITATE, MZ_HUMAN), MR_SLEEP, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_HOSTILE|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("nurse", S_HUMAN, LVL(11, 6, 0, 0, 0), (G_GENO|3), A(ATTK(AT_CLAW, AD_HEAL, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NURSE, MZ_HUMAN), MR_POISON, MR_POISON, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_HOSTILE, M3_INFRAVISIBLE, HI_DOMESTIC), MON("shopkeeper", S_HUMAN, LVL(12, 18, 0, 50, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4, 4), ATTK(AT_WEAP, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, sizeof(struct eshk), MS_SELL, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE, HI_DOMESTIC), MON("guard", S_HUMAN, LVL(12, 12, 10, 40, 10), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, sizeof(struct egd), MS_GUARD, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_MERC|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), MON("prisoner", S_HUMAN, LVL(12, 12, 10, 0, 0), G_NOGEN, /* for special levels */ A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_DJINNI, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE|M3_CLOSE, HI_DOMESTIC), MON("Oracle", S_HUMAN, LVL(12, 0, 0, 50, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_NONE, AD_MAGM, 0, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_ORACLE, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_FEMALE, M3_INFRAVISIBLE, HI_ZAP), MON("aligned priest", S_HUMAN, LVL(12, 12, 10, 50, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_KICK, AD_PHYS, 1, 4), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, sizeof(struct epri), MS_PRIEST, MZ_HUMAN), MR_ELEC, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_LORD|M2_PEACEFUL|M2_COLLECT, M3_INFRAVISIBLE, CLR_WHITE), MON("high priest", S_HUMAN, LVL(25, 15, 7, 70, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_KICK, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, sizeof(struct epri), MS_PRIEST, MZ_HUMAN), MR_FIRE|MR_ELEC|MR_SLEEP|MR_POISON, 0, M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_MINION|M2_PRINCE|M2_NASTY|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE, CLR_WHITE), MON("soldier", S_HUMAN, LVL(6, 10, 10, 0, -2), (G_SGROUP|G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_HOSTILE|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, CLR_GRAY), MON("sergeant", S_HUMAN, LVL(8, 10, 10, 5, -3), (G_SGROUP|G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_HOSTILE|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, CLR_RED), MON("lieutenant", S_HUMAN, LVL(10, 10, 10, 15, -4), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_WEAP, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_HOSTILE|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, CLR_GREEN), MON("captain", S_HUMAN, LVL(12, 10, 10, 15, -5), (G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 4, 4), ATTK(AT_WEAP, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_HOSTILE|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, CLR_BLUE), /* Keep these separate - some of the mkroom code assumes that * all the soldiers are contiguous. */ MON("watchman", S_HUMAN, LVL(6, 10, 10, 0, -2), (G_SGROUP|G_NOGEN|G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, CLR_GRAY), MON("watch captain", S_HUMAN, LVL(10, 10, 10, 15, -4), (G_NOGEN|G_GENO|1), A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_WEAP, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SOLDIER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_MERC|M2_STALK|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, CLR_GREEN), /* Unique humans not tied to quests. */ MON("Medusa", S_HUMAN, LVL(20, 12, 2, 50, -15), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_GAZE, AD_STON, 0, 0), ATTK(AT_BITE, AD_DRST, 1, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HISS, MZ_LARGE), MR_POISON|MR_STONE, MR_POISON|MR_STONE, M1_FLY|M1_SWIM|M1_AMPHIBIOUS|M1_HUMANOID|M1_POIS|M1_OMNIVORE, M2_NOPOLY|M2_HOSTILE|M2_STRONG|M2_PNAME|M2_FEMALE, M3_WAITFORU|M3_INFRAVISIBLE, CLR_BRIGHT_GREEN), MON("Wizard of Yendor", S_HUMAN, LVL(30, 12, -8, 100, A_NONE), (G_NOGEN|G_UNIQ), A(ATTK(AT_CLAW, AD_SAMU, 2,12), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_CUSS, MZ_HUMAN), MR_FIRE|MR_POISON, MR_FIRE|MR_POISON, M1_FLY|M1_BREATHLESS|M1_HUMANOID|M1_REGEN|M1_SEE_INVIS|M1_TPORT| M1_TPORT_CNTRL|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_HOSTILE|M2_STRONG|M2_NASTY| M2_PRINCE|M2_MALE|M2_MAGIC, M3_COVETOUS|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD), MON("Croesus", S_HUMAN, LVL(20, 15, 0, 40, 15), (G_UNIQ|G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 4,10), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARD, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_PNAME| M2_PRINCE|M2_MALE|M2_GREEDY|M2_JEWELS|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE, HI_LORD), #ifdef CHARON MON("Charon", S_HUMAN, LVL(76, 18, -5, 120, 0), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_TUCH, AD_PLYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_FERRY, MZ_HUMAN), MR_FIRE|MR_COLD|MR_POISON|MR_STONE, 0, M1_BREATHLESS|M1_SEE_INVIS|M1_HUMANOID, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_PNAME|M2_MALE|M2_GREEDY|M2_COLLECT, M3_INFRAVISIBLE, CLR_WHITE), #endif /* * ghosts */ MON("ghost", S_GHOST, LVL(10, 3, -5, 50, -5), (G_NOCORPSE|G_NOGEN), A(ATTK(AT_TUCH, AD_PHYS, 1, 1), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 0, 0, MS_SILENT, MZ_HUMAN), MR_COLD|MR_DISINT|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_WALLWALK|M1_HUMANOID|M1_UNSOLID, M2_NOPOLY|M2_UNDEAD|M2_STALK|M2_HOSTILE, M3_INFRAVISION, CLR_GRAY), MON("shade", S_GHOST, LVL(12, 10, 10, 0, 0), (G_NOCORPSE|G_NOGEN), A(ATTK(AT_TUCH, AD_PLYS, 2, 6), ATTK(AT_TUCH, AD_SLOW, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 0, 0, MS_WAIL, MZ_HUMAN), MR_COLD|MR_DISINT|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_BREATHLESS|M1_WALLWALK|M1_HUMANOID|M1_UNSOLID|M1_SEE_INVIS, M2_NOPOLY|M2_UNDEAD|M2_WANDER|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISION, CLR_BLACK), /* * (major) demons */ MON("water demon", S_DEMON, LVL(8, 12,-4, 30, -7), (G_NOCORPSE|G_NOGEN), A(ATTK(AT_WEAP, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_DJINNI, MZ_HUMAN), MR_FIRE|MR_POISON, 0, M1_HUMANOID|M1_POIS|M1_SWIM, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BLUE), /* standard demons & devils */ MON("horned devil", S_DEMON, LVL(6, 9, -5, 50, 11), (G_HELL|G_NOCORPSE|2), A(ATTK(AT_WEAP, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 2, 3), ATTK(AT_STNG, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_HUMAN), MR_FIRE|MR_POISON, 0, M1_POIS|M1_THICK_HIDE, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BROWN), #ifdef SEDUCE # define SEDUCTION_ATTACKS \ A(ATTK(AT_BITE, AD_SSEX, 0, 0), ATTK(AT_CLAW, AD_PHYS, 1, 3), \ ATTK(AT_CLAW, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK) #else # define SEDUCTION_ATTACKS \ A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), \ ATTK(AT_BITE, AD_DRLI, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK) #endif MON("succubus", S_DEMON, LVL(6, 12, 0, 70, -9), (G_NOCORPSE|1), SEDUCTION_ATTACKS, SIZ(WT_HUMAN, 400, 0, MS_SEDUCE, MZ_HUMAN), MR_FIRE|MR_POISON, 0, M1_HUMANOID|M1_FLY|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_FEMALE, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY), MON("incubus", S_DEMON, LVL(6, 12, 0, 70, -9), (G_NOCORPSE|1), SEDUCTION_ATTACKS, SIZ(WT_HUMAN, 400, 0, MS_SEDUCE, MZ_HUMAN), MR_FIRE|MR_POISON, 0, M1_HUMANOID|M1_FLY|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_MALE, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY), #undef SEDUCTION_ATTACKS /* Used by AD&D for a type of demon, originally one of the Furies */ /* and spelled this way */ MON("erinys", S_DEMON, LVL(7, 12, 2, 30, 10), (G_HELL|G_NOCORPSE|G_SGROUP|2), A(ATTK(AT_WEAP, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_HUMAN), MR_FIRE|MR_POISON, 0, M1_HUMANOID|M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_FEMALE| M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("barbed devil", S_DEMON, LVL(8, 12, 0, 35, 8), (G_HELL|G_NOCORPSE|G_SGROUP|2), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_PHYS, 3, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_HUMAN), MR_FIRE|MR_POISON, 0, M1_POIS|M1_THICK_HIDE, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("marilith", S_DEMON, LVL(7, 12, -6, 80, -12), (G_HELL|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4)), SIZ(WT_HUMAN, 400, 0, MS_CUSS, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_HUMANOID|M1_SLITHY|M1_SEE_INVIS|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("vrock", S_DEMON, LVL(8, 12, 0, 50, -9), (G_HELL|G_NOCORPSE|G_SGROUP|2), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("hezrou", S_DEMON, LVL(9, 6, -2, 55, -10), (G_HELL|G_NOCORPSE|G_SGROUP|2), A(ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_CLAW, AD_PHYS, 1, 3), ATTK(AT_BITE, AD_PHYS, 4, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_HUMANOID|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("bone devil", S_DEMON, LVL(9, 15, -1, 40, -9), (G_HELL|G_NOCORPSE|G_SGROUP|2), A(ATTK(AT_WEAP, AD_PHYS, 3, 4), ATTK(AT_STNG, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY), MON("ice devil", S_DEMON, LVL(11, 6, -4, 55, -12), (G_HELL|G_NOCORPSE|2), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_STNG, AD_COLD, 3, 4), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_COLD|MR_POISON, 0, M1_SEE_INVIS|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_WHITE), MON("nalfeshnee", S_DEMON, LVL(11, 9, -1, 65, -11), (G_HELL|G_NOCORPSE|1), A(ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_CLAW, AD_PHYS, 1, 4), ATTK(AT_BITE, AD_PHYS, 2, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SPELL, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_HUMANOID|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("pit fiend", S_DEMON, LVL(13, 6, -3, 65, -13), (G_HELL|G_NOCORPSE|2), A(ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_WEAP, AD_PHYS, 4, 2), ATTK(AT_HUGS, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GROWL, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_SEE_INVIS|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), MON("balrog", S_DEMON, LVL(16, 5, -2, 75, -14), (G_HELL|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_FLY|M1_SEE_INVIS|M1_POIS, M2_DEMON|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_RED), /* Named demon lords & princes plus Arch-Devils. * (their order matters; see minion.c) */ MON("Juiblex", S_DEMON, LVL(50, 3, -7, 65, -15), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_ENGL, AD_DISE, 4,10), ATTK(AT_SPIT, AD_ACID, 3, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 0, 0, MS_GURGLE, MZ_LARGE), MR_FIRE|MR_POISON|MR_ACID|MR_STONE, 0, M1_AMPHIBIOUS|M1_AMORPHOUS|M1_NOHEAD|M1_FLY|M1_SEE_INVIS|M1_ACID| M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|M2_LORD| M2_MALE, M3_WAITFORU|M3_WANTSAMUL|M3_INFRAVISION, CLR_BRIGHT_GREEN), MON("Yeenoghu", S_DEMON, LVL(56, 18, -5, 80, -15), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_WEAP, AD_CONF, 2, 8), ATTK(AT_CLAW, AD_PLYS, 1, 6), ATTK(AT_MAGC, AD_MAGM, 2, 6), NO_ATTK, NO_ATTK), SIZ(900, 500, 0, MS_ORC, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_FLY|M1_SEE_INVIS|M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|M2_LORD| M2_MALE|M2_COLLECT, M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("Orcus", S_DEMON, LVL(66, 9, -6, 85, -20), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_CLAW, AD_PHYS, 3, 4), ATTK(AT_MAGC, AD_SPEL, 8, 6), ATTK(AT_STNG, AD_DRST, 2, 4), NO_ATTK), SIZ(1500, 500, 0, MS_ORC, MZ_HUGE), MR_FIRE|MR_POISON, 0, M1_FLY|M1_SEE_INVIS|M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY|M2_PRINCE| M2_MALE|M2_COLLECT, M3_WAITFORU|M3_WANTSBOOK|M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("Geryon", S_DEMON, LVL(72, 3, -3, 75, 15), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_CLAW, AD_PHYS, 3, 6), ATTK(AT_STNG, AD_DRST, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_BRIBE, MZ_HUGE), MR_FIRE|MR_POISON, 0, M1_FLY|M1_SEE_INVIS|M1_POIS|M1_SLITHY, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY| M2_PRINCE|M2_MALE, M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("Dispater", S_DEMON, LVL(78, 15, -2, 80, 15), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 6, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_BRIBE, MZ_HUMAN), MR_FIRE|MR_POISON, 0, M1_FLY|M1_SEE_INVIS|M1_POIS|M1_HUMANOID, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY| M2_PRINCE|M2_MALE|M2_COLLECT, M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("Baalzebub", S_DEMON, LVL(89, 9, -5, 85, 20), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_BITE, AD_DRST, 2, 6), ATTK(AT_GAZE, AD_STUN, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_BRIBE, MZ_LARGE), MR_FIRE|MR_POISON, 0, M1_FLY|M1_SEE_INVIS|M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY| M2_PRINCE|M2_MALE, M3_WANTSAMUL|M3_WAITFORU|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("Asmodeus", S_DEMON, LVL(105, 12, -7, 90, 20), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 4, 4), ATTK(AT_MAGC, AD_COLD, 6, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_BRIBE, MZ_HUGE), MR_FIRE|MR_COLD|MR_POISON, 0, M1_FLY|M1_SEE_INVIS|M1_HUMANOID|M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG| M2_NASTY|M2_PRINCE|M2_MALE, M3_WANTSAMUL|M3_WAITFORU|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("Demogorgon", S_DEMON, LVL(106, 15, -8, 95, -20), (G_HELL|G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_MAGC, AD_SPEL, 8, 6), ATTK(AT_STNG, AD_DRLI, 1, 4), ATTK(AT_CLAW, AD_DISE, 1, 6), ATTK(AT_CLAW, AD_DISE, 1, 6), NO_ATTK, NO_ATTK), SIZ(1500, 500, 0, MS_GROWL, MZ_HUGE), MR_FIRE|MR_POISON, 0, M1_FLY|M1_SEE_INVIS|M1_NOHANDS|M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_PNAME|M2_NASTY| M2_PRINCE|M2_MALE, M3_WANTSAMUL|M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), /* Riders -- the Four Horsemen of the Apocalypse ("War" == player) */ MON("Death", S_DEMON, LVL(30, 12, -5, 100, 0), (G_UNIQ|G_NOGEN), A(ATTK(AT_TUCH, AD_DETH, 8, 8), ATTK(AT_TUCH, AD_DETH, 8, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 1, 0, MS_RIDER, MZ_HUMAN), MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_HUMANOID|M1_REGEN|M1_SEE_INVIS|M1_TPORT_CNTRL, M2_NOPOLY|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("Pestilence", S_DEMON, LVL(30, 12, -5, 100, 0), (G_UNIQ|G_NOGEN), A(ATTK(AT_TUCH, AD_PEST, 8, 8), ATTK(AT_TUCH, AD_PEST, 8, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 1, 0, MS_RIDER, MZ_HUMAN), MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_HUMANOID|M1_REGEN|M1_SEE_INVIS|M1_TPORT_CNTRL, M2_NOPOLY|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), MON("Famine", S_DEMON, LVL(30, 12, -5, 100, 0), (G_UNIQ|G_NOGEN), A(ATTK(AT_TUCH, AD_FAMN, 8, 8), ATTK(AT_TUCH, AD_FAMN, 8, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 1, 0, MS_RIDER, MZ_HUMAN), MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_HUMANOID|M1_REGEN|M1_SEE_INVIS|M1_TPORT_CNTRL, M2_NOPOLY|M2_STALK|M2_HOSTILE|M2_PNAME|M2_STRONG|M2_NASTY, M3_INFRAVISIBLE|M3_INFRAVISION, HI_LORD), /* other demons */ #ifdef MAIL MON("mail daemon", S_DEMON, LVL(56, 24, 10, 127, 0), (G_NOGEN|G_NOCORPSE), A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(600, 300, 0, MS_SILENT, MZ_HUMAN), MR_FIRE|MR_COLD|MR_ELEC|MR_SLEEP|MR_POISON|MR_STONE, 0, M1_FLY|M1_SWIM|M1_BREATHLESS|M1_SEE_INVIS|M1_HUMANOID|M1_POIS, M2_NOPOLY|M2_STALK|M2_PEACEFUL, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_BRIGHT_BLUE), #endif MON("djinni", S_DEMON, LVL(7, 12, 4, 30, 0), (G_NOGEN|G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 400, 0, MS_DJINNI, MZ_HUMAN), MR_POISON|MR_STONE, 0, M1_HUMANOID|M1_FLY|M1_POIS, M2_NOPOLY|M2_STALK|M2_COLLECT, M3_INFRAVISIBLE, CLR_YELLOW), MON("sandestin", S_DEMON, LVL(13, 12, 4, 60, -5), (G_HELL|G_NOCORPSE|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1500, 400, 0, MS_CUSS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID, M2_NOPOLY|M2_STALK|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE|M3_INFRAVISION, CLR_GRAY), /* * sea monsters */ MON("jellyfish", S_EEL, LVL(3, 3, 6, 0, 0), (G_GENO|G_NOGEN), A(ATTK(AT_STNG, AD_DRST, 3, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(80, 20, 0, MS_SILENT, MZ_SMALL), MR_POISON, MR_POISON, M1_SWIM|M1_AMPHIBIOUS|M1_SLITHY|M1_NOLIMBS|M1_NOTAKE|M1_POIS, M2_HOSTILE, 0, CLR_BLUE), MON("piranha", S_EEL, LVL(5, 12, 4, 0, 0), (G_GENO|G_NOGEN|G_SGROUP), A(ATTK(AT_BITE, AD_PHYS, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(60, 30, 0, MS_SILENT, MZ_SMALL), 0, 0, M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_SLITHY|M1_NOLIMBS| M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE, M2_HOSTILE, 0, CLR_RED), MON("shark", S_EEL, LVL(7, 12, 2, 0, 0), (G_GENO|G_NOGEN), A(ATTK(AT_BITE, AD_PHYS, 5, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(500, 350, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_SLITHY|M1_NOLIMBS| M1_CARNIVORE|M1_OVIPAROUS|M1_THICK_HIDE|M1_NOTAKE, M2_HOSTILE, 0, CLR_GRAY), MON("giant eel", S_EEL, LVL(5, 9, -1, 0, 0), (G_GENO|G_NOGEN), A(ATTK(AT_BITE, AD_PHYS, 3, 6), ATTK(AT_TUCH, AD_WRAP, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 250, 0, MS_SILENT, MZ_HUGE), 0, 0, M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_SLITHY|M1_NOLIMBS| M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_CYAN), MON("electric eel", S_EEL, LVL(7, 10, -3, 0, 0), (G_GENO|G_NOGEN), A(ATTK(AT_BITE, AD_ELEC, 4, 6), ATTK(AT_TUCH, AD_WRAP, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 250, 0, MS_SILENT, MZ_HUGE), MR_ELEC, MR_ELEC, M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_SLITHY|M1_NOLIMBS| M1_CARNIVORE|M1_OVIPAROUS|M1_NOTAKE, M2_HOSTILE, M3_INFRAVISIBLE, CLR_BRIGHT_BLUE), MON("kraken", S_EEL, LVL(20, 3, 6, 0, -3), (G_GENO|G_NOGEN), A(ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_HUGS, AD_WRAP, 2, 6), ATTK(AT_BITE, AD_PHYS, 5, 4), NO_ATTK, NO_ATTK), SIZ(1800, 1000, 0, MS_SILENT, MZ_HUGE), 0, 0, M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_NOPOLY|M2_HOSTILE|M2_STRONG, M3_INFRAVISIBLE, CLR_RED), /* * lizards, &c */ MON("newt", S_LIZARD, LVL(0, 6, 8, 0, 0), (G_GENO|5), A(ATTK(AT_BITE, AD_PHYS, 1, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 20, 0, MS_SILENT, MZ_TINY), 0, 0, M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_YELLOW), MON("gecko", S_LIZARD, LVL(1, 6, 8, 0, 0), (G_GENO|5), A(ATTK(AT_BITE, AD_PHYS, 1, 3), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 20, 0, MS_SQEEK, MZ_TINY), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_GREEN), MON("iguana", S_LIZARD, LVL(2, 6, 7, 0, 0), (G_GENO|5), A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(30, 30, 0, MS_SILENT, MZ_TINY), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN), MON("baby crocodile", S_LIZARD, LVL(3, 6, 7, 0, 0), G_GENO, A(ATTK(AT_BITE, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(200, 200, 0, MS_SILENT, MZ_MEDIUM), 0, 0, M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_BROWN), MON("lizard", S_LIZARD, LVL(5, 6, 6, 10, 0), (G_GENO|5), A(ATTK(AT_BITE, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(10, 40, 0, MS_SILENT, MZ_TINY), MR_STONE, MR_STONE, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_HOSTILE, 0, CLR_GREEN), MON("chameleon", S_LIZARD, LVL(6, 5, 6, 10, 0), (G_GENO|2), A(ATTK(AT_BITE, AD_PHYS, 4, 2), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(100, 100, 0, MS_SILENT, MZ_TINY), 0, 0, M1_ANIMAL|M1_NOHANDS|M1_CARNIVORE, M2_NOPOLY|M2_HOSTILE, 0, CLR_BROWN), MON("crocodile", S_LIZARD, LVL(6, 9, 5, 0, 0), (G_GENO|1), A(ATTK(AT_BITE, AD_PHYS, 4, 2), ATTK(AT_CLAW, AD_PHYS, 1,12), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_SILENT, MZ_LARGE), 0, 0, M1_SWIM|M1_AMPHIBIOUS|M1_ANIMAL|M1_THICK_HIDE|M1_NOHANDS| M1_OVIPAROUS|M1_CARNIVORE, M2_STRONG|M2_HOSTILE, 0, CLR_BROWN), MON("salamander", S_LIZARD, LVL(8, 12, -1, 0, -9), (G_HELL|1), A(ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_TUCH, AD_FIRE, 1, 6), ATTK(AT_HUGS, AD_PHYS, 2, 6), ATTK(AT_HUGS, AD_FIRE, 3, 6), NO_ATTK, NO_ATTK), SIZ(1500, 400, 0, MS_MUMBLE, MZ_HUMAN), MR_SLEEP|MR_FIRE, MR_FIRE, M1_HUMANOID|M1_SLITHY|M1_THICK_HIDE|M1_POIS, M2_STALK|M2_HOSTILE|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE, CLR_ORANGE), /* * dummy monster needed for visual interface */ /* (marking it unique prevents figurines) */ MON("long worm tail", S_WORM_TAIL, LVL(0, 0, 0, 0, 0), (G_NOGEN|G_NOCORPSE|G_UNIQ), A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, 0, 0), 0, 0, 0L, M2_NOPOLY, 0, CLR_BROWN), /* Note: * Worm tail must be between the normal monsters and the special * quest & pseudo-character ones because an optimization in the * random monster selection code assumes everything beyond here * has the G_NOGEN and M2_NOPOLY attributes. */ /* * character classes */ MON("archeologist", S_HUMAN, LVL(10, 12, 10, 1, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_TUNNEL|M1_NEEDPICK|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("barbarian", S_HUMAN, LVL(10, 12, 10, 1, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("caveman", S_HUMAN, LVL(10, 12, 10, 0, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("cavewoman", S_HUMAN, LVL(10, 12, 10, 0, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("healer", S_HUMAN, LVL(10, 12, 10, 1, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("knight", S_HUMAN, LVL(10, 12, 10, 1, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("monk", S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, A(ATTK(AT_CLAW, AD_PHYS, 1, 8), ATTK(AT_KICK, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_HERBIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT|M2_MALE, M3_INFRAVISIBLE, HI_DOMESTIC), MON("priest", S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_MALE|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("priestess", S_HUMAN, LVL(10, 12, 10, 2, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("ranger", S_HUMAN, LVL(10, 12, 10, 2, -3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("rogue", S_HUMAN, LVL(10, 12, 10, 1, -3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_GREEDY|M2_JEWELS|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("samurai", S_HUMAN, LVL(10, 12, 10, 1, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), #ifdef TOURIST MON("tourist", S_HUMAN, LVL(10, 12, 10, 1, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), #endif MON("valkyrie", S_HUMAN, LVL(10, 12, 10, 1, -1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), MR_COLD, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_FEMALE|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("wizard", S_HUMAN, LVL(10, 12, 10, 3, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE, HI_DOMESTIC), /* * quest leaders */ MON("Lord Carnarvon", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0, M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_LORD), MON("Pelias", S_HUMAN, LVL(20, 12, 0, 30, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_LORD), MON("Shaman Karnov", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_LORD), #if 0 /* OBSOLETE */ /* Two for elves - one of each sex. */ MON("Earendil", S_HUMAN, LVL(20, 12, 0, 50, -20), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_LEADER, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_NOPOLY|M2_ELF|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG| M2_MALE|M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD), MON("Elwing", S_HUMAN, LVL(20, 12, 0, 50, -20), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_LEADER, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_NOPOLY|M2_ELF|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG| M2_FEMALE|M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD), #endif MON("Hippocrates", S_HUMAN, LVL(20, 12, 0, 40, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_LORD), MON("King Arthur", S_HUMAN, LVL(20, 12, 0, 40, 20), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_LORD), MON("Grand Master", S_HUMAN, LVL(25, 12, 0, 70, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 4, 10), ATTK(AT_KICK, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_FIRE|MR_ELEC|MR_SLEEP|MR_POISON, 0, M1_HUMANOID|M1_SEE_INVIS|M1_HERBIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_NASTY|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, CLR_BLACK), MON("Arch Priest", S_HUMAN, LVL(25, 12, 7, 70, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4,10), ATTK(AT_KICK, AD_PHYS, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), ATTK(AT_MAGC, AD_CLRC, 2, 8), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_FIRE|MR_ELEC|MR_SLEEP|MR_POISON, 0, M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, CLR_WHITE), MON("Orion", S_HUMAN, LVL(20, 12, 0, 30, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE|M1_SEE_INVIS|M1_SWIM|M1_AMPHIBIOUS, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD), /* Note: Master of Thieves is also the Tourist's nemesis. */ MON("Master of Thieves", S_HUMAN, LVL(20, 12, 0, 30, -20), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_MALE|M2_GREEDY| M2_JEWELS|M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_LORD), MON("Lord Sato", S_HUMAN, LVL(20, 12, 0, 30, 20), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_LORD), #ifdef TOURIST MON("Twoflower", S_HUMAN, LVL(20, 12, 10, 20, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_PEACEFUL|M2_STRONG|M2_MALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_DOMESTIC), #endif MON("Norn", S_HUMAN, LVL(20, 12, 0, 80, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), MR_COLD, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_FEMALE| M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, HI_LORD), MON("Neferet the Green", S_HUMAN, LVL(20, 12, 0, 60, 0), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 2, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_LEADER, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_FEMALE|M2_PNAME|M2_PEACEFUL| M2_STRONG|M2_COLLECT|M2_MAGIC, M3_CLOSE|M3_INFRAVISIBLE, CLR_GREEN), /* * quest nemeses */ MON("Minion of Huhetotl", S_DEMON, LVL(16, 12, -2, 75, -14), (G_NOCORPSE|G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE), MR_FIRE|MR_POISON|MR_STONE, 0, M1_FLY|M1_SEE_INVIS|M1_POIS, M2_NOPOLY|M2_DEMON|M2_STALK|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_COLLECT, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_RED), MON("Thoth Amon", S_HUMAN, LVL(16, 12, 0, 10, -14), (G_NOGEN|G_UNIQ|G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_STRONG|M2_MALE|M2_STALK|M2_HOSTILE| M2_NASTY|M2_COLLECT|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD), /* Multi-headed, possessing the breath attacks of all the other dragons * (selected at random when attacking). */ MON("Chromatic Dragon", S_DRAGON, LVL(16, 12, 0, 30, -14), (G_NOGEN|G_UNIQ), A(ATTK(AT_BREA, AD_RBRE, 6, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 8), ATTK(AT_BITE, AD_PHYS, 4, 8), ATTK(AT_BITE, AD_PHYS, 4, 8), ATTK(AT_STNG, AD_PHYS, 1, 6)), SIZ(WT_DRAGON, 1700, 0, MS_NEMESIS, MZ_GIGANTIC), MR_FIRE|MR_COLD|MR_SLEEP|MR_DISINT|MR_ELEC|MR_POISON|MR_ACID|MR_STONE, MR_FIRE|MR_COLD|MR_SLEEP|MR_DISINT|MR_ELEC|MR_POISON|MR_STONE, M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_SEE_INVIS|M1_POIS, M2_NOPOLY|M2_HOSTILE|M2_FEMALE|M2_STALK|M2_STRONG|M2_NASTY| M2_GREEDY|M2_JEWELS|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD), #if 0 /* OBSOLETE */ MON("Goblin King", S_ORC, LVL(15, 12, 10, 0, -15), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 350, 0, MS_NEMESIS, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_ORC|M2_HOSTILE|M2_STRONG|M2_STALK|M2_NASTY|M2_MALE| M2_GREEDY|M2_JEWELS|M2_COLLECT|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD), #endif MON("Cyclops", S_GIANT, LVL(18, 12, 0, 0, -15), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 4, 8), ATTK(AT_WEAP, AD_PHYS, 4, 8), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(1900, 700, 0, MS_NEMESIS, MZ_HUGE), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_GIANT|M2_STRONG|M2_ROCKTHROW|M2_STALK|M2_HOSTILE| M2_NASTY|M2_MALE|M2_JEWELS|M2_COLLECT, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_GRAY), MON("Ixoth", S_DRAGON, LVL(15, 12, -1, 20, -14), (G_NOGEN|G_UNIQ), A(ATTK(AT_BREA, AD_FIRE, 8, 6), ATTK(AT_BITE, AD_PHYS, 4, 8), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_PHYS, 2, 4), ATTK(AT_CLAW, AD_SAMU, 2, 4), NO_ATTK ), SIZ(WT_DRAGON, 1600, 0, MS_NEMESIS, MZ_GIGANTIC), MR_FIRE|MR_STONE, MR_FIRE, M1_FLY|M1_THICK_HIDE|M1_NOHANDS|M1_CARNIVORE|M1_SEE_INVIS, M2_NOPOLY|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_NASTY|M2_STALK| M2_GREEDY|M2_JEWELS|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, CLR_RED), MON("Master Kaen", S_HUMAN, LVL(25, 12, -10, 10, -20), (G_NOGEN|G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 16, 2), ATTK(AT_CLAW, AD_PHYS, 16, 2), ATTK(AT_MAGC, AD_CLRC, 0, 0), ATTK(AT_CLAW, AD_SAMU, 1, 4), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, MR_POISON, M1_HUMANOID|M1_HERBIVORE|M1_SEE_INVIS, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_NASTY| M2_STALK|M2_COLLECT|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD), MON("Nalzok", S_DEMON, LVL(16, 12, -2, 85, -127), (G_NOGEN|G_UNIQ|G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 8, 4), ATTK(AT_WEAP, AD_PHYS, 4, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_LARGE), MR_FIRE|MR_POISON|MR_STONE, 0, M1_FLY|M1_SEE_INVIS|M1_POIS, M2_NOPOLY|M2_DEMON|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK| M2_NASTY|M2_COLLECT, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, CLR_RED), MON("Scorpius", S_SPIDER, LVL(15, 12, 10, 0, -15), (G_NOGEN|G_UNIQ), A(ATTK(AT_CLAW, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 6), ATTK(AT_STNG, AD_DISE, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(750, 350, 0, MS_NEMESIS, MZ_HUMAN), MR_POISON|MR_STONE, MR_POISON, M1_ANIMAL|M1_NOHANDS|M1_OVIPAROUS|M1_POIS|M1_CARNIVORE, M2_NOPOLY|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK|M2_NASTY| M2_COLLECT|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU, HI_LORD), MON("Master Assassin", S_HUMAN, LVL(15, 12, 0, 30, 18), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_DRST, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 8), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_HOSTILE|M2_STALK|M2_NASTY| M2_COLLECT|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD), /* A renegade daimyo who led a 13 year civil war against the shogun * of his time. */ MON("Ashikaga Takauji", S_HUMAN, LVL(15, 12, 0, 40, -13), (G_NOGEN|G_UNIQ|G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_WEAP, AD_PHYS, 2, 6), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PNAME|M2_HOSTILE|M2_STRONG|M2_STALK| M2_NASTY|M2_MALE|M2_COLLECT|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, HI_LORD), #ifdef TOURIST /* * Note: the Master of Thieves was defined above. */ #endif MON("Lord Surtur", S_GIANT, LVL(15, 12, 2, 50, 12), (G_NOGEN|G_UNIQ), A(ATTK(AT_WEAP, AD_PHYS, 2,10), ATTK(AT_WEAP, AD_PHYS, 2,10), ATTK(AT_CLAW, AD_SAMU, 2, 6), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(2250, 850, 0, MS_NEMESIS, MZ_HUGE), MR_FIRE|MR_STONE, MR_FIRE, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_GIANT|M2_MALE|M2_PNAME|M2_HOSTILE|M2_STALK| M2_STRONG|M2_NASTY|M2_ROCKTHROW|M2_JEWELS|M2_COLLECT, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISION|M3_INFRAVISIBLE, HI_LORD), MON("Dark One", S_HUMAN, LVL(15, 12, 0, 80, -10), (G_NOGEN|G_UNIQ|G_NOCORPSE), A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_CLAW, AD_SAMU, 1, 4), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_NEMESIS, MZ_HUMAN), MR_STONE, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_STRONG|M2_HOSTILE|M2_STALK|M2_NASTY| M2_COLLECT|M2_MAGIC, M3_WANTSARTI|M3_WAITFORU|M3_INFRAVISIBLE, CLR_BLACK), /* * quest "guardians" */ MON("student", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_TUNNEL|M1_NEEDPICK|M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("chieftain", S_HUMAN, LVL(5, 12, 10, 10, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("neanderthal", S_HUMAN, LVL(5, 12, 10, 10, 1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), #if 0 /* OBSOLETE */ MON("High-elf", S_HUMAN, LVL(5, 12, 10, 10, -7), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 2, 4), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_ELF, 350, 0, MS_GUARDIAN, MZ_HUMAN), MR_SLEEP, MR_SLEEP, M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_NOPOLY|M2_ELF|M2_PEACEFUL|M2_COLLECT, M3_INFRAVISION|M3_INFRAVISIBLE, HI_DOMESTIC), #endif MON("attendant", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), MR_POISON, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("page", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("abbot", S_HUMAN, LVL(5, 12, 10, 20, 0), G_NOGEN, A(ATTK(AT_CLAW, AD_PHYS, 8, 2), ATTK(AT_KICK, AD_STUN, 3, 2), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_HERBIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("acolyte", S_HUMAN, LVL(5, 12, 10, 20, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_CLRC, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("hunter", S_HUMAN, LVL(5, 12, 10, 10, -7), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 4), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_SEE_INVIS|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISION|M3_INFRAVISIBLE, HI_DOMESTIC), MON("thug", S_HUMAN, LVL(5, 12, 10, 10, -3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_WEAP, AD_PHYS, 1, 6), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_GREEDY|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("ninja", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_HUMANOID, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_HOSTILE|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), MON("roshi", S_HUMAN, LVL(5, 12, 10, 10, 3), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT, M3_INFRAVISIBLE, HI_DOMESTIC), #ifdef TOURIST MON("guide", S_HUMAN, LVL(5, 12, 10, 20, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL | M2_STRONG|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE, HI_DOMESTIC), #endif MON("warrior", S_HUMAN, LVL(5, 12, 10, 10, -1), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 8), ATTK(AT_WEAP, AD_PHYS, 1, 8), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT|M2_FEMALE, M3_INFRAVISIBLE, HI_DOMESTIC), MON("apprentice", S_HUMAN, LVL(5, 12, 10, 30, 0), G_NOGEN, A(ATTK(AT_WEAP, AD_PHYS, 1, 6), ATTK(AT_MAGC, AD_SPEL, 0, 0), NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(WT_HUMAN, 400, 0, MS_GUARDIAN, MZ_HUMAN), 0, 0, M1_HUMANOID|M1_OMNIVORE, M2_NOPOLY|M2_HUMAN|M2_PEACEFUL|M2_STRONG|M2_COLLECT|M2_MAGIC, M3_INFRAVISIBLE, HI_DOMESTIC), /* * array terminator */ MON("", 0, LVL(0, 0, 0, 0, 0), (0), A(NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK, NO_ATTK), SIZ(0, 0, 0, 0, 0), 0, 0, 0L, 0L, 0, 0) }; #endif /* !SPLITMON_1 */ #ifndef SPLITMON_1 /* dummy routine used to force linkage */ void monst_init() { return; } #endif /*monst.c*/ nethack-3.4.3/src/mplayer.c0100644000000000000000000002240007764735041014254 0ustar rootroot/* SCCS Id: @(#)mplayer.c 3.4 1997/02/04 */ /* Copyright (c) Izchak Miller, 1992. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL const char *NDECL(dev_name); STATIC_DCL void FDECL(get_mplname, (struct monst *, char *)); STATIC_DCL void FDECL(mk_mplayer_armor, (struct monst *, SHORT_P)); /* These are the names of those who * contributed to the development of NetHack 3.2/3.3/3.4. * * Keep in alphabetical order within teams. * Same first name is entered once within each team. */ static const char *developers[] = { /* devteam */ "Dave", "Dean", "Eric", "Izchak", "Janet", "Jessie", "Ken", "Kevin", "Michael", "Mike", "Pat", "Paul", "Steve", "Timo", "Warwick", /* PC team */ "Bill", "Eric", "Keizo", "Ken", "Kevin", "Michael", "Mike", "Paul", "Stephen", "Steve", "Timo", "Yitzhak", /* Amiga team */ "Andy", "Gregg", "Janne", "Keni", "Mike", "Olaf", "Richard", /* Mac team */ "Andy", "Chris", "Dean", "Jon", "Jonathan", "Kevin", "Wang", /* Atari team */ "Eric", "Marvin", "Warwick", /* NT team */ "Alex", "Dion", "Michael", /* OS/2 team */ "Helge", "Ron", "Timo", /* VMS team */ "Joshua", "Pat", ""}; /* return a randomly chosen developer name */ STATIC_OVL const char * dev_name() { register int i, m = 0, n = SIZE(developers); register struct monst *mtmp; register boolean match; do { match = FALSE; i = rn2(n); for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if(!is_mplayer(mtmp->data)) continue; if(!strncmp(developers[i], NAME(mtmp), strlen(developers[i]))) { match = TRUE; break; } } m++; } while (match && m < 100); /* m for insurance */ if (match) return (const char *)0; return(developers[i]); } STATIC_OVL void get_mplname(mtmp, nam) register struct monst *mtmp; char *nam; { boolean fmlkind = is_female(mtmp->data); const char *devnam; devnam = dev_name(); if (!devnam) Strcpy(nam, fmlkind ? "Eve" : "Adam"); else if (fmlkind && !!strcmp(devnam, "Janet")) Strcpy(nam, rn2(2) ? "Maud" : "Eve"); else Strcpy(nam, devnam); if (fmlkind || !strcmp(nam, "Janet")) mtmp->female = 1; else mtmp->female = 0; Strcat(nam, " the "); Strcat(nam, rank_of((int)mtmp->m_lev, monsndx(mtmp->data), (boolean)mtmp->female)); } STATIC_OVL void mk_mplayer_armor(mon, typ) struct monst *mon; short typ; { struct obj *obj; if (typ == STRANGE_OBJECT) return; obj = mksobj(typ, FALSE, FALSE); if (!rn2(3)) obj->oerodeproof = 1; if (!rn2(3)) curse(obj); if (!rn2(3)) bless(obj); /* Most players who get to the endgame who have cursed equipment * have it because the wizard or other monsters cursed it, so its * chances of having plusses is the same as usual.... */ obj->spe = rn2(10) ? (rn2(3) ? rn2(5) : rn1(4,4)) : -rnd(3); (void) mpickobj(mon, obj); } struct monst * mk_mplayer(ptr, x, y, special) register struct permonst *ptr; xchar x, y; register boolean special; { register struct monst *mtmp; char nam[PL_NSIZ]; if(!is_mplayer(ptr)) return((struct monst *)0); if(MON_AT(x, y)) (void) rloc(m_at(x, y), FALSE); /* insurance */ if(!In_endgame(&u.uz)) special = FALSE; if ((mtmp = makemon(ptr, x, y, NO_MM_FLAGS)) != 0) { short weapon = rn2(2) ? LONG_SWORD : rnd_class(SPEAR, BULLWHIP); short armor = rnd_class(GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL); short cloak = !rn2(8) ? STRANGE_OBJECT : rnd_class(OILSKIN_CLOAK, CLOAK_OF_DISPLACEMENT); short helm = !rn2(8) ? STRANGE_OBJECT : rnd_class(ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY); short shield = !rn2(8) ? STRANGE_OBJECT : rnd_class(ELVEN_SHIELD, SHIELD_OF_REFLECTION); int quan; struct obj *otmp; mtmp->m_lev = (special ? rn1(16,15) : rnd(16)); mtmp->mhp = mtmp->mhpmax = d((int)mtmp->m_lev,10) + (special ? (30 + rnd(30)) : 30); if(special) { get_mplname(mtmp, nam); mtmp = christen_monst(mtmp, nam); /* that's why they are "stuck" in the endgame :-) */ (void)mongets(mtmp, FAKE_AMULET_OF_YENDOR); } mtmp->mpeaceful = 0; set_malign(mtmp); /* peaceful may have changed again */ switch(monsndx(ptr)) { case PM_ARCHEOLOGIST: if (rn2(2)) weapon = BULLWHIP; break; case PM_BARBARIAN: if (rn2(2)) { weapon = rn2(2) ? TWO_HANDED_SWORD : BATTLE_AXE; shield = STRANGE_OBJECT; } if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL); if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT; break; case PM_CAVEMAN: case PM_CAVEWOMAN: if (rn2(4)) weapon = MACE; else if (rn2(2)) weapon = CLUB; if (helm == HELM_OF_BRILLIANCE) helm = STRANGE_OBJECT; break; case PM_HEALER: if (rn2(4)) weapon = QUARTERSTAFF; else if (rn2(2)) weapon = rn2(2) ? UNICORN_HORN : SCALPEL; if (rn2(4)) helm = rn2(2) ? HELM_OF_BRILLIANCE : HELM_OF_TELEPATHY; if (rn2(2)) shield = STRANGE_OBJECT; break; case PM_KNIGHT: if (rn2(4)) weapon = LONG_SWORD; if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL); break; case PM_MONK: weapon = STRANGE_OBJECT; armor = STRANGE_OBJECT; cloak = ROBE; if (rn2(2)) shield = STRANGE_OBJECT; break; case PM_PRIEST: case PM_PRIESTESS: if (rn2(2)) weapon = MACE; if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL); if (rn2(4)) cloak = ROBE; if (rn2(4)) helm = rn2(2) ? HELM_OF_BRILLIANCE : HELM_OF_TELEPATHY; if (rn2(2)) shield = STRANGE_OBJECT; break; case PM_RANGER: if (rn2(2)) weapon = ELVEN_DAGGER; break; case PM_ROGUE: if (rn2(2)) weapon = SHORT_SWORD; break; case PM_SAMURAI: if (rn2(2)) weapon = KATANA; break; #ifdef TOURIST case PM_TOURIST: /* Defaults are just fine */ break; #endif case PM_VALKYRIE: if (rn2(2)) weapon = WAR_HAMMER; if (rn2(2)) armor = rnd_class(PLATE_MAIL, CHAIN_MAIL); break; case PM_WIZARD: if (rn2(4)) weapon = rn2(2) ? QUARTERSTAFF : ATHAME; if (rn2(2)) { armor = rn2(2) ? BLACK_DRAGON_SCALE_MAIL : SILVER_DRAGON_SCALE_MAIL; cloak = CLOAK_OF_MAGIC_RESISTANCE; } if (rn2(4)) helm = HELM_OF_BRILLIANCE; shield = STRANGE_OBJECT; break; default: impossible("bad mplayer monster"); weapon = 0; break; } if (weapon != STRANGE_OBJECT) { otmp = mksobj(weapon, TRUE, FALSE); otmp->spe = (special ? rn1(5,4) : rn2(4)); if (!rn2(3)) otmp->oerodeproof = 1; else if (!rn2(2)) otmp->greased = 1; if (special && rn2(2)) otmp = mk_artifact(otmp, A_NONE); /* mplayers knew better than to overenchant Magicbane */ if (otmp->oartifact == ART_MAGICBANE) otmp->spe = rnd(4); (void) mpickobj(mtmp, otmp); } if(special) { if (!rn2(10)) (void) mongets(mtmp, rn2(3) ? LUCKSTONE : LOADSTONE); mk_mplayer_armor(mtmp, armor); mk_mplayer_armor(mtmp, cloak); mk_mplayer_armor(mtmp, helm); mk_mplayer_armor(mtmp, shield); if (rn2(8)) mk_mplayer_armor(mtmp, rnd_class(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY)); if (rn2(8)) mk_mplayer_armor(mtmp, rnd_class(LOW_BOOTS, LEVITATION_BOOTS)); m_dowear(mtmp, TRUE); quan = rn2(3) ? rn2(3) : rn2(16); while(quan--) (void)mongets(mtmp, rnd_class(DILITHIUM_CRYSTAL, JADE)); /* To get the gold "right" would mean a player can double his */ /* gold supply by killing one mplayer. Not good. */ #ifndef GOLDOBJ mtmp->mgold = rn2(1000); #else mkmonmoney(mtmp, rn2(1000)); #endif quan = rn2(10); while(quan--) (void) mpickobj(mtmp, mkobj(RANDOM_CLASS, FALSE)); } quan = rnd(3); while(quan--) (void)mongets(mtmp, rnd_offensive_item(mtmp)); quan = rnd(3); while(quan--) (void)mongets(mtmp, rnd_defensive_item(mtmp)); quan = rnd(3); while(quan--) (void)mongets(mtmp, rnd_misc_item(mtmp)); } return(mtmp); } /* create the indicated number (num) of monster-players, * randomly chosen, and in randomly chosen (free) locations * on the level. If "special", the size of num should not * be bigger than the number of _non-repeated_ names in the * developers array, otherwise a bunch of Adams and Eves will * fill up the overflow. */ void create_mplayers(num, special) register int num; boolean special; { int pm, x, y; struct monst fakemon; while(num) { int tryct = 0; /* roll for character class */ pm = PM_ARCHEOLOGIST + rn2(PM_WIZARD - PM_ARCHEOLOGIST + 1); fakemon.data = &mons[pm]; /* roll for an available location */ do { x = rn1(COLNO-4, 2); y = rnd(ROWNO-2); } while(!goodpos(x, y, &fakemon, 0) && tryct++ <= 50); /* if pos not found in 50 tries, don't bother to continue */ if(tryct > 50) return; (void) mk_mplayer(&mons[pm], (xchar)x, (xchar)y, special); num--; } } void mplayer_talk(mtmp) register struct monst *mtmp; { static const char *same_class_msg[3] = { "I can't win, and neither will you!", "You don't deserve to win!", "Mine should be the honor, not yours!", }, *other_class_msg[3] = { "The low-life wants to talk, eh?", "Fight, scum!", "Here is what I have to say!", }; if(mtmp->mpeaceful) return; /* will drop to humanoid talk */ pline("Talk? -- %s", (mtmp->data == &mons[urole.malenum] || mtmp->data == &mons[urole.femalenum]) ? same_class_msg[rn2(3)] : other_class_msg[rn2(3)]); } /*mplayer.c*/ nethack-3.4.3/src/mthrowu.c0100644000000000000000000005451707764735041014326 0ustar rootroot/* SCCS Id: @(#)mthrowu.c 3.4 2003/05/09 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL int FDECL(drop_throw,(struct obj *,BOOLEAN_P,int,int)); #define URETREATING(x,y) (distmin(u.ux,u.uy,x,y) > distmin(u.ux0,u.uy0,x,y)) #define POLE_LIM 5 /* How far monsters can use pole-weapons */ #ifndef OVLB STATIC_DCL const char *breathwep[]; #else /* OVLB */ /* * Keep consistent with breath weapons in zap.c, and AD_* in monattk.h. */ STATIC_OVL NEARDATA const char *breathwep[] = { "fragments", "fire", "frost", "sleep gas", "a disintegration blast", "lightning", "poison gas", "acid", "strange breath #8", "strange breath #9" }; /* hero is hit by something other than a monster */ int thitu(tlev, dam, obj, name) int tlev, dam; struct obj *obj; const char *name; /* if null, then format `obj' */ { const char *onm, *knm; boolean is_acid; int kprefix = KILLED_BY_AN; char onmbuf[BUFSZ], knmbuf[BUFSZ]; if (!name) { if (!obj) panic("thitu: name & obj both null?"); name = strcpy(onmbuf, (obj->quan > 1L) ? doname(obj) : mshot_xname(obj)); knm = strcpy(knmbuf, killer_xname(obj)); kprefix = KILLED_BY; /* killer_name supplies "an" if warranted */ } else { knm = name; /* [perhaps ought to check for plural here to] */ if (!strncmpi(name, "the ", 4) || !strncmpi(name, "an ", 3) || !strncmpi(name, "a ", 2)) kprefix = KILLED_BY; } onm = (obj && obj_is_pname(obj)) ? the(name) : (obj && obj->quan > 1L) ? name : an(name); is_acid = (obj && obj->otyp == ACID_VENOM); if(u.uac + tlev <= rnd(20)) { if(Blind || !flags.verbose) pline("It misses."); else You("are almost hit by %s.", onm); return(0); } else { if(Blind || !flags.verbose) You("are hit!"); else You("are hit by %s%s", onm, exclam(dam)); if (obj && objects[obj->otyp].oc_material == SILVER && hates_silver(youmonst.data)) { dam += rnd(20); pline_The("silver sears your flesh!"); exercise(A_CON, FALSE); } if (is_acid && Acid_resistance) pline("It doesn't seem to hurt you."); else { if (is_acid) pline("It burns!"); if (Half_physical_damage) dam = (dam+1) / 2; losehp(dam, knm, kprefix); exercise(A_STR, FALSE); } return(1); } } /* Be sure this corresponds with what happens to player-thrown objects in * dothrow.c (for consistency). --KAA * Returns 0 if object still exists (not destroyed). */ STATIC_OVL int drop_throw(obj, ohit, x, y) register struct obj *obj; boolean ohit; int x,y; { int retvalu = 1; int create; struct monst *mtmp; struct trap *t; if (obj->otyp == CREAM_PIE || obj->oclass == VENOM_CLASS || (ohit && obj->otyp == EGG)) create = 0; else if (ohit && (is_multigen(obj) || obj->otyp == ROCK)) create = !rn2(3); else create = 1; if (create && !((mtmp = m_at(x, y)) && (mtmp->mtrapped) && (t = t_at(x, y)) && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)))) { int objgone = 0; if (down_gate(x, y) != -1) objgone = ship_object(obj, x, y, FALSE); if (!objgone) { if (!flooreffects(obj,x,y,"fall")) { /* don't double-dip on damage */ place_object(obj, x, y); if (!mtmp && x == u.ux && y == u.uy) mtmp = &youmonst; if (mtmp && ohit) passive_obj(mtmp, obj, (struct attack *)0); stackobj(obj); retvalu = 0; } } } else obfree(obj, (struct obj*) 0); return retvalu; } #endif /* OVLB */ #ifdef OVL1 /* an object launched by someone/thing other than player attacks a monster; return 1 if the object has stopped moving (hit or its range used up) */ int ohitmon(mtmp, otmp, range, verbose) struct monst *mtmp; /* accidental target */ struct obj *otmp; /* missile; might be destroyed by drop_throw */ int range; /* how much farther will object travel if it misses */ /* Use -1 to signify to keep going even after hit, */ /* unless its gone (used for rolling_boulder_traps) */ boolean verbose; /* give message(s) even when you can't see what happened */ { int damage, tmp; boolean vis, ismimic; int objgone = 1; ismimic = mtmp->m_ap_type && mtmp->m_ap_type != M_AP_MONSTER; vis = cansee(bhitpos.x, bhitpos.y); tmp = 5 + find_mac(mtmp) + omon_adj(mtmp, otmp, FALSE); if (tmp < rnd(20)) { if (!ismimic) { if (vis) miss(distant_name(otmp, mshot_xname), mtmp); else if (verbose) pline("It is missed."); } if (!range) { /* Last position; object drops */ (void) drop_throw(otmp, 0, mtmp->mx, mtmp->my); return 1; } } else if (otmp->oclass == POTION_CLASS) { if (ismimic) seemimic(mtmp); mtmp->msleeping = 0; if (vis) otmp->dknown = 1; potionhit(mtmp, otmp, FALSE); return 1; } else { damage = dmgval(otmp, mtmp); if (otmp->otyp == ACID_VENOM && resists_acid(mtmp)) damage = 0; if (ismimic) seemimic(mtmp); mtmp->msleeping = 0; if (vis) hit(distant_name(otmp,mshot_xname), mtmp, exclam(damage)); else if (verbose) pline("%s is hit%s", Monnam(mtmp), exclam(damage)); if (otmp->opoisoned && is_poisonable(otmp)) { if (resists_poison(mtmp)) { if (vis) pline_The("poison doesn't seem to affect %s.", mon_nam(mtmp)); } else { if (rn2(30)) { damage += rnd(6); } else { if (vis) pline_The("poison was deadly..."); damage = mtmp->mhp; } } } if (objects[otmp->otyp].oc_material == SILVER && hates_silver(mtmp->data)) { if (vis) pline_The("silver sears %s flesh!", s_suffix(mon_nam(mtmp))); else if (verbose) pline("Its flesh is seared!"); } if (otmp->otyp == ACID_VENOM && cansee(mtmp->mx,mtmp->my)) { if (resists_acid(mtmp)) { if (vis || verbose) pline("%s is unaffected.", Monnam(mtmp)); damage = 0; } else { if (vis) pline_The("acid burns %s!", mon_nam(mtmp)); else if (verbose) pline("It is burned!"); } } mtmp->mhp -= damage; if (mtmp->mhp < 1) { if (vis || verbose) pline("%s is %s!", Monnam(mtmp), (nonliving(mtmp->data) || !canspotmon(mtmp)) ? "destroyed" : "killed"); /* don't blame hero for unknown rolling boulder trap */ if (!flags.mon_moving && (otmp->otyp != BOULDER || range >= 0 || !otmp->otrapped)) xkilled(mtmp,0); else mondied(mtmp); } if (can_blnd((struct monst*)0, mtmp, (uchar)(otmp->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP), otmp)) { if (vis && mtmp->mcansee) pline("%s is blinded by %s.", Monnam(mtmp), the(xname(otmp))); mtmp->mcansee = 0; tmp = (int)mtmp->mblinded + rnd(25) + 20; if (tmp > 127) tmp = 127; mtmp->mblinded = tmp; } objgone = drop_throw(otmp, 1, bhitpos.x, bhitpos.y); if (!objgone && range == -1) { /* special case */ obj_extract_self(otmp); /* free it for motion again */ return 0; } return 1; } return 0; } void m_throw(mon, x, y, dx, dy, range, obj) register struct monst *mon; register int x,y,dx,dy,range; /* direction and range */ register struct obj *obj; { register struct monst *mtmp; struct obj *singleobj; char sym = obj->oclass; int hitu, blindinc = 0; bhitpos.x = x; bhitpos.y = y; if (obj->quan == 1L) { /* * Remove object from minvent. This cannot be done later on; * what if the player dies before then, leaving the monster * with 0 daggers? (This caused the infamous 2^32-1 orcish * dagger bug). * * VENOM is not in minvent - it should already be OBJ_FREE. * The extract below does nothing. */ /* not possibly_unwield, which checks the object's */ /* location, not its existence */ if (MON_WEP(mon) == obj) { setmnotwielded(mon,obj); MON_NOWEP(mon); } obj_extract_self(obj); singleobj = obj; obj = (struct obj *) 0; } else { singleobj = splitobj(obj, 1L); obj_extract_self(singleobj); } singleobj->owornmask = 0; /* threw one of multiple weapons in hand? */ if (singleobj->cursed && (dx || dy) && !rn2(7)) { if(canseemon(mon) && flags.verbose) { if(is_ammo(singleobj)) pline("%s misfires!", Monnam(mon)); else pline("%s as %s throws it!", Tobjnam(singleobj, "slip"), mon_nam(mon)); } dx = rn2(3)-1; dy = rn2(3)-1; /* check validity of new direction */ if (!dx && !dy) { (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } } /* pre-check for doors, walls and boundaries. Also need to pre-check for bars regardless of direction; the random chance for small objects hitting bars is skipped when reaching them at point blank range */ if (!isok(bhitpos.x+dx,bhitpos.y+dy) || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ) || closed_door(bhitpos.x+dx, bhitpos.y+dy) || (levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS && hits_bars(&singleobj, bhitpos.x, bhitpos.y, 0, 0))) { (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); return; } /* Note: drop_throw may destroy singleobj. Since obj must be destroyed * early to avoid the dagger bug, anyone who modifies this code should * be careful not to use either one after it's been freed. */ if (sym) tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); while(range-- > 0) { /* Actually the loop is always exited by break */ bhitpos.x += dx; bhitpos.y += dy; if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { if (ohitmon(mtmp, singleobj, range, TRUE)) break; } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { if (multi) nomul(0); if (singleobj->oclass == GEM_CLASS && singleobj->otyp <= LAST_GEM+9 /* 9 glass colors */ && is_unicorn(youmonst.data)) { if (singleobj->otyp > LAST_GEM) { You("catch the %s.", xname(singleobj)); You("are not interested in %s junk.", s_suffix(mon_nam(mon))); makeknown(singleobj->otyp); dropy(singleobj); } else { You("accept %s gift in the spirit in which it was intended.", s_suffix(mon_nam(mon))); (void)hold_another_object(singleobj, "You catch, but drop, %s.", xname(singleobj), "You catch:"); } break; } if (singleobj->oclass == POTION_CLASS) { if (!Blind) singleobj->dknown = 1; potionhit(&youmonst, singleobj, FALSE); break; } switch(singleobj->otyp) { int dam, hitv; case EGG: if (!touch_petrifies(&mons[singleobj->corpsenm])) { impossible("monster throwing egg type %d", singleobj->corpsenm); hitu = 0; break; } /* fall through */ case CREAM_PIE: case BLINDING_VENOM: hitu = thitu(8, 0, singleobj, (char *)0); break; default: dam = dmgval(singleobj, &youmonst); hitv = 3 - distmin(u.ux,u.uy, mon->mx,mon->my); if (hitv < -4) hitv = -4; if (is_elf(mon->data) && objects[singleobj->otyp].oc_skill == P_BOW) { hitv++; if (MON_WEP(mon) && MON_WEP(mon)->otyp == ELVEN_BOW) hitv++; if(singleobj->otyp == ELVEN_ARROW) dam++; } if (bigmonst(youmonst.data)) hitv++; hitv += 8 + singleobj->spe; if (dam < 1) dam = 1; hitu = thitu(hitv, dam, singleobj, (char *)0); } if (hitu && singleobj->opoisoned && is_poisonable(singleobj)) { char onmbuf[BUFSZ], knmbuf[BUFSZ]; Strcpy(onmbuf, xname(singleobj)); Strcpy(knmbuf, killer_xname(singleobj)); poisoned(onmbuf, A_STR, knmbuf, -10); } if(hitu && can_blnd((struct monst*)0, &youmonst, (uchar)(singleobj->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP), singleobj)) { blindinc = rnd(25); if(singleobj->otyp == CREAM_PIE) { if(!Blind) pline("Yecch! You've been creamed."); else pline("There's %s sticky all over your %s.", something, body_part(FACE)); } else if(singleobj->otyp == BLINDING_VENOM) { int num_eyes = eyecount(youmonst.data); /* venom in the eyes */ if(!Blind) pline_The("venom blinds you."); else Your("%s sting%s.", (num_eyes == 1) ? body_part(EYE) : makeplural(body_part(EYE)), (num_eyes == 1) ? "s" : ""); } } if (hitu && singleobj->otyp == EGG) { if (!Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { Stoned = 5; killer = (char *) 0; } } stop_occupation(); if (hitu || !range) { (void) drop_throw(singleobj, hitu, u.ux, u.uy); break; } } else if (!range /* reached end of path */ /* missile hits edge of screen */ || !isok(bhitpos.x+dx,bhitpos.y+dy) /* missile hits the wall */ || IS_ROCK(levl[bhitpos.x+dx][bhitpos.y+dy].typ) /* missile hit closed door */ || closed_door(bhitpos.x+dx, bhitpos.y+dy) /* missile might hit iron bars */ || (levl[bhitpos.x+dx][bhitpos.y+dy].typ == IRONBARS && hits_bars(&singleobj, bhitpos.x, bhitpos.y, !rn2(5), 0)) #ifdef SINKS /* Thrown objects "sink" */ || IS_SINK(levl[bhitpos.x][bhitpos.y].typ) #endif ) { if (singleobj) /* hits_bars might have destroyed it */ (void) drop_throw(singleobj, 0, bhitpos.x, bhitpos.y); break; } tmp_at(bhitpos.x, bhitpos.y); delay_output(); } tmp_at(bhitpos.x, bhitpos.y); delay_output(); tmp_at(DISP_END, 0); if (blindinc) { u.ucreamed += blindinc; make_blinded(Blinded + (long)blindinc, FALSE); if (!Blind) Your(vision_clears); } } #endif /* OVL1 */ #ifdef OVLB /* Remove an item from the monster's inventory and destroy it. */ void m_useup(mon, obj) struct monst *mon; struct obj *obj; { if (obj->quan > 1L) { obj->quan--; obj->owt = weight(obj); } else { obj_extract_self(obj); possibly_unwield(mon, FALSE); if (obj->owornmask) { mon->misc_worn_check &= ~obj->owornmask; update_mon_intrinsics(mon, obj, FALSE, FALSE); } obfree(obj, (struct obj*) 0); } } #endif /* OVLB */ #ifdef OVL1 /* monster attempts ranged weapon attack against player */ void thrwmu(mtmp) struct monst *mtmp; { struct obj *otmp, *mwep; xchar x, y; schar skill; int multishot; const char *onm; /* Rearranged beginning so monsters can use polearms not in a line */ if (mtmp->weapon_check == NEED_WEAPON || !MON_WEP(mtmp)) { mtmp->weapon_check = NEED_RANGED_WEAPON; /* mon_wield_item resets weapon_check as appropriate */ if(mon_wield_item(mtmp) != 0) return; } /* Pick a weapon */ otmp = select_rwep(mtmp); if (!otmp) return; if (is_pole(otmp)) { int dam, hitv; if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) > POLE_LIM || !couldsee(mtmp->mx, mtmp->my)) return; /* Out of range, or intervening wall */ if (canseemon(mtmp)) { onm = xname(otmp); pline("%s thrusts %s.", Monnam(mtmp), obj_is_pname(otmp) ? the(onm) : an(onm)); } dam = dmgval(otmp, &youmonst); hitv = 3 - distmin(u.ux,u.uy, mtmp->mx,mtmp->my); if (hitv < -4) hitv = -4; if (bigmonst(youmonst.data)) hitv++; hitv += 8 + otmp->spe; if (dam < 1) dam = 1; (void) thitu(hitv, dam, otmp, (char *)0); stop_occupation(); return; } x = mtmp->mx; y = mtmp->my; /* If you are coming toward the monster, the monster * should try to soften you up with missiles. If you are * going away, you are probably hurt or running. Give * chase, but if you are getting too far away, throw. */ if (!lined_up(mtmp) || (URETREATING(x,y) && rn2(BOLT_LIM - distmin(x,y,mtmp->mux,mtmp->muy)))) return; skill = objects[otmp->otyp].oc_skill; mwep = MON_WEP(mtmp); /* wielded weapon */ /* Multishot calculations */ multishot = 1; if ((ammo_and_launcher(otmp, mwep) || skill == P_DAGGER || skill == -P_DART || skill == -P_SHURIKEN) && !mtmp->mconf) { /* Assumes lords are skilled, princes are expert */ if (is_prince(mtmp->data)) multishot += 2; else if (is_lord(mtmp->data)) multishot++; switch (monsndx(mtmp->data)) { case PM_RANGER: multishot++; break; case PM_ROGUE: if (skill == P_DAGGER) multishot++; break; case PM_NINJA: case PM_SAMURAI: if (otmp->otyp == YA && mwep && mwep->otyp == YUMI) multishot++; break; default: break; } /* racial bonus */ if ((is_elf(mtmp->data) && otmp->otyp == ELVEN_ARROW && mwep && mwep->otyp == ELVEN_BOW) || (is_orc(mtmp->data) && otmp->otyp == ORCISH_ARROW && mwep && mwep->otyp == ORCISH_BOW)) multishot++; if ((long)multishot > otmp->quan) multishot = (int)otmp->quan; if (multishot < 1) multishot = 1; else multishot = rnd(multishot); } if (canseemon(mtmp)) { char onmbuf[BUFSZ]; if (multishot > 1) { /* "N arrows"; multishot > 1 implies otmp->quan > 1, so xname()'s result will already be pluralized */ Sprintf(onmbuf, "%d %s", multishot, xname(otmp)); onm = onmbuf; } else { /* "an arrow" */ onm = singular(otmp, xname); onm = obj_is_pname(otmp) ? the(onm) : an(onm); } m_shot.s = ammo_and_launcher(otmp,mwep) ? TRUE : FALSE; pline("%s %s %s!", Monnam(mtmp), m_shot.s ? "shoots" : "throws", onm); m_shot.o = otmp->otyp; } else { m_shot.o = STRANGE_OBJECT; /* don't give multishot feedback */ } m_shot.n = multishot; for (m_shot.i = 1; m_shot.i <= m_shot.n; m_shot.i++) m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), distmin(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy), otmp); m_shot.n = m_shot.i = 0; m_shot.o = STRANGE_OBJECT; m_shot.s = FALSE; nomul(0); } #endif /* OVL1 */ #ifdef OVLB int spitmu(mtmp, mattk) /* monster spits substance at you */ register struct monst *mtmp; register struct attack *mattk; { register struct obj *otmp; if(mtmp->mcan) { if(flags.soundok) pline("A dry rattle comes from %s throat.", s_suffix(mon_nam(mtmp))); return 0; } if(lined_up(mtmp)) { switch (mattk->adtyp) { case AD_BLND: case AD_DRST: otmp = mksobj(BLINDING_VENOM, TRUE, FALSE); break; default: impossible("bad attack type in spitmu"); /* fall through */ case AD_ACID: otmp = mksobj(ACID_VENOM, TRUE, FALSE); break; } if(!rn2(BOLT_LIM-distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy))) { if (canseemon(mtmp)) pline("%s spits venom!", Monnam(mtmp)); m_throw(mtmp, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby), distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp); nomul(0); return 0; } } return 0; } #endif /* OVLB */ #ifdef OVL1 int breamu(mtmp, mattk) /* monster breathes at you (ranged) */ register struct monst *mtmp; register struct attack *mattk; { /* if new breath types are added, change AD_ACID to max type */ int typ = (mattk->adtyp == AD_RBRE) ? rnd(AD_ACID) : mattk->adtyp ; if(lined_up(mtmp)) { if(mtmp->mcan) { if(flags.soundok) { if(canseemon(mtmp)) pline("%s coughs.", Monnam(mtmp)); else You_hear("a cough."); } return(0); } if(!mtmp->mspec_used && rn2(3)) { if((typ >= AD_MAGM) && (typ <= AD_ACID)) { if(canseemon(mtmp)) pline("%s breathes %s!", Monnam(mtmp), breathwep[typ-1]); buzz((int) (-20 - (typ-1)), (int)mattk->damn, mtmp->mx, mtmp->my, sgn(tbx), sgn(tby)); nomul(0); /* breath runs out sometimes. Also, give monster some * cunning; don't breath if the player fell asleep. */ if(!rn2(3)) mtmp->mspec_used = 10+rn2(20); if(typ == AD_SLEE && !Sleep_resistance) mtmp->mspec_used += rnd(20); } else impossible("Breath weapon %d used", typ-1); } } return(1); } boolean linedup(ax, ay, bx, by) register xchar ax, ay, bx, by; { tbx = ax - bx; /* These two values are set for use */ tby = ay - by; /* after successful return. */ /* sometimes displacement makes a monster think that you're at its own location; prevent it from throwing and zapping in that case */ if (!tbx && !tby) return FALSE; if((!tbx || !tby || abs(tbx) == abs(tby)) /* straight line or diagonal */ && distmin(tbx, tby, 0, 0) < BOLT_LIM) { if(ax == u.ux && ay == u.uy) return((boolean)(couldsee(bx,by))); else if(clear_path(ax,ay,bx,by)) return TRUE; } return FALSE; } boolean lined_up(mtmp) /* is mtmp in position to use ranged attack? */ register struct monst *mtmp; { return(linedup(mtmp->mux,mtmp->muy,mtmp->mx,mtmp->my)); } #endif /* OVL1 */ #ifdef OVL0 /* Check if a monster is carrying a particular item. */ struct obj * m_carrying(mtmp, type) struct monst *mtmp; int type; { register struct obj *otmp; for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if(otmp->otyp == type) return(otmp); return((struct obj *) 0); } /* TRUE iff thrown/kicked/rolled object doesn't pass through iron bars */ boolean hits_bars(obj_p, x, y, always_hit, whodidit) struct obj **obj_p; /* *obj_p will be set to NULL if object breaks */ int x, y; int always_hit; /* caller can force a hit for items which would fit through */ int whodidit; /* 1==hero, 0=other, -1==just check whether it'll pass thru */ { struct obj *otmp = *obj_p; int obj_type = otmp->otyp; boolean hits = always_hit; if (!hits) switch (otmp->oclass) { case WEAPON_CLASS: { int oskill = objects[obj_type].oc_skill; hits = (oskill != -P_BOW && oskill != -P_CROSSBOW && oskill != -P_DART && oskill != -P_SHURIKEN && oskill != P_SPEAR && oskill != P_JAVELIN && oskill != P_KNIFE); /* but not dagger */ break; } case ARMOR_CLASS: hits = (objects[obj_type].oc_armcat != ARM_GLOVES); break; case TOOL_CLASS: hits = (obj_type != SKELETON_KEY && obj_type != LOCK_PICK && #ifdef TOURIST obj_type != CREDIT_CARD && #endif obj_type != TALLOW_CANDLE && obj_type != WAX_CANDLE && obj_type != LENSES && obj_type != TIN_WHISTLE && obj_type != MAGIC_WHISTLE); break; case ROCK_CLASS: /* includes boulder */ if (obj_type != STATUE || mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE; break; case FOOD_CLASS: if (obj_type == CORPSE && mons[otmp->corpsenm].msize > MZ_TINY) hits = TRUE; else hits = (obj_type == MEAT_STICK || obj_type == HUGE_CHUNK_OF_MEAT); break; case SPBOOK_CLASS: case WAND_CLASS: case BALL_CLASS: case CHAIN_CLASS: hits = TRUE; break; default: break; } if (hits && whodidit != -1) { if (whodidit ? hero_breaks(otmp, x, y, FALSE) : breaks(otmp, x, y)) *obj_p = otmp = 0; /* object is now gone */ /* breakage makes its own noises */ else if (obj_type == BOULDER || obj_type == HEAVY_IRON_BALL) pline("Whang!"); else if (otmp->oclass == COIN_CLASS || objects[obj_type].oc_material == GOLD || objects[obj_type].oc_material == SILVER) pline("Clink!"); else pline("Clonk!"); } return hits; } #endif /* OVL0 */ /*mthrowu.c*/ nethack-3.4.3/src/muse.c0100644000000000000000000017552207764735041013572 0ustar rootroot/* SCCS Id: @(#)muse.c 3.4 2002/12/23 */ /* Copyright (C) 1990 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ /* * Monster item usage routines. */ #include "hack.h" #include "edog.h" extern const int monstr[]; boolean m_using = FALSE; /* Let monsters use magic items. Arbitrary assumptions: Monsters only use * scrolls when they can see, monsters know when wands have 0 charges, monsters * cannot recognize if items are cursed are not, monsters which are confused * don't know not to read scrolls, etc.... */ STATIC_DCL struct permonst *FDECL(muse_newcham_mon, (struct monst *)); STATIC_DCL int FDECL(precheck, (struct monst *,struct obj *)); STATIC_DCL void FDECL(mzapmsg, (struct monst *,struct obj *,BOOLEAN_P)); STATIC_DCL void FDECL(mreadmsg, (struct monst *,struct obj *)); STATIC_DCL void FDECL(mquaffmsg, (struct monst *,struct obj *)); STATIC_PTR int FDECL(mbhitm, (struct monst *,struct obj *)); STATIC_DCL void FDECL(mbhit, (struct monst *,int,int FDECL((*),(MONST_P,OBJ_P)), int FDECL((*),(OBJ_P,OBJ_P)),struct obj *)); STATIC_DCL void FDECL(you_aggravate, (struct monst *)); STATIC_DCL void FDECL(mon_consume_unstone, (struct monst *,struct obj *, BOOLEAN_P,BOOLEAN_P)); static struct musable { struct obj *offensive; struct obj *defensive; struct obj *misc; int has_offense, has_defense, has_misc; /* =0, no capability; otherwise, different numbers. * If it's an object, the object is also set (it's 0 otherwise). */ } m; static int trapx, trapy; static boolean zap_oseen; /* for wands which use mbhitm and are zapped at players. We usually * want an oseen local to the function, but this is impossible since the * function mbhitm has to be compatible with the normal zap routines, * and those routines don't remember who zapped the wand. */ /* Any preliminary checks which may result in the monster being unable to use * the item. Returns 0 if nothing happened, 2 if the monster can't do anything * (i.e. it teleported) and 1 if it's dead. */ STATIC_OVL int precheck(mon, obj) struct monst *mon; struct obj *obj; { boolean vis; if (!obj) return 0; vis = cansee(mon->mx, mon->my); if (obj->oclass == POTION_CLASS) { coord cc; static const char *empty = "The potion turns out to be empty."; const char *potion_descr; struct monst *mtmp; #define POTION_OCCUPANT_CHANCE(n) (13 + 2*(n)) /* also in potion.c */ potion_descr = OBJ_DESCR(objects[obj->otyp]); if (potion_descr && !strcmp(potion_descr, "milky")) { if ( flags.ghost_count < MAXMONNO && !rn2(POTION_OCCUPANT_CHANCE(flags.ghost_count))) { if (!enexto(&cc, mon->mx, mon->my, &mons[PM_GHOST])) return 0; mquaffmsg(mon, obj); m_useup(mon, obj); mtmp = makemon(&mons[PM_GHOST], cc.x, cc.y, NO_MM_FLAGS); if (!mtmp) { if (vis) pline(empty); } else { if (vis) { pline("As %s opens the bottle, an enormous %s emerges!", mon_nam(mon), Hallucination ? rndmonnam() : (const char *)"ghost"); pline("%s is frightened to death, and unable to move.", Monnam(mon)); } mon->mcanmove = 0; mon->mfrozen = 3; } return 2; } } if (potion_descr && !strcmp(potion_descr, "smoky") && flags.djinni_count < MAXMONNO && !rn2(POTION_OCCUPANT_CHANCE(flags.djinni_count))) { if (!enexto(&cc, mon->mx, mon->my, &mons[PM_DJINNI])) return 0; mquaffmsg(mon, obj); m_useup(mon, obj); mtmp = makemon(&mons[PM_DJINNI], cc.x, cc.y, NO_MM_FLAGS); if (!mtmp) { if (vis) pline(empty); } else { if (vis) pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp)); pline("%s speaks.", vis ? Monnam(mtmp) : Something); /* I suspect few players will be upset that monsters */ /* can't wish for wands of death here.... */ if (rn2(2)) { verbalize("You freed me!"); mtmp->mpeaceful = 1; set_malign(mtmp); } else { verbalize("It is about time."); if (vis) pline("%s vanishes.", Monnam(mtmp)); mongone(mtmp); } } return 2; } } if (obj->oclass == WAND_CLASS && obj->cursed && !rn2(100)) { int dam = d(obj->spe+2, 6); if (flags.soundok) { if (vis) pline("%s zaps %s, which suddenly explodes!", Monnam(mon), an(xname(obj))); else You_hear("a zap and an explosion in the distance."); } m_useup(mon, obj); if (mon->mhp <= dam) { monkilled(mon, "", AD_RBRE); return 1; } else mon->mhp -= dam; m.has_defense = m.has_offense = m.has_misc = 0; /* Only one needed to be set to 0 but the others are harmless */ } return 0; } STATIC_OVL void mzapmsg(mtmp, otmp, self) struct monst *mtmp; struct obj *otmp; boolean self; { if (!canseemon(mtmp)) { if (flags.soundok) You_hear("a %s zap.", (distu(mtmp->mx,mtmp->my) <= (BOLT_LIM+1)*(BOLT_LIM+1)) ? "nearby" : "distant"); } else if (self) pline("%s zaps %sself with %s!", Monnam(mtmp), mhim(mtmp), doname(otmp)); else { pline("%s zaps %s!", Monnam(mtmp), an(xname(otmp))); stop_occupation(); } } STATIC_OVL void mreadmsg(mtmp, otmp) struct monst *mtmp; struct obj *otmp; { boolean vismon = canseemon(mtmp); char onambuf[BUFSZ]; short saverole; unsigned savebknown; if (!vismon && !flags.soundok) return; /* no feedback */ otmp->dknown = 1; /* seeing or hearing it read reveals its label */ /* shouldn't be able to hear curse/bless status of unseen scrolls; for priest characters, bknown will always be set during naming */ savebknown = otmp->bknown; saverole = Role_switch; if (!vismon) { otmp->bknown = 0; if (Role_if(PM_PRIEST)) Role_switch = 0; } Strcpy(onambuf, singular(otmp, doname)); Role_switch = saverole; otmp->bknown = savebknown; if (vismon) pline("%s reads %s!", Monnam(mtmp), onambuf); else You_hear("%s reading %s.", x_monnam(mtmp, ARTICLE_A, (char *)0, (SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_SADDLE), FALSE), onambuf); if (mtmp->mconf) pline("Being confused, %s mispronounces the magic words...", vismon ? mon_nam(mtmp) : mhe(mtmp)); } STATIC_OVL void mquaffmsg(mtmp, otmp) struct monst *mtmp; struct obj *otmp; { if (canseemon(mtmp)) { otmp->dknown = 1; pline("%s drinks %s!", Monnam(mtmp), singular(otmp, doname)); } else if (flags.soundok) You_hear("a chugging sound."); } /* Defines for various types of stuff. The order in which monsters prefer * to use them is determined by the order of the code logic, not the * numerical order in which they are defined. */ #define MUSE_SCR_TELEPORTATION 1 #define MUSE_WAN_TELEPORTATION_SELF 2 #define MUSE_POT_HEALING 3 #define MUSE_POT_EXTRA_HEALING 4 #define MUSE_WAN_DIGGING 5 #define MUSE_TRAPDOOR 6 #define MUSE_TELEPORT_TRAP 7 #define MUSE_UPSTAIRS 8 #define MUSE_DOWNSTAIRS 9 #define MUSE_WAN_CREATE_MONSTER 10 #define MUSE_SCR_CREATE_MONSTER 11 #define MUSE_UP_LADDER 12 #define MUSE_DN_LADDER 13 #define MUSE_SSTAIRS 14 #define MUSE_WAN_TELEPORTATION 15 #define MUSE_BUGLE 16 #define MUSE_UNICORN_HORN 17 #define MUSE_POT_FULL_HEALING 18 #define MUSE_LIZARD_CORPSE 19 /* #define MUSE_INNATE_TPT 9999 * We cannot use this. Since monsters get unlimited teleportation, if they * were allowed to teleport at will you could never catch them. Instead, * assume they only teleport at random times, despite the inconsistency that if * you polymorph into one you teleport at will. */ /* Select a defensive item/action for a monster. Returns TRUE iff one is * found. */ boolean find_defensive(mtmp) struct monst *mtmp; { register struct obj *obj = 0; struct trap *t; int x=mtmp->mx, y=mtmp->my; boolean stuck = (mtmp == u.ustuck); boolean immobile = (mtmp->data->mmove == 0); int fraction; if (is_animal(mtmp->data) || mindless(mtmp->data)) return FALSE; if(dist2(x, y, mtmp->mux, mtmp->muy) > 25) return FALSE; if (u.uswallow && stuck) return FALSE; m.defensive = (struct obj *)0; m.has_defense = 0; /* since unicorn horns don't get used up, the monster would look * silly trying to use the same cursed horn round after round */ if (mtmp->mconf || mtmp->mstun || !mtmp->mcansee) { if (!is_unicorn(mtmp->data) && !nohands(mtmp->data)) { for(obj = mtmp->minvent; obj; obj = obj->nobj) if (obj->otyp == UNICORN_HORN && !obj->cursed) break; } if (obj || is_unicorn(mtmp->data)) { m.defensive = obj; m.has_defense = MUSE_UNICORN_HORN; return TRUE; } } if (mtmp->mconf) { for(obj = mtmp->minvent; obj; obj = obj->nobj) { if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD) { m.defensive = obj; m.has_defense = MUSE_LIZARD_CORPSE; return TRUE; } } } /* It so happens there are two unrelated cases when we might want to * check specifically for healing alone. The first is when the monster * is blind (healing cures blindness). The second is when the monster * is peaceful; then we don't want to flee the player, and by * coincidence healing is all there is that doesn't involve fleeing. * These would be hard to combine because of the control flow. * Pestilence won't use healing even when blind. */ if (!mtmp->mcansee && !nohands(mtmp->data) && mtmp->data != &mons[PM_PESTILENCE]) { if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_FULL_HEALING; return TRUE; } if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_EXTRA_HEALING; return TRUE; } if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_HEALING; return TRUE; } } fraction = u.ulevel < 10 ? 5 : u.ulevel < 14 ? 4 : 3; if(mtmp->mhp >= mtmp->mhpmax || (mtmp->mhp >= 10 && mtmp->mhp*fraction >= mtmp->mhpmax)) return FALSE; if (mtmp->mpeaceful) { if (!nohands(mtmp->data)) { if ((obj = m_carrying(mtmp, POT_FULL_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_FULL_HEALING; return TRUE; } if ((obj = m_carrying(mtmp, POT_EXTRA_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_EXTRA_HEALING; return TRUE; } if ((obj = m_carrying(mtmp, POT_HEALING)) != 0) { m.defensive = obj; m.has_defense = MUSE_POT_HEALING; return TRUE; } } return FALSE; } if (levl[x][y].typ == STAIRS && !stuck && !immobile) { if (x == xdnstair && y == ydnstair && !is_floater(mtmp->data)) m.has_defense = MUSE_DOWNSTAIRS; if (x == xupstair && y == yupstair && ledger_no(&u.uz) != 1) /* Unfair to let the monsters leave the dungeon with the Amulet */ /* (or go to the endlevel since you also need it, to get there) */ m.has_defense = MUSE_UPSTAIRS; } else if (levl[x][y].typ == LADDER && !stuck && !immobile) { if (x == xupladder && y == yupladder) m.has_defense = MUSE_UP_LADDER; if (x == xdnladder && y == ydnladder && !is_floater(mtmp->data)) m.has_defense = MUSE_DN_LADDER; } else if (sstairs.sx && sstairs.sx == x && sstairs.sy == y) { m.has_defense = MUSE_SSTAIRS; } else if (!stuck && !immobile) { /* Note: trap doors take precedence over teleport traps. */ int xx, yy; for(xx = x-1; xx <= x+1; xx++) for(yy = y-1; yy <= y+1; yy++) if (isok(xx,yy)) if (xx != u.ux && yy != u.uy) if (mtmp->data != &mons[PM_GRID_BUG] || xx == x || yy == y) if ((xx==x && yy==y) || !level.monsters[xx][yy]) if ((t = t_at(xx,yy)) != 0) if ((verysmall(mtmp->data) || throws_rocks(mtmp->data) || passes_walls(mtmp->data)) || !sobj_at(BOULDER, xx, yy)) if (!onscary(xx,yy,mtmp)) { if ((t->ttyp == TRAPDOOR || t->ttyp == HOLE) && !is_floater(mtmp->data) && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest && Can_fall_thru(&u.uz) ) { trapx = xx; trapy = yy; m.has_defense = MUSE_TRAPDOOR; } else if (t->ttyp == TELEP_TRAP && m.has_defense != MUSE_TRAPDOOR) { trapx = xx; trapy = yy; m.has_defense = MUSE_TELEPORT_TRAP; } } } if (nohands(mtmp->data)) /* can't use objects */ goto botm; if (is_mercenary(mtmp->data) && (obj = m_carrying(mtmp, BUGLE))) { int xx, yy; struct monst *mon; /* Distance is arbitrary. What we really want to do is * have the soldier play the bugle when it sees or * remembers soldiers nearby... */ for(xx = x-3; xx <= x+3; xx++) for(yy = y-3; yy <= y+3; yy++) if (isok(xx,yy)) if ((mon = m_at(xx,yy)) && is_mercenary(mon->data) && mon->data != &mons[PM_GUARD] && (mon->msleeping || (!mon->mcanmove))) { m.defensive = obj; m.has_defense = MUSE_BUGLE; } } /* use immediate physical escape prior to attempting magic */ if (m.has_defense) /* stairs, trap door or tele-trap, bugle alert */ goto botm; /* kludge to cut down on trap destruction (particularly portals) */ t = t_at(x,y); if (t && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == WEB || t->ttyp == BEAR_TRAP)) t = 0; /* ok for monster to dig here */ #define nomore(x) if(m.has_defense==x) continue; for (obj = mtmp->minvent; obj; obj = obj->nobj) { /* don't always use the same selection pattern */ if (m.has_defense && !rn2(3)) break; /* nomore(MUSE_WAN_DIGGING); */ if (m.has_defense == MUSE_WAN_DIGGING) break; if (obj->otyp == WAN_DIGGING && obj->spe > 0 && !stuck && !t && !mtmp->isshk && !mtmp->isgd && !mtmp->ispriest && !is_floater(mtmp->data) /* monsters digging in Sokoban can ruin things */ && !In_sokoban(&u.uz) /* digging wouldn't be effective; assume they know that */ && !(levl[x][y].wall_info & W_NONDIGGABLE) && !(Is_botlevel(&u.uz) || In_endgame(&u.uz)) && !(is_ice(x,y) || is_pool(x,y) || is_lava(x,y)) && !(mtmp->data == &mons[PM_VLAD_THE_IMPALER] && In_V_tower(&u.uz))) { m.defensive = obj; m.has_defense = MUSE_WAN_DIGGING; } nomore(MUSE_WAN_TELEPORTATION_SELF); nomore(MUSE_WAN_TELEPORTATION); if(obj->otyp == WAN_TELEPORTATION && obj->spe > 0) { /* use the TELEP_TRAP bit to determine if they know * about noteleport on this level or not. Avoids * ineffective re-use of teleportation. This does * mean if the monster leaves the level, they'll know * about teleport traps. */ if (!level.flags.noteleport || !(mtmp->mtrapseen & (1 << (TELEP_TRAP-1)))) { m.defensive = obj; m.has_defense = (mon_has_amulet(mtmp)) ? MUSE_WAN_TELEPORTATION : MUSE_WAN_TELEPORTATION_SELF; } } nomore(MUSE_SCR_TELEPORTATION); if(obj->otyp == SCR_TELEPORTATION && mtmp->mcansee && haseyes(mtmp->data) && (!obj->cursed || (!(mtmp->isshk && inhishop(mtmp)) && !mtmp->isgd && !mtmp->ispriest))) { /* see WAN_TELEPORTATION case above */ if (!level.flags.noteleport || !(mtmp->mtrapseen & (1 << (TELEP_TRAP-1)))) { m.defensive = obj; m.has_defense = MUSE_SCR_TELEPORTATION; } } if (mtmp->data != &mons[PM_PESTILENCE]) { nomore(MUSE_POT_FULL_HEALING); if(obj->otyp == POT_FULL_HEALING) { m.defensive = obj; m.has_defense = MUSE_POT_FULL_HEALING; } nomore(MUSE_POT_EXTRA_HEALING); if(obj->otyp == POT_EXTRA_HEALING) { m.defensive = obj; m.has_defense = MUSE_POT_EXTRA_HEALING; } nomore(MUSE_WAN_CREATE_MONSTER); if(obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) { m.defensive = obj; m.has_defense = MUSE_WAN_CREATE_MONSTER; } nomore(MUSE_POT_HEALING); if(obj->otyp == POT_HEALING) { m.defensive = obj; m.has_defense = MUSE_POT_HEALING; } } else { /* Pestilence */ nomore(MUSE_POT_FULL_HEALING); if (obj->otyp == POT_SICKNESS) { m.defensive = obj; m.has_defense = MUSE_POT_FULL_HEALING; } nomore(MUSE_WAN_CREATE_MONSTER); if (obj->otyp == WAN_CREATE_MONSTER && obj->spe > 0) { m.defensive = obj; m.has_defense = MUSE_WAN_CREATE_MONSTER; } } nomore(MUSE_SCR_CREATE_MONSTER); if(obj->otyp == SCR_CREATE_MONSTER) { m.defensive = obj; m.has_defense = MUSE_SCR_CREATE_MONSTER; } } botm: return((boolean)(!!m.has_defense)); #undef nomore } /* Perform a defensive action for a monster. Must be called immediately * after find_defensive(). Return values are 0: did something, 1: died, * 2: did something and can't attack again (i.e. teleported). */ int use_defensive(mtmp) struct monst *mtmp; { int i, fleetim, how = 0; struct obj *otmp = m.defensive; boolean vis, vismon, oseen; const char *mcsa = "%s can see again."; if ((i = precheck(mtmp, otmp)) != 0) return i; vis = cansee(mtmp->mx, mtmp->my); vismon = canseemon(mtmp); oseen = otmp && vismon; /* when using defensive choice to run away, we want monster to avoid rushing right straight back; don't override if already scared */ fleetim = !mtmp->mflee ? (33 - (30 * mtmp->mhp / mtmp->mhpmax)) : 0; #define m_flee(m) if (fleetim && !m->iswiz) \ { monflee(m, fleetim, FALSE, FALSE); } switch(m.has_defense) { case MUSE_UNICORN_HORN: if (vismon) { if (otmp) pline("%s uses a unicorn horn!", Monnam(mtmp)); else pline_The("tip of %s's horn glows!", mon_nam(mtmp)); } if (!mtmp->mcansee) { mtmp->mcansee = 1; mtmp->mblinded = 0; if (vismon) pline(mcsa, Monnam(mtmp)); } else if (mtmp->mconf || mtmp->mstun) { mtmp->mconf = mtmp->mstun = 0; if (vismon) pline("%s seems steadier now.", Monnam(mtmp)); } else impossible("No need for unicorn horn?"); return 2; case MUSE_BUGLE: if (vismon) pline("%s plays %s!", Monnam(mtmp), doname(otmp)); else if (flags.soundok) You_hear("a bugle playing reveille!"); awaken_soldiers(); return 2; case MUSE_WAN_TELEPORTATION_SELF: if ((mtmp->isshk && inhishop(mtmp)) || mtmp->isgd || mtmp->ispriest) return 2; m_flee(mtmp); mzapmsg(mtmp, otmp, TRUE); otmp->spe--; how = WAN_TELEPORTATION; mon_tele: if (tele_restrict(mtmp)) { /* mysterious force... */ if (vismon && how) /* mentions 'teleport' */ makeknown(how); /* monster learns that teleportation isn't useful here */ if (level.flags.noteleport) mtmp->mtrapseen |= (1 << (TELEP_TRAP-1)); return 2; } if (( #if 0 mon_has_amulet(mtmp) || #endif On_W_tower_level(&u.uz)) && !rn2(3)) { if (vismon) pline("%s seems disoriented for a moment.", Monnam(mtmp)); return 2; } if (oseen && how) makeknown(how); (void) rloc(mtmp, FALSE); return 2; case MUSE_WAN_TELEPORTATION: zap_oseen = oseen; mzapmsg(mtmp, otmp, FALSE); otmp->spe--; m_using = TRUE; mbhit(mtmp,rn1(8,6),mbhitm,bhito,otmp); /* monster learns that teleportation isn't useful here */ if (level.flags.noteleport) mtmp->mtrapseen |= (1 << (TELEP_TRAP-1)); m_using = FALSE; return 2; case MUSE_SCR_TELEPORTATION: { int obj_is_cursed = otmp->cursed; if (mtmp->isshk || mtmp->isgd || mtmp->ispriest) return 2; m_flee(mtmp); mreadmsg(mtmp, otmp); m_useup(mtmp, otmp); /* otmp might be free'ed */ how = SCR_TELEPORTATION; if (obj_is_cursed || mtmp->mconf) { int nlev; d_level flev; if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { if (vismon) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); return 2; } nlev = random_teleport_level(); if (nlev == depth(&u.uz)) { if (vismon) pline("%s shudders for a moment.", Monnam(mtmp)); return 2; } get_level(&flev, nlev); migrate_to_level(mtmp, ledger_no(&flev), MIGR_RANDOM, (coord *)0); if (oseen) makeknown(SCR_TELEPORTATION); } else goto mon_tele; return 2; } case MUSE_WAN_DIGGING: { struct trap *ttmp; m_flee(mtmp); mzapmsg(mtmp, otmp, FALSE); otmp->spe--; if (oseen) makeknown(WAN_DIGGING); if (IS_FURNITURE(levl[mtmp->mx][mtmp->my].typ) || IS_DRAWBRIDGE(levl[mtmp->mx][mtmp->my].typ) || (is_drawbridge_wall(mtmp->mx, mtmp->my) >= 0) || (sstairs.sx && sstairs.sx == mtmp->mx && sstairs.sy == mtmp->my)) { pline_The("digging ray is ineffective."); return 2; } if (!Can_dig_down(&u.uz)) { if(canseemon(mtmp)) pline_The("%s here is too hard to dig in.", surface(mtmp->mx, mtmp->my)); return 2; } ttmp = maketrap(mtmp->mx, mtmp->my, HOLE); if (!ttmp) return 2; seetrap(ttmp); if (vis) { pline("%s has made a hole in the %s.", Monnam(mtmp), surface(mtmp->mx, mtmp->my)); pline("%s %s through...", Monnam(mtmp), is_flyer(mtmp->data) ? "dives" : "falls"); } else if (flags.soundok) You_hear("%s crash through the %s.", something, surface(mtmp->mx, mtmp->my)); /* we made sure that there is a level for mtmp to go to */ migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM, (coord *)0); return 2; } case MUSE_WAN_CREATE_MONSTER: { coord cc; /* pm: 0 => random, eel => aquatic, croc => amphibious */ struct permonst *pm = !is_pool(mtmp->mx, mtmp->my) ? 0 : &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE]; struct monst *mon; if (!enexto(&cc, mtmp->mx, mtmp->my, pm)) return 0; mzapmsg(mtmp, otmp, FALSE); otmp->spe--; mon = makemon((struct permonst *)0, cc.x, cc.y, NO_MM_FLAGS); if (mon && canspotmon(mon) && oseen) makeknown(WAN_CREATE_MONSTER); return 2; } case MUSE_SCR_CREATE_MONSTER: { coord cc; struct permonst *pm = 0, *fish = 0; int cnt = 1; struct monst *mon; boolean known = FALSE; if (!rn2(73)) cnt += rnd(4); if (mtmp->mconf || otmp->cursed) cnt += 12; if (mtmp->mconf) pm = fish = &mons[PM_ACID_BLOB]; else if (is_pool(mtmp->mx, mtmp->my)) fish = &mons[u.uinwater ? PM_GIANT_EEL : PM_CROCODILE]; mreadmsg(mtmp, otmp); while(cnt--) { /* `fish' potentially gives bias towards water locations; `pm' is what to actually create (0 => random) */ if (!enexto(&cc, mtmp->mx, mtmp->my, fish)) break; mon = makemon(pm, cc.x, cc.y, NO_MM_FLAGS); if (mon && canspotmon(mon)) known = TRUE; } /* The only case where we don't use oseen. For wands, you * have to be able to see the monster zap the wand to know * what type it is. For teleport scrolls, you have to see * the monster to know it teleported. */ if (known) makeknown(SCR_CREATE_MONSTER); else if (!objects[SCR_CREATE_MONSTER].oc_name_known && !objects[SCR_CREATE_MONSTER].oc_uname) docall(otmp); m_useup(mtmp, otmp); return 2; } case MUSE_TRAPDOOR: /* trap doors on "bottom" levels of dungeons are rock-drop * trap doors, not holes in the floor. We check here for * safety. */ if (Is_botlevel(&u.uz)) return 0; m_flee(mtmp); if (vis) { struct trap *t; t = t_at(trapx,trapy); pline("%s %s into a %s!", Monnam(mtmp), makeplural(locomotion(mtmp->data, "jump")), t->ttyp == TRAPDOOR ? "trap door" : "hole"); if (levl[trapx][trapy].typ == SCORR) { levl[trapx][trapy].typ = CORR; unblock_point(trapx, trapy); } seetrap(t_at(trapx,trapy)); } /* don't use rloc_to() because worm tails must "move" */ remove_monster(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); /* update old location */ place_monster(mtmp, trapx, trapy); if (mtmp->wormno) worm_move(mtmp); newsym(trapx, trapy); migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM, (coord *)0); return 2; case MUSE_UPSTAIRS: /* Monsters without amulets escape the dungeon and are * gone for good when they leave up the up stairs. * Monsters with amulets would reach the endlevel, * which we cannot allow since that would leave the * player stranded. */ if (ledger_no(&u.uz) == 1) { if (mon_has_special(mtmp)) return 0; if (vismon) pline("%s escapes the dungeon!", Monnam(mtmp)); mongone(mtmp); return 2; } m_flee(mtmp); if (Inhell && mon_has_amulet(mtmp) && !rn2(4) && (dunlev(&u.uz) < dunlevs_in_dungeon(&u.uz) - 3)) { if (vismon) pline( "As %s climbs the stairs, a mysterious force momentarily surrounds %s...", mon_nam(mtmp), mhim(mtmp)); /* simpler than for the player; this will usually be the Wizard and he'll immediately go right to the upstairs, so there's not much point in having any chance for a random position on the current level */ migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_RANDOM, (coord *)0); } else { if (vismon) pline("%s escapes upstairs!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_STAIRS_DOWN, (coord *)0); } return 2; case MUSE_DOWNSTAIRS: m_flee(mtmp); if (vismon) pline("%s escapes downstairs!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_STAIRS_UP, (coord *)0); return 2; case MUSE_UP_LADDER: m_flee(mtmp); if (vismon) pline("%s escapes up the ladder!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&u.uz) - 1, MIGR_LADDER_DOWN, (coord *)0); return 2; case MUSE_DN_LADDER: m_flee(mtmp); if (vismon) pline("%s escapes down the ladder!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&u.uz) + 1, MIGR_LADDER_UP, (coord *)0); return 2; case MUSE_SSTAIRS: m_flee(mtmp); /* the stairs leading up from the 1st level are */ /* regular stairs, not sstairs. */ if (sstairs.up) { if (vismon) pline("%s escapes upstairs!", Monnam(mtmp)); if(Inhell) { migrate_to_level(mtmp, ledger_no(&sstairs.tolev), MIGR_RANDOM, (coord *)0); return 2; } } else if (vismon) pline("%s escapes downstairs!", Monnam(mtmp)); migrate_to_level(mtmp, ledger_no(&sstairs.tolev), MIGR_SSTAIRS, (coord *)0); return 2; case MUSE_TELEPORT_TRAP: m_flee(mtmp); if (vis) { pline("%s %s onto a teleport trap!", Monnam(mtmp), makeplural(locomotion(mtmp->data, "jump"))); if (levl[trapx][trapy].typ == SCORR) { levl[trapx][trapy].typ = CORR; unblock_point(trapx, trapy); } seetrap(t_at(trapx,trapy)); } /* don't use rloc_to() because worm tails must "move" */ remove_monster(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); /* update old location */ place_monster(mtmp, trapx, trapy); if (mtmp->wormno) worm_move(mtmp); newsym(trapx, trapy); goto mon_tele; case MUSE_POT_HEALING: mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 4); mtmp->mhp += i; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = ++mtmp->mhpmax; if (!otmp->cursed && !mtmp->mcansee) { mtmp->mcansee = 1; mtmp->mblinded = 0; if (vismon) pline(mcsa, Monnam(mtmp)); } if (vismon) pline("%s looks better.", Monnam(mtmp)); if (oseen) makeknown(POT_HEALING); m_useup(mtmp, otmp); return 2; case MUSE_POT_EXTRA_HEALING: mquaffmsg(mtmp, otmp); i = d(6 + 2 * bcsign(otmp), 8); mtmp->mhp += i; if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 5 : 2)); if (!mtmp->mcansee) { mtmp->mcansee = 1; mtmp->mblinded = 0; if (vismon) pline(mcsa, Monnam(mtmp)); } if (vismon) pline("%s looks much better.", Monnam(mtmp)); if (oseen) makeknown(POT_EXTRA_HEALING); m_useup(mtmp, otmp); return 2; case MUSE_POT_FULL_HEALING: mquaffmsg(mtmp, otmp); if (otmp->otyp == POT_SICKNESS) unbless(otmp); /* Pestilence */ mtmp->mhp = (mtmp->mhpmax += (otmp->blessed ? 8 : 4)); if (!mtmp->mcansee && otmp->otyp != POT_SICKNESS) { mtmp->mcansee = 1; mtmp->mblinded = 0; if (vismon) pline(mcsa, Monnam(mtmp)); } if (vismon) pline("%s looks completely healed.", Monnam(mtmp)); if (oseen) makeknown(otmp->otyp); m_useup(mtmp, otmp); return 2; case MUSE_LIZARD_CORPSE: /* not actually called for its unstoning effect */ mon_consume_unstone(mtmp, otmp, FALSE, FALSE); return 2; case 0: return 0; /* i.e. an exploded wand */ default: impossible("%s wanted to perform action %d?", Monnam(mtmp), m.has_defense); break; } return 0; #undef m_flee } int rnd_defensive_item(mtmp) struct monst *mtmp; { struct permonst *pm = mtmp->data; int difficulty = monstr[(monsndx(pm))]; int trycnt = 0; if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data) || pm->mlet == S_GHOST # ifdef KOPS || pm->mlet == S_KOP # endif ) return 0; try_again: switch (rn2(8 + (difficulty > 3) + (difficulty > 6) + (difficulty > 8))) { case 6: case 9: if (level.flags.noteleport && ++trycnt < 2) goto try_again; if (!rn2(3)) return WAN_TELEPORTATION; /* else FALLTHRU */ case 0: case 1: return SCR_TELEPORTATION; case 8: case 10: if (!rn2(3)) return WAN_CREATE_MONSTER; /* else FALLTHRU */ case 2: return SCR_CREATE_MONSTER; case 3: return POT_HEALING; case 4: return POT_EXTRA_HEALING; case 5: return (mtmp->data != &mons[PM_PESTILENCE]) ? POT_FULL_HEALING : POT_SICKNESS; case 7: if (is_floater(pm) || mtmp->isshk || mtmp->isgd || mtmp->ispriest ) return 0; else return WAN_DIGGING; } /*NOTREACHED*/ return 0; } #define MUSE_WAN_DEATH 1 #define MUSE_WAN_SLEEP 2 #define MUSE_WAN_FIRE 3 #define MUSE_WAN_COLD 4 #define MUSE_WAN_LIGHTNING 5 #define MUSE_WAN_MAGIC_MISSILE 6 #define MUSE_WAN_STRIKING 7 #define MUSE_SCR_FIRE 8 #define MUSE_POT_PARALYSIS 9 #define MUSE_POT_BLINDNESS 10 #define MUSE_POT_CONFUSION 11 #define MUSE_FROST_HORN 12 #define MUSE_FIRE_HORN 13 #define MUSE_POT_ACID 14 /*#define MUSE_WAN_TELEPORTATION 15*/ #define MUSE_POT_SLEEPING 16 #define MUSE_SCR_EARTH 17 /* Select an offensive item/action for a monster. Returns TRUE iff one is * found. */ boolean find_offensive(mtmp) struct monst *mtmp; { register struct obj *obj; boolean ranged_stuff = lined_up(mtmp); boolean reflection_skip = (Reflecting && rn2(2)); struct obj *helmet = which_armor(mtmp, W_ARMH); m.offensive = (struct obj *)0; m.has_offense = 0; if (mtmp->mpeaceful || is_animal(mtmp->data) || mindless(mtmp->data) || nohands(mtmp->data)) return FALSE; if (u.uswallow) return FALSE; if (in_your_sanctuary(mtmp, 0, 0)) return FALSE; if (dmgtype(mtmp->data, AD_HEAL) && !uwep #ifdef TOURIST && !uarmu #endif && !uarm && !uarmh && !uarms && !uarmg && !uarmc && !uarmf) return FALSE; if (!ranged_stuff) return FALSE; #define nomore(x) if(m.has_offense==x) continue; for(obj=mtmp->minvent; obj; obj=obj->nobj) { /* nomore(MUSE_WAN_DEATH); */ if (!reflection_skip) { if(obj->otyp == WAN_DEATH && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_DEATH; } nomore(MUSE_WAN_SLEEP); if(obj->otyp == WAN_SLEEP && obj->spe > 0 && multi >= 0) { m.offensive = obj; m.has_offense = MUSE_WAN_SLEEP; } nomore(MUSE_WAN_FIRE); if(obj->otyp == WAN_FIRE && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_FIRE; } nomore(MUSE_FIRE_HORN); if(obj->otyp == FIRE_HORN && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_FIRE_HORN; } nomore(MUSE_WAN_COLD); if(obj->otyp == WAN_COLD && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_COLD; } nomore(MUSE_FROST_HORN); if(obj->otyp == FROST_HORN && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_FROST_HORN; } nomore(MUSE_WAN_LIGHTNING); if(obj->otyp == WAN_LIGHTNING && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_LIGHTNING; } nomore(MUSE_WAN_MAGIC_MISSILE); if(obj->otyp == WAN_MAGIC_MISSILE && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_MAGIC_MISSILE; } } nomore(MUSE_WAN_STRIKING); if(obj->otyp == WAN_STRIKING && obj->spe > 0) { m.offensive = obj; m.has_offense = MUSE_WAN_STRIKING; } nomore(MUSE_POT_PARALYSIS); if(obj->otyp == POT_PARALYSIS && multi >= 0) { m.offensive = obj; m.has_offense = MUSE_POT_PARALYSIS; } nomore(MUSE_POT_BLINDNESS); if(obj->otyp == POT_BLINDNESS && !attacktype(mtmp->data, AT_GAZE)) { m.offensive = obj; m.has_offense = MUSE_POT_BLINDNESS; } nomore(MUSE_POT_CONFUSION); if(obj->otyp == POT_CONFUSION) { m.offensive = obj; m.has_offense = MUSE_POT_CONFUSION; } nomore(MUSE_POT_SLEEPING); if(obj->otyp == POT_SLEEPING) { m.offensive = obj; m.has_offense = MUSE_POT_SLEEPING; } nomore(MUSE_POT_ACID); if(obj->otyp == POT_ACID) { m.offensive = obj; m.has_offense = MUSE_POT_ACID; } /* we can safely put this scroll here since the locations that * are in a 1 square radius are a subset of the locations that * are in wand range */ nomore(MUSE_SCR_EARTH); if (obj->otyp == SCR_EARTH && ((helmet && is_metallic(helmet)) || mtmp->mconf || amorphous(mtmp->data) || passes_walls(mtmp->data) || noncorporeal(mtmp->data) || unsolid(mtmp->data) || !rn2(10)) && dist2(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy) <= 2 && mtmp->mcansee && haseyes(mtmp->data) #ifdef REINCARNATION && !Is_rogue_level(&u.uz) #endif && (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) { m.offensive = obj; m.has_offense = MUSE_SCR_EARTH; } #if 0 nomore(MUSE_SCR_FIRE); if (obj->otyp == SCR_FIRE && resists_fire(mtmp) && dist2(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy) <= 2 && mtmp->mcansee && haseyes(mtmp->data)) { m.offensive = obj; m.has_offense = MUSE_SCR_FIRE; } #endif } return((boolean)(!!m.has_offense)); #undef nomore } STATIC_PTR int mbhitm(mtmp, otmp) register struct monst *mtmp; register struct obj *otmp; { int tmp; boolean reveal_invis = FALSE; if (mtmp != &youmonst) { mtmp->msleeping = 0; if (mtmp->m_ap_type) seemimic(mtmp); } switch(otmp->otyp) { case WAN_STRIKING: reveal_invis = TRUE; if (mtmp == &youmonst) { if (zap_oseen) makeknown(WAN_STRIKING); if (Antimagic) { shieldeff(u.ux, u.uy); pline("Boing!"); } else if (rnd(20) < 10 + u.uac) { pline_The("wand hits you!"); tmp = d(2,12); if(Half_spell_damage) tmp = (tmp+1) / 2; losehp(tmp, "wand", KILLED_BY_AN); } else pline_The("wand misses you."); stop_occupation(); nomul(0); } else if (resists_magm(mtmp)) { shieldeff(mtmp->mx, mtmp->my); pline("Boing!"); } else if (rnd(20) < 10+find_mac(mtmp)) { tmp = d(2,12); hit("wand", mtmp, exclam(tmp)); (void) resist(mtmp, otmp->oclass, tmp, TELL); if (cansee(mtmp->mx, mtmp->my) && zap_oseen) makeknown(WAN_STRIKING); } else { miss("wand", mtmp); if (cansee(mtmp->mx, mtmp->my) && zap_oseen) makeknown(WAN_STRIKING); } break; case WAN_TELEPORTATION: if (mtmp == &youmonst) { if (zap_oseen) makeknown(WAN_TELEPORTATION); tele(); } else { /* for consistency with zap.c, don't identify */ if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) { if (cansee(mtmp->mx, mtmp->my)) pline("%s resists the magic!", Monnam(mtmp)); mtmp->msleeping = 0; if(mtmp->m_ap_type) seemimic(mtmp); } else if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); } break; case WAN_CANCELLATION: case SPE_CANCELLATION: (void) cancel_monst(mtmp, otmp, FALSE, TRUE, FALSE); break; } if (reveal_invis) { if (mtmp->mhp > 0 && cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); } return 0; } /* A modified bhit() for monsters. Based on bhit() in zap.c. Unlike * buzz(), bhit() doesn't take into account the possibility of a monster * zapping you, so we need a special function for it. (Unless someone wants * to merge the two functions...) */ STATIC_OVL void mbhit(mon,range,fhitm,fhito,obj) struct monst *mon; /* monster shooting the wand */ register int range; /* direction and range */ int FDECL((*fhitm),(MONST_P,OBJ_P)); int FDECL((*fhito),(OBJ_P,OBJ_P)); /* fns called when mon/obj hit */ struct obj *obj; /* 2nd arg to fhitm/fhito */ { register struct monst *mtmp; register struct obj *otmp; register uchar typ; int ddx, ddy; bhitpos.x = mon->mx; bhitpos.y = mon->my; ddx = sgn(mon->mux - mon->mx); ddy = sgn(mon->muy - mon->my); while(range-- > 0) { int x,y; bhitpos.x += ddx; bhitpos.y += ddy; x = bhitpos.x; y = bhitpos.y; if (!isok(x,y)) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if (find_drawbridge(&x,&y)) switch (obj->otyp) { case WAN_STRIKING: destroy_drawbridge(x,y); } if(bhitpos.x==u.ux && bhitpos.y==u.uy) { (*fhitm)(&youmonst, obj); range -= 3; } else if(MON_AT(bhitpos.x, bhitpos.y)){ mtmp = m_at(bhitpos.x,bhitpos.y); if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); (*fhitm)(mtmp, obj); range -= 3; } /* modified by GAN to hit all objects */ if(fhito){ int hitanything = 0; register struct obj *next_obj; for(otmp = level.objects[bhitpos.x][bhitpos.y]; otmp; otmp = next_obj) { /* Fix for polymorph bug, Tim Wright */ next_obj = otmp->nexthere; hitanything += (*fhito)(otmp, obj); } if(hitanything) range--; } typ = levl[bhitpos.x][bhitpos.y].typ; if(IS_DOOR(typ) || typ == SDOOR) { switch (obj->otyp) { /* note: monsters don't use opening or locking magic at present, but keep these as placeholders */ case WAN_OPENING: case WAN_LOCKING: case WAN_STRIKING: if (doorlock(obj, bhitpos.x, bhitpos.y)) { makeknown(obj->otyp); /* if a shop door gets broken, add it to the shk's fix list (no cost to player) */ if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) add_damage(bhitpos.x, bhitpos.y, 0L); } break; } } if(!ZAP_POS(typ) || (IS_DOOR(typ) && (levl[bhitpos.x][bhitpos.y].doormask & (D_LOCKED | D_CLOSED))) ) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } } } /* Perform an offensive action for a monster. Must be called immediately * after find_offensive(). Return values are same as use_defensive(). */ int use_offensive(mtmp) struct monst *mtmp; { int i; struct obj *otmp = m.offensive; boolean oseen; /* offensive potions are not drunk, they're thrown */ if (otmp->oclass != POTION_CLASS && (i = precheck(mtmp, otmp)) != 0) return i; oseen = otmp && canseemon(mtmp); switch(m.has_offense) { case MUSE_WAN_DEATH: case MUSE_WAN_SLEEP: case MUSE_WAN_FIRE: case MUSE_WAN_COLD: case MUSE_WAN_LIGHTNING: case MUSE_WAN_MAGIC_MISSILE: mzapmsg(mtmp, otmp, FALSE); otmp->spe--; if (oseen) makeknown(otmp->otyp); m_using = TRUE; buzz((int)(-30 - (otmp->otyp - WAN_MAGIC_MISSILE)), (otmp->otyp == WAN_MAGIC_MISSILE) ? 2 : 6, mtmp->mx, mtmp->my, sgn(mtmp->mux-mtmp->mx), sgn(mtmp->muy-mtmp->my)); m_using = FALSE; return (mtmp->mhp <= 0) ? 1 : 2; case MUSE_FIRE_HORN: case MUSE_FROST_HORN: if (oseen) { makeknown(otmp->otyp); pline("%s plays a %s!", Monnam(mtmp), xname(otmp)); } else You_hear("a horn being played."); otmp->spe--; m_using = TRUE; buzz(-30 - ((otmp->otyp==FROST_HORN) ? AD_COLD-1 : AD_FIRE-1), rn1(6,6), mtmp->mx, mtmp->my, sgn(mtmp->mux-mtmp->mx), sgn(mtmp->muy-mtmp->my)); m_using = FALSE; return (mtmp->mhp <= 0) ? 1 : 2; case MUSE_WAN_TELEPORTATION: case MUSE_WAN_STRIKING: zap_oseen = oseen; mzapmsg(mtmp, otmp, FALSE); otmp->spe--; m_using = TRUE; mbhit(mtmp,rn1(8,6),mbhitm,bhito,otmp); m_using = FALSE; return 2; case MUSE_SCR_EARTH: { /* TODO: handle steeds */ register int x, y; /* don't use monster fields after killing it */ boolean confused = (mtmp->mconf ? TRUE : FALSE); int mmx = mtmp->mx, mmy = mtmp->my; mreadmsg(mtmp, otmp); /* Identify the scroll */ if (canspotmon(mtmp)) { pline_The("%s rumbles %s %s!", ceiling(mtmp->mx, mtmp->my), otmp->blessed ? "around" : "above", mon_nam(mtmp)); if (oseen) makeknown(otmp->otyp); } else if (cansee(mtmp->mx, mtmp->my)) { pline_The("%s rumbles in the middle of nowhere!", ceiling(mtmp->mx, mtmp->my)); if (mtmp->minvis) map_invisible(mtmp->mx, mtmp->my); if (oseen) makeknown(otmp->otyp); } /* Loop through the surrounding squares */ for (x = mmx-1; x <= mmx+1; x++) { for (y = mmy-1; y <= mmy+1; y++) { /* Is this a suitable spot? */ if (isok(x, y) && !closed_door(x, y) && !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) && (((x == mmx) && (y == mmy)) ? !otmp->blessed : !otmp->cursed) && (x != u.ux || y != u.uy)) { register struct obj *otmp2; register struct monst *mtmp2; /* Make the object(s) */ otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE); if (!otmp2) continue; /* Shouldn't happen */ otmp2->quan = confused ? rn1(5,2) : 1; otmp2->owt = weight(otmp2); /* Find the monster here (might be same as mtmp) */ mtmp2 = m_at(x, y); if (mtmp2 && !amorphous(mtmp2->data) && !passes_walls(mtmp2->data) && !noncorporeal(mtmp2->data) && !unsolid(mtmp2->data)) { struct obj *helmet = which_armor(mtmp2, W_ARMH); int mdmg; if (cansee(mtmp2->mx, mtmp2->my)) { pline("%s is hit by %s!", Monnam(mtmp2), doname(otmp2)); if (mtmp2->minvis && !canspotmon(mtmp2)) map_invisible(mtmp2->mx, mtmp2->my); } mdmg = dmgval(otmp2, mtmp2) * otmp2->quan; if (helmet) { if(is_metallic(helmet)) { if (canspotmon(mtmp2)) pline("Fortunately, %s is wearing a hard helmet.", mon_nam(mtmp2)); else if (flags.soundok) You_hear("a clanging sound."); if (mdmg > 2) mdmg = 2; } else { if (canspotmon(mtmp2)) pline("%s's %s does not protect %s.", Monnam(mtmp2), xname(helmet), mhim(mtmp2)); } } mtmp2->mhp -= mdmg; if (mtmp2->mhp <= 0) { pline("%s is killed.", Monnam(mtmp2)); mondied(mtmp2); } } /* Drop the rock/boulder to the floor */ if (!flooreffects(otmp2, x, y, "fall")) { place_object(otmp2, x, y); stackobj(otmp2); newsym(x, y); /* map the rock */ } } } } m_useup(mtmp, otmp); /* Attack the player */ if (distmin(mmx, mmy, u.ux, u.uy) == 1 && !otmp->cursed) { int dmg; struct obj *otmp2; /* Okay, _you_ write this without repeating the code */ otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE); if (!otmp2) goto xxx_noobj; /* Shouldn't happen */ otmp2->quan = confused ? rn1(5,2) : 1; otmp2->owt = weight(otmp2); if (!amorphous(youmonst.data) && !Passes_walls && !noncorporeal(youmonst.data) && !unsolid(youmonst.data)) { You("are hit by %s!", doname(otmp2)); dmg = dmgval(otmp2, &youmonst) * otmp2->quan; if (uarmh) { if(is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); if (dmg > 2) dmg = 2; } else if (flags.verbose) { Your("%s does not protect you.", xname(uarmh)); } } } else dmg = 0; if (!flooreffects(otmp2, u.ux, u.uy, "fall")) { place_object(otmp2, u.ux, u.uy); stackobj(otmp2); newsym(u.ux, u.uy); } if (dmg) losehp(dmg, "scroll of earth", KILLED_BY_AN); } xxx_noobj: return (mtmp->mhp <= 0) ? 1 : 2; } #if 0 case MUSE_SCR_FIRE: { boolean vis = cansee(mtmp->mx, mtmp->my); mreadmsg(mtmp, otmp); if (mtmp->mconf) { if (vis) pline("Oh, what a pretty fire!"); } else { struct monst *mtmp2; int num; if (vis) pline_The("scroll erupts in a tower of flame!"); shieldeff(mtmp->mx, mtmp->my); pline("%s is uninjured.", Monnam(mtmp)); (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); num = (2*(rn1(3, 3) + 2 * bcsign(otmp)) + 1)/3; if (Fire_resistance) You("are not harmed."); burn_away_slime(); if (Half_spell_damage) num = (num+1) / 2; else losehp(num, "scroll of fire", KILLED_BY_AN); for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) { if(DEADMONSTER(mtmp2)) continue; if(mtmp == mtmp2) continue; if(dist2(mtmp2->mx,mtmp2->my,mtmp->mx,mtmp->my) < 3){ if (resists_fire(mtmp2)) continue; mtmp2->mhp -= num; if (resists_cold(mtmp2)) mtmp2->mhp -= 3*num; if(mtmp2->mhp < 1) { mondied(mtmp2); break; } } } } return 2; } #endif /* 0 */ case MUSE_POT_PARALYSIS: case MUSE_POT_BLINDNESS: case MUSE_POT_CONFUSION: case MUSE_POT_SLEEPING: case MUSE_POT_ACID: /* Note: this setting of dknown doesn't suffice. A monster * which is out of sight might throw and it hits something _in_ * sight, a problem not existing with wands because wand rays * are not objects. Also set dknown in mthrowu.c. */ if (cansee(mtmp->mx, mtmp->my)) { otmp->dknown = 1; pline("%s hurls %s!", Monnam(mtmp), singular(otmp, doname)); } m_throw(mtmp, mtmp->mx, mtmp->my, sgn(mtmp->mux-mtmp->mx), sgn(mtmp->muy-mtmp->my), distmin(mtmp->mx,mtmp->my,mtmp->mux,mtmp->muy), otmp); return 2; case 0: return 0; /* i.e. an exploded wand */ default: impossible("%s wanted to perform action %d?", Monnam(mtmp), m.has_offense); break; } return 0; } int rnd_offensive_item(mtmp) struct monst *mtmp; { struct permonst *pm = mtmp->data; int difficulty = monstr[(monsndx(pm))]; if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data) || pm->mlet == S_GHOST # ifdef KOPS || pm->mlet == S_KOP # endif ) return 0; if (difficulty > 7 && !rn2(35)) return WAN_DEATH; switch (rn2(9 - (difficulty < 4) + 4 * (difficulty > 6))) { case 0: { struct obj *helmet = which_armor(mtmp, W_ARMH); if ((helmet && is_metallic(helmet)) || amorphous(pm) || passes_walls(pm) || noncorporeal(pm) || unsolid(pm)) return SCR_EARTH; } /* fall through */ case 1: return WAN_STRIKING; case 2: return POT_ACID; case 3: return POT_CONFUSION; case 4: return POT_BLINDNESS; case 5: return POT_SLEEPING; case 6: return POT_PARALYSIS; case 7: case 8: return WAN_MAGIC_MISSILE; case 9: return WAN_SLEEP; case 10: return WAN_FIRE; case 11: return WAN_COLD; case 12: return WAN_LIGHTNING; } /*NOTREACHED*/ return 0; } #define MUSE_POT_GAIN_LEVEL 1 #define MUSE_WAN_MAKE_INVISIBLE 2 #define MUSE_POT_INVISIBILITY 3 #define MUSE_POLY_TRAP 4 #define MUSE_WAN_POLYMORPH 5 #define MUSE_POT_SPEED 6 #define MUSE_WAN_SPEED_MONSTER 7 #define MUSE_BULLWHIP 8 #define MUSE_POT_POLYMORPH 9 boolean find_misc(mtmp) struct monst *mtmp; { register struct obj *obj; struct permonst *mdat = mtmp->data; int x = mtmp->mx, y = mtmp->my; struct trap *t; int xx, yy; boolean immobile = (mdat->mmove == 0); boolean stuck = (mtmp == u.ustuck); m.misc = (struct obj *)0; m.has_misc = 0; if (is_animal(mdat) || mindless(mdat)) return 0; if (u.uswallow && stuck) return FALSE; /* We arbitrarily limit to times when a player is nearby for the * same reason as Junior Pac-Man doesn't have energizers eaten until * you can see them... */ if(dist2(x, y, mtmp->mux, mtmp->muy) > 36) return FALSE; if (!stuck && !immobile && !mtmp->cham && monstr[monsndx(mdat)] < 6) { boolean ignore_boulders = (verysmall(mdat) || throws_rocks(mdat) || passes_walls(mdat)); for(xx = x-1; xx <= x+1; xx++) for(yy = y-1; yy <= y+1; yy++) if (isok(xx,yy) && (xx != u.ux || yy != u.uy)) if (mdat != &mons[PM_GRID_BUG] || xx == x || yy == y) if (/* (xx==x && yy==y) || */ !level.monsters[xx][yy]) if ((t = t_at(xx, yy)) != 0 && (ignore_boulders || !sobj_at(BOULDER, xx, yy)) && !onscary(xx, yy, mtmp)) { if (t->ttyp == POLY_TRAP) { trapx = xx; trapy = yy; m.has_misc = MUSE_POLY_TRAP; return TRUE; } } } if (nohands(mdat)) return 0; #define nomore(x) if(m.has_misc==x) continue; for(obj=mtmp->minvent; obj; obj=obj->nobj) { /* Monsters shouldn't recognize cursed items; this kludge is */ /* necessary to prevent serious problems though... */ if(obj->otyp == POT_GAIN_LEVEL && (!obj->cursed || (!mtmp->isgd && !mtmp->isshk && !mtmp->ispriest))) { m.misc = obj; m.has_misc = MUSE_POT_GAIN_LEVEL; } nomore(MUSE_BULLWHIP); if(obj->otyp == BULLWHIP && (MON_WEP(mtmp) == obj) && distu(mtmp->mx,mtmp->my)==1 && uwep && !mtmp->mpeaceful) { m.misc = obj; m.has_misc = MUSE_BULLWHIP; } /* Note: peaceful/tame monsters won't make themselves * invisible unless you can see them. Not really right, but... */ nomore(MUSE_WAN_MAKE_INVISIBLE); if(obj->otyp == WAN_MAKE_INVISIBLE && obj->spe > 0 && !mtmp->minvis && !mtmp->invis_blkd && (!mtmp->mpeaceful || See_invisible) && (!attacktype(mtmp->data, AT_GAZE) || mtmp->mcan)) { m.misc = obj; m.has_misc = MUSE_WAN_MAKE_INVISIBLE; } nomore(MUSE_POT_INVISIBILITY); if(obj->otyp == POT_INVISIBILITY && !mtmp->minvis && !mtmp->invis_blkd && (!mtmp->mpeaceful || See_invisible) && (!attacktype(mtmp->data, AT_GAZE) || mtmp->mcan)) { m.misc = obj; m.has_misc = MUSE_POT_INVISIBILITY; } nomore(MUSE_WAN_SPEED_MONSTER); if(obj->otyp == WAN_SPEED_MONSTER && obj->spe > 0 && mtmp->mspeed != MFAST && !mtmp->isgd) { m.misc = obj; m.has_misc = MUSE_WAN_SPEED_MONSTER; } nomore(MUSE_POT_SPEED); if(obj->otyp == POT_SPEED && mtmp->mspeed != MFAST && !mtmp->isgd) { m.misc = obj; m.has_misc = MUSE_POT_SPEED; } nomore(MUSE_WAN_POLYMORPH); if(obj->otyp == WAN_POLYMORPH && obj->spe > 0 && !mtmp->cham && monstr[monsndx(mdat)] < 6) { m.misc = obj; m.has_misc = MUSE_WAN_POLYMORPH; } nomore(MUSE_POT_POLYMORPH); if(obj->otyp == POT_POLYMORPH && !mtmp->cham && monstr[monsndx(mdat)] < 6) { m.misc = obj; m.has_misc = MUSE_POT_POLYMORPH; } } return((boolean)(!!m.has_misc)); #undef nomore } /* type of monster to polymorph into; defaults to one suitable for the current level rather than the totally arbitrary choice of newcham() */ static struct permonst * muse_newcham_mon(mon) struct monst *mon; { struct obj *m_armr; if ((m_armr = which_armor(mon, W_ARM)) != 0) { if (Is_dragon_scales(m_armr)) return Dragon_scales_to_pm(m_armr); else if (Is_dragon_mail(m_armr)) return Dragon_mail_to_pm(m_armr); } return rndmonst(); } int use_misc(mtmp) struct monst *mtmp; { int i; struct obj *otmp = m.misc; boolean vis, vismon, oseen; char nambuf[BUFSZ]; if ((i = precheck(mtmp, otmp)) != 0) return i; vis = cansee(mtmp->mx, mtmp->my); vismon = canseemon(mtmp); oseen = otmp && vismon; switch(m.has_misc) { case MUSE_POT_GAIN_LEVEL: mquaffmsg(mtmp, otmp); if (otmp->cursed) { if (Can_rise_up(mtmp->mx, mtmp->my, &u.uz)) { register int tolev = depth(&u.uz)-1; d_level tolevel; get_level(&tolevel, tolev); /* insurance against future changes... */ if(on_level(&tolevel, &u.uz)) goto skipmsg; if (vismon) { pline("%s rises up, through the %s!", Monnam(mtmp), ceiling(mtmp->mx, mtmp->my)); if(!objects[POT_GAIN_LEVEL].oc_name_known && !objects[POT_GAIN_LEVEL].oc_uname) docall(otmp); } m_useup(mtmp, otmp); migrate_to_level(mtmp, ledger_no(&tolevel), MIGR_RANDOM, (coord *)0); return 2; } else { skipmsg: if (vismon) { pline("%s looks uneasy.", Monnam(mtmp)); if(!objects[POT_GAIN_LEVEL].oc_name_known && !objects[POT_GAIN_LEVEL].oc_uname) docall(otmp); } m_useup(mtmp, otmp); return 2; } } if (vismon) pline("%s seems more experienced.", Monnam(mtmp)); if (oseen) makeknown(POT_GAIN_LEVEL); m_useup(mtmp, otmp); if (!grow_up(mtmp,(struct monst *)0)) return 1; /* grew into genocided monster */ return 2; case MUSE_WAN_MAKE_INVISIBLE: case MUSE_POT_INVISIBILITY: if (otmp->otyp == WAN_MAKE_INVISIBLE) { mzapmsg(mtmp, otmp, TRUE); otmp->spe--; } else mquaffmsg(mtmp, otmp); /* format monster's name before altering its visibility */ Strcpy(nambuf, See_invisible ? Monnam(mtmp) : mon_nam(mtmp)); mon_set_minvis(mtmp); if (vismon && mtmp->minvis) { /* was seen, now invisible */ if (See_invisible) pline("%s body takes on a %s transparency.", s_suffix(nambuf), Hallucination ? "normal" : "strange"); else pline("Suddenly you cannot see %s.", nambuf); if (oseen) makeknown(otmp->otyp); } if (otmp->otyp == POT_INVISIBILITY) { if (otmp->cursed) you_aggravate(mtmp); m_useup(mtmp, otmp); } return 2; case MUSE_WAN_SPEED_MONSTER: mzapmsg(mtmp, otmp, TRUE); otmp->spe--; mon_adjust_speed(mtmp, 1, otmp); return 2; case MUSE_POT_SPEED: mquaffmsg(mtmp, otmp); /* note difference in potion effect due to substantially different methods of maintaining speed ratings: player's character becomes "very fast" temporarily; monster becomes "one stage faster" permanently */ mon_adjust_speed(mtmp, 1, otmp); m_useup(mtmp, otmp); return 2; case MUSE_WAN_POLYMORPH: mzapmsg(mtmp, otmp, TRUE); otmp->spe--; (void) newcham(mtmp, muse_newcham_mon(mtmp), TRUE, FALSE); if (oseen) makeknown(WAN_POLYMORPH); return 2; case MUSE_POT_POLYMORPH: mquaffmsg(mtmp, otmp); if (vismon) pline("%s suddenly mutates!", Monnam(mtmp)); (void) newcham(mtmp, muse_newcham_mon(mtmp), FALSE, FALSE); if (oseen) makeknown(POT_POLYMORPH); m_useup(mtmp, otmp); return 2; case MUSE_POLY_TRAP: if (vismon) pline("%s deliberately %s onto a polymorph trap!", Monnam(mtmp), makeplural(locomotion(mtmp->data, "jump"))); if (vis) seetrap(t_at(trapx,trapy)); /* don't use rloc() due to worms */ remove_monster(mtmp->mx, mtmp->my); newsym(mtmp->mx, mtmp->my); place_monster(mtmp, trapx, trapy); if (mtmp->wormno) worm_move(mtmp); newsym(trapx, trapy); (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); return 2; case MUSE_BULLWHIP: /* attempt to disarm hero */ if (uwep && !rn2(5)) { const char *The_whip = vismon ? "The bullwhip" : "A whip"; int where_to = rn2(4); struct obj *obj = uwep; const char *hand; char the_weapon[BUFSZ]; Strcpy(the_weapon, the(xname(obj))); hand = body_part(HAND); if (bimanual(obj)) hand = makeplural(hand); if (vismon) pline("%s flicks a bullwhip towards your %s!", Monnam(mtmp), hand); if (obj->otyp == HEAVY_IRON_BALL) { pline("%s fails to wrap around %s.", The_whip, the_weapon); return 1; } pline("%s wraps around %s you're wielding!", The_whip, the_weapon); if (welded(obj)) { pline("%s welded to your %s%c", !is_plural(obj) ? "It is" : "They are", hand, !obj->bknown ? '!' : '.'); /* obj->bknown = 1; */ /* welded() takes care of this */ where_to = 0; } if (!where_to) { pline_The("whip slips free."); /* not `The_whip' */ return 1; } else if (where_to == 3 && hates_silver(mtmp->data) && objects[obj->otyp].oc_material == SILVER) { /* this monster won't want to catch a silver weapon; drop it at hero's feet instead */ where_to = 2; } freeinv(obj); uwepgone(); switch (where_to) { case 1: /* onto floor beneath mon */ pline("%s yanks %s from your %s!", Monnam(mtmp), the_weapon, hand); place_object(obj, mtmp->mx, mtmp->my); break; case 2: /* onto floor beneath you */ pline("%s yanks %s to the %s!", Monnam(mtmp), the_weapon, surface(u.ux, u.uy)); dropy(obj); break; case 3: /* into mon's inventory */ pline("%s snatches %s!", Monnam(mtmp), the_weapon); (void) mpickobj(mtmp,obj); break; } return 1; } return 0; case 0: return 0; /* i.e. an exploded wand */ default: impossible("%s wanted to perform action %d?", Monnam(mtmp), m.has_misc); break; } return 0; } STATIC_OVL void you_aggravate(mtmp) struct monst *mtmp; { pline("For some reason, %s presence is known to you.", s_suffix(noit_mon_nam(mtmp))); cls(); #ifdef CLIPPING cliparound(mtmp->mx, mtmp->my); #endif show_glyph(mtmp->mx, mtmp->my, mon_to_glyph(mtmp)); display_self(); You_feel("aggravated at %s.", noit_mon_nam(mtmp)); display_nhwindow(WIN_MAP, TRUE); docrt(); if (unconscious()) { multi = -1; nomovemsg = "Aggravated, you are jolted into full consciousness."; } newsym(mtmp->mx,mtmp->my); if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); } int rnd_misc_item(mtmp) struct monst *mtmp; { struct permonst *pm = mtmp->data; int difficulty = monstr[(monsndx(pm))]; if(is_animal(pm) || attacktype(pm, AT_EXPL) || mindless(mtmp->data) || pm->mlet == S_GHOST # ifdef KOPS || pm->mlet == S_KOP # endif ) return 0; /* Unlike other rnd_item functions, we only allow _weak_ monsters * to have this item; after all, the item will be used to strengthen * the monster and strong monsters won't use it at all... */ if (difficulty < 6 && !rn2(30)) return rn2(6) ? POT_POLYMORPH : WAN_POLYMORPH; if (!rn2(40) && !nonliving(pm)) return AMULET_OF_LIFE_SAVING; switch (rn2(3)) { case 0: if (mtmp->isgd) return 0; return rn2(6) ? POT_SPEED : WAN_SPEED_MONSTER; case 1: if (mtmp->mpeaceful && !See_invisible) return 0; return rn2(6) ? POT_INVISIBILITY : WAN_MAKE_INVISIBLE; case 2: return POT_GAIN_LEVEL; } /*NOTREACHED*/ return 0; } boolean searches_for_item(mon, obj) struct monst *mon; struct obj *obj; { int typ = obj->otyp; if (is_animal(mon->data) || mindless(mon->data) || mon->data == &mons[PM_GHOST]) /* don't loot bones piles */ return FALSE; if (typ == WAN_MAKE_INVISIBLE || typ == POT_INVISIBILITY) return (boolean)(!mon->minvis && !mon->invis_blkd && !attacktype(mon->data, AT_GAZE)); if (typ == WAN_SPEED_MONSTER || typ == POT_SPEED) return (boolean)(mon->mspeed != MFAST); switch (obj->oclass) { case WAND_CLASS: if (obj->spe <= 0) return FALSE; if (typ == WAN_DIGGING) return (boolean)(!is_floater(mon->data)); if (typ == WAN_POLYMORPH) return (boolean)(monstr[monsndx(mon->data)] < 6); if (objects[typ].oc_dir == RAY || typ == WAN_STRIKING || typ == WAN_TELEPORTATION || typ == WAN_CREATE_MONSTER) return TRUE; break; case POTION_CLASS: if (typ == POT_HEALING || typ == POT_EXTRA_HEALING || typ == POT_FULL_HEALING || typ == POT_POLYMORPH || typ == POT_GAIN_LEVEL || typ == POT_PARALYSIS || typ == POT_SLEEPING || typ == POT_ACID || typ == POT_CONFUSION) return TRUE; if (typ == POT_BLINDNESS && !attacktype(mon->data, AT_GAZE)) return TRUE; break; case SCROLL_CLASS: if (typ == SCR_TELEPORTATION || typ == SCR_CREATE_MONSTER || typ == SCR_EARTH) return TRUE; break; case AMULET_CLASS: if (typ == AMULET_OF_LIFE_SAVING) return (boolean)(!nonliving(mon->data)); if (typ == AMULET_OF_REFLECTION) return TRUE; break; case TOOL_CLASS: if (typ == PICK_AXE) return (boolean)needspick(mon->data); if (typ == UNICORN_HORN) return (boolean)(!obj->cursed && !is_unicorn(mon->data)); if (typ == FROST_HORN || typ == FIRE_HORN) return (obj->spe > 0); break; case FOOD_CLASS: if (typ == CORPSE) return (boolean)(((mon->misc_worn_check & W_ARMG) && touch_petrifies(&mons[obj->corpsenm])) || (!resists_ston(mon) && (obj->corpsenm == PM_LIZARD || (acidic(&mons[obj->corpsenm]) && obj->corpsenm != PM_GREEN_SLIME)))); if (typ == EGG) return (boolean)(touch_petrifies(&mons[obj->corpsenm])); break; default: break; } return FALSE; } boolean mon_reflects(mon,str) struct monst *mon; const char *str; { struct obj *orefl = which_armor(mon, W_ARMS); if (orefl && orefl->otyp == SHIELD_OF_REFLECTION) { if (str) { pline(str, s_suffix(mon_nam(mon)), "shield"); makeknown(SHIELD_OF_REFLECTION); } return TRUE; } else if (arti_reflects(MON_WEP(mon))) { /* due to wielded artifact weapon */ if (str) pline(str, s_suffix(mon_nam(mon)), "weapon"); return TRUE; } else if ((orefl = which_armor(mon, W_AMUL)) && orefl->otyp == AMULET_OF_REFLECTION) { if (str) { pline(str, s_suffix(mon_nam(mon)), "amulet"); makeknown(AMULET_OF_REFLECTION); } return TRUE; } else if ((orefl = which_armor(mon, W_ARM)) && (orefl->otyp == SILVER_DRAGON_SCALES || orefl->otyp == SILVER_DRAGON_SCALE_MAIL)) { if (str) pline(str, s_suffix(mon_nam(mon)), "armor"); return TRUE; } else if (mon->data == &mons[PM_SILVER_DRAGON] || mon->data == &mons[PM_CHROMATIC_DRAGON]) { /* Silver dragons only reflect when mature; babies do not */ if (str) pline(str, s_suffix(mon_nam(mon)), "scales"); return TRUE; } return FALSE; } boolean ureflects (fmt, str) const char *fmt, *str; { /* Check from outermost to innermost objects */ if (EReflecting & W_ARMS) { if (fmt && str) { pline(fmt, str, "shield"); makeknown(SHIELD_OF_REFLECTION); } return TRUE; } else if (EReflecting & W_WEP) { /* Due to wielded artifact weapon */ if (fmt && str) pline(fmt, str, "weapon"); return TRUE; } else if (EReflecting & W_AMUL) { if (fmt && str) { pline(fmt, str, "medallion"); makeknown(AMULET_OF_REFLECTION); } return TRUE; } else if (EReflecting & W_ARM) { if (fmt && str) pline(fmt, str, "armor"); return TRUE; } else if (youmonst.data == &mons[PM_SILVER_DRAGON]) { if (fmt && str) pline(fmt, str, "scales"); return TRUE; } return FALSE; } /* TRUE if the monster ate something */ boolean munstone(mon, by_you) struct monst *mon; boolean by_you; { struct obj *obj; if (resists_ston(mon)) return FALSE; if (mon->meating || !mon->mcanmove || mon->msleeping) return FALSE; for(obj = mon->minvent; obj; obj = obj->nobj) { /* Monsters can also use potions of acid */ if ((obj->otyp == POT_ACID) || (obj->otyp == CORPSE && (obj->corpsenm == PM_LIZARD || (acidic(&mons[obj->corpsenm]) && obj->corpsenm != PM_GREEN_SLIME)))) { mon_consume_unstone(mon, obj, by_you, TRUE); return TRUE; } } return FALSE; } STATIC_OVL void mon_consume_unstone(mon, obj, by_you, stoning) struct monst *mon; struct obj *obj; boolean by_you; boolean stoning; { int nutrit = (obj->otyp == CORPSE) ? dog_nutrition(mon, obj) : 0; /* also sets meating */ /* give a " is slowing down" message and also remove intrinsic speed (comparable to similar effect on the hero) */ mon_adjust_speed(mon, -3, (struct obj *)0); if (canseemon(mon)) { long save_quan = obj->quan; obj->quan = 1L; pline("%s %ss %s.", Monnam(mon), (obj->otyp == POT_ACID) ? "quaff" : "eat", distant_name(obj,doname)); obj->quan = save_quan; } else if (flags.soundok) You_hear("%s.", (obj->otyp == POT_ACID) ? "drinking" : "chewing"); m_useup(mon, obj); if (((obj->otyp == POT_ACID) || acidic(&mons[obj->corpsenm])) && !resists_acid(mon)) { mon->mhp -= rnd(15); pline("%s has a very bad case of stomach acid.", Monnam(mon)); } if (mon->mhp <= 0) { pline("%s dies!", Monnam(mon)); if (by_you) xkilled(mon, 0); else mondead(mon); return; } if (stoning && canseemon(mon)) { if (Hallucination) pline("What a pity - %s just ruined a future piece of art!", mon_nam(mon)); else pline("%s seems limber!", Monnam(mon)); } if (obj->otyp == CORPSE && obj->corpsenm == PM_LIZARD && mon->mconf) { mon->mconf = 0; if (canseemon(mon)) pline("%s seems steadier now.", Monnam(mon)); } if (mon->mtame && !mon->isminion && nutrit > 0) { struct edog *edog = EDOG(mon); if (edog->hungrytime < monstermoves) edog->hungrytime = monstermoves; edog->hungrytime += nutrit; mon->mconf = 0; } mon->mlstmv = monstermoves; /* it takes a turn */ } /*muse.c*/ nethack-3.4.3/src/music.c0100644000000000000000000004600407764735041013731 0ustar rootroot/* SCCS Id: @(#)music.c 3.4 2003/05/25 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the different functions designed to manipulate the * musical instruments and their various effects. * * Actually the list of instruments / effects is : * * (wooden) flute may calm snakes if player has enough dexterity * magic flute may put monsters to sleep: area of effect depends * on player level. * (tooled) horn Will awaken monsters: area of effect depends on player * level. May also scare monsters. * fire horn Acts like a wand of fire. * frost horn Acts like a wand of cold. * bugle Will awaken soldiers (if any): area of effect depends * on player level. * (wooden) harp May calm nymph if player has enough dexterity. * magic harp Charm monsters: area of effect depends on player * level. * (leather) drum Will awaken monsters like the horn. * drum of earthquake Will initiate an earthquake whose intensity depends * on player level. That is, it creates random pits * called here chasms. */ #include "hack.h" STATIC_DCL void FDECL(awaken_monsters,(int)); STATIC_DCL void FDECL(put_monsters_to_sleep,(int)); STATIC_DCL void FDECL(charm_snakes,(int)); STATIC_DCL void FDECL(calm_nymphs,(int)); STATIC_DCL void FDECL(charm_monsters,(int)); STATIC_DCL void FDECL(do_earthquake,(int)); STATIC_DCL int FDECL(do_improvisation,(struct obj *)); #ifdef UNIX386MUSIC STATIC_DCL int NDECL(atconsole); STATIC_DCL void FDECL(speaker,(struct obj *,char *)); #endif #ifdef VPIX_MUSIC extern int sco_flag_console; /* will need changing if not _M_UNIX */ STATIC_DCL void NDECL(playinit); STATIC_DCL void FDECL(playstring, (char *,size_t)); STATIC_DCL void FDECL(speaker,(struct obj *,char *)); #endif #ifdef PCMUSIC void FDECL( pc_speaker, ( struct obj *, char * ) ); #endif #ifdef AMIGA void FDECL( amii_speaker, ( struct obj *, char *, int ) ); #endif /* * Wake every monster in range... */ STATIC_OVL void awaken_monsters(distance) int distance; { register struct monst *mtmp = fmon; register int distm; while(mtmp) { if (!DEADMONSTER(mtmp)) { distm = distu(mtmp->mx, mtmp->my); if (distm < distance) { mtmp->msleeping = 0; mtmp->mcanmove = 1; mtmp->mfrozen = 0; /* May scare some monsters */ if (distm < distance/3 && !resist(mtmp, TOOL_CLASS, 0, NOTELL)) monflee(mtmp, 0, FALSE, TRUE); } } mtmp = mtmp->nmon; } } /* * Make monsters fall asleep. Note that they may resist the spell. */ STATIC_OVL void put_monsters_to_sleep(distance) int distance; { register struct monst *mtmp = fmon; while(mtmp) { if (!DEADMONSTER(mtmp) && distu(mtmp->mx, mtmp->my) < distance && sleep_monst(mtmp, d(10,10), TOOL_CLASS)) { mtmp->msleeping = 1; /* 10d10 turns + wake_nearby to rouse */ slept_monst(mtmp); } mtmp = mtmp->nmon; } } /* * Charm snakes in range. Note that the snakes are NOT tamed. */ STATIC_OVL void charm_snakes(distance) int distance; { register struct monst *mtmp = fmon; int could_see_mon, was_peaceful; while (mtmp) { if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_SNAKE && mtmp->mcanmove && distu(mtmp->mx, mtmp->my) < distance) { was_peaceful = mtmp->mpeaceful; mtmp->mpeaceful = 1; mtmp->mavenge = 0; could_see_mon = canseemon(mtmp); mtmp->mundetected = 0; newsym(mtmp->mx, mtmp->my); if (canseemon(mtmp)) { if (!could_see_mon) You("notice %s, swaying with the music.", a_monnam(mtmp)); else pline("%s freezes, then sways with the music%s.", Monnam(mtmp), was_peaceful ? "" : ", and now seems quieter"); } } mtmp = mtmp->nmon; } } /* * Calm nymphs in range. */ STATIC_OVL void calm_nymphs(distance) int distance; { register struct monst *mtmp = fmon; while (mtmp) { if (!DEADMONSTER(mtmp) && mtmp->data->mlet == S_NYMPH && mtmp->mcanmove && distu(mtmp->mx, mtmp->my) < distance) { mtmp->msleeping = 0; mtmp->mpeaceful = 1; mtmp->mavenge = 0; if (canseemon(mtmp)) pline( "%s listens cheerfully to the music, then seems quieter.", Monnam(mtmp)); } mtmp = mtmp->nmon; } } /* Awake only soldiers of the level. */ void awaken_soldiers() { register struct monst *mtmp = fmon; while(mtmp) { if (!DEADMONSTER(mtmp) && is_mercenary(mtmp->data) && mtmp->data != &mons[PM_GUARD]) { mtmp->mpeaceful = mtmp->msleeping = mtmp->mfrozen = 0; mtmp->mcanmove = 1; if (canseemon(mtmp)) pline("%s is now ready for battle!", Monnam(mtmp)); else Norep("You hear the rattle of battle gear being readied."); } mtmp = mtmp->nmon; } } /* Charm monsters in range. Note that they may resist the spell. * If swallowed, range is reduced to 0. */ STATIC_OVL void charm_monsters(distance) int distance; { struct monst *mtmp, *mtmp2; if (u.uswallow) { if (!resist(u.ustuck, TOOL_CLASS, 0, NOTELL)) (void) tamedog(u.ustuck, (struct obj *) 0); } else { for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (distu(mtmp->mx, mtmp->my) <= distance) { if (!resist(mtmp, TOOL_CLASS, 0, NOTELL)) (void) tamedog(mtmp, (struct obj *) 0); } } } } /* Generate earthquake :-) of desired force. * That is: create random chasms (pits). */ STATIC_OVL void do_earthquake(force) int force; { register int x,y; struct monst *mtmp; struct obj *otmp; struct trap *chasm; int start_x, start_y, end_x, end_y; start_x = u.ux - (force * 2); start_y = u.uy - (force * 2); end_x = u.ux + (force * 2); end_y = u.uy + (force * 2); if (start_x < 1) start_x = 1; if (start_y < 1) start_y = 1; if (end_x >= COLNO) end_x = COLNO - 1; if (end_y >= ROWNO) end_y = ROWNO - 1; for (x=start_x; x<=end_x; x++) for (y=start_y; y<=end_y; y++) { if ((mtmp = m_at(x,y)) != 0) { wakeup(mtmp); /* peaceful monster will become hostile */ if (mtmp->mundetected && is_hider(mtmp->data)) { mtmp->mundetected = 0; if (cansee(x,y)) pline("%s is shaken loose from the ceiling!", Amonnam(mtmp)); else You_hear("a thumping sound."); if (x==u.ux && y==u.uy) You("easily dodge the falling %s.", mon_nam(mtmp)); newsym(x,y); } } if (!rn2(14 - force)) switch (levl[x][y].typ) { case FOUNTAIN : /* Make the fountain disappear */ if (cansee(x,y)) pline_The("fountain falls into a chasm."); goto do_pit; #ifdef SINKS case SINK : if (cansee(x,y)) pline_The("kitchen sink falls into a chasm."); goto do_pit; #endif case ALTAR : if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) break; if (cansee(x,y)) pline_The("altar falls into a chasm."); goto do_pit; case GRAVE : if (cansee(x,y)) pline_The("headstone topples into a chasm."); goto do_pit; case THRONE : if (cansee(x,y)) pline_The("throne falls into a chasm."); /* Falls into next case */ case ROOM : case CORR : /* Try to make a pit */ do_pit: chasm = maketrap(x,y,PIT); if (!chasm) break; /* no pit if portal at that location */ chasm->tseen = 1; levl[x][y].doormask = 0; mtmp = m_at(x,y); if ((otmp = sobj_at(BOULDER, x, y)) != 0) { if (cansee(x, y)) pline("KADOOM! The boulder falls into a chasm%s!", ((x == u.ux) && (y == u.uy)) ? " below you" : ""); if (mtmp) mtmp->mtrapped = 0; obj_extract_self(otmp); (void) flooreffects(otmp, x, y, ""); break; } /* We have to check whether monsters or player falls in a chasm... */ if (mtmp) { if(!is_flyer(mtmp->data) && !is_clinger(mtmp->data)) { mtmp->mtrapped = 1; if(cansee(x,y)) pline("%s falls into a chasm!", Monnam(mtmp)); else if (flags.soundok && humanoid(mtmp->data)) You_hear("a scream!"); mselftouch(mtmp, "Falling, ", TRUE); if (mtmp->mhp > 0) if ((mtmp->mhp -= rnd(6)) <= 0) { if(!cansee(x,y)) pline("It is destroyed!"); else { You("destroy %s!", mtmp->mtame ? x_monnam(mtmp, ARTICLE_THE, "poor", mtmp->mnamelth ? SUPPRESS_SADDLE : 0, FALSE): mon_nam(mtmp)); } xkilled(mtmp,0); } } } else if (x == u.ux && y == u.uy) { if (Levitation || Flying || is_clinger(youmonst.data)) { pline("A chasm opens up under you!"); You("don't fall in!"); } else { You("fall into a chasm!"); u.utrap = rn1(6,2); u.utraptype = TT_PIT; losehp(rnd(6),"fell into a chasm", NO_KILLER_PREFIX); selftouch("Falling, you"); } } else newsym(x,y); break; case DOOR : /* Make the door collapse */ if (levl[x][y].doormask == D_NODOOR) goto do_pit; if (cansee(x,y)) pline_The("door collapses."); if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); levl[x][y].doormask = D_NODOOR; unblock_point(x,y); newsym(x,y); break; } } } /* * The player is trying to extract something from his/her instrument. */ STATIC_OVL int do_improvisation(instr) struct obj *instr; { int damage, do_spec = !Confusion; #if defined(MAC) || defined(AMIGA) || defined(VPIX_MUSIC) || defined (PCMUSIC) struct obj itmp; itmp = *instr; /* if won't yield special effect, make sound of mundane counterpart */ if (!do_spec || instr->spe <= 0) while (objects[itmp.otyp].oc_magic) itmp.otyp -= 1; # ifdef MAC mac_speaker(&itmp, "C"); # endif # ifdef AMIGA amii_speaker(&itmp, "Cw", AMII_OKAY_VOLUME); # endif # ifdef VPIX_MUSIC if (sco_flag_console) speaker(&itmp, "C"); # endif #ifdef PCMUSIC pc_speaker ( &itmp, "C"); #endif #endif /* MAC || AMIGA || VPIX_MUSIC || PCMUSIC */ if (!do_spec) pline("What you produce is quite far from music..."); else You("start playing %s.", the(xname(instr))); switch (instr->otyp) { case MAGIC_FLUTE: /* Make monster fall asleep */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); You("produce soft music."); put_monsters_to_sleep(u.ulevel * 5); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_FLUTE: /* May charm snakes */ do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25); pline("%s.", Tobjnam(instr, do_spec ? "trill" : "toot")); if (do_spec) charm_snakes(u.ulevel * 3); exercise(A_DEX, TRUE); break; case FROST_HORN: /* Idem wand of cold */ case FIRE_HORN: /* Idem wand of fire */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); if (!getdir((char *)0)) { pline("%s.", Tobjnam(instr, "vibrate")); break; } else if (!u.dx && !u.dy && !u.dz) { if ((damage = zapyourself(instr, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "using a magical horn on %sself", uhim()); losehp(damage, buf, KILLED_BY); } } else { buzz((instr->otyp == FROST_HORN) ? AD_COLD-1 : AD_FIRE-1, rn1(6,6), u.ux, u.uy, u.dx, u.dy); } makeknown(instr->otyp); break; } /* else FALLTHRU */ case TOOLED_HORN: /* Awaken or scare monsters */ You("produce a frightful, grave sound."); awaken_monsters(u.ulevel * 30); exercise(A_WIS, FALSE); break; case BUGLE: /* Awaken & attract soldiers */ You("extract a loud noise from %s.", the(xname(instr))); awaken_soldiers(); exercise(A_WIS, FALSE); break; case MAGIC_HARP: /* Charm monsters */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); pline("%s very attractive music.", Tobjnam(instr, "produce")); charm_monsters((u.ulevel - 1) / 3 + 1); exercise(A_DEX, TRUE); break; } /* else FALLTHRU */ case WOODEN_HARP: /* May calm Nymph */ do_spec &= (rn2(ACURR(A_DEX)) + u.ulevel > 25); pline("%s %s.", The(xname(instr)), do_spec ? "produces a lilting melody" : "twangs"); if (do_spec) calm_nymphs(u.ulevel * 3); exercise(A_DEX, TRUE); break; case DRUM_OF_EARTHQUAKE: /* create several pits */ if (do_spec && instr->spe > 0) { consume_obj_charge(instr, TRUE); You("produce a heavy, thunderous rolling!"); pline_The("entire dungeon is shaking around you!"); do_earthquake((u.ulevel - 1) / 3 + 1); /* shake up monsters in a much larger radius... */ awaken_monsters(ROWNO * COLNO); makeknown(DRUM_OF_EARTHQUAKE); break; } /* else FALLTHRU */ case LEATHER_DRUM: /* Awaken monsters */ You("beat a deafening row!"); awaken_monsters(u.ulevel * 40); exercise(A_WIS, FALSE); break; default: impossible("What a weird instrument (%d)!", instr->otyp); break; } return 2; /* That takes time */ } /* * So you want music... */ int do_play_instrument(instr) struct obj *instr; { char buf[BUFSZ], c = 'y'; char *s; int x,y; boolean ok; if (Underwater) { You_cant("play music underwater!"); return(0); } if (instr->otyp != LEATHER_DRUM && instr->otyp != DRUM_OF_EARTHQUAKE) { c = yn("Improvise?"); } if (c == 'n') { if (u.uevent.uheard_tune == 2 && yn("Play the passtune?") == 'y') { Strcpy(buf, tune); } else { getlin("What tune are you playing? [5 notes, A-G]", buf); (void)mungspaces(buf); /* convert to uppercase and change any "H" to the expected "B" */ for (s = buf; *s; s++) { #ifndef AMIGA *s = highc(*s); #else /* The AMIGA supports two octaves of notes */ if (*s == 'h') *s = 'b'; #endif if (*s == 'H') *s = 'B'; } } You("extract a strange sound from %s!", the(xname(instr))); #ifdef UNIX386MUSIC /* if user is at the console, play through the console speaker */ if (atconsole()) speaker(instr, buf); #endif #ifdef VPIX_MUSIC if (sco_flag_console) speaker(instr, buf); #endif #ifdef MAC mac_speaker ( instr , buf ) ; #endif #ifdef PCMUSIC pc_speaker ( instr, buf ); #endif #ifdef AMIGA { char nbuf[ 20 ]; int i; for( i = 0; buf[i] && i < 5; ++i ) { nbuf[ i*2 ] = buf[ i ]; nbuf[ (i*2)+1 ] = 'h'; } nbuf[ i*2 ] = 0; amii_speaker ( instr , nbuf, AMII_OKAY_VOLUME ) ; } #endif /* Check if there was the Stronghold drawbridge near * and if the tune conforms to what we're waiting for. */ if(Is_stronghold(&u.uz)) { exercise(A_WIS, TRUE); /* just for trying */ if(!strcmp(buf,tune)) { /* Search for the drawbridge */ for(y=u.uy-1; y<=u.uy+1; y++) for(x=u.ux-1;x<=u.ux+1;x++) if(isok(x,y)) if(find_drawbridge(&x,&y)) { u.uevent.uheard_tune = 2; /* tune now fully known */ if(levl[x][y].typ == DRAWBRIDGE_DOWN) close_drawbridge(x,y); else open_drawbridge(x,y); return 0; } } else if(flags.soundok) { if (u.uevent.uheard_tune < 1) u.uevent.uheard_tune = 1; /* Okay, it wasn't the right tune, but perhaps * we can give the player some hints like in the * Mastermind game */ ok = FALSE; for(y = u.uy-1; y <= u.uy+1 && !ok; y++) for(x = u.ux-1; x <= u.ux+1 && !ok; x++) if(isok(x,y)) if(IS_DRAWBRIDGE(levl[x][y].typ) || is_drawbridge_wall(x,y) >= 0) ok = TRUE; if(ok) { /* There is a drawbridge near */ int tumblers, gears; boolean matched[5]; tumblers = gears = 0; for(x=0; x < 5; x++) matched[x] = FALSE; for(x=0; x < (int)strlen(buf); x++) if(x < 5) { if(buf[x] == tune[x]) { gears++; matched[x] = TRUE; } else for(y=0; y < 5; y++) if(!matched[y] && buf[x] == tune[y] && buf[y] != tune[y]) { tumblers++; matched[y] = TRUE; break; } } if(tumblers) if(gears) You_hear("%d tumbler%s click and %d gear%s turn.", tumblers, plur(tumblers), gears, plur(gears)); else You_hear("%d tumbler%s click.", tumblers, plur(tumblers)); else if(gears) { You_hear("%d gear%s turn.", gears, plur(gears)); /* could only get `gears == 5' by playing five correct notes followed by excess; otherwise, tune would have matched above */ if (gears == 5) u.uevent.uheard_tune = 2; } } } } return 1; } else return do_improvisation(instr); } #ifdef UNIX386MUSIC /* * Play audible music on the machine's speaker if appropriate. */ STATIC_OVL int atconsole() { /* * Kluge alert: This code assumes that your [34]86 has no X terminals * attached and that the console tty type is AT386 (this is always true * under AT&T UNIX for these boxen). The theory here is that your remote * ttys will have terminal type `ansi' or something else other than * `AT386' or `xterm'. We'd like to do better than this, but testing * to see if we're running on the console physical terminal is quite * difficult given the presence of virtual consoles and other modern * UNIX impedimenta... */ char *termtype = nh_getenv("TERM"); return(!strcmp(termtype, "AT386") || !strcmp(termtype, "xterm")); } STATIC_OVL void speaker(instr, buf) struct obj *instr; char *buf; { /* * For this to work, you need to have installed the PD speaker-control * driver for PC-compatible UNIX boxes that I (esr@snark.thyrsus.com) * posted to comp.sources.unix in Feb 1990. A copy should be included * with your nethack distribution. */ int fd; if ((fd = open("/dev/speaker", 1)) != -1) { /* send a prefix to modify instrumental `timbre' */ switch (instr->otyp) { case WOODEN_FLUTE: case MAGIC_FLUTE: (void) write(fd, ">ol", 1); /* up one octave & lock */ break; case TOOLED_HORN: case FROST_HORN: case FIRE_HORN: (void) write(fd, "< #include #include # else #define KIOC ('K' << 8) #define KDMKTONE (KIOC | 8) # endif #define noDEBUG STATIC_OVL void tone(hz, ticks) /* emit tone of frequency hz for given number of ticks */ unsigned int hz, ticks; { ioctl(0,KDMKTONE,hz|((ticks*10)<<16)); # ifdef DEBUG printf("TONE: %6d %6d\n",hz,ticks * 10); # endif nap(ticks * 10); } STATIC_OVL void rest(ticks) /* rest for given number of ticks */ int ticks; { nap(ticks * 10); # ifdef DEBUG printf("REST: %6d\n",ticks * 10); # endif } #include "interp.c" /* from snd86unx.shr */ STATIC_OVL void speaker(instr, buf) struct obj *instr; char *buf; { /* emit a prefix to modify instrumental `timbre' */ playinit(); switch (instr->otyp) { case WOODEN_FLUTE: case MAGIC_FLUTE: playstring(">ol", 1); /* up one octave & lock */ break; case TOOLED_HORN: case FROST_HORN: case FIRE_HORN: playstring("< maxledgerno()) ? maxledgerno() : ledger_no(dlev); else lev = 0; first = bases[GEM_CLASS]; for(j = 0; j < 9-lev/3; j++) objects[first+j].oc_prob = 0; first += j; if (first > LAST_GEM || objects[first].oc_class != GEM_CLASS || OBJ_NAME(objects[first]) == (char *)0) { raw_printf("Not enough gems? - first=%d j=%d LAST_GEM=%d", first, j, LAST_GEM); wait_synch(); } for (j = first; j <= LAST_GEM; j++) objects[j].oc_prob = (171+j-first)/(LAST_GEM+1-first); } /* shuffle descriptions on objects o_low to o_high */ STATIC_OVL void shuffle(o_low, o_high, domaterial) int o_low, o_high; boolean domaterial; { int i, j, num_to_shuffle; short sw; int color; for (num_to_shuffle = 0, j=o_low; j <= o_high; j++) if (!objects[j].oc_name_known) num_to_shuffle++; if (num_to_shuffle < 2) return; for (j=o_low; j <= o_high; j++) { if (objects[j].oc_name_known) continue; do i = j + rn2(o_high-j+1); while (objects[i].oc_name_known); sw = objects[j].oc_descr_idx; objects[j].oc_descr_idx = objects[i].oc_descr_idx; objects[i].oc_descr_idx = sw; sw = objects[j].oc_tough; objects[j].oc_tough = objects[i].oc_tough; objects[i].oc_tough = sw; color = objects[j].oc_color; objects[j].oc_color = objects[i].oc_color; objects[i].oc_color = color; /* shuffle material */ if (domaterial) { sw = objects[j].oc_material; objects[j].oc_material = objects[i].oc_material; objects[i].oc_material = sw; } } } void init_objects() { register int i, first, last, sum; register char oclass; #ifdef TEXTCOLOR # define COPY_OBJ_DESCR(o_dst,o_src) \ o_dst.oc_descr_idx = o_src.oc_descr_idx,\ o_dst.oc_color = o_src.oc_color #else # define COPY_OBJ_DESCR(o_dst,o_src) o_dst.oc_descr_idx = o_src.oc_descr_idx #endif /* bug fix to prevent "initialization error" abort on Intel Xenix. * reported by mikew@semike */ for (i = 0; i < MAXOCLASSES; i++) bases[i] = 0; /* initialize object descriptions */ for (i = 0; i < NUM_OBJECTS; i++) objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init base; if probs given check that they add up to 1000, otherwise compute probs */ first = 0; while( first < NUM_OBJECTS ) { oclass = objects[first].oc_class; last = first+1; while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++; bases[(int)oclass] = first; if (oclass == GEM_CLASS) { setgemprobs((d_level *)0); if (rn2(2)) { /* change turquoise from green to blue? */ COPY_OBJ_DESCR(objects[TURQUOISE],objects[SAPPHIRE]); } if (rn2(2)) { /* change aquamarine from green to blue? */ COPY_OBJ_DESCR(objects[AQUAMARINE],objects[SAPPHIRE]); } switch (rn2(4)) { /* change fluorite from violet? */ case 0: break; case 1: /* blue */ COPY_OBJ_DESCR(objects[FLUORITE],objects[SAPPHIRE]); break; case 2: /* white */ COPY_OBJ_DESCR(objects[FLUORITE],objects[DIAMOND]); break; case 3: /* green */ COPY_OBJ_DESCR(objects[FLUORITE],objects[EMERALD]); break; } } check: sum = 0; for(i = first; i < last; i++) sum += objects[i].oc_prob; if(sum == 0) { for(i = first; i < last; i++) objects[i].oc_prob = (1000+i-first)/(last-first); goto check; } if(sum != 1000) error("init-prob error for class %d (%d%%)", oclass, sum); first = last; } /* shuffle descriptions */ shuffle_all(); #ifdef USE_TILES shuffle_tiles(); #endif } STATIC_OVL void shuffle_all() { int first, last, oclass; for (oclass = 1; oclass < MAXOCLASSES; oclass++) { first = bases[oclass]; last = first+1; while (last < NUM_OBJECTS && objects[last].oc_class == oclass) last++; if (OBJ_DESCR(objects[first]) != (char *)0 && oclass != TOOL_CLASS && oclass != WEAPON_CLASS && oclass != ARMOR_CLASS && oclass != GEM_CLASS) { int j = last-1; if (oclass == POTION_CLASS) j -= 1; /* only water has a fixed description */ else if (oclass == AMULET_CLASS || oclass == SCROLL_CLASS || oclass == SPBOOK_CLASS) { while (!objects[j].oc_magic || objects[j].oc_unique) j--; } /* non-magical amulets, scrolls, and spellbooks * (ex. imitation Amulets, blank, scrolls of mail) * and one-of-a-kind magical artifacts at the end of * their class in objects[] have fixed descriptions. */ shuffle(first, j, TRUE); } } /* shuffle the helmets */ shuffle(HELMET, HELM_OF_TELEPATHY, FALSE); /* shuffle the gloves */ shuffle(LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY, FALSE); /* shuffle the cloaks */ shuffle(CLOAK_OF_PROTECTION, CLOAK_OF_DISPLACEMENT, FALSE); /* shuffle the boots [if they change, update find_skates() below] */ shuffle(SPEED_BOOTS, LEVITATION_BOOTS, FALSE); } /* find the object index for snow boots; used [once] by slippery ice code */ int find_skates() { register int i; register const char *s; for (i = SPEED_BOOTS; i <= LEVITATION_BOOTS; i++) if ((s = OBJ_DESCR(objects[i])) != 0 && !strcmp(s, "snow boots")) return i; impossible("snow boots not found?"); return -1; /* not 0, or caller would try again each move */ } void oinit() /* level dependent initialization */ { setgemprobs(&u.uz); } void savenames(fd, mode) int fd, mode; { register int i; unsigned int len; if (perform_bwrite(mode)) { bwrite(fd, (genericptr_t)bases, sizeof bases); bwrite(fd, (genericptr_t)disco, sizeof disco); bwrite(fd, (genericptr_t)objects, sizeof(struct objclass) * NUM_OBJECTS); } /* as long as we use only one version of Hack we need not save oc_name and oc_descr, but we must save oc_uname for all objects */ for (i = 0; i < NUM_OBJECTS; i++) if (objects[i].oc_uname) { if (perform_bwrite(mode)) { len = strlen(objects[i].oc_uname)+1; bwrite(fd, (genericptr_t)&len, sizeof len); bwrite(fd, (genericptr_t)objects[i].oc_uname, len); } if (release_data(mode)) { free((genericptr_t)objects[i].oc_uname); objects[i].oc_uname = 0; } } } void restnames(fd) register int fd; { register int i; unsigned int len; mread(fd, (genericptr_t) bases, sizeof bases); mread(fd, (genericptr_t) disco, sizeof disco); mread(fd, (genericptr_t) objects, sizeof(struct objclass) * NUM_OBJECTS); for (i = 0; i < NUM_OBJECTS; i++) if (objects[i].oc_uname) { mread(fd, (genericptr_t) &len, sizeof len); objects[i].oc_uname = (char *) alloc(len); mread(fd, (genericptr_t)objects[i].oc_uname, len); } #ifdef USE_TILES shuffle_tiles(); #endif } void discover_object(oindx, mark_as_known, credit_hero) register int oindx; boolean mark_as_known; boolean credit_hero; { if (!objects[oindx].oc_name_known) { register int dindx, acls = objects[oindx].oc_class; /* Loop thru disco[] 'til we find the target (which may have been uname'd) or the next open slot; one or the other will be found before we reach the next class... */ for (dindx = bases[acls]; disco[dindx] != 0; dindx++) if (disco[dindx] == oindx) break; disco[dindx] = oindx; if (mark_as_known) { objects[oindx].oc_name_known = 1; if (credit_hero) exercise(A_WIS, TRUE); } if (moves > 1L) update_inventory(); } } /* if a class name has been cleared, we may need to purge it from disco[] */ void undiscover_object(oindx) register int oindx; { if (!objects[oindx].oc_name_known) { register int dindx, acls = objects[oindx].oc_class; register boolean found = FALSE; /* find the object; shift those behind it forward one slot */ for (dindx = bases[acls]; dindx < NUM_OBJECTS && disco[dindx] != 0 && objects[dindx].oc_class == acls; dindx++) if (found) disco[dindx-1] = disco[dindx]; else if (disco[dindx] == oindx) found = TRUE; /* clear last slot */ if (found) disco[dindx-1] = 0; else impossible("named object not in disco"); update_inventory(); } } STATIC_OVL boolean interesting_to_discover(i) register int i; { /* Pre-discovered objects are now printed with a '*' */ return((boolean)(objects[i].oc_uname != (char *)0 || (objects[i].oc_name_known && OBJ_DESCR(objects[i]) != (char *)0))); } /* items that should stand out once they're known */ static short uniq_objs[] = { AMULET_OF_YENDOR, SPE_BOOK_OF_THE_DEAD, CANDELABRUM_OF_INVOCATION, BELL_OF_OPENING, }; int dodiscovered() /* free after Robert Viduya */ { register int i, dis; int ct = 0; char *s, oclass, prev_class, classes[MAXOCLASSES]; winid tmpwin; char buf[BUFSZ]; tmpwin = create_nhwindow(NHW_MENU); putstr(tmpwin, 0, "Discoveries"); putstr(tmpwin, 0, ""); /* gather "unique objects" into a pseudo-class; note that they'll also be displayed individually within their regular class */ for (i = dis = 0; i < SIZE(uniq_objs); i++) if (objects[uniq_objs[i]].oc_name_known) { if (!dis++) putstr(tmpwin, iflags.menu_headings, "Unique Items"); Sprintf(buf, " %s", OBJ_NAME(objects[uniq_objs[i]])); putstr(tmpwin, 0, buf); ++ct; } /* display any known artifacts as another pseudo-class */ ct += disp_artifact_discoveries(tmpwin); /* several classes are omitted from packorder; one is of interest here */ Strcpy(classes, flags.inv_order); if (!index(classes, VENOM_CLASS)) { s = eos(classes); *s++ = VENOM_CLASS; *s = '\0'; } for (s = classes; *s; s++) { oclass = *s; prev_class = oclass + 1; /* forced different from oclass */ for (i = bases[(int)oclass]; i < NUM_OBJECTS && objects[i].oc_class == oclass; i++) { if ((dis = disco[i]) && interesting_to_discover(dis)) { ct++; if (oclass != prev_class) { putstr(tmpwin, iflags.menu_headings, let_to_name(oclass, FALSE)); prev_class = oclass; } Sprintf(buf, "%s %s",(objects[dis].oc_pre_discovered ? "*" : " "), obj_typename(dis)); putstr(tmpwin, 0, buf); } } } if (ct == 0) { You("haven't discovered anything yet..."); } else display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); return 0; } /*o_init.c*/ nethack-3.4.3/src/objects.c0100644000000000000000000014140007764735041014236 0ustar rootroot/* SCCS Id: @(#)objects.c 3.4 2002/07/31 */ /* Copyright (c) Mike Threepoint, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef OBJECTS_PASS_2_ /* first pass */ struct monst { struct monst *dummy; }; /* lint: struct obj's union */ #include "config.h" #include "obj.h" #include "objclass.h" #include "prop.h" #include "skills.h" #else /* !OBJECTS_PASS_2_ */ /* second pass */ #include "color.h" # define COLOR_FIELD(X) X, #endif /* !OBJECTS_PASS_2_ */ /* objects have symbols: ) [ = " ( % ! ? + / $ * ` 0 _ . */ /* * Note: OBJ() and BITS() macros are used to avoid exceeding argument * limits imposed by some compilers. The ctnr field of BITS currently * does not map into struct objclass, and is ignored in the expansion. * The 0 in the expansion corresponds to oc_pre_discovered, which is * set at run-time during role-specific character initialization. */ #ifndef OBJECTS_PASS_2_ /* first pass -- object descriptive text */ # define OBJ(name,desc) name,desc # define OBJECT(obj,bits,prp,sym,prob,dly,wt,cost,sdam,ldam,oc1,oc2,nut,color) \ {obj} NEARDATA struct objdescr obj_descr[] = { #else /* second pass -- object definitions */ # define BITS(nmkn,mrg,uskn,ctnr,mgc,chrg,uniq,nwsh,big,tuf,dir,sub,mtrl) \ nmkn,mrg,uskn,0,mgc,chrg,uniq,nwsh,big,tuf,dir,mtrl,sub /* SCO ODT 1.1 cpp fodder */ # define OBJECT(obj,bits,prp,sym,prob,dly,wt,cost,sdam,ldam,oc1,oc2,nut,color) \ {0, 0, (char *)0, bits, prp, sym, dly, COLOR_FIELD(color) \ prob, wt, cost, sdam, ldam, oc1, oc2, nut} # ifndef lint # define HARDGEM(n) (n >= 8) # else # define HARDGEM(n) (0) # endif NEARDATA struct objclass objects[] = { #endif /* dummy object[0] -- description [2nd arg] *must* be NULL */ OBJECT(OBJ("strange object",(char *)0), BITS(1,0,0,0,0,0,0,0,0,0,0,P_NONE,0), 0, ILLOBJ_CLASS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), /* weapons ... */ #define WEAPON(name,app,kn,mg,bi,prob,wt,cost,sdam,ldam,hitbon,typ,sub,metal,color) \ OBJECT( \ OBJ(name,app), BITS(kn,mg,1,0,0,1,0,0,bi,0,typ,sub,metal), 0, \ WEAPON_CLASS, prob, 0, \ wt, cost, sdam, ldam, hitbon, 0, wt, color ) #define PROJECTILE(name,app,kn,prob,wt,cost,sdam,ldam,hitbon,metal,sub,color) \ OBJECT( \ OBJ(name,app), \ BITS(kn,1,1,0,0,1,0,0,0,0,PIERCE,sub,metal), 0, \ WEAPON_CLASS, prob, 0, \ wt, cost, sdam, ldam, hitbon, 0, wt, color ) #define BOW(name,app,kn,prob,wt,cost,hitbon,metal,sub,color) \ OBJECT( \ OBJ(name,app), BITS(kn,0,1,0,0,1,0,0,0,0,0,sub,metal), 0, \ WEAPON_CLASS, prob, 0, \ wt, cost, 2, 2, hitbon, 0, wt, color ) /* Note: for weapons that don't do an even die of damage (ex. 2-7 or 3-18) * the extra damage is added on in weapon.c, not here! */ #define P PIERCE #define S SLASH #define B WHACK /* missiles */ PROJECTILE("arrow", (char *)0, 1, 55, 1, 2, 6, 6, 0, IRON, -P_BOW, HI_METAL), PROJECTILE("elven arrow", "runed arrow", 0, 20, 1, 2, 7, 6, 0, WOOD, -P_BOW, HI_WOOD), PROJECTILE("orcish arrow", "crude arrow", 0, 20, 1, 2, 5, 6, 0, IRON, -P_BOW, CLR_BLACK), PROJECTILE("silver arrow", (char *)0, 1, 12, 1, 5, 6, 6, 0, SILVER, -P_BOW, HI_SILVER), PROJECTILE("ya", "bamboo arrow", 0, 15, 1, 4, 7, 7, 1, METAL, -P_BOW, HI_METAL), PROJECTILE("crossbow bolt", (char *)0, 1, 55, 1, 2, 4, 6, 0, IRON, -P_CROSSBOW, HI_METAL), WEAPON("dart", (char *)0, 1, 1, 0, 60, 1, 2, 3, 2, 0, P, -P_DART, IRON, HI_METAL), WEAPON("shuriken", "throwing star", 0, 1, 0, 35, 1, 5, 8, 6, 2, P, -P_SHURIKEN, IRON, HI_METAL), WEAPON("boomerang", (char *)0, 1, 1, 0, 15, 5, 20, 9, 9, 0, 0, -P_BOOMERANG, WOOD, HI_WOOD), /* spears */ WEAPON("spear", (char *)0, 1, 1, 0, 50, 30, 3, 6, 8, 0, P, P_SPEAR, IRON, HI_METAL), WEAPON("elven spear", "runed spear", 0, 1, 0, 10, 30, 3, 7, 8, 0, P, P_SPEAR, WOOD, HI_WOOD), WEAPON("orcish spear", "crude spear", 0, 1, 0, 13, 30, 3, 5, 8, 0, P, P_SPEAR, IRON, CLR_BLACK), WEAPON("dwarvish spear", "stout spear", 0, 1, 0, 12, 35, 3, 8, 8, 0, P, P_SPEAR, IRON, HI_METAL), WEAPON("silver spear", (char *)0, 1, 1, 0, 2, 36, 40, 6, 8, 0, P, P_SPEAR, SILVER, HI_SILVER), WEAPON("javelin", "throwing spear", 0, 1, 0, 10, 20, 3, 6, 6, 0, P, P_JAVELIN, IRON, HI_METAL), WEAPON("trident", (char *)0, 1, 0, 0, 8, 25, 5, 6, 4, 0, P, P_TRIDENT, IRON, HI_METAL), /* +1 small, +2d4 large */ /* blades */ WEAPON("dagger", (char *)0, 1, 1, 0, 30, 10, 4, 4, 3, 2, P, P_DAGGER, IRON, HI_METAL), WEAPON("elven dagger", "runed dagger", 0, 1, 0, 10, 10, 4, 5, 3, 2, P, P_DAGGER, WOOD, HI_WOOD), WEAPON("orcish dagger", "crude dagger", 0, 1, 0, 12, 10, 4, 3, 3, 2, P, P_DAGGER, IRON, CLR_BLACK), WEAPON("silver dagger", (char *)0, 1, 1, 0, 3, 12, 40, 4, 3, 2, P, P_DAGGER, SILVER, HI_SILVER), WEAPON("athame", (char *)0, 1, 1, 0, 0, 10, 4, 4, 3, 2, S, P_DAGGER, IRON, HI_METAL), WEAPON("scalpel", (char *)0, 1, 1, 0, 0, 5, 6, 3, 3, 2, S, P_KNIFE, METAL, HI_METAL), WEAPON("knife", (char *)0, 1, 1, 0, 20, 5, 4, 3, 2, 0, P|S, P_KNIFE, IRON, HI_METAL), WEAPON("stiletto", (char *)0, 1, 1, 0, 5, 5, 4, 3, 2, 0, P|S, P_KNIFE, IRON, HI_METAL), WEAPON("worm tooth", (char *)0, 1, 0, 0, 0, 20, 2, 2, 2, 0, 0, P_KNIFE, 0, CLR_WHITE), WEAPON("crysknife", (char *)0, 1, 0, 0, 0, 20,100, 10, 10, 3, P, P_KNIFE, MINERAL, CLR_WHITE), WEAPON("axe", (char *)0, 1, 0, 0, 40, 60, 8, 6, 4, 0, S, P_AXE, IRON, HI_METAL), WEAPON("battle-axe", "double-headed axe", 0, 0, 1, 10,120, 40, 8, 6, 0, S, P_AXE, IRON, HI_METAL), /* "double-bitted" ? */ /* swords */ WEAPON("short sword", (char *)0, 1, 0, 0, 8, 30, 10, 6, 8, 0, P, P_SHORT_SWORD, IRON, HI_METAL), WEAPON("elven short sword", "runed short sword", 0, 0, 0, 2, 30, 10, 8, 8, 0, P, P_SHORT_SWORD, WOOD, HI_WOOD), WEAPON("orcish short sword", "crude short sword", 0, 0, 0, 3, 30, 10, 5, 8, 0, P, P_SHORT_SWORD, IRON, CLR_BLACK), WEAPON("dwarvish short sword", "broad short sword", 0, 0, 0, 2, 30, 10, 7, 8, 0, P, P_SHORT_SWORD, IRON, HI_METAL), WEAPON("scimitar", "curved sword", 0, 0, 0, 15, 40, 15, 8, 8, 0, S, P_SCIMITAR, IRON, HI_METAL), WEAPON("silver saber", (char *)0, 1, 0, 0, 6, 40, 75, 8, 8, 0, S, P_SABER, SILVER, HI_SILVER), WEAPON("broadsword", (char *)0, 1, 0, 0, 8, 70, 10, 4, 6, 0, S, P_BROAD_SWORD, IRON, HI_METAL), /* +d4 small, +1 large */ WEAPON("elven broadsword", "runed broadsword", 0, 0, 0, 4, 70, 10, 6, 6, 0, S, P_BROAD_SWORD, WOOD, HI_WOOD), /* +d4 small, +1 large */ WEAPON("long sword", (char *)0, 1, 0, 0, 50, 40, 15, 8, 12, 0, S, P_LONG_SWORD, IRON, HI_METAL), WEAPON("two-handed sword", (char *)0, 1, 0, 1, 22,150, 50, 12, 6, 0, S, P_TWO_HANDED_SWORD, IRON, HI_METAL), /* +2d6 large */ WEAPON("katana", "samurai sword", 0, 0, 0, 4, 40, 80, 10, 12, 1, S, P_LONG_SWORD, IRON, HI_METAL), /* special swords set up for artifacts */ WEAPON("tsurugi", "long samurai sword", 0, 0, 1, 0, 60,500, 16, 8, 2, S, P_TWO_HANDED_SWORD, METAL, HI_METAL), /* +2d6 large */ WEAPON("runesword", "runed broadsword", 0, 0, 0, 0, 40,300, 4, 6, 0, S, P_BROAD_SWORD, IRON, CLR_BLACK), /* +d4 small, +1 large */ /* +5d2 +d8 from level drain */ /* polearms */ /* spear-type */ WEAPON("partisan", "vulgar polearm", 0, 0, 1, 5, 80, 10, 6, 6, 0, P, P_POLEARMS, IRON, HI_METAL), /* +1 large */ WEAPON("ranseur", "hilted polearm", 0, 0, 1, 5, 50, 6, 4, 4, 0, P, P_POLEARMS, IRON, HI_METAL), /* +d4 both */ WEAPON("spetum", "forked polearm", 0, 0, 1, 5, 50, 5, 6, 6, 0, P, P_POLEARMS, IRON, HI_METAL), /* +1 small, +d6 large */ WEAPON("glaive", "single-edged polearm", 0, 0, 1, 8, 75, 6, 6, 10, 0, S, P_POLEARMS, IRON, HI_METAL), WEAPON("lance", (char *)0, 1, 0, 0, 4,180, 10, 6, 8, 0, P, P_LANCE, IRON, HI_METAL), /* axe-type */ WEAPON("halberd", "angled poleaxe", 0, 0, 1, 8,150, 10, 10, 6, 0, P|S, P_POLEARMS, IRON, HI_METAL), /* +1d6 large */ WEAPON("bardiche", "long poleaxe", 0, 0, 1, 4,120, 7, 4, 4, 0, S, P_POLEARMS, IRON, HI_METAL), /* +1d4 small, +2d4 large */ WEAPON("voulge", "pole cleaver", 0, 0, 1, 4,125, 5, 4, 4, 0, S, P_POLEARMS, IRON, HI_METAL), /* +d4 both */ WEAPON("dwarvish mattock", "broad pick", 0, 0, 1, 13,120, 50, 12, 8,-1, B, P_PICK_AXE, IRON, HI_METAL), /* curved/hooked */ WEAPON("fauchard", "pole sickle", 0, 0, 1, 6, 60, 5, 6, 8, 0, P|S, P_POLEARMS, IRON, HI_METAL), WEAPON("guisarme", "pruning hook", 0, 0, 1, 6, 80, 5, 4, 8, 0, S, P_POLEARMS, IRON, HI_METAL), /* +1d4 small */ WEAPON("bill-guisarme", "hooked polearm", 0, 0, 1, 4,120, 7, 4, 10, 0, P|S, P_POLEARMS, IRON, HI_METAL), /* +1d4 small */ /* other */ WEAPON("lucern hammer", "pronged polearm", 0, 0, 1, 5,150, 7, 4, 6, 0, B|P, P_POLEARMS, IRON, HI_METAL), /* +1d4 small */ WEAPON("bec de corbin", "beaked polearm", 0, 0, 1, 4,100, 8, 8, 6, 0, B|P, P_POLEARMS, IRON, HI_METAL), /* bludgeons */ WEAPON("mace", (char *)0, 1, 0, 0, 40, 30, 5, 6, 6, 0, B, P_MACE, IRON, HI_METAL), /* +1 small */ WEAPON("morning star", (char *)0, 1, 0, 0, 12,120, 10, 4, 6, 0, B, P_MORNING_STAR, IRON, HI_METAL), /* +d4 small, +1 large */ WEAPON("war hammer", (char *)0, 1, 0, 0, 15, 50, 5, 4, 4, 0, B, P_HAMMER, IRON, HI_METAL), /* +1 small */ WEAPON("club", (char *)0, 1, 0, 0, 12, 30, 3, 6, 3, 0, B, P_CLUB, WOOD, HI_WOOD), #ifdef KOPS WEAPON("rubber hose", (char *)0, 1, 0, 0, 0, 20, 3, 4, 3, 0, B, P_WHIP, PLASTIC, CLR_BROWN), #endif WEAPON("quarterstaff", "staff", 0, 0, 1, 11, 40, 5, 6, 6, 0, B, P_QUARTERSTAFF, WOOD, HI_WOOD), /* two-piece */ WEAPON("aklys", "thonged club", 0, 0, 0, 8, 15, 4, 6, 3, 0, B, P_CLUB, IRON, HI_METAL), WEAPON("flail", (char *)0, 1, 0, 0, 40, 15, 4, 6, 4, 0, B, P_FLAIL, IRON, HI_METAL), /* +1 small, +1d4 large */ /* misc */ WEAPON("bullwhip", (char *)0, 1, 0, 0, 2, 20, 4, 2, 1, 0, 0, P_WHIP, LEATHER, CLR_BROWN), /* bows */ BOW("bow", (char *)0, 1, 24, 30, 60, 0, WOOD, P_BOW, HI_WOOD), BOW("elven bow", "runed bow", 0, 12, 30, 60, 0, WOOD, P_BOW, HI_WOOD), BOW("orcish bow", "crude bow", 0, 12, 30, 60, 0, WOOD, P_BOW, CLR_BLACK), BOW("yumi", "long bow", 0, 0, 30, 60, 0, WOOD, P_BOW, HI_WOOD), BOW("sling", (char *)0, 1, 40, 3, 20, 0, LEATHER, P_SLING, HI_LEATHER), BOW("crossbow", (char *)0, 1, 45, 50, 40, 0, WOOD, P_CROSSBOW, HI_WOOD), #undef P #undef S #undef B #undef WEAPON #undef PROJECTILE #undef BOW /* armor ... */ /* IRON denotes ferrous metals, including steel. * Only IRON weapons and armor can rust. * Only COPPER (including brass) corrodes. * Some creatures are vulnerable to SILVER. */ #define ARMOR(name,desc,kn,mgc,blk,power,prob,delay,wt,cost,ac,can,sub,metal,c) \ OBJECT( \ OBJ(name,desc), BITS(kn,0,1,0,mgc,1,0,0,blk,0,0,sub,metal), power, \ ARMOR_CLASS, prob, delay, wt, cost, \ 0, 0, 10 - ac, can, wt, c ) #define HELM(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name,desc,kn,mgc,0,power,prob,delay,wt,cost,ac,can,ARM_HELM,metal,c) #define CLOAK(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name,desc,kn,mgc,0,power,prob,delay,wt,cost,ac,can,ARM_CLOAK,metal,c) #define SHIELD(name,desc,kn,mgc,blk,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name,desc,kn,mgc,blk,power,prob,delay,wt,cost,ac,can,ARM_SHIELD,metal,c) #define GLOVES(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name,desc,kn,mgc,0,power,prob,delay,wt,cost,ac,can,ARM_GLOVES,metal,c) #define BOOTS(name,desc,kn,mgc,power,prob,delay,wt,cost,ac,can,metal,c) \ ARMOR(name,desc,kn,mgc,0,power,prob,delay,wt,cost,ac,can,ARM_BOOTS,metal,c) /* helmets */ HELM("elven leather helm", "leather hat", 0, 0, 0, 6, 1, 3, 8, 9, 0, LEATHER, HI_LEATHER), HELM("orcish helm", "iron skull cap", 0, 0, 0, 6, 1, 30, 10, 9, 0, IRON, CLR_BLACK), HELM("dwarvish iron helm", "hard hat", 0, 0, 0, 6, 1, 40, 20, 8, 0, IRON, HI_METAL), HELM("fedora", (char *)0, 1, 0, 0, 0, 0, 3, 1,10, 0, CLOTH, CLR_BROWN), HELM("cornuthaum", "conical hat", 0, 1, CLAIRVOYANT, 3, 1, 4, 80,10, 2, CLOTH, CLR_BLUE), HELM("dunce cap", "conical hat", 0, 1, 0, 3, 1, 4, 1,10, 0, CLOTH, CLR_BLUE), HELM("dented pot", (char *)0, 1, 0, 0, 2, 0, 10, 8, 9, 0, IRON, CLR_BLACK), /* With shuffled appearances... */ HELM("helmet", "plumed helmet", 0, 0, 0, 10, 1, 30, 10, 9, 0, IRON, HI_METAL), HELM("helm of brilliance", "etched helmet", 0, 1, 0, 6, 1, 50, 50, 9, 0, IRON, CLR_GREEN), HELM("helm of opposite alignment", "crested helmet", 0, 1, 0, 6, 1, 50, 50, 9, 0, IRON, HI_METAL), HELM("helm of telepathy", "visored helmet", 0, 1, TELEPAT, 2, 1, 50, 50, 9, 0, IRON, HI_METAL), /* suits of armor */ /* * There is code in polyself.c that assumes (1) and (2). * There is code in obj.h, objnam.c, mon.c, read.c that assumes (2). * * (1) The dragon scale mails and the dragon scales are together. * (2) That the order of the dragon scale mail and dragon scales is the * the same defined in monst.c. */ #define DRGN_ARMR(name,mgc,power,cost,ac,color) \ ARMOR(name,(char *)0,1,mgc,1,power,0,5,40,cost,ac,0,ARM_SUIT,DRAGON_HIDE,color) /* 3.4.1: dragon scale mail reclassified as "magic" since magic is needed to create them */ DRGN_ARMR("gray dragon scale mail", 1, ANTIMAGIC, 1200, 1, CLR_GRAY), DRGN_ARMR("silver dragon scale mail", 1, REFLECTING, 1200, 1, DRAGON_SILVER), #if 0 /* DEFERRED */ DRGN_ARMR("shimmering dragon scale mail", 1, DISPLACED, 1200, 1, CLR_CYAN), #endif DRGN_ARMR("red dragon scale mail", 1, FIRE_RES, 900, 1, CLR_RED), DRGN_ARMR("white dragon scale mail", 1, COLD_RES, 900, 1, CLR_WHITE), DRGN_ARMR("orange dragon scale mail", 1, SLEEP_RES, 900, 1, CLR_ORANGE), DRGN_ARMR("black dragon scale mail", 1, DISINT_RES, 1200, 1, CLR_BLACK), DRGN_ARMR("blue dragon scale mail", 1, SHOCK_RES, 900, 1, CLR_BLUE), DRGN_ARMR("green dragon scale mail", 1, POISON_RES, 900, 1, CLR_GREEN), DRGN_ARMR("yellow dragon scale mail", 1, ACID_RES, 900, 1, CLR_YELLOW), /* For now, only dragons leave these. */ /* 3.4.1: dragon scales left classified as "non-magic"; they confer magical properties but are produced "naturally" */ DRGN_ARMR("gray dragon scales", 0, ANTIMAGIC, 700, 7, CLR_GRAY), DRGN_ARMR("silver dragon scales", 0, REFLECTING, 700, 7, DRAGON_SILVER), #if 0 /* DEFERRED */ DRGN_ARMR("shimmering dragon scales", 0, DISPLACED, 700, 7, CLR_CYAN), #endif DRGN_ARMR("red dragon scales", 0, FIRE_RES, 500, 7, CLR_RED), DRGN_ARMR("white dragon scales", 0, COLD_RES, 500, 7, CLR_WHITE), DRGN_ARMR("orange dragon scales", 0, SLEEP_RES, 500, 7, CLR_ORANGE), DRGN_ARMR("black dragon scales", 0, DISINT_RES, 700, 7, CLR_BLACK), DRGN_ARMR("blue dragon scales", 0, SHOCK_RES, 500, 7, CLR_BLUE), DRGN_ARMR("green dragon scales", 0, POISON_RES, 500, 7, CLR_GREEN), DRGN_ARMR("yellow dragon scales", 0, ACID_RES, 500, 7, CLR_YELLOW), #undef DRGN_ARMR ARMOR("plate mail", (char *)0, 1, 0, 1, 0, 44, 5, 450, 600, 3, 2, ARM_SUIT, IRON, HI_METAL), ARMOR("crystal plate mail", (char *)0, 1, 0, 1, 0, 10, 5, 450, 820, 3, 2, ARM_SUIT, GLASS, CLR_WHITE), #ifdef TOURIST ARMOR("bronze plate mail", (char *)0, 1, 0, 1, 0, 25, 5, 450, 400, 4, 0, ARM_SUIT, COPPER, HI_COPPER), #else ARMOR("bronze plate mail", (char *)0, 1, 0, 1, 0, 35, 5, 450, 400, 4, 0, ARM_SUIT, COPPER, HI_COPPER), #endif ARMOR("splint mail", (char *)0, 1, 0, 1, 0, 62, 5, 400, 80, 4, 1, ARM_SUIT, IRON, HI_METAL), ARMOR("banded mail", (char *)0, 1, 0, 1, 0, 72, 5, 350, 90, 4, 0, ARM_SUIT, IRON, HI_METAL), ARMOR("dwarvish mithril-coat", (char *)0, 1, 0, 0, 0, 10, 1, 150, 240, 4, 3, ARM_SUIT, MITHRIL, HI_METAL), ARMOR("elven mithril-coat", (char *)0, 1, 0, 0, 0, 15, 1, 150, 240, 5, 3, ARM_SUIT, MITHRIL, HI_METAL), ARMOR("chain mail", (char *)0, 1, 0, 0, 0, 72, 5, 300, 75, 5, 1, ARM_SUIT, IRON, HI_METAL), ARMOR("orcish chain mail", "crude chain mail", 0, 0, 0, 0, 20, 5, 300, 75, 6, 1, ARM_SUIT, IRON, CLR_BLACK), ARMOR("scale mail", (char *)0, 1, 0, 0, 0, 72, 5, 250, 45, 6, 0, ARM_SUIT, IRON, HI_METAL), ARMOR("studded leather armor", (char *)0, 1, 0, 0, 0, 72, 3, 200, 15, 7, 1, ARM_SUIT, LEATHER, HI_LEATHER), ARMOR("ring mail", (char *)0, 1, 0, 0, 0, 72, 5, 250, 100, 7, 0, ARM_SUIT, IRON, HI_METAL), ARMOR("orcish ring mail", "crude ring mail", 0, 0, 0, 0, 20, 5, 250, 80, 8, 1, ARM_SUIT, IRON, CLR_BLACK), ARMOR("leather armor", (char *)0, 1, 0, 0, 0, 82, 3, 150, 5, 8, 0, ARM_SUIT, LEATHER, HI_LEATHER), ARMOR("leather jacket", (char *)0, 1, 0, 0, 0, 12, 0, 30, 10, 9, 0, ARM_SUIT, LEATHER, CLR_BLACK), #ifdef TOURIST /* shirts */ ARMOR("Hawaiian shirt", (char *)0, 1, 0, 0, 0, 8, 0, 5, 3, 10, 0, ARM_SHIRT, CLOTH, CLR_MAGENTA), ARMOR("T-shirt", (char *)0, 1, 0, 0, 0, 2, 0, 5, 2, 10, 0, ARM_SHIRT, CLOTH, CLR_WHITE), #endif /* cloaks */ /* 'cope' is not a spelling mistake... leave it be */ CLOAK("mummy wrapping", (char *)0, 1, 0, 0, 0, 0, 3, 2, 10, 1, CLOTH, CLR_GRAY), CLOAK("elven cloak", "faded pall", 0, 1, STEALTH, 8, 0, 10, 60, 9, 3, CLOTH, CLR_BLACK), CLOAK("orcish cloak", "coarse mantelet", 0, 0, 0, 8, 0, 10, 40, 10, 2, CLOTH, CLR_BLACK), CLOAK("dwarvish cloak", "hooded cloak", 0, 0, 0, 8, 0, 10, 50, 10, 2, CLOTH, HI_CLOTH), CLOAK("oilskin cloak", "slippery cloak", 0, 0, 0, 8, 0, 10, 50, 9, 3, CLOTH, HI_CLOTH), CLOAK("robe", (char *)0, 1, 1, 0, 3, 0, 15, 50, 8, 3, CLOTH, CLR_RED), CLOAK("alchemy smock", "apron", 0, 1, POISON_RES, 9, 0, 10, 50, 9, 1, CLOTH, CLR_WHITE), CLOAK("leather cloak", (char *)0, 1, 0, 0, 8, 0, 15, 40, 9, 1, LEATHER, CLR_BROWN), /* With shuffled appearances... */ CLOAK("cloak of protection", "tattered cape", 0, 1, PROTECTION, 9, 0, 10, 50, 7, 3, CLOTH, HI_CLOTH), CLOAK("cloak of invisibility", "opera cloak", 0, 1, INVIS, 10, 0, 10, 60, 9, 2, CLOTH, CLR_BRIGHT_MAGENTA), CLOAK("cloak of magic resistance", "ornamental cope", 0, 1, ANTIMAGIC, 2, 0, 10, 60, 9, 3, CLOTH, CLR_WHITE), CLOAK("cloak of displacement", "piece of cloth", 0, 1, DISPLACED, 10, 0, 10, 50, 9, 2, CLOTH, HI_CLOTH), /* shields */ SHIELD("small shield", (char *)0, 1, 0, 0, 0, 6, 0, 30, 3, 9, 0, WOOD, HI_WOOD), SHIELD("elven shield", "blue and green shield", 0, 0, 0, 0, 2, 0, 40, 7, 8, 0, WOOD, CLR_GREEN), SHIELD("Uruk-hai shield", "white-handed shield", 0, 0, 0, 0, 2, 0, 50, 7, 9, 0, IRON, HI_METAL), SHIELD("orcish shield", "red-eyed shield", 0, 0, 0, 0, 2, 0, 50, 7, 9, 0, IRON, CLR_RED), SHIELD("large shield", (char *)0, 1, 0, 1, 0, 7, 0,100, 10, 8, 0, IRON, HI_METAL), SHIELD("dwarvish roundshield", "large round shield", 0, 0, 0, 0, 4, 0,100, 10, 8, 0, IRON, HI_METAL), SHIELD("shield of reflection", "polished silver shield", 0, 1, 0, REFLECTING, 3, 0, 50, 50, 8, 0, SILVER, HI_SILVER), /* gloves */ /* these have their color but not material shuffled, so the IRON must stay * CLR_BROWN (== HI_LEATHER) */ GLOVES("leather gloves", "old gloves", 0, 0, 0, 16, 1, 10, 8, 9, 0, LEATHER, HI_LEATHER), GLOVES("gauntlets of fumbling", "padded gloves", 0, 1, FUMBLING, 8, 1, 10, 50, 9, 0, LEATHER, HI_LEATHER), GLOVES("gauntlets of power", "riding gloves", 0, 1, 0, 8, 1, 30, 50, 9, 0, IRON, CLR_BROWN), GLOVES("gauntlets of dexterity", "fencing gloves", 0, 1, 0, 8, 1, 10, 50, 9, 0, LEATHER, HI_LEATHER), /* boots */ BOOTS("low boots", "walking shoes", 0, 0, 0, 25, 2, 10, 8, 9, 0, LEATHER, HI_LEATHER), BOOTS("iron shoes", "hard shoes", 0, 0, 0, 7, 2, 50, 16, 8, 0, IRON, HI_METAL), BOOTS("high boots", "jackboots", 0, 0, 0, 15, 2, 20, 12, 8, 0, LEATHER, HI_LEATHER), /* With shuffled appearances... */ BOOTS("speed boots", "combat boots", 0, 1, FAST, 12, 2, 20, 50, 9, 0, LEATHER, HI_LEATHER), BOOTS("water walking boots", "jungle boots", 0, 1, WWALKING, 12, 2, 20, 50, 9, 0, LEATHER, HI_LEATHER), BOOTS("jumping boots", "hiking boots", 0, 1, JUMPING, 12, 2, 20, 50, 9, 0, LEATHER, HI_LEATHER), BOOTS("elven boots", "mud boots", 0, 1, STEALTH, 12, 2, 15, 8, 9, 0, LEATHER, HI_LEATHER), BOOTS("kicking boots", "buckled boots", 0, 1, 0, 12, 2, 15, 8, 9, 0, IRON, CLR_BROWN), BOOTS("fumble boots", "riding boots", 0, 1, FUMBLING, 12, 2, 20, 30, 9, 0, LEATHER, HI_LEATHER), BOOTS("levitation boots", "snow boots", 0, 1, LEVITATION,12, 2, 15, 30, 9, 0, LEATHER, HI_LEATHER), #undef HELM #undef CLOAK #undef SHIELD #undef GLOVES #undef BOOTS #undef ARMOR /* rings ... */ #define RING(name,power,stone,cost,mgc,spec,mohs,metal,color) OBJECT( \ OBJ(name,stone), \ BITS(0,0,spec,0,mgc,spec,0,0,0,HARDGEM(mohs),0,P_NONE,metal), \ power, RING_CLASS, 0, 0, 3, cost, 0, 0, 0, 0, 15, color ) RING("adornment", ADORNED, "wooden", 100, 1, 1, 2, WOOD, HI_WOOD), RING("gain strength", 0, "granite", 150, 1, 1, 7, MINERAL, HI_MINERAL), RING("gain constitution", 0, "opal", 150, 1, 1, 7, MINERAL, HI_MINERAL), RING("increase accuracy", 0, "clay", 150, 1, 1, 4, MINERAL, CLR_RED), RING("increase damage", 0, "coral", 150, 1, 1, 4, MINERAL, CLR_ORANGE), RING("protection", PROTECTION, "black onyx",100, 1, 1, 7, MINERAL, CLR_BLACK), RING("regeneration", REGENERATION, "moonstone", 200, 1, 0, 6, MINERAL, HI_MINERAL), RING("searching", SEARCHING, "tiger eye", 200, 1, 0, 6, GEMSTONE, CLR_BROWN), RING("stealth", STEALTH, "jade", 100, 1, 0, 6, GEMSTONE, CLR_GREEN), RING("sustain ability", FIXED_ABIL, "bronze", 100, 1, 0, 4, COPPER, HI_COPPER), RING("levitation", LEVITATION, "agate", 200, 1, 0, 7, GEMSTONE, CLR_RED), RING("hunger", HUNGER, "topaz", 100, 1, 0, 8, GEMSTONE, CLR_CYAN), RING("aggravate monster", AGGRAVATE_MONSTER, "sapphire", 150, 1, 0, 9, GEMSTONE, CLR_BLUE), RING("conflict", CONFLICT, "ruby", 300, 1, 0, 9, GEMSTONE, CLR_RED), RING("warning", WARNING, "diamond", 100, 1, 0,10, GEMSTONE, CLR_WHITE), RING("poison resistance", POISON_RES, "pearl", 150, 1, 0, 4, IRON, CLR_WHITE), RING("fire resistance", FIRE_RES, "iron", 200, 1, 0, 5, IRON, HI_METAL), RING("cold resistance", COLD_RES, "brass", 150, 1, 0, 4, COPPER, HI_COPPER), RING("shock resistance", SHOCK_RES, "copper", 150, 1, 0, 3, COPPER, HI_COPPER), RING("free action", FREE_ACTION, "twisted", 200, 1, 0, 6, IRON, HI_METAL), RING("slow digestion", SLOW_DIGESTION, "steel", 200, 1, 0, 8, IRON, HI_METAL), RING("teleportation", TELEPORT, "silver", 200, 1, 0, 3, SILVER, HI_SILVER), RING("teleport control", TELEPORT_CONTROL, "gold", 300, 1, 0, 3, GOLD, HI_GOLD), RING("polymorph", POLYMORPH, "ivory", 300, 1, 0, 4, BONE, CLR_WHITE), RING("polymorph control", POLYMORPH_CONTROL, "emerald", 300, 1, 0, 8, GEMSTONE, CLR_BRIGHT_GREEN), RING("invisibility", INVIS, "wire", 150, 1, 0, 5, IRON, HI_METAL), RING("see invisible", SEE_INVIS, "engagement", 150, 1, 0, 5, IRON, HI_METAL), RING("protection from shape changers", PROT_FROM_SHAPE_CHANGERS, "shiny", 100, 1, 0, 5, IRON, CLR_BRIGHT_CYAN), #undef RING /* amulets ... - THE Amulet comes last because it is special */ #define AMULET(name,desc,power,prob) OBJECT( \ OBJ(name,desc), BITS(0,0,0,0,1,0,0,0,0,0,0,P_NONE,IRON), power, \ AMULET_CLASS, prob, 0, 20, 150, 0, 0, 0, 0, 20, HI_METAL ) AMULET("amulet of ESP", "circular", TELEPAT, 175), AMULET("amulet of life saving", "spherical", LIFESAVED, 75), AMULET("amulet of strangulation", "oval", STRANGLED, 135), AMULET("amulet of restful sleep", "triangular", SLEEPING, 135), AMULET("amulet versus poison", "pyramidal", POISON_RES, 165), AMULET("amulet of change", "square", 0, 130), /* POLYMORPH */ AMULET("amulet of unchanging", "concave", UNCHANGING, 45), AMULET("amulet of reflection", "hexagonal", REFLECTING, 75), AMULET("amulet of magical breathing", "octagonal", MAGICAL_BREATHING, 65), OBJECT(OBJ("cheap plastic imitation of the Amulet of Yendor", "Amulet of Yendor"), BITS(0,0,1,0,0,0,0,0,0,0,0,0,PLASTIC), 0, AMULET_CLASS, 0, 0, 20, 0, 0, 0, 0, 0, 1, HI_METAL), OBJECT(OBJ("Amulet of Yendor", /* note: description == name */ "Amulet of Yendor"), BITS(0,0,1,0,1,0,1,1,0,0,0,0,MITHRIL), 0, AMULET_CLASS, 0, 0, 20, 30000, 0, 0, 0, 0, 20, HI_METAL), #undef AMULET /* tools ... */ /* tools with weapon characteristics come last */ #define TOOL(name,desc,kn,mrg,mgc,chg,prob,wt,cost,mat,color) \ OBJECT( OBJ(name,desc), \ BITS(kn,mrg,chg,0,mgc,chg,0,0,0,0,0,P_NONE,mat), \ 0, TOOL_CLASS, prob, 0, \ wt, cost, 0, 0, 0, 0, wt, color ) #define CONTAINER(name,desc,kn,mgc,chg,prob,wt,cost,mat,color) \ OBJECT( OBJ(name,desc), \ BITS(kn,0,chg,1,mgc,chg,0,0,0,0,0,P_NONE,mat), \ 0, TOOL_CLASS, prob, 0, \ wt, cost, 0, 0, 0, 0, wt, color ) #define WEPTOOL(name,desc,kn,mgc,bi,prob,wt,cost,sdam,ldam,hitbon,sub,mat,clr) \ OBJECT( OBJ(name,desc), \ BITS(kn,0,1,0,mgc,1,0,0,bi,0,hitbon,sub,mat), \ 0, TOOL_CLASS, prob, 0, \ wt, cost, sdam, ldam, hitbon, 0, wt, clr ) /* containers */ CONTAINER("large box", (char *)0, 1, 0, 0, 40,350, 8, WOOD, HI_WOOD), CONTAINER("chest", (char *)0, 1, 0, 0, 35,600, 16, WOOD, HI_WOOD), CONTAINER("ice box", (char *)0, 1, 0, 0, 5,900, 42, PLASTIC, CLR_WHITE), CONTAINER("sack", "bag", 0, 0, 0, 35, 15, 2, CLOTH, HI_CLOTH), CONTAINER("oilskin sack", "bag", 0, 0, 0, 5, 15, 100, CLOTH, HI_CLOTH), CONTAINER("bag of holding", "bag", 0, 1, 0, 20, 15, 100, CLOTH, HI_CLOTH), CONTAINER("bag of tricks", "bag", 0, 1, 1, 20, 15, 100, CLOTH, HI_CLOTH), #undef CONTAINER /* lock opening tools */ TOOL("skeleton key", "key", 0, 0, 0, 0, 80, 3, 10, IRON, HI_METAL), #ifdef TOURIST TOOL("lock pick", (char *)0, 1, 0, 0, 0, 60, 4, 20, IRON, HI_METAL), TOOL("credit card", (char *)0, 1, 0, 0, 0, 15, 1, 10, PLASTIC, CLR_WHITE), #else TOOL("lock pick", (char *)0, 1, 0, 0, 0, 75, 4, 20, IRON, HI_METAL), #endif /* light sources */ TOOL("tallow candle", "candle", 0, 1, 0, 0, 20, 2, 10, WAX, CLR_WHITE), TOOL("wax candle", "candle", 0, 1, 0, 0, 5, 2, 20, WAX, CLR_WHITE), TOOL("brass lantern", (char *)0,1, 0, 0, 0, 30, 30, 12, COPPER, CLR_YELLOW), TOOL("oil lamp", "lamp", 0, 0, 0, 0, 45, 20, 10, COPPER, CLR_YELLOW), TOOL("magic lamp", "lamp", 0, 0, 1, 0, 15, 20, 50, COPPER, CLR_YELLOW), /* other tools */ #ifdef TOURIST TOOL("expensive camera", (char *)0, 1, 0, 0, 1, 15, 12, 200, PLASTIC, CLR_BLACK), TOOL("mirror", "looking glass", 0, 0, 0, 0, 45, 13, 10, GLASS, HI_SILVER), #else TOOL("mirror", "looking glass", 0, 0, 0, 0, 60, 13, 10, GLASS, HI_SILVER), #endif TOOL("crystal ball", "glass orb", 0, 0, 1, 1, 15,150, 60, GLASS, HI_GLASS), TOOL("lenses", (char *)0, 1, 0, 0, 0, 5, 3, 80, GLASS, HI_GLASS), TOOL("blindfold", (char *)0, 1, 0, 0, 0, 50, 2, 20, CLOTH, CLR_BLACK), TOOL("towel", (char *)0, 1, 0, 0, 0, 50, 2, 50, CLOTH, CLR_MAGENTA), #ifdef STEED TOOL("saddle", (char *)0, 1, 0, 0, 0, 5,200, 150, LEATHER, HI_LEATHER), TOOL("leash", (char *)0, 1, 0, 0, 0, 65, 12, 20, LEATHER, HI_LEATHER), #else TOOL("leash", (char *)0, 1, 0, 0, 0, 70, 12, 20, LEATHER, HI_LEATHER), #endif TOOL("stethoscope", (char *)0, 1, 0, 0, 0, 25, 4, 75, IRON, HI_METAL), TOOL("tinning kit", (char *)0, 1, 0, 0, 1, 15,100, 30, IRON, HI_METAL), TOOL("tin opener", (char *)0, 1, 0, 0, 0, 35, 4, 30, IRON, HI_METAL), TOOL("can of grease", (char *)0,1, 0, 0, 1, 15, 15, 20, IRON, HI_METAL), TOOL("figurine", (char *)0, 1, 0, 1, 0, 25, 50, 80, MINERAL, HI_MINERAL), TOOL("magic marker", (char *)0, 1, 0, 1, 1, 15, 2, 50, PLASTIC, CLR_RED), /* traps */ TOOL("land mine",(char *)0, 1, 0, 0, 0, 0,300, 180, IRON, CLR_RED), TOOL("beartrap", (char *)0, 1, 0, 0, 0, 0,200, 60, IRON, HI_METAL), /* instruments */ TOOL("tin whistle", "whistle", 0, 0, 0, 0, 100, 3, 10, METAL, HI_METAL), TOOL("magic whistle", "whistle",0, 0, 1, 0, 30, 3, 10, METAL, HI_METAL), /* "If tin whistles are made out of tin, what do they make foghorns out of?" */ TOOL("wooden flute", "flute", 0, 0, 0, 0, 4, 5, 12, WOOD, HI_WOOD), TOOL("magic flute", "flute", 0, 0, 1, 1, 2, 5, 36, WOOD, HI_WOOD), TOOL("tooled horn", "horn", 0, 0, 0, 0, 5, 18, 15, BONE, CLR_WHITE), TOOL("frost horn", "horn", 0, 0, 1, 1, 2, 18, 50, BONE, CLR_WHITE), TOOL("fire horn", "horn", 0, 0, 1, 1, 2, 18, 50, BONE, CLR_WHITE), TOOL("horn of plenty", "horn", 0, 0, 1, 1, 2, 18, 50, BONE, CLR_WHITE), TOOL("wooden harp", "harp", 0, 0, 0, 0, 4, 30, 50, WOOD, HI_WOOD), TOOL("magic harp", "harp", 0, 0, 1, 1, 2, 30, 50, WOOD, HI_WOOD), TOOL("bell", (char *)0, 1, 0, 0, 0, 2, 30, 50, COPPER, HI_COPPER), TOOL("bugle", (char *)0, 1, 0, 0, 0, 4, 10, 15, COPPER, HI_COPPER), TOOL("leather drum", "drum", 0, 0, 0, 0, 4, 25, 25, LEATHER, HI_LEATHER), TOOL("drum of earthquake", "drum", 0, 0, 1, 1, 2, 25, 25, LEATHER, HI_LEATHER), /* tools useful as weapons */ WEPTOOL("pick-axe", (char *)0, 1, 0, 0, 20, 100, 50, 6, 3, WHACK, P_PICK_AXE, IRON, HI_METAL), WEPTOOL("grappling hook", "iron hook", 0, 0, 0, 5, 30, 50, 2, 6, WHACK, P_FLAIL, IRON, HI_METAL), /* 3.4.1: unicorn horn left classified as "magic" */ WEPTOOL("unicorn horn", (char *)0, 1, 1, 1, 0, 20, 100, 12, 12, PIERCE, P_UNICORN_HORN, BONE, CLR_WHITE), /* two special unique artifact "tools" */ OBJECT(OBJ("Candelabrum of Invocation", "candelabrum"), BITS(0,0,1,0,1,0,1,1,0,0,0,P_NONE,GOLD), 0, TOOL_CLASS, 0, 0,10, 5000, 0, 0, 0, 0, 200, HI_GOLD), OBJECT(OBJ("Bell of Opening", "silver bell"), BITS(0,0,1,0,1,1,1,1,0,0,0,P_NONE,SILVER), 0, TOOL_CLASS, 0, 0,10, 5000, 0, 0, 0, 0, 50, HI_SILVER), #undef TOOL #undef WEPTOOL /* Comestibles ... */ #define FOOD(name,prob,delay,wt,unk,tin,nutrition,color) OBJECT( \ OBJ(name,(char *)0), BITS(1,1,unk,0,0,0,0,0,0,0,0,P_NONE,tin), 0, \ FOOD_CLASS, prob, delay, \ wt, nutrition/20 + 5, 0, 0, 0, 0, nutrition, color ) /* all types of food (except tins & corpses) must have a delay of at least 1. */ /* delay on corpses is computed and is weight dependant */ /* dog eats foods 0-4 but prefers tripe rations above all others */ /* fortune cookies can be read */ /* carrots improve your vision */ /* +0 tins contain monster meat */ /* +1 tins (of spinach) make you stronger (like Popeye) */ /* food CORPSE is a cadaver of some type */ /* meatballs/sticks/rings are only created from objects via stone to flesh */ /* meat */ FOOD("tripe ration", 140, 2, 10, 0, FLESH, 200, CLR_BROWN), FOOD("corpse", 0, 1, 0, 0, FLESH, 0, CLR_BROWN), FOOD("egg", 85, 1, 1, 1, FLESH, 80, CLR_WHITE), FOOD("meatball", 0, 1, 1, 0, FLESH, 5, CLR_BROWN), FOOD("meat stick", 0, 1, 1, 0, FLESH, 5, CLR_BROWN), FOOD("huge chunk of meat", 0,20,400, 0, FLESH,2000, CLR_BROWN), /* special case because it's not mergable */ OBJECT(OBJ("meat ring", (char *)0), BITS(1,0,0,0,0,0,0,0,0,0,0,0,FLESH), 0, FOOD_CLASS, 0, 1, 5, 1, 0, 0, 0, 0, 5, CLR_BROWN), /* fruits & veggies */ FOOD("kelp frond", 0, 1, 1, 0, VEGGY, 30, CLR_GREEN), FOOD("eucalyptus leaf", 3, 1, 1, 0, VEGGY, 30, CLR_GREEN), FOOD("apple", 15, 1, 2, 0, VEGGY, 50, CLR_RED), FOOD("orange", 10, 1, 2, 0, VEGGY, 80, CLR_ORANGE), FOOD("pear", 10, 1, 2, 0, VEGGY, 50, CLR_BRIGHT_GREEN), FOOD("melon", 10, 1, 5, 0, VEGGY, 100, CLR_BRIGHT_GREEN), FOOD("banana", 10, 1, 2, 0, VEGGY, 80, CLR_YELLOW), FOOD("carrot", 15, 1, 2, 0, VEGGY, 50, CLR_ORANGE), FOOD("sprig of wolfsbane", 7, 1, 1, 0, VEGGY, 40, CLR_GREEN), FOOD("clove of garlic", 7, 1, 1, 0, VEGGY, 40, CLR_WHITE), FOOD("slime mold", 75, 1, 5, 0, VEGGY, 250, HI_ORGANIC), /* people food */ FOOD("lump of royal jelly", 0, 1, 2, 0, VEGGY, 200, CLR_YELLOW), FOOD("cream pie", 25, 1, 10, 0, VEGGY, 100, CLR_WHITE), FOOD("candy bar", 13, 1, 2, 0, VEGGY, 100, CLR_BROWN), FOOD("fortune cookie", 55, 1, 1, 0, VEGGY, 40, CLR_YELLOW), FOOD("pancake", 25, 2, 2, 0, VEGGY, 200, CLR_YELLOW), FOOD("lembas wafer", 20, 2, 5, 0, VEGGY, 800, CLR_WHITE), FOOD("cram ration", 20, 3, 15, 0, VEGGY, 600, HI_ORGANIC), FOOD("food ration", 380, 5, 20, 0, VEGGY, 800, HI_ORGANIC), FOOD("K-ration", 0, 1, 10, 0, VEGGY, 400, HI_ORGANIC), FOOD("C-ration", 0, 1, 10, 0, VEGGY, 300, HI_ORGANIC), FOOD("tin", 75, 0, 10, 1, METAL, 0, HI_METAL), #undef FOOD /* potions ... */ #define POTION(name,desc,mgc,power,prob,cost,color) OBJECT( \ OBJ(name,desc), BITS(0,1,0,0,mgc,0,0,0,0,0,0,P_NONE,GLASS), power, \ POTION_CLASS, prob, 0, 20, cost, 0, 0, 0, 0, 10, color ) POTION("gain ability", "ruby", 1, 0, 42, 300, CLR_RED), POTION("restore ability", "pink", 1, 0, 40, 100, CLR_BRIGHT_MAGENTA), POTION("confusion", "orange", 1, CONFUSION, 42, 100, CLR_ORANGE), POTION("blindness", "yellow", 1, BLINDED, 40, 150, CLR_YELLOW), POTION("paralysis", "emerald", 1, 0, 42, 300, CLR_BRIGHT_GREEN), POTION("speed", "dark green", 1, FAST, 42, 200, CLR_GREEN), POTION("levitation", "cyan", 1, LEVITATION, 42, 200, CLR_CYAN), POTION("hallucination", "sky blue", 1, HALLUC, 40, 100, CLR_CYAN), POTION("invisibility", "brilliant blue",1, INVIS, 40, 150, CLR_BRIGHT_BLUE), POTION("see invisible", "magenta", 1, SEE_INVIS, 42, 50, CLR_MAGENTA), POTION("healing", "purple-red", 1, 0, 57, 100, CLR_MAGENTA), POTION("extra healing", "puce", 1, 0, 47, 100, CLR_RED), POTION("gain level", "milky", 1, 0, 20, 300, CLR_WHITE), POTION("enlightenment", "swirly", 1, 0, 20, 200, CLR_BROWN), POTION("monster detection", "bubbly", 1, 0, 40, 150, CLR_WHITE), POTION("object detection", "smoky", 1, 0, 42, 150, CLR_GRAY), POTION("gain energy", "cloudy", 1, 0, 42, 150, CLR_WHITE), POTION("sleeping", "effervescent", 1, 0, 42, 100, CLR_GRAY), POTION("full healing", "black", 1, 0, 10, 200, CLR_BLACK), POTION("polymorph", "golden", 1, 0, 10, 200, CLR_YELLOW), POTION("booze", "brown", 0, 0, 42, 50, CLR_BROWN), POTION("sickness", "fizzy", 0, 0, 42, 50, CLR_CYAN), POTION("fruit juice", "dark", 0, 0, 42, 50, CLR_BLACK), POTION("acid", "white", 0, 0, 10, 250, CLR_WHITE), POTION("oil", "murky", 0, 0, 30, 250, CLR_BROWN), POTION("water", "clear", 0, 0, 92, 100, CLR_CYAN), #undef POTION /* scrolls ... */ #define SCROLL(name,text,mgc,prob,cost) OBJECT( \ OBJ(name,text), BITS(0,1,0,0,mgc,0,0,0,0,0,0,P_NONE,PAPER), 0, \ SCROLL_CLASS, prob, 0, 5, cost, 0, 0, 0, 0, 6, HI_PAPER ) SCROLL("enchant armor", "ZELGO MER", 1, 63, 80), SCROLL("destroy armor", "JUYED AWK YACC", 1, 45, 100), SCROLL("confuse monster", "NR 9", 1, 53, 100), SCROLL("scare monster", "XIXAXA XOXAXA XUXAXA", 1, 35, 100), SCROLL("remove curse", "PRATYAVAYAH", 1, 65, 80), SCROLL("enchant weapon", "DAIYEN FOOELS", 1, 80, 60), SCROLL("create monster", "LEP GEX VEN ZEA", 1, 45, 200), SCROLL("taming", "PRIRUTSENIE", 1, 15, 200), SCROLL("genocide", "ELBIB YLOH", 1, 15, 300), SCROLL("light", "VERR YED HORRE", 1, 90, 50), SCROLL("teleportation", "VENZAR BORGAVVE", 1, 55, 100), SCROLL("gold detection", "THARR", 1, 33, 100), SCROLL("food detection", "YUM YUM", 1, 25, 100), SCROLL("identify", "KERNOD WEL", 1, 180, 20), SCROLL("magic mapping", "ELAM EBOW", 1, 45, 100), SCROLL("amnesia", "DUAM XNAHT", 1, 35, 200), SCROLL("fire", "ANDOVA BEGARIN", 1, 30, 100), SCROLL("earth", "KIRJE", 1, 18, 200), SCROLL("punishment", "VE FORBRYDERNE", 1, 15, 300), SCROLL("charging", "HACKEM MUCHE", 1, 15, 300), SCROLL("stinking cloud", "VELOX NEB", 1, 15, 300), SCROLL((char *)0, "FOOBIE BLETCH", 1, 0, 100), SCROLL((char *)0, "TEMOV", 1, 0, 100), SCROLL((char *)0, "GARVEN DEH", 1, 0, 100), SCROLL((char *)0, "READ ME", 1, 0, 100), /* these must come last because they have special descriptions */ #ifdef MAIL SCROLL("mail", "stamped", 0, 0, 0), #endif SCROLL("blank paper", "unlabeled", 0, 28, 60), #undef SCROLL /* spellbooks ... */ #define SPELL(name,desc,sub,prob,delay,level,mgc,dir,color) OBJECT( \ OBJ(name,desc), BITS(0,0,0,0,mgc,0,0,0,0,0,dir,sub,PAPER), 0, \ SPBOOK_CLASS, prob, delay, \ 50, level*100, 0, 0, 0, level, 20, color ) SPELL("dig", "parchment", P_MATTER_SPELL, 20, 6, 5, 1, RAY, HI_PAPER), SPELL("magic missile", "vellum", P_ATTACK_SPELL, 45, 2, 2, 1, RAY, HI_PAPER), SPELL("fireball", "ragged", P_ATTACK_SPELL, 20, 4, 4, 1, RAY, HI_PAPER), SPELL("cone of cold", "dog eared", P_ATTACK_SPELL, 10, 7, 4, 1, RAY, HI_PAPER), SPELL("sleep", "mottled", P_ENCHANTMENT_SPELL, 50, 1, 1, 1, RAY, HI_PAPER), SPELL("finger of death", "stained", P_ATTACK_SPELL, 5, 10, 7, 1, RAY, HI_PAPER), SPELL("light", "cloth", P_DIVINATION_SPELL, 45, 1, 1, 1, NODIR, HI_CLOTH), SPELL("detect monsters", "leather", P_DIVINATION_SPELL, 43, 1, 1, 1, NODIR, HI_LEATHER), SPELL("healing", "white", P_HEALING_SPELL, 40, 2, 1, 1, IMMEDIATE, CLR_WHITE), SPELL("knock", "pink", P_MATTER_SPELL, 35, 1, 1, 1, IMMEDIATE, CLR_BRIGHT_MAGENTA), SPELL("force bolt", "red", P_ATTACK_SPELL, 35, 2, 1, 1, IMMEDIATE, CLR_RED), SPELL("confuse monster", "orange", P_ENCHANTMENT_SPELL, 30, 2, 2, 1, IMMEDIATE, CLR_ORANGE), SPELL("cure blindness", "yellow", P_HEALING_SPELL, 25, 2, 2, 1, IMMEDIATE, CLR_YELLOW), SPELL("drain life", "velvet", P_ATTACK_SPELL, 10, 2, 2, 1, IMMEDIATE, CLR_MAGENTA), SPELL("slow monster", "light green", P_ENCHANTMENT_SPELL, 30, 2, 2, 1, IMMEDIATE, CLR_BRIGHT_GREEN), SPELL("wizard lock", "dark green", P_MATTER_SPELL, 30, 3, 2, 1, IMMEDIATE, CLR_GREEN), SPELL("create monster", "turquoise", P_CLERIC_SPELL, 35, 3, 2, 1, NODIR, CLR_BRIGHT_CYAN), SPELL("detect food", "cyan", P_DIVINATION_SPELL, 30, 3, 2, 1, NODIR, CLR_CYAN), SPELL("cause fear", "light blue", P_ENCHANTMENT_SPELL, 25, 3, 3, 1, NODIR, CLR_BRIGHT_BLUE), SPELL("clairvoyance", "dark blue", P_DIVINATION_SPELL, 15, 3, 3, 1, NODIR, CLR_BLUE), SPELL("cure sickness", "indigo", P_HEALING_SPELL, 32, 3, 3, 1, NODIR, CLR_BLUE), SPELL("charm monster", "magenta", P_ENCHANTMENT_SPELL, 20, 3, 3, 1, IMMEDIATE, CLR_MAGENTA), SPELL("haste self", "purple", P_ESCAPE_SPELL, 33, 4, 3, 1, NODIR, CLR_MAGENTA), SPELL("detect unseen", "violet", P_DIVINATION_SPELL, 20, 4, 3, 1, NODIR, CLR_MAGENTA), SPELL("levitation", "tan", P_ESCAPE_SPELL, 20, 4, 4, 1, NODIR, CLR_BROWN), SPELL("extra healing", "plaid", P_HEALING_SPELL, 27, 5, 3, 1, IMMEDIATE, CLR_GREEN), SPELL("restore ability", "light brown", P_HEALING_SPELL, 25, 5, 4, 1, NODIR, CLR_BROWN), SPELL("invisibility", "dark brown", P_ESCAPE_SPELL, 25, 5, 4, 1, NODIR, CLR_BROWN), SPELL("detect treasure", "gray", P_DIVINATION_SPELL, 20, 5, 4, 1, NODIR, CLR_GRAY), SPELL("remove curse", "wrinkled", P_CLERIC_SPELL, 25, 5, 3, 1, NODIR, HI_PAPER), SPELL("magic mapping", "dusty", P_DIVINATION_SPELL, 18, 7, 5, 1, NODIR, HI_PAPER), SPELL("identify", "bronze", P_DIVINATION_SPELL, 20, 6, 3, 1, NODIR, HI_COPPER), SPELL("turn undead", "copper", P_CLERIC_SPELL, 16, 8, 6, 1, IMMEDIATE, HI_COPPER), SPELL("polymorph", "silver", P_MATTER_SPELL, 10, 8, 6, 1, IMMEDIATE, HI_SILVER), SPELL("teleport away", "gold", P_ESCAPE_SPELL, 15, 6, 6, 1, IMMEDIATE, HI_GOLD), SPELL("create familiar", "glittering", P_CLERIC_SPELL, 10, 7, 6, 1, NODIR, CLR_WHITE), SPELL("cancellation", "shining", P_MATTER_SPELL, 15, 8, 7, 1, IMMEDIATE, CLR_WHITE), SPELL("protection", "dull", P_CLERIC_SPELL, 18, 3, 1, 1, NODIR, HI_PAPER), SPELL("jumping", "thin", P_ESCAPE_SPELL, 20, 3, 1, 1, IMMEDIATE, HI_PAPER), SPELL("stone to flesh", "thick", P_HEALING_SPELL, 15, 1, 3, 1, IMMEDIATE, HI_PAPER), #if 0 /* DEFERRED */ SPELL("flame sphere", "canvas", P_MATTER_SPELL, 20, 2, 1, 1, NODIR, CLR_BROWN), SPELL("freeze sphere", "hardcover", P_MATTER_SPELL, 20, 2, 1, 1, NODIR, CLR_BROWN), #endif /* blank spellbook must come last because it retains its description */ SPELL("blank paper", "plain", P_NONE, 18, 0, 0, 0, 0, HI_PAPER), /* a special, one of a kind, spellbook */ OBJECT(OBJ("Book of the Dead", "papyrus"), BITS(0,0,1,0,1,0,1,1,0,0,0,P_NONE,PAPER), 0, SPBOOK_CLASS, 0, 0,20, 10000, 0, 0, 0, 7, 20, HI_PAPER), #undef SPELL /* wands ... */ #define WAND(name,typ,prob,cost,mgc,dir,metal,color) OBJECT( \ OBJ(name,typ), BITS(0,0,1,0,mgc,1,0,0,0,0,dir,P_NONE,metal), 0, \ WAND_CLASS, prob, 0, 7, cost, 0, 0, 0, 0, 30, color ) WAND("light", "glass", 95, 100, 1, NODIR, GLASS, HI_GLASS), WAND("secret door detection", "balsa", 50, 150, 1, NODIR, WOOD, HI_WOOD), WAND("enlightenment", "crystal", 15, 150, 1, NODIR, GLASS, HI_GLASS), WAND("create monster", "maple", 45, 200, 1, NODIR, WOOD, HI_WOOD), WAND("wishing", "pine", 5, 500, 1, NODIR, WOOD, HI_WOOD), WAND("nothing", "oak", 25, 100, 0, IMMEDIATE, WOOD, HI_WOOD), WAND("striking", "ebony", 75, 150, 1, IMMEDIATE, WOOD, HI_WOOD), WAND("make invisible", "marble", 45, 150, 1, IMMEDIATE, MINERAL, HI_MINERAL), WAND("slow monster", "tin", 50, 150, 1, IMMEDIATE, METAL, HI_METAL), WAND("speed monster", "brass", 50, 150, 1, IMMEDIATE, COPPER, HI_COPPER), WAND("undead turning", "copper", 50, 150, 1, IMMEDIATE, COPPER, HI_COPPER), WAND("polymorph", "silver", 45, 200, 1, IMMEDIATE, SILVER, HI_SILVER), WAND("cancellation", "platinum", 45, 200, 1, IMMEDIATE, PLATINUM, CLR_WHITE), WAND("teleportation", "iridium", 45, 200, 1, IMMEDIATE, METAL, CLR_BRIGHT_CYAN), WAND("opening", "zinc", 25, 150, 1, IMMEDIATE, METAL, HI_METAL), WAND("locking", "aluminum", 25, 150, 1, IMMEDIATE, METAL, HI_METAL), WAND("probing", "uranium", 30, 150, 1, IMMEDIATE, METAL, HI_METAL), WAND("digging", "iron", 55, 150, 1, RAY, IRON, HI_METAL), WAND("magic missile", "steel", 50, 150, 1, RAY, IRON, HI_METAL), WAND("fire", "hexagonal",40, 175, 1, RAY, IRON, HI_METAL), WAND("cold", "short", 40, 175, 1, RAY, IRON, HI_METAL), WAND("sleep", "runed", 50, 175, 1, RAY, IRON, HI_METAL), WAND("death", "long", 5, 500, 1, RAY, IRON, HI_METAL), WAND("lightning", "curved", 40, 175, 1, RAY, IRON, HI_METAL), WAND((char *)0, "forked", 0, 150, 1, 0, WOOD, HI_WOOD), WAND((char *)0, "spiked", 0, 150, 1, 0, IRON, HI_METAL), WAND((char *)0, "jeweled", 0, 150, 1, 0, IRON, HI_MINERAL), #undef WAND /* coins ... - so far, gold is all there is */ #define COIN(name,prob,metal,worth) OBJECT( \ OBJ(name,(char *)0), BITS(0,1,0,0,0,0,0,0,0,0,0,P_NONE,metal), 0, \ COIN_CLASS, prob, 0, 1, worth, 0, 0, 0, 0, 0, HI_GOLD ) COIN("gold piece", 1000, GOLD,1), #undef COIN /* gems ... - includes stones and rocks but not boulders */ #define GEM(name,desc,prob,wt,gval,nutr,mohs,glass,color) OBJECT( \ OBJ(name,desc), \ BITS(0,1,0,0,0,0,0,0,0,HARDGEM(mohs),0,-P_SLING,glass), 0, \ GEM_CLASS, prob, 0, 1, gval, 3, 3, 0, 0, nutr, color ) #define ROCK(name,desc,kn,prob,wt,gval,sdam,ldam,mgc,nutr,mohs,glass,color) OBJECT( \ OBJ(name,desc), \ BITS(kn,1,0,0,mgc,0,0,0,0,HARDGEM(mohs),0,-P_SLING,glass), 0, \ GEM_CLASS, prob, 0, wt, gval, sdam, ldam, 0, 0, nutr, color ) GEM("dilithium crystal", "white", 2, 1, 4500, 15, 5, GEMSTONE, CLR_WHITE), GEM("diamond", "white", 3, 1, 4000, 15, 10, GEMSTONE, CLR_WHITE), GEM("ruby", "red", 4, 1, 3500, 15, 9, GEMSTONE, CLR_RED), GEM("jacinth", "orange", 3, 1, 3250, 15, 9, GEMSTONE, CLR_ORANGE), GEM("sapphire", "blue", 4, 1, 3000, 15, 9, GEMSTONE, CLR_BLUE), GEM("black opal", "black", 3, 1, 2500, 15, 8, GEMSTONE, CLR_BLACK), GEM("emerald", "green", 5, 1, 2500, 15, 8, GEMSTONE, CLR_GREEN), GEM("turquoise", "green", 6, 1, 2000, 15, 6, GEMSTONE, CLR_GREEN), GEM("citrine", "yellow", 4, 1, 1500, 15, 6, GEMSTONE, CLR_YELLOW), GEM("aquamarine", "green", 6, 1, 1500, 15, 8, GEMSTONE, CLR_GREEN), GEM("amber", "yellowish brown", 8, 1, 1000, 15, 2, GEMSTONE, CLR_BROWN), GEM("topaz", "yellowish brown", 10, 1, 900, 15, 8, GEMSTONE, CLR_BROWN), GEM("jet", "black", 6, 1, 850, 15, 7, GEMSTONE, CLR_BLACK), GEM("opal", "white", 12, 1, 800, 15, 6, GEMSTONE, CLR_WHITE), GEM("chrysoberyl", "yellow", 8, 1, 700, 15, 5, GEMSTONE, CLR_YELLOW), GEM("garnet", "red", 12, 1, 700, 15, 7, GEMSTONE, CLR_RED), GEM("amethyst", "violet", 14, 1, 600, 15, 7, GEMSTONE, CLR_MAGENTA), GEM("jasper", "red", 15, 1, 500, 15, 7, GEMSTONE, CLR_RED), GEM("fluorite", "violet", 15, 1, 400, 15, 4, GEMSTONE, CLR_MAGENTA), GEM("obsidian", "black", 9, 1, 200, 15, 6, GEMSTONE, CLR_BLACK), GEM("agate", "orange", 12, 1, 200, 15, 6, GEMSTONE, CLR_ORANGE), GEM("jade", "green", 10, 1, 300, 15, 6, GEMSTONE, CLR_GREEN), GEM("worthless piece of white glass", "white", 77, 1, 0, 6, 5, GLASS, CLR_WHITE), GEM("worthless piece of blue glass", "blue", 77, 1, 0, 6, 5, GLASS, CLR_BLUE), GEM("worthless piece of red glass", "red", 77, 1, 0, 6, 5, GLASS, CLR_RED), GEM("worthless piece of yellowish brown glass", "yellowish brown", 77, 1, 0, 6, 5, GLASS, CLR_BROWN), GEM("worthless piece of orange glass", "orange", 76, 1, 0, 6, 5, GLASS, CLR_ORANGE), GEM("worthless piece of yellow glass", "yellow", 77, 1, 0, 6, 5, GLASS, CLR_YELLOW), GEM("worthless piece of black glass", "black", 76, 1, 0, 6, 5, GLASS, CLR_BLACK), GEM("worthless piece of green glass", "green", 77, 1, 0, 6, 5, GLASS, CLR_GREEN), GEM("worthless piece of violet glass", "violet", 77, 1, 0, 6, 5, GLASS, CLR_MAGENTA), /* Placement note: there is a wishable subrange for * "gray stones" in the o_ranges[] array in objnam.c * that is currently everything between luckstones and flint (inclusive). */ ROCK("luckstone", "gray", 0, 10, 10, 60, 3, 3, 1, 10, 7, MINERAL, CLR_GRAY), ROCK("loadstone", "gray", 0, 10, 500, 1, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY), ROCK("touchstone", "gray", 0, 8, 10, 45, 3, 3, 1, 10, 6, MINERAL, CLR_GRAY), ROCK("flint", "gray", 0, 10, 10, 1, 6, 6, 0, 10, 7, MINERAL, CLR_GRAY), ROCK("rock", (char *)0, 1,100, 10, 0, 3, 3, 0, 10, 7, MINERAL, CLR_GRAY), #undef GEM #undef ROCK /* miscellaneous ... */ /* Note: boulders and rocks are not normally created at random; the * probabilities only come into effect when you try to polymorph them. * Boulders weigh more than MAX_CARR_CAP; statues use corpsenm to take * on a specific type and may act as containers (both affect weight). */ OBJECT(OBJ("boulder",(char *)0), BITS(1,0,0,0,0,0,0,0,1,0,0,P_NONE,MINERAL), 0, ROCK_CLASS, 100, 0, 6000, 0, 20, 20, 0, 0, 2000, HI_MINERAL), OBJECT(OBJ("statue", (char *)0), BITS(1,0,0,1,0,0,0,0,0,0,0,P_NONE,MINERAL), 0, ROCK_CLASS, 900, 0, 2500, 0, 20, 20, 0, 0, 2500, CLR_WHITE), OBJECT(OBJ("heavy iron ball", (char *)0), BITS(1,0,0,0,0,0,0,0,0,0,WHACK,P_NONE,IRON), 0, BALL_CLASS, 1000, 0, 480, 10, 25, 25, 0, 0, 200, HI_METAL), /* +d4 when "very heavy" */ OBJECT(OBJ("iron chain", (char *)0), BITS(1,0,0,0,0,0,0,0,0,0,WHACK,P_NONE,IRON), 0, CHAIN_CLASS, 1000, 0, 120, 0, 4, 4, 0, 0, 200, HI_METAL), /* +1 both l & s */ OBJECT(OBJ("blinding venom", "splash of venom"), BITS(0,1,0,0,0,0,0,1,0,0,0,P_NONE,LIQUID), 0, VENOM_CLASS, 500, 0, 1, 0, 0, 0, 0, 0, 0, HI_ORGANIC), OBJECT(OBJ("acid venom", "splash of venom"), BITS(0,1,0,0,0,0,0,1,0,0,0,P_NONE,LIQUID), 0, VENOM_CLASS, 500, 0, 1, 0, 6, 6, 0, 0, 0, HI_ORGANIC), /* +d6 small or large */ /* fencepost, the deadly Array Terminator -- name [1st arg] *must* be NULL */ OBJECT(OBJ((char *)0,(char *)0), BITS(0,0,0,0,0,0,0,0,0,0,0,P_NONE,0), 0, ILLOBJ_CLASS, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) }; /* objects[] */ #ifndef OBJECTS_PASS_2_ /* perform recursive compilation for second structure */ # undef OBJ # undef OBJECT # define OBJECTS_PASS_2_ #include "objects.c" void NDECL(objects_init); /* dummy routine used to force linkage */ void objects_init() { return; } #endif /* !OBJECTS_PASS_2_ */ /*objects.c*/ nethack-3.4.3/src/objnam.c0100644000000000000000000022102107764735041014051 0ustar rootroot/* SCCS Id: @(#)objnam.c 3.4 2003/12/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* "an uncursed greased partly eaten guardian naga hatchling [corpse]" */ #define PREFIX 80 /* (56) */ #define SCHAR_LIM 127 #define NUMOBUF 12 STATIC_DCL char *FDECL(strprepend,(char *,const char *)); #ifdef OVLB static boolean FDECL(wishymatch, (const char *,const char *,BOOLEAN_P)); #endif static char *NDECL(nextobuf); static void FDECL(add_erosion_words, (struct obj *, char *)); struct Jitem { int item; const char *name; }; /* true for gems/rocks that should have " stone" appended to their names */ #define GemStone(typ) (typ == FLINT || \ (objects[typ].oc_material == GEMSTONE && \ (typ != DILITHIUM_CRYSTAL && typ != RUBY && \ typ != DIAMOND && typ != SAPPHIRE && \ typ != BLACK_OPAL && \ typ != EMERALD && typ != OPAL))) #ifndef OVLB STATIC_DCL struct Jitem Japanese_items[]; #else /* OVLB */ STATIC_OVL struct Jitem Japanese_items[] = { { SHORT_SWORD, "wakizashi" }, { BROADSWORD, "ninja-to" }, { FLAIL, "nunchaku" }, { GLAIVE, "naginata" }, { LOCK_PICK, "osaku" }, { WOODEN_HARP, "koto" }, { KNIFE, "shito" }, { PLATE_MAIL, "tanko" }, { HELMET, "kabuto" }, { LEATHER_GLOVES, "yugake" }, { FOOD_RATION, "gunyoki" }, { POT_BOOZE, "sake" }, {0, "" } }; #endif /* OVLB */ STATIC_DCL const char *FDECL(Japanese_item_name,(int i)); #ifdef OVL1 STATIC_OVL char * strprepend(s,pref) register char *s; register const char *pref; { register int i = (int)strlen(pref); if(i > PREFIX) { impossible("PREFIX too short (for %d).", i); return(s); } s -= i; (void) strncpy(s, pref, i); /* do not copy trailing 0 */ return(s); } #endif /* OVL1 */ #ifdef OVLB /* manage a pool of BUFSZ buffers, so callers don't have to */ static char * nextobuf() { static char NEARDATA bufs[NUMOBUF][BUFSZ]; static int bufidx = 0; bufidx = (bufidx + 1) % NUMOBUF; return bufs[bufidx]; } char * obj_typename(otyp) register int otyp; { char *buf = nextobuf(); register struct objclass *ocl = &objects[otyp]; register const char *actualn = OBJ_NAME(*ocl); register const char *dn = OBJ_DESCR(*ocl); register const char *un = ocl->oc_uname; register int nn = ocl->oc_name_known; if (Role_if(PM_SAMURAI) && Japanese_item_name(otyp)) actualn = Japanese_item_name(otyp); switch(ocl->oc_class) { case COIN_CLASS: Strcpy(buf, "coin"); break; case POTION_CLASS: Strcpy(buf, "potion"); break; case SCROLL_CLASS: Strcpy(buf, "scroll"); break; case WAND_CLASS: Strcpy(buf, "wand"); break; case SPBOOK_CLASS: Strcpy(buf, "spellbook"); break; case RING_CLASS: Strcpy(buf, "ring"); break; case AMULET_CLASS: if(nn) Strcpy(buf,actualn); else Strcpy(buf,"amulet"); if(un) Sprintf(eos(buf)," called %s",un); if(dn) Sprintf(eos(buf)," (%s)",dn); return(buf); default: if(nn) { Strcpy(buf, actualn); if (GemStone(otyp)) Strcat(buf, " stone"); if(un) Sprintf(eos(buf), " called %s", un); if(dn) Sprintf(eos(buf), " (%s)", dn); } else { Strcpy(buf, dn ? dn : actualn); if(ocl->oc_class == GEM_CLASS) Strcat(buf, (ocl->oc_material == MINERAL) ? " stone" : " gem"); if(un) Sprintf(eos(buf), " called %s", un); } return(buf); } /* here for ring/scroll/potion/wand */ if(nn) { if (ocl->oc_unique) Strcpy(buf, actualn); /* avoid spellbook of Book of the Dead */ else Sprintf(eos(buf), " of %s", actualn); } if(un) Sprintf(eos(buf), " called %s", un); if(dn) Sprintf(eos(buf), " (%s)", dn); return(buf); } /* less verbose result than obj_typename(); either the actual name or the description (but not both); user-assigned name is ignored */ char * simple_typename(otyp) int otyp; { char *bufp, *pp, *save_uname = objects[otyp].oc_uname; objects[otyp].oc_uname = 0; /* suppress any name given by user */ bufp = obj_typename(otyp); objects[otyp].oc_uname = save_uname; if ((pp = strstri(bufp, " (")) != 0) *pp = '\0'; /* strip the appended description */ return bufp; } boolean obj_is_pname(obj) register struct obj *obj; { return((boolean)(obj->dknown && obj->known && obj->onamelth && /* Since there aren't any objects which are both artifacts and unique, the last check is redundant. */ obj->oartifact && !objects[obj->otyp].oc_unique)); } /* Give the name of an object seen at a distance. Unlike xname/doname, * we don't want to set dknown if it's not set already. The kludge used is * to temporarily set Blind so that xname() skips the dknown setting. This * assumes that we don't want to do this too often; if this function becomes * frequently used, it'd probably be better to pass a parameter to xname() * or doname() instead. */ char * distant_name(obj, func) register struct obj *obj; char *FDECL((*func), (OBJ_P)); { char *str; long save_Blinded = Blinded; Blinded = 1; str = (*func)(obj); Blinded = save_Blinded; return str; } /* convert player specified fruit name into corresponding fruit juice name ("slice of pizza" -> "pizza juice" rather than "slice of pizza juice") */ char * fruitname(juice) boolean juice; /* whether or not to append " juice" to the name */ { char *buf = nextobuf(); const char *fruit_nam = strstri(pl_fruit, " of "); if (fruit_nam) fruit_nam += 4; /* skip past " of " */ else fruit_nam = pl_fruit; /* use it as is */ Sprintf(buf, "%s%s", makesingular(fruit_nam), juice ? " juice" : ""); return buf; } #endif /* OVLB */ #ifdef OVL1 char * xname(obj) register struct obj *obj; { register char *buf; register int typ = obj->otyp; register struct objclass *ocl = &objects[typ]; register int nn = ocl->oc_name_known; register const char *actualn = OBJ_NAME(*ocl); register const char *dn = OBJ_DESCR(*ocl); register const char *un = ocl->oc_uname; buf = nextobuf() + PREFIX; /* leave room for "17 -3 " */ if (Role_if(PM_SAMURAI) && Japanese_item_name(typ)) actualn = Japanese_item_name(typ); buf[0] = '\0'; /* * clean up known when it's tied to oc_name_known, eg after AD_DRIN * This is only required for unique objects since the article * printed for the object is tied to the combination of the two * and printing the wrong article gives away information. */ if (!nn && ocl->oc_uses_known && ocl->oc_unique) obj->known = 0; if (!Blind) obj->dknown = TRUE; if (Role_if(PM_PRIEST)) obj->bknown = TRUE; if (obj_is_pname(obj)) goto nameit; switch (obj->oclass) { case AMULET_CLASS: if (!obj->dknown) Strcpy(buf, "amulet"); else if (typ == AMULET_OF_YENDOR || typ == FAKE_AMULET_OF_YENDOR) /* each must be identified individually */ Strcpy(buf, obj->known ? actualn : dn); else if (nn) Strcpy(buf, actualn); else if (un) Sprintf(buf,"amulet called %s", un); else Sprintf(buf,"%s amulet", dn); break; case WEAPON_CLASS: if (is_poisonable(obj) && obj->opoisoned) Strcpy(buf, "poisoned "); case VENOM_CLASS: case TOOL_CLASS: if (typ == LENSES) Strcpy(buf, "pair of "); if (!obj->dknown) Strcat(buf, dn ? dn : actualn); else if (nn) Strcat(buf, actualn); else if (un) { Strcat(buf, dn ? dn : actualn); Strcat(buf, " called "); Strcat(buf, un); } else Strcat(buf, dn ? dn : actualn); /* If we use an() here we'd have to remember never to use */ /* it whenever calling doname() or xname(). */ if (typ == FIGURINE) Sprintf(eos(buf), " of a%s %s", index(vowels,*(mons[obj->corpsenm].mname)) ? "n" : "", mons[obj->corpsenm].mname); break; case ARMOR_CLASS: /* depends on order of the dragon scales objects */ if (typ >= GRAY_DRAGON_SCALES && typ <= YELLOW_DRAGON_SCALES) { Sprintf(buf, "set of %s", actualn); break; } if(is_boots(obj) || is_gloves(obj)) Strcpy(buf,"pair of "); if(obj->otyp >= ELVEN_SHIELD && obj->otyp <= ORCISH_SHIELD && !obj->dknown) { Strcpy(buf, "shield"); break; } if(obj->otyp == SHIELD_OF_REFLECTION && !obj->dknown) { Strcpy(buf, "smooth shield"); break; } if(nn) Strcat(buf, actualn); else if(un) { if(is_boots(obj)) Strcat(buf,"boots"); else if(is_gloves(obj)) Strcat(buf,"gloves"); else if(is_cloak(obj)) Strcpy(buf,"cloak"); else if(is_helmet(obj)) Strcpy(buf,"helmet"); else if(is_shield(obj)) Strcpy(buf,"shield"); else Strcpy(buf,"armor"); Strcat(buf, " called "); Strcat(buf, un); } else Strcat(buf, dn); break; case FOOD_CLASS: if (typ == SLIME_MOLD) { register struct fruit *f; for(f=ffruit; f; f = f->nextf) { if(f->fid == obj->spe) { Strcpy(buf, f->fname); break; } } if (!f) impossible("Bad fruit #%d?", obj->spe); break; } Strcpy(buf, actualn); if (typ == TIN && obj->known) { if(obj->spe > 0) Strcat(buf, " of spinach"); else if (obj->corpsenm == NON_PM) Strcpy(buf, "empty tin"); else if (vegetarian(&mons[obj->corpsenm])) Sprintf(eos(buf), " of %s", mons[obj->corpsenm].mname); else Sprintf(eos(buf), " of %s meat", mons[obj->corpsenm].mname); } break; case COIN_CLASS: case CHAIN_CLASS: Strcpy(buf, actualn); break; case ROCK_CLASS: if (typ == STATUE) Sprintf(buf, "%s%s of %s%s", (Role_if(PM_ARCHEOLOGIST) && (obj->spe & STATUE_HISTORIC)) ? "historic " : "" , actualn, type_is_pname(&mons[obj->corpsenm]) ? "" : (mons[obj->corpsenm].geno & G_UNIQ) ? "the " : (index(vowels,*(mons[obj->corpsenm].mname)) ? "an " : "a "), mons[obj->corpsenm].mname); else Strcpy(buf, actualn); break; case BALL_CLASS: Sprintf(buf, "%sheavy iron ball", (obj->owt > ocl->oc_weight) ? "very " : ""); break; case POTION_CLASS: if (obj->dknown && obj->odiluted) Strcpy(buf, "diluted "); if(nn || un || !obj->dknown) { Strcat(buf, "potion"); if(!obj->dknown) break; if(nn) { Strcat(buf, " of "); if (typ == POT_WATER && obj->bknown && (obj->blessed || obj->cursed)) { Strcat(buf, obj->blessed ? "holy " : "unholy "); } Strcat(buf, actualn); } else { Strcat(buf, " called "); Strcat(buf, un); } } else { Strcat(buf, dn); Strcat(buf, " potion"); } break; case SCROLL_CLASS: Strcpy(buf, "scroll"); if(!obj->dknown) break; if(nn) { Strcat(buf, " of "); Strcat(buf, actualn); } else if(un) { Strcat(buf, " called "); Strcat(buf, un); } else if (ocl->oc_magic) { Strcat(buf, " labeled "); Strcat(buf, dn); } else { Strcpy(buf, dn); Strcat(buf, " scroll"); } break; case WAND_CLASS: if(!obj->dknown) Strcpy(buf, "wand"); else if(nn) Sprintf(buf, "wand of %s", actualn); else if(un) Sprintf(buf, "wand called %s", un); else Sprintf(buf, "%s wand", dn); break; case SPBOOK_CLASS: if (!obj->dknown) { Strcpy(buf, "spellbook"); } else if (nn) { if (typ != SPE_BOOK_OF_THE_DEAD) Strcpy(buf, "spellbook of "); Strcat(buf, actualn); } else if (un) { Sprintf(buf, "spellbook called %s", un); } else Sprintf(buf, "%s spellbook", dn); break; case RING_CLASS: if(!obj->dknown) Strcpy(buf, "ring"); else if(nn) Sprintf(buf, "ring of %s", actualn); else if(un) Sprintf(buf, "ring called %s", un); else Sprintf(buf, "%s ring", dn); break; case GEM_CLASS: { const char *rock = (ocl->oc_material == MINERAL) ? "stone" : "gem"; if (!obj->dknown) { Strcpy(buf, rock); } else if (!nn) { if (un) Sprintf(buf,"%s called %s", rock, un); else Sprintf(buf, "%s %s", dn, rock); } else { Strcpy(buf, actualn); if (GemStone(typ)) Strcat(buf, " stone"); } break; } default: Sprintf(buf,"glorkum %d %d %d", obj->oclass, typ, obj->spe); } if (obj->quan != 1L) Strcpy(buf, makeplural(buf)); if (obj->onamelth && obj->dknown) { Strcat(buf, " named "); nameit: Strcat(buf, ONAME(obj)); } if (!strncmpi(buf, "the ", 4)) buf += 4; return(buf); } /* xname() output augmented for multishot missile feedback */ char * mshot_xname(obj) struct obj *obj; { char tmpbuf[BUFSZ]; char *onm = xname(obj); if (m_shot.n > 1 && m_shot.o == obj->otyp) { /* copy xname's result so that we can reuse its return buffer */ Strcpy(tmpbuf, onm); /* "the Nth arrow"; value will eventually be passed to an() or The(), both of which correctly handle this "the " prefix */ Sprintf(onm, "the %d%s %s", m_shot.i, ordin(m_shot.i), tmpbuf); } return onm; } #endif /* OVL1 */ #ifdef OVL0 /* used for naming "the unique_item" instead of "a unique_item" */ boolean the_unique_obj(obj) register struct obj *obj; { if (!obj->dknown) return FALSE; else if (obj->otyp == FAKE_AMULET_OF_YENDOR && !obj->known) return TRUE; /* lie */ else return (boolean)(objects[obj->otyp].oc_unique && (obj->known || obj->otyp == AMULET_OF_YENDOR)); } static void add_erosion_words(obj,prefix) struct obj *obj; char *prefix; { boolean iscrys = (obj->otyp == CRYSKNIFE); if (!is_damageable(obj) && !iscrys) return; /* The only cases where any of these bits do double duty are for * rotted food and diluted potions, which are all not is_damageable(). */ if (obj->oeroded && !iscrys) { switch (obj->oeroded) { case 2: Strcat(prefix, "very "); break; case 3: Strcat(prefix, "thoroughly "); break; } Strcat(prefix, is_rustprone(obj) ? "rusty " : "burnt "); } if (obj->oeroded2 && !iscrys) { switch (obj->oeroded2) { case 2: Strcat(prefix, "very "); break; case 3: Strcat(prefix, "thoroughly "); break; } Strcat(prefix, is_corrodeable(obj) ? "corroded " : "rotted "); } if (obj->rknown && obj->oerodeproof) Strcat(prefix, iscrys ? "fixed " : is_rustprone(obj) ? "rustproof " : is_corrodeable(obj) ? "corrodeproof " : /* "stainless"? */ is_flammable(obj) ? "fireproof " : ""); } char * doname(obj) register struct obj *obj; { boolean ispoisoned = FALSE; char prefix[PREFIX]; char tmpbuf[PREFIX+1]; /* when we have to add something at the start of prefix instead of the * end (Strcat is used on the end) */ register char *bp = xname(obj); /* When using xname, we want "poisoned arrow", and when using * doname, we want "poisoned +0 arrow". This kludge is about the only * way to do it, at least until someone overhauls xname() and doname(), * combining both into one function taking a parameter. */ /* must check opoisoned--someone can have a weirdly-named fruit */ if (!strncmp(bp, "poisoned ", 9) && obj->opoisoned) { bp += 9; ispoisoned = TRUE; } if(obj->quan != 1L) Sprintf(prefix, "%ld ", obj->quan); else if (obj_is_pname(obj) || the_unique_obj(obj)) { if (!strncmpi(bp, "the ", 4)) bp += 4; Strcpy(prefix, "the "); } else Strcpy(prefix, "a "); #ifdef INVISIBLE_OBJECTS if (obj->oinvis) Strcat(prefix,"invisible "); #endif if (obj->bknown && obj->oclass != COIN_CLASS && (obj->otyp != POT_WATER || !objects[POT_WATER].oc_name_known || (!obj->cursed && !obj->blessed))) { /* allow 'blessed clear potion' if we don't know it's holy water; * always allow "uncursed potion of water" */ if (obj->cursed) Strcat(prefix, "cursed "); else if (obj->blessed) Strcat(prefix, "blessed "); else if ((!obj->known || !objects[obj->otyp].oc_charged || (obj->oclass == ARMOR_CLASS || obj->oclass == RING_CLASS)) /* For most items with charges or +/-, if you know how many * charges are left or what the +/- is, then you must have * totally identified the item, so "uncursed" is unneccesary, * because an identified object not described as "blessed" or * "cursed" must be uncursed. * * If the charges or +/- is not known, "uncursed" must be * printed to avoid ambiguity between an item whose curse * status is unknown, and an item known to be uncursed. */ #ifdef MAIL && obj->otyp != SCR_MAIL #endif && obj->otyp != FAKE_AMULET_OF_YENDOR && obj->otyp != AMULET_OF_YENDOR && !Role_if(PM_PRIEST)) Strcat(prefix, "uncursed "); } if (obj->greased) Strcat(prefix, "greased "); switch(obj->oclass) { case AMULET_CLASS: if(obj->owornmask & W_AMUL) Strcat(bp, " (being worn)"); break; case WEAPON_CLASS: if(ispoisoned) Strcat(prefix, "poisoned "); plus: add_erosion_words(obj, prefix); if(obj->known) { Strcat(prefix, sitoa(obj->spe)); Strcat(prefix, " "); } break; case ARMOR_CLASS: if(obj->owornmask & W_ARMOR) Strcat(bp, (obj == uskin) ? " (embedded in your skin)" : " (being worn)"); goto plus; case TOOL_CLASS: /* weptools already get this done when we go to the +n code */ if (!is_weptool(obj)) add_erosion_words(obj, prefix); if(obj->owornmask & (W_TOOL /* blindfold */ #ifdef STEED | W_SADDLE #endif )) { Strcat(bp, " (being worn)"); break; } if (obj->otyp == LEASH && obj->leashmon != 0) { Strcat(bp, " (in use)"); break; } if (is_weptool(obj)) goto plus; if (obj->otyp == CANDELABRUM_OF_INVOCATION) { if (!obj->spe) Strcpy(tmpbuf, "no"); else Sprintf(tmpbuf, "%d", obj->spe); Sprintf(eos(bp), " (%s candle%s%s)", tmpbuf, plur(obj->spe), !obj->lamplit ? " attached" : ", lit"); break; } else if (obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP || obj->otyp == BRASS_LANTERN || Is_candle(obj)) { if (Is_candle(obj) && obj->age < 20L * (long)objects[obj->otyp].oc_cost) Strcat(prefix, "partly used "); if(obj->lamplit) Strcat(bp, " (lit)"); break; } if(objects[obj->otyp].oc_charged) goto charges; break; case WAND_CLASS: add_erosion_words(obj, prefix); charges: if(obj->known) Sprintf(eos(bp), " (%d:%d)", (int)obj->recharged, obj->spe); break; case POTION_CLASS: if (obj->otyp == POT_OIL && obj->lamplit) Strcat(bp, " (lit)"); break; case RING_CLASS: add_erosion_words(obj, prefix); ring: if(obj->owornmask & W_RINGR) Strcat(bp, " (on right "); if(obj->owornmask & W_RINGL) Strcat(bp, " (on left "); if(obj->owornmask & W_RING) { Strcat(bp, body_part(HAND)); Strcat(bp, ")"); } if(obj->known && objects[obj->otyp].oc_charged) { Strcat(prefix, sitoa(obj->spe)); Strcat(prefix, " "); } break; case FOOD_CLASS: if (obj->oeaten) Strcat(prefix, "partly eaten "); if (obj->otyp == CORPSE) { if (mons[obj->corpsenm].geno & G_UNIQ) { Sprintf(prefix, "%s%s ", (type_is_pname(&mons[obj->corpsenm]) ? "" : "the "), s_suffix(mons[obj->corpsenm].mname)); if (obj->oeaten) Strcat(prefix, "partly eaten "); } else { Strcat(prefix, mons[obj->corpsenm].mname); Strcat(prefix, " "); } } else if (obj->otyp == EGG) { #if 0 /* corpses don't tell if they're stale either */ if (obj->known && stale_egg(obj)) Strcat(prefix, "stale "); #endif if (obj->corpsenm >= LOW_PM && (obj->known || mvitals[obj->corpsenm].mvflags & MV_KNOWS_EGG)) { Strcat(prefix, mons[obj->corpsenm].mname); Strcat(prefix, " "); if (obj->spe) Strcat(bp, " (laid by you)"); } } if (obj->otyp == MEAT_RING) goto ring; break; case BALL_CLASS: case CHAIN_CLASS: add_erosion_words(obj, prefix); if(obj->owornmask & W_BALL) Strcat(bp, " (chained to you)"); break; } if((obj->owornmask & W_WEP) && !mrg_to_wielded) { if (obj->quan != 1L) { Strcat(bp, " (wielded)"); } else { const char *hand_s = body_part(HAND); if (bimanual(obj)) hand_s = makeplural(hand_s); Sprintf(eos(bp), " (weapon in %s)", hand_s); } } if(obj->owornmask & W_SWAPWEP) { if (u.twoweap) Sprintf(eos(bp), " (wielded in other %s)", body_part(HAND)); else Strcat(bp, " (alternate weapon; not wielded)"); } if(obj->owornmask & W_QUIVER) Strcat(bp, " (in quiver)"); if(obj->unpaid) { xchar ox, oy; long quotedprice = unpaid_cost(obj); struct monst *shkp = (struct monst *)0; if (Has_contents(obj) && get_obj_location(obj, &ox, &oy, BURIED_TOO|CONTAINED_TOO) && costly_spot(ox, oy) && (shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE)))) quotedprice += contained_cost(obj, shkp, 0L, FALSE, TRUE); Sprintf(eos(bp), " (unpaid, %ld %s)", quotedprice, currency(quotedprice)); } if (!strncmp(prefix, "a ", 2) && index(vowels, *(prefix+2) ? *(prefix+2) : *bp) && (*(prefix+2) || (strncmp(bp, "uranium", 7) && strncmp(bp, "unicorn", 7) && strncmp(bp, "eucalyptus", 10)))) { Strcpy(tmpbuf, prefix); Strcpy(prefix, "an "); Strcpy(prefix+3, tmpbuf+2); } bp = strprepend(bp, prefix); return(bp); } #endif /* OVL0 */ #ifdef OVLB /* used from invent.c */ boolean not_fully_identified(otmp) register struct obj *otmp; { #ifdef GOLDOBJ /* gold doesn't have any interesting attributes [yet?] */ if (otmp->oclass == COIN_CLASS) return FALSE; /* always fully ID'd */ #endif /* check fundamental ID hallmarks first */ if (!otmp->known || !otmp->dknown || #ifdef MAIL (!otmp->bknown && otmp->otyp != SCR_MAIL) || #else !otmp->bknown || #endif !objects[otmp->otyp].oc_name_known) /* ?redundant? */ return TRUE; if (otmp->oartifact && undiscovered_artifact(otmp->oartifact)) return TRUE; /* otmp->rknown is the only item of interest if we reach here */ /* * Note: if a revision ever allows scrolls to become fireproof or * rings to become shockproof, this checking will need to be revised. * `rknown' ID only matters if xname() will provide the info about it. */ if (otmp->rknown || (otmp->oclass != ARMOR_CLASS && otmp->oclass != WEAPON_CLASS && !is_weptool(otmp) && /* (redunant) */ otmp->oclass != BALL_CLASS)) /* (useless) */ return FALSE; else /* lack of `rknown' only matters for vulnerable objects */ return (boolean)(is_rustprone(otmp) || is_corrodeable(otmp) || is_flammable(otmp)); } char * corpse_xname(otmp, ignore_oquan) struct obj *otmp; boolean ignore_oquan; /* to force singular */ { char *nambuf = nextobuf(); Sprintf(nambuf, "%s corpse", mons[otmp->corpsenm].mname); if (ignore_oquan || otmp->quan < 2) return nambuf; else return makeplural(nambuf); } /* xname, unless it's a corpse, then corpse_xname(obj, FALSE) */ char * cxname(obj) struct obj *obj; { if (obj->otyp == CORPSE) return corpse_xname(obj, FALSE); return xname(obj); } /* treat an object as fully ID'd when it might be used as reason for death */ char * killer_xname(obj) struct obj *obj; { struct obj save_obj; unsigned save_ocknown; char *buf, *save_ocuname; /* remember original settings for core of the object; oname and oattached extensions don't matter here--since they aren't modified they don't need to be saved and restored */ save_obj = *obj; /* killer name should be more specific than general xname; however, exact info like blessed/cursed and rustproof makes things be too verbose */ obj->known = obj->dknown = 1; obj->bknown = obj->rknown = obj->greased = 0; /* if character is a priest[ess], bknown will get toggled back on */ obj->blessed = obj->cursed = 0; /* "killed by poisoned " would be misleading when poison is not the cause of death and "poisoned by poisoned " would be redundant when it is, so suppress "poisoned" prefix */ obj->opoisoned = 0; /* strip user-supplied name; artifacts keep theirs */ if (!obj->oartifact) obj->onamelth = 0; /* temporarily identify the type of object */ save_ocknown = objects[obj->otyp].oc_name_known; objects[obj->otyp].oc_name_known = 1; save_ocuname = objects[obj->otyp].oc_uname; objects[obj->otyp].oc_uname = 0; /* avoid "foo called bar" */ buf = xname(obj); if (obj->quan == 1L) buf = obj_is_pname(obj) ? the(buf) : an(buf); objects[obj->otyp].oc_name_known = save_ocknown; objects[obj->otyp].oc_uname = save_ocuname; *obj = save_obj; /* restore object's core settings */ return buf; } /* * Used if only one of a collection of objects is named (e.g. in eat.c). */ const char * singular(otmp, func) register struct obj *otmp; char *FDECL((*func), (OBJ_P)); { long savequan; char *nam; /* Note: using xname for corpses will not give the monster type */ if (otmp->otyp == CORPSE && func == xname) return corpse_xname(otmp, TRUE); savequan = otmp->quan; otmp->quan = 1L; nam = (*func)(otmp); otmp->quan = savequan; return nam; } char * an(str) register const char *str; { char *buf = nextobuf(); buf[0] = '\0'; if (strncmpi(str, "the ", 4) && strcmp(str, "molten lava") && strcmp(str, "iron bars") && strcmp(str, "ice")) { if (index(vowels, *str) && strncmp(str, "one-", 4) && strncmp(str, "useful", 6) && strncmp(str, "unicorn", 7) && strncmp(str, "uranium", 7) && strncmp(str, "eucalyptus", 10)) Strcpy(buf, "an "); else Strcpy(buf, "a "); } Strcat(buf, str); return buf; } char * An(str) const char *str; { register char *tmp = an(str); *tmp = highc(*tmp); return tmp; } /* * Prepend "the" if necessary; assumes str is a subject derived from xname. * Use type_is_pname() for monster names, not the(). the() is idempotent. */ char * the(str) const char *str; { char *buf = nextobuf(); boolean insert_the = FALSE; if (!strncmpi(str, "the ", 4)) { buf[0] = lowc(*str); Strcpy(&buf[1], str+1); return buf; } else if (*str < 'A' || *str > 'Z') { /* not a proper name, needs an article */ insert_the = TRUE; } else { /* Probably a proper name, might not need an article */ register char *tmp, *named, *called; int l; /* some objects have capitalized adjectives in their names */ if(((tmp = rindex(str, ' ')) || (tmp = rindex(str, '-'))) && (tmp[1] < 'A' || tmp[1] > 'Z')) insert_the = TRUE; else if (tmp && index(str, ' ') < tmp) { /* has spaces */ /* it needs an article if the name contains "of" */ tmp = strstri(str, " of "); named = strstri(str, " named "); called = strstri(str, " called "); if (called && (!named || called < named)) named = called; if (tmp && (!named || tmp < named)) /* found an "of" */ insert_the = TRUE; /* stupid special case: lacks "of" but needs "the" */ else if (!named && (l = strlen(str)) >= 31 && !strcmp(&str[l - 31], "Platinum Yendorian Express Card")) insert_the = TRUE; } } if (insert_the) Strcpy(buf, "the "); else buf[0] = '\0'; Strcat(buf, str); return buf; } char * The(str) const char *str; { register char *tmp = the(str); *tmp = highc(*tmp); return tmp; } /* returns "count cxname(otmp)" or just cxname(otmp) if count == 1 */ char * aobjnam(otmp,verb) register struct obj *otmp; register const char *verb; { register char *bp = cxname(otmp); char prefix[PREFIX]; if(otmp->quan != 1L) { Sprintf(prefix, "%ld ", otmp->quan); bp = strprepend(bp, prefix); } if(verb) { Strcat(bp, " "); Strcat(bp, otense(otmp, verb)); } return(bp); } /* like aobjnam, but prepend "The", not count, and use xname */ char * Tobjnam(otmp, verb) register struct obj *otmp; register const char *verb; { char *bp = The(xname(otmp)); if(verb) { Strcat(bp, " "); Strcat(bp, otense(otmp, verb)); } return(bp); } /* return form of the verb (input plural) if xname(otmp) were the subject */ char * otense(otmp, verb) register struct obj *otmp; register const char *verb; { char *buf; /* * verb is given in plural (without trailing s). Return as input * if the result of xname(otmp) would be plural. Don't bother * recomputing xname(otmp) at this time. */ if (!is_plural(otmp)) return vtense((char *)0, verb); buf = nextobuf(); Strcpy(buf, verb); return buf; } /* various singular words that vtense would otherwise categorize as plural */ static const char * const special_subjs[] = { "erinys", "manes", /* this one is ambiguous */ "Cyclops", "Hippocrates", "Pelias", "aklys", "amnesia", "paralysis", 0 }; /* return form of the verb (input plural) for present tense 3rd person subj */ char * vtense(subj, verb) register const char *subj; register const char *verb; { char *buf = nextobuf(); int len, ltmp; const char *sp, *spot; const char * const *spec; /* * verb is given in plural (without trailing s). Return as input * if subj appears to be plural. Add special cases as necessary. * Many hard cases can already be handled by using otense() instead. * If this gets much bigger, consider decomposing makeplural. * Note: monster names are not expected here (except before corpse). * * special case: allow null sobj to get the singular 3rd person * present tense form so we don't duplicate this code elsewhere. */ if (subj) { if (!strncmpi(subj, "a ", 2) || !strncmpi(subj, "an ", 3)) goto sing; spot = (const char *)0; for (sp = subj; (sp = index(sp, ' ')) != 0; ++sp) { if (!strncmp(sp, " of ", 4) || !strncmp(sp, " from ", 6) || !strncmp(sp, " called ", 8) || !strncmp(sp, " named ", 7) || !strncmp(sp, " labeled ", 9)) { if (sp != subj) spot = sp - 1; break; } } len = (int) strlen(subj); if (!spot) spot = subj + len - 1; /* * plural: anything that ends in 's', but not '*us' or '*ss'. * Guess at a few other special cases that makeplural creates. */ if ((*spot == 's' && spot != subj && (*(spot-1) != 'u' && *(spot-1) != 's')) || ((spot - subj) >= 4 && !strncmp(spot-3, "eeth", 4)) || ((spot - subj) >= 3 && !strncmp(spot-3, "feet", 4)) || ((spot - subj) >= 2 && !strncmp(spot-1, "ia", 2)) || ((spot - subj) >= 2 && !strncmp(spot-1, "ae", 2))) { /* check for special cases to avoid false matches */ len = (int)(spot - subj) + 1; for (spec = special_subjs; *spec; spec++) { ltmp = strlen(*spec); if (len == ltmp && !strncmpi(*spec, subj, len)) goto sing; /* also check for to catch things like "the invisible erinys" */ if (len > ltmp && *(spot - ltmp) == ' ' && !strncmpi(*spec, spot - ltmp + 1, ltmp)) goto sing; } return strcpy(buf, verb); } /* * 3rd person plural doesn't end in telltale 's'; * 2nd person singular behaves as if plural. */ if (!strcmpi(subj, "they") || !strcmpi(subj, "you")) return strcpy(buf, verb); } sing: len = strlen(verb); spot = verb + len - 1; if (!strcmp(verb, "are")) Strcpy(buf, "is"); else if (!strcmp(verb, "have")) Strcpy(buf, "has"); else if (index("zxs", *spot) || (len >= 2 && *spot=='h' && index("cs", *(spot-1))) || (len == 2 && *spot == 'o')) { /* Ends in z, x, s, ch, sh; add an "es" */ Strcpy(buf, verb); Strcat(buf, "es"); } else if (*spot == 'y' && (!index(vowels, *(spot-1)))) { /* like "y" case in makeplural */ Strcpy(buf, verb); Strcpy(buf + len - 1, "ies"); } else { Strcpy(buf, verb); Strcat(buf, "s"); } return buf; } /* capitalized variant of doname() */ char * Doname2(obj) register struct obj *obj; { register char *s = doname(obj); *s = highc(*s); return(s); } /* returns "your xname(obj)" or "Foobar's xname(obj)" or "the xname(obj)" */ char * yname(obj) struct obj *obj; { char *outbuf = nextobuf(); char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */ int space_left = BUFSZ - strlen(s) - sizeof " "; return strncat(strcat(s, " "), cxname(obj), space_left); } /* capitalized variant of yname() */ char * Yname2(obj) struct obj *obj; { char *s = yname(obj); *s = highc(*s); return s; } /* returns "your simple_typename(obj->otyp)" * or "Foobar's simple_typename(obj->otyp)" * or "the simple_typename(obj-otyp)" */ char * ysimple_name(obj) struct obj *obj; { char *outbuf = nextobuf(); char *s = shk_your(outbuf, obj); /* assert( s == outbuf ); */ int space_left = BUFSZ - strlen(s) - sizeof " "; return strncat(strcat(s, " "), simple_typename(obj->otyp), space_left); } /* capitalized variant of ysimple_name() */ char * Ysimple_name2(obj) struct obj *obj; { char *s = ysimple_name(obj); *s = highc(*s); return s; } static const char *wrp[] = { "wand", "ring", "potion", "scroll", "gem", "amulet", "spellbook", "spell book", /* for non-specific wishes */ "weapon", "armor", "armour", "tool", "food", "comestible", }; static const char wrpsym[] = { WAND_CLASS, RING_CLASS, POTION_CLASS, SCROLL_CLASS, GEM_CLASS, AMULET_CLASS, SPBOOK_CLASS, SPBOOK_CLASS, WEAPON_CLASS, ARMOR_CLASS, ARMOR_CLASS, TOOL_CLASS, FOOD_CLASS, FOOD_CLASS }; #endif /* OVLB */ #ifdef OVL0 /* Plural routine; chiefly used for user-defined fruits. We have to try to * account for everything reasonable the player has; something unreasonable * can still break the code. However, it's still a lot more accurate than * "just add an s at the end", which Rogue uses... * * Also used for plural monster names ("Wiped out all homunculi.") * and body parts. * * Also misused by muse.c to convert 1st person present verbs to 2nd person. */ char * makeplural(oldstr) const char *oldstr; { /* Note: cannot use strcmpi here -- it'd give MATZot, CAVEMeN,... */ register char *spot; char *str = nextobuf(); const char *excess = (char *)0; int len; while (*oldstr==' ') oldstr++; if (!oldstr || !*oldstr) { impossible("plural of null?"); Strcpy(str, "s"); return str; } Strcpy(str, oldstr); /* * Skip changing "pair of" to "pairs of". According to Webster, usual * English usage is use pairs for humans, e.g. 3 pairs of dancers, * and pair for objects and non-humans, e.g. 3 pair of boots. We don't * refer to pairs of humans in this game so just skip to the bottom. */ if (!strncmp(str, "pair of ", 8)) goto bottom; /* Search for common compounds, ex. lump of royal jelly */ for(spot=str; *spot; spot++) { if (!strncmp(spot, " of ", 4) || !strncmp(spot, " labeled ", 9) || !strncmp(spot, " called ", 8) || !strncmp(spot, " named ", 7) || !strcmp(spot, " above") /* lurkers above */ || !strncmp(spot, " versus ", 8) || !strncmp(spot, " from ", 6) || !strncmp(spot, " in ", 4) || !strncmp(spot, " on ", 4) || !strncmp(spot, " a la ", 6) || !strncmp(spot, " with", 5) /* " with "? */ || !strncmp(spot, " de ", 4) || !strncmp(spot, " d'", 3) || !strncmp(spot, " du ", 4)) { excess = oldstr + (int) (spot - str); *spot = 0; break; } } spot--; while (*spot==' ') spot--; /* Strip blanks from end */ *(spot+1) = 0; /* Now spot is the last character of the string */ len = strlen(str); /* Single letters */ if (len==1 || !letter(*spot)) { Strcpy(spot+1, "'s"); goto bottom; } /* Same singular and plural; mostly Japanese words except for "manes" */ if ((len == 2 && !strcmp(str, "ya")) || (len >= 2 && !strcmp(spot-1, "ai")) || /* samurai, Uruk-hai */ (len >= 3 && !strcmp(spot-2, " ya")) || (len >= 4 && (!strcmp(spot-3, "fish") || !strcmp(spot-3, "tuna") || !strcmp(spot-3, "deer") || !strcmp(spot-3, "yaki"))) || (len >= 5 && (!strcmp(spot-4, "sheep") || !strcmp(spot-4, "ninja") || !strcmp(spot-4, "ronin") || !strcmp(spot-4, "shito") || !strcmp(spot-7, "shuriken") || !strcmp(spot-4, "tengu") || !strcmp(spot-4, "manes"))) || (len >= 6 && !strcmp(spot-5, "ki-rin")) || (len >= 7 && !strcmp(spot-6, "gunyoki"))) goto bottom; /* man/men ("Wiped out all cavemen.") */ if (len >= 3 && !strcmp(spot-2, "man") && (len<6 || strcmp(spot-5, "shaman")) && (len<5 || strcmp(spot-4, "human"))) { *(spot-1) = 'e'; goto bottom; } /* tooth/teeth */ if (len >= 5 && !strcmp(spot-4, "tooth")) { Strcpy(spot-3, "eeth"); goto bottom; } /* knife/knives, etc... */ if (!strcmp(spot-1, "fe")) { Strcpy(spot-1, "ves"); goto bottom; } else if (*spot == 'f') { if (index("lr", *(spot-1)) || index(vowels, *(spot-1))) { Strcpy(spot, "ves"); goto bottom; } else if (len >= 5 && !strncmp(spot-4, "staf", 4)) { Strcpy(spot-1, "ves"); goto bottom; } } /* foot/feet (body part) */ if (len >= 4 && !strcmp(spot-3, "foot")) { Strcpy(spot-2, "eet"); goto bottom; } /* ium/ia (mycelia, baluchitheria) */ if (len >= 3 && !strcmp(spot-2, "ium")) { *(spot--) = (char)0; *spot = 'a'; goto bottom; } /* algae, larvae, hyphae (another fungus part) */ if ((len >= 4 && !strcmp(spot-3, "alga")) || (len >= 5 && (!strcmp(spot-4, "hypha") || !strcmp(spot-4, "larva")))) { Strcpy(spot, "ae"); goto bottom; } /* fungus/fungi, homunculus/homunculi, but buses, lotuses, wumpuses */ if (len > 3 && !strcmp(spot-1, "us") && (len < 5 || (strcmp(spot-4, "lotus") && (len < 6 || strcmp(spot-5, "wumpus"))))) { *(spot--) = (char)0; *spot = 'i'; goto bottom; } /* vortex/vortices */ if (len >= 6 && !strcmp(spot-3, "rtex")) { Strcpy(spot-1, "ices"); goto bottom; } /* djinni/djinn (note: also efreeti/efreet) */ if (len >= 6 && !strcmp(spot-5, "djinni")) { *spot = (char)0; goto bottom; } /* mumak/mumakil */ if (len >= 5 && !strcmp(spot-4, "mumak")) { Strcpy(spot+1, "il"); goto bottom; } /* sis/ses (nemesis) */ if (len >= 3 && !strcmp(spot-2, "sis")) { *(spot-1) = 'e'; goto bottom; } /* erinys/erinyes */ if (len >= 6 && !strcmp(spot-5, "erinys")) { Strcpy(spot, "es"); goto bottom; } /* mouse/mice,louse/lice (not a monster, but possible in food names) */ if (len >= 5 && !strcmp(spot-3, "ouse") && index("MmLl", *(spot-4))) { Strcpy(spot-3, "ice"); goto bottom; } /* matzoh/matzot, possible food name */ if (len >= 6 && (!strcmp(spot-5, "matzoh") || !strcmp(spot-5, "matzah"))) { Strcpy(spot-1, "ot"); goto bottom; } if (len >= 5 && (!strcmp(spot-4, "matzo") || !strcmp(spot-5, "matza"))) { Strcpy(spot, "ot"); goto bottom; } /* child/children (for wise guys who give their food funny names) */ if (len >= 5 && !strcmp(spot-4, "child")) { Strcpy(spot, "dren"); goto bottom; } /* note: -eau/-eaux (gateau, bordeau...) */ /* note: ox/oxen, VAX/VAXen, goose/geese */ /* Ends in z, x, s, ch, sh; add an "es" */ if (index("zxs", *spot) || (len >= 2 && *spot=='h' && index("cs", *(spot-1))) /* Kludge to get "tomatoes" and "potatoes" right */ || (len >= 4 && !strcmp(spot-2, "ato"))) { Strcpy(spot+1, "es"); goto bottom; } /* Ends in y preceded by consonant (note: also "qu") change to "ies" */ if (*spot == 'y' && (!index(vowels, *(spot-1)))) { Strcpy(spot, "ies"); goto bottom; } /* Default: append an 's' */ Strcpy(spot+1, "s"); bottom: if (excess) Strcpy(eos(str), excess); return str; } #endif /* OVL0 */ struct o_range { const char *name, oclass; int f_o_range, l_o_range; }; #ifndef OVLB STATIC_DCL const struct o_range o_ranges[]; #else /* OVLB */ /* wishable subranges of objects */ STATIC_OVL NEARDATA const struct o_range o_ranges[] = { { "bag", TOOL_CLASS, SACK, BAG_OF_TRICKS }, { "lamp", TOOL_CLASS, OIL_LAMP, MAGIC_LAMP }, { "candle", TOOL_CLASS, TALLOW_CANDLE, WAX_CANDLE }, { "horn", TOOL_CLASS, TOOLED_HORN, HORN_OF_PLENTY }, { "shield", ARMOR_CLASS, SMALL_SHIELD, SHIELD_OF_REFLECTION }, { "helm", ARMOR_CLASS, ELVEN_LEATHER_HELM, HELM_OF_TELEPATHY }, { "gloves", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY }, { "gauntlets", ARMOR_CLASS, LEATHER_GLOVES, GAUNTLETS_OF_DEXTERITY }, { "boots", ARMOR_CLASS, LOW_BOOTS, LEVITATION_BOOTS }, { "shoes", ARMOR_CLASS, LOW_BOOTS, IRON_SHOES }, { "cloak", ARMOR_CLASS, MUMMY_WRAPPING, CLOAK_OF_DISPLACEMENT }, #ifdef TOURIST { "shirt", ARMOR_CLASS, HAWAIIAN_SHIRT, T_SHIRT }, #endif { "dragon scales", ARMOR_CLASS, GRAY_DRAGON_SCALES, YELLOW_DRAGON_SCALES }, { "dragon scale mail", ARMOR_CLASS, GRAY_DRAGON_SCALE_MAIL, YELLOW_DRAGON_SCALE_MAIL }, { "sword", WEAPON_CLASS, SHORT_SWORD, KATANA }, #ifdef WIZARD { "venom", VENOM_CLASS, BLINDING_VENOM, ACID_VENOM }, #endif { "gray stone", GEM_CLASS, LUCKSTONE, FLINT }, { "grey stone", GEM_CLASS, LUCKSTONE, FLINT }, }; #define BSTRCMP(base,ptr,string) ((ptr) < base || strcmp((ptr),string)) #define BSTRCMPI(base,ptr,string) ((ptr) < base || strcmpi((ptr),string)) #define BSTRNCMP(base,ptr,string,num) ((ptr)= bp+1 && p[-1] == 's') { if (p >= bp+2 && p[-2] == 'e') { if (p >= bp+3 && p[-3] == 'i') { if(!BSTRCMP(bp, p-7, "cookies") || !BSTRCMP(bp, p-4, "pies")) goto mins; Strcpy(p-3, "y"); return bp; } /* note: cloves / knives from clove / knife */ if(!BSTRCMP(bp, p-6, "knives")) { Strcpy(p-3, "fe"); return bp; } if(!BSTRCMP(bp, p-6, "staves")) { Strcpy(p-3, "ff"); return bp; } if (!BSTRCMPI(bp, p-6, "leaves")) { Strcpy(p-3, "f"); return bp; } if (!BSTRCMP(bp, p-8, "vortices")) { Strcpy(p-4, "ex"); return bp; } /* note: nurses, axes but boxes */ if (!BSTRCMP(bp, p-5, "boxes") || !BSTRCMP(bp, p-4, "ches")) { p[-2] = '\0'; return bp; } if (!BSTRCMP(bp, p-6, "gloves") || !BSTRCMP(bp, p-6, "lenses") || !BSTRCMP(bp, p-5, "shoes") || !BSTRCMP(bp, p-6, "scales")) return bp; } else if (!BSTRCMP(bp, p-5, "boots") || !BSTRCMP(bp, p-9, "gauntlets") || !BSTRCMP(bp, p-6, "tricks") || !BSTRCMP(bp, p-9, "paralysis") || !BSTRCMP(bp, p-5, "glass") || !BSTRCMP(bp, p-4, "ness") || !BSTRCMP(bp, p-14, "shape changers") || !BSTRCMP(bp, p-15, "detect monsters") || !BSTRCMPI(bp, p-11, "Aesculapius") || /* staff */ !BSTRCMP(bp, p-10, "eucalyptus") || #ifdef WIZARD !BSTRCMP(bp, p-9, "iron bars") || #endif !BSTRCMP(bp, p-5, "aklys") || !BSTRCMP(bp, p-6, "fungus")) return bp; mins: p[-1] = '\0'; } else { if(!BSTRCMP(bp, p-5, "teeth")) { Strcpy(p-5, "tooth"); return bp; } if (!BSTRCMP(bp, p-5, "fungi")) { Strcpy(p-5, "fungus"); return bp; } /* here we cannot find the plural suffix */ } return bp; } /* compare user string against object name string using fuzzy matching */ static boolean wishymatch(u_str, o_str, retry_inverted) const char *u_str; /* from user, so might be variant spelling */ const char *o_str; /* from objects[], so is in canonical form */ boolean retry_inverted; /* optional extra "of" handling */ { /* special case: wizards can wish for traps. The object is "beartrap" * and the trap is "bear trap", so to let wizards wish for both we * must not fuzzymatch. */ #ifdef WIZARD if (wizard && !strcmp(o_str, "beartrap")) return !strncmpi(o_str, u_str, 8); #endif /* ignore spaces & hyphens and upper/lower case when comparing */ if (fuzzymatch(u_str, o_str, " -", TRUE)) return TRUE; if (retry_inverted) { const char *u_of, *o_of; char *p, buf[BUFSZ]; /* when just one of the strings is in the form "foo of bar", convert it into "bar foo" and perform another comparison */ u_of = strstri(u_str, " of "); o_of = strstri(o_str, " of "); if (u_of && !o_of) { Strcpy(buf, u_of + 4); p = eos(strcat(buf, " ")); while (u_str < u_of) *p++ = *u_str++; *p = '\0'; return fuzzymatch(buf, o_str, " -", TRUE); } else if (o_of && !u_of) { Strcpy(buf, o_of + 4); p = eos(strcat(buf, " ")); while (o_str < o_of) *p++ = *o_str++; *p = '\0'; return fuzzymatch(u_str, buf, " -", TRUE); } } /* [note: if something like "elven speed boots" ever gets added, these special cases should be changed to call wishymatch() recursively in order to get the "of" inversion handling] */ if (!strncmp(o_str, "dwarvish ", 9)) { if (!strncmpi(u_str, "dwarven ", 8)) return fuzzymatch(u_str + 8, o_str + 9, " -", TRUE); } else if (!strncmp(o_str, "elven ", 6)) { if (!strncmpi(u_str, "elvish ", 7)) return fuzzymatch(u_str + 7, o_str + 6, " -", TRUE); else if (!strncmpi(u_str, "elfin ", 6)) return fuzzymatch(u_str + 6, o_str + 6, " -", TRUE); } else if (!strcmp(o_str, "aluminum")) { /* this special case doesn't really fit anywhere else... */ /* (note that " wand" will have been stripped off by now) */ if (!strcmpi(u_str, "aluminium")) return fuzzymatch(u_str + 9, o_str + 8, " -", TRUE); } return FALSE; } /* alternate spellings; if the difference is only the presence or absence of spaces and/or hyphens (such as "pickaxe" vs "pick axe" vs "pick-axe") then there is no need for inclusion in this list; likewise for ``"of" inversions'' ("boots of speed" vs "speed boots") */ struct alt_spellings { const char *sp; int ob; } spellings[] = { { "pickax", PICK_AXE }, { "whip", BULLWHIP }, { "saber", SILVER_SABER }, { "silver sabre", SILVER_SABER }, { "smooth shield", SHIELD_OF_REFLECTION }, { "grey dragon scale mail", GRAY_DRAGON_SCALE_MAIL }, { "grey dragon scales", GRAY_DRAGON_SCALES }, { "enchant armour", SCR_ENCHANT_ARMOR }, { "destroy armour", SCR_DESTROY_ARMOR }, { "scroll of enchant armour", SCR_ENCHANT_ARMOR }, { "scroll of destroy armour", SCR_DESTROY_ARMOR }, { "leather armour", LEATHER_ARMOR }, { "studded leather armour", STUDDED_LEATHER_ARMOR }, { "iron ball", HEAVY_IRON_BALL }, { "lantern", BRASS_LANTERN }, { "mattock", DWARVISH_MATTOCK }, { "amulet of poison resistance", AMULET_VERSUS_POISON }, { "stone", ROCK }, #ifdef TOURIST { "camera", EXPENSIVE_CAMERA }, { "tee shirt", T_SHIRT }, #endif { "can", TIN }, { "can opener", TIN_OPENER }, { "kelp", KELP_FROND }, { "eucalyptus", EUCALYPTUS_LEAF }, { "grapple", GRAPPLING_HOOK }, { (const char *)0, 0 }, }; /* * Return something wished for. Specifying a null pointer for * the user request string results in a random object. Otherwise, * if asking explicitly for "nothing" (or "nil") return no_wish; * if not an object return &zeroobj; if an error (no matching object), * return null. * If from_user is false, we're reading from the wizkit, nothing was typed in. */ struct obj * readobjnam(bp, no_wish, from_user) register char *bp; struct obj *no_wish; boolean from_user; { register char *p; register int i; register struct obj *otmp; int cnt, spe, spesgn, typ, very, rechrg; int blessed, uncursed, iscursed, ispoisoned, isgreased; int eroded, eroded2, erodeproof; #ifdef INVISIBLE_OBJECTS int isinvisible; #endif int halfeaten, mntmp, contents; int islit, unlabeled, ishistoric, isdiluted; struct fruit *f; int ftype = current_fruit; char fruitbuf[BUFSZ]; /* Fruits may not mess up the ability to wish for real objects (since * you can leave a fruit in a bones file and it will be added to * another person's game), so they must be checked for last, after * stripping all the possible prefixes and seeing if there's a real * name in there. So we have to save the full original name. However, * it's still possible to do things like "uncursed burnt Alaska", * or worse yet, "2 burned 5 course meals", so we need to loop to * strip off the prefixes again, this time stripping only the ones * possible on food. * We could get even more detailed so as to allow food names with * prefixes that _are_ possible on food, so you could wish for * "2 3 alarm chilis". Currently this isn't allowed; options.c * automatically sticks 'candied' in front of such names. */ char oclass; char *un, *dn, *actualn; const char *name=0; cnt = spe = spesgn = typ = very = rechrg = blessed = uncursed = iscursed = #ifdef INVISIBLE_OBJECTS isinvisible = #endif ispoisoned = isgreased = eroded = eroded2 = erodeproof = halfeaten = islit = unlabeled = ishistoric = isdiluted = 0; mntmp = NON_PM; #define UNDEFINED 0 #define EMPTY 1 #define SPINACH 2 contents = UNDEFINED; oclass = 0; actualn = dn = un = 0; if (!bp) goto any; /* first, remove extra whitespace they may have typed */ (void)mungspaces(bp); /* allow wishing for "nothing" to preserve wishless conduct... [now requires "wand of nothing" if that's what was really wanted] */ if (!strcmpi(bp, "nothing") || !strcmpi(bp, "nil") || !strcmpi(bp, "none")) return no_wish; /* save the [nearly] unmodified choice string */ Strcpy(fruitbuf, bp); for(;;) { register int l; if (!bp || !*bp) goto any; if (!strncmpi(bp, "an ", l=3) || !strncmpi(bp, "a ", l=2)) { cnt = 1; } else if (!strncmpi(bp, "the ", l=4)) { ; /* just increment `bp' by `l' below */ } else if (!cnt && digit(*bp) && strcmp(bp, "0")) { cnt = atoi(bp); while(digit(*bp)) bp++; while(*bp == ' ') bp++; l = 0; } else if (*bp == '+' || *bp == '-') { spesgn = (*bp++ == '+') ? 1 : -1; spe = atoi(bp); while(digit(*bp)) bp++; while(*bp == ' ') bp++; l = 0; } else if (!strncmpi(bp, "blessed ", l=8) || !strncmpi(bp, "holy ", l=5)) { blessed = 1; } else if (!strncmpi(bp, "cursed ", l=7) || !strncmpi(bp, "unholy ", l=7)) { iscursed = 1; } else if (!strncmpi(bp, "uncursed ", l=9)) { uncursed = 1; #ifdef INVISIBLE_OBJECTS } else if (!strncmpi(bp, "invisible ", l=10)) { isinvisible = 1; #endif } else if (!strncmpi(bp, "rustproof ", l=10) || !strncmpi(bp, "erodeproof ", l=11) || !strncmpi(bp, "corrodeproof ", l=13) || !strncmpi(bp, "fixed ", l=6) || !strncmpi(bp, "fireproof ", l=10) || !strncmpi(bp, "rotproof ", l=9)) { erodeproof = 1; } else if (!strncmpi(bp,"lit ", l=4) || !strncmpi(bp,"burning ", l=8)) { islit = 1; } else if (!strncmpi(bp,"unlit ", l=6) || !strncmpi(bp,"extinguished ", l=13)) { islit = 0; /* "unlabeled" and "blank" are synonymous */ } else if (!strncmpi(bp,"unlabeled ", l=10) || !strncmpi(bp,"unlabelled ", l=11) || !strncmpi(bp,"blank ", l=6)) { unlabeled = 1; } else if(!strncmpi(bp, "poisoned ",l=9) #ifdef WIZARD || (wizard && !strncmpi(bp, "trapped ",l=8)) #endif ) { ispoisoned=1; } else if(!strncmpi(bp, "greased ",l=8)) { isgreased=1; } else if (!strncmpi(bp, "very ", l=5)) { /* very rusted very heavy iron ball */ very = 1; } else if (!strncmpi(bp, "thoroughly ", l=11)) { very = 2; } else if (!strncmpi(bp, "rusty ", l=6) || !strncmpi(bp, "rusted ", l=7) || !strncmpi(bp, "burnt ", l=6) || !strncmpi(bp, "burned ", l=7)) { eroded = 1 + very; very = 0; } else if (!strncmpi(bp, "corroded ", l=9) || !strncmpi(bp, "rotted ", l=7)) { eroded2 = 1 + very; very = 0; } else if (!strncmpi(bp, "partly eaten ", l=13)) { halfeaten = 1; } else if (!strncmpi(bp, "historic ", l=9)) { ishistoric = 1; } else if (!strncmpi(bp, "diluted ", l=8)) { isdiluted = 1; } else if(!strncmpi(bp, "empty ", l=6)) { contents = EMPTY; } else break; bp += l; } if(!cnt) cnt = 1; /* %% what with "gems" etc. ? */ if (strlen(bp) > 1) { if ((p = rindex(bp, '(')) != 0) { if (p > bp && p[-1] == ' ') p[-1] = 0; else *p = 0; p++; if (!strcmpi(p, "lit)")) { islit = 1; } else { spe = atoi(p); while (digit(*p)) p++; if (*p == ':') { p++; rechrg = spe; spe = atoi(p); while (digit(*p)) p++; } if (*p != ')') { spe = rechrg = 0; } else { spesgn = 1; p++; if (*p) Strcat(bp, p); } } } } /* otmp->spe is type schar; so we don't want spe to be any bigger or smaller. also, spe should always be positive -- some cheaters may try to confuse atoi() */ if (spe < 0) { spesgn = -1; /* cheaters get what they deserve */ spe = abs(spe); } if (spe > SCHAR_LIM) spe = SCHAR_LIM; if (rechrg < 0 || rechrg > 7) rechrg = 7; /* recharge_limit */ /* now we have the actual name, as delivered by xname, say green potions called whisky scrolls labeled "QWERTY" egg fortune cookies very heavy iron ball named hoei wand of wishing elven cloak */ if ((p = strstri(bp, " named ")) != 0) { *p = 0; name = p+7; } if ((p = strstri(bp, " called ")) != 0) { *p = 0; un = p+8; /* "helmet called telepathy" is not "helmet" (a specific type) * "shield called reflection" is not "shield" (a general type) */ for(i = 0; i < SIZE(o_ranges); i++) if(!strcmpi(bp, o_ranges[i].name)) { oclass = o_ranges[i].oclass; goto srch; } } if ((p = strstri(bp, " labeled ")) != 0) { *p = 0; dn = p+9; } else if ((p = strstri(bp, " labelled ")) != 0) { *p = 0; dn = p+10; } if ((p = strstri(bp, " of spinach")) != 0) { *p = 0; contents = SPINACH; } /* Skip over "pair of ", "pairs of", "set of" and "sets of". Accept "3 pair of boots" as well as "3 pairs of boots". It is valid English either way. See makeplural() for more on pair/pairs. We should only double count if the object in question is not refered to as a "pair of". E.g. We should double if the player types "pair of spears", but not if the player types "pair of lenses". Luckily (?) all objects that are refered to as pairs -- boots, gloves, and lenses -- are also not mergable, so cnt is ignored anyway. */ if(!strncmpi(bp, "pair of ",8)) { bp += 8; cnt *= 2; } else if(cnt > 1 && !strncmpi(bp, "pairs of ",9)) { bp += 9; cnt *= 2; } else if (!strncmpi(bp, "set of ",7)) { bp += 7; } else if (!strncmpi(bp, "sets of ",8)) { bp += 8; } /* * Find corpse type using "of" (figurine of an orc, tin of orc meat) * Don't check if it's a wand or spellbook. * (avoid "wand/finger of death" confusion). */ if (!strstri(bp, "wand ") && !strstri(bp, "spellbook ") && !strstri(bp, "finger ")) { if ((p = strstri(bp, " of ")) != 0 && (mntmp = name_to_mon(p+4)) >= LOW_PM) *p = 0; } /* Find corpse type w/o "of" (red dragon scale mail, yeti corpse) */ if (strncmpi(bp, "samurai sword", 13)) /* not the "samurai" monster! */ if (strncmpi(bp, "wizard lock", 11)) /* not the "wizard" monster! */ if (strncmpi(bp, "ninja-to", 8)) /* not the "ninja" rank */ if (strncmpi(bp, "master key", 10)) /* not the "master" rank */ if (strncmpi(bp, "magenta", 7)) /* not the "mage" rank */ if (mntmp < LOW_PM && strlen(bp) > 2 && (mntmp = name_to_mon(bp)) >= LOW_PM) { int mntmptoo, mntmplen; /* double check for rank title */ char *obp = bp; mntmptoo = title_to_mon(bp, (int *)0, &mntmplen); bp += mntmp != mntmptoo ? (int)strlen(mons[mntmp].mname) : mntmplen; if (*bp == ' ') bp++; else if (!strncmpi(bp, "s ", 2)) bp += 2; else if (!strncmpi(bp, "es ", 3)) bp += 3; else if (!*bp && !actualn && !dn && !un && !oclass) { /* no referent; they don't really mean a monster type */ bp = obp; mntmp = NON_PM; } } /* first change to singular if necessary */ if (*bp) { char *sng = makesingular(bp); if (strcmp(bp, sng)) { if (cnt == 1) cnt = 2; Strcpy(bp, sng); } } /* Alternate spellings (pick-ax, silver sabre, &c) */ { struct alt_spellings *as = spellings; while (as->sp) { if (fuzzymatch(bp, as->sp, " -", TRUE)) { typ = as->ob; goto typfnd; } as++; } /* can't use spellings list for this one due to shuffling */ if (!strncmpi(bp, "grey spell", 10)) *(bp + 2) = 'a'; } /* dragon scales - assumes order of dragons */ if(!strcmpi(bp, "scales") && mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) { typ = GRAY_DRAGON_SCALES + mntmp - PM_GRAY_DRAGON; mntmp = NON_PM; /* no monster */ goto typfnd; } p = eos(bp); if(!BSTRCMPI(bp, p-10, "holy water")) { typ = POT_WATER; if ((p-bp) >= 12 && *(p-12) == 'u') iscursed = 1; /* unholy water */ else blessed = 1; goto typfnd; } if(unlabeled && !BSTRCMPI(bp, p-6, "scroll")) { typ = SCR_BLANK_PAPER; goto typfnd; } if(unlabeled && !BSTRCMPI(bp, p-9, "spellbook")) { typ = SPE_BLANK_PAPER; goto typfnd; } /* * NOTE: Gold pieces are handled as objects nowadays, and therefore * this section should probably be reconsidered as well as the entire * gold/money concept. Maybe we want to add other monetary units as * well in the future. (TH) */ if(!BSTRCMPI(bp, p-10, "gold piece") || !BSTRCMPI(bp, p-7, "zorkmid") || !strcmpi(bp, "gold") || !strcmpi(bp, "money") || !strcmpi(bp, "coin") || *bp == GOLD_SYM) { if (cnt > 5000 #ifdef WIZARD && !wizard #endif ) cnt=5000; if (cnt < 1) cnt=1; #ifndef GOLDOBJ if (from_user) pline("%d gold piece%s.", cnt, plur(cnt)); u.ugold += cnt; flags.botl=1; return (&zeroobj); #else otmp = mksobj(GOLD_PIECE, FALSE, FALSE); otmp->quan = cnt; otmp->owt = weight(otmp); flags.botl=1; return (otmp); #endif } if (strlen(bp) == 1 && (i = def_char_to_objclass(*bp)) < MAXOCLASSES && i > ILLOBJ_CLASS #ifdef WIZARD && (wizard || i != VENOM_CLASS) #else && i != VENOM_CLASS #endif ) { oclass = i; goto any; } /* Search for class names: XXXXX potion, scroll of XXXXX. Avoid */ /* false hits on, e.g., rings for "ring mail". */ if(strncmpi(bp, "enchant ", 8) && strncmpi(bp, "destroy ", 8) && strncmpi(bp, "food detection", 14) && strncmpi(bp, "ring mail", 9) && strncmpi(bp, "studded leather arm", 19) && strncmpi(bp, "leather arm", 11) && strncmpi(bp, "tooled horn", 11) && strncmpi(bp, "food ration", 11) && strncmpi(bp, "meat ring", 9) ) for (i = 0; i < (int)(sizeof wrpsym); i++) { register int j = strlen(wrp[i]); if(!strncmpi(bp, wrp[i], j)){ oclass = wrpsym[i]; if(oclass != AMULET_CLASS) { bp += j; if(!strncmpi(bp, " of ", 4)) actualn = bp+4; /* else if(*bp) ?? */ } else actualn = bp; goto srch; } if(!BSTRCMPI(bp, p-j, wrp[i])){ oclass = wrpsym[i]; p -= j; *p = 0; if(p > bp && p[-1] == ' ') p[-1] = 0; actualn = dn = bp; goto srch; } } /* "grey stone" check must be before general "stone" */ for (i = 0; i < SIZE(o_ranges); i++) if(!strcmpi(bp, o_ranges[i].name)) { typ = rnd_class(o_ranges[i].f_o_range, o_ranges[i].l_o_range); goto typfnd; } if (!BSTRCMPI(bp, p-6, " stone")) { p[-6] = 0; oclass = GEM_CLASS; dn = actualn = bp; goto srch; } else if (!strcmpi(bp, "looking glass")) { ; /* avoid false hit on "* glass" */ } else if (!BSTRCMPI(bp, p-6, " glass") || !strcmpi(bp, "glass")) { register char *g = bp; if (strstri(g, "broken")) return (struct obj *)0; if (!strncmpi(g, "worthless ", 10)) g += 10; if (!strncmpi(g, "piece of ", 9)) g += 9; if (!strncmpi(g, "colored ", 8)) g += 8; else if (!strncmpi(g, "coloured ", 9)) g += 9; if (!strcmpi(g, "glass")) { /* choose random color */ /* 9 different kinds */ typ = LAST_GEM + rnd(9); if (objects[typ].oc_class == GEM_CLASS) goto typfnd; else typ = 0; /* somebody changed objects[]? punt */ } else { /* try to construct canonical form */ char tbuf[BUFSZ]; Strcpy(tbuf, "worthless piece of "); Strcat(tbuf, g); /* assume it starts with the color */ Strcpy(bp, tbuf); } } actualn = bp; if (!dn) dn = actualn; /* ex. "skull cap" */ srch: /* check real names of gems first */ if(!oclass && actualn) { for(i = bases[GEM_CLASS]; i <= LAST_GEM; i++) { register const char *zn; if((zn = OBJ_NAME(objects[i])) && !strcmpi(actualn, zn)) { typ = i; goto typfnd; } } } i = oclass ? bases[(int)oclass] : 1; while(i < NUM_OBJECTS && (!oclass || objects[i].oc_class == oclass)){ register const char *zn; if (actualn && (zn = OBJ_NAME(objects[i])) != 0 && wishymatch(actualn, zn, TRUE)) { typ = i; goto typfnd; } if (dn && (zn = OBJ_DESCR(objects[i])) != 0 && wishymatch(dn, zn, FALSE)) { /* don't match extra descriptions (w/o real name) */ if (!OBJ_NAME(objects[i])) return (struct obj *)0; typ = i; goto typfnd; } if (un && (zn = objects[i].oc_uname) != 0 && wishymatch(un, zn, FALSE)) { typ = i; goto typfnd; } i++; } if (actualn) { struct Jitem *j = Japanese_items; while(j->item) { if (actualn && !strcmpi(actualn, j->name)) { typ = j->item; goto typfnd; } j++; } } if (!strcmpi(bp, "spinach")) { contents = SPINACH; typ = TIN; goto typfnd; } /* Note: not strncmpi. 2 fruits, one capital, one not, are possible. */ { char *fp; int l, cntf; int blessedf, iscursedf, uncursedf, halfeatenf; blessedf = iscursedf = uncursedf = halfeatenf = 0; cntf = 0; fp = fruitbuf; for(;;) { if (!fp || !*fp) break; if (!strncmpi(fp, "an ", l=3) || !strncmpi(fp, "a ", l=2)) { cntf = 1; } else if (!cntf && digit(*fp)) { cntf = atoi(fp); while(digit(*fp)) fp++; while(*fp == ' ') fp++; l = 0; } else if (!strncmpi(fp, "blessed ", l=8)) { blessedf = 1; } else if (!strncmpi(fp, "cursed ", l=7)) { iscursedf = 1; } else if (!strncmpi(fp, "uncursed ", l=9)) { uncursedf = 1; } else if (!strncmpi(fp, "partly eaten ", l=13)) { halfeatenf = 1; } else break; fp += l; } for(f=ffruit; f; f = f->nextf) { char *f1 = f->fname, *f2 = makeplural(f->fname); if(!strncmp(fp, f1, strlen(f1)) || !strncmp(fp, f2, strlen(f2))) { typ = SLIME_MOLD; blessed = blessedf; iscursed = iscursedf; uncursed = uncursedf; halfeaten = halfeatenf; cnt = cntf; ftype = f->fid; goto typfnd; } } } if(!oclass && actualn) { short objtyp; /* Perhaps it's an artifact specified by name, not type */ name = artifact_name(actualn, &objtyp); if(name) { typ = objtyp; goto typfnd; } } #ifdef WIZARD /* Let wizards wish for traps --KAA */ /* must come after objects check so wizards can still wish for * trap objects like beartraps */ if (wizard && from_user) { int trap; for (trap = NO_TRAP+1; trap < TRAPNUM; trap++) { const char *tname; tname = defsyms[trap_to_defsym(trap)].explanation; if (!strncmpi(tname, bp, strlen(tname))) { /* avoid stupid mistakes */ if((trap == TRAPDOOR || trap == HOLE) && !Can_fall_thru(&u.uz)) trap = ROCKTRAP; (void) maketrap(u.ux, u.uy, trap); pline("%s.", An(tname)); return(&zeroobj); } } /* or some other dungeon features -dlc */ p = eos(bp); if(!BSTRCMP(bp, p-8, "fountain")) { levl[u.ux][u.uy].typ = FOUNTAIN; level.flags.nfountains++; if(!strncmpi(bp, "magic ", 6)) levl[u.ux][u.uy].blessedftn = 1; pline("A %sfountain.", levl[u.ux][u.uy].blessedftn ? "magic " : ""); newsym(u.ux, u.uy); return(&zeroobj); } if(!BSTRCMP(bp, p-6, "throne")) { levl[u.ux][u.uy].typ = THRONE; pline("A throne."); newsym(u.ux, u.uy); return(&zeroobj); } # ifdef SINKS if(!BSTRCMP(bp, p-4, "sink")) { levl[u.ux][u.uy].typ = SINK; level.flags.nsinks++; pline("A sink."); newsym(u.ux, u.uy); return &zeroobj; } # endif if(!BSTRCMP(bp, p-4, "pool")) { levl[u.ux][u.uy].typ = POOL; del_engr_at(u.ux, u.uy); pline("A pool."); /* Must manually make kelp! */ water_damage(level.objects[u.ux][u.uy], FALSE, TRUE); newsym(u.ux, u.uy); return &zeroobj; } if (!BSTRCMP(bp, p-4, "lava")) { /* also matches "molten lava" */ levl[u.ux][u.uy].typ = LAVAPOOL; del_engr_at(u.ux, u.uy); pline("A pool of molten lava."); if (!(Levitation || Flying)) (void) lava_effects(); newsym(u.ux, u.uy); return &zeroobj; } if(!BSTRCMP(bp, p-5, "altar")) { aligntyp al; levl[u.ux][u.uy].typ = ALTAR; if(!strncmpi(bp, "chaotic ", 8)) al = A_CHAOTIC; else if(!strncmpi(bp, "neutral ", 8)) al = A_NEUTRAL; else if(!strncmpi(bp, "lawful ", 7)) al = A_LAWFUL; else if(!strncmpi(bp, "unaligned ", 10)) al = A_NONE; else /* -1 - A_CHAOTIC, 0 - A_NEUTRAL, 1 - A_LAWFUL */ al = (!rn2(6)) ? A_NONE : rn2((int)A_LAWFUL+2) - 1; levl[u.ux][u.uy].altarmask = Align2amask( al ); pline("%s altar.", An(align_str(al))); newsym(u.ux, u.uy); return(&zeroobj); } if(!BSTRCMP(bp, p-5, "grave") || !BSTRCMP(bp, p-9, "headstone")) { make_grave(u.ux, u.uy, (char *) 0); pline("A grave."); newsym(u.ux, u.uy); return(&zeroobj); } if(!BSTRCMP(bp, p-4, "tree")) { levl[u.ux][u.uy].typ = TREE; pline("A tree."); newsym(u.ux, u.uy); block_point(u.ux, u.uy); return &zeroobj; } if(!BSTRCMP(bp, p-4, "bars")) { levl[u.ux][u.uy].typ = IRONBARS; pline("Iron bars."); newsym(u.ux, u.uy); return &zeroobj; } } #endif if(!oclass) return((struct obj *)0); any: if(!oclass) oclass = wrpsym[rn2((int)sizeof(wrpsym))]; typfnd: if (typ) oclass = objects[typ].oc_class; /* check for some objects that are not allowed */ if (typ && objects[typ].oc_unique) { #ifdef WIZARD if (wizard) ; /* allow unique objects */ else #endif switch (typ) { case AMULET_OF_YENDOR: typ = FAKE_AMULET_OF_YENDOR; break; case CANDELABRUM_OF_INVOCATION: typ = rnd_class(TALLOW_CANDLE, WAX_CANDLE); break; case BELL_OF_OPENING: typ = BELL; break; case SPE_BOOK_OF_THE_DEAD: typ = SPE_BLANK_PAPER; break; } } /* catch any other non-wishable objects */ if (objects[typ].oc_nowish #ifdef WIZARD && !wizard #endif ) return((struct obj *)0); /* convert magic lamps to regular lamps before lighting them or setting the charges */ if (typ == MAGIC_LAMP #ifdef WIZARD && !wizard #endif ) typ = OIL_LAMP; if(typ) { otmp = mksobj(typ, TRUE, FALSE); } else { otmp = mkobj(oclass, FALSE); if (otmp) typ = otmp->otyp; } if (islit && (typ == OIL_LAMP || typ == MAGIC_LAMP || typ == BRASS_LANTERN || Is_candle(otmp) || typ == POT_OIL)) { place_object(otmp, u.ux, u.uy); /* make it viable light source */ begin_burn(otmp, FALSE); obj_extract_self(otmp); /* now release it for caller's use */ } if(cnt > 0 && objects[typ].oc_merge && oclass != SPBOOK_CLASS && (cnt < rnd(6) || #ifdef WIZARD wizard || #endif (cnt <= 7 && Is_candle(otmp)) || (cnt <= 20 && ((oclass == WEAPON_CLASS && is_ammo(otmp)) || typ == ROCK || is_missile(otmp))))) otmp->quan = (long) cnt; #ifdef WIZARD if (oclass == VENOM_CLASS) otmp->spe = 1; #endif if (spesgn == 0) spe = otmp->spe; #ifdef WIZARD else if (wizard) /* no alteration to spe */ ; #endif else if (oclass == ARMOR_CLASS || oclass == WEAPON_CLASS || is_weptool(otmp) || (oclass==RING_CLASS && objects[typ].oc_charged)) { if(spe > rnd(5) && spe > otmp->spe) spe = 0; if(spe > 2 && Luck < 0) spesgn = -1; } else { if (oclass == WAND_CLASS) { if (spe > 1 && spesgn == -1) spe = 1; } else { if (spe > 0 && spesgn == -1) spe = 0; } if (spe > otmp->spe) spe = otmp->spe; } if (spesgn == -1) spe = -spe; /* set otmp->spe. This may, or may not, use spe... */ switch (typ) { case TIN: if (contents==EMPTY) { otmp->corpsenm = NON_PM; otmp->spe = 0; } else if (contents==SPINACH) { otmp->corpsenm = NON_PM; otmp->spe = 1; } break; case SLIME_MOLD: otmp->spe = ftype; /* Fall through */ case SKELETON_KEY: case CHEST: case LARGE_BOX: case HEAVY_IRON_BALL: case IRON_CHAIN: case STATUE: /* otmp->cobj already done in mksobj() */ break; #ifdef MAIL case SCR_MAIL: otmp->spe = 1; break; #endif case WAN_WISHING: #ifdef WIZARD if (!wizard) { #endif otmp->spe = (rn2(10) ? -1 : 0); break; #ifdef WIZARD } /* fall through, if wizard */ #endif default: otmp->spe = spe; } /* set otmp->corpsenm or dragon scale [mail] */ if (mntmp >= LOW_PM) { if (mntmp == PM_LONG_WORM_TAIL) mntmp = PM_LONG_WORM; switch (typ) { case TIN: otmp->spe = 0; /* No spinach */ if (dead_species(mntmp, FALSE)) { otmp->corpsenm = NON_PM; /* it's empty */ } else if (!(mons[mntmp].geno & G_UNIQ) && !(mvitals[mntmp].mvflags & G_NOCORPSE) && mons[mntmp].cnutrit != 0) { otmp->corpsenm = mntmp; } break; case CORPSE: if (!(mons[mntmp].geno & G_UNIQ) && !(mvitals[mntmp].mvflags & G_NOCORPSE)) { /* beware of random troll or lizard corpse, or of ordinary one being forced to such */ if (otmp->timed) obj_stop_timers(otmp); if (mons[mntmp].msound == MS_GUARDIAN) otmp->corpsenm = genus(mntmp,1); else otmp->corpsenm = mntmp; start_corpse_timeout(otmp); } break; case FIGURINE: if (!(mons[mntmp].geno & G_UNIQ) && !is_human(&mons[mntmp]) #ifdef MAIL && mntmp != PM_MAIL_DAEMON #endif ) otmp->corpsenm = mntmp; break; case EGG: mntmp = can_be_hatched(mntmp); if (mntmp != NON_PM) { otmp->corpsenm = mntmp; if (!dead_species(mntmp, TRUE)) attach_egg_hatch_timeout(otmp); else kill_egg(otmp); } break; case STATUE: otmp->corpsenm = mntmp; if (Has_contents(otmp) && verysmall(&mons[mntmp])) delete_contents(otmp); /* no spellbook */ otmp->spe = ishistoric ? STATUE_HISTORIC : 0; break; case SCALE_MAIL: /* Dragon mail - depends on the order of objects */ /* & dragons. */ if (mntmp >= PM_GRAY_DRAGON && mntmp <= PM_YELLOW_DRAGON) otmp->otyp = GRAY_DRAGON_SCALE_MAIL + mntmp - PM_GRAY_DRAGON; break; } } /* set blessed/cursed -- setting the fields directly is safe * since weight() is called below and addinv() will take care * of luck */ if (iscursed) { curse(otmp); } else if (uncursed) { otmp->blessed = 0; otmp->cursed = (Luck < 0 #ifdef WIZARD && !wizard #endif ); } else if (blessed) { otmp->blessed = (Luck >= 0 #ifdef WIZARD || wizard #endif ); otmp->cursed = (Luck < 0 #ifdef WIZARD && !wizard #endif ); } else if (spesgn < 0) { curse(otmp); } #ifdef INVISIBLE_OBJECTS if (isinvisible) otmp->oinvis = 1; #endif /* set eroded */ if (is_damageable(otmp) || otmp->otyp == CRYSKNIFE) { if (eroded && (is_flammable(otmp) || is_rustprone(otmp))) otmp->oeroded = eroded; if (eroded2 && (is_corrodeable(otmp) || is_rottable(otmp))) otmp->oeroded2 = eroded2; /* set erodeproof */ if (erodeproof && !eroded && !eroded2) otmp->oerodeproof = (Luck >= 0 #ifdef WIZARD || wizard #endif ); } /* set otmp->recharged */ if (oclass == WAND_CLASS) { /* prevent wishing abuse */ if (otmp->otyp == WAN_WISHING #ifdef WIZARD && !wizard #endif ) rechrg = 1; otmp->recharged = (unsigned)rechrg; } /* set poisoned */ if (ispoisoned) { if (is_poisonable(otmp)) otmp->opoisoned = (Luck >= 0); else if (Is_box(otmp) || typ == TIN) otmp->otrapped = 1; else if (oclass == FOOD_CLASS) /* try to taint by making it as old as possible */ otmp->age = 1L; } if (isgreased) otmp->greased = 1; if (isdiluted && otmp->oclass == POTION_CLASS && otmp->otyp != POT_WATER) otmp->odiluted = 1; if (name) { const char *aname; short objtyp; /* an artifact name might need capitalization fixing */ aname = artifact_name(name, &objtyp); if (aname && objtyp == otmp->otyp) name = aname; otmp = oname(otmp, name); if (otmp->oartifact) { otmp->quan = 1L; u.uconduct.wisharti++; /* KMH, conduct */ } } /* more wishing abuse: don't allow wishing for certain artifacts */ /* and make them pay; charge them for the wish anyway! */ if ((is_quest_artifact(otmp) || (otmp->oartifact && rn2(nartifact_exist()) > 1)) #ifdef WIZARD && !wizard #endif ) { artifact_exists(otmp, ONAME(otmp), FALSE); obfree(otmp, (struct obj *) 0); otmp = &zeroobj; pline("For a moment, you feel %s in your %s, but it disappears!", something, makeplural(body_part(HAND))); } if (halfeaten && otmp->oclass == FOOD_CLASS) { if (otmp->otyp == CORPSE) otmp->oeaten = mons[otmp->corpsenm].cnutrit; else otmp->oeaten = objects[otmp->otyp].oc_nutrition; /* (do this adjustment before setting up object's weight) */ consume_oeaten(otmp, 1); } otmp->owt = weight(otmp); if (very && otmp->otyp == HEAVY_IRON_BALL) otmp->owt += 160; return(otmp); } int rnd_class(first,last) int first,last; { int i, x, sum=0; if (first == last) return (first); for(i=first; i<=last; i++) sum += objects[i].oc_prob; if (!sum) /* all zero */ return first + rn2(last-first+1); x = rnd(sum); for(i=first; i<=last; i++) if (objects[i].oc_prob && (x -= objects[i].oc_prob) <= 0) return i; return 0; } STATIC_OVL const char * Japanese_item_name(i) int i; { struct Jitem *j = Japanese_items; while(j->item) { if (i == j->item) return j->name; j++; } return (const char *)0; } const char * cloak_simple_name(cloak) struct obj *cloak; { if (cloak) { switch (cloak->otyp) { case ROBE: return "robe"; case MUMMY_WRAPPING: return "wrapping"; case ALCHEMY_SMOCK: return (objects[cloak->otyp].oc_name_known && cloak->dknown) ? "smock" : "apron"; default: break; } } return "cloak"; } const char * mimic_obj_name(mtmp) struct monst *mtmp; { if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance != STRANGE_OBJECT) { int idx = objects[mtmp->mappearance].oc_descr_idx; if (mtmp->mappearance == GOLD_PIECE) return "gold"; return obj_descr[idx].oc_name; } return "whatcha-may-callit"; } #endif /* OVLB */ /*objnam.c*/ nethack-3.4.3/src/options.c0100644000000000000000000033501207764735041014304 0ustar rootroot/* SCCS Id: @(#)options.c 3.4 2003/11/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #ifdef OPTION_LISTS_ONLY /* (AMIGA) external program for opt lists */ #include "config.h" #include "objclass.h" #include "flag.h" NEARDATA struct flag flags; /* provide linkage */ NEARDATA struct instance_flags iflags; /* provide linkage */ #define static #else #include "hack.h" #include "tcap.h" #include #endif #define WINTYPELEN 16 #ifdef DEFAULT_WC_TILED_MAP #define PREFER_TILED TRUE #else #define PREFER_TILED FALSE #endif /* * NOTE: If you add (or delete) an option, please update the short * options help (option_help()), the long options help (dat/opthelp), * and the current options setting display function (doset()), * and also the Guidebooks. * * The order matters. If an option is a an initial substring of another * option (e.g. time and timed_delay) the shorter one must come first. */ static struct Bool_Opt { const char *name; boolean *addr, initvalue; int optflags; } boolopt[] = { #ifdef AMIGA {"altmeta", &flags.altmeta, TRUE, DISP_IN_GAME}, #else {"altmeta", (boolean *)0, TRUE, DISP_IN_GAME}, #endif {"ascii_map", &iflags.wc_ascii_map, !PREFER_TILED, SET_IN_GAME}, /*WC*/ #ifdef MFLOPPY {"asksavedisk", &flags.asksavedisk, FALSE, SET_IN_GAME}, #else {"asksavedisk", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"autodig", &flags.autodig, FALSE, SET_IN_GAME}, {"autopickup", &flags.pickup, TRUE, SET_IN_GAME}, {"autoquiver", &flags.autoquiver, FALSE, SET_IN_GAME}, #if defined(MICRO) && !defined(AMIGA) {"BIOS", &iflags.BIOS, FALSE, SET_IN_FILE}, #else {"BIOS", (boolean *)0, FALSE, SET_IN_FILE}, #endif #ifdef INSURANCE {"checkpoint", &flags.ins_chkpt, TRUE, SET_IN_GAME}, #else {"checkpoint", (boolean *)0, FALSE, SET_IN_FILE}, #endif #ifdef MFLOPPY {"checkspace", &iflags.checkspace, TRUE, SET_IN_GAME}, #else {"checkspace", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"cmdassist", &iflags.cmdassist, TRUE, SET_IN_GAME}, # if defined(MICRO) || defined(WIN32) {"color", &iflags.wc_color,TRUE, SET_IN_GAME}, /*WC*/ # else /* systems that support multiple terminals, many monochrome */ {"color", &iflags.wc_color, FALSE, SET_IN_GAME}, /*WC*/ # endif {"confirm",&flags.confirm, TRUE, SET_IN_GAME}, #if defined(TERMLIB) && !defined(MAC_GRAPHICS_ENV) {"DECgraphics", &iflags.DECgraphics, FALSE, SET_IN_GAME}, #else {"DECgraphics", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"eight_bit_tty", &iflags.wc_eight_bit_input, FALSE, SET_IN_GAME}, /*WC*/ #ifdef TTY_GRAPHICS {"extmenu", &iflags.extmenu, FALSE, SET_IN_GAME}, #else {"extmenu", (boolean *)0, FALSE, SET_IN_FILE}, #endif #ifdef OPT_DISPMAP {"fast_map", &flags.fast_map, TRUE, SET_IN_GAME}, #else {"fast_map", (boolean *)0, TRUE, SET_IN_FILE}, #endif {"female", &flags.female, FALSE, DISP_IN_GAME}, {"fixinv", &flags.invlet_constant, TRUE, SET_IN_GAME}, #ifdef AMIFLUSH {"flush", &flags.amiflush, FALSE, SET_IN_GAME}, #else {"flush", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"fullscreen", &iflags.wc2_fullscreen, FALSE, SET_IN_FILE}, {"help", &flags.help, TRUE, SET_IN_GAME}, {"hilite_pet", &iflags.wc_hilite_pet, FALSE, SET_IN_GAME}, /*WC*/ #ifdef ASCIIGRAPH {"IBMgraphics", &iflags.IBMgraphics, FALSE, SET_IN_GAME}, #else {"IBMgraphics", (boolean *)0, FALSE, SET_IN_FILE}, #endif #ifndef MAC {"ignintr", &flags.ignintr, FALSE, SET_IN_GAME}, #else {"ignintr", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"large_font", &iflags.obsolete, FALSE, SET_IN_FILE}, /* OBSOLETE */ {"legacy", &flags.legacy, TRUE, DISP_IN_GAME}, {"lit_corridor", &flags.lit_corridor, FALSE, SET_IN_GAME}, {"lootabc", &iflags.lootabc, FALSE, SET_IN_GAME}, #ifdef MAC_GRAPHICS_ENV {"Macgraphics", &iflags.MACgraphics, TRUE, SET_IN_GAME}, #else {"Macgraphics", (boolean *)0, FALSE, SET_IN_FILE}, #endif #ifdef MAIL {"mail", &flags.biff, TRUE, SET_IN_GAME}, #else {"mail", (boolean *)0, TRUE, SET_IN_FILE}, #endif #ifdef WIZARD /* for menu debugging only*/ {"menu_tab_sep", &iflags.menu_tab_sep, FALSE, SET_IN_GAME}, #else {"menu_tab_sep", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"mouse_support", &iflags.wc_mouse_support, TRUE, DISP_IN_GAME}, /*WC*/ #ifdef NEWS {"news", &iflags.news, TRUE, DISP_IN_GAME}, #else {"news", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"null", &flags.null, TRUE, SET_IN_GAME}, #ifdef MAC {"page_wait", &flags.page_wait, TRUE, SET_IN_GAME}, #else {"page_wait", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"perm_invent", &flags.perm_invent, FALSE, SET_IN_GAME}, {"popup_dialog", &iflags.wc_popup_dialog, FALSE, SET_IN_GAME}, /*WC*/ {"prayconfirm", &flags.prayconfirm, TRUE, SET_IN_GAME}, {"preload_tiles", &iflags.wc_preload_tiles, TRUE, DISP_IN_GAME}, /*WC*/ {"pushweapon", &flags.pushweapon, FALSE, SET_IN_GAME}, #if defined(MICRO) && !defined(AMIGA) {"rawio", &iflags.rawio, FALSE, DISP_IN_GAME}, #else {"rawio", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"rest_on_space", &flags.rest_on_space, FALSE, SET_IN_GAME}, {"safe_pet", &flags.safe_dog, TRUE, SET_IN_GAME}, #ifdef WIZARD {"sanity_check", &iflags.sanity_check, FALSE, SET_IN_GAME}, #else {"sanity_check", (boolean *)0, FALSE, SET_IN_FILE}, #endif #ifdef EXP_ON_BOTL {"showexp", &flags.showexp, FALSE, SET_IN_GAME}, #else {"showexp", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"showrace", &iflags.showrace, FALSE, SET_IN_GAME}, #ifdef SCORE_ON_BOTL {"showscore", &flags.showscore, FALSE, SET_IN_GAME}, #else {"showscore", (boolean *)0, FALSE, SET_IN_FILE}, #endif {"silent", &flags.silent, TRUE, SET_IN_GAME}, {"softkeyboard", &iflags.wc2_softkeyboard, FALSE, SET_IN_FILE}, {"sortpack", &flags.sortpack, TRUE, SET_IN_GAME}, {"sound", &flags.soundok, TRUE, SET_IN_GAME}, {"sparkle", &flags.sparkle, TRUE, SET_IN_GAME}, {"standout", &flags.standout, FALSE, SET_IN_GAME}, {"splash_screen", &iflags.wc_splash_screen, TRUE, DISP_IN_GAME}, /*WC*/ {"tiled_map", &iflags.wc_tiled_map, PREFER_TILED, DISP_IN_GAME}, /*WC*/ {"time", &flags.time, FALSE, SET_IN_GAME}, #ifdef TIMED_DELAY {"timed_delay", &flags.nap, TRUE, SET_IN_GAME}, #else {"timed_delay", (boolean *)0, FALSE, SET_IN_GAME}, #endif {"tombstone",&flags.tombstone, TRUE, SET_IN_GAME}, {"toptenwin",&flags.toptenwin, FALSE, SET_IN_GAME}, {"travel", &iflags.travelcmd, TRUE, SET_IN_GAME}, #ifdef WIN32CON {"use_inverse", &iflags.wc_inverse, TRUE, SET_IN_GAME}, /*WC*/ #else {"use_inverse", &iflags.wc_inverse, FALSE, SET_IN_GAME}, /*WC*/ #endif {"verbose", &flags.verbose, TRUE, SET_IN_GAME}, {"wraptext", &iflags.wc2_wraptext, FALSE, SET_IN_GAME}, {(char *)0, (boolean *)0, FALSE, 0} }; /* compound options, for option_help() and external programs like Amiga * frontend */ static struct Comp_Opt { const char *name, *descr; int size; /* for frontends and such allocating space -- * usually allowed size of data in game, but * occasionally maximum reasonable size for * typing when game maintains information in * a different format */ int optflags; } compopt[] = { { "align", "your starting alignment (lawful, neutral, or chaotic)", 8, DISP_IN_GAME }, { "align_message", "message window alignment", 20, DISP_IN_GAME }, /*WC*/ { "align_status", "status window alignment", 20, DISP_IN_GAME }, /*WC*/ { "altkeyhandler", "alternate key handler", 20, DISP_IN_GAME }, { "boulder", "the symbol to use for displaying boulders", 1, SET_IN_GAME }, { "catname", "the name of your (first) cat (e.g., catname:Tabby)", PL_PSIZ, DISP_IN_GAME }, { "disclose", "the kinds of information to disclose at end of game", sizeof(flags.end_disclose) * 2, SET_IN_GAME }, { "dogname", "the name of your (first) dog (e.g., dogname:Fang)", PL_PSIZ, DISP_IN_GAME }, { "dungeon", "the symbols to use in drawing the dungeon map", MAXDCHARS+1, SET_IN_FILE }, { "effects", "the symbols to use in drawing special effects", MAXECHARS+1, SET_IN_FILE }, { "font_map", "the font to use in the map window", 40, DISP_IN_GAME }, /*WC*/ { "font_menu", "the font to use in menus", 40, DISP_IN_GAME }, /*WC*/ { "font_message", "the font to use in the message window", 40, DISP_IN_GAME }, /*WC*/ { "font_size_map", "the size of the map font", 20, DISP_IN_GAME }, /*WC*/ { "font_size_menu", "the size of the menu font", 20, DISP_IN_GAME }, /*WC*/ { "font_size_message", "the size of the message font", 20, DISP_IN_GAME }, /*WC*/ { "font_size_status", "the size of the status font", 20, DISP_IN_GAME }, /*WC*/ { "font_size_text", "the size of the text font", 20, DISP_IN_GAME }, /*WC*/ { "font_status", "the font to use in status window", 40, DISP_IN_GAME }, /*WC*/ { "font_text", "the font to use in text windows", 40, DISP_IN_GAME }, /*WC*/ { "fruit", "the name of a fruit you enjoy eating", PL_FSIZ, SET_IN_GAME }, { "gender", "your starting gender (male or female)", 8, DISP_IN_GAME }, { "horsename", "the name of your (first) horse (e.g., horsename:Silver)", PL_PSIZ, DISP_IN_GAME }, { "map_mode", "map display mode under Windows", 20, DISP_IN_GAME }, /*WC*/ { "menustyle", "user interface for object selection", MENUTYPELEN, SET_IN_GAME }, { "menu_deselect_all", "deselect all items in a menu", 4, SET_IN_FILE }, { "menu_deselect_page", "deselect all items on this page of a menu", 4, SET_IN_FILE }, { "menu_first_page", "jump to the first page in a menu", 4, SET_IN_FILE }, { "menu_headings", "bold, inverse, or underline headings", 9, SET_IN_GAME }, { "menu_invert_all", "invert all items in a menu", 4, SET_IN_FILE }, { "menu_invert_page", "invert all items on this page of a menu", 4, SET_IN_FILE }, { "menu_last_page", "jump to the last page in a menu", 4, SET_IN_FILE }, { "menu_next_page", "goto the next menu page", 4, SET_IN_FILE }, { "menu_previous_page", "goto the previous menu page", 4, SET_IN_FILE }, { "menu_search", "search for a menu item", 4, SET_IN_FILE }, { "menu_select_all", "select all items in a menu", 4, SET_IN_FILE }, { "menu_select_page", "select all items on this page of a menu", 4, SET_IN_FILE }, { "monsters", "the symbols to use for monsters", MAXMCLASSES, SET_IN_FILE }, { "msghistory", "number of top line messages to save", 5, DISP_IN_GAME }, # ifdef TTY_GRAPHICS {"msg_window", "the type of message window required",1, SET_IN_GAME}, # else {"msg_window", "the type of message window required", 1, SET_IN_FILE}, # endif { "name", "your character's name (e.g., name:Merlin-W)", PL_NSIZ, DISP_IN_GAME }, { "number_pad", "use the number pad", 1, SET_IN_GAME}, { "objects", "the symbols to use for objects", MAXOCLASSES, SET_IN_FILE }, { "packorder", "the inventory order of the items in your pack", MAXOCLASSES, SET_IN_GAME }, #ifdef CHANGE_COLOR { "palette", "palette (00c/880/-fff is blue/yellow/reverse white)", 15 , SET_IN_GAME }, # if defined(MAC) { "hicolor", "same as palette, only order is reversed", 15, SET_IN_FILE }, # endif #endif { "pettype", "your preferred initial pet type", 4, DISP_IN_GAME }, { "pickup_burden", "maximum burden picked up before prompt", 20, SET_IN_GAME }, { "pickup_types", "types of objects to pick up automatically", MAXOCLASSES, SET_IN_GAME }, { "player_selection", "choose character via dialog or prompts", 12, DISP_IN_GAME }, { "race", "your starting race (e.g., Human, Elf)", PL_CSIZ, DISP_IN_GAME }, { "role", "your starting role (e.g., Barbarian, Valkyrie)", PL_CSIZ, DISP_IN_GAME }, { "runmode", "display frequency when `running' or `travelling'", sizeof "teleport", SET_IN_GAME }, { "scores", "the parts of the score list you wish to see", 32, SET_IN_GAME }, { "scroll_amount", "amount to scroll map when scroll_margin is reached", 20, DISP_IN_GAME }, /*WC*/ { "scroll_margin", "scroll map when this far from the edge", 20, DISP_IN_GAME }, /*WC*/ #ifdef MSDOS { "soundcard", "type of sound card to use", 20, SET_IN_FILE }, #endif { "suppress_alert", "suppress alerts about version-specific features", 8, SET_IN_GAME }, { "tile_width", "width of tiles", 20, DISP_IN_GAME}, /*WC*/ { "tile_height", "height of tiles", 20, DISP_IN_GAME}, /*WC*/ { "tile_file", "name of tile file", 70, DISP_IN_GAME}, /*WC*/ { "traps", "the symbols to use in drawing traps", MAXTCHARS+1, SET_IN_FILE }, { "vary_msgcount", "show more old messages at a time", 20, DISP_IN_GAME }, /*WC*/ #ifdef MSDOS { "video", "method of video updating", 20, SET_IN_FILE }, #endif #ifdef VIDEOSHADES { "videocolors", "color mappings for internal screen routines", 40, DISP_IN_GAME }, { "videoshades", "gray shades to map to black/gray/white", 32, DISP_IN_GAME }, #endif #ifdef WIN32CON {"subkeyvalue", "override keystroke value", 7, SET_IN_FILE}, #endif { "windowcolors", "the foreground/background colors of windows", /*WC*/ 80, DISP_IN_GAME }, { "windowtype", "windowing system to use", WINTYPELEN, DISP_IN_GAME }, { (char *)0, (char *)0, 0, 0 } }; #ifdef OPTION_LISTS_ONLY #undef static #else /* use rest of file */ static boolean need_redraw; /* for doset() */ #if defined(TOS) && defined(TEXTCOLOR) extern boolean colors_changed; /* in tos.c */ #endif #ifdef VIDEOSHADES extern char *shade[3]; /* in sys/msdos/video.c */ extern char ttycolors[CLR_MAX]; /* in sys/msdos/video.c */ #endif static char def_inv_order[MAXOCLASSES] = { COIN_CLASS, AMULET_CLASS, WEAPON_CLASS, ARMOR_CLASS, FOOD_CLASS, SCROLL_CLASS, SPBOOK_CLASS, POTION_CLASS, RING_CLASS, WAND_CLASS, TOOL_CLASS, GEM_CLASS, ROCK_CLASS, BALL_CLASS, CHAIN_CLASS, 0, }; /* * Default menu manipulation command accelerators. These may _not_ be: * * + a number - reserved for counts * + an upper or lower case US ASCII letter - used for accelerators * + ESC - reserved for escaping the menu * + NULL, CR or LF - reserved for commiting the selection(s). NULL * is kind of odd, but the tty's xwaitforspace() will return it if * someone hits a . * + a default object class symbol - used for object class accelerators * * Standard letters (for now) are: * * < back 1 page * > forward 1 page * ^ first page * | last page * : search * * page all * , select . * \ deselect - * ~ invert @ * * The command name list is duplicated in the compopt array. */ typedef struct { const char *name; char cmd; } menu_cmd_t; #define NUM_MENU_CMDS 11 static const menu_cmd_t default_menu_cmd_info[NUM_MENU_CMDS] = { /* 0*/ { "menu_first_page", MENU_FIRST_PAGE }, { "menu_last_page", MENU_LAST_PAGE }, { "menu_next_page", MENU_NEXT_PAGE }, { "menu_previous_page", MENU_PREVIOUS_PAGE }, { "menu_select_all", MENU_SELECT_ALL }, /* 5*/ { "menu_deselect_all", MENU_UNSELECT_ALL }, { "menu_invert_all", MENU_INVERT_ALL }, { "menu_select_page", MENU_SELECT_PAGE }, { "menu_deselect_page", MENU_UNSELECT_PAGE }, { "menu_invert_page", MENU_INVERT_PAGE }, /*10*/ { "menu_search", MENU_SEARCH }, }; /* * Allow the user to map incoming characters to various menu commands. * The accelerator list must be a valid C string. */ #define MAX_MENU_MAPPED_CMDS 32 /* some number */ char mapped_menu_cmds[MAX_MENU_MAPPED_CMDS+1]; /* exported */ static char mapped_menu_op[MAX_MENU_MAPPED_CMDS+1]; static short n_menu_mapped = 0; static boolean initial, from_file; STATIC_DCL void FDECL(doset_add_menu, (winid,const char *,int)); STATIC_DCL void FDECL(nmcpy, (char *, const char *, int)); STATIC_DCL void FDECL(escapes, (const char *, char *)); STATIC_DCL void FDECL(rejectoption, (const char *)); STATIC_DCL void FDECL(badoption, (const char *)); STATIC_DCL char *FDECL(string_for_opt, (char *,BOOLEAN_P)); STATIC_DCL char *FDECL(string_for_env_opt, (const char *, char *,BOOLEAN_P)); STATIC_DCL void FDECL(bad_negation, (const char *,BOOLEAN_P)); STATIC_DCL int FDECL(change_inv_order, (char *)); STATIC_DCL void FDECL(oc_to_str, (char *, char *)); STATIC_DCL void FDECL(graphics_opts, (char *,const char *,int,int)); STATIC_DCL int FDECL(feature_alert_opts, (char *, const char *)); STATIC_DCL const char *FDECL(get_compopt_value, (const char *, char *)); STATIC_DCL boolean FDECL(special_handling, (const char *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL void FDECL(warning_opts, (char *,const char *)); STATIC_DCL void FDECL(duplicate_opt_detection, (const char *, int)); STATIC_OVL void FDECL(wc_set_font_name, (int, char *)); STATIC_OVL int FDECL(wc_set_window_colors, (char *)); STATIC_OVL boolean FDECL(is_wc_option, (const char *)); STATIC_OVL boolean FDECL(wc_supported, (const char *)); STATIC_OVL boolean FDECL(is_wc2_option, (const char *)); STATIC_OVL boolean FDECL(wc2_supported, (const char *)); #ifdef AUTOPICKUP_EXCEPTIONS STATIC_DCL void FDECL(remove_autopickup_exception, (struct autopickup_exception *)); STATIC_OVL int FDECL(count_ape_maps, (int *, int *)); #endif /* check whether a user-supplied option string is a proper leading substring of a particular option name; option string might have a colon or equals sign and arbitrary value appended to it */ boolean match_optname(user_string, opt_name, min_length, val_allowed) const char *user_string, *opt_name; int min_length; boolean val_allowed; { int len = (int)strlen(user_string); if (val_allowed) { const char *p = index(user_string, ':'), *q = index(user_string, '='); if (!p || (q && q < p)) p = q; while(p && p > user_string && isspace(*(p-1))) p--; if (p) len = (int)(p - user_string); } return (len >= min_length) && !strncmpi(opt_name, user_string, len); } /* most environment variables will eventually be printed in an error * message if they don't work, and most error message paths go through * BUFSZ buffers, which could be overflowed by a maliciously long * environment variable. if a variable can legitimately be long, or * if it's put in a smaller buffer, the responsible code will have to * bounds-check itself. */ char * nh_getenv(ev) const char *ev; { char *getev = getenv(ev); if (getev && strlen(getev) <= (BUFSZ / 2)) return getev; else return (char *)0; } void initoptions() { #ifndef MAC char *opts; #endif int i; /* initialize the random number generator */ setrandom(); /* for detection of configfile options specified multiple times */ iflags.opt_booldup = iflags.opt_compdup = (int *)0; for (i = 0; boolopt[i].name; i++) { if (boolopt[i].addr) *(boolopt[i].addr) = boolopt[i].initvalue; } flags.end_own = FALSE; flags.end_top = 3; flags.end_around = 2; iflags.runmode = RUN_LEAP; iflags.msg_history = 20; #ifdef TTY_GRAPHICS iflags.prevmsg_window = 's'; #endif iflags.menu_headings = ATR_INVERSE; /* Use negative indices to indicate not yet selected */ flags.initrole = -1; flags.initrace = -1; flags.initgend = -1; flags.initalign = -1; /* Set the default monster and object class symbols. Don't use */ /* memcpy() --- sizeof char != sizeof uchar on some machines. */ for (i = 0; i < MAXOCLASSES; i++) oc_syms[i] = (uchar) def_oc_syms[i]; for (i = 0; i < MAXMCLASSES; i++) monsyms[i] = (uchar) def_monsyms[i]; for (i = 0; i < WARNCOUNT; i++) warnsyms[i] = def_warnsyms[i].sym; iflags.bouldersym = 0; iflags.travelcc.x = iflags.travelcc.y = -1; flags.warnlevel = 1; flags.warntype = 0L; /* assert( sizeof flags.inv_order == sizeof def_inv_order ); */ (void)memcpy((genericptr_t)flags.inv_order, (genericptr_t)def_inv_order, sizeof flags.inv_order); flags.pickup_types[0] = '\0'; flags.pickup_burden = MOD_ENCUMBER; for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) flags.end_disclose[i] = DISCLOSE_PROMPT_DEFAULT_NO; switch_graphics(ASCII_GRAPHICS); /* set default characters */ #if defined(UNIX) && defined(TTY_GRAPHICS) /* * Set defaults for some options depending on what we can * detect about the environment's capabilities. * This has to be done after the global initialization above * and before reading user-specific initialization via * config file/environment variable below. */ /* this detects the IBM-compatible console on most 386 boxes */ if ((opts = nh_getenv("TERM")) && !strncmp(opts, "AT", 2)) { switch_graphics(IBM_GRAPHICS); # ifdef TEXTCOLOR iflags.use_color = TRUE; # endif } #endif /* UNIX && TTY_GRAPHICS */ #if defined(UNIX) || defined(VMS) # ifdef TTY_GRAPHICS /* detect whether a "vt" terminal can handle alternate charsets */ if ((opts = nh_getenv("TERM")) && !strncmpi(opts, "vt", 2) && AS && AE && index(AS, '\016') && index(AE, '\017')) { switch_graphics(DEC_GRAPHICS); } # endif #endif /* UNIX || VMS */ #ifdef MAC_GRAPHICS_ENV switch_graphics(MAC_GRAPHICS); #endif /* MAC_GRAPHICS_ENV */ flags.menu_style = MENU_FULL; /* since this is done before init_objects(), do partial init here */ objects[SLIME_MOLD].oc_name_idx = SLIME_MOLD; nmcpy(pl_fruit, OBJ_NAME(objects[SLIME_MOLD]), PL_FSIZ); #ifndef MAC opts = getenv("NETHACKOPTIONS"); if (!opts) opts = getenv("HACKOPTIONS"); if (opts) { if (*opts == '/' || *opts == '\\' || *opts == '@') { if (*opts == '@') opts++; /* @filename */ /* looks like a filename */ if (strlen(opts) < BUFSZ/2) read_config_file(opts); } else { read_config_file((char *)0); /* let the total length of options be long; * parseoptions() will check each individually */ parseoptions(opts, TRUE, FALSE); } } else #endif read_config_file((char *)0); (void)fruitadd(pl_fruit); /* Remove "slime mold" from list of object names; this will */ /* prevent it from being wished unless it's actually present */ /* as a named (or default) fruit. Wishing for "fruit" will */ /* result in the player's preferred fruit [better than "\033"]. */ obj_descr[SLIME_MOLD].oc_name = "fruit"; return; } STATIC_OVL void nmcpy(dest, src, maxlen) char *dest; const char *src; int maxlen; { int count; for(count = 1; count < maxlen; count++) { if(*src == ',' || *src == '\0') break; /*exit on \0 terminator*/ *dest++ = *src++; } *dest = 0; } /* * escapes: escape expansion for showsyms. C-style escapes understood include * \n, \b, \t, \r, \xnnn (hex), \onnn (octal), \nnn (decimal). The ^-prefix * for control characters is also understood, and \[mM] followed by any of the * previous forms or by a character has the effect of 'meta'-ing the value (so * that the alternate character set will be enabled). */ STATIC_OVL void escapes(cp, tp) const char *cp; char *tp; { while (*cp) { int cval = 0, meta = 0; if (*cp == '\\' && index("mM", cp[1])) { meta = 1; cp += 2; } if (*cp == '\\' && index("0123456789xXoO", cp[1])) { const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF"; int dcount = 0; cp++; if (*cp == 'x' || *cp == 'X') for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++) cval = (cval * 16) + (dp - hex) / 2; else if (*cp == 'o' || *cp == 'O') for (++cp; (index("01234567",*cp)) && (dcount++ < 3); cp++) cval = (cval * 8) + (*cp - '0'); else for (; (index("0123456789",*cp)) && (dcount++ < 3); cp++) cval = (cval * 10) + (*cp - '0'); } else if (*cp == '\\') /* C-style character escapes */ { switch (*++cp) { case '\\': cval = '\\'; break; case 'n': cval = '\n'; break; case 't': cval = '\t'; break; case 'b': cval = '\b'; break; case 'r': cval = '\r'; break; default: cval = *cp; } cp++; } else if (*cp == '^') /* expand control-character syntax */ { cval = (*++cp & 0x1f); cp++; } else cval = *cp++; if (meta) cval |= 0x80; *tp++ = cval; } *tp = '\0'; } STATIC_OVL void rejectoption(optname) const char *optname; { #ifdef MICRO pline("\"%s\" settable only from %s.", optname, configfile); #else pline("%s can be set only from NETHACKOPTIONS or %s.", optname, configfile); #endif } STATIC_OVL void badoption(opts) const char *opts; { if (!initial) { if (!strncmp(opts, "h", 1) || !strncmp(opts, "?", 1)) option_help(); else pline("Bad syntax: %s. Enter \"?g\" for help.", opts); return; } #ifdef MAC else return; #endif if(from_file) raw_printf("Bad syntax in OPTIONS in %s: %s.", configfile, opts); else raw_printf("Bad syntax in NETHACKOPTIONS: %s.", opts); wait_synch(); } STATIC_OVL char * string_for_opt(opts, val_optional) char *opts; boolean val_optional; { char *colon, *equals; colon = index(opts, ':'); equals = index(opts, '='); if (!colon || (equals && equals < colon)) colon = equals; if (!colon || !*++colon) { if (!val_optional) badoption(opts); return (char *)0; } return colon; } STATIC_OVL char * string_for_env_opt(optname, opts, val_optional) const char *optname; char *opts; boolean val_optional; { if(!initial) { rejectoption(optname); return (char *)0; } return string_for_opt(opts, val_optional); } STATIC_OVL void bad_negation(optname, with_parameter) const char *optname; boolean with_parameter; { pline_The("%s option may not %sbe negated.", optname, with_parameter ? "both have a value and " : ""); } /* * Change the inventory order, using the given string as the new order. * Missing characters in the new order are filled in at the end from * the current inv_order, except for gold, which is forced to be first * if not explicitly present. * * This routine returns 1 unless there is a duplicate or bad char in * the string. */ STATIC_OVL int change_inv_order(op) char *op; { int oc_sym, num; char *sp, buf[BUFSZ]; num = 0; #ifndef GOLDOBJ if (!index(op, GOLD_SYM)) buf[num++] = COIN_CLASS; #else /* !!!! probably unnecessary with gold as normal inventory */ #endif for (sp = op; *sp; sp++) { oc_sym = def_char_to_objclass(*sp); /* reject bad or duplicate entries */ if (oc_sym == MAXOCLASSES || oc_sym == RANDOM_CLASS || oc_sym == ILLOBJ_CLASS || !index(flags.inv_order, oc_sym) || index(sp+1, *sp)) return 0; /* retain good ones */ buf[num++] = (char) oc_sym; } buf[num] = '\0'; /* fill in any omitted classes, using previous ordering */ for (sp = flags.inv_order; *sp; sp++) if (!index(buf, *sp)) { buf[num++] = *sp; buf[num] = '\0'; /* explicitly terminate for next index() */ } Strcpy(flags.inv_order, buf); return 1; } STATIC_OVL void graphics_opts(opts, optype, maxlen, offset) register char *opts; const char *optype; int maxlen, offset; { uchar translate[MAXPCHARS+1]; int length, i; if (!(opts = string_for_env_opt(optype, opts, FALSE))) return; escapes(opts, opts); length = strlen(opts); if (length > maxlen) length = maxlen; /* match the form obtained from PC configuration files */ for (i = 0; i < length; i++) translate[i] = (uchar) opts[i]; assign_graphics(translate, length, maxlen, offset); } STATIC_OVL void warning_opts(opts, optype) register char *opts; const char *optype; { uchar translate[MAXPCHARS+1]; int length, i; if (!(opts = string_for_env_opt(optype, opts, FALSE))) return; escapes(opts, opts); length = strlen(opts); if (length > WARNCOUNT) length = WARNCOUNT; /* match the form obtained from PC configuration files */ for (i = 0; i < length; i++) translate[i] = (((i < WARNCOUNT) && opts[i]) ? (uchar) opts[i] : def_warnsyms[i].sym); assign_warnings(translate); } void assign_warnings(graph_chars) register uchar *graph_chars; { int i; for (i = 0; i < WARNCOUNT; i++) if (graph_chars[i]) warnsyms[i] = graph_chars[i]; } STATIC_OVL int feature_alert_opts(op, optn) char *op; const char *optn; { char buf[BUFSZ]; boolean rejectver = FALSE; unsigned long fnv = get_feature_notice_ver(op); /* version.c */ if (fnv == 0L) return 0; if (fnv > get_current_feature_ver()) rejectver = TRUE; else flags.suppress_alert = fnv; if (rejectver) { if (!initial) You_cant("disable new feature alerts for future versions."); else { Sprintf(buf, "\n%s=%s Invalid reference to a future version ignored", optn, op); badoption(buf); } return 0; } if (!initial) { Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ, FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH); pline("Feature change alerts disabled for NetHack %s features and prior.", buf); } return 1; } void set_duplicate_opt_detection(on_or_off) int on_or_off; { int k, *optptr; if (on_or_off != 0) { /*-- ON --*/ if (iflags.opt_booldup) impossible("iflags.opt_booldup already on (memory leak)"); iflags.opt_booldup = (int *)alloc(SIZE(boolopt) * sizeof(int)); optptr = iflags.opt_booldup; for (k = 0; k < SIZE(boolopt); ++k) *optptr++ = 0; if (iflags.opt_compdup) impossible("iflags.opt_compdup already on (memory leak)"); iflags.opt_compdup = (int *)alloc(SIZE(compopt) * sizeof(int)); optptr = iflags.opt_compdup; for (k = 0; k < SIZE(compopt); ++k) *optptr++ = 0; } else { /*-- OFF --*/ if (iflags.opt_booldup) free((genericptr_t) iflags.opt_booldup); iflags.opt_booldup = (int *)0; if (iflags.opt_compdup) free((genericptr_t) iflags.opt_compdup); iflags.opt_compdup = (int *)0; } } STATIC_OVL void duplicate_opt_detection(opts, bool_or_comp) const char *opts; int bool_or_comp; /* 0 == boolean option, 1 == compound */ { int i, *optptr; #if defined(MAC) /* the Mac has trouble dealing with the output of messages while * processing the config file. That should get fixed one day. * For now just return. */ return; #endif if ((bool_or_comp == 0) && iflags.opt_booldup && initial && from_file) { for (i = 0; boolopt[i].name; i++) { if (match_optname(opts, boolopt[i].name, 3, FALSE)) { optptr = iflags.opt_booldup + i; if (*optptr == 1) { raw_printf( "\nWarning - Boolean option specified multiple times: %s.\n", opts); wait_synch(); } *optptr += 1; break; /* don't match multiple options */ } } } else if ((bool_or_comp == 1) && iflags.opt_compdup && initial && from_file) { for (i = 0; compopt[i].name; i++) { if (match_optname(opts, compopt[i].name, strlen(compopt[i].name), TRUE)) { optptr = iflags.opt_compdup + i; if (*optptr == 1) { raw_printf( "\nWarning - compound option specified multiple times: %s.\n", compopt[i].name); wait_synch(); } *optptr += 1; break; /* don't match multiple options */ } } } } void parseoptions(opts, tinitial, tfrom_file) register char *opts; boolean tinitial, tfrom_file; { register char *op; unsigned num; boolean negated; int i; const char *fullname; initial = tinitial; from_file = tfrom_file; if ((op = index(opts, ',')) != 0) { *op++ = 0; parseoptions(op, initial, from_file); } if (strlen(opts) > BUFSZ/2) { badoption("option too long"); return; } /* strip leading and trailing white space */ while (isspace(*opts)) opts++; op = eos(opts); while (--op >= opts && isspace(*op)) *op = '\0'; if (!*opts) return; negated = FALSE; while ((*opts == '!') || !strncmpi(opts, "no", 2)) { if (*opts == '!') opts++; else opts += 2; negated = !negated; } /* variant spelling */ if (match_optname(opts, "colour", 5, FALSE)) Strcpy(opts, "color"); /* fortunately this isn't longer */ if (!match_optname(opts, "subkeyvalue", 11, TRUE)) /* allow multiple */ duplicate_opt_detection(opts, 1); /* 1 means compound opts */ /* special boolean options */ if (match_optname(opts, "female", 3, FALSE)) { if(!initial && flags.female == negated) pline("That is not anatomically possible."); else flags.initgend = flags.female = !negated; return; } if (match_optname(opts, "male", 4, FALSE)) { if(!initial && flags.female != negated) pline("That is not anatomically possible."); else flags.initgend = flags.female = negated; return; } #if defined(MICRO) && !defined(AMIGA) /* included for compatibility with old NetHack.cnf files */ if (match_optname(opts, "IBM_", 4, FALSE)) { iflags.BIOS = !negated; return; } #endif /* MICRO */ /* compound options */ fullname = "pettype"; if (match_optname(opts, fullname, 3, TRUE)) { if ((op = string_for_env_opt(fullname, opts, negated)) != 0) { if (negated) bad_negation(fullname, TRUE); else switch (*op) { case 'd': /* dog */ case 'D': preferred_pet = 'd'; break; case 'c': /* cat */ case 'C': case 'f': /* feline */ case 'F': preferred_pet = 'c'; break; case 'n': /* no pet */ case 'N': preferred_pet = 'n'; break; default: pline("Unrecognized pet type '%s'.", op); break; } } else if (negated) preferred_pet = 'n'; return; } fullname = "catname"; if (match_optname(opts, fullname, 3, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) nmcpy(catname, op, PL_PSIZ); return; } fullname = "dogname"; if (match_optname(opts, fullname, 3, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) nmcpy(dogname, op, PL_PSIZ); return; } fullname = "horsename"; if (match_optname(opts, fullname, 5, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) nmcpy(horsename, op, PL_PSIZ); return; } fullname = "number_pad"; if (match_optname(opts, fullname, 10, TRUE)) { boolean compat = (strlen(opts) <= 10); number_pad(iflags.num_pad ? 1 : 0); op = string_for_opt(opts, (compat || !initial)); if (!op) { if (compat || negated || initial) { /* for backwards compatibility, "number_pad" without a value is a synonym for number_pad:1 */ iflags.num_pad = !negated; if (iflags.num_pad) iflags.num_pad_mode = 0; } return; } if (negated) { bad_negation("number_pad", TRUE); return; } if (*op == '1' || *op == '2') { iflags.num_pad = 1; if (*op == '2') iflags.num_pad_mode = 1; else iflags.num_pad_mode = 0; } else if (*op == '0') { iflags.num_pad = 0; iflags.num_pad_mode = 0; } else badoption(opts); return; } fullname = "runmode"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) { iflags.runmode = RUN_TPORT; } else if ((op = string_for_opt(opts, FALSE)) != 0) { if (!strncmpi(op, "teleport", strlen(op))) iflags.runmode = RUN_TPORT; else if (!strncmpi(op, "run", strlen(op))) iflags.runmode = RUN_LEAP; else if (!strncmpi(op, "walk", strlen(op))) iflags.runmode = RUN_STEP; else if (!strncmpi(op, "crawl", strlen(op))) iflags.runmode = RUN_CRAWL; else badoption(opts); } return; } fullname = "msghistory"; if (match_optname(opts, fullname, 3, TRUE)) { op = string_for_env_opt(fullname, opts, negated); if ((negated && !op) || (!negated && op)) { iflags.msg_history = negated ? 0 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } fullname="msg_window"; /* msg_window:single, combo, full or reversed */ if (match_optname(opts, fullname, 4, TRUE)) { /* allow option to be silently ignored by non-tty ports */ #ifdef TTY_GRAPHICS int tmp; if (!(op = string_for_opt(opts, TRUE))) { tmp = negated ? 's' : 'f'; } else { if (negated) { bad_negation(fullname, TRUE); return; } tmp = tolower(*op); } switch (tmp) { case 's': /* single message history cycle (default if negated) */ iflags.prevmsg_window = 's'; break; case 'c': /* combination: two singles, then full page reversed */ iflags.prevmsg_window = 'c'; break; case 'f': /* full page (default if no opts) */ iflags.prevmsg_window = 'f'; break; case 'r': /* full page (reversed) */ iflags.prevmsg_window = 'r'; break; default: badoption(opts); } #endif return; } /* WINCAP * setting font options */ fullname = "font"; if (!strncmpi(opts, fullname, 4)) { int wintype = -1; char *fontopts = opts + 4; if (!strncmpi(fontopts, "map", 3) || !strncmpi(fontopts, "_map", 4)) wintype = NHW_MAP; else if (!strncmpi(fontopts, "message", 7) || !strncmpi(fontopts, "_message", 8)) wintype = NHW_MESSAGE; else if (!strncmpi(fontopts, "text", 4) || !strncmpi(fontopts, "_text", 5)) wintype = NHW_TEXT; else if (!strncmpi(fontopts, "menu", 4) || !strncmpi(fontopts, "_menu", 5)) wintype = NHW_MENU; else if (!strncmpi(fontopts, "status", 6) || !strncmpi(fontopts, "_status", 7)) wintype = NHW_STATUS; else if (!strncmpi(fontopts, "_size", 5)) { if (!strncmpi(fontopts, "_size_map", 8)) wintype = NHW_MAP; else if (!strncmpi(fontopts, "_size_message", 12)) wintype = NHW_MESSAGE; else if (!strncmpi(fontopts, "_size_text", 9)) wintype = NHW_TEXT; else if (!strncmpi(fontopts, "_size_menu", 9)) wintype = NHW_MENU; else if (!strncmpi(fontopts, "_size_status", 11)) wintype = NHW_STATUS; else { badoption(opts); return; } if (wintype > 0 && !negated && (op = string_for_opt(opts, FALSE)) != 0) { switch(wintype) { case NHW_MAP: iflags.wc_fontsiz_map = atoi(op); break; case NHW_MESSAGE: iflags.wc_fontsiz_message = atoi(op); break; case NHW_TEXT: iflags.wc_fontsiz_text = atoi(op); break; case NHW_MENU: iflags.wc_fontsiz_menu = atoi(op); break; case NHW_STATUS: iflags.wc_fontsiz_status = atoi(op); break; } } return; } else { badoption(opts); } if (wintype > 0 && (op = string_for_opt(opts, FALSE)) != 0) { wc_set_font_name(wintype, op); #ifdef MAC set_font_name (wintype, op); #endif return; } else if (negated) bad_negation(fullname, TRUE); return; } #ifdef CHANGE_COLOR if (match_optname(opts, "palette", 3, TRUE) # ifdef MAC || match_optname(opts, "hicolor", 3, TRUE) # endif ) { int color_number, color_incr; # ifdef MAC if (match_optname(opts, "hicolor", 3, TRUE)) { if (negated) { bad_negation("hicolor", FALSE); return; } color_number = CLR_MAX + 4; /* HARDCODED inverse number */ color_incr = -1; } else { # endif if (negated) { bad_negation("palette", FALSE); return; } color_number = 0; color_incr = 1; # ifdef MAC } # endif if ((op = string_for_opt(opts, FALSE)) != (char *)0) { char *pt = op; int cnt, tmp, reverse; long rgb; while (*pt && color_number >= 0) { cnt = 3; rgb = 0L; if (*pt == '-') { reverse = 1; pt++; } else { reverse = 0; } while (cnt-- > 0) { if (*pt && *pt != '/') { # ifdef AMIGA rgb <<= 4; # else rgb <<= 8; # endif tmp = *(pt++); if (isalpha(tmp)) { tmp = (tmp + 9) & 0xf; /* Assumes ASCII... */ } else { tmp &= 0xf; /* Digits in ASCII too... */ } # ifndef AMIGA /* Add an extra so we fill f -> ff and 0 -> 00 */ rgb += tmp << 4; # endif rgb += tmp; } } if (*pt == '/') { pt++; } change_color(color_number, rgb, reverse); color_number += color_incr; } } if (!initial) { need_redraw = TRUE; } return; } #endif /* CHANGE_COLOR */ if (match_optname(opts, "fruit", 2, TRUE)) { char empty_str = '\0'; op = string_for_opt(opts, negated); if (negated) { if (op) { bad_negation("fruit", TRUE); return; } op = &empty_str; goto goodfruit; } if (!op) return; if (!initial) { struct fruit *f; num = 0; for(f=ffruit; f; f=f->nextf) { if (!strcmp(op, f->fname)) goto goodfruit; num++; } if (num >= 100) { pline("Doing that so many times isn't very fruitful."); return; } } goodfruit: nmcpy(pl_fruit, op, PL_FSIZ); /* OBJ_NAME(objects[SLIME_MOLD]) won't work after initialization */ if (!*pl_fruit) nmcpy(pl_fruit, "slime mold", PL_FSIZ); if (!initial) (void)fruitadd(pl_fruit); /* If initial, then initoptions is allowed to do it instead * of here (initoptions always has to do it even if there's * no fruit option at all. Also, we don't want people * setting multiple fruits in their options.) */ return; } /* graphics:string */ fullname = "graphics"; if (match_optname(opts, fullname, 2, TRUE)) { if (negated) bad_negation(fullname, FALSE); else graphics_opts(opts, fullname, MAXPCHARS, 0); return; } fullname = "dungeon"; if (match_optname(opts, fullname, 2, TRUE)) { if (negated) bad_negation(fullname, FALSE); else graphics_opts(opts, fullname, MAXDCHARS, 0); return; } fullname = "traps"; if (match_optname(opts, fullname, 2, TRUE)) { if (negated) bad_negation(fullname, FALSE); else graphics_opts(opts, fullname, MAXTCHARS, MAXDCHARS); return; } fullname = "effects"; if (match_optname(opts, fullname, 2, TRUE)) { if (negated) bad_negation(fullname, FALSE); else graphics_opts(opts, fullname, MAXECHARS, MAXDCHARS+MAXTCHARS); return; } /* objects:string */ fullname = "objects"; if (match_optname(opts, fullname, 7, TRUE)) { int length; if (negated) { bad_negation(fullname, FALSE); return; } if (!(opts = string_for_env_opt(fullname, opts, FALSE))) return; escapes(opts, opts); /* * Override the default object class symbols. The first * object in the object class is the "random object". I * don't want to use 0 as an object class, so the "random * object" is basically a place holder. * * The object class symbols have already been initialized in * initoptions(). */ length = strlen(opts); if (length >= MAXOCLASSES) length = MAXOCLASSES-1; /* don't count RANDOM_OBJECT */ for (i = 0; i < length; i++) oc_syms[i+1] = (uchar) opts[i]; return; } /* monsters:string */ fullname = "monsters"; if (match_optname(opts, fullname, 8, TRUE)) { int length; if (negated) { bad_negation(fullname, FALSE); return; } if (!(opts = string_for_env_opt(fullname, opts, FALSE))) return; escapes(opts, opts); /* Override default mon class symbols set in initoptions(). */ length = strlen(opts); if (length >= MAXMCLASSES) length = MAXMCLASSES-1; /* mon class 0 unused */ for (i = 0; i < length; i++) monsyms[i+1] = (uchar) opts[i]; return; } fullname = "warnings"; if (match_optname(opts, fullname, 5, TRUE)) { if (negated) bad_negation(fullname, FALSE); else warning_opts(opts, fullname); return; } /* boulder:symbol */ fullname = "boulder"; if (match_optname(opts, fullname, 7, TRUE)) { int clash = 0; if (negated) { bad_negation(fullname, FALSE); return; } /* if (!(opts = string_for_env_opt(fullname, opts, FALSE))) */ if (!(opts = string_for_opt(opts, FALSE))) return; escapes(opts, opts); if (def_char_to_monclass(opts[0]) != MAXMCLASSES) clash = 1; else if (opts[0] >= '1' && opts[0] <= '5') clash = 2; if (clash) { /* symbol chosen matches a used monster or warning symbol which is not good - reject it*/ pline( "Badoption - boulder symbol '%c' conflicts with a %s symbol.", opts[0], (clash == 1) ? "monster" : "warning"); } else { /* * Override the default boulder symbol. */ iflags.bouldersym = (uchar) opts[0]; } if (!initial) need_redraw = TRUE; return; } /* name:string */ fullname = "name"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) nmcpy(plname, op, PL_NSIZ); return; } /* role:string or character:string */ fullname = "role"; if (match_optname(opts, fullname, 4, TRUE) || match_optname(opts, (fullname = "character"), 4, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { if ((flags.initrole = str2role(op)) == ROLE_NONE) badoption(opts); else /* Backwards compatibility */ nmcpy(pl_character, op, PL_NSIZ); } return; } /* race:string */ fullname = "race"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { if ((flags.initrace = str2race(op)) == ROLE_NONE) badoption(opts); else /* Backwards compatibility */ pl_race = *op; } return; } /* gender:string */ fullname = "gender"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { if ((flags.initgend = str2gend(op)) == ROLE_NONE) badoption(opts); else flags.female = flags.initgend; } return; } /* altkeyhandler:string */ fullname = "altkeyhandler"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_opt(opts, negated))) { #ifdef WIN32CON (void)strncpy(iflags.altkeyhandler, op, MAX_ALTKEYHANDLER - 5); load_keyboard_handler(); #endif } return; } /* WINCAP * align_status:[left|top|right|bottom] */ fullname = "align_status"; if (match_optname(opts, fullname, sizeof("align_status")-1, TRUE)) { op = string_for_opt(opts, negated); if (op && !negated) { if (!strncmpi (op, "left", sizeof("left")-1)) iflags.wc_align_status = ALIGN_LEFT; else if (!strncmpi (op, "top", sizeof("top")-1)) iflags.wc_align_status = ALIGN_TOP; else if (!strncmpi (op, "right", sizeof("right")-1)) iflags.wc_align_status = ALIGN_RIGHT; else if (!strncmpi (op, "bottom", sizeof("bottom")-1)) iflags.wc_align_status = ALIGN_BOTTOM; else badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * align_message:[left|top|right|bottom] */ fullname = "align_message"; if (match_optname(opts, fullname, sizeof("align_message")-1, TRUE)) { op = string_for_opt(opts, negated); if (op && !negated) { if (!strncmpi (op, "left", sizeof("left")-1)) iflags.wc_align_message = ALIGN_LEFT; else if (!strncmpi (op, "top", sizeof("top")-1)) iflags.wc_align_message = ALIGN_TOP; else if (!strncmpi (op, "right", sizeof("right")-1)) iflags.wc_align_message = ALIGN_RIGHT; else if (!strncmpi (op, "bottom", sizeof("bottom")-1)) iflags.wc_align_message = ALIGN_BOTTOM; else badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* align:string */ fullname = "align"; if (match_optname(opts, fullname, sizeof("align")-1, TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) if ((flags.initalign = str2align(op)) == ROLE_NONE) badoption(opts); return; } /* the order to list the pack */ fullname = "packorder"; if (match_optname(opts, fullname, 4, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if (!(op = string_for_opt(opts, FALSE))) return; if (!change_inv_order(op)) badoption(opts); return; } /* maximum burden picked up before prompt (Warren Cheung) */ fullname = "pickup_burden"; if (match_optname(opts, fullname, 8, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { switch (tolower(*op)) { /* Unencumbered */ case 'u': flags.pickup_burden = UNENCUMBERED; break; /* Burdened (slight encumbrance) */ case 'b': flags.pickup_burden = SLT_ENCUMBER; break; /* streSsed (moderate encumbrance) */ case 's': flags.pickup_burden = MOD_ENCUMBER; break; /* straiNed (heavy encumbrance) */ case 'n': flags.pickup_burden = HVY_ENCUMBER; break; /* OverTaxed (extreme encumbrance) */ case 'o': case 't': flags.pickup_burden = EXT_ENCUMBER; break; /* overLoaded */ case 'l': flags.pickup_burden = OVERLOADED; break; default: badoption(opts); } } return; } /* types of objects to pick up automatically */ if (match_optname(opts, "pickup_types", 8, TRUE)) { char ocl[MAXOCLASSES + 1], tbuf[MAXOCLASSES + 1], qbuf[QBUFSZ], abuf[BUFSZ]; int oc_sym; boolean badopt = FALSE, compat = (strlen(opts) <= 6), use_menu; oc_to_str(flags.pickup_types, tbuf); flags.pickup_types[0] = '\0'; /* all */ op = string_for_opt(opts, (compat || !initial)); if (!op) { if (compat || negated || initial) { /* for backwards compatibility, "pickup" without a value is a synonym for autopickup of all types (and during initialization, we can't prompt yet) */ flags.pickup = !negated; return; } oc_to_str(flags.inv_order, ocl); use_menu = TRUE; if (flags.menu_style == MENU_TRADITIONAL || flags.menu_style == MENU_COMBINATION) { use_menu = FALSE; Sprintf(qbuf, "New pickup_types: [%s am] (%s)", ocl, *tbuf ? tbuf : "all"); getlin(qbuf, abuf); op = mungspaces(abuf); if (abuf[0] == '\0' || abuf[0] == '\033') op = tbuf; /* restore */ else if (abuf[0] == 'm') use_menu = TRUE; } if (use_menu) { (void) choose_classes_menu("Auto-Pickup what?", 1, TRUE, ocl, tbuf); op = tbuf; } } if (negated) { bad_negation("pickup_types", TRUE); return; } while (*op == ' ') op++; if (*op != 'a' && *op != 'A') { num = 0; while (*op) { oc_sym = def_char_to_objclass(*op); /* make sure all are valid obj symbols occuring once */ if (oc_sym != MAXOCLASSES && !index(flags.pickup_types, oc_sym)) { flags.pickup_types[num] = (char)oc_sym; flags.pickup_types[++num] = '\0'; } else badopt = TRUE; op++; } if (badopt) badoption(opts); } return; } /* WINCAP * player_selection: dialog | prompts */ fullname = "player_selection"; if (match_optname(opts, fullname, sizeof("player_selection")-1, TRUE)) { op = string_for_opt(opts, negated); if (op && !negated) { if (!strncmpi (op, "dialog", sizeof("dialog")-1)) iflags.wc_player_selection = VIA_DIALOG; else if (!strncmpi (op, "prompt", sizeof("prompt")-1)) iflags.wc_player_selection = VIA_PROMPTS; else badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* things to disclose at end of game */ if (match_optname(opts, "disclose", 7, TRUE)) { /* * The order that the end_disclore options are stored: * inventory, attribs, vanquished, genocided, conduct * There is an array in flags: * end_disclose[NUM_DISCLOSURE_OPT]; * with option settings for the each of the following: * iagvc [see disclosure_options in decl.c]: * Legal setting values in that array are: * DISCLOSE_PROMPT_DEFAULT_YES ask with default answer yes * DISCLOSE_PROMPT_DEFAULT_NO ask with default answer no * DISCLOSE_YES_WITHOUT_PROMPT always disclose and don't ask * DISCLOSE_NO_WITHOUT_PROMPT never disclose and don't ask * * Those setting values can be used in the option * string as a prefix to get the desired behaviour. * * For backward compatibility, no prefix is required, * and the presence of a i,a,g,v, or c without a prefix * sets the corresponding value to DISCLOSE_YES_WITHOUT_PROMPT. */ boolean badopt = FALSE; int idx, prefix_val; op = string_for_opt(opts, TRUE); if (op && negated) { bad_negation("disclose", TRUE); return; } /* "disclose" without a value means "all with prompting" and negated means "none without prompting" */ if (!op || !strcmpi(op, "all") || !strcmpi(op, "none")) { if (op && !strcmpi(op, "none")) negated = TRUE; for (num = 0; num < NUM_DISCLOSURE_OPTIONS; num++) flags.end_disclose[num] = negated ? DISCLOSE_NO_WITHOUT_PROMPT : DISCLOSE_PROMPT_DEFAULT_YES; return; } num = 0; prefix_val = -1; while (*op && num < sizeof flags.end_disclose - 1) { register char c, *dop; static char valid_settings[] = { DISCLOSE_PROMPT_DEFAULT_YES, DISCLOSE_PROMPT_DEFAULT_NO, DISCLOSE_YES_WITHOUT_PROMPT, DISCLOSE_NO_WITHOUT_PROMPT, '\0' }; c = lowc(*op); if (c == 'k') c = 'v'; /* killed -> vanquished */ dop = index(disclosure_options, c); if (dop) { idx = dop - disclosure_options; if (idx < 0 || idx > NUM_DISCLOSURE_OPTIONS - 1) { impossible("bad disclosure index %d %c", idx, c); continue; } if (prefix_val != -1) { flags.end_disclose[idx] = prefix_val; prefix_val = -1; } else flags.end_disclose[idx] = DISCLOSE_YES_WITHOUT_PROMPT; } else if (index(valid_settings, c)) { prefix_val = c; } else if (c == ' ') { /* do nothing */ } else badopt = TRUE; op++; } if (badopt) badoption(opts); return; } /* scores:5t[op] 5a[round] o[wn] */ if (match_optname(opts, "scores", 4, TRUE)) { if (negated) { bad_negation("scores", FALSE); return; } if (!(op = string_for_opt(opts, FALSE))) return; while (*op) { int inum = 1; if (digit(*op)) { inum = atoi(op); while (digit(*op)) op++; } else if (*op == '!') { negated = !negated; op++; } while (*op == ' ') op++; switch (*op) { case 't': case 'T': flags.end_top = inum; break; case 'a': case 'A': flags.end_around = inum; break; case 'o': case 'O': flags.end_own = !negated; break; default: badoption(opts); return; } while (letter(*++op) || *op == ' ') continue; if (*op == '/') op++; } return; } fullname = "suppress_alert"; if (match_optname(opts, fullname, 4, TRUE)) { op = string_for_opt(opts, negated); if (negated) bad_negation(fullname, FALSE); else if (op) (void) feature_alert_opts(op,fullname); return; } #ifdef VIDEOSHADES /* videocolors:string */ fullname = "videocolors"; if (match_optname(opts, fullname, 6, TRUE) || match_optname(opts, "videocolours", 10, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!assign_videocolors(opts)) badoption(opts); return; } /* videoshades:string */ fullname = "videoshades"; if (match_optname(opts, fullname, 6, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!assign_videoshades(opts)) badoption(opts); return; } #endif /* VIDEOSHADES */ #ifdef MSDOS # ifdef NO_TERMS /* video:string -- must be after longer tests */ fullname = "video"; if (match_optname(opts, fullname, 5, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!assign_video(opts)) badoption(opts); return; } # endif /* NO_TERMS */ /* soundcard:string -- careful not to match boolean 'sound' */ fullname = "soundcard"; if (match_optname(opts, fullname, 6, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!assign_soundcard(opts)) badoption(opts); return; } #endif /* MSDOS */ /* WINCAP * map_mode:[tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8|ascii7x12|ascii8x12| ascii16x12|ascii12x16|ascii10x18|fit_to_screen] */ fullname = "map_mode"; if (match_optname(opts, fullname, sizeof("map_mode")-1, TRUE)) { op = string_for_opt(opts, negated); if (op && !negated) { if (!strncmpi (op, "tiles", sizeof("tiles")-1)) iflags.wc_map_mode = MAP_MODE_TILES; else if (!strncmpi (op, "ascii4x6", sizeof("ascii4x6")-1)) iflags.wc_map_mode = MAP_MODE_ASCII4x6; else if (!strncmpi (op, "ascii6x8", sizeof("ascii6x8")-1)) iflags.wc_map_mode = MAP_MODE_ASCII6x8; else if (!strncmpi (op, "ascii8x8", sizeof("ascii8x8")-1)) iflags.wc_map_mode = MAP_MODE_ASCII8x8; else if (!strncmpi (op, "ascii16x8", sizeof("ascii16x8")-1)) iflags.wc_map_mode = MAP_MODE_ASCII16x8; else if (!strncmpi (op, "ascii7x12", sizeof("ascii7x12")-1)) iflags.wc_map_mode = MAP_MODE_ASCII7x12; else if (!strncmpi (op, "ascii8x12", sizeof("ascii8x12")-1)) iflags.wc_map_mode = MAP_MODE_ASCII8x12; else if (!strncmpi (op, "ascii16x12", sizeof("ascii16x12")-1)) iflags.wc_map_mode = MAP_MODE_ASCII16x12; else if (!strncmpi (op, "ascii12x16", sizeof("ascii12x16")-1)) iflags.wc_map_mode = MAP_MODE_ASCII12x16; else if (!strncmpi (op, "ascii10x18", sizeof("ascii10x18")-1)) iflags.wc_map_mode = MAP_MODE_ASCII10x18; else if (!strncmpi (op, "fit_to_screen", sizeof("fit_to_screen")-1)) iflags.wc_map_mode = MAP_MODE_ASCII_FIT_TO_SCREEN; else badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * scroll_amount:nn */ fullname = "scroll_amount"; if (match_optname(opts, fullname, sizeof("scroll_amount")-1, TRUE)) { op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_scroll_amount = negated ? 1 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * scroll_margin:nn */ fullname = "scroll_margin"; if (match_optname(opts, fullname, sizeof("scroll_margin")-1, TRUE)) { op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_scroll_margin = negated ? 5 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } fullname = "subkeyvalue"; if (match_optname(opts, fullname, 5, TRUE)) { if (negated) bad_negation(fullname, FALSE); else { #if defined(WIN32CON) op = string_for_opt(opts, 0); map_subkeyvalue(op); #endif } return; } /* WINCAP * tile_width:nn */ fullname = "tile_width"; if (match_optname(opts, fullname, sizeof("tile_width")-1, TRUE)) { op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_tile_width = negated ? 0 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * tile_file:name */ fullname = "tile_file"; if (match_optname(opts, fullname, sizeof("tile_file")-1, TRUE)) { if ((op = string_for_opt(opts, FALSE)) != 0) { if (iflags.wc_tile_file) free(iflags.wc_tile_file); iflags.wc_tile_file = (char *)alloc(strlen(op) + 1); Strcpy(iflags.wc_tile_file, op); } return; } /* WINCAP * tile_height:nn */ fullname = "tile_height"; if (match_optname(opts, fullname, sizeof("tile_height")-1, TRUE)) { op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_tile_height = negated ? 0 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } /* WINCAP * vary_msgcount:nn */ fullname = "vary_msgcount"; if (match_optname(opts, fullname, sizeof("vary_msgcount")-1, TRUE)) { op = string_for_opt(opts, negated); if ((negated && !op) || (!negated && op)) { iflags.wc_vary_msgcount = negated ? 0 : atoi(op); } else if (negated) bad_negation(fullname, TRUE); return; } fullname = "windowtype"; if (match_optname(opts, fullname, 3, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if ((op = string_for_env_opt(fullname, opts, FALSE)) != 0) { char buf[WINTYPELEN]; nmcpy(buf, op, WINTYPELEN); choose_windows(buf); } return; } /* WINCAP * setting window colors * syntax: windowcolors=menu foregrnd/backgrnd text foregrnd/backgrnd */ fullname = "windowcolors"; if (match_optname(opts, fullname, 7, TRUE)) { if ((op = string_for_opt(opts, FALSE)) != 0) { if (!wc_set_window_colors(op)) badoption(opts); } else if (negated) bad_negation(fullname, TRUE); return; } /* menustyle:traditional or combo or full or partial */ if (match_optname(opts, "menustyle", 4, TRUE)) { int tmp; boolean val_required = (strlen(opts) > 5 && !negated); if (!(op = string_for_opt(opts, !val_required))) { if (val_required) return; /* string_for_opt gave feedback */ tmp = negated ? 'n' : 'f'; } else { tmp = tolower(*op); } switch (tmp) { case 'n': /* none */ case 't': /* traditional */ flags.menu_style = MENU_TRADITIONAL; break; case 'c': /* combo: trad.class sel+menu */ flags.menu_style = MENU_COMBINATION; break; case 'p': /* partial: no class menu */ flags.menu_style = MENU_PARTIAL; break; case 'f': /* full: class menu + menu */ flags.menu_style = MENU_FULL; break; default: badoption(opts); } return; } fullname = "menu_headings"; if (match_optname(opts, fullname, 12, TRUE)) { if (negated) { bad_negation(fullname, FALSE); return; } else if (!(opts = string_for_env_opt(fullname, opts, FALSE))) { return; } if (!strcmpi(opts,"bold")) iflags.menu_headings = ATR_BOLD; else if (!strcmpi(opts,"inverse")) iflags.menu_headings = ATR_INVERSE; else if (!strcmpi(opts,"underline")) iflags.menu_headings = ATR_ULINE; else badoption(opts); return; } /* check for menu command mapping */ for (i = 0; i < NUM_MENU_CMDS; i++) { fullname = default_menu_cmd_info[i].name; if (match_optname(opts, fullname, (int)strlen(fullname), TRUE)) { if (negated) bad_negation(fullname, FALSE); else if ((op = string_for_opt(opts, FALSE)) != 0) { int j; char c, op_buf[BUFSZ]; boolean isbad = FALSE; escapes(op, op_buf); c = *op_buf; if (c == 0 || c == '\r' || c == '\n' || c == '\033' || c == ' ' || digit(c) || (letter(c) && c != '@')) isbad = TRUE; else /* reject default object class symbols */ for (j = 1; j < MAXOCLASSES; j++) if (c == def_oc_syms[i]) { isbad = TRUE; break; } if (isbad) badoption(opts); else add_menu_cmd_alias(c, default_menu_cmd_info[i].cmd); } return; } } /* OK, if we still haven't recognized the option, check the boolean * options list */ for (i = 0; boolopt[i].name; i++) { if (match_optname(opts, boolopt[i].name, 3, FALSE)) { /* options that don't exist */ if (!boolopt[i].addr) { if (!initial && !negated) pline_The("\"%s\" option is not available.", boolopt[i].name); return; } /* options that must come from config file */ if (!initial && (boolopt[i].optflags == SET_IN_FILE)) { rejectoption(boolopt[i].name); return; } *(boolopt[i].addr) = !negated; duplicate_opt_detection(boolopt[i].name, 0); #if defined(TERMLIB) || defined(ASCIIGRAPH) || defined(MAC_GRAPHICS_ENV) if (FALSE # ifdef TERMLIB || (boolopt[i].addr) == &iflags.DECgraphics # endif # ifdef ASCIIGRAPH || (boolopt[i].addr) == &iflags.IBMgraphics # endif # ifdef MAC_GRAPHICS_ENV || (boolopt[i].addr) == &iflags.MACgraphics # endif ) { # ifdef REINCARNATION if (!initial && Is_rogue_level(&u.uz)) assign_rogue_graphics(FALSE); # endif need_redraw = TRUE; # ifdef TERMLIB if ((boolopt[i].addr) == &iflags.DECgraphics) switch_graphics(iflags.DECgraphics ? DEC_GRAPHICS : ASCII_GRAPHICS); # endif # ifdef ASCIIGRAPH if ((boolopt[i].addr) == &iflags.IBMgraphics) switch_graphics(iflags.IBMgraphics ? IBM_GRAPHICS : ASCII_GRAPHICS); # endif # ifdef MAC_GRAPHICS_ENV if ((boolopt[i].addr) == &iflags.MACgraphics) switch_graphics(iflags.MACgraphics ? MAC_GRAPHICS : ASCII_GRAPHICS); # endif # ifdef REINCARNATION if (!initial && Is_rogue_level(&u.uz)) assign_rogue_graphics(TRUE); # endif } #endif /* TERMLIB || ASCIIGRAPH || MAC_GRAPHICS_ENV */ /* only do processing below if setting with doset() */ if (initial) return; if ((boolopt[i].addr) == &flags.time #ifdef EXP_ON_BOTL || (boolopt[i].addr) == &flags.showexp #endif #ifdef SCORE_ON_BOTL || (boolopt[i].addr) == &flags.showscore #endif ) flags.botl = TRUE; else if ((boolopt[i].addr) == &flags.invlet_constant) { if (flags.invlet_constant) reassign(); } #ifdef LAN_MAIL else if ((boolopt[i].addr) == &flags.biff) { if (flags.biff) lan_mail_init(); else lan_mail_finish(); } #endif else if ((boolopt[i].addr) == &flags.lit_corridor) { /* * All corridor squares seen via night vision or * candles & lamps change. Update them by calling * newsym() on them. Don't do this if we are * initializing the options --- the vision system * isn't set up yet. */ vision_recalc(2); /* shut down vision */ vision_full_recalc = 1; /* delayed recalc */ } else if ((boolopt[i].addr) == &iflags.use_inverse || (boolopt[i].addr) == &iflags.showrace || (boolopt[i].addr) == &iflags.hilite_pet) { need_redraw = TRUE; } #ifdef TEXTCOLOR else if ((boolopt[i].addr) == &iflags.use_color) { need_redraw = TRUE; # ifdef TOS if ((boolopt[i].addr) == &iflags.use_color && iflags.BIOS) { if (colors_changed) restore_colors(); else set_colors(); } # endif } #endif return; } } /* out of valid options */ badoption(opts); } static NEARDATA const char *menutype[] = { "traditional", "combination", "partial", "full" }; static NEARDATA const char *burdentype[] = { "unencumbered", "burdened", "stressed", "strained", "overtaxed", "overloaded" }; static NEARDATA const char *runmodes[] = { "teleport", "run", "walk", "crawl" }; /* * Convert the given string of object classes to a string of default object * symbols. */ STATIC_OVL void oc_to_str(src,dest) char *src, *dest; { int i; while ((i = (int) *src++) != 0) { if (i < 0 || i >= MAXOCLASSES) impossible("oc_to_str: illegal object class %d", i); else *dest++ = def_oc_syms[i]; } *dest = '\0'; } /* * Add the given mapping to the menu command map list. Always keep the * maps valid C strings. */ void add_menu_cmd_alias(from_ch, to_ch) char from_ch, to_ch; { if (n_menu_mapped >= MAX_MENU_MAPPED_CMDS) pline("out of menu map space."); else { mapped_menu_cmds[n_menu_mapped] = from_ch; mapped_menu_op[n_menu_mapped] = to_ch; n_menu_mapped++; mapped_menu_cmds[n_menu_mapped] = 0; mapped_menu_op[n_menu_mapped] = 0; } } /* * Map the given character to its corresponding menu command. If it * doesn't match anything, just return the original. */ char map_menu_cmd(ch) char ch; { char *found = index(mapped_menu_cmds, ch); if (found) { int idx = found - mapped_menu_cmds; ch = mapped_menu_op[idx]; } return ch; } #if defined(MICRO) || defined(MAC) || defined(WIN32) # define OPTIONS_HEADING "OPTIONS" #else # define OPTIONS_HEADING "NETHACKOPTIONS" #endif static char fmtstr_doset_add_menu[] = "%s%-15s [%s] "; static char fmtstr_doset_add_menu_tab[] = "%s\t[%s]"; STATIC_OVL void doset_add_menu(win, option, indexoffset) winid win; /* window to add to */ const char *option; /* option name */ int indexoffset; /* value to add to index in compopt[], or zero if option cannot be changed */ { const char *value = "unknown"; /* current value */ char buf[BUFSZ], buf2[BUFSZ]; anything any; int i; any.a_void = 0; if (indexoffset == 0) { any.a_int = 0; value = get_compopt_value(option, buf2); } else { for (i=0; compopt[i].name; i++) if (strcmp(option, compopt[i].name) == 0) break; if (compopt[i].name) { any.a_int = i + 1 + indexoffset; value = get_compopt_value(option, buf2); } else { /* We are trying to add an option not found in compopt[]. This is almost certainly bad, but we'll let it through anyway (with a zero value, so it can't be selected). */ any.a_int = 0; } } /* " " replaces "a - " -- assumes menus follow that style */ if (!iflags.menu_tab_sep) Sprintf(buf, fmtstr_doset_add_menu, any.a_int ? "" : " ", option, value); else Sprintf(buf, fmtstr_doset_add_menu_tab, option, value); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } /* Changing options via menu by Per Liboriussen */ int doset() { char buf[BUFSZ], buf2[BUFSZ]; int i, pass, boolcount, pick_cnt, pick_idx, opt_indx; boolean *bool_p; winid tmpwin; anything any; menu_item *pick_list; int indexoffset, startpass, endpass; boolean setinitial = FALSE, fromfile = FALSE; int biggest_name = 0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any.a_void = 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Booleans (selecting will toggle value):", MENU_UNSELECTED); any.a_int = 0; /* first list any other non-modifiable booleans, then modifiable ones */ for (pass = 0; pass <= 1; pass++) for (i = 0; boolopt[i].name; i++) if ((bool_p = boolopt[i].addr) != 0 && ((boolopt[i].optflags == DISP_IN_GAME && pass == 0) || (boolopt[i].optflags == SET_IN_GAME && pass == 1))) { if (bool_p == &flags.female) continue; /* obsolete */ #ifdef WIZARD if (bool_p == &iflags.sanity_check && !wizard) continue; if (bool_p == &iflags.menu_tab_sep && !wizard) continue; #endif if (is_wc_option(boolopt[i].name) && !wc_supported(boolopt[i].name)) continue; if (is_wc2_option(boolopt[i].name) && !wc2_supported(boolopt[i].name)) continue; any.a_int = (pass == 0) ? 0 : i + 1; if (!iflags.menu_tab_sep) Sprintf(buf, "%s%-13s [%s]", pass == 0 ? " " : "", boolopt[i].name, *bool_p ? "true" : "false"); else Sprintf(buf, "%s\t[%s]", boolopt[i].name, *bool_p ? "true" : "false"); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } boolcount = i; indexoffset = boolcount; any.a_void = 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Compounds (selecting will prompt for new value):", MENU_UNSELECTED); startpass = DISP_IN_GAME; endpass = SET_IN_GAME; /* spin through the options to find the biggest name and adjust the format string accordingly if needed */ biggest_name = 0; for (i = 0; compopt[i].name; i++) if (compopt[i].optflags >= startpass && compopt[i].optflags <= endpass && strlen(compopt[i].name) > (unsigned) biggest_name) biggest_name = (int) strlen(compopt[i].name); if (biggest_name > 30) biggest_name = 30; if (!iflags.menu_tab_sep) Sprintf(fmtstr_doset_add_menu, "%%s%%-%ds [%%s]", biggest_name); /* deliberately put `name', `role', `race', `gender' first */ doset_add_menu(tmpwin, "name", 0); doset_add_menu(tmpwin, "role", 0); doset_add_menu(tmpwin, "race", 0); doset_add_menu(tmpwin, "gender", 0); for (pass = startpass; pass <= endpass; pass++) for (i = 0; compopt[i].name; i++) if (compopt[i].optflags == pass) { if (!strcmp(compopt[i].name, "name") || !strcmp(compopt[i].name, "role") || !strcmp(compopt[i].name, "race") || !strcmp(compopt[i].name, "gender")) continue; else if (is_wc_option(compopt[i].name) && !wc_supported(compopt[i].name)) continue; else if (is_wc2_option(compopt[i].name) && !wc2_supported(compopt[i].name)) continue; else doset_add_menu(tmpwin, compopt[i].name, (pass == DISP_IN_GAME) ? 0 : indexoffset); } #ifdef AUTOPICKUP_EXCEPTIONS any.a_int = -1; Sprintf(buf, "autopickup exceptions (%d currently set)", count_ape_maps((int *)0, (int *)0)); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); #endif /* AUTOPICKUP_EXCEPTIONS */ #ifdef PREFIXES_IN_USE any.a_void = 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, "Variable playground locations:", MENU_UNSELECTED); for (i = 0; i < PREFIX_COUNT; i++) doset_add_menu(tmpwin, fqn_prefix_names[i], 0); #endif end_menu(tmpwin, "Set what options?"); need_redraw = FALSE; if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &pick_list)) > 0) { /* * Walk down the selection list and either invert the booleans * or prompt for new values. In most cases, call parseoptions() * to take care of options that require special attention, like * redraws. */ for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { opt_indx = pick_list[pick_idx].item.a_int - 1; #ifdef AUTOPICKUP_EXCEPTIONS if (opt_indx == -2) { special_handling("autopickup_exception", setinitial, fromfile); } else #endif if (opt_indx < boolcount) { /* boolean option */ Sprintf(buf, "%s%s", *boolopt[opt_indx].addr ? "!" : "", boolopt[opt_indx].name); parseoptions(buf, setinitial, fromfile); if (wc_supported(boolopt[opt_indx].name) || wc2_supported(boolopt[opt_indx].name)) preference_update(boolopt[opt_indx].name); } else { /* compound option */ opt_indx -= boolcount; if (!special_handling(compopt[opt_indx].name, setinitial, fromfile)) { Sprintf(buf, "Set %s to what?", compopt[opt_indx].name); getlin(buf, buf2); if (buf2[0] == '\033') continue; Sprintf(buf, "%s:%s", compopt[opt_indx].name, buf2); /* pass the buck */ parseoptions(buf, setinitial, fromfile); } if (wc_supported(compopt[opt_indx].name) || wc2_supported(compopt[opt_indx].name)) preference_update(compopt[opt_indx].name); } } free((genericptr_t)pick_list); pick_list = (menu_item *)0; } destroy_nhwindow(tmpwin); if (need_redraw) (void) doredraw(); return 0; } STATIC_OVL boolean special_handling(optname, setinitial, setfromfile) const char *optname; boolean setinitial,setfromfile; { winid tmpwin; anything any; int i; char buf[BUFSZ]; boolean retval = FALSE; /* Special handling of menustyle, pickup_burden, pickup_types, * disclose, runmode, msg_window, menu_headings, and number_pad options. #ifdef AUTOPICKUP_EXCEPTIONS * Also takes care of interactive autopickup_exception_handling changes. #endif */ if (!strcmp("menustyle", optname)) { const char *style_name; menu_item *style_pick = (menu_item *)0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (i = 0; i < SIZE(menutype); i++) { style_name = menutype[i]; /* note: separate `style_name' variable used to avoid an optimizer bug in VAX C V2.3 */ any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, *style_name, 0, ATR_NONE, style_name, MENU_UNSELECTED); } end_menu(tmpwin, "Select menustyle:"); if (select_menu(tmpwin, PICK_ONE, &style_pick) > 0) { flags.menu_style = style_pick->item.a_int - 1; free((genericptr_t)style_pick); } destroy_nhwindow(tmpwin); retval = TRUE; } else if (!strcmp("pickup_burden", optname)) { const char *burden_name, *burden_letters = "ubsntl"; menu_item *burden_pick = (menu_item *)0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (i = 0; i < SIZE(burdentype); i++) { burden_name = burdentype[i]; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, burden_letters[i], 0, ATR_NONE, burden_name, MENU_UNSELECTED); } end_menu(tmpwin, "Select encumbrance level:"); if (select_menu(tmpwin, PICK_ONE, &burden_pick) > 0) { flags.pickup_burden = burden_pick->item.a_int - 1; free((genericptr_t)burden_pick); } destroy_nhwindow(tmpwin); retval = TRUE; } else if (!strcmp("pickup_types", optname)) { /* parseoptions will prompt for the list of types */ parseoptions(strcpy(buf, "pickup_types"), setinitial, setfromfile); retval = TRUE; } else if (!strcmp("disclose", optname)) { int pick_cnt, pick_idx, opt_idx; menu_item *disclosure_category_pick = (menu_item *)0; /* * The order of disclose_names[] * must correspond to disclosure_options in decl.h */ static const char *disclosure_names[] = { "inventory", "attributes", "vanquished", "genocides", "conduct" }; int disc_cat[NUM_DISCLOSURE_OPTIONS]; const char *disclosure_name; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) { disclosure_name = disclosure_names[i]; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, disclosure_options[i], 0, ATR_NONE, disclosure_name, MENU_UNSELECTED); disc_cat[i] = 0; } end_menu(tmpwin, "Change which disclosure options categories:"); if ((pick_cnt = select_menu(tmpwin, PICK_ANY, &disclosure_category_pick)) > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { opt_idx = disclosure_category_pick[pick_idx].item.a_int - 1; disc_cat[opt_idx] = 1; } free((genericptr_t)disclosure_category_pick); disclosure_category_pick = (menu_item *)0; } destroy_nhwindow(tmpwin); for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) { if (disc_cat[i]) { char dbuf[BUFSZ]; menu_item *disclosure_option_pick = (menu_item *)0; Sprintf(dbuf, "Disclosure options for %s:", disclosure_names[i]); tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any.a_char = DISCLOSE_NO_WITHOUT_PROMPT; add_menu(tmpwin, NO_GLYPH, &any, 'a', 0, ATR_NONE,"Never disclose and don't prompt", MENU_UNSELECTED); any.a_void = 0; any.a_char = DISCLOSE_YES_WITHOUT_PROMPT; add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, ATR_NONE,"Always disclose and don't prompt", MENU_UNSELECTED); any.a_void = 0; any.a_char = DISCLOSE_PROMPT_DEFAULT_NO; add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE,"Prompt and default answer to \"No\"", MENU_UNSELECTED); any.a_void = 0; any.a_char = DISCLOSE_PROMPT_DEFAULT_YES; add_menu(tmpwin, NO_GLYPH, &any, 'd', 0, ATR_NONE,"Prompt and default answer to \"Yes\"", MENU_UNSELECTED); end_menu(tmpwin, dbuf); if (select_menu(tmpwin, PICK_ONE, &disclosure_option_pick) > 0) { flags.end_disclose[i] = disclosure_option_pick->item.a_char; free((genericptr_t)disclosure_option_pick); } destroy_nhwindow(tmpwin); } } retval = TRUE; } else if (!strcmp("runmode", optname)) { const char *mode_name; menu_item *mode_pick = (menu_item *)0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (i = 0; i < SIZE(runmodes); i++) { mode_name = runmodes[i]; any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, *mode_name, 0, ATR_NONE, mode_name, MENU_UNSELECTED); } end_menu(tmpwin, "Select run/travel display mode:"); if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) { iflags.runmode = mode_pick->item.a_int - 1; free((genericptr_t)mode_pick); } destroy_nhwindow(tmpwin); retval = TRUE; } #ifdef TTY_GRAPHICS else if (!strcmp("msg_window", optname)) { /* by Christian W. Cooper */ menu_item *window_pick = (menu_item *)0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any.a_char = 's'; add_menu(tmpwin, NO_GLYPH, &any, 's', 0, ATR_NONE, "single", MENU_UNSELECTED); any.a_char = 'c'; add_menu(tmpwin, NO_GLYPH, &any, 'c', 0, ATR_NONE, "combination", MENU_UNSELECTED); any.a_char = 'f'; add_menu(tmpwin, NO_GLYPH, &any, 'f', 0, ATR_NONE, "full", MENU_UNSELECTED); any.a_char = 'r'; add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "reversed", MENU_UNSELECTED); end_menu(tmpwin, "Select message history display type:"); if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) { iflags.prevmsg_window = window_pick->item.a_char; free((genericptr_t)window_pick); } destroy_nhwindow(tmpwin); retval = TRUE; } #endif else if (!strcmp("align_message", optname) || !strcmp("align_status", optname)) { menu_item *window_pick = (menu_item *)0; char abuf[BUFSZ]; boolean msg = (*(optname+6) == 'm'); tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any.a_int = ALIGN_TOP; add_menu(tmpwin, NO_GLYPH, &any, 't', 0, ATR_NONE, "top", MENU_UNSELECTED); any.a_int = ALIGN_BOTTOM; add_menu(tmpwin, NO_GLYPH, &any, 'b', 0, ATR_NONE, "bottom", MENU_UNSELECTED); any.a_int = ALIGN_LEFT; add_menu(tmpwin, NO_GLYPH, &any, 'l', 0, ATR_NONE, "left", MENU_UNSELECTED); any.a_int = ALIGN_RIGHT; add_menu(tmpwin, NO_GLYPH, &any, 'r', 0, ATR_NONE, "right", MENU_UNSELECTED); Sprintf(abuf, "Select %s window placement relative to the map:", msg ? "message" : "status"); end_menu(tmpwin, abuf); if (select_menu(tmpwin, PICK_ONE, &window_pick) > 0) { if (msg) iflags.wc_align_message = window_pick->item.a_int; else iflags.wc_align_status = window_pick->item.a_int; free((genericptr_t)window_pick); } destroy_nhwindow(tmpwin); retval = TRUE; } else if (!strcmp("number_pad", optname)) { static const char *npchoices[3] = {"0 (off)", "1 (on)", "2 (on, DOS compatible)"}; const char *npletters = "abc"; menu_item *mode_pick = (menu_item *)0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (i = 0; i < SIZE(npchoices); i++) { any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0, ATR_NONE, npchoices[i], MENU_UNSELECTED); } end_menu(tmpwin, "Select number_pad mode:"); if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) { int mode = mode_pick->item.a_int - 1; switch(mode) { case 2: iflags.num_pad = 1; iflags.num_pad_mode = 1; break; case 1: iflags.num_pad = 1; iflags.num_pad_mode = 0; break; case 0: default: iflags.num_pad = 0; iflags.num_pad_mode = 0; } free((genericptr_t)mode_pick); } destroy_nhwindow(tmpwin); retval = TRUE; } else if (!strcmp("menu_headings", optname)) { static const char *mhchoices[3] = {"bold", "inverse", "underline"}; const char *npletters = "biu"; menu_item *mode_pick = (menu_item *)0; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (i = 0; i < SIZE(mhchoices); i++) { any.a_int = i + 1; add_menu(tmpwin, NO_GLYPH, &any, npletters[i], 0, ATR_NONE, mhchoices[i], MENU_UNSELECTED); } end_menu(tmpwin, "How to highlight menu headings:"); if (select_menu(tmpwin, PICK_ONE, &mode_pick) > 0) { int mode = mode_pick->item.a_int - 1; switch(mode) { case 2: iflags.menu_headings = ATR_ULINE; break; case 0: iflags.menu_headings = ATR_BOLD; break; case 1: default: iflags.menu_headings = ATR_INVERSE; } free((genericptr_t)mode_pick); } destroy_nhwindow(tmpwin); retval = TRUE; #ifdef AUTOPICKUP_EXCEPTIONS } else if (!strcmp("autopickup_exception", optname)) { boolean retval; int pick_cnt, pick_idx, opt_idx, pass; int totalapes = 0, numapes[2] = {0,0}; menu_item *pick_list = (menu_item *)0; anything any; char apebuf[BUFSZ]; struct autopickup_exception *ape; static const char *action_titles[] = { "a", "add new autopickup exception", "l", "list autopickup exceptions", "r", "remove existing autopickup exception", "e", "exit this menu", }; ape_again: opt_idx = 0; totalapes = count_ape_maps(&numapes[AP_LEAVE], &numapes[AP_GRAB]); tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any.a_int = 0; for (i = 0; i < SIZE(action_titles) ; i += 2) { any.a_int++; if (!totalapes && (i >= 2 && i < 6)) continue; add_menu(tmpwin, NO_GLYPH, &any, *action_titles[i], 0, ATR_NONE, action_titles[i+1], MENU_UNSELECTED); } end_menu(tmpwin, "Do what?"); if ((pick_cnt = select_menu(tmpwin, PICK_ONE, &pick_list)) > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) { opt_idx = pick_list[pick_idx].item.a_int - 1; } free((genericptr_t)pick_list); pick_list = (menu_item *)0; } destroy_nhwindow(tmpwin); if (pick_cnt < 1) return FALSE; if (opt_idx == 0) { /* add new */ getlin("What new autopickup exception pattern?", &apebuf[1]); if (apebuf[1] == '\033') return FALSE; apebuf[0] = '"'; Strcat(apebuf,"\""); add_autopickup_exception(apebuf); goto ape_again; } else if (opt_idx == 3) { retval = TRUE; } else { /* remove */ tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { if (numapes[pass] == 0) continue; ape = iflags.autopickup_exceptions[pass]; any.a_void = 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, iflags.menu_headings, (pass == 0) ? "Never pickup" : "Always pickup", MENU_UNSELECTED); for (i = 0; i < numapes[pass] && ape; i++) { any.a_void = (opt_idx == 1) ? 0 : ape; Sprintf(apebuf, "\"%s\"", ape->pattern); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, apebuf, MENU_UNSELECTED); ape = ape->next; } } Sprintf(apebuf, "%s autopickup exceptions", (opt_idx == 1) ? "List of" : "Remove which"); end_menu(tmpwin, apebuf); pick_cnt = select_menu(tmpwin, (opt_idx == 1) ? PICK_NONE : PICK_ANY, &pick_list); if (pick_cnt > 0) { for (pick_idx = 0; pick_idx < pick_cnt; ++pick_idx) remove_autopickup_exception( (struct autopickup_exception *)pick_list[pick_idx].item.a_void); } free((genericptr_t)pick_list); pick_list = (menu_item *)0; destroy_nhwindow(tmpwin); goto ape_again; } retval = TRUE; #endif /* AUTOPICKUP_EXCEPTIONS */ } return retval; } #define rolestring(val,array,field) ((val >= 0) ? array[val].field : \ (val == ROLE_RANDOM) ? randomrole : none) /* This is ugly. We have all the option names in the compopt[] array, but we need to look at each option individually to get the value. */ STATIC_OVL const char * get_compopt_value(optname, buf) const char *optname; char *buf; { char ocl[MAXOCLASSES+1]; static const char none[] = "(none)", randomrole[] = "random", to_be_done[] = "(to be done)", defopt[] = "default", defbrief[] = "def"; int i; buf[0] = '\0'; if (!strcmp(optname,"align_message")) Sprintf(buf, "%s", iflags.wc_align_message == ALIGN_TOP ? "top" : iflags.wc_align_message == ALIGN_LEFT ? "left" : iflags.wc_align_message == ALIGN_BOTTOM ? "bottom" : iflags.wc_align_message == ALIGN_RIGHT ? "right" : defopt); else if (!strcmp(optname,"align_status")) Sprintf(buf, "%s", iflags.wc_align_status == ALIGN_TOP ? "top" : iflags.wc_align_status == ALIGN_LEFT ? "left" : iflags.wc_align_status == ALIGN_BOTTOM ? "bottom" : iflags.wc_align_status == ALIGN_RIGHT ? "right" : defopt); else if (!strcmp(optname,"align")) Sprintf(buf, "%s", rolestring(flags.initalign, aligns, adj)); #ifdef WIN32CON else if (!strcmp(optname,"altkeyhandler")) Sprintf(buf, "%s", iflags.altkeyhandler[0] ? iflags.altkeyhandler : "default"); #endif else if (!strcmp(optname, "boulder")) Sprintf(buf, "%c", iflags.bouldersym ? iflags.bouldersym : oc_syms[(int)objects[BOULDER].oc_class]); else if (!strcmp(optname, "catname")) Sprintf(buf, "%s", catname[0] ? catname : none ); else if (!strcmp(optname, "disclose")) { for (i = 0; i < NUM_DISCLOSURE_OPTIONS; i++) { char topt[2]; if (i) Strcat(buf," "); topt[1] = '\0'; topt[0] = flags.end_disclose[i]; Strcat(buf, topt); topt[0] = disclosure_options[i]; Strcat(buf, topt); } } else if (!strcmp(optname, "dogname")) Sprintf(buf, "%s", dogname[0] ? dogname : none ); else if (!strcmp(optname, "dungeon")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "effects")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "font_map")) Sprintf(buf, "%s", iflags.wc_font_map ? iflags.wc_font_map : defopt); else if (!strcmp(optname, "font_message")) Sprintf(buf, "%s", iflags.wc_font_message ? iflags.wc_font_message : defopt); else if (!strcmp(optname, "font_status")) Sprintf(buf, "%s", iflags.wc_font_status ? iflags.wc_font_status : defopt); else if (!strcmp(optname, "font_menu")) Sprintf(buf, "%s", iflags.wc_font_menu ? iflags.wc_font_menu : defopt); else if (!strcmp(optname, "font_text")) Sprintf(buf, "%s", iflags.wc_font_text ? iflags.wc_font_text : defopt); else if (!strcmp(optname, "font_size_map")) { if (iflags.wc_fontsiz_map) Sprintf(buf, "%d", iflags.wc_fontsiz_map); else Strcpy(buf, defopt); } else if (!strcmp(optname, "font_size_message")) { if (iflags.wc_fontsiz_message) Sprintf(buf, "%d", iflags.wc_fontsiz_message); else Strcpy(buf, defopt); } else if (!strcmp(optname, "font_size_status")) { if (iflags.wc_fontsiz_status) Sprintf(buf, "%d", iflags.wc_fontsiz_status); else Strcpy(buf, defopt); } else if (!strcmp(optname, "font_size_menu")) { if (iflags.wc_fontsiz_menu) Sprintf(buf, "%d", iflags.wc_fontsiz_menu); else Strcpy(buf, defopt); } else if (!strcmp(optname, "font_size_text")) { if (iflags.wc_fontsiz_text) Sprintf(buf, "%d",iflags.wc_fontsiz_text); else Strcpy(buf, defopt); } else if (!strcmp(optname, "fruit")) Sprintf(buf, "%s", pl_fruit); else if (!strcmp(optname, "gender")) Sprintf(buf, "%s", rolestring(flags.initgend, genders, adj)); else if (!strcmp(optname, "horsename")) Sprintf(buf, "%s", horsename[0] ? horsename : none); else if (!strcmp(optname, "map_mode")) Sprintf(buf, "%s", iflags.wc_map_mode == MAP_MODE_TILES ? "tiles" : iflags.wc_map_mode == MAP_MODE_ASCII4x6 ? "ascii4x6" : iflags.wc_map_mode == MAP_MODE_ASCII6x8 ? "ascii6x8" : iflags.wc_map_mode == MAP_MODE_ASCII8x8 ? "ascii8x8" : iflags.wc_map_mode == MAP_MODE_ASCII16x8 ? "ascii16x8" : iflags.wc_map_mode == MAP_MODE_ASCII7x12 ? "ascii7x12" : iflags.wc_map_mode == MAP_MODE_ASCII8x12 ? "ascii8x12" : iflags.wc_map_mode == MAP_MODE_ASCII16x12 ? "ascii16x12" : iflags.wc_map_mode == MAP_MODE_ASCII12x16 ? "ascii12x16" : iflags.wc_map_mode == MAP_MODE_ASCII10x18 ? "ascii10x18" : iflags.wc_map_mode == MAP_MODE_ASCII_FIT_TO_SCREEN ? "fit_to_screen" : defopt); else if (!strcmp(optname, "menustyle")) Sprintf(buf, "%s", menutype[(int)flags.menu_style] ); else if (!strcmp(optname, "menu_deselect_all")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_deselect_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_first_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_invert_all")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_headings")) { Sprintf(buf, "%s", (iflags.menu_headings == ATR_BOLD) ? "bold" : (iflags.menu_headings == ATR_INVERSE) ? "inverse" : (iflags.menu_headings == ATR_ULINE) ? "underline" : "unknown"); } else if (!strcmp(optname, "menu_invert_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_last_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_next_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_previous_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_search")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_select_all")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "menu_select_page")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "monsters")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "msghistory")) Sprintf(buf, "%u", iflags.msg_history); #ifdef TTY_GRAPHICS else if (!strcmp(optname, "msg_window")) Sprintf(buf, "%s", (iflags.prevmsg_window=='s') ? "single" : (iflags.prevmsg_window=='c') ? "combination" : (iflags.prevmsg_window=='f') ? "full" : "reversed"); #endif else if (!strcmp(optname, "name")) Sprintf(buf, "%s", plname); else if (!strcmp(optname, "number_pad")) Sprintf(buf, "%s", (!iflags.num_pad) ? "0=off" : (iflags.num_pad_mode) ? "2=on, DOS compatible" : "1=on"); else if (!strcmp(optname, "objects")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "packorder")) { oc_to_str(flags.inv_order, ocl); Sprintf(buf, "%s", ocl); } #ifdef CHANGE_COLOR else if (!strcmp(optname, "palette")) Sprintf(buf, "%s", get_color_string()); #endif else if (!strcmp(optname, "pettype")) Sprintf(buf, "%s", (preferred_pet == 'c') ? "cat" : (preferred_pet == 'd') ? "dog" : (preferred_pet == 'n') ? "none" : "random"); else if (!strcmp(optname, "pickup_burden")) Sprintf(buf, "%s", burdentype[flags.pickup_burden] ); else if (!strcmp(optname, "pickup_types")) { oc_to_str(flags.pickup_types, ocl); Sprintf(buf, "%s", ocl[0] ? ocl : "all" ); } else if (!strcmp(optname, "race")) Sprintf(buf, "%s", rolestring(flags.initrace, races, noun)); else if (!strcmp(optname, "role")) Sprintf(buf, "%s", rolestring(flags.initrole, roles, name.m)); else if (!strcmp(optname, "runmode")) Sprintf(buf, "%s", runmodes[iflags.runmode]); else if (!strcmp(optname, "scores")) { Sprintf(buf, "%d top/%d around%s", flags.end_top, flags.end_around, flags.end_own ? "/own" : ""); } else if (!strcmp(optname, "scroll_amount")) { if (iflags.wc_scroll_amount) Sprintf(buf, "%d",iflags.wc_scroll_amount); else Strcpy(buf, defopt); } else if (!strcmp(optname, "scroll_margin")) { if (iflags.wc_scroll_margin) Sprintf(buf, "%d",iflags.wc_scroll_margin); else Strcpy(buf, defopt); } else if (!strcmp(optname, "player_selection")) Sprintf(buf, "%s", iflags.wc_player_selection ? "prompts" : "dialog"); #ifdef MSDOS else if (!strcmp(optname, "soundcard")) Sprintf(buf, "%s", to_be_done); #endif else if (!strcmp(optname, "suppress_alert")) { if (flags.suppress_alert == 0L) Strcpy(buf, none); else Sprintf(buf, "%lu.%lu.%lu", FEATURE_NOTICE_VER_MAJ, FEATURE_NOTICE_VER_MIN, FEATURE_NOTICE_VER_PATCH); } else if (!strcmp(optname, "tile_file")) Sprintf(buf, "%s", iflags.wc_tile_file ? iflags.wc_tile_file : defopt); else if (!strcmp(optname, "tile_height")) { if (iflags.wc_tile_height) Sprintf(buf, "%d",iflags.wc_tile_height); else Strcpy(buf, defopt); } else if (!strcmp(optname, "tile_width")) { if (iflags.wc_tile_width) Sprintf(buf, "%d",iflags.wc_tile_width); else Strcpy(buf, defopt); } else if (!strcmp(optname, "traps")) Sprintf(buf, "%s", to_be_done); else if (!strcmp(optname, "vary_msgcount")) { if (iflags.wc_vary_msgcount) Sprintf(buf, "%d",iflags.wc_vary_msgcount); else Strcpy(buf, defopt); } #ifdef MSDOS else if (!strcmp(optname, "video")) Sprintf(buf, "%s", to_be_done); #endif #ifdef VIDEOSHADES else if (!strcmp(optname, "videoshades")) Sprintf(buf, "%s-%s-%s", shade[0],shade[1],shade[2]); else if (!strcmp(optname, "videocolors")) Sprintf(buf, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d-%d", ttycolors[CLR_RED], ttycolors[CLR_GREEN], ttycolors[CLR_BROWN], ttycolors[CLR_BLUE], ttycolors[CLR_MAGENTA], ttycolors[CLR_CYAN], ttycolors[CLR_ORANGE], ttycolors[CLR_BRIGHT_GREEN], ttycolors[CLR_YELLOW], ttycolors[CLR_BRIGHT_BLUE], ttycolors[CLR_BRIGHT_MAGENTA], ttycolors[CLR_BRIGHT_CYAN]); #endif /* VIDEOSHADES */ else if (!strcmp(optname, "windowtype")) Sprintf(buf, "%s", windowprocs.name); else if (!strcmp(optname, "windowcolors")) Sprintf(buf, "%s/%s %s/%s %s/%s %s/%s", iflags.wc_foregrnd_menu ? iflags.wc_foregrnd_menu : defbrief, iflags.wc_backgrnd_menu ? iflags.wc_backgrnd_menu : defbrief, iflags.wc_foregrnd_message ? iflags.wc_foregrnd_message : defbrief, iflags.wc_backgrnd_message ? iflags.wc_backgrnd_message : defbrief, iflags.wc_foregrnd_status ? iflags.wc_foregrnd_status : defbrief, iflags.wc_backgrnd_status ? iflags.wc_backgrnd_status : defbrief, iflags.wc_foregrnd_text ? iflags.wc_foregrnd_text : defbrief, iflags.wc_backgrnd_text ? iflags.wc_backgrnd_text : defbrief); #ifdef PREFIXES_IN_USE else { for (i = 0; i < PREFIX_COUNT; ++i) if (!strcmp(optname, fqn_prefix_names[i]) && fqn_prefix[i]) Sprintf(buf, "%s", fqn_prefix[i]); } #endif if (buf[0]) return buf; else return "unknown"; } int dotogglepickup() { char buf[BUFSZ], ocl[MAXOCLASSES+1]; flags.pickup = !flags.pickup; if (flags.pickup) { oc_to_str(flags.pickup_types, ocl); Sprintf(buf, "ON, for %s objects%s", ocl[0] ? ocl : "all", #ifdef AUTOPICKUP_EXCEPTIONS (iflags.autopickup_exceptions[AP_LEAVE] || iflags.autopickup_exceptions[AP_GRAB]) ? ((count_ape_maps((int *)0, (int *)0) == 1) ? ", with one exception" : ", with some exceptions") : #endif ""); } else { Strcpy(buf, "OFF"); } pline("Autopickup: %s.", buf); return 0; } #ifdef AUTOPICKUP_EXCEPTIONS int add_autopickup_exception(mapping) const char *mapping; { struct autopickup_exception *ape, **apehead; char text[256], *text2; int textsize = 0; boolean grab = FALSE; if (sscanf(mapping, "\"%255[^\"]\"", text) == 1) { text2 = &text[0]; if (*text2 == '<') { /* force autopickup */ grab = TRUE; ++text2; } else if (*text2 == '>') { /* default - Do not pickup */ grab = FALSE; ++text2; } textsize = strlen(text2); apehead = (grab) ? &iflags.autopickup_exceptions[AP_GRAB] : &iflags.autopickup_exceptions[AP_LEAVE]; ape = (struct autopickup_exception *) alloc(sizeof(struct autopickup_exception)); ape->pattern = (char *) alloc(textsize+1); Strcpy(ape->pattern, text2); ape->grab = grab; if (!*apehead) ape->next = (struct autopickup_exception *)0; else ape->next = *apehead; *apehead = ape; } else { raw_print("syntax error in AUTOPICKUP_EXCEPTION"); return 0; } return 1; } STATIC_OVL void remove_autopickup_exception(whichape) struct autopickup_exception *whichape; { struct autopickup_exception *ape, *prev = 0; int chain = whichape->grab ? AP_GRAB : AP_LEAVE; for (ape = iflags.autopickup_exceptions[chain]; ape;) { if (ape == whichape) { struct autopickup_exception *freeape = ape; ape = ape->next; if (prev) prev->next = ape; else iflags.autopickup_exceptions[chain] = ape; free(freeape->pattern); free(freeape); } else { prev = ape; ape = ape->next; } } } STATIC_OVL int count_ape_maps(leave, grab) int *leave, *grab; { struct autopickup_exception *ape; int pass, totalapes, numapes[2] = {0,0}; for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { ape = iflags.autopickup_exceptions[pass]; while(ape) { ape = ape->next; numapes[pass]++; } } totalapes = numapes[AP_LEAVE] + numapes[AP_GRAB]; if (leave) *leave = numapes[AP_LEAVE]; if (grab) *grab = numapes[AP_GRAB]; return totalapes; } void free_autopickup_exceptions() { struct autopickup_exception *ape; int pass; for (pass = AP_LEAVE; pass <= AP_GRAB; ++pass) { while((ape = iflags.autopickup_exceptions[pass]) != 0) { free(ape->pattern); iflags.autopickup_exceptions[pass] = ape->next; free(ape); } } } #endif /* AUTOPICKUP_EXCEPTIONS */ /* data for option_help() */ static const char *opt_intro[] = { "", " NetHack Options Help:", "", #define CONFIG_SLOT 3 /* fill in next value at run-time */ (char *)0, #if !defined(MICRO) && !defined(MAC) "or use `NETHACKOPTIONS=\"\"' in your environment", #endif "( is a list of options separated by commas)", #ifdef VMS "-- for example, $ DEFINE NETHACKOPTIONS \"noautopickup,fruit:kumquat\"", #endif "or press \"O\" while playing and use the menu.", "", "Boolean options (which can be negated by prefixing them with '!' or \"no\"):", (char *)0 }; static const char *opt_epilog[] = { "", "Some of the options can be set only before the game is started; those", "items will not be selectable in the 'O' command's menu.", (char *)0 }; void option_help() { char buf[BUFSZ], buf2[BUFSZ]; register int i; winid datawin; datawin = create_nhwindow(NHW_TEXT); Sprintf(buf, "Set options as OPTIONS= in %s", configfile); opt_intro[CONFIG_SLOT] = (const char *) buf; for (i = 0; opt_intro[i]; i++) putstr(datawin, 0, opt_intro[i]); /* Boolean options */ for (i = 0; boolopt[i].name; i++) { if (boolopt[i].addr) { #ifdef WIZARD if (boolopt[i].addr == &iflags.sanity_check && !wizard) continue; if (boolopt[i].addr == &iflags.menu_tab_sep && !wizard) continue; #endif next_opt(datawin, boolopt[i].name); } } next_opt(datawin, ""); /* Compound options */ putstr(datawin, 0, "Compound options:"); for (i = 0; compopt[i].name; i++) { Sprintf(buf2, "`%s'", compopt[i].name); Sprintf(buf, "%-20s - %s%c", buf2, compopt[i].descr, compopt[i+1].name ? ',' : '.'); putstr(datawin, 0, buf); } for (i = 0; opt_epilog[i]; i++) putstr(datawin, 0, opt_epilog[i]); display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); return; } /* * prints the next boolean option, on the same line if possible, on a new * line if not. End with next_opt(""). */ void next_opt(datawin, str) winid datawin; const char *str; { static char *buf = 0; int i; char *s; if (!buf) *(buf = (char *)alloc(BUFSZ)) = '\0'; if (!*str) { s = eos(buf); if (s > &buf[1] && s[-2] == ',') Strcpy(s - 2, "."); /* replace last ", " */ i = COLNO; /* (greater than COLNO - 2) */ } else { i = strlen(buf) + strlen(str) + 2; } if (i > COLNO - 2) { /* rule of thumb */ putstr(datawin, 0, buf); buf[0] = 0; } if (*str) { Strcat(buf, str); Strcat(buf, ", "); } else { putstr(datawin, 0, str); free(buf), buf = 0; } return; } /* Returns the fid of the fruit type; if that type already exists, it * returns the fid of that one; if it does not exist, it adds a new fruit * type to the chain and returns the new one. */ int fruitadd(str) char *str; { register int i; register struct fruit *f; struct fruit *lastf = 0; int highest_fruit_id = 0; char buf[PL_FSIZ]; boolean user_specified = (str == pl_fruit); /* if not user-specified, then it's a fruit name for a fruit on * a bones level... */ /* Note: every fruit has an id (spe for fruit objects) of at least * 1; 0 is an error. */ if (user_specified) { /* disallow naming after other foods (since it'd be impossible * to tell the difference) */ boolean found = FALSE, numeric = FALSE; for (i = bases[FOOD_CLASS]; objects[i].oc_class == FOOD_CLASS; i++) { if (!strcmp(OBJ_NAME(objects[i]), pl_fruit)) { found = TRUE; break; } } { char *c; c = pl_fruit; for(c = pl_fruit; *c >= '0' && *c <= '9'; c++) ; if (isspace(*c) || *c == 0) numeric = TRUE; } if (found || numeric || !strncmp(str, "cursed ", 7) || !strncmp(str, "uncursed ", 9) || !strncmp(str, "blessed ", 8) || !strncmp(str, "partly eaten ", 13) || (!strncmp(str, "tin of ", 7) && (!strcmp(str+7, "spinach") || name_to_mon(str+7) >= LOW_PM)) || !strcmp(str, "empty tin") || ((!strncmp(eos(str)-7," corpse",7) || !strncmp(eos(str)-4, " egg",4)) && name_to_mon(str) >= LOW_PM)) { Strcpy(buf, pl_fruit); Strcpy(pl_fruit, "candied "); nmcpy(pl_fruit+8, buf, PL_FSIZ-8); } } for(f=ffruit; f; f = f->nextf) { lastf = f; if(f->fid > highest_fruit_id) highest_fruit_id = f->fid; if(!strncmp(str, f->fname, PL_FSIZ)) goto nonew; } /* if adding another fruit would overflow spe, use a random fruit instead... we've got a lot to choose from. */ if (highest_fruit_id >= 127) return rnd(127); highest_fruit_id++; f = newfruit(); if (ffruit) lastf->nextf = f; else ffruit = f; Strcpy(f->fname, str); f->fid = highest_fruit_id; f->nextf = 0; nonew: if (user_specified) current_fruit = highest_fruit_id; return f->fid; } /* * This is a somewhat generic menu for taking a list of NetHack style * class choices and presenting them via a description * rather than the traditional NetHack characters. * (Benefits users whose first exposure to NetHack is via tiles). * * prompt * The title at the top of the menu. * * category: 0 = monster class * 1 = object class * * way * FALSE = PICK_ONE, TRUE = PICK_ANY * * class_list * a null terminated string containing the list of choices. * * class_selection * a null terminated string containing the selected characters. * * Returns number selected. */ int choose_classes_menu(prompt, category, way, class_list, class_select) const char *prompt; int category; boolean way; char *class_list; char *class_select; { menu_item *pick_list = (menu_item *)0; winid win; anything any; char buf[BUFSZ]; int i, n; int ret; int next_accelerator, accelerator; if (class_list == (char *)0 || class_select == (char *)0) return 0; accelerator = 0; next_accelerator = 'a'; any.a_void = 0; win = create_nhwindow(NHW_MENU); start_menu(win); while (*class_list) { const char *text; boolean selected; text = (char *)0; selected = FALSE; switch (category) { case 0: text = monexplain[def_char_to_monclass(*class_list)]; accelerator = *class_list; Sprintf(buf, "%s", text); break; case 1: text = objexplain[def_char_to_objclass(*class_list)]; accelerator = next_accelerator; Sprintf(buf, "%c %s", *class_list, text); break; default: impossible("choose_classes_menu: invalid category %d", category); } if (way && *class_select) { /* Selections there already */ if (index(class_select, *class_list)) { selected = TRUE; } } any.a_int = *class_list; add_menu(win, NO_GLYPH, &any, accelerator, category ? *class_list : 0, ATR_NONE, buf, selected); ++class_list; if (category > 0) { ++next_accelerator; if (next_accelerator == ('z' + 1)) next_accelerator = 'A'; if (next_accelerator == ('Z' + 1)) break; } } end_menu(win, prompt); n = select_menu(win, way ? PICK_ANY : PICK_ONE, &pick_list); destroy_nhwindow(win); if (n > 0) { for (i = 0; i < n; ++i) *class_select++ = (char)pick_list[i].item.a_int; free((genericptr_t)pick_list); ret = n; } else if (n == -1) { class_select = eos(class_select); ret = -1; } else ret = 0; *class_select = '\0'; return ret; } struct wc_Opt wc_options[] = { {"ascii_map", WC_ASCII_MAP}, {"color", WC_COLOR}, {"eight_bit_tty", WC_EIGHT_BIT_IN}, {"hilite_pet", WC_HILITE_PET}, {"popup_dialog", WC_POPUP_DIALOG}, {"player_selection", WC_PLAYER_SELECTION}, {"preload_tiles", WC_PRELOAD_TILES}, {"tiled_map", WC_TILED_MAP}, {"tile_file", WC_TILE_FILE}, {"tile_width", WC_TILE_WIDTH}, {"tile_height", WC_TILE_HEIGHT}, {"use_inverse", WC_INVERSE}, {"align_message", WC_ALIGN_MESSAGE}, {"align_status", WC_ALIGN_STATUS}, {"font_map", WC_FONT_MAP}, {"font_menu", WC_FONT_MENU}, {"font_message",WC_FONT_MESSAGE}, #if 0 {"perm_invent",WC_PERM_INVENT}, #endif {"font_size_map", WC_FONTSIZ_MAP}, {"font_size_menu", WC_FONTSIZ_MENU}, {"font_size_message", WC_FONTSIZ_MESSAGE}, {"font_size_status", WC_FONTSIZ_STATUS}, {"font_size_text", WC_FONTSIZ_TEXT}, {"font_status", WC_FONT_STATUS}, {"font_text", WC_FONT_TEXT}, {"map_mode", WC_MAP_MODE}, {"scroll_amount", WC_SCROLL_AMOUNT}, {"scroll_margin", WC_SCROLL_MARGIN}, {"splash_screen", WC_SPLASH_SCREEN}, {"vary_msgcount",WC_VARY_MSGCOUNT}, {"windowcolors", WC_WINDOWCOLORS}, {"mouse_support", WC_MOUSE_SUPPORT}, {(char *)0, 0L} }; struct wc_Opt wc2_options[] = { {"fullscreen", WC2_FULLSCREEN}, {"softkeyboard", WC2_SOFTKEYBOARD}, {"wraptext", WC2_WRAPTEXT}, {(char *)0, 0L} }; /* * If a port wants to change or ensure that the * SET_IN_FILE, DISP_IN_GAME, or SET_IN_GAME status of an option is * correct (for controlling its display in the option menu) call * set_option_mod_status() * with the second argument of 0,2, or 3 respectively. */ void set_option_mod_status(optnam, status) const char *optnam; int status; { int k; if (status < SET_IN_FILE || status > SET_IN_GAME) { impossible("set_option_mod_status: status out of range %d.", status); return; } for (k = 0; boolopt[k].name; k++) { if (!strncmpi(boolopt[k].name, optnam, strlen(optnam))) { boolopt[k].optflags = status; return; } } for (k = 0; compopt[k].name; k++) { if (!strncmpi(compopt[k].name, optnam, strlen(optnam))) { compopt[k].optflags = status; return; } } } /* * You can set several wc_options in one call to * set_wc_option_mod_status() by setting * the appropriate bits for each option that you * are setting in the optmask argument * prior to calling. * example: set_wc_option_mod_status(WC_COLOR|WC_SCROLL_MARGIN, SET_IN_GAME); */ void set_wc_option_mod_status(optmask, status) unsigned long optmask; int status; { int k = 0; if (status < SET_IN_FILE || status > SET_IN_GAME) { impossible("set_wc_option_mod_status: status out of range %d.", status); return; } while (wc_options[k].wc_name) { if (optmask & wc_options[k].wc_bit) { set_option_mod_status(wc_options[k].wc_name, status); } k++; } } STATIC_OVL boolean is_wc_option(optnam) const char *optnam; { int k = 0; while (wc_options[k].wc_name) { if (strcmp(wc_options[k].wc_name, optnam) == 0) return TRUE; k++; } return FALSE; } STATIC_OVL boolean wc_supported(optnam) const char *optnam; { int k = 0; while (wc_options[k].wc_name) { if (!strcmp(wc_options[k].wc_name, optnam) && (windowprocs.wincap & wc_options[k].wc_bit)) return TRUE; k++; } return FALSE; } /* * You can set several wc2_options in one call to * set_wc2_option_mod_status() by setting * the appropriate bits for each option that you * are setting in the optmask argument * prior to calling. * example: set_wc2_option_mod_status(WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, SET_IN_FILE); */ void set_wc2_option_mod_status(optmask, status) unsigned long optmask; int status; { int k = 0; if (status < SET_IN_FILE || status > SET_IN_GAME) { impossible("set_wc2_option_mod_status: status out of range %d.", status); return; } while (wc2_options[k].wc_name) { if (optmask & wc2_options[k].wc_bit) { set_option_mod_status(wc2_options[k].wc_name, status); } k++; } } STATIC_OVL boolean is_wc2_option(optnam) const char *optnam; { int k = 0; while (wc2_options[k].wc_name) { if (strcmp(wc2_options[k].wc_name, optnam) == 0) return TRUE; k++; } return FALSE; } STATIC_OVL boolean wc2_supported(optnam) const char *optnam; { int k = 0; while (wc2_options[k].wc_name) { if (!strcmp(wc2_options[k].wc_name, optnam) && (windowprocs.wincap2 & wc2_options[k].wc_bit)) return TRUE; k++; } return FALSE; } STATIC_OVL void wc_set_font_name(wtype, fontname) int wtype; char *fontname; { char **fn = (char **)0; if (!fontname) return; switch(wtype) { case NHW_MAP: fn = &iflags.wc_font_map; break; case NHW_MESSAGE: fn = &iflags.wc_font_message; break; case NHW_TEXT: fn = &iflags.wc_font_text; break; case NHW_MENU: fn = &iflags.wc_font_menu; break; case NHW_STATUS: fn = &iflags.wc_font_status; break; default: return; } if (fn) { if (*fn) free(*fn); *fn = (char *)alloc(strlen(fontname) + 1); Strcpy(*fn, fontname); } return; } STATIC_OVL int wc_set_window_colors(op) char *op; { /* syntax: * menu white/black message green/yellow status white/blue text white/black */ int j; char buf[BUFSZ]; char *wn, *tfg, *tbg, *newop; static const char *wnames[] = { "menu", "message", "status", "text" }; static const char *shortnames[] = { "mnu", "msg", "sts", "txt" }; static char **fgp[] = { &iflags.wc_foregrnd_menu, &iflags.wc_foregrnd_message, &iflags.wc_foregrnd_status, &iflags.wc_foregrnd_text }; static char **bgp[] = { &iflags.wc_backgrnd_menu, &iflags.wc_backgrnd_message, &iflags.wc_backgrnd_status, &iflags.wc_backgrnd_text }; Strcpy(buf, op); newop = mungspaces(buf); while (newop && *newop) { wn = tfg = tbg = (char *)0; /* until first non-space in case there's leading spaces - before colorname*/ while(*newop && isspace(*newop)) newop++; if (*newop) wn = newop; else return 0; /* until first space - colorname*/ while(*newop && !isspace(*newop)) newop++; if (*newop) *newop = '\0'; else return 0; newop++; /* until first non-space - before foreground*/ while(*newop && isspace(*newop)) newop++; if (*newop) tfg = newop; else return 0; /* until slash - foreground */ while(*newop && *newop != '/') newop++; if (*newop) *newop = '\0'; else return 0; newop++; /* until first non-space (in case there's leading space after slash) - before background */ while(*newop && isspace(*newop)) newop++; if (*newop) tbg = newop; else return 0; /* until first space - background */ while(*newop && !isspace(*newop)) newop++; if (*newop) *newop++ = '\0'; for (j = 0; j < 4; ++j) { if (!strcmpi(wn, wnames[j]) || !strcmpi(wn, shortnames[j])) { if (tfg && !strstri(tfg, " ")) { if (*fgp[j]) free(*fgp[j]); *fgp[j] = (char *)alloc(strlen(tfg) + 1); Strcpy(*fgp[j], tfg); } if (tbg && !strstri(tbg, " ")) { if (*bgp[j]) free(*bgp[j]); *bgp[j] = (char *)alloc(strlen(tbg) + 1); Strcpy(*bgp[j], tbg); } break; } } } return 1; } #endif /* OPTION_LISTS_ONLY */ /*options.c*/ nethack-3.4.3/src/pager.c0100644000000000000000000006552507764735041013720 0ustar rootroot/* SCCS Id: @(#)pager.c 3.4 2003/08/13 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file contains the command routines dowhatis() and dohelp() and */ /* a few other help related facilities */ #include "hack.h" #include "dlb.h" STATIC_DCL boolean FDECL(is_swallow_sym, (int)); STATIC_DCL int FDECL(append_str, (char *, const char *)); STATIC_DCL struct permonst * FDECL(lookat, (int, int, char *, char *)); STATIC_DCL void FDECL(checkfile, (char *,struct permonst *,BOOLEAN_P,BOOLEAN_P)); STATIC_DCL int FDECL(do_look, (BOOLEAN_P)); STATIC_DCL boolean FDECL(help_menu, (int *)); #ifdef PORT_HELP extern void NDECL(port_help); #endif /* Returns "true" for characters that could represent a monster's stomach. */ STATIC_OVL boolean is_swallow_sym(c) int c; { int i; for (i = S_sw_tl; i <= S_sw_br; i++) if ((int)showsyms[i] == c) return TRUE; return FALSE; } /* * Append new_str to the end of buf if new_str doesn't already exist as * a substring of buf. Return 1 if the string was appended, 0 otherwise. * It is expected that buf is of size BUFSZ. */ STATIC_OVL int append_str(buf, new_str) char *buf; const char *new_str; { int space_left; /* space remaining in buf */ if (strstri(buf, new_str)) return 0; space_left = BUFSZ - strlen(buf) - 1; (void) strncat(buf, " or ", space_left); (void) strncat(buf, new_str, space_left - 4); return 1; } /* * Return the name of the glyph found at (x,y). * If not hallucinating and the glyph is a monster, also monster data. */ STATIC_OVL struct permonst * lookat(x, y, buf, monbuf) int x, y; char *buf, *monbuf; { register struct monst *mtmp = (struct monst *) 0; struct permonst *pm = (struct permonst *) 0; int glyph; buf[0] = monbuf[0] = 0; glyph = glyph_at(x,y); if (u.ux == x && u.uy == y && senseself()) { char race[QBUFSZ]; /* if not polymorphed, show both the role and the race */ race[0] = 0; if (!Upolyd) { Sprintf(race, "%s ", urace.adj); } Sprintf(buf, "%s%s%s called %s", Invis ? "invisible " : "", race, mons[u.umonnum].mname, plname); /* file lookup can't distinguish between "gnomish wizard" monster and correspondingly named player character, always picking the former; force it to find the general "wizard" entry instead */ if (Role_if(PM_WIZARD) && Race_if(PM_GNOME) && !Upolyd) pm = &mons[PM_WIZARD]; #ifdef STEED if (u.usteed) { char steedbuf[BUFSZ]; Sprintf(steedbuf, ", mounted on %s", y_monnam(u.usteed)); /* assert((sizeof buf >= strlen(buf)+strlen(steedbuf)+1); */ Strcat(buf, steedbuf); } #endif /* When you see yourself normally, no explanation is appended (even if you could also see yourself via other means). Sensing self while blind or swallowed is treated as if it were by normal vision (cf canseeself()). */ if ((Invisible || u.uundetected) && !Blind && !u.uswallow) { unsigned how = 0; if (Infravision) how |= 1; if (Unblind_telepat) how |= 2; if (Detect_monsters) how |= 4; if (how) Sprintf(eos(buf), " [seen: %s%s%s%s%s]", (how & 1) ? "infravision" : "", /* add comma if telep and infrav */ ((how & 3) > 2) ? ", " : "", (how & 2) ? "telepathy" : "", /* add comma if detect and (infrav or telep or both) */ ((how & 7) > 4) ? ", " : "", (how & 4) ? "monster detection" : ""); } } else if (u.uswallow) { /* all locations when swallowed other than the hero are the monster */ Sprintf(buf, "interior of %s", Blind ? "a monster" : a_monnam(u.ustuck)); pm = u.ustuck->data; } else if (glyph_is_monster(glyph)) { bhitpos.x = x; bhitpos.y = y; mtmp = m_at(x,y); if (mtmp != (struct monst *) 0) { char *name, monnambuf[BUFSZ]; boolean accurate = !Hallucination; if (mtmp->data == &mons[PM_COYOTE] && accurate) name = coyotename(mtmp, monnambuf); else name = distant_monnam(mtmp, ARTICLE_NONE, monnambuf); pm = mtmp->data; Sprintf(buf, "%s%s%s", (mtmp->mx != x || mtmp->my != y) ? ((mtmp->isshk && accurate) ? "tail of " : "tail of a ") : "", (mtmp->mtame && accurate) ? "tame " : (mtmp->mpeaceful && accurate) ? "peaceful " : "", name); if (u.ustuck == mtmp) Strcat(buf, (Upolyd && sticks(youmonst.data)) ? ", being held" : ", holding you"); if (mtmp->mleashed) Strcat(buf, ", leashed to you"); if (mtmp->mtrapped && cansee(mtmp->mx, mtmp->my)) { struct trap *t = t_at(mtmp->mx, mtmp->my); int tt = t ? t->ttyp : NO_TRAP; /* newsym lets you know of the trap, so mention it here */ if (tt == BEAR_TRAP || tt == PIT || tt == SPIKED_PIT || tt == WEB) Sprintf(eos(buf), ", trapped in %s", an(defsyms[trap_to_defsym(tt)].explanation)); } { int ways_seen = 0, normal = 0, xraydist; boolean useemon = (boolean) canseemon(mtmp); xraydist = (u.xray_range<0) ? -1 : u.xray_range * u.xray_range; /* normal vision */ if ((mtmp->wormno ? worm_known(mtmp) : cansee(mtmp->mx, mtmp->my)) && mon_visible(mtmp) && !mtmp->minvis) { ways_seen++; normal++; } /* see invisible */ if (useemon && mtmp->minvis) ways_seen++; /* infravision */ if ((!mtmp->minvis || See_invisible) && see_with_infrared(mtmp)) ways_seen++; /* telepathy */ if (tp_sensemon(mtmp)) ways_seen++; /* xray */ if (useemon && xraydist > 0 && distu(mtmp->mx, mtmp->my) <= xraydist) ways_seen++; if (Detect_monsters) ways_seen++; if (MATCH_WARN_OF_MON(mtmp)) ways_seen++; if (ways_seen > 1 || !normal) { if (normal) { Strcat(monbuf, "normal vision"); /* can't actually be 1 yet here */ if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (useemon && mtmp->minvis) { Strcat(monbuf, "see invisible"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if ((!mtmp->minvis || See_invisible) && see_with_infrared(mtmp)) { Strcat(monbuf, "infravision"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (tp_sensemon(mtmp)) { Strcat(monbuf, "telepathy"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (useemon && xraydist > 0 && distu(mtmp->mx, mtmp->my) <= xraydist) { /* Eyes of the Overworld */ Strcat(monbuf, "astral vision"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (Detect_monsters) { Strcat(monbuf, "monster detection"); if (ways_seen-- > 1) Strcat(monbuf, ", "); } if (MATCH_WARN_OF_MON(mtmp)) { char wbuf[BUFSZ]; if (Hallucination) Strcat(monbuf, "paranoid delusion"); else { Sprintf(wbuf, "warned of %s", makeplural(mtmp->data->mname)); Strcat(monbuf, wbuf); } if (ways_seen-- > 1) Strcat(monbuf, ", "); } } } } } else if (glyph_is_object(glyph)) { struct obj *otmp = vobj_at(x,y); if (!otmp || otmp->otyp != glyph_to_obj(glyph)) { if (glyph_to_obj(glyph) != STRANGE_OBJECT) { otmp = mksobj(glyph_to_obj(glyph), FALSE, FALSE); if (otmp->oclass == COIN_CLASS) otmp->quan = 2L; /* to force pluralization */ else if (otmp->otyp == SLIME_MOLD) otmp->spe = current_fruit; /* give the fruit a type */ Strcpy(buf, distant_name(otmp, xname)); dealloc_obj(otmp); } } else Strcpy(buf, distant_name(otmp, xname)); if (levl[x][y].typ == STONE || levl[x][y].typ == SCORR) Strcat(buf, " embedded in stone"); else if (IS_WALL(levl[x][y].typ) || levl[x][y].typ == SDOOR) Strcat(buf, " embedded in a wall"); else if (closed_door(x,y)) Strcat(buf, " embedded in a door"); else if (is_pool(x,y)) Strcat(buf, " in water"); else if (is_lava(x,y)) Strcat(buf, " in molten lava"); /* [can this ever happen?] */ } else if (glyph_is_trap(glyph)) { int tnum = what_trap(glyph_to_trap(glyph)); Strcpy(buf, defsyms[trap_to_defsym(tnum)].explanation); } else if(!glyph_is_cmap(glyph)) { Strcpy(buf,"dark part of a room"); } else switch(glyph_to_cmap(glyph)) { case S_altar: if(!In_endgame(&u.uz)) Sprintf(buf, "%s altar", align_str(Amask2align(levl[x][y].altarmask & ~AM_SHRINE))); else Sprintf(buf, "aligned altar"); break; case S_ndoor: if (is_drawbridge_wall(x, y) >= 0) Strcpy(buf,"open drawbridge portcullis"); else if ((levl[x][y].doormask & ~D_TRAPPED) == D_BROKEN) Strcpy(buf,"broken door"); else Strcpy(buf,"doorway"); break; case S_cloud: Strcpy(buf, Is_airlevel(&u.uz) ? "cloudy area" : "fog/vapor cloud"); break; default: Strcpy(buf,defsyms[glyph_to_cmap(glyph)].explanation); break; } return ((pm && !Hallucination) ? pm : (struct permonst *) 0); } /* * Look in the "data" file for more info. Called if the user typed in the * whole name (user_typed_name == TRUE), or we've found a possible match * with a character/glyph and flags.help is TRUE. * * NOTE: when (user_typed_name == FALSE), inp is considered read-only and * must not be changed directly, e.g. via lcase(). We want to force * lcase() for data.base lookup so that we can have a clean key. * Therefore, we create a copy of inp _just_ for data.base lookup. */ STATIC_OVL void checkfile(inp, pm, user_typed_name, without_asking) char *inp; struct permonst *pm; boolean user_typed_name, without_asking; { dlb *fp; char buf[BUFSZ], newstr[BUFSZ]; char *ep, *dbase_str; long txt_offset; int chk_skip; boolean found_in_file = FALSE, skipping_entry = FALSE; fp = dlb_fopen(DATAFILE, "r"); if (!fp) { pline("Cannot open data file!"); return; } /* To prevent the need for entries in data.base like *ngel to account * for Angel and angel, make the lookup string the same for both * user_typed_name and picked name. */ if (pm != (struct permonst *) 0 && !user_typed_name) dbase_str = strcpy(newstr, pm->mname); else dbase_str = strcpy(newstr, inp); (void) lcase(dbase_str); if (!strncmp(dbase_str, "interior of ", 12)) dbase_str += 12; if (!strncmp(dbase_str, "a ", 2)) dbase_str += 2; else if (!strncmp(dbase_str, "an ", 3)) dbase_str += 3; else if (!strncmp(dbase_str, "the ", 4)) dbase_str += 4; if (!strncmp(dbase_str, "tame ", 5)) dbase_str += 5; else if (!strncmp(dbase_str, "peaceful ", 9)) dbase_str += 9; if (!strncmp(dbase_str, "invisible ", 10)) dbase_str += 10; if (!strncmp(dbase_str, "statue of ", 10)) dbase_str[6] = '\0'; else if (!strncmp(dbase_str, "figurine of ", 12)) dbase_str[8] = '\0'; /* Make sure the name is non-empty. */ if (*dbase_str) { /* adjust the input to remove "named " and convert to lower case */ char *alt = 0; /* alternate description */ if ((ep = strstri(dbase_str, " named ")) != 0) alt = ep + 7; else ep = strstri(dbase_str, " called "); if (!ep) ep = strstri(dbase_str, ", "); if (ep && ep > dbase_str) *ep = '\0'; /* * If the object is named, then the name is the alternate description; * otherwise, the result of makesingular() applied to the name is. This * isn't strictly optimal, but named objects of interest to the user * will usually be found under their name, rather than under their * object type, so looking for a singular form is pointless. */ if (!alt) alt = makesingular(dbase_str); else if (user_typed_name) (void) lcase(alt); /* skip first record; read second */ txt_offset = 0L; if (!dlb_fgets(buf, BUFSZ, fp) || !dlb_fgets(buf, BUFSZ, fp)) { impossible("can't read 'data' file"); (void) dlb_fclose(fp); return; } else if (sscanf(buf, "%8lx\n", &txt_offset) < 1 || txt_offset <= 0) goto bad_data_file; /* look for the appropriate entry */ while (dlb_fgets(buf,BUFSZ,fp)) { if (*buf == '.') break; /* we passed last entry without success */ if (digit(*buf)) { /* a number indicates the end of current entry */ skipping_entry = FALSE; } else if (!skipping_entry) { if (!(ep = index(buf, '\n'))) goto bad_data_file; *ep = 0; /* if we match a key that begins with "~", skip this entry */ chk_skip = (*buf == '~') ? 1 : 0; if (pmatch(&buf[chk_skip], dbase_str) || (alt && pmatch(&buf[chk_skip], alt))) { if (chk_skip) { skipping_entry = TRUE; continue; } else { found_in_file = TRUE; break; } } } } } if(found_in_file) { long entry_offset; int entry_count; int i; /* skip over other possible matches for the info */ do { if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file; } while (!digit(*buf)); if (sscanf(buf, "%ld,%d\n", &entry_offset, &entry_count) < 2) { bad_data_file: impossible("'data' file in wrong format"); (void) dlb_fclose(fp); return; } if (user_typed_name || without_asking || yn("More info?") == 'y') { winid datawin; if (dlb_fseek(fp, txt_offset + entry_offset, SEEK_SET) < 0) { pline("? Seek error on 'data' file!"); (void) dlb_fclose(fp); return; } datawin = create_nhwindow(NHW_MENU); for (i = 0; i < entry_count; i++) { if (!dlb_fgets(buf, BUFSZ, fp)) goto bad_data_file; if ((ep = index(buf, '\n')) != 0) *ep = 0; if (index(buf+1, '\t') != 0) (void) tabexpand(buf+1); putstr(datawin, 0, buf+1); } display_nhwindow(datawin, FALSE); destroy_nhwindow(datawin); } } else if (user_typed_name) pline("I don't have any information on those things."); (void) dlb_fclose(fp); } /* getpos() return values */ #define LOOK_TRADITIONAL 0 /* '.' -- ask about "more info?" */ #define LOOK_QUICK 1 /* ',' -- skip "more info?" */ #define LOOK_ONCE 2 /* ';' -- skip and stop looping */ #define LOOK_VERBOSE 3 /* ':' -- show more info w/o asking */ /* also used by getpos hack in do_name.c */ const char what_is_an_unknown_object[] = "an unknown object"; STATIC_OVL int do_look(quick) boolean quick; /* use cursor && don't search for "more info" */ { char out_str[BUFSZ], look_buf[BUFSZ]; const char *x_str, *firstmatch = 0; struct permonst *pm = 0; int i, ans = 0; int sym; /* typed symbol or converted glyph */ int found; /* count of matching syms found */ coord cc; /* screen pos of unknown glyph */ boolean save_verbose; /* saved value of flags.verbose */ boolean from_screen; /* question from the screen */ boolean need_to_look; /* need to get explan. from glyph */ boolean hit_trap; /* true if found trap explanation */ int skipped_venom; /* non-zero if we ignored "splash of venom" */ static const char *mon_interior = "the interior of a monster"; if (quick) { from_screen = TRUE; /* yes, we want to use the cursor */ } else { i = ynq("Specify unknown object by cursor?"); if (i == 'q') return 0; from_screen = (i == 'y'); } if (from_screen) { cc.x = u.ux; cc.y = u.uy; sym = 0; /* gcc -Wall lint */ } else { getlin("Specify what? (type the word)", out_str); if (out_str[0] == '\0' || out_str[0] == '\033') return 0; if (out_str[1]) { /* user typed in a complete string */ checkfile(out_str, pm, TRUE, TRUE); return 0; } sym = out_str[0]; } /* Save the verbose flag, we change it later. */ save_verbose = flags.verbose; flags.verbose = flags.verbose && !quick; /* * The user typed one letter, or we're identifying from the screen. */ do { /* Reset some variables. */ need_to_look = FALSE; pm = (struct permonst *)0; skipped_venom = 0; found = 0; out_str[0] = '\0'; if (from_screen) { int glyph; /* glyph at selected position */ if (flags.verbose) pline("Please move the cursor to %s.", what_is_an_unknown_object); else pline("Pick an object."); ans = getpos(&cc, quick, what_is_an_unknown_object); if (ans < 0 || cc.x < 0) { flags.verbose = save_verbose; return 0; /* done */ } flags.verbose = FALSE; /* only print long question once */ /* Convert the glyph at the selected position to a symbol. */ glyph = glyph_at(cc.x,cc.y); if (glyph_is_cmap(glyph)) { sym = showsyms[glyph_to_cmap(glyph)]; } else if (glyph_is_trap(glyph)) { sym = showsyms[trap_to_defsym(glyph_to_trap(glyph))]; } else if (glyph_is_object(glyph)) { sym = oc_syms[(int)objects[glyph_to_obj(glyph)].oc_class]; if (sym == '`' && iflags.bouldersym && (int)glyph_to_obj(glyph) == BOULDER) sym = iflags.bouldersym; } else if (glyph_is_monster(glyph)) { /* takes care of pets, detected, ridden, and regular mons */ sym = monsyms[(int)mons[glyph_to_mon(glyph)].mlet]; } else if (glyph_is_swallow(glyph)) { sym = showsyms[glyph_to_swallow(glyph)+S_sw_tl]; } else if (glyph_is_invisible(glyph)) { sym = DEF_INVISIBLE; } else if (glyph_is_warning(glyph)) { sym = glyph_to_warning(glyph); sym = warnsyms[sym]; } else { impossible("do_look: bad glyph %d at (%d,%d)", glyph, (int)cc.x, (int)cc.y); sym = ' '; } } /* * Check all the possibilities, saving all explanations in a buffer. * When all have been checked then the string is printed. */ /* Check for monsters */ for (i = 0; i < MAXMCLASSES; i++) { if (sym == (from_screen ? monsyms[i] : def_monsyms[i]) && monexplain[i]) { need_to_look = TRUE; if (!found) { Sprintf(out_str, "%c %s", sym, an(monexplain[i])); firstmatch = monexplain[i]; found++; } else { found += append_str(out_str, an(monexplain[i])); } } } /* handle '@' as a special case if it refers to you and you're playing a character which isn't normally displayed by that symbol; firstmatch is assumed to already be set for '@' */ if ((from_screen ? (sym == monsyms[S_HUMAN] && cc.x == u.ux && cc.y == u.uy) : (sym == def_monsyms[S_HUMAN] && !iflags.showrace)) && !(Race_if(PM_HUMAN) || Race_if(PM_ELF)) && !Upolyd) found += append_str(out_str, "you"); /* tack on "or you" */ /* * Special case: if identifying from the screen, and we're swallowed, * and looking at something other than our own symbol, then just say * "the interior of a monster". */ if (u.uswallow && from_screen && is_swallow_sym(sym)) { if (!found) { Sprintf(out_str, "%c %s", sym, mon_interior); firstmatch = mon_interior; } else { found += append_str(out_str, mon_interior); } need_to_look = TRUE; } /* Now check for objects */ for (i = 1; i < MAXOCLASSES; i++) { if (sym == (from_screen ? oc_syms[i] : def_oc_syms[i])) { need_to_look = TRUE; if (from_screen && i == VENOM_CLASS) { skipped_venom++; continue; } if (!found) { Sprintf(out_str, "%c %s", sym, an(objexplain[i])); firstmatch = objexplain[i]; found++; } else { found += append_str(out_str, an(objexplain[i])); } } } if (sym == DEF_INVISIBLE) { if (!found) { Sprintf(out_str, "%c %s", sym, an(invisexplain)); firstmatch = invisexplain; found++; } else { found += append_str(out_str, an(invisexplain)); } } #define is_cmap_trap(i) ((i) >= S_arrow_trap && (i) <= S_polymorph_trap) #define is_cmap_drawbridge(i) ((i) >= S_vodbridge && (i) <= S_hcdbridge) /* Now check for graphics symbols */ for (hit_trap = FALSE, i = 0; i < MAXPCHARS; i++) { x_str = defsyms[i].explanation; if (sym == (from_screen ? showsyms[i] : defsyms[i].sym) && *x_str) { /* avoid "an air", "a water", or "a floor of a room" */ int article = (i == S_room) ? 2 : /* 2=>"the" */ !(strcmp(x_str, "air") == 0 || /* 1=>"an" */ strcmp(x_str, "water") == 0); /* 0=>(none)*/ if (!found) { if (is_cmap_trap(i)) { Sprintf(out_str, "%c a trap", sym); hit_trap = TRUE; } else { Sprintf(out_str, "%c %s", sym, article == 2 ? the(x_str) : article == 1 ? an(x_str) : x_str); } firstmatch = x_str; found++; } else if (!u.uswallow && !(hit_trap && is_cmap_trap(i)) && !(found >= 3 && is_cmap_drawbridge(i))) { found += append_str(out_str, article == 2 ? the(x_str) : article == 1 ? an(x_str) : x_str); if (is_cmap_trap(i)) hit_trap = TRUE; } if (i == S_altar || is_cmap_trap(i)) need_to_look = TRUE; } } /* Now check for warning symbols */ for (i = 1; i < WARNCOUNT; i++) { x_str = def_warnsyms[i].explanation; if (sym == (from_screen ? warnsyms[i] : def_warnsyms[i].sym)) { if (!found) { Sprintf(out_str, "%c %s", sym, def_warnsyms[i].explanation); firstmatch = def_warnsyms[i].explanation; found++; } else { found += append_str(out_str, def_warnsyms[i].explanation); } /* Kludge: warning trumps boulders on the display. Reveal the boulder too or player can get confused */ if (from_screen && sobj_at(BOULDER, cc.x, cc.y)) Strcat(out_str, " co-located with a boulder"); break; /* out of for loop*/ } } /* if we ignored venom and list turned out to be short, put it back */ if (skipped_venom && found < 2) { x_str = objexplain[VENOM_CLASS]; if (!found) { Sprintf(out_str, "%c %s", sym, an(x_str)); firstmatch = x_str; found++; } else { found += append_str(out_str, an(x_str)); } } /* handle optional boulder symbol as a special case */ if (iflags.bouldersym && sym == iflags.bouldersym) { if (!found) { firstmatch = "boulder"; Sprintf(out_str, "%c %s", sym, an(firstmatch)); found++; } else { found += append_str(out_str, "boulder"); } } /* * If we are looking at the screen, follow multiple possibilities or * an ambiguous explanation by something more detailed. */ if (from_screen) { if (found > 1 || need_to_look) { char monbuf[BUFSZ]; char temp_buf[BUFSZ]; pm = lookat(cc.x, cc.y, look_buf, monbuf); firstmatch = look_buf; if (*firstmatch) { Sprintf(temp_buf, " (%s)", firstmatch); (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1); found = 1; /* we have something to look up */ } if (monbuf[0]) { Sprintf(temp_buf, " [seen: %s]", monbuf); (void)strncat(out_str, temp_buf, BUFSZ-strlen(out_str)-1); } } } /* Finally, print out our explanation. */ if (found) { pline("%s", out_str); /* check the data file for information about this thing */ if (found == 1 && ans != LOOK_QUICK && ans != LOOK_ONCE && (ans == LOOK_VERBOSE || (flags.help && !quick))) { char temp_buf[BUFSZ]; Strcpy(temp_buf, firstmatch); checkfile(temp_buf, pm, FALSE, (boolean)(ans == LOOK_VERBOSE)); } } else { pline("I've never heard of such things."); } } while (from_screen && !quick && ans != LOOK_ONCE); flags.verbose = save_verbose; return 0; } int dowhatis() { return do_look(FALSE); } int doquickwhatis() { return do_look(TRUE); } int doidtrap() { register struct trap *trap; int x, y, tt; if (!getdir("^")) return 0; x = u.ux + u.dx; y = u.uy + u.dy; for (trap = ftrap; trap; trap = trap->ntrap) if (trap->tx == x && trap->ty == y) { if (!trap->tseen) break; tt = trap->ttyp; if (u.dz) { if (u.dz < 0 ? (tt == TRAPDOOR || tt == HOLE) : tt == ROCKTRAP) break; } tt = what_trap(tt); pline("That is %s%s%s.", an(defsyms[trap_to_defsym(tt)].explanation), !trap->madeby_u ? "" : (tt == WEB) ? " woven" : /* trap doors & spiked pits can't be made by player, and should be considered at least as much "set" as "dug" anyway */ (tt == HOLE || tt == PIT) ? " dug" : " set", !trap->madeby_u ? "" : " by you"); return 0; } pline("I can't see a trap there."); return 0; } char * dowhatdoes_core(q, cbuf) char q; char *cbuf; { dlb *fp; char bufr[BUFSZ]; register char *buf = &bufr[6], *ep, ctrl, meta; fp = dlb_fopen(CMDHELPFILE, "r"); if (!fp) { pline("Cannot open data file!"); return 0; } ctrl = ((q <= '\033') ? (q - 1 + 'A') : 0); meta = ((0x80 & q) ? (0x7f & q) : 0); while(dlb_fgets(buf,BUFSZ-6,fp)) { if ((ctrl && *buf=='^' && *(buf+1)==ctrl) || (meta && *buf=='M' && *(buf+1)=='-' && *(buf+2)==meta) || *buf==q) { ep = index(buf, '\n'); if(ep) *ep = 0; if (ctrl && buf[2] == '\t'){ buf = bufr + 1; (void) strncpy(buf, "^? ", 8); buf[1] = ctrl; } else if (meta && buf[3] == '\t'){ buf = bufr + 2; (void) strncpy(buf, "M-? ", 8); buf[2] = meta; } else if(buf[1] == '\t'){ buf = bufr; buf[0] = q; (void) strncpy(buf+1, " ", 7); } (void) dlb_fclose(fp); Strcpy(cbuf, buf); return cbuf; } } (void) dlb_fclose(fp); return (char *)0; } int dowhatdoes() { char bufr[BUFSZ]; char q, *reslt; #if defined(UNIX) || defined(VMS) introff(); #endif q = yn_function("What command?", (char *)0, '\0'); #if defined(UNIX) || defined(VMS) intron(); #endif reslt = dowhatdoes_core(q, bufr); if (reslt) pline("%s", reslt); else pline("I've never heard of such commands."); return 0; } /* data for help_menu() */ static const char *help_menu_items[] = { /* 0*/ "Long description of the game and commands.", /* 1*/ "List of game commands.", /* 2*/ "Concise history of NetHack.", /* 3*/ "Info on a character in the game display.", /* 4*/ "Info on what a given key does.", /* 5*/ "List of game options.", /* 6*/ "Longer explanation of game options.", /* 7*/ "List of extended commands.", /* 8*/ "The NetHack license.", #ifdef PORT_HELP "%s-specific help and commands.", #define PORT_HELP_ID 100 #define WIZHLP_SLOT 10 #else #define WIZHLP_SLOT 9 #endif #ifdef WIZARD "List of wizard-mode commands.", #endif "", (char *)0 }; STATIC_OVL boolean help_menu(sel) int *sel; { winid tmpwin = create_nhwindow(NHW_MENU); #ifdef PORT_HELP char helpbuf[QBUFSZ]; #endif int i, n; menu_item *selected; anything any; any.a_void = 0; /* zero all bits */ start_menu(tmpwin); #ifdef WIZARD if (!wizard) help_menu_items[WIZHLP_SLOT] = "", help_menu_items[WIZHLP_SLOT+1] = (char *)0; #endif for (i = 0; help_menu_items[i]; i++) #ifdef PORT_HELP /* port-specific line has a %s in it for the PORT_ID */ if (help_menu_items[i][0] == '%') { Sprintf(helpbuf, help_menu_items[i], PORT_ID); any.a_int = PORT_HELP_ID + 1; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, helpbuf, MENU_UNSELECTED); } else #endif { any.a_int = (*help_menu_items[i]) ? i+1 : 0; add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_NONE, help_menu_items[i], MENU_UNSELECTED); } end_menu(tmpwin, "Select one item:"); n = select_menu(tmpwin, PICK_ONE, &selected); destroy_nhwindow(tmpwin); if (n > 0) { *sel = selected[0].item.a_int - 1; free((genericptr_t)selected); return TRUE; } return FALSE; } int dohelp() { int sel = 0; if (help_menu(&sel)) { switch (sel) { case 0: display_file(HELP, TRUE); break; case 1: display_file(SHELP, TRUE); break; case 2: (void) dohistory(); break; case 3: (void) dowhatis(); break; case 4: (void) dowhatdoes(); break; case 5: option_help(); break; case 6: display_file(OPTIONFILE, TRUE); break; case 7: (void) doextlist(); break; case 8: display_file(LICENSE, TRUE); break; #ifdef WIZARD /* handle slot 9 or 10 */ default: display_file(DEBUGHELP, TRUE); break; #endif #ifdef PORT_HELP case PORT_HELP_ID: port_help(); break; #endif } } return 0; } int dohistory() { display_file(HISTORY, TRUE); return 0; } /*pager.c*/ nethack-3.4.3/src/pickup.c0100644000000000000000000020734407764735041014112 0ustar rootroot/* SCCS Id: @(#)pickup.c 3.4 2003/07/27 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * Contains code for picking objects up, and container use. */ #include "hack.h" STATIC_DCL void FDECL(simple_look, (struct obj *,BOOLEAN_P)); #ifndef GOLDOBJ STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *, const char *,struct obj *,BOOLEAN_P,BOOLEAN_P,int *)); #else STATIC_DCL boolean FDECL(query_classes, (char *,boolean *,boolean *, const char *,struct obj *,BOOLEAN_P,int *)); #endif STATIC_DCL void FDECL(check_here, (BOOLEAN_P)); STATIC_DCL boolean FDECL(n_or_more, (struct obj *)); STATIC_DCL boolean FDECL(all_but_uchain, (struct obj *)); #if 0 /* not used */ STATIC_DCL boolean FDECL(allow_cat_no_uchain, (struct obj *)); #endif STATIC_DCL int FDECL(autopick, (struct obj*, int, menu_item **)); STATIC_DCL int FDECL(count_categories, (struct obj *,int)); STATIC_DCL long FDECL(carry_count, (struct obj *,struct obj *,long,BOOLEAN_P,int *,int *)); STATIC_DCL int FDECL(lift_object, (struct obj *,struct obj *,long *,BOOLEAN_P)); STATIC_DCL boolean FDECL(mbag_explodes, (struct obj *,int)); STATIC_PTR int FDECL(in_container,(struct obj *)); STATIC_PTR int FDECL(ck_bag,(struct obj *)); STATIC_PTR int FDECL(out_container,(struct obj *)); STATIC_DCL long FDECL(mbag_item_gone, (int,struct obj *)); STATIC_DCL void FDECL(observe_quantum_cat, (struct obj *)); STATIC_DCL int FDECL(menu_loot, (int, struct obj *, BOOLEAN_P)); STATIC_DCL int FDECL(in_or_out_menu, (const char *,struct obj *, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL int FDECL(container_at, (int, int, BOOLEAN_P)); STATIC_DCL boolean FDECL(able_to_loot, (int, int)); STATIC_DCL boolean FDECL(mon_beside, (int, int)); /* define for query_objlist() and autopickup() */ #define FOLLOW(curr, flags) \ (((flags) & BY_NEXTHERE) ? (curr)->nexthere : (curr)->nobj) /* * How much the weight of the given container will change when the given * object is removed from it. This calculation must match the one used * by weight() in mkobj.c. */ #define DELTA_CWT(cont,obj) \ ((cont)->cursed ? (obj)->owt * 2 : \ 1 + ((obj)->owt / ((cont)->blessed ? 4 : 2))) #define GOLD_WT(n) (((n) + 50L) / 100L) /* if you can figure this out, give yourself a hearty pat on the back... */ #define GOLD_CAPACITY(w,n) (((w) * -100L) - ((n) + 50L) - 1L) static const char moderateloadmsg[] = "You have a little trouble lifting"; static const char nearloadmsg[] = "You have much trouble lifting"; static const char overloadmsg[] = "You have extreme difficulty lifting"; /* BUG: this lets you look at cockatrice corpses while blind without touching them */ /* much simpler version of the look-here code; used by query_classes() */ STATIC_OVL void simple_look(otmp, here) struct obj *otmp; /* list of objects */ boolean here; /* flag for type of obj list linkage */ { /* Neither of the first two cases is expected to happen, since * we're only called after multiple classes of objects have been * detected, hence multiple objects must be present. */ if (!otmp) { impossible("simple_look(null)"); } else if (!(here ? otmp->nexthere : otmp->nobj)) { pline("%s", doname(otmp)); } else { winid tmpwin = create_nhwindow(NHW_MENU); putstr(tmpwin, 0, ""); do { putstr(tmpwin, 0, doname(otmp)); otmp = here ? otmp->nexthere : otmp->nobj; } while (otmp); display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); } } #ifndef GOLDOBJ int collect_obj_classes(ilets, otmp, here, incl_gold, filter, itemcount) char ilets[]; register struct obj *otmp; boolean here, incl_gold; boolean FDECL((*filter),(OBJ_P)); int *itemcount; #else int collect_obj_classes(ilets, otmp, here, filter, itemcount) char ilets[]; register struct obj *otmp; boolean here; boolean FDECL((*filter),(OBJ_P)); int *itemcount; #endif { register int iletct = 0; register char c; *itemcount = 0; #ifndef GOLDOBJ if (incl_gold) ilets[iletct++] = def_oc_syms[COIN_CLASS]; #endif ilets[iletct] = '\0'; /* terminate ilets so that index() will work */ while (otmp) { c = def_oc_syms[(int)otmp->oclass]; if (!index(ilets, c) && (!filter || (*filter)(otmp))) ilets[iletct++] = c, ilets[iletct] = '\0'; *itemcount += 1; otmp = here ? otmp->nexthere : otmp->nobj; } return iletct; } /* * Suppose some '?' and '!' objects are present, but '/' objects aren't: * "a" picks all items without further prompting; * "A" steps through all items, asking one by one; * "?" steps through '?' items, asking, and ignores '!' ones; * "/" becomes 'A', since no '/' present; * "?a" or "a?" picks all '?' without further prompting; * "/a" or "a/" becomes 'A' since there aren't any '/' * (bug fix: 3.1.0 thru 3.1.3 treated it as "a"); * "?/a" or "a?/" or "/a?",&c picks all '?' even though no '/' * (ie, treated as if it had just been "?a"). */ #ifndef GOLDOBJ STATIC_OVL boolean query_classes(oclasses, one_at_a_time, everything, action, objs, here, incl_gold, menu_on_demand) char oclasses[]; boolean *one_at_a_time, *everything; const char *action; struct obj *objs; boolean here, incl_gold; int *menu_on_demand; #else STATIC_OVL boolean query_classes(oclasses, one_at_a_time, everything, action, objs, here, menu_on_demand) char oclasses[]; boolean *one_at_a_time, *everything; const char *action; struct obj *objs; boolean here; int *menu_on_demand; #endif { char ilets[20], inbuf[BUFSZ]; int iletct, oclassct; boolean not_everything; char qbuf[QBUFSZ]; boolean m_seen; int itemcount; oclasses[oclassct = 0] = '\0'; *one_at_a_time = *everything = m_seen = FALSE; iletct = collect_obj_classes(ilets, objs, here, #ifndef GOLDOBJ incl_gold, #endif (boolean FDECL((*),(OBJ_P))) 0, &itemcount); if (iletct == 0) { return FALSE; } else if (iletct == 1) { oclasses[0] = def_char_to_objclass(ilets[0]); oclasses[1] = '\0'; if (itemcount && menu_on_demand) { ilets[iletct++] = 'm'; *menu_on_demand = 0; ilets[iletct] = '\0'; } } else { /* more than one choice available */ const char *where = 0; register char sym, oc_of_sym, *p; /* additional choices */ ilets[iletct++] = ' '; ilets[iletct++] = 'a'; ilets[iletct++] = 'A'; ilets[iletct++] = (objs == invent ? 'i' : ':'); if (menu_on_demand) { ilets[iletct++] = 'm'; *menu_on_demand = 0; } ilets[iletct] = '\0'; ask_again: oclasses[oclassct = 0] = '\0'; *one_at_a_time = *everything = FALSE; not_everything = FALSE; Sprintf(qbuf,"What kinds of thing do you want to %s? [%s]", action, ilets); getlin(qbuf,inbuf); if (*inbuf == '\033') return FALSE; for (p = inbuf; (sym = *p++); ) { /* new A function (selective all) added by GAN 01/09/87 */ if (sym == ' ') continue; else if (sym == 'A') *one_at_a_time = TRUE; else if (sym == 'a') *everything = TRUE; else if (sym == ':') { simple_look(objs, here); /* dumb if objs==invent */ goto ask_again; } else if (sym == 'i') { (void) display_inventory((char *)0, TRUE); goto ask_again; } else if (sym == 'm') { m_seen = TRUE; } else { oc_of_sym = def_char_to_objclass(sym); if (index(ilets,sym)) { add_valid_menu_class(oc_of_sym); oclasses[oclassct++] = oc_of_sym; oclasses[oclassct] = '\0'; } else { if (!where) where = !strcmp(action,"pick up") ? "here" : !strcmp(action,"take out") ? "inside" : ""; if (*where) There("are no %c's %s.", sym, where); else You("have no %c's.", sym); not_everything = TRUE; } } } if (m_seen && menu_on_demand) { *menu_on_demand = (*everything || !oclassct) ? -2 : -3; return FALSE; } if (!oclassct && (!*everything || not_everything)) { /* didn't pick anything, or tried to pick something that's not present */ *one_at_a_time = TRUE; /* force 'A' */ *everything = FALSE; /* inhibit 'a' */ } } return TRUE; } /* look at the objects at our location, unless there are too many of them */ STATIC_OVL void check_here(picked_some) boolean picked_some; { register struct obj *obj; register int ct = 0; /* count the objects here */ for (obj = level.objects[u.ux][u.uy]; obj; obj = obj->nexthere) { if (obj != uchain) ct++; } /* If there are objects here, take a look. */ if (ct) { if (flags.run) nomul(0); flush_screen(1); (void) look_here(ct, picked_some); } else { read_engr_at(u.ux,u.uy); } } /* Value set by query_objlist() for n_or_more(). */ static long val_for_n_or_more; /* query_objlist callback: return TRUE if obj's count is >= reference value */ STATIC_OVL boolean n_or_more(obj) struct obj *obj; { if (obj == uchain) return FALSE; return (obj->quan >= val_for_n_or_more); } /* List of valid menu classes for query_objlist() and allow_category callback */ static char valid_menu_classes[MAXOCLASSES + 2]; void add_valid_menu_class(c) int c; { static int vmc_count = 0; if (c == 0) /* reset */ vmc_count = 0; else valid_menu_classes[vmc_count++] = (char)c; valid_menu_classes[vmc_count] = '\0'; } /* query_objlist callback: return TRUE if not uchain */ STATIC_OVL boolean all_but_uchain(obj) struct obj *obj; { return (obj != uchain); } /* query_objlist callback: return TRUE */ /*ARGSUSED*/ boolean allow_all(obj) struct obj *obj; { return TRUE; } boolean allow_category(obj) struct obj *obj; { if (Role_if(PM_PRIEST)) obj->bknown = TRUE; if (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) || (index(valid_menu_classes, obj->oclass) != (char *)0)) return TRUE; else if (((index(valid_menu_classes,'U') != (char *)0) && (obj->oclass != COIN_CLASS && obj->bknown && !obj->blessed && !obj->cursed))) return TRUE; else if (((index(valid_menu_classes,'B') != (char *)0) && (obj->oclass != COIN_CLASS && obj->bknown && obj->blessed))) return TRUE; else if (((index(valid_menu_classes,'C') != (char *)0) && (obj->oclass != COIN_CLASS && obj->bknown && obj->cursed))) return TRUE; else if (((index(valid_menu_classes,'X') != (char *)0) && (obj->oclass != COIN_CLASS && !obj->bknown))) return TRUE; else return FALSE; } #if 0 /* not used */ /* query_objlist callback: return TRUE if valid category (class), no uchain */ STATIC_OVL boolean allow_cat_no_uchain(obj) struct obj *obj; { if ((obj != uchain) && (((index(valid_menu_classes,'u') != (char *)0) && obj->unpaid) || (index(valid_menu_classes, obj->oclass) != (char *)0))) return TRUE; else return FALSE; } #endif /* query_objlist callback: return TRUE if valid class and worn */ boolean is_worn_by_type(otmp) register struct obj *otmp; { return((boolean)(!!(otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP | W_SWAPWEP | W_QUIVER))) && (index(valid_menu_classes, otmp->oclass) != (char *)0)); } /* * Have the hero pick things from the ground * or a monster's inventory if swallowed. * * Arg what: * >0 autopickup * =0 interactive * <0 pickup count of something * * Returns 1 if tried to pick something up, whether * or not it succeeded. */ int pickup(what) int what; /* should be a long */ { int i, n, res, count, n_tried = 0, n_picked = 0; menu_item *pick_list = (menu_item *) 0; boolean autopickup = what > 0; struct obj *objchain; int traverse_how; if (what < 0) /* pick N of something */ count = -what; else /* pick anything */ count = 0; if (!u.uswallow) { struct trap *ttmp = t_at(u.ux, u.uy); /* no auto-pick if no-pick move, nothing there, or in a pool */ if (autopickup && (flags.nopick || !OBJ_AT(u.ux, u.uy) || (is_pool(u.ux, u.uy) && !Underwater) || is_lava(u.ux, u.uy))) { read_engr_at(u.ux, u.uy); return (0); } /* no pickup if levitating & not on air or water level */ if (!can_reach_floor()) { if ((multi && !flags.run) || (autopickup && !flags.pickup)) read_engr_at(u.ux, u.uy); return (0); } if (ttmp && ttmp->tseen) { /* Allow pickup from holes and trap doors that you escaped * from because that stuff is teetering on the edge just * like you, but not pits, because there is an elevation * discrepancy with stuff in pits. */ if ((ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) && (!u.utrap || (u.utrap && u.utraptype != TT_PIT))) { read_engr_at(u.ux, u.uy); return(0); } } /* multi && !flags.run means they are in the middle of some other * action, or possibly paralyzed, sleeping, etc.... and they just * teleported onto the object. They shouldn't pick it up. */ if ((multi && !flags.run) || (autopickup && !flags.pickup)) { check_here(FALSE); return (0); } if (notake(youmonst.data)) { if (!autopickup) You("are physically incapable of picking anything up."); else check_here(FALSE); return (0); } /* if there's anything here, stop running */ if (OBJ_AT(u.ux,u.uy) && flags.run && flags.run != 8 && !flags.nopick) nomul(0); } add_valid_menu_class(0); /* reset */ if (!u.uswallow) { objchain = level.objects[u.ux][u.uy]; traverse_how = BY_NEXTHERE; } else { objchain = u.ustuck->minvent; traverse_how = 0; /* nobj */ } /* * Start the actual pickup process. This is split into two main * sections, the newer menu and the older "traditional" methods. * Automatic pickup has been split into its own menu-style routine * to make things less confusing. */ if (autopickup) { n = autopick(objchain, traverse_how, &pick_list); goto menu_pickup; } if (flags.menu_style != MENU_TRADITIONAL || iflags.menu_requested) { /* use menus exclusively */ if (count) { /* looking for N of something */ char buf[QBUFSZ]; Sprintf(buf, "Pick %d of what?", count); val_for_n_or_more = count; /* set up callback selector */ n = query_objlist(buf, objchain, traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT, &pick_list, PICK_ONE, n_or_more); /* correct counts, if any given */ for (i = 0; i < n; i++) pick_list[i].count = count; } else { n = query_objlist("Pick up what?", objchain, traverse_how|AUTOSELECT_SINGLE|INVORDER_SORT|FEEL_COCKATRICE, &pick_list, PICK_ANY, all_but_uchain); } menu_pickup: n_tried = n; for (n_picked = i = 0 ; i < n; i++) { res = pickup_object(pick_list[i].item.a_obj,pick_list[i].count, FALSE); if (res < 0) break; /* can't continue */ n_picked += res; } if (pick_list) free((genericptr_t)pick_list); } else { /* old style interface */ int ct = 0; long lcount; boolean all_of_a_type, selective; char oclasses[MAXOCLASSES]; struct obj *obj, *obj2; oclasses[0] = '\0'; /* types to consider (empty for all) */ all_of_a_type = TRUE; /* take all of considered types */ selective = FALSE; /* ask for each item */ /* check for more than one object */ for (obj = objchain; obj; obj = (traverse_how == BY_NEXTHERE) ? obj->nexthere : obj->nobj) ct++; if (ct == 1 && count) { /* if only one thing, then pick it */ obj = objchain; lcount = min(obj->quan, (long)count); n_tried++; if (pickup_object(obj, lcount, FALSE) > 0) n_picked++; /* picked something */ goto end_query; } else if (ct >= 2) { int via_menu = 0; There("are %s objects here.", (ct <= 10) ? "several" : "many"); if (!query_classes(oclasses, &selective, &all_of_a_type, "pick up", objchain, traverse_how == BY_NEXTHERE, #ifndef GOLDOBJ FALSE, #endif &via_menu)) { if (!via_menu) return (0); n = query_objlist("Pick up what?", objchain, traverse_how|(selective ? 0 : INVORDER_SORT), &pick_list, PICK_ANY, via_menu == -2 ? allow_all : allow_category); goto menu_pickup; } } for (obj = objchain; obj; obj = obj2) { if (traverse_how == BY_NEXTHERE) obj2 = obj->nexthere; /* perhaps obj will be picked up */ else obj2 = obj->nobj; lcount = -1L; if (!selective && oclasses[0] && !index(oclasses,obj->oclass)) continue; if (!all_of_a_type) { char qbuf[BUFSZ]; Sprintf(qbuf, "Pick up %s?", safe_qbuf("", sizeof("Pick up ?"), doname(obj), an(simple_typename(obj->otyp)), "something")); switch ((obj->quan < 2L) ? ynaq(qbuf) : ynNaq(qbuf)) { case 'q': goto end_query; /* out 2 levels */ case 'n': continue; case 'a': all_of_a_type = TRUE; if (selective) { selective = FALSE; oclasses[0] = obj->oclass; oclasses[1] = '\0'; } break; case '#': /* count was entered */ if (!yn_number) continue; /* 0 count => No */ lcount = (long) yn_number; if (lcount > obj->quan) lcount = obj->quan; /* fall thru */ default: /* 'y' */ break; } } if (lcount == -1L) lcount = obj->quan; n_tried++; if ((res = pickup_object(obj, lcount, FALSE)) < 0) break; n_picked += res; } end_query: ; /* semicolon needed by brain-damaged compilers */ } if (!u.uswallow) { if (!OBJ_AT(u.ux,u.uy)) u.uundetected = 0; /* position may need updating (invisible hero) */ if (n_picked) newsym(u.ux,u.uy); /* see whether there's anything else here, after auto-pickup is done */ if (autopickup) check_here(n_picked > 0); } return (n_tried > 0); } #ifdef AUTOPICKUP_EXCEPTIONS boolean is_autopickup_exception(obj, grab) struct obj *obj; boolean grab; /* forced pickup, rather than forced leave behind? */ { /* * Does the text description of this match an exception? */ char *objdesc = makesingular(doname(obj)); struct autopickup_exception *ape = (grab) ? iflags.autopickup_exceptions[AP_GRAB] : iflags.autopickup_exceptions[AP_LEAVE]; while (ape) { if (pmatch(ape->pattern, objdesc)) return TRUE; ape = ape->next; } return FALSE; } #endif /* AUTOPICKUP_EXCEPTIONS */ /* * Pick from the given list using flags.pickup_types. Return the number * of items picked (not counts). Create an array that returns pointers * and counts of the items to be picked up. If the number of items * picked is zero, the pickup list is left alone. The caller of this * function must free the pickup list. */ STATIC_OVL int autopick(olist, follow, pick_list) struct obj *olist; /* the object list */ int follow; /* how to follow the object list */ menu_item **pick_list; /* list of objects and counts to pick up */ { menu_item *pi; /* pick item */ struct obj *curr; int n; const char *otypes = flags.pickup_types; /* first count the number of eligible items */ for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) #ifndef AUTOPICKUP_EXCEPTIONS if (!*otypes || index(otypes, curr->oclass)) #else if ((!*otypes || index(otypes, curr->oclass) || is_autopickup_exception(curr, TRUE)) && !is_autopickup_exception(curr, FALSE)) #endif n++; if (n) { *pick_list = pi = (menu_item *) alloc(sizeof(menu_item) * n); for (n = 0, curr = olist; curr; curr = FOLLOW(curr, follow)) #ifndef AUTOPICKUP_EXCEPTIONS if (!*otypes || index(otypes, curr->oclass)) { #else if ((!*otypes || index(otypes, curr->oclass) || is_autopickup_exception(curr, TRUE)) && !is_autopickup_exception(curr, FALSE)) { #endif pi[n].item.a_obj = curr; pi[n].count = curr->quan; n++; } } return n; } /* * Put up a menu using the given object list. Only those objects on the * list that meet the approval of the allow function are displayed. Return * a count of the number of items selected, as well as an allocated array of * menu_items, containing pointers to the objects selected and counts. The * returned counts are guaranteed to be in bounds and non-zero. * * Query flags: * BY_NEXTHERE - Follow object list via nexthere instead of nobj. * AUTOSELECT_SINGLE - Don't ask if only 1 object qualifies - just * use it. * USE_INVLET - Use object's invlet. * INVORDER_SORT - Use hero's pack order. * SIGNAL_NOMENU - Return -1 rather than 0 if nothing passes "allow". */ int query_objlist(qstr, olist, qflags, pick_list, how, allow) const char *qstr; /* query string */ struct obj *olist; /* the list to pick from */ int qflags; /* options to control the query */ menu_item **pick_list; /* return list of items picked */ int how; /* type of query */ boolean FDECL((*allow), (OBJ_P));/* allow function */ { int n; winid win; struct obj *curr, *last; char *pack; anything any; boolean printed_type_name; *pick_list = (menu_item *) 0; if (!olist) return 0; /* count the number of items allowed */ for (n = 0, last = 0, curr = olist; curr; curr = FOLLOW(curr, qflags)) if ((*allow)(curr)) { last = curr; n++; } if (n == 0) /* nothing to pick here */ return (qflags & SIGNAL_NOMENU) ? -1 : 0; if (n == 1 && (qflags & AUTOSELECT_SINGLE)) { *pick_list = (menu_item *) alloc(sizeof(menu_item)); (*pick_list)->item.a_obj = last; (*pick_list)->count = last->quan; return 1; } win = create_nhwindow(NHW_MENU); start_menu(win); any.a_obj = (struct obj *) 0; /* * Run through the list and add the objects to the menu. If * INVORDER_SORT is set, we'll run through the list once for * each type so we can group them. The allow function will only * be called once per object in the list. */ pack = flags.inv_order; do { printed_type_name = FALSE; for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { if ((qflags & FEEL_COCKATRICE) && curr->otyp == CORPSE && will_feel_cockatrice(curr, FALSE)) { destroy_nhwindow(win); /* stop the menu and revert */ (void) look_here(0, FALSE); return 0; } if ((!(qflags & INVORDER_SORT) || curr->oclass == *pack) && (*allow)(curr)) { /* if sorting, print type name (once only) */ if (qflags & INVORDER_SORT && !printed_type_name) { any.a_obj = (struct obj *) 0; add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, let_to_name(*pack, FALSE), MENU_UNSELECTED); printed_type_name = TRUE; } any.a_obj = curr; add_menu(win, obj_to_glyph(curr), &any, qflags & USE_INVLET ? curr->invlet : 0, def_oc_syms[(int)objects[curr->otyp].oc_class], ATR_NONE, doname(curr), MENU_UNSELECTED); } } pack++; } while (qflags & INVORDER_SORT && *pack); end_menu(win, qstr); n = select_menu(win, how, pick_list); destroy_nhwindow(win); if (n > 0) { menu_item *mi; int i; /* fix up counts: -1 means no count used => pick all */ for (i = 0, mi = *pick_list; i < n; i++, mi++) if (mi->count == -1L || mi->count > mi->item.a_obj->quan) mi->count = mi->item.a_obj->quan; } else if (n < 0) { n = 0; /* caller's don't expect -1 */ } return n; } /* * allow menu-based category (class) selection (for Drop,take off etc.) * */ int query_category(qstr, olist, qflags, pick_list, how) const char *qstr; /* query string */ struct obj *olist; /* the list to pick from */ int qflags; /* behaviour modification flags */ menu_item **pick_list; /* return list of items picked */ int how; /* type of query */ { int n; winid win; struct obj *curr; char *pack; anything any; boolean collected_type_name; char invlet; int ccount; boolean do_unpaid = FALSE; boolean do_blessed = FALSE, do_cursed = FALSE, do_uncursed = FALSE, do_buc_unknown = FALSE; int num_buc_types = 0; *pick_list = (menu_item *) 0; if (!olist) return 0; if ((qflags & UNPAID_TYPES) && count_unpaid(olist)) do_unpaid = TRUE; if ((qflags & BUC_BLESSED) && count_buc(olist, BUC_BLESSED)) { do_blessed = TRUE; num_buc_types++; } if ((qflags & BUC_CURSED) && count_buc(olist, BUC_CURSED)) { do_cursed = TRUE; num_buc_types++; } if ((qflags & BUC_UNCURSED) && count_buc(olist, BUC_UNCURSED)) { do_uncursed = TRUE; num_buc_types++; } if ((qflags & BUC_UNKNOWN) && count_buc(olist, BUC_UNKNOWN)) { do_buc_unknown = TRUE; num_buc_types++; } ccount = count_categories(olist, qflags); /* no point in actually showing a menu for a single category */ if (ccount == 1 && !do_unpaid && num_buc_types <= 1 && !(qflags & BILLED_TYPES)) { for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { if ((qflags & WORN_TYPES) && !(curr->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL|W_WEP|W_SWAPWEP|W_QUIVER))) continue; break; } if (curr) { *pick_list = (menu_item *) alloc(sizeof(menu_item)); (*pick_list)->item.a_int = curr->oclass; return 1; } else { #ifdef DEBUG impossible("query_category: no single object match"); #endif } return 0; } win = create_nhwindow(NHW_MENU); start_menu(win); pack = flags.inv_order; if ((qflags & ALL_TYPES) && (ccount > 1)) { invlet = 'a'; any.a_void = 0; any.a_int = ALL_TYPES_SELECTED; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, (qflags & WORN_TYPES) ? "All worn types" : "All types", MENU_UNSELECTED); invlet = 'b'; } else invlet = 'a'; do { collected_type_name = FALSE; for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { if (curr->oclass == *pack) { if ((qflags & WORN_TYPES) && !(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP | W_SWAPWEP | W_QUIVER))) continue; if (!collected_type_name) { any.a_void = 0; any.a_int = curr->oclass; add_menu(win, NO_GLYPH, &any, invlet++, def_oc_syms[(int)objects[curr->otyp].oc_class], ATR_NONE, let_to_name(*pack, FALSE), MENU_UNSELECTED); collected_type_name = TRUE; } } } pack++; if (invlet >= 'u') { impossible("query_category: too many categories"); return 0; } } while (*pack); /* unpaid items if there are any */ if (do_unpaid) { invlet = 'u'; any.a_void = 0; any.a_int = 'u'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Unpaid items", MENU_UNSELECTED); } /* billed items: checked by caller, so always include if BILLED_TYPES */ if (qflags & BILLED_TYPES) { invlet = 'x'; any.a_void = 0; any.a_int = 'x'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Unpaid items already used up", MENU_UNSELECTED); } if (qflags & CHOOSE_ALL) { invlet = 'A'; any.a_void = 0; any.a_int = 'A'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, (qflags & WORN_TYPES) ? "Auto-select every item being worn" : "Auto-select every item", MENU_UNSELECTED); } /* items with b/u/c/unknown if there are any */ if (do_blessed) { invlet = 'B'; any.a_void = 0; any.a_int = 'B'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Items known to be Blessed", MENU_UNSELECTED); } if (do_cursed) { invlet = 'C'; any.a_void = 0; any.a_int = 'C'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Items known to be Cursed", MENU_UNSELECTED); } if (do_uncursed) { invlet = 'U'; any.a_void = 0; any.a_int = 'U'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Items known to be Uncursed", MENU_UNSELECTED); } if (do_buc_unknown) { invlet = 'X'; any.a_void = 0; any.a_int = 'X'; add_menu(win, NO_GLYPH, &any, invlet, 0, ATR_NONE, "Items of unknown B/C/U status", MENU_UNSELECTED); } end_menu(win, qstr); n = select_menu(win, how, pick_list); destroy_nhwindow(win); if (n < 0) n = 0; /* caller's don't expect -1 */ return n; } STATIC_OVL int count_categories(olist, qflags) struct obj *olist; int qflags; { char *pack; boolean counted_category; int ccount = 0; struct obj *curr; pack = flags.inv_order; do { counted_category = FALSE; for (curr = olist; curr; curr = FOLLOW(curr, qflags)) { if (curr->oclass == *pack) { if ((qflags & WORN_TYPES) && !(curr->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL | W_WEP | W_SWAPWEP | W_QUIVER))) continue; if (!counted_category) { ccount++; counted_category = TRUE; } } } pack++; } while (*pack); return ccount; } /* could we carry `obj'? if not, could we carry some of it/them? */ STATIC_OVL long carry_count(obj, container, count, telekinesis, wt_before, wt_after) struct obj *obj, *container; /* object to pick up, bag it's coming out of */ long count; boolean telekinesis; int *wt_before, *wt_after; { boolean adjust_wt = container && carried(container), is_gold = obj->oclass == COIN_CLASS; int wt, iw, ow, oow; long qq, savequan; #ifdef GOLDOBJ long umoney = money_cnt(invent); #endif unsigned saveowt; const char *verb, *prefx1, *prefx2, *suffx; char obj_nambuf[BUFSZ], where[BUFSZ]; savequan = obj->quan; saveowt = obj->owt; iw = max_capacity(); if (count != savequan) { obj->quan = count; obj->owt = (unsigned)weight(obj); } wt = iw + (int)obj->owt; if (adjust_wt) wt -= (container->otyp == BAG_OF_HOLDING) ? (int)DELTA_CWT(container, obj) : (int)obj->owt; #ifndef GOLDOBJ if (is_gold) /* merged gold might affect cumulative weight */ wt -= (GOLD_WT(u.ugold) + GOLD_WT(count) - GOLD_WT(u.ugold + count)); #else /* This will go with silver+copper & new gold weight */ if (is_gold) /* merged gold might affect cumulative weight */ wt -= (GOLD_WT(umoney) + GOLD_WT(count) - GOLD_WT(umoney + count)); #endif if (count != savequan) { obj->quan = savequan; obj->owt = saveowt; } *wt_before = iw; *wt_after = wt; if (wt < 0) return count; /* see how many we can lift */ if (is_gold) { #ifndef GOLDOBJ iw -= (int)GOLD_WT(u.ugold); if (!adjust_wt) { qq = GOLD_CAPACITY((long)iw, u.ugold); } else { oow = 0; qq = 50L - (u.ugold % 100L) - 1L; #else iw -= (int)GOLD_WT(umoney); if (!adjust_wt) { qq = GOLD_CAPACITY((long)iw, umoney); } else { oow = 0; qq = 50L - (umoney % 100L) - 1L; #endif if (qq < 0L) qq += 100L; for ( ; qq <= count; qq += 100L) { obj->quan = qq; obj->owt = (unsigned)GOLD_WT(qq); #ifndef GOLDOBJ ow = (int)GOLD_WT(u.ugold + qq); #else ow = (int)GOLD_WT(umoney + qq); #endif ow -= (container->otyp == BAG_OF_HOLDING) ? (int)DELTA_CWT(container, obj) : (int)obj->owt; if (iw + ow >= 0) break; oow = ow; } iw -= oow; qq -= 100L; } if (qq < 0L) qq = 0L; else if (qq > count) qq = count; #ifndef GOLDOBJ wt = iw + (int)GOLD_WT(u.ugold + qq); #else wt = iw + (int)GOLD_WT(umoney + qq); #endif } else if (count > 1 || count < obj->quan) { /* * Ugh. Calc num to lift by changing the quan of of the * object and calling weight. * * This works for containers only because containers * don't merge. -dean */ for (qq = 1L; qq <= count; qq++) { obj->quan = qq; obj->owt = (unsigned)(ow = weight(obj)); if (adjust_wt) ow -= (container->otyp == BAG_OF_HOLDING) ? (int)DELTA_CWT(container, obj) : (int)obj->owt; if (iw + ow >= 0) break; wt = iw + ow; } --qq; } else { /* there's only one, and we can't lift it */ qq = 0L; } obj->quan = savequan; obj->owt = saveowt; if (qq < count) { /* some message will be given */ Strcpy(obj_nambuf, doname(obj)); if (container) { Sprintf(where, "in %s", the(xname(container))); verb = "carry"; } else { Strcpy(where, "lying here"); verb = telekinesis ? "acquire" : "lift"; } } else { /* lint supppression */ *obj_nambuf = *where = '\0'; verb = ""; } /* we can carry qq of them */ if (qq > 0) { if (qq < count) You("can only %s %s of the %s %s.", verb, (qq == 1L) ? "one" : "some", obj_nambuf, where); *wt_after = wt; return qq; } if (!container) Strcpy(where, "here"); /* slightly shorter form */ #ifndef GOLDOBJ if (invent || u.ugold) { #else if (invent || umoney) { #endif prefx1 = "you cannot "; prefx2 = ""; suffx = " any more"; } else { prefx1 = (obj->quan == 1L) ? "it " : "even one "; prefx2 = "is too heavy for you to "; suffx = ""; } There("%s %s %s, but %s%s%s%s.", otense(obj, "are"), obj_nambuf, where, prefx1, prefx2, verb, suffx); /* *wt_after = iw; */ return 0L; } /* determine whether character is able and player is willing to carry `obj' */ STATIC_OVL int lift_object(obj, container, cnt_p, telekinesis) struct obj *obj, *container; /* object to pick up, bag it's coming out of */ long *cnt_p; boolean telekinesis; { int result, old_wt, new_wt, prev_encumbr, next_encumbr; if (obj->otyp == BOULDER && In_sokoban(&u.uz)) { You("cannot get your %s around this %s.", body_part(HAND), xname(obj)); return -1; } if (obj->otyp == LOADSTONE || (obj->otyp == BOULDER && throws_rocks(youmonst.data))) return 1; /* lift regardless of current situation */ *cnt_p = carry_count(obj, container, *cnt_p, telekinesis, &old_wt, &new_wt); if (*cnt_p < 1L) { result = -1; /* nothing lifted */ #ifndef GOLDOBJ } else if (obj->oclass != COIN_CLASS && inv_cnt() >= 52 && !merge_choice(invent, obj)) { #else } else if (inv_cnt() >= 52 && !merge_choice(invent, obj)) { #endif Your("knapsack cannot accommodate any more items."); result = -1; /* nothing lifted */ } else { result = 1; prev_encumbr = near_capacity(); if (prev_encumbr < flags.pickup_burden) prev_encumbr = flags.pickup_burden; next_encumbr = calc_capacity(new_wt - old_wt); if (next_encumbr > prev_encumbr) { if (telekinesis) { result = 0; /* don't lift */ } else { char qbuf[BUFSZ]; long savequan = obj->quan; obj->quan = *cnt_p; Strcpy(qbuf, (next_encumbr > HVY_ENCUMBER) ? overloadmsg : (next_encumbr > MOD_ENCUMBER) ? nearloadmsg : moderateloadmsg); Sprintf(eos(qbuf), " %s. Continue?", safe_qbuf(qbuf, sizeof(" . Continue?"), doname(obj), an(simple_typename(obj->otyp)), "something")); obj->quan = savequan; switch (ynq(qbuf)) { case 'q': result = -1; break; case 'n': result = 0; break; default: break; /* 'y' => result == 1 */ } clear_nhwindow(WIN_MESSAGE); } } } if (obj->otyp == SCR_SCARE_MONSTER && result <= 0 && !container) obj->spe = 0; return result; } /* To prevent qbuf overflow in prompts use planA only * if it fits, or planB if PlanA doesn't fit, * finally using the fallback as a last resort. * last_restort is expected to be very short. */ const char * safe_qbuf(qbuf, padlength, planA, planB, last_resort) const char *qbuf, *planA, *planB, *last_resort; unsigned padlength; { /* convert size_t (or int for ancient systems) to ordinary unsigned */ unsigned len_qbuf = (unsigned)strlen(qbuf), len_planA = (unsigned)strlen(planA), len_planB = (unsigned)strlen(planB), len_lastR = (unsigned)strlen(last_resort); unsigned textleft = QBUFSZ - (len_qbuf + padlength); if (len_lastR >= textleft) { impossible("safe_qbuf: last_resort too large at %u characters.", len_lastR); return ""; } return (len_planA < textleft) ? planA : (len_planB < textleft) ? planB : last_resort; } /* * Pick up of obj from the ground and add it to the hero's inventory. * Returns -1 if caller should break out of its loop, 0 if nothing picked * up, 1 if otherwise. */ int pickup_object(obj, count, telekinesis) struct obj *obj; long count; boolean telekinesis; /* not picking it up directly by hand */ { int res, nearload; #ifndef GOLDOBJ const char *where = (obj->ox == u.ux && obj->oy == u.uy) ? "here" : "there"; #endif if (obj->quan < count) { impossible("pickup_object: count %ld > quan %ld?", count, obj->quan); return 0; } /* In case of auto-pickup, where we haven't had a chance to look at it yet; affects docall(SCR_SCARE_MONSTER). */ if (!Blind) #ifdef INVISIBLE_OBJECTS if (!obj->oinvis || See_invisible) #endif obj->dknown = 1; if (obj == uchain) { /* do not pick up attached chain */ return 0; } else if (obj->oartifact && !touch_artifact(obj,&youmonst)) { return 0; #ifndef GOLDOBJ } else if (obj->oclass == COIN_CLASS) { /* Special consideration for gold pieces... */ long iw = (long)max_capacity() - GOLD_WT(u.ugold); long gold_capacity = GOLD_CAPACITY(iw, u.ugold); if (gold_capacity <= 0L) { pline( "There %s %ld gold piece%s %s, but you cannot carry any more.", otense(obj, "are"), obj->quan, plur(obj->quan), where); return 0; } else if (gold_capacity < count) { You("can only %s %s of the %ld gold pieces lying %s.", telekinesis ? "acquire" : "carry", gold_capacity == 1L ? "one" : "some", obj->quan, where); pline("%s %ld gold piece%s.", nearloadmsg, gold_capacity, plur(gold_capacity)); u.ugold += gold_capacity; obj->quan -= gold_capacity; costly_gold(obj->ox, obj->oy, gold_capacity); } else { u.ugold += count; if ((nearload = near_capacity()) != 0) pline("%s %ld gold piece%s.", nearload < MOD_ENCUMBER ? moderateloadmsg : nearloadmsg, count, plur(count)); else prinv((char *) 0, obj, count); costly_gold(obj->ox, obj->oy, count); if (count == obj->quan) delobj(obj); else obj->quan -= count; } flags.botl = 1; if (flags.run) nomul(0); return 1; #endif } else if (obj->otyp == CORPSE) { if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg && !Stone_resistance && !telekinesis) { if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) display_nhwindow(WIN_MESSAGE, FALSE); else { char kbuf[BUFSZ]; Strcpy(kbuf, an(corpse_xname(obj, TRUE))); pline("Touching %s is a fatal mistake.", kbuf); instapetrify(kbuf); return -1; } } else if (is_rider(&mons[obj->corpsenm])) { pline("At your %s, the corpse suddenly moves...", telekinesis ? "attempted acquisition" : "touch"); (void) revive_corpse(obj); exercise(A_WIS, FALSE); return -1; } } else if (obj->otyp == SCR_SCARE_MONSTER) { if (obj->blessed) obj->blessed = 0; else if (!obj->spe && !obj->cursed) obj->spe = 1; else { pline_The("scroll%s %s to dust as you %s %s up.", plur(obj->quan), otense(obj, "turn"), telekinesis ? "raise" : "pick", (obj->quan == 1L) ? "it" : "them"); if (!(objects[SCR_SCARE_MONSTER].oc_name_known) && !(objects[SCR_SCARE_MONSTER].oc_uname)) docall(obj); useupf(obj, obj->quan); return 1; /* tried to pick something up and failed, but don't want to terminate pickup loop yet */ } } if ((res = lift_object(obj, (struct obj *)0, &count, telekinesis)) <= 0) return res; #ifdef GOLDOBJ /* Whats left of the special case for gold :-) */ if (obj->oclass == COIN_CLASS) flags.botl = 1; #endif if (obj->quan != count && obj->otyp != LOADSTONE) obj = splitobj(obj, count); obj = pick_obj(obj); if (uwep && uwep == obj) mrg_to_wielded = TRUE; nearload = near_capacity(); prinv(nearload == SLT_ENCUMBER ? moderateloadmsg : (char *) 0, obj, count); mrg_to_wielded = FALSE; return 1; } /* * Do the actual work of picking otmp from the floor or monster's interior * and putting it in the hero's inventory. Take care of billing. Return a * pointer to the object where otmp ends up. This may be different * from otmp because of merging. * * Gold never reaches this routine unless GOLDOBJ is defined. */ struct obj * pick_obj(otmp) struct obj *otmp; { obj_extract_self(otmp); if (!u.uswallow && otmp != uball && costly_spot(otmp->ox, otmp->oy)) { char saveushops[5], fakeshop[2]; /* addtobill cares about your location rather than the object's; usually they'll be the same, but not when using telekinesis (if ever implemented) or a grappling hook */ Strcpy(saveushops, u.ushops); fakeshop[0] = *in_rooms(otmp->ox, otmp->oy, SHOPBASE); fakeshop[1] = '\0'; Strcpy(u.ushops, fakeshop); /* sets obj->unpaid if necessary */ addtobill(otmp, TRUE, FALSE, FALSE); Strcpy(u.ushops, saveushops); /* if you're outside the shop, make shk notice */ if (!index(u.ushops, *fakeshop)) remote_burglary(otmp->ox, otmp->oy); } if (otmp->no_charge) /* only applies to objects outside invent */ otmp->no_charge = 0; newsym(otmp->ox, otmp->oy); return addinv(otmp); /* might merge it with other objects */ } /* * prints a message if encumbrance changed since the last check and * returns the new encumbrance value (from near_capacity()). */ int encumber_msg() { static int oldcap = UNENCUMBERED; int newcap = near_capacity(); if(oldcap < newcap) { switch(newcap) { case 1: Your("movements are slowed slightly because of your load."); break; case 2: You("rebalance your load. Movement is difficult."); break; case 3: You("%s under your heavy load. Movement is very hard.", stagger(youmonst.data, "stagger")); break; default: You("%s move a handspan with this load!", newcap == 4 ? "can barely" : "can't even"); break; } flags.botl = 1; } else if(oldcap > newcap) { switch(newcap) { case 0: Your("movements are now unencumbered."); break; case 1: Your("movements are only slowed slightly by your load."); break; case 2: You("rebalance your load. Movement is still difficult."); break; case 3: You("%s under your load. Movement is still very hard.", stagger(youmonst.data, "stagger")); break; } flags.botl = 1; } oldcap = newcap; return (newcap); } /* Is there a container at x,y. Optional: return count of containers at x,y */ STATIC_OVL int container_at(x, y, countem) int x,y; boolean countem; { struct obj *cobj, *nobj; int container_count = 0; for(cobj = level.objects[x][y]; cobj; cobj = nobj) { nobj = cobj->nexthere; if(Is_container(cobj)) { container_count++; if (!countem) break; } } return container_count; } STATIC_OVL boolean able_to_loot(x, y) int x, y; { if (!can_reach_floor()) { #ifdef STEED if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) rider_cant_reach(); /* not skilled enough to reach */ else #endif You("cannot reach the %s.", surface(x, y)); return FALSE; } else if (is_pool(x, y) || is_lava(x, y)) { /* at present, can't loot in water even when Underwater */ You("cannot loot things that are deep in the %s.", is_lava(x, y) ? "lava" : "water"); return FALSE; } else if (nolimbs(youmonst.data)) { pline("Without limbs, you cannot loot anything."); return FALSE; } else if (!freehand()) { pline("Without a free %s, you cannot loot anything.", body_part(HAND)); return FALSE; } return TRUE; } STATIC_OVL boolean mon_beside(x,y) int x, y; { int i,j,nx,ny; for(i = -1; i <= 1; i++) for(j = -1; j <= 1; j++) { nx = x + i; ny = y + j; if(isok(nx, ny) && MON_AT(nx, ny)) return TRUE; } return FALSE; } int doloot() /* loot a container on the floor or loot saddle from mon. */ { register struct obj *cobj, *nobj; register int c = -1; int timepassed = 0; coord cc; boolean underfoot = TRUE; const char *dont_find_anything = "don't find anything"; struct monst *mtmp; char qbuf[BUFSZ]; int prev_inquiry = 0; boolean prev_loot = FALSE; if (check_capacity((char *)0)) { /* "Can't do that while carrying so much stuff." */ return 0; } if (nohands(youmonst.data)) { You("have no hands!"); /* not `body_part(HAND)' */ return 0; } cc.x = u.ux; cc.y = u.uy; lootcont: if (container_at(cc.x, cc.y, FALSE)) { boolean any = FALSE; if (!able_to_loot(cc.x, cc.y)) return 0; for (cobj = level.objects[cc.x][cc.y]; cobj; cobj = nobj) { nobj = cobj->nexthere; if (Is_container(cobj)) { Sprintf(qbuf, "There is %s here, loot it?", safe_qbuf("", sizeof("There is here, loot it?"), doname(cobj), an(simple_typename(cobj->otyp)), "a container")); c = ynq(qbuf); if (c == 'q') return (timepassed); if (c == 'n') continue; any = TRUE; if (cobj->olocked) { pline("Hmmm, it seems to be locked."); continue; } if (cobj->otyp == BAG_OF_TRICKS) { int tmp; You("carefully open the bag..."); pline("It develops a huge set of teeth and bites you!"); tmp = rnd(10); if (Half_physical_damage) tmp = (tmp+1) / 2; losehp(tmp, "carnivorous bag", KILLED_BY_AN); makeknown(BAG_OF_TRICKS); timepassed = 1; continue; } You("carefully open %s...", the(xname(cobj))); timepassed |= use_container(cobj, 0); if (multi < 0) return 1; /* chest trap */ } } if (any) c = 'y'; } else if (Confusion) { #ifndef GOLDOBJ if (u.ugold){ long contribution = rnd((int)min(LARGEST_INT,u.ugold)); struct obj *goldob = mkgoldobj(contribution); #else struct obj *goldob; /* Find a money object to mess with */ for (goldob = invent; goldob; goldob = goldob->nobj) { if (goldob->oclass == COIN_CLASS) break; } if (goldob){ long contribution = rnd((int)min(LARGEST_INT, goldob->quan)); if (contribution < goldob->quan) goldob = splitobj(goldob, contribution); freeinv(goldob); #endif if (IS_THRONE(levl[u.ux][u.uy].typ)){ struct obj *coffers; int pass; /* find the original coffers chest, or any chest */ for (pass = 2; pass > -1; pass -= 2) for (coffers = fobj; coffers; coffers = coffers->nobj) if (coffers->otyp == CHEST && coffers->spe == pass) goto gotit; /* two level break */ gotit: if (coffers) { verbalize("Thank you for your contribution to reduce the debt."); (void) add_to_container(coffers, goldob); coffers->owt = weight(coffers); } else { struct monst *mon = makemon(courtmon(), u.ux, u.uy, NO_MM_FLAGS); if (mon) { #ifndef GOLDOBJ mon->mgold += goldob->quan; delobj(goldob); pline("The exchequer accepts your contribution."); } else { dropx(goldob); } } } else { dropx(goldob); #else add_to_minv(mon, goldob); pline("The exchequer accepts your contribution."); } else { dropy(goldob); } } } else { dropy(goldob); #endif pline("Ok, now there is loot here."); } } } else if (IS_GRAVE(levl[cc.x][cc.y].typ)) { You("need to dig up the grave to effectively loot it..."); } /* * 3.3.1 introduced directional looting for some things. */ if (c != 'y' && mon_beside(u.ux, u.uy)) { if (!get_adjacent_loc("Loot in what direction?", "Invalid loot location", u.ux, u.uy, &cc)) return 0; if (cc.x == u.ux && cc.y == u.uy) { underfoot = TRUE; if (container_at(cc.x, cc.y, FALSE)) goto lootcont; } else underfoot = FALSE; if (u.dz < 0) { You("%s to loot on the %s.", dont_find_anything, ceiling(cc.x, cc.y)); timepassed = 1; return timepassed; } mtmp = m_at(cc.x, cc.y); if (mtmp) timepassed = loot_mon(mtmp, &prev_inquiry, &prev_loot); /* Preserve pre-3.3.1 behaviour for containers. * Adjust this if-block to allow container looting * from one square away to change that in the future. */ if (!underfoot) { if (container_at(cc.x, cc.y, FALSE)) { if (mtmp) { You_cant("loot anything %sthere with %s in the way.", prev_inquiry ? "else " : "", mon_nam(mtmp)); return timepassed; } else { You("have to be at a container to loot it."); } } else { You("%s %sthere to loot.", dont_find_anything, (prev_inquiry || prev_loot) ? "else " : ""); return timepassed; } } } else if (c != 'y' && c != 'n') { You("%s %s to loot.", dont_find_anything, underfoot ? "here" : "there"); } return (timepassed); } /* loot_mon() returns amount of time passed. */ int loot_mon(mtmp, passed_info, prev_loot) struct monst *mtmp; int *passed_info; boolean *prev_loot; { int c = -1; int timepassed = 0; #ifdef STEED struct obj *otmp; char qbuf[QBUFSZ]; /* 3.3.1 introduced the ability to remove saddle from a steed */ /* *passed_info is set to TRUE if a loot query was given. */ /* *prev_loot is set to TRUE if something was actually acquired in here. */ if (mtmp && mtmp != u.usteed && (otmp = which_armor(mtmp, W_SADDLE))) { long unwornmask; if (passed_info) *passed_info = 1; Sprintf(qbuf, "Do you want to remove the saddle from %s?", x_monnam(mtmp, ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE)); if ((c = yn_function(qbuf, ynqchars, 'n')) == 'y') { if (nolimbs(youmonst.data)) { You_cant("do that without limbs."); /* not body_part(HAND) */ return (0); } if (otmp->cursed) { You("can't. The saddle seems to be stuck to %s.", x_monnam(mtmp, ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE)); /* the attempt costs you time */ return (1); } obj_extract_self(otmp); if ((unwornmask = otmp->owornmask) != 0L) { mtmp->misc_worn_check &= ~unwornmask; otmp->owornmask = 0L; update_mon_intrinsics(mtmp, otmp, FALSE, FALSE); } otmp = hold_another_object(otmp, "You drop %s!", doname(otmp), (const char *)0); timepassed = rnd(3); if (prev_loot) *prev_loot = TRUE; } else if (c == 'q') { return (0); } } #endif /* STEED */ /* 3.4.0 introduced the ability to pick things up from within swallower's stomach */ if (u.uswallow) { int count = passed_info ? *passed_info : 0; timepassed = pickup(count); } return timepassed; } /* * Decide whether an object being placed into a magic bag will cause * it to explode. If the object is a bag itself, check recursively. */ STATIC_OVL boolean mbag_explodes(obj, depthin) struct obj *obj; int depthin; { /* these won't cause an explosion when they're empty */ if ((obj->otyp == WAN_CANCELLATION || obj->otyp == BAG_OF_TRICKS) && obj->spe <= 0) return FALSE; /* odds: 1/1, 2/2, 3/4, 4/8, 5/16, 6/32, 7/64, 8/128, 9/128, 10/128,... */ if ((Is_mbag(obj) || obj->otyp == WAN_CANCELLATION) && (rn2(1 << (depthin > 7 ? 7 : depthin)) <= depthin)) return TRUE; else if (Has_contents(obj)) { struct obj *otmp; for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (mbag_explodes(otmp, depthin+1)) return TRUE; } return FALSE; } /* A variable set in use_container(), to be used by the callback routines */ /* in_container(), and out_container() from askchain() and use_container(). */ static NEARDATA struct obj *current_container; #define Icebox (current_container->otyp == ICE_BOX) /* Returns: -1 to stop, 1 item was inserted, 0 item was not inserted. */ STATIC_PTR int in_container(obj) register struct obj *obj; { boolean floor_container = !carried(current_container); boolean was_unpaid = FALSE; char buf[BUFSZ]; if (!current_container) { impossible(" no current_container?"); return 0; } else if (obj == uball || obj == uchain) { You("must be kidding."); return 0; } else if (obj == current_container) { pline("That would be an interesting topological exercise."); return 0; } else if (obj->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) { Norep("You cannot %s %s you are wearing.", Icebox ? "refrigerate" : "stash", something); return 0; } else if ((obj->otyp == LOADSTONE) && obj->cursed) { obj->bknown = 1; pline_The("stone%s won't leave your person.", plur(obj->quan)); return 0; } else if (obj->otyp == AMULET_OF_YENDOR || obj->otyp == CANDELABRUM_OF_INVOCATION || obj->otyp == BELL_OF_OPENING || obj->otyp == SPE_BOOK_OF_THE_DEAD) { /* Prohibit Amulets in containers; if you allow it, monsters can't * steal them. It also becomes a pain to check to see if someone * has the Amulet. Ditto for the Candelabrum, the Bell and the Book. */ pline("%s cannot be confined in such trappings.", The(xname(obj))); return 0; } else if (obj->otyp == LEASH && obj->leashmon != 0) { pline("%s attached to your pet.", Tobjnam(obj, "are")); return 0; } else if (obj == uwep) { if (welded(obj)) { weldmsg(obj); return 0; } setuwep((struct obj *) 0); if (uwep) return 0; /* unwielded, died, rewielded */ } else if (obj == uswapwep) { setuswapwep((struct obj *) 0); if (uswapwep) return 0; /* unwielded, died, rewielded */ } else if (obj == uquiver) { setuqwep((struct obj *) 0); if (uquiver) return 0; /* unwielded, died, rewielded */ } if (obj->otyp == CORPSE) { if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg && !Stone_resistance) { if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) display_nhwindow(WIN_MESSAGE, FALSE); else { char kbuf[BUFSZ]; Strcpy(kbuf, an(corpse_xname(obj, TRUE))); pline("Touching %s is a fatal mistake.", kbuf); instapetrify(kbuf); return -1; } } } /* boxes, boulders, and big statues can't fit into any container */ if (obj->otyp == ICE_BOX || Is_box(obj) || obj->otyp == BOULDER || (obj->otyp == STATUE && bigmonst(&mons[obj->corpsenm]))) { /* * xname() uses a static result array. Save obj's name * before current_container's name is computed. Don't * use the result of strcpy() within You() --- the order * of evaluation of the parameters is undefined. */ Strcpy(buf, the(xname(obj))); You("cannot fit %s into %s.", buf, the(xname(current_container))); return 0; } freeinv(obj); if (obj_is_burning(obj)) /* this used to be part of freeinv() */ (void) snuff_lit(obj); if (floor_container && costly_spot(u.ux, u.uy)) { if (current_container->no_charge && !obj->unpaid) { /* don't sell when putting the item into your own container */ obj->no_charge = 1; } else if (obj->oclass != COIN_CLASS) { /* sellobj() will take an unpaid item off the shop bill * note: coins are handled later */ was_unpaid = obj->unpaid ? TRUE : FALSE; sellobj_state(SELL_DELIBERATE); sellobj(obj, u.ux, u.uy); sellobj_state(SELL_NORMAL); } } if (Icebox && !age_is_relative(obj)) { obj->age = monstermoves - obj->age; /* actual age */ /* stop any corpse timeouts when frozen */ if (obj->otyp == CORPSE && obj->timed) { long rot_alarm = stop_timer(ROT_CORPSE, (genericptr_t)obj); (void) stop_timer(REVIVE_MON, (genericptr_t)obj); /* mark a non-reviving corpse as such */ if (rot_alarm) obj->norevive = 1; } } else if (Is_mbag(current_container) && mbag_explodes(obj, 0)) { /* explicitly mention what item is triggering the explosion */ pline( "As you put %s inside, you are blasted by a magical explosion!", doname(obj)); /* did not actually insert obj yet */ if (was_unpaid) addtobill(obj, FALSE, FALSE, TRUE); obfree(obj, (struct obj *)0); delete_contents(current_container); if (!floor_container) useup(current_container); else if (obj_here(current_container, u.ux, u.uy)) useupf(current_container, obj->quan); else panic("in_container: bag not found."); losehp(d(6,6),"magical explosion", KILLED_BY_AN); current_container = 0; /* baggone = TRUE; */ } if (current_container) { Strcpy(buf, the(xname(current_container))); You("put %s into %s.", doname(obj), buf); /* gold in container always needs to be added to credit */ if (floor_container && obj->oclass == COIN_CLASS) sellobj(obj, current_container->ox, current_container->oy); (void) add_to_container(current_container, obj); current_container->owt = weight(current_container); } /* gold needs this, and freeinv() many lines above may cause * the encumbrance to disappear from the status, so just always * update status immediately. */ bot(); return(current_container ? 1 : -1); } STATIC_PTR int ck_bag(obj) struct obj *obj; { return current_container && obj != current_container; } /* Returns: -1 to stop, 1 item was removed, 0 item was not removed. */ STATIC_PTR int out_container(obj) register struct obj *obj; { register struct obj *otmp; boolean is_gold = (obj->oclass == COIN_CLASS); int res, loadlev; long count; if (!current_container) { impossible(" no current_container?"); return -1; } else if (is_gold) { obj->owt = weight(obj); } if(obj->oartifact && !touch_artifact(obj,&youmonst)) return 0; if (obj->otyp == CORPSE) { if ( (touch_petrifies(&mons[obj->corpsenm])) && !uarmg && !Stone_resistance) { if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) display_nhwindow(WIN_MESSAGE, FALSE); else { char kbuf[BUFSZ]; Strcpy(kbuf, an(corpse_xname(obj, TRUE))); pline("Touching %s is a fatal mistake.", kbuf); instapetrify(kbuf); return -1; } } } count = obj->quan; if ((res = lift_object(obj, current_container, &count, FALSE)) <= 0) return res; if (obj->quan != count && obj->otyp != LOADSTONE) obj = splitobj(obj, count); /* Remove the object from the list. */ obj_extract_self(obj); current_container->owt = weight(current_container); if (Icebox && !age_is_relative(obj)) { obj->age = monstermoves - obj->age; /* actual age */ if (obj->otyp == CORPSE) start_corpse_timeout(obj); } /* simulated point of time */ if(!obj->unpaid && !carried(current_container) && costly_spot(current_container->ox, current_container->oy)) { obj->ox = current_container->ox; obj->oy = current_container->oy; addtobill(obj, FALSE, FALSE, FALSE); } if (is_pick(obj) && !obj->unpaid && *u.ushops && shop_keeper(*u.ushops)) verbalize("You sneaky cad! Get out of here with that pick!"); otmp = addinv(obj); loadlev = near_capacity(); prinv(loadlev ? (loadlev < MOD_ENCUMBER ? "You have a little trouble removing" : "You have much trouble removing") : (char *)0, otmp, count); if (is_gold) { #ifndef GOLDOBJ dealloc_obj(obj); #endif bot(); /* update character's gold piece count immediately */ } return 1; } /* an object inside a cursed bag of holding is being destroyed */ STATIC_OVL long mbag_item_gone(held, item) int held; struct obj *item; { struct monst *shkp; long loss = 0L; if (item->dknown) pline("%s %s vanished!", Doname2(item), otense(item, "have")); else You("%s %s disappear!", Blind ? "notice" : "see", doname(item)); if (*u.ushops && (shkp = shop_keeper(*u.ushops)) != 0) { if (held ? (boolean) item->unpaid : costly_spot(u.ux, u.uy)) loss = stolen_value(item, u.ux, u.uy, (boolean)shkp->mpeaceful, TRUE); } obfree(item, (struct obj *) 0); return loss; } STATIC_OVL void observe_quantum_cat(box) struct obj *box; { static NEARDATA const char sc[] = "Schroedinger's Cat"; struct obj *deadcat; struct monst *livecat; xchar ox, oy; box->spe = 0; /* box->owt will be updated below */ if (get_obj_location(box, &ox, &oy, 0)) box->ox = ox, box->oy = oy; /* in case it's being carried */ /* this isn't really right, since any form of observation (telepathic or monster/object/food detection) ought to force the determination of alive vs dead state; but basing it just on opening the box is much simpler to cope with */ livecat = rn2(2) ? makemon(&mons[PM_HOUSECAT], box->ox, box->oy, NO_MINVENT) : 0; if (livecat) { livecat->mpeaceful = 1; set_malign(livecat); if (!canspotmon(livecat)) You("think %s brushed your %s.", something, body_part(FOOT)); else pline("%s inside the box is still alive!", Monnam(livecat)); (void) christen_monst(livecat, sc); } else { deadcat = mk_named_object(CORPSE, &mons[PM_HOUSECAT], box->ox, box->oy, sc); if (deadcat) { obj_extract_self(deadcat); (void) add_to_container(box, deadcat); } pline_The("%s inside the box is dead!", Hallucination ? rndmonnam() : "housecat"); } box->owt = weight(box); return; } #undef Icebox int use_container(obj, held) register struct obj *obj; register int held; { struct obj *curr, *otmp; #ifndef GOLDOBJ struct obj *u_gold = (struct obj *)0; #endif boolean one_by_one, allflag, quantum_cat = FALSE, loot_out = FALSE, loot_in = FALSE; char select[MAXOCLASSES+1]; char qbuf[BUFSZ], emptymsg[BUFSZ], pbuf[QBUFSZ]; long loss = 0L; int cnt = 0, used = 0, menu_on_request; emptymsg[0] = '\0'; if (nohands(youmonst.data)) { You("have no hands!"); /* not `body_part(HAND)' */ return 0; } else if (!freehand()) { You("have no free %s.", body_part(HAND)); return 0; } if (obj->olocked) { pline("%s to be locked.", Tobjnam(obj, "seem")); if (held) You("must put it down to unlock."); return 0; } else if (obj->otrapped) { if (held) You("open %s...", the(xname(obj))); (void) chest_trap(obj, HAND, FALSE); /* even if the trap fails, you've used up this turn */ if (multi >= 0) { /* in case we didn't become paralyzed */ nomul(-1); nomovemsg = ""; } return 1; } current_container = obj; /* for use by in/out_container */ if (obj->spe == 1) { observe_quantum_cat(obj); used = 1; quantum_cat = TRUE; /* for adjusting "it's empty" message */ } /* Count the number of contained objects. Sometimes toss objects if */ /* a cursed magic bag. */ for (curr = obj->cobj; curr; curr = otmp) { otmp = curr->nobj; if (Is_mbag(obj) && obj->cursed && !rn2(13)) { obj_extract_self(curr); loss += mbag_item_gone(held, curr); used = 1; } else { cnt++; } } if (loss) /* magic bag lost some shop goods */ You("owe %ld %s for lost merchandise.", loss, currency(loss)); obj->owt = weight(obj); /* in case any items were lost */ if (!cnt) Sprintf(emptymsg, "%s is %sempty.", Yname2(obj), quantum_cat ? "now " : ""); if (cnt || flags.menu_style == MENU_FULL) { Strcpy(qbuf, "Do you want to take something out of "); Sprintf(eos(qbuf), "%s?", safe_qbuf(qbuf, 1, yname(obj), ysimple_name(obj), "it")); if (flags.menu_style != MENU_TRADITIONAL) { if (flags.menu_style == MENU_FULL) { int t; char menuprompt[BUFSZ]; boolean outokay = (cnt != 0); #ifndef GOLDOBJ boolean inokay = (invent != 0) || (u.ugold != 0); #else boolean inokay = (invent != 0); #endif if (!outokay && !inokay) { pline("%s", emptymsg); You("don't have anything to put in."); return used; } menuprompt[0] = '\0'; if (!cnt) Sprintf(menuprompt, "%s ", emptymsg); Strcat(menuprompt, "Do what?"); t = in_or_out_menu(menuprompt, current_container, outokay, inokay); if (t <= 0) return 0; loot_out = (t & 0x01) != 0; loot_in = (t & 0x02) != 0; } else { /* MENU_COMBINATION or MENU_PARTIAL */ loot_out = (yn_function(qbuf, "ynq", 'n') == 'y'); } if (loot_out) { add_valid_menu_class(0); /* reset */ used |= menu_loot(0, current_container, FALSE) > 0; } } else { /* traditional code */ ask_again2: menu_on_request = 0; add_valid_menu_class(0); /* reset */ Strcpy(pbuf, ":ynq"); if (cnt) Strcat(pbuf, "m"); switch (yn_function(qbuf, pbuf, 'n')) { case ':': container_contents(current_container, FALSE, FALSE); goto ask_again2; case 'y': if (query_classes(select, &one_by_one, &allflag, "take out", current_container->cobj, FALSE, #ifndef GOLDOBJ FALSE, #endif &menu_on_request)) { if (askchain((struct obj **)¤t_container->cobj, (one_by_one ? (char *)0 : select), allflag, out_container, (int FDECL((*),(OBJ_P)))0, 0, "nodot")) used = 1; } else if (menu_on_request < 0) { used |= menu_loot(menu_on_request, current_container, FALSE) > 0; } /*FALLTHRU*/ case 'n': break; case 'm': menu_on_request = -2; /* triggers ALL_CLASSES */ used |= menu_loot(menu_on_request, current_container, FALSE) > 0; break; case 'q': default: return used; } } } else { pline("%s", emptymsg); /* is empty. */ } #ifndef GOLDOBJ if (!invent && u.ugold == 0) { #else if (!invent) { #endif /* nothing to put in, but some feedback is necessary */ You("don't have anything to put in."); return used; } if (flags.menu_style != MENU_FULL) { Sprintf(qbuf, "Do you wish to put %s in?", something); Strcpy(pbuf, ynqchars); if (flags.menu_style == MENU_TRADITIONAL && invent && inv_cnt() > 0) Strcat(pbuf, "m"); switch (yn_function(qbuf, pbuf, 'n')) { case 'y': loot_in = TRUE; break; case 'n': break; case 'm': add_valid_menu_class(0); /* reset */ menu_on_request = -2; /* triggers ALL_CLASSES */ used |= menu_loot(menu_on_request, current_container, TRUE) > 0; break; case 'q': default: return used; } } /* * Gone: being nice about only selecting food if we know we are * putting things in an ice chest. */ if (loot_in) { #ifndef GOLDOBJ if (u.ugold) { /* * Hack: gold is not in the inventory, so make a gold object * and put it at the head of the inventory list. */ u_gold = mkgoldobj(u.ugold); /* removes from u.ugold */ u_gold->in_use = TRUE; u.ugold = u_gold->quan; /* put the gold back */ assigninvlet(u_gold); /* might end up as NOINVSYM */ u_gold->nobj = invent; invent = u_gold; } #endif add_valid_menu_class(0); /* reset */ if (flags.menu_style != MENU_TRADITIONAL) { used |= menu_loot(0, current_container, TRUE) > 0; } else { /* traditional code */ menu_on_request = 0; if (query_classes(select, &one_by_one, &allflag, "put in", invent, FALSE, #ifndef GOLDOBJ (u.ugold != 0L), #endif &menu_on_request)) { (void) askchain((struct obj **)&invent, (one_by_one ? (char *)0 : select), allflag, in_container, ck_bag, 0, "nodot"); used = 1; } else if (menu_on_request < 0) { used |= menu_loot(menu_on_request, current_container, TRUE) > 0; } } } #ifndef GOLDOBJ if (u_gold && invent && invent->oclass == COIN_CLASS) { /* didn't stash [all of] it */ u_gold = invent; invent = u_gold->nobj; u_gold->in_use = FALSE; dealloc_obj(u_gold); } #endif return used; } /* Loot a container (take things out, put things in), using a menu. */ STATIC_OVL int menu_loot(retry, container, put_in) int retry; struct obj *container; boolean put_in; { int n, i, n_looted = 0; boolean all_categories = TRUE, loot_everything = FALSE; char buf[BUFSZ]; const char *takeout = "Take out", *putin = "Put in"; struct obj *otmp, *otmp2; menu_item *pick_list; int mflags, res; long count; if (retry) { all_categories = (retry == -2); } else if (flags.menu_style == MENU_FULL) { all_categories = FALSE; Sprintf(buf,"%s what type of objects?", put_in ? putin : takeout); mflags = put_in ? ALL_TYPES | BUC_ALLBKNOWN | BUC_UNKNOWN : ALL_TYPES | CHOOSE_ALL | BUC_ALLBKNOWN | BUC_UNKNOWN; n = query_category(buf, put_in ? invent : container->cobj, mflags, &pick_list, PICK_ANY); if (!n) return 0; for (i = 0; i < n; i++) { if (pick_list[i].item.a_int == 'A') loot_everything = TRUE; else if (pick_list[i].item.a_int == ALL_TYPES_SELECTED) all_categories = TRUE; else add_valid_menu_class(pick_list[i].item.a_int); } free((genericptr_t) pick_list); } if (loot_everything) { for (otmp = container->cobj; otmp; otmp = otmp2) { otmp2 = otmp->nobj; res = out_container(otmp); if (res < 0) break; } } else { mflags = INVORDER_SORT; if (put_in && flags.invlet_constant) mflags |= USE_INVLET; Sprintf(buf,"%s what?", put_in ? putin : takeout); n = query_objlist(buf, put_in ? invent : container->cobj, mflags, &pick_list, PICK_ANY, all_categories ? allow_all : allow_category); if (n) { n_looted = n; for (i = 0; i < n; i++) { otmp = pick_list[i].item.a_obj; count = pick_list[i].count; if (count > 0 && count < otmp->quan) { otmp = splitobj(otmp, count); /* special split case also handled by askchain() */ } res = put_in ? in_container(otmp) : out_container(otmp); if (res < 0) { if (otmp != pick_list[i].item.a_obj) { /* split occurred, merge again */ (void) merged(&pick_list[i].item.a_obj, &otmp); } break; } } free((genericptr_t)pick_list); } } return n_looted; } STATIC_OVL int in_or_out_menu(prompt, obj, outokay, inokay) const char *prompt; struct obj *obj; boolean outokay, inokay; { winid win; anything any; menu_item *pick_list; char buf[BUFSZ]; int n; const char *menuselector = iflags.lootabc ? "abc" : "oib"; any.a_void = 0; win = create_nhwindow(NHW_MENU); start_menu(win); if (outokay) { any.a_int = 1; Sprintf(buf,"Take %s out of %s", something, the(xname(obj))); add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED); } menuselector++; if (inokay) { any.a_int = 2; Sprintf(buf,"Put %s into %s", something, the(xname(obj))); add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, buf, MENU_UNSELECTED); } menuselector++; if (outokay && inokay) { any.a_int = 3; add_menu(win, NO_GLYPH, &any, *menuselector, 0, ATR_NONE, "Both of the above", MENU_UNSELECTED); } end_menu(win, prompt); n = select_menu(win, PICK_ONE, &pick_list); destroy_nhwindow(win); if (n > 0) { n = pick_list[0].item.a_int; free((genericptr_t) pick_list); } return n; } /*pickup.c*/ nethack-3.4.3/src/pline.c0100644000000000000000000002435607764735041013726 0ustar rootroot/* SCCS Id: @(#)pline.c 3.4 1999/11/28 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers */ #include "hack.h" #include "epri.h" #ifdef WIZARD #include "edog.h" #endif #ifdef OVLB static boolean no_repeat = FALSE; static char *FDECL(You_buf, (int)); /*VARARGS1*/ /* Note that these declarations rely on knowledge of the internals * of the variable argument handling stuff in "tradstdc.h" */ #if defined(USE_STDARG) || defined(USE_VARARGS) static void FDECL(vpline, (const char *, va_list)); void pline VA_DECL(const char *, line) VA_START(line); VA_INIT(line, char *); vpline(line, VA_ARGS); VA_END(); } # ifdef USE_STDARG static void vpline(const char *line, va_list the_args) { # else static void vpline(line, the_args) const char *line; va_list the_args; { # endif #else /* USE_STDARG | USE_VARARG */ #define vpline pline void pline VA_DECL(const char *, line) #endif /* USE_STDARG | USE_VARARG */ char pbuf[BUFSZ]; /* Do NOT use VA_START and VA_END in here... see above */ if (!line || !*line) return; if (index(line, '%')) { Vsprintf(pbuf,line,VA_ARGS); line = pbuf; } if (!iflags.window_inited) { raw_print(line); return; } #ifndef MAC if (no_repeat && !strcmp(line, toplines)) return; #endif /* MAC */ if (vision_full_recalc) vision_recalc(0); if (u.ux) flush_screen(1); /* %% */ putstr(WIN_MESSAGE, 0, line); } /*VARARGS1*/ void Norep VA_DECL(const char *, line) VA_START(line); VA_INIT(line, const char *); no_repeat = TRUE; vpline(line, VA_ARGS); no_repeat = FALSE; VA_END(); return; } /* work buffer for You(), &c and verbalize() */ static char *you_buf = 0; static int you_buf_siz = 0; static char * You_buf(siz) int siz; { if (siz > you_buf_siz) { if (you_buf) free((genericptr_t) you_buf); you_buf_siz = siz + 10; you_buf = (char *) alloc((unsigned) you_buf_siz); } return you_buf; } void free_youbuf() { if (you_buf) free((genericptr_t) you_buf), you_buf = (char *)0; you_buf_siz = 0; } /* `prefix' must be a string literal, not a pointer */ #define YouPrefix(pointer,prefix,text) \ Strcpy((pointer = You_buf((int)(strlen(text) + sizeof prefix))), prefix) #define YouMessage(pointer,prefix,text) \ strcat((YouPrefix(pointer, prefix, text), pointer), text) /*VARARGS1*/ void You VA_DECL(const char *, line) char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "You ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void Your VA_DECL(const char *,line) char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "Your ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void You_feel VA_DECL(const char *,line) char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "You feel ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void You_cant VA_DECL(const char *,line) char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "You can't ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void pline_The VA_DECL(const char *,line) char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "The ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void There VA_DECL(const char *,line) char *tmp; VA_START(line); VA_INIT(line, const char *); vpline(YouMessage(tmp, "There ", line), VA_ARGS); VA_END(); } /*VARARGS1*/ void You_hear VA_DECL(const char *,line) char *tmp; VA_START(line); VA_INIT(line, const char *); if (Underwater) YouPrefix(tmp, "You barely hear ", line); else if (u.usleep) YouPrefix(tmp, "You dream that you hear ", line); else YouPrefix(tmp, "You hear ", line); vpline(strcat(tmp, line), VA_ARGS); VA_END(); } /*VARARGS1*/ void verbalize VA_DECL(const char *,line) char *tmp; if (!flags.soundok) return; VA_START(line); VA_INIT(line, const char *); tmp = You_buf((int)strlen(line) + sizeof "\"\""); Strcpy(tmp, "\""); Strcat(tmp, line); Strcat(tmp, "\""); vpline(tmp, VA_ARGS); VA_END(); } /*VARARGS1*/ /* Note that these declarations rely on knowledge of the internals * of the variable argument handling stuff in "tradstdc.h" */ #if defined(USE_STDARG) || defined(USE_VARARGS) static void FDECL(vraw_printf,(const char *,va_list)); void raw_printf VA_DECL(const char *, line) VA_START(line); VA_INIT(line, char *); vraw_printf(line, VA_ARGS); VA_END(); } # ifdef USE_STDARG static void vraw_printf(const char *line, va_list the_args) { # else static void vraw_printf(line, the_args) const char *line; va_list the_args; { # endif #else /* USE_STDARG | USE_VARARG */ void raw_printf VA_DECL(const char *, line) #endif /* Do NOT use VA_START and VA_END in here... see above */ if(!index(line, '%')) raw_print(line); else { char pbuf[BUFSZ]; Vsprintf(pbuf,line,VA_ARGS); raw_print(pbuf); } } /*VARARGS1*/ void impossible VA_DECL(const char *, s) VA_START(s); VA_INIT(s, const char *); if (program_state.in_impossible) panic("impossible called impossible"); program_state.in_impossible = 1; { char pbuf[BUFSZ]; Vsprintf(pbuf,s,VA_ARGS); paniclog("impossible", pbuf); } vpline(s,VA_ARGS); pline("Program in disorder - perhaps you'd better #quit."); program_state.in_impossible = 0; VA_END(); } const char * align_str(alignment) aligntyp alignment; { switch ((int)alignment) { case A_CHAOTIC: return "chaotic"; case A_NEUTRAL: return "neutral"; case A_LAWFUL: return "lawful"; case A_NONE: return "unaligned"; } return "unknown"; } void mstatusline(mtmp) register struct monst *mtmp; { aligntyp alignment; char info[BUFSZ], monnambuf[BUFSZ]; if (mtmp->ispriest || mtmp->data == &mons[PM_ALIGNED_PRIEST] || mtmp->data == &mons[PM_ANGEL]) alignment = EPRI(mtmp)->shralign; else alignment = mtmp->data->maligntyp; alignment = (alignment > 0) ? A_LAWFUL : (alignment < 0) ? A_CHAOTIC : A_NEUTRAL; info[0] = 0; if (mtmp->mtame) { Strcat(info, ", tame"); #ifdef WIZARD if (wizard) { Sprintf(eos(info), " (%d", mtmp->mtame); if (!mtmp->isminion) Sprintf(eos(info), "; hungry %ld; apport %d", EDOG(mtmp)->hungrytime, EDOG(mtmp)->apport); Strcat(info, ")"); } #endif } else if (mtmp->mpeaceful) Strcat(info, ", peaceful"); if (mtmp->meating) Strcat(info, ", eating"); if (mtmp->mcan) Strcat(info, ", cancelled"); if (mtmp->mconf) Strcat(info, ", confused"); if (mtmp->mblinded || !mtmp->mcansee) Strcat(info, ", blind"); if (mtmp->mstun) Strcat(info, ", stunned"); if (mtmp->msleeping) Strcat(info, ", asleep"); #if 0 /* unfortunately mfrozen covers temporary sleep and being busy (donning armor, for instance) as well as paralysis */ else if (mtmp->mfrozen) Strcat(info, ", paralyzed"); #else else if (mtmp->mfrozen || !mtmp->mcanmove) Strcat(info, ", can't move"); #endif /* [arbitrary reason why it isn't moving] */ else if (mtmp->mstrategy & STRAT_WAITMASK) Strcat(info, ", meditating"); else if (mtmp->mflee) Strcat(info, ", scared"); if (mtmp->mtrapped) Strcat(info, ", trapped"); if (mtmp->mspeed) Strcat(info, mtmp->mspeed == MFAST ? ", fast" : mtmp->mspeed == MSLOW ? ", slow" : ", ???? speed"); if (mtmp->mundetected) Strcat(info, ", concealed"); if (mtmp->minvis) Strcat(info, ", invisible"); if (mtmp == u.ustuck) Strcat(info, (sticks(youmonst.data)) ? ", held by you" : u.uswallow ? (is_animal(u.ustuck->data) ? ", swallowed you" : ", engulfed you") : ", holding you"); #ifdef STEED if (mtmp == u.usteed) Strcat(info, ", carrying you"); #endif /* avoid "Status of the invisible newt ..., invisible" */ /* and unlike a normal mon_nam, use "saddled" even if it has a name */ Strcpy(monnambuf, x_monnam(mtmp, ARTICLE_THE, (char *)0, (SUPPRESS_IT|SUPPRESS_INVISIBLE), FALSE)); pline("Status of %s (%s): Level %d HP %d(%d) AC %d%s.", monnambuf, align_str(alignment), mtmp->m_lev, mtmp->mhp, mtmp->mhpmax, find_mac(mtmp), info); } void ustatusline() { char info[BUFSZ]; info[0] = '\0'; if (Sick) { Strcat(info, ", dying from"); if (u.usick_type & SICK_VOMITABLE) Strcat(info, " food poisoning"); if (u.usick_type & SICK_NONVOMITABLE) { if (u.usick_type & SICK_VOMITABLE) Strcat(info, " and"); Strcat(info, " illness"); } } if (Stoned) Strcat(info, ", solidifying"); if (Slimed) Strcat(info, ", becoming slimy"); if (Strangled) Strcat(info, ", being strangled"); if (Vomiting) Strcat(info, ", nauseated"); /* !"nauseous" */ if (Confusion) Strcat(info, ", confused"); if (Blind) { Strcat(info, ", blind"); if (u.ucreamed) { if ((long)u.ucreamed < Blinded || Blindfolded || !haseyes(youmonst.data)) Strcat(info, ", cover"); Strcat(info, "ed by sticky goop"); } /* note: "goop" == "glop"; variation is intentional */ } if (Stunned) Strcat(info, ", stunned"); #ifdef STEED if (!u.usteed) #endif if (Wounded_legs) { const char *what = body_part(LEG); if ((Wounded_legs & BOTH_SIDES) == BOTH_SIDES) what = makeplural(what); Sprintf(eos(info), ", injured %s", what); } if (Glib) Sprintf(eos(info), ", slippery %s", makeplural(body_part(HAND))); if (u.utrap) Strcat(info, ", trapped"); if (Fast) Strcat(info, Very_fast ? ", very fast" : ", fast"); if (u.uundetected) Strcat(info, ", concealed"); if (Invis) Strcat(info, ", invisible"); if (u.ustuck) { if (sticks(youmonst.data)) Strcat(info, ", holding "); else Strcat(info, ", held by "); Strcat(info, mon_nam(u.ustuck)); } pline("Status of %s (%s%s): Level %d HP %d(%d) AC %d%s.", plname, (u.ualign.record >= 20) ? "piously " : (u.ualign.record > 13) ? "devoutly " : (u.ualign.record > 8) ? "fervently " : (u.ualign.record > 3) ? "stridently " : (u.ualign.record == 3) ? "" : (u.ualign.record >= 1) ? "haltingly " : (u.ualign.record == 0) ? "nominally " : "insufficiently ", align_str(u.ualign.type), Upolyd ? mons[u.umonnum].mlevel : u.ulevel, Upolyd ? u.mh : u.uhp, Upolyd ? u.mhmax : u.uhpmax, u.uac, info); } void self_invis_message() { pline("%s %s.", Hallucination ? "Far out, man! You" : "Gee! All of a sudden, you", See_invisible ? "can see right through yourself" : "can't see yourself"); } #endif /* OVLB */ /*pline.c*/ nethack-3.4.3/src/polyself.c0100644000000000000000000011204607764735041014446 0ustar rootroot/* SCCS Id: @(#)polyself.c 3.4 2003/01/08 */ /* Copyright (C) 1987, 1988, 1989 by Ken Arromdee */ /* NetHack may be freely redistributed. See license for details. */ /* * Polymorph self routine. * * Note: the light source handling code assumes that both youmonst.m_id * and youmonst.mx will always remain 0 when it handles the case of the * player polymorphed into a light-emitting monster. */ #include "hack.h" #ifdef OVLB STATIC_DCL void FDECL(polyman, (const char *,const char *)); STATIC_DCL void NDECL(break_armor); STATIC_DCL void FDECL(drop_weapon,(int)); STATIC_DCL void NDECL(uunstick); STATIC_DCL int FDECL(armor_to_dragon,(int)); STATIC_DCL void NDECL(newman); /* update the youmonst.data structure pointer */ void set_uasmon() { set_mon_data(&youmonst, &mons[u.umonnum], 0); } /* make a (new) human out of the player */ STATIC_OVL void polyman(fmt, arg) const char *fmt, *arg; { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, was_mimicking = (youmonst.m_ap_type == M_AP_OBJECT); boolean could_pass_walls = Passes_walls; boolean was_blind = !!Blind; if (Upolyd) { u.acurr = u.macurr; /* restore old attribs */ u.amax = u.mamax; u.umonnum = u.umonster; flags.female = u.mfemale; } set_uasmon(); u.mh = u.mhmax = 0; u.mtimedone = 0; skinback(FALSE); u.uundetected = 0; if (sticky) uunstick(); find_ac(); if (was_mimicking) { if (multi < 0) unmul(""); youmonst.m_ap_type = M_AP_NOTHING; } newsym(u.ux,u.uy); You(fmt, arg); /* check whether player foolishly genocided self while poly'd */ if ((mvitals[urole.malenum].mvflags & G_GENOD) || (urole.femalenum != NON_PM && (mvitals[urole.femalenum].mvflags & G_GENOD)) || (mvitals[urace.malenum].mvflags & G_GENOD) || (urace.femalenum != NON_PM && (mvitals[urace.femalenum].mvflags & G_GENOD))) { /* intervening activity might have clobbered genocide info */ killer = delayed_killer; if (!killer || !strstri(killer, "genocid")) { killer_format = KILLED_BY; killer = "self-genocide"; } done(GENOCIDED); } if (u.twoweap && !could_twoweap(youmonst.data)) untwoweapon(); if (u.utraptype == TT_PIT) { if (could_pass_walls) { /* player forms cannot pass walls */ u.utrap = rn1(6,2); } } if (was_blind && !Blind) { /* reverting from eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ } if(!Levitation && !u.ustuck && (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy))) spoteffects(TRUE); see_monsters(); } void change_sex() { /* setting u.umonster for caveman/cavewoman or priest/priestess swap unintentionally makes `Upolyd' appear to be true */ boolean already_polyd = (boolean) Upolyd; /* Some monsters are always of one sex and their sex can't be changed */ /* succubi/incubi can change, but are handled below */ /* !already_polyd check necessary because is_male() and is_female() are true if the player is a priest/priestess */ if (!already_polyd || (!is_male(youmonst.data) && !is_female(youmonst.data) && !is_neuter(youmonst.data))) flags.female = !flags.female; if (already_polyd) /* poly'd: also change saved sex */ u.mfemale = !u.mfemale; max_rank_sz(); /* [this appears to be superfluous] */ if ((already_polyd ? u.mfemale : flags.female) && urole.name.f) Strcpy(pl_character, urole.name.f); else Strcpy(pl_character, urole.name.m); u.umonster = ((already_polyd ? u.mfemale : flags.female) && urole.femalenum != NON_PM) ? urole.femalenum : urole.malenum; if (!already_polyd) { u.umonnum = u.umonster; } else if (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS) { flags.female = !flags.female; /* change monster type to match new sex */ u.umonnum = (u.umonnum == PM_SUCCUBUS) ? PM_INCUBUS : PM_SUCCUBUS; set_uasmon(); } } STATIC_OVL void newman() { int tmp, oldlvl; tmp = u.uhpmax; oldlvl = u.ulevel; u.ulevel = u.ulevel + rn1(5, -2); if (u.ulevel > 127 || u.ulevel < 1) { /* level went below 0? */ u.ulevel = oldlvl; /* restore old level in case they lifesave */ goto dead; } if (u.ulevel > MAXULEV) u.ulevel = MAXULEV; /* If your level goes down, your peak level goes down by the same amount so that you can't simply use blessed full healing to undo the decrease. But if your level goes up, your peak level does *not* undergo the same adjustment; you might end up losing out on the chance to regain some levels previously lost to other causes. */ if (u.ulevel < oldlvl) u.ulevelmax -= (oldlvl - u.ulevel); if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel; if (!rn2(10)) change_sex(); adjabil(oldlvl, (int)u.ulevel); reset_rndmonst(NON_PM); /* new monster generation criteria */ /* random experience points for the new experience level */ u.uexp = rndexp(FALSE); /* u.uhpmax * u.ulevel / oldlvl: proportionate hit points to new level * -10 and +10: don't apply proportionate HP to 10 of a starting * character's hit points (since a starting character's hit points * are not on the same scale with hit points obtained through level * gain) * 9 - rn2(19): random change of -9 to +9 hit points */ #ifndef LINT u.uhpmax = ((u.uhpmax - 10) * (long)u.ulevel / oldlvl + 10) + (9 - rn2(19)); #endif #ifdef LINT u.uhp = u.uhp + tmp; #else u.uhp = u.uhp * (long)u.uhpmax/tmp; #endif tmp = u.uenmax; #ifndef LINT u.uenmax = u.uenmax * (long)u.ulevel / oldlvl + 9 - rn2(19); #endif if (u.uenmax < 0) u.uenmax = 0; #ifndef LINT u.uen = (tmp ? u.uen * (long)u.uenmax / tmp : u.uenmax); #endif redist_attr(); u.uhunger = rn1(500,500); if (Sick) make_sick(0L, (char *) 0, FALSE, SICK_ALL); Stoned = 0; delayed_killer = 0; if (u.uhp <= 0 || u.uhpmax <= 0) { if (Polymorph_control) { if (u.uhp <= 0) u.uhp = 1; if (u.uhpmax <= 0) u.uhpmax = 1; } else { dead: /* we come directly here if their experience level went to 0 or less */ Your("new form doesn't seem healthy enough to survive."); killer_format = KILLED_BY_AN; killer="unsuccessful polymorph"; done(DIED); newuhs(FALSE); return; /* lifesaved */ } } newuhs(FALSE); polyman("feel like a new %s!", (flags.female && urace.individual.f) ? urace.individual.f : (urace.individual.m) ? urace.individual.m : urace.noun); if (Slimed) { Your("body transforms, but there is still slime on you."); Slimed = 10L; } flags.botl = 1; see_monsters(); (void) encumber_msg(); } void polyself(forcecontrol) boolean forcecontrol; { char buf[BUFSZ]; int old_light, new_light; int mntmp = NON_PM; int tries=0; boolean draconian = (uarm && uarm->otyp >= GRAY_DRAGON_SCALE_MAIL && uarm->otyp <= YELLOW_DRAGON_SCALES); boolean iswere = (u.ulycn >= LOW_PM || is_were(youmonst.data)); boolean isvamp = (youmonst.data->mlet == S_VAMPIRE || u.umonnum == PM_VAMPIRE_BAT); boolean was_floating = (Levitation || Flying); if(!Polymorph_control && !forcecontrol && !draconian && !iswere && !isvamp) { if (rn2(20) > ACURR(A_CON)) { You(shudder_for_moment); losehp(rnd(30), "system shock", KILLED_BY_AN); exercise(A_CON, FALSE); return; } } old_light = Upolyd ? emits_light(youmonst.data) : 0; if (Polymorph_control || forcecontrol) { do { getlin("Become what kind of monster? [type the name]", buf); mntmp = name_to_mon(buf); if (mntmp < LOW_PM) pline("I've never heard of such monsters."); /* Note: humans are illegal as monsters, but an * illegal monster forces newman(), which is what we * want if they specified a human.... */ else if (!polyok(&mons[mntmp]) && !your_race(&mons[mntmp])) You("cannot polymorph into that."); else break; } while(++tries < 5); if (tries==5) pline(thats_enough_tries); /* allow skin merging, even when polymorph is controlled */ if (draconian && (mntmp == armor_to_dragon(uarm->otyp) || tries == 5)) goto do_merge; } else if (draconian || iswere || isvamp) { /* special changes that don't require polyok() */ if (draconian) { do_merge: mntmp = armor_to_dragon(uarm->otyp); if (!(mvitals[mntmp].mvflags & G_GENOD)) { /* allow G_EXTINCT */ You("merge with your scaly armor."); uskin = uarm; uarm = (struct obj *)0; /* save/restore hack */ uskin->owornmask |= I_SPECIAL; } } else if (iswere) { if (is_were(youmonst.data)) mntmp = PM_HUMAN; /* Illegal; force newman() */ else mntmp = u.ulycn; } else { if (youmonst.data->mlet == S_VAMPIRE) mntmp = PM_VAMPIRE_BAT; else mntmp = PM_VAMPIRE; } /* if polymon fails, "you feel" message has been given so don't follow up with another polymon or newman */ if (mntmp == PM_HUMAN) newman(); /* werecritter */ else (void) polymon(mntmp); goto made_change; /* maybe not, but this is right anyway */ } if (mntmp < LOW_PM) { tries = 0; do { /* randomly pick an "ordinary" monster */ mntmp = rn1(SPECIAL_PM - LOW_PM, LOW_PM); } while((!polyok(&mons[mntmp]) || is_placeholder(&mons[mntmp])) && tries++ < 200); } /* The below polyok() fails either if everything is genocided, or if * we deliberately chose something illegal to force newman(). */ if (!polyok(&mons[mntmp]) || !rn2(5) || your_race(&mons[mntmp])) newman(); else if(!polymon(mntmp)) return; if (!uarmg) selftouch("No longer petrify-resistant, you"); made_change: new_light = Upolyd ? emits_light(youmonst.data) : 0; if (old_light != new_light) { if (old_light) del_light_source(LS_MONSTER, (genericptr_t)&youmonst); if (new_light == 1) ++new_light; /* otherwise it's undetectable */ if (new_light) new_light_source(u.ux, u.uy, new_light, LS_MONSTER, (genericptr_t)&youmonst); } if (is_pool(u.ux,u.uy) && was_floating && !(Levitation || Flying) && !breathless(youmonst.data) && !amphibious(youmonst.data) && !Swimming) drown(); } /* (try to) make a mntmp monster out of the player */ int polymon(mntmp) /* returns 1 if polymorph successful */ int mntmp; { boolean sticky = sticks(youmonst.data) && u.ustuck && !u.uswallow, was_blind = !!Blind, dochange = FALSE; boolean could_pass_walls = Passes_walls; int mlvl; if (mvitals[mntmp].mvflags & G_GENOD) { /* allow G_EXTINCT */ You_feel("rather %s-ish.",mons[mntmp].mname); exercise(A_WIS, TRUE); return(0); } /* KMH, conduct */ u.uconduct.polyselfs++; if (!Upolyd) { /* Human to monster; save human stats */ u.macurr = u.acurr; u.mamax = u.amax; u.mfemale = flags.female; } else { /* Monster to monster; restore human stats, to be * immediately changed to provide stats for the new monster */ u.acurr = u.macurr; u.amax = u.mamax; flags.female = u.mfemale; } if (youmonst.m_ap_type) { /* stop mimicking immediately */ if (multi < 0) unmul(""); } else if (mons[mntmp].mlet != S_MIMIC) { /* as in polyman() */ youmonst.m_ap_type = M_AP_NOTHING; } if (is_male(&mons[mntmp])) { if(flags.female) dochange = TRUE; } else if (is_female(&mons[mntmp])) { if(!flags.female) dochange = TRUE; } else if (!is_neuter(&mons[mntmp]) && mntmp != u.ulycn) { if(!rn2(10)) dochange = TRUE; } if (dochange) { flags.female = !flags.female; You("%s %s%s!", (u.umonnum != mntmp) ? "turn into a" : "feel like a new", (is_male(&mons[mntmp]) || is_female(&mons[mntmp])) ? "" : flags.female ? "female " : "male ", mons[mntmp].mname); } else { if (u.umonnum != mntmp) You("turn into %s!", an(mons[mntmp].mname)); else You_feel("like a new %s!", mons[mntmp].mname); } if (Stoned && poly_when_stoned(&mons[mntmp])) { /* poly_when_stoned already checked stone golem genocide */ You("turn to stone!"); mntmp = PM_STONE_GOLEM; Stoned = 0; delayed_killer = 0; } u.mtimedone = rn1(500, 500); u.umonnum = mntmp; set_uasmon(); /* New stats for monster, to last only as long as polymorphed. * Currently only strength gets changed. */ if(strongmonst(&mons[mntmp])) ABASE(A_STR) = AMAX(A_STR) = STR18(100); if (Stone_resistance && Stoned) { /* parnes@eniac.seas.upenn.edu */ Stoned = 0; delayed_killer = 0; You("no longer seem to be petrifying."); } if (Sick_resistance && Sick) { make_sick(0L, (char *) 0, FALSE, SICK_ALL); You("no longer feel sick."); } if (Slimed) { if (flaming(youmonst.data)) { pline_The("slime burns away!"); Slimed = 0L; flags.botl = 1; } else if (mntmp == PM_GREEN_SLIME) { /* do it silently */ Slimed = 0L; flags.botl = 1; } } if (nohands(youmonst.data)) Glib = 0; /* mlvl = adj_lev(&mons[mntmp]); * We can't do the above, since there's no such thing as an * "experience level of you as a monster" for a polymorphed character. */ mlvl = (int)mons[mntmp].mlevel; if (youmonst.data->mlet == S_DRAGON && mntmp >= PM_GRAY_DRAGON) { u.mhmax = In_endgame(&u.uz) ? (8*mlvl) : (4*mlvl + d(mlvl,4)); } else if (is_golem(youmonst.data)) { u.mhmax = golemhp(mntmp); } else { if (!mlvl) u.mhmax = rnd(4); else u.mhmax = d(mlvl, 8); if (is_home_elemental(&mons[mntmp])) u.mhmax *= 3; } u.mh = u.mhmax; if (u.ulevel < mlvl) { /* Low level characters can't become high level monsters for long */ #ifdef DUMB /* DRS/NS 2.2.6 messes up -- Peter Kendell */ int mtd = u.mtimedone, ulv = u.ulevel; u.mtimedone = mtd * ulv / mlvl; #else u.mtimedone = u.mtimedone * u.ulevel / mlvl; #endif } if (uskin && mntmp != armor_to_dragon(uskin->otyp)) skinback(FALSE); break_armor(); drop_weapon(1); if (hides_under(youmonst.data)) u.uundetected = OBJ_AT(u.ux, u.uy); else if (youmonst.data->mlet == S_EEL) u.uundetected = is_pool(u.ux, u.uy); else u.uundetected = 0; if (u.utraptype == TT_PIT) { if (could_pass_walls && !Passes_walls) { u.utrap = rn1(6,2); } else if (!could_pass_walls && Passes_walls) { u.utrap = 0; } } if (was_blind && !Blind) { /* previous form was eyeless */ Blinded = 1L; make_blinded(0L, TRUE); /* remove blindness */ } newsym(u.ux,u.uy); /* Change symbol */ if (!sticky && !u.uswallow && u.ustuck && sticks(youmonst.data)) u.ustuck = 0; else if (sticky && !sticks(youmonst.data)) uunstick(); #ifdef STEED if (u.usteed) { if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { char buf[BUFSZ]; pline("No longer petrifying-resistant, you touch %s.", mon_nam(u.usteed)); Sprintf(buf, "riding %s", an(u.usteed->data->mname)); instapetrify(buf); } if (!can_ride(u.usteed)) dismount_steed(DISMOUNT_POLY); } #endif if (flags.verbose) { static const char use_thec[] = "Use the command #%s to %s."; static const char monsterc[] = "monster"; if (can_breathe(youmonst.data)) pline(use_thec,monsterc,"use your breath weapon"); if (attacktype(youmonst.data, AT_SPIT)) pline(use_thec,monsterc,"spit venom"); if (youmonst.data->mlet == S_NYMPH) pline(use_thec,monsterc,"remove an iron ball"); if (attacktype(youmonst.data, AT_GAZE)) pline(use_thec,monsterc,"gaze at monsters"); if (is_hider(youmonst.data)) pline(use_thec,monsterc,"hide"); if (is_were(youmonst.data)) pline(use_thec,monsterc,"summon help"); if (webmaker(youmonst.data)) pline(use_thec,monsterc,"spin a web"); if (u.umonnum == PM_GREMLIN) pline(use_thec,monsterc,"multiply in a fountain"); if (is_unicorn(youmonst.data)) pline(use_thec,monsterc,"use your horn"); if (is_mind_flayer(youmonst.data)) pline(use_thec,monsterc,"emit a mental blast"); if (youmonst.data->msound == MS_SHRIEK) /* worthless, actually */ pline(use_thec,monsterc,"shriek"); if (lays_eggs(youmonst.data) && flags.female) pline(use_thec,"sit","lay an egg"); } /* you now know what an egg of your type looks like */ if (lays_eggs(youmonst.data)) { learn_egg_type(u.umonnum); /* make queen bees recognize killer bee eggs */ learn_egg_type(egg_type_from_parent(u.umonnum, TRUE)); } find_ac(); if((!Levitation && !u.ustuck && !Flying && (is_pool(u.ux,u.uy) || is_lava(u.ux,u.uy))) || (Underwater && !Swimming)) spoteffects(TRUE); if (Passes_walls && u.utrap && u.utraptype == TT_INFLOOR) { u.utrap = 0; pline_The("rock seems to no longer trap you."); } else if (likes_lava(youmonst.data) && u.utrap && u.utraptype == TT_LAVA) { u.utrap = 0; pline_The("lava now feels soothing."); } if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { if (Punished) { You("slip out of the iron chain."); unpunish(); } } if (u.utrap && (u.utraptype == TT_WEB || u.utraptype == TT_BEARTRAP) && (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data) || (youmonst.data->msize <= MZ_SMALL && u.utraptype == TT_BEARTRAP))) { You("are no longer stuck in the %s.", u.utraptype == TT_WEB ? "web" : "bear trap"); /* probably should burn webs too if PM_FIRE_ELEMENTAL */ u.utrap = 0; } if (webmaker(youmonst.data) && u.utrap && u.utraptype == TT_WEB) { You("orient yourself on the web."); u.utrap = 0; } flags.botl = 1; vision_full_recalc = 1; see_monsters(); exercise(A_CON, FALSE); exercise(A_WIS, TRUE); (void) encumber_msg(); return(1); } STATIC_OVL void break_armor() { register struct obj *otmp; if (breakarm(youmonst.data)) { if ((otmp = uarm) != 0) { if (donning(otmp)) cancel_don(); You("break out of your armor!"); exercise(A_STR, FALSE); (void) Armor_gone(); useup(otmp); } if ((otmp = uarmc) != 0) { if(otmp->oartifact) { Your("%s falls off!", cloak_simple_name(otmp)); (void) Cloak_off(); dropx(otmp); } else { Your("%s tears apart!", cloak_simple_name(otmp)); (void) Cloak_off(); useup(otmp); } } #ifdef TOURIST if (uarmu) { Your("shirt rips to shreds!"); useup(uarmu); } #endif } else if (sliparm(youmonst.data)) { if (((otmp = uarm) != 0) && (racial_exception(&youmonst, otmp) < 1)) { if (donning(otmp)) cancel_don(); Your("armor falls around you!"); (void) Armor_gone(); dropx(otmp); } if ((otmp = uarmc) != 0) { if (is_whirly(youmonst.data)) Your("%s falls, unsupported!", cloak_simple_name(otmp)); else You("shrink out of your %s!", cloak_simple_name(otmp)); (void) Cloak_off(); dropx(otmp); } #ifdef TOURIST if ((otmp = uarmu) != 0) { if (is_whirly(youmonst.data)) You("seep right through your shirt!"); else You("become much too small for your shirt!"); setworn((struct obj *)0, otmp->owornmask & W_ARMU); dropx(otmp); } #endif } if (has_horns(youmonst.data)) { if ((otmp = uarmh) != 0) { if (is_flimsy(otmp) && !donning(otmp)) { char hornbuf[BUFSZ], yourbuf[BUFSZ]; /* Future possiblities: This could damage/destroy helmet */ Sprintf(hornbuf, "horn%s", plur(num_horns(youmonst.data))); Your("%s %s through %s %s.", hornbuf, vtense(hornbuf, "pierce"), shk_your(yourbuf, otmp), xname(otmp)); } else { if (donning(otmp)) cancel_don(); Your("helmet falls to the %s!", surface(u.ux, u.uy)); (void) Helmet_off(); dropx(otmp); } } } if (nohands(youmonst.data) || verysmall(youmonst.data)) { if ((otmp = uarmg) != 0) { if (donning(otmp)) cancel_don(); /* Drop weapon along with gloves */ You("drop your gloves%s!", uwep ? " and weapon" : ""); drop_weapon(0); (void) Gloves_off(); dropx(otmp); } if ((otmp = uarms) != 0) { You("can no longer hold your shield!"); (void) Shield_off(); dropx(otmp); } if ((otmp = uarmh) != 0) { if (donning(otmp)) cancel_don(); Your("helmet falls to the %s!", surface(u.ux, u.uy)); (void) Helmet_off(); dropx(otmp); } } if (nohands(youmonst.data) || verysmall(youmonst.data) || slithy(youmonst.data) || youmonst.data->mlet == S_CENTAUR) { if ((otmp = uarmf) != 0) { if (donning(otmp)) cancel_don(); if (is_whirly(youmonst.data)) Your("boots fall away!"); else Your("boots %s off your feet!", verysmall(youmonst.data) ? "slide" : "are pushed"); (void) Boots_off(); dropx(otmp); } } } STATIC_OVL void drop_weapon(alone) int alone; { struct obj *otmp; struct obj *otmp2; if ((otmp = uwep) != 0) { /* !alone check below is currently superfluous but in the * future it might not be so if there are monsters which cannot * wear gloves but can wield weapons */ if (!alone || cantwield(youmonst.data)) { struct obj *wep = uwep; if (alone) You("find you must drop your weapon%s!", u.twoweap ? "s" : ""); otmp2 = u.twoweap ? uswapwep : 0; uwepgone(); if (!wep->cursed || wep->otyp != LOADSTONE) dropx(otmp); if (otmp2 != 0) { uswapwepgone(); if (!otmp2->cursed || otmp2->otyp != LOADSTONE) dropx(otmp2); } untwoweapon(); } else if (!could_twoweap(youmonst.data)) { untwoweapon(); } } } void rehumanize() { /* You can't revert back while unchanging */ if (Unchanging && (u.mh < 1)) { killer_format = NO_KILLER_PREFIX; killer = "killed while stuck in creature form"; done(DIED); } if (emits_light(youmonst.data)) del_light_source(LS_MONSTER, (genericptr_t)&youmonst); polyman("return to %s form!", urace.adj); if (u.uhp < 1) { char kbuf[256]; Sprintf(kbuf, "reverting to unhealthy %s form", urace.adj); killer_format = KILLED_BY; killer = kbuf; done(DIED); } if (!uarmg) selftouch("No longer petrify-resistant, you"); nomul(0); flags.botl = 1; vision_full_recalc = 1; (void) encumber_msg(); } int dobreathe() { struct attack *mattk; if (Strangled) { You_cant("breathe. Sorry."); return(0); } if (u.uen < 15) { You("don't have enough energy to breathe!"); return(0); } u.uen -= 15; flags.botl = 1; if (!getdir((char *)0)) return(0); mattk = attacktype_fordmg(youmonst.data, AT_BREA, AD_ANY); if (!mattk) impossible("bad breath attack?"); /* mouthwash needed... */ else buzz((int) (20 + mattk->adtyp-1), (int)mattk->damn, u.ux, u.uy, u.dx, u.dy); return(1); } int dospit() { struct obj *otmp; if (!getdir((char *)0)) return(0); otmp = mksobj(u.umonnum==PM_COBRA ? BLINDING_VENOM : ACID_VENOM, TRUE, FALSE); otmp->spe = 1; /* to indicate it's yours */ throwit(otmp, 0L, FALSE); return(1); } int doremove() { if (!Punished) { You("are not chained to anything!"); return(0); } unpunish(); return(1); } int dospinweb() { register struct trap *ttmp = t_at(u.ux,u.uy); if (Levitation || Is_airlevel(&u.uz) || Underwater || Is_waterlevel(&u.uz)) { You("must be on the ground to spin a web."); return(0); } if (u.uswallow) { You("release web fluid inside %s.", mon_nam(u.ustuck)); if (is_animal(u.ustuck->data)) { expels(u.ustuck, u.ustuck->data, TRUE); return(0); } if (is_whirly(u.ustuck->data)) { int i; for (i = 0; i < NATTK; i++) if (u.ustuck->data->mattk[i].aatyp == AT_ENGL) break; if (i == NATTK) impossible("Swallower has no engulfing attack?"); else { char sweep[30]; sweep[0] = '\0'; switch(u.ustuck->data->mattk[i].adtyp) { case AD_FIRE: Strcpy(sweep, "ignites and "); break; case AD_ELEC: Strcpy(sweep, "fries and "); break; case AD_COLD: Strcpy(sweep, "freezes, shatters and "); break; } pline_The("web %sis swept away!", sweep); } return(0); } /* default: a nasty jelly-like creature */ pline_The("web dissolves into %s.", mon_nam(u.ustuck)); return(0); } if (u.utrap) { You("cannot spin webs while stuck in a trap."); return(0); } exercise(A_DEX, TRUE); if (ttmp) switch (ttmp->ttyp) { case PIT: case SPIKED_PIT: You("spin a web, covering up the pit."); deltrap(ttmp); bury_objs(u.ux, u.uy); newsym(u.ux, u.uy); return(1); case SQKY_BOARD: pline_The("squeaky board is muffled."); deltrap(ttmp); newsym(u.ux, u.uy); return(1); case TELEP_TRAP: case LEVEL_TELEP: case MAGIC_PORTAL: Your("webbing vanishes!"); return(0); case WEB: You("make the web thicker."); return(1); case HOLE: case TRAPDOOR: You("web over the %s.", (ttmp->ttyp == TRAPDOOR) ? "trap door" : "hole"); deltrap(ttmp); newsym(u.ux, u.uy); return 1; case ROLLING_BOULDER_TRAP: You("spin a web, jamming the trigger."); deltrap(ttmp); newsym(u.ux, u.uy); return(1); case ARROW_TRAP: case DART_TRAP: case BEAR_TRAP: case ROCKTRAP: case FIRE_TRAP: case LANDMINE: case SLP_GAS_TRAP: case RUST_TRAP: case MAGIC_TRAP: case ANTI_MAGIC: case POLY_TRAP: You("have triggered a trap!"); dotrap(ttmp, 0); return(1); default: impossible("Webbing over trap type %d?", ttmp->ttyp); return(0); } else if (On_stairs(u.ux, u.uy)) { /* cop out: don't let them hide the stairs */ Your("web fails to impede access to the %s.", (levl[u.ux][u.uy].typ == STAIRS) ? "stairs" : "ladder"); return(1); } ttmp = maketrap(u.ux, u.uy, WEB); if (ttmp) { ttmp->tseen = 1; ttmp->madeby_u = 1; } newsym(u.ux, u.uy); return(1); } int dosummon() { int placeholder; if (u.uen < 10) { You("lack the energy to send forth a call for help!"); return(0); } u.uen -= 10; flags.botl = 1; You("call upon your brethren for help!"); exercise(A_WIS, TRUE); if (!were_summon(youmonst.data, TRUE, &placeholder, (char *)0)) pline("But none arrive."); return(1); } int dogaze() { register struct monst *mtmp; int looked = 0; char qbuf[QBUFSZ]; int i; uchar adtyp = 0; for (i = 0; i < NATTK; i++) { if(youmonst.data->mattk[i].aatyp == AT_GAZE) { adtyp = youmonst.data->mattk[i].adtyp; break; } } if (adtyp != AD_CONF && adtyp != AD_FIRE) { impossible("gaze attack %d?", adtyp); return 0; } if (Blind) { You_cant("see anything to gaze at."); return 0; } if (u.uen < 15) { You("lack the energy to use your special gaze!"); return(0); } u.uen -= 15; flags.botl = 1; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (canseemon(mtmp) && couldsee(mtmp->mx, mtmp->my)) { looked++; if (Invis && !perceives(mtmp->data)) pline("%s seems not to notice your gaze.", Monnam(mtmp)); else if (mtmp->minvis && !See_invisible) You_cant("see where to gaze at %s.", Monnam(mtmp)); else if (mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) { looked--; continue; } else if (flags.safe_dog && !Confusion && !Hallucination && mtmp->mtame) { You("avoid gazing at %s.", y_monnam(mtmp)); } else { if (flags.confirm && mtmp->mpeaceful && !Confusion && !Hallucination) { Sprintf(qbuf, "Really %s %s?", (adtyp == AD_CONF) ? "confuse" : "attack", mon_nam(mtmp)); if (yn(qbuf) != 'y') continue; setmangry(mtmp); } if (!mtmp->mcanmove || mtmp->mstun || mtmp->msleeping || !mtmp->mcansee || !haseyes(mtmp->data)) { looked--; continue; } /* No reflection check for consistency with when a monster * gazes at *you*--only medusa gaze gets reflected then. */ if (adtyp == AD_CONF) { if (!mtmp->mconf) Your("gaze confuses %s!", mon_nam(mtmp)); else pline("%s is getting more and more confused.", Monnam(mtmp)); mtmp->mconf = 1; } else if (adtyp == AD_FIRE) { int dmg = d(2,6); You("attack %s with a fiery gaze!", mon_nam(mtmp)); if (resists_fire(mtmp)) { pline_The("fire doesn't burn %s!", mon_nam(mtmp)); dmg = 0; } if((int) u.ulevel > rn2(20)) (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); if((int) u.ulevel > rn2(20)) (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); if((int) u.ulevel > rn2(25)) (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); if (dmg && !DEADMONSTER(mtmp)) mtmp->mhp -= dmg; if (mtmp->mhp <= 0) killed(mtmp); } /* For consistency with passive() in uhitm.c, this only * affects you if the monster is still alive. */ if (!DEADMONSTER(mtmp) && (mtmp->data==&mons[PM_FLOATING_EYE]) && !mtmp->mcan) { if (!Free_action) { You("are frozen by %s gaze!", s_suffix(mon_nam(mtmp))); nomul((u.ulevel > 6 || rn2(4)) ? -d((int)mtmp->m_lev+1, (int)mtmp->data->mattk[0].damd) : -200); return 1; } else You("stiffen momentarily under %s gaze.", s_suffix(mon_nam(mtmp))); } /* Technically this one shouldn't affect you at all because * the Medusa gaze is an active monster attack that only * works on the monster's turn, but for it to *not* have an * effect would be too weird. */ if (!DEADMONSTER(mtmp) && (mtmp->data == &mons[PM_MEDUSA]) && !mtmp->mcan) { pline( "Gazing at the awake %s is not a very good idea.", l_monnam(mtmp)); /* as if gazing at a sleeping anything is fruitful... */ You("turn to stone..."); killer_format = KILLED_BY; killer = "deliberately meeting Medusa's gaze"; done(STONING); } } } } if (!looked) You("gaze at no place in particular."); return 1; } int dohide() { boolean ismimic = youmonst.data->mlet == S_MIMIC; if (u.uundetected || (ismimic && youmonst.m_ap_type != M_AP_NOTHING)) { You("are already hiding."); return(0); } if (ismimic) { /* should bring up a dialog "what would you like to imitate?" */ youmonst.m_ap_type = M_AP_OBJECT; youmonst.mappearance = STRANGE_OBJECT; } else u.uundetected = 1; newsym(u.ux,u.uy); return(1); } int domindblast() { struct monst *mtmp, *nmon; if (u.uen < 10) { You("concentrate but lack the energy to maintain doing so."); return(0); } u.uen -= 10; flags.botl = 1; You("concentrate."); pline("A wave of psychic energy pours out."); for(mtmp=fmon; mtmp; mtmp = nmon) { int u_sen; nmon = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (distu(mtmp->mx, mtmp->my) > BOLT_LIM * BOLT_LIM) continue; if(mtmp->mpeaceful) continue; u_sen = telepathic(mtmp->data) && !mtmp->mcansee; if (u_sen || (telepathic(mtmp->data) && rn2(2)) || !rn2(10)) { You("lock in on %s %s.", s_suffix(mon_nam(mtmp)), u_sen ? "telepathy" : telepathic(mtmp->data) ? "latent telepathy" : "mind"); mtmp->mhp -= rnd(15); if (mtmp->mhp <= 0) killed(mtmp); } } return 1; } STATIC_OVL void uunstick() { pline("%s is no longer in your clutches.", Monnam(u.ustuck)); u.ustuck = 0; } void skinback(silently) boolean silently; { if (uskin) { if (!silently) Your("skin returns to its original form."); uarm = uskin; uskin = (struct obj *)0; /* undo save/restore hack */ uarm->owornmask &= ~I_SPECIAL; } } #endif /* OVLB */ #ifdef OVL1 const char * mbodypart(mon, part) struct monst *mon; int part; { static NEARDATA const char *humanoid_parts[] = { "arm", "eye", "face", "finger", "fingertip", "foot", "hand", "handed", "head", "leg", "light headed", "neck", "spine", "toe", "hair", "blood", "lung", "nose", "stomach"}, *jelly_parts[] = { "pseudopod", "dark spot", "front", "pseudopod extension", "pseudopod extremity", "pseudopod root", "grasp", "grasped", "cerebral area", "lower pseudopod", "viscous", "middle", "surface", "pseudopod extremity", "ripples", "juices", "surface", "sensor", "stomach" }, *animal_parts[] = { "forelimb", "eye", "face", "foreclaw", "claw tip", "rear claw", "foreclaw", "clawed", "head", "rear limb", "light headed", "neck", "spine", "rear claw tip", "fur", "blood", "lung", "nose", "stomach" }, *bird_parts[] = { "wing", "eye", "face", "wing", "wing tip", "foot", "wing", "winged", "head", "leg", "light headed", "neck", "spine", "toe", "feathers", "blood", "lung", "bill", "stomach" }, *horse_parts[] = { "foreleg", "eye", "face", "forehoof", "hoof tip", "rear hoof", "foreclaw", "hooved", "head", "rear leg", "light headed", "neck", "backbone", "rear hoof tip", "mane", "blood", "lung", "nose", "stomach"}, *sphere_parts[] = { "appendage", "optic nerve", "body", "tentacle", "tentacle tip", "lower appendage", "tentacle", "tentacled", "body", "lower tentacle", "rotational", "equator", "body", "lower tentacle tip", "cilia", "life force", "retina", "olfactory nerve", "interior" }, *fungus_parts[] = { "mycelium", "visual area", "front", "hypha", "hypha", "root", "strand", "stranded", "cap area", "rhizome", "sporulated", "stalk", "root", "rhizome tip", "spores", "juices", "gill", "gill", "interior" }, *vortex_parts[] = { "region", "eye", "front", "minor current", "minor current", "lower current", "swirl", "swirled", "central core", "lower current", "addled", "center", "currents", "edge", "currents", "life force", "center", "leading edge", "interior" }, *snake_parts[] = { "vestigial limb", "eye", "face", "large scale", "large scale tip", "rear region", "scale gap", "scale gapped", "head", "rear region", "light headed", "neck", "length", "rear scale", "scales", "blood", "lung", "forked tongue", "stomach" }, *fish_parts[] = { "fin", "eye", "premaxillary", "pelvic axillary", "pelvic fin", "anal fin", "pectoral fin", "finned", "head", "peduncle", "played out", "gills", "dorsal fin", "caudal fin", "scales", "blood", "gill", "nostril", "stomach" }; /* claw attacks are overloaded in mons[]; most humanoids with such attacks should still reference hands rather than claws */ static const char not_claws[] = { S_HUMAN, S_MUMMY, S_ZOMBIE, S_ANGEL, S_NYMPH, S_LEPRECHAUN, S_QUANTMECH, S_VAMPIRE, S_ORC, S_GIANT, /* quest nemeses */ '\0' /* string terminator; assert( S_xxx != 0 ); */ }; struct permonst *mptr = mon->data; if (part == HAND || part == HANDED) { /* some special cases */ if (mptr->mlet == S_DOG || mptr->mlet == S_FELINE || mptr->mlet == S_YETI) return part == HAND ? "paw" : "pawed"; if (humanoid(mptr) && attacktype(mptr, AT_CLAW) && !index(not_claws, mptr->mlet) && mptr != &mons[PM_STONE_GOLEM] && mptr != &mons[PM_INCUBUS] && mptr != &mons[PM_SUCCUBUS]) return part == HAND ? "claw" : "clawed"; } if ((mptr == &mons[PM_MUMAK] || mptr == &mons[PM_MASTODON]) && part == NOSE) return "trunk"; if (mptr == &mons[PM_SHARK] && part == HAIR) return "skin"; /* sharks don't have scales */ if (mptr == &mons[PM_JELLYFISH] && (part == ARM || part == FINGER || part == HAND || part == FOOT || part == TOE)) return "tentacle"; if (mptr == &mons[PM_FLOATING_EYE] && part == EYE) return "cornea"; if (humanoid(mptr) && (part == ARM || part == FINGER || part == FINGERTIP || part == HAND || part == HANDED)) return humanoid_parts[part]; if (mptr == &mons[PM_RAVEN]) return bird_parts[part]; if (mptr->mlet == S_CENTAUR || mptr->mlet == S_UNICORN || (mptr == &mons[PM_ROTHE] && part != HAIR)) return horse_parts[part]; if (mptr->mlet == S_LIGHT) { if (part == HANDED) return "rayed"; else if (part == ARM || part == FINGER || part == FINGERTIP || part == HAND) return "ray"; else return "beam"; } if (mptr->mlet == S_EEL && mptr != &mons[PM_JELLYFISH]) return fish_parts[part]; if (slithy(mptr) || (mptr->mlet == S_DRAGON && part == HAIR)) return snake_parts[part]; if (mptr->mlet == S_EYE) return sphere_parts[part]; if (mptr->mlet == S_JELLY || mptr->mlet == S_PUDDING || mptr->mlet == S_BLOB || mptr == &mons[PM_JELLYFISH]) return jelly_parts[part]; if (mptr->mlet == S_VORTEX || mptr->mlet == S_ELEMENTAL) return vortex_parts[part]; if (mptr->mlet == S_FUNGUS) return fungus_parts[part]; if (humanoid(mptr)) return humanoid_parts[part]; return animal_parts[part]; } const char * body_part(part) int part; { return mbodypart(&youmonst, part); } #endif /* OVL1 */ #ifdef OVL0 int poly_gender() { /* Returns gender of polymorphed player; 0/1=same meaning as flags.female, * 2=none. */ if (is_neuter(youmonst.data) || !humanoid(youmonst.data)) return 2; return flags.female; } #endif /* OVL0 */ #ifdef OVLB void ugolemeffects(damtype, dam) int damtype, dam; { int heal = 0; /* We won't bother with "slow"/"haste" since players do not * have a monster-specific slow/haste so there is no way to * restore the old velocity once they are back to human. */ if (u.umonnum != PM_FLESH_GOLEM && u.umonnum != PM_IRON_GOLEM) return; switch (damtype) { case AD_ELEC: if (u.umonnum == PM_FLESH_GOLEM) heal = dam / 6; /* Approx 1 per die */ break; case AD_FIRE: if (u.umonnum == PM_IRON_GOLEM) heal = dam; break; } if (heal && (u.mh < u.mhmax)) { u.mh += heal; if (u.mh > u.mhmax) u.mh = u.mhmax; flags.botl = 1; pline("Strangely, you feel better than before."); exercise(A_STR, TRUE); } } STATIC_OVL int armor_to_dragon(atyp) int atyp; { switch(atyp) { case GRAY_DRAGON_SCALE_MAIL: case GRAY_DRAGON_SCALES: return PM_GRAY_DRAGON; case SILVER_DRAGON_SCALE_MAIL: case SILVER_DRAGON_SCALES: return PM_SILVER_DRAGON; #if 0 /* DEFERRED */ case SHIMMERING_DRAGON_SCALE_MAIL: case SHIMMERING_DRAGON_SCALES: return PM_SHIMMERING_DRAGON; #endif case RED_DRAGON_SCALE_MAIL: case RED_DRAGON_SCALES: return PM_RED_DRAGON; case ORANGE_DRAGON_SCALE_MAIL: case ORANGE_DRAGON_SCALES: return PM_ORANGE_DRAGON; case WHITE_DRAGON_SCALE_MAIL: case WHITE_DRAGON_SCALES: return PM_WHITE_DRAGON; case BLACK_DRAGON_SCALE_MAIL: case BLACK_DRAGON_SCALES: return PM_BLACK_DRAGON; case BLUE_DRAGON_SCALE_MAIL: case BLUE_DRAGON_SCALES: return PM_BLUE_DRAGON; case GREEN_DRAGON_SCALE_MAIL: case GREEN_DRAGON_SCALES: return PM_GREEN_DRAGON; case YELLOW_DRAGON_SCALE_MAIL: case YELLOW_DRAGON_SCALES: return PM_YELLOW_DRAGON; default: return -1; } } #endif /* OVLB */ /*polyself.c*/ nethack-3.4.3/src/potion.c0100644000000000000000000014647507764735041014136 0ustar rootroot/* SCCS Id: @(#)potion.c 3.4 2002/10/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef OVLB boolean notonhead = FALSE; static NEARDATA int nothing, unkn; static NEARDATA const char beverages[] = { POTION_CLASS, 0 }; STATIC_DCL long FDECL(itimeout, (long)); STATIC_DCL long FDECL(itimeout_incr, (long,int)); STATIC_DCL void NDECL(ghost_from_bottle); STATIC_DCL short FDECL(mixtype, (struct obj *,struct obj *)); /* force `val' to be within valid range for intrinsic timeout value */ STATIC_OVL long itimeout(val) long val; { if (val >= TIMEOUT) val = TIMEOUT; else if (val < 1) val = 0; return val; } /* increment `old' by `incr' and force result to be valid intrinsic timeout */ STATIC_OVL long itimeout_incr(old, incr) long old; int incr; { return itimeout((old & TIMEOUT) + (long)incr); } /* set the timeout field of intrinsic `which' */ void set_itimeout(which, val) long *which, val; { *which &= ~TIMEOUT; *which |= itimeout(val); } /* increment the timeout field of intrinsic `which' */ void incr_itimeout(which, incr) long *which; int incr; { set_itimeout(which, itimeout_incr(*which, incr)); } void make_confused(xtime,talk) long xtime; boolean talk; { long old = HConfusion; if (!xtime && old) { if (talk) You_feel("less %s now.", Hallucination ? "trippy" : "confused"); } if ((xtime && !old) || (!xtime && old)) flags.botl = TRUE; set_itimeout(&HConfusion, xtime); } void make_stunned(xtime,talk) long xtime; boolean talk; { long old = HStun; if (!xtime && old) { if (talk) You_feel("%s now.", Hallucination ? "less wobbly" : "a bit steadier"); } if (xtime && !old) { if (talk) { #ifdef STEED if (u.usteed) You("wobble in the saddle."); else #endif You("%s...", stagger(youmonst.data, "stagger")); } } if ((!xtime && old) || (xtime && !old)) flags.botl = TRUE; set_itimeout(&HStun, xtime); } void make_sick(xtime, cause, talk, type) long xtime; const char *cause; /* sickness cause */ boolean talk; int type; { long old = Sick; if (xtime > 0L) { if (Sick_resistance) return; if (!old) { /* newly sick */ You_feel("deathly sick."); } else { /* already sick */ if (talk) You_feel("%s worse.", xtime <= Sick/2L ? "much" : "even"); } set_itimeout(&Sick, xtime); u.usick_type |= type; flags.botl = TRUE; } else if (old && (type & u.usick_type)) { /* was sick, now not */ u.usick_type &= ~type; if (u.usick_type) { /* only partly cured */ if (talk) You_feel("somewhat better."); set_itimeout(&Sick, Sick * 2); /* approximation */ } else { if (talk) pline("What a relief!"); Sick = 0L; /* set_itimeout(&Sick, 0L) */ } flags.botl = TRUE; } if (Sick) { exercise(A_CON, FALSE); if (cause) { (void) strncpy(u.usick_cause, cause, sizeof(u.usick_cause)); u.usick_cause[sizeof(u.usick_cause)-1] = 0; } else u.usick_cause[0] = 0; } else u.usick_cause[0] = 0; } void make_vomiting(xtime, talk) long xtime; boolean talk; { long old = Vomiting; if(!xtime && old) if(talk) You_feel("much less nauseated now."); set_itimeout(&Vomiting, xtime); } static const char vismsg[] = "vision seems to %s for a moment but is %s now."; static const char eyemsg[] = "%s momentarily %s."; void make_blinded(xtime, talk) long xtime; boolean talk; { long old = Blinded; boolean u_could_see, can_see_now; int eyecnt; char buf[BUFSZ]; /* we need to probe ahead in case the Eyes of the Overworld are or will be overriding blindness */ u_could_see = !Blind; Blinded = xtime ? 1L : 0L; can_see_now = !Blind; Blinded = old; /* restore */ if (u.usleep) talk = FALSE; if (can_see_now && !u_could_see) { /* regaining sight */ if (talk) { if (Hallucination) pline("Far out! Everything is all cosmic again!"); else You("can see again."); } } else if (old && !xtime) { /* clearing temporary blindness without toggling blindness */ if (talk) { if (!haseyes(youmonst.data)) { strange_feeling((struct obj *)0, (char *)0); } else if (Blindfolded) { Strcpy(buf, body_part(EYE)); eyecnt = eyecount(youmonst.data); Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf), (eyecnt == 1) ? "itches" : "itch"); } else { /* Eyes of the Overworld */ Your(vismsg, "brighten", Hallucination ? "sadder" : "normal"); } } } if (u_could_see && !can_see_now) { /* losing sight */ if (talk) { if (Hallucination) pline("Oh, bummer! Everything is dark! Help!"); else pline("A cloud of darkness falls upon you."); } /* Before the hero goes blind, set the ball&chain variables. */ if (Punished) set_bc(0); } else if (!old && xtime) { /* setting temporary blindness without toggling blindness */ if (talk) { if (!haseyes(youmonst.data)) { strange_feeling((struct obj *)0, (char *)0); } else if (Blindfolded) { Strcpy(buf, body_part(EYE)); eyecnt = eyecount(youmonst.data); Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf), (eyecnt == 1) ? "twitches" : "twitch"); } else { /* Eyes of the Overworld */ Your(vismsg, "dim", Hallucination ? "happier" : "normal"); } } } set_itimeout(&Blinded, xtime); if (u_could_see ^ can_see_now) { /* one or the other but not both */ flags.botl = 1; vision_full_recalc = 1; /* blindness just got toggled */ if (Blind_telepat || Infravision) see_monsters(); } } boolean make_hallucinated(xtime, talk, mask) long xtime; /* nonzero if this is an attempt to turn on hallucination */ boolean talk; long mask; /* nonzero if resistance status should change by mask */ { long old = HHallucination; boolean changed = 0; const char *message, *verb; message = (!xtime) ? "Everything %s SO boring now." : "Oh wow! Everything %s so cosmic!"; verb = (!Blind) ? "looks" : "feels"; if (mask) { if (HHallucination) changed = TRUE; if (!xtime) EHalluc_resistance |= mask; else EHalluc_resistance &= ~mask; } else { if (!EHalluc_resistance && (!!HHallucination != !!xtime)) changed = TRUE; set_itimeout(&HHallucination, xtime); /* clearing temporary hallucination without toggling vision */ if (!changed && !HHallucination && old && talk) { if (!haseyes(youmonst.data)) { strange_feeling((struct obj *)0, (char *)0); } else if (Blind) { char buf[BUFSZ]; int eyecnt = eyecount(youmonst.data); Strcpy(buf, body_part(EYE)); Your(eyemsg, (eyecnt == 1) ? buf : makeplural(buf), (eyecnt == 1) ? "itches" : "itch"); } else { /* Grayswandir */ Your(vismsg, "flatten", "normal"); } } } if (changed) { if (u.uswallow) { swallowed(0); /* redraw swallow display */ } else { /* The see_* routines should be called *before* the pline. */ see_monsters(); see_objects(); see_traps(); } /* for perm_inv and anything similar (eg. Qt windowport's equipped items display) */ update_inventory(); flags.botl = 1; if (talk) pline(message, verb); } return changed; } STATIC_OVL void ghost_from_bottle() { struct monst *mtmp = makemon(&mons[PM_GHOST], u.ux, u.uy, NO_MM_FLAGS); if (!mtmp) { pline("This bottle turns out to be empty."); return; } if (Blind) { pline("As you open the bottle, %s emerges.", something); return; } pline("As you open the bottle, an enormous %s emerges!", Hallucination ? rndmonnam() : (const char *)"ghost"); if(flags.verbose) You("are frightened to death, and unable to move."); nomul(-3); nomovemsg = "You regain your composure."; } /* "Quaffing is like drinking, except you spill more." -- Terry Pratchett */ int dodrink() { register struct obj *otmp; const char *potion_descr; if (Strangled) { pline("If you can't breathe air, how can you drink liquid?"); return 0; } /* Is there a fountain to drink from here? */ if (IS_FOUNTAIN(levl[u.ux][u.uy].typ) && !Levitation) { if(yn("Drink from the fountain?") == 'y') { drinkfountain(); return 1; } } #ifdef SINKS /* Or a kitchen sink? */ if (IS_SINK(levl[u.ux][u.uy].typ)) { if (yn("Drink from the sink?") == 'y') { drinksink(); return 1; } } #endif /* Or are you surrounded by water? */ if (Underwater) { if (yn("Drink the water around you?") == 'y') { pline("Do you know what lives in this water!"); return 1; } } otmp = getobj(beverages, "drink"); if(!otmp) return(0); otmp->in_use = TRUE; /* you've opened the stopper */ #define POTION_OCCUPANT_CHANCE(n) (13 + 2*(n)) /* also in muse.c */ potion_descr = OBJ_DESCR(objects[otmp->otyp]); if (potion_descr) { if (!strcmp(potion_descr, "milky") && flags.ghost_count < MAXMONNO && !rn2(POTION_OCCUPANT_CHANCE(flags.ghost_count))) { ghost_from_bottle(); useup(otmp); return(1); } else if (!strcmp(potion_descr, "smoky") && flags.djinni_count < MAXMONNO && !rn2(POTION_OCCUPANT_CHANCE(flags.djinni_count))) { djinni_from_bottle(otmp); useup(otmp); return(1); } } return dopotion(otmp); } int dopotion(otmp) register struct obj *otmp; { int retval; otmp->in_use = TRUE; nothing = unkn = 0; if((retval = peffects(otmp)) >= 0) return(retval); if(nothing) { unkn++; You("have a %s feeling for a moment, then it passes.", Hallucination ? "normal" : "peculiar"); } if(otmp->dknown && !objects[otmp->otyp].oc_name_known) { if(!unkn) { makeknown(otmp->otyp); more_experienced(0,10); } else if(!objects[otmp->otyp].oc_uname) docall(otmp); } useup(otmp); return(1); } int peffects(otmp) register struct obj *otmp; { register int i, ii, lim; switch(otmp->otyp){ case POT_RESTORE_ABILITY: case SPE_RESTORE_ABILITY: unkn++; if(otmp->cursed) { pline("Ulch! This makes you feel mediocre!"); break; } else { pline("Wow! This makes you feel %s!", (otmp->blessed) ? (unfixable_trouble_count(FALSE) ? "better" : "great") : "good"); i = rn2(A_MAX); /* start at a random point */ for (ii = 0; ii < A_MAX; ii++) { lim = AMAX(i); if (i == A_STR && u.uhs >= 3) --lim; /* WEAK */ if (ABASE(i) < lim) { ABASE(i) = lim; flags.botl = 1; /* only first found if not blessed */ if (!otmp->blessed) break; } if(++i >= A_MAX) i = 0; } } break; case POT_HALLUCINATION: if (Hallucination || Halluc_resistance) nothing++; (void) make_hallucinated(itimeout_incr(HHallucination, rn1(200, 600 - 300 * bcsign(otmp))), TRUE, 0L); break; case POT_WATER: if(!otmp->blessed && !otmp->cursed) { pline("This tastes like water."); u.uhunger += rnd(10); newuhs(FALSE); break; } unkn++; if(is_undead(youmonst.data) || is_demon(youmonst.data) || u.ualign.type == A_CHAOTIC) { if(otmp->blessed) { pline("This burns like acid!"); exercise(A_CON, FALSE); if (u.ulycn >= LOW_PM) { Your("affinity to %s disappears!", makeplural(mons[u.ulycn].mname)); if (youmonst.data == &mons[u.ulycn]) you_unwere(FALSE); u.ulycn = NON_PM; /* cure lycanthropy */ } losehp(d(2,6), "potion of holy water", KILLED_BY_AN); } else if(otmp->cursed) { You_feel("quite proud of yourself."); healup(d(2,6),0,0,0); if (u.ulycn >= LOW_PM && !Upolyd) you_were(); exercise(A_CON, TRUE); } } else { if(otmp->blessed) { You_feel("full of awe."); make_sick(0L, (char *) 0, TRUE, SICK_ALL); exercise(A_WIS, TRUE); exercise(A_CON, TRUE); if (u.ulycn >= LOW_PM) you_unwere(TRUE); /* "Purified" */ /* make_confused(0L,TRUE); */ } else { if(u.ualign.type == A_LAWFUL) { pline("This burns like acid!"); losehp(d(2,6), "potion of unholy water", KILLED_BY_AN); } else You_feel("full of dread."); if (u.ulycn >= LOW_PM && !Upolyd) you_were(); exercise(A_CON, FALSE); } } break; case POT_BOOZE: unkn++; pline("Ooph! This tastes like %s%s!", otmp->odiluted ? "watered down " : "", Hallucination ? "dandelion wine" : "liquid fire"); if (!otmp->blessed) make_confused(itimeout_incr(HConfusion, d(3,8)), FALSE); /* the whiskey makes us feel better */ if (!otmp->odiluted) healup(1, 0, FALSE, FALSE); u.uhunger += 10 * (2 + bcsign(otmp)); newuhs(FALSE); exercise(A_WIS, FALSE); if(otmp->cursed) { You("pass out."); multi = -rnd(15); nomovemsg = "You awake with a headache."; } break; case POT_ENLIGHTENMENT: if(otmp->cursed) { unkn++; You("have an uneasy feeling..."); exercise(A_WIS, FALSE); } else { if (otmp->blessed) { (void) adjattrib(A_INT, 1, FALSE); (void) adjattrib(A_WIS, 1, FALSE); } You_feel("self-knowledgeable..."); display_nhwindow(WIN_MESSAGE, FALSE); enlightenment(0); pline_The("feeling subsides."); exercise(A_WIS, TRUE); } break; case SPE_INVISIBILITY: /* spell cannot penetrate mummy wrapping */ if (BInvis && uarmc->otyp == MUMMY_WRAPPING) { You_feel("rather itchy under your %s.", xname(uarmc)); break; } /* FALLTHRU */ case POT_INVISIBILITY: if (Invis || Blind || BInvis) { nothing++; } else { self_invis_message(); } if (otmp->blessed) HInvis |= FROMOUTSIDE; else incr_itimeout(&HInvis, rn1(15,31)); newsym(u.ux,u.uy); /* update position */ if(otmp->cursed) { pline("For some reason, you feel your presence is known."); aggravate(); } break; case POT_SEE_INVISIBLE: /* tastes like fruit juice in Rogue */ case POT_FRUIT_JUICE: { int msg = Invisible && !Blind; unkn++; if (otmp->cursed) pline("Yecch! This tastes %s.", Hallucination ? "overripe" : "rotten"); else pline(Hallucination ? "This tastes like 10%% real %s%s all-natural beverage." : "This tastes like %s%s.", otmp->odiluted ? "reconstituted " : "", fruitname(TRUE)); if (otmp->otyp == POT_FRUIT_JUICE) { u.uhunger += (otmp->odiluted ? 5 : 10) * (2 + bcsign(otmp)); newuhs(FALSE); break; } if (!otmp->cursed) { /* Tell them they can see again immediately, which * will help them identify the potion... */ make_blinded(0L,TRUE); } if (otmp->blessed) HSee_invisible |= FROMOUTSIDE; else incr_itimeout(&HSee_invisible, rn1(100,750)); set_mimic_blocking(); /* do special mimic handling */ see_monsters(); /* see invisible monsters */ newsym(u.ux,u.uy); /* see yourself! */ if (msg && !Blind) { /* Blind possible if polymorphed */ You("can see through yourself, but you are visible!"); unkn--; } break; } case POT_PARALYSIS: if (Free_action) You("stiffen momentarily."); else { if (Levitation || Is_airlevel(&u.uz)||Is_waterlevel(&u.uz)) You("are motionlessly suspended."); #ifdef STEED else if (u.usteed) You("are frozen in place!"); #endif else Your("%s are frozen to the %s!", makeplural(body_part(FOOT)), surface(u.ux, u.uy)); nomul(-(rn1(10, 25 - 12*bcsign(otmp)))); nomovemsg = You_can_move_again; exercise(A_DEX, FALSE); } break; case POT_SLEEPING: if(Sleep_resistance || Free_action) You("yawn."); else { You("suddenly fall asleep!"); fall_asleep(-rn1(10, 25 - 12*bcsign(otmp)), TRUE); } break; case POT_MONSTER_DETECTION: case SPE_DETECT_MONSTERS: if (otmp->blessed) { int x, y; if (Detect_monsters) nothing++; unkn++; /* after a while, repeated uses become less effective */ if (HDetect_monsters >= 300L) i = 1; else i = rn1(40,21); incr_itimeout(&HDetect_monsters, i); for (x = 1; x < COLNO; x++) { for (y = 0; y < ROWNO; y++) { if (levl[x][y].glyph == GLYPH_INVISIBLE) { unmap_object(x, y); newsym(x,y); } if (MON_AT(x,y)) unkn = 0; } } see_monsters(); if (unkn) You_feel("lonely."); break; } if (monster_detect(otmp, 0)) return(1); /* nothing detected */ exercise(A_WIS, TRUE); break; case POT_OBJECT_DETECTION: case SPE_DETECT_TREASURE: if (object_detect(otmp, 0)) return(1); /* nothing detected */ exercise(A_WIS, TRUE); break; case POT_SICKNESS: pline("Yecch! This stuff tastes like poison."); if (otmp->blessed) { pline("(But in fact it was mildly stale %s.)", fruitname(TRUE)); if (!Role_if(PM_HEALER)) { /* NB: blessed otmp->fromsink is not possible */ losehp(1, "mildly contaminated potion", KILLED_BY_AN); } } else { if(Poison_resistance) pline( "(But in fact it was biologically contaminated %s.)", fruitname(TRUE)); if (Role_if(PM_HEALER)) pline("Fortunately, you have been immunized."); else { int typ = rn2(A_MAX); if (!Fixed_abil) { poisontell(typ); (void) adjattrib(typ, Poison_resistance ? -1 : -rn1(4,3), TRUE); } if(!Poison_resistance) { if (otmp->fromsink) losehp(rnd(10)+5*!!(otmp->cursed), "contaminated tap water", KILLED_BY); else losehp(rnd(10)+5*!!(otmp->cursed), "contaminated potion", KILLED_BY_AN); } exercise(A_CON, FALSE); } } if(Hallucination) { You("are shocked back to your senses!"); (void) make_hallucinated(0L,FALSE,0L); } break; case POT_CONFUSION: if(!Confusion) if (Hallucination) { pline("What a trippy feeling!"); unkn++; } else pline("Huh, What? Where am I?"); else nothing++; make_confused(itimeout_incr(HConfusion, rn1(7, 16 - 8 * bcsign(otmp))), FALSE); break; case POT_GAIN_ABILITY: if(otmp->cursed) { pline("Ulch! That potion tasted foul!"); unkn++; } else if (Fixed_abil) { nothing++; } else { /* If blessed, increase all; if not, try up to */ int itmp; /* 6 times to find one which can be increased. */ i = -1; /* increment to 0 */ for (ii = A_MAX; ii > 0; ii--) { i = (otmp->blessed ? i + 1 : rn2(A_MAX)); /* only give "your X is already as high as it can get" message on last attempt (except blessed potions) */ itmp = (otmp->blessed || ii == 1) ? 0 : -1; if (adjattrib(i, 1, itmp) && !otmp->blessed) break; } } break; case POT_SPEED: if(Wounded_legs && !otmp->cursed #ifdef STEED && !u.usteed /* heal_legs() would heal steeds legs */ #endif ) { heal_legs(); unkn++; break; } /* and fall through */ case SPE_HASTE_SELF: if(!Very_fast) /* wwf@doe.carleton.ca */ You("are suddenly moving %sfaster.", Fast ? "" : "much "); else { Your("%s get new energy.", makeplural(body_part(LEG))); unkn++; } exercise(A_DEX, TRUE); incr_itimeout(&HFast, rn1(10, 100 + 60 * bcsign(otmp))); break; case POT_BLINDNESS: if(Blind) nothing++; make_blinded(itimeout_incr(Blinded, rn1(200, 250 - 125 * bcsign(otmp))), (boolean)!Blind); break; case POT_GAIN_LEVEL: if (otmp->cursed) { unkn++; /* they went up a level */ if((ledger_no(&u.uz) == 1 && u.uhave.amulet) || Can_rise_up(u.ux, u.uy, &u.uz)) { const char *riseup ="rise up, through the %s!"; if(ledger_no(&u.uz) == 1) { You(riseup, ceiling(u.ux,u.uy)); goto_level(&earth_level, FALSE, FALSE, FALSE); } else { register int newlev = depth(&u.uz)-1; d_level newlevel; get_level(&newlevel, newlev); if(on_level(&newlevel, &u.uz)) { pline("It tasted bad."); break; } else You(riseup, ceiling(u.ux,u.uy)); goto_level(&newlevel, FALSE, FALSE, FALSE); } } else You("have an uneasy feeling."); break; } pluslvl(FALSE); if (otmp->blessed) /* blessed potions place you at a random spot in the * middle of the new level instead of the low point */ u.uexp = rndexp(TRUE); break; case POT_HEALING: You_feel("better."); healup(d(6 + 2 * bcsign(otmp), 4), !otmp->cursed ? 1 : 0, !!otmp->blessed, !otmp->cursed); exercise(A_CON, TRUE); break; case POT_EXTRA_HEALING: You_feel("much better."); healup(d(6 + 2 * bcsign(otmp), 8), otmp->blessed ? 5 : !otmp->cursed ? 2 : 0, !otmp->cursed, TRUE); (void) make_hallucinated(0L,TRUE,0L); exercise(A_CON, TRUE); exercise(A_STR, TRUE); break; case POT_FULL_HEALING: You_feel("completely healed."); healup(400, 4+4*bcsign(otmp), !otmp->cursed, TRUE); /* Restore one lost level if blessed */ if (otmp->blessed && u.ulevel < u.ulevelmax) { /* when multiple levels have been lost, drinking multiple potions will only get half of them back */ u.ulevelmax -= 1; pluslvl(FALSE); } (void) make_hallucinated(0L,TRUE,0L); exercise(A_STR, TRUE); exercise(A_CON, TRUE); break; case POT_LEVITATION: case SPE_LEVITATION: if (otmp->cursed) HLevitation &= ~I_SPECIAL; if(!Levitation) { /* kludge to ensure proper operation of float_up() */ HLevitation = 1; float_up(); /* reverse kludge */ HLevitation = 0; if (otmp->cursed && !Is_waterlevel(&u.uz)) { if((u.ux != xupstair || u.uy != yupstair) && (u.ux != sstairs.sx || u.uy != sstairs.sy || !sstairs.up) && (!xupladder || u.ux != xupladder || u.uy != yupladder) ) { You("hit your %s on the %s.", body_part(HEAD), ceiling(u.ux,u.uy)); losehp(uarmh ? 1 : rnd(10), "colliding with the ceiling", KILLED_BY); } else (void) doup(); } } else nothing++; if (otmp->blessed) { incr_itimeout(&HLevitation, rn1(50,250)); HLevitation |= I_SPECIAL; } else incr_itimeout(&HLevitation, rn1(140,10)); spoteffects(FALSE); /* for sinks */ break; case POT_GAIN_ENERGY: /* M. Stephenson */ { register int num; if(otmp->cursed) You_feel("lackluster."); else pline("Magical energies course through your body."); num = rnd(5) + 5 * otmp->blessed + 1; u.uenmax += (otmp->cursed) ? -num : num; u.uen += (otmp->cursed) ? -num : num; if(u.uenmax <= 0) u.uenmax = 0; if(u.uen <= 0) u.uen = 0; flags.botl = 1; exercise(A_WIS, TRUE); } break; case POT_OIL: /* P. Winner */ { boolean good_for_you = FALSE; if (otmp->lamplit) { if (likes_fire(youmonst.data)) { pline("Ahh, a refreshing drink."); good_for_you = TRUE; } else { You("burn your %s.", body_part(FACE)); losehp(d(Fire_resistance ? 1 : 3, 4), "burning potion of oil", KILLED_BY_AN); } } else if(otmp->cursed) pline("This tastes like castor oil."); else pline("That was smooth!"); exercise(A_WIS, good_for_you); } break; case POT_ACID: if (Acid_resistance) /* Not necessarily a creature who _likes_ acid */ pline("This tastes %s.", Hallucination ? "tangy" : "sour"); else { pline("This burns%s!", otmp->blessed ? " a little" : otmp->cursed ? " a lot" : " like acid"); losehp(d(otmp->cursed ? 2 : 1, otmp->blessed ? 4 : 8), "potion of acid", KILLED_BY_AN); exercise(A_CON, FALSE); } if (Stoned) fix_petrification(); unkn++; /* holy/unholy water can burn like acid too */ break; case POT_POLYMORPH: You_feel("a little %s.", Hallucination ? "normal" : "strange"); if (!Unchanging) polyself(FALSE); break; default: impossible("What a funny potion! (%u)", otmp->otyp); return(0); } return(-1); } void healup(nhp, nxtra, curesick, cureblind) int nhp, nxtra; register boolean curesick, cureblind; { if (nhp) { if (Upolyd) { u.mh += nhp; if (u.mh > u.mhmax) u.mh = (u.mhmax += nxtra); } else { u.uhp += nhp; if(u.uhp > u.uhpmax) u.uhp = (u.uhpmax += nxtra); } } if(cureblind) make_blinded(0L,TRUE); if(curesick) make_sick(0L, (char *) 0, TRUE, SICK_ALL); flags.botl = 1; return; } void strange_feeling(obj,txt) register struct obj *obj; register const char *txt; { if (flags.beginner || !txt) You("have a %s feeling for a moment, then it passes.", Hallucination ? "normal" : "strange"); else pline(txt); if(!obj) /* e.g., crystal ball finds no traps */ return; if(obj->dknown && !objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) docall(obj); useup(obj); } const char *bottlenames[] = { "bottle", "phial", "flagon", "carafe", "flask", "jar", "vial" }; const char * bottlename() { return bottlenames[rn2(SIZE(bottlenames))]; } void potionhit(mon, obj, your_fault) register struct monst *mon; register struct obj *obj; boolean your_fault; { register const char *botlnam = bottlename(); boolean isyou = (mon == &youmonst); int distance; if(isyou) { distance = 0; pline_The("%s crashes on your %s and breaks into shards.", botlnam, body_part(HEAD)); losehp(rnd(2), "thrown potion", KILLED_BY_AN); } else { distance = distu(mon->mx,mon->my); if (!cansee(mon->mx,mon->my)) pline("Crash!"); else { char *mnam = mon_nam(mon); char buf[BUFSZ]; if(has_head(mon->data)) { Sprintf(buf, "%s %s", s_suffix(mnam), (notonhead ? "body" : "head")); } else { Strcpy(buf, mnam); } pline_The("%s crashes on %s and breaks into shards.", botlnam, buf); } if(rn2(5) && mon->mhp > 1) mon->mhp--; } /* oil doesn't instantly evaporate */ if (obj->otyp != POT_OIL && cansee(mon->mx,mon->my)) pline("%s.", Tobjnam(obj, "evaporate")); if (isyou) { switch (obj->otyp) { case POT_OIL: if (obj->lamplit) splatter_burning_oil(u.ux, u.uy); break; case POT_POLYMORPH: You_feel("a little %s.", Hallucination ? "normal" : "strange"); if (!Unchanging && !Antimagic) polyself(FALSE); break; case POT_ACID: if (!Acid_resistance) { pline("This burns%s!", obj->blessed ? " a little" : obj->cursed ? " a lot" : ""); losehp(d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8), "potion of acid", KILLED_BY_AN); } break; } } else { boolean angermon = TRUE; if (!your_fault) angermon = FALSE; switch (obj->otyp) { case POT_HEALING: case POT_EXTRA_HEALING: case POT_FULL_HEALING: if (mon->data == &mons[PM_PESTILENCE]) goto do_illness; /*FALLTHRU*/ case POT_RESTORE_ABILITY: case POT_GAIN_ABILITY: do_healing: angermon = FALSE; if(mon->mhp < mon->mhpmax) { mon->mhp = mon->mhpmax; if (canseemon(mon)) pline("%s looks sound and hale again.", Monnam(mon)); } break; case POT_SICKNESS: if (mon->data == &mons[PM_PESTILENCE]) goto do_healing; if (dmgtype(mon->data, AD_DISE) || dmgtype(mon->data, AD_PEST) || /* won't happen, see prior goto */ resists_poison(mon)) { if (canseemon(mon)) pline("%s looks unharmed.", Monnam(mon)); break; } do_illness: if((mon->mhpmax > 3) && !resist(mon, POTION_CLASS, 0, NOTELL)) mon->mhpmax /= 2; if((mon->mhp > 2) && !resist(mon, POTION_CLASS, 0, NOTELL)) mon->mhp /= 2; if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; if (canseemon(mon)) pline("%s looks rather ill.", Monnam(mon)); break; case POT_CONFUSION: case POT_BOOZE: if(!resist(mon, POTION_CLASS, 0, NOTELL)) mon->mconf = TRUE; break; case POT_INVISIBILITY: angermon = FALSE; mon_set_minvis(mon); break; case POT_SLEEPING: /* wakeup() doesn't rouse victims of temporary sleep */ if (sleep_monst(mon, rnd(12), POTION_CLASS)) { pline("%s falls asleep.", Monnam(mon)); slept_monst(mon); } break; case POT_PARALYSIS: if (mon->mcanmove) { mon->mcanmove = 0; /* really should be rnd(5) for consistency with players * breathing potions, but... */ mon->mfrozen = rnd(25); } break; case POT_SPEED: angermon = FALSE; mon_adjust_speed(mon, 1, obj); break; case POT_BLINDNESS: if(haseyes(mon->data)) { register int btmp = 64 + rn2(32) + rn2(32) * !resist(mon, POTION_CLASS, 0, NOTELL); btmp += mon->mblinded; mon->mblinded = min(btmp,127); mon->mcansee = 0; } break; case POT_WATER: if (is_undead(mon->data) || is_demon(mon->data) || is_were(mon->data)) { if (obj->blessed) { pline("%s %s in pain!", Monnam(mon), is_silent(mon->data) ? "writhes" : "shrieks"); mon->mhp -= d(2,6); /* should only be by you */ if (mon->mhp < 1) killed(mon); else if (is_were(mon->data) && !is_human(mon->data)) new_were(mon); /* revert to human */ } else if (obj->cursed) { angermon = FALSE; if (canseemon(mon)) pline("%s looks healthier.", Monnam(mon)); mon->mhp += d(2,6); if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; if (is_were(mon->data) && is_human(mon->data) && !Protection_from_shape_changers) new_were(mon); /* transform into beast */ } } else if(mon->data == &mons[PM_GREMLIN]) { angermon = FALSE; (void)split_mon(mon, (struct monst *)0); } else if(mon->data == &mons[PM_IRON_GOLEM]) { if (canseemon(mon)) pline("%s rusts.", Monnam(mon)); mon->mhp -= d(1,6); /* should only be by you */ if (mon->mhp < 1) killed(mon); } break; case POT_OIL: if (obj->lamplit) splatter_burning_oil(mon->mx, mon->my); break; case POT_ACID: if (!resists_acid(mon) && !resist(mon, POTION_CLASS, 0, NOTELL)) { pline("%s %s in pain!", Monnam(mon), is_silent(mon->data) ? "writhes" : "shrieks"); mon->mhp -= d(obj->cursed ? 2 : 1, obj->blessed ? 4 : 8); if (mon->mhp < 1) { if (your_fault) killed(mon); else monkilled(mon, "", AD_ACID); } } break; case POT_POLYMORPH: (void) bhitm(mon, obj); break; /* case POT_GAIN_LEVEL: case POT_LEVITATION: case POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case POT_OBJECT_DETECTION: break; */ } if (angermon) wakeup(mon); else mon->msleeping = 0; } /* Note: potionbreathe() does its own docall() */ if ((distance==0 || ((distance < 3) && rn2(5))) && (!breathless(youmonst.data) || haseyes(youmonst.data))) potionbreathe(obj); else if (obj->dknown && !objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname && cansee(mon->mx,mon->my)) docall(obj); if(*u.ushops && obj->unpaid) { register struct monst *shkp = shop_keeper(*in_rooms(u.ux, u.uy, SHOPBASE)); if(!shkp) obj->unpaid = 0; else { (void)stolen_value(obj, u.ux, u.uy, (boolean)shkp->mpeaceful, FALSE); subfrombill(obj, shkp); } } obfree(obj, (struct obj *)0); } /* vapors are inhaled or get in your eyes */ void potionbreathe(obj) register struct obj *obj; { register int i, ii, isdone, kn = 0; switch(obj->otyp) { case POT_RESTORE_ABILITY: case POT_GAIN_ABILITY: if(obj->cursed) { if (!breathless(youmonst.data)) pline("Ulch! That potion smells terrible!"); else if (haseyes(youmonst.data)) { int numeyes = eyecount(youmonst.data); Your("%s sting%s!", (numeyes == 1) ? body_part(EYE) : makeplural(body_part(EYE)), (numeyes == 1) ? "s" : ""); } break; } else { i = rn2(A_MAX); /* start at a random point */ for(isdone = ii = 0; !isdone && ii < A_MAX; ii++) { if(ABASE(i) < AMAX(i)) { ABASE(i)++; /* only first found if not blessed */ isdone = !(obj->blessed); flags.botl = 1; } if(++i >= A_MAX) i = 0; } } break; case POT_FULL_HEALING: if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1; if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1; /*FALL THROUGH*/ case POT_EXTRA_HEALING: if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1; if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1; /*FALL THROUGH*/ case POT_HEALING: if (Upolyd && u.mh < u.mhmax) u.mh++, flags.botl = 1; if (u.uhp < u.uhpmax) u.uhp++, flags.botl = 1; exercise(A_CON, TRUE); break; case POT_SICKNESS: if (!Role_if(PM_HEALER)) { if (Upolyd) { if (u.mh <= 5) u.mh = 1; else u.mh -= 5; } else { if (u.uhp <= 5) u.uhp = 1; else u.uhp -= 5; } flags.botl = 1; exercise(A_CON, FALSE); } break; case POT_HALLUCINATION: You("have a momentary vision."); break; case POT_CONFUSION: case POT_BOOZE: if(!Confusion) You_feel("somewhat dizzy."); make_confused(itimeout_incr(HConfusion, rnd(5)), FALSE); break; case POT_INVISIBILITY: if (!Blind && !Invis) { kn++; pline("For an instant you %s!", See_invisible ? "could see right through yourself" : "couldn't see yourself"); } break; case POT_PARALYSIS: kn++; if (!Free_action) { pline("%s seems to be holding you.", Something); nomul(-rnd(5)); nomovemsg = You_can_move_again; exercise(A_DEX, FALSE); } else You("stiffen momentarily."); break; case POT_SLEEPING: kn++; if (!Free_action && !Sleep_resistance) { You_feel("rather tired."); nomul(-rnd(5)); nomovemsg = You_can_move_again; exercise(A_DEX, FALSE); } else You("yawn."); break; case POT_SPEED: if (!Fast) Your("knees seem more flexible now."); incr_itimeout(&HFast, rnd(5)); exercise(A_DEX, TRUE); break; case POT_BLINDNESS: if (!Blind && !u.usleep) { kn++; pline("It suddenly gets dark."); } make_blinded(itimeout_incr(Blinded, rnd(5)), FALSE); if (!Blind && !u.usleep) Your(vision_clears); break; case POT_WATER: if(u.umonnum == PM_GREMLIN) { (void)split_mon(&youmonst, (struct monst *)0); } else if (u.ulycn >= LOW_PM) { /* vapor from [un]holy water will trigger transformation but won't cure lycanthropy */ if (obj->blessed && youmonst.data == &mons[u.ulycn]) you_unwere(FALSE); else if (obj->cursed && !Upolyd) you_were(); } break; case POT_ACID: case POT_POLYMORPH: exercise(A_CON, FALSE); break; /* case POT_GAIN_LEVEL: case POT_LEVITATION: case POT_FRUIT_JUICE: case POT_MONSTER_DETECTION: case POT_OBJECT_DETECTION: case POT_OIL: break; */ } /* note: no obfree() */ if (obj->dknown) { if (kn) makeknown(obj->otyp); else if (!objects[obj->otyp].oc_name_known && !objects[obj->otyp].oc_uname) docall(obj); } } STATIC_OVL short mixtype(o1, o2) register struct obj *o1, *o2; /* returns the potion type when o1 is dipped in o2 */ { /* cut down on the number of cases below */ if (o1->oclass == POTION_CLASS && (o2->otyp == POT_GAIN_LEVEL || o2->otyp == POT_GAIN_ENERGY || o2->otyp == POT_HEALING || o2->otyp == POT_EXTRA_HEALING || o2->otyp == POT_FULL_HEALING || o2->otyp == POT_ENLIGHTENMENT || o2->otyp == POT_FRUIT_JUICE)) { struct obj *swp; swp = o1; o1 = o2; o2 = swp; } switch (o1->otyp) { case POT_HEALING: switch (o2->otyp) { case POT_SPEED: case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: return POT_EXTRA_HEALING; } case POT_EXTRA_HEALING: switch (o2->otyp) { case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: return POT_FULL_HEALING; } case POT_FULL_HEALING: switch (o2->otyp) { case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: return POT_GAIN_ABILITY; } case UNICORN_HORN: switch (o2->otyp) { case POT_SICKNESS: return POT_FRUIT_JUICE; case POT_HALLUCINATION: case POT_BLINDNESS: case POT_CONFUSION: return POT_WATER; } break; case AMETHYST: /* "a-methyst" == "not intoxicated" */ if (o2->otyp == POT_BOOZE) return POT_FRUIT_JUICE; break; case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: switch (o2->otyp) { case POT_CONFUSION: return (rn2(3) ? POT_BOOZE : POT_ENLIGHTENMENT); case POT_HEALING: return POT_EXTRA_HEALING; case POT_EXTRA_HEALING: return POT_FULL_HEALING; case POT_FULL_HEALING: return POT_GAIN_ABILITY; case POT_FRUIT_JUICE: return POT_SEE_INVISIBLE; case POT_BOOZE: return POT_HALLUCINATION; } break; case POT_FRUIT_JUICE: switch (o2->otyp) { case POT_SICKNESS: return POT_SICKNESS; case POT_SPEED: return POT_BOOZE; case POT_GAIN_LEVEL: case POT_GAIN_ENERGY: return POT_SEE_INVISIBLE; } break; case POT_ENLIGHTENMENT: switch (o2->otyp) { case POT_LEVITATION: if (rn2(3)) return POT_GAIN_LEVEL; break; case POT_FRUIT_JUICE: return POT_BOOZE; case POT_BOOZE: return POT_CONFUSION; } break; } return 0; } boolean get_wet(obj) register struct obj *obj; /* returns TRUE if something happened (potion should be used up) */ { char Your_buf[BUFSZ]; if (snuff_lit(obj)) return(TRUE); if (obj->greased) { grease_protect(obj,(char *)0,&youmonst); return(FALSE); } (void) Shk_Your(Your_buf, obj); /* (Rusting shop goods ought to be charged for.) */ switch (obj->oclass) { case POTION_CLASS: if (obj->otyp == POT_WATER) return FALSE; /* KMH -- Water into acid causes an explosion */ if (obj->otyp == POT_ACID) { pline("It boils vigorously!"); You("are caught in the explosion!"); losehp(rnd(10), "elementary chemistry", KILLED_BY); makeknown(obj->otyp); update_inventory(); return (TRUE); } pline("%s %s%s.", Your_buf, aobjnam(obj,"dilute"), obj->odiluted ? " further" : ""); if(obj->unpaid && costly_spot(u.ux, u.uy)) { You("dilute it, you pay for it."); bill_dummy_object(obj); } if (obj->odiluted) { obj->odiluted = 0; #ifdef UNIXPC obj->blessed = FALSE; obj->cursed = FALSE; #else obj->blessed = obj->cursed = FALSE; #endif obj->otyp = POT_WATER; } else obj->odiluted++; update_inventory(); return TRUE; case SCROLL_CLASS: if (obj->otyp != SCR_BLANK_PAPER #ifdef MAIL && obj->otyp != SCR_MAIL #endif ) { if (!Blind) { boolean oq1 = obj->quan == 1L; pline_The("scroll%s %s.", oq1 ? "" : "s", otense(obj, "fade")); } if(obj->unpaid && costly_spot(u.ux, u.uy)) { You("erase it, you pay for it."); bill_dummy_object(obj); } obj->otyp = SCR_BLANK_PAPER; obj->spe = 0; update_inventory(); return TRUE; } else break; case SPBOOK_CLASS: if (obj->otyp != SPE_BLANK_PAPER) { if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { pline("%s suddenly heats up; steam rises and it remains dry.", The(xname(obj))); } else { if (!Blind) { boolean oq1 = obj->quan == 1L; pline_The("spellbook%s %s.", oq1 ? "" : "s", otense(obj, "fade")); } if(obj->unpaid && costly_spot(u.ux, u.uy)) { You("erase it, you pay for it."); bill_dummy_object(obj); } obj->otyp = SPE_BLANK_PAPER; update_inventory(); } return TRUE; } break; case WEAPON_CLASS: /* Just "fall through" to generic rustprone check for now. */ /* fall through */ default: if (!obj->oerodeproof && is_rustprone(obj) && (obj->oeroded < MAX_ERODE) && !rn2(2)) { pline("%s %s some%s.", Your_buf, aobjnam(obj, "rust"), obj->oeroded ? " more" : "what"); obj->oeroded++; update_inventory(); return TRUE; } else break; } pline("%s %s wet.", Your_buf, aobjnam(obj,"get")); return FALSE; } int dodip() { register struct obj *potion, *obj; struct obj *singlepotion; const char *tmp; uchar here; char allowall[2]; short mixture; char qbuf[QBUFSZ], Your_buf[BUFSZ]; allowall[0] = ALL_CLASSES; allowall[1] = '\0'; if(!(obj = getobj(allowall, "dip"))) return(0); here = levl[u.ux][u.uy].typ; /* Is there a fountain to dip into here? */ if (IS_FOUNTAIN(here)) { if(yn("Dip it into the fountain?") == 'y') { dipfountain(obj); return(1); } } else if (is_pool(u.ux,u.uy)) { tmp = waterbody_name(u.ux,u.uy); Sprintf(qbuf, "Dip it into the %s?", tmp); if (yn(qbuf) == 'y') { if (Levitation) { floating_above(tmp); #ifdef STEED } else if (u.usteed && !is_swimmer(u.usteed->data) && P_SKILL(P_RIDING) < P_BASIC) { rider_cant_reach(); /* not skilled enough to reach */ #endif } else { (void) get_wet(obj); if (obj->otyp == POT_ACID) useup(obj); } return 1; } } if(!(potion = getobj(beverages, "dip into"))) return(0); if (potion == obj && potion->quan == 1L) { pline("That is a potion bottle, not a Klein bottle!"); return 0; } potion->in_use = TRUE; /* assume it will be used up */ if(potion->otyp == POT_WATER) { boolean useeit = !Blind; if (useeit) (void) Shk_Your(Your_buf, obj); if (potion->blessed) { if (obj->cursed) { if (useeit) pline("%s %s %s.", Your_buf, aobjnam(obj, "softly glow"), hcolor(NH_AMBER)); uncurse(obj); obj->bknown=1; poof: if(!(objects[potion->otyp].oc_name_known) && !(objects[potion->otyp].oc_uname)) docall(potion); useup(potion); return(1); } else if(!obj->blessed) { if (useeit) { tmp = hcolor(NH_LIGHT_BLUE); pline("%s %s with a%s %s aura.", Your_buf, aobjnam(obj, "softly glow"), index(vowels, *tmp) ? "n" : "", tmp); } bless(obj); obj->bknown=1; goto poof; } } else if (potion->cursed) { if (obj->blessed) { if (useeit) pline("%s %s %s.", Your_buf, aobjnam(obj, "glow"), hcolor((const char *)"brown")); unbless(obj); obj->bknown=1; goto poof; } else if(!obj->cursed) { if (useeit) { tmp = hcolor(NH_BLACK); pline("%s %s with a%s %s aura.", Your_buf, aobjnam(obj, "glow"), index(vowels, *tmp) ? "n" : "", tmp); } curse(obj); obj->bknown=1; goto poof; } } else if (get_wet(obj)) goto poof; } else if (obj->otyp == POT_POLYMORPH || potion->otyp == POT_POLYMORPH) { /* some objects can't be polymorphed */ if (obj->otyp == potion->otyp || /* both POT_POLY */ obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH || obj == uball || obj == uskin || obj_resists(obj->otyp == POT_POLYMORPH ? potion : obj, 5, 95)) { pline(nothing_happens); } else { boolean was_wep = FALSE, was_swapwep = FALSE, was_quiver = FALSE; short save_otyp = obj->otyp; /* KMH, conduct */ u.uconduct.polypiles++; if (obj == uwep) was_wep = TRUE; else if (obj == uswapwep) was_swapwep = TRUE; else if (obj == uquiver) was_quiver = TRUE; obj = poly_obj(obj, STRANGE_OBJECT); if (was_wep) setuwep(obj); else if (was_swapwep) setuswapwep(obj); else if (was_quiver) setuqwep(obj); if (obj->otyp != save_otyp) { makeknown(POT_POLYMORPH); useup(potion); prinv((char *)0, obj, 0L); return 1; } else { pline("Nothing seems to happen."); goto poof; } } potion->in_use = FALSE; /* didn't go poof */ return(1); } else if(obj->oclass == POTION_CLASS && obj->otyp != potion->otyp) { /* Mixing potions is dangerous... */ pline_The("potions mix..."); /* KMH, balance patch -- acid is particularly unstable */ if (obj->cursed || obj->otyp == POT_ACID || !rn2(10)) { pline("BOOM! They explode!"); exercise(A_STR, FALSE); if (!breathless(youmonst.data) || haseyes(youmonst.data)) potionbreathe(obj); useup(obj); useup(potion); losehp(rnd(10), "alchemic blast", KILLED_BY_AN); return(1); } obj->blessed = obj->cursed = obj->bknown = 0; if (Blind || Hallucination) obj->dknown = 0; if ((mixture = mixtype(obj, potion)) != 0) { obj->otyp = mixture; } else { switch (obj->odiluted ? 1 : rnd(8)) { case 1: obj->otyp = POT_WATER; break; case 2: case 3: obj->otyp = POT_SICKNESS; break; case 4: { struct obj *otmp; otmp = mkobj(POTION_CLASS,FALSE); obj->otyp = otmp->otyp; obfree(otmp, (struct obj *)0); } break; default: if (!Blind) pline_The("mixture glows brightly and evaporates."); useup(obj); useup(potion); return(1); } } obj->odiluted = (obj->otyp != POT_WATER); if (obj->otyp == POT_WATER && !Hallucination) { pline_The("mixture bubbles%s.", Blind ? "" : ", then clears"); } else if (!Blind) { pline_The("mixture looks %s.", hcolor(OBJ_DESCR(objects[obj->otyp]))); } useup(potion); return(1); } #ifdef INVISIBLE_OBJECTS if (potion->otyp == POT_INVISIBILITY && !obj->oinvis) { obj->oinvis = TRUE; if (!Blind) { if (!See_invisible) pline("Where did %s go?", the(xname(obj))); else You("notice a little haziness around %s.", the(xname(obj))); } goto poof; } else if (potion->otyp == POT_SEE_INVISIBLE && obj->oinvis) { obj->oinvis = FALSE; if (!Blind) { if (!See_invisible) pline("So that's where %s went!", the(xname(obj))); else pline_The("haziness around %s disappears.", the(xname(obj))); } goto poof; } #endif if(is_poisonable(obj)) { if(potion->otyp == POT_SICKNESS && !obj->opoisoned) { char buf[BUFSZ]; if (potion->quan > 1L) Sprintf(buf, "One of %s", the(xname(potion))); else Strcpy(buf, The(xname(potion))); pline("%s forms a coating on %s.", buf, the(xname(obj))); obj->opoisoned = TRUE; goto poof; } else if(obj->opoisoned && (potion->otyp == POT_HEALING || potion->otyp == POT_EXTRA_HEALING || potion->otyp == POT_FULL_HEALING)) { pline("A coating wears off %s.", the(xname(obj))); obj->opoisoned = 0; goto poof; } } if (potion->otyp == POT_OIL) { boolean wisx = FALSE; if (potion->lamplit) { /* burning */ int omat = objects[obj->otyp].oc_material; /* the code here should be merged with fire_damage */ if (catch_lit(obj)) { /* catch_lit does all the work if true */ } else if (obj->oerodeproof || obj_resists(obj, 5, 95) || !is_flammable(obj) || obj->oclass == FOOD_CLASS) { pline("%s %s to burn for a moment.", Yname2(obj), otense(obj, "seem")); } else { if ((omat == PLASTIC || omat == PAPER) && !obj->oartifact) obj->oeroded = MAX_ERODE; pline_The("burning oil %s %s.", obj->oeroded == MAX_ERODE ? "destroys" : "damages", yname(obj)); if (obj->oeroded == MAX_ERODE) { obj_extract_self(obj); obfree(obj, (struct obj *)0); obj = (struct obj *) 0; } else { /* we know it's carried */ if (obj->unpaid) { /* create a dummy duplicate to put on bill */ verbalize("You burnt it, you bought it!"); bill_dummy_object(obj); } obj->oeroded++; } } } else if (potion->cursed) { pline_The("potion spills and covers your %s with oil.", makeplural(body_part(FINGER))); incr_itimeout(&Glib, d(2,10)); } else if (obj->oclass != WEAPON_CLASS && !is_weptool(obj)) { /* the following cases apply only to weapons */ goto more_dips; /* Oil removes rust and corrosion, but doesn't unburn. * Arrows, etc are classed as metallic due to arrowhead * material, but dipping in oil shouldn't repair them. */ } else if ((!is_rustprone(obj) && !is_corrodeable(obj)) || is_ammo(obj) || (!obj->oeroded && !obj->oeroded2)) { /* uses up potion, doesn't set obj->greased */ pline("%s %s with an oily sheen.", Yname2(obj), otense(obj, "gleam")); } else { pline("%s %s less %s.", Yname2(obj), otense(obj, "are"), (obj->oeroded && obj->oeroded2) ? "corroded and rusty" : obj->oeroded ? "rusty" : "corroded"); if (obj->oeroded > 0) obj->oeroded--; if (obj->oeroded2 > 0) obj->oeroded2--; wisx = TRUE; } exercise(A_WIS, wisx); makeknown(potion->otyp); useup(potion); return 1; } more_dips: /* Allow filling of MAGIC_LAMPs to prevent identification by player */ if ((obj->otyp == OIL_LAMP || obj->otyp == MAGIC_LAMP) && (potion->otyp == POT_OIL)) { /* Turn off engine before fueling, turn off fuel too :-) */ if (obj->lamplit || potion->lamplit) { useup(potion); explode(u.ux, u.uy, 11, d(6,6), 0, EXPL_FIERY); exercise(A_WIS, FALSE); return 1; } /* Adding oil to an empty magic lamp renders it into an oil lamp */ if ((obj->otyp == MAGIC_LAMP) && obj->spe == 0) { obj->otyp = OIL_LAMP; obj->age = 0; } if (obj->age > 1000L) { pline("%s %s full.", Yname2(obj), otense(obj, "are")); potion->in_use = FALSE; /* didn't go poof */ } else { You("fill %s with oil.", yname(obj)); check_unpaid(potion); /* Yendorian Fuel Tax */ obj->age += 2*potion->age; /* burns more efficiently */ if (obj->age > 1500L) obj->age = 1500L; useup(potion); exercise(A_WIS, TRUE); } makeknown(POT_OIL); obj->spe = 1; update_inventory(); return 1; } potion->in_use = FALSE; /* didn't go poof */ if ((obj->otyp == UNICORN_HORN || obj->otyp == AMETHYST) && (mixture = mixtype(obj, potion)) != 0) { char oldbuf[BUFSZ], newbuf[BUFSZ]; short old_otyp = potion->otyp; boolean old_dknown = FALSE; boolean more_than_one = potion->quan > 1; oldbuf[0] = '\0'; if (potion->dknown) { old_dknown = TRUE; Sprintf(oldbuf, "%s ", hcolor(OBJ_DESCR(objects[potion->otyp]))); } /* with multiple merged potions, split off one and just clear it */ if (potion->quan > 1L) { singlepotion = splitobj(potion, 1L); } else singlepotion = potion; if(singlepotion->unpaid && costly_spot(u.ux, u.uy)) { You("use it, you pay for it."); bill_dummy_object(singlepotion); } singlepotion->otyp = mixture; singlepotion->blessed = 0; if (mixture == POT_WATER) singlepotion->cursed = singlepotion->odiluted = 0; else singlepotion->cursed = obj->cursed; /* odiluted left as-is */ singlepotion->bknown = FALSE; if (Blind) { singlepotion->dknown = FALSE; } else { singlepotion->dknown = !Hallucination; if (mixture == POT_WATER && singlepotion->dknown) Sprintf(newbuf, "clears"); else Sprintf(newbuf, "turns %s", hcolor(OBJ_DESCR(objects[mixture]))); pline_The("%spotion%s %s.", oldbuf, more_than_one ? " that you dipped into" : "", newbuf); if(!objects[old_otyp].oc_uname && !objects[old_otyp].oc_name_known && old_dknown) { struct obj fakeobj; fakeobj = zeroobj; fakeobj.dknown = 1; fakeobj.otyp = old_otyp; fakeobj.oclass = POTION_CLASS; docall(&fakeobj); } } obj_extract_self(singlepotion); singlepotion = hold_another_object(singlepotion, "You juggle and drop %s!", doname(singlepotion), (const char *)0); update_inventory(); return(1); } pline("Interesting..."); return(1); } void djinni_from_bottle(obj) register struct obj *obj; { struct monst *mtmp; int chance; if(!(mtmp = makemon(&mons[PM_DJINNI], u.ux, u.uy, NO_MM_FLAGS))){ pline("It turns out to be empty."); return; } if (!Blind) { pline("In a cloud of smoke, %s emerges!", a_monnam(mtmp)); pline("%s speaks.", Monnam(mtmp)); } else { You("smell acrid fumes."); pline("%s speaks.", Something); } chance = rn2(5); if (obj->blessed) chance = (chance == 4) ? rnd(4) : 0; else if (obj->cursed) chance = (chance == 0) ? rn2(4) : 4; /* 0,1,2,3,4: b=80%,5,5,5,5; nc=20%,20,20,20,20; c=5%,5,5,5,80 */ switch (chance) { case 0 : verbalize("I am in your debt. I will grant one wish!"); makewish(); mongone(mtmp); break; case 1 : verbalize("Thank you for freeing me!"); (void) tamedog(mtmp, (struct obj *)0); break; case 2 : verbalize("You freed me!"); mtmp->mpeaceful = TRUE; set_malign(mtmp); break; case 3 : verbalize("It is about time!"); pline("%s vanishes.", Monnam(mtmp)); mongone(mtmp); break; default: verbalize("You disturbed me, fool!"); break; } } /* clone a gremlin or mold (2nd arg non-null implies heat as the trigger); hit points are cut in half (odd HP stays with original) */ struct monst * split_mon(mon, mtmp) struct monst *mon, /* monster being split */ *mtmp; /* optional attacker whose heat triggered it */ { struct monst *mtmp2; char reason[BUFSZ]; reason[0] = '\0'; if (mtmp) Sprintf(reason, " from %s heat", (mtmp == &youmonst) ? (const char *)"your" : (const char *)s_suffix(mon_nam(mtmp))); if (mon == &youmonst) { mtmp2 = cloneu(); if (mtmp2) { mtmp2->mhpmax = u.mhmax / 2; u.mhmax -= mtmp2->mhpmax; flags.botl = 1; You("multiply%s!", reason); } } else { mtmp2 = clone_mon(mon, 0, 0); if (mtmp2) { mtmp2->mhpmax = mon->mhpmax / 2; mon->mhpmax -= mtmp2->mhpmax; if (canspotmon(mon)) pline("%s multiplies%s!", Monnam(mon), reason); } } return mtmp2; } #endif /* OVLB */ /*potion.c*/ nethack-3.4.3/src/pray.c0100644000000000000000000015462307764735041013573 0ustar rootroot/* SCCS Id: @(#)pray.c 3.4 2003/03/23 */ /* Copyright (c) Benson I. Margulies, Mike Stephenson, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "epri.h" STATIC_PTR int NDECL(prayer_done); STATIC_DCL struct obj *NDECL(worst_cursed_item); STATIC_DCL int NDECL(in_trouble); STATIC_DCL void FDECL(fix_worst_trouble,(int)); STATIC_DCL void FDECL(angrygods,(ALIGNTYP_P)); STATIC_DCL void FDECL(at_your_feet, (const char *)); #ifdef ELBERETH STATIC_DCL void NDECL(gcrownu); #endif /*ELBERETH*/ STATIC_DCL void FDECL(pleased,(ALIGNTYP_P)); STATIC_DCL void FDECL(godvoice,(ALIGNTYP_P,const char*)); STATIC_DCL void FDECL(god_zaps_you,(ALIGNTYP_P)); STATIC_DCL void FDECL(fry_by_god,(ALIGNTYP_P)); STATIC_DCL void FDECL(gods_angry,(ALIGNTYP_P)); STATIC_DCL void FDECL(gods_upset,(ALIGNTYP_P)); STATIC_DCL void FDECL(consume_offering,(struct obj *)); STATIC_DCL boolean FDECL(water_prayer,(BOOLEAN_P)); STATIC_DCL boolean FDECL(blocked_boulder,(int,int)); /* simplify a few tests */ #define Cursed_obj(obj,typ) ((obj) && (obj)->otyp == (typ) && (obj)->cursed) /* * Logic behind deities and altars and such: * + prayers are made to your god if not on an altar, and to the altar's god * if you are on an altar * + If possible, your god answers all prayers, which is why bad things happen * if you try to pray on another god's altar * + sacrifices work basically the same way, but the other god may decide to * accept your allegiance, after which they are your god. If rejected, * your god takes over with your punishment. * + if you're in Gehennom, all messages come from Moloch */ /* * Moloch, who dwells in Gehennom, is the "renegade" cruel god * responsible for the theft of the Amulet from Marduk, the Creator. * Moloch is unaligned. */ static const char *Moloch = "Moloch"; static const char *godvoices[] = { "booms out", "thunders", "rings out", "booms", }; /* values calculated when prayer starts, and used when completed */ static aligntyp p_aligntyp; static int p_trouble; static int p_type; /* (-1)-3: (-1)=really naughty, 3=really good */ #define PIOUS 20 #define DEVOUT 14 #define FERVENT 9 #define STRIDENT 4 /* * The actual trouble priority is determined by the order of the * checks performed in in_trouble() rather than by these numeric * values, so keep that code and these values synchronized in * order to have the values be meaningful. */ #define TROUBLE_STONED 13 #define TROUBLE_SLIMED 12 #define TROUBLE_STRANGLED 11 #define TROUBLE_LAVA 10 #define TROUBLE_SICK 9 #define TROUBLE_STARVING 8 #define TROUBLE_HIT 7 #define TROUBLE_LYCANTHROPE 6 #define TROUBLE_COLLAPSING 5 #define TROUBLE_STUCK_IN_WALL 4 #define TROUBLE_CURSED_LEVITATION 3 #define TROUBLE_UNUSEABLE_HANDS 2 #define TROUBLE_CURSED_BLINDFOLD 1 #define TROUBLE_PUNISHED (-1) #define TROUBLE_FUMBLING (-2) #define TROUBLE_CURSED_ITEMS (-3) #define TROUBLE_SADDLE (-4) #define TROUBLE_BLIND (-5) #define TROUBLE_POISONED (-6) #define TROUBLE_WOUNDED_LEGS (-7) #define TROUBLE_HUNGRY (-8) #define TROUBLE_STUNNED (-9) #define TROUBLE_CONFUSED (-10) #define TROUBLE_HALLUCINATION (-11) /* We could force rehumanize of polyselfed people, but we can't tell unintentional shape changes from the other kind. Oh well. 3.4.2: make an exception if polymorphed into a form which lacks hands; that's a case where the ramifications override this doubt. */ /* Return 0 if nothing particular seems wrong, positive numbers for serious trouble, and negative numbers for comparative annoyances. This returns the worst problem. There may be others, and the gods may fix more than one. This could get as bizarre as noting surrounding opponents, (or hostile dogs), but that's really hard. */ #define ugod_is_angry() (u.ualign.record < 0) #define on_altar() IS_ALTAR(levl[u.ux][u.uy].typ) #define on_shrine() ((levl[u.ux][u.uy].altarmask & AM_SHRINE) != 0) #define a_align(x,y) ((aligntyp)Amask2align(levl[x][y].altarmask & AM_MASK)) STATIC_OVL int in_trouble() { struct obj *otmp; int i, j, count=0; /* Borrowed from eat.c */ #define SATIATED 0 #define NOT_HUNGRY 1 #define HUNGRY 2 #define WEAK 3 #define FAINTING 4 #define FAINTED 5 #define STARVED 6 /* * major troubles */ if(Stoned) return(TROUBLE_STONED); if(Slimed) return(TROUBLE_SLIMED); if(Strangled) return(TROUBLE_STRANGLED); if(u.utrap && u.utraptype == TT_LAVA) return(TROUBLE_LAVA); if(Sick) return(TROUBLE_SICK); if(u.uhs >= WEAK) return(TROUBLE_STARVING); if (Upolyd ? (u.mh <= 5 || u.mh*7 <= u.mhmax) : (u.uhp <= 5 || u.uhp*7 <= u.uhpmax)) return TROUBLE_HIT; if(u.ulycn >= LOW_PM) return(TROUBLE_LYCANTHROPE); if(near_capacity() >= EXT_ENCUMBER && AMAX(A_STR)-ABASE(A_STR) > 3) return(TROUBLE_COLLAPSING); for (i= -1; i<=1; i++) for(j= -1; j<=1; j++) { if (!i && !j) continue; if (!isok(u.ux+i, u.uy+j) || IS_ROCK(levl[u.ux+i][u.uy+j].typ) || (blocked_boulder(i,j) && !throws_rocks(youmonst.data))) count++; } if (count == 8 && !Passes_walls) return(TROUBLE_STUCK_IN_WALL); if (Cursed_obj(uarmf, LEVITATION_BOOTS) || stuck_ring(uleft, RIN_LEVITATION) || stuck_ring(uright, RIN_LEVITATION)) return(TROUBLE_CURSED_LEVITATION); if (nohands(youmonst.data) || !freehand()) { /* for bag/box access [cf use_container()]... make sure it's a case that we know how to handle; otherwise "fix all troubles" would get stuck in a loop */ if (welded(uwep)) return TROUBLE_UNUSEABLE_HANDS; if (Upolyd && nohands(youmonst.data) && (!Unchanging || ((otmp = unchanger()) != 0 && otmp->cursed))) return TROUBLE_UNUSEABLE_HANDS; } if(Blindfolded && ublindf->cursed) return(TROUBLE_CURSED_BLINDFOLD); /* * minor troubles */ if(Punished) return(TROUBLE_PUNISHED); if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING) || Cursed_obj(uarmf, FUMBLE_BOOTS)) return TROUBLE_FUMBLING; if (worst_cursed_item()) return TROUBLE_CURSED_ITEMS; #ifdef STEED if (u.usteed) { /* can't voluntarily dismount from a cursed saddle */ otmp = which_armor(u.usteed, W_SADDLE); if (Cursed_obj(otmp, SADDLE)) return TROUBLE_SADDLE; } #endif if (Blinded > 1 && haseyes(youmonst.data)) return(TROUBLE_BLIND); for(i=0; i= HUNGRY) return(TROUBLE_HUNGRY); if(HStun) return (TROUBLE_STUNNED); if(HConfusion) return (TROUBLE_CONFUSED); if(Hallucination) return(TROUBLE_HALLUCINATION); return(0); } /* select an item for TROUBLE_CURSED_ITEMS */ STATIC_OVL struct obj * worst_cursed_item() { register struct obj *otmp; /* if strained or worse, check for loadstone first */ if (near_capacity() >= HVY_ENCUMBER) { for (otmp = invent; otmp; otmp = otmp->nobj) if (Cursed_obj(otmp, LOADSTONE)) return otmp; } /* weapon takes precedence if it is interfering with taking off a ring or putting on a shield */ if (welded(uwep) && (uright || bimanual(uwep))) { /* weapon */ otmp = uwep; /* gloves come next, due to rings */ } else if (uarmg && uarmg->cursed) { /* gloves */ otmp = uarmg; /* then shield due to two handed weapons and spells */ } else if (uarms && uarms->cursed) { /* shield */ otmp = uarms; /* then cloak due to body armor */ } else if (uarmc && uarmc->cursed) { /* cloak */ otmp = uarmc; } else if (uarm && uarm->cursed) { /* suit */ otmp = uarm; } else if (uarmh && uarmh->cursed) { /* helmet */ otmp = uarmh; } else if (uarmf && uarmf->cursed) { /* boots */ otmp = uarmf; #ifdef TOURIST } else if (uarmu && uarmu->cursed) { /* shirt */ otmp = uarmu; #endif } else if (uamul && uamul->cursed) { /* amulet */ otmp = uamul; } else if (uleft && uleft->cursed) { /* left ring */ otmp = uleft; } else if (uright && uright->cursed) { /* right ring */ otmp = uright; } else if (ublindf && ublindf->cursed) { /* eyewear */ otmp = ublindf; /* must be non-blinding lenses */ /* if weapon wasn't handled above, do it now */ } else if (welded(uwep)) { /* weapon */ otmp = uwep; /* active secondary weapon even though it isn't welded */ } else if (uswapwep && uswapwep->cursed && u.twoweap) { otmp = uswapwep; /* all worn items ought to be handled by now */ } else { for (otmp = invent; otmp; otmp = otmp->nobj) { if (!otmp->cursed) continue; if (otmp->otyp == LOADSTONE || confers_luck(otmp)) break; } } return otmp; } STATIC_OVL void fix_worst_trouble(trouble) register int trouble; { int i; struct obj *otmp = 0; const char *what = (const char *)0; static NEARDATA const char leftglow[] = "left ring softly glows", rightglow[] = "right ring softly glows"; switch (trouble) { case TROUBLE_STONED: You_feel("more limber."); Stoned = 0; flags.botl = 1; delayed_killer = 0; break; case TROUBLE_SLIMED: pline_The("slime disappears."); Slimed = 0; flags.botl = 1; delayed_killer = 0; break; case TROUBLE_STRANGLED: if (uamul && uamul->otyp == AMULET_OF_STRANGULATION) { Your("amulet vanishes!"); useup(uamul); } You("can breathe again."); Strangled = 0; flags.botl = 1; break; case TROUBLE_LAVA: You("are back on solid ground."); /* teleport should always succeed, but if not, * just untrap them. */ if(!safe_teleds(FALSE)) u.utrap = 0; break; case TROUBLE_STARVING: losestr(-1); /* fall into... */ case TROUBLE_HUNGRY: Your("%s feels content.", body_part(STOMACH)); init_uhunger(); flags.botl = 1; break; case TROUBLE_SICK: You_feel("better."); make_sick(0L, (char *) 0, FALSE, SICK_ALL); break; case TROUBLE_HIT: /* "fix all troubles" will keep trying if hero has 5 or less hit points, so make sure they're always boosted to be more than that */ You_feel("much better."); if (Upolyd) { u.mhmax += rnd(5); if (u.mhmax <= 5) u.mhmax = 5+1; u.mh = u.mhmax; } if (u.uhpmax < u.ulevel * 5 + 11) u.uhpmax += rnd(5); if (u.uhpmax <= 5) u.uhpmax = 5+1; u.uhp = u.uhpmax; flags.botl = 1; break; case TROUBLE_COLLAPSING: ABASE(A_STR) = AMAX(A_STR); flags.botl = 1; break; case TROUBLE_STUCK_IN_WALL: Your("surroundings change."); /* no control, but works on no-teleport levels */ (void) safe_teleds(FALSE); break; case TROUBLE_CURSED_LEVITATION: if (Cursed_obj(uarmf, LEVITATION_BOOTS)) { otmp = uarmf; } else if ((otmp = stuck_ring(uleft,RIN_LEVITATION)) !=0) { if (otmp == uleft) what = leftglow; } else if ((otmp = stuck_ring(uright,RIN_LEVITATION))!=0) { if (otmp == uright) what = rightglow; } goto decurse; case TROUBLE_UNUSEABLE_HANDS: if (welded(uwep)) { otmp = uwep; goto decurse; } if (Upolyd && nohands(youmonst.data)) { if (!Unchanging) { Your("shape becomes uncertain."); rehumanize(); /* "You return to {normal} form." */ } else if ((otmp = unchanger()) != 0 && otmp->cursed) { /* otmp is an amulet of unchanging */ goto decurse; } } if (nohands(youmonst.data) || !freehand()) impossible("fix_worst_trouble: couldn't cure hands."); break; case TROUBLE_CURSED_BLINDFOLD: otmp = ublindf; goto decurse; case TROUBLE_LYCANTHROPE: you_unwere(TRUE); break; /* */ case TROUBLE_PUNISHED: Your("chain disappears."); unpunish(); break; case TROUBLE_FUMBLING: if (Cursed_obj(uarmg, GAUNTLETS_OF_FUMBLING)) otmp = uarmg; else if (Cursed_obj(uarmf, FUMBLE_BOOTS)) otmp = uarmf; goto decurse; /*NOTREACHED*/ break; case TROUBLE_CURSED_ITEMS: otmp = worst_cursed_item(); if (otmp == uright) what = rightglow; else if (otmp == uleft) what = leftglow; decurse: if (!otmp) { impossible("fix_worst_trouble: nothing to uncurse."); return; } uncurse(otmp); if (!Blind) { Your("%s %s.", what ? what : (const char *)aobjnam(otmp, "softly glow"), hcolor(NH_AMBER)); otmp->bknown = TRUE; } update_inventory(); break; case TROUBLE_POISONED: if (Hallucination) pline("There's a tiger in your tank."); else You_feel("in good health again."); for(i=0; ibknown = TRUE; } break; #endif } } /* "I am sometimes shocked by... the nuns who never take a bath without * wearing a bathrobe all the time. When asked why, since no man can see them, * they reply 'Oh, but you forget the good God'. Apparently they conceive of * the Deity as a Peeping Tom, whose omnipotence enables Him to see through * bathroom walls, but who is foiled by bathrobes." --Bertrand Russell, 1943 * Divine wrath, dungeon walls, and armor follow the same principle. */ STATIC_OVL void god_zaps_you(resp_god) aligntyp resp_god; { if (u.uswallow) { pline("Suddenly a bolt of lightning comes down at you from the heavens!"); pline("It strikes %s!", mon_nam(u.ustuck)); if (!resists_elec(u.ustuck)) { pline("%s fries to a crisp!", Monnam(u.ustuck)); /* Yup, you get experience. It takes guts to successfully * pull off this trick on your god, anyway. */ xkilled(u.ustuck, 0); } else pline("%s seems unaffected.", Monnam(u.ustuck)); } else { pline("Suddenly, a bolt of lightning strikes you!"); if (Reflecting) { shieldeff(u.ux, u.uy); if (Blind) pline("For some reason you're unaffected."); else (void) ureflects("%s reflects from your %s.", "It"); } else if (Shock_resistance) { shieldeff(u.ux, u.uy); pline("It seems not to affect you."); } else fry_by_god(resp_god); } pline("%s is not deterred...", align_gname(resp_god)); if (u.uswallow) { pline("A wide-angle disintegration beam aimed at you hits %s!", mon_nam(u.ustuck)); if (!resists_disint(u.ustuck)) { pline("%s fries to a crisp!", Monnam(u.ustuck)); xkilled(u.ustuck, 2); /* no corpse */ } else pline("%s seems unaffected.", Monnam(u.ustuck)); } else { pline("A wide-angle disintegration beam hits you!"); /* disintegrate shield and body armor before disintegrating * the impudent mortal, like black dragon breath -3. */ if (uarms && !(EReflecting & W_ARMS) && !(EDisint_resistance & W_ARMS)) (void) destroy_arm(uarms); if (uarmc && !(EReflecting & W_ARMC) && !(EDisint_resistance & W_ARMC)) (void) destroy_arm(uarmc); if (uarm && !(EReflecting & W_ARM) && !(EDisint_resistance & W_ARM) && !uarmc) (void) destroy_arm(uarm); #ifdef TOURIST if (uarmu && !uarm && !uarmc) (void) destroy_arm(uarmu); #endif if (!Disint_resistance) fry_by_god(resp_god); else { You("bask in its %s glow for a minute...", NH_BLACK); godvoice(resp_god, "I believe it not!"); } if (Is_astralevel(&u.uz) || Is_sanctum(&u.uz)) { /* one more try for high altars */ verbalize("Thou cannot escape my wrath, mortal!"); summon_minion(resp_god, FALSE); summon_minion(resp_god, FALSE); summon_minion(resp_god, FALSE); verbalize("Destroy %s, my servants!", uhim()); } } } STATIC_OVL void fry_by_god(resp_god) aligntyp resp_god; { char killerbuf[64]; You("fry to a crisp."); killer_format = KILLED_BY; Sprintf(killerbuf, "the wrath of %s", align_gname(resp_god)); killer = killerbuf; done(DIED); } STATIC_OVL void angrygods(resp_god) aligntyp resp_god; { register int maxanger; if(Inhell) resp_god = A_NONE; u.ublessed = 0; /* changed from tmp = u.ugangr + abs (u.uluck) -- rph */ /* added test for alignment diff -dlc */ if(resp_god != u.ualign.type) maxanger = u.ualign.record/2 + (Luck > 0 ? -Luck/3 : -Luck); else maxanger = 3*u.ugangr + ((Luck > 0 || u.ualign.record >= STRIDENT) ? -Luck/3 : -Luck); if (maxanger < 1) maxanger = 1; /* possible if bad align & good luck */ else if (maxanger > 15) maxanger = 15; /* be reasonable */ switch (rn2(maxanger)) { case 0: case 1: You_feel("that %s is %s.", align_gname(resp_god), Hallucination ? "bummed" : "displeased"); break; case 2: case 3: godvoice(resp_god,(char *)0); pline("\"Thou %s, %s.\"", (ugod_is_angry() && resp_god == u.ualign.type) ? "hast strayed from the path" : "art arrogant", youmonst.data->mlet == S_HUMAN ? "mortal" : "creature"); verbalize("Thou must relearn thy lessons!"); (void) adjattrib(A_WIS, -1, FALSE); losexp((char *)0); break; case 6: if (!Punished) { gods_angry(resp_god); punish((struct obj *)0); break; } /* else fall thru */ case 4: case 5: gods_angry(resp_god); if (!Blind && !Antimagic) pline("%s glow surrounds you.", An(hcolor(NH_BLACK))); rndcurse(); break; case 7: case 8: godvoice(resp_god,(char *)0); verbalize("Thou durst %s me?", (on_altar() && (a_align(u.ux,u.uy) != resp_god)) ? "scorn":"call upon"); pline("\"Then die, %s!\"", youmonst.data->mlet == S_HUMAN ? "mortal" : "creature"); summon_minion(resp_god, FALSE); break; default: gods_angry(resp_god); god_zaps_you(resp_god); break; } u.ublesscnt = rnz(300); return; } /* helper to print "str appears at your feet", or appropriate */ static void at_your_feet(str) const char *str; { if (Blind) str = Something; if (u.uswallow) { /* barrier between you and the floor */ pline("%s %s into %s %s.", str, vtense(str, "drop"), s_suffix(mon_nam(u.ustuck)), mbodypart(u.ustuck, STOMACH)); } else { pline("%s %s %s your %s!", str, Blind ? "lands" : vtense(str, "appear"), Levitation ? "beneath" : "at", makeplural(body_part(FOOT))); } } #ifdef ELBERETH STATIC_OVL void gcrownu() { struct obj *obj; boolean already_exists, in_hand; short class_gift; int sp_no; #define ok_wep(o) ((o) && ((o)->oclass == WEAPON_CLASS || is_weptool(o))) HSee_invisible |= FROMOUTSIDE; HFire_resistance |= FROMOUTSIDE; HCold_resistance |= FROMOUTSIDE; HShock_resistance |= FROMOUTSIDE; HSleep_resistance |= FROMOUTSIDE; HPoison_resistance |= FROMOUTSIDE; godvoice(u.ualign.type, (char *)0); obj = ok_wep(uwep) ? uwep : 0; already_exists = in_hand = FALSE; /* lint suppression */ switch (u.ualign.type) { case A_LAWFUL: u.uevent.uhand_of_elbereth = 1; verbalize("I crown thee... The Hand of Elbereth!"); break; case A_NEUTRAL: u.uevent.uhand_of_elbereth = 2; in_hand = (uwep && uwep->oartifact == ART_VORPAL_BLADE); already_exists = exist_artifact(LONG_SWORD, artiname(ART_VORPAL_BLADE)); verbalize("Thou shalt be my Envoy of Balance!"); break; case A_CHAOTIC: u.uevent.uhand_of_elbereth = 3; in_hand = (uwep && uwep->oartifact == ART_STORMBRINGER); already_exists = exist_artifact(RUNESWORD, artiname(ART_STORMBRINGER)); verbalize("Thou art chosen to %s for My Glory!", already_exists && !in_hand ? "take lives" : "steal souls"); break; } class_gift = STRANGE_OBJECT; /* 3.3.[01] had this in the A_NEUTRAL case below, preventing chaotic wizards from receiving a spellbook */ if (Role_if(PM_WIZARD) && (!uwep || (uwep->oartifact != ART_VORPAL_BLADE && uwep->oartifact != ART_STORMBRINGER)) && !carrying(SPE_FINGER_OF_DEATH)) { class_gift = SPE_FINGER_OF_DEATH; make_splbk: obj = mksobj(class_gift, TRUE, FALSE); bless(obj); obj->bknown = TRUE; at_your_feet("A spellbook"); dropy(obj); u.ugifts++; /* when getting a new book for known spell, enhance currently wielded weapon rather than the book */ for (sp_no = 0; sp_no < MAXSPELL; sp_no++) if (spl_book[sp_no].sp_id == class_gift) { if (ok_wep(uwep)) obj = uwep; /* to be blessed,&c */ break; } } else if (Role_if(PM_MONK) && (!uwep || !uwep->oartifact) && !carrying(SPE_RESTORE_ABILITY)) { /* monks rarely wield a weapon */ class_gift = SPE_RESTORE_ABILITY; goto make_splbk; } switch (u.ualign.type) { case A_LAWFUL: if (class_gift != STRANGE_OBJECT) { ; /* already got bonus above */ } else if (obj && obj->otyp == LONG_SWORD && !obj->oartifact) { if (!Blind) Your("sword shines brightly for a moment."); obj = oname(obj, artiname(ART_EXCALIBUR)); if (obj && obj->oartifact == ART_EXCALIBUR) u.ugifts++; } /* acquire Excalibur's skill regardless of weapon or gift */ unrestrict_weapon_skill(P_LONG_SWORD); if (obj && obj->oartifact == ART_EXCALIBUR) discover_artifact(ART_EXCALIBUR); break; case A_NEUTRAL: if (class_gift != STRANGE_OBJECT) { ; /* already got bonus above */ } else if (in_hand) { Your("%s goes snicker-snack!", xname(obj)); obj->dknown = TRUE; } else if (!already_exists) { obj = mksobj(LONG_SWORD, FALSE, FALSE); obj = oname(obj, artiname(ART_VORPAL_BLADE)); obj->spe = 1; at_your_feet("A sword"); dropy(obj); u.ugifts++; } /* acquire Vorpal Blade's skill regardless of weapon or gift */ unrestrict_weapon_skill(P_LONG_SWORD); if (obj && obj->oartifact == ART_VORPAL_BLADE) discover_artifact(ART_VORPAL_BLADE); break; case A_CHAOTIC: { char swordbuf[BUFSZ]; Sprintf(swordbuf, "%s sword", hcolor(NH_BLACK)); if (class_gift != STRANGE_OBJECT) { ; /* already got bonus above */ } else if (in_hand) { Your("%s hums ominously!", swordbuf); obj->dknown = TRUE; } else if (!already_exists) { obj = mksobj(RUNESWORD, FALSE, FALSE); obj = oname(obj, artiname(ART_STORMBRINGER)); at_your_feet(An(swordbuf)); obj->spe = 1; dropy(obj); u.ugifts++; } /* acquire Stormbringer's skill regardless of weapon or gift */ unrestrict_weapon_skill(P_BROAD_SWORD); if (obj && obj->oartifact == ART_STORMBRINGER) discover_artifact(ART_STORMBRINGER); break; } default: obj = 0; /* lint */ break; } /* enhance weapon regardless of alignment or artifact status */ if (ok_wep(obj)) { bless(obj); obj->oeroded = obj->oeroded2 = 0; obj->oerodeproof = TRUE; obj->bknown = obj->rknown = TRUE; if (obj->spe < 1) obj->spe = 1; /* acquire skill in this weapon */ unrestrict_weapon_skill(weapon_type(obj)); } else if (class_gift == STRANGE_OBJECT) { /* opportunity knocked, but there was nobody home... */ You_feel("unworthy."); } update_inventory(); return; } #endif /*ELBERETH*/ STATIC_OVL void pleased(g_align) aligntyp g_align; { /* don't use p_trouble, worst trouble may get fixed while praying */ int trouble = in_trouble(); /* what's your worst difficulty? */ int pat_on_head = 0, kick_on_butt; You_feel("that %s is %s.", align_gname(g_align), u.ualign.record >= DEVOUT ? Hallucination ? "pleased as punch" : "well-pleased" : u.ualign.record >= STRIDENT ? Hallucination ? "ticklish" : "pleased" : Hallucination ? "full" : "satisfied"); /* not your deity */ if (on_altar() && p_aligntyp != u.ualign.type) { adjalign(-1); return; } else if (u.ualign.record < 2 && trouble <= 0) adjalign(1); /* depending on your luck & align level, the god you prayed to will: - fix your worst problem if it's major. - fix all your major problems. - fix your worst problem if it's minor. - fix all of your problems. - do you a gratuitous favor. if you make it to the the last category, you roll randomly again to see what they do for you. If your luck is at least 0, then you are guaranteed rescued from your worst major problem. */ if (!trouble && u.ualign.record >= DEVOUT) { /* if hero was in trouble, but got better, no special favor */ if (p_trouble == 0) pat_on_head = 1; } else { int action = rn1(Luck + (on_altar() ? 3 + on_shrine() : 2), 1); if (!on_altar()) action = min(action, 3); if (u.ualign.record < STRIDENT) action = (u.ualign.record > 0 || !rnl(2)) ? 1 : 0; switch(min(action,5)) { case 5: pat_on_head = 1; case 4: do fix_worst_trouble(trouble); while ((trouble = in_trouble()) != 0); break; case 3: fix_worst_trouble(trouble); case 2: while ((trouble = in_trouble()) > 0) fix_worst_trouble(trouble); break; case 1: if (trouble > 0) fix_worst_trouble(trouble); case 0: break; /* your god blows you off, too bad */ } } /* note: can't get pat_on_head unless all troubles have just been fixed or there were no troubles to begin with; hallucination won't be in effect so special handling for it is superfluous */ if(pat_on_head) switch(rn2((Luck + 6)>>1)) { case 0: break; case 1: if (uwep && (welded(uwep) || uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) { char repair_buf[BUFSZ]; *repair_buf = '\0'; if (uwep->oeroded || uwep->oeroded2) Sprintf(repair_buf, " and %s now as good as new", otense(uwep, "are")); if (uwep->cursed) { uncurse(uwep); uwep->bknown = TRUE; if (!Blind) Your("%s %s%s.", aobjnam(uwep, "softly glow"), hcolor(NH_AMBER), repair_buf); else You_feel("the power of %s over your %s.", u_gname(), xname(uwep)); *repair_buf = '\0'; } else if (!uwep->blessed) { bless(uwep); uwep->bknown = TRUE; if (!Blind) Your("%s with %s aura%s.", aobjnam(uwep, "softly glow"), an(hcolor(NH_LIGHT_BLUE)), repair_buf); else You_feel("the blessing of %s over your %s.", u_gname(), xname(uwep)); *repair_buf = '\0'; } /* fix any rust/burn/rot damage, but don't protect against future damage */ if (uwep->oeroded || uwep->oeroded2) { uwep->oeroded = uwep->oeroded2 = 0; /* only give this message if we didn't just bless or uncurse (which has already given a message) */ if (*repair_buf) Your("%s as good as new!", aobjnam(uwep, Blind ? "feel" : "look")); } update_inventory(); } break; case 3: /* takes 2 hints to get the music to enter the stronghold */ if (!u.uevent.uopened_dbridge) { if (u.uevent.uheard_tune < 1) { godvoice(g_align,(char *)0); verbalize("Hark, %s!", youmonst.data->mlet == S_HUMAN ? "mortal" : "creature"); verbalize( "To enter the castle, thou must play the right tune!"); u.uevent.uheard_tune++; break; } else if (u.uevent.uheard_tune < 2) { You_hear("a divine music..."); pline("It sounds like: \"%s\".", tune); u.uevent.uheard_tune++; break; } } /* Otherwise, falls into next case */ case 2: if (!Blind) You("are surrounded by %s glow.", an(hcolor(NH_GOLDEN))); /* if any levels have been lost (and not yet regained), treat this effect like blessed full healing */ if (u.ulevel < u.ulevelmax) { u.ulevelmax -= 1; /* see potion.c */ pluslvl(FALSE); } else { u.uhpmax += 5; if (Upolyd) u.mhmax += 5; } u.uhp = u.uhpmax; if (Upolyd) u.mh = u.mhmax; ABASE(A_STR) = AMAX(A_STR); if (u.uhunger < 900) init_uhunger(); if (u.uluck < 0) u.uluck = 0; make_blinded(0L,TRUE); flags.botl = 1; break; case 4: { register struct obj *otmp; int any = 0; if (Blind) You_feel("the power of %s.", u_gname()); else You("are surrounded by %s aura.", an(hcolor(NH_LIGHT_BLUE))); for(otmp=invent; otmp; otmp=otmp->nobj) { if (otmp->cursed) { uncurse(otmp); if (!Blind) { Your("%s %s.", aobjnam(otmp, "softly glow"), hcolor(NH_AMBER)); otmp->bknown = TRUE; ++any; } } } if (any) update_inventory(); break; } case 5: { const char *msg="\"and thus I grant thee the gift of %s!\""; godvoice(u.ualign.type, "Thou hast pleased me with thy progress,"); if (!(HTelepat & INTRINSIC)) { HTelepat |= FROMOUTSIDE; pline(msg, "Telepathy"); if (Blind) see_monsters(); } else if (!(HFast & INTRINSIC)) { HFast |= FROMOUTSIDE; pline(msg, "Speed"); } else if (!(HStealth & INTRINSIC)) { HStealth |= FROMOUTSIDE; pline(msg, "Stealth"); } else { if (!(HProtection & INTRINSIC)) { HProtection |= FROMOUTSIDE; if (!u.ublessed) u.ublessed = rn1(3, 2); } else u.ublessed++; pline(msg, "my protection"); } verbalize("Use it wisely in my name!"); break; } case 7: case 8: case 9: /* KMH -- can occur during full moons */ #ifdef ELBERETH if (u.ualign.record >= PIOUS && !u.uevent.uhand_of_elbereth) { gcrownu(); break; } /* else FALLTHRU */ #endif /*ELBERETH*/ case 6: { struct obj *otmp; int sp_no, trycnt = u.ulevel + 1; at_your_feet("An object"); /* not yet known spells given preference over already known ones */ /* Also, try to grant a spell for which there is a skill slot */ otmp = mkobj(SPBOOK_CLASS, TRUE); while (--trycnt > 0) { if (otmp->otyp != SPE_BLANK_PAPER) { for (sp_no = 0; sp_no < MAXSPELL; sp_no++) if (spl_book[sp_no].sp_id == otmp->otyp) break; if (sp_no == MAXSPELL && !P_RESTRICTED(spell_skilltype(otmp->otyp))) break; /* usable, but not yet known */ } else { if (!objects[SPE_BLANK_PAPER].oc_name_known || carrying(MAGIC_MARKER)) break; } otmp->otyp = rnd_class(bases[SPBOOK_CLASS], SPE_BLANK_PAPER); } bless(otmp); place_object(otmp, u.ux, u.uy); break; } default: impossible("Confused deity!"); break; } u.ublesscnt = rnz(350); kick_on_butt = u.uevent.udemigod ? 1 : 0; #ifdef ELBERETH if (u.uevent.uhand_of_elbereth) kick_on_butt++; #endif if (kick_on_butt) u.ublesscnt += kick_on_butt * rnz(1000); return; } /* either blesses or curses water on the altar, * returns true if it found any water here. */ STATIC_OVL boolean water_prayer(bless_water) boolean bless_water; { register struct obj* otmp; register long changed = 0; boolean other = FALSE, bc_known = !(Blind || Hallucination); for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp->nexthere) { /* turn water into (un)holy water */ if (otmp->otyp == POT_WATER && (bless_water ? !otmp->blessed : !otmp->cursed)) { otmp->blessed = bless_water; otmp->cursed = !bless_water; otmp->bknown = bc_known; changed += otmp->quan; } else if(otmp->oclass == POTION_CLASS) other = TRUE; } if(!Blind && changed) { pline("%s potion%s on the altar glow%s %s for a moment.", ((other && changed > 1L) ? "Some of the" : (other ? "One of the" : "The")), ((other || changed > 1L) ? "s" : ""), (changed > 1L ? "" : "s"), (bless_water ? hcolor(NH_LIGHT_BLUE) : hcolor(NH_BLACK))); } return((boolean)(changed > 0L)); } STATIC_OVL void godvoice(g_align, words) aligntyp g_align; const char *words; { const char *quot = ""; if(words) quot = "\""; else words = ""; pline_The("voice of %s %s: %s%s%s", align_gname(g_align), godvoices[rn2(SIZE(godvoices))], quot, words, quot); } STATIC_OVL void gods_angry(g_align) aligntyp g_align; { godvoice(g_align, "Thou hast angered me."); } /* The g_align god is upset with you. */ STATIC_OVL void gods_upset(g_align) aligntyp g_align; { if(g_align == u.ualign.type) u.ugangr++; else if(u.ugangr) u.ugangr--; angrygods(g_align); } static NEARDATA const char sacrifice_types[] = { FOOD_CLASS, AMULET_CLASS, 0 }; STATIC_OVL void consume_offering(otmp) register struct obj *otmp; { if (Hallucination) switch (rn2(3)) { case 0: Your("sacrifice sprouts wings and a propeller and roars away!"); break; case 1: Your("sacrifice puffs up, swelling bigger and bigger, and pops!"); break; case 2: Your("sacrifice collapses into a cloud of dancing particles and fades away!"); break; } else if (Blind && u.ualign.type == A_LAWFUL) Your("sacrifice disappears!"); else Your("sacrifice is consumed in a %s!", u.ualign.type == A_LAWFUL ? "flash of light" : "burst of flame"); if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); exercise(A_WIS, TRUE); } int dosacrifice() { register struct obj *otmp; int value = 0; int pm; aligntyp altaralign = a_align(u.ux,u.uy); if (!on_altar() || u.uswallow) { You("are not standing on an altar."); return 0; } if (In_endgame(&u.uz)) { if (!(otmp = getobj(sacrifice_types, "sacrifice"))) return 0; } else { if (!(otmp = floorfood("sacrifice", 1))) return 0; } /* Was based on nutritional value and aging behavior (< 50 moves). Sacrificing a food ration got you max luck instantly, making the gods as easy to please as an angry dog! Now only accepts corpses, based on the game's evaluation of their toughness. Human and pet sacrifice, as well as sacrificing unicorns of your alignment, is strongly discouraged. */ #define MAXVALUE 24 /* Highest corpse value (besides Wiz) */ if (otmp->otyp == CORPSE) { register struct permonst *ptr = &mons[otmp->corpsenm]; struct monst *mtmp; extern const int monstr[]; /* KMH, conduct */ u.uconduct.gnostic++; /* you're handling this corpse, even if it was killed upon the altar */ feel_cockatrice(otmp, TRUE); if (otmp->corpsenm == PM_ACID_BLOB || (monstermoves <= peek_at_iced_corpse_age(otmp) + 50)) { value = monstr[otmp->corpsenm] + 1; if (otmp->oeaten) value = eaten_stat(value, otmp); } if (your_race(ptr)) { if (is_demon(youmonst.data)) { You("find the idea very satisfying."); exercise(A_WIS, TRUE); } else if (u.ualign.type != A_CHAOTIC) { pline("You'll regret this infamous offense!"); exercise(A_WIS, FALSE); } if (altaralign != A_CHAOTIC && altaralign != A_NONE) { /* curse the lawful/neutral altar */ pline_The("altar is stained with %s blood.", urace.adj); if(!Is_astralevel(&u.uz)) levl[u.ux][u.uy].altarmask = AM_CHAOTIC; angry_priest(); } else { struct monst *dmon; const char *demonless_msg; /* Human sacrifice on a chaotic or unaligned altar */ /* is equivalent to demon summoning */ if (altaralign == A_CHAOTIC && u.ualign.type != A_CHAOTIC) { pline( "The blood floods the altar, which vanishes in %s cloud!", an(hcolor(NH_BLACK))); levl[u.ux][u.uy].typ = ROOM; levl[u.ux][u.uy].altarmask = 0; newsym(u.ux, u.uy); angry_priest(); demonless_msg = "cloud dissipates"; } else { /* either you're chaotic or altar is Moloch's or both */ pline_The("blood covers the altar!"); change_luck(altaralign == A_NONE ? -2 : 2); demonless_msg = "blood coagulates"; } if ((pm = dlord(altaralign)) != NON_PM && (dmon = makemon(&mons[pm], u.ux, u.uy, NO_MM_FLAGS))) { You("have summoned %s!", a_monnam(dmon)); if (sgn(u.ualign.type) == sgn(dmon->data->maligntyp)) dmon->mpeaceful = TRUE; You("are terrified, and unable to move."); nomul(-3); } else pline_The("%s.", demonless_msg); } if (u.ualign.type != A_CHAOTIC) { adjalign(-5); u.ugangr += 3; (void) adjattrib(A_WIS, -1, TRUE); if (!Inhell) angrygods(u.ualign.type); change_luck(-5); } else adjalign(5); if (carried(otmp)) useup(otmp); else useupf(otmp, 1L); return(1); } else if (otmp->oxlth && otmp->oattached == OATTACHED_MONST && ((mtmp = get_mtraits(otmp, FALSE)) != (struct monst *)0) && mtmp->mtame) { /* mtmp is a temporary pointer to a tame monster's attributes, * not a real monster */ pline("So this is how you repay loyalty?"); adjalign(-3); value = -1; HAggravate_monster |= FROMOUTSIDE; } else if (is_undead(ptr)) { /* Not demons--no demon corpses */ if (u.ualign.type != A_CHAOTIC) value += 1; } else if (is_unicorn(ptr)) { int unicalign = sgn(ptr->maligntyp); /* If same as altar, always a very bad action. */ if (unicalign == altaralign) { pline("Such an action is an insult to %s!", (unicalign == A_CHAOTIC) ? "chaos" : unicalign ? "law" : "balance"); (void) adjattrib(A_WIS, -1, TRUE); value = -5; } else if (u.ualign.type == altaralign) { /* If different from altar, and altar is same as yours, */ /* it's a very good action */ if (u.ualign.record < ALIGNLIM) You_feel("appropriately %s.", align_str(u.ualign.type)); else You_feel("you are thoroughly on the right path."); adjalign(5); value += 3; } else /* If sacrificing unicorn of your alignment to altar not of */ /* your alignment, your god gets angry and it's a conversion */ if (unicalign == u.ualign.type) { u.ualign.record = -1; value = 1; } else value += 3; } } /* corpse */ if (otmp->otyp == AMULET_OF_YENDOR) { if (!Is_astralevel(&u.uz)) { if (Hallucination) You_feel("homesick."); else You_feel("an urge to return to the surface."); return 1; } else { /* The final Test. Did you win? */ if(uamul == otmp) Amulet_off(); u.uevent.ascended = 1; if(carried(otmp)) useup(otmp); /* well, it's gone now */ else useupf(otmp, 1L); You("offer the Amulet of Yendor to %s...", a_gname()); if (u.ualign.type != altaralign) { /* And the opposing team picks you up and carries you off on their shoulders */ adjalign(-99); pline("%s accepts your gift, and gains dominion over %s...", a_gname(), u_gname()); pline("%s is enraged...", u_gname()); pline("Fortunately, %s permits you to live...", a_gname()); pline("A cloud of %s smoke surrounds you...", hcolor((const char *)"orange")); done(ESCAPED); } else { /* super big win */ adjalign(10); pline("An invisible choir sings, and you are bathed in radiance..."); godvoice(altaralign, "Congratulations, mortal!"); display_nhwindow(WIN_MESSAGE, FALSE); verbalize("In return for thy service, I grant thee the gift of Immortality!"); You("ascend to the status of Demigod%s...", flags.female ? "dess" : ""); done(ASCENDED); } } } /* real Amulet */ if (otmp->otyp == FAKE_AMULET_OF_YENDOR) { if (flags.soundok) You_hear("a nearby thunderclap."); if (!otmp->known) { You("realize you have made a %s.", Hallucination ? "boo-boo" : "mistake"); otmp->known = TRUE; change_luck(-1); return 1; } else { /* don't you dare try to fool the gods */ change_luck(-3); adjalign(-1); u.ugangr += 3; value = -3; } } /* fake Amulet */ if (value == 0) { pline(nothing_happens); return (1); } if (altaralign != u.ualign.type && (Is_astralevel(&u.uz) || Is_sanctum(&u.uz))) { /* * REAL BAD NEWS!!! High altars cannot be converted. Even an attempt * gets the god who owns it truely pissed off. */ You_feel("the air around you grow charged..."); pline("Suddenly, you realize that %s has noticed you...", a_gname()); godvoice(altaralign, "So, mortal! You dare desecrate my High Temple!"); /* Throw everything we have at the player */ god_zaps_you(altaralign); } else if (value < 0) { /* I don't think the gods are gonna like this... */ gods_upset(altaralign); } else { int saved_anger = u.ugangr; int saved_cnt = u.ublesscnt; int saved_luck = u.uluck; /* Sacrificing at an altar of a different alignment */ if (u.ualign.type != altaralign) { /* Is this a conversion ? */ /* An unaligned altar in Gehennom will always elicit rejection. */ if (ugod_is_angry() || (altaralign == A_NONE && Inhell)) { if(u.ualignbase[A_CURRENT] == u.ualignbase[A_ORIGINAL] && altaralign != A_NONE) { You("have a strong feeling that %s is angry...", u_gname()); consume_offering(otmp); pline("%s accepts your allegiance.", a_gname()); /* The player wears a helm of opposite alignment? */ if (uarmh && uarmh->otyp == HELM_OF_OPPOSITE_ALIGNMENT) u.ualignbase[A_CURRENT] = altaralign; else u.ualign.type = u.ualignbase[A_CURRENT] = altaralign; u.ublessed = 0; flags.botl = 1; You("have a sudden sense of a new direction."); /* Beware, Conversion is costly */ change_luck(-3); u.ublesscnt += 300; adjalign((int)(u.ualignbase[A_ORIGINAL] * (ALIGNLIM / 2))); } else { u.ugangr += 3; adjalign(-5); pline("%s rejects your sacrifice!", a_gname()); godvoice(altaralign, "Suffer, infidel!"); change_luck(-5); (void) adjattrib(A_WIS, -2, TRUE); if (!Inhell) angrygods(u.ualign.type); } return(1); } else { consume_offering(otmp); You("sense a conflict between %s and %s.", u_gname(), a_gname()); if (rn2(8 + u.ulevel) > 5) { struct monst *pri; You_feel("the power of %s increase.", u_gname()); exercise(A_WIS, TRUE); change_luck(1); /* Yes, this is supposed to be &=, not |= */ levl[u.ux][u.uy].altarmask &= AM_SHRINE; /* the following accommodates stupid compilers */ levl[u.ux][u.uy].altarmask = levl[u.ux][u.uy].altarmask | (Align2amask(u.ualign.type)); if (!Blind) pline_The("altar glows %s.", hcolor( u.ualign.type == A_LAWFUL ? NH_WHITE : u.ualign.type ? NH_BLACK : (const char *)"gray")); if (rnl(u.ulevel) > 6 && u.ualign.record > 0 && rnd(u.ualign.record) > (3*ALIGNLIM)/4) summon_minion(altaralign, TRUE); /* anger priest; test handles bones files */ if((pri = findpriest(temple_occupied(u.urooms))) && !p_coaligned(pri)) angry_priest(); } else { pline("Unluckily, you feel the power of %s decrease.", u_gname()); change_luck(-1); exercise(A_WIS, FALSE); if (rnl(u.ulevel) > 6 && u.ualign.record > 0 && rnd(u.ualign.record) > (7*ALIGNLIM)/8) summon_minion(altaralign, TRUE); } return(1); } } consume_offering(otmp); /* OK, you get brownie points. */ if(u.ugangr) { u.ugangr -= ((value * (u.ualign.type == A_CHAOTIC ? 2 : 3)) / MAXVALUE); if(u.ugangr < 0) u.ugangr = 0; if(u.ugangr != saved_anger) { if (u.ugangr) { pline("%s seems %s.", u_gname(), Hallucination ? "groovy" : "slightly mollified"); if ((int)u.uluck < 0) change_luck(1); } else { pline("%s seems %s.", u_gname(), Hallucination ? "cosmic (not a new fact)" : "mollified"); if ((int)u.uluck < 0) u.uluck = 0; } } else { /* not satisfied yet */ if (Hallucination) pline_The("gods seem tall."); else You("have a feeling of inadequacy."); } } else if(ugod_is_angry()) { if(value > MAXVALUE) value = MAXVALUE; if(value > -u.ualign.record) value = -u.ualign.record; adjalign(value); You_feel("partially absolved."); } else if (u.ublesscnt > 0) { u.ublesscnt -= ((value * (u.ualign.type == A_CHAOTIC ? 500 : 300)) / MAXVALUE); if(u.ublesscnt < 0) u.ublesscnt = 0; if(u.ublesscnt != saved_cnt) { if (u.ublesscnt) { if (Hallucination) You("realize that the gods are not like you and I."); else You("have a hopeful feeling."); if ((int)u.uluck < 0) change_luck(1); } else { if (Hallucination) pline("Overall, there is a smell of fried onions."); else You("have a feeling of reconciliation."); if ((int)u.uluck < 0) u.uluck = 0; } } } else { int nartifacts = nartifact_exist(); /* you were already in pretty good standing */ /* The player can gain an artifact */ /* The chance goes down as the number of artifacts goes up */ if (u.ulevel > 2 && u.uluck >= 0 && !rn2(10 + (2 * u.ugifts * nartifacts))) { otmp = mk_artifact((struct obj *)0, a_align(u.ux,u.uy)); if (otmp) { if (otmp->spe < 0) otmp->spe = 0; if (otmp->cursed) uncurse(otmp); otmp->oerodeproof = TRUE; dropy(otmp); at_your_feet("An object"); godvoice(u.ualign.type, "Use my gift wisely!"); u.ugifts++; u.ublesscnt = rnz(300 + (50 * nartifacts)); exercise(A_WIS, TRUE); /* make sure we can use this weapon */ unrestrict_weapon_skill(weapon_type(otmp)); discover_artifact(otmp->oartifact); return(1); } } change_luck((value * LUCKMAX) / (MAXVALUE * 2)); if ((int)u.uluck < 0) u.uluck = 0; if (u.uluck != saved_luck) { if (Blind) You("think %s brushed your %s.",something, body_part(FOOT)); else You(Hallucination ? "see crabgrass at your %s. A funny thing in a dungeon." : "glimpse a four-leaf clover at your %s.", makeplural(body_part(FOOT))); } } } return(1); } /* determine prayer results in advance; also used for enlightenment */ boolean can_pray(praying) boolean praying; /* false means no messages should be given */ { int alignment; p_aligntyp = on_altar() ? a_align(u.ux,u.uy) : u.ualign.type; p_trouble = in_trouble(); if (is_demon(youmonst.data) && (p_aligntyp != A_CHAOTIC)) { if (praying) pline_The("very idea of praying to a %s god is repugnant to you.", p_aligntyp ? "lawful" : "neutral"); return FALSE; } if (praying) You("begin praying to %s.", align_gname(p_aligntyp)); if (u.ualign.type && u.ualign.type == -p_aligntyp) alignment = -u.ualign.record; /* Opposite alignment altar */ else if (u.ualign.type != p_aligntyp) alignment = u.ualign.record / 2; /* Different alignment altar */ else alignment = u.ualign.record; if ((p_trouble > 0) ? (u.ublesscnt > 200) : /* big trouble */ (p_trouble < 0) ? (u.ublesscnt > 100) : /* minor difficulties */ (u.ublesscnt > 0)) /* not in trouble */ p_type = 0; /* too soon... */ else if ((int)Luck < 0 || u.ugangr || alignment < 0) p_type = 1; /* too naughty... */ else /* alignment >= 0 */ { if(on_altar() && u.ualign.type != p_aligntyp) p_type = 2; else p_type = 3; } if (is_undead(youmonst.data) && !Inhell && (p_aligntyp == A_LAWFUL || (p_aligntyp == A_NEUTRAL && !rn2(10)))) p_type = -1; /* Note: when !praying, the random factor for neutrals makes the return value a non-deterministic approximation for enlightenment. This case should be uncommon enough to live with... */ return !praying ? (boolean)(p_type == 3 && !Inhell) : TRUE; } int dopray() { /* Confirm accidental slips of Alt-P */ if (flags.prayconfirm) if (yn("Are you sure you want to pray?") == 'n') return 0; u.uconduct.gnostic++; /* Praying implies that the hero is conscious and since we have no deafness attribute this implies that all verbalized messages can be heard. So, in case the player has used the 'O' command to toggle this accessible flag off, force it to be on. */ flags.soundok = 1; /* set up p_type and p_alignment */ if (!can_pray(TRUE)) return 0; #ifdef WIZARD if (wizard && p_type >= 0) { if (yn("Force the gods to be pleased?") == 'y') { u.ublesscnt = 0; if (u.uluck < 0) u.uluck = 0; if (u.ualign.record <= 0) u.ualign.record = 1; u.ugangr = 0; if(p_type < 2) p_type = 3; } } #endif nomul(-3); nomovemsg = "You finish your prayer."; afternmv = prayer_done; if(p_type == 3 && !Inhell) { /* if you've been true to your god you can't die while you pray */ if (!Blind) You("are surrounded by a shimmering light."); u.uinvulnerable = TRUE; } return(1); } STATIC_PTR int prayer_done() /* M. Stephenson (1.0.3b) */ { aligntyp alignment = p_aligntyp; u.uinvulnerable = FALSE; if(p_type == -1) { godvoice(alignment, alignment == A_LAWFUL ? "Vile creature, thou durst call upon me?" : "Walk no more, perversion of nature!"); You_feel("like you are falling apart."); /* KMH -- Gods have mastery over unchanging */ rehumanize(); losehp(rnd(20), "residual undead turning effect", KILLED_BY_AN); exercise(A_CON, FALSE); return(1); } if (Inhell) { pline("Since you are in Gehennom, %s won't help you.", align_gname(alignment)); /* haltingly aligned is least likely to anger */ if (u.ualign.record <= 0 || rnl(u.ualign.record)) angrygods(u.ualign.type); return(0); } if (p_type == 0) { if(on_altar() && u.ualign.type != alignment) (void) water_prayer(FALSE); u.ublesscnt += rnz(250); change_luck(-3); gods_upset(u.ualign.type); } else if(p_type == 1) { if(on_altar() && u.ualign.type != alignment) (void) water_prayer(FALSE); angrygods(u.ualign.type); /* naughty */ } else if(p_type == 2) { if(water_prayer(FALSE)) { /* attempted water prayer on a non-coaligned altar */ u.ublesscnt += rnz(250); change_luck(-3); gods_upset(u.ualign.type); } else pleased(alignment); } else { /* coaligned */ if(on_altar()) (void) water_prayer(TRUE); pleased(alignment); /* nice */ } return(1); } int doturn() { /* Knights & Priest(esse)s only please */ struct monst *mtmp, *mtmp2; int once, range, xlev; if (!Role_if(PM_PRIEST) && !Role_if(PM_KNIGHT)) { /* Try to use turn undead spell. */ if (objects[SPE_TURN_UNDEAD].oc_name_known) { register int sp_no; for (sp_no = 0; sp_no < MAXSPELL && spl_book[sp_no].sp_id != NO_SPELL && spl_book[sp_no].sp_id != SPE_TURN_UNDEAD; sp_no++); if (sp_no < MAXSPELL && spl_book[sp_no].sp_id == SPE_TURN_UNDEAD) return spelleffects(sp_no, TRUE); } You("don't know how to turn undead!"); return(0); } u.uconduct.gnostic++; if ((u.ualign.type != A_CHAOTIC && (is_demon(youmonst.data) || is_undead(youmonst.data))) || u.ugangr > 6 /* "Die, mortal!" */) { pline("For some reason, %s seems to ignore you.", u_gname()); aggravate(); exercise(A_WIS, FALSE); return(0); } if (Inhell) { pline("Since you are in Gehennom, %s won't help you.", u_gname()); aggravate(); return(0); } pline("Calling upon %s, you chant an arcane formula.", u_gname()); exercise(A_WIS, TRUE); /* note: does not perform unturn_dead() on victims' inventories */ range = BOLT_LIM + (u.ulevel / 5); /* 5 to 11 */ range *= range; once = 0; for(mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; if (!cansee(mtmp->mx,mtmp->my) || distu(mtmp->mx,mtmp->my) > range) continue; if (!mtmp->mpeaceful && (is_undead(mtmp->data) || (is_demon(mtmp->data) && (u.ulevel > (MAXULEV/2))))) { mtmp->msleeping = 0; if (Confusion) { if (!once++) pline("Unfortunately, your voice falters."); mtmp->mflee = 0; mtmp->mfrozen = 0; mtmp->mcanmove = 1; } else if (!resist(mtmp, '\0', 0, TELL)) { xlev = 6; switch (mtmp->data->mlet) { /* this is intentional, lichs are tougher than zombies. */ case S_LICH: xlev += 2; /*FALLTHRU*/ case S_GHOST: xlev += 2; /*FALLTHRU*/ case S_VAMPIRE: xlev += 2; /*FALLTHRU*/ case S_WRAITH: xlev += 2; /*FALLTHRU*/ case S_MUMMY: xlev += 2; /*FALLTHRU*/ case S_ZOMBIE: if (u.ulevel >= xlev && !resist(mtmp, '\0', 0, NOTELL)) { if (u.ualign.type == A_CHAOTIC) { mtmp->mpeaceful = 1; set_malign(mtmp); } else { /* damn them */ killed(mtmp); } break; } /* else flee */ /*FALLTHRU*/ default: monflee(mtmp, 0, FALSE, TRUE); break; } } } } nomul(-5); return(1); } const char * a_gname() { return(a_gname_at(u.ux, u.uy)); } const char * a_gname_at(x,y) /* returns the name of an altar's deity */ xchar x, y; { if(!IS_ALTAR(levl[x][y].typ)) return((char *)0); return align_gname(a_align(x,y)); } const char * u_gname() /* returns the name of the player's deity */ { return align_gname(u.ualign.type); } const char * align_gname(alignment) aligntyp alignment; { const char *gnam; switch (alignment) { case A_NONE: gnam = Moloch; break; case A_LAWFUL: gnam = urole.lgod; break; case A_NEUTRAL: gnam = urole.ngod; break; case A_CHAOTIC: gnam = urole.cgod; break; default: impossible("unknown alignment."); gnam = "someone"; break; } if (*gnam == '_') ++gnam; return gnam; } /* hallucination handling for priest/minion names: select a random god iff character is hallucinating */ const char * halu_gname(alignment) aligntyp alignment; { const char *gnam; int which; if (!Hallucination) return align_gname(alignment); which = randrole(); switch (rn2(3)) { case 0: gnam = roles[which].lgod; break; case 1: gnam = roles[which].ngod; break; case 2: gnam = roles[which].cgod; break; default: gnam = 0; break; /* lint suppression */ } if (!gnam) gnam = Moloch; if (*gnam == '_') ++gnam; return gnam; } /* deity's title */ const char * align_gtitle(alignment) aligntyp alignment; { const char *gnam, *result = "god"; switch (alignment) { case A_LAWFUL: gnam = urole.lgod; break; case A_NEUTRAL: gnam = urole.ngod; break; case A_CHAOTIC: gnam = urole.cgod; break; default: gnam = 0; break; } if (gnam && *gnam == '_') result = "goddess"; return result; } void altar_wrath(x, y) register int x, y; { aligntyp altaralign = a_align(x,y); if(!strcmp(align_gname(altaralign), u_gname())) { godvoice(altaralign, "How darest thou desecrate my altar!"); (void) adjattrib(A_WIS, -1, FALSE); } else { pline("A voice (could it be %s?) whispers:", align_gname(altaralign)); verbalize("Thou shalt pay, infidel!"); change_luck(-1); } } /* assumes isok() at one space away, but not necessarily at two */ STATIC_OVL boolean blocked_boulder(dx,dy) int dx,dy; { register struct obj *otmp; long count = 0L; for(otmp = level.objects[u.ux+dx][u.uy+dy]; otmp; otmp = otmp->nexthere) { if(otmp->otyp == BOULDER) count += otmp->quan; } switch(count) { case 0: return FALSE; /* no boulders--not blocked */ case 1: break; /* possibly blocked depending on if it's pushable */ default: return TRUE; /* >1 boulder--blocked after they push the top one; don't force them to push it first to find out */ } if (!isok(u.ux+2*dx, u.uy+2*dy)) return TRUE; if (IS_ROCK(levl[u.ux+2*dx][u.uy+2*dy].typ)) return TRUE; if (sobj_at(BOULDER, u.ux+2*dx, u.uy+2*dy)) return TRUE; return FALSE; } /*pray.c*/ nethack-3.4.3/src/priest.c0100644000000000000000000004552607764735041014127 0ustar rootroot/* SCCS Id: @(#)priest.c 3.4 2002/11/06 */ /* Copyright (c) Izchak Miller, Steve Linhart, 1989. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mfndpos.h" #include "eshk.h" #include "epri.h" #include "emin.h" /* this matches the categorizations shown by enlightenment */ #define ALGN_SINNED (-4) /* worse than strayed */ #ifdef OVLB STATIC_DCL boolean FDECL(histemple_at,(struct monst *,XCHAR_P,XCHAR_P)); STATIC_DCL boolean FDECL(has_shrine,(struct monst *)); /* * Move for priests and shopkeepers. Called from shk_move() and pri_move(). * Valid returns are 1: moved 0: didn't -1: let m_move do it -2: died. */ int move_special(mtmp,in_his_shop,appr,uondoor,avoid,omx,omy,gx,gy) register struct monst *mtmp; boolean in_his_shop; schar appr; boolean uondoor,avoid; register xchar omx,omy,gx,gy; { register xchar nx,ny,nix,niy; register schar i; schar chcnt,cnt; coord poss[9]; long info[9]; long allowflags; struct obj *ib = (struct obj *)0; if(omx == gx && omy == gy) return(0); if(mtmp->mconf) { avoid = FALSE; appr = 0; } nix = omx; niy = omy; if (mtmp->isshk) allowflags = ALLOW_SSM; else allowflags = ALLOW_SSM | ALLOW_SANCT; if (passes_walls(mtmp->data)) allowflags |= (ALLOW_ROCK|ALLOW_WALL); if (throws_rocks(mtmp->data)) allowflags |= ALLOW_ROCK; if (tunnels(mtmp->data)) allowflags |= ALLOW_DIG; if (!nohands(mtmp->data) && !verysmall(mtmp->data)) { allowflags |= OPENDOOR; if (m_carrying(mtmp, SKELETON_KEY)) allowflags |= BUSTDOOR; } if (is_giant(mtmp->data)) allowflags |= BUSTDOOR; cnt = mfndpos(mtmp, poss, info, allowflags); if(mtmp->isshk && avoid && uondoor) { /* perhaps we cannot avoid him */ for(i=0; iispriest && levl[nx][ny].typ == ALTAR) || (mtmp->isshk && (!in_his_shop || ESHK(mtmp)->following))) { if(avoid && (info[i] & NOTONL)) continue; if((!appr && !rn2(++chcnt)) || (appr && GDIST(nx,ny) < GDIST(nix,niy))) { nix = nx; niy = ny; } } } if(mtmp->ispriest && avoid && nix == omx && niy == omy && onlineu(omx,omy)) { /* might as well move closer as long it's going to stay * lined up */ avoid = FALSE; goto pick_move; } if(nix != omx || niy != omy) { remove_monster(omx, omy); place_monster(mtmp, nix, niy); newsym(nix,niy); if (mtmp->isshk && !in_his_shop && inhishop(mtmp)) check_special_room(FALSE); if(ib) { if (cansee(mtmp->mx,mtmp->my)) pline("%s picks up %s.", Monnam(mtmp), distant_name(ib,doname)); obj_extract_self(ib); (void) mpickobj(mtmp, ib); } return(1); } return(0); } #endif /* OVLB */ #ifdef OVL0 char temple_occupied(array) register char *array; { register char *ptr; for (ptr = array; *ptr; ptr++) if (rooms[*ptr - ROOMOFFSET].rtype == TEMPLE) return(*ptr); return('\0'); } #endif /* OVL0 */ #ifdef OVLB STATIC_OVL boolean histemple_at(priest, x, y) register struct monst *priest; register xchar x, y; { return((boolean)((EPRI(priest)->shroom == *in_rooms(x, y, TEMPLE)) && on_level(&(EPRI(priest)->shrlevel), &u.uz))); } /* * pri_move: return 1: moved 0: didn't -1: let m_move do it -2: died */ int pri_move(priest) register struct monst *priest; { register xchar gx,gy,omx,omy; schar temple; boolean avoid = TRUE; omx = priest->mx; omy = priest->my; if(!histemple_at(priest, omx, omy)) return(-1); temple = EPRI(priest)->shroom; gx = EPRI(priest)->shrpos.x; gy = EPRI(priest)->shrpos.y; gx += rn1(3,-1); /* mill around the altar */ gy += rn1(3,-1); if(!priest->mpeaceful || (Conflict && !resist(priest, RING_CLASS, 0, 0))) { if(monnear(priest, u.ux, u.uy)) { if(Displaced) Your("displaced image doesn't fool %s!", mon_nam(priest)); (void) mattacku(priest); return(0); } else if(index(u.urooms, temple)) { /* chase player if inside temple & can see him */ if(priest->mcansee && m_canseeu(priest)) { gx = u.ux; gy = u.uy; } avoid = FALSE; } } else if(Invis) avoid = FALSE; return(move_special(priest,FALSE,TRUE,FALSE,avoid,omx,omy,gx,gy)); } /* exclusively for mktemple() */ void priestini(lvl, sroom, sx, sy, sanctum) d_level *lvl; struct mkroom *sroom; int sx, sy; boolean sanctum; /* is it the seat of the high priest? */ { struct monst *priest; struct obj *otmp; int cnt; if(MON_AT(sx+1, sy)) (void) rloc(m_at(sx+1, sy), FALSE); /* insurance */ priest = makemon(&mons[sanctum ? PM_HIGH_PRIEST : PM_ALIGNED_PRIEST], sx + 1, sy, NO_MM_FLAGS); if (priest) { EPRI(priest)->shroom = (sroom - rooms) + ROOMOFFSET; EPRI(priest)->shralign = Amask2align(levl[sx][sy].altarmask); EPRI(priest)->shrpos.x = sx; EPRI(priest)->shrpos.y = sy; assign_level(&(EPRI(priest)->shrlevel), lvl); priest->mtrapseen = ~0; /* traps are known */ priest->mpeaceful = 1; priest->ispriest = 1; priest->msleeping = 0; set_malign(priest); /* mpeaceful may have changed */ /* now his/her goodies... */ if(sanctum && EPRI(priest)->shralign == A_NONE && on_level(&sanctum_level, &u.uz)) { (void) mongets(priest, AMULET_OF_YENDOR); } /* 2 to 4 spellbooks */ for (cnt = rn1(3,2); cnt > 0; --cnt) { (void) mpickobj(priest, mkobj(SPBOOK_CLASS, FALSE)); } /* robe [via makemon()] */ if (rn2(2) && (otmp = which_armor(priest, W_ARMC)) != 0) { if (p_coaligned(priest)) uncurse(otmp); else curse(otmp); } } } /* * Specially aligned monsters are named specially. * - aligned priests with ispriest and high priests have shrines * they retain ispriest and epri when polymorphed * - aligned priests without ispriest and Angels are roamers * they retain isminion and access epri as emin when polymorphed * (coaligned Angels are also created as minions, but they * use the same naming convention) * - minions do not have ispriest but have isminion and emin * - caller needs to inhibit Hallucination if it wants to force * the true name even when under that influence */ char * priestname(mon, pname) register struct monst *mon; char *pname; /* caller-supplied output buffer */ { const char *what = Hallucination ? rndmonnam() : mon->data->mname; Strcpy(pname, "the "); if (mon->minvis) Strcat(pname, "invisible "); if (mon->ispriest || mon->data == &mons[PM_ALIGNED_PRIEST] || mon->data == &mons[PM_ANGEL]) { /* use epri */ if (mon->mtame && mon->data == &mons[PM_ANGEL]) Strcat(pname, "guardian "); if (mon->data != &mons[PM_ALIGNED_PRIEST] && mon->data != &mons[PM_HIGH_PRIEST]) { Strcat(pname, what); Strcat(pname, " "); } if (mon->data != &mons[PM_ANGEL]) { if (!mon->ispriest && EPRI(mon)->renegade) Strcat(pname, "renegade "); if (mon->data == &mons[PM_HIGH_PRIEST]) Strcat(pname, "high "); if (Hallucination) Strcat(pname, "poohbah "); else if (mon->female) Strcat(pname, "priestess "); else Strcat(pname, "priest "); } Strcat(pname, "of "); Strcat(pname, halu_gname((int)EPRI(mon)->shralign)); return(pname); } /* use emin instead of epri */ Strcat(pname, what); Strcat(pname, " of "); Strcat(pname, halu_gname(EMIN(mon)->min_align)); return(pname); } boolean p_coaligned(priest) struct monst *priest; { return((boolean)(u.ualign.type == ((int)EPRI(priest)->shralign))); } STATIC_OVL boolean has_shrine(pri) struct monst *pri; { struct rm *lev; if(!pri) return(FALSE); lev = &levl[EPRI(pri)->shrpos.x][EPRI(pri)->shrpos.y]; if (!IS_ALTAR(lev->typ) || !(lev->altarmask & AM_SHRINE)) return(FALSE); return((boolean)(EPRI(pri)->shralign == Amask2align(lev->altarmask & ~AM_SHRINE))); } struct monst * findpriest(roomno) char roomno; { register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if(mtmp->ispriest && (EPRI(mtmp)->shroom == roomno) && histemple_at(mtmp,mtmp->mx,mtmp->my)) return(mtmp); } return (struct monst *)0; } /* called from check_special_room() when the player enters the temple room */ void intemple(roomno) register int roomno; { register struct monst *priest = findpriest((char)roomno); boolean tended = (priest != (struct monst *)0); boolean shrined, sanctum, can_speak; const char *msg1, *msg2; char buf[BUFSZ]; if(!temple_occupied(u.urooms0)) { if(tended) { shrined = has_shrine(priest); sanctum = (priest->data == &mons[PM_HIGH_PRIEST] && (Is_sanctum(&u.uz) || In_endgame(&u.uz))); can_speak = (priest->mcanmove && !priest->msleeping && flags.soundok); if (can_speak) { unsigned save_priest = priest->ispriest; /* don't reveal the altar's owner upon temple entry in the endgame; for the Sanctum, the next message names Moloch so suppress the "of Moloch" for him here too */ if (sanctum && !Hallucination) priest->ispriest = 0; pline("%s intones:", canseemon(priest) ? Monnam(priest) : "A nearby voice"); priest->ispriest = save_priest; } msg2 = 0; if(sanctum && Is_sanctum(&u.uz)) { if(priest->mpeaceful) { msg1 = "Infidel, you have entered Moloch's Sanctum!"; msg2 = "Be gone!"; priest->mpeaceful = 0; set_malign(priest); } else msg1 = "You desecrate this place by your presence!"; } else { Sprintf(buf, "Pilgrim, you enter a %s place!", !shrined ? "desecrated" : "sacred"); msg1 = buf; } if (can_speak) { verbalize(msg1); if (msg2) verbalize(msg2); } if(!sanctum) { /* !tended -> !shrined */ if (!shrined || !p_coaligned(priest) || u.ualign.record <= ALGN_SINNED) You("have a%s forbidding feeling...", (!shrined) ? "" : " strange"); else You("experience a strange sense of peace."); } } else { switch(rn2(3)) { case 0: You("have an eerie feeling..."); break; case 1: You_feel("like you are being watched."); break; default: pline("A shiver runs down your %s.", body_part(SPINE)); break; } if(!rn2(5)) { struct monst *mtmp; if(!(mtmp = makemon(&mons[PM_GHOST],u.ux,u.uy,NO_MM_FLAGS))) return; if (!Blind || sensemon(mtmp)) pline("An enormous ghost appears next to you!"); else You("sense a presence close by!"); mtmp->mpeaceful = 0; set_malign(mtmp); if(flags.verbose) You("are frightened to death, and unable to move."); nomul(-3); nomovemsg = "You regain your composure."; } } } } void priest_talk(priest) register struct monst *priest; { boolean coaligned = p_coaligned(priest); boolean strayed = (u.ualign.record < 0); /* KMH, conduct */ u.uconduct.gnostic++; if(priest->mflee || (!priest->ispriest && coaligned && strayed)) { pline("%s doesn't want anything to do with you!", Monnam(priest)); priest->mpeaceful = 0; return; } /* priests don't chat unless peaceful and in their own temple */ if(!histemple_at(priest,priest->mx,priest->my) || !priest->mpeaceful || !priest->mcanmove || priest->msleeping) { static const char *cranky_msg[3] = { "Thou wouldst have words, eh? I'll give thee a word or two!", "Talk? Here is what I have to say!", "Pilgrim, I would speak no longer with thee." }; if(!priest->mcanmove || priest->msleeping) { pline("%s breaks out of %s reverie!", Monnam(priest), mhis(priest)); priest->mfrozen = priest->msleeping = 0; priest->mcanmove = 1; } priest->mpeaceful = 0; verbalize(cranky_msg[rn2(3)]); return; } /* you desecrated the temple and now you want to chat? */ if(priest->mpeaceful && *in_rooms(priest->mx, priest->my, TEMPLE) && !has_shrine(priest)) { verbalize("Begone! Thou desecratest this holy place with thy presence."); priest->mpeaceful = 0; return; } #ifndef GOLDOBJ if(!u.ugold) { if(coaligned && !strayed) { if (priest->mgold > 0L) { /* Note: two bits is actually 25 cents. Hmm. */ pline("%s gives you %s for an ale.", Monnam(priest), (priest->mgold == 1L) ? "one bit" : "two bits"); if (priest->mgold > 1L) u.ugold = 2L; else u.ugold = 1L; priest->mgold -= u.ugold; flags.botl = 1; #else if(!money_cnt(invent)) { if(coaligned && !strayed) { long pmoney = money_cnt(priest->minvent); if (pmoney > 0L) { /* Note: two bits is actually 25 cents. Hmm. */ pline("%s gives you %s for an ale.", Monnam(priest), (pmoney == 1L) ? "one bit" : "two bits"); money2u(priest, pmoney > 1L ? 2 : 1); #endif } else pline("%s preaches the virtues of poverty.", Monnam(priest)); exercise(A_WIS, TRUE); } else pline("%s is not interested.", Monnam(priest)); return; } else { long offer; pline("%s asks you for a contribution for the temple.", Monnam(priest)); if((offer = bribe(priest)) == 0) { verbalize("Thou shalt regret thine action!"); if(coaligned) adjalign(-1); } else if(offer < (u.ulevel * 200)) { #ifndef GOLDOBJ if(u.ugold > (offer * 2L)) verbalize("Cheapskate."); #else if(money_cnt(invent) > (offer * 2L)) verbalize("Cheapskate."); #endif else { verbalize("I thank thee for thy contribution."); /* give player some token */ exercise(A_WIS, TRUE); } } else if(offer < (u.ulevel * 400)) { verbalize("Thou art indeed a pious individual."); #ifndef GOLDOBJ if(u.ugold < (offer * 2L)) { #else if(money_cnt(invent) < (offer * 2L)) { #endif if (coaligned && u.ualign.record <= ALGN_SINNED) adjalign(1); verbalize("I bestow upon thee a blessing."); incr_itimeout(&HClairvoyant, rn1(500,500)); } } else if(offer < (u.ulevel * 600) && u.ublessed < 20 && (u.ublessed < 9 || !rn2(u.ublessed))) { verbalize("Thy devotion has been rewarded."); if (!(HProtection & INTRINSIC)) { HProtection |= FROMOUTSIDE; if (!u.ublessed) u.ublessed = rn1(3, 2); } else u.ublessed++; } else { verbalize("Thy selfless generosity is deeply appreciated."); #ifndef GOLDOBJ if(u.ugold < (offer * 2L) && coaligned) { #else if(money_cnt(invent) < (offer * 2L) && coaligned) { #endif if(strayed && (moves - u.ucleansed) > 5000L) { u.ualign.record = 0; /* cleanse thee */ u.ucleansed = moves; } else { adjalign(2); } } } } } struct monst * mk_roamer(ptr, alignment, x, y, peaceful) register struct permonst *ptr; aligntyp alignment; xchar x, y; boolean peaceful; { register struct monst *roamer; register boolean coaligned = (u.ualign.type == alignment); if (ptr != &mons[PM_ALIGNED_PRIEST] && ptr != &mons[PM_ANGEL]) return((struct monst *)0); if (MON_AT(x, y)) (void) rloc(m_at(x, y), FALSE); /* insurance */ if (!(roamer = makemon(ptr, x, y, NO_MM_FLAGS))) return((struct monst *)0); EPRI(roamer)->shralign = alignment; if (coaligned && !peaceful) EPRI(roamer)->renegade = TRUE; /* roamer->ispriest == FALSE naturally */ roamer->isminion = TRUE; /* borrowing this bit */ roamer->mtrapseen = ~0; /* traps are known */ roamer->mpeaceful = peaceful; roamer->msleeping = 0; set_malign(roamer); /* peaceful may have changed */ /* MORE TO COME */ return(roamer); } void reset_hostility(roamer) register struct monst *roamer; { if(!(roamer->isminion && (roamer->data == &mons[PM_ALIGNED_PRIEST] || roamer->data == &mons[PM_ANGEL]))) return; if(EPRI(roamer)->shralign != u.ualign.type) { roamer->mpeaceful = roamer->mtame = 0; set_malign(roamer); } newsym(roamer->mx, roamer->my); } boolean in_your_sanctuary(mon, x, y) struct monst *mon; /* if non-null, overrides */ xchar x, y; { register char roomno; register struct monst *priest; if (mon) { if (is_minion(mon->data) || is_rider(mon->data)) return FALSE; x = mon->mx, y = mon->my; } if (u.ualign.record <= ALGN_SINNED) /* sinned or worse */ return FALSE; if ((roomno = temple_occupied(u.urooms)) == 0 || roomno != *in_rooms(x, y, TEMPLE)) return FALSE; if ((priest = findpriest(roomno)) == 0) return FALSE; return (boolean)(has_shrine(priest) && p_coaligned(priest) && priest->mpeaceful); } void ghod_hitsu(priest) /* when attacking "priest" in his temple */ struct monst *priest; { int x, y, ax, ay, roomno = (int)temple_occupied(u.urooms); struct mkroom *troom; if (!roomno || !has_shrine(priest)) return; ax = x = EPRI(priest)->shrpos.x; ay = y = EPRI(priest)->shrpos.y; troom = &rooms[roomno - ROOMOFFSET]; if((u.ux == x && u.uy == y) || !linedup(u.ux, u.uy, x, y)) { if(IS_DOOR(levl[u.ux][u.uy].typ)) { if(u.ux == troom->lx - 1) { x = troom->hx; y = u.uy; } else if(u.ux == troom->hx + 1) { x = troom->lx; y = u.uy; } else if(u.uy == troom->ly - 1) { x = u.ux; y = troom->hy; } else if(u.uy == troom->hy + 1) { x = u.ux; y = troom->ly; } } else { switch(rn2(4)) { case 0: x = u.ux; y = troom->ly; break; case 1: x = u.ux; y = troom->hy; break; case 2: x = troom->lx; y = u.uy; break; default: x = troom->hx; y = u.uy; break; } } if(!linedup(u.ux, u.uy, x, y)) return; } switch(rn2(3)) { case 0: pline("%s roars in anger: \"Thou shalt suffer!\"", a_gname_at(ax, ay)); break; case 1: pline("%s voice booms: \"How darest thou harm my servant!\"", s_suffix(a_gname_at(ax, ay))); break; default: pline("%s roars: \"Thou dost profane my shrine!\"", a_gname_at(ax, ay)); break; } buzz(-10-(AD_ELEC-1), 6, x, y, sgn(tbx), sgn(tby)); /* bolt of lightning */ exercise(A_WIS, FALSE); } void angry_priest() { register struct monst *priest; struct rm *lev; if ((priest = findpriest(temple_occupied(u.urooms))) != 0) { wakeup(priest); /* * If the altar has been destroyed or converted, let the * priest run loose. * (When it's just a conversion and there happens to be * a fresh corpse nearby, the priest ought to have an * opportunity to try converting it back; maybe someday...) */ lev = &levl[EPRI(priest)->shrpos.x][EPRI(priest)->shrpos.y]; if (!IS_ALTAR(lev->typ) || ((aligntyp)Amask2align(lev->altarmask & AM_MASK) != EPRI(priest)->shralign)) { priest->ispriest = 0; /* now a roamer */ priest->isminion = 1; /* but still aligned */ /* this overloads the `shroom' field, which is now clobbered */ EPRI(priest)->renegade = 0; } } } /* * When saving bones, find priests that aren't on their shrine level, * and remove them. This avoids big problems when restoring bones. */ void clearpriests() { register struct monst *mtmp, *mtmp2; for(mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (!DEADMONSTER(mtmp) && mtmp->ispriest && !on_level(&(EPRI(mtmp)->shrlevel), &u.uz)) mongone(mtmp); } } /* munge priest-specific structure when restoring -dlc */ void restpriest(mtmp, ghostly) register struct monst *mtmp; boolean ghostly; { if(u.uz.dlevel) { if (ghostly) assign_level(&(EPRI(mtmp)->shrlevel), &u.uz); } } #endif /* OVLB */ /*priest.c*/ nethack-3.4.3/src/quest.c0100644000000000000000000002361107764735041013751 0ustar rootroot/* SCCS Id: @(#)quest.c 3.4 2000/05/05 */ /* Copyright 1991, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* quest dungeon branch routines. */ #include "quest.h" #include "qtext.h" #define Not_firsttime (on_level(&u.uz0, &u.uz)) #define Qstat(x) (quest_status.x) STATIC_DCL void NDECL(on_start); STATIC_DCL void NDECL(on_locate); STATIC_DCL void NDECL(on_goal); STATIC_DCL boolean NDECL(not_capable); STATIC_DCL int FDECL(is_pure, (BOOLEAN_P)); STATIC_DCL void FDECL(expulsion, (BOOLEAN_P)); STATIC_DCL void NDECL(chat_with_leader); STATIC_DCL void NDECL(chat_with_nemesis); STATIC_DCL void NDECL(chat_with_guardian); STATIC_DCL void FDECL(prisoner_speaks, (struct monst *)); STATIC_OVL void on_start() { if(!Qstat(first_start)) { qt_pager(QT_FIRSTTIME); Qstat(first_start) = TRUE; } else if((u.uz0.dnum != u.uz.dnum) || (u.uz0.dlevel < u.uz.dlevel)) { if(Qstat(not_ready) <= 2) qt_pager(QT_NEXTTIME); else qt_pager(QT_OTHERTIME); } } STATIC_OVL void on_locate() { if(!Qstat(first_locate)) { qt_pager(QT_FIRSTLOCATE); Qstat(first_locate) = TRUE; } else if(u.uz0.dlevel < u.uz.dlevel && !Qstat(killed_nemesis)) qt_pager(QT_NEXTLOCATE); } STATIC_OVL void on_goal() { if (Qstat(killed_nemesis)) { return; } else if (!Qstat(made_goal)) { qt_pager(QT_FIRSTGOAL); Qstat(made_goal) = 1; } else { qt_pager(QT_NEXTGOAL); if(Qstat(made_goal) < 7) Qstat(made_goal)++; } } void onquest() { if(u.uevent.qcompleted || Not_firsttime) return; if(!Is_special(&u.uz)) return; if(Is_qstart(&u.uz)) on_start(); else if(Is_qlocate(&u.uz) && u.uz.dlevel > u.uz0.dlevel) on_locate(); else if(Is_nemesis(&u.uz)) on_goal(); return; } void nemdead() { if(!Qstat(killed_nemesis)) { Qstat(killed_nemesis) = TRUE; qt_pager(QT_KILLEDNEM); } } void artitouch() { if(!Qstat(touched_artifact)) { Qstat(touched_artifact) = TRUE; qt_pager(QT_GOTIT); exercise(A_WIS, TRUE); } } /* external hook for do.c (level change check) */ boolean ok_to_quest() { return((boolean)((Qstat(got_quest) || Qstat(got_thanks))) && (is_pure(FALSE) > 0)); } STATIC_OVL boolean not_capable() { return((boolean)(u.ulevel < MIN_QUEST_LEVEL)); } STATIC_OVL int is_pure(talk) boolean talk; { int purity; aligntyp original_alignment = u.ualignbase[A_ORIGINAL]; #ifdef WIZARD if (wizard && talk) { if (u.ualign.type != original_alignment) { You("are currently %s instead of %s.", align_str(u.ualign.type), align_str(original_alignment)); } else if (u.ualignbase[A_CURRENT] != original_alignment) { You("have converted."); } else if (u.ualign.record < MIN_QUEST_ALIGN) { You("are currently %d and require %d.", u.ualign.record, MIN_QUEST_ALIGN); if (yn_function("adjust?", (char *)0, 'y') == 'y') u.ualign.record = MIN_QUEST_ALIGN; } } #endif purity = (u.ualign.record >= MIN_QUEST_ALIGN && u.ualign.type == original_alignment && u.ualignbase[A_CURRENT] == original_alignment) ? 1 : (u.ualignbase[A_CURRENT] != original_alignment) ? -1 : 0; return purity; } /* * Expell the player to the stairs on the parent of the quest dungeon. * * This assumes that the hero is currently _in_ the quest dungeon and that * there is a single branch to and from it. */ STATIC_OVL void expulsion(seal) boolean seal; { branch *br; d_level *dest; struct trap *t; int portal_flag; br = dungeon_branch("The Quest"); dest = (br->end1.dnum == u.uz.dnum) ? &br->end2 : &br->end1; portal_flag = u.uevent.qexpelled ? 0 : /* returned via artifact? */ !seal ? 1 : -1; schedule_goto(dest, FALSE, FALSE, portal_flag, (char *)0, (char *)0); if (seal) { /* remove the portal to the quest - sealing it off */ int reexpelled = u.uevent.qexpelled; u.uevent.qexpelled = 1; /* Delete the near portal now; the far (main dungeon side) portal will be deleted as part of arrival on that level. If monster movement is in progress, any who haven't moved yet will now miss out on a chance to wander through it... */ for (t = ftrap; t; t = t->ntrap) if (t->ttyp == MAGIC_PORTAL) break; if (t) deltrap(t); /* (display might be briefly out of sync) */ else if (!reexpelled) impossible("quest portal already gone?"); } } /* Either you've returned to quest leader while carrying the quest artifact or you've just thrown it to/at him or her. If quest completion text hasn't been given yet, give it now. Otherwise give another message about the character keeping the artifact and using the magic portal to return to the dungeon. */ void finish_quest(obj) struct obj *obj; /* quest artifact; possibly null if carrying Amulet */ { struct obj *otmp; if (u.uhave.amulet) { /* unlikely but not impossible */ qt_pager(QT_HASAMULET); /* leader IDs the real amulet but ignores any fakes */ if ((otmp = carrying(AMULET_OF_YENDOR)) != 0) fully_identify_obj(otmp); } else { qt_pager(!Qstat(got_thanks) ? QT_OFFEREDIT : QT_OFFEREDIT2); /* should have obtained bell during quest; if not, suggest returning for it now */ if ((otmp = carrying(BELL_OF_OPENING)) == 0) com_pager(5); } Qstat(got_thanks) = TRUE; if (obj) { u.uevent.qcompleted = 1; /* you did it! */ /* behave as if leader imparts sufficient info about the quest artifact */ fully_identify_obj(obj); update_inventory(); } } STATIC_OVL void chat_with_leader() { /* Rule 0: Cheater checks. */ if(u.uhave.questart && !Qstat(met_nemesis)) Qstat(cheater) = TRUE; /* It is possible for you to get the amulet without completing * the quest. If so, try to induce the player to quest. */ if(Qstat(got_thanks)) { /* Rule 1: You've gone back with/without the amulet. */ if(u.uhave.amulet) finish_quest((struct obj *)0); /* Rule 2: You've gone back before going for the amulet. */ else qt_pager(QT_POSTHANKS); } /* Rule 3: You've got the artifact and are back to return it. */ else if(u.uhave.questart) { struct obj *otmp; for (otmp = invent; otmp; otmp = otmp->nobj) if (is_quest_artifact(otmp)) break; finish_quest(otmp); /* Rule 4: You haven't got the artifact yet. */ } else if(Qstat(got_quest)) { qt_pager(rn1(10, QT_ENCOURAGE)); /* Rule 5: You aren't yet acceptable - or are you? */ } else { if(!Qstat(met_leader)) { qt_pager(QT_FIRSTLEADER); Qstat(met_leader) = TRUE; Qstat(not_ready) = 0; } else qt_pager(QT_NEXTLEADER); /* the quest leader might have passed through the portal into the regular dungeon; none of the remaining make sense there */ if (!on_level(&u.uz, &qstart_level)) return; if(not_capable()) { qt_pager(QT_BADLEVEL); exercise(A_WIS, TRUE); expulsion(FALSE); } else if(is_pure(TRUE) < 0) { com_pager(QT_BANISHED); expulsion(TRUE); } else if(is_pure(TRUE) == 0) { qt_pager(QT_BADALIGN); if(Qstat(not_ready) == MAX_QUEST_TRIES) { qt_pager(QT_LASTLEADER); expulsion(TRUE); } else { Qstat(not_ready)++; exercise(A_WIS, TRUE); expulsion(FALSE); } } else { /* You are worthy! */ qt_pager(QT_ASSIGNQUEST); exercise(A_WIS, TRUE); Qstat(got_quest) = TRUE; } } } void leader_speaks(mtmp) register struct monst *mtmp; { /* maybe you attacked leader? */ if(!mtmp->mpeaceful) { Qstat(pissed_off) = TRUE; mtmp->mstrategy &= ~STRAT_WAITMASK; /* end the inaction */ } /* the quest leader might have passed through the portal into the regular dungeon; if so, mustn't perform "backwards expulsion" */ if (!on_level(&u.uz, &qstart_level)) return; if(Qstat(pissed_off)) { qt_pager(QT_LASTLEADER); expulsion(TRUE); } else chat_with_leader(); } STATIC_OVL void chat_with_nemesis() { /* The nemesis will do most of the talking, but... */ qt_pager(rn1(10, QT_DISCOURAGE)); if(!Qstat(met_nemesis)) Qstat(met_nemesis++); } void nemesis_speaks() { if(!Qstat(in_battle)) { if(u.uhave.questart) qt_pager(QT_NEMWANTSIT); else if(Qstat(made_goal) == 1 || !Qstat(met_nemesis)) qt_pager(QT_FIRSTNEMESIS); else if(Qstat(made_goal) < 4) qt_pager(QT_NEXTNEMESIS); else if(Qstat(made_goal) < 7) qt_pager(QT_OTHERNEMESIS); else if(!rn2(5)) qt_pager(rn1(10, QT_DISCOURAGE)); if(Qstat(made_goal) < 7) Qstat(made_goal)++; Qstat(met_nemesis) = TRUE; } else /* he will spit out random maledictions */ if(!rn2(5)) qt_pager(rn1(10, QT_DISCOURAGE)); } STATIC_OVL void chat_with_guardian() { /* These guys/gals really don't have much to say... */ if (u.uhave.questart && Qstat(killed_nemesis)) qt_pager(rn1(5, QT_GUARDTALK2)); else qt_pager(rn1(5, QT_GUARDTALK)); } STATIC_OVL void prisoner_speaks (mtmp) register struct monst *mtmp; { if (mtmp->data == &mons[PM_PRISONER] && (mtmp->mstrategy & STRAT_WAITMASK)) { /* Awaken the prisoner */ if (canseemon(mtmp)) pline("%s speaks:", Monnam(mtmp)); verbalize("I'm finally free!"); mtmp->mstrategy &= ~STRAT_WAITMASK; mtmp->mpeaceful = 1; /* Your god is happy... */ adjalign(3); /* ...But the guards are not */ (void) angry_guards(FALSE); } return; } void quest_chat(mtmp) register struct monst *mtmp; { if (mtmp->m_id == Qstat(leader_m_id)) { chat_with_leader(); return; } switch(mtmp->data->msound) { case MS_NEMESIS: chat_with_nemesis(); break; case MS_GUARDIAN: chat_with_guardian(); break; default: impossible("quest_chat: Unknown quest character %s.", mon_nam(mtmp)); } } void quest_talk(mtmp) register struct monst *mtmp; { if (mtmp->m_id == Qstat(leader_m_id)) { leader_speaks(mtmp); return; } switch(mtmp->data->msound) { case MS_NEMESIS: nemesis_speaks(); break; case MS_DJINNI: prisoner_speaks(mtmp); break; default: break; } } void quest_stat_check(mtmp) struct monst *mtmp; { if(mtmp->data->msound == MS_NEMESIS) Qstat(in_battle) = (mtmp->mcanmove && !mtmp->msleeping && monnear(mtmp, u.ux, u.uy)); } /*quest.c*/ nethack-3.4.3/src/questpgr.c0100644000000000000000000002323707764735041014466 0ustar rootroot/* SCCS Id: @(#)questpgr.c 3.4 2000/05/05 */ /* Copyright 1991, M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" /* quest-specific pager routines. */ #include "qtext.h" #define QTEXT_FILE "quest.dat" /* #define DEBUG */ /* uncomment for debugging */ static void FDECL(Fread, (genericptr_t,int,int,dlb *)); STATIC_DCL struct qtmsg * FDECL(construct_qtlist, (long)); STATIC_DCL const char * NDECL(intermed); STATIC_DCL const char * NDECL(neminame); STATIC_DCL const char * NDECL(guardname); STATIC_DCL const char * NDECL(homebase); STATIC_DCL struct qtmsg * FDECL(msg_in, (struct qtmsg *,int)); STATIC_DCL void FDECL(convert_arg, (CHAR_P)); STATIC_DCL void NDECL(convert_line); STATIC_DCL void FDECL(deliver_by_pline, (struct qtmsg *)); STATIC_DCL void FDECL(deliver_by_window, (struct qtmsg *,int)); static char in_line[80], cvt_buf[64], out_line[128]; static struct qtlists qt_list; static dlb *msg_file; /* used by ldrname() and neminame(), then copied into cvt_buf */ static char nambuf[sizeof cvt_buf]; #ifdef DEBUG static void NDECL(dump_qtlist); static void dump_qtlist() /* dump the character msg list to check appearance */ { struct qtmsg *msg; long size; for (msg = qt_list.chrole; msg->msgnum > 0; msg++) { pline("msgnum %d: delivery %c", msg->msgnum, msg->delivery); more(); (void) dlb_fseek(msg_file, msg->offset, SEEK_SET); deliver_by_window(msg, NHW_TEXT); } } #endif /* DEBUG */ static void Fread(ptr, size, nitems, stream) genericptr_t ptr; int size, nitems; dlb *stream; { int cnt; if ((cnt = dlb_fread(ptr, size, nitems, stream)) != nitems) { panic("PREMATURE EOF ON QUEST TEXT FILE! Expected %d bytes, got %d", (size * nitems), (size * cnt)); } } STATIC_OVL struct qtmsg * construct_qtlist(hdr_offset) long hdr_offset; { struct qtmsg *msg_list; int n_msgs; (void) dlb_fseek(msg_file, hdr_offset, SEEK_SET); Fread(&n_msgs, sizeof(int), 1, msg_file); msg_list = (struct qtmsg *) alloc((unsigned)(n_msgs+1)*sizeof(struct qtmsg)); /* * Load up the list. */ Fread((genericptr_t)msg_list, n_msgs*sizeof(struct qtmsg), 1, msg_file); msg_list[n_msgs].msgnum = -1; return(msg_list); } void load_qtlist() { int n_classes, i; char qt_classes[N_HDR][LEN_HDR]; long qt_offsets[N_HDR]; msg_file = dlb_fopen(QTEXT_FILE, RDBMODE); if (!msg_file) panic("CANNOT OPEN QUEST TEXT FILE %s.", QTEXT_FILE); /* * Read in the number of classes, then the ID's & offsets for * each header. */ Fread(&n_classes, sizeof(int), 1, msg_file); Fread(&qt_classes[0][0], sizeof(char)*LEN_HDR, n_classes, msg_file); Fread(qt_offsets, sizeof(long), n_classes, msg_file); /* * Now construct the message lists for quick reference later * on when we are actually paging the messages out. */ qt_list.common = qt_list.chrole = (struct qtmsg *)0; for (i = 0; i < n_classes; i++) { if (!strncmp(COMMON_ID, qt_classes[i], LEN_HDR)) qt_list.common = construct_qtlist(qt_offsets[i]); else if (!strncmp(urole.filecode, qt_classes[i], LEN_HDR)) qt_list.chrole = construct_qtlist(qt_offsets[i]); #if 0 /* UNUSED but available */ else if (!strncmp(urace.filecode, qt_classes[i], LEN_HDR)) qt_list.chrace = construct_qtlist(qt_offsets[i]); #endif } if (!qt_list.common || !qt_list.chrole) impossible("load_qtlist: cannot load quest text."); #ifdef DEBUG dump_qtlist(); #endif return; /* no ***DON'T*** close the msg_file */ } /* called at program exit */ void unload_qtlist() { if (msg_file) (void) dlb_fclose(msg_file), msg_file = 0; if (qt_list.common) free((genericptr_t) qt_list.common), qt_list.common = 0; if (qt_list.chrole) free((genericptr_t) qt_list.chrole), qt_list.chrole = 0; return; } short quest_info(typ) int typ; { switch (typ) { case 0: return (urole.questarti); case MS_LEADER: return (urole.ldrnum); case MS_NEMESIS: return (urole.neminum); case MS_GUARDIAN: return (urole.guardnum); default: impossible("quest_info(%d)", typ); } return 0; } const char * ldrname() /* return your role leader's name */ { int i = urole.ldrnum; Sprintf(nambuf, "%s%s", type_is_pname(&mons[i]) ? "" : "the ", mons[i].mname); return nambuf; } STATIC_OVL const char * intermed() /* return your intermediate target string */ { return (urole.intermed); } boolean is_quest_artifact(otmp) struct obj *otmp; { return((boolean)(otmp->oartifact == urole.questarti)); } STATIC_OVL const char * neminame() /* return your role nemesis' name */ { int i = urole.neminum; Sprintf(nambuf, "%s%s", type_is_pname(&mons[i]) ? "" : "the ", mons[i].mname); return nambuf; } STATIC_OVL const char * guardname() /* return your role leader's guard monster name */ { int i = urole.guardnum; return(mons[i].mname); } STATIC_OVL const char * homebase() /* return your role leader's location */ { return(urole.homebase); } STATIC_OVL struct qtmsg * msg_in(qtm_list, msgnum) struct qtmsg *qtm_list; int msgnum; { struct qtmsg *qt_msg; for (qt_msg = qtm_list; qt_msg->msgnum > 0; qt_msg++) if (qt_msg->msgnum == msgnum) return(qt_msg); return((struct qtmsg *)0); } STATIC_OVL void convert_arg(c) char c; { register const char *str; switch (c) { case 'p': str = plname; break; case 'c': str = (flags.female && urole.name.f) ? urole.name.f : urole.name.m; break; case 'r': str = rank_of(u.ulevel, Role_switch, flags.female); break; case 'R': str = rank_of(MIN_QUEST_LEVEL, Role_switch, flags.female); break; case 's': str = (flags.female) ? "sister" : "brother"; break; case 'S': str = (flags.female) ? "daughter" : "son"; break; case 'l': str = ldrname(); break; case 'i': str = intermed(); break; case 'o': str = the(artiname(urole.questarti)); break; case 'n': str = neminame(); break; case 'g': str = guardname(); break; case 'G': str = align_gtitle(u.ualignbase[A_ORIGINAL]); break; case 'H': str = homebase(); break; case 'a': str = align_str(u.ualignbase[A_ORIGINAL]); break; case 'A': str = align_str(u.ualign.type); break; case 'd': str = align_gname(u.ualignbase[A_ORIGINAL]); break; case 'D': str = align_gname(A_LAWFUL); break; case 'C': str = "chaotic"; break; case 'N': str = "neutral"; break; case 'L': str = "lawful"; break; case 'x': str = Blind ? "sense" : "see"; break; case 'Z': str = dungeons[0].dname; break; case '%': str = "%"; break; default: str = ""; break; } Strcpy(cvt_buf, str); } STATIC_OVL void convert_line() { char *c, *cc; char xbuf[BUFSZ]; cc = out_line; for (c = xcrypt(in_line, xbuf); *c; c++) { *cc = 0; switch(*c) { case '\r': case '\n': *(++cc) = 0; return; case '%': if (*(c+1)) { convert_arg(*(++c)); switch (*(++c)) { /* insert "a"/"an" prefix */ case 'A': Strcat(cc, An(cvt_buf)); cc += strlen(cc); continue; /* for */ case 'a': Strcat(cc, an(cvt_buf)); cc += strlen(cc); continue; /* for */ /* capitalize */ case 'C': cvt_buf[0] = highc(cvt_buf[0]); break; /* pluralize */ case 'P': cvt_buf[0] = highc(cvt_buf[0]); case 'p': Strcpy(cvt_buf, makeplural(cvt_buf)); break; /* append possessive suffix */ case 'S': cvt_buf[0] = highc(cvt_buf[0]); case 's': Strcpy(cvt_buf, s_suffix(cvt_buf)); break; /* strip any "the" prefix */ case 't': if (!strncmpi(cvt_buf, "the ", 4)) { Strcat(cc, &cvt_buf[4]); cc += strlen(cc); continue; /* for */ } break; default: --c; /* undo switch increment */ break; } Strcat(cc, cvt_buf); cc += strlen(cvt_buf); break; } /* else fall through */ default: *cc++ = *c; break; } } if (cc >= out_line + sizeof out_line) panic("convert_line: overflow"); *cc = 0; return; } STATIC_OVL void deliver_by_pline(qt_msg) struct qtmsg *qt_msg; { long size; for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) { (void) dlb_fgets(in_line, 80, msg_file); convert_line(); pline(out_line); } } STATIC_OVL void deliver_by_window(qt_msg, how) struct qtmsg *qt_msg; int how; { long size; winid datawin = create_nhwindow(how); for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) { (void) dlb_fgets(in_line, 80, msg_file); convert_line(); putstr(datawin, 0, out_line); } display_nhwindow(datawin, TRUE); destroy_nhwindow(datawin); } void com_pager(msgnum) int msgnum; { struct qtmsg *qt_msg; if (!(qt_msg = msg_in(qt_list.common, msgnum))) { impossible("com_pager: message %d not found.", msgnum); return; } (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET); if (qt_msg->delivery == 'p') deliver_by_pline(qt_msg); else if (msgnum == 1) deliver_by_window(qt_msg, NHW_MENU); else deliver_by_window(qt_msg, NHW_TEXT); return; } void qt_pager(msgnum) int msgnum; { struct qtmsg *qt_msg; if (!(qt_msg = msg_in(qt_list.chrole, msgnum))) { impossible("qt_pager: message %d not found.", msgnum); return; } (void) dlb_fseek(msg_file, qt_msg->offset, SEEK_SET); if (qt_msg->delivery == 'p' && strcmp(windowprocs.name, "X11")) deliver_by_pline(qt_msg); else deliver_by_window(qt_msg, NHW_TEXT); return; } struct permonst * qt_montype() { int qpm; if (rn2(5)) { qpm = urole.enemy1num; if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD)) return (&mons[qpm]); return (mkclass(urole.enemy1sym, 0)); } qpm = urole.enemy2num; if (qpm != NON_PM && rn2(5) && !(mvitals[qpm].mvflags & G_GENOD)) return (&mons[qpm]); return (mkclass(urole.enemy2sym, 0)); } /*questpgr.c*/ nethack-3.4.3/src/read.c0100644000000000000000000014672107764735041013533 0ustar rootroot/* SCCS Id: @(#)read.c 3.4 2003/10/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* KMH -- Copied from pray.c; this really belongs in a header file */ #define DEVOUT 14 #define STRIDENT 4 #define Your_Own_Role(mndx) \ ((mndx) == urole.malenum || \ (urole.femalenum != NON_PM && (mndx) == urole.femalenum)) #define Your_Own_Race(mndx) \ ((mndx) == urace.malenum || \ (urace.femalenum != NON_PM && (mndx) == urace.femalenum)) #ifdef OVLB boolean known; static NEARDATA const char readable[] = { ALL_CLASSES, SCROLL_CLASS, SPBOOK_CLASS, 0 }; static const char all_count[] = { ALLOW_COUNT, ALL_CLASSES, 0 }; static void FDECL(wand_explode, (struct obj *)); static void NDECL(do_class_genocide); static void FDECL(stripspe,(struct obj *)); static void FDECL(p_glow1,(struct obj *)); static void FDECL(p_glow2,(struct obj *,const char *)); static void FDECL(randomize,(int *, int)); static void FDECL(forget_single_object, (int)); static void FDECL(forget, (int)); static void FDECL(maybe_tame, (struct monst *,struct obj *)); STATIC_PTR void FDECL(set_lit, (int,int,genericptr_t)); int doread() { register struct obj *scroll; register boolean confused; known = FALSE; if(check_capacity((char *)0)) return (0); scroll = getobj(readable, "read"); if(!scroll) return(0); /* outrumor has its own blindness check */ if(scroll->otyp == FORTUNE_COOKIE) { if(flags.verbose) You("break up the cookie and throw away the pieces."); outrumor(bcsign(scroll), BY_COOKIE); if (!Blind) u.uconduct.literate++; useup(scroll); return(1); #ifdef TOURIST } else if (scroll->otyp == T_SHIRT) { static const char *shirt_msgs[] = { /* Scott Bigham */ "I explored the Dungeons of Doom and all I got was this lousy T-shirt!", "Is that Mjollnir in your pocket or are you just happy to see me?", "It's not the size of your sword, it's how #enhance'd you are with it.", "Madame Elvira's House O' Succubi Lifetime Customer", "Madame Elvira's House O' Succubi Employee of the Month", "Ludios Vault Guards Do It In Small, Dark Rooms", "Yendor Military Soldiers Do It In Large Groups", "I survived Yendor Military Boot Camp", "Ludios Accounting School Intra-Mural Lacrosse Team", "Oracle(TM) Fountains 10th Annual Wet T-Shirt Contest", "Hey, black dragon! Disintegrate THIS!", "I'm With Stupid -->", "Don't blame me, I voted for Izchak!", "Don't Panic", /* HHGTTG */ "Furinkan High School Athletic Dept.", /* Ranma 1/2 */ "Hel-LOOO, Nurse!", /* Animaniacs */ }; char buf[BUFSZ]; int erosion; if (Blind) { You_cant("feel any Braille writing."); return 0; } u.uconduct.literate++; if(flags.verbose) pline("It reads:"); Strcpy(buf, shirt_msgs[scroll->o_id % SIZE(shirt_msgs)]); erosion = greatest_erosion(scroll); if (erosion) wipeout_text(buf, (int)(strlen(buf) * erosion / (2*MAX_ERODE)), scroll->o_id ^ (unsigned)u.ubirthday); pline("\"%s\"", buf); return 1; #endif /* TOURIST */ } else if (scroll->oclass != SCROLL_CLASS && scroll->oclass != SPBOOK_CLASS) { pline(silly_thing_to, "read"); return(0); } else if (Blind) { const char *what = 0; if (scroll->oclass == SPBOOK_CLASS) what = "mystic runes"; else if (!scroll->dknown) what = "formula on the scroll"; if (what) { pline("Being blind, you cannot read the %s.", what); return(0); } } /* Actions required to win the game aren't counted towards conduct */ if (scroll->otyp != SPE_BOOK_OF_THE_DEAD && scroll->otyp != SPE_BLANK_PAPER && scroll->otyp != SCR_BLANK_PAPER) u.uconduct.literate++; confused = (Confusion != 0); #ifdef MAIL if (scroll->otyp == SCR_MAIL) confused = FALSE; #endif if(scroll->oclass == SPBOOK_CLASS) { return(study_book(scroll)); } scroll->in_use = TRUE; /* scroll, not spellbook, now being read */ if(scroll->otyp != SCR_BLANK_PAPER) { if(Blind) pline("As you %s the formula on it, the scroll disappears.", is_silent(youmonst.data) ? "cogitate" : "pronounce"); else pline("As you read the scroll, it disappears."); if(confused) { if (Hallucination) pline("Being so trippy, you screw up..."); else pline("Being confused, you mis%s the magic words...", is_silent(youmonst.data) ? "understand" : "pronounce"); } } if(!seffects(scroll)) { if(!objects[scroll->otyp].oc_name_known) { if(known) { makeknown(scroll->otyp); more_experienced(0,10); } else if(!objects[scroll->otyp].oc_uname) docall(scroll); } if(scroll->otyp != SCR_BLANK_PAPER) useup(scroll); else scroll->in_use = FALSE; } return(1); } static void stripspe(obj) register struct obj *obj; { if (obj->blessed) pline(nothing_happens); else { if (obj->spe > 0) { obj->spe = 0; if (obj->otyp == OIL_LAMP || obj->otyp == BRASS_LANTERN) obj->age = 0; Your("%s %s briefly.",xname(obj), otense(obj, "vibrate")); } else pline(nothing_happens); } } static void p_glow1(otmp) register struct obj *otmp; { Your("%s %s briefly.", xname(otmp), otense(otmp, Blind ? "vibrate" : "glow")); } static void p_glow2(otmp,color) register struct obj *otmp; register const char *color; { Your("%s %s%s%s for a moment.", xname(otmp), otense(otmp, Blind ? "vibrate" : "glow"), Blind ? "" : " ", Blind ? nul : hcolor(color)); } /* Is the object chargeable? For purposes of inventory display; it is */ /* possible to be able to charge things for which this returns FALSE. */ boolean is_chargeable(obj) struct obj *obj; { if (obj->oclass == WAND_CLASS) return TRUE; /* known && !uname is possible after amnesia/mind flayer */ if (obj->oclass == RING_CLASS) return (boolean)(objects[obj->otyp].oc_charged && (obj->known || objects[obj->otyp].oc_uname)); if (is_weptool(obj)) /* specific check before general tools */ return FALSE; if (obj->oclass == TOOL_CLASS) return (boolean)(objects[obj->otyp].oc_charged); return FALSE; /* why are weapons/armor considered charged anyway? */ } /* * recharge an object; curse_bless is -1 if the recharging implement * was cursed, +1 if blessed, 0 otherwise. */ void recharge(obj, curse_bless) struct obj *obj; int curse_bless; { register int n; boolean is_cursed, is_blessed; is_cursed = curse_bless < 0; is_blessed = curse_bless > 0; if (obj->oclass == WAND_CLASS) { /* undo any prior cancellation, even when is_cursed */ if (obj->spe == -1) obj->spe = 0; /* * Recharging might cause wands to explode. * v = number of previous recharges * v = percentage chance to explode on this attempt * v = cumulative odds for exploding * 0 : 0 0 * 1 : 0.29 0.29 * 2 : 2.33 2.62 * 3 : 7.87 10.28 * 4 : 18.66 27.02 * 5 : 36.44 53.62 * 6 : 62.97 82.83 * 7 : 100 100 */ n = (int)obj->recharged; if (n > 0 && (obj->otyp == WAN_WISHING || (n * n * n > rn2(7*7*7)))) { /* recharge_limit */ wand_explode(obj); return; } /* didn't explode, so increment the recharge count */ obj->recharged = (unsigned)(n + 1); /* now handle the actual recharging */ if (is_cursed) { stripspe(obj); } else { int lim = (obj->otyp == WAN_WISHING) ? 3 : (objects[obj->otyp].oc_dir != NODIR) ? 8 : 15; n = (lim == 3) ? 3 : rn1(5, lim + 1 - 5); if (!is_blessed) n = rnd(n); if (obj->spe < n) obj->spe = n; else obj->spe++; if (obj->otyp == WAN_WISHING && obj->spe > 3) { wand_explode(obj); return; } if (obj->spe >= lim) p_glow2(obj, NH_BLUE); else p_glow1(obj); } } else if (obj->oclass == RING_CLASS && objects[obj->otyp].oc_charged) { /* charging does not affect ring's curse/bless status */ int s = is_blessed ? rnd(3) : is_cursed ? -rnd(2) : 1; boolean is_on = (obj == uleft || obj == uright); /* destruction depends on current state, not adjustment */ if (obj->spe > rn2(7) || obj->spe <= -5) { Your("%s %s momentarily, then %s!", xname(obj), otense(obj,"pulsate"), otense(obj,"explode")); if (is_on) Ring_gone(obj); s = rnd(3 * abs(obj->spe)); /* amount of damage */ useup(obj); losehp(s, "exploding ring", KILLED_BY_AN); } else { long mask = is_on ? (obj == uleft ? LEFT_RING : RIGHT_RING) : 0L; Your("%s spins %sclockwise for a moment.", xname(obj), s < 0 ? "counter" : ""); /* cause attributes and/or properties to be updated */ if (is_on) Ring_off(obj); obj->spe += s; /* update the ring while it's off */ if (is_on) setworn(obj, mask), Ring_on(obj); /* oartifact: if a touch-sensitive artifact ring is ever created the above will need to be revised */ } } else if (obj->oclass == TOOL_CLASS) { int rechrg = (int)obj->recharged; if (objects[obj->otyp].oc_charged) { /* tools don't have a limit, but the counter used does */ if (rechrg < 7) /* recharge_limit */ obj->recharged++; } switch(obj->otyp) { case BELL_OF_OPENING: if (is_cursed) stripspe(obj); else if (is_blessed) obj->spe += rnd(3); else obj->spe += 1; if (obj->spe > 5) obj->spe = 5; break; case MAGIC_MARKER: case TINNING_KIT: #ifdef TOURIST case EXPENSIVE_CAMERA: #endif if (is_cursed) stripspe(obj); else if (rechrg && obj->otyp == MAGIC_MARKER) { /* previously recharged */ obj->recharged = 1; /* override increment done above */ if (obj->spe < 3) Your("marker seems permanently dried out."); else pline(nothing_happens); } else if (is_blessed) { n = rn1(16,15); /* 15..30 */ if (obj->spe + n <= 50) obj->spe = 50; else if (obj->spe + n <= 75) obj->spe = 75; else { int chrg = (int)obj->spe; if ((chrg + n) > 127) obj->spe = 127; else obj->spe += n; } p_glow2(obj, NH_BLUE); } else { n = rn1(11,10); /* 10..20 */ if (obj->spe + n <= 50) obj->spe = 50; else { int chrg = (int)obj->spe; if ((chrg + n) > 127) obj->spe = 127; else obj->spe += n; } p_glow2(obj, NH_WHITE); } break; case OIL_LAMP: case BRASS_LANTERN: if (is_cursed) { stripspe(obj); if (obj->lamplit) { if (!Blind) pline("%s out!", Tobjnam(obj, "go")); end_burn(obj, TRUE); } } else if (is_blessed) { obj->spe = 1; obj->age = 1500; p_glow2(obj, NH_BLUE); } else { obj->spe = 1; obj->age += 750; if (obj->age > 1500) obj->age = 1500; p_glow1(obj); } break; case CRYSTAL_BALL: if (is_cursed) stripspe(obj); else if (is_blessed) { obj->spe = 6; p_glow2(obj, NH_BLUE); } else { if (obj->spe < 5) { obj->spe++; p_glow1(obj); } else pline(nothing_happens); } break; case HORN_OF_PLENTY: case BAG_OF_TRICKS: case CAN_OF_GREASE: if (is_cursed) stripspe(obj); else if (is_blessed) { if (obj->spe <= 10) obj->spe += rn1(10, 6); else obj->spe += rn1(5, 6); if (obj->spe > 50) obj->spe = 50; p_glow2(obj, NH_BLUE); } else { obj->spe += rnd(5); if (obj->spe > 50) obj->spe = 50; p_glow1(obj); } break; case MAGIC_FLUTE: case MAGIC_HARP: case FROST_HORN: case FIRE_HORN: case DRUM_OF_EARTHQUAKE: if (is_cursed) { stripspe(obj); } else if (is_blessed) { obj->spe += d(2,4); if (obj->spe > 20) obj->spe = 20; p_glow2(obj, NH_BLUE); } else { obj->spe += rnd(4); if (obj->spe > 20) obj->spe = 20; p_glow1(obj); } break; default: goto not_chargable; /*NOTREACHED*/ break; } /* switch */ } else { not_chargable: You("have a feeling of loss."); } } /* Forget known information about this object class. */ static void forget_single_object(obj_id) int obj_id; { objects[obj_id].oc_name_known = 0; objects[obj_id].oc_pre_discovered = 0; /* a discovery when relearned */ if (objects[obj_id].oc_uname) { free((genericptr_t)objects[obj_id].oc_uname); objects[obj_id].oc_uname = 0; } undiscover_object(obj_id); /* after clearing oc_name_known */ /* clear & free object names from matching inventory items too? */ } #if 0 /* here if anyone wants it.... */ /* Forget everything known about a particular object class. */ static void forget_objclass(oclass) int oclass; { int i; for (i=bases[oclass]; i < NUM_OBJECTS && objects[i].oc_class==oclass; i++) forget_single_object(i); } #endif /* randomize the given list of numbers 0 <= i < count */ static void randomize(indices, count) int *indices; int count; { int i, iswap, temp; for (i = count - 1; i > 0; i--) { if ((iswap = rn2(i + 1)) == i) continue; temp = indices[i]; indices[i] = indices[iswap]; indices[iswap] = temp; } } /* Forget % of known objects. */ void forget_objects(percent) int percent; { int i, count; int indices[NUM_OBJECTS]; if (percent == 0) return; if (percent <= 0 || percent > 100) { impossible("forget_objects: bad percent %d", percent); return; } for (count = 0, i = 1; i < NUM_OBJECTS; i++) if (OBJ_DESCR(objects[i]) && (objects[i].oc_name_known || objects[i].oc_uname)) indices[count++] = i; randomize(indices, count); /* forget first % of randomized indices */ count = ((count * percent) + 50) / 100; for (i = 0; i < count; i++) forget_single_object(indices[i]); } /* Forget some or all of map (depends on parameters). */ void forget_map(howmuch) int howmuch; { register int zx, zy; if (In_sokoban(&u.uz)) return; known = TRUE; for(zx = 0; zx < COLNO; zx++) for(zy = 0; zy < ROWNO; zy++) if (howmuch & ALL_MAP || rn2(7)) { /* Zonk all memory of this location. */ levl[zx][zy].seenv = 0; levl[zx][zy].waslit = 0; levl[zx][zy].glyph = cmap_to_glyph(S_stone); } } /* Forget all traps on the level. */ void forget_traps() { register struct trap *trap; /* forget all traps (except the one the hero is in :-) */ for (trap = ftrap; trap; trap = trap->ntrap) if ((trap->tx != u.ux || trap->ty != u.uy) && (trap->ttyp != HOLE)) trap->tseen = 0; } /* * Forget given % of all levels that the hero has visited and not forgotten, * except this one. */ void forget_levels(percent) int percent; { int i, count; xchar maxl, this_lev; int indices[MAXLINFO]; if (percent == 0) return; if (percent <= 0 || percent > 100) { impossible("forget_levels: bad percent %d", percent); return; } this_lev = ledger_no(&u.uz); maxl = maxledgerno(); /* count & save indices of non-forgotten visited levels */ /* Sokoban levels are pre-mapped for the player, and should stay * so, or they become nearly impossible to solve. But try to * shift the forgetting elsewhere by fiddling with percent * instead of forgetting fewer levels. */ for (count = 0, i = 0; i <= maxl; i++) if ((level_info[i].flags & VISITED) && !(level_info[i].flags & FORGOTTEN) && i != this_lev) { if (ledger_to_dnum(i) == sokoban_dnum) percent += 2; else indices[count++] = i; } if (percent > 100) percent = 100; randomize(indices, count); /* forget first % of randomized indices */ count = ((count * percent) + 50) / 100; for (i = 0; i < count; i++) { level_info[indices[i]].flags |= FORGOTTEN; } } /* * Forget some things (e.g. after reading a scroll of amnesia). When called, * the following are always forgotten: * * - felt ball & chain * - traps * - part (6 out of 7) of the map * * Other things are subject to flags: * * howmuch & ALL_MAP = forget whole map * howmuch & ALL_SPELLS = forget all spells */ static void forget(howmuch) int howmuch; { if (Punished) u.bc_felt = 0; /* forget felt ball&chain */ forget_map(howmuch); forget_traps(); /* 1 in 3 chance of forgetting some levels */ if (!rn2(3)) forget_levels(rn2(25)); /* 1 in 3 chance of forgeting some objects */ if (!rn2(3)) forget_objects(rn2(25)); if (howmuch & ALL_SPELLS) losespells(); /* * Make sure that what was seen is restored correctly. To do this, * we need to go blind for an instant --- turn off the display, * then restart it. All this work is needed to correctly handle * walls which are stone on one side and wall on the other. Turning * off the seen bits above will make the wall revert to stone, but * there are cases where we don't want this to happen. The easiest * thing to do is to run it through the vision system again, which * is always correct. */ docrt(); /* this correctly will reset vision */ } /* monster is hit by scroll of taming's effect */ static void maybe_tame(mtmp, sobj) struct monst *mtmp; struct obj *sobj; { if (sobj->cursed) { setmangry(mtmp); } else { if (mtmp->isshk) make_happy_shk(mtmp, FALSE); else if (!resist(mtmp, sobj->oclass, 0, NOTELL)) (void) tamedog(mtmp, (struct obj *) 0); } } int seffects(sobj) register struct obj *sobj; { register int cval; register boolean confused = (Confusion != 0); register struct obj *otmp; if (objects[sobj->otyp].oc_magic) exercise(A_WIS, TRUE); /* just for trying */ switch(sobj->otyp) { #ifdef MAIL case SCR_MAIL: known = TRUE; if (sobj->spe) pline("This seems to be junk mail addressed to the finder of the Eye of Larn."); /* note to the puzzled: the game Larn actually sends you junk * mail if you win! */ else readmail(sobj); break; #endif case SCR_ENCHANT_ARMOR: { register schar s; boolean special_armor; boolean same_color; otmp = some_armor(&youmonst); if(!otmp) { strange_feeling(sobj, !Blind ? "Your skin glows then fades." : "Your skin feels warm for a moment."); exercise(A_CON, !sobj->cursed); exercise(A_STR, !sobj->cursed); return(1); } if(confused) { otmp->oerodeproof = !(sobj->cursed); if(Blind) { otmp->rknown = FALSE; Your("%s %s warm for a moment.", xname(otmp), otense(otmp, "feel")); } else { otmp->rknown = TRUE; Your("%s %s covered by a %s %s %s!", xname(otmp), otense(otmp, "are"), sobj->cursed ? "mottled" : "shimmering", hcolor(sobj->cursed ? NH_BLACK : NH_GOLDEN), sobj->cursed ? "glow" : (is_shield(otmp) ? "layer" : "shield")); } if (otmp->oerodeproof && (otmp->oeroded || otmp->oeroded2)) { otmp->oeroded = otmp->oeroded2 = 0; Your("%s %s as good as new!", xname(otmp), otense(otmp, Blind ? "feel" : "look")); } break; } /* elven armor vibrates warningly when enchanted beyond a limit */ special_armor = is_elven_armor(otmp) || (Role_if(PM_WIZARD) && otmp->otyp == CORNUTHAUM); if (sobj->cursed) same_color = (otmp->otyp == BLACK_DRAGON_SCALE_MAIL || otmp->otyp == BLACK_DRAGON_SCALES); else same_color = (otmp->otyp == SILVER_DRAGON_SCALE_MAIL || otmp->otyp == SILVER_DRAGON_SCALES || otmp->otyp == SHIELD_OF_REFLECTION); if (Blind) same_color = FALSE; /* KMH -- catch underflow */ s = sobj->cursed ? -otmp->spe : otmp->spe; if (s > (special_armor ? 5 : 3) && rn2(s)) { Your("%s violently %s%s%s for a while, then %s.", xname(otmp), otense(otmp, Blind ? "vibrate" : "glow"), (!Blind && !same_color) ? " " : nul, (Blind || same_color) ? nul : hcolor(sobj->cursed ? NH_BLACK : NH_SILVER), otense(otmp, "evaporate")); if(is_cloak(otmp)) (void) Cloak_off(); if(is_boots(otmp)) (void) Boots_off(); if(is_helmet(otmp)) (void) Helmet_off(); if(is_gloves(otmp)) (void) Gloves_off(); if(is_shield(otmp)) (void) Shield_off(); if(otmp == uarm) (void) Armor_gone(); useup(otmp); break; } s = sobj->cursed ? -1 : otmp->spe >= 9 ? (rn2(otmp->spe) == 0) : sobj->blessed ? rnd(3-otmp->spe/3) : 1; if (s >= 0 && otmp->otyp >= GRAY_DRAGON_SCALES && otmp->otyp <= YELLOW_DRAGON_SCALES) { /* dragon scales get turned into dragon scale mail */ Your("%s merges and hardens!", xname(otmp)); setworn((struct obj *)0, W_ARM); /* assumes same order */ otmp->otyp = GRAY_DRAGON_SCALE_MAIL + otmp->otyp - GRAY_DRAGON_SCALES; otmp->cursed = 0; if (sobj->blessed) { otmp->spe++; otmp->blessed = 1; } otmp->known = 1; setworn(otmp, W_ARM); break; } Your("%s %s%s%s%s for a %s.", xname(otmp), s == 0 ? "violently " : nul, otense(otmp, Blind ? "vibrate" : "glow"), (!Blind && !same_color) ? " " : nul, (Blind || same_color) ? nul : hcolor(sobj->cursed ? NH_BLACK : NH_SILVER), (s*s>1) ? "while" : "moment"); otmp->cursed = sobj->cursed; if (!otmp->blessed || sobj->cursed) otmp->blessed = sobj->blessed; if (s) { otmp->spe += s; adj_abon(otmp, s); known = otmp->known; } if ((otmp->spe > (special_armor ? 5 : 3)) && (special_armor || !rn2(7))) Your("%s suddenly %s %s.", xname(otmp), otense(otmp, "vibrate"), Blind ? "again" : "unexpectedly"); break; } case SCR_DESTROY_ARMOR: { otmp = some_armor(&youmonst); if(confused) { if(!otmp) { strange_feeling(sobj,"Your bones itch."); exercise(A_STR, FALSE); exercise(A_CON, FALSE); return(1); } otmp->oerodeproof = sobj->cursed; p_glow2(otmp, NH_PURPLE); break; } if(!sobj->cursed || !otmp || !otmp->cursed) { if(!destroy_arm(otmp)) { strange_feeling(sobj,"Your skin itches."); exercise(A_STR, FALSE); exercise(A_CON, FALSE); return(1); } else known = TRUE; } else { /* armor and scroll both cursed */ Your("%s %s.", xname(otmp), otense(otmp, "vibrate")); if (otmp->spe >= -6) otmp->spe--; make_stunned(HStun + rn1(10, 10), TRUE); } } break; case SCR_CONFUSE_MONSTER: case SPE_CONFUSE_MONSTER: if(youmonst.data->mlet != S_HUMAN || sobj->cursed) { if(!HConfusion) You_feel("confused."); make_confused(HConfusion + rnd(100),FALSE); } else if(confused) { if(!sobj->blessed) { Your("%s begin to %s%s.", makeplural(body_part(HAND)), Blind ? "tingle" : "glow ", Blind ? nul : hcolor(NH_PURPLE)); make_confused(HConfusion + rnd(100),FALSE); } else { pline("A %s%s surrounds your %s.", Blind ? nul : hcolor(NH_RED), Blind ? "faint buzz" : " glow", body_part(HEAD)); make_confused(0L,TRUE); } } else { if (!sobj->blessed) { Your("%s%s %s%s.", makeplural(body_part(HAND)), Blind ? "" : " begin to glow", Blind ? (const char *)"tingle" : hcolor(NH_RED), u.umconf ? " even more" : ""); u.umconf++; } else { if (Blind) Your("%s tingle %s sharply.", makeplural(body_part(HAND)), u.umconf ? "even more" : "very"); else Your("%s glow a%s brilliant %s.", makeplural(body_part(HAND)), u.umconf ? "n even more" : "", hcolor(NH_RED)); /* after a while, repeated uses become less effective */ if (u.umconf >= 40) u.umconf++; else u.umconf += rn1(8, 2); } } break; case SCR_SCARE_MONSTER: case SPE_CAUSE_FEAR: { register int ct = 0; register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if(cansee(mtmp->mx,mtmp->my)) { if(confused || sobj->cursed) { mtmp->mflee = mtmp->mfrozen = mtmp->msleeping = 0; mtmp->mcanmove = 1; } else if (! resist(mtmp, sobj->oclass, 0, NOTELL)) monflee(mtmp, 0, FALSE, FALSE); if(!mtmp->mtame) ct++; /* pets don't laugh at you */ } } if(!ct) You_hear("%s in the distance.", (confused || sobj->cursed) ? "sad wailing" : "maniacal laughter"); else if(sobj->otyp == SCR_SCARE_MONSTER) You_hear("%s close by.", (confused || sobj->cursed) ? "sad wailing" : "maniacal laughter"); break; } case SCR_BLANK_PAPER: if (Blind) You("don't remember there being any magic words on this scroll."); else pline("This scroll seems to be blank."); known = TRUE; break; case SCR_REMOVE_CURSE: case SPE_REMOVE_CURSE: { register struct obj *obj; if(confused) if (Hallucination) You_feel("the power of the Force against you!"); else You_feel("like you need some help."); else if (Hallucination) You_feel("in touch with the Universal Oneness."); else You_feel("like someone is helping you."); if (sobj->cursed) { pline_The("scroll disintegrates."); } else { for (obj = invent; obj; obj = obj->nobj) { long wornmask; #ifdef GOLDOBJ /* gold isn't subject to cursing and blessing */ if (obj->oclass == COIN_CLASS) continue; #endif wornmask = (obj->owornmask & ~(W_BALL|W_ART|W_ARTI)); if (wornmask && !sobj->blessed) { /* handle a couple of special cases; we don't allow auxiliary weapon slots to be used to artificially increase number of worn items */ if (obj == uswapwep) { if (!u.twoweap) wornmask = 0L; } else if (obj == uquiver) { if (obj->oclass == WEAPON_CLASS) { /* mergeable weapon test covers ammo, missiles, spears, daggers & knives */ if (!objects[obj->otyp].oc_merge) wornmask = 0L; } else if (obj->oclass == GEM_CLASS) { /* possibly ought to check whether alternate weapon is a sling... */ if (!uslinging()) wornmask = 0L; } else { /* weptools don't merge and aren't reasonable quivered weapons */ wornmask = 0L; } } } if (sobj->blessed || wornmask || obj->otyp == LOADSTONE || (obj->otyp == LEASH && obj->leashmon)) { if(confused) blessorcurse(obj, 2); else uncurse(obj); } } } if(Punished && !confused) unpunish(); update_inventory(); break; } case SCR_CREATE_MONSTER: case SPE_CREATE_MONSTER: if (create_critters(1 + ((confused || sobj->cursed) ? 12 : 0) + ((sobj->blessed || rn2(73)) ? 0 : rnd(4)), confused ? &mons[PM_ACID_BLOB] : (struct permonst *)0)) known = TRUE; /* no need to flush monsters; we ask for identification only if the * monsters are not visible */ break; case SCR_ENCHANT_WEAPON: if(uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep)) && confused) { /* oclass check added 10/25/86 GAN */ uwep->oerodeproof = !(sobj->cursed); if (Blind) { uwep->rknown = FALSE; Your("weapon feels warm for a moment."); } else { uwep->rknown = TRUE; Your("%s covered by a %s %s %s!", aobjnam(uwep, "are"), sobj->cursed ? "mottled" : "shimmering", hcolor(sobj->cursed ? NH_PURPLE : NH_GOLDEN), sobj->cursed ? "glow" : "shield"); } if (uwep->oerodeproof && (uwep->oeroded || uwep->oeroded2)) { uwep->oeroded = uwep->oeroded2 = 0; Your("%s as good as new!", aobjnam(uwep, Blind ? "feel" : "look")); } } else return !chwepon(sobj, sobj->cursed ? -1 : !uwep ? 1 : uwep->spe >= 9 ? (rn2(uwep->spe) == 0) : sobj->blessed ? rnd(3-uwep->spe/3) : 1); break; case SCR_TAMING: case SPE_CHARM_MONSTER: if (u.uswallow) { maybe_tame(u.ustuck, sobj); } else { int i, j, bd = confused ? 5 : 1; struct monst *mtmp; for (i = -bd; i <= bd; i++) for(j = -bd; j <= bd; j++) { if (!isok(u.ux + i, u.uy + j)) continue; if ((mtmp = m_at(u.ux + i, u.uy + j)) != 0) maybe_tame(mtmp, sobj); } } break; case SCR_GENOCIDE: You("have found a scroll of genocide!"); known = TRUE; if (sobj->blessed) do_class_genocide(); else do_genocide(!sobj->cursed | (2 * !!Confusion)); break; case SCR_LIGHT: if(!Blind) known = TRUE; litroom(!confused && !sobj->cursed, sobj); break; case SCR_TELEPORTATION: if(confused || sobj->cursed) level_tele(); else { if (sobj->blessed && !Teleport_control) { known = TRUE; if (yn("Do you wish to teleport?")=='n') break; } tele(); if(Teleport_control || !couldsee(u.ux0, u.uy0) || (distu(u.ux0, u.uy0) >= 16)) known = TRUE; } break; case SCR_GOLD_DETECTION: if (confused || sobj->cursed) return(trap_detect(sobj)); else return(gold_detect(sobj)); case SCR_FOOD_DETECTION: case SPE_DETECT_FOOD: if (food_detect(sobj)) return(1); /* nothing detected */ break; case SPE_IDENTIFY: cval = rn2(5); goto id; case SCR_IDENTIFY: /* known = TRUE; */ if(confused) You("identify this as an identify scroll."); else pline("This is an identify scroll."); if (sobj->blessed || (!sobj->cursed && !rn2(5))) { cval = rn2(5); /* Note: if rn2(5)==0, identify all items */ if (cval == 1 && sobj->blessed && Luck > 0) ++cval; } else cval = 1; if(!objects[sobj->otyp].oc_name_known) more_experienced(0,10); useup(sobj); makeknown(SCR_IDENTIFY); id: if(invent && !confused) { identify_pack(cval); } return(1); case SCR_CHARGING: if (confused) { You_feel("charged up!"); if (u.uen < u.uenmax) u.uen = u.uenmax; else u.uen = (u.uenmax += d(5,4)); flags.botl = 1; break; } known = TRUE; pline("This is a charging scroll."); otmp = getobj(all_count, "charge"); if (!otmp) break; recharge(otmp, sobj->cursed ? -1 : (sobj->blessed ? 1 : 0)); break; case SCR_MAGIC_MAPPING: if (level.flags.nommap) { Your("mind is filled with crazy lines!"); if (Hallucination) pline("Wow! Modern art."); else Your("%s spins in bewilderment.", body_part(HEAD)); make_confused(HConfusion + rnd(30), FALSE); break; } if (sobj->blessed) { register int x, y; for (x = 1; x < COLNO; x++) for (y = 0; y < ROWNO; y++) if (levl[x][y].typ == SDOOR) cvt_sdoor_to_door(&levl[x][y]); /* do_mapping() already reveals secret passages */ } known = TRUE; case SPE_MAGIC_MAPPING: if (level.flags.nommap) { Your("%s spins as %s blocks the spell!", body_part(HEAD), something); make_confused(HConfusion + rnd(30), FALSE); break; } pline("A map coalesces in your mind!"); cval = (sobj->cursed && !confused); if(cval) HConfusion = 1; /* to screw up map */ do_mapping(); if(cval) { HConfusion = 0; /* restore */ pline("Unfortunately, you can't grasp the details."); } break; case SCR_AMNESIA: known = TRUE; forget( (!sobj->blessed ? ALL_SPELLS : 0) | (!confused || sobj->cursed ? ALL_MAP : 0) ); if (Hallucination) /* Ommmmmm! */ Your("mind releases itself from mundane concerns."); else if (!strncmpi(plname, "Maud", 4)) pline("As your mind turns inward on itself, you forget everything else."); else if (rn2(2)) pline("Who was that Maud person anyway?"); else pline("Thinking of Maud you forget everything else."); exercise(A_WIS, FALSE); break; case SCR_FIRE: /* * Note: Modifications have been made as of 3.0 to allow for * some damage under all potential cases. */ cval = bcsign(sobj); if(!objects[sobj->otyp].oc_name_known) more_experienced(0,10); useup(sobj); makeknown(SCR_FIRE); if(confused) { if(Fire_resistance) { shieldeff(u.ux, u.uy); if(!Blind) pline("Oh, look, what a pretty fire in your %s.", makeplural(body_part(HAND))); else You_feel("a pleasant warmth in your %s.", makeplural(body_part(HAND))); } else { pline_The("scroll catches fire and you burn your %s.", makeplural(body_part(HAND))); losehp(1, "scroll of fire", KILLED_BY_AN); } return(1); } if (Underwater) pline_The("water around you vaporizes violently!"); else { pline_The("scroll erupts in a tower of flame!"); burn_away_slime(); } explode(u.ux, u.uy, 11, (2*(rn1(3, 3) + 2 * cval) + 1)/3, SCROLL_CLASS, EXPL_FIERY); return(1); case SCR_EARTH: /* TODO: handle steeds */ if ( #ifdef REINCARNATION !Is_rogue_level(&u.uz) && #endif (!In_endgame(&u.uz) || Is_earthlevel(&u.uz))) { register int x, y; /* Identify the scroll */ pline_The("%s rumbles %s you!", ceiling(u.ux,u.uy), sobj->blessed ? "around" : "above"); known = 1; if (In_sokoban(&u.uz)) change_luck(-1); /* Sokoban guilt */ /* Loop through the surrounding squares */ if (!sobj->cursed) for (x = u.ux-1; x <= u.ux+1; x++) { for (y = u.uy-1; y <= u.uy+1; y++) { /* Is this a suitable spot? */ if (isok(x, y) && !closed_door(x, y) && !IS_ROCK(levl[x][y].typ) && !IS_AIR(levl[x][y].typ) && (x != u.ux || y != u.uy)) { register struct obj *otmp2; register struct monst *mtmp; /* Make the object(s) */ otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE); if (!otmp2) continue; /* Shouldn't happen */ otmp2->quan = confused ? rn1(5,2) : 1; otmp2->owt = weight(otmp2); /* Find the monster here (won't be player) */ mtmp = m_at(x, y); if (mtmp && !amorphous(mtmp->data) && !passes_walls(mtmp->data) && !noncorporeal(mtmp->data) && !unsolid(mtmp->data)) { struct obj *helmet = which_armor(mtmp, W_ARMH); int mdmg; if (cansee(mtmp->mx, mtmp->my)) { pline("%s is hit by %s!", Monnam(mtmp), doname(otmp2)); if (mtmp->minvis && !canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); } mdmg = dmgval(otmp2, mtmp) * otmp2->quan; if (helmet) { if(is_metallic(helmet)) { if (canspotmon(mtmp)) pline("Fortunately, %s is wearing a hard helmet.", mon_nam(mtmp)); else if (flags.soundok) You_hear("a clanging sound."); if (mdmg > 2) mdmg = 2; } else { if (canspotmon(mtmp)) pline("%s's %s does not protect %s.", Monnam(mtmp), xname(helmet), mhim(mtmp)); } } mtmp->mhp -= mdmg; if (mtmp->mhp <= 0) xkilled(mtmp, 1); } /* Drop the rock/boulder to the floor */ if (!flooreffects(otmp2, x, y, "fall")) { place_object(otmp2, x, y); stackobj(otmp2); newsym(x, y); /* map the rock */ } } } } /* Attack the player */ if (!sobj->blessed) { int dmg; struct obj *otmp2; /* Okay, _you_ write this without repeating the code */ otmp2 = mksobj(confused ? ROCK : BOULDER, FALSE, FALSE); if (!otmp2) break; otmp2->quan = confused ? rn1(5,2) : 1; otmp2->owt = weight(otmp2); if (!amorphous(youmonst.data) && !Passes_walls && !noncorporeal(youmonst.data) && !unsolid(youmonst.data)) { You("are hit by %s!", doname(otmp2)); dmg = dmgval(otmp2, &youmonst) * otmp2->quan; if (uarmh && !sobj->cursed) { if(is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); if (dmg > 2) dmg = 2; } else if (flags.verbose) { Your("%s does not protect you.", xname(uarmh)); } } } else dmg = 0; /* Must be before the losehp(), for bones files */ if (!flooreffects(otmp2, u.ux, u.uy, "fall")) { place_object(otmp2, u.ux, u.uy); stackobj(otmp2); newsym(u.ux, u.uy); } if (dmg) losehp(dmg, "scroll of earth", KILLED_BY_AN); } } break; case SCR_PUNISHMENT: known = TRUE; if(confused || sobj->blessed) { You_feel("guilty."); break; } punish(sobj); break; case SCR_STINKING_CLOUD: { coord cc; You("have found a scroll of stinking cloud!"); known = TRUE; pline("Where do you want to center the cloud?"); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the desired position") < 0) { pline(Never_mind); return 0; } if (!cansee(cc.x, cc.y) || distu(cc.x, cc.y) >= 32) { You("smell rotten eggs."); return 0; } (void) create_gas_cloud(cc.x, cc.y, 3+bcsign(sobj), 8+4*bcsign(sobj)); break; } default: impossible("What weird effect is this? (%u)", sobj->otyp); } return(0); } static void wand_explode(obj) register struct obj *obj; { obj->in_use = TRUE; /* in case losehp() is fatal */ Your("%s vibrates violently, and explodes!",xname(obj)); nhbell(); losehp(rnd(2*(u.uhpmax+1)/3), "exploding wand", KILLED_BY_AN); useup(obj); exercise(A_STR, FALSE); } /* * Low-level lit-field update routine. */ STATIC_PTR void set_lit(x,y,val) int x, y; genericptr_t val; { if (val) levl[x][y].lit = 1; else { levl[x][y].lit = 0; snuff_light_source(x, y); } } void litroom(on,obj) register boolean on; struct obj *obj; { char is_lit; /* value is irrelevant; we use its address as a `not null' flag for set_lit() */ /* first produce the text (provided you're not blind) */ if(!on) { register struct obj *otmp; if (!Blind) { if(u.uswallow) { pline("It seems even darker in here than before."); return; } if (uwep && artifact_light(uwep) && uwep->lamplit) pline("Suddenly, the only light left comes from %s!", the(xname(uwep))); else You("are surrounded by darkness!"); } /* the magic douses lamps, et al, too */ for(otmp = invent; otmp; otmp = otmp->nobj) if (otmp->lamplit) (void) snuff_lit(otmp); if (Blind) goto do_it; } else { if (Blind) goto do_it; if(u.uswallow){ if (is_animal(u.ustuck->data)) pline("%s %s is lit.", s_suffix(Monnam(u.ustuck)), mbodypart(u.ustuck, STOMACH)); else if (is_whirly(u.ustuck->data)) pline("%s shines briefly.", Monnam(u.ustuck)); else pline("%s glistens.", Monnam(u.ustuck)); return; } pline("A lit field surrounds you!"); } do_it: /* No-op in water - can only see the adjacent squares and that's it! */ if (Underwater || Is_waterlevel(&u.uz)) return; /* * If we are darkening the room and the hero is punished but not * blind, then we have to pick up and replace the ball and chain so * that we don't remember them if they are out of sight. */ if (Punished && !on && !Blind) move_bc(1, 0, uball->ox, uball->oy, uchain->ox, uchain->oy); #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) { /* Can't use do_clear_area because MAX_RADIUS is too small */ /* rogue lighting must light the entire room */ int rnum = levl[u.ux][u.uy].roomno - ROOMOFFSET; int rx, ry; if(rnum >= 0) { for(rx = rooms[rnum].lx-1; rx <= rooms[rnum].hx+1; rx++) for(ry = rooms[rnum].ly-1; ry <= rooms[rnum].hy+1; ry++) set_lit(rx, ry, (genericptr_t)(on ? &is_lit : (char *)0)); rooms[rnum].rlit = on; } /* hallways remain dark on the rogue level */ } else #endif do_clear_area(u.ux,u.uy, (obj && obj->oclass==SCROLL_CLASS && obj->blessed) ? 9 : 5, set_lit, (genericptr_t)(on ? &is_lit : (char *)0)); /* * If we are not blind, then force a redraw on all positions in sight * by temporarily blinding the hero. The vision recalculation will * correctly update all previously seen positions *and* correctly * set the waslit bit [could be messed up from above]. */ if (!Blind) { vision_recalc(2); /* replace ball&chain */ if (Punished && !on) move_bc(0, 0, uball->ox, uball->oy, uchain->ox, uchain->oy); } vision_full_recalc = 1; /* delayed vision recalculation */ } static void do_class_genocide() { int i, j, immunecnt, gonecnt, goodcnt, class, feel_dead = 0; char buf[BUFSZ]; boolean gameover = FALSE; /* true iff killed self */ for(j=0; ; j++) { if (j >= 5) { pline(thats_enough_tries); return; } do { getlin("What class of monsters do you wish to genocide?", buf); (void)mungspaces(buf); } while (buf[0]=='\033' || !buf[0]); /* choosing "none" preserves genocideless conduct */ if (!strcmpi(buf, "none") || !strcmpi(buf, "nothing")) return; if (strlen(buf) == 1) { if (buf[0] == ILLOBJ_SYM) buf[0] = def_monsyms[S_MIMIC]; class = def_char_to_monclass(buf[0]); } else { char buf2[BUFSZ]; class = 0; Strcpy(buf2, makesingular(buf)); Strcpy(buf, buf2); } immunecnt = gonecnt = goodcnt = 0; for (i = LOW_PM; i < NUMMONS; i++) { if (class == 0 && strstri(monexplain[(int)mons[i].mlet], buf) != 0) class = mons[i].mlet; if (mons[i].mlet == class) { if (!(mons[i].geno & G_GENO)) immunecnt++; else if(mvitals[i].mvflags & G_GENOD) gonecnt++; else goodcnt++; } } /* * TODO[?]: If user's input doesn't match any class * description, check individual species names. */ if (!goodcnt && class != mons[urole.malenum].mlet && class != mons[urace.malenum].mlet) { if (gonecnt) pline("All such monsters are already nonexistent."); else if (immunecnt || (buf[0] == DEF_INVISIBLE && buf[1] == '\0')) You("aren't permitted to genocide such monsters."); else #ifdef WIZARD /* to aid in topology testing; remove pesky monsters */ if (wizard && buf[0] == '*') { register struct monst *mtmp, *mtmp2; gonecnt = 0; for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (DEADMONSTER(mtmp)) continue; mongone(mtmp); gonecnt++; } pline("Eliminated %d monster%s.", gonecnt, plur(gonecnt)); return; } else #endif pline("That symbol does not represent any monster."); continue; } for (i = LOW_PM; i < NUMMONS; i++) { if(mons[i].mlet == class) { char nam[BUFSZ]; Strcpy(nam, makeplural(mons[i].mname)); /* Although "genus" is Latin for race, the hero benefits * from both race and role; thus genocide affects either. */ if (Your_Own_Role(i) || Your_Own_Race(i) || ((mons[i].geno & G_GENO) && !(mvitals[i].mvflags & G_GENOD))) { /* This check must be first since player monsters might * have G_GENOD or !G_GENO. */ mvitals[i].mvflags |= (G_GENOD|G_NOCORPSE); reset_rndmonst(i); kill_genocided_monsters(); update_inventory(); /* eggs & tins */ pline("Wiped out all %s.", nam); if (Upolyd && i == u.umonnum) { u.mh = -1; if (Unchanging) { if (!feel_dead++) You("die."); /* finish genociding this class of monsters before ultimately dying */ gameover = TRUE; } else rehumanize(); } /* Self-genocide if it matches either your race or role. Assumption: male and female forms share same monster class. */ if (i == urole.malenum || i == urace.malenum) { u.uhp = -1; if (Upolyd) { if (!feel_dead++) You_feel("dead inside."); } else { if (!feel_dead++) You("die."); gameover = TRUE; } } } else if (mvitals[i].mvflags & G_GENOD) { if (!gameover) pline("All %s are already nonexistent.", nam); } else if (!gameover) { /* suppress feedback about quest beings except for those applicable to our own role */ if ((mons[i].msound != MS_LEADER || quest_info(MS_LEADER) == i) && (mons[i].msound != MS_NEMESIS || quest_info(MS_NEMESIS) == i) && (mons[i].msound != MS_GUARDIAN || quest_info(MS_GUARDIAN) == i) /* non-leader/nemesis/guardian role-specific monster */ && (i != PM_NINJA || /* nuisance */ Role_if(PM_SAMURAI))) { boolean named, uniq; named = type_is_pname(&mons[i]) ? TRUE : FALSE; uniq = (mons[i].geno & G_UNIQ) ? TRUE : FALSE; /* one special case */ if (i == PM_HIGH_PRIEST) uniq = FALSE; You("aren't permitted to genocide %s%s.", (uniq && !named) ? "the " : "", (uniq || named) ? mons[i].mname : nam); } } } } if (gameover || u.uhp == -1) { killer_format = KILLED_BY_AN; killer = "scroll of genocide"; if (gameover) done(GENOCIDED); } return; } } #define REALLY 1 #define PLAYER 2 #define ONTHRONE 4 void do_genocide(how) int how; /* 0 = no genocide; create monsters (cursed scroll) */ /* 1 = normal genocide */ /* 3 = forced genocide of player */ /* 5 (4 | 1) = normal genocide from throne */ { char buf[BUFSZ]; register int i, killplayer = 0; register int mndx; register struct permonst *ptr; const char *which; if (how & PLAYER) { mndx = u.umonster; /* non-polymorphed mon num */ ptr = &mons[mndx]; Strcpy(buf, ptr->mname); killplayer++; } else { for(i = 0; ; i++) { if(i >= 5) { pline(thats_enough_tries); return; } getlin("What monster do you want to genocide? [type the name]", buf); (void)mungspaces(buf); /* choosing "none" preserves genocideless conduct */ if (!strcmpi(buf, "none") || !strcmpi(buf, "nothing")) { /* ... but no free pass if cursed */ if (!(how & REALLY)) { ptr = rndmonst(); if (!ptr) return; /* no message, like normal case */ mndx = monsndx(ptr); break; /* remaining checks don't apply */ } else return; } mndx = name_to_mon(buf); if (mndx == NON_PM || (mvitals[mndx].mvflags & G_GENOD)) { pline("Such creatures %s exist in this world.", (mndx == NON_PM) ? "do not" : "no longer"); continue; } ptr = &mons[mndx]; /* Although "genus" is Latin for race, the hero benefits * from both race and role; thus genocide affects either. */ if (Your_Own_Role(mndx) || Your_Own_Race(mndx)) { killplayer++; break; } if (is_human(ptr)) adjalign(-sgn(u.ualign.type)); if (is_demon(ptr)) adjalign(sgn(u.ualign.type)); if(!(ptr->geno & G_GENO)) { if(flags.soundok) { /* fixme: unconditional "caverns" will be silly in some circumstances */ if(flags.verbose) pline("A thunderous voice booms through the caverns:"); verbalize("No, mortal! That will not be done."); } continue; } /* KMH -- Unchanging prevents rehumanization */ if (Unchanging && ptr == youmonst.data) killplayer++; break; } } which = "all "; if (Hallucination) { if (Upolyd) Strcpy(buf,youmonst.data->mname); else { Strcpy(buf, (flags.female && urole.name.f) ? urole.name.f : urole.name.m); buf[0] = lowc(buf[0]); } } else { Strcpy(buf, ptr->mname); /* make sure we have standard singular */ if ((ptr->geno & G_UNIQ) && ptr != &mons[PM_HIGH_PRIEST]) which = !type_is_pname(ptr) ? "the " : ""; } if (how & REALLY) { /* setting no-corpse affects wishing and random tin generation */ mvitals[mndx].mvflags |= (G_GENOD | G_NOCORPSE); pline("Wiped out %s%s.", which, (*which != 'a') ? buf : makeplural(buf)); if (killplayer) { /* might need to wipe out dual role */ if (urole.femalenum != NON_PM && mndx == urole.malenum) mvitals[urole.femalenum].mvflags |= (G_GENOD | G_NOCORPSE); if (urole.femalenum != NON_PM && mndx == urole.femalenum) mvitals[urole.malenum].mvflags |= (G_GENOD | G_NOCORPSE); if (urace.femalenum != NON_PM && mndx == urace.malenum) mvitals[urace.femalenum].mvflags |= (G_GENOD | G_NOCORPSE); if (urace.femalenum != NON_PM && mndx == urace.femalenum) mvitals[urace.malenum].mvflags |= (G_GENOD | G_NOCORPSE); u.uhp = -1; if (how & PLAYER) { killer_format = KILLED_BY; killer = "genocidal confusion"; } else if (how & ONTHRONE) { /* player selected while on a throne */ killer_format = KILLED_BY_AN; killer = "imperious order"; } else { /* selected player deliberately, not confused */ killer_format = KILLED_BY_AN; killer = "scroll of genocide"; } /* Polymorphed characters will die as soon as they're rehumanized. */ /* KMH -- Unchanging prevents rehumanization */ if (Upolyd && ptr != youmonst.data) { delayed_killer = killer; killer = 0; You_feel("dead inside."); } else done(GENOCIDED); } else if (ptr == youmonst.data) { rehumanize(); } reset_rndmonst(mndx); kill_genocided_monsters(); update_inventory(); /* in case identified eggs were affected */ } else { int cnt = 0; if (!(mons[mndx].geno & G_UNIQ) && !(mvitals[mndx].mvflags & (G_GENOD | G_EXTINCT))) for (i = rn1(3, 4); i > 0; i--) { if (!makemon(ptr, u.ux, u.uy, NO_MINVENT)) break; /* couldn't make one */ ++cnt; if (mvitals[mndx].mvflags & G_EXTINCT) break; /* just made last one */ } if (cnt) pline("Sent in some %s.", makeplural(buf)); else pline(nothing_happens); } } void punish(sobj) register struct obj *sobj; { /* KMH -- Punishment is still okay when you are riding */ You("are being punished for your misbehavior!"); if(Punished){ Your("iron ball gets heavier."); uball->owt += 160 * (1 + sobj->cursed); return; } if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { pline("A ball and chain appears, then falls away."); dropy(mkobj(BALL_CLASS, TRUE)); return; } setworn(mkobj(CHAIN_CLASS, TRUE), W_CHAIN); setworn(mkobj(BALL_CLASS, TRUE), W_BALL); uball->spe = 1; /* special ball (see save) */ /* * Place ball & chain if not swallowed. If swallowed, the ball & * chain variables will be set at the next call to placebc(). */ if (!u.uswallow) { placebc(); if (Blind) set_bc(1); /* set up ball and chain variables */ newsym(u.ux,u.uy); /* see ball&chain if can't see self */ } } void unpunish() { /* remove the ball and chain */ struct obj *savechain = uchain; obj_extract_self(uchain); newsym(uchain->ox,uchain->oy); setworn((struct obj *)0, W_CHAIN); dealloc_obj(savechain); uball->spe = 0; setworn((struct obj *)0, W_BALL); } /* some creatures have special data structures that only make sense in their * normal locations -- if the player tries to create one elsewhere, or to revive * one, the disoriented creature becomes a zombie */ boolean cant_create(mtype, revival) int *mtype; boolean revival; { /* SHOPKEEPERS can be revived now */ if (*mtype==PM_GUARD || (*mtype==PM_SHOPKEEPER && !revival) || *mtype==PM_ALIGNED_PRIEST || *mtype==PM_ANGEL) { *mtype = PM_HUMAN_ZOMBIE; return TRUE; } else if (*mtype==PM_LONG_WORM_TAIL) { /* for create_particular() */ *mtype = PM_LONG_WORM; return TRUE; } return FALSE; } #ifdef WIZARD /* * Make a new monster with the type controlled by the user. * * Note: when creating a monster by class letter, specifying the * "strange object" (']') symbol produces a random monster rather * than a mimic; this behavior quirk is useful so don't "fix" it... */ boolean create_particular() { char buf[BUFSZ], *bufp, monclass = MAXMCLASSES; int which, tries, i; struct permonst *whichpm; struct monst *mtmp; boolean madeany = FALSE; boolean maketame, makepeaceful, makehostile; tries = 0; do { which = urole.malenum; /* an arbitrary index into mons[] */ maketame = makepeaceful = makehostile = FALSE; getlin("Create what kind of monster? [type the name or symbol]", buf); bufp = mungspaces(buf); if (*bufp == '\033') return FALSE; /* allow the initial disposition to be specified */ if (!strncmpi(bufp, "tame ", 5)) { bufp += 5; maketame = TRUE; } else if (!strncmpi(bufp, "peaceful ", 9)) { bufp += 9; makepeaceful = TRUE; } else if (!strncmpi(bufp, "hostile ", 8)) { bufp += 8; makehostile = TRUE; } /* decide whether a valid monster was chosen */ if (strlen(bufp) == 1) { monclass = def_char_to_monclass(*bufp); if (monclass != MAXMCLASSES) break; /* got one */ } else { which = name_to_mon(bufp); if (which >= LOW_PM) break; /* got one */ } /* no good; try again... */ pline("I've never heard of such monsters."); } while (++tries < 5); if (tries == 5) { pline(thats_enough_tries); } else { (void) cant_create(&which, FALSE); whichpm = &mons[which]; for (i = 0; i <= multi; i++) { if (monclass != MAXMCLASSES) whichpm = mkclass(monclass, 0); if (maketame) { mtmp = makemon(whichpm, u.ux, u.uy, MM_EDOG); if (mtmp) { initedog(mtmp); set_malign(mtmp); } } else { mtmp = makemon(whichpm, u.ux, u.uy, NO_MM_FLAGS); if ((makepeaceful || makehostile) && mtmp) { mtmp->mtame = 0; /* sanity precaution */ mtmp->mpeaceful = makepeaceful ? 1 : 0; set_malign(mtmp); } } if (mtmp) madeany = TRUE; } } return madeany; } #endif /* WIZARD */ #endif /* OVLB */ /*read.c*/ nethack-3.4.3/src/rect.c0100644000000000000000000000711307764735041013544 0ustar rootroot/* SCCS Id: @(#)rect.c 3.4 1990/02/22 */ /* Copyright (c) 1990 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" int FDECL(get_rect_ind, (NhRect *)); static boolean FDECL(intersect, (NhRect *,NhRect *,NhRect *)); /* * In this file, we will handle the various rectangle functions we * need for room generation. */ #define MAXRECT 50 #define XLIM 4 #define YLIM 3 static NhRect rect[MAXRECT+1]; static int rect_cnt; /* * Initialisation of internal structures. Should be called for every * new level to be build... */ void init_rect() { rect_cnt = 1; rect[0].lx = rect[0].ly = 0; rect[0].hx = COLNO - 1; rect[0].hy = ROWNO - 1; } /* * Search Index of one precise NhRect. * */ int get_rect_ind(r) NhRect *r; { register NhRect *rectp; register int lx, ly, hx, hy; register int i; lx = r->lx; ly = r->ly; hx = r->hx; hy = r->hy; for (i=0,rectp = &rect[0];ilx && ly == rectp->ly && hx == rectp->hx && hy == rectp->hy) return i; return -1; } /* * Search a free rectangle that include the one given in arg */ NhRect * get_rect(r) NhRect *r; { register NhRect *rectp; register int lx, ly, hx, hy; register int i; lx = r->lx; ly = r->ly; hx = r->hx; hy = r->hy; for (i=0,rectp = &rect[0];i= rectp->lx && ly >= rectp->ly && hx <= rectp->hx && hy <= rectp->hy) return rectp; return 0; } /* * Get some random NhRect from the list. */ NhRect * rnd_rect() { return rect_cnt > 0 ? &rect[rn2(rect_cnt)] : 0; } /* * Search intersection between two rectangles (r1 & r2). * return TRUE if intersection exist and put it in r3. * otherwise returns FALSE */ static boolean intersect(r1, r2, r3) NhRect *r1, *r2, *r3; { if (r2->lx > r1->hx || r2->ly > r1->hy || r2->hx < r1->lx || r2->hy < r1->ly) return FALSE; r3->lx = (r2->lx > r1->lx ? r2->lx : r1->lx); r3->ly = (r2->ly > r1->ly ? r2->ly : r1->ly); r3->hx = (r2->hx > r1->hx ? r1->hx : r2->hx); r3->hy = (r2->hy > r1->hy ? r1->hy : r2->hy); if (r3->lx > r3->hx || r3->ly > r3->hy) return FALSE; return TRUE; } /* * Remove a rectangle from the list of free NhRect. */ void remove_rect(r) NhRect *r; { int ind; ind = get_rect_ind(r); if ( ind >=0 ) rect[ind] = rect[--rect_cnt]; } /* * Add a NhRect to the list. */ void add_rect(r) NhRect *r; { if (rect_cnt >= MAXRECT) { #ifdef WIZARD if (wizard) pline("MAXRECT may be too small."); #endif return; } /* Check that this NhRect is not included in another one */ if (get_rect(r)) return; rect[rect_cnt] = *r; rect_cnt++; } /* * Okay, here we have two rectangles (r1 & r2). * r1 was already in the list and r2 is included in r1. * What we want is to allocate r2, that is split r1 into smaller rectangles * then remove it. */ void split_rects(r1, r2) NhRect *r1, *r2; { NhRect r, old_r; int i; old_r = *r1; remove_rect(r1); /* Walk down since rect_cnt & rect[] will change... */ for (i=rect_cnt-1; i>=0; i--) if (intersect(&rect[i], r2, &r)) split_rects(&rect[i], &r); if (r2->ly - old_r.ly-1 > (old_r.hy < ROWNO - 1 ? 2*YLIM : YLIM+1)+4) { r = old_r; r.hy = r2->ly - 2; add_rect(&r); } if (r2->lx - old_r.lx-1 > (old_r.hx < COLNO - 1 ? 2*XLIM : XLIM+1)+4) { r = old_r; r.hx = r2->lx - 2; add_rect(&r); } if (old_r.hy - r2->hy-1 > (old_r.ly > 0 ? 2*YLIM : YLIM+1)+4) { r = old_r; r.ly = r2->hy + 2; add_rect(&r); } if (old_r.hx - r2->hx-1 > (old_r.lx > 0 ? 2*XLIM : XLIM+1)+4) { r = old_r; r.lx = r2->hx + 2; add_rect(&r); } } /*rect.c*/ nethack-3.4.3/src/region.c0100644000000000000000000006266607764735041014110 0ustar rootroot/* SCCS Id: @(#)region.c 3.4 2002/10/15 */ /* Copyright (c) 1996 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" /* * This should really go into the level structure, but * I'll start here for ease. It *WILL* move into the level * structure eventually. */ static NhRegion **regions; static int n_regions = 0; static int max_regions = 0; #define NO_CALLBACK (-1) boolean FDECL(inside_gas_cloud, (genericptr,genericptr)); boolean FDECL(expire_gas_cloud, (genericptr,genericptr)); boolean FDECL(inside_rect, (NhRect *,int,int)); boolean FDECL(inside_region, (NhRegion *,int,int)); NhRegion *FDECL(create_region, (NhRect *,int)); void FDECL(add_rect_to_reg, (NhRegion *,NhRect *)); void FDECL(add_mon_to_reg, (NhRegion *,struct monst *)); void FDECL(remove_mon_from_reg, (NhRegion *,struct monst *)); boolean FDECL(mon_in_region, (NhRegion *,struct monst *)); #if 0 NhRegion *FDECL(clone_region, (NhRegion *)); #endif void FDECL(free_region, (NhRegion *)); void FDECL(add_region, (NhRegion *)); void FDECL(remove_region, (NhRegion *)); #if 0 void FDECL(replace_mon_regions, (struct monst *,struct monst *)); void FDECL(remove_mon_from_regions, (struct monst *)); NhRegion *FDECL(create_msg_region, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P, const char *,const char *)); boolean FDECL(enter_force_field, (genericptr,genericptr)); NhRegion *FDECL(create_force_field, (XCHAR_P,XCHAR_P,int,int)); #endif static void FDECL(reset_region_mids, (NhRegion *)); static callback_proc callbacks[] = { #define INSIDE_GAS_CLOUD 0 inside_gas_cloud, #define EXPIRE_GAS_CLOUD 1 expire_gas_cloud }; /* Should be inlined. */ boolean inside_rect(r, x, y) NhRect *r; int x, y; { return (x >= r->lx && x <= r->hx && y >= r->ly && y <= r->hy); } /* * Check if a point is inside a region. */ boolean inside_region(reg, x, y) NhRegion *reg; int x, y; { int i; if (reg == NULL || !inside_rect(&(reg->bounding_box), x, y)) return FALSE; for (i = 0; i < reg->nrects; i++) if (inside_rect(&(reg->rects[i]), x, y)) return TRUE; return FALSE; } /* * Create a region. It does not activate it. */ NhRegion * create_region(rects, nrect) NhRect *rects; int nrect; { int i; NhRegion *reg; reg = (NhRegion *) alloc(sizeof (NhRegion)); /* Determines bounding box */ if (nrect > 0) { reg->bounding_box = rects[0]; } else { reg->bounding_box.lx = 99; reg->bounding_box.ly = 99; reg->bounding_box.hx = 0; reg->bounding_box.hy = 0; } reg->nrects = nrect; reg->rects = nrect > 0 ? (NhRect *)alloc((sizeof (NhRect)) * nrect) : NULL; for (i = 0; i < nrect; i++) { if (rects[i].lx < reg->bounding_box.lx) reg->bounding_box.lx = rects[i].lx; if (rects[i].ly < reg->bounding_box.ly) reg->bounding_box.ly = rects[i].ly; if (rects[i].hx > reg->bounding_box.hx) reg->bounding_box.hx = rects[i].hx; if (rects[i].hy > reg->bounding_box.hy) reg->bounding_box.hy = rects[i].hy; reg->rects[i] = rects[i]; } reg->ttl = -1; /* Defaults */ reg->attach_2_u = FALSE; reg->attach_2_m = 0; /* reg->attach_2_o = NULL; */ reg->enter_msg = NULL; reg->leave_msg = NULL; reg->expire_f = NO_CALLBACK; reg->enter_f = NO_CALLBACK; reg->can_enter_f = NO_CALLBACK; reg->leave_f = NO_CALLBACK; reg->can_leave_f = NO_CALLBACK; reg->inside_f = NO_CALLBACK; clear_hero_inside(reg); clear_heros_fault(reg); reg->n_monst = 0; reg->max_monst = 0; reg->monsters = NULL; reg->arg = NULL; return reg; } /* * Add rectangle to region. */ void add_rect_to_reg(reg, rect) NhRegion *reg; NhRect *rect; { NhRect *tmp_rect; tmp_rect = (NhRect *) alloc(sizeof (NhRect) * (reg->nrects + 1)); if (reg->nrects > 0) { (void) memcpy((genericptr_t) tmp_rect, (genericptr_t) reg->rects, (sizeof (NhRect) * reg->nrects)); free((genericptr_t) reg->rects); } tmp_rect[reg->nrects] = *rect; reg->nrects++; reg->rects = tmp_rect; /* Update bounding box if needed */ if (reg->bounding_box.lx > rect->lx) reg->bounding_box.lx = rect->lx; if (reg->bounding_box.ly > rect->ly) reg->bounding_box.ly = rect->ly; if (reg->bounding_box.hx < rect->hx) reg->bounding_box.hx = rect->hx; if (reg->bounding_box.hy < rect->hy) reg->bounding_box.hy = rect->hy; } /* * Add a monster to the region */ void add_mon_to_reg(reg, mon) NhRegion *reg; struct monst *mon; { int i; unsigned *tmp_m; if (reg->max_monst <= reg->n_monst) { tmp_m = (unsigned *) alloc(sizeof (unsigned) * (reg->max_monst + MONST_INC)); if (reg->max_monst > 0) { for (i = 0; i < reg->max_monst; i++) tmp_m[i] = reg->monsters[i]; free((genericptr_t) reg->monsters); } reg->monsters = tmp_m; reg->max_monst += MONST_INC; } reg->monsters[reg->n_monst++] = mon->m_id; } /* * Remove a monster from the region list (it left or died...) */ void remove_mon_from_reg(reg, mon) NhRegion *reg; struct monst *mon; { register int i; for (i = 0; i < reg->n_monst; i++) if (reg->monsters[i] == mon->m_id) { reg->n_monst--; reg->monsters[i] = reg->monsters[reg->n_monst]; return; } } /* * Check if a monster is inside the region. * It's probably quicker to check with the region internal list * than to check for coordinates. */ boolean mon_in_region(reg, mon) NhRegion *reg; struct monst *mon; { int i; for (i = 0; i < reg->n_monst; i++) if (reg->monsters[i] == mon->m_id) return TRUE; return FALSE; } #if 0 /* not yet used */ /* * Clone (make a standalone copy) the region. */ NhRegion * clone_region(reg) NhRegion *reg; { NhRegion *ret_reg; ret_reg = create_region(reg->rects, reg->nrects); ret_reg->ttl = reg->ttl; ret_reg->attach_2_u = reg->attach_2_u; ret_reg->attach_2_m = reg->attach_2_m; /* ret_reg->attach_2_o = reg->attach_2_o; */ ret_reg->expire_f = reg->expire_f; ret_reg->enter_f = reg->enter_f; ret_reg->can_enter_f = reg->can_enter_f; ret_reg->leave_f = reg->leave_f; ret_reg->can_leave_f = reg->can_leave_f; ret_reg->player_flags = reg->player_flags; /* set/clear_hero_inside,&c*/ ret_reg->n_monst = reg->n_monst; if (reg->n_monst > 0) { ret_reg->monsters = (unsigned *) alloc((sizeof (unsigned)) * reg->n_monst); (void) memcpy((genericptr_t) ret_reg->monsters, (genericptr_t) reg->monsters, sizeof (unsigned) * reg->n_monst); } else ret_reg->monsters = NULL; return ret_reg; } #endif /*0*/ /* * Free mem from region. */ void free_region(reg) NhRegion *reg; { if (reg) { if (reg->rects) free((genericptr_t) reg->rects); if (reg->monsters) free((genericptr_t) reg->monsters); free((genericptr_t) reg); } } /* * Add a region to the list. * This actually activates the region. */ void add_region(reg) NhRegion *reg; { NhRegion **tmp_reg; int i, j; if (max_regions <= n_regions) { tmp_reg = regions; regions = (NhRegion **)alloc(sizeof (NhRegion *) * (max_regions + 10)); if (max_regions > 0) { (void) memcpy((genericptr_t) regions, (genericptr_t) tmp_reg, max_regions * sizeof (NhRegion *)); free((genericptr_t) tmp_reg); } max_regions += 10; } regions[n_regions] = reg; n_regions++; /* Check for monsters inside the region */ for (i = reg->bounding_box.lx; i <= reg->bounding_box.hx; i++) for (j = reg->bounding_box.ly; j <= reg->bounding_box.hy; j++) { /* Some regions can cross the level boundaries */ if (!isok(i,j)) continue; if (MON_AT(i, j) && inside_region(reg, i, j)) add_mon_to_reg(reg, level.monsters[i][j]); if (reg->visible && cansee(i, j)) newsym(i, j); } /* Check for player now... */ if (inside_region(reg, u.ux, u.uy)) set_hero_inside(reg); else clear_hero_inside(reg); } /* * Remove a region from the list & free it. */ void remove_region(reg) NhRegion *reg; { register int i, x, y; for (i = 0; i < n_regions; i++) if (regions[i] == reg) break; if (i == n_regions) return; /* Update screen if necessary */ if (reg->visible) for (x = reg->bounding_box.lx; x <= reg->bounding_box.hx; x++) for (y = reg->bounding_box.ly; y <= reg->bounding_box.hy; y++) if (isok(x,y) && inside_region(reg, x, y) && cansee(x, y)) newsym(x, y); free_region(reg); regions[i] = regions[n_regions - 1]; regions[n_regions - 1] = (NhRegion *) 0; n_regions--; } /* * Remove all regions and clear all related data (This must be down * when changing level, for instance). */ void clear_regions() { register int i; for (i = 0; i < n_regions; i++) free_region(regions[i]); n_regions = 0; if (max_regions > 0) free((genericptr_t) regions); max_regions = 0; regions = NULL; } /* * This function is called every turn. * It makes the regions age, if necessary and calls the appropriate * callbacks when needed. */ void run_regions() { register int i, j, k; int f_indx; /* End of life ? */ /* Do it backward because the array will be modified */ for (i = n_regions - 1; i >= 0; i--) { if (regions[i]->ttl == 0) { if ((f_indx = regions[i]->expire_f) == NO_CALLBACK || (*callbacks[f_indx])(regions[i], (genericptr_t) 0)) remove_region(regions[i]); } } /* Process remaining regions */ for (i = 0; i < n_regions; i++) { /* Make the region age */ if (regions[i]->ttl > 0) regions[i]->ttl--; /* Check if player is inside region */ f_indx = regions[i]->inside_f; if (f_indx != NO_CALLBACK && hero_inside(regions[i])) (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); /* Check if any monster is inside region */ if (f_indx != NO_CALLBACK) { for (j = 0; j < regions[i]->n_monst; j++) { struct monst *mtmp = find_mid(regions[i]->monsters[j], FM_FMON); if (!mtmp || mtmp->mhp <= 0 || (*callbacks[f_indx])(regions[i], mtmp)) { /* The monster died, remove it from list */ k = (regions[i]->n_monst -= 1); regions[i]->monsters[j] = regions[i]->monsters[k]; regions[i]->monsters[k] = 0; --j; /* current slot has been reused; recheck it next */ } } } } } /* * check whether player enters/leaves one or more regions. */ boolean in_out_region(x, y) xchar x, y; { int i, f_indx; /* First check if we can do the move */ for (i = 0; i < n_regions; i++) { if (inside_region(regions[i], x, y) && !hero_inside(regions[i]) && !regions[i]->attach_2_u) { if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) return FALSE; } else if (hero_inside(regions[i]) && !inside_region(regions[i], x, y) && !regions[i]->attach_2_u) { if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], (genericptr_t) 0)) return FALSE; } } /* Callbacks for the regions we do leave */ for (i = 0; i < n_regions; i++) if (hero_inside(regions[i]) && !regions[i]->attach_2_u && !inside_region(regions[i], x, y)) { clear_hero_inside(regions[i]); if (regions[i]->leave_msg != NULL) pline(regions[i]->leave_msg); if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); } /* Callbacks for the regions we do enter */ for (i = 0; i < n_regions; i++) if (!hero_inside(regions[i]) && !regions[i]->attach_2_u && inside_region(regions[i], x, y)) { set_hero_inside(regions[i]); if (regions[i]->enter_msg != NULL) pline(regions[i]->enter_msg); if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) (void) (*callbacks[f_indx])(regions[i], (genericptr_t) 0); } return TRUE; } /* * check wether a monster enters/leaves one or more region. */ boolean m_in_out_region(mon, x, y) struct monst *mon; xchar x, y; { int i, f_indx; /* First check if we can do the move */ for (i = 0; i < n_regions; i++) { if (inside_region(regions[i], x, y) && !mon_in_region(regions[i], mon) && regions[i]->attach_2_m != mon->m_id) { if ((f_indx = regions[i]->can_enter_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], mon)) return FALSE; } else if (mon_in_region(regions[i], mon) && !inside_region(regions[i], x, y) && regions[i]->attach_2_m != mon->m_id) { if ((f_indx = regions[i]->can_leave_f) != NO_CALLBACK) if (!(*callbacks[f_indx])(regions[i], mon)) return FALSE; } } /* Callbacks for the regions we do leave */ for (i = 0; i < n_regions; i++) if (mon_in_region(regions[i], mon) && regions[i]->attach_2_m != mon->m_id && !inside_region(regions[i], x, y)) { remove_mon_from_reg(regions[i], mon); if ((f_indx = regions[i]->leave_f) != NO_CALLBACK) (void) (*callbacks[f_indx])(regions[i], mon); } /* Callbacks for the regions we do enter */ for (i = 0; i < n_regions; i++) if (!hero_inside(regions[i]) && !regions[i]->attach_2_u && inside_region(regions[i], x, y)) { add_mon_to_reg(regions[i], mon); if ((f_indx = regions[i]->enter_f) != NO_CALLBACK) (void) (*callbacks[f_indx])(regions[i], mon); } return TRUE; } /* * Checks player's regions after a teleport for instance. */ void update_player_regions() { register int i; for (i = 0; i < n_regions; i++) if (!regions[i]->attach_2_u && inside_region(regions[i], u.ux, u.uy)) set_hero_inside(regions[i]); else clear_hero_inside(regions[i]); } /* * Ditto for a specified monster. */ void update_monster_region(mon) struct monst *mon; { register int i; for (i = 0; i < n_regions; i++) { if (inside_region(regions[i], mon->mx, mon->my)) { if (!mon_in_region(regions[i], mon)) add_mon_to_reg(regions[i], mon); } else { if (mon_in_region(regions[i], mon)) remove_mon_from_reg(regions[i], mon); } } } #if 0 /* not yet used */ /* * Change monster pointer in regions * This happens, for instance, when a monster grows and * need a new structure (internally that is). */ void replace_mon_regions(monold, monnew) struct monst *monold, *monnew; { register int i; for (i = 0; i < n_regions; i++) if (mon_in_region(regions[i], monold)) { remove_mon_from_reg(regions[i], monold); add_mon_to_reg(regions[i], monnew); } } /* * Remove monster from all regions it was in (ie monster just died) */ void remove_mon_from_regions(mon) struct monst *mon; { register int i; for (i = 0; i < n_regions; i++) if (mon_in_region(regions[i], mon)) remove_mon_from_reg(regions[i], mon); } #endif /*0*/ /* * Check if a spot is under a visible region (eg: gas cloud). * Returns NULL if not, otherwise returns region. */ NhRegion * visible_region_at(x, y) xchar x, y; { register int i; for (i = 0; i < n_regions; i++) if (inside_region(regions[i], x, y) && regions[i]->visible && regions[i]->ttl != 0) return regions[i]; return (NhRegion *) 0; } void show_region(reg, x, y) NhRegion *reg; xchar x, y; { show_glyph(x, y, reg->glyph); } /** * save_regions : */ void save_regions(fd, mode) int fd; int mode; { int i, j; unsigned n; if (!perform_bwrite(mode)) goto skip_lots; bwrite(fd, (genericptr_t) &moves, sizeof (moves)); /* timestamp */ bwrite(fd, (genericptr_t) &n_regions, sizeof (n_regions)); for (i = 0; i < n_regions; i++) { bwrite(fd, (genericptr_t) ®ions[i]->bounding_box, sizeof (NhRect)); bwrite(fd, (genericptr_t) ®ions[i]->nrects, sizeof (short)); for (j = 0; j < regions[i]->nrects; j++) bwrite(fd, (genericptr_t) ®ions[i]->rects[j], sizeof (NhRect)); bwrite(fd, (genericptr_t) ®ions[i]->attach_2_u, sizeof (boolean)); n = 0; bwrite(fd, (genericptr_t) ®ions[i]->attach_2_m, sizeof (unsigned)); n = regions[i]->enter_msg != NULL ? strlen(regions[i]->enter_msg) : 0; bwrite(fd, (genericptr_t) &n, sizeof n); if (n > 0) bwrite(fd, (genericptr_t) regions[i]->enter_msg, n); n = regions[i]->leave_msg != NULL ? strlen(regions[i]->leave_msg) : 0; bwrite(fd, (genericptr_t) &n, sizeof n); if (n > 0) bwrite(fd, (genericptr_t) regions[i]->leave_msg, n); bwrite(fd, (genericptr_t) ®ions[i]->ttl, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->expire_f, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->can_enter_f, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->enter_f, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->leave_f, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->inside_f, sizeof (short)); bwrite(fd, (genericptr_t) ®ions[i]->player_flags, sizeof (boolean)); bwrite(fd, (genericptr_t) ®ions[i]->n_monst, sizeof (short)); for (j = 0; j < regions[i]->n_monst; j++) bwrite(fd, (genericptr_t) ®ions[i]->monsters[j], sizeof (unsigned)); bwrite(fd, (genericptr_t) ®ions[i]->visible, sizeof (boolean)); bwrite(fd, (genericptr_t) ®ions[i]->glyph, sizeof (int)); bwrite(fd, (genericptr_t) ®ions[i]->arg, sizeof (genericptr_t)); } skip_lots: if (release_data(mode)) clear_regions(); } void rest_regions(fd, ghostly) int fd; boolean ghostly; /* If a bones file restore */ { int i, j; unsigned n; long tmstamp; char *msg_buf; clear_regions(); /* Just for security */ mread(fd, (genericptr_t) &tmstamp, sizeof (tmstamp)); if (ghostly) tmstamp = 0; else tmstamp = (moves - tmstamp); mread(fd, (genericptr_t) &n_regions, sizeof (n_regions)); max_regions = n_regions; if (n_regions > 0) regions = (NhRegion **) alloc(sizeof (NhRegion *) * n_regions); for (i = 0; i < n_regions; i++) { regions[i] = (NhRegion *) alloc(sizeof (NhRegion)); mread(fd, (genericptr_t) ®ions[i]->bounding_box, sizeof (NhRect)); mread(fd, (genericptr_t) ®ions[i]->nrects, sizeof (short)); if (regions[i]->nrects > 0) regions[i]->rects = (NhRect *) alloc(sizeof (NhRect) * regions[i]->nrects); for (j = 0; j < regions[i]->nrects; j++) mread(fd, (genericptr_t) ®ions[i]->rects[j], sizeof (NhRect)); mread(fd, (genericptr_t) ®ions[i]->attach_2_u, sizeof (boolean)); mread(fd, (genericptr_t) ®ions[i]->attach_2_m, sizeof (unsigned)); mread(fd, (genericptr_t) &n, sizeof n); if (n > 0) { msg_buf = (char *) alloc(n + 1); mread(fd, (genericptr_t) msg_buf, n); msg_buf[n] = '\0'; regions[i]->enter_msg = (const char *) msg_buf; } else regions[i]->enter_msg = NULL; mread(fd, (genericptr_t) &n, sizeof n); if (n > 0) { msg_buf = (char *) alloc(n + 1); mread(fd, (genericptr_t) msg_buf, n); msg_buf[n] = '\0'; regions[i]->leave_msg = (const char *) msg_buf; } else regions[i]->leave_msg = NULL; mread(fd, (genericptr_t) ®ions[i]->ttl, sizeof (short)); /* check for expired region */ if (regions[i]->ttl >= 0) regions[i]->ttl = (regions[i]->ttl > tmstamp) ? regions[i]->ttl - tmstamp : 0; mread(fd, (genericptr_t) ®ions[i]->expire_f, sizeof (short)); mread(fd, (genericptr_t) ®ions[i]->can_enter_f, sizeof (short)); mread(fd, (genericptr_t) ®ions[i]->enter_f, sizeof (short)); mread(fd, (genericptr_t) ®ions[i]->can_leave_f, sizeof (short)); mread(fd, (genericptr_t) ®ions[i]->leave_f, sizeof (short)); mread(fd, (genericptr_t) ®ions[i]->inside_f, sizeof (short)); mread(fd, (genericptr_t) ®ions[i]->player_flags, sizeof (boolean)); if (ghostly) { /* settings pertained to old player */ clear_hero_inside(regions[i]); clear_heros_fault(regions[i]); } mread(fd, (genericptr_t) ®ions[i]->n_monst, sizeof (short)); if (regions[i]->n_monst > 0) regions[i]->monsters = (unsigned *) alloc(sizeof (unsigned) * regions[i]->n_monst); else regions[i]->monsters = NULL; regions[i]->max_monst = regions[i]->n_monst; for (j = 0; j < regions[i]->n_monst; j++) mread(fd, (genericptr_t) ®ions[i]->monsters[j], sizeof (unsigned)); mread(fd, (genericptr_t) ®ions[i]->visible, sizeof (boolean)); mread(fd, (genericptr_t) ®ions[i]->glyph, sizeof (int)); mread(fd, (genericptr_t) ®ions[i]->arg, sizeof (genericptr_t)); } /* remove expired regions, do not trigger the expire_f callback (yet!); also update monster lists if this data is coming from a bones file */ for (i = n_regions - 1; i >= 0; i--) if (regions[i]->ttl == 0) remove_region(regions[i]); else if (ghostly && regions[i]->n_monst > 0) reset_region_mids(regions[i]); } /* update monster IDs for region being loaded from bones; `ghostly' implied */ static void reset_region_mids(reg) NhRegion *reg; { int i = 0, n = reg->n_monst; unsigned *mid_list = reg->monsters; while (i < n) if (!lookup_id_mapping(mid_list[i], &mid_list[i])) { /* shrink list to remove missing monster; order doesn't matter */ mid_list[i] = mid_list[--n]; } else { /* move on to next monster */ ++i; } reg->n_monst = n; return; } #if 0 /* not yet used */ /*--------------------------------------------------------------* * * * Create Region with just a message * * * *--------------------------------------------------------------*/ NhRegion * create_msg_region(x, y, w, h, msg_enter, msg_leave) xchar x, y; xchar w, h; const char *msg_enter; const char *msg_leave; { NhRect tmprect; NhRegion *reg = create_region((NhRect *) 0, 0); reg->enter_msg = msg_enter; reg->leave_msg = msg_leave; tmprect.lx = x; tmprect.ly = y; tmprect.hx = x + w; tmprect.hy = y + h; add_rect_to_reg(reg, &tmprect); reg->ttl = -1; return reg; } /*--------------------------------------------------------------* * * * Force Field Related Code * * (unused yet) * *--------------------------------------------------------------*/ boolean enter_force_field(p1, p2) genericptr_t p1; genericptr_t p2; { struct monst *mtmp; if (p2 == NULL) { /* That means the player */ if (!Blind) You("bump into %s. Ouch!", Hallucination ? "an invisible tree" : "some kind of invisible wall"); else pline("Ouch!"); } else { mtmp = (struct monst *) p2; if (canseemon(mtmp)) pline("%s bumps into %s!", Monnam(mtmp), something); } return FALSE; } NhRegion * create_force_field(x, y, radius, ttl) xchar x, y; int radius, ttl; { int i; NhRegion *ff; int nrect; NhRect tmprect; ff = create_region((NhRect *) 0, 0); nrect = radius; tmprect.lx = x; tmprect.hx = x; tmprect.ly = y - (radius - 1); tmprect.hy = y + (radius - 1); for (i = 0; i < nrect; i++) { add_rect_to_reg(ff, &tmprect); tmprect.lx--; tmprect.hx++; tmprect.ly++; tmprect.hy--; } ff->ttl = ttl; if (!in_mklev && !flags.mon_moving) set_heros_fault(ff); /* assume player has created it */ /* ff->can_enter_f = enter_force_field; */ /* ff->can_leave_f = enter_force_field; */ add_region(ff); return ff; } #endif /*0*/ /*--------------------------------------------------------------* * * * Gas cloud related code * * * *--------------------------------------------------------------*/ /* * Here is an example of an expire function that may prolong * region life after some mods... */ boolean expire_gas_cloud(p1, p2) genericptr_t p1; genericptr_t p2; { NhRegion *reg; int damage; reg = (NhRegion *) p1; damage = (int) reg->arg; /* If it was a thick cloud, it dissipates a little first */ if (damage >= 5) { damage /= 2; /* It dissipates, let's do less damage */ reg->arg = (genericptr_t) damage; reg->ttl = 2; /* Here's the trick : reset ttl */ return FALSE; /* THEN return FALSE, means "still there" */ } return TRUE; /* OK, it's gone, you can free it! */ } boolean inside_gas_cloud(p1, p2) genericptr_t p1; genericptr_t p2; { NhRegion *reg; struct monst *mtmp; int dam; reg = (NhRegion *) p1; dam = (int) reg->arg; if (p2 == NULL) { /* This means *YOU* Bozo! */ if (nonliving(youmonst.data) || Breathless) return FALSE; if (!Blind) make_blinded(1L, FALSE); if (!Poison_resistance) { pline("%s is burning your %s!", Something, makeplural(body_part(LUNG))); You("cough and spit blood!"); losehp(rnd(dam) + 5, "gas cloud", KILLED_BY_AN); return FALSE; } else { You("cough!"); return FALSE; } } else { /* A monster is inside the cloud */ mtmp = (struct monst *) p2; /* Non living and non breathing monsters are not concerned */ if (!nonliving(mtmp->data) && !breathless(mtmp->data)) { if (cansee(mtmp->mx, mtmp->my)) pline("%s coughs!", Monnam(mtmp)); setmangry(mtmp); if (haseyes(mtmp->data) && mtmp->mcansee) { mtmp->mblinded = 1; mtmp->mcansee = 0; } if (resists_poison(mtmp)) return FALSE; mtmp->mhp -= rnd(dam) + 5; if (mtmp->mhp <= 0) { if (heros_fault(reg)) killed(mtmp); else monkilled(mtmp, "gas cloud", AD_DRST); if (mtmp->mhp <= 0) { /* not lifesaved */ return TRUE; } } } } return FALSE; /* Monster is still alive */ } NhRegion * create_gas_cloud(x, y, radius, damage) xchar x, y; int radius; int damage; { NhRegion *cloud; int i, nrect; NhRect tmprect; cloud = create_region((NhRect *) 0, 0); nrect = radius; tmprect.lx = x; tmprect.hx = x; tmprect.ly = y - (radius - 1); tmprect.hy = y + (radius - 1); for (i = 0; i < nrect; i++) { add_rect_to_reg(cloud, &tmprect); tmprect.lx--; tmprect.hx++; tmprect.ly++; tmprect.hy--; } cloud->ttl = rn1(3,4); if (!in_mklev && !flags.mon_moving) set_heros_fault(cloud); /* assume player has created it */ cloud->inside_f = INSIDE_GAS_CLOUD; cloud->expire_f = EXPIRE_GAS_CLOUD; cloud->arg = (genericptr_t) damage; cloud->visible = TRUE; cloud->glyph = cmap_to_glyph(S_cloud); add_region(cloud); return cloud; } /*region.c*/ nethack-3.4.3/src/restore.c0100644000000000000000000006613107764735041014277 0ustar rootroot/* SCCS Id: @(#)restore.c 3.4 2003/09/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #include "tcap.h" /* for TERMLIB and ASCIIGRAPH */ #if defined(MICRO) extern int dotcnt; /* shared with save */ extern int dotrow; /* shared with save */ #endif #ifdef USE_TILES extern void FDECL(substitute_tiles, (d_level *)); /* from tile.c */ #endif #ifdef ZEROCOMP static int NDECL(mgetc); #endif STATIC_DCL void NDECL(find_lev_obj); STATIC_DCL void FDECL(restlevchn, (int)); STATIC_DCL void FDECL(restdamage, (int,BOOLEAN_P)); STATIC_DCL struct obj *FDECL(restobjchn, (int,BOOLEAN_P,BOOLEAN_P)); STATIC_DCL struct monst *FDECL(restmonchn, (int,BOOLEAN_P)); STATIC_DCL struct fruit *FDECL(loadfruitchn, (int)); STATIC_DCL void FDECL(freefruitchn, (struct fruit *)); STATIC_DCL void FDECL(ghostfruit, (struct obj *)); STATIC_DCL boolean FDECL(restgamestate, (int, unsigned int *, unsigned int *)); STATIC_DCL void FDECL(restlevelstate, (unsigned int, unsigned int)); STATIC_DCL int FDECL(restlevelfile, (int,XCHAR_P)); STATIC_DCL void FDECL(reset_oattached_mids, (BOOLEAN_P)); /* * Save a mapping of IDs from ghost levels to the current level. This * map is used by the timer routines when restoring ghost levels. */ #define N_PER_BUCKET 64 struct bucket { struct bucket *next; struct { unsigned gid; /* ghost ID */ unsigned nid; /* new ID */ } map[N_PER_BUCKET]; }; STATIC_DCL void NDECL(clear_id_mapping); STATIC_DCL void FDECL(add_id_mapping, (unsigned, unsigned)); static int n_ids_mapped = 0; static struct bucket *id_map = 0; #ifdef AMII_GRAPHICS void FDECL( amii_setpens, (int) ); /* use colors from save file */ extern int amii_numcolors; #endif #include "quest.h" boolean restoring = FALSE; static NEARDATA struct fruit *oldfruit; static NEARDATA long omoves; #define Is_IceBox(o) ((o)->otyp == ICE_BOX ? TRUE : FALSE) /* Recalculate level.objects[x][y], since this info was not saved. */ STATIC_OVL void find_lev_obj() { register struct obj *fobjtmp = (struct obj *)0; register struct obj *otmp; int x,y; for(x=0; xnobj; otmp->nobj = fobjtmp; otmp->where = OBJ_FREE; fobjtmp = otmp; } /* fobj should now be empty */ /* Set level.objects (as well as reversing the chain back again) */ while ((otmp = fobjtmp) != 0) { fobjtmp = otmp->nobj; place_object(otmp, otmp->ox, otmp->oy); } } /* Things that were marked "in_use" when the game was saved (ex. via the * infamous "HUP" cheat) get used up here. */ void inven_inuse(quietly) boolean quietly; { register struct obj *otmp, *otmp2; for (otmp = invent; otmp; otmp = otmp2) { otmp2 = otmp->nobj; #ifndef GOLDOBJ if (otmp->oclass == COIN_CLASS) { /* in_use gold is created by some menu operations */ if (!otmp->in_use) { impossible("inven_inuse: !in_use gold in inventory"); } extract_nobj(otmp, &invent); otmp->in_use = FALSE; dealloc_obj(otmp); } else #endif /* GOLDOBJ */ if (otmp->in_use) { if (!quietly) pline("Finishing off %s...", xname(otmp)); useup(otmp); } } } STATIC_OVL void restlevchn(fd) register int fd; { int cnt; s_level *tmplev, *x; sp_levchn = (s_level *) 0; mread(fd, (genericptr_t) &cnt, sizeof(int)); for(; cnt > 0; cnt--) { tmplev = (s_level *)alloc(sizeof(s_level)); mread(fd, (genericptr_t) tmplev, sizeof(s_level)); if(!sp_levchn) sp_levchn = tmplev; else { for(x = sp_levchn; x->next; x = x->next); x->next = tmplev; } tmplev->next = (s_level *)0; } } STATIC_OVL void restdamage(fd, ghostly) int fd; boolean ghostly; { int counter; struct damage *tmp_dam; mread(fd, (genericptr_t) &counter, sizeof(counter)); if (!counter) return; tmp_dam = (struct damage *)alloc(sizeof(struct damage)); while (--counter >= 0) { char damaged_shops[5], *shp = (char *)0; mread(fd, (genericptr_t) tmp_dam, sizeof(*tmp_dam)); if (ghostly) tmp_dam->when += (monstermoves - omoves); Strcpy(damaged_shops, in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE)); if (u.uz.dlevel) { /* when restoring, there are two passes over the current * level. the first time, u.uz isn't set, so neither is * shop_keeper(). just wait and process the damage on * the second pass. */ for (shp = damaged_shops; *shp; shp++) { struct monst *shkp = shop_keeper(*shp); if (shkp && inhishop(shkp) && repair_damage(shkp, tmp_dam, TRUE)) break; } } if (!shp || !*shp) { tmp_dam->next = level.damagelist; level.damagelist = tmp_dam; tmp_dam = (struct damage *)alloc(sizeof(*tmp_dam)); } } free((genericptr_t)tmp_dam); } STATIC_OVL struct obj * restobjchn(fd, ghostly, frozen) register int fd; boolean ghostly, frozen; { register struct obj *otmp, *otmp2 = 0; register struct obj *first = (struct obj *)0; int xl; while(1) { mread(fd, (genericptr_t) &xl, sizeof(xl)); if(xl == -1) break; otmp = newobj(xl); if(!first) first = otmp; else otmp2->nobj = otmp; mread(fd, (genericptr_t) otmp, (unsigned) xl + sizeof(struct obj)); if (ghostly) { unsigned nid = flags.ident++; add_id_mapping(otmp->o_id, nid); otmp->o_id = nid; } if (ghostly && otmp->otyp == SLIME_MOLD) ghostfruit(otmp); /* Ghost levels get object age shifted from old player's clock * to new player's clock. Assumption: new player arrived * immediately after old player died. */ if (ghostly && !frozen && !age_is_relative(otmp)) otmp->age = monstermoves - omoves + otmp->age; /* get contents of a container or statue */ if (Has_contents(otmp)) { struct obj *otmp3; otmp->cobj = restobjchn(fd, ghostly, Is_IceBox(otmp)); /* restore container back pointers */ for (otmp3 = otmp->cobj; otmp3; otmp3 = otmp3->nobj) otmp3->ocontainer = otmp; } if (otmp->bypass) otmp->bypass = 0; otmp2 = otmp; } if(first && otmp2->nobj){ impossible("Restobjchn: error reading objchn."); otmp2->nobj = 0; } return(first); } STATIC_OVL struct monst * restmonchn(fd, ghostly) register int fd; boolean ghostly; { register struct monst *mtmp, *mtmp2 = 0; register struct monst *first = (struct monst *)0; int xl; struct permonst *monbegin; boolean moved; /* get the original base address */ mread(fd, (genericptr_t)&monbegin, sizeof(monbegin)); moved = (monbegin != mons); while(1) { mread(fd, (genericptr_t) &xl, sizeof(xl)); if(xl == -1) break; mtmp = newmonst(xl); if(!first) first = mtmp; else mtmp2->nmon = mtmp; mread(fd, (genericptr_t) mtmp, (unsigned) xl + sizeof(struct monst)); if (ghostly) { unsigned nid = flags.ident++; add_id_mapping(mtmp->m_id, nid); mtmp->m_id = nid; } if (moved && mtmp->data) { int offset = mtmp->data - monbegin; /*(ptrdiff_t)*/ mtmp->data = mons + offset; /* new permonst location */ } if (ghostly) { int mndx = monsndx(mtmp->data); if (propagate(mndx, TRUE, ghostly) == 0) { /* cookie to trigger purge in getbones() */ mtmp->mhpmax = DEFUNCT_MONSTER; } } if(mtmp->minvent) { struct obj *obj; mtmp->minvent = restobjchn(fd, ghostly, FALSE); /* restore monster back pointer */ for (obj = mtmp->minvent; obj; obj = obj->nobj) obj->ocarry = mtmp; } if (mtmp->mw) { struct obj *obj; for(obj = mtmp->minvent; obj; obj = obj->nobj) if (obj->owornmask & W_WEP) break; if (obj) mtmp->mw = obj; else { MON_NOWEP(mtmp); impossible("bad monster weapon restore"); } } if (mtmp->isshk) restshk(mtmp, ghostly); if (mtmp->ispriest) restpriest(mtmp, ghostly); mtmp2 = mtmp; } if(first && mtmp2->nmon){ impossible("Restmonchn: error reading monchn."); mtmp2->nmon = 0; } return(first); } STATIC_OVL struct fruit * loadfruitchn(fd) int fd; { register struct fruit *flist, *fnext; flist = 0; while (fnext = newfruit(), mread(fd, (genericptr_t)fnext, sizeof *fnext), fnext->fid != 0) { fnext->nextf = flist; flist = fnext; } dealloc_fruit(fnext); return flist; } STATIC_OVL void freefruitchn(flist) register struct fruit *flist; { register struct fruit *fnext; while (flist) { fnext = flist->nextf; dealloc_fruit(flist); flist = fnext; } } STATIC_OVL void ghostfruit(otmp) register struct obj *otmp; { register struct fruit *oldf; for (oldf = oldfruit; oldf; oldf = oldf->nextf) if (oldf->fid == otmp->spe) break; if (!oldf) impossible("no old fruit?"); else otmp->spe = fruitadd(oldf->fname); } STATIC_OVL boolean restgamestate(fd, stuckid, steedid) register int fd; unsigned int *stuckid, *steedid; /* STEED */ { /* discover is actually flags.explore */ boolean remember_discover = discover; struct obj *otmp; int uid; mread(fd, (genericptr_t) &uid, sizeof uid); if (uid != getuid()) { /* strange ... */ /* for wizard mode, issue a reminder; for others, treat it as an attempt to cheat and refuse to restore this file */ pline("Saved game was not yours."); #ifdef WIZARD if (!wizard) #endif return FALSE; } mread(fd, (genericptr_t) &flags, sizeof(struct flag)); flags.bypasses = 0; /* never use the saved value of bypasses */ if (remember_discover) discover = remember_discover; role_init(); /* Reset the initial role, race, gender, and alignment */ #ifdef AMII_GRAPHICS amii_setpens(amii_numcolors); /* use colors from save file */ #endif mread(fd, (genericptr_t) &u, sizeof(struct you)); set_uasmon(); #ifdef CLIPPING cliparound(u.ux, u.uy); #endif if(u.uhp <= 0 && (!Upolyd || u.mh <= 0)) { u.ux = u.uy = 0; /* affects pline() [hence You()] */ You("were not healthy enough to survive restoration."); /* wiz1_level.dlevel is used by mklev.c to see if lots of stuff is * uninitialized, so we only have to set it and not the other stuff. */ wiz1_level.dlevel = 0; u.uz.dnum = 0; u.uz.dlevel = 1; return(FALSE); } /* this stuff comes after potential aborted restore attempts */ restore_timers(fd, RANGE_GLOBAL, FALSE, 0L); restore_light_sources(fd); invent = restobjchn(fd, FALSE, FALSE); migrating_objs = restobjchn(fd, FALSE, FALSE); migrating_mons = restmonchn(fd, FALSE); mread(fd, (genericptr_t) mvitals, sizeof(mvitals)); /* this comes after inventory has been loaded */ for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp->owornmask) setworn(otmp, otmp->owornmask); /* reset weapon so that player will get a reminder about "bashing" during next fight when bare-handed or wielding an unconventional item; for pick-axe, we aren't able to distinguish between having applied or wielded it, so be conservative and assume the former */ otmp = uwep; /* `uwep' usually init'd by setworn() in loop above */ uwep = 0; /* clear it and have setuwep() reinit */ setuwep(otmp); /* (don't need any null check here) */ if (!uwep || uwep->otyp == PICK_AXE || uwep->otyp == GRAPPLING_HOOK) unweapon = TRUE; restore_dungeon(fd); restlevchn(fd); mread(fd, (genericptr_t) &moves, sizeof moves); mread(fd, (genericptr_t) &monstermoves, sizeof monstermoves); mread(fd, (genericptr_t) &quest_status, sizeof(struct q_score)); mread(fd, (genericptr_t) spl_book, sizeof(struct spell) * (MAXSPELL + 1)); restore_artifacts(fd); restore_oracles(fd); if (u.ustuck) mread(fd, (genericptr_t) stuckid, sizeof (*stuckid)); #ifdef STEED if (u.usteed) mread(fd, (genericptr_t) steedid, sizeof (*steedid)); #endif mread(fd, (genericptr_t) pl_character, sizeof pl_character); mread(fd, (genericptr_t) pl_fruit, sizeof pl_fruit); mread(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit); freefruitchn(ffruit); /* clean up fruit(s) made by initoptions() */ ffruit = loadfruitchn(fd); restnames(fd); restore_waterlevel(fd); /* must come after all mons & objs are restored */ relink_timers(FALSE); relink_light_sources(FALSE); return(TRUE); } /* update game state pointers to those valid for the current level (so we * don't dereference a wild u.ustuck when saving the game state, for instance) */ STATIC_OVL void restlevelstate(stuckid, steedid) unsigned int stuckid, steedid; /* STEED */ { register struct monst *mtmp; if (stuckid) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == stuckid) break; if (!mtmp) panic("Cannot find the monster ustuck."); u.ustuck = mtmp; } #ifdef STEED if (steedid) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (mtmp->m_id == steedid) break; if (!mtmp) panic("Cannot find the monster usteed."); u.usteed = mtmp; remove_monster(mtmp->mx, mtmp->my); } #endif } /*ARGSUSED*/ /* fd used in MFLOPPY only */ STATIC_OVL int restlevelfile(fd, ltmp) register int fd; xchar ltmp; #if defined(macintosh) && (defined(__SC__) || defined(__MRC__)) # pragma unused(fd) #endif { register int nfd; char whynot[BUFSZ]; nfd = create_levelfile(ltmp, whynot); if (nfd < 0) { /* BUG: should suppress any attempt to write a panic save file if file creation is now failing... */ panic("restlevelfile: %s", whynot); } #ifdef MFLOPPY if (!savelev(nfd, ltmp, COUNT_SAVE)) { /* The savelev can't proceed because the size required * is greater than the available disk space. */ pline("Not enough space on `%s' to restore your game.", levels); /* Remove levels and bones that may have been created. */ (void) close(nfd); # ifdef AMIGA clearlocks(); # else eraseall(levels, alllevels); eraseall(levels, allbones); /* Perhaps the person would like to play without a * RAMdisk. */ if (ramdisk) { /* PlaywoRAMdisk may not return, but if it does * it is certain that ramdisk will be 0. */ playwoRAMdisk(); /* Rewind save file and try again */ (void) lseek(fd, (off_t)0, 0); (void) uptodate(fd, (char *)0); /* skip version */ return dorecover(fd); /* 0 or 1 */ } else { # endif pline("Be seeing you..."); terminate(EXIT_SUCCESS); # ifndef AMIGA } # endif } #endif bufon(nfd); savelev(nfd, ltmp, WRITE_SAVE | FREE_SAVE); bclose(nfd); return(2); } int dorecover(fd) register int fd; { unsigned int stuckid = 0, steedid = 0; /* not a register */ xchar ltmp; int rtmp; struct obj *otmp; #ifdef STORE_PLNAME_IN_FILE mread(fd, (genericptr_t) plname, PL_NSIZ); #endif restoring = TRUE; getlev(fd, 0, (xchar)0, FALSE); if (!restgamestate(fd, &stuckid, &steedid)) { display_nhwindow(WIN_MESSAGE, TRUE); savelev(-1, 0, FREE_SAVE); /* discard current level */ (void) close(fd); (void) delete_savefile(); restoring = FALSE; return(0); } restlevelstate(stuckid, steedid); #ifdef INSURANCE savestateinlock(); #endif rtmp = restlevelfile(fd, ledger_no(&u.uz)); if (rtmp < 2) return(rtmp); /* dorecover called recursively */ /* these pointers won't be valid while we're processing the * other levels, but they'll be reset again by restlevelstate() * afterwards, and in the meantime at least u.usteed may mislead * place_monster() on other levels */ u.ustuck = (struct monst *)0; #ifdef STEED u.usteed = (struct monst *)0; #endif #ifdef MICRO # ifdef AMII_GRAPHICS { extern struct window_procs amii_procs; if(windowprocs.win_init_nhwindows== amii_procs.win_init_nhwindows){ extern winid WIN_BASE; clear_nhwindow(WIN_BASE); /* hack until there's a hook for this */ } } # else clear_nhwindow(WIN_MAP); # endif clear_nhwindow(WIN_MESSAGE); You("return to level %d in %s%s.", depth(&u.uz), dungeons[u.uz.dnum].dname, flags.debug ? " while in debug mode" : flags.explore ? " while in explore mode" : ""); curs(WIN_MAP, 1, 1); dotcnt = 0; dotrow = 2; if (strncmpi("X11", windowprocs.name, 3)) putstr(WIN_MAP, 0, "Restoring:"); #endif while(1) { #ifdef ZEROCOMP if(mread(fd, (genericptr_t) <mp, sizeof ltmp) < 0) #else if(read(fd, (genericptr_t) <mp, sizeof ltmp) != sizeof ltmp) #endif break; getlev(fd, 0, ltmp, FALSE); #ifdef MICRO curs(WIN_MAP, 1+dotcnt++, dotrow); if (dotcnt >= (COLNO - 1)) { dotrow++; dotcnt = 0; } if (strncmpi("X11", windowprocs.name, 3)){ putstr(WIN_MAP, 0, "."); } mark_synch(); #endif rtmp = restlevelfile(fd, ltmp); if (rtmp < 2) return(rtmp); /* dorecover called recursively */ } #ifdef BSD (void) lseek(fd, 0L, 0); #else (void) lseek(fd, (off_t)0, 0); #endif (void) uptodate(fd, (char *)0); /* skip version info */ #ifdef STORE_PLNAME_IN_FILE mread(fd, (genericptr_t) plname, PL_NSIZ); #endif getlev(fd, 0, (xchar)0, FALSE); (void) close(fd); if (!wizard && !discover) (void) delete_savefile(); #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) assign_rogue_graphics(TRUE); #endif #ifdef USE_TILES substitute_tiles(&u.uz); #endif restlevelstate(stuckid, steedid); #ifdef MFLOPPY gameDiskPrompt(); #endif max_rank_sz(); /* to recompute mrank_sz (botl.c) */ /* take care of iron ball & chain */ for(otmp = fobj; otmp; otmp = otmp->nobj) if(otmp->owornmask) setworn(otmp, otmp->owornmask); /* in_use processing must be after: * + The inventory has been read so that freeinv() works. * + The current level has been restored so billing information * is available. */ inven_inuse(FALSE); load_qtlist(); /* re-load the quest text info */ reset_attribute_clock(); /* Set up the vision internals, after levl[] data is loaded */ /* but before docrt(). */ vision_reset(); vision_full_recalc = 1; /* recompute vision (not saved) */ run_timers(); /* expire all timers that have gone off while away */ docrt(); restoring = FALSE; clear_nhwindow(WIN_MESSAGE); program_state.something_worth_saving++; /* useful data now exists */ /* Success! */ welcome(FALSE); return(1); } void trickery(reason) char *reason; { pline("Strange, this map is not as I remember it."); pline("Somebody is trying some trickery here..."); pline("This game is void."); killer = reason; done(TRICKED); } void getlev(fd, pid, lev, ghostly) int fd, pid; xchar lev; boolean ghostly; { register struct trap *trap; register struct monst *mtmp; branch *br; int hpid; xchar dlvl; int x, y; #ifdef TOS short tlev; #endif if (ghostly) clear_id_mapping(); #if defined(MSDOS) || defined(OS2) setmode(fd, O_BINARY); #endif /* Load the old fruit info. We have to do it first, so the * information is available when restoring the objects. */ if (ghostly) oldfruit = loadfruitchn(fd); /* First some sanity checks */ mread(fd, (genericptr_t) &hpid, sizeof(hpid)); /* CHECK: This may prevent restoration */ #ifdef TOS mread(fd, (genericptr_t) &tlev, sizeof(tlev)); dlvl=tlev&0x00ff; #else mread(fd, (genericptr_t) &dlvl, sizeof(dlvl)); #endif if ((pid && pid != hpid) || (lev && dlvl != lev)) { char trickbuf[BUFSZ]; if (pid && pid != hpid) Sprintf(trickbuf, "PID (%d) doesn't match saved PID (%d)!", hpid, pid); else Sprintf(trickbuf, "This is level %d, not %d!", dlvl, lev); #ifdef WIZARD if (wizard) pline(trickbuf); #endif trickery(trickbuf); } #ifdef RLECOMP { short i, j; uchar len; struct rm r; #if defined(MAC) /* Suppress warning about used before set */ (void) memset((genericptr_t) &r, 0, sizeof(r)); #endif i = 0; j = 0; len = 0; while(i < ROWNO) { while(j < COLNO) { if(len > 0) { levl[j][i] = r; len -= 1; j += 1; } else { mread(fd, (genericptr_t)&len, sizeof(uchar)); mread(fd, (genericptr_t)&r, sizeof(struct rm)); } } j = 0; i += 1; } } #else mread(fd, (genericptr_t) levl, sizeof(levl)); #endif /* RLECOMP */ mread(fd, (genericptr_t)&omoves, sizeof(omoves)); mread(fd, (genericptr_t)&upstair, sizeof(stairway)); mread(fd, (genericptr_t)&dnstair, sizeof(stairway)); mread(fd, (genericptr_t)&upladder, sizeof(stairway)); mread(fd, (genericptr_t)&dnladder, sizeof(stairway)); mread(fd, (genericptr_t)&sstairs, sizeof(stairway)); mread(fd, (genericptr_t)&updest, sizeof(dest_area)); mread(fd, (genericptr_t)&dndest, sizeof(dest_area)); mread(fd, (genericptr_t)&level.flags, sizeof(level.flags)); mread(fd, (genericptr_t)doors, sizeof(doors)); rest_rooms(fd); /* No joke :-) */ if (nroom) doorindex = rooms[nroom - 1].fdoor + rooms[nroom - 1].doorct; else doorindex = 0; restore_timers(fd, RANGE_LEVEL, ghostly, monstermoves - omoves); restore_light_sources(fd); fmon = restmonchn(fd, ghostly); /* regenerate animals while on another level */ if (u.uz.dlevel) { register struct monst *mtmp2; for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (ghostly) { /* reset peaceful/malign relative to new character */ if(!mtmp->isshk) /* shopkeepers will reset based on name */ mtmp->mpeaceful = peace_minded(mtmp->data); set_malign(mtmp); } else if (monstermoves > omoves) mon_catchup_elapsed_time(mtmp, monstermoves - omoves); /* update shape-changers in case protection against them is different now than when the level was saved */ restore_cham(mtmp); } } rest_worm(fd); /* restore worm information */ ftrap = 0; while (trap = newtrap(), mread(fd, (genericptr_t)trap, sizeof(struct trap)), trap->tx != 0) { /* need "!= 0" to work around DICE 3.0 bug */ trap->ntrap = ftrap; ftrap = trap; } dealloc_trap(trap); fobj = restobjchn(fd, ghostly, FALSE); find_lev_obj(); /* restobjchn()'s `frozen' argument probably ought to be a callback routine so that we can check for objects being buried under ice */ level.buriedobjlist = restobjchn(fd, ghostly, FALSE); billobjs = restobjchn(fd, ghostly, FALSE); rest_engravings(fd); /* reset level.monsters for new level */ for (x = 0; x < COLNO; x++) for (y = 0; y < ROWNO; y++) level.monsters[x][y] = (struct monst *) 0; for (mtmp = level.monlist; mtmp; mtmp = mtmp->nmon) { if (mtmp->isshk) set_residency(mtmp, FALSE); place_monster(mtmp, mtmp->mx, mtmp->my); if (mtmp->wormno) place_wsegs(mtmp); } restdamage(fd, ghostly); rest_regions(fd, ghostly); if (ghostly) { /* Now get rid of all the temp fruits... */ freefruitchn(oldfruit), oldfruit = 0; if (lev > ledger_no(&medusa_level) && lev < ledger_no(&stronghold_level) && xdnstair == 0) { coord cc; mazexy(&cc); xdnstair = cc.x; ydnstair = cc.y; levl[cc.x][cc.y].typ = STAIRS; } br = Is_branchlev(&u.uz); if (br && u.uz.dlevel == 1) { d_level ltmp; if (on_level(&u.uz, &br->end1)) assign_level(<mp, &br->end2); else assign_level(<mp, &br->end1); switch(br->type) { case BR_STAIR: case BR_NO_END1: case BR_NO_END2: /* OK to assign to sstairs if it's not used */ assign_level(&sstairs.tolev, <mp); break; case BR_PORTAL: /* max of 1 portal per level */ { register struct trap *ttmp; for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) if (ttmp->ttyp == MAGIC_PORTAL) break; if (!ttmp) panic("getlev: need portal but none found"); assign_level(&ttmp->dst, <mp); } break; } } else if (!br) { /* Remove any dangling portals. */ register struct trap *ttmp; for (ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) if (ttmp->ttyp == MAGIC_PORTAL) { deltrap(ttmp); break; /* max of 1 portal/level */ } } } /* must come after all mons & objs are restored */ relink_timers(ghostly); relink_light_sources(ghostly); reset_oattached_mids(ghostly); if (ghostly) clear_id_mapping(); } /* Clear all structures for object and monster ID mapping. */ STATIC_OVL void clear_id_mapping() { struct bucket *curr; while ((curr = id_map) != 0) { id_map = curr->next; free((genericptr_t) curr); } n_ids_mapped = 0; } /* Add a mapping to the ID map. */ STATIC_OVL void add_id_mapping(gid, nid) unsigned gid, nid; { int idx; idx = n_ids_mapped % N_PER_BUCKET; /* idx is zero on first time through, as well as when a new bucket is */ /* needed */ if (idx == 0) { struct bucket *gnu = (struct bucket *) alloc(sizeof(struct bucket)); gnu->next = id_map; id_map = gnu; } id_map->map[idx].gid = gid; id_map->map[idx].nid = nid; n_ids_mapped++; } /* * Global routine to look up a mapping. If found, return TRUE and fill * in the new ID value. Otherwise, return false and return -1 in the new * ID. */ boolean lookup_id_mapping(gid, nidp) unsigned gid, *nidp; { int i; struct bucket *curr; if (n_ids_mapped) for (curr = id_map; curr; curr = curr->next) { /* first bucket might not be totally full */ if (curr == id_map) { i = n_ids_mapped % N_PER_BUCKET; if (i == 0) i = N_PER_BUCKET; } else i = N_PER_BUCKET; while (--i >= 0) if (gid == curr->map[i].gid) { *nidp = curr->map[i].nid; return TRUE; } } return FALSE; } STATIC_OVL void reset_oattached_mids(ghostly) boolean ghostly; { struct obj *otmp; unsigned oldid, nid; for (otmp = fobj; otmp; otmp = otmp->nobj) { if (ghostly && otmp->oattached == OATTACHED_MONST && otmp->oxlth) { struct monst *mtmp = (struct monst *)otmp->oextra; mtmp->m_id = 0; mtmp->mpeaceful = mtmp->mtame = 0; /* pet's owner died! */ } if (ghostly && otmp->oattached == OATTACHED_M_ID) { (void) memcpy((genericptr_t)&oldid, (genericptr_t)otmp->oextra, sizeof(oldid)); if (lookup_id_mapping(oldid, &nid)) (void) memcpy((genericptr_t)otmp->oextra, (genericptr_t)&nid, sizeof(nid)); else otmp->oattached = OATTACHED_NOTHING; } } } #ifdef ZEROCOMP #define RLESC '\0' /* Leading character for run of RLESC's */ #ifndef ZEROCOMP_BUFSIZ #define ZEROCOMP_BUFSIZ BUFSZ #endif static NEARDATA unsigned char inbuf[ZEROCOMP_BUFSIZ]; static NEARDATA unsigned short inbufp = 0; static NEARDATA unsigned short inbufsz = 0; static NEARDATA short inrunlength = -1; static NEARDATA int mreadfd; static int mgetc() { if (inbufp >= inbufsz) { inbufsz = read(mreadfd, (genericptr_t)inbuf, sizeof inbuf); if (!inbufsz) { if (inbufp > sizeof inbuf) error("EOF on file #%d.\n", mreadfd); inbufp = 1 + sizeof inbuf; /* exactly one warning :-) */ return -1; } inbufp = 0; } return inbuf[inbufp++]; } void minit() { inbufsz = 0; inbufp = 0; inrunlength = -1; } int mread(fd, buf, len) int fd; genericptr_t buf; register unsigned len; { /*register int readlen = 0;*/ if (fd < 0) error("Restore error; mread attempting to read file %d.", fd); mreadfd = fd; while (len--) { if (inrunlength > 0) { inrunlength--; *(*((char **)&buf))++ = '\0'; } else { register short ch = mgetc(); if (ch < 0) return -1; /*readlen;*/ if ((*(*(char **)&buf)++ = (char)ch) == RLESC) { inrunlength = mgetc(); } } /*readlen++;*/ } return 0; /*readlen;*/ } #else /* ZEROCOMP */ void minit() { return; } void mread(fd, buf, len) register int fd; register genericptr_t buf; register unsigned int len; { register int rlen; #if defined(BSD) || defined(ULTRIX) rlen = read(fd, buf, (int) len); if(rlen != len){ #else /* e.g. SYSV, __TURBOC__ */ rlen = read(fd, buf, (unsigned) len); if((unsigned)rlen != len){ #endif pline("Read %d instead of %u bytes.", rlen, len); if(restoring) { (void) close(fd); (void) delete_savefile(); error("Error restoring old game."); } panic("Error reading level file."); } } #endif /* ZEROCOMP */ /*restore.c*/ nethack-3.4.3/src/rip.c0100644000000000000000000001200207764735041013372 0ustar rootroot/* SCCS Id: @(#)rip.c 3.4 2003/01/08 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL void FDECL(center, (int, char *)); extern const char * const killed_by_prefix[]; /* from topten.c */ #if defined(TTY_GRAPHICS) || defined(X11_GRAPHICS) || defined(GEM_GRAPHICS) || defined(MSWIN_GRAPHICS) # define TEXT_TOMBSTONE #endif #if defined(mac) || defined(__BEOS__) || defined(WIN32_GRAPHICS) # ifndef TEXT_TOMBSTONE # define TEXT_TOMBSTONE # endif #endif #ifdef TEXT_TOMBSTONE #ifndef NH320_DEDICATION /* A normal tombstone for end of game display. */ static const char *rip_txt[] = { " ----------", " / \\", " / REST \\", " / IN \\", " / PEACE \\", " / \\", " | |", /* Name of player */ " | |", /* Amount of $ */ " | |", /* Type of death */ " | |", /* . */ " | |", /* . */ " | |", /* . */ " | 1001 |", /* Real year of death */ " *| * * * | *", " _________)/\\\\_//(\\/(/\\)/\\//\\/|_)_______", 0 }; #define STONE_LINE_CENT 28 /* char[] element of center of stone face */ #else /* NH320_DEDICATION */ /* NetHack 3.2.x displayed a dual tombstone as a tribute to Izchak. */ static const char *rip_txt[] = { " ---------- ----------", " / \\ / \\", " / REST \\ / This \\", " / IN \\ / release of \\", " / PEACE \\ / NetHack is \\", " / \\ / dedicated to \\", " | | | the memory of |", " | | | |", " | | | Izchak Miller |", " | | | 1935 - 1994 |", " | | | |", " | | | Ascended |", " | 1001 | | |", " * | * * * | * * | * * * | *", " _____)/\\|\\__//(\\/(/\\)/\\//\\/|_)________)/|\\\\_/_/(\\/(/\\)/\\/\\/|_)____", 0 }; #define STONE_LINE_CENT 19 /* char[] element of center of stone face */ #endif /* NH320_DEDICATION */ #define STONE_LINE_LEN 16 /* # chars that fit on one line * (note 1 ' ' border) */ #define NAME_LINE 6 /* *char[] line # for player name */ #define GOLD_LINE 7 /* *char[] line # for amount of gold */ #define DEATH_LINE 8 /* *char[] line # for death description */ #define YEAR_LINE 12 /* *char[] line # for year */ static char **rip; STATIC_OVL void center(line, text) int line; char *text; { register char *ip,*op; ip = text; op = &rip[line][STONE_LINE_CENT - ((strlen(text)+1)>>1)]; while(*ip) *op++ = *ip++; } void genl_outrip(tmpwin, how) winid tmpwin; int how; { register char **dp; register char *dpx; char buf[BUFSZ]; register int x; int line; rip = dp = (char **) alloc(sizeof(rip_txt)); for (x = 0; rip_txt[x]; x++) { dp[x] = (char *) alloc((unsigned int)(strlen(rip_txt[x]) + 1)); Strcpy(dp[x], rip_txt[x]); } dp[x] = (char *)0; /* Put name on stone */ Sprintf(buf, "%s", plname); buf[STONE_LINE_LEN] = 0; center(NAME_LINE, buf); /* Put $ on stone */ #ifndef GOLDOBJ Sprintf(buf, "%ld Au", u.ugold); #else Sprintf(buf, "%ld Au", done_money); #endif buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ center(GOLD_LINE, buf); /* Put together death description */ switch (killer_format) { default: impossible("bad killer format?"); case KILLED_BY_AN: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, an(killer)); break; case KILLED_BY: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, killer); break; case NO_KILLER_PREFIX: Strcpy(buf, killer); break; } /* Put death type on stone */ for (line=DEATH_LINE, dpx = buf; line STONE_LINE_LEN) { for(i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) if(dpx[i] == ' ') i0 = i; if(!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; center(line, dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx= &dpx[i0]; } else dpx= &dpx[i0+1]; } /* Put year on stone */ Sprintf(buf, "%4d", getyear()); center(YEAR_LINE, buf); putstr(tmpwin, 0, ""); for(; *dp; dp++) putstr(tmpwin, 0, *dp); putstr(tmpwin, 0, ""); putstr(tmpwin, 0, ""); for (x = 0; rip_txt[x]; x++) { free((genericptr_t)rip[x]); } free((genericptr_t)rip); rip = 0; } #endif /* TEXT_TOMBSTONE */ /*rip.c*/ nethack-3.4.3/src/rnd.c0100644000000000000000000000451707764735041013377 0ustar rootroot/* SCCS Id: @(#)rnd.c 3.4 1996/02/07 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* "Rand()"s definition is determined by [OS]conf.h */ #if defined(LINT) && defined(UNIX) /* rand() is long... */ extern int NDECL(rand); #define RND(x) (rand() % x) #else /* LINT */ # if defined(UNIX) || defined(RANDOM) #define RND(x) (int)(Rand() % (long)(x)) # else /* Good luck: the bottom order bits are cyclic. */ #define RND(x) (int)((Rand()>>3) % (x)) # endif #endif /* LINT */ #ifdef OVL0 int rn2(x) /* 0 <= rn2(x) < x */ register int x; { #ifdef DEBUG if (x <= 0) { impossible("rn2(%d) attempted", x); return(0); } x = RND(x); return(x); #else return(RND(x)); #endif } #endif /* OVL0 */ #ifdef OVLB int rnl(x) /* 0 <= rnl(x) < x; sometimes subtracting Luck */ register int x; /* good luck approaches 0, bad luck approaches (x-1) */ { register int i; #ifdef DEBUG if (x <= 0) { impossible("rnl(%d) attempted", x); return(0); } #endif i = RND(x); if (Luck && rn2(50 - Luck)) { i -= (x <= 15 && Luck >= -5 ? Luck/3 : Luck); if (i < 0) i = 0; else if (i >= x) i = x-1; } return i; } #endif /* OVLB */ #ifdef OVL0 int rnd(x) /* 1 <= rnd(x) <= x */ register int x; { #ifdef DEBUG if (x <= 0) { impossible("rnd(%d) attempted", x); return(1); } x = RND(x)+1; return(x); #else return(RND(x)+1); #endif } #endif /* OVL0 */ #ifdef OVL1 int d(n,x) /* n <= d(n,x) <= (n*x) */ register int n, x; { register int tmp = n; #ifdef DEBUG if (x < 0 || n < 0 || (x == 0 && n != 0)) { impossible("d(%d,%d) attempted", n, x); return(1); } #endif while(n--) tmp += RND(x); return(tmp); /* Alea iacta est. -- J.C. */ } #endif /* OVL1 */ #ifdef OVLB int rne(x) register int x; { register int tmp, utmp; utmp = (u.ulevel < 15) ? 5 : u.ulevel/3; tmp = 1; while (tmp < utmp && !rn2(x)) tmp++; return tmp; /* was: * tmp = 1; * while(!rn2(x)) tmp++; * return(min(tmp,(u.ulevel < 15) ? 5 : u.ulevel/3)); * which is clearer but less efficient and stands a vanishingly * small chance of overflowing tmp */ } int rnz(i) int i; { #ifdef LINT int x = i; int tmp = 1000; #else register long x = i; register long tmp = 1000; #endif tmp += rn2(1000); tmp *= rne(4); if (rn2(2)) { x *= tmp; x /= 1000; } else { x *= 1000; x /= tmp; } return((int)x); } #endif /* OVLB */ /*rnd.c*/ nethack-3.4.3/src/role.c0100644000000000000000000012303007764735041013545 0ustar rootroot/* SCCS Id: @(#)role.c 3.4 2003/01/08 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985-1999. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /*** Table of all roles ***/ /* According to AD&D, HD for some classes (ex. Wizard) should be smaller * (4-sided for wizards). But this is not AD&D, and using the AD&D * rule here produces an unplayable character. Thus I have used a minimum * of an 10-sided hit die for everything. Another AD&D change: wizards get * a minimum strength of 4 since without one you can't teleport or cast * spells. --KAA * * As the wizard has been updated (wizard patch 5 jun '96) their HD can be * brought closer into line with AD&D. This forces wizards to use magic more * and distance themselves from their attackers. --LSZ * * With the introduction of races, some hit points and energy * has been reallocated for each race. The values assigned * to the roles has been reduced by the amount allocated to * humans. --KMH * * God names use a leading underscore to flag goddesses. */ const struct Role roles[] = { { {"Archeologist", 0}, { {"Digger", 0}, {"Field Worker",0}, {"Investigator",0}, {"Exhumer", 0}, {"Excavator", 0}, {"Spelunker", 0}, {"Speleologist",0}, {"Collector", 0}, {"Curator", 0} }, "Quetzalcoatl", "Camaxtli", "Huhetotl", /* Central American */ "Arc", "the College of Archeology", "the Tomb of the Toltec Kings", PM_ARCHEOLOGIST, NON_PM, NON_PM, PM_LORD_CARNARVON, PM_STUDENT, PM_MINION_OF_HUHETOTL, NON_PM, PM_HUMAN_MUMMY, S_SNAKE, S_MUMMY, ART_ORB_OF_DETECTION, MH_HUMAN|MH_DWARF|MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 10, 10, 7, 7, 7 }, { 20, 20, 20, 10, 20, 10 }, /* Init Lower Higher */ { 11, 0, 0, 8, 1, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 },14, /* Energy */ 10, 5, 0, 2, 10, A_INT, SPE_MAGIC_MAPPING, -4 }, { {"Barbarian", 0}, { {"Plunderer", "Plunderess"}, {"Pillager", 0}, {"Bandit", 0}, {"Brigand", 0}, {"Raider", 0}, {"Reaver", 0}, {"Slayer", 0}, {"Chieftain", "Chieftainess"}, {"Conqueror", "Conqueress"} }, "Mitra", "Crom", "Set", /* Hyborian */ "Bar", "the Camp of the Duali Tribe", "the Duali Oasis", PM_BARBARIAN, NON_PM, NON_PM, PM_PELIAS, PM_CHIEFTAIN, PM_THOTH_AMON, PM_OGRE, PM_TROLL, S_OGRE, S_TROLL, ART_HEART_OF_AHRIMAN, MH_HUMAN|MH_ORC | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL|ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 16, 7, 7, 15, 16, 6 }, { 30, 6, 7, 20, 30, 7 }, /* Init Lower Higher */ { 14, 0, 0,10, 2, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 },10, /* Energy */ 10, 14, 0, 0, 8, A_INT, SPE_HASTE_SELF, -4 }, { {"Caveman", "Cavewoman"}, { {"Troglodyte", 0}, {"Aborigine", 0}, {"Wanderer", 0}, {"Vagrant", 0}, {"Wayfarer", 0}, {"Roamer", 0}, {"Nomad", 0}, {"Rover", 0}, {"Pioneer", 0} }, "Anu", "_Ishtar", "Anshar", /* Babylonian */ "Cav", "the Caves of the Ancestors", "the Dragon's Lair", PM_CAVEMAN, PM_CAVEWOMAN, PM_LITTLE_DOG, PM_SHAMAN_KARNOV, PM_NEANDERTHAL, PM_CHROMATIC_DRAGON, PM_BUGBEAR, PM_HILL_GIANT, S_HUMANOID, S_GIANT, ART_SCEPTRE_OF_MIGHT, MH_HUMAN|MH_DWARF|MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 10, 7, 7, 7, 8, 6 }, { 30, 6, 7, 20, 30, 7 }, /* Init Lower Higher */ { 14, 0, 0, 8, 2, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 },10, /* Energy */ 0, 12, 0, 1, 8, A_INT, SPE_DIG, -4 }, { {"Healer", 0}, { {"Rhizotomist", 0}, {"Empiric", 0}, {"Embalmer", 0}, {"Dresser", 0}, {"Medicus ossium", "Medica ossium"}, {"Herbalist", 0}, {"Magister", "Magistra"}, {"Physician", 0}, {"Chirurgeon", 0} }, "_Athena", "Hermes", "Poseidon", /* Greek */ "Hea", "the Temple of Epidaurus", "the Temple of Coeus", PM_HEALER, NON_PM, NON_PM, PM_HIPPOCRATES, PM_ATTENDANT, PM_CYCLOPS, PM_GIANT_RAT, PM_SNAKE, S_RODENT, S_YETI, ART_STAFF_OF_AESCULAPIUS, MH_HUMAN|MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 7, 13, 7, 11, 16 }, { 15, 20, 20, 15, 25, 5 }, /* Init Lower Higher */ { 11, 0, 0, 8, 1, 0 }, /* Hit points */ { 1, 4, 0, 1, 0, 2 },20, /* Energy */ 10, 3,-3, 2, 10, A_WIS, SPE_CURE_SICKNESS, -4 }, { {"Knight", 0}, { {"Gallant", 0}, {"Esquire", 0}, {"Bachelor", 0}, {"Sergeant", 0}, {"Knight", 0}, {"Banneret", 0}, {"Chevalier", "Chevaliere"}, {"Seignieur", "Dame"}, {"Paladin", 0} }, "Lugh", "_Brigit", "Manannan Mac Lir", /* Celtic */ "Kni", "Camelot Castle", "the Isle of Glass", PM_KNIGHT, NON_PM, PM_PONY, PM_KING_ARTHUR, PM_PAGE, PM_IXOTH, PM_QUASIT, PM_OCHRE_JELLY, S_IMP, S_JELLY, ART_MAGIC_MIRROR_OF_MERLIN, MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL, /* Str Int Wis Dex Con Cha */ { 13, 7, 14, 8, 10, 17 }, { 30, 15, 15, 10, 20, 10 }, /* Init Lower Higher */ { 14, 0, 0, 8, 2, 0 }, /* Hit points */ { 1, 4, 0, 1, 0, 2 },10, /* Energy */ 10, 8,-2, 0, 9, A_WIS, SPE_TURN_UNDEAD, -4 }, { {"Monk", 0}, { {"Candidate", 0}, {"Novice", 0}, {"Initiate", 0}, {"Student of Stones", 0}, {"Student of Waters", 0}, {"Student of Metals", 0}, {"Student of Winds", 0}, {"Student of Fire", 0}, {"Master", 0} }, "Shan Lai Ching", "Chih Sung-tzu", "Huan Ti", /* Chinese */ "Mon", "the Monastery of Chan-Sune", "the Monastery of the Earth-Lord", PM_MONK, NON_PM, NON_PM, PM_GRAND_MASTER, PM_ABBOT, PM_MASTER_KAEN, PM_EARTH_ELEMENTAL, PM_XORN, S_ELEMENTAL, S_XORN, ART_EYES_OF_THE_OVERWORLD, MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 10, 7, 8, 8, 7, 7 }, { 25, 10, 20, 20, 15, 10 }, /* Init Lower Higher */ { 12, 0, 0, 8, 1, 0 }, /* Hit points */ { 2, 2, 0, 2, 0, 2 },10, /* Energy */ 10, 8,-2, 2, 20, A_WIS, SPE_RESTORE_ABILITY, -4 }, { {"Priest", "Priestess"}, { {"Aspirant", 0}, {"Acolyte", 0}, {"Adept", 0}, {"Priest", "Priestess"}, {"Curate", 0}, {"Canon", "Canoness"}, {"Lama", 0}, {"Patriarch", "Matriarch"}, {"High Priest", "High Priestess"} }, 0, 0, 0, /* chosen randomly from among the other roles */ "Pri", "the Great Temple", "the Temple of Nalzok", PM_PRIEST, PM_PRIESTESS, NON_PM, PM_ARCH_PRIEST, PM_ACOLYTE, PM_NALZOK, PM_HUMAN_ZOMBIE, PM_WRAITH, S_ZOMBIE, S_WRAITH, ART_MITRE_OF_HOLINESS, MH_HUMAN|MH_ELF | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 7, 7, 10, 7, 7, 7 }, { 15, 10, 30, 15, 20, 10 }, /* Init Lower Higher */ { 12, 0, 0, 8, 1, 0 }, /* Hit points */ { 4, 3, 0, 2, 0, 2 },10, /* Energy */ 0, 3,-2, 2, 10, A_WIS, SPE_REMOVE_CURSE, -4 }, /* Note: Rogue precedes Ranger so that use of `-R' on the command line retains its traditional meaning. */ { {"Rogue", 0}, { {"Footpad", 0}, {"Cutpurse", 0}, {"Rogue", 0}, {"Pilferer", 0}, {"Robber", 0}, {"Burglar", 0}, {"Filcher", 0}, {"Magsman", "Magswoman"}, {"Thief", 0} }, "Issek", "Mog", "Kos", /* Nehwon */ "Rog", "the Thieves' Guild Hall", "the Assassins' Guild Hall", PM_ROGUE, NON_PM, NON_PM, PM_MASTER_OF_THIEVES, PM_THUG, PM_MASTER_ASSASSIN, PM_LEPRECHAUN, PM_GUARDIAN_NAGA, S_NYMPH, S_NAGA, ART_MASTER_KEY_OF_THIEVERY, MH_HUMAN|MH_ORC | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 7, 7, 7, 10, 7, 6 }, { 20, 10, 10, 30, 20, 10 }, /* Init Lower Higher */ { 10, 0, 0, 8, 1, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 },11, /* Energy */ 10, 8, 0, 1, 9, A_INT, SPE_DETECT_TREASURE, -4 }, { {"Ranger", 0}, { #if 0 /* OBSOLETE */ {"Edhel", "Elleth"}, {"Edhel", "Elleth"}, /* elf-maid */ {"Ohtar", "Ohtie"}, /* warrior */ {"Kano", /* commander (Q.) ['a] */ "Kanie"}, /* educated guess, until further research- SAC */ {"Arandur", /* king's servant, minister (Q.) - guess */ "Aranduriel"}, /* educated guess */ {"Hir", "Hiril"}, /* lord, lady (S.) ['ir] */ {"Aredhel", "Arwen"}, /* noble elf, maiden (S.) */ {"Ernil", "Elentariel"}, /* prince (S.), elf-maiden (Q.) */ {"Elentar", "Elentari"}, /* Star-king, -queen (Q.) */ "Solonor Thelandira", "Aerdrie Faenya", "Lolth", /* Elven */ #endif {"Tenderfoot", 0}, {"Lookout", 0}, {"Trailblazer", 0}, {"Reconnoiterer", "Reconnoiteress"}, {"Scout", 0}, {"Arbalester", 0}, /* One skilled at crossbows */ {"Archer", 0}, {"Sharpshooter", 0}, {"Marksman", "Markswoman"} }, "Mercury", "_Venus", "Mars", /* Roman/planets */ "Ran", "Orion's camp", "the cave of the wumpus", PM_RANGER, NON_PM, PM_LITTLE_DOG /* Orion & canis major */, PM_ORION, PM_HUNTER, PM_SCORPIUS, PM_FOREST_CENTAUR, PM_SCORPION, S_CENTAUR, S_SPIDER, ART_LONGBOW_OF_DIANA, MH_HUMAN|MH_ELF|MH_GNOME|MH_ORC | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL|ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 13, 13, 13, 9, 13, 7 }, { 30, 10, 10, 20, 20, 10 }, /* Init Lower Higher */ { 13, 0, 0, 6, 1, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 },12, /* Energy */ 10, 9, 2, 1, 10, A_INT, SPE_INVISIBILITY, -4 }, { {"Samurai", 0}, { {"Hatamoto", 0}, /* Banner Knight */ {"Ronin", 0}, /* no allegiance */ {"Ninja", "Kunoichi"}, /* secret society */ {"Joshu", 0}, /* heads a castle */ {"Ryoshu", 0}, /* has a territory */ {"Kokushu", 0}, /* heads a province */ {"Daimyo", 0}, /* a samurai lord */ {"Kuge", 0}, /* Noble of the Court */ {"Shogun", 0} },/* supreme commander, warlord */ "_Amaterasu Omikami", "Raijin", "Susanowo", /* Japanese */ "Sam", "the Castle of the Taro Clan", "the Shogun's Castle", PM_SAMURAI, NON_PM, PM_LITTLE_DOG, PM_LORD_SATO, PM_ROSHI, PM_ASHIKAGA_TAKAUJI, PM_WOLF, PM_STALKER, S_DOG, S_ELEMENTAL, ART_TSURUGI_OF_MURAMASA, MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL, /* Str Int Wis Dex Con Cha */ { 10, 8, 7, 10, 17, 6 }, { 30, 10, 8, 30, 14, 8 }, /* Init Lower Higher */ { 13, 0, 0, 8, 1, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 },11, /* Energy */ 10, 10, 0, 0, 8, A_INT, SPE_CLAIRVOYANCE, -4 }, #ifdef TOURIST { {"Tourist", 0}, { {"Rambler", 0}, {"Sightseer", 0}, {"Excursionist",0}, {"Peregrinator","Peregrinatrix"}, {"Traveler", 0}, {"Journeyer", 0}, {"Voyager", 0}, {"Explorer", 0}, {"Adventurer", 0} }, "Blind Io", "_The Lady", "Offler", /* Discworld */ "Tou", "Ankh-Morpork", "the Thieves' Guild Hall", PM_TOURIST, NON_PM, NON_PM, PM_TWOFLOWER, PM_GUIDE, PM_MASTER_OF_THIEVES, PM_GIANT_SPIDER, PM_FOREST_CENTAUR, S_SPIDER, S_CENTAUR, ART_YENDORIAN_EXPRESS_CARD, MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 7, 10, 6, 7, 7, 10 }, { 15, 10, 10, 15, 30, 20 }, /* Init Lower Higher */ { 8, 0, 0, 8, 0, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 },14, /* Energy */ 0, 5, 1, 2, 10, A_INT, SPE_CHARM_MONSTER, -4 }, #endif { {"Valkyrie", 0}, { {"Stripling", 0}, {"Skirmisher", 0}, {"Fighter", 0}, {"Man-at-arms", "Woman-at-arms"}, {"Warrior", 0}, {"Swashbuckler",0}, {"Hero", "Heroine"}, {"Champion", 0}, {"Lord", "Lady"} }, "Tyr", "Odin", "Loki", /* Norse */ "Val", "the Shrine of Destiny", "the cave of Surtur", PM_VALKYRIE, NON_PM, NON_PM /*PM_WINTER_WOLF_CUB*/, PM_NORN, PM_WARRIOR, PM_LORD_SURTUR, PM_FIRE_ANT, PM_FIRE_GIANT, S_ANT, S_GIANT, ART_ORB_OF_FATE, MH_HUMAN|MH_DWARF | ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL, /* Str Int Wis Dex Con Cha */ { 10, 7, 7, 7, 10, 7 }, { 30, 6, 7, 20, 30, 7 }, /* Init Lower Higher */ { 14, 0, 0, 8, 2, 0 }, /* Hit points */ { 1, 0, 0, 1, 0, 1 },10, /* Energy */ 0, 10,-2, 0, 9, A_WIS, SPE_CONE_OF_COLD, -4 }, { {"Wizard", 0}, { {"Evoker", 0}, {"Conjurer", 0}, {"Thaumaturge", 0}, {"Magician", 0}, {"Enchanter", "Enchantress"}, {"Sorcerer", "Sorceress"}, {"Necromancer", 0}, {"Wizard", 0}, {"Mage", 0} }, "Ptah", "Thoth", "Anhur", /* Egyptian */ "Wiz", "the Lonely Tower", "the Tower of Darkness", PM_WIZARD, NON_PM, PM_KITTEN, PM_NEFERET_THE_GREEN, PM_APPRENTICE, PM_DARK_ONE, PM_VAMPIRE_BAT, PM_XORN, S_BAT, S_WRAITH, ART_EYE_OF_THE_AETHIOPICA, MH_HUMAN|MH_ELF|MH_GNOME|MH_ORC | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL|ROLE_CHAOTIC, /* Str Int Wis Dex Con Cha */ { 7, 10, 7, 7, 7, 7 }, { 10, 30, 10, 20, 20, 10 }, /* Init Lower Higher */ { 10, 0, 0, 8, 1, 0 }, /* Hit points */ { 4, 3, 0, 2, 0, 3 },12, /* Energy */ 0, 1, 0, 3, 10, A_INT, SPE_MAGIC_MISSILE, -4 }, /* Array terminator */ {{0, 0}} }; /* The player's role, created at runtime from initial * choices. This may be munged in role_init(). */ struct Role urole = { {"Undefined", 0}, { {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0} }, "L", "N", "C", "Xxx", "home", "locate", NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, NON_PM, 0, 0, 0, 0, /* Str Int Wis Dex Con Cha */ { 7, 7, 7, 7, 7, 7 }, { 20, 15, 15, 20, 20, 10 }, /* Init Lower Higher */ { 10, 0, 0, 8, 1, 0 }, /* Hit points */ { 2, 0, 0, 2, 0, 3 },14, /* Energy */ 0, 10, 0, 0, 4, A_INT, 0, -3 }; /* Table of all races */ const struct Race races[] = { { "human", "human", "humanity", "Hum", {"man", "woman"}, PM_HUMAN, NON_PM, PM_HUMAN_MUMMY, PM_HUMAN_ZOMBIE, MH_HUMAN | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL|ROLE_NEUTRAL|ROLE_CHAOTIC, MH_HUMAN, 0, MH_GNOME|MH_ORC, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(100), 18, 18, 18, 18, 18 }, /* Init Lower Higher */ { 2, 0, 0, 2, 1, 0 }, /* Hit points */ { 1, 0, 2, 0, 2, 0 } /* Energy */ }, { "elf", "elven", "elvenkind", "Elf", {0, 0}, PM_ELF, NON_PM, PM_ELF_MUMMY, PM_ELF_ZOMBIE, MH_ELF | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC, MH_ELF, MH_ELF, MH_ORC, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { 18, 20, 20, 18, 16, 18 }, /* Init Lower Higher */ { 1, 0, 0, 1, 1, 0 }, /* Hit points */ { 2, 0, 3, 0, 3, 0 } /* Energy */ }, { "dwarf", "dwarven", "dwarvenkind", "Dwa", {0, 0}, PM_DWARF, NON_PM, PM_DWARF_MUMMY, PM_DWARF_ZOMBIE, MH_DWARF | ROLE_MALE|ROLE_FEMALE | ROLE_LAWFUL, MH_DWARF, MH_DWARF|MH_GNOME, MH_ORC, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(100), 16, 16, 20, 20, 16 }, /* Init Lower Higher */ { 4, 0, 0, 3, 2, 0 }, /* Hit points */ { 0, 0, 0, 0, 0, 0 } /* Energy */ }, { "gnome", "gnomish", "gnomehood", "Gno", {0, 0}, PM_GNOME, NON_PM, PM_GNOME_MUMMY, PM_GNOME_ZOMBIE, MH_GNOME | ROLE_MALE|ROLE_FEMALE | ROLE_NEUTRAL, MH_GNOME, MH_DWARF|MH_GNOME, MH_HUMAN, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, {STR18(50),19, 18, 18, 18, 18 }, /* Init Lower Higher */ { 1, 0, 0, 1, 0, 0 }, /* Hit points */ { 2, 0, 2, 0, 2, 0 } /* Energy */ }, { "orc", "orcish", "orcdom", "Orc", {0, 0}, PM_ORC, NON_PM, PM_ORC_MUMMY, PM_ORC_ZOMBIE, MH_ORC | ROLE_MALE|ROLE_FEMALE | ROLE_CHAOTIC, MH_ORC, 0, MH_HUMAN|MH_ELF|MH_DWARF, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, {STR18(50),16, 16, 18, 18, 16 }, /* Init Lower Higher */ { 1, 0, 0, 1, 0, 0 }, /* Hit points */ { 1, 0, 1, 0, 1, 0 } /* Energy */ }, /* Array terminator */ { 0, 0, 0, 0 }}; /* The player's race, created at runtime from initial * choices. This may be munged in role_init(). */ struct Race urace = { "something", "undefined", "something", "Xxx", {0, 0}, NON_PM, NON_PM, NON_PM, NON_PM, 0, 0, 0, 0, /* Str Int Wis Dex Con Cha */ { 3, 3, 3, 3, 3, 3 }, { STR18(100), 18, 18, 18, 18, 18 }, /* Init Lower Higher */ { 2, 0, 0, 2, 1, 0 }, /* Hit points */ { 1, 0, 2, 0, 2, 0 } /* Energy */ }; /* Table of all genders */ const struct Gender genders[] = { {"male", "he", "him", "his", "Mal", ROLE_MALE}, {"female", "she", "her", "her", "Fem", ROLE_FEMALE}, {"neuter", "it", "it", "its", "Ntr", ROLE_NEUTER} }; /* Table of all alignments */ const struct Align aligns[] = { {"law", "lawful", "Law", ROLE_LAWFUL, A_LAWFUL}, {"balance", "neutral", "Neu", ROLE_NEUTRAL, A_NEUTRAL}, {"chaos", "chaotic", "Cha", ROLE_CHAOTIC, A_CHAOTIC}, {"evil", "unaligned", "Una", 0, A_NONE} }; STATIC_DCL char * FDECL(promptsep, (char *, int)); STATIC_DCL int FDECL(role_gendercount, (int)); STATIC_DCL int FDECL(race_alignmentcount, (int)); /* used by str2XXX() */ static char NEARDATA randomstr[] = "random"; boolean validrole(rolenum) int rolenum; { return (rolenum >= 0 && rolenum < SIZE(roles)-1); } int randrole() { return (rn2(SIZE(roles)-1)); } int str2role(str) char *str; { int i, len; /* Is str valid? */ if (!str || !str[0]) return ROLE_NONE; /* Match as much of str as is provided */ len = strlen(str); for (i = 0; roles[i].name.m; i++) { /* Does it match the male name? */ if (!strncmpi(str, roles[i].name.m, len)) return i; /* Or the female name? */ if (roles[i].name.f && !strncmpi(str, roles[i].name.f, len)) return i; /* Or the filecode? */ if (!strcmpi(str, roles[i].filecode)) return i; } if ((len == 1 && (*str == '*' || *str == '@')) || !strncmpi(str, randomstr, len)) return ROLE_RANDOM; /* Couldn't find anything appropriate */ return ROLE_NONE; } boolean validrace(rolenum, racenum) int rolenum, racenum; { /* Assumes validrole */ return (racenum >= 0 && racenum < SIZE(races)-1 && (roles[rolenum].allow & races[racenum].allow & ROLE_RACEMASK)); } int randrace(rolenum) int rolenum; { int i, n = 0; /* Count the number of valid races */ for (i = 0; races[i].noun; i++) if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) n++; /* Pick a random race */ /* Use a factor of 100 in case of bad random number generators */ if (n) n = rn2(n*100)/100; for (i = 0; races[i].noun; i++) if (roles[rolenum].allow & races[i].allow & ROLE_RACEMASK) { if (n) n--; else return (i); } /* This role has no permitted races? */ return (rn2(SIZE(races)-1)); } int str2race(str) char *str; { int i, len; /* Is str valid? */ if (!str || !str[0]) return ROLE_NONE; /* Match as much of str as is provided */ len = strlen(str); for (i = 0; races[i].noun; i++) { /* Does it match the noun? */ if (!strncmpi(str, races[i].noun, len)) return i; /* Or the filecode? */ if (!strcmpi(str, races[i].filecode)) return i; } if ((len == 1 && (*str == '*' || *str == '@')) || !strncmpi(str, randomstr, len)) return ROLE_RANDOM; /* Couldn't find anything appropriate */ return ROLE_NONE; } boolean validgend(rolenum, racenum, gendnum) int rolenum, racenum, gendnum; { /* Assumes validrole and validrace */ return (gendnum >= 0 && gendnum < ROLE_GENDERS && (roles[rolenum].allow & races[racenum].allow & genders[gendnum].allow & ROLE_GENDMASK)); } int randgend(rolenum, racenum) int rolenum, racenum; { int i, n = 0; /* Count the number of valid genders */ for (i = 0; i < ROLE_GENDERS; i++) if (roles[rolenum].allow & races[racenum].allow & genders[i].allow & ROLE_GENDMASK) n++; /* Pick a random gender */ if (n) n = rn2(n); for (i = 0; i < ROLE_GENDERS; i++) if (roles[rolenum].allow & races[racenum].allow & genders[i].allow & ROLE_GENDMASK) { if (n) n--; else return (i); } /* This role/race has no permitted genders? */ return (rn2(ROLE_GENDERS)); } int str2gend(str) char *str; { int i, len; /* Is str valid? */ if (!str || !str[0]) return ROLE_NONE; /* Match as much of str as is provided */ len = strlen(str); for (i = 0; i < ROLE_GENDERS; i++) { /* Does it match the adjective? */ if (!strncmpi(str, genders[i].adj, len)) return i; /* Or the filecode? */ if (!strcmpi(str, genders[i].filecode)) return i; } if ((len == 1 && (*str == '*' || *str == '@')) || !strncmpi(str, randomstr, len)) return ROLE_RANDOM; /* Couldn't find anything appropriate */ return ROLE_NONE; } boolean validalign(rolenum, racenum, alignnum) int rolenum, racenum, alignnum; { /* Assumes validrole and validrace */ return (alignnum >= 0 && alignnum < ROLE_ALIGNS && (roles[rolenum].allow & races[racenum].allow & aligns[alignnum].allow & ROLE_ALIGNMASK)); } int randalign(rolenum, racenum) int rolenum, racenum; { int i, n = 0; /* Count the number of valid alignments */ for (i = 0; i < ROLE_ALIGNS; i++) if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow & ROLE_ALIGNMASK) n++; /* Pick a random alignment */ if (n) n = rn2(n); for (i = 0; i < ROLE_ALIGNS; i++) if (roles[rolenum].allow & races[racenum].allow & aligns[i].allow & ROLE_ALIGNMASK) { if (n) n--; else return (i); } /* This role/race has no permitted alignments? */ return (rn2(ROLE_ALIGNS)); } int str2align(str) char *str; { int i, len; /* Is str valid? */ if (!str || !str[0]) return ROLE_NONE; /* Match as much of str as is provided */ len = strlen(str); for (i = 0; i < ROLE_ALIGNS; i++) { /* Does it match the adjective? */ if (!strncmpi(str, aligns[i].adj, len)) return i; /* Or the filecode? */ if (!strcmpi(str, aligns[i].filecode)) return i; } if ((len == 1 && (*str == '*' || *str == '@')) || !strncmpi(str, randomstr, len)) return ROLE_RANDOM; /* Couldn't find anything appropriate */ return ROLE_NONE; } /* is rolenum compatible with any racenum/gendnum/alignnum constraints? */ boolean ok_role(rolenum, racenum, gendnum, alignnum) int rolenum, racenum, gendnum, alignnum; { int i; short allow; if (rolenum >= 0 && rolenum < SIZE(roles)-1) { allow = roles[rolenum].allow; if (racenum >= 0 && racenum < SIZE(races)-1 && !(allow & races[racenum].allow & ROLE_RACEMASK)) return FALSE; if (gendnum >= 0 && gendnum < ROLE_GENDERS && !(allow & genders[gendnum].allow & ROLE_GENDMASK)) return FALSE; if (alignnum >= 0 && alignnum < ROLE_ALIGNS && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) return FALSE; return TRUE; } else { for (i = 0; i < SIZE(roles)-1; i++) { allow = roles[i].allow; if (racenum >= 0 && racenum < SIZE(races)-1 && !(allow & races[racenum].allow & ROLE_RACEMASK)) continue; if (gendnum >= 0 && gendnum < ROLE_GENDERS && !(allow & genders[gendnum].allow & ROLE_GENDMASK)) continue; if (alignnum >= 0 && alignnum < ROLE_ALIGNS && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) continue; return TRUE; } return FALSE; } } /* pick a random role subject to any racenum/gendnum/alignnum constraints */ /* If pickhow == PICK_RIGID a role is returned only if there is */ /* a single possibility */ int pick_role(racenum, gendnum, alignnum, pickhow) int racenum, gendnum, alignnum, pickhow; { int i; int roles_ok = 0; for (i = 0; i < SIZE(roles)-1; i++) { if (ok_role(i, racenum, gendnum, alignnum)) roles_ok++; } if (roles_ok == 0 || (roles_ok > 1 && pickhow == PICK_RIGID)) return ROLE_NONE; roles_ok = rn2(roles_ok); for (i = 0; i < SIZE(roles)-1; i++) { if (ok_role(i, racenum, gendnum, alignnum)) { if (roles_ok == 0) return i; else roles_ok--; } } return ROLE_NONE; } /* is racenum compatible with any rolenum/gendnum/alignnum constraints? */ boolean ok_race(rolenum, racenum, gendnum, alignnum) int rolenum, racenum, gendnum, alignnum; { int i; short allow; if (racenum >= 0 && racenum < SIZE(races)-1) { allow = races[racenum].allow; if (rolenum >= 0 && rolenum < SIZE(roles)-1 && !(allow & roles[rolenum].allow & ROLE_RACEMASK)) return FALSE; if (gendnum >= 0 && gendnum < ROLE_GENDERS && !(allow & genders[gendnum].allow & ROLE_GENDMASK)) return FALSE; if (alignnum >= 0 && alignnum < ROLE_ALIGNS && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) return FALSE; return TRUE; } else { for (i = 0; i < SIZE(races)-1; i++) { allow = races[i].allow; if (rolenum >= 0 && rolenum < SIZE(roles)-1 && !(allow & roles[rolenum].allow & ROLE_RACEMASK)) continue; if (gendnum >= 0 && gendnum < ROLE_GENDERS && !(allow & genders[gendnum].allow & ROLE_GENDMASK)) continue; if (alignnum >= 0 && alignnum < ROLE_ALIGNS && !(allow & aligns[alignnum].allow & ROLE_ALIGNMASK)) continue; return TRUE; } return FALSE; } } /* pick a random race subject to any rolenum/gendnum/alignnum constraints */ /* If pickhow == PICK_RIGID a race is returned only if there is */ /* a single possibility */ int pick_race(rolenum, gendnum, alignnum, pickhow) int rolenum, gendnum, alignnum, pickhow; { int i; int races_ok = 0; for (i = 0; i < SIZE(races)-1; i++) { if (ok_race(rolenum, i, gendnum, alignnum)) races_ok++; } if (races_ok == 0 || (races_ok > 1 && pickhow == PICK_RIGID)) return ROLE_NONE; races_ok = rn2(races_ok); for (i = 0; i < SIZE(races)-1; i++) { if (ok_race(rolenum, i, gendnum, alignnum)) { if (races_ok == 0) return i; else races_ok--; } } return ROLE_NONE; } /* is gendnum compatible with any rolenum/racenum/alignnum constraints? */ /* gender and alignment are not comparable (and also not constrainable) */ boolean ok_gend(rolenum, racenum, gendnum, alignnum) int rolenum, racenum, gendnum, alignnum; { int i; short allow; if (gendnum >= 0 && gendnum < ROLE_GENDERS) { allow = genders[gendnum].allow; if (rolenum >= 0 && rolenum < SIZE(roles)-1 && !(allow & roles[rolenum].allow & ROLE_GENDMASK)) return FALSE; if (racenum >= 0 && racenum < SIZE(races)-1 && !(allow & races[racenum].allow & ROLE_GENDMASK)) return FALSE; return TRUE; } else { for (i = 0; i < ROLE_GENDERS; i++) { allow = genders[i].allow; if (rolenum >= 0 && rolenum < SIZE(roles)-1 && !(allow & roles[rolenum].allow & ROLE_GENDMASK)) continue; if (racenum >= 0 && racenum < SIZE(races)-1 && !(allow & races[racenum].allow & ROLE_GENDMASK)) continue; return TRUE; } return FALSE; } } /* pick a random gender subject to any rolenum/racenum/alignnum constraints */ /* gender and alignment are not comparable (and also not constrainable) */ /* If pickhow == PICK_RIGID a gender is returned only if there is */ /* a single possibility */ int pick_gend(rolenum, racenum, alignnum, pickhow) int rolenum, racenum, alignnum, pickhow; { int i; int gends_ok = 0; for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(rolenum, racenum, i, alignnum)) gends_ok++; } if (gends_ok == 0 || (gends_ok > 1 && pickhow == PICK_RIGID)) return ROLE_NONE; gends_ok = rn2(gends_ok); for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(rolenum, racenum, i, alignnum)) { if (gends_ok == 0) return i; else gends_ok--; } } return ROLE_NONE; } /* is alignnum compatible with any rolenum/racenum/gendnum constraints? */ /* alignment and gender are not comparable (and also not constrainable) */ boolean ok_align(rolenum, racenum, gendnum, alignnum) int rolenum, racenum, gendnum, alignnum; { int i; short allow; if (alignnum >= 0 && alignnum < ROLE_ALIGNS) { allow = aligns[alignnum].allow; if (rolenum >= 0 && rolenum < SIZE(roles)-1 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK)) return FALSE; if (racenum >= 0 && racenum < SIZE(races)-1 && !(allow & races[racenum].allow & ROLE_ALIGNMASK)) return FALSE; return TRUE; } else { for (i = 0; i < ROLE_ALIGNS; i++) { allow = races[i].allow; if (rolenum >= 0 && rolenum < SIZE(roles)-1 && !(allow & roles[rolenum].allow & ROLE_ALIGNMASK)) continue; if (racenum >= 0 && racenum < SIZE(races)-1 && !(allow & races[racenum].allow & ROLE_ALIGNMASK)) continue; return TRUE; } return FALSE; } } /* pick a random alignment subject to any rolenum/racenum/gendnum constraints */ /* alignment and gender are not comparable (and also not constrainable) */ /* If pickhow == PICK_RIGID an alignment is returned only if there is */ /* a single possibility */ int pick_align(rolenum, racenum, gendnum, pickhow) int rolenum, racenum, gendnum, pickhow; { int i; int aligns_ok = 0; for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(rolenum, racenum, gendnum, i)) aligns_ok++; } if (aligns_ok == 0 || (aligns_ok > 1 && pickhow == PICK_RIGID)) return ROLE_NONE; aligns_ok = rn2(aligns_ok); for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(rolenum, racenum, gendnum, i)) { if (aligns_ok == 0) return i; else aligns_ok--; } } return ROLE_NONE; } void rigid_role_checks() { /* Some roles are limited to a single race, alignment, or gender and * calling this routine prior to XXX_player_selection() will help * prevent an extraneous prompt that actually doesn't allow * you to choose anything further. Note the use of PICK_RIGID which * causes the pick_XX() routine to return a value only if there is one * single possible selection, otherwise it returns ROLE_NONE. * */ if (flags.initrole == ROLE_RANDOM) { /* If the role was explicitly specified as ROLE_RANDOM * via -uXXXX-@ then choose the role in here to narrow down * later choices. Pick a random role in this case. */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) flags.initrole = randrole(); } if (flags.initrole != ROLE_NONE) { if (flags.initrace == ROLE_NONE) flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RIGID); if (flags.initalign == ROLE_NONE) flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RIGID); if (flags.initgend == ROLE_NONE) flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RIGID); } } #define BP_ALIGN 0 #define BP_GEND 1 #define BP_RACE 2 #define BP_ROLE 3 #define NUM_BP 4 STATIC_VAR char pa[NUM_BP], post_attribs; STATIC_OVL char * promptsep(buf, num_post_attribs) char *buf; int num_post_attribs; { const char *conj = "and "; if (num_post_attribs > 1 && post_attribs < num_post_attribs && post_attribs > 1) Strcat(buf, ","); Strcat(buf, " "); --post_attribs; if (!post_attribs && num_post_attribs > 1) Strcat(buf, conj); return buf; } STATIC_OVL int role_gendercount(rolenum) int rolenum; { int gendcount = 0; if (validrole(rolenum)) { if (roles[rolenum].allow & ROLE_MALE) ++gendcount; if (roles[rolenum].allow & ROLE_FEMALE) ++gendcount; if (roles[rolenum].allow & ROLE_NEUTER) ++gendcount; } return gendcount; } STATIC_OVL int race_alignmentcount(racenum) int racenum; { int aligncount = 0; if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) { if (races[racenum].allow & ROLE_CHAOTIC) ++aligncount; if (races[racenum].allow & ROLE_LAWFUL) ++aligncount; if (races[racenum].allow & ROLE_NEUTRAL) ++aligncount; } return aligncount; } char * root_plselection_prompt(suppliedbuf, buflen, rolenum, racenum, gendnum, alignnum) char *suppliedbuf; int buflen, rolenum, racenum, gendnum, alignnum; { int k, gendercount = 0, aligncount = 0; char buf[BUFSZ]; static char err_ret[] = " character's"; boolean donefirst = FALSE; if (!suppliedbuf || buflen < 1) return err_ret; /* initialize these static variables each time this is called */ post_attribs = 0; for (k=0; k < NUM_BP; ++k) pa[k] = 0; buf[0] = '\0'; *suppliedbuf = '\0'; /* How many alignments are allowed for the desired race? */ if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) aligncount = race_alignmentcount(racenum); if (alignnum != ROLE_NONE && alignnum != ROLE_RANDOM) { /* if race specified, and multiple choice of alignments for it */ if ((racenum >= 0) && (aligncount > 1)) { if (donefirst) Strcat(buf, " "); Strcat(buf, aligns[alignnum].adj); donefirst = TRUE; } else { if (donefirst) Strcat(buf, " "); Strcat(buf, aligns[alignnum].adj); donefirst = TRUE; } } else { /* if alignment not specified, but race is specified and only one choice of alignment for that race then don't include it in the later list */ if ((((racenum != ROLE_NONE && racenum != ROLE_RANDOM) && ok_race(rolenum, racenum, gendnum, alignnum)) && (aligncount > 1)) || (racenum == ROLE_NONE || racenum == ROLE_RANDOM)) { pa[BP_ALIGN] = 1; post_attribs++; } } /* */ /* How many genders are allowed for the desired role? */ if (validrole(rolenum)) gendercount = role_gendercount(rolenum); if (gendnum != ROLE_NONE && gendnum != ROLE_RANDOM) { if (validrole(rolenum)) { /* if role specified, and multiple choice of genders for it, and name of role itself does not distinguish gender */ if ((rolenum != ROLE_NONE) && (gendercount > 1) && !roles[rolenum].name.f) { if (donefirst) Strcat(buf, " "); Strcat(buf, genders[gendnum].adj); donefirst = TRUE; } } else { if (donefirst) Strcat(buf, " "); Strcat(buf, genders[gendnum].adj); donefirst = TRUE; } } else { /* if gender not specified, but role is specified and only one choice of gender then don't include it in the later list */ if ((validrole(rolenum) && (gendercount > 1)) || !validrole(rolenum)) { pa[BP_GEND] = 1; post_attribs++; } } /* */ if (racenum != ROLE_NONE && racenum != ROLE_RANDOM) { if (validrole(rolenum) && ok_race(rolenum, racenum, gendnum, alignnum)) { if (donefirst) Strcat(buf, " "); Strcat(buf, (rolenum == ROLE_NONE) ? races[racenum].noun : races[racenum].adj); donefirst = TRUE; } else if (!validrole(rolenum)) { if (donefirst) Strcat(buf, " "); Strcat(buf, races[racenum].noun); donefirst = TRUE; } else { pa[BP_RACE] = 1; post_attribs++; } } else { pa[BP_RACE] = 1; post_attribs++; } /* || */ if (validrole(rolenum)) { if (donefirst) Strcat(buf, " "); if (gendnum != ROLE_NONE) { if (gendnum == 1 && roles[rolenum].name.f) Strcat(buf, roles[rolenum].name.f); else Strcat(buf, roles[rolenum].name.m); } else { if (roles[rolenum].name.f) { Strcat(buf, roles[rolenum].name.m); Strcat(buf, "/"); Strcat(buf, roles[rolenum].name.f); } else Strcat(buf, roles[rolenum].name.m); } donefirst = TRUE; } else if (rolenum == ROLE_NONE) { pa[BP_ROLE] = 1; post_attribs++; } if ((racenum == ROLE_NONE || racenum == ROLE_RANDOM) && !validrole(rolenum)) { if (donefirst) Strcat(buf, " "); Strcat(buf, "character"); donefirst = TRUE; } /* || * || */ if (buflen > (int) (strlen(buf) + 1)) { Strcpy(suppliedbuf, buf); return suppliedbuf; } else return err_ret; } char * build_plselection_prompt(buf, buflen, rolenum, racenum, gendnum, alignnum) char *buf; int buflen, rolenum, racenum, gendnum, alignnum; { const char *defprompt = "Shall I pick a character for you? [ynq] "; int num_post_attribs = 0; char tmpbuf[BUFSZ]; if (buflen < QBUFSZ) return (char *)defprompt; Strcpy(tmpbuf, "Shall I pick "); if (racenum != ROLE_NONE || validrole(rolenum)) Strcat(tmpbuf, "your "); else { Strcat(tmpbuf, "a "); } /* */ (void) root_plselection_prompt(eos(tmpbuf), buflen - strlen(tmpbuf), rolenum, racenum, gendnum, alignnum); Sprintf(buf, "%s", s_suffix(tmpbuf)); /* buf should now be: * < your lawful female gnomish cavewoman's> || * || * * Now append the post attributes to it */ num_post_attribs = post_attribs; if (post_attribs) { if (pa[BP_RACE]) { (void) promptsep(eos(buf), num_post_attribs); Strcat(buf, "race"); } if (pa[BP_ROLE]) { (void) promptsep(eos(buf), num_post_attribs); Strcat(buf, "role"); } if (pa[BP_GEND]) { (void) promptsep(eos(buf), num_post_attribs); Strcat(buf, "gender"); } if (pa[BP_ALIGN]) { (void) promptsep(eos(buf), num_post_attribs); Strcat(buf, "alignment"); } } Strcat(buf, " for you? [ynq] "); return buf; } #undef BP_ALIGN #undef BP_GEND #undef BP_RACE #undef BP_ROLE #undef NUM_BP void plnamesuffix() { char *sptr, *eptr; int i; /* Look for tokens delimited by '-' */ if ((eptr = index(plname, '-')) != (char *) 0) *eptr++ = '\0'; while (eptr) { /* Isolate the next token */ sptr = eptr; if ((eptr = index(sptr, '-')) != (char *)0) *eptr++ = '\0'; /* Try to match it to something */ if ((i = str2role(sptr)) != ROLE_NONE) flags.initrole = i; else if ((i = str2race(sptr)) != ROLE_NONE) flags.initrace = i; else if ((i = str2gend(sptr)) != ROLE_NONE) flags.initgend = i; else if ((i = str2align(sptr)) != ROLE_NONE) flags.initalign = i; } if(!plname[0]) { askname(); plnamesuffix(); } /* commas in the plname confuse the record file, convert to spaces */ for (sptr = plname; *sptr; sptr++) { if (*sptr == ',') *sptr = ' '; } } /* * Special setup modifications here: * * Unfortunately, this is going to have to be done * on each newgame or restore, because you lose the permonst mods * across a save/restore. :-) * * 1 - The Rogue Leader is the Tourist Nemesis. * 2 - Priests start with a random alignment - convert the leader and * guardians here. * 3 - Elves can have one of two different leaders, but can't work it * out here because it requires hacking the level file data (see * sp_lev.c). * * This code also replaces quest_init(). */ void role_init() { int alignmnt; /* Strip the role letter out of the player name. * This is included for backwards compatibility. */ plnamesuffix(); /* Check for a valid role. Try flags.initrole first. */ if (!validrole(flags.initrole)) { /* Try the player letter second */ if ((flags.initrole = str2role(pl_character)) < 0) /* None specified; pick a random role */ flags.initrole = randrole(); } /* We now have a valid role index. Copy the role name back. */ /* This should become OBSOLETE */ Strcpy(pl_character, roles[flags.initrole].name.m); pl_character[PL_CSIZ-1] = '\0'; /* Check for a valid race */ if (!validrace(flags.initrole, flags.initrace)) flags.initrace = randrace(flags.initrole); /* Check for a valid gender. If new game, check both initgend * and female. On restore, assume flags.female is correct. */ if (flags.pantheon == -1) { /* new game */ if (!validgend(flags.initrole, flags.initrace, flags.female)) flags.female = !flags.female; } if (!validgend(flags.initrole, flags.initrace, flags.initgend)) /* Note that there is no way to check for an unspecified gender. */ flags.initgend = flags.female; /* Check for a valid alignment */ if (!validalign(flags.initrole, flags.initrace, flags.initalign)) /* Pick a random alignment */ flags.initalign = randalign(flags.initrole, flags.initrace); alignmnt = aligns[flags.initalign].value; /* Initialize urole and urace */ urole = roles[flags.initrole]; urace = races[flags.initrace]; /* Fix up the quest leader */ if (urole.ldrnum != NON_PM) { mons[urole.ldrnum].msound = MS_LEADER; mons[urole.ldrnum].mflags2 |= (M2_PEACEFUL); mons[urole.ldrnum].mflags3 |= M3_CLOSE; mons[urole.ldrnum].maligntyp = alignmnt * 3; } /* Fix up the quest guardians */ if (urole.guardnum != NON_PM) { mons[urole.guardnum].mflags2 |= (M2_PEACEFUL); mons[urole.guardnum].maligntyp = alignmnt * 3; } /* Fix up the quest nemesis */ if (urole.neminum != NON_PM) { mons[urole.neminum].msound = MS_NEMESIS; mons[urole.neminum].mflags2 &= ~(M2_PEACEFUL); mons[urole.neminum].mflags2 |= (M2_NASTY|M2_STALK|M2_HOSTILE); mons[urole.neminum].mflags3 |= M3_WANTSARTI | M3_WAITFORU; } /* Fix up the god names */ if (flags.pantheon == -1) { /* new game */ flags.pantheon = flags.initrole; /* use own gods */ while (!roles[flags.pantheon].lgod) /* unless they're missing */ flags.pantheon = randrole(); } if (!urole.lgod) { urole.lgod = roles[flags.pantheon].lgod; urole.ngod = roles[flags.pantheon].ngod; urole.cgod = roles[flags.pantheon].cgod; } /* Fix up infravision */ if (mons[urace.malenum].mflags3 & M3_INFRAVISION) { /* although an infravision intrinsic is possible, infravision * is purely a property of the physical race. This means that we * must put the infravision flag in the player's current race * (either that or have separate permonst entries for * elven/non-elven members of each class). The side effect is that * all NPCs of that class will have (probably bogus) infravision, * but since infravision has no effect for NPCs anyway we can * ignore this. */ mons[urole.malenum].mflags3 |= M3_INFRAVISION; if (urole.femalenum != NON_PM) mons[urole.femalenum].mflags3 |= M3_INFRAVISION; } /* Artifacts are fixed in hack_artifacts() */ /* Success! */ return; } const char * Hello(mtmp) struct monst *mtmp; { switch (Role_switch) { case PM_KNIGHT: return ("Salutations"); /* Olde English */ case PM_SAMURAI: return (mtmp && mtmp->data == &mons[PM_SHOPKEEPER] ? "Irasshaimase" : "Konnichi wa"); /* Japanese */ #ifdef TOURIST case PM_TOURIST: return ("Aloha"); /* Hawaiian */ #endif case PM_VALKYRIE: return ( #ifdef MAIL mtmp && mtmp->data == &mons[PM_MAIL_DAEMON] ? "Hallo" : #endif "Velkommen"); /* Norse */ default: return ("Hello"); } } const char * Goodbye() { switch (Role_switch) { case PM_KNIGHT: return ("Fare thee well"); /* Olde English */ case PM_SAMURAI: return ("Sayonara"); /* Japanese */ #ifdef TOURIST case PM_TOURIST: return ("Aloha"); /* Hawaiian */ #endif case PM_VALKYRIE: return ("Farvel"); /* Norse */ default: return ("Goodbye"); } } /* role.c */ nethack-3.4.3/src/rumors.c0100644000000000000000000002531507764735041014142 0ustar rootroot/* SCCS Id: @(#)rumors.c 3.4 1996/04/20 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #include "dlb.h" /* [note: this comment is fairly old, but still accurate for 3.1] * Rumors have been entirely rewritten to speed up the access. This is * essential when working from floppies. Using fseek() the way that's done * here means rumors following longer rumors are output more often than those * following shorter rumors. Also, you may see the same rumor more than once * in a particular game (although the odds are highly against it), but * this also happens with real fortune cookies. -dgk */ /* 3.1 * The rumors file consists of a "do not edit" line, a hexadecimal number * giving the number of bytes of useful/true rumors, followed by those * true rumors (one per line), followed by the useless/false/misleading/cute * rumors (also one per line). Number of bytes of untrue rumors is derived * via fseek(EOF)+ftell(). * * The oracles file consists of a "do not edit" comment, a decimal count N * and set of N+1 hexadecimal fseek offsets, followed by N multiple-line * records, separated by "---" lines. The first oracle is a special case, * and placed there by 'makedefs'. */ STATIC_DCL void FDECL(init_rumors, (dlb *)); STATIC_DCL void FDECL(init_oracles, (dlb *)); static long true_rumor_start, true_rumor_size, true_rumor_end, false_rumor_start, false_rumor_size, false_rumor_end; static int oracle_flg = 0; /* -1=>don't use, 0=>need init, 1=>init done */ static unsigned oracle_cnt = 0; static long *oracle_loc = 0; STATIC_OVL void init_rumors(fp) dlb *fp; { char line[BUFSZ]; (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment */ (void) dlb_fgets(line, sizeof line, fp); if (sscanf(line, "%6lx\n", &true_rumor_size) == 1 && true_rumor_size > 0L) { (void) dlb_fseek(fp, 0L, SEEK_CUR); true_rumor_start = dlb_ftell(fp); true_rumor_end = true_rumor_start + true_rumor_size; (void) dlb_fseek(fp, 0L, SEEK_END); false_rumor_end = dlb_ftell(fp); false_rumor_start = true_rumor_end; /* ok, so it's redundant... */ false_rumor_size = false_rumor_end - false_rumor_start; } else true_rumor_size = -1L; /* init failed */ } /* exclude_cookie is a hack used because we sometimes want to get rumors in a * context where messages such as "You swallowed the fortune!" that refer to * cookies should not appear. This has no effect for true rumors since none * of them contain such references anyway. */ char * getrumor(truth, rumor_buf, exclude_cookie) int truth; /* 1=true, -1=false, 0=either */ char *rumor_buf; boolean exclude_cookie; { dlb *rumors; long tidbit, beginning; char *endp, line[BUFSZ], xbuf[BUFSZ]; rumor_buf[0] = '\0'; if (true_rumor_size < 0L) /* we couldn't open RUMORFILE */ return rumor_buf; rumors = dlb_fopen(RUMORFILE, "r"); if (rumors) { int count = 0; int adjtruth; do { rumor_buf[0] = '\0'; if (true_rumor_size == 0L) { /* if this is 1st outrumor() */ init_rumors(rumors); if (true_rumor_size < 0L) { /* init failed */ Sprintf(rumor_buf, "Error reading \"%.80s\".", RUMORFILE); return rumor_buf; } } /* * input: 1 0 -1 * rn2 \ +1 2=T 1=T 0=F * adj./ +0 1=T 0=F -1=F */ switch (adjtruth = truth + rn2(2)) { case 2: /*(might let a bogus input arg sneak thru)*/ case 1: beginning = true_rumor_start; tidbit = Rand() % true_rumor_size; break; case 0: /* once here, 0 => false rather than "either"*/ case -1: beginning = false_rumor_start; tidbit = Rand() % false_rumor_size; break; default: impossible("strange truth value for rumor"); return strcpy(rumor_buf, "Oops..."); } (void) dlb_fseek(rumors, beginning + tidbit, SEEK_SET); (void) dlb_fgets(line, sizeof line, rumors); if (!dlb_fgets(line, sizeof line, rumors) || (adjtruth > 0 && dlb_ftell(rumors) > true_rumor_end)) { /* reached end of rumors -- go back to beginning */ (void) dlb_fseek(rumors, beginning, SEEK_SET); (void) dlb_fgets(line, sizeof line, rumors); } if ((endp = index(line, '\n')) != 0) *endp = 0; Strcat(rumor_buf, xcrypt(line, xbuf)); } while(count++ < 50 && exclude_cookie && (strstri(rumor_buf, "fortune") || strstri(rumor_buf, "pity"))); (void) dlb_fclose(rumors); if (count >= 50) impossible("Can't find non-cookie rumor?"); else exercise(A_WIS, (adjtruth > 0)); } else { pline("Can't open rumors file!"); true_rumor_size = -1; /* don't try to open it again */ } return rumor_buf; } void outrumor(truth, mechanism) int truth; /* 1=true, -1=false, 0=either */ int mechanism; { static const char fortune_msg[] = "This cookie has a scrap of paper inside."; const char *line; char buf[BUFSZ]; boolean reading = (mechanism == BY_COOKIE || mechanism == BY_PAPER); if (reading) { /* deal with various things that prevent reading */ if (is_fainted() && mechanism == BY_COOKIE) return; else if (Blind) { if (mechanism == BY_COOKIE) pline(fortune_msg); pline("What a pity that you cannot read it!"); return; } } line = getrumor(truth, buf, reading ? FALSE : TRUE); if (!*line) line = "NetHack rumors file closed for renovation."; switch (mechanism) { case BY_ORACLE: /* Oracle delivers the rumor */ pline("True to her word, the Oracle %ssays: ", (!rn2(4) ? "offhandedly " : (!rn2(3) ? "casually " : (rn2(2) ? "nonchalantly " : "")))); verbalize("%s", line); exercise(A_WIS, TRUE); return; case BY_COOKIE: pline(fortune_msg); /* FALLTHRU */ case BY_PAPER: pline("It reads:"); break; } pline("%s", line); } STATIC_OVL void init_oracles(fp) dlb *fp; { register int i; char line[BUFSZ]; int cnt = 0; /* this assumes we're only called once */ (void) dlb_fgets(line, sizeof line, fp); /* skip "don't edit" comment*/ (void) dlb_fgets(line, sizeof line, fp); if (sscanf(line, "%5d\n", &cnt) == 1 && cnt > 0) { oracle_cnt = (unsigned) cnt; oracle_loc = (long *) alloc((unsigned)cnt * sizeof (long)); for (i = 0; i < cnt; i++) { (void) dlb_fgets(line, sizeof line, fp); (void) sscanf(line, "%5lx\n", &oracle_loc[i]); } } return; } void save_oracles(fd, mode) int fd, mode; { if (perform_bwrite(mode)) { bwrite(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt); if (oracle_cnt) bwrite(fd, (genericptr_t)oracle_loc, oracle_cnt*sizeof (long)); } if (release_data(mode)) { if (oracle_cnt) { free((genericptr_t)oracle_loc); oracle_loc = 0, oracle_cnt = 0, oracle_flg = 0; } } } void restore_oracles(fd) int fd; { mread(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt); if (oracle_cnt) { oracle_loc = (long *) alloc(oracle_cnt * sizeof (long)); mread(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof (long)); oracle_flg = 1; /* no need to call init_oracles() */ } } void outoracle(special, delphi) boolean special; boolean delphi; { char line[COLNO]; char *endp; dlb *oracles; int oracle_idx; char xbuf[BUFSZ]; if(oracle_flg < 0 || /* couldn't open ORACLEFILE */ (oracle_flg > 0 && oracle_cnt == 0)) /* oracles already exhausted */ return; oracles = dlb_fopen(ORACLEFILE, "r"); if (oracles) { winid tmpwin; if (oracle_flg == 0) { /* if this is the first outoracle() */ init_oracles(oracles); oracle_flg = 1; if (oracle_cnt == 0) return; } /* oracle_loc[0] is the special oracle; */ /* oracle_loc[1..oracle_cnt-1] are normal ones */ if (oracle_cnt <= 1 && !special) return; /*(shouldn't happen)*/ oracle_idx = special ? 0 : rnd((int) oracle_cnt - 1); (void) dlb_fseek(oracles, oracle_loc[oracle_idx], SEEK_SET); if (!special) oracle_loc[oracle_idx] = oracle_loc[--oracle_cnt]; tmpwin = create_nhwindow(NHW_TEXT); if (delphi) putstr(tmpwin, 0, special ? "The Oracle scornfully takes all your money and says:" : "The Oracle meditates for a moment and then intones:"); else putstr(tmpwin, 0, "The message reads:"); putstr(tmpwin, 0, ""); while(dlb_fgets(line, COLNO, oracles) && strcmp(line,"---\n")) { if ((endp = index(line, '\n')) != 0) *endp = 0; putstr(tmpwin, 0, xcrypt(line, xbuf)); } display_nhwindow(tmpwin, TRUE); destroy_nhwindow(tmpwin); (void) dlb_fclose(oracles); } else { pline("Can't open oracles file!"); oracle_flg = -1; /* don't try to open it again */ } } int doconsult(oracl) register struct monst *oracl; { #ifdef GOLDOBJ long umoney = money_cnt(invent); #endif int u_pay, minor_cost = 50, major_cost = 500 + 50 * u.ulevel; int add_xpts; char qbuf[QBUFSZ]; multi = 0; if (!oracl) { There("is no one here to consult."); return 0; } else if (!oracl->mpeaceful) { pline("%s is in no mood for consultations.", Monnam(oracl)); return 0; #ifndef GOLDOBJ } else if (!u.ugold) { #else } else if (!umoney) { #endif You("have no money."); return 0; } Sprintf(qbuf, "\"Wilt thou settle for a minor consultation?\" (%d %s)", minor_cost, currency((long)minor_cost)); switch (ynq(qbuf)) { default: case 'q': return 0; case 'y': #ifndef GOLDOBJ if (u.ugold < (long)minor_cost) { #else if (umoney < (long)minor_cost) { #endif You("don't even have enough money for that!"); return 0; } u_pay = minor_cost; break; case 'n': #ifndef GOLDOBJ if (u.ugold <= (long)minor_cost || /* don't even ask */ #else if (umoney <= (long)minor_cost || /* don't even ask */ #endif (oracle_cnt == 1 || oracle_flg < 0)) return 0; Sprintf(qbuf, "\"Then dost thou desire a major one?\" (%d %s)", major_cost, currency((long)major_cost)); if (yn(qbuf) != 'y') return 0; #ifndef GOLDOBJ u_pay = (u.ugold < (long)major_cost ? (int)u.ugold : major_cost); #else u_pay = (umoney < (long)major_cost ? (int)umoney : major_cost); #endif break; } #ifndef GOLDOBJ u.ugold -= (long)u_pay; oracl->mgold += (long)u_pay; #else money2mon(oracl, (long)u_pay); #endif flags.botl = 1; add_xpts = 0; /* first oracle of each type gives experience points */ if (u_pay == minor_cost) { outrumor(1, BY_ORACLE); if (!u.uevent.minor_oracle) add_xpts = u_pay / (u.uevent.major_oracle ? 25 : 10); /* 5 pts if very 1st, or 2 pts if major already done */ u.uevent.minor_oracle = TRUE; } else { boolean cheapskate = u_pay < major_cost; outoracle(cheapskate, TRUE); if (!cheapskate && !u.uevent.major_oracle) add_xpts = u_pay / (u.uevent.minor_oracle ? 25 : 10); /* ~100 pts if very 1st, ~40 pts if minor already done */ u.uevent.major_oracle = TRUE; exercise(A_WIS, !cheapskate); } if (add_xpts) { more_experienced(add_xpts, u_pay/50); newexplevel(); } return 1; } /*rumors.c*/ nethack-3.4.3/src/save.c0100644000000000000000000006546407764735041013562 0ustar rootroot/* SCCS Id: @(#)save.c 3.4 2003/11/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #include "quest.h" #ifndef NO_SIGNAL #include #endif #if !defined(LSC) && !defined(O_WRONLY) && !defined(AZTEC_C) #include #endif #ifdef MFLOPPY long bytes_counted; static int count_only; #endif #ifdef MICRO int dotcnt, dotrow; /* also used in restore */ #endif #ifdef ZEROCOMP STATIC_DCL void FDECL(bputc, (int)); #endif STATIC_DCL void FDECL(savelevchn, (int,int)); STATIC_DCL void FDECL(savedamage, (int,int)); STATIC_DCL void FDECL(saveobjchn, (int,struct obj *,int)); STATIC_DCL void FDECL(savemonchn, (int,struct monst *,int)); STATIC_DCL void FDECL(savetrapchn, (int,struct trap *,int)); STATIC_DCL void FDECL(savegamestate, (int,int)); #ifdef MFLOPPY STATIC_DCL void FDECL(savelev0, (int,XCHAR_P,int)); STATIC_DCL boolean NDECL(swapout_oldest); STATIC_DCL void FDECL(copyfile, (char *,char *)); #endif /* MFLOPPY */ #ifdef GCC_WARN static long nulls[10]; #else #define nulls nul #endif #if defined(UNIX) || defined(VMS) || defined(__EMX__) || defined(WIN32) #define HUP if (!program_state.done_hup) #else #define HUP #endif /* need to preserve these during save to avoid accessing freed memory */ static unsigned ustuck_id = 0, usteed_id = 0; int dosave() { clear_nhwindow(WIN_MESSAGE); if(yn("Really save?") == 'n') { clear_nhwindow(WIN_MESSAGE); if(multi > 0) nomul(0); } else { clear_nhwindow(WIN_MESSAGE); pline("Saving..."); #if defined(UNIX) || defined(VMS) || defined(__EMX__) program_state.done_hup = 0; #endif if(dosave0()) { program_state.something_worth_saving = 0; u.uhp = -1; /* universal game's over indicator */ /* make sure they see the Saving message */ display_nhwindow(WIN_MESSAGE, TRUE); exit_nhwindows("Be seeing you..."); terminate(EXIT_SUCCESS); } else (void)doredraw(); } return 0; } #if defined(UNIX) || defined(VMS) || defined (__EMX__) || defined(WIN32) /*ARGSUSED*/ void hangup(sig_unused) /* called as signal() handler, so sent at least one arg */ int sig_unused; { # ifdef NOSAVEONHANGUP (void) signal(SIGINT, SIG_IGN); clearlocks(); # ifndef VMS terminate(EXIT_FAILURE); # endif # else /* SAVEONHANGUP */ if (!program_state.done_hup++) { if (program_state.something_worth_saving) (void) dosave0(); # ifdef VMS /* don't call exit when already within an exit handler; that would cancel any other pending user-mode handlers */ if (!program_state.exiting) # endif { clearlocks(); terminate(EXIT_FAILURE); } } # endif return; } #endif /* returns 1 if save successful */ int dosave0() { const char *fq_save; register int fd, ofd; xchar ltmp; d_level uz_save; char whynot[BUFSZ]; if (!SAVEF[0]) return 0; fq_save = fqname(SAVEF, SAVEPREFIX, 1); /* level files take 0 */ #if defined(UNIX) || defined(VMS) (void) signal(SIGHUP, SIG_IGN); #endif #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif #if defined(MICRO) && defined(MFLOPPY) if (!saveDiskPrompt(0)) return 0; #endif HUP if (iflags.window_inited) { uncompress(fq_save); fd = open_savefile(); if (fd > 0) { (void) close(fd); clear_nhwindow(WIN_MESSAGE); There("seems to be an old save file."); if (yn("Overwrite the old file?") == 'n') { compress(fq_save); return 0; } } } HUP mark_synch(); /* flush any buffered screen output */ fd = create_savefile(); if(fd < 0) { HUP pline("Cannot open save file."); (void) delete_savefile(); /* ab@unido */ return(0); } vision_recalc(2); /* shut down vision to prevent problems in the event of an impossible() call */ /* undo date-dependent luck adjustments made at startup time */ if(flags.moonphase == FULL_MOON) /* ut-sally!fletcher */ change_luck(-1); /* and unido!ab */ if(flags.friday13) change_luck(1); if(iflags.window_inited) HUP clear_nhwindow(WIN_MESSAGE); #ifdef MICRO dotcnt = 0; dotrow = 2; curs(WIN_MAP, 1, 1); if (strncmpi("X11", windowprocs.name, 3)) putstr(WIN_MAP, 0, "Saving:"); #endif #ifdef MFLOPPY /* make sure there is enough disk space */ if (iflags.checkspace) { long fds, needed; savelev(fd, ledger_no(&u.uz), COUNT_SAVE); savegamestate(fd, COUNT_SAVE); needed = bytes_counted; for (ltmp = 1; ltmp <= maxledgerno(); ltmp++) if (ltmp != ledger_no(&u.uz) && level_info[ltmp].where) needed += level_info[ltmp].size + (sizeof ltmp); fds = freediskspace(fq_save); if (needed > fds) { HUP { There("is insufficient space on SAVE disk."); pline("Require %ld bytes but only have %ld.", needed, fds); } flushout(); (void) close(fd); (void) delete_savefile(); return 0; } co_false(); } #endif /* MFLOPPY */ store_version(fd); #ifdef STORE_PLNAME_IN_FILE bwrite(fd, (genericptr_t) plname, PL_NSIZ); #endif ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); #ifdef STEED usteed_id = (u.usteed ? u.usteed->m_id : 0); #endif savelev(fd, ledger_no(&u.uz), WRITE_SAVE | FREE_SAVE); savegamestate(fd, WRITE_SAVE | FREE_SAVE); /* While copying level files around, zero out u.uz to keep * parts of the restore code from completely initializing all * in-core data structures, since all we're doing is copying. * This also avoids at least one nasty core dump. */ uz_save = u.uz; u.uz.dnum = u.uz.dlevel = 0; /* these pointers are no longer valid, and at least u.usteed * may mislead place_monster() on other levels */ u.ustuck = (struct monst *)0; #ifdef STEED u.usteed = (struct monst *)0; #endif for(ltmp = (xchar)1; ltmp <= maxledgerno(); ltmp++) { if (ltmp == ledger_no(&uz_save)) continue; if (!(level_info[ltmp].flags & LFILE_EXISTS)) continue; #ifdef MICRO curs(WIN_MAP, 1 + dotcnt++, dotrow); if (dotcnt >= (COLNO - 1)) { dotrow++; dotcnt = 0; } if (strncmpi("X11", windowprocs.name, 3)){ putstr(WIN_MAP, 0, "."); } mark_synch(); #endif ofd = open_levelfile(ltmp, whynot); if (ofd < 0) { HUP pline("%s", whynot); (void) close(fd); (void) delete_savefile(); HUP killer = whynot; HUP done(TRICKED); return(0); } minit(); /* ZEROCOMP */ getlev(ofd, hackpid, ltmp, FALSE); (void) close(ofd); bwrite(fd, (genericptr_t) <mp, sizeof ltmp); /* level number*/ savelev(fd, ltmp, WRITE_SAVE | FREE_SAVE); /* actual level*/ delete_levelfile(ltmp); } bclose(fd); u.uz = uz_save; /* get rid of current level --jgm */ delete_levelfile(ledger_no(&u.uz)); delete_levelfile(0); compress(fq_save); return(1); } STATIC_OVL void savegamestate(fd, mode) register int fd, mode; { int uid; #ifdef MFLOPPY count_only = (mode & COUNT_SAVE); #endif uid = getuid(); bwrite(fd, (genericptr_t) &uid, sizeof uid); bwrite(fd, (genericptr_t) &flags, sizeof(struct flag)); bwrite(fd, (genericptr_t) &u, sizeof(struct you)); /* must come before migrating_objs and migrating_mons are freed */ save_timers(fd, mode, RANGE_GLOBAL); save_light_sources(fd, mode, RANGE_GLOBAL); saveobjchn(fd, invent, mode); saveobjchn(fd, migrating_objs, mode); savemonchn(fd, migrating_mons, mode); if (release_data(mode)) { invent = 0; migrating_objs = 0; migrating_mons = 0; } bwrite(fd, (genericptr_t) mvitals, sizeof(mvitals)); save_dungeon(fd, (boolean)!!perform_bwrite(mode), (boolean)!!release_data(mode)); savelevchn(fd, mode); bwrite(fd, (genericptr_t) &moves, sizeof moves); bwrite(fd, (genericptr_t) &monstermoves, sizeof monstermoves); bwrite(fd, (genericptr_t) &quest_status, sizeof(struct q_score)); bwrite(fd, (genericptr_t) spl_book, sizeof(struct spell) * (MAXSPELL + 1)); save_artifacts(fd); save_oracles(fd, mode); if(ustuck_id) bwrite(fd, (genericptr_t) &ustuck_id, sizeof ustuck_id); #ifdef STEED if(usteed_id) bwrite(fd, (genericptr_t) &usteed_id, sizeof usteed_id); #endif bwrite(fd, (genericptr_t) pl_character, sizeof pl_character); bwrite(fd, (genericptr_t) pl_fruit, sizeof pl_fruit); bwrite(fd, (genericptr_t) ¤t_fruit, sizeof current_fruit); savefruitchn(fd, mode); savenames(fd, mode); save_waterlevel(fd, mode); bflush(fd); } #ifdef INSURANCE void savestateinlock() { int fd, hpid; static boolean havestate = TRUE; char whynot[BUFSZ]; /* When checkpointing is on, the full state needs to be written * on each checkpoint. When checkpointing is off, only the pid * needs to be in the level.0 file, so it does not need to be * constantly rewritten. When checkpointing is turned off during * a game, however, the file has to be rewritten once to truncate * it and avoid restoring from outdated information. * * Restricting havestate to this routine means that an additional * noop pid rewriting will take place on the first "checkpoint" after * the game is started or restored, if checkpointing is off. */ if (flags.ins_chkpt || havestate) { /* save the rest of the current game state in the lock file, * following the original int pid, the current level number, * and the current savefile name, which should not be subject * to any internal compression schemes since they must be * readable by an external utility */ fd = open_levelfile(0, whynot); if (fd < 0) { pline("%s", whynot); pline("Probably someone removed it."); killer = whynot; done(TRICKED); return; } (void) read(fd, (genericptr_t) &hpid, sizeof(hpid)); if (hackpid != hpid) { Sprintf(whynot, "Level #0 pid (%d) doesn't match ours (%d)!", hpid, hackpid); pline("%s", whynot); killer = whynot; done(TRICKED); } (void) close(fd); fd = create_levelfile(0, whynot); if (fd < 0) { pline("%s", whynot); killer = whynot; done(TRICKED); return; } (void) write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); if (flags.ins_chkpt) { int currlev = ledger_no(&u.uz); (void) write(fd, (genericptr_t) &currlev, sizeof(currlev)); save_savefile_name(fd); store_version(fd); #ifdef STORE_PLNAME_IN_FILE bwrite(fd, (genericptr_t) plname, PL_NSIZ); #endif ustuck_id = (u.ustuck ? u.ustuck->m_id : 0); #ifdef STEED usteed_id = (u.usteed ? u.usteed->m_id : 0); #endif savegamestate(fd, WRITE_SAVE); } bclose(fd); } havestate = flags.ins_chkpt; } #endif #ifdef MFLOPPY boolean savelev(fd, lev, mode) int fd; xchar lev; int mode; { if (mode & COUNT_SAVE) { bytes_counted = 0; savelev0(fd, lev, COUNT_SAVE); /* probably bytes_counted will be filled in again by an * immediately following WRITE_SAVE anyway, but we'll * leave it out of checkspace just in case */ if (iflags.checkspace) { while (bytes_counted > freediskspace(levels)) if (!swapout_oldest()) return FALSE; } } if (mode & (WRITE_SAVE | FREE_SAVE)) { bytes_counted = 0; savelev0(fd, lev, mode); } if (mode != FREE_SAVE) { level_info[lev].where = ACTIVE; level_info[lev].time = moves; level_info[lev].size = bytes_counted; } return TRUE; } STATIC_OVL void savelev0(fd,lev,mode) #else void savelev(fd,lev,mode) #endif int fd; xchar lev; int mode; { #ifdef TOS short tlev; #endif /* if we're tearing down the current level without saving anything (which happens upon entrance to the endgame or after an aborted restore attempt) then we don't want to do any actual I/O */ if (mode == FREE_SAVE) goto skip_lots; if (iflags.purge_monsters) { /* purge any dead monsters (necessary if we're starting * a panic save rather than a normal one, or sometimes * when changing levels without taking time -- e.g. * create statue trap then immediately level teleport) */ dmonsfree(); } if(fd < 0) panic("Save on bad file!"); /* impossible */ #ifdef MFLOPPY count_only = (mode & COUNT_SAVE); #endif if (lev >= 0 && lev <= maxledgerno()) level_info[lev].flags |= VISITED; bwrite(fd,(genericptr_t) &hackpid,sizeof(hackpid)); #ifdef TOS tlev=lev; tlev &= 0x00ff; bwrite(fd,(genericptr_t) &tlev,sizeof(tlev)); #else bwrite(fd,(genericptr_t) &lev,sizeof(lev)); #endif #ifdef RLECOMP { /* perform run-length encoding of rm structs */ struct rm *prm, *rgrm; int x, y; uchar match; rgrm = &levl[0][0]; /* start matching at first rm */ match = 0; for (y = 0; y < ROWNO; y++) { for (x = 0; x < COLNO; x++) { prm = &levl[x][y]; if (prm->glyph == rgrm->glyph && prm->typ == rgrm->typ && prm->seenv == rgrm->seenv && prm->horizontal == rgrm->horizontal && prm->flags == rgrm->flags && prm->lit == rgrm->lit && prm->waslit == rgrm->waslit && prm->roomno == rgrm->roomno && prm->edge == rgrm->edge) { match++; if (match > 254) { match = 254; /* undo this match */ goto writeout; } } else { /* the run has been broken, * write out run-length encoding */ writeout: bwrite(fd, (genericptr_t)&match, sizeof(uchar)); bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm)); /* start encoding again. we have at least 1 rm * in the next run, viz. this one. */ match = 1; rgrm = prm; } } } if (match > 0) { bwrite(fd, (genericptr_t)&match, sizeof(uchar)); bwrite(fd, (genericptr_t)rgrm, sizeof(struct rm)); } } #else bwrite(fd,(genericptr_t) levl,sizeof(levl)); #endif /* RLECOMP */ bwrite(fd,(genericptr_t) &monstermoves,sizeof(monstermoves)); bwrite(fd,(genericptr_t) &upstair,sizeof(stairway)); bwrite(fd,(genericptr_t) &dnstair,sizeof(stairway)); bwrite(fd,(genericptr_t) &upladder,sizeof(stairway)); bwrite(fd,(genericptr_t) &dnladder,sizeof(stairway)); bwrite(fd,(genericptr_t) &sstairs,sizeof(stairway)); bwrite(fd,(genericptr_t) &updest,sizeof(dest_area)); bwrite(fd,(genericptr_t) &dndest,sizeof(dest_area)); bwrite(fd,(genericptr_t) &level.flags,sizeof(level.flags)); bwrite(fd, (genericptr_t) doors, sizeof(doors)); save_rooms(fd); /* no dynamic memory to reclaim */ /* from here on out, saving also involves allocated memory cleanup */ skip_lots: /* must be saved before mons, objs, and buried objs */ save_timers(fd, mode, RANGE_LEVEL); save_light_sources(fd, mode, RANGE_LEVEL); savemonchn(fd, fmon, mode); save_worm(fd, mode); /* save worm information */ savetrapchn(fd, ftrap, mode); saveobjchn(fd, fobj, mode); saveobjchn(fd, level.buriedobjlist, mode); saveobjchn(fd, billobjs, mode); if (release_data(mode)) { fmon = 0; ftrap = 0; fobj = 0; level.buriedobjlist = 0; billobjs = 0; } save_engravings(fd, mode); savedamage(fd, mode); save_regions(fd, mode); if (mode != FREE_SAVE) bflush(fd); } #ifdef ZEROCOMP /* The runs of zero-run compression are flushed after the game state or a * level is written out. This adds a couple bytes to a save file, where * the runs could be mashed together, but it allows gluing together game * state and level files to form a save file, and it means the flushing * does not need to be specifically called for every other time a level * file is written out. */ #define RLESC '\0' /* Leading character for run of LRESC's */ #define flushoutrun(ln) (bputc(RLESC), bputc(ln), ln = -1) #ifndef ZEROCOMP_BUFSIZ # define ZEROCOMP_BUFSIZ BUFSZ #endif static NEARDATA unsigned char outbuf[ZEROCOMP_BUFSIZ]; static NEARDATA unsigned short outbufp = 0; static NEARDATA short outrunlength = -1; static NEARDATA int bwritefd; static NEARDATA boolean compressing = FALSE; /*dbg() { HUP printf("outbufp %d outrunlength %d\n", outbufp,outrunlength); }*/ STATIC_OVL void bputc(c) int c; { #ifdef MFLOPPY bytes_counted++; if (count_only) return; #endif if (outbufp >= sizeof outbuf) { (void) write(bwritefd, outbuf, sizeof outbuf); outbufp = 0; } outbuf[outbufp++] = (unsigned char)c; } /*ARGSUSED*/ void bufon(fd) int fd; { compressing = TRUE; return; } /*ARGSUSED*/ void bufoff(fd) int fd; { if (outbufp) { outbufp = 0; panic("closing file with buffered data still unwritten"); } outrunlength = -1; compressing = FALSE; return; } void bflush(fd) /* flush run and buffer */ register int fd; { bwritefd = fd; if (outrunlength >= 0) { /* flush run */ flushoutrun(outrunlength); } #ifdef MFLOPPY if (count_only) outbufp = 0; #endif if (outbufp) { if (write(fd, outbuf, outbufp) != outbufp) { #if defined(UNIX) || defined(VMS) || defined(__EMX__) if (program_state.done_hup) terminate(EXIT_FAILURE); else #endif bclose(fd); /* panic (outbufp != 0) */ } outbufp = 0; } } void bwrite(fd, loc, num) int fd; genericptr_t loc; register unsigned num; { register unsigned char *bp = (unsigned char *)loc; if (!compressing) { #ifdef MFLOPPY bytes_counted += num; if (count_only) return; #endif if ((unsigned) write(fd, loc, num) != num) { #if defined(UNIX) || defined(VMS) || defined(__EMX__) if (program_state.done_hup) terminate(EXIT_FAILURE); else #endif panic("cannot write %u bytes to file #%d", num, fd); } } else { bwritefd = fd; for (; num; num--, bp++) { if (*bp == RLESC) { /* One more char in run */ if (++outrunlength == 0xFF) { flushoutrun(outrunlength); } } else { /* end of run */ if (outrunlength >= 0) { /* flush run */ flushoutrun(outrunlength); } bputc(*bp); } } } } void bclose(fd) int fd; { bufoff(fd); (void) close(fd); return; } #else /* ZEROCOMP */ static int bw_fd = -1; static FILE *bw_FILE = 0; static boolean buffering = FALSE; void bufon(fd) int fd; { #ifdef UNIX if(bw_fd >= 0) panic("double buffering unexpected"); bw_fd = fd; if((bw_FILE = fdopen(fd, "w")) == 0) panic("buffering of file %d failed", fd); #endif buffering = TRUE; } void bufoff(fd) int fd; { bflush(fd); buffering = FALSE; } void bflush(fd) int fd; { #ifdef UNIX if(fd == bw_fd) { if(fflush(bw_FILE) == EOF) panic("flush of savefile failed!"); } #endif return; } void bwrite(fd,loc,num) register int fd; register genericptr_t loc; register unsigned num; { boolean failed; #ifdef MFLOPPY bytes_counted += num; if (count_only) return; #endif #ifdef UNIX if (buffering) { if(fd != bw_fd) panic("unbuffered write to fd %d (!= %d)", fd, bw_fd); failed = (fwrite(loc, (int)num, 1, bw_FILE) != 1); } else #endif /* UNIX */ { /* lint wants the 3rd arg of write to be an int; lint -p an unsigned */ #if defined(BSD) || defined(ULTRIX) failed = (write(fd, loc, (int)num) != (int)num); #else /* e.g. SYSV, __TURBOC__ */ failed = (write(fd, loc, num) != num); #endif } if (failed) { #if defined(UNIX) || defined(VMS) || defined(__EMX__) if (program_state.done_hup) terminate(EXIT_FAILURE); else #endif panic("cannot write %u bytes to file #%d", num, fd); } } void bclose(fd) int fd; { bufoff(fd); #ifdef UNIX if (fd == bw_fd) { (void) fclose(bw_FILE); bw_fd = -1; bw_FILE = 0; } else #endif (void) close(fd); return; } #endif /* ZEROCOMP */ STATIC_OVL void savelevchn(fd, mode) register int fd, mode; { s_level *tmplev, *tmplev2; int cnt = 0; for (tmplev = sp_levchn; tmplev; tmplev = tmplev->next) cnt++; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &cnt, sizeof(int)); for (tmplev = sp_levchn; tmplev; tmplev = tmplev2) { tmplev2 = tmplev->next; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) tmplev, sizeof(s_level)); if (release_data(mode)) free((genericptr_t) tmplev); } if (release_data(mode)) sp_levchn = 0; } STATIC_OVL void savedamage(fd, mode) register int fd, mode; { register struct damage *damageptr, *tmp_dam; unsigned int xl = 0; damageptr = level.damagelist; for (tmp_dam = damageptr; tmp_dam; tmp_dam = tmp_dam->next) xl++; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &xl, sizeof(xl)); while (xl--) { if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) damageptr, sizeof(*damageptr)); tmp_dam = damageptr; damageptr = damageptr->next; if (release_data(mode)) free((genericptr_t)tmp_dam); } if (release_data(mode)) level.damagelist = 0; } STATIC_OVL void saveobjchn(fd, otmp, mode) register int fd, mode; register struct obj *otmp; { register struct obj *otmp2; unsigned int xl; int minusone = -1; while(otmp) { otmp2 = otmp->nobj; if (perform_bwrite(mode)) { xl = otmp->oxlth + otmp->onamelth; bwrite(fd, (genericptr_t) &xl, sizeof(int)); bwrite(fd, (genericptr_t) otmp, xl + sizeof(struct obj)); } if (Has_contents(otmp)) saveobjchn(fd,otmp->cobj,mode); if (release_data(mode)) { if (otmp->oclass == FOOD_CLASS) food_disappears(otmp); if (otmp->oclass == SPBOOK_CLASS) book_disappears(otmp); otmp->where = OBJ_FREE; /* set to free so dealloc will work */ otmp->timed = 0; /* not timed any more */ otmp->lamplit = 0; /* caller handled lights */ dealloc_obj(otmp); } otmp = otmp2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &minusone, sizeof(int)); } STATIC_OVL void savemonchn(fd, mtmp, mode) register int fd, mode; register struct monst *mtmp; { register struct monst *mtmp2; unsigned int xl; int minusone = -1; struct permonst *monbegin = &mons[0]; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &monbegin, sizeof(monbegin)); while (mtmp) { mtmp2 = mtmp->nmon; if (perform_bwrite(mode)) { xl = mtmp->mxlth + mtmp->mnamelth; bwrite(fd, (genericptr_t) &xl, sizeof(int)); bwrite(fd, (genericptr_t) mtmp, xl + sizeof(struct monst)); } if (mtmp->minvent) saveobjchn(fd,mtmp->minvent,mode); if (release_data(mode)) dealloc_monst(mtmp); mtmp = mtmp2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) &minusone, sizeof(int)); } STATIC_OVL void savetrapchn(fd, trap, mode) register int fd, mode; register struct trap *trap; { register struct trap *trap2; while (trap) { trap2 = trap->ntrap; if (perform_bwrite(mode)) bwrite(fd, (genericptr_t) trap, sizeof(struct trap)); if (release_data(mode)) dealloc_trap(trap); trap = trap2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t)nulls, sizeof(struct trap)); } /* save all the fruit names and ID's; this is used only in saving whole games * (not levels) and in saving bones levels. When saving a bones level, * we only want to save the fruits which exist on the bones level; the bones * level routine marks nonexistent fruits by making the fid negative. */ void savefruitchn(fd, mode) register int fd, mode; { register struct fruit *f2, *f1; f1 = ffruit; while (f1) { f2 = f1->nextf; if (f1->fid >= 0 && perform_bwrite(mode)) bwrite(fd, (genericptr_t) f1, sizeof(struct fruit)); if (release_data(mode)) dealloc_fruit(f1); f1 = f2; } if (perform_bwrite(mode)) bwrite(fd, (genericptr_t)nulls, sizeof(struct fruit)); if (release_data(mode)) ffruit = 0; } /* also called by prscore(); this probably belongs in dungeon.c... */ void free_dungeons() { #ifdef FREE_ALL_MEMORY savelevchn(0, FREE_SAVE); save_dungeon(0, FALSE, TRUE); #endif return; } void freedynamicdata() { unload_qtlist(); free_invbuf(); /* let_to_name (invent.c) */ free_youbuf(); /* You_buf,&c (pline.c) */ tmp_at(DISP_FREEMEM, 0); /* temporary display effects */ #ifdef FREE_ALL_MEMORY # define freeobjchn(X) (saveobjchn(0, X, FREE_SAVE), X = 0) # define freemonchn(X) (savemonchn(0, X, FREE_SAVE), X = 0) # define freetrapchn(X) (savetrapchn(0, X, FREE_SAVE), X = 0) # define freefruitchn() savefruitchn(0, FREE_SAVE) # define freenames() savenames(0, FREE_SAVE) # define free_oracles() save_oracles(0, FREE_SAVE) # define free_waterlevel() save_waterlevel(0, FREE_SAVE) # define free_worm() save_worm(0, FREE_SAVE) # define free_timers(R) save_timers(0, FREE_SAVE, R) # define free_light_sources(R) save_light_sources(0, FREE_SAVE, R); # define free_engravings() save_engravings(0, FREE_SAVE) # define freedamage() savedamage(0, FREE_SAVE) # define free_animals() mon_animal_list(FALSE) /* move-specific data */ dmonsfree(); /* release dead monsters */ /* level-specific data */ free_timers(RANGE_LEVEL); free_light_sources(RANGE_LEVEL); freemonchn(fmon); free_worm(); /* release worm segment information */ freetrapchn(ftrap); freeobjchn(fobj); freeobjchn(level.buriedobjlist); freeobjchn(billobjs); free_engravings(); freedamage(); /* game-state data */ free_timers(RANGE_GLOBAL); free_light_sources(RANGE_GLOBAL); freeobjchn(invent); freeobjchn(migrating_objs); freemonchn(migrating_mons); freemonchn(mydogs); /* ascension or dungeon escape */ /* freelevchn(); [folded into free_dungeons()] */ free_animals(); free_oracles(); freefruitchn(); freenames(); free_waterlevel(); free_dungeons(); /* some pointers in iflags */ if (iflags.wc_font_map) free(iflags.wc_font_map); if (iflags.wc_font_message) free(iflags.wc_font_message); if (iflags.wc_font_text) free(iflags.wc_font_text); if (iflags.wc_font_menu) free(iflags.wc_font_menu); if (iflags.wc_font_status) free(iflags.wc_font_status); if (iflags.wc_tile_file) free(iflags.wc_tile_file); #ifdef AUTOPICKUP_EXCEPTIONS free_autopickup_exceptions(); #endif #endif /* FREE_ALL_MEMORY */ return; } #ifdef MFLOPPY boolean swapin_file(lev) int lev; { char to[PATHLEN], from[PATHLEN]; Sprintf(from, "%s%s", permbones, alllevels); Sprintf(to, "%s%s", levels, alllevels); set_levelfile_name(from, lev); set_levelfile_name(to, lev); if (iflags.checkspace) { while (level_info[lev].size > freediskspace(to)) if (!swapout_oldest()) return FALSE; } # ifdef WIZARD if (wizard) { pline("Swapping in `%s'.", from); wait_synch(); } # endif copyfile(from, to); (void) unlink(from); level_info[lev].where = ACTIVE; return TRUE; } STATIC_OVL boolean swapout_oldest() { char to[PATHLEN], from[PATHLEN]; int i, oldest; long oldtime; if (!ramdisk) return FALSE; for (i = 1, oldtime = 0, oldest = 0; i <= maxledgerno(); i++) if (level_info[i].where == ACTIVE && (!oldtime || level_info[i].time < oldtime)) { oldest = i; oldtime = level_info[i].time; } if (!oldest) return FALSE; Sprintf(from, "%s%s", levels, alllevels); Sprintf(to, "%s%s", permbones, alllevels); set_levelfile_name(from, oldest); set_levelfile_name(to, oldest); # ifdef WIZARD if (wizard) { pline("Swapping out `%s'.", from); wait_synch(); } # endif copyfile(from, to); (void) unlink(from); level_info[oldest].where = SWAPPED; return TRUE; } STATIC_OVL void copyfile(from, to) char *from, *to; { # ifdef TOS if (_copyfile(from, to)) panic("Can't copy %s to %s", from, to); # else char buf[BUFSIZ]; /* this is system interaction, therefore * BUFSIZ instead of NetHack's BUFSZ */ int nfrom, nto, fdfrom, fdto; if ((fdfrom = open(from, O_RDONLY | O_BINARY, FCMASK)) < 0) panic("Can't copy from %s !?", from); if ((fdto = open(to, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK)) < 0) panic("Can't copy to %s", to); do { nfrom = read(fdfrom, buf, BUFSIZ); nto = write(fdto, buf, nfrom); if (nto != nfrom) panic("Copyfile failed!"); } while (nfrom == BUFSIZ); (void) close(fdfrom); (void) close(fdto); # endif /* TOS */ } void co_false() /* see comment in bones.c */ { count_only = FALSE; return; } #endif /* MFLOPPY */ /*save.c*/ nethack-3.4.3/src/shk.c0100644000000000000000000032600207764735041013375 0ustar rootroot/* SCCS Id: @(#)shk.c 3.4 2003/12/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "eshk.h" /*#define DEBUG*/ #define PAY_SOME 2 #define PAY_BUY 1 #define PAY_CANT 0 /* too poor */ #define PAY_SKIP (-1) #define PAY_BROKE (-2) #ifdef KOPS STATIC_DCL void FDECL(makekops, (coord *)); STATIC_DCL void FDECL(call_kops, (struct monst *,BOOLEAN_P)); # ifdef OVLB STATIC_DCL void FDECL(kops_gone, (BOOLEAN_P)); # endif /* OVLB */ #endif /* KOPS */ #define IS_SHOP(x) (rooms[x].rtype >= SHOPBASE) extern const struct shclass shtypes[]; /* defined in shknam.c */ extern struct obj *thrownobj; /* defined in dothrow.c */ STATIC_VAR NEARDATA long int followmsg; /* last time of follow message */ STATIC_DCL void FDECL(setpaid, (struct monst *)); STATIC_DCL long FDECL(addupbill, (struct monst *)); STATIC_DCL void FDECL(pacify_shk, (struct monst *)); STATIC_DCL struct bill_x *FDECL(onbill, (struct obj *, struct monst *, BOOLEAN_P)); STATIC_DCL struct monst *FDECL(next_shkp, (struct monst *, BOOLEAN_P)); STATIC_DCL long FDECL(shop_debt, (struct eshk *)); STATIC_DCL char *FDECL(shk_owns, (char *,struct obj *)); STATIC_DCL char *FDECL(mon_owns, (char *,struct obj *)); STATIC_DCL void FDECL(clear_unpaid,(struct obj *)); STATIC_DCL long FDECL(check_credit, (long, struct monst *)); STATIC_DCL void FDECL(pay, (long, struct monst *)); STATIC_DCL long FDECL(get_cost, (struct obj *, struct monst *)); STATIC_DCL long FDECL(set_cost, (struct obj *, struct monst *)); STATIC_DCL const char *FDECL(shk_embellish, (struct obj *, long)); STATIC_DCL long FDECL(cost_per_charge, (struct monst *,struct obj *,BOOLEAN_P)); STATIC_DCL long FDECL(cheapest_item, (struct monst *)); STATIC_DCL int FDECL(dopayobj, (struct monst *, struct bill_x *, struct obj **, int, BOOLEAN_P)); STATIC_DCL long FDECL(stolen_container, (struct obj *, struct monst *, long, BOOLEAN_P)); STATIC_DCL long FDECL(getprice, (struct obj *,BOOLEAN_P)); STATIC_DCL void FDECL(shk_names_obj, (struct monst *,struct obj *,const char *,long,const char *)); STATIC_DCL struct obj *FDECL(bp_to_obj, (struct bill_x *)); STATIC_DCL boolean FDECL(inherits, (struct monst *,int,int)); STATIC_DCL void FDECL(set_repo_loc, (struct eshk *)); STATIC_DCL boolean NDECL(angry_shk_exists); STATIC_DCL void FDECL(rile_shk, (struct monst *)); STATIC_DCL void FDECL(rouse_shk, (struct monst *,BOOLEAN_P)); STATIC_DCL void FDECL(remove_damage, (struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(sub_one_frombill, (struct obj *, struct monst *)); STATIC_DCL void FDECL(add_one_tobill, (struct obj *, BOOLEAN_P)); STATIC_DCL void FDECL(dropped_container, (struct obj *, struct monst *, BOOLEAN_P)); STATIC_DCL void FDECL(add_to_billobjs, (struct obj *)); STATIC_DCL void FDECL(bill_box_content, (struct obj *, BOOLEAN_P, BOOLEAN_P, struct monst *)); #ifdef OVL1 static boolean FDECL(rob_shop, (struct monst *)); #endif #ifdef OVLB /* invariants: obj->unpaid iff onbill(obj) [unless bp->useup] obj->quan <= bp->bquan */ #ifdef GOLDOBJ /* Transfer money from inventory to monster when paying shopkeepers, priests, oracle, succubus, & other demons. Simple with only gold coins. This routine will handle money changing when multiple coin types is implemented, only appropriate monsters will pay change. (Peaceful shopkeepers, priests & the oracle try to maintain goodwill while selling their wares or services. Angry monsters and all demons will keep anything they get their hands on. Returns the amount actually paid, so we can know if the monster kept the change. */ long money2mon(mon, amount) struct monst *mon; long amount; { struct obj *ygold = findgold(invent); if (amount <= 0) { impossible("%s payment in money2mon!", amount ? "negative" : "zero"); return 0L; } if (!ygold || ygold->quan < amount) { impossible("Paying without %s money?", ygold ? "enough" : ""); return 0L; } if (ygold->quan > amount) ygold = splitobj(ygold, amount); else if (ygold->owornmask) remove_worn_item(ygold, FALSE); /* quiver */ freeinv(ygold); add_to_minv(mon, ygold); flags.botl = 1; return amount; } /* Transfer money from monster to inventory. Used when the shopkeeper pay for items, and when the priest gives you money for an ale. */ void money2u(mon, amount) struct monst *mon; long amount; { struct obj *mongold = findgold(mon->minvent); if (amount <= 0) { impossible("%s payment in money2u!", amount ? "negative" : "zero"); return; } if (!mongold || mongold->quan < amount) { impossible("%s paying without %s money?", a_monnam(mon), mongold ? "enough" : ""); return; } if (mongold->quan > amount) mongold = splitobj(mongold, amount); obj_extract_self(mongold); if (!merge_choice(invent, mongold) && inv_cnt() >= 52) { You("have no room for the money!"); dropy(mongold); } else { addinv(mongold); flags.botl = 1; } } #endif /* GOLDOBJ */ STATIC_OVL struct monst * next_shkp(shkp, withbill) register struct monst *shkp; register boolean withbill; { for (; shkp; shkp = shkp->nmon) { if (DEADMONSTER(shkp)) continue; if (shkp->isshk && (ESHK(shkp)->billct || !withbill)) break; } if (shkp) { if (NOTANGRY(shkp)) { if (ESHK(shkp)->surcharge) pacify_shk(shkp); } else { if (!ESHK(shkp)->surcharge) rile_shk(shkp); } } return(shkp); } char * shkname(mtmp) /* called in do_name.c */ register struct monst *mtmp; { return(ESHK(mtmp)->shknam); } void shkgone(mtmp) /* called in mon.c */ struct monst *mtmp; { struct eshk *eshk = ESHK(mtmp); struct mkroom *sroom = &rooms[eshk->shoproom - ROOMOFFSET]; struct obj *otmp; char *p; int sx, sy; /* [BUG: some of this should be done on the shop level */ /* even when the shk dies on a different level.] */ if (on_level(&eshk->shoplevel, &u.uz)) { remove_damage(mtmp, TRUE); sroom->resident = (struct monst *)0; if (!search_special(ANY_SHOP)) level.flags.has_shop = 0; /* items on shop floor revert to ordinary objects */ for (sx = sroom->lx; sx <= sroom->hx; sx++) for (sy = sroom->ly; sy <= sroom->hy; sy++) for (otmp = level.objects[sx][sy]; otmp; otmp = otmp->nexthere) otmp->no_charge = 0; /* Make sure bill is set only when the dead shk is the resident shk. */ if ((p = index(u.ushops, eshk->shoproom)) != 0) { setpaid(mtmp); eshk->bill_p = (struct bill_x *)0; /* remove eshk->shoproom from u.ushops */ do { *p = *(p + 1); } while (*++p); } } } void set_residency(shkp, zero_out) register struct monst *shkp; register boolean zero_out; { if (on_level(&(ESHK(shkp)->shoplevel), &u.uz)) rooms[ESHK(shkp)->shoproom - ROOMOFFSET].resident = (zero_out)? (struct monst *)0 : shkp; } void replshk(mtmp,mtmp2) register struct monst *mtmp, *mtmp2; { rooms[ESHK(mtmp2)->shoproom - ROOMOFFSET].resident = mtmp2; if (inhishop(mtmp) && *u.ushops == ESHK(mtmp)->shoproom) { ESHK(mtmp2)->bill_p = &(ESHK(mtmp2)->bill[0]); } } /* do shopkeeper specific structure munging -dlc */ void restshk(shkp, ghostly) struct monst *shkp; boolean ghostly; { if (u.uz.dlevel) { struct eshk *eshkp = ESHK(shkp); if (eshkp->bill_p != (struct bill_x *) -1000) eshkp->bill_p = &eshkp->bill[0]; /* shoplevel can change as dungeons move around */ /* savebones guarantees that non-homed shk's will be gone */ if (ghostly) { assign_level(&eshkp->shoplevel, &u.uz); if (ANGRY(shkp) && strncmpi(eshkp->customer, plname, PL_NSIZ)) pacify_shk(shkp); } } } #endif /* OVLB */ #ifdef OVL3 /* Clear the unpaid bit on all of the objects in the list. */ STATIC_OVL void clear_unpaid(list) register struct obj *list; { while (list) { if (Has_contents(list)) clear_unpaid(list->cobj); list->unpaid = 0; list = list->nobj; } } #endif /*OVL3*/ #ifdef OVLB /* either you paid or left the shop or the shopkeeper died */ STATIC_OVL void setpaid(shkp) register struct monst *shkp; { register struct obj *obj; register struct monst *mtmp; /* FIXME: object handling should be limited to items which are on this particular shk's bill */ clear_unpaid(invent); clear_unpaid(fobj); clear_unpaid(level.buriedobjlist); if (thrownobj) thrownobj->unpaid = 0; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) clear_unpaid(mtmp->minvent); for(mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) clear_unpaid(mtmp->minvent); while ((obj = billobjs) != 0) { obj_extract_self(obj); dealloc_obj(obj); } if(shkp) { ESHK(shkp)->billct = 0; ESHK(shkp)->credit = 0L; ESHK(shkp)->debit = 0L; ESHK(shkp)->loan = 0L; } } STATIC_OVL long addupbill(shkp) register struct monst *shkp; { register int ct = ESHK(shkp)->billct; register struct bill_x *bp = ESHK(shkp)->bill_p; register long total = 0L; while(ct--){ total += bp->price * bp->bquan; bp++; } return(total); } #endif /* OVLB */ #ifdef OVL1 #ifdef KOPS STATIC_OVL void call_kops(shkp, nearshop) register struct monst *shkp; register boolean nearshop; { /* Keystone Kops srt@ucla */ register boolean nokops; if(!shkp) return; if (flags.soundok) pline("An alarm sounds!"); nokops = ((mvitals[PM_KEYSTONE_KOP].mvflags & G_GONE) && (mvitals[PM_KOP_SERGEANT].mvflags & G_GONE) && (mvitals[PM_KOP_LIEUTENANT].mvflags & G_GONE) && (mvitals[PM_KOP_KAPTAIN].mvflags & G_GONE)); if(!angry_guards(!flags.soundok) && nokops) { if(flags.verbose && flags.soundok) pline("But no one seems to respond to it."); return; } if(nokops) return; { coord mm; if (nearshop) { /* Create swarm around you, if you merely "stepped out" */ if (flags.verbose) pline_The("Keystone Kops appear!"); mm.x = u.ux; mm.y = u.uy; makekops(&mm); return; } if (flags.verbose) pline_The("Keystone Kops are after you!"); /* Create swarm near down staircase (hinders return to level) */ mm.x = xdnstair; mm.y = ydnstair; makekops(&mm); /* Create swarm near shopkeeper (hinders return to shop) */ mm.x = shkp->mx; mm.y = shkp->my; makekops(&mm); } } #endif /* KOPS */ /* x,y is strictly inside shop */ char inside_shop(x, y) register xchar x, y; { register char rno; rno = levl[x][y].roomno; if ((rno < ROOMOFFSET) || levl[x][y].edge || !IS_SHOP(rno-ROOMOFFSET)) return(NO_ROOM); else return(rno); } void u_left_shop(leavestring, newlev) char *leavestring; boolean newlev; { struct monst *shkp; struct eshk *eshkp; /* * IF player * ((didn't leave outright) AND * ((he is now strictly-inside the shop) OR * (he wasn't strictly-inside last turn anyway))) * THEN (there's nothing to do, so just return) */ if(!*leavestring && (!levl[u.ux][u.uy].edge || levl[u.ux0][u.uy0].edge)) return; shkp = shop_keeper(*u.ushops0); if (!shkp || !inhishop(shkp)) return; /* shk died, teleported, changed levels... */ eshkp = ESHK(shkp); if (!eshkp->billct && !eshkp->debit) /* bill is settled */ return; if (!*leavestring && shkp->mcanmove && !shkp->msleeping) { /* * Player just stepped onto shop-boundary (known from above logic). * Try to intimidate him into paying his bill */ verbalize(NOTANGRY(shkp) ? "%s! Please pay before leaving." : "%s! Don't you leave without paying!", plname); return; } if (rob_shop(shkp)) { #ifdef KOPS call_kops(shkp, (!newlev && levl[u.ux0][u.uy0].edge)); #else (void) angry_guards(FALSE); #endif } } /* robbery from outside the shop via telekinesis or grappling hook */ void remote_burglary(x, y) xchar x, y; { struct monst *shkp; struct eshk *eshkp; shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); if (!shkp || !inhishop(shkp)) return; /* shk died, teleported, changed levels... */ eshkp = ESHK(shkp); if (!eshkp->billct && !eshkp->debit) /* bill is settled */ return; if (rob_shop(shkp)) { #ifdef KOPS /*[might want to set 2nd arg based on distance from shop doorway]*/ call_kops(shkp, FALSE); #else (void) angry_guards(FALSE); #endif } } /* shop merchandise has been taken; pay for it with any credit available; return false if the debt is fully covered by credit, true otherwise */ static boolean rob_shop(shkp) struct monst *shkp; { struct eshk *eshkp; long total; eshkp = ESHK(shkp); rouse_shk(shkp, TRUE); total = (addupbill(shkp) + eshkp->debit); if (eshkp->credit >= total) { Your("credit of %ld %s is used to cover your shopping bill.", eshkp->credit, currency(eshkp->credit)); total = 0L; /* credit gets cleared by setpaid() */ } else { You("escaped the shop without paying!"); total -= eshkp->credit; } setpaid(shkp); if (!total) return FALSE; /* by this point, we know an actual robbery has taken place */ eshkp->robbed += total; You("stole %ld %s worth of merchandise.", total, currency(total)); if (!Role_if(PM_ROGUE)) /* stealing is unlawful */ adjalign(-sgn(u.ualign.type)); hot_pursuit(shkp); return TRUE; } void u_entered_shop(enterstring) register char *enterstring; { register int rt; register struct monst *shkp; register struct eshk *eshkp; static const char no_shk[] = "This shop appears to be deserted."; static char empty_shops[5]; if(!*enterstring) return; if(!(shkp = shop_keeper(*enterstring))) { if (!index(empty_shops, *enterstring) && in_rooms(u.ux, u.uy, SHOPBASE) != in_rooms(u.ux0, u.uy0, SHOPBASE)) pline(no_shk); Strcpy(empty_shops, u.ushops); u.ushops[0] = '\0'; return; } eshkp = ESHK(shkp); if (!inhishop(shkp)) { /* dump core when referenced */ eshkp->bill_p = (struct bill_x *) -1000; if (!index(empty_shops, *enterstring)) pline(no_shk); Strcpy(empty_shops, u.ushops); u.ushops[0] = '\0'; return; } eshkp->bill_p = &(eshkp->bill[0]); if ((!eshkp->visitct || *eshkp->customer) && strncmpi(eshkp->customer, plname, PL_NSIZ)) { /* You seem to be new here */ eshkp->visitct = 0; eshkp->following = 0; (void) strncpy(eshkp->customer,plname,PL_NSIZ); pacify_shk(shkp); } if (shkp->msleeping || !shkp->mcanmove || eshkp->following) return; /* no dialog */ if (Invis) { pline("%s senses your presence.", shkname(shkp)); verbalize("Invisible customers are not welcome!"); return; } rt = rooms[*enterstring - ROOMOFFSET].rtype; if (ANGRY(shkp)) { verbalize("So, %s, you dare return to %s %s?!", plname, s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); } else if (eshkp->robbed) { pline("%s mutters imprecations against shoplifters.", shkname(shkp)); } else { verbalize("%s, %s! Welcome%s to %s %s!", Hello(shkp), plname, eshkp->visitct++ ? " again" : "", s_suffix(shkname(shkp)), shtypes[rt - SHOPBASE].name); } /* can't do anything about blocking if teleported in */ if (!inside_shop(u.ux, u.uy)) { boolean should_block; int cnt; const char *tool; struct obj *pick = carrying(PICK_AXE), *mattock = carrying(DWARVISH_MATTOCK); if (pick || mattock) { cnt = 1; /* so far */ if (pick && mattock) { /* carrying both types */ tool = "digging tool"; cnt = 2; /* `more than 1' is all that matters */ } else if (pick) { tool = "pick-axe"; /* hack: `pick' already points somewhere into inventory */ while ((pick = pick->nobj) != 0) if (pick->otyp == PICK_AXE) ++cnt; } else { /* assert(mattock != 0) */ tool = "mattock"; while ((mattock = mattock->nobj) != 0) if (mattock->otyp == DWARVISH_MATTOCK) ++cnt; /* [ALI] Shopkeeper identifies mattock(s) */ if (!Blind) makeknown(DWARVISH_MATTOCK); } verbalize(NOTANGRY(shkp) ? "Will you please leave your %s%s outside?" : "Leave the %s%s outside.", tool, plur(cnt)); should_block = TRUE; #ifdef STEED } else if (u.usteed) { verbalize(NOTANGRY(shkp) ? "Will you please leave %s outside?" : "Leave %s outside.", y_monnam(u.usteed)); should_block = TRUE; #endif } else { should_block = (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) || sobj_at(DWARVISH_MATTOCK, u.ux, u.uy))); } if (should_block) (void) dochug(shkp); /* shk gets extra move */ } return; } /* Decide whether two unpaid items are mergable; caller is responsible for making sure they're unpaid and the same type of object; we check the price quoted by the shopkeeper and also that they both belong to the same shk. */ boolean same_price(obj1, obj2) struct obj *obj1, *obj2; { register struct monst *shkp1, *shkp2; register struct bill_x *bp1 = 0, *bp2 = 0; register boolean are_mergable = FALSE; /* look up the first object by finding shk whose bill it's on */ for (shkp1 = next_shkp(fmon, TRUE); shkp1; shkp1 = next_shkp(shkp1->nmon, TRUE)) if ((bp1 = onbill(obj1, shkp1, TRUE)) != 0) break; /* second object is probably owned by same shk; if not, look harder */ if (shkp1 && (bp2 = onbill(obj2, shkp1, TRUE)) != 0) { shkp2 = shkp1; } else { for (shkp2 = next_shkp(fmon, TRUE); shkp2; shkp2 = next_shkp(shkp2->nmon, TRUE)) if ((bp2 = onbill(obj2, shkp2, TRUE)) != 0) break; } if (!bp1 || !bp2) impossible("same_price: object wasn't on any bill!"); else are_mergable = (shkp1 == shkp2 && bp1->price == bp2->price); return are_mergable; } /* * Figure out how much is owed to a given shopkeeper. * At present, we ignore any amount robbed from the shop, to avoid * turning the `$' command into a way to discover that the current * level is bones data which has a shk on the warpath. */ STATIC_OVL long shop_debt(eshkp) struct eshk *eshkp; { struct bill_x *bp; int ct; long debt = eshkp->debit; for (bp = eshkp->bill_p, ct = eshkp->billct; ct > 0; bp++, ct--) debt += bp->price * bp->bquan; return debt; } /* called in response to the `$' command */ void shopper_financial_report() { struct monst *shkp, *this_shkp = shop_keeper(inside_shop(u.ux, u.uy)); struct eshk *eshkp; long amt; int pass; if (this_shkp && !(ESHK(this_shkp)->credit || shop_debt(ESHK(this_shkp)))) { You("have no credit or debt in here."); this_shkp = 0; /* skip first pass */ } /* pass 0: report for the shop we're currently in, if any; pass 1: report for all other shops on this level. */ for (pass = this_shkp ? 0 : 1; pass <= 1; pass++) for (shkp = next_shkp(fmon, FALSE); shkp; shkp = next_shkp(shkp->nmon, FALSE)) { if ((shkp != this_shkp) ^ pass) continue; eshkp = ESHK(shkp); if ((amt = eshkp->credit) != 0) You("have %ld %s credit at %s %s.", amt, currency(amt), s_suffix(shkname(shkp)), shtypes[eshkp->shoptype - SHOPBASE].name); else if (shkp == this_shkp) You("have no credit in here."); if ((amt = shop_debt(eshkp)) != 0) You("owe %s %ld %s.", shkname(shkp), amt, currency(amt)); else if (shkp == this_shkp) You("don't owe any money here."); } } #endif /* OVL1 */ #ifdef OVLB int inhishop(mtmp) register struct monst *mtmp; { return(index(in_rooms(mtmp->mx, mtmp->my, SHOPBASE), ESHK(mtmp)->shoproom) && on_level(&(ESHK(mtmp)->shoplevel), &u.uz)); } struct monst * shop_keeper(rmno) register char rmno; { struct monst *shkp = rmno >= ROOMOFFSET ? rooms[rmno - ROOMOFFSET].resident : 0; if (shkp) { if (NOTANGRY(shkp)) { if (ESHK(shkp)->surcharge) pacify_shk(shkp); } else { if (!ESHK(shkp)->surcharge) rile_shk(shkp); } } return shkp; } boolean tended_shop(sroom) register struct mkroom *sroom; { register struct monst *mtmp = sroom->resident; if (!mtmp) return(FALSE); else return((boolean)(inhishop(mtmp))); } STATIC_OVL struct bill_x * onbill(obj, shkp, silent) register struct obj *obj; register struct monst *shkp; register boolean silent; { if (shkp) { register struct bill_x *bp = ESHK(shkp)->bill_p; register int ct = ESHK(shkp)->billct; while (--ct >= 0) if (bp->bo_id == obj->o_id) { if (!obj->unpaid) pline("onbill: paid obj on bill?"); return bp; } else bp++; } if(obj->unpaid & !silent) pline("onbill: unpaid obj not on bill?"); return (struct bill_x *)0; } /* Delete the contents of the given object. */ void delete_contents(obj) register struct obj *obj; { register struct obj *curr; while ((curr = obj->cobj) != 0) { obj_extract_self(curr); obfree(curr, (struct obj *)0); } } /* called with two args on merge */ void obfree(obj, merge) register struct obj *obj, *merge; { register struct bill_x *bp; register struct bill_x *bpm; register struct monst *shkp; if (obj->otyp == LEASH && obj->leashmon) o_unleash(obj); if (obj->oclass == FOOD_CLASS) food_disappears(obj); if (obj->oclass == SPBOOK_CLASS) book_disappears(obj); if (Has_contents(obj)) delete_contents(obj); shkp = 0; if (obj->unpaid) { /* look for a shopkeeper who owns this object */ for (shkp = next_shkp(fmon, TRUE); shkp; shkp = next_shkp(shkp->nmon, TRUE)) if (onbill(obj, shkp, TRUE)) break; } /* sanity check, more or less */ if (!shkp) shkp = shop_keeper(*u.ushops); /* * Note: `shkp = shop_keeper(*u.ushops)' used to be * unconditional. But obfree() is used all over * the place, so making its behavior be dependent * upon player location doesn't make much sense. */ if ((bp = onbill(obj, shkp, FALSE)) != 0) { if(!merge){ bp->useup = 1; obj->unpaid = 0; /* only for doinvbill */ add_to_billobjs(obj); return; } bpm = onbill(merge, shkp, FALSE); if(!bpm){ /* this used to be a rename */ impossible("obfree: not on bill??"); return; } else { /* this was a merger */ bpm->bquan += bp->bquan; ESHK(shkp)->billct--; #ifdef DUMB { /* DRS/NS 2.2.6 messes up -- Peter Kendell */ int indx = ESHK(shkp)->billct; *bp = ESHK(shkp)->bill_p[indx]; } #else *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct]; #endif } } dealloc_obj(obj); } #endif /* OVLB */ #ifdef OVL3 STATIC_OVL long check_credit(tmp, shkp) long tmp; register struct monst *shkp; { long credit = ESHK(shkp)->credit; if(credit == 0L) return(tmp); if(credit >= tmp) { pline_The("price is deducted from your credit."); ESHK(shkp)->credit -=tmp; tmp = 0L; } else { pline_The("price is partially covered by your credit."); ESHK(shkp)->credit = 0L; tmp -= credit; } return(tmp); } STATIC_OVL void pay(tmp,shkp) long tmp; register struct monst *shkp; { long robbed = ESHK(shkp)->robbed; long balance = ((tmp <= 0L) ? tmp : check_credit(tmp, shkp)); #ifndef GOLDOBJ u.ugold -= balance; shkp->mgold += balance; #else if (balance > 0) money2mon(shkp, balance); else if (balance < 0) money2u(shkp, -balance); #endif flags.botl = 1; if(robbed) { robbed -= tmp; if(robbed < 0) robbed = 0L; ESHK(shkp)->robbed = robbed; } } #endif /*OVL3*/ #ifdef OVLB /* return shkp to home position */ void home_shk(shkp, killkops) register struct monst *shkp; register boolean killkops; { register xchar x = ESHK(shkp)->shk.x, y = ESHK(shkp)->shk.y; (void) mnearto(shkp, x, y, TRUE); level.flags.has_shop = 1; if (killkops) { #ifdef KOPS kops_gone(TRUE); #else You_feel("vaguely apprehensive."); #endif pacify_guards(); } after_shk_move(shkp); } STATIC_OVL boolean angry_shk_exists() { register struct monst *shkp; for (shkp = next_shkp(fmon, FALSE); shkp; shkp = next_shkp(shkp->nmon, FALSE)) if (ANGRY(shkp)) return(TRUE); return(FALSE); } /* remove previously applied surcharge from all billed items */ STATIC_OVL void pacify_shk(shkp) register struct monst *shkp; { NOTANGRY(shkp) = TRUE; /* make peaceful */ if (ESHK(shkp)->surcharge) { register struct bill_x *bp = ESHK(shkp)->bill_p; register int ct = ESHK(shkp)->billct; ESHK(shkp)->surcharge = FALSE; while (ct-- > 0) { register long reduction = (bp->price + 3L) / 4L; bp->price -= reduction; /* undo 33% increase */ bp++; } } } /* add aggravation surcharge to all billed items */ STATIC_OVL void rile_shk(shkp) register struct monst *shkp; { NOTANGRY(shkp) = FALSE; /* make angry */ if (!ESHK(shkp)->surcharge) { register struct bill_x *bp = ESHK(shkp)->bill_p; register int ct = ESHK(shkp)->billct; ESHK(shkp)->surcharge = TRUE; while (ct-- > 0) { register long surcharge = (bp->price + 2L) / 3L; bp->price += surcharge; bp++; } } } /* wakeup and/or unparalyze shopkeeper */ STATIC_OVL void rouse_shk(shkp, verbosely) struct monst *shkp; boolean verbosely; { if (!shkp->mcanmove || shkp->msleeping) { /* greed induced recovery... */ if (verbosely && canspotmon(shkp)) pline("%s %s.", Monnam(shkp), shkp->msleeping ? "wakes up" : "can move again"); shkp->msleeping = 0; shkp->mfrozen = 0; shkp->mcanmove = 1; } } void make_happy_shk(shkp, silentkops) register struct monst *shkp; register boolean silentkops; { boolean wasmad = ANGRY(shkp); struct eshk *eshkp = ESHK(shkp); pacify_shk(shkp); eshkp->following = 0; eshkp->robbed = 0L; if (!Role_if(PM_ROGUE)) adjalign(sgn(u.ualign.type)); if(!inhishop(shkp)) { char shk_nam[BUFSZ]; boolean vanished = canseemon(shkp); Strcpy(shk_nam, mon_nam(shkp)); if (on_level(&eshkp->shoplevel, &u.uz)) { home_shk(shkp, FALSE); /* didn't disappear if shk can still be seen */ if (canseemon(shkp)) vanished = FALSE; } else { /* if sensed, does disappear regardless whether seen */ if (sensemon(shkp)) vanished = TRUE; /* can't act as porter for the Amulet, even if shk happens to be going farther down rather than up */ mdrop_special_objs(shkp); /* arrive near shop's door */ migrate_to_level(shkp, ledger_no(&eshkp->shoplevel), MIGR_APPROX_XY, &eshkp->shd); } if (vanished) pline("Satisfied, %s suddenly disappears!", shk_nam); } else if(wasmad) pline("%s calms down.", Monnam(shkp)); if(!angry_shk_exists()) { #ifdef KOPS kops_gone(silentkops); #endif pacify_guards(); } } void hot_pursuit(shkp) register struct monst *shkp; { if(!shkp->isshk) return; rile_shk(shkp); (void) strncpy(ESHK(shkp)->customer, plname, PL_NSIZ); ESHK(shkp)->following = 1; } /* used when the shkp is teleported or falls (ox == 0) out of his shop, * or when the player is not on a costly_spot and he * damages something inside the shop. these conditions * must be checked by the calling function. */ void make_angry_shk(shkp, ox, oy) register struct monst *shkp; register xchar ox,oy; { xchar sx, sy; struct eshk *eshkp = ESHK(shkp); /* all pending shop transactions are now "past due" */ if (eshkp->billct || eshkp->debit || eshkp->loan || eshkp->credit) { eshkp->robbed += (addupbill(shkp) + eshkp->debit + eshkp->loan); eshkp->robbed -= eshkp->credit; if (eshkp->robbed < 0L) eshkp->robbed = 0L; /* billct, debit, loan, and credit will be cleared by setpaid */ setpaid(shkp); } /* If you just used a wand of teleportation to send the shk away, you might not be able to see her any more. Monnam would yield "it", which makes this message look pretty silly, so temporarily restore her original location during the call to Monnam. */ sx = shkp->mx, sy = shkp->my; if (isok(ox, oy) && cansee(ox, oy) && !cansee(sx, sy)) shkp->mx = ox, shkp->my = oy; pline("%s %s!", Monnam(shkp), !ANGRY(shkp) ? "gets angry" : "is furious"); shkp->mx = sx, shkp->my = sy; hot_pursuit(shkp); } STATIC_VAR const char no_money[] = "Moreover, you%s have no money."; STATIC_VAR const char not_enough_money[] = "Besides, you don't have enough to interest %s."; #else STATIC_VAR const char no_money[]; STATIC_VAR const char not_enough_money[]; #endif /*OVLB*/ #ifdef OVL3 STATIC_OVL long cheapest_item(shkp) /* delivers the cheapest item on the list */ register struct monst *shkp; { register int ct = ESHK(shkp)->billct; register struct bill_x *bp = ESHK(shkp)->bill_p; register long gmin = (bp->price * bp->bquan); while(ct--){ if(bp->price * bp->bquan < gmin) gmin = bp->price * bp->bquan; bp++; } return(gmin); } #endif /*OVL3*/ #ifdef OVL0 int dopay() { register struct eshk *eshkp; register struct monst *shkp; struct monst *nxtm, *resident; long ltmp; #ifdef GOLDOBJ long umoney; #endif int pass, tmp, sk = 0, seensk = 0; boolean paid = FALSE, stashed_gold = (hidden_gold() > 0L); multi = 0; /* find how many shk's there are, how many are in */ /* sight, and are you in a shop room with one. */ nxtm = resident = 0; for (shkp = next_shkp(fmon, FALSE); shkp; shkp = next_shkp(shkp->nmon, FALSE)) { sk++; if (ANGRY(shkp) && distu(shkp->mx, shkp->my) <= 2) nxtm = shkp; if (canspotmon(shkp)) seensk++; if (inhishop(shkp) && (*u.ushops == ESHK(shkp)->shoproom)) resident = shkp; } if (nxtm) { /* Player should always appease an */ shkp = nxtm; /* irate shk standing next to them. */ goto proceed; } if ((!sk && (!Blind || Blind_telepat)) || (!Blind && !seensk)) { There("appears to be no shopkeeper here to receive your payment."); return(0); } if(!seensk) { You_cant("see..."); return(0); } /* the usual case. allow paying at a distance when */ /* inside a tended shop. should we change that? */ if(sk == 1 && resident) { shkp = resident; goto proceed; } if (seensk == 1) { for (shkp = next_shkp(fmon, FALSE); shkp; shkp = next_shkp(shkp->nmon, FALSE)) if (canspotmon(shkp)) break; if (shkp != resident && distu(shkp->mx, shkp->my) > 2) { pline("%s is not near enough to receive your payment.", Monnam(shkp)); return(0); } } else { struct monst *mtmp; coord cc; int cx, cy; pline("Pay whom?"); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the creature you want to pay") < 0) return 0; /* player pressed ESC */ cx = cc.x; cy = cc.y; if(cx < 0) { pline("Try again..."); return(0); } if(u.ux == cx && u.uy == cy) { You("are generous to yourself."); return(0); } mtmp = m_at(cx, cy); if(!mtmp) { There("is no one there to receive your payment."); return(0); } if(!mtmp->isshk) { pline("%s is not interested in your payment.", Monnam(mtmp)); return(0); } if (mtmp != resident && distu(mtmp->mx, mtmp->my) > 2) { pline("%s is too far to receive your payment.", Monnam(mtmp)); return(0); } shkp = mtmp; } if(!shkp) { #ifdef DEBUG pline("dopay: null shkp."); #endif return(0); } proceed: eshkp = ESHK(shkp); ltmp = eshkp->robbed; /* wake sleeping shk when someone who owes money offers payment */ if (ltmp || eshkp->billct || eshkp->debit) rouse_shk(shkp, TRUE); if (!shkp->mcanmove || shkp->msleeping) { /* still asleep/paralyzed */ pline("%s %s.", Monnam(shkp), rn2(2) ? "seems to be napping" : "doesn't respond"); return 0; } if(shkp != resident && NOTANGRY(shkp)) { #ifdef GOLDOBJ umoney = money_cnt(invent); #endif if(!ltmp) You("do not owe %s anything.", mon_nam(shkp)); #ifndef GOLDOBJ else if(!u.ugold) { #else else if(!umoney) { #endif You("%shave no money.", stashed_gold ? "seem to " : ""); if(stashed_gold) pline("But you have some gold stashed away."); } else { #ifndef GOLDOBJ long ugold = u.ugold; if(ugold > ltmp) { #else if(umoney > ltmp) { #endif You("give %s the %ld gold piece%s %s asked for.", mon_nam(shkp), ltmp, plur(ltmp), mhe(shkp)); pay(ltmp, shkp); } else { You("give %s all your%s gold.", mon_nam(shkp), stashed_gold ? " openly kept" : ""); #ifndef GOLDOBJ pay(u.ugold, shkp); #else pay(umoney, shkp); #endif if (stashed_gold) pline("But you have hidden gold!"); } #ifndef GOLDOBJ if((ugold < ltmp/2L) || (ugold < ltmp && stashed_gold)) #else if((umoney < ltmp/2L) || (umoney < ltmp && stashed_gold)) #endif pline("Unfortunately, %s doesn't look satisfied.", mhe(shkp)); else make_happy_shk(shkp, FALSE); } return(1); } /* ltmp is still eshkp->robbed here */ if (!eshkp->billct && !eshkp->debit) { #ifdef GOLDOBJ umoney = money_cnt(invent); #endif if(!ltmp && NOTANGRY(shkp)) { You("do not owe %s anything.", mon_nam(shkp)); #ifndef GOLDOBJ if (!u.ugold) #else if (!umoney) #endif pline(no_money, stashed_gold ? " seem to" : ""); } else if(ltmp) { pline("%s is after blood, not money!", Monnam(shkp)); #ifndef GOLDOBJ if(u.ugold < ltmp/2L || (u.ugold < ltmp && stashed_gold)) { if (!u.ugold) #else if(umoney < ltmp/2L || (umoney < ltmp && stashed_gold)) { if (!umoney) #endif pline(no_money, stashed_gold ? " seem to" : ""); else pline(not_enough_money, mhim(shkp)); return(1); } pline("But since %s shop has been robbed recently,", mhis(shkp)); pline("you %scompensate %s for %s losses.", #ifndef GOLDOBJ (u.ugold < ltmp) ? #else (umoney < ltmp) ? #endif "partially " : "", mon_nam(shkp), mhis(shkp)); #ifndef GOLDOBJ pay(u.ugold < ltmp ? u.ugold : ltmp, shkp); #else pay(umoney < ltmp ? umoney : ltmp, shkp); #endif make_happy_shk(shkp, FALSE); } else { /* shopkeeper is angry, but has not been robbed -- * door broken, attacked, etc. */ pline("%s is after your hide, not your money!", Monnam(shkp)); #ifndef GOLDOBJ if(u.ugold < 1000L) { if (!u.ugold) #else if(umoney < 1000L) { if (!umoney) #endif pline(no_money, stashed_gold ? " seem to" : ""); else pline(not_enough_money, mhim(shkp)); return(1); } You("try to appease %s by giving %s 1000 gold pieces.", x_monnam(shkp, ARTICLE_THE, "angry", 0, FALSE), mhim(shkp)); pay(1000L,shkp); if (strncmp(eshkp->customer, plname, PL_NSIZ) || rn2(3)) make_happy_shk(shkp, FALSE); else pline("But %s is as angry as ever.", mon_nam(shkp)); } return(1); } if(shkp != resident) { impossible("dopay: not to shopkeeper?"); if(resident) setpaid(resident); return(0); } /* pay debt, if any, first */ if(eshkp->debit) { long dtmp = eshkp->debit; long loan = eshkp->loan; char sbuf[BUFSZ]; #ifdef GOLDOBJ umoney = money_cnt(invent); #endif Sprintf(sbuf, "You owe %s %ld %s ", shkname(shkp), dtmp, currency(dtmp)); if(loan) { if(loan == dtmp) Strcat(sbuf, "you picked up in the store."); else Strcat(sbuf, "for gold picked up and the use of merchandise."); } else Strcat(sbuf, "for the use of merchandise."); pline(sbuf); #ifndef GOLDOBJ if (u.ugold + eshkp->credit < dtmp) { #else if (umoney + eshkp->credit < dtmp) { #endif pline("But you don't%s have enough gold%s.", stashed_gold ? " seem to" : "", eshkp->credit ? " or credit" : ""); return(1); } else { if (eshkp->credit >= dtmp) { eshkp->credit -= dtmp; eshkp->debit = 0L; eshkp->loan = 0L; Your("debt is covered by your credit."); } else if (!eshkp->credit) { #ifndef GOLDOBJ u.ugold -= dtmp; shkp->mgold += dtmp; #else money2mon(shkp, dtmp); #endif eshkp->debit = 0L; eshkp->loan = 0L; You("pay that debt."); flags.botl = 1; } else { dtmp -= eshkp->credit; eshkp->credit = 0L; #ifndef GOLDOBJ u.ugold -= dtmp; shkp->mgold += dtmp; #else money2mon(shkp, dtmp); #endif eshkp->debit = 0L; eshkp->loan = 0L; pline("That debt is partially offset by your credit."); You("pay the remainder."); flags.botl = 1; } paid = TRUE; } } /* now check items on bill */ if (eshkp->billct) { register boolean itemize; #ifndef GOLDOBJ if (!u.ugold && !eshkp->credit) { #else umoney = money_cnt(invent); if (!umoney && !eshkp->credit) { #endif You("%shave no money or credit%s.", stashed_gold ? "seem to " : "", paid ? " left" : ""); return(0); } #ifndef GOLDOBJ if ((u.ugold + eshkp->credit) < cheapest_item(shkp)) { #else if ((umoney + eshkp->credit) < cheapest_item(shkp)) { #endif You("don't have enough money to buy%s the item%s you picked.", eshkp->billct > 1 ? " any of" : "", plur(eshkp->billct)); if(stashed_gold) pline("Maybe you have some gold stashed away?"); return(0); } /* this isn't quite right; it itemizes without asking if the * single item on the bill is partly used up and partly unpaid */ itemize = (eshkp->billct > 1 ? yn("Itemized billing?") == 'y' : 1); for (pass = 0; pass <= 1; pass++) { tmp = 0; while (tmp < eshkp->billct) { struct obj *otmp; register struct bill_x *bp = &(eshkp->bill_p[tmp]); /* find the object on one of the lists */ if ((otmp = bp_to_obj(bp)) != 0) { /* if completely used up, object quantity is stale; restoring it to its original value here avoids making the partly-used-up code more complicated */ if (bp->useup) otmp->quan = bp->bquan; } else { impossible("Shopkeeper administration out of order."); setpaid(shkp); /* be nice to the player */ return 1; } if (pass == bp->useup && otmp->quan == bp->bquan) { /* pay for used-up items on first pass and others * on second, so player will be stuck in the store * less often; things which are partly used up * are processed on both passes */ tmp++; } else { switch (dopayobj(shkp, bp, &otmp, pass, itemize)) { case PAY_CANT: return 1; /*break*/ case PAY_BROKE: paid = TRUE; goto thanks; /*break*/ case PAY_SKIP: tmp++; continue; /*break*/ case PAY_SOME: paid = TRUE; if (itemize) bot(); continue; /*break*/ case PAY_BUY: paid = TRUE; break; } if (itemize) bot(); *bp = eshkp->bill_p[--eshkp->billct]; } } } thanks: if (!itemize) update_inventory(); /* Done in dopayobj() if itemize. */ } if(!ANGRY(shkp) && paid) verbalize("Thank you for shopping in %s %s!", s_suffix(shkname(shkp)), shtypes[eshkp->shoptype - SHOPBASE].name); return(1); } #endif /*OVL0*/ #ifdef OVL3 /* return 2 if used-up portion paid */ /* 1 if paid successfully */ /* 0 if not enough money */ /* -1 if skip this object */ /* -2 if no money/credit left */ STATIC_OVL int dopayobj(shkp, bp, obj_p, which, itemize) register struct monst *shkp; register struct bill_x *bp; struct obj **obj_p; int which; /* 0 => used-up item, 1 => other (unpaid or lost) */ boolean itemize; { register struct obj *obj = *obj_p; long ltmp, quan, save_quan; #ifdef GOLDOBJ long umoney = money_cnt(invent); #endif int buy; boolean stashed_gold = (hidden_gold() > 0L), consumed = (which == 0); if(!obj->unpaid && !bp->useup){ impossible("Paid object on bill??"); return PAY_BUY; } #ifndef GOLDOBJ if(itemize && u.ugold + ESHK(shkp)->credit == 0L){ #else if(itemize && umoney + ESHK(shkp)->credit == 0L){ #endif You("%shave no money or credit left.", stashed_gold ? "seem to " : ""); return PAY_BROKE; } /* we may need to temporarily adjust the object, if part of the original quantity has been used up but part remains unpaid */ save_quan = obj->quan; if (consumed) { /* either completely used up (simple), or split needed */ quan = bp->bquan; if (quan > obj->quan) /* difference is amount used up */ quan -= obj->quan; } else { /* dealing with ordinary unpaid item */ quan = obj->quan; } obj->quan = quan; /* to be used by doname() */ obj->unpaid = 0; /* ditto */ ltmp = bp->price * quan; buy = PAY_BUY; /* flag; if changed then return early */ if (itemize) { char qbuf[BUFSZ]; Sprintf(qbuf,"%s for %ld %s. Pay?", quan == 1L ? Doname2(obj) : doname(obj), ltmp, currency(ltmp)); if (yn(qbuf) == 'n') { buy = PAY_SKIP; /* don't want to buy */ } else if (quan < bp->bquan && !consumed) { /* partly used goods */ obj->quan = bp->bquan - save_quan; /* used up amount */ verbalize("%s for the other %s before buying %s.", ANGRY(shkp) ? "Pay" : "Please pay", xname(obj), save_quan > 1L ? "these" : "this one"); buy = PAY_SKIP; /* shk won't sell */ } } #ifndef GOLDOBJ if (buy == PAY_BUY && u.ugold + ESHK(shkp)->credit < ltmp) { #else if (buy == PAY_BUY && umoney + ESHK(shkp)->credit < ltmp) { #endif You("don't%s have gold%s enough to pay for %s.", stashed_gold ? " seem to" : "", (ESHK(shkp)->credit > 0L) ? " or credit" : "", doname(obj)); buy = itemize ? PAY_SKIP : PAY_CANT; } if (buy != PAY_BUY) { /* restore unpaid object to original state */ obj->quan = save_quan; obj->unpaid = 1; return buy; } pay(ltmp, shkp); shk_names_obj(shkp, obj, consumed ? "paid for %s at a cost of %ld gold piece%s.%s" : "bought %s for %ld gold piece%s.%s", ltmp, ""); obj->quan = save_quan; /* restore original count */ /* quan => amount just bought, save_quan => remaining unpaid count */ if (consumed) { if (quan != bp->bquan) { /* eliminate used-up portion; remainder is still unpaid */ bp->bquan = obj->quan; obj->unpaid = 1; bp->useup = 0; buy = PAY_SOME; } else { /* completely used-up, so get rid of it */ obj_extract_self(obj); /* assert( obj == *obj_p ); */ dealloc_obj(obj); *obj_p = 0; /* destroy pointer to freed object */ } } else if (itemize) update_inventory(); /* Done just once in dopay() if !itemize. */ return buy; } #endif /*OVL3*/ #ifdef OVLB static coord repo_location; /* repossession context */ /* routine called after dying (or quitting) */ boolean paybill(croaked) int croaked; /* -1: escaped dungeon; 0: quit; 1: died */ { register struct monst *mtmp, *mtmp2, *resident= (struct monst *)0; register boolean taken = FALSE; register int numsk = 0; /* if we escaped from the dungeon, shopkeepers can't reach us; shops don't occur on level 1, but this could happen if hero level teleports out of the dungeon and manages not to die */ if (croaked < 0) return FALSE; /* this is where inventory will end up if any shk takes it */ repo_location.x = repo_location.y = 0; /* give shopkeeper first crack */ if ((mtmp = shop_keeper(*u.ushops)) && inhishop(mtmp)) { numsk++; resident = mtmp; taken = inherits(resident, numsk, croaked); } for (mtmp = next_shkp(fmon, FALSE); mtmp; mtmp = next_shkp(mtmp2, FALSE)) { mtmp2 = mtmp->nmon; if (mtmp != resident) { /* for bones: we don't want a shopless shk around */ if(!on_level(&(ESHK(mtmp)->shoplevel), &u.uz)) mongone(mtmp); else { numsk++; taken |= inherits(mtmp, numsk, croaked); } } } if(numsk == 0) return(FALSE); return(taken); } STATIC_OVL boolean inherits(shkp, numsk, croaked) struct monst *shkp; int numsk; int croaked; { long loss = 0L; #ifdef GOLDOBJ long umoney; #endif struct eshk *eshkp = ESHK(shkp); boolean take = FALSE, taken = FALSE; int roomno = *u.ushops; char takes[BUFSZ]; /* the simplifying principle is that first-come */ /* already took everything you had. */ if (numsk > 1) { if (cansee(shkp->mx, shkp->my && croaked)) pline("%s %slooks at your corpse%s and %s.", Monnam(shkp), (!shkp->mcanmove || shkp->msleeping) ? "wakes up, " : "", !rn2(2) ? (shkp->female ? ", shakes her head," : ", shakes his head,") : "", !inhishop(shkp) ? "disappears" : "sighs"); rouse_shk(shkp, FALSE); /* wake shk for bones */ taken = (roomno == eshkp->shoproom); goto skip; } /* get one case out of the way: you die in the shop, the */ /* shopkeeper is peaceful, nothing stolen, nothing owed. */ if(roomno == eshkp->shoproom && inhishop(shkp) && !eshkp->billct && !eshkp->robbed && !eshkp->debit && NOTANGRY(shkp) && !eshkp->following) { if (invent) pline("%s gratefully inherits all your possessions.", shkname(shkp)); set_repo_loc(eshkp); goto clear; } if (eshkp->billct || eshkp->debit || eshkp->robbed) { if (roomno == eshkp->shoproom && inhishop(shkp)) loss = addupbill(shkp) + eshkp->debit; if (loss < eshkp->robbed) loss = eshkp->robbed; take = TRUE; } if (eshkp->following || ANGRY(shkp) || take) { #ifndef GOLDOBJ if (!invent && !u.ugold) goto skip; #else if (!invent) goto skip; umoney = money_cnt(invent); #endif takes[0] = '\0'; if (!shkp->mcanmove || shkp->msleeping) Strcat(takes, "wakes up and "); if (distu(shkp->mx, shkp->my) > 2) Strcat(takes, "comes and "); Strcat(takes, "takes"); #ifndef GOLDOBJ if (loss > u.ugold || !loss || roomno == eshkp->shoproom) { eshkp->robbed -= u.ugold; if (eshkp->robbed < 0L) eshkp->robbed = 0L; shkp->mgold += u.ugold; u.ugold = 0L; #else if (loss > umoney || !loss || roomno == eshkp->shoproom) { eshkp->robbed -= umoney; if (eshkp->robbed < 0L) eshkp->robbed = 0L; if (umoney > 0) money2mon(shkp, umoney); #endif flags.botl = 1; pline("%s %s all your possessions.", shkname(shkp), takes); taken = TRUE; /* where to put player's invent (after disclosure) */ set_repo_loc(eshkp); } else { #ifndef GOLDOBJ shkp->mgold += loss; u.ugold -= loss; #else money2mon(shkp, loss); #endif flags.botl = 1; pline("%s %s the %ld %s %sowed %s.", Monnam(shkp), takes, loss, currency(loss), strncmp(eshkp->customer, plname, PL_NSIZ) ? "" : "you ", shkp->female ? "her" : "him"); /* shopkeeper has now been paid in full */ pacify_shk(shkp); eshkp->following = 0; eshkp->robbed = 0L; } skip: /* in case we create bones */ rouse_shk(shkp, FALSE); /* wake up */ if (!inhishop(shkp)) home_shk(shkp, FALSE); } clear: setpaid(shkp); return(taken); } STATIC_OVL void set_repo_loc(eshkp) struct eshk *eshkp; { register xchar ox, oy; /* if you're not in this shk's shop room, or if you're in its doorway or entry spot, then your gear gets dumped all the way inside */ if (*u.ushops != eshkp->shoproom || IS_DOOR(levl[u.ux][u.uy].typ) || (u.ux == eshkp->shk.x && u.uy == eshkp->shk.y)) { /* shk.x,shk.y is the position immediately in * front of the door -- move in one more space */ ox = eshkp->shk.x; oy = eshkp->shk.y; ox += sgn(ox - eshkp->shd.x); oy += sgn(oy - eshkp->shd.y); } else { /* already inside this shk's shop */ ox = u.ux; oy = u.uy; } /* finish_paybill will deposit invent here */ repo_location.x = ox; repo_location.y = oy; } /* called at game exit, after inventory disclosure but before making bones */ void finish_paybill() { register struct obj *otmp; int ox = repo_location.x, oy = repo_location.y; #if 0 /* don't bother */ if (ox == 0 && oy == 0) impossible("finish_paybill: no location"); #endif /* normally done by savebones(), but that's too late in this case */ unleash_all(); /* transfer all of the character's inventory to the shop floor */ while ((otmp = invent) != 0) { otmp->owornmask = 0L; /* perhaps we should call setnotworn? */ otmp->lamplit = 0; /* avoid "goes out" msg from freeinv */ if (rn2(5)) curse(otmp); /* normal bones treatment for invent */ obj_extract_self(otmp); place_object(otmp, ox, oy); } } /* find obj on one of the lists */ STATIC_OVL struct obj * bp_to_obj(bp) register struct bill_x *bp; { register struct obj *obj; register unsigned int id = bp->bo_id; if(bp->useup) obj = o_on(id, billobjs); else obj = find_oid(id); return obj; } /* * Look for o_id on all lists but billobj. Return obj or NULL if not found. * Its OK for restore_timers() to call this function, there should not * be any timeouts on the billobjs chain. */ struct obj * find_oid(id) unsigned id; { struct obj *obj; struct monst *mon, *mmtmp[3]; int i; /* first check various obj lists directly */ if ((obj = o_on(id, invent)) != 0) return obj; if ((obj = o_on(id, fobj)) != 0) return obj; if ((obj = o_on(id, level.buriedobjlist)) != 0) return obj; if ((obj = o_on(id, migrating_objs)) != 0) return obj; /* not found yet; check inventory for members of various monst lists */ mmtmp[0] = fmon; mmtmp[1] = migrating_mons; mmtmp[2] = mydogs; /* for use during level changes */ for (i = 0; i < 3; i++) for (mon = mmtmp[i]; mon; mon = mon->nmon) if ((obj = o_on(id, mon->minvent)) != 0) return obj; /* not found at all */ return (struct obj *)0; } #endif /*OVLB*/ #ifdef OVL3 /* calculate the value that the shk will charge for [one of] an object */ STATIC_OVL long get_cost(obj, shkp) register struct obj *obj; register struct monst *shkp; /* if angry, impose a surcharge */ { register long tmp = getprice(obj, FALSE); if (!tmp) tmp = 5L; /* shopkeeper may notice if the player isn't very knowledgeable - especially when gem prices are concerned */ if (!obj->dknown || !objects[obj->otyp].oc_name_known) { if (obj->oclass == GEM_CLASS && objects[obj->otyp].oc_material == GLASS) { int i; /* get a value that's 'random' from game to game, but the same within the same game */ boolean pseudorand = (((int)u.ubirthday % obj->otyp) >= obj->otyp/2); /* all gems are priced high - real or not */ switch(obj->otyp - LAST_GEM) { case 1: /* white */ i = pseudorand ? DIAMOND : OPAL; break; case 2: /* blue */ i = pseudorand ? SAPPHIRE : AQUAMARINE; break; case 3: /* red */ i = pseudorand ? RUBY : JASPER; break; case 4: /* yellowish brown */ i = pseudorand ? AMBER : TOPAZ; break; case 5: /* orange */ i = pseudorand ? JACINTH : AGATE; break; case 6: /* yellow */ i = pseudorand ? CITRINE : CHRYSOBERYL; break; case 7: /* black */ i = pseudorand ? BLACK_OPAL : JET; break; case 8: /* green */ i = pseudorand ? EMERALD : JADE; break; case 9: /* violet */ i = pseudorand ? AMETHYST : FLUORITE; break; default: impossible("bad glass gem %d?", obj->otyp); i = STRANGE_OBJECT; break; } tmp = (long) objects[i].oc_cost; } else if (!(obj->o_id % 4)) /* arbitrarily impose surcharge */ tmp += tmp / 3L; } #ifdef TOURIST if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2)) || (uarmu && !uarm && !uarmc)) /* touristy shirt visible */ tmp += tmp / 3L; else #endif if (uarmh && uarmh->otyp == DUNCE_CAP) tmp += tmp / 3L; if (ACURR(A_CHA) > 18) tmp /= 2L; else if (ACURR(A_CHA) > 17) tmp -= tmp / 3L; else if (ACURR(A_CHA) > 15) tmp -= tmp / 4L; else if (ACURR(A_CHA) < 6) tmp *= 2L; else if (ACURR(A_CHA) < 8) tmp += tmp / 2L; else if (ACURR(A_CHA) < 11) tmp += tmp / 3L; if (tmp <= 0L) tmp = 1L; else if (obj->oartifact) tmp *= 4L; /* anger surcharge should match rile_shk's */ if (shkp && ESHK(shkp)->surcharge) tmp += (tmp + 2L) / 3L; return tmp; } #endif /*OVL3*/ #ifdef OVLB /* returns the price of a container's content. the price * of the "top" container is added in the calling functions. * a different price quoted for selling as vs. buying. */ long contained_cost(obj, shkp, price, usell, unpaid_only) register struct obj *obj; register struct monst *shkp; long price; register boolean usell; register boolean unpaid_only; { register struct obj *otmp; /* the price of contained objects */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; /* the "top" container is evaluated by caller */ if (usell) { if (saleable(shkp, otmp) && !otmp->unpaid && otmp->oclass != BALL_CLASS && !(otmp->oclass == FOOD_CLASS && otmp->oeaten) && !(Is_candle(otmp) && otmp->age < 20L * (long)objects[otmp->otyp].oc_cost)) price += set_cost(otmp, shkp); } else if (!otmp->no_charge && (!unpaid_only || (unpaid_only && otmp->unpaid))) { price += get_cost(otmp, shkp) * otmp->quan; } if (Has_contents(otmp)) price += contained_cost(otmp, shkp, price, usell, unpaid_only); } return(price); } long contained_gold(obj) register struct obj *obj; { register struct obj *otmp; register long value = 0L; /* accumulate contained gold */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) if (otmp->oclass == COIN_CLASS) value += otmp->quan; else if (Has_contents(otmp)) value += contained_gold(otmp); return(value); } STATIC_OVL void dropped_container(obj, shkp, sale) register struct obj *obj; register struct monst *shkp; register boolean sale; { register struct obj *otmp; /* the "top" container is treated in the calling fn */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; if (!otmp->unpaid && !(sale && saleable(shkp, otmp))) otmp->no_charge = 1; if (Has_contents(otmp)) dropped_container(otmp, shkp, sale); } } void picked_container(obj) register struct obj *obj; { register struct obj *otmp; /* the "top" container is treated in the calling fn */ for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; if (otmp->no_charge) otmp->no_charge = 0; if (Has_contents(otmp)) picked_container(otmp); } } #endif /*OVLB*/ #ifdef OVL3 /* calculate how much the shk will pay when buying [all of] an object */ STATIC_OVL long set_cost(obj, shkp) register struct obj *obj; register struct monst *shkp; { long tmp = getprice(obj, TRUE) * obj->quan; #ifdef TOURIST if ((Role_if(PM_TOURIST) && u.ulevel < (MAXULEV/2)) || (uarmu && !uarm && !uarmc)) /* touristy shirt visible */ tmp /= 3L; else #endif if (uarmh && uarmh->otyp == DUNCE_CAP) tmp /= 3L; else tmp /= 2L; /* shopkeeper may notice if the player isn't very knowledgeable - especially when gem prices are concerned */ if (!obj->dknown || !objects[obj->otyp].oc_name_known) { if (obj->oclass == GEM_CLASS) { /* different shop keepers give different prices */ if (objects[obj->otyp].oc_material == GEMSTONE || objects[obj->otyp].oc_material == GLASS) { tmp = (obj->otyp % (6 - shkp->m_id % 3)); tmp = (tmp + 3) * obj->quan; } } else if (tmp > 1L && !rn2(4)) tmp -= tmp / 4L; } return tmp; } #endif /*OVL3*/ #ifdef OVLB /* called from doinv(invent.c) for inventory of unpaid objects */ long unpaid_cost(unp_obj) register struct obj *unp_obj; /* known to be unpaid */ { register struct bill_x *bp = (struct bill_x *)0; register struct monst *shkp; for(shkp = next_shkp(fmon, TRUE); shkp; shkp = next_shkp(shkp->nmon, TRUE)) if ((bp = onbill(unp_obj, shkp, TRUE)) != 0) break; /* onbill() gave no message if unexpected problem occurred */ if(!bp) impossible("unpaid_cost: object wasn't on any bill!"); return bp ? unp_obj->quan * bp->price : 0L; } STATIC_OVL void add_one_tobill(obj, dummy) register struct obj *obj; register boolean dummy; { register struct monst *shkp; register struct bill_x *bp; register int bct; register char roomno = *u.ushops; if (!roomno) return; if (!(shkp = shop_keeper(roomno))) return; if (!inhishop(shkp)) return; if (onbill(obj, shkp, FALSE) || /* perhaps thrown away earlier */ (obj->oclass == FOOD_CLASS && obj->oeaten)) return; if (ESHK(shkp)->billct == BILLSZ) { You("got that for free!"); return; } /* To recognize objects the shopkeeper is not interested in. -dgk */ if (obj->no_charge) { obj->no_charge = 0; return; } bct = ESHK(shkp)->billct; bp = &(ESHK(shkp)->bill_p[bct]); bp->bo_id = obj->o_id; bp->bquan = obj->quan; if(dummy) { /* a dummy object must be inserted into */ bp->useup = 1; /* the billobjs chain here. crucial for */ add_to_billobjs(obj); /* eating floorfood in shop. see eat.c */ } else bp->useup = 0; bp->price = get_cost(obj, shkp); ESHK(shkp)->billct++; obj->unpaid = 1; } STATIC_OVL void add_to_billobjs(obj) struct obj *obj; { if (obj->where != OBJ_FREE) panic("add_to_billobjs: obj not free"); if (obj->timed) obj_stop_timers(obj); obj->nobj = billobjs; billobjs = obj; obj->where = OBJ_ONBILL; } /* recursive billing of objects within containers. */ STATIC_OVL void bill_box_content(obj, ininv, dummy, shkp) register struct obj *obj; register boolean ininv, dummy; register struct monst *shkp; { register struct obj *otmp; for (otmp = obj->cobj; otmp; otmp = otmp->nobj) { if (otmp->oclass == COIN_CLASS) continue; /* the "top" box is added in addtobill() */ if (!otmp->no_charge) add_one_tobill(otmp, dummy); if (Has_contents(otmp)) bill_box_content(otmp, ininv, dummy, shkp); } } /* shopkeeper tells you what you bought or sold, sometimes partly IDing it */ STATIC_OVL void shk_names_obj(shkp, obj, fmt, amt, arg) struct monst *shkp; struct obj *obj; const char *fmt; /* "%s %ld %s %s", doname(obj), amt, plur(amt), arg */ long amt; const char *arg; { char *obj_name, fmtbuf[BUFSZ]; boolean was_unknown = !obj->dknown; obj->dknown = TRUE; /* Use real name for ordinary weapons/armor, and spell-less * scrolls/books (that is, blank and mail), but only if the * object is within the shk's area of interest/expertise. */ if (!objects[obj->otyp].oc_magic && saleable(shkp, obj) && (obj->oclass == WEAPON_CLASS || obj->oclass == ARMOR_CLASS || obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS || obj->otyp == MIRROR)) { was_unknown |= !objects[obj->otyp].oc_name_known; makeknown(obj->otyp); } obj_name = doname(obj); /* Use an alternate message when extra information is being provided */ if (was_unknown) { Sprintf(fmtbuf, "%%s; you %s", fmt); obj_name[0] = highc(obj_name[0]); pline(fmtbuf, obj_name, (obj->quan > 1) ? "them" : "it", amt, plur(amt), arg); } else { You(fmt, obj_name, amt, plur(amt), arg); } } void addtobill(obj, ininv, dummy, silent) register struct obj *obj; register boolean ininv, dummy, silent; { register struct monst *shkp; register char roomno = *u.ushops; long ltmp = 0L, cltmp = 0L, gltmp = 0L; register boolean container = Has_contents(obj); if(!*u.ushops) return; if(!(shkp = shop_keeper(roomno))) return; if(!inhishop(shkp)) return; if(/* perhaps we threw it away earlier */ onbill(obj, shkp, FALSE) || (obj->oclass == FOOD_CLASS && obj->oeaten) ) return; if(ESHK(shkp)->billct == BILLSZ) { You("got that for free!"); return; } if(obj->oclass == COIN_CLASS) { costly_gold(obj->ox, obj->oy, obj->quan); return; } if(!obj->no_charge) ltmp = get_cost(obj, shkp); if (obj->no_charge && !container) { obj->no_charge = 0; return; } if(container) { if(obj->cobj == (struct obj *)0) { if(obj->no_charge) { obj->no_charge = 0; return; } else { add_one_tobill(obj, dummy); goto speak; } } else { cltmp += contained_cost(obj, shkp, cltmp, FALSE, FALSE); gltmp += contained_gold(obj); } if(ltmp) add_one_tobill(obj, dummy); if(cltmp) bill_box_content(obj, ininv, dummy, shkp); picked_container(obj); /* reset contained obj->no_charge */ ltmp += cltmp; if(gltmp) { costly_gold(obj->ox, obj->oy, gltmp); if(!ltmp) return; } if(obj->no_charge) obj->no_charge = 0; } else /* i.e., !container */ add_one_tobill(obj, dummy); speak: if (shkp->mcanmove && !shkp->msleeping && !silent) { char buf[BUFSZ]; if(!ltmp) { pline("%s has no interest in %s.", Monnam(shkp), the(xname(obj))); return; } Strcpy(buf, "\"For you, "); if (ANGRY(shkp)) Strcat(buf, "scum "); else { static const char *honored[5] = { "good", "honored", "most gracious", "esteemed", "most renowned and sacred" }; Strcat(buf, honored[rn2(4) + u.uevent.udemigod]); if (!is_human(youmonst.data)) Strcat(buf, " creature"); else Strcat(buf, (flags.female) ? " lady" : " sir"); } if(ininv) { long quan = obj->quan; obj->quan = 1L; /* fool xname() into giving singular */ pline("%s; only %ld %s %s.\"", buf, ltmp, (quan > 1L) ? "per" : "for this", xname(obj)); obj->quan = quan; } else pline("%s will cost you %ld %s%s.", The(xname(obj)), ltmp, currency(ltmp), (obj->quan > 1L) ? " each" : ""); } else if(!silent) { if(ltmp) pline_The("list price of %s is %ld %s%s.", the(xname(obj)), ltmp, currency(ltmp), (obj->quan > 1L) ? " each" : ""); else pline("%s does not notice.", Monnam(shkp)); } } void splitbill(obj, otmp) register struct obj *obj, *otmp; { /* otmp has been split off from obj */ register struct bill_x *bp; register long tmp; register struct monst *shkp = shop_keeper(*u.ushops); if(!shkp || !inhishop(shkp)) { impossible("splitbill: no resident shopkeeper??"); return; } bp = onbill(obj, shkp, FALSE); if(!bp) { impossible("splitbill: not on bill?"); return; } if(bp->bquan < otmp->quan) { impossible("Negative quantity on bill??"); } if(bp->bquan == otmp->quan) { impossible("Zero quantity on bill??"); } bp->bquan -= otmp->quan; if(ESHK(shkp)->billct == BILLSZ) otmp->unpaid = 0; else { tmp = bp->price; bp = &(ESHK(shkp)->bill_p[ESHK(shkp)->billct]); bp->bo_id = otmp->o_id; bp->bquan = otmp->quan; bp->useup = 0; bp->price = tmp; ESHK(shkp)->billct++; } } STATIC_OVL void sub_one_frombill(obj, shkp) register struct obj *obj; register struct monst *shkp; { register struct bill_x *bp; if((bp = onbill(obj, shkp, FALSE)) != 0) { register struct obj *otmp; obj->unpaid = 0; if(bp->bquan > obj->quan){ otmp = newobj(0); *otmp = *obj; bp->bo_id = otmp->o_id = flags.ident++; otmp->where = OBJ_FREE; otmp->quan = (bp->bquan -= obj->quan); otmp->owt = 0; /* superfluous */ otmp->onamelth = 0; otmp->oxlth = 0; otmp->oattached = OATTACHED_NOTHING; bp->useup = 1; add_to_billobjs(otmp); return; } ESHK(shkp)->billct--; #ifdef DUMB { /* DRS/NS 2.2.6 messes up -- Peter Kendell */ int indx = ESHK(shkp)->billct; *bp = ESHK(shkp)->bill_p[indx]; } #else *bp = ESHK(shkp)->bill_p[ESHK(shkp)->billct]; #endif return; } else if (obj->unpaid) { impossible("sub_one_frombill: unpaid object not on bill"); obj->unpaid = 0; } } /* recursive check of unpaid objects within nested containers. */ void subfrombill(obj, shkp) register struct obj *obj; register struct monst *shkp; { register struct obj *otmp; sub_one_frombill(obj, shkp); if (Has_contents(obj)) for(otmp = obj->cobj; otmp; otmp = otmp->nobj) { if(otmp->oclass == COIN_CLASS) continue; if (Has_contents(otmp)) subfrombill(otmp, shkp); else sub_one_frombill(otmp, shkp); } } #endif /*OVLB*/ #ifdef OVL3 STATIC_OVL long stolen_container(obj, shkp, price, ininv) register struct obj *obj; register struct monst *shkp; long price; register boolean ininv; { register struct obj *otmp; if(ininv && obj->unpaid) price += get_cost(obj, shkp); else { if(!obj->no_charge) price += get_cost(obj, shkp); obj->no_charge = 0; } /* the price of contained objects, if any */ for(otmp = obj->cobj; otmp; otmp = otmp->nobj) { if(otmp->oclass == COIN_CLASS) continue; if (!Has_contents(otmp)) { if(ininv) { if(otmp->unpaid) price += otmp->quan * get_cost(otmp, shkp); } else { if(!otmp->no_charge) { if(otmp->oclass != FOOD_CLASS || !otmp->oeaten) price += otmp->quan * get_cost(otmp, shkp); } otmp->no_charge = 0; } } else price += stolen_container(otmp, shkp, price, ininv); } return(price); } #endif /*OVL3*/ #ifdef OVLB long stolen_value(obj, x, y, peaceful, silent) register struct obj *obj; register xchar x, y; register boolean peaceful, silent; { register long value = 0L, gvalue = 0L; register struct monst *shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); if (!shkp || !inhishop(shkp)) return (0L); if(obj->oclass == COIN_CLASS) { gvalue += obj->quan; } else if (Has_contents(obj)) { register boolean ininv = !!count_unpaid(obj->cobj); value += stolen_container(obj, shkp, value, ininv); if(!ininv) gvalue += contained_gold(obj); } else if (!obj->no_charge && saleable(shkp, obj)) { value += get_cost(obj, shkp); } if(gvalue + value == 0L) return(0L); value += gvalue; if(peaceful) { boolean credit_use = !!ESHK(shkp)->credit; value = check_credit(value, shkp); /* 'peaceful' affects general treatment, but doesn't affect * the fact that other code expects that all charges after the * shopkeeper is angry are included in robbed, not debit */ if (ANGRY(shkp)) ESHK(shkp)->robbed += value; else ESHK(shkp)->debit += value; if(!silent) { const char *still = ""; if (credit_use) { if (ESHK(shkp)->credit) { You("have %ld %s credit remaining.", ESHK(shkp)->credit, currency(ESHK(shkp)->credit)); return value; } else if (!value) { You("have no credit remaining."); return 0; } still = "still "; } if(obj->oclass == COIN_CLASS) You("%sowe %s %ld %s!", still, mon_nam(shkp), value, currency(value)); else You("%sowe %s %ld %s for %s!", still, mon_nam(shkp), value, currency(value), obj->quan > 1L ? "them" : "it"); } } else { ESHK(shkp)->robbed += value; if(!silent) { if(cansee(shkp->mx, shkp->my)) { Norep("%s booms: \"%s, you are a thief!\"", Monnam(shkp), plname); } else Norep("You hear a scream, \"Thief!\""); } hot_pursuit(shkp); (void) angry_guards(FALSE); } return(value); } /* auto-response flag for/from "sell foo?" 'a' => 'y', 'q' => 'n' */ static char sell_response = 'a'; static int sell_how = SELL_NORMAL; /* can't just use sell_response='y' for auto_credit because the 'a' response shouldn't carry over from ordinary selling to credit selling */ static boolean auto_credit = FALSE; void sellobj_state(deliberate) int deliberate; { /* If we're deliberately dropping something, there's no automatic response to the shopkeeper's "want to sell" query; however, if we accidentally drop anything, the shk will buy it/them without asking. This retains the old pre-query risk that slippery fingers while in shops entailed: you drop it, you've lost it. */ sell_response = (deliberate != SELL_NORMAL) ? '\0' : 'a'; sell_how = deliberate; auto_credit = FALSE; } void sellobj(obj, x, y) register struct obj *obj; xchar x, y; { register struct monst *shkp; register struct eshk *eshkp; long ltmp = 0L, cltmp = 0L, gltmp = 0L, offer; boolean saleitem, cgold = FALSE, container = Has_contents(obj); boolean isgold = (obj->oclass == COIN_CLASS); boolean only_partially_your_contents = FALSE; if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp)) return; if(!costly_spot(x, y)) return; if(!*u.ushops) return; if(obj->unpaid && !container && !isgold) { sub_one_frombill(obj, shkp); return; } if(container) { /* find the price of content before subfrombill */ cltmp += contained_cost(obj, shkp, cltmp, TRUE, FALSE); /* find the value of contained gold */ gltmp += contained_gold(obj); cgold = (gltmp > 0L); } saleitem = saleable(shkp, obj); if(!isgold && !obj->unpaid && saleitem) ltmp = set_cost(obj, shkp); offer = ltmp + cltmp; /* get one case out of the way: nothing to sell, and no gold */ if(!isgold && ((offer + gltmp) == 0L || sell_how == SELL_DONTSELL)) { register boolean unpaid = (obj->unpaid || (container && count_unpaid(obj->cobj))); if(container) { dropped_container(obj, shkp, FALSE); if(!obj->unpaid && !saleitem) obj->no_charge = 1; if(obj->unpaid || count_unpaid(obj->cobj)) subfrombill(obj, shkp); } else obj->no_charge = 1; if(!unpaid && (sell_how != SELL_DONTSELL)) pline("%s seems uninterested.", Monnam(shkp)); return; } /* you dropped something of your own - probably want to sell it */ rouse_shk(shkp, TRUE); /* wake up sleeping or paralyzed shk */ eshkp = ESHK(shkp); if (ANGRY(shkp)) { /* they become shop-objects, no pay */ pline("Thank you, scum!"); subfrombill(obj, shkp); return; } if(eshkp->robbed) { /* shkp is not angry? */ if(isgold) offer = obj->quan; else if(cgold) offer += cgold; if((eshkp->robbed -= offer < 0L)) eshkp->robbed = 0L; if(offer) verbalize( "Thank you for your contribution to restock this recently plundered shop."); subfrombill(obj, shkp); return; } if(isgold || cgold) { if(!cgold) gltmp = obj->quan; if(eshkp->debit >= gltmp) { if(eshkp->loan) { /* you carry shop's gold */ if(eshkp->loan >= gltmp) eshkp->loan -= gltmp; else eshkp->loan = 0L; } eshkp->debit -= gltmp; Your("debt is %spaid off.", eshkp->debit ? "partially " : ""); } else { long delta = gltmp - eshkp->debit; eshkp->credit += delta; if(eshkp->debit) { eshkp->debit = 0L; eshkp->loan = 0L; Your("debt is paid off."); } pline("%ld %s %s added to your credit.", delta, currency(delta), delta > 1L ? "are" : "is"); } if(offer) goto move_on; else { if(!isgold) { if (container) dropped_container(obj, shkp, FALSE); if (!obj->unpaid && !saleitem) obj->no_charge = 1; subfrombill(obj, shkp); } return; } } move_on: if((!saleitem && !(container && cltmp > 0L)) || eshkp->billct == BILLSZ || obj->oclass == BALL_CLASS || obj->oclass == CHAIN_CLASS || offer == 0L || (obj->oclass == FOOD_CLASS && obj->oeaten) || (Is_candle(obj) && obj->age < 20L * (long)objects[obj->otyp].oc_cost)) { pline("%s seems uninterested%s.", Monnam(shkp), cgold ? " in the rest" : ""); if (container) dropped_container(obj, shkp, FALSE); obj->no_charge = 1; return; } #ifndef GOLDOBJ if(!shkp->mgold) { #else if(!money_cnt(shkp->minvent)) { #endif char c, qbuf[BUFSZ]; long tmpcr = ((offer * 9L) / 10L) + (offer <= 1L); if (sell_how == SELL_NORMAL || auto_credit) { c = sell_response = 'y'; } else if (sell_response != 'n') { pline("%s cannot pay you at present.", Monnam(shkp)); Sprintf(qbuf, "Will you accept %ld %s in credit for %s?", tmpcr, currency(tmpcr), doname(obj)); /* won't accept 'a' response here */ /* KLY - 3/2000 yes, we will, it's a damn nuisance to have to constantly hit 'y' to sell for credit */ c = ynaq(qbuf); if (c == 'a') { c = 'y'; auto_credit = TRUE; } } else /* previously specified "quit" */ c = 'n'; if (c == 'y') { shk_names_obj(shkp, obj, (sell_how != SELL_NORMAL) ? "traded %s for %ld zorkmid%s in %scredit." : "relinquish %s and acquire %ld zorkmid%s in %scredit.", tmpcr, (eshkp->credit > 0L) ? "additional " : ""); eshkp->credit += tmpcr; subfrombill(obj, shkp); } else { if (c == 'q') sell_response = 'n'; if (container) dropped_container(obj, shkp, FALSE); if (!obj->unpaid) obj->no_charge = 1; subfrombill(obj, shkp); } } else { char qbuf[BUFSZ]; #ifndef GOLDOBJ boolean short_funds = (offer > shkp->mgold); if (short_funds) offer = shkp->mgold; #else long shkmoney = money_cnt(shkp->minvent); boolean short_funds = (offer > shkmoney); if (short_funds) offer = shkmoney; #endif if (!sell_response) { only_partially_your_contents = (contained_cost(obj, shkp, 0L, FALSE, FALSE) != contained_cost(obj, shkp, 0L, FALSE, TRUE)); Sprintf(qbuf, "%s offers%s %ld gold piece%s for%s %s %s. Sell %s?", Monnam(shkp), short_funds ? " only" : "", offer, plur(offer), (!ltmp && cltmp && only_partially_your_contents) ? " your items in" : (!ltmp && cltmp) ? " the contents of" : "", obj->unpaid ? "the" : "your", cxname(obj), (obj->quan == 1L && !(!ltmp && cltmp && only_partially_your_contents)) ? "it" : "them"); } else qbuf[0] = '\0'; /* just to pacify lint */ switch (sell_response ? sell_response : ynaq(qbuf)) { case 'q': sell_response = 'n'; case 'n': if (container) dropped_container(obj, shkp, FALSE); if (!obj->unpaid) obj->no_charge = 1; subfrombill(obj, shkp); break; case 'a': sell_response = 'y'; case 'y': if (container) dropped_container(obj, shkp, TRUE); if (!obj->unpaid && !saleitem) obj->no_charge = 1; subfrombill(obj, shkp); pay(-offer, shkp); shk_names_obj(shkp, obj, (sell_how != SELL_NORMAL) ? (!ltmp && cltmp && only_partially_your_contents) ? "sold some items inside %s for %ld gold pieces%s.%s" : "sold %s for %ld gold piece%s.%s" : "relinquish %s and receive %ld gold piece%s in compensation.%s", offer, ""); break; default: impossible("invalid sell response"); } } } int doinvbill(mode) int mode; /* 0: deliver count 1: paged */ { #ifdef __SASC void sasc_bug(struct obj *, unsigned); #endif struct monst *shkp; struct eshk *eshkp; struct bill_x *bp, *end_bp; struct obj *obj; long totused; char *buf_p; winid datawin; shkp = shop_keeper(*u.ushops); if (!shkp || !inhishop(shkp)) { if (mode != 0) impossible("doinvbill: no shopkeeper?"); return 0; } eshkp = ESHK(shkp); if (mode == 0) { /* count expended items, so that the `I' command can decide whether to include 'x' in its prompt string */ int cnt = !eshkp->debit ? 0 : 1; for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct]; bp < end_bp; bp++) if (bp->useup || ((obj = bp_to_obj(bp)) != 0 && obj->quan < bp->bquan)) cnt++; return cnt; } datawin = create_nhwindow(NHW_MENU); putstr(datawin, 0, "Unpaid articles already used up:"); putstr(datawin, 0, ""); totused = 0L; for (bp = eshkp->bill_p, end_bp = &eshkp->bill_p[eshkp->billct]; bp < end_bp; bp++) { obj = bp_to_obj(bp); if(!obj) { impossible("Bad shopkeeper administration."); goto quit; } if(bp->useup || bp->bquan > obj->quan) { long oquan, uquan, thisused; unsigned save_unpaid; save_unpaid = obj->unpaid; oquan = obj->quan; uquan = (bp->useup ? bp->bquan : bp->bquan - oquan); thisused = bp->price * uquan; totused += thisused; obj->unpaid = 0; /* ditto */ /* Why 'x'? To match `I x', more or less. */ buf_p = xprname(obj, (char *)0, 'x', FALSE, thisused, uquan); #ifdef __SASC /* SAS/C 6.2 can't cope for some reason */ sasc_bug(obj,save_unpaid); #else obj->unpaid = save_unpaid; #endif putstr(datawin, 0, buf_p); } } if (eshkp->debit) { /* additional shop debt which has no itemization available */ if (totused) putstr(datawin, 0, ""); totused += eshkp->debit; buf_p = xprname((struct obj *)0, "usage charges and/or other fees", GOLD_SYM, FALSE, eshkp->debit, 0L); putstr(datawin, 0, buf_p); } buf_p = xprname((struct obj *)0, "Total:", '*', FALSE, totused, 0L); putstr(datawin, 0, ""); putstr(datawin, 0, buf_p); display_nhwindow(datawin, FALSE); quit: destroy_nhwindow(datawin); return(0); } #define HUNGRY 2 STATIC_OVL long getprice(obj, shk_buying) register struct obj *obj; boolean shk_buying; { register long tmp = (long) objects[obj->otyp].oc_cost; if (obj->oartifact) { tmp = arti_cost(obj); if (shk_buying) tmp /= 4; } switch(obj->oclass) { case FOOD_CLASS: /* simpler hunger check, (2-4)*cost */ if (u.uhs >= HUNGRY && !shk_buying) tmp *= (long) u.uhs; if (obj->oeaten) tmp = 0L; break; case WAND_CLASS: if (obj->spe == -1) tmp = 0L; break; case POTION_CLASS: if (obj->otyp == POT_WATER && !obj->blessed && !obj->cursed) tmp = 0L; break; case ARMOR_CLASS: case WEAPON_CLASS: if (obj->spe > 0) tmp += 10L * (long) obj->spe; break; case TOOL_CLASS: if (Is_candle(obj) && obj->age < 20L * (long)objects[obj->otyp].oc_cost) tmp /= 2L; break; } return tmp; } /* shk catches thrown pick-axe */ struct monst * shkcatch(obj, x, y) register struct obj *obj; register xchar x, y; { register struct monst *shkp; if (!(shkp = shop_keeper(inside_shop(x, y))) || !inhishop(shkp)) return(0); if (shkp->mcanmove && !shkp->msleeping && (*u.ushops != ESHK(shkp)->shoproom || !inside_shop(u.ux, u.uy)) && dist2(shkp->mx, shkp->my, x, y) < 3 && /* if it is the shk's pos, you hit and anger him */ (shkp->mx != x || shkp->my != y)) { if (mnearto(shkp, x, y, TRUE)) verbalize("Out of my way, scum!"); if (cansee(x, y)) { pline("%s nimbly%s catches %s.", Monnam(shkp), (x == shkp->mx && y == shkp->my) ? "" : " reaches over and", the(xname(obj))); if (!canspotmon(shkp)) map_invisible(x, y); delay_output(); mark_synch(); } subfrombill(obj, shkp); (void) mpickobj(shkp, obj); return shkp; } return (struct monst *)0; } void add_damage(x, y, cost) register xchar x, y; long cost; { struct damage *tmp_dam; char *shops; if (IS_DOOR(levl[x][y].typ)) { struct monst *mtmp; /* Don't schedule for repair unless it's a real shop entrance */ for (shops = in_rooms(x, y, SHOPBASE); *shops; shops++) if ((mtmp = shop_keeper(*shops)) != 0 && x == ESHK(mtmp)->shd.x && y == ESHK(mtmp)->shd.y) break; if (!*shops) return; } for (tmp_dam = level.damagelist; tmp_dam; tmp_dam = tmp_dam->next) if (tmp_dam->place.x == x && tmp_dam->place.y == y) { tmp_dam->cost += cost; return; } tmp_dam = (struct damage *)alloc((unsigned)sizeof(struct damage)); tmp_dam->when = monstermoves; tmp_dam->place.x = x; tmp_dam->place.y = y; tmp_dam->cost = cost; tmp_dam->typ = levl[x][y].typ; tmp_dam->next = level.damagelist; level.damagelist = tmp_dam; /* If player saw damage, display as a wall forever */ if (cansee(x, y)) levl[x][y].seenv = SVALL; } #endif /*OVLB*/ #ifdef OVL0 /* * Do something about damage. Either (!croaked) try to repair it, or * (croaked) just discard damage structs for non-shared locations, since * they'll never get repaired. Assume that shared locations will get * repaired eventually by the other shopkeeper(s). This might be an erroneous * assumption (they might all be dead too), but we have no reasonable way of * telling that. */ STATIC_OVL void remove_damage(shkp, croaked) register struct monst *shkp; register boolean croaked; { register struct damage *tmp_dam, *tmp2_dam; register boolean did_repair = FALSE, saw_door = FALSE; register boolean saw_floor = FALSE, stop_picking = FALSE; register boolean saw_untrap = FALSE; uchar saw_walls = 0; tmp_dam = level.damagelist; tmp2_dam = 0; while (tmp_dam) { register xchar x = tmp_dam->place.x, y = tmp_dam->place.y; char shops[5]; int disposition; disposition = 0; Strcpy(shops, in_rooms(x, y, SHOPBASE)); if (index(shops, ESHK(shkp)->shoproom)) { if (croaked) disposition = (shops[1])? 0 : 1; else if (stop_picking) disposition = repair_damage(shkp, tmp_dam, FALSE); else { /* Defer the stop_occupation() until after repair msgs */ if (closed_door(x, y)) stop_picking = picking_at(x, y); disposition = repair_damage(shkp, tmp_dam, FALSE); if (!disposition) stop_picking = FALSE; } } if (!disposition) { tmp2_dam = tmp_dam; tmp_dam = tmp_dam->next; continue; } if (disposition > 1) { did_repair = TRUE; if (cansee(x, y)) { if (IS_WALL(levl[x][y].typ)) saw_walls++; else if (IS_DOOR(levl[x][y].typ)) saw_door = TRUE; else if (disposition == 3) /* untrapped */ saw_untrap = TRUE; else saw_floor = TRUE; } } tmp_dam = tmp_dam->next; if (!tmp2_dam) { free((genericptr_t)level.damagelist); level.damagelist = tmp_dam; } else { free((genericptr_t)tmp2_dam->next); tmp2_dam->next = tmp_dam; } } if (!did_repair) return; if (saw_walls) { pline("Suddenly, %s section%s of wall close%s up!", (saw_walls == 1) ? "a" : (saw_walls <= 3) ? "some" : "several", (saw_walls == 1) ? "" : "s", (saw_walls == 1) ? "s" : ""); if (saw_door) pline_The("shop door reappears!"); if (saw_floor) pline_The("floor is repaired!"); } else { if (saw_door) pline("Suddenly, the shop door reappears!"); else if (saw_floor) pline("Suddenly, the floor damage is gone!"); else if (saw_untrap) pline("Suddenly, the trap is removed from the floor!"); else if (inside_shop(u.ux, u.uy) == ESHK(shkp)->shoproom) You_feel("more claustrophobic than before."); else if (flags.soundok && !rn2(10)) Norep("The dungeon acoustics noticeably change."); } if (stop_picking) stop_occupation(); } /* * 0: repair postponed, 1: silent repair (no messages), 2: normal repair * 3: untrap */ int repair_damage(shkp, tmp_dam, catchup) register struct monst *shkp; register struct damage *tmp_dam; boolean catchup; /* restoring a level */ { register xchar x, y, i; xchar litter[9]; register struct monst *mtmp; register struct obj *otmp; register struct trap *ttmp; if ((monstermoves - tmp_dam->when) < REPAIR_DELAY) return(0); if (shkp->msleeping || !shkp->mcanmove || ESHK(shkp)->following) return(0); x = tmp_dam->place.x; y = tmp_dam->place.y; if (!IS_ROOM(tmp_dam->typ)) { if (x == u.ux && y == u.uy) if (!Passes_walls) return(0); if (x == shkp->mx && y == shkp->my) return(0); if ((mtmp = m_at(x, y)) && (!passes_walls(mtmp->data))) return(0); } if ((ttmp = t_at(x, y)) != 0) { if (x == u.ux && y == u.uy) if (!Passes_walls) return(0); if (ttmp->ttyp == LANDMINE || ttmp->ttyp == BEAR_TRAP) { /* convert to an object */ otmp = mksobj((ttmp->ttyp == LANDMINE) ? LAND_MINE : BEARTRAP, TRUE, FALSE); otmp->quan= 1; otmp->owt = weight(otmp); (void) mpickobj(shkp, otmp); } deltrap(ttmp); if(IS_DOOR(tmp_dam->typ)) { levl[x][y].doormask = D_CLOSED; /* arbitrary */ block_point(x, y); } else if (IS_WALL(tmp_dam->typ)) { levl[x][y].typ = tmp_dam->typ; block_point(x, y); } newsym(x, y); return(3); } if (IS_ROOM(tmp_dam->typ)) { /* No messages, because player already filled trap door */ return(1); } if ((tmp_dam->typ == levl[x][y].typ) && (!IS_DOOR(tmp_dam->typ) || (levl[x][y].doormask > D_BROKEN))) /* No messages if player already replaced shop door */ return(1); levl[x][y].typ = tmp_dam->typ; (void) memset((genericptr_t)litter, 0, sizeof(litter)); if ((otmp = level.objects[x][y]) != 0) { /* Scatter objects haphazardly into the shop */ #define NEED_UPDATE 1 #define OPEN 2 #define INSHOP 4 #define horiz(i) ((i%3)-1) #define vert(i) ((i/3)-1) for (i = 0; i < 9; i++) { if ((i == 4) || (!ZAP_POS(levl[x+horiz(i)][y+vert(i)].typ))) continue; litter[i] = OPEN; if (inside_shop(x+horiz(i), y+vert(i)) == ESHK(shkp)->shoproom) litter[i] |= INSHOP; } if (Punished && !u.uswallow && ((uchain->ox == x && uchain->oy == y) || (uball->ox == x && uball->oy == y))) { /* * Either the ball or chain is in the repair location. * * Take the easy way out and put ball&chain under hero. */ verbalize("Get your junk out of my wall!"); unplacebc(); /* pick 'em up */ placebc(); /* put 'em down */ } while ((otmp = level.objects[x][y]) != 0) /* Don't mess w/ boulders -- just merge into wall */ if ((otmp->otyp == BOULDER) || (otmp->otyp == ROCK)) { obj_extract_self(otmp); obfree(otmp, (struct obj *)0); } else { while (!(litter[i = rn2(9)] & INSHOP)); remove_object(otmp); place_object(otmp, x+horiz(i), y+vert(i)); litter[i] |= NEED_UPDATE; } } if (catchup) return 1; /* repair occurred while off level */ block_point(x, y); if(IS_DOOR(tmp_dam->typ)) { levl[x][y].doormask = D_CLOSED; /* arbitrary */ newsym(x, y); } else { /* don't set doormask - it is (hopefully) the same as it was */ /* if not, perhaps save it with the damage array... */ if (IS_WALL(tmp_dam->typ) && cansee(x, y)) { /* Player sees actual repair process, so they KNOW it's a wall */ levl[x][y].seenv = SVALL; newsym(x, y); } /* Mark this wall as "repaired". There currently is no code */ /* to do anything about repaired walls, so don't do it. */ } for (i = 0; i < 9; i++) if (litter[i] & NEED_UPDATE) newsym(x+horiz(i), y+vert(i)); return(2); #undef NEED_UPDATE #undef OPEN #undef INSHOP #undef vert #undef horiz } #endif /*OVL0*/ #ifdef OVL3 /* * shk_move: return 1: moved 0: didn't -1: let m_move do it -2: died */ int shk_move(shkp) register struct monst *shkp; { register xchar gx,gy,omx,omy; register int udist; register schar appr; register struct eshk *eshkp = ESHK(shkp); int z; boolean uondoor = FALSE, satdoor, avoid = FALSE, badinv; omx = shkp->mx; omy = shkp->my; if (inhishop(shkp)) remove_damage(shkp, FALSE); if((udist = distu(omx,omy)) < 3 && (shkp->data != &mons[PM_GRID_BUG] || (omx==u.ux || omy==u.uy))) { if(ANGRY(shkp) || (Conflict && !resist(shkp, RING_CLASS, 0, 0))) { if(Displaced) Your("displaced image doesn't fool %s!", mon_nam(shkp)); (void) mattacku(shkp); return(0); } if(eshkp->following) { if(strncmp(eshkp->customer, plname, PL_NSIZ)) { verbalize("%s, %s! I was looking for %s.", Hello(shkp), plname, eshkp->customer); eshkp->following = 0; return(0); } if(moves > followmsg+4) { verbalize("%s, %s! Didn't you forget to pay?", Hello(shkp), plname); followmsg = moves; if (!rn2(9)) { pline("%s doesn't like customers who don't pay.", Monnam(shkp)); rile_shk(shkp); } } if(udist < 2) return(0); } } appr = 1; gx = eshkp->shk.x; gy = eshkp->shk.y; satdoor = (gx == omx && gy == omy); if(eshkp->following || ((z = holetime()) >= 0 && z*z <= udist)){ /* [This distance check used to apply regardless of whether the shk was following, but that resulted in m_move() sometimes taking the shk out of the shop if the player had fenced him in with boulders or traps. Such voluntary abandonment left unpaid objects in invent, triggering billing impossibilities on the next level once the character fell through the hole.] */ if (udist > 4 && eshkp->following) return(-1); /* leave it to m_move */ gx = u.ux; gy = u.uy; } else if(ANGRY(shkp)) { /* Move towards the hero if the shopkeeper can see him. */ if(shkp->mcansee && m_canseeu(shkp)) { gx = u.ux; gy = u.uy; } avoid = FALSE; } else { #define GDIST(x,y) (dist2(x,y,gx,gy)) if (Invis #ifdef STEED || u.usteed #endif ) { avoid = FALSE; } else { uondoor = (u.ux == eshkp->shd.x && u.uy == eshkp->shd.y); if(uondoor) { badinv = (carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK) || (Fast && (sobj_at(PICK_AXE, u.ux, u.uy) || sobj_at(DWARVISH_MATTOCK, u.ux, u.uy)))); if(satdoor && badinv) return(0); avoid = !badinv; } else { avoid = (*u.ushops && distu(gx,gy) > 8); badinv = FALSE; } if(((!eshkp->robbed && !eshkp->billct && !eshkp->debit) || avoid) && GDIST(omx,omy) < 3) { if (!badinv && !onlineu(omx,omy)) return(0); if(satdoor) appr = gx = gy = 0; } } } z = move_special(shkp,inhishop(shkp),appr,uondoor,avoid,omx,omy,gx,gy); if (z > 0) after_shk_move(shkp); return z; } /* called after shopkeeper moves, in case the move causes re-entry into shop */ void after_shk_move(shkp) struct monst *shkp; { struct eshk *eshkp = ESHK(shkp); if (eshkp->bill_p == (struct bill_x *) -1000 && inhishop(shkp)) { /* reset bill_p, need to re-calc player's occupancy too */ eshkp->bill_p = &eshkp->bill[0]; check_special_room(FALSE); } } #endif /*OVL3*/ #ifdef OVLB /* for use in levl_follower (mondata.c) */ boolean is_fshk(mtmp) register struct monst *mtmp; { return((boolean)(mtmp->isshk && ESHK(mtmp)->following)); } /* You are digging in the shop. */ void shopdig(fall) register int fall; { register struct monst *shkp = shop_keeper(*u.ushops); int lang; const char *grabs = "grabs"; if(!shkp) return; /* 0 == can't speak, 1 == makes animal noises, 2 == speaks */ lang = 0; if (shkp->msleeping || !shkp->mcanmove || is_silent(shkp->data)) ; /* lang stays 0 */ else if (shkp->data->msound <= MS_ANIMAL) lang = 1; else if (shkp->data->msound >= MS_HUMANOID) lang = 2; if(!inhishop(shkp)) { if (Role_if(PM_KNIGHT)) { You_feel("like a common thief."); adjalign(-sgn(u.ualign.type)); } return; } if(!fall) { if (lang == 2) { if(u.utraptype == TT_PIT) verbalize( "Be careful, %s, or you might fall through the floor.", flags.female ? "madam" : "sir"); else verbalize("%s, do not damage the floor here!", flags.female ? "Madam" : "Sir"); } if (Role_if(PM_KNIGHT)) { You_feel("like a common thief."); adjalign(-sgn(u.ualign.type)); } } else if(!um_dist(shkp->mx, shkp->my, 5) && !shkp->msleeping && shkp->mcanmove && (ESHK(shkp)->billct || ESHK(shkp)->debit)) { register struct obj *obj, *obj2; if (nolimbs(shkp->data)) { grabs = "knocks off"; #if 0 /* This is what should happen, but for balance * reasons, it isn't currently. */ if (lang == 2) pline("%s curses %s inability to grab your backpack!", shkname(shkp), mhim(shkp)); rile_shk(shkp); return; #endif } if (distu(shkp->mx, shkp->my) > 2) { mnexto(shkp); /* for some reason the shopkeeper can't come next to you */ if (distu(shkp->mx, shkp->my) > 2) { if (lang == 2) pline("%s curses you in anger and frustration!", shkname(shkp)); rile_shk(shkp); return; } else pline("%s %s, and %s your backpack!", shkname(shkp), makeplural(locomotion(shkp->data,"leap")), grabs); } else pline("%s %s your backpack!", shkname(shkp), grabs); for(obj = invent; obj; obj = obj2) { obj2 = obj->nobj; if ((obj->owornmask & ~(W_SWAPWEP|W_QUIVER)) != 0 || (obj == uswapwep && u.twoweap) || (obj->otyp == LEASH && obj->leashmon)) continue; if (obj == current_wand) continue; setnotworn(obj); freeinv(obj); subfrombill(obj, shkp); (void) add_to_minv(shkp, obj); /* may free obj */ } } } #ifdef KOPS STATIC_OVL void makekops(mm) coord *mm; { static const short k_mndx[4] = { PM_KEYSTONE_KOP, PM_KOP_SERGEANT, PM_KOP_LIEUTENANT, PM_KOP_KAPTAIN }; int k_cnt[4], cnt, mndx, k; k_cnt[0] = cnt = abs(depth(&u.uz)) + rnd(5); k_cnt[1] = (cnt / 3) + 1; /* at least one sarge */ k_cnt[2] = (cnt / 6); /* maybe a lieutenant */ k_cnt[3] = (cnt / 9); /* and maybe a kaptain */ for (k = 0; k < 4; k++) { if ((cnt = k_cnt[k]) == 0) break; mndx = k_mndx[k]; if (mvitals[mndx].mvflags & G_GONE) continue; while (cnt--) if (enexto(mm, mm->x, mm->y, &mons[mndx])) (void) makemon(&mons[mndx], mm->x, mm->y, NO_MM_FLAGS); } } #endif /* KOPS */ void pay_for_damage(dmgstr, cant_mollify) const char *dmgstr; boolean cant_mollify; { register struct monst *shkp = (struct monst *)0; char shops_affected[5]; register boolean uinshp = (*u.ushops != '\0'); char qbuf[80]; register xchar x, y; boolean dugwall = !strcmp(dmgstr, "dig into") || /* wand */ !strcmp(dmgstr, "damage"); /* pick-axe */ struct damage *tmp_dam, *appear_here = 0; /* any number >= (80*80)+(24*24) would do, actually */ long cost_of_damage = 0L; unsigned int nearest_shk = 7000, nearest_damage = 7000; int picks = 0; for (tmp_dam = level.damagelist; (tmp_dam && (tmp_dam->when == monstermoves)); tmp_dam = tmp_dam->next) { char *shp; if (!tmp_dam->cost) continue; cost_of_damage += tmp_dam->cost; Strcpy(shops_affected, in_rooms(tmp_dam->place.x, tmp_dam->place.y, SHOPBASE)); for (shp = shops_affected; *shp; shp++) { struct monst *tmp_shk; unsigned int shk_distance; if (!(tmp_shk = shop_keeper(*shp))) continue; if (tmp_shk == shkp) { unsigned int damage_distance = distu(tmp_dam->place.x, tmp_dam->place.y); if (damage_distance < nearest_damage) { nearest_damage = damage_distance; appear_here = tmp_dam; } continue; } if (!inhishop(tmp_shk)) continue; shk_distance = distu(tmp_shk->mx, tmp_shk->my); if (shk_distance > nearest_shk) continue; if ((shk_distance == nearest_shk) && picks) { if (rn2(++picks)) continue; } else picks = 1; shkp = tmp_shk; nearest_shk = shk_distance; appear_here = tmp_dam; nearest_damage = distu(tmp_dam->place.x, tmp_dam->place.y); } } if (!cost_of_damage || !shkp) return; x = appear_here->place.x; y = appear_here->place.y; /* not the best introduction to the shk... */ (void) strncpy(ESHK(shkp)->customer,plname,PL_NSIZ); /* if the shk is already on the war path, be sure it's all out */ if(ANGRY(shkp) || ESHK(shkp)->following) { hot_pursuit(shkp); return; } /* if the shk is not in their shop.. */ if(!*in_rooms(shkp->mx,shkp->my,SHOPBASE)) { if(!cansee(shkp->mx, shkp->my)) return; goto getcad; } if(uinshp) { if(um_dist(shkp->mx, shkp->my, 1) && !um_dist(shkp->mx, shkp->my, 3)) { pline("%s leaps towards you!", shkname(shkp)); mnexto(shkp); } if(um_dist(shkp->mx, shkp->my, 1)) goto getcad; } else { /* * Make shkp show up at the door. Effect: If there is a monster * in the doorway, have the hero hear the shopkeeper yell a bit, * pause, then have the shopkeeper appear at the door, having * yanked the hapless critter out of the way. */ if (MON_AT(x, y)) { if(flags.soundok) { You_hear("an angry voice:"); verbalize("Out of my way, scum!"); wait_synch(); #if defined(UNIX) || defined(VMS) # if defined(SYSV) || defined(ULTRIX) || defined(VMS) (void) # endif sleep(1); #endif } } (void) mnearto(shkp, x, y, TRUE); } if((um_dist(x, y, 1) && !uinshp) || cant_mollify || #ifndef GOLDOBJ (u.ugold + ESHK(shkp)->credit) < cost_of_damage #else (money_cnt(invent) + ESHK(shkp)->credit) < cost_of_damage #endif || !rn2(50)) { if(um_dist(x, y, 1) && !uinshp) { pline("%s shouts:", shkname(shkp)); verbalize("Who dared %s my %s?", dmgstr, dugwall ? "shop" : "door"); } else { getcad: verbalize("How dare you %s my %s?", dmgstr, dugwall ? "shop" : "door"); } hot_pursuit(shkp); return; } if (Invis) Your("invisibility does not fool %s!", shkname(shkp)); Sprintf(qbuf,"\"Cad! You did %ld %s worth of damage!\" Pay? ", cost_of_damage, currency(cost_of_damage)); if(yn(qbuf) != 'n') { cost_of_damage = check_credit(cost_of_damage, shkp); #ifndef GOLDOBJ u.ugold -= cost_of_damage; shkp->mgold += cost_of_damage; #else money2mon(shkp, cost_of_damage); #endif flags.botl = 1; pline("Mollified, %s accepts your restitution.", shkname(shkp)); /* move shk back to his home loc */ home_shk(shkp, FALSE); pacify_shk(shkp); } else { verbalize("Oh, yes! You'll pay!"); hot_pursuit(shkp); adjalign(-sgn(u.ualign.type)); } } #endif /*OVLB*/ #ifdef OVL0 /* called in dokick.c when we kick an object that might be in a store */ boolean costly_spot(x, y) register xchar x, y; { register struct monst *shkp; if (!level.flags.has_shop) return FALSE; shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); if(!shkp || !inhishop(shkp)) return(FALSE); return((boolean)(inside_shop(x, y) && !(x == ESHK(shkp)->shk.x && y == ESHK(shkp)->shk.y))); } #endif /*OVL0*/ #ifdef OVLB /* called by dotalk(sounds.c) when #chatting; returns obj if location contains shop goods and shopkeeper is willing & able to speak */ struct obj * shop_object(x, y) register xchar x, y; { register struct obj *otmp; register struct monst *shkp; if(!(shkp = shop_keeper(*in_rooms(x, y, SHOPBASE))) || !inhishop(shkp)) return(struct obj *)0; for (otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if (otmp->oclass != COIN_CLASS) break; /* note: otmp might have ->no_charge set, but that's ok */ return (otmp && costly_spot(x, y) && NOTANGRY(shkp) && shkp->mcanmove && !shkp->msleeping) ? otmp : (struct obj *)0; } /* give price quotes for all objects linked to this one (ie, on this spot) */ void price_quote(first_obj) register struct obj *first_obj; { register struct obj *otmp; char buf[BUFSZ], price[40]; long cost; int cnt = 0; winid tmpwin; struct monst *shkp = shop_keeper(inside_shop(u.ux, u.uy)); tmpwin = create_nhwindow(NHW_MENU); putstr(tmpwin, 0, "Fine goods for sale:"); putstr(tmpwin, 0, ""); for (otmp = first_obj; otmp; otmp = otmp->nexthere) { if (otmp->oclass == COIN_CLASS) continue; cost = (otmp->no_charge || otmp == uball || otmp == uchain) ? 0L : get_cost(otmp, (struct monst *)0); if (Has_contents(otmp)) cost += contained_cost(otmp, shkp, 0L, FALSE, FALSE); if (!cost) { Strcpy(price, "no charge"); } else { Sprintf(price, "%ld %s%s", cost, currency(cost), otmp->quan > 1L ? " each" : ""); } Sprintf(buf, "%s, %s", doname(otmp), price); putstr(tmpwin, 0, buf), cnt++; } if (cnt > 1) { display_nhwindow(tmpwin, TRUE); } else if (cnt == 1) { if (first_obj->no_charge || first_obj == uball || first_obj == uchain){ pline("%s!", buf); /* buf still contains the string */ } else { /* print cost in slightly different format, so can't reuse buf */ cost = get_cost(first_obj, (struct monst *)0); if (Has_contents(first_obj)) cost += contained_cost(first_obj, shkp, 0L, FALSE, FALSE); pline("%s, price %ld %s%s%s", doname(first_obj), cost, currency(cost), first_obj->quan > 1L ? " each" : "", shk_embellish(first_obj, cost)); } } destroy_nhwindow(tmpwin); } #endif /*OVLB*/ #ifdef OVL3 STATIC_OVL const char * shk_embellish(itm, cost) register struct obj *itm; long cost; { if (!rn2(3)) { register int o, choice = rn2(5); if (choice == 0) choice = (cost < 100L ? 1 : cost < 500L ? 2 : 3); switch (choice) { case 4: if (cost < 10L) break; else o = itm->oclass; if (o == FOOD_CLASS) return ", gourmets' delight!"; if (objects[itm->otyp].oc_name_known ? objects[itm->otyp].oc_magic : (o == AMULET_CLASS || o == RING_CLASS || o == WAND_CLASS || o == POTION_CLASS || o == SCROLL_CLASS || o == SPBOOK_CLASS)) return ", painstakingly developed!"; return ", superb craftsmanship!"; case 3: return ", finest quality."; case 2: return ", an excellent choice."; case 1: return ", a real bargain."; default: break; } } else if (itm->oartifact) { return ", one of a kind!"; } return "."; } #endif /*OVL3*/ #ifdef OVLB /* First 4 supplied by Ronen and Tamar, remainder by development team */ const char *Izchak_speaks[]={ "%s says: 'These shopping malls give me a headache.'", "%s says: 'Slow down. Think clearly.'", "%s says: 'You need to take things one at a time.'", "%s says: 'I don't like poofy coffee... give me Columbian Supremo.'", "%s says that getting the devteam's agreement on anything is difficult.", "%s says that he has noticed those who serve their deity will prosper.", "%s says: 'Don't try to steal from me - I have friends in high places!'", "%s says: 'You may well need something from this shop in the future.'", "%s comments about the Valley of the Dead as being a gateway." }; void shk_chat(shkp) struct monst *shkp; { struct eshk *eshk; #ifdef GOLDOBJ long shkmoney; #endif if (!shkp->isshk) { /* The monster type is shopkeeper, but this monster is not actually a shk, which could happen if someone wishes for a shopkeeper statue and then animates it. (Note: shkname() would be "" in a case like this.) */ pline("%s asks whether you've seen any untended shops recently.", Monnam(shkp)); /* [Perhaps we ought to check whether this conversation is taking place inside an untended shop, but a shopless shk can probably be expected to be rather disoriented.] */ return; } eshk = ESHK(shkp); if (ANGRY(shkp)) pline("%s mentions how much %s dislikes %s customers.", shkname(shkp), mhe(shkp), eshk->robbed ? "non-paying" : "rude"); else if (eshk->following) { if (strncmp(eshk->customer, plname, PL_NSIZ)) { verbalize("%s %s! I was looking for %s.", Hello(shkp), plname, eshk->customer); eshk->following = 0; } else { verbalize("%s %s! Didn't you forget to pay?", Hello(shkp), plname); } } else if (eshk->billct) { register long total = addupbill(shkp) + eshk->debit; pline("%s says that your bill comes to %ld %s.", shkname(shkp), total, currency(total)); } else if (eshk->debit) pline("%s reminds you that you owe %s %ld %s.", shkname(shkp), mhim(shkp), eshk->debit, currency(eshk->debit)); else if (eshk->credit) pline("%s encourages you to use your %ld %s of credit.", shkname(shkp), eshk->credit, currency(eshk->credit)); else if (eshk->robbed) pline("%s complains about a recent robbery.", shkname(shkp)); #ifndef GOLDOBJ else if (shkp->mgold < 50) #else else if ((shkmoney = money_cnt(shkp->minvent)) < 50) #endif pline("%s complains that business is bad.", shkname(shkp)); #ifndef GOLDOBJ else if (shkp->mgold > 4000) #else else if (shkmoney > 4000) #endif pline("%s says that business is good.", shkname(shkp)); else if (strcmp(shkname(shkp), "Izchak") == 0) pline(Izchak_speaks[rn2(SIZE(Izchak_speaks))],shkname(shkp)); else pline("%s talks about the problem of shoplifters.",shkname(shkp)); } #ifdef KOPS STATIC_OVL void kops_gone(silent) register boolean silent; { register int cnt = 0; register struct monst *mtmp, *mtmp2; for (mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; if (mtmp->data->mlet == S_KOP) { if (canspotmon(mtmp)) cnt++; mongone(mtmp); } } if (cnt && !silent) pline_The("Kop%s (disappointed) vanish%s into thin air.", plur(cnt), cnt == 1 ? "es" : ""); } #endif /* KOPS */ #endif /*OVLB*/ #ifdef OVL3 STATIC_OVL long cost_per_charge(shkp, otmp, altusage) struct monst *shkp; struct obj *otmp; boolean altusage; /* some items have an "alternate" use with different cost */ { long tmp = 0L; if(!shkp || !inhishop(shkp)) return(0L); /* insurance */ tmp = get_cost(otmp, shkp); /* The idea is to make the exhaustive use of */ /* an unpaid item more expensive than buying */ /* it outright. */ if(otmp->otyp == MAGIC_LAMP) { /* 1 */ /* normal use (ie, as light source) of a magic lamp never degrades its value, but not charging anything would make identifcation too easy; charge an amount comparable to what is charged for an ordinary lamp (don't bother with angry shk surchage) */ if (!altusage) tmp = (long) objects[OIL_LAMP].oc_cost; else tmp += tmp / 3L; /* djinni is being released */ } else if(otmp->otyp == MAGIC_MARKER) { /* 70 - 100 */ /* no way to determine in advance */ /* how many charges will be wasted. */ /* so, arbitrarily, one half of the */ /* price per use. */ tmp /= 2L; } else if(otmp->otyp == BAG_OF_TRICKS || /* 1 - 20 */ otmp->otyp == HORN_OF_PLENTY) { tmp /= 5L; } else if(otmp->otyp == CRYSTAL_BALL || /* 1 - 5 */ otmp->otyp == OIL_LAMP || /* 1 - 10 */ otmp->otyp == BRASS_LANTERN || (otmp->otyp >= MAGIC_FLUTE && otmp->otyp <= DRUM_OF_EARTHQUAKE) || /* 5 - 9 */ otmp->oclass == WAND_CLASS) { /* 3 - 11 */ if (otmp->spe > 1) tmp /= 4L; } else if (otmp->oclass == SPBOOK_CLASS) { tmp -= tmp / 5L; } else if (otmp->otyp == CAN_OF_GREASE || otmp->otyp == TINNING_KIT #ifdef TOURIST || otmp->otyp == EXPENSIVE_CAMERA #endif ) { tmp /= 10L; } else if (otmp->otyp == POT_OIL) { tmp /= 5L; } return(tmp); } #endif /*OVL3*/ #ifdef OVLB /* Charge the player for partial use of an unpaid object. * * Note that bill_dummy_object() should be used instead * when an object is completely used. */ void check_unpaid_usage(otmp, altusage) struct obj *otmp; boolean altusage; { struct monst *shkp; const char *fmt, *arg1, *arg2; long tmp; if (!otmp->unpaid || !*u.ushops || (otmp->spe <= 0 && objects[otmp->otyp].oc_charged)) return; if (!(shkp = shop_keeper(*u.ushops)) || !inhishop(shkp)) return; if ((tmp = cost_per_charge(shkp, otmp, altusage)) == 0L) return; arg1 = arg2 = ""; if (otmp->oclass == SPBOOK_CLASS) { fmt = "%sYou owe%s %ld %s."; arg1 = rn2(2) ? "This is no free library, cad! " : ""; arg2 = ESHK(shkp)->debit > 0L ? " an additional" : ""; } else if (otmp->otyp == POT_OIL) { fmt = "%s%sThat will cost you %ld %s (Yendorian Fuel Tax)."; } else { fmt = "%s%sUsage fee, %ld %s."; if (!rn2(3)) arg1 = "Hey! "; if (!rn2(3)) arg2 = "Ahem. "; } if (shkp->mcanmove || !shkp->msleeping) verbalize(fmt, arg1, arg2, tmp, currency(tmp)); ESHK(shkp)->debit += tmp; exercise(A_WIS, TRUE); /* you just got info */ } /* for using charges of unpaid objects "used in the normal manner" */ void check_unpaid(otmp) struct obj *otmp; { check_unpaid_usage(otmp, FALSE); /* normal item use */ } void costly_gold(x, y, amount) register xchar x, y; register long amount; { register long delta; register struct monst *shkp; register struct eshk *eshkp; if(!costly_spot(x, y)) return; /* shkp now guaranteed to exist by costly_spot() */ shkp = shop_keeper(*in_rooms(x, y, SHOPBASE)); eshkp = ESHK(shkp); if(eshkp->credit >= amount) { if(eshkp->credit > amount) Your("credit is reduced by %ld %s.", amount, currency(amount)); else Your("credit is erased."); eshkp->credit -= amount; } else { delta = amount - eshkp->credit; if(eshkp->credit) Your("credit is erased."); if(eshkp->debit) Your("debt increases by %ld %s.", delta, currency(delta)); else You("owe %s %ld %s.", shkname(shkp), delta, currency(delta)); eshkp->debit += delta; eshkp->loan += delta; eshkp->credit = 0L; } } /* used in domove to block diagonal shop-exit */ /* x,y should always be a door */ boolean block_door(x,y) register xchar x, y; { register int roomno = *in_rooms(x, y, SHOPBASE); register struct monst *shkp; if(roomno < 0 || !IS_SHOP(roomno)) return(FALSE); if(!IS_DOOR(levl[x][y].typ)) return(FALSE); if(roomno != *u.ushops) return(FALSE); if(!(shkp = shop_keeper((char)roomno)) || !inhishop(shkp)) return(FALSE); if(shkp->mx == ESHK(shkp)->shk.x && shkp->my == ESHK(shkp)->shk.y /* Actually, the shk should be made to block _any_ * door, including a door the player digs, if the * shk is within a 'jumping' distance. */ && ESHK(shkp)->shd.x == x && ESHK(shkp)->shd.y == y && shkp->mcanmove && !shkp->msleeping && (ESHK(shkp)->debit || ESHK(shkp)->billct || ESHK(shkp)->robbed)) { pline("%s%s blocks your way!", shkname(shkp), Invis ? " senses your motion and" : ""); return(TRUE); } return(FALSE); } /* used in domove to block diagonal shop-entry */ /* u.ux, u.uy should always be a door */ boolean block_entry(x,y) register xchar x, y; { register xchar sx, sy; register int roomno; register struct monst *shkp; if(!(IS_DOOR(levl[u.ux][u.uy].typ) && levl[u.ux][u.uy].doormask == D_BROKEN)) return(FALSE); roomno = *in_rooms(x, y, SHOPBASE); if(roomno < 0 || !IS_SHOP(roomno)) return(FALSE); if(!(shkp = shop_keeper((char)roomno)) || !inhishop(shkp)) return(FALSE); if(ESHK(shkp)->shd.x != u.ux || ESHK(shkp)->shd.y != u.uy) return(FALSE); sx = ESHK(shkp)->shk.x; sy = ESHK(shkp)->shk.y; if(shkp->mx == sx && shkp->my == sy && shkp->mcanmove && !shkp->msleeping && (x == sx-1 || x == sx+1 || y == sy-1 || y == sy+1) && (Invis || carrying(PICK_AXE) || carrying(DWARVISH_MATTOCK) #ifdef STEED || u.usteed #endif )) { pline("%s%s blocks your way!", shkname(shkp), Invis ? " senses your motion and" : ""); return(TRUE); } return(FALSE); } #endif /* OVLB */ #ifdef OVL2 char * shk_your(buf, obj) char *buf; struct obj *obj; { if (!shk_owns(buf, obj) && !mon_owns(buf, obj)) Strcpy(buf, carried(obj) ? "your" : "the"); return buf; } char * Shk_Your(buf, obj) char *buf; struct obj *obj; { (void) shk_your(buf, obj); *buf = highc(*buf); return buf; } STATIC_OVL char * shk_owns(buf, obj) char *buf; struct obj *obj; { struct monst *shkp; xchar x, y; if (get_obj_location(obj, &x, &y, 0) && (obj->unpaid || (obj->where==OBJ_FLOOR && !obj->no_charge && costly_spot(x,y)))) { shkp = shop_keeper(inside_shop(x, y)); return strcpy(buf, shkp ? s_suffix(shkname(shkp)) : "the"); } return (char *)0; } STATIC_OVL char * mon_owns(buf, obj) char *buf; struct obj *obj; { if (obj->where == OBJ_MINVENT) return strcpy(buf, s_suffix(mon_nam(obj->ocarry))); return (char *)0; } #endif /* OVL2 */ #ifdef OVLB #ifdef __SASC void sasc_bug(struct obj *op, unsigned x){ op->unpaid=x; } #endif #endif /* OVLB */ /*shk.c*/ nethack-3.4.3/src/shknam.c0100644000000000000000000004152707764735041014077 0ustar rootroot/* SCCS Id: @(#)shknam.c 3.4 2003/01/09 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* shknam.c -- initialize a shop */ #include "hack.h" #include "eshk.h" #ifndef OVLB extern const struct shclass shtypes[]; #else STATIC_DCL void FDECL(mkshobj_at, (const struct shclass *,int,int)); STATIC_DCL void FDECL(nameshk, (struct monst *,const char * const *)); STATIC_DCL int FDECL(shkinit, (const struct shclass *,struct mkroom *)); static const char * const shkliquors[] = { /* Ukraine */ "Njezjin", "Tsjernigof", "Ossipewsk", "Gorlowka", /* Belarus */ "Gomel", /* N. Russia */ "Konosja", "Weliki Oestjoeg", "Syktywkar", "Sablja", "Narodnaja", "Kyzyl", /* Silezie */ "Walbrzych", "Swidnica", "Klodzko", "Raciborz", "Gliwice", "Brzeg", "Krnov", "Hradec Kralove", /* Schweiz */ "Leuk", "Brig", "Brienz", "Thun", "Sarnen", "Burglen", "Elm", "Flims", "Vals", "Schuls", "Zum Loch", 0 }; static const char * const shkbooks[] = { /* Eire */ "Skibbereen", "Kanturk", "Rath Luirc", "Ennistymon", "Lahinch", "Kinnegad", "Lugnaquillia", "Enniscorthy", "Gweebarra", "Kittamagh", "Nenagh", "Sneem", "Ballingeary", "Kilgarvan", "Cahersiveen", "Glenbeigh", "Kilmihil", "Kiltamagh", "Droichead Atha", "Inniscrone", "Clonegal", "Lisnaskea", "Culdaff", "Dunfanaghy", "Inishbofin", "Kesh", 0 }; static const char * const shkarmors[] = { /* Turquie */ "Demirci", "Kalecik", "Boyabai", "Yildizeli", "Gaziantep", "Siirt", "Akhalataki", "Tirebolu", "Aksaray", "Ermenak", "Iskenderun", "Kadirli", "Siverek", "Pervari", "Malasgirt", "Bayburt", "Ayancik", "Zonguldak", "Balya", "Tefenni", "Artvin", "Kars", "Makharadze", "Malazgirt", "Midyat", "Birecik", "Kirikkale", "Alaca", "Polatli", "Nallihan", 0 }; static const char * const shkwands[] = { /* Wales */ "Yr Wyddgrug", "Trallwng", "Mallwyd", "Pontarfynach", "Rhaeader", "Llandrindod", "Llanfair-ym-muallt", "Y-Fenni", "Maesteg", "Rhydaman", "Beddgelert", "Curig", "Llanrwst", "Llanerchymedd", "Caergybi", /* Scotland */ "Nairn", "Turriff", "Inverurie", "Braemar", "Lochnagar", "Kerloch", "Beinn a Ghlo", "Drumnadrochit", "Morven", "Uist", "Storr", "Sgurr na Ciche", "Cannich", "Gairloch", "Kyleakin", "Dunvegan", 0 }; static const char * const shkrings[] = { /* Hollandse familienamen */ "Feyfer", "Flugi", "Gheel", "Havic", "Haynin", "Hoboken", "Imbyze", "Juyn", "Kinsky", "Massis", "Matray", "Moy", "Olycan", "Sadelin", "Svaving", "Tapper", "Terwen", "Wirix", "Ypey", /* Skandinaviske navne */ "Rastegaisa", "Varjag Njarga", "Kautekeino", "Abisko", "Enontekis", "Rovaniemi", "Avasaksa", "Haparanda", "Lulea", "Gellivare", "Oeloe", "Kajaani", "Fauske", 0 }; static const char * const shkfoods[] = { /* Indonesia */ "Djasinga", "Tjibarusa", "Tjiwidej", "Pengalengan", "Bandjar", "Parbalingga", "Bojolali", "Sarangan", "Ngebel", "Djombang", "Ardjawinangun", "Berbek", "Papar", "Baliga", "Tjisolok", "Siboga", "Banjoewangi", "Trenggalek", "Karangkobar", "Njalindoeng", "Pasawahan", "Pameunpeuk", "Patjitan", "Kediri", "Pemboeang", "Tringanoe", "Makin", "Tipor", "Semai", "Berhala", "Tegal", "Samoe", 0 }; static const char * const shkweapons[] = { /* Perigord */ "Voulgezac", "Rouffiac", "Lerignac", "Touverac", "Guizengeard", "Melac", "Neuvicq", "Vanzac", "Picq", "Urignac", "Corignac", "Fleac", "Lonzac", "Vergt", "Queyssac", "Liorac", "Echourgnac", "Cazelon", "Eypau", "Carignan", "Monbazillac", "Jonzac", "Pons", "Jumilhac", "Fenouilledes", "Laguiolet", "Saujon", "Eymoutiers", "Eygurande", "Eauze", "Labouheyre", 0 }; static const char * const shktools[] = { /* Spmi */ "Ymla", "Eed-morra", "Cubask", "Nieb", "Bnowr Falr", "Telloc Cyaj", "Sperc", "Noskcirdneh", "Yawolloh", "Hyeghu", "Niskal", "Trahnil", "Htargcm", "Enrobwem", "Kachzi Rellim", "Regien", "Donmyar", "Yelpur", "Nosnehpets", "Stewe", "Renrut", "_Zlaw", "Nosalnef", "Rewuorb", "Rellenk", "Yad", "Cire Htims", "Y-crad", "Nenilukah", "Corsh", "Aned", #ifdef OVERLAY "Erreip", "Nehpets", "Mron", "Snivek", "Lapu", "Kahztiy", #endif #ifdef WIN32 "Lechaim", "Lexa", "Niod", #endif #ifdef MAC "Nhoj-lee", "Evad\'kh", "Ettaw-noj", "Tsew-mot", "Ydna-s", "Yao-hang", "Tonbar", "Kivenhoug", #endif #ifdef AMIGA "Falo", "Nosid-da\'r", "Ekim-p", "Rebrol-nek", "Noslo", "Yl-rednow", "Mured-oog", "Ivrajimsal", #endif #ifdef TOS "Nivram", #endif #ifdef VMS "Lez-tneg", "Ytnu-haled", "Niknar", #endif 0 }; static const char * const shklight[] = { /* Romania */ "Zarnesti", "Slanic", "Nehoiasu", "Ludus", "Sighisoara", "Nisipitu", "Razboieni", "Bicaz", "Dorohoi", "Vaslui", "Fetesti", "Tirgu Neamt", "Babadag", "Zimnicea", "Zlatna", "Jiu", "Eforie", "Mamaia", /* Bulgaria */ "Silistra", "Tulovo", "Panagyuritshte", "Smolyan", "Kirklareli", "Pernik", "Lom", "Haskovo", "Dobrinishte", "Varvara", "Oryahovo", "Troyan", "Lovech", "Sliven", 0 }; static const char * const shkgeneral[] = { /* Suriname */ "Hebiwerie", "Possogroenoe", "Asidonhopo", "Manlobbi", "Adjama", "Pakka Pakka", "Kabalebo", "Wonotobo", "Akalapi", "Sipaliwini", /* Greenland */ "Annootok", "Upernavik", "Angmagssalik", /* N. Canada */ "Aklavik", "Inuvik", "Tuktoyaktuk", "Chicoutimi", "Ouiatchouane", "Chibougamau", "Matagami", "Kipawa", "Kinojevis", "Abitibi", "Maganasipi", /* Iceland */ "Akureyri", "Kopasker", "Budereyri", "Akranes", "Bordeyri", "Holmavik", 0 }; /* * To add new shop types, all that is necessary is to edit the shtypes[] array. * See mkroom.h for the structure definition. Typically, you'll have to lower * some or all of the probability fields in old entries to free up some * percentage for the new type. * * The placement type field is not yet used but will be in the near future. * * The iprobs array in each entry defines the probabilities for various kinds * of objects to be present in the given shop type. You can associate with * each percentage either a generic object type (represented by one of the * *_CLASS macros) or a specific object (represented by an onames.h define). * In the latter case, prepend it with a unary minus so the code can know * (by testing the sign) whether to use mkobj() or mksobj(). */ const struct shclass shtypes[] = { {"general store", RANDOM_CLASS, 44, D_SHOP, {{100, RANDOM_CLASS}, {0, 0}, {0, 0}}, shkgeneral}, {"used armor dealership", ARMOR_CLASS, 14, D_SHOP, {{90, ARMOR_CLASS}, {10, WEAPON_CLASS}, {0, 0}}, shkarmors}, {"second-hand bookstore", SCROLL_CLASS, 10, D_SHOP, {{90, SCROLL_CLASS}, {10, SPBOOK_CLASS}, {0, 0}}, shkbooks}, {"liquor emporium", POTION_CLASS, 10, D_SHOP, {{100, POTION_CLASS}, {0, 0}, {0, 0}}, shkliquors}, {"antique weapons outlet", WEAPON_CLASS, 5, D_SHOP, {{90, WEAPON_CLASS}, {10, ARMOR_CLASS}, {0, 0}}, shkweapons}, {"delicatessen", FOOD_CLASS, 5, D_SHOP, {{83, FOOD_CLASS}, {5, -POT_FRUIT_JUICE}, {4, -POT_BOOZE}, {5, -POT_WATER}, {3, -ICE_BOX}}, shkfoods}, {"jewelers", RING_CLASS, 3, D_SHOP, {{85, RING_CLASS}, {10, GEM_CLASS}, {5, AMULET_CLASS}, {0, 0}}, shkrings}, {"quality apparel and accessories", WAND_CLASS, 3, D_SHOP, {{90, WAND_CLASS}, {5, -LEATHER_GLOVES}, {5, -ELVEN_CLOAK}, {0, 0}}, shkwands}, {"hardware store", TOOL_CLASS, 3, D_SHOP, {{100, TOOL_CLASS}, {0, 0}, {0, 0}}, shktools}, /* Actually shktools is ignored; the code specifically chooses a * random implementor name (along with candle shops having * random shopkeepers) */ {"rare books", SPBOOK_CLASS, 3, D_SHOP, {{90, SPBOOK_CLASS}, {10, SCROLL_CLASS}, {0, 0}}, shkbooks}, /* Shops below this point are "unique". That is they must all have a * probability of zero. They are only created via the special level * loader. */ {"lighting store", TOOL_CLASS, 0, D_SHOP, {{32, -WAX_CANDLE}, {50, -TALLOW_CANDLE}, {5, -BRASS_LANTERN}, {10, -OIL_LAMP}, {3, -MAGIC_LAMP}}, shklight}, {(char *)0, 0, 0, 0, {{0, 0}, {0, 0}, {0, 0}}, 0} }; #if 0 /* validate shop probabilities; otherwise incorrect local changes could end up provoking infinite loops or wild subscripts fetching garbage */ void init_shop_selection() { register int i, j, item_prob, shop_prob; for (shop_prob = 0, i = 0; i < SIZE(shtypes); i++) { shop_prob += shtypes[i].prob; for (item_prob = 0, j = 0; j < SIZE(shtypes[0].iprobs); j++) item_prob += shtypes[i].iprobs[j].iprob; if (item_prob != 100) panic("item probabilities total to %d for %s shops!", item_prob, shtypes[i].name); } if (shop_prob != 100) panic("shop probabilities total to %d!", shop_prob); } #endif /*0*/ STATIC_OVL void mkshobj_at(shp, sx, sy) /* make an object of the appropriate type for a shop square */ const struct shclass *shp; int sx, sy; { struct monst *mtmp; int atype; struct permonst *ptr; if (rn2(100) < depth(&u.uz) && !MON_AT(sx, sy) && (ptr = mkclass(S_MIMIC,0)) && (mtmp = makemon(ptr,sx,sy,NO_MM_FLAGS)) != 0) { /* note: makemon will set the mimic symbol to a shop item */ if (rn2(10) >= depth(&u.uz)) { mtmp->m_ap_type = M_AP_OBJECT; mtmp->mappearance = STRANGE_OBJECT; } } else { atype = get_shop_item(shp - shtypes); if (atype < 0) (void) mksobj_at(-atype, sx, sy, TRUE, TRUE); else (void) mkobj_at(atype, sx, sy, TRUE); } } /* extract a shopkeeper name for the given shop type */ STATIC_OVL void nameshk(shk, nlp) struct monst *shk; const char * const *nlp; { int i, trycnt, names_avail; const char *shname = 0; struct monst *mtmp; int name_wanted; s_level *sptr; if (nlp == shklight && In_mines(&u.uz) && (sptr = Is_special(&u.uz)) != 0 && sptr->flags.town) { /* special-case minetown lighting shk */ shname = "Izchak"; shk->female = FALSE; } else { /* We want variation from game to game, without needing the save and restore support which would be necessary for randomization; try not to make too many assumptions about time_t's internals; use ledger_no rather than depth to keep mine town distinct. */ int nseed = (int)((long)u.ubirthday / 257L); name_wanted = ledger_no(&u.uz) + (nseed % 13) - (nseed % 5); if (name_wanted < 0) name_wanted += (13 + 5); shk->female = name_wanted & 1; for (names_avail = 0; nlp[names_avail]; names_avail++) continue; for (trycnt = 0; trycnt < 50; trycnt++) { if (nlp == shktools) { shname = shktools[rn2(names_avail)]; shk->female = (*shname == '_'); if (shk->female) shname++; } else if (name_wanted < names_avail) { shname = nlp[name_wanted]; } else if ((i = rn2(names_avail)) != 0) { shname = nlp[i - 1]; } else if (nlp != shkgeneral) { nlp = shkgeneral; /* try general names */ for (names_avail = 0; nlp[names_avail]; names_avail++) continue; continue; /* next `trycnt' iteration */ } else { shname = shk->female ? "Lucrezia" : "Dirk"; } /* is name already in use on this level? */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp) || (mtmp == shk) || !mtmp->isshk) continue; if (strcmp(ESHK(mtmp)->shknam, shname)) continue; break; } if (!mtmp) break; /* new name */ } } (void) strncpy(ESHK(shk)->shknam, shname, PL_NSIZ); ESHK(shk)->shknam[PL_NSIZ-1] = 0; } STATIC_OVL int shkinit(shp, sroom) /* create a new shopkeeper in the given room */ const struct shclass *shp; struct mkroom *sroom; { register int sh, sx, sy; struct monst *shk; /* place the shopkeeper in the given room */ sh = sroom->fdoor; sx = doors[sh].x; sy = doors[sh].y; /* check that the shopkeeper placement is sane */ if(sroom->irregular) { int rmno = (sroom - rooms) + ROOMOFFSET; if (isok(sx-1,sy) && !levl[sx-1][sy].edge && (int) levl[sx-1][sy].roomno == rmno) sx--; else if (isok(sx+1,sy) && !levl[sx+1][sy].edge && (int) levl[sx+1][sy].roomno == rmno) sx++; else if (isok(sx,sy-1) && !levl[sx][sy-1].edge && (int) levl[sx][sy-1].roomno == rmno) sy--; else if (isok(sx,sy+1) && !levl[sx][sy+1].edge && (int) levl[sx][sy+1].roomno == rmno) sx++; else goto shk_failed; } else if(sx == sroom->lx-1) sx++; else if(sx == sroom->hx+1) sx--; else if(sy == sroom->ly-1) sy++; else if(sy == sroom->hy+1) sy--; else { shk_failed: #ifdef DEBUG # ifdef WIZARD /* Said to happen sometimes, but I have never seen it. */ /* Supposedly fixed by fdoor change in mklev.c */ if(wizard) { register int j = sroom->doorct; pline("Where is shopdoor?"); pline("Room at (%d,%d),(%d,%d).", sroom->lx, sroom->ly, sroom->hx, sroom->hy); pline("doormax=%d doorct=%d fdoor=%d", doorindex, sroom->doorct, sh); while(j--) { pline("door [%d,%d]", doors[sh].x, doors[sh].y); sh++; } display_nhwindow(WIN_MESSAGE, FALSE); } # endif #endif return(-1); } if(MON_AT(sx, sy)) (void) rloc(m_at(sx, sy), FALSE); /* insurance */ /* now initialize the shopkeeper monster structure */ if(!(shk = makemon(&mons[PM_SHOPKEEPER], sx, sy, NO_MM_FLAGS))) return(-1); shk->isshk = shk->mpeaceful = 1; set_malign(shk); shk->msleeping = 0; shk->mtrapseen = ~0; /* we know all the traps already */ ESHK(shk)->shoproom = (sroom - rooms) + ROOMOFFSET; sroom->resident = shk; ESHK(shk)->shoptype = sroom->rtype; assign_level(&(ESHK(shk)->shoplevel), &u.uz); ESHK(shk)->shd = doors[sh]; ESHK(shk)->shk.x = sx; ESHK(shk)->shk.y = sy; ESHK(shk)->robbed = 0L; ESHK(shk)->credit = 0L; ESHK(shk)->debit = 0L; ESHK(shk)->loan = 0L; ESHK(shk)->visitct = 0; ESHK(shk)->following = 0; ESHK(shk)->billct = 0; #ifndef GOLDOBJ shk->mgold = 1000L + 30L*(long)rnd(100); /* initial capital */ #else mkmonmoney(shk, 1000L + 30L*(long)rnd(100)); /* initial capital */ #endif if (shp->shknms == shkrings) (void) mongets(shk, TOUCHSTONE); nameshk(shk, shp->shknms); return(sh); } /* stock a newly-created room with objects */ void stock_room(shp_indx, sroom) int shp_indx; register struct mkroom *sroom; { /* * Someday soon we'll dispatch on the shdist field of shclass to do * different placements in this routine. Currently it only supports * shop-style placement (all squares except a row nearest the first * door get objects). */ register int sx, sy, sh; char buf[BUFSZ]; int rmno = (sroom - rooms) + ROOMOFFSET; const struct shclass *shp = &shtypes[shp_indx]; /* first, try to place a shopkeeper in the room */ if ((sh = shkinit(shp, sroom)) < 0) return; /* make sure no doorways without doors, and no */ /* trapped doors, in shops. */ sx = doors[sroom->fdoor].x; sy = doors[sroom->fdoor].y; if(levl[sx][sy].doormask == D_NODOOR) { levl[sx][sy].doormask = D_ISOPEN; newsym(sx,sy); } if(levl[sx][sy].typ == SDOOR) { cvt_sdoor_to_door(&levl[sx][sy]); /* .typ = DOOR */ newsym(sx,sy); } if(levl[sx][sy].doormask & D_TRAPPED) levl[sx][sy].doormask = D_LOCKED; if(levl[sx][sy].doormask == D_LOCKED) { register int m = sx, n = sy; if(inside_shop(sx+1,sy)) m--; else if(inside_shop(sx-1,sy)) m++; if(inside_shop(sx,sy+1)) n--; else if(inside_shop(sx,sy-1)) n++; Sprintf(buf, "Closed for inventory"); make_engr_at(m, n, buf, 0L, DUST); } for(sx = sroom->lx; sx <= sroom->hx; sx++) for(sy = sroom->ly; sy <= sroom->hy; sy++) { if(sroom->irregular) { if (levl[sx][sy].edge || (int) levl[sx][sy].roomno != rmno || distmin(sx, sy, doors[sh].x, doors[sh].y) <= 1) continue; } else if((sx == sroom->lx && doors[sh].x == sx-1) || (sx == sroom->hx && doors[sh].x == sx+1) || (sy == sroom->ly && doors[sh].y == sy-1) || (sy == sroom->hy && doors[sh].y == sy+1)) continue; mkshobj_at(shp, sx, sy); } /* * Special monster placements (if any) should go here: that way, * monsters will sit on top of objects and not the other way around. */ level.flags.has_shop = TRUE; } #endif /* OVLB */ #ifdef OVL0 /* does shkp's shop stock this item type? */ boolean saleable(shkp, obj) struct monst *shkp; struct obj *obj; { int i, shp_indx = ESHK(shkp)->shoptype - SHOPBASE; const struct shclass *shp = &shtypes[shp_indx]; if (shp->symb == RANDOM_CLASS) return TRUE; else for (i = 0; i < SIZE(shtypes[0].iprobs) && shp->iprobs[i].iprob; i++) if (shp->iprobs[i].itype < 0 ? shp->iprobs[i].itype == - obj->otyp : shp->iprobs[i].itype == obj->oclass) return TRUE; /* not found */ return FALSE; } /* positive value: class; negative value: specific object type */ int get_shop_item(type) int type; { const struct shclass *shp = shtypes+type; register int i,j; /* select an appropriate object type at random */ for(j = rnd(100), i = 0; (j -= shp->iprobs[i].iprob) > 0; i++) continue; return shp->iprobs[i].itype; } #endif /* OVL0 */ /*shknam.c*/ nethack-3.4.3/src/sit.c0100644000000000000000000002562307764735041013414 0ustar rootroot/* SCCS Id: @(#)sit.c 3.4 2002/09/21 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "artifact.h" void take_gold() { #ifndef GOLDOBJ if (u.ugold <= 0) { You_feel("a strange sensation."); } else { You("notice you have no gold!"); u.ugold = 0; flags.botl = 1; } #else struct obj *otmp, *nobj; int lost_money = 0; for (otmp = invent; otmp; otmp = nobj) { nobj = otmp->nobj; if (otmp->oclass == COIN_CLASS) { lost_money = 1; delobj(otmp); } } if (!lost_money) { You_feel("a strange sensation."); } else { You("notice you have no money!"); flags.botl = 1; } #endif } int dosit() { static const char sit_message[] = "sit on the %s."; register struct trap *trap; register int typ = levl[u.ux][u.uy].typ; #ifdef STEED if (u.usteed) { You("are already sitting on %s.", mon_nam(u.usteed)); return (0); } #endif if(!can_reach_floor()) { if (Levitation) You("tumble in place."); else You("are sitting on air."); return 0; } else if (is_pool(u.ux, u.uy) && !Underwater) { /* water walking */ goto in_water; } if(OBJ_AT(u.ux, u.uy)) { register struct obj *obj; obj = level.objects[u.ux][u.uy]; You("sit on %s.", the(xname(obj))); if (!(Is_box(obj) || objects[obj->otyp].oc_material == CLOTH)) pline("It's not very comfortable..."); } else if ((trap = t_at(u.ux, u.uy)) != 0 || (u.utrap && (u.utraptype >= TT_LAVA))) { if (u.utrap) { exercise(A_WIS, FALSE); /* you're getting stuck longer */ if(u.utraptype == TT_BEARTRAP) { You_cant("sit down with your %s in the bear trap.", body_part(FOOT)); u.utrap++; } else if(u.utraptype == TT_PIT) { if(trap->ttyp == SPIKED_PIT) { You("sit down on a spike. Ouch!"); losehp(1, "sitting on an iron spike", KILLED_BY); exercise(A_STR, FALSE); } else You("sit down in the pit."); u.utrap += rn2(5); } else if(u.utraptype == TT_WEB) { You("sit in the spider web and get entangled further!"); u.utrap += rn1(10, 5); } else if(u.utraptype == TT_LAVA) { /* Must have fire resistance or they'd be dead already */ You("sit in the lava!"); u.utrap += rnd(4); losehp(d(2,10), "sitting in lava", KILLED_BY); } else if(u.utraptype == TT_INFLOOR) { You_cant("maneuver to sit!"); u.utrap++; } } else { You("sit down."); dotrap(trap, 0); } } else if(Underwater || Is_waterlevel(&u.uz)) { if (Is_waterlevel(&u.uz)) There("are no cushions floating nearby."); else You("sit down on the muddy bottom."); } else if(is_pool(u.ux, u.uy)) { in_water: You("sit in the water."); if (!rn2(10) && uarm) (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst); if (!rn2(10) && uarmf && uarmf->otyp != WATER_WALKING_BOOTS) (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst); #ifdef SINKS } else if(IS_SINK(typ)) { You(sit_message, defsyms[S_sink].explanation); Your("%s gets wet.", humanoid(youmonst.data) ? "rump" : "underside"); #endif } else if(IS_ALTAR(typ)) { You(sit_message, defsyms[S_altar].explanation); altar_wrath(u.ux, u.uy); } else if(IS_GRAVE(typ)) { You(sit_message, defsyms[S_grave].explanation); } else if(typ == STAIRS) { You(sit_message, "stairs"); } else if(typ == LADDER) { You(sit_message, "ladder"); } else if (is_lava(u.ux, u.uy)) { /* must be WWalking */ You(sit_message, "lava"); burn_away_slime(); if (likes_lava(youmonst.data)) { pline_The("lava feels warm."); return 1; } pline_The("lava burns you!"); losehp(d((Fire_resistance ? 2 : 10), 10), "sitting on lava", KILLED_BY); } else if (is_ice(u.ux, u.uy)) { You(sit_message, defsyms[S_ice].explanation); if (!Cold_resistance) pline_The("ice feels cold."); } else if (typ == DRAWBRIDGE_DOWN) { You(sit_message, "drawbridge"); } else if(IS_THRONE(typ)) { You(sit_message, defsyms[S_throne].explanation); if (rnd(6) > 4) { switch (rnd(13)) { case 1: (void) adjattrib(rn2(A_MAX), -rn1(4,3), FALSE); losehp(rnd(10), "cursed throne", KILLED_BY_AN); break; case 2: (void) adjattrib(rn2(A_MAX), 1, FALSE); break; case 3: pline("A%s electric shock shoots through your body!", (Shock_resistance) ? "n" : " massive"); losehp(Shock_resistance ? rnd(6) : rnd(30), "electric chair", KILLED_BY_AN); exercise(A_CON, FALSE); break; case 4: You_feel("much, much better!"); if (Upolyd) { if (u.mh >= (u.mhmax - 5)) u.mhmax += 4; u.mh = u.mhmax; } if(u.uhp >= (u.uhpmax - 5)) u.uhpmax += 4; u.uhp = u.uhpmax; make_blinded(0L,TRUE); make_sick(0L, (char *) 0, FALSE, SICK_ALL); heal_legs(); flags.botl = 1; break; case 5: take_gold(); break; case 6: if(u.uluck + rn2(5) < 0) { You_feel("your luck is changing."); change_luck(1); } else makewish(); break; case 7: { register int cnt = rnd(10); pline("A voice echoes:"); verbalize("Thy audience hath been summoned, %s!", flags.female ? "Dame" : "Sire"); while(cnt--) (void) makemon(courtmon(), u.ux, u.uy, NO_MM_FLAGS); break; } case 8: pline("A voice echoes:"); verbalize("By thy Imperious order, %s...", flags.female ? "Dame" : "Sire"); do_genocide(5); /* REALLY|ONTHRONE, see do_genocide() */ break; case 9: pline("A voice echoes:"); verbalize("A curse upon thee for sitting upon this most holy throne!"); if (Luck > 0) { make_blinded(Blinded + rn1(100,250),TRUE); } else rndcurse(); break; case 10: if (Luck < 0 || (HSee_invisible & INTRINSIC)) { if (level.flags.nommap) { pline( "A terrible drone fills your head!"); make_confused(HConfusion + rnd(30), FALSE); } else { pline("An image forms in your mind."); do_mapping(); } } else { Your("vision becomes clear."); HSee_invisible |= FROMOUTSIDE; newsym(u.ux, u.uy); } break; case 11: if (Luck < 0) { You_feel("threatened."); aggravate(); } else { You_feel("a wrenching sensation."); tele(); /* teleport him */ } break; case 12: You("are granted an insight!"); if (invent) { /* rn2(5) agrees w/seffects() */ identify_pack(rn2(5)); } break; case 13: Your("mind turns into a pretzel!"); make_confused(HConfusion + rn1(7,16),FALSE); break; default: impossible("throne effect"); break; } } else { if (is_prince(youmonst.data)) You_feel("very comfortable here."); else You_feel("somehow out of place..."); } if (!rn2(3) && IS_THRONE(levl[u.ux][u.uy].typ)) { /* may have teleported */ levl[u.ux][u.uy].typ = ROOM; pline_The("throne vanishes in a puff of logic."); newsym(u.ux,u.uy); } } else if (lays_eggs(youmonst.data)) { struct obj *uegg; if (!flags.female) { pline("Males can't lay eggs!"); return 0; } if (u.uhunger < (int)objects[EGG].oc_nutrition) { You("don't have enough energy to lay an egg."); return 0; } uegg = mksobj(EGG, FALSE, FALSE); uegg->spe = 1; uegg->quan = 1; uegg->owt = weight(uegg); uegg->corpsenm = egg_type_from_parent(u.umonnum, FALSE); uegg->known = uegg->dknown = 1; attach_egg_hatch_timeout(uegg); You("lay an egg."); dropy(uegg); stackobj(uegg); morehungry((int)objects[EGG].oc_nutrition); } else if (u.uswallow) There("are no seats in here!"); else pline("Having fun sitting on the %s?", surface(u.ux,u.uy)); return(1); } void rndcurse() /* curse a few inventory items at random! */ { int nobj = 0; int cnt, onum; struct obj *otmp; static const char mal_aura[] = "feel a malignant aura surround %s."; if (uwep && (uwep->oartifact == ART_MAGICBANE) && rn2(20)) { You(mal_aura, "the magic-absorbing blade"); return; } if(Antimagic) { shieldeff(u.ux, u.uy); You(mal_aura, "you"); } for (otmp = invent; otmp; otmp = otmp->nobj) { #ifdef GOLDOBJ /* gold isn't subject to being cursed or blessed */ if (otmp->oclass == COIN_CLASS) continue; #endif nobj++; } if (nobj) { for (cnt = rnd(6/((!!Antimagic) + (!!Half_spell_damage) + 1)); cnt > 0; cnt--) { onum = rnd(nobj); for (otmp = invent; otmp; otmp = otmp->nobj) { #ifdef GOLDOBJ /* as above */ if (otmp->oclass == COIN_CLASS) continue; #endif if (--onum == 0) break; /* found the target */ } /* the !otmp case should never happen; picking an already cursed item happens--avoid "resists" message in that case */ if (!otmp || otmp->cursed) continue; /* next target */ if(otmp->oartifact && spec_ability(otmp, SPFX_INTEL) && rn2(10) < 8) { pline("%s!", Tobjnam(otmp, "resist")); continue; } if(otmp->blessed) unbless(otmp); else curse(otmp); } update_inventory(); } #ifdef STEED /* treat steed's saddle as extended part of hero's inventory */ if (u.usteed && !rn2(4) && (otmp = which_armor(u.usteed, W_SADDLE)) != 0 && !otmp->cursed) { /* skip if already cursed */ if (otmp->blessed) unbless(otmp); else curse(otmp); if (!Blind) { pline("%s %s %s.", s_suffix(upstart(y_monnam(u.usteed))), aobjnam(otmp, "glow"), hcolor(otmp->cursed ? NH_BLACK : (const char *)"brown")); otmp->bknown = TRUE; } } #endif /*STEED*/ } void attrcurse() /* remove a random INTRINSIC ability */ { switch(rnd(11)) { case 1 : if (HFire_resistance & INTRINSIC) { HFire_resistance &= ~INTRINSIC; You_feel("warmer."); break; } case 2 : if (HTeleportation & INTRINSIC) { HTeleportation &= ~INTRINSIC; You_feel("less jumpy."); break; } case 3 : if (HPoison_resistance & INTRINSIC) { HPoison_resistance &= ~INTRINSIC; You_feel("a little sick!"); break; } case 4 : if (HTelepat & INTRINSIC) { HTelepat &= ~INTRINSIC; if (Blind && !Blind_telepat) see_monsters(); /* Can't sense mons anymore! */ Your("senses fail!"); break; } case 5 : if (HCold_resistance & INTRINSIC) { HCold_resistance &= ~INTRINSIC; You_feel("cooler."); break; } case 6 : if (HInvis & INTRINSIC) { HInvis &= ~INTRINSIC; You_feel("paranoid."); break; } case 7 : if (HSee_invisible & INTRINSIC) { HSee_invisible &= ~INTRINSIC; You("%s!", Hallucination ? "tawt you taw a puttie tat" : "thought you saw something"); break; } case 8 : if (HFast & INTRINSIC) { HFast &= ~INTRINSIC; You_feel("slower."); break; } case 9 : if (HStealth & INTRINSIC) { HStealth &= ~INTRINSIC; You_feel("clumsy."); break; } case 10: if (HProtection & INTRINSIC) { HProtection &= ~INTRINSIC; You_feel("vulnerable."); break; } case 11: if (HAggravate_monster & INTRINSIC) { HAggravate_monster &= ~INTRINSIC; You_feel("less attractive."); break; } default: break; } } /*sit.c*/ nethack-3.4.3/src/sounds.c0100644000000000000000000006432707764735041014134 0ustar rootroot/* SCCS Id: @(#)sounds.c 3.4 2002/05/06 */ /* Copyright (c) 1989 Janet Walz, Mike Threepoint */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "edog.h" #ifdef USER_SOUNDS # ifdef USER_SOUNDS_REGEX #include # endif #endif #ifdef OVLB static int FDECL(domonnoise,(struct monst *)); static int NDECL(dochat); #endif /* OVLB */ #ifdef OVL0 static int FDECL(mon_in_room, (struct monst *,int)); /* this easily could be a macro, but it might overtax dumb compilers */ static int mon_in_room(mon, rmtyp) struct monst *mon; int rmtyp; { int rno = levl[mon->mx][mon->my].roomno; return rooms[rno - ROOMOFFSET].rtype == rmtyp; } void dosounds() { register struct mkroom *sroom; register int hallu, vx, vy; #if defined(AMIGA) && defined(AZTEC_C_WORKAROUND) int xx; #endif struct monst *mtmp; if (!flags.soundok || u.uswallow || Underwater) return; hallu = Hallucination ? 1 : 0; if (level.flags.nfountains && !rn2(400)) { static const char * const fountain_msg[4] = { "bubbling water.", "water falling on coins.", "the splashing of a naiad.", "a soda fountain!", }; You_hear(fountain_msg[rn2(3)+hallu]); } #ifdef SINK if (level.flags.nsinks && !rn2(300)) { static const char * const sink_msg[3] = { "a slow drip.", "a gurgling noise.", "dishes being washed!", }; You_hear(sink_msg[rn2(2)+hallu]); } #endif if (level.flags.has_court && !rn2(200)) { static const char * const throne_msg[4] = { "the tones of courtly conversation.", "a sceptre pounded in judgment.", "Someone shouts \"Off with %s head!\"", "Queen Beruthiel's cats!", }; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->msleeping || is_lord(mtmp->data) || is_prince(mtmp->data)) && !is_animal(mtmp->data) && mon_in_room(mtmp, COURT)) { /* finding one is enough, at least for now */ int which = rn2(3)+hallu; if (which != 2) You_hear(throne_msg[which]); else pline(throne_msg[2], uhis()); return; } } } if (level.flags.has_swamp && !rn2(200)) { static const char * const swamp_msg[3] = { "hear mosquitoes!", "smell marsh gas!", /* so it's a smell...*/ "hear Donald Duck!", }; You(swamp_msg[rn2(2)+hallu]); return; } if (level.flags.has_vault && !rn2(200)) { if (!(sroom = search_special(VAULT))) { /* strange ... */ level.flags.has_vault = 0; return; } if(gd_sound()) switch (rn2(2)+hallu) { case 1: { boolean gold_in_vault = FALSE; for (vx = sroom->lx;vx <= sroom->hx; vx++) for (vy = sroom->ly; vy <= sroom->hy; vy++) if (g_at(vx, vy)) gold_in_vault = TRUE; #if defined(AMIGA) && defined(AZTEC_C_WORKAROUND) /* Bug in aztec assembler here. Workaround below */ xx = ROOM_INDEX(sroom) + ROOMOFFSET; xx = (xx != vault_occupied(u.urooms)); if(xx) #else if (vault_occupied(u.urooms) != (ROOM_INDEX(sroom) + ROOMOFFSET)) #endif /* AZTEC_C_WORKAROUND */ { if (gold_in_vault) You_hear(!hallu ? "someone counting money." : "the quarterback calling the play."); else You_hear("someone searching."); break; } /* fall into... (yes, even for hallucination) */ } case 0: You_hear("the footsteps of a guard on patrol."); break; case 2: You_hear("Ebenezer Scrooge!"); break; } return; } if (level.flags.has_beehive && !rn2(200)) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->data->mlet == S_ANT && is_flyer(mtmp->data)) && mon_in_room(mtmp, BEEHIVE)) { switch (rn2(2)+hallu) { case 0: You_hear("a low buzzing."); break; case 1: You_hear("an angry drone."); break; case 2: You_hear("bees in your %sbonnet!", uarmh ? "" : "(nonexistent) "); break; } return; } } } if (level.flags.has_morgue && !rn2(200)) { for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_undead(mtmp->data) && mon_in_room(mtmp, MORGUE)) { switch (rn2(2)+hallu) { case 0: You("suddenly realize it is unnaturally quiet."); break; case 1: pline_The("%s on the back of your %s stands up.", body_part(HAIR), body_part(NECK)); break; case 2: pline_The("%s on your %s seems to stand up.", body_part(HAIR), body_part(HEAD)); break; } return; } } } if (level.flags.has_barracks && !rn2(200)) { static const char * const barracks_msg[4] = { "blades being honed.", "loud snoring.", "dice being thrown.", "General MacArthur!", }; int count = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if (is_mercenary(mtmp->data) && #if 0 /* don't bother excluding these */ !strstri(mtmp->data->mname, "watch") && !strstri(mtmp->data->mname, "guard") && #endif mon_in_room(mtmp, BARRACKS) && /* sleeping implies not-yet-disturbed (usually) */ (mtmp->msleeping || ++count > 5)) { You_hear(barracks_msg[rn2(3)+hallu]); return; } } } if (level.flags.has_zoo && !rn2(200)) { static const char * const zoo_msg[3] = { "a sound reminiscent of an elephant stepping on a peanut.", "a sound reminiscent of a seal barking.", "Doctor Doolittle!", }; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; if ((mtmp->msleeping || is_animal(mtmp->data)) && mon_in_room(mtmp, ZOO)) { You_hear(zoo_msg[rn2(2)+hallu]); return; } } } if (level.flags.has_shop && !rn2(200)) { if (!(sroom = search_special(ANY_SHOP))) { /* strange... */ level.flags.has_shop = 0; return; } if (tended_shop(sroom) && !index(u.ushops, ROOM_INDEX(sroom) + ROOMOFFSET)) { static const char * const shop_msg[3] = { "someone cursing shoplifters.", "the chime of a cash register.", "Neiman and Marcus arguing!", }; You_hear(shop_msg[rn2(2)+hallu]); } return; } if (Is_oracle_level(&u.uz) && !rn2(400)) { /* make sure the Oracle is still here */ for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp) && mtmp->data == &mons[PM_ORACLE]) break; /* and don't produce silly effects when she's clearly visible */ if (mtmp && (hallu || !canseemon(mtmp))) { static const char * const ora_msg[5] = { "a strange wind.", /* Jupiter at Dodona */ "convulsive ravings.", /* Apollo at Delphi */ "snoring snakes.", /* AEsculapius at Epidaurus */ "someone say \"No more woodchucks!\"", "a loud ZOT!" /* both rec.humor.oracle */ }; You_hear(ora_msg[rn2(3)+hallu*2]); } return; } } #endif /* OVL0 */ #ifdef OVLB static const char * const h_sounds[] = { "beep", "boing", "sing", "belche", "creak", "cough", "rattle", "ululate", "pop", "jingle", "sniffle", "tinkle", "eep" }; const char * growl_sound(mtmp) register struct monst *mtmp; { const char *ret; switch (mtmp->data->msound) { case MS_MEW: case MS_HISS: ret = "hiss"; break; case MS_BARK: case MS_GROWL: ret = "growl"; break; case MS_ROAR: ret = "roar"; break; case MS_BUZZ: ret = "buzz"; break; case MS_SQEEK: ret = "squeal"; break; case MS_SQAWK: ret = "screech"; break; case MS_NEIGH: ret = "neigh"; break; case MS_WAIL: ret = "wail"; break; case MS_SILENT: ret = "commotion"; break; default: ret = "scream"; } return ret; } /* the sounds of a seriously abused pet, including player attacking it */ void growl(mtmp) register struct monst *mtmp; { register const char *growl_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) return; /* presumably nearness and soundok checks have already been made */ if (Hallucination) growl_verb = h_sounds[rn2(SIZE(h_sounds))]; else growl_verb = growl_sound(mtmp); if (growl_verb) { pline("%s %s!", Monnam(mtmp), vtense((char *)0, growl_verb)); if(flags.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 18); } } /* the sounds of mistreated pets */ void yelp(mtmp) register struct monst *mtmp; { register const char *yelp_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) return; /* presumably nearness and soundok checks have already been made */ if (Hallucination) yelp_verb = h_sounds[rn2(SIZE(h_sounds))]; else switch (mtmp->data->msound) { case MS_MEW: yelp_verb = "yowl"; break; case MS_BARK: case MS_GROWL: yelp_verb = "yelp"; break; case MS_ROAR: yelp_verb = "snarl"; break; case MS_SQEEK: yelp_verb = "squeal"; break; case MS_SQAWK: yelp_verb = "screak"; break; case MS_WAIL: yelp_verb = "wail"; break; } if (yelp_verb) { pline("%s %s!", Monnam(mtmp), vtense((char *)0, yelp_verb)); if(flags.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 12); } } /* the sounds of distressed pets */ void whimper(mtmp) register struct monst *mtmp; { register const char *whimper_verb = 0; if (mtmp->msleeping || !mtmp->mcanmove || !mtmp->data->msound) return; /* presumably nearness and soundok checks have already been made */ if (Hallucination) whimper_verb = h_sounds[rn2(SIZE(h_sounds))]; else switch (mtmp->data->msound) { case MS_MEW: case MS_GROWL: whimper_verb = "whimper"; break; case MS_BARK: whimper_verb = "whine"; break; case MS_SQEEK: whimper_verb = "squeal"; break; } if (whimper_verb) { pline("%s %s.", Monnam(mtmp), vtense((char *)0, whimper_verb)); if(flags.run) nomul(0); wake_nearto(mtmp->mx, mtmp->my, mtmp->data->mlevel * 6); } } /* pet makes "I'm hungry" noises */ void beg(mtmp) register struct monst *mtmp; { if (mtmp->msleeping || !mtmp->mcanmove || !(carnivorous(mtmp->data) || herbivorous(mtmp->data))) return; /* presumably nearness and soundok checks have already been made */ if (!is_silent(mtmp->data) && mtmp->data->msound <= MS_ANIMAL) (void) domonnoise(mtmp); else if (mtmp->data->msound >= MS_HUMANOID) { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); verbalize("I'm hungry."); } } static int domonnoise(mtmp) register struct monst *mtmp; { register const char *pline_msg = 0, /* Monnam(mtmp) will be prepended */ *verbl_msg = 0; /* verbalize() */ struct permonst *ptr = mtmp->data; char verbuf[BUFSZ]; /* presumably nearness and sleep checks have already been made */ if (!flags.soundok) return(0); if (is_silent(ptr)) return(0); /* Make sure its your role's quest quardian; adjust if not */ if (ptr->msound == MS_GUARDIAN && ptr != &mons[urole.guardnum]) { int mndx = monsndx(ptr); ptr = &mons[genus(mndx,1)]; } /* be sure to do this before talking; the monster might teleport away, in * which case we want to check its pre-teleport position */ if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); switch (ptr->msound) { case MS_ORACLE: return doconsult(mtmp); case MS_PRIEST: priest_talk(mtmp); break; case MS_LEADER: case MS_NEMESIS: case MS_GUARDIAN: quest_chat(mtmp); break; case MS_SELL: /* pitch, pay, total */ shk_chat(mtmp); break; case MS_VAMPIRE: { /* vampire messages are varied by tameness, peacefulness, and time of night */ boolean isnight = night(); boolean kindred = (Upolyd && (u.umonnum == PM_VAMPIRE || u.umonnum == PM_VAMPIRE_LORD)); boolean nightchild = (Upolyd && (u.umonnum == PM_WOLF || u.umonnum == PM_WINTER_WOLF || u.umonnum == PM_WINTER_WOLF_CUB)); const char *racenoun = (flags.female && urace.individual.f) ? urace.individual.f : (urace.individual.m) ? urace.individual.m : urace.noun; if (mtmp->mtame) { if (kindred) { Sprintf(verbuf, "Good %s to you Master%s", isnight ? "evening" : "day", isnight ? "!" : ". Why do we not rest?"); verbl_msg = verbuf; } else { Sprintf(verbuf,"%s%s", nightchild ? "Child of the night, " : "", midnight() ? "I can stand this craving no longer!" : isnight ? "I beg you, help me satisfy this growing craving!" : "I find myself growing a little weary."); verbl_msg = verbuf; } } else if (mtmp->mpeaceful) { if (kindred && isnight) { Sprintf(verbuf, "Good feeding %s!", flags.female ? "sister" : "brother"); verbl_msg = verbuf; } else if (nightchild && isnight) { Sprintf(verbuf, "How nice to hear you, child of the night!"); verbl_msg = verbuf; } else verbl_msg = "I only drink... potions."; } else { int vampindex; static const char * const vampmsg[] = { /* These first two (0 and 1) are specially handled below */ "I vant to suck your %s!", "I vill come after %s without regret!", /* other famous vampire quotes can follow here if desired */ }; if (kindred) verbl_msg = "This is my hunting ground that you dare to prowl!"; else if (youmonst.data == &mons[PM_SILVER_DRAGON] || youmonst.data == &mons[PM_BABY_SILVER_DRAGON]) { /* Silver dragons are silver in color, not made of silver */ Sprintf(verbuf, "%s! Your silver sheen does not frighten me!", youmonst.data == &mons[PM_SILVER_DRAGON] ? "Fool" : "Young Fool"); verbl_msg = verbuf; } else { vampindex = rn2(SIZE(vampmsg)); if (vampindex == 0) { Sprintf(verbuf, vampmsg[vampindex], body_part(BLOOD)); verbl_msg = verbuf; } else if (vampindex == 1) { Sprintf(verbuf, vampmsg[vampindex], Upolyd ? an(mons[u.umonnum].mname) : an(racenoun)); verbl_msg = verbuf; } else verbl_msg = vampmsg[vampindex]; } } } break; case MS_WERE: if (flags.moonphase == FULL_MOON && (night() ^ !rn2(13))) { pline("%s throws back %s head and lets out a blood curdling %s!", Monnam(mtmp), mhis(mtmp), ptr == &mons[PM_HUMAN_WERERAT] ? "shriek" : "howl"); wake_nearto(mtmp->mx, mtmp->my, 11*11); } else pline_msg = "whispers inaudibly. All you can make out is \"moon\"."; break; case MS_BARK: if (flags.moonphase == FULL_MOON && night()) { pline_msg = "howls."; } else if (mtmp->mpeaceful) { if (mtmp->mtame && (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || moves > EDOG(mtmp)->hungrytime || mtmp->mtame < 5)) pline_msg = "whines."; else if (mtmp->mtame && EDOG(mtmp)->hungrytime > moves + 1000) pline_msg = "yips."; else { if (mtmp->data != &mons[PM_DINGO]) /* dingos do not actually bark */ pline_msg = "barks."; } } else { pline_msg = "growls."; } break; case MS_MEW: if (mtmp->mtame) { if (mtmp->mconf || mtmp->mflee || mtmp->mtrapped || mtmp->mtame < 5) pline_msg = "yowls."; else if (moves > EDOG(mtmp)->hungrytime) pline_msg = "meows."; else if (EDOG(mtmp)->hungrytime > moves + 1000) pline_msg = "purrs."; else pline_msg = "mews."; break; } /* else FALLTHRU */ case MS_GROWL: pline_msg = mtmp->mpeaceful ? "snarls." : "growls!"; break; case MS_ROAR: pline_msg = mtmp->mpeaceful ? "snarls." : "roars!"; break; case MS_SQEEK: pline_msg = "squeaks."; break; case MS_SQAWK: if (ptr == &mons[PM_RAVEN] && !mtmp->mpeaceful) verbl_msg = "Nevermore!"; else pline_msg = "squawks."; break; case MS_HISS: if (!mtmp->mpeaceful) pline_msg = "hisses!"; else return 0; /* no sound */ break; case MS_BUZZ: pline_msg = mtmp->mpeaceful ? "drones." : "buzzes angrily."; break; case MS_GRUNT: pline_msg = "grunts."; break; case MS_NEIGH: if (mtmp->mtame < 5) pline_msg = "neighs."; else if (moves > EDOG(mtmp)->hungrytime) pline_msg = "whinnies."; else pline_msg = "whickers."; break; case MS_WAIL: pline_msg = "wails mournfully."; break; case MS_GURGLE: pline_msg = "gurgles."; break; case MS_BURBLE: pline_msg = "burbles."; break; case MS_SHRIEK: pline_msg = "shrieks."; aggravate(); break; case MS_IMITATE: pline_msg = "imitates you."; break; case MS_BONES: pline("%s rattles noisily.", Monnam(mtmp)); You("freeze for a moment."); nomul(-2); break; case MS_LAUGH: { static const char * const laugh_msg[4] = { "giggles.", "chuckles.", "snickers.", "laughs.", }; pline_msg = laugh_msg[rn2(4)]; } break; case MS_MUMBLE: pline_msg = "mumbles incomprehensibly."; break; case MS_DJINNI: if (mtmp->mtame) { verbl_msg = "Sorry, I'm all out of wishes."; } else if (mtmp->mpeaceful) { if (ptr == &mons[PM_WATER_DEMON]) pline_msg = "gurgles."; else verbl_msg = "I'm free!"; } else verbl_msg = "This will teach you not to disturb me!"; break; case MS_BOAST: /* giants */ if (!mtmp->mpeaceful) { switch (rn2(4)) { case 0: pline("%s boasts about %s gem collection.", Monnam(mtmp), mhis(mtmp)); break; case 1: pline_msg = "complains about a diet of mutton."; break; default: pline_msg = "shouts \"Fee Fie Foe Foo!\" and guffaws."; wake_nearto(mtmp->mx, mtmp->my, 7*7); break; } break; } /* else FALLTHRU */ case MS_HUMANOID: if (!mtmp->mpeaceful) { if (In_endgame(&u.uz) && is_mplayer(ptr)) { mplayer_talk(mtmp); break; } else return 0; /* no sound */ } /* Generic peaceful humanoid behaviour. */ if (mtmp->mflee) pline_msg = "wants nothing to do with you."; else if (mtmp->mhp < mtmp->mhpmax/4) pline_msg = "moans."; else if (mtmp->mconf || mtmp->mstun) verbl_msg = !rn2(3) ? "Huh?" : rn2(2) ? "What?" : "Eh?"; else if (!mtmp->mcansee) verbl_msg = "I can't see!"; else if (mtmp->mtrapped) { struct trap *t = t_at(mtmp->mx, mtmp->my); if (t) t->tseen = 1; verbl_msg = "I'm trapped!"; } else if (mtmp->mhp < mtmp->mhpmax/2) pline_msg = "asks for a potion of healing."; else if (mtmp->mtame && !mtmp->isminion && moves > EDOG(mtmp)->hungrytime) verbl_msg = "I'm hungry."; /* Specific monsters' interests */ else if (is_elf(ptr)) pline_msg = "curses orcs."; else if (is_dwarf(ptr)) pline_msg = "talks about mining."; else if (likes_magic(ptr)) pline_msg = "talks about spellcraft."; else if (ptr->mlet == S_CENTAUR) pline_msg = "discusses hunting."; else switch (monsndx(ptr)) { case PM_HOBBIT: pline_msg = (mtmp->mhpmax - mtmp->mhp >= 10) ? "complains about unpleasant dungeon conditions." : "asks you about the One Ring."; break; case PM_ARCHEOLOGIST: pline_msg = "describes a recent article in \"Spelunker Today\" magazine."; break; #ifdef TOURIST case PM_TOURIST: verbl_msg = "Aloha."; break; #endif default: pline_msg = "discusses dungeon exploration."; break; } break; case MS_SEDUCE: #ifdef SEDUCE if (ptr->mlet != S_NYMPH && could_seduce(mtmp, &youmonst, (struct attack *)0) == 1) { (void) doseduce(mtmp); break; } switch ((poly_gender() != (int) mtmp->female) ? rn2(3) : 0) #else switch ((poly_gender() == 0) ? rn2(3) : 0) #endif { case 2: verbl_msg = "Hello, sailor."; break; case 1: pline_msg = "comes on to you."; break; default: pline_msg = "cajoles you."; } break; #ifdef KOPS case MS_ARREST: if (mtmp->mpeaceful) verbalize("Just the facts, %s.", flags.female ? "Ma'am" : "Sir"); else { static const char * const arrest_msg[3] = { "Anything you say can be used against you.", "You're under arrest!", "Stop in the name of the Law!", }; verbl_msg = arrest_msg[rn2(3)]; } break; #endif case MS_BRIBE: if (mtmp->mpeaceful && !mtmp->mtame) { (void) demon_talk(mtmp); break; } /* fall through */ case MS_CUSS: if (!mtmp->mpeaceful) cuss(mtmp); break; case MS_SPELL: /* deliberately vague, since it's not actually casting any spell */ pline_msg = "seems to mutter a cantrip."; break; case MS_NURSE: if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) verbl_msg = "Put that weapon away before you hurt someone!"; else if (uarmc || uarm || uarmh || uarms || uarmg || uarmf) verbl_msg = Role_if(PM_HEALER) ? "Doc, I can't help you unless you cooperate." : "Please undress so I can examine you."; #ifdef TOURIST else if (uarmu) verbl_msg = "Take off your shirt, please."; #endif else verbl_msg = "Relax, this won't hurt a bit."; break; case MS_GUARD: #ifndef GOLDOBJ if (u.ugold) #else if (money_cnt(invent)) #endif verbl_msg = "Please drop that gold and follow me."; else verbl_msg = "Please follow me."; break; case MS_SOLDIER: { static const char * const soldier_foe_msg[3] = { "Resistance is useless!", "You're dog meat!", "Surrender!", }, * const soldier_pax_msg[3] = { "What lousy pay we're getting here!", "The food's not fit for Orcs!", "My feet hurt, I've been on them all day!", }; verbl_msg = mtmp->mpeaceful ? soldier_pax_msg[rn2(3)] : soldier_foe_msg[rn2(3)]; } break; case MS_RIDER: if (ptr == &mons[PM_DEATH] && !rn2(10)) pline_msg = "is busy reading a copy of Sandman #8."; else verbl_msg = "Who do you think you are, War?"; break; } if (pline_msg) pline("%s %s", Monnam(mtmp), pline_msg); else if (verbl_msg) verbalize(verbl_msg); return(1); } int dotalk() { int result; boolean save_soundok = flags.soundok; flags.soundok = 1; /* always allow sounds while chatting */ result = dochat(); flags.soundok = save_soundok; return result; } static int dochat() { register struct monst *mtmp; register int tx,ty; struct obj *otmp; if (is_silent(youmonst.data)) { pline("As %s, you cannot speak.", an(youmonst.data->mname)); return(0); } if (Strangled) { You_cant("speak. You're choking!"); return(0); } if (u.uswallow) { pline("They won't hear you out there."); return(0); } if (Underwater) { Your("speech is unintelligible underwater."); return(0); } if (!Blind && (otmp = shop_object(u.ux, u.uy)) != (struct obj *)0) { /* standing on something in a shop and chatting causes the shopkeeper to describe the price(s). This can inhibit other chatting inside a shop, but that shouldn't matter much. shop_object() returns an object iff inside a shop and the shopkeeper is present and willing (not angry) and able (not asleep) to speak and the position contains any objects other than just gold. */ price_quote(otmp); return(1); } if (!getdir("Talk to whom? (in what direction)")) { /* decided not to chat */ return(0); } #ifdef STEED if (u.usteed && u.dz > 0) return (domonnoise(u.usteed)); #endif if (u.dz) { pline("They won't hear you %s there.", u.dz < 0 ? "up" : "down"); return(0); } if (u.dx == 0 && u.dy == 0) { /* * Let's not include this. It raises all sorts of questions: can you wear * 2 helmets, 2 amulets, 3 pairs of gloves or 6 rings as a marilith, * etc... --KAA if (u.umonnum == PM_ETTIN) { You("discover that your other head makes boring conversation."); return(1); } */ pline("Talking to yourself is a bad habit for a dungeoneer."); return(0); } tx = u.ux+u.dx; ty = u.uy+u.dy; mtmp = m_at(tx, ty); if (!mtmp || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT) return(0); /* sleeping monsters won't talk, except priests (who wake up) */ if ((!mtmp->mcanmove || mtmp->msleeping) && !mtmp->ispriest) { /* If it is unseen, the player can't tell the difference between not noticing him and just not existing, so skip the message. */ if (canspotmon(mtmp)) pline("%s seems not to notice you.", Monnam(mtmp)); return(0); } /* if this monster is waiting for something, prod it into action */ mtmp->mstrategy &= ~STRAT_WAITMASK; if (mtmp->mtame && mtmp->meating) { if (!canspotmon(mtmp)) map_invisible(mtmp->mx, mtmp->my); pline("%s is eating noisily.", Monnam(mtmp)); return (0); } return domonnoise(mtmp); } #ifdef USER_SOUNDS extern void FDECL(play_usersound, (const char*, int)); typedef struct audio_mapping_rec { #ifdef USER_SOUNDS_REGEX struct re_pattern_buffer regex; #else char *pattern; #endif char *filename; int volume; struct audio_mapping_rec *next; } audio_mapping; static audio_mapping *soundmap = 0; char* sounddir = "."; /* adds a sound file mapping, returns 0 on failure, 1 on success */ int add_sound_mapping(mapping) const char *mapping; { char text[256]; char filename[256]; char filespec[256]; int volume; if (sscanf(mapping, "MESG \"%255[^\"]\"%*[\t ]\"%255[^\"]\" %d", text, filename, &volume) == 3) { const char *err; audio_mapping *new_map; if (strlen(sounddir) + strlen(filename) > 254) { raw_print("sound file name too long"); return 0; } Sprintf(filespec, "%s/%s", sounddir, filename); if (can_read_file(filespec)) { new_map = (audio_mapping *)alloc(sizeof(audio_mapping)); #ifdef USER_SOUNDS_REGEX new_map->regex.translate = 0; new_map->regex.fastmap = 0; new_map->regex.buffer = 0; new_map->regex.allocated = 0; new_map->regex.regs_allocated = REGS_FIXED; #else new_map->pattern = (char *)alloc(strlen(text) + 1); Strcpy(new_map->pattern, text); #endif new_map->filename = strdup(filespec); new_map->volume = volume; new_map->next = soundmap; #ifdef USER_SOUNDS_REGEX err = re_compile_pattern(text, strlen(text), &new_map->regex); #else err = 0; #endif if (err) { raw_print(err); free(new_map->filename); free(new_map); return 0; } else { soundmap = new_map; } } else { Sprintf(text, "cannot read %.243s", filespec); raw_print(text); return 0; } } else { raw_print("syntax error in SOUND"); return 0; } return 1; } void play_sound_for_message(msg) const char* msg; { audio_mapping* cursor = soundmap; while (cursor) { #ifdef USER_SOUNDS_REGEX if (re_search(&cursor->regex, msg, strlen(msg), 0, 9999, 0) >= 0) { #else if (pmatch(cursor->pattern, msg)) { #endif play_usersound(cursor->filename, cursor->volume); } cursor = cursor->next; } } #endif /* USER_SOUNDS */ #endif /* OVLB */ /*sounds.c*/ nethack-3.4.3/src/sp_lev.c0100644000000000000000000017707607764735041014117 0ustar rootroot/* SCCS Id: @(#)sp_lev.c 3.4 2001/09/06 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the various functions that are related to the special * levels. * It contains also the special level loader. * */ #include "hack.h" #include "dlb.h" /* #define DEBUG */ /* uncomment to enable code debugging */ #ifdef DEBUG # ifdef WIZARD #define debugpline if (wizard) pline # else #define debugpline pline # endif #endif #include "sp_lev.h" #include "rect.h" extern void FDECL(mkmap, (lev_init *)); STATIC_DCL void FDECL(get_room_loc, (schar *, schar *, struct mkroom *)); STATIC_DCL void FDECL(get_free_room_loc, (schar *, schar *, struct mkroom *)); STATIC_DCL void FDECL(create_trap, (trap *, struct mkroom *)); STATIC_DCL int FDECL(noncoalignment, (ALIGNTYP_P)); STATIC_DCL void FDECL(create_monster, (monster *, struct mkroom *)); STATIC_DCL void FDECL(create_object, (object *, struct mkroom *)); STATIC_DCL void FDECL(create_engraving, (engraving *,struct mkroom *)); STATIC_DCL void FDECL(create_stairs, (stair *, struct mkroom *)); STATIC_DCL void FDECL(create_altar, (altar *, struct mkroom *)); STATIC_DCL void FDECL(create_gold, (gold *, struct mkroom *)); STATIC_DCL void FDECL(create_feature, (int,int,struct mkroom *,int)); STATIC_DCL boolean FDECL(search_door, (struct mkroom *, xchar *, xchar *, XCHAR_P, int)); STATIC_DCL void NDECL(fix_stair_rooms); STATIC_DCL void FDECL(create_corridor, (corridor *)); STATIC_DCL boolean FDECL(create_subroom, (struct mkroom *, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P, XCHAR_P)); #define LEFT 1 #define H_LEFT 2 #define CENTER 3 #define H_RIGHT 4 #define RIGHT 5 #define TOP 1 #define BOTTOM 5 #define sq(x) ((x)*(x)) #define XLIM 4 #define YLIM 3 #define Fread (void)dlb_fread #define Fgetc (schar)dlb_fgetc #define New(type) (type *) alloc(sizeof(type)) #define NewTab(type, size) (type **) alloc(sizeof(type *) * (unsigned)size) #define Free(ptr) if(ptr) free((genericptr_t) (ptr)) static NEARDATA walk walklist[50]; extern int min_rx, max_rx, min_ry, max_ry; /* from mkmap.c */ static char Map[COLNO][ROWNO]; static char robjects[10], rloc_x[10], rloc_y[10], rmonst[10]; static aligntyp ralign[3] = { AM_CHAOTIC, AM_NEUTRAL, AM_LAWFUL }; static NEARDATA xchar xstart, ystart; static NEARDATA char xsize, ysize; STATIC_DCL void FDECL(set_wall_property, (XCHAR_P,XCHAR_P,XCHAR_P,XCHAR_P,int)); STATIC_DCL int NDECL(rnddoor); STATIC_DCL int NDECL(rndtrap); STATIC_DCL void FDECL(get_location, (schar *,schar *,int)); STATIC_DCL void FDECL(sp_lev_shuffle, (char *,char *,int)); STATIC_DCL void FDECL(light_region, (region *)); STATIC_DCL void FDECL(load_common_data, (dlb *,int)); STATIC_DCL void FDECL(load_one_monster, (dlb *,monster *)); STATIC_DCL void FDECL(load_one_object, (dlb *,object *)); STATIC_DCL void FDECL(load_one_engraving, (dlb *,engraving *)); STATIC_DCL boolean FDECL(load_rooms, (dlb *)); STATIC_DCL void FDECL(maze1xy, (coord *,int)); STATIC_DCL boolean FDECL(load_maze, (dlb *)); STATIC_DCL void FDECL(create_door, (room_door *, struct mkroom *)); STATIC_DCL void FDECL(free_rooms,(room **, int)); STATIC_DCL void FDECL(build_room, (room *, room*)); char *lev_message = 0; lev_region *lregions = 0; int num_lregions = 0; lev_init init_lev; /* * Make walls of the area (x1, y1, x2, y2) non diggable/non passwall-able */ STATIC_OVL void set_wall_property(x1,y1,x2,y2, prop) xchar x1, y1, x2, y2; int prop; { register xchar x, y; for(y = y1; y <= y2; y++) for(x = x1; x <= x2; x++) if(IS_STWALL(levl[x][y].typ)) levl[x][y].wall_info |= prop; } /* * Choose randomly the state (nodoor, open, closed or locked) for a door */ STATIC_OVL int rnddoor() { int i = 1 << rn2(5); i >>= 1; return i; } /* * Select a random trap */ STATIC_OVL int rndtrap() { int rtrap; do { rtrap = rnd(TRAPNUM-1); switch (rtrap) { case HOLE: /* no random holes on special levels */ case MAGIC_PORTAL: rtrap = NO_TRAP; break; case TRAPDOOR: if (!Can_dig_down(&u.uz)) rtrap = NO_TRAP; break; case LEVEL_TELEP: case TELEP_TRAP: if (level.flags.noteleport) rtrap = NO_TRAP; break; case ROLLING_BOULDER_TRAP: case ROCKTRAP: if (In_endgame(&u.uz)) rtrap = NO_TRAP; break; } } while (rtrap == NO_TRAP); return rtrap; } /* * Coordinates in special level files are handled specially: * * if x or y is -11, we generate a random coordinate. * if x or y is between -1 and -10, we read one from the corresponding * register (x0, x1, ... x9). * if x or y is nonnegative, we convert it from relative to the local map * to global coordinates. * The "humidity" flag is used to insure that engravings aren't * created underwater, or eels on dry land. */ #define DRY 0x1 #define WET 0x2 STATIC_DCL boolean FDECL(is_ok_location, (SCHAR_P, SCHAR_P, int)); STATIC_OVL void get_location(x, y, humidity) schar *x, *y; int humidity; { int cpt = 0; if (*x >= 0) { /* normal locations */ *x += xstart; *y += ystart; } else if (*x > -11) { /* special locations */ *y = ystart + rloc_y[ - *y - 1]; *x = xstart + rloc_x[ - *x - 1]; } else { /* random location */ do { *x = xstart + rn2((int)xsize); *y = ystart + rn2((int)ysize); if (is_ok_location(*x,*y,humidity)) break; } while (++cpt < 100); if (cpt >= 100) { register int xx, yy; /* last try */ for (xx = 0; xx < xsize; xx++) for (yy = 0; yy < ysize; yy++) { *x = xstart + xx; *y = ystart + yy; if (is_ok_location(*x,*y,humidity)) goto found_it; } panic("get_location: can't find a place!"); } } found_it:; if (!isok(*x,*y)) { impossible("get_location: (%d,%d) out of bounds", *x, *y); *x = x_maze_max; *y = y_maze_max; } } STATIC_OVL boolean is_ok_location(x, y, humidity) register schar x, y; register int humidity; { register int typ; if (Is_waterlevel(&u.uz)) return TRUE; /* accept any spot */ if (humidity & DRY) { typ = levl[x][y].typ; if (typ == ROOM || typ == AIR || typ == CLOUD || typ == ICE || typ == CORR) return TRUE; } if (humidity & WET) { if (is_pool(x,y) || is_lava(x,y)) return TRUE; } return FALSE; } /* * Shuffle the registers for locations, objects or monsters */ STATIC_OVL void sp_lev_shuffle(list1, list2, n) char list1[], list2[]; int n; { register int i, j; register char k; for (i = n - 1; i > 0; i--) { if ((j = rn2(i + 1)) == i) continue; k = list1[j]; list1[j] = list1[i]; list1[i] = k; if (list2) { k = list2[j]; list2[j] = list2[i]; list2[i] = k; } } } /* * Get a relative position inside a room. * negative values for x or y means RANDOM! */ STATIC_OVL void get_room_loc(x,y, croom) schar *x, *y; struct mkroom *croom; { coord c; if (*x <0 && *y <0) { if (somexy(croom, &c)) { *x = c.x; *y = c.y; } else panic("get_room_loc : can't find a place!"); } else { if (*x < 0) *x = rn2(croom->hx - croom->lx + 1); if (*y < 0) *y = rn2(croom->hy - croom->ly + 1); *x += croom->lx; *y += croom->ly; } } /* * Get a relative position inside a room. * negative values for x or y means RANDOM! */ STATIC_OVL void get_free_room_loc(x,y, croom) schar *x, *y; struct mkroom *croom; { schar try_x, try_y; register int trycnt = 0; do { try_x = *x, try_y = *y; get_room_loc(&try_x, &try_y, croom); } while (levl[try_x][try_y].typ != ROOM && ++trycnt <= 100); if (trycnt > 100) panic("get_free_room_loc: can't find a place!"); *x = try_x, *y = try_y; } boolean check_room(lowx, ddx, lowy, ddy, vault) xchar *lowx, *ddx, *lowy, *ddy; boolean vault; { register int x,y,hix = *lowx + *ddx, hiy = *lowy + *ddy; register struct rm *lev; int xlim, ylim, ymax; xlim = XLIM + (vault ? 1 : 0); ylim = YLIM + (vault ? 1 : 0); if (*lowx < 3) *lowx = 3; if (*lowy < 2) *lowy = 2; if (hix > COLNO-3) hix = COLNO-3; if (hiy > ROWNO-3) hiy = ROWNO-3; chk: if (hix <= *lowx || hiy <= *lowy) return FALSE; /* check area around room (and make room smaller if necessary) */ for (x = *lowx - xlim; x<= hix + xlim; x++) { if(x <= 0 || x >= COLNO) continue; y = *lowy - ylim; ymax = hiy + ylim; if(y < 0) y = 0; if(ymax >= ROWNO) ymax = (ROWNO-1); lev = &levl[x][y]; for (; y <= ymax; y++) { if (lev++->typ) { #ifdef DEBUG if(!vault) debugpline("strange area [%d,%d] in check_room.",x,y); #endif if (!rn2(3)) return FALSE; if (x < *lowx) *lowx = x + xlim + 1; else hix = x - xlim - 1; if (y < *lowy) *lowy = y + ylim + 1; else hiy = y - ylim - 1; goto chk; } } } *ddx = hix - *lowx; *ddy = hiy - *lowy; return TRUE; } /* * Create a new room. * This is still very incomplete... */ boolean create_room(x,y,w,h,xal,yal,rtype,rlit) xchar x,y; xchar w,h; xchar xal,yal; xchar rtype, rlit; { xchar xabs, yabs; int wtmp, htmp, xaltmp, yaltmp, xtmp, ytmp; NhRect *r1 = 0, r2; int trycnt = 0; boolean vault = FALSE; int xlim = XLIM, ylim = YLIM; if (rtype == -1) /* Is the type random ? */ rtype = OROOM; if (rtype == VAULT) { vault = TRUE; xlim++; ylim++; } /* on low levels the room is lit (usually) */ /* some other rooms may require lighting */ /* is light state random ? */ if (rlit == -1) rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE; /* * Here we will try to create a room. If some parameters are * random we are willing to make several try before we give * it up. */ do { xchar xborder, yborder; wtmp = w; htmp = h; xtmp = x; ytmp = y; xaltmp = xal; yaltmp = yal; /* First case : a totaly random room */ if((xtmp < 0 && ytmp <0 && wtmp < 0 && xaltmp < 0 && yaltmp < 0) || vault) { xchar hx, hy, lx, ly, dx, dy; r1 = rnd_rect(); /* Get a random rectangle */ if (!r1) { /* No more free rectangles ! */ #ifdef DEBUG debugpline("No more rects..."); #endif return FALSE; } hx = r1->hx; hy = r1->hy; lx = r1->lx; ly = r1->ly; if (vault) dx = dy = 1; else { dx = 2 + rn2((hx-lx > 28) ? 12 : 8); dy = 2 + rn2(4); if(dx*dy > 50) dy = 50/dx; } xborder = (lx > 0 && hx < COLNO -1) ? 2*xlim : xlim+1; yborder = (ly > 0 && hy < ROWNO -1) ? 2*ylim : ylim+1; if(hx-lx < dx + 3 + xborder || hy-ly < dy + 3 + yborder) { r1 = 0; continue; } xabs = lx + (lx > 0 ? xlim : 3) + rn2(hx - (lx>0?lx : 3) - dx - xborder + 1); yabs = ly + (ly > 0 ? ylim : 2) + rn2(hy - (ly>0?ly : 2) - dy - yborder + 1); if (ly == 0 && hy >= (ROWNO-1) && (!nroom || !rn2(nroom)) && (yabs+dy > ROWNO/2)) { yabs = rn1(3, 2); if(nroom < 4 && dy>1) dy--; } if (!check_room(&xabs, &dx, &yabs, &dy, vault)) { r1 = 0; continue; } wtmp = dx+1; htmp = dy+1; r2.lx = xabs-1; r2.ly = yabs-1; r2.hx = xabs + wtmp; r2.hy = yabs + htmp; } else { /* Only some parameters are random */ int rndpos = 0; if (xtmp < 0 && ytmp < 0) { /* Position is RANDOM */ xtmp = rnd(5); ytmp = rnd(5); rndpos = 1; } if (wtmp < 0 || htmp < 0) { /* Size is RANDOM */ wtmp = rn1(15, 3); htmp = rn1(8, 2); } if (xaltmp == -1) /* Horizontal alignment is RANDOM */ xaltmp = rnd(3); if (yaltmp == -1) /* Vertical alignment is RANDOM */ yaltmp = rnd(3); /* Try to generate real (absolute) coordinates here! */ xabs = (((xtmp-1) * COLNO) / 5) + 1; yabs = (((ytmp-1) * ROWNO) / 5) + 1; switch (xaltmp) { case LEFT: break; case RIGHT: xabs += (COLNO / 5) - wtmp; break; case CENTER: xabs += ((COLNO / 5) - wtmp) / 2; break; } switch (yaltmp) { case TOP: break; case BOTTOM: yabs += (ROWNO / 5) - htmp; break; case CENTER: yabs += ((ROWNO / 5) - htmp) / 2; break; } if (xabs + wtmp - 1 > COLNO - 2) xabs = COLNO - wtmp - 3; if (xabs < 2) xabs = 2; if (yabs + htmp - 1> ROWNO - 2) yabs = ROWNO - htmp - 3; if (yabs < 2) yabs = 2; /* Try to find a rectangle that fit our room ! */ r2.lx = xabs-1; r2.ly = yabs-1; r2.hx = xabs + wtmp + rndpos; r2.hy = yabs + htmp + rndpos; r1 = get_rect(&r2); } } while (++trycnt <= 100 && !r1); if (!r1) { /* creation of room failed ? */ return FALSE; } split_rects(r1, &r2); if (!vault) { smeq[nroom] = nroom; add_room(xabs, yabs, xabs+wtmp-1, yabs+htmp-1, rlit, rtype, FALSE); } else { rooms[nroom].lx = xabs; rooms[nroom].ly = yabs; } return TRUE; } /* * Create a subroom in room proom at pos x,y with width w & height h. * x & y are relative to the parent room. */ STATIC_OVL boolean create_subroom(proom, x, y, w, h, rtype, rlit) struct mkroom *proom; xchar x,y; xchar w,h; xchar rtype, rlit; { xchar width, height; width = proom->hx - proom->lx + 1; height = proom->hy - proom->ly + 1; /* There is a minimum size for the parent room */ if (width < 4 || height < 4) return FALSE; /* Check for random position, size, etc... */ if (w == -1) w = rnd(width - 3); if (h == -1) h = rnd(height - 3); if (x == -1) x = rnd(width - w - 1) - 1; if (y == -1) y = rnd(height - h - 1) - 1; if (x == 1) x = 0; if (y == 1) y = 0; if ((x + w + 1) == width) x++; if ((y + h + 1) == height) y++; if (rtype == -1) rtype = OROOM; if (rlit == -1) rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE; add_subroom(proom, proom->lx + x, proom->ly + y, proom->lx + x + w - 1, proom->ly + y + h - 1, rlit, rtype, FALSE); return TRUE; } /* * Create a new door in a room. * It's placed on a wall (north, south, east or west). */ STATIC_OVL void create_door(dd, broom) room_door *dd; struct mkroom *broom; { int x, y; int trycnt = 0; if (dd->secret == -1) dd->secret = rn2(2); if (dd->mask == -1) { /* is it a locked door, closed, or a doorway? */ if (!dd->secret) { if(!rn2(3)) { if(!rn2(5)) dd->mask = D_ISOPEN; else if(!rn2(6)) dd->mask = D_LOCKED; else dd->mask = D_CLOSED; if (dd->mask != D_ISOPEN && !rn2(25)) dd->mask |= D_TRAPPED; } else dd->mask = D_NODOOR; } else { if(!rn2(5)) dd->mask = D_LOCKED; else dd->mask = D_CLOSED; if(!rn2(20)) dd->mask |= D_TRAPPED; } } do { register int dwall, dpos; dwall = dd->wall; if (dwall == -1) /* The wall is RANDOM */ dwall = 1 << rn2(4); dpos = dd->pos; if (dpos == -1) /* The position is RANDOM */ dpos = rn2((dwall == W_WEST || dwall == W_EAST) ? (broom->hy - broom->ly) : (broom->hx - broom->lx)); /* Convert wall and pos into an absolute coordinate! */ switch (dwall) { case W_NORTH: y = broom->ly - 1; x = broom->lx + dpos; break; case W_SOUTH: y = broom->hy + 1; x = broom->lx + dpos; break; case W_WEST: x = broom->lx - 1; y = broom->ly + dpos; break; case W_EAST: x = broom->hx + 1; y = broom->ly + dpos; break; default: x = y = 0; panic("create_door: No wall for door!"); break; } if (okdoor(x,y)) break; } while (++trycnt <= 100); if (trycnt > 100) { impossible("create_door: Can't find a proper place!"); return; } add_door(x,y,broom); levl[x][y].typ = (dd->secret ? SDOOR : DOOR); levl[x][y].doormask = dd->mask; } /* * Create a secret door in croom on any one of the specified walls. */ void create_secret_door(croom, walls) struct mkroom *croom; xchar walls; /* any of W_NORTH | W_SOUTH | W_EAST | W_WEST (or W_ANY) */ { xchar sx, sy; /* location of the secret door */ int count; for(count = 0; count < 100; count++) { sx = rn1(croom->hx - croom->lx + 1, croom->lx); sy = rn1(croom->hy - croom->ly + 1, croom->ly); switch(rn2(4)) { case 0: /* top */ if(!(walls & W_NORTH)) continue; sy = croom->ly-1; break; case 1: /* bottom */ if(!(walls & W_SOUTH)) continue; sy = croom->hy+1; break; case 2: /* left */ if(!(walls & W_EAST)) continue; sx = croom->lx-1; break; case 3: /* right */ if(!(walls & W_WEST)) continue; sx = croom->hx+1; break; } if(okdoor(sx,sy)) { levl[sx][sy].typ = SDOOR; levl[sx][sy].doormask = D_CLOSED; add_door(sx,sy,croom); return; } } impossible("couldn't create secret door on any walls 0x%x", walls); } /* * Create a trap in a room. */ STATIC_OVL void create_trap(t,croom) trap *t; struct mkroom *croom; { schar x,y; coord tm; if (rn2(100) < t->chance) { x = t->x; y = t->y; if (croom) get_free_room_loc(&x, &y, croom); else get_location(&x, &y, DRY); tm.x = x; tm.y = y; mktrap(t->type, 1, (struct mkroom*) 0, &tm); } } /* * Create a monster in a room. */ STATIC_OVL int noncoalignment(alignment) aligntyp alignment; { int k; k = rn2(2); if (!alignment) return(k ? -1 : 1); return(k ? -alignment : 0); } STATIC_OVL void create_monster(m,croom) monster *m; struct mkroom *croom; { struct monst *mtmp; schar x, y; char class; aligntyp amask; coord cc; struct permonst *pm; unsigned g_mvflags; if (rn2(100) < m->chance) { if (m->class >= 0) class = (char) def_char_to_monclass((char)m->class); else if (m->class > -11) class = (char) def_char_to_monclass(rmonst[- m->class - 1]); else class = 0; if (class == MAXMCLASSES) panic("create_monster: unknown monster class '%c'", m->class); amask = (m->align == AM_SPLEV_CO) ? Align2amask(u.ualignbase[A_ORIGINAL]) : (m->align == AM_SPLEV_NONCO) ? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) : (m->align <= -11) ? induced_align(80) : (m->align < 0 ? ralign[-m->align-1] : m->align); if (!class) pm = (struct permonst *) 0; else if (m->id != NON_PM) { pm = &mons[m->id]; g_mvflags = (unsigned) mvitals[monsndx(pm)].mvflags; if ((pm->geno & G_UNIQ) && (g_mvflags & G_EXTINCT)) goto m_done; else if (g_mvflags & G_GONE) /* genocided or extinct */ pm = (struct permonst *) 0; /* make random monster */ } else { pm = mkclass(class,G_NOGEN); /* if we can't get a specific monster type (pm == 0) then the class has been genocided, so settle for a random monster */ } if (In_mines(&u.uz) && pm && your_race(pm) && (Race_if(PM_DWARF) || Race_if(PM_GNOME)) && rn2(3)) pm = (struct permonst *) 0; x = m->x; y = m->y; if (croom) get_room_loc(&x, &y, croom); else { if (!pm || !is_swimmer(pm)) get_location(&x, &y, DRY); else if (pm->mlet == S_EEL) get_location(&x, &y, WET); else get_location(&x, &y, DRY|WET); } /* try to find a close place if someone else is already there */ if (MON_AT(x,y) && enexto(&cc, x, y, pm)) x = cc.x, y = cc.y; if(m->align != -12) mtmp = mk_roamer(pm, Amask2align(amask), x, y, m->peaceful); else if(PM_ARCHEOLOGIST <= m->id && m->id <= PM_WIZARD) mtmp = mk_mplayer(pm, x, y, FALSE); else mtmp = makemon(pm, x, y, NO_MM_FLAGS); if (mtmp) { /* handle specific attributes for some special monsters */ if (m->name.str) mtmp = christen_monst(mtmp, m->name.str); /* * This is currently hardwired for mimics only. It should * eventually be expanded. */ if (m->appear_as.str && mtmp->data->mlet == S_MIMIC) { int i; switch (m->appear) { case M_AP_NOTHING: impossible( "create_monster: mon has an appearance, \"%s\", but no type", m->appear_as.str); break; case M_AP_FURNITURE: for (i = 0; i < MAXPCHARS; i++) if (!strcmp(defsyms[i].explanation, m->appear_as.str)) break; if (i == MAXPCHARS) { impossible( "create_monster: can't find feature \"%s\"", m->appear_as.str); } else { mtmp->m_ap_type = M_AP_FURNITURE; mtmp->mappearance = i; } break; case M_AP_OBJECT: for (i = 0; i < NUM_OBJECTS; i++) if (OBJ_NAME(objects[i]) && !strcmp(OBJ_NAME(objects[i]),m->appear_as.str)) break; if (i == NUM_OBJECTS) { impossible( "create_monster: can't find object \"%s\"", m->appear_as.str); } else { mtmp->m_ap_type = M_AP_OBJECT; mtmp->mappearance = i; } break; case M_AP_MONSTER: /* note: mimics don't appear as monsters! */ /* (but chameleons can :-) */ default: impossible( "create_monster: unimplemented mon appear type [%d,\"%s\"]", m->appear, m->appear_as.str); break; } if (does_block(x, y, &levl[x][y])) block_point(x, y); } if (m->peaceful >= 0) { mtmp->mpeaceful = m->peaceful; /* changed mpeaceful again; have to reset malign */ set_malign(mtmp); } if (m->asleep >= 0) { #ifdef UNIXPC /* optimizer bug strikes again */ if (m->asleep) mtmp->msleeping = 1; else mtmp->msleeping = 0; #else mtmp->msleeping = m->asleep; #endif } } } /* if (rn2(100) < m->chance) */ m_done: Free(m->name.str); Free(m->appear_as.str); } /* * Create an object in a room. */ STATIC_OVL void create_object(o,croom) object *o; struct mkroom *croom; { struct obj *otmp; schar x, y; char c; boolean named; /* has a name been supplied in level description? */ if (rn2(100) < o->chance) { named = o->name.str ? TRUE : FALSE; x = o->x; y = o->y; if (croom) get_room_loc(&x, &y, croom); else get_location(&x, &y, DRY); if (o->class >= 0) c = o->class; else if (o->class > -11) c = robjects[ -(o->class+1)]; else c = 0; if (!c) otmp = mkobj_at(RANDOM_CLASS, x, y, !named); else if (o->id != -1) otmp = mksobj_at(o->id, x, y, TRUE, !named); else { /* * The special levels are compiled with the default "text" object * class characters. We must convert them to the internal format. */ char oclass = (char) def_char_to_objclass(c); if (oclass == MAXOCLASSES) panic("create_object: unexpected object class '%c'",c); /* KMH -- Create piles of gold properly */ if (oclass == COIN_CLASS) otmp = mkgold(0L, x, y); else otmp = mkobj_at(oclass, x, y, !named); } if (o->spe != -127) /* That means NOT RANDOM! */ otmp->spe = (schar)o->spe; switch (o->curse_state) { case 1: bless(otmp); break; /* BLESSED */ case 2: unbless(otmp); uncurse(otmp); break; /* uncursed */ case 3: curse(otmp); break; /* CURSED */ default: break; /* Otherwise it's random and we're happy * with what mkobj gave us! */ } /* corpsenm is "empty" if -1, random if -2, otherwise specific */ if (o->corpsenm == NON_PM - 1) otmp->corpsenm = rndmonnum(); else if (o->corpsenm != NON_PM) otmp->corpsenm = o->corpsenm; /* assume we wouldn't be given an egg corpsenm unless it was hatchable */ if (otmp->otyp == EGG && otmp->corpsenm != NON_PM) { if (dead_species(otmp->otyp, TRUE)) kill_egg(otmp); /* make sure nothing hatches */ else attach_egg_hatch_timeout(otmp); /* attach new hatch timeout */ } if (named) otmp = oname(otmp, o->name.str); switch(o->containment) { static struct obj *container = 0; /* contents */ case 1: if (!container) { impossible("create_object: no container"); break; } remove_object(otmp); (void) add_to_container(container, otmp); goto o_done; /* don't stack, but do other cleanup */ /* container */ case 2: delete_contents(otmp); container = otmp; break; /* nothing */ case 0: break; default: impossible("containment type %d?", (int) o->containment); } /* Medusa level special case: statues are petrified monsters, so they * are not stone-resistant and have monster inventory. They also lack * other contents, but that can be specified as an empty container. */ if (o->id == STATUE && Is_medusa_level(&u.uz) && o->corpsenm == NON_PM) { struct monst *was; struct obj *obj; int wastyp; /* Named random statues are of player types, and aren't stone- * resistant (if they were, we'd have to reset the name as well as * setting corpsenm). */ for (wastyp = otmp->corpsenm; ; wastyp = rndmonnum()) { /* makemon without rndmonst() might create a group */ was = makemon(&mons[wastyp], 0, 0, NO_MM_FLAGS); if (!resists_ston(was)) break; mongone(was); } otmp->corpsenm = wastyp; while(was->minvent) { obj = was->minvent; obj->owornmask = 0; obj_extract_self(obj); (void) add_to_container(otmp, obj); } otmp->owt = weight(otmp); mongone(was); } stackobj(otmp); } /* if (rn2(100) < o->chance) */ o_done: Free(o->name.str); } /* * Randomly place a specific engraving, then release its memory. */ STATIC_OVL void create_engraving(e, croom) engraving *e; struct mkroom *croom; { xchar x, y; x = e->x, y = e->y; if (croom) get_room_loc(&x, &y, croom); else get_location(&x, &y, DRY); make_engr_at(x, y, e->engr.str, 0L, e->etype); free((genericptr_t) e->engr.str); } /* * Create stairs in a room. * */ STATIC_OVL void create_stairs(s,croom) stair *s; struct mkroom *croom; { schar x,y; x = s->x; y = s->y; get_free_room_loc(&x, &y, croom); mkstairs(x,y,(char)s->up, croom); } /* * Create an altar in a room. */ STATIC_OVL void create_altar(a, croom) altar *a; struct mkroom *croom; { schar sproom,x,y; aligntyp amask; boolean croom_is_temple = TRUE; int oldtyp; x = a->x; y = a->y; if (croom) { get_free_room_loc(&x, &y, croom); if (croom->rtype != TEMPLE) croom_is_temple = FALSE; } else { get_location(&x, &y, DRY); if ((sproom = (schar) *in_rooms(x, y, TEMPLE)) != 0) croom = &rooms[sproom - ROOMOFFSET]; else croom_is_temple = FALSE; } /* check for existing features */ oldtyp = levl[x][y].typ; if (oldtyp == STAIRS || oldtyp == LADDER) return; a->x = x; a->y = y; /* Is the alignment random ? * If so, it's an 80% chance that the altar will be co-aligned. * * The alignment is encoded as amask values instead of alignment * values to avoid conflicting with the rest of the encoding, * shared by many other parts of the special level code. */ amask = (a->align == AM_SPLEV_CO) ? Align2amask(u.ualignbase[A_ORIGINAL]) : (a->align == AM_SPLEV_NONCO) ? Align2amask(noncoalignment(u.ualignbase[A_ORIGINAL])) : (a->align == -11) ? induced_align(80) : (a->align < 0 ? ralign[-a->align-1] : a->align); levl[x][y].typ = ALTAR; levl[x][y].altarmask = amask; if (a->shrine < 0) a->shrine = rn2(2); /* handle random case */ if (oldtyp == FOUNTAIN) level.flags.nfountains--; else if (oldtyp == SINK) level.flags.nsinks--; if (!croom_is_temple || !a->shrine) return; if (a->shrine) { /* Is it a shrine or sanctum? */ priestini(&u.uz, croom, x, y, (a->shrine > 1)); levl[x][y].altarmask |= AM_SHRINE; level.flags.has_temple = TRUE; } } /* * Create a gold pile in a room. */ STATIC_OVL void create_gold(g,croom) gold *g; struct mkroom *croom; { schar x,y; x = g->x; y= g->y; if (croom) get_room_loc(&x, &y, croom); else get_location(&x, &y, DRY); if (g->amount == -1) g->amount = rnd(200); (void) mkgold((long) g->amount, x, y); } /* * Create a feature (e.g a fountain) in a room. */ STATIC_OVL void create_feature(fx, fy, croom, typ) int fx, fy; struct mkroom *croom; int typ; { schar x,y; int trycnt = 0; x = fx; y = fy; if (croom) { if (x < 0 && y < 0) do { x = -1; y = -1; get_room_loc(&x, &y, croom); } while (++trycnt <= 200 && occupied(x,y)); else get_room_loc(&x, &y, croom); if(trycnt > 200) return; } else { get_location(&x, &y, DRY); } /* Don't cover up an existing feature (particularly randomly placed stairs). However, if the _same_ feature is already here, it came from the map drawing and we still need to update the special counters. */ if (IS_FURNITURE(levl[x][y].typ) && levl[x][y].typ != typ) return; levl[x][y].typ = typ; if (typ == FOUNTAIN) level.flags.nfountains++; else if (typ == SINK) level.flags.nsinks++; } /* * Search for a door in a room on a specified wall. */ STATIC_OVL boolean search_door(croom,x,y,wall,cnt) struct mkroom *croom; xchar *x, *y; xchar wall; int cnt; { int dx, dy; int xx,yy; switch(wall) { case W_NORTH: dy = 0; dx = 1; xx = croom->lx; yy = croom->hy + 1; break; case W_SOUTH: dy = 0; dx = 1; xx = croom->lx; yy = croom->ly - 1; break; case W_EAST: dy = 1; dx = 0; xx = croom->hx + 1; yy = croom->ly; break; case W_WEST: dy = 1; dx = 0; xx = croom->lx - 1; yy = croom->ly; break; default: dx = dy = xx = yy = 0; panic("search_door: Bad wall!"); break; } while (xx <= croom->hx+1 && yy <= croom->hy+1) { if (IS_DOOR(levl[xx][yy].typ) || levl[xx][yy].typ == SDOOR) { *x = xx; *y = yy; if (cnt-- <= 0) return TRUE; } xx += dx; yy += dy; } return FALSE; } /* * Dig a corridor between two points. */ boolean dig_corridor(org,dest,nxcor,ftyp,btyp) coord *org, *dest; boolean nxcor; schar ftyp, btyp; { register int dx=0, dy=0, dix, diy, cct; register struct rm *crm; register int tx, ty, xx, yy; xx = org->x; yy = org->y; tx = dest->x; ty = dest->y; if (xx <= 0 || yy <= 0 || tx <= 0 || ty <= 0 || xx > COLNO-1 || tx > COLNO-1 || yy > ROWNO-1 || ty > ROWNO-1) { #ifdef DEBUG debugpline("dig_corridor: bad coords : (%d,%d) (%d,%d).", xx,yy,tx,ty); #endif return FALSE; } if (tx > xx) dx = 1; else if (ty > yy) dy = 1; else if (tx < xx) dx = -1; else dy = -1; xx -= dx; yy -= dy; cct = 0; while(xx != tx || yy != ty) { /* loop: dig corridor at [xx,yy] and find new [xx,yy] */ if(cct++ > 500 || (nxcor && !rn2(35))) return FALSE; xx += dx; yy += dy; if(xx >= COLNO-1 || xx <= 0 || yy <= 0 || yy >= ROWNO-1) return FALSE; /* impossible */ crm = &levl[xx][yy]; if(crm->typ == btyp) { if(ftyp != CORR || rn2(100)) { crm->typ = ftyp; if(nxcor && !rn2(50)) (void) mksobj_at(BOULDER, xx, yy, TRUE, FALSE); } else { crm->typ = SCORR; } } else if(crm->typ != ftyp && crm->typ != SCORR) { /* strange ... */ return FALSE; } /* find next corridor position */ dix = abs(xx-tx); diy = abs(yy-ty); /* do we have to change direction ? */ if(dy && dix > diy) { register int ddx = (xx > tx) ? -1 : 1; crm = &levl[xx+ddx][yy]; if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) { dx = ddx; dy = 0; continue; } } else if(dx && diy > dix) { register int ddy = (yy > ty) ? -1 : 1; crm = &levl[xx][yy+ddy]; if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) { dy = ddy; dx = 0; continue; } } /* continue straight on? */ crm = &levl[xx+dx][yy+dy]; if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) continue; /* no, what must we do now?? */ if(dx) { dx = 0; dy = (ty < yy) ? -1 : 1; } else { dy = 0; dx = (tx < xx) ? -1 : 1; } crm = &levl[xx+dx][yy+dy]; if(crm->typ == btyp || crm->typ == ftyp || crm->typ == SCORR) continue; dy = -dy; dx = -dx; } return TRUE; } /* * Disgusting hack: since special levels have their rooms filled before * sorting the rooms, we have to re-arrange the speed values upstairs_room * and dnstairs_room after the rooms have been sorted. On normal levels, * stairs don't get created until _after_ sorting takes place. */ STATIC_OVL void fix_stair_rooms() { int i; struct mkroom *croom; if(xdnstair && !((dnstairs_room->lx <= xdnstair && xdnstair <= dnstairs_room->hx) && (dnstairs_room->ly <= ydnstair && ydnstair <= dnstairs_room->hy))) { for(i=0; i < nroom; i++) { croom = &rooms[i]; if((croom->lx <= xdnstair && xdnstair <= croom->hx) && (croom->ly <= ydnstair && ydnstair <= croom->hy)) { dnstairs_room = croom; break; } } if(i == nroom) panic("Couldn't find dnstair room in fix_stair_rooms!"); } if(xupstair && !((upstairs_room->lx <= xupstair && xupstair <= upstairs_room->hx) && (upstairs_room->ly <= yupstair && yupstair <= upstairs_room->hy))) { for(i=0; i < nroom; i++) { croom = &rooms[i]; if((croom->lx <= xupstair && xupstair <= croom->hx) && (croom->ly <= yupstair && yupstair <= croom->hy)) { upstairs_room = croom; break; } } if(i == nroom) panic("Couldn't find upstair room in fix_stair_rooms!"); } } /* * Corridors always start from a door. But it can end anywhere... * Basically we search for door coordinates or for endpoints coordinates * (from a distance). */ STATIC_OVL void create_corridor(c) corridor *c; { coord org, dest; if (c->src.room == -1) { sort_rooms(); fix_stair_rooms(); makecorridors(); return; } if( !search_door(&rooms[c->src.room], &org.x, &org.y, c->src.wall, c->src.door)) return; if (c->dest.room != -1) { if(!search_door(&rooms[c->dest.room], &dest.x, &dest.y, c->dest.wall, c->dest.door)) return; switch(c->src.wall) { case W_NORTH: org.y--; break; case W_SOUTH: org.y++; break; case W_WEST: org.x--; break; case W_EAST: org.x++; break; } switch(c->dest.wall) { case W_NORTH: dest.y--; break; case W_SOUTH: dest.y++; break; case W_WEST: dest.x--; break; case W_EAST: dest.x++; break; } (void) dig_corridor(&org, &dest, FALSE, CORR, STONE); } } /* * Fill a room (shop, zoo, etc...) with appropriate stuff. */ void fill_room(croom, prefilled) struct mkroom *croom; boolean prefilled; { if (!croom || croom->rtype == OROOM) return; if (!prefilled) { int x,y; /* Shop ? */ if (croom->rtype >= SHOPBASE) { stock_room(croom->rtype - SHOPBASE, croom); level.flags.has_shop = TRUE; return; } switch (croom->rtype) { case VAULT: for (x=croom->lx;x<=croom->hx;x++) for (y=croom->ly;y<=croom->hy;y++) (void) mkgold((long)rn1(abs(depth(&u.uz))*100, 51), x, y); break; case COURT: case ZOO: case BEEHIVE: case MORGUE: case BARRACKS: fill_zoo(croom); break; } } switch (croom->rtype) { case VAULT: level.flags.has_vault = TRUE; break; case ZOO: level.flags.has_zoo = TRUE; break; case COURT: level.flags.has_court = TRUE; break; case MORGUE: level.flags.has_morgue = TRUE; break; case BEEHIVE: level.flags.has_beehive = TRUE; break; case BARRACKS: level.flags.has_barracks = TRUE; break; case TEMPLE: level.flags.has_temple = TRUE; break; case SWAMP: level.flags.has_swamp = TRUE; break; } } STATIC_OVL void free_rooms(ro, n) room **ro; int n; { short j; room *r; while(n--) { r = ro[n]; Free(r->name); Free(r->parent); if ((j = r->ndoor) != 0) { while(j--) Free(r->doors[j]); Free(r->doors); } if ((j = r->nstair) != 0) { while(j--) Free(r->stairs[j]); Free(r->stairs); } if ((j = r->naltar) != 0) { while (j--) Free(r->altars[j]); Free(r->altars); } if ((j = r->nfountain) != 0) { while(j--) Free(r->fountains[j]); Free(r->fountains); } if ((j = r->nsink) != 0) { while(j--) Free(r->sinks[j]); Free(r->sinks); } if ((j = r->npool) != 0) { while(j--) Free(r->pools[j]); Free(r->pools); } if ((j = r->ntrap) != 0) { while (j--) Free(r->traps[j]); Free(r->traps); } if ((j = r->nmonster) != 0) { while (j--) Free(r->monsters[j]); Free(r->monsters); } if ((j = r->nobject) != 0) { while (j--) Free(r->objects[j]); Free(r->objects); } if ((j = r->ngold) != 0) { while(j--) Free(r->golds[j]); Free(r->golds); } if ((j = r->nengraving) != 0) { while (j--) Free(r->engravings[j]); Free(r->engravings); } Free(r); } Free(ro); } STATIC_OVL void build_room(r, pr) room *r, *pr; { boolean okroom; struct mkroom *aroom; short i; xchar rtype = (!r->chance || rn2(100) < r->chance) ? r->rtype : OROOM; if(pr) { aroom = &subrooms[nsubroom]; okroom = create_subroom(pr->mkr, r->x, r->y, r->w, r->h, rtype, r->rlit); } else { aroom = &rooms[nroom]; okroom = create_room(r->x, r->y, r->w, r->h, r->xalign, r->yalign, rtype, r->rlit); r->mkr = aroom; } if (okroom) { /* Create subrooms if necessary... */ for(i=0; i < r->nsubroom; i++) build_room(r->subrooms[i], r); /* And now we can fill the room! */ /* Priority to the stairs */ for(i=0; i nstair; i++) create_stairs(r->stairs[i], aroom); /* Then to the various elements (sinks, etc..) */ for(i = 0; insink; i++) create_feature(r->sinks[i]->x, r->sinks[i]->y, aroom, SINK); for(i = 0; inpool; i++) create_feature(r->pools[i]->x, r->pools[i]->y, aroom, POOL); for(i = 0; infountain; i++) create_feature(r->fountains[i]->x, r->fountains[i]->y, aroom, FOUNTAIN); for(i = 0; inaltar; i++) create_altar(r->altars[i], aroom); for(i = 0; indoor; i++) create_door(r->doors[i], aroom); /* The traps */ for(i = 0; intrap; i++) create_trap(r->traps[i], aroom); /* The monsters */ for(i = 0; inmonster; i++) create_monster(r->monsters[i], aroom); /* The objects */ for(i = 0; inobject; i++) create_object(r->objects[i], aroom); /* The gold piles */ for(i = 0; ingold; i++) create_gold(r->golds[i], aroom); /* The engravings */ for (i = 0; i < r->nengraving; i++) create_engraving(r->engravings[i], aroom); #ifdef SPECIALIZATION topologize(aroom,FALSE); /* set roomno */ #else topologize(aroom); /* set roomno */ #endif /* MRS - 07/04/91 - This is temporary but should result * in proper filling of shops, etc. * DLC - this can fail if corridors are added to this room * at a later point. Currently no good way to fix this. */ if(aroom->rtype != OROOM && r->filled) fill_room(aroom, FALSE); } } /* * set lighting in a region that will not become a room. */ STATIC_OVL void light_region(tmpregion) region *tmpregion; { register boolean litstate = tmpregion->rlit ? 1 : 0; register int hiy = tmpregion->y2; register int x, y; register struct rm *lev; int lowy = tmpregion->y1; int lowx = tmpregion->x1, hix = tmpregion->x2; if(litstate) { /* adjust region size for walls, but only if lighted */ lowx = max(lowx-1,1); hix = min(hix+1,COLNO-1); lowy = max(lowy-1,0); hiy = min(hiy+1, ROWNO-1); } for(x = lowx; x <= hix; x++) { lev = &levl[x][lowy]; for(y = lowy; y <= hiy; y++) { if (lev->typ != LAVAPOOL) /* this overrides normal lighting */ lev->lit = litstate; lev++; } } } /* initialization common to all special levels */ STATIC_OVL void load_common_data(fd, typ) dlb *fd; int typ; { uchar n; long lev_flags; int i; { aligntyp atmp; /* shuffle 3 alignments; can't use sp_lev_shuffle() on aligntyp's */ i = rn2(3); atmp=ralign[2]; ralign[2]=ralign[i]; ralign[i]=atmp; if (rn2(2)) { atmp=ralign[1]; ralign[1]=ralign[0]; ralign[0]=atmp; } } level.flags.is_maze_lev = typ == SP_LEV_MAZE; /* Read the level initialization data */ Fread((genericptr_t) &init_lev, 1, sizeof(lev_init), fd); if(init_lev.init_present) { if(init_lev.lit < 0) init_lev.lit = rn2(2); mkmap(&init_lev); } /* Read the per level flags */ Fread((genericptr_t) &lev_flags, 1, sizeof(lev_flags), fd); if (lev_flags & NOTELEPORT) level.flags.noteleport = 1; if (lev_flags & HARDFLOOR) level.flags.hardfloor = 1; if (lev_flags & NOMMAP) level.flags.nommap = 1; if (lev_flags & SHORTSIGHTED) level.flags.shortsighted = 1; if (lev_flags & ARBOREAL) level.flags.arboreal = 1; /* Read message */ Fread((genericptr_t) &n, 1, sizeof(n), fd); if (n) { lev_message = (char *) alloc(n + 1); Fread((genericptr_t) lev_message, 1, (int) n, fd); lev_message[n] = 0; } } STATIC_OVL void load_one_monster(fd, m) dlb *fd; monster *m; { int size; Fread((genericptr_t) m, 1, sizeof *m, fd); if ((size = m->name.len) != 0) { m->name.str = (char *) alloc((unsigned)size + 1); Fread((genericptr_t) m->name.str, 1, size, fd); m->name.str[size] = '\0'; } else m->name.str = (char *) 0; if ((size = m->appear_as.len) != 0) { m->appear_as.str = (char *) alloc((unsigned)size + 1); Fread((genericptr_t) m->appear_as.str, 1, size, fd); m->appear_as.str[size] = '\0'; } else m->appear_as.str = (char *) 0; } STATIC_OVL void load_one_object(fd, o) dlb *fd; object *o; { int size; Fread((genericptr_t) o, 1, sizeof *o, fd); if ((size = o->name.len) != 0) { o->name.str = (char *) alloc((unsigned)size + 1); Fread((genericptr_t) o->name.str, 1, size, fd); o->name.str[size] = '\0'; } else o->name.str = (char *) 0; } STATIC_OVL void load_one_engraving(fd, e) dlb *fd; engraving *e; { int size; Fread((genericptr_t) e, 1, sizeof *e, fd); size = e->engr.len; e->engr.str = (char *) alloc((unsigned)size+1); Fread((genericptr_t) e->engr.str, 1, size, fd); e->engr.str[size] = '\0'; } STATIC_OVL boolean load_rooms(fd) dlb *fd; { xchar nrooms, ncorr; char n; short size; corridor tmpcor; room** tmproom; int i, j; load_common_data(fd, SP_LEV_ROOMS); Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrobjects */ if (n) { Fread((genericptr_t)robjects, sizeof(*robjects), n, fd); sp_lev_shuffle(robjects, (char *)0, (int)n); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* nrmonst */ if (n) { Fread((genericptr_t)rmonst, sizeof(*rmonst), n, fd); sp_lev_shuffle(rmonst, (char *)0, (int)n); } Fread((genericptr_t) &nrooms, 1, sizeof(nrooms), fd); /* Number of rooms to read */ tmproom = NewTab(room,nrooms); for (i=0;i 0) { /* Yup, it does! */ r->name = (char *) alloc((unsigned)size + 1); Fread((genericptr_t) r->name, 1, size, fd); r->name[size] = 0; } else r->name = (char *) 0; /* Let's see if this room has a parent */ Fread((genericptr_t) &size, 1, sizeof(size), fd); if (size > 0) { /* Yup, it does! */ r->parent = (char *) alloc((unsigned)size + 1); Fread((genericptr_t) r->parent, 1, size, fd); r->parent[size] = 0; } else r->parent = (char *) 0; Fread((genericptr_t) &r->x, 1, sizeof(r->x), fd); /* x pos on the grid (1-5) */ Fread((genericptr_t) &r->y, 1, sizeof(r->y), fd); /* y pos on the grid (1-5) */ Fread((genericptr_t) &r->w, 1, sizeof(r->w), fd); /* width of the room */ Fread((genericptr_t) &r->h, 1, sizeof(r->h), fd); /* height of the room */ Fread((genericptr_t) &r->xalign, 1, sizeof(r->xalign), fd); /* horizontal alignment */ Fread((genericptr_t) &r->yalign, 1, sizeof(r->yalign), fd); /* vertical alignment */ Fread((genericptr_t) &r->rtype, 1, sizeof(r->rtype), fd); /* type of room (zoo, shop, etc.) */ Fread((genericptr_t) &r->chance, 1, sizeof(r->chance), fd); /* chance of room being special. */ Fread((genericptr_t) &r->rlit, 1, sizeof(r->rlit), fd); /* lit or not ? */ Fread((genericptr_t) &r->filled, 1, sizeof(r->filled), fd); /* to be filled? */ r->nsubroom= 0; /* read the doors */ Fread((genericptr_t) &r->ndoor, 1, sizeof(r->ndoor), fd); if ((n = r->ndoor) != 0) r->doors = NewTab(room_door, n); while(n--) { r->doors[(int)n] = New(room_door); Fread((genericptr_t) r->doors[(int)n], 1, sizeof(room_door), fd); } /* read the stairs */ Fread((genericptr_t) &r->nstair, 1, sizeof(r->nstair), fd); if ((n = r->nstair) != 0) r->stairs = NewTab(stair, n); while (n--) { r->stairs[(int)n] = New(stair); Fread((genericptr_t) r->stairs[(int)n], 1, sizeof(stair), fd); } /* read the altars */ Fread((genericptr_t) &r->naltar, 1, sizeof(r->naltar), fd); if ((n = r->naltar) != 0) r->altars = NewTab(altar, n); while (n--) { r->altars[(int)n] = New(altar); Fread((genericptr_t) r->altars[(int)n], 1, sizeof(altar), fd); } /* read the fountains */ Fread((genericptr_t) &r->nfountain, 1, sizeof(r->nfountain), fd); if ((n = r->nfountain) != 0) r->fountains = NewTab(fountain, n); while (n--) { r->fountains[(int)n] = New(fountain); Fread((genericptr_t) r->fountains[(int)n], 1, sizeof(fountain), fd); } /* read the sinks */ Fread((genericptr_t) &r->nsink, 1, sizeof(r->nsink), fd); if ((n = r->nsink) != 0) r->sinks = NewTab(sink, n); while (n--) { r->sinks[(int)n] = New(sink); Fread((genericptr_t) r->sinks[(int)n], 1, sizeof(sink), fd); } /* read the pools */ Fread((genericptr_t) &r->npool, 1, sizeof(r->npool), fd); if ((n = r->npool) != 0) r->pools = NewTab(pool,n); while (n--) { r->pools[(int)n] = New(pool); Fread((genericptr_t) r->pools[(int)n], 1, sizeof(pool), fd); } /* read the traps */ Fread((genericptr_t) &r->ntrap, 1, sizeof(r->ntrap), fd); if ((n = r->ntrap) != 0) r->traps = NewTab(trap, n); while(n--) { r->traps[(int)n] = New(trap); Fread((genericptr_t) r->traps[(int)n], 1, sizeof(trap), fd); } /* read the monsters */ Fread((genericptr_t) &r->nmonster, 1, sizeof(r->nmonster), fd); if ((n = r->nmonster) != 0) { r->monsters = NewTab(monster, n); while(n--) { r->monsters[(int)n] = New(monster); load_one_monster(fd, r->monsters[(int)n]); } } else r->monsters = 0; /* read the objects, in same order as mazes */ Fread((genericptr_t) &r->nobject, 1, sizeof(r->nobject), fd); if ((n = r->nobject) != 0) { r->objects = NewTab(object, n); for (j = 0; j < n; ++j) { r->objects[j] = New(object); load_one_object(fd, r->objects[j]); } } else r->objects = 0; /* read the gold piles */ Fread((genericptr_t) &r->ngold, 1, sizeof(r->ngold), fd); if ((n = r->ngold) != 0) r->golds = NewTab(gold, n); while (n--) { r->golds[(int)n] = New(gold); Fread((genericptr_t) r->golds[(int)n], 1, sizeof(gold), fd); } /* read the engravings */ Fread((genericptr_t) &r->nengraving, 1, sizeof(r->nengraving), fd); if ((n = r->nengraving) != 0) { r->engravings = NewTab(engraving,n); while (n--) { r->engravings[(int)n] = New(engraving); load_one_engraving(fd, r->engravings[(int)n]); } } else r->engravings = 0; } /* Now that we have loaded all the rooms, search the * subrooms and create the links. */ for (i = 0; iparent) { /* Search the parent room */ for(j=0; jname && !strcmp(tmproom[j]->name, tmproom[i]->parent)) { n = tmproom[j]->nsubroom++; tmproom[j]->subrooms[(int)n] = tmproom[i]; break; } } /* * Create the rooms now... */ for (i=0; i < nrooms; i++) if(!tmproom[i]->parent) build_room(tmproom[i], (room *) 0); free_rooms(tmproom, nrooms); /* read the corridors */ Fread((genericptr_t) &ncorr, sizeof(ncorr), 1, fd); for (i=0; ix = (xchar)x, m->y = (xchar)y; } /* * The Big Thing: special maze loader * * Could be cleaner, but it works. */ STATIC_OVL boolean load_maze(fd) dlb *fd; { xchar x, y, typ; boolean prefilled, room_not_needed; char n, numpart = 0; xchar nwalk = 0, nwalk_sav; schar filling; char halign, valign; int xi, dir, size; coord mm; int mapcount, mapcountmax, mapfact; lev_region tmplregion; region tmpregion; door tmpdoor; trap tmptrap; monster tmpmons; object tmpobj; drawbridge tmpdb; walk tmpwalk; digpos tmpdig; lad tmplad; stair tmpstair, prevstair; altar tmpaltar; gold tmpgold; fountain tmpfountain; engraving tmpengraving; xchar mustfill[(MAXNROFROOMS+1)*2]; struct trap *badtrap; boolean has_bounds; (void) memset((genericptr_t)&Map[0][0], 0, sizeof Map); load_common_data(fd, SP_LEV_MAZE); /* Initialize map */ Fread((genericptr_t) &filling, 1, sizeof(filling), fd); if (!init_lev.init_present) { /* don't init if mkmap() has been called */ for(x = 2; x <= x_maze_max; x++) for(y = 0; y <= y_maze_max; y++) if (filling == -1) { #ifndef WALLIFIED_MAZE levl[x][y].typ = STONE; #else levl[x][y].typ = (y < 2 || ((x % 2) && (y % 2))) ? STONE : HWALL; #endif } else { levl[x][y].typ = filling; } } /* Start reading the file */ Fread((genericptr_t) &numpart, 1, sizeof(numpart), fd); /* Number of parts */ if (!numpart || numpart > 9) panic("load_maze error: numpart = %d", (int) numpart); while (numpart--) { Fread((genericptr_t) &halign, 1, sizeof(halign), fd); /* Horizontal alignment */ Fread((genericptr_t) &valign, 1, sizeof(valign), fd); /* Vertical alignment */ Fread((genericptr_t) &xsize, 1, sizeof(xsize), fd); /* size in X */ Fread((genericptr_t) &ysize, 1, sizeof(ysize), fd); /* size in Y */ switch((int) halign) { case LEFT: xstart = 3; break; case H_LEFT: xstart = 2+((x_maze_max-2-xsize)/4); break; case CENTER: xstart = 2+((x_maze_max-2-xsize)/2); break; case H_RIGHT: xstart = 2+((x_maze_max-2-xsize)*3/4); break; case RIGHT: xstart = x_maze_max-xsize-1; break; } switch((int) valign) { case TOP: ystart = 3; break; case CENTER: ystart = 2+((y_maze_max-2-ysize)/2); break; case BOTTOM: ystart = y_maze_max-ysize-1; break; } if (!(xstart % 2)) xstart++; if (!(ystart % 2)) ystart++; if ((ystart < 0) || (ystart + ysize > ROWNO)) { /* try to move the start a bit */ ystart += (ystart > 0) ? -2 : 2; if(ysize == ROWNO) ystart = 0; if(ystart < 0 || ystart + ysize > ROWNO) panic("reading special level with ysize too large"); } /* * If any CROSSWALLs are found, must change to ROOM after REGION's * are laid out. CROSSWALLS are used to specify "invisible" * boundaries where DOOR syms look bad or aren't desirable. */ has_bounds = FALSE; if(init_lev.init_present && xsize <= 1 && ysize <= 1) { xstart = 1; ystart = 0; xsize = COLNO-1; ysize = ROWNO; } else { /* Load the map */ for(y = ystart; y < ystart+ysize; y++) for(x = xstart; x < xstart+xsize; x++) { levl[x][y].typ = Fgetc(fd); levl[x][y].lit = FALSE; /* clear out levl: load_common_data may set them */ levl[x][y].flags = 0; levl[x][y].horizontal = 0; levl[x][y].roomno = 0; levl[x][y].edge = 0; /* * Note: Even though levl[x][y].typ is type schar, * lev_comp.y saves it as type char. Since schar != char * all the time we must make this exception or hack * through lev_comp.y to fix. */ /* * Set secret doors to closed (why not trapped too?). Set * the horizontal bit. */ if (levl[x][y].typ == SDOOR || IS_DOOR(levl[x][y].typ)) { if(levl[x][y].typ == SDOOR) levl[x][y].doormask = D_CLOSED; /* * If there is a wall to the left that connects to a * (secret) door, then it is horizontal. This does * not allow (secret) doors to be corners of rooms. */ if (x != xstart && (IS_WALL(levl[x-1][y].typ) || levl[x-1][y].horizontal)) levl[x][y].horizontal = 1; } else if(levl[x][y].typ == HWALL || levl[x][y].typ == IRONBARS) levl[x][y].horizontal = 1; else if(levl[x][y].typ == LAVAPOOL) levl[x][y].lit = 1; else if(levl[x][y].typ == CROSSWALL) has_bounds = TRUE; Map[x][y] = 1; } if (init_lev.init_present && init_lev.joined) remove_rooms(xstart, ystart, xstart+xsize, ystart+ysize); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of level regions */ if(n) { if(num_lregions) { /* realloc the lregion space to add the new ones */ /* don't really free it up until the whole level is done */ lev_region *newl = (lev_region *) alloc(sizeof(lev_region) * (unsigned)(n+num_lregions)); (void) memcpy((genericptr_t)(newl+n), (genericptr_t)lregions, sizeof(lev_region) * num_lregions); Free(lregions); num_lregions += n; lregions = newl; } else { num_lregions = n; lregions = (lev_region *) alloc(sizeof(lev_region) * (unsigned)n); } } while(n--) { Fread((genericptr_t) &tmplregion, sizeof(tmplregion), 1, fd); if ((size = tmplregion.rname.len) != 0) { tmplregion.rname.str = (char *) alloc((unsigned)size + 1); Fread((genericptr_t) tmplregion.rname.str, size, 1, fd); tmplregion.rname.str[size] = '\0'; } else tmplregion.rname.str = (char *) 0; if(!tmplregion.in_islev) { get_location(&tmplregion.inarea.x1, &tmplregion.inarea.y1, DRY|WET); get_location(&tmplregion.inarea.x2, &tmplregion.inarea.y2, DRY|WET); } if(!tmplregion.del_islev) { get_location(&tmplregion.delarea.x1, &tmplregion.delarea.y1, DRY|WET); get_location(&tmplregion.delarea.x2, &tmplregion.delarea.y2, DRY|WET); } lregions[(int)n] = tmplregion; } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Random objects */ if(n) { Fread((genericptr_t)robjects, sizeof(*robjects), (int) n, fd); sp_lev_shuffle(robjects, (char *)0, (int)n); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Random locations */ if(n) { Fread((genericptr_t)rloc_x, sizeof(*rloc_x), (int) n, fd); Fread((genericptr_t)rloc_y, sizeof(*rloc_y), (int) n, fd); sp_lev_shuffle(rloc_x, rloc_y, (int)n); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Random monsters */ if(n) { Fread((genericptr_t)rmonst, sizeof(*rmonst), (int) n, fd); sp_lev_shuffle(rmonst, (char *)0, (int)n); } (void) memset((genericptr_t)mustfill, 0, sizeof(mustfill)); Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of subrooms */ while(n--) { register struct mkroom *troom; Fread((genericptr_t)&tmpregion, 1, sizeof(tmpregion), fd); if(tmpregion.rtype > MAXRTYPE) { tmpregion.rtype -= MAXRTYPE+1; prefilled = TRUE; } else prefilled = FALSE; if(tmpregion.rlit < 0) tmpregion.rlit = (rnd(1+abs(depth(&u.uz))) < 11 && rn2(77)) ? TRUE : FALSE; get_location(&tmpregion.x1, &tmpregion.y1, DRY|WET); get_location(&tmpregion.x2, &tmpregion.y2, DRY|WET); /* for an ordinary room, `prefilled' is a flag to force an actual room to be created (such rooms are used to control placement of migrating monster arrivals) */ room_not_needed = (tmpregion.rtype == OROOM && !tmpregion.rirreg && !prefilled); if (room_not_needed || nroom >= MAXNROFROOMS) { if (!room_not_needed) impossible("Too many rooms on new level!"); light_region(&tmpregion); continue; } troom = &rooms[nroom]; /* mark rooms that must be filled, but do it later */ if (tmpregion.rtype != OROOM) mustfill[nroom] = (prefilled ? 2 : 1); if(tmpregion.rirreg) { min_rx = max_rx = tmpregion.x1; min_ry = max_ry = tmpregion.y1; flood_fill_rm(tmpregion.x1, tmpregion.y1, nroom+ROOMOFFSET, tmpregion.rlit, TRUE); add_room(min_rx, min_ry, max_rx, max_ry, FALSE, tmpregion.rtype, TRUE); troom->rlit = tmpregion.rlit; troom->irregular = TRUE; } else { add_room(tmpregion.x1, tmpregion.y1, tmpregion.x2, tmpregion.y2, tmpregion.rlit, tmpregion.rtype, TRUE); #ifdef SPECIALIZATION topologize(troom,FALSE); /* set roomno */ #else topologize(troom); /* set roomno */ #endif } } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of doors */ while(n--) { struct mkroom *croom = &rooms[0]; Fread((genericptr_t)&tmpdoor, 1, sizeof(tmpdoor), fd); x = tmpdoor.x; y = tmpdoor.y; typ = tmpdoor.mask == -1 ? rnddoor() : tmpdoor.mask; get_location(&x, &y, DRY); if(levl[x][y].typ != SDOOR) levl[x][y].typ = DOOR; else { if(typ < D_CLOSED) typ = D_CLOSED; /* force it to be closed */ } levl[x][y].doormask = typ; /* Now the complicated part, list it with each subroom */ /* The dog move and mail daemon routines use this */ while(croom->hx >= 0 && doorindex < DOORMAX) { if(croom->hx >= x-1 && croom->lx <= x+1 && croom->hy >= y-1 && croom->ly <= y+1) { /* Found it */ add_door(x, y, croom); } croom++; } } /* now that we have rooms _and_ associated doors, fill the rooms */ for(n = 0; n < SIZE(mustfill); n++) if(mustfill[(int)n]) fill_room(&rooms[(int)n], (mustfill[(int)n] == 2)); /* if special boundary syms (CROSSWALL) in map, remove them now */ if(has_bounds) { for(x = xstart; x < xstart+xsize; x++) for(y = ystart; y < ystart+ysize; y++) if(levl[x][y].typ == CROSSWALL) levl[x][y].typ = ROOM; } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of drawbridges */ while(n--) { Fread((genericptr_t)&tmpdb, 1, sizeof(tmpdb), fd); x = tmpdb.x; y = tmpdb.y; get_location(&x, &y, DRY|WET); if (!create_drawbridge(x, y, tmpdb.dir, tmpdb.db_open)) impossible("Cannot create drawbridge."); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of mazewalks */ while(n--) { Fread((genericptr_t)&tmpwalk, 1, sizeof(tmpwalk), fd); get_location(&tmpwalk.x, &tmpwalk.y, DRY|WET); walklist[nwalk++] = tmpwalk; } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of non_diggables */ while(n--) { Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd); get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET); get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET); set_wall_property(tmpdig.x1, tmpdig.y1, tmpdig.x2, tmpdig.y2, W_NONDIGGABLE); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of non_passables */ while(n--) { Fread((genericptr_t)&tmpdig, 1, sizeof(tmpdig), fd); get_location(&tmpdig.x1, &tmpdig.y1, DRY|WET); get_location(&tmpdig.x2, &tmpdig.y2, DRY|WET); set_wall_property(tmpdig.x1, tmpdig.y1, tmpdig.x2, tmpdig.y2, W_NONPASSWALL); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of ladders */ while(n--) { Fread((genericptr_t)&tmplad, 1, sizeof(tmplad), fd); x = tmplad.x; y = tmplad.y; get_location(&x, &y, DRY); levl[x][y].typ = LADDER; if (tmplad.up == 1) { xupladder = x; yupladder = y; levl[x][y].ladder = LA_UP; } else { xdnladder = x; ydnladder = y; levl[x][y].ladder = LA_DOWN; } } prevstair.x = prevstair.y = 0; Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of stairs */ while(n--) { Fread((genericptr_t)&tmpstair, 1, sizeof(tmpstair), fd); xi = 0; do { x = tmpstair.x; y = tmpstair.y; get_location(&x, &y, DRY); } while(prevstair.x && xi++ < 100 && distmin(x,y,prevstair.x,prevstair.y) <= 8); if ((badtrap = t_at(x,y)) != 0) deltrap(badtrap); mkstairs(x, y, (char)tmpstair.up, (struct mkroom *)0); prevstair.x = x; prevstair.y = y; } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of altars */ while(n--) { Fread((genericptr_t)&tmpaltar, 1, sizeof(tmpaltar), fd); create_altar(&tmpaltar, (struct mkroom *)0); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of fountains */ while (n--) { Fread((genericptr_t)&tmpfountain, 1, sizeof(tmpfountain), fd); create_feature(tmpfountain.x, tmpfountain.y, (struct mkroom *)0, FOUNTAIN); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of traps */ while(n--) { Fread((genericptr_t)&tmptrap, 1, sizeof(tmptrap), fd); create_trap(&tmptrap, (struct mkroom *)0); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of monsters */ while(n--) { load_one_monster(fd, &tmpmons); create_monster(&tmpmons, (struct mkroom *)0); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of objects */ while(n--) { load_one_object(fd, &tmpobj); create_object(&tmpobj, (struct mkroom *)0); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of gold piles */ while (n--) { Fread((genericptr_t)&tmpgold, 1, sizeof(tmpgold), fd); create_gold(&tmpgold, (struct mkroom *)0); } Fread((genericptr_t) &n, 1, sizeof(n), fd); /* Number of engravings */ while(n--) { load_one_engraving(fd, &tmpengraving); create_engraving(&tmpengraving, (struct mkroom *)0); } } /* numpart loop */ nwalk_sav = nwalk; while(nwalk--) { x = (xchar) walklist[nwalk].x; y = (xchar) walklist[nwalk].y; dir = walklist[nwalk].dir; /* don't use move() - it doesn't use W_NORTH, etc. */ switch (dir) { case W_NORTH: --y; break; case W_SOUTH: y++; break; case W_EAST: x++; break; case W_WEST: --x; break; default: panic("load_maze: bad MAZEWALK direction"); } if(!IS_DOOR(levl[x][y].typ)) { #ifndef WALLIFIED_MAZE levl[x][y].typ = CORR; #else levl[x][y].typ = ROOM; #endif levl[x][y].flags = 0; } /* * We must be sure that the parity of the coordinates for * walkfrom() is odd. But we must also take into account * what direction was chosen. */ if(!(x % 2)) { if (dir == W_EAST) x++; else x--; /* no need for IS_DOOR check; out of map bounds */ #ifndef WALLIFIED_MAZE levl[x][y].typ = CORR; #else levl[x][y].typ = ROOM; #endif levl[x][y].flags = 0; } if (!(y % 2)) { if (dir == W_SOUTH) y++; else y--; } walkfrom(x, y); } wallification(1, 0, COLNO-1, ROWNO-1); /* * If there's a significant portion of maze unused by the special level, * we don't want it empty. * * Makes the number of traps, monsters, etc. proportional * to the size of the maze. */ mapcountmax = mapcount = (x_maze_max - 2) * (y_maze_max - 2); for(x = 2; x < x_maze_max; x++) for(y = 0; y < y_maze_max; y++) if(Map[x][y]) mapcount--; if (nwalk_sav && (mapcount > (int) (mapcountmax / 10))) { mapfact = (int) ((mapcount * 100L) / mapcountmax); for(x = rnd((int) (20 * mapfact) / 100); x; x--) { maze1xy(&mm, DRY); (void) mkobj_at(rn2(2) ? GEM_CLASS : RANDOM_CLASS, mm.x, mm.y, TRUE); } for(x = rnd((int) (12 * mapfact) / 100); x; x--) { maze1xy(&mm, DRY); (void) mksobj_at(BOULDER, mm.x, mm.y, TRUE, FALSE); } for (x = rn2(2); x; x--) { maze1xy(&mm, DRY); (void) makemon(&mons[PM_MINOTAUR], mm.x, mm.y, NO_MM_FLAGS); } for(x = rnd((int) (12 * mapfact) / 100); x; x--) { maze1xy(&mm, WET|DRY); (void) makemon((struct permonst *) 0, mm.x, mm.y, NO_MM_FLAGS); } for(x = rn2((int) (15 * mapfact) / 100); x; x--) { maze1xy(&mm, DRY); (void) mkgold(0L,mm.x,mm.y); } for(x = rn2((int) (15 * mapfact) / 100); x; x--) { int trytrap; maze1xy(&mm, DRY); trytrap = rndtrap(); if (sobj_at(BOULDER, mm.x, mm.y)) while (trytrap == PIT || trytrap == SPIKED_PIT || trytrap == TRAPDOOR || trytrap == HOLE) trytrap = rndtrap(); (void) maketrap(mm.x, mm.y, trytrap); } } return TRUE; } /* * General loader */ boolean load_special(name) const char *name; { dlb *fd; boolean result = FALSE; char c; struct version_info vers_info; fd = dlb_fopen(name, RDBMODE); if (!fd) return FALSE; Fread((genericptr_t) &vers_info, sizeof vers_info, 1, fd); if (!check_version(&vers_info, name, TRUE)) goto give_up; Fread((genericptr_t) &c, sizeof c, 1, fd); /* c Header */ switch (c) { case SP_LEV_ROOMS: result = load_rooms(fd); break; case SP_LEV_MAZE: result = load_maze(fd); break; default: /* ??? */ result = FALSE; } give_up: (void)dlb_fclose(fd); return result; } /*sp_lev.c*/ nethack-3.4.3/src/spell.c0100644000000000000000000010512207764735041013725 0ustar rootroot/* SCCS Id: @(#)spell.c 3.4 2003/01/17 */ /* Copyright (c) M. Stephenson 1988 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" static NEARDATA schar delay; /* moves left for this spell */ static NEARDATA struct obj *book; /* last/current book being xscribed */ /* spellmenu arguments; 0 thru n-1 used as spl_book[] index when swapping */ #define SPELLMENU_CAST (-2) #define SPELLMENU_VIEW (-1) #define KEEN 20000 #define MAX_SPELL_STUDY 3 #define incrnknow(spell) spl_book[spell].sp_know = KEEN #define spellev(spell) spl_book[spell].sp_lev #define spellname(spell) OBJ_NAME(objects[spellid(spell)]) #define spellet(spell) \ ((char)((spell < 26) ? ('a' + spell) : ('A' + spell - 26))) STATIC_DCL int FDECL(spell_let_to_idx, (CHAR_P)); STATIC_DCL boolean FDECL(cursed_book, (struct obj *bp)); STATIC_DCL boolean FDECL(confused_book, (struct obj *)); STATIC_DCL void FDECL(deadbook, (struct obj *)); STATIC_PTR int NDECL(learn); STATIC_DCL boolean FDECL(getspell, (int *)); STATIC_DCL boolean FDECL(dospellmenu, (const char *,int,int *)); STATIC_DCL int FDECL(percent_success, (int)); STATIC_DCL int NDECL(throwspell); STATIC_DCL void NDECL(cast_protection); STATIC_DCL void FDECL(spell_backfire, (int)); STATIC_DCL const char *FDECL(spelltypemnemonic, (int)); STATIC_DCL int FDECL(isqrt, (int)); /* The roles[] table lists the role-specific values for tuning * percent_success(). * * Reasoning: * spelbase, spelheal: * Arc are aware of magic through historical research * Bar abhor magic (Conan finds it "interferes with his animal instincts") * Cav are ignorant to magic * Hea are very aware of healing magic through medical research * Kni are moderately aware of healing from Paladin training * Mon use magic to attack and defend in lieu of weapons and armor * Pri are very aware of healing magic through theological research * Ran avoid magic, preferring to fight unseen and unheard * Rog are moderately aware of magic through trickery * Sam have limited magical awareness, prefering meditation to conjuring * Tou are aware of magic from all the great films they have seen * Val have limited magical awareness, prefering fighting * Wiz are trained mages * * The arms penalty is lessened for trained fighters Bar, Kni, Ran, * Sam, Val - * the penalty is its metal interference, not encumbrance. * The `spelspec' is a single spell which is fundamentally easier * for that role to cast. * * spelspec, spelsbon: * Arc map masters (SPE_MAGIC_MAPPING) * Bar fugue/berserker (SPE_HASTE_SELF) * Cav born to dig (SPE_DIG) * Hea to heal (SPE_CURE_SICKNESS) * Kni to turn back evil (SPE_TURN_UNDEAD) * Mon to preserve their abilities (SPE_RESTORE_ABILITY) * Pri to bless (SPE_REMOVE_CURSE) * Ran to hide (SPE_INVISIBILITY) * Rog to find loot (SPE_DETECT_TREASURE) * Sam to be At One (SPE_CLAIRVOYANCE) * Tou to smile (SPE_CHARM_MONSTER) * Val control the cold (SPE_CONE_OF_COLD) * Wiz all really, but SPE_MAGIC_MISSILE is their party trick * * See percent_success() below for more comments. * * uarmbon, uarmsbon, uarmhbon, uarmgbon, uarmfbon: * Fighters find body armour & shield a little less limiting. * Headgear, Gauntlets and Footwear are not role-specific (but * still have an effect, except helm of brilliance, which is designed * to permit magic-use). */ #define uarmhbon 4 /* Metal helmets interfere with the mind */ #define uarmgbon 6 /* Casting channels through the hands */ #define uarmfbon 2 /* All metal interferes to some degree */ /* since the spellbook itself doesn't blow up, don't say just "explodes" */ static const char explodes[] = "radiates explosive energy"; /* convert a letter into a number in the range 0..51, or -1 if not a letter */ STATIC_OVL int spell_let_to_idx(ilet) char ilet; { int indx; indx = ilet - 'a'; if (indx >= 0 && indx < 26) return indx; indx = ilet - 'A'; if (indx >= 0 && indx < 26) return indx + 26; return -1; } /* TRUE: book should be destroyed by caller */ STATIC_OVL boolean cursed_book(bp) struct obj *bp; { int lev = objects[bp->otyp].oc_level; switch(rn2(lev)) { case 0: You_feel("a wrenching sensation."); tele(); /* teleport him */ break; case 1: You_feel("threatened."); aggravate(); break; case 2: make_blinded(Blinded + rn1(100,250),TRUE); break; case 3: take_gold(); break; case 4: pline("These runes were just too much to comprehend."); make_confused(HConfusion + rn1(7,16),FALSE); break; case 5: pline_The("book was coated with contact poison!"); if (uarmg) { if (uarmg->oerodeproof || !is_corrodeable(uarmg)) { Your("gloves seem unaffected."); } else if (uarmg->oeroded2 < MAX_ERODE) { if (uarmg->greased) { grease_protect(uarmg, "gloves", &youmonst); } else { Your("gloves corrode%s!", uarmg->oeroded2+1 == MAX_ERODE ? " completely" : uarmg->oeroded2 ? " further" : ""); uarmg->oeroded2++; } } else Your("gloves %s completely corroded.", Blind ? "feel" : "look"); break; } /* temp disable in_use; death should not destroy the book */ bp->in_use = FALSE; losestr(Poison_resistance ? rn1(2,1) : rn1(4,3)); losehp(rnd(Poison_resistance ? 6 : 10), "contact-poisoned spellbook", KILLED_BY_AN); bp->in_use = TRUE; break; case 6: if(Antimagic) { shieldeff(u.ux, u.uy); pline_The("book %s, but you are unharmed!", explodes); } else { pline("As you read the book, it %s in your %s!", explodes, body_part(FACE)); losehp(2*rnd(10)+5, "exploding rune", KILLED_BY_AN); } return TRUE; default: rndcurse(); break; } return FALSE; } /* study while confused: returns TRUE if the book is destroyed */ STATIC_OVL boolean confused_book(spellbook) struct obj *spellbook; { boolean gone = FALSE; if (!rn2(3) && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { spellbook->in_use = TRUE; /* in case called from learn */ pline( "Being confused you have difficulties in controlling your actions."); display_nhwindow(WIN_MESSAGE, FALSE); You("accidentally tear the spellbook to pieces."); if (!objects[spellbook->otyp].oc_name_known && !objects[spellbook->otyp].oc_uname) docall(spellbook); useup(spellbook); gone = TRUE; } else { You("find yourself reading the %s line over and over again.", spellbook == book ? "next" : "first"); } return gone; } /* special effects for The Book of the Dead */ STATIC_OVL void deadbook(book2) struct obj *book2; { struct monst *mtmp, *mtmp2; coord mm; You("turn the pages of the Book of the Dead..."); makeknown(SPE_BOOK_OF_THE_DEAD); /* KMH -- Need ->known to avoid "_a_ Book of the Dead" */ book2->known = 1; if(invocation_pos(u.ux, u.uy) && !On_stairs(u.ux, u.uy)) { register struct obj *otmp; register boolean arti1_primed = FALSE, arti2_primed = FALSE, arti_cursed = FALSE; if(book2->cursed) { pline_The("runes appear scrambled. You can't read them!"); return; } if(!u.uhave.bell || !u.uhave.menorah) { pline("A chill runs down your %s.", body_part(SPINE)); if(!u.uhave.bell) You_hear("a faint chime..."); if(!u.uhave.menorah) pline("Vlad's doppelganger is amused."); return; } for(otmp = invent; otmp; otmp = otmp->nobj) { if(otmp->otyp == CANDELABRUM_OF_INVOCATION && otmp->spe == 7 && otmp->lamplit) { if(!otmp->cursed) arti1_primed = TRUE; else arti_cursed = TRUE; } if(otmp->otyp == BELL_OF_OPENING && (moves - otmp->age) < 5L) { /* you rang it recently */ if(!otmp->cursed) arti2_primed = TRUE; else arti_cursed = TRUE; } } if(arti_cursed) { pline_The("invocation fails!"); pline("At least one of your artifacts is cursed..."); } else if(arti1_primed && arti2_primed) { unsigned soon = (unsigned) d(2,6); /* time til next intervene() */ /* successful invocation */ mkinvokearea(); u.uevent.invoked = 1; /* in case you haven't killed the Wizard yet, behave as if you just did */ u.uevent.udemigod = 1; /* wizdead() */ if (!u.udg_cnt || u.udg_cnt > soon) u.udg_cnt = soon; } else { /* at least one artifact not prepared properly */ You("have a feeling that %s is amiss...", something); goto raise_dead; } return; } /* when not an invocation situation */ if (book2->cursed) { raise_dead: You("raised the dead!"); /* first maybe place a dangerous adversary */ if (!rn2(3) && ((mtmp = makemon(&mons[PM_MASTER_LICH], u.ux, u.uy, NO_MINVENT)) != 0 || (mtmp = makemon(&mons[PM_NALFESHNEE], u.ux, u.uy, NO_MINVENT)) != 0)) { mtmp->mpeaceful = 0; set_malign(mtmp); } /* next handle the affect on things you're carrying */ (void) unturn_dead(&youmonst); /* last place some monsters around you */ mm.x = u.ux; mm.y = u.uy; mkundead(&mm, TRUE, NO_MINVENT); } else if(book2->blessed) { for(mtmp = fmon; mtmp; mtmp = mtmp2) { mtmp2 = mtmp->nmon; /* tamedog() changes chain */ if (DEADMONSTER(mtmp)) continue; if (is_undead(mtmp->data) && cansee(mtmp->mx, mtmp->my)) { mtmp->mpeaceful = TRUE; if(sgn(mtmp->data->maligntyp) == sgn(u.ualign.type) && distu(mtmp->mx, mtmp->my) < 4) if (mtmp->mtame) { if (mtmp->mtame < 20) mtmp->mtame++; } else (void) tamedog(mtmp, (struct obj *)0); else monflee(mtmp, 0, FALSE, TRUE); } } } else { switch(rn2(3)) { case 0: Your("ancestors are annoyed with you!"); break; case 1: pline_The("headstones in the cemetery begin to move!"); break; default: pline("Oh my! Your name appears in the book!"); } } return; } STATIC_PTR int learn() { int i; short booktype; char splname[BUFSZ]; boolean costly = TRUE; /* JDS: lenses give 50% faster reading; 33% smaller read time */ if (delay && ublindf && ublindf->otyp == LENSES && rn2(2)) delay++; if (Confusion) { /* became confused while learning */ (void) confused_book(book); book = 0; /* no longer studying */ nomul(delay); /* remaining delay is uninterrupted */ delay = 0; return(0); } if (delay) { /* not if (delay++), so at end delay == 0 */ delay++; return(1); /* still busy */ } exercise(A_WIS, TRUE); /* you're studying. */ booktype = book->otyp; if(booktype == SPE_BOOK_OF_THE_DEAD) { deadbook(book); return(0); } Sprintf(splname, objects[booktype].oc_name_known ? "\"%s\"" : "the \"%s\" spell", OBJ_NAME(objects[booktype])); for (i = 0; i < MAXSPELL; i++) { if (spellid(i) == booktype) { if (book->spestudied > MAX_SPELL_STUDY) { pline("This spellbook is too faint to be read any more."); book->otyp = booktype = SPE_BLANK_PAPER; } else if (spellknow(i) <= 1000) { Your("knowledge of %s is keener.", splname); incrnknow(i); book->spestudied++; exercise(A_WIS,TRUE); /* extra study */ } else { /* 1000 < spellknow(i) <= MAX_SPELL_STUDY */ You("know %s quite well already.", splname); costly = FALSE; } /* make book become known even when spell is already known, in case amnesia made you forget the book */ makeknown((int)booktype); break; } else if (spellid(i) == NO_SPELL) { spl_book[i].sp_id = booktype; spl_book[i].sp_lev = objects[booktype].oc_level; incrnknow(i); book->spestudied++; You(i > 0 ? "add %s to your repertoire." : "learn %s.", splname); makeknown((int)booktype); break; } } if (i == MAXSPELL) impossible("Too many spells memorized!"); if (book->cursed) { /* maybe a demon cursed it */ if (cursed_book(book)) { useup(book); book = 0; return 0; } } if (costly) check_unpaid(book); book = 0; return(0); } int study_book(spellbook) register struct obj *spellbook; { register int booktype = spellbook->otyp; register boolean confused = (Confusion != 0); boolean too_hard = FALSE; if (delay && !confused && spellbook == book && /* handle the sequence: start reading, get interrupted, have book become erased somehow, resume reading it */ booktype != SPE_BLANK_PAPER) { You("continue your efforts to memorize the spell."); } else { /* KMH -- Simplified this code */ if (booktype == SPE_BLANK_PAPER) { pline("This spellbook is all blank."); makeknown(booktype); return(1); } switch (objects[booktype].oc_level) { case 1: case 2: delay = -objects[booktype].oc_delay; break; case 3: case 4: delay = -(objects[booktype].oc_level - 1) * objects[booktype].oc_delay; break; case 5: case 6: delay = -objects[booktype].oc_level * objects[booktype].oc_delay; break; case 7: delay = -8 * objects[booktype].oc_delay; break; default: impossible("Unknown spellbook level %d, book %d;", objects[booktype].oc_level, booktype); return 0; } /* Books are often wiser than their readers (Rus.) */ spellbook->in_use = TRUE; if (!spellbook->blessed && spellbook->otyp != SPE_BOOK_OF_THE_DEAD) { if (spellbook->cursed) { too_hard = TRUE; } else { /* uncursed - chance to fail */ int read_ability = ACURR(A_INT) + 4 + u.ulevel/2 - 2*objects[booktype].oc_level + ((ublindf && ublindf->otyp == LENSES) ? 2 : 0); /* only wizards know if a spell is too difficult */ if (Role_if(PM_WIZARD) && read_ability < 20 && !confused) { char qbuf[QBUFSZ]; Sprintf(qbuf, "This spellbook is %sdifficult to comprehend. Continue?", (read_ability < 12 ? "very " : "")); if (yn(qbuf) != 'y') { spellbook->in_use = FALSE; return(1); } } /* its up to random luck now */ if (rnd(20) > read_ability) { too_hard = TRUE; } } } if (too_hard) { boolean gone = cursed_book(spellbook); nomul(delay); /* study time */ delay = 0; if(gone || !rn2(3)) { if (!gone) pline_The("spellbook crumbles to dust!"); if (!objects[spellbook->otyp].oc_name_known && !objects[spellbook->otyp].oc_uname) docall(spellbook); useup(spellbook); } else spellbook->in_use = FALSE; return(1); } else if (confused) { if (!confused_book(spellbook)) { spellbook->in_use = FALSE; } nomul(delay); delay = 0; return(1); } spellbook->in_use = FALSE; You("begin to %s the runes.", spellbook->otyp == SPE_BOOK_OF_THE_DEAD ? "recite" : "memorize"); } book = spellbook; set_occupation(learn, "studying", 0); return(1); } /* a spellbook has been destroyed or the character has changed levels; the stored address for the current book is no longer valid */ void book_disappears(obj) struct obj *obj; { if (obj == book) book = (struct obj *)0; } /* renaming an object usually results in it having a different address; so the sequence start reading, get interrupted, name the book, resume reading would read the "new" book from scratch */ void book_substitution(old_obj, new_obj) struct obj *old_obj, *new_obj; { if (old_obj == book) book = new_obj; } /* called from moveloop() */ void age_spells() { int i; /* * The time relative to the hero (a pass through move * loop) causes all spell knowledge to be decremented. * The hero's speed, rest status, conscious status etc. * does not alter the loss of memory. */ for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) if (spellknow(i)) decrnknow(i); return; } /* * Return TRUE if a spell was picked, with the spell index in the return * parameter. Otherwise return FALSE. */ STATIC_OVL boolean getspell(spell_no) int *spell_no; { int nspells, idx; char ilet, lets[BUFSZ], qbuf[QBUFSZ]; if (spellid(0) == NO_SPELL) { You("don't know any spells right now."); return FALSE; } if (flags.menu_style == MENU_TRADITIONAL) { /* we know there is at least 1 known spell */ for (nspells = 1; nspells < MAXSPELL && spellid(nspells) != NO_SPELL; nspells++) continue; if (nspells == 1) Strcpy(lets, "a"); else if (nspells < 27) Sprintf(lets, "a-%c", 'a' + nspells - 1); else if (nspells == 27) Sprintf(lets, "a-zA"); else Sprintf(lets, "a-zA-%c", 'A' + nspells - 27); for(;;) { Sprintf(qbuf, "Cast which spell? [%s ?]", lets); if ((ilet = yn_function(qbuf, (char *)0, '\0')) == '?') break; if (index(quitchars, ilet)) return FALSE; idx = spell_let_to_idx(ilet); if (idx >= 0 && idx < nspells) { *spell_no = idx; return TRUE; } else You("don't know that spell."); } } return dospellmenu("Choose which spell to cast", SPELLMENU_CAST, spell_no); } /* the 'Z' command -- cast a spell */ int docast() { int spell_no; if (getspell(&spell_no)) return spelleffects(spell_no, FALSE); return 0; } STATIC_OVL const char * spelltypemnemonic(skill) int skill; { switch (skill) { case P_ATTACK_SPELL: return "attack"; case P_HEALING_SPELL: return "healing"; case P_DIVINATION_SPELL: return "divination"; case P_ENCHANTMENT_SPELL: return "enchantment"; case P_CLERIC_SPELL: return "clerical"; case P_ESCAPE_SPELL: return "escape"; case P_MATTER_SPELL: return "matter"; default: impossible("Unknown spell skill, %d;", skill); return ""; } } int spell_skilltype(booktype) int booktype; { return (objects[booktype].oc_skill); } STATIC_OVL void cast_protection() { int loglev = 0; int l = u.ulevel; int natac = u.uac - u.uspellprot; int gain; /* loglev=log2(u.ulevel)+1 (1..5) */ while (l) { loglev++; l /= 2; } /* The more u.uspellprot you already have, the less you get, * and the better your natural ac, the less you get. * * LEVEL AC SPELLPROT from sucessive SPE_PROTECTION casts * 1 10 0, 1, 2, 3, 4 * 1 0 0, 1, 2, 3 * 1 -10 0, 1, 2 * 2-3 10 0, 2, 4, 5, 6, 7, 8 * 2-3 0 0, 2, 4, 5, 6 * 2-3 -10 0, 2, 3, 4 * 4-7 10 0, 3, 6, 8, 9, 10, 11, 12 * 4-7 0 0, 3, 5, 7, 8, 9 * 4-7 -10 0, 3, 5, 6 * 7-15 -10 0, 3, 5, 6 * 8-15 10 0, 4, 7, 10, 12, 13, 14, 15, 16 * 8-15 0 0, 4, 7, 9, 10, 11, 12 * 8-15 -10 0, 4, 6, 7, 8 * 16-30 10 0, 5, 9, 12, 14, 16, 17, 18, 19, 20 * 16-30 0 0, 5, 9, 11, 13, 14, 15 * 16-30 -10 0, 5, 8, 9, 10 */ gain = loglev - (int)u.uspellprot / (4 - min(3,(10 - natac)/10)); if (gain > 0) { if (!Blind) { const char *hgolden = hcolor(NH_GOLDEN); if (u.uspellprot) pline_The("%s haze around you becomes more dense.", hgolden); else pline_The("%s around you begins to shimmer with %s haze.", /*[ what about being inside solid rock while polyd? ]*/ (Underwater || Is_waterlevel(&u.uz)) ? "water" : "air", an(hgolden)); } u.uspellprot += gain; u.uspmtime = P_SKILL(spell_skilltype(SPE_PROTECTION)) == P_EXPERT ? 20 : 10; if (!u.usptime) u.usptime = u.uspmtime; find_ac(); } else { Your("skin feels warm for a moment."); } } /* attempting to cast a forgotten spell will cause disorientation */ STATIC_OVL void spell_backfire(spell) int spell; { long duration = (long)((spellev(spell) + 1) * 3); /* 6..24 */ /* prior to 3.4.1, the only effect was confusion; it still predominates */ switch (rn2(10)) { case 0: case 1: case 2: case 3: make_confused(duration, FALSE); /* 40% */ break; case 4: case 5: case 6: make_confused(2L * duration / 3L, FALSE); /* 30% */ make_stunned(duration / 3L, FALSE); break; case 7: case 8: make_stunned(2L * duration / 3L, FALSE); /* 20% */ make_confused(duration / 3L, FALSE); break; case 9: make_stunned(duration, FALSE); /* 10% */ break; } return; } int spelleffects(spell, atme) int spell; boolean atme; { int energy, damage, chance, n, intell; int skill, role_skill; boolean confused = (Confusion != 0); struct obj *pseudo; coord cc; /* * Spell casting no longer affects knowledge of the spell. A * decrement of spell knowledge is done every turn. */ if (spellknow(spell) <= 0) { Your("knowledge of this spell is twisted."); pline("It invokes nightmarish images in your mind..."); spell_backfire(spell); return(0); } else if (spellknow(spell) <= 100) { You("strain to recall the spell."); } else if (spellknow(spell) <= 1000) { Your("knowledge of this spell is growing faint."); } energy = (spellev(spell) * 5); /* 5 <= energy <= 35 */ if (u.uhunger <= 10 && spellid(spell) != SPE_DETECT_FOOD) { You("are too hungry to cast that spell."); return(0); } else if (ACURR(A_STR) < 4) { You("lack the strength to cast spells."); return(0); } else if(check_capacity( "Your concentration falters while carrying so much stuff.")) { return (1); } else if (!freehand()) { Your("arms are not free to cast!"); return (0); } if (u.uhave.amulet) { You_feel("the amulet draining your energy away."); energy += rnd(2*energy); } if(energy > u.uen) { You("don't have enough energy to cast that spell."); return(0); } else { if (spellid(spell) != SPE_DETECT_FOOD) { int hungr = energy * 2; /* If hero is a wizard, their current intelligence * (bonuses + temporary + current) * affects hunger reduction in casting a spell. * 1. int = 17-18 no reduction * 2. int = 16 1/4 hungr * 3. int = 15 1/2 hungr * 4. int = 1-14 normal reduction * The reason for this is: * a) Intelligence affects the amount of exertion * in thinking. * b) Wizards have spent their life at magic and * understand quite well how to cast spells. */ intell = acurr(A_INT); if (!Role_if(PM_WIZARD)) intell = 10; switch (intell) { case 25: case 24: case 23: case 22: case 21: case 20: case 19: case 18: case 17: hungr = 0; break; case 16: hungr /= 4; break; case 15: hungr /= 2; break; } /* don't put player (quite) into fainting from * casting a spell, particularly since they might * not even be hungry at the beginning; however, * this is low enough that they must eat before * casting anything else except detect food */ if (hungr > u.uhunger-3) hungr = u.uhunger-3; morehungry(hungr); } } chance = percent_success(spell); if (confused || (rnd(100) > chance)) { You("fail to cast the spell correctly."); u.uen -= energy / 2; flags.botl = 1; return(1); } u.uen -= energy; flags.botl = 1; exercise(A_WIS, TRUE); /* pseudo is a temporary "false" object containing the spell stats */ pseudo = mksobj(spellid(spell), FALSE, FALSE); pseudo->blessed = pseudo->cursed = 0; pseudo->quan = 20L; /* do not let useup get it */ /* * Find the skill the hero has in a spell type category. * See spell_skilltype for categories. */ skill = spell_skilltype(pseudo->otyp); role_skill = P_SKILL(skill); switch(pseudo->otyp) { /* * At first spells act as expected. As the hero increases in skill * with the appropriate spell type, some spells increase in their * effects, e.g. more damage, further distance, and so on, without * additional cost to the spellcaster. */ case SPE_CONE_OF_COLD: case SPE_FIREBALL: if (role_skill >= P_SKILLED) { if (throwspell()) { cc.x=u.dx;cc.y=u.dy; n=rnd(8)+1; while(n--) { if(!u.dx && !u.dy && !u.dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "zapped %sself with a spell", uhim()); losehp(damage, buf, NO_KILLER_PREFIX); } } else { explode(u.dx, u.dy, pseudo->otyp - SPE_MAGIC_MISSILE + 10, u.ulevel/2 + 1 + spell_damage_bonus(), 0, (pseudo->otyp == SPE_CONE_OF_COLD) ? EXPL_FROSTY : EXPL_FIERY); } u.dx = cc.x+rnd(3)-2; u.dy = cc.y+rnd(3)-2; if (!isok(u.dx,u.dy) || !cansee(u.dx,u.dy) || IS_STWALL(levl[u.dx][u.dy].typ) || u.uswallow) { /* Spell is reflected back to center */ u.dx = cc.x; u.dy = cc.y; } } } break; } /* else fall through... */ /* these spells are all duplicates of wand effects */ case SPE_FORCE_BOLT: case SPE_SLEEP: case SPE_MAGIC_MISSILE: case SPE_KNOCK: case SPE_SLOW_MONSTER: case SPE_WIZARD_LOCK: case SPE_DIG: case SPE_TURN_UNDEAD: case SPE_POLYMORPH: case SPE_TELEPORT_AWAY: case SPE_CANCELLATION: case SPE_FINGER_OF_DEATH: case SPE_LIGHT: case SPE_DETECT_UNSEEN: case SPE_HEALING: case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case SPE_STONE_TO_FLESH: if (!(objects[pseudo->otyp].oc_dir == NODIR)) { if (atme) u.dx = u.dy = u.dz = 0; else if (!getdir((char *)0)) { /* getdir cancelled, re-use previous direction */ pline_The("magical energy is released!"); } if(!u.dx && !u.dy && !u.dz) { if ((damage = zapyourself(pseudo, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "zapped %sself with a spell", uhim()); losehp(damage, buf, NO_KILLER_PREFIX); } } else weffects(pseudo); } else weffects(pseudo); update_inventory(); /* spell may modify inventory */ break; /* these are all duplicates of scroll effects */ case SPE_REMOVE_CURSE: case SPE_CONFUSE_MONSTER: case SPE_DETECT_FOOD: case SPE_CAUSE_FEAR: /* high skill yields effect equivalent to blessed scroll */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; /* fall through */ case SPE_CHARM_MONSTER: case SPE_MAGIC_MAPPING: case SPE_CREATE_MONSTER: case SPE_IDENTIFY: (void) seffects(pseudo); break; /* these are all duplicates of potion effects */ case SPE_HASTE_SELF: case SPE_DETECT_TREASURE: case SPE_DETECT_MONSTERS: case SPE_LEVITATION: case SPE_RESTORE_ABILITY: /* high skill yields effect equivalent to blessed potion */ if (role_skill >= P_SKILLED) pseudo->blessed = 1; /* fall through */ case SPE_INVISIBILITY: (void) peffects(pseudo); break; case SPE_CURE_BLINDNESS: healup(0, 0, FALSE, TRUE); break; case SPE_CURE_SICKNESS: if (Sick) You("are no longer ill."); if (Slimed) { pline_The("slime disappears!"); Slimed = 0; /* flags.botl = 1; -- healup() handles this */ } healup(0, 0, TRUE, FALSE); break; case SPE_CREATE_FAMILIAR: (void) make_familiar((struct obj *)0, u.ux, u.uy, FALSE); break; case SPE_CLAIRVOYANCE: if (!BClairvoyant) do_vicinity_map(); /* at present, only one thing blocks clairvoyance */ else if (uarmh && uarmh->otyp == CORNUTHAUM) You("sense a pointy hat on top of your %s.", body_part(HEAD)); break; case SPE_PROTECTION: cast_protection(); break; case SPE_JUMPING: if (!jump(max(role_skill,1))) pline(nothing_happens); break; default: impossible("Unknown spell %d attempted.", spell); obfree(pseudo, (struct obj *)0); return(0); } /* gain skill for successful cast */ use_skill(skill, spellev(spell)); obfree(pseudo, (struct obj *)0); /* now, get rid of it */ return(1); } /* Choose location where spell takes effect. */ STATIC_OVL int throwspell() { coord cc; if (u.uinwater) { pline("You're joking! In this weather?"); return 0; } else if (Is_waterlevel(&u.uz)) { You("had better wait for the sun to come out."); return 0; } pline("Where do you want to cast the spell?"); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the desired position") < 0) return 0; /* user pressed ESC */ /* The number of moves from hero to where the spell drops.*/ if (distmin(u.ux, u.uy, cc.x, cc.y) > 10) { pline_The("spell dissipates over the distance!"); return 0; } else if (u.uswallow) { pline_The("spell is cut short!"); exercise(A_WIS, FALSE); /* What were you THINKING! */ u.dx = 0; u.dy = 0; return 1; } else if (!cansee(cc.x, cc.y) || IS_STWALL(levl[cc.x][cc.y].typ)) { Your("mind fails to lock onto that location!"); return 0; } else { u.dx=cc.x; u.dy=cc.y; return 1; } } void losespells() { boolean confused = (Confusion != 0); int n, nzap, i; book = 0; for (n = 0; n < MAXSPELL && spellid(n) != NO_SPELL; n++) continue; if (n) { nzap = rnd(n) + confused ? 1 : 0; if (nzap > n) nzap = n; for (i = n - nzap; i < n; i++) { spellid(i) = NO_SPELL; exercise(A_WIS, FALSE); /* ouch! */ } } } /* the '+' command -- view known spells */ int dovspell() { char qbuf[QBUFSZ]; int splnum, othnum; struct spell spl_tmp; if (spellid(0) == NO_SPELL) You("don't know any spells right now."); else { while (dospellmenu("Currently known spells", SPELLMENU_VIEW, &splnum)) { Sprintf(qbuf, "Reordering spells; swap '%c' with", spellet(splnum)); if (!dospellmenu(qbuf, splnum, &othnum)) break; spl_tmp = spl_book[splnum]; spl_book[splnum] = spl_book[othnum]; spl_book[othnum] = spl_tmp; } } return 0; } STATIC_OVL boolean dospellmenu(prompt, splaction, spell_no) const char *prompt; int splaction; /* SPELLMENU_CAST, SPELLMENU_VIEW, or spl_book[] index */ int *spell_no; { winid tmpwin; int i, n, how; char buf[BUFSZ]; menu_item *selected; anything any; tmpwin = create_nhwindow(NHW_MENU); start_menu(tmpwin); any.a_void = 0; /* zero out all bits */ /* * The correct spacing of the columns depends on the * following that (1) the font is monospaced and (2) * that selection letters are pre-pended to the given * string and are of the form "a - ". * * To do it right would require that we implement columns * in the window-ports (say via a tab character). */ if (!iflags.menu_tab_sep) Sprintf(buf, "%-20s Level %-12s Fail", " Name", "Category"); else Sprintf(buf, "Name\tLevel\tCategory\tFail"); add_menu(tmpwin, NO_GLYPH, &any, 0, 0, ATR_BOLD, buf, MENU_UNSELECTED); for (i = 0; i < MAXSPELL && spellid(i) != NO_SPELL; i++) { Sprintf(buf, iflags.menu_tab_sep ? "%s\t%-d%s\t%s\t%-d%%" : "%-20s %2d%s %-12s %3d%%", spellname(i), spellev(i), spellknow(i) ? " " : "*", spelltypemnemonic(spell_skilltype(spellid(i))), 100 - percent_success(i)); any.a_int = i+1; /* must be non-zero */ add_menu(tmpwin, NO_GLYPH, &any, spellet(i), 0, ATR_NONE, buf, (i == splaction) ? MENU_SELECTED : MENU_UNSELECTED); } end_menu(tmpwin, prompt); how = PICK_ONE; if (splaction == SPELLMENU_VIEW && spellid(1) == NO_SPELL) how = PICK_NONE; /* only one spell => nothing to swap with */ n = select_menu(tmpwin, how, &selected); destroy_nhwindow(tmpwin); if (n > 0) { *spell_no = selected[0].item.a_int - 1; /* menu selection for `PICK_ONE' does not de-select any preselected entry */ if (n > 1 && *spell_no == splaction) *spell_no = selected[1].item.a_int - 1; free((genericptr_t)selected); /* default selection of preselected spell means that user chose not to swap it with anything */ if (*spell_no == splaction) return FALSE; return TRUE; } else if (splaction >= 0) { /* explicit de-selection of preselected spell means that user is still swapping but not for the current spell */ *spell_no = splaction; return TRUE; } return FALSE; } /* Integer square root function without using floating point. */ STATIC_OVL int isqrt(val) int val; { int rt = 0; int odd = 1; while(val >= odd) { val = val-odd; odd = odd+2; rt = rt + 1; } return rt; } STATIC_OVL int percent_success(spell) int spell; { /* Intrinsic and learned ability are combined to calculate * the probability of player's success at cast a given spell. */ int chance, splcaster, special, statused; int difficulty; int skill; /* Calculate intrinsic ability (splcaster) */ splcaster = urole.spelbase; special = urole.spelheal; statused = ACURR(urole.spelstat); if (uarm && is_metallic(uarm)) splcaster += (uarmc && uarmc->otyp == ROBE) ? urole.spelarmr/2 : urole.spelarmr; else if (uarmc && uarmc->otyp == ROBE) splcaster -= urole.spelarmr; if (uarms) splcaster += urole.spelshld; if (uarmh && is_metallic(uarmh) && uarmh->otyp != HELM_OF_BRILLIANCE) splcaster += uarmhbon; if (uarmg && is_metallic(uarmg)) splcaster += uarmgbon; if (uarmf && is_metallic(uarmf)) splcaster += uarmfbon; if (spellid(spell) == urole.spelspec) splcaster += urole.spelsbon; /* `healing spell' bonus */ if (spellid(spell) == SPE_HEALING || spellid(spell) == SPE_EXTRA_HEALING || spellid(spell) == SPE_CURE_BLINDNESS || spellid(spell) == SPE_CURE_SICKNESS || spellid(spell) == SPE_RESTORE_ABILITY || spellid(spell) == SPE_REMOVE_CURSE) splcaster += special; if (splcaster > 20) splcaster = 20; /* Calculate learned ability */ /* Players basic likelihood of being able to cast any spell * is based of their `magic' statistic. (Int or Wis) */ chance = 11 * statused / 2; /* * High level spells are harder. Easier for higher level casters. * The difficulty is based on the hero's level and their skill level * in that spell type. */ skill = P_SKILL(spell_skilltype(spellid(spell))); skill = max(skill,P_UNSKILLED) - 1; /* unskilled => 0 */ difficulty= (spellev(spell)-1) * 4 - ((skill * 6) + (u.ulevel/3) + 1); if (difficulty > 0) { /* Player is too low level or unskilled. */ chance -= isqrt(900 * difficulty + 2000); } else { /* Player is above level. Learning continues, but the * law of diminishing returns sets in quickly for * low-level spells. That is, a player quickly gains * no advantage for raising level. */ int learning = 15 * -difficulty / spellev(spell); chance += learning > 20 ? 20 : learning; } /* Clamp the chance: >18 stat and advanced learning only help * to a limit, while chances below "hopeless" only raise the * specter of overflowing 16-bit ints (and permit wearing a * shield to raise the chances :-). */ if (chance < 0) chance = 0; if (chance > 120) chance = 120; /* Wearing anything but a light shield makes it very awkward * to cast a spell. The penalty is not quite so bad for the * player's role-specific spell. */ if (uarms && weight(uarms) > (int) objects[SMALL_SHIELD].oc_weight) { if (spellid(spell) == urole.spelspec) { chance /= 2; } else { chance /= 4; } } /* Finally, chance (based on player intell/wisdom and level) is * combined with ability (based on player intrinsics and * encumbrances). No matter how intelligent/wise and advanced * a player is, intrinsics and encumbrance can prevent casting; * and no matter how able, learning is always required. */ chance = chance * (20-splcaster) / 15 - splcaster; /* Clamp to percentile */ if (chance > 100) chance = 100; if (chance < 0) chance = 0; return chance; } /* Learn a spell during creation of the initial inventory */ void initialspell(obj) struct obj *obj; { int i; for (i = 0; i < MAXSPELL; i++) { if (spellid(i) == obj->otyp) { pline("Error: Spell %s already known.", OBJ_NAME(objects[obj->otyp])); return; } if (spellid(i) == NO_SPELL) { spl_book[i].sp_id = obj->otyp; spl_book[i].sp_lev = objects[obj->otyp].oc_level; incrnknow(i); return; } } impossible("Too many spells memorized!"); return; } /*spell.c*/ nethack-3.4.3/src/steal.c0100644000000000000000000004365607764735041013733 0ustar rootroot/* SCCS Id: @(#)steal.c 3.4 2003/12/04 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_PTR int NDECL(stealarm); #ifdef OVLB STATIC_DCL const char *FDECL(equipname, (struct obj *)); STATIC_DCL void FDECL(mdrop_obj, (struct monst *,struct obj *,BOOLEAN_P)); STATIC_OVL const char * equipname(otmp) register struct obj *otmp; { return ( #ifdef TOURIST (otmp == uarmu) ? "shirt" : #endif (otmp == uarmf) ? "boots" : (otmp == uarms) ? "shield" : (otmp == uarmg) ? "gloves" : (otmp == uarmc) ? cloak_simple_name(otmp) : (otmp == uarmh) ? "helmet" : "armor"); } #ifndef GOLDOBJ long /* actually returns something that fits in an int */ somegold() { #ifdef LINT /* long conv. ok */ return(0L); #else return (long)( (u.ugold < 100) ? u.ugold : (u.ugold > 10000) ? rnd(10000) : rnd((int) u.ugold) ); #endif } void stealgold(mtmp) register struct monst *mtmp; { register struct obj *gold = g_at(u.ux, u.uy); register long tmp; if (gold && ( !u.ugold || gold->quan > u.ugold || !rn2(5))) { mtmp->mgold += gold->quan; delobj(gold); newsym(u.ux, u.uy); pline("%s quickly snatches some gold from between your %s!", Monnam(mtmp), makeplural(body_part(FOOT))); if(!u.ugold || !rn2(5)) { if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); /* do not set mtmp->mavenge here; gold on the floor is fair game */ monflee(mtmp, 0, FALSE, FALSE); } } else if(u.ugold) { u.ugold -= (tmp = somegold()); Your("purse feels lighter."); mtmp->mgold += tmp; if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); mtmp->mavenge = 1; monflee(mtmp, 0, FALSE, FALSE); flags.botl = 1; } } #else /* !GOLDOBJ */ long /* actually returns something that fits in an int */ somegold(umoney) long umoney; { #ifdef LINT /* long conv. ok */ return(0L); #else return (long)( (umoney < 100) ? umoney : (umoney > 10000) ? rnd(10000) : rnd((int) umoney) ); #endif } /* Find the first (and hopefully only) gold object in a chain. Used when leprechaun (or you as leprechaun) looks for someone else's gold. Returns a pointer so the gold may be seized without further searching. May search containers too. Deals in gold only, as leprechauns don't care for lesser coins. */ struct obj * findgold(chain) register struct obj *chain; { while (chain && chain->otyp != GOLD_PIECE) chain = chain->nobj; return chain; } /* Steal gold coins only. Leprechauns don't care for lesser coins. */ void stealgold(mtmp) register struct monst *mtmp; { register struct obj *fgold = g_at(u.ux, u.uy); register struct obj *ygold; register long tmp; /* skip lesser coins on the floor */ while (fgold && fgold->otyp != GOLD_PIECE) fgold = fgold->nexthere; /* Do you have real gold? */ ygold = findgold(invent); if (fgold && ( !ygold || fgold->quan > ygold->quan || !rn2(5))) { obj_extract_self(fgold); add_to_minv(mtmp, fgold); newsym(u.ux, u.uy); pline("%s quickly snatches some gold from between your %s!", Monnam(mtmp), makeplural(body_part(FOOT))); if(!ygold || !rn2(5)) { if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); monflee(mtmp, 0, FALSE, FALSE); } } else if(ygold) { const int gold_price = objects[GOLD_PIECE].oc_cost; tmp = (somegold(money_cnt(invent)) + gold_price - 1) / gold_price; tmp = min(tmp, ygold->quan); if (tmp < ygold->quan) ygold = splitobj(ygold, tmp); freeinv(ygold); add_to_minv(mtmp, ygold); Your("purse feels lighter."); if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); monflee(mtmp, 0, FALSE, FALSE); flags.botl = 1; } } #endif /* GOLDOBJ */ /* steal armor after you finish taking it off */ unsigned int stealoid; /* object to be stolen */ unsigned int stealmid; /* monster doing the stealing */ STATIC_PTR int stealarm() { register struct monst *mtmp; register struct obj *otmp; for(otmp = invent; otmp; otmp = otmp->nobj) { if(otmp->o_id == stealoid) { for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if(mtmp->m_id == stealmid) { if(DEADMONSTER(mtmp)) impossible("stealarm(): dead monster stealing"); if(!dmgtype(mtmp->data, AD_SITM)) /* polymorphed */ goto botm; if(otmp->unpaid) subfrombill(otmp, shop_keeper(*u.ushops)); freeinv(otmp); pline("%s steals %s!", Monnam(mtmp), doname(otmp)); (void) mpickobj(mtmp,otmp); /* may free otmp */ /* Implies seduction, "you gladly hand over ..." so we don't set mavenge bit here. */ monflee(mtmp, 0, FALSE, FALSE); if (!tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); break; } } break; } } botm: stealoid = 0; return 0; } /* An object you're wearing has been taken off by a monster (theft or seduction). Also used if a worn item gets transformed (stone to flesh). */ void remove_worn_item(obj, unchain_ball) struct obj *obj; boolean unchain_ball; /* whether to unpunish or just unwield */ { if (donning(obj)) cancel_don(); if (!obj->owornmask) return; if (obj->owornmask & W_ARMOR) { if (obj == uskin) { impossible("Removing embedded scales?"); skinback(TRUE); /* uarm = uskin; uskin = 0; */ } if (obj == uarm) (void) Armor_off(); else if (obj == uarmc) (void) Cloak_off(); else if (obj == uarmf) (void) Boots_off(); else if (obj == uarmg) (void) Gloves_off(); else if (obj == uarmh) (void) Helmet_off(); else if (obj == uarms) (void) Shield_off(); #ifdef TOURIST else if (obj == uarmu) (void) Shirt_off(); #endif /* catchall -- should never happen */ else setworn((struct obj *)0, obj->owornmask & W_ARMOR); } else if (obj->owornmask & W_AMUL) { Amulet_off(); } else if (obj->owornmask & W_RING) { Ring_gone(obj); } else if (obj->owornmask & W_TOOL) { Blindf_off(obj); } else if (obj->owornmask & (W_WEP|W_SWAPWEP|W_QUIVER)) { if (obj == uwep) uwepgone(); if (obj == uswapwep) uswapwepgone(); if (obj == uquiver) uqwepgone(); } if (obj->owornmask & (W_BALL|W_CHAIN)) { if (unchain_ball) unpunish(); } else if (obj->owornmask) { /* catchall */ setnotworn(obj); } } /* Returns 1 when something was stolen (or at least, when N should flee now) * Returns -1 if the monster died in the attempt * Avoid stealing the object stealoid */ int steal(mtmp, objnambuf) struct monst *mtmp; char *objnambuf; { struct obj *otmp; int tmp, could_petrify, named = 0, armordelay; boolean monkey_business; /* true iff an animal is doing the thievery */ if (objnambuf) *objnambuf = '\0'; /* the following is true if successful on first of two attacks. */ if(!monnear(mtmp, u.ux, u.uy)) return(0); /* food being eaten might already be used up but will not have been removed from inventory yet; we don't want to steal that, so this will cause it to be removed now */ if (occupation) (void) maybe_finished_meal(FALSE); if (!invent || (inv_cnt() == 1 && uskin)) { nothing_to_steal: /* Not even a thousand men in armor can strip a naked man. */ if(Blind) pline("Somebody tries to rob you, but finds nothing to steal."); else pline("%s tries to rob you, but there is nothing to steal!", Monnam(mtmp)); return(1); /* let her flee */ } monkey_business = is_animal(mtmp->data); if (monkey_business) { ; /* skip ring special cases */ } else if (Adornment & LEFT_RING) { otmp = uleft; goto gotobj; } else if (Adornment & RIGHT_RING) { otmp = uright; goto gotobj; } tmp = 0; for(otmp = invent; otmp; otmp = otmp->nobj) if ((!uarm || otmp != uarmc) && otmp != uskin #ifdef INVISIBLE_OBJECTS && (!otmp->oinvis || perceives(mtmp->data)) #endif ) tmp += ((otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1); if (!tmp) goto nothing_to_steal; tmp = rn2(tmp); for(otmp = invent; otmp; otmp = otmp->nobj) if ((!uarm || otmp != uarmc) && otmp != uskin #ifdef INVISIBLE_OBJECTS && (!otmp->oinvis || perceives(mtmp->data)) #endif ) if((tmp -= ((otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL)) ? 5 : 1)) < 0) break; if(!otmp) { impossible("Steal fails!"); return(0); } /* can't steal gloves while wielding - so steal the wielded item. */ if (otmp == uarmg && uwep) otmp = uwep; /* can't steal armor while wearing cloak - so steal the cloak. */ else if(otmp == uarm && uarmc) otmp = uarmc; #ifdef TOURIST else if(otmp == uarmu && uarmc) otmp = uarmc; else if(otmp == uarmu && uarm) otmp = uarm; #endif gotobj: if(otmp->o_id == stealoid) return(0); /* animals can't overcome curse stickiness nor unlock chains */ if (monkey_business) { boolean ostuck; /* is the player prevented from voluntarily giving up this item? (ignores loadstones; the !can_carry() check will catch those) */ if (otmp == uball) ostuck = TRUE; /* effectively worn; curse is implicit */ else if (otmp == uquiver || (otmp == uswapwep && !u.twoweap)) ostuck = FALSE; /* not really worn; curse doesn't matter */ else ostuck = (otmp->cursed && otmp->owornmask); if (ostuck || !can_carry(mtmp, otmp)) { static const char * const how[] = { "steal","snatch","grab","take" }; cant_take: pline("%s tries to %s your %s but gives up.", Monnam(mtmp), how[rn2(SIZE(how))], (otmp->owornmask & W_ARMOR) ? equipname(otmp) : cxname(otmp)); /* the fewer items you have, the less likely the thief is going to stick around to try again (0) instead of running away (1) */ return !rn2(inv_cnt() / 5 + 2); } } if (otmp->otyp == LEASH && otmp->leashmon) { if (monkey_business && otmp->cursed) goto cant_take; o_unleash(otmp); } /* you're going to notice the theft... */ stop_occupation(); if((otmp->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL))){ switch(otmp->oclass) { case TOOL_CLASS: case AMULET_CLASS: case RING_CLASS: case FOOD_CLASS: /* meat ring */ remove_worn_item(otmp, TRUE); break; case ARMOR_CLASS: armordelay = objects[otmp->otyp].oc_delay; /* Stop putting on armor which has been stolen. */ if (donning(otmp)) { remove_worn_item(otmp, TRUE); break; } else if (monkey_business) { /* animals usually don't have enough patience to take off items which require extra time */ if (armordelay >= 1 && rn2(10)) goto cant_take; remove_worn_item(otmp, TRUE); break; } else { int curssv = otmp->cursed; int slowly; boolean seen = canspotmon(mtmp); otmp->cursed = 0; /* can't charm you without first waking you */ if (multi < 0 && is_fainted()) unmul((char *)0); slowly = (armordelay >= 1 || multi < 0); if(flags.female) pline("%s charms you. You gladly %s your %s.", !seen ? "She" : Monnam(mtmp), curssv ? "let her take" : slowly ? "start removing" : "hand over", equipname(otmp)); else pline("%s seduces you and %s off your %s.", !seen ? "She" : Adjmonnam(mtmp, "beautiful"), curssv ? "helps you to take" : slowly ? "you start taking" : "you take", equipname(otmp)); named++; /* the following is to set multi for later on */ nomul(-armordelay); remove_worn_item(otmp, TRUE); otmp->cursed = curssv; if(multi < 0){ /* multi = 0; nomovemsg = 0; afternmv = 0; */ stealoid = otmp->o_id; stealmid = mtmp->m_id; afternmv = stealarm; return(0); } } break; default: impossible("Tried to steal a strange worn thing. [%d]", otmp->oclass); } } else if (otmp->owornmask) remove_worn_item(otmp, TRUE); /* do this before removing it from inventory */ if (objnambuf) Strcpy(objnambuf, yname(otmp)); /* set mavenge bit so knights won't suffer an * alignment penalty during retaliation; */ mtmp->mavenge = 1; freeinv(otmp); pline("%s stole %s.", named ? "She" : Monnam(mtmp), doname(otmp)); could_petrify = (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm])); (void) mpickobj(mtmp,otmp); /* may free otmp */ if (could_petrify && !(mtmp->misc_worn_check & W_ARMG)) { minstapetrify(mtmp, TRUE); return -1; } return((multi < 0) ? 0 : 1); } #endif /* OVLB */ #ifdef OVL1 /* Returns 1 if otmp is free'd, 0 otherwise. */ int mpickobj(mtmp,otmp) register struct monst *mtmp; register struct obj *otmp; { int freed_otmp; #ifndef GOLDOBJ if (otmp->oclass == COIN_CLASS) { mtmp->mgold += otmp->quan; obfree(otmp, (struct obj *)0); freed_otmp = 1; } else { #endif boolean snuff_otmp = FALSE; /* don't want hidden light source inside the monster; assumes that engulfers won't have external inventories; whirly monsters cause the light to be extinguished rather than letting it shine thru */ if (otmp->lamplit && /* hack to avoid function calls for most objs */ obj_sheds_light(otmp) && attacktype(mtmp->data, AT_ENGL)) { /* this is probably a burning object that you dropped or threw */ if (u.uswallow && mtmp == u.ustuck && !Blind) pline("%s out.", Tobjnam(otmp, "go")); snuff_otmp = TRUE; } /* Must do carrying effects on object prior to add_to_minv() */ carry_obj_effects(otmp); /* add_to_minv() might free otmp [if merged with something else], so we have to call it after doing the object checks */ freed_otmp = add_to_minv(mtmp, otmp); /* and we had to defer this until object is in mtmp's inventory */ if (snuff_otmp) snuff_light_source(mtmp->mx, mtmp->my); #ifndef GOLDOBJ } #endif return freed_otmp; } #endif /* OVL1 */ #ifdef OVLB void stealamulet(mtmp) struct monst *mtmp; { struct obj *otmp = (struct obj *)0; int real=0, fake=0; /* select the artifact to steal */ if(u.uhave.amulet) { real = AMULET_OF_YENDOR; fake = FAKE_AMULET_OF_YENDOR; } else if(u.uhave.questart) { for(otmp = invent; otmp; otmp = otmp->nobj) if(is_quest_artifact(otmp)) break; if (!otmp) return; /* should we panic instead? */ } else if(u.uhave.bell) { real = BELL_OF_OPENING; fake = BELL; } else if(u.uhave.book) { real = SPE_BOOK_OF_THE_DEAD; } else if(u.uhave.menorah) { real = CANDELABRUM_OF_INVOCATION; } else return; /* you have nothing of special interest */ if (!otmp) { /* If we get here, real and fake have been set up. */ for(otmp = invent; otmp; otmp = otmp->nobj) if(otmp->otyp == real || (otmp->otyp == fake && !mtmp->iswiz)) break; } if (otmp) { /* we have something to snatch */ if (otmp->owornmask) remove_worn_item(otmp, TRUE); freeinv(otmp); /* mpickobj wont merge otmp because none of the above things to steal are mergable */ (void) mpickobj(mtmp,otmp); /* may merge and free otmp */ pline("%s stole %s!", Monnam(mtmp), doname(otmp)); if (can_teleport(mtmp->data) && !tele_restrict(mtmp)) (void) rloc(mtmp, FALSE); } } #endif /* OVLB */ #ifdef OVL0 /* drop one object taken from a (possibly dead) monster's inventory */ STATIC_OVL void mdrop_obj(mon, obj, verbosely) struct monst *mon; struct obj *obj; boolean verbosely; { int omx = mon->mx, omy = mon->my; if (obj->owornmask) { /* perform worn item handling if the monster is still alive */ if (mon->mhp > 0) { mon->misc_worn_check &= ~obj->owornmask; update_mon_intrinsics(mon, obj, FALSE, TRUE); /* obj_no_longer_held(obj); -- done by place_object */ if (obj->owornmask & W_WEP) setmnotwielded(mon, obj); #ifdef STEED /* don't charge for an owned saddle on dead steed */ } else if (mon->mtame && (obj->owornmask & W_SADDLE) && !obj->unpaid && costly_spot(omx, omy)) { obj->no_charge = 1; #endif } obj->owornmask = 0L; } if (verbosely && cansee(omx, omy)) pline("%s drops %s.", Monnam(mon), distant_name(obj, doname)); if (!flooreffects(obj, omx, omy, "fall")) { place_object(obj, omx, omy); stackobj(obj); } } /* some monsters bypass the normal rules for moving between levels or even leaving the game entirely; when that happens, prevent them from taking the Amulet or invocation tools with them */ void mdrop_special_objs(mon) struct monst *mon; { struct obj *obj, *otmp; for (obj = mon->minvent; obj; obj = otmp) { otmp = obj->nobj; /* the Amulet, invocation tools, and Rider corpses resist even when artifacts and ordinary objects are given 0% resistance chance */ if (obj_resists(obj, 0, 0)) { obj_extract_self(obj); mdrop_obj(mon, obj, FALSE); } } } /* release the objects the creature is carrying */ void relobj(mtmp,show,is_pet) register struct monst *mtmp; register int show; boolean is_pet; /* If true, pet should keep wielded/worn items */ { register struct obj *otmp; register int omx = mtmp->mx, omy = mtmp->my; struct obj *keepobj = 0; struct obj *wep = MON_WEP(mtmp); boolean item1 = FALSE, item2 = FALSE; if (!is_pet || mindless(mtmp->data) || is_animal(mtmp->data)) item1 = item2 = TRUE; if (!tunnels(mtmp->data) || !needspick(mtmp->data)) item1 = TRUE; while ((otmp = mtmp->minvent) != 0) { obj_extract_self(otmp); /* special case: pick-axe and unicorn horn are non-worn */ /* items that we also want pets to keep 1 of */ /* (It is a coincidence that these can also be wielded.) */ if (otmp->owornmask || otmp == wep || ((!item1 && otmp->otyp == PICK_AXE) || (!item2 && otmp->otyp == UNICORN_HORN && !otmp->cursed))) { if (is_pet) { /* dont drop worn/wielded item */ if (otmp->otyp == PICK_AXE) item1 = TRUE; if (otmp->otyp == UNICORN_HORN && !otmp->cursed) item2 = TRUE; otmp->nobj = keepobj; keepobj = otmp; continue; } } mdrop_obj(mtmp, otmp, is_pet && flags.verbose); } /* put kept objects back */ while ((otmp = keepobj) != (struct obj *)0) { keepobj = otmp->nobj; (void) add_to_minv(mtmp, otmp); } #ifndef GOLDOBJ if (mtmp->mgold) { register long g = mtmp->mgold; (void) mkgold(g, omx, omy); if (is_pet && cansee(omx, omy) && flags.verbose) pline("%s drops %ld gold piece%s.", Monnam(mtmp), g, plur(g)); mtmp->mgold = 0L; } #endif if (show & cansee(omx, omy)) newsym(omx, omy); } #endif /* OVL0 */ /*steal.c*/ nethack-3.4.3/src/steed.c0100644000000000000000000004276607764735041013730 0ustar rootroot/* SCCS Id: @(#)steed.c 3.4 2003/01/10 */ /* Copyright (c) Kevin Hugo, 1998-1999. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef STEED /* Monsters that might be ridden */ static NEARDATA const char steeds[] = { S_QUADRUPED, S_UNICORN, S_ANGEL, S_CENTAUR, S_DRAGON, S_JABBERWOCK, '\0' }; STATIC_DCL boolean FDECL(landing_spot, (coord *, int, int)); /* caller has decided that hero can't reach something while mounted */ void rider_cant_reach() { You("aren't skilled enough to reach from %s.", y_monnam(u.usteed)); } /*** Putting the saddle on ***/ /* Can this monster wear a saddle? */ boolean can_saddle(mtmp) struct monst *mtmp; { struct permonst *ptr = mtmp->data; return (index(steeds, ptr->mlet) && (ptr->msize >= MZ_MEDIUM) && (!humanoid(ptr) || ptr->mlet == S_CENTAUR) && !amorphous(ptr) && !noncorporeal(ptr) && !is_whirly(ptr) && !unsolid(ptr)); } int use_saddle(otmp) struct obj *otmp; { struct monst *mtmp; struct permonst *ptr; int chance; const char *s; /* Can you use it? */ if (nohands(youmonst.data)) { You("have no hands!"); /* not `body_part(HAND)' */ return 0; } else if (!freehand()) { You("have no free %s.", body_part(HAND)); return 0; } /* Select an animal */ if (u.uswallow || Underwater || !getdir((char *)0)) { pline(Never_mind); return 0; } if (!u.dx && !u.dy) { pline("Saddle yourself? Very funny..."); return 0; } if (!isok(u.ux+u.dx, u.uy+u.dy) || !(mtmp = m_at(u.ux+u.dx, u.uy+u.dy)) || !canspotmon(mtmp)) { pline("I see nobody there."); return 1; } /* Is this a valid monster? */ if (mtmp->misc_worn_check & W_SADDLE || which_armor(mtmp, W_SADDLE)) { pline("%s doesn't need another one.", Monnam(mtmp)); return 1; } ptr = mtmp->data; if (touch_petrifies(ptr) && !uarmg && !Stone_resistance) { char kbuf[BUFSZ]; You("touch %s.", mon_nam(mtmp)); if (!(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { Sprintf(kbuf, "attempting to saddle %s", an(mtmp->data->mname)); instapetrify(kbuf); } } if (ptr == &mons[PM_INCUBUS] || ptr == &mons[PM_SUCCUBUS]) { pline("Shame on you!"); exercise(A_WIS, FALSE); return 1; } if (mtmp->isminion || mtmp->isshk || mtmp->ispriest || mtmp->isgd || mtmp->iswiz) { pline("I think %s would mind.", mon_nam(mtmp)); return 1; } if (!can_saddle(mtmp)) { You_cant("saddle such a creature."); return 1; } /* Calculate your chance */ chance = ACURR(A_DEX) + ACURR(A_CHA)/2 + 2*mtmp->mtame; chance += u.ulevel * (mtmp->mtame ? 20 : 5); if (!mtmp->mtame) chance -= 10*mtmp->m_lev; if (Role_if(PM_KNIGHT)) chance += 20; switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: default: chance -= 20; break; case P_BASIC: break; case P_SKILLED: chance += 15; break; case P_EXPERT: chance += 30; break; } if (Confusion || Fumbling || Glib) chance -= 20; else if (uarmg && (s = OBJ_DESCR(objects[uarmg->otyp])) != (char *)0 && !strncmp(s, "riding ", 7)) /* Bonus for wearing "riding" (but not fumbling) gloves */ chance += 10; else if (uarmf && (s = OBJ_DESCR(objects[uarmf->otyp])) != (char *)0 && !strncmp(s, "riding ", 7)) /* ... or for "riding boots" */ chance += 10; if (otmp->cursed) chance -= 50; /* Make the attempt */ if (rn2(100) < chance) { You("put the saddle on %s.", mon_nam(mtmp)); if (otmp->owornmask) remove_worn_item(otmp, FALSE); freeinv(otmp); /* mpickobj may free otmp it if merges, but we have already checked for a saddle above, so no merger should happen */ (void) mpickobj(mtmp, otmp); mtmp->misc_worn_check |= W_SADDLE; otmp->owornmask = W_SADDLE; otmp->leashmon = mtmp->m_id; update_mon_intrinsics(mtmp, otmp, TRUE, FALSE); } else pline("%s resists!", Monnam(mtmp)); return 1; } /*** Riding the monster ***/ /* Can we ride this monster? Caller should also check can_saddle() */ boolean can_ride(mtmp) struct monst *mtmp; { return (mtmp->mtame && humanoid(youmonst.data) && !verysmall(youmonst.data) && !bigmonst(youmonst.data) && (!Underwater || is_swimmer(mtmp->data))); } int doride() { boolean forcemount = FALSE; if (u.usteed) dismount_steed(DISMOUNT_BYCHOICE); else if (getdir((char *)0) && isok(u.ux+u.dx, u.uy+u.dy)) { #ifdef WIZARD if (wizard && yn("Force the mount to succeed?") == 'y') forcemount = TRUE; #endif return (mount_steed(m_at(u.ux+u.dx, u.uy+u.dy), forcemount)); } else return 0; return 1; } /* Start riding, with the given monster */ boolean mount_steed(mtmp, force) struct monst *mtmp; /* The animal */ boolean force; /* Quietly force this animal */ { struct obj *otmp; char buf[BUFSZ]; struct permonst *ptr; /* Sanity checks */ if (u.usteed) { You("are already riding %s.", mon_nam(u.usteed)); return (FALSE); } /* Is the player in the right form? */ if (Hallucination && !force) { pline("Maybe you should find a designated driver."); return (FALSE); } /* While riding Wounded_legs refers to the steed's, * not the hero's legs. * That opens up a potential abuse where the player * can mount a steed, then dismount immediately to * heal leg damage, because leg damage is always * healed upon dismount (Wounded_legs context switch). * By preventing a hero with Wounded_legs from * mounting a steed, the potential for abuse is * minimized, if not eliminated altogether. */ if (Wounded_legs) { Your("%s are in no shape for riding.", makeplural(body_part(LEG))); #ifdef WIZARD if (force && wizard && yn("Heal your legs?") == 'y') HWounded_legs = EWounded_legs = 0; else #endif return (FALSE); } if (Upolyd && (!humanoid(youmonst.data) || verysmall(youmonst.data) || bigmonst(youmonst.data) || slithy(youmonst.data))) { You("won't fit on a saddle."); return (FALSE); } if(!force && (near_capacity() > SLT_ENCUMBER)) { You_cant("do that while carrying so much stuff."); return (FALSE); } /* Can the player reach and see the monster? */ if (!mtmp || (!force && ((Blind && !Blind_telepat) || mtmp->mundetected || mtmp->m_ap_type == M_AP_FURNITURE || mtmp->m_ap_type == M_AP_OBJECT))) { pline("I see nobody there."); return (FALSE); } if (u.uswallow || u.ustuck || u.utrap || Punished || !test_move(u.ux, u.uy, mtmp->mx-u.ux, mtmp->my-u.uy, TEST_MOVE)) { if (Punished || !(u.uswallow || u.ustuck || u.utrap)) You("are unable to swing your %s over.", body_part(LEG)); else You("are stuck here for now."); return (FALSE); } /* Is this a valid monster? */ otmp = which_armor(mtmp, W_SADDLE); if (!otmp) { pline("%s is not saddled.", Monnam(mtmp)); return (FALSE); } ptr = mtmp->data; if (touch_petrifies(ptr) && !Stone_resistance) { char kbuf[BUFSZ]; You("touch %s.", mon_nam(mtmp)); Sprintf(kbuf, "attempting to ride %s", an(mtmp->data->mname)); instapetrify(kbuf); } if (!mtmp->mtame || mtmp->isminion) { pline("I think %s would mind.", mon_nam(mtmp)); return (FALSE); } if (mtmp->mtrapped) { struct trap *t = t_at(mtmp->mx, mtmp->my); You_cant("mount %s while %s's trapped in %s.", mon_nam(mtmp), mhe(mtmp), an(defsyms[trap_to_defsym(t->ttyp)].explanation)); return (FALSE); } if (!force && !Role_if(PM_KNIGHT) && !(--mtmp->mtame)) { /* no longer tame */ newsym(mtmp->mx, mtmp->my); pline("%s resists%s!", Monnam(mtmp), mtmp->mleashed ? " and its leash comes off" : ""); if (mtmp->mleashed) m_unleash(mtmp, FALSE); return (FALSE); } if (!force && Underwater && !is_swimmer(ptr)) { You_cant("ride that creature while under water."); return (FALSE); } if (!can_saddle(mtmp) || !can_ride(mtmp)) { You_cant("ride such a creature."); return (0); } /* Is the player impaired? */ if (!force && !is_floater(ptr) && !is_flyer(ptr) && Levitation && !Lev_at_will) { You("cannot reach %s.", mon_nam(mtmp)); return (FALSE); } if (!force && uarm && is_metallic(uarm) && greatest_erosion(uarm)) { Your("%s armor is too stiff to be able to mount %s.", uarm->oeroded ? "rusty" : "corroded", mon_nam(mtmp)); return (FALSE); } if (!force && (Confusion || Fumbling || Glib || Wounded_legs || otmp->cursed || (u.ulevel+mtmp->mtame < rnd(MAXULEV/2+5)))) { if (Levitation) { pline("%s slips away from you.", Monnam(mtmp)); return FALSE; } You("slip while trying to get on %s.", mon_nam(mtmp)); Sprintf(buf, "slipped while mounting %s", /* "a saddled mumak" or "a saddled pony called Dobbin" */ x_monnam(mtmp, ARTICLE_A, (char *)0, SUPPRESS_IT|SUPPRESS_INVISIBLE|SUPPRESS_HALLUCINATION, TRUE)); losehp(rn1(5,10), buf, NO_KILLER_PREFIX); return (FALSE); } /* Success */ if (!force) { if (Levitation && !is_floater(ptr) && !is_flyer(ptr)) /* Must have Lev_at_will at this point */ pline("%s magically floats up!", Monnam(mtmp)); You("mount %s.", mon_nam(mtmp)); } /* setuwep handles polearms differently when you're mounted */ if (uwep && is_pole(uwep)) unweapon = FALSE; u.usteed = mtmp; remove_monster(mtmp->mx, mtmp->my); teleds(mtmp->mx, mtmp->my, TRUE); return (TRUE); } /* You and your steed have moved */ void exercise_steed() { if (!u.usteed) return; /* It takes many turns of riding to exercise skill */ if (u.urideturns++ >= 100) { u.urideturns = 0; use_skill(P_RIDING, 1); } return; } /* The player kicks or whips the steed */ void kick_steed() { char He[4]; if (!u.usteed) return; /* [ALI] Various effects of kicking sleeping/paralyzed steeds */ if (u.usteed->msleeping || !u.usteed->mcanmove) { /* We assume a message has just been output of the form * "You kick ." */ Strcpy(He, mhe(u.usteed)); *He = highc(*He); if ((u.usteed->mcanmove || u.usteed->mfrozen) && !rn2(2)) { if (u.usteed->mcanmove) u.usteed->msleeping = 0; else if (u.usteed->mfrozen > 2) u.usteed->mfrozen -= 2; else { u.usteed->mfrozen = 0; u.usteed->mcanmove = 1; } if (u.usteed->msleeping || !u.usteed->mcanmove) pline("%s stirs.", He); else pline("%s rouses %sself!", He, mhim(u.usteed)); } else pline("%s does not respond.", He); return; } /* Make the steed less tame and check if it resists */ if (u.usteed->mtame) u.usteed->mtame--; if (!u.usteed->mtame && u.usteed->mleashed) m_unleash(u.usteed, TRUE); if (!u.usteed->mtame || (u.ulevel+u.usteed->mtame < rnd(MAXULEV/2+5))) { newsym(u.usteed->mx, u.usteed->my); dismount_steed(DISMOUNT_THROWN); return; } pline("%s gallops!", Monnam(u.usteed)); u.ugallop += rn1(20, 30); return; } /* * Try to find a dismount point adjacent to the steed's location. * If all else fails, try enexto(). Use enexto() as a last resort because * enexto() chooses its point randomly, possibly even outside the * room's walls, which is not what we want. * Adapted from mail daemon code. */ STATIC_OVL boolean landing_spot(spot, reason, forceit) coord *spot; /* landing position (we fill it in) */ int reason; int forceit; { int i = 0, x, y, distance, min_distance = -1; boolean found = FALSE; struct trap *t; /* avoid known traps (i == 0) and boulders, but allow them as a backup */ if (reason != DISMOUNT_BYCHOICE || Stunned || Confusion || Fumbling) i = 1; for (; !found && i < 2; ++i) { for (x = u.ux-1; x <= u.ux+1; x++) for (y = u.uy-1; y <= u.uy+1; y++) { if (!isok(x, y) || (x == u.ux && y == u.uy)) continue; if (ACCESSIBLE(levl[x][y].typ) && !MON_AT(x,y) && !closed_door(x,y)) { distance = distu(x,y); if (min_distance < 0 || distance < min_distance || (distance == min_distance && rn2(2))) { if (i > 0 || (((t = t_at(x, y)) == 0 || !t->tseen) && (!sobj_at(BOULDER, x, y) || throws_rocks(youmonst.data)))) { spot->x = x; spot->y = y; min_distance = distance; found = TRUE; } } } } } /* If we didn't find a good spot and forceit is on, try enexto(). */ if (forceit && min_distance < 0 && !enexto(spot, u.ux, u.uy, youmonst.data)) return FALSE; return found; } /* Stop riding the current steed */ void dismount_steed(reason) int reason; /* Player was thrown off etc. */ { struct monst *mtmp; struct obj *otmp; coord cc; const char *verb = "fall"; boolean repair_leg_damage = TRUE; unsigned save_utrap = u.utrap; boolean have_spot = landing_spot(&cc,reason,0); mtmp = u.usteed; /* make a copy of steed pointer */ /* Sanity check */ if (!mtmp) /* Just return silently */ return; /* Check the reason for dismounting */ otmp = which_armor(mtmp, W_SADDLE); switch (reason) { case DISMOUNT_THROWN: verb = "are thrown"; case DISMOUNT_FELL: You("%s off of %s!", verb, mon_nam(mtmp)); if (!have_spot) have_spot = landing_spot(&cc,reason,1); losehp(rn1(10,10), "riding accident", KILLED_BY_AN); set_wounded_legs(BOTH_SIDES, (int)HWounded_legs + rn1(5,5)); repair_leg_damage = FALSE; break; case DISMOUNT_POLY: You("can no longer ride %s.", mon_nam(u.usteed)); if (!have_spot) have_spot = landing_spot(&cc,reason,1); break; case DISMOUNT_ENGULFED: /* caller displays message */ break; case DISMOUNT_BONES: /* hero has just died... */ break; case DISMOUNT_GENERIC: /* no messages, just make it so */ break; case DISMOUNT_BYCHOICE: default: if (otmp && otmp->cursed) { You("can't. The saddle %s cursed.", otmp->bknown ? "is" : "seems to be"); otmp->bknown = TRUE; return; } if (!have_spot) { You("can't. There isn't anywhere for you to stand."); return; } if (!mtmp->mnamelth) { pline("You've been through the dungeon on %s with no name.", an(mtmp->data->mname)); if (Hallucination) pline("It felt good to get out of the rain."); } else You("dismount %s.", mon_nam(mtmp)); } /* While riding these refer to the steed's legs * so after dismounting they refer to the player's * legs once again. */ if (repair_leg_damage) HWounded_legs = EWounded_legs = 0; /* Release the steed and saddle */ u.usteed = 0; u.ugallop = 0L; /* Set player and steed's position. Try moving the player first unless we're in the midst of creating a bones file. */ if (reason == DISMOUNT_BONES) { /* move the steed to an adjacent square */ if (enexto(&cc, u.ux, u.uy, mtmp->data)) rloc_to(mtmp, cc.x, cc.y); else /* evidently no room nearby; move steed elsewhere */ (void) rloc(mtmp, FALSE); return; } if (!DEADMONSTER(mtmp)) { place_monster(mtmp, u.ux, u.uy); if (!u.uswallow && !u.ustuck && have_spot) { struct permonst *mdat = mtmp->data; /* The steed may drop into water/lava */ if (!is_flyer(mdat) && !is_floater(mdat) && !is_clinger(mdat)) { if (is_pool(u.ux, u.uy)) { if (!Underwater) pline("%s falls into the %s!", Monnam(mtmp), surface(u.ux, u.uy)); if (!is_swimmer(mdat) && !amphibious(mdat)) { killed(mtmp); adjalign(-1); } } else if (is_lava(u.ux, u.uy)) { pline("%s is pulled into the lava!", Monnam(mtmp)); if (!likes_lava(mdat)) { killed(mtmp); adjalign(-1); } } } /* Steed dismounting consists of two steps: being moved to another * square, and descending to the floor. We have functions to do * each of these activities, but they're normally called * individually and include an attempt to look at or pick up the * objects on the floor: * teleds() --> spoteffects() --> pickup() * float_down() --> pickup() * We use this kludge to make sure there is only one such attempt. * * Clearly this is not the best way to do it. A full fix would * involve having these functions not call pickup() at all, instead * calling them first and calling pickup() afterwards. But it * would take a lot of work to keep this change from having any * unforseen side effects (for instance, you would no longer be * able to walk onto a square with a hole, and autopickup before * falling into the hole). */ /* [ALI] No need to move the player if the steed died. */ if (!DEADMONSTER(mtmp)) { /* Keep steed here, move the player to cc; * teleds() clears u.utrap */ in_steed_dismounting = TRUE; teleds(cc.x, cc.y, TRUE); in_steed_dismounting = FALSE; /* Put your steed in your trap */ if (save_utrap) (void) mintrap(mtmp); } /* Couldn't... try placing the steed */ } else if (enexto(&cc, u.ux, u.uy, mtmp->data)) { /* Keep player here, move the steed to cc */ rloc_to(mtmp, cc.x, cc.y); /* Player stays put */ /* Otherwise, kill the steed */ } else { killed(mtmp); adjalign(-1); } } /* Return the player to the floor */ if (reason != DISMOUNT_ENGULFED) { in_steed_dismounting = TRUE; (void) float_down(0L, W_SADDLE); in_steed_dismounting = FALSE; flags.botl = 1; (void)encumber_msg(); vision_full_recalc = 1; } else flags.botl = 1; /* polearms behave differently when not mounted */ if (uwep && is_pole(uwep)) unweapon = TRUE; return; } void place_monster(mon, x, y) struct monst *mon; int x, y; { if (mon == u.usteed || /* special case is for convoluted vault guard handling */ (DEADMONSTER(mon) && !(mon->isgd && x == 0 && y == 0))) { impossible("placing %s onto map?", (mon == u.usteed) ? "steed" : "defunct monster"); return; } mon->mx = x, mon->my = y; level.monsters[x][y] = mon; } #endif /* STEED */ /*steed.c*/ nethack-3.4.3/src/teleport.c0100644000000000000000000010412307764735041014444 0ustar rootroot/* SCCS Id: @(#)teleport.c 3.4 2003/08/11 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL boolean FDECL(tele_jump_ok, (int,int,int,int)); STATIC_DCL boolean FDECL(teleok, (int,int,BOOLEAN_P)); STATIC_DCL void NDECL(vault_tele); STATIC_DCL boolean FDECL(rloc_pos_ok, (int,int,struct monst *)); STATIC_DCL void FDECL(mvault_tele, (struct monst *)); /* * Is (x,y) a good position of mtmp? If mtmp is NULL, then is (x,y) good * for an object? * * This function will only look at mtmp->mdat, so makemon, mplayer, etc can * call it to generate new monster positions with fake monster structures. */ boolean goodpos(x, y, mtmp, gpflags) int x,y; struct monst *mtmp; unsigned gpflags; { struct permonst *mdat = NULL; boolean ignorewater = ((gpflags & MM_IGNOREWATER) != 0); if (!isok(x, y)) return FALSE; /* in many cases, we're trying to create a new monster, which * can't go on top of the player or any existing monster. * however, occasionally we are relocating engravings or objects, * which could be co-located and thus get restricted a bit too much. * oh well. */ if (mtmp != &youmonst && x == u.ux && y == u.uy #ifdef STEED && (!u.usteed || mtmp != u.usteed) #endif ) return FALSE; if (mtmp) { struct monst *mtmp2 = m_at(x,y); /* Be careful with long worms. A monster may be placed back in * its own location. Normally, if m_at() returns the same monster * that we're trying to place, the monster is being placed in its * own location. However, that is not correct for worm segments, * because all the segments of the worm return the same m_at(). * Actually we overdo the check a little bit--a worm can't be placed * in its own location, period. If we just checked for mtmp->mx * != x || mtmp->my != y, we'd miss the case where we're called * to place the worm segment and the worm's head is at x,y. */ if (mtmp2 && (mtmp2 != mtmp || mtmp->wormno)) return FALSE; mdat = mtmp->data; if (is_pool(x,y) && !ignorewater) { if (mtmp == &youmonst) return !!(HLevitation || Flying || Wwalking || Swimming || Amphibious); else return (is_flyer(mdat) || is_swimmer(mdat) || is_clinger(mdat)); } else if (mdat->mlet == S_EEL && rn2(13) && !ignorewater) { return FALSE; } else if (is_lava(x,y)) { if (mtmp == &youmonst) return !!HLevitation; else return (is_flyer(mdat) || likes_lava(mdat)); } if (passes_walls(mdat) && may_passwall(x,y)) return TRUE; } if (!ACCESSIBLE(levl[x][y].typ)) { if (!(is_pool(x,y) && ignorewater)) return FALSE; } if (closed_door(x, y) && (!mdat || !amorphous(mdat))) return FALSE; if (sobj_at(BOULDER, x, y) && (!mdat || !throws_rocks(mdat))) return FALSE; return TRUE; } /* * "entity next to" * * Attempt to find a good place for the given monster type in the closest * position to (xx,yy). Do so in successive square rings around (xx,yy). * If there is more than one valid positon in the ring, choose one randomly. * Return TRUE and the position chosen when successful, FALSE otherwise. */ boolean enexto(cc, xx, yy, mdat) coord *cc; register xchar xx, yy; struct permonst *mdat; { return enexto_core(cc, xx, yy, mdat, 0); } boolean enexto_core(cc, xx, yy, mdat, entflags) coord *cc; register xchar xx, yy; struct permonst *mdat; unsigned entflags; { #define MAX_GOOD 15 coord good[MAX_GOOD], *good_ptr; int x, y, range, i; int xmin, xmax, ymin, ymax; struct monst fakemon; /* dummy monster */ if (!mdat) { #ifdef DEBUG pline("enexto() called with mdat==0"); #endif /* default to player's original monster type */ mdat = &mons[u.umonster]; } fakemon.data = mdat; /* set up for goodpos */ good_ptr = good; range = 1; /* * Walk around the border of the square with center (xx,yy) and * radius range. Stop when we find at least one valid position. */ do { xmin = max(1, xx-range); xmax = min(COLNO-1, xx+range); ymin = max(0, yy-range); ymax = min(ROWNO-1, yy+range); for (x = xmin; x <= xmax; x++) if (goodpos(x, ymin, &fakemon, entflags)) { good_ptr->x = x; good_ptr->y = ymin ; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD-1]) goto full; } for (x = xmin; x <= xmax; x++) if (goodpos(x, ymax, &fakemon, entflags)) { good_ptr->x = x; good_ptr->y = ymax ; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD-1]) goto full; } for (y = ymin+1; y < ymax; y++) if (goodpos(xmin, y, &fakemon, entflags)) { good_ptr->x = xmin; good_ptr-> y = y ; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD-1]) goto full; } for (y = ymin+1; y < ymax; y++) if (goodpos(xmax, y, &fakemon, entflags)) { good_ptr->x = xmax; good_ptr->y = y ; /* beware of accessing beyond segment boundaries.. */ if (good_ptr++ == &good[MAX_GOOD-1]) goto full; } range++; /* return if we've grown too big (nothing is valid) */ if (range > ROWNO && range > COLNO) return FALSE; } while (good_ptr == good); full: i = rn2((int)(good_ptr - good)); cc->x = good[i].x; cc->y = good[i].y; return TRUE; } /* * Check for restricted areas present in some special levels. (This might * need to be augmented to allow deliberate passage in wizard mode, but * only for explicitly chosen destinations.) */ STATIC_OVL boolean tele_jump_ok(x1, y1, x2, y2) int x1, y1, x2, y2; { if (dndest.nlx > 0) { /* if inside a restricted region, can't teleport outside */ if (within_bounded_area(x1, y1, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy) && !within_bounded_area(x2, y2, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy)) return FALSE; /* and if outside, can't teleport inside */ if (!within_bounded_area(x1, y1, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy) && within_bounded_area(x2, y2, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy)) return FALSE; } if (updest.nlx > 0) { /* ditto */ if (within_bounded_area(x1, y1, updest.nlx, updest.nly, updest.nhx, updest.nhy) && !within_bounded_area(x2, y2, updest.nlx, updest.nly, updest.nhx, updest.nhy)) return FALSE; if (!within_bounded_area(x1, y1, updest.nlx, updest.nly, updest.nhx, updest.nhy) && within_bounded_area(x2, y2, updest.nlx, updest.nly, updest.nhx, updest.nhy)) return FALSE; } return TRUE; } STATIC_OVL boolean teleok(x, y, trapok) register int x, y; boolean trapok; { if (!trapok && t_at(x, y)) return FALSE; if (!goodpos(x, y, &youmonst, 0)) return FALSE; if (!tele_jump_ok(u.ux, u.uy, x, y)) return FALSE; if (!in_out_region(x, y)) return FALSE; return TRUE; } void teleds(nux, nuy, allow_drag) register int nux,nuy; boolean allow_drag; { boolean ball_active = (Punished && uball->where != OBJ_FREE), ball_still_in_range = FALSE; /* If they have to move the ball, then drag if allow_drag is true; * otherwise they are teleporting, so unplacebc(). * If they don't have to move the ball, then always "drag" whether or * not allow_drag is true, because we are calling that function, not * to drag, but to move the chain. *However* there are some dumb * special cases: * 0 0 * _X move east -----> X_ * @ @ * These are permissible if teleporting, but not if dragging. As a * result, drag_ball() needs to know about allow_drag and might end * up dragging the ball anyway. Also, drag_ball() might find that * dragging the ball is completely impossible (ball in range but there's * rock in the way), in which case it teleports the ball on its own. */ if (ball_active) { if (!carried(uball) && distmin(nux, nuy, uball->ox, uball->oy) <= 2) ball_still_in_range = TRUE; /* don't have to move the ball */ else { /* have to move the ball */ if (!allow_drag || distmin(u.ux, u.uy, nux, nuy) > 1) { /* we should not have dist > 1 and allow_drag at the same * time, but just in case, we must then revert to teleport. */ allow_drag = FALSE; unplacebc(); } } } u.utrap = 0; u.ustuck = 0; u.ux0 = u.ux; u.uy0 = u.uy; if (hides_under(youmonst.data)) u.uundetected = OBJ_AT(nux, nuy); else if (youmonst.data->mlet == S_EEL) u.uundetected = is_pool(nux, nuy); else { u.uundetected = 0; /* mimics stop being unnoticed */ if (youmonst.data->mlet == S_MIMIC) youmonst.m_ap_type = M_AP_NOTHING; } if (u.uswallow) { u.uswldtim = u.uswallow = 0; if (Punished && !ball_active) { /* ensure ball placement, like unstuck */ ball_active = TRUE; allow_drag = FALSE; } docrt(); } if (ball_active) { if (ball_still_in_range || allow_drag) { int bc_control; xchar ballx, bally, chainx, chainy; boolean cause_delay; if (drag_ball(nux, nuy, &bc_control, &ballx, &bally, &chainx, &chainy, &cause_delay, allow_drag)) move_bc(0, bc_control, ballx, bally, chainx, chainy); } } /* must set u.ux, u.uy after drag_ball(), which may need to know the old position if allow_drag is true... */ u.ux = nux; u.uy = nuy; fill_pit(u.ux0, u.uy0); if (ball_active) { if (!ball_still_in_range && !allow_drag) placebc(); } initrack(); /* teleports mess up tracking monsters without this */ update_player_regions(); #ifdef STEED /* Move your steed, too */ if (u.usteed) { u.usteed->mx = nux; u.usteed->my = nuy; } #endif /* * Make sure the hero disappears from the old location. This will * not happen if she is teleported within sight of her previous * location. Force a full vision recalculation because the hero * is now in a new location. */ newsym(u.ux0,u.uy0); see_monsters(); vision_full_recalc = 1; nomul(0); vision_recalc(0); /* vision before effects */ spoteffects(TRUE); invocation_message(); } boolean safe_teleds(allow_drag) boolean allow_drag; { register int nux, nuy, tcnt = 0; do { nux = rnd(COLNO-1); nuy = rn2(ROWNO); } while (!teleok(nux, nuy, (boolean)(tcnt > 200)) && ++tcnt <= 400); if (tcnt <= 400) { teleds(nux, nuy, allow_drag); return TRUE; } else return FALSE; } STATIC_OVL void vault_tele() { register struct mkroom *croom = search_special(VAULT); coord c; if (croom && somexy(croom, &c) && teleok(c.x,c.y,FALSE)) { teleds(c.x,c.y,FALSE); return; } tele(); } boolean teleport_pet(mtmp, force_it) register struct monst *mtmp; boolean force_it; { register struct obj *otmp; #ifdef STEED if (mtmp == u.usteed) return (FALSE); #endif if (mtmp->mleashed) { otmp = get_mleash(mtmp); if (!otmp) { impossible("%s is leashed, without a leash.", Monnam(mtmp)); goto release_it; } if (otmp->cursed && !force_it) { yelp(mtmp); return FALSE; } else { Your("leash goes slack."); release_it: m_unleash(mtmp, FALSE); return TRUE; } } return TRUE; } void tele() { coord cc; /* Disable teleportation in stronghold && Vlad's Tower */ if (level.flags.noteleport) { #ifdef WIZARD if (!wizard) { #endif pline("A mysterious force prevents you from teleporting!"); return; #ifdef WIZARD } #endif } /* don't show trap if "Sorry..." */ if (!Blinded) make_blinded(0L,FALSE); if ((u.uhave.amulet || On_W_tower_level(&u.uz)) && !rn2(3)) { You_feel("disoriented for a moment."); return; } if ((Teleport_control && !Stunned) #ifdef WIZARD || wizard #endif ) { if (unconscious()) { pline("Being unconscious, you cannot control your teleport."); } else { #ifdef STEED char buf[BUFSZ]; if (u.usteed) Sprintf(buf," and %s", mon_nam(u.usteed)); #endif pline("To what position do you%s want to be teleported?", #ifdef STEED u.usteed ? buf : #endif ""); cc.x = u.ux; cc.y = u.uy; if (getpos(&cc, TRUE, "the desired position") < 0) return; /* abort */ /* possible extensions: introduce a small error if magic power is low; allow transfer to solid rock */ if (teleok(cc.x, cc.y, FALSE)) { teleds(cc.x, cc.y, FALSE); return; } pline("Sorry..."); } } (void) safe_teleds(FALSE); } int dotele() { struct trap *trap; trap = t_at(u.ux, u.uy); if (trap && (!trap->tseen || trap->ttyp != TELEP_TRAP)) trap = 0; if (trap) { if (trap->once) { pline("This is a vault teleport, usable once only."); if (yn("Jump in?") == 'n') trap = 0; else { deltrap(trap); newsym(u.ux, u.uy); } } if (trap) You("%s onto the teleportation trap.", locomotion(youmonst.data, "jump")); } if (!trap) { boolean castit = FALSE; register int sp_no = 0, energy = 0; if (!Teleportation || (u.ulevel < (Role_if(PM_WIZARD) ? 8 : 12) && !can_teleport(youmonst.data))) { /* Try to use teleport away spell. */ if (objects[SPE_TELEPORT_AWAY].oc_name_known && !Confusion) for (sp_no = 0; sp_no < MAXSPELL; sp_no++) if (spl_book[sp_no].sp_id == SPE_TELEPORT_AWAY) { castit = TRUE; break; } #ifdef WIZARD if (!wizard) { #endif if (!castit) { if (!Teleportation) You("don't know that spell."); else You("are not able to teleport at will."); return(0); } #ifdef WIZARD } #endif } if (u.uhunger <= 100 || ACURR(A_STR) < 6) { #ifdef WIZARD if (!wizard) { #endif You("lack the strength %s.", castit ? "for a teleport spell" : "to teleport"); return 1; #ifdef WIZARD } #endif } energy = objects[SPE_TELEPORT_AWAY].oc_level * 7 / 2 - 2; if (u.uen <= energy) { #ifdef WIZARD if (wizard) energy = u.uen; else #endif { You("lack the energy %s.", castit ? "for a teleport spell" : "to teleport"); return 1; } } if (check_capacity( "Your concentration falters from carrying so much.")) return 1; if (castit) { exercise(A_WIS, TRUE); if (spelleffects(sp_no, TRUE)) return(1); else #ifdef WIZARD if (!wizard) #endif return(0); } else { u.uen -= energy; flags.botl = 1; } } if (next_to_u()) { if (trap && trap->once) vault_tele(); else tele(); (void) next_to_u(); } else { You(shudder_for_moment); return(0); } if (!trap) morehungry(100); return(1); } void level_tele() { register int newlev; d_level newlevel; const char *escape_by_flying = 0; /* when surviving dest of -N */ char buf[BUFSZ]; boolean force_dest = FALSE; if ((u.uhave.amulet || In_endgame(&u.uz) || In_sokoban(&u.uz)) #ifdef WIZARD && !wizard #endif ) { You_feel("very disoriented for a moment."); return; } if ((Teleport_control && !Stunned) #ifdef WIZARD || wizard #endif ) { char qbuf[BUFSZ]; int trycnt = 0; Strcpy(qbuf, "To what level do you want to teleport?"); do { if (++trycnt == 2) { #ifdef WIZARD if (wizard) Strcat(qbuf, " [type a number or ? for a menu]"); else #endif Strcat(qbuf, " [type a number]"); } getlin(qbuf, buf); if (!strcmp(buf,"\033")) { /* cancelled */ if (Confusion && rnl(5)) { pline("Oops..."); goto random_levtport; } return; } else if (!strcmp(buf,"*")) { goto random_levtport; } else if (Confusion && rnl(5)) { pline("Oops..."); goto random_levtport; } #ifdef WIZARD if (wizard && !strcmp(buf,"?")) { schar destlev = 0; xchar destdnum = 0; if ((newlev = (int)print_dungeon(TRUE, &destlev, &destdnum))) { newlevel.dnum = destdnum; newlevel.dlevel = destlev; if (In_endgame(&newlevel) && !In_endgame(&u.uz)) { Sprintf(buf, "Destination is earth level"); if (!u.uhave.amulet) { struct obj *obj; obj = mksobj(AMULET_OF_YENDOR, TRUE, FALSE); if (obj) { obj = addinv(obj); Strcat(buf, " with the amulet"); } } assign_level(&newlevel, &earth_level); pline("%s.", buf); } force_dest = TRUE; } else return; } else #endif if ((newlev = lev_by_name(buf)) == 0) newlev = atoi(buf); } while (!newlev && !digit(buf[0]) && (buf[0] != '-' || !digit(buf[1])) && trycnt < 10); /* no dungeon escape via this route */ if (newlev == 0) { if (trycnt >= 10) goto random_levtport; if (ynq("Go to Nowhere. Are you sure?") != 'y') return; You("%s in agony as your body begins to warp...", is_silent(youmonst.data) ? "writhe" : "scream"); display_nhwindow(WIN_MESSAGE, FALSE); You("cease to exist."); if (invent) Your("possessions land on the %s with a thud.", surface(u.ux, u.uy)); killer_format = NO_KILLER_PREFIX; killer = "committed suicide"; done(DIED); pline("An energized cloud of dust begins to coalesce."); Your("body rematerializes%s.", invent ? ", and you gather up all your possessions" : ""); return; } /* if in Knox and the requested level > 0, stay put. * we let negative values requests fall into the "heaven" loop. */ if (Is_knox(&u.uz) && newlev > 0) { You(shudder_for_moment); return; } /* if in Quest, the player sees "Home 1", etc., on the status * line, instead of the logical depth of the level. controlled * level teleport request is likely to be relativized to the * status line, and consequently it should be incremented to * the value of the logical depth of the target level. * * we let negative values requests fall into the "heaven" loop. */ if (In_quest(&u.uz) && newlev > 0) newlev = newlev + dungeons[u.uz.dnum].depth_start - 1; } else { /* involuntary level tele */ random_levtport: newlev = random_teleport_level(); if (newlev == depth(&u.uz)) { You(shudder_for_moment); return; } } if (!next_to_u()) { You(shudder_for_moment); return; } #ifdef WIZARD if (In_endgame(&u.uz)) { /* must already be wizard */ int llimit = dunlevs_in_dungeon(&u.uz); if (newlev >= 0 || newlev <= -llimit) { You_cant("get there from here."); return; } newlevel.dnum = u.uz.dnum; newlevel.dlevel = llimit + newlev; schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0); return; } #endif killer = 0; /* still alive, so far... */ if (newlev < 0 && !force_dest) { if (*u.ushops0) { /* take unpaid inventory items off of shop bills */ in_mklev = TRUE; /* suppress map update */ u_left_shop(u.ushops0, TRUE); /* you're now effectively out of the shop */ *u.ushops0 = *u.ushops = '\0'; in_mklev = FALSE; } if (newlev <= -10) { You("arrive in heaven."); verbalize("Thou art early, but we'll admit thee."); killer_format = NO_KILLER_PREFIX; killer = "went to heaven prematurely"; } else if (newlev == -9) { You_feel("deliriously happy. "); pline("(In fact, you're on Cloud 9!) "); display_nhwindow(WIN_MESSAGE, FALSE); } else You("are now high above the clouds..."); if (killer) { ; /* arrival in heaven is pending */ } else if (Levitation) { escape_by_flying = "float gently down to earth"; } else if (Flying) { escape_by_flying = "fly down to the ground"; } else { pline("Unfortunately, you don't know how to fly."); You("plummet a few thousand feet to your death."); Sprintf(buf, "teleported out of the dungeon and fell to %s death", uhis()); killer = buf; killer_format = NO_KILLER_PREFIX; } } if (killer) { /* the chosen destination was not survivable */ d_level lsav; /* set specific death location; this also suppresses bones */ lsav = u.uz; /* save current level, see below */ u.uz.dnum = 0; /* main dungeon */ u.uz.dlevel = (newlev <= -10) ? -10 : 0; /* heaven or surface */ done(DIED); /* can only get here via life-saving (or declining to die in explore|debug mode); the hero has now left the dungeon... */ escape_by_flying = "find yourself back on the surface"; u.uz = lsav; /* restore u.uz so escape code works */ } /* calls done(ESCAPED) if newlevel==0 */ if (escape_by_flying) { You("%s.", escape_by_flying); newlevel.dnum = 0; /* specify main dungeon */ newlevel.dlevel = 0; /* escape the dungeon */ /* [dlevel used to be set to 1, but it doesn't make sense to teleport out of the dungeon and float or fly down to the surface but then actually arrive back inside the dungeon] */ } else if (u.uz.dnum == medusa_level.dnum && newlev >= dungeons[u.uz.dnum].depth_start + dunlevs_in_dungeon(&u.uz)) { #ifdef WIZARD if (!(wizard && force_dest)) #endif find_hell(&newlevel); } else { /* if invocation did not yet occur, teleporting into * the last level of Gehennom is forbidden. */ #ifdef WIZARD if (!wizard) #endif if (Inhell && !u.uevent.invoked && newlev >= (dungeons[u.uz.dnum].depth_start + dunlevs_in_dungeon(&u.uz) - 1)) { newlev = dungeons[u.uz.dnum].depth_start + dunlevs_in_dungeon(&u.uz) - 2; pline("Sorry..."); } /* no teleporting out of quest dungeon */ if (In_quest(&u.uz) && newlev < depth(&qstart_level)) newlev = depth(&qstart_level); /* the player thinks of levels purely in logical terms, so * we must translate newlev to a number relative to the * current dungeon. */ #ifdef WIZARD if (!(wizard && force_dest)) #endif get_level(&newlevel, newlev); } schedule_goto(&newlevel, FALSE, FALSE, 0, (char *)0, (char *)0); /* in case player just read a scroll and is about to be asked to call it something, we can't defer until the end of the turn */ if (u.utotype && !flags.mon_moving) deferred_goto(); } void domagicportal(ttmp) register struct trap *ttmp; { struct d_level target_level; if (!next_to_u()) { You(shudder_for_moment); return; } /* if landed from another portal, do nothing */ /* problem: level teleport landing escapes the check */ if (!on_level(&u.uz, &u.uz0)) return; You("activated a magic portal!"); /* prevent the poor shnook, whose amulet was stolen while in * the endgame, from accidently triggering the portal to the * next level, and thus losing the game */ if (In_endgame(&u.uz) && !u.uhave.amulet) { You_feel("dizzy for a moment, but nothing happens..."); return; } target_level = ttmp->dst; schedule_goto(&target_level, FALSE, FALSE, 1, "You feel dizzy for a moment, but the sensation passes.", (char *)0); } void tele_trap(trap) struct trap *trap; { if (In_endgame(&u.uz) || Antimagic) { if (Antimagic) shieldeff(u.ux, u.uy); You_feel("a wrenching sensation."); } else if (!next_to_u()) { You(shudder_for_moment); } else if (trap->once) { deltrap(trap); newsym(u.ux,u.uy); /* get rid of trap symbol */ vault_tele(); } else tele(); } void level_tele_trap(trap) struct trap *trap; { You("%s onto a level teleport trap!", Levitation ? (const char *)"float" : locomotion(youmonst.data, "step")); if (Antimagic) { shieldeff(u.ux, u.uy); } if (Antimagic || In_endgame(&u.uz)) { You_feel("a wrenching sensation."); return; } if (!Blind) You("are momentarily blinded by a flash of light."); else You("are momentarily disoriented."); deltrap(trap); newsym(u.ux,u.uy); /* get rid of trap symbol */ level_tele(); } /* check whether monster can arrive at location via Tport (or fall) */ STATIC_OVL boolean rloc_pos_ok(x, y, mtmp) register int x, y; /* coordinates of candidate location */ struct monst *mtmp; { register int xx, yy; if (!goodpos(x, y, mtmp, 0)) return FALSE; /* * Check for restricted areas present in some special levels. * * `xx' is current column; if 0, then `yy' will contain flag bits * rather than row: bit #0 set => moving upwards; bit #1 set => * inside the Wizard's tower. */ xx = mtmp->mx; yy = mtmp->my; if (!xx) { /* no current location (migrating monster arrival) */ if (dndest.nlx && On_W_tower_level(&u.uz)) return ((yy & 2) != 0) ^ /* inside xor not within */ !within_bounded_area(x, y, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy); if (updest.lx && (yy & 1) != 0) /* moving up */ return (within_bounded_area(x, y, updest.lx, updest.ly, updest.hx, updest.hy) && (!updest.nlx || !within_bounded_area(x, y, updest.nlx, updest.nly, updest.nhx, updest.nhy))); if (dndest.lx && (yy & 1) == 0) /* moving down */ return (within_bounded_area(x, y, dndest.lx, dndest.ly, dndest.hx, dndest.hy) && (!dndest.nlx || !within_bounded_area(x, y, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy))); } else { /* current location is */ if (!tele_jump_ok(xx, yy, x, y)) return FALSE; } /* is ok */ return TRUE; } /* * rloc_to() * * Pulls a monster from its current position and places a monster at * a new x and y. If oldx is 0, then the monster was not in the levels.monsters * array. However, if oldx is 0, oldy may still have a value because mtmp is a * migrating_mon. Worm tails are always placed randomly around the head of * the worm. */ void rloc_to(mtmp, x, y) struct monst *mtmp; register int x, y; { register int oldx = mtmp->mx, oldy = mtmp->my; boolean resident_shk = mtmp->isshk && inhishop(mtmp); if (x == mtmp->mx && y == mtmp->my) /* that was easy */ return; if (oldx) { /* "pick up" monster */ if (mtmp->wormno) remove_worm(mtmp); else { remove_monster(oldx, oldy); newsym(oldx, oldy); /* update old location */ } } place_monster(mtmp, x, y); /* put monster down */ update_monster_region(mtmp); if (mtmp->wormno) /* now put down tail */ place_worm_tail_randomly(mtmp, x, y); if (u.ustuck == mtmp) { if (u.uswallow) { u.ux = x; u.uy = y; docrt(); } else u.ustuck = 0; } newsym(x, y); /* update new location */ set_apparxy(mtmp); /* orient monster */ /* shopkeepers will only teleport if you zap them with a wand of teleportation or if they've been transformed into a jumpy monster; the latter only happens if you've attacked them with polymorph */ if (resident_shk && !inhishop(mtmp)) make_angry_shk(mtmp, oldx, oldy); } /* place a monster at a random location, typically due to teleport */ /* return TRUE if successful, FALSE if not */ boolean rloc(mtmp, suppress_impossible) struct monst *mtmp; /* mx==0 implies migrating monster arrival */ boolean suppress_impossible; { register int x, y, trycount; #ifdef STEED if (mtmp == u.usteed) { tele(); return TRUE; } #endif if (mtmp->iswiz && mtmp->mx) { /* Wizard, not just arriving */ if (!In_W_tower(u.ux, u.uy, &u.uz)) x = xupstair, y = yupstair; else if (!xdnladder) /* bottom level of tower */ x = xupladder, y = yupladder; else x = xdnladder, y = ydnladder; /* if the wiz teleports away to heal, try the up staircase, to block the player's escaping before he's healed (deliberately use `goodpos' rather than `rloc_pos_ok' here) */ if (goodpos(x, y, mtmp, 0)) goto found_xy; } trycount = 0; do { x = rn1(COLNO-3,2); y = rn2(ROWNO); if ((trycount < 500) ? rloc_pos_ok(x, y, mtmp) : goodpos(x, y, mtmp, 0)) goto found_xy; } while (++trycount < 1000); /* last ditch attempt to find a good place */ for (x = 2; x < COLNO - 1; x++) for (y = 0; y < ROWNO; y++) if (goodpos(x, y, mtmp, 0)) goto found_xy; /* level either full of monsters or somehow faulty */ if (!suppress_impossible) impossible("rloc(): couldn't relocate monster"); return FALSE; found_xy: rloc_to(mtmp, x, y); return TRUE; } STATIC_OVL void mvault_tele(mtmp) struct monst *mtmp; { register struct mkroom *croom = search_special(VAULT); coord c; if (croom && somexy(croom, &c) && goodpos(c.x, c.y, mtmp, 0)) { rloc_to(mtmp, c.x, c.y); return; } (void) rloc(mtmp, FALSE); } boolean tele_restrict(mon) struct monst *mon; { if (level.flags.noteleport) { if (canseemon(mon)) pline("A mysterious force prevents %s from teleporting!", mon_nam(mon)); return TRUE; } return FALSE; } void mtele_trap(mtmp, trap, in_sight) struct monst *mtmp; struct trap *trap; int in_sight; { char *monname; if (tele_restrict(mtmp)) return; if (teleport_pet(mtmp, FALSE)) { /* save name with pre-movement visibility */ monname = Monnam(mtmp); /* Note: don't remove the trap if a vault. Other- * wise the monster will be stuck there, since * the guard isn't going to come for it... */ if (trap->once) mvault_tele(mtmp); else (void) rloc(mtmp, FALSE); if (in_sight) { if (canseemon(mtmp)) pline("%s seems disoriented.", monname); else pline("%s suddenly disappears!", monname); seetrap(trap); } } } /* return 0 if still on level, 3 if not */ int mlevel_tele_trap(mtmp, trap, force_it, in_sight) struct monst *mtmp; struct trap *trap; boolean force_it; int in_sight; { int tt = trap->ttyp; struct permonst *mptr = mtmp->data; if (mtmp == u.ustuck) /* probably a vortex */ return 0; /* temporary? kludge */ if (teleport_pet(mtmp, force_it)) { d_level tolevel; int migrate_typ = MIGR_RANDOM; if ((tt == HOLE || tt == TRAPDOOR)) { if (Is_stronghold(&u.uz)) { assign_level(&tolevel, &valley_level); } else if (Is_botlevel(&u.uz)) { if (in_sight && trap->tseen) pline("%s avoids the %s.", Monnam(mtmp), (tt == HOLE) ? "hole" : "trap"); return 0; } else { get_level(&tolevel, depth(&u.uz) + 1); } } else if (tt == MAGIC_PORTAL) { if (In_endgame(&u.uz) && (mon_has_amulet(mtmp) || is_home_elemental(mptr))) { if (in_sight && mptr->mlet != S_ELEMENTAL) { pline("%s seems to shimmer for a moment.", Monnam(mtmp)); seetrap(trap); } return 0; } else { assign_level(&tolevel, &trap->dst); migrate_typ = MIGR_PORTAL; } } else { /* (tt == LEVEL_TELEP) */ int nlev; if (mon_has_amulet(mtmp) || In_endgame(&u.uz)) { if (in_sight) pline("%s seems very disoriented for a moment.", Monnam(mtmp)); return 0; } nlev = random_teleport_level(); if (nlev == depth(&u.uz)) { if (in_sight) pline("%s shudders for a moment.", Monnam(mtmp)); return 0; } get_level(&tolevel, nlev); } if (in_sight) { pline("Suddenly, %s disappears out of sight.", mon_nam(mtmp)); seetrap(trap); } migrate_to_level(mtmp, ledger_no(&tolevel), migrate_typ, (coord *)0); return 3; /* no longer on this level */ } return 0; } void rloco(obj) register struct obj *obj; { register xchar tx, ty, otx, oty; boolean restricted_fall; int try_limit = 4000; if (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm])) { if (revive_corpse(obj)) return; } obj_extract_self(obj); otx = obj->ox; oty = obj->oy; restricted_fall = (otx == 0 && dndest.lx); do { tx = rn1(COLNO-3,2); ty = rn2(ROWNO); if (!--try_limit) break; } while (!goodpos(tx, ty, (struct monst *)0, 0) || /* bug: this lacks provision for handling the Wizard's tower */ (restricted_fall && (!within_bounded_area(tx, ty, dndest.lx, dndest.ly, dndest.hx, dndest.hy) || (dndest.nlx && within_bounded_area(tx, ty, dndest.nlx, dndest.nly, dndest.nhx, dndest.nhy))))); if (flooreffects(obj, tx, ty, "fall")) { return; } else if (otx == 0 && oty == 0) { ; /* fell through a trap door; no update of old loc needed */ } else { if (costly_spot(otx, oty) && (!costly_spot(tx, ty) || !index(in_rooms(tx, ty, 0), *in_rooms(otx, oty, 0)))) { if (costly_spot(u.ux, u.uy) && index(u.urooms, *in_rooms(otx, oty, 0))) addtobill(obj, FALSE, FALSE, FALSE); else (void)stolen_value(obj, otx, oty, FALSE, FALSE); } newsym(otx, oty); /* update old location */ } place_object(obj, tx, ty); newsym(tx, ty); } /* Returns an absolute depth */ int random_teleport_level() { int nlev, max_depth, min_depth, cur_depth = (int)depth(&u.uz); if (!rn2(5) || Is_knox(&u.uz)) return cur_depth; /* What I really want to do is as follows: * -- If in a dungeon that goes down, the new level is to be restricted * to [top of parent, bottom of current dungeon] * -- If in a dungeon that goes up, the new level is to be restricted * to [top of current dungeon, bottom of parent] * -- If in a quest dungeon or similar dungeon entered by portals, * the new level is to be restricted to [top of current dungeon, * bottom of current dungeon] * The current behavior is not as sophisticated as that ideal, but is * still better what we used to do, which was like this for players * but different for monsters for no obvious reason. Currently, we * must explicitly check for special dungeons. We check for Knox * above; endgame is handled in the caller due to its different * message ("disoriented"). * --KAA * 3.4.2: explicitly handle quest here too, to fix the problem of * monsters sometimes level teleporting out of it into main dungeon. * Also prevent monsters reaching the Sanctum prior to invocation. */ min_depth = In_quest(&u.uz) ? dungeons[u.uz.dnum].depth_start : 1; max_depth = dunlevs_in_dungeon(&u.uz) + (dungeons[u.uz.dnum].depth_start - 1); /* can't reach the Sanctum if the invocation hasn't been performed */ if (Inhell && !u.uevent.invoked) max_depth -= 1; /* Get a random value relative to the current dungeon */ /* Range is 1 to current+3, current not counting */ nlev = rn2(cur_depth + 3 - min_depth) + min_depth; if (nlev >= cur_depth) nlev++; if (nlev > max_depth) { nlev = max_depth; /* teleport up if already on bottom */ if (Is_botlevel(&u.uz)) nlev -= rnd(3); } if (nlev < min_depth) { nlev = min_depth; if (nlev == cur_depth) { nlev += rnd(3); if (nlev > max_depth) nlev = max_depth; } } return nlev; } /* you teleport a monster (via wand, spell, or poly'd q.mechanic attack); return false iff the attempt fails */ boolean u_teleport_mon(mtmp, give_feedback) struct monst *mtmp; boolean give_feedback; { coord cc; if (mtmp->ispriest && *in_rooms(mtmp->mx, mtmp->my, TEMPLE)) { if (give_feedback) pline("%s resists your magic!", Monnam(mtmp)); return FALSE; } else if (level.flags.noteleport && u.uswallow && mtmp == u.ustuck) { if (give_feedback) You("are no longer inside %s!", mon_nam(mtmp)); unstuck(mtmp); (void) rloc(mtmp, FALSE); } else if (is_rider(mtmp->data) && rn2(13) && enexto(&cc, u.ux, u.uy, mtmp->data)) rloc_to(mtmp, cc.x, cc.y); else (void) rloc(mtmp, FALSE); return TRUE; } /*teleport.c*/ nethack-3.4.3/src/timeout.c0100644000000000000000000013120607764735041014276 0ustar rootroot/* SCCS Id: @(#)timeout.c 3.4 2002/12/17 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" /* for checking save modes */ STATIC_DCL void NDECL(stoned_dialogue); STATIC_DCL void NDECL(vomiting_dialogue); STATIC_DCL void NDECL(choke_dialogue); STATIC_DCL void NDECL(slime_dialogue); STATIC_DCL void NDECL(slip_or_trip); STATIC_DCL void FDECL(see_lamp_flicker, (struct obj *, const char *)); STATIC_DCL void FDECL(lantern_message, (struct obj *)); STATIC_DCL void FDECL(cleanup_burn, (genericptr_t,long)); #ifdef OVLB /* He is being petrified - dialogue by inmet!tower */ static NEARDATA const char * const stoned_texts[] = { "You are slowing down.", /* 5 */ "Your limbs are stiffening.", /* 4 */ "Your limbs have turned to stone.", /* 3 */ "You have turned to stone.", /* 2 */ "You are a statue." /* 1 */ }; STATIC_OVL void stoned_dialogue() { register long i = (Stoned & TIMEOUT); if (i > 0L && i <= SIZE(stoned_texts)) pline(stoned_texts[SIZE(stoned_texts) - i]); if (i == 5L) HFast = 0L; if (i == 3L) nomul(-3); exercise(A_DEX, FALSE); } /* He is getting sicker and sicker prior to vomiting */ static NEARDATA const char * const vomiting_texts[] = { "are feeling mildly nauseated.", /* 14 */ "feel slightly confused.", /* 11 */ "can't seem to think straight.", /* 8 */ "feel incredibly sick.", /* 5 */ "suddenly vomit!" /* 2 */ }; STATIC_OVL void vomiting_dialogue() { register long i = (Vomiting & TIMEOUT) / 3L; if ((((Vomiting & TIMEOUT) % 3L) == 2) && (i >= 0) && (i < SIZE(vomiting_texts))) You(vomiting_texts[SIZE(vomiting_texts) - i - 1]); switch ((int) i) { case 0: vomit(); morehungry(20); break; case 2: make_stunned(HStun + d(2,4), FALSE); /* fall through */ case 3: make_confused(HConfusion + d(2,4), FALSE); break; } exercise(A_CON, FALSE); } static NEARDATA const char * const choke_texts[] = { "You find it hard to breathe.", "You're gasping for air.", "You can no longer breathe.", "You're turning %s.", "You suffocate." }; static NEARDATA const char * const choke_texts2[] = { "Your %s is becoming constricted.", "Your blood is having trouble reaching your brain.", "The pressure on your %s increases.", "Your consciousness is fading.", "You suffocate." }; STATIC_OVL void choke_dialogue() { register long i = (Strangled & TIMEOUT); if(i > 0 && i <= SIZE(choke_texts)) { if (Breathless || !rn2(50)) pline(choke_texts2[SIZE(choke_texts2) - i], body_part(NECK)); else { const char *str = choke_texts[SIZE(choke_texts)-i]; if (index(str, '%')) pline(str, hcolor(NH_BLUE)); else pline(str); } } exercise(A_STR, FALSE); } static NEARDATA const char * const slime_texts[] = { "You are turning a little %s.", /* 5 */ "Your limbs are getting oozy.", /* 4 */ "Your skin begins to peel away.", /* 3 */ "You are turning into %s.", /* 2 */ "You have become %s." /* 1 */ }; STATIC_OVL void slime_dialogue() { register long i = (Slimed & TIMEOUT) / 2L; if (((Slimed & TIMEOUT) % 2L) && i >= 0L && i < SIZE(slime_texts)) { const char *str = slime_texts[SIZE(slime_texts) - i - 1L]; if (index(str, '%')) { if (i == 4L) { /* "you are turning green" */ if (!Blind) /* [what if you're already green?] */ pline(str, hcolor(NH_GREEN)); } else pline(str, an(Hallucination ? rndmonnam() : "green slime")); } else pline(str); } if (i == 3L) { /* limbs becoming oozy */ HFast = 0L; /* lose intrinsic speed */ stop_occupation(); if (multi > 0) nomul(0); } exercise(A_DEX, FALSE); } void burn_away_slime() { if (Slimed) { pline_The("slime that covers you is burned away!"); Slimed = 0L; flags.botl = 1; } return; } #endif /* OVLB */ #ifdef OVL0 void nh_timeout() { register struct prop *upp; int sleeptime; int m_idx; int baseluck = (flags.moonphase == FULL_MOON) ? 1 : 0; if (flags.friday13) baseluck -= 1; if (u.uluck != baseluck && moves % (u.uhave.amulet || u.ugangr ? 300 : 600) == 0) { /* Cursed luckstones stop bad luck from timing out; blessed luckstones * stop good luck from timing out; normal luckstones stop both; * neither is stopped if you don't have a luckstone. * Luck is based at 0 usually, +1 if a full moon and -1 on Friday 13th */ register int time_luck = stone_luck(FALSE); boolean nostone = !carrying(LUCKSTONE) && !stone_luck(TRUE); if(u.uluck > baseluck && (nostone || time_luck < 0)) u.uluck--; else if(u.uluck < baseluck && (nostone || time_luck > 0)) u.uluck++; } if(u.uinvulnerable) return; /* things past this point could kill you */ if(Stoned) stoned_dialogue(); if(Slimed) slime_dialogue(); if(Vomiting) vomiting_dialogue(); if(Strangled) choke_dialogue(); if(u.mtimedone && !--u.mtimedone) { if (Unchanging) u.mtimedone = rnd(100*youmonst.data->mlevel + 1); else rehumanize(); } if(u.ucreamed) u.ucreamed--; /* Dissipate spell-based protection. */ if (u.usptime) { if (--u.usptime == 0 && u.uspellprot) { u.usptime = u.uspmtime; u.uspellprot--; find_ac(); if (!Blind) Norep("The %s haze around you %s.", hcolor(NH_GOLDEN), u.uspellprot ? "becomes less dense" : "disappears"); } } #ifdef STEED if (u.ugallop) { if (--u.ugallop == 0L && u.usteed) pline("%s stops galloping.", Monnam(u.usteed)); } #endif for(upp = u.uprops; upp < u.uprops+SIZE(u.uprops); upp++) if((upp->intrinsic & TIMEOUT) && !(--upp->intrinsic & TIMEOUT)) { switch(upp - u.uprops){ case STONED: if (delayed_killer && !killer) { killer = delayed_killer; delayed_killer = 0; } if (!killer) { /* leaving killer_format would make it "petrified by petrification" */ killer_format = NO_KILLER_PREFIX; killer = "killed by petrification"; } done(STONING); break; case SLIMED: if (delayed_killer && !killer) { killer = delayed_killer; delayed_killer = 0; } if (!killer) { killer_format = NO_KILLER_PREFIX; killer = "turned into green slime"; } done(TURNED_SLIME); break; case VOMITING: make_vomiting(0L, TRUE); break; case SICK: You("die from your illness."); killer_format = KILLED_BY_AN; killer = u.usick_cause; if ((m_idx = name_to_mon(killer)) >= LOW_PM) { if (type_is_pname(&mons[m_idx])) { killer_format = KILLED_BY; } else if (mons[m_idx].geno & G_UNIQ) { killer = the(killer); Strcpy(u.usick_cause, killer); killer_format = KILLED_BY; } } u.usick_type = 0; done(POISONING); break; case FAST: if (!Very_fast) You_feel("yourself slowing down%s.", Fast ? " a bit" : ""); break; case CONFUSION: HConfusion = 1; /* So make_confused works properly */ make_confused(0L, TRUE); stop_occupation(); break; case STUNNED: HStun = 1; make_stunned(0L, TRUE); stop_occupation(); break; case BLINDED: Blinded = 1; make_blinded(0L, TRUE); stop_occupation(); break; case INVIS: newsym(u.ux,u.uy); if (!Invis && !BInvis && !Blind) { You(!See_invisible ? "are no longer invisible." : "can no longer see through yourself."); stop_occupation(); } break; case SEE_INVIS: set_mimic_blocking(); /* do special mimic handling */ see_monsters(); /* make invis mons appear */ newsym(u.ux,u.uy); /* make self appear */ stop_occupation(); break; case WOUNDED_LEGS: heal_legs(); stop_occupation(); break; case HALLUC: HHallucination = 1; (void) make_hallucinated(0L, TRUE, 0L); stop_occupation(); break; case SLEEPING: if (unconscious() || Sleep_resistance) HSleeping += rnd(100); else if (Sleeping) { You("fall asleep."); sleeptime = rnd(20); fall_asleep(-sleeptime, TRUE); HSleeping += sleeptime + rnd(100); } break; case LEVITATION: (void) float_down(I_SPECIAL|TIMEOUT, 0L); break; case STRANGLED: killer_format = KILLED_BY; killer = (u.uburied) ? "suffocation" : "strangulation"; done(DIED); break; case FUMBLING: /* call this only when a move took place. */ /* otherwise handle fumbling msgs locally. */ if (u.umoved && !Levitation) { slip_or_trip(); nomul(-2); nomovemsg = ""; /* The more you are carrying the more likely you * are to make noise when you fumble. Adjustments * to this number must be thoroughly play tested. */ if ((inv_weight() > -500)) { You("make a lot of noise!"); wake_nearby(); } } /* from outside means slippery ice; don't reset counter if that's the only fumble reason */ HFumbling &= ~FROMOUTSIDE; if (Fumbling) HFumbling += rnd(20); break; case DETECT_MONSTERS: see_monsters(); break; } } run_timers(); } #endif /* OVL0 */ #ifdef OVL1 void fall_asleep(how_long, wakeup_msg) int how_long; boolean wakeup_msg; { stop_occupation(); nomul(how_long); /* generally don't notice sounds while sleeping */ if (wakeup_msg && multi == how_long) { /* caller can follow with a direct call to Hear_again() if there's a need to override this when wakeup_msg is true */ flags.soundok = 0; afternmv = Hear_again; /* this won't give any messages */ } /* early wakeup from combat won't be possible until next monster turn */ u.usleep = monstermoves; nomovemsg = wakeup_msg ? "You wake up." : You_can_move_again; } /* Attach an egg hatch timeout to the given egg. */ void attach_egg_hatch_timeout(egg) struct obj *egg; { int i; /* stop previous timer, if any */ (void) stop_timer(HATCH_EGG, (genericptr_t) egg); /* * Decide if and when to hatch the egg. The old hatch_it() code tried * once a turn from age 151 to 200 (inclusive), hatching if it rolled * a number x, 1<=x<=age, where x>150. This yields a chance of * hatching > 99.9993%. Mimic that here. */ for (i = (MAX_EGG_HATCH_TIME-50)+1; i <= MAX_EGG_HATCH_TIME; i++) if (rnd(i) > 150) { /* egg will hatch */ (void) start_timer((long)i, TIMER_OBJECT, HATCH_EGG, (genericptr_t)egg); break; } } /* prevent an egg from ever hatching */ void kill_egg(egg) struct obj *egg; { /* stop previous timer, if any */ (void) stop_timer(HATCH_EGG, (genericptr_t) egg); } /* timer callback routine: hatch the given egg */ void hatch_egg(arg, timeout) genericptr_t arg; long timeout; { struct obj *egg; struct monst *mon, *mon2; coord cc; xchar x, y; boolean yours, silent, knows_egg = FALSE; boolean cansee_hatchspot = FALSE; int i, mnum, hatchcount = 0; egg = (struct obj *) arg; /* sterilized while waiting */ if (egg->corpsenm == NON_PM) return; mon = mon2 = (struct monst *)0; mnum = big_to_little(egg->corpsenm); /* The identity of one's father is learned, not innate */ yours = (egg->spe || (!flags.female && carried(egg) && !rn2(2))); silent = (timeout != monstermoves); /* hatched while away */ /* only can hatch when in INVENT, FLOOR, MINVENT */ if (get_obj_location(egg, &x, &y, 0)) { hatchcount = rnd((int)egg->quan); cansee_hatchspot = cansee(x, y) && !silent; if (!(mons[mnum].geno & G_UNIQ) && !(mvitals[mnum].mvflags & (G_GENOD | G_EXTINCT))) { for (i = hatchcount; i > 0; i--) { if (!enexto(&cc, x, y, &mons[mnum]) || !(mon = makemon(&mons[mnum], cc.x, cc.y, NO_MINVENT))) break; /* tame if your own egg hatches while you're on the same dungeon level, or any dragon egg which hatches while it's in your inventory */ if ((yours && !silent) || (carried(egg) && mon->data->mlet == S_DRAGON)) { if ((mon2 = tamedog(mon, (struct obj *)0)) != 0) { mon = mon2; if (carried(egg) && mon->data->mlet != S_DRAGON) mon->mtame = 20; } } if (mvitals[mnum].mvflags & G_EXTINCT) break; /* just made last one */ mon2 = mon; /* in case makemon() fails on 2nd egg */ } if (!mon) mon = mon2; hatchcount -= i; egg->quan -= (long)hatchcount; } } #if 0 /* * We could possibly hatch while migrating, but the code isn't * set up for it... */ else if (obj->where == OBJ_MIGRATING) { /* We can do several things. The first ones that come to mind are: + Create the hatched monster then place it on the migrating mons list. This is tough because all makemon() is made to place the monster as well. Makemon() also doesn't lend itself well to splitting off a "not yet placed" subroutine. + Mark the egg as hatched, then place the monster when we place the migrating objects. + Or just kill any egg which gets sent to another level. Falling is the usual reason such transportation occurs. */ cansee_hatchspot = FALSE; mon = ??? } #endif if (mon) { char monnambuf[BUFSZ], carriedby[BUFSZ]; boolean siblings = (hatchcount > 1), redraw = FALSE; if (cansee_hatchspot) { Sprintf(monnambuf, "%s%s", siblings ? "some " : "", siblings ? makeplural(m_monnam(mon)) : an(m_monnam(mon))); /* we don't learn the egg type here because learning an egg type requires either seeing the egg hatch or being familiar with the egg already, as well as being able to see the resulting monster, checked below */ } switch (egg->where) { case OBJ_INVENT: knows_egg = TRUE; /* true even if you are blind */ if (!cansee_hatchspot) You_feel("%s %s from your pack!", something, locomotion(mon->data, "drop")); else You("see %s %s out of your pack!", monnambuf, locomotion(mon->data, "drop")); if (yours) { pline("%s cries sound like \"%s%s\"", siblings ? "Their" : "Its", flags.female ? "mommy" : "daddy", egg->spe ? "." : "?"); } else if (mon->data->mlet == S_DRAGON) { verbalize("Gleep!"); /* Mything eggs :-) */ } break; case OBJ_FLOOR: if (cansee_hatchspot) { knows_egg = TRUE; You("see %s hatch.", monnambuf); redraw = TRUE; /* update egg's map location */ } break; case OBJ_MINVENT: if (cansee_hatchspot) { /* egg carring monster might be invisible */ if (canseemon(egg->ocarry)) { Sprintf(carriedby, "%s pack", s_suffix(a_monnam(egg->ocarry))); knows_egg = TRUE; } else if (is_pool(mon->mx, mon->my)) Strcpy(carriedby, "empty water"); else Strcpy(carriedby, "thin air"); You("see %s %s out of %s!", monnambuf, locomotion(mon->data, "drop"), carriedby); } break; #if 0 case OBJ_MIGRATING: break; #endif default: impossible("egg hatched where? (%d)", (int)egg->where); break; } if (cansee_hatchspot && knows_egg) learn_egg_type(mnum); if (egg->quan > 0) { /* still some eggs left */ attach_egg_hatch_timeout(egg); if (egg->timed) { /* replace ordinary egg timeout with a short one */ (void) stop_timer(HATCH_EGG, (genericptr_t)egg); (void) start_timer((long)rnd(12), TIMER_OBJECT, HATCH_EGG, (genericptr_t)egg); } } else if (carried(egg)) { useup(egg); } else { /* free egg here because we use it above */ obj_extract_self(egg); obfree(egg, (struct obj *)0); } if (redraw) newsym(x, y); } } /* Learn to recognize eggs of the given type. */ void learn_egg_type(mnum) int mnum; { /* baby monsters hatch from grown-up eggs */ mnum = little_to_big(mnum); mvitals[mnum].mvflags |= MV_KNOWS_EGG; /* we might have just learned about other eggs being carried */ update_inventory(); } /* Attach a fig_transform timeout to the given figurine. */ void attach_fig_transform_timeout(figurine) struct obj *figurine; { int i; /* stop previous timer, if any */ (void) stop_timer(FIG_TRANSFORM, (genericptr_t) figurine); /* * Decide when to transform the figurine. */ i = rnd(9000) + 200; /* figurine will transform */ (void) start_timer((long)i, TIMER_OBJECT, FIG_TRANSFORM, (genericptr_t)figurine); } /* give a fumble message */ STATIC_OVL void slip_or_trip() { struct obj *otmp = vobj_at(u.ux, u.uy); const char *what, *pronoun; char buf[BUFSZ]; boolean on_foot = TRUE; #ifdef STEED if (u.usteed) on_foot = FALSE; #endif if (otmp && on_foot && !u.uinwater && is_pool(u.ux, u.uy)) otmp = 0; if (otmp && on_foot) { /* trip over something in particular */ /* If there is only one item, it will have just been named during the move, so refer to by via pronoun; otherwise, if the top item has been or can be seen, refer to it by name; if not, look for rocks to trip over; trip over anonymous "something" if there aren't any rocks. */ pronoun = otmp->quan == 1L ? "it" : Hallucination ? "they" : "them"; what = !otmp->nexthere ? pronoun : (otmp->dknown || !Blind) ? doname(otmp) : ((otmp = sobj_at(ROCK, u.ux, u.uy)) == 0 ? something : (otmp->quan == 1L ? "a rock" : "some rocks")); if (Hallucination) { what = strcpy(buf, what); buf[0] = highc(buf[0]); pline("Egads! %s bite%s your %s!", what, (!otmp || otmp->quan == 1L) ? "s" : "", body_part(FOOT)); } else { You("trip over %s.", what); } } else if (rn2(3) && is_ice(u.ux, u.uy)) { pline("%s %s%s on the ice.", #ifdef STEED u.usteed ? upstart(x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE)) : #endif "You", rn2(2) ? "slip" : "slide", on_foot ? "" : "s"); } else { if (on_foot) { switch (rn2(4)) { case 1: You("trip over your own %s.", Hallucination ? "elbow" : makeplural(body_part(FOOT))); break; case 2: You("slip %s.", Hallucination ? "on a banana peel" : "and nearly fall"); break; case 3: You("flounder."); break; default: You("stumble."); break; } } #ifdef STEED else { switch (rn2(4)) { case 1: Your("%s slip out of the stirrups.", makeplural(body_part(FOOT))); break; case 2: You("let go of the reins."); break; case 3: You("bang into the saddle-horn."); break; default: You("slide to one side of the saddle."); break; } dismount_steed(DISMOUNT_FELL); } #endif } } /* Print a lamp flicker message with tailer. */ STATIC_OVL void see_lamp_flicker(obj, tailer) struct obj *obj; const char *tailer; { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s flickers%s.", Yname2(obj), tailer); break; case OBJ_FLOOR: You("see %s flicker%s.", an(xname(obj)), tailer); break; } } /* Print a dimming message for brass lanterns. */ STATIC_OVL void lantern_message(obj) struct obj *obj; { /* from adventure */ switch (obj->where) { case OBJ_INVENT: Your("lantern is getting dim."); if (Hallucination) pline("Batteries have not been invented yet."); break; case OBJ_FLOOR: You("see a lantern getting dim."); break; case OBJ_MINVENT: pline("%s lantern is getting dim.", s_suffix(Monnam(obj->ocarry))); break; } } /* * Timeout callback for for objects that are burning. E.g. lamps, candles. * See begin_burn() for meanings of obj->age and obj->spe. */ void burn_object(arg, timeout) genericptr_t arg; long timeout; { struct obj *obj = (struct obj *) arg; boolean canseeit, many, menorah, need_newsym; xchar x, y; char whose[BUFSZ]; menorah = obj->otyp == CANDELABRUM_OF_INVOCATION; many = menorah ? obj->spe > 1 : obj->quan > 1L; /* timeout while away */ if (timeout != monstermoves) { long how_long = monstermoves - timeout; if (how_long >= obj->age) { obj->age = 0; end_burn(obj, FALSE); if (menorah) { obj->spe = 0; /* no more candles */ } else if (Is_candle(obj) || obj->otyp == POT_OIL) { /* get rid of candles and burning oil potions */ obj_extract_self(obj); obfree(obj, (struct obj *)0); obj = (struct obj *) 0; } } else { obj->age -= how_long; begin_burn(obj, TRUE); } return; } /* only interested in INVENT, FLOOR, and MINVENT */ if (get_obj_location(obj, &x, &y, 0)) { canseeit = !Blind && cansee(x, y); /* set up `whose[]' to be "Your" or "Fred's" or "The goblin's" */ (void) Shk_Your(whose, obj); } else { canseeit = FALSE; } need_newsym = FALSE; /* obj->age is the age remaining at this point. */ switch (obj->otyp) { case POT_OIL: /* this should only be called when we run out */ if (canseeit) { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s potion of oil has burnt away.", whose); break; case OBJ_FLOOR: You("see a burning potion of oil go out."); need_newsym = TRUE; break; } } end_burn(obj, FALSE); /* turn off light source */ obj_extract_self(obj); obfree(obj, (struct obj *)0); obj = (struct obj *) 0; break; case BRASS_LANTERN: case OIL_LAMP: switch((int)obj->age) { case 150: case 100: case 50: if (canseeit) { if (obj->otyp == BRASS_LANTERN) lantern_message(obj); else see_lamp_flicker(obj, obj->age == 50L ? " considerably" : ""); } break; case 25: if (canseeit) { if (obj->otyp == BRASS_LANTERN) lantern_message(obj); else { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s %s seems about to go out.", whose, xname(obj)); break; case OBJ_FLOOR: You("see %s about to go out.", an(xname(obj))); break; } } } break; case 0: /* even if blind you'll know if holding it */ if (canseeit || obj->where == OBJ_INVENT) { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: if (obj->otyp == BRASS_LANTERN) pline("%s lantern has run out of power.", whose); else pline("%s %s has gone out.", whose, xname(obj)); break; case OBJ_FLOOR: if (obj->otyp == BRASS_LANTERN) You("see a lantern run out of power."); else You("see %s go out.", an(xname(obj))); break; } } end_burn(obj, FALSE); break; default: /* * Someone added fuel to the lamp while it was * lit. Just fall through and let begin burn * handle the new age. */ break; } if (obj->age) begin_burn(obj, TRUE); break; case CANDELABRUM_OF_INVOCATION: case TALLOW_CANDLE: case WAX_CANDLE: switch (obj->age) { case 75: if (canseeit) switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s %scandle%s getting short.", whose, menorah ? "candelabrum's " : "", many ? "s are" : " is"); break; case OBJ_FLOOR: You("see %scandle%s getting short.", menorah ? "a candelabrum's " : many ? "some " : "a ", many ? "s" : ""); break; } break; case 15: if (canseeit) switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline( "%s %scandle%s flame%s flicker%s low!", whose, menorah ? "candelabrum's " : "", many ? "s'" : "'s", many ? "s" : "", many ? "" : "s"); break; case OBJ_FLOOR: You("see %scandle%s flame%s flicker low!", menorah ? "a candelabrum's " : many ? "some " : "a ", many ? "s'" : "'s", many ? "s" : ""); break; } break; case 0: /* we know even if blind and in our inventory */ if (canseeit || obj->where == OBJ_INVENT) { if (menorah) { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s candelabrum's flame%s.", whose, many ? "s die" : " dies"); break; case OBJ_FLOOR: You("see a candelabrum's flame%s die.", many ? "s" : ""); break; } } else { switch (obj->where) { case OBJ_INVENT: case OBJ_MINVENT: pline("%s %s %s consumed!", whose, xname(obj), many ? "are" : "is"); break; case OBJ_FLOOR: /* You see some wax candles consumed! You see a wax candle consumed! */ You("see %s%s consumed!", many ? "some " : "", many ? xname(obj):an(xname(obj))); need_newsym = TRUE; break; } /* post message */ pline(Hallucination ? (many ? "They shriek!" : "It shrieks!") : Blind ? "" : (many ? "Their flames die." : "Its flame dies.")); } } end_burn(obj, FALSE); if (menorah) { obj->spe = 0; } else { obj_extract_self(obj); obfree(obj, (struct obj *)0); obj = (struct obj *) 0; } break; default: /* * Someone added fuel (candles) to the menorah while * it was lit. Just fall through and let begin burn * handle the new age. */ break; } if (obj && obj->age) begin_burn(obj, TRUE); break; default: impossible("burn_object: unexpeced obj %s", xname(obj)); break; } if (need_newsym) newsym(x, y); } /* * Start a burn timeout on the given object. If not "already lit" then * create a light source for the vision system. There had better not * be a burn already running on the object. * * Magic lamps stay lit as long as there's a genie inside, so don't start * a timer. * * Burn rules: * potions of oil, lamps & candles: * age = # of turns of fuel left * spe = * * magic lamps: * age = * spe = 0 not lightable, 1 lightable forever * * candelabrum: * age = # of turns of fuel left * spe = # of candles * * Once the burn begins, the age will be set to the amount of fuel * remaining _once_the_burn_finishes_. If the burn is terminated * early then fuel is added back. * * This use of age differs from the use of age for corpses and eggs. * For the latter items, age is when the object was created, so we * know when it becomes "bad". * * This is a "silent" routine - it should not print anything out. */ void begin_burn(obj, already_lit) struct obj *obj; boolean already_lit; { int radius = 3; long turns = 0; boolean do_timer = TRUE; if (obj->age == 0 && obj->otyp != MAGIC_LAMP && !artifact_light(obj)) return; switch (obj->otyp) { case MAGIC_LAMP: obj->lamplit = 1; do_timer = FALSE; break; case POT_OIL: turns = obj->age; radius = 1; /* very dim light */ break; case BRASS_LANTERN: case OIL_LAMP: /* magic times are 150, 100, 50, 25, and 0 */ if (obj->age > 150L) turns = obj->age - 150L; else if (obj->age > 100L) turns = obj->age - 100L; else if (obj->age > 50L) turns = obj->age - 50L; else if (obj->age > 25L) turns = obj->age - 25L; else turns = obj->age; break; case CANDELABRUM_OF_INVOCATION: case TALLOW_CANDLE: case WAX_CANDLE: /* magic times are 75, 15, and 0 */ if (obj->age > 75L) turns = obj->age - 75L; else if (obj->age > 15L) turns = obj->age - 15L; else turns = obj->age; radius = candle_light_range(obj); break; default: /* [ALI] Support artifact light sources */ if (artifact_light(obj)) { obj->lamplit = 1; do_timer = FALSE; radius = 2; } else { impossible("begin burn: unexpected %s", xname(obj)); turns = obj->age; } break; } if (do_timer) { if (start_timer(turns, TIMER_OBJECT, BURN_OBJECT, (genericptr_t)obj)) { obj->lamplit = 1; obj->age -= turns; if (carried(obj) && !already_lit) update_inventory(); } else { obj->lamplit = 0; } } else { if (carried(obj) && !already_lit) update_inventory(); } if (obj->lamplit && !already_lit) { xchar x, y; if (get_obj_location(obj, &x, &y, CONTAINED_TOO|BURIED_TOO)) new_light_source(x, y, radius, LS_OBJECT, (genericptr_t) obj); else impossible("begin_burn: can't get obj position"); } } /* * Stop a burn timeout on the given object if timer attached. Darken * light source. */ void end_burn(obj, timer_attached) struct obj *obj; boolean timer_attached; { if (!obj->lamplit) { impossible("end_burn: obj %s not lit", xname(obj)); return; } if (obj->otyp == MAGIC_LAMP || artifact_light(obj)) timer_attached = FALSE; if (!timer_attached) { /* [DS] Cleanup explicitly, since timer cleanup won't happen */ del_light_source(LS_OBJECT, (genericptr_t)obj); obj->lamplit = 0; if (obj->where == OBJ_INVENT) update_inventory(); } else if (!stop_timer(BURN_OBJECT, (genericptr_t) obj)) impossible("end_burn: obj %s not timed!", xname(obj)); } #endif /* OVL1 */ #ifdef OVL0 /* * Cleanup a burning object if timer stopped. */ static void cleanup_burn(arg, expire_time) genericptr_t arg; long expire_time; { struct obj *obj = (struct obj *)arg; if (!obj->lamplit) { impossible("cleanup_burn: obj %s not lit", xname(obj)); return; } del_light_source(LS_OBJECT, arg); /* restore unused time */ obj->age += expire_time - monstermoves; obj->lamplit = 0; if (obj->where == OBJ_INVENT) update_inventory(); } #endif /* OVL0 */ #ifdef OVL1 void do_storms() { int nstrike; register int x, y; int dirx, diry; int count; /* no lightning if not the air level or too often, even then */ if(!Is_airlevel(&u.uz) || rn2(8)) return; /* the number of strikes is 8-log2(nstrike) */ for(nstrike = rnd(64); nstrike <= 64; nstrike *= 2) { count = 0; do { x = rnd(COLNO-1); y = rn2(ROWNO); } while (++count < 100 && levl[x][y].typ != CLOUD); if(count < 100) { dirx = rn2(3) - 1; diry = rn2(3) - 1; if(dirx != 0 || diry != 0) buzz(-15, /* "monster" LIGHTNING spell */ 8, x, y, dirx, diry); } } if(levl[u.ux][u.uy].typ == CLOUD) { /* inside a cloud during a thunder storm is deafening */ pline("Kaboom!!! Boom!! Boom!!"); if(!u.uinvulnerable) { stop_occupation(); nomul(-3); } } else You_hear("a rumbling noise."); } #endif /* OVL1 */ #ifdef OVL0 /* ------------------------------------------------------------------------- */ /* * Generic Timeout Functions. * * Interface: * * General: * boolean start_timer(long timeout,short kind,short func_index, * genericptr_t arg) * Start a timer of kind 'kind' that will expire at time * monstermoves+'timeout'. Call the function at 'func_index' * in the timeout table using argument 'arg'. Return TRUE if * a timer was started. This places the timer on a list ordered * "sooner" to "later". If an object, increment the object's * timer count. * * long stop_timer(short func_index, genericptr_t arg) * Stop a timer specified by the (func_index, arg) pair. This * assumes that such a pair is unique. Return the time the * timer would have gone off. If no timer is found, return 0. * If an object, decrement the object's timer count. * * void run_timers(void) * Call timers that have timed out. * * * Save/Restore: * void save_timers(int fd, int mode, int range) * Save all timers of range 'range'. Range is either global * or local. Global timers follow game play, local timers * are saved with a level. Object and monster timers are * saved using their respective id's instead of pointers. * * void restore_timers(int fd, int range, boolean ghostly, long adjust) * Restore timers of range 'range'. If from a ghost pile, * adjust the timeout by 'adjust'. The object and monster * ids are not restored until later. * * void relink_timers(boolean ghostly) * Relink all object and monster timers that had been saved * using their object's or monster's id number. * * Object Specific: * void obj_move_timers(struct obj *src, struct obj *dest) * Reassign all timers from src to dest. * * void obj_split_timers(struct obj *src, struct obj *dest) * Duplicate all timers assigned to src and attach them to dest. * * void obj_stop_timers(struct obj *obj) * Stop all timers attached to obj. */ #ifdef WIZARD STATIC_DCL const char *FDECL(kind_name, (SHORT_P)); STATIC_DCL void FDECL(print_queue, (winid, timer_element *)); #endif STATIC_DCL void FDECL(insert_timer, (timer_element *)); STATIC_DCL timer_element *FDECL(remove_timer, (timer_element **, SHORT_P, genericptr_t)); STATIC_DCL void FDECL(write_timer, (int, timer_element *)); STATIC_DCL boolean FDECL(mon_is_local, (struct monst *)); STATIC_DCL boolean FDECL(timer_is_local, (timer_element *)); STATIC_DCL int FDECL(maybe_write_timer, (int, int, BOOLEAN_P)); /* ordered timer list */ static timer_element *timer_base; /* "active" */ static unsigned long timer_id = 1; /* If defined, then include names when printing out the timer queue */ #define VERBOSE_TIMER typedef struct { timeout_proc f, cleanup; #ifdef VERBOSE_TIMER const char *name; # define TTAB(a, b, c) {a,b,c} #else # define TTAB(a, b, c) {a,b} #endif } ttable; /* table of timeout functions */ static const ttable timeout_funcs[NUM_TIME_FUNCS] = { TTAB(rot_organic, (timeout_proc)0, "rot_organic"), TTAB(rot_corpse, (timeout_proc)0, "rot_corpse"), TTAB(revive_mon, (timeout_proc)0, "revive_mon"), TTAB(burn_object, cleanup_burn, "burn_object"), TTAB(hatch_egg, (timeout_proc)0, "hatch_egg"), TTAB(fig_transform, (timeout_proc)0, "fig_transform") }; #undef TTAB #if defined(WIZARD) STATIC_OVL const char * kind_name(kind) short kind; { switch (kind) { case TIMER_LEVEL: return "level"; case TIMER_GLOBAL: return "global"; case TIMER_OBJECT: return "object"; case TIMER_MONSTER: return "monster"; } return "unknown"; } STATIC_OVL void print_queue(win, base) winid win; timer_element *base; { timer_element *curr; char buf[BUFSZ], arg_address[20]; if (!base) { putstr(win, 0, ""); } else { putstr(win, 0, "timeout id kind call"); for (curr = base; curr; curr = curr->next) { #ifdef VERBOSE_TIMER Sprintf(buf, " %4ld %4ld %-6s %s(%s)", curr->timeout, curr->tid, kind_name(curr->kind), timeout_funcs[curr->func_index].name, fmt_ptr((genericptr_t)curr->arg, arg_address)); #else Sprintf(buf, " %4ld %4ld %-6s #%d(%s)", curr->timeout, curr->tid, kind_name(curr->kind), curr->func_index, fmt_ptr((genericptr_t)curr->arg, arg_address)); #endif putstr(win, 0, buf); } } } int wiz_timeout_queue() { winid win; char buf[BUFSZ]; win = create_nhwindow(NHW_MENU); /* corner text window */ if (win == WIN_ERR) return 0; Sprintf(buf, "Current time = %ld.", monstermoves); putstr(win, 0, buf); putstr(win, 0, ""); putstr(win, 0, "Active timeout queue:"); putstr(win, 0, ""); print_queue(win, timer_base); display_nhwindow(win, FALSE); destroy_nhwindow(win); return 0; } void timer_sanity_check() { timer_element *curr; char obj_address[20]; /* this should be much more complete */ for (curr = timer_base; curr; curr = curr->next) if (curr->kind == TIMER_OBJECT) { struct obj *obj = (struct obj *) curr->arg; if (obj->timed == 0) { pline("timer sanity: untimed obj %s, timer %ld", fmt_ptr((genericptr_t)obj, obj_address), curr->tid); } } } #endif /* WIZARD */ /* * Pick off timeout elements from the global queue and call their functions. * Do this until their time is less than or equal to the move count. */ void run_timers() { timer_element *curr; /* * Always use the first element. Elements may be added or deleted at * any time. The list is ordered, we are done when the first element * is in the future. */ while (timer_base && timer_base->timeout <= monstermoves) { curr = timer_base; timer_base = curr->next; if (curr->kind == TIMER_OBJECT) ((struct obj *)(curr->arg))->timed--; (*timeout_funcs[curr->func_index].f)(curr->arg, curr->timeout); free((genericptr_t) curr); } } /* * Start a timer. Return TRUE if successful. */ boolean start_timer(when, kind, func_index, arg) long when; short kind; short func_index; genericptr_t arg; { timer_element *gnu; if (func_index < 0 || func_index >= NUM_TIME_FUNCS) panic("start_timer"); gnu = (timer_element *) alloc(sizeof(timer_element)); gnu->next = 0; gnu->tid = timer_id++; gnu->timeout = monstermoves + when; gnu->kind = kind; gnu->needs_fixup = 0; gnu->func_index = func_index; gnu->arg = arg; insert_timer(gnu); if (kind == TIMER_OBJECT) /* increment object's timed count */ ((struct obj *)arg)->timed++; /* should check for duplicates and fail if any */ return TRUE; } /* * Remove the timer from the current list and free it up. Return the time * it would have gone off, 0 if not found. */ long stop_timer(func_index, arg) short func_index; genericptr_t arg; { timer_element *doomed; long timeout; doomed = remove_timer(&timer_base, func_index, arg); if (doomed) { timeout = doomed->timeout; if (doomed->kind == TIMER_OBJECT) ((struct obj *)arg)->timed--; if (timeout_funcs[doomed->func_index].cleanup) (*timeout_funcs[doomed->func_index].cleanup)(arg, timeout); free((genericptr_t) doomed); return timeout; } return 0; } /* * Move all object timers from src to dest, leaving src untimed. */ void obj_move_timers(src, dest) struct obj *src, *dest; { int count; timer_element *curr; for (count = 0, curr = timer_base; curr; curr = curr->next) if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)src) { curr->arg = (genericptr_t) dest; dest->timed++; count++; } if (count != src->timed) panic("obj_move_timers"); src->timed = 0; } /* * Find all object timers and duplicate them for the new object "dest". */ void obj_split_timers(src, dest) struct obj *src, *dest; { timer_element *curr, *next_timer=0; for (curr = timer_base; curr; curr = next_timer) { next_timer = curr->next; /* things may be inserted */ if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)src) { (void) start_timer(curr->timeout-monstermoves, TIMER_OBJECT, curr->func_index, (genericptr_t)dest); } } } /* * Stop all timers attached to this object. We can get away with this because * all object pointers are unique. */ void obj_stop_timers(obj) struct obj *obj; { timer_element *curr, *prev, *next_timer=0; for (prev = 0, curr = timer_base; curr; curr = next_timer) { next_timer = curr->next; if (curr->kind == TIMER_OBJECT && curr->arg == (genericptr_t)obj) { if (prev) prev->next = curr->next; else timer_base = curr->next; if (timeout_funcs[curr->func_index].cleanup) (*timeout_funcs[curr->func_index].cleanup)(curr->arg, curr->timeout); free((genericptr_t) curr); } else { prev = curr; } } obj->timed = 0; } /* Insert timer into the global queue */ STATIC_OVL void insert_timer(gnu) timer_element *gnu; { timer_element *curr, *prev; for (prev = 0, curr = timer_base; curr; prev = curr, curr = curr->next) if (curr->timeout >= gnu->timeout) break; gnu->next = curr; if (prev) prev->next = gnu; else timer_base = gnu; } STATIC_OVL timer_element * remove_timer(base, func_index, arg) timer_element **base; short func_index; genericptr_t arg; { timer_element *prev, *curr; for (prev = 0, curr = *base; curr; prev = curr, curr = curr->next) if (curr->func_index == func_index && curr->arg == arg) break; if (curr) { if (prev) prev->next = curr->next; else *base = curr->next; } return curr; } STATIC_OVL void write_timer(fd, timer) int fd; timer_element *timer; { genericptr_t arg_save; switch (timer->kind) { case TIMER_GLOBAL: case TIMER_LEVEL: /* assume no pointers in arg */ bwrite(fd, (genericptr_t) timer, sizeof(timer_element)); break; case TIMER_OBJECT: if (timer->needs_fixup) bwrite(fd, (genericptr_t)timer, sizeof(timer_element)); else { /* replace object pointer with id */ arg_save = timer->arg; timer->arg = (genericptr_t)((struct obj *)timer->arg)->o_id; timer->needs_fixup = 1; bwrite(fd, (genericptr_t)timer, sizeof(timer_element)); timer->arg = arg_save; timer->needs_fixup = 0; } break; case TIMER_MONSTER: if (timer->needs_fixup) bwrite(fd, (genericptr_t)timer, sizeof(timer_element)); else { /* replace monster pointer with id */ arg_save = timer->arg; timer->arg = (genericptr_t)((struct monst *)timer->arg)->m_id; timer->needs_fixup = 1; bwrite(fd, (genericptr_t)timer, sizeof(timer_element)); timer->arg = arg_save; timer->needs_fixup = 0; } break; default: panic("write_timer"); break; } } /* * Return TRUE if the object will stay on the level when the level is * saved. */ boolean obj_is_local(obj) struct obj *obj; { switch (obj->where) { case OBJ_INVENT: case OBJ_MIGRATING: return FALSE; case OBJ_FLOOR: case OBJ_BURIED: return TRUE; case OBJ_CONTAINED: return obj_is_local(obj->ocontainer); case OBJ_MINVENT: return mon_is_local(obj->ocarry); } panic("obj_is_local"); return FALSE; } /* * Return TRUE if the given monster will stay on the level when the * level is saved. */ STATIC_OVL boolean mon_is_local(mon) struct monst *mon; { struct monst *curr; for (curr = migrating_mons; curr; curr = curr->nmon) if (curr == mon) return FALSE; /* `mydogs' is used during level changes, never saved and restored */ for (curr = mydogs; curr; curr = curr->nmon) if (curr == mon) return FALSE; return TRUE; } /* * Return TRUE if the timer is attached to something that will stay on the * level when the level is saved. */ STATIC_OVL boolean timer_is_local(timer) timer_element *timer; { switch (timer->kind) { case TIMER_LEVEL: return TRUE; case TIMER_GLOBAL: return FALSE; case TIMER_OBJECT: return obj_is_local((struct obj *)timer->arg); case TIMER_MONSTER: return mon_is_local((struct monst *)timer->arg); } panic("timer_is_local"); return FALSE; } /* * Part of the save routine. Count up the number of timers that would * be written. If write_it is true, actually write the timer. */ STATIC_OVL int maybe_write_timer(fd, range, write_it) int fd, range; boolean write_it; { int count = 0; timer_element *curr; for (curr = timer_base; curr; curr = curr->next) { if (range == RANGE_GLOBAL) { /* global timers */ if (!timer_is_local(curr)) { count++; if (write_it) write_timer(fd, curr); } } else { /* local timers */ if (timer_is_local(curr)) { count++; if (write_it) write_timer(fd, curr); } } } return count; } /* * Save part of the timer list. The parameter 'range' specifies either * global or level timers to save. The timer ID is saved with the global * timers. * * Global range: * + timeouts that follow the hero (global) * + timeouts that follow obj & monst that are migrating * * Level range: * + timeouts that are level specific (e.g. storms) * + timeouts that stay with the level (obj & monst) */ void save_timers(fd, mode, range) int fd, mode, range; { timer_element *curr, *prev, *next_timer=0; int count; if (perform_bwrite(mode)) { if (range == RANGE_GLOBAL) bwrite(fd, (genericptr_t) &timer_id, sizeof(timer_id)); count = maybe_write_timer(fd, range, FALSE); bwrite(fd, (genericptr_t) &count, sizeof count); (void) maybe_write_timer(fd, range, TRUE); } if (release_data(mode)) { for (prev = 0, curr = timer_base; curr; curr = next_timer) { next_timer = curr->next; /* in case curr is removed */ if ( !(!!(range == RANGE_LEVEL) ^ !!timer_is_local(curr)) ) { if (prev) prev->next = curr->next; else timer_base = curr->next; free((genericptr_t) curr); /* prev stays the same */ } else { prev = curr; } } } } /* * Pull in the structures from disk, but don't recalculate the object and * monster pointers. */ void restore_timers(fd, range, ghostly, adjust) int fd, range; boolean ghostly; /* restoring from a ghost level */ long adjust; /* how much to adjust timeout */ { int count; timer_element *curr; if (range == RANGE_GLOBAL) mread(fd, (genericptr_t) &timer_id, sizeof timer_id); /* restore elements */ mread(fd, (genericptr_t) &count, sizeof count); while (count-- > 0) { curr = (timer_element *) alloc(sizeof(timer_element)); mread(fd, (genericptr_t) curr, sizeof(timer_element)); if (ghostly) curr->timeout += adjust; insert_timer(curr); } } /* reset all timers that are marked for reseting */ void relink_timers(ghostly) boolean ghostly; { timer_element *curr; unsigned nid; for (curr = timer_base; curr; curr = curr->next) { if (curr->needs_fixup) { if (curr->kind == TIMER_OBJECT) { if (ghostly) { if (!lookup_id_mapping((unsigned)curr->arg, &nid)) panic("relink_timers 1"); } else nid = (unsigned) curr->arg; curr->arg = (genericptr_t) find_oid(nid); if (!curr->arg) panic("cant find o_id %d", nid); curr->needs_fixup = 0; } else if (curr->kind == TIMER_MONSTER) { panic("relink_timers: no monster timer implemented"); } else panic("relink_timers 2"); } } } #endif /* OVL0 */ /*timeout.c*/ nethack-3.4.3/src/topten.c0100644000000000000000000006225207764735041014125 0ustar rootroot/* SCCS Id: @(#)topten.c 3.4 2000/01/21 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #ifdef VMS /* We don't want to rewrite the whole file, because that entails */ /* creating a new version which requires that the old one be deletable. */ # define UPDATE_RECORD_IN_PLACE #endif /* * Updating in place can leave junk at the end of the file in some * circumstances (if it shrinks and the O.S. doesn't have a straightforward * way to truncate it). The trailing junk is harmless and the code * which reads the scores will ignore it. */ #ifdef UPDATE_RECORD_IN_PLACE static long final_fpos; #endif #define done_stopprint program_state.stopprint #define newttentry() (struct toptenentry *) alloc(sizeof(struct toptenentry)) #define dealloc_ttentry(ttent) free((genericptr_t) (ttent)) #define NAMSZ 10 #define DTHSZ 100 #define ROLESZ 3 #define PERSMAX 3 /* entries per name/uid per char. allowed */ #define POINTSMIN 1 /* must be > 0 */ #define ENTRYMAX 100 /* must be >= 10 */ #if !defined(MICRO) && !defined(MAC) && !defined(WIN32) #define PERS_IS_UID /* delete for PERSMAX per name; now per uid */ #endif struct toptenentry { struct toptenentry *tt_next; #ifdef UPDATE_RECORD_IN_PLACE long fpos; #endif long points; int deathdnum, deathlev; int maxlvl, hp, maxhp, deaths; int ver_major, ver_minor, patchlevel; long deathdate, birthdate; int uid; char plrole[ROLESZ+1]; char plrace[ROLESZ+1]; char plgend[ROLESZ+1]; char plalign[ROLESZ+1]; char name[NAMSZ+1]; char death[DTHSZ+1]; } *tt_head; STATIC_DCL void FDECL(topten_print, (const char *)); STATIC_DCL void FDECL(topten_print_bold, (const char *)); STATIC_DCL xchar FDECL(observable_depth, (d_level *)); STATIC_DCL void NDECL(outheader); STATIC_DCL void FDECL(outentry, (int,struct toptenentry *,BOOLEAN_P)); STATIC_DCL void FDECL(readentry, (FILE *,struct toptenentry *)); STATIC_DCL void FDECL(writeentry, (FILE *,struct toptenentry *)); STATIC_DCL void FDECL(free_ttlist, (struct toptenentry *)); STATIC_DCL int FDECL(classmon, (char *,BOOLEAN_P)); STATIC_DCL int FDECL(score_wanted, (BOOLEAN_P, int,struct toptenentry *,int,const char **,int)); #ifdef NO_SCAN_BRACK STATIC_DCL void FDECL(nsb_mung_line,(char*)); STATIC_DCL void FDECL(nsb_unmung_line,(char*)); #endif /* must fit with end.c; used in rip.c */ NEARDATA const char * const killed_by_prefix[] = { "killed by ", "choked on ", "poisoned by ", "died of ", "drowned in ", "burned by ", "dissolved in ", "crushed to death by ", "petrified by ", "turned to slime by ", "killed by ", "", "", "", "", "" }; static winid toptenwin = WIN_ERR; STATIC_OVL void topten_print(x) const char *x; { if (toptenwin == WIN_ERR) raw_print(x); else putstr(toptenwin, ATR_NONE, x); } STATIC_OVL void topten_print_bold(x) const char *x; { if (toptenwin == WIN_ERR) raw_print_bold(x); else putstr(toptenwin, ATR_BOLD, x); } STATIC_OVL xchar observable_depth(lev) d_level *lev; { #if 0 /* if we ever randomize the order of the elemental planes, we must use a constant external representation in the record file */ if (In_endgame(lev)) { if (Is_astralevel(lev)) return -5; else if (Is_waterlevel(lev)) return -4; else if (Is_firelevel(lev)) return -3; else if (Is_airlevel(lev)) return -2; else if (Is_earthlevel(lev)) return -1; else return 0; /* ? */ } else #endif return depth(lev); } STATIC_OVL void readentry(rfile,tt) FILE *rfile; struct toptenentry *tt; { #ifdef NO_SCAN_BRACK /* Version_ Pts DgnLevs_ Hp___ Died__Born id */ static const char fmt[] = "%d %d %d %ld %d %d %d %d %d %d %ld %ld %d%*c"; static const char fmt32[] = "%c%c %s %s%*c"; static const char fmt33[] = "%s %s %s %s %s %s%*c"; #else static const char fmt[] = "%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d "; static const char fmt32[] = "%c%c %[^,],%[^\n]%*c"; static const char fmt33[] = "%s %s %s %s %[^,],%[^\n]%*c"; #endif #ifdef UPDATE_RECORD_IN_PLACE /* note: fscanf() below must read the record's terminating newline */ final_fpos = tt->fpos = ftell(rfile); #endif #define TTFIELDS 13 if(fscanf(rfile, fmt, &tt->ver_major, &tt->ver_minor, &tt->patchlevel, &tt->points, &tt->deathdnum, &tt->deathlev, &tt->maxlvl, &tt->hp, &tt->maxhp, &tt->deaths, &tt->deathdate, &tt->birthdate, &tt->uid) != TTFIELDS) #undef TTFIELDS tt->points = 0; else { /* Check for backwards compatibility */ if (tt->ver_major < 3 || (tt->ver_major == 3 && tt->ver_minor < 3)) { int i; if (fscanf(rfile, fmt32, tt->plrole, tt->plgend, tt->name, tt->death) != 4) tt->points = 0; tt->plrole[1] = '\0'; if ((i = str2role(tt->plrole)) >= 0) Strcpy(tt->plrole, roles[i].filecode); Strcpy(tt->plrace, "?"); Strcpy(tt->plgend, (tt->plgend[0] == 'M') ? "Mal" : "Fem"); Strcpy(tt->plalign, "?"); } else if (fscanf(rfile, fmt33, tt->plrole, tt->plrace, tt->plgend, tt->plalign, tt->name, tt->death) != 6) tt->points = 0; #ifdef NO_SCAN_BRACK if(tt->points > 0) { nsb_unmung_line(tt->name); nsb_unmung_line(tt->death); } #endif } /* check old score entries for Y2K problem and fix whenever found */ if (tt->points > 0) { if (tt->birthdate < 19000000L) tt->birthdate += 19000000L; if (tt->deathdate < 19000000L) tt->deathdate += 19000000L; } } STATIC_OVL void writeentry(rfile,tt) FILE *rfile; struct toptenentry *tt; { #ifdef NO_SCAN_BRACK nsb_mung_line(tt->name); nsb_mung_line(tt->death); /* Version_ Pts DgnLevs_ Hp___ Died__Born id */ (void) fprintf(rfile,"%d %d %d %ld %d %d %d %d %d %d %ld %ld %d ", #else (void) fprintf(rfile,"%d.%d.%d %ld %d %d %d %d %d %d %ld %ld %d ", #endif tt->ver_major, tt->ver_minor, tt->patchlevel, tt->points, tt->deathdnum, tt->deathlev, tt->maxlvl, tt->hp, tt->maxhp, tt->deaths, tt->deathdate, tt->birthdate, tt->uid); if (tt->ver_major < 3 || (tt->ver_major == 3 && tt->ver_minor < 3)) #ifdef NO_SCAN_BRACK (void) fprintf(rfile,"%c%c %s %s\n", #else (void) fprintf(rfile,"%c%c %s,%s\n", #endif tt->plrole[0], tt->plgend[0], onlyspace(tt->name) ? "_" : tt->name, tt->death); else #ifdef NO_SCAN_BRACK (void) fprintf(rfile,"%s %s %s %s %s %s\n", #else (void) fprintf(rfile,"%s %s %s %s %s,%s\n", #endif tt->plrole, tt->plrace, tt->plgend, tt->plalign, onlyspace(tt->name) ? "_" : tt->name, tt->death); #ifdef NO_SCAN_BRACK nsb_unmung_line(tt->name); nsb_unmung_line(tt->death); #endif } STATIC_OVL void free_ttlist(tt) struct toptenentry *tt; { struct toptenentry *ttnext; while (tt->points > 0) { ttnext = tt->tt_next; dealloc_ttentry(tt); tt = ttnext; } dealloc_ttentry(tt); } void topten(how) int how; { int uid = getuid(); int rank, rank0 = -1, rank1 = 0; int occ_cnt = PERSMAX; register struct toptenentry *t0, *tprev; struct toptenentry *t1; FILE *rfile; register int flg = 0; boolean t0_used; #ifdef LOGFILE FILE *lfile; #endif /* LOGFILE */ /* Under DICE 3.0, this crashes the system consistently, apparently due to * corruption of *rfile somewhere. Until I figure this out, just cut out * topten support entirely - at least then the game exits cleanly. --AC */ #ifdef _DCC return; #endif /* If we are in the midst of a panic, cut out topten entirely. * topten uses alloc() several times, which will lead to * problems if the panic was the result of an alloc() failure. */ if (program_state.panicking) return; if (flags.toptenwin) { toptenwin = create_nhwindow(NHW_TEXT); } #if defined(UNIX) || defined(VMS) || defined(__EMX__) #define HUP if (!program_state.done_hup) #else #define HUP #endif #ifdef TOS restore_colors(); /* make sure the screen is black on white */ #endif /* create a new 'topten' entry */ t0_used = FALSE; t0 = newttentry(); /* deepest_lev_reached() is in terms of depth(), and reporting the * deepest level reached in the dungeon death occurred in doesn't * seem right, so we have to report the death level in depth() terms * as well (which also seems reasonable since that's all the player * sees on the screen anyway) */ t0->ver_major = VERSION_MAJOR; t0->ver_minor = VERSION_MINOR; t0->patchlevel = PATCHLEVEL; t0->points = u.urexp; t0->deathdnum = u.uz.dnum; t0->deathlev = observable_depth(&u.uz); t0->maxlvl = deepest_lev_reached(TRUE); t0->hp = u.uhp; t0->maxhp = u.uhpmax; t0->deaths = u.umortality; t0->uid = uid; (void) strncpy(t0->plrole, urole.filecode, ROLESZ); t0->plrole[ROLESZ] = '\0'; (void) strncpy(t0->plrace, urace.filecode, ROLESZ); t0->plrace[ROLESZ] = '\0'; (void) strncpy(t0->plgend, genders[flags.female].filecode, ROLESZ); t0->plgend[ROLESZ] = '\0'; (void) strncpy(t0->plalign, aligns[1-u.ualign.type].filecode, ROLESZ); t0->plalign[ROLESZ] = '\0'; (void) strncpy(t0->name, plname, NAMSZ); t0->name[NAMSZ] = '\0'; t0->death[0] = '\0'; switch (killer_format) { default: impossible("bad killer format?"); case KILLED_BY_AN: Strcat(t0->death, killed_by_prefix[how]); (void) strncat(t0->death, an(killer), DTHSZ-strlen(t0->death)); break; case KILLED_BY: Strcat(t0->death, killed_by_prefix[how]); (void) strncat(t0->death, killer, DTHSZ-strlen(t0->death)); break; case NO_KILLER_PREFIX: (void) strncat(t0->death, killer, DTHSZ); break; } t0->birthdate = yyyymmdd(u.ubirthday); t0->deathdate = yyyymmdd((time_t)0L); t0->tt_next = 0; #ifdef UPDATE_RECORD_IN_PLACE t0->fpos = -1L; #endif #ifdef LOGFILE /* used for debugging (who dies of what, where) */ if (lock_file(LOGFILE, SCOREPREFIX, 10)) { if(!(lfile = fopen_datafile(LOGFILE, "a", SCOREPREFIX))) { HUP raw_print("Cannot open log file!"); } else { writeentry(lfile, t0); (void) fclose(lfile); } unlock_file(LOGFILE); } #endif /* LOGFILE */ if (wizard || discover) { if (how != PANICKED) HUP { char pbuf[BUFSZ]; topten_print(""); Sprintf(pbuf, "Since you were in %s mode, the score list will not be checked.", wizard ? "wizard" : "discover"); topten_print(pbuf); } goto showwin; } if (!lock_file(RECORD, SCOREPREFIX, 60)) goto destroywin; #ifdef UPDATE_RECORD_IN_PLACE rfile = fopen_datafile(RECORD, "r+", SCOREPREFIX); #else rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); #endif if (!rfile) { HUP raw_print("Cannot open record file!"); unlock_file(RECORD); goto destroywin; } HUP topten_print(""); /* assure minimum number of points */ if(t0->points < POINTSMIN) t0->points = 0; t1 = tt_head = newttentry(); tprev = 0; /* rank0: -1 undefined, 0 not_on_list, n n_th on list */ for(rank = 1; ; ) { readentry(rfile, t1); if (t1->points < POINTSMIN) t1->points = 0; if(rank0 < 0 && t1->points < t0->points) { rank0 = rank++; if(tprev == 0) tt_head = t0; else tprev->tt_next = t0; t0->tt_next = t1; #ifdef UPDATE_RECORD_IN_PLACE t0->fpos = t1->fpos; /* insert here */ #endif t0_used = TRUE; occ_cnt--; flg++; /* ask for a rewrite */ } else tprev = t1; if(t1->points == 0) break; if( #ifdef PERS_IS_UID t1->uid == t0->uid && #else strncmp(t1->name, t0->name, NAMSZ) == 0 && #endif !strncmp(t1->plrole, t0->plrole, ROLESZ) && --occ_cnt <= 0) { if(rank0 < 0) { rank0 = 0; rank1 = rank; HUP { char pbuf[BUFSZ]; Sprintf(pbuf, "You didn't beat your previous score of %ld points.", t1->points); topten_print(pbuf); topten_print(""); } } if(occ_cnt < 0) { flg++; continue; } } if(rank <= ENTRYMAX) { t1->tt_next = newttentry(); t1 = t1->tt_next; rank++; } if(rank > ENTRYMAX) { t1->points = 0; break; } } if(flg) { /* rewrite record file */ #ifdef UPDATE_RECORD_IN_PLACE (void) fseek(rfile, (t0->fpos >= 0 ? t0->fpos : final_fpos), SEEK_SET); #else (void) fclose(rfile); if(!(rfile = fopen_datafile(RECORD, "w", SCOREPREFIX))){ HUP raw_print("Cannot write record file"); unlock_file(RECORD); free_ttlist(tt_head); goto destroywin; } #endif /* UPDATE_RECORD_IN_PLACE */ if(!done_stopprint) if(rank0 > 0){ if(rank0 <= 10) topten_print("You made the top ten list!"); else { char pbuf[BUFSZ]; Sprintf(pbuf, "You reached the %d%s place on the top %d list.", rank0, ordin(rank0), ENTRYMAX); topten_print(pbuf); } topten_print(""); } } if(rank0 == 0) rank0 = rank1; if(rank0 <= 0) rank0 = rank; if(!done_stopprint) outheader(); t1 = tt_head; for(rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { if(flg #ifdef UPDATE_RECORD_IN_PLACE && rank >= rank0 #endif ) writeentry(rfile, t1); if (done_stopprint) continue; if (rank > flags.end_top && (rank < rank0 - flags.end_around || rank > rank0 + flags.end_around) && (!flags.end_own || #ifdef PERS_IS_UID t1->uid != t0->uid #else strncmp(t1->name, t0->name, NAMSZ) #endif )) continue; if (rank == rank0 - flags.end_around && rank0 > flags.end_top + flags.end_around + 1 && !flags.end_own) topten_print(""); if(rank != rank0) outentry(rank, t1, FALSE); else if(!rank1) outentry(rank, t1, TRUE); else { outentry(rank, t1, TRUE); outentry(0, t0, TRUE); } } if(rank0 >= rank) if(!done_stopprint) outentry(0, t0, TRUE); #ifdef UPDATE_RECORD_IN_PLACE if (flg) { # ifdef TRUNCATE_FILE /* if a reasonable way to truncate a file exists, use it */ truncate_file(rfile); # else /* use sentinel record rather than relying on truncation */ t1->points = 0L; /* terminates file when read back in */ t1->ver_major = t1->ver_minor = t1->patchlevel = 0; t1->uid = t1->deathdnum = t1->deathlev = 0; t1->maxlvl = t1->hp = t1->maxhp = t1->deaths = 0; t1->plrole[0] = t1->plrace[0] = t1->plgend[0] = t1->plalign[0] = '-'; t1->plrole[1] = t1->plrace[1] = t1->plgend[1] = t1->plalign[1] = 0; t1->birthdate = t1->deathdate = yyyymmdd((time_t)0L); Strcpy(t1->name, "@"); Strcpy(t1->death, "\n"); writeentry(rfile, t1); (void) fflush(rfile); # endif /* TRUNCATE_FILE */ } #endif /* UPDATE_RECORD_IN_PLACE */ (void) fclose(rfile); unlock_file(RECORD); free_ttlist(tt_head); showwin: if (flags.toptenwin && !done_stopprint) display_nhwindow(toptenwin, 1); destroywin: if (!t0_used) dealloc_ttentry(t0); if (flags.toptenwin) { destroy_nhwindow(toptenwin); toptenwin=WIN_ERR; } } STATIC_OVL void outheader() { char linebuf[BUFSZ]; register char *bp; Strcpy(linebuf, " No Points Name"); bp = eos(linebuf); while(bp < linebuf + COLNO - 9) *bp++ = ' '; Strcpy(bp, "Hp [max]"); topten_print(linebuf); } /* so>0: standout line; so=0: ordinary line */ STATIC_OVL void outentry(rank, t1, so) struct toptenentry *t1; int rank; boolean so; { boolean second_line = TRUE; char linebuf[BUFSZ]; char *bp, hpbuf[24], linebuf3[BUFSZ]; int hppos, lngr; linebuf[0] = '\0'; if (rank) Sprintf(eos(linebuf), "%3d", rank); else Strcat(linebuf, " "); Sprintf(eos(linebuf), " %10ld %.10s", t1->points, t1->name); Sprintf(eos(linebuf), "-%s", t1->plrole); if (t1->plrace[0] != '?') Sprintf(eos(linebuf), "-%s", t1->plrace); /* Printing of gender and alignment is intentional. It has been * part of the NetHack Geek Code, and illustrates a proper way to * specify a character from the command line. */ Sprintf(eos(linebuf), "-%s", t1->plgend); if (t1->plalign[0] != '?') Sprintf(eos(linebuf), "-%s ", t1->plalign); else Strcat(linebuf, " "); if (!strncmp("escaped", t1->death, 7)) { Sprintf(eos(linebuf), "escaped the dungeon %s[max level %d]", !strncmp(" (", t1->death + 7, 2) ? t1->death + 7 + 2 : "", t1->maxlvl); /* fixup for closing paren in "escaped... with...Amulet)[max..." */ if ((bp = index(linebuf, ')')) != 0) *bp = (t1->deathdnum == astral_level.dnum) ? '\0' : ' '; second_line = FALSE; } else if (!strncmp("ascended", t1->death, 8)) { Sprintf(eos(linebuf), "ascended to demigod%s-hood", (t1->plgend[0] == 'F') ? "dess" : ""); second_line = FALSE; } else { if (!strncmp(t1->death, "quit", 4)) { Strcat(linebuf, "quit"); second_line = FALSE; } else if (!strncmp(t1->death, "died of st", 10)) { Strcat(linebuf, "starved to death"); second_line = FALSE; } else if (!strncmp(t1->death, "choked", 6)) { Sprintf(eos(linebuf), "choked on h%s food", (t1->plgend[0] == 'F') ? "er" : "is"); } else if (!strncmp(t1->death, "poisoned", 8)) { Strcat(linebuf, "was poisoned"); } else if (!strncmp(t1->death, "crushed", 7)) { Strcat(linebuf, "was crushed to death"); } else if (!strncmp(t1->death, "petrified by ", 13)) { Strcat(linebuf, "turned to stone"); } else Strcat(linebuf, "died"); if (t1->deathdnum == astral_level.dnum) { const char *arg, *fmt = " on the Plane of %s"; switch (t1->deathlev) { case -5: fmt = " on the %s Plane"; arg = "Astral"; break; case -4: arg = "Water"; break; case -3: arg = "Fire"; break; case -2: arg = "Air"; break; case -1: arg = "Earth"; break; default: arg = "Void"; break; } Sprintf(eos(linebuf), fmt, arg); } else { Sprintf(eos(linebuf), " in %s", dungeons[t1->deathdnum].dname); if (t1->deathdnum != knox_level.dnum) Sprintf(eos(linebuf), " on level %d", t1->deathlev); if (t1->deathlev != t1->maxlvl) Sprintf(eos(linebuf), " [max %d]", t1->maxlvl); } /* kludge for "quit while already on Charon's boat" */ if (!strncmp(t1->death, "quit ", 5)) Strcat(linebuf, t1->death + 4); } Strcat(linebuf, "."); /* Quit, starved, ascended, and escaped contain no second line */ if (second_line) Sprintf(eos(linebuf), " %c%s.", highc(*(t1->death)), t1->death+1); lngr = (int)strlen(linebuf); if (t1->hp <= 0) hpbuf[0] = '-', hpbuf[1] = '\0'; else Sprintf(hpbuf, "%d", t1->hp); /* beginning of hp column after padding (not actually padded yet) */ hppos = COLNO - (sizeof(" Hp [max]")-1); /* sizeof(str) includes \0 */ while (lngr >= hppos) { for(bp = eos(linebuf); !(*bp == ' ' && (bp-linebuf < hppos)); bp--) ; /* special case: if about to wrap in the middle of maximum dungeon depth reached, wrap in front of it instead */ if (bp > linebuf + 5 && !strncmp(bp - 5, " [max", 5)) bp -= 5; Strcpy(linebuf3, bp+1); *bp = 0; if (so) { while (bp < linebuf + (COLNO-1)) *bp++ = ' '; *bp = 0; topten_print_bold(linebuf); } else topten_print(linebuf); Sprintf(linebuf, "%15s %s", "", linebuf3); lngr = strlen(linebuf); } /* beginning of hp column not including padding */ hppos = COLNO - 7 - (int)strlen(hpbuf); bp = eos(linebuf); if (bp <= linebuf + hppos) { /* pad any necessary blanks to the hit point entry */ while (bp < linebuf + hppos) *bp++ = ' '; Strcpy(bp, hpbuf); Sprintf(eos(bp), " %s[%d]", (t1->maxhp < 10) ? " " : (t1->maxhp < 100) ? " " : "", t1->maxhp); } if (so) { bp = eos(linebuf); if (so >= COLNO) so = COLNO-1; while (bp < linebuf + so) *bp++ = ' '; *bp = 0; topten_print_bold(linebuf); } else topten_print(linebuf); } STATIC_OVL int score_wanted(current_ver, rank, t1, playerct, players, uid) boolean current_ver; int rank; struct toptenentry *t1; int playerct; const char **players; int uid; { int i; if (current_ver && (t1->ver_major != VERSION_MAJOR || t1->ver_minor != VERSION_MINOR || t1->patchlevel != PATCHLEVEL)) return 0; #ifdef PERS_IS_UID if (!playerct && t1->uid == uid) return 1; #endif for (i = 0; i < playerct; i++) { if (players[i][0] == '-' && index("pr", players[i][1]) && players[i][2] == 0 && i + 1 < playerct) { char *arg = (char *)players[i + 1]; if ((players[i][1] == 'p' && str2role(arg) == str2role(t1->plrole)) || (players[i][1] == 'r' && str2race(arg) == str2race(t1->plrace))) return 1; i++; } else if (strcmp(players[i], "all") == 0 || strncmp(t1->name, players[i], NAMSZ) == 0 || (players[i][0] == '-' && players[i][1] == t1->plrole[0] && players[i][2] == 0) || (digit(players[i][0]) && rank <= atoi(players[i]))) return 1; } return 0; } /* * print selected parts of score list. * argc >= 2, with argv[0] untrustworthy (directory names, et al.), * and argv[1] starting with "-s". */ void prscore(argc,argv) int argc; char **argv; { const char **players; int playerct, rank; boolean current_ver = TRUE, init_done = FALSE; register struct toptenentry *t1; FILE *rfile; boolean match_found = FALSE; register int i; char pbuf[BUFSZ]; int uid = -1; #ifndef PERS_IS_UID const char *player0; #endif if (argc < 2 || strncmp(argv[1], "-s", 2)) { raw_printf("prscore: bad arguments (%d)", argc); return; } rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); if (!rfile) { raw_print("Cannot open record file!"); return; } #ifdef AMIGA { extern winid amii_rawprwin; init_nhwindows(&argc, argv); amii_rawprwin = create_nhwindow(NHW_TEXT); } #endif /* If the score list isn't after a game, we never went through * initialization. */ if (wiz1_level.dlevel == 0) { dlb_init(); init_dungeons(); init_done = TRUE; } if (!argv[1][2]){ /* plain "-s" */ argc--; argv++; } else argv[1] += 2; if (argc > 1 && !strcmp(argv[1], "-v")) { current_ver = FALSE; argc--; argv++; } if (argc <= 1) { #ifdef PERS_IS_UID uid = getuid(); playerct = 0; players = (const char **)0; #else player0 = plname; if (!*player0) # ifdef AMIGA player0 = "all"; /* single user system */ # else player0 = "hackplayer"; # endif playerct = 1; players = &player0; #endif } else { playerct = --argc; players = (const char **)++argv; } raw_print(""); t1 = tt_head = newttentry(); for (rank = 1; ; rank++) { readentry(rfile, t1); if (t1->points == 0) break; if (!match_found && score_wanted(current_ver, rank, t1, playerct, players, uid)) match_found = TRUE; t1->tt_next = newttentry(); t1 = t1->tt_next; } (void) fclose(rfile); if (init_done) { free_dungeons(); dlb_cleanup(); } if (match_found) { outheader(); t1 = tt_head; for (rank = 1; t1->points != 0; rank++, t1 = t1->tt_next) { if (score_wanted(current_ver, rank, t1, playerct, players, uid)) (void) outentry(rank, t1, 0); } } else { Sprintf(pbuf, "Cannot find any %sentries for ", current_ver ? "current " : ""); if (playerct < 1) Strcat(pbuf, "you."); else { if (playerct > 1) Strcat(pbuf, "any of "); for (i = 0; i < playerct; i++) { /* stop printing players if there are too many to fit */ if (strlen(pbuf) + strlen(players[i]) + 2 >= BUFSZ) { if (strlen(pbuf) < BUFSZ-4) Strcat(pbuf, "..."); else Strcpy(pbuf+strlen(pbuf)-4, "..."); break; } Strcat(pbuf, players[i]); if (i < playerct-1) { if (players[i][0] == '-' && index("pr", players[i][1]) && players[i][2] == 0) Strcat(pbuf, " "); else Strcat(pbuf, ":"); } } } raw_print(pbuf); raw_printf("Usage: %s -s [-v] [maxrank] [playernames]", hname); raw_printf("Player types are: [-p role] [-r race]"); } free_ttlist(tt_head); #ifdef AMIGA { extern winid amii_rawprwin; display_nhwindow(amii_rawprwin, 1); destroy_nhwindow(amii_rawprwin); amii_rawprwin = WIN_ERR; } #endif } STATIC_OVL int classmon(plch, fem) char *plch; boolean fem; { int i; /* Look for this role in the role table */ for (i = 0; roles[i].name.m; i++) if (!strncmp(plch, roles[i].filecode, ROLESZ)) { if (fem && roles[i].femalenum != NON_PM) return roles[i].femalenum; else if (roles[i].malenum != NON_PM) return roles[i].malenum; else return PM_HUMAN; } /* this might be from a 3.2.x score for former Elf class */ if (!strcmp(plch, "E")) return PM_RANGER; impossible("What weird role is this? (%s)", plch); return (PM_HUMAN_MUMMY); } /* * Get a random player name and class from the high score list, * and attach them to an object (for statues or morgue corpses). */ struct obj * tt_oname(otmp) struct obj *otmp; { int rank; register int i; register struct toptenentry *tt; FILE *rfile; struct toptenentry tt_buf; if (!otmp) return((struct obj *) 0); rfile = fopen_datafile(RECORD, "r", SCOREPREFIX); if (!rfile) { impossible("Cannot open record file!"); return (struct obj *)0; } tt = &tt_buf; rank = rnd(10); pickentry: for(i = rank; i; i--) { readentry(rfile, tt); if(tt->points == 0) break; } if(tt->points == 0) { if(rank > 1) { rank = 1; rewind(rfile); goto pickentry; } otmp = (struct obj *) 0; } else { /* reset timer in case corpse started out as lizard or troll */ if (otmp->otyp == CORPSE) obj_stop_timers(otmp); otmp->corpsenm = classmon(tt->plrole, (tt->plgend[0] == 'F')); otmp->owt = weight(otmp); otmp = oname(otmp, tt->name); if (otmp->otyp == CORPSE) start_corpse_timeout(otmp); } (void) fclose(rfile); return otmp; } #ifdef NO_SCAN_BRACK /* Lattice scanf isn't up to reading the scorefile. What */ /* follows deals with that; I admit it's ugly. (KL) */ /* Now generally available (KL) */ STATIC_OVL void nsb_mung_line(p) char *p; { while ((p = index(p, ' ')) != 0) *p = '|'; } STATIC_OVL void nsb_unmung_line(p) char *p; { while ((p = index(p, '|')) != 0) *p = ' '; } #endif /* NO_SCAN_BRACK */ /*topten.c*/ nethack-3.4.3/src/track.c0100644000000000000000000000237107764735041013714 0ustar rootroot/* SCCS Id: @(#)track.c 3.4 87/08/08 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* track.c - version 1.0.2 */ #include "hack.h" #define UTSZ 50 STATIC_VAR NEARDATA int utcnt, utpnt; STATIC_VAR NEARDATA coord utrack[UTSZ]; #ifdef OVLB void initrack() { utcnt = utpnt = 0; } #endif /* OVLB */ #ifdef OVL1 /* add to track */ void settrack() { if(utcnt < UTSZ) utcnt++; if(utpnt == UTSZ) utpnt = 0; utrack[utpnt].x = u.ux; utrack[utpnt].y = u.uy; utpnt++; } #endif /* OVL1 */ #ifdef OVL0 coord * gettrack(x, y) register int x, y; { register int cnt, ndist; register coord *tc; cnt = utcnt; for(tc = &utrack[utpnt]; cnt--; ){ if(tc == utrack) tc = &utrack[UTSZ-1]; else tc--; ndist = distmin(x,y,tc->x,tc->y); /* if far away, skip track entries til we're closer */ if(ndist > 2) { ndist -= 2; /* be careful due to extra decrement at top of loop */ cnt -= ndist; if(cnt <= 0) return (coord *) 0; /* too far away, no matches possible */ if(tc < &utrack[ndist]) tc += (UTSZ-ndist); else tc -= ndist; } else if(ndist <= 1) return(ndist ? tc : 0); } return (coord *)0; } #endif /* OVL0 */ /*track.c*/ nethack-3.4.3/src/trap.c0100644000000000000000000032645107764735041013566 0ustar rootroot/* SCCS Id: @(#)trap.c 3.4 2003/10/20 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" extern const char * const destroy_strings[]; /* from zap.c */ STATIC_DCL void FDECL(dofiretrap, (struct obj *)); STATIC_DCL void NDECL(domagictrap); STATIC_DCL boolean FDECL(emergency_disrobe,(boolean *)); STATIC_DCL int FDECL(untrap_prob, (struct trap *ttmp)); STATIC_DCL void FDECL(cnv_trap_obj, (int, int, struct trap *)); STATIC_DCL void FDECL(move_into_trap, (struct trap *)); STATIC_DCL int FDECL(try_disarm, (struct trap *,BOOLEAN_P)); STATIC_DCL void FDECL(reward_untrap, (struct trap *, struct monst *)); STATIC_DCL int FDECL(disarm_holdingtrap, (struct trap *)); STATIC_DCL int FDECL(disarm_landmine, (struct trap *)); STATIC_DCL int FDECL(disarm_squeaky_board, (struct trap *)); STATIC_DCL int FDECL(disarm_shooting_trap, (struct trap *, int)); STATIC_DCL int FDECL(try_lift, (struct monst *, struct trap *, int, BOOLEAN_P)); STATIC_DCL int FDECL(help_monster_out, (struct monst *, struct trap *)); STATIC_DCL boolean FDECL(thitm, (int,struct monst *,struct obj *,int,BOOLEAN_P)); STATIC_DCL int FDECL(mkroll_launch, (struct trap *,XCHAR_P,XCHAR_P,SHORT_P,long)); STATIC_DCL boolean FDECL(isclearpath,(coord *, int, SCHAR_P, SCHAR_P)); #ifdef STEED STATIC_OVL int FDECL(steedintrap, (struct trap *, struct obj *)); STATIC_OVL boolean FDECL(keep_saddle_with_steedcorpse, (unsigned, struct obj *, struct obj *)); #endif #ifndef OVLB STATIC_VAR const char *a_your[2]; STATIC_VAR const char *A_Your[2]; STATIC_VAR const char tower_of_flame[]; STATIC_VAR const char *A_gush_of_water_hits; STATIC_VAR const char * const blindgas[6]; #else STATIC_VAR const char * const a_your[2] = { "a", "your" }; STATIC_VAR const char * const A_Your[2] = { "A", "Your" }; STATIC_VAR const char tower_of_flame[] = "tower of flame"; STATIC_VAR const char * const A_gush_of_water_hits = "A gush of water hits"; STATIC_VAR const char * const blindgas[6] = {"humid", "odorless", "pungent", "chilling", "acrid", "biting"}; #endif /* OVLB */ #ifdef OVLB /* called when you're hit by fire (dofiretrap,buzz,zapyourself,explode) */ boolean /* returns TRUE if hit on torso */ burnarmor(victim) struct monst *victim; { struct obj *item; char buf[BUFSZ]; int mat_idx; if (!victim) return 0; #define burn_dmg(obj,descr) rust_dmg(obj, descr, 0, FALSE, victim) while (1) { switch (rn2(5)) { case 0: item = (victim == &youmonst) ? uarmh : which_armor(victim, W_ARMH); if (item) { mat_idx = objects[item->otyp].oc_material; Sprintf(buf,"%s helmet", materialnm[mat_idx] ); } if (!burn_dmg(item, item ? buf : "helmet")) continue; break; case 1: item = (victim == &youmonst) ? uarmc : which_armor(victim, W_ARMC); if (item) { (void) burn_dmg(item, cloak_simple_name(item)); return TRUE; } item = (victim == &youmonst) ? uarm : which_armor(victim, W_ARM); if (item) { (void) burn_dmg(item, xname(item)); return TRUE; } #ifdef TOURIST item = (victim == &youmonst) ? uarmu : which_armor(victim, W_ARMU); if (item) (void) burn_dmg(item, "shirt"); #endif return TRUE; case 2: item = (victim == &youmonst) ? uarms : which_armor(victim, W_ARMS); if (!burn_dmg(item, "wooden shield")) continue; break; case 3: item = (victim == &youmonst) ? uarmg : which_armor(victim, W_ARMG); if (!burn_dmg(item, "gloves")) continue; break; case 4: item = (victim == &youmonst) ? uarmf : which_armor(victim, W_ARMF); if (!burn_dmg(item, "boots")) continue; break; } break; /* Out of while loop */ } return FALSE; #undef burn_dmg } /* Generic rust-armor function. Returns TRUE if a message was printed; * "print", if set, means to print a message (and thus to return TRUE) even * if the item could not be rusted; otherwise a message is printed and TRUE is * returned only for rustable items. */ boolean rust_dmg(otmp, ostr, type, print, victim) register struct obj *otmp; register const char *ostr; int type; boolean print; struct monst *victim; { static NEARDATA const char * const action[] = { "smoulder", "rust", "rot", "corrode" }; static NEARDATA const char * const msg[] = { "burnt", "rusted", "rotten", "corroded" }; boolean vulnerable = FALSE; boolean grprot = FALSE; boolean is_primary = TRUE; boolean vismon = (victim != &youmonst) && canseemon(victim); int erosion; if (!otmp) return(FALSE); switch(type) { case 0: vulnerable = is_flammable(otmp); break; case 1: vulnerable = is_rustprone(otmp); grprot = TRUE; break; case 2: vulnerable = is_rottable(otmp); is_primary = FALSE; break; case 3: vulnerable = is_corrodeable(otmp); grprot = TRUE; is_primary = FALSE; break; } erosion = is_primary ? otmp->oeroded : otmp->oeroded2; if (!print && (!vulnerable || otmp->oerodeproof || erosion == MAX_ERODE)) return FALSE; if (!vulnerable) { if (flags.verbose) { if (victim == &youmonst) Your("%s %s not affected.", ostr, vtense(ostr, "are")); else if (vismon) pline("%s's %s %s not affected.", Monnam(victim), ostr, vtense(ostr, "are")); } } else if (erosion < MAX_ERODE) { if (grprot && otmp->greased) { grease_protect(otmp,ostr,victim); } else if (otmp->oerodeproof || (otmp->blessed && !rnl(4))) { if (flags.verbose) { if (victim == &youmonst) pline("Somehow, your %s %s not affected.", ostr, vtense(ostr, "are")); else if (vismon) pline("Somehow, %s's %s %s not affected.", mon_nam(victim), ostr, vtense(ostr, "are")); } } else { if (victim == &youmonst) Your("%s %s%s!", ostr, vtense(ostr, action[type]), erosion+1 == MAX_ERODE ? " completely" : erosion ? " further" : ""); else if (vismon) pline("%s's %s %s%s!", Monnam(victim), ostr, vtense(ostr, action[type]), erosion+1 == MAX_ERODE ? " completely" : erosion ? " further" : ""); if (is_primary) otmp->oeroded++; else otmp->oeroded2++; update_inventory(); } } else { if (flags.verbose) { if (victim == &youmonst) Your("%s %s completely %s.", ostr, vtense(ostr, Blind ? "feel" : "look"), msg[type]); else if (vismon) pline("%s's %s %s completely %s.", Monnam(victim), ostr, vtense(ostr, "look"), msg[type]); } } return(TRUE); } void grease_protect(otmp,ostr,victim) register struct obj *otmp; register const char *ostr; struct monst *victim; { static const char txt[] = "protected by the layer of grease!"; boolean vismon = victim && (victim != &youmonst) && canseemon(victim); if (ostr) { if (victim == &youmonst) Your("%s %s %s", ostr, vtense(ostr, "are"), txt); else if (vismon) pline("%s's %s %s %s", Monnam(victim), ostr, vtense(ostr, "are"), txt); } else { if (victim == &youmonst) Your("%s %s",aobjnam(otmp,"are"), txt); else if (vismon) pline("%s's %s %s", Monnam(victim), aobjnam(otmp,"are"), txt); } if (!rn2(2)) { otmp->greased = 0; if (carried(otmp)) { pline_The("grease dissolves."); update_inventory(); } } } struct trap * maketrap(x,y,typ) register int x, y, typ; { register struct trap *ttmp; register struct rm *lev; register boolean oldplace; if ((ttmp = t_at(x,y)) != 0) { if (ttmp->ttyp == MAGIC_PORTAL) return (struct trap *)0; oldplace = TRUE; if (u.utrap && (x == u.ux) && (y == u.uy) && ((u.utraptype == TT_BEARTRAP && typ != BEAR_TRAP) || (u.utraptype == TT_WEB && typ != WEB) || (u.utraptype == TT_PIT && typ != PIT && typ != SPIKED_PIT))) u.utrap = 0; } else { oldplace = FALSE; ttmp = newtrap(); ttmp->tx = x; ttmp->ty = y; ttmp->launch.x = -1; /* force error if used before set */ ttmp->launch.y = -1; } ttmp->ttyp = typ; switch(typ) { case STATUE_TRAP: /* create a "living" statue */ { struct monst *mtmp; struct obj *otmp, *statue; statue = mkcorpstat(STATUE, (struct monst *)0, &mons[rndmonnum()], x, y, FALSE); mtmp = makemon(&mons[statue->corpsenm], 0, 0, NO_MM_FLAGS); if (!mtmp) break; /* should never happen */ while(mtmp->minvent) { otmp = mtmp->minvent; otmp->owornmask = 0; obj_extract_self(otmp); (void) add_to_container(statue, otmp); } statue->owt = weight(statue); mongone(mtmp); break; } case ROLLING_BOULDER_TRAP: /* boulder will roll towards trigger */ (void) mkroll_launch(ttmp, x, y, BOULDER, 1L); break; case HOLE: case PIT: case SPIKED_PIT: case TRAPDOOR: lev = &levl[x][y]; if (*in_rooms(x, y, SHOPBASE) && ((typ == HOLE || typ == TRAPDOOR) || IS_DOOR(lev->typ) || IS_WALL(lev->typ))) add_damage(x, y, /* schedule repair */ ((IS_DOOR(lev->typ) || IS_WALL(lev->typ)) && !flags.mon_moving) ? 200L : 0L); lev->doormask = 0; /* subsumes altarmask, icedpool... */ if (IS_ROOM(lev->typ)) /* && !IS_AIR(lev->typ) */ lev->typ = ROOM; /* * some cases which can happen when digging * down while phazing thru solid areas */ else if (lev->typ == STONE || lev->typ == SCORR) lev->typ = CORR; else if (IS_WALL(lev->typ) || lev->typ == SDOOR) lev->typ = level.flags.is_maze_lev ? ROOM : level.flags.is_cavernous_lev ? CORR : DOOR; unearth_objs(x, y); break; } if (ttmp->ttyp == HOLE) ttmp->tseen = 1; /* You can't hide a hole */ else ttmp->tseen = 0; ttmp->once = 0; ttmp->madeby_u = 0; ttmp->dst.dnum = -1; ttmp->dst.dlevel = -1; if (!oldplace) { ttmp->ntrap = ftrap; ftrap = ttmp; } return(ttmp); } void fall_through(td) boolean td; /* td == TRUE : trap door or hole */ { d_level dtmp; char msgbuf[BUFSZ]; const char *dont_fall = 0; register int newlevel = dunlev(&u.uz); /* KMH -- You can't escape the Sokoban level traps */ if(Blind && Levitation && !In_sokoban(&u.uz)) return; do { newlevel++; } while(!rn2(4) && newlevel < dunlevs_in_dungeon(&u.uz)); if(td) { struct trap *t=t_at(u.ux,u.uy); seetrap(t); if (!In_sokoban(&u.uz)) { if (t->ttyp == TRAPDOOR) pline("A trap door opens up under you!"); else pline("There's a gaping hole under you!"); } } else pline_The("%s opens up under you!", surface(u.ux,u.uy)); if (In_sokoban(&u.uz) && Can_fall_thru(&u.uz)) ; /* KMH -- You can't escape the Sokoban level traps */ else if(Levitation || u.ustuck || !Can_fall_thru(&u.uz) || Flying || is_clinger(youmonst.data) || (Inhell && !u.uevent.invoked && newlevel == dunlevs_in_dungeon(&u.uz)) ) { dont_fall = "don't fall in."; } else if (youmonst.data->msize >= MZ_HUGE) { dont_fall = "don't fit through."; } else if (!next_to_u()) { dont_fall = "are jerked back by your pet!"; } if (dont_fall) { You(dont_fall); /* hero didn't fall through, but any objects here might */ impact_drop((struct obj *)0, u.ux, u.uy, 0); if (!td) { display_nhwindow(WIN_MESSAGE, FALSE); pline_The("opening under you closes up."); } return; } if(*u.ushops) shopdig(1); if (Is_stronghold(&u.uz)) { find_hell(&dtmp); } else { dtmp.dnum = u.uz.dnum; dtmp.dlevel = newlevel; } if (!td) Sprintf(msgbuf, "The hole in the %s above you closes up.", ceiling(u.ux,u.uy)); schedule_goto(&dtmp, FALSE, TRUE, 0, (char *)0, !td ? msgbuf : (char *)0); } /* * Animate the given statue. May have been via shatter attempt, trap, * or stone to flesh spell. Return a monster if successfully animated. * If the monster is animated, the object is deleted. If fail_reason * is non-null, then fill in the reason for failure (or success). * * The cause of animation is: * * ANIMATE_NORMAL - hero "finds" the monster * ANIMATE_SHATTER - hero tries to destroy the statue * ANIMATE_SPELL - stone to flesh spell hits the statue * * Perhaps x, y is not needed if we can use get_obj_location() to find * the statue's location... ??? */ struct monst * animate_statue(statue, x, y, cause, fail_reason) struct obj *statue; xchar x, y; int cause; int *fail_reason; { struct permonst *mptr; struct monst *mon = 0; struct obj *item; coord cc; boolean historic = (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (statue->spe & STATUE_HISTORIC)); char statuename[BUFSZ]; Strcpy(statuename,the(xname(statue))); if (statue->oxlth && statue->oattached == OATTACHED_MONST) { cc.x = x, cc.y = y; mon = montraits(statue, &cc); if (mon && mon->mtame && !mon->isminion) wary_dog(mon, TRUE); } else { /* statue of any golem hit with stone-to-flesh becomes flesh golem */ if (is_golem(&mons[statue->corpsenm]) && cause == ANIMATE_SPELL) mptr = &mons[PM_FLESH_GOLEM]; else mptr = &mons[statue->corpsenm]; /* * Guard against someone wishing for a statue of a unique monster * (which is allowed in normal play) and then tossing it onto the * [detected or guessed] location of a statue trap. Normally the * uppermost statue is the one which would be activated. */ if ((mptr->geno & G_UNIQ) && cause != ANIMATE_SPELL) { if (fail_reason) *fail_reason = AS_MON_IS_UNIQUE; return (struct monst *)0; } if (cause == ANIMATE_SPELL && ((mptr->geno & G_UNIQ) || mptr->msound == MS_GUARDIAN)) { /* Statues of quest guardians or unique monsters * will not stone-to-flesh as the real thing. */ mon = makemon(&mons[PM_DOPPELGANGER], x, y, NO_MINVENT|MM_NOCOUNTBIRTH|MM_ADJACENTOK); if (mon) { /* makemon() will set mon->cham to * CHAM_ORDINARY if hero is wearing * ring of protection from shape changers * when makemon() is called, so we have to * check the field before calling newcham(). */ if (mon->cham == CHAM_DOPPELGANGER) (void) newcham(mon, mptr, FALSE, FALSE); } } else mon = makemon(mptr, x, y, (cause == ANIMATE_SPELL) ? (NO_MINVENT | MM_ADJACENTOK) : NO_MINVENT); } if (!mon) { if (fail_reason) *fail_reason = AS_NO_MON; return (struct monst *)0; } /* in case statue is wielded and hero zaps stone-to-flesh at self */ if (statue->owornmask) remove_worn_item(statue, TRUE); /* allow statues to be of a specific gender */ if (statue->spe & STATUE_MALE) mon->female = FALSE; else if (statue->spe & STATUE_FEMALE) mon->female = TRUE; /* if statue has been named, give same name to the monster */ if (statue->onamelth) mon = christen_monst(mon, ONAME(statue)); /* transfer any statue contents to monster's inventory */ while ((item = statue->cobj) != 0) { obj_extract_self(item); (void) add_to_minv(mon, item); } m_dowear(mon, TRUE); delobj(statue); /* mimic statue becomes seen mimic; other hiders won't be hidden */ if (mon->m_ap_type) seemimic(mon); else mon->mundetected = FALSE; if ((x == u.ux && y == u.uy) || cause == ANIMATE_SPELL) { const char *comes_to_life = nonliving(mon->data) ? "moves" : "comes to life"; if (cause == ANIMATE_SPELL) pline("%s %s!", upstart(statuename), canspotmon(mon) ? comes_to_life : "disappears"); else pline_The("statue %s!", canspotmon(mon) ? comes_to_life : "disappears"); if (historic) { You_feel("guilty that the historic statue is now gone."); adjalign(-1); } } else if (cause == ANIMATE_SHATTER) pline("Instead of shattering, the statue suddenly %s!", canspotmon(mon) ? "comes to life" : "disappears"); else { /* cause == ANIMATE_NORMAL */ You("find %s posing as a statue.", canspotmon(mon) ? a_monnam(mon) : something); stop_occupation(); } /* avoid hiding under nothing */ if (x == u.ux && y == u.uy && Upolyd && hides_under(youmonst.data) && !OBJ_AT(x, y)) u.uundetected = 0; if (fail_reason) *fail_reason = AS_OK; return mon; } /* * You've either stepped onto a statue trap's location or you've triggered a * statue trap by searching next to it or by trying to break it with a wand * or pick-axe. */ struct monst * activate_statue_trap(trap, x, y, shatter) struct trap *trap; xchar x, y; boolean shatter; { struct monst *mtmp = (struct monst *)0; struct obj *otmp = sobj_at(STATUE, x, y); int fail_reason; /* * Try to animate the first valid statue. Stop the loop when we * actually create something or the failure cause is not because * the mon was unique. */ deltrap(trap); while (otmp) { mtmp = animate_statue(otmp, x, y, shatter ? ANIMATE_SHATTER : ANIMATE_NORMAL, &fail_reason); if (mtmp || fail_reason != AS_MON_IS_UNIQUE) break; while ((otmp = otmp->nexthere) != 0) if (otmp->otyp == STATUE) break; } if (Blind) feel_location(x, y); else newsym(x, y); return mtmp; } #ifdef STEED STATIC_OVL boolean keep_saddle_with_steedcorpse(steed_mid, objchn, saddle) unsigned steed_mid; struct obj *objchn, *saddle; { if (!saddle) return FALSE; while(objchn) { if(objchn->otyp == CORPSE && objchn->oattached == OATTACHED_MONST && objchn->oxlth) { struct monst *mtmp = (struct monst *)objchn->oextra; if (mtmp->m_id == steed_mid) { /* move saddle */ xchar x,y; if (get_obj_location(objchn, &x, &y, 0)) { obj_extract_self(saddle); place_object(saddle, x, y); stackobj(saddle); } return TRUE; } } if (Has_contents(objchn) && keep_saddle_with_steedcorpse(steed_mid, objchn->cobj, saddle)) return TRUE; objchn = objchn->nobj; } return FALSE; } #endif /*STEED*/ void dotrap(trap, trflags) register struct trap *trap; unsigned trflags; { register int ttype = trap->ttyp; register struct obj *otmp; boolean already_seen = trap->tseen; boolean webmsgok = (!(trflags & NOWEBMSG)); boolean forcebungle = (trflags & FORCEBUNGLE); nomul(0); /* KMH -- You can't escape the Sokoban level traps */ if (In_sokoban(&u.uz) && (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE || ttype == TRAPDOOR)) { /* The "air currents" message is still appropriate -- even when * the hero isn't flying or levitating -- because it conveys the * reason why the player cannot escape the trap with a dexterity * check, clinging to the ceiling, etc. */ pline("Air currents pull you down into %s %s!", a_your[trap->madeby_u], defsyms[trap_to_defsym(ttype)].explanation); /* then proceed to normal trap effect */ } else if (already_seen) { if ((Levitation || Flying) && (ttype == PIT || ttype == SPIKED_PIT || ttype == HOLE || ttype == BEAR_TRAP)) { You("%s over %s %s.", Levitation ? "float" : "fly", a_your[trap->madeby_u], defsyms[trap_to_defsym(ttype)].explanation); return; } if(!Fumbling && ttype != MAGIC_PORTAL && ttype != ANTI_MAGIC && !forcebungle && (!rn2(5) || ((ttype == PIT || ttype == SPIKED_PIT) && is_clinger(youmonst.data)))) { You("escape %s %s.", (ttype == ARROW_TRAP && !trap->madeby_u) ? "an" : a_your[trap->madeby_u], defsyms[trap_to_defsym(ttype)].explanation); return; } } #ifdef STEED if (u.usteed) u.usteed->mtrapseen |= (1 << (ttype-1)); #endif switch(ttype) { case ARROW_TRAP: if (trap->once && trap->tseen && !rn2(15)) { You_hear("a loud click!"); deltrap(trap); newsym(u.ux,u.uy); break; } trap->once = 1; seetrap(trap); pline("An arrow shoots out at you!"); otmp = mksobj(ARROW, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); otmp->opoisoned = 0; #ifdef STEED if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */; else #endif if (thitu(8, dmgval(otmp, &youmonst), otmp, "arrow")) { obfree(otmp, (struct obj *)0); } else { place_object(otmp, u.ux, u.uy); if (!Blind) otmp->dknown = 1; stackobj(otmp); newsym(u.ux, u.uy); } break; case DART_TRAP: if (trap->once && trap->tseen && !rn2(15)) { You_hear("a soft click."); deltrap(trap); newsym(u.ux,u.uy); break; } trap->once = 1; seetrap(trap); pline("A little dart shoots out at you!"); otmp = mksobj(DART, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); if (!rn2(6)) otmp->opoisoned = 1; #ifdef STEED if (u.usteed && !rn2(2) && steedintrap(trap, otmp)) /* nothing */; else #endif if (thitu(7, dmgval(otmp, &youmonst), otmp, "little dart")) { if (otmp->opoisoned) poisoned("dart", A_CON, "little dart", -10); obfree(otmp, (struct obj *)0); } else { place_object(otmp, u.ux, u.uy); if (!Blind) otmp->dknown = 1; stackobj(otmp); newsym(u.ux, u.uy); } break; case ROCKTRAP: if (trap->once && trap->tseen && !rn2(15)) { pline("A trap door in %s opens, but nothing falls out!", the(ceiling(u.ux,u.uy))); deltrap(trap); newsym(u.ux,u.uy); } else { int dmg = d(2,6); /* should be std ROCK dmg? */ trap->once = 1; seetrap(trap); otmp = mksobj_at(ROCK, u.ux, u.uy, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); pline("A trap door in %s opens and %s falls on your %s!", the(ceiling(u.ux,u.uy)), an(xname(otmp)), body_part(HEAD)); if (uarmh) { if(is_metallic(uarmh)) { pline("Fortunately, you are wearing a hard helmet."); dmg = 2; } else if (flags.verbose) { Your("%s does not protect you.", xname(uarmh)); } } if (!Blind) otmp->dknown = 1; stackobj(otmp); newsym(u.ux,u.uy); /* map the rock */ losehp(dmg, "falling rock", KILLED_BY_AN); exercise(A_STR, FALSE); } break; case SQKY_BOARD: /* stepped on a squeaky board */ if (Levitation || Flying) { if (!Blind) { seetrap(trap); if (Hallucination) You("notice a crease in the linoleum."); else You("notice a loose board below you."); } } else { seetrap(trap); pline("A board beneath you squeaks loudly."); wake_nearby(); } break; case BEAR_TRAP: if(Levitation || Flying) break; seetrap(trap); if(amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { pline("%s bear trap closes harmlessly through you.", A_Your[trap->madeby_u]); break; } if( #ifdef STEED !u.usteed && #endif youmonst.data->msize <= MZ_SMALL) { pline("%s bear trap closes harmlessly over you.", A_Your[trap->madeby_u]); break; } u.utrap = rn1(4, 4); u.utraptype = TT_BEARTRAP; #ifdef STEED if (u.usteed) { pline("%s bear trap closes on %s %s!", A_Your[trap->madeby_u], s_suffix(mon_nam(u.usteed)), mbodypart(u.usteed, FOOT)); } else #endif { pline("%s bear trap closes on your %s!", A_Your[trap->madeby_u], body_part(FOOT)); if(u.umonnum == PM_OWLBEAR || u.umonnum == PM_BUGBEAR) You("howl in anger!"); } exercise(A_DEX, FALSE); break; case SLP_GAS_TRAP: seetrap(trap); if(Sleep_resistance || breathless(youmonst.data)) { You("are enveloped in a cloud of gas!"); break; } pline("A cloud of gas puts you to sleep!"); fall_asleep(-rnd(25), TRUE); #ifdef STEED (void) steedintrap(trap, (struct obj *)0); #endif break; case RUST_TRAP: seetrap(trap); if (u.umonnum == PM_IRON_GOLEM) { int dam = u.mhmax; pline("%s you!", A_gush_of_water_hits); You("are covered with rust!"); if (Half_physical_damage) dam = (dam+1) / 2; losehp(dam, "rusting away", KILLED_BY); break; } else if (u.umonnum == PM_GREMLIN && rn2(3)) { pline("%s you!", A_gush_of_water_hits); (void)split_mon(&youmonst, (struct monst *)0); break; } /* Unlike monsters, traps cannot aim their rust attacks at * you, so instead of looping through and taking either the * first rustable one or the body, we take whatever we get, * even if it is not rustable. */ switch (rn2(5)) { case 0: pline("%s you on the %s!", A_gush_of_water_hits, body_part(HEAD)); (void) rust_dmg(uarmh, "helmet", 1, TRUE, &youmonst); break; case 1: pline("%s your left %s!", A_gush_of_water_hits, body_part(ARM)); if (rust_dmg(uarms, "shield", 1, TRUE, &youmonst)) break; if (u.twoweap || (uwep && bimanual(uwep))) erode_obj(u.twoweap ? uswapwep : uwep, FALSE, TRUE); glovecheck: (void) rust_dmg(uarmg, "gauntlets", 1, TRUE, &youmonst); /* Not "metal gauntlets" since it gets called * even if it's leather for the message */ break; case 2: pline("%s your right %s!", A_gush_of_water_hits, body_part(ARM)); erode_obj(uwep, FALSE, TRUE); goto glovecheck; default: pline("%s you!", A_gush_of_water_hits); for (otmp=invent; otmp; otmp = otmp->nobj) (void) snuff_lit(otmp); if (uarmc) (void) rust_dmg(uarmc, cloak_simple_name(uarmc), 1, TRUE, &youmonst); else if (uarm) (void) rust_dmg(uarm, "armor", 1, TRUE, &youmonst); #ifdef TOURIST else if (uarmu) (void) rust_dmg(uarmu, "shirt", 1, TRUE, &youmonst); #endif } update_inventory(); break; case FIRE_TRAP: seetrap(trap); dofiretrap((struct obj *)0); break; case PIT: case SPIKED_PIT: /* KMH -- You can't escape the Sokoban level traps */ if (!In_sokoban(&u.uz) && (Levitation || Flying)) break; seetrap(trap); if (!In_sokoban(&u.uz) && is_clinger(youmonst.data)) { if(trap->tseen) { You("see %s %spit below you.", a_your[trap->madeby_u], ttype == SPIKED_PIT ? "spiked " : ""); } else { pline("%s pit %sopens up under you!", A_Your[trap->madeby_u], ttype == SPIKED_PIT ? "full of spikes " : ""); You("don't fall in!"); } break; } if (!In_sokoban(&u.uz)) { char verbbuf[BUFSZ]; #ifdef STEED if (u.usteed) { if ((trflags & RECURSIVETRAP) != 0) Sprintf(verbbuf, "and %s fall", x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE)); else Sprintf(verbbuf,"lead %s", x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, "poor", SUPPRESS_SADDLE, FALSE)); } else #endif Strcpy(verbbuf,"fall"); You("%s into %s pit!", verbbuf, a_your[trap->madeby_u]); } /* wumpus reference */ if (Role_if(PM_RANGER) && !trap->madeby_u && !trap->once && In_quest(&u.uz) && Is_qlocate(&u.uz)) { pline("Fortunately it has a bottom after all..."); trap->once = 1; } else if (u.umonnum == PM_PIT_VIPER || u.umonnum == PM_PIT_FIEND) pline("How pitiful. Isn't that the pits?"); if (ttype == SPIKED_PIT) { const char *predicament = "on a set of sharp iron spikes"; #ifdef STEED if (u.usteed) { pline("%s lands %s!", upstart(x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, "poor", SUPPRESS_SADDLE, FALSE)), predicament); } else #endif You("land %s!", predicament); } if (!Passes_walls) u.utrap = rn1(6,2); u.utraptype = TT_PIT; #ifdef STEED if (!steedintrap(trap, (struct obj *)0)) { #endif if (ttype == SPIKED_PIT) { losehp(rnd(10),"fell into a pit of iron spikes", NO_KILLER_PREFIX); if (!rn2(6)) poisoned("spikes", A_STR, "fall onto poison spikes", 8); } else losehp(rnd(6),"fell into a pit", NO_KILLER_PREFIX); if (Punished && !carried(uball)) { unplacebc(); ballfall(); placebc(); } selftouch("Falling, you"); vision_full_recalc = 1; /* vision limits change */ exercise(A_STR, FALSE); exercise(A_DEX, FALSE); #ifdef STEED } #endif break; case HOLE: case TRAPDOOR: if (!Can_fall_thru(&u.uz)) { seetrap(trap); /* normally done in fall_through */ impossible("dotrap: %ss cannot exist on this level.", defsyms[trap_to_defsym(ttype)].explanation); break; /* don't activate it after all */ } fall_through(TRUE); break; case TELEP_TRAP: seetrap(trap); tele_trap(trap); break; case LEVEL_TELEP: seetrap(trap); level_tele_trap(trap); break; case WEB: /* Our luckless player has stumbled into a web. */ seetrap(trap); if (amorphous(youmonst.data) || is_whirly(youmonst.data) || unsolid(youmonst.data)) { if (acidic(youmonst.data) || u.umonnum == PM_GELATINOUS_CUBE || u.umonnum == PM_FIRE_ELEMENTAL) { if (webmsgok) You("%s %s spider web!", (u.umonnum == PM_FIRE_ELEMENTAL) ? "burn" : "dissolve", a_your[trap->madeby_u]); deltrap(trap); newsym(u.ux,u.uy); break; } if (webmsgok) You("flow through %s spider web.", a_your[trap->madeby_u]); break; } if (webmaker(youmonst.data)) { if (webmsgok) pline(trap->madeby_u ? "You take a walk on your web." : "There is a spider web here."); break; } if (webmsgok) { char verbbuf[BUFSZ]; verbbuf[0] = '\0'; #ifdef STEED if (u.usteed) Sprintf(verbbuf,"lead %s", x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, "poor", SUPPRESS_SADDLE, FALSE)); else #endif Sprintf(verbbuf, "%s", Levitation ? (const char *)"float" : locomotion(youmonst.data, "stumble")); You("%s into %s spider web!", verbbuf, a_your[trap->madeby_u]); } u.utraptype = TT_WEB; /* Time stuck in the web depends on your/steed strength. */ { register int str = ACURR(A_STR); #ifdef STEED /* If mounted, the steed gets trapped. Use mintrap * to do all the work. If mtrapped is set as a result, * unset it and set utrap instead. In the case of a * strongmonst and mintrap said it's trapped, use a * short but non-zero trap time. Otherwise, monsters * have no specific strength, so use player strength. * This gets skipped for webmsgok, which implies that * the steed isn't a factor. */ if (u.usteed && webmsgok) { /* mtmp location might not be up to date */ u.usteed->mx = u.ux; u.usteed->my = u.uy; /* mintrap currently does not return 2(died) for webs */ if (mintrap(u.usteed)) { u.usteed->mtrapped = 0; if (strongmonst(u.usteed->data)) str = 17; } else { break; } webmsgok = FALSE; /* mintrap printed the messages */ } #endif if (str <= 3) u.utrap = rn1(6,6); else if (str < 6) u.utrap = rn1(6,4); else if (str < 9) u.utrap = rn1(4,4); else if (str < 12) u.utrap = rn1(4,2); else if (str < 15) u.utrap = rn1(2,2); else if (str < 18) u.utrap = rnd(2); else if (str < 69) u.utrap = 1; else { u.utrap = 0; if (webmsgok) You("tear through %s web!", a_your[trap->madeby_u]); deltrap(trap); newsym(u.ux,u.uy); /* get rid of trap symbol */ } } break; case STATUE_TRAP: (void) activate_statue_trap(trap, u.ux, u.uy, FALSE); break; case MAGIC_TRAP: /* A magic trap. */ seetrap(trap); if (!rn2(30)) { deltrap(trap); newsym(u.ux,u.uy); /* update position */ You("are caught in a magical explosion!"); losehp(rnd(10), "magical explosion", KILLED_BY_AN); Your("body absorbs some of the magical energy!"); u.uen = (u.uenmax += 2); } else domagictrap(); #ifdef STEED (void) steedintrap(trap, (struct obj *)0); #endif break; case ANTI_MAGIC: seetrap(trap); if(Antimagic) { shieldeff(u.ux, u.uy); You_feel("momentarily lethargic."); } else drain_en(rnd(u.ulevel) + 1); break; case POLY_TRAP: { char verbbuf[BUFSZ]; seetrap(trap); #ifdef STEED if (u.usteed) Sprintf(verbbuf, "lead %s", x_monnam(u.usteed, u.usteed->mnamelth ? ARTICLE_NONE : ARTICLE_THE, (char *)0, SUPPRESS_SADDLE, FALSE)); else #endif Sprintf(verbbuf,"%s", Levitation ? (const char *)"float" : locomotion(youmonst.data, "step")); You("%s onto a polymorph trap!", verbbuf); if(Antimagic || Unchanging) { shieldeff(u.ux, u.uy); You_feel("momentarily different."); /* Trap did nothing; don't remove it --KAA */ } else { #ifdef STEED (void) steedintrap(trap, (struct obj *)0); #endif deltrap(trap); /* delete trap before polymorph */ newsym(u.ux,u.uy); /* get rid of trap symbol */ You_feel("a change coming over you."); polyself(FALSE); } break; } case LANDMINE: { #ifdef STEED unsigned steed_mid = 0; struct obj *saddle = 0; #endif if (Levitation || Flying) { if (!already_seen && rn2(3)) break; seetrap(trap); pline("%s %s in a pile of soil below you.", already_seen ? "There is" : "You discover", trap->madeby_u ? "the trigger of your mine" : "a trigger"); if (already_seen && rn2(3)) break; pline("KAABLAMM!!! %s %s%s off!", forcebungle ? "Your inept attempt sets" : "The air currents set", already_seen ? a_your[trap->madeby_u] : "", already_seen ? " land mine" : "it"); } else { #ifdef STEED /* prevent landmine from killing steed, throwing you to * the ground, and you being affected again by the same * mine because it hasn't been deleted yet */ static boolean recursive_mine = FALSE; if (recursive_mine) break; #endif seetrap(trap); pline("KAABLAMM!!! You triggered %s land mine!", a_your[trap->madeby_u]); #ifdef STEED if (u.usteed) steed_mid = u.usteed->m_id; recursive_mine = TRUE; (void) steedintrap(trap, (struct obj *)0); recursive_mine = FALSE; saddle = sobj_at(SADDLE,u.ux, u.uy); #endif set_wounded_legs(LEFT_SIDE, rn1(35, 41)); set_wounded_legs(RIGHT_SIDE, rn1(35, 41)); exercise(A_DEX, FALSE); } blow_up_landmine(trap); #ifdef STEED if (steed_mid && saddle && !u.usteed) (void)keep_saddle_with_steedcorpse(steed_mid, fobj, saddle); #endif newsym(u.ux,u.uy); /* update trap symbol */ losehp(rnd(16), "land mine", KILLED_BY_AN); /* fall recursively into the pit... */ if ((trap = t_at(u.ux, u.uy)) != 0) dotrap(trap, RECURSIVETRAP); fill_pit(u.ux, u.uy); break; } case ROLLING_BOULDER_TRAP: { int style = ROLL | (trap->tseen ? LAUNCH_KNOWN : 0); seetrap(trap); pline("Click! You trigger a rolling boulder trap!"); if(!launch_obj(BOULDER, trap->launch.x, trap->launch.y, trap->launch2.x, trap->launch2.y, style)) { deltrap(trap); newsym(u.ux,u.uy); /* get rid of trap symbol */ pline("Fortunately for you, no boulder was released."); } break; } case MAGIC_PORTAL: seetrap(trap); domagicportal(trap); break; default: seetrap(trap); impossible("You hit a trap of type %u", trap->ttyp); } } #ifdef STEED STATIC_OVL int steedintrap(trap, otmp) struct trap *trap; struct obj *otmp; { struct monst *mtmp = u.usteed; struct permonst *mptr; int tt; boolean in_sight; boolean trapkilled = FALSE; boolean steedhit = FALSE; if (!u.usteed || !trap) return 0; mptr = mtmp->data; tt = trap->ttyp; mtmp->mx = u.ux; mtmp->my = u.uy; in_sight = !Blind; switch (tt) { case ARROW_TRAP: if(!otmp) { impossible("steed hit by non-existant arrow?"); return 0; } if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; steedhit = TRUE; break; case DART_TRAP: if(!otmp) { impossible("steed hit by non-existant dart?"); return 0; } if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; steedhit = TRUE; break; case SLP_GAS_TRAP: if (!resists_sleep(mtmp) && !breathless(mptr) && !mtmp->msleeping && mtmp->mcanmove) { mtmp->mcanmove = 0; mtmp->mfrozen = rnd(25); if (in_sight) { pline("%s suddenly falls asleep!", Monnam(mtmp)); } } steedhit = TRUE; break; case LANDMINE: if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE)) trapkilled = TRUE; steedhit = TRUE; break; case PIT: case SPIKED_PIT: if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *)0, rnd((tt == PIT) ? 6 : 10), FALSE)) trapkilled = TRUE; steedhit = TRUE; break; case POLY_TRAP: if (!resists_magm(mtmp)) { if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); if (!can_saddle(mtmp) || !can_ride(mtmp)) { dismount_steed(DISMOUNT_POLY); } else { You("have to adjust yourself in the saddle on %s.", x_monnam(mtmp, mtmp->mnamelth ? ARTICLE_NONE : ARTICLE_A, (char *)0, SUPPRESS_SADDLE, FALSE)); } } steedhit = TRUE; break; default: return 0; } } if(trapkilled) { dismount_steed(DISMOUNT_POLY); return 2; } else if(steedhit) return 1; else return 0; } #endif /*STEED*/ /* some actions common to both player and monsters for triggered landmine */ void blow_up_landmine(trap) struct trap *trap; { (void)scatter(trap->tx, trap->ty, 4, MAY_DESTROY | MAY_HIT | MAY_FRACTURE | VIS_EFFECTS, (struct obj *)0); del_engr_at(trap->tx, trap->ty); wake_nearto(trap->tx, trap->ty, 400); if (IS_DOOR(levl[trap->tx][trap->ty].typ)) levl[trap->tx][trap->ty].doormask = D_BROKEN; /* TODO: destroy drawbridge if present */ /* caller may subsequently fill pit, e.g. with a boulder */ trap->ttyp = PIT; /* explosion creates a pit */ trap->madeby_u = FALSE; /* resulting pit isn't yours */ seetrap(trap); /* and it isn't concealed */ } #endif /* OVLB */ #ifdef OVL3 /* * Move obj from (x1,y1) to (x2,y2) * * Return 0 if no object was launched. * 1 if an object was launched and placed somewhere. * 2 if an object was launched, but used up. */ int launch_obj(otyp, x1, y1, x2, y2, style) short otyp; register int x1,y1,x2,y2; int style; { register struct monst *mtmp; register struct obj *otmp, *otmp2; register int dx,dy; struct obj *singleobj; boolean used_up = FALSE; boolean otherside = FALSE; int dist; int tmp; int delaycnt = 0; otmp = sobj_at(otyp, x1, y1); /* Try the other side too, for rolling boulder traps */ if (!otmp && otyp == BOULDER) { otherside = TRUE; otmp = sobj_at(otyp, x2, y2); } if (!otmp) return 0; if (otherside) { /* swap 'em */ int tx, ty; tx = x1; ty = y1; x1 = x2; y1 = y2; x2 = tx; y2 = ty; } if (otmp->quan == 1L) { obj_extract_self(otmp); singleobj = otmp; otmp = (struct obj *) 0; } else { singleobj = splitobj(otmp, 1L); obj_extract_self(singleobj); } newsym(x1,y1); /* in case you're using a pick-axe to chop the boulder that's being launched (perhaps a monster triggered it), destroy context so that next dig attempt never thinks you're resuming previous effort */ if ((otyp == BOULDER || otyp == STATUE) && singleobj->ox == digging.pos.x && singleobj->oy == digging.pos.y) (void) memset((genericptr_t)&digging, 0, sizeof digging); dist = distmin(x1,y1,x2,y2); bhitpos.x = x1; bhitpos.y = y1; dx = sgn(x2 - x1); dy = sgn(y2 - y1); switch (style) { case ROLL|LAUNCH_UNSEEN: if (otyp == BOULDER) { You_hear(Hallucination ? "someone bowling." : "rumbling in the distance."); } style &= ~LAUNCH_UNSEEN; goto roll; case ROLL|LAUNCH_KNOWN: /* use otrapped as a flag to ohitmon */ singleobj->otrapped = 1; style &= ~LAUNCH_KNOWN; /* fall through */ roll: case ROLL: delaycnt = 2; /* fall through */ default: if (!delaycnt) delaycnt = 1; if (!cansee(bhitpos.x,bhitpos.y)) curs_on_u(); tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); tmp_at(bhitpos.x, bhitpos.y); } /* Set the object in motion */ while(dist-- > 0 && !used_up) { struct trap *t; tmp_at(bhitpos.x, bhitpos.y); tmp = delaycnt; /* dstage@u.washington.edu -- Delay only if hero sees it */ if (cansee(bhitpos.x, bhitpos.y)) while (tmp-- > 0) delay_output(); bhitpos.x += dx; bhitpos.y += dy; t = t_at(bhitpos.x, bhitpos.y); if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { if (otyp == BOULDER && throws_rocks(mtmp->data)) { if (rn2(3)) { pline("%s snatches the boulder.", Monnam(mtmp)); singleobj->otrapped = 0; (void) mpickobj(mtmp, singleobj); used_up = TRUE; break; } } if (ohitmon(mtmp,singleobj, (style==ROLL) ? -1 : dist, FALSE)) { used_up = TRUE; break; } } else if (bhitpos.x == u.ux && bhitpos.y == u.uy) { if (multi) nomul(0); if (thitu(9 + singleobj->spe, dmgval(singleobj, &youmonst), singleobj, (char *)0)) stop_occupation(); } if (style == ROLL) { if (down_gate(bhitpos.x, bhitpos.y) != -1) { if(ship_object(singleobj, bhitpos.x, bhitpos.y, FALSE)){ used_up = TRUE; break; } } if (t && otyp == BOULDER) { switch(t->ttyp) { case LANDMINE: if (rn2(10) > 2) { pline( "KAABLAMM!!!%s", cansee(bhitpos.x, bhitpos.y) ? " The rolling boulder triggers a land mine." : ""); deltrap(t); del_engr_at(bhitpos.x,bhitpos.y); place_object(singleobj, bhitpos.x, bhitpos.y); singleobj->otrapped = 0; fracture_rock(singleobj); (void)scatter(bhitpos.x,bhitpos.y, 4, MAY_DESTROY|MAY_HIT|MAY_FRACTURE|VIS_EFFECTS, (struct obj *)0); if (cansee(bhitpos.x,bhitpos.y)) newsym(bhitpos.x,bhitpos.y); used_up = TRUE; } break; case LEVEL_TELEP: case TELEP_TRAP: if (cansee(bhitpos.x, bhitpos.y)) pline("Suddenly the rolling boulder disappears!"); else You_hear("a rumbling stop abruptly."); singleobj->otrapped = 0; if (t->ttyp == TELEP_TRAP) rloco(singleobj); else { int newlev = random_teleport_level(); d_level dest; if (newlev == depth(&u.uz) || In_endgame(&u.uz)) continue; add_to_migration(singleobj); get_level(&dest, newlev); singleobj->ox = dest.dnum; singleobj->oy = dest.dlevel; singleobj->owornmask = (long)MIGR_RANDOM; } seetrap(t); used_up = TRUE; break; case PIT: case SPIKED_PIT: case HOLE: case TRAPDOOR: /* the boulder won't be used up if there is a monster in the trap; stop rolling anyway */ x2 = bhitpos.x, y2 = bhitpos.y; /* stops here */ if (flooreffects(singleobj, x2, y2, "fall")) used_up = TRUE; dist = -1; /* stop rolling immediately */ break; } if (used_up || dist == -1) break; } if (flooreffects(singleobj, bhitpos.x, bhitpos.y, "fall")) { used_up = TRUE; break; } if (otyp == BOULDER && (otmp2 = sobj_at(BOULDER, bhitpos.x, bhitpos.y)) != 0) { const char *bmsg = " as one boulder sets another in motion"; if (!isok(bhitpos.x + dx, bhitpos.y + dy) || !dist || IS_ROCK(levl[bhitpos.x + dx][bhitpos.y + dy].typ)) bmsg = " as one boulder hits another"; You_hear("a loud crash%s!", cansee(bhitpos.x, bhitpos.y) ? bmsg : ""); obj_extract_self(otmp2); /* pass off the otrapped flag to the next boulder */ otmp2->otrapped = singleobj->otrapped; singleobj->otrapped = 0; place_object(singleobj, bhitpos.x, bhitpos.y); singleobj = otmp2; otmp2 = (struct obj *)0; wake_nearto(bhitpos.x, bhitpos.y, 10*10); } } if (otyp == BOULDER && closed_door(bhitpos.x,bhitpos.y)) { if (cansee(bhitpos.x, bhitpos.y)) pline_The("boulder crashes through a door."); levl[bhitpos.x][bhitpos.y].doormask = D_BROKEN; if (dist) unblock_point(bhitpos.x, bhitpos.y); } /* if about to hit iron bars, do so now */ if (dist > 0 && isok(bhitpos.x + dx,bhitpos.y + dy) && levl[bhitpos.x + dx][bhitpos.y + dy].typ == IRONBARS) { x2 = bhitpos.x, y2 = bhitpos.y; /* object stops here */ if (hits_bars(&singleobj, x2, y2, !rn2(20), 0)) { if (!singleobj) used_up = TRUE; break; } } } tmp_at(DISP_END, 0); if (!used_up) { singleobj->otrapped = 0; place_object(singleobj, x2,y2); newsym(x2,y2); return 1; } else return 2; } #endif /* OVL3 */ #ifdef OVLB void seetrap(trap) register struct trap *trap; { if(!trap->tseen) { trap->tseen = 1; newsym(trap->tx, trap->ty); } } #endif /* OVLB */ #ifdef OVL3 STATIC_OVL int mkroll_launch(ttmp, x, y, otyp, ocount) struct trap *ttmp; xchar x,y; short otyp; long ocount; { struct obj *otmp; register int tmp; schar dx,dy; int distance; coord cc; coord bcc; int trycount = 0; boolean success = FALSE; int mindist = 4; if (ttmp->ttyp == ROLLING_BOULDER_TRAP) mindist = 2; distance = rn1(5,4); /* 4..8 away */ tmp = rn2(8); /* randomly pick a direction to try first */ while (distance >= mindist) { dx = xdir[tmp]; dy = ydir[tmp]; cc.x = x; cc.y = y; /* Prevent boulder from being placed on water */ if (ttmp->ttyp == ROLLING_BOULDER_TRAP && is_pool(x+distance*dx,y+distance*dy)) success = FALSE; else success = isclearpath(&cc, distance, dx, dy); if (ttmp->ttyp == ROLLING_BOULDER_TRAP) { boolean success_otherway; bcc.x = x; bcc.y = y; success_otherway = isclearpath(&bcc, distance, -(dx), -(dy)); if (!success_otherway) success = FALSE; } if (success) break; if (++tmp > 7) tmp = 0; if ((++trycount % 8) == 0) --distance; } if (!success) { /* create the trap without any ammo, launch pt at trap location */ cc.x = bcc.x = x; cc.y = bcc.y = y; } else { otmp = mksobj(otyp, TRUE, FALSE); otmp->quan = ocount; otmp->owt = weight(otmp); place_object(otmp, cc.x, cc.y); stackobj(otmp); } ttmp->launch.x = cc.x; ttmp->launch.y = cc.y; if (ttmp->ttyp == ROLLING_BOULDER_TRAP) { ttmp->launch2.x = bcc.x; ttmp->launch2.y = bcc.y; } else ttmp->launch_otyp = otyp; newsym(ttmp->launch.x, ttmp->launch.y); return 1; } STATIC_OVL boolean isclearpath(cc,distance,dx,dy) coord *cc; int distance; schar dx,dy; { uchar typ; xchar x, y; x = cc->x; y = cc->y; while (distance-- > 0) { x += dx; y += dy; typ = levl[x][y].typ; if (!isok(x,y) || !ZAP_POS(typ) || closed_door(x,y)) return FALSE; } cc->x = x; cc->y = y; return TRUE; } #endif /* OVL3 */ #ifdef OVL1 int mintrap(mtmp) register struct monst *mtmp; { register struct trap *trap = t_at(mtmp->mx, mtmp->my); boolean trapkilled = FALSE; struct permonst *mptr = mtmp->data; struct obj *otmp; if (!trap) { mtmp->mtrapped = 0; /* perhaps teleported? */ } else if (mtmp->mtrapped) { /* is currently in the trap */ if (!trap->tseen && cansee(mtmp->mx, mtmp->my) && canseemon(mtmp) && (trap->ttyp == SPIKED_PIT || trap->ttyp == BEAR_TRAP || trap->ttyp == HOLE || trap->ttyp == PIT || trap->ttyp == WEB)) { /* If you come upon an obviously trapped monster, then * you must be able to see the trap it's in too. */ seetrap(trap); } if (!rn2(40)) { if (sobj_at(BOULDER, mtmp->mx, mtmp->my) && (trap->ttyp == PIT || trap->ttyp == SPIKED_PIT)) { if (!rn2(2)) { mtmp->mtrapped = 0; if (canseemon(mtmp)) pline("%s pulls free...", Monnam(mtmp)); fill_pit(mtmp->mx, mtmp->my); } } else { mtmp->mtrapped = 0; } } else if (metallivorous(mptr)) { if (trap->ttyp == BEAR_TRAP) { if (canseemon(mtmp)) pline("%s eats a bear trap!", Monnam(mtmp)); deltrap(trap); mtmp->meating = 5; mtmp->mtrapped = 0; } else if (trap->ttyp == SPIKED_PIT) { if (canseemon(mtmp)) pline("%s munches on some spikes!", Monnam(mtmp)); trap->ttyp = PIT; mtmp->meating = 5; } } } else { register int tt = trap->ttyp; boolean in_sight, tear_web, see_it, inescapable = ((tt == HOLE || tt == PIT) && In_sokoban(&u.uz) && !trap->madeby_u); const char *fallverb; #ifdef STEED /* true when called from dotrap, inescapable is not an option */ if (mtmp == u.usteed) inescapable = TRUE; #endif if (!inescapable && ((mtmp->mtrapseen & (1 << (tt-1))) != 0 || (tt == HOLE && !mindless(mtmp->data)))) { /* it has been in such a trap - perhaps it escapes */ if(rn2(4)) return(0); } else { mtmp->mtrapseen |= (1 << (tt-1)); } /* Monster is aggravated by being trapped by you. Recognizing who made the trap isn't completely unreasonable; everybody has their own style. */ if (trap->madeby_u && rnl(5)) setmangry(mtmp); in_sight = canseemon(mtmp); see_it = cansee(mtmp->mx, mtmp->my); #ifdef STEED /* assume hero can tell what's going on for the steed */ if (mtmp == u.usteed) in_sight = TRUE; #endif switch (tt) { case ARROW_TRAP: if (trap->once && trap->tseen && !rn2(15)) { if (in_sight && see_it) pline("%s triggers a trap but nothing happens.", Monnam(mtmp)); deltrap(trap); newsym(mtmp->mx, mtmp->my); break; } trap->once = 1; otmp = mksobj(ARROW, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); otmp->opoisoned = 0; if (in_sight) seetrap(trap); if (thitm(8, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; break; case DART_TRAP: if (trap->once && trap->tseen && !rn2(15)) { if (in_sight && see_it) pline("%s triggers a trap but nothing happens.", Monnam(mtmp)); deltrap(trap); newsym(mtmp->mx, mtmp->my); break; } trap->once = 1; otmp = mksobj(DART, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); if (!rn2(6)) otmp->opoisoned = 1; if (in_sight) seetrap(trap); if (thitm(7, mtmp, otmp, 0, FALSE)) trapkilled = TRUE; break; case ROCKTRAP: if (trap->once && trap->tseen && !rn2(15)) { if (in_sight && see_it) pline("A trap door above %s opens, but nothing falls out!", mon_nam(mtmp)); deltrap(trap); newsym(mtmp->mx, mtmp->my); break; } trap->once = 1; otmp = mksobj(ROCK, TRUE, FALSE); otmp->quan = 1L; otmp->owt = weight(otmp); if (in_sight) seetrap(trap); if (thitm(0, mtmp, otmp, d(2, 6), FALSE)) trapkilled = TRUE; break; case SQKY_BOARD: if(is_flyer(mptr)) break; /* stepped on a squeaky board */ if (in_sight) { pline("A board beneath %s squeaks loudly.", mon_nam(mtmp)); seetrap(trap); } else You_hear("a distant squeak."); /* wake up nearby monsters */ wake_nearto(mtmp->mx, mtmp->my, 40); break; case BEAR_TRAP: if(mptr->msize > MZ_SMALL && !amorphous(mptr) && !is_flyer(mptr) && !is_whirly(mptr) && !unsolid(mptr)) { mtmp->mtrapped = 1; if(in_sight) { pline("%s is caught in %s bear trap!", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); } else { if((mptr == &mons[PM_OWLBEAR] || mptr == &mons[PM_BUGBEAR]) && flags.soundok) You_hear("the roaring of an angry bear!"); } } break; case SLP_GAS_TRAP: if (!resists_sleep(mtmp) && !breathless(mptr) && !mtmp->msleeping && mtmp->mcanmove) { mtmp->mcanmove = 0; mtmp->mfrozen = rnd(25); if (in_sight) { pline("%s suddenly falls asleep!", Monnam(mtmp)); seetrap(trap); } } break; case RUST_TRAP: { struct obj *target; if (in_sight) seetrap(trap); switch (rn2(5)) { case 0: if (in_sight) pline("%s %s on the %s!", A_gush_of_water_hits, mon_nam(mtmp), mbodypart(mtmp, HEAD)); target = which_armor(mtmp, W_ARMH); (void) rust_dmg(target, "helmet", 1, TRUE, mtmp); break; case 1: if (in_sight) pline("%s %s's left %s!", A_gush_of_water_hits, mon_nam(mtmp), mbodypart(mtmp, ARM)); target = which_armor(mtmp, W_ARMS); if (rust_dmg(target, "shield", 1, TRUE, mtmp)) break; target = MON_WEP(mtmp); if (target && bimanual(target)) erode_obj(target, FALSE, TRUE); glovecheck: target = which_armor(mtmp, W_ARMG); (void) rust_dmg(target, "gauntlets", 1, TRUE, mtmp); break; case 2: if (in_sight) pline("%s %s's right %s!", A_gush_of_water_hits, mon_nam(mtmp), mbodypart(mtmp, ARM)); erode_obj(MON_WEP(mtmp), FALSE, TRUE); goto glovecheck; default: if (in_sight) pline("%s %s!", A_gush_of_water_hits, mon_nam(mtmp)); for (otmp=mtmp->minvent; otmp; otmp = otmp->nobj) (void) snuff_lit(otmp); target = which_armor(mtmp, W_ARMC); if (target) (void) rust_dmg(target, cloak_simple_name(target), 1, TRUE, mtmp); else { target = which_armor(mtmp, W_ARM); if (target) (void) rust_dmg(target, "armor", 1, TRUE, mtmp); #ifdef TOURIST else { target = which_armor(mtmp, W_ARMU); (void) rust_dmg(target, "shirt", 1, TRUE, mtmp); } #endif } } if (mptr == &mons[PM_IRON_GOLEM]) { if (in_sight) pline("%s falls to pieces!", Monnam(mtmp)); else if(mtmp->mtame) pline("May %s rust in peace.", mon_nam(mtmp)); mondied(mtmp); if (mtmp->mhp <= 0) trapkilled = TRUE; } else if (mptr == &mons[PM_GREMLIN] && rn2(3)) { (void)split_mon(mtmp, (struct monst *)0); } break; } case FIRE_TRAP: mfiretrap: if (in_sight) pline("A %s erupts from the %s under %s!", tower_of_flame, surface(mtmp->mx,mtmp->my), mon_nam(mtmp)); else if (see_it) /* evidently `mtmp' is invisible */ You("see a %s erupt from the %s!", tower_of_flame, surface(mtmp->mx,mtmp->my)); if (resists_fire(mtmp)) { if (in_sight) { shieldeff(mtmp->mx,mtmp->my); pline("%s is uninjured.", Monnam(mtmp)); } } else { int num = d(2,4), alt; boolean immolate = FALSE; /* paper burns very fast, assume straw is tightly * packed and burns a bit slower */ switch (monsndx(mtmp->data)) { case PM_PAPER_GOLEM: immolate = TRUE; alt = mtmp->mhpmax; break; case PM_STRAW_GOLEM: alt = mtmp->mhpmax / 2; break; case PM_WOOD_GOLEM: alt = mtmp->mhpmax / 4; break; case PM_LEATHER_GOLEM: alt = mtmp->mhpmax / 8; break; default: alt = 0; break; } if (alt > num) num = alt; if (thitm(0, mtmp, (struct obj *)0, num, immolate)) trapkilled = TRUE; else /* we know mhp is at least `num' below mhpmax, so no (mhp > mhpmax) check is needed here */ mtmp->mhpmax -= rn2(num + 1); } if (burnarmor(mtmp) || rn2(3)) { (void) destroy_mitem(mtmp, SCROLL_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, SPBOOK_CLASS, AD_FIRE); (void) destroy_mitem(mtmp, POTION_CLASS, AD_FIRE); } if (burn_floor_paper(mtmp->mx, mtmp->my, see_it, FALSE) && !see_it && distu(mtmp->mx, mtmp->my) <= 3*3) You("smell smoke."); if (is_ice(mtmp->mx,mtmp->my)) melt_ice(mtmp->mx,mtmp->my); if (see_it) seetrap(trap); break; case PIT: case SPIKED_PIT: fallverb = "falls"; if (is_flyer(mptr) || is_floater(mptr) || (mtmp->wormno && count_wsegs(mtmp) > 5) || is_clinger(mptr)) { if (!inescapable) break; /* avoids trap */ fallverb = "is dragged"; /* sokoban pit */ } if (!passes_walls(mptr)) mtmp->mtrapped = 1; if (in_sight) { pline("%s %s into %s pit!", Monnam(mtmp), fallverb, a_your[trap->madeby_u]); if (mptr == &mons[PM_PIT_VIPER] || mptr == &mons[PM_PIT_FIEND]) pline("How pitiful. Isn't that the pits?"); seetrap(trap); } mselftouch(mtmp, "Falling, ", FALSE); if (mtmp->mhp <= 0 || thitm(0, mtmp, (struct obj *)0, rnd((tt == PIT) ? 6 : 10), FALSE)) trapkilled = TRUE; break; case HOLE: case TRAPDOOR: if (!Can_fall_thru(&u.uz)) { impossible("mintrap: %ss cannot exist on this level.", defsyms[trap_to_defsym(tt)].explanation); break; /* don't activate it after all */ } if (is_flyer(mptr) || is_floater(mptr) || mptr == &mons[PM_WUMPUS] || (mtmp->wormno && count_wsegs(mtmp) > 5) || mptr->msize >= MZ_HUGE) { if (inescapable) { /* sokoban hole */ if (in_sight) { pline("%s seems to be yanked down!", Monnam(mtmp)); /* suppress message in mlevel_tele_trap() */ in_sight = FALSE; seetrap(trap); } } else break; } /* Fall through */ case LEVEL_TELEP: case MAGIC_PORTAL: { int mlev_res; mlev_res = mlevel_tele_trap(mtmp, trap, inescapable, in_sight); if (mlev_res) return(mlev_res); } break; case TELEP_TRAP: mtele_trap(mtmp, trap, in_sight); break; case WEB: /* Monster in a web. */ if (webmaker(mptr)) break; if (amorphous(mptr) || is_whirly(mptr) || unsolid(mptr)){ if(acidic(mptr) || mptr == &mons[PM_GELATINOUS_CUBE] || mptr == &mons[PM_FIRE_ELEMENTAL]) { if (in_sight) pline("%s %s %s spider web!", Monnam(mtmp), (mptr == &mons[PM_FIRE_ELEMENTAL]) ? "burns" : "dissolves", a_your[trap->madeby_u]); deltrap(trap); newsym(mtmp->mx, mtmp->my); break; } if (in_sight) { pline("%s flows through %s spider web.", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); } break; } tear_web = FALSE; switch (monsndx(mptr)) { case PM_OWLBEAR: /* Eric Backus */ case PM_BUGBEAR: if (!in_sight) { You_hear("the roaring of a confused bear!"); mtmp->mtrapped = 1; break; } /* fall though */ default: if (mptr->mlet == S_GIANT || (mptr->mlet == S_DRAGON && extra_nasty(mptr)) || /* excl. babies */ (mtmp->wormno && count_wsegs(mtmp) > 5)) { tear_web = TRUE; } else if (in_sight) { pline("%s is caught in %s spider web.", Monnam(mtmp), a_your[trap->madeby_u]); seetrap(trap); } mtmp->mtrapped = tear_web ? 0 : 1; break; /* this list is fairly arbitrary; it deliberately excludes wumpus & giant/ettin zombies/mummies */ case PM_TITANOTHERE: case PM_BALUCHITHERIUM: case PM_PURPLE_WORM: case PM_JABBERWOCK: case PM_IRON_GOLEM: case PM_BALROG: case PM_KRAKEN: case PM_MASTODON: tear_web = TRUE; break; } if (tear_web) { if (in_sight) pline("%s tears through %s spider web!", Monnam(mtmp), a_your[trap->madeby_u]); deltrap(trap); newsym(mtmp->mx, mtmp->my); } break; case STATUE_TRAP: break; case MAGIC_TRAP: /* A magic trap. Monsters usually immune. */ if (!rn2(21)) goto mfiretrap; break; case ANTI_MAGIC: break; case LANDMINE: if(rn2(3)) break; /* monsters usually don't set it off */ if(is_flyer(mptr)) { boolean already_seen = trap->tseen; if (in_sight && !already_seen) { pline("A trigger appears in a pile of soil below %s.", mon_nam(mtmp)); seetrap(trap); } if (rn2(3)) break; if (in_sight) { newsym(mtmp->mx, mtmp->my); pline_The("air currents set %s off!", already_seen ? "a land mine" : "it"); } } else if(in_sight) { newsym(mtmp->mx, mtmp->my); pline("KAABLAMM!!! %s triggers %s land mine!", Monnam(mtmp), a_your[trap->madeby_u]); } if (!in_sight) pline("Kaablamm! You hear an explosion in the distance!"); blow_up_landmine(trap); if (thitm(0, mtmp, (struct obj *)0, rnd(16), FALSE)) trapkilled = TRUE; else { /* monsters recursively fall into new pit */ if (mintrap(mtmp) == 2) trapkilled=TRUE; } /* a boulder may fill the new pit, crushing monster */ fill_pit(trap->tx, trap->ty); if (mtmp->mhp <= 0) trapkilled = TRUE; if (unconscious()) { multi = -1; nomovemsg="The explosion awakens you!"; } break; case POLY_TRAP: if (resists_magm(mtmp)) { shieldeff(mtmp->mx, mtmp->my); } else if (!resist(mtmp, WAND_CLASS, 0, NOTELL)) { (void) newcham(mtmp, (struct permonst *)0, FALSE, FALSE); if (in_sight) seetrap(trap); } break; case ROLLING_BOULDER_TRAP: if (!is_flyer(mptr)) { int style = ROLL | (in_sight ? 0 : LAUNCH_UNSEEN); newsym(mtmp->mx,mtmp->my); if (in_sight) pline("Click! %s triggers %s.", Monnam(mtmp), trap->tseen ? "a rolling boulder trap" : something); if (launch_obj(BOULDER, trap->launch.x, trap->launch.y, trap->launch2.x, trap->launch2.y, style)) { if (in_sight) trap->tseen = TRUE; if (mtmp->mhp <= 0) trapkilled = TRUE; } else { deltrap(trap); newsym(mtmp->mx,mtmp->my); } } break; default: impossible("Some monster encountered a strange trap of type %d.", tt); } } if(trapkilled) return 2; return mtmp->mtrapped; } #endif /* OVL1 */ #ifdef OVLB /* Combine cockatrice checks into single functions to avoid repeating code. */ void instapetrify(str) const char *str; { if (Stone_resistance) return; if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) return; You("turn to stone..."); killer_format = KILLED_BY; killer = str; done(STONING); } void minstapetrify(mon,byplayer) struct monst *mon; boolean byplayer; { if (resists_ston(mon)) return; if (poly_when_stoned(mon->data)) { mon_to_stone(mon); return; } /* give a " is slowing down" message and also remove intrinsic speed (comparable to similar effect on the hero) */ mon_adjust_speed(mon, -3, (struct obj *)0); if (cansee(mon->mx, mon->my)) pline("%s turns to stone.", Monnam(mon)); if (byplayer) { stoned = TRUE; xkilled(mon,0); } else monstone(mon); } void selftouch(arg) const char *arg; { char kbuf[BUFSZ]; if(uwep && uwep->otyp == CORPSE && touch_petrifies(&mons[uwep->corpsenm]) && !Stone_resistance) { pline("%s touch the %s corpse.", arg, mons[uwep->corpsenm].mname); Sprintf(kbuf, "%s corpse", an(mons[uwep->corpsenm].mname)); instapetrify(kbuf); } /* Or your secondary weapon, if wielded */ if(u.twoweap && uswapwep && uswapwep->otyp == CORPSE && touch_petrifies(&mons[uswapwep->corpsenm]) && !Stone_resistance){ pline("%s touch the %s corpse.", arg, mons[uswapwep->corpsenm].mname); Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname)); instapetrify(kbuf); } } void mselftouch(mon,arg,byplayer) struct monst *mon; const char *arg; boolean byplayer; { struct obj *mwep = MON_WEP(mon); if (mwep && mwep->otyp == CORPSE && touch_petrifies(&mons[mwep->corpsenm])) { if (cansee(mon->mx, mon->my)) { pline("%s%s touches the %s corpse.", arg ? arg : "", arg ? mon_nam(mon) : Monnam(mon), mons[mwep->corpsenm].mname); } minstapetrify(mon, byplayer); } } void float_up() { if(u.utrap) { if(u.utraptype == TT_PIT) { u.utrap = 0; You("float up, out of the pit!"); vision_full_recalc = 1; /* vision limits change */ fill_pit(u.ux, u.uy); } else if (u.utraptype == TT_INFLOOR) { Your("body pulls upward, but your %s are still stuck.", makeplural(body_part(LEG))); } else { You("float up, only your %s is still stuck.", body_part(LEG)); } } else if(Is_waterlevel(&u.uz)) pline("It feels as though you've lost some weight."); else if(u.uinwater) spoteffects(TRUE); else if(u.uswallow) You(is_animal(u.ustuck->data) ? "float away from the %s." : "spiral up into %s.", is_animal(u.ustuck->data) ? surface(u.ux, u.uy) : mon_nam(u.ustuck)); else if (Hallucination) pline("Up, up, and awaaaay! You're walking on air!"); else if(Is_airlevel(&u.uz)) You("gain control over your movements."); else You("start to float in the air!"); #ifdef STEED if (u.usteed && !is_floater(u.usteed->data) && !is_flyer(u.usteed->data)) { if (Lev_at_will) pline("%s magically floats up!", Monnam(u.usteed)); else { You("cannot stay on %s.", mon_nam(u.usteed)); dismount_steed(DISMOUNT_GENERIC); } } #endif return; } void fill_pit(x, y) int x, y; { struct obj *otmp; struct trap *t; if ((t = t_at(x, y)) && ((t->ttyp == PIT) || (t->ttyp == SPIKED_PIT)) && (otmp = sobj_at(BOULDER, x, y))) { obj_extract_self(otmp); (void) flooreffects(otmp, x, y, "settle"); } } int float_down(hmask, emask) long hmask, emask; /* might cancel timeout */ { register struct trap *trap = (struct trap *)0; d_level current_dungeon_level; boolean no_msg = FALSE; HLevitation &= ~hmask; ELevitation &= ~emask; if(Levitation) return(0); /* maybe another ring/potion/boots */ if(u.uswallow) { You("float down, but you are still %s.", is_animal(u.ustuck->data) ? "swallowed" : "engulfed"); return(1); } if (Punished && !carried(uball) && (is_pool(uball->ox, uball->oy) || ((trap = t_at(uball->ox, uball->oy)) && ((trap->ttyp == PIT) || (trap->ttyp == SPIKED_PIT) || (trap->ttyp == TRAPDOOR) || (trap->ttyp == HOLE))))) { u.ux0 = u.ux; u.uy0 = u.uy; u.ux = uball->ox; u.uy = uball->oy; movobj(uchain, uball->ox, uball->oy); newsym(u.ux0, u.uy0); vision_full_recalc = 1; /* in case the hero moved. */ } /* check for falling into pool - added by GAN 10/20/86 */ if(!Flying) { if (!u.uswallow && u.ustuck) { if (sticks(youmonst.data)) You("aren't able to maintain your hold on %s.", mon_nam(u.ustuck)); else pline("Startled, %s can no longer hold you!", mon_nam(u.ustuck)); u.ustuck = 0; } /* kludge alert: * drown() and lava_effects() print various messages almost * every time they're called which conflict with the "fall * into" message below. Thus, we want to avoid printing * confusing, duplicate or out-of-order messages. * Use knowledge of the two routines as a hack -- this * should really be handled differently -dlc */ if(is_pool(u.ux,u.uy) && !Wwalking && !Swimming && !u.uinwater) no_msg = drown(); if(is_lava(u.ux,u.uy)) { (void) lava_effects(); no_msg = TRUE; } } if (!trap) { trap = t_at(u.ux,u.uy); if(Is_airlevel(&u.uz)) You("begin to tumble in place."); else if (Is_waterlevel(&u.uz) && !no_msg) You_feel("heavier."); /* u.uinwater msgs already in spoteffects()/drown() */ else if (!u.uinwater && !no_msg) { #ifdef STEED if (!(emask & W_SADDLE)) #endif { boolean sokoban_trap = (In_sokoban(&u.uz) && trap); if (Hallucination) pline("Bummer! You've %s.", is_pool(u.ux,u.uy) ? "splashed down" : sokoban_trap ? "crashed" : "hit the ground"); else { if (!sokoban_trap) You("float gently to the %s.", surface(u.ux, u.uy)); else { /* Justification elsewhere for Sokoban traps * is based on air currents. This is * consistent with that. * The unexpected additional force of the * air currents once leviation * ceases knocks you off your feet. */ You("fall over."); losehp(rnd(2), "dangerous winds", KILLED_BY); #ifdef STEED if (u.usteed) dismount_steed(DISMOUNT_FELL); #endif selftouch("As you fall, you"); } } } } } /* can't rely on u.uz0 for detecting trap door-induced level change; it gets changed to reflect the new level before we can check it */ assign_level(¤t_dungeon_level, &u.uz); if(trap) switch(trap->ttyp) { case STATUE_TRAP: break; case HOLE: case TRAPDOOR: if(!Can_fall_thru(&u.uz) || u.ustuck) break; /* fall into next case */ default: if (!u.utrap) /* not already in the trap */ dotrap(trap, 0); } if (!Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !u.uswallow && /* falling through trap door calls goto_level, and goto_level does its own pickup() call */ on_level(&u.uz, ¤t_dungeon_level)) (void) pickup(1); return 1; } STATIC_OVL void dofiretrap(box) struct obj *box; /* null for floor trap */ { boolean see_it = !Blind; int num, alt; /* Bug: for box case, the equivalent of burn_floor_paper() ought * to be done upon its contents. */ if ((box && !carried(box)) ? is_pool(box->ox, box->oy) : Underwater) { pline("A cascade of steamy bubbles erupts from %s!", the(box ? xname(box) : surface(u.ux,u.uy))); if (Fire_resistance) You("are uninjured."); else losehp(rnd(3), "boiling water", KILLED_BY); return; } pline("A %s %s from %s!", tower_of_flame, box ? "bursts" : "erupts", the(box ? xname(box) : surface(u.ux,u.uy))); if (Fire_resistance) { shieldeff(u.ux, u.uy); num = rn2(2); } else if (Upolyd) { num = d(2,4); switch (u.umonnum) { case PM_PAPER_GOLEM: alt = u.mhmax; break; case PM_STRAW_GOLEM: alt = u.mhmax / 2; break; case PM_WOOD_GOLEM: alt = u.mhmax / 4; break; case PM_LEATHER_GOLEM: alt = u.mhmax / 8; break; default: alt = 0; break; } if (alt > num) num = alt; if (u.mhmax > mons[u.umonnum].mlevel) u.mhmax -= rn2(min(u.mhmax,num + 1)), flags.botl = 1; } else { num = d(2,4); if (u.uhpmax > u.ulevel) u.uhpmax -= rn2(min(u.uhpmax,num + 1)), flags.botl = 1; } if (!num) You("are uninjured."); else losehp(num, tower_of_flame, KILLED_BY_AN); burn_away_slime(); if (burnarmor(&youmonst) || rn2(3)) { destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); } if (!box && burn_floor_paper(u.ux, u.uy, see_it, TRUE) && !see_it) You("smell paper burning."); if (is_ice(u.ux, u.uy)) melt_ice(u.ux, u.uy); } STATIC_OVL void domagictrap() { register int fate = rnd(20); /* What happened to the poor sucker? */ if (fate < 10) { /* Most of the time, it creates some monsters. */ register int cnt = rnd(4); if (!resists_blnd(&youmonst)) { You("are momentarily blinded by a flash of light!"); make_blinded((long)rn1(5,10),FALSE); if (!Blind) Your(vision_clears); } else if (!Blind) { You("see a flash of light!"); } else You_hear("a deafening roar!"); while(cnt--) (void) makemon((struct permonst *) 0, u.ux, u.uy, NO_MM_FLAGS); } else switch (fate) { case 10: case 11: /* sometimes nothing happens */ break; case 12: /* a flash of fire */ dofiretrap((struct obj *)0); break; /* odd feelings */ case 13: pline("A shiver runs up and down your %s!", body_part(SPINE)); break; case 14: You_hear(Hallucination ? "the moon howling at you." : "distant howling."); break; case 15: if (on_level(&u.uz, &qstart_level)) You_feel("%slike the prodigal son.", (flags.female || (Upolyd && is_neuter(youmonst.data))) ? "oddly " : ""); else You("suddenly yearn for %s.", Hallucination ? "Cleveland" : (In_quest(&u.uz) || at_dgn_entrance("The Quest")) ? "your nearby homeland" : "your distant homeland"); break; case 16: Your("pack shakes violently!"); break; case 17: You(Hallucination ? "smell hamburgers." : "smell charred flesh."); break; case 18: You_feel("tired."); break; /* very occasionally something nice happens. */ case 19: /* tame nearby monsters */ { register int i,j; register struct monst *mtmp; (void) adjattrib(A_CHA,1,FALSE); for(i = -1; i <= 1; i++) for(j = -1; j <= 1; j++) { if(!isok(u.ux+i, u.uy+j)) continue; mtmp = m_at(u.ux+i, u.uy+j); if(mtmp) (void) tamedog(mtmp, (struct obj *)0); } break; } case 20: /* uncurse stuff */ { struct obj pseudo; long save_conf = HConfusion; pseudo = zeroobj; /* neither cursed nor blessed */ pseudo.otyp = SCR_REMOVE_CURSE; HConfusion = 0L; (void) seffects(&pseudo); HConfusion = save_conf; break; } default: break; } } /* * Scrolls, spellbooks, potions, and flammable items * may get affected by the fire. * * Return number of objects destroyed. --ALI */ int fire_damage(chain, force, here, x, y) struct obj *chain; boolean force, here; xchar x, y; { int chance; struct obj *obj, *otmp, *nobj, *ncobj; int retval = 0; int in_sight = !Blind && couldsee(x, y); /* Don't care if it's lit */ int dindx; for (obj = chain; obj; obj = nobj) { nobj = here ? obj->nexthere : obj->nobj; /* object might light in a controlled manner */ if (catch_lit(obj)) continue; if (Is_container(obj)) { switch (obj->otyp) { case ICE_BOX: continue; /* Immune */ /*NOTREACHED*/ break; case CHEST: chance = 40; break; case LARGE_BOX: chance = 30; break; default: chance = 20; break; } if (!force && (Luck + 5) > rn2(chance)) continue; /* Container is burnt up - dump contents out */ if (in_sight) pline("%s catches fire and burns.", Yname2(obj)); if (Has_contents(obj)) { if (in_sight) pline("Its contents fall out."); for (otmp = obj->cobj; otmp; otmp = ncobj) { ncobj = otmp->nobj; obj_extract_self(otmp); if (!flooreffects(otmp, x, y, "")) place_object(otmp, x, y); } } delobj(obj); retval++; } else if (!force && (Luck + 5) > rn2(20)) { /* chance per item of sustaining damage: * max luck (full moon): 5% * max luck (elsewhen): 10% * avg luck (Luck==0): 75% * awful luck (Luck<-4): 100% */ continue; } else if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) { if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) continue; if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { if (in_sight) pline("Smoke rises from %s.", the(xname(obj))); continue; } dindx = (obj->oclass == SCROLL_CLASS) ? 2 : 3; if (in_sight) pline("%s %s.", Yname2(obj), (obj->quan > 1) ? destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]); delobj(obj); retval++; } else if (obj->oclass == POTION_CLASS) { dindx = 1; if (in_sight) pline("%s %s.", Yname2(obj), (obj->quan > 1) ? destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]); delobj(obj); retval++; } else if (is_flammable(obj) && obj->oeroded < MAX_ERODE && !(obj->oerodeproof || (obj->blessed && !rnl(4)))) { if (in_sight) { pline("%s %s%s.", Yname2(obj), otense(obj, "burn"), obj->oeroded+1 == MAX_ERODE ? " completely" : obj->oeroded ? " further" : ""); } obj->oeroded++; } } if (retval && !in_sight) You("smell smoke."); return retval; } void water_damage(obj, force, here) register struct obj *obj; register boolean force, here; { struct obj *otmp; /* Scrolls, spellbooks, potions, weapons and pieces of armor may get affected by the water */ for (; obj; obj = otmp) { otmp = here ? obj->nexthere : obj->nobj; (void) snuff_lit(obj); if(obj->otyp == CAN_OF_GREASE && obj->spe > 0) { continue; } else if(obj->greased) { if (force || !rn2(2)) obj->greased = 0; } else if(Is_container(obj) && !Is_box(obj) && (obj->otyp != OILSKIN_SACK || (obj->cursed && !rn2(3)))) { water_damage(obj->cobj, force, FALSE); } else if (!force && (Luck + 5) > rn2(20)) { /* chance per item of sustaining damage: * max luck (full moon): 5% * max luck (elsewhen): 10% * avg luck (Luck==0): 75% * awful luck (Luck<-4): 100% */ continue; } else if (obj->oclass == SCROLL_CLASS) { #ifdef MAIL if (obj->otyp != SCR_MAIL) #endif { obj->otyp = SCR_BLANK_PAPER; obj->spe = 0; } } else if (obj->oclass == SPBOOK_CLASS) { if (obj->otyp == SPE_BOOK_OF_THE_DEAD) pline("Steam rises from %s.", the(xname(obj))); else obj->otyp = SPE_BLANK_PAPER; } else if (obj->oclass == POTION_CLASS) { if (obj->otyp == POT_ACID) { /* damage player/monster? */ pline("A potion explodes!"); delobj(obj); continue; } else if (obj->odiluted) { obj->otyp = POT_WATER; obj->blessed = obj->cursed = 0; obj->odiluted = 0; } else if (obj->otyp != POT_WATER) obj->odiluted++; } else if (is_rustprone(obj) && obj->oeroded < MAX_ERODE && !(obj->oerodeproof || (obj->blessed && !rnl(4)))) { /* all metal stuff and armor except (body armor protected by oilskin cloak) */ if(obj->oclass != ARMOR_CLASS || obj != uarm || !uarmc || uarmc->otyp != OILSKIN_CLOAK || (uarmc->cursed && !rn2(3))) obj->oeroded++; } } } /* * This function is potentially expensive - rolling * inventory list multiple times. Luckily it's seldom needed. * Returns TRUE if disrobing made player unencumbered enough to * crawl out of the current predicament. */ STATIC_OVL boolean emergency_disrobe(lostsome) boolean *lostsome; { int invc = inv_cnt(); while (near_capacity() > (Punished ? UNENCUMBERED : SLT_ENCUMBER)) { register struct obj *obj, *otmp = (struct obj *)0; register int i; /* Pick a random object */ if (invc > 0) { i = rn2(invc); for (obj = invent; obj; obj = obj->nobj) { /* * Undroppables are: body armor, boots, gloves, * amulets, and rings because of the time and effort * in removing them + loadstone and other cursed stuff * for obvious reasons. */ if (!((obj->otyp == LOADSTONE && obj->cursed) || obj == uamul || obj == uleft || obj == uright || obj == ublindf || obj == uarm || obj == uarmc || obj == uarmg || obj == uarmf || #ifdef TOURIST obj == uarmu || #endif (obj->cursed && (obj == uarmh || obj == uarms)) || welded(obj))) otmp = obj; /* reached the mark and found some stuff to drop? */ if (--i < 0 && otmp) break; /* else continue */ } } #ifndef GOLDOBJ if (!otmp) { /* Nothing available left to drop; try gold */ if (u.ugold) { pline("In desperation, you drop your purse."); /* Hack: gold is not in the inventory, so make a gold object * and put it at the head of the inventory list. */ obj = mkgoldobj(u.ugold); /* removes from u.ugold */ obj->in_use = TRUE; u.ugold = obj->quan; /* put the gold back */ assigninvlet(obj); /* might end up as NOINVSYM */ obj->nobj = invent; invent = obj; *lostsome = TRUE; dropx(obj); continue; /* Try again */ } /* We can't even drop gold! */ return (FALSE); } #else if (!otmp) return (FALSE); /* nothing to drop! */ #endif if (otmp->owornmask) remove_worn_item(otmp, FALSE); *lostsome = TRUE; dropx(otmp); invc--; } return(TRUE); } /* * return(TRUE) == player relocated */ boolean drown() { boolean inpool_ok = FALSE, crawl_ok; int i, x, y; /* happily wading in the same contiguous pool */ if (u.uinwater && is_pool(u.ux-u.dx,u.uy-u.dy) && (Swimming || Amphibious)) { /* water effects on objects every now and then */ if (!rn2(5)) inpool_ok = TRUE; else return(FALSE); } if (!u.uinwater) { You("%s into the water%c", Is_waterlevel(&u.uz) ? "plunge" : "fall", Amphibious || Swimming ? '.' : '!'); if (!Swimming && !Is_waterlevel(&u.uz)) You("sink like %s.", Hallucination ? "the Titanic" : "a rock"); } water_damage(invent, FALSE, FALSE); if (u.umonnum == PM_GREMLIN && rn2(3)) (void)split_mon(&youmonst, (struct monst *)0); else if (u.umonnum == PM_IRON_GOLEM) { You("rust!"); i = d(2,6); if (u.mhmax > i) u.mhmax -= i; losehp(i, "rusting away", KILLED_BY); } if (inpool_ok) return(FALSE); if ((i = number_leashed()) > 0) { pline_The("leash%s slip%s loose.", (i > 1) ? "es" : "", (i > 1) ? "" : "s"); unleash_all(); } if (Amphibious || Swimming) { if (Amphibious) { if (flags.verbose) pline("But you aren't drowning."); if (!Is_waterlevel(&u.uz)) { if (Hallucination) Your("keel hits the bottom."); else You("touch bottom."); } } if (Punished) { unplacebc(); placebc(); } vision_recalc(2); /* unsee old position */ u.uinwater = 1; under_water(1); vision_full_recalc = 1; return(FALSE); } if ((Teleportation || can_teleport(youmonst.data)) && !u.usleep && (Teleport_control || rn2(3) < Luck+2)) { You("attempt a teleport spell."); /* utcsri!carroll */ if (!level.flags.noteleport) { (void) dotele(); if(!is_pool(u.ux,u.uy)) return(TRUE); } else pline_The("attempted teleport spell fails."); } #ifdef STEED if (u.usteed) { dismount_steed(DISMOUNT_GENERIC); if(!is_pool(u.ux,u.uy)) return(TRUE); } #endif crawl_ok = FALSE; x = y = 0; /* lint suppression */ /* if sleeping, wake up now so that we don't crawl out of water while still asleep; we can't do that the same way that waking due to combat is handled; note unmul() clears u.usleep */ if (u.usleep) unmul("Suddenly you wake up!"); /* can't crawl if unable to move (crawl_ok flag stays false) */ if (multi < 0 || (Upolyd && !youmonst.data->mmove)) goto crawl; /* look around for a place to crawl to */ for (i = 0; i < 100; i++) { x = rn1(3,u.ux - 1); y = rn1(3,u.uy - 1); if (goodpos(x, y, &youmonst, 0)) { crawl_ok = TRUE; goto crawl; } } /* one more scan */ for (x = u.ux - 1; x <= u.ux + 1; x++) for (y = u.uy - 1; y <= u.uy + 1; y++) if (goodpos(x, y, &youmonst, 0)) { crawl_ok = TRUE; goto crawl; } crawl: if (crawl_ok) { boolean lost = FALSE; /* time to do some strip-tease... */ boolean succ = Is_waterlevel(&u.uz) ? TRUE : emergency_disrobe(&lost); You("try to crawl out of the water."); if (lost) You("dump some of your gear to lose weight..."); if (succ) { pline("Pheew! That was close."); teleds(x,y,TRUE); return(TRUE); } /* still too much weight */ pline("But in vain."); } u.uinwater = 1; You("drown."); killer_format = KILLED_BY_AN; killer = (levl[u.ux][u.uy].typ == POOL || Is_medusa_level(&u.uz)) ? "pool of water" : "moat"; done(DROWNING); /* oops, we're still alive. better get out of the water. */ while (!safe_teleds(TRUE)) { pline("You're still drowning."); done(DROWNING); } if (u.uinwater) { u.uinwater = 0; You("find yourself back %s.", Is_waterlevel(&u.uz) ? "in an air bubble" : "on land"); } return(TRUE); } void drain_en(n) register int n; { if (!u.uenmax) return; You_feel("your magical energy drain away!"); u.uen -= n; if(u.uen < 0) { u.uenmax += u.uen; if(u.uenmax < 0) u.uenmax = 0; u.uen = 0; } flags.botl = 1; } int dountrap() /* disarm a trap */ { if (near_capacity() >= HVY_ENCUMBER) { pline("You're too strained to do that."); return 0; } if ((nohands(youmonst.data) && !webmaker(youmonst.data)) || !youmonst.data->mmove) { pline("And just how do you expect to do that?"); return 0; } else if (u.ustuck && sticks(youmonst.data)) { pline("You'll have to let go of %s first.", mon_nam(u.ustuck)); return 0; } if (u.ustuck || (welded(uwep) && bimanual(uwep))) { Your("%s seem to be too busy for that.", makeplural(body_part(HAND))); return 0; } return untrap(FALSE); } #endif /* OVLB */ #ifdef OVL2 /* Probability of disabling a trap. Helge Hafting */ STATIC_OVL int untrap_prob(ttmp) struct trap *ttmp; { int chance = 3; /* Only spiders know how to deal with webs reliably */ if (ttmp->ttyp == WEB && !webmaker(youmonst.data)) chance = 30; if (Confusion || Hallucination) chance++; if (Blind) chance++; if (Stunned) chance += 2; if (Fumbling) chance *= 2; /* Your own traps are better known than others. */ if (ttmp && ttmp->madeby_u) chance--; if (Role_if(PM_ROGUE)) { if (rn2(2 * MAXULEV) < u.ulevel) chance--; if (u.uhave.questart && chance > 1) chance--; } else if (Role_if(PM_RANGER) && chance > 1) chance--; return rn2(chance); } /* Replace trap with object(s). Helge Hafting */ STATIC_OVL void cnv_trap_obj(otyp, cnt, ttmp) int otyp; int cnt; struct trap *ttmp; { struct obj *otmp = mksobj(otyp, TRUE, FALSE); otmp->quan=cnt; otmp->owt = weight(otmp); /* Only dart traps are capable of being poisonous */ if (otyp != DART) otmp->opoisoned = 0; place_object(otmp, ttmp->tx, ttmp->ty); /* Sell your own traps only... */ if (ttmp->madeby_u) sellobj(otmp, ttmp->tx, ttmp->ty); stackobj(otmp); newsym(ttmp->tx, ttmp->ty); deltrap(ttmp); } /* while attempting to disarm an adjacent trap, we've fallen into it */ STATIC_OVL void move_into_trap(ttmp) struct trap *ttmp; { int bc; xchar x = ttmp->tx, y = ttmp->ty, bx, by, cx, cy; boolean unused; /* we know there's no monster in the way, and we're not trapped */ if (!Punished || drag_ball(x, y, &bc, &bx, &by, &cx, &cy, &unused, TRUE)) { u.ux0 = u.ux, u.uy0 = u.uy; u.ux = x, u.uy = y; u.umoved = TRUE; newsym(u.ux0, u.uy0); vision_recalc(1); check_leash(u.ux0, u.uy0); if (Punished) move_bc(0, bc, bx, by, cx, cy); spoteffects(FALSE); /* dotrap() */ exercise(A_WIS, FALSE); } } /* 0: doesn't even try * 1: tries and fails * 2: succeeds */ STATIC_OVL int try_disarm(ttmp, force_failure) struct trap *ttmp; boolean force_failure; { struct monst *mtmp = m_at(ttmp->tx,ttmp->ty); int ttype = ttmp->ttyp; boolean under_u = (!u.dx && !u.dy); boolean holdingtrap = (ttype == BEAR_TRAP || ttype == WEB); /* Test for monster first, monsters are displayed instead of trap. */ if (mtmp && (!mtmp->mtrapped || !holdingtrap)) { pline("%s is in the way.", Monnam(mtmp)); return 0; } /* We might be forced to move onto the trap's location. */ if (sobj_at(BOULDER, ttmp->tx, ttmp->ty) && !Passes_walls && !under_u) { There("is a boulder in your way."); return 0; } /* duplicate tight-space checks from test_move */ if (u.dx && u.dy && bad_rock(youmonst.data,u.ux,ttmp->ty) && bad_rock(youmonst.data,ttmp->tx,u.uy)) { if ((invent && (inv_weight() + weight_cap() > 600)) || bigmonst(youmonst.data)) { /* don't allow untrap if they can't get thru to it */ You("are unable to reach the %s!", defsyms[trap_to_defsym(ttype)].explanation); return 0; } } /* untrappable traps are located on the ground. */ if (!can_reach_floor()) { #ifdef STEED if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) You("aren't skilled enough to reach from %s.", mon_nam(u.usteed)); else #endif You("are unable to reach the %s!", defsyms[trap_to_defsym(ttype)].explanation); return 0; } /* Will our hero succeed? */ if (force_failure || untrap_prob(ttmp)) { if (rnl(5)) { pline("Whoops..."); if (mtmp) { /* must be a trap that holds monsters */ if (ttype == BEAR_TRAP) { if (mtmp->mtame) abuse_dog(mtmp); if ((mtmp->mhp -= rnd(4)) <= 0) killed(mtmp); } else if (ttype == WEB) { if (!webmaker(youmonst.data)) { struct trap *ttmp2 = maketrap(u.ux, u.uy, WEB); if (ttmp2) { pline_The("webbing sticks to you. You're caught too!"); dotrap(ttmp2, NOWEBMSG); #ifdef STEED if (u.usteed && u.utrap) { /* you, not steed, are trapped */ dismount_steed(DISMOUNT_FELL); } #endif } } else pline("%s remains entangled.", Monnam(mtmp)); } } else if (under_u) { dotrap(ttmp, 0); } else { move_into_trap(ttmp); } } else { pline("%s %s is difficult to %s.", ttmp->madeby_u ? "Your" : under_u ? "This" : "That", defsyms[trap_to_defsym(ttype)].explanation, (ttype == WEB) ? "remove" : "disarm"); } return 1; } return 2; } STATIC_OVL void reward_untrap(ttmp, mtmp) struct trap *ttmp; struct monst *mtmp; { if (!ttmp->madeby_u) { if (rnl(10) < 8 && !mtmp->mpeaceful && !mtmp->msleeping && !mtmp->mfrozen && !mindless(mtmp->data) && mtmp->data->mlet != S_HUMAN) { mtmp->mpeaceful = 1; set_malign(mtmp); /* reset alignment */ pline("%s is grateful.", Monnam(mtmp)); } /* Helping someone out of a trap is a nice thing to do, * A lawful may be rewarded, but not too often. */ if (!rn2(3) && !rnl(8) && u.ualign.type == A_LAWFUL) { adjalign(1); You_feel("that you did the right thing."); } } } STATIC_OVL int disarm_holdingtrap(ttmp) /* Helge Hafting */ struct trap *ttmp; { struct monst *mtmp; int fails = try_disarm(ttmp, FALSE); if (fails < 2) return fails; /* ok, disarm it. */ /* untrap the monster, if any. There's no need for a cockatrice test, only the trap is touched */ if ((mtmp = m_at(ttmp->tx,ttmp->ty)) != 0) { mtmp->mtrapped = 0; You("remove %s %s from %s.", the_your[ttmp->madeby_u], (ttmp->ttyp == BEAR_TRAP) ? "bear trap" : "webbing", mon_nam(mtmp)); reward_untrap(ttmp, mtmp); } else { if (ttmp->ttyp == BEAR_TRAP) { You("disarm %s bear trap.", the_your[ttmp->madeby_u]); cnv_trap_obj(BEARTRAP, 1, ttmp); } else /* if (ttmp->ttyp == WEB) */ { You("succeed in removing %s web.", the_your[ttmp->madeby_u]); deltrap(ttmp); } } newsym(u.ux + u.dx, u.uy + u.dy); return 1; } STATIC_OVL int disarm_landmine(ttmp) /* Helge Hafting */ struct trap *ttmp; { int fails = try_disarm(ttmp, FALSE); if (fails < 2) return fails; You("disarm %s land mine.", the_your[ttmp->madeby_u]); cnv_trap_obj(LAND_MINE, 1, ttmp); return 1; } /* getobj will filter down to cans of grease and known potions of oil */ static NEARDATA const char oil[] = { ALL_CLASSES, TOOL_CLASS, POTION_CLASS, 0 }; /* it may not make much sense to use grease on floor boards, but so what? */ STATIC_OVL int disarm_squeaky_board(ttmp) struct trap *ttmp; { struct obj *obj; boolean bad_tool; int fails; obj = getobj(oil, "untrap with"); if (!obj) return 0; bad_tool = (obj->cursed || ((obj->otyp != POT_OIL || obj->lamplit) && (obj->otyp != CAN_OF_GREASE || !obj->spe))); fails = try_disarm(ttmp, bad_tool); if (fails < 2) return fails; /* successfully used oil or grease to fix squeaky board */ if (obj->otyp == CAN_OF_GREASE) { consume_obj_charge(obj, TRUE); } else { useup(obj); /* oil */ makeknown(POT_OIL); } You("repair the squeaky board."); /* no madeby_u */ deltrap(ttmp); newsym(u.ux + u.dx, u.uy + u.dy); more_experienced(1, 5); newexplevel(); return 1; } /* removes traps that shoot arrows, darts, etc. */ STATIC_OVL int disarm_shooting_trap(ttmp, otyp) struct trap *ttmp; int otyp; { int fails = try_disarm(ttmp, FALSE); if (fails < 2) return fails; You("disarm %s trap.", the_your[ttmp->madeby_u]); cnv_trap_obj(otyp, 50-rnl(50), ttmp); return 1; } /* Is the weight too heavy? * Formula as in near_capacity() & check_capacity() */ STATIC_OVL int try_lift(mtmp, ttmp, wt, stuff) struct monst *mtmp; struct trap *ttmp; int wt; boolean stuff; { int wc = weight_cap(); if (((wt * 2) / wc) >= HVY_ENCUMBER) { pline("%s is %s for you to lift.", Monnam(mtmp), stuff ? "carrying too much" : "too heavy"); if (!ttmp->madeby_u && !mtmp->mpeaceful && mtmp->mcanmove && !mindless(mtmp->data) && mtmp->data->mlet != S_HUMAN && rnl(10) < 3) { mtmp->mpeaceful = 1; set_malign(mtmp); /* reset alignment */ pline("%s thinks it was nice of you to try.", Monnam(mtmp)); } return 0; } return 1; } /* Help trapped monster (out of a (spiked) pit) */ STATIC_OVL int help_monster_out(mtmp, ttmp) struct monst *mtmp; struct trap *ttmp; { int wt; struct obj *otmp; boolean uprob; /* * This works when levitating too -- consistent with the ability * to hit monsters while levitating. * * Should perhaps check that our hero has arms/hands at the * moment. Helping can also be done by engulfing... * * Test the monster first - monsters are displayed before traps. */ if (!mtmp->mtrapped) { pline("%s isn't trapped.", Monnam(mtmp)); return 0; } /* Do you have the necessary capacity to lift anything? */ if (check_capacity((char *)0)) return 1; /* Will our hero succeed? */ if ((uprob = untrap_prob(ttmp)) && !mtmp->msleeping && mtmp->mcanmove) { You("try to reach out your %s, but %s backs away skeptically.", makeplural(body_part(ARM)), mon_nam(mtmp)); return 1; } /* is it a cockatrice?... */ if (touch_petrifies(mtmp->data) && !uarmg && !Stone_resistance) { You("grab the trapped %s using your bare %s.", mtmp->data->mname, makeplural(body_part(HAND))); if (poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM)) display_nhwindow(WIN_MESSAGE, FALSE); else { char kbuf[BUFSZ]; Sprintf(kbuf, "trying to help %s out of a pit", an(mtmp->data->mname)); instapetrify(kbuf); return 1; } } /* need to do cockatrice check first if sleeping or paralyzed */ if (uprob) { You("try to grab %s, but cannot get a firm grasp.", mon_nam(mtmp)); if (mtmp->msleeping) { mtmp->msleeping = 0; pline("%s awakens.", Monnam(mtmp)); } return 1; } You("reach out your %s and grab %s.", makeplural(body_part(ARM)), mon_nam(mtmp)); if (mtmp->msleeping) { mtmp->msleeping = 0; pline("%s awakens.", Monnam(mtmp)); } else if (mtmp->mfrozen && !rn2(mtmp->mfrozen)) { /* After such manhandling, perhaps the effect wears off */ mtmp->mcanmove = 1; mtmp->mfrozen = 0; pline("%s stirs.", Monnam(mtmp)); } /* is the monster too heavy? */ wt = inv_weight() + mtmp->data->cwt; if (!try_lift(mtmp, ttmp, wt, FALSE)) return 1; /* is the monster with inventory too heavy? */ for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) wt += otmp->owt; if (!try_lift(mtmp, ttmp, wt, TRUE)) return 1; You("pull %s out of the pit.", mon_nam(mtmp)); mtmp->mtrapped = 0; fill_pit(mtmp->mx, mtmp->my); reward_untrap(ttmp, mtmp); return 1; } int untrap(force) boolean force; { register struct obj *otmp; register boolean confused = (Confusion > 0 || Hallucination > 0); register int x,y; int ch; struct trap *ttmp; struct monst *mtmp; boolean trap_skipped = FALSE; boolean box_here = FALSE; boolean deal_with_floor_trap = FALSE; char the_trap[BUFSZ], qbuf[QBUFSZ]; int containercnt = 0; if(!getdir((char *)0)) return(0); x = u.ux + u.dx; y = u.uy + u.dy; for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) { if(Is_box(otmp) && !u.dx && !u.dy) { box_here = TRUE; containercnt++; if (containercnt > 1) break; } } if ((ttmp = t_at(x,y)) && ttmp->tseen) { deal_with_floor_trap = TRUE; Strcpy(the_trap, the(defsyms[trap_to_defsym(ttmp->ttyp)].explanation)); if (box_here) { if (ttmp->ttyp == PIT || ttmp->ttyp == SPIKED_PIT) { You_cant("do much about %s%s.", the_trap, u.utrap ? " that you're stuck in" : " while standing on the edge of it"); trap_skipped = TRUE; deal_with_floor_trap = FALSE; } else { Sprintf(qbuf, "There %s and %s here. %s %s?", (containercnt == 1) ? "is a container" : "are containers", an(defsyms[trap_to_defsym(ttmp->ttyp)].explanation), ttmp->ttyp == WEB ? "Remove" : "Disarm", the_trap); switch (ynq(qbuf)) { case 'q': return(0); case 'n': trap_skipped = TRUE; deal_with_floor_trap = FALSE; break; } } } if (deal_with_floor_trap) { if (u.utrap) { You("cannot deal with %s while trapped%s!", the_trap, (x == u.ux && y == u.uy) ? " in it" : ""); return 1; } switch(ttmp->ttyp) { case BEAR_TRAP: case WEB: return disarm_holdingtrap(ttmp); case LANDMINE: return disarm_landmine(ttmp); case SQKY_BOARD: return disarm_squeaky_board(ttmp); case DART_TRAP: return disarm_shooting_trap(ttmp, DART); case ARROW_TRAP: return disarm_shooting_trap(ttmp, ARROW); case PIT: case SPIKED_PIT: if (!u.dx && !u.dy) { You("are already on the edge of the pit."); return 0; } if (!(mtmp = m_at(x,y))) { pline("Try filling the pit instead."); return 0; } return help_monster_out(mtmp, ttmp); default: You("cannot disable %s trap.", (u.dx || u.dy) ? "that" : "this"); return 0; } } } /* end if */ if(!u.dx && !u.dy) { for(otmp = level.objects[x][y]; otmp; otmp = otmp->nexthere) if(Is_box(otmp)) { Sprintf(qbuf, "There is %s here. Check it for traps?", safe_qbuf("", sizeof("There is here. Check it for traps?"), doname(otmp), an(simple_typename(otmp->otyp)), "a box")); switch (ynq(qbuf)) { case 'q': return(0); case 'n': continue; } #ifdef STEED if (u.usteed && P_SKILL(P_RIDING) < P_BASIC) { You("aren't skilled enough to reach from %s.", mon_nam(u.usteed)); return(0); } #endif if((otmp->otrapped && (force || (!confused && rn2(MAXULEV + 1 - u.ulevel) < 10))) || (!force && confused && !rn2(3))) { You("find a trap on %s!", the(xname(otmp))); if (!confused) exercise(A_WIS, TRUE); switch (ynq("Disarm it?")) { case 'q': return(1); case 'n': trap_skipped = TRUE; continue; } if(otmp->otrapped) { exercise(A_DEX, TRUE); ch = ACURR(A_DEX) + u.ulevel; if (Role_if(PM_ROGUE)) ch *= 2; if(!force && (confused || Fumbling || rnd(75+level_difficulty()/2) > ch)) { (void) chest_trap(otmp, FINGER, TRUE); } else { You("disarm it!"); otmp->otrapped = 0; } } else pline("That %s was not trapped.", xname(otmp)); return(1); } else { You("find no traps on %s.", the(xname(otmp))); return(1); } } You(trap_skipped ? "find no other traps here." : "know of no traps here."); return(0); } if ((mtmp = m_at(x,y)) && mtmp->m_ap_type == M_AP_FURNITURE && (mtmp->mappearance == S_hcdoor || mtmp->mappearance == S_vcdoor) && !Protection_from_shape_changers) { stumble_onto_mimic(mtmp); return(1); } if (!IS_DOOR(levl[x][y].typ)) { if ((ttmp = t_at(x,y)) && ttmp->tseen) You("cannot disable that trap."); else You("know of no traps there."); return(0); } switch (levl[x][y].doormask) { case D_NODOOR: You("%s no door there.", Blind ? "feel" : "see"); return(0); case D_ISOPEN: pline("This door is safely open."); return(0); case D_BROKEN: pline("This door is broken."); return(0); } if ((levl[x][y].doormask & D_TRAPPED && (force || (!confused && rn2(MAXULEV - u.ulevel + 11) < 10))) || (!force && confused && !rn2(3))) { You("find a trap on the door!"); exercise(A_WIS, TRUE); if (ynq("Disarm it?") != 'y') return(1); if (levl[x][y].doormask & D_TRAPPED) { ch = 15 + (Role_if(PM_ROGUE) ? u.ulevel*3 : u.ulevel); exercise(A_DEX, TRUE); if(!force && (confused || Fumbling || rnd(75+level_difficulty()/2) > ch)) { You("set it off!"); b_trapped("door", FINGER); levl[x][y].doormask = D_NODOOR; unblock_point(x, y); newsym(x, y); /* (probably ought to charge for this damage...) */ if (*in_rooms(x, y, SHOPBASE)) add_damage(x, y, 0L); } else { You("disarm it!"); levl[x][y].doormask &= ~D_TRAPPED; } } else pline("This door was not trapped."); return(1); } else { You("find no traps on the door."); return(1); } } #endif /* OVL2 */ #ifdef OVLB /* only called when the player is doing something to the chest directly */ boolean chest_trap(obj, bodypart, disarm) register struct obj *obj; register int bodypart; boolean disarm; { register struct obj *otmp = obj, *otmp2; char buf[80]; const char *msg; coord cc; if (get_obj_location(obj, &cc.x, &cc.y, 0)) /* might be carried */ obj->ox = cc.x, obj->oy = cc.y; otmp->otrapped = 0; /* trap is one-shot; clear flag first in case chest kills you and ends up in bones file */ You(disarm ? "set it off!" : "trigger a trap!"); display_nhwindow(WIN_MESSAGE, FALSE); if (Luck > -13 && rn2(13+Luck) > 7) { /* saved by luck */ /* trap went off, but good luck prevents damage */ switch (rn2(13)) { case 12: case 11: msg = "explosive charge is a dud"; break; case 10: case 9: msg = "electric charge is grounded"; break; case 8: case 7: msg = "flame fizzles out"; break; case 6: case 5: case 4: msg = "poisoned needle misses"; break; case 3: case 2: case 1: case 0: msg = "gas cloud blows away"; break; default: impossible("chest disarm bug"); msg = (char *)0; break; } if (msg) pline("But luckily the %s!", msg); } else { switch(rn2(20) ? ((Luck >= 13) ? 0 : rn2(13-Luck)) : rn2(26)) { case 25: case 24: case 23: case 22: case 21: { struct monst *shkp = 0; long loss = 0L; boolean costly, insider; register xchar ox = obj->ox, oy = obj->oy; /* the obj location need not be that of player */ costly = (costly_spot(ox, oy) && (shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE))) != (struct monst *)0); insider = (*u.ushops && inside_shop(u.ux, u.uy) && *in_rooms(ox, oy, SHOPBASE) == *u.ushops); pline("%s!", Tobjnam(obj, "explode")); Sprintf(buf, "exploding %s", xname(obj)); if(costly) loss += stolen_value(obj, ox, oy, (boolean)shkp->mpeaceful, TRUE); delete_contents(obj); /* we're about to delete all things at this location, * which could include the ball & chain. * If we attempt to call unpunish() in the * for-loop below we can end up with otmp2 * being invalid once the chain is gone. * Deal with ball & chain right now instead. */ if (Punished && !carried(uball) && ((uchain->ox == u.ux && uchain->oy == u.uy) || (uball->ox == u.ux && uball->oy == u.uy))) unpunish(); for(otmp = level.objects[u.ux][u.uy]; otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if(costly) loss += stolen_value(otmp, otmp->ox, otmp->oy, (boolean)shkp->mpeaceful, TRUE); delobj(otmp); } wake_nearby(); losehp(d(6,6), buf, KILLED_BY_AN); exercise(A_STR, FALSE); if(costly && loss) { if(insider) You("owe %ld %s for objects destroyed.", loss, currency(loss)); else { You("caused %ld %s worth of damage!", loss, currency(loss)); make_angry_shk(shkp, ox, oy); } } return TRUE; } case 20: case 19: case 18: case 17: pline("A cloud of noxious gas billows from %s.", the(xname(obj))); poisoned("gas cloud", A_STR, "cloud of poison gas",15); exercise(A_CON, FALSE); break; case 16: case 15: case 14: case 13: You_feel("a needle prick your %s.",body_part(bodypart)); poisoned("needle", A_CON, "poisoned needle",10); exercise(A_CON, FALSE); break; case 12: case 11: case 10: case 9: dofiretrap(obj); break; case 8: case 7: case 6: { int dmg; You("are jolted by a surge of electricity!"); if(Shock_resistance) { shieldeff(u.ux, u.uy); You("don't seem to be affected."); dmg = 0; } else dmg = d(4, 4); destroy_item(RING_CLASS, AD_ELEC); destroy_item(WAND_CLASS, AD_ELEC); if (dmg) losehp(dmg, "electric shock", KILLED_BY_AN); break; } case 5: case 4: case 3: if (!Free_action) { pline("Suddenly you are frozen in place!"); nomul(-d(5, 6)); exercise(A_DEX, FALSE); nomovemsg = You_can_move_again; } else You("momentarily stiffen."); break; case 2: case 1: case 0: pline("A cloud of %s gas billows from %s.", Blind ? blindgas[rn2(SIZE(blindgas))] : rndcolor(), the(xname(obj))); if(!Stunned) { if (Hallucination) pline("What a groovy feeling!"); else if (Blind) You("%s and get dizzy...", stagger(youmonst.data, "stagger")); else You("%s and your vision blurs...", stagger(youmonst.data, "stagger")); } make_stunned(HStun + rn1(7, 16),FALSE); (void) make_hallucinated(HHallucination + rn1(5, 16),FALSE,0L); break; default: impossible("bad chest trap"); break; } bot(); /* to get immediate botl re-display */ } return FALSE; } #endif /* OVLB */ #ifdef OVL0 struct trap * t_at(x,y) register int x, y; { register struct trap *trap = ftrap; while(trap) { if(trap->tx == x && trap->ty == y) return(trap); trap = trap->ntrap; } return((struct trap *)0); } #endif /* OVL0 */ #ifdef OVLB void deltrap(trap) register struct trap *trap; { register struct trap *ttmp; if(trap == ftrap) ftrap = ftrap->ntrap; else { for(ttmp = ftrap; ttmp->ntrap != trap; ttmp = ttmp->ntrap) ; ttmp->ntrap = trap->ntrap; } dealloc_trap(trap); } boolean delfloortrap(ttmp) register struct trap *ttmp; { /* Destroy a trap that emanates from the floor. */ /* some of these are arbitrary -dlc */ if (ttmp && ((ttmp->ttyp == SQKY_BOARD) || (ttmp->ttyp == BEAR_TRAP) || (ttmp->ttyp == LANDMINE) || (ttmp->ttyp == FIRE_TRAP) || (ttmp->ttyp == PIT) || (ttmp->ttyp == SPIKED_PIT) || (ttmp->ttyp == HOLE) || (ttmp->ttyp == TRAPDOOR) || (ttmp->ttyp == TELEP_TRAP) || (ttmp->ttyp == LEVEL_TELEP) || (ttmp->ttyp == WEB) || (ttmp->ttyp == MAGIC_TRAP) || (ttmp->ttyp == ANTI_MAGIC))) { register struct monst *mtmp; if (ttmp->tx == u.ux && ttmp->ty == u.uy) { u.utrap = 0; u.utraptype = 0; } else if ((mtmp = m_at(ttmp->tx, ttmp->ty)) != 0) { mtmp->mtrapped = 0; } deltrap(ttmp); return TRUE; } else return FALSE; } /* used for doors (also tins). can be used for anything else that opens. */ void b_trapped(item, bodypart) register const char *item; register int bodypart; { register int lvl = level_difficulty(); int dmg = rnd(5 + (lvl < 5 ? lvl : 2+lvl/2)); pline("KABOOM!! %s was booby-trapped!", The(item)); wake_nearby(); losehp(dmg, "explosion", KILLED_BY_AN); exercise(A_STR, FALSE); if (bodypart) exercise(A_CON, FALSE); make_stunned(HStun + dmg, TRUE); } /* Monster is hit by trap. */ /* Note: doesn't work if both obj and d_override are null */ STATIC_OVL boolean thitm(tlev, mon, obj, d_override, nocorpse) int tlev; struct monst *mon; struct obj *obj; int d_override; boolean nocorpse; { int strike; boolean trapkilled = FALSE; if (d_override) strike = 1; else if (obj) strike = (find_mac(mon) + tlev + obj->spe <= rnd(20)); else strike = (find_mac(mon) + tlev <= rnd(20)); /* Actually more accurate than thitu, which doesn't take * obj->spe into account. */ if(!strike) { if (obj && cansee(mon->mx, mon->my)) pline("%s is almost hit by %s!", Monnam(mon), doname(obj)); } else { int dam = 1; if (obj && cansee(mon->mx, mon->my)) pline("%s is hit by %s!", Monnam(mon), doname(obj)); if (d_override) dam = d_override; else if (obj) { dam = dmgval(obj, mon); if (dam < 1) dam = 1; } if ((mon->mhp -= dam) <= 0) { int xx = mon->mx; int yy = mon->my; monkilled(mon, "", nocorpse ? -AD_RBRE : AD_PHYS); if (mon->mhp <= 0) { newsym(xx, yy); trapkilled = TRUE; } } } if (obj && (!strike || d_override)) { place_object(obj, mon->mx, mon->my); stackobj(obj); } else if (obj) dealloc_obj(obj); return trapkilled; } boolean unconscious() { return((boolean)(multi < 0 && (!nomovemsg || u.usleep || !strncmp(nomovemsg,"You regain con", 14) || !strncmp(nomovemsg,"You are consci", 14)))); } static const char lava_killer[] = "molten lava"; boolean lava_effects() { register struct obj *obj, *obj2; int dmg; boolean usurvive; burn_away_slime(); if (likes_lava(youmonst.data)) return FALSE; if (!Fire_resistance) { if(Wwalking) { dmg = d(6,6); pline_The("lava here burns you!"); if(dmg < u.uhp) { losehp(dmg, lava_killer, KILLED_BY); goto burn_stuff; } } else You("fall into the lava!"); usurvive = Lifesaved || discover; #ifdef WIZARD if (wizard) usurvive = TRUE; #endif for(obj = invent; obj; obj = obj2) { obj2 = obj->nobj; if(is_organic(obj) && !obj->oerodeproof) { if(obj->owornmask) { if (usurvive) Your("%s into flame!", aobjnam(obj, "burst")); if(obj == uarm) (void) Armor_gone(); else if(obj == uarmc) (void) Cloak_off(); else if(obj == uarmh) (void) Helmet_off(); else if(obj == uarms) (void) Shield_off(); else if(obj == uarmg) (void) Gloves_off(); else if(obj == uarmf) (void) Boots_off(); #ifdef TOURIST else if(obj == uarmu) setnotworn(obj); #endif else if(obj == uleft) Ring_gone(obj); else if(obj == uright) Ring_gone(obj); else if(obj == ublindf) Blindf_off(obj); else if(obj == uamul) Amulet_off(); else if(obj == uwep) uwepgone(); else if (obj == uquiver) uqwepgone(); else if (obj == uswapwep) uswapwepgone(); } useupall(obj); } } /* s/he died... */ u.uhp = -1; killer_format = KILLED_BY; killer = lava_killer; You("burn to a crisp..."); done(BURNING); while (!safe_teleds(TRUE)) { pline("You're still burning."); done(BURNING); } You("find yourself back on solid %s.", surface(u.ux, u.uy)); return(TRUE); } if (!Wwalking) { u.utrap = rn1(4, 4) + (rn1(4, 12) << 8); u.utraptype = TT_LAVA; You("sink into the lava, but it only burns slightly!"); if (u.uhp > 1) losehp(1, lava_killer, KILLED_BY); } /* just want to burn boots, not all armor; destroy_item doesn't work on armor anyway */ burn_stuff: if(uarmf && !uarmf->oerodeproof && is_organic(uarmf)) { /* save uarmf value because Boots_off() sets uarmf to null */ obj = uarmf; Your("%s bursts into flame!", xname(obj)); (void) Boots_off(); useup(obj); } destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); return(FALSE); } #endif /* OVLB */ /*trap.c*/ nethack-3.4.3/src/u_init.c0100644000000000000000000010175507764735041014105 0ustar rootroot/* SCCS Id: @(#)u_init.c 3.4 2002/10/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" struct trobj { short trotyp; schar trspe; char trclass; Bitfield(trquan,6); Bitfield(trbless,2); }; STATIC_DCL void FDECL(ini_inv, (struct trobj *)); STATIC_DCL void FDECL(knows_object,(int)); STATIC_DCL void FDECL(knows_class,(CHAR_P)); STATIC_DCL boolean FDECL(restricted_spell_discipline, (int)); #define UNDEF_TYP 0 #define UNDEF_SPE '\177' #define UNDEF_BLESS 2 /* * Initial inventory for the various roles. */ static struct trobj Archeologist[] = { /* if adventure has a name... idea from tan@uvm-gen */ { BULLWHIP, 2, WEAPON_CLASS, 1, UNDEF_BLESS }, { LEATHER_JACKET, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { FEDORA, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { FOOD_RATION, 0, FOOD_CLASS, 3, 0 }, { PICK_AXE, UNDEF_SPE, TOOL_CLASS, 1, UNDEF_BLESS }, { TINNING_KIT, UNDEF_SPE, TOOL_CLASS, 1, UNDEF_BLESS }, { TOUCHSTONE, 0, GEM_CLASS, 1, 0 }, { SACK, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Barbarian[] = { #define B_MAJOR 0 /* two-handed sword or battle-axe */ #define B_MINOR 1 /* matched with axe or short sword */ { TWO_HANDED_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { AXE, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { RING_MAIL, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { FOOD_RATION, 0, FOOD_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Cave_man[] = { #define C_AMMO 2 { CLUB, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { SLING, 2, WEAPON_CLASS, 1, UNDEF_BLESS }, { FLINT, 0, GEM_CLASS, 15, UNDEF_BLESS }, /* quan is variable */ { ROCK, 0, GEM_CLASS, 3, 0 }, /* yields 18..33 */ { LEATHER_ARMOR, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; static struct trobj Healer[] = { { SCALPEL, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { LEATHER_GLOVES, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, { STETHOSCOPE, 0, TOOL_CLASS, 1, 0 }, { POT_HEALING, 0, POTION_CLASS, 4, UNDEF_BLESS }, { POT_EXTRA_HEALING, 0, POTION_CLASS, 4, UNDEF_BLESS }, { WAN_SLEEP, UNDEF_SPE, WAND_CLASS, 1, UNDEF_BLESS }, /* always blessed, so it's guaranteed readable */ { SPE_HEALING, 0, SPBOOK_CLASS, 1, 1 }, { SPE_EXTRA_HEALING, 0, SPBOOK_CLASS, 1, 1 }, { SPE_STONE_TO_FLESH, 0, SPBOOK_CLASS, 1, 1 }, { APPLE, 0, FOOD_CLASS, 5, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Knight[] = { { LONG_SWORD, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { LANCE, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { RING_MAIL, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, { HELMET, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { SMALL_SHIELD, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { LEATHER_GLOVES, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { APPLE, 0, FOOD_CLASS, 10, 0 }, { CARROT, 0, FOOD_CLASS, 10, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Monk[] = { #define M_BOOK 2 { LEATHER_GLOVES, 2, ARMOR_CLASS, 1, UNDEF_BLESS }, { ROBE, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 1, 1 }, { UNDEF_TYP, UNDEF_SPE, SCROLL_CLASS, 1, UNDEF_BLESS }, { POT_HEALING, 0, POTION_CLASS, 3, UNDEF_BLESS }, { FOOD_RATION, 0, FOOD_CLASS, 3, 0 }, { APPLE, 0, FOOD_CLASS, 5, UNDEF_BLESS }, { ORANGE, 0, FOOD_CLASS, 5, UNDEF_BLESS }, /* Yes, we know fortune cookies aren't really from China. They were * invented by George Jung in Los Angeles, California, USA in 1916. */ { FORTUNE_COOKIE, 0, FOOD_CLASS, 3, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; static struct trobj Priest[] = { { MACE, 1, WEAPON_CLASS, 1, 1 }, { ROBE, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { SMALL_SHIELD, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { POT_WATER, 0, POTION_CLASS, 4, 1 }, /* holy water */ { CLOVE_OF_GARLIC, 0, FOOD_CLASS, 1, 0 }, { SPRIG_OF_WOLFSBANE, 0, FOOD_CLASS, 1, 0 }, { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 2, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; static struct trobj Ranger[] = { #define RAN_BOW 1 #define RAN_TWO_ARROWS 2 #define RAN_ZERO_ARROWS 3 { DAGGER, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { BOW, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { ARROW, 2, WEAPON_CLASS, 50, UNDEF_BLESS }, { ARROW, 0, WEAPON_CLASS, 30, UNDEF_BLESS }, { CLOAK_OF_DISPLACEMENT, 2, ARMOR_CLASS, 1, UNDEF_BLESS }, { CRAM_RATION, 0, FOOD_CLASS, 4, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Rogue[] = { #define R_DAGGERS 1 { SHORT_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { DAGGER, 0, WEAPON_CLASS, 10, 0 }, /* quan is variable */ { LEATHER_ARMOR, 1, ARMOR_CLASS, 1, UNDEF_BLESS }, { POT_SICKNESS, 0, POTION_CLASS, 1, 0 }, { LOCK_PICK, 9, TOOL_CLASS, 1, 0 }, { SACK, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Samurai[] = { #define S_ARROWS 3 { KATANA, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { SHORT_SWORD, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, /* wakizashi */ { YUMI, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { YA, 0, WEAPON_CLASS, 25, UNDEF_BLESS }, /* variable quan */ { SPLINT_MAIL, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; #ifdef TOURIST static struct trobj Tourist[] = { #define T_DARTS 0 { DART, 2, WEAPON_CLASS, 25, UNDEF_BLESS }, /* quan is variable */ { UNDEF_TYP, UNDEF_SPE, FOOD_CLASS, 10, 0 }, { POT_EXTRA_HEALING, 0, POTION_CLASS, 2, UNDEF_BLESS }, { SCR_MAGIC_MAPPING, 0, SCROLL_CLASS, 4, UNDEF_BLESS }, { HAWAIIAN_SHIRT, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { EXPENSIVE_CAMERA, UNDEF_SPE, TOOL_CLASS, 1, 0 }, { CREDIT_CARD, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; #endif static struct trobj Valkyrie[] = { { LONG_SWORD, 1, WEAPON_CLASS, 1, UNDEF_BLESS }, { DAGGER, 0, WEAPON_CLASS, 1, UNDEF_BLESS }, { SMALL_SHIELD, 3, ARMOR_CLASS, 1, UNDEF_BLESS }, { FOOD_RATION, 0, FOOD_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Wizard[] = { #define W_MULTSTART 2 #define W_MULTEND 6 { QUARTERSTAFF, 1, WEAPON_CLASS, 1, 1 }, { CLOAK_OF_MAGIC_RESISTANCE, 0, ARMOR_CLASS, 1, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, WAND_CLASS, 1, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, RING_CLASS, 2, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, POTION_CLASS, 3, UNDEF_BLESS }, { UNDEF_TYP, UNDEF_SPE, SCROLL_CLASS, 3, UNDEF_BLESS }, { SPE_FORCE_BOLT, 0, SPBOOK_CLASS, 1, 1 }, { UNDEF_TYP, UNDEF_SPE, SPBOOK_CLASS, 1, UNDEF_BLESS }, { 0, 0, 0, 0, 0 } }; /* * Optional extra inventory items. */ static struct trobj Tinopener[] = { { TIN_OPENER, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Magicmarker[] = { { MAGIC_MARKER, UNDEF_SPE, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Lamp[] = { { OIL_LAMP, 1, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Blindfold[] = { { BLINDFOLD, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Instrument[] = { { WOODEN_FLUTE, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Xtra_food[] = { { UNDEF_TYP, UNDEF_SPE, FOOD_CLASS, 2, 0 }, { 0, 0, 0, 0, 0 } }; #ifdef TOURIST static struct trobj Leash[] = { { LEASH, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; static struct trobj Towel[] = { { TOWEL, 0, TOOL_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; #endif /* TOURIST */ static struct trobj Wishing[] = { { WAN_WISHING, 3, WAND_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; #ifdef GOLDOBJ static struct trobj Money[] = { { GOLD_PIECE, 0 , COIN_CLASS, 1, 0 }, { 0, 0, 0, 0, 0 } }; #endif /* race-based substitutions for initial inventory; the weaker cloak for elven rangers is intentional--they shoot better */ static struct inv_sub { short race_pm, item_otyp, subs_otyp; } inv_subs[] = { { PM_ELF, DAGGER, ELVEN_DAGGER }, { PM_ELF, SPEAR, ELVEN_SPEAR }, { PM_ELF, SHORT_SWORD, ELVEN_SHORT_SWORD }, { PM_ELF, BOW, ELVEN_BOW }, { PM_ELF, ARROW, ELVEN_ARROW }, { PM_ELF, HELMET, ELVEN_LEATHER_HELM }, /* { PM_ELF, SMALL_SHIELD, ELVEN_SHIELD }, */ { PM_ELF, CLOAK_OF_DISPLACEMENT, ELVEN_CLOAK }, { PM_ELF, CRAM_RATION, LEMBAS_WAFER }, { PM_ORC, DAGGER, ORCISH_DAGGER }, { PM_ORC, SPEAR, ORCISH_SPEAR }, { PM_ORC, SHORT_SWORD, ORCISH_SHORT_SWORD }, { PM_ORC, BOW, ORCISH_BOW }, { PM_ORC, ARROW, ORCISH_ARROW }, { PM_ORC, HELMET, ORCISH_HELM }, { PM_ORC, SMALL_SHIELD, ORCISH_SHIELD }, { PM_ORC, RING_MAIL, ORCISH_RING_MAIL }, { PM_ORC, CHAIN_MAIL, ORCISH_CHAIN_MAIL }, { PM_DWARF, SPEAR, DWARVISH_SPEAR }, { PM_DWARF, SHORT_SWORD, DWARVISH_SHORT_SWORD }, { PM_DWARF, HELMET, DWARVISH_IRON_HELM }, /* { PM_DWARF, SMALL_SHIELD, DWARVISH_ROUNDSHIELD }, */ /* { PM_DWARF, PICK_AXE, DWARVISH_MATTOCK }, */ { PM_GNOME, BOW, CROSSBOW }, { PM_GNOME, ARROW, CROSSBOW_BOLT }, { NON_PM, STRANGE_OBJECT, STRANGE_OBJECT } }; static const struct def_skill Skill_A[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_BASIC }, { P_PICK_AXE, P_EXPERT }, { P_SHORT_SWORD, P_BASIC }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_EXPERT }, { P_CLUB, P_SKILLED }, { P_QUARTERSTAFF, P_SKILLED }, { P_SLING, P_SKILLED }, { P_DART, P_BASIC }, { P_BOOMERANG, P_EXPERT }, { P_WHIP, P_EXPERT }, { P_UNICORN_HORN, P_SKILLED }, { P_ATTACK_SPELL, P_BASIC }, { P_HEALING_SPELL, P_BASIC }, { P_DIVINATION_SPELL, P_EXPERT}, { P_MATTER_SPELL, P_BASIC}, #ifdef STEED { P_RIDING, P_BASIC }, #endif { P_TWO_WEAPON_COMBAT, P_BASIC }, { P_BARE_HANDED_COMBAT, P_EXPERT }, { P_NONE, 0 } }; static const struct def_skill Skill_B[] = { { P_DAGGER, P_BASIC }, { P_AXE, P_EXPERT }, { P_PICK_AXE, P_SKILLED }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_SKILLED }, { P_TWO_HANDED_SWORD, P_EXPERT }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_BASIC }, { P_CLUB, P_SKILLED }, { P_MACE, P_SKILLED }, { P_MORNING_STAR, P_SKILLED }, { P_FLAIL, P_BASIC }, { P_HAMMER, P_EXPERT }, { P_QUARTERSTAFF, P_BASIC }, { P_SPEAR, P_SKILLED }, { P_TRIDENT, P_SKILLED }, { P_BOW, P_BASIC }, { P_ATTACK_SPELL, P_SKILLED }, #ifdef STEED { P_RIDING, P_BASIC }, #endif { P_TWO_WEAPON_COMBAT, P_BASIC }, { P_BARE_HANDED_COMBAT, P_MASTER }, { P_NONE, 0 } }; static const struct def_skill Skill_C[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_CLUB, P_EXPERT }, { P_MACE, P_EXPERT }, { P_MORNING_STAR, P_BASIC }, { P_FLAIL, P_SKILLED }, { P_HAMMER, P_SKILLED }, { P_QUARTERSTAFF, P_EXPERT }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_EXPERT }, { P_JAVELIN, P_SKILLED }, { P_TRIDENT, P_SKILLED }, { P_BOW, P_SKILLED }, { P_SLING, P_EXPERT }, { P_ATTACK_SPELL, P_BASIC }, { P_MATTER_SPELL, P_SKILLED }, { P_BOOMERANG, P_EXPERT }, { P_UNICORN_HORN, P_BASIC }, { P_BARE_HANDED_COMBAT, P_MASTER }, { P_NONE, 0 } }; static const struct def_skill Skill_H[] = { { P_DAGGER, P_SKILLED }, { P_KNIFE, P_EXPERT }, { P_SHORT_SWORD, P_SKILLED }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_BASIC }, { P_CLUB, P_SKILLED }, { P_MACE, P_BASIC }, { P_QUARTERSTAFF, P_EXPERT }, { P_POLEARMS, P_BASIC }, { P_SPEAR, P_BASIC }, { P_JAVELIN, P_BASIC }, { P_TRIDENT, P_BASIC }, { P_SLING, P_SKILLED }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_SKILLED }, { P_UNICORN_HORN, P_EXPERT }, { P_HEALING_SPELL, P_EXPERT }, { P_BARE_HANDED_COMBAT, P_BASIC }, { P_NONE, 0 } }; static const struct def_skill Skill_K[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_BASIC }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_SKILLED }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_EXPERT }, { P_TWO_HANDED_SWORD, P_SKILLED }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_SKILLED }, { P_CLUB, P_BASIC }, { P_MACE, P_SKILLED }, { P_MORNING_STAR, P_SKILLED }, { P_FLAIL, P_BASIC }, { P_HAMMER, P_BASIC }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_SKILLED }, { P_JAVELIN, P_SKILLED }, { P_TRIDENT, P_BASIC }, { P_LANCE, P_EXPERT }, { P_BOW, P_BASIC }, { P_CROSSBOW, P_SKILLED }, { P_ATTACK_SPELL, P_SKILLED }, { P_HEALING_SPELL, P_SKILLED }, { P_CLERIC_SPELL, P_SKILLED }, #ifdef STEED { P_RIDING, P_EXPERT }, #endif { P_TWO_WEAPON_COMBAT, P_SKILLED }, { P_BARE_HANDED_COMBAT, P_EXPERT }, { P_NONE, 0 } }; static const struct def_skill Skill_Mon[] = { { P_QUARTERSTAFF, P_BASIC }, { P_SPEAR, P_BASIC }, { P_JAVELIN, P_BASIC }, { P_CROSSBOW, P_BASIC }, { P_SHURIKEN, P_BASIC }, { P_ATTACK_SPELL, P_BASIC }, { P_HEALING_SPELL, P_EXPERT }, { P_DIVINATION_SPELL, P_BASIC },{ P_ENCHANTMENT_SPELL, P_BASIC }, { P_CLERIC_SPELL, P_SKILLED }, { P_ESCAPE_SPELL, P_BASIC }, { P_MATTER_SPELL, P_BASIC }, { P_MARTIAL_ARTS, P_GRAND_MASTER }, { P_NONE, 0 } }; static const struct def_skill Skill_P[] = { { P_CLUB, P_EXPERT }, { P_MACE, P_EXPERT }, { P_MORNING_STAR, P_EXPERT }, { P_FLAIL, P_EXPERT }, { P_HAMMER, P_EXPERT }, { P_QUARTERSTAFF, P_EXPERT }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_SKILLED }, { P_JAVELIN, P_SKILLED }, { P_TRIDENT, P_SKILLED }, { P_LANCE, P_BASIC }, { P_BOW, P_BASIC }, { P_SLING, P_BASIC }, { P_CROSSBOW, P_BASIC }, { P_DART, P_BASIC }, { P_SHURIKEN, P_BASIC }, { P_BOOMERANG, P_BASIC }, { P_UNICORN_HORN, P_SKILLED }, { P_HEALING_SPELL, P_EXPERT }, { P_DIVINATION_SPELL, P_EXPERT }, { P_CLERIC_SPELL, P_EXPERT }, { P_BARE_HANDED_COMBAT, P_BASIC }, { P_NONE, 0 } }; static const struct def_skill Skill_R[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_EXPERT }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_SKILLED }, { P_TWO_HANDED_SWORD, P_BASIC }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_SKILLED }, { P_CLUB, P_SKILLED }, { P_MACE, P_SKILLED }, { P_MORNING_STAR, P_BASIC }, { P_FLAIL, P_BASIC }, { P_HAMMER, P_BASIC }, { P_POLEARMS, P_BASIC }, { P_SPEAR, P_BASIC }, { P_CROSSBOW, P_EXPERT }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_SKILLED }, { P_DIVINATION_SPELL, P_SKILLED }, { P_ESCAPE_SPELL, P_SKILLED }, { P_MATTER_SPELL, P_SKILLED }, #ifdef STEED { P_RIDING, P_BASIC }, #endif { P_TWO_WEAPON_COMBAT, P_EXPERT }, { P_BARE_HANDED_COMBAT, P_EXPERT }, { P_NONE, 0 } }; static const struct def_skill Skill_Ran[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_BASIC }, { P_MORNING_STAR, P_BASIC }, { P_FLAIL, P_SKILLED }, { P_HAMMER, P_BASIC }, { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_SKILLED }, { P_JAVELIN, P_EXPERT }, { P_TRIDENT, P_BASIC }, { P_BOW, P_EXPERT }, { P_SLING, P_EXPERT }, { P_CROSSBOW, P_EXPERT }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_SKILLED }, { P_BOOMERANG, P_EXPERT }, { P_WHIP, P_BASIC }, { P_HEALING_SPELL, P_BASIC }, { P_DIVINATION_SPELL, P_EXPERT }, { P_ESCAPE_SPELL, P_BASIC }, #ifdef STEED { P_RIDING, P_BASIC }, #endif { P_BARE_HANDED_COMBAT, P_BASIC }, { P_NONE, 0 } }; static const struct def_skill Skill_S[] = { { P_DAGGER, P_BASIC }, { P_KNIFE, P_SKILLED }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_EXPERT }, { P_TWO_HANDED_SWORD, P_EXPERT }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_BASIC }, { P_FLAIL, P_SKILLED }, { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_BASIC }, { P_JAVELIN, P_BASIC }, { P_LANCE, P_SKILLED }, { P_BOW, P_EXPERT }, { P_SHURIKEN, P_EXPERT }, { P_ATTACK_SPELL, P_SKILLED }, { P_CLERIC_SPELL, P_SKILLED }, #ifdef STEED { P_RIDING, P_SKILLED }, #endif { P_TWO_WEAPON_COMBAT, P_EXPERT }, { P_MARTIAL_ARTS, P_MASTER }, { P_NONE, 0 } }; #ifdef TOURIST static const struct def_skill Skill_T[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_BASIC }, { P_PICK_AXE, P_BASIC }, { P_SHORT_SWORD, P_EXPERT }, { P_BROAD_SWORD, P_BASIC }, { P_LONG_SWORD, P_BASIC }, { P_TWO_HANDED_SWORD, P_BASIC }, { P_SCIMITAR, P_SKILLED }, { P_SABER, P_SKILLED }, { P_MACE, P_BASIC }, { P_MORNING_STAR, P_BASIC }, { P_FLAIL, P_BASIC }, { P_HAMMER, P_BASIC }, { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_BASIC }, { P_SPEAR, P_BASIC }, { P_JAVELIN, P_BASIC }, { P_TRIDENT, P_BASIC }, { P_LANCE, P_BASIC }, { P_BOW, P_BASIC }, { P_SLING, P_BASIC }, { P_CROSSBOW, P_BASIC }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_BASIC }, { P_BOOMERANG, P_BASIC }, { P_WHIP, P_BASIC }, { P_UNICORN_HORN, P_SKILLED }, { P_DIVINATION_SPELL, P_BASIC }, { P_ENCHANTMENT_SPELL, P_BASIC }, { P_ESCAPE_SPELL, P_SKILLED }, #ifdef STEED { P_RIDING, P_BASIC }, #endif { P_TWO_WEAPON_COMBAT, P_SKILLED }, { P_BARE_HANDED_COMBAT, P_SKILLED }, { P_NONE, 0 } }; #endif /* TOURIST */ static const struct def_skill Skill_V[] = { { P_DAGGER, P_EXPERT }, { P_AXE, P_EXPERT }, { P_PICK_AXE, P_SKILLED }, { P_SHORT_SWORD, P_SKILLED }, { P_BROAD_SWORD, P_SKILLED }, { P_LONG_SWORD, P_EXPERT }, { P_TWO_HANDED_SWORD, P_EXPERT }, { P_SCIMITAR, P_BASIC }, { P_SABER, P_BASIC }, { P_HAMMER, P_EXPERT }, { P_QUARTERSTAFF, P_BASIC }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_SKILLED }, { P_JAVELIN, P_BASIC }, { P_TRIDENT, P_BASIC }, { P_LANCE, P_SKILLED }, { P_SLING, P_BASIC }, { P_ATTACK_SPELL, P_BASIC }, { P_ESCAPE_SPELL, P_BASIC }, #ifdef STEED { P_RIDING, P_SKILLED }, #endif { P_TWO_WEAPON_COMBAT, P_SKILLED }, { P_BARE_HANDED_COMBAT, P_EXPERT }, { P_NONE, 0 } }; static const struct def_skill Skill_W[] = { { P_DAGGER, P_EXPERT }, { P_KNIFE, P_SKILLED }, { P_AXE, P_SKILLED }, { P_SHORT_SWORD, P_BASIC }, { P_CLUB, P_SKILLED }, { P_MACE, P_BASIC }, { P_QUARTERSTAFF, P_EXPERT }, { P_POLEARMS, P_SKILLED }, { P_SPEAR, P_BASIC }, { P_JAVELIN, P_BASIC }, { P_TRIDENT, P_BASIC }, { P_SLING, P_SKILLED }, { P_DART, P_EXPERT }, { P_SHURIKEN, P_BASIC }, { P_ATTACK_SPELL, P_EXPERT }, { P_HEALING_SPELL, P_SKILLED }, { P_DIVINATION_SPELL, P_EXPERT }, { P_ENCHANTMENT_SPELL, P_SKILLED }, { P_CLERIC_SPELL, P_SKILLED }, { P_ESCAPE_SPELL, P_EXPERT }, { P_MATTER_SPELL, P_EXPERT }, #ifdef STEED { P_RIDING, P_BASIC }, #endif { P_BARE_HANDED_COMBAT, P_BASIC }, { P_NONE, 0 } }; STATIC_OVL void knows_object(obj) register int obj; { discover_object(obj,TRUE,FALSE); objects[obj].oc_pre_discovered = 1; /* not a "discovery" */ } /* Know ordinary (non-magical) objects of a certain class, * like all gems except the loadstone and luckstone. */ STATIC_OVL void knows_class(sym) register char sym; { register int ct; for (ct = 1; ct < NUM_OBJECTS; ct++) if (objects[ct].oc_class == sym && !objects[ct].oc_magic) knows_object(ct); } void u_init() { register int i; flags.female = flags.initgend; flags.beginner = 1; /* zero u, including pointer values -- * necessary when aborting from a failed restore */ (void) memset((genericptr_t)&u, 0, sizeof(u)); u.ustuck = (struct monst *)0; #if 0 /* documentation of more zero values as desirable */ u.usick_cause[0] = 0; u.uluck = u.moreluck = 0; # ifdef TOURIST uarmu = 0; # endif uarm = uarmc = uarmh = uarms = uarmg = uarmf = 0; uwep = uball = uchain = uleft = uright = 0; uswapwep = uquiver = 0; u.twoweap = 0; u.ublessed = 0; /* not worthy yet */ u.ugangr = 0; /* gods not angry */ u.ugifts = 0; /* no divine gifts bestowed */ # ifdef ELBERETH u.uevent.uhand_of_elbereth = 0; # endif u.uevent.uheard_tune = 0; u.uevent.uopened_dbridge = 0; u.uevent.udemigod = 0; /* not a demi-god yet... */ u.udg_cnt = 0; u.mh = u.mhmax = u.mtimedone = 0; u.uz.dnum = u.uz0.dnum = 0; u.utotype = 0; #endif /* 0 */ u.uz.dlevel = 1; u.uz0.dlevel = 0; u.utolev = u.uz; u.umoved = FALSE; u.umortality = 0; u.ugrave_arise = NON_PM; u.umonnum = u.umonster = (flags.female && urole.femalenum != NON_PM) ? urole.femalenum : urole.malenum; set_uasmon(); u.ulevel = 0; /* set up some of the initial attributes */ u.uhp = u.uhpmax = newhp(); u.uenmax = urole.enadv.infix + urace.enadv.infix; if (urole.enadv.inrnd > 0) u.uenmax += rnd(urole.enadv.inrnd); if (urace.enadv.inrnd > 0) u.uenmax += rnd(urace.enadv.inrnd); u.uen = u.uenmax; u.uspellprot = 0; adjabil(0,1); u.ulevel = u.ulevelmax = 1; init_uhunger(); for (i = 0; i <= MAXSPELL; i++) spl_book[i].sp_id = NO_SPELL; u.ublesscnt = 300; /* no prayers just yet */ u.ualignbase[A_CURRENT] = u.ualignbase[A_ORIGINAL] = u.ualign.type = aligns[flags.initalign].value; u.ulycn = NON_PM; #if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *)&u.ubirthday); #else (void) time(&u.ubirthday); #endif /* * For now, everyone starts out with a night vision range of 1 and * their xray range disabled. */ u.nv_range = 1; u.xray_range = -1; /*** Role-specific initializations ***/ switch (Role_switch) { /* rn2(100) > 50 necessary for some choices because some * random number generators are bad enough to seriously * skew the results if we use rn2(2)... --KAA */ case PM_ARCHEOLOGIST: ini_inv(Archeologist); if(!rn2(10)) ini_inv(Tinopener); else if(!rn2(4)) ini_inv(Lamp); else if(!rn2(10)) ini_inv(Magicmarker); knows_object(SACK); knows_object(TOUCHSTONE); skill_init(Skill_A); break; case PM_BARBARIAN: if (rn2(100) >= 50) { /* see above comment */ Barbarian[B_MAJOR].trotyp = BATTLE_AXE; Barbarian[B_MINOR].trotyp = SHORT_SWORD; } ini_inv(Barbarian); if(!rn2(6)) ini_inv(Lamp); knows_class(WEAPON_CLASS); knows_class(ARMOR_CLASS); skill_init(Skill_B); break; case PM_CAVEMAN: Cave_man[C_AMMO].trquan = rn1(11, 10); /* 10..20 */ ini_inv(Cave_man); skill_init(Skill_C); break; case PM_HEALER: #ifndef GOLDOBJ u.ugold = u.ugold0 = rn1(1000, 1001); #else u.umoney0 = rn1(1000, 1001); #endif ini_inv(Healer); if(!rn2(25)) ini_inv(Lamp); knows_object(POT_FULL_HEALING); skill_init(Skill_H); break; case PM_KNIGHT: ini_inv(Knight); knows_class(WEAPON_CLASS); knows_class(ARMOR_CLASS); /* give knights chess-like mobility * -- idea from wooledge@skybridge.scl.cwru.edu */ HJumping |= FROMOUTSIDE; skill_init(Skill_K); break; case PM_MONK: switch (rn2(90) / 30) { case 0: Monk[M_BOOK].trotyp = SPE_HEALING; break; case 1: Monk[M_BOOK].trotyp = SPE_PROTECTION; break; case 2: Monk[M_BOOK].trotyp = SPE_SLEEP; break; } ini_inv(Monk); if(!rn2(5)) ini_inv(Magicmarker); else if(!rn2(10)) ini_inv(Lamp); knows_class(ARMOR_CLASS); skill_init(Skill_Mon); break; case PM_PRIEST: ini_inv(Priest); if(!rn2(10)) ini_inv(Magicmarker); else if(!rn2(10)) ini_inv(Lamp); knows_object(POT_WATER); skill_init(Skill_P); /* KMH, conduct -- * Some may claim that this isn't agnostic, since they * are literally "priests" and they have holy water. * But we don't count it as such. Purists can always * avoid playing priests and/or confirm another player's * role in their YAAP. */ break; case PM_RANGER: Ranger[RAN_TWO_ARROWS].trquan = rn1(10, 50); Ranger[RAN_ZERO_ARROWS].trquan = rn1(10, 30); ini_inv(Ranger); skill_init(Skill_Ran); break; case PM_ROGUE: Rogue[R_DAGGERS].trquan = rn1(10, 6); #ifndef GOLDOBJ u.ugold = u.ugold0 = 0; #else u.umoney0 = 0; #endif ini_inv(Rogue); if(!rn2(5)) ini_inv(Blindfold); knows_object(SACK); skill_init(Skill_R); break; case PM_SAMURAI: Samurai[S_ARROWS].trquan = rn1(20, 26); ini_inv(Samurai); if(!rn2(5)) ini_inv(Blindfold); knows_class(WEAPON_CLASS); knows_class(ARMOR_CLASS); skill_init(Skill_S); break; #ifdef TOURIST case PM_TOURIST: Tourist[T_DARTS].trquan = rn1(20, 21); #ifndef GOLDOBJ u.ugold = u.ugold0 = rnd(1000); #else u.umoney0 = rnd(1000); #endif ini_inv(Tourist); if(!rn2(25)) ini_inv(Tinopener); else if(!rn2(25)) ini_inv(Leash); else if(!rn2(25)) ini_inv(Towel); else if(!rn2(25)) ini_inv(Magicmarker); skill_init(Skill_T); break; #endif case PM_VALKYRIE: ini_inv(Valkyrie); if(!rn2(6)) ini_inv(Lamp); knows_class(WEAPON_CLASS); knows_class(ARMOR_CLASS); skill_init(Skill_V); break; case PM_WIZARD: ini_inv(Wizard); if(!rn2(5)) ini_inv(Magicmarker); if(!rn2(5)) ini_inv(Blindfold); skill_init(Skill_W); break; default: /* impossible */ break; } /*** Race-specific initializations ***/ switch (Race_switch) { case PM_HUMAN: /* Nothing special */ break; case PM_ELF: /* * Elves are people of music and song, or they are warriors. * Non-warriors get an instrument. We use a kludge to * get only non-magic instruments. */ if (Role_if(PM_PRIEST) || Role_if(PM_WIZARD)) { static int trotyp[] = { WOODEN_FLUTE, TOOLED_HORN, WOODEN_HARP, BELL, BUGLE, LEATHER_DRUM }; Instrument[0].trotyp = trotyp[rn2(SIZE(trotyp))]; ini_inv(Instrument); } /* Elves can recognize all elvish objects */ knows_object(ELVEN_SHORT_SWORD); knows_object(ELVEN_ARROW); knows_object(ELVEN_BOW); knows_object(ELVEN_SPEAR); knows_object(ELVEN_DAGGER); knows_object(ELVEN_BROADSWORD); knows_object(ELVEN_MITHRIL_COAT); knows_object(ELVEN_LEATHER_HELM); knows_object(ELVEN_SHIELD); knows_object(ELVEN_BOOTS); knows_object(ELVEN_CLOAK); break; case PM_DWARF: /* Dwarves can recognize all dwarvish objects */ knows_object(DWARVISH_SPEAR); knows_object(DWARVISH_SHORT_SWORD); knows_object(DWARVISH_MATTOCK); knows_object(DWARVISH_IRON_HELM); knows_object(DWARVISH_MITHRIL_COAT); knows_object(DWARVISH_CLOAK); knows_object(DWARVISH_ROUNDSHIELD); break; case PM_GNOME: break; case PM_ORC: /* compensate for generally inferior equipment */ if (!Role_if(PM_WIZARD)) ini_inv(Xtra_food); /* Orcs can recognize all orcish objects */ knows_object(ORCISH_SHORT_SWORD); knows_object(ORCISH_ARROW); knows_object(ORCISH_BOW); knows_object(ORCISH_SPEAR); knows_object(ORCISH_DAGGER); knows_object(ORCISH_CHAIN_MAIL); knows_object(ORCISH_RING_MAIL); knows_object(ORCISH_HELM); knows_object(ORCISH_SHIELD); knows_object(URUK_HAI_SHIELD); knows_object(ORCISH_CLOAK); break; default: /* impossible */ break; } if (discover) ini_inv(Wishing); #ifdef WIZARD if (wizard) read_wizkit(); #endif #ifndef GOLDOBJ u.ugold0 += hidden_gold(); /* in case sack has gold in it */ #else if (u.umoney0) ini_inv(Money); u.umoney0 += hidden_gold(); /* in case sack has gold in it */ #endif find_ac(); /* get initial ac value */ init_attr(75); /* init attribute values */ max_rank_sz(); /* set max str size for class ranks */ /* * Do we really need this? */ for(i = 0; i < A_MAX; i++) if(!rn2(20)) { register int xd = rn2(7) - 2; /* biased variation */ (void) adjattrib(i, xd, TRUE); if (ABASE(i) < AMAX(i)) AMAX(i) = ABASE(i); } /* make sure you can carry all you have - especially for Tourists */ while (inv_weight() > 0) { if (adjattrib(A_STR, 1, TRUE)) continue; if (adjattrib(A_CON, 1, TRUE)) continue; /* only get here when didn't boost strength or constitution */ break; } return; } /* skills aren't initialized, so we use the role-specific skill lists */ STATIC_OVL boolean restricted_spell_discipline(otyp) int otyp; { const struct def_skill *skills; int this_skill = spell_skilltype(otyp); switch (Role_switch) { case PM_ARCHEOLOGIST: skills = Skill_A; break; case PM_BARBARIAN: skills = Skill_B; break; case PM_CAVEMAN: skills = Skill_C; break; case PM_HEALER: skills = Skill_H; break; case PM_KNIGHT: skills = Skill_K; break; case PM_MONK: skills = Skill_Mon; break; case PM_PRIEST: skills = Skill_P; break; case PM_RANGER: skills = Skill_Ran; break; case PM_ROGUE: skills = Skill_R; break; case PM_SAMURAI: skills = Skill_S; break; #ifdef TOURIST case PM_TOURIST: skills = Skill_T; break; #endif case PM_VALKYRIE: skills = Skill_V; break; case PM_WIZARD: skills = Skill_W; break; default: skills = 0; break; /* lint suppression */ } while (skills->skill != P_NONE) { if (skills->skill == this_skill) return FALSE; ++skills; } return TRUE; } STATIC_OVL void ini_inv(trop) register struct trobj *trop; { struct obj *obj; int otyp, i; while (trop->trclass) { if (trop->trotyp != UNDEF_TYP) { otyp = (int)trop->trotyp; if (urace.malenum != PM_HUMAN) { /* substitute specific items for generic ones */ for (i = 0; inv_subs[i].race_pm != NON_PM; ++i) if (inv_subs[i].race_pm == urace.malenum && otyp == inv_subs[i].item_otyp) { otyp = inv_subs[i].subs_otyp; break; } } obj = mksobj(otyp, TRUE, FALSE); } else { /* UNDEF_TYP */ static NEARDATA short nocreate = STRANGE_OBJECT; static NEARDATA short nocreate2 = STRANGE_OBJECT; static NEARDATA short nocreate3 = STRANGE_OBJECT; static NEARDATA short nocreate4 = STRANGE_OBJECT; /* * For random objects, do not create certain overly powerful * items: wand of wishing, ring of levitation, or the * polymorph/polymorph control combination. Specific objects, * i.e. the discovery wishing, are still OK. * Also, don't get a couple of really useless items. (Note: * punishment isn't "useless". Some players who start out with * one will immediately read it and use the iron ball as a * weapon.) */ obj = mkobj(trop->trclass, FALSE); otyp = obj->otyp; while (otyp == WAN_WISHING || otyp == nocreate || otyp == nocreate2 || otyp == nocreate3 || otyp == nocreate4 #ifdef ELBERETH || otyp == RIN_LEVITATION #endif /* 'useless' items */ || otyp == POT_HALLUCINATION || otyp == POT_ACID || otyp == SCR_AMNESIA || otyp == SCR_FIRE || otyp == SCR_BLANK_PAPER || otyp == SPE_BLANK_PAPER || otyp == RIN_AGGRAVATE_MONSTER || otyp == RIN_HUNGER || otyp == WAN_NOTHING /* Monks don't use weapons */ || (otyp == SCR_ENCHANT_WEAPON && Role_if(PM_MONK)) /* wizard patch -- they already have one */ || (otyp == SPE_FORCE_BOLT && Role_if(PM_WIZARD)) /* powerful spells are either useless to low level players or unbalancing; also spells in restricted skill categories */ || (obj->oclass == SPBOOK_CLASS && (objects[otyp].oc_level > 3 || restricted_spell_discipline(otyp))) ) { dealloc_obj(obj); obj = mkobj(trop->trclass, FALSE); otyp = obj->otyp; } /* Don't start with +0 or negative rings */ if (objects[otyp].oc_charged && obj->spe <= 0) obj->spe = rne(3); /* Heavily relies on the fact that 1) we create wands * before rings, 2) that we create rings before * spellbooks, and that 3) not more than 1 object of a * particular symbol is to be prohibited. (For more * objects, we need more nocreate variables...) */ switch (otyp) { case WAN_POLYMORPH: case RIN_POLYMORPH: case POT_POLYMORPH: nocreate = RIN_POLYMORPH_CONTROL; break; case RIN_POLYMORPH_CONTROL: nocreate = RIN_POLYMORPH; nocreate2 = SPE_POLYMORPH; nocreate3 = POT_POLYMORPH; } /* Don't have 2 of the same ring or spellbook */ if (obj->oclass == RING_CLASS || obj->oclass == SPBOOK_CLASS) nocreate4 = otyp; } #ifdef GOLDOBJ if (trop->trclass == COIN_CLASS) { /* no "blessed" or "identified" money */ obj->quan = u.umoney0; } else { #endif obj->dknown = obj->bknown = obj->rknown = 1; if (objects[otyp].oc_uses_known) obj->known = 1; obj->cursed = 0; if (obj->opoisoned && u.ualign.type != A_CHAOTIC) obj->opoisoned = 0; if (obj->oclass == WEAPON_CLASS || obj->oclass == TOOL_CLASS) { obj->quan = (long) trop->trquan; trop->trquan = 1; } else if (obj->oclass == GEM_CLASS && is_graystone(obj) && obj->otyp != FLINT) { obj->quan = 1L; } if (trop->trspe != UNDEF_SPE) obj->spe = trop->trspe; if (trop->trbless != UNDEF_BLESS) obj->blessed = trop->trbless; #ifdef GOLDOBJ } #endif /* defined after setting otyp+quan + blessedness */ obj->owt = weight(obj); obj = addinv(obj); /* Make the type known if necessary */ if (OBJ_DESCR(objects[otyp]) && obj->known) discover_object(otyp, TRUE, FALSE); if (otyp == OIL_LAMP) discover_object(POT_OIL, TRUE, FALSE); if(obj->oclass == ARMOR_CLASS){ if (is_shield(obj) && !uarms) { setworn(obj, W_ARMS); if (uswapwep) setuswapwep((struct obj *) 0); } else if (is_helmet(obj) && !uarmh) setworn(obj, W_ARMH); else if (is_gloves(obj) && !uarmg) setworn(obj, W_ARMG); #ifdef TOURIST else if (is_shirt(obj) && !uarmu) setworn(obj, W_ARMU); #endif else if (is_cloak(obj) && !uarmc) setworn(obj, W_ARMC); else if (is_boots(obj) && !uarmf) setworn(obj, W_ARMF); else if (is_suit(obj) && !uarm) setworn(obj, W_ARM); } if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || otyp == TIN_OPENER || otyp == FLINT || otyp == ROCK) { if (is_ammo(obj) || is_missile(obj)) { if (!uquiver) setuqwep(obj); } else if (!uwep) setuwep(obj); else if (!uswapwep) setuswapwep(obj); } if (obj->oclass == SPBOOK_CLASS && obj->otyp != SPE_BLANK_PAPER) initialspell(obj); #if !defined(PYRAMID_BUG) && !defined(MAC) if(--trop->trquan) continue; /* make a similar object */ #else if(trop->trquan) { /* check if zero first */ --trop->trquan; if(trop->trquan) continue; /* make a similar object */ } #endif trop++; } } /*u_init.c*/ nethack-3.4.3/src/uhitm.c0100644000000000000000000021542507764735041013744 0ustar rootroot/* SCCS Id: @(#)uhitm.c 3.4 2003/02/18 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL boolean FDECL(known_hitum, (struct monst *,int *,struct attack *)); STATIC_DCL void FDECL(steal_it, (struct monst *, struct attack *)); STATIC_DCL boolean FDECL(hitum, (struct monst *,int,struct attack *)); STATIC_DCL boolean FDECL(hmon_hitmon, (struct monst *,struct obj *,int)); #ifdef STEED STATIC_DCL int FDECL(joust, (struct monst *,struct obj *)); #endif STATIC_DCL void NDECL(demonpet); STATIC_DCL boolean FDECL(m_slips_free, (struct monst *mtmp,struct attack *mattk)); STATIC_DCL int FDECL(explum, (struct monst *,struct attack *)); STATIC_DCL void FDECL(start_engulf, (struct monst *)); STATIC_DCL void NDECL(end_engulf); STATIC_DCL int FDECL(gulpum, (struct monst *,struct attack *)); STATIC_DCL boolean FDECL(hmonas, (struct monst *,int)); STATIC_DCL void FDECL(nohandglow, (struct monst *)); STATIC_DCL boolean FDECL(shade_aware, (struct obj *)); extern boolean notonhead; /* for long worms */ /* The below might become a parameter instead if we use it a lot */ static int dieroll; /* Used to flag attacks caused by Stormbringer's maliciousness. */ static boolean override_confirmation = FALSE; #define PROJECTILE(obj) ((obj) && is_ammo(obj)) /* modified from hurtarmor() in mhitu.c */ /* This is not static because it is also used for monsters rusting monsters */ void hurtmarmor(mdef, attk) struct monst *mdef; int attk; { int hurt; struct obj *target; switch(attk) { /* 0 is burning, which we should never be called with */ case AD_RUST: hurt = 1; break; case AD_CORR: hurt = 3; break; default: hurt = 2; break; } /* What the following code does: it keeps looping until it * finds a target for the rust monster. * Head, feet, etc... not covered by metal, or covered by * rusty metal, are not targets. However, your body always * is, no matter what covers it. */ while (1) { switch(rn2(5)) { case 0: target = which_armor(mdef, W_ARMH); if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef)) continue; break; case 1: target = which_armor(mdef, W_ARMC); if (target) { (void)rust_dmg(target, xname(target), hurt, TRUE, mdef); break; } if ((target = which_armor(mdef, W_ARM)) != (struct obj *)0) { (void)rust_dmg(target, xname(target), hurt, TRUE, mdef); #ifdef TOURIST } else if ((target = which_armor(mdef, W_ARMU)) != (struct obj *)0) { (void)rust_dmg(target, xname(target), hurt, TRUE, mdef); #endif } break; case 2: target = which_armor(mdef, W_ARMS); if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef)) continue; break; case 3: target = which_armor(mdef, W_ARMG); if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef)) continue; break; case 4: target = which_armor(mdef, W_ARMF); if (!target || !rust_dmg(target, xname(target), hurt, FALSE, mdef)) continue; break; } break; /* Out of while loop */ } } /* FALSE means it's OK to attack */ boolean attack_checks(mtmp, wep) register struct monst *mtmp; struct obj *wep; /* uwep for attack(), null for kick_monster() */ { char qbuf[QBUFSZ]; /* if you're close enough to attack, alert any waiting monster */ mtmp->mstrategy &= ~STRAT_WAITMASK; if (u.uswallow && mtmp == u.ustuck) return FALSE; if (flags.forcefight) { /* Do this in the caller, after we checked that the monster * didn't die from the blow. Reason: putting the 'I' there * causes the hero to forget the square's contents since * both 'I' and remembered contents are stored in .glyph. * If the monster dies immediately from the blow, the 'I' will * not stay there, so the player will have suddenly forgotten * the square's contents for no apparent reason. if (!canspotmon(mtmp) && !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph)) map_invisible(u.ux+u.dx, u.uy+u.dy); */ return FALSE; } /* Put up an invisible monster marker, but with exceptions for * monsters that hide and monsters you've been warned about. * The former already prints a warning message and * prevents you from hitting the monster just via the hidden monster * code below; if we also did that here, similar behavior would be * happening two turns in a row. The latter shows a glyph on * the screen, so you know something is there. */ if (!canspotmon(mtmp) && !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy)) && !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph) && !(!Blind && mtmp->mundetected && hides_under(mtmp->data))) { pline("Wait! There's %s there you can't see!", something); map_invisible(u.ux+u.dx, u.uy+u.dy); /* if it was an invisible mimic, treat it as if we stumbled * onto a visible mimic */ if(mtmp->m_ap_type && !Protection_from_shape_changers) { if(!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data,AD_STCK)) u.ustuck = mtmp; } wakeup(mtmp); /* always necessary; also un-mimics mimics */ return TRUE; } if (mtmp->m_ap_type && !Protection_from_shape_changers && !sensemon(mtmp) && !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy))) { /* If a hidden mimic was in a square where a player remembers * some (probably different) unseen monster, the player is in * luck--he attacks it even though it's hidden. */ if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) { seemimic(mtmp); return(FALSE); } stumble_onto_mimic(mtmp); return TRUE; } if (mtmp->mundetected && !canseemon(mtmp) && !glyph_is_warning(glyph_at(u.ux+u.dx,u.uy+u.dy)) && (hides_under(mtmp->data) || mtmp->data->mlet == S_EEL)) { mtmp->mundetected = mtmp->msleeping = 0; newsym(mtmp->mx, mtmp->my); if (glyph_is_invisible(levl[mtmp->mx][mtmp->my].glyph)) { seemimic(mtmp); return(FALSE); } if (!(Blind ? Blind_telepat : Unblind_telepat)) { struct obj *obj; if (Blind || (is_pool(mtmp->mx,mtmp->my) && !Underwater)) pline("Wait! There's a hidden monster there!"); else if ((obj = level.objects[mtmp->mx][mtmp->my]) != 0) pline("Wait! There's %s hiding under %s!", an(l_monnam(mtmp)), doname(obj)); return TRUE; } } /* * make sure to wake up a monster from the above cases if the * hero can sense that the monster is there. */ if ((mtmp->mundetected || mtmp->m_ap_type) && sensemon(mtmp)) { mtmp->mundetected = 0; wakeup(mtmp); } if (flags.confirm && mtmp->mpeaceful && !Confusion && !Hallucination && !Stunned) { /* Intelligent chaotic weapons (Stormbringer) want blood */ if (wep && wep->oartifact == ART_STORMBRINGER) { override_confirmation = TRUE; return(FALSE); } if (canspotmon(mtmp)) { Sprintf(qbuf, "Really attack %s?", mon_nam(mtmp)); if (yn(qbuf) != 'y') { flags.move = 0; return(TRUE); } } } return(FALSE); } /* * It is unchivalrous for a knight to attack the defenseless or from behind. */ void check_caitiff(mtmp) struct monst *mtmp; { if (Role_if(PM_KNIGHT) && u.ualign.type == A_LAWFUL && (!mtmp->mcanmove || mtmp->msleeping || (mtmp->mflee && !mtmp->mavenge)) && u.ualign.record > -10) { You("caitiff!"); adjalign(-1); } } schar find_roll_to_hit(mtmp) register struct monst *mtmp; { schar tmp; int tmp2; tmp = 1 + Luck + abon() + find_mac(mtmp) + u.uhitinc + maybe_polyd(youmonst.data->mlevel, u.ulevel); check_caitiff(mtmp); /* attacking peaceful creatures is bad for the samurai's giri */ if (Role_if(PM_SAMURAI) && mtmp->mpeaceful && u.ualign.record > -10) { You("dishonorably attack the innocent!"); adjalign(-1); } /* Adjust vs. (and possibly modify) monster state. */ if(mtmp->mstun) tmp += 2; if(mtmp->mflee) tmp += 2; if (mtmp->msleeping) { mtmp->msleeping = 0; tmp += 2; } if(!mtmp->mcanmove) { tmp += 4; if(!rn2(10)) { mtmp->mcanmove = 1; mtmp->mfrozen = 0; } } if (is_orc(mtmp->data) && maybe_polyd(is_elf(youmonst.data), Race_if(PM_ELF))) tmp++; if(Role_if(PM_MONK) && !Upolyd) { if (uarm) { Your("armor is rather cumbersome..."); tmp -= urole.spelarmr; } else if (!uwep && !uarms) { tmp += (u.ulevel / 3) + 2; } } /* with a lot of luggage, your agility diminishes */ if ((tmp2 = near_capacity()) != 0) tmp -= (tmp2*2) - 1; if (u.utrap) tmp -= 3; /* Some monsters have a combination of weapon attacks and non-weapon * attacks. It is therefore wrong to add hitval to tmp; we must add * it only for the specific attack (in hmonas()). */ if (uwep && !Upolyd) { tmp += hitval(uwep, mtmp); tmp += weapon_hit_bonus(uwep); } return tmp; } /* try to attack; return FALSE if monster evaded */ /* u.dx and u.dy must be set */ boolean attack(mtmp) register struct monst *mtmp; { schar tmp; register struct permonst *mdat = mtmp->data; /* This section of code provides protection against accidentally * hitting peaceful (like '@') and tame (like 'd') monsters. * Protection is provided as long as player is not: blind, confused, * hallucinating or stunned. * changes by wwp 5/16/85 * More changes 12/90, -dkh-. if its tame and safepet, (and protected * 07/92) then we assume that you're not trying to attack. Instead, * you'll usually just swap places if this is a movement command */ /* Intelligent chaotic weapons (Stormbringer) want blood */ if (is_safepet(mtmp) && !flags.forcefight) { if (!uwep || uwep->oartifact != ART_STORMBRINGER) { /* there are some additional considerations: this won't work * if in a shop or Punished or you miss a random roll or * if you can walk thru walls and your pet cannot (KAA) or * if your pet is a long worm (unless someone does better). * there's also a chance of displacing a "frozen" monster. * sleeping monsters might magically walk in their sleep. */ boolean foo = (Punished || !rn2(7) || is_longworm(mtmp->data)), inshop = FALSE; char *p; for (p = in_rooms(mtmp->mx, mtmp->my, SHOPBASE); *p; p++) if (tended_shop(&rooms[*p - ROOMOFFSET])) { inshop = TRUE; break; } if (inshop || foo || (IS_ROCK(levl[u.ux][u.uy].typ) && !passes_walls(mtmp->data))) { char buf[BUFSZ]; monflee(mtmp, rnd(6), FALSE, FALSE); Strcpy(buf, y_monnam(mtmp)); buf[0] = highc(buf[0]); You("stop. %s is in the way!", buf); return(TRUE); } else if ((mtmp->mfrozen || (! mtmp->mcanmove) || (mtmp->data->mmove == 0)) && rn2(6)) { pline("%s doesn't seem to move!", Monnam(mtmp)); return(TRUE); } else return(FALSE); } } /* possibly set in attack_checks; examined in known_hitum, called via hitum or hmonas below */ override_confirmation = FALSE; if (attack_checks(mtmp, uwep)) return(TRUE); if (Upolyd) { /* certain "pacifist" monsters don't attack */ if(noattacks(youmonst.data)) { You("have no way to attack monsters physically."); mtmp->mstrategy &= ~STRAT_WAITMASK; goto atk_done; } } if(check_capacity("You cannot fight while so heavily loaded.")) goto atk_done; if (u.twoweap && !can_twoweapon()) untwoweapon(); if(unweapon) { unweapon = FALSE; if(flags.verbose) { if(uwep) You("begin bashing monsters with your %s.", aobjnam(uwep, (char *)0)); else if (!cantwield(youmonst.data)) You("begin %sing monsters with your %s %s.", Role_if(PM_MONK) ? "strik" : "bash", uarmg ? "gloved" : "bare", /* Del Lamb */ makeplural(body_part(HAND))); } } exercise(A_STR, TRUE); /* you're exercising muscles */ /* andrew@orca: prevent unlimited pick-axe attacks */ u_wipe_engr(3); /* Is the "it died" check actually correct? */ if(mdat->mlet == S_LEPRECHAUN && !mtmp->mfrozen && !mtmp->msleeping && !mtmp->mconf && mtmp->mcansee && !rn2(7) && (m_move(mtmp, 0) == 2 || /* it died */ mtmp->mx != u.ux+u.dx || mtmp->my != u.uy+u.dy)) /* it moved */ return(FALSE); tmp = find_roll_to_hit(mtmp); if (Upolyd) (void) hmonas(mtmp, tmp); else (void) hitum(mtmp, tmp, youmonst.data->mattk); mtmp->mstrategy &= ~STRAT_WAITMASK; atk_done: /* see comment in attack_checks() */ /* we only need to check for this if we did an attack_checks() * and it returned 0 (it's okay to attack), and the monster didn't * evade. */ if (flags.forcefight && mtmp->mhp > 0 && !canspotmon(mtmp) && !glyph_is_invisible(levl[u.ux+u.dx][u.uy+u.dy].glyph) && !(u.uswallow && mtmp == u.ustuck)) map_invisible(u.ux+u.dx, u.uy+u.dy); return(TRUE); } STATIC_OVL boolean known_hitum(mon, mhit, uattk) /* returns TRUE if monster still lives */ register struct monst *mon; register int *mhit; struct attack *uattk; { register boolean malive = TRUE; if (override_confirmation) { /* this may need to be generalized if weapons other than Stormbringer acquire similar anti-social behavior... */ if (flags.verbose) Your("bloodthirsty blade attacks!"); } if(!*mhit) { missum(mon, uattk); } else { int oldhp = mon->mhp, x = u.ux + u.dx, y = u.uy + u.dy; /* KMH, conduct */ if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) u.uconduct.weaphit++; /* we hit the monster; be careful: it might die or be knocked into a different location */ notonhead = (mon->mx != x || mon->my != y); malive = hmon(mon, uwep, 0); /* this assumes that Stormbringer was uwep not uswapwep */ if (malive && u.twoweap && !override_confirmation && m_at(x, y) == mon) malive = hmon(mon, uswapwep, 0); if (malive) { /* monster still alive */ if(!rn2(25) && mon->mhp < mon->mhpmax/2 && !(u.uswallow && mon == u.ustuck)) { /* maybe should regurgitate if swallowed? */ if(!rn2(3)) { monflee(mon, rnd(100), FALSE, TRUE); } else monflee(mon, 0, FALSE, TRUE); if(u.ustuck == mon && !u.uswallow && !sticks(youmonst.data)) u.ustuck = 0; } /* Vorpal Blade hit converted to miss */ /* could be headless monster or worm tail */ if (mon->mhp == oldhp) { *mhit = 0; /* a miss does not break conduct */ if (uwep && (uwep->oclass == WEAPON_CLASS || is_weptool(uwep))) --u.uconduct.weaphit; } if (mon->wormno && *mhit) cutworm(mon, x, y, uwep); } } return(malive); } STATIC_OVL boolean hitum(mon, tmp, uattk) /* returns TRUE if monster still lives */ struct monst *mon; int tmp; struct attack *uattk; { boolean malive; int mhit = (tmp > (dieroll = rnd(20)) || u.uswallow); if(tmp > dieroll) exercise(A_DEX, TRUE); malive = known_hitum(mon, &mhit, uattk); (void) passive(mon, mhit, malive, AT_WEAP); return(malive); } boolean /* general "damage monster" routine */ hmon(mon, obj, thrown) /* return TRUE if mon still alive */ struct monst *mon; struct obj *obj; int thrown; { boolean result, anger_guards; anger_guards = (mon->mpeaceful && (mon->ispriest || mon->isshk || mon->data == &mons[PM_WATCHMAN] || mon->data == &mons[PM_WATCH_CAPTAIN])); result = hmon_hitmon(mon, obj, thrown); if (mon->ispriest && !rn2(2)) ghod_hitsu(mon); if (anger_guards) (void)angry_guards(!flags.soundok); return result; } /* guts of hmon() */ STATIC_OVL boolean hmon_hitmon(mon, obj, thrown) struct monst *mon; struct obj *obj; int thrown; { int tmp; struct permonst *mdat = mon->data; int barehand_silver_rings = 0; /* The basic reason we need all these booleans is that we don't want * a "hit" message when a monster dies, so we have to know how much * damage it did _before_ outputting a hit message, but any messages * associated with the damage don't come out until _after_ outputting * a hit message. */ boolean hittxt = FALSE, destroyed = FALSE, already_killed = FALSE; boolean get_dmg_bonus = TRUE; boolean ispoisoned = FALSE, needpoismsg = FALSE, poiskilled = FALSE; boolean silvermsg = FALSE, silverobj = FALSE; boolean valid_weapon_attack = FALSE; boolean unarmed = !uwep && !uarm && !uarms; #ifdef STEED int jousting = 0; #endif int wtype; struct obj *monwep; char yourbuf[BUFSZ]; char unconventional[BUFSZ]; /* substituted for word "attack" in msg */ char saved_oname[BUFSZ]; unconventional[0] = '\0'; saved_oname[0] = '\0'; wakeup(mon); if(!obj) { /* attack with bare hands */ if (mdat == &mons[PM_SHADE]) tmp = 0; else if (martial_bonus()) tmp = rnd(4); /* bonus for martial arts */ else tmp = rnd(2); valid_weapon_attack = (tmp > 1); /* blessed gloves give bonuses when fighting 'bare-handed' */ if (uarmg && uarmg->blessed && (is_undead(mdat) || is_demon(mdat))) tmp += rnd(4); /* So do silver rings. Note: rings are worn under gloves, so you * don't get both bonuses. */ if (!uarmg) { if (uleft && objects[uleft->otyp].oc_material == SILVER) barehand_silver_rings++; if (uright && objects[uright->otyp].oc_material == SILVER) barehand_silver_rings++; if (barehand_silver_rings && hates_silver(mdat)) { tmp += rnd(20); silvermsg = TRUE; } } } else { Strcpy(saved_oname, cxname(obj)); if(obj->oclass == WEAPON_CLASS || is_weptool(obj) || obj->oclass == GEM_CLASS) { /* is it not a melee weapon? */ if (/* if you strike with a bow... */ is_launcher(obj) || /* or strike with a missile in your hand... */ (!thrown && (is_missile(obj) || is_ammo(obj))) || /* or use a pole at short range and not mounted... */ (!thrown && #ifdef STEED !u.usteed && #endif is_pole(obj)) || /* or throw a missile without the proper bow... */ (is_ammo(obj) && !ammo_and_launcher(obj, uwep))) { /* then do only 1-2 points of damage */ if (mdat == &mons[PM_SHADE] && obj->otyp != SILVER_ARROW) tmp = 0; else tmp = rnd(2); if (!thrown && obj == uwep && obj->otyp == BOOMERANG && rnl(4) == 4-1) { boolean more_than_1 = (obj->quan > 1L); pline("As you hit %s, %s%s %s breaks into splinters.", mon_nam(mon), more_than_1 ? "one of " : "", shk_your(yourbuf, obj), xname(obj)); if (!more_than_1) uwepgone(); /* set unweapon */ useup(obj); if (!more_than_1) obj = (struct obj *) 0; hittxt = TRUE; if (mdat != &mons[PM_SHADE]) tmp++; } } else { tmp = dmgval(obj, mon); /* a minimal hit doesn't exercise proficiency */ valid_weapon_attack = (tmp > 1); if (!valid_weapon_attack || mon == u.ustuck || u.twoweap) { ; /* no special bonuses */ } else if (mon->mflee && Role_if(PM_ROGUE) && !Upolyd) { You("strike %s from behind!", mon_nam(mon)); tmp += rnd(u.ulevel); hittxt = TRUE; } else if (dieroll == 2 && obj == uwep && obj->oclass == WEAPON_CLASS && (bimanual(obj) || (Role_if(PM_SAMURAI) && obj->otyp == KATANA && !uarms)) && ((wtype = uwep_skill_type()) != P_NONE && P_SKILL(wtype) >= P_SKILLED) && ((monwep = MON_WEP(mon)) != 0 && !is_flimsy(monwep) && !obj_resists(monwep, 50 + 15 * greatest_erosion(obj), 100))) { /* * 2.5% chance of shattering defender's weapon when * using a two-handed weapon; less if uwep is rusted. * [dieroll == 2 is most successful non-beheading or * -bisecting hit, in case of special artifact damage; * the percentage chance is (1/20)*(50/100).] */ setmnotwielded(mon,monwep); MON_NOWEP(mon); mon->weapon_check = NEED_WEAPON; pline("%s %s %s from the force of your blow!", s_suffix(Monnam(mon)), xname(monwep), otense(monwep, "shatter")); m_useup(mon, monwep); /* If someone just shattered MY weapon, I'd flee! */ if (rn2(4)) { monflee(mon, d(2,3), TRUE, TRUE); } hittxt = TRUE; } if (obj->oartifact && artifact_hit(&youmonst, mon, obj, &tmp, dieroll)) { if(mon->mhp <= 0) /* artifact killed monster */ return FALSE; if (tmp == 0) return TRUE; hittxt = TRUE; } if (objects[obj->otyp].oc_material == SILVER && hates_silver(mdat)) { silvermsg = TRUE; silverobj = TRUE; } #ifdef STEED if (u.usteed && !thrown && tmp > 0 && weapon_type(obj) == P_LANCE && mon != u.ustuck) { jousting = joust(mon, obj); /* exercise skill even for minimal damage hits */ if (jousting) valid_weapon_attack = TRUE; } #endif if (thrown && (is_ammo(obj) || is_missile(obj))) { if (ammo_and_launcher(obj, uwep)) { /* Elves and Samurai do extra damage using * their bows&arrows; they're highly trained. */ if (Role_if(PM_SAMURAI) && obj->otyp == YA && uwep->otyp == YUMI) tmp++; else if (Race_if(PM_ELF) && obj->otyp == ELVEN_ARROW && uwep->otyp == ELVEN_BOW) tmp++; } if(obj->opoisoned && is_poisonable(obj)) ispoisoned = TRUE; } } } else if(obj->oclass == POTION_CLASS) { if (obj->quan > 1L) obj = splitobj(obj, 1L); else setuwep((struct obj *)0); freeinv(obj); potionhit(mon, obj, TRUE); if (mon->mhp <= 0) return FALSE; /* killed */ hittxt = TRUE; /* in case potion effect causes transformation */ mdat = mon->data; tmp = (mdat == &mons[PM_SHADE]) ? 0 : 1; } else { if (mdat == &mons[PM_SHADE] && !shade_aware(obj)) { tmp = 0; Strcpy(unconventional, cxname(obj)); } else { switch(obj->otyp) { case BOULDER: /* 1d20 */ case HEAVY_IRON_BALL: /* 1d25 */ case IRON_CHAIN: /* 1d4+1 */ tmp = dmgval(obj, mon); break; case MIRROR: if (breaktest(obj)) { You("break %s mirror. That's bad luck!", shk_your(yourbuf, obj)); change_luck(-2); useup(obj); obj = (struct obj *) 0; unarmed = FALSE; /* avoid obj==0 confusion */ get_dmg_bonus = FALSE; hittxt = TRUE; } tmp = 1; break; #ifdef TOURIST case EXPENSIVE_CAMERA: You("succeed in destroying %s camera. Congratulations!", shk_your(yourbuf, obj)); useup(obj); return(TRUE); /*NOTREACHED*/ break; #endif case CORPSE: /* fixed by polder@cs.vu.nl */ if (touch_petrifies(&mons[obj->corpsenm])) { static const char withwhat[] = "corpse"; tmp = 1; hittxt = TRUE; You("hit %s with %s %s.", mon_nam(mon), obj->dknown ? the(mons[obj->corpsenm].mname) : an(mons[obj->corpsenm].mname), (obj->quan > 1) ? makeplural(withwhat) : withwhat); if (!munstone(mon, TRUE)) minstapetrify(mon, TRUE); if (resists_ston(mon)) break; /* note: hp may be <= 0 even if munstoned==TRUE */ return (boolean) (mon->mhp > 0); #if 0 } else if (touch_petrifies(mdat)) { /* maybe turn the corpse into a statue? */ #endif } tmp = (obj->corpsenm >= LOW_PM ? mons[obj->corpsenm].msize : 0) + 1; break; case EGG: { #define useup_eggs(o) { if (thrown) obfree(o,(struct obj *)0); \ else useupall(o); \ o = (struct obj *)0; } /* now gone */ long cnt = obj->quan; tmp = 1; /* nominal physical damage */ get_dmg_bonus = FALSE; hittxt = TRUE; /* message always given */ /* egg is always either used up or transformed, so next hand-to-hand attack should yield a "bashing" mesg */ if (obj == uwep) unweapon = TRUE; if (obj->spe && obj->corpsenm >= LOW_PM) { if (obj->quan < 5) change_luck((schar) -(obj->quan)); else change_luck(-5); } if (touch_petrifies(&mons[obj->corpsenm])) { /*learn_egg_type(obj->corpsenm);*/ pline("Splat! You hit %s with %s %s egg%s!", mon_nam(mon), obj->known ? "the" : cnt > 1L ? "some" : "a", obj->known ? mons[obj->corpsenm].mname : "petrifying", plur(cnt)); obj->known = 1; /* (not much point...) */ useup_eggs(obj); if (!munstone(mon, TRUE)) minstapetrify(mon, TRUE); if (resists_ston(mon)) break; return (boolean) (mon->mhp > 0); } else { /* ordinary egg(s) */ const char *eggp = (obj->corpsenm != NON_PM && obj->known) ? the(mons[obj->corpsenm].mname) : (cnt > 1L) ? "some" : "an"; You("hit %s with %s egg%s.", mon_nam(mon), eggp, plur(cnt)); if (touch_petrifies(mdat) && !stale_egg(obj)) { pline_The("egg%s %s alive any more...", plur(cnt), (cnt == 1L) ? "isn't" : "aren't"); if (obj->timed) obj_stop_timers(obj); obj->otyp = ROCK; obj->oclass = GEM_CLASS; obj->oartifact = 0; obj->spe = 0; obj->known = obj->dknown = obj->bknown = 0; obj->owt = weight(obj); if (thrown) place_object(obj, mon->mx, mon->my); } else { pline("Splat!"); useup_eggs(obj); exercise(A_WIS, FALSE); } } break; #undef useup_eggs } case CLOVE_OF_GARLIC: /* no effect against demons */ if (is_undead(mdat)) { monflee(mon, d(2, 4), FALSE, TRUE); } tmp = 1; break; case CREAM_PIE: case BLINDING_VENOM: mon->msleeping = 0; if (can_blnd(&youmonst, mon, (uchar) (obj->otyp == BLINDING_VENOM ? AT_SPIT : AT_WEAP), obj)) { if (Blind) { pline(obj->otyp == CREAM_PIE ? "Splat!" : "Splash!"); } else if (obj->otyp == BLINDING_VENOM) { pline_The("venom blinds %s%s!", mon_nam(mon), mon->mcansee ? "" : " further"); } else { char *whom = mon_nam(mon); char *what = The(xname(obj)); if (!thrown && obj->quan > 1) what = An(singular(obj, xname)); /* note: s_suffix returns a modifiable buffer */ if (haseyes(mdat) && mdat != &mons[PM_FLOATING_EYE]) whom = strcat(strcat(s_suffix(whom), " "), mbodypart(mon, FACE)); pline("%s %s over %s!", what, vtense(what, "splash"), whom); } setmangry(mon); mon->mcansee = 0; tmp = rn1(25, 21); if(((int) mon->mblinded + tmp) > 127) mon->mblinded = 127; else mon->mblinded += tmp; } else { pline(obj->otyp==CREAM_PIE ? "Splat!" : "Splash!"); setmangry(mon); } if (thrown) obfree(obj, (struct obj *)0); else useup(obj); hittxt = TRUE; get_dmg_bonus = FALSE; tmp = 0; break; case ACID_VENOM: /* thrown (or spit) */ if (resists_acid(mon)) { Your("venom hits %s harmlessly.", mon_nam(mon)); tmp = 0; } else { Your("venom burns %s!", mon_nam(mon)); tmp = dmgval(obj, mon); } if (thrown) obfree(obj, (struct obj *)0); else useup(obj); hittxt = TRUE; get_dmg_bonus = FALSE; break; default: /* non-weapons can damage because of their weight */ /* (but not too much) */ tmp = obj->owt/100; if(tmp < 1) tmp = 1; else tmp = rnd(tmp); if(tmp > 6) tmp = 6; /* * Things like silver wands can arrive here so * so we need another silver check. */ if (objects[obj->otyp].oc_material == SILVER && hates_silver(mdat)) { tmp += rnd(20); silvermsg = TRUE; silverobj = TRUE; } } } } } /****** NOTE: perhaps obj is undefined!! (if !thrown && BOOMERANG) * *OR* if attacking bare-handed!! */ if (get_dmg_bonus && tmp > 0) { tmp += u.udaminc; /* If you throw using a propellor, you don't get a strength * bonus but you do get an increase-damage bonus. */ if(!thrown || !obj || !uwep || !ammo_and_launcher(obj, uwep)) tmp += dbon(); } if (valid_weapon_attack) { struct obj *wep; /* to be valid a projectile must have had the correct projector */ wep = PROJECTILE(obj) ? uwep : obj; tmp += weapon_dam_bonus(wep); /* [this assumes that `!thrown' implies wielded...] */ wtype = thrown ? weapon_type(wep) : uwep_skill_type(); use_skill(wtype, 1); } if (ispoisoned) { int nopoison = (10 - (obj->owt/10)); if(nopoison < 2) nopoison = 2; if Role_if(PM_SAMURAI) { You("dishonorably use a poisoned weapon!"); adjalign(-sgn(u.ualign.type)); } else if ((u.ualign.type == A_LAWFUL) && (u.ualign.record > -10)) { You_feel("like an evil coward for using a poisoned weapon."); adjalign(-1); } if (obj && !rn2(nopoison)) { obj->opoisoned = FALSE; Your("%s %s no longer poisoned.", xname(obj), otense(obj, "are")); } if (resists_poison(mon)) needpoismsg = TRUE; else if (rn2(10)) tmp += rnd(6); else poiskilled = TRUE; } if (tmp < 1) { /* make sure that negative damage adjustment can't result in inadvertently boosting the victim's hit points */ tmp = 0; if (mdat == &mons[PM_SHADE]) { if (!hittxt) { const char *what = unconventional[0] ? unconventional : "attack"; Your("%s %s harmlessly through %s.", what, vtense(what, "pass"), mon_nam(mon)); hittxt = TRUE; } } else { if (get_dmg_bonus) tmp = 1; } } #ifdef STEED if (jousting) { tmp += d(2, (obj == uwep) ? 10 : 2); /* [was in dmgval()] */ You("joust %s%s", mon_nam(mon), canseemon(mon) ? exclam(tmp) : "."); if (jousting < 0) { Your("%s shatters on impact!", xname(obj)); /* (must be either primary or secondary weapon to get here) */ u.twoweap = FALSE; /* untwoweapon() is too verbose here */ if (obj == uwep) uwepgone(); /* set unweapon */ /* minor side-effect: broken lance won't split puddings */ useup(obj); obj = 0; } /* avoid migrating a dead monster */ if (mon->mhp > tmp) { mhurtle(mon, u.dx, u.dy, 1); mdat = mon->data; /* in case of a polymorph trap */ if (DEADMONSTER(mon)) already_killed = TRUE; } hittxt = TRUE; } else #endif /* VERY small chance of stunning opponent if unarmed. */ if (unarmed && tmp > 1 && !thrown && !obj && !Upolyd) { if (rnd(100) < P_SKILL(P_BARE_HANDED_COMBAT) && !bigmonst(mdat) && !thick_skinned(mdat)) { if (canspotmon(mon)) pline("%s %s from your powerful strike!", Monnam(mon), makeplural(stagger(mon->data, "stagger"))); /* avoid migrating a dead monster */ if (mon->mhp > tmp) { mhurtle(mon, u.dx, u.dy, 1); mdat = mon->data; /* in case of a polymorph trap */ if (DEADMONSTER(mon)) already_killed = TRUE; } hittxt = TRUE; } } if (!already_killed) mon->mhp -= tmp; /* adjustments might have made tmp become less than what a level draining artifact has already done to max HP */ if (mon->mhp > mon->mhpmax) mon->mhp = mon->mhpmax; if (mon->mhp < 1) destroyed = TRUE; if (mon->mtame && (!mon->mflee || mon->mfleetim) && tmp > 0) { abuse_dog(mon); monflee(mon, 10 * rnd(tmp), FALSE, FALSE); } if((mdat == &mons[PM_BLACK_PUDDING] || mdat == &mons[PM_BROWN_PUDDING]) && obj && obj == uwep && objects[obj->otyp].oc_material == IRON && mon->mhp > 1 && !thrown && !mon->mcan /* && !destroyed -- guaranteed by mhp > 1 */ ) { if (clone_mon(mon, 0, 0)) { pline("%s divides as you hit it!", Monnam(mon)); hittxt = TRUE; } } if (!hittxt && /*( thrown => obj exists )*/ (!destroyed || (thrown && m_shot.n > 1 && m_shot.o == obj->otyp))) { if (thrown) hit(mshot_xname(obj), mon, exclam(tmp)); else if (!flags.verbose) You("hit it."); else You("%s %s%s", Role_if(PM_BARBARIAN) ? "smite" : "hit", mon_nam(mon), canseemon(mon) ? exclam(tmp) : "."); } if (silvermsg) { const char *fmt; char *whom = mon_nam(mon); char silverobjbuf[BUFSZ]; if (canspotmon(mon)) { if (barehand_silver_rings == 1) fmt = "Your silver ring sears %s!"; else if (barehand_silver_rings == 2) fmt = "Your silver rings sear %s!"; else if (silverobj && saved_oname[0]) { Sprintf(silverobjbuf, "Your %s%s %s %%s!", strstri(saved_oname, "silver") ? "" : "silver ", saved_oname, vtense(saved_oname, "sear")); fmt = silverobjbuf; } else fmt = "The silver sears %s!"; } else { *whom = highc(*whom); /* "it" -> "It" */ fmt = "%s is seared!"; } /* note: s_suffix returns a modifiable buffer */ if (!noncorporeal(mdat)) whom = strcat(s_suffix(whom), " flesh"); pline(fmt, whom); } if (needpoismsg) pline_The("poison doesn't seem to affect %s.", mon_nam(mon)); if (poiskilled) { pline_The("poison was deadly..."); if (!already_killed) xkilled(mon, 0); return FALSE; } else if (destroyed) { if (!already_killed) killed(mon); /* takes care of most messages */ } else if(u.umconf && !thrown) { nohandglow(mon); if (!mon->mconf && !resist(mon, SPBOOK_CLASS, 0, NOTELL)) { mon->mconf = 1; if (!mon->mstun && mon->mcanmove && !mon->msleeping && canseemon(mon)) pline("%s appears confused.", Monnam(mon)); } } return((boolean)(destroyed ? FALSE : TRUE)); } STATIC_OVL boolean shade_aware(obj) struct obj *obj; { if (!obj) return FALSE; /* * The things in this list either * 1) affect shades. * OR * 2) are dealt with properly by other routines * when it comes to shades. */ if (obj->otyp == BOULDER || obj->otyp == HEAVY_IRON_BALL || obj->otyp == IRON_CHAIN /* dmgval handles those first three */ || obj->otyp == MIRROR /* silver in the reflective surface */ || obj->otyp == CLOVE_OF_GARLIC /* causes shades to flee */ || objects[obj->otyp].oc_material == SILVER) return TRUE; return FALSE; } /* check whether slippery clothing protects from hug or wrap attack */ /* [currently assumes that you are the attacker] */ STATIC_OVL boolean m_slips_free(mdef, mattk) struct monst *mdef; struct attack *mattk; { struct obj *obj; if (mattk->adtyp == AD_DRIN) { /* intelligence drain attacks the head */ obj = which_armor(mdef, W_ARMH); } else { /* grabbing attacks the body */ obj = which_armor(mdef, W_ARMC); /* cloak */ if (!obj) obj = which_armor(mdef, W_ARM); /* suit */ #ifdef TOURIST if (!obj) obj = which_armor(mdef, W_ARMU); /* shirt */ #endif } /* if your cloak/armor is greased, monster slips off; this protection might fail (33% chance) when the armor is cursed */ if (obj && (obj->greased || obj->otyp == OILSKIN_CLOAK) && (!obj->cursed || rn2(3))) { You("%s %s %s %s!", mattk->adtyp == AD_WRAP ? "slip off of" : "grab, but cannot hold onto", s_suffix(mon_nam(mdef)), obj->greased ? "greased" : "slippery", /* avoid "slippery slippery cloak" for undiscovered oilskin cloak */ (obj->greased || objects[obj->otyp].oc_name_known) ? xname(obj) : cloak_simple_name(obj)); if (obj->greased && !rn2(2)) { pline_The("grease wears off."); obj->greased = 0; } return TRUE; } return FALSE; } /* used when hitting a monster with a lance while mounted */ STATIC_OVL int /* 1: joust hit; 0: ordinary hit; -1: joust but break lance */ joust(mon, obj) struct monst *mon; /* target */ struct obj *obj; /* weapon */ { int skill_rating, joust_dieroll; if (Fumbling || Stunned) return 0; /* sanity check; lance must be wielded in order to joust */ if (obj != uwep && (obj != uswapwep || !u.twoweap)) return 0; /* if using two weapons, use worse of lance and two-weapon skills */ skill_rating = P_SKILL(weapon_type(obj)); /* lance skill */ if (u.twoweap && P_SKILL(P_TWO_WEAPON_COMBAT) < skill_rating) skill_rating = P_SKILL(P_TWO_WEAPON_COMBAT); if (skill_rating == P_ISRESTRICTED) skill_rating = P_UNSKILLED; /* 0=>1 */ /* odds to joust are expert:80%, skilled:60%, basic:40%, unskilled:20% */ if ((joust_dieroll = rn2(5)) < skill_rating) { if (joust_dieroll == 0 && rnl(50) == (50-1) && !unsolid(mon->data) && !obj_resists(obj, 0, 100)) return -1; /* hit that breaks lance */ return 1; /* successful joust */ } return 0; /* no joust bonus; revert to ordinary attack */ } /* * Send in a demon pet for the hero. Exercise wisdom. * * This function used to be inline to damageum(), but the Metrowerks compiler * (DR4 and DR4.5) screws up with an internal error 5 "Expression Too Complex." * Pulling it out makes it work. */ STATIC_OVL void demonpet() { int i; struct permonst *pm; struct monst *dtmp; pline("Some hell-p has arrived!"); i = !rn2(6) ? ndemon(u.ualign.type) : NON_PM; pm = i != NON_PM ? &mons[i] : youmonst.data; if ((dtmp = makemon(pm, u.ux, u.uy, NO_MM_FLAGS)) != 0) (void)tamedog(dtmp, (struct obj *)0); exercise(A_WIS, TRUE); } /* * Player uses theft attack against monster. * * If the target is wearing body armor, take all of its possesions; * otherwise, take one object. [Is this really the behavior we want?] * * This routine implicitly assumes that there is no way to be able to * resist petfication (ie, be polymorphed into a xorn or golem) at the * same time as being able to steal (poly'd into nymph or succubus). * If that ever changes, the check for touching a cockatrice corpse * will need to be smarter about whether to break out of the theft loop. */ STATIC_OVL void steal_it(mdef, mattk) struct monst *mdef; struct attack *mattk; { struct obj *otmp, *stealoid, **minvent_ptr; long unwornmask; if (!mdef->minvent) return; /* nothing to take */ /* look for worn body armor */ stealoid = (struct obj *)0; if (could_seduce(&youmonst, mdef, mattk)) { /* find armor, and move it to end of inventory in the process */ minvent_ptr = &mdef->minvent; while ((otmp = *minvent_ptr) != 0) if (otmp->owornmask & W_ARM) { if (stealoid) panic("steal_it: multiple worn suits"); *minvent_ptr = otmp->nobj; /* take armor out of minvent */ stealoid = otmp; stealoid->nobj = (struct obj *)0; } else { minvent_ptr = &otmp->nobj; } *minvent_ptr = stealoid; /* put armor back into minvent */ } if (stealoid) { /* we will be taking everything */ if (gender(mdef) == (int) u.mfemale && youmonst.data->mlet == S_NYMPH) You("charm %s. She gladly hands over her possessions.", mon_nam(mdef)); else You("seduce %s and %s starts to take off %s clothes.", mon_nam(mdef), mhe(mdef), mhis(mdef)); } while ((otmp = mdef->minvent) != 0) { if (!Upolyd) break; /* no longer have ability to steal */ /* take the object away from the monster */ obj_extract_self(otmp); if ((unwornmask = otmp->owornmask) != 0L) { mdef->misc_worn_check &= ~unwornmask; if (otmp->owornmask & W_WEP) { setmnotwielded(mdef,otmp); MON_NOWEP(mdef); } otmp->owornmask = 0L; update_mon_intrinsics(mdef, otmp, FALSE, FALSE); if (otmp == stealoid) /* special message for final item */ pline("%s finishes taking off %s suit.", Monnam(mdef), mhis(mdef)); } /* give the object to the character */ otmp = hold_another_object(otmp, "You snatched but dropped %s.", doname(otmp), "You steal: "); if (otmp->where != OBJ_INVENT) continue; if (otmp->otyp == CORPSE && touch_petrifies(&mons[otmp->corpsenm]) && !uarmg) { char kbuf[BUFSZ]; Sprintf(kbuf, "stolen %s corpse", mons[otmp->corpsenm].mname); instapetrify(kbuf); break; /* stop the theft even if hero survives */ } /* more take-away handling, after theft message */ if (unwornmask & W_WEP) { /* stole wielded weapon */ possibly_unwield(mdef, FALSE); } else if (unwornmask & W_ARMG) { /* stole worn gloves */ mselftouch(mdef, (const char *)0, TRUE); if (mdef->mhp <= 0) /* it's now a statue */ return; /* can't continue stealing */ } if (!stealoid) break; /* only taking one item */ } } int damageum(mdef, mattk) register struct monst *mdef; register struct attack *mattk; { register struct permonst *pd = mdef->data; register int tmp = d((int)mattk->damn, (int)mattk->damd); int armpro; boolean negated; armpro = magic_negation(mdef); /* since hero can't be cancelled, only defender's armor applies */ negated = !((rn2(3) >= armpro) || !rn2(50)); if (is_demon(youmonst.data) && !rn2(13) && !uwep && u.umonnum != PM_SUCCUBUS && u.umonnum != PM_INCUBUS && u.umonnum != PM_BALROG) { demonpet(); return(0); } switch(mattk->adtyp) { case AD_STUN: if(!Blind) pline("%s %s for a moment.", Monnam(mdef), makeplural(stagger(mdef->data, "stagger"))); mdef->mstun = 1; goto physical; case AD_LEGS: /* if (u.ucancelled) { */ /* tmp = 0; */ /* break; */ /* } */ goto physical; case AD_WERE: /* no special effect on monsters */ case AD_HEAL: /* likewise */ case AD_PHYS: physical: if(mattk->aatyp == AT_WEAP) { if(uwep) tmp = 0; } else if(mattk->aatyp == AT_KICK) { if(thick_skinned(mdef->data)) tmp = 0; if(mdef->data == &mons[PM_SHADE]) { if (!(uarmf && uarmf->blessed)) { impossible("bad shade attack function flow?"); tmp = 0; } else tmp = rnd(4); /* bless damage */ } } break; case AD_FIRE: if (negated) { tmp = 0; break; } if (!Blind) pline("%s is %s!", Monnam(mdef), on_fire(mdef->data, mattk)); if (pd == &mons[PM_STRAW_GOLEM] || pd == &mons[PM_PAPER_GOLEM]) { if (!Blind) pline("%s burns completely!", Monnam(mdef)); xkilled(mdef,2); tmp = 0; break; /* Don't return yet; keep hp<1 and tmp=0 for pet msg */ } tmp += destroy_mitem(mdef, SCROLL_CLASS, AD_FIRE); tmp += destroy_mitem(mdef, SPBOOK_CLASS, AD_FIRE); if (resists_fire(mdef)) { if (!Blind) pline_The("fire doesn't heat %s!", mon_nam(mdef)); golemeffects(mdef, AD_FIRE, tmp); shieldeff(mdef->mx, mdef->my); tmp = 0; } /* only potions damage resistant players in destroy_item */ tmp += destroy_mitem(mdef, POTION_CLASS, AD_FIRE); break; case AD_COLD: if (negated) { tmp = 0; break; } if (!Blind) pline("%s is covered in frost!", Monnam(mdef)); if (resists_cold(mdef)) { shieldeff(mdef->mx, mdef->my); if (!Blind) pline_The("frost doesn't chill %s!", mon_nam(mdef)); golemeffects(mdef, AD_COLD, tmp); tmp = 0; } tmp += destroy_mitem(mdef, POTION_CLASS, AD_COLD); break; case AD_ELEC: if (negated) { tmp = 0; break; } if (!Blind) pline("%s is zapped!", Monnam(mdef)); tmp += destroy_mitem(mdef, WAND_CLASS, AD_ELEC); if (resists_elec(mdef)) { if (!Blind) pline_The("zap doesn't shock %s!", mon_nam(mdef)); golemeffects(mdef, AD_ELEC, tmp); shieldeff(mdef->mx, mdef->my); tmp = 0; } /* only rings damage resistant players in destroy_item */ tmp += destroy_mitem(mdef, RING_CLASS, AD_ELEC); break; case AD_ACID: if (resists_acid(mdef)) tmp = 0; break; case AD_STON: if (!munstone(mdef, TRUE)) minstapetrify(mdef, TRUE); tmp = 0; break; #ifdef SEDUCE case AD_SSEX: #endif case AD_SEDU: case AD_SITM: steal_it(mdef, mattk); tmp = 0; break; case AD_SGLD: #ifndef GOLDOBJ if (mdef->mgold) { u.ugold += mdef->mgold; mdef->mgold = 0; Your("purse feels heavier."); } #else /* This you as a leprechaun, so steal real gold only, no lesser coins */ { struct obj *mongold = findgold(mdef->minvent); if (mongold) { obj_extract_self(mongold); if (merge_choice(invent, mongold) || inv_cnt() < 52) { addinv(mongold); Your("purse feels heavier."); } else { You("grab %s's gold, but find no room in your knapsack.", mon_nam(mdef)); dropy(mongold); } } } #endif exercise(A_DEX, TRUE); tmp = 0; break; case AD_TLPT: if (tmp <= 0) tmp = 1; if (!negated && tmp < mdef->mhp) { char nambuf[BUFSZ]; boolean u_saw_mon = canseemon(mdef) || (u.uswallow && u.ustuck == mdef); /* record the name before losing sight of monster */ Strcpy(nambuf, Monnam(mdef)); if (u_teleport_mon(mdef, FALSE) && u_saw_mon && !canseemon(mdef)) pline("%s suddenly disappears!", nambuf); } break; case AD_BLND: if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj*)0)) { if(!Blind && mdef->mcansee) pline("%s is blinded.", Monnam(mdef)); mdef->mcansee = 0; tmp += mdef->mblinded; if (tmp > 127) tmp = 127; mdef->mblinded = tmp; } tmp = 0; break; case AD_CURS: if (night() && !rn2(10) && !mdef->mcan) { if (mdef->data == &mons[PM_CLAY_GOLEM]) { if (!Blind) pline("Some writing vanishes from %s head!", s_suffix(mon_nam(mdef))); xkilled(mdef, 0); /* Don't return yet; keep hp<1 and tmp=0 for pet msg */ } else { mdef->mcan = 1; You("chuckle."); } } tmp = 0; break; case AD_DRLI: if (!negated && !rn2(3) && !resists_drli(mdef)) { int xtmp = d(2,6); pline("%s suddenly seems weaker!", Monnam(mdef)); mdef->mhpmax -= xtmp; if ((mdef->mhp -= xtmp) <= 0 || !mdef->m_lev) { pline("%s dies!", Monnam(mdef)); xkilled(mdef,0); } else mdef->m_lev--; tmp = 0; } break; case AD_RUST: if (pd == &mons[PM_IRON_GOLEM]) { pline("%s falls to pieces!", Monnam(mdef)); xkilled(mdef,0); } hurtmarmor(mdef, AD_RUST); tmp = 0; break; case AD_CORR: hurtmarmor(mdef, AD_CORR); tmp = 0; break; case AD_DCAY: if (pd == &mons[PM_WOOD_GOLEM] || pd == &mons[PM_LEATHER_GOLEM]) { pline("%s falls to pieces!", Monnam(mdef)); xkilled(mdef,0); } hurtmarmor(mdef, AD_DCAY); tmp = 0; break; case AD_DRST: case AD_DRDX: case AD_DRCO: if (!negated && !rn2(8)) { Your("%s was poisoned!", mpoisons_subj(&youmonst, mattk)); if (resists_poison(mdef)) pline_The("poison doesn't seem to affect %s.", mon_nam(mdef)); else { if (!rn2(10)) { Your("poison was deadly..."); tmp = mdef->mhp; } else tmp += rn1(10,6); } } break; case AD_DRIN: if (notonhead || !has_head(mdef->data)) { pline("%s doesn't seem harmed.", Monnam(mdef)); tmp = 0; if (!Unchanging && mdef->data == &mons[PM_GREEN_SLIME]) { if (!Slimed) { You("suck in some slime and don't feel very well."); Slimed = 10L; } } break; } if (m_slips_free(mdef, mattk)) break; if ((mdef->misc_worn_check & W_ARMH) && rn2(8)) { pline("%s helmet blocks your attack to %s head.", s_suffix(Monnam(mdef)), mhis(mdef)); break; } You("eat %s brain!", s_suffix(mon_nam(mdef))); u.uconduct.food++; if (touch_petrifies(mdef->data) && !Stone_resistance && !Stoned) { Stoned = 5; killer_format = KILLED_BY_AN; delayed_killer = mdef->data->mname; } if (!vegan(mdef->data)) u.uconduct.unvegan++; if (!vegetarian(mdef->data)) violated_vegetarian(); if (mindless(mdef->data)) { pline("%s doesn't notice.", Monnam(mdef)); break; } tmp += rnd(10); morehungry(-rnd(30)); /* cannot choke */ if (ABASE(A_INT) < AMAX(A_INT)) { ABASE(A_INT) += rnd(4); if (ABASE(A_INT) > AMAX(A_INT)) ABASE(A_INT) = AMAX(A_INT); flags.botl = 1; } exercise(A_WIS, TRUE); break; case AD_STCK: if (!negated && !sticks(mdef->data)) u.ustuck = mdef; /* it's now stuck to you */ break; case AD_WRAP: if (!sticks(mdef->data)) { if (!u.ustuck && !rn2(10)) { if (m_slips_free(mdef, mattk)) { tmp = 0; } else { You("swing yourself around %s!", mon_nam(mdef)); u.ustuck = mdef; } } else if(u.ustuck == mdef) { /* Monsters don't wear amulets of magical breathing */ if (is_pool(u.ux,u.uy) && !is_swimmer(mdef->data) && !amphibious(mdef->data)) { You("drown %s...", mon_nam(mdef)); tmp = mdef->mhp; } else if(mattk->aatyp == AT_HUGS) pline("%s is being crushed.", Monnam(mdef)); } else { tmp = 0; if (flags.verbose) You("brush against %s %s.", s_suffix(mon_nam(mdef)), mbodypart(mdef, LEG)); } } else tmp = 0; break; case AD_PLYS: if (!negated && mdef->mcanmove && !rn2(3) && tmp < mdef->mhp) { if (!Blind) pline("%s is frozen by you!", Monnam(mdef)); mdef->mcanmove = 0; mdef->mfrozen = rnd(10); } break; case AD_SLEE: if (!negated && !mdef->msleeping && sleep_monst(mdef, rnd(10), -1)) { if (!Blind) pline("%s is put to sleep by you!", Monnam(mdef)); slept_monst(mdef); } break; case AD_SLIM: if (negated) break; /* physical damage only */ if (!rn2(4) && !flaming(mdef->data) && mdef->data != &mons[PM_GREEN_SLIME]) { You("turn %s into slime.", mon_nam(mdef)); (void) newcham(mdef, &mons[PM_GREEN_SLIME], FALSE, FALSE); tmp = 0; } break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ /* there's no msomearmor() function, so just do damage */ /* if (negated) break; */ break; case AD_SLOW: if (!negated && mdef->mspeed != MSLOW) { unsigned int oldspeed = mdef->mspeed; mon_adjust_speed(mdef, -1, (struct obj *)0); if (mdef->mspeed != oldspeed && canseemon(mdef)) pline("%s slows down.", Monnam(mdef)); } break; case AD_CONF: if (!mdef->mconf) { if (canseemon(mdef)) pline("%s looks confused.", Monnam(mdef)); mdef->mconf = 1; } break; default: tmp = 0; break; } mdef->mstrategy &= ~STRAT_WAITFORU; /* in case player is very fast */ if((mdef->mhp -= tmp) < 1) { if (mdef->mtame && !cansee(mdef->mx,mdef->my)) { You_feel("embarrassed for a moment."); if (tmp) xkilled(mdef, 0); /* !tmp but hp<1: already killed */ } else if (!flags.verbose) { You("destroy it!"); if (tmp) xkilled(mdef, 0); } else if (tmp) killed(mdef); return(2); } return(1); } STATIC_OVL int explum(mdef, mattk) register struct monst *mdef; register struct attack *mattk; { register int tmp = d((int)mattk->damn, (int)mattk->damd); You("explode!"); switch(mattk->adtyp) { boolean resistance; /* only for cold/fire/elec */ case AD_BLND: if (!resists_blnd(mdef)) { pline("%s is blinded by your flash of light!", Monnam(mdef)); mdef->mblinded = min((int)mdef->mblinded + tmp, 127); mdef->mcansee = 0; } break; case AD_HALU: if (haseyes(mdef->data) && mdef->mcansee) { pline("%s is affected by your flash of light!", Monnam(mdef)); mdef->mconf = 1; } break; case AD_COLD: resistance = resists_cold(mdef); goto common; case AD_FIRE: resistance = resists_fire(mdef); goto common; case AD_ELEC: resistance = resists_elec(mdef); common: if (!resistance) { pline("%s gets blasted!", Monnam(mdef)); mdef->mhp -= tmp; if (mdef->mhp <= 0) { killed(mdef); return(2); } } else { shieldeff(mdef->mx, mdef->my); if (is_golem(mdef->data)) golemeffects(mdef, (int)mattk->adtyp, tmp); else pline_The("blast doesn't seem to affect %s.", mon_nam(mdef)); } break; default: break; } return(1); } STATIC_OVL void start_engulf(mdef) struct monst *mdef; { if (!Invisible) { map_location(u.ux, u.uy, TRUE); tmp_at(DISP_ALWAYS, mon_to_glyph(&youmonst)); tmp_at(mdef->mx, mdef->my); } You("engulf %s!", mon_nam(mdef)); delay_output(); delay_output(); } STATIC_OVL void end_engulf() { if (!Invisible) { tmp_at(DISP_END, 0); newsym(u.ux, u.uy); } } STATIC_OVL int gulpum(mdef,mattk) register struct monst *mdef; register struct attack *mattk; { register int tmp; register int dam = d((int)mattk->damn, (int)mattk->damd); struct obj *otmp; /* Not totally the same as for real monsters. Specifically, these * don't take multiple moves. (It's just too hard, for too little * result, to program monsters which attack from inside you, which * would be necessary if done accurately.) Instead, we arbitrarily * kill the monster immediately for AD_DGST and we regurgitate them * after exactly 1 round of attack otherwise. -KAA */ if(mdef->data->msize >= MZ_HUGE) return 0; if(u.uhunger < 1500 && !u.uswallow) { for (otmp = mdef->minvent; otmp; otmp = otmp->nobj) (void) snuff_lit(otmp); if(!touch_petrifies(mdef->data) || Stone_resistance) { #ifdef LINT /* static char msgbuf[BUFSZ]; */ char msgbuf[BUFSZ]; #else static char msgbuf[BUFSZ]; #endif start_engulf(mdef); switch(mattk->adtyp) { case AD_DGST: /* eating a Rider or its corpse is fatal */ if (is_rider(mdef->data)) { pline("Unfortunately, digesting any of it is fatal."); end_engulf(); Sprintf(msgbuf, "unwisely tried to eat %s", mdef->data->mname); killer = msgbuf; killer_format = NO_KILLER_PREFIX; done(DIED); return 0; /* lifesaved */ } if (Slow_digestion) { dam = 0; break; } /* KMH, conduct */ u.uconduct.food++; if (!vegan(mdef->data)) u.uconduct.unvegan++; if (!vegetarian(mdef->data)) violated_vegetarian(); /* Use up amulet of life saving */ if (!!(otmp = mlifesaver(mdef))) m_useup(mdef, otmp); newuhs(FALSE); xkilled(mdef,2); if (mdef->mhp > 0) { /* monster lifesaved */ You("hurriedly regurgitate the sizzling in your %s.", body_part(STOMACH)); } else { tmp = 1 + (mdef->data->cwt >> 8); if (corpse_chance(mdef, &youmonst, TRUE) && !(mvitals[monsndx(mdef->data)].mvflags & G_NOCORPSE)) { /* nutrition only if there can be a corpse */ u.uhunger += (mdef->data->cnutrit+1) / 2; } else tmp = 0; Sprintf(msgbuf, "You totally digest %s.", mon_nam(mdef)); if (tmp != 0) { /* setting afternmv = end_engulf is tempting, * but will cause problems if the player is * attacked (which uses his real location) or * if his See_invisible wears off */ You("digest %s.", mon_nam(mdef)); if (Slow_digestion) tmp *= 2; nomul(-tmp); nomovemsg = msgbuf; } else pline("%s", msgbuf); if (mdef->data == &mons[PM_GREEN_SLIME]) { Sprintf(msgbuf, "%s isn't sitting well with you.", The(mdef->data->mname)); if (!Unchanging) { Slimed = 5L; flags.botl = 1; } } else exercise(A_CON, TRUE); } end_engulf(); return(2); case AD_PHYS: if (youmonst.data == &mons[PM_FOG_CLOUD]) { pline("%s is laden with your moisture.", Monnam(mdef)); if (amphibious(mdef->data) && !flaming(mdef->data)) { dam = 0; pline("%s seems unharmed.", Monnam(mdef)); } } else pline("%s is pummeled with your debris!", Monnam(mdef)); break; case AD_ACID: pline("%s is covered with your goo!", Monnam(mdef)); if (resists_acid(mdef)) { pline("It seems harmless to %s.", mon_nam(mdef)); dam = 0; } break; case AD_BLND: if (can_blnd(&youmonst, mdef, mattk->aatyp, (struct obj *)0)) { if (mdef->mcansee) pline("%s can't see in there!", Monnam(mdef)); mdef->mcansee = 0; dam += mdef->mblinded; if (dam > 127) dam = 127; mdef->mblinded = dam; } dam = 0; break; case AD_ELEC: if (rn2(2)) { pline_The("air around %s crackles with electricity.", mon_nam(mdef)); if (resists_elec(mdef)) { pline("%s seems unhurt.", Monnam(mdef)); dam = 0; } golemeffects(mdef,(int)mattk->adtyp,dam); } else dam = 0; break; case AD_COLD: if (rn2(2)) { if (resists_cold(mdef)) { pline("%s seems mildly chilly.", Monnam(mdef)); dam = 0; } else pline("%s is freezing to death!",Monnam(mdef)); golemeffects(mdef,(int)mattk->adtyp,dam); } else dam = 0; break; case AD_FIRE: if (rn2(2)) { if (resists_fire(mdef)) { pline("%s seems mildly hot.", Monnam(mdef)); dam = 0; } else pline("%s is burning to a crisp!",Monnam(mdef)); golemeffects(mdef,(int)mattk->adtyp,dam); } else dam = 0; break; } end_engulf(); if ((mdef->mhp -= dam) <= 0) { killed(mdef); if (mdef->mhp <= 0) /* not lifesaved */ return(2); } You("%s %s!", is_animal(youmonst.data) ? "regurgitate" : "expel", mon_nam(mdef)); if (Slow_digestion || is_animal(youmonst.data)) { pline("Obviously, you didn't like %s taste.", s_suffix(mon_nam(mdef))); } } else { char kbuf[BUFSZ]; You("bite into %s.", mon_nam(mdef)); Sprintf(kbuf, "swallowing %s whole", an(mdef->data->mname)); instapetrify(kbuf); } } return(0); } void missum(mdef,mattk) register struct monst *mdef; register struct attack *mattk; { if (could_seduce(&youmonst, mdef, mattk)) You("pretend to be friendly to %s.", mon_nam(mdef)); else if(canspotmon(mdef) && flags.verbose) You("miss %s.", mon_nam(mdef)); else You("miss it."); if (!mdef->msleeping && mdef->mcanmove) wakeup(mdef); } STATIC_OVL boolean hmonas(mon, tmp) /* attack monster as a monster. */ register struct monst *mon; register int tmp; { struct attack *mattk, alt_attk; int i, sum[NATTK], hittmp = 0; int nsum = 0; int dhit = 0; for(i = 0; i < NATTK; i++) { sum[i] = 0; mattk = getmattk(youmonst.data, i, sum, &alt_attk); switch(mattk->aatyp) { case AT_WEAP: use_weapon: /* Certain monsters don't use weapons when encountered as enemies, * but players who polymorph into them have hands or claws and thus * should be able to use weapons. This shouldn't prohibit the use * of most special abilities, either. */ /* Potential problem: if the monster gets multiple weapon attacks, * we currently allow the player to get each of these as a weapon * attack. Is this really desirable? */ if (uwep) { hittmp = hitval(uwep, mon); hittmp += weapon_hit_bonus(uwep); tmp += hittmp; } dhit = (tmp > (dieroll = rnd(20)) || u.uswallow); /* KMH -- Don't accumulate to-hit bonuses */ if (uwep) tmp -= hittmp; /* Enemy dead, before any special abilities used */ if (!known_hitum(mon,&dhit,mattk)) { sum[i] = 2; break; } else sum[i] = dhit; /* might be a worm that gets cut in half */ if (m_at(u.ux+u.dx, u.uy+u.dy) != mon) return((boolean)(nsum != 0)); /* Do not print "You hit" message, since known_hitum * already did it. */ if (dhit && mattk->adtyp != AD_SPEL && mattk->adtyp != AD_PHYS) sum[i] = damageum(mon,mattk); break; case AT_CLAW: if (i==0 && uwep && !cantwield(youmonst.data)) goto use_weapon; #ifdef SEDUCE /* succubi/incubi are humanoid, but their _second_ * attack is AT_CLAW, not their first... */ if (i==1 && uwep && (u.umonnum == PM_SUCCUBUS || u.umonnum == PM_INCUBUS)) goto use_weapon; #endif case AT_KICK: case AT_BITE: case AT_STNG: case AT_TUCH: case AT_BUTT: case AT_TENT: if (i==0 && uwep && (youmonst.data->mlet==S_LICH)) goto use_weapon; if ((dhit = (tmp > rnd(20) || u.uswallow)) != 0) { int compat; if (!u.uswallow && (compat=could_seduce(&youmonst, mon, mattk))) { You("%s %s %s.", mon->mcansee && haseyes(mon->data) ? "smile at" : "talk to", mon_nam(mon), compat == 2 ? "engagingly":"seductively"); /* doesn't anger it; no wakeup() */ sum[i] = damageum(mon, mattk); break; } wakeup(mon); /* maybe this check should be in damageum()? */ if (mon->data == &mons[PM_SHADE] && !(mattk->aatyp == AT_KICK && uarmf && uarmf->blessed)) { Your("attack passes harmlessly through %s.", mon_nam(mon)); break; } if (mattk->aatyp == AT_KICK) You("kick %s.", mon_nam(mon)); else if (mattk->aatyp == AT_BITE) You("bite %s.", mon_nam(mon)); else if (mattk->aatyp == AT_STNG) You("sting %s.", mon_nam(mon)); else if (mattk->aatyp == AT_BUTT) You("butt %s.", mon_nam(mon)); else if (mattk->aatyp == AT_TUCH) You("touch %s.", mon_nam(mon)); else if (mattk->aatyp == AT_TENT) Your("tentacles suck %s.", mon_nam(mon)); else You("hit %s.", mon_nam(mon)); sum[i] = damageum(mon, mattk); } else missum(mon, mattk); break; case AT_HUGS: /* automatic if prev two attacks succeed, or if * already grabbed in a previous attack */ dhit = 1; wakeup(mon); if (mon->data == &mons[PM_SHADE]) Your("hug passes harmlessly through %s.", mon_nam(mon)); else if (!sticks(mon->data) && !u.uswallow) { if (mon==u.ustuck) { pline("%s is being %s.", Monnam(mon), u.umonnum==PM_ROPE_GOLEM ? "choked": "crushed"); sum[i] = damageum(mon, mattk); } else if(i >= 2 && sum[i-1] && sum[i-2]) { You("grab %s!", mon_nam(mon)); u.ustuck = mon; sum[i] = damageum(mon, mattk); } } break; case AT_EXPL: /* automatic hit if next to */ dhit = -1; wakeup(mon); sum[i] = explum(mon, mattk); break; case AT_ENGL: if((dhit = (tmp > rnd(20+i)))) { wakeup(mon); if (mon->data == &mons[PM_SHADE]) Your("attempt to surround %s is harmless.", mon_nam(mon)); else { sum[i]= gulpum(mon,mattk); if (sum[i] == 2 && (mon->data->mlet == S_ZOMBIE || mon->data->mlet == S_MUMMY) && rn2(5) && !Sick_resistance) { You_feel("%ssick.", (Sick) ? "very " : ""); mdamageu(mon, rnd(8)); } } } else missum(mon, mattk); break; case AT_MAGC: /* No check for uwep; if wielding nothing we want to * do the normal 1-2 points bare hand damage... */ if (i==0 && (youmonst.data->mlet==S_KOBOLD || youmonst.data->mlet==S_ORC || youmonst.data->mlet==S_GNOME )) goto use_weapon; case AT_NONE: case AT_BOOM: continue; /* Not break--avoid passive attacks from enemy */ case AT_BREA: case AT_SPIT: case AT_GAZE: /* all done using #monster command */ dhit = 0; break; default: /* Strange... */ impossible("strange attack of yours (%d)", mattk->aatyp); } if (dhit == -1) { u.mh = -1; /* dead in the current form */ rehumanize(); } if (sum[i] == 2) return((boolean)passive(mon, 1, 0, mattk->aatyp)); /* defender dead */ else { (void) passive(mon, sum[i], 1, mattk->aatyp); nsum |= sum[i]; } if (!Upolyd) break; /* No extra attacks if no longer a monster */ if (multi < 0) break; /* If paralyzed while attacking, i.e. floating eye */ } return((boolean)(nsum != 0)); } /* Special (passive) attacks on you by monsters done here. */ int passive(mon, mhit, malive, aatyp) register struct monst *mon; register boolean mhit; register int malive; uchar aatyp; { register struct permonst *ptr = mon->data; register int i, tmp; for(i = 0; ; i++) { if(i >= NATTK) return(malive | mhit); /* no passive attacks */ if(ptr->mattk[i].aatyp == AT_NONE) break; /* try this one */ } /* Note: tmp not always used */ if (ptr->mattk[i].damn) tmp = d((int)ptr->mattk[i].damn, (int)ptr->mattk[i].damd); else if(ptr->mattk[i].damd) tmp = d((int)mon->m_lev+1, (int)ptr->mattk[i].damd); else tmp = 0; /* These affect you even if they just died */ switch(ptr->mattk[i].adtyp) { case AD_ACID: if(mhit && rn2(2)) { if (Blind || !flags.verbose) You("are splashed!"); else You("are splashed by %s acid!", s_suffix(mon_nam(mon))); if (!Acid_resistance) mdamageu(mon, tmp); if(!rn2(30)) erode_armor(&youmonst, TRUE); } if (mhit) { if (aatyp == AT_KICK) { if (uarmf && !rn2(6)) (void)rust_dmg(uarmf, xname(uarmf), 3, TRUE, &youmonst); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) passive_obj(mon, (struct obj*)0, &(ptr->mattk[i])); } exercise(A_STR, FALSE); break; case AD_STON: if (mhit) { /* successful attack */ long protector = attk_protection((int)aatyp); /* hero using monsters' AT_MAGC attack is hitting hand to hand rather than casting a spell */ if (aatyp == AT_MAGC) protector = W_ARMG; if (protector == 0L || /* no protection */ (protector == W_ARMG && !uarmg && !uwep) || (protector == W_ARMF && !uarmf) || (protector == W_ARMH && !uarmh) || (protector == (W_ARMC|W_ARMG) && (!uarmc || !uarmg))) { if (!Stone_resistance && !(poly_when_stoned(youmonst.data) && polymon(PM_STONE_GOLEM))) { You("turn to stone..."); done_in_by(mon); return 2; } } } break; case AD_RUST: if(mhit && !mon->mcan) { if (aatyp == AT_KICK) { if (uarmf) (void)rust_dmg(uarmf, xname(uarmf), 1, TRUE, &youmonst); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) passive_obj(mon, (struct obj*)0, &(ptr->mattk[i])); } break; case AD_CORR: if(mhit && !mon->mcan) { if (aatyp == AT_KICK) { if (uarmf) (void)rust_dmg(uarmf, xname(uarmf), 3, TRUE, &youmonst); } else if (aatyp == AT_WEAP || aatyp == AT_CLAW || aatyp == AT_MAGC || aatyp == AT_TUCH) passive_obj(mon, (struct obj*)0, &(ptr->mattk[i])); } break; case AD_MAGM: /* wrath of gods for attacking Oracle */ if(Antimagic) { shieldeff(u.ux, u.uy); pline("A hail of magic missiles narrowly misses you!"); } else { You("are hit by magic missiles appearing from thin air!"); mdamageu(mon, tmp); } break; case AD_ENCH: /* KMH -- remove enchantment (disenchanter) */ if (mhit) { struct obj *obj = (struct obj *)0; if (aatyp == AT_KICK) { obj = uarmf; if (!obj) break; } else if (aatyp == AT_BITE || aatyp == AT_BUTT || (aatyp >= AT_STNG && aatyp < AT_WEAP)) { break; /* no object involved */ } passive_obj(mon, obj, &(ptr->mattk[i])); } break; default: break; } /* These only affect you if they still live */ if(malive && !mon->mcan && rn2(3)) { switch(ptr->mattk[i].adtyp) { case AD_PLYS: if(ptr == &mons[PM_FLOATING_EYE]) { if (!canseemon(mon)) { break; } if(mon->mcansee) { if (ureflects("%s gaze is reflected by your %s.", s_suffix(Monnam(mon)))) ; else if (Free_action) You("momentarily stiffen under %s gaze!", s_suffix(mon_nam(mon))); else { You("are frozen by %s gaze!", s_suffix(mon_nam(mon))); nomul((ACURR(A_WIS) > 12 || rn2(4)) ? -tmp : -127); } } else { pline("%s cannot defend itself.", Adjmonnam(mon,"blind")); if(!rn2(500)) change_luck(-1); } } else if (Free_action) { You("momentarily stiffen."); } else { /* gelatinous cube */ You("are frozen by %s!", mon_nam(mon)); nomovemsg = 0; /* default: "you can move again" */ nomul(-tmp); exercise(A_DEX, FALSE); } break; case AD_COLD: /* brown mold or blue jelly */ if(monnear(mon, u.ux, u.uy)) { if(Cold_resistance) { shieldeff(u.ux, u.uy); You_feel("a mild chill."); ugolemeffects(AD_COLD, tmp); break; } You("are suddenly very cold!"); mdamageu(mon, tmp); /* monster gets stronger with your heat! */ mon->mhp += tmp / 2; if (mon->mhpmax < mon->mhp) mon->mhpmax = mon->mhp; /* at a certain point, the monster will reproduce! */ if(mon->mhpmax > ((int) (mon->m_lev+1) * 8)) (void)split_mon(mon, &youmonst); } break; case AD_STUN: /* specifically yellow mold */ if(!Stunned) make_stunned((long)tmp, TRUE); break; case AD_FIRE: if(monnear(mon, u.ux, u.uy)) { if(Fire_resistance) { shieldeff(u.ux, u.uy); You_feel("mildly warm."); ugolemeffects(AD_FIRE, tmp); break; } You("are suddenly very hot!"); mdamageu(mon, tmp); } break; case AD_ELEC: if(Shock_resistance) { shieldeff(u.ux, u.uy); You_feel("a mild tingle."); ugolemeffects(AD_ELEC, tmp); break; } You("are jolted with electricity!"); mdamageu(mon, tmp); break; default: break; } } return(malive | mhit); } /* * Special (passive) attacks on an attacking object by monsters done here. * Assumes the attack was successful. */ void passive_obj(mon, obj, mattk) register struct monst *mon; register struct obj *obj; /* null means pick uwep, uswapwep or uarmg */ struct attack *mattk; /* null means we find one internally */ { register struct permonst *ptr = mon->data; register int i; /* if caller hasn't specified an object, use uwep, uswapwep or uarmg */ if (!obj) { obj = (u.twoweap && uswapwep && !rn2(2)) ? uswapwep : uwep; if (!obj && mattk->adtyp == AD_ENCH) obj = uarmg; /* no weapon? then must be gloves */ if (!obj) return; /* no object to affect */ } /* if caller hasn't specified an attack, find one */ if (!mattk) { for(i = 0; ; i++) { if(i >= NATTK) return; /* no passive attacks */ if(ptr->mattk[i].aatyp == AT_NONE) break; /* try this one */ } mattk = &(ptr->mattk[i]); } switch(mattk->adtyp) { case AD_ACID: if(!rn2(6)) { erode_obj(obj, TRUE, FALSE); } break; case AD_RUST: if(!mon->mcan) { erode_obj(obj, FALSE, FALSE); } break; case AD_CORR: if(!mon->mcan) { erode_obj(obj, TRUE, FALSE); } break; case AD_ENCH: if (!mon->mcan) { if (drain_item(obj) && carried(obj) && (obj->known || obj->oclass == ARMOR_CLASS)) { Your("%s less effective.", aobjnam(obj, "seem")); } break; } default: break; } if (carried(obj)) update_inventory(); } /* Note: caller must ascertain mtmp is mimicking... */ void stumble_onto_mimic(mtmp) struct monst *mtmp; { const char *fmt = "Wait! That's %s!", *generic = "a monster", *what = 0; if(!u.ustuck && !mtmp->mflee && dmgtype(mtmp->data,AD_STCK)) u.ustuck = mtmp; if (Blind) { if (!Blind_telepat) what = generic; /* with default fmt */ else if (mtmp->m_ap_type == M_AP_MONSTER) what = a_monnam(mtmp); /* differs from what was sensed */ } else { int glyph = levl[u.ux+u.dx][u.uy+u.dy].glyph; if (glyph_is_cmap(glyph) && (glyph_to_cmap(glyph) == S_hcdoor || glyph_to_cmap(glyph) == S_vcdoor)) fmt = "The door actually was %s!"; else if (glyph_is_object(glyph) && glyph_to_obj(glyph) == GOLD_PIECE) fmt = "That gold was %s!"; /* cloned Wiz starts out mimicking some other monster and might make himself invisible before being revealed */ if (mtmp->minvis && !See_invisible) what = generic; else what = a_monnam(mtmp); } if (what) pline(fmt, what); wakeup(mtmp); /* clears mimicking */ } STATIC_OVL void nohandglow(mon) struct monst *mon; { char *hands=makeplural(body_part(HAND)); if (!u.umconf || mon->mconf) return; if (u.umconf == 1) { if (Blind) Your("%s stop tingling.", hands); else Your("%s stop glowing %s.", hands, hcolor(NH_RED)); } else { if (Blind) pline_The("tingling in your %s lessens.", hands); else Your("%s no longer glow so brightly %s.", hands, hcolor(NH_RED)); } u.umconf--; } int flash_hits_mon(mtmp, otmp) struct monst *mtmp; struct obj *otmp; /* source of flash */ { int tmp, amt, res = 0, useeit = canseemon(mtmp); if (mtmp->msleeping) { mtmp->msleeping = 0; if (useeit) { pline_The("flash awakens %s.", mon_nam(mtmp)); res = 1; } } else if (mtmp->data->mlet != S_LIGHT) { if (!resists_blnd(mtmp)) { tmp = dist2(otmp->ox, otmp->oy, mtmp->mx, mtmp->my); if (useeit) { pline("%s is blinded by the flash!", Monnam(mtmp)); res = 1; } if (mtmp->data == &mons[PM_GREMLIN]) { /* Rule #1: Keep them out of the light. */ amt = otmp->otyp == WAN_LIGHT ? d(1 + otmp->spe, 4) : rn2(min(mtmp->mhp,4)); pline("%s %s!", Monnam(mtmp), amt > mtmp->mhp / 2 ? "wails in agony" : "cries out in pain"); if ((mtmp->mhp -= amt) <= 0) { if (flags.mon_moving) monkilled(mtmp, (char *)0, AD_BLND); else killed(mtmp); } else if (cansee(mtmp->mx,mtmp->my) && !canspotmon(mtmp)){ map_invisible(mtmp->mx, mtmp->my); } } if (mtmp->mhp > 0) { if (!flags.mon_moving) setmangry(mtmp); if (tmp < 9 && !mtmp->isshk && rn2(4)) { if (rn2(4)) monflee(mtmp, rnd(100), FALSE, TRUE); else monflee(mtmp, 0, FALSE, TRUE); } mtmp->mcansee = 0; mtmp->mblinded = (tmp < 3) ? 0 : rnd(1 + 50/tmp); } } } return res; } /*uhitm.c*/ nethack-3.4.3/src/vault.c0100644000000000000000000005225107764735041013745 0ustar rootroot/* SCCS Id: @(#)vault.c 3.4 2003/01/15 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "vault.h" STATIC_DCL struct monst *NDECL(findgd); #define g_monnam(mtmp) \ x_monnam(mtmp, ARTICLE_NONE, (char *)0, SUPPRESS_IT, FALSE) #ifdef OVLB STATIC_DCL boolean FDECL(clear_fcorr, (struct monst *,BOOLEAN_P)); STATIC_DCL void FDECL(restfakecorr,(struct monst *)); STATIC_DCL boolean FDECL(in_fcorridor, (struct monst *,int,int)); STATIC_DCL void FDECL(move_gold,(struct obj *,int)); STATIC_DCL void FDECL(wallify_vault,(struct monst *)); STATIC_OVL boolean clear_fcorr(grd, forceshow) register struct monst *grd; register boolean forceshow; { register int fcx, fcy, fcbeg; register struct monst *mtmp; if (!on_level(&(EGD(grd)->gdlevel), &u.uz)) return TRUE; while((fcbeg = EGD(grd)->fcbeg) < EGD(grd)->fcend) { fcx = EGD(grd)->fakecorr[fcbeg].fx; fcy = EGD(grd)->fakecorr[fcbeg].fy; if((grd->mhp <= 0 || !in_fcorridor(grd, u.ux, u.uy)) && EGD(grd)->gddone) forceshow = TRUE; if((u.ux == fcx && u.uy == fcy && grd->mhp > 0) || (!forceshow && couldsee(fcx,fcy)) || (Punished && !carried(uball) && uball->ox == fcx && uball->oy == fcy)) return FALSE; if ((mtmp = m_at(fcx,fcy)) != 0) { if(mtmp->isgd) return(FALSE); else if(!in_fcorridor(grd, u.ux, u.uy)) { if(mtmp->mtame) yelp(mtmp); (void) rloc(mtmp, FALSE); } } levl[fcx][fcy].typ = EGD(grd)->fakecorr[fcbeg].ftyp; map_location(fcx, fcy, 1); /* bypass vision */ if(!ACCESSIBLE(levl[fcx][fcy].typ)) block_point(fcx,fcy); EGD(grd)->fcbeg++; } if(grd->mhp <= 0) { pline_The("corridor disappears."); if(IS_ROCK(levl[u.ux][u.uy].typ)) You("are encased in rock."); } return(TRUE); } STATIC_OVL void restfakecorr(grd) register struct monst *grd; { /* it seems you left the corridor - let the guard disappear */ if(clear_fcorr(grd, FALSE)) mongone(grd); } boolean grddead(grd) /* called in mon.c */ register struct monst *grd; { register boolean dispose = clear_fcorr(grd, TRUE); if(!dispose) { /* see comment by newpos in gd_move() */ remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, 0, 0); EGD(grd)->ogx = grd->mx; EGD(grd)->ogy = grd->my; dispose = clear_fcorr(grd, TRUE); } return(dispose); } STATIC_OVL boolean in_fcorridor(grd, x, y) register struct monst *grd; int x, y; { register int fci; for(fci = EGD(grd)->fcbeg; fci < EGD(grd)->fcend; fci++) if(x == EGD(grd)->fakecorr[fci].fx && y == EGD(grd)->fakecorr[fci].fy) return(TRUE); return(FALSE); } STATIC_OVL struct monst * findgd() { register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if(mtmp->isgd && !DEADMONSTER(mtmp) && on_level(&(EGD(mtmp)->gdlevel), &u.uz)) return(mtmp); return((struct monst *)0); } #endif /* OVLB */ #ifdef OVL0 char vault_occupied(array) char *array; { register char *ptr; for (ptr = array; *ptr; ptr++) if (rooms[*ptr - ROOMOFFSET].rtype == VAULT) return(*ptr); return('\0'); } void invault() { #ifdef BSD_43_BUG int dummy; /* hack to avoid schain botch */ #endif struct monst *guard; int trycount, vaultroom = (int)vault_occupied(u.urooms); if(!vaultroom) { u.uinvault = 0; return; } vaultroom -= ROOMOFFSET; guard = findgd(); if(++u.uinvault % 30 == 0 && !guard) { /* if time ok and no guard now. */ char buf[BUFSZ]; register int x, y, dd, gx, gy; int lx = 0, ly = 0; #ifdef GOLDOBJ long umoney; #endif /* first find the goal for the guard */ for(dd = 2; (dd < ROWNO || dd < COLNO); dd++) { for(y = u.uy-dd; y <= u.uy+dd; ly = y, y++) { if(y < 0 || y > ROWNO-1) continue; for(x = u.ux-dd; x <= u.ux+dd; lx = x, x++) { if(y != u.uy-dd && y != u.uy+dd && x != u.ux-dd) x = u.ux+dd; if(x < 1 || x > COLNO-1) continue; if(levl[x][y].typ == CORR) { if(x < u.ux) lx = x + 1; else if(x > u.ux) lx = x - 1; else lx = x; if(y < u.uy) ly = y + 1; else if(y > u.uy) ly = y - 1; else ly = y; if(levl[lx][ly].typ != STONE && levl[lx][ly].typ != CORR) goto incr_radius; goto fnd; } } } incr_radius: ; } impossible("Not a single corridor on this level??"); tele(); return; fnd: gx = x; gy = y; /* next find a good place for a door in the wall */ x = u.ux; y = u.uy; if(levl[x][y].typ != ROOM) { /* player dug a door and is in it */ if(levl[x+1][y].typ == ROOM) x = x + 1; else if(levl[x][y+1].typ == ROOM) y = y + 1; else if(levl[x-1][y].typ == ROOM) x = x - 1; else if(levl[x][y-1].typ == ROOM) y = y - 1; else if(levl[x+1][y+1].typ == ROOM) { x = x + 1; y = y + 1; } else if (levl[x-1][y-1].typ == ROOM) { x = x - 1; y = y - 1; } else if (levl[x+1][y-1].typ == ROOM) { x = x + 1; y = y - 1; } else if (levl[x-1][y+1].typ == ROOM) { x = x - 1; y = y + 1; } } while(levl[x][y].typ == ROOM) { register int dx,dy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if(abs(gx-x) >= abs(gy-y)) x += dx; else y += dy; } if(x == u.ux && y == u.uy) { if(levl[x+1][y].typ == HWALL || levl[x+1][y].typ == DOOR) x = x + 1; else if(levl[x-1][y].typ == HWALL || levl[x-1][y].typ == DOOR) x = x - 1; else if(levl[x][y+1].typ == VWALL || levl[x][y+1].typ == DOOR) y = y + 1; else if(levl[x][y-1].typ == VWALL || levl[x][y-1].typ == DOOR) y = y - 1; else return; } /* make something interesting happen */ if(!(guard = makemon(&mons[PM_GUARD], x, y, NO_MM_FLAGS))) return; guard->isgd = 1; guard->mpeaceful = 1; set_malign(guard); EGD(guard)->gddone = 0; EGD(guard)->ogx = x; EGD(guard)->ogy = y; assign_level(&(EGD(guard)->gdlevel), &u.uz); EGD(guard)->vroom = vaultroom; EGD(guard)->warncnt = 0; reset_faint(); /* if fainted - wake up */ if (canspotmon(guard)) pline("Suddenly one of the Vault's %s enters!", makeplural(g_monnam(guard))); else pline("Someone else has entered the Vault."); newsym(guard->mx,guard->my); if (youmonst.m_ap_type == M_AP_OBJECT || u.uundetected) { if (youmonst.m_ap_type == M_AP_OBJECT && youmonst.mappearance != GOLD_PIECE) verbalize("Hey! Who left that %s in here?", mimic_obj_name(&youmonst)); /* You're mimicking some object or you're hidden. */ pline("Puzzled, %s turns around and leaves.", mhe(guard)); mongone(guard); return; } if (Strangled || is_silent(youmonst.data) || multi < 0) { /* [we ought to record whether this this message has already been given in order to vary it upon repeat visits, but discarding the monster and its egd data renders that hard] */ verbalize("I'll be back when you're ready to speak to me!"); mongone(guard); return; } stop_occupation(); /* if occupied, stop it *now* */ if (multi > 0) { nomul(0); unmul((char *)0); } trycount = 5; do { getlin("\"Hello stranger, who are you?\" -", buf); (void) mungspaces(buf); } while (!letter(buf[0]) && --trycount > 0); if (u.ualign.type == A_LAWFUL && /* ignore trailing text, in case player includes character's rank */ strncmpi(buf, plname, (int) strlen(plname)) != 0) { adjalign(-1); /* Liar! */ } if (!strcmpi(buf, "Croesus") || !strcmpi(buf, "Kroisos") #ifdef TOURIST || !strcmpi(buf, "Creosote") #endif ) { if (!mvitals[PM_CROESUS].died) { verbalize("Oh, yes, of course. Sorry to have disturbed you."); mongone(guard); } else { setmangry(guard); verbalize("Back from the dead, are you? I'll remedy that!"); /* don't want guard to waste next turn wielding a weapon */ if (!MON_WEP(guard)) { guard->weapon_check = NEED_HTH_WEAPON; (void) mon_wield_item(guard); } } return; } verbalize("I don't know you."); #ifndef GOLDOBJ if (!u.ugold && !hidden_gold()) verbalize("Please follow me."); else { if (!u.ugold) verbalize("You have hidden gold."); verbalize("Most likely all your gold was stolen from this vault."); verbalize("Please drop that gold and follow me."); } #else umoney = money_cnt(invent); if (!umoney && !hidden_gold()) verbalize("Please follow me."); else { if (!umoney) verbalize("You have hidden money."); verbalize("Most likely all your money was stolen from this vault."); verbalize("Please drop that money and follow me."); } #endif EGD(guard)->gdx = gx; EGD(guard)->gdy = gy; EGD(guard)->fcbeg = 0; EGD(guard)->fakecorr[0].fx = x; EGD(guard)->fakecorr[0].fy = y; if(IS_WALL(levl[x][y].typ)) EGD(guard)->fakecorr[0].ftyp = levl[x][y].typ; else { /* the initial guard location is a dug door */ int vlt = EGD(guard)->vroom; xchar lowx = rooms[vlt].lx, hix = rooms[vlt].hx; xchar lowy = rooms[vlt].ly, hiy = rooms[vlt].hy; if(x == lowx-1 && y == lowy-1) EGD(guard)->fakecorr[0].ftyp = TLCORNER; else if(x == hix+1 && y == lowy-1) EGD(guard)->fakecorr[0].ftyp = TRCORNER; else if(x == lowx-1 && y == hiy+1) EGD(guard)->fakecorr[0].ftyp = BLCORNER; else if(x == hix+1 && y == hiy+1) EGD(guard)->fakecorr[0].ftyp = BRCORNER; else if(y == lowy-1 || y == hiy+1) EGD(guard)->fakecorr[0].ftyp = HWALL; else if(x == lowx-1 || x == hix+1) EGD(guard)->fakecorr[0].ftyp = VWALL; } levl[x][y].typ = DOOR; levl[x][y].doormask = D_NODOOR; unblock_point(x, y); /* doesn't block light */ EGD(guard)->fcend = 1; EGD(guard)->warncnt = 1; } } #endif /* OVL0 */ #ifdef OVLB STATIC_OVL void move_gold(gold, vroom) struct obj *gold; int vroom; { xchar nx, ny; remove_object(gold); newsym(gold->ox, gold->oy); nx = rooms[vroom].lx + rn2(2); ny = rooms[vroom].ly + rn2(2); place_object(gold, nx, ny); stackobj(gold); newsym(nx,ny); } STATIC_OVL void wallify_vault(grd) struct monst *grd; { int x, y, typ; int vlt = EGD(grd)->vroom; char tmp_viz; xchar lox = rooms[vlt].lx - 1, hix = rooms[vlt].hx + 1, loy = rooms[vlt].ly - 1, hiy = rooms[vlt].hy + 1; struct monst *mon; struct obj *gold; struct trap *trap; boolean fixed = FALSE; boolean movedgold = FALSE; for (x = lox; x <= hix; x++) for (y = loy; y <= hiy; y++) { /* if not on the room boundary, skip ahead */ if (x != lox && x != hix && y != loy && y != hiy) continue; if (!IS_WALL(levl[x][y].typ) && !in_fcorridor(grd, x, y)) { if ((mon = m_at(x, y)) != 0 && mon != grd) { if (mon->mtame) yelp(mon); (void) rloc(mon, FALSE); } if ((gold = g_at(x, y)) != 0) { move_gold(gold, EGD(grd)->vroom); movedgold = TRUE; } if ((trap = t_at(x, y)) != 0) deltrap(trap); if (x == lox) typ = (y == loy) ? TLCORNER : (y == hiy) ? BLCORNER : VWALL; else if (x == hix) typ = (y == loy) ? TRCORNER : (y == hiy) ? BRCORNER : VWALL; else /* not left or right side, must be top or bottom */ typ = HWALL; levl[x][y].typ = typ; levl[x][y].doormask = 0; /* * hack: player knows walls are restored because of the * message, below, so show this on the screen. */ tmp_viz = viz_array[y][x]; viz_array[y][x] = IN_SIGHT|COULD_SEE; newsym(x,y); viz_array[y][x] = tmp_viz; block_point(x,y); fixed = TRUE; } } if(movedgold || fixed) { if(in_fcorridor(grd, grd->mx, grd->my) || cansee(grd->mx, grd->my)) pline_The("%s whispers an incantation.", g_monnam(grd)); else You_hear("a distant chant."); if(movedgold) pline("A mysterious force moves the gold into the vault."); if(fixed) pline_The("damaged vault's walls are magically restored!"); } } /* * return 1: guard moved, 0: guard didn't, -1: let m_move do it, -2: died */ int gd_move(grd) register struct monst *grd; { int x, y, nx, ny, m, n; int dx, dy, gx, gy, fci; uchar typ; struct fakecorridor *fcp; register struct egd *egrd = EGD(grd); register struct rm *crm; register boolean goldincorridor = FALSE, u_in_vault = vault_occupied(u.urooms)? TRUE : FALSE, grd_in_vault = *in_rooms(grd->mx, grd->my, VAULT)? TRUE : FALSE; boolean disappear_msg_seen = FALSE, semi_dead = (grd->mhp <= 0); #ifndef GOLDOBJ register boolean u_carry_gold = ((u.ugold + hidden_gold()) > 0L); #else long umoney = money_cnt(invent); register boolean u_carry_gold = ((umoney + hidden_gold()) > 0L); #endif boolean see_guard; if(!on_level(&(egrd->gdlevel), &u.uz)) return(-1); nx = ny = m = n = 0; if(!u_in_vault && !grd_in_vault) wallify_vault(grd); if(!grd->mpeaceful) { if(semi_dead) { egrd->gddone =1; goto newpos; } if(!u_in_vault && (grd_in_vault || (in_fcorridor(grd, grd->mx, grd->my) && !in_fcorridor(grd, u.ux, u.uy)))) { (void) rloc(grd, FALSE); wallify_vault(grd); (void) clear_fcorr(grd, TRUE); goto letknow; } if(!in_fcorridor(grd, grd->mx, grd->my)) (void) clear_fcorr(grd, TRUE); return(-1); } if(abs(egrd->ogx - grd->mx) > 1 || abs(egrd->ogy - grd->my) > 1) return(-1); /* teleported guard - treat as monster */ if(egrd->fcend == 1) { if(u_in_vault && (u_carry_gold || um_dist(grd->mx, grd->my, 1))) { if(egrd->warncnt == 3) verbalize("I repeat, %sfollow me!", u_carry_gold ? ( #ifndef GOLDOBJ !u.ugold ? "drop that hidden gold and " : "drop that gold and ") : ""); #else !umoney ? "drop that hidden money and " : "drop that money and ") : ""); #endif if(egrd->warncnt == 7) { m = grd->mx; n = grd->my; verbalize("You've been warned, knave!"); mnexto(grd); levl[m][n].typ = egrd->fakecorr[0].ftyp; newsym(m,n); grd->mpeaceful = 0; return(-1); } /* not fair to get mad when (s)he's fainted or paralyzed */ if(!is_fainted() && multi >= 0) egrd->warncnt++; return(0); } if (!u_in_vault) { if (u_carry_gold) { /* player teleported */ m = grd->mx; n = grd->my; (void) rloc(grd, FALSE); levl[m][n].typ = egrd->fakecorr[0].ftyp; newsym(m,n); grd->mpeaceful = 0; letknow: if (!cansee(grd->mx, grd->my) || !mon_visible(grd)) You_hear("the shrill sound of a guard's whistle."); else You(um_dist(grd->mx, grd->my, 2) ? "see an angry %s approaching." : "are confronted by an angry %s.", g_monnam(grd)); return(-1); } else { verbalize("Well, begone."); wallify_vault(grd); egrd->gddone = 1; goto cleanup; } } } if(egrd->fcend > 1) { if(egrd->fcend > 2 && in_fcorridor(grd, grd->mx, grd->my) && !egrd->gddone && !in_fcorridor(grd, u.ux, u.uy) && levl[egrd->fakecorr[0].fx][egrd->fakecorr[0].fy].typ == egrd->fakecorr[0].ftyp) { pline_The("%s, confused, disappears.", g_monnam(grd)); disappear_msg_seen = TRUE; goto cleanup; } if(u_carry_gold && (in_fcorridor(grd, u.ux, u.uy) || /* cover a 'blind' spot */ (egrd->fcend > 1 && u_in_vault))) { if(!grd->mx) { restfakecorr(grd); return(-2); } if(egrd->warncnt < 6) { egrd->warncnt = 6; verbalize("Drop all your gold, scoundrel!"); return(0); } else { verbalize("So be it, rogue!"); grd->mpeaceful = 0; return(-1); } } } for(fci = egrd->fcbeg; fci < egrd->fcend; fci++) if(g_at(egrd->fakecorr[fci].fx, egrd->fakecorr[fci].fy)){ m = egrd->fakecorr[fci].fx; n = egrd->fakecorr[fci].fy; goldincorridor = TRUE; } if(goldincorridor && !egrd->gddone) { x = grd->mx; y = grd->my; if (m == u.ux && n == u.uy) { struct obj *gold = g_at(m,n); /* Grab the gold from between the hero's feet. */ #ifndef GOLDOBJ grd->mgold += gold->quan; delobj(gold); #else obj_extract_self(gold); add_to_minv(grd, gold); #endif newsym(m,n); } else if (m == x && n == y) { mpickgold(grd); /* does a newsym */ } else { /* just for insurance... */ if (MON_AT(m, n) && m != grd->mx && n != grd->my) { verbalize("Out of my way, scum!"); (void) rloc(m_at(m, n), FALSE); } remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, m, n); mpickgold(grd); /* does a newsym */ } if(cansee(m,n)) pline("%s%s picks up the gold.", Monnam(grd), grd->mpeaceful ? " calms down and" : ""); if(x != grd->mx || y != grd->my) { remove_monster(grd->mx, grd->my); newsym(grd->mx, grd->my); place_monster(grd, x, y); newsym(x, y); } if(!grd->mpeaceful) return(-1); else { egrd->warncnt = 5; return(0); } } if(um_dist(grd->mx, grd->my, 1) || egrd->gddone) { if(!egrd->gddone && !rn2(10)) verbalize("Move along!"); restfakecorr(grd); return(0); /* didn't move */ } x = grd->mx; y = grd->my; if(u_in_vault) goto nextpos; /* look around (hor & vert only) for accessible places */ for(nx = x-1; nx <= x+1; nx++) for(ny = y-1; ny <= y+1; ny++) { if((nx == x || ny == y) && (nx != x || ny != y) && isok(nx, ny)) { typ = (crm = &levl[nx][ny])->typ; if(!IS_STWALL(typ) && !IS_POOL(typ)) { if(in_fcorridor(grd, nx, ny)) goto nextnxy; if(*in_rooms(nx,ny,VAULT)) continue; /* seems we found a good place to leave him alone */ egrd->gddone = 1; if(ACCESSIBLE(typ)) goto newpos; #ifdef STUPID if (typ == SCORR) crm->typ = CORR; else crm->typ = DOOR; #else crm->typ = (typ == SCORR) ? CORR : DOOR; #endif if(crm->typ == DOOR) crm->doormask = D_NODOOR; goto proceed; } } nextnxy: ; } nextpos: nx = x; ny = y; gx = egrd->gdx; gy = egrd->gdy; dx = (gx > x) ? 1 : (gx < x) ? -1 : 0; dy = (gy > y) ? 1 : (gy < y) ? -1 : 0; if(abs(gx-x) >= abs(gy-y)) nx += dx; else ny += dy; while((typ = (crm = &levl[nx][ny])->typ) != 0) { /* in view of the above we must have IS_WALL(typ) or typ == POOL */ /* must be a wall here */ if(isok(nx+nx-x,ny+ny-y) && !IS_POOL(typ) && IS_ROOM(levl[nx+nx-x][ny+ny-y].typ)){ crm->typ = DOOR; crm->doormask = D_NODOOR; goto proceed; } if(dy && nx != x) { nx = x; ny = y+dy; continue; } if(dx && ny != y) { ny = y; nx = x+dx; dy = 0; continue; } /* I don't like this, but ... */ if(IS_ROOM(typ)) { crm->typ = DOOR; crm->doormask = D_NODOOR; goto proceed; } break; } crm->typ = CORR; proceed: unblock_point(nx, ny); /* doesn't block light */ if (cansee(nx,ny)) newsym(nx,ny); fcp = &(egrd->fakecorr[egrd->fcend]); if(egrd->fcend++ == FCSIZ) panic("fakecorr overflow"); fcp->fx = nx; fcp->fy = ny; fcp->ftyp = typ; newpos: if(egrd->gddone) { /* The following is a kludge. We need to keep */ /* the guard around in order to be able to make */ /* the fake corridor disappear as the player */ /* moves out of it, but we also need the guard */ /* out of the way. We send the guard to never- */ /* never land. We set ogx ogy to mx my in order */ /* to avoid a check at the top of this function. */ /* At the end of the process, the guard is killed */ /* in restfakecorr(). */ cleanup: x = grd->mx; y = grd->my; see_guard = canspotmon(grd); wallify_vault(grd); remove_monster(grd->mx, grd->my); newsym(grd->mx,grd->my); place_monster(grd, 0, 0); egrd->ogx = grd->mx; egrd->ogy = grd->my; restfakecorr(grd); if(!semi_dead && (in_fcorridor(grd, u.ux, u.uy) || cansee(x, y))) { if (!disappear_msg_seen && see_guard) pline("Suddenly, the %s disappears.", g_monnam(grd)); return(1); } return(-2); } egrd->ogx = grd->mx; /* update old positions */ egrd->ogy = grd->my; remove_monster(grd->mx, grd->my); place_monster(grd, nx, ny); newsym(grd->mx,grd->my); restfakecorr(grd); return(1); } /* Routine when dying or quitting with a vault guard around */ void paygd() { register struct monst *grd = findgd(); #ifndef GOLDOBJ struct obj *gold; #else long umoney = money_cnt(invent); struct obj *coins, *nextcoins; #endif int gx,gy; char buf[BUFSZ]; #ifndef GOLDOBJ if (!u.ugold || !grd) return; #else if (!umoney || !grd) return; #endif if (u.uinvault) { Your("%ld %s goes into the Magic Memory Vault.", #ifndef GOLDOBJ u.ugold, currency(u.ugold)); #else umoney, currency(umoney)); #endif gx = u.ux; gy = u.uy; } else { if(grd->mpeaceful) { /* guard has no "right" to your gold */ mongone(grd); return; } mnexto(grd); pline("%s remits your gold to the vault.", Monnam(grd)); gx = rooms[EGD(grd)->vroom].lx + rn2(2); gy = rooms[EGD(grd)->vroom].ly + rn2(2); Sprintf(buf, "To Croesus: here's the gold recovered from %s the %s.", plname, mons[u.umonster].mname); make_grave(gx, gy, buf); } #ifndef GOLDOBJ place_object(gold = mkgoldobj(u.ugold), gx, gy); stackobj(gold); #else for (coins = invent; coins; coins = nextcoins) { nextcoins = coins->nobj; if (objects[coins->otyp].oc_class == COIN_CLASS) { freeinv(coins); place_object(coins, gx, gy); stackobj(coins); } } #endif mongone(grd); } long hidden_gold() { register long value = 0L; register struct obj *obj; for (obj = invent; obj; obj = obj->nobj) if (Has_contents(obj)) value += contained_gold(obj); /* unknown gold stuck inside statues may cause some consternation... */ return(value); } boolean gd_sound() /* prevent "You hear footsteps.." when inappropriate */ { register struct monst *grd = findgd(); if (vault_occupied(u.urooms)) return(FALSE); else return((boolean)(grd == (struct monst *)0)); } #endif /* OVLB */ /*vault.c*/ nethack-3.4.3/src/version.c0100644000000000000000000000727007764735041014300 0ustar rootroot/* SCCS Id: @(#)version.c 3.4 2003/12/06 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "date.h" /* * All the references to the contents of patchlevel.h have been moved * into makedefs.... */ #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif /* #define BETA_INFO "" */ /* "[ beta n]" */ /* fill buffer with short version (so caller can avoid including date.h) */ char * version_string(buf) char *buf; { return strcpy(buf, VERSION_STRING); } /* fill and return the given buffer with the long nethack version string */ char * getversionstring(buf) char *buf; { Strcpy(buf, VERSION_ID); #if defined(BETA) && defined(BETA_INFO) Sprintf(eos(buf), " %s", BETA_INFO); #endif #if defined(RUNTIME_PORT_ID) append_port_id(buf); #endif return buf; } int doversion() { char buf[BUFSZ]; pline("%s", getversionstring(buf)); return 0; } int doextversion() { display_file(OPTIONS_USED, TRUE); return 0; } #ifdef MICRO boolean comp_times(filetime) long filetime; { return((boolean)(filetime < BUILD_TIME)); } #endif boolean check_version(version_data, filename, complain) struct version_info *version_data; const char *filename; boolean complain; { if ( #ifdef VERSION_COMPATIBILITY version_data->incarnation < VERSION_COMPATIBILITY || version_data->incarnation > VERSION_NUMBER #else version_data->incarnation != VERSION_NUMBER #endif ) { if (complain) pline("Version mismatch for file \"%s\".", filename); return FALSE; } else if ( #ifndef IGNORED_FEATURES version_data->feature_set != VERSION_FEATURES || #else (version_data->feature_set & ~IGNORED_FEATURES) != (VERSION_FEATURES & ~IGNORED_FEATURES) || #endif version_data->entity_count != VERSION_SANITY1 || version_data->struct_sizes != VERSION_SANITY2) { if (complain) pline("Configuration incompatibility for file \"%s\".", filename); return FALSE; } return TRUE; } /* this used to be based on file date and somewhat OS-dependant, but now examines the initial part of the file's contents */ boolean uptodate(fd, name) int fd; const char *name; { int rlen; struct version_info vers_info; boolean verbose = name ? TRUE : FALSE; rlen = read(fd, (genericptr_t) &vers_info, sizeof vers_info); minit(); /* ZEROCOMP */ if (rlen == 0) { if (verbose) { pline("File \"%s\" is empty?", name); wait_synch(); } return FALSE; } if (!check_version(&vers_info, name, verbose)) { if (verbose) wait_synch(); return FALSE; } return TRUE; } void store_version(fd) int fd; { const static struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2 }; bufoff(fd); /* bwrite() before bufon() uses plain write() */ bwrite(fd,(genericptr_t)&version_data,(unsigned)(sizeof version_data)); bufon(fd); return; } #ifdef AMIGA const char amiga_version_string[] = AMIGA_VERSION_STRING; #endif unsigned long get_feature_notice_ver(str) char *str; { char buf[BUFSZ]; int ver_maj, ver_min, patch; char *istr[3]; int j = 0; if (!str) return 0L; str = strcpy(buf, str); istr[j] = str; while (*str) { if (*str == '.') { *str++ = '\0'; j++; istr[j] = str; if (j == 2) break; } else if (index("0123456789", *str) != 0) { str++; } else return 0L; } if (j != 2) return 0L; ver_maj = atoi(istr[0]); ver_min = atoi(istr[1]); patch = atoi(istr[2]); return FEATURE_NOTICE_VER(ver_maj,ver_min,patch); /* macro from hack.h */ } unsigned long get_current_feature_ver() { return FEATURE_NOTICE_VER(VERSION_MAJOR,VERSION_MINOR,PATCHLEVEL); } /*version.c*/ nethack-3.4.3/src/vision.c0100644000000000000000000022262307764735041014123 0ustar rootroot/* SCCS Id: @(#)vision.c 3.4 1999/02/18 */ /* Copyright (c) Dean Luick, with acknowledgements to Dave Cohrs, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* Circles ==================================================================*/ /* * These numbers are limit offsets for one quadrant of a circle of a given * radius (the first number of each line) from the source. The number in * the comment is the element number (so pointers can be set up). Each * "circle" has as many elements as its radius+1. The radius is the number * of points away from the source that the limit exists. The radius of the * offset on the same row as the source *is* included so we don't have to * make an extra check. For example, a circle of radius 4 has offsets: * * XXX +2 * ...X +3 * ....X +4 * ....X +4 * @...X +4 * */ char circle_data[] = { /* 0*/ 1, 1, /* 2*/ 2, 2, 1, /* 5*/ 3, 3, 2, 1, /* 9*/ 4, 4, 4, 3, 2, /* 14*/ 5, 5, 5, 4, 3, 2, /* 20*/ 6, 6, 6, 5, 5, 4, 2, /* 27*/ 7, 7, 7, 6, 6, 5, 4, 2, /* 35*/ 8, 8, 8, 7, 7, 6, 6, 4, 2, /* 44*/ 9, 9, 9, 9, 8, 8, 7, 6, 5, 3, /* 54*/ 10,10,10,10, 9, 9, 8, 7, 6, 5, 3, /* 65*/ 11,11,11,11,10,10, 9, 9, 8, 7, 5, 3, /* 77*/ 12,12,12,12,11,11,10,10, 9, 8, 7, 5, 3, /* 90*/ 13,13,13,13,12,12,12,11,10,10, 9, 7, 6, 3, /*104*/ 14,14,14,14,13,13,13,12,12,11,10, 9, 8, 6, 3, /*119*/ 15,15,15,15,14,14,14,13,13,12,11,10, 9, 8, 6, 3, /*135*/ 16 /* should be MAX_RADIUS+1; used to terminate range loops -dlc */ }; /* * These are the starting indexes into the circle_data[] array for a * circle of a given radius. */ char circle_start[] = { /* */ 0, /* circles of radius zero are not used */ /* 1*/ 0, /* 2*/ 2, /* 3*/ 5, /* 4*/ 9, /* 5*/ 14, /* 6*/ 20, /* 7*/ 27, /* 8*/ 35, /* 9*/ 44, /*10*/ 54, /*11*/ 65, /*12*/ 77, /*13*/ 90, /*14*/ 104, /*15*/ 119, }; /*===========================================================================*/ /* Vision (arbitrary line of sight) =========================================*/ /*------ global variables ------*/ #if 0 /* (moved to decl.c) */ /* True if we need to run a full vision recalculation. */ boolean vision_full_recalc = 0; /* Pointers to the current vision array. */ char **viz_array; #endif char *viz_rmin, *viz_rmax; /* current vision cs bounds */ /*------ local variables ------*/ static char could_see[2][ROWNO][COLNO]; /* vision work space */ static char *cs_rows0[ROWNO], *cs_rows1[ROWNO]; static char cs_rmin0[ROWNO], cs_rmax0[ROWNO]; static char cs_rmin1[ROWNO], cs_rmax1[ROWNO]; static char viz_clear[ROWNO][COLNO]; /* vision clear/blocked map */ static char *viz_clear_rows[ROWNO]; static char left_ptrs[ROWNO][COLNO]; /* LOS algorithm helpers */ static char right_ptrs[ROWNO][COLNO]; /* Forward declarations. */ STATIC_DCL void FDECL(fill_point, (int,int)); STATIC_DCL void FDECL(dig_point, (int,int)); STATIC_DCL void NDECL(view_init); STATIC_DCL void FDECL(view_from,(int,int,char **,char *,char *,int, void (*)(int,int,genericptr_t),genericptr_t)); STATIC_DCL void FDECL(get_unused_cs, (char ***,char **,char **)); #ifdef REINCARNATION STATIC_DCL void FDECL(rogue_vision, (char **,char *,char *)); #endif /* Macro definitions that I can't find anywhere. */ #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0 )) #define v_abs(z) ((z) < 0 ? -(z) : (z)) /* don't use abs -- it may exist */ /* * vision_init() * * The one-time vision initialization routine. * * This must be called before mklev() is called in newgame() [allmain.c], * or before a game restore. Else we die a horrible death. */ void vision_init() { int i; /* Set up the pointers. */ for (i = 0; i < ROWNO; i++) { cs_rows0[i] = could_see[0][i]; cs_rows1[i] = could_see[1][i]; viz_clear_rows[i] = viz_clear[i]; } /* Start out with cs0 as our current array */ viz_array = cs_rows0; viz_rmin = cs_rmin0; viz_rmax = cs_rmax0; vision_full_recalc = 0; (void) memset((genericptr_t) could_see, 0, sizeof(could_see)); /* Initialize the vision algorithm (currently C or D). */ view_init(); #ifdef VISION_TABLES /* Note: this initializer doesn't do anything except guarantee that we're linked properly. */ vis_tab_init(); #endif } /* * does_block() * * Returns true if the level feature, object, or monster at (x,y) blocks * sight. */ int does_block(x,y,lev) int x, y; register struct rm *lev; { struct obj *obj; struct monst *mon; /* Features that block . . */ if (IS_ROCK(lev->typ) || lev->typ == TREE || (IS_DOOR(lev->typ) && (lev->doormask & (D_CLOSED|D_LOCKED|D_TRAPPED) ))) return 1; if (lev->typ == CLOUD || lev->typ == WATER || (lev->typ == MOAT && Underwater)) return 1; /* Boulders block light. */ for (obj = level.objects[x][y]; obj; obj = obj->nexthere) if (obj->otyp == BOULDER) return 1; /* Mimics mimicing a door or boulder block light. */ if ((mon = m_at(x,y)) && (!mon->minvis || See_invisible) && ((mon->m_ap_type == M_AP_FURNITURE && (mon->mappearance == S_hcdoor || mon->mappearance == S_vcdoor)) || (mon->m_ap_type == M_AP_OBJECT && mon->mappearance == BOULDER))) return 1; return 0; } /* * vision_reset() * * This must be called *after* the levl[][] structure is set with the new * level and the level monsters and objects are in place. */ void vision_reset() { int y; register int x, i, dig_left, block; register struct rm *lev; /* Start out with cs0 as our current array */ viz_array = cs_rows0; viz_rmin = cs_rmin0; viz_rmax = cs_rmax0; (void) memset((genericptr_t) could_see, 0, sizeof(could_see)); /* Reset the pointers and clear so that we have a "full" dungeon. */ (void) memset((genericptr_t) viz_clear, 0, sizeof(viz_clear)); /* Dig the level */ for (y = 0; y < ROWNO; y++) { dig_left = 0; block = TRUE; /* location (0,y) is always stone; it's !isok() */ lev = &levl[1][y]; for (x = 1; x < COLNO; x++, lev += ROWNO) if (block != (IS_ROCK(lev->typ) || does_block(x,y,lev))) { if(block) { for(i=dig_left; i= 0) { for (zy = rooms[rnum].ly-1; zy <= rooms[rnum].hy+1; zy++) { rmin[zy] = start = rooms[rnum].lx-1; rmax[zy] = stop = rooms[rnum].hx+1; for (zx = start; zx <= stop; zx++) { if (rooms[rnum].rlit) { next[zy][zx] = COULD_SEE | IN_SIGHT; levl[zx][zy].seenv = SVALL; /* see the walls */ } else next[zy][zx] = COULD_SEE; } } } in_door = levl[u.ux][u.uy].typ == DOOR; /* Can always see adjacent. */ ylo = max(u.uy - 1, 0); yhi = min(u.uy + 1, ROWNO - 1); xlo = max(u.ux - 1, 1); xhi = min(u.ux + 1, COLNO - 1); for (zy = ylo; zy <= yhi; zy++) { if (xlo < rmin[zy]) rmin[zy] = xlo; if (xhi > rmax[zy]) rmax[zy] = xhi; for (zx = xlo; zx <= xhi; zx++) { next[zy][zx] = COULD_SEE | IN_SIGHT; /* * Yuck, update adjacent non-diagonal positions when in a doorway. * We need to do this to catch the case when we first step into * a room. The room's walls were not seen from the outside, but * now are seen (the seen bits are set just above). However, the * positions are not updated because they were already in sight. * So, we have to do it here. */ if (in_door && (zx == u.ux || zy == u.uy)) newsym(zx,zy); } } } #endif /* REINCARNATION */ /*#define EXTEND_SPINE*/ /* possibly better looking wall-angle */ #ifdef EXTEND_SPINE STATIC_DCL int FDECL(new_angle, (struct rm *, unsigned char *, int, int)); /* * new_angle() * * Return the new angle seen by the hero for this location. The angle * bit is given in the value pointed at by sv. * * For T walls and crosswall, just setting the angle bit, even though * it is technically correct, doesn't look good. If we can see the * next position beyond the current one and it is a wall that we can * see, then we want to extend a spine of the T to connect with the wall * that is beyond. Example: * * Correct, but ugly Extend T spine * * | ... | ... * | ... <-- wall beyond & floor --> | ... * | ... | ... * Unseen --> ... | ... * spine +-... <-- trwall & doorway --> +-... * | ... | ... * * * @ <-- hero --> @ * * * We fake the above check by only checking if the horizontal & * vertical positions adjacent to the crosswall and T wall are * unblocked. Then, _in general_ we can see beyond. Generally, * this is good enough. * * + When this function is called we don't have all of the seen * information (we're doing a top down scan in vision_recalc). * We would need to scan once to set all IN_SIGHT and COULD_SEE * bits, then again to correctly set the seenv bits. * + I'm trying to make this as cheap as possible. The display & * vision eat up too much CPU time. * * * Note: Even as I write this, I'm still not convinced. There are too * many exceptions. I may have to bite the bullet and do more * checks. - Dean 2/11/93 */ STATIC_OVL int new_angle(lev, sv, row, col) struct rm *lev; unsigned char *sv; int row, col; { register int res = *sv; /* * Do extra checks for crosswalls and T walls if we see them from * an angle. */ if (lev->typ >= CROSSWALL && lev->typ <= TRWALL) { switch (res) { case SV0: if (col > 0 && viz_clear[row][col-1]) res |= SV7; if (row > 0 && viz_clear[row-1][col]) res |= SV1; break; case SV2: if (row > 0 && viz_clear[row-1][col]) res |= SV1; if (col < COLNO-1 && viz_clear[row][col+1]) res |= SV3; break; case SV4: if (col < COLNO-1 && viz_clear[row][col+1]) res |= SV3; if (row < ROWNO-1 && viz_clear[row+1][col]) res |= SV5; break; case SV6: if (row < ROWNO-1 && viz_clear[row+1][col]) res |= SV5; if (col > 0 && viz_clear[row][col-1]) res |= SV7; break; } } return res; } #else /* * new_angle() * * Return the new angle seen by the hero for this location. The angle * bit is given in the value pointed at by sv. * * The other parameters are not used. */ #define new_angle(lev, sv, row, col) (*sv) #endif /* * vision_recalc() * * Do all of the heavy vision work. Recalculate all locations that could * possibly be seen by the hero --- if the location were lit, etc. Note * which locations are actually seen because of lighting. Then add to * this all locations that be seen by hero due to night vision and x-ray * vision. Finally, compare with what the hero was able to see previously. * Update the difference. * * This function is usually called only when the variable 'vision_full_recalc' * is set. The following is a list of places where this function is called, * with three valid values for the control flag parameter: * * Control flag = 0. A complete vision recalculation. Generate the vision * tables from scratch. This is necessary to correctly set what the hero * can see. (1) and (2) call this routine for synchronization purposes, (3) * calls this routine so it can operate correctly. * * + After the monster move, before input from the player. [moveloop()] * + At end of moveloop. [moveloop() ??? not sure why this is here] * + Right before something is printed. [pline()] * + Right before we do a vision based operation. [do_clear_area()] * + screen redraw, so we can renew all positions in sight. [docrt()] * * Control flag = 1. An adjacent vision recalculation. The hero has moved * one square. Knowing this, it might be possible to optimize the vision * recalculation using the current knowledge. This is presently unimplemented * and is treated as a control = 0 call. * * + Right after the hero moves. [domove()] * * Control flag = 2. Turn off the vision system. Nothing new will be * displayed, since nothing is seen. This is usually done when you need * a newsym() run on all locations in sight, or on some locations but you * don't know which ones. * * + Before a screen redraw, so all positions are renewed. [docrt()] * + Right before the hero arrives on a new level. [goto_level()] * + Right after a scroll of light is read. [litroom()] * + After an option has changed that affects vision [parseoptions()] * + Right after the hero is swallowed. [gulpmu()] * + Just before bubbles are moved. [movebubbles()] */ void vision_recalc(control) int control; { char **temp_array; /* points to the old vision array */ char **next_array; /* points to the new vision array */ char *next_row; /* row pointer for the new array */ char *old_row; /* row pointer for the old array */ char *next_rmin; /* min pointer for the new array */ char *next_rmax; /* max pointer for the new array */ char *ranges; /* circle ranges -- used for xray & night vision */ int row; /* row counter (outer loop) */ int start, stop; /* inner loop starting/stopping index */ int dx, dy; /* one step from a lit door or lit wall (see below) */ register int col; /* inner loop counter */ register struct rm *lev; /* pointer to current pos */ struct rm *flev; /* pointer to position in "front" of current pos */ extern unsigned char seenv_matrix[3][3]; /* from display.c */ static unsigned char colbump[COLNO+1]; /* cols to bump sv */ unsigned char *sv; /* ptr to seen angle bits */ int oldseenv; /* previous seenv value */ vision_full_recalc = 0; /* reset flag */ if (in_mklev || !iflags.vision_inited) return; #ifdef GCC_WARN row = 0; #endif /* * Either the light sources have been taken care of, or we must * recalculate them here. */ /* Get the unused could see, row min, and row max arrays. */ get_unused_cs(&next_array, &next_rmin, &next_rmax); /* You see nothing, nothing can see you --- if swallowed or refreshing. */ if (u.uswallow || control == 2) { /* do nothing -- get_unused_cs() nulls out the new work area */ } else if (Blind) { /* * Calculate the could_see array even when blind so that monsters * can see you, even if you can't see them. Note that the current * setup allows: * * + Monsters to see with the "new" vision, even on the rogue * level. * * + Monsters can see you even when you're in a pit. */ view_from(u.uy, u.ux, next_array, next_rmin, next_rmax, 0, (void FDECL((*),(int,int,genericptr_t)))0, (genericptr_t)0); /* * Our own version of the update loop below. We know we can't see * anything, so we only need update positions we used to be able * to see. */ temp_array = viz_array; /* set viz_array so newsym() will work */ viz_array = next_array; for (row = 0; row < ROWNO; row++) { old_row = temp_array[row]; /* Find the min and max positions on the row. */ start = min(viz_rmin[row], next_rmin[row]); stop = max(viz_rmax[row], next_rmax[row]); for (col = start; col <= stop; col++) if (old_row[col] & IN_SIGHT) newsym(col,row); } /* skip the normal update loop */ goto skip; } #ifdef REINCARNATION else if (Is_rogue_level(&u.uz)) { rogue_vision(next_array,next_rmin,next_rmax); } #endif else { int has_night_vision = 1; /* hero has night vision */ if (Underwater && !Is_waterlevel(&u.uz)) { /* * The hero is under water. Only see surrounding locations if * they are also underwater. This overrides night vision but * does not override x-ray vision. */ has_night_vision = 0; for (row = u.uy-1; row <= u.uy+1; row++) for (col = u.ux-1; col <= u.ux+1; col++) { if (!isok(col,row) || !is_pool(col,row)) continue; next_rmin[row] = min(next_rmin[row], col); next_rmax[row] = max(next_rmax[row], col); next_array[row][col] = IN_SIGHT | COULD_SEE; } } /* if in a pit, just update for immediate locations */ else if (u.utrap && u.utraptype == TT_PIT) { for (row = u.uy-1; row <= u.uy+1; row++) { if (row < 0) continue; if (row >= ROWNO) break; next_rmin[row] = max( 0, u.ux - 1); next_rmax[row] = min(COLNO-1, u.ux + 1); next_row = next_array[row]; for(col=next_rmin[row]; col <= next_rmax[row]; col++) next_row[col] = IN_SIGHT | COULD_SEE; } } else view_from(u.uy, u.ux, next_array, next_rmin, next_rmax, 0, (void FDECL((*),(int,int,genericptr_t)))0, (genericptr_t)0); /* * Set the IN_SIGHT bit for xray and night vision. */ if (u.xray_range >= 0) { if (u.xray_range) { ranges = circle_ptr(u.xray_range); for (row = u.uy-u.xray_range; row <= u.uy+u.xray_range; row++) { if (row < 0) continue; if (row >= ROWNO) break; dy = v_abs(u.uy-row); next_row = next_array[row]; start = max( 0, u.ux - ranges[dy]); stop = min(COLNO-1, u.ux + ranges[dy]); for (col = start; col <= stop; col++) { char old_row_val = next_row[col]; next_row[col] |= IN_SIGHT; oldseenv = levl[col][row].seenv; levl[col][row].seenv = SVALL; /* see all! */ /* Update if previously not in sight or new angle. */ if (!(old_row_val & IN_SIGHT) || oldseenv != SVALL) newsym(col,row); } next_rmin[row] = min(start, next_rmin[row]); next_rmax[row] = max(stop, next_rmax[row]); } } else { /* range is 0 */ next_array[u.uy][u.ux] |= IN_SIGHT; levl[u.ux][u.uy].seenv = SVALL; next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]); next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]); } } if (has_night_vision && u.xray_range < u.nv_range) { if (!u.nv_range) { /* range is 0 */ next_array[u.uy][u.ux] |= IN_SIGHT; levl[u.ux][u.uy].seenv = SVALL; next_rmin[u.uy] = min(u.ux, next_rmin[u.uy]); next_rmax[u.uy] = max(u.ux, next_rmax[u.uy]); } else if (u.nv_range > 0) { ranges = circle_ptr(u.nv_range); for (row = u.uy-u.nv_range; row <= u.uy+u.nv_range; row++) { if (row < 0) continue; if (row >= ROWNO) break; dy = v_abs(u.uy-row); next_row = next_array[row]; start = max( 0, u.ux - ranges[dy]); stop = min(COLNO-1, u.ux + ranges[dy]); for (col = start; col <= stop; col++) if (next_row[col]) next_row[col] |= IN_SIGHT; next_rmin[row] = min(start, next_rmin[row]); next_rmax[row] = max(stop, next_rmax[row]); } } } } /* Set the correct bits for all light sources. */ do_light_sources(next_array); /* * Make the viz_array the new array so that cansee() will work correctly. */ temp_array = viz_array; viz_array = next_array; /* * The main update loop. Here we do two things: * * + Set the IN_SIGHT bit for places that we could see and are lit. * + Reset changed places. * * There is one thing that make deciding what the hero can see * difficult: * * 1. Directional lighting. Items that block light create problems. * The worst offenders are doors. Suppose a door to a lit room * is closed. It is lit on one side, but not on the other. How * do you know? You have to check the closest adjacent position. * Even so, that is not entirely correct. But it seems close * enough for now. */ colbump[u.ux] = colbump[u.ux+1] = 1; for (row = 0; row < ROWNO; row++) { dy = u.uy - row; dy = sign(dy); next_row = next_array[row]; old_row = temp_array[row]; /* Find the min and max positions on the row. */ start = min(viz_rmin[row], next_rmin[row]); stop = max(viz_rmax[row], next_rmax[row]); lev = &levl[start][row]; sv = &seenv_matrix[dy+1][start < u.ux ? 0 : (start > u.ux ? 2:1)]; for (col = start; col <= stop; lev += ROWNO, sv += (int) colbump[++col]) { if (next_row[col] & IN_SIGHT) { /* * We see this position because of night- or xray-vision. */ oldseenv = lev->seenv; lev->seenv |= new_angle(lev,sv,row,col); /* update seen angle */ /* Update pos if previously not in sight or new angle. */ if ( !(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv) newsym(col,row); } else if ((next_row[col] & COULD_SEE) && (lev->lit || (next_row[col] & TEMP_LIT))) { /* * We see this position because it is lit. */ if ((IS_DOOR(lev->typ) || lev->typ == SDOOR || IS_WALL(lev->typ)) && !viz_clear[row][col]) { /* * Make sure doors, walls, boulders or mimics don't show up * at the end of dark hallways. We do this by checking * the adjacent position. If it is lit, then we can see * the door or wall, otherwise we can't. */ dx = u.ux - col; dx = sign(dx); flev = &(levl[col+dx][row+dy]); if (flev->lit || next_array[row+dy][col+dx] & TEMP_LIT) { next_row[col] |= IN_SIGHT; /* we see it */ oldseenv = lev->seenv; lev->seenv |= new_angle(lev,sv,row,col); /* Update pos if previously not in sight or new angle.*/ if (!(old_row[col] & IN_SIGHT) || oldseenv!=lev->seenv) newsym(col,row); } else goto not_in_sight; /* we don't see it */ } else { next_row[col] |= IN_SIGHT; /* we see it */ oldseenv = lev->seenv; lev->seenv |= new_angle(lev,sv,row,col); /* Update pos if previously not in sight or new angle. */ if ( !(old_row[col] & IN_SIGHT) || oldseenv != lev->seenv) newsym(col,row); } } else if ((next_row[col] & COULD_SEE) && lev->waslit) { /* * If we make it here, the hero _could see_ the location, * but doesn't see it (location is not lit). * However, the hero _remembers_ it as lit (waslit is true). * The hero can now see that it is not lit, so change waslit * and update the location. */ lev->waslit = 0; /* remember lit condition */ newsym(col,row); } /* * At this point we know that the row position is *not* in normal * sight. That is, the position is could be seen, but is dark * or LOS is just plain blocked. * * Update the position if: * o If the old one *was* in sight. We may need to clean up * the glyph -- E.g. darken room spot, etc. * o If we now could see the location (yet the location is not * lit), but previously we couldn't see the location, or vice * versa. Update the spot because there there may be an infared * monster there. */ else { not_in_sight: if ((old_row[col] & IN_SIGHT) || ((next_row[col] & COULD_SEE) ^ (old_row[col] & COULD_SEE))) newsym(col,row); } } /* end for col . . */ } /* end for row . . */ colbump[u.ux] = colbump[u.ux+1] = 0; skip: /* This newsym() caused a crash delivering msg about failure to open * dungeon file init_dungeons() -> panic() -> done(11) -> * vision_recalc(2) -> newsym() -> crash! u.ux and u.uy are 0 and * program_state.panicking == 1 under those circumstances */ if (!program_state.panicking) newsym(u.ux, u.uy); /* Make sure the hero shows up! */ /* Set the new min and max pointers. */ viz_rmin = next_rmin; viz_rmax = next_rmax; } /* * block_point() * * Make the location opaque to light. */ void block_point(x,y) int x, y; { fill_point(y,x); /* recalc light sources here? */ /* * We have to do a full vision recalculation if we "could see" the * location. Why? Suppose some monster opened a way so that the * hero could see a lit room. However, the position of the opening * was out of night-vision range of the hero. Suddenly the hero should * see the lit room. */ if (viz_array[y][x]) vision_full_recalc = 1; } /* * unblock_point() * * Make the location transparent to light. */ void unblock_point(x,y) int x, y; { dig_point(y,x); /* recalc light sources here? */ if (viz_array[y][x]) vision_full_recalc = 1; } /*===========================================================================*\ | | | Everything below this line uses (y,x) instead of (x,y) --- the | | algorithms are faster if they are less recursive and can scan | | on a row longer. | | | \*===========================================================================*/ /* ========================================================================= *\ Left and Right Pointer Updates \* ========================================================================= */ /* * LEFT and RIGHT pointer rules * * * **NOTE** The rules changed on 4/4/90. This comment reflects the * new rules. The change was so that the stone-wall optimization * would work. * * OK, now the tough stuff. We must maintain our left and right * row pointers. The rules are as follows: * * Left Pointers: * ______________ * * + If you are a clear spot, your left will point to the first * stone to your left. If there is none, then point the first * legal position in the row (0). * * + If you are a blocked spot, then your left will point to the * left-most blocked spot to your left that is connected to you. * This means that a left-edge (a blocked spot that has an open * spot on its left) will point to itself. * * * Right Pointers: * --------------- * + If you are a clear spot, your right will point to the first * stone to your right. If there is none, then point the last * legal position in the row (COLNO-1). * * + If you are a blocked spot, then your right will point to the * right-most blocked spot to your right that is connected to you. * This means that a right-edge (a blocked spot that has an open * spot on its right) will point to itself. */ STATIC_OVL void dig_point(row,col) int row,col; { int i; if (viz_clear[row][col]) return; /* already done */ viz_clear[row][col] = 1; /* * Boundary cases first. */ if (col == 0) { /* left edge */ if (viz_clear[row][1]) { right_ptrs[row][0] = right_ptrs[row][1]; } else { right_ptrs[row][0] = 1; for (i = 1; i <= right_ptrs[row][1]; i++) left_ptrs[row][i] = 1; } } else if (col == (COLNO-1)) { /* right edge */ if (viz_clear[row][COLNO-2]) { left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2]; } else { left_ptrs[row][COLNO-1] = COLNO-2; for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++) right_ptrs[row][i] = COLNO-2; } } /* * At this point, we know we aren't on the boundaries. */ else if (viz_clear[row][col-1] && viz_clear[row][col+1]) { /* Both sides clear */ for (i = left_ptrs[row][col-1]; i <= col; i++) { if (!viz_clear[row][i]) continue; /* catch non-end case */ right_ptrs[row][i] = right_ptrs[row][col+1]; } for (i = col; i <= right_ptrs[row][col+1]; i++) { if (!viz_clear[row][i]) continue; /* catch non-end case */ left_ptrs[row][i] = left_ptrs[row][col-1]; } } else if (viz_clear[row][col-1]) { /* Left side clear, right side blocked. */ for (i = col+1; i <= right_ptrs[row][col+1]; i++) left_ptrs[row][i] = col+1; for (i = left_ptrs[row][col-1]; i <= col; i++) { if (!viz_clear[row][i]) continue; /* catch non-end case */ right_ptrs[row][i] = col+1; } left_ptrs[row][col] = left_ptrs[row][col-1]; } else if (viz_clear[row][col+1]) { /* Right side clear, left side blocked. */ for (i = left_ptrs[row][col-1]; i < col; i++) right_ptrs[row][i] = col-1; for (i = col; i <= right_ptrs[row][col+1]; i++) { if (!viz_clear[row][i]) continue; /* catch non-end case */ left_ptrs[row][i] = col-1; } right_ptrs[row][col] = right_ptrs[row][col+1]; } else { /* Both sides blocked */ for (i = left_ptrs[row][col-1]; i < col; i++) right_ptrs[row][i] = col-1; for (i = col+1; i <= right_ptrs[row][col+1]; i++) left_ptrs[row][i] = col+1; left_ptrs[row][col] = col-1; right_ptrs[row][col] = col+1; } } STATIC_OVL void fill_point(row,col) int row, col; { int i; if (!viz_clear[row][col]) return; viz_clear[row][col] = 0; if (col == 0) { if (viz_clear[row][1]) { /* adjacent is clear */ right_ptrs[row][0] = 0; } else { right_ptrs[row][0] = right_ptrs[row][1]; for (i = 1; i <= right_ptrs[row][1]; i++) left_ptrs[row][i] = 0; } } else if (col == COLNO-1) { if (viz_clear[row][COLNO-2]) { /* adjacent is clear */ left_ptrs[row][COLNO-1] = COLNO-1; } else { left_ptrs[row][COLNO-1] = left_ptrs[row][COLNO-2]; for (i = left_ptrs[row][COLNO-2]; i < COLNO-1; i++) right_ptrs[row][i] = COLNO-1; } } /* * Else we know that we are not on an edge. */ else if (viz_clear[row][col-1] && viz_clear[row][col+1]) { /* Both sides clear */ for (i = left_ptrs[row][col-1]+1; i <= col; i++) right_ptrs[row][i] = col; if (!left_ptrs[row][col-1]) /* catch the end case */ right_ptrs[row][0] = col; for (i = col; i < right_ptrs[row][col+1]; i++) left_ptrs[row][i] = col; if (right_ptrs[row][col+1] == COLNO-1) /* catch the end case */ left_ptrs[row][COLNO-1] = col; } else if (viz_clear[row][col-1]) { /* Left side clear, right side blocked. */ for (i = col; i <= right_ptrs[row][col+1]; i++) left_ptrs[row][i] = col; for (i = left_ptrs[row][col-1]+1; i < col; i++) right_ptrs[row][i] = col; if (!left_ptrs[row][col-1]) /* catch the end case */ right_ptrs[row][i] = col; right_ptrs[row][col] = right_ptrs[row][col+1]; } else if (viz_clear[row][col+1]) { /* Right side clear, left side blocked. */ for (i = left_ptrs[row][col-1]; i <= col; i++) right_ptrs[row][i] = col; for (i = col+1; i < right_ptrs[row][col+1]; i++) left_ptrs[row][i] = col; if (right_ptrs[row][col+1] == COLNO-1) /* catch the end case */ left_ptrs[row][i] = col; left_ptrs[row][col] = left_ptrs[row][col-1]; } else { /* Both sides blocked */ for (i = left_ptrs[row][col-1]; i <= col; i++) right_ptrs[row][i] = right_ptrs[row][col+1]; for (i = col; i <= right_ptrs[row][col+1]; i++) left_ptrs[row][i] = left_ptrs[row][col-1]; } } /*===========================================================================*/ /*===========================================================================*/ /* Use either algorithm C or D. See the config.h for more details. =========*/ /* * Variables local to both Algorithms C and D. */ static int start_row; static int start_col; static int step; static char **cs_rows; static char *cs_left; static char *cs_right; static void FDECL((*vis_func), (int,int,genericptr_t)); static genericptr_t varg; /* * Both Algorithms C and D use the following macros. * * good_row(z) - Return TRUE if the argument is a legal row. * set_cs(rowp,col) - Set the local could see array. * set_min(z) - Save the min value of the argument and the current * row minimum. * set_max(z) - Save the max value of the argument and the current * row maximum. * * The last three macros depend on having local pointers row_min, row_max, * and rowp being set correctly. */ #define set_cs(rowp,col) (rowp[col] = COULD_SEE) #define good_row(z) ((z) >= 0 && (z) < ROWNO) #define set_min(z) if (*row_min > (z)) *row_min = (z) #define set_max(z) if (*row_max < (z)) *row_max = (z) #define is_clear(row,col) viz_clear_rows[row][col] /* * clear_path() expanded into 4 macros/functions: * * q1_path() * q2_path() * q3_path() * q4_path() * * "Draw" a line from the start to the given location. Stop if we hit * something that blocks light. The start and finish points themselves are * not checked, just the points between them. These routines do _not_ * expect to be called with the same starting and stopping point. * * These routines use the generalized integer Bresenham's algorithm (fast * line drawing) for all quadrants. The algorithm was taken from _Procedural * Elements for Computer Graphics_, by David F. Rogers. McGraw-Hill, 1985. */ #ifdef MACRO_CPATH /* quadrant calls are macros */ /* * When called, the result is in "result". * The first two arguments (srow,scol) are one end of the path. The next * two arguments (row,col) are the destination. The last argument is * used as a C language label. This means that it must be different * in each pair of calls. */ /* * Quadrant I (step < 0). */ #define q1_path(srow,scol,y2,x2,label) \ { \ int dx, dy; \ register int k, err, x, y, dxs, dys; \ \ x = (scol); y = (srow); \ dx = (x2) - x; dy = y - (y2); \ \ result = 0; /* default to a blocked path */\ \ dxs = dx << 1; /* save the shifted values */\ dys = dy << 1; \ if (dy > dx) { \ err = dxs - dy; \ \ for (k = dy-1; k; k--) { \ if (err >= 0) { \ x++; \ err -= dys; \ } \ y--; \ err += dxs; \ if (!is_clear(y,x)) goto label;/* blocked */\ } \ } else { \ err = dys - dx; \ \ for (k = dx-1; k; k--) { \ if (err >= 0) { \ y--; \ err -= dxs; \ } \ x++; \ err += dys; \ if (!is_clear(y,x)) goto label;/* blocked */\ } \ } \ \ result = 1; \ } /* * Quadrant IV (step > 0). */ #define q4_path(srow,scol,y2,x2,label) \ { \ int dx, dy; \ register int k, err, x, y, dxs, dys; \ \ x = (scol); y = (srow); \ dx = (x2) - x; dy = (y2) - y; \ \ result = 0; /* default to a blocked path */\ \ dxs = dx << 1; /* save the shifted values */\ dys = dy << 1; \ if (dy > dx) { \ err = dxs - dy; \ \ for (k = dy-1; k; k--) { \ if (err >= 0) { \ x++; \ err -= dys; \ } \ y++; \ err += dxs; \ if (!is_clear(y,x)) goto label;/* blocked */\ } \ \ } else { \ err = dys - dx; \ \ for (k = dx-1; k; k--) { \ if (err >= 0) { \ y++; \ err -= dxs; \ } \ x++; \ err += dys; \ if (!is_clear(y,x)) goto label;/* blocked */\ } \ } \ \ result = 1; \ } /* * Quadrant II (step < 0). */ #define q2_path(srow,scol,y2,x2,label) \ { \ int dx, dy; \ register int k, err, x, y, dxs, dys; \ \ x = (scol); y = (srow); \ dx = x - (x2); dy = y - (y2); \ \ result = 0; /* default to a blocked path */\ \ dxs = dx << 1; /* save the shifted values */\ dys = dy << 1; \ if (dy > dx) { \ err = dxs - dy; \ \ for (k = dy-1; k; k--) { \ if (err >= 0) { \ x--; \ err -= dys; \ } \ y--; \ err += dxs; \ if (!is_clear(y,x)) goto label;/* blocked */\ } \ } else { \ err = dys - dx; \ \ for (k = dx-1; k; k--) { \ if (err >= 0) { \ y--; \ err -= dxs; \ } \ x--; \ err += dys; \ if (!is_clear(y,x)) goto label;/* blocked */\ } \ } \ \ result = 1; \ } /* * Quadrant III (step > 0). */ #define q3_path(srow,scol,y2,x2,label) \ { \ int dx, dy; \ register int k, err, x, y, dxs, dys; \ \ x = (scol); y = (srow); \ dx = x - (x2); dy = (y2) - y; \ \ result = 0; /* default to a blocked path */\ \ dxs = dx << 1; /* save the shifted values */\ dys = dy << 1; \ if (dy > dx) { \ err = dxs - dy; \ \ for (k = dy-1; k; k--) { \ if (err >= 0) { \ x--; \ err -= dys; \ } \ y++; \ err += dxs; \ if (!is_clear(y,x)) goto label;/* blocked */\ } \ \ } else { \ err = dys - dx; \ \ for (k = dx-1; k; k--) { \ if (err >= 0) { \ y++; \ err -= dxs; \ } \ x--; \ err += dys; \ if (!is_clear(y,x)) goto label;/* blocked */\ } \ } \ \ result = 1; \ } #else /* quadrants are really functions */ STATIC_DCL int FDECL(_q1_path, (int,int,int,int)); STATIC_DCL int FDECL(_q2_path, (int,int,int,int)); STATIC_DCL int FDECL(_q3_path, (int,int,int,int)); STATIC_DCL int FDECL(_q4_path, (int,int,int,int)); #define q1_path(sy,sx,y,x,dummy) result = _q1_path(sy,sx,y,x) #define q2_path(sy,sx,y,x,dummy) result = _q2_path(sy,sx,y,x) #define q3_path(sy,sx,y,x,dummy) result = _q3_path(sy,sx,y,x) #define q4_path(sy,sx,y,x,dummy) result = _q4_path(sy,sx,y,x) /* * Quadrant I (step < 0). */ STATIC_OVL int _q1_path(srow,scol,y2,x2) int scol, srow, y2, x2; { int dx, dy; register int k, err, x, y, dxs, dys; x = scol; y = srow; dx = x2 - x; dy = y - y2; dxs = dx << 1; /* save the shifted values */ dys = dy << 1; if (dy > dx) { err = dxs - dy; for (k = dy-1; k; k--) { if (err >= 0) { x++; err -= dys; } y--; err += dxs; if (!is_clear(y,x)) return 0; /* blocked */ } } else { err = dys - dx; for (k = dx-1; k; k--) { if (err >= 0) { y--; err -= dxs; } x++; err += dys; if (!is_clear(y,x)) return 0;/* blocked */ } } return 1; } /* * Quadrant IV (step > 0). */ STATIC_OVL int _q4_path(srow,scol,y2,x2) int scol, srow, y2, x2; { int dx, dy; register int k, err, x, y, dxs, dys; x = scol; y = srow; dx = x2 - x; dy = y2 - y; dxs = dx << 1; /* save the shifted values */ dys = dy << 1; if (dy > dx) { err = dxs - dy; for (k = dy-1; k; k--) { if (err >= 0) { x++; err -= dys; } y++; err += dxs; if (!is_clear(y,x)) return 0; /* blocked */ } } else { err = dys - dx; for (k = dx-1; k; k--) { if (err >= 0) { y++; err -= dxs; } x++; err += dys; if (!is_clear(y,x)) return 0;/* blocked */ } } return 1; } /* * Quadrant II (step < 0). */ STATIC_OVL int _q2_path(srow,scol,y2,x2) int scol, srow, y2, x2; { int dx, dy; register int k, err, x, y, dxs, dys; x = scol; y = srow; dx = x - x2; dy = y - y2; dxs = dx << 1; /* save the shifted values */ dys = dy << 1; if (dy > dx) { err = dxs - dy; for (k = dy-1; k; k--) { if (err >= 0) { x--; err -= dys; } y--; err += dxs; if (!is_clear(y,x)) return 0; /* blocked */ } } else { err = dys - dx; for (k = dx-1; k; k--) { if (err >= 0) { y--; err -= dxs; } x--; err += dys; if (!is_clear(y,x)) return 0;/* blocked */ } } return 1; } /* * Quadrant III (step > 0). */ STATIC_OVL int _q3_path(srow,scol,y2,x2) int scol, srow, y2, x2; { int dx, dy; register int k, err, x, y, dxs, dys; x = scol; y = srow; dx = x - x2; dy = y2 - y; dxs = dx << 1; /* save the shifted values */ dys = dy << 1; if (dy > dx) { err = dxs - dy; for (k = dy-1; k; k--) { if (err >= 0) { x--; err -= dys; } y++; err += dxs; if (!is_clear(y,x)) return 0; /* blocked */ } } else { err = dys - dx; for (k = dx-1; k; k--) { if (err >= 0) { y++; err -= dxs; } x--; err += dys; if (!is_clear(y,x)) return 0;/* blocked */ } } return 1; } #endif /* quadrants are functions */ /* * Use vision tables to determine if there is a clear path from * (col1,row1) to (col2,row2). This is used by: * m_cansee() * m_canseeu() * do_light_sources() */ boolean clear_path(col1,row1,col2,row2) int col1, row1, col2, row2; { int result; if(col1 < col2) { if(row1 > row2) { q1_path(row1,col1,row2,col2,cleardone); } else { q4_path(row1,col1,row2,col2,cleardone); } } else { if(row1 > row2) { q2_path(row1,col1,row2,col2,cleardone); } else if(row1 == row2 && col1 == col2) { result = 1; } else { q3_path(row1,col1,row2,col2,cleardone); } } #ifdef MACRO_CPATH cleardone: #endif return((boolean)result); } #ifdef VISION_TABLES /*===========================================================================*\ GENERAL LINE OF SIGHT Algorithm D \*===========================================================================*/ /* * Indicate caller for the shadow routines. */ #define FROM_RIGHT 0 #define FROM_LEFT 1 /* * Include the table definitions. */ #include "vis_tab.h" /* 3D table pointers. */ static close2d *close_dy[CLOSE_MAX_BC_DY]; static far2d *far_dy[FAR_MAX_BC_DY]; STATIC_DCL void FDECL(right_side, (int,int,int,int,int,int,int,char*)); STATIC_DCL void FDECL(left_side, (int,int,int,int,int,int,int,char*)); STATIC_DCL int FDECL(close_shadow, (int,int,int,int)); STATIC_DCL int FDECL(far_shadow, (int,int,int,int)); /* * Initialize algorithm D's table pointers. If we don't have these, * then we do 3D table lookups. Verrrry slow. */ STATIC_OVL void view_init() { int i; for (i = 0; i < CLOSE_MAX_BC_DY; i++) close_dy[i] = &close_table[i]; for (i = 0; i < FAR_MAX_BC_DY; i++) far_dy[i] = &far_table[i]; } /* * If the far table has an entry of OFF_TABLE, then the far block prevents * us from seeing the location just above/below it. I.e. the first visible * location is one *before* the block. */ #define OFF_TABLE 0xff STATIC_OVL int close_shadow(side,this_row,block_row,block_col) int side,this_row,block_row,block_col; { register int sdy, sdx, pdy, offset; /* * If on the same column (block_row = -1), then we can see it. */ if (block_row < 0) return block_col; /* Take explicit absolute values. Adjust. */ if ((sdy = (start_row-block_row)) < 0) sdy = -sdy; --sdy; /* src dy */ if ((sdx = (start_col-block_col)) < 0) sdx = -sdx; /* src dx */ if ((pdy = (block_row-this_row)) < 0) pdy = -pdy; /* point dy */ if (sdy < 0 || sdy >= CLOSE_MAX_SB_DY || sdx >= CLOSE_MAX_SB_DX || pdy >= CLOSE_MAX_BC_DY) { impossible("close_shadow: bad value"); return block_col; } offset = close_dy[sdy]->close[sdx][pdy]; if (side == FROM_RIGHT) return block_col + offset; return block_col - offset; } STATIC_OVL int far_shadow(side,this_row,block_row,block_col) int side,this_row,block_row,block_col; { register int sdy, sdx, pdy, offset; /* * Take care of a bug that shows up only on the borders. * * If the block is beyond the border, then the row is negative. Return * the block's column number (should be 0 or COLNO-1). * * Could easily have the column be -1, but then wouldn't know if it was * the left or right border. */ if (block_row < 0) return block_col; /* Take explicit absolute values. Adjust. */ if ((sdy = (start_row-block_row)) < 0) sdy = -sdy; /* src dy */ if ((sdx = (start_col-block_col)) < 0) sdx = -sdx; --sdx; /* src dx */ if ((pdy = (block_row-this_row)) < 0) pdy = -pdy; --pdy; /* point dy */ if (sdy >= FAR_MAX_SB_DY || sdx < 0 || sdx >= FAR_MAX_SB_DX || pdy < 0 || pdy >= FAR_MAX_BC_DY) { impossible("far_shadow: bad value"); return block_col; } if ((offset = far_dy[sdy]->far_q[sdx][pdy]) == OFF_TABLE) offset = -1; if (side == FROM_RIGHT) return block_col + offset; return block_col - offset; } /* * right_side() * * Figure out what could be seen on the right side of the source. */ STATIC_OVL void right_side(row, cb_row, cb_col, fb_row, fb_col, left, right_mark, limits) int row; /* current row */ int cb_row, cb_col; /* close block row and col */ int fb_row, fb_col; /* far block row and col */ int left; /* left mark of the previous row */ int right_mark; /* right mark of previous row */ char *limits; /* points at range limit for current row, or NULL */ { register int i; register char *rowp; int hit_stone = 0; int left_shadow, right_shadow, loc_right; int lblock_col; /* local block column (current row) */ int nrow, deeper; char *row_min; /* left most */ char *row_max; /* right most */ int lim_max; /* right most limit of circle */ #ifdef GCC_WARN rowp = 0; #endif nrow = row + step; deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1))); if(!vis_func) { rowp = cs_rows[row]; row_min = &cs_left[row]; row_max = &cs_right[row]; } if(limits) { lim_max = start_col + *limits; if(lim_max > COLNO-1) lim_max = COLNO-1; if(right_mark > lim_max) right_mark = lim_max; limits++; /* prepare for next row */ } else lim_max = COLNO-1; /* * Get the left shadow from the close block. This value could be * illegal. */ left_shadow = close_shadow(FROM_RIGHT,row,cb_row,cb_col); /* * Mark all stone walls as seen before the left shadow. All this work * for a special case. * * NOTE. With the addition of this code in here, it is now *required* * for the algorithm to work correctly. If this is commented out, * change the above assignment so that left and not left_shadow is the * variable that gets the shadow. */ while (left <= right_mark) { loc_right = right_ptrs[row][left]; if(loc_right > lim_max) loc_right = lim_max; if (viz_clear_rows[row][left]) { if (loc_right >= left_shadow) { left = left_shadow; /* opening ends beyond shadow */ break; } left = loc_right; loc_right = right_ptrs[row][left]; if(loc_right > lim_max) loc_right = lim_max; if (left == loc_right) return; /* boundary */ /* Shadow covers opening, beyond right mark */ if (left == right_mark && left_shadow > right_mark) return; } if (loc_right > right_mark) /* can't see stone beyond the mark */ loc_right = right_mark; if(vis_func) { for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= loc_right; i++) set_cs(rowp,i); set_min(left); set_max(loc_right); } if (loc_right == right_mark) return; /* all stone */ if (loc_right >= left_shadow) hit_stone = 1; left = loc_right + 1; } /* * At this point we are at the first visible clear spot on or beyond * the left shadow, unless the left shadow is an illegal value. If we * have "hit stone" then we have a stone wall just to our left. */ /* * Get the right shadow. Make sure that it is a legal value. */ if ((right_shadow = far_shadow(FROM_RIGHT,row,fb_row,fb_col)) >= COLNO) right_shadow = COLNO-1; /* * Make vertical walls work the way we want them. In this case, we * note when the close block blocks the column just above/beneath * it (right_shadow < fb_col [actually right_shadow == fb_col-1]). If * the location is filled, then we want to see it, so we put the * right shadow back (same as fb_col). */ if (right_shadow < fb_col && !viz_clear_rows[row][fb_col]) right_shadow = fb_col; if(right_shadow > lim_max) right_shadow = lim_max; /* * Main loop. Within the range of sight of the previous row, mark all * stone walls as seen. Follow open areas recursively. */ while (left <= right_mark) { /* Get the far right of the opening or wall */ loc_right = right_ptrs[row][left]; if(loc_right > lim_max) loc_right = lim_max; if (!viz_clear_rows[row][left]) { hit_stone = 1; /* use stone on this row as close block */ /* * We can see all of the wall until the next open spot or the * start of the shadow caused by the far block (right). * * Can't see stone beyond the right mark. */ if (loc_right > right_mark) loc_right = right_mark; if(vis_func) { for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= loc_right; i++) set_cs(rowp,i); set_min(left); set_max(loc_right); } if (loc_right == right_mark) return; /* hit the end */ left = loc_right + 1; loc_right = right_ptrs[row][left]; if(loc_right > lim_max) loc_right = lim_max; /* fall through... we know at least one position is visible */ } /* * We are in an opening. * * If this is the first open spot since the could see area (this is * true if we have hit stone), get the shadow generated by the wall * just to our left. */ if (hit_stone) { lblock_col = left-1; /* local block column */ left = close_shadow(FROM_RIGHT,row,row,lblock_col); if (left > lim_max) break; /* off the end */ } /* * Check if the shadow covers the opening. If it does, then * move to end of the opening. A shadow generated on from a * wall on this row does *not* cover the wall on the right * of the opening. */ if (left >= loc_right) { if (loc_right == lim_max) { /* boundary */ if (left == lim_max) { if(vis_func) (*vis_func)(lim_max, row, varg); else { set_cs(rowp,lim_max); /* last pos */ set_max(lim_max); } } return; /* done */ } left = loc_right; continue; } /* * If the far wall of the opening (loc_right) is closer than the * shadow limit imposed by the far block (right) then use the far * wall as our new far block when we recurse. * * If the limits are the the same, and the far block really exists * (fb_row >= 0) then do the same as above. * * Normally, the check would be for the far wall being closer OR EQUAL * to the shadow limit. However, there is a bug that arises from the * fact that the clear area pointers end in an open space (if it * exists) on a boundary. This then makes a far block exist where it * shouldn't --- on a boundary. To get around that, I had to * introduce the concept of a non-existent far block (when the * row < 0). Next I have to check for it. Here is where that check * exists. */ if ((loc_right < right_shadow) || (fb_row >= 0 && loc_right == right_shadow)) { if(vis_func) { for (i = left; i <= loc_right; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= loc_right; i++) set_cs(rowp,i); set_min(left); set_max(loc_right); } if (deeper) { if (hit_stone) right_side(nrow,row,lblock_col,row,loc_right, left,loc_right,limits); else right_side(nrow,cb_row,cb_col,row,loc_right, left,loc_right,limits); } /* * The following line, setting hit_stone, is needed for those * walls that are only 1 wide. If hit stone is *not* set and * the stone is only one wide, then the close block is the old * one instead one on the current row. A way around having to * set it here is to make left = loc_right (not loc_right+1) and * let the outer loop take care of it. However, if we do that * then we then have to check for boundary conditions here as * well. */ hit_stone = 1; left = loc_right+1; } /* * The opening extends beyond the right mark. This means that * the next far block is the current far block. */ else { if(vis_func) { for (i=left; i <= right_shadow; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= right_shadow; i++) set_cs(rowp,i); set_min(left); set_max(right_shadow); } if (deeper) { if (hit_stone) right_side(nrow, row,lblock_col,fb_row,fb_col, left,right_shadow,limits); else right_side(nrow,cb_row, cb_col,fb_row,fb_col, left,right_shadow,limits); } return; /* we're outta here */ } } } /* * left_side() * * This routine is the mirror image of right_side(). Please see right_side() * for blow by blow comments. */ STATIC_OVL void left_side(row, cb_row, cb_col, fb_row, fb_col, left_mark, right, limits) int row; /* the current row */ int cb_row, cb_col; /* close block row and col */ int fb_row, fb_col; /* far block row and col */ int left_mark; /* left mark of previous row */ int right; /* right mark of the previous row */ char *limits; { register int i; register char *rowp; int hit_stone = 0; int left_shadow, right_shadow, loc_left; int lblock_col; /* local block column (current row) */ int nrow, deeper; char *row_min; /* left most */ char *row_max; /* right most */ int lim_min; #ifdef GCC_WARN rowp = 0; #endif nrow = row + step; deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1))); if(!vis_func) { rowp = cs_rows[row]; row_min = &cs_left[row]; row_max = &cs_right[row]; } if(limits) { lim_min = start_col - *limits; if(lim_min < 0) lim_min = 0; if(left_mark < lim_min) left_mark = lim_min; limits++; /* prepare for next row */ } else lim_min = 0; /* This value could be illegal. */ right_shadow = close_shadow(FROM_LEFT,row,cb_row,cb_col); while ( right >= left_mark ) { loc_left = left_ptrs[row][right]; if(loc_left < lim_min) loc_left = lim_min; if (viz_clear_rows[row][right]) { if (loc_left <= right_shadow) { right = right_shadow; /* opening ends beyond shadow */ break; } right = loc_left; loc_left = left_ptrs[row][right]; if(loc_left < lim_min) loc_left = lim_min; if (right == loc_left) return; /* boundary */ } if (loc_left < left_mark) /* can't see beyond the left mark */ loc_left = left_mark; if(vis_func) { for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = loc_left; i <= right; i++) set_cs(rowp,i); set_min(loc_left); set_max(right); } if (loc_left == left_mark) return; /* all stone */ if (loc_left <= right_shadow) hit_stone = 1; right = loc_left - 1; } /* At first visible clear spot on or beyond the right shadow. */ if ((left_shadow = far_shadow(FROM_LEFT,row,fb_row,fb_col)) < 0) left_shadow = 0; /* Do vertical walls as we want. */ if (left_shadow > fb_col && !viz_clear_rows[row][fb_col]) left_shadow = fb_col; if(left_shadow < lim_min) left_shadow = lim_min; while (right >= left_mark) { loc_left = left_ptrs[row][right]; if (!viz_clear_rows[row][right]) { hit_stone = 1; /* use stone on this row as close block */ /* We can only see walls until the left mark */ if (loc_left < left_mark) loc_left = left_mark; if(vis_func) { for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = loc_left; i <= right; i++) set_cs(rowp,i); set_min(loc_left); set_max(right); } if (loc_left == left_mark) return; /* hit end */ right = loc_left - 1; loc_left = left_ptrs[row][right]; if (loc_left < lim_min) loc_left = lim_min; /* fall through...*/ } /* We are in an opening. */ if (hit_stone) { lblock_col = right+1; /* stone block (local) */ right = close_shadow(FROM_LEFT,row,row,lblock_col); if (right < lim_min) return; /* off the end */ } /* Check if the shadow covers the opening. */ if (right <= loc_left) { /* Make a boundary condition work. */ if (loc_left == lim_min) { /* at boundary */ if (right == lim_min) { if(vis_func) (*vis_func)(lim_min, row, varg); else { set_cs(rowp,lim_min); /* caught the last pos */ set_min(lim_min); } } return; /* and break out the loop */ } right = loc_left; continue; } /* If the far wall of the opening is closer than the shadow limit. */ if ((loc_left > left_shadow) || (fb_row >= 0 && loc_left == left_shadow)) { if(vis_func) { for (i = loc_left; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = loc_left; i <= right; i++) set_cs(rowp,i); set_min(loc_left); set_max(right); } if (deeper) { if (hit_stone) left_side(nrow,row,lblock_col,row,loc_left, loc_left,right,limits); else left_side(nrow,cb_row,cb_col,row,loc_left, loc_left,right,limits); } hit_stone = 1; /* needed for walls of width 1 */ right = loc_left-1; } /* The opening extends beyond the left mark. */ else { if(vis_func) { for (i=left_shadow; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = left_shadow; i <= right; i++) set_cs(rowp,i); set_min(left_shadow); set_max(right); } if (deeper) { if (hit_stone) left_side(nrow,row,lblock_col,fb_row,fb_col, left_shadow,right,limits); else left_side(nrow,cb_row,cb_col,fb_row,fb_col, left_shadow,right,limits); } return; /* we're outta here */ } } } /* * view_from * * Calculate a view from the given location. Initialize and fill a * ROWNOxCOLNO array (could_see) with all the locations that could be * seen from the source location. Initialize and fill the left most * and right most boundaries of what could be seen. */ STATIC_OVL void view_from(srow,scol,loc_cs_rows,left_most,right_most, range, func, arg) int srow, scol; /* source row and column */ char **loc_cs_rows; /* could_see array (row pointers) */ char *left_most, *right_most; /* limits of what could be seen */ int range; /* 0 if unlimited */ void FDECL((*func), (int,int,genericptr_t)); genericptr_t arg; { register int i; char *rowp; int nrow, left, right, left_row, right_row; char *limits; /* Set globals for near_shadow(), far_shadow(), etc. to use. */ start_col = scol; start_row = srow; cs_rows = loc_cs_rows; cs_left = left_most; cs_right = right_most; vis_func = func; varg = arg; /* Find the left and right limits of sight on the starting row. */ if (viz_clear_rows[srow][scol]) { left = left_ptrs[srow][scol]; right = right_ptrs[srow][scol]; } else { left = (!scol) ? 0 : (viz_clear_rows[srow][scol-1] ? left_ptrs[srow][scol-1] : scol-1); right = (scol == COLNO-1) ? COLNO-1 : (viz_clear_rows[srow][scol+1] ? right_ptrs[srow][scol+1] : scol+1); } if(range) { if(range > MAX_RADIUS || range < 1) panic("view_from called with range %d", range); limits = circle_ptr(range) + 1; /* start at next row */ if(left < scol - range) left = scol - range; if(right > scol + range) right = scol + range; } else limits = (char*) 0; if(func) { for (i = left; i <= right; i++) (*func)(i, srow, arg); } else { /* Row optimization */ rowp = cs_rows[srow]; /* We know that we can see our row. */ for (i = left; i <= right; i++) set_cs(rowp,i); cs_left[srow] = left; cs_right[srow] = right; } /* The far block has a row number of -1 if we are on an edge. */ right_row = (right == COLNO-1) ? -1 : srow; left_row = (!left) ? -1 : srow; /* * Check what could be seen in quadrants. */ if ( (nrow = srow+1) < ROWNO ) { step = 1; /* move down */ if (scol= 0 ) { step = -1; /* move up */ if (scol= *(limits+1))); if(!vis_func) { rowp = cs_rows[row]; /* optimization */ row_min = &cs_left[row]; row_max = &cs_right[row]; } if(limits) { lim_max = start_col + *limits; if(lim_max > COLNO-1) lim_max = COLNO-1; if(right_mark > lim_max) right_mark = lim_max; limits++; /* prepare for next row */ } else lim_max = COLNO-1; while (left <= right_mark) { right_edge = right_ptrs[row][left]; if(right_edge > lim_max) right_edge = lim_max; if (!is_clear(row,left)) { /* * Jump to the far side of a stone wall. We can set all * the points in between as seen. * * If the right edge goes beyond the right mark, check to see * how much we can see. */ if (right_edge > right_mark) { /* * If the mark on the previous row was a clear position, * the odds are that we can actually see part of the wall * beyond the mark on this row. If so, then see one beyond * the mark. Otherwise don't. This is a kludge so corners * with an adjacent doorway show up in nethack. */ right_edge = is_clear(row-step,right_mark) ? right_mark+1 : right_mark; } if(vis_func) { for (i = left; i <= right_edge; i++) (*vis_func)(i, row, varg); } else { for (i = left; i <= right_edge; i++) set_cs(rowp,i); set_min(left); set_max(right_edge); } left = right_edge + 1; /* no limit check necessary */ continue; } /* No checking needed if our left side is the start column. */ if (left != start_col) { /* * Find the left side. Move right until we can see it or we run * into a wall. */ for (; left <= right_edge; left++) { if (step < 0) { q1_path(start_row,start_col,row,left,rside1); } else { q4_path(start_row,start_col,row,left,rside1); } rside1: /* used if q?_path() is a macro */ if (result) break; } /* * Check for boundary conditions. We *need* check (2) to break * an infinite loop where: * * left == right_edge == right_mark == lim_max. * */ if (left > lim_max) return; /* check (1) */ if (left == lim_max) { /* check (2) */ if(vis_func) (*vis_func)(lim_max, row, varg); else { set_cs(rowp,lim_max); set_max(lim_max); } return; } /* * Check if we can see any spots in the opening. We might * (left == right_edge) or might not (left == right_edge+1) have * been able to see the far wall. Make sure we *can* see the * wall (remember, we can see the spot above/below this one) * by backing up. */ if (left >= right_edge) { left = right_edge; /* for the case left == right_edge+1 */ continue; } } /* * Find the right side. If the marker from the previous row is * closer than the edge on this row, then we have to check * how far we can see around the corner (under the overhang). Stop * at the first non-visible spot or we actually hit the far wall. * * Otherwise, we know we can see the right edge of the current row. * * This must be a strict less than so that we can always see a * horizontal wall, even if it is adjacent to us. */ if (right_mark < right_edge) { for (right = right_mark; right <= right_edge; right++) { if (step < 0) { q1_path(start_row,start_col,row,right,rside2); } else { q4_path(start_row,start_col,row,right,rside2); } rside2: /* used if q?_path() is a macro */ if (!result) break; } --right; /* get rid of the last increment */ } else right = right_edge; /* * We have the range that we want. Set the bits. Note that * there is no else --- we no longer handle splinters. */ if (left <= right) { /* * An ugly special case. If you are adjacent to a vertical wall * and it has a break in it, then the right mark is set to be * start_col. We *want* to be able to see adjacent vertical * walls, so we have to set it back. */ if (left == right && left == start_col && start_col < (COLNO-1) && !is_clear(row,start_col+1)) right = start_col+1; if(right > lim_max) right = lim_max; /* set the bits */ if(vis_func) for (i = left; i <= right; i++) (*vis_func)(i, row, varg); else { for (i = left; i <= right; i++) set_cs(rowp,i); set_min(left); set_max(right); } /* recursive call for next finger of light */ if (deeper) right_side(nrow,left,right,limits); left = right + 1; /* no limit check necessary */ } } } /* * This routine is the mirror image of right_side(). See right_side() for * extensive comments. */ STATIC_OVL void left_side(row, left_mark, right, limits) int row, left_mark, right; char *limits; { int left, left_edge, nrow, deeper, result; register int i; register char *rowp; char *row_min, *row_max; int lim_min; #ifdef GCC_WARN rowp = row_min = row_max = 0; #endif nrow = row+step; deeper = good_row(nrow) && (!limits || (*limits >= *(limits+1))); if(!vis_func) { rowp = cs_rows[row]; row_min = &cs_left[row]; row_max = &cs_right[row]; } if(limits) { lim_min = start_col - *limits; if(lim_min < 0) lim_min = 0; if(left_mark < lim_min) left_mark = lim_min; limits++; /* prepare for next row */ } else lim_min = 0; while (right >= left_mark) { left_edge = left_ptrs[row][right]; if(left_edge < lim_min) left_edge = lim_min; if (!is_clear(row,right)) { /* Jump to the far side of a stone wall. */ if (left_edge < left_mark) { /* Maybe see more (kludge). */ left_edge = is_clear(row-step,left_mark) ? left_mark-1 : left_mark; } if(vis_func) { for (i = left_edge; i <= right; i++) (*vis_func)(i, row, varg); } else { for (i = left_edge; i <= right; i++) set_cs(rowp,i); set_min(left_edge); set_max(right); } right = left_edge - 1; /* no limit check necessary */ continue; } if (right != start_col) { /* Find the right side. */ for (; right >= left_edge; right--) { if (step < 0) { q2_path(start_row,start_col,row,right,lside1); } else { q3_path(start_row,start_col,row,right,lside1); } lside1: /* used if q?_path() is a macro */ if (result) break; } /* Check for boundary conditions. */ if (right < lim_min) return; if (right == lim_min) { if(vis_func) (*vis_func)(lim_min, row, varg); else { set_cs(rowp,lim_min); set_min(lim_min); } return; } /* Check if we can see any spots in the opening. */ if (right <= left_edge) { right = left_edge; continue; } } /* Find the left side. */ if (left_mark > left_edge) { for (left = left_mark; left >= left_edge; --left) { if (step < 0) { q2_path(start_row,start_col,row,left,lside2); } else { q3_path(start_row,start_col,row,left,lside2); } lside2: /* used if q?_path() is a macro */ if (!result) break; } left++; /* get rid of the last decrement */ } else left = left_edge; if (left <= right) { /* An ugly special case. */ if (left == right && right == start_col && start_col > 0 && !is_clear(row,start_col-1)) left = start_col-1; if(left < lim_min) left = lim_min; if(vis_func) for (i = left; i <= right; i++) (*vis_func)(i, row, varg); else { for (i = left; i <= right; i++) set_cs(rowp,i); set_min(left); set_max(right); } /* Recurse */ if (deeper) left_side(nrow,left,right,limits); right = left - 1; /* no limit check necessary */ } } } /* * Calculate all possible visible locations from the given location * (srow,scol). NOTE this is (y,x)! Mark the visible locations in the * array provided. */ STATIC_OVL void view_from(srow, scol, loc_cs_rows, left_most, right_most, range, func, arg) int srow, scol; /* starting row and column */ char **loc_cs_rows; /* pointers to the rows of the could_see array */ char *left_most; /* min mark on each row */ char *right_most; /* max mark on each row */ int range; /* 0 if unlimited */ void FDECL((*func), (int,int,genericptr_t)); genericptr_t arg; { register int i; /* loop counter */ char *rowp; /* optimization for setting could_see */ int nrow; /* the next row */ int left; /* the left-most visible column */ int right; /* the right-most visible column */ char *limits; /* range limit for next row */ /* Set globals for q?_path(), left_side(), and right_side() to use. */ start_col = scol; start_row = srow; cs_rows = loc_cs_rows; /* 'could see' rows */ cs_left = left_most; cs_right = right_most; vis_func = func; varg = arg; /* * Determine extent of sight on the starting row. */ if (is_clear(srow,scol)) { left = left_ptrs[srow][scol]; right = right_ptrs[srow][scol]; } else { /* * When in stone, you can only see your adjacent squares, unless * you are on an array boundary or a stone/clear boundary. */ left = (!scol) ? 0 : (is_clear(srow,scol-1) ? left_ptrs[srow][scol-1] : scol-1); right = (scol == COLNO-1) ? COLNO-1 : (is_clear(srow,scol+1) ? right_ptrs[srow][scol+1] : scol+1); } if(range) { if(range > MAX_RADIUS || range < 1) panic("view_from called with range %d", range); limits = circle_ptr(range) + 1; /* start at next row */ if(left < scol - range) left = scol - range; if(right > scol + range) right = scol + range; } else limits = (char*) 0; if(func) { for (i = left; i <= right; i++) (*func)(i, srow, arg); } else { /* Row pointer optimization. */ rowp = cs_rows[srow]; /* We know that we can see our row. */ for (i = left; i <= right; i++) set_cs(rowp,i); cs_left[srow] = left; cs_right[srow] = right; } /* * Check what could be seen in quadrants. We need to check for valid * rows here, since we don't do it in the routines right_side() and * left_side() [ugliness to remove extra routine calls]. */ if ( (nrow = srow+1) < ROWNO ) { /* move down */ step = 1; if (scol < COLNO-1) right_side(nrow, scol, right, limits); if (scol) left_side (nrow, left, scol, limits); } if ( (nrow = srow-1) >= 0 ) { /* move up */ step = -1; if (scol < COLNO-1) right_side(nrow, scol, right, limits); if (scol) left_side (nrow, left, scol, limits); } } #endif /*===== End of algorithm C =====*/ /* * AREA OF EFFECT "ENGINE" * * Calculate all possible visible locations as viewed from the given location * (srow,scol) within the range specified. Perform "func" with (x, y) args and * additional argument "arg" for each square. * * If not centered on the hero, just forward arguments to view_from(); it * will call "func" when necessary. If the hero is the center, use the * vision matrix and reduce extra work. */ void do_clear_area(scol,srow,range,func,arg) int scol, srow, range; void FDECL((*func), (int,int,genericptr_t)); genericptr_t arg; { /* If not centered on hero, do the hard work of figuring the area */ if (scol != u.ux || srow != u.uy) view_from(srow, scol, (char **)0, (char *)0, (char *)0, range, func, arg); else { register int x; int y, min_x, max_x, max_y, offset; char *limits; if (range > MAX_RADIUS || range < 1) panic("do_clear_area: illegal range %d", range); if(vision_full_recalc) vision_recalc(0); /* recalc vision if dirty */ limits = circle_ptr(range); if ((max_y = (srow + range)) >= ROWNO) max_y = ROWNO-1; if ((y = (srow - range)) < 0) y = 0; for (; y <= max_y; y++) { offset = limits[v_abs(y-srow)]; if((min_x = (scol - offset)) < 0) min_x = 0; if((max_x = (scol + offset)) >= COLNO) max_x = COLNO-1; for (x = min_x; x <= max_x; x++) if (couldsee(x, y)) (*func)(x, y, arg); } } } /*vision.c*/ nethack-3.4.3/src/weapon.c0100644000000000000000000011221707764735041014102 0ustar rootroot/* SCCS Id: @(#)weapon.c 3.4 2002/11/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * This module contains code for calculation of "to hit" and damage * bonuses for any given weapon used, as well as weapons selection * code for monsters. */ #include "hack.h" /* Categories whose names don't come from OBJ_NAME(objects[type]) */ #define PN_BARE_HANDED (-1) /* includes martial arts */ #define PN_TWO_WEAPONS (-2) #define PN_RIDING (-3) #define PN_POLEARMS (-4) #define PN_SABER (-5) #define PN_HAMMER (-6) #define PN_WHIP (-7) #define PN_ATTACK_SPELL (-8) #define PN_HEALING_SPELL (-9) #define PN_DIVINATION_SPELL (-10) #define PN_ENCHANTMENT_SPELL (-11) #define PN_CLERIC_SPELL (-12) #define PN_ESCAPE_SPELL (-13) #define PN_MATTER_SPELL (-14) STATIC_DCL void FDECL(give_may_advance_msg, (int)); #ifndef OVLB STATIC_DCL NEARDATA const short skill_names_indices[]; STATIC_DCL NEARDATA const char *odd_skill_names[]; STATIC_DCL NEARDATA const char *barehands_or_martial[]; #else /* OVLB */ STATIC_VAR NEARDATA const short skill_names_indices[P_NUM_SKILLS] = { 0, DAGGER, KNIFE, AXE, PICK_AXE, SHORT_SWORD, BROADSWORD, LONG_SWORD, TWO_HANDED_SWORD, SCIMITAR, PN_SABER, CLUB, MACE, MORNING_STAR, FLAIL, PN_HAMMER, QUARTERSTAFF, PN_POLEARMS, SPEAR, JAVELIN, TRIDENT, LANCE, BOW, SLING, CROSSBOW, DART, SHURIKEN, BOOMERANG, PN_WHIP, UNICORN_HORN, PN_ATTACK_SPELL, PN_HEALING_SPELL, PN_DIVINATION_SPELL, PN_ENCHANTMENT_SPELL, PN_CLERIC_SPELL, PN_ESCAPE_SPELL, PN_MATTER_SPELL, PN_BARE_HANDED, PN_TWO_WEAPONS, #ifdef STEED PN_RIDING #endif }; /* note: entry [0] isn't used */ STATIC_VAR NEARDATA const char * const odd_skill_names[] = { "no skill", "bare hands", /* use barehands_or_martial[] instead */ "two weapon combat", "riding", "polearms", "saber", "hammer", "whip", "attack spells", "healing spells", "divination spells", "enchantment spells", "clerical spells", "escape spells", "matter spells", }; /* indexed vis `is_martial() */ STATIC_VAR NEARDATA const char * const barehands_or_martial[] = { "bare handed combat", "martial arts" }; STATIC_OVL void give_may_advance_msg(skill) int skill; { You_feel("more confident in your %sskills.", skill == P_NONE ? "" : skill <= P_LAST_WEAPON ? "weapon " : skill <= P_LAST_SPELL ? "spell casting " : "fighting "); } #endif /* OVLB */ STATIC_DCL boolean FDECL(can_advance, (int, BOOLEAN_P)); STATIC_DCL boolean FDECL(could_advance, (int)); STATIC_DCL boolean FDECL(peaked_skill, (int)); STATIC_DCL int FDECL(slots_required, (int)); #ifdef OVL1 STATIC_DCL char *FDECL(skill_level_name, (int,char *)); STATIC_DCL void FDECL(skill_advance, (int)); #endif /* OVL1 */ #define P_NAME(type) ((skill_names_indices[type] > 0) ? \ OBJ_NAME(objects[skill_names_indices[type]]) : \ (type == P_BARE_HANDED_COMBAT) ? \ barehands_or_martial[martial_bonus()] : \ odd_skill_names[-skill_names_indices[type]]) #ifdef OVLB static NEARDATA const char kebabable[] = { S_XORN, S_DRAGON, S_JABBERWOCK, S_NAGA, S_GIANT, '\0' }; /* * hitval returns an integer representing the "to hit" bonuses * of "otmp" against the monster. */ int hitval(otmp, mon) struct obj *otmp; struct monst *mon; { int tmp = 0; struct permonst *ptr = mon->data; boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)); if (Is_weapon) tmp += otmp->spe; /* Put weapon specific "to hit" bonuses in below: */ tmp += objects[otmp->otyp].oc_hitbon; /* Put weapon vs. monster type "to hit" bonuses in below: */ /* Blessed weapons used against undead or demons */ if (Is_weapon && otmp->blessed && (is_demon(ptr) || is_undead(ptr))) tmp += 2; if (is_spear(otmp) && index(kebabable, ptr->mlet)) tmp += 2; /* trident is highly effective against swimmers */ if (otmp->otyp == TRIDENT && is_swimmer(ptr)) { if (is_pool(mon->mx, mon->my)) tmp += 4; else if (ptr->mlet == S_EEL || ptr->mlet == S_SNAKE) tmp += 2; } /* Picks used against xorns and earth elementals */ if (is_pick(otmp) && (passes_walls(ptr) && thick_skinned(ptr))) tmp += 2; #ifdef INVISIBLE_OBJECTS /* Invisible weapons against monsters who can't see invisible */ if (otmp->oinvis && !perceives(ptr)) tmp += 3; #endif /* Check specially named weapon "to hit" bonuses */ if (otmp->oartifact) tmp += spec_abon(otmp, mon); return tmp; } /* Historical note: The original versions of Hack used a range of damage * which was similar to, but not identical to the damage used in Advanced * Dungeons and Dragons. I figured that since it was so close, I may as well * make it exactly the same as AD&D, adding some more weapons in the process. * This has the advantage that it is at least possible that the player would * already know the damage of at least some of the weapons. This was circa * 1987 and I used the table from Unearthed Arcana until I got tired of typing * them in (leading to something of an imbalance towards weapons early in * alphabetical order). The data structure still doesn't include fields that * fully allow the appropriate damage to be described (there's no way to say * 3d6 or 1d6+1) so we add on the extra damage in dmgval() if the weapon * doesn't do an exact die of damage. * * Of course new weapons were added later in the development of Nethack. No * AD&D consistency was kept, but most of these don't exist in AD&D anyway. * * Second edition AD&D came out a few years later; luckily it used the same * table. As of this writing (1999), third edition is in progress but not * released. Let's see if the weapon table stays the same. --KAA * October 2000: It didn't. Oh, well. */ /* * dmgval returns an integer representing the damage bonuses * of "otmp" against the monster. */ int dmgval(otmp, mon) struct obj *otmp; struct monst *mon; { int tmp = 0, otyp = otmp->otyp; struct permonst *ptr = mon->data; boolean Is_weapon = (otmp->oclass == WEAPON_CLASS || is_weptool(otmp)); if (otyp == CREAM_PIE) return 0; if (bigmonst(ptr)) { if (objects[otyp].oc_wldam) tmp = rnd(objects[otyp].oc_wldam); switch (otyp) { case IRON_CHAIN: case CROSSBOW_BOLT: case MORNING_STAR: case PARTISAN: case RUNESWORD: case ELVEN_BROADSWORD: case BROADSWORD: tmp++; break; case FLAIL: case RANSEUR: case VOULGE: tmp += rnd(4); break; case ACID_VENOM: case HALBERD: case SPETUM: tmp += rnd(6); break; case BATTLE_AXE: case BARDICHE: case TRIDENT: tmp += d(2,4); break; case TSURUGI: case DWARVISH_MATTOCK: case TWO_HANDED_SWORD: tmp += d(2,6); break; } } else { if (objects[otyp].oc_wsdam) tmp = rnd(objects[otyp].oc_wsdam); switch (otyp) { case IRON_CHAIN: case CROSSBOW_BOLT: case MACE: case WAR_HAMMER: case FLAIL: case SPETUM: case TRIDENT: tmp++; break; case BATTLE_AXE: case BARDICHE: case BILL_GUISARME: case GUISARME: case LUCERN_HAMMER: case MORNING_STAR: case RANSEUR: case BROADSWORD: case ELVEN_BROADSWORD: case RUNESWORD: case VOULGE: tmp += rnd(4); break; case ACID_VENOM: tmp += rnd(6); break; } } if (Is_weapon) { tmp += otmp->spe; /* negative enchantment mustn't produce negative damage */ if (tmp < 0) tmp = 0; } if (objects[otyp].oc_material <= LEATHER && thick_skinned(ptr)) /* thick skinned/scaled creatures don't feel it */ tmp = 0; if (ptr == &mons[PM_SHADE] && objects[otyp].oc_material != SILVER) tmp = 0; /* "very heavy iron ball"; weight increase is in increments of 160 */ if (otyp == HEAVY_IRON_BALL && tmp > 0) { int wt = (int)objects[HEAVY_IRON_BALL].oc_weight; if ((int)otmp->owt > wt) { wt = ((int)otmp->owt - wt) / 160; tmp += rnd(4 * wt); if (tmp > 25) tmp = 25; /* objects[].oc_wldam */ } } /* Put weapon vs. monster type damage bonuses in below: */ if (Is_weapon || otmp->oclass == GEM_CLASS || otmp->oclass == BALL_CLASS || otmp->oclass == CHAIN_CLASS) { int bonus = 0; if (otmp->blessed && (is_undead(ptr) || is_demon(ptr))) bonus += rnd(4); if (is_axe(otmp) && is_wooden(ptr)) bonus += rnd(4); if (objects[otyp].oc_material == SILVER && hates_silver(ptr)) bonus += rnd(20); /* if the weapon is going to get a double damage bonus, adjust this bonus so that effectively it's added after the doubling */ if (bonus > 1 && otmp->oartifact && spec_dbon(otmp, mon, 25) >= 25) bonus = (bonus + 1) / 2; tmp += bonus; } if (tmp > 0) { /* It's debateable whether a rusted blunt instrument should do less damage than a pristine one, since it will hit with essentially the same impact, but there ought to some penalty for using damaged gear so always subtract erosion even for blunt weapons. */ tmp -= greatest_erosion(otmp); if (tmp < 1) tmp = 1; } return(tmp); } #endif /* OVLB */ #ifdef OVL0 STATIC_DCL struct obj *FDECL(oselect, (struct monst *,int)); #define Oselect(x) if ((otmp = oselect(mtmp, x)) != 0) return(otmp); STATIC_OVL struct obj * oselect(mtmp, x) struct monst *mtmp; int x; { struct obj *otmp; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { if (otmp->otyp == x && /* never select non-cockatrice corpses */ !((x == CORPSE || x == EGG) && !touch_petrifies(&mons[otmp->corpsenm])) && (!otmp->oartifact || touch_artifact(otmp,mtmp))) return otmp; } return (struct obj *)0; } static NEARDATA const int rwep[] = { DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, JAVELIN, SHURIKEN, YA, SILVER_ARROW, ELVEN_ARROW, ARROW, ORCISH_ARROW, CROSSBOW_BOLT, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, KNIFE, FLINT, ROCK, LOADSTONE, LUCKSTONE, DART, /* BOOMERANG, */ CREAM_PIE /* note: CREAM_PIE should NOT be #ifdef KOPS */ }; static NEARDATA const int pwep[] = { HALBERD, BARDICHE, SPETUM, BILL_GUISARME, VOULGE, RANSEUR, GUISARME, GLAIVE, LUCERN_HAMMER, BEC_DE_CORBIN, FAUCHARD, PARTISAN, LANCE }; static struct obj *propellor; struct obj * select_rwep(mtmp) /* select a ranged weapon for the monster */ register struct monst *mtmp; { register struct obj *otmp; int i; #ifdef KOPS char mlet = mtmp->data->mlet; #endif propellor = &zeroobj; Oselect(EGG); /* cockatrice egg */ #ifdef KOPS if(mlet == S_KOP) /* pies are first choice for Kops */ Oselect(CREAM_PIE); #endif if(throws_rocks(mtmp->data)) /* ...boulders for giants */ Oselect(BOULDER); /* Select polearms first; they do more damage and aren't expendable */ /* The limit of 13 here is based on the monster polearm range limit * (defined as 5 in mthrowu.c). 5 corresponds to a distance of 2 in * one direction and 1 in another; one space beyond that would be 3 in * one direction and 2 in another; 3^2+2^2=13. */ if (dist2(mtmp->mx, mtmp->my, mtmp->mux, mtmp->muy) <= 13 && couldsee(mtmp->mx, mtmp->my)) { for (i = 0; i < SIZE(pwep); i++) { /* Only strong monsters can wield big (esp. long) weapons. * Big weapon is basically the same as bimanual. * All monsters can wield the remaining weapons. */ if (((strongmonst(mtmp->data) && (mtmp->misc_worn_check & W_ARMS) == 0) || !objects[pwep[i]].oc_bimanual) && (objects[pwep[i]].oc_material != SILVER || !hates_silver(mtmp->data))) { if ((otmp = oselect(mtmp, pwep[i])) != 0) { propellor = otmp; /* force the monster to wield it */ return otmp; } } } } /* * other than these two specific cases, always select the * most potent ranged weapon to hand. */ for (i = 0; i < SIZE(rwep); i++) { int prop; /* shooting gems from slings; this goes just before the darts */ /* (shooting rocks is already handled via the rwep[] ordering) */ if (rwep[i] == DART && !likes_gems(mtmp->data) && m_carrying(mtmp, SLING)) { /* propellor */ for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if (otmp->oclass == GEM_CLASS && (otmp->otyp != LOADSTONE || !otmp->cursed)) { propellor = m_carrying(mtmp, SLING); return otmp; } } /* KMH -- This belongs here so darts will work */ propellor = &zeroobj; prop = (objects[rwep[i]]).oc_skill; if (prop < 0) { switch (-prop) { case P_BOW: propellor = (oselect(mtmp, YUMI)); if (!propellor) propellor = (oselect(mtmp, ELVEN_BOW)); if (!propellor) propellor = (oselect(mtmp, BOW)); if (!propellor) propellor = (oselect(mtmp, ORCISH_BOW)); break; case P_SLING: propellor = (oselect(mtmp, SLING)); break; case P_CROSSBOW: propellor = (oselect(mtmp, CROSSBOW)); } if ((otmp = MON_WEP(mtmp)) && otmp->cursed && otmp != propellor && mtmp->weapon_check == NO_WEAPON_WANTED) propellor = 0; } /* propellor = obj, propellor to use * propellor = &zeroobj, doesn't need a propellor * propellor = 0, needed one and didn't have one */ if (propellor != 0) { /* Note: cannot use m_carrying for loadstones, since it will * always select the first object of a type, and maybe the * monster is carrying two but only the first is unthrowable. */ if (rwep[i] != LOADSTONE) { /* Don't throw a cursed weapon-in-hand or an artifact */ if ((otmp = oselect(mtmp, rwep[i])) && !otmp->oartifact && (!otmp->cursed || otmp != MON_WEP(mtmp))) return(otmp); } else for(otmp=mtmp->minvent; otmp; otmp=otmp->nobj) { if (otmp->otyp == LOADSTONE && !otmp->cursed) return otmp; } } } /* failure */ return (struct obj *)0; } /* Weapons in order of preference */ static const NEARDATA short hwep[] = { CORPSE, /* cockatrice corpse */ TSURUGI, RUNESWORD, DWARVISH_MATTOCK, TWO_HANDED_SWORD, BATTLE_AXE, KATANA, UNICORN_HORN, CRYSKNIFE, TRIDENT, LONG_SWORD, ELVEN_BROADSWORD, BROADSWORD, SCIMITAR, SILVER_SABER, MORNING_STAR, ELVEN_SHORT_SWORD, DWARVISH_SHORT_SWORD, SHORT_SWORD, ORCISH_SHORT_SWORD, MACE, AXE, DWARVISH_SPEAR, SILVER_SPEAR, ELVEN_SPEAR, SPEAR, ORCISH_SPEAR, FLAIL, BULLWHIP, QUARTERSTAFF, JAVELIN, AKLYS, CLUB, PICK_AXE, #ifdef KOPS RUBBER_HOSE, #endif /* KOPS */ WAR_HAMMER, SILVER_DAGGER, ELVEN_DAGGER, DAGGER, ORCISH_DAGGER, ATHAME, SCALPEL, KNIFE, WORM_TOOTH }; struct obj * select_hwep(mtmp) /* select a hand to hand weapon for the monster */ register struct monst *mtmp; { register struct obj *otmp; register int i; boolean strong = strongmonst(mtmp->data); boolean wearing_shield = (mtmp->misc_worn_check & W_ARMS) != 0; /* prefer artifacts to everything else */ for(otmp=mtmp->minvent; otmp; otmp = otmp->nobj) { if (otmp->oclass == WEAPON_CLASS && otmp->oartifact && touch_artifact(otmp,mtmp) && ((strong && !wearing_shield) || !objects[otmp->otyp].oc_bimanual)) return otmp; } if(is_giant(mtmp->data)) /* giants just love to use clubs */ Oselect(CLUB); /* only strong monsters can wield big (esp. long) weapons */ /* big weapon is basically the same as bimanual */ /* all monsters can wield the remaining weapons */ for (i = 0; i < SIZE(hwep); i++) { if (hwep[i] == CORPSE && !(mtmp->misc_worn_check & W_ARMG)) continue; if (((strong && !wearing_shield) || !objects[hwep[i]].oc_bimanual) && (objects[hwep[i]].oc_material != SILVER || !hates_silver(mtmp->data))) Oselect(hwep[i]); } /* failure */ return (struct obj *)0; } /* Called after polymorphing a monster, robbing it, etc.... Monsters * otherwise never unwield stuff on their own. Might print message. */ void possibly_unwield(mon, polyspot) struct monst *mon; boolean polyspot; { struct obj *obj, *mw_tmp; if (!(mw_tmp = MON_WEP(mon))) return; for (obj = mon->minvent; obj; obj = obj->nobj) if (obj == mw_tmp) break; if (!obj) { /* The weapon was stolen or destroyed */ MON_NOWEP(mon); mon->weapon_check = NEED_WEAPON; return; } if (!attacktype(mon->data, AT_WEAP)) { setmnotwielded(mon, mw_tmp); MON_NOWEP(mon); mon->weapon_check = NO_WEAPON_WANTED; obj_extract_self(obj); if (cansee(mon->mx, mon->my)) { pline("%s drops %s.", Monnam(mon), distant_name(obj, doname)); newsym(mon->mx, mon->my); } /* might be dropping object into water or lava */ if (!flooreffects(obj, mon->mx, mon->my, "drop")) { if (polyspot) bypass_obj(obj); place_object(obj, mon->mx, mon->my); stackobj(obj); } return; } /* The remaining case where there is a change is where a monster * is polymorphed into a stronger/weaker monster with a different * choice of weapons. This has no parallel for players. It can * be handled by waiting until mon_wield_item is actually called. * Though the monster still wields the wrong weapon until then, * this is OK since the player can't see it. (FIXME: Not okay since * probing can reveal it.) * Note that if there is no change, setting the check to NEED_WEAPON * is harmless. * Possible problem: big monster with big cursed weapon gets * polymorphed into little monster. But it's not quite clear how to * handle this anyway.... */ if (!(mw_tmp->cursed && mon->weapon_check == NO_WEAPON_WANTED)) mon->weapon_check = NEED_WEAPON; return; } /* Let a monster try to wield a weapon, based on mon->weapon_check. * Returns 1 if the monster took time to do it, 0 if it did not. */ int mon_wield_item(mon) register struct monst *mon; { struct obj *obj; /* This case actually should never happen */ if (mon->weapon_check == NO_WEAPON_WANTED) return 0; switch(mon->weapon_check) { case NEED_HTH_WEAPON: obj = select_hwep(mon); break; case NEED_RANGED_WEAPON: (void)select_rwep(mon); obj = propellor; break; case NEED_PICK_AXE: obj = m_carrying(mon, PICK_AXE); /* KMH -- allow other picks */ if (!obj && !which_armor(mon, W_ARMS)) obj = m_carrying(mon, DWARVISH_MATTOCK); break; case NEED_AXE: /* currently, only 2 types of axe */ obj = m_carrying(mon, BATTLE_AXE); if (!obj || which_armor(mon, W_ARMS)) obj = m_carrying(mon, AXE); break; case NEED_PICK_OR_AXE: /* prefer pick for fewer switches on most levels */ obj = m_carrying(mon, DWARVISH_MATTOCK); if (!obj) obj = m_carrying(mon, BATTLE_AXE); if (!obj || which_armor(mon, W_ARMS)) { obj = m_carrying(mon, PICK_AXE); if (!obj) obj = m_carrying(mon, AXE); } break; default: impossible("weapon_check %d for %s?", mon->weapon_check, mon_nam(mon)); return 0; } if (obj && obj != &zeroobj) { struct obj *mw_tmp = MON_WEP(mon); if (mw_tmp && mw_tmp->otyp == obj->otyp) { /* already wielding it */ mon->weapon_check = NEED_WEAPON; return 0; } /* Actually, this isn't necessary--as soon as the monster * wields the weapon, the weapon welds itself, so the monster * can know it's cursed and needn't even bother trying. * Still.... */ if (mw_tmp && mw_tmp->cursed && mw_tmp->otyp != CORPSE) { if (canseemon(mon)) { char welded_buf[BUFSZ]; const char *mon_hand = mbodypart(mon, HAND); if (bimanual(mw_tmp)) mon_hand = makeplural(mon_hand); Sprintf(welded_buf, "%s welded to %s %s", otense(mw_tmp, "are"), mhis(mon), mon_hand); if (obj->otyp == PICK_AXE) { pline("Since %s weapon%s %s,", s_suffix(mon_nam(mon)), plur(mw_tmp->quan), welded_buf); pline("%s cannot wield that %s.", mon_nam(mon), xname(obj)); } else { pline("%s tries to wield %s.", Monnam(mon), doname(obj)); pline("%s %s %s!", s_suffix(Monnam(mon)), xname(mw_tmp), welded_buf); } mw_tmp->bknown = 1; } mon->weapon_check = NO_WEAPON_WANTED; return 1; } mon->mw = obj; /* wield obj */ setmnotwielded(mon, mw_tmp); mon->weapon_check = NEED_WEAPON; if (canseemon(mon)) { pline("%s wields %s!", Monnam(mon), doname(obj)); if (obj->cursed && obj->otyp != CORPSE) { pline("%s %s to %s %s!", Tobjnam(obj, "weld"), is_plural(obj) ? "themselves" : "itself", s_suffix(mon_nam(mon)), mbodypart(mon,HAND)); obj->bknown = 1; } } if (artifact_light(obj) && !obj->lamplit) { begin_burn(obj, FALSE); if (canseemon(mon)) pline("%s brilliantly in %s %s!", Tobjnam(obj, "glow"), s_suffix(mon_nam(mon)), mbodypart(mon,HAND)); } obj->owornmask = W_WEP; return 1; } mon->weapon_check = NEED_WEAPON; return 0; } int abon() /* attack bonus for strength & dexterity */ { int sbon; int str = ACURR(A_STR), dex = ACURR(A_DEX); if (Upolyd) return(adj_lev(&mons[u.umonnum]) - 3); if (str < 6) sbon = -2; else if (str < 8) sbon = -1; else if (str < 17) sbon = 0; else if (str <= STR18(50)) sbon = 1; /* up to 18/50 */ else if (str < STR18(100)) sbon = 2; else sbon = 3; /* Game tuning kludge: make it a bit easier for a low level character to hit */ sbon += (u.ulevel < 3) ? 1 : 0; if (dex < 4) return(sbon-3); else if (dex < 6) return(sbon-2); else if (dex < 8) return(sbon-1); else if (dex < 14) return(sbon); else return(sbon + dex-14); } #endif /* OVL0 */ #ifdef OVL1 int dbon() /* damage bonus for strength */ { int str = ACURR(A_STR); if (Upolyd) return(0); if (str < 6) return(-1); else if (str < 16) return(0); else if (str < 18) return(1); else if (str == 18) return(2); /* up to 18 */ else if (str <= STR18(75)) return(3); /* up to 18/75 */ else if (str <= STR18(90)) return(4); /* up to 18/90 */ else if (str < STR18(100)) return(5); /* up to 18/99 */ else return(6); } /* copy the skill level name into the given buffer */ STATIC_OVL char * skill_level_name(skill, buf) int skill; char *buf; { const char *ptr; switch (P_SKILL(skill)) { case P_UNSKILLED: ptr = "Unskilled"; break; case P_BASIC: ptr = "Basic"; break; case P_SKILLED: ptr = "Skilled"; break; case P_EXPERT: ptr = "Expert"; break; /* these are for unarmed combat/martial arts only */ case P_MASTER: ptr = "Master"; break; case P_GRAND_MASTER: ptr = "Grand Master"; break; default: ptr = "Unknown"; break; } Strcpy(buf, ptr); return buf; } /* return the # of slots required to advance the skill */ STATIC_OVL int slots_required(skill) int skill; { int tmp = P_SKILL(skill); /* The more difficult the training, the more slots it takes. * unskilled -> basic 1 * basic -> skilled 2 * skilled -> expert 3 */ if (skill <= P_LAST_WEAPON || skill == P_TWO_WEAPON_COMBAT) return tmp; /* Fewer slots used up for unarmed or martial. * unskilled -> basic 1 * basic -> skilled 1 * skilled -> expert 2 * expert -> master 2 * master -> grand master 3 */ return (tmp + 1) / 2; } /* return true if this skill can be advanced */ /*ARGSUSED*/ STATIC_OVL boolean can_advance(skill, speedy) int skill; boolean speedy; { return !P_RESTRICTED(skill) && P_SKILL(skill) < P_MAX_SKILL(skill) && ( #ifdef WIZARD (wizard && speedy) || #endif (P_ADVANCE(skill) >= (unsigned) practice_needed_to_advance(P_SKILL(skill)) && u.skills_advanced < P_SKILL_LIMIT && u.weapon_slots >= slots_required(skill))); } /* return true if this skill could be advanced if more slots were available */ STATIC_OVL boolean could_advance(skill) int skill; { return !P_RESTRICTED(skill) && P_SKILL(skill) < P_MAX_SKILL(skill) && ( (P_ADVANCE(skill) >= (unsigned) practice_needed_to_advance(P_SKILL(skill)) && u.skills_advanced < P_SKILL_LIMIT)); } /* return true if this skill has reached its maximum and there's been enough practice to become eligible for the next step if that had been possible */ STATIC_OVL boolean peaked_skill(skill) int skill; { return !P_RESTRICTED(skill) && P_SKILL(skill) >= P_MAX_SKILL(skill) && ( (P_ADVANCE(skill) >= (unsigned) practice_needed_to_advance(P_SKILL(skill)))); } STATIC_OVL void skill_advance(skill) int skill; { u.weapon_slots -= slots_required(skill); P_SKILL(skill)++; u.skill_record[u.skills_advanced++] = skill; /* subtly change the advance message to indicate no more advancement */ You("are now %s skilled in %s.", P_SKILL(skill) >= P_MAX_SKILL(skill) ? "most" : "more", P_NAME(skill)); } const static struct skill_range { short first, last; const char *name; } skill_ranges[] = { { P_FIRST_H_TO_H, P_LAST_H_TO_H, "Fighting Skills" }, { P_FIRST_WEAPON, P_LAST_WEAPON, "Weapon Skills" }, { P_FIRST_SPELL, P_LAST_SPELL, "Spellcasting Skills" }, }; /* * The `#enhance' extended command. What we _really_ would like is * to keep being able to pick things to advance until we couldn't any * more. This is currently not possible -- the menu code has no way * to call us back for instant action. Even if it did, we would also need * to be able to update the menu since selecting one item could make * others unselectable. */ int enhance_weapon_skill() { int pass, i, n, len, longest, to_advance, eventually_advance, maxxed_cnt; char buf[BUFSZ], sklnambuf[BUFSZ]; const char *prefix; menu_item *selected; anything any; winid win; boolean speedy = FALSE; #ifdef WIZARD if (wizard && yn("Advance skills without practice?") == 'y') speedy = TRUE; #endif do { /* find longest available skill name, count those that can advance */ to_advance = eventually_advance = maxxed_cnt = 0; for (longest = 0, i = 0; i < P_NUM_SKILLS; i++) { if (P_RESTRICTED(i)) continue; if ((len = strlen(P_NAME(i))) > longest) longest = len; if (can_advance(i, speedy)) to_advance++; else if (could_advance(i)) eventually_advance++; else if (peaked_skill(i)) maxxed_cnt++; } win = create_nhwindow(NHW_MENU); start_menu(win); /* start with a legend if any entries will be annotated with "*" or "#" below */ if (eventually_advance > 0 || maxxed_cnt > 0) { any.a_void = 0; if (eventually_advance > 0) { Sprintf(buf, "(Skill%s flagged by \"*\" may be enhanced %s.)", plur(eventually_advance), (u.ulevel < MAXULEV) ? "when you're more experienced" : "if skill slots become available"); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } if (maxxed_cnt > 0) { Sprintf(buf, "(Skill%s flagged by \"#\" cannot be enhanced any further.)", plur(maxxed_cnt)); add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); } /* List the skills, making ones that could be advanced selectable. List the miscellaneous skills first. Possible future enhancement: list spell skills before weapon skills for spellcaster roles. */ for (pass = 0; pass < SIZE(skill_ranges); pass++) for (i = skill_ranges[pass].first; i <= skill_ranges[pass].last; i++) { /* Print headings for skill types */ any.a_void = 0; if (i == skill_ranges[pass].first) add_menu(win, NO_GLYPH, &any, 0, 0, iflags.menu_headings, skill_ranges[pass].name, MENU_UNSELECTED); if (P_RESTRICTED(i)) continue; /* * Sigh, this assumes a monospaced font unless * iflags.menu_tab_sep is set in which case it puts * tabs between columns. * The 12 is the longest skill level name. * The " " is room for a selection letter and dash, "a - ". */ if (can_advance(i, speedy)) prefix = ""; /* will be preceded by menu choice */ else if (could_advance(i)) prefix = " * "; else if (peaked_skill(i)) prefix = " # "; else prefix = (to_advance + eventually_advance + maxxed_cnt > 0) ? " " : ""; (void) skill_level_name(i, sklnambuf); #ifdef WIZARD if (wizard) { if (!iflags.menu_tab_sep) Sprintf(buf, " %s%-*s %-12s %5d(%4d)", prefix, longest, P_NAME(i), sklnambuf, P_ADVANCE(i), practice_needed_to_advance(P_SKILL(i))); else Sprintf(buf, " %s%s\t%s\t%5d(%4d)", prefix, P_NAME(i), sklnambuf, P_ADVANCE(i), practice_needed_to_advance(P_SKILL(i))); } else #endif { if (!iflags.menu_tab_sep) Sprintf(buf, " %s %-*s [%s]", prefix, longest, P_NAME(i), sklnambuf); else Sprintf(buf, " %s%s\t[%s]", prefix, P_NAME(i), sklnambuf); } any.a_int = can_advance(i, speedy) ? i+1 : 0; add_menu(win, NO_GLYPH, &any, 0, 0, ATR_NONE, buf, MENU_UNSELECTED); } Strcpy(buf, (to_advance > 0) ? "Pick a skill to advance:" : "Current skills:"); #ifdef WIZARD if (wizard && !speedy) Sprintf(eos(buf), " (%d slot%s available)", u.weapon_slots, plur(u.weapon_slots)); #endif end_menu(win, buf); n = select_menu(win, to_advance ? PICK_ONE : PICK_NONE, &selected); destroy_nhwindow(win); if (n > 0) { n = selected[0].item.a_int - 1; /* get item selected */ free((genericptr_t)selected); skill_advance(n); /* check for more skills able to advance, if so then .. */ for (n = i = 0; i < P_NUM_SKILLS; i++) { if (can_advance(i, speedy)) { if (!speedy) You_feel("you could be more dangerous!"); n++; break; } } } } while (speedy && n > 0); return 0; } /* * Change from restricted to unrestricted, allowing P_BASIC as max. This * function may be called with with P_NONE. Used in pray.c. */ void unrestrict_weapon_skill(skill) int skill; { if (skill < P_NUM_SKILLS && P_RESTRICTED(skill)) { P_SKILL(skill) = P_UNSKILLED; P_MAX_SKILL(skill) = P_BASIC; P_ADVANCE(skill) = 0; } } #endif /* OVL1 */ #ifdef OVLB void use_skill(skill,degree) int skill; int degree; { boolean advance_before; if (skill != P_NONE && !P_RESTRICTED(skill)) { advance_before = can_advance(skill, FALSE); P_ADVANCE(skill)+=degree; if (!advance_before && can_advance(skill, FALSE)) give_may_advance_msg(skill); } } void add_weapon_skill(n) int n; /* number of slots to gain; normally one */ { int i, before, after; for (i = 0, before = 0; i < P_NUM_SKILLS; i++) if (can_advance(i, FALSE)) before++; u.weapon_slots += n; for (i = 0, after = 0; i < P_NUM_SKILLS; i++) if (can_advance(i, FALSE)) after++; if (before < after) give_may_advance_msg(P_NONE); } void lose_weapon_skill(n) int n; /* number of slots to lose; normally one */ { int skill; while (--n >= 0) { /* deduct first from unused slots, then from last placed slot, if any */ if (u.weapon_slots) { u.weapon_slots--; } else if (u.skills_advanced) { skill = u.skill_record[--u.skills_advanced]; if (P_SKILL(skill) <= P_UNSKILLED) panic("lose_weapon_skill (%d)", skill); P_SKILL(skill)--; /* drop skill one level */ /* Lost skill might have taken more than one slot; refund rest. */ u.weapon_slots = slots_required(skill) - 1; /* It might now be possible to advance some other pending skill by using the refunded slots, but giving a message to that effect would seem pretty confusing.... */ } } } int weapon_type(obj) struct obj *obj; { /* KMH -- now uses the object table */ int type; if (!obj) /* Not using a weapon */ return (P_BARE_HANDED_COMBAT); if (obj->oclass != WEAPON_CLASS && obj->oclass != TOOL_CLASS && obj->oclass != GEM_CLASS) /* Not a weapon, weapon-tool, or ammo */ return (P_NONE); type = objects[obj->otyp].oc_skill; return ((type < 0) ? -type : type); } int uwep_skill_type() { if (u.twoweap) return P_TWO_WEAPON_COMBAT; return weapon_type(uwep); } /* * Return hit bonus/penalty based on skill of weapon. * Treat restricted weapons as unskilled. */ int weapon_hit_bonus(weapon) struct obj *weapon; { int type, wep_type, skill, bonus = 0; static const char bad_skill[] = "weapon_hit_bonus: bad skill %d"; wep_type = weapon_type(weapon); /* use two weapon skill only if attacking with one of the wielded weapons */ type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ? P_TWO_WEAPON_COMBAT : wep_type; if (type == P_NONE) { bonus = 0; } else if (type <= P_LAST_WEAPON) { switch (P_SKILL(type)) { default: impossible(bad_skill, P_SKILL(type)); /* fall through */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -4; break; case P_BASIC: bonus = 0; break; case P_SKILLED: bonus = 2; break; case P_EXPERT: bonus = 3; break; } } else if (type == P_TWO_WEAPON_COMBAT) { skill = P_SKILL(P_TWO_WEAPON_COMBAT); if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type); switch (skill) { default: impossible(bad_skill, skill); /* fall through */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -9; break; case P_BASIC: bonus = -7; break; case P_SKILLED: bonus = -5; break; case P_EXPERT: bonus = -3; break; } } else if (type == P_BARE_HANDED_COMBAT) { /* * b.h. m.a. * unskl: +1 n/a * basic: +1 +3 * skild: +2 +4 * exprt: +2 +5 * mastr: +3 +6 * grand: +3 +7 */ bonus = P_SKILL(type); bonus = max(bonus,P_UNSKILLED) - 1; /* unskilled => 0 */ bonus = ((bonus + 2) * (martial_bonus() ? 2 : 1)) / 2; } #ifdef STEED /* KMH -- It's harder to hit while you are riding */ if (u.usteed) { switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: bonus -= 2; break; case P_BASIC: bonus -= 1; break; case P_SKILLED: break; case P_EXPERT: break; } if (u.twoweap) bonus -= 2; } #endif return bonus; } /* * Return damage bonus/penalty based on skill of weapon. * Treat restricted weapons as unskilled. */ int weapon_dam_bonus(weapon) struct obj *weapon; { int type, wep_type, skill, bonus = 0; wep_type = weapon_type(weapon); /* use two weapon skill only if attacking with one of the wielded weapons */ type = (u.twoweap && (weapon == uwep || weapon == uswapwep)) ? P_TWO_WEAPON_COMBAT : wep_type; if (type == P_NONE) { bonus = 0; } else if (type <= P_LAST_WEAPON) { switch (P_SKILL(type)) { default: impossible("weapon_dam_bonus: bad skill %d",P_SKILL(type)); /* fall through */ case P_ISRESTRICTED: case P_UNSKILLED: bonus = -2; break; case P_BASIC: bonus = 0; break; case P_SKILLED: bonus = 1; break; case P_EXPERT: bonus = 2; break; } } else if (type == P_TWO_WEAPON_COMBAT) { skill = P_SKILL(P_TWO_WEAPON_COMBAT); if (P_SKILL(wep_type) < skill) skill = P_SKILL(wep_type); switch (skill) { default: case P_ISRESTRICTED: case P_UNSKILLED: bonus = -3; break; case P_BASIC: bonus = -1; break; case P_SKILLED: bonus = 0; break; case P_EXPERT: bonus = 1; break; } } else if (type == P_BARE_HANDED_COMBAT) { /* * b.h. m.a. * unskl: 0 n/a * basic: +1 +3 * skild: +1 +4 * exprt: +2 +6 * mastr: +2 +7 * grand: +3 +9 */ bonus = P_SKILL(type); bonus = max(bonus,P_UNSKILLED) - 1; /* unskilled => 0 */ bonus = ((bonus + 1) * (martial_bonus() ? 3 : 1)) / 2; } #ifdef STEED /* KMH -- Riding gives some thrusting damage */ if (u.usteed && type != P_TWO_WEAPON_COMBAT) { switch (P_SKILL(P_RIDING)) { case P_ISRESTRICTED: case P_UNSKILLED: break; case P_BASIC: break; case P_SKILLED: bonus += 1; break; case P_EXPERT: bonus += 2; break; } } #endif return bonus; } /* * Initialize weapon skill array for the game. Start by setting all * skills to restricted, then set the skill for every weapon the * hero is holding, finally reading the given array that sets * maximums. */ void skill_init(class_skill) const struct def_skill *class_skill; { struct obj *obj; int skmax, skill; /* initialize skill array; by default, everything is restricted */ for (skill = 0; skill < P_NUM_SKILLS; skill++) { P_SKILL(skill) = P_ISRESTRICTED; P_MAX_SKILL(skill) = P_ISRESTRICTED; P_ADVANCE(skill) = 0; } /* Set skill for all weapons in inventory to be basic */ for (obj = invent; obj; obj = obj->nobj) { skill = weapon_type(obj); if (skill != P_NONE) P_SKILL(skill) = P_BASIC; } /* set skills for magic */ if (Role_if(PM_HEALER) || Role_if(PM_MONK)) { P_SKILL(P_HEALING_SPELL) = P_BASIC; } else if (Role_if(PM_PRIEST)) { P_SKILL(P_CLERIC_SPELL) = P_BASIC; } else if (Role_if(PM_WIZARD)) { P_SKILL(P_ATTACK_SPELL) = P_BASIC; P_SKILL(P_ENCHANTMENT_SPELL) = P_BASIC; } /* walk through array to set skill maximums */ for (; class_skill->skill != P_NONE; class_skill++) { skmax = class_skill->skmax; skill = class_skill->skill; P_MAX_SKILL(skill) = skmax; if (P_SKILL(skill) == P_ISRESTRICTED) /* skill pre-set */ P_SKILL(skill) = P_UNSKILLED; } /* High potential fighters already know how to use their hands. */ if (P_MAX_SKILL(P_BARE_HANDED_COMBAT) > P_EXPERT) P_SKILL(P_BARE_HANDED_COMBAT) = P_BASIC; /* Roles that start with a horse know how to ride it */ #ifdef STEED if (urole.petnum == PM_PONY) P_SKILL(P_RIDING) = P_BASIC; #endif /* * Make sure we haven't missed setting the max on a skill * & set advance */ for (skill = 0; skill < P_NUM_SKILLS; skill++) { if (!P_RESTRICTED(skill)) { if (P_MAX_SKILL(skill) < P_SKILL(skill)) { impossible("skill_init: curr > max: %s", P_NAME(skill)); P_MAX_SKILL(skill) = P_SKILL(skill); } P_ADVANCE(skill) = practice_needed_to_advance(P_SKILL(skill)-1); } } } void setmnotwielded(mon,obj) register struct monst *mon; register struct obj *obj; { if (!obj) return; if (artifact_light(obj) && obj->lamplit) { end_burn(obj, FALSE); if (canseemon(mon)) pline("%s in %s %s %s glowing.", The(xname(obj)), s_suffix(mon_nam(mon)), mbodypart(mon,HAND), otense(obj, "stop")); } obj->owornmask &= ~W_WEP; } #endif /* OVLB */ /*weapon.c*/ nethack-3.4.3/src/were.c0100644000000000000000000000760007764735041013552 0ustar rootroot/* SCCS Id: @(#)were.c 3.4 2002/11/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef OVL0 void were_change(mon) register struct monst *mon; { if (!is_were(mon->data)) return; if (is_human(mon->data)) { if (!Protection_from_shape_changers && !rn2(night() ? (flags.moonphase == FULL_MOON ? 3 : 30) : (flags.moonphase == FULL_MOON ? 10 : 50))) { new_were(mon); /* change into animal form */ if (flags.soundok && !canseemon(mon)) { const char *howler; switch (monsndx(mon->data)) { case PM_WEREWOLF: howler = "wolf"; break; case PM_WEREJACKAL: howler = "jackal"; break; default: howler = (char *)0; break; } if (howler) You_hear("a %s howling at the moon.", howler); } } } else if (!rn2(30) || Protection_from_shape_changers) { new_were(mon); /* change back into human form */ } } #endif /* OVL0 */ #ifdef OVLB STATIC_DCL int FDECL(counter_were,(int)); STATIC_OVL int counter_were(pm) int pm; { switch(pm) { case PM_WEREWOLF: return(PM_HUMAN_WEREWOLF); case PM_HUMAN_WEREWOLF: return(PM_WEREWOLF); case PM_WEREJACKAL: return(PM_HUMAN_WEREJACKAL); case PM_HUMAN_WEREJACKAL: return(PM_WEREJACKAL); case PM_WERERAT: return(PM_HUMAN_WERERAT); case PM_HUMAN_WERERAT: return(PM_WERERAT); default: return(0); } } void new_were(mon) register struct monst *mon; { register int pm; pm = counter_were(monsndx(mon->data)); if(!pm) { impossible("unknown lycanthrope %s.", mon->data->mname); return; } if(canseemon(mon) && !Hallucination) pline("%s changes into a %s.", Monnam(mon), is_human(&mons[pm]) ? "human" : mons[pm].mname+4); set_mon_data(mon, &mons[pm], 0); if (mon->msleeping || !mon->mcanmove) { /* transformation wakens and/or revitalizes */ mon->msleeping = 0; mon->mfrozen = 0; /* not asleep or paralyzed */ mon->mcanmove = 1; } /* regenerate by 1/4 of the lost hit points */ mon->mhp += (mon->mhpmax - mon->mhp) / 4; newsym(mon->mx,mon->my); mon_break_armor(mon, FALSE); possibly_unwield(mon, FALSE); } int were_summon(ptr,yours,visible,genbuf) /* were-creature (even you) summons a horde */ register struct permonst *ptr; register boolean yours; int *visible; /* number of visible helpers created */ char *genbuf; { register int i, typ, pm = monsndx(ptr); register struct monst *mtmp; int total = 0; *visible = 0; if(Protection_from_shape_changers && !yours) return 0; for(i = rnd(5); i > 0; i--) { switch(pm) { case PM_WERERAT: case PM_HUMAN_WERERAT: typ = rn2(3) ? PM_SEWER_RAT : rn2(3) ? PM_GIANT_RAT : PM_RABID_RAT ; if (genbuf) Strcpy(genbuf, "rat"); break; case PM_WEREJACKAL: case PM_HUMAN_WEREJACKAL: typ = PM_JACKAL; if (genbuf) Strcpy(genbuf, "jackal"); break; case PM_WEREWOLF: case PM_HUMAN_WEREWOLF: typ = rn2(5) ? PM_WOLF : PM_WINTER_WOLF ; if (genbuf) Strcpy(genbuf, "wolf"); break; default: continue; } mtmp = makemon(&mons[typ], u.ux, u.uy, NO_MM_FLAGS); if (mtmp) { total++; if (canseemon(mtmp)) *visible += 1; } if (yours && mtmp) (void) tamedog(mtmp, (struct obj *) 0); } return total; } void you_were() { char qbuf[QBUFSZ]; if (Unchanging || (u.umonnum == u.ulycn)) return; if (Polymorph_control) { /* `+4' => skip "were" prefix to get name of beast */ Sprintf(qbuf, "Do you want to change into %s? ", an(mons[u.ulycn].mname+4)); if(yn(qbuf) == 'n') return; } (void) polymon(u.ulycn); } void you_unwere(purify) boolean purify; { if (purify) { You_feel("purified."); u.ulycn = NON_PM; /* cure lycanthropy */ } if (!Unchanging && is_were(youmonst.data) && (!Polymorph_control || yn("Remain in beast form?") == 'n')) rehumanize(); } #endif /* OVLB */ /*were.c*/ nethack-3.4.3/src/wield.c0100644000000000000000000005267407764735041013727 0ustar rootroot/* SCCS Id: @(#)wield.c 3.4 2003/01/29 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* KMH -- Differences between the three weapon slots. * * The main weapon (uwep): * 1. Is filled by the (w)ield command. * 2. Can be filled with any type of item. * 3. May be carried in one or both hands. * 4. Is used as the melee weapon and as the launcher for * ammunition. * 5. Only conveys intrinsics when it is a weapon, weapon-tool, * or artifact. * 6. Certain cursed items will weld to the hand and cannot be * unwielded or dropped. See erodeable_wep() and will_weld() * below for the list of which items apply. * * The secondary weapon (uswapwep): * 1. Is filled by the e(x)change command, which swaps this slot * with the main weapon. If the "pushweapon" option is set, * the (w)ield command will also store the old weapon in the * secondary slot. * 2. Can be field with anything that will fit in the main weapon * slot; that is, any type of item. * 3. Is usually NOT considered to be carried in the hands. * That would force too many checks among the main weapon, * second weapon, shield, gloves, and rings; and it would * further be complicated by bimanual weapons. A special * exception is made for two-weapon combat. * 4. Is used as the second weapon for two-weapon combat, and as * a convenience to swap with the main weapon. * 5. Never conveys intrinsics. * 6. Cursed items never weld (see #3 for reasons), but they also * prevent two-weapon combat. * * The quiver (uquiver): * 1. Is filled by the (Q)uiver command. * 2. Can be filled with any type of item. * 3. Is considered to be carried in a special part of the pack. * 4. Is used as the item to throw with the (f)ire command. * This is a convenience over the normal (t)hrow command. * 5. Never conveys intrinsics. * 6. Cursed items never weld; their effect is handled by the normal * throwing code. * * No item may be in more than one of these slots. */ STATIC_DCL int FDECL(ready_weapon, (struct obj *)); /* used by will_weld() */ /* probably should be renamed */ #define erodeable_wep(optr) ((optr)->oclass == WEAPON_CLASS \ || is_weptool(optr) \ || (optr)->otyp == HEAVY_IRON_BALL \ || (optr)->otyp == IRON_CHAIN) /* used by welded(), and also while wielding */ #define will_weld(optr) ((optr)->cursed \ && (erodeable_wep(optr) \ || (optr)->otyp == TIN_OPENER)) /*** Functions that place a given item in a slot ***/ /* Proper usage includes: * 1. Initializing the slot during character generation or a * restore. * 2. Setting the slot due to a player's actions. * 3. If one of the objects in the slot are split off, these * functions can be used to put the remainder back in the slot. * 4. Putting an item that was thrown and returned back into the slot. * 5. Emptying the slot, by passing a null object. NEVER pass * zeroobj! * * If the item is being moved from another slot, it is the caller's * responsibility to handle that. It's also the caller's responsibility * to print the appropriate messages. */ void setuwep(obj) register struct obj *obj; { struct obj *olduwep = uwep; if (obj == uwep) return; /* necessary to not set unweapon */ /* This message isn't printed in the caller because it happens * *whenever* Sunsword is unwielded, from whatever cause. */ setworn(obj, W_WEP); if (uwep == obj && artifact_light(olduwep) && olduwep->lamplit) { end_burn(olduwep, FALSE); if (!Blind) pline("%s glowing.", Tobjnam(olduwep, "stop")); } /* Note: Explicitly wielding a pick-axe will not give a "bashing" * message. Wielding one via 'a'pplying it will. * 3.2.2: Wielding arbitrary objects will give bashing message too. */ if (obj) { unweapon = (obj->oclass == WEAPON_CLASS) ? is_launcher(obj) || is_ammo(obj) || is_missile(obj) || (is_pole(obj) #ifdef STEED && !u.usteed #endif ) : !is_weptool(obj); } else unweapon = TRUE; /* for "bare hands" message */ update_inventory(); } STATIC_OVL int ready_weapon(wep) struct obj *wep; { /* Separated function so swapping works easily */ int res = 0; if (!wep) { /* No weapon */ if (uwep) { You("are empty %s.", body_part(HANDED)); setuwep((struct obj *) 0); res++; } else You("are already empty %s.", body_part(HANDED)); } else if (!uarmg && !Stone_resistance && wep->otyp == CORPSE && touch_petrifies(&mons[wep->corpsenm])) { /* Prevent wielding cockatrice when not wearing gloves --KAA */ char kbuf[BUFSZ]; You("wield the %s corpse in your bare %s.", mons[wep->corpsenm].mname, makeplural(body_part(HAND))); Sprintf(kbuf, "%s corpse", an(mons[wep->corpsenm].mname)); instapetrify(kbuf); } else if (uarms && bimanual(wep)) You("cannot wield a two-handed %s while wearing a shield.", is_sword(wep) ? "sword" : wep->otyp == BATTLE_AXE ? "axe" : "weapon"); else if (wep->oartifact && !touch_artifact(wep, &youmonst)) { res++; /* takes a turn even though it doesn't get wielded */ } else { /* Weapon WILL be wielded after this point */ res++; if (will_weld(wep)) { const char *tmp = xname(wep), *thestr = "The "; if (strncmp(tmp, thestr, 4) && !strncmp(The(tmp),thestr,4)) tmp = thestr; else tmp = ""; pline("%s%s %s to your %s!", tmp, aobjnam(wep, "weld"), (wep->quan == 1L) ? "itself" : "themselves", /* a3 */ bimanual(wep) ? (const char *)makeplural(body_part(HAND)) : body_part(HAND)); wep->bknown = TRUE; } else { /* The message must be printed before setuwep (since * you might die and be revived from changing weapons), * and the message must be before the death message and * Lifesaved rewielding. Yet we want the message to * say "weapon in hand", thus this kludge. */ long dummy = wep->owornmask; wep->owornmask |= W_WEP; prinv((char *)0, wep, 0L); wep->owornmask = dummy; } setuwep(wep); /* KMH -- Talking artifacts are finally implemented */ arti_speak(wep); if (artifact_light(wep) && !wep->lamplit) { begin_burn(wep, FALSE); if (!Blind) pline("%s to glow brilliantly!", Tobjnam(wep, "begin")); } #if 0 /* we'll get back to this someday, but it's not balanced yet */ if (Race_if(PM_ELF) && !wep->oartifact && objects[wep->otyp].oc_material == IRON) { /* Elves are averse to wielding cold iron */ You("have an uneasy feeling about wielding cold iron."); change_luck(-1); } #endif if (wep->unpaid) { struct monst *this_shkp; if ((this_shkp = shop_keeper(inside_shop(u.ux, u.uy))) != (struct monst *)0) { pline("%s says \"You be careful with my %s!\"", shkname(this_shkp), xname(wep)); } } } return(res); } void setuqwep(obj) register struct obj *obj; { setworn(obj, W_QUIVER); update_inventory(); } void setuswapwep(obj) register struct obj *obj; { setworn(obj, W_SWAPWEP); update_inventory(); } /*** Commands to change particular slot(s) ***/ static NEARDATA const char wield_objs[] = { ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, TOOL_CLASS, 0 }; static NEARDATA const char ready_objs[] = { ALL_CLASSES, ALLOW_NONE, WEAPON_CLASS, 0 }; static NEARDATA const char bullets[] = /* (note: different from dothrow.c) */ { ALL_CLASSES, ALLOW_NONE, GEM_CLASS, WEAPON_CLASS, 0 }; int dowield() { register struct obj *wep, *oldwep; int result; /* May we attempt this? */ multi = 0; if (cantwield(youmonst.data)) { pline("Don't be ridiculous!"); return(0); } /* Prompt for a new weapon */ if (!(wep = getobj(wield_objs, "wield"))) /* Cancelled */ return (0); else if (wep == uwep) { You("are already wielding that!"); if (is_weptool(wep)) unweapon = FALSE; /* [see setuwep()] */ return (0); } else if (welded(uwep)) { weldmsg(uwep); /* previously interrupted armor removal mustn't be resumed */ reset_remarm(); return (0); } /* Handle no object, or object in other slot */ if (wep == &zeroobj) wep = (struct obj *) 0; else if (wep == uswapwep) return (doswapweapon()); else if (wep == uquiver) setuqwep((struct obj *) 0); else if (wep->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL #ifdef STEED | W_SADDLE #endif )) { You("cannot wield that!"); return (0); } /* Set your new primary weapon */ oldwep = uwep; result = ready_weapon(wep); if (flags.pushweapon && oldwep && uwep != oldwep) setuswapwep(oldwep); untwoweapon(); return (result); } int doswapweapon() { register struct obj *oldwep, *oldswap; int result = 0; /* May we attempt this? */ multi = 0; if (cantwield(youmonst.data)) { pline("Don't be ridiculous!"); return(0); } if (welded(uwep)) { weldmsg(uwep); return (0); } /* Unwield your current secondary weapon */ oldwep = uwep; oldswap = uswapwep; setuswapwep((struct obj *) 0); /* Set your new primary weapon */ result = ready_weapon(oldswap); /* Set your new secondary weapon */ if (uwep == oldwep) /* Wield failed for some reason */ setuswapwep(oldswap); else { setuswapwep(oldwep); if (uswapwep) prinv((char *)0, uswapwep, 0L); else You("have no secondary weapon readied."); } if (u.twoweap && !can_twoweapon()) untwoweapon(); return (result); } int dowieldquiver() { register struct obj *newquiver; const char *quivee_types = (uslinging() || (uswapwep && objects[uswapwep->otyp].oc_skill == P_SLING)) ? bullets : ready_objs; /* Since the quiver isn't in your hands, don't check cantwield(), */ /* will_weld(), touch_petrifies(), etc. */ multi = 0; /* Because 'Q' used to be quit... */ if (flags.suppress_alert < FEATURE_NOTICE_VER(3,3,0)) pline("Note: Please use #quit if you wish to exit the game."); /* Prompt for a new quiver */ if (!(newquiver = getobj(quivee_types, "ready"))) /* Cancelled */ return (0); /* Handle no object, or object in other slot */ /* Any type is okay, since we give no intrinsics anyways */ if (newquiver == &zeroobj) { /* Explicitly nothing */ if (uquiver) { You("now have no ammunition readied."); setuqwep(newquiver = (struct obj *) 0); } else { You("already have no ammunition readied!"); return(0); } } else if (newquiver == uquiver) { pline("That ammunition is already readied!"); return(0); } else if (newquiver == uwep) { /* Prevent accidentally readying the main weapon */ pline("%s already being used as a weapon!", !is_plural(uwep) ? "That is" : "They are"); return(0); } else if (newquiver->owornmask & (W_ARMOR | W_RING | W_AMUL | W_TOOL #ifdef STEED | W_SADDLE #endif )) { You("cannot ready that!"); return (0); } else { long dummy; /* Check if it's the secondary weapon */ if (newquiver == uswapwep) { setuswapwep((struct obj *) 0); untwoweapon(); } /* Okay to put in quiver; print it */ dummy = newquiver->owornmask; newquiver->owornmask |= W_QUIVER; prinv((char *)0, newquiver, 0L); newquiver->owornmask = dummy; } /* Finally, place it in the quiver */ setuqwep(newquiver); /* Take no time since this is a convenience slot */ return (0); } /* used for #rub and for applying pick-axe, whip, grappling hook, or polearm */ /* (moved from apply.c) */ boolean wield_tool(obj, verb) struct obj *obj; const char *verb; /* "rub",&c */ { const char *what; boolean more_than_1; if (obj == uwep) return TRUE; /* nothing to do if already wielding it */ if (!verb) verb = "wield"; what = xname(obj); more_than_1 = (obj->quan > 1L || strstri(what, "pair of ") != 0 || strstri(what, "s of ") != 0); if (obj->owornmask & (W_ARMOR|W_RING|W_AMUL|W_TOOL)) { char yourbuf[BUFSZ]; You_cant("%s %s %s while wearing %s.", verb, shk_your(yourbuf, obj), what, more_than_1 ? "them" : "it"); return FALSE; } if (welded(uwep)) { if (flags.verbose) { const char *hand = body_part(HAND); if (bimanual(uwep)) hand = makeplural(hand); if (strstri(what, "pair of ") != 0) more_than_1 = FALSE; pline( "Since your weapon is welded to your %s, you cannot %s %s %s.", hand, verb, more_than_1 ? "those" : "that", xname(obj)); } else { You_cant("do that."); } return FALSE; } if (cantwield(youmonst.data)) { You_cant("hold %s strongly enough.", more_than_1 ? "them" : "it"); return FALSE; } /* check shield */ if (uarms && bimanual(obj)) { You("cannot %s a two-handed %s while wearing a shield.", verb, (obj->oclass == WEAPON_CLASS) ? "weapon" : "tool"); return FALSE; } if (uquiver == obj) setuqwep((struct obj *)0); if (uswapwep == obj) { (void) doswapweapon(); /* doswapweapon might fail */ if (uswapwep == obj) return FALSE; } else { You("now wield %s.", doname(obj)); setuwep(obj); } if (uwep != obj) return FALSE; /* rewielded old object after dying */ /* applying weapon or tool that gets wielded ends two-weapon combat */ if (u.twoweap) untwoweapon(); if (obj->oclass != WEAPON_CLASS) unweapon = TRUE; return TRUE; } int can_twoweapon() { struct obj *otmp; #define NOT_WEAPON(obj) (!is_weptool(obj) && obj->oclass != WEAPON_CLASS) if (!could_twoweap(youmonst.data)) { if (Upolyd) You_cant("use two weapons in your current form."); else pline("%s aren't able to use two weapons at once.", makeplural((flags.female && urole.name.f) ? urole.name.f : urole.name.m)); } else if (!uwep || !uswapwep) Your("%s%s%s empty.", uwep ? "left " : uswapwep ? "right " : "", body_part(HAND), (!uwep && !uswapwep) ? "s are" : " is"); else if (NOT_WEAPON(uwep) || NOT_WEAPON(uswapwep)) { otmp = NOT_WEAPON(uwep) ? uwep : uswapwep; pline("%s %s.", Yname2(otmp), is_plural(otmp) ? "aren't weapons" : "isn't a weapon"); } else if (bimanual(uwep) || bimanual(uswapwep)) { otmp = bimanual(uwep) ? uwep : uswapwep; pline("%s isn't one-handed.", Yname2(otmp)); } else if (uarms) You_cant("use two weapons while wearing a shield."); else if (uswapwep->oartifact) pline("%s %s being held second to another weapon!", Yname2(uswapwep), otense(uswapwep, "resist")); else if (!uarmg && !Stone_resistance && (uswapwep->otyp == CORPSE && touch_petrifies(&mons[uswapwep->corpsenm]))) { char kbuf[BUFSZ]; You("wield the %s corpse with your bare %s.", mons[uswapwep->corpsenm].mname, body_part(HAND)); Sprintf(kbuf, "%s corpse", an(mons[uswapwep->corpsenm].mname)); instapetrify(kbuf); } else if (Glib || uswapwep->cursed) { if (!Glib) uswapwep->bknown = TRUE; drop_uswapwep(); } else return (TRUE); return (FALSE); } void drop_uswapwep() { char str[BUFSZ]; struct obj *obj = uswapwep; /* Avoid trashing makeplural's static buffer */ Strcpy(str, makeplural(body_part(HAND))); Your("%s from your %s!", aobjnam(obj, "slip"), str); dropx(obj); } int dotwoweapon() { /* You can always toggle it off */ if (u.twoweap) { You("switch to your primary weapon."); u.twoweap = 0; update_inventory(); return (0); } /* May we use two weapons? */ if (can_twoweapon()) { /* Success! */ You("begin two-weapon combat."); u.twoweap = 1; update_inventory(); return (rnd(20) > ACURR(A_DEX)); } return (0); } /*** Functions to empty a given slot ***/ /* These should be used only when the item can't be put back in * the slot by life saving. Proper usage includes: * 1. The item has been eaten, stolen, burned away, or rotted away. * 2. Making an item disappear for a bones pile. */ void uwepgone() { if (uwep) { if (artifact_light(uwep) && uwep->lamplit) { end_burn(uwep, FALSE); if (!Blind) pline("%s glowing.", Tobjnam(uwep, "stop")); } setworn((struct obj *)0, W_WEP); unweapon = TRUE; update_inventory(); } } void uswapwepgone() { if (uswapwep) { setworn((struct obj *)0, W_SWAPWEP); update_inventory(); } } void uqwepgone() { if (uquiver) { setworn((struct obj *)0, W_QUIVER); update_inventory(); } } void untwoweapon() { if (u.twoweap) { You("can no longer use two weapons at once."); u.twoweap = FALSE; update_inventory(); } return; } /* Maybe rust object, or corrode it if acid damage is called for */ void erode_obj(target, acid_dmg, fade_scrolls) struct obj *target; /* object (e.g. weapon or armor) to erode */ boolean acid_dmg; boolean fade_scrolls; { int erosion; struct monst *victim; boolean vismon; boolean visobj; if (!target) return; victim = carried(target) ? &youmonst : mcarried(target) ? target->ocarry : (struct monst *)0; vismon = victim && (victim != &youmonst) && canseemon(victim); visobj = !victim && cansee(bhitpos.x, bhitpos.y); /* assume thrown */ erosion = acid_dmg ? target->oeroded2 : target->oeroded; if (target->greased) { grease_protect(target,(char *)0,victim); } else if (target->oclass == SCROLL_CLASS) { if(fade_scrolls && target->otyp != SCR_BLANK_PAPER #ifdef MAIL && target->otyp != SCR_MAIL #endif ) { if (!Blind) { if (victim == &youmonst) Your("%s.", aobjnam(target, "fade")); else if (vismon) pline("%s's %s.", Monnam(victim), aobjnam(target, "fade")); else if (visobj) pline_The("%s.", aobjnam(target, "fade")); } target->otyp = SCR_BLANK_PAPER; target->spe = 0; } } else if (target->oerodeproof || (acid_dmg ? !is_corrodeable(target) : !is_rustprone(target))) { if (flags.verbose || !(target->oerodeproof && target->rknown)) { if (victim == &youmonst) Your("%s not affected.", aobjnam(target, "are")); else if (vismon) pline("%s's %s not affected.", Monnam(victim), aobjnam(target, "are")); /* no message if not carried */ } if (target->oerodeproof) target->rknown = TRUE; } else if (erosion < MAX_ERODE) { if (victim == &youmonst) Your("%s%s!", aobjnam(target, acid_dmg ? "corrode" : "rust"), erosion+1 == MAX_ERODE ? " completely" : erosion ? " further" : ""); else if (vismon) pline("%s's %s%s!", Monnam(victim), aobjnam(target, acid_dmg ? "corrode" : "rust"), erosion+1 == MAX_ERODE ? " completely" : erosion ? " further" : ""); else if (visobj) pline_The("%s%s!", aobjnam(target, acid_dmg ? "corrode" : "rust"), erosion+1 == MAX_ERODE ? " completely" : erosion ? " further" : ""); if (acid_dmg) target->oeroded2++; else target->oeroded++; } else { if (flags.verbose) { if (victim == &youmonst) Your("%s completely %s.", aobjnam(target, Blind ? "feel" : "look"), acid_dmg ? "corroded" : "rusty"); else if (vismon) pline("%s's %s completely %s.", Monnam(victim), aobjnam(target, "look"), acid_dmg ? "corroded" : "rusty"); else if (visobj) pline_The("%s completely %s.", aobjnam(target, "look"), acid_dmg ? "corroded" : "rusty"); } } } int chwepon(otmp, amount) register struct obj *otmp; register int amount; { const char *color = hcolor((amount < 0) ? NH_BLACK : NH_BLUE); const char *xtime; int otyp = STRANGE_OBJECT; if(!uwep || (uwep->oclass != WEAPON_CLASS && !is_weptool(uwep))) { char buf[BUFSZ]; Sprintf(buf, "Your %s %s.", makeplural(body_part(HAND)), (amount >= 0) ? "twitch" : "itch"); strange_feeling(otmp, buf); exercise(A_DEX, (boolean) (amount >= 0)); return(0); } if (otmp && otmp->oclass == SCROLL_CLASS) otyp = otmp->otyp; if(uwep->otyp == WORM_TOOTH && amount >= 0) { uwep->otyp = CRYSKNIFE; uwep->oerodeproof = 0; Your("weapon seems sharper now."); uwep->cursed = 0; if (otyp != STRANGE_OBJECT) makeknown(otyp); return(1); } if(uwep->otyp == CRYSKNIFE && amount < 0) { uwep->otyp = WORM_TOOTH; uwep->oerodeproof = 0; Your("weapon seems duller now."); if (otyp != STRANGE_OBJECT && otmp->bknown) makeknown(otyp); return(1); } if (amount < 0 && uwep->oartifact && restrict_name(uwep, ONAME(uwep))) { if (!Blind) Your("%s %s.", aobjnam(uwep, "faintly glow"), color); return(1); } /* there is a (soft) upper and lower limit to uwep->spe */ if(((uwep->spe > 5 && amount >= 0) || (uwep->spe < -5 && amount < 0)) && rn2(3)) { if (!Blind) Your("%s %s for a while and then %s.", aobjnam(uwep, "violently glow"), color, otense(uwep, "evaporate")); else Your("%s.", aobjnam(uwep, "evaporate")); useupall(uwep); /* let all of them disappear */ return(1); } if (!Blind) { xtime = (amount*amount == 1) ? "moment" : "while"; Your("%s %s for a %s.", aobjnam(uwep, amount == 0 ? "violently glow" : "glow"), color, xtime); if (otyp != STRANGE_OBJECT && uwep->known && (amount > 0 || (amount < 0 && otmp->bknown))) makeknown(otyp); } uwep->spe += amount; if(amount > 0) uwep->cursed = 0; /* * Enchantment, which normally improves a weapon, has an * addition adverse reaction on Magicbane whose effects are * spe dependent. Give an obscure clue here. */ if (uwep->oartifact == ART_MAGICBANE && uwep->spe >= 0) { Your("right %s %sches!", body_part(HAND), (((amount > 1) && (uwep->spe > 1)) ? "flin" : "it")); } /* an elven magic clue, cookie@keebler */ /* elven weapons vibrate warningly when enchanted beyond a limit */ if ((uwep->spe > 5) && (is_elven_weapon(uwep) || uwep->oartifact || !rn2(7))) Your("%s unexpectedly.", aobjnam(uwep, "suddenly vibrate")); return(1); } int welded(obj) register struct obj *obj; { if (obj && obj == uwep && will_weld(obj)) { obj->bknown = TRUE; return 1; } return 0; } void weldmsg(obj) register struct obj *obj; { long savewornmask; savewornmask = obj->owornmask; Your("%s %s welded to your %s!", xname(obj), otense(obj, "are"), bimanual(obj) ? (const char *)makeplural(body_part(HAND)) : body_part(HAND)); obj->owornmask = savewornmask; } /*wield.c*/ nethack-3.4.3/src/windows.c0100644000000000000000000000626007764735041014303 0ustar rootroot/* SCCS Id: @(#)windows.c 3.4 1996/05/19 */ /* Copyright (c) D. Cohrs, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef TTY_GRAPHICS #include "wintty.h" #endif #ifdef X11_GRAPHICS /* cannot just blindly include winX.h without including all of X11 stuff */ /* and must get the order of include files right. Don't bother */ extern struct window_procs X11_procs; extern void NDECL(win_X11_init); #endif #ifdef QT_GRAPHICS extern struct window_procs Qt_procs; #endif #ifdef GEM_GRAPHICS #include "wingem.h" #endif #ifdef MAC extern struct window_procs mac_procs; #endif #ifdef BEOS_GRAPHICS extern struct window_procs beos_procs; extern void NDECL(be_win_init); #endif #ifdef AMIGA_INTUITION extern struct window_procs amii_procs; extern struct window_procs amiv_procs; extern void NDECL(ami_wininit_data); #endif #ifdef WIN32_GRAPHICS extern struct window_procs win32_procs; #endif #ifdef GNOME_GRAPHICS #include "winGnome.h" extern struct window_procs Gnome_procs; #endif #ifdef MSWIN_GRAPHICS extern struct window_procs mswin_procs; #endif STATIC_DCL void FDECL(def_raw_print, (const char *s)); NEARDATA struct window_procs windowprocs; static struct win_choices { struct window_procs *procs; void NDECL((*ini_routine)); /* optional (can be 0) */ } winchoices[] = { #ifdef TTY_GRAPHICS { &tty_procs, win_tty_init }, #endif #ifdef X11_GRAPHICS { &X11_procs, win_X11_init }, #endif #ifdef QT_GRAPHICS { &Qt_procs, 0 }, #endif #ifdef GEM_GRAPHICS { &Gem_procs, win_Gem_init }, #endif #ifdef MAC { &mac_procs, 0 }, #endif #ifdef BEOS_GRAPHICS { &beos_procs, be_win_init }, #endif #ifdef AMIGA_INTUITION { &amii_procs, ami_wininit_data }, /* Old font version of the game */ { &amiv_procs, ami_wininit_data }, /* Tile version of the game */ #endif #ifdef WIN32_GRAPHICS { &win32_procs, 0 }, #endif #ifdef GNOME_GRAPHICS { &Gnome_procs, 0 }, #endif #ifdef MSWIN_GRAPHICS { &mswin_procs, 0 }, #endif { 0, 0 } /* must be last */ }; STATIC_OVL void def_raw_print(s) const char *s; { puts(s); } void choose_windows(s) const char *s; { register int i; for(i=0; winchoices[i].procs; i++) if (!strcmpi(s, winchoices[i].procs->name)) { windowprocs = *winchoices[i].procs; if (winchoices[i].ini_routine) (*winchoices[i].ini_routine)(); return; } if (!windowprocs.win_raw_print) windowprocs.win_raw_print = def_raw_print; raw_printf("Window type %s not recognized. Choices are:", s); for(i=0; winchoices[i].procs; i++) raw_printf(" %s", winchoices[i].procs->name); if (windowprocs.win_raw_print == def_raw_print) terminate(EXIT_SUCCESS); wait_synch(); } /* * tty_message_menu() provides a means to get feedback from the * --More-- prompt; other interfaces generally don't need that. */ /*ARGSUSED*/ char genl_message_menu(let, how, mesg) char let; int how; const char *mesg; { pline("%s", mesg); return 0; } /*ARGSUSED*/ void genl_preference_update(pref) const char *pref; { /* window ports are expected to provide their own preference update routine for the preference capabilities that they support. Just return in this genl one. */ } /*windows.c*/ nethack-3.4.3/src/wizard.c0100644000000000000000000004055407764735041014115 0ustar rootroot/* SCCS Id: @(#)wizard.c 3.4 2003/02/18 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* wizard code - inspired by rogue code from Merlyn Leroy (digi-g!brian) */ /* - heavily modified to give the wiz balls. (genat!mike) */ /* - dewimped and given some maledictions. -3. */ /* - generalized for 3.1 (mike@bullns.on01.bull.ca) */ #include "hack.h" #include "qtext.h" #include "epri.h" extern const int monstr[]; #ifdef OVLB STATIC_DCL short FDECL(which_arti, (int)); STATIC_DCL boolean FDECL(mon_has_arti, (struct monst *,SHORT_P)); STATIC_DCL struct monst *FDECL(other_mon_has_arti, (struct monst *,SHORT_P)); STATIC_DCL struct obj *FDECL(on_ground, (SHORT_P)); STATIC_DCL boolean FDECL(you_have, (int)); STATIC_DCL long FDECL(target_on, (int,struct monst *)); STATIC_DCL long FDECL(strategy, (struct monst *)); static NEARDATA const int nasties[] = { PM_COCKATRICE, PM_ETTIN, PM_STALKER, PM_MINOTAUR, PM_RED_DRAGON, PM_BLACK_DRAGON, PM_GREEN_DRAGON, PM_OWLBEAR, PM_PURPLE_WORM, PM_ROCK_TROLL, PM_XAN, PM_GREMLIN, PM_UMBER_HULK, PM_VAMPIRE_LORD, PM_XORN, PM_ZRUTY, PM_ELF_LORD, PM_ELVENKING, PM_YELLOW_DRAGON, PM_LEOCROTTA, PM_BALUCHITHERIUM, PM_CARNIVOROUS_APE, PM_FIRE_GIANT, PM_COUATL, PM_CAPTAIN, PM_WINGED_GARGOYLE, PM_MASTER_MIND_FLAYER, PM_FIRE_ELEMENTAL, PM_JABBERWOCK, PM_ARCH_LICH, PM_OGRE_KING, PM_OLOG_HAI, PM_IRON_GOLEM, PM_OCHRE_JELLY, PM_GREEN_SLIME, PM_DISENCHANTER }; static NEARDATA const unsigned wizapp[] = { PM_HUMAN, PM_WATER_DEMON, PM_VAMPIRE, PM_RED_DRAGON, PM_TROLL, PM_UMBER_HULK, PM_XORN, PM_XAN, PM_COCKATRICE, PM_FLOATING_EYE, PM_GUARDIAN_NAGA, PM_TRAPPER }; #endif /* OVLB */ #ifdef OVL0 /* If you've found the Amulet, make the Wizard appear after some time */ /* Also, give hints about portal locations, if amulet is worn/wielded -dlc */ void amulet() { struct monst *mtmp; struct trap *ttmp; struct obj *amu; #if 0 /* caller takes care of this check */ if (!u.uhave.amulet) return; #endif if ((((amu = uamul) != 0 && amu->otyp == AMULET_OF_YENDOR) || ((amu = uwep) != 0 && amu->otyp == AMULET_OF_YENDOR)) && !rn2(15)) { for(ttmp = ftrap; ttmp; ttmp = ttmp->ntrap) { if(ttmp->ttyp == MAGIC_PORTAL) { int du = distu(ttmp->tx, ttmp->ty); if (du <= 9) pline("%s hot!", Tobjnam(amu, "feel")); else if (du <= 64) pline("%s very warm.", Tobjnam(amu, "feel")); else if (du <= 144) pline("%s warm.", Tobjnam(amu, "feel")); /* else, the amulet feels normal */ break; } } } if (!flags.no_of_wizards) return; /* find Wizard, and wake him if necessary */ for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp) && mtmp->iswiz && mtmp->msleeping && !rn2(40)) { mtmp->msleeping = 0; if (distu(mtmp->mx,mtmp->my) > 2) You( "get the creepy feeling that somebody noticed your taking the Amulet." ); return; } } #endif /* OVL0 */ #ifdef OVLB int mon_has_amulet(mtmp) register struct monst *mtmp; { register struct obj *otmp; for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if(otmp->otyp == AMULET_OF_YENDOR) return(1); return(0); } int mon_has_special(mtmp) register struct monst *mtmp; { register struct obj *otmp; for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) if(otmp->otyp == AMULET_OF_YENDOR || is_quest_artifact(otmp) || otmp->otyp == BELL_OF_OPENING || otmp->otyp == CANDELABRUM_OF_INVOCATION || otmp->otyp == SPE_BOOK_OF_THE_DEAD) return(1); return(0); } /* * New for 3.1 Strategy / Tactics for the wiz, as well as other * monsters that are "after" something (defined via mflag3). * * The strategy section decides *what* the monster is going * to attempt, the tactics section implements the decision. */ #define STRAT(w, x, y, typ) (w | ((long)(x)<<16) | ((long)(y)<<8) | (long)typ) #define M_Wants(mask) (mtmp->data->mflags3 & (mask)) STATIC_OVL short which_arti(mask) register int mask; { switch(mask) { case M3_WANTSAMUL: return(AMULET_OF_YENDOR); case M3_WANTSBELL: return(BELL_OF_OPENING); case M3_WANTSCAND: return(CANDELABRUM_OF_INVOCATION); case M3_WANTSBOOK: return(SPE_BOOK_OF_THE_DEAD); default: break; /* 0 signifies quest artifact */ } return(0); } /* * If "otyp" is zero, it triggers a check for the quest_artifact, * since bell, book, candle, and amulet are all objects, not really * artifacts right now. [MRS] */ STATIC_OVL boolean mon_has_arti(mtmp, otyp) register struct monst *mtmp; register short otyp; { register struct obj *otmp; for(otmp = mtmp->minvent; otmp; otmp = otmp->nobj) { if(otyp) { if(otmp->otyp == otyp) return(1); } else if(is_quest_artifact(otmp)) return(1); } return(0); } STATIC_OVL struct monst * other_mon_has_arti(mtmp, otyp) register struct monst *mtmp; register short otyp; { register struct monst *mtmp2; for(mtmp2 = fmon; mtmp2; mtmp2 = mtmp2->nmon) /* no need for !DEADMONSTER check here since they have no inventory */ if(mtmp2 != mtmp) if(mon_has_arti(mtmp2, otyp)) return(mtmp2); return((struct monst *)0); } STATIC_OVL struct obj * on_ground(otyp) register short otyp; { register struct obj *otmp; for (otmp = fobj; otmp; otmp = otmp->nobj) if (otyp) { if (otmp->otyp == otyp) return(otmp); } else if (is_quest_artifact(otmp)) return(otmp); return((struct obj *)0); } STATIC_OVL boolean you_have(mask) register int mask; { switch(mask) { case M3_WANTSAMUL: return(boolean)(u.uhave.amulet); case M3_WANTSBELL: return(boolean)(u.uhave.bell); case M3_WANTSCAND: return(boolean)(u.uhave.menorah); case M3_WANTSBOOK: return(boolean)(u.uhave.book); case M3_WANTSARTI: return(boolean)(u.uhave.questart); default: break; } return(0); } STATIC_OVL long target_on(mask, mtmp) register int mask; register struct monst *mtmp; { register short otyp; register struct obj *otmp; register struct monst *mtmp2; if(!M_Wants(mask)) return(STRAT_NONE); otyp = which_arti(mask); if(!mon_has_arti(mtmp, otyp)) { if(you_have(mask)) return(STRAT(STRAT_PLAYER, u.ux, u.uy, mask)); else if((otmp = on_ground(otyp))) return(STRAT(STRAT_GROUND, otmp->ox, otmp->oy, mask)); else if((mtmp2 = other_mon_has_arti(mtmp, otyp))) return(STRAT(STRAT_MONSTR, mtmp2->mx, mtmp2->my, mask)); } return(STRAT_NONE); } STATIC_OVL long strategy(mtmp) register struct monst *mtmp; { long strat, dstrat; if (!is_covetous(mtmp->data) || /* perhaps a shopkeeper has been polymorphed into a master lich; we don't want it teleporting to the stairs to heal because that will leave its shop untended */ (mtmp->isshk && inhishop(mtmp))) return STRAT_NONE; switch((mtmp->mhp*3)/mtmp->mhpmax) { /* 0-3 */ default: case 0: /* panic time - mtmp is almost snuffed */ return(STRAT_HEAL); case 1: /* the wiz is less cautious */ if(mtmp->data != &mons[PM_WIZARD_OF_YENDOR]) return(STRAT_HEAL); /* else fall through */ case 2: dstrat = STRAT_HEAL; break; case 3: dstrat = STRAT_NONE; break; } if(flags.made_amulet) if((strat = target_on(M3_WANTSAMUL, mtmp)) != STRAT_NONE) return(strat); if(u.uevent.invoked) { /* priorities change once gate opened */ if((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE) return(strat); if((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE) return(strat); if((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE) return(strat); if((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE) return(strat); } else { if((strat = target_on(M3_WANTSBOOK, mtmp)) != STRAT_NONE) return(strat); if((strat = target_on(M3_WANTSBELL, mtmp)) != STRAT_NONE) return(strat); if((strat = target_on(M3_WANTSCAND, mtmp)) != STRAT_NONE) return(strat); if((strat = target_on(M3_WANTSARTI, mtmp)) != STRAT_NONE) return(strat); } return(dstrat); } int tactics(mtmp) register struct monst *mtmp; { long strat = strategy(mtmp); mtmp->mstrategy = (mtmp->mstrategy & STRAT_WAITMASK) | strat; switch (strat) { case STRAT_HEAL: /* hide and recover */ /* if wounded, hole up on or near the stairs (to block them) */ /* unless, of course, there are no stairs (e.g. endlevel) */ mtmp->mavenge = 1; /* covetous monsters attack while fleeing */ if (In_W_tower(mtmp->mx, mtmp->my, &u.uz) || (mtmp->iswiz && !xupstair && !mon_has_amulet(mtmp))) { if (!rn2(3 + mtmp->mhp/10)) (void) rloc(mtmp, FALSE); } else if (xupstair && (mtmp->mx != xupstair || mtmp->my != yupstair)) { (void) mnearto(mtmp, xupstair, yupstair, TRUE); } /* if you're not around, cast healing spells */ if (distu(mtmp->mx,mtmp->my) > (BOLT_LIM * BOLT_LIM)) if(mtmp->mhp <= mtmp->mhpmax - 8) { mtmp->mhp += rnd(8); return(1); } /* fall through :-) */ case STRAT_NONE: /* harrass */ if (!rn2(!mtmp->mflee ? 5 : 33)) mnexto(mtmp); return(0); default: /* kill, maim, pillage! */ { long where = (strat & STRAT_STRATMASK); xchar tx = STRAT_GOALX(strat), ty = STRAT_GOALY(strat); int targ = strat & STRAT_GOAL; struct obj *otmp; if(!targ) { /* simply wants you to close */ return(0); } if((u.ux == tx && u.uy == ty) || where == STRAT_PLAYER) { /* player is standing on it (or has it) */ mnexto(mtmp); return(0); } if(where == STRAT_GROUND) { if(!MON_AT(tx, ty) || (mtmp->mx == tx && mtmp->my == ty)) { /* teleport to it and pick it up */ rloc_to(mtmp, tx, ty); /* clean old pos */ if ((otmp = on_ground(which_arti(targ))) != 0) { if (cansee(mtmp->mx, mtmp->my)) pline("%s picks up %s.", Monnam(mtmp), (distu(mtmp->mx, mtmp->my) <= 5) ? doname(otmp) : distant_name(otmp, doname)); obj_extract_self(otmp); (void) mpickobj(mtmp, otmp); return(1); } else return(0); } else { /* a monster is standing on it - cause some trouble */ if (!rn2(5)) mnexto(mtmp); return(0); } } else { /* a monster has it - 'port beside it. */ (void) mnearto(mtmp, tx, ty, FALSE); return(0); } } } /*NOTREACHED*/ return(0); } void aggravate() { register struct monst *mtmp; for(mtmp = fmon; mtmp; mtmp = mtmp->nmon) if (!DEADMONSTER(mtmp)) { mtmp->msleeping = 0; if(!mtmp->mcanmove && !rn2(5)) { mtmp->mfrozen = 0; mtmp->mcanmove = 1; } } } void clonewiz() { register struct monst *mtmp2; if ((mtmp2 = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy, NO_MM_FLAGS)) != 0) { mtmp2->msleeping = mtmp2->mtame = mtmp2->mpeaceful = 0; if (!u.uhave.amulet && rn2(2)) { /* give clone a fake */ (void) add_to_minv(mtmp2, mksobj(FAKE_AMULET_OF_YENDOR, TRUE, FALSE)); } mtmp2->m_ap_type = M_AP_MONSTER; mtmp2->mappearance = wizapp[rn2(SIZE(wizapp))]; newsym(mtmp2->mx,mtmp2->my); } } /* also used by newcham() */ int pick_nasty() { /* To do? Possibly should filter for appropriate forms when in the elemental planes or surrounded by water or lava. */ return nasties[rn2(SIZE(nasties))]; } /* create some nasty monsters, aligned or neutral with the caster */ /* a null caster defaults to a chaotic caster (e.g. the wizard) */ int nasty(mcast) struct monst *mcast; { register struct monst *mtmp; register int i, j, tmp; int castalign = (mcast ? mcast->data->maligntyp : -1); coord bypos; int count=0; if(!rn2(10) && Inhell) { msummon((struct monst *) 0); /* summons like WoY */ count++; } else { tmp = (u.ulevel > 3) ? u.ulevel/3 : 1; /* just in case -- rph */ /* if we don't have a casting monster, the nasties appear around you */ bypos.x = u.ux; bypos.y = u.uy; for(i = rnd(tmp); i > 0; --i) for(j=0; j<20; j++) { int makeindex; /* Don't create more spellcasters of the monsters' level or * higher--avoids chain summoners filling up the level. */ do { makeindex = pick_nasty(); } while(mcast && attacktype(&mons[makeindex], AT_MAGC) && monstr[makeindex] >= monstr[mcast->mnum]); /* do this after picking the monster to place */ if (mcast && !enexto(&bypos, mcast->mux, mcast->muy, &mons[makeindex])) continue; if ((mtmp = makemon(&mons[makeindex], bypos.x, bypos.y, NO_MM_FLAGS)) != 0) { mtmp->msleeping = mtmp->mpeaceful = mtmp->mtame = 0; set_malign(mtmp); } else /* GENOD? */ mtmp = makemon((struct permonst *)0, bypos.x, bypos.y, NO_MM_FLAGS); if(mtmp && (mtmp->data->maligntyp == 0 || sgn(mtmp->data->maligntyp) == sgn(castalign)) ) { count++; break; } } } return count; } /* Let's resurrect the wizard, for some unexpected fun. */ void resurrect() { struct monst *mtmp, **mmtmp; long elapsed; const char *verb; if (!flags.no_of_wizards) { /* make a new Wizard */ verb = "kill"; mtmp = makemon(&mons[PM_WIZARD_OF_YENDOR], u.ux, u.uy, MM_NOWAIT); } else { /* look for a migrating Wizard */ verb = "elude"; mmtmp = &migrating_mons; while ((mtmp = *mmtmp) != 0) { if (mtmp->iswiz && /* if he has the Amulet, he won't bring it to you */ !mon_has_amulet(mtmp) && (elapsed = monstermoves - mtmp->mlstmv) > 0L) { mon_catchup_elapsed_time(mtmp, elapsed); if (elapsed >= LARGEST_INT) elapsed = LARGEST_INT - 1; elapsed /= 50L; if (mtmp->msleeping && rn2((int)elapsed + 1)) mtmp->msleeping = 0; if (mtmp->mfrozen == 1) /* would unfreeze on next move */ mtmp->mfrozen = 0, mtmp->mcanmove = 1; if (mtmp->mcanmove && !mtmp->msleeping) { *mmtmp = mtmp->nmon; mon_arrive(mtmp, TRUE); /* note: there might be a second Wizard; if so, he'll have to wait til the next resurrection */ break; } } mmtmp = &mtmp->nmon; } } if (mtmp) { mtmp->msleeping = mtmp->mtame = mtmp->mpeaceful = 0; set_malign(mtmp); pline("A voice booms out..."); verbalize("So thou thought thou couldst %s me, fool.", verb); } } /* Here, we make trouble for the poor shmuck who actually */ /* managed to do in the Wizard. */ void intervene() { int which = Is_astralevel(&u.uz) ? rnd(4) : rn2(6); /* cases 0 and 5 don't apply on the Astral level */ switch (which) { case 0: case 1: You_feel("vaguely nervous."); break; case 2: if (!Blind) You("notice a %s glow surrounding you.", hcolor(NH_BLACK)); rndcurse(); break; case 3: aggravate(); break; case 4: (void)nasty((struct monst *)0); break; case 5: resurrect(); break; } } void wizdead() { flags.no_of_wizards--; if (!u.uevent.udemigod) { u.uevent.udemigod = TRUE; u.udg_cnt = rn1(250, 50); } } const char * const random_insult[] = { "antic", "blackguard", "caitiff", "chucklehead", "coistrel", "craven", "cretin", "cur", "dastard", "demon fodder", "dimwit", "dolt", "fool", "footpad", "imbecile", "knave", "maledict", "miscreant", "niddering", "poltroon", "rattlepate", "reprobate", "scapegrace", "varlet", "villein", /* (sic.) */ "wittol", "worm", "wretch", }; const char * const random_malediction[] = { "Hell shall soon claim thy remains,", "I chortle at thee, thou pathetic", "Prepare to die, thou", "Resistance is useless,", "Surrender or die, thou", "There shall be no mercy, thou", "Thou shalt repent of thy cunning,", "Thou art as a flea to me,", "Thou art doomed,", "Thy fate is sealed,", "Verily, thou shalt be one dead" }; /* Insult or intimidate the player */ void cuss(mtmp) register struct monst *mtmp; { if (mtmp->iswiz) { if (!rn2(5)) /* typical bad guy action */ pline("%s laughs fiendishly.", Monnam(mtmp)); else if (u.uhave.amulet && !rn2(SIZE(random_insult))) verbalize("Relinquish the amulet, %s!", random_insult[rn2(SIZE(random_insult))]); else if (u.uhp < 5 && !rn2(2)) /* Panic */ verbalize(rn2(2) ? "Even now thy life force ebbs, %s!" : "Savor thy breath, %s, it be thy last!", random_insult[rn2(SIZE(random_insult))]); else if (mtmp->mhp < 5 && !rn2(2)) /* Parthian shot */ verbalize(rn2(2) ? "I shall return." : "I'll be back."); else verbalize("%s %s!", random_malediction[rn2(SIZE(random_malediction))], random_insult[rn2(SIZE(random_insult))]); } else if(is_lminion(mtmp)) { com_pager(rn2(QTN_ANGELIC - 1 + (Hallucination ? 1 : 0)) + QT_ANGELIC); } else { if (!rn2(5)) pline("%s casts aspersions on your ancestry.", Monnam(mtmp)); else com_pager(rn2(QTN_DEMONIC) + QT_DEMONIC); } } #endif /* OVLB */ /*wizard.c*/ nethack-3.4.3/src/worm.c0100644000000000000000000004547607764735041013611 0ustar rootroot/* SCCS Id: @(#)worm.c 3.4 1995/01/28 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "lev.h" #define newseg() (struct wseg *) alloc(sizeof(struct wseg)) #define dealloc_seg(wseg) free((genericptr_t) (wseg)) /* worm segment structure */ struct wseg { struct wseg *nseg; xchar wx, wy; /* the segment's position */ }; STATIC_DCL void FDECL(toss_wsegs, (struct wseg *,BOOLEAN_P)); STATIC_DCL void FDECL(shrink_worm, (int)); STATIC_DCL void FDECL(random_dir, (XCHAR_P,XCHAR_P,xchar *,xchar *)); STATIC_DCL struct wseg *FDECL(create_worm_tail, (int)); /* Description of long worm implementation. * * Each monst struct of the head of a tailed worm has a wormno set to * 1 <= wormno < MAX_NUM_WORMS * If wormno == 0 this does not mean that the monster is not a worm, * it just means that the monster does not have a long worm tail. * * The actual segments of a worm are not full blown monst structs. * They are small wseg structs, and their position in the levels.monsters[][] * array is held by the monst struct of the head of the worm. This makes * things like probing and hit point bookkeeping much easier. * * The segments of the long worms on a level are kept as an array of * singly threaded linked lists. The wormno variable is used as an index * for these segment arrays. * * wtails: The first (starting struct) of a linked list. This points * to the tail (last) segment of the worm. * * wheads: The last (end) of a linked list of segments. This points to * the segment that is at the same position as the real monster * (the head). Note that the segment that wheads[wormno] points * to, is not displayed. It is simply there to keep track of * where the head came from, so that worm movement and display are * simplified later. * Keeping the head segment of the worm at the end of the list * of tail segments is an endless source of confusion, but it is * necessary. * From now on, we will use "start" and "end" to refer to the * linked list and "head" and "tail" to refer to the worm. * * One final worm array is: * * wgrowtime: This tells us when to add another segment to the worm. * * When a worm is moved, we add a new segment at the head, and delete the * segment at the tail (unless we want it to grow). This new head segment is * located in the same square as the actual head of the worm. If we want * to grow the worm, we don't delete the tail segment, and we give the worm * extra hit points, which possibly go into its maximum. * * Non-moving worms (worm_nomove) are assumed to be surrounded by their own * tail, and, thus, shrink instead of grow (as their tails keep going while * their heads are stopped short). In this case, we delete the last tail * segment, and remove hit points from the worm. */ struct wseg *wheads[MAX_NUM_WORMS] = DUMMY, *wtails[MAX_NUM_WORMS] = DUMMY; long wgrowtime[MAX_NUM_WORMS] = DUMMY; /* * get_wormno() * * Find an unused worm tail slot and return the index. A zero means that * there are no slots available. This means that the worm head can exist, * it just cannot ever grow a tail. * * It, also, means that there is an optimisation to made. The [0] positions * of the arrays are never used. Meaning, we really *could* have one more * tailed worm on the level, or use a smaller array (using wormno - 1). * * Implementation is left to the interested hacker. */ int get_wormno() { register int new_wormno = 1; while (new_wormno < MAX_NUM_WORMS) { if (!wheads[new_wormno]) return new_wormno; /* found an empty wtails[] slot at new_wormno */ new_wormno++; } return(0); /* level infested with worms */ } /* * initworm() * * Use if (mon->wormno = get_wormno()) before calling this function! * * Initialize the worm entry. This will set up the worm grow time, and * create and initialize the dummy segment for wheads[] and wtails[]. * * If the worm has no tail (ie get_wormno() fails) then this function need * not be called. */ void initworm(worm, wseg_count) struct monst *worm; int wseg_count; { register struct wseg *seg, *new_tail = create_worm_tail(wseg_count); register int wnum = worm->wormno; /* if (!wnum) return; bullet proofing */ if (new_tail) { wtails[wnum] = new_tail; for (seg = new_tail; seg->nseg; seg = seg->nseg); wheads[wnum] = seg; } else { wtails[wnum] = wheads[wnum] = seg = newseg(); seg->nseg = (struct wseg *) 0; seg->wx = worm->mx; seg->wy = worm->my; } wgrowtime[wnum] = 0L; } /* * toss_wsegs() * * Get rid of all worm segments on and following the given pointer curr. * The display may or may not need to be updated as we free the segments. */ STATIC_OVL void toss_wsegs(curr, display_update) register struct wseg *curr; register boolean display_update; { register struct wseg *seg; while (curr) { seg = curr->nseg; /* remove from level.monsters[][] */ /* need to check curr->wx for genocided while migrating_mon */ if (curr->wx) { remove_monster(curr->wx, curr->wy); /* update screen before deallocation */ if (display_update) newsym(curr->wx,curr->wy); } /* free memory used by the segment */ dealloc_seg(curr); curr = seg; } } /* * shrink_worm() * * Remove the tail segment of the worm (the starting segment of the list). */ STATIC_OVL void shrink_worm(wnum) int wnum; /* worm number */ { struct wseg *seg; if (wtails[wnum] == wheads[wnum]) return; /* no tail */ seg = wtails[wnum]; wtails[wnum] = seg->nseg; seg->nseg = (struct wseg *) 0; toss_wsegs(seg, TRUE); } /* * worm_move() * * Check for mon->wormno before calling this function! * * Move the worm. Maybe grow. */ void worm_move(worm) struct monst *worm; { register struct wseg *seg, *new_seg; /* new segment */ register int wnum = worm->wormno; /* worm number */ /* if (!wnum) return; bullet proofing */ /* * Place a segment at the old worm head. The head has already moved. */ seg = wheads[wnum]; place_worm_seg(worm, seg->wx, seg->wy); newsym(seg->wx,seg->wy); /* display the new segment */ /* * Create a new dummy segment head and place it at the end of the list. */ new_seg = newseg(); new_seg->wx = worm->mx; new_seg->wy = worm->my; new_seg->nseg = (struct wseg *) 0; seg->nseg = new_seg; /* attach it to the end of the list */ wheads[wnum] = new_seg; /* move the end pointer */ if (wgrowtime[wnum] <= moves) { if (!wgrowtime[wnum]) wgrowtime[wnum] = moves + rnd(5); else wgrowtime[wnum] += rn1(15, 3); worm->mhp += 3; if (worm->mhp > MHPMAX) worm->mhp = MHPMAX; if (worm->mhp > worm->mhpmax) worm->mhpmax = worm->mhp; } else /* The worm doesn't grow, so the last segment goes away. */ shrink_worm(wnum); } /* * worm_nomove() * * Check for mon->wormno before calling this function! * * The worm don't move so it should shrink. */ void worm_nomove(worm) register struct monst *worm; { shrink_worm((int) worm->wormno); /* shrink */ if (worm->mhp > 3) worm->mhp -= 3; /* mhpmax not changed ! */ else worm->mhp = 1; } /* * wormgone() * * Check for mon->wormno before calling this function! * * Kill a worm tail. */ void wormgone(worm) register struct monst *worm; { register int wnum = worm->wormno; /* if (!wnum) return; bullet proofing */ worm->wormno = 0; /* This will also remove the real monster (ie 'w') from the its * position in level.monsters[][]. */ toss_wsegs(wtails[wnum], TRUE); wheads[wnum] = wtails[wnum] = (struct wseg *) 0; } /* * wormhitu() * * Check for mon->wormno before calling this function! * * If the hero is near any part of the worm, the worm will try to attack. */ void wormhitu(worm) register struct monst *worm; { register int wnum = worm->wormno; register struct wseg *seg; /* if (!wnum) return; bullet proofing */ /* This does not work right now because mattacku() thinks that the head is * out of range of the player. We might try to kludge, and bring the head * within range for a tiny moment, but this needs a bit more looking at * before we decide to do this. */ for (seg = wtails[wnum]; seg; seg = seg->nseg) if (distu(seg->wx, seg->wy) < 3) (void) mattacku(worm); } /* cutworm() * * Check for mon->wormno before calling this function! * * When hitting a worm (worm) at position x, y, with a weapon (weap), * there is a chance that the worm will be cut in half, and a chance * that both halves will survive. */ void cutworm(worm, x, y, weap) struct monst *worm; xchar x,y; struct obj *weap; { register struct wseg *curr, *new_tail; register struct monst *new_worm; int wnum = worm->wormno; int cut_chance, new_wnum; if (!wnum) return; /* bullet proofing */ if (x == worm->mx && y == worm->my) return; /* hit on head */ /* cutting goes best with a bladed weapon */ cut_chance = rnd(20); /* Normally 1-16 does not cut */ /* Normally 17-20 does */ if (weap && is_blade(weap)) /* With a blade 1- 6 does not cut */ cut_chance += 10; /* 7-20 does */ if (cut_chance < 17) return; /* not good enough */ /* Find the segment that was attacked. */ curr = wtails[wnum]; while ( (curr->wx != x) || (curr->wy != y) ) { curr = curr->nseg; if (!curr) { impossible("cutworm: no segment at (%d,%d)", (int) x, (int) y); return; } } /* If this is the tail segment, then the worm just loses it. */ if (curr == wtails[wnum]) { shrink_worm(wnum); return; } /* * Split the worm. The tail for the new worm is the old worm's tail. * The tail for the old worm is the segment that follows "curr", * and "curr" becomes the dummy segment under the new head. */ new_tail = wtails[wnum]; wtails[wnum] = curr->nseg; curr->nseg = (struct wseg *) 0; /* split the worm */ /* * At this point, the old worm is correct. Any new worm will have * it's head at "curr" and its tail at "new_tail". */ /* Sometimes the tail end dies. */ if (rn2(3) || !(new_wnum = get_wormno())) { if (flags.mon_moving) pline("Part of the tail of %s is cut off.", mon_nam(worm)); else You("cut part of the tail off of %s.", mon_nam(worm)); toss_wsegs(new_tail, TRUE); if (worm->mhp > 1) worm->mhp /= 2; return; } remove_monster(x, y); /* clone_mon puts new head here */ new_worm = clone_mon(worm, x, y); new_worm->wormno = new_wnum; /* affix new worm number */ /* Devalue the monster level of both halves of the worm. */ worm->m_lev = ((unsigned)worm->m_lev <= 3) ? (unsigned)worm->m_lev : max((unsigned)worm->m_lev - 2, 3); new_worm->m_lev = worm->m_lev; /* Calculate the mhp on the new_worm for the (lower) monster level. */ new_worm->mhpmax = new_worm->mhp = d((int)new_worm->m_lev, 8); /* Calculate the mhp on the old worm for the (lower) monster level. */ if (worm->m_lev > 3) { worm->mhpmax = d((int)worm->m_lev, 8); if (worm->mhpmax < worm->mhp) worm->mhp = worm->mhpmax; } wtails[new_wnum] = new_tail; /* We've got all the info right now */ wheads[new_wnum] = curr; /* so we can do this faster than */ wgrowtime[new_wnum] = 0L; /* trying to call initworm(). */ /* Place the new monster at all the segment locations. */ place_wsegs(new_worm); if (flags.mon_moving) pline("%s is cut in half.", Monnam(worm)); else You("cut %s in half.", mon_nam(worm)); } /* * see_wsegs() * * Refresh all of the segments of the given worm. This is only called * from see_monster() in display.c or when a monster goes minvis. It * is located here for modularity. */ void see_wsegs(worm) struct monst *worm; { struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ while (curr != wheads[worm->wormno]) { newsym(curr->wx,curr->wy); curr = curr->nseg; } } /* * detect_wsegs() * * Display all of the segments of the given worm for detection. */ void detect_wsegs(worm, use_detection_glyph) struct monst *worm; boolean use_detection_glyph; { int num; struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ while (curr != wheads[worm->wormno]) { num = use_detection_glyph ? detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)) : monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); show_glyph(curr->wx,curr->wy,num); curr = curr->nseg; } } /* * save_worm() * * Save the worm information for later use. The count is the number * of segments, including the dummy. Called from save.c. */ void save_worm(fd, mode) int fd, mode; { int i; int count; struct wseg *curr, *temp; if (perform_bwrite(mode)) { for (i = 1; i < MAX_NUM_WORMS; i++) { for (count = 0, curr = wtails[i]; curr; curr = curr->nseg) count++; /* Save number of segments */ bwrite(fd, (genericptr_t) &count, sizeof(int)); /* Save segment locations of the monster. */ if (count) { for (curr = wtails[i]; curr; curr = curr->nseg) { bwrite(fd, (genericptr_t) &(curr->wx), sizeof(xchar)); bwrite(fd, (genericptr_t) &(curr->wy), sizeof(xchar)); } } } bwrite(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime)); } if (release_data(mode)) { /* Free the segments only. savemonchn() will take care of the * monsters. */ for (i = 1; i < MAX_NUM_WORMS; i++) { if (!(curr = wtails[i])) continue; while (curr) { temp = curr->nseg; dealloc_seg(curr); /* free the segment */ curr = temp; } wheads[i] = wtails[i] = (struct wseg *) 0; } } } /* * rest_worm() * * Restore the worm information from the save file. Called from restore.c */ void rest_worm(fd) int fd; { int i, j, count; struct wseg *curr, *temp; for (i = 1; i < MAX_NUM_WORMS; i++) { mread(fd, (genericptr_t) &count, sizeof(int)); if (!count) continue; /* none */ /* Get the segments. */ for (curr = (struct wseg *) 0, j = 0; j < count; j++) { temp = newseg(); temp->nseg = (struct wseg *) 0; mread(fd, (genericptr_t) &(temp->wx), sizeof(xchar)); mread(fd, (genericptr_t) &(temp->wy), sizeof(xchar)); if (curr) curr->nseg = temp; else wtails[i] = temp; curr = temp; } wheads[i] = curr; } mread(fd, (genericptr_t) wgrowtime, sizeof(wgrowtime)); } /* * place_wsegs() * * Place the segments of the given worm. Called from restore.c */ void place_wsegs(worm) struct monst *worm; { struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ while (curr != wheads[worm->wormno]) { place_worm_seg(worm,curr->wx,curr->wy); curr = curr->nseg; } } /* * remove_worm() * * This function is equivalent to the remove_monster #define in * rm.h, only it will take the worm *and* tail out of the levels array. * It does not get rid of (dealloc) the worm tail structures, and it does * not remove the mon from the fmon chain. */ void remove_worm(worm) register struct monst *worm; { register struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ while (curr) { remove_monster(curr->wx, curr->wy); newsym(curr->wx, curr->wy); curr = curr->nseg; } } /* * place_worm_tail_randomly() * * Place a worm tail somewhere on a level behind the head. * This routine essentially reverses the order of the wsegs from head * to tail while placing them. * x, and y are most likely the worm->mx, and worm->my, but don't *need* to * be, if somehow the head is disjoint from the tail. */ void place_worm_tail_randomly(worm, x, y) struct monst *worm; xchar x, y; { int wnum = worm->wormno; struct wseg *curr = wtails[wnum]; struct wseg *new_tail; register xchar ox = x, oy = y; /* if (!wnum) return; bullet proofing */ if (wnum && (!wtails[wnum] || !wheads[wnum]) ) { impossible("place_worm_tail_randomly: wormno is set without a tail!"); return; } wheads[wnum] = new_tail = curr; curr = curr->nseg; new_tail->nseg = (struct wseg *) 0; new_tail->wx = x; new_tail->wy = y; while(curr) { xchar nx, ny; char tryct = 0; /* pick a random direction from x, y and search for goodpos() */ do { random_dir(ox, oy, &nx, &ny); } while (!goodpos(nx, ny, worm, 0) && (tryct++ < 50)); if (tryct < 50) { place_worm_seg(worm, nx, ny); curr->wx = ox = nx; curr->wy = oy = ny; wtails[wnum] = curr; curr = curr->nseg; wtails[wnum]->nseg = new_tail; new_tail = wtails[wnum]; newsym(nx, ny); } else { /* Oops. Truncate because there was */ toss_wsegs(curr, FALSE); /* no place for the rest of it */ curr = (struct wseg *) 0; } } } /* * Given a coordinate x, y. * return in *nx, *ny, the coordinates of one of the <= 8 squares adjoining. * * This function, and the loop it serves, could be eliminated by coding * enexto() with a search radius. */ STATIC_OVL void random_dir(x, y, nx, ny) register xchar x, y; register xchar *nx, *ny; { *nx = x; *ny = y; *nx += (x > 1 ? /* extreme left ? */ (x < COLNO ? /* extreme right ? */ (rn2(3) - 1) /* neither so +1, 0, or -1 */ : -rn2(2)) /* 0, or -1 */ : rn2(2)); /* 0, or 1 */ *ny += (*nx == x ? /* same kind of thing with y */ (y > 1 ? (y < ROWNO ? (rn2(2) ? 1 : -1) : -1) : 1) : (y > 1 ? (y < ROWNO ? (rn2(3) - 1) : -rn2(2)) : rn2(2))); } /* count_wsegs() * * returns * the number of visible segments that a worm has. */ int count_wsegs(mtmp) struct monst *mtmp; { register int i=0; register struct wseg *curr = (wtails[mtmp->wormno])->nseg; /* if (!mtmp->wormno) return 0; bullet proofing */ while (curr) { i++; curr = curr->nseg; } return i; } /* create_worm_tail() * * will create a worm tail chain of (num_segs + 1) and return a pointer to it. */ STATIC_OVL struct wseg * create_worm_tail(num_segs) int num_segs; { register int i=0; register struct wseg *new_tail, *curr; if (!num_segs) return (struct wseg *)0; new_tail = curr = newseg(); curr->nseg = (struct wseg *)0; curr->wx = 0; curr->wy = 0; while (i < num_segs) { curr->nseg = newseg(); curr = curr->nseg; curr->nseg = (struct wseg *)0; curr->wx = 0; curr->wy = 0; i++; } return (new_tail); } /* worm_known() * * Is any segment of this worm in viewing range? Note: caller must check * invisibility and telepathy (which should only show the head anyway). * Mostly used in the canseemon() macro. */ boolean worm_known(worm) struct monst *worm; { struct wseg *curr = wtails[worm->wormno]; while (curr) { if(cansee(curr->wx,curr->wy)) return TRUE; curr = curr->nseg; } return FALSE; } /*worm.c*/ nethack-3.4.3/src/worn.c0100644000000000000000000005401707764735041013601 0ustar rootroot/* SCCS Id: @(#)worn.c 3.4 2003/01/08 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL void FDECL(m_lose_armor, (struct monst *,struct obj *)); STATIC_DCL void FDECL(m_dowear_type, (struct monst *,long, BOOLEAN_P, BOOLEAN_P)); STATIC_DCL int FDECL(extra_pref, (struct monst *, struct obj *)); const struct worn { long w_mask; struct obj **w_obj; } worn[] = { { W_ARM, &uarm }, { W_ARMC, &uarmc }, { W_ARMH, &uarmh }, { W_ARMS, &uarms }, { W_ARMG, &uarmg }, { W_ARMF, &uarmf }, #ifdef TOURIST { W_ARMU, &uarmu }, #endif { W_RINGL, &uleft }, { W_RINGR, &uright }, { W_WEP, &uwep }, { W_SWAPWEP, &uswapwep }, { W_QUIVER, &uquiver }, { W_AMUL, &uamul }, { W_TOOL, &ublindf }, { W_BALL, &uball }, { W_CHAIN, &uchain }, { 0, 0 } }; /* This only allows for one blocking item per property */ #define w_blocks(o,m) \ ((o->otyp == MUMMY_WRAPPING && ((m) & W_ARMC)) ? INVIS : \ (o->otyp == CORNUTHAUM && ((m) & W_ARMH) && \ !Role_if(PM_WIZARD)) ? CLAIRVOYANT : 0) /* note: monsters don't have clairvoyance, so your role has no significant effect on their use of w_blocks() */ /* Updated to use the extrinsic and blocked fields. */ void setworn(obj, mask) register struct obj *obj; long mask; { register const struct worn *wp; register struct obj *oobj; register int p; if ((mask & (W_ARM|I_SPECIAL)) == (W_ARM|I_SPECIAL)) { /* restoring saved game; no properties are conferred via skin */ uskin = obj; /* assert( !uarm ); */ } else { for(wp = worn; wp->w_mask; wp++) if(wp->w_mask & mask) { oobj = *(wp->w_obj); if(oobj && !(oobj->owornmask & wp->w_mask)) impossible("Setworn: mask = %ld.", wp->w_mask); if(oobj) { if (u.twoweap && (oobj->owornmask & (W_WEP|W_SWAPWEP))) u.twoweap = 0; oobj->owornmask &= ~wp->w_mask; if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) { /* leave as "x = x y", here and below, for broken * compilers */ p = objects[oobj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask; if ((p = w_blocks(oobj,mask)) != 0) u.uprops[p].blocked &= ~wp->w_mask; if (oobj->oartifact) set_artifact_intrinsic(oobj, 0, mask); } } *(wp->w_obj) = obj; if(obj) { obj->owornmask |= wp->w_mask; /* Prevent getting/blocking intrinsics from wielding * potions, through the quiver, etc. * Allow weapon-tools, too. * wp_mask should be same as mask at this point. */ if (wp->w_mask & ~(W_SWAPWEP|W_QUIVER)) { if (obj->oclass == WEAPON_CLASS || is_weptool(obj) || mask != W_WEP) { p = objects[obj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic | wp->w_mask; if ((p = w_blocks(obj, mask)) != 0) u.uprops[p].blocked |= wp->w_mask; } if (obj->oartifact) set_artifact_intrinsic(obj, 1, mask); } } } } update_inventory(); } /* called e.g. when obj is destroyed */ /* Updated to use the extrinsic and blocked fields. */ void setnotworn(obj) register struct obj *obj; { register const struct worn *wp; register int p; if (!obj) return; if (obj == uwep || obj == uswapwep) u.twoweap = 0; for(wp = worn; wp->w_mask; wp++) if(obj == *(wp->w_obj)) { *(wp->w_obj) = 0; p = objects[obj->otyp].oc_oprop; u.uprops[p].extrinsic = u.uprops[p].extrinsic & ~wp->w_mask; obj->owornmask &= ~wp->w_mask; if (obj->oartifact) set_artifact_intrinsic(obj, 0, wp->w_mask); if ((p = w_blocks(obj,wp->w_mask)) != 0) u.uprops[p].blocked &= ~wp->w_mask; } update_inventory(); } void mon_set_minvis(mon) struct monst *mon; { mon->perminvis = 1; if (!mon->invis_blkd) { mon->minvis = 1; newsym(mon->mx, mon->my); /* make it disappear */ if (mon->wormno) see_wsegs(mon); /* and any tail too */ } } void mon_adjust_speed(mon, adjust, obj) struct monst *mon; int adjust; /* positive => increase speed, negative => decrease */ struct obj *obj; /* item to make known if effect can be seen */ { struct obj *otmp; boolean give_msg = !in_mklev, petrify = FALSE; unsigned int oldspeed = mon->mspeed; switch (adjust) { case 2: mon->permspeed = MFAST; give_msg = FALSE; /* special case monster creation */ break; case 1: if (mon->permspeed == MSLOW) mon->permspeed = 0; else mon->permspeed = MFAST; break; case 0: /* just check for worn speed boots */ break; case -1: if (mon->permspeed == MFAST) mon->permspeed = 0; else mon->permspeed = MSLOW; break; case -2: mon->permspeed = MSLOW; give_msg = FALSE; /* (not currently used) */ break; case -3: /* petrification */ /* take away intrinsic speed but don't reduce normal speed */ if (mon->permspeed == MFAST) mon->permspeed = 0; petrify = TRUE; break; } for (otmp = mon->minvent; otmp; otmp = otmp->nobj) if (otmp->owornmask && objects[otmp->otyp].oc_oprop == FAST) break; if (otmp) /* speed boots */ mon->mspeed = MFAST; else mon->mspeed = mon->permspeed; if (give_msg && (mon->mspeed != oldspeed || petrify) && canseemon(mon)) { /* fast to slow (skipping intermediate state) or vice versa */ const char *howmuch = (mon->mspeed + oldspeed == MFAST + MSLOW) ? "much " : ""; if (petrify) { /* mimic the player's petrification countdown; "slowing down" even if fast movement rate retained via worn speed boots */ if (flags.verbose) pline("%s is slowing down.", Monnam(mon)); } else if (adjust > 0 || mon->mspeed == MFAST) pline("%s is suddenly moving %sfaster.", Monnam(mon), howmuch); else pline("%s seems to be moving %sslower.", Monnam(mon), howmuch); /* might discover an object if we see the speed change happen, but avoid making possibly forgotten book known when casting its spell */ if (obj != 0 && obj->dknown && objects[obj->otyp].oc_class != SPBOOK_CLASS) makeknown(obj->otyp); } } /* armor put on or taken off; might be magical variety */ void update_mon_intrinsics(mon, obj, on, silently) struct monst *mon; struct obj *obj; boolean on, silently; { int unseen; uchar mask; struct obj *otmp; int which = (int) objects[obj->otyp].oc_oprop; unseen = !canseemon(mon); if (!which) goto maybe_blocks; if (on) { switch (which) { case INVIS: mon->minvis = !mon->invis_blkd; break; case FAST: { boolean save_in_mklev = in_mklev; if (silently) in_mklev = TRUE; mon_adjust_speed(mon, 0, obj); in_mklev = save_in_mklev; break; } /* properties handled elsewhere */ case ANTIMAGIC: case REFLECTING: break; /* properties which have no effect for monsters */ case CLAIRVOYANT: case STEALTH: case TELEPAT: break; /* properties which should have an effect but aren't implemented */ case LEVITATION: case WWALKING: break; /* properties which maybe should have an effect but don't */ case DISPLACED: case FUMBLING: case JUMPING: case PROTECTION: break; default: if (which <= 8) { /* 1 thru 8 correspond to MR_xxx mask values */ /* FIRE,COLD,SLEEP,DISINT,SHOCK,POISON,ACID,STONE */ mask = (uchar) (1 << (which - 1)); mon->mintrinsics |= (unsigned short) mask; } break; } } else { /* off */ switch (which) { case INVIS: mon->minvis = mon->perminvis; break; case FAST: { boolean save_in_mklev = in_mklev; if (silently) in_mklev = TRUE; mon_adjust_speed(mon, 0, obj); in_mklev = save_in_mklev; break; } case FIRE_RES: case COLD_RES: case SLEEP_RES: case DISINT_RES: case SHOCK_RES: case POISON_RES: case ACID_RES: case STONE_RES: mask = (uchar) (1 << (which - 1)); /* If the monster doesn't have this resistance intrinsically, check whether any other worn item confers it. Note that we don't currently check for anything conferred via simply carrying an object. */ if (!(mon->data->mresists & mask)) { for (otmp = mon->minvent; otmp; otmp = otmp->nobj) if (otmp->owornmask && (int) objects[otmp->otyp].oc_oprop == which) break; if (!otmp) mon->mintrinsics &= ~((unsigned short) mask); } break; default: break; } } maybe_blocks: /* obj->owornmask has been cleared by this point, so we can't use it. However, since monsters don't wield armor, we don't have to guard against that and can get away with a blanket worn-mask value. */ switch (w_blocks(obj,~0L)) { case INVIS: mon->invis_blkd = on ? 1 : 0; mon->minvis = on ? 0 : mon->perminvis; break; default: break; } #ifdef STEED if (!on && mon == u.usteed && obj->otyp == SADDLE) dismount_steed(DISMOUNT_FELL); #endif /* if couldn't see it but now can, or vice versa, update display */ if (!silently && (unseen ^ !canseemon(mon))) newsym(mon->mx, mon->my); } int find_mac(mon) register struct monst *mon; { register struct obj *obj; int base = mon->data->ac; long mwflags = mon->misc_worn_check; for (obj = mon->minvent; obj; obj = obj->nobj) { if (obj->owornmask & mwflags) base -= ARM_BONUS(obj); /* since ARM_BONUS is positive, subtracting it increases AC */ } return base; } /* weapons are handled separately; rings and eyewear aren't used by monsters */ /* Wear the best object of each type that the monster has. During creation, * the monster can put everything on at once; otherwise, wearing takes time. * This doesn't affect monster searching for objects--a monster may very well * search for objects it would not want to wear, because we don't want to * check which_armor() each round. * * We'll let monsters put on shirts and/or suits under worn cloaks, but * not shirts under worn suits. This is somewhat arbitrary, but it's * too tedious to have them remove and later replace outer garments, * and preventing suits under cloaks makes it a little bit too easy for * players to influence what gets worn. Putting on a shirt underneath * already worn body armor is too obviously buggy... */ void m_dowear(mon, creation) register struct monst *mon; boolean creation; { #define RACE_EXCEPTION TRUE /* Note the restrictions here are the same as in dowear in do_wear.c * except for the additional restriction on intelligence. (Players * are always intelligent, even if polymorphed). */ if (verysmall(mon->data) || nohands(mon->data) || is_animal(mon->data)) return; /* give mummies a chance to wear their wrappings * and let skeletons wear their initial armor */ if (mindless(mon->data) && (!creation || (mon->data->mlet != S_MUMMY && mon->data != &mons[PM_SKELETON]))) return; m_dowear_type(mon, W_AMUL, creation, FALSE); #ifdef TOURIST /* can't put on shirt if already wearing suit */ if (!cantweararm(mon->data) || (mon->misc_worn_check & W_ARM)) m_dowear_type(mon, W_ARMU, creation, FALSE); #endif /* treating small as a special case allows hobbits, gnomes, and kobolds to wear cloaks */ if (!cantweararm(mon->data) || mon->data->msize == MZ_SMALL) m_dowear_type(mon, W_ARMC, creation, FALSE); m_dowear_type(mon, W_ARMH, creation, FALSE); if (!MON_WEP(mon) || !bimanual(MON_WEP(mon))) m_dowear_type(mon, W_ARMS, creation, FALSE); m_dowear_type(mon, W_ARMG, creation, FALSE); if (!slithy(mon->data) && mon->data->mlet != S_CENTAUR) m_dowear_type(mon, W_ARMF, creation, FALSE); if (!cantweararm(mon->data)) m_dowear_type(mon, W_ARM, creation, FALSE); else m_dowear_type(mon, W_ARM, creation, RACE_EXCEPTION); } STATIC_OVL void m_dowear_type(mon, flag, creation, racialexception) struct monst *mon; long flag; boolean creation; boolean racialexception; { struct obj *old, *best, *obj; int m_delay = 0; int unseen = !canseemon(mon); char nambuf[BUFSZ]; if (mon->mfrozen) return; /* probably putting previous item on */ /* Get a copy of monster's name before altering its visibility */ Strcpy(nambuf, See_invisible ? Monnam(mon) : mon_nam(mon)); old = which_armor(mon, flag); if (old && old->cursed) return; if (old && flag == W_AMUL) return; /* no such thing as better amulets */ best = old; for(obj = mon->minvent; obj; obj = obj->nobj) { switch(flag) { case W_AMUL: if (obj->oclass != AMULET_CLASS || (obj->otyp != AMULET_OF_LIFE_SAVING && obj->otyp != AMULET_OF_REFLECTION)) continue; best = obj; goto outer_break; /* no such thing as better amulets */ #ifdef TOURIST case W_ARMU: if (!is_shirt(obj)) continue; break; #endif case W_ARMC: if (!is_cloak(obj)) continue; break; case W_ARMH: if (!is_helmet(obj)) continue; /* (flimsy exception matches polyself handling) */ if (has_horns(mon->data) && !is_flimsy(obj)) continue; break; case W_ARMS: if (!is_shield(obj)) continue; break; case W_ARMG: if (!is_gloves(obj)) continue; break; case W_ARMF: if (!is_boots(obj)) continue; break; case W_ARM: if (!is_suit(obj)) continue; if (racialexception && (racial_exception(mon, obj) < 1)) continue; break; } if (obj->owornmask) continue; /* I'd like to define a VISIBLE_ARM_BONUS which doesn't assume the * monster knows obj->spe, but if I did that, a monster would keep * switching forever between two -2 caps since when it took off one * it would forget spe and once again think the object is better * than what it already has. */ if (best && (ARM_BONUS(best) + extra_pref(mon,best) >= ARM_BONUS(obj) + extra_pref(mon,obj))) continue; best = obj; } outer_break: if (!best || best == old) return; /* if wearing a cloak, account for the time spent removing and re-wearing it when putting on a suit or shirt */ if ((flag == W_ARM #ifdef TOURIST || flag == W_ARMU #endif ) && (mon->misc_worn_check & W_ARMC)) m_delay += 2; /* when upgrading a piece of armor, account for time spent taking off current one */ if (old) m_delay += objects[old->otyp].oc_delay; if (old) /* do this first to avoid "(being worn)" */ old->owornmask = 0L; if (!creation) { if (canseemon(mon)) { char buf[BUFSZ]; if (old) Sprintf(buf, " removes %s and", distant_name(old, doname)); else buf[0] = '\0'; pline("%s%s puts on %s.", Monnam(mon), buf, distant_name(best,doname)); } /* can see it */ m_delay += objects[best->otyp].oc_delay; mon->mfrozen = m_delay; if (mon->mfrozen) mon->mcanmove = 0; } if (old) update_mon_intrinsics(mon, old, FALSE, creation); mon->misc_worn_check |= flag; best->owornmask |= flag; update_mon_intrinsics(mon, best, TRUE, creation); /* if couldn't see it but now can, or vice versa, */ if (!creation && (unseen ^ !canseemon(mon))) { if (mon->minvis && !See_invisible) { pline("Suddenly you cannot see %s.", nambuf); makeknown(best->otyp); } /* else if (!mon->minvis) pline("%s suddenly appears!", Amonnam(mon)); */ } } #undef RACE_EXCEPTION struct obj * which_armor(mon, flag) struct monst *mon; long flag; { register struct obj *obj; for(obj = mon->minvent; obj; obj = obj->nobj) if (obj->owornmask & flag) return obj; return((struct obj *)0); } /* remove an item of armor and then drop it */ STATIC_OVL void m_lose_armor(mon, obj) struct monst *mon; struct obj *obj; { mon->misc_worn_check &= ~obj->owornmask; if (obj->owornmask) update_mon_intrinsics(mon, obj, FALSE, FALSE); obj->owornmask = 0L; obj_extract_self(obj); place_object(obj, mon->mx, mon->my); /* call stackobj() if we ever drop anything that can merge */ newsym(mon->mx, mon->my); } /* all objects with their bypass bit set should now be reset to normal */ void clear_bypasses() { struct obj *otmp, *nobj; struct monst *mtmp; for (otmp = fobj; otmp; otmp = nobj) { nobj = otmp->nobj; if (otmp->bypass) { otmp->bypass = 0; /* bypass will have inhibited any stacking, but since it's used for polymorph handling, the objects here probably have been transformed and won't be stacked in the usual manner afterwards; so don't bother with this */ #if 0 if (objects[otmp->otyp].oc_merge) { xchar ox, oy; (void) get_obj_location(otmp, &ox, &oy, 0); stack_object(otmp); newsym(ox, oy); } #endif /*0*/ } } /* invent and mydogs chains shouldn't matter here */ for (otmp = migrating_objs; otmp; otmp = otmp->nobj) otmp->bypass = 0; for (mtmp = fmon; mtmp; mtmp = mtmp->nmon) { if (DEADMONSTER(mtmp)) continue; for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; } for (mtmp = migrating_mons; mtmp; mtmp = mtmp->nmon) { for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->bypass = 0; } flags.bypasses = FALSE; } void bypass_obj(obj) struct obj *obj; { obj->bypass = 1; flags.bypasses = TRUE; } void mon_break_armor(mon, polyspot) struct monst *mon; boolean polyspot; { register struct obj *otmp; struct permonst *mdat = mon->data; boolean vis = cansee(mon->mx, mon->my); boolean handless_or_tiny = (nohands(mdat) || verysmall(mdat)); const char *pronoun = mhim(mon), *ppronoun = mhis(mon); if (breakarm(mdat)) { if ((otmp = which_armor(mon, W_ARM)) != 0) { if ((Is_dragon_scales(otmp) && mdat == Dragon_scales_to_pm(otmp)) || (Is_dragon_mail(otmp) && mdat == Dragon_mail_to_pm(otmp))) ; /* no message here; "the dragon merges with his scaly armor" is odd and the monster's previous form is already gone */ else if (vis) pline("%s breaks out of %s armor!", Monnam(mon), ppronoun); else You_hear("a cracking sound."); m_useup(mon, otmp); } if ((otmp = which_armor(mon, W_ARMC)) != 0) { if (otmp->oartifact) { if (vis) pline("%s %s falls off!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } else { if (vis) pline("%s %s tears apart!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); else You_hear("a ripping sound."); m_useup(mon, otmp); } } #ifdef TOURIST if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) pline("%s shirt rips to shreds!", s_suffix(Monnam(mon))); else You_hear("a ripping sound."); m_useup(mon, otmp); } #endif } else if (sliparm(mdat)) { if ((otmp = which_armor(mon, W_ARM)) != 0) { if (vis) pline("%s armor falls around %s!", s_suffix(Monnam(mon)), pronoun); else You_hear("a thud."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } if ((otmp = which_armor(mon, W_ARMC)) != 0) { if (vis) { if (is_whirly(mon->data)) pline("%s %s falls, unsupported!", s_suffix(Monnam(mon)), cloak_simple_name(otmp)); else pline("%s shrinks out of %s %s!", Monnam(mon), ppronoun, cloak_simple_name(otmp)); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } #ifdef TOURIST if ((otmp = which_armor(mon, W_ARMU)) != 0) { if (vis) { if (sliparm(mon->data)) pline("%s seeps right through %s shirt!", Monnam(mon), ppronoun); else pline("%s becomes much too small for %s shirt!", Monnam(mon), ppronoun); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } #endif } if (handless_or_tiny) { /* [caller needs to handle weapon checks] */ if ((otmp = which_armor(mon, W_ARMG)) != 0) { if (vis) pline("%s drops %s gloves%s!", Monnam(mon), ppronoun, MON_WEP(mon) ? " and weapon" : ""); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } if ((otmp = which_armor(mon, W_ARMS)) != 0) { if (vis) pline("%s can no longer hold %s shield!", Monnam(mon), ppronoun); else You_hear("a clank."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (handless_or_tiny || has_horns(mdat)) { if ((otmp = which_armor(mon, W_ARMH)) != 0 && /* flimsy test for horns matches polyself handling */ (handless_or_tiny || !is_flimsy(otmp))) { if (vis) pline("%s helmet falls to the %s!", s_suffix(Monnam(mon)), surface(mon->mx, mon->my)); else You_hear("a clank."); if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } if (handless_or_tiny || slithy(mdat) || mdat->mlet == S_CENTAUR) { if ((otmp = which_armor(mon, W_ARMF)) != 0) { if (vis) { if (is_whirly(mon->data)) pline("%s boots fall away!", s_suffix(Monnam(mon))); else pline("%s boots %s off %s feet!", s_suffix(Monnam(mon)), verysmall(mdat) ? "slide" : "are pushed", ppronoun); } if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); } } #ifdef STEED if (!can_saddle(mon)) { if ((otmp = which_armor(mon, W_SADDLE)) != 0) { if (polyspot) bypass_obj(otmp); m_lose_armor(mon, otmp); if (vis) pline("%s saddle falls off.", s_suffix(Monnam(mon))); } if (mon == u.usteed) goto noride; } else if (mon == u.usteed && !can_ride(mon)) { noride: You("can no longer ride %s.", mon_nam(mon)); if (touch_petrifies(u.usteed->data) && !Stone_resistance && rnl(3)) { char buf[BUFSZ]; You("touch %s.", mon_nam(u.usteed)); Sprintf(buf, "falling off %s", an(u.usteed->data->mname)); instapetrify(buf); } dismount_steed(DISMOUNT_FELL); } #endif return; } /* bias a monster's preferences towards armor that has special benefits. */ /* currently only does speed boots, but might be expanded if monsters get to use more armor abilities */ static int extra_pref(mon, obj) struct monst *mon; struct obj *obj; { if (obj) { if (obj->otyp == SPEED_BOOTS && mon->permspeed != MFAST) return 20; } return 0; } /* * Exceptions to things based on race. Correctly checks polymorphed player race. * Returns: * 0 No exception, normal rules apply. * 1 If the race/object combination is acceptable. * -1 If the race/object combination is unacceptable. */ int racial_exception(mon, obj) struct monst *mon; struct obj *obj; { const struct permonst *ptr = raceptr(mon); /* Acceptable Exceptions: */ /* Allow hobbits to wear elven armor - LoTR */ if (ptr == &mons[PM_HOBBIT] && is_elven_armor(obj)) return 1; /* Unacceptable Exceptions: */ /* Checks for object that certain races should never use go here */ /* return -1; */ return 0; } /*worn.c*/ nethack-3.4.3/src/write.c0100644000000000000000000001375707764735041013754 0ustar rootroot/* SCCS Id: @(#)write.c 3.4 2001/11/29 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" STATIC_DCL int FDECL(cost,(struct obj *)); /* * returns basecost of a scroll or a spellbook */ STATIC_OVL int cost(otmp) register struct obj *otmp; { if (otmp->oclass == SPBOOK_CLASS) return(10 * objects[otmp->otyp].oc_level); switch (otmp->otyp) { # ifdef MAIL case SCR_MAIL: return(2); /* break; */ # endif case SCR_LIGHT: case SCR_GOLD_DETECTION: case SCR_FOOD_DETECTION: case SCR_MAGIC_MAPPING: case SCR_AMNESIA: case SCR_FIRE: case SCR_EARTH: return(8); /* break; */ case SCR_DESTROY_ARMOR: case SCR_CREATE_MONSTER: case SCR_PUNISHMENT: return(10); /* break; */ case SCR_CONFUSE_MONSTER: return(12); /* break; */ case SCR_IDENTIFY: return(14); /* break; */ case SCR_ENCHANT_ARMOR: case SCR_REMOVE_CURSE: case SCR_ENCHANT_WEAPON: case SCR_CHARGING: return(16); /* break; */ case SCR_SCARE_MONSTER: case SCR_STINKING_CLOUD: case SCR_TAMING: case SCR_TELEPORTATION: return(20); /* break; */ case SCR_GENOCIDE: return(30); /* break; */ case SCR_BLANK_PAPER: default: impossible("You can't write such a weird scroll!"); } return(1000); } static NEARDATA const char write_on[] = { SCROLL_CLASS, SPBOOK_CLASS, 0 }; int dowrite(pen) register struct obj *pen; { register struct obj *paper; char namebuf[BUFSZ], *nm, *bp; register struct obj *new_obj; int basecost, actualcost; int curseval; char qbuf[QBUFSZ]; int first, last, i; boolean by_descr = FALSE; const char *typeword; if (nohands(youmonst.data)) { You("need hands to be able to write!"); return 0; } else if (Glib) { pline("%s from your %s.", Tobjnam(pen, "slip"), makeplural(body_part(FINGER))); dropx(pen); return 1; } /* get paper to write on */ paper = getobj(write_on,"write on"); if(!paper) return(0); typeword = (paper->oclass == SPBOOK_CLASS) ? "spellbook" : "scroll"; if(Blind && !paper->dknown) { You("don't know if that %s is blank or not!", typeword); return(1); } paper->dknown = 1; if(paper->otyp != SCR_BLANK_PAPER && paper->otyp != SPE_BLANK_PAPER) { pline("That %s is not blank!", typeword); exercise(A_WIS, FALSE); return(1); } /* what to write */ Sprintf(qbuf, "What type of %s do you want to write?", typeword); getlin(qbuf, namebuf); (void)mungspaces(namebuf); /* remove any excess whitespace */ if(namebuf[0] == '\033' || !namebuf[0]) return(1); nm = namebuf; if (!strncmpi(nm, "scroll ", 7)) nm += 7; else if (!strncmpi(nm, "spellbook ", 10)) nm += 10; if (!strncmpi(nm, "of ", 3)) nm += 3; if ((bp = strstri(nm, " armour")) != 0) { (void)strncpy(bp, " armor ", 7); /* won't add '\0' */ (void)mungspaces(bp + 1); /* remove the extra space */ } first = bases[(int)paper->oclass]; last = bases[(int)paper->oclass + 1] - 1; for (i = first; i <= last; i++) { /* extra shufflable descr not representing a real object */ if (!OBJ_NAME(objects[i])) continue; if (!strcmpi(OBJ_NAME(objects[i]), nm)) goto found; if (!strcmpi(OBJ_DESCR(objects[i]), nm)) { by_descr = TRUE; goto found; } } There("is no such %s!", typeword); return 1; found: if (i == SCR_BLANK_PAPER || i == SPE_BLANK_PAPER) { You_cant("write that!"); pline("It's obscene!"); return 1; } else if (i == SPE_BOOK_OF_THE_DEAD) { pline("No mere dungeon adventurer could write that."); return 1; } else if (by_descr && paper->oclass == SPBOOK_CLASS && !objects[i].oc_name_known) { /* can't write unknown spellbooks by description */ pline( "Unfortunately you don't have enough information to go on."); return 1; } /* KMH, conduct */ u.uconduct.literate++; new_obj = mksobj(i, FALSE, FALSE); new_obj->bknown = (paper->bknown && pen->bknown); /* shk imposes a flat rate per use, not based on actual charges used */ check_unpaid(pen); /* see if there's enough ink */ basecost = cost(new_obj); if(pen->spe < basecost/2) { Your("marker is too dry to write that!"); obfree(new_obj, (struct obj *) 0); return(1); } /* we're really going to write now, so calculate cost */ actualcost = rn1(basecost/2,basecost/2); curseval = bcsign(pen) + bcsign(paper); exercise(A_WIS, TRUE); /* dry out marker */ if (pen->spe < actualcost) { pen->spe = 0; Your("marker dries out!"); /* scrolls disappear, spellbooks don't */ if (paper->oclass == SPBOOK_CLASS) { pline_The( "spellbook is left unfinished and your writing fades."); update_inventory(); /* pen charges */ } else { pline_The("scroll is now useless and disappears!"); useup(paper); } obfree(new_obj, (struct obj *) 0); return(1); } pen->spe -= actualcost; /* can't write if we don't know it - unless we're lucky */ if(!(objects[new_obj->otyp].oc_name_known) && !(objects[new_obj->otyp].oc_uname) && (rnl(Role_if(PM_WIZARD) ? 3 : 15))) { You("%s to write that!", by_descr ? "fail" : "don't know how"); /* scrolls disappear, spellbooks don't */ if (paper->oclass == SPBOOK_CLASS) { You( "write in your best handwriting: \"My Diary\", but it quickly fades."); update_inventory(); /* pen charges */ } else { if (by_descr) { Strcpy(namebuf, OBJ_DESCR(objects[new_obj->otyp])); wipeout_text(namebuf, (6+MAXULEV - u.ulevel)/6, 0); } else Sprintf(namebuf, "%s was here!", plname); You("write \"%s\" and the scroll disappears.", namebuf); useup(paper); } obfree(new_obj, (struct obj *) 0); return(1); } /* useup old scroll / spellbook */ useup(paper); /* success */ if (new_obj->oclass == SPBOOK_CLASS) { /* acknowledge the change in the object's description... */ pline_The("spellbook warps strangely, then turns %s.", OBJ_DESCR(objects[new_obj->otyp])); } new_obj->blessed = (curseval > 0); new_obj->cursed = (curseval < 0); #ifdef MAIL if (new_obj->otyp == SCR_MAIL) new_obj->spe = 1; #endif new_obj = hold_another_object(new_obj, "Oops! %s out of your grasp!", The(aobjnam(new_obj, "slip")), (const char *)0); return(1); } /*write.c*/ nethack-3.4.3/src/zap.c0100644000000000000000000033127607764735041013413 0ustar rootroot/* SCCS Id: @(#)zap.c 3.4 2003/08/24 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" /* Disintegration rays have special treatment; corpses are never left. * But the routine which calculates the damage is separate from the routine * which kills the monster. The damage routine returns this cookie to * indicate that the monster should be disintegrated. */ #define MAGIC_COOKIE 1000 #ifdef OVLB static NEARDATA boolean obj_zapped; static NEARDATA int poly_zapped; #endif extern boolean notonhead; /* for long worms */ /* kludge to use mondied instead of killed */ extern boolean m_using; STATIC_DCL void FDECL(costly_cancel, (struct obj *)); STATIC_DCL void FDECL(polyuse, (struct obj*, int, int)); STATIC_DCL void FDECL(create_polymon, (struct obj *, int)); STATIC_DCL boolean FDECL(zap_updown, (struct obj *)); STATIC_DCL int FDECL(zhitm, (struct monst *,int,int,struct obj **)); STATIC_DCL void FDECL(zhitu, (int,int,const char *,XCHAR_P,XCHAR_P)); STATIC_DCL void FDECL(revive_egg, (struct obj *)); #ifdef STEED STATIC_DCL boolean FDECL(zap_steed, (struct obj *)); #endif #ifdef OVLB STATIC_DCL int FDECL(zap_hit, (int,int)); #endif #ifdef OVL0 STATIC_DCL void FDECL(backfire, (struct obj *)); STATIC_DCL int FDECL(spell_hit_bonus, (int)); #endif #define ZT_MAGIC_MISSILE (AD_MAGM-1) #define ZT_FIRE (AD_FIRE-1) #define ZT_COLD (AD_COLD-1) #define ZT_SLEEP (AD_SLEE-1) #define ZT_DEATH (AD_DISN-1) /* or disintegration */ #define ZT_LIGHTNING (AD_ELEC-1) #define ZT_POISON_GAS (AD_DRST-1) #define ZT_ACID (AD_ACID-1) /* 8 and 9 are currently unassigned */ #define ZT_WAND(x) (x) #define ZT_SPELL(x) (10+(x)) #define ZT_BREATH(x) (20+(x)) #define is_hero_spell(type) ((type) >= 10 && (type) < 20) #ifndef OVLB STATIC_VAR const char are_blinded_by_the_flash[]; extern const char * const flash_types[]; #else STATIC_VAR const char are_blinded_by_the_flash[] = "are blinded by the flash!"; const char * const flash_types[] = { /* also used in buzzmu(mcastu.c) */ "magic missile", /* Wands must be 0-9 */ "bolt of fire", "bolt of cold", "sleep ray", "death ray", "bolt of lightning", "", "", "", "", "magic missile", /* Spell equivalents must be 10-19 */ "fireball", "cone of cold", "sleep ray", "finger of death", "bolt of lightning", /* There is no spell, used for retribution */ "", "", "", "", "blast of missiles", /* Dragon breath equivalents 20-29*/ "blast of fire", "blast of frost", "blast of sleep gas", "blast of disintegration", "blast of lightning", "blast of poison gas", "blast of acid", "", "" }; /* Routines for IMMEDIATE wands and spells. */ /* bhitm: monster mtmp was hit by the effect of wand or spell otmp */ int bhitm(mtmp, otmp) struct monst *mtmp; struct obj *otmp; { boolean wake = TRUE; /* Most 'zaps' should wake monster */ boolean reveal_invis = FALSE; boolean dbldam = Role_if(PM_KNIGHT) && u.uhave.questart; int dmg, otyp = otmp->otyp; const char *zap_type_text = "spell"; struct obj *obj; boolean disguised_mimic = (mtmp->data->mlet == S_MIMIC && mtmp->m_ap_type != M_AP_NOTHING); if (u.uswallow && mtmp == u.ustuck) reveal_invis = FALSE; switch(otyp) { case WAN_STRIKING: zap_type_text = "wand"; /* fall through */ case SPE_FORCE_BOLT: reveal_invis = TRUE; if (resists_magm(mtmp)) { /* match effect on player */ shieldeff(mtmp->mx, mtmp->my); break; /* skip makeknown */ } else if (u.uswallow || rnd(20) < 10 + find_mac(mtmp)) { dmg = d(2,12); if(dbldam) dmg *= 2; if (otyp == SPE_FORCE_BOLT) dmg += spell_damage_bonus(); hit(zap_type_text, mtmp, exclam(dmg)); (void) resist(mtmp, otmp->oclass, dmg, TELL); } else miss(zap_type_text, mtmp); makeknown(otyp); break; case WAN_SLOW_MONSTER: case SPE_SLOW_MONSTER: if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { mon_adjust_speed(mtmp, -1, otmp); m_dowear(mtmp, FALSE); /* might want speed boots */ if (u.uswallow && (mtmp == u.ustuck) && is_whirly(mtmp->data)) { You("disrupt %s!", mon_nam(mtmp)); pline("A huge hole opens up..."); expels(mtmp, mtmp->data, TRUE); } } break; case WAN_SPEED_MONSTER: if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { mon_adjust_speed(mtmp, 1, otmp); m_dowear(mtmp, FALSE); /* might want speed boots */ } break; case WAN_UNDEAD_TURNING: case SPE_TURN_UNDEAD: wake = FALSE; if (unturn_dead(mtmp)) wake = TRUE; if (is_undead(mtmp->data)) { reveal_invis = TRUE; wake = TRUE; dmg = rnd(8); if(dbldam) dmg *= 2; if (otyp == SPE_TURN_UNDEAD) dmg += spell_damage_bonus(); flags.bypasses = TRUE; /* for make_corpse() */ if (!resist(mtmp, otmp->oclass, dmg, NOTELL)) { if (mtmp->mhp > 0) monflee(mtmp, 0, FALSE, TRUE); } } break; case WAN_POLYMORPH: case SPE_POLYMORPH: case POT_POLYMORPH: if (resists_magm(mtmp)) { /* magic resistance protects from polymorph traps, so make it guard against involuntary polymorph attacks too... */ shieldeff(mtmp->mx, mtmp->my); } else if (!resist(mtmp, otmp->oclass, 0, NOTELL)) { /* natural shapechangers aren't affected by system shock (unless protection from shapechangers is interfering with their metabolism...) */ if (mtmp->cham == CHAM_ORDINARY && !rn2(25)) { if (canseemon(mtmp)) { pline("%s shudders!", Monnam(mtmp)); makeknown(otyp); } /* dropped inventory shouldn't be hit by this zap */ for (obj = mtmp->minvent; obj; obj = obj->nobj) bypass_obj(obj); /* flags.bypasses = TRUE; ## for make_corpse() */ /* no corpse after system shock */ xkilled(mtmp, 3); } else if (newcham(mtmp, (struct permonst *)0, (otyp != POT_POLYMORPH), FALSE)) { if (!Hallucination && canspotmon(mtmp)) makeknown(otyp); } } break; case WAN_CANCELLATION: case SPE_CANCELLATION: (void) cancel_monst(mtmp, otmp, TRUE, TRUE, FALSE); break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: reveal_invis = !u_teleport_mon(mtmp, TRUE); break; case WAN_MAKE_INVISIBLE: { int oldinvis = mtmp->minvis; char nambuf[BUFSZ]; /* format monster's name before altering its visibility */ Strcpy(nambuf, Monnam(mtmp)); mon_set_minvis(mtmp); if (!oldinvis && knowninvisible(mtmp)) { pline("%s turns transparent!", nambuf); makeknown(otyp); } break; } case WAN_NOTHING: case WAN_LOCKING: case SPE_WIZARD_LOCK: wake = FALSE; break; case WAN_PROBING: wake = FALSE; reveal_invis = TRUE; probe_monster(mtmp); makeknown(otyp); break; case WAN_OPENING: case SPE_KNOCK: wake = FALSE; /* don't want immediate counterattack */ if (u.uswallow && mtmp == u.ustuck) { if (is_animal(mtmp->data)) { if (Blind) You_feel("a sudden rush of air!"); else pline("%s opens its mouth!", Monnam(mtmp)); } expels(mtmp, mtmp->data, TRUE); #ifdef STEED } else if (!!(obj = which_armor(mtmp, W_SADDLE))) { mtmp->misc_worn_check &= ~obj->owornmask; update_mon_intrinsics(mtmp, obj, FALSE, FALSE); obj->owornmask = 0L; obj_extract_self(obj); place_object(obj, mtmp->mx, mtmp->my); /* call stackobj() if we ever drop anything that can merge */ newsym(mtmp->mx, mtmp->my); #endif } break; case SPE_HEALING: case SPE_EXTRA_HEALING: reveal_invis = TRUE; if (mtmp->data != &mons[PM_PESTILENCE]) { wake = FALSE; /* wakeup() makes the target angry */ mtmp->mhp += d(6, otyp == SPE_EXTRA_HEALING ? 8 : 4); if (mtmp->mhp > mtmp->mhpmax) mtmp->mhp = mtmp->mhpmax; if (mtmp->mblinded) { mtmp->mblinded = 0; mtmp->mcansee = 1; } if (canseemon(mtmp)) { if (disguised_mimic) { if (mtmp->m_ap_type == M_AP_OBJECT && mtmp->mappearance == STRANGE_OBJECT) { /* it can do better now */ set_mimic_sym(mtmp); newsym(mtmp->mx, mtmp->my); } else mimic_hit_msg(mtmp, otyp); } else pline("%s looks%s better.", Monnam(mtmp), otyp == SPE_EXTRA_HEALING ? " much" : "" ); } if (mtmp->mtame || mtmp->mpeaceful) { adjalign(Role_if(PM_HEALER) ? 1 : sgn(u.ualign.type)); } } else { /* Pestilence */ /* Pestilence will always resist; damage is half of 3d{4,8} */ (void) resist(mtmp, otmp->oclass, d(3, otyp == SPE_EXTRA_HEALING ? 8 : 4), TELL); } break; case WAN_LIGHT: /* (broken wand) */ if (flash_hits_mon(mtmp, otmp)) { makeknown(WAN_LIGHT); reveal_invis = TRUE; } break; case WAN_SLEEP: /* (broken wand) */ /* [wakeup() doesn't rouse victims of temporary sleep, so it's okay to leave `wake' set to TRUE here] */ reveal_invis = TRUE; if (sleep_monst(mtmp, d(1 + otmp->spe, 12), WAND_CLASS)) slept_monst(mtmp); if (!Blind) makeknown(WAN_SLEEP); break; case SPE_STONE_TO_FLESH: if (monsndx(mtmp->data) == PM_STONE_GOLEM) { char *name = Monnam(mtmp); /* turn into flesh golem */ if (newcham(mtmp, &mons[PM_FLESH_GOLEM], FALSE, FALSE)) { if (canseemon(mtmp)) pline("%s turns to flesh!", name); } else { if (canseemon(mtmp)) pline("%s looks rather fleshy for a moment.", name); } } else wake = FALSE; break; case SPE_DRAIN_LIFE: dmg = rnd(8); if(dbldam) dmg *= 2; if (otyp == SPE_DRAIN_LIFE) dmg += spell_damage_bonus(); if (resists_drli(mtmp)) shieldeff(mtmp->mx, mtmp->my); else if (!resist(mtmp, otmp->oclass, dmg, NOTELL) && mtmp->mhp > 0) { mtmp->mhp -= dmg; mtmp->mhpmax -= dmg; if (mtmp->mhp <= 0 || mtmp->mhpmax <= 0 || mtmp->m_lev < 1) xkilled(mtmp, 1); else { mtmp->m_lev--; if (canseemon(mtmp)) pline("%s suddenly seems weaker!", Monnam(mtmp)); } } break; default: impossible("What an interesting effect (%d)", otyp); break; } if(wake) { if(mtmp->mhp > 0) { wakeup(mtmp); m_respond(mtmp); if(mtmp->isshk && !*u.ushops) hot_pursuit(mtmp); } else if(mtmp->m_ap_type) seemimic(mtmp); /* might unblock if mimicing a boulder/door */ } /* note: bhitpos won't be set if swallowed, but that's okay since * reveal_invis will be false. We can't use mtmp->mx, my since it * might be an invisible worm hit on the tail. */ if (reveal_invis) { if (mtmp->mhp > 0 && cansee(bhitpos.x, bhitpos.y) && !canspotmon(mtmp)) map_invisible(bhitpos.x, bhitpos.y); } return 0; } void probe_monster(mtmp) struct monst *mtmp; { struct obj *otmp; mstatusline(mtmp); if (notonhead) return; /* don't show minvent for long worm tail */ #ifndef GOLDOBJ if (mtmp->minvent || mtmp->mgold) { #else if (mtmp->minvent) { #endif for (otmp = mtmp->minvent; otmp; otmp = otmp->nobj) otmp->dknown = 1; /* treat as "seen" */ (void) display_minventory(mtmp, MINV_ALL, (char *)0); } else { pline("%s is not carrying anything.", noit_Monnam(mtmp)); } } #endif /*OVLB*/ #ifdef OVL1 /* * Return the object's physical location. This only makes sense for * objects that are currently on the level (i.e. migrating objects * are nowhere). By default, only things that can be seen (in hero's * inventory, monster's inventory, or on the ground) are reported. * By adding BURIED_TOO and/or CONTAINED_TOO flags, you can also get * the location of buried and contained objects. Note that if an * object is carried by a monster, its reported position may change * from turn to turn. This function returns FALSE if the position * is not available or subject to the constraints above. */ boolean get_obj_location(obj, xp, yp, locflags) struct obj *obj; xchar *xp, *yp; int locflags; { switch (obj->where) { case OBJ_INVENT: *xp = u.ux; *yp = u.uy; return TRUE; case OBJ_FLOOR: *xp = obj->ox; *yp = obj->oy; return TRUE; case OBJ_MINVENT: if (obj->ocarry->mx) { *xp = obj->ocarry->mx; *yp = obj->ocarry->my; return TRUE; } break; /* !mx => migrating monster */ case OBJ_BURIED: if (locflags & BURIED_TOO) { *xp = obj->ox; *yp = obj->oy; return TRUE; } break; case OBJ_CONTAINED: if (locflags & CONTAINED_TOO) return get_obj_location(obj->ocontainer, xp, yp, locflags); break; } *xp = *yp = 0; return FALSE; } boolean get_mon_location(mon, xp, yp, locflags) struct monst *mon; xchar *xp, *yp; int locflags; /* non-zero means get location even if monster is buried */ { if (mon == &youmonst) { *xp = u.ux; *yp = u.uy; return TRUE; } else if (mon->mx > 0 && (!mon->mburied || locflags)) { *xp = mon->mx; *yp = mon->my; return TRUE; } else { /* migrating or buried */ *xp = *yp = 0; return FALSE; } } /* used by revive() and animate_statue() */ struct monst * montraits(obj,cc) struct obj *obj; coord *cc; { struct monst *mtmp = (struct monst *)0; struct monst *mtmp2 = (struct monst *)0; if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) mtmp2 = get_mtraits(obj, TRUE); if (mtmp2) { /* save_mtraits() validated mtmp2->mnum */ mtmp2->data = &mons[mtmp2->mnum]; if (mtmp2->mhpmax <= 0 && !is_rider(mtmp2->data)) return (struct monst *)0; mtmp = makemon(mtmp2->data, cc->x, cc->y, NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH); if (!mtmp) return mtmp; /* heal the monster */ if (mtmp->mhpmax > mtmp2->mhpmax && is_rider(mtmp2->data)) mtmp2->mhpmax = mtmp->mhpmax; mtmp2->mhp = mtmp2->mhpmax; /* Get these ones from mtmp */ mtmp2->minvent = mtmp->minvent; /*redundant*/ /* monster ID is available if the monster died in the current game, but should be zero if the corpse was in a bones level (we cleared it when loading bones) */ if (!mtmp2->m_id) mtmp2->m_id = mtmp->m_id; mtmp2->mx = mtmp->mx; mtmp2->my = mtmp->my; mtmp2->mux = mtmp->mux; mtmp2->muy = mtmp->muy; mtmp2->mw = mtmp->mw; mtmp2->wormno = mtmp->wormno; mtmp2->misc_worn_check = mtmp->misc_worn_check; mtmp2->weapon_check = mtmp->weapon_check; mtmp2->mtrapseen = mtmp->mtrapseen; mtmp2->mflee = mtmp->mflee; mtmp2->mburied = mtmp->mburied; mtmp2->mundetected = mtmp->mundetected; mtmp2->mfleetim = mtmp->mfleetim; mtmp2->mlstmv = mtmp->mlstmv; mtmp2->m_ap_type = mtmp->m_ap_type; /* set these ones explicitly */ mtmp2->mavenge = 0; mtmp2->meating = 0; mtmp2->mleashed = 0; mtmp2->mtrapped = 0; mtmp2->msleeping = 0; mtmp2->mfrozen = 0; mtmp2->mcanmove = 1; /* most cancelled monsters return to normal, but some need to stay cancelled */ if (!dmgtype(mtmp2->data, AD_SEDU) #ifdef SEDUCE && !dmgtype(mtmp2->data, AD_SSEX) #endif ) mtmp2->mcan = 0; mtmp2->mcansee = 1; /* set like in makemon */ mtmp2->mblinded = 0; mtmp2->mstun = 0; mtmp2->mconf = 0; replmon(mtmp,mtmp2); } return mtmp2; } /* * get_container_location() returns the following information * about the outermost container: * loc argument gets set to: * OBJ_INVENT if in hero's inventory; return 0. * OBJ_FLOOR if on the floor; return 0. * OBJ_BURIED if buried; return 0. * OBJ_MINVENT if in monster's inventory; return monster. * container_nesting is updated with the nesting depth of the containers * if applicable. */ struct monst * get_container_location(obj, loc, container_nesting) struct obj *obj; int *loc; int *container_nesting; { if (!obj || !loc) return 0; if (container_nesting) *container_nesting = 0; while (obj && obj->where == OBJ_CONTAINED) { if (container_nesting) *container_nesting += 1; obj = obj->ocontainer; } if (obj) { *loc = obj->where; /* outermost container's location */ if (obj->where == OBJ_MINVENT) return obj->ocarry; } return (struct monst *)0; } /* * Attempt to revive the given corpse, return the revived monster if * successful. Note: this does NOT use up the corpse if it fails. */ struct monst * revive(obj) register struct obj *obj; { register struct monst *mtmp = (struct monst *)0; struct obj *container = (struct obj *)0; int container_nesting = 0; schar savetame = 0; boolean recorporealization = FALSE; boolean in_container = FALSE; if(obj->otyp == CORPSE) { int montype = obj->corpsenm; xchar x, y; if (obj->where == OBJ_CONTAINED) { /* deal with corpses in [possibly nested] containers */ struct monst *carrier; int holder = 0; container = obj->ocontainer; carrier = get_container_location(container, &holder, &container_nesting); switch(holder) { case OBJ_MINVENT: x = carrier->mx; y = carrier->my; in_container = TRUE; break; case OBJ_INVENT: x = u.ux; y = u.uy; in_container = TRUE; break; case OBJ_FLOOR: if (!get_obj_location(obj, &x, &y, CONTAINED_TOO)) return (struct monst *) 0; in_container = TRUE; break; default: return (struct monst *)0; } } else { /* only for invent, minvent, or floor */ if (!get_obj_location(obj, &x, &y, 0)) return (struct monst *) 0; } if (in_container) { /* Rules for revival from containers: - the container cannot be locked - the container cannot be heavily nested (>2 is arbitrary) - the container cannot be a statue or bag of holding (except in very rare cases for the latter) */ if (!x || !y || container->olocked || container_nesting > 2 || container->otyp == STATUE || (container->otyp == BAG_OF_HOLDING && rn2(40))) return (struct monst *)0; } if (MON_AT(x,y)) { coord new_xy; if (enexto(&new_xy, x, y, &mons[montype])) x = new_xy.x, y = new_xy.y; } if(cant_create(&montype, TRUE)) { /* make a zombie or worm instead */ mtmp = makemon(&mons[montype], x, y, NO_MINVENT|MM_NOWAIT); if (mtmp) { mtmp->mhp = mtmp->mhpmax = 100; mon_adjust_speed(mtmp, 2, (struct obj *)0); /* MFAST */ } } else { if (obj->oxlth && (obj->oattached == OATTACHED_MONST)) { coord xy; xy.x = x; xy.y = y; mtmp = montraits(obj, &xy); if (mtmp && mtmp->mtame && !mtmp->isminion) wary_dog(mtmp, TRUE); } else mtmp = makemon(&mons[montype], x, y, NO_MINVENT|MM_NOWAIT|MM_NOCOUNTBIRTH); if (mtmp) { if (obj->oxlth && (obj->oattached == OATTACHED_M_ID)) { unsigned m_id; struct monst *ghost; (void) memcpy((genericptr_t)&m_id, (genericptr_t)obj->oextra, sizeof(m_id)); ghost = find_mid(m_id, FM_FMON); if (ghost && ghost->data == &mons[PM_GHOST]) { int x2, y2; x2 = ghost->mx; y2 = ghost->my; if (ghost->mtame) savetame = ghost->mtame; if (canseemon(ghost)) pline("%s is suddenly drawn into its former body!", Monnam(ghost)); mondead(ghost); recorporealization = TRUE; newsym(x2, y2); } /* don't mess with obj->oxlth here */ obj->oattached = OATTACHED_NOTHING; } /* Monster retains its name */ if (obj->onamelth) mtmp = christen_monst(mtmp, ONAME(obj)); /* flag the quest leader as alive. */ if (mtmp->data->msound == MS_LEADER || mtmp->m_id == quest_status.leader_m_id) quest_status.leader_is_dead = FALSE; } } if (mtmp) { if (obj->oeaten) mtmp->mhp = eaten_stat(mtmp->mhp, obj); /* track that this monster was revived at least once */ mtmp->mrevived = 1; if (recorporealization) { /* If mtmp is revivification of former tame ghost*/ if (savetame) { struct monst *mtmp2 = tamedog(mtmp, (struct obj *)0); if (mtmp2) { mtmp2->mtame = savetame; mtmp = mtmp2; } } /* was ghost, now alive, it's all very confusing */ mtmp->mconf = 1; } switch (obj->where) { case OBJ_INVENT: useup(obj); break; case OBJ_FLOOR: /* in case MON_AT+enexto for invisible mon */ x = obj->ox, y = obj->oy; /* not useupf(), which charges */ if (obj->quan > 1L) obj = splitobj(obj, 1L); delobj(obj); newsym(x, y); break; case OBJ_MINVENT: m_useup(obj->ocarry, obj); break; case OBJ_CONTAINED: obj_extract_self(obj); obfree(obj, (struct obj *) 0); break; default: panic("revive"); } } } return mtmp; } STATIC_OVL void revive_egg(obj) struct obj *obj; { /* * Note: generic eggs with corpsenm set to NON_PM will never hatch. */ if (obj->otyp != EGG) return; if (obj->corpsenm != NON_PM && !dead_species(obj->corpsenm, TRUE)) attach_egg_hatch_timeout(obj); } /* try to revive all corpses and eggs carried by `mon' */ int unturn_dead(mon) struct monst *mon; { struct obj *otmp, *otmp2; struct monst *mtmp2; char owner[BUFSZ], corpse[BUFSZ]; boolean youseeit; int once = 0, res = 0; youseeit = (mon == &youmonst) ? TRUE : canseemon(mon); otmp2 = (mon == &youmonst) ? invent : mon->minvent; while ((otmp = otmp2) != 0) { otmp2 = otmp->nobj; if (otmp->otyp == EGG) revive_egg(otmp); if (otmp->otyp != CORPSE) continue; /* save the name; the object is liable to go away */ if (youseeit) Strcpy(corpse, corpse_xname(otmp, TRUE)); /* for a merged group, only one is revived; should this be fixed? */ if ((mtmp2 = revive(otmp)) != 0) { ++res; if (youseeit) { if (!once++) Strcpy(owner, (mon == &youmonst) ? "Your" : s_suffix(Monnam(mon))); pline("%s %s suddenly comes alive!", owner, corpse); } else if (canseemon(mtmp2)) pline("%s suddenly appears!", Amonnam(mtmp2)); } } return res; } #endif /*OVL1*/ #ifdef OVLB static const char charged_objs[] = { WAND_CLASS, WEAPON_CLASS, ARMOR_CLASS, 0 }; STATIC_OVL void costly_cancel(obj) register struct obj *obj; { char objroom; struct monst *shkp = (struct monst *)0; if (obj->no_charge) return; switch (obj->where) { case OBJ_INVENT: if (obj->unpaid) { shkp = shop_keeper(*u.ushops); if (!shkp) return; Norep("You cancel an unpaid object, you pay for it!"); bill_dummy_object(obj); } break; case OBJ_FLOOR: objroom = *in_rooms(obj->ox, obj->oy, SHOPBASE); shkp = shop_keeper(objroom); if (!shkp || !inhishop(shkp)) return; if (costly_spot(u.ux, u.uy) && objroom == *u.ushops) { Norep("You cancel it, you pay for it!"); bill_dummy_object(obj); } else (void) stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE); break; } } /* cancel obj, possibly carried by you or a monster */ void cancel_item(obj) register struct obj *obj; { boolean u_ring = (obj == uleft) || (obj == uright); register boolean holy = (obj->otyp == POT_WATER && obj->blessed); switch(obj->otyp) { case RIN_GAIN_STRENGTH: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_STR) -= obj->spe; flags.botl = 1; } break; case RIN_GAIN_CONSTITUTION: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_CON) -= obj->spe; flags.botl = 1; } break; case RIN_ADORNMENT: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_CHA) -= obj->spe; flags.botl = 1; } break; case RIN_INCREASE_ACCURACY: if ((obj->owornmask & W_RING) && u_ring) u.uhitinc -= obj->spe; break; case RIN_INCREASE_DAMAGE: if ((obj->owornmask & W_RING) && u_ring) u.udaminc -= obj->spe; break; case GAUNTLETS_OF_DEXTERITY: if ((obj->owornmask & W_ARMG) && (obj == uarmg)) { ABON(A_DEX) -= obj->spe; flags.botl = 1; } break; case HELM_OF_BRILLIANCE: if ((obj->owornmask & W_ARMH) && (obj == uarmh)) { ABON(A_INT) -= obj->spe; ABON(A_WIS) -= obj->spe; flags.botl = 1; } break; /* case RIN_PROTECTION: not needed */ } if (objects[obj->otyp].oc_magic || (obj->spe && (obj->oclass == ARMOR_CLASS || obj->oclass == WEAPON_CLASS || is_weptool(obj))) || obj->otyp == POT_ACID || obj->otyp == POT_SICKNESS) { if (obj->spe != ((obj->oclass == WAND_CLASS) ? -1 : 0) && obj->otyp != WAN_CANCELLATION && /* can't cancel cancellation */ obj->otyp != MAGIC_LAMP && obj->otyp != CANDELABRUM_OF_INVOCATION) { costly_cancel(obj); obj->spe = (obj->oclass == WAND_CLASS) ? -1 : 0; } switch (obj->oclass) { case SCROLL_CLASS: costly_cancel(obj); obj->otyp = SCR_BLANK_PAPER; obj->spe = 0; break; case SPBOOK_CLASS: if (obj->otyp != SPE_CANCELLATION && obj->otyp != SPE_BOOK_OF_THE_DEAD) { costly_cancel(obj); obj->otyp = SPE_BLANK_PAPER; } break; case POTION_CLASS: costly_cancel(obj); if (obj->otyp == POT_SICKNESS || obj->otyp == POT_SEE_INVISIBLE) { /* sickness is "biologically contaminated" fruit juice; cancel it * and it just becomes fruit juice... whereas see invisible * tastes like "enchanted" fruit juice, it similarly cancels. */ obj->otyp = POT_FRUIT_JUICE; } else { obj->otyp = POT_WATER; obj->odiluted = 0; /* same as any other water */ } break; } } if (holy) costly_cancel(obj); unbless(obj); uncurse(obj); #ifdef INVISIBLE_OBJECTS if (obj->oinvis) obj->oinvis = 0; #endif return; } /* Remove a positive enchantment or charge from obj, * possibly carried by you or a monster */ boolean drain_item(obj) register struct obj *obj; { boolean u_ring; /* Is this a charged/enchanted object? */ if (!obj || (!objects[obj->otyp].oc_charged && obj->oclass != WEAPON_CLASS && obj->oclass != ARMOR_CLASS && !is_weptool(obj)) || obj->spe <= 0) return (FALSE); if (obj_resists(obj, 10, 90)) return (FALSE); /* Charge for the cost of the object */ costly_cancel(obj); /* The term "cancel" is okay for now */ /* Drain the object and any implied effects */ obj->spe--; u_ring = (obj == uleft) || (obj == uright); switch(obj->otyp) { case RIN_GAIN_STRENGTH: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_STR)--; flags.botl = 1; } break; case RIN_GAIN_CONSTITUTION: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_CON)--; flags.botl = 1; } break; case RIN_ADORNMENT: if ((obj->owornmask & W_RING) && u_ring) { ABON(A_CHA)--; flags.botl = 1; } break; case RIN_INCREASE_ACCURACY: if ((obj->owornmask & W_RING) && u_ring) u.uhitinc--; break; case RIN_INCREASE_DAMAGE: if ((obj->owornmask & W_RING) && u_ring) u.udaminc--; break; case HELM_OF_BRILLIANCE: if ((obj->owornmask & W_ARMH) && (obj == uarmh)) { ABON(A_INT)--; ABON(A_WIS)--; flags.botl = 1; } break; case GAUNTLETS_OF_DEXTERITY: if ((obj->owornmask & W_ARMG) && (obj == uarmg)) { ABON(A_DEX)--; flags.botl = 1; } break; case RIN_PROTECTION: flags.botl = 1; break; } if (carried(obj)) update_inventory(); return (TRUE); } #endif /*OVLB*/ #ifdef OVL0 boolean obj_resists(obj, ochance, achance) struct obj *obj; int ochance, achance; /* percent chance for ordinary objects, artifacts */ { if (obj->otyp == AMULET_OF_YENDOR || obj->otyp == SPE_BOOK_OF_THE_DEAD || obj->otyp == CANDELABRUM_OF_INVOCATION || obj->otyp == BELL_OF_OPENING || (obj->otyp == CORPSE && is_rider(&mons[obj->corpsenm]))) { return TRUE; } else { int chance = rn2(100); return((boolean)(chance < (obj->oartifact ? achance : ochance))); } } boolean obj_shudders(obj) struct obj *obj; { int zap_odds; if (obj->oclass == WAND_CLASS) zap_odds = 3; /* half-life = 2 zaps */ else if (obj->cursed) zap_odds = 3; /* half-life = 2 zaps */ else if (obj->blessed) zap_odds = 12; /* half-life = 8 zaps */ else zap_odds = 8; /* half-life = 6 zaps */ /* adjust for "large" quantities of identical things */ if(obj->quan > 4L) zap_odds /= 2; return((boolean)(! rn2(zap_odds))); } #endif /*OVL0*/ #ifdef OVLB /* Use up at least minwt number of things made of material mat. * There's also a chance that other stuff will be used up. Finally, * there's a random factor here to keep from always using the stuff * at the top of the pile. */ STATIC_OVL void polyuse(objhdr, mat, minwt) struct obj *objhdr; int mat, minwt; { register struct obj *otmp, *otmp2; for(otmp = objhdr; minwt > 0 && otmp; otmp = otmp2) { otmp2 = otmp->nexthere; if (otmp == uball || otmp == uchain) continue; if (obj_resists(otmp, 0, 0)) continue; /* preserve unique objects */ #ifdef MAIL if (otmp->otyp == SCR_MAIL) continue; #endif if (((int) objects[otmp->otyp].oc_material == mat) == (rn2(minwt + 1) != 0)) { /* appropriately add damage to bill */ if (costly_spot(otmp->ox, otmp->oy)) { if (*u.ushops) addtobill(otmp, FALSE, FALSE, FALSE); else (void)stolen_value(otmp, otmp->ox, otmp->oy, FALSE, FALSE); } if (otmp->quan < LARGEST_INT) minwt -= (int)otmp->quan; else minwt = 0; delobj(otmp); } } } /* * Polymorph some of the stuff in this pile into a monster, preferably * a golem of the kind okind. */ STATIC_OVL void create_polymon(obj, okind) struct obj *obj; int okind; { struct permonst *mdat = (struct permonst *)0; struct monst *mtmp; const char *material; int pm_index; /* no golems if you zap only one object -- not enough stuff */ if(!obj || (!obj->nexthere && obj->quan == 1L)) return; /* some of these choices are arbitrary */ switch(okind) { case IRON: case METAL: case MITHRIL: pm_index = PM_IRON_GOLEM; material = "metal "; break; case COPPER: case SILVER: case PLATINUM: case GEMSTONE: case MINERAL: pm_index = rn2(2) ? PM_STONE_GOLEM : PM_CLAY_GOLEM; material = "lithic "; break; case 0: case FLESH: /* there is no flesh type, but all food is type 0, so we use it */ pm_index = PM_FLESH_GOLEM; material = "organic "; break; case WOOD: pm_index = PM_WOOD_GOLEM; material = "wood "; break; case LEATHER: pm_index = PM_LEATHER_GOLEM; material = "leather "; break; case CLOTH: pm_index = PM_ROPE_GOLEM; material = "cloth "; break; case BONE: pm_index = PM_SKELETON; /* nearest thing to "bone golem" */ material = "bony "; break; case GOLD: pm_index = PM_GOLD_GOLEM; material = "gold "; break; case GLASS: pm_index = PM_GLASS_GOLEM; material = "glassy "; break; case PAPER: pm_index = PM_PAPER_GOLEM; material = "paper "; break; default: /* if all else fails... */ pm_index = PM_STRAW_GOLEM; material = ""; break; } if (!(mvitals[pm_index].mvflags & G_GENOD)) mdat = &mons[pm_index]; mtmp = makemon(mdat, obj->ox, obj->oy, NO_MM_FLAGS); polyuse(obj, okind, (int)mons[pm_index].cwt); if(mtmp && cansee(mtmp->mx, mtmp->my)) { pline("Some %sobjects meld, and %s arises from the pile!", material, a_monnam(mtmp)); } } /* Assumes obj is on the floor. */ void do_osshock(obj) struct obj *obj; { long i; #ifdef MAIL if (obj->otyp == SCR_MAIL) return; #endif obj_zapped = TRUE; if(poly_zapped < 0) { /* some may metamorphosize */ for (i = obj->quan; i; i--) if (! rn2(Luck + 45)) { poly_zapped = objects[obj->otyp].oc_material; break; } } /* if quan > 1 then some will survive intact */ if (obj->quan > 1L) { if (obj->quan > LARGEST_INT) obj = splitobj(obj, (long)rnd(30000)); else obj = splitobj(obj, (long)rnd((int)obj->quan - 1)); } /* appropriately add damage to bill */ if (costly_spot(obj->ox, obj->oy)) { if (*u.ushops) addtobill(obj, FALSE, FALSE, FALSE); else (void)stolen_value(obj, obj->ox, obj->oy, FALSE, FALSE); } /* zap the object */ delobj(obj); } /* * Polymorph the object to the given object ID. If the ID is STRANGE_OBJECT * then pick random object from the source's class (this is the standard * "polymorph" case). If ID is set to a specific object, inhibit fusing * n objects into 1. This could have been added as a flag, but currently * it is tied to not being the standard polymorph case. The new polymorphed * object replaces obj in its link chains. Return value is a pointer to * the new object. * * This should be safe to call for an object anywhere. */ struct obj * poly_obj(obj, id) struct obj *obj; int id; { struct obj *otmp; xchar ox, oy; boolean can_merge = (id == STRANGE_OBJECT); int obj_location = obj->where; if (obj->otyp == BOULDER && In_sokoban(&u.uz)) change_luck(-1); /* Sokoban guilt */ if (id == STRANGE_OBJECT) { /* preserve symbol */ int try_limit = 3; /* Try up to 3 times to make the magic-or-not status of the new item be the same as it was for the old one. */ otmp = (struct obj *)0; do { if (otmp) delobj(otmp); otmp = mkobj(obj->oclass, FALSE); } while (--try_limit > 0 && objects[obj->otyp].oc_magic != objects[otmp->otyp].oc_magic); } else { /* literally replace obj with this new thing */ otmp = mksobj(id, FALSE, FALSE); /* Actually more things use corpsenm but they polymorph differently */ #define USES_CORPSENM(typ) ((typ)==CORPSE || (typ)==STATUE || (typ)==FIGURINE) if (USES_CORPSENM(obj->otyp) && USES_CORPSENM(id)) otmp->corpsenm = obj->corpsenm; #undef USES_CORPSENM } /* preserve quantity */ otmp->quan = obj->quan; /* preserve the shopkeepers (lack of) interest */ otmp->no_charge = obj->no_charge; /* preserve inventory letter if in inventory */ if (obj_location == OBJ_INVENT) otmp->invlet = obj->invlet; #ifdef MAIL /* You can't send yourself 100 mail messages and then * polymorph them into useful scrolls */ if (obj->otyp == SCR_MAIL) { otmp->otyp = SCR_MAIL; otmp->spe = 1; } #endif /* avoid abusing eggs laid by you */ if (obj->otyp == EGG && obj->spe) { int mnum, tryct = 100; /* first, turn into a generic egg */ if (otmp->otyp == EGG) kill_egg(otmp); else { otmp->otyp = EGG; otmp->owt = weight(otmp); } otmp->corpsenm = NON_PM; otmp->spe = 0; /* now change it into something layed by the hero */ while (tryct--) { mnum = can_be_hatched(random_monster()); if (mnum != NON_PM && !dead_species(mnum, TRUE)) { otmp->spe = 1; /* layed by hero */ otmp->corpsenm = mnum; attach_egg_hatch_timeout(otmp); break; } } } /* keep special fields (including charges on wands) */ if (index(charged_objs, otmp->oclass)) otmp->spe = obj->spe; otmp->recharged = obj->recharged; otmp->cursed = obj->cursed; otmp->blessed = obj->blessed; otmp->oeroded = obj->oeroded; otmp->oeroded2 = obj->oeroded2; if (!is_flammable(otmp) && !is_rustprone(otmp)) otmp->oeroded = 0; if (!is_corrodeable(otmp) && !is_rottable(otmp)) otmp->oeroded2 = 0; if (is_damageable(otmp)) otmp->oerodeproof = obj->oerodeproof; /* Keep chest/box traps and poisoned ammo if we may */ if (obj->otrapped && Is_box(otmp)) otmp->otrapped = TRUE; if (obj->opoisoned && is_poisonable(otmp)) otmp->opoisoned = TRUE; if (id == STRANGE_OBJECT && obj->otyp == CORPSE) { /* turn crocodile corpses into shoes */ if (obj->corpsenm == PM_CROCODILE) { otmp->otyp = LOW_BOOTS; otmp->oclass = ARMOR_CLASS; otmp->spe = 0; otmp->oeroded = 0; otmp->oerodeproof = TRUE; otmp->quan = 1L; otmp->cursed = FALSE; } } /* no box contents --KAA */ if (Has_contents(otmp)) delete_contents(otmp); /* 'n' merged objects may be fused into 1 object */ if (otmp->quan > 1L && (!objects[otmp->otyp].oc_merge || (can_merge && otmp->quan > (long)rn2(1000)))) otmp->quan = 1L; switch (otmp->oclass) { case TOOL_CLASS: if (otmp->otyp == MAGIC_LAMP) { otmp->otyp = OIL_LAMP; otmp->age = 1500L; /* "best" oil lamp possible */ } else if (otmp->otyp == MAGIC_MARKER) { otmp->recharged = 1; /* degraded quality */ } /* don't care about the recharge count of other tools */ break; case WAND_CLASS: while (otmp->otyp == WAN_WISHING || otmp->otyp == WAN_POLYMORPH) otmp->otyp = rnd_class(WAN_LIGHT, WAN_LIGHTNING); /* altering the object tends to degrade its quality (analogous to spellbook `read count' handling) */ if ((int)otmp->recharged < rn2(7)) /* recharge_limit */ otmp->recharged++; break; case POTION_CLASS: while (otmp->otyp == POT_POLYMORPH) otmp->otyp = rnd_class(POT_GAIN_ABILITY, POT_WATER); break; case SPBOOK_CLASS: while (otmp->otyp == SPE_POLYMORPH) otmp->otyp = rnd_class(SPE_DIG, SPE_BLANK_PAPER); /* reduce spellbook abuse */ otmp->spestudied = obj->spestudied + 1; break; case GEM_CLASS: if (otmp->quan > (long) rnd(4) && objects[obj->otyp].oc_material == MINERAL && objects[otmp->otyp].oc_material != MINERAL) { otmp->otyp = ROCK; /* transmutation backfired */ otmp->quan /= 2L; /* some material has been lost */ } break; } /* update the weight */ otmp->owt = weight(otmp); /* for now, take off worn items being polymorphed */ if (obj_location == OBJ_INVENT) { if (id == STRANGE_OBJECT) remove_worn_item(obj, TRUE); else { /* This is called only for stone to flesh. It's a lot simpler * than it otherwise might be. We don't need to check for * special effects when putting them on (no meat objects have * any) and only three worn masks are possible. */ otmp->owornmask = obj->owornmask; remove_worn_item(obj, TRUE); setworn(otmp, otmp->owornmask); if (otmp->owornmask & LEFT_RING) uleft = otmp; if (otmp->owornmask & RIGHT_RING) uright = otmp; if (otmp->owornmask & W_WEP) uwep = otmp; if (otmp->owornmask & W_SWAPWEP) uswapwep = otmp; if (otmp->owornmask & W_QUIVER) uquiver = otmp; goto no_unwear; } } /* preserve the mask in case being used by something else */ otmp->owornmask = obj->owornmask; no_unwear: if (obj_location == OBJ_FLOOR && obj->otyp == BOULDER && otmp->otyp != BOULDER) unblock_point(obj->ox, obj->oy); /* ** we are now done adjusting the object ** */ /* swap otmp for obj */ replace_object(obj, otmp); if (obj_location == OBJ_INVENT) { /* * We may need to do extra adjustments for the hero if we're * messing with the hero's inventory. The following calls are * equivalent to calling freeinv on obj and addinv on otmp, * while doing an in-place swap of the actual objects. */ freeinv_core(obj); addinv_core1(otmp); addinv_core2(otmp); } if ((!carried(otmp) || obj->unpaid) && get_obj_location(otmp, &ox, &oy, BURIED_TOO|CONTAINED_TOO) && costly_spot(ox, oy)) { register struct monst *shkp = shop_keeper(*in_rooms(ox, oy, SHOPBASE)); if ((!obj->no_charge || (Has_contents(obj) && (contained_cost(obj, shkp, 0L, FALSE, FALSE) != 0L))) && inhishop(shkp)) { if(shkp->mpeaceful) { if(*u.ushops && *in_rooms(u.ux, u.uy, 0) == *in_rooms(shkp->mx, shkp->my, 0) && !costly_spot(u.ux, u.uy)) make_angry_shk(shkp, ox, oy); else { pline("%s gets angry!", Monnam(shkp)); hot_pursuit(shkp); } } else Norep("%s is furious!", Monnam(shkp)); } } delobj(obj); return otmp; } /* * Object obj was hit by the effect of the wand/spell otmp. Return * non-zero if the wand/spell had any effect. */ int bhito(obj, otmp) struct obj *obj, *otmp; { int res = 1; /* affected object by default */ xchar refresh_x, refresh_y; if (obj->bypass) { /* The bypass bit is currently only used as follows: * * POLYMORPH - When a monster being polymorphed drops something * from its inventory as a result of the change. * If the items fall to the floor, they are not * subject to direct subsequent polymorphing * themselves on that same zap. This makes it * consistent with items that remain in the * monster's inventory. They are not polymorphed * either. * UNDEAD_TURNING - When an undead creature gets killed via * undead turning, prevent its corpse from being * immediately revived by the same effect. * * The bypass bit on all objects is reset each turn, whenever * flags.bypasses is set. * * We check the obj->bypass bit above AND flags.bypasses * as a safeguard against any stray occurrence left in an obj * struct someplace, although that should never happen. */ if (flags.bypasses) return 0; else { #ifdef DEBUG pline("%s for a moment.", Tobjnam(obj, "pulsate")); #endif obj->bypass = 0; } } /* * Some parts of this function expect the object to be on the floor * obj->{ox,oy} to be valid. The exception to this (so far) is * for the STONE_TO_FLESH spell. */ if (!(obj->where == OBJ_FLOOR || otmp->otyp == SPE_STONE_TO_FLESH)) impossible("bhito: obj is not floor or Stone To Flesh spell"); if (obj == uball) { res = 0; } else if (obj == uchain) { if (otmp->otyp == WAN_OPENING || otmp->otyp == SPE_KNOCK) { unpunish(); makeknown(otmp->otyp); } else res = 0; } else switch(otmp->otyp) { case WAN_POLYMORPH: case SPE_POLYMORPH: if (obj->otyp == WAN_POLYMORPH || obj->otyp == SPE_POLYMORPH || obj->otyp == POT_POLYMORPH || obj_resists(obj, 5, 95)) { res = 0; break; } /* KMH, conduct */ u.uconduct.polypiles++; /* any saved lock context will be dangerously obsolete */ if (Is_box(obj)) (void) boxlock(obj, otmp); if (obj_shudders(obj)) { if (cansee(obj->ox, obj->oy)) makeknown(otmp->otyp); do_osshock(obj); break; } obj = poly_obj(obj, STRANGE_OBJECT); newsym(obj->ox,obj->oy); break; case WAN_PROBING: res = !obj->dknown; /* target object has now been "seen (up close)" */ obj->dknown = 1; if (Is_container(obj) || obj->otyp == STATUE) { if (!obj->cobj) pline("%s empty.", Tobjnam(obj, "are")); else { struct obj *o; /* view contents (not recursively) */ for (o = obj->cobj; o; o = o->nobj) o->dknown = 1; /* "seen", even if blind */ (void) display_cinventory(obj); } res = 1; } if (res) makeknown(WAN_PROBING); break; case WAN_STRIKING: case SPE_FORCE_BOLT: if (obj->otyp == BOULDER) fracture_rock(obj); else if (obj->otyp == STATUE) (void) break_statue(obj); else { if (!flags.mon_moving) (void)hero_breaks(obj, obj->ox, obj->oy, FALSE); else (void)breaks(obj, obj->ox, obj->oy); res = 0; } /* BUG[?]: shouldn't this depend upon you seeing it happen? */ makeknown(otmp->otyp); break; case WAN_CANCELLATION: case SPE_CANCELLATION: cancel_item(obj); #ifdef TEXTCOLOR newsym(obj->ox,obj->oy); /* might change color */ #endif break; case SPE_DRAIN_LIFE: (void) drain_item(obj); break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: rloco(obj); break; case WAN_MAKE_INVISIBLE: #ifdef INVISIBLE_OBJECTS obj->oinvis = TRUE; newsym(obj->ox,obj->oy); /* make object disappear */ #endif break; case WAN_UNDEAD_TURNING: case SPE_TURN_UNDEAD: if (obj->otyp == EGG) revive_egg(obj); else res = !!revive(obj); break; case WAN_OPENING: case SPE_KNOCK: case WAN_LOCKING: case SPE_WIZARD_LOCK: if(Is_box(obj)) res = boxlock(obj, otmp); else res = 0; if (res /* && otmp->oclass == WAND_CLASS */) makeknown(otmp->otyp); break; case WAN_SLOW_MONSTER: /* no effect on objects */ case SPE_SLOW_MONSTER: case WAN_SPEED_MONSTER: case WAN_NOTHING: case SPE_HEALING: case SPE_EXTRA_HEALING: res = 0; break; case SPE_STONE_TO_FLESH: refresh_x = obj->ox; refresh_y = obj->oy; if (objects[obj->otyp].oc_material != MINERAL && objects[obj->otyp].oc_material != GEMSTONE) { res = 0; break; } /* add more if stone objects are added.. */ switch (objects[obj->otyp].oc_class) { case ROCK_CLASS: /* boulders and statues */ if (obj->otyp == BOULDER) { obj = poly_obj(obj, HUGE_CHUNK_OF_MEAT); goto smell; } else if (obj->otyp == STATUE) { xchar oox, ooy; (void) get_obj_location(obj, &oox, &ooy, 0); refresh_x = oox; refresh_y = ooy; if (vegetarian(&mons[obj->corpsenm])) { /* Don't animate monsters that aren't flesh */ obj = poly_obj(obj, MEATBALL); goto smell; } if (!animate_statue(obj, oox, ooy, ANIMATE_SPELL, (int *)0)) { struct obj *item; makecorpse: if (mons[obj->corpsenm].geno & (G_NOCORPSE|G_UNIQ)) { res = 0; break; } /* Unlikely to get here since genociding * monsters also sets the G_NOCORPSE flag. * Drop the contents, poly_obj looses them. */ while ((item = obj->cobj) != 0) { obj_extract_self(item); place_object(item, oox, ooy); } obj = poly_obj(obj, CORPSE); break; } } else { /* new rock class object... */ /* impossible? */ res = 0; } break; case TOOL_CLASS: /* figurine */ { struct monst *mon; xchar oox, ooy; if (obj->otyp != FIGURINE) { res = 0; break; } if (vegetarian(&mons[obj->corpsenm])) { /* Don't animate monsters that aren't flesh */ obj = poly_obj(obj, MEATBALL); goto smell; } (void) get_obj_location(obj, &oox, &ooy, 0); refresh_x = oox; refresh_y = ooy; mon = makemon(&mons[obj->corpsenm], oox, ooy, NO_MM_FLAGS); if (mon) { delobj(obj); if (cansee(mon->mx, mon->my)) pline_The("figurine animates!"); break; } goto makecorpse; } /* maybe add weird things to become? */ case RING_CLASS: /* some of the rings are stone */ obj = poly_obj(obj, MEAT_RING); goto smell; case WAND_CLASS: /* marble wand */ obj = poly_obj(obj, MEAT_STICK); goto smell; case GEM_CLASS: /* rocks & gems */ obj = poly_obj(obj, MEATBALL); smell: if (herbivorous(youmonst.data) && (!carnivorous(youmonst.data) || Role_if(PM_MONK) || !u.uconduct.unvegetarian)) Norep("You smell the odor of meat."); else Norep("You smell a delicious smell."); break; case WEAPON_CLASS: /* crysknife */ /* fall through */ default: res = 0; break; } newsym(refresh_x, refresh_y); break; default: impossible("What an interesting effect (%d)", otmp->otyp); break; } return res; } /* returns nonzero if something was hit */ int bhitpile(obj,fhito,tx,ty) struct obj *obj; int FDECL((*fhito), (OBJ_P,OBJ_P)); int tx, ty; { int hitanything = 0; register struct obj *otmp, *next_obj; if (obj->otyp == SPE_FORCE_BOLT || obj->otyp == WAN_STRIKING) { struct trap *t = t_at(tx, ty); /* We can't settle for the default calling sequence of bhito(otmp) -> break_statue(otmp) -> activate_statue_trap(ox,oy) because that last call might end up operating on our `next_obj' (below), rather than on the current object, if it happens to encounter a statue which mustn't become animated. */ if (t && t->ttyp == STATUE_TRAP && activate_statue_trap(t, tx, ty, TRUE) && obj->otyp == WAN_STRIKING) makeknown(obj->otyp); } poly_zapped = -1; for(otmp = level.objects[tx][ty]; otmp; otmp = next_obj) { /* Fix for polymorph bug, Tim Wright */ next_obj = otmp->nexthere; hitanything += (*fhito)(otmp, obj); } if(poly_zapped >= 0) create_polymon(level.objects[tx][ty], poly_zapped); return hitanything; } #endif /*OVLB*/ #ifdef OVL1 /* * zappable - returns 1 if zap is available, 0 otherwise. * it removes a charge from the wand if zappable. * added by GAN 11/03/86 */ int zappable(wand) register struct obj *wand; { if(wand->spe < 0 || (wand->spe == 0 && rn2(121))) return 0; if(wand->spe == 0) You("wrest one last charge from the worn-out wand."); wand->spe--; return 1; } /* * zapnodir - zaps a NODIR wand/spell. * added by GAN 11/03/86 */ void zapnodir(obj) register struct obj *obj; { boolean known = FALSE; switch(obj->otyp) { case WAN_LIGHT: case SPE_LIGHT: litroom(TRUE,obj); if (!Blind) known = TRUE; break; case WAN_SECRET_DOOR_DETECTION: case SPE_DETECT_UNSEEN: if(!findit()) return; if (!Blind) known = TRUE; break; case WAN_CREATE_MONSTER: known = create_critters(rn2(23) ? 1 : rn1(7,2), (struct permonst *)0); break; case WAN_WISHING: known = TRUE; if(Luck + rn2(5) < 0) { pline("Unfortunately, nothing happens."); break; } makewish(); break; case WAN_ENLIGHTENMENT: known = TRUE; You_feel("self-knowledgeable..."); display_nhwindow(WIN_MESSAGE, FALSE); enlightenment(FALSE); pline_The("feeling subsides."); exercise(A_WIS, TRUE); break; } if (known && !objects[obj->otyp].oc_name_known) { makeknown(obj->otyp); more_experienced(0,10); } } #endif /*OVL1*/ #ifdef OVL0 STATIC_OVL void backfire(otmp) struct obj *otmp; { otmp->in_use = TRUE; /* in case losehp() is fatal */ pline("%s suddenly explodes!", The(xname(otmp))); losehp(d(otmp->spe+2,6), "exploding wand", KILLED_BY_AN); useup(otmp); } static NEARDATA const char zap_syms[] = { WAND_CLASS, 0 }; int dozap() { register struct obj *obj; int damage; if(check_capacity((char *)0)) return(0); obj = getobj(zap_syms, "zap"); if(!obj) return(0); check_unpaid(obj); /* zappable addition done by GAN 11/03/86 */ if(!zappable(obj)) pline(nothing_happens); else if(obj->cursed && !rn2(100)) { backfire(obj); /* the wand blows up in your face! */ exercise(A_STR, FALSE); return(1); } else if(!(objects[obj->otyp].oc_dir == NODIR) && !getdir((char *)0)) { if (!Blind) pline("%s glows and fades.", The(xname(obj))); /* make him pay for knowing !NODIR */ } else if(!u.dx && !u.dy && !u.dz && !(objects[obj->otyp].oc_dir == NODIR)) { if ((damage = zapyourself(obj, TRUE)) != 0) { char buf[BUFSZ]; Sprintf(buf, "zapped %sself with a wand", uhim()); losehp(damage, buf, NO_KILLER_PREFIX); } } else { /* Are we having fun yet? * weffects -> buzz(obj->otyp) -> zhitm (temple priest) -> * attack -> hitum -> known_hitum -> ghod_hitsu -> * buzz(AD_ELEC) -> destroy_item(WAND_CLASS) -> * useup -> obfree -> dealloc_obj -> free(obj) */ current_wand = obj; weffects(obj); obj = current_wand; current_wand = 0; } if (obj && obj->spe < 0) { pline("%s to dust.", Tobjnam(obj, "turn")); useup(obj); } update_inventory(); /* maybe used a charge */ return(1); } int zapyourself(obj, ordinary) struct obj *obj; boolean ordinary; { int damage = 0; char buf[BUFSZ]; switch(obj->otyp) { case WAN_STRIKING: makeknown(WAN_STRIKING); case SPE_FORCE_BOLT: if(Antimagic) { shieldeff(u.ux, u.uy); pline("Boing!"); } else { if (ordinary) { You("bash yourself!"); damage = d(2,12); } else damage = d(1 + obj->spe,6); exercise(A_STR, FALSE); } break; case WAN_LIGHTNING: makeknown(WAN_LIGHTNING); if (!Shock_resistance) { You("shock yourself!"); damage = d(12,6); exercise(A_CON, FALSE); } else { shieldeff(u.ux, u.uy); You("zap yourself, but seem unharmed."); ugolemeffects(AD_ELEC, d(12,6)); } destroy_item(WAND_CLASS, AD_ELEC); destroy_item(RING_CLASS, AD_ELEC); if (!resists_blnd(&youmonst)) { You(are_blinded_by_the_flash); make_blinded((long)rnd(100),FALSE); if (!Blind) Your(vision_clears); } break; case SPE_FIREBALL: You("explode a fireball on top of yourself!"); explode(u.ux, u.uy, 11, d(6,6), WAND_CLASS, EXPL_FIERY); break; case WAN_FIRE: makeknown(WAN_FIRE); case FIRE_HORN: if (Fire_resistance) { shieldeff(u.ux, u.uy); You_feel("rather warm."); ugolemeffects(AD_FIRE, d(12,6)); } else { pline("You've set yourself afire!"); damage = d(12,6); } burn_away_slime(); (void) burnarmor(&youmonst); destroy_item(SCROLL_CLASS, AD_FIRE); destroy_item(POTION_CLASS, AD_FIRE); destroy_item(SPBOOK_CLASS, AD_FIRE); break; case WAN_COLD: makeknown(WAN_COLD); case SPE_CONE_OF_COLD: case FROST_HORN: if (Cold_resistance) { shieldeff(u.ux, u.uy); You_feel("a little chill."); ugolemeffects(AD_COLD, d(12,6)); } else { You("imitate a popsicle!"); damage = d(12,6); } destroy_item(POTION_CLASS, AD_COLD); break; case WAN_MAGIC_MISSILE: makeknown(WAN_MAGIC_MISSILE); case SPE_MAGIC_MISSILE: if(Antimagic) { shieldeff(u.ux, u.uy); pline_The("missiles bounce!"); } else { damage = d(4,6); pline("Idiot! You've shot yourself!"); } break; case WAN_POLYMORPH: if (!Unchanging) makeknown(WAN_POLYMORPH); case SPE_POLYMORPH: if (!Unchanging) polyself(FALSE); break; case WAN_CANCELLATION: case SPE_CANCELLATION: (void) cancel_monst(&youmonst, obj, TRUE, FALSE, TRUE); break; case SPE_DRAIN_LIFE: if (!Drain_resistance) { losexp("life drainage"); makeknown(obj->otyp); } damage = 0; /* No additional damage */ break; case WAN_MAKE_INVISIBLE: { /* have to test before changing HInvis but must change * HInvis before doing newsym(). */ int msg = !Invis && !Blind && !BInvis; if (BInvis && uarmc->otyp == MUMMY_WRAPPING) { /* A mummy wrapping absorbs it and protects you */ You_feel("rather itchy under your %s.", xname(uarmc)); break; } if (ordinary || !rn2(10)) { /* permanent */ HInvis |= FROMOUTSIDE; } else { /* temporary */ incr_itimeout(&HInvis, d(obj->spe, 250)); } if (msg) { makeknown(WAN_MAKE_INVISIBLE); newsym(u.ux, u.uy); self_invis_message(); } break; } case WAN_SPEED_MONSTER: if (!(HFast & INTRINSIC)) { if (!Fast) You("speed up."); else Your("quickness feels more natural."); makeknown(WAN_SPEED_MONSTER); exercise(A_DEX, TRUE); } HFast |= FROMOUTSIDE; break; case WAN_SLEEP: makeknown(WAN_SLEEP); case SPE_SLEEP: if(Sleep_resistance) { shieldeff(u.ux, u.uy); You("don't feel sleepy!"); } else { pline_The("sleep ray hits you!"); fall_asleep(-rnd(50), TRUE); } break; case WAN_SLOW_MONSTER: case SPE_SLOW_MONSTER: if(HFast & (TIMEOUT | INTRINSIC)) { u_slow_down(); makeknown(obj->otyp); } break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: tele(); break; case WAN_DEATH: case SPE_FINGER_OF_DEATH: if (nonliving(youmonst.data) || is_demon(youmonst.data)) { pline((obj->otyp == WAN_DEATH) ? "The wand shoots an apparently harmless beam at you." : "You seem no deader than before."); break; } Sprintf(buf, "shot %sself with a death ray", uhim()); killer = buf; killer_format = NO_KILLER_PREFIX; You("irradiate yourself with pure energy!"); You("die."); makeknown(obj->otyp); /* They might survive with an amulet of life saving */ done(DIED); break; case WAN_UNDEAD_TURNING: makeknown(WAN_UNDEAD_TURNING); case SPE_TURN_UNDEAD: (void) unturn_dead(&youmonst); if (is_undead(youmonst.data)) { You_feel("frightened and %sstunned.", Stunned ? "even more " : ""); make_stunned(HStun + rnd(30), FALSE); } else You("shudder in dread."); break; case SPE_HEALING: case SPE_EXTRA_HEALING: healup(d(6, obj->otyp == SPE_EXTRA_HEALING ? 8 : 4), 0, FALSE, (obj->otyp == SPE_EXTRA_HEALING)); You_feel("%sbetter.", obj->otyp == SPE_EXTRA_HEALING ? "much " : ""); break; case WAN_LIGHT: /* (broken wand) */ /* assert( !ordinary ); */ damage = d(obj->spe, 25); #ifdef TOURIST case EXPENSIVE_CAMERA: #endif damage += rnd(25); if (!resists_blnd(&youmonst)) { You(are_blinded_by_the_flash); make_blinded((long)damage, FALSE); makeknown(obj->otyp); if (!Blind) Your(vision_clears); } damage = 0; /* reset */ break; case WAN_OPENING: if (Punished) makeknown(WAN_OPENING); case SPE_KNOCK: if (Punished) Your("chain quivers for a moment."); break; case WAN_DIGGING: case SPE_DIG: case SPE_DETECT_UNSEEN: case WAN_NOTHING: case WAN_LOCKING: case SPE_WIZARD_LOCK: break; case WAN_PROBING: for (obj = invent; obj; obj = obj->nobj) obj->dknown = 1; /* note: `obj' reused; doesn't point at wand anymore */ makeknown(WAN_PROBING); ustatusline(); break; case SPE_STONE_TO_FLESH: { struct obj *otemp, *onext; boolean didmerge; if (u.umonnum == PM_STONE_GOLEM) (void) polymon(PM_FLESH_GOLEM); if (Stoned) fix_petrification(); /* saved! */ /* but at a cost.. */ for (otemp = invent; otemp; otemp = onext) { onext = otemp->nobj; (void) bhito(otemp, obj); } /* * It is possible that we can now merge some inventory. * Do a higly paranoid merge. Restart from the beginning * until no merges. */ do { didmerge = FALSE; for (otemp = invent; !didmerge && otemp; otemp = otemp->nobj) for (onext = otemp->nobj; onext; onext = onext->nobj) if (merged(&otemp, &onext)) { didmerge = TRUE; break; } } while (didmerge); } break; default: impossible("object %d used?",obj->otyp); break; } return(damage); } #ifdef STEED /* you've zapped a wand downwards while riding * Return TRUE if the steed was hit by the wand. * Return FALSE if the steed was not hit by the wand. */ STATIC_OVL boolean zap_steed(obj) struct obj *obj; /* wand or spell */ { int steedhit = FALSE; switch (obj->otyp) { /* * Wands that are allowed to hit the steed * Carefully test the results of any that are * moved here from the bottom section. */ case WAN_PROBING: probe_monster(u.usteed); makeknown(WAN_PROBING); steedhit = TRUE; break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: /* you go together */ tele(); if(Teleport_control || !couldsee(u.ux0, u.uy0) || (distu(u.ux0, u.uy0) >= 16)) makeknown(obj->otyp); steedhit = TRUE; break; /* Default processing via bhitm() for these */ case SPE_CURE_SICKNESS: case WAN_MAKE_INVISIBLE: case WAN_CANCELLATION: case SPE_CANCELLATION: case WAN_POLYMORPH: case SPE_POLYMORPH: case WAN_STRIKING: case SPE_FORCE_BOLT: case WAN_SLOW_MONSTER: case SPE_SLOW_MONSTER: case WAN_SPEED_MONSTER: case SPE_HEALING: case SPE_EXTRA_HEALING: case SPE_DRAIN_LIFE: case WAN_OPENING: case SPE_KNOCK: (void) bhitm(u.usteed, obj); steedhit = TRUE; break; default: steedhit = FALSE; break; } return steedhit; } #endif #endif /*OVL0*/ #ifdef OVL3 /* * cancel a monster (possibly the hero). inventory is cancelled only * if the monster is zapping itself directly, since otherwise the * effect is too strong. currently non-hero monsters do not zap * themselves with cancellation. */ boolean cancel_monst(mdef, obj, youattack, allow_cancel_kill, self_cancel) register struct monst *mdef; register struct obj *obj; boolean youattack, allow_cancel_kill, self_cancel; { boolean youdefend = (mdef == &youmonst); static const char writing_vanishes[] = "Some writing vanishes from %s head!"; static const char your[] = "your"; /* should be extern */ if (youdefend ? (!youattack && Antimagic) : resist(mdef, obj->oclass, 0, NOTELL)) return FALSE; /* resisted cancellation */ if (self_cancel) { /* 1st cancel inventory */ struct obj *otmp; for (otmp = (youdefend ? invent : mdef->minvent); otmp; otmp = otmp->nobj) cancel_item(otmp); if (youdefend) { flags.botl = 1; /* potential AC change */ find_ac(); } } /* now handle special cases */ if (youdefend) { if (Upolyd) { if ((u.umonnum == PM_CLAY_GOLEM) && !Blind) pline(writing_vanishes, your); if (Unchanging) Your("amulet grows hot for a moment, then cools."); else rehumanize(); } } else { mdef->mcan = TRUE; if (is_were(mdef->data) && mdef->data->mlet != S_HUMAN) were_change(mdef); if (mdef->data == &mons[PM_CLAY_GOLEM]) { if (canseemon(mdef)) pline(writing_vanishes, s_suffix(mon_nam(mdef))); if (allow_cancel_kill) { if (youattack) killed(mdef); else monkilled(mdef, "", AD_SPEL); } } } return TRUE; } /* you've zapped an immediate type wand up or down */ STATIC_OVL boolean zap_updown(obj) struct obj *obj; /* wand or spell */ { boolean striking = FALSE, disclose = FALSE; int x, y, xx, yy, ptmp; struct obj *otmp; struct engr *e; struct trap *ttmp; char buf[BUFSZ]; /* some wands have special effects other than normal bhitpile */ /* drawbridge might change */ x = xx = u.ux; /* is zap location */ y = yy = u.uy; /* is drawbridge (portcullis) position */ ttmp = t_at(x, y); /* trap if there is one */ switch (obj->otyp) { case WAN_PROBING: ptmp = 0; if (u.dz < 0) { You("probe towards the %s.", ceiling(x,y)); } else { ptmp += bhitpile(obj, bhito, x, y); You("probe beneath the %s.", surface(x,y)); ptmp += display_binventory(x, y, TRUE); } if (!ptmp) Your("probe reveals nothing."); return TRUE; /* we've done our own bhitpile */ case WAN_OPENING: case SPE_KNOCK: /* up or down, but at closed portcullis only */ if (is_db_wall(x,y) && find_drawbridge(&xx, &yy)) { open_drawbridge(xx, yy); disclose = TRUE; } else if (u.dz > 0 && (x == xdnstair && y == ydnstair) && /* can't use the stairs down to quest level 2 until leader "unlocks" them; give feedback if you try */ on_level(&u.uz, &qstart_level) && !ok_to_quest()) { pline_The("stairs seem to ripple momentarily."); disclose = TRUE; } break; case WAN_STRIKING: case SPE_FORCE_BOLT: striking = TRUE; /*FALLTHRU*/ case WAN_LOCKING: case SPE_WIZARD_LOCK: /* down at open bridge or up or down at open portcullis */ if ((levl[x][y].typ == DRAWBRIDGE_DOWN) ? (u.dz > 0) : (is_drawbridge_wall(x,y) && !is_db_wall(x,y)) && find_drawbridge(&xx, &yy)) { if (!striking) close_drawbridge(xx, yy); else destroy_drawbridge(xx, yy); disclose = TRUE; } else if (striking && u.dz < 0 && rn2(3) && !Is_airlevel(&u.uz) && !Is_waterlevel(&u.uz) && !Underwater && !Is_qstart(&u.uz)) { /* similar to zap_dig() */ pline("A rock is dislodged from the %s and falls on your %s.", ceiling(x, y), body_part(HEAD)); losehp(rnd((uarmh && is_metallic(uarmh)) ? 2 : 6), "falling rock", KILLED_BY_AN); if ((otmp = mksobj_at(ROCK, x, y, FALSE, FALSE)) != 0) { (void)xname(otmp); /* set dknown, maybe bknown */ stackobj(otmp); } newsym(x, y); } else if (!striking && ttmp && ttmp->ttyp == TRAPDOOR && u.dz > 0) { if (!Blind) { if (ttmp->tseen) { pline("A trap door beneath you closes up then vanishes."); disclose = TRUE; } else { You("see a swirl of %s beneath you.", is_ice(x,y) ? "frost" : "dust"); } } else { You_hear("a twang followed by a thud."); } deltrap(ttmp); ttmp = (struct trap *)0; newsym(x, y); } break; case SPE_STONE_TO_FLESH: if (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || Underwater || (Is_qstart(&u.uz) && u.dz < 0)) { pline(nothing_happens); } else if (u.dz < 0) { /* we should do more... */ pline("Blood drips on your %s.", body_part(FACE)); } else if (u.dz > 0 && !OBJ_AT(u.ux, u.uy)) { /* Print this message only if there wasn't an engraving affected here. If water or ice, act like waterlevel case. */ e = engr_at(u.ux, u.uy); if (!(e && e->engr_type == ENGRAVE)) { if (is_pool(u.ux, u.uy) || is_ice(u.ux, u.uy)) pline(nothing_happens); else pline("Blood %ss %s your %s.", is_lava(u.ux, u.uy) ? "boil" : "pool", Levitation ? "beneath" : "at", makeplural(body_part(FOOT))); } } break; default: break; } if (u.dz > 0) { /* zapping downward */ (void) bhitpile(obj, bhito, x, y); /* subset of engraving effects; none sets `disclose' */ if ((e = engr_at(x, y)) != 0 && e->engr_type != HEADSTONE) { switch (obj->otyp) { case WAN_POLYMORPH: case SPE_POLYMORPH: del_engr(e); make_engr_at(x, y, random_engraving(buf), moves, (xchar)0); break; case WAN_CANCELLATION: case SPE_CANCELLATION: case WAN_MAKE_INVISIBLE: del_engr(e); break; case WAN_TELEPORTATION: case SPE_TELEPORT_AWAY: rloc_engr(e); break; case SPE_STONE_TO_FLESH: if (e->engr_type == ENGRAVE) { /* only affects things in stone */ pline_The(Hallucination ? "floor runs like butter!" : "edges on the floor get smoother."); wipe_engr_at(x, y, d(2,4)); } break; case WAN_STRIKING: case SPE_FORCE_BOLT: wipe_engr_at(x, y, d(2,4)); break; default: break; } } } return disclose; } #endif /*OVL3*/ #ifdef OVLB /* called for various wand and spell effects - M. Stephenson */ void weffects(obj) register struct obj *obj; { int otyp = obj->otyp; boolean disclose = FALSE, was_unkn = !objects[otyp].oc_name_known; exercise(A_WIS, TRUE); #ifdef STEED if (u.usteed && (objects[otyp].oc_dir != NODIR) && !u.dx && !u.dy && (u.dz > 0) && zap_steed(obj)) { disclose = TRUE; } else #endif if (objects[otyp].oc_dir == IMMEDIATE) { obj_zapped = FALSE; if (u.uswallow) { (void) bhitm(u.ustuck, obj); /* [how about `bhitpile(u.ustuck->minvent)' effect?] */ } else if (u.dz) { disclose = zap_updown(obj); } else { (void) bhit(u.dx,u.dy, rn1(8,6),ZAPPED_WAND, bhitm,bhito, obj); } /* give a clue if obj_zapped */ if (obj_zapped) You_feel("shuddering vibrations."); } else if (objects[otyp].oc_dir == NODIR) { zapnodir(obj); } else { /* neither immediate nor directionless */ if (otyp == WAN_DIGGING || otyp == SPE_DIG) zap_dig(); else if (otyp >= SPE_MAGIC_MISSILE && otyp <= SPE_FINGER_OF_DEATH) buzz(otyp - SPE_MAGIC_MISSILE + 10, u.ulevel / 2 + 1, u.ux, u.uy, u.dx, u.dy); else if (otyp >= WAN_MAGIC_MISSILE && otyp <= WAN_LIGHTNING) buzz(otyp - WAN_MAGIC_MISSILE, (otyp == WAN_MAGIC_MISSILE) ? 2 : 6, u.ux, u.uy, u.dx, u.dy); else impossible("weffects: unexpected spell or wand"); disclose = TRUE; } if (disclose && was_unkn) { makeknown(otyp); more_experienced(0,10); } return; } #endif /*OVLB*/ #ifdef OVL0 /* * Generate the to damage bonus for a spell. Based on the hero's intelligence */ int spell_damage_bonus() { int tmp, intell = ACURR(A_INT); /* Punish low intellegence before low level else low intellegence gets punished only when high level */ if (intell < 10) tmp = -3; else if (u.ulevel < 5) tmp = 0; else if (intell < 14) tmp = 0; else if (intell <= 18) tmp = 1; else /* helm of brilliance */ tmp = 2; return tmp; } /* * Generate the to hit bonus for a spell. Based on the hero's skill in * spell class and dexterity. */ STATIC_OVL int spell_hit_bonus(skill) int skill; { int hit_bon = 0; int dex = ACURR(A_DEX); switch (P_SKILL(spell_skilltype(skill))) { case P_ISRESTRICTED: case P_UNSKILLED: hit_bon = -4; break; case P_BASIC: hit_bon = 0; break; case P_SKILLED: hit_bon = 2; break; case P_EXPERT: hit_bon = 3; break; } if (dex < 4) hit_bon -= 3; else if (dex < 6) hit_bon -= 2; else if (dex < 8) hit_bon -= 1; else if (dex < 14) hit_bon -= 0; /* Will change when print stuff below removed */ else hit_bon += dex - 14; /* Even increment for dextrous heroes (see weapon.c abon) */ return hit_bon; } const char * exclam(force) register int force; { /* force == 0 occurs e.g. with sleep ray */ /* note that large force is usual with wands so that !! would require information about hand/weapon/wand */ return (const char *)((force < 0) ? "?" : (force <= 4) ? "." : "!"); } void hit(str,mtmp,force) register const char *str; register struct monst *mtmp; register const char *force; /* usually either "." or "!" */ { if((!cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp) && !(u.uswallow && mtmp == u.ustuck)) || !flags.verbose) pline("%s %s it.", The(str), vtense(str, "hit")); else pline("%s %s %s%s", The(str), vtense(str, "hit"), mon_nam(mtmp), force); } void miss(str,mtmp) register const char *str; register struct monst *mtmp; { pline("%s %s %s.", The(str), vtense(str, "miss"), ((cansee(bhitpos.x,bhitpos.y) || canspotmon(mtmp)) && flags.verbose) ? mon_nam(mtmp) : "it"); } #endif /*OVL0*/ #ifdef OVL1 /* * Called for the following distance effects: * when a weapon is thrown (weapon == THROWN_WEAPON) * when an object is kicked (KICKED_WEAPON) * when an IMMEDIATE wand is zapped (ZAPPED_WAND) * when a light beam is flashed (FLASHED_LIGHT) * when a mirror is applied (INVIS_BEAM) * A thrown/kicked object falls down at the end of its range or when a monster * is hit. The variable 'bhitpos' is set to the final position of the weapon * thrown/zapped. The ray of a wand may affect (by calling a provided * function) several objects and monsters on its path. The return value * is the monster hit (weapon != ZAPPED_WAND), or a null monster pointer. * * Check !u.uswallow before calling bhit(). * This function reveals the absence of a remembered invisible monster in * necessary cases (throwing or kicking weapons). The presence of a real * one is revealed for a weapon, but if not a weapon is left up to fhitm(). */ struct monst * bhit(ddx,ddy,range,weapon,fhitm,fhito,obj) register int ddx,ddy,range; /* direction and range */ int weapon; /* see values in hack.h */ int FDECL((*fhitm), (MONST_P, OBJ_P)), /* fns called when mon/obj hit */ FDECL((*fhito), (OBJ_P, OBJ_P)); struct obj *obj; /* object tossed/used */ { struct monst *mtmp; uchar typ; boolean shopdoor = FALSE, point_blank = TRUE; if (weapon == KICKED_WEAPON) { /* object starts one square in front of player */ bhitpos.x = u.ux + ddx; bhitpos.y = u.uy + ddy; range--; } else { bhitpos.x = u.ux; bhitpos.y = u.uy; } if (weapon == FLASHED_LIGHT) { tmp_at(DISP_BEAM, cmap_to_glyph(S_flashbeam)); } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_FLASH, obj_to_glyph(obj)); while(range-- > 0) { int x,y; bhitpos.x += ddx; bhitpos.y += ddy; x = bhitpos.x; y = bhitpos.y; if(!isok(x, y)) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if(is_pick(obj) && inside_shop(x, y) && (mtmp = shkcatch(obj, x, y))) { tmp_at(DISP_END, 0); return(mtmp); } typ = levl[bhitpos.x][bhitpos.y].typ; /* iron bars will block anything big enough */ if ((weapon == THROWN_WEAPON || weapon == KICKED_WEAPON) && typ == IRONBARS && hits_bars(&obj, x - ddx, y - ddy, point_blank ? 0 : !rn2(5), 1)) { /* caveat: obj might now be null... */ bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if (weapon == ZAPPED_WAND && find_drawbridge(&x,&y)) switch (obj->otyp) { case WAN_OPENING: case SPE_KNOCK: if (is_db_wall(bhitpos.x, bhitpos.y)) { if (cansee(x,y) || cansee(bhitpos.x,bhitpos.y)) makeknown(obj->otyp); open_drawbridge(x,y); } break; case WAN_LOCKING: case SPE_WIZARD_LOCK: if ((cansee(x,y) || cansee(bhitpos.x, bhitpos.y)) && levl[x][y].typ == DRAWBRIDGE_DOWN) makeknown(obj->otyp); close_drawbridge(x,y); break; case WAN_STRIKING: case SPE_FORCE_BOLT: if (typ != DRAWBRIDGE_UP) destroy_drawbridge(x,y); makeknown(obj->otyp); break; } if ((mtmp = m_at(bhitpos.x, bhitpos.y)) != 0) { notonhead = (bhitpos.x != mtmp->mx || bhitpos.y != mtmp->my); if (weapon != FLASHED_LIGHT) { if(weapon != ZAPPED_WAND) { if(weapon != INVIS_BEAM) tmp_at(DISP_END, 0); if (cansee(bhitpos.x,bhitpos.y) && !canspotmon(mtmp)) { if (weapon != INVIS_BEAM) { map_invisible(bhitpos.x, bhitpos.y); return(mtmp); } } else return(mtmp); } if (weapon != INVIS_BEAM) { (*fhitm)(mtmp, obj); range -= 3; } } else { /* FLASHED_LIGHT hitting invisible monster should pass through instead of stop so we call flash_hits_mon() directly rather than returning mtmp back to caller. That allows the flash to keep on going. Note that we use mtmp->minvis not canspotmon() because it makes no difference whether the hero can see the monster or not.*/ if (mtmp->minvis) { obj->ox = u.ux, obj->oy = u.uy; (void) flash_hits_mon(mtmp, obj); } else { tmp_at(DISP_END, 0); return(mtmp); /* caller will call flash_hits_mon */ } } } else { if (weapon == ZAPPED_WAND && obj->otyp == WAN_PROBING && glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph)) { unmap_object(bhitpos.x, bhitpos.y); newsym(x, y); } } if(fhito) { if(bhitpile(obj,fhito,bhitpos.x,bhitpos.y)) range--; } else { if(weapon == KICKED_WEAPON && ((obj->oclass == COIN_CLASS && OBJ_AT(bhitpos.x, bhitpos.y)) || ship_object(obj, bhitpos.x, bhitpos.y, costly_spot(bhitpos.x, bhitpos.y)))) { tmp_at(DISP_END, 0); return (struct monst *)0; } } if(weapon == ZAPPED_WAND && (IS_DOOR(typ) || typ == SDOOR)) { switch (obj->otyp) { case WAN_OPENING: case WAN_LOCKING: case WAN_STRIKING: case SPE_KNOCK: case SPE_WIZARD_LOCK: case SPE_FORCE_BOLT: if (doorlock(obj, bhitpos.x, bhitpos.y)) { if (cansee(bhitpos.x, bhitpos.y) || (obj->otyp == WAN_STRIKING)) makeknown(obj->otyp); if (levl[bhitpos.x][bhitpos.y].doormask == D_BROKEN && *in_rooms(bhitpos.x, bhitpos.y, SHOPBASE)) { shopdoor = TRUE; add_damage(bhitpos.x, bhitpos.y, 400L); } } break; } } if(!ZAP_POS(typ) || closed_door(bhitpos.x, bhitpos.y)) { bhitpos.x -= ddx; bhitpos.y -= ddy; break; } if(weapon != ZAPPED_WAND && weapon != INVIS_BEAM) { /* 'I' present but no monster: erase */ /* do this before the tmp_at() */ if (glyph_is_invisible(levl[bhitpos.x][bhitpos.y].glyph) && cansee(x, y)) { unmap_object(bhitpos.x, bhitpos.y); newsym(x, y); } tmp_at(bhitpos.x, bhitpos.y); delay_output(); /* kicked objects fall in pools */ if((weapon == KICKED_WEAPON) && (is_pool(bhitpos.x, bhitpos.y) || is_lava(bhitpos.x, bhitpos.y))) break; #ifdef SINKS if(IS_SINK(typ) && weapon != FLASHED_LIGHT) break; /* physical objects fall onto sink */ #endif } /* limit range of ball so hero won't make an invalid move */ if (weapon == THROWN_WEAPON && range > 0 && obj->otyp == HEAVY_IRON_BALL) { struct obj *bobj; struct trap *t; if ((bobj = sobj_at(BOULDER, x, y)) != 0) { if (cansee(x,y)) pline("%s hits %s.", The(distant_name(obj, xname)), an(xname(bobj))); range = 0; } else if (obj == uball) { if (!test_move(x - ddx, y - ddy, ddx, ddy, TEST_MOVE)) { /* nb: it didn't hit anything directly */ if (cansee(x,y)) pline("%s jerks to an abrupt halt.", The(distant_name(obj, xname))); /* lame */ range = 0; } else if (In_sokoban(&u.uz) && (t = t_at(x, y)) != 0 && (t->ttyp == PIT || t->ttyp == SPIKED_PIT || t->ttyp == HOLE || t->ttyp == TRAPDOOR)) { /* hero falls into the trap, so ball stops */ range = 0; } } } /* thrown/kicked missile has moved away from its starting spot */ point_blank = FALSE; /* affects passing through iron bars */ } if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) tmp_at(DISP_END, 0); if(shopdoor) pay_for_damage("destroy", FALSE); return (struct monst *)0; } struct monst * boomhit(dx, dy) int dx, dy; { register int i, ct; int boom = S_boomleft; /* showsym[] index */ struct monst *mtmp; bhitpos.x = u.ux; bhitpos.y = u.uy; for (i = 0; i < 8; i++) if (xdir[i] == dx && ydir[i] == dy) break; tmp_at(DISP_FLASH, cmap_to_glyph(boom)); for (ct = 0; ct < 10; ct++) { if(i == 8) i = 0; boom = (boom == S_boomleft) ? S_boomright : S_boomleft; tmp_at(DISP_CHANGE, cmap_to_glyph(boom));/* change glyph */ dx = xdir[i]; dy = ydir[i]; bhitpos.x += dx; bhitpos.y += dy; if(MON_AT(bhitpos.x, bhitpos.y)) { mtmp = m_at(bhitpos.x,bhitpos.y); m_respond(mtmp); tmp_at(DISP_END, 0); return(mtmp); } if(!ZAP_POS(levl[bhitpos.x][bhitpos.y].typ) || closed_door(bhitpos.x, bhitpos.y)) { bhitpos.x -= dx; bhitpos.y -= dy; break; } if(bhitpos.x == u.ux && bhitpos.y == u.uy) { /* ct == 9 */ if(Fumbling || rn2(20) >= ACURR(A_DEX)) { /* we hit ourselves */ (void) thitu(10, rnd(10), (struct obj *)0, "boomerang"); break; } else { /* we catch it */ tmp_at(DISP_END, 0); You("skillfully catch the boomerang."); return(&youmonst); } } tmp_at(bhitpos.x, bhitpos.y); delay_output(); if(ct % 5 != 0) i++; #ifdef SINKS if(IS_SINK(levl[bhitpos.x][bhitpos.y].typ)) break; /* boomerang falls on sink */ #endif } tmp_at(DISP_END, 0); /* do not leave last symbol */ return (struct monst *)0; } STATIC_OVL int zhitm(mon, type, nd, ootmp) /* returns damage to mon */ register struct monst *mon; register int type, nd; struct obj **ootmp; /* to return worn armor for caller to disintegrate */ { register int tmp = 0; register int abstype = abs(type) % 10; boolean sho_shieldeff = FALSE; boolean spellcaster = is_hero_spell(type); /* maybe get a bonus! */ *ootmp = (struct obj *)0; switch(abstype) { case ZT_MAGIC_MISSILE: if (resists_magm(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd,6); if (spellcaster) tmp += spell_damage_bonus(); #ifdef WIZ_PATCH_DEBUG if (spellcaster) pline("Damage = %d + %d", tmp-spell_damage_bonus(), spell_damage_bonus()); #endif break; case ZT_FIRE: if (resists_fire(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd,6); if (resists_cold(mon)) tmp += 7; if (spellcaster) tmp += spell_damage_bonus(); #ifdef WIZ_PATCH_DEBUG if (spellcaster) pline("Damage = %d + %d",tmp-spell_damage_bonus(), spell_damage_bonus()); #endif if (burnarmor(mon)) { if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_FIRE); if (!rn2(3)) (void)destroy_mitem(mon, SCROLL_CLASS, AD_FIRE); if (!rn2(5)) (void)destroy_mitem(mon, SPBOOK_CLASS, AD_FIRE); } break; case ZT_COLD: if (resists_cold(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd,6); if (resists_fire(mon)) tmp += d(nd, 3); if (spellcaster) tmp += spell_damage_bonus(); #ifdef WIZ_PATCH_DEBUG if (spellcaster) pline("Damage = %d + %d", tmp-spell_damage_bonus(), spell_damage_bonus()); #endif if (!rn2(3)) (void)destroy_mitem(mon, POTION_CLASS, AD_COLD); break; case ZT_SLEEP: tmp = 0; (void)sleep_monst(mon, d(nd, 25), type == ZT_WAND(ZT_SLEEP) ? WAND_CLASS : '\0'); break; case ZT_DEATH: /* death/disintegration */ if(abs(type) != ZT_BREATH(ZT_DEATH)) { /* death */ if(mon->data == &mons[PM_DEATH]) { mon->mhpmax += mon->mhpmax/2; if (mon->mhpmax >= MAGIC_COOKIE) mon->mhpmax = MAGIC_COOKIE - 1; mon->mhp = mon->mhpmax; tmp = 0; break; } if (nonliving(mon->data) || is_demon(mon->data) || resists_magm(mon)) { /* similar to player */ sho_shieldeff = TRUE; break; } type = -1; /* so they don't get saving throws */ } else { struct obj *otmp2; if (resists_disint(mon)) { sho_shieldeff = TRUE; } else if (mon->misc_worn_check & W_ARMS) { /* destroy shield; victim survives */ *ootmp = which_armor(mon, W_ARMS); } else if (mon->misc_worn_check & W_ARM) { /* destroy body armor, also cloak if present */ *ootmp = which_armor(mon, W_ARM); if ((otmp2 = which_armor(mon, W_ARMC)) != 0) m_useup(mon, otmp2); } else { /* no body armor, victim dies; destroy cloak and shirt now in case target gets life-saved */ tmp = MAGIC_COOKIE; if ((otmp2 = which_armor(mon, W_ARMC)) != 0) m_useup(mon, otmp2); #ifdef TOURIST if ((otmp2 = which_armor(mon, W_ARMU)) != 0) m_useup(mon, otmp2); #endif } type = -1; /* no saving throw wanted */ break; /* not ordinary damage */ } tmp = mon->mhp+1; break; case ZT_LIGHTNING: if (resists_elec(mon)) { sho_shieldeff = TRUE; tmp = 0; /* can still blind the monster */ } else tmp = d(nd,6); if (spellcaster) tmp += spell_damage_bonus(); #ifdef WIZ_PATCH_DEBUG if (spellcaster) pline("Damage = %d + %d", tmp-spell_damage_bonus(), spell_damage_bonus()); #endif if (!resists_blnd(mon) && !(type > 0 && u.uswallow && mon == u.ustuck)) { register unsigned rnd_tmp = rnd(50); mon->mcansee = 0; if((mon->mblinded + rnd_tmp) > 127) mon->mblinded = 127; else mon->mblinded += rnd_tmp; } if (!rn2(3)) (void)destroy_mitem(mon, WAND_CLASS, AD_ELEC); /* not actually possible yet */ if (!rn2(3)) (void)destroy_mitem(mon, RING_CLASS, AD_ELEC); break; case ZT_POISON_GAS: if (resists_poison(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd,6); break; case ZT_ACID: if (resists_acid(mon)) { sho_shieldeff = TRUE; break; } tmp = d(nd,6); if (!rn2(6)) erode_obj(MON_WEP(mon), TRUE, TRUE); if (!rn2(6)) erode_armor(mon, TRUE); break; } if (sho_shieldeff) shieldeff(mon->mx, mon->my); if (is_hero_spell(type) && (Role_if(PM_KNIGHT) && u.uhave.questart)) tmp *= 2; if (tmp > 0 && type >= 0 && resist(mon, type < ZT_SPELL(0) ? WAND_CLASS : '\0', 0, NOTELL)) tmp /= 2; if (tmp < 0) tmp = 0; /* don't allow negative damage */ #ifdef WIZ_PATCH_DEBUG pline("zapped monster hp = %d (= %d - %d)", mon->mhp-tmp,mon->mhp,tmp); #endif mon->mhp -= tmp; return(tmp); } STATIC_OVL void zhitu(type, nd, fltxt, sx, sy) int type, nd; const char *fltxt; xchar sx, sy; { int dam = 0; switch (abs(type) % 10) { case ZT_MAGIC_MISSILE: if (Antimagic) { shieldeff(sx, sy); pline_The("missiles bounce off!"); } else { dam = d(nd,6); exercise(A_STR, FALSE); } break; case ZT_FIRE: if (Fire_resistance) { shieldeff(sx, sy); You("don't feel hot!"); ugolemeffects(AD_FIRE, d(nd, 6)); } else { dam = d(nd, 6); } burn_away_slime(); if (burnarmor(&youmonst)) { /* "body hit" */ if (!rn2(3)) destroy_item(POTION_CLASS, AD_FIRE); if (!rn2(3)) destroy_item(SCROLL_CLASS, AD_FIRE); if (!rn2(5)) destroy_item(SPBOOK_CLASS, AD_FIRE); } break; case ZT_COLD: if (Cold_resistance) { shieldeff(sx, sy); You("don't feel cold."); ugolemeffects(AD_COLD, d(nd, 6)); } else { dam = d(nd, 6); } if (!rn2(3)) destroy_item(POTION_CLASS, AD_COLD); break; case ZT_SLEEP: if (Sleep_resistance) { shieldeff(u.ux, u.uy); You("don't feel sleepy."); } else { fall_asleep(-d(nd,25), TRUE); /* sleep ray */ } break; case ZT_DEATH: if (abs(type) == ZT_BREATH(ZT_DEATH)) { if (Disint_resistance) { You("are not disintegrated."); break; } else if (uarms) { /* destroy shield; other possessions are safe */ (void) destroy_arm(uarms); break; } else if (uarm) { /* destroy suit; if present, cloak goes too */ if (uarmc) (void) destroy_arm(uarmc); (void) destroy_arm(uarm); break; } /* no shield or suit, you're dead; wipe out cloak and/or shirt in case of life-saving or bones */ if (uarmc) (void) destroy_arm(uarmc); #ifdef TOURIST if (uarmu) (void) destroy_arm(uarmu); #endif } else if (nonliving(youmonst.data) || is_demon(youmonst.data)) { shieldeff(sx, sy); You("seem unaffected."); break; } else if (Antimagic) { shieldeff(sx, sy); You("aren't affected."); break; } killer_format = KILLED_BY_AN; killer = fltxt; /* when killed by disintegration breath, don't leave corpse */ u.ugrave_arise = (type == -ZT_BREATH(ZT_DEATH)) ? -3 : NON_PM; done(DIED); return; /* lifesaved */ case ZT_LIGHTNING: if (Shock_resistance) { shieldeff(sx, sy); You("aren't affected."); ugolemeffects(AD_ELEC, d(nd, 6)); } else { dam = d(nd, 6); exercise(A_CON, FALSE); } if (!rn2(3)) destroy_item(WAND_CLASS, AD_ELEC); if (!rn2(3)) destroy_item(RING_CLASS, AD_ELEC); break; case ZT_POISON_GAS: poisoned("blast", A_DEX, "poisoned blast", 15); break; case ZT_ACID: if (Acid_resistance) { dam = 0; } else { pline_The("acid burns!"); dam = d(nd,6); exercise(A_STR, FALSE); } /* using two weapons at once makes both of them more vulnerable */ if (!rn2(u.twoweap ? 3 : 6)) erode_obj(uwep, TRUE, TRUE); if (u.twoweap && !rn2(3)) erode_obj(uswapwep, TRUE, TRUE); if (!rn2(6)) erode_armor(&youmonst, TRUE); break; } if (Half_spell_damage && dam && type < 0 && (type > -20 || type < -29)) /* !Breath */ dam = (dam + 1) / 2; losehp(dam, fltxt, KILLED_BY_AN); return; } #endif /*OVL1*/ #ifdef OVLB /* * burn scrolls and spellbooks on floor at position x,y * return the number of scrolls and spellbooks burned */ int burn_floor_paper(x, y, give_feedback, u_caused) int x, y; boolean give_feedback; /* caller needs to decide about visibility checks */ boolean u_caused; { struct obj *obj, *obj2; long i, scrquan, delquan; char buf1[BUFSZ], buf2[BUFSZ]; int cnt = 0; for (obj = level.objects[x][y]; obj; obj = obj2) { obj2 = obj->nexthere; if (obj->oclass == SCROLL_CLASS || obj->oclass == SPBOOK_CLASS) { if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL || obj_resists(obj, 2, 100)) continue; scrquan = obj->quan; /* number present */ delquan = 0; /* number to destroy */ for (i = scrquan; i > 0; i--) if (!rn2(3)) delquan++; if (delquan) { /* save name before potential delobj() */ if (give_feedback) { obj->quan = 1; Strcpy(buf1, (x == u.ux && y == u.uy) ? xname(obj) : distant_name(obj, xname)); obj->quan = 2; Strcpy(buf2, (x == u.ux && y == u.uy) ? xname(obj) : distant_name(obj, xname)); obj->quan = scrquan; } /* useupf(), which charges, only if hero caused damage */ if (u_caused) useupf(obj, delquan); else if (delquan < scrquan) obj->quan -= delquan; else delobj(obj); cnt += delquan; if (give_feedback) { if (delquan > 1) pline("%ld %s burn.", delquan, buf2); else pline("%s burns.", An(buf1)); } } } } return cnt; } /* will zap/spell/breath attack score a hit against armor class `ac'? */ STATIC_OVL int zap_hit(ac, type) int ac; int type; /* either hero cast spell type or 0 */ { int chance = rn2(20); int spell_bonus = type ? spell_hit_bonus(type) : 0; /* small chance for naked target to avoid being hit */ if (!chance) return rnd(10) < ac+spell_bonus; /* very high armor protection does not achieve invulnerability */ ac = AC_VALUE(ac); return (3 - chance) < ac+spell_bonus; } /* type == 0 to 9 : you shooting a wand */ /* type == 10 to 19 : you casting a spell */ /* type == 20 to 29 : you breathing as a monster */ /* type == -10 to -19 : monster casting spell */ /* type == -20 to -29 : monster breathing at you */ /* type == -30 to -39 : monster shooting a wand */ /* called with dx = dy = 0 with vertical bolts */ void buzz(type,nd,sx,sy,dx,dy) register int type, nd; register xchar sx,sy; register int dx,dy; { int range, abstype = abs(type) % 10; struct rm *lev; register xchar lsx, lsy; struct monst *mon; coord save_bhitpos; boolean shopdamage = FALSE; register const char *fltxt; struct obj *otmp; int spell_type; /* if its a Hero Spell then get its SPE_TYPE */ spell_type = is_hero_spell(type) ? SPE_MAGIC_MISSILE + abstype : 0; fltxt = flash_types[(type <= -30) ? abstype : abs(type)]; if(u.uswallow) { register int tmp; if(type < 0) return; tmp = zhitm(u.ustuck, type, nd, &otmp); if(!u.ustuck) u.uswallow = 0; else pline("%s rips into %s%s", The(fltxt), mon_nam(u.ustuck), exclam(tmp)); /* Using disintegration from the inside only makes a hole... */ if (tmp == MAGIC_COOKIE) u.ustuck->mhp = 0; if (u.ustuck->mhp < 1) killed(u.ustuck); return; } if(type < 0) newsym(u.ux,u.uy); range = rn1(7,7); if(dx == 0 && dy == 0) range = 1; save_bhitpos = bhitpos; tmp_at(DISP_BEAM, zapdir_to_glyph(dx, dy, abstype)); while(range-- > 0) { lsx = sx; sx += dx; lsy = sy; sy += dy; if(isok(sx,sy) && (lev = &levl[sx][sy])->typ) { mon = m_at(sx, sy); if(cansee(sx,sy)) { /* reveal/unreveal invisible monsters before tmp_at() */ if (mon && !canspotmon(mon)) map_invisible(sx, sy); else if (!mon && glyph_is_invisible(levl[sx][sy].glyph)) { unmap_object(sx, sy); newsym(sx, sy); } if(ZAP_POS(lev->typ) || cansee(lsx,lsy)) tmp_at(sx,sy); delay_output(); /* wait a little */ } } else goto make_bounce; /* hit() and miss() need bhitpos to match the target */ bhitpos.x = sx, bhitpos.y = sy; /* Fireballs only damage when they explode */ if (type != ZT_SPELL(ZT_FIRE)) range += zap_over_floor(sx, sy, type, &shopdamage); if (mon) { if (type == ZT_SPELL(ZT_FIRE)) break; if (type >= 0) mon->mstrategy &= ~STRAT_WAITMASK; #ifdef STEED buzzmonst: #endif if (zap_hit(find_mac(mon), spell_type)) { if (mon_reflects(mon, (char *)0)) { if(cansee(mon->mx,mon->my)) { hit(fltxt, mon, exclam(0)); shieldeff(mon->mx, mon->my); (void) mon_reflects(mon, "But it reflects from %s %s!"); } dx = -dx; dy = -dy; } else { boolean mon_could_move = mon->mcanmove; int tmp = zhitm(mon, type, nd, &otmp); if (is_rider(mon->data) && abs(type) == ZT_BREATH(ZT_DEATH)) { if (canseemon(mon)) { hit(fltxt, mon, "."); pline("%s disintegrates.", Monnam(mon)); pline("%s body reintegrates before your %s!", s_suffix(Monnam(mon)), (eyecount(youmonst.data) == 1) ? body_part(EYE) : makeplural(body_part(EYE))); pline("%s resurrects!", Monnam(mon)); } mon->mhp = mon->mhpmax; break; /* Out of while loop */ } if (mon->data == &mons[PM_DEATH] && abstype == ZT_DEATH) { if (canseemon(mon)) { hit(fltxt, mon, "."); pline("%s absorbs the deadly %s!", Monnam(mon), type == ZT_BREATH(ZT_DEATH) ? "blast" : "ray"); pline("It seems even stronger than before."); } break; /* Out of while loop */ } if (tmp == MAGIC_COOKIE) { /* disintegration */ struct obj *otmp2, *m_amulet = mlifesaver(mon); if (canseemon(mon)) { if (!m_amulet) pline("%s is disintegrated!", Monnam(mon)); else hit(fltxt, mon, "!"); } #ifndef GOLDOBJ mon->mgold = 0L; #endif /* note: worn amulet of life saving must be preserved in order to operate */ #define oresist_disintegration(obj) \ (objects[obj->otyp].oc_oprop == DISINT_RES || \ obj_resists(obj, 5, 50) || is_quest_artifact(obj) || \ obj == m_amulet) for (otmp = mon->minvent; otmp; otmp = otmp2) { otmp2 = otmp->nobj; if (!oresist_disintegration(otmp)) { obj_extract_self(otmp); obfree(otmp, (struct obj *)0); } } if (type < 0) monkilled(mon, (char *)0, -AD_RBRE); else xkilled(mon, 2); } else if(mon->mhp < 1) { if(type < 0) monkilled(mon, fltxt, AD_RBRE); else killed(mon); } else { if (!otmp) { /* normal non-fatal hit */ hit(fltxt, mon, exclam(tmp)); } else { /* some armor was destroyed; no damage done */ if (canseemon(mon)) pline("%s %s is disintegrated!", s_suffix(Monnam(mon)), distant_name(otmp, xname)); m_useup(mon, otmp); } if (mon_could_move && !mon->mcanmove) /* ZT_SLEEP */ slept_monst(mon); } } range -= 2; } else { miss(fltxt,mon); } } else if (sx == u.ux && sy == u.uy && range >= 0) { nomul(0); #ifdef STEED if (u.usteed && !rn2(3) && !mon_reflects(u.usteed, (char *)0)) { mon = u.usteed; goto buzzmonst; } else #endif if (zap_hit((int) u.uac, 0)) { range -= 2; pline("%s hits you!", The(fltxt)); if (Reflecting) { if (!Blind) { (void) ureflects("But %s reflects from your %s!", "it"); } else pline("For some reason you are not affected."); dx = -dx; dy = -dy; shieldeff(sx, sy); } else { zhitu(type, nd, fltxt, sx, sy); } } else { pline("%s whizzes by you!", The(fltxt)); } if (abstype == ZT_LIGHTNING && !resists_blnd(&youmonst)) { You(are_blinded_by_the_flash); make_blinded((long)d(nd,50),FALSE); if (!Blind) Your(vision_clears); } stop_occupation(); nomul(0); } if(!ZAP_POS(lev->typ) || (closed_door(sx, sy) && (range >= 0))) { int bounce; uchar rmn; make_bounce: if (type == ZT_SPELL(ZT_FIRE)) { sx = lsx; sy = lsy; break; /* fireballs explode before the wall */ } bounce = 0; range--; if(range && isok(lsx, lsy) && cansee(lsx,lsy)) pline("%s bounces!", The(fltxt)); if(!dx || !dy || !rn2(20)) { dx = -dx; dy = -dy; } else { if(isok(sx,lsy) && ZAP_POS(rmn = levl[sx][lsy].typ) && !closed_door(sx,lsy) && (IS_ROOM(rmn) || (isok(sx+dx,lsy) && ZAP_POS(levl[sx+dx][lsy].typ)))) bounce = 1; if(isok(lsx,sy) && ZAP_POS(rmn = levl[lsx][sy].typ) && !closed_door(lsx,sy) && (IS_ROOM(rmn) || (isok(lsx,sy+dy) && ZAP_POS(levl[lsx][sy+dy].typ)))) if(!bounce || rn2(2)) bounce = 2; switch(bounce) { case 0: dx = -dx; /* fall into... */ case 1: dy = -dy; break; case 2: dx = -dx; break; } tmp_at(DISP_CHANGE, zapdir_to_glyph(dx,dy,abstype)); } } } tmp_at(DISP_END,0); if (type == ZT_SPELL(ZT_FIRE)) explode(sx, sy, type, d(12,6), 0, EXPL_FIERY); if (shopdamage) pay_for_damage(abstype == ZT_FIRE ? "burn away" : abstype == ZT_COLD ? "shatter" : abstype == ZT_DEATH ? "disintegrate" : "destroy", FALSE); bhitpos = save_bhitpos; } #endif /*OVLB*/ #ifdef OVL0 void melt_ice(x, y) xchar x, y; { struct rm *lev = &levl[x][y]; struct obj *otmp; if (lev->typ == DRAWBRIDGE_UP) lev->drawbridgemask &= ~DB_ICE; /* revert to DB_MOAT */ else { /* lev->typ == ICE */ #ifdef STUPID if (lev->icedpool == ICED_POOL) lev->typ = POOL; else lev->typ = MOAT; #else lev->typ = (lev->icedpool == ICED_POOL ? POOL : MOAT); #endif lev->icedpool = 0; } obj_ice_effects(x, y, FALSE); unearth_objs(x, y); if (Underwater) vision_recalc(1); newsym(x,y); if (cansee(x,y)) Norep("The ice crackles and melts."); if ((otmp = sobj_at(BOULDER, x, y)) != 0) { if (cansee(x,y)) pline("%s settles...", An(xname(otmp))); do { obj_extract_self(otmp); /* boulder isn't being pushed */ if (!boulder_hits_pool(otmp, x, y, FALSE)) impossible("melt_ice: no pool?"); /* try again if there's another boulder and pool didn't fill */ } while (is_pool(x,y) && (otmp = sobj_at(BOULDER, x, y)) != 0); newsym(x,y); } if (x == u.ux && y == u.uy) spoteffects(TRUE); /* possibly drown, notice objects */ } /* Burn floor scrolls, evaporate pools, etc... in a single square. Used * both for normal bolts of fire, cold, etc... and for fireballs. * Sets shopdamage to TRUE if a shop door is destroyed, and returns the * amount by which range is reduced (the latter is just ignored by fireballs) */ int zap_over_floor(x, y, type, shopdamage) xchar x, y; int type; boolean *shopdamage; { struct monst *mon; int abstype = abs(type) % 10; struct rm *lev = &levl[x][y]; int rangemod = 0; if(abstype == ZT_FIRE) { struct trap *t = t_at(x, y); if (t && t->ttyp == WEB) { /* a burning web is too flimsy to notice if you can't see it */ if (cansee(x,y)) Norep("A web bursts into flames!"); (void) delfloortrap(t); if (cansee(x,y)) newsym(x,y); } if(is_ice(x, y)) { melt_ice(x, y); } else if(is_pool(x,y)) { const char *msgtxt = "You hear hissing gas."; if(lev->typ != POOL) { /* MOAT or DRAWBRIDGE_UP */ if (cansee(x,y)) msgtxt = "Some water evaporates."; } else { register struct trap *ttmp; rangemod -= 3; lev->typ = ROOM; ttmp = maketrap(x, y, PIT); if (ttmp) ttmp->tseen = 1; if (cansee(x,y)) msgtxt = "The water evaporates."; } Norep(msgtxt); if (lev->typ == ROOM) newsym(x,y); } else if(IS_FOUNTAIN(lev->typ)) { if (cansee(x,y)) pline("Steam billows from the fountain."); rangemod -= 1; dryup(x, y, type > 0); } } else if(abstype == ZT_COLD && (is_pool(x,y) || is_lava(x,y))) { boolean lava = is_lava(x,y); boolean moat = (!lava && (lev->typ != POOL) && (lev->typ != WATER) && !Is_medusa_level(&u.uz) && !Is_waterlevel(&u.uz)); if (lev->typ == WATER) { /* For now, don't let WATER freeze. */ if (cansee(x,y)) pline_The("water freezes for a moment."); else You_hear("a soft crackling."); rangemod -= 1000; /* stop */ } else { rangemod -= 3; if (lev->typ == DRAWBRIDGE_UP) { lev->drawbridgemask &= ~DB_UNDER; /* clear lava */ lev->drawbridgemask |= (lava ? DB_FLOOR : DB_ICE); } else { if (!lava) lev->icedpool = (lev->typ == POOL ? ICED_POOL : ICED_MOAT); lev->typ = (lava ? ROOM : ICE); } bury_objs(x,y); if(cansee(x,y)) { if(moat) Norep("The moat is bridged with ice!"); else if(lava) Norep("The lava cools and solidifies."); else Norep("The water freezes."); newsym(x,y); } else if(flags.soundok && !lava) You_hear("a crackling sound."); if (x == u.ux && y == u.uy) { if (u.uinwater) { /* not just `if (Underwater)' */ /* leave the no longer existent water */ u.uinwater = 0; u.uundetected = 0; docrt(); vision_full_recalc = 1; } else if (u.utrap && u.utraptype == TT_LAVA) { if (Passes_walls) { You("pass through the now-solid rock."); } else { u.utrap = rn1(50,20); u.utraptype = TT_INFLOOR; You("are firmly stuck in the cooling rock."); } } } else if ((mon = m_at(x,y)) != 0) { /* probably ought to do some hefty damage to any non-ice creature caught in freezing water; at a minimum, eels are forced out of hiding */ if (is_swimmer(mon->data) && mon->mundetected) { mon->mundetected = 0; newsym(x,y); } } } obj_ice_effects(x,y,TRUE); } if(closed_door(x, y)) { int new_doormask = -1; const char *see_txt = 0, *sense_txt = 0, *hear_txt = 0; rangemod = -1000; switch(abstype) { case ZT_FIRE: new_doormask = D_NODOOR; see_txt = "The door is consumed in flames!"; sense_txt = "smell smoke."; break; case ZT_COLD: new_doormask = D_NODOOR; see_txt = "The door freezes and shatters!"; sense_txt = "feel cold."; break; case ZT_DEATH: /* death spells/wands don't disintegrate */ if(abs(type) != ZT_BREATH(ZT_DEATH)) goto def_case; new_doormask = D_NODOOR; see_txt = "The door disintegrates!"; hear_txt = "crashing wood."; break; case ZT_LIGHTNING: new_doormask = D_BROKEN; see_txt = "The door splinters!"; hear_txt = "crackling."; break; default: def_case: if(cansee(x,y)) { pline_The("door absorbs %s %s!", (type < 0) ? "the" : "your", abs(type) < ZT_SPELL(0) ? "bolt" : abs(type) < ZT_BREATH(0) ? "spell" : "blast"); } else You_feel("vibrations."); break; } if (new_doormask >= 0) { /* door gets broken */ if (*in_rooms(x, y, SHOPBASE)) { if (type >= 0) { add_damage(x, y, 400L); *shopdamage = TRUE; } else /* caused by monster */ add_damage(x, y, 0L); } lev->doormask = new_doormask; unblock_point(x, y); /* vision */ if (cansee(x, y)) { pline(see_txt); newsym(x, y); } else if (sense_txt) { You(sense_txt); } else if (hear_txt) { if (flags.soundok) You_hear(hear_txt); } if (picking_at(x, y)) { stop_occupation(); reset_pick(); } } } if(OBJ_AT(x, y) && abstype == ZT_FIRE) if (burn_floor_paper(x, y, FALSE, type > 0) && couldsee(x, y)) { newsym(x,y); You("%s of smoke.", !Blind ? "see a puff" : "smell a whiff"); } if ((mon = m_at(x,y)) != 0) { /* Cannot use wakeup() which also angers the monster */ mon->msleeping = 0; if(mon->m_ap_type) seemimic(mon); if(type >= 0) { setmangry(mon); if(mon->ispriest && *in_rooms(mon->mx, mon->my, TEMPLE)) ghod_hitsu(mon); if(mon->isshk && !*u.ushops) hot_pursuit(mon); } } return rangemod; } #endif /*OVL0*/ #ifdef OVL3 void fracture_rock(obj) /* fractured by pick-axe or wand of striking */ register struct obj *obj; /* no texts here! */ { /* A little Sokoban guilt... */ if (obj->otyp == BOULDER && In_sokoban(&u.uz) && !flags.mon_moving) change_luck(-1); obj->otyp = ROCK; obj->quan = (long) rn1(60, 7); obj->owt = weight(obj); obj->oclass = GEM_CLASS; obj->known = FALSE; obj->onamelth = 0; /* no names */ obj->oxlth = 0; /* no extra data */ obj->oattached = OATTACHED_NOTHING; if (obj->where == OBJ_FLOOR) { obj_extract_self(obj); /* move rocks back on top */ place_object(obj, obj->ox, obj->oy); if(!does_block(obj->ox,obj->oy,&levl[obj->ox][obj->oy])) unblock_point(obj->ox,obj->oy); if(cansee(obj->ox,obj->oy)) newsym(obj->ox,obj->oy); } } /* handle statue hit by striking/force bolt/pick-axe */ boolean break_statue(obj) register struct obj *obj; { /* [obj is assumed to be on floor, so no get_obj_location() needed] */ struct trap *trap = t_at(obj->ox, obj->oy); struct obj *item; if (trap && trap->ttyp == STATUE_TRAP && activate_statue_trap(trap, obj->ox, obj->oy, TRUE)) return FALSE; /* drop any objects contained inside the statue */ while ((item = obj->cobj) != 0) { obj_extract_self(item); place_object(item, obj->ox, obj->oy); } if (Role_if(PM_ARCHEOLOGIST) && !flags.mon_moving && (obj->spe & STATUE_HISTORIC)) { You_feel("guilty about damaging such a historic statue."); adjalign(-1); } obj->spe = 0; fracture_rock(obj); return TRUE; } const char * const destroy_strings[] = { /* also used in trap.c */ "freezes and shatters", "freeze and shatter", "shattered potion", "boils and explodes", "boil and explode", "boiling potion", "catches fire and burns", "catch fire and burn", "burning scroll", "catches fire and burns", "catch fire and burn", "burning book", "turns to dust and vanishes", "turn to dust and vanish", "", "breaks apart and explodes", "break apart and explode", "exploding wand" }; void destroy_item(osym, dmgtyp) register int osym, dmgtyp; { register struct obj *obj, *obj2; register int dmg, xresist, skip; register long i, cnt, quan; register int dindx; const char *mult; for(obj = invent; obj; obj = obj2) { obj2 = obj->nobj; if(obj->oclass != osym) continue; /* test only objs of type osym */ if(obj->oartifact) continue; /* don't destroy artifacts */ if(obj->in_use && obj->quan == 1) continue; /* not available */ xresist = skip = 0; #ifdef GCC_WARN dmg = dindx = 0; quan = 0L; #endif switch(dmgtyp) { case AD_COLD: if(osym == POTION_CLASS && obj->otyp != POT_OIL) { quan = obj->quan; dindx = 0; dmg = rnd(4); } else skip++; break; case AD_FIRE: xresist = (Fire_resistance && obj->oclass != POTION_CLASS); if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) skip++; if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { skip++; if (!Blind) pline("%s glows a strange %s, but remains intact.", The(xname(obj)), hcolor("dark red")); } quan = obj->quan; switch(osym) { case POTION_CLASS: dindx = 1; dmg = rnd(6); break; case SCROLL_CLASS: dindx = 2; dmg = 1; break; case SPBOOK_CLASS: dindx = 3; dmg = 1; break; default: skip++; break; } break; case AD_ELEC: xresist = (Shock_resistance && obj->oclass != RING_CLASS); quan = obj->quan; switch(osym) { case RING_CLASS: if(obj->otyp == RIN_SHOCK_RESISTANCE) { skip++; break; } dindx = 4; dmg = 0; break; case WAND_CLASS: if(obj->otyp == WAN_LIGHTNING) { skip++; break; } #if 0 if (obj == current_wand) { skip++; break; } #endif dindx = 5; dmg = rnd(10); break; default: skip++; break; } break; default: skip++; break; } if(!skip) { if (obj->in_use) --quan; /* one will be used up elsewhere */ for(i = cnt = 0L; i < quan; i++) if(!rn2(3)) cnt++; if(!cnt) continue; if(cnt == quan) mult = "Your"; else mult = (cnt == 1L) ? "One of your" : "Some of your"; pline("%s %s %s!", mult, xname(obj), (cnt > 1L) ? destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]); if(osym == POTION_CLASS && dmgtyp != AD_COLD) { if (!breathless(youmonst.data) || haseyes(youmonst.data)) potionbreathe(obj); } if (obj->owornmask) { if (obj->owornmask & W_RING) /* ring being worn */ Ring_gone(obj); else setnotworn(obj); } if (obj == current_wand) current_wand = 0; /* destroyed */ for (i = 0; i < cnt; i++) useup(obj); if(dmg) { if(xresist) You("aren't hurt!"); else { const char *how = destroy_strings[dindx * 3 + 2]; boolean one = (cnt == 1L); losehp(dmg, one ? how : (const char *)makeplural(how), one ? KILLED_BY_AN : KILLED_BY); exercise(A_STR, FALSE); } } } } return; } int destroy_mitem(mtmp, osym, dmgtyp) struct monst *mtmp; int osym, dmgtyp; { struct obj *obj, *obj2; int skip, tmp = 0; long i, cnt, quan; int dindx; boolean vis; if (mtmp == &youmonst) { /* this simplifies artifact_hit() */ destroy_item(osym, dmgtyp); return 0; /* arbitrary; value doesn't matter to artifact_hit() */ } vis = canseemon(mtmp); for(obj = mtmp->minvent; obj; obj = obj2) { obj2 = obj->nobj; if(obj->oclass != osym) continue; /* test only objs of type osym */ skip = 0; quan = 0L; dindx = 0; switch(dmgtyp) { case AD_COLD: if(osym == POTION_CLASS && obj->otyp != POT_OIL) { quan = obj->quan; dindx = 0; tmp++; } else skip++; break; case AD_FIRE: if (obj->otyp == SCR_FIRE || obj->otyp == SPE_FIREBALL) skip++; if (obj->otyp == SPE_BOOK_OF_THE_DEAD) { skip++; if (vis) pline("%s glows a strange %s, but remains intact.", The(distant_name(obj, xname)), hcolor("dark red")); } quan = obj->quan; switch(osym) { case POTION_CLASS: dindx = 1; tmp++; break; case SCROLL_CLASS: dindx = 2; tmp++; break; case SPBOOK_CLASS: dindx = 3; tmp++; break; default: skip++; break; } break; case AD_ELEC: quan = obj->quan; switch(osym) { case RING_CLASS: if(obj->otyp == RIN_SHOCK_RESISTANCE) { skip++; break; } dindx = 4; break; case WAND_CLASS: if(obj->otyp == WAN_LIGHTNING) { skip++; break; } dindx = 5; tmp++; break; default: skip++; break; } break; default: skip++; break; } if(!skip) { for(i = cnt = 0L; i < quan; i++) if(!rn2(3)) cnt++; if(!cnt) continue; if (vis) pline("%s %s %s!", s_suffix(Monnam(mtmp)), xname(obj), (cnt > 1L) ? destroy_strings[dindx*3 + 1] : destroy_strings[dindx*3]); for(i = 0; i < cnt; i++) m_useup(mtmp, obj); } } return(tmp); } #endif /*OVL3*/ #ifdef OVL2 int resist(mtmp, oclass, damage, tell) struct monst *mtmp; char oclass; int damage, tell; { int resisted; int alev, dlev; /* attack level */ switch (oclass) { case WAND_CLASS: alev = 12; break; case TOOL_CLASS: alev = 10; break; /* instrument */ case WEAPON_CLASS: alev = 10; break; /* artifact */ case SCROLL_CLASS: alev = 9; break; case POTION_CLASS: alev = 6; break; case RING_CLASS: alev = 5; break; default: alev = u.ulevel; break; /* spell */ } /* defense level */ dlev = (int)mtmp->m_lev; if (dlev > 50) dlev = 50; else if (dlev < 1) dlev = is_mplayer(mtmp->data) ? u.ulevel : 1; resisted = rn2(100 + alev - dlev) < mtmp->data->mr; if (resisted) { if (tell) { shieldeff(mtmp->mx, mtmp->my); pline("%s resists!", Monnam(mtmp)); } damage = (damage + 1) / 2; } if (damage) { mtmp->mhp -= damage; if (mtmp->mhp < 1) { if(m_using) monkilled(mtmp, "", AD_RBRE); else killed(mtmp); } } return(resisted); } void makewish() { char buf[BUFSZ]; struct obj *otmp, nothing; int tries = 0; nothing = zeroobj; /* lint suppression; only its address matters */ if (flags.verbose) You("may wish for an object."); retry: getlin("For what do you wish?", buf); if(buf[0] == '\033') buf[0] = 0; /* * Note: if they wished for and got a non-object successfully, * otmp == &zeroobj. That includes gold, or an artifact that * has been denied. Wishing for "nothing" requires a separate * value to remain distinct. */ otmp = readobjnam(buf, ¬hing, TRUE); if (!otmp) { pline("Nothing fitting that description exists in the game."); if (++tries < 5) goto retry; pline(thats_enough_tries); otmp = readobjnam((char *)0, (struct obj *)0, TRUE); if (!otmp) return; /* for safety; should never happen */ } else if (otmp == ¬hing) { /* explicitly wished for "nothing", presumeably attempting to retain wishless conduct */ return; } /* KMH, conduct */ u.uconduct.wishes++; if (otmp != &zeroobj) { /* The(aobjnam()) is safe since otmp is unidentified -dlc */ (void) hold_another_object(otmp, u.uswallow ? "Oops! %s out of your reach!" : (Is_airlevel(&u.uz) || Is_waterlevel(&u.uz) || levl[u.ux][u.uy].typ < IRONBARS || levl[u.ux][u.uy].typ >= ICE) ? "Oops! %s away from you!" : "Oops! %s to the floor!", The(aobjnam(otmp, Is_airlevel(&u.uz) || u.uinwater ? "slip" : "drop")), (const char *)0); u.ublesscnt += rn1(100,50); /* the gods take notice */ } } #endif /*OVL2*/ /*zap.c*/ nethack-3.4.3/sys/0040755000000000000000000000000007764735105012474 5ustar rootrootnethack-3.4.3/sys/amiga/0040755000000000000000000000000007764735105013552 5ustar rootrootnethack-3.4.3/sys/amiga/Build.ami0100644000000000000000000001605407764735041015303 0ustar rootroot Compiling Amiga NetHack 3.4 Last Revision: 21 February 2002 for NetHack 3.4.2 We would like to thank each and every one of the people who took the time and effort to report bugs to us. THANK YOU! (And keep up the good work!) I. Introduction The Amiga-specific documentation has been split since the 3.1.3 release - please read the file Install.ami for information specific to the Amiga port before continuing. If you have problems with compilation, installation, or think you have found a bug in the game, please report it by electronic mail to the development group at nethack-bugs@nethack.org, where it will be routed to the appropriate person. Include your configuration, the version of NetHack you are playing (use the 'v' command or see include/patchlevel.h), and as much specific information as possible. As NetHack runs on many different machines, be sure to mention that you are playing the Amiga version and also mention if you are using the version for mc68k or ppc. If you want to find out about distributing NetHack, read the license (in NetHack:license or type ?i during the game). II. Compiling Amiga NetHack 3.4 II.A. Compilation Overview Compiling NetHack is not very hard - basically you do a little configuration and start make. It does, however, require a good amount of disk space and time. It also needs a good bit of memory, especially for linking. II.B. Basic Compilation NetHack can be built with SAS/C version 6.5x. The commercial version of DICE might work, but NetHack version 3.2.2 or later haven't been compiled with it. The "official" compiler for NetHack 3.4 is SAS/C 6.58 - we have dropped support for SAS/C 5.x. The Manx/Aztec port has not been tested recently and is certainly broken. Anyone managing to compile NetHack with this compiler is encouraged to submit context diffs of the required changes. When last tested, NetHack required version 5.0B of that compiler. Compiling with gcc should also work. II.B.1. Introduction to Compiling NetHack Before doing any compilation, read the README files distributed with the source. These should familiarize you with the source tree layout and what files are shared with what computers; everything in the sys/amiga directory is used exclusively by the Amiga. The makefile (sys/amiga/Makefile.ami) depends on certain assignments, providing the developer with a fairly flexible environment. See sys/amiga/Makefile.ami for assignment assumptions. DICE users should see section II.B.3 for information on creating a DMakefile usable with DMake. Edit config.h to your liking and system configuration. The defaults should be satisfactory for most systems. Read VERY CAREFULLY through the Makefile to familiarize yourself with which assignments are assumed. Otherwise, you're going to get something like "Insert NH: in any drive." You will need uudecode, and, if you need to modify dgn_comp or lev_comp, flex, and bison. The first thing Makefile.ami does is build makedefs, which handles a variety of data file generation, and then lev_comp and dgn_comp which compile the special levels. Makedefs will then be run to create a few files, followed by a roughly alphabetically sorted compilation of the entire source tree. This process will compile selected files from the sys/amiga, sys/share, win/tty, and src directories, eventually creating sbin/nethack. After building the main binary, a make install will build the auxiliary files including help files, special levels, icons, and the font files and will put these files into their final positions - most will be in dlb archives (if DLB was defined in config.h). The first make run should be done in NH:obj and the make install should be done in NetHack:; for both runs, the makefile is NH:sys/amiga/Makefile.ami (or NH:sys/amiga/DMakefile for DMake and NH:sys/amiga/Makefile.agc for gcc). Note that not all the source is simple C code. If you are modifying lev_comp or dgn_comp you may need bison and/or flex (depending on what modifications you are making). You do not need any of these tools to simply build NetHack - all the C output files are provided in the source distribution. Also, the ifchange script requires a version of diff that produces standard Unix format context diffs for proper operation - the version shipped with SAS/C is not sufficient. If you do not have bison and flex, copy the files from sys/share. The include files go in include/ and the C files go in util/. If the compile fails due to prototype errors for malloc and realloc, try deleting the first line of lev_comp.c and dgn_comp.c. II.B.2. Compiling NetHack with SAS/C version 6.58 NOTE WELL - Amiga NetHack has dropped support for SAS/C version 5. This version of NetHack was developed with SAS/C 6.58. Earlier versions than version of the compiler are known to cause problems - don't use them. A couple of notes and warnings from the SAS/C users on the team: * Included in the SAS/C port is code for generating a SnapShot.tb file upon catching various internal disasters. That is why the debug=l flag is in the makefile. This adds about 270K to the disk image, but it does not increase the run time memory requirements. * The 5.10b optimizer did not produce correct code for NetHack. The current optimizer has not been tested. II.B.3. Compiling NetHack with the commercial version of DICE IMPORTANT NOTE: If you are using DMake, you need to create DMakefile from Makefile.ami. Do the following: cd NH:sys/amiga edit from Makefile.ami to DMakefile with mkdmake opt w255 Some versions of DMake have been known to crash horribly on the makefile - if this happens, you'll need to download another make utility, such as AMake (ftp://ftp.dragonfire.net/amiga/utils/amake), which will run in DMake-compatibility mode if invoked with the -C switch (e.g. "amake -C -f NH:sys/amiga/DMakefile", or just "alias dmake amake -C"). SECOND IMPORTANT NOTE: The score list is currently disabled when compiling under DICE, due to an as-yet-unknown problem which causes system crashes when displaying the score list. NetHack can be compiled using the commercial version of DICE only. The registered shareware version had a bug in it which resulted in odd- aligned procedures. (It is possible to patch DC1 to fix this problem; however, this is not recommended, and you should upgrade to the commercial version.) DICE 3.0 (the first commercial release) has a couple of bugs in it which turn up in several of the NetHack sources; the DCC30_BUG define fixes them. If you have a more recent version of the compiler, you may be able to compile without this (and get slightly more efficient code) by commenting out the define in amiconf.h. During compilation, DICE will output a lot of warnings; they can be safely ignored. nethack-3.4.3/sys/amiga/Install.ami0100644000000000000000000002223007764735041015643 0ustar rootroot Using and Installing Amiga NetHack 3.4 (or Everything You Never Wanted to Know Before NetHacking) (or Not Everything That Happens Always Comes Knocking) Last Revision: 28 March 2000 for NetHack 3.4.2 0. Pre-intro for NetHack 3.4.2: Amiga-specific changes for 3.4.2: Most (around 99%) known bugs fixed (volunteers welcome). HackWB and HackCli are no longer supported. Use the main binary. We would like to thank each and every one of the people who took the time and effort to report bugs to us. THANK YOU! I. Introduction I.A. Overview Welcome to Amiga NetHack! If this is your first visit to our fair city, you are in for an amazing but dangerous journey; if you have visited us before, beware! the city has changed in many strange and subtle ways; it has also grown quite a bit. This missive brings to light those mundane tasks which must be dealt with before beginning your journey; for those of you who are faced with the task of installing the pre-fabricated version of our town, section III (Installing Amiga NetHack 3.4) will guide you through the task at hand. If you are ready to visit, the local visitors guide is in section II (Using Amiga NetHack 3.4); please also see the general guide packaged separately (the file "GuideBook"). To all our visitors, a hearty Welcome! - and please be careful. [Those responsible for the previous paragraphs have been sacked. The documentation has been completed at great expense in a more traditional style. -- The Management] I.B. Getting Help If you have questions about strategy, weapons, or monsters, the best place to go for help is the Usenet newsgroup rec.games.roguelike.nethack. If you have problems with installation or think you have found a bug in the game, please report it by electronic mail to the development team at nethack-bugs@nethack.org, where it will be routed to the appropriate person. Include your configuration, the version of NetHack you are playing (use the 'v' command), whether or not you are using an official binary release (and if so which one) and as much specific information as possible. As NetHack runs on many different machines, be sure to mention that you are playing the Amiga version. I.C. Credits Olaf Seibert first ported NetHack 2.3 and 3.0 to the Amiga. Richard Addison, Andrew Church, Jochen Erwied, Mark Gooderum, Ken Lorber, Greg Olson, Mike Passaretti, and Gregg Wonderly polished and extended the 3.0 and 3.1 ports. Andrew Church, Ken Lorber, and Gregg Wonderly are responsible for the 3.2 port. Janne Salmijärvi resurrected the amigaport for 3.3 and Teemu Suikki joined before 3.4.0. II. Using Amiga NetHack 3.4 Run NetHack from the shell or from some tool that allows that, ie. ToolManager. See the NetHack.txt file for command line options and other usage. II.A. Sources of Information Where to go depends on what you want to find out. If you want to find out about distributing NetHack, read the license (in NetHack:license or type ?i during the game). For an introduction to NetHack, read the GuideBook file. To find out what options are compiled into your copy of NetHack, type #v during the game. Finally, for information during the game on all kinds of things, type ? and select from the menu or by pressing Help key. II.B. The Amiga NetHack WorkBench Front End Starting from 3.3.0 HackWB is not supported. II.C. The Amiga NetHack CLI Front End Starting from 3.3.0 CLI Front end is not supported either. Instead, use the main binary. See NetHack.txt file for the standard Unix flags for NetHack. In addition to those flags, Amiga NetHack accepts the flags -l to force non-interlaced mode and -L to force interlaced mode. II.D. Amiga-Specific Information for NetHack There are several options that are unique to the Amiga version of NetHack that may be specified in the NetHack.cnf file or on an OPTIONS line: altmeta allows the ALT keys to function as META keys. The default is altmeta. flush flush discards all characters in the queue except the first, which limits typeahead accidents. The default is !flush. silent turn off the audio output. The default is silent. The current version of Amiga NetHack also supports menu accelerators. See Guidebook.txt for a detailed description. Also supported is selecting the number of stacked objects to drop, used with the (D)rop command. Type the number and then select an item (or items with accelerators). Items with a count associated with them are denoted with # in place of -. I.e. 'd - 3 blessed daggers' becomes 'd # 3 blessed daggers'. You can clear the count by hitting esc while counting or deselect and reselect the item. The default is to drop all selected items (as before). For other options how to configure the screen setting and colors refer to Nethack.cnf. III. Installing Amiga NetHack 3.4 III.A. General Installation Installation should be easy - basically it consists of putting files where they belong and adding an assign to your startup. If you are installing from the official binary distribution, simply unpacking the archive in the appropriate directory will put the files in the places they belong. IF YOU ALREADY HAVE A PREVIOUS VERSION INSTALLED YOU MUST DELETE THE OLD SAVE AND BONES FILES - THEY WILL NOT WORK! This includes save and bones files from all previous versions of NetHack (yes, even 3.3.1). If you have a game in progress and want to finish it, use your current version and then update. Will NetHack fit on your machine? NetHack 3.4 is large. NetHack 3.4 is very large. You will need: > Any standard series Amiga: 500, 600, 1000, 1200, 2000, 2500, 3000, 4000. > WorkBench 2.04 or later. > At least 3 meg of RAM. NetHack will NOT run in 1 meg (probably even 2). > Mass storage: A hard drive with over 3 meg of free space is highly recommended. Hard Disk Installation: Unpack the archive to your place of choice. Since you are reading this you've probably done that already. Now just assign NetHack: to NetHack directory containing the executable and datafiles and other needed directories. Use the table in the next section to see where things should end up. Be sure that the file 8 ends up in NetHack:hack/8. Configuration Using your favorite text editor, edit NetHack:NetHack.cnf to match your system. Create the save file directory (makedir NetHack:save) and the levels file directory (makedir NetHack:levels), if they don't already exist. Create the score file (echo to NetHack:record) and, if desired, the log file (echo to NetHack:logfile), if they don't already exist. You may leave out logfile, but record is needed. III.B. File Location Table NetHack: amii.hlp Guidebook.txt hack.font license NetHack NetHack.cnf NetHack.txt nhdat nhsdat record Recover Recover.txt logfile (optional, but useful) NetHack:hack 8 NetHack:tiles monsters.iff objects.iff other.iff IV. BBS Interface [Since HackCli and split binary is no longer supported the following probably doesn't apply anymore. Due to lack of a suitable environment it is also untested.] The BBS mode is based on the standard NetHack tty port and is designed for use in a BBS setting - it is specifically not recommended for use on the console. The current TTY mode has changed significantly since the preliminary version released with 3.1.2. In particular, BBS mode now works with split binaries (only), and now supports multiple games in progress at the same time for multi-line boards (note however that any individual user should not be allowed to run two instances of NetHack at the same time). To set up NetHack for use with a BBS, set OPTIONS=windowtype:tty and unset DUNGEONS, TRAPS, and EFFECTS in NetHack.cnf. Configure the BBS to expect I/O through stdin and stdout, and have NetHack invoked as: HackCLI :uid -u uname options... where uid is any string (without embedded spaces, colons, or slashes) that is unique for each BBS user and uname is some corresponding human- readable name for that user. Uid is used in constructing file names to prevent collisions between simultaneous games and to prevent people from using other people's save files. Uname is the name the character will have in the game and the name that will appear in the record file. The terminal is assumed to be a 24x80 ANSI-compatible terminal. The present version does not deal with situations such as low memory gracefully - as NetHack uses a considerable amount of memory this is particularly painful with multiple games in progress. Sysops are reminded to be familiar with the recover utility, which may be needed from time to time and which should probably not be available directly to users. Bug reports and suggestions for improvements are requested from the user community - this is still considered alpha software. nethack-3.4.3/sys/amiga/Makefile.agc0100644000000000000000000011261007764735041015740 0ustar rootroot# NetHack Makefile. # SCCS Id: @(#)Makefile.agc 3.2 2000/01/12 # Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996. # NetHack may be freely redistributed. See license for details. ### ### modified for gcc by Teemu Suikki (zu@iki.fi) ### ### note: you need to use smake.. sorry ### ### ### DIRECTORY STRUCTURE ### NH = nh: SBIN = $(NH)sbin/ SLIB = $(NH)slib/ NETHACK = $(NH)NetHack/ HACKEXE = $(NH)HackExe/ AMI = $(NH)sys/amiga/ DAT = $(NH)dat/ DOC = $(NH)doc/ I = $(NH)include/ SHARE = $(NH)sys/share/ NHS = $(NH)src/ TTY = $(NH)win/tty/ WSHARE = $(NH)win/share/ UTIL = $(NH)util/ O = $(NH)obj/ OO = $(NH)objo/ # NB: O and OO MUST be different directories ### ### INVOCATION ### MAKE = smake # Startup makefile with: # # $(MAKE) -f $(AMI)Makefile.amigcc # $(MAKE) -f $(AMI)Makefile.amigcc install # # You may use following targets on $(MAKE) command lines: # all do it all (default) # link just create binary from object files # obj just create common object files # obja just create amiga object files # objs just create shared object files # clean deletes the object files # spotless deletes the object files, main binary, and more # # Note: We do not build the Guidebook here since it needs tbl # (See the file sys/unix/Makefile.doc for more information) #[SAS5] [and gcc?] # If we were to use the precompiled header file feature in a newer version # of SAS/C, we would comment out these following two lines. # If we don't use precompiled header files, we uncomment it as well. HDEP = $(I)hack.h CSYM = #Pathname for uudecode program: UUDEC = uudecode # Flex/Bison command assignments -- Useful only if you have flex/bison FLEX = flex BISON = bison # FBFIL and FBLIB may be used, if required by your version of flex or bison, # to specify additional files or libraries to be linked with FBFIL = FBLIB = #lib lib:compat.lib # If you're compiling this on a 1.3 system, you'll have to uncomment the # following (for use with the ifchange script below). Also useful instead of # "protect ifchange +s" EXECUTE = execute # Headers we depend on AMDEP = $(AMI)winproto.h $(AMI)winext.h $(AMI)windefs.h $(I)winami.h # Pathname for the C compiler being used. CC = gcc -c ASM = as # Compilation flags for selected C Compiler: # $(CFLAGS) should appear before filename arguments of $(CC) command line. CFLAGS = -O3 -I $(I) # Components of various link command lines: # $(LINK) should be the pathname of the linker being used (with any options # that should appear at the beginning of the command line). The name of the # output file should appear immediately after $(LNSPEC). $(LIN) should # appear before the list of object files in each link command. $(LLINK) # should appear as the list of object files in the link command line that # creates the NetHack executable. $(LLIB) should appear at the end of each # link command line. LINK = gcc -noixemul -O3 LIN = LLINK = LLIB = FLLIB = OBJSPEC = -o PNSPEC = -o LNSPEC = -o CCLINK = gcc -noixemul CLFLAGS = -O3 INCLSPEC = -I DEFSPEC = -D IGNSPEC = -j ### ### FILE LISTS ### # A more reasonable random number generator (recommended for the Amiga): RANDOBJ = $(O)random.o .PRECIOUS: $(I)config.h $(I)decl.h $(I)hack.h $(I)permonst.h $(I)you.h # Almost nothing below this line should have to be changed. # (Exceptions are marked by [SAS6], [MANX], etc.) # # Other things that have to be reconfigured are in config.h, # (amiconf.h, pcconf.h), and possibly system.h, tradstdc.h. # Object files for makedefs: MAKEOBJS = \ $(OO)makedefs.o $(O)monst.o $(O)objects.o # Object files for special levels compiler: SPLEVOBJS = \ $(OO)lev_yacc.o $(OO)lev_lex.o $(OO)lev_main.o \ $(O)decl.o $(O)drawing.o $(O)monst.o \ $(O)objects.o $(OO)panic.o # Object files for dungeon compiler DGNCOMPOBJS = \ $(OO)dgn_yacc.o $(OO)dgn_lex.o $(OO)dgn_main.o $(O)alloc.o $(OO)panic.o # Object files for NetHack: COMMOBJ = \ $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o \ $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o \ $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o \ $(O)dig.o $(O)display.o $(O)dlb.o $(O)do.o \ $(O)do_name.o $(O)do_wear.o $(O)dog.o $(O)dogmove.o \ $(O)dokick.o $(O)dothrow.o $(O)drawing.o $(O)dungeon.o \ $(O)eat.o $(O)end.o $(O)engrave.o $(O)exper.o \ $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o \ $(O)hack.o $(O)hacklib.o $(O)invent.o $(O)light.o \ $(O)lock.o $(O)mail.o $(O)makemon.o $(O)mapglyph.o \ $(O)mcastu.o $(O)mhitm.o $(O)mhitu.o $(O)minion.o \ $(O)mklev.o $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o \ $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o \ $(O)monst.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o \ $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o \ $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o \ $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o \ $(O)quest.o $(O)questpgr.o $(O)read.o $(O)rect.o \ $(O)region.o $(O)restore.o $(O)rnd.o $(O)role.o \ $(O)rumors.o $(O)save.o $(O)shk.o $(O)shknam.o \ $(O)sit.o $(O)sounds.o $(O)sp_lev.o $(O)spell.o \ $(O)steal.o $(O)steed.o $(O)teleport.o $(O)timeout.o \ $(O)topten.o $(O)track.o $(O)trap.o $(O)u_init.o \ $(O)uhitm.o $(O)vault.o $(O)version.o $(O)vision.o \ $(O)weapon.o $(O)were.o $(O)wield.o $(O)windows.o \ $(O)wizard.o $(O)worm.o $(O)worn.o $(O)write.o \ $(O)zap.o MAKEDEFOBJ = \ $(O)monstr.o AMIGAOBJ = \ $(O)amidos.o $(O)amirip.o $(O)amisnd.o $(O)amistack.o \ $(O)amiwind.o $(O)winami.o $(O)winchar.o $(O)winfuncs.o \ $(O)winkey.o $(O)winmenu.o $(O)winreq.o $(O)winstr.o # Objects from assembly sources (because DMake can't handle default rules) AMIGAOBJ2 = \ # $(O)dispmap.o SHAREOBJ = \ $(O)pcmain.o $(RANDOBJ) TTYOBJ = \ $(O)getline.o $(O)termcap.o $(O)topl.o $(O)wintty.o $(O)amitty.o \ $(O)rip.o # Yuck yuck yuck. Have to tell DMake where these are, since they're not # all in the same place. TTYSRC = \ $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \ $(AMI)amitty.c $(NHS)rip.c # All the object files for NetHack: HOBJ = $(COMMOBJ) $(AMIGAOBJ) $(AMIGAOBJ2) $(SHAREOBJ) $(MAKEDEFOBJ) $(TTYOBJ) ### ### DATA FILES ### # quest files ADFILES1= $(SLIB)Arc-fila.lev $(SLIB)Arc-filb.lev $(SLIB)Arc-loca.lev \ $(SLIB)Arc-strt.lev ADFILES= $(SLIB)Arc-goal.lev $(ADFILES1) BDFILES1= $(SLIB)Bar-fila.lev $(SLIB)Bar-filb.lev $(SLIB)Bar-loca.lev \ $(SLIB)Bar-strt.lev BDFILES= $(SLIB)Bar-goal.lev $(BDFILES1) CDFILES1= $(SLIB)Cav-fila.lev $(SLIB)Cav-filb.lev $(SLIB)Cav-loca.lev \ $(SLIB)Cav-strt.lev CDFILES= $(SLIB)Cav-goal.lev $(CDFILES1) HDFILES1= $(SLIB)Hea-fila.lev $(SLIB)Hea-filb.lev $(SLIB)Hea-loca.lev \ $(SLIB)Hea-strt.lev HDFILES= $(SLIB)Hea-goal.lev $(HDFILES1) KDFILES1= $(SLIB)Kni-fila.lev $(SLIB)Kni-filb.lev $(SLIB)Kni-loca.lev \ $(SLIB)Kni-strt.lev KDFILES= $(SLIB)Kni-goal.lev $(KDFILES1) MDFILES1= $(SLIB)Mon-fila.lev $(SLIB)Mon-filb.lev $(SLIB)Mon-loca.lev \ $(SLIB)Mon-strt.lev MDFILES= $(SLIB)Mon-goal.lev $(MDFILES1) PDFILES1= $(SLIB)Pri-fila.lev $(SLIB)Pri-filb.lev $(SLIB)Pri-loca.lev \ $(SLIB)Pri-strt.lev PDFILES= $(SLIB)Pri-goal.lev $(PDFILES1) RDFILES1= $(SLIB)Rog-fila.lev $(SLIB)Rog-filb.lev $(SLIB)Rog-loca.lev \ $(SLIB)Rog-strt.lev RDFILES= $(SLIB)Rog-goal.lev $(RDFILES1) RANFILES1= $(SLIB)Ran-fila.lev $(SLIB)Ran-filb.lev $(SLIB)Ran-loca.lev \ $(SLIB)Ran-strt.lev RANFILES= $(SLIB)Ran-goal.lev $(RANFILES1) SDFILES1= $(SLIB)Sam-fila.lev $(SLIB)Sam-filb.lev $(SLIB)Sam-loca.lev \ $(SLIB)Sam-strt.lev SDFILES= $(SLIB)Sam-goal.lev $(SDFILES1) TDFILES1= $(SLIB)Tou-fila.lev $(SLIB)Tou-filb.lev $(SLIB)Tou-loca.lev \ $(SLIB)Tou-strt.lev TDFILES= $(SLIB)Tou-goal.lev $(TDFILES1) VDFILES1= $(SLIB)Val-fila.lev $(SLIB)Val-filb.lev $(SLIB)Val-loca.lev \ $(SLIB)Val-strt.lev VDFILES= $(SLIB)Val-goal.lev $(VDFILES1) WDFILES1= $(SLIB)Wiz-fila.lev $(SLIB)Wiz-filb.lev $(SLIB)Wiz-loca.lev \ $(SLIB)Wiz-strt.lev WDFILES= $(SLIB)Wiz-goal.lev $(WDFILES1) XDFILES= $(ADFILES) $(BDFILES) $(CDFILES) $(HDFILES) $(KDFILES) \ $(MDFILES) $(PDFILES) $(RDFILES) $(RANFILES) $(SDFILES) $(TDFILES) \ $(VDFILES) $(WDFILES) SOUNDFILES= \ $(SBIN)cvtsnd \ $(SLIB)sounds \ $(SLIB)sounds/Bell $(SLIB)sounds/Bugle \ $(SLIB)sounds/Drum_Of_Earthquake \ $(SLIB)sounds/Fire_Horn $(SLIB)sounds/Frost_Horn \ $(SLIB)sounds/Leather_Drum $(SLIB)sounds/Magic_Flute \ $(SLIB)sounds/Magic_Harp $(SLIB)sounds/Tooled_Horn \ $(SLIB)sounds/Wooden_Flute $(SLIB)sounds/Wooden_Harp TILEFILES= \ $(SBIN)txt2iff \ $(NETHACK)tiles \ $(NETHACK)tiles/objects.iff \ $(NETHACK)tiles/monsters.iff \ $(NETHACK)tiles/other.iff INSTDUNGEONFILES1= \ $(SLIB)air.lev $(SLIB)asmodeus.lev $(SLIB)astral.lev \ $(SLIB)baalz.lev $(SLIB)bigrm-1.lev $(SLIB)bigrm-2.lev \ $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev \ $(SLIB)castle.lev $(SLIB)dungeon $(SLIB)earth.lev \ $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev $(SLIB)fire.lev \ $(SLIB)juiblex.lev $(SLIB)knox.lev $(SLIB)medusa-1.lev \ $(SLIB)medusa-2.lev $(SLIB)minend-1.lev $(SLIB)minend-2.lev \ $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev $(SLIB)minefill.lev \ $(SLIB)options $(SLIB)oracle.lev $(SLIB)orcus.lev \ $(SLIB)sanctum.lev $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev \ $(SLIB)soko2-1.lev $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev \ $(SLIB)soko3-2.lev $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev \ $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev \ $(SLIB)valley.lev $(SLIB)water.lev $(SLIB)wizard1.lev \ $(SLIB)wizard2.lev $(SLIB)wizard3.lev \ $(XDFILES) INSTDUNGEONFILES= $(NETHACK)NetHack.cnf $(INSTDUNGEONFILES1) INSTDATAFILES= \ $(NETHACK)license $(NETHACK)logfile $(NETHACK)record \ $(NETHACK)tomb.iff $(NETHACK)amii.hlp $(NETHACK)Recover.txt \ $(NETHACK)GuideBook.txt $(NETHACK)NetHack.txt $(NETHACK)Install.ami \ # $(NETHACK)HackWB.hlp $(NETHACK)WBDefaults.def LIBFILES= \ $(INSTDUNGEONFILES1) \ $(SLIB)cmdhelp $(SLIB)data $(SLIB)dungeon \ $(SLIB)help $(SLIB)hh $(SLIB)history \ $(SLIB)opthelp $(SLIB)oracles $(SLIB)rumors \ $(SLIB)quest.dat $(SLIB)wizhelp ### ### Getting down to business: ### all: $(COMPACT_HEADERS) $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \ $(SBIN)dlb $(NETHACK)recover #$(NETHACK)HackCli $(SBIN)splitter \ # $(NETHACK)HackWB install: inst-data inst-dungeon inst-fonts inst-sounds inst-tiles \ $(NETHACK)recover $(NETHACK)NetHack $(NETHACK)nhdat #$(NETHACK)NetHack.dir inst-icons $(SBIN)NetHack: link $(NETHACK)NetHack: $(SBIN)NetHack copy $(SBIN)NetHack $(NETHACK)NetHack ## uuh this is messy.. smake has weird command line length limit link: $(HOBJ) list to t:link lformat="$(O)%s" $(O)\#?.o QUICK NOHEAD echo "\#sh" to t:cc echo "$(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLIB) $(LLINK) " >>t:cc noline fmt -u -w 2500 t:link >>t:cc sh t:cc delete t:cc t:link ## dlb support $(OO)dlb_main.o: $(UTIL)dlb_main.c $(HDEP) $(I)dlb.h $(I)date.h $(CC) $(CFLAGS) $(OBJSPEC)$(OO)dlb_main.o $(UTIL)dlb_main.c $(SBIN)dlb: $(OO)dlb_main.o $(O)dlb.o $(O)alloc.o $(OO)panic.o $(LINK) $(PNSPEC) $(SBIN)dlb $(LIN) $(OO)dlb_main.o $(O)dlb.o \ $(O)alloc.o $(OO)panic.o $(LLIB) obj: $(HOBJ) obja: $(AMIGAOBJ) objs: $(SHAREOBJ) SUFFIXES = .lev .des .des.lev: $(SBIN)lev_comp $< # The default method for creating object files: #$(O)%.o: $(NHS)%.c .c.o: $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)$@ $< clean: -delete $(O)\#?.o $(OO)\#?.o spotless: clean -delete $(SBIN)NetHack $(SBIN)lev_comp $(SBIN)makedefs $(SBIN)dgn_comp -delete $(SBIN)cvtsnd $(SBIN)dlb $(SBIN)txt2iff $(SBIN)splitter -delete $(SBIN)tilemap -delete $(SLIB)data $(SLIB)rumors -delete $(SLIB)\#?.lev -delete $(SLIB)dungeon -delete $(SLIB)cmdhelp $(SLIB)help $(SLIB)hh $(SLIB)history -delete $(SLIB)opthelp $(SLIB)options $(SLIB)oracles -delete $(SLIB)quest.dat $(SLIB)wizhelp # -delete $(SLIB)earth.lev $(SLIB)air.lev $(SLIB)fire.lev # -delete $(SLIB)water.lev $(SLIB)astral.lev # -delete $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev # -delete $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev # -delete $(SLIB)medusa-1.lev $(SLIB)medusa-2.lev # -delete $(SLIB)oracle.lev $(SLIB)wizard1.lev $(SLIB)wizard2.lev # -delete $(SLIB)wizard3.lev $(DAT)dungeon.pdf $(SLIB)valley.lev # -delete $(SLIB)minefill.lev # -delete $(SLIB)minetn-1 $(SLIB)minetn-2 $(SLIB)minend-1 $(SLIB)minend-2 # -delete $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev # -delete $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev # -delete $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev # -delete $(ADFILES) # -delete $(BDFILES) # -delete $(CDFILES) # -delete $(HDFILES) # -delete $(KDFILES) # -delete $(MDFILES) # -delete $(PDFILES) # -delete $(RDFILES) # -delete $(RANFILES) # -delete $(SDFILES) # -delete $(TDFILES) # -delete $(VDFILES) # -delete $(WDFILES) -delete $(I)onames.h $(I)pm.h $(I)date.h -delete $(NHS)tile.c $(NHS)monstr.c -delete $(I)tile.h # -echo to $(I)onames.h "" noline # -c:wait 2 # -echo to $(I)pm.h "" noline # -c:wait 2 # -setdate $(UTIL)makedefs.c # -c:wait 2 # Creating precompiled version of $(I)hack.h to save disk I/O. # # Please note: The dependency lines for the modules here are # deliberately incorrect. Including "hack.h" in # the dependency list would cause a dependency # loop. # $(SBIN)makedefs: $(MAKEOBJS) $(LINK) $(LNSPEC) $(SBIN)makedefs $(LIN) $(MAKEOBJS) $(LLIB) $(OO)makedefs.o: $(UTIL)makedefs.c $(I)config.h $(I)permonst.h $(I)monsym.h \ $(I)objclass.h $(I)patchlevel.h $(I)qtext.h $(I)artilist.h $(CC) $(DEFSPEC)MAKEDEFS_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)makedefs.c $(SBIN)lev_comp: $(SPLEVOBJS) $(LINK) $(LNSPEC) $(SBIN)lev_comp $(LIN) $(SPLEVOBJS) $(FBFIL) $(FLLIB) $(SBIN)dgn_comp: $(DGNCOMPOBJS) $(LINK) $(LNSPEC) $(SBIN)dgn_comp $(LIN) $(DGNCOMPOBJS) $(FBFIL) $(FLLIB) $(OO)lev_yacc.o: $(UTIL)lev_yacc.c $(HDEP) $(I)sp_lev.h $(I)pm.h $(I)onames.h # setdate $(UTIL)lev_yacc.c $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)PREFIX="NH:slib/" $(CFLAGS) \ $(DEFSPEC)alloca=malloc $(OBJSPEC)$@ $(UTIL)lev_yacc.c $(OO)lev_lex.o: $(UTIL)lev_lex.c $(HDEP) $(I)lev_comp.h $(I)sp_lev.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)lev_lex.c $(OO)lev_main.o: $(UTIL)lev_main.c $(HDEP) $(I)pm.h $(I)onames.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)lev_main.c $(OO)dgn_yacc.o: $(UTIL)dgn_yacc.c $(HDEP) $(I)dgn_file.h $(I)patchlevel.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(DEFSPEC)alloca=malloc \ $(OBJSPEC)$@ $(UTIL)dgn_yacc.c $(OO)dgn_lex.o: $(UTIL)dgn_lex.c $(I)config.h $(I)dgn_comp.h $(I)dgn_file.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)dgn_lex.c $(OO)dgn_main.o: $(UTIL)dgn_main.c $(I)config.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)dgn_main.c $(OO)panic.o: $(UTIL)panic.c $(HDEP) $(OO)recover.o: $(UTIL)recover.c $(I)config.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)recover.c $(NETHACK)recover: $(OO)recover.o $(LINK) $(LNSPEC) $(NETHACK)recover $(LIN) $(OO)recover.o $(LLIB) # [OPTION] -- If you have flex/bison, leave these uncommented. Otherwise, # comment them out and be careful! (You're not guaranteed to have the most # up to date *_comp.c, *_comp.h and *_lex.c) $(I)lev_comp.h: $(UTIL)lev_yacc.c $(I)patchlevel.h $(UTIL)lev_yacc.c: $(UTIL)lev_comp.y $(I)patchlevel.h $(BISON) -d $(UTIL)lev_comp.y # copy y.tab.c $(UTIL)lev_yacc.c # copy y.tab.h $(I)lev_comp.h copy $(UTIL)lev_comp.tab.c $(UTIL)lev_yacc.c copy $(UTIL)lev_comp.tab.h $(I)lev_comp.h # delete y.tab.c # delete y.tab.h delete $(UTIL)lev_comp.tab.c delete $(UTIL)lev_comp.tab.h $(UTIL)lev_lex.c: $(UTIL)lev_comp.l $(I)patchlevel.h $(FLEX) $(UTIL)lev_comp.l copy lex.yy.c $(UTIL)lev_lex.c delete lex.yy.c $(I)dgn_comp.h: $(UTIL)dgn_yacc.c $(I)patchlevel.h $(UTIL)dgn_yacc.c: $(UTIL)dgn_comp.y $(I)patchlevel.h $(BISON) -d $(UTIL)dgn_comp.y # copy y.tab.c $(UTIL)dgn_yacc.c # copy y.tab.h $(I)dgn_comp.h copy $(UTIL)dgn_comp.tab.c $(UTIL)dgn_yacc.c copy $(UTIL)dgn_comp.tab.h $(I)dgn_comp.h # delete y.tab.c # delete y.tab.h delete $(UTIL)dgn_comp.tab.c delete $(UTIL)dgn_comp.tab.h $(UTIL)dgn_lex.c: $(UTIL)dgn_comp.l $(I)patchlevel.h $(FLEX) $(UTIL)dgn_comp.l copy lex.yy.c $(UTIL)dgn_lex.c delete lex.yy.c # # The following include files depend on makedefs to be created. # As a result, they are not defined in HACKINCL, instead, their # dependencies are explicitly outlined here. # # # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. # $(I)date.h $(DAT)options: $(HDEP) $(SBIN)makedefs $(AMIGAOBJ) $(I)patchlevel.h $(SBIN)makedefs -v $(EXECUTE) ifchange MOVE $(I)t.date.h $(I)date.h -c:wait 2 $(I)onames.h: $(SBIN)makedefs $(SBIN)makedefs -o $(EXECUTE) ifchange TOUCH $(I)t.onames.h $(I)onames.h $(I)decl.h $(EXECUTE) ifchange MOVE $(I)t.onames.h $(I)onames.h -c:wait 2 $(I)pm.h: $(SBIN)makedefs $(SBIN)makedefs -p $(EXECUTE) ifchange TOUCH $(I)t.pm.h $(I)pm.h $(I)decl.h $(I)youprop.h $(EXECUTE) ifchange MOVE $(I)t.pm.h $(I)pm.h -c:wait 2 $(SLIB)quest.dat: $(DAT)quest.txt $(SBIN)makedefs $(SBIN)makedefs -q $(NHS)monstr.c: $(HDEP) $(SBIN)makedefs $(SBIN)makedefs -m -c:wait 2 $(SLIB)oracles: $(DAT)oracles.txt $(SBIN)makedefs $(SBIN)makedefs -h -c:wait 2 # # The following programs vary depending on what OS you are using. # As a result, they are not defined in HACKSRC and their dependencies # are explicitly outlined here. # $(O)amidos.o: $(AMI)amidos.c $(HDEP) $(O)amirip.o: $(AMI)amirip.c $(HDEP) $(O)aglue.o: $(AMI)aglue.a $(ASM) $(AFLAGS) $(AOBJSPEC)$(O)aglue.o $(AMI)aglue.a $(O)amisnd.o: $(AMI)amisnd.c $(HDEP) $(O)winchar.o: $(AMI)winchar.c $(NHS)tile.c $(HDEP) $(NHS)tile.c: $(WSHARE)tilemap.c $(CCLINK) $(CFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c $(SBIN)tilemap $(O)winstr.o: $(AMI)winstr.c $(HDEP) $(AMDEP) $(O)winreq.o: $(AMI)winreq.c $(HDEP) $(AMDEP) $(AMI)colorwin.c $(AMI)clipwin.c $(O)winfuncs.o: $(AMI)winfuncs.c $(HDEP) $(AMDEP) $(I)patchlevel.h $(O)winkey.o: $(AMI)winkey.c $(HDEP) $(AMDEP) $(O)winmenu.o: $(AMI)winmenu.c $(HDEP) $(AMDEP) $(O)winami.o: $(AMI)winami.c $(HDEP) $(AMDEP) #$(AMI)char.c $(AMI)randwin.c #$(O)amilib.o: $(AMI)amilib.c $(HDEP) $(AMDEP) $(O)amiwind.o: $(AMI)amiwind.c $(AMI)amimenu.c $(HDEP) $(AMDEP) $(O)amiwbench.o: $(AMI)amiwbench.c $(HDEP) $(O)random.o: $(SHARE)random.c $(O)pcmain.o: $(SHARE)pcmain.c $(HDEP) $(I)dlb.h $(O)dispmap.o: $(AMI)dispmap.s $(ASM) $(AFLAGS) $(AOBJSPEC)$@ $< # Stuff to build the front ends $(NETHACK)HackWB: $(OO)wb.o $(OO)wbx.o $(OO)loader.o $(OO)multi.o $(LINK) $(LNSPEC) $(NETHACK)HackWB $(LIN) $(OO)wb.o $(OO)wbx.o \ $(OO)loader.o $(OO)multi.o $(LLIB) $(NETHACK)HackCli: $(OO)cli.o $(OO)loader.o $(OO)multi.o $(LINK) $(LNSPEC) $(NETHACK)HackCli $(LIN) $(OO)cli.o $(OO)loader.o \ $(OO)multi.o $(LLIB) # This needs to exist to eliminate the HackWB startup message $(NETHACK)WBDefaults.def: echo to $(NETHACK)WBDefaults.def WBH = $(AMI)wbdefs.h $(AMI)wbstruct.h $(AMI)wbprotos.h ASP = $(AMI)splitter $(OO)wb.o: $(WBH) $(AMI)wb.c $(AMI)wbwin.c $(AMI)wbdata.c $(AMI)wbgads.c \ $(I)patchlevel.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wb.o $(AMI)wb.c $(OO)wbx.o: $(WBH) $(AMI)wbcli.c $(AMI)wbwin.c $(AMI)wbdata.c \ $(I)patchlevel.h $(I)date.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wbx.o $(AMI)wbcli.c $(OO)loader.o: $(ASP)/loader.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/multi.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)loader.o $(ASP)/loader.c $(OO)multi.o: $(ASP)/multi.c $(ASP)/multi.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)multi.o $(ASP)/multi.c $(OO)cli.o: $(WBH) $(AMI)wbcli.c $(I)patchlevel.h $(I)date.h $(CC) $(WBCFLAGS) $(WBC2FLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)cli.o \ $(AMI)wbcli.c #### # splitter support $(SBIN)splitter: $(OO)splitter.o $(OO)arg.o $(LINK) $(LNSPEC) $(SBIN)splitter $(LIN) $(OO)splitter.o $(OO)arg.o \ $(LLIB) $(NETHACK)NetHack.dir: $(SBIN)splitter $(SBIN)NetHack $(SBIN)splitter $(SBIN)NetHack $(OO)splitter.o: $(ASP)/splitter.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/arg.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)splitter.o \ $(ASP)/splitter.c $(OO)arg.o: $(ASP)/arg.c $(ASP)/arg.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)arg.o $(ASP)/arg.c # Create/copy other stuff into NetHack: directory: $(NETHACK)tomb.iff: $(SBIN)xpm2iff $(AMI)grave16.xpm $(SBIN)xpm2iff $(AMI)grave16.xpm $(NETHACK)tomb.iff $(OO)xpm2iff.o: $(AMI)xpm2iff.c $(CC) $(CFLAGS) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(AMI)xpm2iff.c $(SBIN)xpm2iff: $(OO)xpm2iff.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)xpm2iff.o $(FLLIB) # Tile installation for the tile version of the game inst-tiles: $(TILEFILES) $(NETHACK)tiles: -makedir $(NETHACK)tiles $(OO)txt2iff.o: $(AMI)txt2iff.c $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ \ $(AMI)txt2iff.c $(OO)ppmwrite.o: $(WSHARE)ppmwrite.c $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)ppmwrite.c $(OO)tiletext.o: $(WSHARE)tiletext.c $(I)config.h $(WSHARE)tile.h $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tiletext.c $(OO)tiletxt.o: $(WSHARE)tilemap.c $(I)hack.h $(CC) $(CFLAGS) $(CSYM) $(DEFSPEC)TILETEXT $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tilemap.c NAMEOBJS = $(O)drawing.o $(O)decl.o $(O)monst.o $(O)objects.o $(SBIN)txt2ppm: $(OO)ppmwrite.o $(NAMEOBJS) $(O)alloc.o $(OO)panic.o $(OO)tiletext.o $(OO)tiletxt.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)ppmwrite.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(O)alloc.o $(OO)panic.o $(FLLIB) $(SBIN)txt2iff: $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o \ $(OO)tiletxt.o $(FLLIB) $(NETHACK)tiles/objects.iff: $(WSHARE)objects.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)objects.txt $(NETHACK)tiles/objects.iff $(NETHACK)tiles/monsters.iff: $(WSHARE)monsters.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)monsters.txt $(NETHACK)tiles/monsters.iff $(NETHACK)tiles/other.iff: $(WSHARE)other.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)other.txt $(NETHACK)tiles/other.iff # Sound installation rules. inst-sounds: $(SOUNDFILES) list to T:nhsdat.lst $(SLIB)sounds QUICK NOHEAD echo >T:make-nhsdat $(SBIN)dlb cCfI $(SLIB)sounds $(NETHACK)nhsdat T:nhsdat.lst echo >>T:make-nhsdat if not exists $(NETHACK)nhsdat echo >>T:make-nhsdat copy $(SLIB)sounds/\#? $(NETHACK)sounds echo >>T:make-nhsdat endif execute T:make-nhsdat -delete T:make-nhsdat $(SLIB)sounds: -makedir $(SLIB)sounds $(SBIN)cvtsnd: $(OO)cvtsnd.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)cvtsnd.o $(FLLIB) $(OO)cvtsnd.o: $(AMI)cvtsnd.c $(SLIB)sounds/Bell: $(SHARE)sounds/bell.uu $(UUDEC) $(SHARE)sounds/bell.uu $(SBIN)cvtsnd Bell $(SLIB)sounds/Bell -delete Bell $(SLIB)sounds/Bugle: $(SHARE)sounds/bugle.uu $(UUDEC) $(SHARE)sounds/bugle.uu $(SBIN)cvtsnd Bugle $(SLIB)sounds/Bugle -delete Bugle $(SLIB)sounds/Drum_Of_Earthquake: $(SHARE)sounds/erthdrum.uu $(UUDEC) $(SHARE)sounds/erthdrum.uu $(SBIN)cvtsnd Drum_Of_Earthquake $(SLIB)sounds/Drum_Of_Earthquake -delete Drum_Of_Earthquake $(SLIB)sounds/Fire_Horn: $(SHARE)sounds/firehorn.uu $(UUDEC) $(SHARE)sounds/firehorn.uu $(SBIN)cvtsnd Fire_Horn $(SLIB)sounds/Fire_Horn -delete Fire_Horn $(SLIB)sounds/Frost_Horn: $(SHARE)sounds/frsthorn.uu $(UUDEC) $(SHARE)sounds/frsthorn.uu $(SBIN)cvtsnd Frost_Horn $(SLIB)sounds/Frost_Horn -delete Frost_Horn $(SLIB)sounds/Leather_Drum: $(SHARE)sounds/lethdrum.uu $(UUDEC) $(SHARE)sounds/lethdrum.uu $(SBIN)cvtsnd Leather_Drum $(SLIB)sounds/Leather_Drum -delete Leather_Drum $(SLIB)sounds/Magic_Flute: $(SHARE)sounds/mgcflute.uu $(UUDEC) $(SHARE)sounds/mgcflute.uu $(SBIN)cvtsnd Magic_Flute $(SLIB)sounds/Magic_Flute -delete Magic_Flute $(SLIB)sounds/Magic_Harp: $(SHARE)sounds/mgcharp.uu $(UUDEC) $(SHARE)sounds/mgcharp.uu $(SBIN)cvtsnd Magic_Harp $(SLIB)sounds/Magic_Harp -delete Magic_Harp $(SLIB)sounds/Tooled_Horn: $(SHARE)sounds/toolhorn.uu $(UUDEC) $(SHARE)sounds/toolhorn.uu $(SBIN)cvtsnd Tooled_Horn $(SLIB)sounds/Tooled_Horn -delete Tooled_Horn $(SLIB)sounds/Wooden_Flute: $(SHARE)sounds/wdnflute.uu $(UUDEC) $(SHARE)sounds/wdnflute.uu $(SBIN)cvtsnd Wooden_Flute $(SLIB)sounds/Wooden_Flute -delete Wooden_Flute $(SLIB)sounds/Wooden_Harp: $(SHARE)sounds/wdnharp.uu $(UUDEC) $(SHARE)sounds/wdnharp.uu $(SBIN)cvtsnd Wooden_Harp $(SLIB)sounds/Wooden_Harp -delete Wooden_Harp inst-dungeon: $(INSTDUNGEONFILES) $(NETHACK)options : $(DAT)options copy $(DAT)options $@ # Create compiled dungeon files BGM= $(SLIB)bigrm-2.lev $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev $(BGM): $(SLIB)bigrm-1.lev $(SLIB)bigrm-1.lev: $(DAT)bigroom.des $(SBIN)lev_comp $(SLIB)castle.lev: $(DAT)castle.des $(SBIN)lev_comp ENDGAME1= $(SLIB)air.lev $(SLIB)earth.lev $(SLIB)fire.lev $(SLIB)water.lev $(ENDGAME1): $(SLIB)astral.lev $(SLIB)astral.lev: $(DAT)endgame.des $(SBIN)lev_comp GEHENNOM1= $(SLIB)asmodeus.lev $(SLIB)baalz.lev $(SLIB)juiblex.lev \ $(SLIB)orcus.lev $(SLIB)sanctum.lev $(GEHENNOM1): $(SLIB)valley.lev $(SLIB)valley.lev: $(DAT)gehennom.des $(SBIN)lev_comp $(SLIB)knox.lev: $(DAT)knox.des $(SBIN)lev_comp MINES1= $(SLIB)minend-1.lev $(SLIB)minend-2.lev $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev $(MINES1): $(SLIB)minefill.lev $(SLIB)minefill.lev: $(DAT)mines.des $(SBIN)lev_comp $(SLIB)oracle.lev: $(DAT)oracle.des $(SBIN)lev_comp TOWER1= $(SLIB)tower1.lev $(SLIB)tower2.lev $(TOWER1): $(SLIB)tower3.lev $(SLIB)tower3.lev: $(DAT)tower.des $(SBIN)lev_comp WIZARD1= $(SLIB)wizard1.lev $(SLIB)wizard2.lev $(SLIB)wizard3.lev \ $(SLIB)fakewiz1.lev $(WIZARD1): $(SLIB)fakewiz2.lev $(SLIB)fakewiz2.lev: $(DAT)yendor.des $(SBIN)lev_comp MEDUSA1= $(SLIB)medusa-1.lev $(MEDUSA1): $(SLIB)medusa-2.lev $(SLIB)medusa-2.lev: $(DAT)medusa.des $(SBIN)lev_comp SOKOBAN1= $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev \ $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev \ $(SLIB)soko4-1.lev $(SOKOBAN1): $(SLIB)soko4-2.lev $(SLIB)soko4-2.lev: $(DAT)sokoban.des $(SBIN)lev_comp $(ADFILES1): $(SLIB)Arc-goal.lev $(SLIB)Arc-goal.lev: $(DAT)Arch.des $(SBIN)lev_comp $(BDFILES1): $(SLIB)Bar-goal.lev $(SLIB)Bar-goal.lev: $(DAT)Barb.des $(SBIN)lev_comp $(CDFILES1): $(SLIB)Cav-goal.lev $(SLIB)Cav-goal.lev: $(DAT)Caveman.des $(SBIN)lev_comp $(HDFILES1): $(SLIB)Hea-goal.lev $(SLIB)Hea-goal.lev: $(DAT)Healer.des $(SBIN)lev_comp $(KDFILES1): $(SLIB)Kni-goal.lev $(SLIB)Kni-goal.lev: $(DAT)Knight.des $(SBIN)lev_comp $(MDFILES1): $(SLIB)Mon-goal.lev $(SLIB)Mon-goal.lev: $(DAT)Monk.des $(SBIN)lev_comp $(PDFILES1): $(SLIB)Pri-goal.lev $(SLIB)Pri-goal.lev: $(DAT)Priest.des $(SBIN)lev_comp $(RDFILES1): $(SLIB)Rog-goal.lev $(SLIB)Rog-goal.lev: $(DAT)Rogue.des $(SBIN)lev_comp $(RANFILES1): $(SLIB)Ran-goal.lev $(SLIB)Ran-goal.lev: $(DAT)Ranger.des $(SBIN)lev_comp $(SDFILES1): $(SLIB)Sam-goal.lev $(SLIB)Sam-goal.lev: $(DAT)Samurai.des $(SBIN)lev_comp $(TDFILES1): $(SLIB)Tou-goal.lev $(SLIB)Tou-goal.lev: $(DAT)Tourist.des $(SBIN)lev_comp $(VDFILES1): $(SLIB)Val-goal.lev $(SLIB)Val-goal.lev: $(DAT)Valkyrie.des $(SBIN)lev_comp $(WDFILES1): $(SLIB)Wiz-goal.lev $(SLIB)Wiz-goal.lev: $(DAT)Wizard.des $(SBIN)lev_comp $(SLIB)dungeon: $(DAT)dungeon.def $(SBIN)makedefs $(SBIN)dgn_comp $(SBIN)makedefs -e $(SBIN)dgn_comp $(DAT)dungeon.pdf copy $(DAT)dungeon $(SLIB)dungeon delete $(DAT)dungeon inst-data: $(INSTDATAFILES) $(NETHACK)amii.hlp: $(AMI)amii.hlp copy $(AMI)amii.hlp $@ #$(NETHACK)data: $(DAT)data # copy $(DAT)data $@ $(SLIB)data: $(DAT)data.base $(I)config.h $(SBIN)makedefs $(SBIN)makedefs -d #$(NETHACK)rumors: $(DAT)rumors # copy $(DAT)rumors $@ $(SLIB)rumors: $(DAT)rumors.tru $(DAT)rumors.fal $(SBIN)makedefs $(SBIN)makedefs -r $(SLIB)cmdhelp: $(DAT)cmdhelp copy $(DAT)cmdhelp $@ $(SLIB)help: $(DAT)help copy $(DAT)help $@ $(SLIB)hh: $(DAT)hh copy $(DAT)hh $@ $(NETHACK)HackWB.hlp: $(AMI)HackWB.hlp copy $(AMI)HackWB.hlp $@ $(SLIB)history: $(DAT)history copy $(DAT)history $@ $(NETHACK)license: $(DAT)license copy $(DAT)license $@ $(SLIB)opthelp: $(DAT)opthelp copy $(DAT)opthelp $@ $(NETHACK)Recover.txt: $(DOC)Recover.txt copy $(DOC)Recover.txt $@ $(NETHACK)GuideBook.txt: $(DOC)GuideBook.txt copy $(DOC)GuideBook.txt $@ $(NETHACK)NetHack.txt: $(DOC)NetHack.txt copy $(DOC)NetHack.txt $@ $(NETHACK)Install.ami: $(AMI)Install.ami copy $(AMI)Install.ami $@ $(NETHACK)logfile: echo to $@ $(NETHACK)record: echo to $@ $(SLIB)wizhelp: $(DAT)wizhelp copy $(DAT)wizhelp $@ # Create the directories here because NetHack.cnf puts them there by default $(NETHACK)NetHack.cnf: $(AMI)NetHack.cnf copy $(AMI)NetHack.cnf $@ -makedir $(NETHACK)save -makedir $(NETHACK)levels # Unpack and install fonts INSTFONTFILES= $(NETHACK)hack.font $(NETHACK)hack $(NETHACK)hack/8 inst-fonts: $(INSTFONTFILES) $(NETHACK)hack/8: $(AMI)amifont8.uu $(NETHACK)hack $(UUDEC) $(AMI)amifont8.uu copy 8 $(NETHACK)hack/8 delete 8 $(NETHACK)hack.font: $(AMI)amifont.uu $(UUDEC) $(AMI)amifont.uu copy hack.font $(NETHACK)hack.font delete hack.font $(NETHACK)hack: -makedir $@ INSTICONFILES= \ $(NETHACK)default.icon $(NETHACK)NetHack.info $(NETHACK)NewGame.info \ $(NETHACK)HackWB.info inst-icons: $(INSTICONFILES) # Unpack the icons into place $(NETHACK)default.icon: $(AMI)dflticon.uu $(UUDEC) $(AMI)dflticon.uu # copy default.icon $(NETHACK)default.icon # delete default.icon $(NETHACK)NetHack.info: $(AMI)NHinfo.uu $(UUDEC) $(AMI)NHinfo.uu # copy NetHack.info $(NETHACK)NetHack.info # delete NetHack.info $(NETHACK)NewGame.info: $(AMI)NewGame.uu $(UUDEC) $(AMI)NewGame.uu # copy NewGame.info $(NETHACK)NewGame.info # delete NewGame.info $(NETHACK)HackWB.info: $(AMI)HackWB.uu $(UUDEC) $(AMI)HackWB.uu # copy HackWB.info $(NETHACK)HackWB.info # delete HackWB.info # If DLB is defined, create the nhdat library file in the playground # directory. If not, move all the data files there. $(NETHACK)nhdat: $(LIBFILES) list to T:nhdat.lst $(SLIB) QUICK NOHEAD FILES echo >T:make-nhdat $(SBIN)dlb cCfI $(SLIB) $(NETHACK)nhdat T:nhdat.lst echo >>T:make-nhdat if not exists $(NETHACK)nhdat echo >>T:make-nhdat copy $(SLIB)\#? $(NETHACK) echo >>T:make-nhdat endif execute T:make-nhdat -delete T:make-nhdat # DO NOT DELETE THIS LINE $(O)allmain.o: $(NHS)allmain.c $(HDEP) $(O)alloc.o: $(NHS)alloc.c $(I)config.h $(O)apply.o: $(NHS)apply.c $(HDEP) $(I)edog.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)apply.c $(O)artifact.o: $(NHS)artifact.c $(HDEP) $(I)artifact.h $(I)artilist.h $(O)attrib.o: $(NHS)attrib.c $(HDEP) $(I)artifact.h $(O)ball.o: $(NHS)ball.c $(HDEP) $(O)bones.o: $(NHS)bones.c $(HDEP) $(I)lev.h $(O)botl.o: $(NHS)botl.c $(HDEP) $(O)cmd.o: $(NHS)cmd.c $(HDEP) $(I)func_tab.h $(O)dbridge.o: $(NHS)dbridge.c $(HDEP) $(O)decl.o: $(NHS)decl.c $(HDEP) $(I)quest.h $(O)detect.o: $(NHS)detect.c $(HDEP) $(I)artifact.h $(O)dig.o: $(NHS)dig.c $(HDEP) $(I)edog.h $(O)display.o: $(NHS)display.c $(HDEP) $(O)dlb.o: $(NHS)dlb.c $(HDEP) $(I)dlb.h $(O)do.o: $(NHS)do.c $(HDEP) $(I)lev.h $(O)do_name.o: $(NHS)do_name.c $(HDEP) $(O)do_wear.o: $(NHS)do_wear.c $(HDEP) $(O)dog.o: $(NHS)dog.c $(HDEP) $(I)edog.h $(O)dogmove.o: $(NHS)dogmove.c $(HDEP) $(I)mfndpos.h $(I)edog.h $(O)dokick.o: $(NHS)dokick.c $(HDEP) $(I)eshk.h $(O)dothrow.o: $(NHS)dothrow.c $(HDEP) $(O)drawing.o: $(NHS)drawing.c $(HDEP) $(I)tcap.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)drawing.c $(O)dungeon.o: $(NHS)dungeon.c $(HDEP) $(I)dgn_file.h $(I)dlb.h $(O)eat.o: $(NHS)eat.c $(HDEP) $(O)end.o: $(NHS)end.c $(HDEP) $(I)eshk.h $(I)dlb.h $(O)engrave.o: $(NHS)engrave.c $(HDEP) $(I)lev.h $(O)exper.o: $(NHS)exper.c $(HDEP) $(O)explode.o: $(NHS)explode.c $(HDEP) $(O)extralev.o: $(NHS)extralev.c $(HDEP) $(O)files.o: $(NHS)files.c $(HDEP) $(I)dlb.h $(I)date.h $(O)fountain.o: $(NHS)fountain.c $(HDEP) $(O)hack.o: $(NHS)hack.c $(HDEP) $(O)hacklib.o: $(NHS)hacklib.c $(HDEP) $(O)invent.o: $(NHS)invent.c $(HDEP) $(I)artifact.h $(O)light.o: $(NHS)light.c $(HDEP) $(I)lev.h $(O)lock.o: $(NHS)lock.c $(HDEP) $(O)mail.o: $(NHS)mail.c $(HDEP) $(I)mail.h $(O)makemon.o: $(NHS)makemon.c $(HDEP) $(I)epri.h $(I)emin.h $(I)edog.h $(O)mapglyph.o: $(NHS)mapglyph.c $(HDEP) $(O)mcastu.o: $(NHS)mcastu.c $(HDEP) $(O)mhitm.o: $(NHS)mhitm.c $(HDEP) $(I)artifact.h $(I)edog.h $(O)mhitu.o: $(NHS)mhitu.c $(HDEP) $(I)artifact.h $(I)edog.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)mhitu.c $(O)minion.o: $(NHS)minion.c $(HDEP) $(I)emin.h $(I)epri.h $(O)mklev.o: $(NHS)mklev.c $(HDEP) $(O)mkmap.o: $(NHS)mkmap.c $(HDEP) $(I)sp_lev.h $(O)mkmaze.o: $(NHS)mkmaze.c $(HDEP) $(I)sp_lev.h $(I)lev.h $(O)mkobj.o: $(NHS)mkobj.c $(HDEP) $(I)artifact.h $(I)prop.h $(O)mkroom.o: $(NHS)mkroom.c $(HDEP) $(O)mon.o: $(NHS)mon.c $(HDEP) $(I)mfndpos.h $(I)edog.h $(O)mondata.o: $(NHS)mondata.c $(HDEP) $(I)eshk.h $(I)epri.h $(O)monmove.o: $(NHS)monmove.c $(HDEP) $(I)mfndpos.h $(I)artifact.h $(O)monst.o: $(NHS)monst.c $(I)config.h $(I)permonst.h $(I)monsym.h \ $(I)eshk.h $(I)vault.h $(I)epri.h $(I)color.h $(O)monstr.o: $(NHS)monstr.c $(HDEP) $(O)mplayer.o: $(NHS)mplayer.c $(HDEP) $(O)mthrowu.o: $(NHS)mthrowu.c $(HDEP) $(O)muse.o: $(NHS)muse.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)muse.c $(O)music.o: $(NHS)music.c $(HDEP) #interp.c $(O)o_init.o: $(NHS)o_init.c $(HDEP) $(I)lev.h $(O)objects.o: $(NHS)objects.c $(I)config.h $(I)obj.h $(I)objclass.h \ $(I)prop.h $(I)skills.h $(I)color.h $(CC) $(CFLAGS) $(INCLSPEC)$(NHS) $(OBJSPEC)$@ $(NHS)objects.c $(O)objnam.o: $(NHS)objnam.c $(HDEP) $(O)options.o: $(NHS)options.c $(HDEP) $(I)tcap.h $(I)config.h \ $(I)objclass.h $(I)flag.h $(O)pager.o: $(NHS)pager.c $(HDEP) $(I)dlb.h $(O)pickup.o: $(NHS)pickup.c $(HDEP) $(O)pline.o: $(NHS)pline.c $(HDEP) $(I)epri.h $(O)polyself.o: $(NHS)polyself.c $(HDEP) $(O)potion.o: $(NHS)potion.c $(HDEP) $(O)pray.o: $(NHS)pray.c $(HDEP) $(I)epri.h $(O)priest.o: $(NHS)priest.c $(HDEP) $(I)mfndpos.h $(I)eshk.h $(I)epri.h \ $(I)emin.h $(O)quest.o: $(NHS)quest.c $(HDEP) $(I)quest.h $(I)qtext.h $(O)questpgr.o: $(NHS)questpgr.c $(HDEP) $(I)qtext.h $(I)dlb.h $(O)read.o: $(NHS)read.c $(HDEP) $(O)rect.o: $(NHS)rect.c $(HDEP) $(O)region.o: $(NHS)region.c $(HDEP) $(O)restore.o: $(NHS)restore.c $(HDEP) $(I)lev.h $(I)tcap.h $(I)quest.h $(O)rnd.o: $(NHS)rnd.c $(HDEP) $(O)role.o: $(NHS)role.c $(HDEP) $(O)rumors.o: $(NHS)rumors.c $(HDEP) $(I)dlb.h $(O)save.o: $(NHS)save.c $(HDEP) $(I)lev.h $(I)quest.h $(O)shk.o: $(NHS)shk.c $(HDEP) $(I)eshk.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)shk.c $(O)shknam.o: $(NHS)shknam.c $(HDEP) $(I)eshk.h $(O)sit.o: $(NHS)sit.c $(HDEP) $(I)artifact.h $(O)sounds.o: $(NHS)sounds.c $(HDEP) $(I)edog.h $(O)sp_lev.o: $(NHS)sp_lev.c $(HDEP) $(I)sp_lev.h $(I)rect.h $(I)dlb.h $(O)spell.o: $(NHS)spell.c $(HDEP) $(O)steal.o: $(NHS)steal.c $(HDEP) $(O)steed.o: $(NHS)steed.c $(HDEP) $(O)teleport.o: $(NHS)teleport.c $(HDEP) $(O)timeout.o: $(NHS)timeout.c $(HDEP) $(I)lev.h $(O)topten.o: $(NHS)topten.c $(HDEP) $(I)dlb.h $(O)track.o: $(NHS)track.c $(HDEP) $(O)trap.o: $(NHS)trap.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)trap.c $(O)u_init.o: $(NHS)u_init.c $(HDEP) $(O)uhitm.o: $(NHS)uhitm.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)uhitm.c $(O)vault.o: $(NHS)vault.c $(HDEP) $(I)vault.h $(O)version.o: $(NHS)version.c $(HDEP) $(I)date.h $(I)patchlevel.h $(O)vision.o: $(NHS)vision.c $(HDEP) #$(I)vis_tab.h $(O)weapon.o: $(NHS)weapon.c $(HDEP) $(O)were.o: $(NHS)were.c $(HDEP) $(O)wield.o: $(NHS)wield.c $(HDEP) $(O)windows.o: $(NHS)windows.c $(HDEP) $(I)wintty.h $(O)wizard.o: $(NHS)wizard.c $(HDEP) $(I)qtext.h $(O)worm.o: $(NHS)worm.c $(HDEP) $(I)lev.h $(O)worn.o: $(NHS)worn.c $(HDEP) $(O)write.o: $(NHS)write.c $(HDEP) $(O)zap.o: $(NHS)zap.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)zap.c $(O)getline.o: $(TTY)getline.c $(HDEP) $(I)wintty.h $(O)termcap.o: $(TTY)termcap.c $(HDEP) $(I)wintty.h $(I)tcap.h $(O)topl.o: $(TTY)topl.c $(HDEP) $(I)wintty.h $(I)tcap.h $(O)wintty.o: $(TTY)wintty.c $(HDEP) $(I)wintty.h $(I)tcap.h \ $(I)patchlevel.h $(O)amitty.o: $(AMI)amitty.c $(HDEP) $(O)amistack.o: $(AMI)amistack.c $(CC) $(CFLAGS3) $(CSYM) $(OBJSPEC)$@ $(AMI)amistack.c $(O)rip.o: $(NHS)rip.c $(HDEP) $(I)config.h: $(I)config1.h $(I)tradstdc.h $(I)global.h -setdate $(I)config.h -c:wait 2 # onames.h handled at onames.h target, pm.h $(I)decl.h: $(I)quest.h $(I)spell.h $(I)color.h $(I)obj.h $(I)you.h -setdate $(I)decl.h -c:wait 2 $(I)global.h: $(I)coord.h $(I)pcconf.h $(I)amiconf.h -setdate $(I)global.h -c:wait 2 $(I)hack.h: $(I)config.h $(I)trap.h $(I)decl.h $(I)dungeon.h $(I)monsym.h \ $(I)mkroom.h $(I)objclass.h $(I)flag.h $(I)rm.h $(I)vision.h \ $(I)display.h $(I)wintype.h $(I)engrave.h $(I)rect.h \ $(I)region.h $(I)trampoli.h -setdate $(I)hack.h -c:wait 2 $(I)permonst.h: $(I)monattk.h $(I)monflag.h $(I)align.h -setdate $(I)permonst.h -c:wait 2 $(I)you.h: $(I)align.h $(I)attrib.h $(I)monst.h $(I)youprop.h $(I)skills.h -setdate $(I)you.h -c:wait 2 # pm.h handled at target $(I)youprop.h: $(I)prop.h $(I)permonst.h $(I)mondata.h -setdate $(I)youprop.h -c:wait 2 $(I)display.h: $(I)vision.h $(I)mondata.h -setdate $(I)display.h -c:wait 2 $(I)dungeon.h: $(I)align.h -setdate $(I)dungeon.h -c:wait 2 $(I)emin.h: $(I)dungeon.h -setdate $(I)emin.h -c:wait 2 $(I)epri.h: $(I)dungeon.h $(I)align.h -setdate $(I)epri.h -c:wait 2 $(I)eshk.h: $(I)dungeon.h -setdate $(I)eshk.h -c:wait 2 $(I)engrave.h: $(I)trampoli.h $(I)rect.h -setdate $(I)engrave.h -c:wait 2 $(I)mondata.h: $(I)align.h -setdate $(I)mondata.h -c:wait 2 $(I)monst.h: $(I)align.h -setdate $(I)monst.h -c:wait 2 $(I)pcconf.h: $(I)micro.h $(I)system.h -setdate $(I)pcconf.h -c:wait 2 $(I)rm.h: $(I)align.h -setdate $(I)rm.h -c:wait 2 $(I)vault.h: $(I)dungeon.h -setdate $(I)vault.h -c:wait 2 #notes # install keeps doing re-install because it keeps rebuilding lev_comp??? # fixed(?) - deleted setdate nethack-3.4.3/sys/amiga/Makefile.ami0100644000000000000000000013627207764735041015766 0ustar rootroot# NetHack Makefile. # SCCS Id: @(#)Makefile.ami 3.4 2002/21/02 # Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996. # NetHack may be freely redistributed. See license for details. ### ### INTRODUCTION ### # This makefile is arranged for compiling for the Amiga with SAS/C 6.51 but # can be configured for compiling with Manx C 5 or commercial DICE with # simple changes. The appropriate changes are identified by #[compiler] # where compiler is one of: SAS6, MANX, or DICE; the options in this # makefile as should be set according to the compiler being used. (But see # note 3 below.) # Note: When using the Manx compiler, an alternate make utility is # required. The bundled Aztec make is just too damaged. # Note 2: The #SFD_xxx lines are used with mkdmake to generate a DMake- # compatible makefile (DMakefile) from this file. Any line beginning with # #SFD_INSTEAD replaces, in DMakefile, the following line from Makefile.ami. # #SFD_BEGIN, #SFD_ELSE, and #SFD_END bracket multi-line sections for the two # makefile formats. # When changing this file, #SFD_INSTEAD lines will need to be inserted for # the following cases: # - Dependencies with different numbers of filenames (both > 1) on # either side. The #SFD_INSTEAD line should immediately precede # the line with the colon, and should contain a double colon "::" # instead of a single colon. # - Special command lists that override the default. A line containing # "#SFD_INSTEAD #none" should precede such a rule. If the rule is # more than one line long, precede it with "#SFD_BEGIN" and # "#SFD_ELSE", and follow it with "#SFD_END". # - Files not in the src, sys/amiga, sys/share, or win/tty directories # that rely on the default ".c.o" rule. Following the dependency # should be "#SFD_INSTEAD " with the filename inserted # into the default rule where appropriate, then a line contianing # "#none". # In any SFD_BEGIN/ELSE/END block added, put a '##' before every line # between the BEGIN and ELSE. Any line that's really a comment needs three # '#'s, e.g. "### DICE comment". # Note 2A: Whenever an SFD line/block is added, the appropriate repeat count # in mkdmake must be changed. (The repeat count "0" meaning "repeat # until end of file" doesn't work as advertised.) # Note 3: mkdmake will automatically substitute DICE flags, etc. for SAS # where appropriate. Since the makefile is already set up for SAS, # the only people who end up having to make changes here are Manx # users (or people who want to change the defaults). ### ### DIRECTORY STRUCTURE ### NH = NH: SBIN = $(NH)sbin/ SLIB = $(NH)slib/ NETHACK = $(NH)NetHack/ HACKEXE = $(NH)HackExe/ AMI = $(NH)sys/amiga/ DAT = $(NH)dat/ DOC = $(NH)doc/ I = $(NH)include/ SHARE = $(NH)sys/share/ NHS = $(NH)src/ TTY = $(NH)win/tty/ WSHARE = $(NH)win/share/ UTIL = $(NH)util/ O = $(NH)obj/ OO = $(NH)objo/ # NB: O and OO MUST be different directories ### ### INVOCATION ### #[SAS6] #MAKE = smake #[MANX] #MAKE = make #[DICE] #MAKE = dmake # Startup makefile with: # #[SAS6] #[MANX] # $(MAKE) -f $(AMI)Makefile.ami # $(MAKE) -f $(AMI)Makefile.ami install # #[DICE] # $(MAKE) -f $(AMI)DMakefile # $(MAKE) -f $(AMI)DMakefile install # # # You may use following targets on $(MAKE) command lines: # all do it all (default) # link just create binary from object files # obj just create common object files # obja just create amiga object files # objs just create shared object files # clean deletes the object files # spotless deletes the object files, main binary, and more # # Note: We do not build the Guidebook here since it needs tbl # (See the file sys/unix/Makefile.doc for more information) #X# Precompiled header files: #X# $(HDEP) should appear in any dependency list for an object file where #X# we would want to make use of the precompiled version of $(I)hack.h, #X# while $(CSYM) should appear in the C compiler command line that creates #X# any such object file. (Changes made here should agree with the $(HDEP): #X# target that appears later in this makefile.) #X# #SFD_BEGIN ## ###[DICE] ### If we were compiling with DICE and wanted to use the symbol table ### pre-loading feature, we would uncomment these following two lines. ## ##HDEP = $(I)hack.sym ##CSYM = -H$(I)hack.sym=hack.h ## #SFD_ELSE #[SAS5] # If we were to use the precompiled header file feature in a newer version # of SAS/C, we would comment out these following two lines. # If we don't use precompiled header files, we uncomment it as well. HDEP = $(I)hack.h $(I)pm.h $(I)onames.h CSYM = #[MANX] # If we were compiling with Aztec, and wanted to use the symbol table # pre-loading feature, we would uncomment these following two lines. #HDEP = Ram:hack.sym #CSYM = +IRam:hack.sym #SFD_END #Pathname for uudecode program: UUDEC = uudecode # Flex/Bison command assignments -- Useful only if you have flex/bison FLEX = flex BISON = bison # FBFIL and FBLIB may be used, if required by your version of flex or bison, # to specify additional files or libraries to be linked with FBFIL = FBLIB = #lib lib:compat.lib # If you're compiling this on a 1.3 system, you'll have to uncomment the # following (for use with the ifchange script below). Also useful instead of # "protect ifchange +s" EXECUTE = execute # Headers we depend on AMDEP = $(AMI)winproto.h $(AMI)winext.h $(AMI)windefs.h $(I)winami.h # Pathname for the C compiler being used. #SFD_BEGIN ## ###[DICE] ##CC = dcc ##ASM = das ## #SFD_ELSE #[SAS6] CC = sc ASM = asm #[MANX] #CC = cc #SFD_END # Compilation flags for selected C Compiler: # $(CFLAGS) should appear before filename arguments of $(CC) command line. #SFD_BEGIN ## ###[DICE] ##CFLAGS = -c -I$(I) -mC -mD -ms -// ##CFLAGS2 = ##WBCFLAGS = -c -I$(I) -mC -mD -ms -// ##WBC2FLAGS = -DCLI ##SPLFLAGS = -DSPLIT ## #SFD_ELSE #[SAS6] # Note: make sure your CLI stack size is large (at least 50K) or lev_comp # and makedefs may fail terribly - stack checking is disabled. # # **** WARNING **** GST support is not fool proof. You must make makedefs # without a GST first so that the generated headers # that are part of the GST can be made. # #GSTSRC=$(AMI)gst.c # #GSTHEAD=$(I)hack.h $(I)pm.h $(I)trap.h $(I)onames.h \ # $(AMI)winami.p $(AMI)amidos.p $(AMI)amiwind.p # #GSTFILE=$(O)NetHack.gst # undefine this to not compile with GSTs #GST=gst=$(GSTFILE) # DEBUG=debug=symbol CPU=cpu=68000 #OPTFLAGS=opt opttime optpeep optgo optinl optsched optcomp=10 optdep=5 optrdep=5 #optalias +OPTTIME -OPTSIZE CFLAGS = data=far nominc $(DEBUG) idir=$(I) $(CPU) nostkchk nover \ codename=nhcode dataname=nhdata strmerge $(OPTFLAGS) $(TILES) $(SAVEDS) \ afp $(ERRREXX) $(GST) # for files that are too large for the standard flags: CFLAGS2 = code=far strmerge $(SAVEDS) WBCFLAGS = ignore=217,62 data=far ansi nminc code=far idir=$(I) $(CPU) afp \ $(DEBUG) $(ERRREXX) define=AMIGA $(GST) XXX = data=far ansi nminc idir=$(I) $(CPU) afp opt optinline optinlocal \ optloop opttime WBC2FLAGS = define=CLI SPLFLAGS = define=SPLIT #dollarok #for amistack.c CFLAGS3 = data=near dataname=__MERGED nominc $(DEBUG) idir=$(I) $(CPU) nover nostkchk \ codename=nhcode strmerge $(OPTFLAGS) $(TILES) $(SAVEDS) \ afp $(ERRREXX) $(GST) #[MANX] #CFLAGS = -i$(I) -mc -md -ms -pa -ps -bs -wo -qq #WBCFLAGS = -mc -md -ms -pa -ps -bs -wo -qq -pp #SFD_END # Assembly flags: #SFD_BEGIN ## ###[DICE] ##AFLAGS = ##AOBJSPEC = -o ## #SFD_ELSE #[SAS6] AFLAGS = #what to put here? AOBJSPEC = -o #SFD_END # Components of various link command lines: # $(LINK) should be the pathname of the linker being used (with any options # that should appear at the beginning of the command line). The name of the # output file should appear immediately after $(LNSPEC). $(LIN) should # appear before the list of object files in each link command. $(LLINK) # should appear as the list of object files in the link command line that # creates the NetHack executable. $(LLIB) should appear at the end of each # link command line. # Note: amiga.lib added due to missing prototypes/pragmas. # Should be deleted when this is resolved. #SFD_BEGIN ## ###[DICE] ### If you have flex/bison libraries, use the second definition of FLLIB ### instead of the first. ## ##LINK = dcc -mD ##LIN = ##LLINK = @$(AMI)ami.lnk ##LLIB = ##FLLIB = ###FLLIB = -l$(FBLIB) ##OBJSPEC = -o ##PNSPEC = -o ##LNSPEC = -o ##CCLINK = dcc ##CLFLAGS = -I$(I) -mC -mD -ms -// ##INCLSPEC = -I ##DEFSPEC = -D ##IGNSPEC = -j ## #SFD_ELSE #[SAS6] LINK = slink noicons verbose maxhunk 262144 stripdebug LIN = from lib:catch.o LLINK = with $(AMI)ami.lnk LLIB = lib lib:scnb.lib BATCH #lib lib:amiga.lib BATCH #scnb.lib or sc.lib FLLIB = $(FBLIB) lib Lib:sc.lib BATCH OBJSPEC = objname= PNSPEC = noicons to #pname= LNSPEC = to CCLINK = sc link INCLSPEC = idir= DEFSPEC = define= IGNSPEC = ignore= COMPACT_HEADERS=$(GSTFILE) #[MANX] #LINK = ln -g +q +ss -o #LIN = #LLINK = -f $(AMI)ami.lnk #LLIB = -lcl16 #FLLIB = -lcl16 #OBJSPEC = -o #PNSPEC = -o #LNSPEC = -o #CCLINK = cc #INCLSPEC = -i #DEFSPEC = -d #IGNSPEC = -j #SFD_END ### ### FILE LISTS ### # A more reasonable random number generator (recommended for the Amiga): RANDOBJ = $(O)random.o #SFD_INSTEAD #none .PRECIOUS: $(I)config.h $(I)decl.h $(I)hack.h $(I)permonst.h $(I)you.h # Almost nothing below this line should have to be changed. # (Exceptions are marked by [SAS6], [MANX], etc.) # # Other things that have to be reconfigured are in config.h, # (amiconf.h, pcconf.h), and possibly system.h, tradstdc.h. # Object files for makedefs: MAKEOBJS = \ $(OO)makedefs.o $(O)monst.o $(O)objects.o # Object files for special levels compiler: SPLEVOBJS = \ $(OO)lev_yacc.o $(OO)lev_lex.o $(OO)lev_main.o \ $(O)decl.o $(O)drawing.o $(O)monst.o \ $(O)objects.o $(OO)panic.o # Object files for dungeon compiler DGNCOMPOBJS = \ $(OO)dgn_yacc.o $(OO)dgn_lex.o $(OO)dgn_main.o $(O)alloc.o $(OO)panic.o # Object files for NetHack: COMMOBJ = \ $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o \ $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o \ $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o \ $(O)dig.o $(O)display.o $(O)dlb.o $(O)do.o \ $(O)do_name.o $(O)do_wear.o $(O)dog.o $(O)dogmove.o \ $(O)dokick.o $(O)dothrow.o $(O)drawing.o $(O)dungeon.o \ $(O)eat.o $(O)end.o $(O)engrave.o $(O)exper.o \ $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o \ $(O)hack.o $(O)hacklib.o $(O)invent.o $(O)light.o \ $(O)lock.o $(O)mail.o $(O)makemon.o $(O)mapglyph.o \ $(O)mcastu.o $(O)mhitm.o $(O)mhitu.o $(O)minion.o \ $(O)mklev.o $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o \ $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o \ $(O)monst.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o \ $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o \ $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o \ $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o \ $(O)quest.o $(O)questpgr.o $(O)read.o $(O)rect.o \ $(O)region.o $(O)restore.o $(O)rnd.o $(O)role.o \ $(O)rumors.o $(O)save.o $(O)shk.o $(O)shknam.o \ $(O)sit.o $(O)sounds.o $(O)sp_lev.o $(O)spell.o \ $(O)steal.o $(O)steed.o $(O)teleport.o $(O)timeout.o \ $(O)topten.o $(O)track.o $(O)trap.o $(O)u_init.o \ $(O)uhitm.o $(O)vault.o $(O)version.o $(O)vision.o \ $(O)weapon.o $(O)were.o $(O)wield.o $(O)windows.o \ $(O)wizard.o $(O)worm.o $(O)worn.o $(O)write.o \ $(O)zap.o MAKEDEFOBJ = \ $(O)monstr.o AMIGAOBJ = \ $(O)amidos.o $(O)amirip.o $(O)amisnd.o $(O)amistack.o \ $(O)amiwind.o $(O)winami.o $(O)winchar.o $(O)winfuncs.o \ $(O)winkey.o $(O)winmenu.o $(O)winreq.o $(O)winstr.o # Objects from assembly sources (because DMake can't handle default rules) AMIGAOBJ2 = \ # $(O)dispmap.o SHAREOBJ = \ $(O)pcmain.o $(RANDOBJ) TTYOBJ = \ $(O)getline.o $(O)termcap.o $(O)topl.o $(O)wintty.o $(O)amitty.o \ $(O)rip.o # Yuck yuck yuck. Have to tell DMake where these are, since they're not # all in the same place. TTYSRC = \ $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \ $(AMI)amitty.c $(NHS)rip.c # All the object files for NetHack: HOBJ = $(COMMOBJ) $(AMIGAOBJ) $(AMIGAOBJ2) $(SHAREOBJ) $(MAKEDEFOBJ) $(TTYOBJ) ### ### DATA FILES ### # quest files ADFILES1= $(SLIB)Arc-fila.lev $(SLIB)Arc-filb.lev $(SLIB)Arc-loca.lev \ $(SLIB)Arc-strt.lev ADFILES= $(SLIB)Arc-goal.lev $(ADFILES1) BDFILES1= $(SLIB)Bar-fila.lev $(SLIB)Bar-filb.lev $(SLIB)Bar-loca.lev \ $(SLIB)Bar-strt.lev BDFILES= $(SLIB)Bar-goal.lev $(BDFILES1) CDFILES1= $(SLIB)Cav-fila.lev $(SLIB)Cav-filb.lev $(SLIB)Cav-loca.lev \ $(SLIB)Cav-strt.lev CDFILES= $(SLIB)Cav-goal.lev $(CDFILES1) HDFILES1= $(SLIB)Hea-fila.lev $(SLIB)Hea-filb.lev $(SLIB)Hea-loca.lev \ $(SLIB)Hea-strt.lev HDFILES= $(SLIB)Hea-goal.lev $(HDFILES1) KDFILES1= $(SLIB)Kni-fila.lev $(SLIB)Kni-filb.lev $(SLIB)Kni-loca.lev \ $(SLIB)Kni-strt.lev KDFILES= $(SLIB)Kni-goal.lev $(KDFILES1) MDFILES1= $(SLIB)Mon-fila.lev $(SLIB)Mon-filb.lev $(SLIB)Mon-loca.lev \ $(SLIB)Mon-strt.lev MDFILES= $(SLIB)Mon-goal.lev $(MDFILES1) PDFILES1= $(SLIB)Pri-fila.lev $(SLIB)Pri-filb.lev $(SLIB)Pri-loca.lev \ $(SLIB)Pri-strt.lev PDFILES= $(SLIB)Pri-goal.lev $(PDFILES1) RDFILES1= $(SLIB)Rog-fila.lev $(SLIB)Rog-filb.lev $(SLIB)Rog-loca.lev \ $(SLIB)Rog-strt.lev RDFILES= $(SLIB)Rog-goal.lev $(RDFILES1) RANFILES1= $(SLIB)Ran-fila.lev $(SLIB)Ran-filb.lev $(SLIB)Ran-loca.lev \ $(SLIB)Ran-strt.lev RANFILES= $(SLIB)Ran-goal.lev $(RANFILES1) SDFILES1= $(SLIB)Sam-fila.lev $(SLIB)Sam-filb.lev $(SLIB)Sam-loca.lev \ $(SLIB)Sam-strt.lev SDFILES= $(SLIB)Sam-goal.lev $(SDFILES1) TDFILES1= $(SLIB)Tou-fila.lev $(SLIB)Tou-filb.lev $(SLIB)Tou-loca.lev \ $(SLIB)Tou-strt.lev TDFILES= $(SLIB)Tou-goal.lev $(TDFILES1) VDFILES1= $(SLIB)Val-fila.lev $(SLIB)Val-filb.lev $(SLIB)Val-loca.lev \ $(SLIB)Val-strt.lev VDFILES= $(SLIB)Val-goal.lev $(VDFILES1) WDFILES1= $(SLIB)Wiz-fila.lev $(SLIB)Wiz-filb.lev $(SLIB)Wiz-loca.lev \ $(SLIB)Wiz-strt.lev WDFILES= $(SLIB)Wiz-goal.lev $(WDFILES1) XDFILES= $(ADFILES) $(BDFILES) $(CDFILES) $(HDFILES) $(KDFILES) \ $(MDFILES) $(PDFILES) $(RDFILES) $(RANFILES) $(SDFILES) $(TDFILES) \ $(VDFILES) $(WDFILES) SOUNDFILES= \ $(SBIN)cvtsnd \ $(SLIB)sounds \ $(SLIB)sounds/Bell $(SLIB)sounds/Bugle \ $(SLIB)sounds/Drum_Of_Earthquake \ $(SLIB)sounds/Fire_Horn $(SLIB)sounds/Frost_Horn \ $(SLIB)sounds/Leather_Drum $(SLIB)sounds/Magic_Flute \ $(SLIB)sounds/Magic_Harp $(SLIB)sounds/Tooled_Horn \ $(SLIB)sounds/Wooden_Flute $(SLIB)sounds/Wooden_Harp TILEFILES= \ $(SBIN)txt2iff \ $(NETHACK)tiles \ $(NETHACK)tiles/objects.iff \ $(NETHACK)tiles/monsters.iff \ $(NETHACK)tiles/other.iff INSTDUNGEONFILES1= \ $(SLIB)air.lev $(SLIB)asmodeus.lev $(SLIB)astral.lev \ $(SLIB)baalz.lev $(SLIB)bigrm-1.lev $(SLIB)bigrm-2.lev \ $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev \ $(SLIB)castle.lev $(SLIB)dungeon $(SLIB)earth.lev \ $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev $(SLIB)fire.lev \ $(SLIB)juiblex.lev $(SLIB)knox.lev $(SLIB)medusa-1.lev \ $(SLIB)medusa-2.lev $(SLIB)minend-1.lev $(SLIB)minend-2.lev \ $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev $(SLIB)minefill.lev \ $(SLIB)options $(SLIB)oracle.lev $(SLIB)orcus.lev \ $(SLIB)sanctum.lev $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev \ $(SLIB)soko2-1.lev $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev \ $(SLIB)soko3-2.lev $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev \ $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev \ $(SLIB)valley.lev $(SLIB)water.lev $(SLIB)wizard1.lev \ $(SLIB)wizard2.lev $(SLIB)wizard3.lev \ $(XDFILES) INSTDUNGEONFILES= $(NETHACK)NetHack.cnf $(INSTDUNGEONFILES1) INSTDATAFILES= \ $(NETHACK)license $(NETHACK)logfile $(NETHACK)record \ $(NETHACK)tomb.iff $(NETHACK)amii.hlp $(NETHACK)Recover.txt \ $(NETHACK)GuideBook.txt $(NETHACK)NetHack.txt $(NETHACK)Install.ami LIBFILES= \ $(INSTDUNGEONFILES1) \ $(SLIB)cmdhelp $(SLIB)data $(SLIB)dungeon \ $(SLIB)help $(SLIB)hh $(SLIB)history \ $(SLIB)opthelp $(SLIB)oracles $(SLIB)rumors \ $(SLIB)quest.dat $(SLIB)wizhelp ### ### Getting down to business: ### #SFD_INSTEAD all: $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \ all: $(COMPACT_HEADERS) $(SBIN)lev_comp $(SBIN)dgn_comp $(SBIN)NetHack \ $(SBIN)dlb $(NETHACK)recover install: all inst-data inst-dungeon inst-fonts inst-sounds inst-tiles \ $(NETHACK)nhdat $(NETHACK)NetHack $(SBIN)NetHack: $(HOBJ) $(AMI)ami.lnk $(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLINK) $(LLIB) $(NETHACK)NetHack: $(SBIN)NetHack copy $(SBIN)NetHack $(NETHACK)NetHack link: $(LINK) $(LNSPEC) $(SBIN)NetHack $(LIN) $(LLINK) $(LLIB) $(AMI)ami.lnk: $(AMI)Makefile.ami list to $(AMI)ami.lnk lformat="$(O)%s" $(O)\#?.o QUICK NOHEAD ## dlb support $(OO)dlb_main.o: $(UTIL)dlb_main.c $(HDEP) $(I)dlb.h $(I)date.h $(CC) $(CFLAGS) $(OBJSPEC)$(OO)dlb_main.o $(UTIL)dlb_main.c $(SBIN)dlb: $(OO)dlb_main.o $(O)dlb.o $(O)alloc.o $(OO)panic.o $(LINK) $(PNSPEC) $(SBIN)dlb $(LIN) $(OO)dlb_main.o $(O)dlb.o \ $(O)alloc.o $(OO)panic.o $(LLIB) obj: $(HOBJ) obja: $(AMIGAOBJ) objs: $(SHAREOBJ) #SFD_BEGIN #SFD_ELSE SUFFIXES = .lev .des .des.lev: $(SBIN)lev_comp $< #SFD_END # The default method for creating object files: #SFD_BEGIN ## ###[DICE] ## ##$(COMMOBJ): $(COMMOBJ:"$(O)*.o":"$(NHS)%1.c") ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right) ## ##$(AMIGAOBJ): $(AMIGAOBJ:"$(O)*.o":"$(AMI)%1.c") ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right) ## ##$(SHAREOBJ): $(SHAREOBJ:"$(O)*.o":"$(SHARE)%1.c") ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right) ## ##$(TTYOBJ): $(TTYSRC) ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)%(left) %(right) ## #SFD_ELSE #[SAS6] .c.o: $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)$@ $< #SFD_END clean: -delete $(O)\#?.o $(OO)\#?.o spotless: clean -delete $(SBIN)NetHack $(SBIN)lev_comp $(SBIN)makedefs $(SBIN)dgn_comp -delete $(SBIN)cvtsnd $(SBIN)dlb $(SBIN)txt2iff $(SBIN)splitter -delete $(SBIN)tilemap -delete $(SLIB)data $(SLIB)rumors -delete $(SLIB)\#?.lev -delete $(SLIB)dungeon -delete $(SLIB)cmdhelp $(SLIB)help $(SLIB)hh $(SLIB)history -delete $(SLIB)opthelp $(SLIB)options $(SLIB)oracles -delete $(SLIB)quest.dat $(SLIB)wizhelp # -delete $(SLIB)earth.lev $(SLIB)air.lev $(SLIB)fire.lev # -delete $(SLIB)water.lev $(SLIB)astral.lev # -delete $(SLIB)tower1.lev $(SLIB)tower2.lev $(SLIB)tower3.lev # -delete $(SLIB)fakewiz1.lev $(SLIB)fakewiz2.lev # -delete $(SLIB)medusa-1.lev $(SLIB)medusa-2.lev # -delete $(SLIB)oracle.lev $(SLIB)wizard1.lev $(SLIB)wizard2.lev # -delete $(SLIB)wizard3.lev $(DAT)dungeon.pdf $(SLIB)valley.lev # -delete $(SLIB)minefill.lev # -delete $(SLIB)minetn-1 $(SLIB)minetn-2 $(SLIB)minend-1 $(SLIB)minend-2 # -delete $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev # -delete $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev # -delete $(SLIB)soko4-1.lev $(SLIB)soko4-2.lev # -delete $(ADFILES) # -delete $(BDFILES) # -delete $(CDFILES) # -delete $(HDFILES) # -delete $(KDFILES) # -delete $(MDFILES) # -delete $(PDFILES) # -delete $(RDFILES) # -delete $(RANFILES) # -delete $(SDFILES) # -delete $(TDFILES) # -delete $(VDFILES) # -delete $(WDFILES) -delete $(I)onames.h $(I)pm.h $(I)date.h -delete $(NHS)tile.c $(NHS)monstr.c -delete $(I)tile.h # -echo to $(I)onames.h "" noline # -wait 2 # -echo to $(I)pm.h "" noline # -wait 2 # -setdate $(UTIL)makedefs.c # -wait 2 # Creating precompiled version of $(I)hack.h to save disk I/O. #SFD_BEGIN ## ###[DICE] ### If we were compiling with DICE and wanted to use the symbol table ### pre-loading feature, we would technically not need a rule to make the ### precompiled header file, because DCC handles this automatically; ### however, we must delete the precompiled header file if any of the ### includes change, and we need to create it manually because the ### sys/amiga sources, compiled first, define things differently than the ### main sources want them. ## ##$(HDEP): $(I)hack.h $(I)pm.h $(I)onames.h ## -delete $(I)hack.sym ## echo to Ram:hackincl.c "#include " ## $(CC) $(CFLAGS) $(CSYM) $(OBJSPEC)Ram:hackincl.o Ram:hackincl.c ## -delete Ram:hackincl.c Ram:hackincl.o ## #SFD_ELSE #X#[SAS5] #X# If we were to use the precompiled header file feature of SAS/C, we #X# would uncomment the following lines. (Also see defines for HDEP and #X# CSYM near the beginning of this file, as these should be appropriately #X# defined.) #X#$(HDEP): $(I)hack.h $(SBIN)makedefs #X# echo to Ram:hackincl.c "#include <$(I)hack.h>" #X# $(CC) $(CFLAGS) -ph $(OBJSPEC)$@ Ram:hackincl.c #X# -delete Ram:hackincl.c #[MANX] # If we were compiling with Aztec, and wanted to use the symbol table # pre-loading feature, we would uncomment these following two lines. #$(HDEP): $(I)hack.h $(SBIN)makedefs # $(CC) $(CFLAGS) -a $(OBJSPEC)Ram:hack.asm +h$@ $(I)hack.h # -delete Ram:hack.asm #SFD_END # # Please note: The dependency lines for the modules here are # deliberately incorrect. Including "hack.h" in # the dependency list would cause a dependency # loop. # $(SBIN)makedefs: $(MAKEOBJS) $(LINK) $(LNSPEC) $(SBIN)makedefs $(LIN) $(MAKEOBJS) $(LLIB) $(OO)makedefs.o: $(UTIL)makedefs.c $(I)config.h $(I)permonst.h $(I)monsym.h \ $(I)objclass.h $(I)patchlevel.h $(I)qtext.h $(I)artilist.h $(CC) $(DEFSPEC)MAKEDEFS_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)makedefs.c $(SBIN)lev_comp: $(SPLEVOBJS) $(LINK) $(LNSPEC) $(SBIN)lev_comp $(LIN) $(SPLEVOBJS) $(FBFIL) $(FLLIB) $(SBIN)dgn_comp: $(DGNCOMPOBJS) $(LINK) $(LNSPEC) $(SBIN)dgn_comp $(LIN) $(DGNCOMPOBJS) $(FBFIL) $(FLLIB) $(OO)lev_yacc.o: $(UTIL)lev_yacc.c $(HDEP) $(I)sp_lev.h $(I)pm.h $(I)onames.h # setdate $(UTIL)lev_yacc.c $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)PREFIX="NH:slib/" $(CFLAGS) \ $(DEFSPEC)alloca=malloc $(OBJSPEC)$@ $(UTIL)lev_yacc.c $(OO)lev_lex.o: $(UTIL)lev_lex.c $(HDEP) $(I)lev_comp.h $(I)sp_lev.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)lev_lex.c $(OO)lev_main.o: $(UTIL)lev_main.c $(HDEP) $(I)pm.h $(I)onames.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)lev_main.c $(OO)dgn_yacc.o: $(UTIL)dgn_yacc.c $(HDEP) $(I)dgn_file.h $(I)patchlevel.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(DEFSPEC)alloca=malloc \ $(OBJSPEC)$@ $(UTIL)dgn_yacc.c $(OO)dgn_lex.o: $(UTIL)dgn_lex.c $(I)config.h $(I)dgn_comp.h $(I)dgn_file.h $(CC) $(DEFSPEC)LEV_LEX_C $(CFLAGS) $(OBJSPEC)$@ $(UTIL)dgn_lex.c $(OO)dgn_main.o: $(UTIL)dgn_main.c $(I)config.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)dgn_main.c $(OO)panic.o: $(UTIL)panic.c $(HDEP) #SFD_INSTEAD $(CC) $(CFLAGS) $(OBJSPEC)%(left) $(UTIL)panic.c #none $(OO)recover.o: $(UTIL)recover.c $(I)config.h $(I)date.h $(CC) $(DEFSPEC)LEV_LEX_C $(DEFSPEC)AMIGA $(CFLAGS) $(OBJSPEC)$@ \ $(UTIL)recover.c $(NETHACK)recover: $(OO)recover.o $(LINK) $(LNSPEC) $(NETHACK)recover $(LIN) $(OO)recover.o $(LLIB) # [OPTION] -- If you have flex/bison, leave these uncommented. Otherwise, # comment them out and be careful! (You're not guaranteed to have the most # up to date *_comp.c, *_comp.h and *_lex.c) $(I)lev_comp.h: $(UTIL)lev_yacc.c $(I)patchlevel.h $(UTIL)lev_yacc.c: $(UTIL)lev_comp.y $(I)patchlevel.h $(BISON) -d $(UTIL)lev_comp.y # copy y.tab.c $(UTIL)lev_yacc.c # copy y.tab.h $(I)lev_comp.h copy $(UTIL)lev_comp.tab.c $(UTIL)lev_yacc.c copy $(UTIL)lev_comp.tab.h $(I)lev_comp.h # delete y.tab.c # delete y.tab.h delete $(UTIL)lev_comp.tab.c delete $(UTIL)lev_comp.tab.h $(UTIL)lev_lex.c: $(UTIL)lev_comp.l $(I)patchlevel.h $(FLEX) $(UTIL)lev_comp.l copy lex.yy.c $(UTIL)lev_lex.c delete lex.yy.c $(I)dgn_comp.h: $(UTIL)dgn_yacc.c $(I)patchlevel.h $(UTIL)dgn_yacc.c: $(UTIL)dgn_comp.y $(I)patchlevel.h $(BISON) -d $(UTIL)dgn_comp.y # copy y.tab.c $(UTIL)dgn_yacc.c # copy y.tab.h $(I)dgn_comp.h copy $(UTIL)dgn_comp.tab.c $(UTIL)dgn_yacc.c copy $(UTIL)dgn_comp.tab.h $(I)dgn_comp.h # delete y.tab.c # delete y.tab.h delete $(UTIL)dgn_comp.tab.c delete $(UTIL)dgn_comp.tab.h $(UTIL)dgn_lex.c: $(UTIL)dgn_comp.l $(I)patchlevel.h $(FLEX) $(UTIL)dgn_comp.l copy lex.yy.c $(UTIL)dgn_lex.c delete lex.yy.c # # The following include files depend on makedefs to be created. # As a result, they are not defined in HACKINCL, instead, their # dependencies are explicitly outlined here. # # # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. # #SFD_INSTEAD $(I)date.h $(DAT)options:: $(HDEP) $(SBIN)makedefs $(AMIGAOBJ) $(I)date.h $(DAT)options: $(HDEP) $(SBIN)makedefs $(AMIGAOBJ) $(I)patchlevel.h $(SBIN)makedefs -v $(EXECUTE) $(AMI)ifchange MOVE $(I)t.date.h $(I)date.h -wait 2 $(I)onames.h: $(SBIN)makedefs $(SBIN)makedefs -o $(EXECUTE) $(AMI)ifchange TOUCH $(I)t.onames.h $(I)onames.h $(I)decl.h $(EXECUTE) $(AMI)ifchange MOVE $(I)t.onames.h $(I)onames.h -wait 2 $(I)pm.h: $(SBIN)makedefs $(SBIN)makedefs -p $(EXECUTE) $(AMI)ifchange TOUCH $(I)t.pm.h $(I)pm.h $(I)decl.h $(I)youprop.h $(EXECUTE) $(AMI)ifchange MOVE $(I)t.pm.h $(I)pm.h -wait 2 $(SLIB)quest.dat: $(DAT)quest.txt $(SBIN)makedefs $(SBIN)makedefs -q $(NHS)monstr.c: $(HDEP) $(SBIN)makedefs $(SBIN)makedefs -m -wait 2 $(SLIB)oracles: $(DAT)oracles.txt $(SBIN)makedefs $(SBIN)makedefs -h -wait 2 # # The following programs vary depending on what OS you are using. # As a result, they are not defined in HACKSRC and their dependencies # are explicitly outlined here. # $(O)amidos.o: $(AMI)amidos.c $(HDEP) $(O)amirip.o: $(AMI)amirip.c $(HDEP) $(O)aglue.o: $(AMI)aglue.a $(ASM) $(AFLAGS) $(AOBJSPEC)$(O)aglue.o $(AMI)aglue.a $(O)amisnd.o: $(AMI)amisnd.c $(HDEP) $(O)winchar.o: $(AMI)winchar.c $(NHS)tile.c $(HDEP) $(NHS)tile.c: $(WSHARE)tilemap.c #SFD_INSTEAD $(CCLINK) $(CLFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c $(CCLINK) $(CFLAGS) $(PNSPEC) $(SBIN)tilemap $(WSHARE)tilemap.c $(SBIN)tilemap $(O)winstr.o: $(AMI)winstr.c $(HDEP) $(AMDEP) $(O)winreq.o: $(AMI)winreq.c $(HDEP) $(AMDEP) $(AMI)colorwin.c $(AMI)clipwin.c $(O)winfuncs.o: $(AMI)winfuncs.c $(HDEP) $(AMDEP) $(I)patchlevel.h $(O)winkey.o: $(AMI)winkey.c $(HDEP) $(AMDEP) $(O)winmenu.o: $(AMI)winmenu.c $(HDEP) $(AMDEP) $(O)winami.o: $(AMI)winami.c $(HDEP) $(AMDEP) #$(AMI)char.c $(AMI)randwin.c #$(O)amilib.o: $(AMI)amilib.c $(HDEP) $(AMDEP) $(O)amiwind.o: $(AMI)amiwind.c $(AMI)amimenu.c $(HDEP) $(AMDEP) $(O)amiwbench.o: $(AMI)amiwbench.c $(HDEP) $(O)random.o: $(SHARE)random.c $(O)pcmain.o: $(SHARE)pcmain.c $(HDEP) $(I)dlb.h $(O)dispmap.o: $(AMI)dispmap.s $(ASM) $(AFLAGS) $(AOBJSPEC)$@ $< # Stuff to build the front ends $(NETHACK)HackWB: $(OO)wb.o $(OO)wbx.o $(OO)loader.o $(OO)multi.o $(LINK) $(LNSPEC) $(NETHACK)HackWB $(LIN) $(OO)wb.o $(OO)wbx.o \ $(OO)loader.o $(OO)multi.o $(LLIB) $(NETHACK)HackCli: $(OO)cli.o $(OO)loader.o $(OO)multi.o $(LINK) $(LNSPEC) $(NETHACK)HackCli $(LIN) $(OO)cli.o $(OO)loader.o \ $(OO)multi.o $(LLIB) # This needs to exist to eliminate the HackWB startup message #SFD_INSTEAD $(NETHACK)WBDefaults.def: $(NETHACK)WBDefaults.def $(NETHACK)WBDefaults.def: echo to $(NETHACK)WBDefaults.def WBH = $(AMI)wbdefs.h $(AMI)wbstruct.h $(AMI)wbprotos.h ASP = $(AMI)splitter $(OO)wb.o: $(WBH) $(AMI)wb.c $(AMI)wbwin.c $(AMI)wbdata.c $(AMI)wbgads.c \ $(I)patchlevel.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wb.o $(AMI)wb.c $(OO)wbx.o: $(WBH) $(AMI)wbcli.c $(AMI)wbwin.c $(AMI)wbdata.c \ $(I)patchlevel.h $(I)date.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)wbx.o $(AMI)wbcli.c $(OO)loader.o: $(ASP)/loader.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/multi.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)loader.o $(ASP)/loader.c $(OO)multi.o: $(ASP)/multi.c $(ASP)/multi.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)multi.o $(ASP)/multi.c $(OO)cli.o: $(WBH) $(AMI)wbcli.c $(I)patchlevel.h $(I)date.h $(CC) $(WBCFLAGS) $(WBC2FLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)cli.o \ $(AMI)wbcli.c #### # splitter support $(SBIN)splitter: $(OO)splitter.o $(OO)arg.o $(LINK) $(LNSPEC) $(SBIN)splitter $(LIN) $(OO)splitter.o $(OO)arg.o \ $(LLIB) $(NETHACK)NetHack.dir: $(SBIN)splitter $(SBIN)NetHack $(SBIN)splitter $(SBIN)NetHack $(OO)splitter.o: $(ASP)/splitter.c $(ASP)/split.h $(ASP)/amiout.h $(ASP)/arg.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)splitter.o \ $(ASP)/splitter.c $(OO)arg.o: $(ASP)/arg.c $(ASP)/arg.h $(CC) $(WBCFLAGS) $(SPLFLAGS) $(OBJSPEC)$(OO)arg.o $(ASP)/arg.c # Create/copy other stuff into NetHack: directory: $(NETHACK)tomb.iff: $(SBIN)xpm2iff $(AMI)grave16.xpm $(SBIN)xpm2iff $(AMI)grave16.xpm $(NETHACK)tomb.iff $(OO)xpm2iff.o: $(AMI)xpm2iff.c $(CC) $(CFLAGS) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(AMI)xpm2iff.c $(SBIN)xpm2iff: $(OO)xpm2iff.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)xpm2iff.o $(FLLIB) # Tile installation for the tile version of the game inst-tiles: $(TILEFILES) #SFD_INSTEAD $(NETHACK)tiles: $(NETHACK)tiles $(NETHACK)tiles: -makedir $(NETHACK)tiles $(OO)txt2iff.o: $(AMI)txt2iff.c $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ \ $(AMI)txt2iff.c $(OO)ppmwrite.o: $(WSHARE)ppmwrite.c $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)ppmwrite.c $(OO)tiletext.o: $(WSHARE)tiletext.c $(I)config.h $(WSHARE)tile.h $(CC) $(CFLAGS) $(CSYM) $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tiletext.c $(OO)tiletxt.o: $(WSHARE)tilemap.c $(I)hack.h $(CC) $(CFLAGS) $(CSYM) $(DEFSPEC)TILETEXT $(INCLSPEC)$(WSHARE) $(OBJSPEC)$@ $(WSHARE)tilemap.c NAMEOBJS = $(O)drawing.o $(O)decl.o $(O)monst.o $(O)objects.o $(SBIN)txt2ppm: $(OO)ppmwrite.o $(NAMEOBJS) $(O)alloc.o $(OO)panic.o $(OO)tiletext.o $(OO)tiletxt.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)ppmwrite.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(O)alloc.o $(OO)panic.o $(FLLIB) $(SBIN)txt2iff: $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o $(OO)tiletxt.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)txt2iff.o $(NAMEOBJS) $(OO)tiletext.o \ $(OO)tiletxt.o $(FLLIB) $(NETHACK)tiles/objects.iff: $(WSHARE)objects.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)objects.txt $(NETHACK)tiles/objects.iff $(NETHACK)tiles/monsters.iff: $(WSHARE)monsters.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)monsters.txt $(NETHACK)tiles/monsters.iff $(NETHACK)tiles/other.iff: $(WSHARE)other.txt $(SBIN)txt2iff $(SBIN)txt2iff $(WSHARE)other.txt $(NETHACK)tiles/other.iff # Sound installation rules. inst-sounds: $(SOUNDFILES) list to T:nhsdat.lst $(SLIB)sounds QUICK NOHEAD echo >T:make-nhsdat $(SBIN)dlb cCfI $(SLIB)sounds $(NETHACK)nhsdat T:nhsdat.lst echo >>T:make-nhsdat if not exists $(NETHACK)nhsdat echo >>T:make-nhsdat copy $(SLIB)sounds/\#? $(NETHACK)sounds echo >>T:make-nhsdat endif execute T:make-nhsdat -delete T:make-nhsdat #SFD_INSTEAD $(SLIB)sounds: $(SLIB)sounds $(SLIB)sounds: -makedir $(SLIB)sounds $(SBIN)cvtsnd: $(OO)cvtsnd.o $(LINK) $(LNSPEC) $@ $(LIN) $(OO)cvtsnd.o $(FLLIB) $(OO)cvtsnd.o: $(AMI)cvtsnd.c #SFD_INSTEAD $(CC) $(CFLAGS) $(OBJSPEC)%(left) %(right) #none $(SLIB)sounds/Bell: $(SHARE)sounds/bell.uu $(UUDEC) $(SHARE)sounds/bell.uu $(SBIN)cvtsnd Bell $(SLIB)sounds/Bell -delete Bell $(SLIB)sounds/Bugle: $(SHARE)sounds/bugle.uu $(UUDEC) $(SHARE)sounds/bugle.uu $(SBIN)cvtsnd Bugle $(SLIB)sounds/Bugle -delete Bugle $(SLIB)sounds/Drum_Of_Earthquake: $(SHARE)sounds/erthdrum.uu $(UUDEC) $(SHARE)sounds/erthdrum.uu $(SBIN)cvtsnd Drum_Of_Earthquake $(SLIB)sounds/Drum_Of_Earthquake -delete Drum_Of_Earthquake $(SLIB)sounds/Fire_Horn: $(SHARE)sounds/firehorn.uu $(UUDEC) $(SHARE)sounds/firehorn.uu $(SBIN)cvtsnd Fire_Horn $(SLIB)sounds/Fire_Horn -delete Fire_Horn $(SLIB)sounds/Frost_Horn: $(SHARE)sounds/frsthorn.uu $(UUDEC) $(SHARE)sounds/frsthorn.uu $(SBIN)cvtsnd Frost_Horn $(SLIB)sounds/Frost_Horn -delete Frost_Horn $(SLIB)sounds/Leather_Drum: $(SHARE)sounds/lethdrum.uu $(UUDEC) $(SHARE)sounds/lethdrum.uu $(SBIN)cvtsnd Leather_Drum $(SLIB)sounds/Leather_Drum -delete Leather_Drum $(SLIB)sounds/Magic_Flute: $(SHARE)sounds/mgcflute.uu $(UUDEC) $(SHARE)sounds/mgcflute.uu $(SBIN)cvtsnd Magic_Flute $(SLIB)sounds/Magic_Flute -delete Magic_Flute $(SLIB)sounds/Magic_Harp: $(SHARE)sounds/mgcharp.uu $(UUDEC) $(SHARE)sounds/mgcharp.uu $(SBIN)cvtsnd Magic_Harp $(SLIB)sounds/Magic_Harp -delete Magic_Harp $(SLIB)sounds/Tooled_Horn: $(SHARE)sounds/toolhorn.uu $(UUDEC) $(SHARE)sounds/toolhorn.uu $(SBIN)cvtsnd Tooled_Horn $(SLIB)sounds/Tooled_Horn -delete Tooled_Horn $(SLIB)sounds/Wooden_Flute: $(SHARE)sounds/wdnflute.uu $(UUDEC) $(SHARE)sounds/wdnflute.uu $(SBIN)cvtsnd Wooden_Flute $(SLIB)sounds/Wooden_Flute -delete Wooden_Flute $(SLIB)sounds/Wooden_Harp: $(SHARE)sounds/wdnharp.uu $(UUDEC) $(SHARE)sounds/wdnharp.uu $(SBIN)cvtsnd Wooden_Harp $(SLIB)sounds/Wooden_Harp -delete Wooden_Harp inst-dungeon: $(INSTDUNGEONFILES) $(NETHACK)options : $(DAT)options copy $(DAT)options $@ # Create compiled dungeon files BGM= $(SLIB)bigrm-2.lev $(SLIB)bigrm-3.lev $(SLIB)bigrm-4.lev $(SLIB)bigrm-5.lev $(BGM): $(SLIB)bigrm-1.lev $(SLIB)bigrm-1.lev: $(DAT)bigroom.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)bigroom.des #none $(SLIB)castle.lev: $(DAT)castle.des $(SBIN)lev_comp ENDGAME1= $(SLIB)air.lev $(SLIB)earth.lev $(SLIB)fire.lev $(SLIB)water.lev $(ENDGAME1): $(SLIB)astral.lev $(SLIB)astral.lev: $(DAT)endgame.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)endgame.des #none GEHENNOM1= $(SLIB)asmodeus.lev $(SLIB)baalz.lev $(SLIB)juiblex.lev \ $(SLIB)orcus.lev $(SLIB)sanctum.lev $(GEHENNOM1): $(SLIB)valley.lev $(SLIB)valley.lev: $(DAT)gehennom.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)gehennom.des #none $(SLIB)knox.lev: $(DAT)knox.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)knox.des #none MINES1= $(SLIB)minend-1.lev $(SLIB)minend-2.lev $(SLIB)minetn-1.lev $(SLIB)minetn-2.lev $(MINES1): $(SLIB)minefill.lev $(SLIB)minefill.lev: $(DAT)mines.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)mines.des #none $(SLIB)oracle.lev: $(DAT)oracle.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)oracle.des #none TOWER1= $(SLIB)tower1.lev $(SLIB)tower2.lev $(TOWER1): $(SLIB)tower3.lev $(SLIB)tower3.lev: $(DAT)tower.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)tower.des #none WIZARD1= $(SLIB)wizard1.lev $(SLIB)wizard2.lev $(SLIB)wizard3.lev \ $(SLIB)fakewiz1.lev $(WIZARD1): $(SLIB)fakewiz2.lev $(SLIB)fakewiz2.lev: $(DAT)yendor.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)yendor.des #none MEDUSA1= $(SLIB)medusa-1.lev $(MEDUSA1): $(SLIB)medusa-2.lev $(SLIB)medusa-2.lev: $(DAT)medusa.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)medusa.des #none SOKOBAN1= $(SLIB)soko1-1.lev $(SLIB)soko1-2.lev $(SLIB)soko2-1.lev \ $(SLIB)soko2-2.lev $(SLIB)soko3-1.lev $(SLIB)soko3-2.lev \ $(SLIB)soko4-1.lev $(SOKOBAN1): $(SLIB)soko4-2.lev $(SLIB)soko4-2.lev: $(DAT)sokoban.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)sokoban.des #none $(ADFILES1): $(SLIB)Arc-goal.lev $(SLIB)Arc-goal.lev: $(DAT)Arch.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Arch.des #none $(BDFILES1): $(SLIB)Bar-goal.lev $(SLIB)Bar-goal.lev: $(DAT)Barb.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Barb.des #none $(CDFILES1): $(SLIB)Cav-goal.lev $(SLIB)Cav-goal.lev: $(DAT)Caveman.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Caveman.des #none $(HDFILES1): $(SLIB)Hea-goal.lev $(SLIB)Hea-goal.lev: $(DAT)Healer.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Healer.des #none $(KDFILES1): $(SLIB)Kni-goal.lev $(SLIB)Kni-goal.lev: $(DAT)Knight.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Knight.des #none $(MDFILES1): $(SLIB)Mon-goal.lev $(SLIB)Mon-goal.lev: $(DAT)Monk.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Monk.des #none $(PDFILES1): $(SLIB)Pri-goal.lev $(SLIB)Pri-goal.lev: $(DAT)Priest.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Priest.des #none $(RDFILES1): $(SLIB)Rog-goal.lev $(SLIB)Rog-goal.lev: $(DAT)Rogue.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Rogue.des #none $(RANFILES1): $(SLIB)Ran-goal.lev $(SLIB)Ran-goal.lev: $(DAT)Ranger.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Ranger.des #none $(SDFILES1): $(SLIB)Sam-goal.lev $(SLIB)Sam-goal.lev: $(DAT)Samurai.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Samurai.des #none $(TDFILES1): $(SLIB)Tou-goal.lev $(SLIB)Tou-goal.lev: $(DAT)Tourist.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Tourist.des #none $(VDFILES1): $(SLIB)Val-goal.lev $(SLIB)Val-goal.lev: $(DAT)Valkyrie.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Valkyrie.des #none $(WDFILES1): $(SLIB)Wiz-goal.lev $(SLIB)Wiz-goal.lev: $(DAT)Wizard.des $(SBIN)lev_comp #SFD_INSTEAD $(SBIN)lev_comp $(DAT)Wizard.des #none $(SLIB)dungeon: $(DAT)dungeon.def $(SBIN)makedefs $(SBIN)dgn_comp $(SBIN)makedefs -e $(SBIN)dgn_comp $(DAT)dungeon.pdf copy $(DAT)dungeon $(SLIB)dungeon delete $(DAT)dungeon inst-data: $(INSTDATAFILES) $(NETHACK)amii.hlp: $(AMI)amii.hlp copy $(AMI)amii.hlp $@ #$(NETHACK)data: $(DAT)data # copy $(DAT)data $@ $(SLIB)data: $(DAT)data.base $(I)config.h $(SBIN)makedefs $(SBIN)makedefs -d #$(NETHACK)rumors: $(DAT)rumors # copy $(DAT)rumors $@ $(SLIB)rumors: $(DAT)rumors.tru $(DAT)rumors.fal $(SBIN)makedefs $(SBIN)makedefs -r $(SLIB)cmdhelp: $(DAT)cmdhelp copy $(DAT)cmdhelp $@ $(SLIB)help: $(DAT)help copy $(DAT)help $@ $(SLIB)hh: $(DAT)hh copy $(DAT)hh $@ $(NETHACK)HackWB.hlp: $(AMI)HackWB.hlp copy $(AMI)HackWB.hlp $@ $(SLIB)history: $(DAT)history copy $(DAT)history $@ $(NETHACK)license: $(DAT)license copy $(DAT)license $@ $(SLIB)opthelp: $(DAT)opthelp copy $(DAT)opthelp $@ $(NETHACK)Recover.txt: $(DOC)Recover.txt copy $(DOC)Recover.txt $@ $(NETHACK)GuideBook.txt: $(DOC)GuideBook.txt copy $(DOC)GuideBook.txt $@ $(NETHACK)NetHack.txt: $(DOC)NetHack.txt copy $(DOC)NetHack.txt $@ $(NETHACK)Install.ami: $(AMI)Install.ami copy $(AMI)Install.ami $@ #SFD_INSTEAD $(NETHACK)logfile: $(NETHACK)logfile $(NETHACK)logfile: echo to $@ #SFD_INSTEAD $(NETHACK)record: $(NETHACK)record $(NETHACK)record: echo to $@ $(SLIB)wizhelp: $(DAT)wizhelp copy $(DAT)wizhelp $@ # Create the directories here because NetHack.cnf puts them there by default $(NETHACK)NetHack.cnf: $(AMI)NetHack.cnf copy $(AMI)NetHack.cnf $@ -makedir $(NETHACK)save -makedir $(NETHACK)levels #SFD_BEGIN #SFD_ELSE $(O)NetHack.gst: $(GSTSRC) $(I)hack.h sc makegst=$(GSTFILE) $(CFLAGS) $(GSTSRC) #SFD_END # Unpack and install fonts INSTFONTFILES= $(NETHACK)hack.font $(NETHACK)hack $(NETHACK)hack/8 inst-fonts: $(INSTFONTFILES) $(NETHACK)hack/8: $(AMI)amifont8.uu $(NETHACK)hack $(UUDEC) $(AMI)amifont8.uu copy 8 $(NETHACK)hack/8 delete 8 $(NETHACK)hack.font: $(AMI)amifont.uu $(UUDEC) $(AMI)amifont.uu copy hack.font $(NETHACK)hack.font delete hack.font #SFD_INSTEAD $(NETHACK)hack: $(NETHACK)hack $(NETHACK)hack: -makedir $@ INSTICONFILES= \ $(NETHACK)default.icon $(NETHACK)NetHack.info $(NETHACK)NewGame.info \ $(NETHACK)HackWB.info inst-icons: $(INSTICONFILES) # Unpack the icons into place $(NETHACK)default.icon: $(AMI)dflticon.uu $(UUDEC) $(AMI)dflticon.uu # copy default.icon $(NETHACK)default.icon # delete default.icon $(NETHACK)NetHack.info: $(AMI)NHinfo.uu $(UUDEC) $(AMI)NHinfo.uu # copy NetHack.info $(NETHACK)NetHack.info # delete NetHack.info $(NETHACK)NewGame.info: $(AMI)NewGame.uu $(UUDEC) $(AMI)NewGame.uu # copy NewGame.info $(NETHACK)NewGame.info # delete NewGame.info $(NETHACK)HackWB.info: $(AMI)HackWB.uu $(UUDEC) $(AMI)HackWB.uu # copy HackWB.info $(NETHACK)HackWB.info # delete HackWB.info # If DLB is defined, create the nhdat library file in the playground # directory. If not, move all the data files there. $(NETHACK)nhdat: $(LIBFILES) $(SBIN)dlb list to T:nhdat.lst $(SLIB) QUICK NOHEAD FILES echo >T:make-nhdat $(SBIN)dlb cCfI $(SLIB) $(NETHACK)nhdat T:nhdat.lst echo >>T:make-nhdat if not exists $(NETHACK)nhdat echo >>T:make-nhdat copy $(SLIB)\#? $(NETHACK) echo >>T:make-nhdat endif execute T:make-nhdat -delete T:make-nhdat # DO NOT DELETE THIS LINE $(O)allmain.o: $(NHS)allmain.c $(HDEP) $(O)alloc.o: $(NHS)alloc.c $(I)config.h $(O)apply.o: $(NHS)apply.c $(HDEP) $(I)edog.h #SFD_INSTEAD #none $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)apply.c $(O)artifact.o: $(NHS)artifact.c $(HDEP) $(I)artifact.h $(I)artilist.h $(O)attrib.o: $(NHS)attrib.c $(HDEP) $(I)artifact.h $(O)ball.o: $(NHS)ball.c $(HDEP) $(O)bones.o: $(NHS)bones.c $(HDEP) $(I)lev.h $(O)botl.o: $(NHS)botl.c $(HDEP) $(O)cmd.o: $(NHS)cmd.c $(HDEP) $(I)func_tab.h $(O)dbridge.o: $(NHS)dbridge.c $(HDEP) $(O)decl.o: $(NHS)decl.c $(HDEP) $(I)quest.h $(O)detect.o: $(NHS)detect.c $(HDEP) $(I)artifact.h $(O)dig.o: $(NHS)dig.c $(HDEP) $(I)edog.h $(O)display.o: $(NHS)display.c $(HDEP) $(O)dlb.o: $(NHS)dlb.c $(HDEP) $(I)dlb.h $(O)do.o: $(NHS)do.c $(HDEP) $(I)lev.h $(O)do_name.o: $(NHS)do_name.c $(HDEP) $(O)do_wear.o: $(NHS)do_wear.c $(HDEP) $(O)dog.o: $(NHS)dog.c $(HDEP) $(I)edog.h $(O)dogmove.o: $(NHS)dogmove.c $(HDEP) $(I)mfndpos.h $(I)edog.h $(O)dokick.o: $(NHS)dokick.c $(HDEP) $(I)eshk.h $(O)dothrow.o: $(NHS)dothrow.c $(HDEP) $(O)drawing.o: $(NHS)drawing.c $(HDEP) $(I)tcap.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)drawing.c $(O)dungeon.o: $(NHS)dungeon.c $(HDEP) $(I)dgn_file.h $(I)dlb.h $(O)eat.o: $(NHS)eat.c $(HDEP) $(O)end.o: $(NHS)end.c $(HDEP) $(I)eshk.h $(I)dlb.h $(O)engrave.o: $(NHS)engrave.c $(HDEP) $(I)lev.h $(O)exper.o: $(NHS)exper.c $(HDEP) $(O)explode.o: $(NHS)explode.c $(HDEP) $(O)extralev.o: $(NHS)extralev.c $(HDEP) $(O)files.o: $(NHS)files.c $(HDEP) $(I)dlb.h $(I)date.h $(O)fountain.o: $(NHS)fountain.c $(HDEP) $(O)hack.o: $(NHS)hack.c $(HDEP) $(O)hacklib.o: $(NHS)hacklib.c $(HDEP) $(O)invent.o: $(NHS)invent.c $(HDEP) $(I)artifact.h $(O)light.o: $(NHS)light.c $(HDEP) $(I)lev.h $(O)lock.o: $(NHS)lock.c $(HDEP) $(O)mail.o: $(NHS)mail.c $(HDEP) $(I)mail.h $(O)makemon.o: $(NHS)makemon.c $(HDEP) $(I)epri.h $(I)emin.h $(I)edog.h $(O)mapglyph.o: $(NHS)mapglyph.c $(HDEP) $(O)mcastu.o: $(NHS)mcastu.c $(HDEP) $(O)mhitm.o: $(NHS)mhitm.c $(HDEP) $(I)artifact.h $(I)edog.h $(O)mhitu.o: $(NHS)mhitu.c $(HDEP) $(I)artifact.h $(I)edog.h $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)mhitu.c $(O)minion.o: $(NHS)minion.c $(HDEP) $(I)emin.h $(I)epri.h $(O)mklev.o: $(NHS)mklev.c $(HDEP) $(O)mkmap.o: $(NHS)mkmap.c $(HDEP) $(I)sp_lev.h $(O)mkmaze.o: $(NHS)mkmaze.c $(HDEP) $(I)sp_lev.h $(I)lev.h $(O)mkobj.o: $(NHS)mkobj.c $(HDEP) $(I)artifact.h $(I)prop.h $(O)mkroom.o: $(NHS)mkroom.c $(HDEP) $(O)mon.o: $(NHS)mon.c $(HDEP) $(I)mfndpos.h $(I)edog.h $(O)mondata.o: $(NHS)mondata.c $(HDEP) $(I)eshk.h $(I)epri.h $(O)monmove.o: $(NHS)monmove.c $(HDEP) $(I)mfndpos.h $(I)artifact.h $(O)monst.o: $(NHS)monst.c $(I)config.h $(I)permonst.h $(I)monsym.h \ $(I)eshk.h $(I)vault.h $(I)epri.h $(I)color.h $(O)monstr.o: $(NHS)monstr.c $(HDEP) #SFD_INSTEAD $(CC) $(CFLAGS) $(OBJSPEC)%(left) $(NHS)monstr.c #none $(O)mplayer.o: $(NHS)mplayer.c $(HDEP) $(O)mthrowu.o: $(NHS)mthrowu.c $(HDEP) $(O)muse.o: $(NHS)muse.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)muse.c $(O)music.o: $(NHS)music.c $(HDEP) #interp.c $(O)o_init.o: $(NHS)o_init.c $(HDEP) $(I)lev.h $(O)objects.o: $(NHS)objects.c $(I)config.h $(I)obj.h $(I)objclass.h \ $(I)prop.h $(I)skills.h $(I)color.h #SFD_INSTEAD #none $(CC) $(CFLAGS) $(INCLSPEC)$(NHS) $(OBJSPEC)$@ $(NHS)objects.c $(O)objnam.o: $(NHS)objnam.c $(HDEP) $(O)options.o: $(NHS)options.c $(HDEP) $(I)tcap.h $(I)config.h \ $(I)objclass.h $(I)flag.h $(O)pager.o: $(NHS)pager.c $(HDEP) $(I)dlb.h $(O)pickup.o: $(NHS)pickup.c $(HDEP) $(O)pline.o: $(NHS)pline.c $(HDEP) $(I)epri.h $(O)polyself.o: $(NHS)polyself.c $(HDEP) $(O)potion.o: $(NHS)potion.c $(HDEP) $(O)pray.o: $(NHS)pray.c $(HDEP) $(I)epri.h $(O)priest.o: $(NHS)priest.c $(HDEP) $(I)mfndpos.h $(I)eshk.h $(I)epri.h \ $(I)emin.h $(O)quest.o: $(NHS)quest.c $(HDEP) $(I)quest.h $(I)qtext.h $(O)questpgr.o: $(NHS)questpgr.c $(HDEP) $(I)qtext.h $(I)dlb.h $(O)read.o: $(NHS)read.c $(HDEP) $(O)rect.o: $(NHS)rect.c $(HDEP) $(O)region.o: $(NHS)region.c $(HDEP) $(O)restore.o: $(NHS)restore.c $(HDEP) $(I)lev.h $(I)tcap.h $(I)quest.h $(O)rnd.o: $(NHS)rnd.c $(HDEP) $(O)role.o: $(NHS)role.c $(HDEP) $(O)rumors.o: $(NHS)rumors.c $(HDEP) $(I)dlb.h $(O)save.o: $(NHS)save.c $(HDEP) $(I)lev.h $(I)quest.h $(O)shk.o: $(NHS)shk.c $(HDEP) $(I)eshk.h #SFD_INSTEAD #none $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)shk.c $(O)shknam.o: $(NHS)shknam.c $(HDEP) $(I)eshk.h $(O)sit.o: $(NHS)sit.c $(HDEP) $(I)artifact.h $(O)sounds.o: $(NHS)sounds.c $(HDEP) $(I)edog.h $(O)sp_lev.o: $(NHS)sp_lev.c $(HDEP) $(I)sp_lev.h $(I)rect.h $(I)dlb.h $(O)spell.o: $(NHS)spell.c $(HDEP) $(O)steal.o: $(NHS)steal.c $(HDEP) $(O)steed.o: $(NHS)steed.c $(HDEP) $(O)teleport.o: $(NHS)teleport.c $(HDEP) $(O)timeout.o: $(NHS)timeout.c $(HDEP) $(I)lev.h $(O)topten.o: $(NHS)topten.c $(HDEP) $(I)dlb.h $(O)track.o: $(NHS)track.c $(HDEP) $(O)trap.o: $(NHS)trap.c $(HDEP) #SFD_INSTEAD #none $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)trap.c $(O)u_init.o: $(NHS)u_init.c $(HDEP) $(O)uhitm.o: $(NHS)uhitm.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)uhitm.c $(O)vault.o: $(NHS)vault.c $(HDEP) $(I)vault.h $(O)version.o: $(NHS)version.c $(HDEP) $(I)date.h $(I)patchlevel.h # DMake doesn't grok mid-line comments #SFD_INSTEAD $(O)vision.o: $(NHS)vision.c $(HDEP) $(O)vision.o: $(NHS)vision.c $(HDEP) #$(I)vis_tab.h $(O)weapon.o: $(NHS)weapon.c $(HDEP) $(O)were.o: $(NHS)were.c $(HDEP) $(O)wield.o: $(NHS)wield.c $(HDEP) $(O)windows.o: $(NHS)windows.c $(HDEP) $(I)wintty.h $(O)wizard.o: $(NHS)wizard.c $(HDEP) $(I)qtext.h $(O)worm.o: $(NHS)worm.c $(HDEP) $(I)lev.h $(O)worn.o: $(NHS)worn.c $(HDEP) $(O)write.o: $(NHS)write.c $(HDEP) $(O)zap.o: $(NHS)zap.c $(HDEP) $(CC) $(CFLAGS) $(CFLAGS2) $(OBJSPEC)$@ $(NHS)zap.c $(O)getline.o: $(TTY)getline.c $(HDEP) $(I)wintty.h $(O)termcap.o: $(TTY)termcap.c $(HDEP) $(I)wintty.h $(I)tcap.h $(O)topl.o: $(TTY)topl.c $(HDEP) $(I)wintty.h $(I)tcap.h $(O)wintty.o: $(TTY)wintty.c $(HDEP) $(I)wintty.h $(I)tcap.h \ $(I)patchlevel.h $(O)amitty.o: $(AMI)amitty.c $(HDEP) $(O)amistack.o: $(AMI)amistack.c $(CC) $(CFLAGS3) $(CSYM) $(OBJSPEC)$@ $(AMI)amistack.c $(O)rip.o: $(NHS)rip.c $(HDEP) $(I)config.h: $(I)config1.h $(I)tradstdc.h $(I)global.h -setdate $(I)config.h -wait 2 # onames.h handled at onames.h target, pm.h $(I)decl.h: $(I)quest.h $(I)spell.h $(I)color.h $(I)obj.h $(I)you.h -setdate $(I)decl.h -wait 2 $(I)global.h: $(I)coord.h $(I)pcconf.h $(I)amiconf.h -setdate $(I)global.h -wait 2 $(I)hack.h: $(I)config.h $(I)trap.h $(I)decl.h $(I)dungeon.h $(I)monsym.h \ $(I)mkroom.h $(I)objclass.h $(I)flag.h $(I)rm.h $(I)vision.h \ $(I)display.h $(I)wintype.h $(I)engrave.h $(I)rect.h \ $(I)region.h $(I)trampoli.h -setdate $(I)hack.h -wait 2 $(I)permonst.h: $(I)monattk.h $(I)monflag.h $(I)align.h -setdate $(I)permonst.h -wait 2 $(I)you.h: $(I)align.h $(I)attrib.h $(I)monst.h $(I)youprop.h $(I)skills.h -setdate $(I)you.h -wait 2 # pm.h handled at target $(I)youprop.h: $(I)prop.h $(I)permonst.h $(I)mondata.h -setdate $(I)youprop.h -wait 2 $(I)display.h: $(I)vision.h $(I)mondata.h -setdate $(I)display.h -wait 2 $(I)dungeon.h: $(I)align.h -setdate $(I)dungeon.h -wait 2 $(I)emin.h: $(I)dungeon.h -setdate $(I)emin.h -wait 2 $(I)epri.h: $(I)dungeon.h $(I)align.h -setdate $(I)epri.h -wait 2 $(I)eshk.h: $(I)dungeon.h -setdate $(I)eshk.h -wait 2 $(I)engrave.h: $(I)trampoli.h $(I)rect.h -setdate $(I)engrave.h -wait 2 $(I)mondata.h: $(I)align.h -setdate $(I)mondata.h -wait 2 $(I)monst.h: $(I)align.h -setdate $(I)monst.h -wait 2 $(I)pcconf.h: $(I)micro.h $(I)system.h -setdate $(I)pcconf.h -wait 2 $(I)rm.h: $(I)align.h -setdate $(I)rm.h -wait 2 $(I)vault.h: $(I)dungeon.h -setdate $(I)vault.h -wait 2 #notes # install keeps doing re-install because it keeps rebuilding lev_comp??? # fixed(?) - deleted setdate # make nhdat rebuils sys/amiga objects nethack-3.4.3/sys/amiga/NetHack.cnf0100644000000000000000000001467207764735041015565 0ustar rootroot# A '#' at the beginning of a line means the rest of the line is a comment. # This is an example configuration file. # If several people are to use it, don't specify "name" or personal # prefences like "dogname" or "packorder" in OPTIONS. # To change configuration, comment out the unwanted configurations, and # remove the comment from the configuration you want. # Some options to set personal preferences. If several people are to # use it, options like these should not be set here - use the command line #OPTIONS=name:Janet-V,female,dogname:Fido,fruit:apricot #OPTIONS=packorder:")[%?+/=!(*0_`,scores:10t/2a,noverbose #OPTIONS=gender:male #OPTIONS=role:random #OPTIONS=race:random #OPTIONS=align:chaotic # Other general options #OPTIONS=time,rest_on_space,noautopickup # The search path for files like record, help, opthelp, etc. PATH=NetHack: # My own setup #OPTIONS=nolegacy,fruit:lemon,time,autopickup,checkpoint,showexp,showscore,standout,nonews #OPTIONS=nomail,flush,eight_bit_tty,scores:10t/2a,pickup_types:$,suppress_alert:3.3.0,autoquiver # The windowtype option must be set before any options regarding colors and palette # are set otherwise previously set values will be overridden by the defaults # # The font version of the game OPTIONS=windowtype:amii # # New tile version of the game #OPTIONS=windowtype:amitile # # A hard disk configuration. # HACKDIR=NetHack: LEVELS=Nethack:Levels SAVE=Nethack:Save BONESDIR=Nethack:Levels SCOREDIR=Nethack: LOCKDIR=Nethack: CONFIGDIR=Nethack: DATADIR=Nethack: TROUBLEDIR=Nethack: # *** CHARACTER GRAPHICS *** # # See the on-line help or the Guidebook for which symbols are in which # positions. # # Note that the hack.font has special graphics characters from 192 on. # An example using the hack.font graphics character set: DUNGEON = 032 192 193 194 195 196 197 198 216 214 \ 215 213 217 145 146 147 148 035 035 217 \ 218 229 060 062 060 062 095 124 092 035 \ 123 125 042 125 042 042 035 035 046 035 \ 125 TRAPS = 094 094 094 094 094 094 094 094 094 094 \ 094 094 094 094 094 094 094 034 094 094 \ 094 094 EFFECTS = 241 240 242 243 042 033 123 125 \ 064 038 042 035 \ 244 245 246 247 239 248 249 250 \ 230 234 231 236 212 237 232 235 233 WARNINGS = 048 049 050 051 052 053 # Monitors vary greatly in their color response. If the default colors # are not good on your monitor, here are some other alternatives for the # font version of the game: # # Last color of the palette is always used for the cursor. # #CBM 1960, set color/contrast for good pure red, green, and blue. True colors. #PENS=000,fff,a61,7bb,0f0,e0c,00f,f00 #CBM 1960, set color/contrast as above, better colors for NetHack. #PENS=667,fff,da1,7bb,2f0,e0d,0af,f42 #and other suggestions: #PENS=888,ffc,840,0b8,4e4,e8b,7be,a04 #PENS=000,fff,830,7ae,181,c06,23e,c00 # # For an "interlaced"+ line screen, the default font is courier:13. If you want # a different font, set it here. The format is "fontname.font:size"; i.e. the # .font extension is required. #FONT=courier.font:13 #FONT=topaz.font:8 # # Proportional fonts such as CGTimes are probably not a good idea because they # result in many things not being spaced out correctly. #FONT=CGTimes.font:15 # # This sized proportional font is readable, but still has spacing problems #FONT=CGTimes.font:21 # # FOR AGA OR OTHER DISPLAYS CAPABLE OF 5 OR MORE PLANES... # # For a screen of depth 5 the following dripens provide a brown border # using pens 16-31. # # Pens 16-31 can be redefined with PENS= if you want different colors, # using the PENS= values below for a 4 plane screen as the first 16 colors. # #DEPTH=5 #DRIPENS=0,0,0,17,27,23,1,23,15,0,23,27 # # The APEN and BPEN values in the various types of windows can be set in # the manner shown below. These values are for the 16 color version of # the tile game. # # These values are specified as APEN,BPEN (foreground,background) # #MSGPENS=1,12 #STATUSPENS=1,12 #MENUPENS=1,23 #TEXTPENS=1,23 #OTHERPENS=1,23 # # FOR ECS OR OTHERS ONLY CAPABLE OF 4 PLANES... # # These values work good for the TILE version of the game on ECS machines # These are the default values for reference purposes. # #DEPTH=4 #defaults for tilemode: #PENS=000,fff,0bf,f60,00f,090,69b,f00,6f0,ff0,f0f,940,466,c40,ddb,fb9 #DRIPENS=0,1,0,2,4,12,14,12,7,1,12,4 #defaults for fontmode: #PENS=000,fff,830,7ac,181,c06,23e,c00 #DRIPENS=0,6,2,1,6,3,1,3,7,1,3,6 # # The APEN and BPEN values in the various types of windows can be set in # the manner shown below. These values are for a 32 color version of # the tile game. # # These values are specified as APEN,BPEN (foreground,background) # #MSGPENS=1,12 #STATUSPENS=1,12 #MENUPENS=0,14 #TEXTPENS=0,14 #OTHERPENS=1,12 # # New alternative color scheme for 16 color font mode. # This changes the colors of monsters, objects etc. # # FGPENS and BGPENS define APEN and BPEN for objects and monsters on the map. # The colors are in the following order: # black, red, green, brown, blue, magenta, cyan, gray, no color, orange, # bright green, yellow, bright blue, bright magenta, bright cyan, white # DEPTH=4 PENS=000,fff,830,7ac,181,c06,23e,c00,888,f60,4f4,ff0,4af,f8f,8ff,f00 FGPENS= 0, 7, 4, 2, 6, 5, 3, 8, 1, 9,10,11,12,13,14, 1 BGPENS= 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 # # Screen mode selections below should all work for either the font or tile # version of the game. Other modes can be tried and as long as they are at # least 640x200, the game should adapt to them... # # Select screenmode with a requester #SCREENMODE=Req # NTSC_MONITOR_ID #SCREENMODE=0x00019000 # PAL_MONITOR_ID #SCREENMODE=0x00029000 # NTSC_MONITOR_ID+LACE #SCREENMODE=0x00019004 # PAL_MONITOR_ID+LACE #SCREENMODE=0x00029004 # NTSC_MONITOR_ID+HIRES+LACE #SCREENMODE=0x00019024 # PAL_MONITOR_ID+HIRES+LACE #SCREENMODE=0x00029024 # VGA_MONITOR_ID #SCREENMODE=0x00031000 # VGAPRODUCT_KEY #SCREENMODE=0x00039024 # A2024TENHERTZ_KEY #SCREENMODE=0x00041000 # A2024FIFTEENHERTZ_KEY #SCREENMODE=0x00049000 # EURO72_MONITOR_ID #SCREENMODE=0x00061000 # EURO72PRODUCT_KEY #SCREENMODE=0x00069024 # EURO72PRODUCTLACE_KEY #SCREENMODE=0x00069025 # EURO72PRODUCTDBL_KEY #SCREENMODE=0x00069020 # EURO36_MONITOR_ID #SCREENMODE=0x00071000 # SUPER72HIRESDBL_KEY #SCREENMODE=0x00089008 # SUPER72SUPERDBL_KEY #SCREENMODE=0x00089028 # DBLNTSCHIRES_KEY #SCREENMODE=0x00099000 # DBLNTSCHIRESFF_KEY #SCREENMODE=0x00099004 # DBLNTSCHIRESLACE_KEY #SCREENMODE=0x00099005 # DBLPALHIRES_KEY #SCREENMODE=0x000a9000 # DBLPALHIRESFF_KEY #SCREENMODE=0x000a9004 # DBLPALHIRESLACE_KEY #SCREENMODE=0x000a9005 nethack-3.4.3/sys/amiga/amidos.c0100644000000000000000000002476207764735041015201 0ustar rootroot/* SCCS Id: @(#)amidos.c 3.2 2000/01/12 /* Copyright (c) Olaf Seibert, Nijmegen, The Netherlands, 1988,1990. */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ /* * An assortment of imitations of cheap plastic MSDOS and Unix functions. */ #include "hack.h" #include "winami.h" /* Defined in config.h, let's undefine it here (static function below) */ #undef strcmpi #include #include #include #undef COUNT #if defined(__SASC_60) || defined(__GNUC__) # include # include #endif #ifdef AZTEC_50 # include # undef strcmpi #endif /* Prototypes */ #include "NH:sys/amiga/winami.p" #include "NH:sys/amiga/amiwind.p" #include "NH:sys/amiga/amidos.p" extern char Initialized; extern struct window_procs amii_procs; #ifndef __SASC_60 int Enable_Abort = 0; /* for stdio package */ #endif /* Initial path, so we can find NetHack.cnf */ char PATH[PATHLEN] = "NetHack:"; static boolean record_exists(void); void flushout() { (void) fflush(stdout); } #ifndef getuid getuid() { return 1; } #endif #ifndef getlogin char * getlogin() { return ((char *) NULL); } #endif #ifndef AZTEC_50 int abs(x) int x; { return x < 0? -x: x; } #endif #ifdef SHELL int dosh() { int i; char buf[ BUFSZ ]; extern struct ExecBase *SysBase; /* Only under 2.0 and later ROMs do we have System() */ if( SysBase->LibNode.lib_Version >= 37 && !amibbs) { getlin("Enter CLI Command...", buf ); if (buf[0] != '\033') i = System( buf, NULL ); } else { i = 0; pline("No mysterious force prevented you from using multitasking."); } return i; } #endif /* SHELL */ #ifdef MFLOPPY # include # define Sprintf (void) sprintf #define EXTENSION 72 /* * This routine uses an approximation of the free bytes on a disk. * How large a file you can actually write depends on the number of * extension blocks you need for it. * In each extenstion block there are maximum 72 pointers to blocks, * so every 73 disk blocks have only 72 available for data. * The (necessary) file header is also good for 72 data block pointers. */ /* TODO: update this for FFS */ long freediskspace(path) char *path; { register long freeBytes = 0; register struct InfoData *infoData; /* Remember... longword aligned */ char fileName[32]; /* * Find a valid path on the device of which we want the free space. * If there is a colon in the name, it is an absolute path * and all up to the colon is everything we need. * Remember slashes in a volume name are allowed! * If there is no colon, it is relative to the current directory, * so must be on the current device, so "" is enough... */ { register char *colon; strncpy(fileName, path, sizeof(fileName) - 1); fileName[31] = 0; if (colon = index(fileName, ':')) colon[1] = '\0'; else fileName[0] = '\0'; } { BPTR fileLock; infoData = (struct InfoData *) alloc(sizeof(struct InfoData)); if (fileLock = Lock(fileName, SHARED_LOCK)) { if (Info(fileLock, infoData)) { /* We got a kind of DOS volume, since we can Lock it. */ /* Calculate number of blocks available for new file */ /* Kludge for the ever-full VOID: (oops RAM:) device */ if (infoData->id_UnitNumber == -1 && infoData->id_NumBlocks == infoData->id_NumBlocksUsed) { freeBytes = AvailMem(0L) - 64 * 1024L; /* Just a stupid guess at the */ /* Ram-Handler overhead per block: */ freeBytes -= freeBytes/16; } else { /* Normal kind of DOS file system device/volume */ freeBytes = infoData->id_NumBlocks - infoData->id_NumBlocksUsed; freeBytes -= (freeBytes + EXTENSION) / (EXTENSION + 1); freeBytes *= infoData->id_BytesPerBlock; } if (freeBytes < 0) freeBytes = 0; } UnLock(fileLock); } free(infoData); return freeBytes; } } long filesize(file) char *file; { register BPTR fileLock; register struct FileInfoBlock *fileInfoBlock; register long size = 0; fileInfoBlock = (struct FileInfoBlock *)alloc(sizeof(struct FileInfoBlock)); if (fileLock = Lock(file, SHARED_LOCK)) { if (Examine(fileLock, fileInfoBlock)) { size = fileInfoBlock->fib_Size; } UnLock(fileLock); } free(fileInfoBlock); return size; } #if 0 void eraseall(path, files) const char *path, *files; { BPTR dirLock, dirLock2; struct FileInfoBlock *fibp; int chklen; #ifdef BETA if(files != alllevels)panic("eraseall"); #endif chklen=(int)index(files,'*')-(int)files; if (dirLock = Lock( (char *)path ,SHARED_LOCK)) { dirLock2=DupLock(dirLock); dirLock2= CurrentDir(dirLock2); fibp=AllocMem(sizeof(struct FileInfoBlock),0); if(fibp){ if(Examine(dirLock,fibp)){ while(ExNext(dirLock,fibp)){ if(!strncmp(fibp->fib_FileName,files,chklen)){ DeleteFile(fibp->fib_FileName); } } } FreeMem(fibp,sizeof(struct FileInfoBlock)); } UnLock(dirLock); UnLock(CurrentDir(dirLock2)); } } #endif /* This size makes that most files can be copied with two Read()/Write()s */ #if 0 /* Unused */ #define COPYSIZE 4096 char *CopyFile(from, to) const char *from, *to; { register BPTR fromFile, toFile; register char *buffer; register long size; char *error = NULL; buffer = (char *) alloc(COPYSIZE); if (fromFile = Open( (char *)from, MODE_OLDFILE)) { if (toFile = Open( (char *)to, MODE_NEWFILE)) { while (size = Read(fromFile, buffer, (long)COPYSIZE)) { if (size == -1){ error = "Read error"; break; } if (size != Write(toFile, buffer, size)) { error = "Write error"; break; } } Close(toFile); } else error = "Cannot open destination"; Close(fromFile); } else error = "Cannot open source (this should not occur)"; free(buffer); return error; } #endif /* this should be replaced */ saveDiskPrompt(start) { char buf[BUFSIZ], *bp; BPTR fileLock; if (flags.asksavedisk) { /* Don't prompt if you can find the save file */ if (fileLock = Lock(SAVEF, SHARED_LOCK)) { UnLock(fileLock); #if defined(TTY_GRAPHICS) if(windowprocs.win_init_nhwindows!=amii_procs.win_init_nhwindows) clear_nhwindow( WIN_MAP ); #endif #if defined(AMII_GRAPHICS) if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows) clear_nhwindow( WIN_BASE ); #endif return 1; } pline( "If save file is on a SAVE disk, put that disk in now." ); if( strlen( SAVEF ) > QBUFSZ - 25 - 22 ) panic( "not enough buffer space for prompt" ); /* THIS IS A HACK */ #if defined(TTY_GRAPHICS) if(windowprocs.win_init_nhwindows!=amii_procs.win_init_nhwindows){ getlin("File name ?",buf); clear_nhwindow( WIN_MAP ); } #endif #if defined(AMII_GRAPHICS) if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows){ getlind("File name ?", buf, SAVEF); clear_nhwindow( WIN_BASE ); } #endif clear_nhwindow( WIN_MESSAGE); if (!start && *buf == '\033') return 0; /* Strip any whitespace. Also, if nothing was entered except * whitespace, do not change the value of SAVEF. */ for (bp = buf; *bp; bp++) { if (!isspace(*bp)) { strncpy(SAVEF, bp, PATHLEN); break; } } } return 1; } /* Return 1 if the record file was found */ static boolean record_exists() { FILE *file; if (file = fopenp(RECORD, "r")) { fclose(file); return TRUE; } return FALSE; } #ifdef MFLOPPY /* * Under MSDOS: Prompt for game disk, then check for record file. * For Amiga: do nothing, but called from restore.c */ void gameDiskPrompt(){} #endif /* * Add a slash to any name not ending in / or :. There must * be room for the /. */ void append_slash(name) char *name; { char *ptr; if (!*name)return; ptr = eos(name) - 1; if (*ptr != '/' && *ptr != ':') { *++ptr = '/'; *++ptr = '\0'; } } void getreturn(str) const char *str; { int ch; raw_printf("Hit %s.", str); while ((ch = nhgetch()) != '\n' && ch != '\r' ) continue; } /* Follow the PATH, trying to fopen the file. */ #define PATHSEP ';' FILE * fopenp(name, mode) register const char *name, *mode; { register char *bp, *pp, lastch; register FILE *fp; register BPTR theLock; char buf[BUFSIZ]; /* Try the default directory first. Then look along PATH. */ if (strlen(name) >= BUFSIZ) return( NULL ); strcpy(buf, name); if (theLock = Lock(buf, SHARED_LOCK)) { UnLock(theLock); if (fp = fopen(buf, mode)) return fp; } pp = PATH; while (pp && *pp) { bp = buf; while (*pp && *pp != PATHSEP){ if( bp > buf + BUFSIZ - 1 ) return( NULL ); lastch = *bp++ = *pp++; } if (lastch != ':' && lastch != '/' && bp != buf) *bp++ = '/'; if (bp + strlen(name) > buf + BUFSIZ - 1) return( NULL ); strcpy(bp, name); if (theLock = Lock(buf, SHARED_LOCK)) { UnLock(theLock); if (fp = fopen(buf, mode)) return fp; } if (*pp) pp++; } return NULL; } #endif /* MFLOPPY */ #ifdef CHDIR /* * A not general-purpose directory changing routine. * Assumes you want to return to the original directory eventually, * by chdir()ing to orgdir (which is defined in pcmain.c). * Assumes -1 is not a valid lock, since 0 is valid. */ #define NO_LOCK ((BPTR) -1) static BPTR OrgDirLock = NO_LOCK; chdir(dir) char *dir; { extern char orgdir[]; if (dir == orgdir) { /* We want to go back to where we came from. */ if (OrgDirLock != NO_LOCK) { UnLock(CurrentDir(OrgDirLock)); OrgDirLock = NO_LOCK; } } else { /* * Go to some new place. If still at the original * directory, save the FileLock. */ BPTR newDir; if (newDir = Lock( (char *)dir, SHARED_LOCK)) { if (OrgDirLock == NO_LOCK) { OrgDirLock = CurrentDir(newDir); } else { UnLock(CurrentDir(newDir)); } } else { return -1; /* Failed */ } } /* CurrentDir always succeeds if you have a lock */ return 0; } #endif /* CHDIR */ /* Chdir back to original directory */ #undef exit void nethack_exit(code) { #ifdef CHDIR extern char orgdir[]; #endif #ifdef CHDIR chdir(orgdir); /* chdir, not chdirx */ #endif #ifdef AMII_GRAPHICS if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows) CleanUp(); #endif exit(code); } void regularize(s) /* normalize file name - we don't like :'s or /'s */ register char *s; { register char *lp; while((lp = index(s, ':')) || (lp = index(s, '/'))) *lp = '_'; } nethack-3.4.3/sys/amiga/amidos.p0100644000000000000000000000221207764735041015200 0ustar rootroot/* SCCS Id: @(#)amidos.p 3.1 93/01/08 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* amidos.c */ void NDECL(flushout ); #ifndef getuid int NDECL(getuid ); #endif #ifndef getpid int NDECL(getpid ); #endif #ifndef getlogin char *NDECL(getlogin ); #endif #ifndef abs int FDECL(abs, (int )); #endif int NDECL(tgetch ); int NDECL(dosh ); long FDECL(freediskspace, (char *)); long FDECL(filesize, (char *)); void FDECL(eraseall, (const char * , const char *)); char *FDECL(CopyFile, (const char * , const char *)); void FDECL(copybones, (int )); void NDECL(playwoRAMdisk ); int FDECL(saveDiskPrompt, (int )); void NDECL(gameDiskPrompt ); void FDECL(append_slash, (char *)); void FDECL(getreturn, (const char *)); #ifndef msmsg void FDECL(msmsg, ( const char *, ... )); #endif #if !defined(__SASC_60) && !defined(_DCC) int FDECL(chdir, (char *)); #endif #ifndef strcmpi int FDECL(strcmpi, (char * , char *)); #endif #if !defined(memcmp) && !defined(AZTEC_C) && !defined(_DCC) && !defined(__GNUC__) int FDECL(memcmp, (unsigned char * , unsigned char * , int )); #endif nethack-3.4.3/sys/amiga/amifont.uu0100644000000000000000000000060607764735041015560 0ustar rootrootbegin 777 hack.font M#P```6AA8VLO.``````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` G````````````````````````````````````````````````"`!` ` end nethack-3.4.3/sys/amiga/amifont8.uu0100644000000000000000000000664207764735041015656 0ustar rootrootbegin 644 8 M```#\P`````````!``````````````)E```#Z0```F5P_TYU```````````, M`````!H/@``!``````````````````````````````````````````!&140` M```````````,`````!H`````"20`"`!```@`!@`!```@_P```&X`M```!@X` M```````````8;&P8`#@8##````````,\&#P\''X?G MYVH```!J:A@````8&!@``!@88L!6`%96```8`!@8`*@5P8.BP:@5YP/_[W_^ M````P,```P`\;&P^QFP8&!AF&`````9F.&9F/&`P9F9F&!@8`!AFQCQF9FQF M9F9F&`9F8,;F;&9L9F9:9L/&9L/&,&`,.``8`&``!@`V`&```&`8```````` M`!@````````8&!B<,Z6BH:&EI*2AI:6EI*2AI*3__\,8`&:DH:6EI:2DH:2D MI58```!65CP````8&!@``!@\96-J`&IJ```8`!@8UB/$`\`C+"O4A`/_]Y_Y M````P,```P`\`/Y@S&@P,`P\&`````QN&`8&;'Q@!F9F&!@P?@P&WCQFP&9@ M8,!F&`9L8.[VQF;&9G`89F;&/&:,,#`,;``,/&P\-CPP.VPX!F889GP\W#WL M/CYF9F-C9GX8&!@`S.7BY^?GY^?AY^?GY^3GY^?_`.<8`,/GX>?GY^?DY^?G MY6K_#_!KZCP````8&!@``!AF8#97_];7`&8<`#@\;&I6)F1I/&F6YP./]]_[ M#__PP,```P`8`&P\&'8`,`S_?@!^`!A^&!P,Y^&`9X8/[>QGS&?#@89F;6&#P8,!@,Q@``!G9F;F9X9G88!FP8=V9F9F9V M8!AF9FLV9DQP&`X`,Z6BI*&AH:6AI:&EI:2EI*3_`.<8_P`E(24A)24D)20D MI595/5Q55F;_#_`/\/\``-O#?AMJ5:JJ```?__C_JIPY:];X*]I;A`-F[\_S M.``,/\//C^ M\#YF?CSF_L;&./`\XSP\/AC&PSS^/`,\````.SP\.SQXQN8\9N8\8V8\8`;P M?`P[ C&'X.&'``S`````````````````````#__\,8`&8````````````` M`&H`:VH``,,`&!@``!B<&#P89F-6:E8``&88&!@`K`/`(\0L(T&"``/_W_F? MP``#P````````````````````#```````````````````#`````````````` M```````````````&`````````````````/X`````````?```/```````\`<` M````````<```````,P````````````````````#__\,8`&8````````````` M`%8`5E8`````&!@``!@``!@8`,!J5FH````8&!@``,&#J!7!HL&#``/_[_Y_ MP``#P`````````@`"``(`!``"``8``@`(``(`"@`"``P``@`.``(`$``"`!( M``@`4``(`%@`"`!@``@`:``(`'``"`!X``@`@``(`(@`"`"0``@`F``(`*`` M"`"H``@`L``(`+@`"`#```@`R``(`-``"`#8``@`X``(`.@`"`#P``@`^``( M`0``"`$(``@!$``(`1@`"`$@``@!*``(`3``"`$X``@!0``(`4@`"`%0``@! M6``(`6``"`%H``@!<``(`7@`"`&```@!B``(`9``"`&8``@!H``(`:@`"`&P M``@!N``(`<``"`'(``@!T``(`=@`"`'@``@!Z``(`?``"`'X``@"```(`@@` M"`(0``@"&``(`B``"`(H``@",``(`C@`"`)```@"2``(`E``"`)8``@"8``( M`F@`"`)P``@">``(`H``"`*(``@"D``(`I@`"`*@``@"J``(`K``"`*X``@" MP``(`L@`"`+0``@"V``(`N``"`+H``@"\``(`O@`"`,```@#"``(`Q``"`,8 M``@#(``(`R@`"`,P``@#.``(`T``"`-(``@#4``(`U@`"`-@``@#:``(`W`` M"`-X``@#@``(`X@`"`.0``@#F``(`Z``"`.H``@#L``(`[@`"`/```@#R``( M`]``"`/8``@#X``(`^@`"`/P``@#^``(!```"``(``@`$``(`!@`"``@``@` M*``(`#``"``X``@`0``(`$@`"`!0``@`6``(`&``"`!H``@`<``(`'@`"`"` M``@`B``(`)``"`"8``@`H``(`*@`"`"P``@`N``(`,``"`#(``@`T``(`-@` M"`#@``@`Z``(`/``"`#X``@$"``(!!``"`08``@$(``(!"@`"`0P``@#J``( M!#@`"`.8``@$0``(!$@`"`10``@$6``(!&``"`1H``@$<``(!'@`"`2```@$ MB``(!)``"`28``@$H``(!*@`"`2P``@$N``(!,``"`3(``@!V``(`>``"`'H M``@!\``(`?@`"`(```@$T``(!-@`"`3@``@$Z``(!/``"`3X``@%```(!0@` M"`40``@%&``(!2``"`4H``@%,``(!3@`"`5```@%2``(!5``"`58``@%8``( M!6@`"`5P``@%>``(!8``"`6(``@%D``(!9@`"`+8``@"X``(`N@`"`+P``@" M^``(````"``````#[`````0`````````#@```$0```!<````8@````````/R ` end nethack-3.4.3/sys/amiga/amigst.c0100644000000000000000000000174507764735041015205 0ustar rootroot/* SCCS Id: @(#)amigst.c 3.1 93/01/08 /* Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993 */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include #include #include #include #include #include #include #include #include #undef strcmpi #include #include #ifdef __SASC #include /* for __emit */ #include #include #include #include #include #include #include #endif #include "hack.h" #include "winprocs.h" #include "winami.h" #ifdef AZTEC #include #endif #include "NH:sys/amiga/winami.p" #include "NH:sys/amiga/amiwind.p" #include "NH:sys/amiga/amidos.p" /* end amigst.c */ nethack-3.4.3/sys/amiga/amii.hlp0100644000000000000000000000244007764735041015172 0ustar rootroot Amiga-specific help file for NetHack 3.4 The Amiga port of NetHack supports a number of additional commands and facilities specific to the Amiga. Listed below are the things which are either specific to the Amiga port or might not appear in other ports. While playing NetHack you can press: ALT-HELP Color requestor. CTL-HELP Scale display (amitile only). SHIFT-HELP Overview window (amitile only). Amiga-specific run-time options: altmeta use the alt keys as meta keys flush throw away keyboard type-ahead Command line options recognized are -n No News at game startup. -X Play in discovery mode. -D Play in debug mode. -L Interlaced screen. -l Never Interlaced screen. -u Play as player given as an argument. -r Pick a race given as an argument. -p Pick a profession given as an argument -? Gives command line usage. nethack-3.4.3/sys/amiga/amimenu.c0100644000000000000000000001577007764735041015357 0ustar rootroot/* SCCS Id: @(#)amimenu.c 3.2 96/02/04 */ /* Copyright (c) Olaf 'Rhialto' Seibert, 1989 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993, 1996 */ /* Copyright (c) Janne Salmijärvi, 2000 */ /* NetHack may be freely redistributed. See license for details. */ /* Originally by John Toebes. */ /* GadTools menus by jhsa */ struct NewMenu GTHackMenu[] = { { NM_TITLE, "Commands", 0, 0, 0, 0}, { NM_ITEM, "? Display help menu", 0, 0, 0, (void *)'?'}, { NM_ITEM, "& Explain a command", 0, 0, 0, (void *)'&'}, { NM_ITEM, "O Set options", 0, 0, 0, (void *)'O'}, { NM_ITEM, "! AmigaDos command", 0, 0, 0, (void *)'!'}, { NM_ITEM, "v Version number", 0, 0, 0, (void *)'v'}, { NM_ITEM, "V Long version and game history", 0, 0, 0, (void *)'V'}, { NM_ITEM, "^R Redraw screen", 0, 0, 0, (void *)022}, { NM_ITEM, "^P Repeat previous messages", 0, 0, 0, (void *)020}, { NM_ITEM, "M-q #quit the game", 0, 0, 0, (void *)(128+'q')}, { NM_ITEM, "S Save the game", 0, 0, 0, (void *)'S'}, { NM_TITLE, "Inventory", 0, 0, 0, 0}, { NM_ITEM, "i Inventory", 0, 0, 0, (void *)'i'}, { NM_ITEM, "p Pay your bill", 0, 0, 0, (void *)'p'}, { NM_ITEM, "d Drop an object", 0, 0, 0, (void *)'d'}, { NM_ITEM, "D Drop several things", 0, 0, 0, (void *)'D'}, { NM_ITEM, ", Pickup an object", 0, 0, 0, (void *)','}, { NM_ITEM, "@ Toggle pickup", 0, 0, 0, (void *)'@'}, { NM_ITEM, "/ Identify something", 0, 0, 0, (void *)'/'}, { NM_ITEM, "C Christen a monster", 0, 0, 0, (void *)'C'}, { NM_ITEM, "+ List known spells", 0, 0, 0, (void *)'+'}, { NM_ITEM, "$ Your gold", 0, 0, 0, (void *)'$'}, { NM_TITLE, "Actions", 0, 0, 0, 0}, { NM_ITEM, "a Apply/use something", 0, 0, 0, (void *)'a'}, { NM_ITEM, "e Eat something", 0, 0, 0, (void *)'e'}, { NM_ITEM, "f Fire ammunition", 0, 0, 0, (void *)'f'}, { NM_ITEM, "F Fight a monster", 0, 0, 0, (void *)'F'}, { NM_ITEM, "q Quaff a monster", 0, 0, 0, (void *)'q'}, { NM_ITEM, "r Read scroll/book", 0, 0, 0, (void *)'r'}, { NM_ITEM, "t Throw something", 0, 0, 0, (void *)'t'}, { NM_ITEM, "z Zap a wand", 0, 0, 0, (void *)'z'}, { NM_ITEM, "Z Cast a spell", 0, 0, 0, (void *)'Z'}, { NM_TITLE, "Preparations", 0, 0, 0, 0}, { NM_ITEM, "A Remove all armor", 0, 0, 0, (void *)'A'}, { NM_ITEM, "P Put on a ring", 0, 0, 0, (void *)'P'}, { NM_ITEM, "R Remove ring", 0, 0, 0, (void *)'R'}, { NM_ITEM, "Q Select ammunition for quiver", 0, 0, 0, (void *)'Q'}, { NM_ITEM, "T Take off armor", 0, 0, 0, (void *)'T'}, { NM_ITEM, "w Wield a weapon", 0, 0, 0, (void *)'w'}, { NM_ITEM, "W Wear armor", 0, 0, 0, (void *)'W'}, { NM_ITEM, "x Swap wielded and secondary weapons", 0, 0, 0, (void *)'x'}, { NM_ITEM, ") Current weapon", 0, 0, 0, (void *)')'}, { NM_ITEM, "[ Current armor", 0, 0, 0, (void *)'['}, { NM_ITEM, "= Current rings", 0, 0, 0, (void *)'='}, { NM_ITEM,"\" Current amulet", 0, 0, 0, (void *)'"'}, { NM_ITEM, "( Current tools", 0, 0, 0, (void *)'('}, { NM_ITEM, "* Current equipment", 0, 0, 0, (void *)'*'}, { NM_TITLE, "Movement", 0, 0, 0, 0}, { NM_ITEM, "o Open door", 0, 0, 0, (void *)'o'}, { NM_ITEM, "c Close door", 0, 0, 0, (void *)'c'}, { NM_ITEM, "^D Kick door", 0, 0, 0, (void *)004}, { NM_ITEM, "s Search", 0, 0, 0, (void *)'s'}, { NM_ITEM, "< Go up stairs", 0, 0, 0, (void *)'<'}, { NM_ITEM, "> Go down stairs", 0, 0, 0, (void *)'>'}, { NM_ITEM, "^T Teleport", 0, 0, 0, (void *)024}, { NM_ITEM, ". Wait a moment", 0, 0, 0, (void *)'.'}, { NM_ITEM, "E Engrave message on floor", 0, 0, 0, (void *)'E'}, { NM_TITLE, "Extended", 0, 0, 0, 0}, { NM_ITEM, "M-a #adjust inventory letters", 0, 0, 0, (void *)(128+'a')}, { NM_ITEM, "M-c #chat with someone", 0, 0, 0, (void *)(128+'c')}, { NM_ITEM, "M-d #dip an object into something", 0, 0, 0, (void *)(128+'d')}, #ifdef WEAPON_SKILLS { NM_ITEM, "M-e #enhance weapon skills", 0, 0, 0, (void *)(128+'e')}, #endif { NM_ITEM, "M-f #force a lock", 0, 0, 0, (void *)(128+'f')}, { NM_ITEM, "M-i #invoke an object's special powers", 0, 0, 0, (void *)(128+'i')}, { NM_ITEM, "M-j #jump to another location", 0, 0, 0, (void *)(128+'j')}, { NM_ITEM, "M-l #loot a box on the floor", 0, 0, 0, (void *)(128+'l')}, { NM_ITEM, "M-m Use a #monster's special ability", 0, 0, 0, (void *)(128+'m')}, { NM_ITEM, "M-n #name an item or type of object", 0, 0, 0, (void *)(128+'n')}, { NM_ITEM, "M-o #offer a sacrifice to the gods", 0, 0, 0, (void *)(128+'o')}, { NM_ITEM, "M-p #pray to the gods for help", 0, 0, 0, (void *)(128+'p')}, { NM_ITEM, "M-q #quit the game", 0, 0, 0, (void *)(128+'q')}, { NM_ITEM, "M-r #rub a lamp", 0, 0, 0, (void *)(128+'r')}, { NM_ITEM, "M-s #sit down", 0, 0, 0, (void *)(128+'s')}, { NM_ITEM, "M-t #turn undead", 0, 0, 0, (void *)(128+'t')}, { NM_ITEM, "M-u #untrap something", 0, 0, 0, (void *)(128+'u')}, { NM_ITEM, "M-v Long #version information", 0, 0, 0, (void *)(128+'v')}, { NM_ITEM, "M-w #wipe off your face", 0, 0, 0, (void *)(128+'w')}, { NM_ITEM, " Your #conduct", 0, 0, 0, (void *)'#'}, /* "#co\n" */ { NM_ITEM, " #ride your steed", 0, 0, 0, (void *)'#'}, /* "#ri\n" */ { NM_ITEM, "M-2 Switch #twoweapon mode on/off", 0, 0, 0, (void *)(128+'2')}, { NM_END, NULL, 0, 0, 0, 0} }; nethack-3.4.3/sys/amiga/amirip.c0100644000000000000000000002162707764735041015203 0ustar rootroot/* SCCS Id: @(#)amirip.c 3.2 96/02/04 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1991,1992,1993,1995,1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "winami.h" #include "windefs.h" #include "winext.h" #include "winproto.h" static struct RastPort *rp; #ifdef AMII_GRAPHICS #undef NULL #define NULL 0 #ifdef AZTEC_C # include #else # ifdef _DCC # include # include # include # include # else # include # include # include # include # endif static char *load_list[]={"tomb.iff",0}; static BitMapHeader tomb_bmhd; static struct BitMap *tbmp[ 1 ] = {0}; static int cols[2]={154,319}; /* X location of center of columns */ static int cno = 0; /* current column */ #define TEXT_TOP (65+yoff) static xoff, yoff; /* image centering */ /* terrible kludge */ /* this is why prototypes should have ONLY types in them! */ # undef red # undef green # undef blue # undef index # ifdef _DCC # include # include # else # include # include # endif #endif /* AZTEC_C */ extern char *killed_by_prefix[]; static struct Window *ripwin=0; static void tomb_text(char*); static void dofade(int,int,int); static int search_cmap(int,int,int); #define STONE_LINE_LEN 13 /* # chars that fit on one line * (note 1 ' ' border) */ #define DEATH_LINE 10 #define YEAR_LINE 15 static unsigned short tomb_line; extern struct amii_DisplayDesc *amiIDisplay; extern struct Screen *HackScreen; extern int havelace; static unsigned short transpalette[ AMII_MAXCOLORS ] = { 0x0000, }; static struct NewWindow newwin = { 0,0,640,200,1,0, MOUSEBUTTONS|VANILLAKEY|NOCAREREFRESH, BORDERLESS|ACTIVATE|SMART_REFRESH, NULL,NULL,(UBYTE*)NULL,NULL,NULL,-1,-1,0xffff,0xffff,CUSTOMSCREEN }; int wh; /* was local in outrip, but needed for SCALE macro */ int cmap_white, cmap_black; void amii_outrip( tmpwin, how ) winid tmpwin; int how; { int just_return = 0; int done, rtxth; struct IntuiMessage *imsg; int i; register char *dpx; char buf[ 200 ]; int line, tw, ww; char *errstr = NULL; if(!WINVERS_AMIV || HackScreen->RastPort.BitMap->Depth < 4)goto cleanup; /* Use the users display size */ newwin.Height = amiIDisplay->ypix - newwin.TopEdge; newwin.Width = amiIDisplay->xpix; newwin.Screen = HackScreen; for( i = 0; i < amii_numcolors; ++i ) flags.amii_curmap[i] = GetRGB4( HackScreen->ViewPort.ColorMap, i ); ripwin = OpenWindow( (void *)&newwin ); if( !ripwin ) goto cleanup; LoadRGB4( &HackScreen->ViewPort, transpalette, amii_numcolors ); rp= ripwin->RPort; wh = ripwin->Height; ww = ripwin->Width; #ifdef HACKFONT if (HackFont) SetFont(rp, HackFont); #endif tomb_bmhd = ReadImageFiles(load_list, tbmp, &errstr ); if(errstr)goto cleanup; if(tomb_bmhd.w > ww || tomb_bmhd.h > wh)goto cleanup; #define GENOFF(full,used) ((((full)-(used))/2) & ~7) xoff = GENOFF(ww,tomb_bmhd.w); yoff = GENOFF(wh,tomb_bmhd.h); for(i=0;iBitMap, xoff, yoff, tomb_bmhd.w, tomb_bmhd.h, 0xc0, 0xff, NULL); /* Put together death description */ switch (killer_format) { default: impossible("bad killer format?"); case KILLED_BY_AN: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, an(killer)); break; case KILLED_BY: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, killer); break; case NO_KILLER_PREFIX: Strcpy(buf, killer); break; } tw = TextLength(rp,buf,STONE_LINE_LEN) + 40; { char *p=buf; int x, tmp; for(x=STONE_LINE_LEN;x;x--)*p++='W'; *p='\0'; tmp = TextLength(rp,buf,STONE_LINE_LEN) + 40; tw = max( tw, tmp); } /* There are 5 lines of text on the stone. */ rtxth = ripwin->RPort->TxHeight * 5; SetAfPt( rp, (UWORD *)NULL, 0 ); SetDrPt( rp, 0xFFFF ); tomb_line=TEXT_TOP; SetDrMd(rp,JAM1); /* Put name on stone */ Sprintf(buf, "%s", plname); buf[STONE_LINE_LEN] = 0; tomb_text(buf); /* Put $ on stone */ Sprintf(buf, "%ld Au", #ifndef GOLDOBJ u.ugold); #else done_money); #endif buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ tomb_text(buf); /* Put together death description */ switch (killer_format) { default: impossible("bad killer format?"); case KILLED_BY_AN: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, an(killer)); break; case KILLED_BY: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, killer); break; case NO_KILLER_PREFIX: Strcpy(buf, killer); break; } /* Put death type on stone */ for (line=DEATH_LINE, dpx = buf; line STONE_LINE_LEN) { for(i=STONE_LINE_LEN;((i0 > STONE_LINE_LEN) && i); i--) { if(dpx[i] == ' ') i0 = i; } if(!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; tomb_text(dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx= &dpx[i0]; } else { dpx= &dpx[i0+1]; } } /* Put year on stone */ Sprintf(buf, "%4d", getyear()); tomb_text(buf); #ifdef NH320_DEDICATION /* dedication */ cno = 1; tomb_line=TEXT_TOP; tomb_text("This release"); tomb_text("of NetHack"); tomb_text("is dedicated"); tomb_text("to the"); tomb_text("memory of"); tomb_text(""); tomb_text("Izchak"); tomb_text(" Miller"); tomb_text(""); tomb_text("1935-1994"); tomb_text(""); tomb_text("Ascended"); #endif /* Fade from black to full color */ dofade(0,16,1); /* Flush all messages to avoid typeahead */ while( imsg = (struct IntuiMessage *)GetMsg( ripwin->UserPort ) ) ReplyMsg( (struct Message *) imsg ); done = 0; while( !done ) { WaitPort( ripwin->UserPort ); while( imsg = (struct IntuiMessage *)GetMsg(ripwin->UserPort) ) { switch( imsg->Class ) { case MOUSEBUTTONS: case VANILLAKEY: done = 1; break; } ReplyMsg( (struct Message *)imsg ); } } /* Fade out */ dofade(16,0,-1); just_return = 1; cleanup: /* free everything */ if(ripwin){ Forbid(); while( imsg = (struct IntuiMessage *)GetMsg( ripwin->UserPort ) ) ReplyMsg( (struct Message *)imsg ); CloseWindow( ripwin ); Permit(); } LoadRGB4( &HackScreen->ViewPort, flags.amii_curmap, amii_numcolors ); if(tbmp[0])FreeImageFiles(load_list, tbmp); if(just_return) return; /* fall back to the straight-ASCII version */ genl_outrip(tmpwin, how); } static void tomb_text(p) char *p; { char buf[STONE_LINE_LEN*2]; int l; tomb_line += rp->TxHeight; if( !*p ) return; sprintf(buf," %s ",p); l=TextLength(rp,buf,strlen(buf)); SetAPen(rp,cmap_white); Move(rp,cols[cno]-(l/2)-1, tomb_line); Text(rp,buf,strlen(buf)); SetAPen(rp,cmap_white); Move(rp,cols[cno]-(l/2)+1, tomb_line); Text(rp,buf,strlen(buf)); SetAPen(rp,cmap_white); Move(rp,cols[cno]-(l/2), tomb_line-1); Text(rp,buf,strlen(buf)); SetAPen(rp,cmap_white); Move(rp,cols[cno]-(l/2), tomb_line+1); Text(rp,buf,strlen(buf)); SetAPen(rp,cmap_black); Move(rp,cols[cno]-(l/2), tomb_line); Text(rp,buf,strlen(buf)); } /* search colormap for best match to given color */ static int search_cmap(int r0, int g0, int b0){ int best = 0; int bdiff = 0x0fffffff; int x; for(x=0;x> 8) & 15); int g = g0-((amiv_init_map[x] >> 4) & 15); int b = b0-((amiv_init_map[x] ) & 15); int diff = (r*r) + (g*g) + (b*b); if(diff> 8; g = ( amiv_init_map[ j ] & 0xf0 ) >> 4; b = ( amiv_init_map[ j ] & 0xf ); r = ( r * i ) / 16; g = ( g * i ) / 16; b = ( b * i ) / 16; transpalette[ j ] = ((r<<8)|(g<<4)|b); } LoadRGB4( &HackScreen->ViewPort, transpalette, amii_numcolors ); Delay( 1 ); } } #endif /* AMII_GRAPHICS */ /* TODO: memory leaks fix ReadImageFiles to return error instead of panic on error */ nethack-3.4.3/sys/amiga/amisnd.c0100644000000000000000000001646407764735041015200 0ustar rootroot/* SCCS Id: @(#)amisnd.c 3.2 2000/01/12*/ /* Copyright (c) 1992, 1993, 1995 by Gregg Wonderly */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains music playing code. * * If we were REALLY determined, we would make the sound play * asynchronously, but I'll save that one for a rainy day... */ #include "hack.h" #include "dlb.h" #undef red #undef blue #undef green #include #include #include #include #include #include #include #include #include #include #include #include #include #define AMII_AVERAGE_VOLUME 60 int amii_volume = AMII_AVERAGE_VOLUME; typedef struct VHDR { char name[4]; long len; unsigned long oneshot, repeat, samples; UWORD freq; UBYTE n_octaves, compress; LONG volume; } VHDR; typedef struct IFFHEAD { char FORM[4]; long flen; char _8SVX[4]; VHDR vhdr; char NAME[4]; long namelen; } IFFHEAD; extern struct GfxBase *GfxBase; UBYTE whichannel[] = { 1, 2, 4, 8 }; void makesound( char *, char *, int vol); void amii_speaker( struct obj *instr, char *melody, int vol ); /* A major scale in indexs to freqtab... */ int notetab[] = { 0, 2, 4, 5, 7, 9, 11, 12 }; /* Frequencies for a scale starting at one octave below 'middle C' */ long freqtab[] = { 220, /*A */ 233, /*Bb*/ 246, /*B */ 261, /*C */ 277, /*Db*/ 293, /*D */ 311, /*Eb*/ 329, /*E */ 349, /*F */ 370, /*Gb*/ 392, /*G */ 415, /*Ab*/ 440, /*A */ }; #ifdef TESTING main( argc, argv ) int argc; char **argv; { makesound( "wooden_flute", "AwBwCwDwEwFwGwawbwcwdwewfwgw", 60 ); makesound( "wooden_flute", "AhBhChDhEhFhGhahbhchdhehfhgh", 60 ); makesound( "wooden_flute", "AqBqCqDqEqFqGqaqbqcqdqeqfqgq", 60 ); makesound( "wooden_flute", "AeBeCeDeEeFeGeaebecedeeefege", 60 ); makesound( "wooden_flute", "AxBxCxDxExFxGxaxbxcxdxexfxgx", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); makesound( "wooden_flute", "AtBtCtDtEtFtGtatbtctdtetftgt", 60 ); } #else void amii_speaker( struct obj *instr, char *melody, int vol ) { int typ = instr->otyp; char * actualn = (char *)OBJ_NAME( objects[typ] ) ; /* Make volume be relative to users volume level, with 60 being the * average level that will be passed to us. */ vol = vol * amii_volume / AMII_AVERAGE_VOLUME; makesound( actualn, melody, vol ); } #endif void makesound ( char *actualn , char * melody, int vol ) { char *t; int c, cycles, dot, dlay; dlb *stream = 0; IFFHEAD iffhead; struct IOAudio *AudioIO = 0; struct MsgPort *AudioMP = 0; struct Message *AudioMSG = 0; ULONG device = -1; BYTE *waveptr = 0; LONG frequency=440, duration=1, clock, samp, samples, samcyc=1; unsigned char name [ 100 ] ; if ( flags.silent ) return; if( GfxBase->DisplayFlags & PAL ) clock = 3546895; else clock = 3579545; /* * Convert type to file name - if there's nothing to play we * shouldn't be here in the first place. */ strncpy(name, actualn,sizeof(name) ) ; for( t = strchr( name, ' ' ); t; t = strchr( name, ' ' ) ) *t = '_'; if( (stream = dlb_fopen( name, "r" )) == NULL ) { perror( name ); return; } AudioIO = (struct IOAudio *) AllocMem( sizeof( struct IOAudio ), MEMF_PUBLIC|MEMF_CLEAR ); if( AudioIO == 0 ) goto killaudio; AudioMP = CreateMsgPort(); if( AudioMP == 0 ) goto killaudio; AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP; AudioIO->ioa_Request.io_Message.mn_Node.ln_Pri = 0; AudioIO->ioa_Request.io_Command = ADCMD_ALLOCATE; AudioIO->ioa_Request.io_Flags = ADIOF_NOWAIT; AudioIO->ioa_AllocKey = 0; AudioIO->ioa_Data = whichannel; AudioIO->ioa_Length = sizeof( whichannel ); device = OpenDevice( AUDIONAME, 0L, (struct IORequest *)AudioIO, 0L ); if( device != 0 ) goto killaudio; if( dlb_fread( (genericptr_t)&iffhead, sizeof( iffhead ), 1, stream ) != 1 ) goto killaudio; /* This is an even number of bytes long */ if( dlb_fread( name, (iffhead.namelen+1) & ~1, 1, stream ) != 1 ) goto killaudio; if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 ) goto killaudio; if( dlb_fread( (genericptr_t)&samples, 4, 1, stream ) != 1 ) goto killaudio; waveptr = AllocMem( samples, MEMF_CHIP|MEMF_PUBLIC ); if( !waveptr ) goto killaudio; if( dlb_fread( waveptr, samples, 1, stream ) != 1 ) goto killaudio; while( melody[0] && melody[1] ) { c = *melody++; duration = *melody++; dot = 0; if( *melody == '.' ) { dot = 1; ++melody; } switch( duration ) { case 'w': dlay = 3; duration = 1; cycles = 1; break; case 'h': dlay = 3; duration = 2; cycles = 1; break; case 'q': dlay = 2; duration = 4; cycles = 1; break; case 'e': dlay = 1; duration = 8; cycles = 1; break; case 'x': dlay = 0; duration = 16; cycles = 1; break; case 't': dlay = 0; duration = 32; cycles = 1; break; default: goto killaudio; /* unrecognized duration */ } /* Lower case characters are one octave above upper case */ switch( c ) { case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': c -= 'a' - 7; break; case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': c -= 'A'; break; default: continue; } samcyc = samples; /* lowercase start at middle 'C', upper case are one octave below */ frequency = c > 7 ? freqtab[notetab[c%7]]*2 : freqtab[notetab[c]]; /* We can't actually do a dotted whole note unless we add code for a real * 8SVX sample which includes sustain sample information to tell us how * to hold the note steady... So when duration == 1, ignore 'dot'... */ if( dot && duration > 1 ) samp = ((samples / duration) * 3) / 2; else samp = samples / duration; /* Only use some of the samples based on frequency */ samp = frequency * samp / 880; /* The 22khz samples are middle C samples, so adjust the play * back frequency accordingly */ frequency = (frequency * (iffhead.vhdr.freq*2)/3) / 440L; AudioIO->ioa_Request.io_Message.mn_ReplyPort = AudioMP; AudioIO->ioa_Request.io_Command = CMD_WRITE; AudioIO->ioa_Request.io_Flags = ADIOF_PERVOL; AudioIO->ioa_Data = (BYTE *)waveptr; AudioIO->ioa_Length = samp; /* The clock rate represents the unity rate, so dividing by * the frequency gives us a period ratio... */ /*printf( "clock: %ld, freq: %ld, div: %ld\n", clock, frequency, clock/frequency );*/ AudioIO->ioa_Period = clock/frequency; AudioIO->ioa_Volume = vol; AudioIO->ioa_Cycles = cycles; BeginIO( (struct IORequest *)AudioIO ); WaitPort( AudioMP ); AudioMSG = GetMsg( AudioMP ); if( dlay ) Delay( dlay ); } killaudio: if( stream ) dlb_fclose( stream ); if( waveptr ) FreeMem( waveptr, samples ); if( device == 0 ) CloseDevice( (struct IORequest *)AudioIO ); if( AudioMP ) DeleteMsgPort( AudioMP ); if( AudioIO ) FreeMem( AudioIO, sizeof( *AudioIO ) ); } nethack-3.4.3/sys/amiga/amistack.c0100644000000000000000000000077307764735041015515 0ustar rootroot/* SCCS Id: @(#)amistack.c 3.4 2000/05/03 */ /* Copyright (c) Janne Salmijärvi, Tampere, Finland, 2000 */ /* NetHack may be freely redistributed. See license for details. */ /* * Increase stack size to allow deep recursions. * * Note: This is SAS/C specific, using other compiler probably * requires another method for increasing stack. * */ #ifdef __SASC_60 #include /* * At the moment 90*1024 would suffice, but just to be on the safe side ... */ long __stack = 128*1024; #endif nethack-3.4.3/sys/amiga/amitty.c0100644000000000000000000000257507764735041015232 0ustar rootroot/* SCCS Id: @(#)amitty.c 3.2 2000/01/12 /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996 */ /* NetHack may be freely redistributed. See license for details. */ /* TTY-specific code for the Amiga * This is still experimental. * Still to do: * add real termcap handling - currently requires ANSI_DEFAULT */ #include "hack.h" #include "tcap.h" #include #include #ifdef _DCC # define getch() getchar() #endif #ifdef __SASC_60 # include #endif void NDECL( tty_change_color ); char *NDECL( tty_get_color_string ); #ifdef TTY_GRAPHICS int amibbs=0; /* BBS mode */ char bbs_id[80]=""; /* BBS uid equivalent */ long afh_in, afh_out; /* BBS mode Amiga filehandles */ void settty(const char *s){ end_screen(); if(s)raw_print(s); iflags.cbreak=ON; /* this is too easy: probably wrong */ #if 1 /* should be version>=36 */ /* if(IsInteractive(afh_in)){ */ SetMode(afh_in,0); /* con mode */ /* } */ #endif } void gettty(){ #if 1 /* should be VERSION >=36 */ /* if(IsInteractive(afh_in)){ */ SetMode(afh_in,1); /* raw mode */ /* } */ #endif } void setftty(){ iflags.cbreak=ON; /* ditto */ } char kill_char='X'-'@'; char erase_char='\b'; tgetch(){ char x; Read(afh_in,&x,1); return (x=='\r')?'\n':x; } void get_scr_size(){ CO=80; LI=24; } #endif void tty_change_color() {} char *tty_get_color_string() { return( "" ); } nethack-3.4.3/sys/amiga/amiwind.c0100644000000000000000000005166007764735041015352 0ustar rootroot/* SCCS Id: @(#)amiwind.c 3.2 2000/01/12 /* Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993,1996 */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" /* Have to undef CLOSE as display.h and intuition.h both use it */ #undef CLOSE #ifdef AMII_GRAPHICS /* too early in the file? too late? */ #ifdef AMIFLUSH static struct Message *FDECL(GetFMsg,(struct MsgPort *)); #endif static int BufferGetchar(void); static void ProcessMessage( register struct IntuiMessage *message ); #define BufferQueueChar(ch) (KbdBuffer[KbdBuffered++] = (ch)) struct Library *ConsoleDevice; #include "NH:sys/amiga/amimenu.c" /* Now our own variables */ struct IntuitionBase *IntuitionBase; struct Screen *HackScreen; struct Window *pr_WindowPtr; struct MsgPort *HackPort; struct IOStdReq ConsoleIO; struct Menu *MenuStrip; APTR *VisualInfo; char Initialized = 0; WEVENT lastevent; #ifdef HACKFONT struct GfxBase *GfxBase; struct Library *DiskfontBase; #endif #define KBDBUFFER 10 static unsigned char KbdBuffer[KBDBUFFER]; unsigned char KbdBuffered; #ifdef HACKFONT struct TextFont *TextsFont = NULL; struct TextFont *HackFont = NULL; struct TextFont *RogueFont = NULL; UBYTE FontName[] = "NetHack:hack.font"; /* # chars in "NetHack:": */ #define SIZEOF_DISKNAME 8 #endif struct TextAttr Hack80 = { #ifdef HACKFONT &FontName[SIZEOF_DISKNAME], #else (UBYTE *) "topaz.font", #endif 8, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED | FPF_ROMFONT }; struct TextAttr TextsFont13 = { (UBYTE *) "courier.font", 13, FS_NORMAL, FPF_DISKFONT | FPF_DESIGNED #ifndef HACKFONT | FPF_ROMFONT #endif }; /* Avoid doing a ReplyMsg through a window that no longer exists. */ static enum {NoAction, CloseOver} delayed_key_action = NoAction; /* * Open a window that shares the HackPort IDCMP. Use CloseShWindow() * to close. */ struct Window *OpenShWindow(nw) struct NewWindow *nw; { register struct Window *win; register ULONG idcmpflags; if (!HackPort) /* Sanity check */ return (struct Window *) 0; idcmpflags = nw->IDCMPFlags; nw->IDCMPFlags = 0; if (!(win = OpenWindow((void *)nw))) { nw->IDCMPFlags = idcmpflags; return (struct Window *) 0; } nw->IDCMPFlags = idcmpflags; win->UserPort = HackPort; ModifyIDCMP(win, idcmpflags); return win; } /* * Close a window that shared the HackPort IDCMP port. */ void FDECL(CloseShWindow, (struct Window *)); void CloseShWindow(win) struct Window *win; { register struct IntuiMessage *msg; if( !HackPort ) panic("HackPort NULL in CloseShWindow" ); if (!win) return; Forbid(); /* Flush all messages for all windows to avoid typeahead and other * similar problems... */ while( msg = (struct IntuiMessage *)GetMsg( win->UserPort ) ) ReplyMsg( (struct Message *) msg ); KbdBuffered = 0; win->UserPort = (struct MsgPort *) 0; ModifyIDCMP(win, 0L); Permit(); CloseWindow(win); } static int BufferGetchar() { register int c; if (KbdBuffered > 0) { c = KbdBuffer[0]; KbdBuffered--; /* Move the remaining characters */ if( KbdBuffered < sizeof( KbdBuffer ) ) memcpy( KbdBuffer, KbdBuffer+1, KbdBuffered ); return c; } return NO_CHAR; } /* * This should remind you remotely of DeadKeyConvert, but we are cheating * a bit. We want complete control over the numeric keypad, and no dead * keys... (they are assumed to be on Alted keys). * * Also assumed is that the IntuiMessage is of type RAWKEY. For some * reason, IECODE_UP_PREFIX events seem to be lost when they occur while * our console window is inactive. This is particulary troublesome with * qualifier keys... Is this because I never RawKeyConvert those events??? */ int ConvertKey(message) register struct IntuiMessage *message; { static struct InputEvent theEvent; static char numpad[] = "bjnh.lyku"; static char ctrl_numpad[] = "\x02\x0A\x0E\x08.\x0C\x19\x0B\x15"; static char shift_numpad[] = "BJNH.LYKU"; unsigned char buffer[10]; struct Window *w = message->IDCMPWindow; register int length; register ULONG qualifier; char numeric_pad, shift, control, alt; if( amii_wins[ WIN_MAP ] ) w = amii_wins[ WIN_MAP ]->win; qualifier = message->Qualifier; control = (qualifier & IEQUALIFIER_CONTROL) != 0; shift = (qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) != 0; alt = (qualifier & (IEQUALIFIER_LALT | IEQUALIFIER_RALT )) != 0; /* Allow ALT to function as a META key ... */ /* But make it switchable - alt is needed for some non-US keymaps */ if(flags.altmeta) qualifier &= ~(IEQUALIFIER_LALT | IEQUALIFIER_RALT); numeric_pad = (qualifier & IEQUALIFIER_NUMERICPAD) != 0; /* * Shortcut for HELP and arrow keys. I suppose this is allowed. * The defines are in intuition/intuition.h, and the keys don't * serve 'text' input, normally. Also, parsing their escape * sequences is such a mess... */ switch (message->Code) { case RAWHELP: if( alt ) { EditColor(); return( -1 ); } #ifdef CLIPPING else if( WINVERS_AMIV && control ) { EditClipping(); CO = ( w->Width - w->BorderLeft - w->BorderRight ) / mxsize; LI = ( w->Height - w->BorderTop - w->BorderBottom ) / mysize; clipxmax = CO + clipx; clipymax = LI + clipy; if( CO < COLNO || LI < ROWNO ) { clipping = TRUE; amii_cliparound( u.ux, u.uy ); } else { clipping = FALSE; clipx = clipy = 0; } BufferQueueChar( 'R'-64 ); return(-1); } #endif else if( WINVERS_AMIV && shift ) { if( WIN_OVER == WIN_ERR ) { WIN_OVER = amii_create_nhwindow( NHW_OVER ); BufferQueueChar( 'R'-64 ); } else { delayed_key_action = CloseOver; } return( -1 ); } return( '?' ); break; case CURSORLEFT: length = '4'; numeric_pad = 1; goto arrow; case CURSORDOWN: length = '2'; numeric_pad = 1; goto arrow; case CURSORUP: length = '8'; numeric_pad = 1; goto arrow; case CURSORRIGHT: length = '6'; numeric_pad = 1; goto arrow; } theEvent.ie_Class = IECLASS_RAWKEY; theEvent.ie_Code = message->Code; theEvent.ie_Qualifier = numeric_pad ? IEQUALIFIER_NUMERICPAD : qualifier; theEvent.ie_EventAddress = (APTR) (message->IAddress); length = RawKeyConvert(&theEvent, (char *)buffer, (long) sizeof(buffer), NULL); if (length == 1) { /* Plain ASCII character */ length = buffer[0]; /* * If iflags.num_pad is set, movement is by 4286. * If not set, translate 4286 into hjkl. * This way, the numeric pad can /always/ be used * for moving, though best results are when it is off. */ arrow: if (!iflags.num_pad && numeric_pad && length >= '1' && length <= '9') { length -= '1'; if (control) { length = ctrl_numpad[length]; } else if (shift) { length = shift_numpad[length]; } else { length = numpad[length]; } } /* Kludge to allow altmeta on eg. scandinavian keymap (# == shift+alt+3) and prevent it from interfering with # command (M-#) */ if (length == ('#'|0x80)) return '#'; if (alt && flags.altmeta) length |= 0x80; return(length); } /* else shift, ctrl, alt, amiga, F-key, shift-tab, etc */ else if( length > 1 ) { int i; if( length == 3 && buffer[ 0 ] == 155 && buffer[ 2 ] == 126 ) { int got = 1; switch( buffer[ 1 ] ) { case 53: mxsize = mysize = 8; break; case 54: mxsize = mysize = 16; break; case 55: mxsize = mysize = 24; break; case 56: mxsize = mysize = 32; break; case 57: mxsize = mysize = 48; break; default: got = 0; break; } #ifdef OPT_DISPMAP dispmap_sanity(); #endif if( got ) { CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize; LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize; clipxmax = CO + clipx; clipymax = LI + clipy; if( CO < COLNO || LI < ROWNO ) { amii_cliparound( u.ux, u.uy ); } else { CO = COLNO; LI = ROWNO; } reclip = 1; doredraw(); flush_screen( 1 ); reclip = 0; /*BufferQueueChar( 'R'-64 );*/ return( -1 ); } } printf( "Unrecognized key: %d ", (int)buffer[0]); for( i = 1; i < length; ++i ) printf( "%d ", (int)buffer[i]); printf( "\n" ); } return( -1 ); } /* * Process an incoming IntuiMessage. * It would certainly look nicer if this could be done using a * PA_SOFTINT message port, but we cannot call RawKeyConvert() * during a software interrupt. * Anyway, amikbhit()/kbhit() is called often enough, and usually gets * ahead of input demands, when the user types ahead. */ static void ProcessMessage(message) register struct IntuiMessage *message; { int c; int cnt; menu_item *mip; static int skip_mouse=0; /* need to ignore next mouse event on * a window activation */ struct Window *w = message->IDCMPWindow; switch(message->Class) { case ACTIVEWINDOW: if( alwaysinvent && WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win ) { cnt = DoMenuScroll( WIN_INVEN, 0, PICK_NONE, &mip ); } else if( scrollmsg && WIN_MESSAGE != WIN_ERR && w == amii_wins[ WIN_MESSAGE ]->win ) { cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip ); } else { skip_mouse=1; } break; case MOUSEBUTTONS: { if( skip_mouse ) { skip_mouse=0; break; } if( !amii_wins[ WIN_MAP ] || w != amii_wins[ WIN_MAP ]->win ) break; if( message->Code == SELECTDOWN ) { lastevent.type = WEMOUSE; lastevent.un.mouse.x = message->MouseX; lastevent.un.mouse.y = message->MouseY; /* With shift equals RUN */ lastevent.un.mouse.qual = (message->Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) != 0; } } break; case MENUPICK: { USHORT thismenu; struct MenuItem *item; thismenu = message->Code; while (thismenu != MENUNULL) { item = ItemAddress(MenuStrip, (ULONG) thismenu); if (KbdBuffered < KBDBUFFER) BufferQueueChar((char)(GTMENUITEM_USERDATA(item))); thismenu = item->NextSelect; } } break; case REFRESHWINDOW: { if( scrollmsg && amii_wins[ WIN_MESSAGE ] && w == amii_wins[ WIN_MESSAGE ]->win ){ cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip ); } } break; case CLOSEWINDOW: if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win ) { dismiss_nhwindow( WIN_INVEN ); } if( WINVERS_AMIV && ( WIN_OVER != WIN_ERR && w == amii_wins[ WIN_OVER ]->win ) ){ destroy_nhwindow( WIN_OVER ); WIN_OVER = WIN_ERR; } break; case RAWKEY: if (!(message->Code & IECODE_UP_PREFIX)){ /* May queue multiple characters * but doesn't do that yet... */ if( ( c = ConvertKey(message) ) > 0 ) BufferQueueChar( c ); } break; case GADGETDOWN: if( WIN_MESSAGE != WIN_ERR && w == amii_wins[ WIN_MESSAGE ]->win ) { cnt = DoMenuScroll( WIN_MESSAGE, 0, PICK_NONE, &mip ); } else if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win ) { cnt = DoMenuScroll( WIN_INVEN, 0, PICK_NONE, &mip ); } break; case NEWSIZE: if( WIN_MESSAGE != WIN_ERR && w == amii_wins[ WIN_MESSAGE ]->win ) { if( WINVERS_AMIV ) { /* Make sure that new size is honored for good. */ SetAPen( w->RPort, amii_msgBPen ); SetBPen( w->RPort, amii_msgBPen ); SetDrMd( w->RPort, JAM2 ); RectFill( w->RPort, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight-1, w->Height - w->BorderBottom-1 ); } ReDisplayData( WIN_MESSAGE ); } else if( WIN_INVEN != WIN_ERR && w == amii_wins[ WIN_INVEN ]->win ) { ReDisplayData( WIN_INVEN ); } else if( WINVERS_AMIV && ( WIN_OVER != WIN_ERR && w == amii_wins[ WIN_OVER ]->win ) ){ BufferQueueChar( 'R'-64 ); } else if( WIN_MAP != WIN_ERR && w == amii_wins[ WIN_MAP ]->win ) { #ifdef CLIPPING CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize; LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize; clipxmax = CO + clipx; clipymax = LI + clipy; if( CO < COLNO || LI < ROWNO ) { amii_cliparound( u.ux, u.uy ); } else { clipping = FALSE; clipx = clipy = 0; } BufferQueueChar( 'R'-64 ); #endif } break; } ReplyMsg((struct Message *) message); switch(delayed_key_action){ case CloseOver: amii_destroy_nhwindow( WIN_OVER ); WIN_OVER = WIN_ERR; delayed_key_action = NoAction; case NoAction: ; /* null */ } } #endif /* AMII_GRAPHICS */ /* * Get all incoming messages and fill up the keyboard buffer, * thus allowing Intuition to (maybe) free up the IntuiMessages. * Return when no more messages left, or keyboard buffer half full. * We need to do this since there is no one-to-one correspondence * between characters and incoming messages. */ #if defined(TTY_GRAPHICS) && !defined(AMII_GRAPHICS) int kbhit(){ return 0; } #else int kbhit() { int c; # ifdef TTY_GRAPHICS /* a kludge to defuse the mess in allmain.c */ /* I hope this is the right approach */ if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows)return 0; # endif c = amikbhit(); if( c <= 0 ) return( 0 ); return( c ); } #endif #ifdef AMII_GRAPHICS int amikbhit() { register struct IntuiMessage *message; while( KbdBuffered < KBDBUFFER / 2 ) { #ifdef AMIFLUSH message = (struct IntuiMessage *) GetFMsg(HackPort); #else message = (struct IntuiMessage *) GetMsg(HackPort); #endif if(message) { ProcessMessage(message); if( lastevent.type != WEUNK && lastevent.type != WEKEY ) break; } else break; } return ( lastevent.type == WEUNK ) ? KbdBuffered : -1; } /* * Get a character from the keyboard buffer, waiting if not available. * Ignore other kinds of events that happen in the mean time. */ int WindowGetchar( ) { while ((lastevent.type = WEUNK), amikbhit() <= 0) { WaitPort(HackPort); } return BufferGetchar(); } WETYPE WindowGetevent() { lastevent.type = WEUNK; while (amikbhit() == 0) { WaitPort(HackPort); } if( KbdBuffered ) { lastevent.type = WEKEY; lastevent.un.key = BufferGetchar(); } return( lastevent.type ); } /* * Clean up everything. But before we do, ask the user to hit return * when there is something that s/he should read. */ void amii_cleanup() { register struct IntuiMessage *msg; /* Close things up */ if( HackPort ) { amii_raw_print(""); amii_getret(); } if (ConsoleIO.io_Device) CloseDevice( (struct IORequest *)&ConsoleIO ); ConsoleIO.io_Device = 0; if( ConsoleIO.io_Message.mn_ReplyPort ) DeleteMsgPort( ConsoleIO.io_Message.mn_ReplyPort ); ConsoleIO.io_Message.mn_ReplyPort = 0; /* Strip messages before deleting the port */ if( HackPort ) { Forbid(); while (msg = (struct IntuiMessage *) GetMsg(HackPort)) ReplyMsg((struct Message *) msg); kill_nhwindows( 1 ); DeleteMsgPort( HackPort ); HackPort = NULL; Permit(); } /* Close the screen, under v37 or greater it is a pub screen and there may * be visitors, so check close status and wait till everyone is gone. */ if( HackScreen ) { #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { if (MenuStrip) FreeMenus(MenuStrip); if (VisualInfo) FreeVisualInfo(VisualInfo); while( CloseScreen( HackScreen ) == FALSE ) { struct EasyStruct easy = { sizeof( struct EasyStruct ), 0, "Nethack Problem", "Can't Close Screen, Close Visiting Windows", "Okay" }; EasyRequest( NULL, &easy, NULL, NULL ); } } else #endif { CloseScreen(HackScreen); } HackScreen = NULL; } #ifdef HACKFONT if (HackFont) { CloseFont(HackFont); HackFont = NULL; } if( TextsFont ) { CloseFont( TextsFont ); TextsFont = NULL; } if( RogueFont ) { CloseFont( RogueFont ); RogueFont = NULL; } if( DiskfontBase ) { CloseLibrary(DiskfontBase); DiskfontBase = NULL; } #endif if (GadToolsBase) { CloseLibrary((struct Library *)GadToolsBase); GadToolsBase=NULL; } if (LayersBase) { CloseLibrary((struct Library *)LayersBase); LayersBase = NULL; } if (GfxBase) { CloseLibrary((struct Library *)GfxBase); GfxBase = NULL; } if (IntuitionBase) { CloseLibrary((struct Library *)IntuitionBase); IntuitionBase = NULL; } #ifdef SHAREDLIB if (DOSBase) { CloseLibrary((struct Library *)DOSBase); DOSBase = NULL; } #endif ((struct Process *) FindTask(NULL))->pr_WindowPtr = (APTR) pr_WindowPtr; Initialized = 0; } #endif /* AMII_GRAPHICS */ #ifndef SHAREDLIB void Abort(rc) long rc; { int fault = 1; #ifdef CHDIR extern char orgdir[]; chdir(orgdir); #endif #ifdef AMII_GRAPHICS if (Initialized && ConsoleDevice && windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows) { printf("\n\nAbort with alert code %08lx...\n", rc); amii_getret(); } else #endif printf("\n\nAbort with alert code %08lx...\n",rc); /* Alert(rc); this is too severe */ #ifdef __SASC # ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { struct EasyStruct es = { sizeof( struct EasyStruct ), 0, "NetHack Panic Request", "NetHack is Aborting with code == 0x%08lx", "Continue Abort|Return to Program|Clean up and exit", }; fault = EasyRequest( NULL, &es, NULL, (long)rc ); if( fault == 2 ) return; } # endif if( fault == 1 ) { /* __emit(0x4afc); */ /* illegal instruction */ __emit(0x40fc); /* divide by */ __emit(0x0000); /* #0 */ /* NOTE: don't move amii_cleanup() above here - */ /* it is too likely to kill the system */ /* before it can get the SnapShot out, if */ /* there is something really wrong. */ } #endif #ifdef AMII_GRAPHICS if(windowprocs.win_init_nhwindows==amii_procs.win_init_nhwindows) amii_cleanup(); #endif #undef exit #ifdef AZTEC_C _abort(); #endif exit((int) rc); } void CleanUp() { amii_cleanup(); } #endif #ifdef AMII_GRAPHICS #ifdef AMIFLUSH /* This routine adapted from AmigaMail IV-37 by Michael Sinz */ static struct Message * GetFMsg(port) struct MsgPort *port; { struct IntuiMessage *msg,*succ,*succ1; if(msg=(struct IntuiMessage *)GetMsg(port)){ if(!flags.amiflush)return((struct Message *)msg); if(msg->Class==RAWKEY){ Forbid(); succ=(struct IntuiMessage *)(port->mp_MsgList.lh_Head); while(succ1=(struct IntuiMessage *) (succ->ExecMessage.mn_Node.ln_Succ)){ if(succ->Class==RAWKEY){ Remove((struct Node *)succ); ReplyMsg((struct Message *)succ); } succ=succ1; } Permit(); } } return((struct Message *)msg); } #endif struct NewWindow * DupNewWindow( win ) struct NewWindow *win; { struct NewWindow *nwin; struct Gadget *ngd, *gd, *pgd = NULL; struct PropInfo *pip; struct StringInfo *sip; /* Copy the (Ext)NewWindow structure */ nwin = (struct NewWindow *)alloc( sizeof( struct NewWindow ) ); *nwin = *win; /* Now do the gadget list */ nwin->FirstGadget = NULL; for( gd = win->FirstGadget; gd; gd = gd->NextGadget ) { ngd = (struct Gadget *)alloc( sizeof( struct Gadget ) ); *ngd = *gd; if( gd->GadgetType == STRGADGET ) { sip = (struct StringInfo *)alloc( sizeof( struct StringInfo ) ); *sip = *((struct StringInfo *)gd->SpecialInfo); sip->Buffer = (UBYTE *) alloc( sip->MaxChars ); *sip->Buffer = 0; ngd->SpecialInfo = (APTR)sip; } else if( gd->GadgetType == PROPGADGET ) { pip = (struct PropInfo *)alloc( sizeof( struct PropInfo ) ); *pip = *((struct PropInfo *)gd->SpecialInfo); ngd->SpecialInfo = (APTR)pip; } if( pgd ) pgd->NextGadget = ngd; else nwin->FirstGadget = ngd; pgd = ngd; ngd->NextGadget = NULL; ngd->UserData = (APTR) 0x45f35c3d; // magic cookie for FreeNewWindow() } return( nwin ); } void FreeNewWindow( win ) struct NewWindow *win; { register struct Gadget *gd, *pgd; register struct StringInfo *sip; for( gd = win->FirstGadget; gd; gd = pgd ) { pgd = gd->NextGadget; if ((ULONG)gd->UserData == 0x45f35c3d) { if( gd->GadgetType == STRGADGET ) { sip = (struct StringInfo *)gd->SpecialInfo; free( sip->Buffer ); free( sip ); } else if( gd->GadgetType == PROPGADGET ) { free( (struct PropInfo *)gd->SpecialInfo ); } free( gd ); } } free( win ); } void bell() { if (flags.silent) return; DisplayBeep(NULL); } void amii_delay_output() { /* delay 50 ms */ Delay(2L); } void amii_number_pad(state) int state; { } #endif /* AMII_GRAPHICS */ #ifndef SHAREDLIB void amiv_loadlib( void ) { } void amii_loadlib( void ) { } /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *, s) VA_START(s); VA_INIT(s, char *); putchar('\n'); vprintf(s, VA_ARGS); putchar('\n'); VA_END(); Abort(0L); } #endif nethack-3.4.3/sys/amiga/amiwind.p0100644000000000000000000000256707764735041015371 0ustar rootroot/* SCCS Id: @(#)amiwind.p 3.1 93/01/08 */ /* Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* amiwind.c */ #ifdef INTUI_NEW_LOOK struct Window *FDECL( OpenShWindow, (struct ExtNewWindow *) ); #else struct Window *FDECL( OpenShWindow, (struct NewWindow *) ); #endif void FDECL( CloseShWindow, (struct Window *)); int NDECL( kbhit ); int NDECL( amikbhit ); int NDECL( WindowGetchar ); WETYPE NDECL( WindowGetevent ); void NDECL( WindowFlush ); void FDECL( WindowPutchar, (char )); void FDECL( WindowFPuts, (const char *)); void FDECL( WindowPuts, (const char *)); void FDECL( WindowPrintf, ( char *,... )); void NDECL( CleanUp ); int FDECL( ConvertKey, ( struct IntuiMessage * )); #ifndef SHAREDLIB void FDECL( Abort, (long )); #endif void FDECL( flush_glyph_buffer, (struct Window *)); void FDECL( amiga_print_glyph, (winid , int , int )); void FDECL( start_glyphout, (winid )); void FDECL( amii_end_glyphout, (winid )); #ifdef INTUI_NEW_LOOK struct ExtNewWindow *FDECL( DupNewWindow, (struct ExtNewWindow *)); void FDECL( FreeNewWindow, (struct ExtNewWindow *)); #else struct NewWindow *FDECL( DupNewWindow, (struct NewWindow *)); void FDECL( FreeNewWindow, (struct NewWindow *)); #endif void NDECL( bell ); void NDECL( amii_delay_output ); void FDECL( amii_number_pad, (int )); void amii_cleanup( void ); nethack-3.4.3/sys/amiga/clipwin.c0100644000000000000000000002153407764735041015364 0ustar rootrootstatic USHORT Palette[] = { 0x0AAA, /* color #0 */ 0x0000, /* color #1 */ 0x0FFF, /* color #2 */ 0x058B, /* color #3 */ 0x000F, /* color #4 */ 0x0F0F, /* color #5 */ 0x00FF, /* color #6 */ 0x0FFF /* color #7 */ #define PaletteColorCount 8 }; #define PALETTE Palette static SHORT ClipBorderVectors1[] = { 0,0, 76,0, 76,11, 0,11, 0,0 }; static struct Border ClipBorder1 = { -1,-1, /* XY origin relative to container TopLeft */ 3,0,JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ ClipBorderVectors1, /* pointer to XY vectors */ NULL /* next border in list */ }; static struct IntuiText ClipIText1 = { 4,0,JAM1, /* front and back text pens, drawmode and fill byte */ 15,1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Cancel", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipCancel = { NULL, /* next gadget */ 240,59, /* origin XY of hit box relative to window TopLeft */ 75,10, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR)&ClipBorder1, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText1, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADCANCEL, /* user-definable data */ NULL /* pointer to user-definable data */ }; static SHORT ClipBorderVectors2[] = { 0,0, 78,0, 78,11, 0,11, 0,0 }; static struct Border ClipBorder2 = { -1,-1, /* XY origin relative to container TopLeft */ 3,0,JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ ClipBorderVectors2, /* pointer to XY vectors */ NULL /* next border in list */ }; static struct IntuiText ClipIText2 = { 4,0,JAM1, /* front and back text pens, drawmode and fill byte */ 24,1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Okay", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipOkay = { &ClipCancel, /* next gadget */ 17,60, /* origin XY of hit box relative to window TopLeft */ 77,10, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR)&ClipBorder2, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText2, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADOKAY, /* user-definable data */ NULL /* pointer to user-definable data */ }; static struct PropInfo ClipClipXCLIPSInfo = { AUTOKNOB+FREEHORIZ, /* PropInfo flags */ 24504,-1, /* horizontal and vertical pot values */ 10922,-1, /* horizontal and vertical body values */ }; static struct Image ClipImage1 = { 43,0, /* XY origin relative to container TopLeft */ 24,3, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000,0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; static struct IntuiText ClipIText3 = { 3,0,JAM1, /* front and back text pens, drawmode and fill byte */ -116,-1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "X Clip Border:", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipXCLIP = { &ClipOkay, /* next gadget */ 134,37, /* origin XY of hit box relative to window TopLeft */ -199,7, /* hit box width and height */ GRELWIDTH, /* gadget flags */ RELVERIFY+GADGIMMEDIATE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR)&ClipImage1, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText3, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR)&ClipClipXCLIPSInfo, /* SpecialInfo structure */ XCLIP, /* user-definable data */ NULL /* pointer to user-definable data */ }; static struct PropInfo ClipClipYCLIPSInfo = { AUTOKNOB+FREEHORIZ, /* PropInfo flags */ 13106,-1, /* horizontal and vertical pot values */ 10922,-1, /* horizontal and vertical body values */ }; static struct Image ClipImage2 = { 22,0, /* XY origin relative to container TopLeft */ 24,3, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000,0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; static struct IntuiText ClipIText4 = { 3,0,JAM1, /* front and back text pens, drawmode and fill byte */ -116,-1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Y Clip Border:", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipYCLIP = { &ClipXCLIP, /* next gadget */ 134,46, /* origin XY of hit box relative to window TopLeft */ -199,7, /* hit box width and height */ GRELWIDTH, /* gadget flags */ RELVERIFY+GADGIMMEDIATE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR)&ClipImage2, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText4, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR)&ClipClipYCLIPSInfo, /* SpecialInfo structure */ YCLIP, /* user-definable data */ NULL /* pointer to user-definable data */ }; static struct PropInfo ClipClipXSIZESInfo = { AUTOKNOB+FREEHORIZ, /* PropInfo flags */ 26212,-1, /* horizontal and vertical pot values */ 10922,-1, /* horizontal and vertical body values */ }; static struct Image ClipImage3 = { 45,0, /* XY origin relative to container TopLeft */ 24,3, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000,0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; static struct IntuiText ClipIText5 = { 3,0,JAM1, /* front and back text pens, drawmode and fill byte */ -124,-1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "X Scale Factor:", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipXSIZE = { &ClipYCLIP, /* next gadget */ 134,15, /* origin XY of hit box relative to window TopLeft */ -199,7, /* hit box width and height */ GRELWIDTH, /* gadget flags */ RELVERIFY+GADGIMMEDIATE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR)&ClipImage3, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText5, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR)&ClipClipXSIZESInfo, /* SpecialInfo structure */ XSIZE, /* user-definable data */ NULL /* pointer to user-definable data */ }; static struct PropInfo ClipClipYSIZESInfo = { AUTOKNOB+FREEHORIZ, /* PropInfo flags */ -25937,-1, /* horizontal and vertical pot values */ 10922,-1, /* horizontal and vertical body values */ }; static struct Image ClipImage4 = { 69,0, /* XY origin relative to container TopLeft */ 24,3, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000,0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; static struct IntuiText ClipIText6 = { 3,0,JAM1, /* front and back text pens, drawmode and fill byte */ -124,-1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Y Scale Factor:", /* pointer to text */ NULL /* next IntuiText structure */ }; static struct Gadget ClipYSIZE = { &ClipXSIZE, /* next gadget */ 134,24, /* origin XY of hit box relative to window TopLeft */ -199,7, /* hit box width and height */ GRELWIDTH, /* gadget flags */ RELVERIFY+GADGIMMEDIATE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR)&ClipImage4, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &ClipIText6, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR)&ClipClipYSIZESInfo, /* SpecialInfo structure */ YSIZE, /* user-definable data */ NULL /* pointer to user-definable data */ }; #define ClipGadgetList1 ClipYSIZE static struct NewWindow ClipNewWindowStructure1 = { 114,16, /* window XY origin relative to TopLeft of screen */ 346,76, /* window width and height */ 0,1, /* detail and block pens */ NEWSIZE+MOUSEMOVE+GADGETDOWN+GADGETUP+CLOSEWINDOW+ACTIVEWINDOW+VANILLAKEY+INTUITICKS, /* IDCMP flags */ WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH, /* other window flags */ &ClipYSIZE, /* first gadget in gadget list */ NULL, /* custom CHECKMARK imagery */ "Edit Clipping Parameters", /* window title */ NULL, /* custom screen pointer */ NULL, /* custom bitmap */ 350,76, /* minimum width and height */ -1,-1, /* maximum width and height */ CUSTOMSCREEN /* destination screen type */ }; /* end of PowerWindows source generation */ nethack-3.4.3/sys/amiga/colorwin.c0100644000000000000000000002030207764735041015543 0ustar rootrootSHORT Col_BorderVectors1[] = { 0,0, 59,0, 59,12, 0,12, 0,0 }; struct Border Col_Border1 = { -1,-1, /* XY origin relative to container TopLeft */ 3,0,JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ Col_BorderVectors1, /* pointer to XY vectors */ NULL /* next border in list */ }; struct IntuiText Col_IText1 = { 7,0,JAM1, /* front and back text pens, drawmode and fill byte */ 13,1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Save", /* pointer to text */ NULL /* next IntuiText structure */ }; struct Gadget Col_Save = { NULL, /* next gadget */ 9,77, /* origin XY of hit box relative to window TopLeft */ 58,11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR)&Col_Border1, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &Col_IText1, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADCOLSAVE, /* user-definable data */ NULL /* pointer to user-definable data */ }; SHORT Col_BorderVectors2[] = { 0,0, 59,0, 59,12, 0,12, 0,0 }; struct Border Col_Border2 = { -1,-1, /* XY origin relative to container TopLeft */ 3,0,JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ Col_BorderVectors2, /* pointer to XY vectors */ NULL /* next border in list */ }; struct IntuiText Col_IText2 = { 7,0,JAM1, /* front and back text pens, drawmode and fill byte */ 17,1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Use", /* pointer to text */ NULL /* next IntuiText structure */ }; struct Gadget Col_Okay = { &Col_Save, /* next gadget */ 128,77, /* origin XY of hit box relative to window TopLeft */ 58,11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR)&Col_Border2, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &Col_IText2, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADCOLOKAY, /* user-definable data */ NULL /* pointer to user-definable data */ }; SHORT Col_BorderVectors3[] = { 0,0, 59,0, 59,12, 0,12, 0,0 }; struct Border Col_Border3 = { -1,-1, /* XY origin relative to container TopLeft */ 3,0,JAM1, /* front pen, back pen and drawmode */ 5, /* number of XY vectors */ Col_BorderVectors3, /* pointer to XY vectors */ NULL /* next border in list */ }; struct IntuiText Col_IText3 = { 7,0,JAM1, /* front and back text pens, drawmode and fill byte */ 6,1, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "Cancel", /* pointer to text */ NULL /* next IntuiText structure */ }; struct Gadget Col_Cancel = { &Col_Okay, /* next gadget */ 244,77, /* origin XY of hit box relative to window TopLeft */ 58,11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY, /* activation flags */ BOOLGADGET, /* gadget type flags */ (APTR)&Col_Border3, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ &Col_IText3, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ NULL, /* SpecialInfo structure */ GADCOLCANCEL, /* user-definable data */ NULL /* pointer to user-definable data */ }; struct PropInfo Col_Col_RedPenSInfo = { AUTOKNOB+FREEHORIZ, /* PropInfo flags */ 0,0, /* horizontal and vertical pot values */ -1,-1, /* horizontal and vertical body values */ }; struct Image Col_Image1 = { 0,0, /* XY origin relative to container TopLeft */ 263,7, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000,0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; struct Gadget Col_RedPen = { &Col_Cancel, /* next gadget */ 32,12, /* origin XY of hit box relative to window TopLeft */ 271,11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY+GADGIMMEDIATE+FOLLOWMOUSE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR)&Col_Image1, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ NULL, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR)&Col_Col_RedPenSInfo, /* SpecialInfo structure */ GADREDPEN, /* user-definable data */ NULL /* pointer to user-definable data */ }; struct PropInfo Col_Col_GreenPenSInfo = { AUTOKNOB+FREEHORIZ, /* PropInfo flags */ 0,0, /* horizontal and vertical pot values */ -1,-1, /* horizontal and vertical body values */ }; struct Image Col_Image2 = { 0,0, /* XY origin relative to container TopLeft */ 263,7, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000,0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; struct Gadget Col_GreenPen = { &Col_RedPen, /* next gadget */ 32,24, /* origin XY of hit box relative to window TopLeft */ 271,11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY+GADGIMMEDIATE+FOLLOWMOUSE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR)&Col_Image2, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ NULL, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR)&Col_Col_GreenPenSInfo, /* SpecialInfo structure */ GADGREENPEN, /* user-definable data */ NULL /* pointer to user-definable data */ }; struct PropInfo Col_Col_BluePenSInfo = { AUTOKNOB+FREEHORIZ, /* PropInfo flags */ 0,0, /* horizontal and vertical pot values */ -1,-1, /* horizontal and vertical body values */ }; struct Image Col_Image3 = { 0,0, /* XY origin relative to container TopLeft */ 263,7, /* Image width and height in pixels */ 0, /* number of bitplanes in Image */ NULL, /* pointer to ImageData */ 0x0000,0x0000, /* PlanePick and PlaneOnOff */ NULL /* next Image structure */ }; struct Gadget Col_BluePen = { &Col_GreenPen, /* next gadget */ 32,36, /* origin XY of hit box relative to window TopLeft */ 271,11, /* hit box width and height */ NULL, /* gadget flags */ RELVERIFY+GADGIMMEDIATE+FOLLOWMOUSE, /* activation flags */ PROPGADGET, /* gadget type flags */ (APTR)&Col_Image3, /* gadget border or image to be rendered */ NULL, /* alternate imagery for selection */ NULL, /* first IntuiText structure */ NULL, /* gadget mutual-exclude long word */ (APTR)&Col_Col_BluePenSInfo, /* SpecialInfo structure */ GADBLUEPEN, /* user-definable data */ NULL /* pointer to user-definable data */ }; #define Col_GadgetList1 Col_BluePen struct IntuiText Col_IText6 = { 3,0,JAM1, /* front and back text pens, drawmode and fill byte */ 17,38, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "B", /* pointer to text */ NULL /* next IntuiText structure */ }; struct IntuiText Col_IText5 = { 4,0,JAM1, /* front and back text pens, drawmode and fill byte */ 16,26, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "G", /* pointer to text */ &Col_IText6 /* next IntuiText structure */ }; struct IntuiText Col_IText4 = { 7,0,JAM1, /* front and back text pens, drawmode and fill byte */ 16,14, /* XY origin relative to container TopLeft */ NULL, /* font pointer or NULL for default */ "R", /* pointer to text */ &Col_IText5 /* next IntuiText structure */ }; #define Col_IntuiTextList1 Col_IText4 struct NewWindow Col_NewWindowStructure1 = { 175,45, /* window XY origin relative to TopLeft of screen */ 312,93, /* window width and height */ 0,1, /* detail and block pens */ MOUSEBUTTONS+MOUSEMOVE+GADGETDOWN+GADGETUP+CLOSEWINDOW+VANILLAKEY+INTUITICKS, /* IDCMP flags */ WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH, /* other window flags */ &Col_BluePen, /* first gadget in gadget list */ NULL, /* custom CHECKMARK imagery */ "Edit Screen Colors", /* window title */ NULL, /* custom screen pointer */ NULL, /* custom bitmap */ 5,5, /* minimum width and height */ -1,-1, /* maximum width and height */ CUSTOMSCREEN /* destination screen type */ }; /* end of PowerWindows source generation */ nethack-3.4.3/sys/amiga/cvtsnd.c0100644000000000000000000000433407764735041015217 0ustar rootroot/* SCCS Id: @(#)cvtsnd.c 3.2 95/09/10 */ /* Copyright (c) 1995, Andrew Church, Olney, Maryland */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include typedef struct { short namelen; char name[62]; char misc[64]; /* rest of MacBinary header */ long FORM; long flen; long AIFF; long SSND; long sndlen; } AIFF; typedef struct { char FORM[4]; long flen; char _8SVX[4]; char VHDR[4]; long vhlen; long oneshot, repeat; long samples; /* 'samplesPerHiCycle' in the docs - usually 32, so * we'll use that */ short freq; char octaves, compress; long volume; char NAME[4]; long nlen; /* should be 64; see name[] comment */ char name[64]; /* for simplicity, i.e. just fwrite() entiree header */ char BODY[4]; long blen; } IFF; main(int ac, char **av) { FILE *in, *out; AIFF aiff; IFF iff; static char buf[16384]; long n, len; if (ac != 3) { fprintf(stderr, "Usage: %s input-file output-file\n", av[0]); exit(20); } if (!(in = fopen(av[1], "r"))) { fprintf(stderr, "Can't open input file\n"); exit(20); } if (!(out = fopen(av[2], "w"))) { fprintf(stderr, "Can't open output file\n"); exit(20); } fread(&aiff, sizeof(aiff), 1, in); memcpy(iff.FORM, "FORM", 4); iff.flen = sizeof(iff) + aiff.sndlen - 8; memcpy(iff._8SVX, "8SVX", 4); memcpy(iff.VHDR, "VHDR", 4); iff.vhlen = 20; iff.oneshot = aiff.sndlen; iff.repeat = 0; iff.samples = 32; iff.freq = 22000; iff.octaves = 1; iff.compress= 0; iff.volume = 0x10000; memcpy(iff.NAME, "NAME", 4); iff.nlen = 64; strncpy(iff.name, aiff.name, 62); iff.name[aiff.namelen] = 0; memcpy(iff.BODY, "BODY", 4); iff.blen = aiff.sndlen; fwrite(&iff, sizeof(iff), 1, out); len = aiff.sndlen; do { if (len >= sizeof(buf)) n = fread(buf, 1, sizeof(buf), in); else n = fread(buf, 1, len, in); if (n) { fwrite(buf, 1, n, out); len -= n; } } while (len && n); if (len) fprintf(stderr, "Warning: %ld bytes of sample missing\n", len); fclose(in); fclose(out); exit(0); } nethack-3.4.3/sys/amiga/grave16.xpm0100644000000000000000000023641307764735041015560 0ustar rootroot/* XPM */ static char *noname[] = { /* width height ncolors chars_per_pixel */ "400 200 16 1", /* colors */ "` c #66686A", "a c #797979", "b c #929291", "c c #43444A", "d c #758A74", "e c #F2F2F2", "f c #D1D0CE", "g c #066906", "h c #065506", "i c #53535C", "j c #0C0D0F", "k c #A3A5A2", "l c #2D332E", "m c #C3C4C1", "n c #B4B4B2", "o c #07840A", /* pixels */ "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjjjjjjjjjljjjjjjjjjjjljljjljljjljjllljljclljlllljlllljlllllllllllllllcicl``clcllclclllclclclcclclclcccccccccccccccccccii`iiccicicicciiciiiiiibiic`iii`a`iiii`icaii`iiii`iiii`ii`ii`iii```iii`i`ii`ii`ii`iiii`iii`ii`iifi`ii`ii`iiiiiiiiiiiiiiiiiiiiii`iciibicicicicciiccciiibiicciiiiccccbicicccccccciccclcccccclc`aiciiiciccclilccccccccccclcccacccccccclccclcclccc", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjljjjjjjljjjjjjajljjljljljljjjjljjljc`baljjllcljjcjlljllllllllllllllllllllllcclllllllclllcclcllclclccccccccclccccccccccccicciicciicicicic`cciiciciciciacicii`iiiiii``iiakii`iiii`ii`ii`iiii`bkb`i`ci``iiiiii`iii`ii``i`iiiiiaiiiiiiiiii`iiiiiiiiiiiiiiiiiiiiiciiciciicicciciiiicllic`iciiiicicciliccccccccccccc`ccccliccccccccciciccclccccclclclclcclccclclclllccclcllccll", "ijjjjjjjjjjjjjjjjjjljjjjjjjjljjjjjjjjjjjljjjljjjjjjljljjjjjjjljjjljljljljjjjlljljljljcclljllllljlllljllllllllllllllllcclccclcjcllclclclclllcclclcccccccccccciccccciiic`a`icciiccciciiiiiiiiibi`iiiiii`ii`ci`iii`ii`i`iiiiiiiii`iii``ici`i`i`i``ii`ii`iiiiiiic``iiiiiiiiiiiiiiaiiiiiiiiiiciicicii`iiiiiliiccicicccicccci`ccicccicccclccinccccccccclcccaccccccclccccccccccilcl`lllccclcclcclcllcllclcccclllilcllci", "jjjjjjjjjjjjj`cjjjjljjjjjjjjcljljjjjjjjljjljijjljjjjjjjljljljjljljljlljljllljjljllflcjljllljljlljllllcllllllllllllcllllccllcc`clclllcllcclclcccclccccccccciccciciccccccic`iciic`iiiiciiiiiiiaiii`iii`i`icak`c``i`iiiiii`ii`i`iii`i`ii`iiiiiiici`iii`ii`i`ii``iiii`c`iiiiiiiii`iiiiiiiiciiiiiiiiiiiccccciccicicciiccccciaillcccciiciccclcccccccccccccc`cclclccillccllcliibilikaicllcclccccclcccclcccccllccllcclcl", "jjcjjjjjjjjljjjjjjjjjjjjjjjjljjjljjjjjjjjjjjljjjjjljjcjjjljjljjljjjljjljljjjlljllljlllcljllllllllllllcclllllllllclllcclccibccclclcclcclcllicicccccccclcccccccciciicciccciaaiciccciiiiiiii`ciiiiii`iiiii`ic`iiiiiiii`ii`iiiiiiiiii`iiiiiciiiii`i`iiiii`ii`iiiciiiiiiiiiiiiiiciiiciiciciiccicciiiiiicicc`cccccccicccccicciiccicccicclilccccccclccccclccllcccilcccclcciclccciclcclccclccclclllcllcllccllcccclaacccl", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljljjjjjjjlljjjjljljjjjjljjljjljljlljljlljlllllljajljljlllllllllllllllcllllllllclccilcicclc`clalcclclclcclcccicclclccccciiccicciccciciiiiiiciib`iiiiiiiiiii`iiii``i`i`iiiiiiii`iiiiiiiiiiiiiiiiiibaiiici`iiiiibiiiii`iiiic`kaiiiiiiiiiiiiiciiiciiiciiciciccicciiiiciiiciccicicccccccciclcccccciiccccaciclclcccciilcccclcclcclcllclilacclcccclccclclcccccclccclclccllcclllllkblllc", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjljjjljjjjjljljjjjjjjljljjljjljljlllljljljljjjjjljllljcjllllllllllllllllllllccclclabclccccciccccllclclcclcclclccccccccciiaiiicciciiicccccciiiiiiiiiciiiiiicii`i`i``i`iiiii`iiiiiiiiiiiiiiiiiiiiiibiciiiicciiii`iiiiiiiiiie`i``ic`iiiiiiiiiciiciciiciciciciciiiciic`cccclcccccccccciccccccciccciicilcillcccccclciccccclclccclibaili`lillccccciicliccccccclcccllallclliiiclcliilcll", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjljjjjjjjjljjljjjljjjjjljjljljlllllljllljlclllllljlllllllllllllllllllllllllcccclccliiccccciccccclclcclccccccclcciccccciacciciiiccci`iiiiciiiiiiiiiiiiiii`i`c``````i``iiiiciiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii`kciiiiiiiiii`c`iciciiiiiiciiiiiiciccicicicciciiiiii`ifcccciccicccccccccccccccclccccccclcclccclccclclclcllilclcclcllclcliilclclclccicccccccccllllcecclclliaacllcllclc", "jjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjljljjjljjjjlljjljjjljljjlijjllllllllllllljljajlljlalllllllllllllllllllllccccclllccclclccccccccccclcccccc`clcccccccccccicacicciciciciiiiiiib`iiciiiii`c`iiii``iii``ii``ciiiiiiciiiiciiiii`biii`iiiiciiiiciiicib`iiiiiiiiiiiiiiiiicii```cccciciciciiiiiiiciiiciiccccccccccciicciccccccccccccciccccclccclcccllccclclc`ccclcclcccccclcccllclccclclllcllcliccllclmccclcccl`lclclclll", "jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjljjjlljjjllljlljjjljljjjljljlcllllljcljjcljlllijllllllllllllllilcllcccccllicllllclcllcclliccccclccclcccccccccccccccc`iciicicciiiaiciciicl`ici`iiiiiiii`ii`i`ii``iiiiiiiiiiiiiii`iiiiiaciiciiiiiiiciiiciiiiiiicici`ciiciiiiciicciiiciiciciiiciiiiiii`cbi`liicicccccccccclccccccccclclccccccclcilccllccccllcclcccclcclclclllllcllllcllllllclcllccccclllcllilllclllclilillccll", "jjjjjjjljljjjjjjjjjjjjjjjjjjljjjjljljjjjjjjjlljjljlllljllljllljlcljjljljcjlllljcljllllcllllllllllim`lljccllcclcbacllcllclccliclcccclccccccccccccccicciciciiciiciiiiiibiiiib``iiii`i`iiaii`ii`iiiiiciiiiiiiiiiicciiiiiii`iiiiiciiiiciciici`cciiciciiiiib`c`aaicciicicciccccciiiiiiiicciiicciilccccclcccccccccccclccccccclccliccccclclclcillccccllcclclccilcccclclcclcccclclclclllcllllcclllllllclllcllcllclcll`cc", "jjjjjjjjjjjjjjjjjjjjijljjjjjjjljjljjljjjljjjjjjcjljljlcjjlcljlljkclllllllcllllljllllllljllllllllllliiccccclllllcccllcclcclclclcicccccclcclcccccccicccciicciciiciiiicc`ciii`ciiiiiiiiii``ii`iiiiiiiicii`i`i`iii`iicic`ii``iiiiiiiiiiciciciiiicc`ciicici`cc`iiiciciicicciicicci`iiiiiciciicicccibiccccccclcccccclclcclclcclccicclclcicclikclcllclllcllcllclccccllclclcliclci`cllclllillliccclcllclclbilllclllclcal", "jjjjjjcbljjcajjjjjjjljjjljljjjjjljjjjjjljljjljjjlljcjllljlilllllaljlljjl`mllljcillllclllllllllllcllclllciiilccclllclclclcclckaclccccccccclccccccccciiciciiciiciiciiiiii`ic`ii`ii`ii`````i`iiiiiiiiciiciiiiiiiiiiic`ibiiciiiiiiiiicicicicccicicicciciccccicccciiicccciccciccciiiiiiiiciccii`cicbicciccciiciclcccccccclcclcccccllcclllliclclcccccclcclcllclcccclcllclclccllc`lllcllcll`llllllcllllllilllllllclcclc", "jjjjjjjljjjlijjjjjjjjljjjjjjjjljjjjjlljjjjljjljljljajljljlljlljcljjlllllljlljijjlllllllllllllllcjcllllaclclllllcccclccclllccclcccccccccccccccccii``a`cccciciciiiiic`i`baba`iiii`ii```ii`ii`iiiiiiiiicciiccciciiiic`ia`iccii`c`iiciciccccccccbcccccic`iciciiiiccciccicicccccccccciiiiciccccccciccccccccccciicii`a``icccccccilclclciaa`iiccciclllcllclcllcllcccllllclllcllllclclcllllamiccaclllllccllllccllclcllcl", "ljjjjjjjjljjjjjjjjljljnjjljljljjljllcjljjjljjjlbjllblljljjjljlcljclljlljlljclikllljlllllllllllllcljclccccccccllclllllcccccclcclcccciccciccciabbkakbnaccici`iciiiiiiic`bbnnnnkbaa``iiii`ciiiiicici``ic``ciiiaiiiiiiiciiciciiiiiiicccciciciiccbcciiccccccciccciicicicicccccccccicccicccccccliccicliiccccici```iabkbaccccccccclccclciammnbbbaaicclcclclclclllllllllllclllllclllllllllccijlakillcllllllclllllllcjcll", "jjljjjjjjljjjjjljjjjjjjljjjjjjljjjjjljjjljjljljjljjijjljljl`liklljljllllllillljlllllllllllllllllllclllccccllccclcccccllcclcclccccccccciii`abnnbknmnmblciiibiiciicik`i`nbkmnmmnmnnk``i`niiiiciiiiciicccicccibciciiiciciccciciiciccicicccccccciccccccicc`ccccicibfcccccccicccccccccccccccclc`cclcclcci`abbbbaii`nnk`ccccccclllc`cciiknnnnbbakbkkicllclllclclllllclclllcllllclllllllllllclccllcllllllllkalllcljclll", "jljjljjjjjljjjliljjljjjjjcljjjjjjljljljljlljjjljljljlljlljlijblljljlljljllcjllllllliklllllllllcllllclccccccclclcccclccclccclcccclccciiaa`babnmnnmnnmkjiiccacciiiiiiiiakkknmmmmmnmnkkbbaiibciiccciciiccccccccccciciicicciccccccciicccccccccccciiiilicicccccccciiiilcccccci`ailciclcccclcccckbcllclciabbkkb`icianmnkcccclllclccccii`ammmnbabknkkaa`iillclllcjcclllllcllli`lllllllllclclllclllllllllllllljcllclllll", "jjjljjljlljljjjljjjjjjljcejjlljlljjjjjjjjjjjjlljjljljljljljllkijlllllllcjkllllcllllcallllllllllllclcclilcclclclcllcccllccccccccccc`bk```baabnmnmmmfmklciiciiiiiciiciiakbbknnmnmnnnkbbbbaknicciiiicccciiiccicciccccciicciiccicccccccccccccccccccccicililccccccciiccicccccciiclcclcccclilclliclccli`abbbnkkacciaknmkllllllclllcccii`amnnnnbbakbk`i`aaa`ccicclllcclcljclllclllllllllllllclllccllcllcjcj`alllllllcll", "jjjjljljljjjjjjjjljljjjjljjjjljjjjlllljlljjlljjlljljljlllllljilljllljlciacjlljb`llllclllcllllcclclllccciccclclcccclcccccclccllc`aabnkii`bbabbnnnnnmnbljiiiciiiiii`i`i`kkkbknmmmnmnnbbknkak`iccccicicccccccccccccicccccibccccccclcciccccccccccccciciicni`ccccccccccccccclcclccclcclacclcclclliiciabbbbbbnb`cc`bkknnlllllclcllccc`iiamnknnnkaaknaiiabbabbkkcccclccjcclllllllllllllllillllllcllcccllllccelllccclicl", "jljjjjjljjjljljljjjjjjljjjjjljbjljjjjjjljjljjlljjljljlljljjljljlllllljlllclllcjllllllllllllcllllll`ccilicccclclc`illcccccccci`bnbaakk``abbb``knbnmmkbllciii`i`i`i`i``akbbbbkmmnnnnbbkkkabnmnb`icccccccciccccccccccccccc`ccccccccciicccccccccccciccccciilcccccccclcclclclcclcclccclicllcllcc`aiiabbbkkbakacl`bnnknklccllllcclciiii`bmnknmmbaabka``akaaaakkicllclccibclllllllllllllc`lllllllcllcllllllcjlccclcc`ll", "jjjjljljjjjjjjjjljjljjjljlljjjljljljljljljlljljlljllljlljlcjllllllllllllljcjllmclllljcllllccllllcclcccccclcccccccccclccccciibnmmaaabbbbbbbb``bmbbnmnbljc`ii`ib`iikb``bnkbabbknmmmkbnnkbbbkmmkkaccccccccccccccccccccccclccccclccclcicccclclccclciic`lccciccccccccclclilccclcclcllcllllc`cc`abaliabkkkkkabiciabnmnfnlllllcllllii`i`i`nkbbmmnbbabaakbbba`iknbbbciclcl`llljcllllllllllllllllllllcllllclljclcclllclll", "jljjjjjjljjljljjjjjjlljjljjljjjljjjljljliljljljljlljlljllllllljljljllllllllcllallllclllllcbkbaclcciillclcccccccclcccccccciaaaknknbai`bbbbbbb`bmnkmnnalliii`i`aiii`ii``bbbbbbnmmnmmbkkkbbbbnmnnnbaiccccccccccccccccclcccillcccclclccllcclcclclccccclciliccclclclcclclcllclcclclcllcilclbaabb`icaakbbknkbaii`abknmnbclllccllllii`iiiibabbbkkkaa`abbbbkbaaknnkmnalclllclclllllllllllljllllllllccllclljlclclllclclll", "jjjljjjjjjljjljljlljjjljlicjljlllljljli`cccjl`cjljlljlllljllllllllllllllljcjlllllllllllllliclclclcmbclicccccccclccccccci`bkbbbbbbaaaabbkbbbbabnmfnbacljici`iiii`ici`iiiaabbbkmmnmnbbbababbnnmknnkbiclc`acccccccclccccclccclccclcllclccccccclccccccicllciccccccccllcclilccllclclclcjccababbicc`bbbbbkknbac`ababbaicllllllllllcii`i`iiiababbbaaaabbbkabbabnnnmmfna`acclclllllllllllllllllllllllllclcalllllclclllll", "jjjjjjljjljjjjjl`ailjljjjljjljjljlc`aabkbaba`aiclljllljljcb`ljlllllllllllclllclillllclllllcllclcililclkclcccccccccccccannbabbbbaaaabbbbkkkkbbkmnbiljlllciiiiic`i`i`iiillcakbbknfnkbbnbkbabbkmnnnknnbilccccclccccccccclcaacllcllccclclllcllclccccclclccccccccclllcclclbclclllcllllccl`aaabaicabkkbbkkknka``bkbbilljlllllllllcciiaaijlljcabaaaaaabbbkkkbbknmnnmnnmbillccjlllllllllljlllcllllllllllllllllclllccllll", "jljljljjljjlljljcjljjljljjlljljc`bbknnkkkkkkkbbbbbcjllljllllllllllllljlllllllllcclllclllllclllcacclcccclcliliclcclcc`mfnnmkbkkbaai`a`aakmkkbikmmlllljllciiii`iiii`iin`iljcbbdbnmnbbbmknnkaaakmkmmnbbbilclclclclcclclk`abilcaclclcllclcclicccccclillcccclilccclclllclllclllcclllcllibbbaaailiakkkkbbnkkk`bbbaballllcllllllcllci`a`lljlllcba`c`a`aakmbkbabmmnnmnnmbacllccllllljllllllllbjlljljllllllclllllllclllll", "jljjjljljjljjljjljljljjjjljjlc`akkkkbkmmnnmnkbkkbkb`cjjllllllllllllllcllllllclacjcllllflclllclc`cclliiicclccclciaciabkkmnmmkkka`cc`a`akbnkkb`knkjllljlll``iiii`aiiiiicccllakkkkkkbbbnnmnmkaabnmnkbbkkbiccccliacllillilccccllli`llllcllllcccclllcailllllcllclcclcclccllllclllllllliabka`i`clibbkknbbkknkbkkbbbillllllllllllllc```llllljjlb`cci``abbknkbianmnnmmnnnallilllljllllcjllljllllllcllllllllllcllllllijjl", "ljljjjjjljjljjljljjjjjlljljjibbkmnnkknnfffmnnknnnkbaa`clllllllllllllllllclilllllcccllclclcllccccccclcccccccclcic`cannbbmnnmnbaiiii``akkdknkaabmblljllllciiiabknmniiiiiijljannkkkbbbkkmmnmk``bbkkbbkkkkkaclcclclclclcllclbilcclllillllccllccclclcclcliccll`llilcclllllllclllllllliabba````ccabbbkknbbkkbknkbbbiljcljcljcbnkbabballlljlllc`iii`a`bkbbknbabnnnnmnnnnalcicilllllljllllllljclljljllljljjclllllllla`ll", "llljljljjljjljljjlj`ljljljlikbbmnfnnmmnfffmnmnmmmkkbkbiiljlllllllllllllciaiclcllllllclcllclccccclcccclcclaclcilc``bknnbkmnnnka`bba`adbkbbkbaabmkcljllllciicbnmnnkiiiiicljcanmnmnkkbbkmnnn`ibbabbbknkabknbclclllclllcllclcllllllcllcclllllilllilllllliclllllcjliccllclllclclllccci`aa`i`aii`bnkbkkkbabaakbnnkkacllllllc`knmkbbbbljjjjjlj``abba``bkkabkaaaknmnmnnnbacli`acllljllllljlllllllllljlbblljllljcllclabll", "jljljljljjljljjljjl`jjljjcabkkbefmmfnfefefffmffmfmfnkkbaillllljlllllcllll`llllllajiclllclcccccclcclcccccc`lciccakbbbknkbnnnmnnnnbaabbbbkbb`iadmmaclllllcclcaknkmmkiiiiicc`knkmmmbkbnnnnnbi`bkbbkbkbbbaakkaiclcclclllcclllcclllllllllllcll`ill`cllcllcllcikllillc`cccclclllllcciii`aa``iii`akkkkbaaaaiakkbknknkaallllcabkknnkabkallllllibkmka`aaabkbbai`akmmnmnnmballcibbillcljllllljlljljlllljcjlllljlllcjlllljl", "jlljljjjjljljjljlljljlajl`bkkkkmffffffeffefffmmfffmmnmkbbillllllllllllllcjcllclllilllilclcccccccllclcccccccclcakmnbbbbbkbkmnnmmbabnkbbbkk`cc`bmmmb`ciia`iii`aabnnmaa`c`abkknmnmmbbknmmnkbiababbbaba`ba`aakk`clclllllciccllllcllclllllllllclllllllllclllclllllllliclclcclcclli`aaaaaa`iclc`bbnnkbaiiiibnbnbbknkbb`ccci`knnknnkbbbb`cjjikfmnbabnnbakkk`li`knmnmnnnb`icccaabclilljll`llllllllljllcljlljlljlllllljal", "ljljjllljljjljljjjljlabliakknmknmfffefmffefefffffffffnmkkailllllllllllialclcllilcllc`jicccccicccccccclcccciccbnnknnkbbkbbknnnmnbbkmmnkbbbiccabnnmmnknkb`ccii`abmnbbbmknnmmnmmmnmkbkkfmnkaa`aabaaa``ia`akbbkkacllccllliillllllllljiaaillclllclllcclllllllllllllclclllllcllcciaaabkbb`iicciabbkkba`iiiaknbmkbbkkbabknbabnknkknmkkbkabbkmnknnabnmmkbbbbiliabnmmnnnnbbaicii`akallllljilljjllllicljjlljljcljljllllcbl", "jljllllcjjljljljlljlljllbbnnmmffffeffeefeefefeeffmmefmmknkbclllllllclllclllclclccccccicccicccclcccccccccclccbnmnnnnmmnbbbbbmnnkknmnnfnbb`i`aabnmmmmnnnbaiii`abbkkbkkknkmmfkmnmmmnkkknnmnaaabkkbaaiii`bknbkbkbcllclclclblllclllllllllllllclllllllcjllclcllllllllllllllllllliabbaaaaa````a`abbkba`a```abbknnkbbbkknkkk`bnmnmnnknnmkbkbabnmnnbnmknfnka`iiaabnmmmnnnnbaci``aabkaljllljlljcljllljllllljlliljlljlljjll", "llljljjjljljjljljljjljc`bkbmnfffefeeeefeefeefffeefffmmnnmnkaclllclllclllllclccccccclccccccciccccccliccclbccanmnmmmnknmnbkbbkmnnnnfmmnmnbi`abbaknmnmnnkb``iai`aa`aabknmmnmnnnmnmmmbkbkfnnkbakmnabaabaabnakbbkbbilllllllllllllllllllllllllllllllllllcjallllllllllllllllllllinkbabbba`iaaaa`akbb``````abbbbkfmbabnmmnbakknmmnmnmnnnmkbbbbknnnnnnnmnnmbiiabbakknmmnnkb`````iaa`ailjlljljlljlljlljljlllljljljiclllljl", "jljljljljljljljljjllljlbknkfnffffefeeeeefeeeeefeeeefffmmnkkbillllllllllclijcclclclccclclccccccccicinacciiibnmmnnnmnnnmnkbkbamnkmnmmnmmnabdaabbbbmmnnnba``iaii``ii`bnknmnnmnmmmmnnkkbbknmmkbknnbkkbbbabnbbkkbbnaclllllllllllllllllllllllclllllllllllcllllccclllllliclllllikfkbaaaaa``aba```baa`a`aaaabbbbkmnnknmnnkbbknnnnmmmnnnnnnnkbbbknnnnmmmnnnabaaakabbnnmnnba`````c``i`iicjlllljllllljllllijjcjlllllcjjjllj", "lljljjljljljljljlcjjllkbknmfnffffeeefeeeeeeeeeefeeefffffmnkkbclllllcl`llllccccklllclclcclcccclcccccilccccbmmnmmnmnmnnnmmkkbbnnnbknmmnmkkmkaabbbaknnkkbaa```c``iiiabkbmmmmnmnnnnmmmkkkkknmnbnmkbkkkaa`bbbbbkkbnkacllljcllllllllllllllllllllllllllllllallllllllllll`cjlljlabkbab`aaa`iaba``abaaaa`aabkkkkkknnnmmnkbabnnnnnnmnnnmnknmnmkbbbnkkbnnnnnkbnnabbbbbbnnnkkaaiii`iaiciaailjjlll`bialjlljjclljljajjljjlljll", "jlljjljljjljlljlcjllljanbmmfnffefeefefeeeeeeeeeeeeeeeeffmfnnk`clcllllaclllcclllclcllccciclcccccccccclicc`mmnnnmmnmnnnknmfbbbbdba`abbdbabkaaaabkbbnnnkbaa``ic`iiiaaabbmnbkkbbdbbkbbabkknmnmkmnnabkkbabbkbkbnkkkbb`llcjllllllllllljllllllllllllllllljlllclllljlllljlllcjl`kbbbbbaaaa```a```abaab`ii``aabbabbbbbkkai`bmnnmmmbbkbkmnnnnmka`aaa``aabbbbaknbabbkbbknmkb``a`ii``iiiaaacllijlcklllbljlljljlljijlljla`ljj", "ljjllljljljljlljljjljibbknffmfeffeeeeeeeeeeeeeeeeeefeffemfmnkbclllcllclcicbcclillccccclcccccccccclcciclinmnnmnmnnnmmnnnnnnkaai``lllllcllllcllc`abknmnac`i`clclliaaaabnalllclclcclcllcc`kmmnnnkbbbkbkknkknkkkbbaa`iccclljlllljllllljllllljllllllllacljljlllllllllljllcliabnnbaaabbaa``````aababllllllcllllcllcciii`bnnnnnncllllnnnnnnnilcllllllcllllciadkbkkbbnnnb`i``iciilc`aaaaclealljllcecllljjjljljjljljjjjll", "jjljljjjlljljljlljllclbbmnmffeefeeeeeeeeeeeeeeeeeeeeefefffmkkb`lclcllllclicciclccclccllccccccccccicccciknmnnmnnmmnnnmnnnkmnbiia`lllllllllllllllliaknnb`i`aclllli``i`abilllllllljllllllliknnnnkbbbbbbknnnkknkbkaiiaillljlllllllljlljlllllllljllllcjjlllcllllllljlllljlcabbbba`babbba```iaaaakkbllllllllllllllclicadkmnmnknlllllmmmnnnmijlllllllllllllccibbkkkkbknna`i```icli``i`aaclljjljljlljjlllljljlljjllllllj", "ljljljllljljljlljifccibbmmfffeffeefeeeeeeeeeeeeeeeefefeffffnknaccclccclcccicclcllllclcccccccccccccccccanmnnnknnmnnmnmmmnnnnbi`nilllcllllllllllllliabbkb`aacllll```iiabillllllcllllllllllibnmnnbabbbknnnnnnknbkaiib`ijljcljlljljllllcljcljlllljll`cjlcjjlljllljlllllllibbka``bbbkbba`i``abbbknbcclclllllllclllllladnnnmnnncllllnnnnnnnallllllllllllllllc`bkknbbakbbaaaaaiiii```ciaalllllljljljljjjl`jljllljjjjjjl", "ljljljl`llljlljljlcclaakmnfffffeeeeeeeeeeeeeeeeeeeeefefefffmnnacccccllccilcclclccci`cclccccccccccccccinknnmkkmmknnnnnmmmmnbaaakicclc``ai````illlllibbaabaalcllc`aai`abilllciada```aicllllannnmkbbbknnkkkkkbnbk````aklllllljlllllljlillijllljlllljlllllcjlljllllljljllbknbaa`kkbbkbai``abbbbbnbilclcccici`icccccllaknnnkkn`lclcknnfnmndlllc`````aaaaccclldbnnbbbabbaaaa`a`ai`aaiibb`jlljljllljljlll`ljljjjjjlljlj", "jjljjljcjljlljlllllllcbnnmneemefeeeeeeeeeeeeeeeeeeeeefeeffmmnbbiccciccccccclcclcccccccccliclicccccicibknnnnnnnnnmnnnnnnmmkabbbbiliclnmmkkkbbkalcclcbbbbaaallllc`ab``abcllllaknffnnnkalllllnkmnbkbbkkknnkkkkkbb```i`alljllllljlljlllilljlljllljlljlllljllljlljljlllljakbkkkaabnmbababbbbkbbbbkacllccciiii``aablllccnkknnnkillcldnnnmnmblllc`kkkknmmnblcillbnnkbbbbabba```aaaaaaa`aabcjlljljljlljljjljjjljlljjjljj", "lljlljljlljljlljlllllibnkmnmffefefeeeeeeeeeeeeeeeeeeefffeffmmkkaccccclcillcllclclccccccci`icicccciciakkbknkknnnnnknnnnmnnbadbkkilclcnnmkkbbkkbllllcabbkabblcllcaabaabkilcclakknnnkbkbcilllkbbbbbbbbkbkkbkkbbbaa`iaaaallljjllljljljlclljlllljlllllljljljlbcjllljljjj`nnkbknbbabkbaabkbkkbbbbbbalcllcciabb``bnnilclckkknkkniccccannnnnnalllc`bbbbnnmmnillcldbdnkdabbbbaaaabaabab`aabb`ljlljljljljljljljljjljjljljl", "jjljllljljllllccjcljlcbmknnnfefeefeeeeeeeeeeeeeeeeeeeefffemmnkk`cclccli`clbcblilccccccccciccccciial`kkkkknkknnnnnkknnmnnbdaabbkclllcknmnkbkmn`cclliaabbbbbcllclabkdaabilllcbkkkmnkakaliilibbbakbbkbkkbbkkbkkba``ibbaailllljlllllllllljlljljlljljlllillllljlljlljllcaknnbbkkbaaa``abkkkkbbabaa`cllcci`abkkabkkclllcbkknkknilllcannnnnk`clcc`bkbabmnnkllccldkkbkb`abbbbbkbbbbbbbbaabknajljlljljljljljljjljljllljll", "ljlljjjljljljlccjlllccamnnnnfemeefeeeeeeeeeeeeeeeeeeeeffmffmfnbacclclllillil`cclcclccccclccccciia`canbkknnnnmnnnmnnknnmkkiidnbbclccl`aa``i``illclc`abbbkkbcllllbbkb``b`llcl````a`a`illicl`bbbbkkabbbbbabbbbkb``i``aaaalljlljjljjljljllljljlljllljlcalljlljllljlibjcbkmkmkbab``iiabbbkbbkbabbaailllcci``iii`icllcl`kkknnnm`cllcannnnnb`lllli```i`ab`ccllccnfnnkdbabbbbkkbakbabkbaiabnkijjljljljljljljjljljlllljlj", "lljlljcjlljlljclclljclamnnknnenefeeeeeeeeeeeeeeeeeeeeefemffmmnb`clcllcllcclccclicccccccccccccciiicinnkknknmnnnnnmnmnnnnkbcc`mnklccllllcllllclccll`kkkkbbkkclclcbbkbaabillclcclllclllllllidbbkbnkbkbbkkbkbbkbaii`aiabbklljlllljlljlllljljlljljljlljlcjljllljjjljljlbbannnmba`ii`akbbbbbbbbbkaad`lllclllllllcljlllidmkbnnmn`cllcannnnnb`llccclllllllccllcldkmmnnmkkbbbbkbbbbbbbbbb`babkaljljljljjljljjljllljljljjl", "jjljlljljllljllljjcc`l`bnmnnkeffefeeeeeeeeeeeeeeeefeeeeemffnnnb`llclccccclccclciclccccccccicccciccknknkkknnkkkbknnnmnmnka``dnkkllclccllllllcllll`kmnkkbkkkclcllbkabbabclllllllllljlllllibkkabbnkknkbbbbabbkbai`aa`abkkbjljljljljljljljljljljljljljjlljljjlljlicjliakkkmnnkkacc`kkkkbbaababnkabalccclllllcllllllcdnnkkmnkkallll`nnnnnballiclllllllllllll`akkkmmnnkkbkkbbbabbabbbabbbbmnclljljljljljjljljljljljjjj", "alljaklllljlllllllllllibknmnneefefeeeeeeeeeeeeeeeeefeeeffmfnmkbicccllclllclcliibcccccccciciiiiiic`nmnnnknnnbbbbkkknknmnkbbkkkbdccclcccllcijcjlcbnmnmnbbkbklllllbkbabbbilcclclllllcllc``kknnbbbkknmnbkkbabbbaa`aaabbabkncljlljjljllljljljljljlljljljljlllljljljjllkbbaannkknac`bkkkkkbbbbbknkbb`lclllllllllcllcibnmnkkmkkb`ccccannnmkbkllllclllllcllllidkbbknnnnnnkkbkkkbbbbbbbbaabbkmmaljjljjljjljljljljjjjjljjl", "ljjl`ajljlllljlljllllliinbmnmmefefeeeeeeeeeeeeeeeeeeeeffmnmnnkblclccclccclilillccccccciciciiiicccamnmnknmnkbknnnkbbkkmmknmnmkballclc`aacl`ccibknnmnnmnkbbkclcclkbbbbab`lllc```aaab`iakkkbnmnkbbkkknbbkkbkbaii`babbbbakb`jlaaljllljljljjljljljljljljljljjjlljjljj`nkbbabkknk`cbkkbbkkbbabnkbbbb`lcllcaailllll`bbmmmknnnkkballlcibkkmnnmllclci`iiaaabbkknkbkbnnnnnnnnbbbbbbbbbkabbabkmnmmcljljljjljjljlljljljljjjj", "lllljljlllbllljllllllllcaknknmffeffeeeeeeeeeeeefeefeefemmfnnnkacclccclclcccccccccccccccccciii`ciabnmmmnnnnbknnmnmmnkkkknnnmkdballcclbmn`llcll`nknmnknkmnbdlcllcbkbbbbk`lcllkkkknnmnkbbknbnknkbkbnkbbbkbakkaiabaabbbbbbabjljcljljlljjljljljljjlljljljljljljjljjclannbbaanbkacikmnkkbbkkbbnnnkbaacclcibbbilcclcaknmnmknmkbbklllccmkkbnkmclclcai``abbnnknnnkbkkknnnnnknkkbbbbbabkbbkbknmmkaljjlljjjlllljjjjjljjajlj", "jljljccjllljllllljllilll`bbnmmfffefefeeeeeeeeeeeefffefenmfmnkbiclccclcccccccccccccccccccciiiiiii`bbknnnnknbbmnmnnnnnnkkkmnkaad`lcllcbkmk`cllll`knmnmnknnnkllllinbbkmnn`clllbnkknknnnkkkkbknnnkbbkkkbkb`iaba`abbbbbknnbbbllilljllljljljljjljjljljljljljjljjlljia`bnkbb`akab`aaknnnnbkbbaabnnbbbdllliibbbailllclabnnnmkbkkbkclcccmnnkkkniclcl`i`akbbknknknnbbkknnmnkknnkbbbabbkbbnknnnnmnnljljjjljljljljljjjjljjlj", "klljljjclljlljllllll`cllcakbmmmfefmffeeeeeeeeeeeeefeeffmmfnnbailclccccclccccccccccccccccciiici`iabbbbkkbkkbnmnnknmnnnnnkkkbdab`lcccibknkn`clillakmnnmnkkmkllccinmnknmncjcccknnkkknmmnnbbkbnknnbbbkbabaciaaaabaabaknmnnbbilijljljlljjljjljljjljljjljjljljljjjljjaknkbbaaba``bknnnmnkkbbabbknkbbblllccbbbbailllcc`bkbkkbkbkklclccnnmnnknillcc`c`abbbknnnnnmkbkkknnnnnnnnnkmkbkmnknnmnknnmm`lljjjljjljljjjjljjcjljj", "ljlllllljlcljcllllllillll`bbkkmmfffffefffeeeeefeeefefffmmmnkb`ccacclcliccclccccccccicciciiciciaibbbkbkbbakbmmbnnnknnnnnnkkkbbaiclllcbnmknncllllldmfknmnknkllllikbknnnniilllknnkkknnnmmnbkbnknnkkabbbaccaaaaabbabknnnnnnkallljjljjljljjljjljjlljljjjjljjljjjljlcbknkkkbbda`aknnnnnmnkbbbbbbbkbbalcclcknkkbaicllil`bkbbbkdmnlllclnknnnnk`llclii`bbabknkkknnbbbkknnnmnnknnnnnnkbkkknnknnmkkbjjjljjjljljljljjjanjjjj", "llmjjljllllllilljlllllllllikbbnmmmfffffefeeeeffeefffmffmmnkbaicclcccccclccccccccccccccciiiiicc``bbkkknkbakbnnknknnkkknnnmnbbbaclcccibnmnmnncllclldmnnmnnnnllclckkkbkmmilllcknnnnbkknmfnnbkknkknnkabaic`bbbabbbbknmnknnnnkljjljljljjjljjljjljjijljljljljjjlljjj`ikkkbnkbaaadnnnkknmmkbbbbbbbkbballlclbbbbbabclllcidnkbbbbnmlccilnkkkknn`llccciabaabnmnnkmnnbbbbnknmmnkkkknmnkbbkbbnnnmnnnflljjljajljljjjjjljjjjjj", "illllllllljllclllllllclllll`bbkmnmmfefeffeffefefmeffmffmknkaiclcclclcccccccccccccccicciciicici`aabbbkknkbabknnnkkkknkkkkkknkb`clcllibknnnmkkcllllcdkmfmnnkllllcbbbbabbclcllknnnnkkknnmnbbkkmnknnnkb`c`bbkbbbbbbbknnnnmnknlljljjljjljjljjljjljcjjjjjjjjljljjjllibkkkknnbaabknmnkkkkknkbkkkbbkknklcclcbkbbakdbilllliakkbabkncllllnnnkknkalllliiaaabbbnnnknmnkbbbkbknmmnkkknkbbkbbaabbknnkkniljjjjljjjljljjjjjljjlj", "lcljlljlllllljlllllllclllillabbnknmmfmfffffffffffmefmnnnkkaicclcilccbcccccccccicciccciciiciiii`babbbbbbkkakkkmnnknkkkkkkknmnda`clllibbbbbakbacllcl`knmnnnklllc`nmb``bbcllclknnnnnnkknnkbbbknnkknnmna`bbbkbbbbbabkknnnnnnncjjjjjjjljjjjjljjljjjljjljljljljjljjj`anknnmnbbabknmmnnkabnnknmkkbaknkcllllbbkbbakaaillclibkbbbbkiclcckkkknkkaclll`bbkkbaabbkabkbbbabbkkbnmmnnkknmmkkkb`abbkkkbkbjjlljjjljljjjjjjjjjljj", "cbjcjllljlllllllllllcllllllclcbbkkmnmnffffffemmmfnmnmknkkbiccccclccliclcccccccciccciccciiiiciciabaabaaabkbnkknnnkkkkknnnknkdakndbkbabbbbbnbkbbaaa`bkbkmfnmbkkbbnna`ammakaaamnnnkkkkkknnkkakknkkkkmnaabakkbbabbbkknnnnnnmkajjljljjjjljljjjjjjljiljjjjjjjjjljjcccknknknnbbdknnnmmnbbbknmmnnnkkbbbabababbbbbkkkbaaa`aiabakdnkdbdbbkbkkkkkkab``bnnnnbkbbbbbbkbkkbbabbbbnnmknnmknmmm``bnmkbkbknjjjjljjjljljljjljjj`jj", "lljljlllllllllllllcllllllllllc`abbkknkmfmmfmfknfmmnnnkkba`cclliliccccncccccciicciccciciciiiiii`bbkbaaabbkbnnbkmkkkkkkbkbkkd`bknknnmnkabbnbkkbknbbbbbbbknmnnnnmnbkiannmnnnknnmnnkkkkkkkknnkkknnkknnnbbabbbkbbbbnkbknnmmmmnbcjjjjjjjljjjjlj`jjjlljjjjllljljljlliiknnnnnnkkbkknknfnkknknnnmmnmnmkkbbknkbaabbnknkbbbbaa`bbkbnkbkmnkkkkbbkbkkaabmkknnnnbbakkbkkkkkbakbbbdbmmnmkmnkbbcdnnmnknbkma`ijjjjjjljjjjljjjjljj", "ljcbaljllllllllllclllllllclcllcci`bbnbkbnknnmkknkkmkkba`ilccilcclcicl`cccciclcliccicicic`icici`nkkkbaabbkbknkbkfnnkkbbkkbbaannknnnnnnbkbkmkknnkkabaaabbbknnnnmfnk`annnmmnnnnnmnnknnknkknnkkknnnkkkkkkbabkkbbbbbkkknmmnmmfkjjljjlljjjlcljjljjjljjljljjjljjlljii`nknnnmmkbbbbnnnmnknknknnnnnmnmnnnkkkkkbaabkmmnbbnbbaabbkbkkkkknkkkkbkkkkdabknknnnnnnbbbkkkbkkkkbaadbbbkknkkmmfkkibnknnnnknmajjjljjljljljjjjjjjjjj", "lljci`cjlllllllllclllllllllccllllc``bbkkkkknknnkbnkba`icccccc`ccccccclcccccccaciciciciciiiiiiiankkmkbbbbbkbbkbbknnnnnkkkbaaknkknnnmmmkbbbnkbknkkbbabbbbbbkmmnmmmb`kmknnnmnknknnnkknnnnknknnkkknnnnkkmnkbbbbbkbbnnkkmmnnnnmjc`ljjjjjjjljjjjlj`jljjjljljjlljlj`c`nnknnnmkbbaabkbbknmnnknknnnnnmnmmnkbnkbbbkbnmnnknnkbbbbbbbkkbknnnnknkbkk`akkkknknnmnnbbknkbkkkkbaaabbabbknmnnmnk`kkknnnnnnbillljjljjjljjjjjjjjljj", "jlljcillllllllllclclllllcllllcccclcliiaabbbbbkbabaaiiiiccccccacccclciciccccciaiccicicicici`iiibnnkfnknbbbkaaknkbnnnmnnnkkbknnnkknnnnmkbbbbkbbkkbaaabbbbbbknmnknkbbknnnnnmnnnnnmmnnknknkkkmnnbkknkkkknnkbbbbkknbkkkknnnkknfjjjjjljjlljjjjljjj`jjljljjlljijjjjccaknnkkknnkb`iaabknnmnnnnknnnnnnnnnmnbkkkabkbknmnkkfnkkkbbbabbbbbknnmnnknkaknknnkknnmnnbbbbkabkbbbadaabbaabnmnknkkaknnnnnnnnfkljcjljljljjjjjjjjjjjj", "llllcjllllllcllllclllclclclclclcccclclcliiiai``icccccccccccibcccccccccccciciiiiciciciciciiiciinmnkmmnmkkbbbbbabbnnnmknnnkkknknnnnnnnnkkbabbbbkka`aabbbbbabnnnnkknnkmnnmmnmnnmmmnmmnnkkkknnnmkbkknnknnnnnkkkkbmmkkkkkkkkkbnjjjljjjljjjljljlljajljjjjljljjjljjjc`kmnnkknnnba```akmnnnnmnnnnknnnnnnmnkkkkbbkkknnnmknmmmnbbbkbbbbbknnmkknnkknknnknnnnnkkkbabbbbkkbiabbbbbbbdnnkkmbknnknnmnnmkmbjinijljljjjjjjjjjjjjj", "llljllllllllllllccclllcllclclllcllcccccccccclcccccccclcccccc`lccccicciccciccicciciciciiiiii`ickmmnmnmnbbbbbclciicccilcciliiilciccicccccclcclicllllcclcccllciiciciiciiiiicciiiicci`iiclliiiciiccciiiicciiiccccamknkkbkbkkkblljljjljjjjjjjjjjljljjlljjljjjjjjlllinmmnnnknmkaacccciiiciiiiiiiciiiciiiicccclciiicc`cciccillccclclciiciclicliicccliiciccccccclccccllllciccccliiciiiakkknnmmnmnnkciijljjjjjjjjjjjjjjjj", "ljlcljlllllllllllclllcllllccccccccclccllcccccccccccccccccccclccccccccicccicci`iiciiiicicii`a`ikmnmmmnkbabbijjjjjjjjljljjjjjljjjjjljjjjjjjjljljjjjjjjjjljjjljjjjjjljjljjjjjjjjljjjjljjjjjljjjljjjljjjjjjjjjjjjinnnkkbbbbbkbjjjjjjlljjjjjjjjljjljljjljajjjjjjljccknnnnknnmkbacjjjjjljjjjjljjljjljjjjljjjjjjjjljjljjljjjljjjjjjjjjjjljjljjjljjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlikkbknnmnnmkncjljjjljjjjjjjjjjjjjj", "llllllcllllllllcclclclclccllclclclcclcccccclilccccccccccilicciccicccccciciciibiciciciiciiia``immmmnnmknnkkillljcccjljclljlllccjijljcllljljlljjljljjljlcjlllllllllcllljlcjljjljllljjlclljllilljllclljlcicjclclcknkkkkkabbbkljjjjljjjjjjjjjjjljjljjjjjjjjjjjjjjcianmnnnknmnbacjllclcjcjcjcjllllllllljllllccjlllllljljllcjjllllljlljljjljljjjjlljjjllllllllcjllljllclljjllljljjllabbbbbknknmkn`jjljjjjjjjjjjjjjjjjj", "lllllljcllcllllccclllclcclclclclcccccccccmkcccilccccccccccccccicccciccccciciiaiiciiiiiiiciii`immmnmnnmmnnkclnmfffffffeeffmmffmmffmfffffmmffffeffemfffffmmmffffffffffffffffmmmffffffmffmmfffffmffffmffmmmmffmmkkmnnkbbnkabkjailjjjjjjjjjjjjjjjjjjjjjjjljjjjjjlcibknmknnnnmkdidkkkmnnnnmmmnkknkkkkkkkknkkkkkknknknnkkkkkkbkbknknnkkknnkkkbkkbbbbbkkbbbbbbbbnkkbbkbkbbkkkabbkbkda`dbbbbbbkbnmnljljljjjj`jljjjjjjjjj", "jlllllcbccnnclclllklclllllcclcclcllccclcciclclciccccccicccccicaiccccciciicciciciiicicicii`ii`innmmnnnmfnmnilmffffeffffffffffffmffmmffffmmfffffffffffmfmmmmffffefffeffeffmffmmmfffmmmffffffffffffffffffmmfffffnbnnkkbbkkkbaljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlcibbmmnknnmkka`bnknmmnnnnnnknnnkkkkkbkknnkbkkknknknnkkkkkkbbbkkkkkkkkkkknnkkkkbbbbkbbbbbkbbbkkkbbbkkkkkkbbbbkkbba`bbabbbabaknniljjjjljjjjjjjjjjjjj`", "c`iljllllliclclclkicllicllccccccccccccccaaiciclcccciclilcicccc`cciciccciciiaiiciiiciciiiii`i``nmmnkknmmmmmilmmmfffffmmffffffmmffmfmmfffmfmmfffffemmffffmmfffffffffffffffmffmmnmffmnmmfmmfeffffffffefffmmfffffkbknnmkbbknkbljjjjjjjjjjllcjjjjjjjjjjjjjjiljjjjliibknmkknnnmnnabkkkmnmnkkknknnkkkkknkkkkknkkkbkknknnkkkkkkbbkkbkkkbkbkkkkkkbkkbbbbkbbbbbkbkkkkkkbkbkbkbkkbbbkbkba`bbbbbbaabkknbjljjjjj`jjjjjjjjijjj", "lljlcclllllllcccclcllcllccclclcccccclccccccclciccccccciccciccaccccccicicciibiiiciiiiiii`i``i``nmnnnkknmmmnicffffffffmmmmfffmmffmffmmfffffmmmffffffmefefmfffffffnfmmmmmmmmffffffffmmmfffffffffffmefffmmffffffmnbbnnmmkbbbknjjjjjjjjjjjjjjjjjjijjjjjjjjjljjjjjliidbnmnnnknmnnaaknmnnnkkkknknnkkknkkkkbknnknkkbbkknnkkkkkkbbnkknnbbbbkbkkbbbkkkkbkkkbbbbkkkkkbkkbkbkkkbbkbkbkbkkaiabbabkkkbbbbajjjjjjjbljjjjjjjljjj", "llllllllcjccjlcllcclalccclclaccccccccccccccccccccciccicicccicbcicicicicicic`iciiiiiiii`iii`ii`nnnnnnknmmnmccmffffffmfmfmffffmffmfffmfeffmfmmffffffmfffmmmmfffffmmmmmmmmmmffffefffffmmffffmfffffffffmmfffefffmnkbkkmmnkbbbkjjjjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjci`bbkmmnkknnnn`annnnnnnnkkknkkkknkkkkkkknnknbkbkkkkkkkkkkkkbnkkkkkbkbbbbbbbbkbknnkkbkbkbkbkbbbkbbbkkkbbbkkkkkkkbbibababbkkkkba`ljjjjjjjjjjjjjjjljjj", "llllllcllclliccclllclccllccik`lc`ccicccccclccccccccciclccicccciciciciciciiccciiiciiiiiiiii`ii`nmnkkkknnmnnlcmmmmffmfmffffffmmffmmfffefffmffmfffmmmnmmmmfmfffffmmmfmmmfmmmfffffmmffffmmfffmmfffffffmmmfffmefmnnkkbbknnnkbabjjjjjjjjjjjjjjijjjjjjjjjjjjjjjjjjjlc`kkkbknnnkmnnaakkknknknnkknnkkknkkkkknmnnkkkkkkkkkbbkbbkkkbkkkkkbkbkbbbbkbbbkbkkkbkbkbkbbbkkbkbbkkkbbbbkbbkkbbba`abbbaabknkkb`ljjjjjjjjjjjjjjjcjjj", "cllcclllllccccclclclccllcclliccciclcccccciccciccicccicaccciciciiciciciciiciiiiiiiii`i`iiiiiiibnmkkkkkknnnmcifmfmmmmmfmmffffmfffffffeffffmffffefmmfmmffmfmfefmmmmmmfmfmmmnfmmmmnmmffffffefmfffmfffmmmmmmnmfmnmnbkbbbkknnnkbljjcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`bmbbbknmkkkkbannnknkkkkkknnnknnnkkknnnnkkkknknkkkkbkbkkkbkbkkkbbbbkkbkkbbbbbbbbbbbkbkbkkkkbbkkbkbkbbbbbabbkbabb`abbbbaaabkkkbljjjjjjjjjdcjjjjjjjj", "lccllcilclllccclllclcccccccclcclccccc`biccccccc`ccicicfiiccciiliiciciciiciiciiciiii``iii`iiiibnmmnkkknnnkklcmmmmmmmmmmmmefffffefffffmmffffmfffffnfmfffnfmfffmmmmfffmfmmmffmnmmmmmnmmfffffmfffnmfnmnmnnmmmfnmfnbkkkkkkknnnmljjljjjjjjjjjjjjjjjjjjjjjjjjljjjjjlciamkba`knnnnbb`nknkkkkkkkkknmkknmnnnkkkkkknknknknnkkkkkknkkbknbbbkkbkbbbbbbkkbbbbbbbbbbbkkkbakkbbbbbbabbababbbbb`aba`aaaabbbbbjjjjljjjjjjjjjjjjjjj", "lclccc``cllccclclccclccclcccccccccccccccbaiccci`cicicciicciciciciciciciiiiaiiii````ii`iiii`i``nmmnnkknnmnklammffmfmmmmmmmmffffmffffffffeffffemmmmffffffmmffmmmmffmffmmmmfffmmnmmnfmmmffffffffffmmmmnmnmmmfffmmnkkkknkbkmnnjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjcccbnbbabbbnnknn`nnknnkkkkkkkkknnnkknnnnknkkknnkkbkbbkkkkkkkkkkbbbbkkbkbkbbbkkkbbbbbbbbbbbkkkkbkkkbbbbabbabbbkbbkbbbnbi`ii`abkbbjjjjeajjjjjjjjjjjjjj", "ccllllcclclcclcclcllcclccccclcccccccccciciicicccilckciciiciciciciiciiicicii`i`iiii`iiiiii`ii``nnmnnnnnmnnklammfffmfmmmmmmmffmmmmffmfffmfffmffnmmmfmfmfmmnmmmmmmmmmmfmmnmmmmnmmmmmmmnnmmmefffmnmfnnnnmnnmnnffmmkbbkkkbabmnkljljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl``abkbkbbbknnmm`knknnknkkkkkkknkkkkkkbkkkkknnnknbkbbkkkbbbbbbbkbbbbkkbkkkbbbbbbbbbbbbbbbbbbbkkkbbbkbbbbabbaabbbkbaakbiiii`aabbkcljjjjjjjjjjljjjjdkj", "clllclclimalccllcclclcccclcccccccccccccccicccciiiciiccicciciciciiciiiiic`iakciiiiiiiiii`ii`iiakmmnnnnnnmnkjanmmfffmfmmmnmmmmmnmmmmmmmmmmfeffmmfmmffmmffmmmmmmmmmmmffmmmmmmmmmmmmmnmmmnnmmfffffmnmnmmmnmnnmffmnnbbbbbbabnmmcjjjj`jjjjjjjjjjjjjjjjjjjjjjjjjcljlii`knkbbbkkbnnn`kknnnnkkkkkbkknkbbkkkkbbkkbknnknkkbkkkkbkkkbbbbkbbbbbbkbkbbbbbbbbbbbbbbbababbkbkbbbbabbbbababbbbb``ka`icc``aabkljjjjjjjjjjjjjjjjjjj", "lclcllcccclcllcclc`kcclcclccclcacicciliccccccccccicciciciciciciciiiciciiii`i`iiiiiii`iiaiii`iakmnmnmnnnnnblbmmfmfffmmmmmmfmmmmmffmmnmnmfmffmmmmmmfmmmffnfmmmmnmnmmmmmmmmmmmmmmnmmmmmmmnmmmmffmmmmmmmmmnnffmfmnnnbbbkkbbbbbcjjjjiljjjljjjjjjjjjjjjjjjjjjjjljjlc`aknnkkbbkbbbk`knnnnnnnkkkkkkkkkkkkkkkkkbbkbnkkkkkbkkkbkkkkbbkbbbbbbbbbbkbbkbkbbbbbbbbbbbbbkbbbkbbababbbbbbbbbkba`bb``lciaabkncjjjjjjjjjjjjjjjjjjj", "llllllccccllcclccccciclccclc`iliccclccicicciiicccicciiciciiciiiiciiiiiii`iicii`c`iiiiii`iii``annmmnnnmnnnbjbmffffmfmmmnnmmmmmmmfmmffmmmnmmfmmfmmmmfnmfmmnmnmmmmffmnmnmmmnmmmmmmmmnnmmnmmfmknffmknnmmmnmmffffnmnnnkbbkbbba`ljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`annnnnkbbbb`aiknnknknkkkkkkkkkbkknkkbkbkkbkkkkbkkbkkbbbbkbbbbbbbkkkkbbbbbbbbbbbbbbbbbbbbabkbbbkbbbbbabbbakbkbbbb`kbailciankkn`jjjjjjjjjjjljjjjjjj", "clllccllllccjcilccllnacllicanaclccn`ccikaicccciicci`cciciciciciiii`iiii`ib`iiiciiiii`iiiii`i`knmmmnmnnmmmblkffffmfmmmmmmmnmmmmmmmmmmmmmnfmfnmffmmmmfmmfmmmfnmmffffmnmmmmmnmnmmnmmmnmmmmfnffffmffmmnmnmmfffffmnnnnnkbbakn``jjjjajji`jjjjjjjjjjjjjljjjjjjjjjjjl`i`nnnnnnbka`ciinnnnnknkkkbkbbkkkkkkkbkkbkbkkkbkbbkkbbkkkkbkkkkbbbnknkbbbbbbbbbbbbbbbbbbbbbkbbbbkbbbbbbbabbbkkkkka`kb`clciannkk`jjjjjjjjjjjjjjjjjjj", "clclcclccclicllclcccacciccciicciicacccli`cccccccicimiiciiiciiiiii`i`i`i`iicii`iii`iiii`ii`ii`knnmnnnmmnmmblkmffmfmmmmnmmnmmmmmmfmnmmnmfffmfmmfmmmmmfmffffffmmffmffmnmmmmmmmmmmmmmmmnmmfmfmmmmmffffmmmnmffmffmmnnmnnkbbknblijjljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiannnknkbbi`ciinnnnnkkkkkkkkkkkkkkkkkkkkbkkkkkkkkkbbkkkkkknkkkbkkkkkkbbbkbbbbbbbbbbbbbbbbbbbkkbbbkbkbbbbbbbbkbbbbibbicci`kknnnajjjjjjjjjjjjjjjjjjj", "llcllclclcjcccclclcclcccbcccccccccicicicccciciiccccicciiciicicii`iii``iiiiiiicii`a`iii`iiiiiinnnnnmnnmnmnbjkmffmmmmmmmmmmmmmmmmmmmffffeffnmmffmmmmmmmnffmffnmffmmmmnnmmmmmmmmmmmmmmnnmmnnmmfmmmmmnmnnmmmmmmmmnmnnmnnkbbba`jijjjjjjjjjjjjjjjjjjjjjjjjjjjjljjjl`iaknmkkb`iiii``nnnkkkkkkkkkkkkkbbkkbbkknnmnkkkkkkkbkbkkbbbkkkkkkknkkkbbbbbkbbbbkbbbbbbbabbbbabkkbabbbbbabakbbbbbb`ab`````nnnkk`jjjjjjjjjjjjjjjjjjj", "lcllccccccclclcccccccccciccccccccccccicciciccciciiciciciiciciiiiaiia`iiiiiiiiiii```i`iii`iiiikkkbmmmnmmnnalnfmmmnmmnmmmmmmmmnmmnmffmffmffffmmfmnmmmmmnmffmfmffffffmmmnnmnnmmmmmmmmmmnnnmmmmmmmnmmmmmmmnnmnnmmmnnmkmnnkabi`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`nnnka`ic`a``innknkkkkkkbkkkkkkkkbkkkknkkkknkkkkbbkkbkbbbkkkkkbknbkkbbbbbbbbbbbbbbbbbbbababbkbbbbbbabbbbbabbabbbcibbai`akkmkkbjjjjjjjjjjjjjjjjjjj", "lccllccclclccclccccccccccccicccc`ciliciccccciccccciciciciciiiii`faiii`iiiiii`ii`ii`ii`iiiiiiikmnkbmmnmmnfalkmmfmmffnmnmmmmmmmmfmffffffnmfmfmffmmmmmmmmmfmfffffffmffmmmmmmmmmmnnmnnnnmmmmnmmmmmmmmmmmmnnmnnnmmmmnnmnnnkba`ajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj`i`nnbbaa`iaaa`inkkkkknkkkkkkkkkbkkkkkknknnbkkkkknkkkbkbbkbkkbbkkkkbkkknbbbbbbbbkbbbbbbabbbbbbbbbbbbbbbbbbabbababa``bba`aabbbnfkjjjjjjjjjjjjjjjjjjj", "clcllclllclccclcclcccccccccclciccicccccciciiiciiciciciiciiiiii`iicciiiiiiiiiiiiiiiiiii`iiiii`nnmbbkmnmmnk`jnnmmmffmmnmnmmnmmnmfmmmfffffmfmfmffnmmmnmmmmfnfmfmfffffffmnnmmmmnmmnmmmnmnmmmmmmmmmmnmmmmmmmfnnnnnnknnfkkknn``aljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji``nnnbbbaaabaaikknkknnkbkbkkkkkkbkknkkknnnkkkkkkkbbbbbbbkkbkkkknkknkkkkbbbbbkbbbbbbbbabbbbbbbbbbbbbbbbbbbbbbbabba`aba`abbbkbakkjjjjjjjjjjjjjjjjjjj", "lclclccccccllccccccccccccciciccclic`cciiiciiiiciiiicicciiiiiiiciii`iiiiiiii`iii`ii`i`iii`ii`akbmnabnnnmnb`jffffmfffmmmnmmnmmmmfmfmmmffffffffffmfnmmnmmmfmffmmfffmmfmmmmmmnnmmmmmmmmnmnmnmmmmmmmnmnnnmfmmfmmmmnknnmnkknkaabjlljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlic`bkmkbbbabbaainnnknnnkkkkbkkkkkkknkkkkkkknkknkkkkkkkbbbbbbnnkkkbnnkbbbkbbbbbbbbbbkbbbbbbbbbbbbbbbabbbabbbkbbbbbba`baaabkbnbbkbccjjjjjjjjjjjjjjjjj", "clcccclcall`lcclccccccccccccbiciicicccicccciicciciciciiii`iiiiiiiiccii`iiiiii`ii`iiiiiiiiiciabbkbbbbmmnnn`jffmmfmfmmmmnfmmmfffffffmmmfffmfffffffffmnmnnmfffmmmffffmmmmnnmnmmfmfmnmmmmmmmmnmnnnnnmnnmmmmmmfmmmnnknknkknbbbkljjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjj`iabknnnkknnkbbinnnnnnnkkkkkkkkknnknnkkkkkkkkkkknnknnkkbkbbbnkkkbbkkkkkkbbbbbbbbkkkbkbbbbbbbbbbbbbabbabbbbbbbbbbbbaabababbbbmnkbljjjjjjjjjjjjjjjjjj", "clclclcl`lcmcccccccccccccciikiiiii``iiicicciiccicicicii`iiiiiiiii```iiiiii`iiiiii`ii`iiiiiii`bbbbkbbmmnmmilmfnmmmmmmmmmmmmffffffffmmffmmffmmfmffmmmmmmmffmfnmmffffmmmmnnmmmffmmmmnmmmmmmmnmnmnmmmfffnnnnmnnmmnnkkknnkkbkbkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji``mnkkknnmmkbbiknnnkkkknnkkkknknnnnnnnkkkkkkknkkkkkkkkbkbkbkbkkbbbkkbkbkbbbbbbkbkkbbbbbbbbbbbbbabbbbbbbbbbbabbabba`b`bkkkkabmmbljjjjjjjjjjjjjjjjjj", "clcccllclcikcc`cccccccciiciib`iiiiabibiiiiiiciiiiiiiiiiiiiiiiiiiiiiciiiiiiii`i`iiiiiiiiiiiic`kbkbbbbnmnnmicmfffmmmfmfmnmfmmfffffmmmmffmffffmmnmmmmmmffmmmmmnmfffnmmmmfffmffffmnmmmmmmmnnmmnmmmmmmffmmnmmnmmnmnnnkkknkkdbbkljjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjji``mnkbbkknkkbaiknnnkbkknkkkknkknnknkkkkknnnknkkbkbbbkbkkkkkkkkkbbkkkbbbbkkbkbkkkbbbbbbbbbbbbbbabbkbbbkbbbbabababaaiiibknnkkknnnijjjjjjjjjjjjjjjjjj", "cclcclcclccclcnicccccciiiiiiciii`ca`iaiciiiciiiiiiiii`iiiiiiiiiiiiii`ic`i`iiiii`iii`iiiiiiii`bknbkkbbnmnnilnfffnmmmmmmmffmfffffmmfnmffffffnmfnmfmfffffmnffmmnfmmmfmmfmmmmffffmmmmmmnmnmmnmmmmmmfmnnnmmnnmnmnnkknkkbnnkbbnbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`kmnkbbkkbbbbiknnnkknkkkkkknkknnnknkbkkkkkkknbkkkkkkkkknnkbkkbbbkbbbkkkbkbbbkknkbbbkbbbbbbbbbbbbkbbbbbbabbbbbabbalilbkkkknnnnmijjjjjjjjjjjjjjjjjj", "lccclccclcccccccccccciiiiiiiiciiiiii`i`iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii`ii`iiiiiiiiiiciankbbkbbbkkmmccnfffffffmffffmmnmmmmfmmmfffffmmfffmfffmmfffmmffffffnmmfffmmmfmfffmmmnfmnmmmnmnnmffmnnnnnnnnmmnmmnnnkknnkkbkkkknljjjjajjjjjjjjjjjjjjjjjjjjjjjjjjjjjc`iknmnbbbkbbba`bnmnnnnnnnnnnnkkkkbnkbkkknkkkkknnkbkknkkkkkbkknnkkbkbkkkbkbkkbbkkbkbbkbbbbbbababkbbabbaabbbaabbbaaalccankknkbnbkajjjjjjjjjjjjjjjjjj", "lclliclcccccccccccccciiia`ccciiicickkiiiiiiii`ii`iiiiiiiiiiiiiiiiiiiii`ii`iiii`ai`iiiiii`ii``mnkkbbbabkkklcnnffffffffefffmmnfffmffffmmmmfmfmmnmmffmnmmmffffffmmmmmmmmmffmfffffmmmmnmnnmnmmmmnnnnnnmmmnnkmmmnmnbbknnkbbknnnljjjjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjia`kbnmnbbbbbkaabknnnnmnnnnnnnkkkknkkknkkknkkbkbkkkkknkkkkknnkkkknkkbbkbkbbkkkkkkkkkbbbbbbbbbbbbbbbababbbabbbbbbkbalciakkknnknkkdjjjjjjjjjjjjjjjjjj", "cclibccaccclcccccccciiicaccciiicic`aai`iiiiiiiiiiiiiiciii`iiiiiii`i`iii`iii`ii`iiiiiiiiciccc`knknkkkbaaa`lifmfmmmfffffffmmnmmffmmfmmmmmmffmfmfffffmfmmmfmfmmnnfnfmmmmnfffffffmmmnmnmmnmmmfmnnmfmfmmfffmmmnmnmnkkbkkkabkknncjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc``kbknmnbbknnkabnkkbnnnnmnnnnnkkknknnnnkknbknkkkbkkkkkkkkkkbkkkbbbkbkbbbkbbkkkkkbbbbbbbbbabbbbbbbakbkbkkkbabbabbbkci`akknkknkkkajjjjjjjjjjjjjjjjjj", "cclc`lcccccccccccccciiiccciiicciicac`ii`ii`i`iiiiiiiiiiiiiiiiiii`iiii`ii`iiiiiiiiiiiiiiciiiiakkknnmnba``ij`mmmmmffffmmnmnmfmmffmfffffmmmffmmmmnmnffffmmmmfnmmmfffnmfnnffmmmmmmmmmnmnnmmfmmnnnffffmmmmmmnmnnnmnknkbabkkkbbkljjjjjjjjjjjjjjjjjjljjjjjjjjjjjjjjji`ikkkkkmmnnnfnbbnknknnnnkknkkkkkkknkkkknnnbknnkkkkbkkknknkbkkkkbbbbkkkbkbbkkkkbbbbbbbbbabbbbkkababkbkbbbbbbbbbbabki`abkkkkkknnkbjjjjjjjjjjjjjjjjjj", "lcllccclcccccccccciiiiiccciicciiciciiiiiiii`iiiiiciiiiiiiiiiiiiiii`iiiiii`bb`iiii`iiiciiiccibnkkbknbba`cijafmmfmfffmmmnmnnmffmffffffffffffmmmmffmffffmmnmfnnmnfmfmmfnnmnmmnnnnmmmnnnmmmmmnnnfmmmnmmfffnnnmmffmknkbabbbkkkkljjjjjjjjjjjjjjjjjjjjjjjjjjjjj`ljjjca`bknkknmnmnnmbannnknkkkkknkbkkkkknnknnnknknkkkbkknkkkkkkkkbbkbbbbbkbbkkbbbbbbbbabbbbbbbbbbkbbabbbbbbbbbkbkbaabkkbaakkkkbbbkknnnjjjjjjjjjjkjjjjjlj", "cccclcccccccccccccccciiiiciicciccici`ii`i`i`iiiiiiiiiiiiiiiiiii`iiiii`iiiiiicci`iiiiciiiiiciakkkknkaaa`i`jamfmmmmmmfmmnnfnnmffmfmfmfmmffffffffffffmmmfmmmmnmmnfmmmmfmnmnnmmmmmnnmnnmmmmnnnnmfmmnffmmfmmmnnmmmnnnmkbkbbknnbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji`ikkknkbkmnnkkbannkkknknnkkbkbkbkknnnnnkkknknnknknkkkkkkkkkbbbkkbbbkkbbkbbabbbbbbbbbbbabbbbbbaabkkbbkkkbkbbbbbbkbbaakkkkkkkbbbknjjjjjjjjjjjjjjjjjj", "clcccilcccccccciiciciiicccciciicic`iii``ii`iiiiiciiiiiiiii`iii`ii`iiiiiiiiii`iiiiiiiiiiiiiiibkknnkaaaa`abjanmnnfmmmfmmnnmmnmmmmmffmmnnmmffffmmnnfmfmfffmffmffmmmmfmmnmmnmmmmmnmnnmmmfmnnnnmmmmmfmmnnnnmmnmmnmmnmmnkkkkkkkkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc``kbkkkbknmnkkbannkknkkkkkbkkkbkkknkkkkkbbkkknnkkkkbkknkkkkknnkkkkbbbkkbbbbbbbbbbbbbbbbbbbbbabbbbkbbbbbbabbbbbbabbaaknknkknkkbkkljjjjjjjjjjjjjjjjk", "lcccbf`cccccciiaccccciiiiciccciiiiim`iaii`iiiciiiiiiiiiiiii`iiiiiii`i`iii`iciiiiiiii```iiiicabbbkb`iba`abjamfnnmfmmmmmmfnffmmmmnnmmmmnmfmmmmmnnnnfffmmfffnmmmfnmmmmnnnmmmmmmnmnmnnnmmnnnnmfmnmmmnnnnnnnnmmfmffmnnmmnkknbbbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`ibabbkkkbnnkbkakkbkkkkknkkknkkknknkbbkkkbbkkbkkbkbbbknnkkkkkkbkkkbkbbkbbbbkbbkkbbbabbbbbbbbabbkbbakbabbabbbabbkkka`knknnmnnnbnkljjljjjjjjjjjjjjjj", "k`ii`icclccccciccciicc`ccicicciiciicibniiiiiiiiiiiiiiii`caci`ii`i`iiiiiiiiiiiiciiciiiniiiiic`b`abaiiaaabbjbmmmmmnnnmmmfffffmfmnnmnffmnnnmmmnnnmnnmffmmmffmmffmmmnmfmmmnmmmmnnnmnfffmnnmmffmmmnmnnnnmmnmfnmmfmnnmnmmnnkkknbcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjci`akkbkkkbbbmkkanknnkkbkkknnkknnknbbbbnknkbkbkkkbbkbbbkkknbkkbbkkkbbbkknkbbbbkbbbbbbbbkkbbabkbbbbbkbbaaabbabbbbbbbaakknnnkbknnkbijjjjjjjjjjjjjjjjj", "ilcciccciccccccciccccii`iiiiciiciiiiiiai`iiiiiiiiiiii`ic`ii`iiaciiiiiiiiiiiciiiiii`iiaiiiccaabaab`iiaabbblkfmmfmmnmmmfmmfffmmnnmnnmmffmmffffmmmmmmmmmmmnmnmmmnnmmmnmmnnmnnnnmmnmmmnmnnmfnmmfmnnnnnnmmmmmmmmmmnnnmmnmnnnkbk`jjjjjjjjjjajjjjjjjjjjjjjjjjjjjjjjjc`iabnkkkbbbbkkk`knnnnbbkknnnnnmnbkbkkkbkknkkkknkkkbbbbkkkkbbkbkbbkbbbbbbbbbbbbbbbbbbbbbbbabbkkbkbkababbbbbkkbbbbbbb`knnnnkbbkkkkijjjjjjjjjjjjjjjjj", "cccciciclccicliaccccciliiicciiiiiii`iiiiiiiiiiiiifkiikaiiiiii`c`iiiii`aai`c`iiiiiiiiiciiiac`bb`aacc`bbkkalkmnmfmnnnnmmmnfffnnnnmnmmmmmmmmmnmmmnmmffffmmffmmmmmmmnnnffmnmnnmmfmmmnnmmmnmmnnmnnnnnnnmnffmmnmnnmmnfmnmmnmnnkbljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`bbbbkkkkkbkkk`knkkkkkbbkbkbknnkbbkbbbkkkbkkkkkbkkkkkkkkkkkkkkbbkbkkbbbknbbbbbbbbkbbbbkkbbbbbbbbabbbbbbbbbkbbbbabaannnknnbbknkk`jjjjjjjjjjjjjjjjj", "cciccicccccccciicciciiiiiciiiiiiiiiii`iiiiiiiiiiiic`iicii``ii`iiiiiiiii`iaikiiiiiiiciciiikilab`a`ciakkbk`jnmnmmmmmnmmffmmfmnnmmnnmfmnmmfmmmnmmffmmmfmfmmfmmmmmmfnnmffmnmnnknnnknmmfffmnnnnnnnmmmnmfmnmnmnnnnnnmmnmmnnnnnmkljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`bkbbbbkkbbnkk`kkknnnnkbnnnknnkbkbbbkknkbkknkkbkbkkkkkkkkkkkkkbkkbkbbbbkkbbbbabbbbbbbbkkkkbbbaabbbbbbbbbbbbbabbaba`knnnnmkbmmnndjjjjjjjjjjjjjjjjj", "ccccccciccccciclcicicia`aiiiicciii`iiai`iiiiiiiic`iikb```ii`eic`iiiiiciccnicbiciiccciciciiickai``c`bnkkkajnmmmmmmnmmmfmmmmmnmmmnnmfmmmffmmnnmmfmnmmfmfmfmnmmnmmnnmfmmmfffnnmnnnmmmfffnnnnnnfffmmmmfmnnmnmfmnnnnmmnkknnnnnn`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlicibnnnkbbkkbnkk`nknnkkkkknnnkkkkbkbbkbnnkkbkkkkkbkkkkbbbkkkkkbbkkbbbbbbkkbkkkbbbabbabkkkkkbbbbbkkkkkbbbkbbbabbbbbbb`aaknnknkmmnnbjjjjjjjjjjjjjjjjj", "cclicciiccccccciccciccbib`ciiiiiiiiii`iiiiiiiiii`iiia`ica`iciin`iiii`iii``cinciccicccccciccinic``aaknnkkajnmfmmnnnnnnnnnnmnnmfmmffmfmmmmnmfmmmmnmmmffffmmmmfmnmnnmffmmmnmnnnnnnmmmmmnmnnmffffmmmmfmmmmmmnmmmnmnnmnnkknnnkn`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiciibkmnkkkkkkkkk`nmkkbbkbbkbbbbkbbkkkkkkkknkkkkbbkbkkbbbkkkknkbkkkbkkbbbkkkkbkbbbbbbbbkbbkbababkbkbkbbbkkbbbbbbbbbbb`baabnnnkmnnkkjjjjjjjjjjjjjjjjj", "cclcccciaicccccciic`icacaiciiii`ii`iiiiiiiiiiiiiiiii`ii`i`i`ciaiiiiiiiiciliaf`ilcciccccccicckic`abkknnnnajmmmnnmmmmnmnmnnnnnmfmmnnnmffffmffffmmnnnmmmmmmmnffmmfmnmfffmmnmmfmmmffmmnmnmmffmmmnnmnfmmmfmmmnmmnmnnnnnmkbbknmkijjjjjjjbjjjjjjjjjjjjjjjjjjjjjjjjjlciibbkknnkknbkkbikkkknknkkkkkkkkbbkkknkbkkknnnnkknkkkbbbkkkbkkkkkkbbbkbbbkkbbbbkbbbkbkkbbbbbbkkkbbbbbbbbkbbbkbbbbbbbakkbbknmnmnnnkjjjjjjjjjjjjjjjjj", "ccccciciiiicciccccciiciiii`iiiiiiiiiii`iiiiiiiiiiii```ii`iiiiiiiiiiiiii`cicia`aiicicccccciciaca`aknkknnn`jfmmnnmmnmmmnmmnnnnmnnmmmnnmnmffffffnnnnmmmfmfmnmmfmmmmfmmmmmnmnmffmmmnnnmmmmmfnnnnmfmnmmmfmmnmmnnnnnkknmnkabkknnijjjijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjci`akkkkknnbknkkannbnkkkkkkkkkbkbknbkbkbkbbkbkkkknkbbbbbbbbkkkkbbbnkkbkknkkkbkbkkkkbbbbbbbkkbbbabbbbbbbbkkkbbbbbabbb`bnnbbknmmnnkbjjjjjjjjjjjjjjjjj", "cccccciiicccccicicicciiiii``biiii`ii`a`iiiiiiiiiiii`iiiia`ii``iciccici`ciicci`icbicccccccici`i`aknknnnnn`jffnnfmmnmnmmmnnnmmmmmnfmmmnmmmnmmffnmnnnmnnnnfnmmfmmmfmnmmmnnnmnnnmmmmmnmmfmmfnnnnmfmmmmmnnmmfnmnnmnmkknnkbbbbkkcjjjjjjjjjjjjjjjjjjjjjjjljcljjjjjjjci`abkkkknkmbnkn`nkkkkkkkkkkknkbkkkbkkknkkbkkkkbbkmkkbbbbbbbbkbbbknkbkkbbbkbkbbbbbbkkkbakkbkkkbbaabbkbkbabbbbkbbbbbbaannnkbbnnmnnnjjjjjjjjjjjjjjjjj", "ccccccciicicicciciaaiccc`iii`iiiiiiiii`iiiiiiiii``iiiii`aiiiaa``ciiiiiiccciciiicilcclcccccciaabkkknnnnnn`jfmnnmnmmnnmmnnnnmmmmfmnnmmfnmfnmmffmmmmnmnnnmmnnnmmnnmmmmmmfffmnmmmmmmmnmmfmmmmnnnnmmnmnnnnmnnnnnmnmmnbnnbbkkbakijjjjcljjjjjjjjjjjjjjbljcjjljjjjjjcjiaakbkkbnknnnmm`nkkkkkkkkkkkbbbkkkkkkkkbknbkkkkbbkkkkkbkbbbbbkbbbkbbbbkbkkbkbkbbbbbbbkbbbkbbkkbkabkbkbbbbabbbbabbbaabnnnnbbbknmnnljjjjjjjjjjjjjjjj", "lciccciiciciccicciiiiiciii```i``i`iiiiiiiiiiii`iii`ii``b`iiiiiicicicciiiciccccccccicccccccciabkkknnnnnnnilnnnmnmnnnnnnnmnffmmmmmnmmfmnmffmmmfmfmnmmmnnnmmmmmnmmnnnnmnmmmnnmmmnmmmmmmmmnnmmmmfffmmmmnnmmnmmnnnnnnbkbbbkbbabcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjj``iabkbkbkkknknn`kkkkkkkkbkbkbkkknkknkkbkknbkknkkknkknbbkkbbbbbkbbbbbbbbbbkbbkkbbbkbkkbkkkbkbbabkbkbbbbbbaabkbbbbbbaaannnmnbbbkknmcjjjjjjjjjjjjjjjj", "iiiccciiiiciciccicicccci``iiii`ii`iiiiiiiiii`iii`i`iiii`iiiiiciiiciciiiiciicccccci`ilccccccaabkknnnnnnnnclmnnmnnnnnnnnmnmfmmmnnmmmmmmnmmmmmmfmmmnnmnmnnnmmmnnmmmnnnnnnnnmnnnffmnmnmmmnnnfmmnmmmmmmmnmmffmmnmnkkknkbkkbabbbcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`abkbkbkkknkkkckkbkkbkbkbkbkkknkkkkbbknkkkbkkkkknkkkbbbkbbbbbkbkkbkkbbbbbbbbbbbbbbkkbbbkbkabbkkbbbknkbkkkbbkkbbbabaamnnnnkbbabbncjjjjj`ljjjjjjjjj", "ciicciiiiiiiciicccciiiamb`i`i````iiiiiiiii`iii`iiii`iiciiiiiiiiiiciiiiiciiiccccccciccclccli`kkmmknknknnnccmnnfnnnnnnnnmfnmfnmnnnmmmmmmnnmnmmmmmmnnnmnnnnnnnnmmmmfmnnnnnmnnnmffmmmmmmnnnnnnnnnnmmnfmmnmmfmnnnnnkkkbbkkbabbbcjjjjjbjjjjjjjjjjjjjjjjjcjjjjjjjjjjcci`bbkbbkbkkkbkckkkkkkbbbbbkkkknkkbbbbnnkkkkbkkbbkkkkkbbbbbbbbbbbbbbkkbbbbbbbbbabkkbbbbbbkbabbbbababbbbbbbabkkbbaababnnmnmnbbbbab`jjjjjijjjjjjjjjj", "ccccciiciiiiiiiiiiciiccaiii`iiii`iiiiiiiiiii`i`i`iii`i`iiiiiiicciiciii`iiiiiciccclcclccccccaknmmmmnnnkknlcmnnmnnnnnnnnmfmfmmmnnnfmmmffmmmmnnnmnfnmnnmnmnnnnnnmmfnnnmmmnnnmmmnmmmmfmmnknnnnnnmmmfmmmnnmmmmknnnnkbabbbabaakaljjjjjjjjjjjjjjjjjjcjjjjjjjjjjjj`jjli``bkbbbkbkknkkckkkkkbkbkbbkknnknnkbbkkkkknkkkkkbbbbbkkbbbkbbbbabbbkbkbbbbbbbbbbbbkkkkkkkkbdbaabbbkbbbkkbbbbbbbabbabakmnnnkkbkkbbijjjjjjjljjjjjjjj", "cccciciiiiiiiiiiciiab`icci`a`ic`i`iii`ii`iiiii`i`iiiicciciiicciiiccicibiiiccccccicccccclcccanmnmmmmnkkkklimnnmnnnnnnnmfffffmnnnnfnnnmffffnmnnmnmmmnmnnnmnnnmmnmmnnmffmmnmmmnnnmmfmnmmnmmmmmnnnnnmmnmmmnmnnnnknkbabkbbbabbaljjjjjjjjjjjbjjjjjjjjjjjjjjjjjjjjijliiabbkbbkkbkkkb`kkkkkkbbkbbknnnnkkkbkbkbbkknkkkkkbbbbkkbkbbbbbbbbbbbbkbbbbkbbbbbbbbbbkbkbbbbbkkbbbbbbbbbbbbbbbbabbba`bnnnnknnbkbb`jjjjjjjjjjjjjjjj", "ccccccciiiiiiiiii`iiiiii``iiiiciiiiiii`iiiiii`i`iiiiiiiiiiiciiicciiaicaicciiccccclcclcclllcafmnfnmnnnnnnlcmfnmnmnnnnnmmfmmnnnnnnnnnnmmmmmnmnmfnnfmnnnnnnnnnmnknnnnnnnnnmmnnnnmfmmnnnnmmmmnmnnnmfnnmmmnnmnknkknbbbbbkbaaaaaljjjjjjjjjjjljjji`jjjjjjjjjjjcljjjjj`iabkkkbkkkkkmaaknkkkkbkbbkknnkkkkbbbbnbbbkkkkkbkbnkkbkkkbbbbbbbbkbbbbbabbbbbbbbbbbbbkkbbbbbkbbbbbabbkbabkbbbbbbaaaa`aknnnmnkknbbajjjjjjjjjjjjjjjj", "icccci`cciciiiiiii`iiiiiii``iiiiii`iiiii`i```iii``ci`ciiiiiccicicccciciiicicccccccclccccclikmmnmnmnnnnnklammnnknnnnnnnnnmmmnnknmnnnnnnmmmmmmfnnmnmmmmnmnmnnnmmnnnnnnnnnnnnmmmmmfnnnnnfnmmnnnnnkmmnnnmmnnmnmnnkbbabbba`aaailjjcjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiakbknkkkbknnk`nkkbbkkbkbbbkknkkbbkbkbkbbbkkkkbknbnbbbkbnkbbbkbkbbbbbbbbbabbbbbbbkbbbbbbbabkkkbbbbbbbbbabbbabbbbbaaibbbbknmmknkabjjjjjjjjjjjjjjjj", "icciccccciicci`bi``i`iii`i``ciiiciiiiiiiiiiiii`aci`iiiciiiiiiiccciicccccccciciccccccccclclcbnnmmnnnnnnnklaffmnnmnnnnnnmmmmmnnnmmnnknmmmmnnmmfnnnnnmmnmnnnmnnmnmnknmnnmmnmmfmmnnnnnnmmfmmnnnnnnnmmmmmnnnkmnnnnkbababaa`aaicjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiakkabkkkkknnnannkkbbkbbkbkkkknkkkbbnbbbbbbkkkkkkbkkbbbkkkkbbbbbbbbbbbabbbbbbbkkkbbbbbabbbkbbbbabbbabkkbbabbabbbabb`abbbkknmmmkbb`ljjjjjjjjjjjjjj", "macciiiicicciii`iii`i`i`i`knai`c`iii`iii`ii`ii`aaciiafiiiciiiciacciccccciciiccclccclccllclcaknnmmnnmnnnnjbmffmnnmnnnnnmmmfnmnnmfmnknmmmnmnmnnnmnmmnmmmnnnnnnnnnnnmmmnmmnnmmnnnnnnnnnnnnnnnmnnnmnnnmnnnknnnnnnkabaaaai```iiljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiiakbaakkknnnmnankmnkkkkkkbbkkkkkkkbbnkkbbnkkkkbbbbbkbkbnkkkbbbbabbbbbbbkkkkbbbbbbbbbbbbbbabbbbabbabbbbabkabababbbbb`abbbbbknmmnbbljjjjjjjjjjjjjjj", "biccclcciicciccii`iiii`iii``ci`ia`iiiii`iii`iii`c`iiii`ciiicccibccciciciiiiiiicccccclccclclabkkkmnnmmnmklanmmnnnmnnnnnnmmfmnnnnmmnknmmnnmnmnnmfmmnmmmmmnnknknnnnmmmmmmnnmnnmmmmmmnmknmmmnmmmmmnnnnnmnnnnknnnmkabbaa```a`iiljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`kkbabkbkknmnakknkkbkkkkbbkknkkkkbbnkkbbkkbbbkkkbbknkbkbbkkbabbbbbbbbbkkbbbbbkbbbbbbbbbbbbbbkbbbbkbbbabbabbababbbb`abbbbbabknkkajjjjjjjjjjjjjjjj", "cciiiiiicciiccib`iii`ii`i`````ic`ii`iii`i`i`iiiiiiiciiciicciiciiiccciiiciiciccilcclclcllcll``aaknmmnmnmblbnnmnnmmnmnnnnmmmmmnknnmnnnnnnnnnmnmnfnknnnnknnnnnnnnnnnnmmnmnmnmnnmmmmmnfnfmmnnnnmmmmnnnnknnnknnkknkabbaaaabba``cjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjii`baaaabakkbknakkkkbkkkkkkbbkknkkkbbbkkkbbbbbbbkkbbkkbbbbbbbbbbbbbbbkbkbbbkbkbbbkbbkkbbbbbkbbbbbbkkbbabaabaaaabaaaa`i```aabaknnbacjjjjjjjjjjjjjjl", "icccciccicciic`b```iiiiii``iiiiiiiii`iii`iiii`iiicii`cicciiciicccccccicciicicciclcclclcllcli``akkmmmnmnbjbnmmnmnmmmmnnnnmmmmnnnkmnnnnnnnkknnnnnnnnnnnknnmnnnnmmmnmmnnnnnnknknnnmmnmnnnnnnnknmmnnkkkknnkknnnknkabbaaabbkabaijjjjjjjjjjjjjjjjjjjjjjjjjjjljjjjjjjcci`ii`abbkkbkkabnkknknknknkbbkknnkkbbbkkbbkkbbbbbkkbkbbbbbbbabbbbbbkbkkkkbbkbbababbbbkbbbbbbabbabbkbabaababbbbbbabaiciii`aabbnnkacjjjjjjjjjjjjjjj", "liiicciiiicciiii`i`iiiii``ii``iii`iiii`i`iiiiiiiki`cciciciiccccicccccccccicciiaicccllcllclcaaabknmmnmnnbjkmmfnnnmmfmmnnknmmfmnmnnnnnnnnnnnnnnnnmnnnnnnnnnnnnnnnmmmmnnmmknnnknnmmnnknnmmfmnnmmmnmnnnnnmmnnnnkkbabaaaabkkbnaijjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjilcic``bkbkkkkbaankkkbkkkkkkkbbkknnkkbkbkbbbkkbbbkkbbbbkbbbbabbbbbabbbbbkbbbbbbbbababbkbbabbkkkbbbbkkkbbbbbabbbbabaaalccciabbbkkkbijjjjjjjjjjjjjjj", "icciciccciiciiiiii`iiiiiii`iii`iiiii`i`iii`iiiiiiic`ciiiiicciicccciccccccilcclilclclclccllcbbbbmmmmmmnnbjkmmmnknnmmnmmmnmfmfmmmfnnmmmmnnknmnmnnmnnnnnnnnnnnnnnnnmmmmmmmmnnnnnnnmnnnmnmnnnnknnmmnmnnnnnnnnnnnnkbb`i`aabnnkaijjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjcllcc`abbbabbkbaannkbbbkkkkkkkkkkknknnkbkbkkkbbbbkbbkbnbbbbbbbbbbbbbbbbkkkkkkkbbbbbabbbababbbabbabbbbbbbbabbbbabbbab`lllciibbabbbbijjjjjjjjjjjjjjj", "ccciciicciiciii``c`i`cii``iiiii`ikbn`iiii`iiiiiiiciiiiiccakaiccccccccccciccccclccllcllclllcbbbnmmmmmmnnajmmmnnnnnnmmnnnmnmmmmmmmmnnnnmmnnnmnmmmknmmnknmnnknknnmnmnmmmnnnmnknnnnnnkkmmmnnmnmnnnnknkknmmmnmnmkkkaaii``bkkkbaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicllccaakbbbann`bnnkbbkkknkkkkbkknnkknkkbbbbkkbbbbbkkbbbkbbbbbbbbabbbbkkbbbkbbbbbabbabbbabbkkbbbbbbabbbaaabbbbbbbbaaalccc`abkbbbabajjjjjjjjjjjjjjj", "ciiil`ciciciciiii`iiiii`ii```iiii`ia`i`iic`ci`iiiiiicciiiciccccciccccccccccllcclcccllclclccbbbnnnnnmmnn`lnmnknnnnnnmmnmnnmfmmmmmmknkknnknnmnmmmnmnnmmnnnnnnnmnnnnknnnnmmnnknnnnnnnnmmnnnmnnnnnnknnnknmnnknnnmka`i``abbknaaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicjcii`bkbkkknmaankbkbkbbknkkkkbknnnknkbbbbbbbbbkkbkkkbbbkkbbbbbbbbbkkbabbbbbbkbbabbbbbbbbbbbbbbbbabbbabbaabbbbaabbbblli``bkbbbbaaajjjjjjjjjjjjjjj", "ccciina`iicicii`iaiiiiiii``i`iiii`i``ii`i`a`iic`iciciiccciicciccccccclcccccccclclclccllclciabkmnnnnmmnm`jnnnnknnkknmmmmknmfmmnmfmnnnnnmnnmmnnmmmmmmmmnknnnnnmmmnnnnnmmmfkknnkknnmmmmnnnnmnmnnnnknkkknnnmnnnnmna````bbknbaaijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjljjcila`i`bkbknnnnaabbkkkbbbbnkkkbbkkkkkkknkbbbkkbbbkbkbnkkkkbbbbbbbbbbkkbbabbkbkkbaabababbbbbbbabbkbbbaaabababbbbbbabbbllababkbbbbbbbjjjjjjjjjjjjjjj", "iiccik`iiciacii`ibiiii`iii```i`ii`i`iciiiiiiiciciiiiiiiiiccciccccccccccccclccllcieillclllciabknnnnnnnnnilknnnnnnnnmmnmmnnmmmmmmmnnkknmmmmnnnnnmmnfmmnmmknnnnnmmnnnmmmmmmnnknnknnmnnmnnnnnmmnnknnknknkmmmmnkknkaaa`abakkaab`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjicca`iibbbknnnnb`bkbkbbkkkkkknkkknknnkkkbbbbbkkkbbbbbbkkkkbkkkbbbbbkbbbbkbkkkbkbabbbabbbbkbbbabbbbbbabbaabbabbbbbbaablcabbbkkbbbbbbjjjjjjjjjjjjjjj", "ciccccicciibiiiiiaiiiiiiiii`i`i``iii```iiiiiiiiiciiiccciciccccicilclcicccilclclclccclclcll`kknnnnmnnnnn`jnknnnnkmmmmnmmmnmmmmmmmmnnnknnnnnknnnnmnnmnnfmmmmnnmnnnmmnnnmmnnnnnknknnmnmmnnknmnnknknnnmnnmmnnnnkkkabaaabbaaibk`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliccb`iibbbbknknk`kkkkbknknkbnnkbkkknkkkkkbbbkkkkbkbakkkbbkbbkkkbbbkbbbbbkbbbbbkbbbababbbbbbbkbabbbbaabbabbbbbbbbaaabbcibbabbkbbaabbljjjjjjjjjjjjjj", "ciciiciicii`iii`i`ii`iiiii`iii``i``iaaai`iici`ciiicc`iccciiiccclccicccciiaillcclcjlallllll`knnnmnmmnnnn`lnnnnnnnmnnnnmmnnnnnnmnnmfmnmmnnnnknnmmmnnmmmmnmmmnmknkkmmnnnmmmnnkknnnnmmmnmmnknnnknnknnnmmnmmnnnmnnkbbb`abba`abkijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiicnk`cakbbknknkabkbkbkkkbkbkkkbbbbkbkkkkkkkbkkbbbbkbkkkbbkkkkkkkkbbbabbkkdkkbkkbabbbbbbbbbkbbabbbabbabbbbbbbbbbabbbaiiabbabkbabbbbjjjjjjjjjjjjjjj", "icciiciciicccii`iiiiiiiiiii`i````iiii`iikiiiabiiiiccaa`ibicbbicicc`iccc`ibcclclllacjclllll`bkknmmmnnnnnilnnnnknnnnnnnmmknnknnnnnnmnmmmnnnnnmnmnnmmmmnknnnnknnkknmmmmmmmmknknnmmmmnmnmnnnnnnknnknnnnnnmnnnnmnknkaiiiab`abbk`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjji`cnnic`bbkbknkk`bkkbbkkbkkkknkkbkkkkbkbkkkkkkkbbbkbbnbnbbkbbbbbbbbbbbabkkkkkkkbbababbbkbkbbbbbabbabbbabbbbabbbbabbab`ibbabbbbbbbkbljjjjjjjjjjjjjj", "cciiciciciiii`iiii`iii`i`i`iiii`````iiiiiiciiiicciii`iccciccccicccilccccc`lclllcclcllcllll`bbkbknmnnnnnicnnnnknmnnnnnnnnnnnnnnnnkmmmmmnnknnmnmnnnmmnknnnnnnmnnknknmmmnmnnnknnnmnnnmnnnnnnmnknmnnnnnknnnkkbnmnmbilcci``abkkijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`kb``akmbakkknakkbbbbkbknbbkbbbbbbbkbbbkkkkbbbbkkkkbbbkkbbbabbbbkbbbbbbbkkbkkbabbbbkkbkbkbbbbbbkbabbbaababbbaaabbbb`ibkabbbbkbbabljjjjjjjjjjjjjj", "iciciiiiiccci`i`iiiiiiiiii``i``i``iiiiiiiiiiciciiacciilccccciicciccccccclclclcllllllllllcl`abbbknmmnmnnlcnnkknnnnmnknnnnknnnnnnmmmnmmknnnffmmmnnnmnkknnnknnknnnnnkknnnnnkknnnmmnnmmnnnmnnnnmmmnknknnmnnnnkmnnnii`ciccikkbbijjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjjjic`bb``bkknbbbnnakkbbkkkkkbbbkkbbkbkbbbknkbkkbbbbnkkkbbbkkbabbbbbbbbbbbbababbbbababbbbbbbbbbbkbbakbbbbbbbabkbbbaabbbb``bbkaknbbkkakijjjajjjjjjjjjj", "cicciccia``ii``i`i`iiiii`i```i```i`iiiiiciiiiiiic`ciccaiciicciicicccccccclclcllclllllllcjcabbbknnmnmnnnlinnnnknmnnnknnnnnmnmmnmnmmnmnkknknmnmnnmknnnknnnknnnkknknnnknnknnnnmmmmmnmnnnnnmnnmnmnnnnnnmmmnnnnnknk`c`iiciiabbbijjjjjjjjjjjjjjjjcjjjjjjjjjjjjjjjjjjci`bb``bkkkkbbkkakbkbbkkkkbbbkkkbkkkkkkkkkkkkbbbbkkkkkkbbbbbbbabbbbababbbbabbbabbbbkbkkbkbbbabbbbbbbbbbbabbbbbbbabbab``babbbkkbbkkbijjjljjjjjjjjjj", "cciciiiciiciii``i`i`i`i`ii`````i`iiiiiii`iicicccciciicb`ciiicicicicccccclcllclllllllllllclakknmnmnnmnmmlinknkknmmnnmnkkmnnnmnmnnmnkmmnnmnmmnmmnmmnnmmkknnnnkknknnnnnnnnknnknnnnnnnnnnknmnmmmnnknknmmnnnnkknkkkiciiclcc`ank`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjic`kb`bbbkkkkbbk`bkbbkkknkkkkkbknbbknkkbkkkkbbbbbkbkkkkkbkbbbbbbbbbbbabbbbbkabbbbbbbbbbkbbbbaabbbkkbbbababbbbbbabaaabaibabbbbkkbbnkajjjjjjjjjjjjjj", "ciciciciiciiiiiiii`i`i``a`i```i`iiiiiiiiicic`iiiiccccci`iicccciccicciclccllclllcllcllcll`c`bbbmfmnnmmmnl`nknnkkmnnnmmnnmmnknnnnknnnkkkkknmmmnmnnmmnmnnkknnnnkknknnnnnmnnnmnnnmnnnnnnnknnnnmmnnknknnnnnnkkknknk`iicclcciakkajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlli`bbbknkkkkkkbbibbkbbbkkkbnkkkkkbbbbbbbkbbbbbbbbkkkkbbbbkbkbbbabkkbbbbbbbbbbbbbbbbbbbbbabbbbbabbkbkbbbabbbbbbabaabakaikaabkbkkbbkkajjjjjjjjjjjjjj", "cciciciciiiiiiiiiii````ibaiiiii`iiiiiiiiiciabiiliccciiiiccccccccccciclcllclllcllllllllllcjbnkbbknkmmmnmj`nnnnnknnnnnmmnmnnkknnnnknnkknnnnmmnnnkknnnnnnnnnnnnnknkknnkknnnnmmnmmnmknmnknnnmmnnnnknnnnknnkkknnnmkaiiccici`abbbjjjjjjjjjljjjcajjjjjjjjjjjjjjjjjjjjcciabbknkkkkkkkb`kkkkbbkkbkkkkkkkbbbbbbbbbbbbbbbkkkbbbbbbbkbbbbbbkbbababbbbbabbbkkbbbbbbbbbbbabbbbbbbbaabbbbabaaabbaba`nbabbkkkkbbkkjjjjjnljjjjjjj", "iiciciciiciiiii`iiiiiii`a`iiiiiiiiiiiiiib`iciciiiciiiibiccccccccccccclcllllclllllccllllllcbbbkkbkkkmnmnlannmnknnknknnmmnmnkknnnmnknnmmnfmnnnknnnknknnmmnknnnnnknknkkknnnmmmnnnnknnmkknnnmnnnnnnknnkkknkkknknnb`icc`ai`a`aa`jjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjjjlci`abbknkkkknnk`kkkkkbkbbbbkkkkkkbbbbkkkbbbbkbkkkbbbbbbbbabkkkbbaabbbbabaababbbbkbbkbbabbbbabbbbbbbbbabbbaaaabaabaabbikkbakkbbnkbbbljjjjajjjjjjjj", "iiciciiiiiiiiiiiiiiii`iiiii`i`iiiiiiiiii`ccciiciiiiiccalcccccccccclclc`lcllllllllcclllllllbbbnbabbbknmkjannmnnnknnknnmmmmnnnnknmfnmnnnkkmnnnnnnnkkkkknnkknknnnnkknknknknnnmnnnnknnnnknmmmnnnknnnnkkkkkkknnnnnk`cc`ab`a`cii`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlciaabbkknkkknnkakkkkkkbbkbbkkkkkkbbbbkkkkkkkkbbkbbkbbbbbabbbbbbbbbbbbbbababbabbbbbbbbbbbbbabakbkbbbabbbabaaabaabbabbaiakbabbbbbkankijjjjjjjjjjjjj", "iiicciciciiiiiiiiii`iii`ii`iii`iiiiiiiiciiiiciiiicciccliccciicclcllclcaclcllclllllclllllllbabbdkdddbnnklannnknnkknknnnnmmnnnkknmmmmnnfnnnknnnnnknnknnnnnkknnnnnkkkknkknnnnnnnnmknnnnmnnnmnnkkknnkkkkkkkknnnknb`c`bkbba`i``ijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjcibbbkkbknknkkn`kkbkkbbbbbkkbkkkbkkbbbknkkbkkbbbbbbbbbbbbbbbbbbbbbkbbbbbbabababbakbbbkabbbbkbbbkkbababbbaabaaaabbkaaa`bnabbkkbabbbkcjjjjjjjjjjjjj", "ciiiiciiiiciiiiiiiiii``i`iiiiiii`iiiiiiiciiciiicicccicccililccccclccllllllclllllllllbllllikkabbbbbkbkmblanmnknnknnnkknnnnnnnmmnmmnnnnnnnnnnnknnnnknnnnnnnnnknnnknnnkknnnkkkknnknknmnkknnnnknknnbkkkkkkkknmkkkb`ibknnkbaa``cjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjli`akkbbkbknnnnnibkbbbbkbkbbbkkbkkkkkkknkkbkbbbbbbbbbbbbbbbbbbbbbabbbbbabbbbbbbbbababbbabbbkabbbbababbbaaabbaaaakbbaaa`bnbbbbnkkbbbbljjjjjjjjjjjjj", "icciccicicii`c`ii`i``cc`ii`iii`ai`iic`iiciiciiiiccccccccclcccclcllciilclllllllllllllcjcllannkbbbkkbaknajknnkkkkkknnknmnnnnnnknnmnnnnnnnknnkkkkkkkknkknkkkknnnnkkmnnkkkkknkkknnnnnknnnknknkknknnnkkkkkkkknnmnnk`aknknknkb`d`jjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl``aknkbbkknnnkkikkbbbbbbbbkbbbkbbbbbbbkkkbbbbkbbbbbbbbbbbbbabbabbbbbbbabkbbaaaabaaababbbabbaabababbaabbbaaaaababbkbbb`ankabbknkbbkbijjjljjjjjjjjj", "iccici`c`ciii`kiiiiiiiai`iiiiii`ii`iiiccicciiicccciccccc`mlclclclccccllcllllclllllllllail`bkkbaknkbabkijnnkknknnkkkkknnmnnkkknnmkkkknnnnnknknnkknnnnnkknknnnknkkmmmnnnnkkkknnnnnkkknknkknkkkknnkknnnnnnnnmmnkbaknnnknfnbbnbjjjjjljjjjlcjjjjjjjjjjjjjjjjjjjjjjjl``bnnknkkbkknkk`kbkbkbbbkbkbbkkkbbbbbbkbbbbbbbbbbbbbabbbbbbbbbbbbbbbbbbbkkbbbbbbbbbbbkbbbbabbaabbbabbbaaabbdbbbbbbbaa`amkbbbknknkbbijjjjjjjjjjjjj", "ciiiiia`ci`bna`iii`iibfiii``i`iiii`iiiiiiiciiicccccicccclccl`cilcllllllcclllccllllllll``liabbabkkkkbbbilknkknnknnnkkknnnknnnkknnkkknknknknknknknnnnnnknknnnkknnmmnnkkkkknknknnnmknmnkknnnnnmmmnkkknknkknknnkkbbnnnknmmkdakbjjjjjjjjjjjljjjjjjjjjjjjjjjjjjjjjjjli`bnknnnkkbbkkmabbbkbkbbkbbbbbkkbkbbbbbbbbbbkbbbbbbbbbbbbbbbbbbbbbababbbkbbbabaabababbbbabbabbbbabbbbabbababbbaabaabaaamnabbkkkkkkkijjjjjjjjjjjjj", "c`icciiciiciiiii`ii`ian`i```iiiaiciiciibiciiiicccccccccccccinlclclcccccllllclclllljcljlilibbbbbbaabkkb`jbkkknkknknkkknnnkknkkkkknkknnkkkkkknknnknnnnkkknknnkknnmmmnnkkknnnnnnnkknnnmnknnkkknnnkbkknnkkkkkkknnkbkkknmnkbbknkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`i`bknknmkkbbbk`bbbbbbkbbkbbbkbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbababbbabbbkkknbababkkbkbbbbkabbabbbabbbbbbaaabbaaabaababa`nkbabbkkkknbaljjjjjjjjjjjj", "ibaiiiiiik`ciai`iiiiii`iii`iiii`iciiiciaiiciiccicccccccccllililcclllcclllllllllllclllllllibkbkndaabnkb`jknnkkkknkknnnnkkknknkkkknnnnnknkknkknnnnkkknknknknnnnnnnknnnnkkknmnnnnnnnnkkknnnnnnknmnmknnnkkkkkkkknnbnnknmnbbnnnncjjjjjjjjjjjjjjjjjjl`jjjjjjjjjjjjjjl``abkkkknmkbbbbibbbbbkbbbkbbkbbbkbbbbbbbbbbbbbbbabbbbbbbbbbbabbbabbbbbbbbbkbbbabbbbbbbabbbabbabbabbabbbbabbbaabbaaabaaikbbbabbkkbbbbjjjjjjjjjjjjj", "c`iciiiii`i`iiii`a`ii`iiii`iiiiciiiiicciiiiicccccccccccclicjillccllcllcllllllllljlljllljlanmnnnbabnnnbclknnnnnnnkkknnkkkknknknnnnkknkkknnknnknnnknknnnnnknnnnnnnnnnnnnmmnnmnnnnnnkbkknnknnkkknnnnnnnkkkkkkbkkkbnknnkbbkmmnkjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`iakkkmnkknkkbbibkkkkkkbbbbbbbbbbbbkbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbkbbbbbkbbbbbkbkbbbbbaababbbbbaabbbbbbabaaaababaaaikbababbbkkkkbjjjjjjjjji`lj", "iiiiiciii`iiiiiiiii`iii``i`ii`i`iiicciiciiicicccccccccicc`ciiilallccllcllllllllllllllllllannmnkbbmkkfkljknnmfnnknkkkkkknkkknnnnnknkkkkkknnkknkknkkkknnnnkknnnmmmnnknkknmmmmmmnnnbknnkkmnnnkknnnnnnkkkkkkkknnkkbnknnbbakmnmbjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjl`iiaknnnnknnmnkcakknkbkbkbbbbbbbbbbbbkbbbbbbbabbbbbbbbbbababbbkbabbbbkkkbbbbbabkkbkbkbbaabaaabbbbbbaabbbbbbbaabaaabbabikbbbbaabbknbkjjjjjjjjjjjjj", "iiiiiiiiiiiiiiiii`i````ii```ii`iiicicici`iicccccccccccclcclclcclclclllllcllllbllljcbcljllannnnbaknnmnncjnmnnnkkkkkknnkkknnnnnkkkkkkkknnnnknnknkknknnnkkkknmnnnnnmmnnnnnnnnnkkkkkkkkkkkkknnnkknnnnknnnkkknkknnb`knkkbdbnmnmbjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`abbkkknnkkmk`kknkkbbbbbbkbbbbbbbkkbbbbbabbbbbbbbbabbbbbbbbbbbbakkbbbbkkbbbkbkbkbbabaababbaaababbabakbbabbbaabbbababcanbaabbabkknkjjjjjjjjjjjjj", "ciciiiiiiiiiii`i`i```i`i`icc``i`iiiiiiiiicciciccccclccccccclcccllllllclllllllijllllijllllaknkkabkkknmnclmnknknkbnknnnnkkkkkknnknkkkknknknnkknkkkkknnkkkkkknnkknfnmnnknnnnnkkkkknkkkkkkkbkknmnnnkkkknkkkkknkkkbabnkkkbknnfnmjijjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjlii`akdbbbbkmmk`cabbbbbbbbbkkkbbbbbbbbbbbabbbbbbbbbbbbbabbbbbbbaabbbbabbbkbbbbbbbbbbaaabbbaaaabaaabbbkbbaaaaabbbaadababiabbbabaaabbkbljjjjjjjjjjjj", "iiiiiiiiiiiii`i````iiiiiiii`baiiiiiiiicccccccccccccccccclclclcclclllcccllllllllllllljlljlbknkbankabknncckknknnnmnnnnmnkkknknkkkkkkknnnkknkknkkknknnnnnnnkkkkkknmknnnkkknknnnnnnknkkkkkkknkknnnnnnnnnnnknkkkkkkbknkkkknnnmnajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjiciakbkbkkkbbbaiakbkkkkbkkbkkkbbbbbbbbbbbbbbbbbbbbbbbbbababkbbbbbabbaabkbbbbaaabababbbbababbbabababbbkbbbbbbbbabbabaabc`aaaaaaaabkknijjjjjjjjjjjj", "iiiiiiii``i`ii`i``i`i`iii`cciiia`i`i`iiiiiccccccccclccccccclccccclcllilllllllllllllllllllkmkkkknbdabkklcknmmnnnnnkknnnkkkkkknknkkkknknnkkkkkkkkkkknnkknknkkkkkkmkkkkkkknnnnnnkkkknnkknnnnkkkknmnnnkkkbkkknkkbkbnmnnnkknmnnajjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjjliiibbbbbbkka`caabkkbkkkkbkbbbkbbbbbbbbbbbbbbbbbbbabababbabbbbbbbbbababbbbaabbabbbbbbkbbaabbabbbbbbbbaabbbbaaaabaababaacc`iaaaa`aabkkijjjjjjjjjjjj", "lllllllllllllllllllljlllllllllllllllllljlljlljljlljljljljjljjljljjljjljjljjjljjjljjjljjjjknknmnnbbbbkklcnnnnnnkknkknnnkbkkknkkkknknknkknkkkkkkknnnmnnnmnnnnnknnnkkkkkknnmnnkkkkkkknknkmmnknkknnkkbkkkkkkkkbkkbbnnmmkkkkmmnkjljjjjjjljljjjjjjljljjjjjjjjjjjjjjjli``bbbbbbbaiiiaaakbkbbkbkbbbkbbabbbbbbbbbbbbkbbbbbbbbbbbbbbbbbbkbkbbbbbkbbababbbkbbbaaabbbbabbbbbbbabbbbaaaaaaababaaaaiccii`ii``aaab`jjjjjjjjjjjj", "ljljljljljljjljlljljlljljjljjjljjjjjjjljljlljljljjjjljljlljljljjljlllllljllljllljlljljjljbbknmmnkbbbbblinnnnnnnnknkknnnnkkkkknknknkkknkkkkkkknkknknnkknknnmnnnmnkkkkkknnnnkkkkknkkkknnnnknnknnnkkkknnnkkkbkkbbakmmkbbbbknnkjjjlljlljljllljljjljlllllllljlljljll`cibabaaa`cliaba`kkkkkbbkbbbbbkbbbbbbbbbbbbbbbbbbbababbbbbkkbbbbbkkbbbkbbbaababbbkbaabaabaabbbbbbababbkababbbbbbaaaaaaiciiicci```aad`ljllllllljlj", "ljlljlljljljljljlllljljljljllljllllhllllljljljjjlllljllllllljljljjljjljljlljjjljllllllljlddknmmnkbkbbbj`mmmnkknnnknkknnnkkkkkkkknkkkkkkkkkknkknknknnnnnnnnnnnnnnknkkbkknnkkknkkkkkbkknnknnkkkknkkknnkkbkkkbkkkaknnbbbbbbknnjljljljllllljllllljlljljljljlllllljl```bbaa`cjlcabbakknkkbkkkbbkbbkkbbbbbbbbbbbbbbbababbbbbbbbbbbbbbbbbkbkbbbbbaaabbabbbbbbaaaaabbbbbbbbaabaababbaaaaaaaab`c``icci`aaaa`iljjjljjljljl", "jlljlljlllhllhlhlljhlllljlljlljllhjljhjllhlllllhljljllhjllllhllhlhllhjllljhjlhjlhjjljlljlbkmmmmnmbkbkbj`knknnnnnnnknkknnkkkkkknkkkkkkkkkkkkknnknkkbnnnmnnnknkkkkknnnkknmmkkbkkkbkkkbknnnkkknkbkkkkkkkbkkknkknnbkmnkbbbabbadllllllhlllljhjhjljlljlllllllhjlllllc```bba`clliakkbabbbkbbbkkbkkbbbkbbbbbbbbbbbbbbbbbbbbbbbbbbabbbkkbbbbbbbabbbbbabbbbaaaabababaaabbababaaabaaaaaaaaababbaaiaa``i`a`add`cljhljlljljll", "lljhjhlhjllllllllhlljlljhjlljllllllhlllhjllhllljlllljljlljljlllllllllhlllhllljljlllllljljnknmnmmmnkkbal`kkknnnkkkkknkknmkkkkkkkkmnkkkkkkkknmnkknnkkbkkkkkkknknknknnnknnnnkkkkbkkkkkkkbkkkkkkknkbkkkkkknnnmnkknnknmnbbbkbbbbljljljjljljhjljlhlhllhjhlllllljljllli``kkaiclc`bbkkkbbbbkkkkbbbbkbbkkbbbbabbbkbbababbabbkkbabbbaabbabbabbbbbbbbkbabbbbbbaaabaabaaabbbaababaaababaabbbbbbabacbbaaa`i`abb`iljlllljhjljj", "llllljljlhllhlllhjllhjhllhlllllljhjljhjlllhjllhlhjhlhlhlhlhlhjhjlljhjljlljlllhlhllhllhllhkknmknmmnkkbbj`nnnnnnnnkkkknnkmnnmnkkkkkkkkkkkkkknnkkkkkkkkkkknkkkkkkkkknmnnnnnkkkkkkkkkkkkbkknkknnnkkknknknnnnknkknmnnnnnbbbbbdbdjlljhlhlhlhlllhlllllljljjhjllllllljhiiiba``ic`bnkbbkbbbkbkkbkbbbkbbbkkkkbbbbbababbbbabbbbbabbbbabbbbbbbbabaabbbkbbbkbbbaabaabaaabaaababbbbbbbabbbbbbbbbababiababba``add`iljhjllljhjhl", "llhllhjhjllljhjhjlhjllllllllhjhlhllhlllhjljhljljllljlljljljhlllhlhllhlhlhlhlljllljljlllllkbnmkknmmnkkalakknnkkkknknnkkkkmnnnnnnkkkbkkkknkknnkkkkkkkkkknkkkkkkkkknnmnnnnnkkbkbkbkbkbkkbkkkknnkkkkbkknnkkkknknknbkbkbbbabbbkbhllhllljljljhjjljlljhllhlllhlllhjhlli`i````a`abnnkbb`bkkkbbbbbkbbbbbbkkbbkbbbbabababbbbbkbbbaaabaaaabbaababbbbbkbbkbbaaaaaabaabaaabababbabaaaaabbbbaabaabbbibabnnk`iaaa``llljhjhllllj", "lllllhlllhllhlllhlllhlhlhjhjlllljlljlhjlllllllhlhlhlhlhlhlhlllllljlljljljlljlhjhjhjhllllckbbkkbknfmkbalannnnkkbknkkknkkknkbknnnkkkkkkknnnnnnnnkkkknnkkkkkkkkkkkkkknnnnnkbkkkkkkkkkkkkkknkkkkkbbkkkkkbkkbkkknnnbbbbbbabbbbbbllllllhlhlhljhlllllhjljljhjljhlllllhiiciiiaaabbnnmnk`kkkkbbbakbbbkbbbbbbbbkbbbbababbkbbkbbbbbbbbbbbabababbabaabbbbbbbaababaaaaabbababbabaaaaaaaaaaaaaabbbbbiabannnb``addahlllllljljll", "jhjhjllhlllhllhlllhllllllllhjhjlllllljhjhjhjhljlllllllhlllllhlhllhlhlhlhlllhljhlllllllllhbbbbbkbknkkb`jamnnnnkkkkkkknnnnnkkkkknkkkkkkkknnnnnnkkkknnnnkkkkkkkkkkkkkkkkkkkkkkkkkkkbkkkknnknnkbkkkkkbkbkkbkbkbnnnkkkkkbbbbkbbdljhjhjljljlllllhlllllhlhllhlhljhlllli`lli`aabbkmmnnmakkkkbbbbbbbbkkkkbbbbbkbbbbbbbbbbbbkbbbkabbkbbbbbababbbaabababaaaababaabaabaabbbbbbaabababaaaababaaabbaibbaknmka`abbbillllllllllj", "llljhjhjlllllllllhlllhlhlhllllhlhlhlhllhjllljlllljhjhljljllllllhllllhllllhlllhljlhllllllibdbbbbknkabkajbnnnnnnnkkbkknnnmkkkkkkknkkbkbkknnknmnnnnknnnnkkkkkkkkkkkkkkkkkkbkbkkbkbkbbkkkkknnkbkkkkbkkkkkkkkkkknnkbknkkkkbbbbkdlllllllhlhlhlhlljllllllllljljllllllliilc`abaabbknnnn`kkkkkkkkbabbbkkkbbbbbbbbbbababbbkbbkbkkbbbbbbbabababaabbabaaababaababaaaaaabababbbaaababaabbabaaaaaabb`abknkkka`abbbcljlljljllll", "lllhjllllljhjhllljhllllllllhllllllllllllhlhlhlhlhlllljhlhllllljllllljlhjhjllllhlhllhllllibdkbabknnbbkalknnnnmmnnnkkkkknnkbbkknnknkkkkkkkkknnnnnnknnnkkkkkkkkkkkkkkbkkkkkkkkkkkkkbkkbknnknkkkkkkbkkkkkkkbbkbbkkbkkkkkbkbbkkkllhjhllljljljlllhlllhllhlhlhlhlllllhiic`aabbbbbbnmmn`kkbkkkkbbbbbbbbbbbbbbbbbkbbabbbbbbkbbkbbbbkbkbbbbbbaabbabababababaaabababaaabbbbbabaaaaaaaaabaaabaaaab`annnkbka`abbdilllllhllllh", "lhlllhlhlhllllhjhlljljllllllllllhjhjhjhllllllllllllhlhllllhllhlhlhlhlhjllhjhlhllllllllll`ddbddaknmkkb`jnmnnknnkkkkkbkknnkknnkknnnkkkkkkknkknkbkknnnnnnnknnnkbkkkkkkkkkkkkkbkbkbkkkkknnnnnnkkbbbkkkkkkkkkkkbkbkbbkkbbbkkbkkbhllllhlllhlhlhllllllljljljlllljhjlll`ciakakbbkbbbknnakkkbkkkbbbkabbbkaabbbbkkbbbbbbbbbbbbbabbbkbbbkbabbbbababbabababbbbababaababbbbbbbbbbaaaababaaaabaaab`aibnmnkbnb`abbb`ljhlllllhll", "lllhllllhllhlhlllllhlhlhlhllllllllllllllllhlhllhjlljllllllllhllhlhlhlhhhlhhlhlhhhhhhhhhlodddddddknmkdglknknnnnkkkkkkkkkkkkkkknnmkkkknkkbnkkknkknmnnnnnnknkkkkknbkkkkkknnknkkkkkkkkbnnknnnknnnnkbkbkbbbkbkkkbbbbbbkkbbkkkbkkljhlljlhlllllljhjhlllhlhlhlhllhllhlh`i`ababkbbkmbknmakkkbbkbbbbbbbbbabbbbabbbkbbbbbbabbbbbbbbbbbkbbbbbbbbbaabbababbbbbbbabaabbaabbbabbbabbbbaaaaaaaaabaaaa``annnnkbb`bbad`llllhlljlll", "hlhllhlhllhlllhlhllllllllllllllhjhlllhjhlljhjhjhlhlhlhlhlhhhlhhhhhhhhhlhhllhhhhhhhhhhhhhhhhhhhhhghghhhhggghhghhhhhhgg`g`g`o`dddbddbbkkkkkkknnnkmnnmnnnkbnnnkbbbkbkbknkkbnknkkkknnkkkkkknnnnnmnkkkbkbkkkkbkkbkkbbbbkkkknnknklljhjhlljljhjllllljllljlllllhllhllllii`dbbbbbkbnnbkncbbbknkbabbkbbabbbbbbbbbbkbbbbabbbababbbbbbkkbkbbbbbbbabaababbbabababababbababbbbkbbbbbbaaaaaaabaaaabaa``mnmkkbb`bbdddllhllhlhlhl", "ljllllllhllhlhllhlhhlhhlhhhhhhhlhlhhhlhhlhhlhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghghhghghhhhhhhhhhhhhhhhhhhhhhhchhhco`oddkknnmnnkknnnkknkkbbkkkkkkbkkkkkkkknmnnnnnnnnnkkbkbkbkbbkkbkkkkbbbkknkbknkkhlllhllhlhllhlhlhlhllhlhlllllllljhjlii`abbbbakbmnkkkibbbbkbbbbbkbbbabbbbbbakbkbbbkbabaabbabbkbbkbbkbbbbbbbbbbbaaaaabaaababaabbaabbbbbbbbbbbbabaaadaaaaaaabaa`knnkbdaadd`ddhlhlhlhlllh", "lhlhlhlhlhllhlhlhhlhhlhhhlhhlhhhhhhhhhhhhhhhhhhhhhhhgghhggggogoogggghhhhhhhhggggggghhhhhhhhhhhhhhhhhhlghhhhhhhhhgghghhhhlhhhhhghghhhhhhhhhhhhhhhhhhgho`oknknmnnmnkkkbkkkkkkkkkkkkknnnkknnnnnnnkbkbbbkbkbkkkbkkbbkkknnkkkkkblllhllllhlllhlllllllhllllhlhlhjhlllh`i`abbabbbknnnkn`bbbabbbbknkkkbkkbbbbbbbkbbbkkbdbbbbbbbbbbbbkbbkbbabbbbbbbbbaabaabbaabababbbbbbdabbbbbbddadddddddddddddd`kmkdd`higio`ghhhhhhhhhhh", "lhlllhllhlhlhlhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhgggghgggggggggggggghghhhhhhhhhhhhhhhhlljhlhhhhhhhhhhhhhhhhhhgggghhhhghggghghhhhhgghhhhhhhgghhhhghhhlhlhhhhhh`oddnnnnkkkkbkkkkkkkkkbkkknnnnnnnnkbkkkbbkkkbkbkbkbbbbbkkkkbkdblhlllllljhlljhlllllllllllljllllljhlli``aaabbanbnnknncaabbbbbbbbbbabbbbbkkbkbbbbbkkdbbdabbbbabbbbbbbkbabbbbbbbkkbbbbbababbbababaaabdbbkbkkbkdddd`oig`og`ghhhhhhhghhhhghhhhhhhhghhhgghh", "hhhhhhhhhhhhhhhhghgggggggggggggggggggghghghggggghghghggggogggggogggggghhhhhhggoggggghhghhghggggghhhhhhhhhghghhhhgggggghghhhhgggggggggggghhhhhgghhhhghhhhllhhhhhglhgiodddnknnnnnkkkkkknnnkknnkkbbbbbkkbbkbkkkkkkbbbbbbbbdbbdlljhjhjhlljhllllllllllllllhlhjlllljli`i`baabbbbnnkkblbkkkbbbbkbbbbbbbbbbkbbbbbbbkbdabbdddabbbbbbbabbbbbbbabbabbbkbabbbbabbbbbbbdddddkddd`oihhlhhhhghgggghhhhhhhhhghhhhhhhghghghghgggg", "hhhhhhhhhhhhhhghggggghghgghghghgggggggghgggggggggghhhhhhggggggggggggggggggggghhhghghhhhhhhhhhhhhgggghhhhghgggghghggggggggggggggggggghhhhhhghghhhhhhhgghhhhhhhhhhhhlhlhhhhhh`ddkkddbbkkkkkknkkkbkkkkbkkkbbbkbbkknnnnnkbbbkkkllhlllhllhlllhlhlhlhllhllhlllhlhlhlhiii`abbbbakkbba`ibbbbkbbkbbbababbkbbabbkkbbkbdbdbbabbbbbkkbkbbbkbbbbbbbbbabbkkbbbkbkbbdbbddd``o`ohhhhhhhhhhhhhhhlhhhhghggghhhhgghhhggggggggghgggg", "gggggggogggggggggggggggggggggggggggghgggggggggggghghgghhhggggghgggggghhhhhggghhghhhhhhhhhhhhhgggghgggggghhhhhghghhhhghhhghghhhhhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhlhhghhhhhhhhhhhhhhhcg`bknnnnnnnnnnnknnnbbbbbbabkknnnnbbbkmnklllllllllllhllljllljlllllljhjllljlll`i`abababkaa`ii````aababbkkkkkkknnkbbbbbbbkbbabbnbkmnnmknknkkbkkkbbbbbkkkkbbkkddkkddd`gcglhhhhhhhhhhhhhhhhghghhhghhhgggggghghhhhhghhhgggghhhhhhhh", "ggoggogogogoggggoggogoggggggghggggggghhgggggggggggggghghgggggggggggghghhhhhhhghhgghghhhhghgggggggggggghghgggghghhhhhhhhhhhhhhhghghhhhhghhhhhhhhlhhhhhhhhhhhhhhhhlhhhhhhlhhhhhhhlhlhhh`ddknnnknnnkknbnnnkabbbbbknnmnnnnnknnnhlllhjhjhjljlllhlllhllllllllllllhljhi`idkkbbabaiciiiccciabbabbknbbkkkkkbabbbbbbbbaabnnkkkmkknnnnkbbknkbdkkkknkkddo`ooggghhhghhhhhggggghghgghhhhhhhgghgggggggggghgggghggogghggghhhhggg", "ggogoggoggggggoggggggggggggghggghgggggggggggggggghhgghgggggggggghhhhhhhhhhhhhhhhhhhlhhhhhhhhhhhhhhhhhhhhhghhghghhhhhhhhghghhhghgggghhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhhhhlhhhhhgddknnkkknknnkbbkkbbbkmnnnnnnnnnnncjhjlllllhlhlllljllljhjllllllllljllli`ibkkbbba`i`aaiccc`aka``abbkbkkkknnbkbaaabkbabbnnkbkknnnknnnkdddmkddo`gghhhhhhhchghhghhhghggggghgghhhhggghhhhhhhhhhggggghgggogogggghhhhhhhghgggg", "hghghghghghhhhhhhghhhggghhghgggggogggggggggogggghghhgghgggggggggggghhhhhhhhhhghhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhghhhhhhhhggghhhhhhhhhhhhhhhhghghhhhhghhhhhhhhhhghghghhhhhhhhhhhhhhlhhhhhgddbkmmmnkakkkbbbkbbbbbbnnmmnnhlllhjhljlljhjhlhlllhllhjhlllllhlhjhi`idbnkkkb```aa`ii``i```i`abbbbknbnkkbaaabbbbbabkmnkbbnnnmnkddo`oghhhhhgghhghhhhgghggghghgggggggggggghghgggghhhhhgogogggggghggggggghgghhghhhhhhhg", "hhhghhhhhhhhhhhhhhhhghhghgggggggggggoggogoggggggghgghhgghggggggggghhhhhhhhhhghhghhhhhhhhhhhhhhghhhhghggghhhhhhhhhhgggggghhhhhgghghghhghhhhhhhhhhgghhhghhhhhhhhhhggggggggggghhhhhhhhhlhhhhlhhhhhhhhgdddbbbbbabkkkkbbaabkknmnllhllhllhlhllhllllhllllllllhlhllllhli`iabkknkbaaaa`aa```aa`icl`akkkkkkkkka`abaabbbbbbkndddndkd`oghhhhhhhhhhhhhghghhhghggggggghgggggoggggooggghhgogggghghhhgggggggggghhghghgghgghghggh", "ggghghhhhhhhlhhhhgggggghgggghghghggggggoggggggggggghhghhhgggggghhhhhhhhhhghhhhghghhhhhhlllhhhhhhhhhhhhhhhhhhhhhhgghggggggghgggggggggggggggghgggghhhhggghghghhhhhgghghhhhhgghghhhhlhhhhhlhhhhlhhhlhlhhhhi`dkdddbbknkkkkkknnmlllhlllhlllhllhlhllhlhlhlhllllhlhlll````bbbbbabbaaabka`akkbicliannkkkbkkba`abbbdkkkbdkkdo`ghhhhhhhhhggghghhggggghggggghhgghghhggggoggghhhhghhhhhhhghgghhhhggohghhhhhgggogogggggggghgh", "hghghghhhhhhhhhhhhgggggggghghghggggghggggggggggggggggggghhhhghghhhhhhhhgghggggggggghhhhhhhhhhhhhhhhhhhhhhhhhhhhhghggggggghghhhghggghghghhhhhhhhhhhhhhhhhhghhhhhhlhhhgggghhhhhhhhhhhhhhhhhhhhhhhlhhlhllhhhhh`dkkdkbbbbbbbkknlhlchlhllhllhlllllhlllllhllhlhlllhlhi`i`bbbbbbbbbabbbbaakkaiiliaknkkbkbbaddbddddddddohhhhhhhhhhhhhhhhggggggggggghhhhhggghghhhhgggoggggggggggghgggggggghghhhhhhhhhghggggggggggggghhhhh", "gggggghghhhhhhhhggggggghhhghhhghhhgggggggggggggggogggggghgghgggggggggghhhhhhggggggggghhhhhhhhhhhgggghggghhhhhhhghgggggghhhhhhghghhhhhhhhhhhhhhhghhhghhhhhhhhhhhhhhhlhhhhgghgghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhgdnmnnnkbbbkblllllhlchlchlchlhllhlhchlchllchcllcliiiabakbbkbaaaaabaaakaaicciabknbbkbaddbddo`gggghhhhhhhhggggggghhgggggoggggggggogggggghghhhhghgggghhhhghhhhhggggggggggggggggggggggogoogggggggggggg", "ghhhhhhhhhhhhghggggggghhhhhhhhhhgggggggggggggoggggggggghggggghghhhhhhhhhhhggghggghgghghghhhhhhhhhhhhhhhhhhhhhghggggggggghghghhghggghhhhllllhhhhgghgggghgghghhhhhhlhhhhhhhgghhhhhhhhhhhhhhhhhhhhhhhhhlhhhhlhlhhlhh`dknmkkbbdlllhlchllhllchllchlchllclllchlllhchlgciabbkbbbbabbbabbabbaailcc`abkkbd`iiihhhhhhhhgghghghgggggggggghhghggggoggogggggggghhhhghgggggggggggghggggghhgggggghggggghggggogogogggggggggghhhh", "hhhhhhggggggghghhhhhhhhhhhhhhhhhhhhhhhhhhggggggohggggggggghhhhhhhhhhhhggggggggghghghghhhhhhhhhhhlhlhlhhhhhhgggggggggghghghhghhhhhhhhhhhlhhhhhhhggghhhhhhhhhhghghhhhhhhgggghhhhhhhhhhhhhhhhhhhhlllhhhhhhhhhhhlhhhllhlgakmkdglhlllllclcclllchllchlchlhchllhcllllccciabbabbbbbbababbaaaiiiiii`ddd`dgghhghhggghhhghhgggggggggggggggggggggogggggghhhhhhgggggggghhhhhhgghgggggggggggoggggghghggggggggggggggggghhghgggg", "hhgggggggggghhhhhhhhhhlhhhhhhhhhhlhhhhhhgghghhhhhhhhhgggghghhhhhhhhhhhgggggggghgggggggggggggghhhhhhhhhhhhgggggggggggggggghhhhhhhhhghhhhhhlhhhhhhgghhhhjljllhhgggghghhhhghghgghhhhhhlhhhhhhhhhhhhlhlhhhhhhhhhhhhhhhhhhhhg`gchllhlhlljjjjljjljljllllllllllllhllhllhidbbaabaabbkkbbbbaa````igioihhhhghghhhghhgggggggggghhhhgggggggghhhgghgggggghghhgghhhhggggggogggggggggggghggggggoggggggoggghhhhhhhhhhhhhgggggggg", "ggggggogggghghhhhhhhhhhhhhhhhhhhhhhhhggghghhhghhhhhhghghgghghhhhhhhhhgggggggggghgggggggggggghghhhhhhhhhgggggggggggghgggghhhghhhhhghghhhhhhhhhhhhhgghhlhjhjhhhhgghhhhhhhhhhghghghhhhhhhhhhhhhlllhhhhhhhhhhhhhhhhhhhhhhjhlhlhlhlhjjjjjjjjjjjjjjjjjjjjjjjjjjljllllhiiidbababbabbbknnkkdido`hhhhhhhhhhghgghghggghhgghgggggggggoggggoggggogggggoggggghgggggghggggggghgggggghhghggggogogghhggggggggggghhhggggggghggggg", "ogogoggggggggggghghggggghhhghggghghghggggghghhhghghghhgggggggggghhhhghgggggggggggggggggggghgggggggghggggggggggggggghghhhhghhhhhhggghhhhhhhhhhhhhhgghhhhhhlhjhhhhhhhhghhhhhhhhghhhhhhhhhhhhhhhhhlhhhhhhhhhhhhlhhhhhhhjhhhlhlhlhllljjjjjjjjjjjjjjjjjjjjjjjjjjjjjjc`iibbbbbaaakbdkkkddighhhhhhhhhghgggggggghgghhhhghgggggggggggggggggogggggoggggggggghggggggggggggggogogghghhgggggggghhhhhhhhgghghhghghghhhgggggogo", "ggogogogggggghhhhhhhhhhhhhghgghhghhhghhhgggggghhghgggghggggghhhhhhhghhhhgggggggggggggggghhghgggggghghghhghhhhgggggghghhghhhhhhggghghhhhhhhhhhhhhgghghhljhjhhhhhhhhghghgghhhhhhhghhhhhhhhlhhhhhhhhhhhhhghhhhhhhhhhhhhhhllhhhhlhlllljjjjjjjjjjjjjjjjjjjjjjjjjjjjlli``bababbddddddogggghhhhhghghgghgggggggghggghggggggggggoggoggggggggggggggggghgggggggggggggggggogggggghghghgggggogghhhhhhggggggggggggogogggoggogo", "oogogogogogghgghhhhhhhhhhhhhhhhhhhhhhhgggggggggghghhhghghghhhhhhhhghgghghhhghhhhhhhhhhhhhghggggghgghghgghgghghhhgghghhghghhhhhhghhhhhhhhhhhhhhhhghghhhhhlhhhhhhhghhhhghhhhhhhhhhhhhhhhhhlhhlhhhhhhhhgghhhghhhhhhhhhhhhhhlhhhhhhhhlhlljjjjjjjjjjjjjjjjjjjjjjjjjjjiiibabbdbd`oghhhhghhghhohhhgggggghghgggghgggggggggggggogggggggogoggggggggogghhggggogoogggggogggggogggggggggggggggggghhgggggggggggggggggggogoogoo", "ggogoggggggggghhhhhhhhhhhhhhhhhhhhgggggghhghhhhhhhhhhhhhhhhhhhhhgghggggggghhghhhhhhghggggggghggghghghghgghhhhhghhhghhghghggggggghhhhhhhhhghgggggghhhhhhhhhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhghhhlhhhhhlhhhhhlhlhlhhhlhjljjjjjjjjjjjjjjjjjjjjjjjjl```kbbd`ggihhhhgggghhghhghhghhhhggggggghgggggghhghggggggoogggggggggggggggoggggggggghhggogggggoggghhhhhhhgggggghgghghgggggggogogggggggggggggggogg", "ggggggogggggghhhhhhhhlllhlhhhhhhgghhhhhhghhhhhhhhhhhhhhhhhhhhhhhhghghghghhhhhhhhhhhhhghggghghghghhhhhhghhhhhhhhhhhhhhhhgghhggghhghghhhhgghgggggggghhhhhhhhhhhghghhhhhhhhhhhhhhhhllhhhhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhhhhlhhhhlhhhhhhhlhlhjjjjjjjjjjjjjjjjjjjjjjlhi``ddihhhhhhhghhhghhhghhghhhhhhggggggggggggghhghgghgggggggogghhhghhgooogggogggggggggggggogoggggggogggggoggghghhhghhggogggghhhhghgggggggggggogggg", "gggggggghhhhhhhhhlhhhhhhhhhhhhghghhghghhhghghhhhhhhhhhhhhhhhhhgghgggghghhghhhhhghgggggggghgggggggggggghhhhhhhhhhhhhhhghhhggggggggggghghghghggggghhhhhhlhhhhhhhghhhhhhhhhhhhghghhhhhhhhhhhhghhhhghhhhhhhhhhhhhhhhllhhhhhhhhhhlhhhhhhhlhlhlhjjjjjjjjjjjjjjjjjjhlhcgggghghhhhhgghghgghgghgggggghhhhgggggghggggghhhgghhgggggogoggggghggghhgoogogoogggooogogogoggogogogogoggghhgggghhhhhghhgoghghhghhhhhhhgggoogggggh", "ghghhhhhhhhhlhhhhhhhhhhhghhhhghhghghhghghhghggghhhhhhhhhhhhhghhhgghghghggghghghghghhghhghggghghgggggggghhhhhlhlhhhhhhhghhhhghggggggghghghgghgggggghhhhhhhhhghhhhhhhhhghhgghgggghhhhhhhhhghhhhhghhhhhhhhhhhhhhhhhhhllhhhhhhhhhhhhhhhhhhhlhlllljjjjjjjjjjjjljlhllhhghhghghhghgggghgghggggghhhhhhhhhghggggghgggggggghhggggogggogogggggggggggggggoggogggggggggggogoggghggggggghggggogggggggggoggggggoggggggggggggggg", "hhhhhhhlhhhhhhhhhhhhhhhhhhghghghghghggggggggggggghhhhhhhhghghggggghghhghhhhhhhhghggghgghghhggggggggggggghhhhhhhhhhhhhhhhghgggghghgghghhghghgghggghhhhhhhhgggghghghghgghghghghhhhhhhhhlhhhhhghhghhhhhhhhhhhhhhlhhhhhhhhhhhhhhhhhlhhhhhlhhhlhhhhjljjjjjjllhhhhhhhhhhhggggogghhghhhggggggggggggghhhhhgghggghgggggggghhhhgggggggogoggggggggggggogogoggggggggggggggggggggggogggggggggogggggggoggggggghggghggggggggggg", "hhhhhhhhhhhhhhhhhhhhhhhhhghhggggggggggggggggoggggggghghhghghghgghgghghhhhhhhhhhhghghgggggghghhhghggggghghhhhhhhhhhhhhhghhghhhghghgggghhghghghhhhhhghhhhghghgggggghggghghhhhhhhhhhhhhhhhhhhgggghhhhhhhhllhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhlhhlhlhhhlljjhjhlhlhhhhhhggggggggggggggggggggooggggggggggggggghghggggoggghgghhggggggggogogggooogggggoggogogogoggghghghhggggggggggooghhhhhgogggooggggogggghhhggggggghghghg", "hhhhhhhghhhhhhhhhhhhhhhhghggggggggghhhghgggggggggghhghhhgghghghghghghhhhhhhhhgggggggghhghghghgghgggggggggggghhhhhhhhhhhhhhhhhhhggggghhhhhhhhghhhhhhhhhhgghghhhhghgghgghghghghhhhhhlhlhlhhhhhhhghhhhhhhhhhhhhhhhlhhhhhhghghhhhhhhhhhhhhlhhlhlhhlhhlhlhlhhhhhghhggggogggogggggghggggggghhggggggghgggggggggghggogggghghhggogggoggggoogggggggoggggggoggggggggggggggggggggggogggghhhghgggggggogoggggggggggggoggghhhhh", "hhhhhhhhhhhhhhhhhhhhhhhggggggggggghghhhghhgggggggggghhghhhhghghggghhhhhhhhhhhghgggggggggghghghgggggogggggghhhghggghgghghhhhhhhhghgghghhhhhhhghghhhhhhghggghghhhhhhghghhghhghhhhhhhhlhjhlhhhhhhghhhhhhhhhhhhhhhhhhhhhhghhghghhhhhhhhhhhhlhlhhhhhhhhhlhhhgghggggggggghggghggghghhggoggghhhggggggggggghhgggghggggggghhhhgggogoggogoggggggggggghghgggggoggggogoogggggogggoggggghggggggoogogggggggghghghggogogogoggog", "hhhhhhhhhhhhhggggggggggggggggghghghhhhhhgggggogggghgghhhhhhggggghghhhhhhhhhhghgggggggggghghhghgggogogggghhhhhggghggghghghhhhgggggghhhhhhhhhghggghhhhhhhghgghhhhhhhhhhhhhhhhhghhhhhhhhhhhhhhhhgghhghhhhhhghhhhhhhhhhhhgghhhhghhhlhhhhhhhhhhhhhhhhllhhlhhhhggggggoghghggoggoggggggggggghhgggggghggghghgggggggggggghhhhhgoogoggoggggooggghggggggggghggogoggggggggggggoggggggghghhhhggggggoggghgggggggggooooogogoggg", "hghhhhhhhhhhggggggggggghhhhhhhhhhhhhhhhgghgggggggghghhhhhghghghhhhhhhhhhhhhggggggggggghhhhghhggggggggghghghgghhghghgggggghggghghgghhhhhhhhhhgggggghhhhhhhhhhgghghhhhhhhhhhhhhhhhlhhhhhhhhhhhhggghhhhhhhgghghhhhhhghghhhghghhhhhhhhhhhhhhhlhlhlhhhhlhhhhhgggggggggghgggggoggggggggggghhhggghggggggggggggggoogggghhhhgoggggggggggggogghhhggggogghhghggghggghgggggggggogooogghhhghhhhhggggghhgggogogogoogogoogogogg", "ghghhhhhgggggggghhhhhhhhhhhhhhhhhhhhhhgghgggghghghghghgggggghhhhhhhhhhhhhhggggggggghghghggggghghgghhhhhhhhhhggggggggggggggghgghggghghhhhhhhgghghhhhghhhhhhhhhhhhhhhghhhhhhhhhhllhlhhhhhhhhhhhhghghhgggghhhhhhhhhhhhghghhghhhghhhhhhhhhhlhhhlhlhhlhhhhhhlghhggoggggggogghggogggggggghhghghggghgghggoggogggggggoogggggggggogoggogogggogghhggogghhhhhggggghhggggoooooooogggoggggghhghhhgghggggggogoghgghgggggoggggg", "ghghggggggggggggghghhhhhhhhhlhhhhhhhhhhhgghggghggggggggghghhghghhhhhhhghhggggggggggggggggggggggghhghghhhhhhghgghghggggogggggggggggghhhhhhggggghghhhhghhhhhhhhhhhggghhhhhlhlhlhhlhhhhhhhhhhhhhghghghhhghhgghhhhlhlhhhghghhhghhhhhhhhhhhhhhhhlhhhhhhhlhhhhhlhhhggoggggggooggggoggggggghhhhggggghgggggggggggggogogghgggggghhggggggghhgggggogoggggggggggggggggggggogogoggooggggggggggggggogoggggoggggggggghggggogggg", "hgggggghghggghghgghghhhhhhhhhhlhhhhhhhhghghhhghgggggghhhghghghhhhhhghghgghghhgggoogogogggghghhgghgghghghghghgghgggggggggggghggggggggghhggggghghhhhghghggghghhhhhhhghhhhhhlhlhlhhhhhhghhhlhhhhhgghhhhhhgghhhhhhhhhhhhhhhghghhhhhhhhhhhghhhhhhhhhhlhhhhhhhlhhhhhhhgggggghhggooggggggoggggggggghghhgooggggogogggggggggghhhhhhgggoghhhggogooggggggggggggogghhggogogoggoggggogggggggggggogogggooogoggoggggggggoggoggg", "ghghghhghhhhhghgggggghhhhhhhlhhhlhhhhhghghghhghggggggghhgggghgggggghhhhhhhhggggggggoggggghghhhhghgggggggggggggggggggggoggghghghgggggggghggggggggghhhhghghgghhhhhhhghhlhhlhhlhlhhhhhghhhlhllhhhhhhhhhhhhhhhhhhhhhhhhhhhgggghhhhhhhhlhhhhhhhlhlhhhlhhhhhhhhlhhhhhhhhggggggogoggggggggggggggghggghgggoogogoggoogogggggghhhhhhgggggggggggogggggggooggogoggghgggoogoogoggogogoggghgggggggggggghggggggggggggggoggogogg", "hhhhhhhhhghghggggggghhhhhhhhhhhhhhhhhhgggggggggggggghgggghgggghghghhhhhhhhgggggggoggggghhhhhhhhhghgghghhggggggggggggggggggggggggggghghghgghghgghhhhghghgghhhhhhhhggghhlhlhlhlhlhhhghhhhhlhlhhhhhhhhhhhhhhhhhhhhhhhhhhgggghhhhhhhlhhlhlhhlhhlhhhhhhhllhhhhlhhhhhhhhggggghggghggghgghhgggghhggggghggggoggggoggggggggogggghhhgghggggghgggggghgggggggggggggggooggogggggogogoggggghggggoooogoggggggggggggggggggoggggg", "hhhhhhhhghggggggggghghhhhhhhhhhhhhhhhggggggggggggggggggggggghghghhhhhhhggggggggoggggghhhhhhhhhhhhghgghggggggghghggggogggogggggghgghggghghghgggggggghghhhhhhhlllhhhghhhhhlhhlhlhhhhhghhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhghhhhhgghhjljhlhhlhlhhlhhhhhhlhhhhlhjhhlhhjhhhhhggghhhoghhgggggghhggggogggghhggggggggoggggggggggggggoggghgggggghhggogggghgggggogggggoggggghghghhhgggggggggggggoggggggggggggogggoggggggogogggg", "hhhhggggggggggggggghhhhhhhhhhhhhhhhggggggggggggghhhghghghghgghgghhhghgggghgggggggggghhhhhhhhhhhhghghggghgghhhhhghgggggggggggghggghgghgghhhgghgghghhgghghhhlllhlhhhhhhhhhhhhhhhhhhhgghhhhhhhhhhhhlllhlhhhhhhhhhghhhhhhhhhhhhhhhlhjhlhhlhhhhhhhhhlhlhhhhllhhlhjhllhhlhlhggggogooggggggggogggggoggggggooggogggggggggggggggggggghggggggggogoggggggooogogggggggggghghhhhhhhhhhhhggggggggoggghhhhhggggogggghggggoooogg", "gggggghggggggggggghgghhhhhhhhhhghgghghggggggggghggggghghggghggghghggghghhhghgggghghhghhhhhhhhhhghhhghggggggghhghghgggggogoggggghgghghghhghghgghghhhghghhhhlhhlhlhhhhhhhhhhhhhhhhhhhghhhhhhhgghhhhlhjhlhlhhhhhhhhhhhhhhhhhhhhhhhhlljlhhhlhhhhhhhhhhlhjhhhjhlhhhgjhhhhhhhhoggoogggoogghggghgggggggggoggggogoggoogggggghgghggghggggggogogogoooggghggoggggggggghhhhhhhhhhhhhhhhggghgggogoggghhhhhggogoghhhhhhgggggog" }; nethack-3.4.3/sys/amiga/ifchange0100644000000000000000000000221707764735041015237 0ustar rootroot.KEY oper/a,tmp/a,real/a,f1,f2,f3,f4,f5 . ; miscellaneous script functions for the Amiga . ; SCCS Id: @(#)ifchange 3.2 96/02/04 . ; Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1992, 1993, 1996. . ; NetHack may be freely redistributed. See license for details. FAILAT 6 IF EQ "MOVE" IF EXISTS diff >T:mic -c search from T:mic SEARCH "---" QUIET IF WARN echo "MOVE: no change" delete ELSE echo "MOVE: copy" copy clone delete ENDIF ELSE echo "MOVE: copy2" copy clone delete ENDIF QUIT ENDIF IF EQ "TOUCH" IF EXISTS diff >T:mic -c search from T:mic SEARCH "---" QUIET IF NOT WARN echo "TOUCH: touch" IF NOT EQ "@" setdate ENDIF IF NOT EQ "@" setdate ENDIF IF NOT EQ "@" setdate ENDIF IF NOT EQ "@" setdate ENDIF IF NOT EQ "@" setdate ENDIF ENDIF ENDIF QUIT ENDIF echo "ifchange: '' not recognized" quit 10 nethack-3.4.3/sys/amiga/mkdmake0100644000000000000000000000062107764735041015101 0ustar rootrootGE/$@/%(left)/ GE/$ #include "config.h" #include "tile.h" #include #include #include #include #include #include #include #include #include #include #ifndef _DCC # include # include # include #endif void panic(const char *); void map_colors(void); int BestMatch(int, int, int); extern pixval ColorMap[3][MAXCOLORMAPSIZE]; extern int colorsinmap; /* * WARNING: * This program carries forth the assumption that the colormaps in all * of the .txt files are the same. This is a bug. */ struct { int Height; int Width; } IFFScreen; /* * We are using a hybrid form of our own design which we call a BMAP (for * bitmap) form. It is an ILBM with the bitmaps already deinterleaved, * completely uncompressed. * This speeds the loading of the images from the games point of view because it * does not have to deinterleave and uncompress them. */ #define ID_BMAP MAKE_ID( 'B', 'M', 'A', 'P' ) /* instead of ILBM */ #define ID_BMHD MAKE_ID( 'B', 'M', 'H', 'D' ) /* Same as ILBM */ #define ID_CAMG MAKE_ID( 'C', 'A', 'M', 'G' ) /* Same as ILBM */ #define ID_CMAP MAKE_ID( 'C', 'M', 'A', 'P' ) /* Same as ILBM */ #define ID_PDAT MAKE_ID( 'P', 'D', 'A', 'T' ) /* Extra data describing plane * size due to graphics.library * rounding requirements. */ #define ID_PLNE MAKE_ID( 'P', 'L', 'N', 'E' ) /* The planes of the image */ #ifndef _DCC extern #endif struct Library *IFFParseBase; int nplanes; /* BMHD from IFF documentation */ typedef struct { UWORD w, h; WORD x, y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE reserved1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; } BitMapHeader; typedef struct { UBYTE r, g, b; } AmiColorMap; pixel pixels[TILE_Y][TILE_X]; AmiColorMap *cmap; int findcolor( register pixel *pix ); void packwritebody( pixel (*tile)[TILE_X], char **planes, int tileno ); void error( char *str ) { fprintf( stderr, "ERROR: %s\n", str ); } /* * This array maps the image colors to the amiga's first 16 colors. The colors * are reordered to help with maintaining dripen settings. */ int colrmap[] = { 0, 6, 9, 15, 4, 10, 2, 3, 5, 11, 7, 13, 8, 1, 14, 12 }; /* How many tiles fit across and down. */ #define COLS 20 #define ROWS ((tiles + COLS-1) / COLS) main( int argc, char **argv ) { int colors; struct { long nplanes; long pbytes; long across; long down; long npics; long xsize; long ysize; } pdat; long pbytes; /* Bytes of data in a plane */ int i, cnt; BitMapHeader bmhd; struct IFFHandle *iff; long camg = HIRES|LACE; int tiles=0; char **planes; if(argc != 3){ fprintf(stderr, "Usage: %s source destination\n", argv[0]); exit(1); } #if defined(_DCC) || defined(__GNUC__) IFFParseBase = OpenLibrary( "iffparse.library", 0 ); if( !IFFParseBase ) { error( "unable to open iffparse.library" ); exit( 1 ); } #endif /* First, count the files in the file */ if( fopen_text_file( argv[1], "r" ) != TRUE ) { perror( argv[1] ); return( 1 ); } nplanes = 0; i = colorsinmap-1; /*IFFScreen.Colors - 1; */ while( i != 0 ) { nplanes++; i >>= 1; } planes = malloc( nplanes * sizeof( char * ) ); if( planes == 0 ) { error( "can not allocate planes pointer" ); exit( 1 ); } while( read_text_tile( pixels ) == TRUE ) ++tiles; fclose_text_file(); IFFScreen.Width = COLS * TILE_X; IFFScreen.Height = ROWS * TILE_Y; pbytes = (COLS * ROWS * TILE_X + 15) / 16 * 2 * TILE_Y; for( i = 0; i < nplanes; ++i ) { planes[ i ] = calloc( 1, pbytes ); if( planes[ i ] == 0 ) { error( "can not allocate planes pointer" ); exit( 1 ); } } /* Now, process it */ if( fopen_text_file( argv[1], "r" ) != TRUE ) { perror( argv[1] ); return( 1 ); } iff = AllocIFF(); if( !iff ) { error( "Can not allocate IFFHandle" ); return( 1 ); } iff->iff_Stream = Open( argv[2], MODE_NEWFILE ); if( !iff->iff_Stream ) { error( "Can not open output file" ); return( 1 ); } InitIFFasDOS( iff ); OpenIFF( iff, IFFF_WRITE ); PushChunk( iff, ID_BMAP, ID_FORM, IFFSIZE_UNKNOWN ); bmhd.w = IFFScreen.Width; bmhd.h = IFFScreen.Height; bmhd.x = 0; bmhd.y = 0; bmhd.nPlanes = nplanes; bmhd.masking = 0; bmhd.compression = 0; bmhd.reserved1 = 0; bmhd.transparentColor = 0; bmhd.xAspect = 100; bmhd.yAspect = 100; bmhd.pageWidth = TILE_X; bmhd.pageHeight = TILE_Y; PushChunk( iff, ID_BMAP, ID_BMHD, sizeof( bmhd ) ); WriteChunkBytes( iff, &bmhd, sizeof( bmhd ) ); PopChunk( iff ); PushChunk( iff, ID_BMAP, ID_CAMG, sizeof( camg ) ); WriteChunkBytes( iff, &camg, sizeof( camg ) ); PopChunk( iff ); /* We need to reorder the colors to get reasonable default pens but * we also need to know where some of the colors are - so go find out. */ map_colors(); cmap = malloc( (colors = (1L<iff_Stream ); FreeIFF( iff ); printf( "\n%d tiles converted\n", cnt ); #if defined(_DCC) || defined(__GNUC__) CloseLibrary( IFFParseBase ); #endif exit( 0 ); } findcolor( register pixel *pix ) { register int i; for( i = 0; i < MAXCOLORMAPSIZE; ++i ) { if( (pix->r == ColorMap[ CM_RED ][i] ) && (pix->g == ColorMap[ CM_GREEN ][i] ) && (pix->b == ColorMap[ CM_BLUE ][i] ) ) { return( i ); } } return( -1 ); } void packwritebody( pixel (*tile)[TILE_X], char **planes, int tileno ) { register int i, j, k, col; register char *buf; register int across, rowbytes, xoff, yoff; /* how many tiles fit across? */ across = COLS; /* How many bytes per pixel row */ rowbytes = ((IFFScreen.Width + 15)/16)*2; /* How many bytes to account for y distance in planes */ yoff = ((tileno / across) * TILE_Y) * rowbytes; /* How many bytes to account for x distance in planes */ xoff = (tileno % across) * (TILE_X/8); /* For each row... */ for( i = 0; i < TILE_Y; ++i ) { /* For each bitplane... */ for( k = 0; k < nplanes; ++k ) { const int mask = 1l< rate){ bestrate = rate; bestslot = x; } } #ifdef DBG printf("map (%d,%d,%d) -> %d (error=%d)\n",r,g,b,bestslot,bestrate); #endif return bestslot; } long * alloc( unsigned int n ) { long *ret = malloc( n ); if(!ret){ error("Can't allocate memory"); exit(1); } return( ret ); } void panic(const char *msg){ fprintf(stderr,"PANIC: %s\n",msg); exit(1); } nethack-3.4.3/sys/amiga/winami.c0100644000000000000000000012645707764735041015215 0ustar rootroot/* SCCS Id: @(#)winami.c 3.2 2000/01/12 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #include "dlb.h" #ifdef AMIGA_INTUITION static int FDECL( put_ext_cmd, ( char *, int, struct amii_WinDesc *, int ) ); struct amii_DisplayDesc *amiIDisplay; /* the Amiga Intuition descriptor */ struct Rectangle lastinvent, lastmsg; int clipping = 0; int clipx=0; int clipy=0; int clipxmax=0; int clipymax=0; int scrollmsg = 1; int alwaysinvent = 0; int amii_numcolors; long amii_scrnmode; /* Interface definition, for use by windows.c and winprocs.h to provide * the intuition interface for the amiga... */ struct window_procs amii_procs = { "amii", WC_COLOR|WC_HILITE_PET|WC_INVERSE, 0L, amii_init_nhwindows, amii_player_selection, amii_askname, amii_get_nh_event, amii_exit_nhwindows, amii_suspend_nhwindows, amii_resume_nhwindows, amii_create_nhwindow, amii_clear_nhwindow, amii_display_nhwindow, amii_destroy_nhwindow, amii_curs, amii_putstr, amii_display_file, amii_start_menu, amii_add_menu, amii_end_menu, amii_select_menu, genl_message_menu, amii_update_inventory, amii_mark_synch, amii_wait_synch, #ifdef CLIPPING amii_cliparound, #endif #ifdef POSITIONBAR donull, #endif amii_print_glyph, amii_raw_print, amii_raw_print_bold, amii_nhgetch, amii_nh_poskey, amii_bell, amii_doprev_message, amii_yn_function, amii_getlin, amii_get_ext_cmd, amii_number_pad, amii_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ amii_change_color, amii_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ amii_delay_output, amii_delay_output, amii_outrip, genl_preference_update }; /* The view window layout uses the same function names so we can use * a shared library to allow the executable to be smaller. */ struct window_procs amiv_procs = { "amitile", WC_COLOR|WC_HILITE_PET|WC_INVERSE, 0L, amii_init_nhwindows, amii_player_selection, amii_askname, amii_get_nh_event, amii_exit_nhwindows, amii_suspend_nhwindows, amii_resume_nhwindows, amii_create_nhwindow, amii_clear_nhwindow, amii_display_nhwindow, amii_destroy_nhwindow, amii_curs, amii_putstr, amii_display_file, amii_start_menu, amii_add_menu, amii_end_menu, amii_select_menu, genl_message_menu, amii_update_inventory, amii_mark_synch, amii_wait_synch, #ifdef CLIPPING amii_cliparound, #endif #ifdef POSITIONBAR donull, #endif amii_print_glyph, amii_raw_print, amii_raw_print_bold, amii_nhgetch, amii_nh_poskey, amii_bell, amii_doprev_message, amii_yn_function, amii_getlin, amii_get_ext_cmd, amii_number_pad, amii_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ amii_change_color, amii_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ amii_delay_output, amii_delay_output, amii_outrip, genl_preference_update }; unsigned short amii_initmap[ AMII_MAXCOLORS ]; /* Default pens used unless user overides in nethack.cnf. */ unsigned short amii_init_map[ AMII_MAXCOLORS ] = { 0x0000, /* color #0 C_BLACK */ 0x0FFF, /* color #1 C_WHITE */ 0x0830, /* color #2 C_BROWN */ 0x07ac, /* color #3 C_CYAN */ 0x0181, /* color #4 C_GREEN */ 0x0C06, /* color #5 C_MAGENTA */ 0x023E, /* color #6 C_BLUE */ 0x0c00, /* color #7 C_RED */ }; unsigned short amiv_init_map[ AMII_MAXCOLORS ] = { 0x0000, /* color #0 C_BLACK */ 0x0fff, /* color #1 C_WHITE */ 0x00bf, /* color #2 C_CYAN */ 0x0f60, /* color #3 C_ORANGE */ 0x000f, /* color #4 C_BLUE */ 0x0090, /* color #5 C_GREEN */ 0x069b, /* color #6 C_GREY */ 0x0f00, /* color #7 C_RED */ 0x06f0, /* color #8 C_LTGREEN */ 0x0ff0, /* color #9 C_YELLOW */ 0x0f0f, /* color #10 C_MAGENTA */ 0x0940, /* color #11 C_BROWN */ 0x0466, /* color #12 C_GREYBLUE */ 0x0c40, /* color #13 C_LTBROWN */ 0x0ddb, /* color #14 C_LTGREY */ 0x0fb9, /* color #15 C_PEACH */ /* Pens for dripens etc under AA or better */ 0x0222, /* color #16 */ 0x0fdc, /* color #17 */ 0x0000, /* color #18 */ 0x0ccc, /* color #19 */ 0x0bbb, /* color #20 */ 0x0BA9, /* color #21 */ 0x0999, /* color #22 */ 0x0987, /* color #23 */ 0x0765, /* color #24 */ 0x0666, /* color #25 */ 0x0555, /* color #26 */ 0x0533, /* color #27 */ 0x0333, /* color #28 */ 0x018f, /* color #29 */ 0x0f81, /* color #30 */ 0x0fff, /* color #31 */ }; #if !defined( TTY_GRAPHICS ) || defined( SHAREDLIB ) /* this should be shared better */ char morc; /* the character typed in response to a --more-- prompt */ #endif char spaces[ 76 ] = " "; winid WIN_BASE = WIN_ERR; winid WIN_OVER = WIN_ERR; winid amii_rawprwin = WIN_ERR; /* Changed later during window/screen opens... */ int txwidth = FONTWIDTH, txheight = FONTHEIGHT, txbaseline = FONTBASELINE; /* If a 240 or more row screen is in front when we start, this will be * set to 1, and the windows will be given borders to allow them to be * arranged differently. The Message window may eventually get a scroller... */ int bigscreen = 0; /* This gadget data is replicated for menu/text windows... */ struct PropInfo PropScroll = { AUTOKNOB|FREEVERT, 0xffff,0xffff, 0xffff,0xffff, }; struct Image Image1 = { 0,0, 7,102, 0, NULL, 0x0000,0x0000, NULL }; struct Gadget MenuScroll = { NULL, -15,10, 15,-19, GRELRIGHT|GRELHEIGHT, RELVERIFY|FOLLOWMOUSE|RIGHTBORDER|GADGIMMEDIATE|RELVERIFY, PROPGADGET, (APTR)&Image1, NULL, NULL, NULL, (APTR)&PropScroll, 1, NULL }; /* This gadget is for the message window... */ struct PropInfo MsgPropScroll = { AUTOKNOB|FREEVERT, 0xffff,0xffff, 0xffff,0xffff, }; struct Image MsgImage1 = { 0,0, 7,102, 0, NULL, 0x0000,0x0000, NULL }; struct Gadget MsgScroll = { NULL, -15,10, 14,-19, GRELRIGHT|GRELHEIGHT, RELVERIFY|FOLLOWMOUSE|RIGHTBORDER|GADGIMMEDIATE|RELVERIFY, PROPGADGET, (APTR)&MsgImage1, NULL, NULL, NULL, (APTR)&MsgPropScroll, 1, NULL }; int wincnt=0; /* # of nh windows opened */ /* We advertise a public screen to allow some people to do other things * while they are playing... like compiling... */ #ifdef INTUI_NEW_LOOK extern struct Hook fillhook; struct TagItem tags[] = { { WA_BackFill, (ULONG)&fillhook }, { WA_PubScreenName, (ULONG)"NetHack" }, { TAG_DONE, 0 }, }; #endif /* * The default dimensions and status values for each window type. The * data here is generally changed in create_nhwindow(), so beware that * what you see here may not be exactly what you get. */ struct win_setup new_wins[] = { /* First entry not used, types are based at 1 */ {{0}}, /* NHW_MESSAGE */ {{0,1,640,11, 0xff,0xff, NEWSIZE|GADGETUP|GADGETDOWN|MOUSEMOVE|MOUSEBUTTONS|RAWKEY, BORDERLESS|ACTIVATE|SMART_REFRESH #ifdef INTUI_NEW_LOOK |WFLG_NW_EXTENDED #endif , NULL,NULL,(UBYTE*)"Messages",NULL,NULL,320,40,0xffff,0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN,tags #else CUSTOMSCREEN #endif }, 0,0,1,1,80,80}, /* NHW_STATUS */ {{0,181,640,24, 0xff,0xff, RAWKEY|MENUPICK|DISKINSERTED, BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP #ifdef INTUI_NEW_LOOK |WFLG_NW_EXTENDED #endif , NULL,NULL,(UBYTE*)"Game Status",NULL,NULL,0,0,0xffff,0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN,tags #else CUSTOMSCREEN #endif }, 0,0,2,2,78,78}, /* NHW_MAP */ {{0,0,WIDTH,WINDOWHEIGHT, 0xff,0xff, RAWKEY|MENUPICK|MOUSEBUTTONS|ACTIVEWINDOW|MOUSEMOVE, BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP #ifdef INTUI_NEW_LOOK |WFLG_NW_EXTENDED #endif , NULL,NULL,(UBYTE*)"Dungeon Map",NULL,NULL,64,64,0xffff,0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN,tags #else CUSTOMSCREEN #endif }, 0,0,22,22,80,80}, /* NHW_MENU */ {{400,10,10,10, 0xff,0xff, RAWKEY|MENUPICK|DISKINSERTED|MOUSEMOVE|MOUSEBUTTONS| GADGETUP|GADGETDOWN|CLOSEWINDOW|VANILLAKEY|NEWSIZE|INACTIVEWINDOW, WINDOWSIZING|WINDOWCLOSE|WINDOWDRAG|ACTIVATE|SMART_REFRESH #ifdef INTUI_NEW_LOOK |WFLG_NW_EXTENDED #endif , &MenuScroll,NULL,NULL,NULL,NULL,64,32,0xffff,0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN,tags #else CUSTOMSCREEN #endif }, 0,0,1,1,22,78}, /* NHW_TEXT */ {{0,0,640,200, 0xff,0xff, RAWKEY|MENUPICK|DISKINSERTED|MOUSEMOVE| GADGETUP|CLOSEWINDOW|VANILLAKEY|NEWSIZE, WINDOWSIZING|WINDOWCLOSE|WINDOWDRAG|ACTIVATE|SMART_REFRESH #ifdef INTUI_NEW_LOOK |WFLG_NW_EXTENDED #endif , &MenuScroll,NULL,(UBYTE*)NULL,NULL,NULL,100,32,0xffff,0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN,tags #else CUSTOMSCREEN #endif }, 0,0,1,1,22,78}, /* NHW_BASE */ {{0,0,WIDTH,WINDOWHEIGHT, 0xff,0xff, RAWKEY|MENUPICK|MOUSEBUTTONS, BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP #ifdef INTUI_NEW_LOOK |WFLG_NW_EXTENDED #endif , NULL,NULL,(UBYTE*)NULL,NULL,NULL,-1,-1,0xffff,0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN,tags #else CUSTOMSCREEN #endif }, 0,0,22,22,80,80}, /* NHW_OVER */ {{320,20,319,179, 0xff,0xff, RAWKEY|MENUPICK|MOUSEBUTTONS, BORDERLESS|ACTIVATE|SMART_REFRESH|BACKDROP #ifdef INTUI_NEW_LOOK |WFLG_NW_EXTENDED #endif , NULL,NULL,(UBYTE*)NULL,NULL,NULL,64,32,0xffff,0xffff, #ifdef INTUI_NEW_LOOK PUBLICSCREEN,tags #else CUSTOMSCREEN #endif }, 0,0,22,22,80,80}, }; const char winpanicstr[] = "Bad winid %d in %s()"; /* The opened windows information */ struct amii_WinDesc *amii_wins[ MAXWIN + 1 ]; #ifdef INTUI_NEW_LOOK /* * NUMDRIPENS varies based on headers, so don't use it * here, its value is used elsewhere. */ UWORD amii_defpens[ 20 ]; struct TagItem scrntags[] = { { SA_PubName, (ULONG)"NetHack" }, { SA_Overscan, OSCAN_TEXT }, { SA_AutoScroll, TRUE }, #if LIBRARY_VERSION >= 39 { SA_Interleaved, TRUE }, #endif { SA_Pens, (ULONG)0 }, { SA_DisplayID, 0 }, { TAG_DONE, 0 }, }; #endif struct NewScreen NewHackScreen = { 0, 0, WIDTH, SCREENHEIGHT, 3, 0, 1, /* DetailPen, BlockPen */ HIRES, CUSTOMSCREEN #ifdef INTUI_NEW_LOOK |NS_EXTENDED #endif , &Hack80, /* Font */ NULL, /*(UBYTE *)" NetHack X.Y.Z" */ NULL, /* Gadgets */ NULL, /* CustomBitmap */ #ifdef INTUI_NEW_LOOK scrntags #endif }; /* * plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. * It may still contain a suffix denoting pl_character. * Always called after init_nhwindows() and before display_gamewindows(). */ void amii_askname() { char plnametmp[300]; /* From winreq.c: sizeof(StrStringSIBuff) */ *plnametmp = 0; do { amii_getlin( "Who are you?", plnametmp ); } while( strlen( plnametmp ) == 0 ); strncpy(plname, plnametmp, PL_NSIZ-1); /* Avoid overflowing plname[] */ plname[PL_NSIZ-1] = 0; if( *plname == '\33' ) { clearlocks(); exit_nhwindows(NULL); terminate(0); } } /* Discarded ... -jhsa #include "NH:sys/amiga/char.c" */ /* Get the player selection character */ #if 0 /* New function at the bottom */ void amii_player_selection() { register struct Window *cwin; register struct IntuiMessage *imsg; register int aredone = 0; register struct Gadget *gd; static int once = 0; long class, code; amii_clear_nhwindow( WIN_BASE ); if (validrole(flags.initrole)) return; else { flags.initrole=randrole(); return; } #if 0 /* Don't query the user ... instead give random character -jhsa */ #if 0 /* OBSOLETE */ if( *pl_character ){ pl_character[ 0 ] = toupper( pl_character[ 0 ] ); if( index( pl_classes, pl_character[ 0 ] ) ) return; } #endif if( !once ){ if( bigscreen ){ Type_NewWindowStructure1.TopEdge = (HackScreen->Height/2) - (Type_NewWindowStructure1.Height/2); } for( gd = Type_NewWindowStructure1.FirstGadget; gd; gd = gd->NextGadget ) { if( gd->GadgetID != 0 ) SetBorder( gd ); } once = 1; } if( WINVERS_AMIV ) { # ifdef INTUI_NEW_LOOK Type_NewWindowStructure1.Extension = wintags; Type_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED; fillhook.h_Entry = (ULONG(*)())LayerFillHook; fillhook.h_Data = (void *)-2; fillhook.h_SubEntry = 0; #endif } Type_NewWindowStructure1.Screen = HackScreen; if( ( cwin = OpenShWindow( (void *)&Type_NewWindowStructure1 ) ) == NULL ) { return; } #if 0 WindowToFront( cwin ); #endif while( !aredone ) { WaitPort( cwin->UserPort ); while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL ) { class = imsg->Class; code = imsg->Code; gd = (struct Gadget *)imsg->IAddress; ReplyMsg( (struct Message *)imsg ); switch( class ) { case VANILLAKEY: if( index( pl_classes, toupper( code ) ) ) { pl_character[0] = toupper( code ); aredone = 1; } else if( code == ' ' || code == '\n' || code == '\r' ) { flags.initrole = randrole(); #if 0 /* OBSOLETE */ #ifdef TOURIST strcpy( pl_character, roles[ rnd( 11 ) ] ); #else strcpy( pl_character, roles[ rnd( 10 ) ] ); #endif #endif aredone = 1; amii_clear_nhwindow( WIN_BASE ); CloseShWindow( cwin ); RandomWindow( pl_character ); return; } else if( code == 'q' || code == 'Q' ) { CloseShWindow( cwin ); clearlocks(); exit_nhwindows(NULL); terminate(0); } else DisplayBeep( NULL ); break; case GADGETUP: switch( gd->GadgetID ) { case 1: /* Random Character */ flags.initrole = randrole(); #if 0 /* OBSOLETE */ #ifdef TOURIST strcpy( pl_character, roles[ rnd( 11 ) ] ); #else strcpy( pl_character, roles[ rnd( 10 ) ] ); #endif #endif amii_clear_nhwindow( WIN_BASE ); CloseShWindow( cwin ); RandomWindow( pl_character ); return; default: pl_character[0] = gd->GadgetID; break; } aredone = 1; break; case CLOSEWINDOW: CloseShWindow( cwin ); clearlocks(); exit_nhwindows(NULL); terminate(0); break; } } } amii_clear_nhwindow( WIN_BASE ); CloseShWindow( cwin ); #endif /* Do not query user ... -jhsa */ } #endif /* Function elsewhere */ #if 0 /* Unused ... -jhsa */ #include "NH:sys/amiga/randwin.c" void RandomWindow( name ) char *name; { struct MsgPort *tport; struct timerequest *trq; static int once = 0; struct Gadget *gd; struct Window *w; struct IntuiMessage *imsg; int ticks = 0, aredone = 0, timerdone = 0; long mask, got; tport = CreateMsgPort(); trq = (struct timerequest *)CreateIORequest( tport, sizeof( *trq ) ); if( tport == NULL || trq == NULL ) { allocerr: if( tport ) DeleteMsgPort( tport ); if( trq ) DeleteIORequest( (struct IORequest *)trq ); Delay( 8 * 50 ); return; } if( OpenDevice( TIMERNAME, UNIT_VBLANK, (struct IORequest *)trq, 0L ) != 0 ) goto allocerr; trq->tr_node.io_Command = TR_ADDREQUEST; trq->tr_time.tv_secs = 8; trq->tr_time.tv_micro = 0; SendIO( (struct IORequest *)trq ); /* Place the name in the center of the screen */ Rnd_IText5.IText = name; Rnd_IText6.LeftEdge = Rnd_IText4.LeftEdge + (strlen(Rnd_IText4.IText)+1)*8; Rnd_NewWindowStructure1.Width = ( (strlen( Rnd_IText2.IText )+1) * 8 ) + HackScreen->WBorLeft + HackScreen->WBorRight; Rnd_IText5.LeftEdge = (Rnd_NewWindowStructure1.Width - (strlen(name)*8))/2; gd = Rnd_NewWindowStructure1.FirstGadget; gd->LeftEdge = (Rnd_NewWindowStructure1.Width - gd->Width)/2; /* Chose correct modifier */ Rnd_IText6.IText = "a"; switch( *name ) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'A': case 'E': case 'I': case 'O': case 'U': Rnd_IText6.IText = "an"; break; } if( !once ) { if( bigscreen ) { Rnd_NewWindowStructure1.TopEdge = (HackScreen->Height/2) - (Rnd_NewWindowStructure1.Height/2); } for( gd = Rnd_NewWindowStructure1.FirstGadget; gd; gd = gd->NextGadget ) { if( gd->GadgetID != 0 ) SetBorder( gd ); } Rnd_NewWindowStructure1.IDCMPFlags |= VANILLAKEY; once = 1; } if( WINVERS_AMIV ) { #ifdef INTUI_NEW_LOOK Rnd_NewWindowStructure1.Extension = wintags; Rnd_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED; fillhook.h_Entry = (ULONG(*)())LayerFillHook; fillhook.h_Data = (void *)-2; fillhook.h_SubEntry = 0; #endif } Rnd_NewWindowStructure1.Screen = HackScreen; if( ( w = OpenShWindow( (void *)&Rnd_NewWindowStructure1 ) ) == NULL ) { AbortIO( (struct IORequest *)trq ); WaitIO( (struct IORequest *)trq ); CloseDevice( (struct IORequest *)trq ); DeleteIORequest( (struct IORequest *) trq ); DeleteMsgPort( tport ); Delay( 50 * 8 ); return; } PrintIText( w->RPort, &Rnd_IntuiTextList1, 0, 0 ); mask = (1L << tport->mp_SigBit)|(1L << w->UserPort->mp_SigBit); while( !aredone ) { got = Wait( mask ); if( got & (1L << tport->mp_SigBit ) ) { aredone = 1; timerdone = 1; GetMsg( tport ); } while( w && ( imsg = (struct IntuiMessage *) GetMsg( w->UserPort ) ) ) { switch( (long)imsg->Class ) { /* Must be up for a little while... */ case INACTIVEWINDOW: if( ticks >= 40 ) aredone = 1; break; case INTUITICKS: ++ticks; break; case GADGETUP: aredone = 1; break; case VANILLAKEY: if(imsg->Code=='\n' || imsg->Code==' ' || imsg->Code=='\r') aredone = 1; break; } ReplyMsg( (struct Message *)imsg ); } } if( !timerdone ) { AbortIO( (struct IORequest *)trq ); WaitIO( (struct IORequest *)trq ); } CloseDevice( (struct IORequest *)trq ); DeleteIORequest( (struct IORequest *) trq ); DeleteMsgPort( tport ); if(w) CloseShWindow( w ); } #endif /* Discarded randwin ... -jhsa */ /* this should probably not be needed (or be renamed) void flush_output(){} */ /* Read in an extended command - doing command line completion for * when enough characters have been entered to make a unique command. */ int amii_get_ext_cmd( void ) { menu_item *mip; anything id; struct amii_WinDesc *cw; #ifdef EXTMENU winid win; int i; char buf[256]; #endif int colx; int bottom = 0; struct Window *w; char obufp[ 100 ]; register char *bufp = obufp; register int c; int com_index, oindex; int did_comp=0; /* did successful completion? */ int sel = -1; if( WIN_MESSAGE == WIN_ERR || ( cw = amii_wins[ WIN_MESSAGE ] ) == NULL ) panic(winpanicstr, WIN_MESSAGE, "get_ext_cmd"); w = cw->win; bottom = amii_msgborder( w ); colx = 3; #ifdef EXTMENU if (iflags.extmenu) { win = amii_create_nhwindow( NHW_MENU ); amii_start_menu( win ); pline("#"); amii_putstr( WIN_MESSAGE, -1, " " ); for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i ) { id.a_char = *extcmdlist[ i ].ef_txt; sprintf( buf, "%-10s - %s ", extcmdlist[ i ].ef_txt, extcmdlist[ i ].ef_desc ); amii_add_menu( win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0, 0, buf, MENU_UNSELECTED); } amii_end_menu( win, (char*)0 ); sel = amii_select_menu( win, PICK_ONE, &mip ); amii_destroy_nhwindow( win ); if( sel == 1 ) { sel = mip->item.a_char; for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i ) { if( sel == extcmdlist[i].ef_txt[0] ) break; } /* copy in the text */ if( extcmdlist[ i ].ef_txt != NULL ) { amii_clear_nhwindow( WIN_MESSAGE ); (void) put_ext_cmd( (char *)extcmdlist[i].ef_txt, 0, cw, bottom ); return( i ); } else DisplayBeep( NULL ); } return( -1 ); } else { #else amii_clear_nhwindow( WIN_MESSAGE ); /* Was NHW_MESSAGE */ if( scrollmsg ) { pline("#"); amii_addtopl(" "); } else { pline("# "); } sel = -1; while((c = WindowGetchar()) != EOF) { amii_curs( WIN_MESSAGE, colx, bottom ); if(c == '?' ) { int win, i; char buf[ 100 ]; if(did_comp){ while(bufp!=obufp) { bufp--; amii_curs(WIN_MESSAGE, --colx, bottom); Text(w->RPort,spaces,1); amii_curs(WIN_MESSAGE,colx,bottom); did_comp=0; } } win = amii_create_nhwindow( NHW_MENU ); amii_start_menu( win ); for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i ) { id.a_char = extcmdlist[i].ef_txt[0]; sprintf( buf, "%-10s - %s ", extcmdlist[ i ].ef_txt, extcmdlist[ i ].ef_desc ); amii_add_menu( win, NO_GLYPH, &id, extcmdlist[i].ef_txt[0], 0, 0, buf, MENU_UNSELECTED); } amii_end_menu( win, (char*)0 ); sel = amii_select_menu( win, PICK_ONE, &mip ); amii_destroy_nhwindow( win ); if( sel == 0 ) { return( -1 ); } else { sel = mip->item.a_char; for( i = 0; extcmdlist[ i ].ef_txt != NULL; ++i ) { if( sel == extcmdlist[i].ef_txt[0] ) break; } /* copy in the text */ if( extcmdlist[ i ].ef_txt != NULL ) { amii_clear_nhwindow( WIN_MESSAGE ); strcpy( bufp = obufp, extcmdlist[ i ].ef_txt ); (void) put_ext_cmd( obufp, colx, cw, bottom ); return( i ); } else DisplayBeep( NULL ); } } else if(c == '\033') { return( -1 ); } else if(c == '\b') { if(did_comp){ while(bufp!=obufp){ bufp--; amii_curs(WIN_MESSAGE, --colx, bottom); Text(w->RPort,spaces,1); amii_curs(WIN_MESSAGE,colx,bottom); did_comp=0; sel = -1; } } else if(bufp != obufp) { sel = -1; bufp--; amii_curs( WIN_MESSAGE, --colx, bottom); Text( w->RPort, spaces, 1 ); amii_curs( WIN_MESSAGE, colx, bottom); } else DisplayBeep( NULL ); } else if( c == '\n' || c == '\r' ) { return(sel); } else if( c >= ' ' && c < '\177') { /* avoid isprint() - some people don't have it ' ' is not always a printing char */ *bufp = c; bufp[1] = 0; oindex = 0; com_index = -1; while(extcmdlist[oindex].ef_txt != NULL) { if(!strnicmp(obufp, (char *)extcmdlist[oindex].ef_txt, strlen(obufp))) { if(com_index == -1) /* No matches yet*/ com_index = oindex; else /* More than 1 match */ com_index = -2; } oindex++; } if(com_index >= 0 && *obufp ) { Strcpy(obufp, extcmdlist[com_index].ef_txt); /* finish printing our string */ colx = put_ext_cmd( obufp, colx, cw, bottom ); bufp = obufp; /* reset it */ if(strlen(obufp) < BUFSZ-1 && strlen(obufp) < COLNO) bufp += strlen(obufp); did_comp=1; sel = com_index; } else { colx = put_ext_cmd( obufp, colx, cw, bottom ); if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO) bufp++; } } else if(c == ('X'-64) || c == '\177') { colx = 0; amii_clear_nhwindow( WIN_MESSAGE ); pline( "# " ); bufp = obufp; } else DisplayBeep( NULL ); } return(-1); #endif } static int put_ext_cmd( obufp, colx, cw, bottom ) char *obufp; int colx, bottom; struct amii_WinDesc *cw; { struct Window *w = cw->win; char *t; t = (char *)alloc( strlen( obufp ) + 7 ); if( t != NULL ) { if( scrollmsg ) { sprintf( t, "xxx%s", obufp ); t[0] = 1; t[1] = 1; t[2] = '#'; amii_curs( WIN_MESSAGE, 0, bottom); SetAPen( w->RPort, C_WHITE ); Text(w->RPort, "># ", 3 ); /* SetAPen( w->RPort, C_BLACK ); */ /* Black text on black screen doesn't look too well ... -jhsa */ Text(w->RPort, t+3, strlen( t ) - 3 ); } else { sprintf( t, "# %s", obufp ); amii_curs( WIN_MESSAGE, 0, bottom); SetAPen( w->RPort, C_WHITE ); Text(w->RPort, t, strlen( t ) ); } if( scrollmsg ) SetAPen( w->RPort, C_WHITE ); if( cw->data[ cw->maxrow - 1 ] ) free( cw->data[ cw->maxrow - 1 ] ); cw->data[ cw->maxrow - 1 ] = t; } else { amii_curs( WIN_MESSAGE, 0, bottom); SetAPen( w->RPort, C_WHITE ); Text(w->RPort, "# ", 2 ); /* SetAPen( w->RPort, C_BLACK ); */ /* Black on black ... -jhsa */ Text(w->RPort, obufp, strlen( obufp ) ); SetAPen( w->RPort, C_WHITE ); } amii_curs( WIN_MESSAGE, colx = strlen( obufp ) + 3 + ( scrollmsg != 0 ), bottom); return( colx ); } /* Ask a question and get a response */ char amii_yn_function(query, resp, def) const char *query,*resp; char def; /* * Generic yes/no function. 'def' is the default (returned by space or * return; 'esc' returns 'q', or 'n', or the default, depending on * what's in the string. The 'query' string is printed before the user * is asked about the string. * If resp is NULL, any single character is accepted and returned. * If not-NULL, only characters in it are allowed (exceptions: the * quitchars are always allowed, and if it contains '#' then digits * are allowed); if it includes an , anything beyond that won't * be shown in the prompt to the user but will be acceptable as input. */ { register char q; char rtmp[40]; boolean digit_ok, allow_num; char prompt[QBUFSZ]; register struct amii_WinDesc *cw; if( cw = amii_wins[ WIN_MESSAGE ] ) cw->disprows = 0; if (resp) { char *rb, respbuf[QBUFSZ]; allow_num = (index(resp, '#') != 0); Strcpy(respbuf, resp); /* any acceptable responses that follow aren't displayed */ if ((rb = index(respbuf, '\033')) != 0) *rb = '\0'; Sprintf(prompt, "%s [%s] ", query, respbuf); if (def) Sprintf(eos(prompt), "(%c) ", def); pline("%s", prompt); } else { amii_putstr(WIN_MESSAGE, 0, query); cursor_on(WIN_MESSAGE); q = WindowGetchar(); cursor_off(WIN_MESSAGE); *rtmp = q; rtmp[ 1 ] = 0; amii_addtopl(rtmp); goto clean_up; } do { /* loop until we get valid input */ cursor_on(WIN_MESSAGE); q = lowc(WindowGetchar()); cursor_off(WIN_MESSAGE); #if 0 /* fix for PL2 */ if (q == '\020') { /* ctrl-P */ if(!doprev) (void) tty_doprev_message(); /* need two initially */ (void) tty_doprev_message(); q = (char)0; doprev = 1; continue; } else if(doprev) { tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; doprev = 0; amii_addtopl(prompt); continue; } #endif digit_ok = allow_num && isdigit(q); if (q == '\033') { if (index(resp, 'q')) q = 'q'; else if (index(resp, 'n')) q = 'n'; else q = def; break; } else if (index(quitchars, q)) { q = def; break; } if (!index(resp, q) && !digit_ok) { amii_bell(); q = (char)0; } else if (q == '#' || digit_ok) { char z, digit_string[2]; int n_len = 0; long value = 0; amii_addtopl("#"), n_len++; digit_string[1] = '\0'; if (q != '#') { digit_string[0] = q; amii_addtopl(digit_string), n_len++; value = q - '0'; q = '#'; } do { /* loop until we get a non-digit */ cursor_on(WIN_MESSAGE); z = lowc(WindowGetchar()); cursor_off(WIN_MESSAGE); if (isdigit(z)) { value = (10 * value) + (z - '0'); if (value < 0) break; /* overflow: try again */ digit_string[0] = z; amii_addtopl(digit_string), n_len++; } else if (z == 'y' || index(quitchars, z)) { if (z == '\033') value = -1; /* abort */ z = '\n'; /* break */ } else if ( z == '\b') { if (n_len <= 1) { value = -1; break; } else { value /= 10; removetopl(1), n_len--; } } else { value = -1; /* abort */ amii_bell(); break; } } while (z != '\n'); if (value > 0) yn_number = value; else if (value == 0) q = 'n'; /* 0 => "no" */ else { /* remove number from top line, then try again */ removetopl(n_len), n_len = 0; q = '\0'; } } } while(!q); if (q != '#' && q != '\033') { Sprintf(rtmp, "%c", q); amii_addtopl(rtmp); } clean_up: cursor_off(WIN_MESSAGE); clear_nhwindow(WIN_MESSAGE); return q; } void amii_display_file(fn, complain) const char *fn; boolean complain; { register struct amii_WinDesc *cw; register int win; register dlb *fp; register char *t; register char buf[ 200 ]; if( fn == NULL ) panic("NULL file name in display_file()"); if( ( fp = dlb_fopen( fn, RDTMODE ) ) == (dlb *)NULL ) { if (complain) { sprintf( buf, "Can't display %s: %s", fn, #if defined(_DCC) || defined(__GNUC__) strerror(errno) #else # ifdef __SASC_60 __sys_errlist[ errno ] # else sys_errlist[ errno ] # endif #endif ); amii_addtopl( buf ); } return; } win = amii_create_nhwindow( NHW_TEXT ); /* Set window title to file name */ if( cw = amii_wins[ win ] ) cw->morestr = (char *)fn; while( dlb_fgets( buf, sizeof( buf ), fp ) != NULL ) { if( t = index( buf, '\n' ) ) *t = 0; amii_putstr( win, 0, buf ); } dlb_fclose( fp ); /* If there were lines in the file, display those lines */ if( amii_wins[ win ]->cury > 0 ) amii_display_nhwindow( win, TRUE ); amii_wins[win]->morestr = NULL; /* don't free title string */ amii_destroy_nhwindow( win ); } /* Put a 3-D motif border around the gadget. String gadgets or those * which do not have highlighting are rendered down. Boolean gadgets * are rendered in the up position by default. */ void SetBorder( gd ) register struct Gadget *gd; { register struct Border *bp; register short *sp; register int i, inc = -1, dec = -1; int borders = 6; int hipen = flags.amii_dripens[ SHINEPEN ], shadowpen = flags.amii_dripens[ SHADOWPEN ]; #ifdef INTUI_NEW_LOOK struct DrawInfo *dip; #endif #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { if( dip = GetScreenDrawInfo( HackScreen ) ) { hipen = dip->dri_Pens[ SHINEPEN ]; shadowpen = dip->dri_Pens[ SHADOWPEN ]; FreeScreenDrawInfo( HackScreen, dip ); } } #endif /* Allocate two border structures one for up image and one for down * image, plus vector arrays for the border lines. */ if( gd->GadgetType == STRGADGET ) borders = 12; if( ( bp = (struct Border *)alloc( ( ( sizeof( struct Border ) * 2 ) + ( sizeof( short ) * borders ) ) * 2 ) ) == NULL ) { return; } /* For a string gadget, we expand the border beyond the area where * the text will be entered. */ /* Remove any special rendering flags to avoid confusing intuition */ gd->Flags &= ~(GADGHIGHBITS|GADGIMAGE); sp = (short *)(bp + 4); if( gd->GadgetType == STRGADGET || ( gd->GadgetType == BOOLGADGET && ( gd->Flags & GADGHIGHBITS ) == GADGHNONE ) ) { sp[0] = -1; sp[1] = gd->Height - 1; sp[2] = -1; sp[3] = -1; sp[4] = gd->Width - 1; sp[5] = -1; sp[6] = gd->Width + 1; sp[7] = -2; sp[8] = gd->Width + 1; sp[9] = gd->Height + 1; sp[10] = -2; sp[11] = gd->Height + 1; sp[12] = -2; sp[13] = gd->Height; sp[14] = -2; sp[15] = -2; sp[16] = gd->Width; sp[17] = -2; sp[18] = gd->Width; sp[19] = gd->Height; sp[20] = -2; sp[21] = gd->Height; for( i = 0; i < 3; ++i ) { bp[ i ].LeftEdge = bp[ i ].TopEdge = -1; bp[ i ].FrontPen = ( i == 0 || i == 1 ) ? shadowpen : hipen; /* Have to use JAM2 so that the old colors disappear. */ bp[ i ].BackPen = C_BLACK; bp[ i ].DrawMode = JAM2; bp[ i ].Count = ( i == 0 || i == 1 ) ? 3 : 5; bp[ i ].XY = &sp[ i*6 ]; bp[ i ].NextBorder = ( i == 2 ) ? NULL : &bp[ i + 1 ]; } /* bp[0] and bp[1] two pieces for the up image */ gd->GadgetRender = (APTR) bp; /* No image change for select */ gd->SelectRender = (APTR) bp; gd->LeftEdge++; gd->TopEdge++; gd->Flags |= GADGHCOMP; } else { /* Create the border vector values for up and left side, and * also the lower and right side. */ sp[0] = dec; sp[1] = gd->Height + inc; sp[2] = dec; sp[3] = dec; sp[4] = gd->Width + inc; sp[5] = dec; sp[6] = gd->Width + inc; sp[7] = dec; sp[8] = gd->Width + inc; sp[9] = gd->Height + inc; sp[10] = dec; sp[11] = gd->Height + inc; /* We are creating 4 sets of borders, the two sides of the * rectangle share the border vectors with the opposite image, * but specify different colors. */ for( i = 0; i < 4; ++i ) { bp[ i ].TopEdge = bp[ i ].LeftEdge = 0; /* A GADGHNONE is always down */ if( gd->GadgetType == BOOLGADGET && ( gd->Flags & GADGHIGHBITS ) != GADGHNONE ) { bp[ i ].FrontPen = ( i == 1 || i == 2 ) ? shadowpen : hipen; } else { bp[ i ].FrontPen = ( i == 1 || i == 3 ) ? hipen : shadowpen; } /* Have to use JAM2 so that the old colors disappear. */ bp[ i ].BackPen = C_BLACK; bp[ i ].DrawMode = JAM2; bp[ i ].Count = 3; bp[ i ].XY = &sp[ 6 * ((i &1) != 0) ]; bp[ i ].NextBorder = ( i == 1 || i == 3 ) ? NULL : &bp[ i + 1 ]; } /* bp[0] and bp[1] two pieces for the up image */ gd->GadgetRender = (APTR) bp; /* bp[2] and bp[3] two pieces for the down image */ gd->SelectRender = (APTR) (bp + 2); gd->Flags |= GADGHIMAGE; } } /* Following function copied from wintty.c */ /* Modified slightly to fit amiga needs */ void amii_player_selection() { int i, k, n; char pick4u = 'n', thisch, lastch = 0; char pbuf[QBUFSZ], plbuf[QBUFSZ], rolenamebuf[QBUFSZ]; winid win; anything any; menu_item *selected = 0; rigid_role_checks(); /* Should we randomly pick for the player? */ if (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE) { char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend, flags.initalign); pline("%s", prompt); do { /* loop until we get valid input */ cursor_on(WIN_MESSAGE); pick4u = lowc(WindowGetchar()); cursor_off(WIN_MESSAGE); if (index(quitchars, pick4u)) pick4u = 'y'; } while(!index(ynqchars, pick4u)); pbuf[0] = pick4u; pbuf[1] = 0; amii_addtopl(pbuf); if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) free((genericptr_t) selected); clearlocks(); exit_nhwindows(NULL); terminate(0); /*NOTREACHED*/ return; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* Select a role, if necessary */ /* we'll try to be compatible with pre-selected race/gender/alignment, * but may not succeed */ if (flags.initrole < 0) { /* Process the choice */ if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { amii_putstr(WIN_MESSAGE, 0, "Incompatible role!"); flags.initrole = randrole(); } } else { /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ thisch = lowc(roles[i].name.m[0]); if (thisch == lastch) thisch = highc(thisch); if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) { if (flags.initgend == 1 && roles[i].name.f) Strcpy(rolenamebuf, roles[i].name.f); else Strcpy(rolenamebuf, roles[i].name.m); } else { if (roles[i].name.f) { Strcpy(rolenamebuf, roles[i].name.m); Strcat(rolenamebuf, "/"); Strcat(rolenamebuf, roles[i].name.f); } else Strcpy(rolenamebuf, roles[i].name.m); } add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED); lastch = thisch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole()+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { amii_putstr(WIN_MESSAGE, 0, "Incompatible race!"); flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { amii_putstr(WIN_MESSAGE, 0, "Incompatible gender!"); flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { amii_putstr(WIN_MESSAGE, 0, "Incompatible alignment!"); flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ } #endif /* AMIGA_INTUITION */ nethack-3.4.3/sys/amiga/winami.p0100644000000000000000000000473207764735041015221 0ustar rootroot/* SCCS Id: @(#)winami.p 3.1 93/01/08 */ /* Copyright (c) Gregg Wonderly, Naperville, IL, 1992, 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* winami.c */ void FDECL(amii_raw_print, (const char *)); void FDECL(amii_raw_print_bold, (const char *)); void FDECL(amii_start_menu, (winid )); void FDECL(amii_add_menu, (winid , char , int , const char *)); void FDECL(amii_end_menu, (winid , char , const char * , const char *)); char FDECL(amii_select_menu, (winid )); void NDECL(amii_update_inventory ); void NDECL(amii_mark_synch ); void NDECL(amii_wait_synch ); void NDECL(amii_setclipped ); void FDECL(amii_cliparound, (int , int )); void NDECL(amii_askname ); void NDECL(amii_player_selection ); void NDECL(flush_output ); void FDECL(amii_destroy_nhwindow, (winid )); int FDECL(amii_create_nhwindow, (int )); void NDECL(amii_init_nhwindows ); int NDECL(amii_get_ext_cmd); char FDECL(amii_yn_function, (const char * , const char * , char )); void FDECL(amii_addtopl, (const char *)); void FDECL(TextSpaces, (struct RastPort * , int )); void FDECL(amii_putstr, (winid , int , const char *)); void FDECL(amii_putsym, (winid , int , int , CHAR_P )); void FDECL(amii_clear_nhwindow, (winid )); void FDECL(amii_exit_nhwindows, (const char *)); int FDECL(amii_nh_poskey, (int * , int * , int *)); int NDECL(amii_nhgetch ); void NDECL(amii_get_nh_event ); void NDECL(amii_remember_topl ); int NDECL(amii_doprev_message ); void FDECL(amii_display_nhwindow, (winid , boolean )); void FDECL(amii_display_file, (const char * , boolean )); void FDECL(amii_curs, (winid , int , int )); void FDECL(amii_print_glyph, (winid , xchar , xchar , int )); void FDECL(DoMenuScroll, (int , int )); void FDECL(DisplayData, (int , int , int )); void FDECL(SetPropInfo, (struct Window * , struct Gadget * , long , long , long )); void FDECL(kill_nhwindows, (int )); void FDECL(amii_cl_end, (struct amii_WinDesc * , int )); void FDECL(cursor_off, (winid )); void FDECL(cursor_on, (winid )); void NDECL(amii_getret ); void FDECL(amii_getlin, (const char * , char *)); void FDECL(getlind, (const char * , char * , const char *)); void FDECL(amii_suspend_nhwindows, (char * )); void NDECL(amii_resume_nhwindows); void NDECL(amii_bell); void NDECL(EditColor); void FDECL(DrawCol, ( struct Window *, int, UWORD * ) ); void FDECL( DispCol, ( struct Window *w, int idx, UWORD * ) ); void FDECL( SetBorder, (struct Gadget *) ); void NDECL( port_help ); void FDECL( dismiss_nhwindow, (winid) ); nethack-3.4.3/sys/amiga/winchar.c0100644000000000000000000007463007764735041015357 0ustar rootroot/* SCCS Id: @(#)winchar.c 3.1 93/07/22 */ /* Copyright (c) Olaf Seibert (KosmoSoft), 1989, 1992 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland 1993 */ /* Copyright (c) Gregg Wonderly, Naperville Illinois, 1994. */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include #ifndef _DCC #include #endif #ifdef TESTING # include "hack.h" #else # include "NH:src/tile.c" #endif #include "NH:win/share/tile.h" #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #ifdef OPT_DISPMAP # define DISPMAP /* use display_map() from dispmap.s */ #endif /* NH:sys/amiga/winvchar.c */ int main ( int , char ** ); struct BitMap *MyAllocBitMap ( int , int , int , long ); void MyFreeBitMap ( struct BitMap * ); void FreeImageFiles ( char **, struct BitMap ** ); void amiv_flush_glyph_buffer ( struct Window * ); void amiv_lprint_glyph ( winid , int , int ); void amii_lprint_glyph ( winid , int , int ); void amiv_start_glyphout ( winid ); void amii_end_glyphout ( winid ); void SetMazeType ( MazeType ); int GlyphToIcon ( int ); void amii_start_glyphout ( winid ); void amii_end_glyphout ( winid ); void amii_flush_glyph_buffer( struct Window * ); int amii_extraplanes = 0; extern int reclip; struct BitMap *MyAllocBitMap( int xsize, int ysize, int depth, long mflags ); void MyFreeBitMap( struct BitMap *bmp ); #ifdef DISPMAP extern void display_map( struct Window * ); #endif /* * These values will be available from tile.c source * * #define MAXMONTILE 335 * #define MAXOBJTILE 722 * #define MAXOTHTILE 841 */ #define IMGROWS 12 #define IMGCOLUMNS 20 #define IMGPAGESIZE (IMGROWS*IMGCOLUMNS) #define ID_BMAP MAKE_ID('B','M','A','P') /* The type of form we use */ #define ID_BMHD MAKE_ID('B','M','H','D') /* The ILBM bitmap header */ #define ID_CAMG MAKE_ID('C','A','M','G') /* The ILBM camg (ignored) */ #define ID_CMAP MAKE_ID('C','M','A','P') /* Standard ILBM color map */ #define ID_PLNE MAKE_ID('P','L','N','E') /* The plane data */ #define ID_PDAT MAKE_ID('P','D','A','T') /* The PDAT structure below */ struct PDAT pictdata; #define NUMTILEIMAGES 3 char *tileimages[] = { #define TBLMONTILE 0 "NetHack:tiles/monsters.iff", #define TBLOBJTILE 1 "NetHack:tiles/objects.iff", #define TBLOTHTILE 2 "NetHack:tiles/other.iff", 0, }; struct BitMap *ifftimg[ NUMTILEIMAGES ], *tile; #ifdef TESTING short pens[NUMDRIPENS] = { 8, 3, 15, 0, 15, 7, 7, 8, 0 }; main( int argc, char **argv ) { BitMapHeader bmhd; struct IntuiMessage *imsg; long code, class; char buf[100]; int i, x, y, tbl, done = 0, num; struct Window *w; struct Screen *scr; bmhd = ReadTileImageFiles( ); scr = OpenScreenTags( NULL, SA_Depth, pictdata.nplanes + amii_extraplanes, SA_DisplayID, DBLNTSC_MONITOR_ID|HIRESLACE_KEY, SA_Overscan, OSCAN_TEXT, SA_Top, 0, SA_Left, 0, SA_Width, STDSCREENWIDTH, SA_Height, STDSCREENHEIGHT, SA_Type, CUSTOMSCREEN, SA_DetailPen, 0, SA_BlockPen, 1, SA_Title, "NetHack Chars", SA_Pens, pens, TAG_DONE ); if( scr == NULL ) { printf( "no screen\n" ); #undef exit exit( 1 ); } w = OpenWindowTags( 0, WA_CustomScreen, scr, WA_Flags, WFLG_DRAGBAR|WFLG_SIZEGADGET|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET, WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE|IDCMP_MOUSEBUTTONS, WA_Left, 0, WA_Top, scr->WBorTop + 1 + 13, WA_MinWidth, 100, WA_MinHeight, 100, WA_MaxWidth, 700, WA_MaxHeight, 1000, WA_Width, 640, WA_Height, 340, WA_SmartRefresh, TRUE, TAG_DONE ); if( w ) { while( !done ) { for( i = 0; i < NUMTILEIMAGES * IMGPAGESIZE; ++i ) { int dx, dy; tbl = i/IMGPAGESIZE; x = i % IMGPAGESIZE; y = x / IMGCOLUMNS; x = x % IMGCOLUMNS; dx = i % (IMGCOLUMNS*2); dy = i / (IMGCOLUMNS*2); BltBitMapRastPort( ifftimg[ tbl ], x * pictdata.xsize, y * pictdata.ysize, w->RPort, w->BorderLeft + 1 + dx*pictdata.xsize, w->BorderTop + 1 + dy*pictdata.ysize, pictdata.xsize, pictdata.ysize, 0xc0 ); } WaitPort( w->UserPort ); while( imsg = (struct IntuiMessage *)GetMsg( w->UserPort ) ) { class = imsg->Class; code = imsg->Code; ReplyMsg( (struct Message *)imsg ); switch( class ) { case IDCMP_MOUSEBUTTONS: { x = imsg->MouseX - w->BorderLeft; y = imsg->MouseY - w->BorderTop; num = ((y/pictdata.ysize)*IMGCOLUMNS*2)+(x/pictdata.xsize); sprintf( buf, "Char #%d", num ); SetWindowTitles( w, buf, buf ); } break; case IDCMP_CLOSEWINDOW: done = 1; break; } } } CloseWindow( w ); CloseScreen( scr ); } FreeImageFiles(tileimages, ifftimg ); return(0); } #endif BitMapHeader ReadTileImageFiles(){ char *errstr = NULL; BitMapHeader ret = ReadImageFiles(tileimages, ifftimg, &errstr); if(errstr){ panic(errstr); } return ret; } BitMapHeader ReadImageFiles(char **filenames, struct BitMap **iffimg, char **errstrp ) { BitMapHeader *bmhd = NULL, bmhds; unsigned char *cmap; extern int errno; register int i, j; struct IFFHandle *iff; struct StoredProperty *prop; IFFParseBase = OpenLibrary( "iffparse.library", 0L ); if( !IFFParseBase ) { *errstrp = "No iffparse.library"; return bmhds; } /* for( i = 0; filenames[i]; ++i ) memset( iffimg[i], 0, sizeof( struct BitMap ) ); */ for( i = 0; filenames[i]; ++i ) { iff = AllocIFF(); if( !iff ) { FreeImageFiles(filenames, iffimg ); *errstrp = "can't start IFF processing"; return bmhds; } iff->iff_Stream = Open( filenames[i], MODE_OLDFILE ); if( iff->iff_Stream == 0 ) { char *buf = malloc(100+strlen(filenames[i])); FreeImageFiles( filenames, iffimg ); sprintf(buf, "Can't open %s: %s", filenames[i], strerror( errno )); *errstrp = buf; return bmhds; } InitIFFasDOS( iff ); OpenIFF( iff, IFFF_READ ); PropChunk( iff, ID_BMAP, ID_BMHD ); PropChunk( iff, ID_BMAP, ID_CMAP ); PropChunk( iff, ID_BMAP, ID_CAMG ); PropChunk( iff, ID_BMAP, ID_PDAT ); StopChunk( iff, ID_BMAP, ID_PLNE ); if( ( j = ParseIFF( iff, IFFPARSE_SCAN ) ) != 0 ) { char *buf = malloc(100); FreeImageFiles( filenames, iffimg ); sprintf(buf,"ParseIFF failed for image %d, failure code: %d",i,j); *errstrp = buf; return bmhds; } if( prop = FindProp( iff, ID_BMAP, ID_BMHD ) ) { bmhd = (BitMapHeader *)prop->sp_Data; } else { FreeImageFiles(filenames, iffimg); CloseIFF( iff ); Close( iff->iff_Stream ); FreeIFF( iff ); *errstrp = "No BMHD CHUNK in file"; return bmhds; } if( prop = FindProp( iff, ID_BMAP, ID_CMAP ) ) { cmap = prop->sp_Data; for( j = 0; j < (1L << bmhd->nPlanes)*3; j+=3 ) { #if 0 /* Some day we will want to use the larger palette * resolution available under v39 and later. i.e. * 32 instead of 12 bits of color. Ususally this * just means shifting the color left by 16-20 bits * depending on what intensity looks best. Experience * says that the higher values are better intensities. * * For now though we won't do this. The color table * structure is incompatible with earlier versions of * intuition. We would have to do some funny things * to make 3*AMII_MAXCOLORS longs work like 3*AMII_MAXCOLORS * UWORD's at run time... A union would help, but... */ if( IntuitionBase->LibNode.lib_Version >= 39 ) { /* 8 bits of color, so shift to left end. */ amiv_init_map[ j+0 ] = cmap[j+0]<<24; amiv_init_map[ j+1 ] = cmap[j+1]<<24; amiv_init_map[ j+2 ] = cmap[j+2]<<24; } else #endif { /* We can only use 4 bits of the 8 that are stored in the * cmap, so mask them and then shift them into position * for the UWORD value to store. */ #ifndef TESTING amii_initmap[ j/3 ] = amiv_init_map[ j/3 ] = ((cmap[j+0]>>4)<<8)| ((cmap[j+1]>>4)<<4)| (cmap[j+2]>>4); #endif } } } else { FreeImageFiles(filenames, iffimg); CloseIFF( iff ); Close( iff->iff_Stream ); FreeIFF( iff ); *errstrp = "No CMAP CHUNK in file"; return bmhds; } if( prop = FindProp( iff, ID_BMAP, ID_PDAT ) ) { struct PDAT *pp; pp = (struct PDAT *)prop->sp_Data; pictdata = *pp; } else { FreeImageFiles(filenames, iffimg); CloseIFF( iff ); Close( iff->iff_Stream ); FreeIFF( iff ); *errstrp = "No PDAT CHUNK in file"; return bmhds; } iffimg[ i ] = MyAllocBitMap( bmhd->w, bmhd->h, pictdata.nplanes + amii_extraplanes, MEMF_CHIP|MEMF_CLEAR ); if( iffimg[ i ] == NULL ) { char *buf = malloc(80); FreeImageFiles(filenames, iffimg); sprintf(buf, "Can't allocate bitmap for image %d\n", i ); *errstrp = buf; return bmhds; } for( j = 0; j < pictdata.nplanes + amii_extraplanes; ++j ) { ReadChunkBytes( iff, iffimg[i]->Planes[j], RASSIZE( bmhd->w, bmhd->h ) ); } bmhds = *bmhd; CloseIFF( iff ); Close( iff->iff_Stream ); FreeIFF( iff ); } CloseLibrary( IFFParseBase ); tile = MyAllocBitMap( pictdata.xsize, pictdata.ysize, pictdata.nplanes + amii_extraplanes, MEMF_CHIP|MEMF_CLEAR ); if( tile == NULL ) { FreeImageFiles(filenames, iffimg); *errstrp = "Can't allocate tile bitmap for scaling"; } return( bmhds ); } struct MyBitMap { struct BitMap bm; long mflags; USHORT xsize, ysize; }; struct BitMap * MyAllocBitMap( int xsize, int ysize, int depth, long mflags ) { int j; struct MyBitMap *bm; bm = (struct MyBitMap *)alloc( sizeof( *bm ) ); if( !bm ) return( NULL ); bm->xsize = xsize; bm->ysize = ysize; InitBitMap( &bm->bm, depth, xsize, ysize ); for( j = 0; j < depth; ++j ) { if( mflags & MEMF_CHIP ) bm->bm.Planes[ j ] = AllocRaster( xsize, ysize ); else bm->bm.Planes[ j ] = AllocMem( RASSIZE( xsize, ysize ), mflags ); if( bm->bm.Planes[ j ] == 0 ) { MyFreeBitMap( &bm->bm ); return( NULL ); } if( mflags & MEMF_CLEAR ) memset( bm->bm.Planes[ j ], 0, RASSIZE( xsize, ysize ) ); } return( &bm->bm ); } void MyFreeBitMap( struct BitMap *bmp ) { int j; struct MyBitMap *bm = (struct MyBitMap *)bmp; for( j = 0; j < bm->bm.Depth; ++j ) { if( bm->bm.Planes[j] ) { if( bm->mflags & MEMF_CHIP ) FreeRaster( bm->bm.Planes[j], bm->xsize, bm->ysize ); else FreeMem( bm->bm.Planes[j], RASSIZE( bm->xsize, bm->ysize ) ); } } free( bm ); } #ifdef TESTING void panic(s,a1,a2,a3,a4) char *s; { printf( s, a1, a2, a3, a4 ); putchar('\n'); } long * alloc(unsigned int x){ long *p = (long *)malloc(x); if(!p){panic("malloc failed"); exit(1);} return p; } #endif void FreeTileImageFiles(){ FreeImageFiles(tileimages,ifftimg); } void FreeImageFiles(char **filenames, struct BitMap **img ) { register int i; for( i = 0; filenames[i]; ++i ) { if( img[ i ] ) MyFreeBitMap( img[ i ] ); } /* REALLY ugly hack alert! */ if( tile && img==ifftimg) MyFreeBitMap( tile ); } #ifndef TESTING /* * Define some stuff for our special glyph drawing routines */ unsigned short glyph_node_index, glyph_buffer_index; #define NUMBER_GLYPH_NODES 80 #define GLYPH_BUFFER_SIZE 512 struct amiv_glyph_node { short odstx, odsty; short srcx, srcy, dstx, dsty; struct BitMap *bitmap; }; struct amiv_glyph_node amiv_g_nodes[NUMBER_GLYPH_NODES]; static char amiv_glyph_buffer[GLYPH_BUFFER_SIZE]; void flush_glyph_buffer( vw ) struct Window *vw; { if( WINVERS_AMIV ) amiv_flush_glyph_buffer ( vw ); else amii_flush_glyph_buffer ( vw ); } /* * Routine to flush whatever is buffered */ void amiv_flush_glyph_buffer( vw ) struct Window *vw; { #if !defined(DISPMAP) || defined(OPT_DISPMAP) int xsize, ysize, x, y; struct BitScaleArgs bsa; struct BitScaleArgs bsm; struct RastPort rast; struct Window *w = NULL; struct BitMap *imgbm = 0, *bm = 0; int i, k; int scaling_needed; register struct RastPort *rp = vw->RPort; #endif /* If nothing is buffered, return before we do anything */ if(glyph_node_index == 0) return; cursor_off( WIN_MAP ); amiv_start_glyphout( WIN_MAP ); #ifdef OPT_DISPMAP if(flags.fast_map){ #endif #ifdef DISPMAP display_map( vw ); #endif #ifdef OPT_DISPMAP } else { #endif #if !defined(DISPMAP) || defined(OPT_DISPMAP) /* XXX fix indent */ /* This is a dynamic value based on this relationship. */ scaling_needed = ( pictdata.xsize != mxsize || pictdata.ysize != mysize ); /* If overview window is up, set up to render the correct scale there */ if( WIN_OVER != WIN_ERR && ( w = amii_wins[ WIN_OVER ]->win ) != NULL ) { InitRastPort( &rast ); /* Calculate the x and y size of each tile for a ROWNO by COLNO map */ xsize = (w->Width - w->BorderLeft - w->BorderRight) / COLNO; ysize = (w->Height - w->BorderTop - w->BorderBottom) / ROWNO; /* Get a chip memory bitmap to blit out of */ bm = MyAllocBitMap( pictdata.xsize, pictdata.ysize, pictdata.nplanes + amii_extraplanes, MEMF_CLEAR|MEMF_CHIP ); if( bm == NULL ) { amii_putstr( WIN_MESSAGE, 0, "Can't allocate bitmap for scaling overview window" ); } rast.BitMap = bm; memset( &bsa, 0, sizeof( bsa ) ); bsa.bsa_SrcX = bsa.bsa_SrcY = 0; bsa.bsa_SrcBitMap = tile; bsa.bsa_SrcWidth = pictdata.xsize; bsa.bsa_SrcHeight = pictdata.ysize; bsa.bsa_XSrcFactor = pictdata.xsize; bsa.bsa_YSrcFactor = pictdata.ysize; bsa.bsa_DestX = 0; bsa.bsa_DestY = 0; bsa.bsa_DestWidth = xsize; bsa.bsa_DestHeight = ysize; bsa.bsa_XDestFactor = xsize; bsa.bsa_YDestFactor = ysize; bsa.bsa_DestBitMap = bm; } if( scaling_needed ) { /* Fill in scaling data for map rendering */ memset( &bsm, 0, sizeof( bsm ) ); bsm.bsa_SrcX = bsm.bsa_SrcY = 0; bsm.bsa_SrcBitMap = tile; bsm.bsa_SrcWidth = pictdata.xsize; bsm.bsa_SrcHeight = pictdata.ysize; bsm.bsa_XSrcFactor = pictdata.xsize; bsm.bsa_YSrcFactor = pictdata.ysize; bsm.bsa_DestWidth = mxsize; bsm.bsa_DestHeight = mysize; bsm.bsa_XDestFactor = mxsize; bsm.bsa_YDestFactor = mysize; bsm.bsa_DestBitMap = rp->BitMap; bsm.bsa_DestY = bsm.bsa_DestX = 0; imgbm = MyAllocBitMap( mxsize, mysize, pictdata.nplanes + amii_extraplanes, MEMF_CLEAR|MEMF_CHIP ); if( imgbm == NULL ) { amii_putstr( WIN_MESSAGE, 0, "Can't allocate scaling bitmap for map window" ); } else bsm.bsa_DestBitMap = imgbm; } /* Go ahead and start dumping the stuff */ for( i=0; iBytesPerRow; for( j = 0; j < pictdata.nplanes + amii_extraplanes; ++j ) { for( k = 0; k < pictdata.ysize; ++k ) { /* For a 16x16 tile, this could just be short assignments, but * this code is generalized to handle any size tile image... */ memcpy( tile->Planes[ j ] + ( ( k * pictdata.ysize ) / 8 ), nodebm->Planes[ j ] + offx + offy + ( nodebm->BytesPerRow * k ), pictdata.ysize/8 ); } } if( !clipping || ( x >= clipx && y >= clipy && x < clipxmax && y < clipymax ) ) { /* scaling is needed, do it */ if( scaling_needed ) { BitMapScale( &bsm ); BltBitMapRastPort( imgbm, 0, 0, rp, amiv_g_nodes[ i ].dstx, amiv_g_nodes[ i ].dsty, mxsize, mysize, 0xc0 ); } else { BltBitMapRastPort( tile, 0, 0, rp, amiv_g_nodes[ i ].dstx, amiv_g_nodes[ i ].dsty, pictdata.xsize, pictdata.ysize, 0xc0 ); } } /* Draw the overview window unless we are scrolling the map raster around */ if( bm && w && reclip != 2 ) { BitMapScale( &bsa ); BltBitMapRastPort( rast.BitMap, 0, 0, w->RPort, w->BorderLeft + amiv_g_nodes[ i ].odstx*xsize, w->BorderTop + amiv_g_nodes[ i ].odsty*ysize, xsize, ysize, 0xc0 ); } } if( imgbm ) MyFreeBitMap( imgbm ); if( bm ) MyFreeBitMap( bm ); #endif /* DISPMAP */ #ifdef OPT_DISPMAP } #endif amii_end_glyphout( WIN_MAP ); /* Clean up */ glyph_node_index = glyph_buffer_index = 0; } /* * Glyph buffering routine. Called instead of WindowPuts(). */ void amiv_lprint_glyph(window,color_index, glyph) winid window; int color_index, glyph; { int base; struct amii_WinDesc *cw; struct Window *w; int curx; int cury; int tbl, icon; register int xoff, yoff; /* Get the real icon index */ if( glyph != NO_GLYPH ) icon = GlyphToIcon( glyph ); if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL ) panic("bad winid in amiv_lprint_glyph: %d", window ); w = cw->win; if( glyph != NO_GLYPH && glyph < 10000) { /* decide on which image has the needed picture */ if( icon <= MAXMONTILE ) { tbl = TBLMONTILE; base = 0; } else if( icon <= MAXOBJTILE ) { tbl = TBLOBJTILE; base = MAXMONTILE+1; } else if( icon <= MAXOTHTILE ) { tbl = TBLOTHTILE; base = MAXOBJTILE+1; } else panic( "Bad icon #%d, glyph #%d, only %d icons known\n", icon, glyph, MAXOTHTILE ); /* Get the relative offset in the page */ /* How many pixels to account for y distance down */ yoff = ((icon-base) / pictdata.across) * pictdata.ysize; /* How many pixels to account for x distance across */ xoff = ((icon-base) % pictdata.across) * pictdata.xsize; } if(glyph >= 10000){ /* Run a single ASCII character out to the rastport right now */ char c= glyph-10000; int xxx,xxy; struct RastPort *rp = w->RPort; Move(rp, xxx=(((cw->curx-clipx)*rp->TxWidth) + w->BorderLeft), xxy=(w->BorderTop + (((cw->cury-clipy)+1)* rp->TxHeight)+1)); Text(rp,&c,1); /* XXX this shouldn't be necessary: */ if(cw->cursx == xxx && cw->cursy == xxy){ cw->wflags &= ~FLMAP_CURSUP; } cw->curx += rp->TxWidth; /* keep things in sync */ return; } if( cw->type == NHW_MAP ) { curx = cw->curx - clipx; cury = cw->cury - clipy; /* See if we're out of glyph nodes */ if(glyph_node_index >= NUMBER_GLYPH_NODES) amiv_flush_glyph_buffer( w ); /* Fill in the node. */ amiv_g_nodes[glyph_node_index].dsty = min( w->BorderTop + (cury * mysize), w->Height - 1 ); #ifdef OPT_DISPMAP if(flags.fast_map){ #endif /* keni */ #ifdef DISPMAP /* display_map() needs byte-aligned destinations, and we don't want to * overwrite the window border. */ amiv_g_nodes[glyph_node_index].dstx = (w->BorderLeft + 8 + (curx * mxsize)) & -8; #endif #ifdef OPT_DISPMAP } else { #endif #if !defined(DISPMAP) || defined(OPT_DISPMAP) amiv_g_nodes[glyph_node_index].dstx = min( w->BorderLeft + (curx * mxsize), w->Width - 1 ); #endif #ifdef OPT_DISPMAP } #endif amiv_g_nodes[glyph_node_index].odsty = cw->cury; amiv_g_nodes[glyph_node_index].odstx = cw->curx; amiv_g_nodes[glyph_node_index].srcx = xoff; amiv_g_nodes[glyph_node_index].srcy = yoff; amiv_g_nodes[glyph_node_index].bitmap = ifftimg[ tbl ]; ++glyph_node_index; } else { /* Do it */ register int j, k, x, y, apen; struct RastPort *rp = w->RPort; x = rp->cp_x - pictdata.xsize - 3; #ifdef OPT_DISPMAP if(flags.fast_map){ #endif #ifdef DISPMAP x &= -8; if(x==0) x = 8; #endif #ifdef OPT_DISPMAP } #endif y = rp->cp_y - pictdata.ysize + 1; if( glyph != NO_GLYPH ) { struct BitMap *bm = ifftimg[ tbl ]; /* 8 bits per byte */ xoff /= 8; yoff *= bm->BytesPerRow; for( j = 0; j < pictdata.nplanes; ++j ) { for( k = 0; k < pictdata.ysize; ++k ) { memcpy( tile->Planes[ j ] + ( ( k * pictdata.ysize ) / 8 ), bm->Planes[ j ] + xoff + yoff + ( bm->BytesPerRow * k ), pictdata.ysize/8 ); } } BltBitMapRastPort( tile, 0, 0, rp, x, y, pictdata.xsize, pictdata.ysize, 0xc0 ); apen = rp->FgPen; SetAPen( rp, flags.amii_dripens[ SHINEPEN ] ); Move( rp, x-1, y + pictdata.ysize ); Draw( rp, x-1, y - 1 ); Draw( rp, x + pictdata.xsize, y - 1 ); SetAPen( rp, flags.amii_dripens[ SHADOWPEN ] ); Move( rp, x + pictdata.xsize, y ); Draw( rp, x + pictdata.xsize, y + pictdata.ysize ); Draw( rp, x, y + pictdata.ysize ); SetAPen( rp, apen ); } else if( x > w->BorderLeft ) { int apen, bpen; apen = rp->FgPen; bpen = rp->BgPen; SetAPen( rp, amii_menuBPen ); SetBPen( rp, amii_menuBPen ); RectFill( rp, x-1, y-1, x + pictdata.xsize, y + pictdata.ysize ); SetAPen( rp, apen ); SetBPen( rp, bpen ); } } } /* * Define some variables which will be used to save context when toggling * back and forth between low level text and console I/O. */ static long xsave, ysave, modesave, apensave, bpensave; static int usecolor; /* * The function is called before any glyphs are driven to the screen. It * removes the cursor, saves internal state of the window, then returns. */ void amiv_start_glyphout(window) winid window; { struct amii_WinDesc *cw; struct Window *w; if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL ) panic( "bad winid %d in start_glyphout()", window ); if( cw->wflags & FLMAP_INGLYPH ) return; if( !(w = cw->win ) ) panic( "bad winid %d, no window ptr set", window ); /* * Save the context of the window */ xsave = w->RPort->cp_x; ysave = w->RPort->cp_y; modesave = w->RPort->DrawMode; apensave = w->RPort->FgPen; bpensave = w->RPort->BgPen; /* * Set the mode, and be done with it */ usecolor = iflags.use_color; iflags.use_color = FALSE; cw->wflags |= FLMAP_INGLYPH; } /* * General cleanup routine -- flushes and restores cursor */ void amii_end_glyphout(window) winid window; { struct amii_WinDesc *cw; struct Window *w; if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL ) panic("bad window id %d in amii_end_glyphout()", window ); if( ( cw->wflags & FLMAP_INGLYPH ) == 0 ) return; cw->wflags &= ~(FLMAP_INGLYPH); if( !(w = cw->win ) ) panic( "bad winid %d, no window ptr set", window ); /* * Clean up whatever is left in the buffer */ iflags.use_color = usecolor; /* * Reset internal data structs */ SetAPen(w->RPort, apensave); SetBPen(w->RPort, bpensave); SetDrMd(w->RPort, modesave); Move(w->RPort, xsave, ysave); } static maze_type=COL_MAZE_BRICK; void SetMazeType(MazeType t) { maze_type=t; } int GlyphToIcon(int glyph) { if(glyph>10000)return glyph; return( glyph2tile[glyph] ); } #endif #ifdef AMII_GRAPHICS # ifdef TESTING /* * Define some stuff for our special glyph drawing routines */ static unsigned short glyph_node_index, glyph_buffer_index; # define NUMBER_GLYPH_NODES 80 # define GLYPH_BUFFER_SIZE 512 # endif /* TESTING */ struct amii_glyph_node { short x; short y; short len; unsigned char bg_color; unsigned char fg_color; char *buffer; }; static struct amii_glyph_node amii_g_nodes[NUMBER_GLYPH_NODES]; static char amii_glyph_buffer[GLYPH_BUFFER_SIZE]; #ifdef TEXTCOLOR /* * Map our amiga-specific colormap into the colormap specified in color.h. * See winami.c for the amiga specific colormap. */ int foreg[AMII_MAXCOLORS] = { 0, 7, 4, 2, 6, 5, 3, 1, 1, 0, 0, 0, 0, 0, 0, 0 }; int backg[AMII_MAXCOLORS] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 7, 4, 1, 6, 5, 3, 1 }; #if 0 #define CLR_BLACK 0 #define CLR_RED 1 #define CLR_GREEN 2 #define CLR_BROWN 3 /* on IBM, low-intensity yellow is brown */ #define CLR_BLUE 4 #define CLR_MAGENTA 5 #define CLR_CYAN 6 #define CLR_GRAY 7 /* low-intensity white */ #define NO_COLOR 8 #define CLR_ORANGE 9 #define CLR_BRIGHT_GREEN 10 #define CLR_YELLOW 11 #define CLR_BRIGHT_BLUE 12 #define CLR_BRIGHT_MAGENTA 13 #define CLR_BRIGHT_CYAN 14 #define CLR_WHITE 15 #define CLR_MAX 16 #endif #endif #ifndef TESTING /* * Begin Revamped Text display routines * * Up until version 3.1, the only method for displaying text on the playing * field was by using the console.device. This was nice for a number of * reasons, the most signifigant of which was a lot of the nuts and bolts was * done for you via escape sequences interpreted by said device. This did * not come without a price however. And that price was speed. It has now * come to a point where the speed has now been deemed unacceptable. * * The following series of routines are designed to drop into the current * nethack display code, using hooks provided for such a measure. It works * on similar principals as the WindowPuts(), buffering I/O internally * until either an explicit flush or internal buffering is exceeded, thereby * forcing the flush. The output (or glyphs) does not go to the * console.device, however. It is driven directly to the rasterport of the * nethack window via the low-level Text() calls, increasing the speed by * a very signifigant factor. */ /* * Routine to simply flush whatever is buffered */ void amii_flush_glyph_buffer( w ) struct Window *w; { short i, x, y; register struct RastPort *rp = w->RPort; /* If nothing is buffered, return before we do anything */ if(glyph_node_index == 0) return; cursor_off( WIN_MAP ); amii_start_glyphout( WIN_MAP ); /* Set up the drawing mode */ SetDrMd( rp, JAM2); /* Go ahead and start dumping the stuff */ for(i=0; iBorderTop + (amii_g_nodes[i].y-2) * rp->TxHeight + rp->TxBaseline + 1; x = amii_g_nodes[i].x * rp->TxWidth + w->BorderLeft; /* Move pens to correct location */ Move( rp, (long)x, (long)y); /* Setup the colors */ SetAPen( rp, (long)amii_g_nodes[i].fg_color); SetBPen( rp, (long)amii_g_nodes[i].bg_color); /* Do it */ Text( rp, amii_g_nodes[i].buffer, amii_g_nodes[i].len); } amii_end_glyphout( WIN_MAP ); /* Clean up */ glyph_node_index = glyph_buffer_index = 0; } void amiga_print_glyph(window,color_index, glyph) winid window; int color_index, glyph; { if( WINVERS_AMIV ) amiv_lprint_glyph(window,color_index, glyph); else amii_lprint_glyph(window,color_index, glyph); } /* * Glyph buffering routine. Called instead of WindowPuts(). */ void amii_lprint_glyph(window,color_index, glyph) winid window; int color_index, glyph; { int fg_color, bg_color; struct amii_WinDesc *cw; struct Window *w; int curx; int cury; if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL ) panic("bad winid in amii_lprint_glyph: %d", window ); w = cw->win; curx=cw->curx; cury=cw->cury; #ifdef TEXTCOLOR fg_color = foreg[color_index]; bg_color = backg[color_index]; #else fg_color = 1; bg_color = 0; #endif /* TEXTCOLOR */ /* See if we have enough character buffer space... */ if(glyph_buffer_index >= GLYPH_BUFFER_SIZE) amii_flush_glyph_buffer( w ); /* * See if we can append it to the current active node of glyph buffer. It * must satisfy the following conditions: * * * background colors are the same, AND * * foreground colors are the same, AND * * they are precisely side by side */ if((glyph_buffer_index != 0) && (fg_color == amii_g_nodes[glyph_node_index-1].fg_color) && (bg_color == amii_g_nodes[glyph_node_index-1].bg_color) && (amii_g_nodes[glyph_node_index-1].x+ amii_g_nodes[glyph_node_index-1].len == curx) && (amii_g_nodes[glyph_node_index-1].y == cury)) { /* * Add it to the end of the buffer */ amii_glyph_buffer[glyph_buffer_index++] = glyph; amii_g_nodes[glyph_node_index-1].len ++; } else { /* See if we're out of glyph nodes */ if(glyph_node_index >= NUMBER_GLYPH_NODES) amii_flush_glyph_buffer( w ); amii_g_nodes[glyph_node_index].len = 1; amii_g_nodes[glyph_node_index].x = curx; amii_g_nodes[glyph_node_index].y = cury; amii_g_nodes[glyph_node_index].fg_color = fg_color; amii_g_nodes[glyph_node_index].bg_color = bg_color; amii_g_nodes[glyph_node_index].buffer = &amii_glyph_buffer[glyph_buffer_index]; amii_glyph_buffer[glyph_buffer_index] = glyph; ++glyph_buffer_index; ++glyph_node_index; } } #endif /* !TESTING */ #ifdef TESTING /* * Define some variables which will be used to save context when toggling * back and forth between low level text and console I/O. */ static long xsave, ysave, modesave, apensave, bpensave; static int usecolor; #endif /* TESTING */ #ifndef TESTING /* * The function is called before any glyphs are driven to the screen. It * removes the cursor, saves internal state of the window, then returns. */ void amii_start_glyphout(window) winid window; { struct amii_WinDesc *cw; struct Window *w; if( ( cw=amii_wins[window] ) == (struct amii_WinDesc *)NULL ) panic( "bad winid %d in start_glyphout()", window ); if( cw->wflags & FLMAP_INGLYPH ) return; if( !(w = cw->win ) ) panic( "bad winid %d, no window ptr set", window ); /* * Save the context of the window */ xsave = w->RPort->cp_x; ysave = w->RPort->cp_y; modesave = w->RPort->DrawMode; apensave = w->RPort->FgPen; bpensave = w->RPort->BgPen; /* * Set the mode, and be done with it */ usecolor = iflags.use_color; iflags.use_color = FALSE; cw->wflags |= FLMAP_INGLYPH; } #endif /* !TESTING */ # if 0 /* * General cleanup routine -- flushes and restores cursor */ void amii_end_glyphout(window) winid window; { struct amii_WinDesc *cw; struct Window *w; if( ( cw = amii_wins[ window ] ) == (struct amii_WinDesc *)NULL ) panic("bad window id %d in amii_end_glyphout()", window ); if( ( cw->wflags & FLMAP_INGLYPH ) == 0 ) return; cw->wflags &= ~(FLMAP_INGLYPH); if( !(w = cw->win ) ) panic( "bad winid %d, no window ptr set", window ); /* * Clean up whatever is left in the buffer */ iflags.use_color = usecolor; /* * Reset internal data structs */ SetAPen(w->RPort, apensave); SetBPen(w->RPort, bpensave); SetDrMd(w->RPort, modesave); Move(w->RPort, xsave, ysave); } # endif #endif #ifndef TESTING # ifdef OPT_DISPMAP /* don't use dispmap unless x & y are 8,16,24,32,48 and equal */ void dispmap_sanity(){ if( mxsize != mysize || dispmap_sanity1(mxsize) || dispmap_sanity1(mysize)){ flags.fast_map = 0; } } int dispmap_sanity1(x) int x; { static unsigned char valid[] = {8,16,24,32,48,0}; return !!strchr(valid,x); } # endif /* OPT_DISPMAP */ #endif /* TESTING */ nethack-3.4.3/sys/amiga/windefs.h0100644000000000000000000001144507764735041015363 0ustar rootroot/* SCCS Id: @(#)windefs.h 3.1 93/04/02 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include #if !defined(_DCC) && !defined(__GNUC__) #include #endif #include #include #include #include #include #include #include #include #include #include #include /* stddef.h is included in the precompiled version of hack.h . If we include * it here normally (through string.h) we'll get an "illegal typedef" later * on. This is the easiest way I can think of to fix it without messing * around with the rest of the #includes. --AMC */ #if defined(_DCC) && !defined(HACK_H) # define ptrdiff_t ptrdiff_t_ # define size_t size_t_ # define wchar_t wchar_t_ #endif #include #undef strcmpi #include #include #if defined(_DCC) && !defined(HACK_H) # undef ptrdiff_t # undef size_t # undef wchar_T #endif #ifdef IDCMP_CLOSEWINDOW # ifndef INTUI_NEW_LOOK # define INTUI_NEW_LOOK # endif #endif #ifndef HACK_H #include "hack.h" #endif #include "wintype.h" #include "winami.h" #include "func_tab.h" #ifndef CLIPPING CLIPPING must be defined for the AMIGA version #endif #undef LI #undef CO /*#define TOPL_GETLINE /* Don't use a window for getlin() */ /*#define WINDOW_YN /* Use a window for y/n questions */ #ifdef AZTEC_C #include #else #ifdef _DCC #include #include #include #include #include #include #else #include #include #include #include #include #include #include #endif /* kludge - see amirip for why */ # undef red # undef green # undef blue #ifdef _DCC # include #else # include #endif #ifdef _DCC # define __asm /* DICE doesn't like __asm */ #endif #ifndef __SASC_60 #undef index # define index strchr #endif #ifdef _DCC #include #else #include #endif #endif #ifdef SHAREDLIB #include "NH:sys/amiga/lib/libmacs.h" #endif #ifdef INTUI_NEW_LOOK #include #endif #define WINVERS_AMII (strcmp("amii",windowprocs.name)==0) #define WINVERS_AMIV (strcmp("amitile",windowprocs.name)==0) #define WINVERS_AMIT (strcmp("amitty",windowprocs.name)==0) /* cw->data[x] contains 2 characters worth of special information. These * characters are stored at the offsets as described here. */ #define VATTR 0 /* Video attribute is in this slot */ #define SEL_ITEM 1 /* If this is a select item, slot is 1 else 0 */ #define SOFF 2 /* The string starts here. */ #undef NULL #define NULL 0L /* * Versions we need of various libraries. We can't use LIBRARY_VERSION * as defined in because some of the libraries we need * don't have that version number in the 1.2 ROM. */ #define LIBRARY_FONT_VERSION 34L #define LIBRARY_TILE_VERSION 37L /* These values are just sorta suggestions in use, but are minimum requirements * in reality... */ #define WINDOWHEIGHT 192 #define SCREENHEIGHT 200 #define WIDTH 640 /* This character is a solid block (cursor) in Hack.font */ #define CURSOR_CHAR 0x90 #define FONTHEIGHT 8 #define FONTWIDTH 8 #define FONTBASELINE 8 #define MAPFTWIDTH 8 #define MAPFTHEIGHT 8 #define MAPFTBASELN 6 /* If Compiling with the "New Look", redefine these now */ #ifdef INTUI_NEW_LOOK #define NewWindow ExtNewWindow #define NewScreen ExtNewScreen #endif #define SIZEOF_DISKNAME 8 #define CSI '\x9b' #define NO_CHAR -1 #define RAWHELP 0x5F /* Rawkey code of the HELP key */ #define C_BLACK 0 #define C_WHITE 1 #define C_BROWN (WINVERS_AMIV ? 11 : 2) #define C_CYAN (WINVERS_AMIV ? 2 : 3) #define C_GREEN (WINVERS_AMIV ? 5 : 4) #define C_MAGENTA (WINVERS_AMIV ? 10 : 5) #define C_BLUE (WINVERS_AMIV ? 4 : 6) #define C_RED 7 #define C_ORANGE 3 #define C_GREY 6 #define C_LTGREEN 8 #define C_YELLOW 9 #define C_GREYBLUE 12 #define C_LTBROWN 13 #define C_LTGREY 14 #define C_PEACH 15 /* Structure describing tile files */ struct PDAT { long nplanes; /* Depth of images */ long pbytes; /* Bytes in a plane of data */ long across; /* Number of tiles across */ long down; /* Number of tiles down */ long npics; /* Number of pictures in this file */ long xsize; /* X-size of a tile */ long ysize; /* Y-size of a-tile */ }; #undef MAXCOLORS #define MAXCOLORS 256 nethack-3.4.3/sys/amiga/winext.h0100644000000000000000000000763107764735041015244 0ustar rootroot/* SCCS Id: @(#)winext.h 3.1 2000/01/12 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ extern int reclip; #ifdef CLIPPING extern int clipping; extern int clipx; extern int clipy; extern int clipxmax; extern int clipymax; extern int xclipbord, yclipbord; #endif extern int CO; extern int LI; extern int scrollmsg; extern int alwaysinvent; #ifndef SHAREDLIB extern unsigned short amii_defpens[ 20 ]; extern struct amii_DisplayDesc *amiIDisplay; /* the Amiga Intuition descriptor */ extern struct window_procs amii_procs; extern struct window_procs amiv_procs; extern unsigned short amii_initmap[ AMII_MAXCOLORS ]; extern unsigned short amiv_init_map[ AMII_MAXCOLORS ]; extern unsigned short amii_init_map[ AMII_MAXCOLORS ]; extern int bigscreen; extern int amii_numcolors; extern long amii_scrnmode; extern winid amii_rawprwin; extern struct Screen *HackScreen; extern char Initialized; /* These have already been defined elsewhere (and some are conflicting) * ... going ... going once ... going twice .... * extern const char *roles[]; * extern struct Library *ConsoleDevice; * extern char toplines[ TBUFSZ ]; * extern NEARDATA winid WIN_MESSAGE; * extern NEARDATA winid WIN_MAP; * extern NEARDATA winid WIN_STATUS; * extern NEARDATA winid WIN_INVEN; * extern winid WIN_OVER; * extern struct GfxBase *GfxBase; * extern struct Library *DiskfontBase; * extern struct IntuitionBase *IntuitionBase; * extern struct Library *LayersBase; */ extern int amii_msgAPen; extern int amii_msgBPen; extern int amii_statAPen; extern int amii_statBPen; extern int amii_menuAPen; extern int amii_menuBPen; extern int amii_textAPen; extern int amii_textBPen; extern int amii_otherAPen; extern int amii_otherBPen; #else extern WinamiBASE *WinamiBase; #endif /* All kinds of shared stuff */ extern struct TextAttr Hack160; extern struct TextAttr Hack40; extern struct TextAttr Hack80; extern struct TextAttr TextsFont13; extern struct Window *pr_WindowPtr; extern struct Menu HackMenu[]; extern struct Menu *MenuStrip; extern struct NewMenu GTHackMenu[]; extern APTR *VisualInfo; extern unsigned char KbdBuffered; extern struct TextFont *TextsFont; extern struct TextFont *HackFont; extern struct IOStdReq ConsoleIO; extern struct MsgPort *HackPort; extern int txwidth, txheight, txbaseline; #ifdef SUPERBITMAP_MAP extern struct BitMap amii_vbm; #endif /* This gadget data is replicated for menu/text windows... */ extern struct PropInfo PropScroll; extern struct Image Image1; extern struct Gadget MenuScroll; /* This gadget is for the message window... */ extern struct PropInfo MsgPropScroll; extern struct Image MsgImage1; extern struct Gadget MsgScroll; extern struct TagItem tags[]; extern struct win_setup { struct NewWindow newwin; UWORD offx,offy,maxrow,rows,maxcol,cols; /* CHECK TYPES */ } new_wins[]; extern UWORD scrnpens[]; /* The last Window event is stored here for reference. */ extern WEVENT lastevent; extern const char winpanicstr[]; extern struct TagItem scrntags[]; extern struct NewScreen NewHackScreen; extern int topl_addspace; extern char spaces[ 76 ]; extern int wincnt; /* # of nh windows opened */ extern struct Rectangle lastinvent, lastmsg; typedef struct { UWORD w, h; WORD x, y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE reserved1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; } BitMapHeader; typedef enum {COL_MAZE_BRICK,COL_MAZE_STONE,COL_MAZE_HEAT,COL_MAZE_WOOD} MazeType; extern struct PDAT pictdata; extern struct Hook fillhook; extern struct TagItem wintags[]; #ifndef SHAREDLIB #ifndef __GNUC__ void __asm LayerFillHook( register __a0 struct Hook *hk, register __a2 struct RastPort *rp, register __a1 struct FillParams *fp ); #else #ifdef __PPC__ struct EmulLibEntry LayerFillHook; #else void LayerFillHook(void); #endif #endif #endif extern int mxsize, mysize; nethack-3.4.3/sys/amiga/winfuncs.c0100644000000000000000000016531707764735041015563 0ustar rootroot/* SCCS Id: @(#)winfuncs.c 3.1 2000/01/12 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #include "patchlevel.h" extern struct TagItem scrntags[]; static BitMapHeader amii_bmhd; static void cursor_common(struct RastPort *, int, int); #ifdef CLIPPING int CO, LI; /* Changing clipping region, skip clear of screen in overview window. */ int reclip; /* Must be set to at least two or you will get stuck! */ int xclipbord = 4, yclipbord = 2; #endif int mxsize, mysize; struct Rectangle amii_oldover; struct Rectangle amii_oldmsg; extern struct TextFont *RogueFont; int amii_msgAPen; int amii_msgBPen; int amii_statAPen; int amii_statBPen; int amii_menuAPen; int amii_menuBPen; int amii_textAPen; int amii_textBPen; int amii_otherAPen; int amii_otherBPen; long amii_libvers = LIBRARY_FONT_VERSION; void ami_wininit_data( void ) { extern unsigned short amii_init_map[ AMII_MAXCOLORS ]; extern unsigned short amiv_init_map[ AMII_MAXCOLORS ]; if( !WINVERS_AMIV ) { # ifdef TEXTCOLOR amii_numcolors = 8; # else amii_numcolors = 4; # endif amii_defpens[ 0 ] = C_BLACK; /* DETAILPEN */ amii_defpens[ 1 ] = C_BLUE; /* BLOCKPEN */ amii_defpens[ 2 ] = C_BROWN; /* TEXTPEN */ amii_defpens[ 3 ] = C_WHITE; /* SHINEPEN */ amii_defpens[ 4 ] = C_BLUE; /* SHADOWPEN */ amii_defpens[ 5 ] = C_CYAN; /* FILLPEN */ amii_defpens[ 6 ] = C_WHITE; /* FILLTEXTPEN */ amii_defpens[ 7 ] = C_CYAN; /* BACKGROUNDPEN */ amii_defpens[ 8 ] = C_RED; /* HIGHLIGHTTEXTPEN */ amii_defpens[ 9 ] = C_WHITE; /* BARDETAILPEN */ amii_defpens[ 10 ] = C_CYAN; /* BARBLOCKPEN */ amii_defpens[ 11 ] = C_BLUE; /* BARTRIMPEN */ amii_defpens[ 12 ] = (unsigned short) ~0; amii_msgAPen = C_WHITE; amii_msgBPen = C_BLACK; amii_statAPen = C_WHITE; amii_statBPen = C_BLACK; amii_menuAPen = C_WHITE; amii_menuBPen = C_BLACK; amii_textAPen = C_WHITE; amii_textBPen = C_BLACK; amii_otherAPen = C_RED; amii_otherBPen = C_BLACK; mxsize = 8; mysize = 8; amii_libvers = LIBRARY_FONT_VERSION; memcpy( amii_initmap, amii_init_map, sizeof( amii_initmap ) ); } else { mxsize = 16; mysize = 16; amii_numcolors = 16; amii_defpens[ 0 ] = C_BLACK; /* DETAILPEN */ amii_defpens[ 1 ] = C_WHITE; /* BLOCKPEN */ amii_defpens[ 2 ] = C_BLACK; /* TEXTPEN */ amii_defpens[ 3 ] = C_CYAN; /* SHINEPEN */ amii_defpens[ 4 ] = C_BLUE; /* SHADOWPEN */ amii_defpens[ 5 ] = C_GREYBLUE; /* FILLPEN */ amii_defpens[ 6 ] = C_LTGREY; /* FILLTEXTPEN */ amii_defpens[ 7 ] = C_GREYBLUE; /* BACKGROUNDPEN */ amii_defpens[ 8 ] = C_RED; /* HIGHLIGHTTEXTPEN */ amii_defpens[ 9 ] = C_WHITE; /* BARDETAILPEN */ amii_defpens[ 10] = C_GREYBLUE; /* BARBLOCKPEN */ amii_defpens[ 11] = C_BLUE; /* BARTRIMPEN */ amii_defpens[ 12] = (unsigned short) ~0; amii_msgAPen = C_WHITE; amii_msgBPen = C_GREYBLUE; amii_statAPen = C_WHITE; amii_statBPen = C_GREYBLUE; amii_menuAPen = C_BLACK; amii_menuBPen = C_LTGREY; amii_textAPen = C_BLACK; amii_textBPen = C_LTGREY; amii_otherAPen = C_RED; amii_otherBPen = C_BLACK; amii_libvers = LIBRARY_TILE_VERSION; memcpy( amii_initmap, amiv_init_map, sizeof( amii_initmap ) ); } #ifdef OPT_DISPMAP dispmap_sanity(); #endif memcpy(flags.amii_dripens,amii_defpens,sizeof(flags.amii_dripens)); } # ifdef INTUI_NEW_LOOK struct Hook SM_FilterHook; struct Hook fillhook; struct TagItem wintags[] = { { WA_BackFill, (ULONG)&fillhook }, { WA_PubScreenName, (ULONG)"NetHack" }, { TAG_END, 0 }, }; # endif void amii_destroy_nhwindow(win) /* just hide */ register winid win; { int i; int type; register struct amii_WinDesc *cw; if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL ) { panic(winpanicstr,win,"destroy_nhwindow"); } if( WINVERS_AMIV ) { if( cw->type == NHW_MAP ) { /* If inventory is up, close it now, it will be freed later */ if( alwaysinvent && WIN_INVEN != WIN_ERR && amii_wins[ WIN_INVEN ] && amii_wins[ WIN_INVEN ]->win ) { dismiss_nhwindow( WIN_INVEN ); } /* Tear down overview window if it is up */ if( WIN_OVER != WIN_ERR ) { amii_destroy_nhwindow( WIN_OVER ); WIN_OVER = WIN_ERR; } } else if( cw->type == NHW_OVER ) { struct Window *w = amii_wins[ WIN_OVER ]->win; amii_oldover.MinX = w->LeftEdge; amii_oldover.MinY = w->TopEdge; amii_oldover.MaxX = w->Width; amii_oldover.MaxY = w->Height; if( WIN_MESSAGE != WIN_ERR && amii_wins[ WIN_MESSAGE ] ) { w = amii_wins[ WIN_MESSAGE ]->win; amii_oldmsg.MinX = w->LeftEdge; amii_oldmsg.MinY = w->TopEdge; amii_oldmsg.MaxX = w->Width; amii_oldmsg.MaxY = w->Height; SizeWindow( amii_wins[ WIN_MESSAGE ]->win, (amiIDisplay->xpix - amii_wins[ WIN_MESSAGE ]->win->LeftEdge) - amii_wins[ WIN_MESSAGE ]->win->Width, 0 ); } } } /* Tear down the Intuition stuff */ dismiss_nhwindow(win); type = cw->type; if( cw->resp ) { free( cw->resp ); cw->resp = NULL; } if( cw->canresp ) { free( cw->canresp ); cw->canresp = NULL; } if( cw->morestr ) { free( cw->morestr ); cw->morestr = NULL; } if( cw->hook ) { free( cw->hook ); cw->hook = NULL; } if( cw->data && ( cw->type == NHW_MESSAGE || cw->type == NHW_MENU || cw->type == NHW_TEXT ) ) { for( i = 0; i < cw->maxrow; ++i ) { if( cw->data[ i ] ) free( cw->data[ i ] ); } free( cw->data ); } free( cw ); amii_wins[win] = NULL; /* Set globals to WIN_ERR for known one-of-a-kind windows. */ if( win == WIN_MAP) WIN_MAP = WIN_ERR; else if( win == WIN_STATUS) WIN_STATUS = WIN_ERR; else if( win == WIN_MESSAGE) WIN_MESSAGE = WIN_ERR; else if( win == WIN_INVEN) WIN_INVEN = WIN_ERR; } #ifdef INTUI_NEW_LOOK struct FillParams { struct Layer *layer; struct Rectangle bounds; WORD offsetx; WORD offsety; }; #ifdef __GNUC__ #ifdef __PPC__ void PPC_LayerFillHook(void); struct EmulLibEntry LayerFillHook = {TRAP_LIB, 0, (void (*)(void)) PPC_LayerFillHook}; void PPC_LayerFillHook(void) { struct Hook *hk = (struct Hook*)REG_A0; struct RastPort *rp = (struct RastPort *)REG_A2; struct FillParams *fp = (struct FillParams*)REG_A1; #else void LayerFillHook(void) { register struct Hook *hk asm("a0"); register struct RastPort *rp asm("a2"); register struct FillParams *fp asm("a1"); #endif #else void #ifndef _DCC __interrupt #endif __saveds __asm LayerFillHook( register __a0 struct Hook *hk, register __a2 struct RastPort *rp, register __a1 struct FillParams *fp ) { #endif register long x, y, xmax, ymax; register int apen; struct RastPort rptmp; memcpy(&rptmp, rp, sizeof(struct RastPort)); rptmp.Layer = NULL; switch( (int)hk->h_Data ) { case NHW_STATUS: apen = amii_statBPen; break; case NHW_MESSAGE: apen = amii_msgBPen; break; case NHW_TEXT: apen = amii_textBPen; break; case NHW_MENU: apen = amii_menuBPen; break; case -2: apen = amii_otherBPen; break; case NHW_BASE: case NHW_MAP: case NHW_OVER: default: apen = C_BLACK; break; } x = fp->bounds.MinX; y = fp->bounds.MinY; xmax = fp->bounds.MaxX; ymax = fp->bounds.MaxY; SetAPen(&rptmp, apen); SetBPen(&rptmp, apen); SetDrMd(&rptmp, JAM2); RectFill(&rptmp, x, y, xmax, ymax); } #endif amii_create_nhwindow(type) register int type; { register struct Window *w = NULL; register struct NewWindow *nw = NULL; register struct amii_WinDesc *wd = NULL; struct Window *mapwin = NULL, *stwin = NULL, *msgwin = NULL; register int newid; int maph, stath, scrfontysize; scrfontysize = HackScreen->Font->ta_YSize; /* * Initial mapwindow height, this might change later in tilemode * and low screen */ maph = ( 21 * mxsize ) + 2 + (bigscreen ? HackScreen->WBorTop + HackScreen->WBorBottom + scrfontysize + 1 : 0); /* Status window height, avoids having to calculate many times */ stath = txheight * 2 + 2 + (WINVERS_AMIV || bigscreen ? HackScreen->WBorTop + HackScreen->WBorBottom + ( bigscreen ? scrfontysize + 1 : 0 ) : 0); if( WIN_STATUS != WIN_ERR && amii_wins[ WIN_STATUS ] ) stwin = amii_wins[ WIN_STATUS ]->win; if( WIN_MESSAGE != WIN_ERR && amii_wins[ WIN_MESSAGE ] ) msgwin = amii_wins[ WIN_MESSAGE ]->win; if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) mapwin = amii_wins[ WIN_MAP ]->win; /* Create Port anytime that we need it */ if( HackPort == NULL ) { HackPort = CreateMsgPort(); if( !HackPort ) panic( "no memory for msg port" ); } nw = &new_wins[ type ].newwin; nw->Width = amiIDisplay->xpix; nw->Screen = HackScreen; if( WINVERS_AMIV ) { nw->DetailPen = C_WHITE; nw->BlockPen = C_GREYBLUE; } else { nw->DetailPen = C_WHITE; nw->BlockPen = C_BLACK; } if ( type == NHW_BASE ) { nw->LeftEdge = 0; nw->TopEdge = HackScreen->BarHeight+1; nw->Width = HackScreen->Width; nw->Height = HackScreen->Height - nw->TopEdge; } else if( !WINVERS_AMIV && type == NHW_MAP ) { nw->LeftEdge = 0; nw->Height = maph; if( msgwin && stwin ) { nw->TopEdge = stwin->TopEdge - maph; } else { panic( "msgwin and stwin must open before map" ); } if (nw->TopEdge < 0) panic( "Too small screen to fit map" ); } else if( type == NHW_MAP && WINVERS_AMIV ) { struct Window *w; w = amii_wins[ WIN_MESSAGE ]->win; nw->LeftEdge = 0; nw->TopEdge = w->TopEdge + w->Height; nw->Width = amiIDisplay->xpix - nw->LeftEdge; w = amii_wins[ WIN_STATUS ]->win; nw->Height = w->TopEdge - nw->TopEdge; nw->MaxHeight = 0xffff; nw->MaxWidth = 0xffff; if( nw->TopEdge + nw->Height > amiIDisplay->ypix - 1 ) nw->Height = amiIDisplay->ypix - nw->TopEdge - 1; } else if( type == NHW_STATUS ) { if( !WINVERS_AMIV && ( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) ) w = amii_wins[ WIN_MAP ]->win; else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] ) w = amii_wins[ WIN_BASE ]->win; else panic( "No window to base STATUS location from" ); nw->Height = stath; nw->TopEdge = amiIDisplay->ypix - nw->Height; nw->LeftEdge = w->LeftEdge; if( nw->LeftEdge + nw->Width >= amiIDisplay->xpix ) nw->LeftEdge = 0; if( nw->Width >= amiIDisplay->xpix - nw->LeftEdge ) nw->Width = amiIDisplay->xpix - nw->LeftEdge; } else if( WINVERS_AMIV && type == NHW_OVER ) { nw->Flags |= WINDOWSIZING|WINDOWDRAG|WINDOWCLOSE; nw->IDCMPFlags |= CLOSEWINDOW; /* Bring up window as half the width of the message window, and make * the message window change to one half the width... */ if( amii_oldover.MaxX != 0 ) { nw->LeftEdge = amii_oldover.MinX; nw->TopEdge = amii_oldover.MinY; nw->Width = amii_oldover.MaxX; nw->Height = amii_oldover.MaxY; ChangeWindowBox( amii_wins[ WIN_MESSAGE ]->win, amii_oldmsg.MinX, amii_oldmsg.MinY, amii_oldmsg.MaxX, amii_oldmsg.MaxY ); } else { nw->LeftEdge = (amii_wins[ WIN_MESSAGE ]->win->Width*4)/9; nw->TopEdge = amii_wins[ WIN_MESSAGE ]->win->TopEdge; nw->Width = amiIDisplay->xpix - nw->LeftEdge; nw->Height = amii_wins[ WIN_MESSAGE ]->win->Height; SizeWindow( amii_wins[ WIN_MESSAGE ]->win, nw->LeftEdge - amii_wins[ WIN_MESSAGE ]->win->Width, 0 ); } } else if( type == NHW_MESSAGE ) { if( !WINVERS_AMIV && ( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) ) w = amii_wins[ WIN_MAP ]->win; else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] ) w = amii_wins[ WIN_BASE ]->win; else panic( "No window to base STATUS location from" ); nw->TopEdge = bigscreen ? HackScreen->BarHeight+1 : 0; /* Assume highest possible message window */ nw->Height = HackScreen->Height - nw->TopEdge - maph - stath; /* In tilemode we can cope with this */ if (WINVERS_AMIV && nw->Height < 0) nw->Height = 0; /* If in fontmode messagewindow is too small, open it with 3 lines and overlap it with map */ if (nw->Height < txheight+2) { nw->Height = txheight*4 + 3 + HackScreen->WBorTop + HackScreen->WBorBottom; } if ((nw->Height-2)/txheight < 3) { scrollmsg = 0; nw->Title = 0; } else { nw->FirstGadget = &MsgScroll; nw->Flags |= WINDOWSIZING|WINDOWDRAG; nw->Flags &= ~BORDERLESS; if( WINVERS_AMIV || nw->Height == 0) { if( WINVERS_AMIV ) { nw->Height = TextsFont->tf_YSize + HackScreen->WBorTop + 3 + HackScreen->WBorBottom; if( bigscreen ) nw->Height += ( txheight * 6 ); else nw->Height += ( txheight * 3 ); } else { nw->Height = HackScreen->Height - nw->TopEdge - stath - maph; } } } /* Do we have room for larger message window ? * This is possible if we can show full height map in tile * mode with default scaling. */ if (nw->Height + stath + maph < HackScreen->Height - nw->TopEdge ) nw->Height = HackScreen->Height - nw->TopEdge - 1 - maph - stath; #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { MsgPropScroll.Flags |= PROPNEWLOOK; PropScroll.Flags |= PROPNEWLOOK; } #endif } nw->IDCMPFlags |= MENUPICK; /* Check if there is "Room" for all this stuff... */ if( ( WINVERS_AMIV || bigscreen ) && type != NHW_BASE ) { nw->Flags &= ~( BORDERLESS | BACKDROP ); if( WINVERS_AMIV ) { if( type == NHW_STATUS ) { nw->Flags &= ~( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING ); nw->IDCMPFlags &= ~NEWSIZE; } else { nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT | WINDOWSIZING ); nw->IDCMPFlags |= NEWSIZE; } } else { if( HackScreen->Width < 657 ) { nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH ); } else { nw->Flags |= ( WINDOWDRAG | WINDOWDEPTH | SIZEBRIGHT ); } } } if ( WINVERS_AMII && type == NHW_MAP ) nw->Flags &= ~WINDOWSIZING; if ( type == NHW_MESSAGE && scrollmsg ) { nw->Flags |= WINDOWDRAG|WINDOWDEPTH|SIZEBRIGHT|WINDOWSIZING; nw->Flags &= ~BORDERLESS; } /* No titles on a hires only screen except for messagewindow */ if( !(WINVERS_AMIV && type == NHW_MAP) && !bigscreen && type != NHW_MESSAGE ) nw->Title = 0; wd = (struct amii_WinDesc *)alloc(sizeof(struct amii_WinDesc)); memset( wd, 0, sizeof( struct amii_WinDesc ) ); /* Both, since user may have changed the pen settings so respect those */ if( WINVERS_AMII || WINVERS_AMIV ) { /* Special backfill for these types of layers */ switch( type ) { case NHW_MESSAGE: case NHW_STATUS: case NHW_TEXT: case NHW_MENU: case NHW_BASE: case NHW_OVER: case NHW_MAP: if( wd ) { #ifdef __GNUC__ fillhook.h_Entry = (void *)&LayerFillHook; #else fillhook.h_Entry = (ULONG(*)())LayerFillHook; #endif fillhook.h_Data = (void *)type; fillhook.h_SubEntry = 0; wd->hook = alloc( sizeof( fillhook ) ); memcpy( wd->hook, &fillhook, sizeof( fillhook ) ); memcpy( wd->wintags, wintags, sizeof( wd->wintags) ); wd->wintags[0].ti_Data = (long)wd->hook; nw->Extension = (void *)wd->wintags; } break; } } /* Don't open MENU or TEXT windows yet */ if( type == NHW_MENU || type == NHW_TEXT ) w = NULL; else w=OpenShWindow( (void *)nw ); if( w == NULL && type != NHW_MENU && type != NHW_TEXT ) { char buf[ 100 ]; sprintf( buf, "nw type (%d) dims l: %d, t: %d, w: %d, h: %d", type, nw->LeftEdge, nw->TopEdge, nw->Width, nw->Height ); raw_print( buf ); panic("bad openwin %d",type); } /* Check for an empty slot */ for(newid = 0; newid wincnt ) wincnt = newid; /* Do common initialization */ amii_wins[newid] = wd; wd->newwin = NULL; wd->win = w; wd->type = type; wd->wflags = 0; wd->active = FALSE; wd->curx=wd->cury = 0; wd->resp = wd->canresp = wd->morestr = 0; /* CHECK THESE */ wd->maxrow = new_wins[type].maxrow; wd->maxcol = new_wins[type].maxcol; if( type != NHW_TEXT && type != NHW_MENU ) { if( TextsFont && ( type == NHW_MESSAGE || type == NHW_STATUS ) ) { SetFont(w->RPort, TextsFont); txheight = w->RPort->TxHeight; txwidth = w->RPort->TxWidth; txbaseline = w->RPort->TxBaseline; if( type == NHW_MESSAGE ) { if (scrollmsg ) { if( WINVERS_AMIV ) { WindowLimits( w, 100, w->BorderTop + w->BorderBottom + ((txheight+1)*2) + 1, 0, 0 ); } else { WindowLimits( w, w->Width, w->BorderTop + w->BorderBottom + ((txheight+1)*2) + 1, 0, 0 ); } } else { WindowLimits( w, w->Width, w->BorderTop + w->BorderBottom + txheight + 2, 0, 0 ); } } } if ( type != NHW_MAP) { SetFont(w->RPort, TextsFont); } #ifdef HACKFONT else if( HackFont ) SetFont(w->RPort, HackFont); #endif } /* Text and menu windows are not opened yet */ if( w ) { wd->rows = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / w->RPort->TxHeight; wd->cols = ( w->Width - w->BorderLeft - w->BorderRight - 2 ) / w->RPort->TxWidth; } /* Okay, now do the individual type initialization */ switch(type) { /* History lines for MESSAGE windows are stored in cw->data[?]. * maxcol and maxrow are used as cursors. maxrow is the count * of the number of history lines stored. maxcol is the cursor * to the last line that was displayed by ^P. */ case NHW_MESSAGE: SetMenuStrip(w, MenuStrip); MsgScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; iflags.msg_history = wd->rows*10; if (iflags.msg_history < 40) iflags.msg_history = 40; if (iflags.msg_history > 400) iflags.msg_history = 400; iflags.window_inited=TRUE; wd->data = (char **)alloc( iflags.msg_history*sizeof( char * ) ); memset( wd->data, 0, iflags.msg_history * sizeof( char * ) ); wd->maxrow = wd->maxcol = 0; /* Indicate that we have not positioned the cursor yet */ wd->curx = -1; break; /* A MENU contains a list of lines in wd->data[?]. These * lines are created in amii_putstr() by reallocating the size * of wd->data to hold enough (char *)'s. wd->rows is the * number of (char *)'s allocated. wd->maxrow is the number * used. wd->maxcol is used to track how wide the menu needs * to be. wd->resp[x] contains the characters that correspond * to selecting wd->data[x]. wd->resp[x] corresponds to * wd->data[x] for any x. Elements of wd->data[?] that are not * valid selections have the corresponding element of * wd->resp[] set to a value of '\01'; i.e. a ^A which is * not currently a valid keystroke for responding to any * MENU or TEXT window. */ case NHW_MENU: MenuScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; wd->resp=(char*)alloc(256); wd->resp[0]=0; wd->rows = wd->maxrow = 0; wd->cols = wd->maxcol = 0; wd->data = NULL; break; /* See the explanation of MENU above. Except, wd->resp[] is not * used for TEXT windows since there is no selection of a * a line performed/allowed. The window is always full * screen width. */ case NHW_TEXT: MenuScroll.TopEdge = HackScreen->WBorTop + scrfontysize + 1; wd->rows = wd->maxrow = 0; wd->cols = wd->maxcol = amiIDisplay->cols; wd->data = NULL; wd->morestr = NULL; break; /* The status window has only two lines. These are stored in * wd->data[], and here we allocate the space for them. */ case NHW_STATUS: SetMenuStrip(w, MenuStrip); /* wd->cols is the number of characters which fit across the * screen. */ wd->data=(char **)alloc(3*sizeof(char *)); wd->data[0] = (char *)alloc(wd->cols + 10); wd->data[1] = (char *)alloc(wd->cols + 10); wd->data[2] = NULL; break; /* NHW_OVER does not use wd->data[] or the other text * manipulating members of the amii_WinDesc structure. */ case NHW_OVER: SetMenuStrip(w, MenuStrip); break; /* NHW_MAP does not use wd->data[] or the other text * manipulating members of the amii_WinDesc structure. */ case NHW_MAP: SetMenuStrip(w, MenuStrip); if( WINVERS_AMIV ) { CO = (w->Width-w->BorderLeft-w->BorderRight)/mxsize; LI = (w->Height-w->BorderTop-w->BorderBottom)/mysize; amii_setclipped(); SetFont( w->RPort, RogueFont); SetAPen( w->RPort, C_WHITE); /* XXX not sufficient */ SetBPen( w->RPort, C_BLACK); SetDrMd( w->RPort, JAM2); } else { if( HackFont ) SetFont( w->RPort, HackFont ); } break; /* The base window must exist until CleanUp() deletes it. */ case NHW_BASE: SetMenuStrip(w, MenuStrip); /* Make our requesters come to our screen */ { register struct Process *myProcess = (struct Process *) FindTask(NULL); pr_WindowPtr = (struct Window *)(myProcess->pr_WindowPtr); myProcess->pr_WindowPtr = (APTR) w; } /* Need this for RawKeyConvert() */ ConsoleIO.io_Data = (APTR) w; ConsoleIO.io_Length = sizeof( struct Window ); ConsoleIO.io_Message.mn_ReplyPort = CreateMsgPort(); if( OpenDevice("console.device", -1L, (struct IORequest *) &ConsoleIO, 0L) != 0) { Abort(AG_OpenDev | AO_ConsoleDev); } ConsoleDevice = (struct Library *) ConsoleIO.io_Device; KbdBuffered = 0; #ifdef HACKFONT if( TextsFont ) SetFont( w->RPort, TextsFont ); else if( HackFont ) SetFont( w->RPort, HackFont ); #endif txwidth = w->RPort->TxWidth; txheight = w->RPort->TxHeight; txbaseline = w->RPort->TxBaseline; break; default: panic("bad create_nhwindow( %d )\n",type); return WIN_ERR; } return( newid ); } #ifdef __GNUC__ #ifdef __PPC__ int PPC_SM_Filter(void); struct EmulLibEntry SM_Filter = {TRAP_LIB, 0, (int (*)(void)) PPC_SM_Filter}; int PPC_SM_Filter(void) { struct Hook *hk = (struct Hook*)REG_A0; ULONG modeID = (ULONG)REG_A1; struct ScreenModeRequester *smr = (struct ScreenModeRequester *)REG_A2; #else int SM_Filter(void) { register struct Hook *hk asm("a0"); register ULONG modeID asm("a1"); register struct ScreenModeRequester *smr asm("a2"); #endif #else int #ifndef _DCC __interrupt #endif __saveds __asm SM_Filter( register __a0 struct Hook *hk, register __a1 ULONG modeID, register __a2 struct ScreenModeRequester *smr) { #endif struct DimensionInfo dims; struct DisplayInfo disp; DisplayInfoHandle handle; handle = FindDisplayInfo(modeID); if (handle) { GetDisplayInfoData(handle, (char *)&dims, sizeof(dims), DTAG_DIMS, modeID); GetDisplayInfoData(handle, (char *)&disp, sizeof(disp), DTAG_DISP, modeID); if (!disp.NotAvailable && dims.MaxDepth <= 8 && dims.StdOScan.MaxX >= WIDTH-1 && dims.StdOScan.MaxY >= SCREENHEIGHT-1) { return 1; } } return 0; } /* Initialize the windowing environment */ void amii_init_nhwindows(argcp,argv) int *argcp; char **argv; { int i; struct Screen *wbscr; int forcenobig = 0; if( HackScreen ) panic( "init_nhwindows() called twice", 0 ); /* run args & set bigscreen from -L(1)/-l(-1) */ { int lclargc = *argcp; int t; char **argv_in = argv; char **argv_out = argv; for(t=1;t<=lclargc;t++){ if(!strcmp("-L",*argv_in) || !strcmp("-l",*argv_in)){ bigscreen = (*argv_in[1]=='l') ? -1 : 1; /* and eat the flag */ (*argcp)--; } else { *argv_out = *argv_in; /* keep the flag */ argv_out++; } argv_in++; } *argv_out = 0; } WIN_MESSAGE = WIN_ERR; WIN_MAP = WIN_ERR; WIN_STATUS = WIN_ERR; WIN_INVEN = WIN_ERR; WIN_BASE = WIN_ERR; WIN_OVER = WIN_ERR; if ( (IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", amii_libvers )) == NULL) { Abort(AG_OpenLib | AO_Intuition); } if ( (GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", amii_libvers )) == NULL) { Abort(AG_OpenLib | AO_GraphicsLib); } if( (LayersBase = (struct Library *) OpenLibrary("layers.library", amii_libvers )) == NULL) { Abort(AG_OpenLib | AO_LayersLib); } if ((GadToolsBase = OpenLibrary("gadtools.library", amii_libvers)) == NULL) { Abort(AG_OpenLib | AO_GadTools); } if ((AslBase = OpenLibrary("asl.library", amii_libvers)) == NULL) { Abort(AG_OpenLib); } amiIDisplay=(struct amii_DisplayDesc *)alloc(sizeof(struct amii_DisplayDesc)); memset( amiIDisplay, 0, sizeof( struct amii_DisplayDesc ) ); /* Use Intuition sizes for overscan screens... */ amiIDisplay->xpix = 0; #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { if( wbscr = LockPubScreen( "Workbench" ) ) { amiIDisplay->xpix = wbscr->Width; amiIDisplay->ypix = wbscr->Height; UnlockPubScreen( NULL, wbscr ); } } #endif if( amiIDisplay->xpix == 0 ) { amiIDisplay->ypix = GfxBase->NormalDisplayRows; amiIDisplay->xpix = GfxBase->NormalDisplayColumns; } amiIDisplay->cols = amiIDisplay->xpix / FONTWIDTH; amiIDisplay->toplin=0; amiIDisplay->rawprint=0; amiIDisplay->lastwin=0; if( bigscreen == 0 ) { if( ( GfxBase->ActiView->ViewPort->Modes & LACE ) == LACE ) { amiIDisplay->ypix *= 2; NewHackScreen.ViewModes |= LACE; bigscreen = 1; } else if( GfxBase->NormalDisplayRows >= 300 || amiIDisplay->ypix >= 300 ) { bigscreen = 1; } } else if( bigscreen == -1 ) { bigscreen = 0; forcenobig = 1; } else if( bigscreen ) { /* If bigscreen requested and we don't have enough rows in * noninterlaced mode, switch to interlaced... */ if( GfxBase->NormalDisplayRows < 300 ) { amiIDisplay->ypix *= 2; NewHackScreen.ViewModes |= LACE; } } if( !bigscreen ) { alwaysinvent = 0; } amiIDisplay->rows = amiIDisplay->ypix / FONTHEIGHT; #ifdef HACKFONT /* * Load the fonts that we need. */ if( DiskfontBase = OpenLibrary( "diskfont.library", amii_libvers ) ) { Hack80.ta_Name -= SIZEOF_DISKNAME; HackFont = OpenDiskFont( &Hack80 ); Hack80.ta_Name += SIZEOF_DISKNAME; /* Textsfont13 is filled in with "FONT=" settings. The default is * courier/13. */ TextsFont = NULL; if( bigscreen ) TextsFont = OpenDiskFont( &TextsFont13 ); /* Try hack/8 for texts if no user specified font */ if( TextsFont == NULL ) { Hack80.ta_Name -= SIZEOF_DISKNAME; TextsFont = OpenDiskFont( &Hack80 ); Hack80.ta_Name += SIZEOF_DISKNAME; } /* If no fonts, make everything topaz 8 for non-view windows. */ Hack80.ta_Name = "topaz.font"; RogueFont = OpenFont( &Hack80 ); if(!RogueFont) panic("Can't get topaz:8"); if( !HackFont || !TextsFont ) { if( !HackFont ) { HackFont = OpenFont( &Hack80 ); if( !HackFont ) panic( "Can't get a map font, topaz:8" ); } if( !TextsFont ) { TextsFont = OpenFont( &Hack80 ); if( !TextsFont ) panic( "Can't open text font" ); } } CloseLibrary(DiskfontBase); DiskfontBase = NULL; } #endif /* Adjust getlin window size to font */ if (TextsFont) { extern SHORT BorderVectors1[]; extern SHORT BorderVectors2[]; extern struct Gadget Gadget2; extern struct Gadget String; extern struct NewWindow StrWindow; BorderVectors1[2] += (TextsFont->tf_XSize-8)*6; /* strlen("Cancel") == 6 */ BorderVectors1[4] += (TextsFont->tf_XSize-8)*6; BorderVectors1[5] += TextsFont->tf_YSize-8; BorderVectors1[7] += TextsFont->tf_YSize-8; BorderVectors2[2] += (TextsFont->tf_XSize-8)*6; BorderVectors2[4] += (TextsFont->tf_XSize-8)*6; BorderVectors2[5] += TextsFont->tf_YSize-8; BorderVectors2[7] += TextsFont->tf_YSize-8; Gadget2.TopEdge += TextsFont->tf_YSize-8; Gadget2.Width += (TextsFont->tf_XSize-8)*6; Gadget2.Height += TextsFont->tf_YSize-8; String.LeftEdge += (TextsFont->tf_XSize-8)*6; String.TopEdge += TextsFont->tf_YSize-8; String.Width += TextsFont->tf_XSize-8; String.Height += TextsFont->tf_YSize-8; StrWindow.Width += (TextsFont->tf_XSize-8)*7; StrWindow.Height += (TextsFont->tf_YSize-8)*2; /* Titlebar + 1 row of gadgets */ } /* This is the size screen we want to open, within reason... */ NewHackScreen.Width = max( WIDTH, amiIDisplay->xpix ); NewHackScreen.Height = max( SCREENHEIGHT, amiIDisplay->ypix ); { static char fname[18]; sprintf(fname,"NetHack %d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); NewHackScreen.DefaultTitle=fname; } #if 0 NewHackScreen.BlockPen = C_BLACK; NewHackScreen.DetailPen = C_WHITE; #endif #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { int i; struct DimensionInfo dims; DisplayInfoHandle handle; struct DisplayInfo disp; ULONG modeid = DEFAULT_MONITOR_ID|HIRES_KEY; NewHackScreen.Width = STDSCREENWIDTH; NewHackScreen.Height = STDSCREENHEIGHT; #ifdef HACKFONT if (TextsFont) { NewHackScreen.Font = &TextsFont13; } #endif if ( amii_scrnmode == 0xffffffff ) { struct ScreenModeRequester *SMR; #ifdef __GNUC__ SM_FilterHook.h_Entry = (void *)&SM_Filter; #else SM_FilterHook.h_Entry = (ULONG(*)())SM_Filter; #endif SM_FilterHook.h_Data = 0; SM_FilterHook.h_SubEntry = 0; SMR = AllocAslRequest(ASL_ScreenModeRequest,NULL); if (AslRequestTags(SMR, ASLSM_FilterFunc, (ULONG)&SM_FilterHook, TAG_END)) amii_scrnmode = SMR->sm_DisplayID; else amii_scrnmode = 0; FreeAslRequest(SMR); } if( forcenobig == 0 ) { if( ( wbscr = LockPubScreen( "Workbench" ) ) != NULL || ( wbscr = LockPubScreen( NULL ) ) != NULL ) { /* Get the default pub screen's size */ modeid = GetVPModeID( &wbscr->ViewPort ); if( modeid == INVALID_ID || ModeNotAvailable( modeid ) || ( handle = FindDisplayInfo( modeid ) ) == NULL || GetDisplayInfoData( handle, (char *)&dims, sizeof( dims ), DTAG_DIMS, modeid ) <= 0 || GetDisplayInfoData( handle, (char *)&disp, sizeof( disp ), DTAG_DISP, modeid ) <= 0 ) { modeid = DEFAULT_MONITOR_ID|HIRES_KEY; /* If the display database seems to not work, use the screen * dimensions */ NewHackScreen.Height = wbscr->Height; NewHackScreen.Width = wbscr->Width; /* * Request LACE if it looks laced. For 2.1/3.0, we will get * promoted to the users choice of modes (if promotion is allowed) * If the user is using a dragable screen, things will get hosed * but that is life... */ if( wbscr->ViewPort.Modes & LACE ) NewHackScreen.ViewModes |= LACE; modeid = -1; } else { /* Use the display database to get the correct information */ if( disp.PropertyFlags & DIPF_IS_LACE ) NewHackScreen.ViewModes |= LACE; NewHackScreen.Height = dims.StdOScan.MaxY+1; NewHackScreen.Width = dims.StdOScan.MaxX+1; } NewHackScreen.TopEdge = 0; NewHackScreen.LeftEdge = 0; UnlockPubScreen( NULL, wbscr ); } } for( i = 0; scrntags[i].ti_Tag != TAG_DONE; ++i ) { switch( scrntags[i].ti_Tag ) { case SA_DisplayID: if( !amii_scrnmode || ModeNotAvailable( amii_scrnmode ) ) { if( ModeNotAvailable( modeid ) ) { scrntags[i].ti_Tag = TAG_IGNORE; break; } else scrntags[i].ti_Data = (long)modeid; } else modeid = scrntags[i].ti_Data = (long)amii_scrnmode; if( ( handle = FindDisplayInfo( modeid ) ) != NULL && GetDisplayInfoData( handle, (char *)&dims, sizeof( dims ), DTAG_DIMS, modeid ) > 0 && GetDisplayInfoData( handle, (char *)&disp, sizeof( disp ), DTAG_DISP, modeid ) > 0 ) { if( disp.PropertyFlags & DIPF_IS_LACE ) NewHackScreen.ViewModes |= LACE; NewHackScreen.Height = dims.StdOScan.MaxY+1; NewHackScreen.Width = dims.StdOScan.MaxX+1; } break; case SA_Pens: scrntags[i].ti_Data = (long)flags.amii_dripens; break; } } } #endif if( WINVERS_AMIV ) amii_bmhd = ReadTileImageFiles( ); else memcpy( amii_initmap, amii_init_map, sizeof( amii_initmap ) ); memcpy(flags.amii_curmap,amii_initmap,sizeof(flags.amii_curmap)); /* Find out how deep the screen needs to be, 32 planes is enough! */ for( i = 0; i < 32; ++i ) { if( ( 1L << i ) >= amii_numcolors ) break; } NewHackScreen.Depth = i; /* If for some reason Height/Width became smaller than the required, have the required one */ if (NewHackScreen.Height < SCREENHEIGHT) NewHackScreen.Height = SCREENHEIGHT; if (NewHackScreen.Width < WIDTH) NewHackScreen.Width = WIDTH; #ifdef HACKFONT i = max(TextsFont->tf_XSize, HackFont->tf_XSize); if (NewHackScreen.Width < 80*i+4) NewHackScreen.Width = 80*i+4; #endif /* While openscreen fails try fewer colors to see if that is the problem. */ while( ( HackScreen = OpenScreen( (void *)&NewHackScreen ) ) == NULL ) { #ifdef TEXTCOLOR if( --NewHackScreen.Depth < 3 ) #else if( --NewHackScreen.Depth < 2 ) #endif Abort( AN_OpenScreen & ~AT_DeadEnd ); } amii_numcolors = 1L << NewHackScreen.Depth; if( HackScreen->Height > 300 && forcenobig == 0 ) bigscreen = 1; else bigscreen = 0; #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) PubScreenStatus( HackScreen, 0 ); #endif amiIDisplay->ypix = HackScreen->Height; amiIDisplay->xpix = HackScreen->Width; LoadRGB4(&HackScreen->ViewPort, flags.amii_curmap, amii_numcolors ); VisualInfo = GetVisualInfo(HackScreen, TAG_END); MenuStrip = CreateMenus(GTHackMenu, TAG_END); LayoutMenus(MenuStrip, VisualInfo, GTMN_NewLookMenus, TRUE, TAG_END); /* Display the copyright etc... */ if( WIN_BASE == WIN_ERR ) WIN_BASE = amii_create_nhwindow( NHW_BASE ); amii_clear_nhwindow( WIN_BASE ); amii_putstr( WIN_BASE, 0, "" ); amii_putstr( WIN_BASE, 0, "" ); amii_putstr( WIN_BASE, 0, "" ); amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_A); amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_B); amii_putstr( WIN_BASE, 0, COPYRIGHT_BANNER_C); amii_putstr( WIN_BASE, 0, ""); Initialized = 1; } void amii_sethipens( struct Window *w, int type, int attr ) { switch( type ) { default: SetAPen( w->RPort, attr ? C_RED : amii_otherAPen ); SetBPen( w->RPort, C_BLACK ); break; case NHW_STATUS: SetAPen( w->RPort, attr ? C_WHITE : amii_statAPen ); SetBPen( w->RPort, amii_statBPen ); break; case NHW_MESSAGE: SetAPen( w->RPort, attr ? C_WHITE : amii_msgAPen ); SetBPen( w->RPort, amii_msgBPen ); break; case NHW_MENU: SetAPen( w->RPort, attr ? C_BLACK : amii_menuAPen ); SetBPen( w->RPort, amii_menuBPen ); break; case NHW_TEXT: SetAPen( w->RPort, attr ? C_BLACK : amii_textAPen ); SetBPen( w->RPort, amii_textBPen ); case -2: SetBPen( w->RPort, amii_otherBPen ); SetAPen( w->RPort, attr ? C_RED : amii_otherAPen ); break; } } void amii_setfillpens( struct Window *w, int type ) { switch( type ) { case NHW_MESSAGE: SetAPen( w->RPort, amii_msgBPen ); SetBPen( w->RPort, amii_msgBPen ); break; case NHW_STATUS: SetAPen( w->RPort, amii_statBPen ); SetBPen( w->RPort, amii_statBPen ); break; case NHW_MENU: SetAPen( w->RPort, amii_menuBPen ); SetBPen( w->RPort, amii_menuBPen ); break; case NHW_TEXT: SetAPen( w->RPort, amii_textBPen ); SetBPen( w->RPort, amii_textBPen ); break; case NHW_MAP: case NHW_BASE: case NHW_OVER: default: SetAPen( w->RPort, C_BLACK ); SetBPen( w->RPort, C_BLACK ); break; case -2: SetAPen( w->RPort, amii_otherBPen ); SetBPen( w->RPort, amii_otherBPen ); break; } } void amii_setdrawpens( struct Window *w, int type ) { switch( type ) { case NHW_MESSAGE: SetAPen( w->RPort, amii_msgAPen ); SetBPen( w->RPort, amii_msgBPen ); break; case NHW_STATUS: SetAPen( w->RPort, amii_statAPen ); SetBPen( w->RPort, amii_statBPen ); break; case NHW_MENU: SetAPen( w->RPort, amii_menuAPen ); SetBPen( w->RPort, amii_menuBPen ); break; case NHW_TEXT: SetAPen( w->RPort, amii_textAPen ); SetBPen( w->RPort, amii_textBPen ); break; case NHW_MAP: case NHW_BASE: case NHW_OVER: SetAPen( w->RPort, C_WHITE ); SetBPen( w->RPort, C_BLACK ); break; default: SetAPen( w->RPort, amii_otherAPen ); SetBPen( w->RPort, amii_otherBPen ); break; } } /* Clear the indicated window */ void amii_clear_nhwindow(win) register winid win; { register struct amii_WinDesc *cw; register struct Window *w; if( reclip == 2 ) return; if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL ) panic( winpanicstr, win, "clear_nhwindow" ); /* Clear the overview window too if it is displayed */ if( WINVERS_AMIV && ( cw->type == WIN_MAP && WIN_OVER != WIN_ERR && reclip == 0 ) ) { amii_clear_nhwindow( WIN_OVER ); } if( w = cw->win ) SetDrMd( w->RPort, JAM2); else return; if( (cw->wflags & FLMAP_CURSUP ) ) { if( cw->type != NHW_MAP ) cursor_off( win ); else cw->wflags &= ~FLMAP_CURSUP; } amii_setfillpens( w, cw->type ); SetDrMd( w->RPort, JAM2 ); if( cw->type == NHW_MENU || cw->type == NHW_TEXT ) { RectFill( w->RPort, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight-1, w->Height - w->BorderBottom-1 ); } else { if( cw->type == NHW_MESSAGE ) { amii_curs( win, 1, 0 ); if( !scrollmsg ) TextSpaces( w->RPort, cw->cols ); } else { RectFill( w->RPort, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight-1, w->Height - w->BorderBottom-1 ); } } cw->cury = 0; cw->curx = 0; amii_curs( win, 1, 0 ); } /* Dismiss the window from the screen */ void dismiss_nhwindow(win) register winid win; { register struct Window *w; register struct amii_WinDesc *cw; if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL ) { panic(winpanicstr,win, "dismiss_nhwindow"); } w = cw->win; if( w ) { /* All windows have this stuff attached to them. */ if( cw->type == NHW_MAP || cw->type == NHW_OVER || cw->type == NHW_BASE || cw->type == NHW_MESSAGE || cw->type == NHW_STATUS ) { ClearMenuStrip( w ); } /* Save where user like inventory to appear */ if( win == WIN_INVEN ) { lastinvent.MinX = w->LeftEdge; lastinvent.MinY = w->TopEdge; lastinvent.MaxX = w->Width; lastinvent.MaxY = w->Height; } /* Close the window */ CloseShWindow( w ); cw->win = NULL; /* Free copy of NewWindow structure for TEXT/MENU windows. */ if( cw->newwin ) FreeNewWindow( (void *)cw->newwin ); cw->newwin = NULL; } } void amii_exit_nhwindows(str) const char *str; { /* Seems strange to have to do this... but we need the BASE window * left behind... */ kill_nhwindows( 0 ); if( WINVERS_AMIV ) FreeTileImageFiles( ); if( str ) { raw_print( "" ); /* be sure we're not under the top margin */ raw_print( str ); } } void amii_display_nhwindow(win,blocking) winid win; boolean blocking; { menu_item *mip; int cnt; static int lastwin = -1; struct amii_WinDesc *cw; if( !Initialized ) return; lastwin = win; if( win == WIN_ERR || ( cw = amii_wins[win] ) == NULL ) panic(winpanicstr,win,"display_nhwindow"); if( cw->type == NHW_MESSAGE ) cw->wflags &= ~FLMAP_SKIP; if( cw->type == NHW_MESSAGE || cw->type == NHW_STATUS ) return; if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) { flush_glyph_buffer( amii_wins[ WIN_MAP ]->win ); } if( cw->type == NHW_MENU || cw->type == NHW_TEXT ) { cnt = DoMenuScroll( win, blocking, PICK_ONE, &mip ); } else if( cw->type==NHW_MAP ) { amii_end_glyphout( win ); /* Do more if it is time... */ if( blocking == TRUE && amii_wins[ WIN_MESSAGE ]->curx ) { outmore( amii_wins[ WIN_MESSAGE ] ); } } } void amii_curs(window, x, y) winid window; register int x, y; /* not xchar: perhaps xchar is unsigned and curx-x would be unsigned as well */ { register struct amii_WinDesc *cw; register struct Window *w; register struct RastPort *rp; if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL ) panic(winpanicstr, window, "curs"); if( (w = cw->win) == NULL ) { if( cw->type == NHW_MENU || cw->type == NHW_TEXT ) return; else panic( "No window open yet in curs() for winid %d\n", window ); } amiIDisplay->lastwin = window; /* Make sure x is within bounds */ if( x > 0 ) --x; /* column 0 is never used */ else x = 0; cw->curx = x; cw->cury = y; #ifdef DEBUG if( x<0 || y<0 || y >= cw->rows || x >= cw->cols ) { char *s = "[unknown type]"; switch(cw->type) { case NHW_MESSAGE: s = "[topl window]"; break; case NHW_STATUS: s = "[status window]"; break; case NHW_MAP: s = "[map window]"; break; case NHW_MENU: s = "[menu window]"; break; case NHW_TEXT: s = "[text window]"; break; case NHW_BASE: s = "[base window]"; break; case NHW_OVER: s = "[overview window]"; break; } impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y); return; } #endif #ifdef CLIPPING if(clipping && cw->type == NHW_MAP) { x -= clipx; y -= clipy; } #endif /* Output all saved output before doing cursor movements for MAP */ if( cw->type == NHW_MAP ) { flush_glyph_buffer( w ); } /* Actually do it */ rp = w->RPort; if( cw->type == NHW_MENU ) { if( WINVERS_AMIV ) { if( window == WIN_INVEN ) { Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1 + pictdata.xsize + 4, (y * max(rp->TxHeight,pictdata.ysize + 3) ) + rp->TxBaseline + pictdata.ysize - rp->TxHeight + w->BorderTop + 4 ); } else { Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y * rp->TxHeight) + rp->TxBaseline + w->BorderTop + 1 ); } } else { Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y*rp->TxHeight ) + rp->TxBaseline + w->BorderTop + 1 ); } } else if( cw->type == NHW_TEXT ) { Move( rp, (x * rp->TxWidth) + w->BorderLeft + 1, (y*rp->TxHeight ) + rp->TxBaseline + w->BorderTop + 1 ); } else if( cw->type == NHW_MAP || cw->type == NHW_BASE ) { /* These coordinate calculations must be synced with those * in flush_glyph_buffer() in winchar.c. curs_on_u() will * use this code, all other drawing occurs through the glyph * code. In order for the cursor to appear on top of the hero, * the code must compute X,Y in the same manner relative to * the RastPort coordinates. * * y = w->BorderTop + (g_nodes[i].y-2) * rp->TxHeight + * rp->TxBaseline + 1; * x = g_nodes[i].x * rp->TxWidth + w->BorderLeft; */ if( WINVERS_AMIV ) { if( cw->type == NHW_MAP ) { if(Is_rogue_level(&u.uz)){ #if 0 int qqx= (x * w->RPort->TxWidth) + w->BorderLeft; int qqy= w->BorderTop + ( (y+1) * w->RPort->TxHeight ) + 1; printf("pos: (%d,%d)->(%d,%d)\n",x,y,qqx,qqy); #endif SetAPen(w->RPort,C_WHITE); /* XXX should be elsewhere (was 4)*/ Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + ( (y+1) * w->RPort->TxHeight ) + 1 ); } else { Move( rp, (x * mxsize) + w->BorderLeft, w->BorderTop + ( (y+1) * mysize ) + 1 ); } } else { Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + ( (y + 1) * w->RPort->TxHeight ) + w->RPort->TxBaseline + 1 ); } } else { Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft, w->BorderTop + ( y * w->RPort->TxHeight ) + w->RPort->TxBaseline + 1 ); } } else if( WINVERS_AMIV && cw->type == NHW_OVER ) { Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, w->BorderTop + w->RPort->TxBaseline + 3 ); } else if( cw->type == NHW_MESSAGE && !scrollmsg ) { Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, w->BorderTop + w->RPort->TxBaseline + 3 ); } else if( cw->type == NHW_STATUS ) { Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, (y*(w->RPort->TxHeight+1)) + w->BorderTop + w->RPort->TxBaseline + 1 ); } else { Move( rp, (x * w->RPort->TxWidth) + w->BorderLeft + 2, (y*w->RPort->TxHeight) + w->BorderTop + w->RPort->TxBaseline + 1 ); } } void amii_set_text_font( name, size ) char *name; int size; { register int i; register struct amii_WinDesc *cw; int osize = TextsFont13.ta_YSize; static char nname[ 100 ]; strncpy( nname, name, sizeof( nname ) - 1 ); nname[ sizeof( nname ) - 1 ] = 0; TextsFont13.ta_Name = nname; TextsFont13.ta_YSize = size; /* No alternate text font allowed for 640x269 or smaller */ if( !HackScreen || !bigscreen ) return; /* Look for windows to set, and change them */ if( DiskfontBase = OpenLibrary( "diskfont.library", amii_libvers ) ) { TextsFont = OpenDiskFont( &TextsFont13 ); for( i = 0; TextsFont && i < MAXWIN; ++i ) { if( (cw = amii_wins[ i ]) && cw->win != NULL ) { switch( cw->type ) { case NHW_STATUS: MoveWindow( cw->win, 0, -( size - osize ) * 2 ); SizeWindow( cw->win, 0, ( size - osize ) * 2 ); SetFont( cw->win->RPort, TextsFont ); break; case NHW_MESSAGE: case NHW_MAP: case NHW_BASE: case NHW_OVER: SetFont( cw->win->RPort, TextsFont ); break; } } } } CloseLibrary(DiskfontBase); DiskfontBase = NULL; } void kill_nhwindows( all ) register int all; { register int i; register struct amii_WinDesc *cw; /* Foreach open window in all of amii_wins[], CloseShWindow, free memory */ for( i = 0; i < MAXWIN; ++i ) { if( (cw = amii_wins[ i ]) && (cw->type != NHW_BASE || all) ) { amii_destroy_nhwindow( i ); } } } void amii_cl_end( cw, curs_pos ) register struct amii_WinDesc *cw; register int curs_pos; { register struct Window *w = cw->win; register int oy, ox; if( !w ) panic("NULL window pointer in amii_cl_end()"); oy = w->RPort->cp_y; ox = w->RPort->cp_x; TextSpaces( w->RPort, cw->cols - curs_pos ); Move( w->RPort, ox, oy ); } void cursor_off( window ) winid window; { register struct amii_WinDesc *cw; register struct Window *w; register struct RastPort *rp; int curx, cury; int x, y; long dmode; short apen, bpen; unsigned char ch; if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL ) { iflags.window_inited=0; panic(winpanicstr,window, "cursor_off"); } if( !(cw->wflags & FLMAP_CURSUP ) ) return; w = cw->win; if( !w ) return; cw->wflags &= ~FLMAP_CURSUP; rp = w->RPort; /* Save the current information */ curx = rp->cp_x; cury = rp->cp_y; x = cw->cursx; y = cw->cursy; dmode = rp->DrawMode; apen = rp->FgPen; bpen = rp->BgPen; SetAPen( rp, cw->curs_apen ); SetBPen( rp, cw->curs_bpen ); SetDrMd( rp, COMPLEMENT ); /*printf("CURSOR OFF: %d %d\n",x,y);*/ if( WINVERS_AMIV && cw->type == NHW_MAP) { cursor_common(rp, x, y); if(Is_rogue_level(&u.uz)) Move(rp,curx,cury); } else { ch = CURSOR_CHAR; Move( rp, x, y ); Text( rp, &ch, 1 ); /* Put back the other stuff */ Move( rp, curx, cury ); } SetDrMd( rp, dmode ); SetAPen( rp, apen ); SetBPen( rp, bpen ); } void cursor_on( window ) winid window; { int x, y; register struct amii_WinDesc *cw; register struct Window *w; register struct RastPort *rp; unsigned char ch; long dmode; short apen, bpen; if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL ) { /* tty does this differently - is this OK? */ iflags.window_inited=0; panic(winpanicstr,window, "cursor_on"); } /*printf("CURSOR ON: %d %d\n",cw->win->RPort->cp_x, cw->win->RPort->cp_y);*/ if( (cw->wflags & FLMAP_CURSUP ) ) cursor_off( window ); w = cw->win; if( !w ) return; cw->wflags |= FLMAP_CURSUP; rp = w->RPort; /* Save the current information */ #ifdef DISPMAP if( WINVERS_AMIV && cw->type == NHW_MAP && !Is_rogue_level(&u.uz)) x = cw->cursx = (rp->cp_x & -8) + 8; else #endif x = cw->cursx = rp->cp_x; y = cw->cursy = rp->cp_y; apen = rp->FgPen; bpen = rp->BgPen; dmode = rp->DrawMode; /* Draw in complement mode. The cursor body will be C_WHITE */ cw->curs_apen = 0xff; /* Last color/all planes, regardless of depth */ cw->curs_bpen = 0xff; SetAPen( rp, cw->curs_apen ); SetBPen( rp, cw->curs_bpen ); SetDrMd( rp, COMPLEMENT ); if( WINVERS_AMIV && cw->type == NHW_MAP) { cursor_common(rp, x, y); } else { Move( rp, x, y ); ch = CURSOR_CHAR; Text( rp, &ch, 1 ); Move( rp, x, y ); } SetDrMd( rp, dmode ); SetAPen( rp, apen ); SetBPen( rp, bpen ); } static void cursor_common(rp, x, y) struct RastPort *rp; int x,y; { int x1,x2,y1,y2; if(Is_rogue_level(&u.uz)){ x1 = x-2; y1 = y-rp->TxHeight; x2 = x+rp->TxWidth+1; y2 = y+3; /*printf("COMM: (%d %d) (%d %d) (%d %d) (%d %d)\n",x1,y1,x2,y2,x1+2,y1+2,x2-2,y2-2);*/ } else { x1 = x; y1 = y-mysize-1; x2 = x+mxsize-1; y2 = y-2; RectFill(rp, x1, y1, x2, y2); } RectFill(rp, x1+2, y1+2, x2-2, y2-2); } void amii_suspend_nhwindows( str ) const char *str; { if( HackScreen ) ScreenToBack( HackScreen ); } void amii_resume_nhwindows() { if( HackScreen ) ScreenToFront( HackScreen ); } void amii_bell() { DisplayBeep( NULL ); } void removetopl(cnt) int cnt; { struct amii_WinDesc *cw=amii_wins[WIN_MESSAGE]; /* NB - this is sufficient for * yn_function, but that's it */ if(cw->curx < cnt)cw->curx=0; else cw->curx -= cnt; amii_curs(WIN_MESSAGE, cw->curx+1, cw->cury); amii_cl_end(cw, cw->curx); } /*#endif /* AMIGA_INTUITION */ #ifdef PORT_HELP void port_help() { display_file( PORT_HELP, 1 ); } #endif /* * print_glyph * * Print the glyph to the output device. Don't flush the output device. * * Since this is only called from show_glyph(), it is assumed that the * position and glyph are always correct (checked there)! */ void amii_print_glyph(win,x,y,glyph) winid win; xchar x,y; int glyph; { struct amii_WinDesc *cw; uchar ch; int color, och; extern const int zapcolors[]; unsigned special; /* In order for the overview window to work, we can not clip here */ if( !WINVERS_AMIV ) { #ifdef CLIPPING /* If point not in visible part of window just skip it */ if( clipping ) { if( x <= clipx || y < clipy || x >= clipxmax || y >= clipymax ) return; } #endif } if( win == WIN_ERR || (cw=amii_wins[win]) == NULL || cw->type != NHW_MAP) { panic(winpanicstr,win,"amii_print_glyph"); } #if 0 { static int x=-1; if(u.uz.dlevel != x){ fprintf(stderr,"lvlchg: %d (%d)\n",u.uz.dlevel,Is_rogue_level(&u.uz)); x = u.uz.dlevel; } } #endif if( WINVERS_AMIV #ifdef REINCARNATION && !Is_rogue_level(&u.uz) #endif ) { amii_curs(win,x,y); amiga_print_glyph(win,0,glyph); } else /* AMII, or Rogue level in either version */ { /* map glyph to character and color */ mapglyph(glyph, &och, &color, &special, x, y); /* XXX next if should be ifdef REINCARNATION */ ch = (uchar)och; if( WINVERS_AMIV ){ /* implies Rogue level here */ amii_curs(win,x,y); amiga_print_glyph(win,NO_COLOR,ch + 10000); } else { /* Move the cursor. */ amii_curs(win,x,y+2); #ifdef TEXTCOLOR /* Turn off color if rogue level. */ # ifdef REINCARNATION if (Is_rogue_level(&u.uz)) color = NO_COLOR; # endif amiga_print_glyph(win,color,ch); #else g_putch(ch); /* print the character */ #endif cw->curx++; /* one character over */ } } } /* Make sure the user sees a text string when no windowing is available */ void amii_raw_print(s) register const char *s; { int argc = 0; if( !s ) return; if(amiIDisplay) amiIDisplay->rawprint++; if (!Initialized) { /* Not yet screen open ... */ puts(s); fflush(stdout); return; } if( Initialized == 0 && WIN_BASE == WIN_ERR ) init_nhwindows(&argc, (char **)0); if( amii_rawprwin != WIN_ERR ) amii_putstr( amii_rawprwin, 0, s ); else if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) amii_putstr( WIN_MAP, 0, s ); else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] ) amii_putstr( WIN_BASE, 0, s ); else { puts( s); fflush(stdout); } } /* Make sure the user sees a bold text string when no windowing * is available */ void amii_raw_print_bold(s) register const char *s; { int argc = 0; if( !s ) return; if(amiIDisplay) amiIDisplay->rawprint++; if (!Initialized) { /* Not yet screen open ... */ puts(s); fflush(stdout); return; } if( Initialized == 0 && WIN_BASE == WIN_ERR ) init_nhwindows(&argc, (char **)0); if( amii_rawprwin != WIN_ERR ) amii_putstr( amii_rawprwin, 1, s ); else if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) amii_putstr( WIN_MAP, 1, s ); else if( WIN_BASE != WIN_ERR && amii_wins[ WIN_BASE ] ) amii_putstr( WIN_BASE, 1, s ); else { printf("\33[1m%s\33[0m\n",s); fflush(stdout); } } /* Rebuild/update the inventory if the window is up. */ void amii_update_inventory() { register struct amii_WinDesc *cw; if( WIN_INVEN != WIN_ERR && ( cw = amii_wins[ WIN_INVEN ] ) && cw->type == NHW_MENU && cw->win ) { display_inventory( NULL, FALSE ); } } /* Humm, doesn't really do anything useful */ void amii_mark_synch() { if(!amiIDisplay) fflush(stderr); /* anything else? do we need this much? */ } /* Wait for everything to sync. Nothing is asynchronous, so we just * ask for a key to be pressed. */ void amii_wait_synch() { if(!amiIDisplay || amiIDisplay->rawprint) { if(amiIDisplay) amiIDisplay->rawprint=0; } else { if( WIN_MAP != WIN_ERR ) { display_nhwindow(WIN_MAP,TRUE); flush_glyph_buffer( amii_wins[ WIN_MAP ]->win ); } } } void amii_setclipped() { #ifdef CLIPPING clipping = TRUE; clipx=clipy=0; clipxmax=CO; clipymax=LI; /* some of this is now redundant with top of amii_cliparound XXX */ #endif } /* XXX still to do: suppress scrolling if we violate the boundary but the * edge of the map is already displayed */ void amii_cliparound(x,y) register int x,y; { extern boolean restoring; #ifdef CLIPPING int oldx = clipx, oldy = clipy; int oldxmax = clipxmax, oldymax = clipymax; int COx, LIx; #define SCROLLCNT 1 /* Get there in 3 moves... */ int scrollcnt = SCROLLCNT; /* ...or 1 if we changed level */ if (!clipping) /* And 1 in anycase, cleaner, simpler, quicker */ return; if(Is_rogue_level(&u.uz)){ struct Window *w = amii_wins[WIN_MAP]->win; struct RastPort *rp = w->RPort; COx = (w->Width-w->BorderLeft-w->BorderRight)/rp->TxWidth; LIx = (w->Height-w->BorderTop-w->BorderBottom)/rp->TxHeight; }else{ COx = CO; LIx = LI; } /* * On a level change, move the clipping region so that for a * reasonablely large window extra motion is avoided; for * the rogue level hopefully this means no motion at all. */ { static d_level saved_level = {127,127}; /* XXX */ if(!on_level(&u.uz, &saved_level)){ scrollcnt = 1; /* jump with blanking */ clipx=clipy=0; clipxmax = COx; clipymax = LIx; saved_level = u.uz; /* save as new current level */ } } if (x <= clipx + xclipbord ) { clipx = max(0, x - (clipxmax - clipx)/2 ); clipxmax = clipx + COx; } else if (x > clipxmax - xclipbord ) { clipxmax = min(COLNO, x + (clipxmax - clipx)/2 ); clipx = clipxmax - COx; } if (y <= clipy + yclipbord ) { clipy = max(0, y - (clipymax - clipy) / 2); clipymax = clipy + LIx; } else if (y > clipymax - yclipbord ) { clipymax = min(ROWNO, y + (clipymax - clipy) / 2); clipy = clipymax - LIx; } reclip = 1; if (clipx != oldx || clipy != oldy || clipxmax != oldxmax || clipymax != oldymax ) { #ifndef NOSCROLLRASTER struct Window *w = amii_wins[ WIN_MAP ]->win; struct RastPort *rp = w->RPort; int xdelta, ydelta, xmod, ymod, i; int incx, incy, mincx, mincy; int savex, savey, savexmax, saveymax; int scrx, scry; if(Is_rogue_level(&u.uz)){ scrx = rp->TxWidth; scry = rp->TxHeight; } else { scrx = mxsize; scry = mysize; } /* Ask that the glyph routines not draw the overview window */ reclip = 2; cursor_off( WIN_MAP ); /* Compute how far we are moving in terms of tiles */ mincx = clipx - oldx ; mincy = clipy - oldy ; /* How many tiles to get there in SCROLLCNT moves */ incx = ( clipx - oldx )/scrollcnt; incy = ( clipy - oldy )/scrollcnt; /* If less than SCROLLCNT tiles, then move by 1 tile if moving at all */ if( incx == 0 ) incx = (mincx != 0); if( incy == 0 ) incy = (mincy != 0); /* Get count of pixels to move each iteration and final pixel count */ xdelta = ((clipx-oldx )*scrx) / scrollcnt; xmod = ((clipx-oldx )*scrx) % scrollcnt; ydelta = ((clipy-oldy )*scry) / scrollcnt; ymod = ((clipy-oldy )*scry) % scrollcnt; /* Preserve the final move location */ savex = clipx; savey = clipy; saveymax = clipymax; savexmax = clipxmax; /* * Set clipping rectangle to be just the region that will be exposed so * that drawing will be faster */ #if 0 /* Doesn't seem to work quite the way it should */ /* In some cases hero is 'centered' offscreen */ if( xdelta < 0 ) { clipx = oldx; clipxmax = clipx + incx; } else if( xdelta > 0 ) { clipxmax = oldxmax; clipx = clipxmax - incx; } else { clipx = oldx; clipxmax = oldxmax; } if( ydelta < 0 ) { clipy = oldy; clipymax = clipy + incy; } else if( ydelta > 0 ) { clipymax = oldymax; clipy = clipymax - incy; } else { clipy = oldy; clipymax = oldymax; } #endif /* Now, in scrollcnt moves, move the picture toward the final view */ for( i = 0; i < scrollcnt; ++i ) { #ifdef DISPMAP if( i == scrollcnt - 1 && (xmod != 0 || ymod != 0) && (xdelta != 0 || ydelta != 0) ) { incx += (clipx - oldx)%scrollcnt; incy += (clipy - oldy)%scrollcnt; xdelta += xmod; ydelta += ymod; } #endif /* Scroll the raster if we are scrolling */ if( xdelta != 0 || ydelta != 0 ) { ScrollRaster( rp, xdelta, ydelta, w->BorderLeft, w->BorderTop, w->Width - w->BorderRight - 1, w->Height - w->BorderBottom - 1 ); if( mincx == 0 ) incx = 0; else mincx -= incx; clipx += incx; clipxmax += incx; if( mincy == 0 ) incy = 0; else mincy -= incy; clipy += incy; clipymax += incy; /* Draw the exposed portion */ if (on_level(&u.uz0, &u.uz) && !restoring) (void) doredraw(); flush_glyph_buffer( amii_wins[ WIN_MAP ]->win ); } } clipx = savex; clipy = savey; clipymax = saveymax; clipxmax = savexmax; #endif if (on_level(&u.uz0, &u.uz) && !restoring && moves > 1) (void) doredraw(); flush_glyph_buffer( amii_wins[ WIN_MAP ]->win ); } reclip = 0; #endif } void flushIDCMP( port ) struct MsgPort *port; { struct Message *msg; while( msg = GetMsg( port ) ) ReplyMsg( msg ); } nethack-3.4.3/sys/amiga/winkey.c0100644000000000000000000000363307764735041015225 0ustar rootroot/* SCCS Id: @(#)winkey.c 3.1 93/04/02 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" amii_nh_poskey(x, y, mod) int*x, *y, *mod; { struct amii_WinDesc *cw; WETYPE type; struct RastPort *rp; struct Window *w; if( cw = amii_wins[WIN_MESSAGE] ) { cw->wflags &= ~FLMAP_SKIP; if( scrollmsg ) cw->wflags |= FLMSG_FIRST; cw->disprows = 0; } if( WIN_MAP != WIN_ERR && (cw = amii_wins[ WIN_MAP ]) && ( w = cw->win ) ) { cursor_on( WIN_MAP ); } else panic( "no MAP window opened for nh_poskey\n" ); rp = w->RPort; while( 1 ) { type = WindowGetevent( ); if( type == WEMOUSE ) { *mod = CLICK_1; if( lastevent.un.mouse.qual ) *mod = 0; /* X coordinates are 1 based, Y are 1 based. */ *x = ( (lastevent.un.mouse.x - w->BorderLeft) / mxsize ) + 1; *y = ( ( lastevent.un.mouse.y - w->BorderTop - MAPFTBASELN ) / mysize ) + 1; #ifdef CLIPPING if( clipping ) { *x += clipx; *y += clipy; } #endif return( 0 ); } else if( type == WEKEY ) { lastevent.type = WEUNK; return( lastevent.un.key ); } } } int amii_nhgetch() { int ch; struct amii_WinDesc *cw=amii_wins[WIN_MESSAGE]; if( WIN_MAP != WIN_ERR && amii_wins[ WIN_MAP ] ) { cursor_on( WIN_MAP ); } if(cw) cw->wflags &= ~FLMAP_SKIP; ch = WindowGetchar(); return( ch ); } void amii_get_nh_event() { /* nothing now - later I have no idea. Is this just a Mac hook? */ } void amii_getret() { register int c; raw_print( "" ); raw_print( "Press Return..." ); c = 0; while( c != '\n' && c != '\r' ) { if( HackPort ) c = WindowGetchar(); else c = getchar(); } return; } nethack-3.4.3/sys/amiga/winmenu.c0100644000000000000000000011122307764735041015374 0ustar rootroot/* SCCS Id: @(#)winmenu.c 3.2 96/02/17 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993,1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" /* Start building the text for a menu */ void amii_start_menu(window) register winid window; { register int i; register struct amii_WinDesc *cw; register amii_menu_item *mip; if(window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU) panic(winpanicstr,window, "start_menu"); amii_clear_nhwindow(window); if( cw->data && ( cw->type == NHW_MESSAGE || cw->type == NHW_MENU || cw->type == NHW_TEXT ) ) { for( i = 0; i < cw->maxrow; ++i ) { if( cw->data[ i ] ) free( cw->data[ i ] ); } free( cw->data ); cw->data = NULL; } for( mip = cw->menu.items, i = 0; (mip = cw->menu.items) && i < cw->menu.count; ++i ) { cw->menu.items = mip->next; free( mip ); } cw->menu.items = 0; cw->menu.count = 0; cw->menu.chr = 'a'; if( cw->morestr ) free( cw->morestr ); cw->morestr = NULL; if( window == WIN_INVEN && cw->win != NULL ) { if( alwaysinvent ) cw->wasup = 1; } cw->cury = cw->rows = cw->maxrow = cw->maxcol = 0; return; } /* Add a string to a menu */ void amii_add_menu(window,glyph, id, ch, gch, attr, str, preselected) register winid window; register int glyph; register const anything *id; register char ch; register char gch; register int attr; register const char *str; register BOOLEAN_P preselected; { register struct amii_WinDesc *cw; amii_menu_item *mip; char buf[ 4+BUFSZ ]; if(str == NULL)return; if(window == WIN_ERR || (cw = amii_wins[window]) == NULL || cw->type != NHW_MENU) panic(winpanicstr,window, "add_menu"); mip = (amii_menu_item *)alloc( sizeof( *mip ) ); mip->identifier = *id; mip->selected = preselected; mip->attr = attr; mip->glyph = Is_rogue_level(&u.uz) ? NO_GLYPH : glyph; mip->selector = 0; mip->gselector = gch; mip->count = -1; if (id->a_void && !ch && cw->menu.chr != 0) { ch = cw->menu.chr++; if( ch == 'z' ) cw->menu.chr = 'A'; if( ch == 'Z' ) cw->menu.chr = 0; } mip->canselect = ( id->a_void != 0 ); if( id->a_void && ch != '\0') { Sprintf( buf, "%c - %s", ch, str ); str = buf; mip->canselect = 1; } mip->selector = ch; amii_putstr( window, attr, str ); mip->str = cw->data[ cw->cury - 1 ]; cw->menu.count++; mip->next = NULL; if( cw->menu.items == 0 ) cw->menu.last = cw->menu.items = mip; else { cw->menu.last->next = mip; cw->menu.last = mip; } } /* Done building a menu. */ void amii_end_menu(window,morestr) register winid window; register const char *morestr; { register struct amii_WinDesc *cw; if(window == WIN_ERR || (cw=amii_wins[window]) == NULL || cw->type != NHW_MENU ) panic(winpanicstr,window, "end_menu"); if( morestr && *morestr ) { anything any; #define PROMPTFIRST /* Define this to have prompt first */ #ifdef PROMPTFIRST amii_menu_item *mip; int i; char *t; mip = cw->menu.last; #endif any.a_void = 0; amii_add_menu( window, NO_GLYPH, &any, 0, 0, ATR_NONE, morestr, MENU_UNSELECTED); #ifdef PROMPTFIRST /* Do some shuffling. Last first, push others one forward */ mip->next = NULL; cw->menu.last->next = cw->menu.items; cw->menu.items = cw->menu.last; cw->menu.last = mip; t = cw->data[cw->cury-1]; for (i=cw->cury-1; i>0; i--) { cw->data[i] = cw->data[i-1]; } cw->data[0] = t; #endif } /* If prompt first, don't put same string in title where in most cases it's not entirely visible anyway */ #ifndef PROMPTFIRST if( morestr ) cw->morestr = strdup( morestr ); #endif } /* Select something from the menu. */ int amii_select_menu(window, how, mip ) register winid window; register int how; register menu_item **mip; { int cnt; register struct amii_WinDesc *cw; if( window == WIN_ERR || ( cw=amii_wins[window] ) == NULL || cw->type != NHW_MENU ) panic(winpanicstr,window, "select_menu"); cnt = DoMenuScroll( window, 1, how, mip ); /* This would allow the inventory window to stay open. */ if( !alwaysinvent || window != WIN_INVEN ) dismiss_nhwindow(window); /* Now tear it down */ return cnt; } amii_menu_item * find_menu_item( register struct amii_WinDesc *cw, int idx ) { amii_menu_item *mip; for( mip = cw->menu.items; idx > 0 && mip; mip = mip->next ) --idx; return( mip ); } int make_menu_items( register struct amii_WinDesc *cw, register menu_item **rmip ) { register int idx = 0; register amii_menu_item *mip; register menu_item *mmip; for( mip = cw->menu.items; mip; mip = mip->next ) { if( mip->selected ) ++idx; } if( idx ) { mmip = *rmip = (menu_item *)alloc( idx * sizeof( *mip ) ); for( mip = cw->menu.items; mip; mip = mip->next ) { if( mip->selected ) { mmip->item = mip->identifier; mmip->count = mip->count; mmip++; } } cw->mi = *rmip; } return( idx ); } int DoMenuScroll( win, blocking, how, retmip ) int win, blocking, how; menu_item **retmip; { amii_menu_item *amip; register struct Window *w; register struct NewWindow *nw; struct PropInfo *pip; register struct amii_WinDesc *cw; struct IntuiMessage *imsg; struct Gadget *gd; register int wheight, xsize, ysize, aredone = 0; register int txwd, txh; long mics, secs, class, code; long oldmics = 0, oldsecs = 0; int aidx, oidx, topidx, hidden; int totalvis; SHORT mx, my; static char title[ 100 ]; int dosize = 1; struct Screen *scrn = HackScreen; int x1,x2,y1,y2; long counting = FALSE, count = 0, reset_counting = FALSE; char countString[32]; if( win == WIN_ERR || ( cw = amii_wins[ win ] ) == NULL ) panic(winpanicstr,win,"DoMenuScroll"); /* Initial guess at window sizing values */ txwd = txwidth; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) txh = max( txheight, pictdata.ysize + 3 ); /* interline space */ else txh = txheight; /* interline space */ } else txh = txheight; /* interline space */ /* Check to see if we should open the window, should need to for * TEXT and MENU but not MESSAGE. */ w = cw->win; topidx = 0; if( w == NULL ) { #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { PropScroll.Flags |= PROPNEWLOOK; } #endif nw = (void *)DupNewWindow( (void *)(&new_wins[ cw->type ].newwin) ); if( !alwaysinvent || win != WIN_INVEN ) { xsize = scrn->WBorLeft + scrn->WBorRight + MenuScroll.Width + 1 + (txwd * cw->maxcol); if( WINVERS_AMIV ) { if( win == WIN_INVEN ) xsize += pictdata.xsize + 4; } if( xsize > amiIDisplay->xpix ) xsize = amiIDisplay->xpix; /* If next row not off window, use it, else use the bottom */ ysize = ( txh * cw->maxrow ) + /* The text space */ HackScreen->WBorTop + txheight + 1 + /* Top border */ HackScreen->WBorBottom + 3; /* The bottom border */ if( ysize > amiIDisplay->ypix ) ysize = amiIDisplay->ypix; /* Adjust the size of the menu scroll gadget */ nw->TopEdge = 0; if( cw->type == NHW_TEXT && ysize < amiIDisplay->ypix ) nw->TopEdge += ( amiIDisplay->ypix - ysize ) / 2; nw->LeftEdge = amiIDisplay->xpix - xsize; if( cw->type == NHW_MENU ) { if( nw->LeftEdge > 10 ) nw->LeftEdge -= 10; else nw->LeftEdge = 0; if( amiIDisplay->ypix - nw->Height > 10 ) nw->TopEdge += 10; else nw->TopEdge = amiIDisplay->ypix - nw->Height - 1; } if( cw->type == NHW_TEXT && xsize < amiIDisplay->xpix ) nw->LeftEdge -= ( amiIDisplay->xpix - xsize ) / 2; } else if( win == WIN_INVEN ) { struct Window *mw = amii_wins[ WIN_MAP ]->win; struct Window *sw = amii_wins[ WIN_STATUS ]->win; xsize = scrn->WBorLeft + scrn->WBorRight + MenuScroll.Width + 1 + (txwd * cw->maxcol); /* Make space for the glyph to appear at the left of the description */ if( WINVERS_AMIV ) xsize += pictdata.xsize + 4; if( xsize > amiIDisplay->xpix ) xsize = amiIDisplay->xpix; /* If next row not off window, use it, else use the bottom */ ysize = sw->TopEdge - (mw->TopEdge + mw->Height) - 1; if( ysize > amiIDisplay->ypix ) ysize = amiIDisplay->ypix; /* Adjust the size of the menu scroll gadget */ nw->TopEdge = mw->TopEdge + mw->Height; nw->LeftEdge = 0; } cw->newwin = (void *)nw; if( nw == NULL ) panic("No NewWindow Allocated" ); nw->Screen = HackScreen; if( win == WIN_INVEN ) { sprintf( title, "%s the %s's Inventory", plname, pl_character ); nw->Title = title; if( lastinvent.MaxX != 0 ) { nw->LeftEdge = lastinvent.MinX; nw->TopEdge = lastinvent.MinY; nw->Width = lastinvent.MaxX; nw->Height = lastinvent.MaxY; } } else if( cw->morestr ) nw->Title = cw->morestr; /* Adjust the window coordinates and size now that we know * how many items are to be displayed. */ if( ( xsize > amiIDisplay->xpix - nw->LeftEdge ) && ( xsize < amiIDisplay->xpix ) ) { nw->LeftEdge = amiIDisplay->xpix - xsize; nw->Width = xsize; } else { nw->Width = min( xsize, amiIDisplay->xpix - nw->LeftEdge ); } nw->Height = min( ysize, amiIDisplay->ypix - nw->TopEdge ); if( WINVERS_AMIV || WINVERS_AMII ) { /* Make sure we are using the correct hook structure */ nw->Extension = cw->wintags; } /* Now, open the window */ w = cw->win = OpenShWindow( (void *)nw ); if( w == NULL ) { char buf[ 130 ]; sprintf( buf, "No Window Opened For Menu (%d,%d,%d-%d,%d-%d)", nw->LeftEdge, nw->TopEdge, nw->Width, amiIDisplay->xpix, nw->Height, amiIDisplay->ypix ); panic( buf ); } #ifdef HACKFONT if( TextsFont ) SetFont(w->RPort, TextsFont ); else if( HackFont ) SetFont(w->RPort, HackFont ); #endif txwd = w->RPort->TxWidth; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) txh = max( w->RPort->TxHeight, pictdata.ysize + 3 ); /* interline space */ else txh = w->RPort->TxHeight; /* interline space */ } else txh = w->RPort->TxHeight; /* interline space */ /* subtract 2 to account for spacing away from border (1 on each side) */ wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / txh; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3 ) / txwd; } else { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } } else { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } totalvis = CountLines( win ); } else { txwd = w->RPort->TxWidth; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) txh = max( w->RPort->TxHeight, pictdata.ysize + 3 ); /* interline space */ else txh = w->RPort->TxHeight; /* interline space */ } else { txh = w->RPort->TxHeight; /* interline space */ } /* subtract 2 to account for spacing away from border (1 on each side) */ wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / txh; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } else { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } totalvis = CountLines( win ); for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( gd ) { pip = (struct PropInfo *)gd->SpecialInfo; hidden = max( totalvis - wheight, 0 ); topidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; } } for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( !gd ) panic("Can't find scroll gadget" ); morc = 0; oidx = -1; #if 0 /* Make sure there are no selections left over from last time. */ /* XXX potential problem for preselection if this is really needed */ for( amip = cw->menu.items; amip; amip = amip->next ) amip->selected = 0; #endif DisplayData( win, topidx ); /* Make the prop gadget the right size and place */ SetPropInfo( w, gd, wheight, totalvis, topidx ); oldsecs = oldmics = 0; /* If window already up, don't stop to process events */ if( cw->wasup ) { aredone = 1; cw->wasup = 0; } while( !aredone ) { /* Process window messages */ WaitPort( w->UserPort ); while( imsg = (struct IntuiMessage * ) GetMsg( w->UserPort ) ) { class = imsg->Class; code = imsg->Code; mics = imsg->Micros; secs = imsg->Seconds; gd = (struct Gadget *) imsg->IAddress; mx = imsg->MouseX; my = imsg->MouseY; /* Only do our window or VANILLAKEY from other windows */ if( imsg->IDCMPWindow != w && class != VANILLAKEY && class != RAWKEY ) { ReplyMsg( (struct Message *) imsg ); continue; } /* Do DeadKeyConvert() stuff if RAWKEY... */ if( class == RAWKEY ) { class = VANILLAKEY; code = ConvertKey( imsg ); } ReplyMsg( (struct Message *) imsg ); switch( class ) { case NEWSIZE: /* * Ignore every other newsize, no action needed, * except RefreshWindowFrame() in case borders got overwritten * for some reason. It should not happen, but ... */ if( !dosize ) { RefreshWindowFrame(w); dosize = 1; break; } if( win == WIN_INVEN ) { lastinvent.MinX = w->LeftEdge; lastinvent.MinY = w->TopEdge; lastinvent.MaxX = w->Width; lastinvent.MaxY = w->Height; } else if( win == WIN_MESSAGE ) { lastmsg.MinX = w->LeftEdge; lastmsg.MinY = w->TopEdge; lastmsg.MaxX = w->Width; lastmsg.MaxY = w->Height; } /* Find the gadget */ for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( !gd ) panic("Can't find scroll gadget" ); totalvis = CountLines( win ); wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2) / txh; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } else { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } if( wheight < 2 ) wheight = 2; /* * Clear the right side & bottom. Parts of letters are not erased by * amii_cl_end if window shrinks and columns decrease. */ if ( WINVERS_AMII || WINVERS_AMIV ) { amii_setfillpens(w, cw->type); SetDrMd(w->RPort, JAM2); x2 = w->Width - w->BorderRight; y2 = w->Height - w->BorderBottom; x1 = x2 - w->IFont->tf_XSize - w->IFont->tf_XSize; y1 = w->BorderTop; if (x1 < w->BorderLeft) x1 = w->BorderLeft; RectFill(w->RPort, x1, y1, x2, y2); x1 = w->BorderLeft; y1 = y1 - w->IFont->tf_YSize; RectFill(w->RPort, x1, y1, x2, y2); RefreshWindowFrame(w); } /* Make the prop gadget the right size and place */ DisplayData( win, topidx ); SetPropInfo( w, gd, wheight, totalvis, topidx ); /* Force the window to a text line boundary <= to * what the user dragged it to. This eliminates * having to clean things up on the bottom edge. */ SizeWindow( w, 0, ( wheight * txh) + w->BorderTop + w->BorderBottom + 2 - w->Height ); /* Don't do next NEWSIZE, we caused it */ dosize = 0; oldsecs = oldmics = 0; break; case VANILLAKEY: #define CTRL(x) ((x)-'@') morc = code = map_menu_cmd(code); if (code == MENU_SELECT_ALL) { if (how == PICK_ANY) { amip = cw->menu.items; while (amip) { if (amip->canselect && amip->selector) { /* * Select those yet unselected * and apply count if necessary */ if (!amip->selected) { amip->selected = TRUE; if (counting) { amip->count = count; reset_counting = TRUE; /* * This makes the assumption that * the string is in format "X - foo" * with additional selecting and formatting * data in front (size SOFF) */ amip->str[SOFF+2] = '#'; } else { amip->count = -1; amip->str[SOFF+2] = '-'; } } } amip=amip->next; } DisplayData(win, topidx); } } else if (code == MENU_UNSELECT_ALL) { if (how == PICK_ANY) { amip = cw->menu.items; while (amip) { if (amip->selected) { amip->selected = FALSE; amip->count = -1; amip->str[SOFF+2] = '-'; } amip=amip->next; } DisplayData(win, topidx); } } else if (code == MENU_INVERT_ALL) { if (how == PICK_ANY) { amip = cw->menu.items; while (amip) { if (amip->canselect && amip->selector) { amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; amip->str[SOFF+2] = '#'; reset_counting = TRUE; } else { amip->count = -1; amip->str[SOFF+2] = '-'; } } amip=amip->next; } DisplayData(win, topidx); } } else if (code == MENU_SELECT_PAGE) { if (how == PICK_ANY) { int i = 0; amip = cw->menu.items; while (amip && i++ < topidx) amip = amip->next; for (i=0;i < wheight && amip; i++, amip=amip->next) { if (amip->canselect && amip->selector) { if (!amip->selected) { if (counting) { amip->count = count; reset_counting = TRUE; amip->str[SOFF+2] = '#'; } else { amip->count = -1; amip->str[SOFF+2] = '-'; } } amip->selected = TRUE; } } DisplayData(win, topidx); } } else if (code == MENU_UNSELECT_PAGE) { if (how == PICK_ANY) { int i = 0; amip = cw->menu.items; while (amip && i++ < topidx) amip = amip->next; for (i=0;i < wheight && amip; i++, amip=amip->next) { if (amip->selected) { amip->selected = FALSE; amip->count = -1; amip->str[SOFF+2] = '-'; } } DisplayData(win, topidx); } } else if (code == MENU_INVERT_PAGE) { if (how == PICK_ANY) { int i = 0; amip = cw->menu.items; while (amip && i++ < topidx) amip = amip->next; for (i=0;i < wheight && amip; i++, amip=amip->next) { if (amip->canselect && amip->selector) { amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; amip->str[SOFF+2] = '#'; reset_counting = TRUE; } else { amip->count = -1; amip->str[SOFF+2] = '-'; } } } DisplayData(win, topidx); } } else if (code == MENU_SEARCH && cw->type == NHW_MENU) { if (how == PICK_ONE || how == PICK_ANY) { char buf[BUFSZ]; amip = cw->menu.items; amii_getlin("Search for:", buf); if (!*buf || *buf == '\033') break; while (amip) { if (amip->canselect && amip->selector && amip->str && strstri(&amip->str[SOFF], buf)) { if (how == PICK_ONE) { amip->selected = TRUE; aredone = 1; break; } amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; reset_counting = TRUE; amip->str[SOFF+2] = '#'; } else { amip->count = -1; reset_counting = TRUE; amip->str[SOFF+2] = '-'; } } amip = amip->next; } } DisplayData(win, topidx); } else if (how == PICK_ANY && isdigit(code) && (counting || (!counting && code !='0'))) { if (count < LARGEST_INT) { count = count*10 + (long)(code-'0'); if (count > LARGEST_INT) count = LARGEST_INT; if (count > 0) { counting = TRUE; reset_counting = FALSE; } else { reset_counting = TRUE; } sprintf(countString, "Count: %d", count); pline(countString); } } else if( code == CTRL('D') || code == CTRL('U') || code == MENU_NEXT_PAGE || code == MENU_PREVIOUS_PAGE || code == MENU_FIRST_PAGE || code == MENU_LAST_PAGE ) { int endcnt, i; for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( !gd ) panic("Can't find scroll gadget" ); endcnt = wheight; /* /2; */ if( endcnt == 0 ) endcnt = 1; if (code == MENU_FIRST_PAGE) { topidx = 0; } else if (code == MENU_LAST_PAGE) { topidx = cw->maxrow - wheight; } else for( i = 0; i < endcnt; ++i ) { if (code == CTRL('D') || code == MENU_NEXT_PAGE) { if( topidx + wheight < cw->maxrow ) ++topidx; else break; } else if (code = CTRL('U') || code == MENU_PREVIOUS_PAGE) { if( topidx > 0 ) --topidx; else break; } } /* Make prop gadget the right size and place */ DisplayData( win, topidx ); SetPropInfo( w,gd, wheight, totalvis, topidx ); oldsecs = oldmics = 0; } else if( code == '\b' ) { for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( !gd ) panic("Can't find scroll gadget" ); if( topidx - wheight - 2 < 0 ) { topidx = 0; } else { topidx -= wheight - 2; } DisplayData( win, topidx ); SetPropInfo( w, gd, wheight, totalvis, topidx ); oldsecs = oldmics = 0; } else if( code == ' ' ) { for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( !gd ) panic("Can't find scroll gadget" ); if( topidx + wheight >= cw->maxrow ) { morc = 0; aredone = 1; } else { /* If there are still lines to be seen */ if( cw->maxrow > topidx + wheight ) { if( wheight > 2 ) topidx += wheight - 2; else ++topidx; DisplayData( win, topidx ); SetPropInfo( w, gd, wheight, totalvis, topidx ); } oldsecs = oldmics = 0; } } else if( code == '\n' || code == '\r' ) { for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( !gd ) panic("Can't find scroll gadget" ); /* If all line displayed, we are done */ if( topidx + wheight >= cw->maxrow ) { morc = 0; aredone = 1; } else { /* If there are still lines to be seen */ if( cw->maxrow > topidx + 1 ) { ++topidx; DisplayData( win, topidx ); SetPropInfo( w, gd, wheight, totalvis, topidx ); } oldsecs = oldmics = 0; } } else if( code == '\33' ) { if (counting) { reset_counting = TRUE; } else { aredone = 1; } } else { int selected = FALSE; for( amip = cw->menu.items; amip; amip = amip->next ) { if( amip->selector == code ) { if( how == PICK_ONE ) aredone = 1; amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; reset_counting = TRUE; amip->str[SOFF+2] = '#'; } else { amip->count = -1; reset_counting = TRUE; amip->str[SOFF+2] = '-'; } selected = TRUE; } else if (amip->gselector == code ) { amip->selected = !amip->selected; if (counting) { amip->count = count; reset_counting = TRUE; amip->str[SOFF+2] = '#'; } else { amip->count = -1; reset_counting = TRUE; amip->str[SOFF+2] = '-'; } selected = TRUE; } } if (selected) DisplayData( win, topidx ); } break; case CLOSEWINDOW: if( win == WIN_INVEN ) { lastinvent.MinX = w->LeftEdge; lastinvent.MinY = w->TopEdge; lastinvent.MaxX = w->Width; lastinvent.MaxY = w->Height; } else if( win == WIN_MESSAGE ) { lastmsg.MinX = w->LeftEdge; lastmsg.MinY = w->TopEdge; lastmsg.MaxX = w->Width; lastmsg.MaxY = w->Height; } aredone = 1; morc = '\33'; break; case GADGETUP: if( win == WIN_MESSAGE ) aredone = 1; for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; pip = (struct PropInfo *)gd->SpecialInfo; totalvis = CountLines( win ); hidden = max( totalvis - wheight, 0 ); aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; if( aidx != topidx ) DisplayData( win, topidx = aidx ); break; case MOUSEMOVE: for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; pip = (struct PropInfo *)gd->SpecialInfo; totalvis = CountLines( win ); hidden = max( totalvis - wheight, 0 ); aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; if( aidx != topidx ) DisplayData( win, topidx = aidx ); break; case INACTIVEWINDOW: if( win == WIN_MESSAGE || ( win == WIN_INVEN && alwaysinvent ) ) aredone = 1; break; case MOUSEBUTTONS: if( ( code == SELECTUP || code == SELECTDOWN ) && cw->type == NHW_MENU && how != PICK_NONE ) { /* Which one is the mouse pointing at? */ aidx = ( ( my - w->BorderTop - 1 ) / txh ) + topidx; /* If different lines, don't select double click */ if( aidx != oidx ) { oldsecs = 0; oldmics = 0; } /* If releasing, check for double click */ if( code == SELECTUP ) { amip = find_menu_item( cw, aidx ); if( aidx == oidx ) { if( DoubleClick( oldsecs, oldmics, secs, mics ) ) { aredone = 1; } oldsecs = secs; oldmics = mics; } else { amip = find_menu_item( cw, oidx ); amip->selected = 0; amip->count = -1; reset_counting = TRUE; if (amip->canselect && amip->selector) amip->str[SOFF+2] = '-'; } if (counting && amip->selected && amip->canselect && amip->selector) { amip->count = count; reset_counting = TRUE; amip->str[SOFF+2] = '#'; } DisplayData( win, topidx ); } else if( aidx - topidx < wheight && aidx < cw->maxrow && code == SELECTDOWN ) { /* Remove old highlighting if visible */ amip = find_menu_item( cw, oidx ); if( amip && oidx != aidx && ( oidx > topidx && oidx - topidx < wheight ) ) { if( how != PICK_ANY ) { amip->selected = 0; amip->count = -1; reset_counting = TRUE; if (amip->canselect && amip->selector) amip->str[SOFF+2] = '-'; } oidx = -1; } amip = find_menu_item( cw, aidx ); if( amip && amip->canselect && amip->selector && how != PICK_NONE ) { oidx = aidx; if( !DoubleClick( oldsecs, oldmics, secs, mics ) ) { amip->selected = !amip->selected; if (counting && amip->selected) { amip->count = count; reset_counting = TRUE; amip->str[SOFF+2] = '#'; } else { amip->count = -1; reset_counting = TRUE; if (amip->canselect && amip->selector) amip->str[SOFF+2] = '-'; } } } else { DisplayBeep( NULL ); oldsecs = 0; oldmics = 0; } DisplayData( win, topidx ); } } else { DisplayBeep( NULL ); } break; } if (!counting && morc == '\33') { amip = cw->menu.items; while (amip) { if (amip->canselect && amip->selector) { amip->selected = FALSE; amip->count = -1; amip->str[SOFF+2] = '-'; } amip=amip->next; } } if (reset_counting) { count = 0; if (counting) pline("Count: 0"); counting = FALSE; } } } /* Force a cursor reposition before next message output */ if( win == WIN_MESSAGE ) cw->curx = -1; return( make_menu_items( cw, retmip ) ); } void ReDisplayData( win ) winid win; { int totalvis; register struct amii_WinDesc *cw; register struct Window *w; register struct Gadget *gd; unsigned long hidden, aidx, wheight; struct PropInfo *pip; if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) ) return; for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( !gd ) return; wheight = (w->Height - w->BorderTop - w->BorderBottom-2)/w->RPort->TxHeight; pip = (struct PropInfo *)gd->SpecialInfo; totalvis = CountLines( win ); hidden = max( totalvis - wheight, 0 ); aidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; clear_nhwindow( win ); DisplayData( win, aidx ); } long FindLine( win, line ) winid win; int line; { int txwd; register char *t; register struct amii_WinDesc *cw; register struct Window *w; register int i, disprow, len; int col = -1; if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) ) { panic( winpanicstr, win, "No Window in FindLine" ); } txwd = w->RPort->TxWidth; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } else { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } disprow = 0; for( col = i = 0; line > disprow && i < cw->maxrow; ++i ) { t = cw->data[ i ] + SOFF; if( cw->data[i][1] >= 0 ) { ++disprow; col = 0; } while( *t ) { len = strlen( t ); if( col + len > cw->cols ) len = cw->cols - col; while( len > 0 ) { if( !t[len] || t[len] == ' ' ) break; --len; } if( len == 0 ) { while ( *t && *t != ' ') { t++; col++; } } else { t += len; col += len; } if( *t ) { while( *t == ' ' ) ++t; col = 0; ++disprow; } } } return( i ); } long CountLines( win ) winid win; { int txwd; amii_menu_item *mip; register char *t; register struct amii_WinDesc *cw; register struct Window *w; register int i, disprow, len; int col = -1; if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) ) { panic( winpanicstr, win, "No Window in CountLines" ); } txwd = w->RPort->TxWidth; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } else { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } disprow = cw->maxrow; mip = cw->menu.items; for( col = i = 0; i < cw->maxrow; ++i ) { t = cw->data[ i ] + SOFF; if( cw->type == NHW_MESSAGE && cw->data[ i ][ SEL_ITEM ] < 0 ) --disprow; else col = 0; while( *t ) { len = strlen( t ); if( col + len > cw->cols ) len = cw->cols - col; while( len > 0 ) { if( !t[len] || t[len] == ' ' ) break; --len; } if( len == 0 ) { while ( *t && *t != ' ') { t++; col++; } } else { t += len; col += len; } if( *t ) { while( *t == ' ' ) ++t; col = 0; ++disprow; } } } return( disprow ); } void DisplayData( win, start ) winid win; int start; { int txwd; amii_menu_item *mip; register char *t; register struct amii_WinDesc *cw; register struct Window *w; register struct RastPort *rp; register int i, disprow, len, wheight; int whichcolor = -1; int col; if( win == WIN_ERR || !(cw = amii_wins[win]) || !( w = cw->win ) ) { panic( winpanicstr, win, "No Window in DisplayData" ); } rp = w->RPort; SetDrMd( rp, JAM2 ); if( WINVERS_AMIV && win == WIN_INVEN ) { wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / max( rp->TxHeight, pictdata.ysize + 3 ); } else { wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / rp->TxHeight; } cw->rows = wheight; txwd = rp->TxWidth; if( WINVERS_AMIV ) { if( win == WIN_INVEN ) { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 - pictdata.xsize - 3) / txwd; } else cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } else { cw->cols = ( w->Width - w->BorderLeft - w->BorderRight - 4 ) / txwd; } /* Get the real line to display at */ start = FindLine( win, start ); mip = cw->menu.items; for( i = 0; mip && i < start; ++i ) { mip = mip->next; } /* Skip any initial response to a previous line */ if( cw->type == NHW_MESSAGE && mip && mip->selected < 0 ) ++start; if( WINVERS_AMIV && cw->type == NHW_MESSAGE ) SetAPen( rp, amii_msgAPen ); for( disprow = i = start; disprow < wheight + start; i++ ) { /* Just erase unused lines in the window */ if( i >= cw->maxrow ) { if (WINVERS_AMIV && win == WIN_INVEN) { amii_curs( win, 0, disprow - start ); amiga_print_glyph( win, 0, NO_GLYPH); } amii_curs( win, 1, disprow - start ); amii_cl_end( cw, 0 ); ++disprow; continue; } /* Any string with a highlighted attribute goes * onto the end of the current line in the message window. */ if( cw->type == NHW_MESSAGE ) SetAPen( rp, cw->data[ i ][ SEL_ITEM ] < 0 ? C_RED : amii_msgAPen ); /* Selected text in the message window goes onto the end of the current line */ if( cw->type != NHW_MESSAGE || cw->data[ i ][ SEL_ITEM ] >= 0 ) { amii_curs( win, 1, disprow - start ); if( WINVERS_AMIV && win == WIN_INVEN ) { if( mip ) amiga_print_glyph( win, 0, mip->glyph ); amii_curs( win, 1, disprow - start ); } col = 0; } /* If this entry is to be highlighted, do so */ if( mip && mip->selected != 0 ) { if( whichcolor != 1 ) { SetDrMd( rp, JAM2 ); if( WINVERS_AMIV ) { SetAPen( rp, amii_menuBPen ); SetBPen( rp, C_BLUE ); } else { SetAPen( rp, C_BLUE ); SetBPen( rp, amii_menuAPen ); } whichcolor = 1; } } else if( whichcolor != 2 ) { SetDrMd( rp, JAM2 ); if( cw->type == NHW_MESSAGE ) { SetAPen( rp, amii_msgAPen ); SetBPen( rp, amii_msgBPen ); } else if( cw->type == NHW_MENU ) { SetAPen( rp, amii_menuAPen ); SetBPen( rp, amii_menuBPen ); } else if( cw->type == NHW_TEXT ) { SetAPen( rp, amii_textAPen ); SetBPen( rp, amii_textBPen ); } whichcolor = 2; } /* Next line out, wrap if too long */ t = cw->data[ i ] + SOFF; ++disprow; col = 0; while( *t ) { len = strlen( t ); if( len > (cw->cols - col) ) len = cw->cols - col; while( len > 0 ) { if( !t[len] || t[len] == ' ' ) break; --len; } if( len == 0 ) { Text( rp, t, cw->cols - col ); while ( *t && *t != ' ') { t++; col++; } } else { Text( rp, t, len ); t += len; col += len; } amii_cl_end( cw, col ); if( *t ) { ++disprow; /* Stop at the bottom of the window */ if( disprow > wheight + start ) break; while( *t == ' ' ) ++t; amii_curs( win, 1, disprow - start - 1 ); if( mip && win == WIN_INVEN && WINVERS_AMIV ) { /* Erase any previous glyph drawn here. */ amiga_print_glyph( win, 0, NO_GLYPH ); amii_curs( win, 1, disprow - start - 1 ); } Text( rp, "+", 1 ); col = 1; } } if( cw->type == NHW_MESSAGE ) { SetAPen( rp, amii_msgBPen ); SetBPen( rp, amii_msgBPen ); } else if( cw->type == NHW_MENU ) { SetAPen( rp, amii_menuBPen ); SetBPen( rp, amii_menuBPen ); } else if( cw->type == NHW_TEXT ) { SetAPen( rp, amii_textBPen ); SetBPen( rp, amii_textBPen ); } amii_cl_end( cw, col ); whichcolor = -1; if( mip ) mip = mip->next; } RefreshWindowFrame(w); return; } void SetPropInfo( win, gad, vis, total, top ) register struct Window *win; register struct Gadget *gad; register long vis, total, top; { long mflags; register long hidden; register int body, pot; hidden = max( total-vis, 0 ); /* Force the last section to be just to the bottom */ if( top > hidden ) top = hidden; /* Scale the body position. */ /* 2 lines overlap */ if( hidden > 0 && total > 2) body = (ULONG) ((vis - 2) * MAXBODY) / (total - 2); else body = MAXBODY; if( hidden > 0 ) pot = (ULONG) (top * MAXPOT) / hidden; else pot = 0; mflags = AUTOKNOB|FREEVERT; #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { mflags |= PROPNEWLOOK; } #endif NewModifyProp( gad, win, NULL, mflags, 0, pot, MAXBODY, body, 1 ); } nethack-3.4.3/sys/amiga/winproto.h0100644000000000000000000001226407764735041015605 0ustar rootroot/* SCCS Id: @(#)winproto.h 3.2 96/01/15 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ /* winreq.c */ void EditColor ( void ); void EditClipping( void ); void DrawCol ( struct Window *w , int idx , UWORD *colors ); void DispCol ( struct Window *w , int idx , UWORD *colors ); void amii_change_color( int, long, int ); char *amii_get_color_string( ); void amii_getlin ( const char *prompt , char *bufp ); void getlind ( const char *prompt , char *bufp , const char *dflt ); char *amii_get_color_string( void ); int filecopy( char *from, char *to ); char *basename( char *str ); char *dirname( char *str ); /* winstr.c */ void amii_putstr ( winid window , int attr , const char *str ); void outmore ( struct amii_WinDesc *cw ); void outsubstr ( struct amii_WinDesc *cw , char *str , int len, int fudge ); void amii_putsym ( winid st , int i , int y , CHAR_P c ); void amii_addtopl ( const char *s ); void TextSpaces ( struct RastPort *rp , int nr ); void amii_remember_topl ( void ); long CountLines( winid ); long FindLine( winid, int ); int amii_doprev_message ( void ); void flushIDCMP( struct MsgPort * ); int amii_msgborder( struct Window * ); void amii_scrollmsg( register struct Window *w, register struct amii_WinDesc *cw ); /* winkey.c */ int amii_nh_poskey ( int *x , int *y , int *mod ); int amii_nhgetch ( void ); void amii_get_nh_event ( void ); void amii_getret ( void ); /* winmenu.c */ void amii_start_menu ( winid window ); void FDECL(amii_add_menu, (winid,int,const anything *,CHAR_P,CHAR_P,int,const char *,BOOLEAN_P)); void FDECL(amii_end_menu, (winid, const char *)); int FDECL(amii_select_menu, (winid, int, menu_item **)); int DoMenuScroll ( int win , int blocking, int how, menu_item ** ); void ReDisplayData ( winid win ); void DisplayData ( winid win , int start ); void SetPropInfo ( struct Window *win , struct Gadget *gad , long vis , long total , long top ); /* amiwind.c */ struct Window *OpenShWindow ( struct NewWindow *nw ); void CloseShWindow ( struct Window *win ); int ConvertKey ( struct IntuiMessage *message ); int kbhit ( void ); int kbhit ( void ); int amikbhit ( void ); int WindowGetchar ( void ); WETYPE WindowGetevent ( void ); void amii_cleanup ( void ); #ifndef SHAREDLIB void Abort ( long rc ); #endif void CleanUp ( void ); void flush_glyph_buffer ( struct Window *w ); void amiga_print_glyph ( winid window , int color_index , int glyph ); void start_glyphout ( winid window ); void amii_end_glyphout ( winid window ); struct NewWindow *DupNewWindow ( struct NewWindow *win ); void FreeNewWindow ( struct NewWindow *win ); void bell ( void ); void amii_delay_output ( void ); void amii_number_pad ( int state ); #ifndef SHAREDLIB void amiv_loadlib ( void ); void amii_loadlib ( void ); #endif void preserve_icon( void ); void clear_icon( void ); /* winfuncs.c */ void amii_destroy_nhwindow ( winid win ); int amii_create_nhwindow ( int type ); void amii_init_nhwindows ( int *, char ** ); void amii_setdrawpens( struct Window *, int type ); void amii_sethipens( struct Window *, int type, int attr ); void amii_setfillpens( struct Window *, int type ); void amii_clear_nhwindow ( winid win ); void dismiss_nhwindow ( winid win ); void amii_exit_nhwindows ( const char *str ); void amii_display_nhwindow ( winid win , boolean blocking ); void amii_curs ( winid window , int x , int y ); void kill_nhwindows ( int all ); void amii_cl_end ( struct amii_WinDesc *cw , int i ); void cursor_off ( winid window ); void cursor_on ( winid window ); void amii_suspend_nhwindows ( const char *str ); void amii_resume_nhwindows ( void ); void amii_bell ( void ); void removetopl ( int cnt ); void port_help ( void ); void amii_print_glyph ( winid win , xchar x , xchar y , int glyph ); void amii_raw_print ( const char *s ); void amii_raw_print_bold ( const char *s ); void amii_update_inventory ( void ); void amii_mark_synch ( void ); void amii_wait_synch ( void ); void amii_setclipped ( void ); void amii_cliparound ( int x , int y ); void amii_set_text_font( char *font, int size ); BitMapHeader ReadImageFiles( char **, struct BitMap **, char ** ); BitMapHeader ReadTileImageFiles(void); void FreeImageFiles( char **, struct BitMap ** ); void FreeTileImageFiles(); /* winami.c */ #ifdef SHAREDLIB int __UserLibInit ( void ); void __UserLibCleanup ( void ); #endif void amii_askname ( void ); void amii_player_selection ( void ); void RandomWindow ( char *name ); int amii_get_ext_cmd ( void ); char amii_yn_function ( const char *prompt , const char *resp , char def ); char amii_yn_function ( const char *query , const char *resp , char def ); void amii_display_file ( const char *fn , boolean complain ); void SetBorder ( struct Gadget *gd ); void *malloc ( register unsigned size ); void free ( void *q ); #ifdef SHAREDLIB /* amilib.c */ void amii_loadlib ( void ); void amiv_loadlib ( void ); void CleanUp ( void ); void setup_librefs ( WinamiBASE *base ); #else void Abort ( long rc ); #endif /* amirip.c */ void FDECL(amii_outrip, ( winid tmpwin, int how )); /* winchar.c */ void SetMazeType(MazeType); int GlyphToIcon(int glyph); #ifdef OPT_DISPMAP void dispmap_sanity(void); int dispmap_sanity1(int); #endif void FreeTileImageFiles(void); nethack-3.4.3/sys/amiga/winreq.c0100644000000000000000000006460607764735041015233 0ustar rootroot/* SCCS Id: @(#)winreq.c 3.1 93/04/02 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" #define GADBLUEPEN 2 #define GADREDPEN 3 #define GADGREENPEN 4 #define GADCOLOKAY 5 #define GADCOLCANCEL 6 #define GADCOLSAVE 7 UBYTE UNDOBUFFER[300]; SHORT BorderVectors1[] = { 0,0, 57,0, 57,11, 0,11, 0,0 }; struct Border Border1 = { -1,-1, 3,0,JAM1, 5, BorderVectors1, NULL }; struct IntuiText IText1 = { 3,0,JAM1, 4,1, NULL, (UBYTE *)"Cancel", NULL }; struct Gadget Gadget2 = { NULL, 9,15, 56,10, NULL, RELVERIFY, BOOLGADGET, (APTR)&Border1, NULL, &IText1, NULL, NULL, 1, NULL }; UBYTE StrStringSIBuff[300]; struct StringInfo StrStringSInfo = { StrStringSIBuff, UNDOBUFFER, 0, 300, 0, 0,0,0,0,0, 0, 0, NULL }; SHORT BorderVectors2[] = { 0,0, 439,0, 439,11, 0,11, 0,0 }; struct Border Border2 = { -1,-1, 3,0,JAM1, 5, BorderVectors2, NULL }; struct Gadget String = { &Gadget2, 77,15, 438,10, NULL, RELVERIFY+STRINGCENTER, STRGADGET, (APTR)&Border2, NULL, NULL, NULL, (APTR)&StrStringSInfo, 2, NULL }; #define StrString \ ((char *)(((struct StringInfo *)(String.SpecialInfo))->Buffer)) struct NewWindow StrWindow = { 57,74, 526,31, 0,1, GADGETUP+CLOSEWINDOW+ACTIVEWINDOW+VANILLAKEY, WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE+ACTIVATE+NOCAREREFRESH, &String, NULL, NULL, NULL, NULL, 5,5, 0xffff,0xffff, CUSTOMSCREEN }; #include "NH:sys/amiga/colorwin.c" #define XSIZE 2 #define YSIZE 3 #define XCLIP 4 #define YCLIP 5 #define GADOKAY 6 #define GADCANCEL 7 #include "NH:sys/amiga/clipwin.c" void ClearCol( struct Window *w ); void EditColor( ) { extern const char *configfile; int i, done = 0, okay = 0; long code, qual, class; register struct Gadget *gd, *dgad; register struct Window *nw; register struct IntuiMessage *imsg; register struct PropInfo *pip; register struct Screen *scrn; long aidx; int msx, msy; int curcol = 0, drag = 0; int bxorx, bxory, bxxlen, bxylen; static UWORD colors[ AMII_MAXCOLORS ]; static UWORD svcolors[ AMII_MAXCOLORS ]; static int once = 0; scrn = HackScreen; if( !once ) { if( WINVERS_AMIV ) { Col_NewWindowStructure1.Width += 300; Col_NewWindowStructure1.Height += 20; Col_NewWindowStructure1.LeftEdge -= 150; Col_BluePen.Width += 300; Col_RedPen.Width += 300; Col_GreenPen.Width += 300; Col_Cancel.LeftEdge += 300; Col_Okay.LeftEdge += 150; Col_Cancel.TopEdge += 20; Col_Save.TopEdge += 20; Col_Okay.TopEdge += 20; } SetBorder( &Col_Okay ); SetBorder( &Col_Cancel ); SetBorder( &Col_Save ); once = 1; } bxylen = Col_NewWindowStructure1.Height - ( Col_BluePen.TopEdge + Col_BluePen.Height + 6 ); bxxlen = Col_BluePen.Width; bxorx = Col_BluePen.LeftEdge; bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2; /* Save the current colors */ for( i = 0; i < amii_numcolors; ++i ) svcolors[ i ] = colors[ i ] = GetRGB4( scrn->ViewPort.ColorMap, i ); Col_NewWindowStructure1.Screen = scrn; #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { ((struct PropInfo *)Col_BluePen.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *)Col_RedPen.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *)Col_GreenPen.SpecialInfo)->Flags |= PROPNEWLOOK; } #endif if( WINVERS_AMIV || WINVERS_AMII ) { #ifdef INTUI_NEW_LOOK Col_NewWindowStructure1.Extension = wintags; Col_NewWindowStructure1.Flags |= WFLG_NW_EXTENDED; # ifdef __GNUC__ fillhook.h_Entry = (void *)&LayerFillHook; # else fillhook.h_Entry = (ULONG(*)())LayerFillHook; # endif fillhook.h_Data = (void *)-2; fillhook.h_SubEntry = 0; #endif } nw = OpenWindow( (void *)&Col_NewWindowStructure1 ); if( nw == NULL ) { DisplayBeep( NULL ); return; } PrintIText( nw->RPort, &Col_IntuiTextList1, 0, 0 ); ClearCol( nw ); DrawCol( nw, curcol, colors ); while( !done ) { WaitPort( nw->UserPort ); while( imsg = (struct IntuiMessage * )GetMsg( nw->UserPort ) ) { gd = (struct Gadget *)imsg->IAddress; code = imsg->Code; class = imsg->Class; qual = imsg->Qualifier; msx = imsg->MouseX; msy = imsg->MouseY; ReplyMsg( (struct Message *)imsg ); switch( class ) { case VANILLAKEY: if( code == 'v' && qual == AMIGALEFT ) okay = done = 1; else if( code == 'b' && qual == AMIGALEFT ) okay = 0, done = 1; else if( code == 'o' || code == 'O' ) okay = done = 1; else if( code == 'c' || code == 'C' ) okay = 0, done = 1; break; case CLOSEWINDOW: done = 1; break; case GADGETUP: drag = 0; if( gd->GadgetID == GADREDPEN || gd->GadgetID == GADBLUEPEN || gd->GadgetID == GADGREENPEN ) { pip = (struct PropInfo *)gd->SpecialInfo; aidx = pip->HorizPot / (MAXPOT/15); if( gd->GadgetID == GADREDPEN ) { colors[ curcol ] = ( colors[ curcol ] & ~0xf00 ) | (aidx << 8); LoadRGB4( &scrn->ViewPort, colors, amii_numcolors ); } else if( gd->GadgetID == GADBLUEPEN ) { colors[ curcol ] = ( colors[ curcol ] & ~0xf ) | aidx; LoadRGB4( &scrn->ViewPort, colors, amii_numcolors ); } else if( gd->GadgetID == GADGREENPEN ) { colors[ curcol ] = ( colors[ curcol ] & ~0x0f0 ) | (aidx << 4); LoadRGB4( &scrn->ViewPort, colors, amii_numcolors ); } DispCol( nw, curcol, colors ); } else if( gd->GadgetID == GADCOLOKAY ) { done = 1; okay = 1; } else if( gd->GadgetID == GADCOLSAVE ) { FILE *fp, *nfp; char buf[ 300 ], nname[ 300 ], oname[ 300 ]; int once = 0; fp = fopen( configfile, "r" ); if( !fp ) { pline( "can't find NetHack.cnf" ); break; } strcpy( oname, dirname( (char *)configfile ) ); if( oname[ strlen(oname)-1 ] != ':' ) { sprintf( nname, "%s/New_NetHack.cnf", oname ); strcat( oname, "/" ); strcat( oname, "Old_NetHack.cnf" ); } else { sprintf( nname, "%sNew_NetHack.cnf", oname ); strcat( oname, "Old_NetHack.cnf" ); } nfp = fopen( nname, "w" ); if( !nfp ) { pline( "can't write to New_NetHack.cnf" ); fclose( fp ); break; } while( fgets( buf, sizeof( buf ), fp ) ) { if( strncmp( buf, "PENS=", 5 ) == 0 ) { once = 1; fputs( "PENS=", nfp ); for( i = 0; i < amii_numcolors; ++i ) { fprintf( nfp, "%03x", colors[i] ); if(( i + 1 ) < amii_numcolors) putc( '/', nfp ); } putc( '\n', nfp ); } else { fputs( buf, nfp ); } } /* If none in the file yet, now write it */ if( !once ) { fputs( "PENS=", nfp ); for( i = 0; i < amii_numcolors; ++i ) { fprintf( nfp, "%03x", colors[i] ); if(( i + 1 ) < amii_numcolors) putc( ',', nfp ); } putc( '\n', nfp ); } fclose( fp ); fclose( nfp ); unlink( oname ); if( filecopy( (char *)configfile, oname ) == 0 ) if( filecopy( nname, (char *)configfile ) == 0 ) unlink( nname ); done = 1; okay = 1; } else if( gd->GadgetID == GADCOLCANCEL ) { done = 1; okay = 0; } break; case GADGETDOWN: drag = 1; dgad = gd; break; case MOUSEMOVE: if( !drag ) break; pip = (struct PropInfo *)dgad->SpecialInfo; aidx = pip->HorizPot / (MAXPOT/15); if( dgad->GadgetID == GADREDPEN ) { colors[ curcol ] = ( colors[ curcol ] & ~0xf00 ) | (aidx << 8); LoadRGB4( &scrn->ViewPort, colors, amii_numcolors ); } else if( dgad->GadgetID == GADBLUEPEN ) { colors[ curcol ] = ( colors[ curcol ] & ~0xf ) | aidx; LoadRGB4( &scrn->ViewPort, colors, amii_numcolors ); } else if( dgad->GadgetID == GADGREENPEN ) { colors[ curcol ] = ( colors[ curcol ] & ~0x0f0 ) | (aidx << 4); LoadRGB4( &scrn->ViewPort, colors, amii_numcolors ); } DispCol( nw, curcol, colors ); break; case MOUSEBUTTONS: if( code == SELECTDOWN ) { if( msy > bxory && msy < bxory + bxylen - 1 && msx > bxorx && msx < bxorx + bxxlen - 1 ) { curcol = ( msx - bxorx )/(bxxlen / amii_numcolors); if( curcol >= 0 && curcol < amii_numcolors ) DrawCol( nw, curcol, colors ); } } break; } } } if( okay ) { for( i = 0; i < ( amii_numcolors ); ++i ) flags.amii_curmap[ i ] = colors[ i ]; LoadRGB4( &scrn->ViewPort, flags.amii_curmap, amii_numcolors ); } else LoadRGB4( &scrn->ViewPort, svcolors, amii_numcolors ); CloseWindow( nw ); } void ShowClipValues( struct Window *nw ) { char buf[ 50 ]; struct Gadget *gd; SetAPen( nw->RPort, 5 ); SetBPen( nw->RPort, amii_otherBPen ); SetDrMd( nw->RPort, JAM2 ); sprintf( buf, "%d ", mxsize ); gd = &ClipXSIZE; Move( nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8, gd->TopEdge + nw->RPort->TxBaseline ); Text( nw->RPort, buf, strlen( buf ) ); sprintf( buf, "%d ", mysize ); gd = &ClipYSIZE; Move( nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8, gd->TopEdge + nw->RPort->TxBaseline ); Text( nw->RPort, buf, strlen( buf ) ); sprintf( buf, "%d ", xclipbord ); gd = &ClipXCLIP; Move( nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8, gd->TopEdge + nw->RPort->TxBaseline ); Text( nw->RPort, buf, strlen( buf ) ); sprintf( buf, "%d ", yclipbord ); gd = &ClipYCLIP; Move( nw->RPort, gd->LeftEdge + (nw->Width + gd->Width) + 8, gd->TopEdge + nw->RPort->TxBaseline ); Text( nw->RPort, buf, strlen( buf ) ); } void EditClipping( void ) { int i; long mflags; static int sizes[] = { 8, 16, 20, 24, 28, 32, 36 }; char buf[ 40 ]; int done = 0, okay = 0; long code, qual, class; register struct Gadget *gd, *dgad; register struct Window *nw; register struct IntuiMessage *imsg; register struct PropInfo *pip; register struct Screen *scrn; long aidx; int lmxsize = mxsize, lmysize = mysize; int lxclipbord = xclipbord, lyclipbord = yclipbord; int msx, msy; int drag = 0; static int once = 0; scrn = HackScreen; if( !once ) { SetBorder( &ClipOkay ); SetBorder( &ClipCancel ); once = 1; } ClipNewWindowStructure1.Screen = scrn; #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { ((struct PropInfo *)ClipXSIZE.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *)ClipYSIZE.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *)ClipXCLIP.SpecialInfo)->Flags |= PROPNEWLOOK; ((struct PropInfo *)ClipYCLIP.SpecialInfo)->Flags |= PROPNEWLOOK; } #endif if( WINVERS_AMIV || WINVERS_AMII ) { # ifdef INTUI_NEW_LOOK ClipNewWindowStructure1.Extension = wintags; ClipNewWindowStructure1.Flags |= WFLG_NW_EXTENDED; # ifdef __GNUC__ fillhook.h_Entry = (void *)&LayerFillHook; # else fillhook.h_Entry = (ULONG(*)())LayerFillHook; # endif fillhook.h_Data = (void *)-2; fillhook.h_SubEntry = 0; # endif } nw = OpenWindow( (void *)&ClipNewWindowStructure1 ); if( nw == NULL ) { DisplayBeep( NULL ); return; } ShowClipValues( nw ); mflags = AUTOKNOB|FREEHORIZ; #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { mflags |= PROPNEWLOOK; } #endif for( i = 0; i < 7; ++i ) { if( mxsize <= sizes[ i ] ) break; } NewModifyProp( &ClipXSIZE, nw, NULL, mflags, (i * MAXPOT ) / 6, 0, MAXPOT/6, 0, 1 ); for( i = 0; i < 7; ++i ) { if( mysize <= sizes[ i ] ) break; } NewModifyProp( &ClipYSIZE, nw, NULL, mflags, (i * MAXPOT ) / 6, 0, MAXPOT/6, 0, 1 ); NewModifyProp( &ClipXCLIP, nw, NULL, mflags, ((xclipbord-2) * MAXPOT ) / 6, 0, MAXPOT/6, 0, 1 ); NewModifyProp( &ClipYCLIP, nw, NULL, mflags, ((yclipbord-2) * MAXPOT ) / 6, 0, MAXPOT/6, 0, 1 ); while( !done ) { WaitPort( nw->UserPort ); while( imsg = (struct IntuiMessage * )GetMsg( nw->UserPort ) ) { gd = (struct Gadget *)imsg->IAddress; code = imsg->Code; class = imsg->Class; qual = imsg->Qualifier; msx = imsg->MouseX; msy = imsg->MouseY; ReplyMsg( (struct Message *)imsg ); switch( class ) { case VANILLAKEY: if( code == '\33' ) okay = 0, done = 1; else if( code == 'v' && qual == AMIGALEFT ) okay = done = 1; else if( code == 'b' && qual == AMIGALEFT ) okay = 0, done = 1; else if( code == 'o' || code == 'O' ) okay = done = 1; else if( code == 'c' || code == 'C' ) okay = 0, done = 1; break; case CLOSEWINDOW: done = 1; break; case GADGETUP: drag = 0; if( gd->GadgetID == XSIZE || gd->GadgetID == YSIZE || gd->GadgetID == XCLIP || gd->GadgetID == YCLIP ) { pip = (struct PropInfo *)gd->SpecialInfo; aidx = pip->HorizPot / (MAXPOT/6); if( gd->GadgetID == XSIZE ) { mxsize = sizes[ aidx ]; } else if( gd->GadgetID == YSIZE ) { mysize = sizes[ aidx ]; } else if( gd->GadgetID == XCLIP ) { xclipbord = aidx + 2; } else if( gd->GadgetID == YCLIP ) { yclipbord = aidx + 2; } ShowClipValues( nw ); #ifdef OPT_DISPMAP dispmap_sanity(); #endif } else if( gd->GadgetID == GADOKAY ) { done = 1; okay = 1; } else if( gd->GadgetID == GADCANCEL ) { done = 1; okay = 0; } ReportMouse( 0, nw ); reclip = 2; doredraw(); flush_glyph_buffer( amii_wins[ WIN_MAP ]->win ); reclip = 0; break; case GADGETDOWN: drag = 1; dgad = gd; ReportMouse( 1, nw ); break; case MOUSEMOVE: if( !drag ) break; pip = (struct PropInfo *)dgad->SpecialInfo; aidx = pip->HorizPot / (MAXPOT/6); Move( nw->RPort, dgad->LeftEdge + (nw->Width + dgad->Width) + 8, dgad->TopEdge + nw->RPort->TxBaseline ); if( dgad->GadgetID == XSIZE ) { mxsize = sizes[ aidx ]; sprintf( buf, "%d ",lmxsize ); } else if( dgad->GadgetID == YSIZE ) { mysize = sizes[ aidx ]; sprintf( buf, "%d ", mysize ); } else if( dgad->GadgetID == XCLIP ) { xclipbord = aidx + 2; sprintf( buf, "%d ", xclipbord ); } else if( dgad->GadgetID == YCLIP ) { yclipbord = aidx + 2; sprintf( buf, "%d ", yclipbord ); } SetAPen( nw->RPort, 5 ); SetBPen( nw->RPort, amii_otherBPen ); SetDrMd( nw->RPort, JAM2 ); Text( nw->RPort, buf, strlen( buf ) ); #ifdef OPT_DISPMAP dispmap_sanity(); #endif break; } } } CloseWindow( nw ); /* Restore oldvalues if cancelled. */ if( !okay ) { mxsize = lmxsize; mysize = lmysize; xclipbord = lxclipbord; yclipbord = lyclipbord; } } char *dirname( str ) char *str; { char *t, c; static char dir[ 300 ]; t = strrchr( str, '/' ); if( !t ) t = strrchr( str, ':' ); if( !t ) t = str; else { c = *t; *t = 0; strcpy( dir, str ); *t = c; } return( dir ); } char *basename( str ) char *str; { char *t; t = strrchr( str, '/' ); if( !t ) t = strrchr( str, ':' ); if( !t ) t = str; else ++t; return( t ); } filecopy( from, to ) char *from, *to; { char *buf; int i = 0; buf = (char *)alloc( strlen(to) + strlen(from) + 20 ); if( buf ) { sprintf( buf, "c:copy \"%s\" \"%s\" clone", from, to ); /* Check SysBase instead? Shouldn't matter */ #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) i = System( buf, NULL ); else #endif Execute( buf, NULL, NULL ); free( buf ); } else { return( -1 ); } return( i ); } /* The colornames, and the default values for the pens */ static struct COLDEF { char *name, *defval; }; struct COLDEF amii_colnames[ AMII_MAXCOLORS ] = { "Black","(000)", "White","(fff)", "Brown","(830)", "Cyan","(7ac)", "Green","(181)", "Magenta","(c06)", "Blue","(23e)", "Red","(c00)", }; struct COLDEF amiv_colnames[ AMII_MAXCOLORS ] = { "Black","(000)", "White","(fff)", "Cyan","(0bf)", "Orange","(f60)", "Blue","(00f)", "Green","(090)", "Grey","(69b)", "Red","(f00)", "Light Green","(6f0)", "Yellow","(ff0)", "Magenta","(f0f)", "Brown","(940)", "Grey Blue","(466)", "Light Brown","(c40)", "Light Grey","(ddb)", "Peach","(fb9)", "Col 16","(222)", "Col 17","(eee)", "Col 18","(000)", "Col 19","(ccc)", "Col 20","(bbb)", "Col 21","(aaa)", "Col 22","(999)", "Col 23","(888)", "Col 24","(777)", "Col 25","(666)", "Col 26","(555)", "Col 27","(444)", "Col 28","(333)", "Col 29","(18f)", "Col 30","(f81)", "Col 31","(fff)", }; void ClearCol( struct Window *w ) { int bxorx, bxory, bxxlen, bxylen; int incx, incy; bxylen = Col_Okay.TopEdge - ( Col_BluePen.TopEdge + Col_BluePen.Height ) - 1 - txheight - 3; bxxlen = Col_BluePen.Width - 2; bxorx = Col_BluePen.LeftEdge + 1; bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2; incx = bxxlen / amii_numcolors; incy = bxylen - 2; bxxlen /= incx; bxxlen *= incx; bxxlen += 2; SetAPen( w->RPort, C_WHITE ); SetDrMd( w->RPort, JAM1 ); RectFill( w->RPort, bxorx, bxory, bxorx + bxxlen + 1, bxory + bxylen ); SetAPen( w->RPort, C_BLACK ); RectFill( w->RPort, bxorx+1, bxory+1, bxorx + bxxlen, bxory + bxylen - 1); } void DrawCol( w, idx, colors ) struct Window *w; int idx; UWORD *colors; { int bxorx, bxory, bxxlen, bxylen; int i, incx, incy, r, g, b; long mflags; bxylen = Col_Okay.TopEdge - ( Col_BluePen.TopEdge + Col_BluePen.Height ) - 1 - txheight - 3; bxxlen = Col_BluePen.Width - 2; bxorx = Col_BluePen.LeftEdge + 1; bxory = Col_BluePen.TopEdge + Col_BluePen.Height + 2; incx = bxxlen / amii_numcolors; incy = bxylen - 2; bxxlen /= incx; bxxlen *= incx; bxxlen += 2; for( i = 0; i < amii_numcolors; ++i ) { int x, y; x = bxorx + 2 + (i*incx); y = bxory + 2; if( i == idx ) { SetAPen( w->RPort, flags.amii_dripens[ SHADOWPEN ] ); Move( w->RPort, x, y+bxylen-4 ); Draw( w->RPort, x, y ); Draw( w->RPort, x+incx-1, y ); Move( w->RPort, x+1, y+bxylen-5 ); Draw( w->RPort, x+1, y+1 ); Draw( w->RPort, x+incx-2, y+1 ); SetAPen( w->RPort, flags.amii_dripens[ SHINEPEN ] ); Move( w->RPort, x+incx-1, y+1 ); Draw( w->RPort, x+incx-1, y+bxylen-4 ); Draw( w->RPort, x, y+bxylen-4 ); Move( w->RPort, x+incx-2, y+2 ); Draw( w->RPort, x+incx-2, y+bxylen-5 ); Draw( w->RPort, x+1, y+bxylen-5 ); } else { SetAPen( w->RPort, C_BLACK ); Move( w->RPort, x, y ); Draw( w->RPort, x +incx-1, y ); Draw( w->RPort, x +incx-1, y +bxylen - 4 ); Draw( w->RPort, x, y + bxylen - 4 ); Draw( w->RPort, x, y ); SetAPen( w->RPort, C_BLACK ); Move( w->RPort, x+1, y+1 ); Draw( w->RPort, x +incx-2, y+1 ); Draw( w->RPort, x +incx-2, y +bxylen - 6 ); Draw( w->RPort, x+1, y + bxylen - 6 ); Draw( w->RPort, x+1, y+1 ); } SetAPen( w->RPort, i ); RectFill( w->RPort, x + 3, y + 3, x + incx - 4, y + bxylen - 6 ); } DispCol( w, idx, colors ); r = (colors[ idx ] & 0xf00) >> 8; g = (colors[ idx ] & 0x0f0) >> 4; b = colors[ idx ] & 0x00f; mflags = AUTOKNOB|FREEHORIZ; #ifdef INTUI_NEW_LOOK if( IntuitionBase->LibNode.lib_Version >= 37 ) { mflags |= PROPNEWLOOK; } #endif NewModifyProp( &Col_RedPen, w, NULL, mflags, (r * MAXPOT ) / 15, 0, MAXPOT/15, 0, 1 ); NewModifyProp( &Col_GreenPen, w, NULL, mflags, (g * MAXPOT ) / 15, 0, MAXPOT/15, 0, 1 ); NewModifyProp( &Col_BluePen, w, NULL, mflags, (b * MAXPOT ) / 15, 0, MAXPOT/15, 0, 1 ); } void DispCol( w, idx, colors ) struct Window *w; int idx; UWORD *colors; { char buf[ 50 ]; char *colname, *defval; if( WINVERS_AMIV ) { colname = amiv_colnames[idx].name; defval = amiv_colnames[idx].defval; } else { colname = amii_colnames[idx].name; defval = amii_colnames[idx].defval; } if( colname == NULL ) { colname = "unknown"; defval = "unknown"; } Move( w->RPort, Col_Save.LeftEdge, Col_Save.TopEdge - 7 ); sprintf( buf, "%s=%03x default=%s%s", colname, colors[idx], defval, " "+strlen(colname)+1 ); SetAPen( w->RPort, C_RED ); SetBPen( w->RPort, amii_otherBPen ); SetDrMd( w->RPort, JAM2 ); Text( w->RPort, buf, strlen( buf ) ); } void amii_setpens( int count ) { #ifdef INTUI_NEW_LOOK struct EasyStruct ea = { sizeof( struct EasyStruct ), 0l, "NetHack Request", "Number of pens requested(%ld) not correct", "Use default pens|Use requested pens" }; struct EasyStruct ea2 = { sizeof( struct EasyStruct ), 0l, "NetHack Request", "Number of pens requested(%ld) not\ncompatible with game configuration(%ld)", "Use default pens|Use requested pens" }; #endif /* If the pens in amii_curmap are * more pens than in amii_numcolors, then we choose to ignore * those pens. */ #ifdef INTUI_NEW_LOOK if( IntuitionBase && IntuitionBase->LibNode.lib_Version >= 39 ) { if( count != amii_numcolors ) { long args[2]; args[0] = count; args[1] = amii_numcolors; if( EasyRequest( NULL, &ea2, NULL, args ) == 1 ) { memcpy( flags.amii_curmap, amii_initmap, amii_numcolors*sizeof(amii_initmap[0])); } } } else if( IntuitionBase && IntuitionBase->LibNode.lib_Version >= 37 ) { if( count != amii_numcolors ) { if( EasyRequest( NULL, &ea, NULL, NULL ) == 1 ) { memcpy( flags.amii_curmap, amii_initmap, amii_numcolors*sizeof(amii_initmap[0])); } } } else #endif if( count != amii_numcolors ) { memcpy( flags.amii_curmap, amii_initmap, amii_numcolors*sizeof(amii_initmap[0])); } /* If the pens are set in NetHack.cnf, we can get called before * HackScreen has been opened. */ if( HackScreen != NULL ) { LoadRGB4( &HackScreen->ViewPort, flags.amii_curmap, amii_numcolors ); } } /* Generate a requester for a string value. */ void amii_getlin(prompt,bufp) const char *prompt; char *bufp; { getlind(prompt,bufp,0); } /* and with default */ void getlind(prompt,bufp, dflt) const char *prompt; char *bufp; const char *dflt; { #ifndef TOPL_GETLINE register struct Window *cwin; register struct IntuiMessage *imsg; register long class, code, qual; register int aredone = 0; register struct Gadget *gd; static int once; *StrString = 0; if( dflt ) strcpy( StrString, dflt ); StrWindow.Title = (UBYTE *)prompt; StrWindow.Screen = HackScreen; if( !once ) { if( bigscreen ) { StrWindow.LeftEdge = (HackScreen->Width/2) - (StrWindow.Width/2); if (amii_wins[WIN_MAP]) { StrWindow.TopEdge = amii_wins[WIN_MAP]->win->TopEdge; } else { StrWindow.TopEdge = (HackScreen->Height/2) - (StrWindow.Height/2); } } SetBorder( &String ); SetBorder( &Gadget2 ); once = 1; } if( WINVERS_AMIV || WINVERS_AMII ) { #ifdef INTUI_NEW_LOOK StrWindow.Extension = wintags; StrWindow.Flags |= WFLG_NW_EXTENDED; # ifdef __GNUC__ fillhook.h_Entry = (void *)&LayerFillHook; # else fillhook.h_Entry = (ULONG(*)())LayerFillHook; # endif fillhook.h_Data = (void *)-2; fillhook.h_SubEntry = 0; #endif } if( ( cwin = OpenWindow( (void *)&StrWindow ) ) == NULL ) { return; } while( !aredone ) { WaitPort( cwin->UserPort ); while( ( imsg = (void *) GetMsg( cwin->UserPort ) ) != NULL ) { class = imsg->Class; code = imsg->Code; qual = imsg->Qualifier; gd = (struct Gadget *) imsg->IAddress; switch( class ) { case VANILLAKEY: if( code == '\033' && (qual & (IEQUALIFIER_LALT|IEQUALIFIER_RALT| IEQUALIFIER_LCOMMAND|IEQUALIFIER_RCOMMAND) ) == 0 ) { if( bufp ) { bufp[0]='\033'; bufp[1]=0; } aredone = 1; } else { ActivateGadget( &String, cwin, NULL ); } break; case ACTIVEWINDOW: ActivateGadget( &String, cwin, NULL ); break; case GADGETUP: switch( gd->GadgetID ) { case 2: aredone = 1; if( bufp ) strcpy( bufp, StrString ); break; case 1: if( bufp ) { bufp[0]='\033'; bufp[1]=0; } aredone = 1; break; } break; case CLOSEWINDOW: if( bufp ) { bufp[0]='\033'; bufp[1]=0; } aredone = 1; break; } ReplyMsg( (struct Message *) imsg ); } } CloseWindow( cwin ); #else struct amii_WinDesc *cw; struct Window *w; int colx, ocolx, c; char *obufp; amii_clear_nhwindow( WIN_MESSAGE ); amii_putstr( WIN_MESSAGE, 0, prompt ); cw = amii_wins[ WIN_MESSAGE ]; w = cw->win; ocolx = colx = strlen( prompt ) + 1; obufp = bufp; cursor_on(WIN_MESSAGE); while((c = WindowGetchar()) != EOF) { cursor_off(WIN_MESSAGE); amii_curs( WIN_MESSAGE, colx, 0 ); if(c == '\033') { *obufp = c; obufp[1] = 0; return; } else if(c == '\b') { if(bufp != obufp) { bufp--; amii_curs( WIN_MESSAGE, --colx, 0); Text( w->RPort, "\177 ", 2 ); amii_curs( WIN_MESSAGE, colx, 0); } else DisplayBeep( NULL ); } else if( c == '\n' || c == '\r' ) { *bufp = 0; amii_addtopl( obufp ); return; } else if(' ' <= c && c < '\177') { /* avoid isprint() - some people don't have it ' ' is not always a printing char */ *bufp = c; bufp[1] = 0; Text( w->RPort, bufp, 1 ); Text( w->RPort, "\177", 1 ); if(bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO) { colx++; bufp++; } } else if(c == ('X'-64) || c == '\177') { amii_curs( WIN_MESSAGE, ocolx, 0 ); Text( w->RPort, " ", colx - ocolx ); amii_curs( WIN_MESSAGE, colx = ocolx, 0 ); } else DisplayBeep( NULL ); cursor_on(WIN_MESSAGE); } cursor_off(WIN_MESSAGE); *bufp = 0; #endif } void amii_change_color( pen, val, rev ) int pen, rev; long val; { if( rev ) flags.amii_curmap[ pen ] = ~val; else flags.amii_curmap[ pen ] = val; if( HackScreen ) LoadRGB4( &HackScreen->ViewPort, flags.amii_curmap, amii_numcolors ); } char * amii_get_color_string( ) { int i; char s[ 10 ]; static char buf[ BUFSZ ]; *buf = 0; for( i = 0; i < min(32,amii_numcolors); ++i ) { sprintf( s, "%s%03lx", i ? "/" : "", (long)flags.amii_curmap[ i ] ); strcat( buf, s ); } return( buf ); } nethack-3.4.3/sys/amiga/winstr.c0100644000000000000000000002663407764735041015253 0ustar rootroot/* SCCS Id: @(#)winstr.c 3.1 93/04/02 */ /* Copyright (c) Gregg Wonderly, Naperville, Illinois, 1991,1992,1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "NH:sys/amiga/windefs.h" #include "NH:sys/amiga/winext.h" #include "NH:sys/amiga/winproto.h" /* Put a string into the indicated window using the indicated attribute */ void amii_putstr(window,attr,str) winid window; int attr; const char *str; { int fudge; int len; struct Window *w; register struct amii_WinDesc *cw; char *ob; int i, j, n0, bottom, totalvis, wheight; static int wrapping = 0; /* Always try to avoid a panic when there is no window */ if( window == WIN_ERR ) { window = WIN_BASE; if( window == WIN_ERR ) window = WIN_BASE = amii_create_nhwindow( NHW_BASE ); } if( window == WIN_ERR || ( cw = amii_wins[window] ) == NULL ) { iflags.window_inited=0; panic(winpanicstr,window, "putstr"); } w = cw->win; if(!str) return; amiIDisplay->lastwin = window; /* do we care??? */ /* NHW_MENU windows are not opened immediately, so check if we * have the window pointer yet */ if( w ) { /* Set the drawing mode and pen colors */ SetDrMd( w->RPort, JAM2 ); amii_sethipens( w, cw->type, attr ); } else if( cw->type != NHW_MENU && cw->type != NHW_TEXT ) { panic( "NULL window pointer in putstr 2: %d", window ); } /* Okay now do the work for each type */ switch(cw->type) { case NHW_MESSAGE: if( WINVERS_AMIV ) fudge = 2; else { /* 8 for --more--, 1 for preceeding sp, 1 for putstr pad */ fudge = 10; } /* There is a one pixel border at the borders, so subtract two */ bottom = amii_msgborder( w ); wheight = ( w->Height - w->BorderTop - w->BorderBottom - 3 ) / w->RPort->TxHeight; if (scrollmsg || wheight > 1) fudge = 0; amii_scrollmsg( w, cw ); while (isspace(*str)) str++; strncpy( toplines, str, TBUFSZ ); toplines[ TBUFSZ - 1 ] = 0; /* For initial message to be visible, we need to explicitly position the * cursor. This flag, cw->curx == -1 is set elsewhere to force the * cursor to be repositioned to the "bottom". */ if( cw->curx == -1 ) { amii_curs( WIN_MESSAGE, 1, bottom ); cw->curx = 0; } /* If used all of history lines, move them down */ if( cw->maxrow >= iflags.msg_history ) { if( cw->data[ 0 ] ) free( cw->data[ 0 ] ); memcpy( cw->data, &cw->data[ 1 ], ( iflags.msg_history - 1 ) * sizeof( char * ) ); cw->data[ iflags.msg_history - 1 ] = (char *) alloc( strlen( toplines ) + 5 ); strcpy( cw->data[ i = iflags.msg_history - 1 ] + SOFF + (scrollmsg!=0), toplines ); } else { /* Otherwise, allocate a new one and copy the line in */ cw->data[ cw->maxrow ] = (char *) alloc( strlen( toplines ) + 5 ); strcpy( cw->data[ i = cw->maxrow++ ] + SOFF + (scrollmsg!=0), toplines ); } cw->data[ i ][ SEL_ITEM ] = 1; cw->data[ i ][ VATTR ] = attr+1; if( scrollmsg ) { cw->curx = 0; cw->data[ i ][2] = (cw->wflags & FLMSG_FIRST ) ? '>' : ' '; } str = cw->data[i] + SOFF; if( cw->curx + strlen(str) >= (cw->cols-fudge) ) { int i; char *ostr = (char *)str; char *p; while( cw->curx + strlen( str ) >= (cw->cols-fudge) ) { for(p=((char *)&str[ cw->cols-1 - cw->curx ])-fudge; !isspace(*p) && p > str;) --p; if (p < str) p = (char *)str; if( p == str ) { /* p = (char *)&str[ cw->cols ]; */ outmore(cw); continue; } i = (long)p-(long)str; outsubstr( cw, (char *)str, i, fudge ); cw->curx += i; while(isspace(*p)) p++; str = p; #if 0 if( str != ostr ) { outsubstr( cw, "+", 1, fudge ); cw->curx+=2; } #endif if(*str) amii_scrollmsg( w, cw ); amii_cl_end( cw, cw->curx ); } if( *str ) { if( str != ostr ) { outsubstr( cw, "+", 1, fudge ); cw->curx+=2; } while ( isspace( *str ) ) ++str; outsubstr( cw, (char *)str, i = strlen( (char *)str ), fudge ); cw->curx += i; amii_cl_end( cw, cw->curx ); } } else { outsubstr( cw, (char *)str, i = strlen( (char *)str ), fudge ); cw->curx += i; amii_cl_end( cw, cw->curx ); } cw->wflags &= ~FLMSG_FIRST; len = 0; if( scrollmsg ) { totalvis = CountLines( window ); SetPropInfo( w, &MsgScroll, ( w->Height-w->BorderTop-w->BorderBottom ) / w->RPort->TxHeight, totalvis, totalvis ); } i = strlen( toplines + SOFF ); cw->maxcol = max( cw->maxcol, i ); cw->vwy = cw->maxrow; break; case NHW_STATUS: if( cw->data[ cw->cury ] == NULL ) panic( "NULL pointer for status window" ); ob = &cw->data[cw->cury][j = cw->curx]; if(flags.botlx) *ob = 0; /* Display when beam at top to avoid flicker... */ WaitTOF(); Text(w->RPort,(char *)str,strlen((char *)str)); if( cw->cols > strlen( str ) ) TextSpaces( w->RPort, cw->cols - strlen( str ) ); (void) strncpy(cw->data[cw->cury], str, cw->cols ); cw->data[cw->cury][cw->cols-1] = '\0'; /* null terminate */ cw->cury = (cw->cury+1) % 2; cw->curx = 0; break; case NHW_MAP: case NHW_BASE: if (cw->type == NHW_BASE && wrapping) { amii_curs(window, cw->curx+1, cw->cury); TextSpaces(w->RPort, cw->cols); if (cw->cury < cw->rows) { amii_curs(window, cw->curx+1, cw->cury+1); TextSpaces(w->RPort, cw->cols); cw->cury--; } } amii_curs(window, cw->curx+1, cw->cury); Text(w->RPort,(char *)str,strlen((char *)str)); cw->curx = 0; /* CR-LF is automatic in these windows */ cw->cury++; if (cw->type == NHW_BASE && cw->cury >= cw->rows) { cw->cury = 0; wrapping = 1; } break; case NHW_MENU: case NHW_TEXT: /* always grows one at a time, but alloc 12 at a time */ if( cw->cury >= cw->rows || !cw->data ) { char **tmp; /* Allocate 12 more rows */ cw->rows += 12; tmp = (char**) alloc(sizeof(char*) * cw->rows); /* Copy the old lines */ for(i=0; icury; i++) tmp[i] = cw->data[i]; if( cw->data ) { free( cw->data ); cw->data = NULL; } cw->data = tmp; /* Null out the unused entries. */ for(i=cw->cury; irows; i++) cw->data[i] = 0; } if( !cw->data ) panic("no data storage"); /* Shouldn't need to do this, but... */ if( cw->data && cw->data[cw->cury] ) { free( cw->data[cw->cury] ); cw->data[cw->cury] = NULL; } n0 = strlen(str)+1; cw->data[cw->cury] = (char*) alloc(n0+SOFF); /* avoid nuls, for convenience */ cw->data[cw->cury][VATTR] = attr+1; cw->data[cw->cury][SEL_ITEM] = 0; Strcpy( cw->data[cw->cury] + SOFF, str); if(n0 > cw->maxcol) cw->maxcol = n0; if(++cw->cury > cw->maxrow) cw->maxrow = cw->cury; break; default: panic("Invalid or unset window type in putstr()"); } } void amii_scrollmsg( w, cw ) register struct Window *w; register struct amii_WinDesc *cw; { int bottom, wheight; bottom = amii_msgborder( w ); wheight = ( w->Height - w->BorderTop - w->BorderBottom - 3 ) / w->RPort->TxHeight; if( scrollmsg ) { if( ++cw->disprows > wheight ) { outmore( cw ); cw->disprows = 1; /* count this line... */ } else { ScrollRaster( w->RPort, 0, w->RPort->TxHeight, w->BorderLeft, w->BorderTop + 1, w->Width - w->BorderRight-1, w->Height - w->BorderBottom - 1 ); } amii_curs( WIN_MESSAGE, 1, bottom ); } } int amii_msgborder( w ) struct Window *w; { register int bottom; /* There is a one pixel border at the borders, so subtract two */ bottom = w->Height - w->BorderTop - w->BorderBottom - 2; bottom /= w->RPort->TxHeight; if( bottom > 0 ) --bottom; return( bottom ); } void outmore( cw ) register struct amii_WinDesc *cw; { struct Window *w = cw->win; if((cw->wflags & FLMAP_SKIP) == 0) { if( scrollmsg ) { int bottom; bottom = amii_msgborder( w ); ScrollRaster( w->RPort, 0, w->RPort->TxHeight, w->BorderLeft, w->BorderTop+1, w->Width - w->BorderRight-1, w->Height - w->BorderBottom - 1 ); amii_curs( WIN_MESSAGE, 1, bottom ); /* -1 for inner border */ Text( w->RPort, "--more--", 8 ); } else Text( w->RPort, " --more--", 9 ); /* Make sure there are no events in the queue */ flushIDCMP( HackPort ); /* Allow mouse clicks to clear --more-- */ WindowGetchar(); if( lastevent.type == WEKEY && lastevent.un.key == '\33' ) cw->wflags |= FLMAP_SKIP; } if( !scrollmsg ) { amii_curs( WIN_MESSAGE, 1, 0 ); amii_cl_end( cw, cw->curx ); } } void outsubstr( cw, str, len, fudge ) register struct amii_WinDesc *cw; char *str; int len; int fudge; { struct Window *w = cw->win; if( cw->curx ) { /* Check if this string and --more-- fit, if not, * then put out --more-- and wait for a key. */ if( (len + fudge ) + cw->curx >= cw->cols ) { if( !scrollmsg ) outmore( cw ); } else { /* Otherwise, move and put out a blank separator */ Text( w->RPort, spaces, 1 ); cw->curx += 1; } } Text(w->RPort,str,len); } /* Put a graphics character onto the screen */ void amii_putsym( st, i, y, c ) winid st; int i, y; CHAR_P c; { amii_curs( st, i, y ); Text(amii_wins[st]->win->RPort, &c, 1); } /* Add to the last line in the message window */ void amii_addtopl(s) const char *s; { register struct amii_WinDesc *cw = amii_wins[WIN_MESSAGE]; while(*s) { if(cw->curx == cw->cols - 1) amii_putstr(WIN_MESSAGE, 0, ""); amii_putsym(WIN_MESSAGE, cw->curx + 1, amii_msgborder(cw->win), *s++); cw->curx++; } } void TextSpaces( rp, nr ) struct RastPort *rp; int nr; { if( nr < 1 ) return; while (nr > sizeof(spaces) - 1) { Text(rp, spaces, (long)sizeof(spaces) - 1); nr -= sizeof(spaces) - 1; } if (nr > 0) Text(rp, spaces, (long)nr); } void amii_remember_topl() { /* ignore for now. I think this will be done automatically by * the code writing to the message window, but I could be wrong. */ } int amii_doprev_message() { struct amii_WinDesc *cw; struct Window *w; char *str; if( WIN_MESSAGE == WIN_ERR || ( cw = amii_wins[ WIN_MESSAGE ] ) == NULL || ( w = cw->win ) == NULL ) { panic(winpanicstr,WIN_MESSAGE, "doprev_message"); } /* When an interlaced/tall screen is in use, the scroll bar will be there */ /* Or in some other cases as well */ if( scrollmsg ) { struct Gadget *gd; struct PropInfo *pip; int hidden, topidx, i, total, wheight; for( gd = w->FirstGadget; gd && gd->GadgetID != 1; ) gd = gd->NextGadget; if( gd ) { pip = (struct PropInfo *)gd->SpecialInfo; wheight = ( w->Height - w->BorderTop - w->BorderBottom - 2 ) / w->RPort->TxHeight; hidden = max( cw->maxrow - wheight, 0 ); topidx = (((ULONG)hidden * pip->VertPot) + (MAXPOT/2)) >> 16; for( total = i = 0; i < cw->maxrow; ++i ) { if( cw->data[i][1] != 0 ) ++total; } i = 0; topidx -= wheight/4 + 1; if (topidx < 0) topidx = 0; SetPropInfo( w, &MsgScroll, wheight, total, topidx ); DisplayData( WIN_MESSAGE, topidx ); } return(0); } if( --cw->vwy < 0 ) { cw->maxcol = 0; DisplayBeep( NULL ); str = "\0\0No more history saved..."; } else str = cw->data[ cw->vwy ]; amii_cl_end(cw, 0); amii_curs( WIN_MESSAGE, 1, 0 ); amii_setdrawpens( amii_wins[WIN_MESSAGE]->win, NHW_MESSAGE ); Text(w->RPort,str+SOFF,strlen(str+SOFF)); cw->curx = cw->cols + 1; return( 0 ); } nethack-3.4.3/sys/amiga/xpm2iff.c0100644000000000000000000002023407764735041015266 0ustar rootroot/* SCCS Id: @(#)xpm2iff.c 3.2 95/08/04 */ /* Copyright (c) 1995 by Gregg Wonderly, Naperville, Illinois */ /* NetHack may be freely redistributed. See license for details. */ #include #include "config.h" #include "tile.h" #include #include #include #include #include #include #include #include #ifndef _DCC # include # include # include #endif struct xpmscreen { int Width; int Height; int Colors; int ColorResolution; int Background; int AspectRatio; int Interlace; int BytesPerRow; } XpmScreen; /* translation table from xpm characters to RGB and colormap slots */ struct Ttable { char flag; char r,g,b; int slot; /* output colortable index */ }ttable[256]; pixval ColorMap[3][MAXCOLORMAPSIZE]; int colorsinmap; /* * We are using a hybrid form of our own design which we call a BMAP (for * bitmap) form. It is an ILBM with the bitmaps already deinterleaved, * completely uncompressed. * This speeds the loading of the images from the games point of view because it * does not have to deinterleave and uncompress them. */ #define ID_BMAP MAKE_ID( 'B', 'M', 'A', 'P' ) /* instead of ILBM */ #define ID_BMHD MAKE_ID( 'B', 'M', 'H', 'D' ) /* Same as ILBM */ #define ID_CAMG MAKE_ID( 'C', 'A', 'M', 'G' ) /* Same as ILBM */ #define ID_CMAP MAKE_ID( 'C', 'M', 'A', 'P' ) /* Same as ILBM */ #define ID_PDAT MAKE_ID( 'P', 'D', 'A', 'T' ) /* Extra data describing plane * size due to graphics.library * rounding requirements. */ #define ID_PLNE MAKE_ID( 'P', 'L', 'N', 'E' ) /* The planes of the image */ int nplanes; /* BMHD from IFF documentation */ typedef struct { UWORD w, h; WORD x, y; UBYTE nPlanes; UBYTE masking; UBYTE compression; UBYTE reserved1; UWORD transparentColor; UBYTE xAspect, yAspect; WORD pageWidth, pageHeight; } BitMapHeader; typedef struct { UBYTE r, g, b; } AmiColorMap; pixel pixels[TILE_Y][TILE_X]; AmiColorMap *cmap; void error( char *str ) { fprintf( stderr, "ERROR: %s\n", str ); } char **planes; main( int argc, char **argv ) { int colors; struct { long nplanes; long pbytes; long across; long down; long npics; long xsize; long ysize; } pdat; long pbytes; /* Bytes of data in a plane */ int i, cnt; BitMapHeader bmhd; struct IFFHandle *iff; long camg = HIRES|LACE; int tiles=0; int index; #if defined(_DCC) || defined (__GNUC__) IFFParseBase = OpenLibrary( "iffparse.library", 0 ); if( !IFFParseBase ) { error( "unable to open iffparse.library" ); exit( 1 ); } #endif if( fopen_xpm_file( argv[1], "r" ) != TRUE ) { perror( argv[1] ); return( 1 ); } nplanes = 0; i = XpmScreen.Colors - 1; while( i != 0 ) { nplanes++; i >>= 1; } planes = malloc( nplanes * sizeof( char * ) ); if( planes == 0 ) { error( "can not allocate planes pointer" ); exit( 1 ); } XpmScreen.BytesPerRow = ((XpmScreen.Width + 15)/16)*2; pbytes = XpmScreen.BytesPerRow * XpmScreen.Height; for( i = 0; i < nplanes; ++i ) { planes[ i ] = malloc( pbytes ); if( planes[ i ] == 0 ) { error( "can not allocate planes pointer" ); exit( 1 ); } memset( planes[i], 0, pbytes ); } iff = AllocIFF(); if( !iff ) { error( "Can not allocate IFFHandle" ); return( 1 ); } iff->iff_Stream = Open( argv[2], MODE_NEWFILE ); if( !iff->iff_Stream ) { error( "Can not open output file" ); return( 1 ); } InitIFFasDOS( iff ); OpenIFF( iff, IFFF_WRITE ); PushChunk( iff, ID_BMAP, ID_FORM, IFFSIZE_UNKNOWN ); bmhd.w = XpmScreen.Width; bmhd.h = XpmScreen.Height; bmhd.x = 0; bmhd.y = 0; bmhd.nPlanes = nplanes; bmhd.masking = 0; bmhd.compression = 0; bmhd.reserved1 = 0; bmhd.transparentColor = 0; bmhd.xAspect = 100; bmhd.yAspect = 100; bmhd.pageWidth = 0; /* not needed for this program */ bmhd.pageHeight = 0; /* not needed for this program */ PushChunk( iff, ID_BMAP, ID_BMHD, sizeof( bmhd ) ); WriteChunkBytes( iff, &bmhd, sizeof( bmhd ) ); PopChunk( iff ); PushChunk( iff, ID_BMAP, ID_CAMG, sizeof( camg ) ); WriteChunkBytes( iff, &camg, sizeof( camg ) ); PopChunk( iff ); #define SCALE(x) (x) cmap = malloc( (colors = (1L<iff_Stream ); FreeIFF( iff ); #if defined(_DCC) || defined (__GNUC__) CloseLibrary( IFFParseBase ); #endif exit( 0 ); } #define SETBIT(Plane, Plane_offset, Col, Value) \ if(Value){ \ planes[Plane][Plane_offset + (Col/8)] |= 1<<(7-(Col & 7)); \ } conv_image(){ int row, col, planeno; for(row = 0;row if any */ for(bp = buf;*bp;bp++); bp--; while(isspace(*bp))bp--; if(*bp==',')bp--; if(*bp=='"')bp--; bp++; *bp = '\0'; return &buf[1]; } nethack-3.4.3/sys/atari/0040755000000000000000000000000007764735105013574 5ustar rootrootnethack-3.4.3/sys/atari/Install.tos0100644000000000000000000001447207764735041015735 0ustar rootroot Instructions for compiling and installing NetHack 3.4 on a TOS system ===================================================== (or, How to make ST NetHack 3.4) Last revision: 2 February 2000 1. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, util, sys\atari, sys\share, sys\unix, and at least one of win\tty and win\gem. You may have other subdirectories under sys and win, but they needn't concern you. If you do not follow this structure, the Makefiles will not function properly. The .c files for the main program belong in src, those for utility programs in util, and Atari-specific ones in sys\atari. All the .h files belong in include, the documentation in doc, and assorted data files in dat. You may also use random.c from sys\share. The Makefiles belong in sys\unix. (A more detailed explanation of the directory structure may be found in Files, which should be in the top directory.) 2. If you don't already have a good command line interpreter, get one. Doing all of the following from the desktop or a GEM shell will probably be a *big* pain. If you can get a Bourne shell compatible one, and put it in \bin\sh, then you'll save yourself some trouble with the Makefiles. There are several good shells on various FTP sites (including atari.archive.umich.edu). Run the "setup.g" shell script in sys\atari. This will setup all the makefiles and other files in the appropriate directories. It assumes that your compiler prefers \ to / as a directory separator. If not, simply copy the makefiles instead of running sed on them. 3. Now go to the include subdirectory to edit a couple of the header files there. First edit config.h according to the comments to match your system and desired set of features. In particular: make sure that UNIX is *not* defined, and TOS is (if you're using the MiNT library, and/or the -mint option to gcc, this will be done automatically) make sure that HACKDIR is defined properly (or not at all) make sure that COMPRESS is not defined Also edit tosconf.h; this shouldn't need much changing. If you are not going to include random.c you will need to comment out RANDOM. Gcc users don't need RANDOM, since the gcc and MiNT libraries have a Berkeley derived srandom() function already. If you have no termcap support and don't want to use the supplied termcap.uu, comment out TERMLIB. Gcc has a termcap library, so TERMLIB should always be "on" with gcc (and you don't need to worry about termcap.uu at all). 4. If you want to change the high score list behavior, examine the top of topten.c, in the src directory. You may want to change the definitions of PERSMAX, POINTSMIN, and ENTRYMAX. I set POINTSMIN to 51 and ENTRYMAX to 50 to keep the size of the score list down. 5. Go to the src directory and edit your Makefile. You'll want the Systos target configuration; the comments explain most of what needs to be done, at least for the gcc. Next, go to the top, util, dat, and doc directories, and edit the Makefiles there, as necessary. You'll need nroff and/or TeX to do the files in doc; if you don't have one/both of these, you can skip it (docs?? we don't need no steenking docs :-)). If you elected to use Fred Fish's termcap library (bundled in as termcap.arc), you will have to generate termcap.a from those sources. If you are recompiling after patching your sources, or if you got your files from somewhere other than the official distribution, "touch makedefs.c" to ensure that certain files (onames.h and pm.h) are remade, lest potentially troublesome timestamps fool "make." 8. Now, enter "make all", and take a long siesta; your computer will be occupied for a long time. If all goes well, you will get an executable. If you tried to compile in too many features, you will probably get a dysfunctional executable, and will have to start over. Hint 1: If you're short on memory, you might enter "make -n all >make.bat," and then run script.bat with some sort of batch program or with the gulam command "script make.bat." Hint 2: You'll save yourself a lot of grief if you use the GNU version of the "make" program. Some of the smaller makes aren't completely compatible. GNU software for the Atari is widely available; for example, by anonymous FTP from atari.archive.umich.edu. 9. Make sure the support files -- data, rumors, cmdhelp, opthelp, help, hh, history, license, and oracles, or simply nhdat if DLB was defined -- were copied to the game directory. If not, move them there from the dat directory yourself. rumors can be created manually by entering "makedefs -r;" data by entering "makedefs -d." Also, make sure that the various level files (*.lev, from the dat subdirectory) were copied over correctly. If you're not sure what files should have been made, double check with Makefile.dat. 10. Go to the src\atari directory. Copy atari.cnf to your game directory as NetHack.cnf. Edit it to reflect your particular setup and personal preferences, following the comments. If you compiled in the TERMLIB feature, also move the "termcap" file to your game directory. (Note: gcc's termcap routines have built-in defaults, so the termcap file is not necessary with that compiler.) If you're running NetHack from the MultiTOS desktop, and you want a more useful set of drop down menus than the plain system "File/Edit" ones, copy nethack.mnu to your games directory. This file contains a menu definition that puts a lot of the common commands into the menu. 11. Play NetHack. If it works, you're done! Notes ----- 1) Save files and bones files from previous versions will not work with NetHack 3.4. Don't bother trying to keep them. 2) To install an update of NetHack after changing something, enter "make" from the src directory. If you add, delete, or reorder monsters or objects, or you change the format of saved level files, delete any save and bones files. (Trying to use such files sometimes produces amusing confusions on the game's part, but more often produces crashes.) nethack-3.4.3/sys/atari/atarifnt.uue0100644000000000000000000001577407764735041016136 0ustar rootroottable !"#$%&'()*+,-./0123456789:;<=>? @ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ begin 644 hackfnt.arc M&@A(04-+1DY4+E!21P E!, #\48JO>BQ\= ,8#0 #" S4 ,! ! &@!Bz M8 "#D!2 > . !Q_P%!5= 'D!0(GN10.X('EB9,Z1L+0"<,&1!DY*5L<@-B,#H(!<(N' 8XIH'SYK3.CQSX057EA26DQ\r MPP$/)REU#@XPB$ 1!G0 0$(: &!033IT8:&$"0KPY1<)0XR@#%5_4O90D1D<"*$)%H((p M\1T&9O C)HDD(,.H$I#R \9 B%1Z::9HFB&+HHQ*\Q4@$&2 !" R (!$,"!Lo MB<0;",#!#S"!4 -(-P(L0$8"*1J 3#1,GNM,T),m M8$< (PQ#%1UHGB%!I5*81\>GD8;JCA"2@" %H 4R0 ')RW% P@\ZO " !H l M>>.0 !1) ))U+(4#""D*H,^.3/PP0)!!@"PRQ76 @!Z5/%1,5,HZ_(//"#Dk MD3,#: P3_2)LS)@#4:4< V708,0A\>,3@X(80P0Z%CR-^,G"0D)$00%@$8 ("#0CD i MH9 +/!B@4 E@R- J) ;$PX.,"_&PD$(&M E) 0B(=+E"&Q0."08%@,(T'ZM_h MKA !"\P)">$ , W)#6UN"HD&#F PX.P&% X&!U4"L"D&8.C$0&W"(P^ 3@ Xg M()(!LTNN4 %@Z#Z Y &(!(,>>IC1N4A;C)[Y["3$-E D(N%#EPT#F>] UAY(f M#PD"A1M^^.?^>,\ '_YP1_<,@P<( '/_CA@GXP #/ 8 PXK1 ?d M/O"#3FIH!C]X@#UM@H/Q . XZ7F' <#87^\P (/XF8$!/# ##. 711C R8H?c M!( )I<@#*RX$ QXP P8\@C&G(0L!G*"UB@ E,>"(?],"Z+YAO).@#b M !5:PSX9@0,$/O!! $PH(S^X@7A?[%__%@*!IOC Q#P0=; 8(#>#80-68,!a M#/#0/Q#B@ ,X\(<$J1YB$ ,,L*+Iz M$N,'#+APA"'<7/0 X_K-"%?/##0GHH0QKV<"'\<.$.=>)#]ASN<)MR'&R.y MF$2%',!TP6/B0'182PP03R?E7(@? ( /=(K1# ?! 9P\@('9P1&-:@%!_N"Xx M3@ LDG 04(8QC%&%.VJ. .E306O6N4YPQ& ,-A@ (;7H!OAE;IW]4Q$$_- 2w M"&RTDW!P0 8P@ $!$"%K>$!"_GA A;00!?^L,8 Q/@ .* 2%*I<2"M?N3DAv M N T*C@/\# !AR8$P=97(@!S"#/B8$!#DL5HSG] 9PFCV!P'T ">@:/Q:P ,:@$4.^_P/;XA7L%\Z+,& 6T-'4+3J#JQ!@CK20!C#&2IR;/EF_$1Z;!BKY;6g M,"\\P.@+'H2<>MP5KYIUPH<-V/I^8(!!G&,(J85$6XP'68@-L+%4-YAA&S>_f M<$!%(0M>\^,#^ #V/XRF@EJ8 \8R(L !,#L(9\?8#@Y@:B80(6=4,*"&,!"$e M'VKH[;ZX$)0D]4-K%@*-K]'U'(&HK37TH0M&=(*%'N! #CBQ95SH8"$(U(4.d M*GD >,P( /\PM3>JM/$9H1B7;#! +\4W$#B0\,B/(H86+D'.$&"D&\ZYE\$,!_VT$Z<^P-2KNVY1'5(b M5QC((+ULN* =W+"-"NM0)'H0A2X '41_RC8 $ !%7HQ#QGS "/?R&P.GVV a MI>+@'8C ,0K.+L5&L8%AMU4M6E5?.!^()*B?0P+#X%*2( ^2P B!P /X $2z MD >>H$K L$JJI$I^ $/X#Y?!'D&8 .31U))-0"ZA'FLQGF&8VG<$'HX%G+?y M90Q&YV+8T#LZX0\?A%YF)1(HN'DC]V/;!08?%(/(9U2' WO*A#T6IF8N! ;_x M4'P)<&IBM'F0)44N9'08@ TVH$-VX ??8'WPM! *H N[YFO>)V+# $JP $[w MH 4]A!' L&S)Q'X>Q 9F4&U@@ (8@':-@@+X!VYHUCL+D348 770P),Q0&Zv M8 _6@ W#0%4

@4X,@ TZ6'LP>'Y5-%< ( 0ZD3RUt M-SLSAV/8@ UAA0 'AGSOM!!&!V#3X S0)UX#9HR;PX6,]5/@$(;!1F)4@ 'Ss MX ;#\ _^ _P@%G!\&(QUGZ*=F-S" -H5T.J8 9 )F3($SRV*$L\($0!V$7,r M90[&@ 4O9C04T(B/J%.1N%0"@!"6Z&*8"$KP5#B9QD0B9T5+)#T#(@[BI56Fq MB(J_J :K""D\ %9G%3PB\8LXYDMO)E\U5'NL&)(AA%[B- PF&8R$$XM@4(PFp MAU5=I$+*.#O21$D&H $8,'3;A9/5. *,%"BLSEX!4\J\ ]7%8Y\0(XV\ >#o M "IM4Y?I%8 !@TS]#Z%IPP@#.P ,U9&$YY@&6R6"])$YL!@D+@%C45&M#l MF$.]] ?IY4LAA%7M%6#2\GRQ9ICB2$TBH0"LLY2)A5CI0P4OY&S_P ?\P \Vk M, 8Y-#KMQP:NQP:;X@\XT 5&PP-L,)<;Y7%%B FO8SH-T$3[,P!!( BKLYZUj MLT)&XY> "0!V0$1M!9$\Z$)Q]$'_h M@#QPT%X?"CT>2DD8\ /YTUZ\P M_H)/!>3V(Y:$+D5"7LPQLQIS\$$C)))T&g M<)Y@X'C]DQZ>,P#P$$G@^47Z* $-X3D1X &8XP!-! E:JA KT$^V@SWZ=@#Kf MU#L#TA:8d M8P"A T\!8ACS83Y"J1!PYH$C-D@D18ZIPP<&P#H(ZCIXT'B"4T'%8U3B=CT"c M\$$A!$P3143&U(2-,M#R+>60#<601Q%*@E G"z MIEL\$*C D$H2Z$J1Z'%@<(&Q4T'1=TL.N4ON)UW4A4ZX! (%D48U%UB9 #6y MZ0Z#5@!DI1/!XQV'DQYKU41MY1W>!$YJYAT.^Y"%\Y#/0U>%@PJU,@.U L1(D35$'^0%3--1+/17#!$V?C@D[JI$%&u M)XM.IZ^t M1&&6R%\1^TI+@?)$0D%7#KA $H1BZ9EZ#^![-MP0!Jq MX'![%G%^!@=@<'HNMD*K]T&SXW$P '(Z@6 DE4'^8'*S6%KF18.>0 /)8I47/9@?FR@;4Q@=BD$&+"RDZQ U4<'K%6SIHn M23AL /+ P#G, Q/-@SYD D/7('>\ ^_59"L=) NA!! 53R9!P,=6'D+$8*:m MMU16%#R;0U)])HLJ*+NI*&"95TNN2(.[=$')WR%T]*(_(-SL,0 /4l M9 ^T'XY%GR@Q@=_4'P(D'-5Q(H^=\.$O 8$QP8VL%1V8 =9>#E># %Z$ HAk MX6M05\9(0 7=@+[R.XYKZ -TRW[090SO@ PX-LAY+%[,T,<<]+!3" "M4B78j M@$D1)(B0FPGS, QP,(9IY@$9@ F2/(&L!@$$@%PBX0\,21?R)$X1:470]8EFi MA4L'9CSB99VF:)T\1%3N%))BY!TD:9,X!@-37)LKR5TMR5Y7FUAB$$4YUD,Fh MU%U&&&!&60 7=$60&F/G ,Jg MX%I^, ;+R0_E> ?O*YU0M*!R"(=Y'$4DP XX8 V$.R.VR 0'H8\%0 (;BU3Gf M< X@, PXL'(;X("RFF]ZO4(>@*5DALD88 3SV:LDC % <)OYV45- ;..XQT7e MM$(M! ::): %"@8V "?)=YD^) .*DD?VD42"I(5Z@,7FJ'8IGG9JD4(T%Z_d M][:40TU86**__*&^I$*2?3D[/1!2Q "&\ D8\*[MI4XW>GUG=4%:)*6#M:5M68T$4(%MU8BJZJC[b MTP"ZHP-9P]:7"@D'X(0#L %T@ 9A, 9KD%5TX (Z+@"X$.(C7N(G7N6XH.)B$ 8Wx M3A]B@072\ 4+P1(V409*O@%\H.)E@ =I$"4J(A)63N)OP 9Rw M\ 5D$ 9^N35L/@!$4 1&$ 15$.> H.)H@.-P\.5^61 JSN(U'B4I7A1N\ : v M+N@B,0!%7@9T4.=XKN.4_A-VD 8QX09Q3@B53@=K, =IH =QC@A?\!)RL.EBu MON2,<.MV'B4+P>5?8.9H'NQZK@]?8!-WKN=Z#@^W'N@K 1;'$>IN0 :O$^>#t M(1(0$,T,@ Z@ +2H@ *X (H &H 0( .KQ !"8*)6P ZP $0X #C3@$ s # !H r q end nethack-3.4.3/sys/atari/nethack.mnu0100644000000000000000000000150407764735041015726 0ustar rootroot# Sample .mnu file for NetHack # This will work only with MINIWIN v1.1 # or TOSWIN v2.0 (or better) #%title "NetHack" #%about "About NetHack" "v" File "Shell" "!" "Options" "O" --- "Save Game" "S" --- "Quit" ?"[1][Really quit?][ Yes | No ]":%A"#quit y":! Edit "Copy" %C "Paste" %P "Paste Options..." %O --- "Set Font..." %F Inventory "Show Inventory" "i" -- "Put on jewelry" "P" "Remove jewelry" "R" "Wear armor" "W" "Take off armor" "T" "Wield weapon" "w" "Exchange weapons" "x" "Ready ammo in quiver" "Q" --- "Eat" "e" "Quaff potion" "q" --- "Drop" "d" "Throw" "t" "Fire" "f" Move "North" "k" 4800 "South" "j" 5000 "East" "l" 4d00 "West" "h" 4b00 --- "Rest" "." --- "Open door" "o" "Close door" "c" Misc "Help" "?" 6200 "List known spells" "+" "Cast spell" "Z" --- "Abort" 001b 6100 nethack-3.4.3/sys/atari/setup.g0100644000000000000000000000131007764735041015073 0ustar rootroot# gulam shell script -- should work with tcsh and many # other Atari shells, too # UNIX shells use '/' in file names, but at least some Atari shells need '\' # so we process the UNIX makefiles to make that switch # sed script not included as a here document in this script because at # least some Atari shells don't do that sed -f unx2atar.sed < ..\unix\Makefile.top > ..\..\Makefile sed -f unx2atar.sed < ..\unix\Makefile.dat > ..\..\dat\Makefile sed -f unx2atar.sed < ..\unix\Makefile.doc > ..\..\doc\Makefile sed -f unx2atar.sed < ..\unix\Makefile.src > ..\..\src\Makefile sed -f unx2atar.sed < ..\unix\Makefile.utl > ..\..\util\Makefile # KLUDGE to fix a Makefile problem echo > ..\..\include\win32api.h nethack-3.4.3/sys/atari/tos.c0100644000000000000000000001645007764735041014547 0ustar rootroot/* SCCS Id: @(#)tos.c 3.1 90/14/08 /* NetHack may be freely redistributed. See license for details. */ /* * TOS system functions. */ #define NEED_VARARGS #include "hack.h" #ifdef TTY_GRAPHICS # include "tcap.h" #else /* To avoid error for tos.c; will be removed later */ static char *nh_HE="\033q"; #endif #ifdef TOS # include # ifndef WORD # define WORD short /* 16 bits -- redefine if necessary */ # endif #include static char NDECL(DOSgetch); static char NDECL(BIOSgetch); static void NDECL(init_aline); char *_a_line; /* for Line A variables */ # ifdef TEXTCOLOR boolean colors_changed = FALSE; # endif int tgetch() { char ch; /* BIOSgetch can use the numeric key pad on IBM compatibles. */ if (iflags.BIOS) ch = BIOSgetch(); else ch = DOSgetch(); return ((ch == '\r') ? '\n' : ch); } /* * Keyboard translation tables. */ #define KEYPADLO 0x61 #define KEYPADHI 0x71 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * When iflags.BIOS is active, shifted keypad keys are translated to the * shift values below. */ static const struct pad { char normal, shift, cntrl; } keypad[PADKEYS] = { {C('['), 'Q', C('[')}, /* UNDO */ {'?', '/', '?'}, /* HELP */ {'(', 'a', '('}, /* ( */ {')', 'w', ')'}, /* ) */ {'/', '/', '/'}, /* / */ {C('p'), '$', C('p')}, /* * */ {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'h', 'H', C('h')}, /* 4 */ {'.', '.', '.'}, {'l', 'L', C('l')}, /* 6 */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }, numpad[PADKEYS] = { {C('['), 'Q', C('[')} , /* UNDO */ {'?', '/', '?'}, /* HELP */ {'(', 'a', '('}, /* ( */ {')', 'w', ')'}, /* ) */ {'/', '/', '/'}, /* / */ {C('p'), '$', C('p')}, /* * */ {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'4', M('4'), '4'}, /* 4 */ {'.', '.', '.'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }; /* * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII * meaning unless assigned one by a keyboard conversion table, so the * keyboard BIOS normally does not return a character code when Alt-letter * is pressed. So, to interpret unassigned Alt-letters, we must use a * scan code table to translate the scan code into a letter, then set the * "meta" bit for it. -3. */ #define SCANLO 0x10 static const char scanmap[] = { /* ... */ 'q','w','e','r','t','y','u','i','o','p','[',']', '\n', 0, 'a','s','d','f','g','h','j','k','l',';','\'', '`', 0, '\\', 'z','x','c','v','b','N','m',',','.','?' /* ... */ }; #define inmap(x) (SCANLO <= (x) && (x) < SCANLO + SIZE(scanmap)) /* * BIOSgetch gets keys directly with a BIOS call. */ #define SHIFT (0x1 | 0x2) #define CTRL 0x4 #define ALT 0x8 static char BIOSgetch() { unsigned char scan, shift, ch; const struct pad *kpad; long x; /* Get scan code. */ x = Crawcin(); ch = x & 0x0ff; scan = (x & 0x00ff0000L) >> 16; /* Get shift status. */ shift = Kbshift(-1); /* Translate keypad keys */ if (iskeypad(scan)) { kpad = iflags.num_pad ? numpad : keypad; if (shift & SHIFT) ch = kpad[scan - KEYPADLO].shift; else if (shift & CTRL) ch = kpad[scan - KEYPADLO].cntrl; else ch = kpad[scan - KEYPADLO].normal; } /* Translate unassigned Alt-letters */ if ((shift & ALT) && !ch) { if (inmap(scan)) ch = scanmap[scan - SCANLO]; return (isprint(ch) ? M(ch) : ch); } return ch; } static char DOSgetch() { return (Crawcin() & 0x007f); } long freediskspace(path) char *path; { int drive = 0; struct { long freal; /*free allocation units*/ long total; /*total number of allocation units*/ long bps; /*bytes per sector*/ long pspal; /*physical sectors per allocation unit*/ } freespace; if (path[0] && path[1] == ':') drive = (toupper(path[0]) - 'A') + 1; if (Dfree(&freespace,drive)<0) return -1; return freespace.freal*freespace.bps*freespace.pspal; } /* * Functions to get filenames using wildcards */ int findfirst(path) char *path; { return (Fsfirst(path, 0) == 0); } int findnext() { return (Fsnext() == 0); } char * foundfile_buffer() { return (char *)Fgetdta() + 30; } long filesize(file) char *file; { if (findfirst(file)) return (* (long *) ((char *)Fgetdta() + 26)); else return -1L; } /* * Chdrive() changes the default drive. */ void chdrive(str) char *str; { char *ptr; char drive; if ((ptr = index(str, ':')) != (char *)0) { drive = toupper(*(ptr - 1)); (void)Dsetdrv(drive - 'A'); } return; } void get_scr_size() { # ifdef MINT # include struct winsize win; char *tmp; if((tmp=nh_getenv("LINES"))) LI = atoi(tmp); else if((tmp=nh_getenv("ROWS"))) LI = atoi(tmp); if(tmp && (tmp=nh_getenv("COLUMNS"))) CO = atoi(tmp); else { ioctl(0,TIOCGWINSZ, &win); LI = win.ws_row; CO = win.ws_col; } # else init_aline(); LI = (*((WORD *)(_a_line + -42L))) + 1; CO = (*((WORD *)(_a_line + -44L))) + 1; # endif } # define BIGBUF 8192 int _copyfile(from, to) char *from, *to; { int fromfd, tofd, r; char *buf; if ((fromfd = open(from, O_RDONLY|O_BINARY, 0)) < 0) return -1; if ((tofd = open(to, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, FCMASK)) < 0) return -1; buf = (char *)alloc((size_t)BIGBUF); while ( (r = read(fromfd, buf, BIGBUF)) > 0) write(tofd, buf, r); close(fromfd); close(tofd); free(buf); return 0; /* successful */ } int kbhit() { return Cconis(); } static void init_aline() { # ifdef __GNUC__ /* line A calls nuke registers d0-d2,a0-a2; not all compilers regard these as scratch registers, though, so we save them */ asm(" moveml d0-d2/a0-a2, sp@-"); asm(" .word 0xa000; movel d0, __a_line"); asm(" moveml sp@+, d0-d2/a0-a2"); # else asm(" movem.l d0-d2/a0-a2, -(sp)"); asm(" .dc.w 0xa000"); /* tweak as necessary for your compiler */ asm(" move.l d0, __a_line"); asm(" movem.l (sp)+, d0-d2/a0-a2"); # endif } # ifdef TEXTCOLOR /* used in termcap.c to decide how to set up the hilites */ unsigned long tos_numcolors = 2; void set_colors() { static char colorHE[] = "\033q\033b0"; if (!iflags.BIOS) return; init_aline(); tos_numcolors = 1 << (((unsigned char *) _a_line)[1]); if (tos_numcolors <= 2) { /* mono */ iflags.use_color = FALSE; return; } else { colors_changed = TRUE; nh_HE = colorHE; } } void restore_colors() { static char plainHE[] = "\033q"; if (colors_changed) nh_HE = plainHE; colors_changed = FALSE; } # endif /* TEXTCOLOR */ # ifdef SUSPEND #include # ifdef MINT extern int __mint; # endif int dosuspend() { # ifdef MINT extern int kill(); if (__mint == 0) { # endif pline("Sorry, it seems we have no SIGTSTP here. Try ! or S."); # ifdef MINT } else if(signal(SIGTSTP, SIG_IGN) == SIG_DFL) { suspend_nhwindows((char *)0); (void) signal(SIGTSTP, SIG_DFL); (void) kill(0, SIGTSTP); get_scr_size(); resume_nhwindows(); } else { pline("I don't think your shell has job control."); } # endif /* MINT */ return(0); } # endif /* SUSPEND */ #endif /* TOS */ nethack-3.4.3/sys/atari/unx2atar.sed0100644000000000000000000000143707764735041016036 0ustar rootroot: loop /\\$/N /\\$/b loop # for each line, append any continuation lines before trying to classify it /^ / { # if it starts with a tab, it's meant for the shell, and we should think # about reversing the slashes s;cd ../util;cd ..\\util; s;cd ../src;cd ..\\src; /librarian/ s;dat/options;dat\\options; /$(MAKE)/b /$(CC)/b s;/;\\;g } # unfortunately, we do not want to reverse *all* the slashes, as even the # Atari make and gcc like forward ones, and it's messy to avoid the ones in # sed addresses # so, flip the first one in e.g. # @( cd ../util ; $(MAKE) ../include/onames.h ) # flip the librarian-related ones in dat/options # ignore other lines related to make and gcc # and flip any slashes left over, which include a number of UNIX-only things # that we didn't need to do but don't hurt nethack-3.4.3/sys/be/0040755000000000000000000000000007764735105013062 5ustar rootrootnethack-3.4.3/sys/be/bemain.c0100644000000000000000000001264007764735041014460 0ustar rootroot/* SCCS Id: @(#)bemain.c 3.4 1998/07/15 */ /* Copyright (c) Dean Luick, 1996. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "dlb.h" #include static void whoami(void); static void process_options(int argc, char **argv); static void chdirx(const char *dir); static void getlock(void); #ifdef __begui__ #define MAIN nhmain int nhmain(int argc, char **argv); #else #define MAIN main #endif int MAIN(int argc, char **argv) { int fd; char *dir; dir = nh_getenv("NETHACKDIR"); if (!dir) dir = nh_getenv("HACKDIR"); choose_windows(DEFAULT_WINDOW_SYS); chdirx(dir); initoptions(); init_nhwindows(&argc, argv); whoami(); /* * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ process_options(argc, argv); /* command line options */ #ifdef WIZARD if (wizard) Strcpy(plname, "wizard"); else #endif if(!*plname || !strncmp(plname, "player", 4) || !strncmp(plname, "games", 4)) askname(); plnamesuffix(); /* strip suffix from name; calls askname() */ /* again if suffix was whole name */ /* accepts any suffix */ Sprintf(lock,"%d%s", getuid(), plname); getlock(); dlb_init(); /* must be before newgame() */ /* * Initialization of the boundaries of the mazes * Both boundaries have to be even. */ x_maze_max = COLNO-1; if (x_maze_max % 2) x_maze_max--; y_maze_max = ROWNO-1; if (y_maze_max % 2) y_maze_max--; /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); if ((fd = restore_saved_game()) >= 0) { #ifdef WIZARD /* Since wizard is actually flags.debug, restoring might * overwrite it. */ boolean remember_wiz_mode = wizard; #endif #ifdef NEWS if(iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; /* in case dorecover() fails */ } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ if(!dorecover(fd)) goto not_recovered; #ifdef WIZARD if(!wizard && remember_wiz_mode) wizard = TRUE; #endif check_special_room(FALSE); if (discover) You("are in non-scoring discovery mode."); if (discover || wizard) { if(yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else { compress(fqname(SAVEF, SAVEPREFIX, 0)); } } flags.move = 0; } else { not_recovered: player_selection(); newgame(); if (discover) You("are in non-scoring discovery mode."); flags.move = 0; set_wear(); (void) pickup(1); } moveloop(); return 0; } static void whoami(void) { /* * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS * 2. Use $USER or $LOGNAME (if 1. fails) * The resulting name is overridden by command line options. * If everything fails, or if the resulting name is some generic * account like "games", "play", "player", "hack" then eventually * we'll ask him. */ char *s; if (*plname) return; if (s = nh_getenv("USER")) { (void) strncpy(plname, s, sizeof(plname)-1); return; } if (s = nh_getenv("LOGNAME")) { (void) strncpy(plname, s, sizeof(plname)-1); return; } } /* normalize file name - we don't like .'s, /'s, spaces */ void regularize(char *s) { register char *lp; while((lp=strchr(s, '.')) || (lp=strchr(s, '/')) || (lp=strchr(s,' '))) *lp = '_'; } static void process_options(int argc, char **argv) { int i; while (argc > 1 && argv[1][0] == '-') { argv++; argc--; switch (argv[0][1]) { case 'D': #ifdef WIZARD wizard = TRUE; break; #endif /* otherwise fall thru to discover */ case 'X': discover = TRUE; break; #ifdef NEWS case 'n': iflags.news = FALSE; break; #endif case 'u': if(argv[0][2]) (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); else if (argc > 1) { argc--; argv++; (void) strncpy(plname, argv[0], sizeof(plname)-1); } else raw_print("Player name expected after -u"); break; case 'p': /* profession (role) */ if (argv[0][2]) { if ((i = str2role(&argv[0][2])) >= 0) flags.initrole = i; } else if (argc > 1) { argc--; argv++; if ((i = str2role(argv[0])) >= 0) flags.initrole = i; } break; case 'r': /* race */ if (argv[0][2]) { if ((i = str2race(&argv[0][2])) >= 0) flags.initrace = i; } else if (argc > 1) { argc--; argv++; if ((i = str2race(argv[0])) >= 0) flags.initrace = i; } break; case '@': flags.randomall = 1; break; default: raw_printf("Unknown option: %s", *argv); break; } } } static void chdirx(const char *dir) { if (!dir) dir = HACKDIR; if (chdir(dir) < 0) error("Cannot chdir to %s.", dir); /* Warn the player if we can't write the record file */ /* perhaps we should also test whether . is writable */ check_recordfile(dir); } void getlock(void) { int fd; regularize(lock); set_levelfile_name(lock, 0); fd = creat(lock, FCMASK); if(fd == -1) { error("cannot creat lock file."); } else { if(write(fd, (genericptr_t) &hackpid, sizeof(hackpid)) != sizeof(hackpid)){ error("cannot write lock"); } if(close(fd) == -1) { error("cannot close lock"); } } } #ifndef __begui__ /* * If we are not using the Be GUI, then just exit -- we don't need to * do anything extra. */ void nethack_exit(int status); void nethack_exit(int status) { exit(status); } #endif /* !__begui__ */ nethack-3.4.3/sys/be/README0100644000000000000000000000473407764735041013746 0ustar rootrootThis file is sys/be/README. It is for those intending to compile NetHack 3.3 on a BeOS 4.5 system. BeOS NetHack currently only supports the TTY windowing system. In order to compile it, it would benefit you greatly to think of your Be system as a UNIX variant. It is possible to compile using BeIDE. However, there are four executables and several steps involved in making NetHack. Unless you are extremely familiar with the build sequence and are willing to modify the code somewhat, I suggest you avoid it for now. Let the UNIX Makefiles take care of all that for you. Known problems: + No special characters for walls. None of the fonts available for use in a tty window has the graphics characters needed to improve the look. If such a font existed, then all you need to do is set the dungeon, object, and/or monter mappings in your defaults file. + The arrow keys don't work. Build instructions. From a freshly unpacked source tree: 1. Copy the Makfiles in sys/unix to their proper spots. You may use setup.sh or copy them by hand. Using setup.sh to create links instead of copying the Makefiles will work, but BeOS will not let you edit a link. It may be helpful to read sys/unix/Install.unx. 2. Edit src/Makefile: o Change System to SysBe. o Comment out the UNIX versions of SYSSRC and SYSOBJ variables. o Uncomment the BeOS versions of SYSRC and SYSOBJ. o Uncomment the BeOS versions of CC, CFLAGS, LD, and LFLAGS. The flags are different for Intel vs BeBox/Mac. o Uncomment one of the Intel or BeBox/Mac BeOS versions of CC, CFLAGS, LD, and LFLAGS. o Comment out the default CFLAGS and LFLAGS. o Change WINTTYLIB to be -ltermcap. 3. Edit util/Makefile: o If on a BeBox/Mac: - Uncomment the BeOS versions of CC and CFLAGS - Comment out the default CFLAGS and LFLAGS. o If on Intel: - the default values of CFLAGS and LFLAGS work fine o Change YACC and LEX to be bison -y and flex respectively. 4. Edit include/config.h to change HACKDIR to be the location of your install directory. 5. Edit top level Makefile and change GAMEDIR to match HACKDIR in include/config.h. Make sure the path to GAMEDIR exists. Change SHELLDIR to a "throw away" directory, like /tmp. We don't use the shell. Change CHOWN and CHGRP commands to "true", there really aren't groups on the BeOS. 6. Type "make install" at the top level. It is possible that some necessary steps needed to make the game have been omitted. Feel free to ad-lib as necessary. nethack-3.4.3/sys/mac/0040755000000000000000000000000007764735105013234 5ustar rootrootnethack-3.4.3/sys/mac/Install.mw0100644000000000000000000002222407764735041015205 0ustar rootrootBuilding a PPC NetHack 3.4 with the Metrowerks compilers You must be familiar with the Metrowerks compiler and know how to construct projects. The NetHack source may come with the four pre-made projects that are needed to build NetHack and the files it needs. These four projects are in :sys:mac and are MakeDefs.u, DgnComp.u, LevComp.u, and NetHack.u. If you do not have them, or wish to construct them yourself, see the section "Project Contents" below. 1. Move the projects MakeDefs.u, DgnComp.u, LevComp.u, and NetHack.u to the top level of the NetHack tree. If you are building your own, create each project as needed, in the order given below. 2. Create a folder "lib" in the top level. This is where the files used by NetHack will be deposited by MakeDefs, DgnComp, and LevComp. 3. Build and run MakeDefs. You will be presented with a list of options. Initially choose them all (the default). Later you may wish to only run a few of them. The options are "odemvpqrhz", each of which makes a file: -o creates :include:onames.h -p creates :include:pm.h -z creates :src:vis_tab.c -m creates :src:monstr.c -e creates :dat:dundeon.pdf -v creates :lib:options -d creates :lib:data -r creates :lib:rumors -h creates :lib:oracles -q creates :lib:quest.dat 4. If you are _not_ using DLB, follow these directions. As of v3.3, DLB is ON for the Mac. Copy the following files. You may want to change News or NHDeflts. a. copy ':sys:mac:MacHelp' to ':lib:MacHelp' b. copy ':sys:mac:News' to ':lib:News' c. copy ':sys:mac:NHDeflts' to ':lib:NetHack Defaults' d. copy ':dat:cmdhelp' to ':lib:cmdhelp' e. copy ':dat:help' to ':lib:help' f. copy ':dat:hh' to 'lib:hh' g. copy ':dat:history' to ':lib:history' h. copy ':dat:license' to ':lib:license' i. copy ':dat:opthelp' to ':lib:opthelp' j. copy ':dat:wizhelp' to ':lib:wizhelp' 5. Create an empty file, ':lib:record' 6. Build and run DgnComp. This will create a file "dungeon" in the lib directory. 7. Build and run LevComp. This will build the level files (*.lev) in the lib directory. 8. Build NetHack. Move NetHack in the lib directory. ------------------------ Building NetHack with MetroWerks IDE 1.x (DR7-DR10, DR11 was never used) To build NetHack, you will need to create four projects at the top level of the NetHack directory tree. These four projects are MakeDefs.u, DgnComp.u, LevComp.u, and NetHack.u. The projects don't have to end in ".u", but you should append some form of ".XXX" to the end of the project's name to distinguish the project from the executable that it produces. The files and libraries to include in these projects are listed in the "Project Contents" section below. You must create and run Makedefs before creating NetHack because MakeDefs will create files used by NetHack. Use the MacOS C/C++ template for each of the projects. The libraries included will be overkill for all the projects (e.g. the C++ libraries are not needed). Add the .c and resource files as indicated below. Unless otherwise noted, the projects can use the default preferences: Font The tabbing on all non-mac files is 8. All mac files have a tab of 4. PPC Processor All projects must have the same alignment to build a consistent NetHack. To share save files with 68K, the alignments must match for their projects, as well. Turn on Global Optimization (official version is compiled with level 1). If you don't turn it on, some files may not compile because of register overflow. [NetHack only] PPC Project Set name to Other settings [NetHack only] creator: nh31 preferred heap size:2500 minimum heap size: 2000 stack size: 128 [PPC only] The SIOUX library may be replaced with console.stubs.c for the NetHack project. NOTE: As NetHack 3.3, you must turn on OLDROUTINENAMES -- so you can't use the default pre-compiled header. You should either remove it from the preferences or insert another precompiled header that has this define off. ------------------------ Building NetHack with MetroWerks IDE 2.0. This is for building a PowerPC version only. This doesn't take advantage of the IDE's subprojects. These will be investigated later. MakeDefs.u, DgnComp.u, LevComp.u: Select ANSI C Console PPC. Settings: PPC Target + Change File Name to MakeDefs, DgnComp, or LevComp respectively. C/C++ Language + Turn off ANSI strict, ANSI Keywords Only, Expand Trigraphs PPC Processor + Turn on global optimization (at least to level 1) NetHack.u: Basic ToolBox PPC PPC Target + Change File Name to NetHack. Other settings creator: nh31 preferred heap size:2500 minimum heap size: 2000 stack size: 128 [PPC only] C/C++ Language + Options ANSI strict, ANSI Keywords Only, Expand Trigraphs are already turned off, so you don't have to do anything. PPC Processor + Turn on global optimization (at least to level 1) ------------------------ Creating projects for NetHack with MetroWerks IDE 3.3 (Pro 4) This is what I changed from the default settings when creating a 68K version. Some of the settings may not be necessary. For example, NetHack doesn't use floating point, so I didn't have to check 8 byte doubles. Some are interrelated. For example, the codegen and the Math and MSL libraries used. For MakeDefs.u, DgnComp.u, LevComp.u: 1. Select File>>New Project...>>MacOS>>C_C++>>Standard Console>>Std C Console 68K 2. 68K Settings: Target Settings: + Set "Target Name" to {MakeDefs,DgnComp,LevComp}. 68K Target: + Set "File Name" to {MakeDefs,DgnComp,LevComp}. C/C++ Language: + Check Require Function Prototypes, uncheck everything else. + Clear "Prefix File". 68K Processor: + Set "Code Model" to Large. + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables, Far String Constants. Uncheck everything else. 3. Libraries 68K + Remove the C++ Library (it is not needed). + Change math library to MathLib68K Fa(4i_8d).Lib. + Change MSL C library to MSL C.68K Fa(4i_8d).Lib. Note: The actual libraries used must match the CodeGen options in 68K Processor. For NetHack.u: 1. Select File>>New Project...>>MacOS>>C_C++>>MacOS ToolBox>>MacOS ToolBox 68K 2. 68K Settings Target Settings: + Set "Target Name" to NetHack Debug and NetHack Final. 68K Target: + Set "File Name" to NetHack Debug and NetHack Final. + Set "Creator" to 'nh31'. + Set "Preferred Heap Size (k)" to 2500. + Set "Minimum Heap Size (k)" to 1500. C/C++ Language: + Check Require Function Prototypes, uncheck everything else. + Set "Prefix File" to LocalDefines.h. I use this header to define OLDROUTINENAMES because the pre-compiled header doesn't have it set any more. One of these days we'll fix up the code... 68K Processor: + Set "Code Model" to Large. + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables, Far String Constants. Uncheck everything else. 3. Libraries 68K + Remove the C++ Library (it is not needed). + Change math library to MathLib68K Fa(4i_8d).Lib. + Change MSL C library to MSL C.68K Fa(4i_8d).Lib. Note: The actual libraries used must match the CodeGen options in 68K Processor. For Recover.u: 1. Select File>>New Project...>>MacOS>>C_C++>>MacOS ToolBox>>MacOS ToolBox 68K 2. 68K Settings Target Settings: + Set "Target Name" to Recover Debug and Recover Final. 68K Target: + Set "File Name" to Recover Debug and Recover Final. + Set "Creator" to 'nhRc'. C/C++ Language: + Check Require Function Prototypes, uncheck everything else. + Set "Prefix File" to LocalDefines.h. I use this header to define OLDROUTINENAMES because the pre-compiled header doesn't have it set any more. One of these days we'll fix up the code... 68K Processor: + Set "Code Model" to Large. + Check 68020 Codegen, 4-Byte Ints, 8-Byte Doubles, Far Data, Far Method Tables, Far String Constants. Uncheck everything else. 3. Libraries 68K + Remove the C++ Library (it is not needed). + Change math library to MathLib68K Fa(4i_8d).Lib. + Change MSL C library to MSL C.68K Fa(4i_8d).Lib. Note: The actual libraries used must match the CodeGen options in 68K Processor. ------------------------ Project Contents: MakeDefs.u should contain the following source files: src objects.c monst.c util makedefs.c DgnComp.u should contain the following source files: src alloc.c sys:share dgn_lex.c dgn_yacc.c util dgn_main.c panic.c LevComp.u should contain the following source files: src alloc.c decl.c drawing.c monst.c objects.c sys:mac macerrs.c macfile.c sys:share lev_lex.c lev_yacc.c util lev_main.c panic.c NetHack.u should contain the following source files: src *.c [can do an add all] sys:mac *.c except mrecover.c NetHack.rsrc machelp.bh [for baloon help] Sound.rsrc [if you wish to have a few, crude sounds] Files.r [if you use DLB (on by default)] sys:share random.c win:tty *.c [can do an add all - termcap.c is not needed, but will compile to nothing] Note: src:monstr.c and src:vis_tab.c are created by MakeDefs -m and -s respectively. Recover.u should contain the following source files: sys:mac mrecover.c mrecover.rsrc nethack-3.4.3/sys/mac/Files.r0100644000000000000000000001605207764735041014461 0ustar rootroot#include #include "date.h" #include "patchlevel.h" resource 'plst' (0, purgeable) { }; resource 'vers' (1, purgeable) { VERSION_MAJOR, (VERSION_MINOR<<4) | PATCHLEVEL, final, EDITLEVEL, verUS, VERSION_STRING, VERSION_STRING }; resource 'vers' (2, purgeable) { VERSION_MAJOR, (VERSION_MINOR<<4) | PATCHLEVEL, final, EDITLEVEL, verUS, VERSION_STRING, "devteam@nethack.org" }; read 'File' (1000,"cmdhelp") ":dat:cmdhelp"; read 'File' (1001,"help") ":dat:help"; read 'File' (1002,"hh") ":dat:hh"; read 'File' (1003,"history") ":dat:history"; read 'File' (1004,"license") ":dat:license"; read 'File' (1005,"MacHelp") ":sys:mac:MacHelp"; read 'File' (1006,"News") ":sys:mac:News"; read 'File' (1007,"opthelp") ":dat:opthelp"; read 'File' (1008,"wizhelp") ":dat:wizhelp"; read 'File' (1009,"air.lev") ":lib:air.lev"; read 'File' (1010,"asmodeus.lev") ":lib:asmodeus.lev"; read 'File' (1011,"astral.lev") ":lib:astral.lev"; read 'File' (1012,"baalz.lev") ":lib:baalz.lev"; read 'File' (1013,"bigrm-1.lev") ":lib:bigrm-1.lev"; read 'File' (1014,"bigrm-2.lev") ":lib:bigrm-2.lev"; read 'File' (1015,"bigrm-3.lev") ":lib:bigrm-3.lev"; read 'File' (1016,"bigrm-4.lev") ":lib:bigrm-4.lev"; read 'File' (1017,"bigrm-5.lev") ":lib:bigrm-5.lev"; read 'File' (1018,"castle.lev") ":lib:castle.lev"; read 'File' (1019,"data") ":lib:data"; read 'File' (1020,"dungeon") ":lib:dungeon"; read 'File' (1021,"earth.lev") ":lib:earth.lev"; read 'File' (1022,"fakewiz1.lev") ":lib:fakewiz1.lev"; read 'File' (1023,"fakewiz2.lev") ":lib:fakewiz2.lev"; read 'File' (1024,"fire.lev") ":lib:fire.lev"; read 'File' (1025,"juiblex.lev") ":lib:juiblex.lev"; read 'File' (1026,"knox.lev") ":lib:knox.lev"; read 'File' (1027,"medusa-1.lev") ":lib:medusa-1.lev"; read 'File' (1028,"medusa-2.lev") ":lib:medusa-2.lev"; read 'File' (1029,"minefill.lev") ":lib:minefill.lev"; read 'File' (1030,"minend-1.lev") ":lib:minend-1.lev"; read 'File' (1031,"minend-2.lev") ":lib:minend-2.lev"; read 'File' (1032,"minend-3.lev") ":lib:minend-3.lev"; read 'File' (1033,"minend-4.lev") ":lib:minend-4.lev"; read 'File' (1034,"minetn-1.lev") ":lib:minetn-1.lev"; read 'File' (1035,"minetn-2.lev") ":lib:minetn-2.lev"; read 'File' (1036,"minetn-3.lev") ":lib:minetn-3.lev"; read 'File' (1037,"minetn-4.lev") ":lib:minetn-4.lev"; read 'File' (1038,"minetn-5.lev") ":lib:minetn-5.lev"; read 'File' (1039,"minetn-6.lev") ":lib:minetn-6.lev"; read 'File' (1040,"minetn-7.lev") ":lib:minetn-7.lev"; read 'File' (1041,"options") ":lib:options"; read 'File' (1042,"oracle.lev") ":lib:oracle.lev"; read 'File' (1043,"oracles") ":lib:oracles"; read 'File' (1044,"orcus.lev") ":lib:orcus.lev"; read 'File' (1045,"quest.dat") ":lib:quest.dat"; read 'File' (1046,"rumors") ":lib:rumors"; read 'File' (1047,"sanctum.lev") ":lib:sanctum.lev"; read 'File' (1048,"soko1-1.lev") ":lib:soko1-1.lev"; read 'File' (1049,"soko1-2.lev") ":lib:soko1-2.lev"; read 'File' (1050,"soko2-1.lev") ":lib:soko2-1.lev"; read 'File' (1051,"soko2-2.lev") ":lib:soko2-2.lev"; read 'File' (1052,"soko3-1.lev") ":lib:soko3-1.lev"; read 'File' (1053,"soko3-2.lev") ":lib:soko3-2.lev"; read 'File' (1054,"soko4-1.lev") ":lib:soko4-1.lev"; read 'File' (1055,"soko4-2.lev") ":lib:soko4-2.lev"; read 'File' (1056,"tower1.lev") ":lib:tower1.lev"; read 'File' (1057,"tower2.lev") ":lib:tower2.lev"; read 'File' (1058,"tower3.lev") ":lib:tower3.lev"; read 'File' (1059,"valley.lev") ":lib:valley.lev"; read 'File' (1060,"water.lev") ":lib:water.lev"; read 'File' (1061,"wizard1.lev") ":lib:wizard1.lev"; read 'File' (1062,"wizard2.lev") ":lib:wizard2.lev"; read 'File' (1063,"wizard3.lev") ":lib:wizard3.lev"; read 'File' (1100,"Arc-fila.lev") ":lib:Arc-fila.lev"; read 'File' (1101,"Arc-filb.lev") ":lib:Arc-filb.lev"; read 'File' (1102,"Arc-goal.lev") ":lib:Arc-goal.lev"; read 'File' (1103,"Arc-loca.lev") ":lib:Arc-loca.lev"; read 'File' (1104,"Arc-strt.lev") ":lib:Arc-strt.lev"; read 'File' (1105,"Bar-fila.lev") ":lib:Bar-fila.lev"; read 'File' (1106,"Bar-filb.lev") ":lib:Bar-filb.lev"; read 'File' (1107,"Bar-goal.lev") ":lib:Bar-goal.lev"; read 'File' (1108,"Bar-loca.lev") ":lib:Bar-loca.lev"; read 'File' (1109,"Bar-strt.lev") ":lib:Bar-strt.lev"; read 'File' (1110,"Cav-fila.lev") ":lib:Cav-fila.lev"; read 'File' (1111,"Cav-filb.lev") ":lib:Cav-filb.lev"; read 'File' (1112,"Cav-goal.lev") ":lib:Cav-goal.lev"; read 'File' (1113,"Cav-loca.lev") ":lib:Cav-loca.lev"; read 'File' (1114,"Cav-strt.lev") ":lib:Cav-strt.lev"; read 'File' (1115,"Hea-fila.lev") ":lib:Hea-fila.lev"; read 'File' (1116,"Hea-filb.lev") ":lib:Hea-filb.lev"; read 'File' (1117,"Hea-goal.lev") ":lib:Hea-goal.lev"; read 'File' (1118,"Hea-loca.lev") ":lib:Hea-loca.lev"; read 'File' (1119,"Hea-strt.lev") ":lib:Hea-strt.lev"; read 'File' (1120,"Kni-fila.lev") ":lib:Kni-fila.lev"; read 'File' (1121,"Kni-filb.lev") ":lib:Kni-filb.lev"; read 'File' (1122,"Kni-goal.lev") ":lib:Kni-goal.lev"; read 'File' (1123,"Kni-loca.lev") ":lib:Kni-loca.lev"; read 'File' (1124,"Kni-strt.lev") ":lib:Kni-strt.lev"; read 'File' (1125,"Mon-fila.lev") ":lib:Mon-fila.lev"; read 'File' (1126,"Mon-filb.lev") ":lib:Mon-filb.lev"; read 'File' (1127,"Mon-goal.lev") ":lib:Mon-goal.lev"; read 'File' (1128,"Mon-loca.lev") ":lib:Mon-loca.lev"; read 'File' (1129,"Mon-strt.lev") ":lib:Mon-strt.lev"; read 'File' (1130,"Pri-fila.lev") ":lib:Pri-fila.lev"; read 'File' (1131,"Pri-filb.lev") ":lib:Pri-filb.lev"; read 'File' (1132,"Pri-goal.lev") ":lib:Pri-goal.lev"; read 'File' (1133,"Pri-loca.lev") ":lib:Pri-loca.lev"; read 'File' (1134,"Pri-strt.lev") ":lib:Pri-strt.lev"; read 'File' (1135,"Ran-fila.lev") ":lib:Ran-fila.lev"; read 'File' (1136,"Ran-filb.lev") ":lib:Ran-filb.lev"; read 'File' (1137,"Ran-goal.lev") ":lib:Ran-goal.lev"; read 'File' (1138,"Ran-loca.lev") ":lib:Ran-loca.lev"; read 'File' (1139,"Ran-strt.lev") ":lib:Ran-strt.lev"; read 'File' (1140,"Rog-fila.lev") ":lib:Rog-fila.lev"; read 'File' (1141,"Rog-filb.lev") ":lib:Rog-filb.lev"; read 'File' (1142,"Rog-goal.lev") ":lib:Rog-goal.lev"; read 'File' (1143,"Rog-loca.lev") ":lib:Rog-loca.lev"; read 'File' (1144,"Rog-strt.lev") ":lib:Rog-strt.lev"; read 'File' (1145,"Sam-fila.lev") ":lib:Sam-fila.lev"; read 'File' (1146,"Sam-filb.lev") ":lib:Sam-filb.lev"; read 'File' (1147,"Sam-goal.lev") ":lib:Sam-goal.lev"; read 'File' (1148,"Sam-loca.lev") ":lib:Sam-loca.lev"; read 'File' (1149,"Sam-strt.lev") ":lib:Sam-strt.lev"; read 'File' (1150,"Tou-fila.lev") ":lib:Tou-fila.lev"; read 'File' (1151,"Tou-filb.lev") ":lib:Tou-filb.lev"; read 'File' (1152,"Tou-goal.lev") ":lib:Tou-goal.lev"; read 'File' (1153,"Tou-loca.lev") ":lib:Tou-loca.lev"; read 'File' (1154,"Tou-strt.lev") ":lib:Tou-strt.lev"; read 'File' (1155,"Val-fila.lev") ":lib:Val-fila.lev"; read 'File' (1156,"Val-filb.lev") ":lib:Val-filb.lev"; read 'File' (1157,"Val-goal.lev") ":lib:Val-goal.lev"; read 'File' (1158,"Val-loca.lev") ":lib:Val-loca.lev"; read 'File' (1159,"Val-strt.lev") ":lib:Val-strt.lev"; read 'File' (1160,"Wiz-fila.lev") ":lib:Wiz-fila.lev"; read 'File' (1161,"Wiz-filb.lev") ":lib:Wiz-filb.lev"; read 'File' (1162,"Wiz-goal.lev") ":lib:Wiz-goal.lev"; read 'File' (1163,"Wiz-loca.lev") ":lib:Wiz-loca.lev"; read 'File' (1164,"Wiz-strt.lev") ":lib:Wiz-strt.lev"; nethack-3.4.3/sys/mac/NHDeflts0100644000000000000000000000770507764735041014633 0ustar rootroot# SCCS Id: @(#)NetHack Defaults 3.4 2002/03/15 # Copyright (c) 2002 by Dean Luick, Mark Modrall, and Kevin Hugo # NetHack may be freely redistributed. See license for details. # # Default settings for the Macintosh port of NetHack. # Lines beginning with a `#' character are "comments" and are # ignored all the way to the end of the line. Using this # method, some of the lines below have been disabled so you # can see an example without having those options actually # set. Remove the `#' character to "uncomment" the line and # allow those options to take effect. ### Display ### # Uncomment for the traditional single-window tty interface #OPTIONS=win:tty # Boulder symbol #OPTIONS=boulder:0 # Color OPTIONS=color # Fonts #OPTIONS=font_map:NewHackFont,font_size_map:9 #OPTIONS=font_menu:geneva,font_size_menu:9 #OPTIONS=font_message:PSHackFont,font_size_message:9 #OPTIONS=font_status:monaco,font_size_status:9 #OPTIONS=font_text:geneva,font_size_text:9 # Don't make dark corridors look like lit corridors OPTIONS=!lit_corridor # Enable sound and beeps OPTIONS=sound,!silent ### Start-up and ending ### # Don't display the game introduction and new feature list at start #OPTIONS=!legacy,!news # Save game state periodically in case of crashes (recommended) OPTIONS=checkpoint # How to prompt for things after death #OPTIONS=disclose:+i na -v yg nc # Show tombstone and top scores at death OPTIONS=tombstone,scores:10t/3a/o # Show top ten list in its own window #OPTIONS=toptenwin ### User input and feedback ### # Choose between menus or text prompts # (traditional, combination, partial, or full) OPTIONS=menustyle:full # Extended (`#') commands by menu #OPTIONS=extmenu # Increase the number of message lines remembered #OPTIONS=msghistory:60 # Enable the number pad keys OPTIONS=number_pad # Pause for --more-- and make it boldface OPTIONS=page_wait,standout # Ask for confirmation with the #pray command OPTIONS=prayconfirm # Allow spacebar as rest command #OPTIONS=rest_on_space # Display experience, score, and time on status line OPTIONS=showexp,showscore,time # Turn off animations #OPTIONS=!sparkle # Display a little more information with some commands #OPTIONS=suppress_alert:3.3.0 OPTIONS=verbose ### Character ### # A Valkyrie... #OPTIONS=name:Brunhilda,role:Val # The old way works, too: #OPTIONS=name:Brunhilda-V # How about an Elven Ranger? #OPTIONS=name:Silwa,role:Ranger,race:Elf,gender:Male # Always a human female #OPTIONS=race:human,female # Or leave them commented out and the game will ask you ### Inventory ### # Automatically dig if wielding a pick #OPTIONS=autodig # Disable autopickup (toggle it with the `@' command) #OPTIONS=!autopickup,pickup_types:$* # Automatically fill the quiver #OPTIONS=autoquiver # Don't use fixed inventory letters OPTIONS=!fixinv,perm_invent,sortpack # What you want to call slime molds #OPTIONS=fruit:grape # Desired inventory display order #OPTIONS=packorder:)[( # How much you're willing to carry without confirmation #OPTIONS=pickup_burden:B # Put weapon in secondary slot when wielding another #OPTIONS=pushweapon ### Pets ### # What to call your starting pet, and its type #OPTIONS=dogname:Quinn,catname:Vladimir,horsename:Silver,pettype:dog # Don't intentionally attack your pets OPTIONS=confirm,!hilite_pet,safe_pet ### Unused options ### # Now obsolete # # background, large_font, popup_dialog, use_stone # Obsolete way to obtain reverse video; use at your own risk #OPTIONS=palette:000/c22/2c2/ca0/22c/a2a/2aa/ccc/999/f00/0f0/dd0/00f/d0d/0dd/fff/999/444/622/62c/-222 # Options used in tty window mode, but not mac window mode # # menu_..., msg_window, timed_delay, use_inverse, vary_msgcount # Options used by other ports but not Macintosh: # # align_message, align_status, ascii_map, BIOS, checkspace, # decgraphics, eight_bit_tty, ibmgraphics, ignintr, mail, # map_mode, null, player_selection, preload_tiles, rawio, # splash_screen, tiled_map, tile_..., videocolors, videoshades, # windowcolors # End-of-file nethack-3.4.3/sys/mac/MacHelp0100644000000000000000000001604707764735041014474 0ustar rootroot Macintosh-specific help file for NetHack 3.4 The following are options, features, or concerns specific to the MacOS Classic port of NetHack. Bug reports, suggestions, comments, and so on, should be addressed to: To: nethack-bugs@nethack.org Subject: Mac NetHack 3.4 or you can use our on-line bug reporting form at http://www.nethack.org Please include your machine-type, system software version and other relevant information (i.e. system extensions, monitor, accelerators and so on). === Configuration of a playground NetHack is packaged in a Dungeon Folder which includes: NetHack - the application file itself. NetHack Defaults - text file for default option settings. License - licensing terms for nethack. Guidebook - description of the game in long format. Recover - the application to restore save files from crashed games. Previous versions had a large number of data files in the Dungeon Folder. These are now packaged as resources inside the application file and will no longer appear in the Dungeon Folder. During play another file type appears: Player level files (labelled "iName.n", i is a constant number, Name is the player name and n is the dungeon level). Two other types of files will appear in the Dungeon Folder as a result of playing NetHack: Bones files (of previously deceased players). Saved games (labelled "save/iName", i is a number, same as above, and Name is the player name). The following files or file types may be thrown away: logfile - if it becomes too large. A new one will be generated. Player level files _not_ belonging to a game in progress. Alternatively, these files may be processed by Recover, which may be able to restore a save file from the level files. Old bones files and saved games. === Resuming a saved game Double-click (or open) the desired saved game file or open NetHack and answer the "Who are you?" dialog with the player name of the saved game in the Dungeon Folder. === Windows The Dungeon Map and Message windows are the essential windows used during window-mode play. During tty-mode play there is only one window which displays the map, messages, lists and other info. For window-mode play, lists (e.g. the list of objects that may be wielded) and special info windows appear as needed. Windows may be closed in the normal ways (i.e. clicking their close box, choosing 'Close' from the File menu or typing the command equivalent for 'Close', cmd-W) and the list windows may also be dismissed by hitting the space bar (or Return or Enter Keys). Hitting the ESCape key will dismiss special windows without scrolling to the end. The command "Reposition" on the File menu may be used to restore the the startup sizes and locations of the various windows. The window positions are saved in a file labelled "NetHack Windows" in the appropriate preferences folder. === Default options The following options are specific to the Macintosh port: background: - black or white MACgraphics - use enhanced dungeon map symbols [TRUE] page_wait - display --MORE-- after messages [TRUE] Default options may be set by editing the NetHack Defaults text file (using SimpleText or your favorite editor). The following notation is used: OPTIONS=name:Arnold,time,!tombstone It should also be mentioned here that there are two graphic interface modes available: 'mac' and 'tty'. Choosing between these interfaces is accomplished by the option: window:mac - the default multi-window Macintosh(tm) interface. window:tty - traditional Unix(tm)-style TTY window interface. See option help (?f or ?g) for more details. === Movement by mouse The shape (direction) of the cursor over the Dungeon Map window, typically, indicates the direction that you desire to move in when the mouse is clicked. Modifier keys affect mouse-movement in the same way that they affect keyboard movement. Clicking on yourself means rest one turn and Shift-clicking on yourself means "open door" in the subsequently indicated direction. === Sounds Real sounds (resources) have been added for various instruments. The option "silent" [FALSE] controls whether or not a sound will be heard when an instrument is applied. === Explore and Debug Modes As of version 3.1.2, you can enter Explore (aka Discover) mode or Debug (aka Wizard) mode by choosing the appropriate entries on the 'Mode' popup-menu section of the "Who are you?" startup dialog. This same dialog allows you to specify your role, race, gender, alignment, and name, of course. Starting in Explore mode is essentially the same as playing in Regular mode except that if you are killed then you are given an opportunity to override your death. Because of this advantage, your Explore mode scores are not entered on the scoreboard record. You also get a wand of wishing in your starting inventory and can see your intrinsic abilities using the command ctl-X (also available on the 'Explore' submenu on the File menu). Starting in Debug mode is only intended for developers and others interested in characterizing bugs. Using this mode for other purposes will have confusing results and eliminate your enjoyment of the game! === Menus As of version 3.1.2, the menus have been reworked to provide access to all the NetHack commands and a special 'Kbd' menu was added to facilitate play using only the mouse. In some cases, a command may appear on more than one menu. In general, the commands have been grouped to appear on an appropriate menu: File - commands related to windows, start mode and play control. Help - info commands generally not related to a specific game (i.e. (key descriptions, version info, internal option editor). Info - commands that are generally game-specific (i.e. inventory related, describe features seen on the map or name things). Equip - commands related to things you might wield or wear. Act - commands for actions that you might do alone (i.e. wait, jump) or do with another dungeon denizen (i.e. pay, chat). Magic - commands for things that you might do with items (drop, eat, read) or spell-related. Bits - commands for things you might do to dungeon pieces (i.e. open door, loot chest, engrave on the floor, climb stairs). The key related to a command generally appears to the left of the menu entry for that command (i.e. w for wield and W for wear). A leftmost # denotes an extended command (without a related key) and a left cloverleaf or command symbol denotes a command that requires either a control or command key modifier (i.e. holding down the control or command key while hitting the related key). === The members of the Macintosh NetHack port team hope you enjoy this game. nethack-3.4.3/sys/mac/NHrsrc.hqx0100644000000000000000000017561007764735041015163 0ustar rootroot(This file must be converted with BinHex 4.0) :$%jPG%KKBfXZFR0bB`"58e*$8P0&4!%!N!I4j"fk!*!%!3#3!mRS!!$)k!!!"r` !N!30!"!!,3!`S!)!U!#3"4B!1!!R!1')'&0dE`a1CA4)B@0V,R*cFQ0UFfecFQ0 PER4c+f036(0`F'pM!!"58e*$8P0&4!%!!&-"%!#3%V0,SqB!N!CM'`!!b!%`!!% !N!J,Z3#3""8!N!AQ!9`!!3#3#!Zi!*!%&3"3!'i!qJ'i!!%!N!J(e!#3""8!8!" Z!2S"Z!!"!*!)"p-!N!39!&!!EJ$k!EJ!!3#3#!I5!*!%&3"3!'i!qJ'i!*!$(!% )!!J"5J$`!*!+"dePFh0KCf8i#J#3!a`",J!%!9)"bJ#3#JC6G'&dGA0V1!S!N!- @!(`!fJ$i!BS!N!3"!*!'66J+!*!$'J#q!!B"8!%b!*!%!3#3"34*EQC[)$J+!*! $)J!S!#J!M!#L!*!%!3#3"3e1G@aX)>EQ4[Gb!K1!S!N!-m$NjeE@*PFL"[CL" VCAPc6d019!8UN!9-8e4$"dYPH@0[C'9)3PP8"%0SBA*$5%&5"5U3"8a69%8!N!- J!#J!+!&+!Hi!N!S,4(9ZCf9[EL"0BA!i#J#3!b!!+!!S!+`"c!#3"!%!N!8,4'P KCfj[Fh4TBh-i#J#3!aB!!400B@-J6Q9d5'&MDb")C@a`b5mr!*!$J!#3#`rr!*! %r`$a!I!!N!2lm!m3(`#3!`qr$`%"m!#3!r[r%"$`!!$`$lrrmI!!$`rrqr!2!!! 2%"$r[`#3!`m"!I$lm!#3!r!3m!qr!*!$$`%2!2[`!*!$rr!!$lm!N!Ilm!#3"Jq r!*!(r`#3!i!!rj!%m!#3!r!!N!2r!*!$m!#3!rc`!!$`!*!$rrm!!2!!N!32!!$ `$r!!!!m!!2$rr`!!$`!!m2rr$rm2!!$`$r!!!!m!!2!!N!32!!$`$r!!!!m!!2$ `$`r`$`!!m2!2!!!2!!$`$r!!!!m!!2!!N!32!!$rN!B!N!4!!!!"`$)J14!G#!m )*qKIN!"$`%,J)R!41!iF!!i!"`!$!!!"`$2J1I!Gq!ri*rKrN!"r`(lJ2R!I1!i F!!i!"`!$!*!$3$rJ)$!J+#!m)!3Q"#m%,h3Q"#!%*J3TC#N%*J3J"$rm2q!rm$r i2r`rr$rm2r`rr$rm2r`rr$rm2r`rr$rm2r`!!!%!N!B2J!!!-'!!%#!3!"`3#!! 1%!J!$a!%!!H3!!3!!r!%!!(J"!!!m!3!-2[N!%mq'!"!(J!!3!m!!%!2J!"!%m! !3"(J!#!3m!!J%(J!%!Jm!!`B(J!$i!m!N!-(J!!!!m!!!!(J!*!$m!#3!hJ!N!- m!*!$(J#3!`i!N!-%!*!&$i!!!$rJ!"!rm!!F(rJ!$Kri!!mIr!!(Rr`!!rrm!!( rr!!!rr`!-2rm!(rq'!"rrJ!!Irm!!(rrJ!"rmm!!Ir(J!$r`m!!rm(J!(rJm!!r i(J!$i!m!N!-(J!!!!m!!!!(J!*!$m!#3!hJ!N!-m!*!$(J#3!`i!N!-%!!!"!!r rr!!)!!B!#!i&!!Q4")!*b)4!#1K%)!Ki4r!*2d!3#[b!%!SH!"!+&`!3#41!%!L *`"!)F1!3#!"`%!J!1"!)!"J3#'!!%!L3!!!3#@J!%!PTrK!)N!!!%!KJ!"!)!!! 3#'!!%!L3!!!3#3J!%!N*[j!!#*!!!"!)B!!3#!!!%!rrrr!2rr`!$rrq!!rrr`! 2rrq!$rrr`!rrrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr! 2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr! 2rrr`$rrrm!rrrr!2rrr`$rrrm!!!!J#3&rrrm!#3$2m3%"r`!*!($`#3!r%"N!- 2!*!($rm!!!m3N!6`!*!(qr!!$`'3"2!!N!Il[`!2%*!%(`#3"`qlm!m"N!32!*! )qlrr%*!%(`#3#!qlm3'3"!m!N!Rl[a#3""m!N!Er!!$rZr(rrr%2!*!&$a$rra$ l[r!!$r!!N!82!C!%$l[`!*!)$a#3"IZr!*!)$`'3"Iqlm!#3"`m3N!3I!2Zr!*! ($`'3"!m!$l[`!*!(m"#3!am!!2Zr!*!(m3'3!`m!!!qlm!#3"Jm3N!6`!!$l[`# 3"rm"!3r`!!!2Zr!!N!Irrr!!N!6l[`#3$Jqlm!#3$[Zr!*!1$l[`!*!1qlm!N!i 2Zr!!N!ll[`#3$Jqlm!#3$[[`!*!1$`#3!`)!N!2rN!N!N!I`!*!($r!!N!E`!*! $rr!!!!r2!*!'m!r`$a!I!!!2c2!!N!A`$lm!m3(`!!r-c`#3"I!!qr$`%"m!$mc -m!#3"2!!$lra!3m!$rq3!`#3"2!2!2[rram!N!32!*!%m2$rrlm!m!#3"!m!N!6 `m3%2qr!!N!82!*!%m2!3(`qr!*!&$`#3"2!2!3m!qr!!N!32!*!%m!$`%2!2[`# 3"!m!N!6`!!rr!!$lm!#3!`m!N!6`!*!&$lm!N!-2!*!%m!#3"[[`!!!2!*!%m!# 3"Jr`!!!2!*!%m!!2m!#3"`m!N!6`!2!2!*!($`#3"2!2$r$`!*!'$`#3"2!2$r$ `$rq3!r!!$`#3"2!!m!m!N!F2!*!%m!!2m!#3"`m!N!6`!*!+$`#3"2!!$r!!N!F 2!*!%m!$`$`#3"`m!N!6`$`!!m!#3"Jm!N!6`$`!!m!r`rj!$m!m!N!6`!2!2!*! ($`#3"2!!$r!!N!F2!*!%m!#3#Jm!N!6rN!`!N!8-!&S!EJ$Z!C)!J84%!*!$6!! #!*!&H!$'!)S"%!3#6dX!N!8+!%B!F`%3L"a$Eh9XC#"ZEh3JAM)JBQ9MBA9cC5" H-#iJ)&ia!*!&#J!8!#S!0+!#!*!%!3!2rr`!#!!'!!J1"3!*N35!#FL%3!MS4#! )H%I`#6p!%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J!F"!)!$J3#!!B%!Q8aP! +95P3#P8T8!T9+9!+95P3#C6'8!J!!"!+C6'3!!U95P!+P8T3#T9+8!U95P!+C6' 3!!J!!"!2rrr`$rrm!!rrrJ!2rrm!$rrrJ!rrrm!2rrrJ$rrrm!rrrr!2rrr`$rr rm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rr rm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!!N!0!2q! J-#!S)$`J"#5N+U3UT#5N)!3T*#UN+U3T*#!%2r`ri$r`2rJrr$rm2r`rr$rm2r` rr$rm2r`rr$rm2r`rr!!!!J#3!rq3#3#3"r!!N!F2m!#3"[!!N!2rm!!!$mm!N!E `$r!2%"m!!!r-m!#3"I!2[`$a!I!!$mc2!*!&m!$lm2!3(`!2c-c`!*!%m!!2[r% "$`!2rj!$!*!%m!m!qrrr(`#3"!m!N!6`m2rr[`$`!*!%$`#3"2$a!3rlm!#3"3m !N!6`m"!I$lm!N!82!*!%m!m"$`$lm!#3"!m!N!6`!2!3m!qr!*!%$`#3"2!!$rm !!2[`!*!$$`#3"2!!N!82[`#3!`m!N!6`!*!'qr!!!!m!N!6`!*!'$r!!!!m!N!6 `$r!2$`$r!!r`$`m!N!6`m!q3"!$`m!q3!`#3"2$`$j!%!2$`$j!$!*!%m2!2N!3 !m2!2N!-!N!6`m!q3"!$`m!q3!`#3"2!2m!m2!2m!$r!2$`#3"2!!N!S2!*!%m2! 2m!m2!2m!$r!2!*!%m*!$$j!%!2$`$`m!N!6`N!-2N!3!m2!2$`#3"2#3!`q3"!$ `m!m2!*!%m*!$$j!%!2$`$`m!N!6`m!r`$`m!r`!2m!m!N!6`!*!+$`#3"2q3$!# 3"5)!!3#3"9!"4!"N!Ai%!Np,!*!&"J!i!%B"I)J#AM!!N!1!!2q3"2!!N!2`!*! $r`#3!r!!N!2mm!!!m!#3!rrr!!$`!*!%$`!!m!m!m2!2!!$`N!82!!$`N!82!!$ `$`$`m!m!!2!!N!32!!$`m!m!m!m!!2#3"3m!!2#3"3m!!2$`$`$`$`!!m!#3"!m !!2q3"J#3!`Q)N!!!N!6q!!B!!2rh!!B!#`1l!!N!!J#3!cm!N$2B!*!'&%%!N!8 T3!!!-!!!'J!!!KK!"@YBL8!(i$P%))"!"*A!F"`"`K3!&3!8))r!rr!"q!#3!h1 !)!#3"5!!!!jJ!3!3!*![F!"3L!)B"!%#J+)!"!))J!!!B!"")K0X!!!#+)!!!IL *3!@J+83JJ%!%P8"3&!&#&!!9!"3JMm$rm!d)!*!$*%"3![2!!!3J!`!*N!!'e6R X6#!!"FZF,l[ZF!!1Flc[Iqk2$'%BZmlc[aM'-ImD!J3!%"JK--!!N!-#!*!%UDl j&+%N#P#YA1q"kP%846SJP(a#4#@Ll%!#55!&DeL*3!@J+83JJ%!%P8"3&!&#&!! 9!"3JMm$rm"-!2J!fG&a!"I`J%KSJ")!*)26IeV+5U3!'2'*S3$'))*'-BaM#%BS -SEc'-Ba*'-94$3d""!!3)#!33!#3!`)!N!5UdIJ!!"J!N!-M'!+!!*!$4L5#SN! !!$-b!!+U!!!"q)P!"D!T4##!3!593&!8!8)8!"8!&##2`2r`)`!5!!QXBL!pr$q 4+L3-Z$P!PB95e#&a!!TS3Upi-BeI3HaM#-)3LJdK@XBaM!NBa*%8L!"rR2Gcr6* pChRfImBeM(kS%&1Hplh1Fj*M'$U1Fk-BaLlRiZI1MDXb3!&9B!9V@2P"rErTI## !3!6eIprhrhq9q"Ai&IL2`2rhC3I)r)L[iZh,r#"mb#"cI#RqPiqj5#'[ciUSM5$ %6SL!)Urp#2[6qJiK'FI4miNBa)SNL!#-BaLNBc4VQ-BjJNBe9%8%%&4M'-BaM&* rreI4M'-BaM@"2%M4MQEXMriCDC!!!Iq2IM'aMmIrN!5A-``c$#"q"rmRrLIrN!2 iT3+&&)LXBaV,r$q4+$q)I%!1N!#&&E8K)3!6+32`a*&iAd6dB`M#%BU0)4M'%BK *'05%4%J!M'%IT'-mDaM'-(*'054)U""hiaM'(rr5BaKqNBaM'-BdKq4)dBaL!3J %)I*0DeMj5rfpq$a!!N!%pIIrGrprJIP"r4Ai6rrm#+-#L45)G'-Gdr`J%KJJF(p !$T!!!&Db%J%!%LSL+-54###!K'-B`K'+M+%BaK'-549Y4)4)!*aK'#4M-QXBaM! +69988+J4*#FjcK#%%Q-B8T'-CcM'0BNZ5G'FBrmB"%"b5!(iL8SPT3!!3!*!"*3 8!93"3!!K3#88)%rrr!LM!T-8L#49%&2m2i!)*)!iJ!#3!)!k63`!%'(2h#FiMR8 !"(4mlhi1Mh4r',S1LiML4L6q12a[R[HMic&V&hR`mE5+LrkS$L2DeVA[Hp*M(pl ZFjVAZFla*%E1E')!i!"`DC9V@)P+*D8!!%!#3!58&!&8!8!!)8!P&#"2rr`(E3+ qjdKcYZ!pr#"rq5!!!)!!m!!3!*!$%#!!N!8"!*!-!3#3"L!!N!9!)!!!3#!!N!4 !F!*`!*!$J!#3#B!%!!C!!*!*!IL*5L@P!!"!!N!%P"3"9!&!!#&!*43J6rrm!#! !!!3!N!3Krq!!#5!!N!SJ!*!'!J#3'!1!`!!!3#!!N!-$J!!%!*!$!3#3#3F!N!- "J!#3#!9V@)P+*qF!!%!#3!58(!(F!F!!)8!P&#"2rr`!N!3%!*!%3!#3!`M!!*" +!3!%!!N!$J!6!"J!'J!G!#!!*3!U!#`!-3!b!$B!1`!p!%)!4`"-!&%!9J"E!'! !C3"Q!'J!D`"`!(-!H!"p!))!K`#-!*%!PJ#E!+!!T3#S!+d!XJ#h!,`!`3$'!-X !d!$9!0S!h`$N!1N!lJ$c!2J!r3$r!3-""3%)!3i"%!%9!4S"(`%N!5N",3%b!6F "1!%l!8!"3J&(!8`"83&@!9X"B!&P!@N"EJ&c!AJ"I3'#!BF"LJ',!Bi"N`'6!CJ "R3'L!DF"V!'a!EB"Z`(!!F8"bJ(0!G!"dJ(A!G`"i3(Q!HX"m!(e!IS"r`)%!JN #$J)6!KJ#(3)L!LF#,!)a!M-#1!)p!N)#4`*,!Nm#9!*C!Pi#C!*U!QX#F!*e!RS #I`+%!S8#L3+0!T)#P`+E!U!#S`+S!Ud#XJ+f!VS#[3,$!XN#c!,5!YJ#f`,I!Z- #j`,Y![-#p`,p!j!$#3-2!a8$'`-I!b)$*3-T!bm$03-j!c`$3J0)!dX$6J08!eS $A`0P!fS$E`0e!hS$J!1&!iS$M`18!jN$R`1P!kX$X31f!lN$[!1r!m-$b!20!p% $eJ2A!p`$i!2N!qF$l3!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B !"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!D3!`)'!3B!"J!'!!B!"J)'!3B #"J!'!!B""J!'!JB""J!'!JB!"J!'!!B!"J!'!!B!"J!'!JB""J%'!!B""J!'!!B !"J!'!!B!"J!'!!B!"J!'!3B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B !"J!'!JB""J)'!3B!"J%'!!B!"J!'!!B!"J%'!!B!"J)'!!B!"J%'!!B!"J!'!!B !"J!'!!B""J!'!!B!"J!'!!B!"J)'!JB""J!'!*!$"J!'!!B!"J!'!!B!"J!'!!B !"J!'!3B""J%'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B #"J!'!!B!"J!'!3B""J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B !"J)'!!B!"J!'!!B!"J-'!!B!"J-'!!B!"J-'!JB#"J)'!!B!"J)'!!B!"J!'!!B !"J!'!JB$"J-'!JB!"J!'!!B$"J!'!!B!"J-'!!B!"J!'!!B!"J!'!!B!"J!'!!B !"J!'!!B!"J!'!!B!"J!'!!B""J%'!`B!"J!'!!B""J!'!JB!"J!'!!B""J!'rrm !!![HN!!!N!6r!!F!!2rp!!F!$`6P!!`!!`#3!d)!N$`i!*!-"S!!N!99UeBL8!( i$P%)%!)!#)T`"`"`!F%&!!#N!!S)%2i$rrJ!N!dJ!*"!"84!!*!%#P!!!!`!!!X !N!-JJ!!!!IiL8!&S#P%)%!)!#)T3"3"3!8%&!!#N!!S)%2i$rrJ!N!N$`!!!)!! !#Q!!!"!!$!#3(("`!*!3(!#3"!B!N!4%J!#3#"!!N!BJJ!"9UeBL8!&S#P%)%!) !#)T3"3"3!8%&!!#N!!S)%2i$rrJ!N!8i!"J!p#!!!#!!!!f3!!$915a5)!!#jFi AcIFi!!(!1mlhrZM`aK',[1mlmBaM(mJ5!)%!"!B)6!#3#5TVJ#)!L3%!J+Fli(X !JL!1L!dI%%L%f,h%!#++!!!"rL*3!@J+83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2 rq!li2J!!%FiJ!I`J!#!J!`!j)(hIeV*5U!!$(M%d%"M%##)J4M'-)4LJbKZ-BaM %NBaM%-J9!%%!"!J)6$!!N!5!!*!$+V4845K*!T4,@-B!T*4&%9')%+L3!*%*D-B N!#55!&@V9L*3!@J+83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2rq"&))J!ENM%J"I` J"%`J")!T6d698Y*KF3!&&#&8)"M%%"![4M'-)3LJdKA-BaM!NBaM%-3BJ!%!"!J )""!!N!5!!*!$+J4!!!!'!*!$#-B!S!#3!a'*%IL3!!!!$-BJ!!JJ!!!"rL*3!@J +83J3!J!)LP!&!&!"338!!+3!#JJ3rJ2rqh&!%!!N1M%3"I`r)T)N")!Trd5&-G3 KF3!&0#DA[#G'TmK3ap#-)3LJiK'XBaM!NBa9%833!"rR2Gcr6*pjhRfGdBeM(kS %)ZHplh1Fj*M'$U1Fk-BaLj!!5,RcSfV'*!!@5PT9UeBq8(p[qPm)%!)!#2TIrIr IrhrP2i#Rq!Tr%2i$rrb54mMm4%BaH"hm)#&5)%Xi)!p%MjL))Dr!#94"q'*)aX! %P[i`MldrS-)4R(dI1*'-5+*#%!!M'-BT'-dDaM'1BT'094&*"#-BaM'-Ba5BapA mBaM'-Bejra)dBjQpa2rTQU8!!IrMhiaXBr(rN!@,aM"JaJ`3(m"rr%IrL2q3"2b 53S8N4%IaMZ[m2rS`2l"m)!p%K498)5%2LC5"%'*)[#I)PXB`M#%BS1)4M'%BK*' -9%4#%!!M'%IT'-iDaM'-A*'054)U"#2iaM'(rr5IrKHNBaM'-Bd35")dBaL!#)" "+d,9UeBq8[p[IJm3!#)!#2Tqrr[IrhrJ2j3(r3Tr#2rrr!0a3SNN4%BaM@[m)#3 4)%Kq)!p%!"@bS3%!%48"%'*)K"!3&mB`M#%BU0)4M'%BK*'0BNK"%!!M'%B*'-d DaM'-!T'0543U"#-)aM'%)35BaK5NBaM'-Bd554)dBaMrm)"#Id+!!IiL8SPT3!! 3!#)!#)S#J!T3!8!!""3!43S)#2rrr!!43T%N4%BUMZ[m2b$a*,"pS!p%J&Da%J! 384B4&'*)LSJJN!"'-B`K'+M+%BaK'-549Z*)34!!*aM'+4M-QXBaM#+6998B+J4 R'FjcM'%8Q-B9T'-CcM'08NZ5G'FBJ"%!"!UP9DY@)P+*D8!!%!!L!!L+!S!+8!& !!!38!%8+#!Mrrr`!%8+M*-3k+SJVr#!(%-!!1'!!4)!k6T)!%'$RlK1F4c+!!)p (c[IJk2G(mBZJk,L1*'*2`*!!Ia[R2FMic&V&hR`FE5+LrkS$QZDeVA1Hj*M(lVZ FjVAZFla*%E1E')!1!!m+@J!"rL*5L@P!!"!!)J!)LJ+!#P!"3!!%&!"&#JJ)rrr m!"C#[XG#%GY`(IrJq"!!N!-J!(d!%!!-!"!J!*!'J!#3$%!!N!9`m!#3"4!)!!! 3#!#3""!F!3#3"#!!N!NJ!3!"%!#3#9@V9L*5L@P!!"!!)J!)LJ+!#P!"3!!%&!" &#JJ)rrrm!"!!!!3!%!!!%IJ!!"!!N!XJ!*!'!3#3$5!!N!X"%!J!!"!)!*!$!4! !!3#3"#!!N!NJ!!!"i!#3#J(q)P+*D8!!%!!L!!L+!S!+8!&!!!38!%8+#!Mrrr` !N!3%!$J!!"!!N!-3!*!Yi$!!N!MJ!!)!N!4!!*!)!F!!N!e9UeBL8SRj`!!3!#) !#)S$J!j`!F!!""3!43S)#2rrr!#3$4!!N%X"!!3!#3!1!"-!'3!D!"d!)!!P!#S !,!!a!$)!0`!m!$i!3`")!%d!8J"A!&`!B3"Q!'F!D3"Y!()!GJ"l!)%!KJ#,!*! !!*8!QJ#I!+3!U3#X!,%!YJ#l!-!!a3$+!-m!e!$C!0i!i`$S!1d!mJ$h!2`"N!- %!3N"$!%4!4J"'J%I!53"+3%Z!6-"0`%m!8%"3J&&!8S"6!&4!9B"@`&J!@8"DJ& [!A-"H!&p!B)"K`'-!C%"P!'9!CJ"R3'G!D)"T`'X!E%"YJ'l!F!"a3(+!Fm"e!( A!GS"h!(K!HB"k`(`!I8"qJ(r!J3##3)1!K-#'!)G!L)#*`)X!M%#0J)l!Md#3J* (!N`#83*@!PX#B!*P!QS#F!*f!RF#I!+"!SJ#M`+@!TF#Q`+I!U3#U3+Y!V)#Y3+ k!Vm#a!,)!X`#d!,A!Yi#iJ,T![!#p!,j![i$N!-+!a%$&J-G!b3$+`-b!cN$3!0 &!dN$6305!eN$B!0N!fJ$E`0f!hS$IJ1&!iX$N!!$P31D!jm$T31U!l%$YJ1l!m! $a32+!mm$e32E!q!$j32S!qX$l`2c!rJ$r33""!B%"`3-""!%&!3B""J%(`!(!!F !"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F !"`!(!!F!"`!(!!F!"`-(!JF""`%(!3F!"`-(!JF#"`%(!3F#"`%(!`F""`%(!JF ""`%(!3F""`%(!3F""`%(!`F#"`%(!3F#"`%(!!F""`%(!3F""`%(!3F""`%(!JF ""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!JF""`)(!3F!"`-(!3F ""`%(!3F""`)(!3F""`-(!3F""`)(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F ""`)(!`F#"`%(!!!""`%(!3F""`%(!3F""`%(!3F""`%(!JF#"`)(!3F""`%(!3F ""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F$"`%(!3F""`%(!3F""`%(!3F ""`%(!3F$"`%(!3F!"`!(!!F$"`!(!!F!"`!(!!F!"`)(!!F!"`!(!!F!"`-(!!F !"`-(!!F!"`-(!JF#"`)(!!F!"`)(!!F!"`!(!!F!"`!(!JF$"`-(!JF!"`!(!!F $"`!(!!F!"`-(!!F""`%(!3F""`%(!3F""`!(!3F""`%(!3F""`%(!3F""`%(!3F #"`)(!`F!"`%(!3F""`%(!`F""`!(!!F""`!"!!Irr`#3!d)!m!#A!*![!3!"!!N !!%Z*!!`!!%Z-!*!$&J!+@APEDeae9QKAEeKX8f*8DP9Z8L`!N!-@!!TC@9Y,A&9 @5&G[@%a63P4+98j5,!#3!d*J!!#B!*![!3!"!!N!!$J*!!`!!$J-!!!)`T!!!*! %l`!+!!$rpJ!+!!`$C`!+!!)!N!-d!*!a!i"0!*!G(i(!!*!'F"`(!(!!N$T83*C 5J!!"J!#3%J+J!*!%&S&!!*!%J!"3&!8!8!#3#383!-$!!!#!!*!A!FB!N!i$J!1 !!!!*#"C!N3'3!&*%"54!6!!i!!(Ki!#3#4D"6J#3!`d!!&!8"3"3!!&93!!!$c` !hlRp*58!!,PhaI0pcJ!"MK21jrZM$')1AHGjhiaJaMp#J))!3-)6'!#3!`3!N!- &65%GqA43P@Q"#UCYT#UD3URb3d32FK)ALd!qGU!!L$2rP[P4!!#J#3!!9j3&!&! !!TC!)N!I`rM99NP'%K!"4iL0"!Ba""*4%M'84'--SajM'-BNM'$')b0!3J""!J% )!*!$"!#3!`9@)5-CM%!!N!Y5j%(9MFc+h!43L!3N9)NTGXpJJ$3!%35!A2B&JGJ !!UU)8!qI``L2dP##(j!!!88*&HJ+-D[SCUS`M%3M$5+YBaM'")a9+88L!"ZCfjq h,fjZHhmaJaRe3(+K&BaGhGhCQC[fjQCQQCP09$[eM5d+U$j3QU4#r*5*4ZaJ[NL J%lL%cF2mr`YJ!*!$LM"I``L&1EP5%Rcb441N(`R2%!5UUp#2G2m1)NeMk2R%LT8 3L4)!"QCP*P0-QCQFK5T8U5JJFU(9M'D3"@95QC!&38j(pEA0#SJ)r+JIJ55N5AD [i-PC2k&&5Aer$F2FN!!!!$m'-2r$#)!8CL)9%!*&)(iBNL%,k5Vq-)a%BidL$1- )d#5+LLL4%J!HBRdQ8ibCQCKP+P4*48$ri41-CT!$Brrp8TQ3"3&81qq0,-J!2T! !bU4#r+5*&UJ46fSLS6P5"3(GIP6rr!!!LM"r``J!9+C5%"!%484&'*)L""!R4M' 84'1-SJcM#XSNL3T%N3S!*QCK*P0-QCQB&53SUB9!M'-6M'D3"#)K8TQ3"3$NKF@ +%K!!%4#)"#3NT5N@U!T)5Q*"3LN&!&8!9)!!!!K5,jr$#)!j'BNJ!3`jqi6R%Fb J!4"(cZI$Sh4q$&d(4F4a#N5I#MmIQGNH8bbCERMLj#NAp8#-AI&cRGhGfGQG8TC QCRGh!%p%"E(Ki!!"(h+rrbGEk4Di'ckaS%%$j)F!93"6i!#3!b(SRm2i!"!!!-! "!*!()!!1!*!*!3#3"3''!*!%"!)!!!J3!*!$!31!!!J!N!8)!*!+1!#3#J3!!"q !!*!%!3#3"&F!F!#3"5!IrJ#3"J)!N!G!!*!A'!`!!!J3!*!$"J#3!a!!N!83!*! 9"!#3#!)!N!4`!*!'!F!!N%J"!!3!#3!1!"B!(3!H!#%!*!!T!#i!-!!d!$8!13! q!%!!43"+!%m!9!"C!&i!B`"S!'N!D`"Z!(-!GJ"k!)%!KJ#,!*!!!*8!Q3#G!+) !T`#S!+d!XJ#f!,d!`J$(!-`!d3$@!0X!i!$P!1S!m3$f!2X!r`'3!`8""`%+!4! "%J%@!4S"(J%L!5B"+J%Z!6)"0!%h!6X"23&%!8J"6!&3!93"@!&F!9m"B`&S!@m "G!&i!A`"I`'!!B-"L!')!Bd"NJ'A!CX"S!'P!DS"VJ'b!EB"ZJ'q!F)"aJ(+!Fi "dJ(@!GJ"fJ(G!H!"j!(S!H`"m!(d!IJ"r!)!!J3##!),!Jm#&!)C!Ki#)`)S!Ld #03)p!N8#4`*+!Nm#9`*H!Q-#D!*X!R!#G3*k!Ri#J`+*!Si#N3+9!TS#S3+S!Ui #XJ+c!VF#[J,"!XB#b`,4!Y8#f3,I!Z8#k3,[![8#r!-!!`B$#J-1!a!$%J-A!ai $)`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-V!bX$+`-a!cF $2J#3$2q3"JB'rj!'!!$rN"`!"rq3"J-$!3-""3%(!!B!#3!)!3-!"!!%!3F!"J% %!!8"!`%'!!B""J!'!!B!"J!'!!B!"J!'!!B#"!%%!38!"J%&!3B!#!%(!!B!"J! '!!8!"3!'!!B"!`!'!!B!"3!)!!B!"J!'!!B!"J!'!!B!"J!'!!J!"J!'!!8""!% '!33!"!!'!!-!"3!&!!8!"3!&!!3!"3!&!!-!"!!&!!-!#!!&!!8!"3!&!!8!"3! %!!8!"J!)!!B!"J!&!!3!!J!%!!B!N!-'!3F!"J!&!!B!"J!'!!8!"3!&!!8!"3! &!!8!"3!&!!8!"3!$!!-!"!!%!!8!"3!&!!8!"3!&!!8!"3!&!!8!"!!&!!B!"J! '!!B!"J!'!!N!#3!*!33!"!!'!!N!"`%+!!B!"3!&!!B!"J!&!!B!"`-)!J8""3! &!!J"#3!'!3B"!`!&!!J""3!'!3F!#!!)!3J!"J!(!`F!"J!*!!J!"3!(!3F#"`% %!33!"J!)!!B!#Iq3+!!'!!B!"`#3"!XQN!!!N!6[!!m!!2rd!!m!$`5C!!`!!`! "!$i!N$Y`!6)!N!3'!*!@!93!N!8IJ1!!N!S1!$J!N!X&!*!k+)J#6**!!!!*!*! G&S#J!*!($RcJ#J!S!*!)m!!!"3!%!!!`!!!%!*!G"``!N"%(!!#)!*!$"#%!f3# ))"N'L33$4))"!*!,!93!N!8@r+!!N!3-!!!+4+!+!#J!!!P+J!!$!I[!!!A46Rj K55!!"-6[`Ajhlc`!!2!!MjlcrhSB--)1,hchchq'$!Bar38!3)!#!`36$!#3"!) !N!3+Q4"alq,d+"+9CJ%%8UEE%)T9L%8VX!ai!mi!!(4D!(jk!!!4!-rrPX5RJ!! %J!L!!!TFS!S!+!!!%Nb!"%B"r#r`"GIeNT&)`!!*,4#$3)!``J!"#H#)BBS3KKJ a3ai`````L)B-"M%-KS!JJ!)%"!%%!*!%!J#3"!UQ%#)BB``J!*!0!8N5K!94(Ki Qi!#JK93!#J!N84EdU%!!N!-4!#!+8+!+!#J!!"+9!%!-!I`S%!@#P*5JKr)!#KB 4"8%!8-)%%3S45'#'%))B-N+Y-----!L'$%94&)3!$[1HlRfh&XeRHIGh4M%BaqU !+&))8``ZFjcR1FjcT5XjcR1M'-9,N!#"k9%K)59!!+#-!)5I4")4&T5`,Z1NJ"% !)!T3TrS!+1i!N!-3T&rer#J3"Br-D%#%`J!5&"-*II"23dJ)&1P2S)B3JKJd3Nd `````#)8558S84!!4M'-8MP-R-jM'1)T'-4M%+S!S8JK6$$'-BaM'-BaP,-BaM'- Ba693HrP5A-bN3"%JP95)4%4a%ADAX$%84)!MXP!+8+3EJ1m4!*!$!44rrI`S%!@ &"K#JK5qI%K3JN3-)N!$#%q3P+LKJKpkIq$K#$,$p$mm)K4+SLL4%!!q-)a5-8dB M'-B`JNBUT8453%5+$dX-,h[Hpm)aM'8SaM'-BaM%"6L(q9&5d)!"qIbN!r!r4*! !N8D@-#m8b2`K6&#Edlpiri-4!*!$IJarqI`S%!@!"5d8K!)!)K4!B3-)N!#q)!* &+LKJKK#''$4#$,$"$3#)K++T4%3N!"'-)r5-8iBM'-B`FN9+SN5+J%5+#%X--Ba M'-2rrq8SaM'-BaM%"4#(p9$Fd)!!)L$&9)K%44%4GTIS8I93KN%!L5M5#8["lar ri!!#$%2jr#J3"B!&8`L%!J!L&)"rJ`N3JK!%42IiB)B3KK`b3Ja``3b!L)5K%84 %*!!4M#-%M&0')aM'-!T&4%9&#S$rrJK($$'-BaM#%)3P+-BaM'-Ba!83Hr23dXb !!%)JK!#%K%85%4D8#&%'8B9"-ST2mrP+IbN3!*!$%44'(r`S%!8!&C-85!!!358 )J8-*%)3,k!)%'''+%)BF-8)-F-%X8)L%34)NK"3!%BaM&)a6*L-BaM#+6)4)aJU !J`BB4``aM'-BaM'-C5M'-BaR1F`&83AK85%K!!(m)B98!!4&*&%@R!54&&'!J8d &)!!"5J!T%3#3"+4)!I`S%!@!$ScL5!!J`-Ih!6ca$cP%%%(%(jlcm(SEd2i-,d$ d,`Ki34)Nr"4rMr1Hj(a6&L-AHI"aY)4)[qU!J`A[`[22HplhZFjcT5LjcR1DeV3 $[S3"GKiH!!#%2RJ$rq4kcp%@J!c1kik!J3(mN!!!!8S!+1i!N!4$`!(m,r!&!!3 !!$!!)!#3#%!!N!i)!*!'"J`!N!8)!J#3!d!J!*!%"!F!N!0!!*!'%!#3#J%!H!# 3#!&8!!"!!!!@J!#3"3%!N!3"5J!S!*!'3!!(i!!&!*!'3!#3#)!!N"b)!J#3!d! J!*!%4!#3"#!!N!BJ!*!CJ!!!&S!!N!8"!*!%!FS!+!#3"34!!*!%"3#3,(!-!*! *1!#3"%!!N"`"9!#3"4q!!*!&!J#3"3i!1!#3"31!!*!%"3#343%!"!!,!"!!&`! I!#!!)`!Q!#`!-3!c!$J!13!q!%3!4J"-!&)!@3"I!'8!D`"a!(F!H!"k!(i!J`# (!)d!P3#F!+)!U!#Z!,-!Z!#q!-3!a3$,!0%!eJ$G!1-!k3$[!28!q`'3!`J"$J% 9!4i")`%S!5d",`%d!6B"13&"!8-"5!&0!9)"9`&F!@!"C3&U!@`"E`&d!AB"I`' %!BN"MJ'6!CJ"R3'K!DB"U`'d!EN"[J($!FB"a`(+!G!"d!(A!Gi"j!(T!Hm"p3( l!J!#"3)+!Jm#&!)C!Ki#)`)S!Ld#-J)d!MB#13)m!N%#4J*,!P!#93*D!Pm#C!* T!Qi#F3*e!RS#J!+'!S`#NJ+C!U%#U3+b!V3#Y`+p!XF#c`,@!YX#h`,M!ZJ#l`, d![S$!3-'!`N$$J-6!aX$*!-V!c!$-3-f!ci$330(!di$9!0C!ei$C30X!h%$H!0 r!iJ$M!16!jJ$R31I!k%$TJ1Y!l)$[`1r!lm$[`1r!lm$[`1r!lm$[`1r!lm$[`1 r!lm$[`1r!lm$[`1r!lm$a32,!p8!!2rr!*!)rj!'#!MrN!B!!2q3*!3%!3-""3% *!3F"#3!*!3-""3%&!3J""`%%!3F"!`%(!3J$#!%)!3J"#!%)!3J"#!%)!3J"!`% %!3B""`%'!3J"#J%*!3J"#!%)!3F""`%)!3J#"3!(!3J""`%*!3J"#!%)!3J"#!% )!!J"#!%*!3X""`%(!3F""!%(!33""!!)!33""`%(!3F""`%(!3B""`%(!38""J% (!38"#`%(!3F""`%(!3B""`%'!3F""`%,!3F""`%(!38"!`%&!3J!!!%*!3N"#!% (!3J"#!%)!3F""`%(!3F""`%(!3F""`%(!3F""`)&!38""3%&!3F""`%(!3F""`% (!3F""`%(!3F""3%'!3F"#!%)!3J"#!%*!3S"#J%,!33""3%)!3`!#!!,!3F""J% '!3F"#3%(!3J"#3)+!38!"J!'!3S"#`!(!3J#"!%(!3S""3%)!3N"#!%)!JS!#!% *!JN"#!--!3X""J%*!3F""`%%!33""`%*!3J"$rq3+!)*!JN!#VEE!*!$4!#3#3J !$!"k!%%!HJ!-!!J!N"-)!!`!IJ"r!(i!$!!)!*!,"`!*!*!$4!#3%J(!!8!"3!G `!L!"3!#!!*!5!F!"`!(!"r!$i!(!!)!!#3!)!*!$4!#3#K!!-!"H!))!AJ!`!"! !N"-3!$!!IJ$q!(i!-!!3!*!+#!!'!*!$4!#3&4!!+3!A!!N!#3!I!*!9%!!j!"m !$`!2!"m!#`!,!*!$4!#3&!J!P!$S!*!!!*!!!2J!N"8)!*`!q!$`!2!!q!!!#`! %!*!$42J!N!!!N!!!k!#8!!J!N"Ai!2!!m!$i!*`!#!#3&J3!"!#3!d3!N!32m!J 3#"!)%!J3#"!)%!J3#"!)%!r`!*!)$r!Iq"L3%Kri$r!!N!8(!!F!N!0%!3!#J!4 !$Z!#J!+!!i!!N")"!!1!"m!2i!1!!i!$J!#3%`B!"`#3!d3!(`!*!!N!&`!T!"! !N"8I!!m!$`!I!$N!%!#3&33!#`#3!b!!-!!3!8)"l3!%!*!)#d4eEQGPEfiJ6@& `+!S!N!-f0DP6G'PMD(4TEQFJ6@&dD'9YBA4TFf0S)%0PER4bG@dX)%&YFh4PFQ4 KE5`J-6Ni0G!a1C!$!*!$J!$rN!6`!*!$m!#3!rm!N!2`!*!$r2!!!2!!N!2rr`! !m!#3"!m!!2!!N!32!!$`!2rr!!m!!2!2!3(`$`!!m2!Im"m2!!$`mI%2N!-!!2# 3!amI$`!!m2%2rr!2!!$`$a#3!`m!!2!!rrr`$`!!m!#3"!m!!2q3"J#3")!!rj! %m!#3!r!!N!2r!*!$m!#3!rc`!!$`!*!$rrm!!2!!N!32!!$`!2rr!!m!!2!2%"$ `$`!!m2(a$j!$!!$`N!-I(`m!!2$a!3%2$`!!m!m3%2!2!!$`$`ram!m!!2!2%"$ `$`!!m!$rr`!2!!$`!*!%$`!!rj!'!*!%3$rJ)$!J+#!m)!3J"#2%*#3TP#T8+P3 Tj#3%)q3J"$rm2q!rm$ri2r`rr$rm2r`rr$rm2r`rr$rm2r`rr$rm2r`!N!0!2q! J-#!S)$`J"#2%*#3U9#T8+"3N*#@N*#3Ma#!%2r`ri$r`2rJrr$rm2r`rr$rm2r` rr$rm2r`rr$rm2r`rr!!!!3!2rr`!#!!'!!J1"3!*N35!#FL%3!MS4#!)H%I`#6p !%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J!F"!)!$J3#!!B%!J!!"!)!!!3#!! !%!J$`"!)"#!3#!Q3!"!)#P!3#!T3%!J*i"!)"!!3#!2J%!J!!"!)!!!3#!!!%!r rrr!2rr`!$rrq!!rrr`!2rrq!$rrr`!rrrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!r rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!!!!3!2rr`!#!!'!!J 1"3!*N35!#FL%3!MS4#!)H%I`#6p!%!VmJ"!+(J!3#KF!%!N6J"!)LF!3#($J%!J !F"!)!$J3#!!B%!L(`K!*@$83#@!0%!SXD*!!#Y+@N!!*8T83#%aN%!NJ#4!+d"D 3!!SAd*!!#5JT%!P)*4!)amB3#!!!%!rrrr!2rr`!$rrq!!rrr`!2rrq!$rrr`!r rrq!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r rrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!rrrr!2rrr`$rrrm!r rrr!2rrr`$rrrm!!!!J#3!rq3#3#3"r!!N!F2m!#3"[!!N!2rm!!!$mm!N!E`$r! 2%"m!!!r-m!#3"I!2[`$a!I!!$mc2!*!&m!$lm2!3(`!2c-c`!*!%m!!2[r%"$`! 2rj!$!*!%m!m!qrrr(`#3"!m!N!6`m2rr[`$`!*!%$`#3"2$a!3rlm!#3"3m!N!6 `m"!I$lm!N!82!*!%m!m"$`$lm!#3"!m!N!6`!2!3m!qr!*!%$`#3"2!!$rm!!2[ `!*!$$`#3"2!!N!82[`#3!`m!N!6`!*!'qr!!!!m!N!6`!*!'$r!!!!m!N!6`!*! +$`#3"2!!N!S2!*!%m!#3#Jm!N!6`!*!%rrm!N!32!*!%m!#3!`m"!I!!N!-2!*! %m!#3!r!Im"m!N!-2!*!%m!#3!r(a$`m!N!-2!*!%m!#3!r$`(am!N!-2!*!%m!# 3!r%2rr!!N!-2!*!%m!#3!`m3N!-!N!-2!*!%m!#3"2rrm!#3!`m!N!6`!*!+$`# 3"2!!N!S2!*!%m!#3#Jm!N!6rN!`!N!3#!*!$rj!*!*!(m!#3"`r`!*!'m!#3!rr `!!!2c`#3"[!2m!m3(`!!$mc`!*!&m!qr!2%"m!!2c-m!N!A`!2[`m"!I!!r-c2! !N!6`!!qrm3%2!!rrN!-!N!6`$`$lrrmI!*!%$`#3"2$`rrqr!2!!N!32!*!%m2% "$r[`!*!&$`#3"2$`%"m2[`#3"3m!N!6`$`%2!2[`!*!%$`#3"2!!m"$`$lm!N!3 2!*!%m!!2r`!!qr!!N!-2!*!%m!#3"3qr!*!$$`#3"2!!N!Elm!!!$`#3"2!!N!B 2m!!!$`#3"2!!m!!2rrm!!2!!$`#3"2!2(`r`%"$r$am!$`#3"2!2$r%"N!6r$`! 2!*!%m2!3m2m3(r$`%2!2!*!%m2(r$mcar-m2mI!2!*!%m!m2(mc`r-mI$`!2!*! %m!!2!Im"$r%2!!!2!*!%m!m!m"#3"2!2!!m!N!6`mIm2!C!$$`ram!m!N!6`m"! I(rrr(a!3m!m!N!6`$`(`m3%"m2%2!!m!N!6`$am!m"!3m!mI!!m!N!6`!2m!$rr r!!r`!!m!N!6`!*!+$`#3"2q3$!#3"3G"8&"-!*!'"e"548B!!3#3"!G%394"!!) !N!3(8d&@43!$!*!%"d*26N8!"!#3"$aZD$-a!*!$!8C548B!"!#3!i!!!3#"!!) !JJ!$!)-!"!#%5801)`!%!!!$k!!"!qN!!J2U!!-$k`!%!q`!N!-1!$i!6J#k!E) 6L3!%-!S!N!1&!)%!N!Mrrre2"%CTE'8+8Q9NFQ&h)%eKF!"5%3!-8(*PGQP[GA- J6A0R!&!4!!T5CA"[FfPdD@pZ!%i!!!%Y!*!%"e*PCh9XBA)!'mJ!$89ZG'9b)%9 iF'a[FQ8!!&J!!5d!N!3%8f&fC3"68`!",3#3"!44G@Pd!&&4!*!&5!##!*!)rj! $q`4&C'Pd"&9ZC'm!@J!!!5d!N!3$3h9d!&J!!!4$Eh"j!%-!!!93BA0dC3"@!!! &3faPBA)!N!LX!)-!N!Mrrrhr!dYLC!a$EfjdFQpX)%YPHA-!'mN!#e"eEQ0dG@& dD@pZ!"[+!!K#FQ&MDf9dF`!Eb`!&B5!Y)'d!'m`!"@iJ,5"k!"[0!!9")#dJ63! EcJ!&6L!Y)&S!'mm!"6!J,5!j!"[3!!%Y!*!%##KPFf0KF'8T!*!%"bKcF'&MC5N !N!3)+'4PE'9dC5N!N!3)+(*PG(9bELN!N!Kc!)3!N!MrN!2E"%KPE(!(6h"dD@p ZF`!!6`!",3#3"!4)C@a`!!!r!!a%CA0MFQPLC5",CAN!!#B!!5d!N!3(9Q9bFfP [EJ!!GJ!(5'PcG'pbH3!!9J!39Q9bFfP[EL"'C@&dGA*PF`!!)`#3"5S!J!#3#2q 3!rX"&!j"BQpeG#"1CA4)B@0Vb3#3"!%Y!*!)aJ#&!*!)rrrpl`4*EQC[$8PZGQ9 ZG'pbH5""E'`!!'N!%%PZGQ9ZG'pbH5"6C@aPBh3!!%N!"N&NDR9cG!!!)`!",3# 3"!P-EfpV)%4[Gfi!!$S!$%4PFf0bD@*P)%pZC3!!1`!04'9cBh*TBQ8J6@&ZH3! !,`!04'9cBh*TBQ8J9(*KF!!!AJ!",3#3"!a$B@aX)%e[ER0dCA)!!%-!#djKE@8 J6f*UC@0d!!!M!!Y%DA0MEhCPFQPPF`!!A!#3"EN!L!#3#2rrqpm&6@&RD@-*4(* [F#"*G'9Y!!"N!!Y%FQp`)&0PE'9MG!!!4!!'8'PMDh9`!!!X!!e8EfGRE'8JF'P MDh9`!!"!!!%Y!*!%!d9KG!!!C3!%8Q9KC!!!FJ!&8A9KCQB!!(%!!d4TF!!!)`! ",3#3"!Y-DA0d)&0`C@aXF`!!+`!+3f&cG#"6F'9XE!!!@J!$@Q&`!!"k!!C*ERC [Df8!!#-!!e*eBJ!!)`#3"EF!L3#3#2rrZlm%3QPdF`C6C@&bBfJ!!(-!#N0XEh0 P)%4[Eh)!!'-!#8p`C@iJ4'p[FJ!!E`!&3A"`E(N!!'%!"%YTBfX!4"%!!5d!N!3 '9@jdFQ&`!!!M!!9'Eh*MC3!!)`!%6'p[G!!!)`!",3#3"!G&EQGbBACP!!"&!!0 %DA!!!#-!!e0TG!!!)`!",3!!)`))3faTEA!J9A!!!$`!#N0XD@eL)%4[Gfi!!$i !N!@,!-S!N!MrN!3,F(9ZBh4eBA4TEfi#)#i!N!3#)#`!N!3#)$X!N!3#)$S!N!3 #)#%!N!3#)$m!N!3#)#X!N!3#)#d!N!3#)$d!N!3#)#-!N!3#)#3!N!3#)%!!N!3 #)#B!N!3#)#S!N!3#)(i!N!3#)&m!N!Ki!-X!N!MrN!3)BR*KBfYPG(-"@`#3"!& G!*!%!5J!N!3"+3#3"!&l!*!%!Ad!N!3"2!#3"!%q!*!%!9i!N!3"B!#3"!%R!*! %!5)!N!3"A!#3"!%[!*!%!A`!N!3"*3#3#'-!c!#3#2q3"!9K)#dJE3&K!*!%!@) !N!3"B`#3"!&N!*!%!@8!N!3"CJ#3"!&R!*!%!@J!N!3"D3#3"!&U!*!%!@X!N!3 "E!#3"!&Y!*!)B`$0!*!)rj!%"@iJ,5"k!@i!N!3"E`#3"!&`!*!%!A%!N!3"FJ# 3"!&c!*!%!A3!N!3"G3#3"!&f!*!%!AF!N!3"H!#3"!&j!*!%!AS!N!KM!-i!N!M rN!3&35!Y)%d"33#3"!&#!*!%!8-!N!3"4!#3"!&&!*!%!8B!N!3"4`#3"!&)!*! %!8N!N!3"5J#3"!&,!*!%!8`!N!3"63#3#'-!c`#3#2q3"!91)#dJ@J&1!*!%!8m !N!3"8!#3"!&4!*!%!9)!N!3"8`#3"!&8!*!%!98!N!3"9J#3"!&A!*!%!9J!N!3 "@3#3"!&D!*!)DJ$*!*!)rrrpr`aMEfjdFQpX)'YPHA-"BJ!a!!!"DJ!b!!!"EJ! c!!!"D!!d!!!"E!!f!!!"H3!h!!!"D`!i!!!"G3!j!!!",3#3"!&N!%3!!!&`!&! !!!&b!&)!!!&d!&3!N!C4!0!!N!MrN!3&-#!Y)$N"-!#3"!%a!*!%!6)!N!3"-`# 3"!%d!*!%!68!N!3"0J#3"!%h!*!%!6J!N!3"13#3#*%!b!#3#2q3"!ChDATKFQ3 +3A4dFQPLGA4PF`!!H!!04'9dC@0d)&9ZFf9PEJ!!C3!*4Qa[Eh)J6@&`!!"Q!"" (C@jPFQ&dC5"0EfjcG'9b!!"R!!K*C'9ZG'PQH3!!D3!*6'pMBA4TEfjc!!"[!!j -CACPE#"8C@aPF'pbG!!!GJ!%9fPcD!!!G`#3"9m!d3#3#2q3"!GMGA*bC@jd"PG PBA"[EJ!!+3!&3A*YEh)!!&X!"9*TEQGc!!!p!!C"EA9XCA3!!#)!"94[Efac!!! S!!4(EfaN!!!N!!C6F'9XE(-!!#X!N!8X!)!!#J#!!*!$J3#3!i)!N!1$!*!$K!# 3!i8!N!1'!*!$K`#3!iJ!N!1*!*!&,!$)!!S!b!#3!mN!N!2+!*!$b`#3!m`!N!2 0!*!$cJ#3!mm!N!23!*!$d3#3"C!!!!d4T6)`-5"$EfjdFQpX)%YPHA-3T6)`-L" 3G@jMG(9KG'P[EJfP-M!c)%*bB@0VCA4c#U8b-$3JB5!Y)'d+T6)`05"Z)#dJHJU P-M!f)%%J,5"0#U8b-$FJ6L!Y)&S+T6)`1#!`)#dJ13+P,3JET@9cBf&`C3FJTA0 `B@0P#!LPC'9XCA4P#!fPFQ9dGA*Z!*!$C3!0"`+PBh4X,@)(#U9MG'`YDJF1T@0 dE#eZ"`LPBh4X,@J($+9MG'`YE!FCT@0dE#ej"`ZPBh4X,@X(&D9MG'`YG3+P,3F %T@0dE#eN"a#PBh4X,A!(%U9MG'`YFJF8T@0dE#ed!*!$)J!3!5i",!%l!6S")3% r!5X",3%p!5-"*!&!!5B"+J&q!9m!N!-L!"!"@`&G!5J"+3&l!Ad"2!%q!9i"B!% R!5)"A!%[!A`"*3#3!a`!$3&K!@)"B`&N!@8"CJ&R!@J"D3&U!@X"E!&Y!*!$(!! 0!@i"E`&`!A%"FJ&c!A3"G3&f!AF"H!&j!AS!N!-F!!d"33&#!8-"4!&&!8B"4`& )!8N"5J&,!8`"63#3!a`!$3&1!8m"8!&4!9)"8`&8!98"9J&A!9J"@3&D!*!$&J! +!6!"-3%b!6-"0!%e!6B"0`%i!6N!N!0#!!J('+9MG'`YH!F&T@0dE#eP"`DPBh4 X,@B("k9MG'`YC`F*T@0dE#eT"`qPBh4X,@m(&U9MG'`YGJFAT@0dE#eh!*!$%!! (!5N"@`%p!5)"+!%N!5X!N!0,#c&cG#"YC@je)%P%4&G54!SM)'pQ)%e&6P9c6d0 19!8UN!9-8e4$"P*PFb"*4%4A8N3)8Q9cCA*fC@4'9e*%"5U3"8a69%8!N!-E!!J "6`+P,3%r!5B#T5d"GJ&@##0fCA*cD@pZ!*!$*J!-!@N"53FMB@4UGA0d!U8Y!6S "1`%[!9i#T5d"3`8MEQ&YC3&F!*!$0!!#!*!&C`%%!(X"9!3#6dX!N!8,!&%!@!& JL!4H-&ia!*!&#J!B!#S!1+!#!!%!N!0%!!-!N!9G!3i!F3&+"!*1E`#3"9d!A3" a!*N%!ePPF`#3"JS!6`"3!91)!Pi`!*!&#J!@!#S!0U!#!*!&$J"%!%3!XJ(9!)" %4$!+!*!$$J"+!'S!d`(A%iJ!"$!+!*!$3!!3!A-"B`&[!@%("+9MG'`YC!+P,3F MG@jdFQ&`"L0QEh*MC38ME'p[G!+P,3&&"#0NDA!%)h0TG!+P,3%m!6i!N!-8%dj PG%KKBfXJ8(*PCQ9bC@jMCA-!N!06!!m",J+P,3J8T5"MG'`YG!8MDR9YF!JME@p ZFh4PFJ8MGfP`C3+P,3&K!A!("+9MG'`YC!8MBfKKG!BMEfCQCA)&)h"bBAN&)h* TC'8&)h4eFQi!N!1F!)F!N!MrN!0l!d&MG!4AB@Pd!!!Z!!%Y!*!%#&4PE'9`Eh* d!&34!!4+G@e`!!!M!!G0EfjcG'9b!!!M!!4ADA"P!!!M!!%Y!*!%"8&`F'aj!!" K!!03BAN!!(!!"%YTBfX!4"%!"%0SBA3!!#-!"8pQCQ9b!!!M!!43FQ&j!!!M!!4 5D@4P!!!M!!48GA*Z!!!M!*!&,J!2!@3"4!%X!8!#T5d"C3&b!A%%)f4TF!+P,3% V!9S"HJFMD@jfEfYP"#0bG@)!N!0#!"%-T6)`15"$GA*bC@jd!U8Y!AF"H!&4!@B "G!&K##0PEQKKEQ0P#L0dGfphC@&`Efi#T5d"9`&8!8%#T5d"8!&5!*!$m3#'!*! )rrphq`9&FA9TF!G$GA*bC@jd!"[4!!%Y!*!%$>C@aN)&GPBA"[EJ!!G`!24AK MD'&ZCf8J9f9KF'pZ!!"i!!e6C@aPBh3J8A9TGQ9b!!"4!!Y'DA*P)&&eDACPFJ! !CJ!&9'KbEhF!!(3!"8&`F'aj!!"K!!G&EQKKEQ0P!!!M!"&8GfmJ9f9KF'pZ)%0 [E@*KG!!!)`!",3#3"!TAC@&b)%&bE@pb!!"A!!K8B@YP)%pQCJ!!9!!+3A0V)&* PE@pfC3!!33!",3#3"!C3GA3J6fi!!&!!"P*PE@pfC3!!8J#3"6!!N!F%!!$GN!B !!3#3"`)!N!F$!*!("2q3"J#3!bS!3J!Z!1)"XJ!&!3#3"aG`%P0PE'9MG#"K)%0 SBA*KBh4PFMB`#J#3!e3!N#!J!!"!!*!Srj!'!*!%!5i!%!#3"5J"%J!m!@)%"&" XBAN!N!91!4)!BJ&L"!44G@Pd!*!&*!%1!%!"CS!!N!C3!%J!B3"k!*!(8!#k!'% !lJ#3"hJ!5!#*!(S!N!Gi!,`!L3$Z!*!(H!%q!)N"B3#3"bN!5J!j!2!3"%jKE@8 !N!8B!"3!1!!dS!)!!3#3"9!!*!"J!%L)"9*[E'8k!*!'8!#@!'!!ZSJ&8Q&MC6T P!*!&H!!8!)J!5)J(4f9ZC'9b1J#3"RJ!PJ#)!,b)"N&XD@GZ1J#3"AJ"%J#)!6k )"8e[C'8kD!#3"4-!5!!N!2+)$&GSEb"KFQ8JH@pe2`#3$!%%!!%AF!#3!c!!N!F %!!$GN!B!!3#3"`)!N!F$!*!("2q3"J#3!c!!N!F%!!$GN!B!!3#3"`)!N!F$!*! ("2q3"J#3!c!!N!F%!!$GN!B!!3#3"`)!N!F$!*!("2q3"J#3!c!!N!F%!!$GN!B !!3#3"`)!N!F$!*!("2q3"J!!#-i!!3#3!a`!N!01!*!%rrm!N"#!)!#3"8!!3!# 3#8J!N!0)!*!&"!!"!!3!N!B)6J#3"#)c-L+3"5-L%4)L)MYiXL+3"K)M-bY$1l- LN!-c-L+3"5-L)K)5[(h$)T!')5)M-b9$)eXb)L)c)T!*)eHA8b+3#50$1d-bZd) L)L3b)T!$-L)M0,CpRFXL)b)L)b+3"M1l3c)PBb)L)l-cZfc'E(ICU[fb)e-M-b+ 3#E4$-b1mXd0,HCQCUT!$rkUBa6-L*M-c)T!()b1d3c-b*'amb0aP9EZlE'9EY&D c-L46-c)K)c)5)lY8+l4$-M-b*FCXZd-L)K&,4%ZdYV-c-eXc-L)MZj!$3V3VY$1 3"E-L@d-b)L'lN!0%4E3c4,8c)LYPXb+3!bXl4$0%-dZl-c1l-c-L)9ZlY%3cY%4 %1l-MCM)LN!3N*83d0%5l3c-b46-c)L*8Zl4%3lY%4$0EA&-b)T!&*84$0%5d-c) L*6-c-L0EZl4%3cY%5c*FDc-LN!BQZd0$Y%3c-L)V3c-L+l5lZdXc+d4%-V@d-L+ 3"%)L0E4%-c4$-c)L)d3c)L@dZd4%3cY$0$)f4$)LN!3b)PY$-c3cN!3L)N-b)LC ,Zd4%-b3d4$)QY$)LN!4#)V4$-c3l-j!$)L)c-L+eZlZd4$-MY8-b*N-b)T!%3b+ l4$0$-j!$0$)L)M)LDlZlY%3c+eDd-MBc-b+3"$3LY%-c0$13"$)L)M-PDlZd4%- c1eCPXN8c-b+3!a%V)N3cN!BM)T!$-caEZl4$-c0,9E99Zc-b)T!$%4Xb0$13!c) M-b)L)5)b9EZ3!c-L1l9EZl[--b+3""%E3c3c-c)L)c)LN!3c@lZ3!d-M5e9EZl4 ADc)LN!-4%e-l-b-b)M)b)T!$)$C9@lZlXcZe@lZlY,aQY$)L)K%5`c3b-c)L-M) LN!-Vc&@lZl3c4E9EZlY$YV[&Y#)K%4,,*$-M-L-LN!3V8la9ZlZc0&YEZj!$-f@ e9QGfZlYSfc4$)M)LN!3VC6-m9EZdY,@lN!5d3f@lZeA-amc-M$3c)T!&1maE3c9 VZlY9DlZ3!l4$1f@l4,Z3"$0V4$)L)L-L)XaV4$-cbe9QCEZ3!d4%-c9EXc-d4$1 3!eZlN!1e9V9F@l-c-b*P9P@lN!0%3d-c0VY$-j!&0'Xc-l0&E-c'3c-c)L+m9PZ lZl4$0$-c0VY%-j!&ZlXb-cAF@lY%3c-b)L%X99Y%4%-cN!3fY$13"#)NY$1c)he EZl4%3b-L)c*'9E3cN!3b)c1fXc13"#)VXc06@0@l4*!$-L)L098d@l-b)T!%)c+ l3c13!c)L+d-bE0GEZlY%-c-L)VZlXeZc)T!'-VXd4$-c-L)NXc*&@lY%4$-c)L+ l-c0#Zl3LN!BbZd-cN!-b)L08-d5d4%-c-b-L+d-L)M0&Y$)cN!-L-c0E3c13!c) L)QZl-l-c3c-b)L*$-L)L-c5l3c-c-L)M-fXc-c4%-L%Pbc)N8c1d-b)L1l-b)L) c-l4$-cZdY%4EZj!$99Xb*'@c)M1c0&@c)L-l-c-b)MZlN!1d3c-b)VY%Zl-cYEY Q4$)L-N)VaV-K%83L)c-b0%4%3c)dY$-L@d53!c5l9V)N3b)c0$5e-L%5Xc13!c) VZl5d-dY$-L+l-c0%-c5l-L+d-c-N4,Zd-L)b)c0%-LZlY%-cN!-M)VXcN!BL)MY $-c1lZc3c5c)M-c-b+d3c-c)L-b)L5c-M-j!%)L)MYEZ3!c-L-cXb)c0$-L4%0$) L)b+3!cXb)c-c-L)M)T!$)c13!c)L*E-cN!-b*%Xc-L-c)T!$06-M-j!$)L)b)L) c-b-c3b*#1c13!c)N5d-cN!-LN!-Q3b-cN!-LN!8M-L)L-c3L)d-c-c)MZd-cN!- b)L)QXc-d-c-L-c)L)M)b)L)M3L)L)d3c-b1l-j!&)L)PY$13!d-LN!NM-L+3!c@ c-cZd-j!&-M)PY$13"#+3"6-b)T!&-b)lY8)eZd3cN!3L)LZc-j!%)T!+)b-c)L- d99@l4,-c3c-L)LYL-j!%)T!$-L+3"M-M-c)L-c)L-j!$3d-c)L)MBc-L)M-LN!J l@d-cN!-L-L+3!b-lY$-c)L)MDc)cY@Xb)T!'+eZl@c0$3c-LN!-c-N1d-c1c)L+ mZl9EY$)L)M)LN!-VZl3c0#-c3c0%-b)N-N4$-c5l3dI'@d4%-c-L)L-L)MZlY$) LN!8M-L1c-d4$-b)L1l@d1c-c0%-b-c-b)VZ3!c-LN!BVZl)b-c-b)T!$5l-N3c- dZd1lZl4$@lZl-b)L-j!&YN)L)c)LN!3M-L+dYEZlY9Zl4,9EY%Y$)L-c-b)L)cX b)T!*)f@d-d4,3c13!l0$0%)L)c-LN!-b)l)LN!-K)T!&Zd-b)M-c-M3c4%-c0E) L)L-LN!-K%V)LN!F4*&3c)K)K)L)l4$1c-d8b)T!%)5)L)E3LN!BK%5Bd-L+3"6Z l3d-d9$)LN!FK+c)LN!-M)L%4YM-LN!3K)NZl3dZl3c)LN!-M)L)5)4-b%4)L)b) K%FXLN!84)N5lY,Zc-b)K%M)LN!853b%4)M)L)5Yc)T!(-d3lZlXc)L)!N!F1!!$ ZN!B!!Gf3"J!#c*!'!!1lN!B!"+U3"J!&L*!'!!ChN!B!"e@3"J!)4*!'!!NLN!B !#K'3"J!,QC!'!!aQN!B!$613"J!2!*!*3J$`!*N!N#m"!!%!#3!!6)N!$!!!6)` !!!Q)N!!!N!6q!!B!!2rh!!B!#`1l!!N!!J#3!cm!N!H!!*!("!#3%#!!N"!"!!E !!*!'SJJ!N!3"5J!!!B!!!0!!!"$#!#YDa%S!ri2P%))"!"*AKm(Jq)8!"8!&##2 `2r`!IJ#3!acJ#!#3"5!!!!jJ!!!3!*!&J!#3"`i!N"!J!*!3!i!#K%!3`#!)&!8 3!#!34!!!!`!##4#EB!!!%83!&!r%5J#ZqU83JJ%!%P@pIlqSK3!&3!8))r!rr!0 #!*!$#4!8!,R!!!3J!`!*N!!!e6RX6#!!!6PcKIGpcJ!"a(HGlrh4iB`M&hRHGq- BaMr3d"!J!)$"#BB!N!33!*!$"8ehb+8*)&+&DZGm$e+)SLR4"+2L%L%Y&f)!%NN !+eV%5J$Glf83JJ%!%PEZkh[BK3!&3!8))r!rr!6!$i!0R4F3!8IJ%KSJ")!*)2( IeV+5U3!"4ia0#!Ba"")ZM'-B3M&"P$HBaM'*)aLU)C!!D!JJ!)%"!))!N!33!*! $"9D2`!!!`!!!!4M!&!#3!`)a*"85!!!"QC!!!"93!"32a%S!VYDP%))"!"*9hAH eU)8!"8!&##2`2r`)`!5!!QXBL!p(rj%U*!bi18#4K9,8)A%!!Nd)9Hm'-D[S2ia K'%)43D3V@-BaJ5-BNL+)3!2mjlZIkC2V1mqcrM'XBr9!JTch[HjcR*-B`G4cR4M '-AFr&cjdE9Q5!!UV!#YDamS2hHpPm))"!"2@lZYlhq9q"Ai&IL2`2rhC3I)r)L[ iZh,(i(c))(0m+Ik9MlP))Dr2`P84T"L*d4!%9IqK(hTr3F3M12SqF5-BN85)3!4 M'-8M'D0FaM(-%M'USLNJJU-BaM'-BT2rqVk-BaM'-D`*iND-FcGNIr$,6*32r([ aVYDr(rq3!rjGhAHeU"q"rmRrLIq3!riT3+&&)LXBaV,(rj%S2iKm3!k9K4@e)5% !"'8JIKL5,`[SPBaK'%)a8D3M'-)a#5-DN!#)K%!%B`Mp)aRM@-BaJj)aU5*&3)1 r'-B`rrk6'-2dM'-BaM'N2b*'M'-3#%!K$j*V@XI+Aph[B2%!#3!6eZlVHprJIP" r4Ai6rrm#+-#L45)G'-Gdaq!5'#"`Id!1P3"@XK)"!!4&4%8BNL%%%!k-BaK#-9' 8)aM#-BNLVDL3!)4!"1-)`5-CNeM'-B"5DUULK8#*)6R1F)3JNaM#P)aM1FBaV%P b6ScM(rM!)J159!r%5P'ZeU!"!!N!%PAGGl@S!!K3#88)%rrr!LM!T-8L#49%&-I rJ!JNJ$L!!*'!1Nd-!"!S1IZ%ja(1S!#+Mjh[`G(ZMq-A3G&a(%M%Rm,(ihch[4m CLeLlciH0T&4Ip8"a(YDeVh[HNaMqph1FeVh1GiNL0R0M%!F!!i0-UeV%5P(Glf! "!!N!%PEZkh[B!!K3#88)%rrr!GY!VlR5(1fi$dIJIrNJ!!#!!2%!%!#3!a!)!*! ')!!+!*!+)!#3"3)!N!8#!3!!!J%!N!3#!i!6J!!!"!#3#33!)!!b!*!*&!r%5P( rrm!"!!N!%P2rN!2i!!K3#88)%rrr!!J!!!%!N!3)Iq!!#5!!N!SJ%!#3"N!!'`# 3%!%!N!8F"J!!!J%!N!3F!3!J!*!$#!#3#6J!N!--!*!*!9V%5P%!N!-"!!N!%P! !N!8)8!P&#"2rr`#3"!%!N!33!*!$#-!!N%S"!!3!#3!1!"-!'!!D!"d!)!!P!#S !,!!b!$-!13!q!%!!43"+!%m!9!"C!&i!B`"S!'N!D`"Z!(-!GJ"l!)!!K3#+!)m !P!#C!*i!S`#S!+X!X!#e!,S![`$%!-N!cJ$6!0J!h3$L!1F!l!$a!2B!q`%!!3) "#!%+!3d"%`%9!4S"(`%N!5N",J%b!6F"2!%p!8!"43&(!8`"83&@!9X"B!&P!@S "EJ&c!AJ"I3'#!BF"M!'2!C!!!C-"Q!'B!Cd"SJ'R!D`"X3'f!EX"`!(&!FS"c`( 5!G8"e`(F!H%"jJ(V!I!"p3(k!Im#"!)*!Ji#%`)B!Kd#)J)R!L`#-3)f!MJ#23* #!NF#6!*3!P3#@3*H!Q-#D3*[!R!#G3*k!Rm#K!+*!SS#MJ+5!TF#R!+J!U8#U3+ Z!V-#Z!+m!X!#``,*!Xm#dJ,B!Yi#i3,P!ZN#l3,b![F#q`-!!`8$#`-4!aF$(3- K!b3$*`-V!c%$0`-l!ci$4!0+!dd$8!0@!e`$B30R!f`$F30h!h`$JJ1(!i`$N31 @!jX$S31Q!kX$X31f!lN$[!1r!m-$b!20!p%$eJ2A!p`$i!2N!qF$l3!'!!B!"J! '!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J! '!!B!"J!'!!D3!`)'!3B!"J!'!!B!"J)'!3B#"J!'!!B""J!'!JB!"J!'!JB!"J! '!!B!"J!'!!B!"J!'!JB""J%'!!B""J!'!!B!"J!'!!B!"J!'!!B!"J!'!3B!"J! '!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!JB!"J)'!3B!"J%'!!B!"J! '!!B!"J%'!!B!"J)'!!B!"J%'!!B!"J!'!!B!"J!'!!B""J!'!!B!"J!'!!B!"J) '!JB""J!'!*!$"J!'!!B!"J!'!!B!"J!'!!B!"J!'!3B""J%'!!B!"J!'!!B!"J! '!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B#"J!'!!B!"J!'!3B""J!'!!B!"J! '!!B$"J!'!!B!"J!'!!B$"J!'!!B!"J!'!!B!"J%'!!B!"J!'!!B!"J-'!!B!"J- '!!B!"J-'!JB""J%'!!B!"J%'!!B!"J!'!!B!"J!'!JB$"J-'!JB!"J!'!!B$"J! '!!B!"J-'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B!"J!'!!B""J% '!`B!"J!'!!B""J!'!JB!"J!'!!B""J!'rrm!!![mN!!!N!6r!!F!!2rp!!F!$`6 d!!`!!`#3!d-!N$0!!*!)!F!!N!`d!*!&!UUeBL8!Ir!r+)3)!3!%46i2`2JIL#J !"5!!8%#(m"rr`!#3#!Fi!!!%!*!'!`#3"b!!N!K!!*!2!3#3%N!!N!JU)J#3"9+ !!!"J!!"B!!!""!!"8"rL*3"A[l8SK!J"!!4&+[VrVr@)+!!&)!"33)I`(rr!!*! )#2`!!!3!!!&-!!!$!"!!$!#3!b!!N!MJ!*!2$`1!!*!3i!#3"$!!N!-#*!#3#B! !N!8""!!#UV9L*3"V@ZXSK!J"!!4&0leVhAU)+!!&)!"33)I`(rr!!*!%!F!!`!M m!!!%!!!"XJ!!!p8j,&)J!!"1A1&mhh1!!"a(HGlrh4iB`M&hRHGq-BaMq)#3!!3 )!#!`3Q!!N!J"8e`"%!4)#!3&1Gm$f!34!(4!D2L#4#E&lL!"&&!"8"rL*3"A[A8 SK!J"!!4&+eVeVV@)+!!&)!"33)I`(rr!Gm(`!!#1F3!)r!!%"!"J"b32J!2IeV* 5U!!!8H-633'-3))Lk-BaK#-8'80aM'-BNM'-BKL!U!))!#"!3Q'!!*!$"!#3!`& 9SU)T3NJ8SPV'-!8NSLL+M%#&4)5)5dBa)!%NN!!#UV9L*3"V@ZXSK!J"!!4&0le VhAU)+!!&)!"33)I`(rr!LN%3!0b4L3!Sr!#*K!#3!!8Tk)!$e9,5BA%!!*&#&8) "M%%"!rM'-B3K&"T#ZBaM'")aM')B3-3!#!!J3%!JJ!#3!`3!N!-"8#)!N!-`!*! $4M!&!*!%M%L2a)!!!'Ba!!""!!&3(q)P!&HpG5L%#!%!"%8V@[@ZYBJS!!8J!&" !Kr!IrpZ+!)!")G')J#Mrj&*%J*!!"6rSJ!1&-G3KF3!!Nd*THm*dDRb&@2S4K#% 8(%)eM'-B%M'+SLK!J!$r1HlRqQ6lc[2XlSaV'2e3)4FplhZFjb6'-(8FjdBaM&b #4FqG'eBa)!#b8Y+UY@2P"qYDkbq%#!%!"(dh[@[GH[mTr!8r`&2iKr!Irq552NI L)M',`1Mm"#T%#@F%!HL!!iqBL#'[`!%94"q'*)aX!%PIaK(hTr3B3M12SqF5-BN 85##!!4M'-8M'D0BaM(-8M'USLNJK'-BaM'-BT-BqVq-BaM'-DmriND-FcHiRrdc 9+9!IrMhieleeq2q3"FAV@[@ZYB$q!rrL2ra(rj!%j*)8+5)L2iah@2rr4JIf$i3 "k)!$K498)5%2i4P)%3BNLm*mL9M'%B3M&"a#-B`M%*)aLSL)))!"'-)r5-C`eM' -BZ5-DNL48#%IaM'-2rqNrr#p)aM'-BaSJN#4SaM%!%3##9S@UV9Mj5rV@ZX(L!! 4!!4p0leVhAVr!IbJ2qK6q%Irrq!ELK4*)L)aM'YBr!5#*!N2a!(SJ!-!&E+K!3! #%9!4"L5)33%!5-B4K#-9'N)aM#-3NM'X53J3J!%B`M")aQM@-BaJ&)aU5+&3)4K '-B`K##6'-+8M'-BaM'L55*'M'-IrK!)6qK93(q)P+0HpG3!)!"%!"%8V@[@ZYB! !)+!#+&"!4rrri!#+&)NL)M&8GeMrj"iNPJqd!HL!!i"@X4)!%")4B4&'*)LSJJM SaM'%)a8C3M'-)aL5+Ya*#"#!!6M'-8M'C0BaM'%8QUUS`9!M1-jcR'-)T-B`V5- BcR'-DT*FNk-ia!#)!#"9+UUeBL8SkeVV!!J!%3!%46HpDpekJ!!JS!)S8%"(rrr J!)S9'5BKd94"@2`!iKJ!"``!#)!$J$T1NJ!3&!jqi6R%FbJ!#+Mjh[`G(ZMq-A3 G&a(%M%Ri#)2ihcRZ4mCLeLlci10T&4Ip8"cA0DeVR2FNaMpeh1FeVh1GiNL0R0M %!(!!H&,48"rL*5MA[A8!#!!4!!4&+eVeVV@!!##J!LK33%Irrq!!XKAf1K#1fi$ Sr"m#!*!$"!!2J!-!%!!-!"!%!*!'#!!!S!#3#3J!N!81#i!!N!@!3!!!J%!!N!5 !i!J!N!-"!*!*!3!)!!L!!*!)!UUeBL8SkeVV!!J!%3!%46HpDpekJ!!JS!)S8%" (rrrJ!)!!!#!!J!!!L2`!!J#3"`-!N!8J#!#3"K!!!+!!N!N%!*!'"!#3"3L!3!! !J%!!N!-)J%!)!*!$!3#3#3%!N!-2!*!*!9!IiL8Srrrq!!J!%3!%44rrN!5!!## J!LK33%Irrq!!N!3J!F!!!)rm!!)!N!F$!*!'#!#3#!'`!*!3"!#3"3F"J!#3"`F !3"!!N!-#!*!*$J#3$JUeBL8SJ!#3!`J!%3!%43#3"b#J!LK33%Irrq!!N!`#!*! (!`#343%!"!!*!!i!%`!C!"S!(3!J!#8!+J!X!$-!0!!l!%!!3J"(!%`!83"@!&X !B!"P!'S!D`"Y!(%!GJ"k!(m!K!#*!)i!N`#B!*d!SJ#R!+`!V`#d!,N![J$$!-J !c3$5!0F!h!$K!1B!k`$`!28!qJ$r!33""`%1!4%"&J%G!4m"*!%T!5i"-`%i!6` "33&'!8F"5J&2!9%"9J&E!@!"C3&U!@m"G!&i!Ad"JJ'(!B`"N3'@!CN"QJ'G!D) "SJ'R!D`"X3'f!EX"`!(&!FS"c`(8!GN"h!(I!H%"jJ(V!I!"p3(k!Im#"!)*!Ji #%`)B!Kd#)J)R!L`#-3)f!MX#3!*#!NF#6!*4!PB#@`*J!Q8#DJ*[!R8#H`*m!S% #KJ+-!T-#QJ+E!Tm#S`+S!Ud#X3+h!V`#`J,)!Xd#d3,9!YN#i!,R!ZX#mJ,j![d $!J-(!``$%J-B!ad$)`-T!c!$0`-q!d8$5J01!e)$9`0H!f8$D30Y!h3$H`0r!i- $LJ13!!19!jS$R`1N!kS$V`1f!lX$`!2&!mS$c`28!pN$hJ2M!qJ$k`2Z!r)$pJ2 l"!!%N!-*"!S%$`36""F%'`3E"#)!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`! (!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F!"`!(!!F$"`)(!3F""`% (!!F$"`)(!JF""`%(!JF!"`-(!!F""`)(!3F""`%(!3F""`%(!3F""`-(!JF""`% (!JF""`%(!3F""`%(!3F""`%(!3F""`)(!3F""`%(!3F""`%(!3F""`%(!3F""`% (!3F""`%(!3F""`)(!!F#"`%(!!F$"`%(!3F""`%(!3F#"`%(!3F$"`%(!3F#"`% (!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F#"`-(!JF""`!!!3F""`%(!3F""`% (!3F""`%(!3F""`)(!JF#"`%(!3F""`%(!3F""`%(!3F""`%(!3F""`%(!3F""`% (!3F""`%(!`F""`%(!3F""`%(!3F""`%(!3F""`%(!`F""`%(!!F!"`!(!`F!"`! (!!F!"`!(!!F""`!(!!F!"`!(!!F$"`!(!!F$"`!(!!F$"`)(!3F""`!(!!F""`! (!!F!"`!(!!F!"`)(!`F$"`)(!!F!"`!(!`F!"`!(!!F$"`!(!3F""`%(!3F""`% (!3F!"`%(!3F""`%(!3F""`%(!3F""`%(!JF#"`-(!!F""`%(!3F""`-(!3F!"`! (!3F!!3!(rrm!!"%Q!!%!N!-F!*!$6J#3"2rr!*!3J%!!N!9!!%!!N!P)!*!$5!# 3"3J!!3!)!*!'%%i!N!3%N!-&"*!,"C!%!J%#!33&"33%"3F4%JS&N!`#!J@3!`F ("!N("3H3"!8&"*!%"`8&"*!,"C!$"*!$!3)""3F,%483"`@3$3)#"38(N!-%#3F &"3F*"`8&"*!%"353%`8&#a%A%3X("C!)"!@3"!3&!3)&"!3'N!-*"`F&"3F*"`8 &"*!%"`53"`8%N!8&"j!$#a%@&a)2#33&N!B%"38%"33&"33%"33&"!3'"!H3"!8 &"!X,"`8&"!3&"`F&N!-(#JX4$!X,$4%5%KFB'4N5#J3%"`N("C!'"!8%N!J&"*! H3!`@3!`B($3N&"`8("a%A&K3B&"L3"4Q3""J8%K%*"`8%"!8,"`@3"!53#`8 &"!F%"!N(N!-&N!3%"`X0%!d4%4-3#j!%#T!%#a!,N!-+"`F,#`F("33%"JN("C! %"!%%"!8%!33%"3F(#3F%"j!&"33&N!-%"!X0$!X,"JF("353"!%""j!*#`H3!`3 '"!N("C!&"!3(#3N("`N("`3("`3*"j!&"!8&"`D3"33%#`F("C!&"!%(N!N*"j! (#`F&N!3,N!-("33&N!-%"38("!N(N!B&"`F'#3N'"*!$"j!$"C!%"!3"#3H3#!B *"j!'#3F&"!8,#`F&N!B%N!-&"`3*"j!*"T!$"353!`F*"`F&"33&"!3*"j!3"3X (#a!,"`8%"353"J@3!`3,"j!$"JH3#!8%N!3*"j!$"C!$"!3,"j!*"!H3"J8,%!X ("`8&"*!-#`H3#J8&"!3&"!3(N!-&N!-%"!F*"j!*"!H3"J3'#`F("C!$"*!("`5 3!`B,"j!+"C!$"*!%"j!%"C!$"!X(N!S%"`B(N!3%"JX("`8&"*!)"C!%#`N(N!S &N!3%N!3(N!-&N!-%#`H3#33%"`B(N!3%"!X(N!-&"*!)"`8%"!H3#`@3"!F%N!3 '"C!&"`X(N!N%"!B'#3F("J3%#`F("C!$"*!("`8&"!H3#33(N!-&"3F&"353"!@ 3!`30#3H3#!8%"!B,#`F("*!$#`F&N!3%N!F("`3%"j!%"3H3"38("`@3"353"!8 &"!X,"j!*"T!%#3d0#3B%"JX&N!8%N!8"!33("38(N!3&"`F&N!8("33&N!-%N!3 &"3B0#3H3"`B%"T!$"`Q3"!X*#3F&N!8%N!8"!33*"38(N!-&N!i%"!%%"!8%#3X (N!F'"!3'#!B,#3N(N!33$3F&N!-%"33&"!3"N!-("`8(N!-&N!3%"C!&"*!$"35 3"3F'#`F*"`N(N!3'"!D3!`X,#3H3"!B*%!X("C!$"*!%!C!%"`X&"!F("C!%"!3 &N!F%N!8!"JX*N!3(N!B%"`B,#`N(N!F0#`X*"`8%N!8"N!-%$38&"`F&N!X%N!3 &"!3'$3d,#C!$"j!&"JB*"JX*#3H3"JN,#3N0#3N("*!$!C!%""!("!F("C!+"*! %"38(#`B($3X*"j!&"T!$#`B*#3F*"j!&"!X,"`N*#`d4%!X(N!-+#a)@"`8("`@ 3"33&N!-%N!3&"`X,"`8($3N*"j!$"T!$"`X*#3H3#3B0#3H3"!N,$C!$%!f3""% 0"!F("C!$"!8%"C!%"!F($3d*"j!$"3X,#3N("`N*#`X*N!-(N!S,#3H3$JX*"`F &N!-%"33%"33&N!-4$3X(N!3&N!-0"`N*#`d,#`F*"j!+"JN,"j!+"38%"!8,#3H 3"3Q3"!X*#3X1#3H3"3@3!`3,N!--#`N*"`N(N!S&"!X*"j!'"3F&N!8("`X*"C! $"`F&"`X,$C!%#`H3"3@3!`3%"`d,$!N*"j!0"3B,"j!("C!'"`F*"j!$"C!%#a% 0#`N(N!J&"353"3d,#`N(N!J&N!F'$3H3!`8("`8("C!&"j!$"3F("38(%"8,"j! )"C!%"!3("!3'#`X*#3F("38("C!'"!@3!`F,"j!$"C!$"`F&N!3%"j!$"38,"3X 5%`X(N!J&N!8%"!N,#`B'#`H3!`8&"!8%"C!%"*!$"38(#3H3"!8(N!-&"33&"!F ("C!$#`d9%3X(N!N&N!-%N!-(#3H3"!X(N!-&"!8%N!J&N!-*"j!'"38("38%N!- (N!-&"3F,#3H3#3@3!`53!`H3!`8%"!F%#3N,"`53"J8&"*!$"38%#3H3!`@3"`5 3"!8*"`F&"`B*"j!("C!%"*!$"`F&"33&"3F("JN("`8&"!3("C!$"*!$"38%#`H 3!`@3"`53"3X("`B%"JN'"j!%"C!("!F'"38%N!3'"!B'#3F("38("C!%"*!&"JX (N!-&"3H3"!8%N!3,$3F'"!3'#`B%"j!%"38%N!-'N!3&"33&"!3("!3'"JH3$3X (N!F*#`N'"J3%"`X,"JB%N!-'#3B%"``*"`8%N!3'"`F&N!F(N!3*#3H3"`8("C! $#3H3#JQ3!`X,"T!$"*!$"J3'!`3($3d("*!$!3%'"`@3#!3(N!F&N!-(N!-&N!3 ,"j!,#`X*"!3("`53!`F%"!B%"`N*"`53!`%%#3@3"!H3!`8%"!H3"`8&"j!%"C! %#3H3$38%"33(N!-%"`3%"JB(N!-'N!-%N!-&N!3(N!3&"!3(N!F&N!N%"JF("C! $"j!%"C!&"!3&"3N("JF&"!3(N!3'N!8("C!&"j!$"33%"JH3"3@3#J3'"`@3"!F ("C!("*!$"33(#3F*N!-("`B%N!-'"!B("`@3"!H3!`8&"!B(N!8&N!S%"JN&N!i %N!J&N!-("3F("*!%#`F&N!B("38%"JH3"3@3#`3,"`@3$J53"3@3"33&"`F%N!- '"!F("C!)"!B(N!3&N!`%#`F&N!3(N!-&N!3%N!-&"*!&"C!+"`3&N!-("`8("C! $"*!$"j!%"3F&"3F("C!&"!3,"`@3"!H3"!@3"J53!`8%"C!'"!8%"3F%"!@3!`3 (N!3&"`3%"JN(N!-&N!3("`@3"33%#`N("C!$"j!%"C!&"*!("33&"*!*"38%N!- (#`F'N!3*#3H3!`8%"j!$"3F&N!3%"!N*"`8("C!)"*!&"33&N!3%N!3&"!3&N!N ("`N'"!B,"j!)"C!&"*!%#3N'"3F&N!F%N!B&N!8%N!J&N!S("`N*#`X(#3H3"38 ("C!&"*!$"`X%"C!&"!8&"*!'"C!%"*!+"C!&"`@3#!3%"J3%"JB(N!8&N!B%"!d %N!J&N!-%N!3&"353#!F*#`N("`@3!`F&N!J%N!F(N!B&N!8%"!X'"*!%"`X,#38 &"*!&"353"`F*"j!$#3F&"3H3!`@3#!3%"38%"JB(N!3&"j!$"353!`F0"`F,N!- (N!-&N!3%"C!&"*!H3"38("`8&"j!*"38%"!F%"!H3"J3(N!3%"a!0#`X(N!B &"`53"!8%"C!$"*!$"`F*"`F&N!N%"!8%"!F&"!8("C!$"j!&"C!$"!3("`N*"`B '"`3'"j!&"JB%N!-&N!3%"!H3"J@3"!3%"38%"38%"!8&"`F*"`@3#33&"!8%"!H 3!`B%"JB%"JH3!`N*"JB,#3N(N!8,"j!'"C!$"!@3#`F,"`@3$J3&"3F%N!-*"JF ,"j!%#3X,"`N*"j!$#`X(N!B&N!i(N!3&N"%%N!-'#j!$"`8(N!B&"`F&"3H3!`B (N!-'"J@3$!3("!8&"`@3#!%&N!-%"C!%"!3'N!-%"C!$"!3'"J8&"!H3"`B("33 *"J@3#J)&"!3#!J8("C!+"!@3"!)#"!B*"JB&N!-""!3""!8&"!H3#!8&"`X&N!X ""38#"3)#"`F&N!-%N!B&N!3"!3)&#`B("`@3"!53"!@3!`H3#!8(#3F&N!S%"C! $!T!%"3F&N!-""*!&"`8%"3)#!3F,"C!*!38#"38(N!J*#3F&N!8%"!8&"!8&"*! $!38&!J%("`8"N!-%"!@3"J)"!JX("C!+!J%&"3H3"`N(N!-&N!3""!3&"353"`8 %!J%%"`8#!C!$"!3&"33%"3%&#K%&N!`#"C!$"j!$"!F*"j!%"C!%"!#3"aN!!2q 3"*QC!!(rN!4QCJ!#rj!%-c-!!rrrc-bCQ3!%rrr-c'CQ!!Arrmc--c-!"[rrQCP QCJ!(rrqCQ6-c!!MrrfD3"!!*rrpQCM-c!!V-c*QC-c-!#mc-CQBc-`!-c-aQCJ# 3!`h-c$13"!!1c-`c-`#3!`qCQ@CQ-c-!%*QC-j!%!"'CQ6-c!*!$%QCQ-c-!N!- 6CQB!N!88-c-!N!89GhF!N!8@998!N!8A4%3!N!8B)L)!N!8C%4%!N!B)[J!"!*! $(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8%!!%!"!#3"JK1!*!%E-C Xc-c'Gfc-c'c'TRT'c-E-aQE-c+CR%A4(DQc-E-aQUNGQChHU4Xc'c-c'aUE-N!2 'E-c-5RUUGUCk4QCXE(DNCXCN&X4-c*!$aNChT-E'c-aXE-4QGk&(4NC-afTXT+T RDNT-a(E-N!4UV'DQc-CXc-aQaRTkGNCfGdCQc'GQCdG+UNG'aXc'aQI-ChCQc*! %C+Ch4NCf&QCdCXaUc%DQ4'4'4QGXc-aQI'aRc'aQCRTRC(4RDKCfUQ4QCmaQ4+H U&NCR4(CQc+GQaRE'c'TdCU5K4dGRCdGQG'TfE-c'UNTf5RC'5QE'GkGXCmE-CU6 -HRTf4(S@G%HQ4kCQc-aXC"URCRCk3@c'HQc-CXb3"'G'4RB@C%CQC'Td4-b3"'H UCRGQGQChaQCQC'a%CRDNCfS@Gk4N4NCf4XCXc*!%TR4'GNGXCmaXCfc'CQE+CdG RCdGhGRGfC'6-aXb3!m6'ThCk4UahChc*aRafaN&kG(SATf4R4fD3"-b3"-I-akG fGfGhc%GNCkCmCXCfTNCNC'GKC'CUC-b3"XCmGj!$CQCR6%V+4'I'4NGfCkCfS@G UGT!$E-b3"'c'I+CQGk4dG%4d5RCQDXCfCQChGRCdGQHNCQc-N!4Xc(c"GhDQ4RB @C'4'GdTfCQI+TRbKCd4kaQE-E-b3!dE"c'E'CRGU&RHNC%CRTdaR5Q4fGQG%CQC %E-E-CXc'CRc'N!2%GfGR4hGfGQ4NI'bKa%HKCaC%C'c-c-E-I-CXaXaXChGdHKH RC'GNC(E'E-a(B@C%CXGhc-c'GhE(Cmb3"AGf4Q4NChThCf4fGQV-ChT'4'aNE-c %GhCfE-I-c-E-a'CRTRDRC'5NE%G-b'CQGhGRHQV'c-CRN!0%E-E-N!0XaQChGK5 NUNG(CfG#I(V'4R4mE-CXI'Gda%V-I-b3!f6(CRCdTkDUGN4k&R4'&TGXGm&Uc-E (FDaQUXb3"FI(4'Tm3@4f4RB@C%CU"T4QDNHXE-aQ5Nc+'XD3!mb3!fCXaXI%DQD NTRHNC'GX&mUKG(E'E%akUQ'NE-b3"@ahCdV%CfahCQCdE'I(N!#N5N4Qc'c'c%' K&Qc-c'E-c-E'4%GNG(CNCRGhc(Cf&KP+T'CXE-c'a"&Qc-c'CXc-E'CNT(4NGR4 h4RCQCXI'G"CdI-c'E'E-a-b3!fE-N!6(4RC%aRDQT(GhTQE(DQ&"c'b3!mc-aXc -E-CQE-c-E'I-ChGU`AHRGQ4fTU4'4%5Qc-E-CXCXE-aXE'4'c-c'C%SDG(&fGNC +5UU3!k&+4d&XCXE-CXE-N!4UTmaXE'5N%8Tk38T+UU4"SDT+GfCNTQc-CQE-E-a XCU'UGQc'C%T%C'T+HQTUUX4'4Xb3!fc*TXE'E(c'CQCf%4UNGXCRHUT%G+3@4dG 'aQI-N!2'aQbTE'c%c-E-E'CN%D&faXGd5QT"a%UU5USAE-c'aQE-N!1@E'I-c'a XaXE"URE(E'G+UNTU5NUUUNI-CXCQaXaQE&PQGmaQCQGQCmG"GQCRT+5USD&+S8U Ua'c-c(aXE-c-aaT+DUCQI(GQE('XE-ad4(&"4%T%T%4NaXc'aQCXN!3CN4UQ4mE -aXCN4QbNG%TdE-E(5NUK5@aQaQaQCXc-aKT8NCSDE(aXN!9mBDT'aXaK4*!%GQC NE'D3!fc-SA%4N!-Fc*!$aXCXCXCfV-E'bNT+DQTXE-aXN!6-CUT"4"%4('CXE'D 3!fGUa%V+CQUUT+T'Gmc'N!6-CQ`4&"4%%4GQCmI+bNUUCRUQc-c%UNC+4(4Qc'C RCfE-aNT+4+UK&dGQN!0N&(TfBD(-E'aUT''THRaQE'GXafc'&+CU%4&"5RCfG(T %F8TaS4UU&QURDNUKTQaQafCXc'`D4Q3D4+4hGXaRCkC(G%SD&"5R5RT"3DUNTQb 3"-CQUUUKUUUKCh('N!0RCQDRHN53!a4%3D&"T"&-E'E-akC"UUSDT%4fGfaRCfT +&dT+4%5N4'UNS8UK34C'E-c'TK5NDUTQYQE'CRC'T+UK3A&"UT!$5U'K5U38UQC %CQC(UU%AUN4kUQE-c'C%UR4h4(4%G%6%5N&"UUSDUUG+CN4(4(5N58CkI'aXTa& "S@&kHNSDS8UKT*!$C'UN5RCa5RCRTkC+GNGQ4XCm`DT"4+5N4%TdT%T+DUTmCU' 3!a%4aQ4QaQI'Gfamc-c'TQGUHT!$UNUUT+HUSDc%UN4d5NV-SDUKV'D3"-c-C%4 U4NUUUNUU&-E(ah4mc+GXbUUUaUSD3@E'UXamc'a+5Q4KG%T+UNT(E'c(C+c'N!5 T%@GUT%CQCQQQCQCf38&%4NDUTU&"GXc'aQ3@c'c'CN5U%CURDUC'Ci&XC%U3!d5 NTUDU'U&%GfE(a+E-aQC+DK3@4QS@E-aX4'aQT%TRTNTh4mC"3Ac(E-aXUXc-bRT d4%UNG-6'CN&Qc'HUUNT'5N4fc-DNTXE-E-bUV-c-CQa+3Dc-5XaXa+4QDUU3!dC K5Rc-CK%AaXCQCUSAaQCXaQT%4Xc'aXb3"'UUDN&kHUTmE-bR4XaXc'GfCQc-N!4 Qc-c'c*!&aNTkGRGUG"E-CNCXN!0QUUT"GXE'c-bRE-aXI-c-CXc'F84aGd5UNfa Q4Qc'DT!$GQT%c*!&CXE+aXCQCXaQG'4fI-4Q4'5UI-4Q5UUU3A&a4QE'c!#3"`` !!*Q3"J!"CT!'!!*QCM-cCQB!!c-cCT!%!!3c-fCQ-c-!"613"'CQ!!BcN!B!"`! !998!N!-)UT!'!!PhN!B!#P@3"J!,4*!'!!`LN!B!!"%@!!%!N!-F!*!$6J#3"2r r!*!3J%!!N!9!!%!!N!P)!*!$5!#3"3J!!3!)!*!'%%i!N!36"a)*"`S5%`J#!`) 4%K86#3B(!`)$!K)4!`F5!`)4!`B#!K!#!`8#N!3"!T!$"J-3!`8'N!-#!K!$!K% $"K)(%a-)%JB#!K!4%JN)%JJ("`B'!K!#%`)#%3F#%3-'%JF5%JF'!K%3!a!$%3- #N!84!J-(!J-4"K%(%JB(%`S6%J+3!`-4!`B(%4%6%4)4!`B(%a-'!J-'"J)(%3B (!`-'%JJ9#48(%j!$"K)5%"!("JN6"K%'"a-(#3B*N!-#!`)#%J-3!J)(!`)(!J) $!T!$%K)(!`B'"`-4!J-#!a%#!J-#%3F$%a3(N!-*"a)("K)("a-("a13!a)+"a% $"a%#"J)#%3B5!`)'!K!#!3)'%JF'!`8'"`B#!a!'"a!#!K-8&3F$!JB#!K%$!K! $%JJ(%K)#"J-*"a)#!K%(%4!'%JB'%K-(%K-6"J-$%JB6#3N)%K%%%JJ$"JF6N!- (%a3*#3B$%a-(%JB#"JB$!J-#%`F'!a%(%3-4!`)3!J)(!J)$"JF(%JF$"JF'#K- 0#JJ5"`-4%a)4!K)*#K-'%K-*#3F(&!F6"`B3!JB#"a)4#4)3!J-5#!B(!JB$%T! $!`B6"JF'"K-#"a%'%T!$"`-5"`-4"`F4!`S6%J-#%3J6#K%$"J)$"J)$"`d6#4) #"a-$!`B4!K%(%3B$%4)(%a%("JF'"`J(%K)(N!-'"`-'%3)'"`N'"`F6"JF4%`J ("a%#N!-'%`B'%K-5"`F*$480%`S6"`d("J-4%4-6#!)'"`F*&!N5"J-'"K)(!K% #"JF5%JF$"K)6"`-4"`F5%3)'!`B*%`F$"a-6#3B5"`-5!`F5"a30&4-(N!-+%J) 4"a)$"J)#"`B(!J-$%!-("K)("J-4%3-'%J)("T!$!J)'%4%(!`-5#K-*"`)(%J) 4!K!#!K%$!J-#%JB*!`)$"J-#"`-'"K!#!K!$"3-5%4-(%3-(%JH3!`)$%K)("`B '!JF(#3N@"a%#!J%5!J-'%J+3!`-'"a'3!`-'!`)4!K%5%`B(%JF5N!-("K)(%JF 5!J-'%3)4"K)5%`F5!`B'#"-0#4)+%a%'!`B(!`)4%3)3%a)6#JB5!`F'"`B5"JJ 5"`N6N!-'"`F5"a)(#4-*"a)(%3)$!`)$!J-$!K%#!JF6"a)("J)$!JB$%3-#"JF $%`F'"a)(%JF5"JS'!a%("K-)"`F$!K%#"K)$%JF#!`)$%3)'%j!$!JB#!K!#!a- 4!a%#%3)4!J-#%3F'%JF'"`B'#")(%J+3!a-#%3F(%j!$%3B4!a)$%JF#%3B#%3) 4%3B6#K-'!K)5%`B#!`B$"`F'!K%#!`B5"`N'"JF5&3d8"a-5!`)3%K)(!`B'%JF (!T!%!`B(%`B5!`)$%JF5%3F(%`F(#3N(!`)5%K-5%J)5%JB$"J)("J-#"a-("JN $%JF5"`B8#")'!J)(!a)5%!)5"JF5!`+3!`B'%J-#!`F6%`)3!J)$!K%5"`N+#3B '"`F$"J)5"JF4!a)$!JB#!`F'!a%(%JF6"`N*%JB$!K)("JB6!K)'!`B(N!-5%a- 5!`)3!J-5!4!#!K%5!`-'#JB5"a%(%JF'%3B#%4-("K)'"3-'N!-5!J-#!`B("a) $%K-("JF'!K)6%K-5%JF'"`B4!`F5%3B(%K38"a%5"`B$!J-4!`-'!JF'"`B$!J- ("JF'!T!%%!)3"`-'%3)(%`F5!`B#%a-("a-)"`B#!a%$%K)'"`B$%JF(!`S6%J- #%3)$#3F'!`)$!`B(%4)4!J-2!K%$"J-#!`)3!`)$%JB$"J)'%JJ("JF'%3-4"a- (%JF(%J)'"a+3!a-'!JB#!JB$"`8'%3F5%K-(!`B("J)#"K)(%`F5"K)5"`B#"JJ 6%`B'"a%#!a)6""%4"T!$%JF5"a%)#4-(%a-(!a)#%3-6#3N6"`B(%3F("JB("J- 5#3F)#3F'%JF+#4-(#3S6"`-("`B6%JN+"J8$"j!%%a-5!`B("a-9#3F'!T!$%4- (%a)(%JJ'"K%$%4))"K-("K-5"`B(!`B'"`-6#3N'!JB'!a))"a-'!a+3!a36%JF #!`F5%`N(%J)'!`B'%JS6"a)#!J-#!JB(%JF6%3F(!`F$!K%$%3F(%JF5%`J(!a% $%3F("JB(!a%(!a%$%3N6%K-'"`B'!J-$%3)'"a36"a)$%3)'"K-+%`F5"`-'!a% 3!JB#"JB5%JF5"a)5%4%#!K%5"a%$!3+3!`F(%`F$!J)$%JF$"JF5"`-'!`B#!a! ("JF5#JN8%`F5%a)'"a%#!K)(%JH3!`B'!J-'!J-#"K-(%J)(%3)5N!-'%J)3!J) '%JF'"JF*"a)&"a%5"a%6"`-'N!-)#3F'"`B#"J-#%JN8%a-(%JB$!J-3!T!$!a% $"J-5%`F5#K)(%J-#"J)5"`B#!K)6"JB#%J-(#3F5"`)5!`F'"`)3!a)$"`B#%JJ 6"`)$!`B'!`B'!`F'%3F("JF(%JB#!j!$%J-'%J-5%J-#%4-(!`)#%!-'%`)'"a) 5"K%'!`)3!K%4%JF'"a)4!`)'"JF$!J)4"a-'N!-5%JF'"J+3!a%&"J)#"3-4"`B #"JF(%K%'!JB("JF5"K)$"JH3!a)5&"3,"a%$!3)$"a%4!T!$%3B'"a)("`J("JF 5!`B#!`B'!J-'%K-(%a)'"a-5%J-#%3-9%JF$"JN(!JF'%`N,%a)("JF6"`B("K% #!`)$%!-'"a-5%`D3!`-'%4%$!a)6"a)6"`F6"a-("a)(&!F'!JB6"`B$!JB$!K) '"J-4!J)'"`B5!J-'%JF("K%'%`F*"a)(&3J4!J-("J)$"4%(!J-6"`B5!`F5%J- '"J)4!JN)"`)4!K)("J-#!J-(%4%(%J-'!J%4"a)6%JF(%JF6#4-'#!F#!K%("J) $!JB(!`B(!`-("JB5!T!$%3-3!K)(%4-)%a)5!J%#!a)(%3F6N!-(!`)(%a)(!J- 5%`S*#JB("`B3%!)4!`F'%4%("K)(%K-5%J-(!K%4!J-#"K-(!a-#"`-("`B#%4% '!`B'"a%$!K!#"K%$"T!$!`)3!a!(#!B'!J-)%K)'!`F'"`J(%a-(%`F4!`%$"JF 5%`F#%"%#!`)"%3)#%`J("a)(#a-$!J)3!K)(%JF'"a%("J)4%J)'"`D3!`F5!JB '#"-'%K-(%JB#%4%("a)'"a)#"J)#%"!$"J)3!`B##3N+%`F#%")6%JJ5"`N(%JB (%JF9#K-6#!B("a)("K)6"`N'"`S6%JF'!JF(%K-(#!B#"J)$%JF6%3F5&K8("JB 5N!-$"JF4!`F9#!N'!`)$"JJ8%JS6"`B$!J-$"a%$%3B$"a)6%JF$!a-5%JF'%J) $%JB$%K)@&3X6%`F4"K3+%`-#!JF'"JF5"`B("J)4%4-6!`B'!`-#%4%'"J)$%`F (%JB'!J)$%3F'!`F$"J)$%J)(#3S+#3)(%3F5!`)'N!-4"JB"!J)'%a))!`)$"a8 +%JF6"`B#%3F5"a)'%JB5"JF("K)5"a)'!`)4!J-6$"-*%T!$%`B6"J-4N!-+%J3 #N!-$%K-("`B("3)3%4-("K)5"`D3!`F5"a)("a-("a-("J-#"K!#N!-5"K-0#") ("a-)%JF#%3-8"`F5"a%5%`B'%JF5#3N(%J-3"`F5"`B$!K!#!K%$%JB(%3-#%a) )%JF'"a)(%JB'!a%6"JF'"J-(%3B$!`)'!J)3"`-'!`)##!F4!`-#%3-#!JB'#") '!T!$!a!#N!-$%JB6#4)(%a)(&!F5!a%$"a-(#!F$!J)5%JB%!K)(%J)3!J-#N!- 3%J-3!a%#%!-#%!-4%`B#!K!'%J)#%!-4"`-(%JF$"K%$"J-#!J-#"K)4!`8$!K% '"`F5%")5"`B$"a-5%K!5"`-#N!-5%`S5!`8(&3S("J-'"a)$%K%("K%4"`)$"J- #!J-#%"!#"JN("`N5!K%(%K)#!`B(!`B#"K-6!`F("T!%%JF6%K)#"JJ0#3B$"a- )%J8$"K)*#JF)"K)'"a%#"K!#%3F*$3F5#3B#"K-(#3F*%`F'%3)$%JF#"a-5%JF #"a)9&3F#!3F6%JF$%4!#!J-#"J)("a-'%JF)%`)#%JF(%K)(%J)$"J)#"JF5"a) '"`)$!JB$%a-(%K-#!a%(&4-,%`F'"JS6"J)#%!F'%K)#!K))&43'"`D3!`)$%K- 5"JB)!`)4!J)3"JB5!`B$"J)4%3-4"3-#%3B$%K%("JJ6%JB'!`F5"a-6%J-#!a% ("JN(&!N6"a)("J)'%3F5!`)4!K!(!`B4!`F$"`F*%JF'"a%5"a-6#!B(!J)(%`N (%3)#!`8$!a!#N!34"a%$"K)("J)"%!)#!`-#"a)$!J-#!`B3!K%#"a)(%K)#"`B (%`F6%JF'!JF5%JJ*N!-'"J)(%3)'%4%$%!-4%JJ5!T!$%3)$!`B#%3+3!a3*%`F 3%3F4!a-(%K-5"a)$"J-#!`)5!JF'!a-8"JF5%J-#!J-'"J-("JF(%K-("JF'!K) 5%`N5"a)4"a+3!a3(!J%#"a%'"a-6%JS5"a)4"a)'"J-#!`B'!K-)%3B("`B("K% $!J-'"a)(%`F'"JJ6"J-'"`N)%a%$!K)(#3N+"J)#%3)2!a%4!a)("K)("a%'!JF '%`B$!JB("J)$%!)#"J-(%`S6%JB$%JB$"JF6"`F6"a)(!`)#"JJ5%JF'%J)'%`B 5&3S(#T!$%J)$%K)*"a)(%4)#"`B(!`%"!J)6%JB'"a)5"J)("JF'"a-(%J)$"K) +&K-'"J)5"`J(%J-5%J)$#K38&3N5%`-6#4-)"a%("K-#"JB(%`F#%a-9&!F(%JF 5!JB(%`N(%JB$"J-5%`F6%`)$%3F5%JF'%`F$!a%(%a)$"`B$%J-'%3F#!J%#%!) #!`F'%`-#%Jd,#4-6#3S6"J-#!a%$%3-4"a-5%`F6#"%#N!-$#4)6"`)3%3)$"K) (%JB#N!-4"`F$%!)!%J)$%3)$"a%#%!X6%JB(!a)3!J)3!JB'!T!$"JF$!J-'"JF $"T!$%`F(%a)6%`F*#4-+"a%5!K)'!JB$%4)5$3S6&"%5!a%$%K81%3B#!J-#!J% "!J-5"`B5#3F'!K%'!`F4!J)$%JS*&!-(%3-5"a)6"a!#!K!#!`N("JF'!`)"!J% #%3F5"a-(%!-("J-"N!-#%JJ8%JB(#4-*"JF5!`F5!`B'%JF5!`)'!a%(%`)'!K! #%3-5%K-("JB$!J)4!J-4"`-'!a-("J)#!3+3!`B(%`N6"`F5#!F(!a%5"a3*"K% 4!a%5!K%$!J)6"`)$!K!#%JF0&`J6"J)("JB*!`B#"JN+$489%`-5%JF4%3-5&!S 6%a)6"a)4!`B("a-6"`)("a)+%a)(%4%'"K!3%4)5#"-6#K%(#3F)%J)'!JB+&!d 0#3B'"`F4#3F6%JF6%`F$!J)$!`B'"`N(%K%$!K!#!`B(%JF5!K)("`)#!`#3"aF !!2rrc*!%!!(-N!B!!Xb3"*QC!!2-c*Q3"!!%c-bCQ@CQ!!@CQFc-QCN!"TQ3"J! (QC!%CQB!#*QCCT!%!!PQN!B!#QD3"$-c!!YQCM13"!!--c0QCM-c!!dcN!B!$J! !)L)!N!-2hC!'!"#lN!B!%DU3"J!5L*!'!"0hN!B!&&@3"J!94*!'!"BLN!B!&a' 3"J!!#)B!!3#3!a`!N!01!*!%rrm!N"#!)!#3"8!!3!#3#8J!N!0)!*!&"!!"!!3 !N!B)6J#3"%4!0%3c-%0$4$-c3c4%!$-`-%4%-c3d-d%d4%3d-$13!d0$-$-d&%4 %-j!$4$-$4!"%&$3c3d%4%c-d-$-c3c4%-c-$-d4%3d-!-!4%-$-c0$&%-d4"%84 %-c3cN!4"3c0$3c0$-c3d-c0$0#-cN!0"0$4%384$-d4$-c-d4"4%-6"!4$!`3d- `-c!`-c0!-a4%3d4%0$4%3d-$0%4%3c-c!c383d-c-`!c0$4%3d3d0$13!d-c!d3 `!c4$4$-d-d4$4"-c-$-`!$3d383c-d4%0$3c-`-d3c-%4$!80%-c3c0$!c-d0$- $3d53!c"$4%4$3c0$-d3c-d0%0$4$-`-c3d-d-$0$3$53!a-c!d0%4$4$!c!d0$1 3"8%$!c13"%0%-d4$384"-c0$0$3c4%3$0%3cN!3d4%-`4$"%-c0%-d4%-$4%4$4 "-a0%4$3cN!0%-c!c-a3c3c-a-d4$3d3c"$-c&%3dN!-c0%-84$-c3d-$0%3c4*! $-a3c4$4$-c0$-c-80"4$0$4%4$0%0$0%-!3c3d-44%0%4$4%0%4%3c3c0%3c3$0 %3d4$4"4%3d-$4$0%3a4%0%4%3d0"-c-`4$-c3c3$"%3c3d0"4%4$!$0$0%3c3d- d3d&%-c3d4$-`!c0%3d0%3c4$3d4$3`3c-a3c4%4"%838&%-c&$3d!$-c"$0$3d4 $4$3c4%-`4$0%4$4"-49"0%4"0%3c4$13"%-c0$4"3a-$-d-d0%!`-d-c4%380$- 84%3c3`-d!c3c3%13!d4%-$-a0%&$-`4$3$4%4%0%0%4"-c0$4%3c-`-$4!0%0$- $343c3d0%0!-d4$-44%%d4$-c-%0%N!0$-%0$0%0$!c4$&$4$-c-d0$-d4*!%3d3 d0%4"4%-c-d4%3838&%0%N!0$4$3c-d53""&%4%0%4%-c%84$-c"%3d4%&%3d-d3 63c4%0$4!0%4%%8-84*!$0$383c!c-"3d4%4"3d4%38&%0!4%4$380%343d&$4%3 `0%4$-j!$3d-84"%c4$0%4$3c3d-d4%0"384$&"4%N!-8363c0%4%3d4$4$0$3d3 4-c3d-d3d3a384*!$0$4%-a4"-`"%4%0%-d4$3d3d%83c4%0%36-c4%0%0%-d4%3 c&%0!-%3d-d-c0%-d4"4%3`-c0%36-d&%0%4%0%4$4$4$0$!c4$0$3`-$4$4%&"3 cN!0%4$-d4%0%4$4$&%53!c3c!d53!c-d3d%d!d-c-$-c0"3c3c4$0%4%0%4%3d3 c4%3d-c3c3d9%4%13!d!!4$0"3d3$4$-c3c!d-d%c4%-c!c0%0%-d4%0%0%-d!c0 %-d-$3`0%4$3`0%0"&$0%3c-d0$0%3c4"3a4$-d-%-d-c0$3c0%3c4$4%4%%63d3 cN!-`-d-c&%&$0$4$0%4%3c0$-j!$3c-c4%38%63d4$-c0$-$4$4%4%0$4%0%4%- c0$0$-j!%4%0"&%0%4"&$-d3c3a-c&$-d3c-$3d-c-d4%0%4$4$4%-43d4"&"363 c0%4$3d%d4%-c-d53!c-c4%0%3d0%4%0"4*!$38383c0%0$0"4$-d0%-c0$0$-c4 $4$3c"$0%-d3d4%36360%N!0$-d&"3d4$-d4%-c-%0$0$3c"%0%4$4$4%N!Bc-c" %3c-c4$3d-%3$-d3c4%%c0%3dN!0$4%-d4$3c3`3c0$4%-c4$0%3d0!4$3d4%&$3 c4%3c4*!$0$3c0$!c4$3c3c!d3`0%-c0%-c0$3d%d0%0%0$36-d4$4*!%0$0$N!- c4%!$0$3%4$0%-c0%%8-`&%0"-%%d-d4%&%3c4$!d3`4$!d4%0$4$-c4%-83d0$- 40%-c4$0$&%4%0%4$N!3c3c4$3c%c3c4$4*!$36-d&%4$0"-c3d4%0%%$3`-c4%0 "3c0"4$4%-c4$3c0$4$0"3d-c3c4%0"0%-6-!-d4%384$-d53!d0$-d-c-c3d3a0 $3c3d4%0%0%0%0$4$0$-c0$-d&$3d-`0$-c!`0$3c4$3d-$0$-c0$4%3d4!0%3c3 d-%3c4%-c4!-c-c53!c-dN!-$0$-d4*!$3d!c3c3d3c3d4%&%0%-c4$3c4$4$&%0 %-`0%4%0%N!3c-c!a4$0%4"4%4$3`0%-c&%!8360$-c!d&%&%&$3cN!4%3c-d3d3 dN!0$0"-d0%0%3d53"!4$4$4%N!0$4$-d-d4$-853!c4%3d3d3d4%-d4"-83d0%- 8384$0$3`0%13!c0"4$0%-d4%0$-c0%4%0"0$3c-d3c3c-d4$-c3c0$!c-d3d4%% d4$-d3c3d3c!8-c3`-c%!4$13!c3c3$-d-c3c4%4$&%4%-c4%N!-c-d-d3c0$3c3 6-c3d3c-d-d0%4%0%3d53"N0%3c-c3d4%0!-d-j!$0%4%0%-c3c!c-d%d0!4$"$- d4$13"%3c3j!$&%3d4%4$-c"%-`!d0!4%4$0%-d0$4%-cN!-a3d4%3d4%-%4$N!- c-d%c!%4%0%3d4"4%4%-d3c-d0%3$4%-c4$-%4*!$3d3d3`!c-d-d4$4"3d3d-%- d-c3d4$4%-c0%3c4%4%0$4%0%3$4%N!0$4%3c&%-d3d0%3a4$4*!%3c0%4%"!-d3 d4$"%4%0%N!0$0%4%-c0%0%38-d4$384$3a%8-$-c4%%8!%3d-d4$4%4$4$3c%a4 %-d3c36&%0!-84$-c4$&%N!-!N!F&!!"QN!B!!613"J!#Gj!'!!09N!B!"%53"J! &)T!'!!!)IJ!"!*!$(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8%!!% !"!#3"JK1!*!%%c!#-`#3""-$!`)J-!!b!$#3!c)b-$!J)!#3!a!L)K!c!!"!!!! `!!!J!J!!-!!K%J#3!b)5)J#3"#!#!!%3!%!`!$!%!!)`%#)J!$-!!J)J!`!")5% !)3-#!L)!!!)J!3!c!J!`)!!4)!)$-$!!)*!$!L)4!3!5)J!L)J!J!")J%!!c!!) !!!)5)c!c-#!$)3!L)K%J)J!!!5)!)3!#)"%!%!!`!J#3!b%"*!!!-J)"!J)!N!3 J!J!b!c!#%#-J)5!!-3)!!$!`)#!!!#%`%K%K)J#3!a)L!!!J!#!#!L)4)L!!!J! #!`!4)J!`)$!L)3!!!L!L%3)J!#-#)#-J%4%")!!3)J)J)"!3)!-#!L!")J-L!4! K!K!!!#3%!J!K)4%!)!%5)J!`%3!#3$-!!M%K)"!!)J)5)!)!%J!J)#)K%!%J)T! $)!)4)!!`!b!3)J!`!L)")L!!!!)J)J!!)K)5!!)$3J)J)!!5-!-b!L!L!!"#)3) 3%6!!%K!#!`!!)J!`!5)!)5!#-J-!-#!#-#%#!L)$)K)30!)#)#!c!b!L!#!L)!) !)5!J!$)#)!)5%L!L%J!"!M)K!!)J!!0!)K%J!!)$!J%!)6)#!`!L)J%!!K)J!#% !!L%!)!!"-a!#%L-J)J!!!`!"!`-#N!-!)J)K!3!!!L)5%#)5)3%5!L!L!3!`!!) L)J#3!`)J)!!b)J!L)3)!-L#3!b)#%3-3!J"!!!!#)"!!3!3#!!!3!#)5!J%J!5% L!#!#%J)L)!)!N!-")J!#N!-5!!)L!"%#!L)J!J)L)K)J%#)5)5!K%J%J%K%3-`! !!K)$!L)#!5!#%!)4!J!#%K)J)!!!!L)5)M-5)L-c)!!3!$-`!#)!)!)L!L%3)J! L!L!K%!%L)3!#!!)"!J)J!5!J!!)$%3)%%K-!%3!#!!!#)J!3!*!$-#!!%3!4)L) J!J!!)4!`!L!!)L!4)!#3!a!"!#!J)M-#!#)5)4)L)#)J-!%K!#!$)`!!)#)#!!- J!L!J)J)$!#!J!!)`)L)6)!)!!L)$)!)3)#)d!J!#!b%K!J!J!J%!!J)J!J)L)L- d)`!K!5-6)!)L!L!!!!)L!6)4)!!M!!!J!"!#!K!#%b!J)L!K)L)M)b)J!L!!%5! #N!-3-!%`!!-!%!!!%3%$!3!!-J)5)J)4)5!!!3!3%%)K%L!!N!B#!#%#!!!%)3) !%L)K!5)J)!!K!J)!!"!!!!)!!J!!!j!$!L!K-#)5)L)4%L)J)!)M)4%5)b!!)J) #-!!!!b-N)!-J-J)!-5!J%"%J)J%4!K!#%L%b-#!!)3!M"#)!!!)!!#%$)!!"!$) L)5)!)5!3%#%L!M)#!J#3!b!J!$-#!#)b!5-M3#!L!K)4)T!%%4!!)!-!)$!!!`) !!L"$)$)b!`)`)`)#)L%5!K!L)K%M)!)!)!)!!J-b-5!5!!&!)*!$!$#3!b!M)L! 4)K)#)K)!)#)c-3)J-`!c)J!3)$)!-J!#)`-`%b!!)5%c)L!L%#!#)J!$-!#3!c! a!L!J%K)c!!!b!`-5!!)K!M-!%"!J3J!!)$3!N!-#!!)L%3)L)$!$!!!$!`!b%!) !N!-L)J-#!J!#)J)#!!-!!L!!!5)J!`-`-$)`%J!L)J!c-#)J-d!!-!!!%5!!-`) !!J)K%5)J!`%J!`!L!!)`"$"!)M!!!!)#!")K)J-J-`!#-J%5)L!!)$-!)#!!N!N #)!!L!"%33L%#)J)!)K)`!J!4!!!5!J!J!`!!)!!!-J)J)!%!!K!#)J&!)5!L)M! #)#)!!a!#!#!#-$)J)$0!)!)b)#!#)!!5!J!L%L%3!#)`)#!#)#)J)b!#!L)$"!) b)L!L!*!$-#)#)!)#!!)!)4-J-c!#!!!`!L!`!$!d-!)$)#-J-!)!)3-!!!)`)J% 3)#-$"$-!-!)!N!3#!d0!)")J"$!c!*!$!L!J!#)J!J!b!$"$3!0#)$3!!!3d3`- !%L!%!`3J!$-!!J"!!#!J!`!J)#)c!!!d!b-#!%!c)c)$!3!!%`!J!#)L!*!$-!- `-#!L!b!!)!-!-!-!!`!#-!)")#%!)#)J)#)#!!!b-"!!%#!J!J-!-!!M!!)!3%! #!")J%!-!!!)4)33#!b%#-M)M-#-$!$!c-`!`)*!$-!-#)!)#!#!!)5!J!`)$!5! #-`)`3c!!!#-$!!!L!!!3)!!L)6)J!`%#)#-!!K3!!!-d-$-!-$!!!#33)J!a!#! #!`!!!`-!!3*!!!)L!$!$!`!J!#!M-%!!N!-L!#)#)!)$!`!`!M-#)!#3!a%c"$! %!b!!"!!`-#!!)$!M!J!5)`!!-$!L)!!"!!3J!#-`)!-`!J!!)J"!-L)!N!-$)#! L!L!"-#*!-!0$!!)J-!)!-`!!!J!M-!!#!`#3"#)`)3!L)$!%!$!#%`!J!$!")!! b!J!J)!!b)#)#)L!#%J!J!!!$-$!$!$!#!#!!!!%J)c!!N!-#)#-5*!)%%#)K!3! J!c3$)#-!3`-!!#!#)!)`0$!L!J-!!J!L)!!$!K)#)L)`)`!J-!!!-c!J-#!#)%0 !4$!!N!-M)*!$!!!M-J-b)J!$!!!#)J!`!j!$)$)c)`3!!b!!)%!L-M!L!J#3""! J!!*!)"%"!!!d-J-#!!-!!$!!)#)!N!-c-!)#!$)#!`!J!$)#)b)!)!3!-#!!-c- $-$-J!J%!-*!$!`-!3J-`)J#3!a!3)!!J!`#3"`3!!*Q3"J!"Zj!'!!+UN!B!!iL 3"J!%Gj!'!!!)PJ!"!*!$(!#3!di!N!6rr`#3%)!J!*!&3!"!!*!*5!#3!dJ!N!8 %!!%!"!#3"JK1!*!%35)R)RBR&L%aFR)L*aG"&8F@%4)LF84(%4%5*b4%&4%Q%L* eBRB8%LBK*fBQ%Q&b)@%4CfGfGK*fCAFR&P%4&@FQ*b4#*Q8QBKChGfB5*N8L%KB LCb)5CfBACK*K)5&K*fBP9d*fCL4@*")A&a)N38&b&L)RFRFR)RGdB5&Q&b*Q%A) 4GR)RB8BP&eF5G(Bf!L%5Gb*L%@GK*bB4%KFR%5FK%LCh)KCQC"%Q)4CK3LCR)R% Q*h*L)4&K)K*'Gb%4*K&K)@)Q&QB9&a*fCb35%d-4%R)RB5GK%@&a0N4b)L%L)K) N3@&KBK%Q4K)ACL48&8CeFR*RFK349RB54"*LGf)bGRB8CaBK&b)b*R*LC@08-(C 5GbBA*K)9BQ%d&h)5&eC"%5)d)4%KCK*LBA)93"96GQ*L&aFL%A3LGP3R)LC5%L% 8%8F5BR*f*b*L*Q)RFL&Q&"*K*b94BL*hN!0Q)K)A*L*48L*LBLBQ)L*#&(Ca34& N&a*L&K9$*b*h&hFL%4*bFKFPGb*LB4)QB5GRGK4K%RCh)K*K%8%LGbFL*R*RFKF L)5BL*Q*LF4%84RBR%5Ca4hFK&a&PCb*QCRF5FQCKF@B@GLFQ)QF@34-@BL%9)A& "&hCLB4%KFR)8*f89CL)L3NF4GfCQB484%4)Q*Q9K*%%5)L)K*'Gb)Q%R&")Q9(* A)4%4*QCR%4&#FPGKCK*a%83A&a0N4b)N)K4%-5&K%N)K8K&LBQGa34&"&5&KCbC '*NGhB54"*P3P99&#)Q*L)5GKB8*LCh)R)dC"FR)RGa%43RBQ%d&h&eB@99*a%53 MGh%4&bFLF5)LC8%L&hGb%4%@)LGP3R*e&PC8Ch0"BQ84Ca&h*a&b%L)Q3A0%4hF @&K4L*hH3!aGa3988)9-5GeBQ%L*&348KFRC#4&3@)K&4%b*b*h%R)LG84f*K4P% QB@)N%@&"GL%4%RBN4"*fF4&#)LGbFL)R)QBLF4Gb)5)L*R3A)QCL%4&a)Q*K%K% K&N*L)Q)LCQGL*L%L%C!$*R*b)5BR)5F@&K4b)A)44hB8FR&44'BAFRBLGh)4%@3 5*L*K&LFLFL%5%R)L*"*A*bGR&&-@&d4LFLG"BKBK%4FQ9aF83")QCL*h*bFL&Q) Q%KCA&44'&K*LF@3A)5%@&a8K)5)@3KB8)@%LF8*L*Q%@&h&&-@%Q*aCfCb)L)4* #*MGK%4*LCQ95GRC"35*LB5)L%L%aFLBA)A&b&@Gh)4*5)4F44"GKCPFL*f&hFQB 4&R&Q%LBK*hF5GLBK&b&R)LB5*534FACKF@GfFK)LF9BN)4%QBKBL&h*fCK8LBRF KCK)K3@Gd*f*9*fCKGb)KBL%K%54@*#CK&bGb*@)RFKCRBL*b)K34)P)QB9FR)Q% A*hGa&8)R)Q)8*LFL)4GKGb)RC5*K*Q*K)Q)5%M4LF5Gd3R9N*h)QN!4KB5%5*hC f)6F89f*4)@*hF5%M84FLGb-QFR*e99%LB5CRB4*f%NGN8K9#Gf&h*RF5%@BN*Q) L4"C')K&84")MBQ%5!5)@)L)R%@)K%R%ABQFRCA9(*8-4FK4b&9*8B5%L*#CdF53 5)4%R*h&")R&K*h&a)LFP-4Ca9#GQ9$33FLFR%f)5%L%@%4)RCd%5)AGa8KB9BL4 %-435BK45&`%9BR*M4NGh)4%8%K)@44BA)L)5%4&R&&38FK%A)QCQF94#*9944a% L&K%4CR34CaC@*R%4BLF5GK*LF@%A)R*f9R8!84F4)8)Q%5CbCR)Q)4G&4bGK%LB L3R)4&&)LGQGb%e4aFAF4"'BRBA%L%5BK&e&KCa%@CK%@)4%84b*PGbG%4#*Q*#* %4'F4)5CaCQBLF4*"FA35)4%KBA8@&RFQ&P8%Gf&R&R3"FLGb&hFK%K864#*Q)Q% R%5*K%5%4GLB598B4)Q)4*f)R*LBLBLB54P0%GL*aF4-LFKB4N!-KB4%M4"%5BR% 54#GaB4G@GQ)L88!5GbC"Ch&QFL)4G#9"44%Q&h*bB4)8Cb&K&f4hCL)L85)KF8) Q%RBKCh)8)K35FL)LFLBLF50L*QB4FQ)L4#*a&b*aCRCR%4BAF4!AFL*L%5&%4#8 5FRGf%@*RChBN%8)ACf*b*KCbBL*aC%GbGLB4)83d%d&4*L*LFM%Q8K&#G(FQ*Q) R)A&LCLC4!QGbGR)L384N4K*%*N&"&a%N&%*N3Q%QBQ)QC(FR)435)d)Q&Q*d%A% 5ChG"FL4bFQ)4Cf)@*L*4*%B93Q%Q&%)P"hCQCLFLC6)R)44"%6*b%N%hB@Ga!K3 K%9%A&(BQCR*L"N)P84)N&KB4&%3N45FL-8CQCL9")5*P%@%LCK)R45%8&#C8%KG QGK8434*"*')4BKCQ%NBL3A&8)LCQ&dF53Q*@3K-bGK*4GK9(-4BAB5GfCT!$*QC LC%*K*QCA%L4(*QC%)R)@F63b*LBa%4)@B5CQCe%QBQBK)K&RBP*L*KGb)K-P"aF 4*4)5*b&%GQD3!f)KB4)QGf*b%5*LF5&K*RCR3"%Q%90P38GRBN*QCP*Q&fBL4LG a)L*hGf)KCb)5CK%@Gf*R&L&#%83L*bCK*#)5B"*&B4&R)L)R*e&#Cb*(3K*#GK% L%a)P%aF43L%8%K3K*4853QGa*hFQC4&N)Q&L&R*KF4BL*fBd&L8$8Q*c%!&f%a% L)N)P3LCL)5C'F83%4#F8*Q%KF488C4&"*f493(*f)8%5G4*$%4&fCKC`4!#3"`F !!2q3"J!"QC!'!!*QN!B!!pf3"J!%Zj!'!!@UN!B!"RH3"J!(4*!'!!!4$J!"!*! $(!#3!di!N!6rr`#3%)"!!*!&3!"!!*!*5!#3!dJ!N!8)!!%!#!#3"K"1!*!%#43 9&!Q3"43-#438%38&%4%&N!36&Im1r`lr$JN&%C!'"4)*$!i,$!@3!a)'%`N8#a8 5"4-*N!F8#C!'&"@3!`8'%C!&"C!$%K)6"`N8ra8(""'3"!84"4)*&Im-$4%&N!- 5%`N9&3i*%K)*N!B8#C!(&!`1r`88%C!'"385%a)6#485"385%a'3"!8&%a39r`i 9%K%&"4)6&"6r&3N&%K-*N!89#3N8#C!%&!crra),%C!'"385%a-8&!@3"")*"4% 4"385#431$K81&"%4"3B*#3`2&"+3"!Q3"")8#C!(&"Arr`B8"4%&N!85%K-*#K% &N!8'#4%&N!-6&"81#a8-%`88"4)*&3i9%T!$"JN6%`8&%K3*N!F9&Im,#43*%38 5"4)5%`N8&384N!3&"4)*%J85#439$K8-$48("!N$"3S1&!@3!`B6&383%386&!N *%a-*N!-9$!`8$!N&N!35%JN*&!`&%3-4%3@3""-8&"81&488&"8-&!B!%K!&&!i &N!85&"3%"388&")6#3J*#439$Im9#4%&%JB6%a39#3F5%C!("3B6&3crN!-&"4) '#43%""%$"438"3B&N!35&436#4Ar%JB*N!-8#C!$&3i&N!-5"K-(%`N9#`N4%"! 4N!-&N!-5&3i-rrm&"4)6#3N8"J-3"3N8%4-&N!3'#Im,#4Ar&!F*N!-(%J8&"K3 5%385%JB5%JN8&Im8%3-4N!3&"3N9N!-1r`8&%K)(#3N'!a!X&%J@3"3N-"4% *rj!$&3N5"K'3!`86#4%&%38&%K)6#46r$K33%"'3!`8@3"2m&N!-'%K)*&"! $"431"C!$%3@3!`F8"4%*$[m-#3N&"4'3!`8'#4'3!`@3!a)5#439r``&%C!%"38 *$"@3!`i5"385N!-6&!83"48,"4%&N!85#384#Im9%`B&"4%3%"%&"3S&%C!%"C! $%JN8r`i0%4!4"386$!i8%aAr#38'"3B5%JN*%3B9&!83"C!&%K3&%3N8"33&&2m &%"%3%388#4'3"!8&%JN*&"Ar&3N4%385&3i*"K)9ra35%J85"K)(&"%5#a8&%3@ 3!`B5#435"4-&%C!$%`i-"3-3"388ra)4N!-&N!-(#439$[m1%`8&"`N5"38($!i 9%`B&"4)'#3`&"`N5"K)&N!-5"JN8%J85#384""%8$"33%4%5&2m9"C!&%K-8&3m 9$[m*"385N!88$[m1&4)&"3B5#Im*"C!$%K-,#38%"`N8"C!%%a)4%3B,$4)4"3B 0r``8"C!%%JN8&C!$$!N4"C!%%T!%&2q3!a8&%385$434"C!%"JN9!33-#4%&N!3 5#4%4"3N9$K-ǡ&38&#"3)%a-9&3N*&"%&%38&%K)'%K)*&Im-#4%4"385&"3 &N!35#3X"""34%3@3"")*"4%4#3i-&4-8$JX&N!-'#K8&%C!$"3B5%"%&"4)'%T! %%a6r$K34N!-&"3B9&!@3!a)6&")*"4%&N!B*"4%&&!`9&3d9ra)4"385#3N4N!3 &%`83%3@3!a+3!`B6%a39&434%4!&N!-*$4)'%K)6&!S&%384"C!%%K-6%388$[m 9r``9%4%&"4)*#4%%%4%%3%4%&%T!&"K)8$`i*%C!$"385%K39%K)6#438%"% &N!B5%`N4"KArN!-1$")4%!8&%JF*%C!$"3B8%C!$"385N!3'%JN*&3i6%4%$%4% &%JN1&!B6#485%4%&N!85%JN*"46r$Jcrr`N3%4%&N!-*#K)4%3B+#a'3!`8&"K+ 3""-*&!i-"4'3"!8&%JN0&3J5#434N!-&N!85%JQ3!`lrN!--#4'3"!@3!`N8"`8 5#3`-"4%4"385N!-6%JN*&2m9%3-4""'3!`86&C!$%K36%"%&N!85"3B8#439$[r r%a!$""'3"!8*&485#48-#4'3!`8&%T!$%a)6#48-#4!4%384%38&%K39&43+%!3 4"C!&%K)(&!84%Jcr&!85%K'3"!8+-#4)$#3N&%4%&"4)5%a)6#4Ar&")3%"' 3!`@3!`B8r`i-#4!$"C!(%K3*"386&2q3!a3*&!84%38ǩ%`8$"3S5%4%&"4) 5%a-*#Im1&4'3"`8&%K6r$K8*%"%&N!B5%`N4%386&3X8%J@3!`B8&!N5#489%J- %"4)*%J8&%T!$%`N*&3i-&!-4N!B&"4)9&4-'#3N4%3@3"4)*"4%4%a6r#3@3"4) 5&"@3"!8#"4'3!`8'#488#4-6#481$[m8""!3%C!%"386&435N!-*#4%&N!3'#4- 4%4-9&"%4"C!&%JB(&"@3!`3$%4!3%4%&"K-8$"88&Im9#C!%%C!&"385#3i5"4) 5%a8)"38'%JN6%38*ra)3%3@3"a)5#"6r&433%!-3N!-4"38*&"81rrm9#3J(#3N 4N!8&%K3*"C!$%K)*&4)&"4-*"JN9ra3#%"%&N!-5"C!%%K)*&480%K%3N!84"38 *&Iq3!``8#3N6#434N!-&"K3*"C!%%K)*ra85#435%`N*$!N#!a%&N!-5"4)&%T! $%a39&3N4%3-3%4!4%38&&"Ar$J`9&43(%a6r&"-*&"-4%3@3"")6#`i8%a)&"4) 5&"3#%"%&N!J'%K)*&3lr"4'3"`85#46r$J`9N!-6%`N1rrm6%`N4%3@3"4-9&4) 5"C!%%K-8!K!3"C!'%T!@3!a3&%38&%C!$"3B*&3i-&C!$$JB6#Im8"385&!N 4"384"385&"35"4%&"4)&%JN4%"%4"C!&%J85N!-6&3`8#4)'%J8&%38&%K39r`i -&48*%a-8#38&%K)6&"34"4%&"4)9%`84"385N!36#4!$%4%&N!B5%JB*$43&N!3 5%K-&"4)*&2rr$J`8#")6%`N&"4+3!`J*&4-4"4%&%K35%4%&"4+3"!B8%K!4%3@ 3"4)5"K)*&4)4N!3%"38*&!N8$!lr&")'%a)6%K%&N!-5N!-6#484%38N&%4% &"4)5"JB5#484%"%&%3@3""+3!`N9%K!4%"%$%!8&#Irr$J`1&!85N!-*"4%&N!- 5"K)6#436"38'&!8&%4%&"4+3!`B6#488!a%4"C!&%K)*&!i&%C!%%"!4%JIr$!i 9&3i*%K)6#4%4"C!$%T!$"JN8&3N5&384"384"385"K)6%JN9$")4N!3&%J85"a6 rr`84%334%"!&"3F9r`i9#481%a)(%a!4"C!$%T!$"K-*$2m-$K%&N!-4"385N!- 6%JN9$K85%3@3"")6&2m1ra)4!a%3%"%&"3N9&3i*"JVrra38#4%&N!-5"4+3!a- 8r`lr$!N&%3@3""+3!a-6#43-&3`9%J8&%a-*#439$!N%%C!&"4)*&Im*"4)*&3l rra33%3@3""+3!a-*$[m1&48&N!B5"K)5#3N9$K81rj!$&!@3!a)*&"31"4'3!`3 4"4)+ra8&"4)*$"89$"83%3@3"4)5%`Rr$K3)#43&N!85%JF)#439$K8-$J`*"38 4"3B*#439#4'3"!8'#489"4%&"JN9$K88r`84%38&%JB5%K-*&3i*%`N8%a%&%T! %%`N*&"@3!rm1%`84%38'%K-*#4Ar"J@3!`B*$"34"!8&%JN1$!N6#`N4N!-&"4) 5%a-8$K85%K-*&!85%K-5%`Q3!a89$K89%K'3"!85N!-6#489&!B&"JN9&4)4%38 &%K3-&")'&2m5%3@3!a)5%`N8&3N5N!-6#486%K13!a)'"4)8&!i&N!-4"C!$"K) 5%`N*"4%&%T!$"JN8$K)&"3Ir$385%JN9ra)4"385%JN*&43&%T!%#43-%a-8#4% 4"3B*$!d4%3@3"")'%JB6%K%4"3B&"4)'%`N8$4)5&2m*"C!$%``1$JN&"3B6#"8 9"C!&"K)*&38&%K%&"JN8$2m8%"!4%38'%T!&%4%&N!35N!-'"JN9&3Rrr`@3!a) 5&!i9"`8&%a3-%K%4"4%&N!-'"a34"C!&%K)*&"33%4%&"4)5%a-'"4!4"4%&N!- 5N!-6%`RrN!35"C!$%K6r%K!4"4)*&"84N!-&N!35#43&%3@3"4)'%a3'%4%&%K- *#4-'%4!4"C!'%JB5%JN9rrm1#3@3!a)*&!-3"C!$%JN8&"%4"4%&"3B(&"-&N!F '%K-8#38&"JN8#3F6!a!3%3@3"K)'%JN9rj!$$!@3!`B8"4!3%38&"K-8&384"38 4"4)6&!i&"4%4"C!$%J85%K8*"3B8&!N6%`)$%"%&N!-5"C!$%K)*&!i9%K-8&"- 5#3-3%4%&"4)(#438%3@3"!B*$!`5"C!$%4%&N!3'#3`*#438#3S*!K!4%3@3"JB &"JN8$"3&"4-8&C!$%"!4"C!$%K-*&"8'"C!%%K3*&")&%C!'"385#3i-&488#`N 5!K!4%3@3!a)&"K+3!`N8$K-&N!-6&481#3-4%38&"K)6&"Ar#385%a-5#3N6%C! ("385#480$"89#4)&!J)$%3@3!a)&%T!$#3N,$J84"38'#3lr$!84"C!$%K)*&"6 r&4)5"K13!`Q3!a%&"4%4"C!$%JN9&3lr&3@3!`-!%"%%"385"4)5%`J*&484%3@ 3!a-8ra88%38&"K)5%`N8r`N5%K-6#C!%&4)4N!-&%38&%a3-&3`9%K%&"4%!!J- 4%3@3!a+3!a-8&434N!-&"4)8r``9%`8&%JB5#!N8&4+3!a13!`Q3!a38%C!%"38 5#4@3!`i5%4%&%38!!K%3%3@3!a)5%`N8$!N4N!3&"JN1&488"C!$%K)6#43-%J8 '%`Q3"439%4%%%385#3X1#a36!K%&N!34!J-3!`84"3B6#439&384%"%4"4)*r`` 9&4)&"4)5%`N8&4)&%K-*N!B9"4%4"JN8$!i9#433%"%4"4%4%K)3!`-4N!-&%`N 9$JN4%4!4%385#3`9N!-'"385%K-*#485"4)6#C!&&"35%3B*#439&385"K3&N!3 4"385#4%$%3-4"3B8&3N4N!8&"4)6$!i9&4-&"4)'%`N8&!8&%K)6#C!&&43&#C! %&!`*"3N1%a%&N!B5&43'"38(&3i1%a'3"J8`9N!-'"C!$%JF*&"3+"4)5#C! &!*!(&J!!c-bCN!3!!Fc-QCPQCJ!#QC!'!!1CN!4QCJ!%QCPQN!3!"@D3"J!'CT! %-c-!"fCQ-j!%!!Jc-fCQ-c-!#613"J!+-j!%!*!$#b)L!*!&$"%4!*!&$3!!)L) !N!-1!!!4%3#3!`m!N!34%3!3L*!'!"&hN!B!%P@3"J!64*!'!"3LN!B!&4'3"J$ r!*!)!3#3!mRS!!$)k!!!"r`$XkJd!hS!N!-F"TB!&eG*6N3!"`$#9%e36!!"!5* 1G@e`!!%"1N&-8P3!!`&54%P86!!%!B*69&)M!"%"[QPMFc3!"!+@D@0c)`!%!Y* *3diM!!3$$QPME$3!"!0+4%a24`!!!iC'6dj8!!8$NNC26N3!!J2D3e958`!)!rj ZD$-a!!!%DNC548B!"!4f3Nj%6!!!",*048j9!"-%[Ne195-!!3@Z8e45)!!!"FC NBh4L!!!&dQPMG')!!!AHB@0dBJ!$"HT`F'&d!!F''J#!!#d!N!0i!*!&J3#3#i) !#!#3!b!!N!@$!!m!N!2H!*!&K!!A!*!$3!#3"B8!(!#3!eS!N!@'!#%!!!%#!*! &K`"f!!!jh!#3"B!!-J#3!ji!N!@"!2d!!%h1!*!&J!!h!!!LkJ#3"B%!33!!)`3 !N!@"rrmJ!!MJ!l1Qf!#!rrm!!%lQ!l1PV"1)!58!!%li!l1Q%"1*!6%!!%*4!l1 Pm!#"rrmJ!!M`!l1PK!#!rrm!!!b-!l1QB"1)rrm!!%jQ!l1QL"1*rrm!!%kH!l1 PZ"G`rrm!!&+%!l1P[!#!!'JJ!!%Q!l1Q,!#$!*%!!%Z4!l1P(!#%!*8!!%iG!l1 Pi!#&!*S!!%im!l1Pr!#'!4%!!!l1Pj!#(!*m!!%pQ!l1Pf!#)!+-!!&"G!l1 PJ!#*!+N!!%m+!l1Q0!$*!+i!!%`P!l1QR!$+!,X!!%b1!l1Rk!$,!-F!!%bd!l1 PM!$-!0!!!%cD!l1Q2!$0!0B!!%ck!l1PX!$1!0`!!%dD!l1PD!$2!1)!!%dk!l1 Q"!$3!1J!!%eD!l1PT!$)!1i!!%ed!l14Y!$4!28!!%fk!l1Q)!2Srrm!!!&!!*! %!qRrr`!!!F3!N!3$k[rr!!!-XJ#3"!2VrrmJ!$Sk!*!%!qcrrb!!1Vi!N!3$k2r r!!!#5!#3"!2Trrm!!!+-!*!%!qVrr`!!#N3!N!3$krrr)!!l3J#3"!2XrrmJ!$Z '!*!%!qMrr`!!!Y!!N!3$kIrr!!!$e!#3"!2Urrm!!!P!!*!%!q[rrb!!1mS!N!3 $l2rr)!!mcJ#3"!2Srrm!!!6B!*!%!qRrr`!!"Y`!N!3$k[rr!!!+L!#3"!2Vrrm J!$h5!*!%!qcrrb!!2pB!N!3AF!%A!!"4rJ1cT0",LIrr)!!00J1cTe4,M2rr!!! @`J1cTe"-$!"G)!!X+J1cTda-LIrr)!"GRJ1cTdK-M2rr!!"R+J1cTd4-#3&C)!! MC!1cTd!!P`"*"!!LT!1cTc`!Q!"5"!!M(J1cTcJ!Q3&0"!"G@!1cTc3#!2rr)!! j"!#3"!)$rrmJ!$P-!*!%!J6rrb!!1C3!N!3#"Irr)!!h9!#3"!)(rrmJ!$HF!*! %!J(rrb!!0q3!N!3#"[rr)!!i,!#3"!))rrmJ!$Kd!*!%!J,rrb!!1,`!N!Errb! !1J#3"S$rrb!!3GS!N!@"rrmJ!%(P!*!&J[rr)!""m!#3"B2rrb!!3IX!N!@%rrm J!%)'!*!&J2rr)!"#%3#3"B(rr`!!3Q-!N!@#rrm!!%,X!*!&Jrrr!!"$1!#3"B6 rr`!!3qJ!N!@!rrm!!%4I!*!&KIrr!!"%M3#3"BErr`!!808!N!@(rrm!!%qp!*! &L2rr!!"&9`#3"BRrr`!!4K3!N!A+rrm!!%E2!*!&brrr!!"(AJ#3"Fcrr`!!4pS !N!A0rrm!!%K"!*!&c[rr!!")U!#3"Frrr`!!53m!N!A*rrm!!%Pf!*!&d2rr!!" *j!#3"FMrr`!!5MN!N!A4rrm!!%V1!*!&J!#"&!",-31cT0J!J3#*&!",B31cT53 !J!%#!!"26J1cT5`AF!%I!!"4bJ1cTG!AF2rr!!"5,!#3""1)!6N!!&1f!l1QG"1 *!88!!&2U!l1Qa!#!rrm!!&3H!l1Ph!#"rrm!!&45!l1N%!#!rrm!!&5'!*!&J[r r!!"c+J#3"B(rr`!!K&3!N!@$rrm!!)d@!*!&K2rr!!#H-!#3"BArr`!!TVS!N!@ 'rrm!!+mm!*!&Krrr!!#heJ#3"!G0CA0cB@GP"P0dBA4eF`G%G@jRC@pZ"%ePER8 %9'9iG!Y%D@&REQpcG'PMF`4198a-"%jeEA!*9@jcD'PQG'9N"e0SD@CdC@3)5'& MDdC[ER3+8&0)B@0V4QpZG!T38dKKBfY'Efjd$8eTFf-Z)&0dFQPZCh-+9&4C)&G TEQ4[G`GYC@jeBQ&b"h0eBQePER8$5f*N"%KPE(!%5@jQE`0"Bh3&6@&RD@-%3QP dF`aMEfjdFQpX)'YPHA-,F(9ZBh4eBA4TEfi)BR*KBfYPG(-&B5!Y)'d&EL!Y)(S &35!Y)%d&6L!Y)&S&-#!Y)$N'GfPkBA*N"f0eFR*PER3%68j9)`j3FQ9Q)%CTE'8 J6Q&YC39&FA9TF!GKFfYZB@eP"90dBA*d#d&LEh9d,f9bFQpb"d0[EQCTFQd,3@* [GA3[CA*bEh)(3fpZCQPbE3Y1CAG)B@0V4QpZG!a38dKKBfY'Efjd)$Q6)`: nethack-3.4.3/sys/mac/NHsound.hqx0100644000000000000000000102443007764735041015334 0ustar rootroot(This file must be converted with BinHex 4.0) :#e0[G@jNFbjbFh*M!(*cFQ058d9%!!!!!!!!!!-,a@BE!!!!!!%!!!-+K!!$#B3 !!!&"!!!"MJ!)Tc`pR`!!$rF!!!'1!!LR2$fI!!!2q!!!!Bi,8fpeEQ4c,R*cFQ- #!!!!FR0bBe*6483"!2rrrrm!!!!!FR0bBe*6483"!2rrrrm!!!!!!!!!!!!!!!! !!!!!$hQR2DiI!!!!!!!$#m83X3!!!C8!#+Fm2eJ!!"$"!!!"P3!)Tc`r@!!!%-3 !!!'9!!LR2$q"!!!3e!!!!C8!#+Fm2kX!!"$P!!!"P3!)Tc`rd!!!%2X!!!'1!!L R2$rR!!!4"`!!!Bi!#+Fm2qJ!!"%)!!!"S!!)Tc`rlJ!!%3d!!!'J!!LR2%!"!!! 4(3!!!!!h3!!"!!%!"3!!!+!!!B"4!!!!!!!8!!!!!!!!0aC@lSZM!!!h&!!!0a8 !2)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)# !J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIi#!JB+$Ji5&KBD'KSD'KB@%K)1 #JS'"J)"rIhprIhprIhprJ)#!J)'"JB+#JS1$Ji1$Ji+#JS+#JS'"J)"rIhjpIAY kHAGfG(0aF'p[EQp[F(*cGRKlIB#%KSL,MBq3!*!!N!#3!)q0M)Z*L)D%Ji'!Ihj qIAepIAepIAepIRjrIi#"JB+$K)5&KB@&KB@&KB@%Ji1#JB"rIRelHAGeFR"YDfP RC@9PC@GTE("dHAf#KSU1NT@AQ*QBPjD8NBq-LSL'K)+!IhemI(YlHhYlHhYmI(e pIRq!JB1$K)5&KBD'KiL)LBQ)KiD%Ji&rIAYjGR*ZDQ9KA9YC9eGC@ejMD'jeHi+ )MT5CR*qKSU'JRTbCPT12M)U(KB1"IhjmHhTkHRTkHRTkHhYmIAk!JB+$K)@'KiL )LBU,LiZ+LBL'KB1"IRYiG'pUC9pD9P*26Np38eGEB@CYG(Z%M*1DS+5SUUUUU+@ LRTZANiq-LBD$JAppI(YkHRTjHAPkHRYmIAk!JB+$Ji5%KBD(L)Q*LSU+LBL(KS@ $J(ekGR&XCf&E99&058P*5de499YLDA*lKBkAS+HXX,+bXDqVTk1HQC@4MBQ'Ji" qI(YkHAPjH(KiHAPkI(erJ)'#JS1%KBD(L)Q,M)f0MBb+LBL'K)&qHR9aDQ0G9e& ,4d0"3%*%5%e8A'9[HSD4R+DZY,LkZVLeX+ZQSCZ@NSf*KB*rIAYkHAKhGhGhGhK iHAYmIS#"JS+$K)@(L)Q+Lib-M)Z+LBL(KS1!IAKcE@CI9e")3cik1$Sm38K4@Q9 [HiH5RUH`YVUm[,UhXkfSSTfBNiq,Ki5!IRakHAKiGhGhGhGiHATmIRq!JB+%KBD )LBZ0MSq3!)q1MBZ+L)5!I(KcE@CI9Nj(3$Se-M%c0Me&8&aTGiD9SUki[m2&a-+ qZ,+VTCqCP)q,Ki5"IRakHAKhGhGhGhKjHAYpIRq!JB'#Ji5&KiL+Lib0MBf-M)Z +L)@"IAGbDf4E8da%2MJc-#ma0$T#6PYVHiZEUVDraFR+b-5rZ,'USjfANBf*KB+ !IRalHRPjHAKiHAPkHhapIRjrIi#!JB+$KBD(LBU,M)b,LiZ+L)@#IRPcE'9F98a &2MJc-#ma0$T#6PYVI)kHVER"amV+b-1pYUkRS*U8MiZ)KB+!IhjpI(amHhYlHha mIAeqIRjqIRjqIRq!JB1&KiQ+Lib0MBf-LSH%J(aeEQCH98j(3$Sd-6!`-MBq5&C RHBZGVEV%bXh0bX@qYkqQRjQ6MSU'K)+!IhjpIAamI(amI(amIAeqIRjpIAepIRj rJB+%KSL*LBU+LSU*L)D%JAeiF@TM@P0-4$ik0cBf1$Y#5P9NG)@@TE+ma-M*am1 qYkqSS*U8MiZ)KB+!IhjqIAepIAamI(apIAjqIRjqIRjqIRq!JS1&KSH)LBU,LiZ *L)D$IhTdE'9F98a%2MJc-$!a0$Y%8@&cKCHSYX()c-h,am#jX+QJQT51LSD$JB" rIRjpIAepIAjqIRprJ)"rIhjqIRjqIRq"JS5'KiL)LBQ+LBL(KB0rHR9ZCejA6dK !1M8a-$!b0Mj+@@TqND1c`-M1d-r,a,bdUk+EP)q,Ki5#JB"rIhjqIRjqIRjqIhp rJ)"rIhjqIAepIAk!JS1&KiL+Lib-LiU)KB*pH(&UBeT66%3q1$-`,c!b0d"0AA# &QDZkaXl4dXr+`lU`TjqANBb)KB1"J)"rIhprIhprIhq!J)'"JB"rIhjpI(amI(j rJB1&KSL*LSZ-M)U)KB&pH(&UBPY66%8r163a-$!b0d"-AA''Qkfmb-r6dp$*`VQ [TTf@N!#,Ki5$JB#!J(prIhpqIRjrIhq!J)"rIhjqIAepIAeqJ)'$KBD(L)Q*LSQ )Ki@$IhTcE'4G98j'3$Xh0$-d0MY$6Pe[JjDSYm2,cp(1bF+jX+HIPj'-L)@$JS' !J(prIhjqIRjqIhq!J)#!IhjqIAepIAjrJ)+$KBD(KiL*LSU+LBH%J(YdE'9F8da $2$Bb,bi[-MP%8Q4iMD#b[mR2dY(0alkfV+1EP)k+KS5#JB"rIRjqIRjqIRjrIi# "JB'!IhpqIRepIAjrJB1&KiQ+LSZ,LiQ)KS5!Hh9ZCej@688q0c%Y+b`[0$j,@fq &QUbmamr6dp$+`lU`TjkANBb)KB1"J(prIRjqIRjqIRprIi#!JB'!IhpqIAepIAk !JB1&KiL)LBU,LSU)KS5!HR4XC&e86%-m0M!X+bd`06p-AR1*RDqqbY(8e0$*`VL [TTf@N!#,Ki@$JS'!IhpqIRjqIRjqIhq!J)'"J(prIRepIAeqJ)+%KSH*LSZ,LiZ +L)H%J(YdE@4F8da$2$Ba,LdY,c3q5eaaKjb[[mV5eGA4bX+iVk@FPC!!LiH&Ji+ "J(prIRjqIRjqIRjqIi#!J(prIRepIAepIS#"Ji@'L)Q+LSZ,LiU*KS0pGfpRAPC 046dh-LiX,#ic2%PDES5CV,c)d069dF[$ZV#RRjH4MBQ'K)+"J(prIRjqIRjqIRj qIhprJ(prIRepIAeqIS#"Ji@(L)Q+LSU,LiU)KB*qH(&SB&G24cmi-LmY,M!f2NY FEi5BUVR&cG$4cXR#ZE#SRjL5MSU(KB1"J(pqIRjpIAepIRjqIRprJ)"rIhjqIAj qIRq"Ji@(LBZ-M)f-LiU)KB&pGQpQA94,3cXd,LXU+bmf3%pKGSZIX,l*cp,4cXM !YkqQRTL5MBU(K)+!IhjpIAepIAepIAeqIRprIhprIRepIAeqIi##K)D)LSU,Lib ,LiQ(KB&mG@jPA94,3MNb,#NS+5`d3&"MHBqMYF2-dY66cXHrYUfNRCD4MBQ(KB1 "J(pqIAepIAepIAeqIRprIhprIRepI(epIS##Ji@(LBU,M)f0MBb+Ki0qGfpQA94 ,3MNb,#JQ*LNa2%aKH)kMYF20dpA8cmLrYUfNR*D4MBQ(KB1"J(pqIAepIAepIAe qIRjrIhpqIAamI(apIRq!JS5'L)U,M)f0MBZ*KS0rHR0UBPP35$mi-LiU+5S[1%C BES@DVEh)d026d-R#ZE#RS*Q6MiZ*Ki5#JApqIAepI(amI(apIAjqIRpqIRepIAe pIS#"JS5'L)U,Lib-M)b+L)5!Hh9YCPe85d-m0M%Z,5ia1846CRZ2SV2!bFr3cm[ %Zl5XSjfANSk,L)D%JS"qIAemI(amI(amI(amIAepIAemI(apIi##K)D)LBZ-M)b ,LiZ+Ki5"I(C[Cej@6N8q0M%Y+b`[0N&3C(Q1SV2!bY$4d-c&[,@XT*kBNiq-L)D %JApqIAamHhYlHhYlI(amIAepIAemI(epIS##K)D(L)U,M)b-M)Z+Ki5"I(G`D&p @683l05mV+LSY08"3CAU2Sl6"bp$5dFc&[V@YTCqCP*!!M)Q'Ji&rIRemHhYlHhY lHhYmI(apIAamI(amIAk!JB1&KiQ+M)b0MBf-LiQ'JhjiF@TK9dj&2$8[+LJR+M% m6'&hMD'c`F[4dp,0aVqfVUDJQT53!)f+Ki5"IhjmI(YlHhYlHhamI(apIAemI(Y lHhapIS##K)D*Lib0MSf0M)Z)KB*rHR0VBPP35$mi-5dU+5X`1NPFFBHEVEc)cY( 4cXM"Z+qSSCZ@NSk,L)D$JApqIAamI(alHhYlHhYlI(amHhYlHhYpIS#"Ji@(LBU -MBk1MSf-LBD#IRG`D&p@683l0#mV+5JV-Mj3CAZ4TEE$c0,6dFc&[,@XTCkCPC' 0LSH%JAppI(YlHRTkHRTkHRYlI(amI(alHhYmIRq"JS5'L)U-MSk0MBf-LBD$IRP bDQ&C8%K"1cBa,LdZ-Ma+A('(QkflaXh3d-h(`,H`U++FPj12LiL&JS"qIAalHRT kHAPjHAPkHRYlHhYlI(apIi##K)D)LBZ-MBf0MBf,LBH$IhTcDf0D8%Fq0c%X+#F U-$Y+AR5+RV#qb-r5dFl)`EQ`UD+FPj12LiH&JAppI(YkHRTkHRTkHAPjHAPjHRP jHRYmIS'$KBH*LSZ-M)b,LiU*L)@#IhTdE@CG98a%2$Fa,5XV,MC%9QZ"PUQjaFh 4dXr+`lbcUk@IQC@4MBU'K)&qIAYkHAPjHAPjHAPjHATkHRTkHRYmIAq"Ji@(LBZ 0MSk0MBb,LBH%JAefEQGH98a$1c8[+bJR+M*!8fQ!PUUlb0$8e0(-aEfdV+@HQC@ 4MBQ'Ji"qIAYkHRTkHRTkHRTkHRTkHRTjHATlI(k!JS5&KiL*Lib0MSf0MBZ)KB& mG@aN@e*)2cJa+bFP*b`h4eadLk'c`Xc5eG22b-'iVkLLR*H6MiZ)K)+!IRalHRP jHAPjHAPjHRTlHhTkHRTkHherJB1%KSL+M)f1MSk0M)Z)KB*pGh"RAP904$`e,bS Q*LSc399XJjQX[-M3e064bm5mXkbPRjQ8N!#-L)@#IhemHhTkHAPjHAKiH(KjHAT jHAPjHRYmIS'$KBH)LSb0MSk1MSf-LBD$IRPbDQ&B6N8m0#iS*#-Q,ce4DB#AUl[ )d069dXc&[E5XTCkCP*!!M)Q&JRppHhTjHAPjHAPjHAPkHRYlHhYkHRTlI(erJB1 &L)U-MBk1Mik0M)U'JRjiF@TK@%p(2cJb,#JR+#ml6'*jN!#NYX61dp66cXHqYkk RSCZ@NSk+KS1!IRalHRPjHAKiH(KiH(PjHRTkHATkHhaqJ)+%KSH*Lif0MSk1MBf ,L)@"Hh4XBeT458!j-L`S*LFY1%PHGBbKXm,0dp66cmM"Z,#SSCbANSk,Ki1"IRa lHRPjHATkHAPjHATkHRTjHAKjHRYmIS##K)H*Lib0MSk0MBb,L)@#IAKaDQ&C8%F q0c!U*5-P,Me4DS1DVVr+dYE9dX[%Zl1VT*kBP*!!MBQ&JRppHhTjHAPjHAPjHAP kHRYlHhTkHRTmIAq!JS5&KiQ+Lib0MSk1MBU(K(pjFQYK@%p&2$3Y+#3M*Lim8'L !PkZmbG(9eG,-aEfdV+@IQC53!)b*KB*rIAakHRPjHATkHAPjHATkHRTjHAPkHha qJ)+%KBH*Lib0MBk1MSf+Ki@!HR0XBPP34cih,bSQ*#FZ1djNI*1RZ-E2e0A5cFD rYUfQS*U9NBf*KS1!IAYkHAPjHAPjHAPjHAPkHRTjHAPjHRaqJ)+$KBH*M)f1Mj! !Miq1M)Q&JAaeE@4E8NP!1$%V*L-N+M9(A(1-SV6$cY29e-r)`,H[Tk'EPT+1LSH %JAjmHhTjHATkHRTkHRTkHhYlHRTjHATlI(jrJB5'LBb0MSq2MSk0M)Q'JRehF'G I9Ne%2$3Z+#-L*Lmr9@k'RV,#cG6AeY(+`VQaU+'FPT+1LiH%J(jmHRPiH(PjHAT kHRTkHRTkHRTjHATlI(k!JS5'L)U-MSk2Miq1MBZ)K(pkFfYL@P&)2cF`+53L*5X j6'0mP+QlbG(@ep61alkeVD@IQC@4MBQ&JRppHhPiH(KiHAPjHAPjHATkHRTjHAP kHherJB5'L)Z0MSq2N!#3!*!!Mib*KS&mG@eN@e**3$Na+L3L)bJd4PaeMU5faFr 9eYA3bF#hVkHKQjD4MBU'Ji"pHhTjH(PjHATkHRTkHRTlHRTjHAPkHherJB1&KiQ ,M)b0MSk1MBb*KS*pGh"SAeC04$Xd,LJN)LBa3PKaLU#c`ml8eYA4bX+jX+QLR*H 5MSZ(Ji&qI(TjH(KiH(KjHAPjHRTlHhTkHRTlI(erJ)+&KiQ,MBq3!*!!N!#3!)q 0LSH$IRG`CPa658!i-#FI'aXJ,8&DG)kPZFM5f0R@dFV"Z+qRSCZ9NBf*KB*rIAY jH(KiHAPkHRYlHhYlHhYkHAKiHATmIS##K)D*Lif1MSk0MBb,LBD#IAKaD'"A6N8 q0LmR)L%M,$a5E)@GXF(0e0I@dFV$ZV'TSTbANiq,L)5"IhelHRTkHRTkHRTkHRY lHhYkHAKiHATlIAq"Ji@(LBZ-MBk2Miq1M)Q&J(YdE'0D8NP!1$!R)4mJ*cC,C(q BVVr-e0MAe-h&[,1USjbANiq,L)@"IhelHRPjHRTkHRTkHRYlHhYkHAPjHATlIAq "Ji@)LSZ0MSq3!*!!N!#2MBU'JAaeE@4E8NJr0biP(KXE)M&(BAf@VF$0eGRCeFr ([V@XT*kBNiq-L)5#IhelHRPjHAPkHRTlHhYlHhYlHRPiH(PkI(k!JS@(LSb0Mj! !NC'3!)q0LB@"Hh4YC&Y558!h,bJL(KdN-8GKHjDX[Xc8fGR9cXHqYDbNRTL8N!# -L)@#IhelHRPjHAPkHRTlHhYmI(alHRPjHAPkI(k!JS5(LSb0MSq2Miq0M)Q'JRe fEQCF8dT"1#mR)4XD)#j%ARU8Ull,eGRCeXr)[V@XT*fBNiq,L)5"IRakHAKiHAP kHRYlHhamI(amHRPjHAPlI(k!JS5'L)Z0MSq2N!#3!)q0LiL%IRG`CPa658!i,bB I'KNI,%&EGj+U[Fc9fY[AdFQrYUfNRCL6Mib)KB*rIAYkHAPjHRTlHhYlHhamI(Y kHAPiH(PlI(k"Ji@(LSb1Mj!!Miq2MSb*K(pjFQPJ9dj&263X*"iD(#Bi8Qf*SVI (dpREf02,`VL[TU#DPC'0LBD$J(jmHRPjHAPkHhYlHhYmI(amHhTjH(PjHherJS5 'KiQ,MBk2Mj!!N!#2MBU'JAYcDf*C8%Bp05XL("FC)M41DiHKYmM6fYcDe-c$ZE# SS*U9NBf*KS+!IAYjH(KiHATkHhYmI(amI(alHRPjHATlIAq"Ji@)LSf3!*+6P*1 5NBk+KB"jFQPI9Na#16%S)"N@'#-f8'b)SVI)e0[GfYA0a,UaU+'DPC'0LBD$Ihe lHRPjHATlI(amI(amI(alHRPiGhGiHRarJB5(LBb1N!#4NC'3!)q0LiL%J(PbD@" A6dBp05`N(4ND)M*,Ci1HY-E5fGcDe-h%ZV'SSCU9NBk+KS5"IRakHAPjHATlI(a mIAepIAalHAKiH(PkI(q"Ji@)LSb0Mj!!N!#4N!#2M)Q&JAYdE'*C8%Fq0biP(KN B(bp)C)'FXX64fGcEeXl&[,+TSTZ@NSk+KS5!IRakHAPjHRTlHhamI(apIAalHRT jHAPkHhf!JS5(LSb1Mj!!N!#3!)q1M)U(JRefE@9F8dT"16%R(KF8'5P"ARbBX-2 5fYhFep$([E5VSjbANiq,L)5"IRakHAKiHAPkHhYmI(apIAemHhTjHAPkI(k!JS5 'L)U-MBk2Miq2MBZ)K(piF'GG9%Y#16!R(KF9'LJr@hQ9VF$2f0cFf0()[V5VSjf ANiq-L)@#IhelHRPjHATkHhYlI(amI(amHhTjHAPkI(k!JS5(LSb1Miq2Miq2MSb *KB"jF@KH98Y#15mP("34&L3m@AH8VF(3fYlHfY2+`,DYTCkBNiq,L)5"IRakHAK iHAPkHhYmI(amI(amHhTjH(KjHhf!JS5(LSb1Mj!!NC+5NBq0LB@!HA"SAP9-3cS `*K`8%"-J0e4cND[!cpRHhYV6bX#fVD@HQ*12M)L&JRpmHRPiH(PkHhYmI(amI(a mI(YjH(KiHAYpIS#$KSQ-Mj'5Nj15NT!!MBU'J(PaCee658!f,#)A%!d6)caDHCD [`p,DhYhCdXLqY+ZMR*H5MSZ(KB&rIAYjHAPjHRYmI(epIAepIAemHRPiH(KkHhf !JS5(Lif2N!#4NC+4Mif+KS"jF@KI9Na$1M!Q("32%Kmf8h14UVr3fYrIfp6+`,H ZTCkBNiq-LB@#IhelHRPjHATkHhYmI(amI(amHhTiH(KjHRapJ)+&L)Z0Mj!!NC+ 6Nj'2M)L#I(9XBeT34cie,#)C%4!C+dCPK+#hbGAFhYc@cX5kXDQKQjD5MSU(Ji" pHhTjHAPjHRYmI(apIAepI(akHAKhH(PlIB#$KBL-MSq3!*'5NT+4MSZ(JhaeE'0 D8NP"1#mP("88'LT$BAqEXXA5fYhEeXr&Zl+TSTb@NSk,Ki5"IRakHAKjHATlHha mI(apIAemHhTjH(KjHhaqJ)1'LSf2NC+6P*56NBk+KApiEf9F8NJr0LdM'K34&bB qA(UAVm,4fGhFf0()[V@XT*fBP*!!M)Q&JRpmHRPiH(PkHhYmI(alHhYlHhTjH(K iHAYpJ)1&L)U-MT!!NC+6Nj+3!)f*KB"jF'GH98Y"1#mQ(4B6&b8l9h@5UVl0ep[ Ef0(*[lDYTCqCP*!!MBQ'JhppHhPiH(KjHRYlI(amI(amI(YkHRPkHhaqIi'$KBL ,MBk2N!#4NT+4MSU'J(PaCej85d%i,L3C%Jm9*$aCGj5Y`G$ChGcBdFLqYDbNRTL 8N!#-L)@#IhelHRPjHATlI(apIAepIAemHhTiH(KiHRaqJ)+%KiZ1N!#5NT16Nj' 1LSD"HR&SAeG146`d+Km@%"%F-8eXLkDlc0MGhY[8c-+jX+HKQjD5MSU(Ji"pHhP iH(KjHATlHhamI(epIAakHAKiHATmIS#$KBH+M)k3!*'5Nj15N!#0LB4pGQePA&* *3$J[*4`@&"XU3PppQ,$$d0RFfpE2aVfcUk1GQ*52M)L&JAppHhTjHAPkHRYlHhY lHhamI(YkHAPjHRYpIi'$KSQ0Mj!!NT18P*+3!)f+KApiF'GH98a$1M!Q("33&#) k9hD6V-$2fGhGfG,*[lDYTCkCPC'0LB@#IhakHAKiH(PkHRTlHhTkHhYlHhTjHAT lIAq!JS5'L)Z0Mj'5Nj15N!#0LS@!HA*TAeC04$Xb+5!B&4FM1&0`M+5jbG6CfYI 5bX'iVkHKQjD5MSU(Ji"pHhPiH(KiHATkHRTkHRTlHhTjHAKjHRYqJ)+%KiU0Mj' 5Nj16NT!!MSZ(JRYdDf*B6N8l-LFG%`i4(643EifR[-c@fpcCdX["Z+qRS*U9NBk +KS0rIATiGhGiHATlHhamI(amI(YlHRKiH(KkI(k!JiD*M)k3!*+6Nj15N!#1LiH "Hh4VBPP34cid+L!A%4%E,NTTKk1jbYEFhG[9cF5kXDLLR*H6MiZ(K)&qI(TjH(K jHATlHhYlHhYmHhYkHAKiHATmIS#$KSL,MT!!NC'5NT+4Mib*K(efEfCF8dP!0b` J&3d,&#P&C)1IYXR@h0lFeXr'[,1USjfANiq,L)5!IRYjH(KiHATlHhamI(amI(a lHRKhGhKjHRaqJ)1'LSk3!*'5Nj16NBq0LSD!HA"SAe9-3cN[*"J2#a!K1eTkPl( %dp[HhGM4alkeV+5HQ*53!)b)KB&rI(TjH(KjHATlHhamI(amI(akHAKiH(TlIAq "JiD)LSf2N!#4NC'4Mif+KS*lG'aM@P&)2c8V(a82%"Xb6fk-TV[-eY[FfG,+`EL [Tk#DPT+1LSD#IhakHAKhH(PkHhYlHhYlHhalHRPiH(KiHAYqJ)1'L)Z0Mj'5Nj1 6NBk,Ki*mG@eN@e**3$BX)KJ4%"SZ5@L(SVM*e0[FfY6-`lUaU++FPT+1LiH$J(e lHAKiH(PkHhYlHhYlHhYlHRPiH(KjHherJB1'L)Z1N!#4NT16NT'2M)L%IACYC&Y 45$id+4d5#`X@,%PTLD5lc0MHhpc9cX5lXUULR*D5MSU'JhppHhPhGhKiHATlI(a mI(amI(YjH(GhH(TmIS##KBH*M)q4NT58NT'2LiL$IRG[CPe656me+Ki6#`X9+NG RKk+jbpIGhY[@cF5kXDQLR*H5MSU(Ji&qHhPiH(KjHRYmI(amI(amHhTjH(GhGhP lIAq"JiD)Lik3!*+8P*58NSq,KS&kF@KH9%Y"0LSG%3F&$b4#C)5KZF[AhYrFeXr &Zl+USTbANSk,Ki5"IRYjH(KiHATlI(epIAemI(YlHAKhGhGiHRaqJ)1'LBf2NC1 8P*56NBk+KB"jFQPJ9de%1M!M&``($4mj@RUBXXA8h0rHf0(([V5VSjfANiq,L)@ #IhakHAKiH(PkHhamI(amI(alHRPhGhGiHAYpIi+&L)b2NC18P*58NBk+KS&kFQT K@%p'26-T(4)-$KXc8A'3!+UrcpRGhGV6bX#hVUDIQC@4MBQ'JhppHhPiH(PjHRY lI(amI(YlHhTjGhGhGhPlIAq#KBL-MT!!NT59PC55MiZ(JRefE@4E8dT#16!N'4% 2&LP%C)5IYXR9fphEe-h%ZV'SSCZ@NSk+Ki5"IRYjH(KiHATkHhamI(amI(YlHRP iH(PkI(k!JS5'LSf2NC18PC56NBf*K(jhEfGH98a#15iM'!m-%L9!B)#FY-I8fpl Fep$([E5VT*fBNiq,Ki5"IAYjH(KiHATlI(amI(amHhTjH(GhGhKkI(k"Ji@)LSf 2NC+6Nj+4MSZ)JhjhF'KI9dj&1c!N'!m,%L-qARqFY-I8fplFemr'[E5VT*fBNj! !M)L&JRjmHRKhGhKjHRYmI(amI(alHRPhGRChHAYpIi+&KiU1N!#4Nj58P*14MiZ &J(PbD&p@683l-5FF%3d4(cK@GT5Z`Y$ChGcBdFLqYDbPRTQ9NBf+Ki1!IATjH(G iHATlI(apIAamI(YjH(GhH(PlI(jrJS@)Lik3!*+6P*@8Niq,Ki*lFQPJ9dj&1c% Q'a%-$ade8h15V-(3fYlGfG,+`,DYTCqCP*!!M)L&JRppHhPiH(KjHhamIAepI(a lHRPiGhCfH(PlIAq"K)H+MT+8PCD@PC13!)f)JhaeE'0D88Jq05SH%``-&ba*DBL MZX[@h0hDe-c$ZE#SSTb@NSk,Ki5"IAYjH(KiHATlHhamI(amHhYkH(GhGhKjHhk "JiD*M)q4NT18P*14Mib*K(piF'KI9Ne%15dJ&!S)%54"BS1JYmV@hGrFeFl&Zl+ TSTbANSk,Ki5"IAYjGhGhH(PkHhamIAamI(alHAKiH(KjHhf!JS5(LBb2NC18PC5 6NBk*K(piEfGH9%Y#15iL&3`*%54!B)'HYXR9h0rFeXr&[,1USjfANiq,L)@#IRa kH(KiH(PkHhamI(amI(YkH(GfGRGiHRaqJB@)Liq4NT59PC56NBk+KB"kFfTK@%p '2$%P'3i)$"dh9RH@Vm24fplGf0()[V@XTCfBP*!!M)Q&Ji"pHRKiH(KjHRYmI(a mI(amHhTiGhGiHATmIS##K)H+MC!!NT18P*55Mib)JhaeE'*C8%Bm-LFE%3`1'c0 4FC!!UVr1f0hGfG,*`,HZTTqCP*!!M)Q&JhppHhPiH(KjHRYmI(amI(amHhTjH(G hGhPlIAq#KBL-N!#6PTHAPT@6N!#-Ki&lG'YK@8p'2$)R'a!*#KF[6Qq2UVr3fYl HfY2,`EL[Tk#DPC'0LBD#IhakHAKhH(PkHhapIAepI(alHRPhGhGiHATmIS'%KiZ 2NT19PTD9Nj!!MBQ$IACYC&Y45$me+am8$3dA,%KSKk1jbYEEh0V6bm1jX+QKQjD 5MSU(K)&qI(TjH(KjHRYmIAepIAamHhTjH(GhH(PlI(q#KBL-MT!!NC+6Nj+4Mif +KApiF@KI9Na$15dK&!X)%59$C)@KZ-V@hGlEeFl&Zl+TSTbANSk,Ki5"IRYjH(G iH(PlI(apIAepI(alHRPhGhGhHAYpJ)1(LSk4Nj58P*@8NSq,KS"jF@KI9Na$15d K%`J$#KipB)'JZ-[Bhq(Hf0$'[,1USjbANSk+Ki5"IRYjH(GiHATlI(epIAemI(Y kH(GfGA9fH(TpJ)1(Lik4Nj59PC@8NT!!M)H#Hh4VBPK246Xa*4N2#JdE-e*cNUc "d0RGhGR5bEqfVD5HQ*53!)f*KS0rIAYjH(KiHATlI(amI(amI(YkHAGhGhKjHhe qJB5(Lik4Nj5@PjD8NBf)JhadDf*C6dBm-LBD$`N+'$"2FC!!Um$3fYrHfY2+`EH ZTU#DPC'0LBD#IhakHAKiH(PkHhapIAemI(alHRKhGhGiHAYpJ)1'LBb2NC18PC@ 8NT!!M)H$I(9XBeT45$mf+Ki5#JS9,%YXM+LpcYMGhYV8bm+iVkLJQT@4MBQ'JS" pHRKhGhKjHRYmI(amI(amHhTjH(GhH(TlIB##KBL,MT'6P*@9P*+3!)b)JhefEQ9 F8NJq0#NG%``,&La*DSUP[-hBhGlEe-c#ZE#RSCZ9NBf+Ki5"IRakHAPjHATmI(e pIAepI(YkHAGfGRGjHhf!Ji@)M)k3!*+6Nj56NBq-L)0pGQePA&0*3$BX)"3-#a8 V5@U+TEc0f0hHfp6,`VL[Tk#DPT+1LSH%JAjlHAKhH(PkHhapIRjqIRemHRPhGRC hH(TpIi'$KSQ-MT!!NT19PC56N!#,KS&kF@KI98Y"0b`I%3B##b&!BS1KZFcChq$ Gf-r&[,1USTb@NSk+KS1!IRYjH(GhH(PlI(epIAepI(YkH(GfGAChHAYpJ)5(LSf 2NC+8P*58NSq-Ki*lFfTK9dj%1LmM&3N$#4Xh@AZDY-M@hZ$HfG$([E1USjbANiq -LB@#IhakH(GhH(PkHhapIAjqIAelHRPhGhGiHRYpIi+&LBZ0Mj'5Nj56NT!!M)L $I(0VBPK04$S`*"J0#!`F0PCiPl$&e0cIhYR4b,keV+5HQ*12LiL%JAjmHRKhGhK jHRapIRjqIRepHhTiGhGhH(TlIB##KBQ-Mj'6PC@9P*13!)b(JRYcDQ"A683k-#- 9#J8*'MCAHCQcapEHiGrCdXLrYDbPRTL6MiZ)K)&qI(TiGhKiHAYmIAjqIRjqIAa kH(GhGhKjHhf!Ji@)M)k3!*'6P*56NSq-L)0mFfYK@%j%15iJ%38!"KSiA(qIZFc Ci1,IfG(([E5VSjfANSk+KS5"IAYjH(GiH(TlIAjrIhprIRemHRKhGA9fH(TpJ)1 'LBb2NC+6Nj16NBk,KS&lFfTK@%p'26)Q'3d(#KJb8h@9X-A8hH$IfY,)[V5VT*b ANiq,L)@#J(elHAKiHATlI(eqIRprIRemHRPhGhGhHATmIS'%KiU0Mj'5Nj16NSq -LB4pGQeNA&0+36FV(3m&"4!S5'b1UX(5hH,Kh06,`EHZTCqCP*!!M)Q'JS"pHhP iH(KjHRapIRprIhpqI(YjH(GfGhKkI(k!JiD*M)q3!*+6Nj15Mib)JhefEQ9F8dT #1#dJ%JJ'%#G(DSbT[p$Ei1$FeF["YkkPRjQ8N!#-L)D$J(elHAKhH(PkHhepIRj qIRemHhTiGhGiHATmIS#%KiU1NC18PC@8Nj'1LS9qGfjP@e*)2M8T'`m'"4%S4QQ +U,r3fq(KhGE0`lQ`Tk#DP*!!M)Q'Ji"pHhPhGhKjHRapIRprIhpqIAYjH(GhGhP kI(k"K)H-N!#5P*D@PT@6N!#0L)0mG'YL@%j%1LmM&JS%"K8a8R@@XFE9hZ(Jfp2 *[l@XT*kBNiq,Ki@#IhelHAKiHATmIAjrJ)#!IhjmHRKhGR9fGhTmIi+%KiZ0MT! !NT16Nj+3!)f*K(jhEfCG9%Y#15iK&3X($b0"Bi@MZmlDi1$GeXl$ZE#SS*U9NBf +Ki5"IRakH(GhH(TlI(jrIhprIRemHRKhGhGiHATpJ)+&LBb3!*+6P*58Nj+2LiD !HA"QA94,3MNZ)K3+"JdJ2&k!RlR-fH$KhYM2aEZaU+'EPT+1LiL%JAjmHAKhGhK jHheqIRprIhjpHhTiGhGhH(TmIS#$KSL,MT!!NC18P*14MSU'J(PbD&pA6N8p-bB D$`S0(6GAHCLbaY6FhphBd-HpY+ZMRCH6MiZ)KB*rI(TjH(KiHATmIAjqIRjqI(Y kHAKhGhKkI(k!Ji@)Lif2NC+5Nj15Mib)JRadE'0D88Jr0#JD$JF*&c&4Fj5[a02 Fi0rDdmR!YUfPRjQ8N!#-LB@#IhakH(GhH(PkI(epIRjqIAalHAKhGRCiHAYqJB5 (LSf3!*+6Nj56NT!!MBU'JATcDf*C8%Fp-bFF%3X0'c06GC5Z`p,EhYhCdFQrYUf PRTL6Mib*KB+!I(TjGhGiHATmIAjqIRjqIAakHAKhGhPkI(k!JiD*MBq4Nj58Nj1 4MSU'J(PbD@"A6dBp-bFD$`N-'M*5G*1Z`p2Gi0rEdmV!YkkPRjQ8N!#-L)D$Ihe lHAKiH(PkI(eqIRpqIRalHAKhGRGiHAaqJ)1&L)Z1N!#5NT16NT'1LiL#I(9YC&Y 558!h,#!9$3`@+NGSL+@mcGMHhY[9c-+jX+HKQj@4MBU(K)&qI(TiH(KjHRYmIAj qIRjpI(TjH(GiH(PlI(erJS@*M)q4Nj59PC55MiZ&IhG[C9a656me+Kd5#JJ5*d0 NKU1lcGMHhpc@cF5kXDQKQjD4MBU(K)&qI(TjH(KjHRYmIAjqIRjpI(YjH(GhGhK kI(q#K)H+MBq4Nj58P*14MSU&IRG[CPa55$ic*aS0!`)0*89UM+R"dYhLiYlAcX@ kXDLKQj@4MBQ&JRpmHAKhGhGiHRapIRprIhpqI(YjGhCfGhKkI(k"K)H,MT'6P*@ 8Nj+2M)L$IA9YC&T45$me+ai5#JS8+8GRL+@mcYVIi0c9cF5kXDLKQj@4MBU'K)& qI(TjH(KjHRapIRprIhjpI(TjGhCfGRKkI(k"JiD+MC!!NT18P*56NBf+KApiF'G H9%T!0LSG%!F%$L4$CSLP[Y$EiH,Heml%ZV'SS*U9N!#-LSH%JAjlHAKhH(KkHhe qIhq!IhjpHhPiGhCfGhPlIB'%KiU1N!#4NT18P*14MSU&IhK`Cej@6%-k,Km4"3% )($YJJk1mcp[LiprBcm@lXUQLQjD5MSU(K)&qI(TiGhKiHAYmIAjqIRjpI(YjH(G fGhKjHRf!JS@*M)k4Nj@9P*15MiZ'J(PbD9p@683k,b%6"`)*(6aJJU'kcGRIi0h @cF1kXDLKQT@4MBQ(K)&qHhTiGhKiHRYpIRprIhpqI(YjH(GfGRGjHhf!JS@)Lik 4Nj58P*14MSZ'JATcDf0D8NJr0#FD$`N0(6KCHTLaaG,Ch0V8cF5kXDQKQjD5MSZ )KB*rI(TjH(KjHRYmIAjrIhpqIAYjH(KiH(KjHherJB5)M)q3!*'6P*16NBq,Ki* lG'aL@9")2c8S'Jm,%#%mA(fEXmE5fG[Ce-[#ZE#SS*U8N!#-LBD$J(jmHRPiHAP kI(eqIhprIhjpHhTiGhGhH(PlIAq#K)H,MT!!NT16Nj+3!)k,KS&mG@eNA&0+3MJ X(a32%b)m@hZBVm,1eGI9d-R!YkqRS*U9NBf*Ki5"IhakHAKiHATmIAjrIhprIRe mHRPiGhGiHRYpIi+&L)Z0Mj'5NT+4Mif+KS&mG@jQAeC24Mdb*adB'53j9(12TlV (d026cmM!Z+qSSCZ@NSk+L)@#J(jmHRPjHATlIAjqIhprIRelHRPiH(KiHAYmIi' $KSQ,MBq3!*'4NC!!MSb)K(jhF'PJ@9"*3$8T(aNC)cK6FBfNYmA0dG$0aVqfVUH JQT@4MBU(K)+!IAYkHAKjHAYmIAjrIhpqIRalHRKiH(KjHRYpIi+&LBb2NC+5NT+ 4Mib)JhpjFQTM@e*,3cN[*4iG*6G3E)HHXX$*cFh+aEkhVUHKQj@4MSZ)KB1!IRa kHAPjHRYmIAjrIhpqIAalHRPiH(PkHhaqJB1&LBb0Mj!!N!#3!)q1M)U(K(pjFfa PA9C24cdc+L3L+6P2DB5EVVc&bX[)`lffVUHJQT@4MBZ)KS1"IhelHRPjHRYmIAj qIhjqIAalHRPjHAPkHhaqJ)+&L)U-MT!!N!#3!*!!Mik,L)4rHR0XC9jA8%P#1#m T*L`j6@H!PUQi`FE)aX+lY+fQS*U9NBk,L)D$JAppHhTjHATlI(eqIRprIRjpI(Y kHAPkHhapIi##K)D*Lif1Mj!!Mik0LSH%J(TeEQKK@P404$Xb+LFX18jRJ*DSYVr %aX6!ZE1XTCqCP*!!MBU)KB1"IhelHRPkHRYmIAjrIhprIRemHRTjHAPkHhaqJ)+ %KSQ,M)f0MBf0M)U)KB&mGh&VC&jB88P!0bmU+cG+BRZ4Sl+l`F2#[VLbUk@HQC@ 4MBU)KS1"IhelHRTkHRYmIAjqIhprIRemHhTkHATkHhapIi'$KBL,MBk2Mik0M)U (K)&mGh*VC&jA88T!0c!X-$Y0C(b4Sl#k[m'rZlD`UD1GQ*53!)b+Ki@$JAppI(Y kHRYlI(eqIhprIhjpI(YkHAPjHRYmIRq"Ji@)LSb0MSk1MBb+Ki5"I(GbE'CJ@P4 04$Xe-M9!8'9lMk#YYEZpZlLcVULLR*H6Mib*Ki@$JB"qIAalHhYmIAeqIhprIhj pI(YkHRPkHRYmIRq"Ji5'L)U,M)f0MBb+L)D#IRTdEfPMA9G34cmh0$Br6f0iM*f UXlLkZEHbVDHJQjD5MSb*Ki@$JS"qIAalHhYmI(eqIRprIhjpIAalHRTkHhapIS# #Ji@(LBU+LiZ,LiU*Ki5"IRTeEfTPB&Y96N8q1MNr6&pcKjLPVl@iZ,@aV+DKQjH 6Mib+L)D%JS"rIAalHhYlI(eqIRprIhjqIAalHhTkHRYmIAq"JS5'KiQ+Lib-M)Z *Ki@#IhYfF@aRB9a@6dFr1MT!6Q"dKjHNVE1eYE1[UU5IQTD5MSZ*Ki@$JApqI(Y lHhYlI(eqIRprIhjqIAalHRTkHRYmIAq!JS1&L)U,M)b-LiZ*Ki@#IhYhFQeTC&p D8da&3$j$6PpaJj+IU+kaXV#YU+1HQC@4MBZ*Ki@%JS"rIRemHhYmI(eqIRjqIRj qIAamHhYkHhYmIAk!JB1&KiL*LiZ,LiZ+L)D$J(ejG'pUC@"F9e"+480(8&eYISf DT+UZVkkVU+1HQTD5Mib*Ki@$JS"rIRemI(amIAeqIRprIhjqIAemHhYlHhapIRq !JB+$KBH)LBU+LSQ)KiD%JAjkGR*ZD@9KA&G46%P+8&YTH)H8RD@TUkZTTU+HQTD 5MSb+L)D%Ji&rIRemI(amI(epIRjqIRjqIAepI(amI(apIAjrJB1%KSH)LBQ+LSQ )Ki@$JAjlH(4`E'KNAeT86dY,8&TSGi@5Qk+RUDQRTD'GQC@4MSb*KiD%Ji&rIRe mI(amI(epIRjqIRjqIRepI(amI(apIAjrJ)+$KBD(L)Q*LBQ)Ki@$JApmH(4aE@P PB&Y@8Np29&eTGS52Q*qMTUDNSTqEPj53!)f,LBH'K)1"J(pqIAamI(epIRjqIRp rIRjqIAamI(amIAeqIi#"JS5&KSD(KiL)KiD&K)+!IAThFh"XD'4J@eG88eCGCh1 !Lj5ERk+MSU#GQTD6N!#0LiQ(KS5$JS&rIRepI(apIAeqIRjqIRjqIRepI(amI(e pIRq!JB+$KBD(KiL)L)H'KB1#J(jlH(9bEQYSC'"F@&CBA@9`I)H3!*DERk#JRTb CPT12MBZ*KiD%Ji+"J(pqIAepIAepIRjqIRjqIRjpIAepI(epIAjrJ)#"JS5&KSH (KiH(KS@%JS&rI(PfFh"XDQGMAeaD@PjQF(U%MC1BR*fGR*UBPC+2MBZ*KiD%Ji+ "J(pqIRepIAeqIRjqIRjqIRjqIAepIAepIAjrIi#"JS1%KBD'KSD'KS@$JS&rIAY iGA0`E@TRC'&IAf&QEACrL)k8Q*QDQTL@P*'2M)U)KiD%Ji+"J)"rIRjpIAeqIRj qIRjqIRjpIAepIAepIRjrIi#"JS1%KB@'KSD'KB@%Ji'!IRakGh4bEfaTCQ*JB'& QERCrKif5PTHBQ*D8NT!!MSb+L)H&K)1#JB"rIhjqIAepIRjqIRprIhjqIRjpIAe pIAeqIRq!JB+#Ji5&KB@&KB5%Ji+"IhjmHRKfG(&[E@PRC@4PD@pfIS5+Mj+8PC@ 8NT'2M)Z*KiD&K)1#JB#!IhjqIRjqIRjqIRprIhpqIRjqIAepIRjqIRq!J)'#Ji1 %K)5%K)5%Ji+"J(pqI(TiGR0aEfaTCfCRDQpfIB1*MC!!NT16NT'2MBZ+L)H&K)1 #JB'!IhpqIRjqIRjqIhprIhprIhjqIRjqIRjqIRjrIi#"JB+$Ji1%K)5%Ji1#JB& rIRelHAGfG(*[E@YTD@a`GRb#KiZ1Mj!!N!#3!)k0LiU)KiD%K)1#JB'!J(prIRj qIRjrIhprIhprIhpqIRjqIRjqIRprIi#!JB+#Ji1$Ji1$Ji+#JB"rIRemHRPhGR4 cF@pYE@pbGRZ!K)L,M)f1MBb,LSL(KS@%Ji+#JB'!J(prIhjqIRjrIhprIhprIhp rIRjqIRjqIRprIi#!JB'#JS+#JS+#JS+"JB"rIhjmHhTjH(GeG(*aFA*dGhYrJiD )LSZ,LiU*L)H'KB5$JS+"JB'!J(prIhprIhprIhprIhprIhprIhprIhprIhprIi# !J)'"JB'"JS+#JB'"JB#!IhjpIAalHRPiGhCeG(9fH(YrJB5'KiL)L)L(KS@&K)1 #JS'"JB#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#"JB'"JB'"JB' "J)#!IhpqIRemI(YkHRPiH(KjHRaqJ)+%KB@&KB@&K)5$JS+#JB'"J)#!J)"rIhp rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!JB'!J)#!J)#!IhprIRjqIAe pI(alHhYlI(erJ)'#JS1$Ji1#JS+"JB'"J)#!J)#!J)"rIhprIhprIhprIhprIhp rIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhjqIRjqIhprJ)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)!!!%*!!!%!!3!&!!!!S!! "J&%!!!!!!"3!!!!!!!"#&PEZLk-!!%)8!!"#&3!mJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhpqIRjqIRepIAa mI(amHhKhGhGiGh9dG(CkIAjrJ)'#JS+"J(jlHAKiHi##JS+#JS+#JS+#JS1"H') p)"dJ(b-R,$)f1MSh1$BY'`B!#!`1$`S$#KNR-cJk2N0)6P0DAQ&J99&CB@adGA9 fHAk&LBZ0N!#5NT+4N!#2MBU)L)Q0NC'4N!#3!*!!N!#3!*!!N!#3!)q2MiPkBe* 26Nj38eCDAQ"IAPpG98-`+5SV,#`Q)b`i3da38P9DAQ0RDfj`E'*LDh4qJi+#JiD -NT@AQCZGRCfFQjQAPC56PCQEQjZEQjZDQTUDQTUCQ*1#E&pF@PTFAf0QD@YUD@T SANXl0cJi1$Fa-6Y'89KDA@&PD@eaGAGiFQTZGhq)LiU,M)q9QTbHSD1NT+5MSU# HR*ZERU+LSU+LSD'KSD'JS+#JS*U(FQGPBf0NCfYZFA*bFA*`C&"$38"!3$ii1N9 3@Q"LC@KXF(4iHhemGA&hIiL2N!#3!*!!NT@DRk'MTDHTUDLSTU5LSD#JSkDQTUD QTU@PTD@PT+5NT*k-GfeUD'KUE("cGRGfGRGfD99+5%C'4N-p3%Y9Af9RDQeaG(K mIi"qGh9mK)f6Nj16PCQHSU5QU+UXV+ZVUDHPT+1NTkQTUDQTU+LSU+LRTkHRTk+ 4I(*[E'YYEh*fHATjHATkE9P16%T+5NC"4%jBBQKUEA"cGhYqJB*rH(KrKSq9PC@ 9PjUJSk@RUDZYVUfYUkQRTU@QUDZVUkZUUUUUUUQTUDQSU+@@J(CcEfj[FA4iHRa mI(amF&e58%e-5dK#49"CBfPVER*eHAarJB1"HAQ"L*'APTDAQ*ZJT+DSUUbZVkq ZVDZTTkDRUkfXV+bXV+ZVUkZUUUUUUDLEKATeF@p[FA9iHhamIAepFf"98Np06%P $48pBBQPXEh*fHAarJS1!HAQ"LC'APjHAQ*ZJT+DSUUbZX+q[VDZTU+HSUkfYVDb XV+bXUkZVUkUUUDQJM(eiFh"`FA0hHRapIAeqG@0A9&"168Y&4%e@B'KVER*eH(a qJ)&rH(L!LC'APjHAQ*UISkDRUDZYVkq[VDbUU+HSUkfYVDbXV+bVUkZVUUUUUUQ MNS*kGA&[F(*eHAYmI(apGfCC9&"06%T&3NP6A'9UE("cGRTmIS"qGh9qKiq@PjD @PjQGSU5QU+UXVUq[VDbUU+HRUUfYV+bXV+ZVUkZUUUUUUUQQQBKpH(*[Eh"cGRP lHhamH'YF9P*05dT'3%419f&SDQjaGAKkI(jpGh0jK)f9PTD@PTHDRk1PTkQVVDq ZVDbUU+HRUDbXV+bXUkZVUkUUUUUTUDQRRiq"Hh9`EQj`G(GjHRTlH@pK@9426%T (38"+8eaPD@a[FhCiHRamGh&fJ)Q5PT@9PCDBRD'MTDHTUkfZVDbUU+HQU+ZXV+Z VUkZUUUUUUDQTUDQSSjH*IhKbEfeZFA4hH(PkHA*PA&G46%T)3Me%69CJCQPYF(0 fH(TkH("aHS51PC58P*5@QCkKSk@RUDZYVDbUU+HQTUQVUkZUUUUUUDQTUDLSU+L RTCf2K(eeF'eYER"dGRGhH(4TAPP66NT(4$ip4NpBBQGUER&dGRKiGh"YG(k)NT5 6Nj18PTZISD1PTkQVV+bUU+DPTDHUUUUUUDQTUDLSU+LRTkHQTU+@LS*lFfpXE'e `Fh9eGR9XBPa@8%Y(48!l2NK3@f0QDQe`Fh9fGA&UEAH!Lj+5NT+5NjDERU#LT+D SUUZUU+DPT+@SUDQTU+LSU+HRTkDQTUDQTD5GN!#(JAPaE@YUE'paFh0dF'9I@e4 15NC$2$P!59*GBfCTEA"bG(4bE'K`HB11NC'4NC'6PTZHRk'MTDHTUULQTD5MTDL SU+LRTkHRTUDQTD@PTD@NSTQ,KB"hF'aUDQYZF(*bFQTJAPT568K%3$Ni3NT8AQ0 QDQe[FA*bEQGSFRZ'Mj!!N!#3!*!!N!#5PjZGRk'MTDHSU+HPT+1MTUHRTkHQTUD QTD@PTD5NT+5MRj1(K(jeEfYTD@YYEh"aEf9HAPK35dC#1c8j3NY@AQ*QD@a[FA& `DQ9UG(f)MSq2MSq3!*1AQTbHS++NTUHRTU5MSU1QTkDQTUDPTD@PT+5NT+1MSk' CM)@$I(0YDQKTDfeZEh"XB9eH@&"+4$mf-cY%69KHB@9SE'j[F'jRBfYeISQ0MBf 0MBq6PjQERCqKSk@RTk@MSU+MTDDQTD@PTD5NT+1MSk1LSU'GNB@%JAKaDfKSD'T XE@j[DPpGAPK358)j-63q4P"CA'"ND'YYEfpXC'0XGAq*M)Z,Lib2NjDBQTbHRk' MTD@NSU'KSk@PT+5NT+1MSk1LSU+LSD'IPiQ$JhjdEQPRCfKUDfaZEfPIA9pD8%F q-Lmi38T69eYJC'KVE@pZDf0MEAD!LBU+LSU-N!#6PCHBQTbHS++NT+1LSD'LT+5 NT+1MSk1LSU+LSD'KRjU0Ji1"HA*XD'GRD'PUE@p`D9pHB&T246FZ-ca%6P0@@f" ND'YYEfjUBf0ZGi#)LBL)LSf4Nj5@Q*QERCqKSk5MSD#KSk5NSk1MSk+LSU+KSD' KRjb4K)+$IR9ZDQGRD'PTDfj`F'KIAf"D6Mmb-6P!5Np59PYJC'KXEQpZD@*PF(L #L)H(L)U1NC+8PCHCQjfISD+MSU'JSD1NSk1MSk+LSU+KSD'KS*f6KS'$J(PaE'K RCfKSDQe`FR&RAepI@%Ni-cJq4de28PGEB'9TE'j[E@GLD(*kJiH'KSQ-Mj!!NC1 9PTLDR*kJSU1LSD#KSk1MSk+LSU+KSD'KS+#GPBL#JS&mG@eTCfGRCfPXEh*dF'9 HAPa53$Fk2N9,68p59eaKCQTYEfpYCQ0VG(f%KB@(LSf1Mj'5P*DBQTbHS+'LSD# JSD1MSU+LSU'KSD'JS*qGPSL"JS*qGfpVD'GRCfGUER&dG@eKA9a94cdp3%9,6%e 29&KHBfGVER"[Df4PEhGrK)5'LBb0MSq4NT5@Q*QERCqKSD'JS++MSU+LSU'KSD# JS*qGPBL"JS*rHA&XD@GRCQGUEA&eGR4SAPY@5d9%4%K-6%a1899DB'9UER"`EfK MDR0kJB5&LBU,MBk2NC+8PTLDR*kIS+'JS+'LSU+LSU'KSD'JS*qGPBH"JS+!Hh0 YDQKRCQGUEA&eH(G`BPY95dP-5de168e06e0BA@0SE'paF@ePCQphIB1'L)U,M)f 1N!#4Nj5@Q*UFRTqJSD#JSU+LSU+KSD'KS+#IR*+'JB+#JAadEfYSCfCRDQeaGAK jG@GE8dY-8P*58Np16Nj49PYKCQY[FA*`D@9XG(Z#KSL*LSZ-MBk3!*'6PCHBQTb HRk#JS+'LSU+LSD'KSD#JRjZ2Ji+#JS&pG@pVD@GQCfTZFRCjHRGV@e"+6PCB@&9 46dj18&4CAf9UER&cFQeQDA*iJ)H)L)Q+Lib0Mj!!NT19PjQERCkIS+#JSU+LSD' KSD#JS*kBM)+#JS+"IAC`DfPRCQGUER*fHATiEPa16&*BA9jB8e&26P"6@&eMD'e aFh0[CfG`Ghq'KiH)LBU,M)k2NC+8PTLDQjfHRjqJSU+KSD'KSD#JRjf9L)+$JS' "IAC`E'PRCQKVEh0hHATjF&e-6P9DB@0F9e048&"59eaLD'eaG(4aD@G[Ghk'KiH )LBU,M)f1N!#4Nj@AQCUFRCkIS+'LSD'KSD#JS*kENB@#Ji+#JRefF'aTCfGTE(" dH(TlHA"F6&&CA@4QB&T@8e&48eGFB@GYFA4eFfYSEhGqKSL(L)Q+LSZ0MSq4NT5 @Q*UER*kIS+'LSU'KSD'JS*kBLi1%K)+#JRafF'aTCfKUEA&eHAYlH'jD6e9FB@C QBejB99048eGFB@KYFA9fG'eTF(KrKSL(L)Q*LSZ-MSq3!*+8PCHCQjbGRU#KSU+ KSD'KS*qFNSD$K)5$Ji&mG("XD'GTDfpcGhTmHhCV@90CAf9RCf9J@PG88P4AA'& SEA&eGR4YDR&jJ)D(KiL)LBU,M)f1N!#4Nj@AQ*UER*kJSD+KSD'KS*qGPiZ%K)5 $Ji1"HR0[DfKSDQeaGAKkHhPcCPTBA@4RCfKSBeeC9P489eaLCfebGACdEQYcHS# 'KiH)L)Q+LSZ0MSq4NT5@Q*QER*fISD'KSD'KS*kEN!#&K)@%Ji1$IhKbE@TSD@a [FhGkHhYhE@9JA@&SD'KTD@CJ@eG99PKGBfKZFhChG@jYGAb"KSH(L)L*LBU,MBk 2NC+8PTHCQTZGRk'KSD'KSCqFP)L%KB@%Ji1#IACaE'PTDfjbGRPlHhPbDQKMB'G UD'KTDQGLA9PA9eTIC'P[GAGiG@p`H(f#KiL)L)L*LSZ,MBk2NC+8PTHCQTZGRk+ LSD'KS*fALi@'KS5%K)5"HR4ZDfTVEA&eHAYlHR9YE@eQCQTTD@PUDfPMAeYB@9a JC@YaGAGiGA"bHRq%L)L)L)L*LSZ-MBk2NC+8PTHCQTZGS++LSD'JRTL0KBD'KB@ %KB0pGR&XDQYYF(4iHRalGQpZFfpTD@TUDQTVE'TPB&aD@eeLCfebGRKiGA&eI)' 'L)L)L)Q*LSZ-MBk2NC+8PTHCQTZGS++LSD#HQSq'KiH&KB@&KB&kFfjVDfe[FhG jHhTfF'peG@pUDQYVDQYXE@YPB&eEA&pNDQpdGhPjG(*jIi1(L)L)L)Q*LSZ-MBk 2NC+8PTHBQTZHS+'KS*kDMiD(KiD&KB@&JhaeEfaXE@pcGRPlHhG`FAGkGfpUDfY VDfaYEfaQB&eGAQ&RE(&eH(TiFh9pJ)@)L)L)L)Q*LSZ-MBk2NC+8PTHCQTbISD' JRTU2KiH)KSD&KBD%IRGaEQaYEh*fHATkGh"bHAamGQaVE'aXE'e[F'aQB9pIB@9 UER0hHRYeFRQ!K)L)L)L)LBQ+LSZ-MBq3!*'6PCDBQCZGRk+KRTQ1KiL)KiD'KSD &J(KcEfeZF(0fHATkGh&cHhjrI("VE@eXE@eZF(&XCQ*JB@0REA*fHRajFhGqJSH *L)L)LBQ*LSZ-MBk2NC+8PCHBQTbHS+#HQ)f(LBQ(KiD'KiD#HR4`EQj`FhCiHRT fFA4mIi+!G@aXE@eYE@j`FR"UC@*LBfCVF(9jI(YeGAb#KSQ*L)L*LBQ+LSZ-MBk 3!*'6P*DBQCUGRk#HQ)f(LBQ)KiH'KiH%I(9aEfj`FR9iHRPfFR9pJB1#H@jXEQe YE@j[FA*ZD'4LBf9TER0hHhYhG(U"KBQ+LBL)LBQ*LSZ-MBk2N!#5Nj@@Q*QERTq HQ)k)LBQ)KiH(KiH&IhGcF'p`FR9iHAPfFR4pJB1$I(&XEQjZEQj[FA0aE'GNBf9 SE(&fHRYiG(Q!K)L+LBL)L)Q*LSU,M)f1N!#4Nj5@PjLDRCkGQT!!L)Q+LBL(KiH (Ki*kGA&[F(&dGhPjGh*dIB'$K(jbE'jZEQjZEh"bFfpTC@4NCfY`G(KkHA4iJ)5 )LSQ*LBQ*LBU+Lib0MSq4NT59PjLDR*fGQT'*LBU*L)L(KiH)KAjhFh&`FA0fH(P hFh0lJB5&Ih4YEQpZEQj[F(*dF@YRC@4QDQjcGhPjGAH!KBL,LSQ*LBQ*LSU,M)f 1Mj!!NT19PjLDR*kGR*5,LBZ+LBL(KiL)Ki0lGR*aFA0eGhKiG(*jJB5&JAGZEQp [EQj[F(&cFfjSCQ9QD'aaG(GiGACrKBL,LiU*LBQ*LSU,M)f1Mj!!NC18PTHCQjf GR*L1LBZ,LSQ)L)L)L)D!HA9bFA*dGRKiGA*hJ)1%JhP[EQp[EQjZEh&bG("UCf9 PCfTZFR9fG(CqKBL-LiU+LBQ*LBU+Lib0MSq4NT59PTLDR*fGQT+*LSZ+LBL)L)L )L)4qH(4bFR0eGRGfFR0mJS1$I(&YEfpZEQj[F(&cFQeSC@4QD'a`Fh9dG(Z$KiZ -LiU*LBQ*LSU,M)b1Mj!!NC18PTHCQjfGQjD-LBZ,LSQ)L)L)L)L$HhGdFR*dGRG hG(*iJB1%J(9ZEfpZEQjZEh"bFh&VCf9PCfTYFA0cFRL#KiU0M)U+LSQ*LSU,Lib 0MSq4NT59PTLDR*fFQT++LSb,LSQ)L)L)L)H"HhGcFR0dGACeFR0mJi1$HR"[F'p ZEQj[F(&cFfpTCQ9PD'YZFA*aFhk'LBf0M)Z+LSU+LSU,M)f1Mj!!NT18PTHCQjf GR*L1LSb-LSU*L)L*LBQ(JAYhG(0cG(9fG(&fJ)1$Ih4[F("ZEQjZEh"aFh*YD@C PCQKXEh&`F(H$L)b1MBb,LSU+LSU,Lib0MSq4NT19PTLDR*fFQj@-LSb-LiU*LBQ *LBQ(JAYhG(0cG(9eFR&jJB1#Hh&`F@pZEQeZEh"aFR&XCf9PCQKVEQpZF(b'LSk 1MBb,LSU+LSZ,M)b0MT!!NC+8PCHCQjfGR*U5LSZ0M)Z+LBQ*LBQ*Ki*lGh4cFh4 dFh"bI)+#J(G[FA&[EQeYEQp`FA*`DfGPC@CSDfeYEA1!L)b1MSf-LiU+LSU,Lib 0MSq3!*'6P*DAQCZGRCZBN!#+M)f-LiU*LBQ*LBQ(JRYhG(0cG(4bEh4qJS*qFfp aF'pZE@eZEh"`FR"XCf9PCQKUE'YXGS+*MBq1MBb,LSU+LSZ,M)f1Mj!!NC18PTL CQjfFQTH1LSf0M)Z+LBQ*LBQ*L)0mH(9dFh0cF@peIi+"I(*`FR"[EQeYEQp`F(* aE'KQC@CSDQYUE(Q%LSq2MSf-LiZ,LiZ,M)b0MSq3!*'6PCDBQTbGR*U9MBZ1MBb ,LSQ*LBQ*LBQ%IRPfG(4cFh&[Gi#"JATaFA*`EfjYE@j[Eh"bF@aSCQ9PCfPTD'e kKBU2N!#2MSf-LiZ,LiZ-M)f1Mj!!NT19PTLDR*fFQT@0Lik1M)Z+LSQ*LSQ*LBD !HRGeG(0bF'phIi'!HA&aFR"[EQeYEQj[F(&bEQPQC@9QD'KRE(Q%Lj!!N!#2MSf -LiZ,LiZ-M)f1Mj!!NT18PTLDQjfEQC@1Lik1M)Z+LSU+LSU*LBH#I(KeG(0bEfj fIi'!H("aFR"[E@eYE@j[Eh"bEfTRC@9QCfGQDhQ$LSq3!)q1MBb,LiZ,LiZ-MBk 2N!#4NT5@PjQERCZCPBf,MSk0M)U+LSU+LSQ*LB9qHRGeFh*[EA4pJ(piFA*cF@p YE@eYEQj[F(*`DfKQC@9QCQ9UH)+*Mj!!Miq0MBb,LiZ,Lib0MBk3!*'5P*@AQCU FR*U@MiZ1MSf-LiU+LSU+LBQ+L)*mH(CdFQpYFRarIhKaFR0aEfjYE@eYEQp`FA& YD'CPC@9PBfKfJBH0N!#3!)q1MBb,LiZ,Lib-MBk2N!#5Nj@@Q*UFR*UAN!#,MBq 1M)Z+LSU+LSU*LSU&IhYhGA0`EA"jIRjjFR*dFR"ZE@eYE@j[Eh"bF'YSCQ9PC'* QFhk'M*!!N!#2Mik0M)Z,Lib-M)f1Mj!!NC18PTHCQjbDQ*+-M)q1MBb,LSU+LSU +LSU)JhjkGR4aEQjfI(ejFh*dFh&[EQeYE@jZEh"aF@eTCf9NBf*NEhb$LSk3!*! !Mik0M)Z,LiZ-M)f0MSq4NT19PjLDR*UBP)f,MSk0M)Z+LSU+LSU+LSU(JAajGA0 [EA*kIATdFA4dFR"ZE@eYE@jZEh"bF'YSCQ4MB@&UH)#(M)k2Mik0M)b,LiZ,M)b 0MSq3!*'5P*@AQCZDQ*D3!)Z0MSf-LiU+LBU+LBQ*LSU'J(aiG(&YERClHR9aFh4 bF@pYE@eYE@jZEh&bEQTRC@0KB'9cIB1*M)k2Mik0M)Z,LiZ,M)b0MSq3!*'6P*D BQTZCPj1-Lik1MBb,LSU+LSU*LBU,LS9rHhGcEfe`H(TfFA*dFh*`EQeYE@eZEQp `FR&YD@CNBPpKE(L!KSZ0Miq1MBf-LiZ,Lib-MBf1Mj!!NT19PTLDQTL@MiU-Mik 0M)Z+LSU+LSU+LSZ+KApkGR*ZEA0jH(0aG(9cFA"ZE@eYEQjZEh&cF@aSCQ0JAf9 bI)+)Lif2Mik0M)b,LiZ,M)b0MBk3!*'5P*@AQCUCPj50LSk2MSf,LSU+LSU+LSU +LiU&IhTfF@eZGAPeFA*eG(*aEfjZEQjZEQp`FR0`E'KPBPjJDhCpK)Q,MBq2MSf -LiZ,LiZ-M)f1Mj!!NC+8PCHCQTL@NBZ,Miq0M)Z+LSU+LSQ*LSU-LS9rHR9`E@p fGh*`Fh9dFR&[EQjZE@jZEh"bFh"VCf4JA@*[HAq&L)Z0Miq1MBb,LiZ,Lib-MBk 2N!#4NT59PjQBPT51LBb2MSf-LiU+LSQ*LBQ+LSb+K(jjG'pYFRGeF(&dG(0bF'p ZEQjZEQj[F(*cF'YRBepHCR*kJ)D)Lif2MSf0M)Z,LiZ,Lib0MBk3!*'5P*@AQ*D 8NBU)MBq1MBZ+LSU+LSQ*LBU,M)U%IRKbEQpeH(4`FR9dFh*`EQjZE@jZEQpaFh4 aE'GMAepTG(Z"KSQ,MBq1MBb-LiZ,LiZ,M)b0MSq3!*+6PCH@P*+-KiQ1MSf-LiU +LSU*LBQ+LSZ-L)*mGR"[G(PjG("bGA4cFR"[EQjZEQj[F(&cGA*YD'4JB@YfI)+ (LBb1Mik0MBb,LiZ,LiZ-M)f1Mj!!NT19PT55MSH'Lik1MBb,LSU+LSU+LSU,MBb (J(TcEh0kHhTdF(0eG(0aF'pZEQjZEQp`FA4fG'jTC@"LERGpJiH+M)q2MSk0M)Z ,LiZ,Lib-MBk2N!#4Nj58NBk)JiH,M)f-LiU+LSU+LSU+Lib0Li4qGh&bHRepI(4 `G(9dFh&[EQjZEQjZEh"bG(CeF'YPB@4[H(k%L)U0Miq1MSf-LiZ+LSZ,Lib0MBk 3!*'6NT!!MSL#K)Q+Lib,LiU+LSU+LSU+Lib0LB&kFh"iIhprI(4aG(9dFR"[EQj YEQjZEh"bG(GfF@aQBQGbHRq&L)Z1Miq1MBb-LiU+LSU+LiZ-MBk2NC'1M)L"JBD )LBU,LiU+LSU+LSU+Lib0Li4pGR&hIi+"J(TbFR9eG(*`EfjZEQjZEh"aFh9hH(0 YCf4UGAb"KSQ-MSq2MSf0M)Z+LSU+LSZ,M)f1N!#3!)k,Ki"rJiD(L)Q+LiU+LSU +LSU,M)k0Ki"iFhCqJi5#IhKaFh9eFh&`EQjZEQj[Eh"bG(CiH(0YCfC[H(k$KiZ 0MSq1MSf-M)Z+LSU+LSZ,M)f1Mif+Ki"pJS@'KiH*LSZ,LiU+LSU,M)f1Li0kG(G qJiD&JAefFA4fG(0aEfjZEQj[Eh"aFh9hHRPdE@GUG(Z!KBQ-MSk2MSk0M)Z,LSU +LSU,Lib0MBZ*KAjlJ)1%KBD(L)U,LiZ+LSU,M)f1Li4lGAKrJiD(Ji"kFh*eGA0 aF'jZEQjZEh"`FR4fHAYjFfaTEhPqJiL,MBk1MSk0MBb,LSU+LSU+LSZ-MBU(Jha kIi+#Ji5&KiQ+LiZ,LSZ,M)f1M)9mGRQ!JiD)KB*qGR&dGA4bF'pZEQjZEfp`FA0 eH(TmHA*XEACpJSD*M)f0MSk1MBb,LSU*LBQ+LSU,LiL&JATjIS#"JB+$KBH*LiZ ,LSZ,M)f1M)CpH(b#K)H*Ki1!HR0bGA4cF@pZEQjZEfp`FA0eGhPmI(G`EA4mJ)@ )Lif0MBk1MBf-LiU+LBQ*LSU,LSD$IRKjIAq!J)'#K)D)LSZ,LiZ-M)f1M)CpHAq %KBH)L)@#IA9aG(9cFR"ZEQjZEh"`FA*dGhPlIAaeEh0lJ)5)LSZ-MBf1MBf-LiZ +LBQ*LBU+L)5"HhCjIAjrIi#"Ji@(LBZ,LiZ-MBf1MB9pI)'&KSL)LBH$IhGbFh9 dFR"[EQjZEh"`FA0dGRPlIAjkFh0lJ)1)LSZ-M)f0MBf-LiZ+LBQ*LBQ*KS0rH(9 jI(eqIRq!JS5'L)U,LiZ-MBf0M)9qIi5'KiL)LBH$J(TbFR9dFR&[EQj[Eh"aFR0 dGRPlIAppGR4lJB5(LSU,M)b0MBf-LiZ+LBQ*LBQ)K)&mGACkI(amIAjrJB1&KiQ +LiZ-MBf0Li0rJSH(L)L)LBL%JAYcFR9dFR&`Efj[Eh"aFR0dGRKlIAprHAClJS5 (LBQ+Lib-M)b-LiZ+LBQ)L)L&JAjiFhClHhYlI(eqJ)+%KSL+LiZ-M)f0LB1"KSL (L)H(LBL%JAYdFR4dFh&`Efp[Eh"aFR0dGRKlIAq!I(KpJi@)LBQ*LSZ-M)b-LiZ +LBQ)L)H$IhYdG(KkHRTlHhaqIi'$KBH*LiZ-MBb-L)1&LBL)L)H)LBL%JAYdFR4 dFh&`Efp[F("aFR0eGhPlIAq"IRTqK)D)LBQ*LSU,Lib,LiU+LBL)L)5!IACbGAP jHRTkHhapIi'$KBH*Lib-M)b+KS@*LSQ)KiH)LBL%JAYdFR9dFh*`F("`F(&bFh4 eGhPmIS#"Ihf"KSL*LSQ*LBU,LiZ,LiU+LBL)KS&qHA0cGhPjHAPjHRYpIi'$K)D *Lib-M)b*KSQ,LSQ)KiH)LBL%JAYdFR9dFh*aF("`FA&bFh4fH(TmIS#"J(q$L)Q +LBL)LBQ+LiZ,LiU+L)L(JhjlG(*fH(KiH(KjHRYpIi##K)D)Lib-LiU*LSb,LBL (KiH)LBL$J(TcFR9dFh*aF("aFA*cG(9hHAYpIi'"JS+'LSU+LBL)L)Q+LSZ,LSU *LBL%IhYeFA4hH(GhGhKiHRYpIi##K)D)Lib,LSQ,MSf,LBL(KiH)LBH#IhKbFh9 dFh*aF(&aFR0dGAChHAYqJ)'#JS5*M)b,LBL)L)Q*LSU+LSQ*L)@!I(GaFhGhGhG fGhGiHRYpIS##K)D)LSZ+LSb2MSb+L)H(KiL*LBD"IRGbG(9dFh*aFA&bFh4dGRG iHRarJB+#K)L0MSb+L)H(L)L*LBU+LSQ*KS&pH(*cGRGhGRCfGRGjHRapIS##K)D )LSU*M*!!N!#0LiL(KiH(L)Q)K)"lG(*eGA4cFR*bFR*cG(9fH(PlIS#"JS1'M)q 1M)U)KiH(L)Q*LBQ*LBD"IAKbFRChGhCfGAChH(PlI(erJ)1&KiQ*LBf5NBk-LBH (KiH)L)Q'JRjiFh0eGA4cFR*bFh0dGAChHAYpIi'#Ji5+N!#4MSb*KiH(KiL)LBQ *LBD"IAKcFhChGRCeGA9fGhKkHhapIi'$KBH)LBf6Niq-LBL(KSH(L)L)K)"lGA* dGA9dFh*bFh0dGAChH(TmIS##Ji1'MT14MSZ*KiH(KiL)L)Q*KS&pH(0cGRGfGR9 eGA9fGhPkHhaqIi'$KBD)MT56N!#0LSH'KSD(KiL)KB&qH(0cGR9eG(0cFh0dGAC hH(TlIAq"Ji1%Lj16Mif+L)D'KSH(L)L)KB"pH(0dGhGfGR9dG(9fGhKjHRYpIS# #Ji5'MT@8N!#0LSL'KSD'KiH)Ki*qHh9cGACeGA4cFh4dGAChH(PlIAq!JS1%L*' 9NSk,LBH'KSD'KiH)KB"pH(4eH(GhGR9eGA9fGhKjHATmIAq"JS1&M*@9NBk+L)D 'KSD'KiH(K(pmGR0eGRCeGA4dG(4eGRGiHAYmIS#"Ji1&MC@8N!#0LBH'KSD'KSH (KB"pH(4eH(KhGR9eGA9fGhKiHATlIAk!JB+%Lj5@NSq,L)H'KBD'KiH(KB&pH(4 dGhGfGA4dG(4eGRGiHATmIAq"JS1%Lj59NSq,L)H'KBD'KSH&JAjjGA9iH(KhGR9 eGA9fGhKjHRYmIRq"JS1*NTD8N!#-LBH'KB@'KSD(KB&qHR4dGhGfGR9dG(9eGRG iHATlIAk!JB+$L*+@Nj!!M)Q(KS@&KBD'KB&qHhCeH(PiGhCeGA9fGRGiHAPkI(e rJ)'#Kiq@PC'0LBH'KB@&KBD'KB&qHR9dGhGhGR9eG(9eGRGiH(PkI(jrJ)'#Kiq 9P*'0LBH'KB@&KBD&JRjlGh9iHAKhGhCeGA9fGhKiHATlI(jrJ)'&M*5@Niq,L)D &KB@&KBD&JAjlGR9hH(GfGA9eGA9fGhKiHATlIAk!JB+&MC59NSk+L)D&KB@&KBD $IhejGAGjHAKhGRCfGRChH(PjHRYmIAq!JB1*NC@9NBf*KiD&K)5&KB@#IhahGAG iH(GfGA9eGAChGhKjHAYmIAq!JB1+NT@6MiZ*Ki@%K)@&KB5!IAThGhPkHAKhGRC fGRGiHAPjHRYpIRq!JSD1Nj@6MiZ)KS@%K)5&KB0rIAPeGhPiH(GfGA9eGRGhH(K jHRYpIRq!JSL2P*54MBU)KS@%K)@&KB*qI(KfHATkHAKhGhCfGhKjHAPkHhapIi# "K)U4PC54MBU)KS@%K)5&K)"qHRGhHAPiGhCfGA9fGRGiH(PjHRapIRq!K)Z4P*1 2M)Q(KB5%K)@&K)"pHRGhHRTkHAKhGhChGhKjHATlHheqIi#"KBf5P*53!)b*Ki@ %K)5%K)&qI(KfH(PjH(GfGR9fGRGhH(KjHRYmIAjrJSL1NT55MSU)KS@%K)5%KB* qI(PfH(YkHAKiGhGhGhKjHATkHhapIRq!JSL1NT56MiZ*KS@%K)5%JRppHRGhHRT jH(GfGRCfGRGhH(KjHRYmIAjrK)Z3!*+6N!#-LBH&K)5%K)5$J(elH(GkHhTjHAK hGhGiH(PjHRTlI(eqIi#$LT!!NT55MiZ)KS@%K)5$J(jmH(GjHRTjH(GfGRCfGhG iH(KjHRYmIAk!KSb2NC+2LiQ'KB5$K)5%JhppHRGiHhYkHAPiGhGhH(PjHRTlHha pIRq"K)Z3!*+6NSk,L)D&K)1$JRppHhGiHRTkHAKhGRCfGhGiH(KjHATlI(eqJSQ 0Mj'4MSZ)KS@%Ji1%K)&qI(PhHAYlHhTjH(KiH(KjHRTkHhapIRq!JBD0N!#5Nj+ 1LSL'KB5$Ji&qI(PhHAYlHRPiGhGfGRGiH(KiHAPkHhapIi1+MBq4NBk+L)D%K)1 $K)5"IRajH(TmHhYkHAKiH(KjHATkHRYmIAjqIi'(MC!!NC+4MSU)KS5$Ji1!IAY iGhPlHhTjH(GhGhGhH(KiH(PjHRYmIAq%LSf2N!#3!)k,L)D%Ji1$Ji1!IAajH(T mHhYkHAKiH(KjHATkHRYmI(eqIi+)MBq4NT'1LiL'K)1$JRppHhKhHRYlHRPiGhG hGhGiH(KiHAPkHhapIi@,MBk3!*!!MSU)KS5$Ji1$JRppHhPiHRalHhTjH(KiH(P jHRTkHhYmIAjrJSH0Mj!!NC'2LiL'KB5$JRjmHhKiHRYlHRPiGhGhGhKiH(KiHAP kHhapJ)@+M)k2Mik,L)D%Ji1$Ji*rIAYjH(YmHhYkHAKiH(KjHATkHRYlI(eqIi' 'M)k3!*'4Mib*Ki@%Ji*qI(TiH(YmHhTjH(KhGhGiH(KiH(PjHRYmIB#&LSb0MSq 1M)Q'KB5$Ji1#IhelHAKlI(alHRPjH(KiHATkHRTlHhapIRq"KSZ1Mj!!NC!!MBU )KS5$JRjmHRKiHhalHhTjH(GhGhKiH(KiHAPkHhYmIi5*M)f1Mik-LBH&K)1$Ji1 !IAakH(TmI(YkHRPjH(KjHRTkHRYlI(eqIS#&LSf2N!#3!*!!MSZ)KS5$JRjmHRK iHhamHhTjH(KhGhKiH(KiHAPkHRYmIi5*Lib0MSk-LSL'K)1$Ji1!IAakH(TmI(a lHRPjH(KjHRTkHRTlI(apIS#%LBb1Mj!!N!#2MBU(KB5#IRakH(KkI(alHRPiH(G hH(KiH(KiHAPkHhYqJiL+Lib0MSf,L)D%Ji1#JS&qI(YjHAYmI(YkHAPiH(PjHRT kHRYlI(eqIi+(Lif1Mj!!N!#1LiL'K)0rI(YiGhTmI(YkHRPiH(KiH(KiH(KjHAT kHhf#KiQ,Lib1MSb*Ki@%Ji1$JRpmHhPjHhamHhYkHAPjHAPkHRTkHhYmI(eqJ)@ +M)k2Miq2MBU(KB5!IAYjGhPmI(YlHRPiH(KiH(KiH(KiHAPkHhb!KBL+Lib-MBb +L)D%Ji1#JS"pI(TjHRamI(YkHRPjHAPkHRTkHRYmI(eqIi+)Lif1Miq2MSb*Ki@ #IRakGhKlI(alHRTjH(KiH(KiH(KiHAPkHRYqJiH*LSZ-MBf,LBH&K)1#JS&qI(Y jHAYpI(alHRPjHAPkHRTkHRYlI(epIS#&LSb0MSq2Mik,L)D%IhalH(KkI(alHhT jHAKiH(KiH(KiH(PjHRYmJBD)LBU,M)f-LSL'KB5$JS+!IAakHATmIAalHhTjHAP jHRTkHRTlHhapIRq#KiZ-MBk2Miq0LSL'JAelHAGjHhamHhTkHAPiH(PiH(KiH(P jHATlIS1(L)Q+LiZ-LiQ)KS5$Ji+"IhalHRPlI(amHhTkHAPjHATkHRTkHhYmIAj rJiL,M)f1Miq1MBU)K)"pHhKiHRamHhYkHRPjH(PjH(KiH(KjHAPkI)'&KiL*LSZ ,M)Z*Ki@%Ji+#JAjmHhPkI(epI(YkHRPjHATkHRTkHhYmI(eqJ)@*Lib0MSk1MSf +Ki0rI(TiHAYmI(YlHRTjHAPjHAKiH(KjHAPkHhf#KSH)LBU+Lib+L)H&K)1#JS" pI(TjHRepIAalHRTjHATkHRTkHRYlI(epIi+'LSZ-MBk1MSk-LSD#IRajH(TmI(a lHhTkHAPjHAPjH(KiHAPjHRYrJiD(L)Q+LSZ,LSL(KB5$JS&qI(YkHAYpIAamHhT kHAPkHRTkHRTlHhapIRq$L)U,M)f1MSk1M)Q&JAelH(KkI(amHhYkHRPjHAPjHAK iHAPjHATmJ)5'KiL*LSU,LiU*Ki@%Ji+!IAalHATmIAemHhYkHRPkHRTkHRTkHhY mIAk"KBQ+Lib-MBk1MBZ)K)"pHhKjHhamI(YlHRTjHAPjHAPjHAPjHATlIB'&KSH )LBQ+LiZ+LBH&K)1"IRalHAPlIAepI(YkHRTjHRTkHRTkHRYlI(erJiH*LSU,M)f 0MBb+Ki0rI(TiHAYmI(alHhTkHAPjHAPjHAPjHAPkHhf#KBD(L)Q+LSZ-LiQ(KB5 #IhalHRPkIAepI(alHRTkHRTkHRTkHRTlHhaqJ)@)LBQ+Lib-MBf,LBD#IRakH(P lI(amHhTkHRPjHRTjHAPjHAPkHRYqJS@(L)L*LSU,M)b+Ki@%JAemHRPkI(epIAa lHhTkHRTkHRTkHRTkHhYmIi1'L)L*LSZ,M)f-LSL&JAjmHRKkI(amI(YlHRTkHRT kHAPjHAPkHRYmIi1'KiL)LBU,Lib-LSH'JhpmHhPjHhepIAamHhYkHRTkHRTkHRT kHRYmIS+&KiL)LBU+Lib-LiL'K)"pHhPiHRepIAalHhTkHRTkHRTjHAPkHRYlIB# %KSH)LBQ+LiZ-M)Q(K)"pHhPjHhepIAamHhYkHRTkHRTkHRPkHRYlIB#%KSH(L)Q *LSZ,LiQ(KB0rI(YjHAYpIAemHhYkHRTkHRTkHAPkHRTlI(f"KBH(L)Q*LSZ-M)Z *KS*qI(TjHRapIAamHhYlHRYlHRTkHRPkHRTlIB#%KBD(KiL)LBU+LiU)KS5"IAa kHATmIAemI(YlHRTkHRTkHRPkHRTlHharJiD(L)L*LSU,M)b,L)0rIAYkHhapI(a mHhYlHhYlHRTkHRTjHRTlI(q$KB@'KSH)L)Q+LSQ)KS5#IhalHRPlIAepI(alHRT kHRTkHRTkHRTlHhaqJB@(KiL*LBU,M)b,LS@"IRYkHhamI(amHhYlHhYlHhTkHRT jHRTlI(q$K)@&KSD(KiL*LBQ)KS@$J(emHhPkI(epIAalHhTkHRTlHRTkHRTlHha pIi1'KiL)LBU+LiZ,LSD#IhalI(epI(amHhYlHhYlHhYkHRTkHRTlI)#$K)5&KBD 'KiL)LBQ(KS@$JAjmHhTkHhepIAamHhYkHRYlHRTkHhYlHhapIS+&KiL)LBQ+LiZ ,LSD$J(emIAepI(amHhYlHhYlHhYkHRTkHRTlIB#$Ji5%KB@'KSH(L)L(KB5$JS" pI(YkHhepIAemHhYlHRYlHhYlHhYlHhamIS'%KSH)LBQ+LSZ,LBD%JAjpIRjpI(a lHhYlHhamHhYkHRTkHRTlIB'$Ji5%K)@&KSD(KiH'KB5$JS"pI(YkHRapIAemI(Y lHhYlHhYlHhYlHhamIAq$KSH)L)Q*LSU+L)@%JRpqIhjpI(alHhYlHhamHhYlHRT kHRTmIS'#Ji1%K)5&KBD'KiH'K)1$JS&qI(YkHRapIAemI(YlHhYlHhYlHhYlI(a pIAq#KBH(L)Q*LSU*KS@%JS#!J(pqIAalHhYlI(amHhYlHRTkHRYmIi+#Ji1$K)5 %KB@'KSD&K)1#JS&qI(akHRapIAepI(alHhYlHhYlHhYmI(apIAq#KBH(L)L*LSU )KB5$JS'"JApqIAalHhYmI(amI(YlHhYkHhYpJ)+#JS1$Ji5%KB@&KSD%Ji+#JS& rIAalHRaqIRepI(alHhYlHhYmHhamI(apIRq#KBD(L)L*LBQ(KB5$JS1#JApqIAa mHhYmI(amI(YlHhYlHharJB+#JS+$Ji1%K)@&KB@%Ji+#JB&rIAalHhaqIRepI(a lHhYlI(amI(amI(epIRq#KBD(L)L*LBH&K)1#Ji5$JB"qI(amHhamI(amI(YlHhY lI(k!JB+#JS+$Ji1$K)5&KB5$JS'"JB&rIAalHhaqIRepI(amHhYlI(amI(amI(e pIRq#KBH(KiL)L)D%Ji+#K)@$JB"qIAamHhamI(amI(YlHhYmIAq"JB'#JS+#Ji1 $K)5%K)1#JB'"JB"qIAalHhaqIRepI(amHhYmI(amI(amIAepIS##KBD(KiL)KS5 %Ji+$KB@$JS"qIAamI(amI(amI(YlHhapIi#"JB'#JS+#JS1$Ji5%Ji+"JB#!J)" qIAalHheqIRepI(alHhYmI(amI(apIAeqIS#$KBD(KiL'KB5$JS1%KB@$JB"qIAa mI(amI(amI(amI(aqJ)'"JB'"JS+#JS1$Ji1$JS'"J)#!J)"qIAalHheqIRepIAa mI(amIAepIAepIAjqIi'%KSH(KiH&K)1#JS5&KB5$JB"qIAepI(amI(amI(amIAk !JB'"JB'"JB+#JS+$Ji1$JB'!J)#!J(pqIAalI(eqIRepI(amI(apIAepIAepIAj qIi'%KSD(KS5$Ji+#K)@&K)5$JApqIAepI(amI(amI(apIS#"JB'"JB'"JB+#JS+ $Ji1"JB"rIhq!J(ppIAamI(jqIRepI(amI(apIAepIAepIRjrJ)+&KSD'K)1$JS+ $K)5%K)1#J(pqIRepI(amI(amI(eqJ)'"JB'"JB'"JB'#JS+#JS'!J(prIhq!Ihj pIAamIAjqIRemI(amI(epIAepIAeqIRprJB1&KS@%Ji1#JS1%K)5%Ji1#J(pqIRe pI(amI(amIAk!JB'"JB'"JB'"JB'#JS+#JB#!IhprIhq!IhjpI(apIRjqIAepI(a pIAepIAepIRjqIRq!JS5&KB5$JS+#Ji5%K)5$Ji+"J(pqIRemI(amI(apIS#"JB' "JB'"JB'"JB'"JS+"J)"rIhprIhprIRepI(apIRjqIAepIAepIAeqIRjqIRjqIi# "Ji@&Ji1#JS+$K)5%K)1$Ji+"J(pqIAemI(amIAerJ)'"JB'!J)'"JB'"JB'"JS' !J(prIhprIhpqIAemI(eqIRjpIAepIAepIRjqIRjqIRjrIi'$K)5$JS+#JS1%K)5 $Ji1$JS+"J(pqIAemI(apIAq!JB'"JB#!J)'"JB'"JB'"JB#!IhpqIRprIhppIAe mIAjqIRjpIAepIAeqIRjqIRjqIRprJ)+%K)1#JS+#Ji5%K)1$Ji+#JS'!IhjpIAa mI(epIi#"JB'"J)#!J)#"JB'"JB'"JB"rIhjqIRprIhjpIAamIRjqIRepIAepIAj qIRjqIRjqIhq!JB1$JS+#JB+$K)5$Ji1$JS+#JS'!IhjpIAapIAeqJ)'"JB'!J)# !J)#"JB'"JB'"J(prIRjqIhprIRepIAepIRjqIRepIAepIRjqIRjqIRjrIi#"Ji1 #JS+"JB1%K)1$Ji1#JS+#JB"rIRepIAepIAk!JB'"JB#!J)#!J)#"JB'"JB'!J(p rIRjrIhpqIAepIAeqIRjqIRepIAeqIRjqIRjqIRjrIi'#Ji+#JS'"JS1$Ji1$Ji+ #JS+#J(pqIRepIAepIRq!JB'"J)#!J)#!J)#"JB'"JB'!IhprIRprIhjpIAepIAj rIRjqIRepIAjqIRjqIRjqIRprJ)+$JS'"JB'#Ji1$Ji1$JS+#JS+"J(pqIAepIAe qIi#"JB'!J)#!J)#!J)#"JB'"JB#!IhprIhprIRepIAepIRpqIRjqIRepIRjqIRj qIRjqIhq!JB1$JS'"JB'#Ji1$Ji1#JS+#JS'!IhjqIAepIAjrJ)#!J)#!J)#!J)# !J)#!JB'"JB#!IhprIhpqIAepIAeqIhjqIRjqIRjqIRjqIRjqIRjqIhq"JS1#JB' "JB+$Ji1$JS+#JS+#JS'!IhjqIAepIAjrJ)#!J)#!J)#!J)#!J)#!JB'"JB"rIhp rIhjpIAepIAjrIhjqIRjqIRjqIRjqIRjqIRjrIi#"JS+"JB'"JB+$Ji1$JS+#JS+ #JB#!IhjqIAepIRq!J)#!J)#!J)#!J)#!J)#!JB'"JB"rIhprIhjpIAepIAjrIhj qIRjqIRjqIRjqIRjqIRjrJ)'#JS'"JB'"JB+$Ji1#JS+#JS+#JB"rIhjqIAeqIRq !J)#!J)#!J)#!J)#!J)#!JB'"J)"rIhprIRepIAepIRprIhjqIRjqIRjqIRjqIRj qIRprJ)'#JS'"JB'"JS+$Ji+#JS+#JS+#JB"rIRjqIRjqIhq!J)#!J)#!J)#!J)# !J)#!JB'"J)"rIhprIRepIAeqIRprIRjqIRjqIRjqIRjqIRjqIRprJ)+#JB'!J)# "JS+#JS+#JS+#JS+"JB"rIRjqIRjqIi#!J)#!J)#!J)#!J)#!J)#!J)'"J)"rIhp qIAepIAeqIhprIRjqIRjqIRjqIRjqIRjqIhq!JB+#JB#!J)#"JS+#JS+#JS'"JB+ "JB"rIRjqIRjqIi#!J)#!J)#!J)#!J)#!J)#!J)'"J)"rIhpqIAepIAeqIhprIRj qIRjqIRjqIRjqIRjqIhq!JB+"JB#!J)#"JS+#JS+#JS'"JB'"J)"rIhjqIRjqIi# !J)#!J)#!J)#!J)#!J)#!J)#"J)#!IhpqIAepIAjrIhprIRjqIRjqIRjqIRjqIRj qIhq!JB'"J)#!J)#"JS+#JS+#JB'"JB'"J)"rIhjqIRjrIi#!J)#!J)#!J)#!J)# !J)#!J)#"J)#!IhpqIAepIAjrIhprIRjqIRjqIRjqIRjqIRjrIhq!JB'"J)#!J)# "JS+#JS+"JB'"JB'"J)"rIhjqIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp qIAepIAjrIhprIRjqIRjqIRjqIRjqIRjrIhq!JB'"J)#!J)#"JS+#JS+"JB'"JB' "JB"rIhjqIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhpqIAepIAjrIhprIhj qIRjqIhpqIRjqIRjrIhq!JB'"J)#!J)#"JS+#JS'"JB'"JB'"JB"rIhpqIRjrIi# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhpqIAepIAjrIhprIhjqIRjqIhpqIRjqIRj rIhq!JB'"J)#!J)#"JB+#JB'"JB'"JB'"JB#!IhpqIRjrIi#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J(pqIRepIAjrIhprIhjqIRjrIhprIRjqIRjrIhq!JB'"J)#!J)# !JB'"JB'"JB'"JB'"JB#!IhprIRjrIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(p qIRjpIRjrIhprIhpqIRjrIhprIhjqIRprIhq!J)'"J)#!J)#!JB'"JB'"JB'"JB' "JB#!IhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIRjqIRjrIhprIhp rIhprIhprIhpqIRprIhq!J)'"J)#!J)#!J)'"JB'"JB'"JB'"JB'!J(prIhprIhq !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIRjqIRjqIhprIhprIhprIhprIhprIhp rIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'!J(prIhprIhq!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)"rIhjqIRjqIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!Ihq !J)#"JB'"JB'"JB'"JB'"J)"rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !IhpqIRjqIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!IhprJ)#!JB'"JB'"JB' "JB'"J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(pqIRjqIhprIhp rIhprIhprIhprIhprIhprIi#!J)#!J(prIi#!J)'"JB'"JB#!J)'"J)#!J(prIhp rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhjqIRprIhprIhprIhprIhprIhp rIhprIi#!J)#!J(prIhq!J)#"JB'"JB#!J)#!J)#!J(prIhprIhq!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)"rIhpqIRprIhprIhprIhprIhprIhprIhprIhq!J)#!J)" rIhprJ)#!JB'"JB#!J)#!J)#!J)"rIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!IhprIRprIhprIhprIhprIhprIhprIhprIhprJ)#!J)"rIhprJ)#!J)#!J)# !J)#!J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhp rIhprIhprIhprIhprIhprIhprIi#!J)#!IhprIi#!J)#!J)#!J)#!J)#!J)#!J(p rIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIi#!J)#!IhprIi#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIi#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)# !J(prIhq!J)#!J)#!J)#!J)#!J)#!J)#!J(prIi#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J(prIhq!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhp rIhprIhprIhprIhprIhprIhprIhprIi#!J(prIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhp rIhprIhprIhprIhq!J(prIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)" rIi#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhq !J(prIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ii#!J)#!J)#!J)# !J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihq!J)#!J)#!J)#!J)#!J)#!J)"rIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J(prIi#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhq!J)#!J)# !J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!Ihp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!Ihq!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)!!!%0!!!%!!3!&!!!!S!!"J&%!!!!!!"3!!!!!!!"$&PE ZLk-!!%-8!!"$&3!mJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!Ihq!Ii#!J)"rJ)#!J)#!J(q!J)"rIhprIhprIhprIhprIhp rIhq!IhprIhprIhprIhprIi"rJ)#!J(q!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB# !J)"rIi#!J)#!J(q!JB#!JB'!J)#"JS'"JB'#JB'"JB'"JB'!Ii'!Ii"qIi"rIhp rJ(prIhq!Ihq!IRk"J(prJ)"qJ)&rIi"rIi"rJ)"rJ)&rIRprIRjrIhpqIi"rJ)" rIi'"Ii#"J)#!J)"mIS4pH)"rHhemHhepHhTqIAYqIAk!IAf"JAjqJ(prJ(jqJAp rJ(q!J(jrJ)"rIi"rJ)"rIRjqJ)"qIB'!Hhk$J(aqJAppIRq!J(eqJ)"rIhjrJ)# "Ihb#KRYpKi&pJS#!K(pqKSCrJ)@%JS&rJB&pJS9pIB@&IAb!K)*pI(q#JAf"KAp lJBU!GB+(Hhb'J(f&Jhf"JRk!K(pkJBCiI)f!GB'(K(q"KAPkK(TqL(KeLiYcFSU *G(q)H(b&Ii1#G(H1MRCbJB'%M(aTHTH-DhQ5I(H0IR+(KA0rM(PcIhk'L(GcHBH 1G(',J('"JhGmLRT[KRTfN!"pFi4kI)0mIAafJBClIS4pJB4pKiTkIB@*MhaZIBU -I'jrLi&cFRamJRe`LBP[HiU*H@k%QS&VK*L+EhfEJ'f(MB&iFAD,LA"jI@q0P'K bQiP`K*5)JBH%LBejHC@9Df@JS9YMPB4UG)'"IB&pFAq6JR+(M(+#RS&aMT4rI)k *H)#%GAb#GhD!IfYlQR*NRBGIMTTVGTk*GC!!LA#2RR"ZPB*UJSC[GiKbG)afCS1 8Hf4qQ)CaJ*H)HC'CJ(Q'MB*fIB&dGAecGACbH@pTG)5+E'Q3!)YlMSb$JS#0N!# &IAD'N!"eFBGjEAYcF(pUB)1$FhTmK)GpL*+0LB#(PjH(G)@8JAaeDhjfBh9dCQe mKQeBKjpjFAU(R*1"L*',M*Z@HhQ(JRq%G@&XK(GID(KlHhT`GT@'ECLSGR@XVS& qQC@+K(Z2Lf*VHQpfE&plI'CbK(aXGiq-IAf-R*f3!)Z9Q)Z-L(Z'MB*XA(#$GQ9 NF(TfI(pbDA@9PATpP+1@J*UUJ@b#R*PZBhpjDR4dDQp`GBTe8AQMG&L,RB+%QTk 2LBq+L)U#JieeD)Cf8'U-HeGMJ(GZEh9pGA#'RiefMDLGIRf6Lhf3!*&aERajF'j XEhTfE(CfERGbGi0aHTZ5K*DGN!"rKjf'HjL-FRC`FApbDA&pH9eYL@pKH(KVJjD "KU+9LTL5J)LINAQ0KPejS(eEFSCmGR4RCRKfB'b0K(L8Qib@QBZ*LSH-NiplE)@ 1ER@5Gf+!HPpaFeaUIR"`N!#@JSqLN!##N!#6Kj@BJBH(H(q,L(KeI'pVH@YCA@C jFf&rR)q%N!#GNi5$LD'FG)#IKh12NAYpHfpSF(0E@QYHCBPpDC+NL(k2PRGpUjK pNS*bS*p[HTKk9Qk$CP"GEQ"AH)YhFSDESS9YKk+MMhQ-QBk8LAZHS@PKIR9TE&Y 1@f0`KAjUFjfVJ'b3!*b6PBarKD5JHC1hKQ5%K'*QD%a@Ef*GGiPkGT1@H)1KNB1 9QBk6S*'B[TGbSip(CT&D2fPF3h@&AR1@FQQAQQjZVV4cGkZTNTkfU)U"K)&cCQ0 F9&9FC'KZHRjUCiq3!'9rVj4jN!#HT,5PMDh(Le5)U&`pEfP#@@YHFhY9AT9r9iL CFiZNKSqrV)HhcTU2Q(TaJRP33&aMC'Y4AS"TAQG[K(GmR)0lT,+PRUh%UiZ6M(e hCeY989KRDPYADA"L@(D+EA@@MRqJ`jkAeX@EVjZ&LRGf@$TTFdG2DQKE@@9DAhe bFiU"MV@JN!$*eUHZc*YYKjCk9dY@DR&66QaM694TEPYQLhj`Sl@ATFV5ZE+hT*1 )IATS69TfC8T2Bej29eC9CAKfBhqVTCbUaFc$bl'BPiD(L@C2BQpI9PK@68K@A99 5BS0eAk$"QD6%dZ'mP,'cMAjeE@*QFf**8ej(29*94e0kG9"dUU5UZ,6@jVbNVlU 9FSGbAi*R2PYM8$mV6Q4'6P9FGhH-Tk5c[GMXVU$AYB1)I(KeC'PI89K006e(89X i4RaXFCLGVF62h-r"aV+QT)"cKS"Q@@4U6$ir0%G8-M9HC@9fQ+QUa0,1f-V!`k+ CPR4qIeeeIN)e@88M3PSi+8pZDhLBSV[CbF6HcmE#NTUVIQKhIR0H66dl46%Y8$3 H@faHL+5DYq65Zq$SZl1bQ*H*DA+$G%Xp6NFX)N&*)cGKB@4qTX2!aG21iH$%Z)b 8[RT'G(YQB$`U26XR,$3S5R"@G+UYaq(FdZ$dflLVSCf2A&"fE%3c,bJX3$)E,8a +8(D'PFRB[0([f0RU[DZhQj9iBiec9P8Z-8Bc("NX1#dd@(f8Ql(#[Z(cd-r0Ylq eJQq6QQ&1CN3X6MiB-6dV1NpULk1XUEhFiF@qdlbHRi"bJR"dG%a19P0F0b&,8$j $5(5IPTbVY-l8a,bmZDfaQR@@TA9aH&T)@9`K&dFX%6G(9B5-K+R)cXh0cFR&X+f YLBfCJ(TT8Pe0068k4LNJ9PGFMSqAXlR2[kE&[U1JRTk+KTb%H)*cF8i`683Y,bi [0f@%BhZcVE#p`mh"aFQ`[VH5Y+KaI'a155dS+KFE*#ip8S"qJX6'SVE+cF1MX,b *Kkk6FBCq8&9N5$Y)589$9Q4QJBq8Tk@LXE#VSkLRPD5DKCZEL)*M594'1cdH+$i Y8'pKH*QPUlV9`lAIhm#cVmHVIUUJ8P&H0L-V&4Fr,aK+HAQ"PTZNZEbjYVZjTkq aS+#6P+1"Bf0G@8)p68&(5%aeI("hKjkDMjHQ[E1JTkbkXDDmPeeeI$id65J826i V5fKJHCk@P+h+aVE5flLZb-fSN!#PNeTH5b9#1K)N1640DQeRFC!!PBQLZ*kC[X# QXF5`UE@PNT&qA&CM6bBm@5ibCP*3H@9@JU1@Ll$&VlRFem$"Xk@4GRC1+dJk&bF q2c93C@'1MfHIekbCb1+lS-MBXTUGMfKRBMT*@b!XEP%kD(&8E)YXDU1GFC[#S*U jYUHecl"pNTG`DQaG6da69dC0CNa1EP4SViPNXm'G[-qiUm2#LSb2A9KH98%hB9B TA)03AC0hCTbeMSr-Zi1[`D'`SSClFS&f9NYAC'9VA&4lGPCKE("ZFT+4JTbPQk' EXG+YLCUPNheVHAa18QTA9f*&,9*V9@5'HB5dZDQ`YlV!Y*D5T)9VE9pK@&*939e b9eYICA4dN!#VQSkF[VD0TVb0JT1-M(&JHQYLEePTENYNE9"+8@jlEAkDQC+KXD5 Vf,5([-+@Tk&`F(KK6e&,2Mib06e)AeC`RC!!M,'qT+M0[SqXaj@1U)alGh&V8R9 e3'YV0QD)C@1,N!"THk'&JT*iJk19MCHJRi#3!+D!G)4mEPpB8dYMDNPLLfpMMj0 qQlqQR,Hca-HMRj!!L)pL9Qe@3cNk6$p(A%YaRA4`Tjf&UUf3!++XT,HhRSb6S(a IJTPi@'CVAhCY8'YVAR4Y9f4rG'*rQBqCYDfPZl+5KBkHLPp@G'%mAQ0$6ejaC&5 3!*U&RTQTZVEIbjHcUiZ(CQ&cAdp+4dp09Pj4CRGQG)*fJjq'E+qlL,I)RTqKQ)U ,Q)CpK@pkM'aN@NaUDP064Q5&APk+N!#9Ul1USlUQJT+-Ghq$CeahG@KV9PeqFQU #M(q3!,+DL+qiSk#6K)b!@P&VF&CFG@9RKhKSIh0ZLB*lHhU4LS#@N!#5UD#&L+# 9GB1AKS11Ji#1FPpkANYQ8e9aA@'$HR58R*ZAN!#VX*H'J)L@NRPaMjKaCQjYG@C VGQ"pPA+&PhQ1Rhq%Nh9pRRYFEi15I@f2JQH*K'GYGhGJCiaeFjTqFD+EKk+8LU@ DJiHAQBZ"HS+2ENpH9Pjc6%e`DfTmJh5*Rhk'YCTrSjL'Sj@$Piq(PjChEhTZGh& NI(akG'#!LQThF@L2Kh+#IB@3!)H'L*Q@JT!!JA@&F('$CA@KDQ@JIh'3!)1!LBH 0LTfKJSf,FibTMeKIK@92D9p6EhKGDSGcGiL"J)@JTSQ@[UQ3!+bHMU'NMhQ-F6j `INpKD'GE6Bq!5RpX8+16AjH[P*!!SjerNkU*Lj!!FR*LCSTbAA+*J@U(NA#+Nf* YR*@2XijRRU'#L)"bE(ab4e0[9&4[FA&MBT'+F*&dGUf0T-fiUil%fAQJ`S@'EPY Y@9GF8dj)@eP1F&j,J(*8J+'ENU5kXjqEREUmIB'EI@TmM&eCNh*1J)YT8fL0CNL ,VipqMkfINCq4S+P[Dijk6dq0E6"fDNChBPTlHfYHQVq'Vp+@XFR!b)qFY9U'Y%* 5INj188p*A(p+-h&k@&Z!Q)@)VTq)RV5pRSZMTD5)G*q5C(')HQf(GN&GK(9PAfb #JRq%K*HUQif+Pk9eBSGZA@9(@PT)LAp%DiQ%N!#9P*He[k@bXUc-XhGrUCYH6Qp K05a5HPNpF(&CIhGLHAPiJjPlAm#jE,'hKlh"N!#5QiarJhGNNSY,E(pIBfeZ8cp ZFeb,QikNRT+VZCPcHSCq9bKDN!"C2(''GiZJNSDZVA5DXBqYXBqIPhZ4N@0CAdF rAf-dCDeRAkUPJAfCKeGbI9P[Lj!!N!#&TEHSX+1IU(aRHS@)D@&fDfalFR"XA@4 hE&H!YCD*[lQ5U+*cGQa35c8mAQ"QFS#HTk2%c*LF[Tb"L)Q8MfTGHiG[AeYHD&T -Bi#-P)k8TS1"ThCGIfe-5PpkFAUBMkM4XTkcXTf%J(T2B)9H6h"dD(YmAAkdI81 *`ijhP)b8T(K6D(TL5P"15@q,Gh@efkUak,0cVGCf1hGqA'05@B1"Bf'AP9aaL(Y qIRpeHDZL8(DM5'QJ5&+6JAQ6UCZEi-jiR,f'GATN8&YQ4%@+P&acTj&iKT1$Kjq $Eib-KSTaEReI8QpN@PjIKi0KSHA&QU62[(Z(N!"bDfC95Qb+FRfCMi9mMijMISa RC@4[M)KL5h@$2NZ*CQ'6JSl5dF2IfE'TSBU)8bjX@b"5E'4rGS+LP(GVQDYSCk5 *3@HcDc+&H6YCF'0TPkKhR1'hVGDeQDQ*F(TYAQ*YD@4YI*1KNB@2JQChG8G9FP3 p8A"RBRKcFS1BQj'VYUZcTkc5`CbIQi"iI'G9Bh"B9B&p@RZEGPPLD9jDF(&8DBG `KTq!L*Z8PSU'MhZBZ)H6[l#STk'1GCDK4%#LILj-IP`PGjNcAT9BGSjNKTq"LTQ +GhQAI&k5QAGcNm#ANpZXLXD`L*Z9Gf9N4bG)9L8[G(a@Dk1PMCUZP)HMM@*rKPG AD@GUJ+#'HDqRR,UVYmfQJiQ8GdeAA$Bq6MpFFfjkQU1$RFLEIBPcChKJ5PGFDRT ZECA$ViHbil1)`XKrJ(T'8Q!r4QK21hD2BA+cX)b@QjfMJ)L$8A119%amGfb'FQQ FTk'SRBf&RBT0AR45DRp,@U#IK*qbQjkXMSbPJfeXEB"QARGKEBaT@A#0MA+#Ihk LM'jmHfekIQCdLBDCRS#%b0b3!(bbUATSBfGaEP41G)0aISQ(LS#(Heq)M%T4B&H !H8eeRiq*QT5Dam1,MF$&Q(f5SSTI5Q0RCA0KHieGKlGjDjZLF$a9C$T,A6YBGQf 6SC+ZcXLMRX,&TB*mUE"S9S'$M'meG*4YJ(&dL'PhL@T8A'eD3NG0@9aQMj@4XVU XVG,JQ)h%UB4mKTYeGjCiHiQ'H95"Md&`Kb!rH%Be2&&D9@jFDjq@Pk1ki-Lk[+[ -b*UUTRYeJ)&TETed1A5@9%4cE%P54M&ME6KDKQPXNUUbTDDmZUH8NDk[MQp`Pi9 NIS1&NhKbP++-KCU&G(KYD6SrH%8ZB&*3H(b"KT1fP(1`ZReaQDk0H*'FKS+NVD+ CQE@cLAk4RiG@18",0a-22&Sl5SebGFkkRVl"ZU#5NTDbR'GVLi*hKhU$P(YpJiL 0Ij9i8R4S894*4PeV69'(VV@YY,1V[jk'TS"38dpHC%SqCj'"JkZpTCDp`*5FUCD #E9pQGP8R29GC@%eSLRq1TCfYYTfLSSL3!'e9K'P3M+@(JDl!STQFN!"hE'")@9% d89a6CA&VFk#YLj5`Ul1p[-+fVVq24'&a3Lm`2eCF5fUVIPZka@eVPiGZK*@%H(f 3!+UmRh#2YTG[BRL2FQH(Ff9m@&f&@e*iG(L$DRHiY)U6UTf-U*0DIhp#DT!!C&G qKR+'Nh*aPTD$Ii'&Kj+,L,#ZKC@SL("qDNGK9Lj8D%06HRTdG)12IC!!TTHXZ+q PSG6&LULEGi9U8PCUGeY`P(jLE)&F3&K40$G@E(GlKkqi[-c-bV'p`S#-YC4`D(P Z5ea9,Mj59@9SGSfRYD1ablU5G)U*A&YQ@&pbER9kFjQdPSKfD*'3!'PeN!#,B&b ETRZ,Uk'KTTUFPiZ4Qj0T4PGD3c3G+die+PpeLEQaXGVQfFr9cVHPIR#2HNKCG'0 PGP3mD)"33'pY9QGZJCb9KAkGVB#%V+5CSUQPQ+#iRAb%C%GE5LNe@'pIARZ0UUk BQUUlS(U(I(UKK&YhLReM9fGXH@8d@(p`Ij+$JV#kLSD[bk+)T)QCZ(9eVijJCQ4 $-8G20c!`3h*ZDERGT+64ZTfeZCf-MiCdJ(U)VhjLK(*JA90HC9Y469eaG)"fE*U 3!'f0Q*qUVYR&TG$0S)&lJ%mJ*b8L1%43Dhf8YkUPcEkKVU#"JiprEhfAK&4EEfK cC9C`GAapGTQaRi"rK'CIG(CRDiqLPD(0bEhAZBKfA&T5)"Bl3#BX9A*mMjH+SXk hNV6EfF#GUlfDJS"kC$e!86T#B@CbJi*hGSk+BQ*`FQ"'FC@&QlbrZ,R*XC@`S(9 iB6e4F'pF8faN6h4S6BbNI(5@VU1MYV1PS)KSFR&-9fe58h9jJBk(LC5'C@Z$J(U "LBkTZkfRUELeMRTXC@j6-d&FBP03B(0dBQprHi52LT1VUVcA[*58XDf'GhKpG&K LFAD+Jh"XBeC29%dk6RCX8A@hdEUddpI!VjD,PSGM9PYC8fGb9&9hF&48CBHbN@q aak'RX*fAP(&3AQeCEB9FC+qXHibPNRKS9dKHDP&@E)#HPiDK`F#YS+1PPTD6D&q )LdddCeic2N&#Ci*iH+6$`m'kY,QkMQL$H%j9B&pFBi'1JAk1PiKUBhKpE'"VKiT dGj+MNAf0PjDEP)Z5QjQ(KC&`@'YG3cBc9f&0HCq4QkDS[UQ9V*&rMfaLJS9lHAf "HRD'JeYVMQ4KMRq!QSQ$LS1&LB9qFh'*P(GlR*U"Gi+(HQGJC@9I@'&fMjZ!KUD SUBf$U*KpPiPfQ*0dIj0pCRjm68aYCNY8EQaULiGSLCk2Pi9pT+5AQD'YS+1IKjb BA9PZBej28R*VG(Y`Q)TFHBejDh0jI)Q%Mk+8QTf,RT9`H)"rG@H!Ih+-NS0aChP lFhejJTD2NjH9TjjiBhZ%3cYa96YSI@eaNk+-M+#-Lk+#M,bCKU5GPD'LJR+)I@e aD'CTE@jTB9TUEeT*8Q4PCh'1TjDGb-A![TbU[TZ!IAebCQ4KDh*fGA@(EPPpJhT aCi&pG)CjL*YkI)0XK*!!JC0rEC@JQCk2KTq,6(542NZ4F'Q8P+5bR+5GKSPaCRT K5'*VBh4kGRaiJ)KMEjb+IikDYV+BTk+(M)&PB@j[A'k)HBUMNSZ-JfKKF9G3C&e VGh13!*bIU)q3!+kBL**rPUjfEBqCL9jXIPpMBePEB(PpF(H4QSQDQA+&N!"RH(p DJl#(F*@bUC5DTCD%I'KHIAa6D)&PFiG`EhGrJ8p5IfTNJiqFUCk*QDQ>+#CB@ )DTDlRB@EXSaREA&X@%TEDR4dHBf0JRpmG'4FBQTTC(bERTqGTEZPJBfMNSL3!)L &RU1*P*&ZKi&*9Q426f0N5@kLD9+*E&'(H90pK@H#Sk'XcG1l[XZdT+qTMA0QC@* EAeYHDPG)69ph984`G'*PICq@JSqUU(YfVTpaPU+"RmHUSFLjM)'@Ld4(I9-V@RK YG(4lNheHFB*G4fTVESb%IS+3!*TpJ*1%FiLMMBLfd0A&U*q`UA&FF@C4-cGkD%" iF9L(DMK@DQCSBh#$N!#SV*UF`,H&TEb+N!#GQE@MMDbjPfjrNeB[6%Xp06TK8NC kF9aqKhjfICHAK*!!ZEbSVXl2PTUiMB5)E@aQEi*IED*q@hb!D9jDBQ*45f*YBR# 8Qik3!)b,MSk3!)'DYi@,bUQBZ*!!Kj4SEA"8C'PbJ'L!V*Q#I(Z!@MY38dC!4QK qJ)1&RV@HM*qfYk#J`,bRZmDHIiZ)B%G*88Nd1PTaFhU"J)jb8'CTA&aCBRLAQ*+ ecX,!d-LKPV#fMA#1R(CLD'4B5N8k(6CJ480XKjQ@Q*Z@U+H*IR4aI(&UKCqRT+' i[DZNMj'GHfe[C(1!F9KMI9Nl@@C*3fjd8e+#Z*q&UCb(RiKUIC')FBLkXDA'e-H [T+5'F(GmB%&5@NaA68*E5MC+15eMGf0rRUE!j-qIb1QULULYPjL,IE+iH(LFJda LIcd[@dmr4PTLD(aY@@*`IA0QIjqHMC[%bkqVaEbDS+&fEC5%@@TrJ)KiJCaqF)9 T4f9j@&KP68aKBepKBA&jBR+,Mk+HV0c1YpEL`,#jQA4kE9TVHhGLDh0DB'YG66d f1$9&C9P8LC4rL*ZYUk+ITX$%YVhHilZbV)f(D%TB66Nl6PC'9RjbBAKaDRPL9R* rG(Q*JiqdRALCUjk2JTqMPl@JPE16LCTdEBad8@0Z68GUFQjrGQ0XGRpR9(GZ8A1 -Fh@NYjk8SE5rVU+aYCQ3!*f*KTb5J'pIBeB[1&Fk0%0&DApmIB'9PS@*MiqFUCb AVlZ`VELkUj0qGQTGA&PYEdTIK&K0H'C*9eaNEfYbJCUeSC5XQSqYRRTrNTD0KBq KXDb2JRjZEh"B8Qp[9PCFEhYLBRKS5QYj5RLLDhQLQk+LT+qSV+L)QDD5Yl4jLUL AJACUC("I-LNf5PG+-%*lE&GrGhqIIRqMRTDK[,LYeXQNYUfKUjarDAU4E&0rJf9 cC$a!6NNe18Nl8RTTCj'VSBH4UTfAS*bU[UDD`-bcTkqZMR4bFR"QCQpZCPaKC9e 23%"%58P#9'PkK(H3!+f6QE1HUF1NSEHcYEl"ZV#NRCKiEiaQ4@C+,8j28e)j9'* (49"BCh0XCBURQCLfd,U`cVqLVVLUS+5AM*Q,IijqFQC(4%K"2N"19NP5I)*IEj' !D@TrIhb1MTbSTDkJUY#mQTZIQ*LKRBk-PSKRDR"A6d`m26`j490HCB1%BB@bMPT fYUCdLE@NLDE*Z*@J[kH%R*YcMj9DAA9F9@PG4%j93e9U9P"dPhT[Ul#2TEDEJSb VR(L'Q)Z+N!#)QUH5N!#6NSPbDeaQLQJl@AjJ5AGf@(4pCPKXMS'+TT+0X,'*P,f MHiL5I(@CTB1&Q)*rMfYDIQ9(98p8C@TIAiQ$B)5IH@f1NB5FU*HN[+bMYTjrM*H +EQKdDR"jB8jAGACB9&jRF'4XKS0qLj@&JTqUNAb)PSU&N!#3!*1TR(D(SC'4Mh9 iKRK96@KUA9C5@Q&YF'GpLAq(IS#MQ)14S+DBMk'@N!#fSR'(NSLINR+%PB&SCf9 CBe)[4eFm5fCID)18KRZJVjqFSDb`VD+GUVbaLBbIK(k%GA"dL)0GCA4A8Q4@4%j F@8P6GhYeHAD5RhZ0[l5IUV#LU-5[NUkMHSZ9IAU0L@aXG@PI8&CE5&CA194jAPP kFQCrJ(D+PBkEYUbM[-2$[E'bSC@DP*q6F)@%C@YF6e!q38a!1PCJ49f+G&epNAQ %QSb4SD+SV+Ubam#JSU'PYT'+QS+'H'PL2eTM,6j518aN4db&HePfNSD"LCbkTBk TUjkNUl#5M+qDLDDQPTHQN@*RD9TK4MjA3N"@A'*FDA0UHhGZQTpmQDfDTDQSVjf CR)f-Q*QDSCZ9QjD(Gh"mA#jBC6T"8&KM9eKUEhb+FQ@9YCCqRVDYVV5kUC+[VBb BMiDDNi&TAhaa6'0P38T-3P&FDf96G*5(J)kKVCb*QCqCYUk"RED9MjfHQSq-IfC TDPP-9A"R5ePXC'f!FPTZN!#(GhL@V*+3!*U(LCL4JSH6PB9pPDQLS+HAIS9mA@4 S5N4L8caUHP9TN!"fDBb'FSqELT'4Jj1QPifAP)HAUC+8XkD@U*L!K(&HB8dq5cS L0NG"6@efBS5`RD1[VF5aPD@LRUfJLT@DP*!!KBH@R)KbIfp-CfT(@Pim3dG$@f* PC''-Tj+HYmE6YD'YRTDDP)plEi+,HhU3!*@+JRPmJ'KQJQe+@fj95'GY9&*RF@4 XMik*TUH8PULkXU@GPD5QNTLGR+LFKiD%Ff4MBe&&8N-b3dC-@&TECRPdHj@@VV# %TpQZRmR"Tl+fSik1QTD-J@eNC99186e$9#ihB99PF'U2Lfq4U*UAS*k5M*@PPS@ BRjb6KjHIRk'5LSb0IfefGep89Na!4eeH8f*dFRZ3!)arN!#NN!#'PB5%RBKfQDL 6MjZXYDDYYC@5SRYIG'aA9d)e6NBk8PP6@'q$GS@dVTq`TjUXUk#EKiZ9KBQ1KU' iLAHPP9eTIQ949eBl5R&C9(*GAiKqC)1VQSDMYDHDUE@JP*''LiGYHCU>Z6FAZ 'Hh&eD%09FeT3Ch"PC(CmF(+1M)'5J(qYVjbCRkqdS(q,XTb!NSjbIiaSBR0KAPG !8f4889jVB&9YK(aiLjkHKB@cVi1DaUk8VUL@ZEH2Mj11Kfj869eA2MSh3PP46fG `D'jjHBQAQDDDRl#ERl'NPTqTL(LFQ)HGPi10NR*ADApN1MK+8&&EE'4YKR4ZIi' 5Rik,M)5GU)H@UC!!NjD,PjqFNT5YS)LBPiZ&D9KI6MG$8NBm6e4'DAe4C+@GG)@ eXBbDbF'ETlUXTUZINUbREA+@GejcDde+9Nim3P*GA9&0BAU#GRbUZ*54V+'S[C+ C`*@1T*LFQT54HRL!G'4GAeYJBdY,FApQCi"V@B#(Bh+2LB@"LCb0KTD6P*Z0Jjr "TjUqRiLXPh&`Hfe066SRC(T,@hCABiTdAi1BIRU+K)fKRCkNRT@CT*bGVUZPRC5 JRB*jFQaE-#p"-$G,4%pKDS')K*'T[CU*[,+)RkqDLC+@JSUEM(q0PhjpLR&hNB" TB&Y89@*24'aU1P')IA1EZ+#9X,+KRDDfQ@KiM)@0Ji5KPhYfI)4rLBK9B)KJ6h" eC'G[8$eTH&YMG(U2RjQEZXbYSlbAJl@THBLIMhb%I'YqL'T5@P94A8e2GR9EAR& hEfYbJBGqFAkCTVHkTl$"YUbRU+fFLBeh9&edE9YA4dGE1$Pd9e+#B@',MSQ$SE# *LCD*Mjq8L*'BTk++Um'8Rl*cGkaU1RCm48&E5#p@G'&@9@k&F'k-TkH,KCQMQj' @P*!!N!"iDCbiMjZrUjZJRTL5M)"U9%!k5%T&2MYBB%4AJ(jrQ*Q-QkqUT,DhT+5 CLT+CQ)KlQDClGD#3!'q6LdG8G8ik8Na%9Na(DRPdI)U5ND#JNUr"SD+cQBqHQ*! !J)DJJ'4[HBb#F(plEfPEDQjJF'j66f*VDA&lK)f!FiQHRU1GN!#DUTPiSFf6HU1 HG(5-F@Z&CNYGCepMFfTJC@PdGh"VGSKqI)&qPTH0RCU5Qk+CPE'hQjfFN!#IN!" JDieT-%480daJ9PeRFA4mJAkEVC&iKkHJL)ZHS*!!LB'#PjL6Q*@APBq)ISL&E@Y I2$eG@NG5@9jaH(L8XTD#TkqIPBHCUjU)K(9aT+GTGU@FJ(k)LSQ1L'KECQ4H9&0 F8%aBCQ4RPjGlS,'FR+UhX*UBRT&mKTZ"GT@CKQYXLi"hJ'j[D9TXFfCRD9aBAPC MGQekKS1BP)QaeV5+T,UEL*QDNk@9GSH(DA"rG'426ep6@'YPE'4@DfaPGh9cJhY kMT'5Y-kKP-HeP+LRQkDLI'L"KfpQB@&U9$K'C@P8@A9bDAk&HSb@I)'9G@q8MS' DRiCqREDGRVkVND'QKR1"M(jVC&9-B'G@6e038'GTA(1,L)Q3!)Z+P*QCN!#1L)D DQjZVVVM!Y*Z*Qk&lDfpI58"28N"1A8!pAfTPCAL1R+HCQEkqTE@VJS#&GAU+I(b DPRb)QTDIQ'ePL(0%@i&`9eCPEfGSDQb%K@jkJi'KVCZ8NTL3!(H"M(H$R(j[SD+ )SkqNPi#&M'jLFfG#2%pB8NpFCh"aD(9pK+@PK*V*UiU[XTkSTik!MBp`FiemD(C hDQTQEfj18f4D99KVLBaqKCfJPU#KRUfEGi19MC+@LSf0HA"XEAYfC&KGDRb0H'Z ARQjXNBGRIj0qG)#2K)ZVP(H#KRTZGB"qIB15NBQ2SDD1KSG`EhpVB(ahAQYbFh0 EIC4JC)9rG(bKSBkSSSbLUSppP++,H@emRC+!K(4aGeY5B&9B8d&FE&YSLk#@P+1 MSTZS`DQ+PkbBKCQDK)&qF'CFA("[5e#"H9KbJR&qG&CQI(YYCS1FQTk6PV1RP+L IJSL#H(jhM*&[KTYlF(Z(Kf*DH@pFCS#'AQZ3!'"'DA"RFA0UFAq1SDU`YUDCV+k @Qj1-UTjrK*!!Q*+%FQCQ88C%2%G-2d0GC9eiL(CrQT@"L+5q[D@fcV1TXkbFQCP fDAGcG'jdI'"JG'YF6%jR86KPEP0iKRZMX*!!LjZFR*Z+MD@0HCQ4LU18MTL)IB@ 9JAQ6JR*hI(*PKhJr8@&-3NCPF'9pJf50`U'4QU#ULiQJNjkKSE'6NEDTLBZ@Gep aAdYKC9P*4eeN8N*AGR9SDhb,Sl@NU-1jTkkHM*5,JB4qFQq-Ti9RJBpdC@PNBQT M9'4dB'*iHiq,9QQFLi#9Mi@IV)q1RC+RURC`MBTlIBGrJC5)Bh'4Gh*[9'Kb86p PL@GKLRYSMD*lI+'5NCQ+NjQTXTDBT*@EQhTbNBCE@@CNDh*HA(KZ89&QIhPUF)' -Kj'RSjbIPT@HLhqFRS'%Qjf!J+QEGhP`BQP93@TY3PYhB@4eHif+IiQ-NTHPUSU @Y*Q#M*H%GB@(IRG`IjD@Ji@0IR9kEeTGC99AANjDEi'(Fj!!S(16ZC1AU*QGRC5 -KT'6KRprF'5-QQadS)PMHheBBRTX5$p@8&CeD'q2IiDPTULRTl+SSkf6LUU9JT4 hCAjmD@PpJ'CMG'"EKhP'9("U8&&ZHR0VJT@+Ql#UV+fRX,+GQTb1NSZ"JPpZQQT 3JAj-6R"U8PPYFfTICAU(HhD3!)K`Mjq)Nk5PTUQZPSURTBk,NReTKj!!FhQ,I'G QCPK)8'4C4eGYE@0qSiejN!#6Kj!!PTU6MD@VR*@GVk'6SjYlGT'-HSL,H9pQF%P %9N!i5dC%AfYfRTaqPEHpU)QIcUGhS+k)L*qPQSQ!I)56J(##Hf"ID&P%9&%h8eX b5RekF)+DQjfkZU5m`*ZNYBCUNCGeH)0kEA12N!#$L)1#LAaF8'Yb99&B5P&SE'e `EhD+STCrUX5ETEqNN!#AU+GqFCH0CAf4JBf0ISTlA9aIA&&)8%a)@Q9UGRZ(LB+ 8TkZSX-#fX+kYZ+@IU)"KFR9NDR4MBQTIDPp4F@**EAGM@QfFPfb$TT@9QiZGXT* pU,Z0HTfcRReiJRThHQeaF'CfF&46DAPP@feXCA50LA5#Mi+2PSD6TCQ)PkZ,IUD RNk+2ET1XKfq$M@YGEPFj5e9&6PC1A'eeHi+6PTDCPk5`UkDdV)f8STk2JT@8F@4 iLhTYFQjjCdC089"15&C25RQ*H)kKPTqhXk#EZmZ2LVZ4I*Z%H)Z%F'4JEhplC'# *M&Y8D@PKBQ*DC@CPKiGhM*ULSBbDZUbBRU@SPB5CPifCIf4lN!"qE(*kHA9ZBPP AA9eG@djDDfTfGR+6PiZ5Mkc(TTfl`kbGTl1lThYhLAjTBfPD6@PP,cCJ5d*H@%e QH(1)PBQHUTbJU+qaTULhXkH6KkHhMhU$HfjcBdPQHNp%B&!h5'PbBPG`MAjjPU+ APTq3!)#IVj5,RkkAGSkVN!#%Q*CiDSUII&pfMA&069Y928CG69TVA(Z6KSb1PTf 0PCq9R+qdTU#PQUI#Rhf*LiGkA@0dF@K559)l1&T&19eB6R59NT'RXE1ZS+biTk5 [ST58Nj!!S+'&IAY`D'ehBeT`DP*6AeP9DQYACR&PITU&JDHLKT1XXCb@UkL9M)' *Tk@#H)U&HS&pGRGhG9j59e09@9PC@@4SDi+0HBDQLAUPUTkUZ-1eQ*bPRkqEDAb %B'ehA@f$CePG@PG*8'4E99pSHSU*PUZBK*'JT*kCUELPMk'QPUDJHRGlB&TVC'" YE'"EC'4GD'TNCQ*TH(k2MS5DRBD-QTQJTCbGRT16RkQILjQ3!'"ZLQaIE@TEA@4 95daHI'Y3BR&lMB+"QC+'PjD5XEULRUqVN!#5UU58N!"mEhKkG'pVD&pG96j"6eC LAPYRF(k8RjkHR)Z1TU5DVEQJPU5ENCQ9M)9Y@@TkEQTZDh&hDP"2A9pLBPeMD(Q 8Q*19Pj14NBk6SU5AN!#XVi+,VCL,LfYVKR*PG(ChDfTR58jQB&KHA%CDMijpNTk 0LC@HTDLXY,QRM*5TSTZFI'0fIQ9GGA"FB9*'9Ne%A'TLBQ9PKD1HPSkET*'BTE# rS*A$XhL"T*KeDQeKB(G`B(&pGA*V8e"X@8PfDdPdPSb)R+D*MUD(HCqYSD#HT+1 -NCfFN@eUGQ9VJAehJRpG9fTJ8eK86Nj4BhL&P*HARTbJSDE%[Tf[`k5+QDLINhe RBQ0bEeaFBfKB5PKE99eKD@K9DBZ1Qk@9MTkcXjqTblbMXkQ)IBH5JfCDC@CEDR4 XC'GqDN0EH'eMH(4@EjfDJifPM(D1NS'+Sl@ZRULMLjf[LhU0EPGhHQKbHh4X@e4 IA8a,B&e"@)H+JT'LQSf5QBq0V,1BUm#PQD1RXU*hERKX@eCRE&"3AdT#B&Sp8R0 X@'b@R*bdZk@CT+5ESkZRRCZ4IS52M)L&F9pZE'&[FQGA@'"0@h*6AiY`6A'RTCD JQjLBP*59RjU4SU'3!)Z(Lj''IAPiJ(plKi0aFA&J894@3ceDAe&IGSU*ND58NU5 CN!#@V-'dVVZbRC1CUTKTARPe8&0jG&KD9NY95d"5A&TC9h'5PUDrX*fTXDDETlH aUk55QCf2MB&hH&G(B@PK@eCDCfYHA@PSFS*T8A'8NSq6NT@CPSb+Q+DSPBQKUik *Qjk9KAepF'q)J9P2C@K,3&"BA@"ECA4dG)HBNS50QSU)SV'bV+qpYDHIRD5BKRj RChp`@eeB9P!h1%Fm39TQB&b$UU5QX+LNUU12QUZJSU@IV+1#MDU0C'ecA9j`Ef& PF@GE@eCCAfCVBPjZM*U9R+bRQjL)L*fFMSL6R)k*PU#GMBD(IRGlIRTeF'KMAPT 8699NA%G2E(4iKBf5NCbYSk+m`UkNV+kQN!#&SU*fF)Pf@A&rA8YE9$a!88j0AQj ZCQq-R*D6S+@6Pl+cVEUkUDDZSS0dH(KSA9P6@f0UH@p8EAj36@YMDi+!FR@CUif -Sj'%Jh1#Q*'@TD+JV*k0RD1-FQ*TE@K`HA"PEA9Q6P&XDeGBB'*cJS14QT@8LiU BS+LGPV@dSDq[U,'SN!"hGS0K3Q4S28G80MeC@9*KH(0ZHBLNTC+GX+kERVU`QUQ URjZ-JRq-MhKeF'KcE@GaCP06@Nj!8f9THRphKC!!PkHJMC@HN!"pLD@LSUL9R+D +Jiq-KRTZE'jeL)TXF)0K590*5eY56f0UD)#GQSUFU)Q-UkHNUU#R`,DBP*ZCPS0 TB&YJEfKHBPpFBee)4ejSA9THDAk)Mj@AV+qCSl+XX+fRX+@CN!#"Q+"jE'jKA'* RC9a1A(051@"eCfYqIQafP)b!NT@+KSkSTjDXYk+MVD++JTLGIh&`CQb!G9TEAeC 956j9C'"XGA0rNjH1N!#9Nj!!LT5ER+k[SkfZVD+#N!#YK9pUG'jPE'j@AQe33%P 09f&QB@U,Ki5VT)kUU)Z5T+58RDDCT+Q8KiQKRACVD'epEeaPE@KJ6Na@8PC9@(& XDiD4NTZVUT19YEkJPVHeR*f5JT+LM@CXK'aJF@9LD&TC@Nj'9@GB9R"lFQarPC@ @RTZAUlURTVLfV+DGK)@BLRCZG(CKB'0THPp*Aee*5e9HEhCXEAk)Kj@HJhUBVDL AS,qqVEQZND'IJS9mEQaC@A&eB9"GEe-p8eP4Ah&fDR'4QCDHPTQJMj5MRkU[T+U fVC+2TU5'FhGS8@9b@8jDAPG33N0JCPjSFhPqLCbEQ,#SLD@pQjQ[RCU`TSk1NT5 HL@GfK'48CQC09@)q-PPH5@5$DQQ,MBUAU+Q-LkkfSTUVVjqRViaiMCZ@K'jhIQ0 SI@YJB&C83MK8@8KVKf4JLD#AN!#DNBqUTCDFTDkbVU1PRiD6UBGRFhKMBh0S@&j L9NY%2NPGDA"N@hDHV*Q3!+1VT*qGV+qJUE+MRjk4LSfENfG3CA&E9&j34@&N0$K TEQCcG(1&PjbBQUHVUDHBSDqEQkUBPTU#IT1CMhjVE(KSAQGD8Q4I1$9GE'&NFA+ "PS'#U+D9QCU8QkkYSU+RV+H6KT5JPSCZERPNB@eI8e*13$G#590RCQ&fK)HNV*L LY+HGUl@SSkbVX+q(I+'HKApR9f9K99pI4P"`@$K)@@&VD'TcJT+,PE1RPk5QTD1 BPk5YR)kEQBH+PT0lBQGYB'CK6QGa8N4'8fGPBh0bCRD+MT+ESCH3!++[Sjkc[DH IUk54NDLSGPebFPpJAdT-@P!r180-8fK[DA*jLTk@P+DYSTUMX,1ZVlbmU*qKQ*1 @J@aR@P*BAP9'99a'4%T'A(0UEi0lJU#KSkZFQU#4QD@@S,5LQ+HHKjDSM(&cFQ& CCfYG99YI8N93BeaCFAPXFBZALBZPSif(RV'GPV+aRk1TRjHQUBjpG'e[DQ&D89" @8N)j39"MF@GJGiU4QTQATDDBQUHTTE#fU+'LNSLJTRpVF@GGC@aG5P9P@N3k3eY fGPjMJ*1ER*QETkD4PUQHNk'ZST@HQ)b8N!#&I'4JGh&CAfKcGeY2B&P6C(*aBQC rLSb4PTUIPBD9Sj1BUU#CSjk0ND@IK(PhF'j[DQCHAA"S4NTFAQGQCh&TGjL6K*b `P)LNV*qLVkZITDU@Kj+5J(PiDePDD&a5A9P@@9"4BA"pIA&fN!#JQTLPST1BT*f 6QkHNQjD9PBU$MSGaCepJE@YA@h0S@'"C9'acDA@"GhQDTT18QjHANSq8PjkLQTq PPSqEQSk%FQKVCeT5@@4L9&"C9NpCC@eaF(@(QT59VkqAQDZSR+5TR+1bSif1QTD )GfKLAP&1@90&9@"-3&CTCQTfH(f0PjDDUV+NR+5RTTkCU+H@PT5+NCD%G(0VCfY E8Q9M5P4I59*X@&4rLR4mPTQ9TUL0Mk5NQTQLSk@URTbRR*+3!)"cEh&cC&9JC9C A@8T,@P4)AhabD)#BRD'NR*UVVC@6UUfXVD#MVU@6Nj9qDQ9IB&aGBP&-CQ&&8Q" 6@R"fER',QCfVT*kYSTDRUCHCUDH9NTU9MC!!L(9[F@GAB'e@5faU5e4QCf9REQa eL)5'PTHAQ*!!PUHMP*DUXk@0KkZjM(5!IhelD@"SCQ&R@%*6Bdp4D'CYJRelMC@ CR*!!LjbPQCbKRl+hQ*'LSSjlI(9SFQ03E(CD@fYJ@&jGAejQJRY`MTLDU*H1RjU BRik)RUDFP*5KRSZ%JRYbFfPADhKL@QC[BeTTCPKXIQe`JB51PTLIPj'FSTb4N!# LU)q*S*b*NT9rF(CjD@PaBPCGBeeB9eaRD'4bJB+#K)fLSj'8SDUVQTQRUU18MBk )KiCmF'YaH@pG@@&SCeC)@QTDA'e`JBTqLjqGPCDKRjHDRjqBR+ZJMBZ*LB9fDQ0 XIA"CB(*cC9pNAf&SA&a[HAeiH*1HNC5MS*QHSTH5TV5GLT@KQBTmER*iE9a8CA* L8eYUE9j9B'jQAh5%JS+(QkQGQULZTjqMTCkMU*H3!*k9JAKiIQa3AR0J4%pQAeT I@@&[F(0iISH&KT5HQC5HSk+LQTZSUD1DM)qENApiHAKXDA&T99&JC900@&aMDfK `JB+'N!#2N!#EPj!!R+1CQ*kDRDZQNT5HNS"rJ(CaH(4UBPaSEPC09eTD8PGZFR5 %KSLASk@CPkHKMSqHSjfCQ*L5NippHhjiF@KSEf9JCQCJ99YXB&0LER*mKBL'QE' LPkZRP*UJPSk6P)U*MBQ"HAZ!GfjdF@CVD'4XCeeUF&YIHA9[Ji9mMCQ0P+LFN!# GT*QATD'4M)H*N!#(G(+"J("`FfaLD(4M89pUB&aUFR+$LhL%STH2SU1BQTUFTUD BNTL6L)CqEfY[Fh*VB'0aF@GIB'Y[Bf9dFA5*MS'0STUDS*@HTSf&N!#8Q)q$KBU 2IfYkJA"`DQ4iDeCdH&aXI'PKERCeIBCmJ*fCKjDSRj'3!*bCL)Z@Li5+MBKkGAq #H@aaGQCDA@GTB9YFDA&XDRL(JB#6P*DRSTUNUTf6SU54N!#5M)9pJS&[ERTdB9e UCf&XANjUFeYMER*qIS@8MT5PSCZISD+EPT+1QTq+J)L1M(CTI)0aEA9[B'CbCfC bC&TSDQ&ZK(T`MD'9N!#FSD@NPT'CS*U+Ljk@K)f,HAf&H@TYFf9KC&eLDQ"9@'9 PCA4eGj19KCQSS+U`SCDASTq0Nj1+NiYmK)&fH(CUCQeZCPjKCQ0I@Q"UB'9lGB1 HL)5SVTk@RDZNMj'DNT!!N!#(LSk"GA4mIR"UGA&JCR"UC9jIDQ"8DAYaFAq+Nj5 5QU1RS*56QjkANj+5MSq3!(ekKAeiGQTVFfPHCQPQCee@C'aRDR9pKBk,LCULQTq NPBqGSC@-NTQ6LBH'JAPfG'aVE@GPBQ9YC@0TCQP`FRTrIikCMSUFUCU,PCH1PT' )NC+3!*1,Ihk)Jh*fGfT[E&YQGfjGA@TZD@ehHi#3!*'#LjfFRCZ,KCDIL)'5Mif AM)+%IiL&E(5%F&jNEh"UCPTDD@YMD(Q&L)k0MTbJRk@6KCQCK)12PBZ(N!#'HSL *GA0kGA0ZC'T`E@PJA@&JBfPZHi"rN!#EP*UUUCb8QTZ-KiL*N!#+J)D&H(KqHA& cFfeUD@jjEejQF'TQCfphI)Q)HiqRRjbPRT!!P*q8IiH@Li+)JhKiGRPmF'jbCfa hFR&`D'YZCfTdGhQ"Ki5&NjLERTHAPTLFNC!!R*H5NBQ%IACjGQeYE'*KEACbB9e XE&pNFA*kL)5#P*Z9Q++IPj@9PTH@NC1CQC5'HAYpGfeMB@KRAQG[CQYTBQPQDRe qHi@1P*16RD+KRC+1N!#*LBq-NTZ-JSQ$JBCkE'aYD@KSCfTXBeYJDfGQH(YlKSH &MTbNQj1BR*f8KBfGNSL0Nib!J)+$JA0bF'4SE'GH@@CR8eTUERb$HS18N!#4T+L EQD'KPif4QjD5Mi5%JRCeIAeaC'KbF'eXDQjRA@&NCQTdJiH!KTH@P+'JQCkAKik DNSZ4Q*@)JAq!KAp`E(&aDfY[EfjYDfGJB@0UHRYfHS#3!*b4PDDDQ*k5PC@0PTD 2N!#2K(k*KA9`F'aNC@YRB@PYBPeSDQGiJA9kMBU$PD@DPD+LPC+9Q*UBMS1(MS* cHB&kF'GQER4XAf*YCPaHCQaeIi'$KBH8R*58QCQ9Lib8NT'4MBq3!)TrHAYqH@p XE'TbG@KNEh*P@PjUFhCiI)''M*HHPjUNQ)H1NSL0PBf)MT1+I(k+KhPYDR"bD@G UD@GQBf&KChKlFAU%K*'CQD+JQjU9PTL3!)Z9PB5&M(plKB4pG'peFQaYD'4SD@9 EA'jcFB#"HBZ4MCZJQCH8QCU1MC18PSq#JSL$HRGjIAKYERGcDfjdE'*KB@0UFhK eHSD)MTQBP*5FQib+P*H8P*!!LSf2KRekJ)&ZCR"[DA&[C@e[B'9VCA&rGA#$MiD ,PjHFRC52NT11P*U1Kif2LRpiIS9hCQKYDfTSCfPVDQ&QG(*aJSClJ*!!Nj'ARCQ 1MjD6N!#2NT5*Kj!!LhphIiKfDR&[DfpcDf"XEf&NDh&dH)@$HSU9Mj+BQC@0MC+ 3!*!!MT'CNBH,Li4rJAjfGQpSFh&MDA4UA'CTAh&rFhb+Ji5AS*H5Qjq8MBq5Nj@ 3!)f0LSQ$Hhf!GfjYDfT`E'T[D@4NCfjXEhaqHi'+NjD9QjfAP*'6NSk8PSZ'Lib "IS4lEhGdCfacD'TaDfTZCQ9[G(ChHB+&KT'5NTZDP*58Nik1Pj@(KBq*HAarHRK cEQeXEQjYDfPPBQK`ER"lHhZ$JBH@N!#4Q*'6PT!!NjD@PC@4M)Z%IS1"H("[E'G [G@aLBQTSB@4RF(amH(b)N!#6QT@1RD#1LTD9N!#ANi@*NBepH)0qG("UE(&`F'e SDh"SB@adG(TlH)'2N!#0NjQCQT@(LTf8KT'2KSq-IAk,KAGfFQpfGQjRDh*SB@T TD@pYG(jpIi@2PT5DRC56QTQ4Mj58M)5*Khf"K(KbGA&`F'eaF@TTD@KXDQPfIAC pKRk*SC@*QTk6P*11PCQ4KSD*K(q"HA0lG@CYGR"bG'j[EfpbE@CcK(TZH)H0MSb *MjU@MSb0NCQ@KS55N!#%K)&iIS&[CA"jG'aYF("`D@4[HhCZH)"lJSq+LCLCN!# 1Mj1CPik+Mj!!Mif!IS9pGh9UDh9`C@PaEfPPDh*aGRalIB@)Lj59NTH@NC!!NT! !MC!!MB@'MBPqIi+!I(4`FR4bF(&XEA4VCA"cF(PqHhk$LC'4MC5DM)D8NiL-N!# +LBQ'Ki5#KRpeH(G[G(9[F'jTDfYSCfY`GhjlHS54PC'5PT18Pik-PT'+NBb$LSY qHAjrFfTcGh"XE@eZEQTQCfTaHAPdI)Q0N!#5PC@3!*HFN!#)MT@ALRf&NSThH)0 qG(0[E(9hE@P[GQeLEA0UFB"kG)#0MSU1PC15PBk-P*10LBH0M)1$J(q"I(4`FhG cE'e[E'aTC@PbFA&rJ(+#Pib+NT+5P*54P*52NC1+LBZ&JB"qHRGhFfpcFh"VDA& YBQT`E(9pHRf(Lif2NC58NT!!MT!!N!#0MT'+KSb*K)&pIhTdH(4bHR9TE(9eE'0 VGA0dGhL!LSH)P*+0Nj'3!*+*Lj@-KBU+LBL!J)4rHh9cHA9[FA*ZE@jSDh4YEAY jGRk%LSq+LC'9NSb1Nik0LiD)KSH'I(k"HRGkHA4cFR"`EQj[D@abGAKjHi''KSH 2MSZ3!*+2M*!!NSf0MBL'KB4rI(ppHACdGhPfFA"dFQj`E@efHATkIBH*LBk-Lj' 3!)f,Lj!!M)Q-LBL*KB@"IApqH(9iHA0bGR4aFR"[FR4hGhGqJB+(LBQ1NBq,MBf 0MBZ,KiQ+JiH(IB'&Hh4kI("aG@pZF@pZF(*eHRPkJ)1)LBQ3!)f0Nik,MSq1LiL )Ki1$JhjrJAYhH(PhFR"dF@e`F'e`GA9jJ(k!LBQ*MBZ,N!#,KSb1LBH*LB5"K)1 "I(TqHhTkG(CiGA9bF(&ZE(&hGR4mJ(k&LSH+MBb0M)U(L)q2KB''L)D#I(f%Ih9 eHRTdEh9dER"`ER"eGRClIRZ$MSL)N!#2MT!!MiU0NSb(LBH'KB'!IRq"HR9kHhC bG(CaG(CXF(YhH(pqIB+*LSH*MSf-M)H,N!#0L)H(KS@#Ii'$J(ajHheiGRKhFh0 eFQpcGRGjHRZ!K)D(KiQ-LSZ+M)f+LiU*LSH&K)1!JB*mHAaiG(4dG(0bEfecH(* dIReqJi1&LBf1LSZ0LiZ+LSZ)JS+&K)1"IRjqHRKjGhGhFh*dFR&dGRChHRaqJ)' $LBZ(L)b-LiU*LBU'JS1&JB#&J(U"JRPjHRKjGh4aFh4bG(9eHRajHi##JiL*KBL 0LSH*LSZ*KS5%KS@"Ihq#J(PhHATiGAGdFRGeFR9eGhjpHRk#KBD'LBZ*LBZ+LBb )KBQ)Ji1&JAq#IhPlIAGeHhGcH(GdGRPiHAjpI)#"JS@*LBL)LBZ+KiQ+KS@&KB@ $Ji0rI)"qH(PlHRKfGh9hHAGfHRelHi##Ii+)L)D'L)b'JiZ*KBH%JiH(JS##JB& qH(PmHA9fGR9eGA9hGRKmI(eqJB1%KSH*L)D)LBH)L)@$KSD"JB5"IAq!HhTlH(K iGAGhGA9eH(TkHherJ)'#KBH)KiH(KiL)KBD'JS5%JS*rIi"mHhalHRKjHRThGRG fH(PiHRYqJ(k"Ji5(KiH(KSL*KB5(K)+'Ji'#IhepIAakHATjHRKhHAPiH(KiHRe qI(f#K)5&KSL*L)D'L)L&K)5%K)5!IS&rHhjpHAPkHRPjHRGjI(PjHharJAjqK)@ $KBH'KSQ(KBH'KBD%Ji1%JAf!JAamI(TlHRKlHhGjH(PkHRaqIAq"J)1(Ji1)Ki5 &KiD&KS@%K)1%Ji"rIhpmIAjjH(YmHRPjHAPkHhTlJ(pqJB'$KS@%KSD&KB@%K)@ %JB+%JS'!IhjqIRakHRTkI(PhHhajHRTjIS"rIRq%KB5%JiD*KS5$KBD$JS+"JS0 qIB#"IAamHhamHhTjHhYkHRPlIRjrIhq"JS+%K)5&KB@%Ji5%Ji'"JS&rIRf!IRT mIRelHhalHhalHAYmI(eqIhq!JB'%K)5&Ji1&K)1$K)1"JS+!J(jqJ(jkI(emI(a mI(YmI(YpI(arIhjrJ)'$JS1$Ji@&JS+&K)+#JS'"JAprIhppIAelIAplHhemIAj mI(f"J(erJB+#JS1$JS1$JS1$Ji1"J)'#JAjrJ(pqIRepIRemIAelIAjmIAjqIhq !Ii#$JB#$Ji+#Ji1#JS+#JB'#JApqJB"qIRjpIAjqIAapIRamI(eqIRprIi#"JB+ #JS1#JS+#JB'#JAq"JAprJ(pqIRpqIAjqIRepIRjpIAjqIRprIhq!JB'#JS'#JB' #JB'"JAq!JB"rIi#!IhprIRjqIRjqIRjqIReqIhjrIhprJB'"JB'"JB'"JB'"J)# !J)#!Ii"rIhpqIhpqIRjqIhpqIRjrIhprIi#!J)#"JB#"JB#!JB#"JB#!J)"rIi# !IhprIhprIhprIhprIhprIhprJ(q!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp rIhprIhprIhprIhprJ(prIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!! !4US!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!%D!9Zk,S`!!4Ri!!%Cr!$b!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp rJ)"rJ)1#JB'!J(prL)k%H(9hIB&jGRb!J(pmI(ajG("aG(9eGACjHAKiHR0VDfj bG(9iGh*aFAD#L)b2M)Q+MjH9MSf(IRU"N!#CQ*56PTLES+#8LSD#J)@0Nj52LSQ ,KRjkH(GhGRU$KB+%Ki0lG@eUIjUJQT5,JApkGR"SC&jGDA4fE@ahF@9KB@GXCPG ,46`l59KKBPaCA&pHAf&LC@acHS#"J)+&Lj5FT+bdZVQfZ,l"`XM6fplJiq,GeF[ %`m1rZ+fMQC!!L)0rHA0VBeeD9e&-5%9%36Xf-c)d06Bi1cXh-5m`-M3f0M8d-c- i3NY49eaME(*fHAYmIS+(M*'9PjUIT+LYXV@fYlHhYV5bXV+bY,HkZlblZVUkZVQ hY,1bX+qVTk@NSk'JRjqGQTD4MSZ*Ki0rHR9`E@PQBPeC9&"+3MSd,LNQ*#-M)b3 P*L8Q*bS[0$T!48K+6P*9@9pND@jcHB#&Lj'@QjqMTULVVV+dYVLk[,r$b-c4eGE @eY64cFR&`EfjYV+[UU@JQjD4MBQ'Ji"pHA9bEfaTCQ4LB&pGA&YC@&KB9e958%j ,58G%3N&"38*$48G)58P*58P+5de18&0CAf9XFRKrK)U3!*@CRU+PU+b[XlDj[Er "`X2%a-6&a-2#`F#r[VflZ,@bVkfUTk5KRTZANj!!M)L%IhTeF'aRBepE@&968%e +4N*!2M`l16Ji1$Jj1ce!3dC)5dj499KD@eaHB'*PD'Y[FRCjHhk!K)H+MT'8PTQ ERD#LTDLXVl5j[X2)c-r3d0(3cmc*aX+qZE1[UU@LRTUAP*'1LSD#IRTfF@eSBep D99"-4d0"2cir2cmr2cmr2d"!3%d9(5Nj499PHBfKXF(4iHhq#KSU0N!#6PCH BQTbHS++NTULTUkbXVDfYVDkYVDbVUkUUUUQTU+LTUDLRTD1JRCZCPj55Mif,L)D $J(ejGA&YD'0H@PG68%a*4N4"2cmr2ciq2Mp!38*$48C(58Y06e*9@&YIC'PZG(T rKBU2PCUGSD5RUkqbYEHiZEQkZlZm[,blZVLfY,1`VUZST+#GQTH8NBk,L)5"IAP fFh&ZE'YTD'GQC@9QCfKSD'GRCQ9NBf&IA9YC9eG@99C@9PGA9eKC@PYFAQ"MCQK VER&dGhYqJB5)Lik3!*+8PjQERCqKSk@RUDUXVDqbYEHjZVZlZlUiYV5aVUURSk# FQ*53!)b)K)"mH(4[DfKNB&eC9P458%p168e06Nj16dp389089PKEAQ*PD@eaGAP mIS#"JS+$Ji1$Ji1$K)5&KiL+Lif2N!#4NC+6PCDAQ*QDQTZFR*fHRTkHRTqIRjq HRCbFQjUCQ*LAPC15N!#2MBZ*KS5"IhajGR*ZDQ9KA9P@8e"05dP(4N9&4NG(5%T ,68p38P9B@PeKC@PXF(0iI)'&LBk6PTUGSD5QUDZYVUq`X,#`VkkXUkQRTD1JRCU BPT56NC!!MSf,LBL(KB5#JApqIAYkH(CdFR"[EQjYE@aXE@eYE@eYE@eXE'YVDfT TD@KRCfGRCQCPC@9NC'0MBf0NC@CSDQa[FA4iHhk"KBL-Mj1@QCbHSD5QTkQVVUq aXl5eYE@eY,1aX+kXUDDLRjZANiq,Ki0rHhKdF@jVD'CMB@"IAPjHAPeGA9eGA9a FA&eGAPpJBQ0PCfPXER&cGAGjHherJB+$K)@'KSD'KSH(KiL)L)Q*LBQ+LSZ,M)b 0MSq3!*'5Nj@@PjQDQjbFR*bFR*bFQjZEQTUCPjD8NT!!MSb+Ki5#IhajGR0`E@T RC'&HA&PA99468P&48&&489*699CB@PaIBQ9SDfjaG(GkIB#$KSL,MT!!Nj@@Q*U FRTqJSD+MSk1LSU'JRjkFQjQBPT@6NT'3!)q1MBb+LBL)KiD&K)1#JB"rIRemHhY kHAPiGhCeGA4cFR&`EfjYE'TSCf9NBf*KB&pIAejHAepIB'&MC'CRD@YYEh*dGhT mIi'%KiU0N!#5PCLDRCqKT+DRU+QUUkZXUkZUUDLRTD5LRjfEQ*D6NBk-LBD%JAj mHAGeFh&[EQeXDfTSCfCPC@9NC@9PC@9QCQCRCfKTDQYXE@j[F(*cG(9fGhKjHAT lI(epIRq!J)'#K)@'KiL+M)f2NC+6P*@@PjLCQTUER*bFR*fGR*bEQjUCQ*H@P*1 4N!#1M)U)KB1!IRYjGR4aEfaUD'CNBQ&JAejGA9aFA&eGAPpJB@*NC@GTDQaZF(* dGRKkHherJB+%KBH)LSb1Mj!!NT16P*59PC@9PC@8P*58Nj15NT'4NC!!N!#3!*! !Miq2Mik1MBf-LiQ)Ki@%Ji+!IhjmHhTjGhCeGA4cFR&`EQeXDfTTD'GQC@4NBf0 MC'4NC@CRD'TVE@paG(CjHhf!JS@(LBZ0N!#5Nj@AQ*QEQjbFRCkHRTkHRjkHRCf FQjQBPj@8NT'2MSb+L)D&Ji&rIAakHAKhGR9dFh0bFA&`F("`F("`F("`F("[Efp [Efp`F("`F(&aFA*cFh4eGAChH(PkHhYmIAeqIhq!JB+%KBD)LBZ0MT!!NT19PTL CQTZFR*fGRCbFQjUCQ*H9P*+4Mif,LSL'K)+!IRelHAGeFh&[EQaUD@GQC@4MBf* LBQ0MC'9PCfKTDfeZF(&cG(ChH(PlI(eqIhq!JB+$K)@'KiH)LBQ*LSU+Lib-MBf 1MSk1Miq1MSk1MSk1MSk1MBf0MBf-M)b-M)Z,LSU+LBL(KB5$JB"qIAYkH(CdFR& [EQaVDQPTD'KSD'KSD'KSD@PTDQYXE@j[F(*cGAGiHRaqJ)1&KiU-MT!!NT18PCD AQ*LBQ*LBQ*HAPT@8Nj+4N!#3!)q1MBb,LSQ(KS@%Ji+"J(pqIRemI(YlHRTjHAP jHAPjHAPjHAPjHAKiH(GhGhCfGA9dG(0cFR*bFR*bFR*bFR0cG(9fGhKjHRYpIRq "JS1%KSH*LSb0MT!!NC+6P*@@PjHBQ*QCQCLBPjH@PC15NBq0M)U)KS5#J(jmHRK hGA4bFA"[EQeXDfYUDQTUDQTVDfaYE@j[F(&bFh4fGhKkHhapIi#"JB+$Ji5%KB@ &KBD'KS@&KB@&KB@'KSD(KiH(L)L)L)Q*LSU+LiZ,LiZ-M)b-M)b-M)b-M)Z,LSU *L)H'KB5#JApqIAYjH(CeG(*aF'pZE@aVDQTTD@PTD@TUDfaYEQp`FR0dGRGjHRa qIi'$KBD)LSZ-MSq3!*!!NC+6Nj16Nj16Nj+5NC!!N!#2MSf0M)Z+LBL(KS@%Ji1 #JB'!IhpqIAemI(amHhYlHhYlHhYlHRTkHRTkHAPjH(KiGhGfGR9eGA4dG(4dFh0 cG(4dG(9fGRGiHAPkHheqIi##Ji5'KiL+Lib0MSq3!*'5NT16P*58P*56Nj15NC! !Mik0LiU)Ki@%JS&rIRalHRKhGR9dFh0bFR&aF("`F("`FA&aFA*bFh4dGAChH(P kHhapIRprJ)#"JB'#JS+$Ji1$Ji1$Ji1$Ji1$Ji5%K)@&KBD'KSH(L)L)LBQ+LSU +LSU+LSU,LiZ,LiZ+LSU*LBL(KS@%Ji+"IhjpHhTjGhCeG(0bFA"`Efp[EQjZEQp [Eh"aFR0dGAChH(PlI(eqJ)'#K)@'KiL+Lib-MBk1Miq3!*!!N!#3!*!!Miq1MBf -LiU*LBL(KS@&K)1#JB'!J(prIhjqIRjpIAepIAamI(amI(amI(YlHhYlHhYlHRT kHRTjHAPjH(KiGhGhGhCfGRCfGRChGhGiHATlHhapIRq"JS1%KBD(L)Q+Lib-MBk 1Miq2N!#3!*!!N!#3!)q2Mik1MBb,LiU)KiD&K)+"IhjmHhTiGhCeG(4cFR*bFA& aFA&bFR0cG(9eGRGiH(PkHRYmI(eqIRprJ)#"JB+#JS1$Ji1$K)5%K)5%Ji1$Ji5 %K)5%K)5%K)5%KB@&KSD'KiH)L)L*LBQ*LBQ*LBQ)L)L(KSD&K)5$JS+"J(pqIAa lHRPiH(GfGA4dFh0bFR*aFA&aFR*bFh4eGRGiHATmIAjrJ)+$K)@(L)Q*LSZ,M)b -MBf0MBf0MBb-LiZ+LSQ)L)H'KS@%Ji+"JB"rIRjpIAamI(YlHhYlHhYlHhYmI(a pIAepIAepIAjpIAepIAepI(amI(alHhYlHhTkHRTkHRTkHRTlHhYlI(apIAjrIi# "JS1%KBD'KiL*LSU,M)b0MBf0MSk0MBf-M)Z+LBQ)KiD&Ji+"J(pqIAalHAKhGhC eGA4dFh0cFR*bFR0cFh4eGAChH(PkHRYmIAjrJ)'#JS1%K)@&KSD'KSD(KiH(KiD 'KS@&KB@%K)5%K)5$Ji1$Ji+#JS+#JS+#JS+#Ji1$Ji1$Ji5%K)5%K)5%Ji1$JS+ "JB"rIhjqIAamHhTjHAKiGhGfGR9eGA9eGA9eGRChH(KjHRYmIAjrJ)'#Ji5&KSH )LBU+LiZ-M)f0MBf0MBf-M)b,LSU*L)H'KB5$Ji+"J(pqIAalHRTjHAPiH(KiH(K iH(KiH(PjHATkHhYmI(apIAeqIRjrIhq!J)#!J)"rIhprIhprIhprIhprIRjqIRp rIhprIi#!J)'"JS+$Ji5%KB@'KSH(KiL)L)L)L)L)L)L)KiH'KS@%Ji1#JB"rIRj pI(YkHAKhGhCfGA9eG(4dG(4dGA9fGRGiHAPkHhapIRq!JB+$K)@'KSH(L)L*LBQ *LBQ*LBQ*LBL)L)H'KS@&K)5$Ji+"JB#!IhpqIRjqIAepIAepIAepIAeqIRjqIhp rIhq!J)#!J)#!J)#!J)"rIhprIhjqIRjpIAepIAepIAepIAepIAjqIRprJ)#!JB+ #Ji1%K)@'KSH(KiL)LBQ*LBQ*LBQ)L)L(KiD'KB5$JS'!IhpqIAamHhTkHAKiGhG fGRCfGRCfGRCfGhGhH(PjHRYlI(eqIRq!JB'#Ji1%K)@&KB@&KSD'KB@&KB@&KB5 %K)1$Ji+#JS'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB'"J)#!J)#!Ihp rIRjqIAepI(alHhYkHRTjHAPjHAPjHATkHRYlHhamIAeqIhq!JB'#JS1%K)@'KSH (L)L)LBQ*LBQ*L)L)L)H(KSD&K)5$JS'!J(pqIRemI(YlHRTkHAPjHAPjHAPjHRT kHRYlI(apIAjqIhq!J)'"JS+$Ji1%K)5%K)5%K)5%K)5%Ji1$Ji+#JS+#JB'"JB' "JB'"JB'"JB'"JB+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"J)#!IhpqIRepI(amHhY lHhTkHRTkHAPjHRTkHRYlI(apIAjqIhq!JB+#Ji5%KB@'KSD(KiH)L)L)L)L(KiH (KSD'KB@%K)1#JS'!J(pqIRepI(alHhYkHRTkHRTkHRTkHRTlHhYlI(amIAeqIRj rIhq!J)#!JB'"JB'"JB'#JS+"JB+"JB'"JB'"JB'"JB'"JB'"JB'"JS+#JS1$Ji1 $K)5%K)5%K)5%K)5%Ji1$Ji+#JB'"J)"rIhjqIAamHhYkHRTjHAPjHAPiH(KiH(P jHATkHhYmI(epIRprJ)'#JS1%K)@&KSD(KiH)L)L)L)L)L)H(KiD'KS@&K)5$Ji+ #JB#!IhprIRjpIAemI(amI(YlHhYlHhYlHhamI(apIAepIAjqIRjqIhprIhprIhp rIhprIhprIhprIhprIhprIhq!J)#!J)'"JB'#JS+$Ji1%K)5&KB@&KB@&KB@&KB@ &KB5%Ji1#JS'"J)"rIRjpIAalHhTkHAPiH(KiGhGhGhGhH(KiH(PjHRTlHhapIAj rIi#"JB+$Ji5&KBD'KiH(L)L)L)L)L)L)L)H(KiH'KS@&KB5%Ji1#JS'"J)"rIhp qIRjqIAepIAepIAepI(amI(apIAepIAepIAepIAepIAepIAepIAepIAepIAepIAe qIRjqIRprIi#!JB'#JS1$K)5&KB@'KSH(L)L)L)L*LBQ)L)L)L)H(KSD'KB5%Ji+ "JB"rIhjpIAalHhTkHAPiH(KiGhGhGhKiH(KiHAPjHRTlHhamIAjqIhq!JB'#JS1 $Ji5%KB@&KBD'KSD'KSD'KSD&KB@%K)5%Ji1$JS+#JS'"JB#!J)#!IhprIhprIhp rIRjqIRjqIAepIAepIAamI(alHhYlHhYlHhTkHRTkHRTkHhYlHhamI(epIAjqIi# !JB'#Ji1%K)@'KSH(KiL)L)Q*LBQ*LBQ*L)L)KiH'KS@%K)1$JS'!J(pqIAemI(Y kHRPjH(KiGhGhGhGhGhGhH(KiHAPjHRTlHhamIAjqIhq!J)'"JS+$Ji1%K)5%KB@ &KB@&KB@&KB@&KB@&KB5%K)5%K)5%K)1$Ji1$Ji+#JS+#JS+#JB'"JB#!IhprIRj qIAepI(alHhYkHRTjHAPjHAPiH(KiHAPjHATkHRYlI(apIAjqIi#!JB+#Ji5%KBD 'KiH)L)L*LBQ*LBQ*LBQ*L)L)KiD'KB@%Ji1#JB'!IhjqIAamHhYkHRPjHAKiH(K iH(KiH(KjHAPjHRTlHhYmI(epIRjrIi#!JB'#JS+$Ji1%K)5%KB@&KB@&KB@&KB@ &KB@&KB@&KB@&KB5%K)5%K)1$Ji1#JS+"JB'"J)"rIhpqIRjpIAamHhYlHRTkHAP jHAPiH(KiH(KiH(PjHATkHRYlI(apIRjrJ)#"JS+$K)5&KBD(KiL)LBQ*LBU+LSU +LSQ*LBQ)L)H(KS@&K)1$JS'"J(pqIRemI(YkHRTjHAKiH(KiGhGhH(KiH(KjHAP jHRTkHhYmI(epIAjqIhq!J)#"JB+#JS1$Ji1%K)5%K)@&KB@&KB@&KB@&KB@&KB@ &KB@&KB@%K)5%Ji1#JS+"JB#!IhpqIRepI(alHhTkHAPjH(KiH(GhGhGhGhGhGhG iH(KjHATkHhYmIAeqIi#"JB+$K)5&KSD(KiL)LBQ*LSU+LSU+LSU*LBQ*L)L(KSD &K)5$JS+"J(prIRepI(YlHRTjHAPiH(KiH(KiH(KiH(KiH(PjHATkHRYlHhamI(e pIRjrIhq!J)'"JS+$Ji1%K)5&KBD'KSD(KiH(KiL)L)L)L)L)L)L(KiH(KSD'KB@ %K)1$JS+"J)"rIhjpIAalHhTkHAPiH(GhGhCfGRCfGRCfGRCfGhGiH(PjHRYlI(e pIRq!JB'#Ji5&KBD(KiL*LBU+LSU,LiZ,LSU+LSU*LBL)KiH'KB@%Ji1#JB#!Ihj qIAamHhYkHRPjHAKiH(KhGhGhGhGhGhGiH(KiHAPjHRTkHhYmI(apIAjqIhq!J)' "JS+$Ji5%KB@&KSD(KiH(L)L)L)L)LBQ*L)L)L)L(KiH'KS@&K)5$Ji+"J)"rIRe pI(YlHRPjH(GhGRCeGA9dG(4dG(4dG(9eGACfGhGiHATkHhapIRq!JB+#Ji5&KSH (L)Q*LSU,Lib-M)b-M)b-LiZ,LSU*L)L(KSD&K)1$JS'!J(pqIAemHhYkHAPiH(K hGhCfGRCfGRCfGRCfGRGhGhGiH(PjHRTlHhamIAeqIRq!J)'"JS1$K)5&KBD'KiH )L)Q*LBQ+LSU+LSU+LSU+LSU*LBQ)L)H'KS@%Ji1#JB"rIRepI(YkHAPiGhCfGA4 dFh0cFh*bFR*cFh0cG(4eGAChH(KjHRYmIAjrJ)'#Ji5&KSH(L)Q+LSZ-M)b0MBf 0MBf0MBf-M)Z,LSU*L)H(KS@%K)1#JB"rIRjpI(YlHRPjH(KhGhCfGR9eGA9eGA9 eGA9eGACfGRGhH(KjHATkHhamIAjqIi#"JB+$K)5&KSH(L)Q*LSU,Lib-M)b0MBf 0MBf0M)b-LiZ+LBQ)KiD&K)5$JS'!IhjpI(YkHAKhGR9eG(0cFR*bFA&aFA&aFA& bFR0cG(9eGRGiHATlI(eqIi#"JS1%KBD(L)Q+LiZ-MBf1MSk1MSk1MSk1MBf0M)Z ,LSQ)L)H'KB5$JS'!IhjpI(YkHRPiGhGfGA9dG(4cFh*bFR*bFR*bFR0cFh4dG(9 fGRGiH(PkHhapIAjrJ)'#Ji5&KSH)LBU+Lib-MBf1MSk2Miq2Miq2MSk0MBb-LiU *L)H'KB5$JS&rIRemHhPiGhCeG(0bFA&`F'p[EQjZEQjZEQp[Eh"aFR*cG(9fGhK jHhapIS#"JS5&KSH*LSZ-MBf1Mj!!N!#4NC+5NT+5NC'4N!#3!)q2MSf-LiU*L)H 'KB5$JB"rIRemHhTjH(GfGA4cFh*aFA"`F("[Efp[Eh"`F(&aFR*cG(4eGRGiHAT lI(erJ)'#Ji@'KiL*LSZ-MBk2N!#4NC+5NT16Nj16Nj+5NC'3!)q2MSf,LSQ)Ki@ %JS&rIRelHRKhGR9cFR&`EfjZE@aXDfYVDfYVDfaXE@eZEh"aFR0dGAGiHAYmIAq !JS1&KSL*LSb0MSq3!*'5NT18P*58PC@9P*58Nj+5NC!!Mik0M)Z+L)H'K)1#J(p pI(YjH(GfGA0bFA"[EfjYE@aXDfYVDfYVDfYXE'eYEQp[F(&bG(9fGhPkI(erJ)+ $KBD)LBU-MBq3!*'5Nj59PCD@PjHAPjHAPTD9PC56NT'2MSf,LSL'KB1"J(jmHRP hGR4cFA"[EQeXDfTTD'KSCfGRCfKSD@PUDfYYEQp`FA0dGRGjHhaqJ)'$K)D)LBZ -MBq3!*'5Nj59PTDAPjHAQ*HAPjD@PC@8Nj+4Mik0LiU*Ki@%JS&rIAakHAGfGA0 bFA"ZE@eXDfTUD@PSD'KSD'KSD@PUDQYXE@j[F(*cG(ChHAYmIS#"Ji@(L)U-MBq 3!*+6P*DAQ*LCQTUDQjZEQTUDQCLAPT@8Nj'2MSb+L)H&Ji&rIAYjGhCdFR&[EQa VDQPSCfCQC@9PC'4PC@9QCQGSD@TVE@j[FA0dGRKjHherJ)+%KSH*Lib1N!#4NT5 9PTHBQCQDQjZEQjZEQTUCQ*LAPT56NT!!Mif,LSL'K)1"IhelHAKfG(0aF'pYE'Y UD@KRCQCPC@9PC@9PC@CRCfKTDQYXEQpaFR4fGhPlIAq"Ji@'L)U-MT!!NC19PTH CQTZFR*fGRCkGRCfFR*ZDQCL@PC15N!#1M)U)KS5#J(jlHAKfG(*`EfeXDQPSCfC PC@4NC'0MBf4NC@9QCfKTDQYXEQpaFR4fGhPlIAq!JS5'L)Q,MBk3!*+6P*DAQ*Q CQTZEQjZEQjZEQTUCQ*H@P*15N!#1MBZ*Ki@$JAppHhTiGR4cF@pZE'YUD@KRCQ9 NC'4MBf0MBf4NC@CQCfPUDfaZF(&cGACiHRaqJ)+%KSL+M)k3!*+6PCHBQCUER*f GRTkHRTfGR*bEQTQBPT@6NC!!MSb+L)D%JAppHhPhGA4bF'pYE'YTD'GRCQ9PC'4 NC'4NC@9QCQGSD@TVE@j[FA0dGRGjHheqJ)+%KBH*Lif1N!#4Nj5@PjLCQTZER*b FR*bFR*ZEQTQBPjD8Nj'3!)k-LSQ(KB1"IhelHAGeFh*`EfeXDfPSCfGQC@9NC'4 NC'4PC@CQCfKTDQaYEh"bFh9hHAYpIS##K)D)LSb1N!#4Nj5@PjQDQjZFRCfGRCf GR*bEQTQBPjD8Nj'2MBZ+L)D%JS"qI(TiGR4bF@pZE@YUD@KRCfCQC@9PC@9PCQC RCfKTDQYXE@p`FR0eGRKjHherJ)+%KBH*LSb1Mj'5Nj@@PjLCQCUDQTZEQjUDQCQ BPjD9P*+4N!#1M)Z*Ki@$JAppHhPiGR4cF@pZE@YUD@KSCfCQC@9PC@9QCQCRD'P TDQaYER"aFR4fGhPlI(k!JS1&KiQ+M)k2NC+8PCDAQ*QDQTZEQjZEQTUCQCLAPT5 6NT!!MSf,LBH&K)+!IRakH(GeFh*aEfjYE'YUD@PSD'GRCfGRCfGSD'PUDfaYEQp `FA0dGAGiHRYpIS##Ji@'L)U,MBk3!*'5P*@@PTHBQ*QCQCQCQCLBPjD9P*15NBq 1M)Z*Ki@%JS"qI(YjGhCdFh&`EfeXDfTUD@KSCfGRCfGRCfKSD@TVE'eZEh"bFh9 fH(PlIAk!JS1&KiL+M)f1N!#4NT59PTDAQ*LBQCQCQ*LAPjD9P*15NC!!MSf-LSL (KB1#J(jpHhTiGh9dFh&`EfjYE@aVDfTUDQTUDQTUDQYVE'eZEh"aFR0dGAGiHAY mIRq!JS1&KSL*Lib1Mj!!NC+6P*@@PjHAQ*LBQ*HAPTD9P*15NC!!Mif-LSL(KB1 "J(jmHhPhGR4cFR"[EQeXE'YUDQPTD@PTD@PUDQYVE'eZEh"aFR4eGRKjHhaqIi' $K)D(LBU,MBk2NC+6P*59PTDAPjHAPjD@PT@8P*15NBq1MBZ+L)H&K)+!IhelHRP hGR4cFR&`EfjYE@aXDfYVDQTUDfYVDfaXE@j[F(&bFh4eGRGjHRYpIRq"JS5&KSL *LSb0MSq3!*'5Nj58PC@@PTD@PT@9P*56NT'3!)q1MBZ+LBH'K)+"IhemHRKhGR4 cFR"[EQeYE'YVDQTUDQPUDQTUDfaXE@j[F(&bFh9fGhPkHheqJ)'$K)D(L)U,M)k 2N!#4NT16P*@9PCD@PTD9PC58Nj+5NC!!Mif-LiQ)Ki@$JS"rIAakHAKfGA4cFR& `EfpZE@eYE'aXE'aXE'eYEQj[F("aFR0dGACiHATlI(jrJ)+$K)D(L)U,M)f1Mj! !NC+5Nj18P*@9PC@8P*56Nj+4N!#2MSf-LiQ)KS@$JS&rIRalHAKhGA4cFR&`Efj ZE@eXE'aXE'aXE'eYEQj[F("aFR0eGRGiHAYmIAk!JB+%KBD)LBU,M)f1Mj!!NC+ 6Nj18P*58P*58Nj15NC'3!)q1MBb+LBL'KB5#JApqIAYkH(GfGA4cFR&`EfpZEQe YE@eYE@eYE@jZEfp`FA&bFh4eGRGjHRYmIAq!JB1%KBD)LBU,M)f1Mj!!NC'5NT1 6Nj58Nj16Nj+5NC!!Mik0M)Z+LBL'KB1#JApqI(YkH(GfGA4cFR&`EfpZEQeYE@e XE@eYE@jZEfp`FA*cG(9fGhKjHRapIRq"JS1%KSH)LBU,M)f1Miq3!*'4NT+5NT1 6NT+5NT'4N!#2Mik0M)Z+LBH'KB1#JApqIAYkHAKfGA4cFR&aF'p[EQjYE@eYE@e YE@jZEfp`FA&bFh4eGRGiHRYmIAk!JB+$KBD(L)Q+M)f1Miq3!*'4NT+6Nj16Nj1 6Nj+5NC!!N!#2MSf-LSQ)KS@%JS'!IRelHRPhGR9dFh*aF("[EfjZE@eYE@eYE@j ZEfp`F(&bFh4eGRGiHATlIAjrJ)'#K)@'KiL*LSZ-MBk2Mj!!NC'4NT+5NT+5NT+ 4NC!!N!#2MSf-LiU*L)H'KB1#JApqIAalHAKhGR9dFh0bFA&`F'p[EfpZEQp[Efp `F(&aFR0cG(9fGhKjHRYmIAq!JB+$K)D(L)Q+Lib0MSq2N!#4NC+5NT+5NT+5NT' 4N!#2Mik0M)Z+LBL'KB5#JB"qIAalHAKhGR9dFh*aFA"`EfpZEQjZEQjZEfp`F(& aFR0dG(9fGhKjHRYmIRq!JB+$K)@'KiL*LSZ-MBk1Miq3!*!!NC'4NC'4NC'3!*! !Miq1MBb-LiU*KiD&K)1"J(pqIAYkHAKhGR9dFh*bFA&`F'p[Efp[Efp[Eh"`FA& bFR0dG(9fGhKjHRYmIAjrJB+$K)@'KiL*LSZ-MBk1Mj!!N!#4NC'4NC'4NC!!N!# 3!)q1MSf-LiU*L)H'K)1#JB"qIAalHRPiGhCeG(0bFR&aF("`Efp[Efp`F("`FA& bFh0dGACfGhKjHRYmIAjrJ)'#K)@'KiL*LSU,M)f0MSq2N!#3!*!!N!#4NC'3!*! !N!#3!)q2MSf0M)Z+LBL(KS@%Ji'!IhjpHhTjH(GfGA4dFh*aFA"`F("[Efp[F(" `F(&aFR0cG(9fGhGiHATlIAjrJ)'#Ji5&KSH)LBU,M)f1MSq2N!#3!*!!NC'4NC' 3!*!!N!#2Mik0MBb,LSQ)KiD&Ji+"J(ppI(YkHAKhGR9dG(0bFR&aFA"`F("`F(" aFA&bFR0cG(9eGRGiHATlI(eqIi#"JS1%KBD'KiL*LSZ-M)f0MSk2Miq2Miq2Miq 2MSk1MBb-LiU*L)H'KB5$JS'!IhjpHhTjH(GhGR9dFh0bFR&aFA"`F("`F(&aFA* bFh0dGA9fGhKjHRYlIAjrJ)'#Ji5&KSH)LBQ+Lib0MBk1Miq2Mj!!N!#3!)q2Miq 1MSf-M)Z+LBL(KS@%Ji+"J(jpI(YkHAKhGR9eG(0cFR*aFA&aFA"`FA&aFA*bFR0 dG(9fGRGiHATlI(eqIi#"JS1%K)@'KiL*LSZ,M)b0MBk1MSq2Miq2Mik1MSf0M)b ,LSQ)KiD&K)1#JB"rIRemHhTjH(GfGA4dFh*bFR&aFA&`F(&aFA&aFR*cG(4eGRC hH(PkHhapIRq!JB+$K)@'KiH)LBU,Lib0MBk1MSq2Miq2Miq1MSk0MBb-LiU*L)L (KS@%JS'!IhjpI(YkHAKhGRCeG(4cFh*bFR&aFA&aFA*bFR0cG(4eGAChGhKjHRY mIAjqIi#"JS1%KBD(L)Q+LSZ-M)f1MSk2Miq2Miq2Miq1MSf0M)Z,LSQ)KiD&K)1 #JB"qIAalHRPiGhGfGA4dFh*bFR&aFA&aFA&aFR*bFh0dGA9fGhKiHATlI(eqIi# "JS1%K)@'KiL*LSU,M)b0MBk1MSk2Miq1MSk1MBf-M)Z+LSQ)KiD&K)1#JB"rIRe mHhTjH(GfGR9dG(0cFR*bFR*aFA&bFR*bFh0dG(9eGRGhH(PkHhamIAjrJ)'#Ji5 &KSH(L)Q+LSZ-M)f0MBk1MSk1MSk0MBf-M)Z,LSQ)L)H'KB5$JS'!IhjpI(YkHAK hGhCeGA4cFh0bFR*bFR*bFR*cFh0dG(9eGRGhH(PkHhamIAjrJ)'#Ji5%KBD(L)L *LSU,Lib-M)f0MBf0MBf0M)b-LiZ+LSQ)KiH'KB5$JS'!IhjqIAalHRPiH(GfGR9 eG(4dFh0cFh0cFh0dG(4eGACfGhGiHAPkHhamIAjrJ)'"JS1%KB@'KiL)LBU+LiZ -M)b-M)f0MBf-M)b-LiZ+LSQ)L)H'KB5$Ji+"J(pqIAalHRTjH(GhGRCeGA4dG(4 dFh4dG(4dG(9eGRChGhKjHATlHhapIRprJ)'#JS1%KB@'KiH)LBQ+LSU,LiZ,Lib -M)Z,LiZ+LSU*LBL(KiD&KB5$JS+"J(pqIAemHhTkHAKiGhGfGR9eGA9eG(4eGA9 eGA9fGRGhH(KjHATlHhapIAjrJ)#"JS1$K)@'KSH(L)L*LBU+LSZ,LiZ,LiZ,LSU +LBQ*L)L(KSD&K)5$JS'"J(pqIAemHhYkHAPiH(GhGRCfGA9eGA9eGA9eGRCfGhG iH(PjHRTlI(apIRjrJ)#"JS1$K)@&KSD(KiL)L)Q*LBQ*LSU+LBQ*LBQ*L)L(KiD 'KB@%K)1#JS'!J(pqIRemI(YkHRPjH(KhGhGfGRCfGRCfGRCfGRGhGhKiH(PjHRT lI(apIAjrIi#"JB+$Ji5%KB@'KSH(L)L)LBQ*LBQ*LBQ*LBQ*L)L)KiH'KS@&K)1 $JS'"J(prIRemI(YlHRTjHAKiGhGhGhCfGRCfGRGhGhGiH(KjHATkHhYmI(epIRp rJ)'"JS+$K)5&KBD'KiH(L)L)L)Q*LBQ*LBL)L)L)KiH(KSD&KB5%Ji1#JS'!J(p rIRjpI(alHhYkHRPjHAKiH(KiH(KiH(KiH(KjHAPkHRYlHhamIAeqIRq!J)'"JS+ $Ji5%KB@'KSD(KiH(L)L)L)L)L)L)KiH(KiD'KS@&K)5$Ji+#JB'!J(prIRepI(a lHhYkHRPjHAPiH(KiH(KiH(KiHAPjHATkHRYlI(apIAjqIhq!J)'#JS1$K)5&KB@ 'KSD(KiH(KiH)L)H(KiH(KiD'KS@&KB5%Ji1#JS'"J)"rIhjpIAamHhYlHRTkHAP jH(KiH(KiH(KiH(KjHAPjHRTkHhYmI(epIRjrIi#!JB'#JS1$K)5&KBD'KSH(KiH (KiH(KiH(KiH(KSD'KB@&K)5$Ji+#JB'!J(pqIRepI(alHhYkHRPjHAPiH(KiH(K iH(KiH(PjHAPkHRYlHhamIAeqIRprJ)#"JB+#Ji1%K)@&KSD'KiH(KiH)L)L)L)L (KiH(KiD'KS@&K)5$Ji+#JB'!J(pqIRepI(alHhYkHRPjHAPiH(KiH(KiH(KiH(K jHAPkHRTlHhamIAeqIRprJ)#"JB+$Ji5%KB@&KSD(KiH(L)L)L)L)L)L)L)L(KiH 'KSD&KB5%Ji1#JS'"J)"rIRjpIAamHhYlHRTjHAPiH(KiH(KiH(KiH(KjHAPkHRT lHhamIAeqIRprJ)#"JB+#Ji1%K)5&KBD'KSH(KiH(KiH)KiH(KiH(KiD'KSD&KB5 %K)1$JS+"JB#!IhpqIRepI(alHhYkHRTjHAPjH(KiH(KiH(KjHAPjHATkHhYlI(a pIAjqIhq!J)'"JS+$Ji5%KB@&KSD'KiH(KiH)L)L)L)H(KiH(KSD'KB@%K)5$Ji+ "JB#!IhpqIAemI(YlHhTkHAPjH(KiH(KiH(KiH(KiH(PjHATkHRYlI(apIAjqIhq !J)'"JS+$Ji5%KB@&KSD'KSH(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+"JB#!Ihp qIRepI(alHhYkHRTjHAPjH(KiH(KiH(KiHAPjHATkHRYlI(amIAeqIRprJ)#"JB+ #Ji1%K)@&KBD'KSD(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+"JB#!IhpqIRepI(a mHhYkHRTkHAPjHAPjHAPjHAPjHAPkHRTlHhYmI(epIAjqIhq!J)'"JS+$Ji5%KB@ &KSD'KiH(KiH(KiH(KiH(KiH'KSD&KB@%K)1$JS+"JB#!IhpqIRepI(amHhYkHRT kHAPjHAPjHAPjHAPjHAPkHRTlHhYmI(apIAjqIhq!J)'"JS+$Ji5%KB@&KSD'KiH (KiH(L)L(KiH(KiH'KSD'KB@%K)1$JS+"JB#!IhpqIRepI(alHhYkHRTjHAPjHAP iH(KiHAPjHAPkHRTkHhYlI(apIAjqIhq!J)'"JS+$Ji5%K)@&KSD'KSH(KiH(KiH (KiH(KSD'KS@&KB5%Ji1$JS+"JB"rIhjqIAepI(alHhTkHRPjHAPjH(KiH(KiH(K jHAPjHATkHRYlI(amIAeqIRprJ)#"JB+#Ji1%K)@&KBD'KSH(KiH(KiH(KiH(KiD 'KSD&KB@%K)1$JS+"JB#!IhpqIAepI(alHhTkHRPjHAPjHAKiH(KiH(PjHAPjHRT kHhYmI(apIAjqIhq!J)'"JS+$Ji1%K)@&KBD'KSD(KiH(KiH(KiH(KSD'KS@&KB5 %K)1$JS+"JB#!IhpqIRepIAamHhYlHRTkHAPjHAPjHAPjHAPjHATkHRTlHhYmI(a pIAjqIhq!J)'"JS+$Ji5%K)@&KBD'KSH(KiH(KiH(KiH(KiD'KSD&KB5%K)1$JS+ "JB#!IhpqIRepIAamHhYlHRTkHRTjHAPjHAPjHAPjHRTkHRYlHhYmI(epIAjqIhq !J)'"JS+$Ji1%K)@&KBD'KSD'KiH(KiH(KiH'KSD'KB@&KB5%Ji1#JS'"JB#!Ihp qIRepIAamHhYlHhTkHRTkHAPjHAPjHAPkHRTkHRYlHhamI(epIAjqIhq!J)'"JB+ #Ji1%K)5&KB@'KSD'KSD(KiH'KSD'KSD'KB@&K)5%Ji1#JS'"J)"rIhjqIAepI(a lHhYkHRTkHAPjHAPjHAPjHAPjHATkHRTlHhYmI(apIAjqIhprJ)#"JB+#Ji1$K)5 %KB@&KSD'KSD'KSD'KSD'KSD'KB@&K)5%Ji1$JS+"JB#!IhpqIRepIAamHhYlHRT kHRPjHAPjHAPjHAPjHAPjHRTkHhYlI(amIAeqIRprJ)#"JB+#JS1$K)5%KB@&KSD 'KSD'KSH(KiD'KSD'KSD&KB@%K)5$Ji+#JB'!J)"rIhjqIAemI(alHhYkHRTkHRT jHAPjHAPjHRTkHRTlHhYlI(apIAeqIRprJ)#!JB'#JS1$Ji5%KB@&KBD'KSD'KSD 'KSD'KSD'KS@&KB@%K)5$Ji+#JB'"J)"rIhjqIRepI(amHhYlHhTkHRTkHRTkHRT kHRTkHRYlHhYmI(apIAeqIRprJ)#!JB'#JS1$Ji5%K)@&KB@'KSD'KSD'KSD'KSD 'KB@&KB5%K)1$Ji+#JB'"J)"rIhjqIRepIAamI(YlHhTkHRTkHRTkHRTkHRTkHRT lHhYlI(amIAepIRjrIi#!J)'"JS+#Ji1%K)5%KB@&KB@'KSD'KSD'KB@&KB@&K)5 %Ji1$JS+"JB'!J(prIhjqIAepI(amHhYlHhTkHRTkHRTkHRTkHRTkHRTlHhYmI(a pIAeqIRjrIi#!JB'"JS+#Ji1%K)5%KB@&KB@&KBD'KS@&KB@&KB@%K)5%Ji1$JS+ "JB'!J(prIhjqIRepIAamI(YlHhYlHRTkHRTkHRTkHRTkHhYlHhYmI(apIAeqIRj rIi#!J)'"JB+#Ji1$K)5%K)@&KB@&KB@&KB@&KB@&KB@%K)5%Ji1$JS+#JB'!J)" rIhpqIRjpIAemI(amHhYlHhYlHRTkHRTkHhYlHhYlI(amI(epIAjqIRprIi#!JB' "JS+$Ji1%K)5%KB@&KB@&KB@'KSD&KB@&KB@&K)5%K)1$Ji+#JS'"J)#!IhpqIRj pIAemI(amHhYlHhYkHRTkHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)'"JB+#JS1 $Ji5%K)5&KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjpIAepI(a mHhYlHhYlHRTkHRTkHRYlHhYlHhYmI(apIAepIRjqIhq!J)#"JB'#JS+$Ji1$K)5 %K)5&KB@&KB@&KB@&KB5%K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhY lHRTkHRTkHRTkHRTlHhYlHhamI(epIAjqIRprIi#!JB'"JS+$Ji1$K)5%K)@&KB@ &KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAepI(amHhYlHhYlHRTkHRT kHRTkHhYlHhYmI(amI(epIAjqIhprJ)#!JB'#JS+$Ji1$K)5%K)@&KB@&KB@&KB@ &KB@&KB@%K)5%Ji1$JS+#JB'!J)"rIhpqIRepIAemI(amHhYlHhYlHhTkHRTlHhY lHhYlI(amI(epIAjqIRprIi#!JB'"JS+#Ji1$K)5%K)@&KB@&KB@&KB@&KB@&KB@ %K)5%Ji1$JS+#JB'"J)#!IhprIRjpIAepI(amI(YlHhYlHhYlHhYlHhYlHhYmI(a mI(epIAjqIRjrIhq!J)#"JB+#JS+$Ji1%K)5%K)5&KB@&KB@&KB@&KB@%K)5%Ji1 $Ji+#JS'"J)#!IhprIRjqIAepI(amHhYlHhYlHRTkHRTkHRTkHhYlHhYmI(amIAe pIRjqIhq!J)#"JB'#JS+$Ji1%K)5%KB@&KB@&KB@&KB@&KB@%K)5%Ji1$Ji+#JS' "J)#!IhprIRjpIAemI(amHhYlHhTkHRTkHRTkHRTkHRYlHhYlI(amIAepIRjqIhp rJ)#!JB'"JS+#Ji1$Ji5%K)5&KB@&KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(p rIhjqIRepIAamI(alHhYlHhYlHRTkHRTkHhYlHhYlI(amI(epIAjqIRprIi#!J)' "JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&KB@&KB5%K)5%Ji1$JS+#JB'"J)#!IhpqIRj pIAepI(amI(YlHhYlHhYlHhYlHhYlHhYmI(amIAepIAjqIRprIi#!J)'"JB+#JS1 $Ji5%K)5%KB@&KB@&KB@&KB@&KB5%K)5%Ji1$JS+#JB'"J)#!IhprIRjqIAepI(a mI(alHhYlHhYlHhYlHhYlHhYmI(amI(epIAjqIRjrIi#!J)'"JB+#JS+$Ji1%K)5 %K)@&KB@&KB@&KB@%K)5%K)5$Ji1$JS+#JB'"J)#!IhprIRjqIAepIAamI(alHhY lHhYlHhYlHhYlHhYlI(amI(apIAepIRjqIhprJ)#!JB'"JS+#JS1$Ji1%K)5%K)5 %K)@&K)5%K)5%K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYkHRT kHhYlHhYlHhYmI(amIAepIRjqIhprJ)#!JB'"JS+#JS1$Ji1%K)5%K)@&KB@&KB@ &KB5%K)5%K)1$Ji1#JS+"JB'!J)"rIhjqIRepIAemI(amHhYlHhYlHhYlHhYlHhY lHhYmI(amIAepIAjqIRprIi#!J)'"JB+#JS1$Ji1%K)5%K)@&KB@&KB@&KB@&K)5 %K)5%Ji1$Ji+#JS'"JB#!IhprIRjqIAepIAamI(amHhYlHhYlHhYlHhYlHhamI(a mIAepIAjqIRprIi#!J)'"JB+#JS1$Ji1%K)5%K)5&KB@&KB@&KB@&K)5%K)5$Ji1 $JS+#JB'"J)#!IhprIRjqIAepIAamI(alHhYlHhYlHhYlHhYlHhamI(amI(epIAe qIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)5%KB@&KB@&KB@&KB5%K)5%K)1$Ji+#JS' "JB#!J(prIRjqIAepI(amI(YlHhYlHhYkHRTkHhYlHhYlHhYmI(amI(epIAjqIRp rIhq!J)#"JB'#JS+$Ji1$K)5%K)5%KB@&KB@&KB@&K)5%K)5%Ji1$JS+#JB'"J)# !IhpqIRjpIAemI(amHhYlHhYlHRTkHRTkHRTlHhYlHhYmI(amIAepIRjqIhprJ)# !JB'"JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhj qIRepIAamI(alHhYlHhYlHhYlHhYlHhYlHhYmI(amIAepIAjqIRprIi#!J)'"JB+ #JS1$Ji5%K)5%KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAe pI(amHhYlHhYlHhTkHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1 %K)5%KB@&KB@&KB@&KB@&KB@&KB@&K)5%K)1$Ji+#JB'"J)"rIhpqIRepIAamI(a lHhYlHhTkHRTkHRTkHRTlHhYlHhamI(epIAeqIRjrIhq!J)'"JB+#JS1$Ji1%K)5 %K)@&KB@&KB@&KB@&KB@%K)5%K)1$Ji+#JS'"J)#!IhpqIRjpIAemI(alHhYlHhY kHRTkHRTkHRTkHhYlHhYmI(amIAepIAjqIRprIi#!JB'"JS+#JS1$Ji5%K)5%KB@ &KB@&KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhjqIRepIAamI(YlHhYlHRTkHRT kHRTkHRYlHhYlHhamI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)@&KB@&KB@ &KB@&KB@&K)5%K)5$Ji1#JS+"JB'!J(prIhjqIRepIAamI(alHhYlHhYlHhYlHhY lHhYlHhYmI(amIAepIAjqIRprJ)#!JB'"JS+#Ji1$Ji5%K)5&KB@&KB@&KB@&KB@ &KB@&K)5%K)1$Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYlHhYlHhYlHhY lI(amI(apIAeqIRjrIhq!J)#"JB'#JS+$Ji1$K)5%K)5&KB@&KB@&KB@&KB@&KB5 %K)5$Ji1$JS+#JB'!J)"rIhpqIRjpIAemI(amHhYlHhYlHhYlHhYlHhYlHhYlI(a mI(epIAeqIRjrIhq!J)#"JB'#JS+#Ji1$Ji5%K)5%KB@&KB@&KB@&K)5%K)5%Ji1 $Ji+#JS'"JB#!IhprIRjqIAepI(amI(YlHhYlHhYlHRTkHRYlHhYlHhYmI(amIAe pIAjqIRprIi#!J)'"JB+#JS+$Ji1$K)5%K)5%KB@&KB@&KB5%K)5%K)1$Ji1#JS+ "JB'!J)"rIhpqIRjpIAemI(amHhYlHhYlHhYlHhYlHhYlHhYlI(amI(apIAeqIRj rIhprJ)#!JB'"JS+#Ji1$Ji5%K)5%K)@&KB@&KB@&KB5%K)5%K)1$Ji1#JS+"JB' !J)"rIhpqIRjpIAepI(amI(alHhYlHhYlHhYlHhYlI(amI(apIAepIRjqIRprIi# !J)'"JB'#JS+$Ji1$Ji5%K)5%K)@&KB@&KB@%K)5%K)5%Ji1$Ji+#JS'"JB#!J(p rIhjqIRjpIAepI(amI(amI(YlHhYlHhYmI(amI(amI(epIAeqIRjqIhprJ)#!J)' "JB+#JS+$Ji1$Ji5%K)5%K)5%K)5%K)5%K)5%K)5$Ji1$JS+#JB'"J)#!IhprIRj qIAepIAamI(amI(YlHhYlHhYlHhYlHhamI(amI(epIAeqIRjqIhprJ)#!J)'"JB' #JS+#Ji1$Ji1%K)5%K)5%K)5%K)5%K)5$Ji1$Ji+#JS'"JB'!J)"rIhpqIRjqIAe pIAamI(amI(YlHhYlHhYlHhYlI(amI(amIAepIAeqIRjqIhprJ)#!J)'"JB'#JS+ #Ji1$Ji1%K)5%K)5%K)5%K)5%K)1$Ji1$JS+#JS'"JB'!J)"rIhpqIRjqIAepIAa mI(amI(amI(amI(amI(amI(amI(epIAepIRjqIRprIhq!J)#"JB'"JS+#JS+$Ji1 $Ji1$K)5%K)5%K)5%Ji1$Ji1$Ji+#JS+#JB'"JB#!J(prIhpqIRjqIRepIAepIAe pI(amI(amI(amI(epIAepIAepIRjqIRjrIhprJ)#!J)'"JB'#JS+#JS1$Ji1$Ji1 %K)5%K)5%K)5%Ji1$Ji1$Ji+#JS+"JB'!J)#!IhprIhjqIRjpIAepIAemI(amI(a mI(amI(amI(epIAepIAjqIRjqIhprIi#!J)#"JB'"JB+#JS+#Ji1$Ji1$Ji1$Ji1 $Ji1$Ji1$Ji1#JS+#JS'"JB'"J)#!J(prIhpqIRjqIRepIAepIAepIAepIAamIAe pIAepIAepIAepIRjqIRjqIhprIi#!J)#!JB'"JB'#JS+#JS+#Ji1$Ji1$Ji1$Ji1 $Ji1#JS+#JS+"JB'"JB#!J)"rIhprIRjqIRjpIAepIAepIAamI(amI(amI(apIAe pIAepIAjqIRjqIRprIhprJ)#!J)#"JB'"JB+#JS+#JS+$Ji1$Ji1$Ji1$Ji1$Ji+ #JS+#JS+"JB'"JB#!J)"rIhprIhjqIRjqIRepIAepIAepIAepIAepIAepIAepIAe pIRjqIRjqIhprIhq!J)#!J)'"JB'"JS+#JS+#JS1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+ #JS+"JB'"JB#!J)#!IhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAeqIRjqIRj qIhprIhprJ)#!J)#!JB'"JB'"JS+#JS+#JS+$Ji1$Ji1$Ji1$Ji1$JS+#JS+#JS+ "JB'"JB#!J)#!IhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAepIAjqIRjqIRj rIhprIhq!J)#!JB'"JB'"JS+#JS+#JS+$Ji1$Ji1$Ji1$JS+#JS+#JS+"JB'"JB# !J)#!IhprIhpqIRjqIRjpIAepIAepIAepIAepIAepIAepIAeqIRjqIRjqIRprIhp rIi#!J)#!JB'"JB'"JB+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"J)#!J)" rIhprIhpqIRjqIRjqIAepIAepIAepIAepIAepIAepIAepIRjqIRjqIRprIhprIi# !J)#!JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"J)#!J)#!Ihp rIhprIRjqIRjqIRjqIRjqIAepIAepIAepIAjqIRjqIRjqIRjrIhprIhprJ)#!J)# !JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"JB#!J)#!J)"rIhp rIhprIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhq!J)#!J)#!JB' "JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS'"JB'"JB'"J)#!J)#!J(prIhprIhp rIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprJ)#!J)#!J)'"JB' "JB'"JS+#JS+#JS+#JS+#JS+#JB'"JB'"JB'"J)#!J)#!J)"rIhprIhprIhjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRprIhprIhq!J)#!J)#!J)'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)"rIhprIhprIhprIRjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRprIhprIhprIi#!J)#!J)#!JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)#!IhprIhprIhprIhprIRjqIRj qIRjqIRjqIRjqIRprIhprIhprIhprIi#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhpqIRj qIRjqIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIRjqIRjqIRjqIRj qIRjrIhprIhprIhprIhprJ)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB#!J)#!J)#!J)#!J(prIhprIhprIhprIhjqIRjqIRjqIRjqIRjqIRjqIRj qIRprIhprIhprIhprIi#!J)#!J)#!J)#!JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhjqIRjqIRjqIRjqIRprIhp rIhprIhprIhprIi#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIi#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprJ)#!J)#!J)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)# !J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB#"J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!IhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!!!"&3!!"!!%!"3!!!+!!!B"4!!!!!!!8!!!!!!! !44C@lSZM!!"&&!!!448!2)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !IhprIhprIhprIRTjHRTlHRCfH(*ZEfYSFR9eKBeeAeP28'CeHiU4J(CdCQ&L9PT fJAZ#J@TME@P[LBaiEfePCh"ZGib,K)Q!E@KI6&Z"M)kGPS"kEPYJEh"eK)@%LRY TG(piJ*!!KRaqEPeYJ)#*P)q1LR*KD'GPIC+3!*LMMAChDeeVIAk*NB*lJAYdIAj mNC9lG(PRAhZ,LjZBI(L!F@*NDhf9QC5HPA4QC@"aLiChK)alGhplJ)U(KSq+Hh4 UB(@0LBqHMA*[Df0cKS'(QTUAP(eSE@jRHSf'KBThES1*IBH@M)D'GR"jFQYrMj+ FPRPZG'GLHif4S+',KBTiCQGUGiD%J)k4Hh4rJSZFNRYlHfCLFhf'NBU,QT!!G'P MA(#1P*qcS(TcG@YbHQYVK)U&M)KrL)KqMU+6IhTQ@A5)JBqNPi5!HhGhDQ@"Qk# YVj*qH@*BHSjpHi4mISk,KT'0JSU1KBKqB'&hHB@VVBPiF@*RHReqLj'EUjprG'e FB'pdJTH5GA1*PCU@K(CiI(q'HfG[Hi1JVSPTG(GPFSZ+Lj+2NCZBL(GK@h"kH*+ LK('!KSLIRhPYIRjjHhPlI(4mQk52JQj*8i'-MUZVJ(5(JAGkDePNHBL9PiCiD9q 'ZUk'FQ*CES4pJ*++J)k8LheM69ChNUUiRB"lF'GqMACPFAL"QCQ#HAClNk#AN!" m8NGUJSQBNR0aKRj`GQjDBRbBX+k6H@KJFik$FhjkBh1FRB@#JRk0PSYmCP4CDhZ AVTKeF@TIF(jXCS'4MjkQNRjU9Q&qMC',EQ1'PiUBT)CcKBf"IQp,5(@KXk@+I(" @9(H)ISQ6Ii#BNhYaD&eUJSZ-IfKSHAq1TTerHhTPCRPZ@fZ(PD'MLh4J8Q1!MCb TPRk*NAYfJ("RHS*kHAGUCfplPkL5IAGJ6f9lFAD4NBfHQAeXBeYNJTZLPi5$L(G YK)afG)9pGB&lF(k1N!#9Q)q!CNY6DQaiQTq-MC&mEA*VC(Z@TDUGLiCqGiD9MBf 8JR5%Lhf%R*U4PBTdC9G19@*dMj0lGRKG6@0XCRbEQC@GNAjfEQplHhU"GepRI(Q )VDb9PC&eDQaHARU-Q+@NQ)9N8fH!LD5rUSb2KQeXG'KRJjL5GeP6@epeRVDZT)j @-d&$3@U9RD+cXU#+E&TKF)fVUTL9L'PdQCL+MB4bFR*F699QJCfZ[Dpa2d"*6R@ JSCZMNRKlJQjIG*UiZU'0H&G@GibFX+"`BA"N9fYlHB5AQije@%G%8)'aTSf+G90 AE'9QJBf-QD@HMAk!QV#f[DjmA&e9@)+DIh+'LA9QA&KJEB@NXDZJI8Y*DQjLGSK rKTqNT+kRQ*kVVCYf@9YF@RUGPBQ+GQ*fMRpbJ)H!K)PrDPGBCfa`K)PZDAY`DSq SQ*!!Rjb3!*53!)"`C@q"I'pZBdpHJSf9V+D(L*Q0FfKPB&jLFiD)KiKmHjZaSCZ RPRU!M(YUCPT19@KeEQ&ZLBf5XVfCKT')I)H$Be0EB@PrNTL3!)'*T,#[VTPmJj0 qDh&P5%CGD'GUE("eHj!!SjkBP(PGC(4N9@0SD)5PX,'iZ+qVVE1aQSZ,Ih*lH9j @BPP4Di*pGAf+QDHTS)a[APP)3PCF5daPFA@(KR"YIif6Q*b@KA0cJB0qIR4UHC' 2M+HeV,2#ZTjqC&&*6f&dHAf,KhZ0S**qK)Q#ND'9I@aNB@*UFfjA6f9bFiZNUVM !U)k@Q(09@'PfJBZ4M)5(P*+3!+#HI@jhE&06A9*1@&TEBfTN@@&qQk+MVkD"E'j VEB'+J)qh`lDYUDQSVXACe,qXM'KYHf04BfYC@'YS99*EFBUGTj&H1$!Y+6jB@9a `I(f&M(YMFTQcZVDUMA"XIBfDTTjqGj+HNj!!R+'P[Y6)TAeB1cG9Fh9TE(CZEiD 0IRb*P+'aThT65%a39fq$G9eIGBHEXl'RZFQpU*f'B9&PKCZLST9c@fU!KBqNRSZ 4NhPH6$NZ2PPNBPeC8deEJ*LCR*k2JBb0FQ9ZF(')V,QcV+kf[ml@`UDJSjZHXl# 0HRKSA'CX@%KAF)L@NS"F3e4XDPeA35Ne8f4dM*@,LU#eVjCrIBDAXlULK@j00e1 $P*bZYl[$aE56HA"`F("jFeK1A'PlT,LFJSH0M)k#E'C[HS1&GQ"(-6PBEhk2P*5 Xcp'qY+5&DfTeHA9cG(D%TVkXNj19LS5)IQjZEQPaJB*N1bJ[394VJSk8QBprHA9 K6&4[L*bKPSZ&M*@GV,ZmVU+PT*qNTk+LUkQ0EP8r0dCQLkc$al+5IA9P5M`k3&K bH'PJC'4MES@CRjD'ISZNUSppLBjiC&Y@9f&[LERLk0#YQT&h9e"HCfTeIiD9N@j 9C)#3!*D9Li5#JB&mHi4lA%C5B9aGF)@K`pE4[kCr9%*0CRU0TV+[YEZUMiH)JSQ GS*D8PiapISf1E6iS,$%j499iTm#hVUU,@cFZ2@'(QCQ9P*1)ISkYY+fe`m5kUSk "P+HKMAjV45N`8h+&Q+5CMBTf8$Xk0MpRKS*cDQCPFBZLUkqhYk'@S*U%IB@(KB4 b8dC-ARZVi2(6VCL*F'"KAf"cJ(eqKRC44f1(SUbRNh9MDACqLBprEhb"C%3p4&9 qX0,JelD*D@CfJB1*PTQARTZ$EfppP,I3`*PkEQpkLT'#E@&9363j1$*,H*HNTjC U3$4$B)'DSjU5PjD%FR5!MUh5hp6!UC10RDbNMATV@8K-Ah#%R+baXk4i5$!Y190 bJhpcD@"@9f9cHikSYVQjVjH1Qk5KRjb'Be*GFBQQa-frY+Q0E9e869f"P*!!LAj P58CFFAZ"KB&pK)GeD'eZB9TE8d9#4e9qZ0hFbELKJ@0FC@4UKCq[[lqIH("mJSL 9SD#ANC'@QjH$CPKB5c-U,M0(GU1j[E#0BNK(694QIik5QU'6I(ChH)QU[EUeX+# 8Q++GLhe`A8e0@'&fRll$a,fED8Y!0ceCFhYjHR9J6&"LFAk9TUU`XCU%LTUBMif "C8j-@@Q$U-6-bmQaKfpR8dPII)+"Jh&869eNA@0jJRPjLBPiGAelHB1!D&C86e" [RVUq[EURLhYdDQf'S+Ha`V+&D'T[Ehq5PBk-MB9pJB"XB'KS6MSm1MPDL*bHSja k9da+4%9HI)Q9UDU5IhKZEj+eYUqj[+@4PTb6LSGiA&"A8NCBISq@V,D@DP!l+64 FGA9mM)ThFRelFi+IVVI'[TQ'NjqKUlDVMRajFh'#Q*bJZXDRIQ4&)LG5EhH$LRG B68`q-N&CB'H!LR*EAf4LG)k"@dBr0$aNMk'[bpE&XkZ@GAQK[FVHjX5@K)*mJ*@ KQjUMQ(edHR&JD(ac8M`S#!)S8QZ(TU@(F@TD5P4bKC'UZ*jlF@eNFjkkYl#YRSU (N!#2MTLHLfeD4LBF0eYeNUDCG9a21c*'CR9lLj+$EQ9I@@kBXE1eXTQ#KjkZZmV )VjD+H&a5Ci'@Y-l#QA9E3N"GGAPiI(CM9P923NKJE@ebFeP!5&TQHjDCIQ4@4M) a4PpfP+k`Sj@!C@@1YF,*d-1TQ)q&KC@PTD+XX*YrHAjqKjH5FeFp'`SL5fKiLjL 6JQpG58GGGi5@UCprDfTXGSkLTU5STjH(L)b(L*56Hf*,+K8P49efN!#9K(0ZD@" GD(4lK*!!Mi0pHh4lQl5aU+HJNj5LVV5iYkL4Ih&E599hNUM#bE+5H@"5A'PRAf" PANe%4NG+A(4lH(*K5NPHFAf)MApQ8N-d-%&II*l#d,qRQBYpKk#VVE'bV+Q[XUD FSkkRPj1-GfpjJ)'+Lh*53$%K)cYCEhb,NSU#Ih4NDS'(J)D0JR4dGRH"M)k*KBZ 5Mj+KTCL6P)"I56BN+%0FDA4rHQPKC@GG@QK`GB@8MiH,MifCVlHVRjZFRkZj[,D cVjZ!G@Y@6f@#Nk+VRSZ!H'aPD@aPAQ&QBPYFA&CFE("SD@YJ@QCiJB&qG@GE98j '5Q*hJjHYVTb1L)+&NCLFTV+cUkLbYUqXXV5TSCU+JSZ3!)f2PBGS6d%p2N98C'e fIha`EQjJ@@b"KBH*JRPpKSfCTkbPRD#QRC!!NTQ6MBk%E9a32MG+BQKPCQPM8NT 06%Y8A&eTJ)4lLD1[Y,r%[V5SR*QKVV@ZUV1cR)D#HR1"PCkSYDk8JAYeE'GTE'T XGhGXDR*aEhq,HQGK9dP+A@abG(4YBPYG9NK4DR4iLTH1KBD&JBQ8P*!!PU'NRk' YXkqd[V@NQiPbG)L3!*!!PTU0H@KD6dP-9epVJBq'IS+#H(Z(K(eqHhCkKj@IUE' dUCH3!)q'K*!!Q*LDPAaM@P&!1dGBAf&PDfeUD@CF@@"B5%T68&4YM++f`EkeV+1 GR+HlamE*d-HaST@)LTQIRD'PRT@6PjZ8KRPYA9&*2cY,@f0cKiCeDQ4IB'CUE'a YE@056eC@@'apJ)L3!)Z'MC14NC52K(elIAk#NkH`Ym#mVDLQQ*1HSjZ8MAp`Cf0 NDA&qJAGdIAjjJBq3!*!!P)TiEQPKAh#,RkLUVDbKPj@4Mj@8Ki#"G@&FB@9QBea 86%G)6P4MFhCaF@T94NG+8'9pMTqZX+UQTUUVUUqiYDfUT*QFTD1JU+QGNSq2N!# 5PTbHPB9b@NY-68pKGRPcGA9XBea@99TKBepFA9pFB'aaEQeVAeeSF(*rNTbKSk# CMi@%MCZ[`F1q`m1`T+DMPSq2M)Z*I@pVFheqFfGJ8d9)99jXIi@(N!#1H@9F@&P MGBZFSD+PTD5ST*D4Q*@,Lib$HhCZE'eL6MSb1NP5A(+!I(CbBP*268TAGC!!S+U aYE5[Vl+aVl+bVVE"[,Dl[,1YTjU+J(b!LjDJTU1ENRYI9&K46&PTER*bDfGSCQ* NDA"[B9GFB9jIBPeGBea5A'a[F)#ATkfTSTf@NT5CSl5lX+UeYkbQTDDUVDLFNSK pFfpfIhY[DfGF@@&QEi16PC@@L'jA69*IEAf,Mj+CR*UNXl1ZY,DSPB4aC'*MC'9 N@d`l18K@B(+'LB0rFPT-5djDGT'FQC@8NT!!PUHeZm'rXUZXT*16SDHPSjf6M)Q 1QUUl`V@IN!"m@8!p3846C@aYEQKH@f0YF@p`FQTE8e06@&pE@@&P@%pBCh@(QkU [TT1$IB14Q*UQYlQaVkqSSk5MT+QPNRTVD'TVERGlFfTM9e"@A'9qR+LINS&ZB&T IEAk1QCQ@QTk9N!#DSk@TUCb*I(9`FRPmG@GD88Br3dj@CRk+K(PQ5$-f4&0PHiZ 5PCQFQCLJUDbbYkZAMiZ#JSqGTUQNQBk-NCUMVlfpUjQ,FeY489KTI)&jF'PJ@&G LF(GfGA"RCQ4E@'9`E@PSAP06@QL!RDk[TCH)H'ehLTDP[FV(`EDJNjQMSk'KQSC aD@TXEhZ&JAGY9d!k3NTCGT!!Q*1*HQYNC@YbJ*1AL(q"IACqMjfXZE5KPT+*IRk *NBKhCP-r06Fq8'epGfjVA88k3P0TJ*1FQT5,IRH#NTHEUE+YUULJQCfQUDLJMRC PCA5&PDZp[E+SPATTAe02A@aVB&G04%&*@'0UFA"PBQKQA@CmKS"iE&Y04dP@F)f IR*@APSKrKj5LYm5qYV+PN!#+PD'RUDUMNAphFh*lKS&dE@*+1Mj,@R+1SUQQQB0 UB'9YFi'4NSH#IhKiIi1)PCqEN!#)KiU3!*fZXUD4H9j069"6CAk0MSKmCdp"4&& PHB@#HRGdEA'%NjZQVkZHNSL#KT1HSCb8KhCYHBqKXmI3cmQjQi"bE'PaJ)L"EeY 04N9,8&GNFA"RD'YTD("hHhacB903@'4cLkHfYE'TQ)4iFhH+T+qZV+LGNBk8R+# MS*@*Ih4RBfa`D'*J98C!4%jJHC!!Rk5KNhaTCQY[HBU6NT!!M)"dGRf$MTqXUU# EQjZGT+5CMB&YA&PIBff"PCZ@L'e11$!b2&"RF@pZEfKMDR0mLTbNRCH8N!#2QDQ dXkUINB0qK)ZCVm$$a-'YMhGUBf*VGhYhF'CD8eTMC@PeHA"SCf4KD("aFhCaBPC CC(&rNk@TTTk2Hh0dGAL+RkDQTD#CP*+5P*UIQ)GrJS"jISb2L(pbB&436%jHH)b 4MiTrE&eC@&YTHAq$M)q)KSk9Qk+RSTD1M)f5S+fZU+5CJh&YDQ9UH)+)Li&T8de 38PKUI(aeGACbFRGiHiQAPBZ,Miq3!*URVl#TQiZ&KS@%N!#QXV5fXk@5Jh9[GiH 0LB5#HfeQDQeVD'KMAf"I@9YRFACjH@pE58*%6&jcJBQ6QT@3!*'2KiQ@SULVUU5 HR+'QU+LMPSU-Nj'-M)U&JAKS9dj*3dKEG)+$JAjiFh*aERH)N!#4Q*k@Ki5,NC@ @NSZ(L)U)MCQEMi4qF&j66%0'@@efHhppG'p`FR"ZFhCcG(TjGRZ#KSqFRjL8Nj! !LiZ4Q*H9NiTrHhYdF(f3!*fSXV1USCQ3!)k8QCD-KiL#GQjSB@"RE@jeHh&PC'T VCf&C6d8r2Mp'@@YfKjfST*qCM(ppJiU8RD'LT+QYUkUZXDbUVDUHPSk$HhKaBe9 04Mir5eaZJ*+DQjQ5JA0cGR*bIB@$JS+#JiU6QCfRX+kNS+#BMSQ$GfaL8dG)8Pe PF(arGfjQA&069eGIFAajGhk"JSL6Qk#LRjL8PjZCPTUFNiU)K(erLjLT[-M'Zkk HLAKbF@eSDfjTC'9PBfPbGhU!JReiHRjrIAPcD@&E8NP+9Q"VIC!!Q*@1JR9[Eh0 jKT@HS+1UVkbUUkbVUkDCN!#1LS&mIhjdD@4JA&eRFAU*P*++Ki&cD@aaG(KmI(P jH(9fJT+9NTHJSU#KRjQBQC+)JAKQ9P0DBfYeI(K[D&e24dT08&pcI(f!K)D,PCZ DQ*H5LSH+LB+#MT@9P*'*JS5,PDDh[EH[UCq1J(PiGhKmHRCbE'*KEAGeFh9cE'9 MCQehJ)"lHA0H5NG3@QChKik4M(jcG(b"K)fESCqJSTqGSkUYXV+PNBD"HA"`GRC `E'TMAf4UEAH+PjQDQSjqGACjI)"rHA0aEQPVGi1,NjU@MBL%IS#,NSf&J(9QA9Y E@f&[IB+%IQeIB@TZFAPqHA*ZE'pkKBQ,Mj11JAPeFA5%PCbHQSq%JSD,NTkVXl5 cX+DBMib+LSZ&GfeSAeKHDh&aF'jVCQ*IA@&YHAalGQG33d0*9'4dJ)Z5Mi9pIB+ <1AMS0lG(4qLT'ARjq8LB4rHhPlJSZ4NBChF'p[GiQDS+#GPSf'K)+%LBb)JAa iF@KTGB')Mj+0LB4pH(f)LiH#IA0Q@9*6@fKdHAYlGQPKBf4MBQ&F@&9489PRGAf $MC10JhpqJ)QASDZeYDQGPj@@Qk1XXE+cXDbUVDZNS*b2I@pK9P4EC@aaFQaL@PK B@fCeHR4ZCPC'2ce%@'jlJSL+KRjkHRepIS"rI(YjG(L(NT@BR*U4KhjjI)1)Lj+ EQialGA9bFhf(MC5DR+'TUk5FPik!FfeYE@aaH(q(Mib'K)&lGhGiGh9`D'*G@PT FBQeeGhf&JRKaDf4KBQ*NDQjXDfphI(jrJB*rIhppJ)Z5PCbMRT+(JS+(MC5FTV# hZVUlZ+ZJR*H1KRjeFhKpIAYlGfeK@P9158pCAPpG8N8q2$a'@@PbI)L2NBk*K)" rKBU+LSU%Ii50N!#5QCfDPT!!LSH,NC+3!*'5LhYXC'&MEAL#N!#ISCZCQC@0LBQ *KAplHRf#KSH*MSb"G@pSBQ&NCfYYD@"B8e059&jXGi'(KS&rI(9bGRPhFh&`FRG qK)L1PCL5LS4qIBL8Q*ZLSCL2LSD&KSL0NjfNSCZFSkHPT++BMSGrHRTpI(KkIRY [B9P88&4GC'PXCPK389"08&PMERGjGhKmJ)'"L)b)Ji1#J)@-N!#9RU@QT*qAN!# 0NCHCQCZDNSZ(IhGiI(YkIi+#JiL-MSf+KAjfF'PMC@jcGS#)Ki&qHRGiHhalJ)D $H'pVCepHBfGXFR4aFAGhFA"dGRCdG(0aFhGlJBZ3!)U"J)"qJBf@R+1VV+LJPSZ $JB+"J)1+MC+CQjH9NiTrHR9XC@CYGAYrJAafGA9cFRGhFR0dE@&B88Y)5e&BAf9 SD'ahIRajJ)5$KBH&KSf6PTZKSTfAP*@@Q*fHRD#PSTZAMAPTC'4NCQeeI)1+M)L $Ih9VDQeUCQP`G(f,Nj15N!#+Ji'"J(apK)@"IRGR9Nj,6&KVG(CkJ)"mHRTjH(K pJ)@,Li5$Lik+L)U)KB@+NCUKT+'GQ)jlD'&LBfk#NjbLSTD1Mif%I(b!JS+'M)k 1MSb+MT'&FfTTD'TeHhK`CPK+3$Ne0d*5BQeiK)D$K)L,NCLCPTQIS*kJTDDLS+1 KPSU$Ii12PT55N!#$E@"GA@"RF(Z$L)L#HRCdEfjjJS1#KBL0PjfGR*ZAM)"mIS' #KSZ,KRaS88C%3802B'aeI)"rHhGdFhGrKSQ1PCD6Q++PSTf8L(ehGRU$MC@BQ*H 2J(9bFR0kKSk9QjU4MBk0LBH)M)f,LSU0P*H5Mj'2JACfHAPjHhThF@9A5dC$2MT "6eTKD'jcHB'$KBk@Q*DAR++SVE+cVUHHP)f,L)@*P*UDQ*'$FfCHA'"SF(CpK)Q )KiZ,KS1%JhpqJ)1-PTZFR*bCMi@"IhYkJ)5%JRPQ8dP"1ce*9f*SDfaXDfTUERU +NC'8Pj@4NTDCRTkCNSf*K)#$M*@DR*b6KAP[CfPdJ)L6R*bANiq-LBH)M*!!Nj5 3!)f3!*'1MT16Li9rH(4cFR9kI(9R@&"+36T!69GIC@KXFR9eGhq(LBL*Mj5@QCZ HSkLMPj!!M)5!KT@NUkZNQj+(H@aQDQpcHB#%JAprJBD-M)H$JB#"KSf9QjqKRC1 (IRCdHS@0P*D0I'TH9P&49f&YGAKhG(*[D@CUEQaRCQT`Ghq*PCkGNSH!HR9bHSf JV,1dVkLGN!#(LBq6Nj@BQCH6NC+8PT@3!)Z*KAaiISH2PCD3!)GlEQ9NDR"cGAP jEQ0G@945@@0ZGhakHAYlH(ChHAPkI(jrJiU3!*LLTjq4KhjiHS13!*ZMTUDPSTb 3!)*mIS'$LC!!NT+5NT+8NiU!HhYlHhk&MC1AQTH1JR9TCQadHAk$JATeF@YNAf" QF(PlGh0cFh&bG(0[DfTSCfY`GAf'M)Q!Gh&VDR1"MTUNU+LSSjU9PCQGSD@RTk@ LRjfHS*k9MBGrHRTrKSq8NSPrFf4A899FB@G[GA9`D&pC9eKGC@jcFh0fHhq#Ji* rHhCbFhZ'M*'@Pj+*IR0ZF(9rM*QMTkDLR*5-LSf3!*5APjDCR*fFQjQ6Li@#JS+ &M*+@QC5+J(GYC'9YGAk%L)U*JhKYCQ4QCQCTDQPTER*eH(GcF'eTC@9UFRZ%MC! !LAedDfCTF(Q(QUHXVl'ZUD1LTUZ[XE#ZUkQPSD'LR*11LiL&KBD-P*D3!)GqG@T G999FC'pjIi&pEep@8e*48eTLCfPYGRarI(GeGhGbFRKrKSf9Qjb9KhKaEQpfJT+ KU+LQSjb@NBf0P*QCQ*UDPT'0LBH&K)1$JB'$L*'BPBb$GQGJBQPcIiQ0MBQ!F@& B9ePFB@KUDQKQCQY[EQYVE'YQBQ&REhQ&LiU#G@CE@PpTHSqHTDHRTD+HR+#SX,5 bVUfVTU+LSk#BMSD%K)5)NCZKSCL+H'"*2N06ChKrIRYbC9P66de18PaSEQjVDQe hIi5'Ki&iFh9pL*+AQCD0J(*PB@9ZHikITD+FPC!!MSf0P*kNTkLQSjkBPCD9MiG qGA&dHS@6QCD0JhGVB9YFChL(NT@4KhCM@&C@9ePGB'4SDh"hIApqI(TfEQGQDh@ $N!#9NiYkD9jEA@4aJBqDRTfCPC1@Qk'VXDqVUDQTUUUTTTq9LB"iFh0jKTDDNB0 `@dY(6&GQFRTqIRGVA9"+58e9B'GSCQ4QEhPqIAYjG(&bGi'1Q*fHQT!!IfTD9Pa QGB54QTkFPj58NT'9R++QTUDQTkQXV+DHNi4iGA4dH(k"J(YaD'*JB@4VFhk%JRa eE@PTDQKQC&pHBfGVFRU$L)H#IRKZDQjjLTUHQ)k!EPj88PGMF(b(Mj+4MBZ1NTD DRU#IRk#PVVDjYl5ZS)YiF("fIBD0MBGkDPjFA&aLEA9jHA9ZCPa99&GGBQ9NC'C RDh@!KBD%IhYlI(k'NTfLSCb5JQpLB'C`I)D0Nj@5M)Q)L)U-NTZJSD+NU+bXUD@ KPS9jG(0fHi'&L)4kEf9IAf&SG(q#IA9YCQ*HA'"SE@eYEh*fH(b%LiZ'IR4XDQa fL*LHR*@+IR*RB'&PDR0lJB1"IAb#LT'DRjqISD+QV,+eYE+USC5)Ji5)N!#DRjf 8JfpL@eTHC@jeH(0YCep96Ne4@&jIAQ"ND'piJ)@'J(KcEfpaHBHCTkZPQSTlF'T UFhb!JiH)Ki5$KBZ4PjfJS*kEQ*ZPV+fUST@&H(&bHB'(MBk+J(*L@PYJD(4pIRT `C9pHAPjKCQPTCQ4REA0pLC!!NijrF@YVF(f2RD5LQ)f$GfaPBQC`H(YlHhKdGRk )NjQBPTHCQjqQVV5fXUZIMi&mISQDTDHKPS9bC&eFB@CVF(&YC9Y46%T,6e9B8dj 16e9IDRD"L)L"HA9jJBbEUDqZTCH'HR&UEAL$Liq4NBf&Ii'(MT+6NT'2LSH0QU5 RTjq8LB"mIiL5QCbFQ)emDQ"E@Q"QDfp[D@"FA&eF@9KEA9YC@Q*[ISU4P)q#GR* dIBZDTkqZTCD%FfGLBfajJS@%J(emIS'%LBZ-M)b-MT1ETV#cVkDCMSH&LjLRX,' VRiaiCPaDAQ0RDQaTB9G48&"28&056NT*6&CPFhq&L)@!HRKmK*'IUUkYSj'!G@p ZFhf&M)q0LSL&Ji1'Lj!!N!#-LBH&L*!!R+HXUU1DNBU'Kif@QjbDP)KhD@*JC'T VE'aTB&K999GA9PPGAepHAfGeJSZ5PC'(IhTmKT+GTUQPQieqFQTRCfjhI(jpHA9 dGAGpJ(pqIRk!KBbAT,#fYDZGNBU)MjbTVl#URj+%Gh"[FRCjHACX@dT"2d**8&0 88e"08&KLDh4lJ)+!I(f$MTkXY,LeTj5&HhCfHAk'M)q0KRplHAKjI(ppH(4cHB5 1PCfLS*U6LS&mIB@3!*ZJRjH-JRTfHB#%K)1!HA"QA9C899CCA&jIA9jRFhk%KS* kG(0dIBZBSUUYUU#4JRKcFR9kIS&rGh"ZEQp`FhCkIRprJSD-NjZLTU5EMiL&L*! !QCqNTD#CNib'JS'&M*'4Li"bC&aA9eTF@PG98e09@&jQEA&eGR4aFRU+QkL`XUf JNSH!IS+&LBk3!)f&I(CfHi#'M)q-Ki"lHRf#LT1DQT5+IhGcG(f+PCUBMi9mGA& hJBf9Q*50K(T`DQGRD'GQC@4JAQ0YH(pqH(&YDfadJT+ITDDPRj1'IAPjI(pqHR0 UC@CXFhU!K)H)KS1!J)5,NTLFQ)f#HhZ#M*@HTUDHNiH!IS'(NCZHQBk"G@aPB'& MC'0J@9*-5NY4@f4UDfKPC@K`Ij+KV,#XTCb4Ki5&L)b-LSL%IAYqKBb6PT11KRY fGRPrKSb2MSGpFfp`GAq)N!#9PBk)K)1)NCUKT+#BMB&fEfaYEh"YCf&F9P4BB'P `F@jUCQ0NDRD*QkDVUCq4KRjpJSD)Ki@"I(GbF(0kJ)D+M)Z(JAq$LBq6NSb&IhP iIB@1PCfKSTk@N!#2NCHITDDKPSCkFh"ZE@YSC&j@6dY)5P"AAf*LAejICA'"NCk QU+@JQT10Lif6PjD6MSCpGhCjJ)L,M)Z)JRelIB+(LBU+Ki&mGhL!LT1DRCZ8M)D %KiZ1NC58NBZ%IAG`E'YTCf4JA9eKC@PZF'pYDQPUEh@!MTULTU1FPT!!LiU0MBQ %IhYfEfPRD@abHAaqIRakI)+*MBk,L)H&K)L3!*QJTUHQSjZ5MSf1NC59PT5-JRT dF'jUCQ0JA&G88P0BA@4VEfjUD'P[H)'*NTUGRCbDQ*H9PC@6MSL"HRCeGAKpIhe kGA&aFRGrKif2N!#1LSD$JiU6QTkIR*H5M)H'LBZ0MSq1LAphFh&[E@YSC@&F@ep QDQe`Fh4aE@aZFRL#MTQKT+'IRTkFQTL8N!#+JhaiFfjVDQeaFQpZEh*hI)''LBQ 'KBD)LSf3!*@ERU#KRjU@PCDCQjL4LS0mGh4cG(0`E'KPB9eD@PjND'YYEQaTCQC YGAZ#LT'@Q*H@Q*QDR*fGQT@-KB1"IhjpHRCdFR*cGRPqK)Q0M)H%JAemIi@+MBq 2NC15Mib)KB1"JS1#IRakGR0ZD'*HA&aJCQaaFh0dGRGhGA0bFh9jJ)L,MBf1NC5 9P*13!)f)K(pjGA"YEA"bFh9jIS1(LBb1MBZ*L)H'Ji'%LBf5PjQEQjD5Mib)K)+ #JRpkGR&VCQ&GA&jJAejLD'aZE@eZF(&aFR0dGhb#LBf1N!#5Nj56NBk0LiL'KiH (KB&qI(YlIB#%L)b3!*5@P*!!M)Q&JApqIi1(Lik2MBU&J(jqIRq#Ji*rH(&VCQ& GAQ0SEA&eH(TlIS+'Ki0mH(KiH(TpJSD+M)q4N!#0LSL*LSD!I(PcE@TTD@ebH)+ -NT56P*HAP*+3!)b'Ji1<!!NjDERjkCNSU%J(q"K)*lG'aQBf&IAf*PCfYZEh& bFR4iHAGbEQaXF(CrKiZ1MSZ*L)D$Ji@(L)Q)KB*mGh9hHAk#K)Q1N!#4PCLAPC! !LiH$IherK)U2NC'3!)U"I(YmJ)@'JhpkFfeSC'4QD@peGRChHRk#KSD&JRYeF'e XEA*kJSL,LSH$IhjqIS#!I(KeF@eUD@Y`HB#&LSk3!*!!MSq6PTD@Niq,L)@%L)k 6Q*Q@MiL!IAapJ)+"IAPcE'PSCfCSDfjbG(9iHhaqIhjmGfjSCQGTFAb&Liq1LiH #IATjHhk!J(ppH(9dGRU#L)U0NC58PjQCQ*LAPC'0LBD%Kib3!*!!MSQ"HA9cG(Z !Ji@%IhK[D'*LC'TaGhb"Ji@)LiZ*LBH"HR0ZE'pfISH-Miq)IhPeFA"aFA"[E'K PC@KZGS'*Mj'5P*DAQjqKSU#CN!#+K)#$Lj5GSD#ENiQ"IRq$L)U)KB"fDf9KB@C YG(TpI(PiHAf!IRajFfYPBQ0XH)52Q*U8LS"iFh"[FA4hGhGfG(GjHRf%LSq8Q*U FRCfIS*kAMB&iFh0hJBZ3!*!!MSH"HhGeHB+*MBq0L)"fF'pbGAGiHAYmHRPpJS@ &KB0qH'pTD@jhJ)D*LSCpGR*`F(&bFh4bE@GPCQP[Gi'+N!#6PCQFRCfEQTQ5L(p iG(4iJSkCRTbAN!#,Ki@'Lik-LBH%J(ajGR4dFh*cG(0bFA0hH(GfGA"VD'KYGhq &M*+6MSGrHAGeGRGiGh4`EA"eHRk%LSk3!*'4NC+5NT+5N!#+J(KcFR4kJSZ3!*+ 2LSH$Ihq%Lj5CQTH6M)4qHhTlHR9bFR*aFRGlIAq!IRYfF'e[GS#)M)k0KhpjGA& aFR"ZE@YRC@4REA9pKBL*LSU,MC'8PCD8MiH!HRCfHi10PCQCPC!!M)Q(LT'9PjH @NBU#HA0aFR0eGA4cFA"bGACeFQeRC'0PEAH"LT+APT!!KhjiGA4fGR9dFh&`FA4 hHi#%L)b-LBD&KSU1N!#5MSCrHhPlIS'&Lik1M)U&JB'&Lj+9PC'-KS1"J)'$Ji' !IhajGR4dGhTlH(4`Efj[GRq'M)q0L)4qHA9dG(*`Eh"aFA&dGRKjHAKjHhamJ)@ ,N!#9PC13!)U$Ihq#Kib4PTL@Nj+5NC+5N!#1M)H!I(TiH(TpJ)"mGh&YE'aYEh* cFR&aEfj[G(f*NCDCPT!!KhpkHRalHAYmHRPjHAPkHRKiHAGeG(4hHhq&LBU*L)@ #JS@(LT!!P*D6MSL(KiL,MBk2M)H$JAppIS'"J(afF@eXEA*jJBD(JhjjFh"bGhk (M)k2Li0kGA*bG(CiH(9`E'TTDfj[EQp`EfpbGAU"Kib2Mik,LBZ4Q*qQV+fUT*k ANSq1Mj+6MSCpGR*`Eh&cF'YQBQ0QD@acHRjqHR0XCQ9TFi'1PTL@NBU$Ii##K)D )Ki&kF@YUE'pcGRGfF@TQCQP[GRYrK)H(KiU1NjLHT+LQSCZ@NBq3!*!!N!#2LB* mGh*[E@aYEfpXD@KTEA4qL)f,KS&kGA0dH)#)MC!!NBk)J(YlIi5'KB"jFQYNAej IAPjKBf0MBQ9VGAq*N!#5NBf+M*'ARkL`Y,DcVDHLR*H9PC52KRadE'CMBf0LBQ* LC@PVEA*hHhjpH(0`Eh0kK)f9PjD8NSf,Lib1Mib'J(P`DQKTEA"`EQTNAeeIC'a fISD+LSL%JS1+NTfPUUURSTkEQTUDQjU6M)4lFfjVE'pbFR&YDfYYFAL"KSL'JAY hGA0eIBD0NT56MiU'KBH*LSH!H(&VCQ4PCQKUD'4LB'&PEAL'MT'3!)f(JB#%Lj@ JTUUXUU@KRCbISk@LQj'&HR"XE'paG(4aE@TSD'Y`GhamH(0YD@TZGAq,NjLCPBk *KiD)M)q0KhedE@TUEh9kI(TfF'aUDR"kJSL,LiL%J(k$M*DITDHQSCQ5N!#4NT5 8NSk*J(KeGRKmIi'"Hh&UCfPZGAb"K)&jFh&cGhq*NjUFQ*+,K)"rJ)5)Ki"hF'P PC@T[GAGdEfaUDQacISH-N!#3!)Z&JB''NCfQV+kVTCb9NC'6PCLCPSk&I(GiHhq #JhphF'PPC'9TER0eG("VDQjeJ)bAR*bAMiL%JB#$KiL'J(KaE'TYGAk%KB&lGA& ZF(H!L)f3!*!!MBU'KSZ8RD@STU#@Li5%KBL-MBb*K(pmI(q&LBb+JhKXBejIC@j hIB'"IATjHRq(N!#AQjU9Li*mHharK)@!GfpRB@&QEA9kHhG`D'4PDR*pL*!!P*5 4N!#4NjDGTDUVTTb6M)L(Lj!!Nj13!)Z'JRprJSD)LB9pFfPJA&jNEA9iHACbEh" dHi@2PTQANSb'Ji'#K)0rHA"TBf&PE(9mJS0qGQeSCfefIiL3!*@@PT56PCQGSD' GQ*11L)D'KSL+Ki5"IRalIB'&Ki@!HA&VD'GXFhTqIhejGA0cHS@4QTqJR*@-KS+ #JB'!I(9YC&jFAQ&PDQjZDf4IAf*UGS11PTZFQTUCQCZISk5KR*L8NT'5PCHBPT! !LS4qHRKiH(TkGh0`E@YVER*fH(GdF@p[FhU%MT@BQ*D2LBD'KiQ*Ki*lF@KLAf" ND@pcG(0aEQYZGS#+NTHCQ*D6NC'5PTQDQCH5MSU)LBU0MSb(JAYhG(4eGRCiH(C cF'eXER0iIB#!IRemIB+*Mj5@PT53!)U'KBD)L)H#I(9VBPaC@PeKC@KUDQPUERH "LT+9PC'0LSQ,MT+AR*kGQTH8NSq0Mj'3!)Z'J(ThGA9iHhYkH(0[E'TVF(9jI(e lHAGfGhb#KSL*L)D&K)1$K)D'JhefE@4IAf9XFhPmIAYjH(Z"Kif5P*53!)Z)KiL *MT5BQjUAP*!!LS@$JS+"IRakHAPjHhk!JApkGR*[F(9kIi@)Ki@"IRerJiH,MSq 2M)L&JS'"J(jjG'aPAeeICQecH(YlHAGeGAPrKSb2Mif,LSU,MBq6PC@9Niq-LSQ *LBU*KS*qHhYmIAepHhPeFR"[FA9mJB5'KB&pHRKjIS+&KiH(KB1!IRalHAGbE@P PBf4TF(KqJS5$J(ajHAf$LBf3!*'3!)k-M)f3!*18P*+2LSD%Ji1$JB'!IRakH(K iH(PkHA4`E'TVF(9lJ)1$JS'!JS5)MC1AQ*H4LS4qHACfGRCcEfYSC@9SEA*fHAP hG(&`FRGmJSH*LSU+LBZ0Mj'4NC!!Mik-M)b0Miq1M)L$IAPhGhPkH(CdF@pZEQp bGhb!JS"pHhYqK)Z3!*15MiU%J(aiGA9hGR4`DQ4JB@K`H(k"JB"rIReqJ)5)M*! !NC!!MSU(KSQ-MSq1MSf,L)L)KS5#J(jkGA&[Efp`FA&`EfeXER0hHherJB5'KiQ 0NTHDQjZAN!#*JhjlHhYkH(9ZCf*HA9jLD@pdGhKjH(KjIB''LBQ)Ki@%KBD(LSZ -MT!!N!#3!)q1N!#4N!#0LS9rHA9bFA"ZE@jZEQjZER"cGRb"K)@&KSH*Lib-M)Z *L)H&JRpmHAGeF@TMA9YEAQ9ZGAYrJS5'KB5%KSL+LiZ+L)D%K)5&KSH)Lik2Mif ,L)5"IRTfFQpYE'aXDfYYEQjZF(0iIB#%L)Z,LSU+M)q3!*'6Nj'0L)5"IAPfFQj TBPY@9PTICQjeHhjrIRepIi'$KB@'KB@%JS"rJ)1)M*!!NT+4NC+4MSb(J(TeFA" `Efj[FA0dG(0cGAPqK)Q,LSL%JS#"JiH*Lik2M)Q'JAelH(4ZCf"E@&KFBfTbHAq $KSD'KSH*Lif0M)Q&J(jmHhk#KSQ0Miq1M)L'JhplGh9bEQeZFA0bFh4cFh4fHAk $KiQ,LiZ*KS5&L)b3!*+5N!#0LBH&JRplGR&VC9pE@&PGCR"iIS#!IhjqIi#!JB1 %Ji&qI(apIi1(LBQ*LBL*LBQ(JhjkHAPiH(KiHAPjHAPiH(PmJSL,MBk0LSD$JS# !JB1'L)L)KS1"IRakGR&UBeeD@PjME(CqJiD(KiD%Ji5(LBZ,L)D%K)5&KiL*LBL )Ki@"IRakHAKhGR9cFR0eGRGiHAYpIi##K)D)LSZ,LBD$Ji5(Lik3!)q1LiQ(K)" pHhKeF@aQBQ"LCfjfIB+%K)1"IhepIS'&LBb-LBH'KSH(KS@%JS"rIi"rIAYlI(Y jGR4cFh4hHhq"JS5'LBb1Miq1M)L&JAppIS'&LBZ,LB@"IRakGh4[DQCLB@&MCQY aHS''KiD&Ji1(LSf3!*'2MSf-LSQ)KiL)L)H%IhYjGhKiGh9cEfeYE@j`G(KpJSD )L)L)LBZ-M)b+L)D&KBD*Lib0MBf,Ki*pHA9cF@jVD@GRD'a`G(KlIAprIRepIi+ 'Liq5NT!!MBU(KSD&KBD%Ji1#J(ekH(GfGR9cFA&bGRTqJ)+&KiL+M)k1MSk0M)Q %IhamIB'&LBU*KS0qHRCcEfaUDQTUDfaZF(0iIB'#JS'!JS5(M*!!P*D@P*+1LSH (L)U+Ki@$JApmHACbF("`F(&aFA*dH(b!Ji@(KiQ-MSq3!*!!MBU(Ji'"JiD+MSq 1LiD"I(GdFh*bFA"ZER"aFh9iHRaqIAYjGhKlJBL1NC+4Mib+LSL(KiH(KiD&Ji" pHhYkHAKhGhGfGRGkI(f"K)L,MBf1MSk-LS@"IhepJ)5(LBL&JAjmHAGfGA9fGh9 cFA*bFh4iHRYmI(apIi'$KiZ1Mj!!N!#2MSb-MBk1MSf-LSL'KB5"IRYiG(*aFA& bFhCkIS#"JB'#Ji5(LBQ)KiD&KBD)LSb0LiQ&JAelHherJ)"rI(TjH(GfGA9fH(K fG(0dH(f#KSU-M)Z+LSU,M)k3!*!!NC!!Mif,LBQ)KS*rI(PhGhKiH(KjHRYmI(e qJ)5)M)f,L)@$JS1&KiQ*Ki1"J(jmHhaqJ)'!IATfGA4dGACfGhGhGhPlIB'%KiU ,LiU)KiQ-N!#8PTD9P*+3!)q0M)Q'JhpmHRGdFh4eGRGfGA4bFhCkIi5(L)L(KB5 %K)D)LSb,LBD%JS'"JB+#JS"pHhPiGhCfGRGhGR9dG(9iIB+&KiH(KB1#JiD+Mj+ 8PC13!)k0MBk1MBZ)K)'!IRakHAPiGR9dG(9hHi'(LSU(K)&rIRq#KBH)L)H&JAj mIAjrJB"qHhGeGA4eGhGiHATjHATlIS+'LBU)KS1"J)+(M*!!NT15NT'2Miq3!*! !Mif*K(pkGhChHRamHR9aF(&cGRYrJS1#J(jmI(k"KSU-M)U'Ji"rJ)#!J(pqIAa kH(KjHheqIAajGR9hHi#%KSD'K)&rIRq#KBL,MBb,LSQ+M)k3!*!!Mib)KB+!Ii# "JS+!IAPeG(CiI)##JS&rIAamIS#$KBD&Ji"pHhTkHhapIAakH(9cG(CjHheqIRe lHRYqJB@(L)H&JRprJ)+&LBZ-MBb-LiU+M)k1M)Q&JAjpIS'$K)5"IAKdFA"aFhG kI(emHRPjHhf!Ji@&K)+"IhjqIRjrIhemHRPjHRarJS1#J(ajH(PlIS'#Ji5#J(j mI(k"K)H)L)D&K)5'L)Q,LiZ*L)D&KBD(L)Q(JhjjGR4eH(TmIRjqIAepI(eqIi# !IhekH(GhH(KjHAGeGAChHAYpIi#"J(ppI(aqJ)1'KSD&KB@&KBD(KiH)KiD&KBD (L)Q+LBH%JS'"JS5'KiD%J(aiGA4dGRKkHhamHhYlI(jrJB'"J(jlHAKhGhGiHAP jHRTlIB##Ji+"IhjpIAjrJB+%KSD'KSD&K)5&KS@%Ji'"JB'#Ji5&KB@&KB5$Ji1 &KSD&Ji"qI(apIAepIAeqIRprIi#!J)"rIAThGA9dG(4dFh4eGRGiH(PkHheqIAa mIAk"K)D)L)L)KiH)L)L)KiD'KSH(KiH(KiD&Ji&qI(YlIAq!JS+"J(ppI(YlI(a pIAalHhYpIi#"JB#!IhelHRPhGRChH(KhGhGjHhapIAemHhYlI(q"JS1&KSD&Ji' "JS1%K)1#JS1$K)@&KB5$JS'!IRalIAq"Ji5%K)1#JS+#Ji+#JB#!J(prJ)'#JS' !IRakH(GfGA9dFh0bFR*cGACiHATkHAKhHAb!Ji5&KSD'KSD(KiH)L)Q*LBL(KiH )L)L'Ji"pHhTkHhaqIi#!IhjqIRq!JS1$JRppI(amIAk!J)'#JB'!IRalHRTjGhC dG(9hHRaqIRjmHRKhGhPlIS#$KB@%Ji+#K)@'KiL)KiD&K)1#JS+#JS&rIRemI(a qIRprIhq!JB1&KB@&KB@%K)1#JS+$Ji1#JApqIAalHAKhGA0bFA&cG(GjHRTjGh9 cFh9hHhf!Ji@&KS@&KBH)Lif2N!#1M)Z*L)D%Ji'!IhjpIAamIAepIAemI(erJB1 $Ji1"JB'#Ji1%K)5%K)1"J(pqIAakHAKfGRChHATlI(amHhTiGR9fH(YpIi'"JB# !JB1&KiQ-MBf-LSH%JS'"JB+!IRemIAk!JB+"J(jpIAeqJ)'%KiQ*L)H'KSD(L)H 'KB1!IRepHhTiGhCfGA9eGA9hH(PjH(CdFh0dGRKkIAq"JS+#Ji@)Lik3!*!!Mif ,LSU+LBH'K)+!IRjqIi##Ji+!IAPhGhKlIi+&KiH&K)+"JB+%KiL)Ki@#J(jpI(Y kH(KiH(PkHRYmIAepI(TjGhCfGhPlI(apIRq"K)L+LiZ,LBH&K)5&KSD'KB1!IRe qJ)+%KB@$JAejH(KlJ)@+MBf+Ki5#JS1&KSH)KiD%JRppHhTkHAKhGR9eGRGiHAT kHRKfG(0cG(GkI(k!JB+$KSL+LiZ+LBQ*LSU-M)b,LBH%JS'"JB+$K)5"IAPhGRG kIS1'KiD%JS"qIAerJS@(L)H&Ji'!IhjqIAalHRTjHAPlI(eqIAakH(ChH(PlIAj rJ)'$K)5&KB@&KB@&KBD)LSU*Ki@#J(q!J)+$K)5$JAjlHATpJ)5)LBQ)KS5$JB' "JS5&KSD&K)+"JB'!IhekH(GfGRGjHRYlHhPhGR4dGAKlIS'#JS+#JS1%KBD'KiH )LBQ*LSQ*L)H'KB5$JS+$Ji+"IRakHRTmIi'$K)@%Ji&rIReqIi#"JB'"JB+$Ji1 #J(jmHRKiH(TpIi#!IhelHAPjHAYpIi#"JB#!Ii#"JS1%K)5$Ji+$Ji1$JS+"JB' #JS+$Ji1$JAppI(erJS@(L)L(KS@%Ji+#JS+"JB'!J)'"JB'!IRYiGR9fH(TpIhp qIAYjGhCfH(YpIhprIRepIRq"Ji5&KSD&K)5%K)@'KS@&K)1$Ji5%K)1#JApqIAj qJ)'#Ji1#JB"rIhprIi"rIhprIhprIhjpI(YjH(KjI(q"Ji1#J(jmHhYmIAprIhj pI(YlI(k!JS1%Ji+"J)#!JS1$JS&rIRjqJ)+$K)@%Ji'!Ihq!JB1%KB@&K)1$JS+ #Ji1$Ji+"J(pqIRepHhPiH(KjHheqIhpqI(TkHATlIAq!IhelHRPkI(k!JS1%K)5 $Ji1$K)@&K)5#JB#"JS1%KB@%JS"rIRjqIi'#Ji1$JB#!Ihq!JB'"J)"rIhprIRj pI(YlHRTlIAjrJ)#!J(prJ)#!J)#!IhemHhYlI(jrJ)'#JS'#JS+$JS+"J(jpIAe qIi'#Ji5$JS"qIRjrJB1%KB@&K)1$Ji5&KB@%Ji+!J)#!J)"qIAYkHAPjHRYmIAe qIRepI(apIAjqIRemHhYlHheqIi'#Ji1%K)5&KB5%Ji+"J)#!JB'#JS+"JB"rIhq !JB+$Ji+"J)#!JB+$Ji1"J(prIhprJ)"rIRemHRTkHhaqJ)'#JS'!IhjpIAeqIRj qIRepIAepIAjrIi#"JS1$Ji+"J(prIRepIRjrJ)#!IhjqIi#"JS1$Ji+#JB'#K)@ 'KSD%Ji+"J)#!J)#!IhemHhTkHhapIRq!IhemHRTkHhYmIAepIAemI(amIAk!JB+ $Ji5&KB@&KB5$JS'!IhprIi#!J)"rIhprIhprIhprIhq!JS+$Ji+#JB'!IhjqIRj qIRepIAepIRq!JB+#JB"qIAamI(amIAepI(alHhYlI(eqJ)'"JS+#JS+"JB'!Ihj qIRjqIhprIhprIRjqIRjrJ)'#JS1%K)@&KB@%K)1#JB"rIRjpI(apIAjrIi#"JB# !IhemHhTkHRTkHhYkHRPjHATlIAjrJ)'"JS+$Ji1$K)5%Ji+"JB#!J)#!J(pqIAe mI(apIRq!JB'#JS+#JS+#JB'"J(prIRjpIAepIRq!JB+#JS+"JB"rIRepI(amI(a mHhYlHhYmIAjqIi#"JB'#JS+#JS+"JB#!J)#!J)#!IhjpIAamI(eqIhq!JB+$Ji5 %KB@&K)5$JS'!IhpqIRjrIi#"JB'"JB"rIhjpI(alHhYlHhTkHRTlHhamIAepIRq !JB+#Ji1$Ji1$Ji+#JS+#JS+"J(pqIAamIAepIRjrIi#!JB+$Ji1$Ji+"J(prIhp rIhq!J)'"JB#!J)#!J)"rIRjpIAjqIRepIAemI(amI(apIRq!JB'#JS+"JB'!J)# !J)#!J)#!IhjqIAamI(epIRjqIhq!JB+$K)@&KB5$JS'!J)#!JB'#JS+#JB"rIhp rIRjqIAemI(amI(amI(YlHhYlI(epIRq!JB'#JS1$Ji1$JS+#JB'#JS+"JB"rIRe pIAeqIRjqIhprJ)#"JS+#JS+"JB#!J)#!JB+#JS+"J)"rIhprIhprIRjpIAepIRj qIRemI(amI(epIRq!J)'#JS+#JS+#JB'!J)#!J)#!J(prIRjqIRjqIRprIhprJ)# "JS1%K)5$Ji+#JS+#JS+$JS+"JB'!J)#!IhpqIAamI(amI(epIAamI(amI(epIRj rIi#"JS1%K)5$JS'"JB'"JB'"JB'!IhpqIRjqIRjqIRjqIRprJ)'#JS+#JS'"JB' #JS+"JB#!J)'"JS+"J(pqIAamI(apIRjqIRjqIAepIAepIRprIi#"JS1$Ji+#JB" rIi#!J)#!J)#!IhjqIRjqIAepIAjqIi#"JS+$Ji1$Ji1$Ji+#JS+#JB'"JB+#JS+ "J(ppI(YkHRTlHhapIAepIAepIAapIAjqIi##JS1$Ji1#JB'"JB'#JS+#JS'"J(p qIRjpIAepIRjqIhq!JB'"JB'"JS+#JS+#JS+"JB'"JB+#Ji1#JB"qIAalHhYmI(e qIRjqIRjqIRjqIhprJ)#"JS+$Ji+#JB#!J)#"JB'#JB'!IhpqIRepIAepIRjqIi# "JB'#JS+#JS1$Ji1$Ji+#JB'"JS+$Ji1#JB"rIAalHRTlHhYmI(epIAepIRjqIRj qIhq!JB+$Ji1#JS+"JS+#JS1$JS+"J)"rIRjqIRjqIRjqIhq!J)#!J)'"JB+#JS+ #JS'"JB'"JB+#Ji+#JB"rIRepI(apIAepIAeqIRjqIhprIhjqIhq!J)'#JS+#JS+ "JB'"JS+#JS'"J(pqIRjqIRjqIRjrIhq!J)#"JB'"JS+#JS+#JS+"JB'"JB+#JS+ #JB"rIRjpIAamI(apIAepIAjqIRjqIRjqIRprJ)#"JB+#JS+#JS+$Ji1$JS+"J)" rIhprIhprIhprIhprIi#!J)#!J)'"JB'"JB#!J)#!J)#"JB'"JB"rIhjqIRjqIRj qIRjqIRjqIRjqIRjqIhprJ)#!JB'"JB'"JB'#JS+#JB'!J(prIhprIhprIhprIhp rJ)#!JB'"JB'"JB'"JB#!J)#!J)#"JB'"JB#!IhjqIRjqIRjqIRjqIRjqIRjqIRj qIRjrIi#!J)'"JB'"JB+#JS+#JS'"J)"rIhprIi#!J)#!J(prIi#!J)'"JB'!J)# !IhprIhprIhq!J)#!J)#!IhprIRjqIRprIhprIhpqIRjqIRjqIRprIi#!J)#"J)# !J)'"JB+#JB'!IhprIhprIhprJ)#!J)#!J)#"JB'"JB'"J)#!J)"rIhprIhprJ)# !J)#!J(pqIRjqIRjrIhprIhjqIRjqIRjqIRprIhprJ)#!J)#!JB'"JS+#JB'!J)" rIhprIhprJ)#!J)#!J)'"JB#!J)#!J)"rIhprIRjqIRjrIhq!J)#!IhprIhprIhp rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"J)#!J(prIhprIhprIi#!J)# "JB'"JB'!J)#!J)#!J(prIhjqIhprIhq!J)#!IhprIhprIhprIhjqIRjqIhprIhp rIhprIhprIi#!J)#!J)#!J)'"JB#!J)"rIhprIhq!J)#!J)#!JB'"JB#!J)#!J(p rIhprIhpqIRjqIRprIhprIhprIhprIhprIhprIhprIhq!J)"rIhprIhprJ)#!J)# !J)#!J)#!J)"rIhprIhprIhprIi#!J)#!JB'"JB'!J)#!J)#!J)"rIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!Ihp rIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprJ)#!J)#!J)#!J)#!IhprIi#!J)#!J(prIhprIhprIhprJ)#!J)# !J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq !J)#!J)#!J)#!J(q!J)#!J)#!J(prIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)# !J)#!J)#!IhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhp rIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIi# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIi#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!!!!X3!!"!!%!"3!!!+!!!B"4!!! !!!!8!!!!!!!!,"C@lSZM!!!X&!!!,"8!2)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J(prIhq!J)#!J)# !J)#!J)#!J)#!J)"rIhprIhprIhprIhprIRjqIRekH(KpJB*rHh"H6%%m2$j!2$% R,d989dp&26Fd0MY"4de6@&jMCfY[FA4jJ)U@SUqla-[4ephKjHRYlr,cp2AfprI fp[Eep22cmr,blqV9Rh&pRDHXXE+aVUHJQ*!!L)"e8"3!'c8p4%P*4N!i,bJP*#F X-cT"4da49PTHB@4QDR"iJBfCT+kf[-,(c0$8f0[Hi1(Mj1AQjqIRk1MRjqIQj0r 8VRjXHBQ8Qk+QUDLPS*Q5LApZ443%%L)X06a!3N!m0M%Y,#da0Ma"4NT18PCCA&j JBfKYGAq*P*kRVV1i[-$%b-[1dG,8eYMCfY[Fh0hGh0[DeXqlNR&XFRZ%M*1DRk' JRCL5LAjV3aS,$aBI+#mh1cdm1MFe0$8i1d"%5%Y1894A@9YGAf*RE(9rL*+ESDH XX,5i[,r#a-I*bXc1cp$4dY26dp(2blqQJfjVEA&iIiD1P*LDQCD4LAjU5#88%K3 B(L8X-MFk1cXl1c`r3N9)5dj38P9A@9YFA@"MD'phJ)Q4QCqMTkZ[XV@iZll!`X2 &amM*bXV,bmR'[l'BI@jXE'eaGRf%Lj!!P*@8NBTrE9%b(aXC'4`J*5Xa0MSp2d& $4NP-6e&69&CA@9YFA9jJBQCVFRU$Lj+BRU+PUDb[XV5hZEZp[X$"`m6%aFA$[lD RNAa`E@eYEh*hIB1*MT'5N!#,JA&D35dP)L!J)5-S,6-i28&&5%a38P9A@9TDA&e HAf"JBQ0QDh"hISD0P*UHSD5RUkf[XV5fZ,Ul[Ekr`-(![VQ`SBjpFfp[Eh"aG(P qK)U1N!#2M)4fC%dk,bSS*bBQ*bX`06Y"4Na39&KEA9jIAf"KB@*LBf4PCfT[G(Z $LC!!PTUHSD5RUDbZX,+dYVHjZVbp[EbkYDZGMApeFR&aFR*dGRZ!KBU0MSb'HfY C4cSc-#iX+bXX,M-j2dC-8PGFB'*MC'4NC'9PC@CQCfPVEh4jIiD-NTHERk'NTUL VVDqaXV5fYlQkZVQfX+HEMB&iG(0cFh4eGRPpJSH,M)Z(IR&L8N8p0c8c-6!`-$- i284-8PKHBQ9RD'KSD'KSD@PTD@YXEh0iIB1*Mj@CR*qKT+DSUUbZX,+dYEHhYlD cVD5CMS4mGh9eGRChH(TmJ)@*LiZ)JAGUA&"'2cXj1$Be06Bi280+8PPJC'KVE'a XE'aXE'aXE'eZF(0hI)+(MC1AQjkJSU5RUDZYVl'bY,@fYV5aUk1CMiCrHRKhH(P kHRapJ)5)LSZ*K(aaC9P35%0!2Mdm1cSl2N0+89PIC@TYEh"`F("`Efp[Eh"`FR4 iI)''M*'@QTfJSU5QU+UXVV#bXl@eYE1`UU1DNBQ#IAYkHRYmIAjrJB5(LSZ+KS" hE@*B8%T'3d*"3$mr384+8&GIC@Y[FA0cFh0cFR*bFR*bG(9iI)#<!!P*LFRk' MTDHUV+k`XV1dY,5bVUQLQj+,KB"pI(apIi#"JS1&KiQ,LiL$I(0TB&G46%K'489 %4%9(5P"@A@4UER*dGA9eGA9dG(4dG(9fHAarK)Q1NTHERU#LTDHTUkf[XE+cXl1 aVDLLQj10Ki*rIRjrJ)'#Ji5&KiQ+LSQ&IhGZCPe@88e+58K)5%K+6&"9A'*SER* dGRGhGhCfGR9eGAChHAYqJSH-N!#9QCfISU5QU+UXVV#aXV+aVkbRSTZ8MBL%JAp rJ)'$K)@'KiL*LSU*Ki*lG'YMA9G56Na,5dY-68p59PYKCfaaG(ChH(KiH(GhGhG hH(PlIS'&LSq6PjZISD1QU+UXVUqaXV'aVkZQSTZ9MiU'Ji'!JB+%KSH)L)Q+LiZ +L)4rH("TBPaA8e"26Nj28&*89eYKCQY`G(CiHAPjHAPjHAPjHATmIS'&LBf5PTU HSD1PU+UXVUqaXE'`VUZRSTb@N!#-L)5$JS+%KBH*LSU,Lib-LiU(JRaeEQGK@eG 88P&48P099ePGB@CUEh0fH(PkHRTkHRTkHRTlI(k"K)L-N!#9QCfJSkDSUUbZVl# aXE#ZUkDKR*H4MBQ'K)1$K)D)LSZ-M)b0MBb,L)4rHA*XCQ"E9e968e499ePEAQ& PD@eaGAGjHRTlHhYkHRTlHhaqJ)1'LSq6PjZISU@RUDZYVUq`X+qXUDDKR*H5MBQ (K)1$K)D)LSZ-MBf0MBb,LBD"I(C[D@4I@eG9999@@&TGAf*PD'a`FhChHATkHRY kHRYlHhapIi+&L)b4PCQGS+1QU+UVVDkZVUfVU+5JQjD5MBQ(KB5$K)D)LSZ0MBk 1MBf-LSH$IRPcE@GLAPTB9eGA@9YHB@0QD@a[FR4fH(PkHRTkHRTlHhapIS'%KiU 1NjHERk+PTkQVV+bYV+ZTTU1IQTD5MSU(KB5%K)D)LSb1Miq2MSf-LSH$IhTeF'T QBPjE@9PC@eeIBQ9RDQaZF(*dGRGhH(PjHAPkHRYmIB#$KBQ0NC@CRD'NTULTUUZ VUUQRT+'GQC@4MSU)KS@&KBD)Lif2N!#4N!#3!)k0LiL&JAaiFfjUCQ*IA9YEA&j KC'GTDfe[FA*cG(9fGhKiH(PjHRYmIAq#KBL-N!#8Q*bJSkDSUDQUUDLRTD+IR*L 9NBk,LBH'KBD(L)Z0Mj'5NT'3!)k-LBD$IhTfF@eTC@*JAPeHAf&NCfTXER"aFR0 dG(9fGhGiH(PjHRYpIi'%KiZ2NjHERk+NTUHSU+LRTD1KRTUAP*'0LiQ(KS@&KSL +MBq3!*+5NC!!Mib+Ki5!I(KdEfYSC@*JAepJB@4RDQe[F(&bFh0cG(9eGRGhH(P jHRaqJ)1'LBf4PCQFS++NTDDQTU@MSCqFQCD6N!#0LSL'KB@&KBH*Lif2NC+4NBq 0LiL%JAjkGR*ZDQCNBQ"JB'*NCQTXER"bFR0cFh0dG(9fGRGiHATlIAq"K)H,Mj+ @QTkJSU5PTD5MSU#HQjL9NBq-LBH'KB5%KBD)LSf2N!#4NC'3!)k-LBD$IhaiG(" XD@CNBQ&KBQ4QD@aZF(*cFh0cFh4dG(9fGhGiHRYmIS'%KSQ0NC@BR*kKSk1MSk+ KRjfDPj54MSZ*Ki@%K)5%KBH*M)k3!*'5NC!!Mif+L)5"IRTfFfpVD@CNBf0MC'C TE'j`FR0dG(4dG(4dGAChGhKjHhaqJ)+&LBb2NjDCRCqKSU+LSD#HR*QAP*'1LiQ (KB5$Ji5&KSL,MBq3!*'4NBq1LiQ'Ji"mH(9aE@YSCQ9NC'4QD'YYF(*cG(4dG(4 dG(9eGRGiHATmIAq#K)H+MT'8PjUGRk#KSD#IRCZBPT13!)f+L)D%Ji+#JS1&KiQ ,MSq3!*'3!*!!MSb+Ki5"IATfFfpXDQKQC@4PCQGTE'paFR0dG(4dG(4dGA9fGhK jHhaqJ)+&L)Z2NT@BQTbHRjqHRCZCPj54Mib*Ki@$JS'"JB+$KBH*M)k2N!#3!)q 1M)U(K)*qHhKdF@eVD@GQC@9PCfPVE@paFh0dG(0cFh0dG(9fGhKkHherJB1'LBb 2NT@BQTbGRCfFQTL@Nj!!MSZ)KS5#JB#!J)##Ji@)LSb1Miq2MSb+L)D$J(ejGR* [E'TSCfCPC@CSDQaZF(*cG(4dFh0cG(4eGRGiHAYmIS##KBL+MC!!NjDBQTZEQjU CPj@5Mif+Ki@$JB"rIhq!JB+%KiQ,MBk2MSk0LiQ(K)&qHhKeF@jXDQKRCQCRD'T XER"bFh4dG(4dG(4dGAChH(PkI(k!JS5(LSb2NT5@Q*UDQTUBPj@5N!#0LSL&Ji' !IhjqIi#"Ji@)LSb0MSk1MBb+L)@$J(ejGR0`E@YTD'GRCfKTDfe[FA0dG(4dG(4 dG(9fGhKjHRYpIi'$KBL,MT!!Nj@@Q*QCQCL@P*+2M)Q(K)+!IhjpIAjrJ)+%KSQ ,M)f1MSf-LSL'K)&qHhKeFQpYDfPSD'GSD@TXER"bFh4dG(4dG(4dGAChH(PlI(k !JS5'LBb1NC18PTHAPjD9Nj'1LiL'Ji&rIRemI(apIS##KBH*Lib0MBb,LSQ'K)* rHhPfFR"YDfTTD'KSD'TVE@paFR0dG(4dFh4dG(9fGhKkHherJB1&KiU-MT!!NT5 9PC@9P*+2MBZ)KB1"IhemHhYlI(erJB1&KiQ,M)b-LiU*Ki@$J(ekGh4aEfeVD@K SD'KTDfaZF(&cFh4dG(4dG(4eGRGiHAYmIS##K)D)Lif2NC+6P*58Nj'2MBU(KB+ !IRemHhYlHhaqJ)+%KSL+Lib-LiU*L)D%JApmHACcF'jXDfTTD@PUDfaZEh&bFh4 dG(4dG(9eGRGiHAYmIS##K)D)LSb1N!#4Nj16Nj+4Mif+L)@$J(jpI(YkHRYmIAq "JiD)LBZ-M)b,LSQ(KB+!IRYiGA*`EQaVDQTUDQYXE@paFR0dG(9eGA9eGRChH(P lI(jrJB1&KiQ,MBq3!*'5NT+5N!#2MBU(KB+!IRelHRTkHRYmIS##KBH*LSZ-LiZ +LBL'K)&rI(PhG(&[E@aVDQTUDfaYER"aFh4dGA9eGA9fGRGiHATmIAq!JS5'L)U -MBq3!*'4NC!!Mik-LSH%JS"qI(YkHAPjHRYpIi'$KBH*LSU,LiU*L)D%JS"pHRG eFh"ZE@YUDQTVDfaZEh"bFh4dGA9eGA9fGRGiHRYmIRq"Ji@(LBU-MBk2N!#3!)q 1MBZ*KS5#IhelHRPiH(KjHRapIi+%KSH*LSU+LSQ)KS@$J(jmHACdF@pZE'YVDfY VE'e[F(&bFh4dGA9eGACfGhKjHhapIi'#K)D)LBZ-MBk2Mik0M)Z*KS5#IhelHRP iH(KjHAYpIS'$KBH)LBU+LSQ)Ki@%JRppHhKeFh&[E@aXDfYXE'e[F(&bFh4eGA9 fGRChH(KkHhaqIi'#K)D(LBU-MBf1MSk0M)Z*Ki5#J(jmHRPiH(KjHAYmIS##K)D )LBU+LSU*L)H&Ji&rI(TiGA0aEfjYE@eYE@j[F(&bFh4eGRCfGhGiH(PkHhaqIi' #K)@(L)U,M)f0MBf0M)U*Ki5#J(jmHhPiH(KiHATmIAq"Ji@(L)Q+LSU*L)H'K)+ !IRYjGh4bF@pZEQeYE@j[F(&bFh4eGRChGhGiH(PkHhaqIi##Ji@'L)Q+Lib-MBb -LiU)KS5#J(jmHRPiH(KiHATlI(k!JS5'KiL*LBQ*L)H'KB1"IhekH(CdFR"[EQj YEQj[Eh"aFh4eGAChGhGiH(PkHhapIS#"Ji5&KiL*LSZ,LiZ,LSQ(KS5#J(jmHRP iGhGhH(PkHherJB1&KSH)LBQ*L)H'KB1#J(elHAGeFh&`EfjZEQj[Eh"aFR0dGAC fGhGiH(PkHhapIRq"JS1&KSH)LBU+LiZ+LBL(KB5#J(jmHRPiGhGhH(KkHheqJ)+ %KBH)L)Q*L)L(KS5$JAppHhKfG(0aF'p[Efp[F("aFR0dGAChGhKiHAPkHhapIRq "JS5&KSH)LBU+LSU+LBL(KB5#J(jmHhPiH(GhH(PkHhaqJ)+%KBH)L)Q*LBL)Ki@ %JS"qI(TiGR9cFR&`F("`F(&bFh4eGRChH(PjHRTlI(apIi#"JS5&KSH)LBU+LSU +LBL(KS5#JAppHhTjH(KiH(PkHhaqJ)'$KBD(L)Q*LBQ)KiD&Ji+!IRakH(CdFh* aFA&aFA&bFh4eGRChH(PjHRYlI(eqIi#"JS5&KSH)LBQ+LSU*LBL(KB5#JAppI(T jH(KiH(KjHRapIi'#K)@(L)L*LBQ)KiH'K)+"IhelHAGfG(0bFA&aFA&bFh0dGAC hH(PjHRTlI(apIRq"JS1%KBD(L)L*LBQ)L)H'KB1#J(jpHhTjH(GhGhKjHRYmIS# "Ji5'KiH)L)L)KiH'K)1"J(jmHRKfGA4cFR&aFA*bFh0dGAChH(KjHRTlI(apIRq !JB1%KBD(KiL)L)L)KiD'K)1#J(jpHhTjH(KhGhKiHATmIAq"JS5&KSH)L)L)L)H 'KB5#JAppHhPiGR9dFh*bFR*bFh0dGAChH(KjHRYlI(eqIRq!JB1%KBD'KiL)L)L )KiD&K)1#J(ppI(YkHAKiH(KjHATmIAq!JS1&KSH(L)L)L)L(KS@%JS"rIAYkH(G eG(4cFh0cG(4eGRChH(PkHhamIAjqIi#"JS1%KBD(KiL)L)L)KiH'KB1#JApqI(Y kHAPiH(KjHRYmIAq!JS1&KSH(L)L)L)L)KiD&Ji+!IRelHRKhGR9dG(4dG(9eGRG iH(PkHhapIAjrIi#"JS1%KBD(KiL)L)L)KiH'KB1#JApqIAYlHRPiH(PjHRTmIAk !JB1%KBD(L)L)L)L)KiD&K)1"IhjmHhPiGhCeGA4dGA9eGRGhH(PkHhamIAjrIi# "JS1%KB@'KiH)L)L(KiD&K)1#J(pqI(YkHAPiH(KjHATlI(erJ)+$K)@'KiH)L)L (KiD&K)1#J(jpHhTiGhCfGA9eGA9eGRChH(PjHRYmIAjqIi#"JB+$K)@'KSH(KiH (KSD&K)1"J(ppI(YkHAPiH(KiHATlI(eqJ)'#K)@&KSH(KiH(KiD'KB5#JApqI(Y kH(GhGR9eGA9fGRGhH(PkHRYmIAjrIi#"JS+$K)@'KSH(KiH(KSD&K)1"J(pqIAY lHRPjH(KjHATlI(eqIi'#Ji5&KSH(KiH(KiH'KB5$JS&rIRalHRPiGhGfGRCfGhG iH(PkHhapIRjrJ)'"JS1%K)@'KSH(KiH(KiD&K)1#JB"qIAalHRTjHAPjHRTlI(e qIi'#Ji5&KSH(L)L)L)H(KS@%Ji+"IhjmHhTjH(KhGhGhGhKiHATkHhapIRprJ)' #JS1%KB@'KiH(KiH(KiD&K)1#JB"rIRamHhTkHAPjHRTlI(eqIi##Ji5&KSD(KiL )L)L(KiD&K)1"J(ppI(YkHAKiH(KiH(KiHATkHhapIRprJ)'#JS1%K)@'KSH(KiH (KSD&K)1#JB"rIAalHhTkHAPjHRTlHhapIS#"JS1%KB@'KiH(KiH(KSD&K)1#J(p qIAYkHRPiH(KiH(KiHAPkHhYmIAjrJ)'"JS1$K)@&KSD'KiD'KS@&K)1#J(pqIAa lHhTjHAPjHATkHhapIRq!JB+$K)@&KSD(KiH(KSD&K)1#JB"rIAalHRPjH(KiH(K iHAPkHhYmIAjrJ)'"JS1$K)@&KSD'KSD'KS@&K)1#JB"qIAamHhTkHAPjHATkHha pIRq!JB+$K)5&KSD(KiH(KiD'KB5$JS'!IRemHhTkHAPjHAPjHATkHhamIAjrJ)' #JS1%K)@'KSD(KiH(KSD&K)1#JB"rIRemHhYkHRTkHRTlHhapIRq!JB+$K)5&KSD (KiH(KiH'KS@%Ji+"J(pqI(alHRTkHAPkHRTlHhapIRprJ)'#Ji1%KB@'KSH(KiH (KSD&K)5$JS"rIRjpI(YlHhTkHhYlI(apIRq!JB+$Ji5&KSD'KiH(KiH'KS@&K)1 #J(pqIAamHhYkHRTkHRYlHhapIRjrJ)'#Ji1%KB@'KSD(KiH(KSD&K)1$JS"rIhj pI(YlHhTkHRYlHhapIRjrJ)'#Ji5%KB@'KSD(KiD'KS@%K)1#JB"rIRemHhYkHRT kHRTlHhamIAjrJ)#"JS1$K)@&KSD'KSD'KS@&K)1#JB"rIRemI(YlHRTkHRTlHha mIAjrIi#"JS1$K)@&KBD'KSD'KS@&K)1#JB"rIRemI(YlHRTkHRTlHhYmIAjqIi# "JS+$K)5&KBD'KSD'KS@&K)1#JB"rIRjpI(YlHhTkHRTlHhamIAjqIi#"JS+$K)5 &KBD'KSD'KS@&K)1$JS'!IhjpI(alHhYlHhYlHhamIAjrIi#"JS1$K)5&KBD'KSD 'KS@&K)1$JS'!IhjpIAamHhYlHhYlI(apIAjrIi#"JS+$K)5&KBD'KSD'KSD&KB5 $Ji+"J(pqIAemI(alHhamI(apIAjrJ)#"JS1%K)@&KSD'KSD'KSD&KB5$JS'!Ihp qIAamI(YlHhYmI(apIAjrIi#"JS+$K)5&KBD'KSD'KSD'KB@%Ji+"JB"rIRjpI(a mI(amI(epIRjrJ)#"JS1$K)@&KSD'KSD'KSD&KB5$JS'!J(pqIAemI(alHhamI(a pIAjrIi#"JB+#Ji5%KB@&KSD'KSD'KB@%Ji1#JB"rIRjpIAamI(amI(apIAjqIi# "JB+$Ji5&KB@'KSD'KB@&K)1$JS'!IhjqIAamI(YlHhYlI(amIAeqIhq!J)'#JS1 $K)5&KB@&KB@&KB5%Ji+#JB"rIhjpIAamI(amI(amIAeqIhq!JB+#Ji5%KB@&KB@ &KB@%K)1$JS'!IhjqIAamI(YlHhYlI(amIAeqIRq!J)'"JS+$Ji5%KB@&KB@&KB@ %Ji1#JB'!IhjqIAemI(amI(apIAjqIhq!JB'#Ji1%K)@&KB@&KB@%K)1$JS'!J(p qIAemI(amI(amI(apIAjqIhq!J)'"JS1$K)5%KB@&KBD&KB@&K)5$JS'"J(prIRj pIAepIAepIRjrIi#!JB+#Ji5%KB@&KSD'KB@&K)5$JS+"J(prIRepIAamI(amI(e pIAjqIhq!J)'"JS+$Ji5%KB@&KBD'KB@&K)5$Ji+"JB"rIhjqIRepIAeqIRjrIi# !JB+#Ji5%KB@&KSD'KB@&K)5$Ji+"J)"rIRjpIAemI(amIAepIAjqIhq!J)'"JS+ $Ji1%K)@&KB@&KB@&KB5%Ji+#JB#!IhjqIRepIAepIRjqIhq!JB'#Ji1%K)5&KB@ &KB@%K)1$JS'"J(prIRepI(amI(amI(apIAeqIRprJ)#!JB'#JS1$Ji5%K)5&KB@ %K)5$Ji+"JB#!IhjqIRepIAepIAjqIRprJ)'"JS+$K)5%K)@&K)5%K)1$JS'"J(p qIRepI(amI(amI(amIAepIRjrIi#!JB'"JS+$Ji1%K)5%K)5%K)5$Ji+#JB'!Ihp qIRjpIAepIAjqIRprJ)#"JS+$Ji5%K)5&K)5%K)1$JS'"J(prIRjpIAamI(amI(a pIAeqIRjrIi#!J)'"JS+$Ji1%K)5%KB@%K)5%Ji1#JS'"J)"rIhjqIRjqIRjqIhq !J)'"JS1$K)5%KB@&KB@%K)5$Ji+"JB"rIhjqIAepIAepIAepIAjqIRprIi#!JB' #JS+$Ji1%K)5&KB@&KB5%K)1$JS+"JB#!IhprIRjqIRprIhq!J)'"JS1$K)5%KB@ &KB@%K)5$Ji+"JB#!IhjqIRepIAepIAepIAjqIRprIi#!JB'"JS+#Ji1$K)5%K)@ &KB5%K)1$Ji+"JB#!J(prIhpqIRjrIhq!J)'"JS+$Ji5%K)5%K)5%K)1$JS+"JB" rIhjqIAepIAemIAepIAepIRjqIhprJ)#"JB'#JS+$Ji1%K)5%K)5%Ji1$JS+"JB# !IhprIRjqIRjqIRprJ)#!JB'#JS1$K)5%K)5%Ji1$JS'"J)"rIRjqIAepI(amI(a pIAepIAjqIRprJ)#!J)'"JS+#Ji1$Ji1%K)5$Ji1$JS+"JB#!IhprIhjqIRjqIhp rJ)#!JB'#JS1$Ji5%K)5$Ji1#JS'"J)"rIhjqIAepIAamI(epIAepIRjqIRprIi# !J)'"JB+#JS1$Ji1%K)5%Ji1$JS+#JB'!J)"rIhprIhprIhprJ)#"JB+#JS1$K)5 %K)5%K)1$JS+"JB#!IhpqIRjpIAepIAepIAeqIRjrIhprJ)#!JB'"JS+#Ji1$Ji5 %K)5%K)5$Ji1#JS'"JB#!J(prIhprIhq!J)#"JB+#Ji1$K)5%K)5%K)1$Ji+#JB' !J(prIRjqIAepIAepIRjqIRjrIhprJ)#!JB'"JB+#JS1$Ji1%K)5%K)5$Ji1#JS+ "JB#!J)"rIhprIhq!J)#"JB'#JS1$Ji5%K)5%K)1$Ji+#JB'!J(prIRjqIAepIAe pIAjqIRjqIRprIi#!J)#"JB'"JS+#JS1$Ji1$Ji1$Ji+#JS'"JB#!J(prIhprIhp rIi#!J)'"JS+#Ji1$Ji1$Ji1#JS+"JB#!IhpqIRjpIAepIAepIAepIAjqIRjrIhp rJ)#!J)'"JB'#JS+#Ji1$Ji1$JS+#JS'"J)#!IhprIhprIhprIhq!J)#"JB+#JS1 $Ji1$Ji1#JS+"JB#!IhpqIRjpIAepIAepIAepIAjqIRjrIhprIi#!J)#"JB'"JS+ #JS1$Ji1$Ji+#JS'"JB#!J)"rIhprIhprIi#!J)'"JB+#JS1$Ji1$Ji1$JS+"JB' !J(prIhjqIRjpIAepIRjqIRjqIRprIhq!J)#!J)'"JB'#JS+#Ji1$Ji1$Ji1$JS+ #JB'"J)#!J)"rJ)#!J)#!JB'"JS+#Ji1$Ji1$Ji1$Ji+#JB'!J)"rIhpqIRjqIRj qIRjqIRjqIhprIhq!J)#!J)'"JB'#JS+#Ji1$Ji1$Ji1$JS+#JS'"JB#!J)#!J)# !J)#!J)'"JS+#JS1$Ji1$Ji1$JS+#JB'!J)"rIhpqIRjqIRjqIRjqIRjqIRprIhp rJ)#!J)#!JB'"JS+#JS+#Ji1$Ji+#JS+#JB'"J)#!J(prIhprIi#!J)#"JB'"JS+ #JS1#JS+#JS+"JB#!J(prIhjqIRjpIAepIAepIRjqIRjqIRprIhprJ)#!J)#"JB' "JB+#JS+#JS+#JS+"JB'!J)#!IhprIhprIhprJ)#!JB'"JB+#JS+#JS+#JS'"JB# !J(prIRjqIRjpIAepIAeqIRjqIRjqIRprIhprIi#!J)#!JB'"JB+#JS+#JS+#JS+ "JB'"J)#!J(prIhprIhprJ)#!J)'"JB+#JS+#JS+#JS+"JB'!J(prIhpqIRjqIRj qIRjqIRjqIRprIhprIhq!J)#!J)'"JB'"JS+#JS+#JS+#JS+#JS'"JB'!J)#!J)# !J)#!J)#"JB'"JS+#JS+#Ji+#JS+#JB'"J)#!IhprIhjqIRjqIRjqIRjrIhprIhp rJ)#!J)#!J)'"JB'"JS+#JS+#JS+#JS+#JS+"JB'"JB#!J)#!J)#!J)#"JB'"JS+ #JS+#JS+#JS+#JB'"J)#!IhprIhjqIRjqIRjqIRjqIhprIhprIi#!J)#!J)#"JB' "JB+#JS+#JS+#JS+#JS'"JB'"J)#!J)#!J)#!J)#!J)'"JB'"JS+#JS+#JS'"JB' !J(prIhpqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprJ)#!J)#!JB'"JB'"JS+#JS+ "JB'"JB#!J)#!IhprIhprIi#!J)#!JB'"JB'"JB'"JB'"JB#!J(prIhjqIRjqIRj qIRjqIRjqIRjqIRjrIhprIhprIi#!J)#!JB'"JB'"JB'#JS'"JB'"JB#!J)#!J(p rIhprIi#!J)#!JB'"JB'"JB'"JB'"JB#!J)"rIhpqIRjqIRjqIRjqIRjqIRjqIRp rIhprIhprJ)#!J)#!JB'"JB'#JS+#JS+#JS+"JB'"JB#!J)#!J)#!J)#!J)'"JB' "JB+#JS+#JS'"JB'!J)#!IhprIhpqIRjqIRjqIRjrIhprIhprIhq!J)#!J)#!J)# "JB'"JB+#JS+#JS+#JS+#JS'"JB'"J)#!J)#!J)#!JB'"JB'"JS+#JS+#JS+"JB' "J)#!J(prIhprIhjqIRjqIRprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'#JS+#JS+ #JS+#JB'"JB'"J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'!J)#!IhprIhjqIRj qIRjqIRjqIRjqIRjrIhprIhprIhq!J)#!J)#!JB'"JB'"JB'"JB'"JB'"JB#!J)# !J)#!J)#!J)#!J)#!JB'"JB'"JB'!J)#!J(prIhprIRjqIRjqIRjqIRjqIRjqIRj qIRprIhprIhprIi#!J)#!J)#"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)# !JB'"JB'"JB'"J)#!J(prIhprIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhprIi# !J)#!J)'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB'"JB' !J)#!J(prIhprIhjrIRjqIRjrIhprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'"JB+ #JS+#JS'"JB'"JB'"J)#!J)#!J)'"JB'"JB'"JB'"JB'"JB'"J)#!J)"rIhprIhp rIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!JB'"JB'"JB'#JS+"JS'"JB'"JB' "J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'!J)#!J(prIhprIhpqIRjqIRjqIRjrIhp rIhprIhprIhprIhprJ)#!J)#!J)'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)# !J)#"JB'"JB#!J)#!J)"rIhprIhjqIRjqIRjqIRjqIRjqIRjqIRjqIhprIhprIhp rIhprJ)#!J)#!J)'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#"J)#!J)# !J)"rIhprIhpqIRjqIRjqIRjqIRjqIRjqIRjrIhprIhprIhprIhprJ)#!J)#!J)' "JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)'"JB'"JB'"JB#!J)#!J)"rIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB' "JB'"J)#!J)#"JB'"JB'"JB'"JB'"JB'"J)#!J)#!IhprIhprIhprIhprIhprIhp rIhprIhprIhprJ)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#"JB' "JB'"JB'"JB'"JB'!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIi#!J)#!J)#!J)#!JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!IhprIhprIhprIRjqIRjqIRjqIRjqIRjqIhprIhprIhprIhprIhprJ)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhp rIRjqIRjqIRjqIRjqIRprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)'"JB'"JB'"JB'"JB'!J)#!J)#!J)# !JB'"JB'"JB'"JB'!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIi# !J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#"JB'"JB'"JB'"JB# !J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)# !J)#!JB'"JB'"JB'!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIRprIhp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhq!J)#!J)#!J)#!J)#"J)'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)# !J)#!JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB' "JB#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprJ)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!Ihp rIhprIhprIhprIhprIhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB' "JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhp rIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB'"JB'"JB#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhq!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhp rIhprIhprIhprIhq!J)#!J)#!J)#!J)!!!#K!!!%!!3!&!!!!S!!"J&%!!!!!!"3 !!!!!!!!S&PEZLk-!!#J8!!!S&3!mJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!IhprIhprIhprIhprIhprIhprIhprJ)#!J)#!J)'"JS1%KBD(LBU,MC@ KUDLSX,Hl[lfcTk@``YANl2(bm1VJdmHlVk5FPSq)L*h$hqAHi[6rr2VikG5rV*q BNSb'JAYjHAPkJT[%j[AaiFQhYF(2dmr'YkDR`Y[A`kqCIQPD8P&DFTLrf1$DcVq aVE5jYl+bYVLeVUDCLA4H6%0-Dj5cZUZ5Gej,5eTUFRPrIhKXC'"HA9pLB9eA9Pp fP+bbSSZ#MUM#f1AKeY$*[,'XUkZTTk+CMSUDZYILhXqlTC58Skq[Tjb1IAZ5VlH `Tj4hA%Bi2PCeM*QGR*qLRTD3!)PqFQTTEh0aDf&@890DD)Lkir(Yh-#RRk+VZ-# rZlZm[,fqZl1QQ)TpF@0@8&GME'aJ5M3a5'9bG(4R8cmV'!i1&L%T,5dX-%9QJik (G@&45%eHER0aE'094dTCB&4'1#`T,cjFIT1AMRYN9PjfMTbMS*H2LSD#IRGXA8X h*KiV8AkETk13!(aS9%T2AQppLBPpE@"E@PYHB@0JA&pZJBkARTb3!)*qN!#SX+Z NQ)PqGQeN@P"-5dT(3$j+BRL#JAGZD'0LCQPN@8j#05db4eaMBee01c!`3ephKib *K)QCUlHl[EU[RSf"IB#)P*qJPB4hITbjaF@mVCq8LS*qHA&UCfKYG(k(LS9mF'* @9fZ(QCZ1Gee+3P*pTV@aSB4M56Xk38K19&KC994FEAk&J(4UD@j`FR0aE'CLBQ" HAfTfIS1(KAppK*Qa`,qbTD+TXEDeXUqVST5'I(CdFR&ZCeT15&9mUEqmUj0pF'j hKBk2KhTVA9GHDh0`CPK*2Mp3F)Q3!)PmE9j48QU)PT@4LS"jFQTM@e415dY19'0 hJB*rHA&VC&jB88Jq0#XP)LFqBharG@&(,L-Y5QKjI(CYC&pMFS#&JRefEQ9IA9Y A8Nj'1c%d8AkLYEDTQjD6N!#1Li*fD@0NCfPYG(K`AdSi-d9PJ)b-KAaeHj1NRBT jCeP68PGGB&pE9%Y)9'TpKS0eCf&QEhGmIAKYB&YSM,6-dF@TMAf#R,R'`V1LPj+ 6Qk'IQC!!LSH%JAjfD9Y668-m4Q@%N!#,IQeLB@PaFh*bFR4kJB5!HhTmIRemKTb YVk',Ff9RGjLh`,DPN!"pE&T,4dY16Na)4PClSEHhU)jeBPYJCfedHRGVB'0hM*1 4JQPA9fKpLiZ!FQYXG(q&Ki@#K)fETDQNPi9hF("qSFRKj0M$V*fCRUDQS*Q9NT! !MSZ'IhalGQP@4NC9CQYSA%Si-N9RH(CZAdj"0LXU0%416dFr4Q"mLBKrFfTQCfK QAeC048"!6QYqIR9S9%0$@AZ4PSq#G'peJ)H0NBq(IA*SAPKA@ea84cSf5h+4R*H (GfpXE'j`F("aEfPJ@P438PTLD(+(RU5CK@jC6NjLK*ZHQBarHheqJBD)KB1"JSb FU+QMPSGlEf0E@&G988a)3d44CA&eF'CHBA#(QUDSTD+JRk@VUkDJQC'-LSH"H(& ZE@adN!#mhZRPeEbQQTQPXVLdV+HQTU@MRj@&FPp148PHGB&pEPT*3NeTJB@"G@0 98&&AA@4VFhCdGAq-N!#0Jh*K@9aPERChG'jVEAQ4TkUGLR*H9PebMk@[X+fTTU@ NSTkEQ*1*IhC`ER&jIheeF)+R`XR%Xjb0KiH0PTZDNiZ!FQ*86%T089GDA'GpN!# 8LhaVBQL#R+5IPib!HRGiHhYfE'*A6%G5DRf#HfeE56dl3de699&)2$P)@PpG9NN q1N"9GT+GQBb"I(YqJB+"K)b6P*',JhPZBP4+5Pq&SkZPNRYUBf0SE'aUE(*hH(9 [D@GUE@TPBQf%PjZ8KA0NCRkARjU,Fej46%pCBfCPC'"GBA@@XlkiU*5%I)+5Rk+ ENSZ5VmlCdEkMLRKaIk$!cp$+`Vr$aX5lVk#3!)*fF'e[GAKeE@*@8&ekMj+&EPC )5&0PHBU6PT10KB"rJ(adD&T,3dpVKC'0I'CDCB@KV+ZJM(KUC'9TEA*fG@pRB@G eIRjiFh0eGR4ZC9a@8e0GFi5$H@pMA&YHDS#BU+fQQT5@R+1TVV+cXl'ZV+fbYDq KMi52XG,Khp#pX+QSUkq`VUbSSCL2KRpeE'4H9dj*8'"VDf"12$Y5FS&qG'*56%a 4@&aC8%8l-L`U-N4FE("R@8j09f9`F'GC6%TFHiq8PC!!K(CP8NK9GTDRVDQIPBb %IRK[CPeA88T%3%"#4NG%4&&VLTqMPS*bERH)QD@VU+'FR*qLSk+GPSf$GfTTICZ XUTU$G)'JXl@YR)9bC'&UGAKhI)+&JAPaF(Z(Li9kEQPYGAb$K(jdCf0`JB4pHR4 XD'CPDhfCVlQhVkUVXEQr[E1PPiZ$JB1(LB4jD9YDET'daF#`RBYqHi'*MBf*JRK ZCPpD9&"-58G'4%*&6ePF@&*9Chf,N!#1J(&YF(CpJ(pmHRTkGh9iKk#jaX5hUD1 PUV#aUTb-JibKVl5hVTb,IA&ZGikSZ,QbUUHRUDfYTTb5LiH)M*'6Mi0bB9PKFSQ HTk#BNBb1PCUFR*Q6MBD"I(CZCf4LAeT446e%@@TYC9eNHSZ3!*'-IQpL@9CB@&4 389496d-f0dTKE'aSB9aGC@pfFfGA6eYaHRGaC9G268e19@L"P*ZAMB0mH(KlIi& rHhPjHRaqIAG`EAH'MC+FRjH3!)b*MTHISU+IQT52LS@!HA"P@%T!1cT"9(#$KRP TDRZ-Q+'JPiq)JAppH(4cGAGhGA"XFibUZlfeTjL,JAq!IhGXCh#&PCbIQ)CfE@G PES+JZmV-`V5QRjkMTk5EN!#)KBL-M)CmEf&A@QTpN!#RZ,HXRSamGACqL)q2LB" iFQeUD'GPBPjC8Ne6CAb,Mif5Sl'`UU#3!)1!JSH1NBq+KS+!IAKaEA"lJi0qGh& `GS#)M)PqEfPaJ)H*LB0kGA*[ER&pPE,)dmr"XDDLTl6"aX1jVD+@LRpiFQe[JTQ PVEUpXkQIPj59PjZIS*fBNib$I(4UB&4(2cXj1dCFEh&Q@&&ECfKNB&9,4N4&58Y +4dC(58T+58K3Chq-LhpZA9&2@'CcHi#-RUDIPBb!FfPH99"8CS@KVUZIN!#%IRk !JAjhF@aTCQ"D9P*-4dTBDA@&Qk@KQ)TmGRKpKBk9QCZGRCQ4LS4rHR0UB9aIF)k TYVDbZ-("ZVDZT*b@N!#0LiQ)LBL%IRG[CQ*VJC@FPSGdC&aFC@e[CPaHEhq%K(p bCQ&KBfKcLkc(dXh!YE#[XVHkYUfNQj+*J(PfGhGkKTDEPCLLT*qDNSU&K)@(Ki9 rH(0XBeK35dT-6Np168pDDA*`D@4VHS1*Mj!!Miq-Ki"kG(&bG(KmIhprLD#lcG( *Z+LKSkbbXDQKTV[0cF@jTj5)JAjrJikPZX#jV*f8N!#4NT'1KhjjGR*VC&pHAQ& ZL*bGQCkJR*Q9MSZ*LBU+L)H+MBf*JhafEQCD5c`Z*Le&C(KlHAf'KS&rI(9XBPC 058K+8&CB9P&)2ca)Ah9pHQpL@9CAA'"H@Q"hNjkDNB"VAeYC@&TNH*1TXl5`UU1 HR*ZCNib%IhalI(q$K)'"LTHANCDIRTL6M)H'LC!!Q*fDMi&bC&TB@epJA9K346` m6@KqKiL4SUZRSCZ3!)CrGR"ZEQpbGAKpJB"iEQTfLTHCNSCqIS+)LiL!GRH*Qjf @Mi4jFh"ZE@adL*qXUk+8KRprL*5GSD+HPBTqG@jRB&eKERU#MTqQU+ZQQj52LiU +LSQ+Lik3!*!!MBCqG@pYE'TVFhk&KB+(Ql#iZ,5PN!"qEQ9NDA"hIAjpHhCaER1 %RDkdVk5@LAaaDQCLB'KrQD@MQSPhEh"cGRQ!NDDh[m'r[VbhXUZNRC5-KiD(LSf 1LiD%M*HGSkQRRTH1Ki1#JS5(Ki"hE@0D8Nj+4N4!1c-Y,6K-@PeC@QQ!LiU(IR" PAPPDAQ0TEA&bF@aK9P0KHSf8Nif(K)+!IRP`DQf"QD#CMi*`B9G36e9QJjkVUTq 5L)*rIi1(KS&jEf095%&$4dP,9'&YHif@P*'0KApmHRPjGh9eGhKhG'pVD@KRC@0 LDAU4SD+AL)HCV,'`UTf6MSb-MBf-LB0lEf0B8ePYKTQJR*'&Ii#(MT'0KS+0TVZ pXkD5Ih0YDh@,Um60bEb[Tk@SV+fUT*kEQjZCP)YqF'*B@@Z*UEl"YULCLS'!JB+ #IRGZD'9NC@4LAeP88%a+8'"cIRpfD@0[KjLGQSTeD@9REhKpJB@)L)0rJ)fQ[m[ )ZD@9MBf6QCfGPT!!P+Hl[V#ILhCTCQKbKk+bXkZJPBq1N!#4N!#-L)5#JB'$KB@ !G@CA8PjpRV+iVjk-Hh"[Gi+0P*D8N!#,K(aaD@0H@9026ePZJSQ(Ih0ZHBf@P)b !F'0F@9KA8de'2cXi1%"9Ehq!H'aI9P&389&25NC&6fL(Q*H1J'aF8e&GGT1QV+L GNBCrIB+*Mj'1LB4qHAGhH(GcEQKVJCqd[,LUQSf$IAaqK)U0M)U*L)H#Hh*TB&T A@'4lNCU6J@aJDBHQY,@XQ)4eD@9UF(4fGR4[D@b!RE6"`lbcV+QUUkUQRjL2L)b HUk@ALRGL@&PPITLSUUDJQTD5Mib)JhjjGR9iIB'$JRecCeaFFjLc[EQUPSCjFhL !Ji*rHhCcFR0cF@eRB&P89f4kMjQ9Kh9TDhkBTUDFL(0TDA"hHhjqI(PfGS#8U,' ZSjH0LBZ6RD+JPiTqG(@'RUbaX+12IA0hMDDdYE#RSCkLUV'dXkqTSCL4MBU)KS& iDepKHCbbY+bFL(KXCfTZFA"ZDfGLAPTB9e414d!m2dpTHhjeC99)5f1#NBf#G@4 @8%j4@&pLC'CQCh'&PjbCMi*fF(*hI(q"J(jkFfjcJSk0LB"[AeaRIC!!PC')IAC dH)#)L)&iEfKPBf"H@eP@88Y(6'5-UV1ZS)PeDQYiLC@BPj@5MSU'IR0SBPpGA@G pPD@SS*+&HA5$SEDiVTk'F@CQE(9lI(GaDQ4UIT@LSjb6MBZ-MSq0LB@!Hh4YF)' 8QTH1IQeSFS@CTUHKRU'RXEc#`VZbU*f5LB5&M*1@P)PpHSbV[,Q[ST!!IR0cHS+ %JATaD'"B8e"168e06P*EDA0hG'YJ@9CBBRQ4RD'KPiU$J(jqIRelHAZ&Ql2#`lL SQBf)MCDFRCfFQT@0Ji@ATkQLQBPlJ*@UYE@XS*H6NjDCQjbEQ*51Ki"hEfKNAeY BA(#4VVLaSj1"FQYVEQp[E'YXF(4hHAThF@GF9PjiNjqHPSPmF'9JDS#2MSCmE&Y 46%a18%j'2$Fr9h'!JAGUB&aFB'*MBf0MBf0JAQClLiU"G@9IEBDAQjD*HR&dIif 5MiCmG'paHB1)L)*hD9P26PalRE#`U*U)H(*cH(k#Ji"lGR"SBPpKC@CREi+CTD5 CLhpiGhKqMUDeXDHHP)Z(KBD(KAphGB#BXm6&ZkbKQjQES+5PT+'FPSf!F@afKBU (JAKlM*UHQj1*JB#'MC+6NBf+L)D$IRG`DfGLA&TKF)5GXlQYRBaiD'0ND@eaGAK mIi'"J(eiF@PND(L1RCq@LAacEfj`HSbDQj@0Ih0YDQKRD@PRDA5&PU+PSTb@Nj5 BQjL4LiU-N!#5N!#2PUD`UTk6MC@TZEklY+kYXVQr`,beVUHJQC12MBZ*KApeE'P ZGS+5QC1+Ih&RBepGAPpG@&436%Y08946894MGi+#HQpJ8NK$3N42ChTmG@eL@&4 69&KFA9ePHBkANS9dCPpKDhH"KSH'JATcDf&B9fCjIhejHB53!*12KhedEh&hHAK iHAapHhKeFh&[E'CH9e9FDAQ3!+QdX+QINib+L)Q,LiL&K)5$Ji1"I(9bIC+NUD1 BLAacFAClIiQDTU1DMhpbE@YXEQeUES'HY,fkVCk5LSH(LBQ(K)"lG'jRB@"YKjU HQTHFTDDFMi&hG(U)Pk#JQC',KAplH(GjHACaDQ9THBfKYX1qVk'6KAjmIB#$Jhp jGR4cFh*ZCf"GBh&rKB0kEfGPDA*iISfKUkLLPS4fF'paGRTmKCDSX+qRR*@@RDH [X+ZNRTbDPj++J(b%PCqHRCqPVV'XSTH3!)f4QD#LRjQ4L)"hF'TQC'CSD@GREhb "K)fCQT@2LB&kF@KLB@4SE("aE'9F99"6BRb3!*H8LAY`D'9NBf"FBR*mI(TdDQ& D88T&2cY#@("mI(GbEfj`G(KjGA&[F("YD'"A9@*jJhpmJ)@)KS&lHAb"Lj@DQCD 5MBQ(KS@$J(ahFQaQCh@'MjDKUDLKQT!!L)@"IAKcE'4HA@"MC@GSCfCYHSD,L)& iFQjYEQeUEAk8RCQ4K(0SBQ&ND'eiMU[!b-5hUCqFR*kJS*kFQjZCPBq'JBDATU+ AP*UMU+DJQT51L)L-N!#0LBD'KiH'KB@$IhGVAPCAB@aeKCbXVUZMPBQ!HA0aFhC iHRTiGA"UBepMFB@5P)f#GQpXE@p`F(0rLSf-L)5#K)D%IhPdGB5CUV'YT*fCQTq PTk@IPj!!M)b0LS*mISZ6N!#2QkUdYUkNR*QDRU1RTk+FP)q0MT'6NSq*JA9SB'0 [GRCjJSH%IhTbDQ4H@PPB9P*48e966NFq1$Y,B'j`CeP26&*EB'&HBR+%L)9qF@9 H@eTEA&eRIC1IRjQ4M)Z1NjH@NBb(KB1!Hh4XC'9bHhC`Gi5-MSU$I(KiHRq%K(p hE@4IAPjHAPjH@eC36eTVGRf*R+QRRC5+KSH(LBk8PT54N!#4NT'0KRjpLTZLSCQ 2KS"pIAYcDQPhKSQ&Ih4SB9eGAPjJDRk6SU5GNSU)MCDFR*H4LS@"IATiGRU*S+b UU+fbYV@aUk@KRjqKSCfANSq0LiQ&IRG`DfCK@eeTGRYpL*UMSjq9KhedE'CNBPj D@&KC@eeGA&eRH)L4NBTrGR"`G(KmJT1TY,1UR)f%J(epIAf"N!#T`Fh1aVbcVUZ TTk@MSU'IRTZ6KhTdISf3!)f3!*HER*H1KAjmIB#&L)D"Hh9`E'PRC'*H9de$1ca ,AQafKT14KRY`BejIBfefI(prIhekGQpQ@eTSJ*!!NSU!HRPmIi&qGh0kKiZ)JhG TB&YA9&09AR+-Rk1EMB&lI)+)LSQ(KS@#I(4VBejNGiU-KiU5QCZANBU'KSL0NT5 9PC55MiZ%I(0VCQ&F9eCGDh9kK*+CPC'-Ki5$J(epJB5$JAjkGA"UC'"RIjURTCU ,HfaJ@9KDAQZ"NjLBNS4eD&pFA&jMFSbNX,+URC+-LSZ0LiD"JB5(Ki0mFQaaIiL (KiqET+@HPBf+Lj!!PTbHR*H3!)Q$IRTeEfKLA9PA@fPpM*LQX+fPRjQ8NT!!MSf ,L)@#IhajGR&UB9aJF)10MSL!H(9cFh"VD('#M)f+J(*QAPPDA@&UICHYYV#KNB4 mHRf!JB"rIi#!IAK`DQk"PTZ@PCULU+DKQC14P*UIS*bAMiCqH(4bF@eSBejD9PG LEA9rMTLBP*!!LBD'KB&rIRakGh0[DfKNB@"QGikHSCZ4L)+"Ji@%JiZETUDJPSG jEQCJAPjJDi5JXE@ZSTD2LiZ2NC'1LS@!HR*SA&9EEhjrI)#*P*D3!)PrGh*aGRY mHAGeFh*`EQPNA94-4N0&6PaUGiLCRjbBNSU'JAYfFh*bGAb#KB*lFQPMCRD*P*5 0K(ahH(aqIAq0RCq@M(p`Cf0KB@*KBQf!P*qLR*+,L)Q0MSU#HhCeG(0bEQPUGS1 'JB',RDQTSTZAPjbNVE5bV++AM)0lGA"ZE@eUCQGbKjDDRD1MQT+*IhCdG(9hGh9 aE@PQBepD9P*5AA'#L)&dD'4QDfpaFRU,PjD4KhKUC'0NCfPVGBZNYVUbT*H1M*+ DRTqIRCL5Li4lF'TbK)k*JiH6Rk5KQC+0MBq4NT'2M)Q(KiD%IhCXBPP68&0JFS# )NCbJRCQ@N!#-Ki+!J(pjFh"bGRKfF@TPEB#5QCL4L(pjH(PiFQa`J)f,K(YZC&j E@9KA@QGrPU+KPiU"J)@-N!#2LB&fE'4IA9YDAQPkJi@-Q+'LRT@-KiH,PCkNTD1 HQ*'+JhehFQaRBPjHDAb)L)5*NTD5Li"cE@jbGAKiG'eQB&aE@PKBBR@)N!#0JR9 VD'T[G(9bFi'8QT1+IR"SCfCRDh5'Rl5r`,Q[Tk+JS*kEPj56NBb(J(K[CQ4XGhq *QD+KRTL4MSq4NT!!MBL$IAG`D@"C99046dj08Q*jMC55NTfQSjZ8LAeeF'eZFR9 jIS+"Hh0TC'b#PTqGNiL#J)'#J(TbDQalLSk,JhCUBPaB@@*aJSk6Nj+8PjQFRTk EP)f'J(TdEfTPB@"SHj+RY,1TRTD5PCbKSCkCP*!!MBQ$IRPcE@GLA&KDCA@$L)C mGi+BT+1HNi9jF@aVE'TPAeaFA&eKEAq3!*H@MiD#JS@)L)*iE@9QH*'JSTf2I'a MB@f(S+k`UU1GQjZHSD'HQTH8NT!!M)CmF@CG994KI*@JRBprFh"fJ)Q0M)H"HR9 bF'jUC@&G@999AfpmIhYcD'*VJjbRTCU+H@pUDR"hHRGaE'KREi'6R*b@MB@#JiQ 0M)GrG@PH@Q9fIRjjE9j@9fCpNCH6MBQ)Lj!!P*13!)Q#I(PkIB'%K(jeE'GZKUI !bF@hT*H4NTHHSD#HQjH4Li@!HhC[CQ"IDRZ*MSU"G@YNBfq'PjU9LhaXB&K89&C @994@BR@+Q*Z@MBD!I(TiGR0[DfKNB&jNGB5(JACUCQjqMCQIRTZES+DTTk+GQC@ 5MSQ%IRPcE'9LBfTjNUUeXUUJPBk-LiU*Ki5!IRakGh4[DQCMD(H*P*QBP)q*JRY cFRq8SD1HPBGlF@KMBQ*NE(b0PjQ9N!#-LBQ*L)@$Ji1"IAPbDQ*GBQeeH(f$L)U ,LSU0NC'2M)Q%J(ajH(PkH(0ZD'0H@PaNE'pYERZ5SUDMQiq'IhPkJ)D*LBH$I(9 XCfYjL)q2LB*qIAq"JAY`BeaNH)L-LS0fD9jA@@9cIB+'L)H&Ji5(LBD!HA0[EQp aFA"XCf&JE)1CTUQJN!##HRKmKBU0N!#6PTQDQTH5Li4lFh*lLjHDPj',Ki1'P+H YTjk6KATdEQYVE'TSDA+!M*'5N!#-L)@#J(jlGh*YD@CLA&KGDh9eFR*eHi'%KB@ 'KSL-N!#5N!#-Ki*mGR&YDQKSDR*mKBQ&I(ClM*bLSTb5L)0rIAjrI(KfG(0eISU 6PjD6MSL%Ji5'L)H%IACcHibBQCD3!)Q+NTLER*UAP*18PTLBPT+1LiH"HR0ZDfe dIB&qGQe[IBU-LS4kFQeTD'PUD@CNB@"LE(f2QCL3!)GqGh&YER*fH(9[DQq!Mj+ -JRKfJBf5Nj'0LSU-N!#8PTH@NSf(J(YeEfaUD@ekKBCrIiU6P*'0KApmI(k!J(j kGR*`E'GPDhb2Pj5,Ih0VCfP`GhPhFhH'PTU@MAp[BPTEE)15PT50Ki&pI(k#K)1 !I(KeFh*`E'CJ@9GLHj+GQT'#FfYVFhq)LiZ*KS&mHAKiGA"VERZ,PTU@MiQ$IAP hIj!!Rk'EP)TrHAGhH(KhISZARCbANBf,LSU,LiL%J(elGh*VBPYA@fTrP*qHPSb #Gh"XEA"eGhKhGhKiGhCdF@eTDh5"LBb+JhP`ERb4RU'HP)GqHAChHATjH(U#MCH DQC52LB5#JiH,LiQ&JAadE'CVH)1+NCDCQCD3!)U%IhYkIi1&KSD(LBU*KRphEQG PE(U'L)0kFRD$MT!!N!#0KS&rIRk!Ji1"IRTiIBQ6Pj@1KhpkH(Z!KSL'JAT`D'G bIS+!HhKlKBU,LSQ(KB@&KiZ1MSf,Ki*pGh*ZDfP[I)Q1LS5%MTLDQ*50Ki1"J)# !IRYjGh0ZD@ahJiL(JheiGA4fHRjrHR*TCQjlJAjiEQ&CA@YiIRjkGA&ZEh0kJ)+ #J(YeF'eVDfTRC@9VFRb,Qk+KRCD4Mj'5NT14MSU'JAppIAb!LjLIRTU6M)4rHhT jGh0aHBQ9PT'+Ih0UBf*VHiD,M)Q&JRppI(eqI(TiH(KhGA0[DQ9LCR@0Rk@LQBf #I(TlIi'"IhjqIRq!J)"pHAKmKSf2MBL"HR4`EQjcIik@P)q(IRCaE'TVFAZ%LSk 3!*!!MSZ(K)@(LBQ+LiZ+L)@#IAKdHBUET+@JPj!!MBZ+Lib0MBb,LBL(KS0qH(* aGS#,NC!!Li*iEfKMD(H,PTH6Li"hEQKNBf0QEhZ&LSZ)KB&pHRKjI)#$JS"pHAC bE@TXGiD6RCqFPj+1LiQ'K)+#Ji5'KS5"IATfFQjYG(q(L)D"Hh4ZERL'MBb*Jha hFfpYDfPRCQYfJSb2MSZ)K)'!JB1%K)*qH(0ZDQKTEhCkIS5)L)D$IhTfG(4fHAb !Ji*rHhCbF("[E@e`GRYpI(PeFR4pKSU-MBZ)KB1!IRakHATlJ)Q3!*58NSq-LSQ (KiD'KSD&Ji&pHAPrK)5%LBk6Niq*JRYeFR0iIB'$K)+"IRTfFQpYDfYaHS#$J(T dG(b%L)U*KS1"IhelHAKhGRCfHS+0PTZDPT+0LB@$Ji5%K)0rHRGlK)Z0LiL&KiZ 0MBb*KS+!Ii#$KSL*LBL'Ji"pHA9aF(&hIS+"Ihq'MT'3!)k+K)"pHRPiGhCdG(0 dGRb'N!#9PC+2LiQ'KB5$JRjkG@pZFhk(LBL$IAYqJi@'KS1!IRk!Ji@&K)1#JB& rI(TiGR0bG(PmI(TpKT!!Nj!!M)L&K)1"IhemHRKhGhKlIi5*MBk0LiH%JS"rIAY jGR0`ER&lK)D$IhTfGhf$KiL'Ji&rIAamI(YkHRTkHRPhFQeRBf&KC@Y`FhCpJi@ "IAYiGhGhHAaqIhjpHhPhGRKpKBf5Nj'-KS*qIAk"Ji1!HhKmKSk4MiU%IRb"L)Z -LiQ'K)1$KBL+Lib,LBD#IhakH(CcFA&dH(TpJiZ1MBU(K)+#Ji1#J(aiG(*cG(4 dGRPqJB1#JApqIAakGh9dFh0cFh9mJiD%JAejH(YrJS1%Ji1%KB@'KiD'KSD(KiL (KS@%Ji+"JS@)L)D&LC+APT54MSf,LBD%Ji+!IRakHAPkIB+)LiZ)K)"qIAepJ)1 %K)*qHRGjJ)D'JRplHATrKBH'JhpmHhf#KSQ+L)D%Ji'!IRajGR0aFA9mJSD(KB5 (Mj58Nj!!M)Q&JS#!IhjpI(TiGR4eHAk#JS+!IhjqIi#"JB"qI(PfFh&[FRPpHhG dG(Q!K)@$J(aiGhKlIS#!IhemHhYlHRPhG(&`FAGrKSQ(JRYhHB1,MSq-KS&pHRT mIAelH(CeG(9jIi1'KS5"Ihq"Ji5$JS"qI(TiGR9dGRZ"JAprJB5(KiD%JB#!JS5 'L)L(KB1"JB+%K)*rI(PfGRZ#KSH&J(TfGAb'LiZ*KB"mHhTjHAGeFh&aFhQ!KSL (JhjkGhGkIAprIhjpHhTiGh9cFhClJ)5*MT'5NBf)KB+"JB'#Ji@(L)H(KSD'KiD $JB#"KBb2N!#1LiD#IRf"Lj+8NSq,Ki1"IhjmHRGdFR0hIiD+LiU)KB1"J)#!J)# !IhprIRajGh4aFRGmJSQ-LiL&JRppIAeqIRepIAjrIRjpI(amI(YlI(q&Lif,L)5 #J(ejHS')LiU)KB"mHRPjHRTjHAPmJSH+LiU)KS5#JB#!J)"rIhprIhelH(9cFA* fJ)Q1Mif*KB+!IhpqI(YjH(GfGRCfG(0bFA&bFhClJ)1$JAppHhTkHAGfGhf%LSZ *KS*qHhPiHATmIi+&KiH'KB@&KBD(KiD&K)5$JAppHRKfGA9eGACkJSQ1MSb)KB+ !IRjpIAemHhTiGhCeGACiHRk"K)D)KiD$JB"rIAemI(amI(f!KSQ+Ki5"IRalHha qJB5&KB@%Ji&rIRjrJ)'"J(ppHhPiH(KjHAPkHRYmIS#$KiU,LiQ'K)1$Ji+"J(p qIRepI(apIRq#K)H,M)b,L)D%JS'!J(prIRemI(YmIB'&KS5#IhemIS#$KB5$JAj pI(apIAjqIRjrIi#!IhpqIAepIAepIS#$KB@$JB'$KiQ*KiD%Ji1$Ji1#JB'!J)# "J)"rIi##K)@&K)1#J(pqIi#!JB'!IRelHAKhGhTqJB+!IRalI)##JS'!IhjpIAj qIRjqIRjqIhq!J(pqI(YkHAKhGhPmJ)+#JB"pHhPkIS+$Ji+"J(prIRemI(YlHRT jHAPlIi5(L)L'KB1#JB'#JS1#JS'"J(pqIRjpI(YlIS+%KBD)LBQ)KS5$JB#!J)# !J(prIhjqIAepIRjqIAalHAKiHhq#Ji1"IhjmHRPhH(b"K)5$JAppI(YkHAPiHAP kI)#%KSD'K)+"J)#!J)'"JS1%K)1#JB"qIAamI(amIS''LSb-LSH%JS'!J)#"JB' #Ji1$JS+"J(pqIRjpIAjrJ)'$K)1$JS#!IhprIhjpIAamIi1(KiD%JS"qIAamI(a qJ)1&KB@%Ji+"J(pqIRjrIi#"JB'"J(pqIAalHhYlHRYlIAq$KSH'K)+!IRjqIRj qIRjrIhprIhprIRjqIRprJ)+$KB@%K)1#JB"rIhprIRjpI(alHhk"Ji1$JB"qIAe mI(eqIi#!J)"rIRjpI(amIAepIAjqIRprIRjqIAjqIRjpIAamI(amIS#$KB@&K)1 #JB'!J)'"JB'"JB'"JB#!IhjqIAeqJ)+%K)5$JS'!J(pqIRemI(YlHRTlI(q"JS+ "J(jpIAamI(eqJ)+$Ji+!IhjqIRjqIhq!J)#"JB'"JB#!IhprIRjpIAamI(apJ)1 &KB@%Ji+"J(prIRprJ)#"JB'!J)#!J)#!J(prIRjqIS'$KB@%Ji+"J)"rIhprIhp rIi#!JB'"JB'"JB#!IhjpIAeqJ)+#JS+"J(prIRjqIRjqIhq!JB'!J(prIhjqIRe pIAemIAeqJ)+$JS+"JB'#JS'"J)#!J)#"JB'"JB'"J)"rIhjqIRjrJ)'#Ji1$JS+ "JB#!J(prIRjpIAepIRjrIhprIhjqIRjqIRjqIhq!JB'"J)#!J(prIhprIhprIhq !J)#!J)"rIhpqIRepIRjqIRprJ)'"J)#!IhpqIRjqIRjrIi#!J)#!J)#!J)#!Ihp rIhprIhprIi#!JB'"JB'!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprIhprIhq!JB+ #JB'!J(prIhprIhprIhprIhjrIhprIhprIhjqIRjqIRjqIRprJ)'"JB'!J(prIhp rIhpqIhprJ)'#JS+"JB#!J)#!J)#!J(prIhq!JB'"JB'!J)"rIhprIi#!J)#!J)# !IhprIhprIhprIhjqIRjqIRprJ)'#JS'"J)#!IhprIhprJ)#!J)#!J(prIi#!J)# !J)"rIhprIhprJ)#"JB'"J)#!IhprIhprIhprIhprJ)#!J)#!J)#!IhprIhprIhp rIhq!J)#!J)#!J(prIhprIhprIi#!J)#!J(prIhprIhprIhprIhprIhprIi#!J)# !J)"rIhprIhprIhprIhprJ)#!J)#!IhprIhprIhprIhprIi#!J)#!J)#!J)#!J(p rIhprIhprIhprIi#!J)#!J)#!J)#!IhprJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J!!!0%!!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!$3@9Zk,S`!!0"3!!$3 9!$b!J)#!J)#!J)#!IhprIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB' !JB'!JB'"JB#!JB'"J)'"JB'"JB'"JB'"JB'"JB'"IhjrJ(prJB'!IhekHAk"JiU 0L)Q0L)1"Ii'$K)@&KS@!I(TkH(4dH(U%M)*hIAphG(CrLSf*JRapIRk$JS"rHiD DNiD(KB"qJSf9PC+)I(&XF(YlE'CXE@GSDQ9MD'CLEAPlIiU&HAq%ISUDQj52Mj' 2Ki#'M)9iDQKcG'CHC@995e0LE'GLD@TTF(Q-R*++PCD5RUUMN!#2S+LINT+AQT@ (HA*qMRPNDf*+3%GHCeC9BQ4PFAPcH)Q0Lj@RXDqaYE+XUkkQU,UrXjk8Qj4kDfa TB'"G6%G46Mmj2NpMEAQ0QCZDQ+'[YE[#`XA-`lV)fY#qZ+fIQj5$Ef&95%4%26d r,b)S18Y19'KlQ+kGNU@XV,rDhFDqeq$4cXDl[,LMLAU$M(9-,b3M+5mZ,MFj-6) m4P4KG)Z-M+Hqc0V3ZEI$aXcPlYrEelqPNhpVC'0@2cBf,LBY-5)9'bSj6QCeJBZ 4Nj1DU,V2f0(-cYAHhG2&XU1JRSk!I@e53c8R-6de-63b0$K$@'9XH(q&Nk@i`-A 1bm(%b,klcH6E[,#[Rj55He!k3%3k1%"#1#mQ("BL5@ebEi'APT5Y[lD[Y,r-f1R jpqI*S)Q4RTH+LAYA3Mij,b3H*#JN,NY46'"`BP9HGBqYcYl5b-@hU+feYm2+`+Z ISjU'E8`c+5B`3%8q1#mH%ada3e"A@fL#Q+#MU+LJR+@[[Fh6ep1lTD'HLR9cFf" 49&4&1MBZ)a`C'#)k6P9KDf0FDRk3!++ZY-('[-,@e,qaV++ESDfZQhaG46e"1Li Z-bdQ,$Y$36Y#8PCBDiUMVl@dVV'fXUf`YEc0hYR&Y+LGK@426&0BA@9G3#XR*#% L,NCIF(aqJjbXRT+CRkM%i16Cdp2*Yl#cVU@HNi0aD'KK6Mij0c%e1M3e4%pACR* eGhk-R+Q`Ylh$c-['`,+ZYlbdV+qbTT4j9$p'6Ne,4N0)q05ml6&CVMDQl`,1 HMT+V`F'iZmhEf-ZiRib%J(9MA@PaC9!r063i-#8U3&CLERCcGB@8Q*'*NkLl`EZ fZ,5SSU'KUkqSST0lF'TG8dBk0cFj2N4$16%c294XHSH3!*DKTD'GRDHcXUqc`Fr 1`,@VRC'*J(&J99YK96id0cJf-Lie3NTBF)')P*Z@N!#-N!#KY,l#`Ebm`m1mXTZ (Ji5*Mi0S88-h,bi[-$9!46ml5'9fH(YkHBk[[E'UXlLbV+qeZ-25cE@RRj'&Hfj J88a14$Jl3d-l-bdT-e0dJS5-PC!!M+#iXk+PVDZbbYrGbE1JM)##LB*`Df*,3dK #05mZ+5Jf8'GVERb"HAq0Nk5rbX6"a-+jXEI'alQXSTQ4LiTmA83k0cJr5Nj$1$3 a0dPFDR0iHS+G[-@fTU5NR*DSb0E6e-ZcR*+1Jh0VCPpE9Np*4M`V)bNe2NaTKj' 'Ii1)ND'd[lqp[Er%dGR1[EHXQTHHR*!!HPj*16)j3d!f-c-c0d"3Af*TFh1!RDq h[lkXR+'c`FR2cX@qYUZNQik&FeT-68p26%8h+bFX0%"@DQa`IiU)M+1fXkURVVD i`Y(3`lL[S*bMS*!!J(&E4N*(5N8m-bSL+$T%5PaQA9aeNCbNVEHeU+Lf[,h"a,b [UUZUUU15H&p24$j#5dj%0c%U*bp!5djCEhq%MD#VTU'GQUDj`XV1aEffUkHUTTU 5K@G16P4346JZ+bFR-$8h3Ne4@'9iLjHGRjbHUlUq[mA$ZVHdUUQf[Db-FfGG88G '5d3j1$8`06e%5NY0@@q,RU+IRU#JS+Ud[FA'[lDdZm'lUCL)FfCPB9C-48%q0#X Y-M3m4%0+BAZ-NjHDQCfUVkklcp$"[VffZ-($ZU@4K(a`@dJr16Fh0$)e1MSi16Y "8fk'Q+5SU+LRVEHj[-E)bmr+bmQjUCZ&Fh&cDPa02c3a-$%e0MFj0ce-@@CjLC5 @NjZ[Z,5f[EqlZEUraX@jTT@+Ih9ZDPp+1cJf,bXa16Sd-MT%9@emJBUBSUU`XV@ r`lfhYX,1c-LpU*@+LB*Y@eG42bmX-$3c,bma-cP$8Q9eIiQ6PTHNYVqpYE1l`mR 1cFI"YD#1IRChEeP)2$)c-bma0$)b06K"8@*`I)1,Pk1[ZVkm[,r"`mR0cp(+XCZ APiPfD&j226-b-6)c-#iZ-$G(@Q4TGBD8R+@`ZEl!Zl5e[FVAeXQpYDUFLAKaD&K '1cJh0$%Z+b3N,cT(9epUIiD"MULf[m+l[F6"`F[3d-QmXkqNPSPjCNmq1M`m0c) [+#3N*Lp"6PPXHhq'P+1YY,Up[-$(cpA4b-M%YUQPRj*rCNp"163d06)Y+#JV,$! p6&KKD(Q4S+Lf[VHb[FM(ap$Bemh!ZEDZSBpjDPT(2d%p0M3c,5FQ,6a&5P4KEhk 2SV'fZX($[m(2hGh9d0$0a,ZaSj0qCP4+36Sl2cBR)5FY,6%q6&CKEAf6T+LZZm, !ap6BeGACeXc&`,ZjVT4pE9C"2Mdd,LiZ,#JQ,68k3%eEDRk4SDqeYER"aFM2f0l DdFh0b-#eTC&pE&a03$Nh-LdT*L8T-$8i2%96D(k4RkL`Yll#`XM8hGV6c-R+b,k [S)ekDPY24MXb,5NL(L-X-6%f2dC3BR@(QkbeYl["ap$6d-r3dY20aX+fSBjrD8p '58)c+LFS*b-N,$3f1d98CRU2SDHSX,l(bFc5fYh8bm[1bm@jSSGhF@K@36Bd-LS M)5BY-M3e1$p1CRU&N!#LYlkk[XV4e0E5dG24dY6)XCf8KQeC6NT(1LNN*5BS+#` a0Me(8PaXL+'XVE'pbY29dXh0dY68e0,,`Uf+EQCQ@dSq16BZ*#!M*#F[1$a!6@9 pL)U5Sl1raml9fYM4bFI,dGE4[+HCM(CH6dK!0LmX+LJS+LNS+6%q8@ChJj'GSUU f`XhCh021dYE6dG(+ZUQEM(jYA8`p-5FN+LiV+#JU,#mi6'"cKC+DTDqlb-r1cY, 8dpADfYA,ZUHAMB*cBP!r-#`Y+5NX+bNU,M3q6&eYISkFTE#qb0$6cF[1dGEIiYR +ZkZGMRpcCP9$0#`V,#dX*L3R+M"!89jZIiH2RUkpbY(5dFl0dp[IfY$(ZDQKQip pCNSh-bdQ*Li`+#-P+5ii4PCQFRq8UVLp`FA(aX,&e1$PjGM"XUbKNS9jEPY#-bm V+LSQ)L)L*M*!59&IERQ%QE2$bml+`X62fGlJi0V1`,#MQ)pqCNiq0LmX,#NL(Ki J*Ldk5PCGCR5*RV#p`XM4cXE,eGVFhGM)Z,@bSBajBdXl-bm`-LmP(KdH)5`p5%p FEAb,Qkbl`m2$aFlDi1(Jh-kqYl1XST@!CN`l06!Y+bBL)"iJ+$)l3dY6AA#*TEV "[m((bXR0fH,KfY,-aEUZT**e@NP#2$Ba-#XI&aBH+$!i4e4BBA5+S,+la-c*bGE HhGhDdp(,`F'mTipjA%3p1cJf-#BI(4`F*$!k2dPEDRQ4U+q[YX$'d0lPjZAGcm6 &aX'kV*L!C%p%1M%Y+5)H(b)P+M%e0Me-ARLBYF#lZX$#b0ALk16LiGR2bX5dRST dB&9-3cXa*4S9&aSJ+c3i1Me*ARD+RV,!aF2(e0lJhY[CeYECeXZkT)edAe"'3$` d+"dD'4NH*#S[0N*5BA5-SUqbYVr0hqRSj1(Bcmr8e-brVT4eAeG-2#mS*#!G(5% M*5BR+c9&BS5GU+faYm,+cpcVl16KiGhEemDYQ)PpF'493cBV(4-4&KdP+bST-$K %@R@+QDZma-R@iH,HfpRFiH2MhXqjSSYeC9a64cSX)"ND'KJG*#-P,cp-AA5'P+1 a[-[CiqMQhYM@f0cIfp,"Tj!!IQaB5N)h+5)I(4iK)4XC(bNh6@GlLCDLUlA"dGh LjZINiprGi0M&XD#4L)"[@NBb)a`D'4`I)b8M)LNf3e4TI*!!S+r#dYIBh0cAdpE Jl1lJc,HMNB"aCea*0b`N(4XH(KNA'b-Y1daBC(U-PUDmcYhQiYE6f0cJjHAIdX# XQ)GkE&P%0#dU*4mI(aN5&"mU08PKEh9qM+1lbG$Eiq(KiqARj0cBd,fYUD'*E&C $-bFJ)#3L(aiD'4`M-%"1B(@,RkqmbY,@e06EjZhbm1MFblQYT*1$H'0*1#`N)b! E'4F8&b-X-Me,9Q9kN!#T`Y$@eY28fq(Ql1cPiGE$YDZFLR"@4MX`+LFL'488&"B F)c!r5P9MGT+XZXM9e0(DiZAVlZVNfXr([+qNN!"c@dNk,bSP)4iC&439(#J`-ca 2CAkAUl[(c-h0dYrTlr2[j0M4c-#XQj'%DNmp0#XM(KS@%a3F*#NV,cY,@'k1V-, 2d-c-dYVMkHhYlqcHcX'dT)jaAP9-36BV(a83%4)@(LNb16j%6fQ+S,$!cYEEhYr IiH2PiYVDfp2#USabB9)X*L!A%!m8'b8V,MP+A(#&QDbla-[5eq$Ym1AGh0l IfmkmUCQ%DP4'1c)U)KS8&4NE("dK+MG$9@f#PUZh[FE3fH$NjqRQj12GeFl$VCD #EPa-2c8U(4BA&a-9(#8T+c*!8fKmMU@laXV9iH2IiHAMh0cRkYV$VjQ#DPG-3cB V*L3I'"-6&aXJ+cP'9@PrNCZPYXI6hqVYk1,IiZ6JfG6,Z+#)G'453$3V)aXA'4X B&4NL+6%p6fCmMTbUZFI9iHAPjZATkqAIh0R0ZU1,GQ993c3T)KdC'4NC'"NG*Li j5f4lLCDS[XV2eYcIiqISkHMRiY6#XD'1IQj@4$JV)amD&KFA&4JI*M%q59P[KCL SYmE2eH$Uk1ASkqIKfpA,ZkUAJ'TC5$8Q(a`F("N9&KNH)LSf4eTYK*QUYmE@fpI Cj[$ZlHhQhYA)Z+UDK@jD56JV*"mF'"8@'"NF*#dh4&GVJ*5PYFM5eYlNjH[Yk1M Ti0A1`+bBKA4F3c8[*KmF'4B@&48C)5`h4&4PHT'PZFM0e1$RkZcYl1VRh0,,`,+ LLQpA4$Sa*KX@'"S@%4)E*#S`28eLIT5MXVr0h1(IiqV`mHhPfY21`V+FJR&Q8MN U*"mE&!i3&KJF)LBY1NPHFSHL[-[3dpMJk1cVjqMVkq63[E+LL'jB58)h+4iA%3i 4%K-A(5Ff2N08FSbIXEr+fqEQjHVam1cTipV5bVkPLRCN8d%[*5%E&4)3%"-C)#B U-80FF)'AVm24epMKkqlZm2,VjHAHbl1JNS"S88%f,#%C&!m0%"8C(#-X08*5CS' DVEh,eH(XlZcZlHITlZVHclfRN!"iC&9&1#`I&K-4$`i1%KSM,$G%8@4mMk+ibpR Nkq[Ul[$VkHAKhpI$V*4pD&9"-LSM("B4$3i6&4JG*6"$9@9iM*kaaGAIjqrdmHM NjqVSiY+qVjZ"E&K#0#`M'aB2$a35$")G+$9!5epkMk#b`-cFk[,hmZVVm1lLeY( ,ZCU!EPa+1bXG&a89&"!0%"FE)bik6fCfKCU[`02Rl1ETpIMak1ARjGI$XD#2H9p )0bSL(4F4$Ji6&aF@(bip69aYK*kd`mh8i[,dlZlZl[(UhYE)XTq2H&j*1biN'a3 4%a)2$"!D*5mk4e9XL*UMYY$MkHRVpIM`l1[MhGI+ZD51H@C61bJI("N@%Jm1%"3 A(#Be4Pa`I)qV`-cAiZRYm22dp2,UhY2'Xk5@J@T415dS(4-5%K!2%"!A)5Fa39" QIC+T`-c9iHVZlZrbp[6Xj0E%Z+L4IQe92c8T'a85$`i2$a%@(bXh38PCGT1QYmh Ik1VUlI,cmI$Xj0I+`V1BI@P@3c%P)"dB%K%2#JdA)5FY1e*QGSLLZX[9h1AZm26 mqr$Sj0h2ZkLFMh9B3c8V)KX@%3d1%4-6'LJh2N49FBkMYmM5h1IZmrAcmIEdip( *aEQJK("I5MFT)4`9$3i5%!mB)5BV0NCBESDGYX[Chq6SkZrhqI(TjH2FaDkGLR" C56S[*amB%JX)$4)@'b)Y1dC8DB'DX,r-fH2XmrAbm1lTjZ(6aEUPLh4H5MX`+#! A%!i-$3m6'b3X08"4D)#AV-$2eplUpIRfmZhSjGr@cF#TMRTN6$dc+"i@%K%2$K! 8'"dR-d&6CRbAVER'eqETkI(lqZrSk1ADblbZQ(YM8N3e+#%E%`d-$a%8&amT-$a 1CAk6TVV'cGcZprEbmr6[jZ$Hdm#VPB&X9%)h,5!8%K34%")6&KdP-$j0B(b8Skr !e1,VmIAhpqrSk1AGd-+bQRpV@8Bd+#!E&3m1%438&"FI+MP0CRf2S,6$bG2Nm[E cmrAdkYlCd,bSQ)PfA8Jm,am8%"!4%K)9'K`I+$9&@h+,S+qqdYrMjZhbmZrYlHV Kdm5YP)&aB&"",L!D&!i-%")6&4NI+6G'9QZ%QUc!dq(Rl2$bm1hZmI,Tf-DaR)K aAP&"-5FH&4!2%"!3%KJK+cK*@@TrP+@hcH(Zmr2bmI([l1IPfmLdTC4pCe-q,53 H'4B9&"%4%a8F*c0$9fYqP+QpcpVJjqrfp[2dp2$RfFLhTC*qDeK&05JG&a-4%4) 4%43D*64%8f0hM+#fc0rTl1cXmr[jm1cUhXUiUjU%EeT%-b8G'aN8$``0%"-B*$) q6@"bKCkhb0AJkI(blr2hpHrQfFr%XCZ)FeT$-bJI&a8A&K%1$!iA*#mj4ejeLCf caY2FiqEXp[clq22SfXr"VjZ*Gf001LXL("F4$!N-%43B)bih4&9TIjQdbYIIj1V Zm[6eprAVhY,(Yk'1H9j(1c)S(KB6%!d,$4)C)bde3P9RI*Lb`p,JkHcXmIIemZl Uj0R,ZUH5H9p,1LiQ)4mD%3`-$!d5(5Nh4&*SJjQTZmh@fH2br[rlqI2Pemh&[Dq AI@YA2bmQ("84$a%4$a-D(L3Z1NYPIjLb`XRAiq,Nl[AjqI6VipV+YkHAI@&54cJ V)a`8$JX-$K%A(LB`2%KEH*+RZXI6hHEZmr6cmr$QiGl4`+qDJ'K84$BY+#%B%!i 1$3m8'b3Z2%pJFibMXX,6hHIcq2RkpqrNhp[3`lHPLfpA46JX)K`A&434$K)@'4i S0N9EH*+QYF64fH$Rl[6kqrA`kq$6`kkCKA4N8N!c+5%C$`S-$a)A(53X0N09E)1 FYFM5fZIcp[$YlZlYkH6EblDJL'pC5%!i,"m@%3m1$!X3&b!X1849EiD9TEE-i1h dpI2cm1[QiprCdm1QM(KK66d`*amE'"84%"%3%4NM-N9CFBHATVM(dYlUm[IjpI$ Xjpr8alDLNB&Z@%3e*K`B%`m3%4)8&KXN-$e2C(Z@UlR+fq(Mkr,al[$bl1AGcVQ MMheX@NSl,5)D&K)2$`m2&"`Q-6e3D(U*RE,#eZMZlr([l[$XjZ$Dd-+[QB9cA8B e,#-E'4N@%!m5%aBI,6j4C(H-SE2"c0IPl[,bmHrVkHIEb,HYSBejC8`j-#FF&a8 @'"F3$4BL,6T+AA5+RV,%dGVJjHVZpIVflHAFcEZUR)YjD&C$-LBH'KB3$!m5&4` P,MP%8fL!NkV(fGcKkHhZkqIUlZMHeFLiSielCNir0LdP)"XA%`m,$aJL,6K%9@T rNkQpbpEMk1RXm22cl12FdF+hV*ClD&C$05dN(4NA%`m0%"FJ+cK$6f0lNDHpcYM Ei1[am[2bkZ$CdFHkUTD#EPK'0bdS)KS8%3i2&"NK+c-q69jdN!#S[Fr9f1(XmI, Zk1ERiYI,[+kGJfG54$Xe,53F&a%0$!i9(bXf3%YHH*!!SDqqdH(Skr$epZlNfp2 0c-QkRS"VA%Xj,LNN(aS8$a!8'4dL+cT2C(H-Rl,%cG(Gl[MjpZlPhGVAc,qdTj* h@dBk05mM'489&K88&"NL,$P(@AD9U,@m`XlJkr(fpHrXkGh6cF1bS)YdC9G'1#i M'a84%4)8'"iL+69'@h1(PkLkbpMKlIAhp1cMhGcFeFQjSielDP9%15dM'aB8&KJ A&KJG*6*%@@k&QUUhapAHk1ramHcQjZMJdF5fTj*kCeY225`M(aX9%a39%a8G+$0 !9R1*PD#``0$Hk2$emH[Ukq6BcmHfRiq%H'G83#iK'"8@'"JC'aXE)Lp#9QChMU@ haG,Hk1hYkqMNjHMPf-5bTCQ(FPe036BS'aBA'4SB%a)B*$0"6f0lND+`[F[Hkqh Sjql[kZAJeXLeSC1)HQTC4M%L(4mI'"-6&4JG*6!r8@0cJC'U`pEIi1,UlHEPk16 GemLdT*H0JQT22MBX)adD'4J9&4BD*$0"69PTJCb``0$GjZRPiHAUlHlPdF+lVjk ,H@KB5$JY*5%G'aJ4$"-I+6%p5PPXISkM[Y,Fi12Pk1hZkH6EdXQpV*f5KR*F4M8 Y+#)I("F8&aJF*c!k59GLGjHba-h8h0rKk1cXlHVJeXUkUk1AK@pF6$id,#3J'aB 8&4FH+6-k4&&MHC!!TVh2f0cEhHMcp1hRiGA([E5UQS9bB%`p05mT)KN6%a3A(bJ a18*2Ah1,TEc)cGIMjqR[m1VJeFr0a,Q`SBTbA%Xr0LmU*KmB&4BA'b)X0N"0Ah@ +SEI"aXh@jI(clqcNeXh*`VbcRiakB%T#2$)T)a`A&KB@'b3X-MT*AA''RV1paY$ EjH[Ym1hLep$+b-+`Rj&jB&0*26-Y*KdA%a3D(b)S-ce'9Qq(QDLfa-rDjHcam1E EeY(-bF@kTSpkCeC)2cJ[*"dD'"SF("mR,69&@h1)Q+@c[mM9iqhdmZMKfY,2blq cTT5!F'"236JX)KdE'KXI)#!N+M4$9'Z%QD@`[-M9iZRYlHIKhGM4bm1eSj!!IR* V@NBj,b-F'KSF(b%L*#Ja3&*UJC!!Rl#laYAKjHVXjq(FeGIBa+kLNi4kE&T-2Lm N(KSC(5%L)L%P-d45BA1*S+feaYVNkHMMi1$Jhpc4`E@SPSCiDf"42biP)4dI)4d D(53U-Me0C(U*Nk+hbpMGiqMPj1AKfpM8blbQNSQ#GfC226-X*5!H(4mK(b!S-N& 6Afb!Nk5ibp6EiqEPj1,JiGr9a,1RRj1$FQ*33cFT)#!L)KmE(#)T-6j0@farND+ daYEKjGrEhqITj0[3aVfZQBZ&HQPA4$3Y+58K(4`F(5)U-d"1@@4eKjbeb0AGhG[ NjprDhYh9bEQTT*Q&G'443MF[+bJM)"iE'KiR-d&-9Q4bKCk`[FrCfGhQjH$JhYE 1aEUZSjL+HfK33$Nb+bFP)KmF'L!U-ca)9Q4aK*kb[XV9fYcFhqEShpA2`l@`VCq +GfKC56Sa,b`S)"SE(b%S06j#6&jcKCHT[Fh4dYEGiqENhG2,alqcTTb5JfT64N% k-L`Q)L!H(L-U-$Y+9&TRJ*b`ZX21eYhJi1AShFr,albdXDD4HfKD68)i-LmX*4m H)#-U-cT"5PYeLT5KXm(*dGMHjZVPh0,(`X'pXU+5KA4H68-m0LmT*#)L*#FU,68 q5PYZJCDUYVh#bYAIjZRRh0(,aEkjVk+8K'pI9%P!0bdS*5)K*5SX-$8l4PCTJ*H QVlR'cpAEi1,Kh0I2aX'pXU'3!)"bCPa02cF`*b-N*53Q,M3f1%*AE(f0Rl#k`Xc @h0rJhYM4bmV+`l'INiCdC9T24MXa+b8K*LXV+LSb2NP9DAk1RDZf`-[6h12Mfp6 8e-l'Zl#MP)4hEQ*95MXX*LBS+5XX+c!e1%*8D(b+QDQh`mrBfpI9fG[Ad-h1aV+ IMi&hF'CA56`d,LJN*#JV,5ie3%P4Ah+%NU#ebG(6fYrAcXl3dpM4`VHTNi*iE'& A6%)h,LdX+58L*#Xe2dYECh&pLTLV[-cEj0r8dpE3bXR([EDZRSk"FPp346Xc-$% a-#XQ*LNZ0N0@Ch@#MCUY[F60epI@f0RBe-r*`,#LQT1(GfTB4M`f-LiZ,b`R*bX `1NK6A@amM*fa[mI0dG$3epVBep6(ZV1RR*@'G'TH6$ij06-a,#JR+5ie2NC2@fT fKCU[[XV5dY(8f0I@e-l(`EQZSTH-IQP64N%q163c-#XS*bNb28C0@QelL*kb[-( 'bp$9ep[IhG,$YUqXTTZ1I@YF6N!k1$8a,5NU,M!d280)8f"cMD1[ZX6(a-M5fGR Bep(([lHVSCU1H@CD8dY$1M-[+bSU+c!h280*8f"[KTkZYEc'c-h4epRBdmR!Zlb jV*b1HQ0@8%Y$26Sd,#FT,M%d18"*9Q4eL*UQVlV"a-hCiGr9bXE#ZlHfVk+4I@Y I9%P!2$Fb-M%[-$)h1MY"6Q&iMTfTXlLl`FV3eYVEemc![m#iUCL*I("N@e90363 Z,#SU-6Sp1Ma'8PeVJ*DSXEDrcG6@ep,+amE*cFDjX+'+GfPI@eC,3M`b,$!`,#m h1cj$6f*jL)kATV5la06Ef0A4b,qq`mE"Xjq-IR9U@8p+36Se-#md0cFd-64"8&p dLT5ETl#h`Fc4dp65cmR(b-+dU*f3!(pbEfPD5Mme,5da-c8f0$Bm3dYBEB#-Pk@ c`-V3dmr*aXE*cmr)[l'HLheeEQ4E6d)k068d-c)a-$-l490PFRZ&MjQSZFR@ep, ,b-M(aF6$[,'NPiYqEf*95$ik2$dj0MFf,b`c3&"MGB5,MjUTYX$&bp2Adml-bmL rX+@KQT'0JQY@5Mme-63k2Mdj0$-h2NK@CA1(RUZ[ZF2&aF2#aXrAf-r%Z+QCN!# ,JhY`BP4'1MFj0c8c-M-j3%4-@@C[HSQCUlh+c-I$`X2,dFh*`lZbTjL2L(eV@8Y &4%%m1MJa,5md1804A'0ZIBLAU,E!aFE(bXc0cFc&[V@UT+5FMhaS@e&&3$mm1MX j0$-f18*-8PPSIC'KUl5l[lkp`X[2d020[l+YUU'8KhYaCPK-4d-q0c-a-cBl3NK +6PTSFi'AV,V"a-#k[m[0bmM"[X#kUjkBMAYUAPK568P%1c3a-M8i2NK39&YSGS5 8T,'i[-,(bFV+bFE!YV5fXDULNRpZ@e&5680!3cdc-cFl26p%6eYPH)qJU+Q[YlQ pbG$5cmHqZVDaUkLJNB&aC&a@6N9!1M3h2$Xl3%4(6&9MGSHATl'`Xlh%aXV,b-@ rZVLfY+bGM)"bBeaD88G"2$Nh0$P!3%"%5e9MGiUBSD@UXl[#b-[1cF1jZEQcX+b JMS&fD@&E88Fr1cXj18"#3$p#4e*PHSQAS+DYX,@ramc1bF,![ELdVD@FN!#&I(* RA94)16%e2d0$38༃Afq#PU@XVDqkaF6!`F,$a-1rZl+PQ)YmFh0bCP9*2cS k1$Fp3N*$4NY4B(@%LT+KX,V!`m$#b-DmZEfr[VLTQ)b"IAKUA9C13cdk1$a"36p !3NKCD("kL*5KVE+mb-M$`,kp[Efq[,#MRC@'HR0XCea*26Sl2d*"2Mj"48Y8Afe qLjDIU,6$b-6![EQp`m+q[EDSQSq&I(CaC9C,4N%q2Mik16a"4djACR9jI)LFV,D paXV([VLm`VqiYE+UR*+2Kh4PAeP13cj!3d%m1c`q3NaFDh"dJ)fATEE!aXR%[Vf mZ,UpYkfSTTU)IRPZB&&*5%C%4%!l1MXq48eABQpkJBQAU,Lr`,qr`FE$[,ZkXl# UR*12L(e[Ae&-5dP%2MXp2M`p5&4CB'TeIiZATV5q`X,$aF+k[-1mVDHQSTf@LRa ZB&G24N0(4d0!1cY#4NT@BQGaJiqCTV#j`,fi[FM,aEbfVk5ISk1@LS*eBe9-5dT &3$mr2Mp#48T5A'KaHSLEV,1bXlV!`X,%aVqdXDfIPjfINS"bC9a96dK#3%!p2%* '58p9@PpQG)UHUUqdZEbq`-(#[lLeX+LSUU5DM(KUCPp@8e403MXl26a"58p9@f" ZJ)b5R+QbYV["a-A*aEU`UD@SUU+CNB9eDQ"A8Ne'3d!p2%"(69"289jZHS@6TE+ bVlM$aFE)`EL[UDbYTU#FNB*cD@*F@%p'36Xk3dY*5%a499KKH*!!QU+XXV+f[X6 %[VUlZE'UUUZMP)CmG@pUCep45%)l1$P"6&*46e0GCh@%N!#ESkQf`F(#b-DkXDZ RV,+YSTU3!)&cE@TN@%e)3M`m38K,4N0-9&YRH)L9QCZRXlDmb-V#ZE1`VUUQTk@ BKi#!HQeNAP*$1MY!4NY-5dY*5eGRGB'1Qk+RVVDr`lqlZ,1ZX,+bV*f-Ki4lGAC bCP9%16Np3NK,6%a-89aREhZ(MjLQY-(,bEqhX+b`YE@cVU5@L(pkHACXB9C,3cp !3N9'4%9,8Pp[H(b!L*5LVlc*cX5jYE'XV+q[Uk5AMBH#IA9TAe4(3dC'4NK'38* (8Q&VFRq(KBkJVV[*bF'lYV+cY+qTT*fCNSH#K)&[@8T)5NC&58P%38*(8PjSGB# !JSqKXm(%`VqlYE'dYDqXUCZ-MC12K(CTAP9-4N9'5%4!380)9'4XEh*iK*DLVEh )aVkhXlDkYUqQRTZDP*12JhKX@P&25NT15d%p2d&*9f"QF(GkJ)kLYEr![EHf[X# jXDfSS*D6Q*U5KhYU@P&388j*4%*#3N"&9'*SDQecK*UQV,DmZlZq[,c![E#LQ*5 @QCZALhj[AP0368Y,48%46@9CFC@TdKC5NZ,UdY,@i[X(![+qLQTDAQCQ6M(j VB9eA8de#28"!3%YB@PCBA'*[KCUTXV@dZEUfZX6#YUbNRCbFQjZ6Jh9XD'4E99* (2$Jk38T39PYF@Q*bJC!!T,+cVl#i`FA#[E@TRTQCSD+DNSYjD'0NC&a13$`m2N0 ,89999PTKF)DCSD5UXEDl`-A&[E'QRTbISU+GN!#!HAC`C9a@8%3j1N&)6e048P0 6A(D,P*kTVDfaZm6'`VQ`UD5ISkLNPSU"HA4[EQjK5MXj16j+8P*58%j@BR#$Njb LTkfi`XE)`lDUSk+QUkZNQBTpGR4eG@aE5Mmk1N&*68p16P*CCA1#NCHBRl#raXR *`E@TSU1QUDQQR)k"H(9fF@4A683p2dG-6%P&48PBEAU$MC59QULi`m[-`E5XTD' RVkUEN!#0LB&mHR9T9N3p2N"&69&,4%*+@'GdJSU0N!#FX,r(b-+mYUbSU+LXVD+ 8Khk!KB"aC9C'3%"$5%Y)4N9#4PCYHAk%KSfFVV[)cmHjXDURUDfZUD#4L)Z*IRP dCe9'3N9+6NT%26Sr6&eYGhk%KBUAU,V(bmLrYl1cXUUKRCbAMik8PBCY@8a$3%C 28dj(3d%q3P"MG(k!Jj+NXEZq[EZhYVQiYVLbSSq(Lj1@NSGiCP4*38"'5dT*4Mm r6PpMBfYeJ*+SZ-(%[l@ZXE@j[EZ`STD4Miq1LS0jDeP058Y-4$Xk2N**8PeNC@G [HBHFYXE'[lHcYVLfXV#VSjbBPjQ9Mi0Z@e058P&15%!l1$P%8PaJC@PVHC'LX,Q jZ,ZkZ,Zr[E@QPT!!PCfLR)jqEf4D8Ne16%Br2$a#5e*A@9KGE(q5T,'j[,UcX,I #`lQ`UU'ER*bDQC!!I@aPBPa@9%`r1$Fl3dY4@&eHB'4bLU1aZ,UiYlh![EbkVk+ ERDHUSjU1H@KLAepJ@8Y!1cFf2dY589*DBQerNCZMVV1bY,r*bm5fTTbDRk1QTjk 0I(*UB9TC98Nl1$j#4NY06Nj29fCrPU1SV+qZXEl'aEqjXUDFRUHTSC5(IAGaDf9 H8$mh16Sq59*56%G*9fTlM*bPUl#cZF,&[lLaTk@SV+fSRjH(GR"`F@aK8N8p16T !48G(58j@A@KmN!#APjbTYm('bFR"X++LT++QV+UFLRjmGfaJ9dp)2cY$5dT(4$m r5PadL)f5RU+MVEV$bmQpYDkMTV#VRjZAMiH"I(GZ@dBl2$j!5P013d&&5P4SIBZ 6QTqSYm6&[lfiX+fXVDq[UU#2JS'%IA4YB%e"2d&$4%9#384*89eZI)+&MTfUY-, 1bVbcVkQPUDfYUTk5MSb&H@pQ@%P%48G*5%C#1cJr6@&dIAq(NCQNXll"`F#kXDf [XDbMRC@3!)q2MBGpD99(2MT!4da04Mip49&BB@jjKT5KVlc#`,QaUUbcZ,LaUD5 EM)5(LS9lEf&3480%3Mik2%C,6&*HD'eZFi@HXEr,blfdX+ZRUDkbXDZJPC+3!)C lF'0C9PG35%G$1cFi28GAC@Y[GAZ$NU@f`F2![VUcVl+aUU'FQjkIQSq"Ff9@6dj -6%Y(3M`k2%96A'*TFAk3!*fQXVkqZ,1cZEqlXUbPQC5ERCD4LRTTB&C+5%P&36i q3%908eGFBfYeK*ba[F#jXlHjY,1cVDLSTU5KQj@4JfjLA&TG@%T$3cdh1%"*8&K MD@YfM*bMUl1h[F#pZlfjVD'DR+'PTU'6J(0XB9C26Np+3Mml2%9,5Ne9BA'%Mj5 IVV@dYEQp[m#kVk@IRTqIRTbBLRCXCee56%K!28"$48G'59"A@@&hMTfTXVDhY,1 k[lL`XE'QSD5RT*Q(I(TaC@*L@%Fm1cXj2NK,6&"6@fThJC!!SkZ[YVUm`-'jXDb NSDUXT+#FNSClF'PM@9",3cXk389&4%9+89PQGSD9Rk@ZZ,Ui[,kiXkqXV+HLTkL DLiCrFfjVAe0)2$Np2d&%48P-699PFhf1R+@YYE[!`,ZfXDZXVDQUVkLEMi*jGR9 YBP4)3Mmk1Mj"4%G*8&YRFhZ%NTqVZ-,%`EkkVU#GUE5cVDHKPiPqGQYKA&T85$i p3d3m0MY&6eYTGi1*NCULU,6%bF+jXUfZVD1LUUQHPj''HR9`Ada%4%C&3cmm3%9 %4e4MFRk)MCDMXm$$ZlLlZ,#YUkUYV+DLQBf)KhYS@P0-5%-r389!1ce$6&9KF(U !LTZSVlM!a-1jVUbYVl'`V+HLR*1*Ih0VBP91584%48%l16Nq5ePNEhU%Lj+HV,H r`lkiYV@bXE#TSU'KRjU3!)CrFPa058T)3d&$36`j28P@A@4aISL5Sl@kYV@l[VL `Vl+bVD@LSCb@Nik!E&jA6dG%3d0#3$`l2d90@fPZGiQESkLa[,qiXE5jYV5aUkH NSU+GNS9mFfC@68a058!k1$Jm3dG0@'*[ISD-QUUdZ,LfZ,Zp[,5RSDDSSCqLRSp qF@4C88P&4%0!2Mp!26e+@f&NFSDBT+Z[XV5fZ,HfYlLeVkDJSD5HPSq#G'YL98a &3%%r16Nr4da,6&CMEi'@SkUbYE@eXl@kZVDaV+UXUk+BNSZ$H@YJ@e9,36Nf16j "3dG-6eKSFRH*SDf[XVDiZVbjY,'`VUQTUkDKQSk#GfYMA94)3$dl2%"!2d*&5eG JEB59R+@XV,'jZEHkZlLbV+USTD@KPSk(IA4VANp$2MXl2N&!3NC&5&&GDhk1QU5 XXEDjYlDjYV5dXDqXUDDKQ)U"IhPVA9*04MSd1$e!3d9'5e&GERU$NCqUXlQl[Eb jY,#XU+kiYkZLR*+%G@aYCeP358!m1cXm2$Y"6&PNERZ'MC@IUE1raX5jXl@cV+D QVV5YRj1+Ih9XBPC048&&3cSj3%&!4NpEERf#LCHMUV+l[lbiYV@aVUk`XUfJQ*D 2K(Y[BeY24%%q16e$3$Y!59*GCfpmLT5HV,Hp[m#kX+QVX,5eY+fQRj@,JhGXC&j 85N4"2Mil1$Sr49"HDR9rK)ZDTkkh`-+qYkq[XDkYVUURSTL4M)&bC&C-5%9$4%3 q16Nl3NpECR0pK)ZATE+jZEUmZE@cXl'ZUkDMSCb@NBGdB9905%4"3NG&2$Sp38G 6BQefK*1HTUbcZ,HeXl1iZE@bVD5IRTkENB&fF9p+4NK'48-p16Sq48j@A'CfK)k 9RUbk[E@[XVbrYl#ZU+HQSCZCPBarDe9-68Y(4$mq2ciq3NT5A@YbGB5EV,+aX,1 iZE@bY,HdUU5MSU'KPS0dD9pE9%P$4%-r1MFm4e&A@&aUISZ9SkQ[ZE@ZY,UjYlD [TD5SU+DJNiClEf&98&*346`i0ce(58G-@@9YG)#9TDQXVl#cZEfmYkkRTkQQSD' LRBplD'"KA8j$3N%q3dC#48e48ePMG)LBSUHVVUq[XlDfYV1YUkHJTUbJMS4pG@j P@P424$dq3%9+6&"68eGNFi@5QU'VVkkaXl5hY+UQU+DRVkbEMB9lFfpVBeG04N* "384+8&"-89eVGi#,Q+#KT+beYlDhXkLLT+LUUD1GPSYrGh"RB&Y546p$6&"15NY 399TLFiD2NTZLSUD`YlLbU+5SUDDPTU@GNSGrHAGbC94+58T*5%Y48Np08&PQGB' *N!#8QDDaXDfYVkfPS+@VVUQHPC'*IhamFf4E98a'5%j588e+6ePKD(4qJB@3!*Z LUDqfYkbIRD+PU+UQS*U4LB4pH(0TA9*-6&*58%p06%pAB'YeIB'%LT5JUl1dVkL MSk1KT+LQRjQ9MSH"Hh0R@P0499G889&368pABQadHS#(Lj1HTkfYUDHRTD+PU+@ JQT12MSk+Ih*SAP959&CA9e436e0CB'aeGRD!MjLGT+QVUD+ISkDQTU1HQC54NSq 'IA9VB&P@@9YC99*38eKHBQG[GATrKT+JTkHNSk'JSU@QT*qEQCH5MSf-JR4RB&e GA&TD@&069PGEBfY`FhKlKjHGRU'LSU#JT+DPSjkANT'6PC++IhGZCPpE@eaE@PK @9ejNCQ4PEAGrLC@HSU'FQCbHS+@SSTZAPTD6Mib)JAP`D@CPB9aB9PCCA@"MCQT XE'pjL*5ERTqFQTfJRjfGRTbDQ*@9PBq$HR4`EQeUC@"F@9GBA@&QDQYVER4mKSf 4PCUHS*qHRk'HPT'8PjLAPBq(IRGaE@PSCf4JA9aHB@0MC'CVF(CqKif4PTD8Pjk KSCqEPj@6NT19P)k'J(PdFR"UCQ*HAQ&MBf9QCQGTE(0rL)f2NC1@QCZER*bCPC5 9PCD9NBU$IATjGh*XCf0KB@&LC@KRCQKXF(GqJSH-MSq6QCbFQjU@NT!!NT5@P*! !M)D"I(KeFfjSC@4NC@KSCQGRD'T`HB#%KSQ0MT'9Q*ZEQ*55Nj15Nj+0L)@$J(e jG'eTCQ9PCfTVDQPSD@ebGhZ"KBL,MT1@PTD@P*'2NT@9Nj!!M)L%J(jpHhKbE'P SD'PVE'TTDfe[FRKpIi#$L)f6PCD9P*'2MT!!NC'5NBf)Ji'"IRTfFQjYE'aYEQa UDQYYFRCkIAk!JiD+MT'8P*+3!)q3!)q2Mif,LBL(KB*qI(PbE@aYEh"`EfpZE@j bGAGkIS+%KiZ2N!#2MBf1MSk2NC!!MBU(KB1$JS&pH(9cF'p[F("`EfpaFh4hHRP kIS+'LSf1Mik-LiZ0MBb0MBU(KiD$JAppHACdFh0cFh&aFA&bG(CiHRYpIi#$KiU ,Lib-LiZ-LiU*L)H(KiD&JS"pHAGeGA9eGACdFh0dGACiHRYpIi'%KSL)L)L*LBZ ,LiQ)KiD&K)5$Ji&qHhPiGhCfGR9fGRChGhPkHRYmIB#%KSH(L)H(KiH(L)H(KS@ &K)5$JAppI(YlHRPjH(KhGhGiHRYlHhapIi#"Ji5&KBD'KSD'KB@%Ji5%K)1#JB" qIAamI(YlHhTkHRTkHRYmIAeqIi#"JS+#Ji1$K)5%Ji1$JS+#JS+"JB"rIRjpIAe mI(amIAepIAepIAjqIi#!JB'"JB'"JB'"JB'"JB'"JB#!J(prIhprIhprIhprIhp rIhprIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!,d!!!3! "!!8!!!#J!!'!83!!!!!!&!!!!!!!!#m@9Zk,S`!!,a3!!#m9!$b!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhq!J)#!J)#!J)#!J(prIhq!J)#!J)#!J)#!J)#!J)#!J)"rIhp rIhprIhprIhprIhprIhprIi#!J)#!J(prIi##JS&qHRf!JB&pJ)D$IRPdGAPkHAb %L)&fEh1!KB#!M*QJR)PeER*dFR4hK)TlHhpqJ(KdIT!!Rjk6JfeXGfaNERU#J(4 XCf9UC'b2S+HSMB')MSekI*HMXVDJQ)jlHhk$PDZcSSb#GfPRCQGqN!#,M)GiE'C dI)1HTT4rHRpbE(0cKD'MQjQ(GAk!Gi5CU++&F'CJBP*(@QCVHRGQ@946@fjbE@K PAe4HB8!m@'9VF@eSD'p`F)16NBL!KBGqIA4XG(q"HR&ZEQpfJ(q0QS&fIR9iIhC mMU'[U*H+NU#JUV+VY,#CSE#HLiL(ND'IJf&99&KRFhf)KRjZ8$Xi28eHEi18PRe NCh+)RkHia,fQM(jaFB'2R+qcT*&e@P4RE@TrNj+%FQ&-3%01D)@9PSKfD@TlMU# bbY1kSC'$Hhk0SDfaXCq!DQYcER&jI)*iANe&1$%j9)#CPik!I)++RVE+fH(C[jf 2N!#-M*@TZVQaQ(C[F@GKER4iJAPR8N!q1$eJHi4qC9025P"IEAQ&N!#8Mi0ZA9T THRk"J'C05da2@'&LChCS56Nc-M!lA(*kH@PRE'4NFB#(M*+%FQYMDRL&QUUSRT1 0KAYfGAD"QU+2G@CHA&e@9faiE&Y699TJDAH4UUqEJhGeJ)f+Mk#SSj*pEQ4MCfY rP*ZCKQjKCh9fIjDIRjf5KS"qJBbKVkqJJh0pLT5FV-("Zl1FMSGqI)QIV+bTPRC PCQplLj1)Hh"MA&aICAZHVUqeTSZ#JS5(NkHLNB9pHA*aGi@NYDZ9F94+6&pcHi1 (L(aVD@TVFAH%NBpqBP&39QGqNTkNSCQ0JACeJC'Zc-kiQATPBhQ3!*fTS)PjBdT !5PT[Mk@HMATQA&jSG(k)LS0lEf"45P0ZLjbHNhpI4d4*9fq%MC'0HfaZE9jNJBq 1Mi0VDRQ#N!#HU,'iYU#(HA"XHTHQTU@DKRTeG(*YER5"KQpJC'0FCAf,S,bTKB1 #H(GhEfT`E9P18Ne+BS1+JRGKAh4kEfKYFA1)P)&bFh4aFhq&IR0M@QGjIAb#KBH &HA0pK)5)QUb`U*H0P+QcRSb5PC1DS*k@MApjMUHTRC!!Lj!!RDQQRUUdTCD+H'Y M98eFEQeL@PCDF)*lHSU1KiH+MC!!M)kBVF#hTCqALiL1N!#@U+qMQjD&F@"-49T UBeTMD@*[JRTpM)b+NjZ5I@jG9'Q(SVUhQAYfIATiIS##LiTkEQGE9&TLC@KVC'* bGfYTEh0pMBPZBfefGh*bH)+*I@jcI(b#M*+DS*H*IRC[Eh9iGR*U@8e38e9PF(D ,PBKmGh0fIifDTUkRQC!!LAq#Q++LT**aAeY348Y26P464Mp$46Xq9@*[J(YVCQY `GAeqIRe`C@G`HAZ"PDDYUj4eDQCJCh"bFfjTD'jdFA1$NjbEP)PiEfGLG*@STUQ [Rj@@Mif4RVI$Yk56L)@0Rl'bT**rGR0UE(Z(NTfLR)YkE@Z!TlZ`STL(IS#'M*Q [ZVbpXCCkD'9`KTkMPi*cD@*IBA#%NjQ@Mi0eDfPiPDQbXk@8L)')Q*qKUE5hXCk $EQ9XGhf+MB"cCf*ND(+"M*'1JQjPC'b'QCUBNBL#JiL4T+kQSk5IQ*+,KBb@QC+ "EPeAB'jlKSb(Hh0Q8dp26PPVGh0L99CHB@9ZIj16K(9F4NY99&aZH(Y[984"5&Y XFhZ"JhpfEfCJ@PpqQCQ#D9C2D(ahHi1#H'jcGQYNB@0aH@pA4%0'6&0BAfPYCPe CA@9UF(0eGfT34P4VJj5AN!#-L(acF@jRDAL!IAGS9%T5B'ajJATXBQ&RFi1'L*1 FQSk!G@eVF)5HUU@GR*bFSkbRUEHbRiYiCQ"UFRH0STU*JhppJib3!*@QXUD2I@Y LFAf'QUDDJA9`D'CSFBUJT+#CN!"qC9KMJ++QMi@0MAq"MTUfb,HXVUHGLh0cMD5 TUDqiZ+LHRU@eZ+QJSkDLPSfAUkDANSb8RCUGT,E)`lblYD10LSkKZE+NSjqBN!# +KBH8Piq"FQeJ5d0$@A0XAeYD9d8a0&&`J)q4HQ"126%qBR9eIB4rH("M@QCkL*@ 4FeP168j3@'KaFh*Q9%T08&CVKU'TNA9UFhpeFB+9R*'!GA*XCh5*R+kQKA&cFQK XJ*HUUCH*JA9R@epeQEl%TReQAP9CFiqJQiQ%KApbBQ9qRD50F&eD9%P@DAkFQB" lIR9TC@f"QU@9I(4lGh*rL*'GPiGkI(efHB+1QC!!E8-[,MC,BA&kIAGQ@Np$8@b "PTqIQ(YB-LC(GC'AMi9rH&j'8h50P*@6H%mf-6eCITHHSU5CKA0dKjkjb-DlU)9 H@S@[ZELhTj+#DeYED)+IXlblRh&58'Z,QCbKUkQ1Efk&R,(#bX[)Vi"HBAZAVEL dU*Q)H(L%L*5XVTQ"B8Bl3eY[IBD'K(CI@QGkLjZ``EUJL(TjN!#`bGA1ZjKdDhQ 1QjD1NTQ)B$`L+6j-B'aYD&!k-MY8C'f"Q*b*GQ4+4&4UKk'QNA*UGi50N!#3!*Q PRi4U@8p,8QQ"MSf!GA&hHh4aFS'3!)k)KSZ6NBkLcH$#Nh4fMTH1KAq'Li&[D(C jDQYZDQT[EfPbIAaqJhaVEAKYEAejEA@,MSZBMS5MZlQaTjk@NBTlGAPlFh&hE&P 9C)+8Niq)JAejIB+(ND#UT*bIS++PRjqTYVUZQS"XFAefEhZ)J@aE5ca$@h5%KS0 dAP96AA"lIAabA%3k0M9-E)QLVl'MM(abGB+-NBf,M(aT@%P8FTDdVj4pE'&FDAk *PU#8Ji+-JfpcJCHbXjq2J(4eIBD8RjZ9PBakE'YdKkQkVTU*K(P`L+1bZkQ*G'T G8Q"cJD'dUjqCMS11S*kCPB&VC'*94%YPJTZ9IR&UC9pLITbKPSYkDfPSC'0bMjq GQ)PdEh*iKSq,L)GiCf"KD'GSG)'(Hf**3PCZKTbKQiYa@%K%5e4NHC@[XTZ'Kj@ LVV1SR*U6JhCeH(9lM*HFM@T9@QeeG)19P)Z"JT1@I9P-C(b$Gf&GE(PiEA@0PC' *JB1)IfPMFSD9KQPVK*U@L*LbZkkCQ*kENAeeLk@`U*LGY,Z`STLEQRpcJSq0Ih* eKT!!M)4jHSD,NTbMUU#+LCQFNB4jGi12LS+"JiD%JB1,PBjqHRepGfTSGS'%Hh9 `B@*[HSb8NiYlF@eL88G0BAL(MB9X@9j[HhK`F'CE@dp&89eKBPeQH'j858K9E(b "Ji0kE@jfG@p[GAb+N!"qCeP@C(*dGB+0KB*rDQk*NC'ETULJQCHHTUHXYF'rTjZ GPSb-M)U6RT4qGRk*NCD5NC@+GQeVEhU+P*!!Li4mHh4aKC!!ND#URj!!MSKpISH AVEQ[RT@+IhTmJ)@,M)4fE(*YA9KIFi&hE@GIA&TNIBD(MBGmGA4ZAf"fMTD5MSQ 0NBq@QT@*HR4SAfCPDAL)MRjTB&GA@fU+RCL+K)5%MC15RDkcUD'BL(GRBh'+Q)" NA9PFDQaUGSH1MB&eI)*[CRH3!*b8Ki+#LT52JAq&LC5DQk#GNC@XYDD8LAPTC'a YCh4jEA9iC9YKAeYZJACPBQCMCRL%Ki@!JBL-LiL$HS5GSjL$E'4H9epQB'4VB&4 96%0-8%P3CfpPAPj@8&aN@9T[J*'EPj+1LBZGVDHEQT!!IhYqHA&hKT+DRjD!G@j RG)@%IhppHAPhHS*lI)f9Q*Q6J'GQJT@1MU1RRjk1Ghk6QU5i[V1NNB+)RU#-L*D IRC*i@eaSDhqBS+1DJAH(T,'MR*f5KRj[A@9hGRZ8TCb+IR*fLiYlIB&fFhppCPp RFibQUk#ISTqNVULFRD1@Ji1#FQemKSZ8PiGbFS',P*b6JRKXAf0XA8P4ChQ+Pj! !Ihk'LTbZT)k"GQPUCe"2DRf$IAGjGR&hIiZEQS0YBQ0pP(pNDhKlHACcGAf'MCD QTjD-LT'ENhacISk4MBQ-MSH8XE+INB*ZDAQ'KAaeHB53!*H3!)f)KT@LRTLCKep 9BfCNB9aEAQ"D9f9`FiQHLR*jH'&FERq%IA"ZHhaXChD'PUDFIR9qG&K4DRaaA8S j1Mia,djYHSZ5IQpYA%"(ESGrCPPJEATdDS#NVD'1GA&qFeGAHjQ-EQPXDfTC5fU 5Q*QNNRKaB8eHLkH9G@TRC'&JBR#'NTUGN!#!H'eTITH@I(0qJACaG(@$PjfU`,q KKR9`JTHELRk1QBf4SkLRUDkeX+'0IAamHhpdA@"jKiL1PB&aIiUCVD11MBjpFSL @KRq,N!#@TkfHRkba[,UPPjD9LB@8P(YbI(GeKiG`DRq-NCbDLRaY@e0EC9a@C'e bI)*rKTUJPT!!KR"C6%YCDfT@8QGcDQ0F6e&SGAqASSebBPeeQ*4lHSq6J(9hIBq QY,'XVTYmG(1!QCQ(IiH-K(KYC@9iMBf4RT4lFAQ#K(piHBL4NBf*LBH3!+U`PRG N@P&299TRD@CT@e9SEepFHT+5NipmFR*aGAq'IR9mG'CZHRQ$R+LUU*0iEA*hH(K dCfGeE9PG@d9)BfaZKTU'EQGIAf"B9@&lM*1APC@ES++[a-+TQT''JR9JC(k8SkQ KMRCLA&pXLCf@Mj54J&p*69KLEAU%I@489@"fLSk(P+'3!(CG3cG&Ah1,RT4jBPa MBhD4Lj!!SC9lC9ePEhL)RVHpUC!!K)QEU+'9NiaqGQYJC'ekM*LBMSH%HhGiJT1 1H@pdIRafGhk0PT'4R+QZVDHXbp#YPBk$IAeeDh&rJh0UFfpZIhpjNjpi9dj"3P" @C(b-KhCqP*kQTjqQ`Ef*D@0A9PTDFSb&GRKiFhPkHB+)MSYrK(PIA'0XJj*qDi# ,J)D9RD@fZTq8RT5!HA4cLU#4Jj+EPj15N!#6PSU'PT!!F9a36fkBS)f*Q*@%KBU 2PT!!Mj@CN!"[9PGHAf&cKj15K)'%J)4kBQL*RS4C69455e0[Lk1TPik6PT!!Ji@ FYm1cNhGTA%)e4fCmGfGUF@GA589HL*PpAe4%,4iU9(U,PTqUXTjqERH4SkLLQC! !F8Nk2e&SIj'DR*4pC&TIBhHFSSTY55dS0%K56fH0NSClD@&dKBD4TD+,F&0%8QY `F*@hUTD@Li#)JRkEShaE8NpFG)'"LUL[P*5YVkHUTDHiU)0hHR&ZH(KdIBZ'D9e RD'YYCB+MJP42AfYfKj+PYkqMSU@ZYVQjaH2IVj!!KhYiH@TRIiYmHS1&Mj@6R+f kVSPS9NY6BfTrQCDATkHHQjUIUDQDKhpjE&eDDR9eDQ"UG("ZD'*fPT'%Pj!!D%m j+N*PD9K5BAH'LB'#SVkZRk+JPB"J8(#4KR9hK)KiER0mMk#IR+HRL'K69RU*JSH ,NjU5KAq)R+DVV*k0J("GAA9kEfphKBCmH(erJ)H2Q+LSNheZCf*TIiU,Nj+(KSZ (KTHUUjf8MS0c@Nj058Y06&"CBejFE(TmFQ9LAe%k,$0"8QCTE(k(GfYdJjU`TSk ,NSKbE(U(L)*eD'PYCPjIFBb+IB'#G93i0$e1@94GDQjU@eadMU1TTk'9LA*EBAU 'Hh*mIQaKCA+"QlDdTk#BLhTjLjQGSkHUTk#CNj1CSE#mYU#0JAPqLj15LiQ*I@p UERU'KBQ9MAZ"LSD(Mj!!NCDAMiL'JS56RkfkYkD8Mik-M)D$L)*ZAPpSDfedJ*5 HN!"cB'*I9ejUH)D%HRb)N!#,IB'9SU1EM)Q4M)'#L)k5KfaJD@TG@fGbJ)CfEAq ,Gf9ZGh4aFA"lNjZ4Mj'CT*q@NjkKN!#1RCf6KhGeJSQ'Kif3!)Z"K)CfITL@PUD LNB&dFRClKj5IQS"cG@j[JT!!MTLRMQeUBPTSG(KlHfpF9&KE9Q&pL)Q&Ef&QAeG NHiU4M)"pJiL"HBqVU+#8FeT@5$P2GAafEPC(58p,4eCQCQ"54Ne99Pk!R*H2LiH 3!*''JBfZb-+RP)TqF'"NK*b5Gf4JA9GBA@k2Nfj86%%q2N&FK*5%FQj[FR9kJT5 SRiU,MB&rHh'!Q*H-L)0mG@ebJBU3!)q-Li&hHhKhP,'QNj1,LjQBSDqRSkHZYUQ FS*f8QCQ*KSPiG)5)NU'8JS5+J@j`KC'5PCL9Pj@0Q+UdbY+jVl5RQ)q*Nk+DM)9 lGR4aFR@$NB0R@eYF@e05EB"lKT+(H'eSFS16QjL6NBk0MBQ+N!#!Fi10H@a[GS+ )K)Z@LRPlI@jND@aG9@YiD@akIik@M*!!QC+*Ji+*NTQCM)bHR)4pKjLSSj@HUT9 mHRf"J'pH99CQF'GKES"qGS@EQiKpIS54LRKmIAQ&JQpYGR4RChf5PBamFi'%AdP BBfGZE'GZIRpZEBUQTT+"K)TZ4d*+8Q&SBQ0ZDPG*8'YlG'TTEfY20$G)89YRFRe pF@PKE*1RQj1AQT*jCh&kFAD&MC@4JR*RG)qBPCH6KA4F4%&$3P"LE@TCA'GVJCZ KSU+2IRP[DhZ#IBbPT)YhHS+&ND+UZF'MN!#6Jh9lI)'JXTf$I)+'JjDme1(5T)f -JRq(JB+DR)4bDfp`DALDYXV'VD@QNhedFRq4MBQ0MC13!)+5[pR6Zk1GR)TcD@e eH(9dGAb)J'akPj10NiZ,NS9aD'GQC@0ND@jiGQYqPCLLS)q9Q)L&LAp`DQYVEhG kG(D)LAb#Ki#"JB@0Hf"A@PeMD@YZFhZ0QTLJS)b*L)1+KAPhG(4fFhD(PjbIRjL GRj@9NT55G'CaG(9jFR+"KRb%QUDdZD@8MSGhC@0MB9p@6eYZCPYYJ)LETCkLTCH !C&TA6eGSG)&mC@"hNTkTVULNPAPJ6e"86dp6A@jU8deDC@KXGR9XD@KH6dj258a FDh*VB@9bK*LRYEf`PSGlD@amJ)5*JR&K@PpXHS5)M(jE4NpD@f0N@9TJA&YB8ep fN!#QZXHcNB&lEQCiKB+&H'9XF'GZKU1b[XD`NB1%LSkCT++3!(PhJS&pJj@acGI 5[Tk-LS1$NjqBJ@PKC@CXHiQIXUfZUC!!IR0`HSL-GeY6A'YcH)QFYFI"am5MMSk 2N!#CNh&E@&eSFAPqKC51IiD'GA"cFA0qF&*'3djPG)#,Mj@ARV@iUD+JSD+FLhC TBQGeISD2Li&cFS+$Hhf#Ji1(K("M@Q&iJSL&Ghb%M+#NQ*58MB*pG@YUFSQNXDq BKBb0MjqCM*+8JQTSDQ*MC@f&NSThERZ'MD+USU@JJfpaDPP@@&edL)"ZDR9hJU' USD+@HfGC5%*29QD%LRYdGS#(PkbaVkD2H'jU@8T6A@TpH@&15NY)9R"rJAKXC9Y 02$jBDRH+LAGYEAH$P+qhUk'@LRpbCf4YHB+0MhpZCQ0JD(arH(9[E'GJ9%Y8BQk "JfjNC@KeMCkDMiPrI(aU@&pVEAqFSC@6NT5KTkZZUD1FPBf!G@pUF)'DSBk)MTQ XX,#dUCkIS*q1H'eUF)5DQSf0NC1BNjQQQBH(LSGkCe91B(qGTjkGTUbVUEDqV*@ 2PCQ3!(9A8Q4iLipqGhTaCfahIhCVFRYhBdJp49"PKTD@RCU'K*DSU*D+N!#EPi" UAQChJj1IR*4qDQjmLBZ#IifEM'jE9PYRGT1PSCH#Eh@0Rk+BP*U@KQjMFi#%NkQ XS*Q*Eh5)NC5,JRpdC&*$5PpVHTUUQSf$FRkHXEZkU*Q+G9p08'4dKjb8IATY@Qb +PU1NLR*RA%Fj3PKaMk#@Lj55KT+RVlDYLh*YC&KCBQjmJAaaCf"44&9eL*!!JQ4 A9%Bk2dpNHi0hERH(L)16VE1SP(efI(PXFBLCSTL#HATdC@*hMj+(G&a28%a'9Qp [D@YPAf9[FRZDTj@*IQGIAPKIFSD-L)9eFB'-MTLXVTL4L@jQC&pRHiZ-NC5+LT' 8RlE0cEfdU*1(J(Z#LiL&MT''JSD0PD'YUTZDQSGkFQYVDQY`J)Q&M*@DUVV'aE1 TST@2LiD$KBL+N!#,JBH)KS4rLC'!GA0R@eG33N&4AQPVDAU,LSU3!+'TQSPmH)# !H(CmKSQ,KRk(MB*jIBU*IRYhH(PU@eKID@j`Dh#(M)+$ND1UT*U4M)4mHS#(KBD (J)DANB1'Pk+CLi@#H@YE99YMDA&lIB'1N!#-P*qSTD5XU**fCQCVFR4dHAGfJ(p lIibDPiq6MAGM@P*39PKID'CSH)1"KjDJSD#PTjCpF'YZH)#%IQKAC'jRCfebGA0 YAdir1cp&8Q&SC&PHGiL)MCbPTCq@NSPfE("qP+HPMhKVEAKlIiL3!*!!Ki"lE&P 389CQH(&F894MG(b*Qjq6KBH1Kh"EA(52PSPiEfpjKT'QZ,@LNj+4Kh9MCAf9QBP iEfq$PTQTZ,#KQjZIS*4rHB58SCq4JAL#M)fETTU0KiD&JRYXB'"XHheaC@ClPk5 PT*kCPCHGS*k6Jhq+Q*D(I(9pLS&mKiGjD@*QD@052Me9DfYNBfb%Pj12PTL3!)4 kJj15JR0bKCQEKhGfIS&dDhD#KS*pK)k%DeYDC(0hF'pcGhTjISL0NT!!NkDVPAp iHB#*N!#1M)k-LB4rJSU1M)H(JR"F8PKTHB5(LBQ)MBf+NjZMUD5FP)b!Ghk,PU+ MR*'*KhpiISQET*D$IAGR@@"ZGi+(IhZ%LS0qKj1MVD@BNSepFAf0N!#-JAGjHR* M@Q*XFA&N9PK84804C'eSB@&UGAYiGS@5N!#'IATkGA0jM*kGMRehI(YmHR@!KhT aFQeK@&&IHi0cAe48@PjSGAU"K(TcGAGdEfq$QCb9LAjkIB+1PT!!N!#5L)5(KRT ZFAb(MBQ"HA0fISqKRC@BQTUBPT11MT+AQCbJQ)f(L*UJKhQ"JAPiH(9fGhClKBU ,KhYfJT+5J(Z$JS50NTUKPiH(PCbIRBq(LSf!E'T`E'9MD(0hC9PKEAGqJ(YlKiY rFhU!GfpcHi1*JRKkKC'CR*@+J(PcER9rFf4SE@eXC'0[I)5$J(KTBf9SDhk8NB@ )L)'!IRTpLjQJUUH1HA4bGSbKP(ppH'YRCQ*VJC'CS*Q$GRGiHj+ZUjL3!)Q'M)Q (MCDMXVL`RBPmFh+&S*TqF@GJC'KYHSqIS+#BL(jcEhL4Uk'#Gh9fIAjpLCLDP*1 4KhPN9PakNS*I6da-6dp@E(eqGhKlGQjL@@U*PS*RB@*QE@abLCL8Lik3!)U"F@T fLT1!BP048e98BRf#H(*[E@PJ9&0SK)eqD@*LAf4`IC!!QjQ3!)Z1M)*iH)@5Qj0 lF'jVE@pfLTUCNC'5Mib)L)kGVUD2LBZ)Ki@'NCfMSCUDQC!!KS5*MSq$F@a[FA4 bG)@9Pj'4PC+-IhKrKSb'G(#!LSCqIiU1Mik0Mj'*HAL"IRKYAPpZG'TLCQjiJAp pKSKhEhf*KAaaC@Z!KRaiJBU,N!#@PCD4IR@&NiGhDPGACfaTEA4kIS1,LiGqFA5 2Tk+5KhPaGRTpJS1%M*HGQBepGB#BU+19LACTE(0lJAalKj1DP)0cEhqATD5CLhT XDA*rLBD&MCQIQSepG)'BTk@BJfC269PXHhf"Lj!!MiTqF'YeLTZHPi9XAf0[HiD )K)L0M)ClEQGYHiL,JQp826T,A'GUDQeZFA0`DfKXHiL(IA0P@Pp[I)D*Ki+#KiD %KSH,P*H-I'pF4dKHFRjrH'pVE'TREAL"Liq%G@pP8eGbKj!!Mi9pHRejF(Q-PTq KNS*rG&jGFB#*LB&mH(9ZD(Q1PTbJQ)Z)JR0eLTH@N!#2N!#2LiD'PULVT*k5Ki* fD('#KB@(Kif1Ki+#LjL6LSZ%Hhq$JB@3!*!!Ki&qJ)*qIB')Mj'-JhK[F(9hHAe eE'PSDR"cGAZ$KS0rGfPKDhZ%LSb)IhCcFR0hI)#*NT@4JfaGB'piHRprGQaRDA* rKiD+NC+2KR0QEAf$KSZ+L)0rJSH0Nj'9RD#LRSjrKC'1LBf-JRGaFhU$L)+"KSD 'KAYhJj16Mik)J(ajHi13!*D5P*D1LSTpFRf+K(k!I(4[D@TfKSq2LB"eFR0YDRb 1N!#1MB9pHA*YG)#%JRjeEfeVCQ9bIhPaF'jVCPYBDATqIRPYC'"C99eaIhadFR9 jG@p`HS1'KS5!J(ecFhq-Mi9hF(*dF'a[Ghk#JAadE'4IDS'3!*5+I(CiHRKlKBb 0M)U*KAjfFS+FUDD@JRKiFh0rKiZ3!*+4NBf"Fh'#Q+5QQiU$IhPlKSq6P*@AQ*1 $GRH%PU@PNAefFR4rMT53!*!!Mib0KhYbG)'2QTb2JATcFi',L)5$HhTqHA"YG)+ -P*H+HA&UE(f-N!#1KhekHh9[EA"jKBf-K(KaEh&rLSD$JRYhGh*[FR0jIhpqH@P IAQ9kK(plGh&ZE@Y[GA9iIRaqIR4bH)54P)f(KB0rJ)#$LBQ0P*!!MBU!IB')NjD +K)9mFhL"M*D9MiZ"I(aiHB+-PTL2LBH"IB##K)L'Ji9qFfpZFAL%N!#5M)b1JhC hI)#)LiU-KhaiGhU!K)L&IAq#HA4eF@pdG(4kH("`GRYpIS5$I(f"I(PiFQpcG(9 jEfCZGhq%K)H&HhZ$K)H0LB5&JRjkDf0YHSD0LiL$G@jaGRYqHRQ"KB&pEf4YHiH 2MSf-J(CiIS'$KBD,LiH"F'GcIBH8Nj!!MiGqJBH1NBb,NT52KhP[G(U%MSb*L)& mJSb5N!#-M*!!MiCpG'pkJSD3!*!!M)KmGS#0NT++Ji5"Gh0bFAU"K)L$HA*SDhU 'MSk'JS9rE@KVEAL&LSb,KAT[F(Z(MSq+KB&kE@ecGS'+Lif*IR*UF(f*NC10LSP pDQ*JA'CdHRelG@pUEAL#KS5"IRPaE'pcG)'0Li9pFfj[G)#,MBU'J(jmGhPpIB5 2MSCpHS#$K)kES*b9M)D!HRb"JBH1KA9UCfjeI)L@Qj5-JhjrIRerISH3!)9hF(* qL)Z8RTqBMS@$JAf"KiD,Mi*aC@0XGAb'Mj!!L(pjGRChI)&qJB9jDfCQF(q)MBq ,JhekHhajIiU*LSf!F'TTF(b#L)q4Li1!JAjpJiCpHRaZB@4SFB+0MSf,Ki1"J)# "Ji4rIRjbD@PSEAb"JB1$JB#"Ji5&L)Q%JS*jFA0hJBk8PC53!)k3!*'2N!#4M)@ "IhYbE'ebHiD,M)b+LSf0MT'4MSk*JAY`CQK[HB1+NT50LBQ+M)k-KB*rI(KYAea LDR"iIRjrJB"rJB&pH(GhGRPcDQYaGAZ!JiD)Lib0Nj@3!)Q&IRTpHR&[Eh"cFQp [GRq$L)f,KAacEQe[EfeaFh0iHhCjJSH+MT5ANSKqGR0eGACkHhPpI(9fIB5-PCq NS*D-KS@&JS1*LSH+LSD(NCQFSUHTST5(JAafFR0iHhPlI(GiIi1'MC5DPiPrHRG fGA9iHRYqJi@'M*HHRjqIQif"I(GbF("`F'jZFR*[FRb&LSb0M)0fF'j`G(9dFA" aG(4bGi@5PjQCPBYrH(0`FA0bF'jZEh"[FAk*Mj'5N!#(H'jVEA&hH(CfHAamHhk (NjQCQTH-J(KdFh4fFh&aFh9dFhD!LSq3!*19N!#&IRTjHhppHRKjIAq!KT!!QCf FQC5,J(TeF("cGAGkHRYlHi'*Mj+6NSk(IRPiGRGkHRPkHhalHB14PjZGQ*5,I(4 `DfYYDQPYF(*bFAL'M)k2LS4rHAGhGRKkH(CeFR4iHAq-NjHDPT!!L(jkI(KdGA0 `F("cGhKrLSq5Niq)J(GeH(4aFh0bFR"bG(4kK)Z4PC'-L(jhGhCeHhpmHRTrJAq $Lj'@QjZCPBb&KB1"KSL&Ji5(L)H,NjQHRjUANiCkH(CfHhekHAf&Ki&qKBU0MBb 0M)*jH(KjI(YiHS'*LiH+NC@9Nik1N!#'H(0bFh0aE'acHRemIB1&JS"pIS&kFR9 kHhYhF'j`GATlJBU-LiU(KiGqGA9fGh9[D@T[FRCjI)+&KB@#J(jfFR9jHhalGhC fH(apIi@(KSH(KS*mGhGfGACdFA&aFRKpIS##KBQ,LSL$J)+"J)#"IhelIS@*L)U -M)k1LiD!IRjpHhYlHRYqJSH+LBQ)KSD(L)H%JB+"Ii#"IherJiQ1Miq3!)q1M)L $IRPfG(*bG(9dG(ClIRerJB'$KB1#IhalHhTlIAelH(GlJB5&KSH,MBU&J(TiGhC fHAepI(TmJ)'#KBH+LiL'JRYfG(*cGhYkGh9iI(q#K)H,M)U)JhahGA0cGAKkHRY qJB'$L)f4NC!!N!#2Li@#Ii##KBH'KSU-Lif3!*!!NC'2MSb&IRThGRGjI(elIB' #Ji@'KSD&KSH#IATiH(KkIAprJiH(KiU+LBH$Ji0pG("[ER"cGA4cGAPmIAq"Ji5 "IhppHAGeFR*hI(YjHhq#KBL+MBk-LB9rH(0bFR0hHhYjHAYpJ)1%KSD%Ji1"I(P iH(PmIRjqJB1$JSD+MSk-LSH$IAKeG(9iHRPjHhk!JiL,MBq3!)k+KS+!J(jlI(q "JB1'KiL,M)Z,LBD$IhThGhCfH(TjH(f#K)5(LBQ*Ki5#J(akHhYjHRYiGRZ#KBD (LBQ)KAjlHA9cFh0cGACcF(4lIAk"K)L,L)*rIATiH(PjHhjkH(f$KSD(LSf2M)D "IAKeFh*bGRTjHAk$KB1$KBL+L)@%JhplHRPiGhGhHAk$Ji'"Ji@%JS'!J(eiGA4 bF(*bG(Z%KiH(LBZ-LiQ)LBQ)Ki@$JB'!J)@0N!#3!)k0M)Q&Ji'"JS'"JAjlHRK kIiD+LiZ+LBL&J(epIRjqIRapIhemJBL-MBb,LSH#I(KhH(KiH(KhGR4cGRarJB+ #K)1"IRTjHAGfGhKjHhYlIi@)L)L*LiU'J(akH(4`F(&cGA9hIB'#JS'#Ji5$JB" qHhKhGR9fHAYqJiH'K)5%Ji+!IhjqIAKeFh0dGRPpJiQ,LSL*LiU)L)Q*L)D#IRY lIS'$KBQ,LiU*L)H&KB5$Ji&rIAamIRq#KBL*Ki@&Ki@!I(aqIAakHAKjI(apJSH )KS1$K)0qHAGfGR9cFA"bGRGfH(erIheqJS1"IhemHhPhGhKjI(q"Ji@%JS'$KiD "IRajGR*[F(0fHReqIi'"IRk!K)D%Ji+!IAPeG(4fHRjrJ)+#J)"rJ)'!J)"qHRC dFh0eHRq$KBD&KB5%K)D&KBD'K)5$JS+$KBL*LSb,LSQ*LSU*L)H$JApmHRTmIi1 'KB1$K)5$K)5$Ji0rIAepI(eqJB5'KSD'KiH'K)1"J(plH(CeGAKjHhq"JB"rIhq "Ji5%K)0rHhTjHATmJ)1&KB1#JS'!J(prJ(pmHAGdFR0eH(f!J)#!JB#!IhjqIi" qI(TjH(GhH(YpIRq"JS+#IhemIAemHhTjH(GhH(YqJ)'%KB@&KB5$JB#!J)#"JB' #JS1$JS+%KSH)KiD$JB"rIRemHhYpIRq"JB#"JS1$JS+!IRepHhTkI(k!JB+$JRp qIRprIRepHhYlHRKfGRGjHhf!J(jqIhpqI(erIRjqIRemI(aqIi'%K)+"JS1#J(j qIAamI(YkHAPkHharIhjrJB+"IhprIRjpIAjqIhq"JS+$Ji1%KBD'K)1$JRpqIRj qIAerJ)'#JS'#K)@&Ji1$Ji+#JS+#Ji5(LBQ+LBH'KB5$Ji+$Ji+"JB&rIAapIi# #Ji+$KB@%JAprIhprIhpqIRjqJ)'$Ji5&KS@$J(emIAalI(eqIRemI(amHhYqJB1 $JAjmHhTjHATmIRjrJ)'"J(jrJB'"JB#!JAppI(TkI(apIi"rIAapIRprIRjrJ(p pIAalHhYpIi'#J)#!JB&rIAk!JB&rIRalHRTmIi'#JS#!J(pqI(apIi'#Ji+"J)# !JB+%KB@&K)1!IRepIRq"JS'!IhjrJ)#"JB'#Ji1"IRamI(epIAjrIhjqIhprIhp rJ)'!IRalI(epI(amI(aqJ)#!IhjpIAjpI(amI(eqIRprIhq!Ji1$JS'"JS'!IRe pIi#!J)"rIAapIi#!J(jpIRjmHhYmIS'#JS+#JAq!JS1%KBD'KS@#IhepIi'#JS1 #J(jqJ)'#Ji5%K)5"IhepIi+%KBD(Ki@%Ji1$K)5%KSD$JApqIS#$K)5%K)1#JS+ $Ji1$Ji1"IhemI(eqIi#"JB#!J)#!JB#!JS+!IRemI(eqIRjqIhjpIAjqIRemI(Y jH(GhH(TmIRjqIRjqIRjqIRjqIRelHRPjHATmIRjqIAepIAjqIRjqIRjlHRTlIAj rJ)"rIi#!J)#"JB'"J)"qIAamIS#"JB'!Ii#"JS+%KB@%Ji&qIAeqIi+%KB@%JS' #Ji1$Ji1$JS&rIAeqJ)'#Ji1$JS'"JS+$Ji1%Ji&qI(YlI(erJ)#!J(prJ)#!Ihq !IhjpI(YlHhapIRjrIhprIhpqIRjrIhppI(alHhapIi#"Ji1%K)1#J)#!J(prIRj qIRepIAepIi#"JB'!IhjrIhpqIRjqIRq!J)#!JB+$Ji1#JB'!J)"rIRjrJ)'"J(p rJ)'#JS1$Ji+"JB"rIhjqIS##JS'"JB'#JS'"JB'"JB"rIRepIRq!J)'"J)#!J)# !J)#!JB'!IRepIAjrJ)#!JB'#Ji1$JS+"JB'"JB#!J)#"J)"rIhq!JB#!J)"rIhp qIRjqIRjqIRjqIRq!JB'!IhpqIRjpIAeqIRpqIRjqIAjrJ)'"J)"rIRjqIRjqIi" rIhprIRq!JB'"JB+"J(prIhprIi#!J(prIReqJ)#!J)'"J(pqIRepIRprJ)'"J)# !J)#!J)'#JS'"J(prIRq!JB+$JS'!J)#!Ii#"JB+#JB"rIRjqIi#"JB'"JB'!Ihp rJ)#"JB"rIRemI(epIAjqIhjpIAepIAepIRq!IhprIhpqIRq!JS+"JB'"J(pqIRq !J)#!J)#!IhjqIRq!J)'!J)"rIhprIi#!J)#!IhprJ(q!JB'"JB#!J)#!J)#"JB' "J(prIhprJ)'"JB'!IhjqIhq!JB+#JB#!Ihq!J)#"JB'"J)"rIhprJ)#"JB'!J)" rJ)#!J)#!IhprIhprJ)#!J)#!JB'"JB'"J)#!J)#!JB'"J)#!IhjqIhprIhq!J(p rIhprIhq!IhprIhjqIi#!J)#!IhpqIRprJ)#!J)#!IhjqIRq!J)#!J(prIRprIi# "JB#!J(prIi#"JB'"JB#!J)#!J)#"JB'"JB"rIhq!J)#!JB#!J)"rIhq!J)#!J)# !J)#!J)#!J(prIhq!J)#!J)#"JB#!J)#!JB#!J(prIhprIhprIhprIhprIhq!J(p rIhjqIRjqIRjqIhprIRjpIAjqIRprIRjqIRjqIhjqIhprIhjqIRjrIi#!IhprIhp rIi#!J)#!J(prIhjrIhq!J(prJ)#!J)#!J)#!J)#!J)#!JB'!J)#!J)#!J)#!J)# !J)#!J)#!JB#!J)#!J)#"JB'"JB#!J(prIi#!J)#!J(prIhq!J)#!J)#!J)#!J)# !J)#!J(prIi#!J)#!J)#!J)#!J)'"JB#!J(prIi#!J)"rIhprIhprIi#!J)#!Ihp rIi#!J(prIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIi#!J(p rIhprIhq!J)#!J)"rIhprJ)#!J(prIhprIi#!J)#!J(prIhprJ)#!J(prIhprIhq !J)#!J(prIhq!J)#!J)"rIhq!J)#!J)#!J)#!J)#!J)#!J)"rIi#!J)#!J)#!J)# !J)#!J)"rIhprIhprIhprIhprIhprIhprIhprIhprIhprJ(prIhprIhprJ)#!J)# !IhprIhprIhprIhprIhprIi#!J)#!IhprIhprIhq!J)#!J)#!J)#!J)#!J(prIhp rIhprIi#!J)#!J)#!J)#!J)#!J)"rIhprJ)#!J)#!J)#!J)#!J)#!J)#!J(prIi# !J)#!J)#!J)#!J(q!J)#!J)#!J)#!J)#!J)#!J)#!J(prIhprIhprIi#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!NLS!!3!"!!8!!!#J!!'!83!!!!!!&!! !!!!!!*)!9Zk,S`!!NIi!!*(r!$b!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!IhprIhjqIAamHhTjH(GfG(0aF'pZE'YUD'CNBf& HA9YC9e988e&36Na+5%C&4%*!2cip2$`m1cSk16Nj16Sk1cXl1cXl2$dr3%""3N0 %48C(5%P,6%e16e&699GC@PaHB'0PD'YYEh"bG(CiHRaqJ)+$KBL,MBk1N!#6PTH APTLFSUDRTU5PUDkaVkURU+keZlZhXDkbZm2'`lZcXEE!bp28cF#aTD1V[-hCfY( !V*U0KSbHZp[amr$Ud+f9NTDAPjD8MiZ(KSqSb0[FdXDmXULIPSq)JAafF@aRB9a A8Na(3Mik0c8d06Bj28&(6PGKDhH$N!#FUE6!bY6FjHc[lr$`lqlZlZhZlHlYl1h YlZlZlqr`m1rYkZINhp[Ae026eGEBfYcGiHEXmI6dm[$YkZMSkHVXl[$bp2AcmHr [lZlXk1,Gf0E6d-c*aX2![VZkZ,HeYE5dY,@eYEDfYVDeY,1aVUZSTD+HQTD5MSQ &J(aiGhGfGA9eGA9eGA9eGA4dFh*bFA"`EfpZEQeYE'aVDQPSCfCPBf*JAeeF@eT C9e9689&48%j*3d!q1cNi0cFh0cFh0cFh0cBf06-`,#JP)KmG'aSD'aXE'4F@&KJ E(L%L)4mH("`E("iK*#FT+LSV,6!c0MJj1MSl28"$4NK+5NP(4%*#3d9)5Na06%T &2MF`+5-H'aSF)#BX-MJm26dp2N"$48K,6P*@@f&QE'pbFh9fGhKiHAKhGA0cG(G mJ)5(LSZ,LiZ,LiZ,M)b,LBD#IhelI)#(MjQLUl1j[Er#aXh5d-c3fH$KhZ$Pj0I 'Z,@iYkfGNSk2MBGrI(q'MC!!N!#,JA4UCQGXFRGmJBH0NTDCRD#MU,#mc0[PkZl `lq[NemDeUkLNQj!!LB@#IAKfFQYK9NT!1cT!5%e-4d)p0LiU+LXT*L3L(4-)!!! !!381'LJd284(5%K*58P+68j)2M8c1$p#3Ndj69PGBA@G`G'pQA&0,48*"38& "3$mq26dm1cSj1MXh-5SN)"`B'"JA%!F"!!3*$K8G)bBL'3m)#K8N-6Y$5e&58eC HC'GPBfCZHSD3!*HHT+UVTk'FQCQAP*+4NjHDQTbJSkLZXl@eYV[$b-V0dYMDep2 3cp,9e066cF5jVkQRUDbYUk@IPj!!LSD'LBb2NC5BQCD2KS"lGR"ZEh4iHRTlI(a kGhClJSL*K(ekISL6RD@VVV#`X+qYTjk6LiL+MBq0LB5%L*'GTkkbYEQp`F,$`m6 %a-'r[Vr&cYRPm2MqrrrrrrrrrrhflHAJh0M5cFR)bFR)amM,cp2@f0E2aVfjZEZ q[lkkXULGP)k+L)H)LBZ0N!#5P*HDR*ZCQCZIT+DPRjL3!)Q"HhGfGRGiGhCcEfP PC'9SDfaXDfecHS#$K)5$JAprJSD+MSq0LB@#JS5)MC!!Nj14MBU(KB5%K)1"Ihe kG@pSC'*LC@TbHS51QD'MS*U6M)H%Ji+$KBQ0NTHERTqIRTfCP*!!M)Q)LSk8QTk JRTL4LiD$IhTdDf&B8%K#2M`l1MSj1cj#5%e69eTGAf"IA&P86dY*5%T3@@9bI)1 (LSU+LSQ'IR*M9%K!2$Xm1cJe-5mZ,5i[-63f16`r48a9B'YfIB"rHhGdFQjVD'9 MBQ&KB@&KBQ0NC'4J@P49AQKTC'"IA&PDB'9PBf0NBeeA8P9C@P0*3Mp"5PKQEh" UB&C9BR@!Ji*rIRamHhTkHACcEfaTCQ0KAPYB9P014cmh-#`V,M%d0MFi16`r3dG -6e09@&YKDA&fGhC`CPaEB'4KAPYA99499PGB@&PEB'KcIB5&Ji1+P*fKSU@SUkZ UU+1CM)"fFR*hIi@,N!#6PCD@PC55N!#2MSk1Mj!!Mik,Ki0qH(4`EQe[G(f*PU' SUkQPSTkEQCQCQjbFQjQ@P*58PC@@PTD9PC56NC!!MSb,LiZ-MBk2Mj!!NC+6NBb $H'aNB'"JB@4RE(0qLjURX,5dXDkYVUq[VUbTTkDPTUHUV+k`X+q[VkkUTCk@Mif 9S+LSSk#JSkHVVUkUSC1&IS+2RDHTSjQ-Ih4YC9jA9&CFC'PZFRGpJ)&rIAYkI(q $L)k9RDHb[XVBjHh`l12@bEkfXDqZX,1fZEHbUD'EQCQDPSf"GQpXD@TXER"[E'G KAPjLDR0mJiL+LB@"IAf$MjUHQT53!)k3!*'3!)Z'JRpmHA9aD9p@8P*9@f0`JC! !QjkBMAjbE'aZF'pVC&jD@9PGC'jkK)U-M)Z+L)L,N!#8P*'1LB@#JS+"IRamI(e pIS''Lj+BR*kGQjH4M)L*M)q1LiL$IRTlIi5'K)&qHhGaD@0HA9eHA9aB9%p06P* BAQ*MB&aB9909A'4RBeY@9PTKDR0mK)Q+Ki0qHA0YE("dGR9dGRTrJB'!JS5%J(a jGA*`FA9lJBH,MBb)JRYdEQTTDfjZF(H$MT16PTfNUUbXV+qfZVQfZ,l#`,bk[,f fU*U2KhpjH(YmH'pRCQYdIS5"H(*dHATjHi#%JhefEQCF8%G%5P"2580$4NT-69" @AQ4SDQjeISH5R+@TV+kZVDQLPif*LSZ'IACaDf9LA94+4%9+6Nj*36j$5NY$16F r58j+4dY@BQTYFACjGQpP@8`q-#3F&aJF)5BT,6-l4%a16Ne39ejLBQ0PD'PTD@T YFA9lJ)@+M)k2Miq2N!#6PT@3!)Z2Q++SUUZYXEHlZE1`YX64eY2*ZkqQSk1QUUb XUU@JQjQBQ*QCPjD6NBq2Mj!!N!#3!)q1MSq5PTUGRCbHT+QUUD@LRjZBPC56Nj+ 3!)k-LSL'K)1!IATiGR4aDPj44$dj-bSK'aSG)L8P*#3P+#SR(aB6&KXH(K`D'K` H)53T,cBl2$Sm38G)48!q26`f,5BQ,$%f1d&'5e*FCQeaFh4fI)51PjkJRCD2Ki" jGR9cE@0D999CB'PdJ)Q1MBZ-N!#4MSD!Ii&rHR4`FACrLT5CQTUDQCH@PC54MSZ *L)U0MBZ)KB+!IhjqJ)+$JhplGh9eGRGjHRYjG'pXE'jaFR"TAeC6@Q9ZG(KkGfp SC@KYF("VC&pIC'PYEh"eIB@,MT'9R+5TUUHKQjZJU+fYUD1HQjQBQCQBPT'+Jha fFR&bFh0bF'j[FR9kIi@-P*kUZFA,bX5qZlUiY,#ZVl'`V++9LS5'MCDISk5QV,+ cVU+9LiL*M)k4N!#0LSU2Pk'TVDZRSk1QUUbVT*U0JRGZCf9XHikHUDfVSjQ3!)k 3!*+8NBb&IRYlIRppHAChH(CYB9P@@&YHAeaEA@4[H(k"Ji5$JRpkG(*fIiU6PT5 3!)k2NjHCQTbHRjfFQjbGRCbDPT!!KhecE'CNC'CVFA9hGhGiHRk#KSZ4PTUFRD' TYF((aVfaTU'LTkfcZEh"aFM+bXM'aFE%`EfmZVHeYVh&bm['`X2'aF'q`FI+b-+ lXUfZXlDdVkbZY,h$aXE'aFE*cYIJj1,FeXl'[VLbVUbUUUfcYV5XTUDUX,Dl[lk lYlDfYE5bX,#bYEHhYlHeVU@GQCLBNB4fE@KSDh*mL*1ES+#FPC!!N!#5P*11L)& lHheqI(TlIi5*M)f1MBb+LBH%JAjkH(GhGR*[E@YVE'j`G(KlHhTjGh9dH(q%Jhp iF'TRCQGQC@*IA9YE@PG98e058%a&2ce!48P+5%9#26Jd-M)b-6!b06Sr3N9'3ci j0MBi1Ma!489"2$e'9@*XG(U!KBQ1P*LDQCQGTDfcYE@cVULLRTZFR*ZCPjZLTk5 EN!#*KSH-NTQHRTL1KB#!JB&rHhPiHATjGhGiHhq$L*!!QD+RUDUVUU@HQ*DBR*q MTULSTU1JRTZCPBk%I(KhH(YqJ)"mGR*dGhGcDQ"C9eKHD(*iHRYmJBU9Rk5LQBq (KBD(KB"lGR0cGhq,Pk'TV+ZPR*'&HhCiJ)bAS+DSU+DKQjH8MiKqG@jTCQ*JB'4 UER"aFR0eGhGfGhTrK)L+M)b,M)k6QCfGQjD4MBZ,M)q4Nj+4Mj'ARCkDNif*KS@ 'L)Z1NC16Nj@CS+HXVDZRT+1NTUHQSTfBNSf)KB*rI(PeFR"ZE'YVE'eXDfPQBPe A88a(2cF`,#NP)L)Q,M-a+#%J*bia,LNR,$3k2d&$3d*$48G)4dC%3N*$4NY28P0 68e0899CA9eC99&966NC!2Mdl1$8e0cSj05mX,M3l3NC*6%j389"16%a28eKE@P9 25%0"3dP39PTFAQ&ND@jdHS#$JRaeEQKNC@TbHi+(Lik4NT'1LS9rH(*XD'CPC'4 NCQT[GRf%LBb1MBU'JS"pHA0UB&C14d%m1MNj1$Nj0c3[,5md16e!3NC-8PC98Ne -6%e-5NP+6%j48e*-4$Xc,bma0$8e-c!Y+LFM)L-Q+bmb06Sr4Na49&CBA&pI@e* )3$dq4%a6@&TD@9TGB@9UF(KrKBZ8RkUcZEl&cG,8dF[%Zl5ZUD5IR*UAN!#(I(0 [F(4jHRGdFhClJ)"qHhPlI(TdDf0G@ejQFAb)NjZGQT53!*'9Qk'QUDZVUD5FNBH !IB#(M)b)K)1$K)5(MjQMU+HLRCZFS+'IQjH6MSL#I(YqJS4rGh"VDQa[FRCjHRY pJifCTUqcY,1cXl@eYE5bXDkVTk5KRjfEPBb$IAapIATfGAGmJB@'K)&qI(f"L)k 6Q*bJSk1MSk+MSU#ENS9hDQ&GAQ&QD@PQB9jF@eYHC'ehJ)H,LSH"IAf#L)k3!)q 0M)b0M)Q&JAjlHhk"KBH)KS"hEQTXFRGiGhCiHhq"KBZ8RkHXVUqaYELk[,l"`m6 %`lqkYE#XUDLUVl5j[-,+dGEAdml*aX2![lr#aXV-bmM&aXR1cml+aF'pZV[!aX[ -b-1r[X$#`EkjYVHpaFc2cFM"ZV1VSjfEQTQANj!!Miq4NT5AQjkJS*kEQ*@6NBq -LSH&K)*rI(PiH(TlI(eqJiZ6QCfJSCqCP*1@Qk#LTDLVVV#`VkbRSTqJSU1NTDH UV+bUTk@PTD@NSCfCP)q)J(PeF@eSC'*KAeeE@9KA@&TGBQCTDfpeIiZBSUQYVUf YVDfYV+QMRCL9PCDAR+1XXV+YTU'IRjkFPj+0L)5!IAakHAKiGhCfGRKkIApqHA& UC'*LB9pGA&aE@eaIC@TUD'CSEhU'NCQFQj@1KS"pHhTlHRTiGR*ZE'YVDQKRD'T YFRGlI(YiGA9fHAk%LSf3!*+8PjD6MSQ&JS"rIi#"JS@*MC'8PjUFRk5SVDqaXV1 eYVDeY,1f[-60e0VIiZ,Jh0I5cFI!YUbMR*LAQ*bIS*qGQjQCR++SV+ZSTD1NTUL XX,Dm`FA(b-R+bXR&`,bl[EfjX+@GQTbJT+1HPiq+LBQ*KS1"JS1&KB1"IheqIRj lG'aNAeYC@9YKD'e`EfaSCQ9NC'0MC'GVE@eVDh"iJB@&JAYeFh0iIS@,Mj1AQjk KSU1PTUHSU+DLQj+)IhPeFh&[E@aZFACmJ)+$K)L-MSf)JAPcFR4iI(q!IRPdFA" bFh0`DQ*C8Nj,5NP)4dK,6e4CA9pIAPY@9&9FC@aYD@&F@epND'PUDfe[EfYPAPK 98Na$1MFi28C4A'0NAeK589GICfaaGRTpIRprIRTdE@PSCfCNC'CQBPK03MXh0MJ k26p"3N%r26`m2$Xh-#NP*5FU,#i[-$!`-6-f1Mdr3N4&489&4NT39PaLCQY`G(9 dFR&eI)1%IR9[FAGqIhTbDfKTDfYRAeC48PGJDA"cFR*dGhTmIAjrJS1#IA9XCQ4 NBPjD9eC@9P988Np06&"AAfCTDQTXEh&aEfjXE'e`Fh9eFfjTC@*JA&9+26%S)Kd E'KXG(amI)LXe1MNd-$)i2d0$3%"$59"9@Q&TF(*`E@jdHi#"IRPdF'j`FhKmIi' #K)Q1N!#0Ki&kFfeSC'"G@9946Na,6%Y(36p"4NT,589#38N4*8PYLD'abHAk "Ji1$J(elHAGfGA4bEfTPB&pIB'&KB&pG@eK99&GGC'PZFRCiHAPiH(TqJi@#HR0 `FRCjHRf"L)b0LiQ*LSU*KS5#JiL4QU#KR*@1LSD$IRThGRKkI(jrJ)'"JB+#IhP `CejA8eCGCfjbFR&[E'KQCfTXEQpZE@j[FA*cFh0cFh0cGA9bE@GLAPeHA9K66Na ,5dP(4N9'5%Y28eGDA&jKC'KXEQjYDQKRD'YZEfjXD@GNBQ&KBQ4PCfTYFA9iHhk !JB'$KSQ-N!#6PCHESUU`Y,1aXVDkZVHdXl@k[X#r[El#am[1cp(5dY$-b-E)bXc ,alqhXE'jaG,GjHVXl1RMhYR9e065cmc+cG6Hk1rbm[$Vk1ISkqh`mI,alqcTjH$ DeG,3cXl1c-M#ZUqPR*HARD@YXE'[VDUUV+k`Xl@fYE1`VDUSTU1KRjkHRk#IRCL 9PCDAPjLCQjbEQ*11LSH'KSD%J(TbDQ4IA9aE@PG888j068e2894A@ejMD@jeIiU 8Q*H8NC'6QCqQUUZST*qDPC'3!*18Nj!!MBb0MSk-LBQ-NC55MSZ+MBf+K)"rIhj lHi+2RDHXVV'dYV1URj@3!)q1M)L'L)f6QCbDPT'0LSH'Ji"pHRPiH(GiI)#%KiQ 0NTDBPjLESDL[YEUmZV@`VDbYVDbXUkZTTkDSUUbYV+USTD5RVEM$c0$8f0cJiZ( Ihq$Liq(JiZETjq2Gf061b-'mZVQfXDUMR*1,KB5(LSZ*KS@'KiL'JRjlHRTmIi5 *M)b+L)H'K)&qIAk!J)+&Lj1DRk'JR*L@PjZJSk@NSk1MT+5MSD#JRjqIRjkFQC@ 5N!#2N!#3!*'5Nj59PjQDR*bDQ*@5N!#0LBD$JAjmHhTkHRYqJiU3!*@APjH@PT@ 6MiL"H("UC@"GA&eHAPjIBfTZFA0fHi##JAajHRf!Ji*rIAYmIAepHhKfGA4dG(G lJBH0Mif'IRGbEQTTDQe`FR*`EQeXER&eHAaqJ)5)M*!!Nj@CRD#LSU'IQjH4LiD #IhYfF'PMB@0SER0hHAaqJB5(LBZ-MBb*K(eiG(&[EQp[EfjXDfPSCfGRCQ4MBf0 KA&G88e4@@9eJB9jB8Nj-5dY08PKFA&C258C(58P(4%0%58j599TKCfPSC@*JB&p HA&YHB@0LAeY@88T$2MSh0MFl2d*%48C'4N9!2$Sl2Mmq1cSk1cj#4NY39PeMD@j aG(GkIS'#JAjpIS+%JhplH(CeFQeQAPG899TJCQPUCf0JA9eHB'0RDQPRBf"G@99 468a,5NK'3d&!2d"#48T49eYFA9eGA9eFA9jKBf4MB&jE@PPEAQ0RCf4KB@*KAPT C@ejJAeT99&CDA&eGAQ*QD'GPC'4NC'*JAejHA9eF@eTD@eeJBQ&JAejHAPjHAQ" MCfTZFR9fGA0dGRTpIhjpHhKiHAf"KBQ-Miq2Mik2Miq4NC'1LiL'KB@'KSD&K)+ !IAPhGA0`E'9I9e"+4N)q1$%V+#BP*5FV0$p0@@"LB@"LCQPSBeeB9P998e089eP C9eCA@PpMCfPXF(0fGhGeG(0cFh*`E@TTDQaZEQeVDQTXE@eXE'eYE@eVD@GNBPp G@eTD@eYE@9G@9ePEAPpKBfCSD@PUE@paFR0dGA9bEQaXF(9kIi1&Ji&qI(YjG@p SB&P888e*4N9(5Np8@9pND@jaFh*`EQjZF(*dH(b!Ji5$JAjlHRPjHAKhGR9eGRG hGR9fHAf"KSZ4PjbJSU+KRTU@NSq1MBb*KB"pI(k#KBH&JRjmHhf!KBZ5QU#LS*f BPC'1LBD%JS"mH(4bFR4hHRYmIi+&KB*pGh4bG(GlIAajGhGjHRPhGA4cF@eSC'0 MBf*I@eG999KFB@P`Ghb!JS@(L)L(KSD*MBq2MBU*Lj!!Q*fIRTfGS++MSU'LTDZ `Y,DfYV@cXDkXV+faYVc#aXR)aF#kY+kVUUQRSjkEQjfJSD'LT+LVVUq`XE1hZVb mZVHcX+ZRSCZ@NT'5PCLDRU+PU+LRTD5LSD#IRk#IRCQ8Mib*KS@&KSL)L)L*LSU *LBU+L)*kFQj[FhPrJi5$JS'#Ji@(Lj!!PCLBPT14NC+8Q*fLTUUZYEc#b-c0bmI %`X#r[EZkZEUm[m6)bmc*aF#mZVZp`-,$a-E'`lbdVDQSUDUSSjfCQCkQVlDm[Vk p[,UhYE1eZ,c!a-R2dpIAe-r*`VZfXl+cXl1aX+k[XVHm[Vqq[Vr$amc5f0lKi0h CeG25dY(2bmM'aFA%`EfkZ,HhYlHiZEQjZlr'cG2@eG,-aX'r[lklYl1bY,Lm[lq q[,bm[,ZkYl5aVUZUUDLRTD+KSD5SUkfYV+UUUkbYVDbUUDLQSjf8Li@"IhajH(T qJiL-Mj'5Nj@BRD'NTD5JQj@2LB@"IhajH(PlI(epHhPiH(KjHRTlI(eqIRq#KSU 0Miq2Mj'5NT+5Nj15N!#-L)5!HhCcF("`FA&aFA"aFR4jIS+'LBb1N!#3!*'3!)k +KB&pHhPiGh4aE@PQBQ"HAPjHAPjHAf&NCQ9MB&eGA9pKC'CQCQ9QCQGRCQ4KB'" KC'KUE'aVDQPVEA"cGACfGhKkHhalHACbEfaUD'GQBf"G@ePA9949@&TE@PK@9&* 58e49994589"26Nj38eKEAPpHAPpKC@acH(apIRq"K)U4PjfJSU5PTUDPSTkEQ*H @Nik(J(TfFh0dGhYpIRYiGA0cG(KqKBb3!)q-Ki+!IhjrJB1&KiD$J(akHRarJB+ #JS+#JS"mGh&VC@"F@9K@99499eTFA9YA8e&48e056de1894A@9YGAf&KAeeF@eT C9P036%P(4dK,6e0@9eC68%e06e*@9e9468T+69&89&",4d0!26Sh06-a,bdX,#d a0$Fi0cFh16e#4dT-6%e39PjQER9lIi&qGh"UCfGTDQKPB9jGAf0SER4iHRTjH(K kHhalHRKeF@aSC'*KB&pHAPpJAejE9Np*4dP089488e*588p069"@@PeE@&0368T (484$38!r2Mip2$Xm2N"#4%9'4dP,5dT*5%K*58G$2$8Y*L%I(amI(4N@%a)3$J` +#3J)#!N,$!m5&adN+c%e0cJk1cj"48Y5@9pNCQCMB&aC@&PD@9C35dK)58e49ea JB@&KBQCUEh0iI(q!IhajHATpIi#"JB'"JB1&L)Z0MSf-LiU+Ki*mGA&`FhGmJ)+ %KSU2PCUHSUHXXE@iZELhY,'ZUkQRT+'GQCLBQjkIRjfBNik+Ki@$JB"rIi#!J(p pI(amI(amI(alHACeH(k'MT5BQjfIS++NTULTUDLRTkHPSTkFR*kKT+HTUUQTU+D MRTH4M)L&JAekH(GhH(TmIi1'KiH'K)+"JB+"J(jmHRKfFfpXDfa[Fh9eFh&aFA0 fHRq&Lik2MSk1Miq2Mif-LSH#IAKeFh0cG(CjHhamHRTlIAq!J(pmHRGeG(9hHi' (MC+8PC56Nj18PCD@PT@8PCHCQTQAPC@@PTD8NT'4NC+8PjQCQ*D9P*15Mib*KiD 'KSH(L)L,N!#ASDUcZVr#`m'q[,UiYV+ZUD5HPj+2Mj'9Q*UER*qLT+DRTU@LRjk ISkHXXEDjZVQfXUkVUUHNS*fDQTZEQjUBPT56NT'3!)q1MSb,LBL(L)Q-NC@CQCH 9Nj19PjUEQjL6Mif-MSq2N!#2MBU'Ji1%KSL*LBQ(KiH(L)Q)KS@&KSH)L)H&Ji& rIRk!JB+#JS'!J)#"J(prJ)1(LSf0MT!!Nj@AQ*LCQjkMU+faY,DhZ,HfYE5cXV+ bXDkTSTU5M)H%JApqJ)+'LBZ-MBk1Mj!!NC5AQTbEQTH@PC@9PCDAPjHAQ*QERU# MTDDSU+LSTU@MSCqHRCfHS++NT+5NTDDTUUZVUkbXUULNSCkGR*bISU5PSk#GQjb ISkHTTk5IQjQCQTbISD1NSk#EPT'3!*5DS+@SUDQTUl#i`-I,cFr2cmh*aF,"`F' rZlDbVUbTTD'GQTL8N!#0LSQ*LSb2NT15Mib*L)U0N!#8PTLBQ*H9PCDCR*fGRCf ISD1PTUHTUkf`XV5eYE@bVUUNRjZAPC56NT+8PjZGR*UAPC56Nj5@Qk#NTkLSU+L STkHRTU5IQC11LSQ*Lif2Miq2Mj'9QCqNU+bZVUUPRTQ9Nj+4NC+8PT@8Nj5BRU1 RUkk`XE'bY,Ll[EfmZlZlZlZlZVLdXE#[VkfTT*f@N!#0M)f0MSf-LSQ(KiL(KB& lGR*[E@aXE'eYE@j[FA0cG(9hHhq#K)5#IhaiFfaPAPPA9PC88e"05NG&4NG+6P& 99eKC@9KB@&PD@PPB9PCB@9PC@9TGB@0NBf&JB@*NC'0KAPYC9e956de-6%a-68e 28%p15dT+5da05dK%36im1cNi0cBe06Bj1c`m1cXm2N&&5%Y-68e16e"69eaJBf4 MBQ*MC'9PC'0LB@"HA&P@8e"26P"599KEA9jIAepIAPY@8%T'3d*#3N0%489&4%* "389,8PPIC'KVER&eHAf!JS&qHhGfGRChGhGhGhCeFh&[E@aVDQTXER"ZDQ4H@PK B@PYE@PG568K&4%C*69*@@&G66NT)5Nj69eKA9&&3890A@f"NCfGPBQ"IAepIB'& JA9K3580!3%*&4dG&3N"!38*&5%e6@&YE9e*15dT,5dY+58G&4%0&5%e48e068P" 15dP(4dP-8&0999469&9@@&KC@9K@8Ne*4N9&4NG)58P)58T089088e&168j49&G A9eGA@&PDA9pKBQ0MC'4MB9pG@eK988j,5NP*5Ne39&GDA&eKCQaaFh4eGhTmHhP dEfYTD'PUE'paFh4dG(CjIB'$KSL+LSQ'K)1$JS"qHhPhGA4dGRKlIRprIRYiGR9 fGA4cFh4hHReqIhprJB1'LSf0M)U)KiH(L)Q*LSU*L)H'KB@&K)1"IRTfFh*cGAG iGh9bFA&cGhb!K)D(KB5$K)D*M)q4P*@9P*!!MBZ*L)D%Ji5'LBb1NC19PjQEQjU BPjHAPjH@P*'1LiL'KB1!IAPeF'aUDQYXEQjYE'YUDfe`FhCjIS1+NTUKTULQSjq EQTQDR*kHRCQ8MBCrHhYpJ)1%K)1%K)@&Ji+!J)#"JS1#JAplH(CiI)##JS"mGR& `FA0fI)+)Lib-LB0mGh4`E'YZGAf&M*+8NSf(JhpmHhk"K)D)M*5ERjf@LRpjHAf "Ji1"Ii##KBL-N!#9Q*UDQTQBQTkNUUqeZVl![VZhXl'[Vl#aXE+bXl5fZ,c"amh 4dp,1aVkfXDkXUkUTUUkcYlLdV+1DNiq0MC!!P*UKTDQUUDDKR*H9P*@BRkLbZm$ "[VZjZ,Um[EfmZlbp[m$"`XA*c-[(`,DYTk1LSD'KSD'KRjbBNiq+KS1$KBL0P*Z NUl'f[-$%aXI(aXA$`F$"a-I+cFr3dG(3cml-bFM*bml4dpA@eG(*[lD[UkHMRjb DQjqNUDbXUkQQSk#GQTQES+DYXlLq`mR3eGRCeY(-bFM)b-I'amV0d0$1bF+lYE# YV+f[XE+cXV'ZV+ZYX,@iZVZm[EqrZl@ZU+@PTUHPSTfBNiq*JhjlIB''Lj!!NT5 9PC13!)Z'JAajGR4fHS')MT'5NBk-LSQ*L)L)L)Q,MBq3!)q0L)*kFfjUD'CNBf* MC@KUEA"bFh0`E@aXER&eHAf!JS1#J(ejGR9fHRq&LSf2N!#4NC!!Mj!!NTDERU# IRTkIS*qFPSk'IRKeFh4fH(PiGA&ZER"cGA9dFR*bG(GlIAjpIAerJSD*LSU,M)q 5PCQFRTqHRCbFRCqMTkZXUkUSU+LSTU1HQC@5NC+8PC53!)Z'Ji'"JB'"J)"rJB5 )Liq6PTQER*bCPT+1M)b0MBf,LBL*Lik4Nj58P*@AQCZEQCH8Nj'3!)f+Ki5"IhY hF@aSC'&HA&K66NY*58K)4dG(5%P+58G&3Mmq2$Nf-c%b0$Bh1$Nm2N$mq2Mi p2$Si0cFi1$Fe0$8i1MXl2$`m2d4+8&*588p26e"38%p05dT*58Y28P068Np,5%9 #38""3N4&4NG'4%%r26j!4%K08PCCA'&QEA&cFR&aFR0cEfTPB@"JBQ4QD@YZF(0 eGhPjH(GeFh0cGA9eFh"[EQpaFR*bFA&aFA"[F(&bG(4cFh0cFh0aF'pZEfp[F(" aFR0dG(0aEQYUD'CPC'CRD@TUDQTUCf0H@&968e4@9P946NY,69"699956dY+5Ne 49&998e"16P"69eTFA9eHBQGXF(&bFA*bG(9hHAYlHhKfFh*bFh9fGhPlIS'&L)U -MBk3!*+8PTHCQTUCPT+2M)U)L)D$IAGaE'KPB9jE@&C688j06%j59eeLC'*I@eP DAQ4SDQPRC@4NBf*KAeeC8dj*4dG)5%G%3N!r380%4%0%4NP,6P&8@9aHAPeF@PK @88a'36dk1$Fh1$Sm2$Xj0#mV+LSY,c%b-c-d0MJi0cBd0$8i2%"%5%a28P4A@Pj LC@CMA9G468a18&*899KEAQ"LBf0MC'9QCQGTDfpcGhPkHRKhGRKjHhYlHRKiH(K kHhepHhTiGhGiHRf!Ji5$JS+#JS5&KiL(KS5#JS1&KSH(KiH*M*'@R++RV+qaXE# XTk'EPBq+KiD'KB1"J(pqIAYjH(KiHAKhGA4eGA0aEfpaG(ChGh9eGhTqJSD*LSU ,MT1AQCQDQjfFQTH9Nj+4Mif-M)k3!*'4NC+8PjLBPC'1LiH#IAapJB5&Ji'#KBU 4PjQBPT58PCD@PT@@QCkLSk1IQjH8NT+8QD#QUDHMRjfHRjqGQjQCQ*LBQ*H9NSk ,L)D'KB@'KSD'KSD(LBb2NC'2MSq5PTZJT+QZXV@fYVDiZVh!`,fiXUfXVE+fZlr #aXM,c-h0cFl2cX[%ZV#SSU'LTDQVUkQRTkQYXlV"b-r6e024cFR'a-2"[VbjZ,Q l[Vqr[,HaUU5IRCfIT+Q[Y,Hk[,fpZlQiYV5aVDZTUDLSTkHRTU5LS+#KSk1LS*k HSUHZYEc#b-[-c-V*bFR*amA"[ELdVUHIPj14NT+4Mik2NTHFS+1PU+Z[XV1aVUU QSTkDPC+3!*'6PCD6MBD!IRk#L)q8PjH@P*16P*DBQTbIS+#FPT!!LiL)L)Q+LSU *LSb1NC@CRD'PTkQTU+DNSk'KRjfEQ*D@PjLCQ*52LB5$Ji@*M)k1LiH"IATkHhq %LBk5P*56Nj+5NC'6PCHBQ*H9NT!!MBb,LSZ-M)Z*KS1!IhjrJ)'$KBH)L)D&KSL -Mj!!N!#2Mj!!NT5AQCUBPC'1LiU,M)q5PTLCQCQCQjbGR*UAP*'1M)Q(KSD)Lj' @R+#MTUHSUUfaY,HiZELfY,'ZV+QRTU@PT+1LSU'LSkDTVDq`VUQNS*qKTDQYVkq YV+UTUDLRT*qCPC19Q*bISD'JSD'LSk5PT+1MT+DQTD'FPT+3!)q1MBU'JAemIAq "Ji@&KSD(L)L)KS@&KSL,MT!!NT5AQCUEQTQBPT53!)b)KiD%JRjjGA"YDQPUDQY UD'9LB@"KB@&JA9TA9PGA9eC@9eG@9P99@&eNE(*fGhGfGR9dFh"VC9j@8%Y)5%K )4N0!26Xm2N&%4dP,6%e-5dP*5Na16Na*4%!p26ir3%!r2Mdp26dp2N"$4NP-8&4 B@9TC@&KB@&KB@&KB@&PC@ejKCQTYEh"`Efp`FA*dGA9eG(9fGhKjH(GdF@pZE@j `FR*aEQTQBf*MC@PXEQp`FA4iIB'$K)1#JB+%KiQ,LiQ'JAjkGh4aEfj[F(*cG(9 eGRGhGR0YCPpC9&&15dK&3d*$48G+5da068a-6%Y+4d4#38""3dC)5de068e,58G %3N!r2MXi06)[,#JN)4iF'a`H)L8S+LSV,#ia0$8d-c%[,Li`0$P!4NY289*48%e *4N)r2$Sj1$Jf0$%Z,#`X,5mc1$j%58a28&"26dj068e168a-6%j49&GDA&eF@eT D@eeIB&pHA&YD@eaHB'&LBQ0MBf0MC'CRD'KSD@TVDfYVDQPSCfGSDQjcH(YpIRq !JB'"J(pqIAYkH(GfGA4cF'aSC&pE9eC999489&9A@&PEA9pLC@KUE'jaGAKmIS# !JB+$KSQ0N!#5P*@@PjLCQTUER*fHS+1QUDUVUDHNSU#IS+'LT+5NSk+JRTbER*b FQC++J(KcF'jZE@YUD'KTDfe[FA0eGhKiHATlIAjqI(ThGA0aF'pZE@aXDfYVDfY UD'KSDfe`FR0cF@pXD@KSD@YYF(0eGA4bF'p`FR0cF'jXE'jaGAPpJSD*LSZ,LSU *L)L(KS5"IRYjGhCfGhKjHAPjH(KiHAYmI(YiFfjUCQ0KB'&MCQGSD'PYFRPqJ)" rIhjmGh*YDQKSDfpcGRGhGRGjHhf!K)Z5QCfJSk@SUUUSTU5LS*qKTUfcYlQiYE+ ZU+#CP*+9QU#NTkLSUDQUUkf[XE1eZ,c"amh4e0E9dmr,aX2![VZjYl@eYlUr`mM ,cFl2d0,8eYIBfYlLjq[Zm2$[l1MMhYM6cml0cFc+am+mYV#XUDQTUDUVVV1k`FA )b-R+c-r4dG$2cmr4dY,3cFR&`VkkYl5cXl1dYEDfY,+[VDURTD@TVl@jZVZkZ,D cXDqYV+USTU5MT+@QTkDPSk+MT+5KR*@2M)f3!*5BQTbGRk#JRjkFQCD6N!#1MBb +L)@#IhemI(apIRpqI(ThG(*`EfjZE@eYE@YUD'KSDQe`FhCjI(k!JB1%KB@$J(j mI(apIRepIRq"JS+"IhajGR*ZE'YVE'jZEQp`FA0eGRCbE@CKAPeHAf"KBQ0MBQ& KBfGXFRL!KiqARU5TV+k`X,#[V+QRTULTUDHMS*bDQCL@P*'1M)b-MBq3!*+8PTH APjD@PjLDQjbFR*bFR*bGRCfGRTqIS++PUDb[XE+cXl5cXE#ZV+USU+UYX,+bXE# [Vl#aXE'[V+LNS*kEQCLAQCZFRCbEQTZHSUDUVDqZV+LNSCkFQTLAPjD@PC@9PC@ 9PCDCRU1QTkDNSU#JS+'JRTZ@NSk-MBk1MBQ$IAPhGA0`E@YUDQPRC@0LBQ0PCfT XEh&bFR&aFA*dGRPlIAjpHRGcF'eVDQYZFR9hGR9eGACiHAYpIi'%KSQ,LiU)KB& rI(ThFfpVCf9MBQ"IAejHAPjHAPpIAejHAQ"KBf4NBf&JB@4SER0fGhGfGA4dFh* `Efj[F(&bFR*aEfeTCQ4MBf0MBf0LB&pGA9aD9e036Na*4dG+8&GEA9eF@eYE@PK @9&*489*89&456dY'3Mim16Fd-M!`-$%c0MNl1cXl2$dr384)5dj38&"48P058%e +58T18PCC@eaIB@9SDfeZEQj[F(&aFR0dGACfG(&YDQGQC@4MB9pGA&aHB'*MBQ& IA&TB9PC@9eGB@&KB@&TGB'*KAPT988p38eGEA9pKC'GVE@j`FR9fGR4cFh9iHAG cEQPPBPpGA&aGA9eGB'4SDfaZEfp[Eh&fI)1*MT'5NBq1MSq1M)H"HR*UBPT66NY *4N)p1MNl28"#3N&!2Miq3%*&4dP-6e&58P&36dj068j499THB&pF@9968e4@9eK A9PC@9PKC@eaF@PG66de06Np38%p26dp48P*699GEAf*QD@a`FhChGR4cFR&bFR0 cG(9fGRCfGA4cFR"ZDfGNBQ&MCQKSCf9LAPTB9PGDA@"LC'9RD@eaGhf$L)b1MBZ +LSU,MBk2MSZ(Ji"qIi'$K)5%Ji&qHA9bFA&aF'jUCQ0KB&pIAf"LC'CPB9aA999 AA'&PCfGRCQGSDfeZE@YTD'PXFAGmIi'!IRYjGh9dFQpYE'e[FhGlIAq!JS5'KiL )LSb4PTUGRCbER*kJS*kEQCLCQTUCQ*LCQCUCQCLAPT@4MBL%JS1'LSk4Nj58Nj1 6NT'4NC'5NT+4NC19PjD4M)L(L)Z-M)U)KiL)Ki@$JS1&KiL(KS@'L)b3!*@DRU+ PTkLSU+LTUDUUUUQSTkHRTkDPSk#GQjL@P*+3!)q3!*'5P*58Nj15Nj59PT@8NBq -LiZ0N!#5Nj+3!)k0MBb-LiZ-MBk2NC1@Q*QDQCHAQ*UGRk#MTUZ[Xl5dXl1cY,D iZVbq[m#r[lr!`X6(b-M(a-,![Vfp[Vr![lfjYE'ZVDfZVl+eZ,UlZlZlZlZm[Ek q[EZjYV@eYVHj[,kr[VUfXDfVUUZXVV#aXV+aX+kXUD@KRCUCQTfJSkDSUDQTTk@ MS*fEQTUDQjbHRk'MTDHSU+LSU+QUV+fZVUkYVDbXUkUST+'IRTkJSU5QTkLSTk5 JR*UERD#LSk+KSD+NTkZ[XV5eYE5bX+qZVUq`XV'`VDZSTkDNSU#GQjQCQTUEQjZ EQTUEQjZCPj@6NT!!Mif-M)Z+LBL'Ji"pHhTlIS'$Ji&rI(YlIAq#KBQ1NjLFRk# JRTZBPT@8PC@9P*14MSb+LBQ*LSZ0MSq2Miq2MSk2N!#6PCHAPT55N!#2MSf,LBQ +MBq4NC!!MSf,LSL(KS@&KBD(L)L(KS@&K)5%K)5%K)5$Ji1%KBD(KiD&K)5&KSL *LSU+LSZ0MSq2MSf0MT!!NjHERU'NUDkbYVLjZEQiYlHhYVDeY,1aVkbSTD1LSk1 LSD#JSU@RUUZXV+ZVUkURT+'HR*ZDPj11LBD&K)1"IRTfFh&aF'eSBPaC@9YHB@* KB'&MCQPVE'aYE@j[F("[EQeYE'YTCQ0JAPYC9e99999@9PC98e&36Na+4d4#3$m p2$Sj16Sm2NN%r26`m26p"3N*#3N0&5%a38P*58P09@9YGA9aD9e988e489&4 56dY(3cml1$Ji16Sk16Fe-c)b-M3f16e!4%C)58T-6P"699GC@PTD@9G@9eTGB'* KAeaD@9KA9eG@99048%p38P9B@ejIB'"JB'"IAPaE@eYE@PK98e&26%P&36dk16J i1$Fe-LmX+LNT+L`[-M3f16`r3dC*5da-6%e16e&58e9@@9aJC'KXF(4fGR4bF'p `FR0dFh*aF'pZE@aUD'CMB@"IAPeFA&aHAf&MC'4PC@9QCQGSDfjbGRTqJSD*M)k 3!*'6PTQERCbCPC!!M)Q)KiD&Ji&qHhKeFR&aFA&[DfGNBQ&JB'"IAepHA&YD@PY FA9jHAPjGA&TB99*48&&48P089&9@9ePEA9pJAeeD@&GA@9YGAPpIAf"JB&pHA9a FA&jJBQ4PC'0LBQ0NCQPVE@jZEQeYEh&dGRKjHAGeG(4fHAaqIRjqIAjrJ)+%KSH )LBQ)KS5#JB#!JB1%KB@#J(ekHRYpIi"rI(TiGhGhH(PkHhapIAepIRq!JB"rI(P hGR9fGRCfGA0aEfaTCfCRD'PUE'jbGhZ!JiD*LBL'K)*rI(PfG(0bFh0dGA9hHAb !KBL+LiZ*Ki5#JS1'L)Z1N!#4NT18PCHAQ*LDR*kKSU+LSD#IRTbDQ*D8NT'4NC1 @QTfIS+'MSk1LRjfEQjbISU@PT+'IRCZER*bGRCkHS++NTUHRTUDQTkLTUUZXV+f [XE'`VkfXV+bYV+ZSTU1KRjkHRjqIRTfFRCkKSU+KRTZCQ*LCQTUCPj54MSb0MT' 5Nj16P*DCRU+QU+QTUDUVVDk[X,'bY,DiZ,DcX+fVU+DMS*fFR*fHRjqHRCZDQCQ CQCQDQjbFQjbGRU#KSCqHR*ZEQjbFRCfHRTkHRCbFQjZFR*fHS+'LSk1LS*kGRCf HRTbCPT14NC1AQTbGRU#MTUUYVkq[VUfYVl#aXV1dXl+`VDZVUkZUTk+GQ*@8PCD AQ*UFRCqKSU1NT+5NSU'HR*UBPT54MSb+LBQ+Lib0Mj'6PTQERCkIS+#JS+#IRTb EQTUDQCLAQ*QERCqKSU+JRCU@NT!!Miq3!*'5P*@@PjLBPjD@PTHBQTbHS++MT+@ PTD5LRjbCPjD@PTD9P*+3!)k-LSL&Ji+"J)"rIhjqJ)+%KB@$J(elHhaqJB@*MBq 3!*!!Miq2MSf,LBH'KSH(L)L(KiD(KiL*LSU+LiZ-MBk1MBZ(JRjkGhCfGhKjHRT kHRTkHherJ)'#Ji1&KiL+LSU+LBQ*LBL'K)*rIAYlHhYmI(epIS##KBH*LiZ,LSU +LSb0N!#6PTLERCfGR*bER*fGRTkIS++NTD@PSk#GQ*54MSb+LBL(KB5#JB"qI(T hGA4dG(9eGA9fGRCeGRGjI(k!J)#!J)'"Ji5&KiU-Mj+8P*55NC!!N!#3!)q1M)U *L)L)L)L(KS5"IRYiGhChHATlHhTjGh9bEfeVDQPSCfCPC'4NC@9RD@aZF("[E@Y UD@TVE'aXE'YVE'j`FhCiHATlHhapIAakHAPjHRYkH(CcFR"`F(&bFh4dFh&`Efj ZE@TSC'"G@PC88P&38&"36Ne-6P&9@f"NCfKRCQCPC@CRD@YYEQp`F("`F("aFhC iHRPiGA0aFA0hI)'&KSD%JS#!J)"rIAYiGA0bF'jVD'CQCQCRD@TVE'aXDfPSCQ9 MBQ*KB@&KB@&LBQ*MBQ&IAPeFA9jJB'"IA9TA9&*48%p168Y)480#38&"3N4'58Y -68j26e"489&58e999P999&069&499PGB@9TD@eYGB'4SDfj[EfpYDfPRC@*I@eK @994688p168e06%Y*5%K*5Na16Nj068e-5NP)58e499PEA&eIBQ9SDfeZEQeVD@G QCQGTDQTTCf4KB'"LC'CSDQYVDQPRC@*IA&P@8e"05NK(4NC'4NC'4NC'4dG)58a 28eGD@eYE@eeHB'*MBf4NC'4PCQGSD'KRCQ4LAeaC9P989&4999CA@9YIBfKXF(4 fGRCeFh*`EfjYE@aUD'9LAejIB@4QCfKSD@TVE'j[FA4eGRCeFh&`Efp`FA*cFh4 eGRGiHATlIAeqIAalHhapIRjpHRCcEfeVDQPSCf9LB&pIAepHA9YC@&KB@PjLCQP YF(0fHAYmI(apIi'%KiU0Mj'4NT+6Nj15NC!!N!#3!)q0LiL&JS"rIRemHhapIi' #K)@(LBb1N!#4N!#1M)Q'Ji&rIRjqIRprJ)#"JB+%KSU1NT@@PT@6NBq1MBb,LBD #IhepI(apIAerJB5(L)L(KSD(LSf2Mik-LSQ*Lik3!*'3!)k,LBH'KiQ+LiU)KS5 #JS1&KiL*LSZ-MT!!NC+6Nj15N!#2MSk2NC+8P*58PCHDRU+NTUHSUkkbYEHjZEL iYlDfYVLk[F$"`F(!`-(#`m2#`,kq[m,&aXE%`F#r`F6(b-R*b-I(b-R*bFM)b-M *bXV,bmV*amA$`F$!`-$!`,qr[lqr[lflZ,@bXE'bXl1bX+kYV+fZX,+cY,@dY,1 bXE'aXV1eYVLk[F(%aXE&a-'r[Vfq[Vqr[VblZVUl[,blZ,1ZUUHPSk+KS*kHRTk HRk#KSU+LSU+MT+@RUUbYVDbVUDHPSk+KSD'JS*qHRTfHRk#LSk1LRjZBPC16Nj+ 4N!#2MSf0MSk3!*+@QCbHRTkGR*ZDQ*H@PC15NC!!N!#2Mik1MSk2NC5@Q*UEQjZ FRCqKSU+LSD#IR*Q@Nj!!Mik2N!#4NC'3!)q3!*+@QTkLTDHRU+LTUkbXUULPSk' KSD'KSD#IRCbDQCQBQ*D6Mib+LSZ-MBk0M)b-MBq5PCHDQjZDQCLCQTZGRjqHRCZ CPjD9PC@AQCZGRTfFQTQBPjD9P*15NT+5NC'3!)q1M)U)KB*qHhKfGR9dFh&`EQa UD@PTD@YXE@j[F("aFR*cFh*bFR4fHAarJS@(L)Q*L)H'KB@&KSD'KB5%Ji+#JB# !J)'#K)@&KB5&KSL+M)b,L)D&KBD)LBU+LBL)LBZ0Mj'6PCHDR*kIRTbCPj55Mik -LSL'KB@'KiH(KS5#J(q!JB+$K)5%K)1#JB#!J)+$K)5#J(ajGA*`E@TRC'&IA9a E@PPB@&PEAQ*PCfGRCfCQC@9PCQ9PC'0LBQ*KB@"IA9eFA&aE@PK@99999PGA9PC 99&*36dj06Np389*58P*48P*699GB@9TD@9PC@9PD@9KA9PCB@PYFA&aD@9KA9P9 68P&38%p26Nj168e,5NP(4NC%3d&!2cip26dm2$Xj1$Fh1$Xq380$3d0#3N*#3N* !2M`k16Nj1M`q2d"!38d0$3N&!2cmr2d""3N4&4NG)5%G(4NC(5%P+6%j389& 46dj06%Y-69"69PKD@eaGA9aGA9jHAPeE@PKA9PCA@&TEA9pJBQ4PCfKTDQYXE'Y VDQPSD'KRCQ4MBf4PCQKSD'GPBQ"HA&TB9P988P*58e9B@ejKBf4PC'4NC'4NBf* KB'"IAPjHA9eGA9eHAQ"LC@KUDfYVDQTUDQYVDfYUDQPTD'KSD@PUDQTTCfCQCfK TDfaXE'aXE'eYEQjZEQp`FA*cGACiHRerJB5'LBb1N!#4N!#1LiQ)KS@%K)1$Ji+ #JAppHRKfGRCfGhKiGhCfGRGjI(k!JB'!IhjqIRjqIi##K)@(LBU,M)f1MSk-LSH $IhelHRPiGA0aF'p`F(&aFA&aFA&aF'pZE'YTCf9NBf*JAeeFA&eHAf&LC'9QCfG SD@YYEh"bFh4eGRCfGRChHAYpIRjpI(YkHAKhGR9eGACfGR9eGAChH(PjHRYmIAp rJ(prIRepIAamI(alHRPiH(TpJSD+M)b,LBL)L)L)KS@#JB"rJ)#"Ji@(LBU+LSU +Lik4Nj@9PC15NT16Nj+3!)k-LiZ-M)f-LiZ+LSU,Lib-MBk3!*1BRD'NTUDPTD5 PTULUV+fYVDfYVDfYV+bXV+fZVkq`X,'bXl5dXl+bXV+dYEDfYV5cXV+bXl5eYVH iZVZlZlZlZlbm[Er"`m6%aFA%`m,![VZjZ,HiZEUm[Vr!`,qpZlQiYlLiZ,DdXDk VUDHQT+'HQTH8NT!!N!#3!*!!NC'5P*@AQCUER*bFR*bFR*bEQTQCQCUER*bDQCL APTD@PTHAQ*LBQ*LBPjHAPT@8Nj+4N!#1MSk2N!#5Nj56NT'3!)q1MSq3!*+8PjQ FRk'KSD#IRk'NU+b[XV5fYlHhYV@cX+bRSTfCPC+3!)k0M)Z,M)k2NT5AQTkKTDL UV+fYVDbXUkQSTkDPSk+KSD'MT+DRU+LTUUbYVl#aXE'`VUkZVl#aXV#ZUULQTUD SUDUTTk5KRTbFR*fGRTqJSU@SV+qbY,DiZEZp[m$![lflZELfYE1aVkfYVUq`XE' bXV'[VUfVUUQSTk@MSCkEPj54MSf0M)Z*L)D&KBD(LBZ-M)b-MBk2N!#5Nj58P*5 8PCDAQ*QCQCQDQTZFR*bEQTQBPjD@PTD9P*+3!)k0M)U)KS5"IhjpI(YkHAKiGhG hGhGiH(KiGhGiHAYpIRq!JB'!IhelHRTkHhYmHhYkHRTlHhYkHAPiHATmIS'$K)@ %K)5%KBH*LSb-MBf-LiU+LSU,M)f1MSk0LiQ)KiH)LBU,LSL'Ji+#K)D*M)f1MSf 0MBf0M)b0MBk0LiQ(KB1#J(jmHACaE@TRC@4NC@9QCfKTDfaYEQj[Efp`FA0dGA9 eGA9dFh&ZDQGNBf0MC'4NBf*KB@"KB@&KB@*LBQ*LBQ*LBQ*MBf4NC'4MBf0NC@C PC'&IAPjIB'*MBf*LB@*MC@KUE'eYDfTTD'GRCfCQC@9QCQGRD'KRCfGRCQ4MBQ& KB&pG@eK98Np-5NK(4N9&4NG)58T08&4B@PaFA&eHB'"KB@&LBf9QCfGQC@4MBQ" IA9YD@&G@9P9999998e&16%P(484#3$mp26`p2Miq26dp2N""3N0&4NG(4dG&3d% q2$Nh063c-M)d0MJl2N"$4%C(58Y-68e06%a-68j389*48%j-5dY-6%e-5dP)4dC &480"2cdm2$dq2Mp!3%&"3N*#3N*#3d0%48C'4N9&489&4NC(58a28PCDAQ&PD'T YER"`FA&aF@pZE'TSC@0KAejGA&aFAQ"LBf4PCQGRD'PTDQYXEQp`F(&aFA*cFh0 aEfaUD@PTDfaZF(&bFR0dG(9fGR9dFR&aFA*dGRKjHAPhGA0aEfaTCf9NC'0KB&j GA9eHB'*MC@CQCfPUE'jaFh9hGhGfGR9fGhPlIAprJ(prIRjrIhprIRjqIRjrIhp rIRakH(CdFh*aFR*cG(9dFh"XD'4KAepIB'*MC'4MBf0NCQKVE@paFhCkIS+'LSb 0MBf-LiU*L)H'K)1#JB"rIRepI(alHhTkHAPjHRTjHAKiHAPjH(GfGACfGRChH(P lIAq"Ji1$JAppI(YlHhYkHAKhGR4bFR*bFh4fGhTpJB5'L)U+LiZ,LSQ*L)Q+M)k 2N!#4NC'3!*!!Mik0MBf0MSk1Miq3!*'6P*DAQ*QCQCQCQCQCQCUEQjUBPjD@PjH BQ*LBQCZGRTqJSU5RUUbZVkq`XV5fZ,QkZELfY,1bXE'aX+qYV+ZUUkbZX,#`Vkk XUkZVUkbXV+bXV+bZVl'bXV+aX+qZVUkYV+USTkHRU+QUUUQSU+LTUkk`XV5eYlQ l[X(%amV-cFl2cmr3d0(4dG(3d-r1cXh0cFc+amA$`F,$a-E'aF2![EUiYV@eYE5 dY,1cXl5dXl+aVkfUUDQTUDQSTU5MSD#JRjqJSU5QU+UXVl'cYEDiZEQjZELfXl# YUUHNSCkEQCH8NT!!Mik2N!#5P*@@PjD8NSk+Ki5#J(jpIAeqJ)1&KSH(KiH)LBU -MBk1MSk1MBf0MBf-LiU+LiZ-MBk1MSk2N!#3!*'5Nj18P*15NC!!MSf-LiU*L)L )LBU-MBk1MBf-M)b-M)f0MSk1MSf-LiQ)KiD&Ji"pHRKfGRChHAYpIi#"JB+%KSQ 0N!#5PCHDR*kJSD'KSU+MT+@PTD5MSk1NT+@PTD5NSk1MSk+LSk5PTUHRTkLSU+L SU+LTUUZYVUq[X,'aXV+aX,#[VUfVUDDNSk+LSk5NTD@PTUDQTUDPT++KRjbDPT1 2LiH%JS'!J)'"JS1%KBD(L)Q+Lib0MBk0MBb-LiU+LSQ)Ki@%JS"rIRakH(9cFR* bFA"ZDQCMBQ*MC'9NBf*KBQ0PCfKTDQPTCfCNBQ"HA&TC9eC999489&489&499PG C@PYFA&eHB'&MC@9PC@4NC'CSDQaZEQjZE@jZEfp`FA*cG(4cFR&`F("aFR*cFh0 dG(9eGA9fGhPlIS'%KSL+M)k3!*'5Nj+4Mik-LSL(KS@%Ji'!IhjqIAalH(4aE@Y UD@PTDQTUDQTUDfYXE@eXDQKPBf*KB@*NC@9QC@9NC'4PCfTYEh&cGAGjHheqIRj pI(PhFfpVCf0KAPaE@PKA990589"389&48P0899CA@&KC@9PC@9PD@PYFA9jIB@0 PCfKTD'CNB9jF@eTC@&G@9&468P&36dj-5dT*5%K*58P+5da06Np38&"38&"48P4 99PGB@&PC@PYFA9jIAf"KBQ0NC@4NBf0LB@&JAepIB'"JB&jF@eTD@eYE@eYD@9K A9eGB@9PD@9K@9&&05NG&3d&!2cmr3%&"38&"3N0%4NG)5Na28PCDA@"KBf9QD'P UDfe[FR0cFh0cFh0bFA"ZE@aVDfYUD@KQBf&HA9aFA&YE@PKA9eGB@9TE@eaGA9j HA9aD@9KB@&KC@PYE@eTC@9PEA@"MCfTZFA0eGRGiH(KiGhCdFh&`EfjYE'aXDfT UD@KSD@TVE'eYEQj[F(&bFA&`Efp[EQeVD@KQC@9PC@4NBf0MC'9QD@YZF(*dGRG jHhapIAepIAepIAjqIhq!J)"rIi#!JB+$Ji5%K)@'KiL+M)f0MBb,LSQ)KiD&K)1 "J(jpI(YkHAKiH(PlI(eqIRjpIAamHRPfG(0bFR0dGRGjHRYmIAeqIi#"JS+$Ji1 $K)5%Ji'!IRalHAKhGhGiHAYmIi'%KSL+Lib-M)Z+LSQ+LSb0N!#5PCLERD'NTkZ ZXE1eYlLiYl@cX+fUTD#EPT+2MSf1N!#5P*DCQjbGRTfGRTqJSU1NSk1LSD#JSD' KS+#IRjqIRjqIRTZBP*!!M)H%JAprIi#!IhjpHhYlI(k!Ji@(L)Q)KiD&K)1$K)@ 'KiL)L)H(KS@&KBD(L)L*LSb1N!#4NT'4N!#3!)q2Mj!!NC'4N!#1M)Q(KSD'KiL +Lib0MSk2NC19PjQERCkJSD1PTkQVVV#dYlQl[,kr`F2&amM)amA#[lbkZVUl[,b mZlUjZEUl[Ekq[VfmZlZkZELhYE5bX+fVUDLRTU@MSU'KSU5QTkLTU+LSU+LSTk@ MSCqHRCfFR*bGRCkIS+'LSk5NTD@PTULSUDQSU+DPSk+JRjfEQTLBPjH@PT@9PC@ @PjLBQCLBQCQER*kJSD+MT+DRU+UVVDk[X,'aX+qYV+bVUkZXV+bVUkQTU+HRTU@ NSU'JS+'LSk5PT+1JRTbEQjbHRk#IRjqISD1PTkHRTk@NT+@QTkLSTk@NSCqGQjL @P*'1LiL'K)1#JApmHACcFA"`FA*bFh0bF@pYDfKQC'0MBf4QD'TYEQpZEQeXE'Y VD@KRCfPUE@p`FA&bFR0eGhKkI(q!JS1%KSL*Lif1Mik1M)Z+LSU+LSQ*L)H'KB5 #JAprIhjqIAakHAKhGhKjHherJB1&KSH)LSZ-MBf0MBf0MBk2Mj!!NC'5NT59PjL CQ*H9Nj!!MSb,LiU+LSU,LiZ,M)b-M)Z+Ki@#IhemHhamIAeqIi##KBL,MBq4Nj5 9PTHAQ*HAPC55N!#1MBb-M)b0MBk2NC1@Q*UER*fGRCbEQCLAPjDAPjHBQ*QCQjb GRk#JSD+LSk1MSk1KRjbCPT13!)k-LiU*L)H&Ji+"J)#!IhpqIAepIRjqIRjpI(T iGhCeGA4cFR"YDQCMB&pHAf"KB@*LBQ&KB'"HA9aE@PPB9eC88P"05dP(4N9'4NG )5%P*58P*58K)4dG(4dG(4dG'489%4%0$3d*"3%!r2cip2$Xj0cBe0MFj1M`p2Mp !3N0%48G)5Na06Np28&&489&36de068e16Nj168e16e&699GB@9PB@&KB@&PD@ea GAQ"KBQ*MC'CRD@TXE'eYEQj[F(*cG(4dFh&`Efp[EQeXDfYUDQPTCfCNBQ"G@eP A99046Na*4d9$3N*$4%C(58T-68p38P0899C@9eKC@eaFA&YD@9G@99468e*488p 16%Y+5NP+5NY,6%a-6%a06P"48P089&9999CA@&PD@PTC@9PC@PYHB'*NC@GSD@Y XE@eZEQjYE@aXE'aXE@jZEfpZEQjZEQp[F("`F("`EfjYE@eYEQp`FA*bFh0cG(9 fH(TlI(epIAemHhTiGR9dG(4dG(0aEfaTCf9NBf4PCQGSD@PTD@PTD@PUDfe[FR9 hHATkHRTkHRPjH(GfGA4cFA"ZE'YUD@PTD@TUDfaXE'aXDfTTD'KTD@TVDfaXDfY XE@pbGAKlIB##K)@'KiH(KiH'KS@&K)5%KB@&KB@&KB5%K)1$Ji5&KSL*LBU,M)f 2NC18PCDAPjLBQ*H@PTDAQTfKT+DQTUDPTD@QTkQUUkUTTk@MSU'JRjkGR*ZDQCL @PC14Mif,LBH&Ji'!Ihq!JB1%KBD(KiH)LBZ1N!#6PCHCR*kKSk5PTD@NT+5NTDD SUDZXV+bVUUUTUDQTU+HQT+1LS+#JS+#JS*qIRTfFQjUBPj@8Nj+4NC'4NC'5P*@ @PTD@PTHCQjqLTDLTUUUUUDQTU+LSTkHQTUDQTUDQTU@PT+5NSk1LSU'JRTfEQTL APjD@PjLCQTZER*fGRTqIS+'MT+@RU+LRTU@NSU'KS*qIRTkGRCbEQjZFRCkGR*Z EQTUDQTUCQ*H9Nj!!Mif-M)b-M)f0MBk1Mj'5Nj@@PjQERU#MT+DRU+QUV+f[Vkq ZVUk[X,+dY,5dXl+aX,#[VUbTU+HRU+QUUUUTU+DPT++KS*qGR*ZDQCLAPC13!)k ,L)D&K)1$K)D(LBZ0Mj'6P*@9PC@@PjQDQjZEQTLAPTD@PTD@PTD9PC@9PC@9PC5 6NT'4NT19PTLCQTUDQTUDQTUDQTUDQCQBQ*LBQ*LBPjD9P*16NT+5NT+6P*59PjL CQTUCQ*HAPjHBQ*LCQCUEQjbFQjZEQjbGRU#LSk1LSCqHRCfGR*ZCPj55N!#2Miq 2Mik1MBf0MBf0MBk1Miq2MSf-LiQ(KB1"J(jmHRKfG(0bFA"[EQjYE@eYE'aUD@G PBf*KB@&LBf0MBf*LBQ0PCQKUDfaYEQj[F(*cG(0cFR&aFR0fH(TlI(epIRq!J)' "JB'"J)#!J)#!IhprIRjpIAamI(aqJ)+%KBD(L)L*LSU,LSU*L)D'KSD'KSD'KS@ %Ji&rIRepIAemHhPhGR4dG(9fGhKiHAPjHAPiH(KiGhCdF@jVCf0JAPaE@PPB9eC @99468P*58e499PKC@PYFA9jIB@*MC'9RD'TVE'eYE@aXDQPSCfCQCQCQC@4MBf0 MBf*LBQ&KBQ*MC'9QD'PUDfYVDfYVE'j`FR4fGhKiHATmIAjqIhpqIRjpIAamHhT jH(GhGhKjHRYlI(amHhYjH(CdFR&[E@YTCf4KAeaE@PTEA&jIB'"JB'&KB@*MBf0 MBf0LB&eD9P*25dP'3d!q2$Xl1MSj0cBe068f0cJk2$dq2dd4'4dG(4N4$3d0 %48G)58Y,6%a-6%Y,5dY-68j389&58e9@9eKD@eaHAf"JB@*LBQ&JAepHAf"KBQ0 NC'9RD@YYEh"aFR0dGAChH(KiGhCeFh&[EQaXDfTTD'GQC@4MBf*LBQ*LBf9RD@Y YEQp[F(&bFR0cFh0bFA"[EQeXE'YUD@KQC@9PC@9PCQGSD@TVE@j[F(&bFh0cFh0 dG(9eGA9dFh*aFA&bFR0cFh*bFR0eH(TpIi#"JS1%KBH)LBU*L)D&Ji+"JB'!Ihj pI(YkHRTkHRPjHAPkHhamIAepIRjqIRepI(YjGhCeG(4dGA9eGAChGhKjHATjHAP jHRTlHhYkHAPiH(KiHATkHRTjHAKiH(KiHATlHhYlHRTkHAPjHATkHhaqIhq!J)# "JB+%KBD'KSD'KiH)LBU,LiU)KS@%Ji1%KBD(L)L)L)L)L)L*LiZ-MBf1Mj'6P*D BQCUEQjZEQjZER*bGRCfGR*ZDQCH@PC56Nj16Nj15NC!!Mik-LiU*L)L)L)Q*LBQ *LSU,Lib-MBk3!*'5P*@@PTHAPjH@PTD@PC@9PC@9PC58P*59PCD@PC56NT'4NC' 3!*!!Mik0M)b-MBk1Mj!!N!#3!*'4NC'4NC'3!*!!Mik0LiU*L)L(KiD&KB@'KiL +M)f1Miq1MBf-M)f1Mj'5Nj59PTHBQ*LAPjD9P*58P*58P*58P*58P*58PC@AQ*Q CQCLAPC15N!#2Mj!!N!#4NC!!Mik-LiU+Lib0Mj!!NC+5P*@AQ*UFRCfGRTqJSU5 PTUDPT+5NT+5PTUHSU+HPSk'JRjqIS+#KSD'LSk5QU+UXVDq`X,'bXl5eYVDfYE5 cXV'`X+qZVUfYV+bXVDf[X,'aXV1cXl1cXl1cXl+bXV+bXl1cXV+aVkkXUULQTD5 NT+5MSk1MSk5PTD@QTUDQTUDQTU@NSk'JRjqHRTkGR*ZDQ*D9P*58P*58P*58Nj1 6NT+5NC+5NT16Nj59PjLDQjZEQjUCQCLAPT@8P*59PC@9PC55N!#1MBf0MSq3!*+ 6P*@9PC58P*15NC!!Mif-M)Z,LiZ,M)b-LiZ+LSQ*LSU,M)b-MBb-MBf0MSk2Miq 2MSk0M)Z+LSQ*L)L(KSD'KiH(L)H(KS@&KB@'KSD&K)1#JB#!J)"rIhpqIRjrIi# !J)#!IhjpHhYkHRYmIAjrIhprIAalHhYlI(YlHRPjH(KiH(GfGA4dG(4dG(4dG(4 dG(4dG(4dFh0bFA"[EQeXDfTTD'GQCQCQCQGRCfCPC@9PC@CQCQCRD'PVE@paFR* cFh4eGhKjHRTjH(GfGA0bF@pZE@aXDfTTD'GRCfGRCfKSD'PTDQYXE'eZEQp[Efj XDfTTD@PTD@KSCfCPC'0MBQ*KB@&KB@&LBQ0MC'4MBQ&HA&YC9eC88e&38&"38P0 8999@9PGB@9TFAQ"KBQ*MBf4PCQGRCfGRCQCQCQCRD'PTD@KSCfCQCQCQC@9NC'* KAejGA&eHAf&LBQ*LBQ&KB@&KB@&KB@"JB&pIAepIB'"JB'&KBQ0PCQGSD'PTD@P TD'KSCfCQCQCQCQCPC@4LB@"IAPpIB'&LBf0MBQ*MBf4QCfKTDQTTD@KQC@4MBQ* LB@&KB'&KBQ*MBf4NC'9QCfKTDQTUDQTUDQTUDQTTD'GQC@4MBQ&JB&pIAepIB'& LBf0MC'4MBf4NCQGSD@PSCfGQCQGSD'PUDQYVDfYXE'eYE@aXE@eZEQjYE'TTD'G RCfGRCfCQCQCQCQ9PC'4MC'4NC@9PC@CQCQ9PC'0LBQ*LBQ*MBf0NC'4NC'4MBf0 MC'4PC@9QC@9QCfKUE'paFh4eGRCfGRGhGhGiH(KiGhCeG(*aF("`F("`EfjYE'Y VDQTUDQPSCQ9PCQKUE'pbG(GjHhk!JS1%Ji1#JB#!JB'"JB"rIRepI(apI(amHhT kHAPjHAPiH(KiH(KiH(PjHATkHhYlHRTkHRTlI(erJ)'#Ji5&KSH)LSf2NC18P*5 8PC@9PC@9PC@@PTDAPjD@PjLCQTZFR*bFR*fIS+'KSD#IRjkHRCfFQjUBPT55NC! !Miq2Miq2Miq3!*!!NC'6P*@AQCZGRk'LSk1MSk+KS*qGQjUBPjH@PC@8NT'3!)k 0MBf0MSq2N!#3!*!!Miq2N!#3!*!!N!#3!*'4NC'5NT16P*59PTD@PT@9PCD@PjL CQTUDQTZFR*fHRTqJSD'LSU+LSU+LSU'KSD#IRjkGR*UCQ*H@PC@9PC@@PTH@PT@ 9P*16P*58PC58Nj16Nj58PC@9PC@9PCD@PjLBQCQDQjbGRTqJSD#JRjkGR*ZDQTU CQCLAPjD@PTD@PjHBQCUER*fGRCfFQTQAPT56Nj+4N!#2Mik1MSk2Miq2N!#3!*! !N!#2Mj!!N!#3!*'5Nj18P*16NT+6Nj58PC@9PC@8P*56NT'4N!#3!*!!N!#4Nj5 9PTHAPjHBQ*QDQjZER*bGRCkHRTkIS+#KSU1MSk1MSk1NT+5MSk+LSCqGQjQ@PC1 5NC!!MSb,LSQ*LSU,MBk2N!#4Nj59PTHBQ*LBPjHAPTD@PTD@PT@9PCD@PjQERCk JSD+MSk1MSk1MSk1NT+@PTUDQTD@PT+1MSU+KSD'KSU1MSk1MSU'JS*qHRCZDQCH 9P*15NT18PTLDR*fISD1PTkQTUDHPSk'JRTfEQTLAPT56NT'4NC+6P*58P*15NC! !N!#2Mik0M)Z+L)D&K)5$Ji1$JS'!IhjpI(alHhYkHRPiGhCeGA9eGA9eGA9dFh0 cFh*bFR&`EfjZEQj[Efp[Efp[F(&cG(ChH(PjHATlHhYlHhYlHhYlHRTjHAPjH(K iH(KjHRYpIRq!JB'!J(pqIRjpIAjqIRq!J)'"JS1$K)5%Ji1$Ji+"IhjmHRKfGA0 bFR&aF(&aFR*cFh4eGACfGRGhH(PjHAPiH(GfGA9eGAChGhKjHATlI(amI(YlHha pIAepIAalHhYlHhYmI(apIRjrJ)#!J)#"JS+#JS'!J)#!J)#!IhpqIAamHhTjH(G eG(0bFA"`Efp[Efp[EfpZEQj[Efp[Efp[EQj[Eh"aFR*bFR*bFR0cG(4dFR"ZE'T TD'GQCQCPC@0LB&pGA9eGAPjGA&TB9P989&488e068P*58e068e068e068e*589& 48P*68e058P*489&489&489&489&489*68e068P&36dp26dp26dp26e&59&GB@PY FA&jIB@*MC'4MBf*LB@"JAeeFA&aFA9eHA9aF@eYEA&eHAf&LC'CRD'PUE'eZEh& aFR0dGAGiH(KiGhGfGRCfGRCfGRCfGRCfGA9eGA4cFh&`EfjYE'aXE'YUD@KRCfG RCfGQC@9NBf0MBQ*KB&pHAPeFA&aFA9eGA9eGA9eGAPpJB@&KB&pHA9eGAPpJB@& LBQ0MC'9QCQCQCQCQC@9QCQGRD'KRCfCPC@9PCQGRCfGRCfGRD'KSD'KRCfCQC@9 PC@9QCQGRCfGRCfKSD'PTD@KRCQ9MBQ"HA9aE@PTC@9PD@eaGAPpJB@&LBf4PCQG SD'KSD'KRCfKSD@TVE'j[F(&bFh0cFh0bFR*aFA&aFA*bFh4eGRGjHRaqJ)'$KBD (L)L)L)H(KiH(L)L)L)L)L)L*LBQ*LBL(KiD&KB5%K)1$JS'"J)#!JB'"JS+#Ji1 $JS+#JS1$K)@&KS@&KB@&KB@&KBD(KiL*LSZ,M)b-MBk2NC18PTHBQCUDQTUCQCQ BQ*LBPjHAPjLCQTbHRk#KSD'KSD#JRjkFQjQAPT@8Nj+4N!#2MSk0MBf1Mj!!NT1 8PCDAPjHAQ*LBQ*QCQCLBQ*LAPjD9P*15NT+4NC'3!*!!N!#3!*'5Nj@AQCZGRk# LSk5PTUHSUDUVUkZUUUQSU+QTUDUUUDQSU+LSUDUUUkZXV+fZX,+cY,@fYE@dXV' [VUfXUkUSTk@MSD#HRCbFR*bGRCfGRCkHRjqJS*qJS+'KSU1MSU+KSD'KSU+LSD# IRTfEQjUDQTUER*fHRTqJS+'LSk5QTkQUUUZUUUQSTkDPT+1KRjfDQ*D9Nj'3!)k -LiU*LBQ*LSb0MT!!NC+5Nj58PCDBQCUER*bGRCfGR*bGRCfGRCfGR*fGRCkHRTk GR*bEQTUCQ*LAPT@9P*58PC58P*16Nj16P*59PC@9P*15NC'4NC'5NT16Nj59PTH BQ*LCQCQDQjZEQjUCQ*H@PT@8P*14N!#3!)q1MSf0MBf0MBf-M)b-M)b-M)b,LSL (KS@%Ji+"J(pqIAeqIRjrIhq!J)+$KBH*Lib0MSq3!*!!NC'4NC'3!*!!Mik0M)b ,LSQ*L)Q*LSZ-MBk2Mj!!N!#4NC+5Nj@@PjHAPTD9P*15NT+4NC!!Mik0MBf1Mj! !N!#4N!#3!)q2Miq2N!#3!*!!N!#3!)q1MSf0M)b-M)f0MBk1MSk1MSk0M)Z,LSU +LBQ)L)H'KB@%K)5&KSH)L)L)KiH'KSH(L)L)L)L(KiD&KB@%K)1#JB"rIhq!J)" rIhprIhprIhpqIRemHhTkHAKhGR9dG(4dFh0bFR*aFA&aFA&bFR*bFR0cFh0cG(4 eGRGiH(PjH(KiGhCfGA4cFR&`F'pZE@aXE'aXE'YVDfTUD@KSCQ9PC'0MBf4NC'9 QCQCQCQ9NBf*KB@&LBQ*LBQ*KB@*LBf4NC@9PC@CQCfGSD'KSCfCPC@9PC@9PC'4 NBf0MBf0MBf*LBQ&KB&pHA9aFA&aGA9eHAPjHAf"KBQ0MBf0LB@"HA9aE@eYFA9j HAf"KBf9RD@TXE@jZEfp`F("`F(&aFA&aFA&`F'p[EfjZE@eYE'aVDfTUD@PTD'K RCfGRD'KTD@PTD@KRCQ9MBQ&KB'"JB'"JB'"JB&pIAepIAepIAepIAepIAepIAf" JB'&KBQ*LBQ*KB@&KBQ0MBf0MBf*LBf0PCQGSD@PTD@TUDQTUD@KQC@4NBf0MC'4 MBf0MBf0NC'9QCQGSD'PTDQYXEQpaFh4fH(TlI(epIAemI(alHhTjH(GhGR9dFh* aF("`F("aFA&`EfpZE@YVDQPRCQ9NBf*LB@&KB@"JB'"JB'"JB@&KB'"JB&pIAep IAepJB'"JB@&LBf0MBf0MBf*LBQ*MBf0MBf0MBf0NC'9PC@9PCQCQCQCQCQ9PC@9 PCQCRCfKRCfGQCQCQCfKTDQYXE'eZEh"`FA*bFh4dGA9eG(4dFh0bFR*bFR0dGAC iHATlIAk!JB1&KSH)L)Q*LBL)KiH(KiH(KiH(KSD'KiH(L)L*LSU,M)b-M)Z,LiZ ,LiU+LBQ*LBQ+LiZ-LiZ,LiZ-MBf1Mj!!N!#3!*!!N!#2Miq1MBf0MBf-M)Z+LSU +LSU,LiU+LSQ*L)L)L)L*LSZ-MBk2Mj!!N!#4NC'4NC'4NC'4N!#2MBb-M)f1Mj' 5Nj@@Q*QDQjZFR*bFRCfGR*bFQjZDQCQCQCQCQCQCQ*LBPjD@PC56NT'3!*!!N!# 3!)q2Mik1MBf-M)Z,LiZ,LSU+LBQ*L)L)L)L*LBU,Lib0MBk2Mj!!N!#4NC+5NT+ 5NC'4N!#3!*!!N!#3!*!!N!#3!*!!N!#3!*'4NT19PTHBQCQCQCQCQ*LBPjHAPjH APjHAPjLBQCQDQjZFR*fGRTqKSU1NTD@QTUDPTD@PTD@PTUDQTkHRU+LSTkHQTU@ NT+1LSU'KS*qHRTfGRTkHRTfGRCbEQjZER*bGRTkIS+#JSD'KSU1NT+@PTD5NSk1 LS*qHRCbEQjZEQTUDQTUDQTQBPjD9P*56Nj+5NC!!MSf-LiU*L)H(KiH(KiH'KSD (L)L*LBU+LiZ,M)b-MBf0MSk1MSk1MSk2Mj!!N!#4NC'3!*!!N!#3!*!!N!#3!*! !N!#3!*!!N!#3!*!!N!#3!*!!N!#3!*'4NC!!Miq1MBb-M)b0MBf0MBb,LiU+LSU ,Lib-M)f0MBk1Miq3!*'5Nj18P*@9PC@9PC@8P*16Nj18P*58PC@8P*16NC!!Mif -LSQ*L)H'KB5#JB#!J)#!J)'"JB'"JB'#JS1%KB@'KiL*LBU,M)f2N!#4NT16Nj5 8P*58Nj16NT'3!)q1MSf0MBf-M)b-M)f0MBk1Miq2Miq2MSf0M)Z+LBL)L)L*LBU +LSQ*L)L)L)L(KiH'KS@&KB@&KBD'KS@&KB@%K)5%Ji1$Ji1#JS+#JB'!IhjpIAa mHhTjH(GfG(0cFR*aFA"`Efp[Eh"`FA*bFh0dGAChGhKiHAPjHAPjH(GhGRCeGA9 eG(4dFh0cG(4eGA9eG(9eGA9eGA9eGA4dFh0bFR&aF'pZEQeZEQjZEQp[Eh"`FA* cGAChHAYmIRjrIhprIRjpIAalHhTjGhCeGA4cFh*bFA&`F("`F("`F("`F'p[EQe YE'aVDfYUDQPSCfCQC@9NC'4MBf*LBQ0MC'9QCfKTD@TUDfaYEQp[EQjYE'YVDQT UDQPTD'GRCQ9PC'4MB@"IAPeGA9eGA9eHAPjHA9eGA9eHAPpIAejGA9aFA&aGAPp JB@*LBQ*LB@&JB'"IAepIB'"JB'&KB@&JB'"IAepJB'"JB'&KBQ0NC@9QCQCQCQ9 PC@9PC@4NBf0LB9pIAPjGA9eGA9aFA&aFA&aFA9eHAepJB@&KBQ*LBf0NC@CRCfK SD@PUDfaYEQj[Efp`F(&aFA&aFA&aFA*bFR&aF'p[EQjZEQeYE'aXE'aXE@eZEQp `F(&bFh0cG(4eGAChGhKiH(KjHAPkHRYlHhYlHhYmI(apIAepIAamI(amI(apIAa mI(YlHhYlI(apIRjrJ)'#JS1$Ji1$JS+#JB'"JS+#JB'"J)#"JB'"J(pqIAalHhY lHhTkHRTkHAPkHRTkHRPjHAKiGhCeGA4dFh0bFR*bFR*bFh4eGRGiH(KiH(KhGRC eFh0bFA"`F("`FA&aFR*cFh4dGA9eGA4dFh0cFh0cFh0dG(4eGACfGhKiHAPkHRP jHAPjHATkHRYlI(apIRjqIhprIhpqIRjqIRjpIAepIAepIAepIAjqJ)'#Ji5%KB@ %K)5$Ji+"JB#!J(prIhprJ)#!JB'"JS+#JS+#JS+#JS+#JS+$K)@'KiL*LSU,M)f 1Miq3!*!!N!#3!*!!N!#3!*!!N!#4NT+6P*@@PTHCQTZGRU#KSD+LSU+KSD'JS*q IRTkHRTkHRTfGRCfGRCkHRTkGRCfGRCfHRjqJSD'KSD'KS+#IRjqHRTkHRCfFQjZ DQTUDQTZER*bGRCfHRTkHRjqIRTkGRCbFR*bFQjZDQTQBQ*LBPjHAPjHAPjD@PC@ 9PC@@PTDAPjHAPjHBQ*LBQCQCQCQBQ*LBPjD@PT@@PjHBQ*QBQ*LBPjHAPjHAPTD @PC56Nj+4NC!!N!#3!*!!N!#3!)q2N!#3!*'5Nj16P*58PCD@PjHAPjD9P*56Nj+ 5NT+5NT+5Nj18P*@@PTHAPjD@PC@9PC@9P*58Nj16Nj15NT+4N!#2MSk0MBf0MBk 1Miq3!*!!NC+6Nj59PC@9PC@@PTD@PC@9P*56Nj16Nj16Nj16Nj16NT+4N!#2MSk 0M)Z,LSU+LSZ,Lib0MBk1Miq2Miq2Mik1MBf-M)b-LiZ+LSQ*LBQ+LSQ*LBL)LBQ +LSU,LiZ,M)b0MBk2N!#3!*!!Mik0M)Z+LBL(KSD&K)1$JS+#JB'!J)'"JB+#JS+ #JS+#JS+#JS'"J)#!J)'"JB'!J)#!J)'"JS+#JS1$Ji1$JS+"J(pqIAalHRPjH(G hGhCfGR9eGACfGhGiHAPkHRYmI(eqIhq!JB+#JS1$Ji1$Ji1$JS+#JB'"J)#!J(p rIhjqIRepIAamHhYlI(apIAeqIRjqIRprJ)#!J)"rIRemHRTjH(GhGR9eG(4dGA9 eGRCfGR9eGA4dFh0cFR*aF'pZEQeYE'aVDfYVDfYVDfYVDfYVDfTTD@KSD'KSD@P UDfaYE@jZEQeYE@eZEQp`FA*cG(ChH(PkHhamI(amI(amI(amHhYkHAPiGhCeG(0 cFR*bFh0dG(4eGA9eGA9fGRCfGR9eG(4cFh0cFh4dGA9eGA9eGA9fGhKjHAPjHAK iGhCfGA4cFR&`F'p[Efp[EQjYE@aXDfYUDQTTD@KSCfCQC@9PC@4NBf0LBQ*KB@& JB&pHAPeGA9eGA9jHAf"KB@&LBQ*LBQ0MC'4NC'4NC'4MBf*LBQ*LBf4PCQGRCfG RCfGRCfKTD@TUDQTUDQYVDfaXE'aVDfYVDfYVDfaXE'aYE@jZEh"`FA*bFh0dG(9 eGA9eGRCfGRCfGA9eGA9eGA4dG(4dFh0cFh0cG(4cFh0bFA"[EfjYE@eYE@eYEQj ZEQjZEQjZEQp[EQjZEQj[Eh"`F("[Efp[Eh"`FA*bFR*bFR&aFA&aFA"`F("`FA* cG(9fGhKiHATlI(epIRq!J)#"J)"rIhjpI(YlHhYmI(eqIi#!JB+#Ji1$Ji1$Ji1 $Ji+#JB'!IhprIhprIhpqIRjqIRjqIRepIAamI(amI(apIAepIRjqIRprIhq!J)" rIhjqIAamHhYkHRTjHAPjHRTlHheqIi'#Ji5&KSD'KiD'KS@%K)1$JS+"J(pqIAa mI(YlHhYmI(epIRjqIhprIhq!J)#!J(prIhq!J)'#Ji5%KB@'KSD(KiH(L)L*LBU ,M)b0MSk2Miq3!*!!N!#3!*!!Miq1MSf-M)Z,LiZ,M)b0MBk1MSk1MSk2N!#4NT1 8PCD@PTH@PT@9P*16NT'4N!#2MSb,LBH'K)1#JB#!J)#!J)'"JS+#Ji1$K)5%K)5 %K)5&KBD'KSH(KiH(KSD&KB@&K)5&KB@'KSH)LBQ+LiZ-M)b0M)b-LiU*LBL)KiH (KSD'KSD(L)Q+LSZ,LiZ-M)f1Miq3!*'4NC'4NC'4NT+6P*@9PTHAPjH@PT@9P*1 6Nj+5NT+5NT16P*@9PTD@PjHAQ*LBQ*HAPjD9P*15NT'4NC'5NT+5NT+5NT+5Nj1 8P*59PC@9PC@9PC@9PC@9P*58P*56Nj16Nj58P*58P*58P*56Nj15NT+5NT+5Nj1 6Nj16P*@9PTHBQCUER*bGRTqIS+'KSD#JS*qIRTkGR*bEQTQCQ*H@PC56NT'4N!# 3!)q2MSf-M)b-M)f0MSk2Miq3!*!!N!#3!)q2MSf-LiU*LBL(KiH'KSD'KSD'KSH (KiH(KiH'KSD'KSD'KS@&K)5$Ji1#JS'"J)"rIhprJ)#"JS1%K)@&KB@&KB@%K)1 #JB"rIhprIhprIi#!J)#!JB'"JS+$K)5%K)1$Ji1$Ji1$Ji1#JS+#JS+#JS1$Ji1 $Ji1$K)5&KB@&KB@&KB5%K)1$JS+#Ji5%KBD(L)L)L)Q*LSZ-M)f0MSk1MSf0MBb -LiZ+LSQ*L)L)L)L(KiH(KSD'KSH(KiH(L)L)L)Q*L)L)KiD&K)5$JS+"J(pqIAe qIRprJ)'"JS1%K)@&KB@&K)1$JS'"JB#!J(prIhpqIRjqIRjqIRjqIRprIhq!J)# "JB'"JB'!J(prIhprIhjpIAalHRPiGR9dFR&aF("`F("`F("aFA&aFR*cG(4eGRC fGRCfGA9dFh*aF'pZEQeYE@aXE'aXDfYVE'aXE'aYE@eYE@eXE'aVDfTUD@KSCfG RCfGRCfGQC@9NC'4PC@CQCQGRCfKSD'PTDQYXE'eZEQp[F("aFA&bFR*cFh0cFh0 bFR&aF("[F("`F(&aFA&aFA&bFR0dG(9eGRCfGRCfGhKiHAPkHRPjHAKiGhGfGRC eGA9eGA9eGA4dG(0cFh0bFR*bFR*cFh0cFh0cG(4cFh0cFR*aFA"[EfjYE'YUDQP SD'GRCfKSD'PTD@TUD@PTD'GRCQ9PC@9PC'4NC'4PC@CQCfGSD'PTDQTUDQTTD@P SD'KSD'GRCfCQCQ9PC'0MBQ*LBQ*LBQ*LBQ*LBf0NC@9QCfKTDQYXE@eZEQp[F(& aFR*bFR&aF'pZEQeYE@eYE'aXDfYUDQPTD@PSD'KSD'KSD'GRCfGRCfGRCfKSD'K TD@PTDQTUDQTUDQPTD@PTDQTUDfYXE'eZEQj[Efp`F(&aFR*cG(4eGACfGRChGhG iH(PjHATkHRPjHAKiGhGhGhKiH(PjHATkHhYlHhamI(amHhYlHhYlHhYmI(amIAe qIhq!J)'"JB'"JS+#Ji1$Ji1%K)5&KB@'KSD'KSH(KiD'KB@%K)5%K)5%K)5&KBD (KiL*LBQ*LSU+LSU*LBQ)L)H(KiH(KiD'KSD(KiL)LBQ*LSU+LBQ*LBQ*L)L(KiD 'KB@%K)5%K)5%K)@&KB@&KSD'KSD'KS@&KBD'KSH(KiH)L)Q+Lib-M)b-LiZ,LSU +LSU+LSU+LSU+LSU+LiZ,LiZ,LiZ,LiZ,LiZ,LiZ,LiZ,M)b0MBf1MSk2Mj!!N!# 3!*'4NC+5Nj16P*58PC@9PC@9PC@@PTD@PTD@PjHAPjHAPjHAPTD9PC56Nj15Nj1 6Nj16Nj16Nj16P*58P*@9PC@9PC58P*58Nj15NT+4NC'4NC+5NT+5NT+5NT16Nj1 6Nj18P*59PC@9PC@9PC@9PC58P*16NT+4NC!!N!#3!)q3!*!!N!#3!*!!N!#3!*! !NC'4NT+5Nj16Nj58P*58PC@9PC@@PTDAPjHAQ*LAPjHAPjHAPTD@PC@9PCD@PjH AQ*LBQ*LAPjHAPTD@PTD9PC@9PC58P*58PC@8P*16NT'3!)q1MBb-LiU*L)H'KB5 %Ji1#JS+#JS+#JS+$Ji5%K)5%K)5%Ji1$Ji1$Ji1$Ji1$K)5&KBD(L)Q*LSU,Lib 0MBk1MSk1MSk1MBf0MBf0MBf0MBf0MBf0MBk1MSq2Mj!!N!#4NC'5NT+6NT+5NC' 4NC!!N!#4NC'4NT+5NT+5NT+4NC'3!*!!N!#3!*!!N!#3!)q2Miq2Miq2Miq2MSk 0MBb-M)b-LiZ,LSU*LBL)KiH'KSD'KSD'KiH(L)L*LBU,LiZ,M)Z,LiZ+LSU+LBQ )L)H'KB5$JB"rIRepI(YlHRPjH(KhGhGhGhGhGhGhGhGhGhGfGRChGhGhGhGhGhG hGhGfGRCfGA9eGA9dG(4dG(9eGA9eGA9eGA9eGA9dG(4cFh*bFR*bFR*cFh0dG(9 eGACfGhKiH(KiH(GhGhCfGR9eGA4eGA9eGA9eG(4cFh0cFh0cFh0cFh4dG(9eGAC fGhKiHAPkHRTkHRTjHAKiGhGhGhGhGhGiH(KjHAPjHAPjHAPjHAPjHAKiH(KiH(K iH(KjHATkHRTkHRTkHRTkHRPjHAPjHAKiGhGfGR9eGA9eGA9dG(4dG(4dGA9eGA9 eGA9eGA9eGA4dFh0bFR*aFA&aFA&aFA*bFR*bFR&aF'p[EQjYE@eYE'aXE'YVDfY VDfYXE'aXE'eYE@eYE@eYE'aXE'YVDfYVDQTTD'GRCQCPC@9PC@9QCQCRCfGSD'K SD'KSD'KSD'GRCfGQCQ9PC'4NBf4NC@9QCQGRCfKSD'PTD@TUDQTUDQTUDfYVDfY VDfYVDQTVDfYVE'aYEQp`F(&bFR0cFh0cFh0cFh0cFh0bFR*bFR*cFh0cG(4dGA9 eGRChGhKjHATkHRTkHAPiH(KhGhCfGRCfGRCeGA9dG(4dG(4dG(0cFh0bFR*bFA& aF("`F(&aFA&aFA&bFR*cFh4dG(4cFh0dG(4dG(4dG(9eGAChGhKiHATlHhamI(e pIAepIAamHhYlHRTkHRTkHRTkHRTkHRYlHhYlHhamI(alHhYlHhTkHRPjHAKiH(K iH(KiGhGhGhCfGhGhGhGhGhGhGhGhGhKiH(PjHAPjH(KiH(KiH(KiH(KiH(KjHAP kHRTlHhapIAjrIi#!JB'"JB'#JS+$Ji1$Ji1%K)5%K)1$Ji5%K)@&KSD'KiH(KiH (KSD&KB@&KB@&KB@&KB@&KSD'KSD&KB5%K)1$Ji1$Ji1$Ji5%KBD(L)L*LBU+LSZ ,LiZ,LiZ,LiZ,LiU+LSQ*LBQ)L)L)L)L)L)L(KiH(KiH(KiD'KSD&KB@&KBD'KiH (KiL)L)Q*LSZ,LiZ,LiZ,LiU+LSU+LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBU +LiZ,Lib-M)b-M)b,LiU+LBQ)L)L)KiH(KiD(KiL)LBQ+LSZ,Lib-MBf1MSq2N!# 3!*!!N!#3!*!!Miq2Miq2Miq2Mik1MSq2Mj!!N!#3!*!!N!#3!*!!N!#4NC'4NC' 4NC!!N!#3!)q2Miq1MSk1MBf-M)b-M)b0MBk1Mj!!NC'5Nj58PC@9PC@9PC@9PC@ @PTD@PTD@PTD@PTD@PjHAPjLBQCUDQTZER*bGRCfHRTkHRTkGRCfFR*bFR*bFR*b FR*ZEQjZDQTUCQCLBPjHAPTD@PT@9PC@9PC@9PC@@PTDAPjHBQ*LBQ*LBQ*HAPjH @PT@8P*15NT'4N!#3!*!!Miq2Mj!!N!#3!*!!NC'3!*!!N!#3!)q2Miq2Miq2Mik 1MSf-M)Z,LiZ,LSU+LSQ*L)L)L)L(KiH(KSD'KS@&KB@&K)5%K)5$Ji1$Ji1$Ji1 #JS+"JB'!J)#!J)#"JB'"JB'"JB'"JB#!J(prIhpqIRprIhprIi#!JB'#Ji1%K)5 %K)5%Ji+#JB#!IhpqIRjqIRjqIRjqIRprIi#!J)#"JB'"JB#!IhprIRjqIRjqIRj qIRjqIRjrIhq!J)#"JB'#JS+#Ji1$K)5$Ji1#JS+"J)"rIhpqIRjqIRjqIRjrIhp rIhprIhprIhq!J)#!J)#!J)#!J(prIRjqIRjqIRjqIRjqIRjqIRjqIhprIRjqIAe mI(amHhYkHRPjHAKiH(GhGRCfGRCfGR9eGA9eGA9eG(4dFh0bFR&aFA&aFA&aFA* bFA&aFR*bFh0cG(4dFh0cFh0cFh0cFh0cFh0cFh0dG(4dG(4cFh0cFh0cFh0bFR* bFR*aFA&`F'p[EfjZEQeYE@aXE'YVDfYVDfYVDfYVDfYUDQTUDQTUDfYVDfaVDfY UDQTUD@PTDQTUDQYVDfaXE@eZEQp[F("`FA&aFA&aFA&`F("`F("`FA&aFA*bFR* bFR*bFR*bFR*bFR*bFR*bFR*bFR*bFh0cFh4dG(4cFh0cFh0dG(9eGRChGhKiHAT kHRTkHAPjH(KiGhGhGhCfGA9dG(4dG(9eGA9eGRChGhKiH(KiH(KhGhGhGRCfGA9 dG(4dG(4dG(9eGAChGhKjHRTlI(apIAeqIRjqIAepIAamHhYkHRPiH(KiH(GhGhG fGRCfGRCfGRCfGR9eGA9eGA9eGA4dG(0cFh*bFR*bFR*aFA&aFA&aFA&aFA&aFA& bFR*bFh0dG(9eGA9eGA9eGA9eGA9dG(0cFR*bFA&aF("`F("aFA*bFh4dGA9fGRC hGhGhGhGhGhCfGA9eGA9eGRCfGRChGhGiH(KiH(KiH(KiHAPjHAPjHRTkHhamIAe qIRjrIhprJ)#!JB'"JB'"JB'#JS+$Ji1$K)5%K)5%K)5%K)5%K)5$Ji1$Ji1$Ji1 $K)5%K)5&KB@&KB@&KB@&KB5%K)5%Ji1$Ji1$JS+#JS+$Ji1$K)5&KB@'KSD(KiH )L)L)L)L)L)L)L)L)L)L)KiH(KiH(KSD'KS@&KB@&KB@&KB@&KB@&KB@&KB@%K)5 $Ji+#JS'"JB'"JB'"JB+$Ji5%K)5&KB@&KB@&KB@&KB5%K)1$Ji1$Ji5%Ji1$Ji1 $JS1$Ji1%K)5&KB@'KSD(KiH(KSD'KSD'KS@&KB@&KB@&KB@&KSD'KiH)L)Q*LBU +LSZ,LiZ,LiZ,M)b-MBf0MBk1MSk1MSk2Miq1MSk2Miq2Mj!!N!#3!*!!NC'4NT+ 5NT+5Nj+5NT'4NC!!N!#3!)q2Miq1MSk1MSk1Miq2Miq2Mj!!N!#3!*'4NC'4NC' 4N!#3!*!!N!#3!)q2Miq1MSk1MBf0MBf-M)b-M)b0MBf0MBf0MBf0MSk1MSk1MSf 0MBf0M)b-M)b-LiZ,LiZ,Lib-M)b0MBf1MSk1MSk1MBf0M)b,LiU+LSQ*LBQ)L)L )L)L)LBQ*LBU+LSU,Lib-M)f0MBf0M)b-M)b,LiZ,LiZ+LSU+LSU*LBQ*LBQ*LBQ )L)L)L)H(KSD&KB@&KB5%K)5%K)5%K)5%K)5%K)5%K)5%KB@&KB@'KSH(KiH)L)L (KiH'KSD'KB@&KB@&KB5%K)5%K)5%KB@&KB@'KSD'KSD'KS@&KB@%K)5$Ji1#JS' "JB'!J)#"JB'"JS+#Ji1%K)@&KBD'KS@&KB@&KB@&KB@&KB@&KB@'KS@&KB@'KSD 'KSD'KiH(KiL)L)L)L)L)L)L)L)H(KiH(KSD'KSD'KSD'KB@&KB@&KB@&KB@&KB@ %K)5$Ji+"JB#!IhpqIRjpIAemI(amI(amI(YlHhYlHhYlHhYmI(amHhYkHRTjHAP jHAKiGhGfGR9eGA4dFh0cFR*bFR*bFR0cFh0dG(9eGRCfGRCfGRCfGRChGhGhH(K iHAPjHAPjHAPiH(KiH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAPjH(KhGhCfGRCfGRC hGhGhH(KiH(PjHAPjHAPjHRTkHhYmI(epIAepIRjqIAepI(YlHRPiH(KhGhGfGRC fGRGhGhKiH(KiH(KiH(KiGhGfGR9eG(4dG(0cFh0cG(4dGA9eGRCfGhGhGhGhGhC fGRCfGA9eG(4dG(4dG(4dG(4dG(4dFh0cFh0bFR*bFR*cFh0cFh4dG(4dGA9eGA9 fGRCfGRCfGRCfGRCfGR9eGA9dG(4dG(4cFh0dG(4dG(4dFh0cFh*bFA&`F("`F(" `F("`F("`FA&bFR*cFh0dG(4dG(4dFh0cFh0cFh0cFh0cFh0dG(4dG(4dG(0cFh0 cFR*bFR*cFh0cFh0cFh0cG(4dG(9eGA9eGA9eGRCfGRCfGRGhGhGhH(KiH(KjHAP kHRTlHhYmI(amI(epIAepIAepIAemI(YlHRTkHAPjHAPjHAPkHRTkHRTkHRPjHAP iH(GhGRCfGRCfGRChGhGiH(KjHATkHhYmI(apIAeqIRjqIRjpIAepIAepI(amI(a lHhYlHhYkHRTkHRTkHRTkHRTkHRYlHhYlHhYmI(amI(YlHhTkHRPjHAPiH(KjHAP kHRYlI(amIAeqIRprIi#!J)#!J)#!JB'"JB+#JS+#JS+#JS+#JB'"JB'#JS+$Ji1 %K)5%K)@&KBD'KSD'KSH(KiH(KiH(KiH(KiH(KiH(KSD'KSD'KSD'KSD'KSD(KiH (KiH(KiH(KiH(KiL)L)L)LBQ*LBQ+LSU,LiZ,LiZ+LSU+LBQ*LBL)L)L)L)L)LBQ *L)L)L)L)L)L)L)L*LBQ*LBU+LSU+LSU*LBQ*L)L)L)H(KiH(KiL)L)L)LBQ*LBQ +LSU+LSU+LSQ*L)L(KiD'KS@'KSD'KSD(KiH(KiH(KiH(KiH)L)L)L)L(KiH(KiH (KiL)L)L)L)L)L)Q*LBU*LBQ)L)L(KiH'KSD'KSD'KSD'KS@&KB@&KB@%K)5%K)5 %Ji1$Ji1%K)5&KB@'KSH(L)L)L)L)L)L)L)L)L)H(KiH(KiD'KSD'KSD'KiH(KiH (L)L)L)L)LBQ*LBQ*LBQ*LSU+LiZ,M)b0MBf0MSk1MSk1MSf0MBb-M)b-M)b-M)b 0MBf0MBk1MSk2Miq3!*!!N!#3!*!!N!#3!*!!N!#2Miq2Miq2Miq2MSk1MSk0MBf 0MBf0MBb-M)b-M)b-M)b-M)Z,LiU+LSQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBL)L)L (KiH'KSD'KB@&KB@&KB@&K)5%K)5%K)5%K)5%K)5%K)1$Ji1#JS+#JB'"JB'"JS+ #JS+$Ji1%K)5%K)5%K)1$JS+#JB'"JB'!J)#!J)#!J)#!J)#!J)"rIhprIhprIhj qIRjqIRjpIAepIAemI(amI(amI(amI(amI(amIAepIAjqIRjqIhprIhprIhprIhp rIhjqIRjqIRjpIAepIAepIAepIAepIRjqIRjqIRprIhprIRjqIRjqIRjqIRjqIRj qIhprJ)#!J)#"JB'#JS+#Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$JS+#JS'"JB'!J)#!J)# !J)#!IhprIhjqIRjpIAepIAepI(amHhYlHRTkHAPkHRTkHRTkHRYlHhTkHRTjHAP jH(KiH(KhGhGhGRCfGR9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA9eGA4dG(4 dG(4cFh0cFh0dG(4dG(4dG(4dG(4dG(4dGA9eGACfGRCfGRCfGRCfGA9eG(4dFh0 cFh0cG(4dGA9fGRChGhGhGhGhGRCfGRCfGRCfGA9fGRCfGRCfGRGhGhGhGhGiH(K iH(KhGhGhGhGhGRCfGRCfGR9eG(4dG(0cFh0cFh*bFR*bFR*cFh0cFh0cFh4dG(4 dG(4cFh0cFh0cFh0cG(4eGA9fGRChGhGhGhKiH(KiH(KiH(PjHAPjHAPjH(KiH(K iH(GhGhGhGhGhGhGhGhGhH(KiH(KiH(KiHAPjHAPjHAPiH(KiGhGhGRCfGRChGhG hH(KiH(PjHAPkHAPjHAKiH(KhGhGhGhCfGRChGhGhGhGhH(KiH(KiH(KiH(KiH(P jHRTlHhamI(epIAepIAepIAepI(amI(amIAepIAepIRjqIhprIhprIhprIi#!J)" rIhprIhprIhprIhpqIRjqIRprIhprJ)#!JB'#JS1$Ji1$Ji1%K)5%K)5%K)1$Ji+ #JS+#JS+#JS+#JS+#JS+$Ji1$Ji1$Ji1$K)5%K)5%K)5%K)5%K)5$K)5%K)5%KB@ &KB@&KB@&KBD'KSD(KiH(KSD'KS@&KB@&KB@%K)5%K)5%K)5%K)5%K)5%K)5%K)5 %K)5$Ji1$Ji1$Ji1$Ji1%K)5%K)5%K)5%K)@&KBD(KiL)L)Q*LBU+LSU+LSU+LSU +LBQ*L)L)L)L)L)L)L)L)L)L)L)L)L)L(KiH'KSD'KB@&K)5%K)5$Ji1$Ji1$Ji1 $Ji1$K)5%K)5%K)5&KB@&KB@&KB@%K)5%K)5%K)1$Ji1$Ji1$Ji1$K)5%K)5%K)@ &KB@&KB@&KB@%K)5%K)5$Ji1$Ji1%K)5%K)@&KBD'KSD(KiH(L)L)L)H(KiH(KiH (KSD'KSD'KSD(KiH(L)L)L)L)L)L)L)L(KiH(KiH(KiH)L)L)LBQ*LBQ*LBQ*LBQ *LBQ*LBQ)L)L(KiH(KiD'KSD'KB@&KB@&KB@&KB@&KBD'KSD(KiH)L)L*LBQ*LBQ *LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LSU+LBQ*LBL)L)L)KiH(KiD'KSD'KiH(KiL)L)L )L)H(KiH(KiH(KSD'KSD'KSD'KSH(KiH(KiH(L)L)KiH(KiH(KSD'KSD'KSD&KB@ &K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5$Ji1#JS+#JS'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'"J)#!J)#!IhprIhprIhq!J)#!J)#!J)#"JB' "JB'"JB'"JB'"JB+#JS+#JS+#JS+#JS+#JB'"JB#!J)#!IhprIhprIhq!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)'"JB'"J)#!J)"rIhpqIRjpIAepIAepI(a mI(amI(amI(amI(amI(amI(amHhYlHhYlHRTkHRTkHAPjHAPjHAPjHRTkHRTkHRT jHRTkHRTkHAPjHAPiH(KiH(KhGhGhGhGiH(KiH(KiH(KiH(KiH(KiH(KiGhGhGhG hGhGhGhGhGhKiH(KiHAPjHAPjHAPjHAKiH(GhGhGfGRCfGA9eGA9fGRCfGhGhGhG hH(KiH(PjHAPjHAPkHRTkHRTjHAPjHAPjHAPiH(KiH(PjHAPjHAPjHAPkHRTkHRT kHhYlHhYlHhYlHhYkHRTkHRTjHAPjH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAPjHAP jH(KiH(KiH(KhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhGhKiH(K iH(KiH(KiHAPjHATkHRYlHhYmI(amHhYlHhYlHhYlHhYlHRTkHRTkHRTkHRTkHRY lHhYkHRTkHRTlHhYlHhYlHhamI(amI(amI(amI(amI(amHhamI(amI(alHhamI(a mI(alHhYlHhTkHRTkHRPjHAPjHATkHRTkHRTkHhYlHhYmI(amI(amI(amI(amI(a mI(amI(amI(amIAepIAepIAeqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIAepIAe pIAepIAepIAepIAeqIRjqIRjqIRprIhprIhprIhprIhprIRjqIRjpIAepI(amI(Y lHhYlHhTkHRTkHRTlHhYlHhYlHhYlI(amI(amI(apIAepIRjqIRjqIRjqIhprIhp qIRjqIRjqIRjqIhprIhq!J)#!J)#"JB'"JB'"JB'"JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JS+#JS+$Ji1$Ji5%K)5%K)@&KB@&KB@'KSD'KS@&KB@&KB@&KB@&KB@&KBD 'KSD'KSD'KB@&KB@&KSD'KSD'KSH(KiH(L)L)L)L)L)L)LBQ*LBQ*LBU+LSU+LSU +LSU+LiZ+LSU+LSU+LSU*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBQ*LBL)L)L )L)H(KiH(KSD'KSH(KiH(L)L)L)L*LBQ*LBQ*LBQ*LBQ*LBL)L)H(KiH(KSD'KSD 'KB@&KB@&KBD'KSD'KSD(KiH(KiH(KiH(KiH'KSD'KS@&KB@%K)5%K)5%K)5%K)5 %K)5%K)5%K)1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji5%K)5 %K)5%KB@&KB@&KB@'KSD'KSD'KiH(KiH(KiH(KiH(KiH(L)L)L)L)L)L)L)L)L)L )L)L)L)L)L)L)L)L)L)H(L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L)L )L)L)KiH(KiH(KiH(KSD'KSD'KS@&KB@&KB@&K)5%K)5%K)1$Ji1$JS+#JS+"JB' "JB#!J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhpqIRjqIRjqIRe pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAjqIRepIAepIAepIAepIAepIAe pIAepIAepIAepIAepIAepI(amI(amI(YlHhYlHhYlHhYlHhYlHhYlHhYlHhYlHhY lHhYlHhYlHhYkHRTkHRTkHAPjHAPjHAPjHATkHRTkHRYlHhYlHhYlHhYlHhYlHhY lHhamI(amI(amI(amI(amI(amI(amHhYlHhYlHhamI(amI(amIAepIAepIAepIAe pI(amI(amI(amI(amI(amI(YlHhYlHhYlHhYlHhYlHhYlHhYlHhamI(amI(amI(a mI(amHhYlHhYlHRTkHRTkHRPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPjHAPiH(K iH(KiH(KiH(KiHAPjHAPjHAPjHAPjH(KiH(KiH(KiH(KiH(KiH(PjHAPjHAPjHAP jHRTkHRTkHRTkHRTkHRPjHAPjHAKiH(KiH(KiH(KiH(KiH(PjHAPkHRTlHhYlHhY lHhYlHhYlHhYlHhYlHhYlHhYmI(amI(amI(amI(alHhYlHhYlHhamI(amI(amI(a mI(amI(epIAamI(amI(amI(amI(amI(amI(amIAepIAepIAepIAepIAepIRjqIRj qIRjqIhprIhprIhprIhq!J)#!J)#"JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)# !IhprIhprIhprIhprIhprIhprIhprIRjqIRjqIRjqIRjqIRjpIAepIAepIAepIAe mI(amI(amI(amI(amI(amI(epIAepIAepIAepIAepIAepIAepIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRprIhprIhprIhprJ)#!J)#"JB'"JB'"JB'"JB+#JS+#JS+"JB' "JB'"JB'"JB'!J)#"JB'"JB'"JB'"JS+#JS+#JS+#JS+#JS+"JB'"JB'"JB+#JS+ #JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JB'"JB'"JB'"JB'"JB'"JB' "JS+#JS+#JS1$Ji1$K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5%K)5 %K)5%K)5%K)5%K)5%K)5%K)@&KB@&KB@&KB@&KB@%K)5%K)5%K)5%K)5%K)5%K)5 %K)5%K)5%K)5%K)5%K)5%K)5%K)1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1 $Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+#JS+#JS+#JS+#Ji1$Ji1$Ji1 $Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$JS+#JS+#JS+ #JS+"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1$Ji1#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS1$Ji1$Ji1$Ji1$Ji1$Ji+ #JS+#JS+#JS+#JS+"JB+"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB#!J)#!J)#!J)#!J)#!J(prIhprIhprIhprIhprIhprJ)# !J)#!J)#!IhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)#!J(p rIhprIhprIhprIhprIhprIhprIhprIhprIhprJ(prIhprIhprIhprIhpqIRjqIRj qIRepIAepIAepIAepIAepIAepI(amI(amI(amI(amI(amI(amI(alHhYlHhYlHhY lHhamI(amI(amI(amI(amI(amI(amI(amI(amI(amI(amI(epIAepIAepIAepIAe pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAamI(a mI(amI(amI(amI(amI(apIAepIAepIAepIAepIAepIAepIAemI(amI(amI(amI(a mI(amI(epIAepIAepIAepIAepIAemI(amI(amI(amI(amI(amI(amI(amI(amI(a lHhYlHhYlHhYlHhYlHhYlHhYlHhYlHhYmI(amI(amI(amI(apIAamI(amI(amI(e pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAepIAe pIAepIAepIAepIAepIAepIAepIAepIAepIAepIAeqIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRjqIhprIhprIhprIhprIhprIhprIhprIhprIhprIhq!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#"JB'"JB'"JB'"JB'"JB'"J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JS+#JS+#JS+#JS+#JS+"JB'"JB'"JB'#JS+#JS+#JS+#JS+#JS+#JS+#JS+ #JS+#JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "JB'"JB'"JB'"JB'"JB'"JB'!J)#!J)#!J)#"JB'!J)#!J)#!J)#!J)#!J)#!JB' "JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB'"JB' "J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRjqIRj qIRjqIRjrIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhprIhp rIhprIhprIhprIhprIhprIhprIhq!J)#!IhprIhprIhprIhprIhprIhprIhq!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J!!!0%!!!3!"!!8 !!!#J!!'!83!!!!!!&!!!!!!!!$3@9Zk,S`!!0"3!!$39!$b!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!IhprIi#!JB+#JS+#JS+#JS+"JS+"J)#!IhjqIi#!JB+#Ji1$K)5 'LBf2N!#3!)Z$H@eLA&YEA@*UFhb"K)5$J(elHRPiH(PmIi'#JB#!JB'!IhprIi# "Ji5$JS'"JB+#JS+#JS1$JS'!IhjqIAepIS##K)D)LSk8Q*UDQC@3!)Z%Hh"M9e* 59epSFAKmIAPaD@0KBQG`Ghb!JS1&KiH&K)5%Ji+!J)'$KSH(KS@%Ji1&KiL(KS@ %JS'"J(pqIRjqIi##Ji5(LSb-LiZ-Mj+9Q*UCPj@6N!#-K(KS9$md0$8j490MFRb "J(elHRKfGRKlJ)@,M)U'K)+!J)#!JS5&KiQ+LSU*L)D%Ji1$Ji+#JB'"IhprIhq "Ji@(LBZ0MSk-LiU+MC'9QTfIS++HNAjM5$-S*b`e2dG199aQFAKmIRelHAGjJSf 8PT52LBD'KSH*LSQ)Ki@&KiL)KS5$JS+#K)D)L)D&K)1#JB'"JS1%KBD(KiH)LSb 1MT!!NjQJTULSTCq4Hf&)0#NP*#3V1%C2@@GfI(eqJS1"Ii'*NTH9MiZ,LSL(KSD (L)D%K)D)LBL(KiD&Ji5(LSb,LSL'Ji"pHRTmIS'$KBL+LiZ+LSU,MBk3!*1AR+' RUkQDJ@4*-b)A$J`B+cpAFB5-N!#3!)k*JRamJSb8Pj+1LiH"Ii##JS'"J)''LSk 2MSb*Ki@#JiD)KiH(Ki@%JRppIAamIAq$KiU-M)Z+LBL)Lj'ARD1RV+kSPATC04S 1$K3L08GCEi1,M)U(KB*lGRL!M*@AP)q+K(epIi'#JS1%L)b1MSk1M)Q&JB#"KBH )LBQ)KB*pHAKhH(PmJB@*Lib-LiU)L)Q-NTUKTkkbVU+,ENmc(J`!"4Nd9hQ2QCH -JAalH(9fIBD1NC!!Mib(JhprJ)"qIAq%Lj!!NT+3!)f*KS5$Ji@)LBL(KS5#IRT iGhCfHAq&Liq4NC!!M)Q(KSH,NCHESUQXTT9pAd)S&!S2)$TCH)kAPSf#HRCdFA& iJSZ4PC53!)Z%IhepIAapJ)@+MT+8PC12LSD#J)'%KiL)L)H&JRjlGh9dGRZ!KBQ 0N!#4Mib*KiH+Mj5DSDHUU*k,F&8p*a!###0(EBUCR*1(I(GeFh&cHi5,MT!!Mif ,Ki*rIRjpIS+(M*!!Nj@@Nik*KB'!JB5'KiH(KS1!HhKfG(4hI)+)MC!!NC!!MSU )KiQ0NTLGSUDNQiPa@%!V&``9-&"[KjDBN!#%HhCdF@pbHS1,Mj'5NBk*Ji#!Ihe qJBD-N!#8PTD8MiU'JS#!JS5'KSD&Ji"pHACdFh9kJ)D-NC16NBk-LiZ1NC@DRU' IPiG`9$SX+#FR,N*KIC!!PT''IAKfG(*bH)+0P*@5M)L&K)1#J(jrJBD,Mj1@Q*H 6M)D"IRq#K)@&KB5$JAjlH(GhH(TrK)U1NC'3!)k,LBQ,Mj1BRD#KQieiB8Xe)43 4(MjQKCLGPSU!HRGdFR4jJ)H0NC+4N!#1LSD$IhamIi@+Mj1@PjD6MSQ&JB#!JS+ #Ji5&Ji&qHRGfGhTrK)Q1NC+5Mif,LSZ-N!#@QjkIQiplBdXf*KX9(6TKJTDFQ)k &IAPeFh0iJ)L1NC'2MBf-LSD#IheqJiL0NC@@PT11LB@#JB+#JS+$K)5$JAjkGh9 eGhb$LSk4Nj+2MBb-MBq4P*QGRjZ1HQ0+0#FH'#!kAS#@RTU3!)CrHhGeG(GqKSb 2Miq1MSf,Ki*qHhb"KSZ2NjDAP)q+KS1#Ji1#JS+#JS+"IhajGhGjIB'(MC!!NT+ 2M)Z,MBq5PTZHRjb4IfP41bJB$"3hBS1BRjQ2Ki&pHACfHAq'LSf0MBk2MSZ(JAe mIB#&LSk5P*55MSU(KB1#JB#!J)+$Ji+!IATiGhKlJBH,MT!!Mik-Lib0MT!!Nj@ CQjL2J'a@3#iI&4`mC)@CRjQ2KRpkH(9eH(q'LSb-M)f1MBU'JAemIB'&LBf4Nj1 5MSU(KB1#J(prJ)'#JS&rI(ThGhPmJBH-MT!!Mik-LSQ,MC'6PCLCPSk!E9G#-5) A(cpQKjUHQ)k'J(ekGh9iIS5*M)f0MBk0LS@"IReqJ)5)M*!!NT14MSU(KB1#JB# !J)'#JS&rIAYjHAPmJBH,MSk1MBZ*LBU0NC@AQCQAMi&Z@83b)48I3'L*QTfAMSD !I(KfGRPrKBU0MBf0MSf+KB&pHharK)L-N!#6Nj'1LSH&Ji'!Ihq!JB+$JS"qHhP iHAb"KSU0MSf-LiQ*LSb2NjDAQ*H2JR&F4c)I&L4)EifERCD0KS"mHAKiHRk$KiU ,M)f2MSU&J(emIB#%L)Z2NC+3!)f+Ki@$JB"rIi##JS+#J(elHAKjI)+'LSb0MBZ +LBL*M)q6PTHAPBq%Fej*-ad6*NphNCZDNiZ&IhYkHATmIi1(LBU-MSq1LB0qI(a pJ)5)M)q4NBq0LSL'Ji"qIRq!JS1$JB"pHRKhHAb"KSU,M)b,LBL)LBZ0NC5@PT5 2K(9K5M)G&La@Hj'EQC+,KAplHAPjHhk"KBL+M)k2MSQ%IhYkI)#$KSU1NC'2MBU )KS1!IReqJ)'#JS+!IATiGhPmJBD*Lib-LiQ)L)Q+MC!!Nj59P)q%G'"*-"`C-Pf !P*UAN!#+K(jlHRTkI(k"K)H*Lik3!)k*K(pmI(f!JiD+MT'4Mif,LBD$J(jqIS# "JB+"IhekH(KjIB+'LSb-M)Z*L)L*Lik4Nj@9NSb"F9a&,4XG2'D&PTU8MSL#IAY kHRYmIS'%KSL,MT!!MSQ%IhepIS#$KSU1NC!!MSf,LBH$IhepIRq!JB'"IhakH(K jIB+'LBZ,LiU*LBQ+M)q4NT58Nib!EPK!+"JK4h#,PjL6MBH"IAYlHhapIi'$KSL ,Mj!!MSQ%J(jqIi#$KiZ1N!#2MSf-LSH$J(jqIRq!JB'"IhekH(PlIS1(LBU,LiU *LBQ+M)q4Nj56N!#)HfK51L-A,&GlNCQ@MiU&IhYkHhapIRq"Ji@(Lik2MBL$J(p rJ)'$KiZ1Miq0M)b+Ki1!IRjqIhq!J)"rIATiHAZ!K)H*LSU+LBL)LBb1N!#4NT+ 4MS9hC8ie(KNhBi18Q*50L)0pHRYmIAjrJ)'#K)D+MBk-L)1"J)#!JB5)M)f1MBb -LiQ'Ji"rIRjrIi#!J(pmHRPkIB'&KiL*LSQ*L)L+M)q5NT'4MiTrEeP#+KNQ6hD 0Q*H3!)U&J(akHhaqIi#!JB+%KiZ0M)U'Ji+"JB'#KBQ-MBf-M)b,LBD#J(pqIRj qIRprIAYjHAb!K)D)LBQ*LBL)LBZ1NC+5NBq-KAPS8MSN($9IJ*+BP)f(JRekHha qJ)#!JB'#JiD+M)U(KB1$Ji1#JiD+M)f-M)b-LiQ&JS"rIRjqIRjqIRekHAYqJSD (L)L)L)L)L)U-Mj'5NT+3!)Z#G&p(,"JK5A',Q*L4LS@!HhTmIRq"JB'"JB+&L)U ,LBD%Ji1$Ji1&L)Z-M)Z,M)Z+Ki5#J(prIhprIRjpI(PjI)#%KiL*LBL)L)L*LSf 2N!#4NC'0KhYU8cSM(6GKJC5CNib'JAekHRarJB+#JS'"JS@)LSQ(KB5%K)5$K)D *M)b-LiZ-LiQ'K)+"IhprIRepIAakHATqJiH)LBQ)L)H(L)Q-Mj'4NT'2LS"aA88 X'LC1GBkCPiq)JhjkHAYpJB1$JS+"JB+&KiL(KB5%KB@%K)@)Lif-LiZ,LiZ*KS5 $JAprIRepI(YkHAPmJB@)LBU*L)H(KiL+MC!!NC+4MiZ%HQP814dB1'@'PjU6Li9 rHRKjI(q#K)5$JB'"Ji@(KS@%K)5&KB5%KSQ-M)U+LiZ,LSH&K)1"IhjqIAemHhP jHRq$KiQ+LSQ(KiH'L)U1N!#4N!#3!)k)Ih&G45F9+eTqP*Z@MBH"I(PiHRf"K)@ %JS'"JS5'KS5$Ji5&KB@&KSL+LiU*LSZ,LSL'KB5#J(jqIAamHhPiHAb"KBL+LiU )KiD'KiQ0N!#4N!#2MBU$GfC40"SK5R11QjQ3!)Q$I(KhHAYrJiD'Ji'"JB1&KB5 $Ji5&KSD'KSH*LiZ+LBU,LiQ(KSD&Ji"qIRemHhPhH(Z!K)H*LiZ*KiD'KSL,MT! !N!#3!)k,KRaX9MNH(d*XLCLDNSU%IAKfH(TqJS@'K)+"JS1%K)1#JS+%KSD'KSD )LSZ+LBU+LSQ(KB@'KB&rIRemHhPiH(TqJSD)LSZ,LBH'KSH+MT!!NC'2M)GrF&a "*4`hBB+@Qj@0KRpjGRGjI)#%KSD%JS+#Ji1#JB'#K)D(KiH'L)U,LiU*LSU*L)H 'KiH%JAjpI(YjGhCjIB'&KiQ,LiQ(KSD'LBb3!*'3!)q-L)*hC%XU&LP@Hj+FQ)q )JATfGRKlIi1&KS@$JS+#Ji+"J)'$KBH(KiD(LBZ+LBQ*LBQ)KiD(L)D$J(ppHhP hGRGlJ)5'L)Z-LiL(KS@(Lik3!*'3!)k*JRPT9$8C)%TcMTbENiZ%I(CeGhTqJS@ (KS5#JB'#JS#!JB+&KiH(KSH*LSZ+L)L*L)L(KSH*L)@"IhemHRKfGhTrJi@(LSb -LSL'KSH+MBq2Mik+JhYY@MmL'caTLCUGPSf'IAGdGRPpJB@(L)D%JS'"JB"rIi+ %KiL(KiH)LSZ+LBQ*L)H'KSH*LSH$J(jpHhKfGAKpJB@(LBb-LSL'KBD*M)k2N!# 2M)CrFf*++aJY@i#@RTQ2L)&jG(9iI(q%KiL(KB1"JB'!Ihq"Ji@(KiH(L)U-LiQ *L)L(KS@'LBZ+KS&rIRakGR4fHi#%KSL+M)b,LBH'KiZ0Mj!!MSb)J(9N6M!A*&& lNjkFNiU$HR4cGRTqJSD)L)D%JS'"J(jqJ)+&KiH(KiL+M)b+L)L)KS@&KBL,LiH $J(jpHRGdGAPqJS@(LSb0M)U)KSD*M)k2Mif*JhPV9c`J($pYLjZHPBb&IA9bG(K pJB@)LBL&JS#!J(pqIi'%KSH(KiH*Lib,LBL)KiD%K)H,M)U%J(pqI(PeG(GmJB5 'LBZ-M)Z*L)H*M)k2Mik+K(YY@6iK'$CQLCZIQ)q)IhGcFhGlJ)5)LBQ'Ji'!J(p qIS#%KSH(KiH)Lib,LBL)Ki@%K)@*M)Z'JRpqI(TfG(ClJ)1&L)U-M)Z*L)H)LSk 3!)q1LS9qFQ&+,4ST9Ab9RjZ5LS*jFh*eHRq$KiQ*Ki@#J)"rIRk!JiD)L)H(L)Z 0M)U)L)H'KB5&LBb-LB5!IhekGh9eHAk#KBH+M)b,LSQ)L)U0Mj!!Mib)JAGP6M! @(8ThNTqHPBb&I(9cG(KpJSD)LBL'Ji'!IhjqIi+&KiH(KiL*M)b+L)L)KS@%K)H ,MBU&JApqI(PfGAKpJB5'LBZ,LiU*KiH*MBq3!)q0L)&iDPBq*"ilD)QERTL2Khp fFR0fHi#&L)U*Ki5"J(pqIRq"K)D(KiH(LBb0LiQ)L)H&Ji1'LSf-Ki1!IhekGh9 hI)#$KBL+LiZ+LSQ)LSb2NC!!MSU$HQaB3#BD-@#&QU#DNBQ"H(0cGAPqJiH+LSL &JS"rIReqJ)1'KiH'KiQ,MBb+L)L(KB1$KBQ0MBL$J(jpHhKfGRYrJS5'LBZ,LSQ *L)Q,MT!!NC!!M)9pF&j),KSP6hU8Rjf8Li4lGA*dH(f"KSQ+LBD$JB"rIAk!JS@ (KiD(L)U-M)U)KiH'KB5%Kib0LS@"IhjmHAChHRk#K)D)LSU+LSQ*LBZ1NC'3!)f )J(9N6M8F(%*aMjkIPSk(IRCbFhGlJ)@*LiQ(Ji'!IhjpIi+%KiH'KSH+M)b,LBL (KS@%K)D+MBZ'JS"qIAThGRKpJB1&L)U,LSQ*LBQ+MC!!NC!!MiZ%HQY@2#%@-Q+ (R+'CN!#*J(KcFhCkIi1(LSZ)K)+!J(jpIS#$KSH'KSH*M)f-LBH(KS@&K)@*MBf )Ji"rIAYhGRKpJB1%KiQ,LiU*L)Q+M*!!NC'2Li4lEPY%+4JT9hqAS*b5LS0kG(0 eHAf#KSU,LB@$JB"rIRk!Ji@(KiD(L)Z0M)U)KiH'KB5&L)b0LS5!IhjmH(ChHi# $KBD)LSU+LBQ+LSb2NC'3!)f'IR&J5M%E)%KfNTqIPBb&I(9bG(KmJ)@*LiQ(Ji' !IhepIi+&KiH'KSL,MBf+L)H'KB@%KBL,M)U&JApqI(PhGhTrJS1&L)U,LSQ*LBQ ,Mj'4N!#0L)"dBdie("Y!EifGS*H1KhphFh0fHRk%L)U+L)@#J)"qIAk"K)H(KiD (LBb0LiQ(KiD&K)@(LSb,Ki*rIRekGhGkIS+%KBH*LSU*LBQ*Lik3!*'3!)k*JRK T96`K&c0MKjZKQT!!LB&jG(0fHAk#KSQ+L)D$JB"rIAk!JiD(KiD'L)Z-LiQ(KiD &K)@'LBb-L)1!IRelH(CjIS+%KBH*LSU+LBQ*LSb1N!#3!)q+JhPX@%!P'#jGJjQ JQj+,JhTdFh9iIB'&LBU*KS1"J(ppIAq#KBL)KiH)LSb-LSL(KS@%K)D)M)f+KB& qIAYiGhKpJB5&KSL+LSQ*LBQ+M)k3!*!!Mib'I'pF45SB*P0mPD#GP)b&I(CcG(K mJ)@*LSU(K)+!IhemIS+&L)L)KiL+M)f,L)H'KB5%KBH,MBZ'JRpqI(PhH(b"Ji5 &KiQ+LBQ*LBU-MT!!NC!!MBGpF&j),KJK6(L6S*k9MSGqGR0dGhYrK)L+LSL&JS" rIAeqJB5(L)L(L)U-M)U)KiD&K)5&KiZ0M)L$IhjmHAGhHi#$K)@(LBU+LBQ*LSZ 0MT!!N!#1L)"cBN`b'Ke%FSqIS*D1L(phFh0fHRk#KSQ+L)D$JAppI(f!JiD)KiH (LBZ-LiQ(KS@%K)5'LSf-L)5!IRakH(GkIi1&KBD)LBQ*LBQ*Lif2N!#3!)k+JRG R86BD&ceYMCfJQ*!!LB&iFh0eHAk#KSQ+LBH$JAppI(erJSD(KiH(LBZ-LiQ)Ki@ %Ji1&LBb0LS@"IRelH(GjIS+&KB@(LBQ*LBQ*Lib1Mj!!MSQ#GfP925)E1@H*Qk# CN!#+JRPdFR4iIB'&L)U*Ki5"IhemI(q#KBH)KiH)Lib-LSL(KS5$Ji@)M)f,KS* rIAYiGhPqJi@&KSL+LSQ*LBQ+Lif2N!#2M)9kE&P"*4J`B)@DSCU5Li4kG(*dH(b "KBL+LBL&JS"qI(aqJS@(L)H(L)Z-M)U)KiD%Ji1%KiZ0M)L$IhjmHAGiIB'%KB@ (LBU*LBQ*Lib1Miq1Li4jE&Y&+aXX@(q@S*b6MBCpGR0cGRZ!K)H*LSL&JS"qI(a qJB@(L)L(L)U-MBZ*KiD%Ji1$KSU0M)Q%J(jmHAGhHi#%KB@(LBQ*LBQ*LSb0MT! !Mib(IA"I55dB*&"kP+#GP)k(IRCbFR9kIi1(LBU)KS1!IRalIB'%KiL)KiL+M)b ,LBH'KB1$Ji@+MBf*KB&rIAThGhU!Ji@&KiL*LBQ*LBU,MBk3!*!!MSKrFf*0-KS I4h54Rjq@MiKrGh*bGAPqJSD*LSQ(K)&qI(YpJ)1'L)L(KiQ-MBb*KiD&Ji+#KBQ 0MBU'JRppHhKfHAk$KSD'L)Q*L)L)LBU-MT!!NBk*JACR8cNG'$YVM*fJQ*!!LS* jG(0eHAk#KSL*LBH%JApmHhf!JiD(KiH(LBZ0M)Q(KS@$JS+%L)b0LiD#IhelH(C iIB+&KSD)LSU*L)L*LSb1N!#4MiU#H'P@25)C0Q5(Qk#CNBZ$HR4bG(KpJB@)LBQ )KB*rIAYpIi+&KiL(KiQ,MBf,L)D&K)1#JiL-MSZ(Ji"qHhKfGhb#KBD'L)Q*LBL )L)Q,MBq4N!#-KRaZA%3Q&#TDJCLKR*+-KAaeFh4hI)'&KiQ*Ki5#J(emI(q#KBH (KiH)LSb0LiL(KS5$JS+'Lif-L)5"IhajGRGmJB5'KSH*LBQ)L)L*Lif2NC!!MBC qFQ"+,aNM6RQ6Rjf8MSGqGR0cGRYrJiH*LBL&JS"qI(aqJB5'KiH(L)U-MBZ)KiD %Ji+#KBU0M)L%JAppHRCfHAq%KSD(LBU*L)L)LBU-Mj'4MSQ"G'01-KNF4A13!*k IPSk*J(KdFh9jIi1(LBQ)KB1!IRemIS'%KSH(KiH*M)f-LBH'K)1#JS@*MBf*KB& rIAThGRKqK)D'KiL+LBL)L)L+M)k3!*!!MSU$H@T@2"mA1'H*R+#BMiU#HA4cGAP qJSD)LBL&Ji&rIAeqJ)1&KiH'KiQ,MBb*KiD&K)1#K)L-MBU'JS"qHhGeH(f$KSD 'L)Q*L)L(L)Q,MT!!N!#2M)CpF&e%*43X@i+BS*U4Li9lGA0dH(f"KBH*LBD$JB" qIAerJS@'KiH(L)Z0MBU(KS@$JS+$L)b0LiH$JApmH(ChI)'&KSH)LSU*L)L)L)U -Mj'3!)f'IA&J5LmD*P&kP*qFNif'IACcG(GmJ)5(LBQ(K)+!IRepIi+&KSH(KSH +M)f,L)D&K)1#JiD,MBZ(K)&qI(PfGhZ!KBD'L)U+LBL)KiH*M)q4N!#0L)"fCe- j(Ka"ESfHRjD1L(piG(4hHi#%KSL*Ki5#J(pqIAq"JiD(KiH(LBb0LiL'KB5$JS+ 'LSf-L)5"IhekGhCjIS1'KSH*LSQ*L)L*LSf2N!#3!)k*JACR86BG(%"VLTbIPiq *JRTeFh9kIi1'L)Q)KB+!IhjpIi'%KSH(KiH*Lif,L)D&K)1$JS@+MBf*KB&rIAY hGRKqJiD'KiL+LSQ)KiH)Lik3!*!!MiZ%I'pG45F@+eU!Pk#ENBZ%Hh9cGAPqJSD )LBL&JS"rIRjqJ)+&KiH'KSL,MBb*KiD&Ji1$K)Q0MBU'JS"qHhKfGhb"KBD'L)U +LBL(KiL+MT!!NC!!MBGrFPp'*a)P9Ak@S*b5M)9pGh4eH(f"KBH*LBD$JB"qIAk !JS@(KiH(L)U-M)Q(KB@%Ji+%L)b1LiH$J(jmHACfHi'&KSH)LSU*LBL)L)U0Mj! !Mif)J(4M66-G)dYeN!#HRC5-KhjhG(9hI)#%KiQ*Ki5"IhjpIAq"K)D(KiD(LBb 0LSH&KB5$Ji5(Lik-Ki1!IRajGRCkJ)5'KiL*LSQ)KiH'L)b2NC'2M)9lE9Jp(K8 hCiLERjH2LB*kGA4hHhq$KSL*Ki5#J(pqIAk!Ji@(KiH(LBZ0LiH&KB5$JS1'LSf 0LB@"IhekGhCiIB+&KSH)LSQ*L)H(L)Z1N!#3!)q-KAa[@d!M&c0JK*QJQBq+JhY eFh9jIS+&L)Q)KB+!IhjpIS##KBH(KiH)Lif-L)@%Ji1$Ji@*MBf+KB+!IRYhGAG mJB5'KiQ,LiQ)KSD(LBf3!*'3!)f)J(9P6M%C)8TfNTqFNiZ'IACcG(KpJB@(LBQ 'Ji&rIRepIi'%KSH(KiL,MBb*KS@%Ji1$K)L-MSZ(Ji"qI(KeGAU!Ji@'L)U+LBL (KiH*M)q3!*!!MSU%HQY@14N@2Qk-R*k9MBL!HA9eGhYrJiH*LBH$JB"rIRjrJB5 'KiH(L)Q-MBU'KB5$Ji1%KiZ0M)L%JAppHRCeHAk#KBD)Lib,LBL(KiL,MSq3!)k ,KAYY@6mN($KPKjUIPiq*JRTeG(CkIi1'LBU)K)'!IhjqIS#$KSH(KiH*M)f,Ki@ %K)1$JiD+MSf*KB&rIAPfGAKpJS5'KiU,LSQ(KB@'LBf3!*'3!)f)JhPT8c3A(%P hNTkFNiZ&IACdGAPpJB@(LBL&JS"rIhjqIi'%KSH'KiL,MBb)KB5$JS+$KBQ0MBU 'JS"rI(KeGRU!Ji@'L)U+LBL(KSH*M)q2Mif+K(aY9MJC&d&aMjfHP)b(J(KdG(G lJ)5(LBL'JS#!IhjqIi'%KSH(KiH+M)b*KB5$JS+$K)L-MBZ(Ji"qI(KeGAPqJS5 'LBZ,LSQ(KSD(LSf2Mif+KRpcB%FS'$"IJjLIQ)q*JRTdFhClJ)5(LBQ'Ji'!Ihp qIS##KBH(KSD)M)f,Ki@%Ji1$K)H,MBb)K)&rIATfGAGmJ)1&KiQ,LSQ(KiD(LBb 1Miq0L)0jD9)b&Kp1HC1IQj'+KAehG(CjIS+&L)Q(K)+!J)"rIS##K)D(KSH)LSf -L)@%Ji1$K)@*MBb*KB'!IRajGAClJ)1%KSQ,LiU)KiD'L)Z0MBf0LiCqEPJk'KT #F)kHRT5-Ki"iG(9iI)#%KiQ)KB+!J)"rIRq"K)H)KiH)LSb-LBD%Ji1$K)@)M)f +KS+!IhajGA9jIS+$KBL,LiU*L)H(L)Z0MBf0LiH!Fep&)a8cC)DDRjL1LB*jG(4 hHi#%KiQ)KB1"J)"rIRq!JiD(KiD'L)Z-LSH&K)1$K)@)M)k-Ki1!IhekGR9iIB' $KBH*LiU)KiH'KiU-MSk1M)L$H'C0+K-Q9Rq@RjU4LS0mGR4fHRk#KSL)KS5"J)" rIRk!Ji@(KiD'KiU-LSH&K)1$K)5'LBf-L)5"IhelGh9hI)#$K)@)LSU*L)H(KiQ 0MSk0LiL$HQY80KXJ5A53!*fFNib'IRGdGAKpJB@)LBL&JS#!IhepIi'&KiH(KSH +M)b*KB5$JS1%KBQ-MBU&JS"qI(KfGRTrJB1&L)U,LSL(KSH)M)k1MSf+KRpcAd- L&MGRL*ZIPSk)JAPdG(GlIi1(LBL'Ji'!J(jpIS#%KSH(KSH*Lib*KS5%Ji1%KBL -MSZ(Ji"rIAThGRPqJB1&KiQ+LSL(KSD(LSk3!*!!MSZ'JACP65`@+PPrPTqENBQ $Hh9cGRTqJSD*LBH%JB#!IheqJ)1'KiH(KiL+M)U(KB5$Ji1%KSU1MBL%JAppHhG eGhb!JS5'LBZ+LBH'KBD*MBq2Mif+KAe[@6SD'8*aMTkHP)b&IAGdGAKpJB@)LBL 'JS#!IhepIi'&KiH'KSH+M)b*KS5$JS1%KBQ0MSZ'JS"rI(KeGRTqJS1&L)U,LBL (KSD)Lik2MSf,L)&eB83K%c4PKjUIPik)JAPdG(GlIi1(LBQ'Ji'!J(jpIS'$KSH (KiH*Lib+KS5$Ji1$K)H-MSZ'JS"rIAPfGAKpJB1%KiU,LSL(KSD(LSf2Mif,Ki* jD9%`&b96I*5IQj++JhYeFR9jIS+'LBQ(K)'!J(ppIS#$KBH(KSD)Lib,Ki@%Ji1 %K)D+MBb)Ji"rIAYhGAGlIi+%KSQ+LSQ(KiD(LBf1MSk0LSGrF&Sm("JrESbGRj@ -KAjhFh4iI)'&L)Q)KB+!J)"qIRq"K)D(KSD(LBb-LB@%Ji1$K)D*M)f+KB+!IRa jGRCjIS'$KBL+LSQ)KiD'L)Z1MSk0LiQ$GQ*')a-[BS@CS*Q2L)&kG(4hHhq$KiQ *Ki1"J)"rIRq"JiD(KiD(L)Z-LSD%K)1$K)@(Lif,KS+!IhajGR9iIB##K)L+LiU *KiD'KiZ1Mif-LSL%HfT4-"8N8RZ6Rjb4LS0lGA0eHRk#KSQ*Ki5"J)"rIRk!JS@ (KiD'L)U-LSH&K)1$K)@(Lif-L)1!IhelH(ChHhq"JiD*LiZ*L)H'KiQ-MSf0MBZ (Ih"D2KmC2@b,RCq@MBCrH(0dGhb"KBL*L)D#J)"rIRjrJS5'KiH'KiQ-M)Q'K)1 $K)@'LBb0LS@"J(jmHAGhHRk"Ji@)LSU+LBL(KSL-MSk0MBZ)JA4J4588,f'&QD# CMiL"HR4dGRTrK)H*L)D%JB#!IReqJB1'KiH'KSL,M)Q'KB5$Ji5&KiZ0LiD#J(j mHRGfH(b!JS5(LSZ+LBL(KSH+MBk1MSb+KATT86%@)8piNU#GNSU$I(9cGAPqJSD *LBH&JB#!IheqJ)1&KiH'KSH+M)Z(KB5$Ji5&KiU0MBL%J(jpHhKfGhYrJB1'L)U +LBL(KSD*M)k1MSk,KRjZ@$XE'%"[MTqJPSb'IhKcG(KmJ)@)LBL'JS#!J(jqIi' %KSH'KSH*LiZ)KS@%Ji5&KSL-MBU&JApqI(PhGhTqJB1&L)U,LSQ)KiD*MBq1MBb +Ki&cAN)K&6CQKjbKQ)k)JAPdFhClIi5)LBQ(Ji'!IhjpIS#%KSH(KSH)Lib*KS@ %Ji1%KBL-MSZ'JS"qI(ThGRPpJ)+&KiQ,LSQ)KiD(Lik2MSk-LB4iC8XU&#GAIjH JQj'+JhYeFh9jIB+'LBQ)K)'!IhjpIB#$KBH(KSD)LSZ+Ki@%Ji1%KBD+MSf)Ji" rIAYiGRKmJ)+$KSL+LSQ)KiH)Lik2MSk-L)0jD9!`&5&3Hj5JRC1-KAeeFR4iI)' &L)Q)KS+!J(ppIAq#KBH(KiD(LBZ,L)@%Ji1%K)D)M)f+K)"qIAYiGRGlIi+$KBL +LSU*L)H(LBf1MSf-LB4mEPJk("e&FBfHRj@0KRphFR0hHi#%L)Q*Ki5"IhppI(k !JiD)KiD(LBZ-LBD&K)1%K)@(Lif,KS*rIRajGhGkIS'$K)H*LSU*KiH(LBb1MSk 1LiD!FPe")4FiD)LES*L2LB*jFh0fHRk$KiQ*L)@"IhppI(f!JiD)L)H(L)U-LSH &K)1$K)5'LSf0LB5!IhekH(CjIB'$K)D*LSU*L)H'KiU0Miq2M)H"GQ4+*a-XAS+ BSCb4LS0kG(*eHAf#KSQ+L)D#J(pqI(erJSD)L)H'L)U-LiH&K)1$Ji5&LBf1LS@ "IhelGhCiI)##Ji@)LSU*L)L(KiU1N!#2MSZ'JRTV9$-B)NpjNjqGP)b&IA9bG(K mJB@)LSQ(Ji"rIRamIS'%KiL(KiH*Lib*KS@%Ji1%KBL-MSZ'JRppI(PfGhTqJB1 &KiQ*LBQ)L)L+MBk1MSf+KAeY968@'dPeN!#IRT@0KhphFR0hHi#%KiQ+L)5"Ihj mI(k"K)H)KiD'L)Z-LBH&K)1$Ji1'LSk0Ki*rIRajGRCkIS'$K)H*LSQ*L)L(L)Z 0MSk0LSCqF9`r(KNqE)ZGS*H2L)"hFR*eHRq$KiQ+L)D#IhjmHherJiD)KiD(L)Z -LSH&K)1$Ji1&LSf0LB5!IRekGR9iIS'$K)H*LSU*L)L)LBZ1MSk0LiCqF9`q(4F lDSUFS*L3!)U#HA0bG(PqJSD)LSQ'JS"qI(YmIS+'L)L(KiL+LiU)KS@%Ji1$KBQ 0MSU&JAjpHhGeH(f"Ji5'LBU+LBQ)L)L+M)f1MSZ'Ih4L5#JC-f#$Q+#DNSZ%HR4 bG(KqJS@)LSQ(K)"rIAYmIS'&L)L(KSL+M)Z)KS@%Ji1$K)L-MSZ'JRpqHhKfH(f "Ji5&KiQ*LBQ)L)Q,M)f1MSb)JA4L4bFD-f#$Q*qDNSb&I(9bG(KmJB@(LBQ(K)& rIAYlIB#%KiL(KSH*LiZ*Ki@%Ji+#JiD-MSb)Ji"qI(PhH(b!Ji5&KiQ*LBQ)L)L *M)k1MSb(J(9P6#dF-&YrPCqENib&IA9bG(GmJ)5(LBQ(KB&rIAYlIB#$KiL(KSH *LSZ*Ki@%Ji+#JS@+MBb)K)"qI(PfGhb!Ji5%KSL)L)L)KiL*Lif2Mib(JAGT8c- E+PCmNTkENSb(IRGdG(GlJ)5'L)Q)KB+!IAYlI(q$KSL(KSD)LSZ*Ki@%Ji+"JS5 )M)b*KB&rIATiGhTrJS5%KBH)L)L(KiH)LBZ-MBb)JhTY@MdN+NpfMTbFNif(J(K dG(ClIi1&KiL)KS+!IAYlI(q#KSH(KSD)LSZ*Ki@&Ji+"JB1(Lib+KS+!IRYiGhT qJS5%KBH)L)L)KiH)LBZ0MSf*JRTY@d%R+8edM*ZFNif)JAPdG(CkIS+&KiQ)KS1 !IRalI(k"KBH(KSD(LSZ+L)D&Ji+"J)+'LSb+Ki1!IRYiGhPqJS5%KBD)L)H(KiH )LBU-MBb*KAjbBNNX*dCZLCLFPBf)JRTeG(CkIS+%KSL)Ki1"IhalI(k!K)D'KSD (LBZ+L)D&Ji+"J)'&LSb+Ki1"IhajGhKpJB5%K)D(KiH(KiH(L)Q,M)b+KApeC8d [*N0VKTHDNif*JhafG(CjIB'%KSL)KS1"IhelI(k!JiD'KB@'L)U+L)D%Ji'!J)' &LBZ*Ki5"IhekGhKmJ)1%K)@(KiH(KiD(L)Q+LiZ*KApeCP%h,80SK*5CP)f*K(a fGACjIB'$KBD(KS1"IhelI(f!Ji@'KB@'L)U+L)D&K)+"J)#$L)U*Ki5"IhekH(P mJ)1%K)@'KiH(KiD'L)U+M)b*K(phDPBp,MpNJC+CPBk+KAehGACjI)#$KBD(KS5 "IhemI(erJi@&KB@'KiQ+L)D%K)+"J)#$KiU+Ki5#J(jlHAKlIi1%K)@'KiH'KSD 'L)Q+LiZ+Ki&jE&P!,ceJIT!!Q*@1LS9rHACfH(b!Ji@'KiD%JS"qI(apJ)+%KS@ &KBH*LBL'K)5#JB#!JSD*LBH&JS"qI(PiHhq#K)5&KSD'KSD'KSH)LBU,LSL$Hfp I4c)i@RU0PTD2LSD!HRCfH(YrJi5'KiD%JS"qI(apIi+%KB@%KBD)LBL'K)5$JAp rJB@*LBH&JS"qI(PiHRk#K)5%KSH(KSD&KBD)LBU+LBD"HR"L6$Fl@RL,PTD2LBD !HRGfH(arJS5&KSD&JS"qIAapIi'$KB@%K)D)LBL'K)5$JB"rJB5)LBH&Ji&rI(T jHRk#Ji5%KBD'KSD&KBD(L)Q+LSL$IA0Q86`k9(1(Nj@2LSH"HhGhH(YrJS5&KSD &JS"rIAapIS'$K)5%K)@(LBL'K)1$JB"rJ)1(LBL&Ji&rIATjHRf"Ji1%KBD'KSD &KBD(L)Q*LBH$IRCT9Mmk8R'&NT52LSH$I(KhHAYqJB1%KBD&JS&rIAapIS##K)5 %K)@(L)L'K)1#JB"rJ)1(L)H&Ji'!IRYjHRf"Ji1%K)@'KS@&KB@'KiL*LBH%IhG X@dFq8'f$Mj53!)U(JhjjGhKlIS'$K)@'KB+!IhjpIAk!JS5%K)5&KSL)KS5$Ji+ "J)##KSL(KB1"J(jmHRTpJ)+$Ji5&KS@&KB5&KSH)LBQ(K)&kF@*02NTSIif6NBZ (JhjkH(KlIB'$K)@&KB1"IhjpIAk!JS1%K)5%KSH)KS5$Ji+"Ihq"KBL(KB1#JAp mHRTmJ)+$Ji5%KBD&KB@&KBD(L)L(K)"jF'033NeSISb5N!#,Ki4rHRKiHRf!JS5 %KB@$JApqIAeqJ)'$K)5$K)@(L)H&Ji1#J(prJB5(Ki@$JB&rIATkI(q"Ji1%KB@ &KB@&K)@'KiH)Ki@#IA4R984+BhU*NC!!LiH%IhYiH(TpJ)+$K)@&Ji&rIRepIRq "JS1$Ji1&KSH'KB1#JS'!Ii#$KSH&Ji+"IhelHRYqJB1$Ji5&KB@&K)5%KBD(L)H &JReeDPK(5Q*jL*!!N!#,Ki@!I(PjHRf!JS1%K)5$JB"rIReqIi'#Ji1$Ji5'KiD &Ji+#JB"rJ)1'Ki@$JB'!IRakHhq"JS1$K)@&KB5%K)5&KSD(Ki@"IACVA%e1BAH 'MSq,Ki@"I(PjHRerJB1%K)5$JB"rIReqIi'#Ji1$Ji5&KSD&Ji+#JB"rJ)+&Ki@ $JB#!IRalI(k"JS1$K)5&KB@%K)5&KBD'KS5#IRP`BP*0AA1$M)q-L)@"IATkHha rJB+$K)5$JS"rIRjqIi##Ji1$Ji5&KSD&Ji1#JB"rIi+&KSD%JS#!IhelHhf!JS+ #Ji5%K)5%K)5%KBD(KS@#IRK`Be42Ah5$M)k,Ki@#IRYkHRaqJB+$K)5$JS"rIRj qIi#"JS1$Ji1%KBD&Ji+#JB"rIi'%KS@%JS'!IhelI(k!JB+#Ji5%K)5%Ji1%KB@ 'KS@#IhYcD&T4@h"rLBf,Ki@#IhYkHRaqJ)+$Ji5$JS"rIReqIi#"JS1$JS1%KBD &Ji+#JB"rIi'%KS@%JS'!IhemHherJB+#JS1%K)5%K)5%K)5&KS@$J(adD9Y6A(" rL)f,Ki@#IhakHhaqJ)'#Ji1$JS"rIRjqIi#"JS1$JS1$K)@&Ji+#JB"rIi'$KB@ %JS'!IhjmI(erJB+#JS1%K)5$Ji1$Ji5&KB@$JAehEf&9@QemKSb,Ki@$IhalHha qJ)'#Ji1$JS&rIRjqIhq"JS+#JS+$K)@%Ji+#JB#!Ii##K)@%JS'!IhjpI(erJB+ #JS1$Ji1$Ji1$K)5&KB5$JAjjF@9EA'YkKBU,Ki@$J(elHhaqIi'#Ji1$JS'!Ihj qIhq!JB+#JS+$K)@%Ji+#JB#!Ii##K)@%JS'!J(ppI(eqJ)'#JS+$Ji1$Ji+#Ji5 %KB@$JAplG'TH@fKiJiQ,L)@$J(emHhapIi'#JS1$JS'!IhjqIhq!JB+#JS+#Ji5 %Ji+"JB#!Ii#"Ji5$JS'!J(ppI(aqJ)'"JS+$Ji1$JS+#Ji1%K)5$JApmGQjLA@G fJBH+L)@$JAjmI(apIi#"JS+$JS'!IhjqIRq!JB'#JS+#Ji5%Ji+"JB#!Ihq"Ji5 $JS'!J(pqI(aqJ)'"JB+#Ji1#JS+#Ji1$K)5$JS"pH("QB'CdIiD*L)@$JAppI(a pIi#"JS+#JS'!IhpqIhq!J)'#JS'#JS1%Ji+"JB#!Ihq"JS1$JS'!J(pqIAeqIi' "JB+#JS+#JS+#JS1$Ji1$JS"pHA*UBfGdIi@)Ki@$JAppI(apIS#"JB+#JS'!Ihp qIhq!J)'"JB'"JS1$Ji+"JB#!Ihq!JS1$JS'!J(pqIAeqIi#"JB'#JS+#JS+#JS+ $Ji1$JS&rHh9ZCQGbIB1(Ki@$JS"qIAepIS#"JB+#JS'!J(prIhq!J)'"JB'"JS+ $Ji+"JB'!J(q!JB1$JS'!J(prIReqIi#"JB'"JS+#JS'"JS+#JS1$JS&rIAKaD@K `Hi+'Ki@$JS"qIAepIRq!JB'#JB'!J(prIhprJ)'"JB'"JB+$JS'"JB#!J(q!JB+ #JS'!J)"rIReqIi#!JB'"JS+#JS'"JB+#JS+#JB&rIATeEQY`HB#%KS@$JS"qIAe pIRq!JB'"JB'!J(prIhprJ)#"JB'"JB'#JS+"JB#!J(q!JB+#JS'!J)"rIRjqIi# !J)'"JB'"JB'"JB'#JS+#JS'!IRYhF@e`HAq$KB5$JS"rIReqIRq!J)'"JB'!J(p rIhprJ)#!JB'"JB'#JS'"JB#!J)#!J)'#JS'!J)"rIhjqIi#!J)#"JB'"JB'"JB' "JB+#JB'!IhejG("bH(k#K)5$JS&rIRjqIRq!J)'"JB'!J(prIhprJ)#!JB'!J)' "JB'"J)#!J)#!J)'"JB'!J)"rIhjqIhq!J)#!JB'"JB'"JB'"JB'"JB'!IhjlGh0 bGhf"Ji5#JB'!IhjqIRprJ)#"JB'!J(prIhprJ)#!J)#!J)'"JB'"J)#!J)#!J)# "JB'!J)"rIhpqIi#!J)#!J)'"JB'!J)#"JB'"JB'!J(jpHRCdGhb!JS1#JB'!Ihj qIRprJ)#!J)#!J)"rIhprIi#!J)#!J)#"JB'!J)#!J)#!J)#"JB'!J)#!IhprIhq !J)#!J)#!J)#!J)#!JB'"JB'!J(pqI(KhH(arJB+#JB#!IhprIhprJ)#!J)#!J)" rIhprIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!IhprIhq!J)#!J)#!J)#!J)# !J)#!J)#!J(pqIAakHRarJ)'"JB#!IhprIhprJ)#!J)#!J)"rIhprIhq!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhj mI(erJ)#"J)#!J(prIhprIi#!J)#!J)#!IhprIhq!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!IhprIhprJ)#!J)#!J)#!J)#!J)#!J)#!J)"rIhprIhprJ)#!J)#!J(p rIhprIi#!J)#!J)#!J(prJ)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J!!!3N!!!3!"!!8!!!#J!!'!83!!!!!!&!!!!!!!!%) @9Zk,S`!!3K3!!%)9!$b!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)"rJ)#!J(q!J(prIRk!JB1 $IAeqHAZ'Li9pGh0lJ)#(MhKXIhaqJ)D(IhjZH)PjGiU8H'D'I@b,P)CaFReiJAp qL(YiL)0hG(&jLi9rPS49Ci9rMU5(DhCP9)LXMhf!J'44GTfFLSk'B9eNF+LJH*@ (6df'Qi+AM(Pk8'LEJAqJLeTdM'&lRAKqPh"VMRPSL)afLSYUIi*XJ)4mLiPSGTP ZAjD5HB"pIS"TC*DPFA10G'KYJjU1IRehCA#6IhZFI'TmH(5'M(Q#Lh&cL(KfL)C qG)#%HhacLSTVHSq&DhLAGQQ1NAGaI(PjLi#)Q(&LGhadLD5-FATRB(q)NjL5F9p lD@HDU)CeK(G@DBkCPhjlJ'aLGSq9MRpaGi"SG*Z4I(GrHfalLB&qKiTZFT0eCiq 5FAH4Hh'#Gh@4Kfk(PR0JIC&mH)11LfPNKT4eFj@2FR"lHB1(GS19G@H(K@f"Qh9 VNS*RIBZ!I(jqIBYcE*Q'DRD0KfYqKS'(Fh@0I'f)NATbMApMIi9rMS&mIAP`F)f *J)epG(0aJS@!KC!!JQG`K)"pKSH&H@eiKB&rLB4hH(CjLiKdJ)j`CiQ)ISGqG(k $EhUCJACpFhjpH)Z3!(KXL)"IM*KkK)&aFS*kHj@*F(erGAKiNj*VH*4mARkBGhL 1HRjmGB*rIi+%HRZ'Ehb3!'akRRjNM*!!ARLAHAZ-I(GkFB#1I(Q4I'q*IQk'L(5 !KRPmL(GeM(phJB@'H(D%Ih0hMBKkL(abJhTZLTjrChq)FA*mNjTeDAq0G'Q1QS9 [DBU'D(UIQ@9UMRYZJj+1GA'$Gh5*P)"`KhY[KRb(PhKXJiKMHk4qHBKfFhYeL*Y pF*+!9iLBDhbAJ@prKB4mCS5NF'5IQ'*MKSZ'GAUSL8Y`S(pUM*U#FfGiQ(0YSTC UEBGqFi1(MB0ZJB4YIC@$GS1&Hh9hJT!!G@qCKQb'J('!KRU,P'TaMR&ZNj*rJhC YJS4mM*&hGAe[I)f%KBTlFB"mFiZ5K(TcH(ahHjH@FAL!Eh5)Mj!!L'jTKRjPMUQ (E('!GR+)NBq"F(*fIRq'PiCfH(9hJS@'LiC[GBK[HjYqDiU-Eh51JhU+H(H-G@b %P)TfHB0jGRZ-MhGaKB9eH)q-ChH9IhL'IR&lKhZ,Q@pZJh0dMj4lHBCeE(k*N!# #G)@(F@D&Q)"cL)paE(Z%MSCeJBpdBBZ8Ehb4IR1(Ih1$JRKpMS9rHA"qJ(b+N!# "H(GjFi+2I)Q-DfL(M'k$TATSKAjQG*f4ISChFh"VLkD0FhU%G'"pMiq9FhQ*BfD 3!+*mG*Cm@A+@L(4kMSCiJRYlGQf$R)pVHiGKCSqIM(elFhCXGCf4JAamDfL)JB@ 3!)KmE(YlDifBI(U-H9pqM(D'Q(PYLRYXJi4jK*&rGS&bGB*cN!#LG'+%K@*hSj9 lI(0YHRCpPT0lI)pQ6BbLKB14J&PHHT5QJRD@G%PXQjZ&JiGlCe9rVSPiPiGL@hU 2LBk4MA*EERjqN!#DMi4VAh@"ISfJM("fFQGiL*56J(f"D9Q$RB1#NSK`BQb#Ni1 (RAPPER@"LjD&Ki4BD)H&MiU-JR"UD)Z4KSZ!JAaNEBq6J)',H'0fLiQ$J*D)9@k 3!)KdJ*U#EQGqQAGYP*jZA*+3!'&ePjP[CiQ(H'Z(QhKTJj4kBi5LJPKpURP*KV* eA)1FKf"[NjG`DTL0D@ppN!#'DhqAIef&S@jUP)aQG*1+FAL'HRTkJT5*Fh#'IPq #Uj*ZD(ppDhDKVh49I)9LH+5@KAPDF)jcGkfMB'U%D@b,Pj+%EA4iDS'INR*jJQT hJSQIJ@"VMS4QMD1'C@D'K(k-KRjlGQppN!#&Ji*kFAb"KC*jHhjUFSfBISL-APU !PSb2PAaT@&k-T*q1Jh459B'SSiQ$G'*5EE'QFS18CNeqRj!!Ji*rG@CYN!#BK)1 *F&plPSapIB9lBRUHNA*eJ(&lLjUDBe*rMhH&UT&R@QL0Nhb5Uh*)GBYcK+H2Fh0 VE(q8PBf+FPKRMiq(RC0K@R0pMD#4Ii"KA)51NTk%BACl@SZlKQf#FQ+!MSUPLP9 MJAU$TTf"F'"GFCLSQiK`CeCRM*keP@YPDQ"TTkZ,JA*ZF'CdVUCPH*jZ8AZ-LCU "E)b%@'kJM(L*KA4hGh@1KhL,K@phKAGrPi9eJRe[H(q'PB9bH(YqIS"qMBpUG)D #HhL#LiTeI)abEBQ'I*!!KA"qH'f)PRGkPAKbJRKmKB#+QA&DLi9HK+Q5GfpZIRp ZMkTqCReiDi#*M*0mGS"YDj!!PRD,MQ*aI(D2QAaePA*4LjQ$Ji'"G@YYN!#DH)D +Dff&JRf2NAKUHSCfGT51F)+*D(H2HhfCI@@+If5)PAL%L'YqL'plRRYTPhTQM)Y bHj9jG)edHiaiGiL*FhZ-HR1#MAjcKBPcHC!!IAH%JhKkL(f#Jh9rIRq#JS#%L@a aMS4fL**`G)*`GC5DH(b(E'0mP)U-MhCQE(arLU#6H'KZGh5'R+#!A@YrHAHAT)a YBA##K(kES'jMHh4VM+10KS"MD(KjMUk2EhaQ9(UNQj',G@pHB*'QMS@+FPYbIS@ ENi*iGfpYJj'4JRZ'G@TmL)b(IAH(K@YlNi4kIAU#LRYfM)4XJ)YqKSaiGRpiI)Z +Ii9jDB1,HBD@KfTbJh@'MS+(JACPICD%LB&rJfpVIjk(FSZ#GRGhJ)q0GB#2H@P kLiTqHj!!L@PaKS5!LS9jKhP[JB5'KhemLRaSJC0kJT!!Fh@*G@f5QhPcKRjdGi1 @L(9hJ)"iHSZAJQelM(YdJ)Q2Hff&MA*ePS9cL)*dJ)GiJBT[IT*fGCQ*AS#6FhL 8NAKdER13!)9rPC!!EQ'$JRq2L)TrE@GpPAQ%S)"PFB4pIj@*J)0XD)@5J)#3!)" XG(k'N!#"I)PiDAf4IhZ8Iff#I(5$N!#+J)&aGS4jJC!!LhTaHB#$Ii'5J@jkIi5 #IB'$Ih9rKAf)IhL-K'jjM(eiMS&lKh4`M)ChM*!!Fh#"HAU*LBq&E(Z!ERUBNAU 'H@CjIS5CNAjpFQ4kMBQ8NR"eGPb&VSCbQiK)DC')NSf!J(CGFCf2KC*kDRGeGC5 EI(KqEfk-MSU3!)"VCS+*ISq9IQGXHi15NSH+GeTVLBZ5PB&dGfeNNU#)KhafG(9 [LUPmDBU(E@q1MB5%GAk'I(D#N!"rG(Z#KBH!Hi0rGRQ(MSL!FhL(H(H2N!"rGi" jGSH%KBjrGRGmIhZ-NSKjEAYqJBD+PiCTChq'GifILA*YGh@$N!#2NReUF(jmJCL -HS0lE(L-L)Q(GB5)BfLLR@CrRhPRGS+'Li1!P(GEJSpiIjL4Hh4[G)*rKTZ2H(9 bEAH4QBZ&JhGNDiL2LiU%JhjXDiQ2JSb2HA&iEhb8MB@+J@abIRq0NS&lIh4`JSk &JSZ%GR0qJAk,M)9lDRU&JB#+PRGcIAf+Gh++PB4aKAjXH)D6MS4mH@jUKj!!Mib #HA*`DBkLJiL*F&pbMSQ2MiL&@eZ1Q(q)SB"MDQf0R)'!N!"k@ALBJAq*K(YeJ)5 *IA5'J(H'LhplK(jbHSb,JRjmJhTZHiZ8J(f*G("mKi@%MhCaKRTjMiYjI)"cJT* hI*9fBAq2KSZ-G(KrCAbIM(b(IQ&kMhk)N!#"GhPhH)b+J)4jHB&pJSZ*HA*jJS1 "NSpcD(Q"J*+1Ki4NAB1BKikJF9P[H)'AUC&aC@"dKiqKSB"G@hD!JCfVMQGMEfe pPk1FGfK`D@b4VSelK@jFH*+5Mi4hGh9aKD'*EAZ$H(+,S)K[FS"hG*19L(jbGhG hKTL0H(pkES5+I)f,F(1,JhQ@K'KqIA5-RBChJh"LIj!!PT@%HR0QC)UPN!#)Nh4 9CiH5NC@+J(&AF*DCLBQ3!(0GFBL2MBk,GfKbJiL(N!#3!(9YGhZ$LC1)HhYYGi@ *LBD,HA&kIBU'JiH%HR"mK)D'J)@'GA#)LR9rPi9VHiKqG(b8NAYdJ)4`HBq2MAa kI@j[KjU)JT&qAQU,Mi@-Pi"ICB#,K)kDJfeXH)+$Mj!!KRTXGS1!JC59EQU*J@k &Ri4`HhpkH)@6Lh4hKhP`Lj0qI)4mHATmLSemHBZ!ChL5LRQ%PAeLGSq!HT16GQp jGhk)M*5*Eh1!Fh+1R)ejFhYlD(LNS(TcJ(&PIj56LRpfFA4jKjQ4HR*pG@f'Qj! !GhPhERQ&Pj@$GQpaEi1CQ)TiEQaeISUMPA9[G'j`Njf)JAP`Ehb)NC'"G(4fHSL 6M(efGh*mN!#8M(ebEA*qM*k4HRKXBRUIPBH2HQ&QH)QJQhTlH&jVNTf2LhpXE'P pS*U#J)"KCSL1N!#9L@eTH(Z(NC!!Lh9XFi5*Jif,I'YbL)Q(L)*rFferNSq#L(a SGiD!LjU&Eh&eHSQ,LC*rCR'&Ji@5MAacF(D(LBQ3!)CcEAQ$K)f0L(j[F(Q)LS@ 4LhCTGSKrIiq8KA"cIhakJC'6JAGjHh4eMTL+K(pfCff)NT'1MRYHDB@+LCLFHQ& SGS+1NjH2EejYKBD(STTfBfTiGibHNi4eE@PfMjD3!)@"H'4VMCD'K)GpF(*qMjG qGiPrDADBLhD(JA0fKSb#KS+!HR#%M)"kKSTdGiQ'IhaqKi9fI*'(ERL-I(D,Li' !JAKcIi5)Li5#HR&cIiU&Lj*rF(0mIRq+Mj&rCR5$GhQAQhjiHQjfJSD6NRjbGh0 cLj'0N!"mDR0mHiLCMRjjD@b$Lif5LRP[ERD&NC'+HfpiGR54QSChHRTZH)bANA9 dIA0eKC@8Jh&VIi"eMTf(FA*fFi13!*!!LAjfE(1*MiH*LR&NHBU-MSTmGQpYJjH @KhYbEA0mN!#EM)"hD'@#PSZ4Q(CDE(k"NCk0HR&MESk3!)b6LQjNGRb*PBZ&I'j XIiZ,NSPbFRPaICQ6I(jpEA+'Lif4IA&jH(+$QBYlJhaZGiH0L)@!HRKcIiZ(Ji* qHAerIib,Hhb"HRH&Khq&KAajJB+!Ji5"Ii+!HAq(IhL"LS*qJi*rHAU$L)5"KAp fHAq$KSD)KAYfI)"jKC!!LRjhHATlJ)U8Kh9iHhjrKBb'IAGpIRk)K(q&K(TmK(a pMBKlIRpfHS@&LBeqGRYlHB@1LB@"H(*dHiZ9LB+'GfCbL)Z2PB&cG@a[LjU0L)T `CAL!Kj'6KR9dF(@$M*H+I(PeGhU)N!#,JhCdGRq+KBU*Gh*qJRf3!**dGS0cGC+ 5IiD"DRD&JT!!P(YdI'paLBq8P(GRH(aaLk'1JhPQChk)LCZ@I'YUG(b-PC5&Fh& ZG)@1P)arFh&iHBQ3!)U'H(4iI(f)Ni4hIAekIS5+L(adIB4qIiD$JAjmIi+!IB+ #IS+#IRjrJ(epKB9pIB@$FhZ0KRf!KAjfH(b+MhapKApcH)H'LBKlHAPfHB+0NBT lEhPiGBbAM(pkF@PfK)qEMRGfH'YUNU1)IBGeA(#,MC59JRC`ChD4NBL3!)"QEAQ !P*D%KATFFCL'I*k1A'L#Hi5BNi4lCfH&LS@8PhYKD(f&L)qDLfYPFRq)NC1'H(0 [F)+BNS#"HfpdJ)D2NRYcIhKbL*H%IB*iG(U)LBD,I(9fIS9qLSU%I'jmKS5!K*! !IR*hIS9rJSk)Gh@"J(U%MSGqHhYiHB@*KSQ$HhGdHBL6Ji+2H'*eLB@+NiPkG'Y fMSL*NiG`DhKjKT1,LS"bF(5&Lj!!LAPpGR*lLTD(IApfGAf&Lif'FhQ#FAbAMAZ #JA"iKi#*NhjbH(f!JB'+NRjYIBClIi1'LS"bH)U#Fi15KhGkKhehJ)+(LB4eHiG hGiU-L)4kFRf"H)H8L(piFRKrJiZ9KR4jGA#$Mif1L(0THhpmMjH*HA*YFSH2LBk -G@C[JBZ-N!#0HQeXH)'-QBq#FQPaHSH4PieiEfGcKBU6QBKXEA4`K*H8MS4[ChC lJjU8JRpaBh@,LSq9JA&bERH0P)k'HA"bGB#4N!#(JAKYGB+%MieqI(CdH)10LiG hHB&cI)f*JB"lFhq)IB1)IRYpIAk(LApkJ)"hHiU+IRf!HRZ!JBU+IAPpHhL%KB1 *IhKrI(Q(LRZ#MAKbJS*lJiPrJS4fHB+!JBD*I(U"H(H"LSU!JRahI(Z$LiQ$I(K bHSD$LBk"HAKdHBZ2JS1'FfjqJS12MRYfIRCdLC1)J(afG(TpLTQ(FhTpGRQ,MSb &F(9rHAf-P)&qIR"jJSH+Ki*iI(KeKik&IB5"F(Q-Khb&KRPiIAq&LRYkMS&bISL $J)1!Ji*eISPmI)f)H(q&HAb'IB'1JR9pKRKjL)D+KRPiJ)"hK)k%JRjiHS##JBZ 'IAepHhk%K)1$IhalIi@%IS+'I(KpKSYrHB+%GRH*Ki1)IAD#IAD'N!##IBGjF)# #KBb'JRekGAQ(L)Z&HRekHAf$MSb#HhGiHS@'JSf'F(5"Ii5-Ji#'G@b%M(f'MAa iHRU"Li9qKhjcHS''L)9rHhjkHS'*MRjjI(b!IB'+MAeZJS4cJiZ$JB0iGSClHj' 'GS'$GAQ'JS1)Ihf"HAQ)JAb(L(afIhpqKB'%KRjiH)+%IS@%I(arIRZ'LhprIAP rJB+#Ki"hIRYqLBD!JS*cGSL#JBQ'HA4kISQ*J)@'G@YrM)H&KB&jG(1!NBL$L(e ZF)D(JSb+Ih*bIi'&LBL$GRGrIRq%M)9fHhppJB##Ki&hH)L$HSQ'GhL!JB#'KS' !H(9rKiL'JAprH(9pLiZ!IB&rGRL)L)+#JhjiHRk(KRU%LhPeJiQ!I(q!K(jlKS0 iHiL%H)5+I(GrL(pqKB+"IRepJB&pKiKlHS'"I)'&KS9kH(q!I)5+J)D$FRD'KAb )MAejH(H!KSH*LAjcH(prKBb*Ih9hI(k(LiU"HhPiI)12LhakI(KiKBU,LhYdHha mLj5"IAp`ES+5LiL'HA9dI)H-LB*rG(0qK)H)KS0mGR@$LS+$L(e`HBD&J)H*I(0 lKS5%KAYqIhCpM)TqJ(edISU#JSb!FhKqJ)D+KB0pFAU'JS5-KhTeH(b%Ki@*JRG iIAaqMiekH)5"F(Z2L(f!JAYmIRZ+MATmKhaYJT'#I)1%HR0jL)f!JBPmFRQ"JBH ,JAjlFRH&LS5*M(GXHS&pKT1'HAacFS@0KSb-G@efHS+1M)D%G@YhJiQ0M)*pFfY lLBD*Mi&`G(arJSU1KhGbHRerK)@-KA&bL)KdK*&rG(Q!J)+"JiTmFAk'Ji#)KRY eGS1(Ji1)J(CfI)1$L)H#I(GmIi+$JiH!GhTrJS'&Jhq"HAL#LAppK(pjI)1!KBK pHhprI)''JS+#H(Q!K)#!KS9rG(Q*KAU$LheeIAq!L)0mKB0cGiZ'I)@$GhL#JS+ &JApqHhq%K)+"IRZ!IRq'KhpjIherKS5"JB0kGB''Ji+&IhCpIhb)MS*kJAPcJSQ #KiYiFRjqIib0K)"iF(Q%KBf1I(KjF(b5Li1+JQPaKB1'MiPlHA4dJiU+LB4lFh9 qKiQ*Li"bFRf$JiU-K(9bIRq"LSq&H(CeIB1%LBk&FRGpHi'+Mi9kGRKlHSH5LRp hHATlIiL3!)4mH(GlIiH)M)9lH(0kKSQ(KS*eGRamL*!!KhepHA4qJiH-JhTlI(P rLSQ(J(GpI(H#MiTlIhefHRf+NS0jI(jcHSU,LAaiJ(jeIT+(HhppHhYpJif&GS+ $F(L,LAf"K(ekGhk,L(YrLAedHS@(JAq#JhTfKBGmIiD#H(b(JRPqK)0pIB#"Jhe pL)&eIBKrGBD*HAU&K(epIS#(IRU%K(PlJhq$KRerJhTfK)0pL)ChHS0iHif(Hi# #GhH#K)L&I(emHAL#M)Q#HhajGS#,LB1$Hh9eHSQ-L)@"H@ekJS+1Li*lGR"hMBD %Mi9aF(epJib*K(jiFRQ$Kik(IhTeH(k$KSZ)GR*mJB+&LB9qHA9iK)Q%JS9qG(C qKBZ-KAKfGAU$L)f'IAGeI)+,L)'"IAKiJiD%JReqIReqKSGqJ(jpJ(b"Ki4mHB& pJ)H"Ji4jGS5%IiD'GhU&HS'+JB#$HR@)LAQ%KhemIAf$LAepKhejJBH"J)&rJRY pL)GqHRprIAk&MS*jIhYhJSb$KS9bH)*iIjL0G(jrF(U*KiZ,H(*pHRZ1MB##Hh0 mIB'1MRTdJRPfKBb,J(PhHi"qK)b*Hh*mJhU!NSPiHRajIiL'K)CkHB"kIiU&IS' #HRf!ISL(HB#(HRH%JRL#LB'!JRjmI(U$MB4pIRahH)#(MBPqHh9fIiD)LiPjEh9 pJSU-L(pdFhZ"Kib+Ih4cH)1'Kik(FQjpJi+(MB9eFRL!K)D,K(aeG(q'K)H*IR* hIRq'LB5!HR4qK(k(M(jdIApjKBL"JRYfJSClIif"Fhk#J)&rHi+%HAk+K(YmIRb "KB1$J(TiHi''Ki@"HRKlIi5(KApqH(H"KB@$JRjjI(f$Li*mIRaeIif%JB9kFAf %J)Z-IRChH(b*LS@)Hh*fI)+)Li0rHh*mKS'$M)0cH)#!JS1$JAakI)''L)"kIRj lJiH!J)0jGi@'J)5"HRarJS1$J)&mFhk+Ki+#IAClHhq2MhpiHAGhK)f+KS&fEAD 'LiZ,KA9YGS'*MBQ&Hfj[J)Z*MBPlG(&fKC!!LS@%FQapKS1,Ni&dG(L#KBH*L(T ZIB&pL)k)HACmJB&lKT!!JA&eJS5!KBf%GR9rJi++KRKeHS5(K)5%I("kLSZ'K(j cG(Z'MiH!JAYaGSL1LS4lHRCbISq3!)9rGR4jIiQ3!)YpG(0fK)L(Mi9`E(b'KBU +KAaXEi11LSD&IR4`HSb0KB5!Fh5"KSQ&JB"jGhf(KS'#HhTrJ)5&JheqI(5#Mi* mJAjlHhq)M)&iIAjiJ)Q)JATiI(pmKT'#FhL"Hhf+L)0pGAD!KS1)L(efH(f"KiL %IRGfHi+&L)PqGhTlISH0J(TqG(@%LSH&J(CfIhk$MBGkH(TiIB@'LB0hGRb"JS@ &IhjjH)+)JRb!IRPrKi5!JRjjHi#'Ki&kIAphHiQ,Ji"pH(TmJBQ*IRarG(D*MB0 qJhYeHB+1L(YlJATbKBf%J(pmH(jqJiZ"HReqH(b,KS#!IhTjJB1'K(ppH(b$KS+ !KAadISH%Ii1"H(YqJSQ%HRk"HAH*MRpmIhjjGi@-K(f"JA9hKSL$K)&lHhTqLSK qIS*jGB1+KAq!J(GhK)Z&JB*lGRU!KSQ'IhYkHAk&L)KqI(eiHS1+K)5"FhQ%Ii' 0LhGdI(k$KBD)J(4fJB+&LiClH(TkJSH(LB"eGS1&I)H,IRGkJ)'%K(q"J(Z"K(e rKRpkJS4pIi5"J(jpJB*rJSL"GAZ"Ii+(Ki&mGAQ(KS'&KRKbIS+#L)4qJ(aeISb (Ii+!HATmJSb*IAYrHhZ%KSL(HR4mJ(k'MS*kI(KiKBq'J)&iFRb&L)Q$I(YlGhf 1M(ppI(akHS1-LATjJRekJ)D'JRelJRpiJBU"HAk$IRf"K)9rGhZ'K(q"K(eiI)' 'K)'"HAQ"Ji'#KRjfHhq%KS*qIhpfHBQ+J(b!IRCjKBU%IRjmH(b"KBU'IAPjHhf &LB+#Ih9fJ)U$JBCpGAL#KB+'JRYkHAq'KRprK(TfIiH'JRjqIhGpKi4rJi0cHBQ !I)D(HhTqHi1'IS#$IAQ"KB'"J(amIRq&K(q!IhTlK)5"KB4lGAf%Ii#(KRYhIRq #JS+'JAGjKB*pK)9mH(jrKSGmJB4iGi5(IS5%H(k"IAq&KRppI(q$I(k)JRPmJS# #KB'!IRKpKSD"K)&iGRk'KB5'JRGeIi+"LSPqGhTlIBD(KB0lHAZ"JS1(K(jfHi@ "Ii5'J(PpIS5'IRq%JAYmJiD"I)#'IAL*LAPmJhppIi5+Kh0bL)0iKC+%F(@#Jhk $Mi9cGB'"IS@*KRadIB0qIiZ,HA4pJRalMT*lEhk%G(f5M)"hGRarIB+8Lh*hJ(Y kKSb(IhClJRZ!MB9kIi&jIi4rJi*mJ)9mHSH$Hhq&KAemJB&kHBQ,IRerIRPmK)U -I(CqI(KrMBf"HhGlIAq)LSL!GR4jJi@&LBClFhD!KiH(KAeeGAZ%LBU'IhGcHi' &LSZ"GRCkI)'(MBKkGAerGi'4LAakI(eiHB@2KhPqJhPdISZ*Ii#%I("iLBD#Ki9 jFhQ!K)H(KAecGAk%K)H,K(0ZIS9qK*!!LA4aHRf"KSZ,IR*cIB1"KiZ'H'plK(q "LiPlH(PlJ)D'JS5"HACmK)5$Ji&qHAPqKBH#Ii&qGRQ&Ki#!K(piHRq%KS*qJAp kHS#'JhpqJS"iIS1$JRk!J(pjHiL&IB#&JRKhJ)H$IB+%I(KmJSD%J)&rHRTrJS5 &JAf!IRYrJi5$Ihk!JATkKSD!IS+$HRU!KS4qK)&jI(q#JS@$IRpkHi'%KB1"IRa mIB+'KS0kHB#!Hi51KAGiIAerKBQ)J(GiHhq(LSL#Hh9iJB1*LS&pHhPkK)Q$JS* mHAZ$KS1$K(jfHi1#JiD#IRYjIiD&J)5%H(L#KB&rKB4mHAq%Ihk%K)&qIAprIS# %KB&rIhTkJ)5'Ji5#HRClK)5'LS&jHRKjK)b,K(jeG(b!LC!!LRjdFhCrLBf2JhC cFRL(Nif$J(9VGB12NiCpH(*bI)b2LS"hHRKiKBZ'JB"kGhk"JSD$J(plHi##J)' $Ihk!IRprIS+%JAk#JAPlJ)+%KB5!HhKlJ)1(LS0iGhKlJ)H-LApdGRemJBZ-JRK hHAb!KBf'GhPqHhb(Li&kHRZ!JB'(KAaeIS4rJ)5$IAKmJS1#Ji*mHAk#J)'$JRa iIS1&JAq#JATfJSZ$IS"pHATqJiU(I(YpHAf&Ki9rI(TmJ)''KRjmIAjpJB@#JAa jJ)&qJSD"HRf!I)#%JS"pIRprIi'(JAKmJB&pJSL#HhKqK)'"KB4jGAk%JS1'K(Y eHS5'JS1)I(0mJS+&KS&mHhPrKi+$KRYfIB+#JSD%J(KeKBKqK)L!GRTqIiH%JB5 !HAYrJ)5(JAprHhjrIS5'IRf$J(b#JRq#JS+!I(arIRf'L)#!IRTqJS#(LAekIhT fKSb%Ji"kHAKqLif"IS*eFB'*L)L$IAYfGSD3!)1"KATbGi5+L)1!J(GfJiQ'JS* qGhQ"LB5!JhpiHS1(K)#!JRefIBQ&IB'#IRYmJSD#IS+$Hhf%JAq!JB'!J)'%IhP rKB*rJB0qHRb"K)+$K(jjHi'#JS5%JAPjIi+!JSL'I(ClJS'!LBTpGRKqK)1%L)* hGi#$JSD$IRajI)5'Ji*rHRZ"JB+)JRTkIAq"Ji1&JAGjJi+!K)@!HhYlIi5$JB& qI(b!Ji5#IAamIS'$KB*mHRk!J)1(JhKhIS1!J)L'I(9jJB1&K)@#GR4pKSD%KRp hGhf"K)Q'I(KiI)'%KiGqH(KpJB@&Ji0mGAb&JS#&JRPjIi+$Ji+"IAKmK)@#Ihk !IRPrLS9lIB"lIB1$K)0mHAf!JS@$IhjlHi#$K)9qHRepIB+)JheqI(f"JSD%IRT mIAk&KB+#I(KpJB1)KRakI(KpLBU$IATjIB#%LiGjH(apJ)@(KAphH)#$K)H$Iha iHi1&KB@"HRPqJ)1&JS4qGRZ#Ji5&JRemHRf(KB'$IRPlJB1&KAprIAQ"KS+!JRp lIS#$KS"pJApkJ)H#IhpqJ(jqKSL"I(jpIB1%KB9pHAjrIBH+JAprHAQ"KB@&IRe qGhk*Ki'#J(PmIS'*KRaqJ(KmLBL#J(emIAQ!MSCmIhpjI)'"KiPrHhjmIB+"K)U !H(aqIS'$K)@!HAq$I(q'JRprIS#!I(k%JAq&JRaqIRf#K)+#IhTmIRk%LS*pIha lIS+)KRakJ(jjJBL'JAalIRjmK)H"IhemI)#%Ji'!J(jlIS5$Ii'#I(U!Ji+"JB0 mHS#"JS1#IhaqI(q&JS'"IAU!Jhq!Ji"lHi+&Ihk$J(GmKS0rJB*mH)#&JAk"JRj lI)'%JRq"K(ahIi0rJ)H$H(b#IRk&KhplHhk"Ii#%JRemJ(prJS+"IherJAepKB4 lIi9rHRq$Ii##J)#"I(b#JAb%KhelIhjpJB5%JhekIhjmJSD$JAjjI)*qJ)L$HAZ !IAk%K)*rI(aqJB'$Ji"mI)#!J)5&IhapIAk!JiD#I(b!IRZ&Ki'!IRaqIRq%LAp jJB"mIi1%JhpjIS4pIiD#IAjqIS'!Ii4rHi#$JAq"J)"rHS''J(f"JRjpJ)5$J(q !IRf"Ji'%JRjqIAq"K)1#JAYlIRq$KB5$IAPqJS+#KB0pI(apJS5$K)&mIAppJBH %Ii"pHRq"JS@$IRjrHRk(K)#"J(emIAq'KRjrJRjlIi+#JS+!J(emJB1#JB1$IAa mJ)1$JB#$IhPqKB*rJi0pIApqJB5"J)*pHS+%IRq%JAjqIS1$IAq$IhZ"K(q"JAf "J(aqKS0kJB*mIS+%J)#!IRppJ)1$J(aqIhjqJSH#I(k!IRb"KS0rIRemIi+$Ji* qIAepIiD'IRb!IAPrLBD!IhplH(k%Ki9rIRajHS#)L)0pIAehI)@'K)1!GhPrIS1 (K)&pHRTrJS+%JRjpHRf#JS'%JhTlJhjmJS@"IRapJhplJiL"HAk$IRYrKi4lIS0 rHAb%K(pqJB*mHS#'JAf#JRajJ)4rIi5$IAZ!J)##JB'!Hhb!J(q#K(emIi#!Ii1 &IhGpK(pqJi4rIAjpJS0qK)0mHhq#I)#&K)&lJ)*qIS'#IhprIi+!Ii#!J(q%Jhb !JRalJB@#Ii'#HhU"K)@"J)"pHAU'LB&pIi&kHB+*L(YlJRYfJ)Z(JAjjIApjJC! !L(ClJRPiKBQ(K(YiIhekKSb$IAjpHRf#KSH!I)"rHhq)KAerJAjpJ)5"J(jqJS" pJiKmGS1%Hhq'KRjlI)'%Hi'+JhGkKB"lIiD)I(Q!K(jjKBGrIRk#IheqJiCmIS1 !IAf$JS#!J)0pHS'$J(q%JheqIAq$JB'%JRTlJi&pK)D"HhTrJS"qKSCkH)##IRq (KAjiHi1"IS1+JR0kJi"lK)b!HRTrJRerL)YkFS1#H(f(LAelIB'!Gi+,JRKpKRe kIi5'IRb"JhpjJB0rIi'%Hhb"IRk!K)&pIhf!J(f$KRjiIS0qIS+%KAYfJBClI)Q &HRTmIi0rISL'G(H&JAb!Ki4mGRb(J(U'KhahIB#"Jhb"KAPjJS0mJSClIB"qJ)# #JB"lHiD!IS+"IhYqIi1$Hi'#HhU#L(pqJ(jmHB'%JS*qIReqIB++IhZ!IATrK)+ $JAPmJ(b"Ki0qJ(YjJi*rKS4iH)"pISL'IhplGhk%JS@(IRKkI(k%L)1!IRPlIS' %KS0kIApjISH(Ii##HharJBD$I(b%IRH&L(jmJB"pJRf"L(YjK)4jISGqIS'!J)& rIB*qHi@$IRq#IhU!JB1%IS'$HRH#LAjrKS&kHRq%Ji*rK)&hHi1'JRq$J(elIiL #IS+!HhU%JS#'JAYpJ(arLS0pJhpjISD!J)GpHRpqIi1%Ii+"HAq#IB+'IhZ$IAL 'KRf"KRaiK(jpKi0pIi0lI)@!JS@!IAk"IB##Ii@"Hi#%IAU%K(k!J(q!Ihf!KAp mJi*pI)1$IAk#JhpmJ)'!Ihk$JRjrJ)"pJB+!JAjrJAjrJS*mJ)9mIS5!IB##Ii* qHSD$HAq'J(Q!J)#%IAk&J(GrKherKApqIhemKB0mK)&mIS"pIiQ"HS+!Hhb"K)+ #HRb%IAU#LRpiJB"pIi#$K(jiJ)CkI)H$I(eqIB1!HS@'H(Z&J(f%J(Z#IhQ"KRj qJhamJRjrKB*lIRppJS&rKB0jHi1"I)1$J(jlIS+$J)#%J(alIi5!Ii'"IRb!J)+ #IS#!IRjrJS*rI)'$I(k&J(b!Ihf$Jhf#JRPmK(prKB*mIRamK)+!KS0hHi0mISL 'IRjqHAq#IiD)IAKrJ(Z!L)@!IAamIi##Ki0mIS"pI)5%IB+"I(q"IS#&IRZ&J(Q "KRjpK(pqJRk!Ji&mJS4lIi*rJ)&rIi9rHS5#I)'&J(k%IAZ$JAk$KRjmJRpqJS+ #JRppIi&rJi*qJB&mIB5$Ii+!IB#!Hi+*IhU$JRYmK)@"Ihk$IhKrKi4mIi*qIRf !L)0lIi4pGi1'IS'%J(arIi#&JRk$J(YpJi&rJi*rIRerJi&rKB0kHi1"IB1&J(p pIB+$IS#)J(GqK)"mJiD!IRZ!JhppJSGpH)+%Ihk"JRpqIS'&IRk%J(PrKB'!Jhp qJ(arKB&qJi&jIB0qJ)@!IS&mI)1"IS5%HRb#JB'"J)'"HAZ'JRb#JReqIRk%KRa mKAjhJ)@#J)"rIhplJB9rIB#!IRq"JS*qI)'#I(k&JRPqJhemKS4lJB*lI)+#JB4 mHi5!HB'*JAPrJB"rI)@)HRL$JhQ!LB&pIRYqJRprLB9hI)0pHS5(J(jqIAapJi@ $IRjrIAerK)0rIhk!IAb$Ji&pJ)4jI)5#Ii#$IhprHi#$J(q#JRYqJ(k"JB+#Ihp qIhjrK)'"JAjpJ)"qJS0rIS"qI)1$J)+!IReqIi#&JAq!I(q!J)+&JhYpJReqK)5 !J(plJ)*qJBH"HRk!I)#%JS1"I(f"Ihf'K(arJ(YqJi+!KB"lJB"pJS9rIi0mHS+ #Ii5%IS&rH(q'JAk&KRTmJ(q%JB#$JRajJi0qJi5"IhjmJ)5!J)5!I(f"IS+%J)' !IRerJi'$JAf"J(apK)CqIi&rIAf"Ji0rJ)*qI(q#Ji#"J)+!HAk&JRq"K(jpJ(k "Ji'"JB"pIi"rJi0rJ)"qIS+"JB*rI)'"I(q(JAb!JAprJB#$JhTpJi"mJBCrIB" rIi#!JS0rHi+"Hi'$J(q"IRf%Ihf'JRTqJhelKS*pJS"mIi*rJB4qIS*qIB'#IS' !I)+"I)#&J(U"JAarJB'"IharJhprK)*pIApqJB'!JhjlIi&rIiD$HRk!Ihq!Ji& rI(f$Ihk$K(jlJB&qIi+$IRarJS"qJi4qI(q#Ii#$J(pmHi#$J)#'JAPrJheqK)* qIAerJS"rKB0kHi&rJ)1!J)"pHi'%Ii'$IAarIRk$KAjqJ(emIi+"JS"mIS"qIi5 %Ii"qI)#"Ii#%JAZ"Ihf#JB#"JAepJhjpJS'!JB"qJ)"mJB1!J)+!I)#"Ii+"J)# !IAf$JAq"JAppIi##JRq"J(jpJ)1"JB"rJ(erJi5!IS0rHB#%JAq#JRjqIB#'JAf #JRamJi+"JAk!JAeqKi*lJi4kI)@#Ii+"IS"qIB5%IB#%IhZ!K)'!Ii'#IRf#K(p qJS&qJB1!Ii"qIi#"JB+#I(f#Ihq%JhaqJRerK)*rJAplJS4rJS*rIRprJB4rIi0 qIB'$J(q"Ihq"IS'%JAarK(ppJi4rIAprIi##KS&pIB"qI)5)JRepJ(jpJ)D(IAU "IhZ!Ki1!IheqIRq#KB"pJAjkJB5#IRk"IhemJiCpIB1"Hhk%JB#"IhprIAq%JRk !JRepJS&rJ(pqIi#"JS&qIRppIi5$IRprHhb#Ji1$J(apIAb&KhjrJRYjJ)1"Ji* mIApmJ)5$J)"qHRq#J)+#IhalIS'%JS#$IRPpJi1!JS&pI(aqJi@!Ii&pHRf$JS+ $IhjpIB##K)'!IhjqIB'&JAk!JAapJS#"JB"qIS"qIi+!J)#!J(prIRq"J)'!J)" pI)#$Ihq%JhYkJB"rJS+#J(elIi4qIi@"I(f!Ii#$J)'!HRk#Ii#%JRf!J(b#KB# !JRjmJS"qKB4mI)+!I)+%JS&pIB#"IAq&JRjpJ)'!Ihq%JAYrK)"lJ)0qJ)'!JB# !Ii+!IB1#IRk#JAb!Ji'!IS'$IRb!KAppJi*rIS#"JB"rJS"lJ)5"IB+$IAk!JS* rIS#"I(k&JhprJApqIi'%JAf!JApqJB1!JB"qJ(q!JB+#IB'#I(k#JAq!Jhq!JAk !JRprJi&qJB"rJAprJS*mIi4rIB'#IS##IS##IAk$JAf#JRarJhpqJS&qJB"rJhp mJS0pIB5!HS+"IS'!Ii'#I(k&IRf&JRarJReqJRq!JRjqJAppJi*pJ)*qI)#"J)* rJ)&qIB'$Ihq$IRerJ)#!JS#!Ihb"JAprJS&lIi&qIi##J(pqIS+!IS+"IAk"Ihk #J(q"IRk#J(Z"JhaqK(pmJB&pJ)&rJAppJ)*pIS1"IRpqJ)&qIS'#IAk#Ihk!JRj qJS"qJB&rIi&qIB+!Ii+#IRq#IAk#Ii#"IRq"IRb%K(Z!K(jmJB"qJRppJS&pIi0 rIB&rJB*rJ)&rIB#"I)+$IAf"JRerJS'!IRq!J(pqJi&pJ)+!IB'#Ii"qJ)*rIB+ %I(k%Ihb"JAk!JAq#JAb!JReqK)&qJi&mJ)"pJS*qJB4mHi+!IS+$Ihq!I)##IS' $J(k!J(f"JAq#JRjqJB"qJB'"JS"qIi+!IS+#Ihq!J(q"JB'#J)#"J(k!JS#!JAp rJ)"rJS+!JS"mIi&rIS1#IS"rIi#"JB##J(jrJ)#!JB'!Ihk"JRprJS&qJ)&qJB& rJ)'!IS+#IS+"IRq"JAq!J)##Ihk$J(jrJS'!JS#!J(jrJS"rJB*rIB#!IS'#J)' "IhprIi#$JAf"JRepJB*rJB&rJAjpJB*rIi*rIS&rIi+!IS'"Hhq$IRq#J(k!J(f !JRq"J(jrJ(prJS#!JReqJRpmJ)4rIS&rIRq!JB&rIS'!IRq"JRpqIi'"I)#$J(e rJhjpJS&rIB'"IS"rJB&qIi'!IAq$J(erJS"qJ)+#IAb#JReqJS*pIS#!J(q!JB" qIS&rIS#"J(q!J(prJ)&rIi'!IhprJ(prIi'"IhprJ)"rJ)+#IRk"Ihk!JB'!IRk !J(k!Ji&qIS#!IAk#K(jpJB"pIi+"J)"qJ(pqJ)+!Ii#!IRprJB*rJ)+!I)#$IRk #JRjqJ)#!Ihq#JAprJ)"qJ)#"JAk!JAprJB0rIi&rIRq!JB'"J(prIi#!JS+!IS" rIB##JB'!J(pqIi#$JB#!J(ppJ)+"JB'"Ihk!J)'!Ii+!IRq"J(q"JB"rJ)#"J(q #JRjrJS&rJ)'"J(pqJB&rJ)+!IS#"Ii#"JB"rIi#!Ii#"J)"rIi'!Ii##J(k"JAp rJB'!J(q!JAk!Ji"rJB&qIi'!JB&qJ)&rIS+$IRk"J(q!JB'"Ihk"JAq!JS'!Ihp rJ)#"JB&rIS#!J)##JB#!IRk"JAq!JhpqJ(q!JB#!J)*rIS#!Ihk!JB#!J)#!Ihp rJ)&rJ)'!IhjrJB&rIi'!IB#"Ii#"Ihk!Ihk"JRq!J(prJ)"rJB&qIS#!J(q"JRp qIi#!IS#"JApqJ(prJ(q!JB"pJ)*qIB'"IS#"IS#!IAq#J(f!JRpqJ(q!J(q!JAp qJ)"qJ)&qIi&rIRq"J(q!Ihq!Ihq!JAjqJi"pJ)'!IS#!Ii"qJ)*qIS'"IS#"IRq !Ii#"Ihq!IRk"JB#!JAprIhq"J(k"JAjqJB"rJB"rJ(jrJB"qJ)*rIS#!J)#!Ii# !IS##J)#"J(prJAjrJRprJB"qJ)&qIi*rIi*rIB'"IS##Ii##Ihq"Ihk#JRq!JRj rJAjrJS"rJB"pJ)&rJB&rIi#!J)#!J)*rIB'!Ii#"J(q"IRq"Ii##J(k!JAq!JB# #J(erJRppJS*rIi&rIi'!J)+"Ii#"IRq"J)#"JAprJ(q!JAq"JRprJB&pJ)0rJ)' !Ii#!Ii+#IAq"Ihq"JB#!Ihq"Ihq"JAq!JAprJAq!JRprJB"rJ)"rJ)#!JB&rJ)& pIi+!Ii'"IS#!Ii'"Ii#"Ihf!JAq!J)'!IS#!JB"rJB"rJ)#!Ii#!Ii#!J)#"J(k !J(q"JAq!JAjrJB"rJ)&rIhpqJB&qIi"rIS#"Ii'!IRprJ)#"JAprIRq!J)#!JB" rIRq"J(q"J(prIhq"JAprJ(prJB#!J(jqJ(prJB&rIhprJ)"rJ)"rIS#!IhprJ)" qIi&rJ)&rIS#"Ii#"IRprIRq"JAq!J(erJ)#"JB"rIhjrJB"rJB"qIS'!IS'"Ihk !J(q!J)#"J(jrJApqJB&qIi'!J)"qJ)"rJ)+!IS'!I)##J(q!J(prIS#$J(q"J(e pJ)'"J(q!IherJB'!J)"rIhq!JB"rJ(pqIi'"JB"rIRq!J)'"J(prIi#"JB#!J)" rJ)'!IhprIi"rJ)+!IRprIi'"J)'"IRf"JAq"JAprIhk!JS#!JS"pIi#!JB'!J)" rIi#!J)'!Ii#"J(q"JB#!J)#"J(q!JAq!J)#!J)#!J)"rJB&rJ(pqJ)#"JB#!Ii" rIi'"J)"rIhprJB'"J(prIhq!J)'!J(prJ)#!J)"rIi"rJ)+"IhprIhq"JB'!Ihq !Ii#"JB"rJ(prJB'!Ihq!J)#!JB&rIS"rIi#"J(prIRq!J)'"J(pqIS#"JB'!IRp rIS#"J)#!Ihq!J)#"J(jrIhk!JB#!JApqJ)#!J(q!J(prJ)&rIi#!J(q!JS"qIi# !J)#!J(pqJ)#!J)'!IRprIhq!JB"qIRprJ)#!J(prJ)#!J)'!IRq!J(q!JB"qIRq #JAq!J(jpJ)#!JB"rIhpqJ)'!J)&qIB#!Ii'"IhjqIS#"J)#!IhjrJ)'!J)#!Ihq !J)#!J)"rIi"rIi#!J(prJ)#!Ihq!J(prJ)"rIhprIi#"J(prIhprJ)'!J(jrJ)# !JB&rIi"rIi#!J)"rIi#!Ii#"Ii#"Ihk!J(q!J(q!J(q!JAprJ)"rIi#!J(prJ)" rJ)#!Ii#!Ii#"J(prJ)#!J)#!J(prJ)"rJ)'!IhprJ)#!JB&rIi#!J)#!J)"rIi# !J)#"J(q!Ii#"J)#"Ihk!J(q!JB#!J(q!JB'!J)"rIi"rJ)#!J)#!J)#!Ii#!J(q "JAprJ)#!J)#!JApqJ)"rJ)#"JB"qJ)"rJ)'!J(q!J)"rJ)&rIi'"Ihq!J(prJB' !Ihq!J(q"JB#!IhprIi#!JB#!J(prJ)'!Ii#!Ihk!JB"rJ)"rJ)#"JB"rIhprJ)# !J)"rIi#!JB"rIi"rIi#"J(prJ)"qJ)+!IRq!Ii#!J)#!IRq!IRq"JAprJ)"rIi' #Ihk!JAjrJB"rIi#!Ii#!J(prJ)"rIi#!J(jrJB"qJ)&rIRq!J(prJ)"qIi#!Ii' !Ihq!IhprJ)"rIRq!Ihq"JB"qIi#!Ii#"Ihk!Ihq!JB"rJ(q!J(k!JApqJ)'!J)# !IhprJ)&rIi&rIi#!Ihq!J(pqJ)#!Ihq!J(prJ)'!Ihq!Ii#!J)#!Ihq!Ihq!J)# !IhprJ(q!JB"rIhprJ)#!J)"rIRprJ)#"J(prIhprJ)'!IhprIhprJB'!Ihq!Ihq !J)#!J(q!J(q!J(q!J(prJ)#!J)#!J(prJ)"rIi#!J)"rIi"rJ)#!Ii"rIi#!J)" rIi"rIi#"Ihq!J)#!Ii#"Ihq!J(q!JAprJ)#!J)#"J(prJAprJB&rIhq!J(prJB& rIi#!Ii#!JB"qJ)'!Ii#!Ii#!J)"rJ)'!Ihq"J(q!J)"rIi#!Ii#!J(q!Ii#!J)# "Ihq!J(q!JB"rJ(prJB#!JB"rJ)"rJ)#!J)"qIi#!J)#!IhprIi#"J(q!J)"rIi' !J(q!J)#!Ii#!Ihq!J(q!Ihq!J)"rIi#!Ihq!J(prJ(prIi#!J)#!J(q!J)#!Ii# !Ihq!JAprJ)"rIi#!J)"rIi#!Ii#"IhprIi"rJ)#!IhprIhq!J)"rIi"rIi#"JAp rJ)"rIS#"IhjrJ(prJ)'!IRk"J(k!JApqIhq!J(q"JAjqIi"rIi+!IRprJ)"rJB+ !IRq!Ihq!JB"rIhprIhq!JAprJ)"qIi'!Ihq!J(prJ)#!IRq"J(jrJ)"rIi#!J(p rJ)"rJ)"rIi'!IS#"IhjrJ)#!J)#!IhjrJB"rJB"qIhq!J)#!J)"qIi'!Ii#"Ihk !J)#!Ihq!Ihk!JB#!IhprIi#!JB'!Ihq!Ii#"JB"rIhq!J)#"JApqIhprJB'!Ihp rIi#!JB&rIS#!IRq#JApqJ)"rIi#"J(jrJ)"rJB&rIS#!Ihq"J(prIi#"Ihq#JAj rJB"rJ)#!J(prJB"rJ)"rIi'!Ihq!J(q!JB'!Ihq!J(q!JS"rIi"rIi#!J)"rIi# !Ii#"Ihq!J(q!J)#!Ihq!J(q!JApqJ)#!J)#"J(prJ)"rJ)#!J(prJ)#!JB&rIhp rJB"rJ)"rIi#!Ii#!IhprIi'"Ihq"J(jrJB'!Ihq!Ihq!JB"rJ)"rIi#!J)"rJ(p rJ)'!IhprIhjrJB&rIi#!Ihq!JB"rIi&rIi#!Ii#!Ii"rIi#!Ihq"Ihq!J)"rIi# !J(q!J(prJ)#!J(prJ(prJ)"rJ(prIhq!J)"rJ(prIi"rJ)"rIi"rIi#!IhprIhq !Ii#!IRq!J(q!JB"rIhq!Ii#"J(jqJ)"rJ)'!IhjrJ(prJB&qIRq!J)#!JB"pIS# !J)#!J(pqIi'!J)'!IRq!Ii#!J)"rIRq"J(q!J(prIi#!J(q!J(prJ(q!J(prIhq !JB"rJ(prIhq!J)"rJ)"rJ)#!J)#!IhprIi#!J)"rIi#!Ii#!J)"rIi#!Ihq!J(q !Ii#!Ihq!Ihq!J(q!Ihq!J(q!JAprJ(q!J)#!JB"rJ)"rJ)#!J)#!J)"rJ)#!Ii# !J)"rJ)#!Ii#!J(q!Ii"rIi#!Ihq!J)#!J)"rIi#!J(q"JAprJ)"rJ)#!J(prJ)# !J)"rIi"rJ)#!J)"rIi"rIi#!IhprIi"rIi'!Ihq!J(q!J)#!Ii#!Ii#!J(prJ(p rJ(q!J(prJ(prJ)#!J(q!J(prJ)"rIi"rIhq!J)"rIi#!Ii"rJ)#!Ii"rIi#!Ii# !Ii#!Ihq!Ihq!J(q!J(q!Ihq!J(prJ(prJ)#!J(prJ)"rJ)"rJ)"rJ)#!J(prJ)" rIi#!J)"rJ)"rIi#!Ii#!Ihq!Ihq!Ihq!J(q!Ihq!J(q!Ihq!J(q!J(q!J(prJ(q !J)"rJ(prIi#!J)"rIhprJ)&rIhprIi#!J)"rIi#!Ii#"J(q!Ii#!Ii#!J(prIhq !Ihq!IhprJ(q!J)"rIhprIi#!J(prJ(prJ)"rIhprJ)"rJ)#!IhprJ)"rIi"rIi# !Ihq!IhprIi#!Ii#!J(q!J)"rIi#!Ii#!J(prIi#"J)#"J(jrJ(q!JB"rIhprJ(q !JB"rIi"rJ(q!J(prJ)"rIi'!Ii#!Ii#!J)#!Ii#!J)#!Ihq!Ii#!J)#!Ihq!JB# !J(prIhq!J(q!J(prJ)#!J(prJ)"rJ)"rJ)"rIi#!Ii#!Ihq!Ii#!J)"rIi#!J(p rJ)"rIi#"J(q!J(prIi#!J(q!J(prJ)#!Ii#!J(q!J)"rJ)"rIi"rIi#!Ii"rJ)# !Ii#!Ii#!J(prJ)"rIi#!Ihq!J(q!J)#!J)#!J(q!J)"rIi#!Ii#!J(q!J(q!J)" rIi#!Ii#!IhprIi#!Ihq!J(prJ)"rJ)"rJ)"rJ)"rIi#!Ihq!J)#!Ii"rIi#!J(q !Ii#!Ihq!J(q!J)"rJ(q!Ihq!J(q!J(q!J(q!J)"rJ(prIi"rJ)"rIhprJ)#!Ii" rIi#!Ii#!Ihq!Ihq!J)#!J(prJ)"rJ)"rJ(prJ(q!J(q!J(prJ)#!J(prJ(prIi# !Ihq!J)#!J)"rJ)"rJ)#!Ii"rIi"rIi"rJ)"rIi#!Ihq!J(prIi#!IhprJ(prIi# !Ihq!J(prIi"rJ(q!J(prJ(prJ(prJ(prIi#!J)#!Ii"rIi#!J(q!IhprJ)#!J)" rIi"rJ(q!J(q!Ihq!J)#!J)#!Ii#!J)#!IhprJ)#!J)"rJ)#!J)#!J(prJ)"rIi# !J(prJ)#!Ii#!IhprJ)"rIi"rIi#!J)#!J(prIi#!Ii#!IhprJ(q!J)"rIhq!J(q !Ii#!Ii"rJ)#!J(prJ)"rJ)#!Ii"rIi#!J)#!Ihq!J)#!Ii"rIi#!Ii#!Ii#!Ihq !J(q!J(prJ)"rJ)#!Ii#!Ihq!J)"rJ)"rIi#!J)"rIi#!Ii#!J(q!Ihq!J(prJ(q !J(q!J(q!J(q!J)#!J(prJ)"rJ)"rJ)"rIi#!J)"rIhq!Ii#!J)#!Ihq!Ihq!J(p rIhprJ)#!J(prJ(q!J)"rIi"rIi#!J)#!IhprIi#!J)#!IhprJ)#!Ii#!IhprJ(q !Ii"rIhprIi"rIi"rIi#!J(prJ)"rIhprJ)#!Ii#!Ii"rIi#!Ii#!Ihq!J(prJ(p rIi"rJ)"rJ(prJ)#!J(prJ)"rJ)#!Ii"rIhq!Ii#!J(prJ(q!J)"rIi#!J)"rJ)# !Ii#!Ihq!Ihq!Ii#!Ii#!Ihq!J(q!J(prJ)#!J)#!J(prJ)"rIi"rIi#!J)"rJ)# !Ii#!J(prJ)"rIi#!J)"rIi"rIi#!Ihq!Ihq!J)#!J(q!Ihq!J)#!J)"rJ)#!J)# !J)"rJ)#!J)"rIi#!Ii#!J)#!Ihq!J)#!J)"rIi"rJ)#!J(q!J(q!J)#!J)"rJ(q !J)"rJ)"rIi#!J(prJ)"rJ)#!Ii#!Ii#!J)#!Ihq!J(q!J)"rJ)"rJ)#!J)#!Ihq !J)#!J)#!Ii"rJ)#!J)#!Ii#!J)#!J(prJ)#!J)#!J)#!Ii#!J)#!J(q!Ii#!J)# !J)"rIi#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)#!J)# !J)#!J)#!J)#!J)#!J)#!J!!!!3!!!`U%!!-*K!!!!8%!di-8&i)!!!!F!,B!!(0 ZC#!!#`!+90m!!#!!!!!!di(S8%N!$#!!0d3!di(`4!-!&b!!HBJ!di(N*8S!)b! ![-`!di(J8L8!-#!"!hS!di(FGdN!Ib!"5,i!di(B,83!2b!"G3)!di(8+f3!FL! "R8B!di(38KX!5L!"dBS!di(-++X!9#!#!-i!di()2VF!Cb!#N[`!di(%C'd!E5! #ad!!di(!#e4[EfaPC#")Eh*Z#NeKCfPM)%KKFR!,6@&RD@-J4QaeG'8-6'9KG'K PFL"%FR9Y$NK[FQiJ6fBJ8'aPER4j#NCbEh0d)%K[FQi*4QPbC5")Eh*Z%N4bG@d J6fBJ4@&bG'KaG@&VC39#G@GXC34#C@aX$&G[Ef4PEL"'E(9dC3YAEfpNC@iJ5'& bF"31: nethack-3.4.3/sys/mac/News0100644000000000000000000000054007764735041014066 0ustar rootrootWelcome to NetHack 3.4 for MacOS 7.0 - 9.x Unfortunately, the 68k version is no longer supported. This game is brought to you by Dean Luick, Kevin Hugo, and Mark Modrall. Bug reports, suggestions, comments, etc., should be e-mailed to the Internet address nethack-bugs@nethack.org, or fill out our comment form on the web at http://www.nethack.org. nethack-3.4.3/sys/mac/README0100644000000000000000000000261407764735041014113 0ustar rootrootJan 2002 The MPW compilers are now supported again. Support for 68k has been discontinued due to a lack of a debugging system for 68k binaries. Note that the tiled MacOS X port uses the Qt windowport and the UNIX build system, not this windowport code. 26 Nov, 1999 NetHack 3.3.0 was built with Metrowerk's Pro 4 compiler on a PPC system. We are still compiling with 68K alignment because we know it works. No one has checked lately if the PPC alignment bug still exists. 23 May, 1996 NetHack 3.2.1 was built with Metrowerk's DR8 compiler on a PPC system. The official 68K and PPC versions were compiled with 68K Alignment to share files. The 3.2.0 versions were compiled with PPC alignment, but it was discovered that the Metrowerks 68K compiler has a bug with PPC alignment and structures that can be aligned to a single byte. This bug _may_ be fixed in DR10, it is not fixed in DR9. Why bother with PPC alignment at all? Because the space saving from 68K alignment is small and the PowerPC version will run better. The 68K version was compiled with 4 byte ints using the far model. Only the Metrowerks compiler has been used to compile the code in a long time. It is _very_ likely that the other compilers, Think C and MPW C, will no longer be able to compile NetHack out of the box. They and their files have been moved to the "old" directory until such time that someone can compile with them. nethack-3.4.3/sys/mac/dprintf.c0100644000000000000000000000201507764735041015040 0ustar rootroot/* SCCS Id: @(#)dprintf.c 3.1 94/01/29 */ /* Copyright (c) Jon W{tte, 1993. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "macwin.h" static Boolean KeyDown (unsigned short code) { unsigned char keys [16]; GetKeys ((void *) keys); return ((keys [code >> 3] >> (code & 7)) & 1) != 0; } void dprintf (char *format, ...) { char buffer [500]; va_list list; int doit; #define DO_DEBUGSTR 1 #define DO_PLINE 2 if (flags.debug) { doit = 0; if (macFlags.hasDebugger && KeyDown (0x39)) { /* Caps Lock */ doit = DO_DEBUGSTR; } else if (KeyDown (0x3B) && iflags.window_inited && /* Control */ (WIN_MESSAGE != -1) && theWindows [WIN_MESSAGE].its_window) { doit = DO_PLINE; } if (doit) { va_start (list, format); vsprintf (&buffer [1], format, list); va_end (list) ; if (doit == DO_DEBUGSTR) { buffer [0] = strlen (&buffer [1]); DebugStr ((uchar *) buffer); } else if (doit == DO_PLINE) pline ("%s", &buffer [1]); } } } nethack-3.4.3/sys/mac/maccurs.c0100644000000000000000000001017707764735041015037 0ustar rootroot/* SCCS Id: @(#)maccurs.c 3.1 93/01/24 */ /* Copyright (c) Jon W{tte, 1992. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mactty.h" #include "macwin.h" #if !TARGET_API_MAC_CARBON #include #include #include #endif static Boolean winFileInit = 0; static unsigned char winFileName [32] = "\pNetHack Preferences"; static long winFileDir; static short winFileVol; typedef struct WinPosSave { char validPos; char validSize; short top; short left; short height; short width; } WinPosSave; static WinPosSave savePos [kLastWindowKind + 1]; static void InitWinFile (void) { StringHandle sh; long len; short ref = 0; if (winFileInit) { return; } /* We trust the glue. If there's an error, store in game dir. */ if (FindFolder (kOnSystemDisk, kPreferencesFolderType, kCreateFolder , &winFileVol, &winFileDir)) { winFileVol = 0; winFileDir = 0; } sh = GetString (128); if (sh && *sh) { BlockMove (*sh, winFileName, **sh + 1); ReleaseResource ((Handle) sh); } if (HOpen (winFileVol, winFileDir, winFileName, fsRdPerm, &ref)) { return; } len = sizeof (savePos); if (!FSRead (ref, &len, savePos)) { winFileInit = 1; } FSClose (ref); } static void FlushWinFile (void) { short ref; long len; if (!winFileInit) { if (!winFileName [0]) { return; } HCreate (winFileVol, winFileDir, winFileName, MAC_CREATOR, PREF_TYPE); HCreateResFile (winFileVol, winFileDir, winFileName); } if (HOpen (winFileVol, winFileDir, winFileName, fsWrPerm, &ref)) { return; } winFileInit = 1; len = sizeof (savePos); (void) FSWrite (ref, &len, savePos); /* Don't care about error */ FSClose (ref); } Boolean RetrievePosition (short kind, short *top, short *left) { Point p; if (kind < 0 || kind > kLastWindowKind) { dprintf ("Retrieve Bad kind %d", kind); return 0; } InitWinFile (); if (!savePos [kind].validPos) { dprintf ("Retrieve Not stored kind %d", kind); return 0; } p.v = savePos [kind].top; p.h = savePos [kind].left; *left = p.h; *top = p.v; dprintf ("Retrieve Kind %d Pt (%d,%d)", kind, p.h, p.v); return (PtInRgn (p, GetGrayRgn ())); } Boolean RetrieveSize (short kind, short top, short left, short *height, short *width) { Point p; if (kind < 0 || kind > kLastWindowKind) { return 0; } InitWinFile (); if (!savePos [kind].validSize) { return 0; } *width = savePos [kind].width; *height = savePos [kind].height; p.h = left + *width; p.v = top + *height; return PtInRgn (p, GetGrayRgn ()); } static void SavePosition (short kind, short top, short left) { if (kind < 0 || kind > kLastWindowKind) { dprintf ("Save bad kind %d", kind); return; } InitWinFile(); savePos[kind].validPos = 1; savePos[kind].top = top; savePos[kind].left = left; dprintf("Save kind %d pt (%d,%d)", kind, left, top); FlushWinFile(); } static void SaveSize (short kind, short height, short width) { if (kind < 0 || kind > kLastWindowKind) { dprintf ("Save bad kind %d", kind); return; } InitWinFile (); savePos [kind].validSize = 1; savePos [kind].width = width; savePos [kind].height = height; FlushWinFile (); } static short GetWinKind (WindowPtr win) { short kind; if (!CheckNhWin (win)) { return -1; } kind = GetWindowKind(win) - WIN_BASE_KIND; if (kind < 0 || kind > NHW_TEXT) { return -1; } dprintf ("In win kind %d (%lx)", kind, win); switch (kind) { case NHW_MAP : case NHW_STATUS : case NHW_BASE : kind = kMapWindow; break; case NHW_MESSAGE : kind = kMessageWindow; break; case NHW_MENU : kind = kMenuWindow; break; default : kind = kTextWindow; break; } dprintf ("Out kind %d", kind); return kind; } Boolean RetrieveWinPos(WindowPtr win, short *top, short *left) { return RetrievePosition(GetWinKind (win), top, left); } void SaveWindowPos(WindowPtr win) { Rect r; GetWindowBounds(win, kWindowContentRgn, &r); SavePosition(GetWinKind(win), r.top, r.left); } void SaveWindowSize(WindowPtr win) { short width, height; Rect r; GetWindowBounds(win, kWindowContentRgn, &r); width = r.right - r.left; height = r.bottom - r.top; SaveSize(GetWinKind (win), height, width); } nethack-3.4.3/sys/mac/macerrs.c0100644000000000000000000000770507764735041015041 0ustar rootroot/* SCCS Id: @(#)macerrs.c 3.1 93/01/24 */ /* Copyright (c) Michael Hamel, 1991 */ /* NetHack may be freely redistributed. See license for details. */ #if defined(macintosh) && defined(__SC__) && !defined(__FAR_CODE__) /* this needs to be resident always */ #pragma segment Main #endif #include "hack.h" #include "macwin.h" #if !TARGET_API_MAC_CARBON #include #include #include #endif void error(const char *format,...) { Str255 buf; va_list ap; va_start(ap, format); vsprintf((char *)buf, format, ap); va_end(ap); C2P((char *)buf, buf); ParamText(buf, (StringPtr)"", (StringPtr)"", (StringPtr)""); Alert(128, (ModalFilterUPP) NULL); ExitToShell(); } #if 0 /* Remainder of file is obsolete and will be removed */ #define stackDepth 1 #define errAlertID 129 #define stdIOErrID 1999 static Str255 gActivities[stackDepth] = {""}; static short gTopactivity = 0; void showerror(char * errdesc, const char * errcomment) { short itemHit; Str255 paserr, pascomment; SetCursor(&qd.arrow); if (errcomment == nil) errcomment = ""; C2P (errcomment, pascomment); C2P (errdesc, paserr); ParamText(paserr,pascomment,gActivities[gTopactivity],(StringPtr)""); itemHit = Alert(errAlertID, (ModalFilterUPP)nil); } Boolean itworked(short errcode) /* Return TRUE if it worked, do an error message and return false if it didn't. Error strings for native C errors are in STR#1999, Mac errs in STR 2000-errcode, e.g 2108 for not enough memory */ { if (errcode != 0) { short itemHit; Str255 errdesc; StringHandle strh; errdesc[0] = '\0'; if (errcode > 0) GetIndString(errdesc,stdIOErrID,errcode); /* STDIO file rres, etc */ else { strh = GetString(2000-errcode); if (strh != (StringHandle) nil) { memcpy(errdesc,*strh,256); ReleaseResource((Handle)strh); } } if (errdesc[0] == '\0') { /* No description found, just give the number */ sprintf((char *)&errdesc[1],"a %d error occurred",errcode); errdesc[0] = strlen((char*)&errdesc[1]); } SetCursor(&qd.arrow); ParamText(errdesc,(StringPtr)"",gActivities[gTopactivity],(StringPtr)""); itemHit = Alert(errAlertID, (ModalFilterUPP)nil); } return(errcode==0); } void mustwork(short errcode) /* For cases where we can't recover from the error by any means */ { if (itworked(errcode)) ; else ExitToShell(); } #if defined(USE_STDARG) || defined(USE_VARARGS) # ifdef USE_STDARG static void vprogerror(const char *line, va_list the_args); # else static void vprogerror(); # endif /* Macro substitute for error() */ void error VA_DECL(const char *, line) VA_START(line); VA_INIT(line, char *); vprogerror(line, VA_ARGS); VA_END(); } # ifdef USE_STDARG static void vprogerror(const char *line, va_list the_args) { # else static void vprogerror(line, the_args) const char *line; va_list the_args; { # endif #else /* USE_STDARG | USE_VARARG */ void error VA_DECL(const char *, line) #endif /* Do NOT use VA_START and VA_END in here... see above */ char pbuf[BUFSZ]; if(index(line, '%')) { Vsprintf(pbuf,line,VA_ARGS); line = pbuf; } showerror("of an internal error",line); } void attemptingto(char * activity) /* Say what we are trying to do for subsequent error-handling: will appear as x in an alert in the form "Could not x because y" */ { C2P(activity,gActivities[gTopactivity]); } void comment(char *s, long n) { Str255 paserr; short itemHit; sprintf((char *)&paserr[1], "%s - %d",s,n); paserr[0] = strlen ((char*)&paserr[1]); ParamText(paserr,(StringPtr)"",(StringPtr)"",(StringPtr)""); itemHit = Alert(128, (ModalFilterUPP)nil); } void pushattemptingto(char * activity) /* Push a new description onto stack so we can pop later to previous state */ { if (gTopactivity < stackDepth) { gTopactivity++; attemptingto(activity); } else error("activity stack overflow"); } void popattempt(void) /* Pop to previous state */ { if (gTopactivity > 1) --gTopactivity; else error("activity stack underflow"); } #endif /* Obsolete */ nethack-3.4.3/sys/mac/macfile.c0100644000000000000000000002161207764735041014776 0ustar rootroot/* SCCS Id: @(#)macfile.c 3.1 93/01/24 */ /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */ /* NetHack may be freely redistributed. See license for details. */ /* * macfile.c * MAC file I/O routines */ #include "hack.h" #include "macwin.h" #ifndef __MACH__ #include #include #include #include #include #include #endif #include "dlb.h" /* * We should get the default dirID and volRefNum (from name) from prefs and * the situation at startup... For now, this will have to do. */ /* The HandleFiles are resources built into the application which are treated as read-only files: if we fail to open a file we look for a resource */ #define FIRST_HF 32000 /* file ID of first HandleFile */ #define MAX_HF 6 /* Max # of open HandleFiles */ #define APP_NAME_RES_ID (-16396) typedef struct handlefile { long type; /* Resource type */ short id; /* Resource id */ long mark; /* Current position */ long size; /* total size */ Handle data; /* The resource, purgeable */ } HandleFile; static HandleFile *FDECL(IsHandleFile,(int)); static int FDECL(OpenHandleFile,(const unsigned char *, long)); static int FDECL(CloseHandleFile,(int)); static int FDECL(ReadHandleFile,(int, void *, unsigned)); static long FDECL(SetHandleFilePos,(int, short, long)); HandleFile theHandleFiles [MAX_HF]; MacDirs theDirs; /* also referenced in macwin.c */ static HandleFile * IsHandleFile(int fd) { HandleFile *hfp = NULL; if (fd >= FIRST_HF && fd < FIRST_HF+MAX_HF) { /* in valid range, check for data */ hfp = &theHandleFiles[fd-FIRST_HF]; if (!hfp->data) hfp = NULL; } return hfp; } static int OpenHandleFile (const unsigned char *name, long fileType) { int i; Handle h; Str255 s; for (i = 0; i < MAX_HF; i ++) { if (theHandleFiles[i].data == 0L) break; } if (i >= MAX_HF) return -1; h = GetNamedResource (fileType, name); if (!h) return (-1); theHandleFiles[i].data = h; theHandleFiles[i].size = GetHandleSize (h); GetResInfo (h, &theHandleFiles[i].id, (void*) &theHandleFiles[i].type, s); theHandleFiles[i].mark = 0L; return(i + FIRST_HF); } static int CloseHandleFile (int fd) { if (!IsHandleFile (fd)) { return -1; } fd -= FIRST_HF; ReleaseResource (theHandleFiles[fd].data); theHandleFiles[fd].data = 0L; return(0); } static int ReadHandleFile (int fd, void *ptr, unsigned len) { unsigned maxBytes; Handle h; if (!IsHandleFile (fd)) return -1; fd -= FIRST_HF; maxBytes = theHandleFiles[fd].size - theHandleFiles[fd].mark; if (len > maxBytes) len = maxBytes; h = theHandleFiles[fd].data; HLock(h); BlockMove (*h + theHandleFiles[fd].mark, ptr, len); HUnlock(h); theHandleFiles[fd].mark += len; return(len); } static long SetHandleFilePos (int fd, short whence, long pos) { long curpos; if (!IsHandleFile (fd)) return -1; fd -= FIRST_HF; curpos = theHandleFiles [fd].mark; switch (whence) { case SEEK_CUR : curpos += pos; break; case SEEK_END : curpos = theHandleFiles[fd].size - pos; break; default : /* set */ curpos = pos; break; } if (curpos < 0) curpos = 0; else if (curpos > theHandleFiles [fd].size) curpos = theHandleFiles [fd].size; theHandleFiles [fd].mark = curpos; return curpos; } void C2P (const char *c, unsigned char *p) { int len = strlen (c), i; if (len > 255) len = 255; for (i = len; i > 0; i--) p[i] = c[i-1]; p[0] = len; } void P2C (const unsigned char *p, char *c) { int idx = *p++; for (; idx > 0; idx--) *c++ = *p++; *c = '\0'; } static void replace_resource(Handle new_res, ResType its_type, short its_id, Str255 its_name) { Handle old_res; SetResLoad(false); old_res = Get1Resource(its_type, its_id); SetResLoad(true); if (old_res) { RemoveResource(old_res); DisposeHandle(old_res); } AddResource(new_res, its_type, its_id, its_name); } int maccreat (const char *name, long fileType){ return macopen (name, O_RDWR | O_CREAT | O_TRUNC, fileType); } int macopen (const char *name, int flags, long fileType) { short refNum; short perm; Str255 s; C2P (name, s); if (flags & O_CREAT) { if (HCreate (theDirs.dataRefNum, theDirs.dataDirID, s , TEXT_CREATOR, fileType) && (flags & O_EXCL)) { return -1; } if (fileType == SAVE_TYPE) { short resRef; HCreateResFile(theDirs.dataRefNum, theDirs.dataDirID, s); resRef = HOpenResFile(theDirs.dataRefNum, theDirs.dataDirID, s, fsRdWrPerm); if (resRef != -1) { Handle name; Str255 plnamep; C2P(plname, plnamep); name = (Handle)NewString(plnamep); if (name) replace_resource(name, 'STR ', PLAYER_NAME_RES_ID, "\pPlayer Name"); /* The application name resource. See IM VI, page 9-21. */ name = (Handle)GetString(APP_NAME_RES_ID); if (name) { DetachResource(name); replace_resource(name, 'STR ', APP_NAME_RES_ID, "\pApplication Name"); } CloseResFile(resRef); } } } /* * Here, we should check for file type, maybe a SFdialog if * we fail with default, etc. etc. Besides, we should use HOpen * and permissions. */ if ((flags & O_RDONLY) == O_RDONLY) { perm = fsRdPerm; } if ((flags & O_WRONLY) == O_WRONLY) { perm = fsWrPerm; } if ((flags & O_RDWR) == O_RDWR) { perm = fsRdWrPerm; } if (HOpen (theDirs.dataRefNum, theDirs.dataDirID, s, perm, &refNum)) { return OpenHandleFile (s, fileType); } if (flags & O_TRUNC) { if (SetEOF (refNum, 0L)) { FSClose (refNum); return -1; } } return refNum; } int macclose (int fd) { if (IsHandleFile (fd)) { CloseHandleFile (fd); } else { if (FSClose (fd)) { return -1; } FlushVol ((StringPtr) 0, theDirs . dataRefNum); } return 0; } int macread (int fd, void *ptr, unsigned len) { long amt = len; if (IsHandleFile (fd)) { return ReadHandleFile (fd, ptr, amt); } else { short err = FSRead (fd, &amt, ptr); return ((err == noErr) || (err == eofErr && len)) ? amt : -1; } } #if 0 /* this function isn't used, if you use it, uncomment prototype in macwin.h */ char * macgets (int fd, char *ptr, unsigned len) { int idx = 0; char c; while (-- len > 0) { if (macread (fd, ptr + idx, 1) <= 0) return (char *)0; c = ptr[idx++]; if (c == '\n' || c == '\r') break; } ptr [idx] = '\0'; return ptr; } #endif /* 0 */ int macwrite (int fd, void *ptr, unsigned len) { long amt = len; if (IsHandleFile (fd)) return -1; if (FSWrite(fd, &amt, ptr) == noErr) return (amt); else return (-1); } long macseek (int fd, long where, short whence) { short posMode; long curPos; if (IsHandleFile (fd)) { return SetHandleFilePos (fd, whence, where); } switch (whence) { default : posMode = fsFromStart; break; case SEEK_CUR : posMode = fsFromMark; break; case SEEK_END : posMode = fsFromLEOF; break; } if (SetFPos(fd, posMode, where) == noErr && GetFPos(fd, &curPos) == noErr) return (curPos); else return(-1); } int macunlink(const char *name) { Str255 pname; C2P(name, pname); return (HDelete(theDirs.dataRefNum, theDirs.dataDirID, pname) == noErr ? 0 : -1); } /* ---------------------------------------------------------------------- */ boolean rsrc_dlb_init(void) { return TRUE; } void rsrc_dlb_cleanup(void) { } boolean rsrc_dlb_fopen(dlb *dp, const char *name, const char *mode) { #if defined(__SC__) || defined(__MRC__) # pragma unused(mode) #endif Str255 pname; C2P(name, pname); dp->fd = OpenHandleFile(pname, 'File'); /* automatically read-only */ return dp->fd >= 0; } int rsrc_dlb_fclose(dlb *dp) { return CloseHandleFile(dp->fd); } int rsrc_dlb_fread(char *buf, int size, int quan, dlb *dp) { int nread; if (size < 0 || quan < 0) return 0; nread = ReadHandleFile(dp->fd, buf, (unsigned)size * (unsigned)quan); return nread/size; /* # of whole pieces (== quan in normal case) */ } int rsrc_dlb_fseek(dlb *dp, long pos, int whence) { return SetHandleFilePos(dp->fd, whence, pos); } char *rsrc_dlb_fgets(char *buf, int len, dlb *dp) { HandleFile *hfp = IsHandleFile(dp->fd); char *p; int bytesLeft, n = 0; if (hfp && hfp->mark < hfp->size) { bytesLeft = hfp->size - hfp->mark; if (bytesLeft < len) len = bytesLeft; HLock(hfp->data); for (n = 0, p = *hfp->data+hfp->mark; n < len; n++, p++) { buf[n] = *p; if (*p == '\r') buf[n] = '\n'; if (buf[n] == '\n') { n++; /* we want the return in the buffer */ break; } } HUnlock(hfp->data); hfp->mark += n; if (n != 0) buf[n] = '\0'; /* null terminate result */ } return n ? buf : NULL; } int rsrc_dlb_fgetc(dlb *dp) { HandleFile *hfp = IsHandleFile(dp->fd); int ret; if (!hfp || hfp->size <= hfp->mark) return EOF; ret = *(unsigned char *)(*hfp->data + hfp->mark); hfp->mark++; return ret; } long rsrc_dlb_ftell(dlb *dp) { HandleFile *hfp = IsHandleFile(dp->fd); if (!hfp) return 0; return hfp->mark; } nethack-3.4.3/sys/mac/machelp.hqx0100644000000000000000000001025407764735041015365 0ustar rootroot(This file must be converted with BinHex 4.0) :#QeKBfKPE(!ZBQJ!9%9B9%0A588"#!!!#PX!!!'XRNmM#90$3e-J5@3k)%!S)bP YB@0SC@a`,Q*S#6-Z-`Nj15m`-bma03dM#80[F(PbD@GSG#!SBbNJ-6Nj1#da16N j)'*j)%YPGQPZ)%KeCfm0)b"1CA4)B@0V)'eKH5"LC5"QFQ9PE(NJFQ9NDA0dFQP LGA4PC#iJ)&0PC5"XD@0PER0P)'C[FL"NCA4KD@ac,Jd0$5-M)b""FfYZB@eP)'4 TB@a[Cb!M)b-04%P"6%p()$B`-$!JBA0VEQ&YC3d0)b"3E'&j)'*eG(4[EJda,Q9 ZB@*XC@3J3faTBfXJD'9bC5"dEb"`E'&j)(4SDA-JBfKKFQ&MG'9b,Jda,Q4TFf& LE'9N)%0XD@0V)'KPFQ8JG'mJF'aKH5"dD'Pc)'0SBA*KBh4PFLl#$5!J6Qpd)'& fB@PXB@*XC5"LC@0KGA0P)(P[G5"SBACPELGd)(4jF'9N)'PZ)'%JEQ&YC5i0$5- J8A9TG#"LGA4dEfi0-LiU)%0XD@0V)'KPFQ8JG'mJFA9TG#"dD'8JF(*[Ch*KE5i 0$5-J8QpXC5"`Eh"eF#"YC@je$63Z+L"6C@aPBh3JH@peFL"NCA0TFQ9N)(*[E'8 J+%&bBfKPEfa[CfPcG#`J3Q&bBQ&bD@&Z,#"PG'-Z+F)0)(GTG'JJG'KTFb"`Eh" eF#"YC@je,Jd0)b"5B@0P)("[F(9`)'ePER8005iU)&0PE'9MG#"jEh9b)'4PFfP bC@3JFQ&MC5!S5(9YB@iX)%9XCL`JCA4M,LR#$5"hDA4S)(4SDA-JF'p`GA!JE@9 ZG5i0$5-J4f9ZC'9b)("[F(9`)'ePER800LiU)&0PE'9MG#"jEh9b)'GPEQ4PFL! SE@&XC5"[FL"QC@eKE'8T)(GTG'JJG'KTFb"`Eh"eF#"YC@je,Jd0)b""E'PREQe PER3JF'p`GA!JE@9ZG3dh,LSJ8f9XC@0d)(P[GA)JB@aTCfjYC@jd)#KXBAGQG@` X)'jPGA4bB@`X)'pb)'0SB@pdD@-T`JdJGfPdD#"dD'Pc)("[F(9`)'ePER8Z$3d M)%e[C'8JF'p`GA!JE@9ZG3di,LSJ9A0P)(4SDA-JF'p`GA!JE@9ZG5"dEb"cC@a PBh3JFQ9RG@aKFL"`E'&j)'e[C'8X`JdJCAK`E'pbC5"YEf4P,#"[FL"NC@*eCfG TEQFJE@pNC5i0$5-J6Q&YC5"dCAKd)'PdC@d015iU)&4jF'8JD@iJH@peFL"MD'& bB@0dCA)RFb"ZB@eP)'KPFQ8Z$3dM)%PMEfi0-6!Z+L"AD'mJDA-JG'KTFb"RGAN r$3e&6N3Y4%P"6%p($3d0689195!a-MJJ3A"`E'80$6%ZC@jKBQaPC#"%DA0`E'& jFb"TEQC[FQeKG'P[EL"KBQpeG#"dD'Pc)(CPFR0TEfiZ$3e&6N3Y689193d0$8e &6P8J-6)j)%CTE'80$6!ZC@jKBQaPC#"'D@aP)%ePERA#`P9cC5"dD'Pc)'ePER8 JG'mJE@&ZDA"eE'&dC5"hD@jNEhGc`JdJEfiJG'KP)(0MFQ9PEL`JB@jN)(4[)(0 KGQ8JEh)JFA9TG#"dD'8JCf&YC5i0$6%Z+L"0B@YPFb"dD'8JE@&`)'&`F'9KFL" [EL"dD'8JFf0bC@9Z,#"TEL"MBA0P)(P[G5"ME'pcC@6#$5"TG(-JGfPZC'ph,Jd 0-LiU)%C[FQ0PFb"dD'8JE@&`)(4[)'*P)(*PC(*KGfiZ$3dc,LSJ8f0bEfaXFb" dD'8J6@9cFf&RCA-JGfPZC'ph)'*KBfXJEfjP)'ePFh0KCf8Z$3dd,LSJ8Q9`Eh0 TG'P[ER-JB@aX)(GTEQ4[Gh-JFfmJG'KPH5"KFQ8JEfiYFf0bC@9Z,Jd005iU)%0 XEh0PFb"dD'8JCR*[ER4YEh0d)(GTEQ4[Gbi0$6JZ+L"&ER4PFR-JCAK`E'pbC5" YEf4P,#"hD'PMD#"TFb"K)'G[Ef3JGf&j)(4[)'aPBA*Z)(4SC5"RB@eP,Jd0-6! Z+L"6BACPFb"dD'8JCf&YC5`JB@jN)(4SC@iJFA9TG(-JG'KP)("bEfGbB@dZ$3d a-LiU)&&eDA4c)(4SC5"`FQpRFQ&Y)(GTG'K[GA3JFf&fD@jR)(4SC5"RB@eP,Jd 048j%,8e&6P80$3e048j9)$%c-#"&C'Pd$3d`,Q9ZB@*XC@3J4@4TG#"0C@je`X* 9Ff8JG'KTFb"YC@je)(4[)'9NDA3JG'9iG#"[FL"eEQ4[`JdJB@iJB@0dD@pZ,Jd `,Q4TFf&LE'9N)%9NDA3J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"PC'Pd)(4PH(3 JEh)JG@jNEm)0)'&Z)'&MG'P[ELiJ)%&fB@PXB@*XC5"[EQaj)'C[FL"NCA0V)'& MBf9cFfpbD@9c,Jd048j%,8e&6P80$3e048j9)$%c-5",BQ30$6!ZC@jKBQaPC#" ,CAPLEf&bC#"0C@je`X*9Ff8JG'KTFb"YC@je)(4[)(0TEA9XBA4P`JdJF(*PFh0 TEQFJDf9jFb"[EL"K)'YPH@*[BA*N,#"cEb"jEh8JBf&Z)("XBANJC@jdDA*PE(R #$5"LH5"YEh9cC5i0$8914#e048j9$3d0689195!a-c)J5'9XF!d0-#jPEQ&LE'9 N)%KPE(!J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"PH("XB@PZ)'K[Gm)0)(4SC5" RB@eP)(G[FQYc,#"[FL"dEb"cCA3JEh"dD@pZFbi0$8914#e048j9$3d0689195! a-c-J5@jQE`d0-#jPEQ&LE'9N)%PZCQmJ6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb" XEfpV)'&d)'pb`JdJE@&ZDA"eE'&dC5"jEh9b)'PZGQ9ZG'pbH5`JCAK`E'&TEL" cEfePG'KTEQFJEfiJG'KP`JdJFf0bC@9Z,#"[FL"RDACP)'&Z)'pLDQ9MG#"[FL" YEfjcG'9b)'%JEQ&YC5i0$8914#e048j9$3d0689195!a-c3J4A&eDA!0$6!ZC@j KBQaPC#"&FA9TF'ePER3J6@9ZGF,#9A0P)(4SDA-JE@9ZG5"dEb"YB@jTF(9XBA4 P`JdJGf9KF'pZFb`JBA*YEh)X)'&ZC#"[G'KPFL"hEh*Z)'PdC@ec,Jd048j%,8e &6P80$3e048j9)$%c05""Bh30$6!ZC@jKBQaPC#""Bh4TEfiJ6@9ZGF,#9A0P)(4 SDA-JE@9ZG5"dEb"`CA*QEh*Y)'&Z)'&MG'P[ELi0$8914#e048j9$3d0689195! a-cBJ6@&RD@-0$6!ZC@jKBQaPC#"0B@GTBb"0C@je`X*9Ff8JG'KTFb"YC@je)(4 [)'eKEQP`G@aKG'8JE@&RD@2#$5"TG'9YFbi0$8914#e048j9$3e048j9)$%c0b" #DA4c$3d`,Q9ZB@*XC@3J3QPdFb"0C@je`X*9Ff8JG'KTFb"YC@je)(4[)("PFQC [FQh#$5"YDA0MC@aXB@jPEh9c)'&MG'P[ER-Z$3e&6N3Y689193d048j%$5dp!!! "!!!!!9S!!!"D!!!!8KY`!4m!6VVdjL!ZrqU`RfF-2`B["5m-U"YJ!!$+9Bmr#Qe KBfKPE(!ZBQKbUL"*4%8J8(*PCR0TEfjMCA0PFfi!$&4&@&4$9dP&!3Mrrrrr!!! !!!!!!!!!!!!!!!!!!!K$XNab!!!!#PX!!!'XmNkkqQSq(fCU9Bmr,[r`5'lrpNK ZrrK)E[rm6VVpU$iICP"9Mh!!,`!r"Lm&6VVkKMiICJS[$+Qa9BqTVciIF!+`V[r iCKC9Mh!!,`!r,[r`,blrmNkkqPik(f!39Bp`!#m!2blrm%kkpFJk(dT(CJ)q"6( (#Q"-lK$JrpT1AL"I6`!!!%J!#8e[EQ&ME`!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!)!"!!V!+F"dJ*H!#X!T`(5!Pkc58b!!!!!!!!!#PX!!!!!!3!!!!!#!!! !!!!%!!%!!!!!!3!!!!&D!!!!@J!!!&)"ITa%(YS!!!!F!&)!!8e38e)!!3!569G #3J!!!#S$lIrr!!!!!!!!!!!$lrrr!!!!6!!!!!!$m2rr!!!!8J!!!!#PK!: nethack-3.4.3/sys/mac/macmain.c0100644000000000000000000001430107764735041015000 0ustar rootroot/* SCCS Id: @(#)macmain.c 3.1 97/01/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* main.c - Mac NetHack */ #include "hack.h" #include "dlb.h" #include "macwin.h" #include "mactty.h" #if !TARGET_API_MAC_CARBON #include #include #include #include #include #include #include #include #endif #ifndef O_RDONLY #include #endif static void finder_file_request(void); int main(void); #if __SC__ || __MRC__ QDGlobals qd; #endif int main (void) { register int fd = -1; int argc = 1; windowprocs = mac_procs; InitMac (); hname = "Mac Hack"; hackpid = getpid(); /* * Initialisation of the boundaries of the mazes * Both boundaries have to be even. */ x_maze_max = COLNO-1; if (x_maze_max % 2) x_maze_max--; y_maze_max = ROWNO-1; if (y_maze_max % 2) y_maze_max--; setrandom(); initoptions(); init_nhwindows(&argc, (char **)&hname); /* * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ finder_file_request (); dlb_init(); /* must be before newgame() */ /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); #ifdef WIZARD if (wizard) Strcpy(plname, "wizard"); else #endif if(!*plname || !strncmp(plname, "player", 4) || !strncmp(plname, "games", 4)) askname(); plnamesuffix(); /* strip suffix from name; calls askname() */ /* again if suffix was whole name */ /* accepts any suffix */ Sprintf (lock, "%d%s", getuid (), plname); getlock (); if ((fd = restore_saved_game()) >= 0) { #ifdef WIZARD /* Since wizard is actually flags.debug, restoring might * overwrite it. */ boolean remember_wiz_mode = wizard; #endif #ifdef NEWS if(iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; /* in case dorecover() fails */ } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ game_active = 1; if (dorecover(fd)) { #ifdef WIZARD if(!wizard && remember_wiz_mode) wizard = TRUE; #endif check_special_room(FALSE); if (discover || wizard) { if(yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else { compress(fqname(SAVEF, SAVEPREFIX, 0)); } } } else { fd = -1; /* set bad status */ } } if (fd < 0) { player_selection(); game_active = 1; /* done with selection, draw active game window */ newgame(); set_wear(); (void) pickup(1); } if (discover) You("are in non-scoring discovery mode."); flags.move = 0; UndimMenuBar (); /* Yes, this is the place for it (!) */ moveloop(); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } static OSErr copy_file(short src_vol, long src_dir, short dst_vol, long dst_dir, Str255 fName, pascal OSErr (*opener)(short vRefNum, long dirID, ConstStr255Param fileName, signed char permission, short *refNum)) { short src_ref, dst_ref; OSErr err = (*opener)(src_vol, src_dir, fName, fsRdPerm, &src_ref); if (err == noErr) { err = (*opener)(dst_vol, dst_dir, fName, fsWrPerm, &dst_ref); if (err == noErr) { long file_len; err = GetEOF(src_ref, &file_len); if (err == noErr) { Handle buf; long count = MaxBlock(); if (count > file_len) count = file_len; buf = NewHandle(count); err = MemError(); if (err == noErr) { while (count > 0) { OSErr rd_err = FSRead(src_ref, &count, *buf); err = FSWrite(dst_ref, &count, *buf); if (err == noErr) err = rd_err; file_len -= count; } if (file_len == 0) err = noErr; DisposeHandle(buf); } } FSClose(dst_ref); } FSClose(src_ref); } return err; } static void force_hdelete(short vol, long dir, Str255 fName) { HRstFLock(vol, dir, fName); HDelete (vol, dir, fName); } void process_openfile (short src_vol, long src_dir, Str255 fName, OSType ftype) { OSErr err = noErr; if (ftype != SAVE_TYPE) return; /* only deal with save files */ if (src_vol != theDirs.dataRefNum || src_dir != theDirs.dataDirID && CatMove(src_vol, src_dir, fName, theDirs.dataDirID, "\p:") != noErr) { HCreate(theDirs.dataRefNum, theDirs.dataDirID, fName, MAC_CREATOR, SAVE_TYPE); err = copy_file(src_vol, src_dir, theDirs.dataRefNum, theDirs.dataDirID, fName, &HOpen); /* HOpenDF is only there under 7.0 */ if (err == noErr) err = copy_file(src_vol, src_dir, theDirs.dataRefNum, theDirs.dataDirID, fName, &HOpenRF); if (err == noErr) force_hdelete(src_vol, src_dir, fName); else HDelete(theDirs.dataRefNum, theDirs.dataDirID, fName); } if (err == noErr) { short ref; ref = HOpenResFile(theDirs.dataRefNum, theDirs.dataDirID, fName, fsRdPerm); if (ref != -1) { Handle name = Get1Resource('STR ', PLAYER_NAME_RES_ID); if (name) { Str255 save_f_p; P2C(*(StringHandle)name, plname); set_savefile_name(); C2P(fqname(SAVEF, SAVEPREFIX, 0), save_f_p); force_hdelete(theDirs.dataRefNum, theDirs.dataDirID, save_f_p); if (HRename(theDirs.dataRefNum, theDirs.dataDirID, fName, save_f_p) == noErr) macFlags.gotOpen = 1; } CloseResFile(ref); } } } static void finder_file_request(void) { if (macFlags.hasAE) { /* we're capable of handling Apple Events, so let's see if we have any */ EventRecord event; long toWhen = TickCount () + 20; /* wait a third of a second for all initial AE */ while (TickCount () < toWhen) { if (WaitNextEvent (highLevelEventMask, &event, 3L, 0)) { AEProcessAppleEvent(&event); if (macFlags.gotOpen) break; } } } #if 0 #ifdef MAC68K else { short finder_msg, file_count; CountAppFiles(&finder_msg, &file_count); if (finder_msg == appOpen && file_count == 1) { OSErr err; AppFile src; FSSpec filespec; GetAppFiles(1, &src); err = FSMakeFSSpec(src.vRefNum, 0, src.fName, &filespec); if (err == noErr && src.fType == SAVE_TYPE) { process_openfile (filespec.vRefNum, filespec.parID, filespec.name, src.fType); if (macFlags.gotOpen) ClrAppFiles(1); } } } #endif /* MAC68K */ #endif /* 0 */ } /*macmain.c*/ nethack-3.4.3/sys/mac/macmenu.c0100644000000000000000000007131007764735041015023 0ustar rootroot/* SCCS Id: @(#)macmenu.c 3.4 1999/11/24 */ /* Copyright (c) Macintosh NetHack Port Team, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /****************************************\ * Extended Macintosh menu support * * provides access to all keyboard commands from cmd.c * provides control key functionality for classic keyboards * provides key equivalent references and logical menu groups * supports various menu highlighting modes \****************************************/ /****************************************\ * Edit History: * * 930512 - More bug fixes and getting tty to work again, Jon W{tte * 930508 - Bug fixes in-flight, Jon W{tte * 04/29/93 - 1st Release Draft, David Hairston * 04/11/93 - 1st Draft, David Hairston \****************************************/ /******** Application Defines ********/ #include "hack.h" #include "mactty.h" #include "macwin.h" #include "macpopup.h" #include "patchlevel.h" /******** Toolbox Defines ********/ #if !TARGET_API_MAC_CARBON #include #include #include #include #include #include #endif /* Borrowed from the Mac tty port */ extern WindowPtr _mt_window; /******** Local Defines ********/ /* 'MNU#' (menu list record) */ typedef union menuRefUnn { short mresID; /* MENU resource ID (before GetMenu) */ MenuHandle mhnd; /* MENU handle (after GetMenu) */ } menuRefUnn; typedef struct menuListRec { short firstMenuID; short numMenus; menuRefUnn mref[]; } menuListRec, *menuListPtr, **menuListHandle; /* indices and resource IDs of the menu list data */ enum { listMenubar, listSubmenu, menuBarListID = 128, subMenuListID }; /* the following mref[] indices are reserved */ enum { /* menu bar */ menuApple, menuFile, menuEdit, /* submenu */ menuWizard = 0 }; /* the following menu items are reserved */ enum { /* apple */ menuAppleAboutBox = 1, ____Apple__1, /* File */ menuFileRedraw = 1, menuFilePrevMsg, menuFileCleanup, ____File___1, menuFilePlayMode, menuFileEnterExplore, ____File___2, menuFileSave, ____File___3, menuFileQuit, /* standard minimum Edit menu items */ /* Wizard */ menuWizardAttributes = 1 }; /* * menuListRec data (preloaded and locked) specifies the number of menus in * the menu bar, the number of hierarchal or submenus and the menu IDs of * all of those menus. menus that go into in the menu bar are specified by * 'MNU#' 128 and submenus are specified by 'MNU#' 129. the fields of the * menuListRec are: * firstMenuID - the menu ID (not resource ID) of the 1st menu. subsequent * menus in the list are _forced_ to have consecutively incremented IDs. * numMenus - the total count of menus in a given list (and the extent of * valid menu IDs). * mref[] - initially the MENU resource ID is stored in the placeholder for * the resource handle. after loading (GetResource), the menu handle * is stored and the menu ID, in memory, is set as noted above. * * NOTE: a ResEdit template editor is supplied to edit the 'MNU#' resources. * * NOTE: the resource IDs do not need to match the menu IDs in a menu list * record although they have been originally set that way. * * NOTE: the menu ID's of menus in the submenu list record may be reset, as * noted above. it is the programmers responsibility to make sure that * submenu references/IDs are valid. * * WARNING: the existence of the submenu list record is assumed even if the * number of submenus is zero. also, no error checking is done on the * extents of the menu IDs. this must be correctly setup by the programmer. */ #define ID1_MBAR pMenuList[listMenubar]->firstMenuID #define ID1_SUBM pMenuList[listSubmenu]->firstMenuID #define NUM_MBAR pMenuList[listMenubar]->numMenus #define NUM_SUBM pMenuList[listSubmenu]->numMenus #define MHND_APPLE pMenuList[listMenubar]->mref[menuApple].mhnd #define MHND_FILE pMenuList[listMenubar]->mref[menuFile].mhnd #define MHND_EDIT pMenuList[listMenubar]->mref[menuEdit].mhnd #define MBARHND(x) pMenuList[listMenubar]->mref[(x)].mhnd #define MHND_WIZ pMenuList[listSubmenu]->mref[menuWizard].mhnd /* mutually exclusive (and prioritized) menu bar states */ enum { mbarDim, mbarNoWindows, mbarDA, mbarNoMap, mbarRegular, mbarSpecial /* explore or debug mode */ }; #define WKND_MAP (WIN_BASE_KIND + NHW_MAP) /* menu routine error numbers */ enum { errGetMenuList, errGetMenu, errGetANDlogTemplate, errGetANDlogItems, errGetANDialog, errANNewMenu, err_Menu_total }; /* menu 'STR#' comment char */ #define mstrEndChar 0xA5 /* '\245' or option-* or "bullet" */ /* 'ALRT' */ enum { alrt_Menu_start = 5000, alrtMenuNote = alrt_Menu_start, alrtMenu_NY, alrt_Menu_limit }; #define beepMenuAlertErr 1 /* # of SysBeep()'s before exitting */ enum { bttnMenuAlertNo = 1, bttnMenuAlertYes }; /******** Globals ********/ static unsigned char *menuErrStr[err_Menu_total] = { "\pAbort: Bad \'MNU#\' resource!", /* errGetMenuList */ "\pAbort: Bad \'MENU\' resource!", /* errGetMenu */ "\pAbort: Bad \'DLOG\' resource!", /* errGetANDlogTemplate */ "\pAbort: Bad \'DITL\' resource!", /* errGetANDlogItems */ "\pAbort: Bad Dialog Allocation!", /* errGetANDialog */ "\pAbort: Bad Menu Allocation!", /* errANNewMenu */ }; static menuListPtr pMenuList[2]; static short theMenubar = mbarDA; /* force initial update */ static short kAdjustWizardMenu = 1; /******** Prototypes ********/ #if !TARGET_API_MAC_CARBON static void alignAD(Rect *, short); #endif static void mustGetMenuAlerts(void); static void menuError(short); static void aboutNetHack(void); static void askSave(void); static void askQuit(void); /*** Askname dialog box ***/ #define RSRC_ASK 6000 /* Askname dialog and item list */ #define RSRC_ASK_PLAY 1 /* Play button */ #define RSRC_ASK_QUIT 2 /* Quit button */ #define RSRC_ASK_DEFAULT 3 /* Default ring */ #define RSRC_ASK_ROLE 4 /* Role popup menu */ #define RSRC_ASK_RACE 5 /* Race popup menu */ #define RSRC_ASK_GEND 6 /* Gender popup menu */ #define RSRC_ASK_ALIGN 7 /* Alignment popup menu */ #define RSRC_ASK_MODE 8 /* Mode popup menu */ #define RSRC_ASK_NAME 9 /* Name text field */ #define RSRC_ASK_MAX 10 /* Maximum enabled item */ #define KEY_MASK 0xff00 #define KEY_RETURN 0x2400 #define KEY_ENTER 0x4c00 #define KEY_ESCAPE 0x3500 #define CH_MASK 0x00ff #define CH_RETURN 0x000d #define CH_ENTER 0x0003 #define CH_ESCAPE 0x001b static void ask_restring(const char *cstr, unsigned char *pstr); static void ask_enable(DialogRef wind, short item, int enable); static pascal void ask_redraw(DialogRef wind, DialogItemIndex item); static pascal Boolean ask_filter(DialogRef wind, EventRecord *event, DialogItemIndex *item); #define noresource(t,n) {SysBeep(3); ExitToShell();} #define fatal(s) {SysBeep(3); ExitToShell();} static MenuHandle askmenu[RSRC_ASK_MAX]; static int askselect[RSRC_ASK_MAX]; #define currrole askselect[RSRC_ASK_ROLE] #define currrace askselect[RSRC_ASK_RACE] #define currgend askselect[RSRC_ASK_GEND] #define curralign askselect[RSRC_ASK_ALIGN] #define currmode askselect[RSRC_ASK_MODE] static RGBColor blackcolor = {0x0000, 0x0000, 0x0000}, // indentcolor = {0x4000, 0x4000, 0x4000}, darkcolor = {0x8000, 0x8000, 0x8000}, backcolor = {0xdddd, 0xdddd, 0xdddd}, lightcolor = {0xffff, 0xffff, 0xffff}, whitecolor = {0xffff, 0xffff, 0xffff}; /* Convert a mixed-case C string to a Capitalized Pascal string */ static void ask_restring (const char *cstr, unsigned char *pstr) { int i; for (i = 0; *cstr && (i < 255); i++) pstr[i+1] = *cstr++; pstr[0] = i; if ((pstr[1] >= 'a') && (pstr[1] <= 'z')) pstr[1] += 'A' - 'a'; return; } /* Enable the dialog item with the given index */ static void ask_enable (DialogRef wind, short item, int enable) { short type; Handle handle; Rect rect; /* Enable or disable the appropriate item */ GetDialogItem(wind, item, &type, &handle, &rect); if (enable) type &= ~itemDisable; else type |= itemDisable; HiliteControl((ControlHandle)handle, enable ? 0 : 255); SetDialogItem(wind, item, type, handle, &rect); return; } static pascal void ask_redraw (DialogRef wind, DialogItemIndex item) { short type; Handle handle; Rect rect; static char *modechar = "NED"; /* Which item shall we redraw? */ GetDialogItem(wind, item, &type, &handle, &rect); switch (item) { case RSRC_ASK_DEFAULT: PenSize(3, 3); FrameRoundRect(&rect, 16, 16); break; case RSRC_ASK_ROLE: case RSRC_ASK_RACE: case RSRC_ASK_GEND: case RSRC_ASK_ALIGN: case RSRC_ASK_MODE: if (macFlags.color) { RGBForeColor(&blackcolor); RGBBackColor(&backcolor); } PenNormal(); TextMode(srcOr); EraseRect(&rect); /* Draw the frame and drop shadow */ rect.right--; rect.bottom--; FrameRect(&rect); MoveTo(rect.right, rect.top+1); LineTo(rect.right, rect.bottom); LineTo(rect.left+1, rect.bottom); /* Draw the menu character */ MoveTo(rect.left+4, rect.top+12); switch (item) { case RSRC_ASK_ROLE: DrawText(roles[askselect[item]].filecode, 0, 3); break; case RSRC_ASK_RACE: DrawText(races[askselect[item]].filecode, 0, 3); break; case RSRC_ASK_GEND: DrawText(genders[askselect[item]].filecode, 0, 3); break; case RSRC_ASK_ALIGN: DrawText(aligns[askselect[item]].filecode, 0, 3); break; case RSRC_ASK_MODE: DrawChar(modechar[askselect[item]]); break; } /* Draw the popup symbol */ MoveTo(rect.right - 16, rect.top + 5); LineTo(rect.right - 6, rect.top + 5); LineTo(rect.right - 11, rect.top + 10); LineTo(rect.right - 15, rect.top + 6); LineTo(rect.right - 8, rect.top + 6); LineTo(rect.right - 11, rect.top + 9); LineTo(rect.right - 13, rect.top + 7); LineTo(rect.right - 10, rect.top + 7); LineTo(rect.right - 11, rect.top + 8); /* Draw the shadow */ InsetRect(&rect, 1, 1); if (macFlags.color) { RGBColor color; /* Save the foreground color */ GetForeColor(&color); /* Draw the top and left */ RGBForeColor(&lightcolor); MoveTo(rect.left, rect.bottom-1); LineTo(rect.left, rect.top); LineTo(rect.right-1, rect.top); /* Draw the bottom and right */ RGBForeColor(&darkcolor); MoveTo(rect.right-1, rect.top+1); LineTo(rect.right-1, rect.bottom-1); LineTo(rect.left+1, rect.bottom-1); /* Restore the foreground color */ RGBForeColor(&color); } break; case RSRC_ASK_NAME: PenNormal(); if (macFlags.color) { RGBForeColor(&whitecolor); RGBBackColor(&whitecolor); TextMode(srcOr); } else { PenMode(notPatCopy); TextMode(srcBic); } InsetRect(&rect, -1, -1); FrameRect(&rect); InsetRect(&rect, -1, -1); FrameRect(&rect); InsetRect(&rect, -2, -2); if (macFlags.color) { /* Draw the top and left */ RGBForeColor(&darkcolor); MoveTo(rect.left, rect.bottom-1); LineTo(rect.left, rect.top); LineTo(rect.right-1, rect.top); /* Draw the bottom and right */ RGBForeColor(&lightcolor); MoveTo(rect.right-1, rect.top+1); LineTo(rect.right-1, rect.bottom-1); LineTo(rect.left+1, rect.bottom-1); /* Restore the colors */ RGBForeColor(&blackcolor); RGBBackColor(&backcolor); } break; } return; } static pascal Boolean ask_filter (DialogRef wind, EventRecord *event, DialogItemIndex *item) { short ch, key; switch (event->what) { case keyDown: case autoKey: ch = event->message & CH_MASK; key = event->message & KEY_MASK; /* Handle equivalents for OK */ if ((ch == CH_RETURN) || (key == KEY_RETURN) || (ch == CH_ENTER) || (key == KEY_ENTER)) { if (GetDialogTextEditHandle(wind)[0]->teLength) { FlashButton(wind, RSRC_ASK_PLAY); *item = RSRC_ASK_PLAY; } else *item = 0; return (TRUE); } /* Handle equivalents for Normal/Explore/Debug */ if ((event->modifiers & cmdKey) && (ch == 'n')) { currmode = 0; ask_redraw(wind, RSRC_ASK_MODE); *item = RSRC_ASK_MODE; return (TRUE); } if ((event->modifiers & cmdKey) && (ch == 'e')) { currmode = 1; ask_redraw(wind, RSRC_ASK_MODE); *item = RSRC_ASK_MODE; return (TRUE); } if ((event->modifiers & cmdKey) && (ch == 'd')) { currmode = 2; ask_redraw(wind, RSRC_ASK_MODE); *item = RSRC_ASK_MODE; return (TRUE); } /* Handle equivalents for Cancel and Quit */ if ((ch == CH_ESCAPE) || (key == KEY_ESCAPE) || ((event->modifiers & cmdKey) && (ch == 'q')) || ((event->modifiers & cmdKey) && (ch == '.'))) { FlashButton(wind, RSRC_ASK_QUIT); *item = RSRC_ASK_QUIT; return (TRUE); } return (FALSE); case updateEvt: ask_redraw(wind, RSRC_ASK_NAME); return (FALSE); default: return (FALSE); } } void mac_askname () { GrafPtr oldport; DialogRef askdialog; short i, j, item, type; Handle handle; Rect rect; Str255 str; Point pt; UserItemUPP redraw = NewUserItemUPP(ask_redraw); ModalFilterUPP filter = NewModalFilterUPP(ask_filter); /* Create the dialog */ if (!(askdialog = GetNewDialog(RSRC_ASK, NULL, (WindowRef)-1))) noresource('DLOG', RSRC_ASK); GetPort(&oldport); SetPortDialogPort(askdialog); /* Initialize the name text item */ ask_restring(plname, str); if (plname[0]) { GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); SetDialogItemText(handle, str); } #if 0 { Str32 pName; pName [0] = 0; if (plname && plname [0]) { strcpy ((char *) pName, plname); c2pstr ((char *) pName); } else { Handle h; h = GetResource ('STR ', -16096); if (((Handle) 0 != h) && (GetHandleSize (h) > 0)) { DetachResource (h); HLock (h); if (**h > 31) { **h = 31; } BlockMove (*h, pName, **h + 1); DisposeHandle (h); } } if (pName [0]) { GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); SetDialogItemText(handle, pName); if (pName [0] > 2 && pName [pName [0] - 1] == '-') { short role = (*pANR).anMenu[anRole]; char suffix = (char) pName[pName[0]], *sfxindx = strchr(pl_classes, suffix); if (sfxindx) role = (short) (sfxindx - pl_classes); else if (suffix == '@') role = (short) rn2((int) strlen(pl_classes)); (*pANR).anMenu[anRole] = role; } } } #endif SelectDialogItemText(askdialog, RSRC_ASK_NAME, 0, 32767); /* Initialize the role popup menu */ if (!(askmenu[RSRC_ASK_ROLE] = NewMenu(RSRC_ASK_ROLE, "\p"))) fatal("\pCannot create role menu"); for (i = 0; roles[i].name.m; i++) { ask_restring(roles[i].name.m, str); AppendMenu(askmenu[RSRC_ASK_ROLE], str); } InsertMenu(askmenu[RSRC_ASK_ROLE], hierMenu); if (flags.initrole >= 0) currrole = flags.initrole; /* Check for backward compatibility */ else if ((currrole = str2role(pl_character)) < 0) currrole = randrole(); /* Initialize the race popup menu */ if (!(askmenu[RSRC_ASK_RACE] = NewMenu(RSRC_ASK_RACE, "\p"))) fatal("\pCannot create race menu"); for (i = 0; races[i].noun; i++) { ask_restring(races[i].noun, str); AppendMenu(askmenu[RSRC_ASK_RACE], str); } InsertMenu(askmenu[RSRC_ASK_RACE], hierMenu); if (flags.initrace >= 0) currrace = flags.initrace; else currrace = randrace(currrole); /* Initialize the gender popup menu */ if (!(askmenu[RSRC_ASK_GEND] = NewMenu(RSRC_ASK_GEND, "\p"))) fatal("\pCannot create gender menu"); for (i = 0; i < ROLE_GENDERS; i++) { ask_restring(genders[i].adj, str); AppendMenu(askmenu[RSRC_ASK_GEND], str); } InsertMenu(askmenu[RSRC_ASK_GEND], hierMenu); if (flags.initgend >= 0) currgend = flags.initgend; else if (flags.female) currgend = 1; else currgend = randgend(currrole, currrace); /* Initialize the alignment popup menu */ if (!(askmenu[RSRC_ASK_ALIGN] = NewMenu(RSRC_ASK_ALIGN, "\p"))) fatal("\pCannot create alignment menu"); for (i = 0; i < ROLE_ALIGNS; i++) { ask_restring(aligns[i].adj, str); AppendMenu(askmenu[RSRC_ASK_ALIGN], str); } InsertMenu(askmenu[RSRC_ASK_ALIGN], hierMenu); if (flags.initalign >= 0) curralign = flags.initalign; else curralign = randalign(currrole, currrace); /* Initialize the mode popup menu */ if (!(askmenu[RSRC_ASK_MODE] = NewMenu(RSRC_ASK_MODE, "\p"))) fatal("\pCannot create mode menu"); AppendMenu(askmenu[RSRC_ASK_MODE], "\pNormal"); AppendMenu(askmenu[RSRC_ASK_MODE], "\pExplore"); #ifdef WIZARD AppendMenu(askmenu[RSRC_ASK_MODE], "\pDebug"); #endif InsertMenu(askmenu[RSRC_ASK_MODE], hierMenu); currmode = 0; /* Set the redraw procedures */ for (item = RSRC_ASK_DEFAULT; item <= RSRC_ASK_MODE; item++) { GetDialogItem(askdialog, item, &type, &handle, &rect); SetDialogItem(askdialog, item, type, (Handle)redraw, &rect); } /* Handle dialog events */ do { /* Adjust the Play button */ ask_enable(askdialog, RSRC_ASK_PLAY, GetDialogTextEditHandle(askdialog)[0]->teLength); /* Adjust the race popup menu */ i = j = currrace; do { if (validrace(currrole, j)) { EnableMenuItem(askmenu[RSRC_ASK_RACE], j+1); CheckMenuItem(askmenu[RSRC_ASK_RACE], j+1, currrace == j); } else { DisableMenuItem(askmenu[RSRC_ASK_RACE], j+1); CheckMenuItem(askmenu[RSRC_ASK_RACE], j+1, FALSE); if ((currrace == j) && !races[++currrace].noun) currrace = 0; } if (!races[++j].noun) j = 0; } while (i != j); if (currrace != i) { GetDialogItem(askdialog, RSRC_ASK_RACE, &type, &handle, &rect); InvalWindowRect(GetDialogWindow(askdialog), &rect); } /* Adjust the gender popup menu */ i = j = currgend; do { if (validgend(currrole, currrace, j)) { EnableMenuItem(askmenu[RSRC_ASK_GEND], j+1); CheckMenuItem(askmenu[RSRC_ASK_GEND], j+1, currgend == j); } else { DisableMenuItem(askmenu[RSRC_ASK_GEND], j+1); CheckMenuItem(askmenu[RSRC_ASK_GEND], j+1, FALSE); if ((currgend == j) && (++currgend >= ROLE_GENDERS)) currgend = 0; } if (++j >= ROLE_GENDERS) j = 0; } while (i != j); if (currgend != i) { GetDialogItem(askdialog, RSRC_ASK_GEND, &type, &handle, &rect); InvalWindowRect(GetDialogWindow(askdialog), &rect); } /* Adjust the alignment popup menu */ i = j = curralign; do { if (validalign(currrole, currrace, j)) { EnableMenuItem(askmenu[RSRC_ASK_ALIGN], j+1); CheckMenuItem(askmenu[RSRC_ASK_ALIGN], j+1, curralign == j); } else { DisableMenuItem(askmenu[RSRC_ASK_ALIGN], j+1); CheckMenuItem(askmenu[RSRC_ASK_ALIGN], j+1, FALSE); if ((curralign == j) && (++curralign >= ROLE_ALIGNS)) curralign = 0; } if (++j >= ROLE_ALIGNS) j = 0; } while (i != j); if (curralign != i) { GetDialogItem(askdialog, RSRC_ASK_ALIGN, &type, &handle, &rect); InvalWindowRect(GetDialogWindow(askdialog), &rect); } /* Adjust the role popup menu */ for (i = 0; roles[i].name.m; i++) { ask_restring((currgend && roles[i].name.f) ? roles[i].name.f : roles[i].name.m, str); SetMenuItemText(askmenu[RSRC_ASK_ROLE], i+1, str); CheckMenuItem(askmenu[RSRC_ASK_ROLE], i+1, currrole == i); } /* Adjust the mode popup menu */ CheckMenuItem(askmenu[RSRC_ASK_MODE], 1, currmode == 0); CheckMenuItem(askmenu[RSRC_ASK_MODE], 2, currmode == 1); #ifdef WIZARD CheckMenuItem(askmenu[RSRC_ASK_MODE], 3, currmode == 2); #endif /* Wait for an action on an item */ ModalDialog(filter, &item); switch (item) { case RSRC_ASK_PLAY: break; case RSRC_ASK_QUIT: currmode = -1; break; case RSRC_ASK_ROLE: case RSRC_ASK_RACE: case RSRC_ASK_ALIGN: case RSRC_ASK_GEND: case RSRC_ASK_MODE: GetDialogItem(askdialog, item, &type, &handle, &rect); pt = *(Point *)▭ LocalToGlobal(&pt); if (!!(i = PopUpMenuSelect(askmenu[item], pt.v, pt.h, askselect[item] + 1))) askselect[item] = LoWord(i) - 1; InvalWindowRect(GetDialogWindow(askdialog), &rect); break; case RSRC_ASK_NAME: #if 0 /* limit the data here to 25 chars */ { short beepTEDelete = 1; while ((**dRec.textH).teLength > 25) { if (beepTEDelete++ <= 3) SysBeep(3); TEKey('\b', dRec.textH); } } /* special case filter (that doesn't plug all the holes!) */ if (((**dRec.textH).teLength == 1) && (**((**dRec.textH).hText) < 32)) TEKey('\b', dRec.textH); #endif break; } } while ((item != RSRC_ASK_PLAY) && (item != RSRC_ASK_QUIT)); /* Process the name */ GetDialogItem(askdialog, RSRC_ASK_NAME, &type, &handle, &rect); GetDialogItemText(handle, str); if (str[0] > PL_NSIZ-1) str[0] = PL_NSIZ-1; BlockMove(&str[1], plname, str[0]); plname[str[0]] = '\0'; /* Destroy the dialog */ for (i = RSRC_ASK_ROLE; i <= RSRC_ASK_MODE; i++) { DeleteMenu(i); DisposeMenu(askmenu[i]); } SetPort(oldport); DisposeDialog(askdialog); DisposeRoutineDescriptor(filter); DisposeRoutineDescriptor(redraw); /* Process the mode */ #ifdef WIZARD wizard = #endif discover = 0; switch (currmode) { case 0: /* Normal */ break; case 1: /* Explore */ discover = 1; break; #ifdef WIZARD case 2: /* Debug */ wizard = 1; strcpy(plname, WIZARD); break; #endif default: /* Quit */ ExitToShell(); } /* Process the role */ strcpy(pl_character, roles[currrole].name.m); flags.initrole = currrole; /* Process the race */ flags.initrace = currrace; /* Process the gender */ flags.female = flags.initgend = currgend; /* Process the alignment */ flags.initalign = curralign; return; } /*** Menu bar routines ***/ #if !TARGET_API_MAC_CARBON static void alignAD(Rect *pRct, short vExempt) { BitMap qbitmap; GetQDGlobalsScreenBits(&qbitmap); (*pRct).right -= (*pRct).left; /* width */ (*pRct).bottom -= (*pRct).top; /* height */ (*pRct).left = (qbitmap.bounds.right - (*pRct).right) / 2; (*pRct).top = (qbitmap.bounds.bottom - (*pRct).bottom - vExempt) / 2; (*pRct).top += vExempt; (*pRct).right += (*pRct).left; (*pRct).bottom += (*pRct).top; } #endif static void mustGetMenuAlerts() { short i; Rect **hRct; for (i = alrt_Menu_start; i < alrt_Menu_limit; i++) { if (! (hRct = (Rect **) GetResource('ALRT', i))) /* AlertTHndl */ { for (i = 0; i < beepMenuAlertErr; i++) SysBeep(3); ExitToShell(); } #if !TARGET_API_MAC_CARBON alignAD(*hRct, GetMBarHeight()); #endif } } static void menuError(short menuErr) { short i; for (i = 0; i < beepMenuAlertErr; i++) SysBeep(3); ParamText(menuErrStr[menuErr], "\p", "\p", "\p"); (void) Alert(alrtMenuNote, (ModalFilterUPP) 0L); ExitToShell(); } void InitMenuRes() { static Boolean was_inited = 0; short i, j; menuListHandle mlHnd; MenuHandle menu; if (was_inited) return; was_inited = 1; mustGetMenuAlerts(); for (i = listMenubar; i <= listSubmenu; i++) { if (! (mlHnd = (menuListHandle) GetResource('MNU#', (menuBarListID + i)))) menuError(errGetMenuList); pMenuList[i] = (menuListPtr) NewPtr(GetHandleSize((Handle) mlHnd)); *pMenuList[i] = **mlHnd; for (j = 0; j < pMenuList[i]->numMenus; j++) { if (! (menu = (MenuHandle) GetMenu((**mlHnd).mref[j].mresID))) { Str31 d; NumToString ((**mlHnd).mref[j].mresID, d); menuError(errGetMenu); } pMenuList[i]->mref[j].mhnd = menu; SetMenuID(menu, j + (**mlHnd).firstMenuID); /* consecutive IDs */ /* expand apple menu */ if ((i == listMenubar) && (j == menuApple)) { AppendResMenu(menu, 'DRVR'); } InsertMenu(menu, ((i == listSubmenu) ? hierMenu : 0)); } } DrawMenuBar(); return; } void AdjustMenus(short dimMenubar) { short newMenubar = mbarRegular; WindowRef win = FrontWindow(); short i; /* * if (windowprocs != mac_procs) { * return; * } */ /* determine the new menubar state */ if (dimMenubar) newMenubar = mbarDim; else if (!win) newMenubar = mbarNoWindows; else if (GetWindowKind(win) < 0) newMenubar = mbarDA; else if (!IsWindowVisible(_mt_window)) newMenubar = mbarNoMap; if (newMenubar != mbarRegular) ; /* we've already found its state */ #ifdef WIZARD else if (wizard) { newMenubar = mbarSpecial; if (kAdjustWizardMenu) { kAdjustWizardMenu = 0; SetMenuItemText(MHND_FILE, menuFilePlayMode, "\pDebug"); } } #endif else if (discover) { newMenubar = mbarSpecial; if (kAdjustWizardMenu) { kAdjustWizardMenu = 0; SetMenuItemText(MHND_FILE, menuFilePlayMode, "\pExplore"); for (i = CountMenuItems(MHND_WIZ); i > menuWizardAttributes; i--) DeleteMenuItem(MHND_WIZ, i); } } /* adjust the menubar, if there's a state change */ if (theMenubar != newMenubar) { switch(theMenubar = newMenubar) { case mbarDim: /* disable all menus (except the apple menu) */ for (i = menuFile; i < NUM_MBAR; i++) DisableMenuItem(MBARHND(i), 0); break; case mbarNoWindows: case mbarDA: case mbarNoMap: /* enable the file menu, but ... */ EnableMenuItem(MHND_FILE, 0); /* ... disable the window commands! */ for (i = menuFileRedraw; i <= menuFileEnterExplore; i++) DisableMenuItem(MHND_FILE, i); /* ... and disable the rest of the menus */ for (i = menuEdit; i < NUM_MBAR; i++) DisableMenuItem(MBARHND(i), 0); if (theMenubar == mbarDA) EnableMenuItem(MHND_EDIT, 0); break; case mbarRegular: case mbarSpecial: /* enable all menus ... */ for (i = menuFile; i < NUM_MBAR; i++) EnableMenuItem(MBARHND(i), 0); /* ... except the unused Edit menu */ DisableMenuItem(MHND_EDIT, 0); /* ... enable the window commands */ for (i = menuFileRedraw; i <= menuFileEnterExplore; i++) EnableMenuItem(MHND_FILE, i); if (theMenubar == mbarRegular) DisableMenuItem(MHND_FILE, menuFilePlayMode); else DisableMenuItem(MHND_FILE, menuFileEnterExplore); break; } DrawMenuBar(); } } void DoMenuEvt(long menuEntry) { short menuID = HiWord(menuEntry); short menuItem = LoWord(menuEntry); switch(menuID - ID1_MBAR) /* all submenus are default case */ { case menuApple: if (menuItem == menuAppleAboutBox) aboutNetHack(); #if !TARGET_API_MAC_CARBON else { unsigned char daName[32]; GetMenuItemText(MHND_APPLE, menuItem, * (Str255 *) daName); (void) OpenDeskAcc(daName); } #endif break; /* * Those direct calls are ugly: they should be installed into cmd.c . * Those AddToKeyQueue() calls are also ugly: they should be put into * the 'STR#' resource. */ case menuFile: switch(menuItem) { case menuFileRedraw: AddToKeyQueue ('R' & 0x1f, 1); break; case menuFilePrevMsg: AddToKeyQueue ('P' & 0x1f, 1); break; case menuFileCleanup: (void) SanePositions(); break; case menuFileEnterExplore: AddToKeyQueue ('X', 1); break; case menuFileSave: askSave(); break; case menuFileQuit: askQuit(); break; } break; case menuEdit: #if !TARGET_API_MAC_CARBON (void) SystemEdit(menuItem - 1); #endif break; default: /* get associated string and add to key queue */ { Str255 mstr; short i; GetIndString(mstr, menuID, menuItem); if (mstr[0] > QUEUE_LEN) mstr[0] = QUEUE_LEN; for (i = 1; ((i <= mstr[0]) && (mstr[i] != mstrEndChar)); i++) AddToKeyQueue(mstr[i], false); } break; } HiliteMenu(0); } static void aboutNetHack() { if (theMenubar >= mbarRegular) { (void) doversion(); /* is this necessary? */ } else { unsigned char aboutStr[32] = "\pNetHack 3.4."; if (PATCHLEVEL > 10) { aboutStr[++aboutStr[0]] = '0'+PATCHLEVEL/10; } aboutStr[++aboutStr[0]] = '0' + (PATCHLEVEL % 10); ParamText(aboutStr, "\p\rdevteam@www.nethack.org", "\p", "\p"); (void) Alert(alrtMenuNote, (ModalFilterUPP) 0L); ResetAlertStage(); } } static void askSave() { Boolean doSave = 1; Boolean doYes = 0; if (theMenubar < mbarRegular) { short itemHit; ParamText("\pReally Save?", "\p", "\p", "\p"); itemHit = Alert(alrtMenu_NY, (ModalFilterUPP) 0L); ResetAlertStage(); if (itemHit != bttnMenuAlertYes) { doSave = 0; } else { doYes = 1; } } if (doSave) { AddToKeyQueue ('S', 1); if (doYes) { AddToKeyQueue ('y', 1); } } } static void askQuit() { Boolean doQuit = 1; Boolean doYes = 0; Boolean winMac; char *quitinput; if (!strcmp (windowprocs.name, "mac")) winMac = 1; else winMac = 0; if (theMenubar < mbarRegular) { short itemHit; ParamText("\pReally Quit?", "\p", "\p", "\p"); itemHit = Alert(alrtMenu_NY, (ModalFilterUPP) 0L); ResetAlertStage(); if (itemHit != bttnMenuAlertYes) { doQuit = 0; } else { doYes = 1; } } if (doQuit) { /* MWM -- forgive me lord, an even uglier kludge to deal with differences in command input handling */ if (winMac) quitinput = "#quit\r"; else quitinput = "#q\r"; /* KMH -- Ugly kludge */ while (*quitinput) AddToKeyQueue(*quitinput++, 1); if (doYes) { if (winMac) quitinput = "y\rq\r\r\r"; else quitinput = "yq\r"; while (*quitinput) AddToKeyQueue(*quitinput++, 1); } } } nethack-3.4.3/sys/mac/macsnd.c0100644000000000000000000000454107764735041014645 0ustar rootroot/* SCCS Id: @(#)macsnd.c 3.1 92/11/28 */ /* Copyright (c) 1992 by Jon Watte */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains music playing code. * * If we were REALLY determinated, we would make the sound play * asynchronously, but I'll save that one for a rainy day... * * This may break A/UX, since it defines MAC but we need to * check that the toolbox is booted. I'll defer that one too. * * - h+ 921128 */ #include "hack.h" #include "mactty.h" #include "macwin.h" #if !TARGET_API_MAC_CARBON # include # include #else # define freqDurationCmd 40 #endif #define SND_BUFFER(s) (&(*s)[20]) #define SND_LEN(s) (GetHandleSize(s)-42) void mac_speaker (struct obj *instr, char *melody) { SndChannelPtr theChannel = (SndChannelPtr) 0; SndCommand theCmd; Handle theSound; unsigned char theName [32]; char *n = (char *) &theName [1]; int typ = instr->otyp; const char *actualn = OBJ_NAME (objects [typ]); /* * First: are we in the library ? */ if (flags.silent) { return; } /* * Is this a known instrument ? */ strcpy (n, actualn); theName [0] = strlen (n); theSound = GetNamedResource ('snd ', theName); if (! theSound) { return; } HLock (theSound); /* * Set up the synth */ if (SndNewChannel(&theChannel, sampledSynth, initMono + initNoInterp, (void *) 0) == noErr) { char midi_note [] = {57, 59, 60, 62, 64, 65, 67}; short err; short snd_len = SND_LEN (theSound) / 18; theCmd.cmd = soundCmd; theCmd.param1 = 0; theCmd.param2 = (long) SND_BUFFER (theSound); err = SndDoCommand (theChannel, &theCmd, false); /* * We rack 'em up all in a row * The mac will play them correctly and then end, since * we do a sync close below. * */ while (*melody && ! err) { while (*melody > 'G') { *melody -= 8; } while (*melody < 'A') { *melody += 8; } theCmd.cmd = freqDurationCmd; theCmd.param1 = snd_len; theCmd.param2 = midi_note [*melody - 'A']; err = SndDoCommand (theChannel, &theCmd, false); melody ++; } SndDisposeChannel (theChannel, false); /* Sync wait for completion */ ReleaseResource (theSound); } } void tty_nhbell (void) { Handle h = GetNamedResource ('snd ', "\pNetHack Bell"); if (h) { HLock (h); SndPlay ((SndChannelPtr) 0, (SndListHandle) h, 0); ReleaseResource (h); } else SysBeep (30); } nethack-3.4.3/sys/mac/mactopl.c0100644000000000000000000000256607764735041015044 0ustar rootroot/* SCCS Id: @(#)mactopl.c 3.1 91/07/23 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mactty.h" #include "macwin.h" #include "macpopup.h" char queued_resp(char *resp) { char buf[30]; if (try_key_queue(buf)) { if (!resp || strchr(resp, buf[0])) return buf[0]; if (digit(buf[0]) && strchr(resp, '#')) { yn_number = atoi(buf); return '#'; } } return '\0'; } char topl_yn_function(const char *query, const char *resp, char def) { char buf[30]; char c = queued_resp((char *) resp); if (!c) { enter_topl_mode((char *) query); topl_set_resp((char *) resp, def); do { c = readchar(); if (c && resp && !strchr(resp, c)) { nhbell(); c = '\0'; } } while (!c); topl_set_resp("", '\0'); leave_topl_mode(buf); if (c == '#') yn_number = atoi(buf); } return c; } char mac_yn_function(query, resp, def) const char *query,*resp; char def; /* * Generic yes/no function. 'def' is the default (returned by space or * return; 'esc' returns 'q', or 'n', or the default, depending on * what's in the string. The 'query' string is printed before the user * is asked about the string. * If resp is NULL, any single character is accepted and returned. */ { return topl_yn_function(query, resp, def); } /* mactopl.c */ nethack-3.4.3/sys/mac/mactty.c0100644000000000000000000006522007764735041014702 0ustar rootroot/* SCCS Id: @(#)mactty.c 3.1 93/03/01 */ /* Copyright (c) Jon W{tte 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* * mactty.c * * This file contains the actual code for the tty library. For a * description, see the file mactty.h, which contains all you * need to know to use the library. */ #include "hack.h" /* to get flags */ #include "mttypriv.h" #if !TARGET_API_MAC_CARBON #include #endif char game_active = 0; /* flag to window rendering routines not to use ppat */ /* these declarations are here because I can't include macwin.h without including the world */ extern void dprintf(char *, ...); /* dprintf.c */ /* * Borrowed from the Mac tty port */ extern WindowPtr _mt_window; static void select_onscreen_window (tty_record *record); static void select_offscreen_port (tty_record *record); #define MEMORY_MARGIN 30000 /* * Convenience macro for most functions - put last in declaration */ #define RECORD_EXISTS(record) \ tty_record * record; \ if (!window || !(record = (tty_record *) GetWRefCon (window))) \ return general_failure; /* * Simple macro for deciding wether we draw at once or delay */ #define DRAW_DIRECT (TA_ALWAYS_REFRESH & record->attribute [TTY_ATTRIB_FLAGS]) /* * Table of special characters. Zero is ALWAYS special; it means * end of string and would be MISSED if it was not included here. */ #define COOKED_CONTROLS 0X00002581 #define RAW_CONTROLS 1 static unsigned long s_control = COOKED_CONTROLS; /* * Memory-related error */ static short mem_err (void) { short ret_val = MemError(); if (!ret_val) { ret_val = general_failure; } return ret_val; } /* * Make a rectangle empty */ static void empty_rect (Rect *r) { r->right = -20000; r->left = 20000; r->top = 20000; r->bottom = -20000; } /* * Union twp rect together */ static void union_rect (Rect *r1, Rect *r2, Rect *dest) { dest->left = min (r1->left, r2->left); dest->top = min (r1->top, r2 ->top); dest->bottom = max (r1->bottom, r2->bottom); dest->right = max (r1->right, r2->right); } /* * Dispose a pointer using the set memory-allocator */ static short dispose_ptr (void *ptr) { if (!ptr) { return noErr; /* Silently accept disposing nulls */ } DisposePtr (ptr); return MemError (); } #if 0 /* Use alloc.c instead */ /* * Allocate a pointer using the set memory-allocator */ static short alloc_ptr (void **ptr, long size) { *ptr = NewPtr (size); return MemError (); } #endif /* * Set up a GWorld in the record */ static short allocate_offscreen_world (tty_record *record) { GWorldPtr gw = (GWorldPtr)0; GWorldFlags world_flags = 0; long mem_here, mem_there, other, required_mem; Point p = {0, 0}; Rect r_screen; GDHandle gdh; short s_err; select_onscreen_window (record); LocalToGlobal (&p); r_screen = record->its_bits.bounds; OffsetRect (&r_screen, p.h, p.v); gdh = GetMaxDevice (&r_screen); required_mem = (long) (*((*gdh)->gdPMap))->pixelSize * ((long) record->its_bits.bounds.right * record->its_bits.bounds.bottom) >> 3; PurgeSpace (&other, &mem_here); if (other < mem_here + MEMORY_MARGIN) { mem_here = other - MEMORY_MARGIN; } dprintf ("Heap %ld Required %ld", mem_here, required_mem); if (required_mem > mem_here) { mem_there = required_mem; if (required_mem > TempMaxMem (&mem_there)) { dprintf ("No memory"); return memFullErr; } world_flags |= useTempMem; } s_err = NewGWorld (&gw, 0, &r_screen, (CTabHandle) 0, (GDHandle) 0, world_flags); if (!s_err) { record->offscreen_world = gw; select_offscreen_port (record); SetOrigin (0, 0); select_onscreen_window (record); dprintf ("New GWorld @ %lx;dm", gw); } return s_err; } /* * Done with GWorld, release data */ static short deallocate_gworld (tty_record *record) { if (record->offscreen_world) { DisposeGWorld (record->offscreen_world); record->offscreen_world = (GWorldPtr) 0; } return noErr; } /* * Get rid of offscreen bitmap */ static short free_bits (tty_record *record) { short s_err; if (record->uses_gworld) { s_err = deallocate_gworld (record); #if !TARGET_API_MAC_CARBON } else { s_err = dispose_ptr (record->its_bits.baseAddr); if (!s_err) { record->its_bits.baseAddr = (char *)0; if (record->offscreen_port) { ClosePort (record->offscreen_port); s_err = dispose_ptr (record->offscreen_port); if (!s_err) { record->offscreen_port = (GrafPtr) 0; } } } #endif } return s_err; } /* * Snatch a window from the resource fork. Create the record. * Otherwise, do nothing. */ short create_tty (WindowRef *window, short resource_id, Boolean in_color) { tty_record * record; Boolean was_allocated = !!*window; if (in_color) { *window = GetNewCWindow (resource_id, (Ptr) *window, (WindowRef) -1L); } else { *window = GetNewWindow (resource_id, (Ptr) *window, (WindowRef) -1L); } if (!*window) { return mem_err (); } record = (tty_record *) NewPtrClear (sizeof (tty_record)); if (!record) { #if !TARGET_API_MAC_CARBON if (was_allocated) { CloseWindow (*window); } else { #endif DisposeWindow (*window); #if !TARGET_API_MAC_CARBON } #endif return mem_err (); } record->its_window = *window; SetWRefCon (*window, (long) record); record->was_allocated = was_allocated; record->its_bits.baseAddr = (char *)0; record->curs_state = TRUE; /* * We need to keep the window world around if we switch worlds */ record->offscreen_world = (GWorldPtr) 0; record->uses_gworld = in_color; if (in_color) { GDHandle gh; SetPortWindowPort(*window); GetGWorld(&(record->its_window_world), &gh); } else { record->its_window_world = (GWorldPtr)0; } #if CLIP_RECT_ONLY empty_rect (&(record->invalid_rect)); #else record->invalid_part = NewRgn (); if (!record->invalid_part) { return destroy_tty (*window); } #endif return noErr; } short init_tty_number (WindowPtr window, short font_number, short font_size, short x_size, short y_size) { RECORD_EXISTS (record); record->font_number = font_number; record->font_size = font_size; record->x_size = x_size; record->y_size = y_size; return force_tty_coordinate_system_recalc (window); } /* * Done with a window - destroy it. Release the memory only if * it wasn't allocated when we got it! */ short destroy_tty (WindowPtr window) { short s_err; RECORD_EXISTS (record); s_err = free_bits (record); if (!s_err) { #if !TARGET_API_MAC_CARBON if (record->was_allocated) { CloseWindow (window); } else { #endif DisposeWindow (window); #if !TARGET_API_MAC_CARBON } #endif s_err = dispose_ptr (record); } return s_err; } static void do_set_port_font (tty_record *record) { PenNormal (); TextFont (record->font_number); TextSize (record->font_size); if (0L != (record->attribute [TTY_ATTRIB_FLAGS] & TA_OVERSTRIKE)) { TextMode (srcOr); } else { TextMode (srcCopy); } } /* * Fill in some fields from some other fields that may have changed */ static void calc_font_sizes (tty_record *record) { FontInfo font_info; do_set_port_font (record); GetFontInfo (&font_info); record->char_width = font_info.widMax; record->ascent_height = font_info.ascent + font_info.leading; record->row_height = record->ascent_height + font_info.descent; } /* * Allocate memory for the bitmap holding the tty window */ static short alloc_bits (tty_record *record) { short s_err; SetRect (&record->its_bits.bounds, 0, 0, record->char_width * record->x_size, record->row_height * record->y_size); /* * Clear two highest and lowest bit - not a color pixMap, and even in size */ record->its_bits.rowBytes = ((record->its_bits.bounds.right + 15) >> 3) & 0x1ffe; if (record->uses_gworld) { s_err = allocate_offscreen_world (record); #if !TARGET_API_MAC_CARBON } else { s_err = alloc_ptr ((void **) &(record->its_bits.baseAddr), record->its_bits.rowBytes * record->its_bits.bounds.bottom); if (!s_err) { s_err = alloc_ptr ((void **) &(record->offscreen_port), sizeof (GrafPort)); } if (!s_err) { OpenPort (record->offscreen_port); SetPort (record->offscreen_port); ClipRect (&(record->its_bits.bounds)); SetPortBits (&(record->its_bits)); } #endif } return s_err; } /* * Save the current port/world in a safe place for later retrieval */ static void save_port (tty_record *record, void *save) { GWorldPtr gw; GDHandle gh; GrafPtr gp; if (record->uses_gworld) { GetGWorld (&gw, &gh); *(GWorldPtr *) save = gw; } else { GetPort (&gp); *(GrafPtr *) save = gp; } } /* * Restore current port/world after a save */ static void use_port (tty_record *record, void *port) { if (record->uses_gworld) { PixMapHandle pix_map; SetGWorld ((GWorldPtr) port, (GDHandle) 0); pix_map = GetGWorldPixMap (record->offscreen_world); if (pix_map) { if (port == record->offscreen_world) LockPixels (pix_map); else UnlockPixels (pix_map); } } else { SetPort ((GrafPtr) port); } } /* * Use offscreen drawing - lock the pixels through use_port */ static void select_offscreen_port (tty_record *record) { if (record->uses_gworld) { use_port (record, record->offscreen_world); } else { use_port (record, record->offscreen_port); } } /* * Use the window - unlock pixels */ static void select_onscreen_window (tty_record *record) { if (record->uses_gworld) { use_port (record, record->its_window_world); SetPortWindowPort(record->its_window); } else { use_port(record, record->its_window); } } /* * Do bits copy depending on if we're using color or not */ static void copy_bits(tty_record *record, Rect *bounds, short xfer_mode, RgnHandle mask_rgn) { GWorldFlags pix_state; BitMap * source; if (record->uses_gworld) { pix_state = GetPixelsState (GetGWorldPixMap (record->offscreen_world)); LockPixels (GetGWorldPixMap (record->offscreen_world)); source = (BitMapPtr) *GetGWorldPixMap(record->offscreen_world); } else source = &record->its_bits; SetPortWindowPort(record->its_window); CopyBits(source, GetPortBitMapForCopyBits(GetWindowPort(record->its_window)), bounds, bounds, xfer_mode, mask_rgn); if (record->uses_gworld) { SetPixelsState (GetGWorldPixMap (record->offscreen_world), pix_state); } } /* * Fill an area with the background color */ static void erase_rect (tty_record *record, Rect *area) { if (game_active && u.uhp > 0 && iflags.use_stone && record->its_window == _mt_window) { PixPatHandle ppat; ppat = GetPixPat(iflags.use_stone + 127); /* find which pat to get */ if (ppat) { /* in game window, using backgroung pattern, and have pattern */ FillCRect (area, ppat); DisposePixPat (ppat); return; } } EraseRect (area); } /* * Recalculate the window based on new size, font, extent values, * and re-allocate the bitmap. */ short force_tty_coordinate_system_recalc (WindowPtr window) { short s_err; RECORD_EXISTS (record); s_err = free_bits (record); if (s_err) { return s_err; } calc_font_sizes (record); s_err = alloc_bits (record); if (s_err) { /* * Catastrophe! We could not allocate memory for the bitmap! Things may go very * much downhill from here! */ dprintf ("alloc_bits returned null in force_tty_coordinate_system_recalc!"); return s_err; } select_offscreen_port (record); do_set_port_font (record); return clear_tty (window); } #if 0 /* * Update TTY according to new color environment for the window */ static short tty_environment_changed (tty_record *record) { Point p = {0, 0}; Rect r_screen; if (record->uses_gworld) { r_screen = record->its_bits.bounds; LocalToGlobal (&p); OffsetRect (&r_screen, p.h, p.v); UpdateGWorld (&(record->offscreen_world), 0, &r_screen, (CTabHandle) 0, (GDHandle) 0, stretchPix); select_offscreen_port (record); SetOrigin (0, 0); select_onscreen_window (record); } return 0; } #endif /* * Read a lot of interesting and useful information from the current tty */ short get_tty_metrics (WindowPtr window, short *x_size, short *y_size, short *x_size_pixels, short *y_size_pixels, short *font_number, short *font_size, short *char_width, short *row_height) { RECORD_EXISTS (record); /* * First, test that we actually have something to draw to... */ if ((((char *)0 == record->its_bits.baseAddr) && !record->uses_gworld) || (((GWorldPtr)0 == record->offscreen_world) && record->uses_gworld)) { return general_failure; } *x_size = record->x_size; *y_size = record->y_size; *x_size_pixels = record->its_bits.bounds.right; *y_size_pixels = record->its_bits.bounds.bottom; *font_number = record->font_number; *font_size = record->font_size; *char_width = record->char_width; *row_height = record->row_height; return noErr; } /* * Map a position on the map to screen coordinates */ static void pos_rect (tty_record *record, Rect *r, short x_pos, short y_pos, short x_end, short y_end) { SetRect (r, x_pos * (record->char_width), y_pos * (record->row_height), (1 + x_end) * (record->char_width) , (1 + y_end) * (record->row_height)); } static void accumulate_rect (tty_record *record, Rect *rect) { #if CLIP_RECT_ONLY union_rect (rect, &(record->invalid_rect), &(record->invalid_rect)); #else RgnHandle rh = NewRgn (); RectRgn (rh, rect); UnionRgn (record->invalid_part, rh, record->invalid_part); DisposeRgn (rh); #endif } /* * get and set window invalid region. exposed for HandleUpdateEvent in macwin.c * to correct display problem */ short get_invalid_region (WindowPtr window, Rect *inval_rect) { RECORD_EXISTS (record); #if CLIP_RECT_ONLY if (record->invalid_rect.right <= record->invalid_rect.left || record->invalid_rect.bottom <= record->invalid_rect.top) { return general_failure; } *inval_rect = record->invalid_rect; #else if (EmptyRgn (record->invalid_part)) { return general_failure; } *inval_rect = (*(record->invalid_part))->rgnBBox; #endif return noErr; } short set_invalid_region (WindowPtr window, Rect *inval_rect) { RECORD_EXISTS (record); accumulate_rect (record, inval_rect); return noErr; } /* * Invert the specified position */ static void curs_pos (tty_record *record, short x_pos, short y_pos, short to_state) { Rect r; if (record->curs_state == to_state) { return; } record->curs_state = to_state; pos_rect (record, &r, x_pos, y_pos, x_pos, y_pos); if (DRAW_DIRECT) { void *old_port; save_port (record, &old_port); select_onscreen_window (record); InvertRect (&r); use_port (record, old_port); } else { accumulate_rect (record, &r); } } /* * Move the cursor (both as displayed and where drawing goes) * HOWEVER: The cursor is NOT stored in the bitmap! */ short move_tty_cursor (WindowPtr window, short x_pos, short y_pos) { RECORD_EXISTS (record); if (record->x_curs == x_pos && record->y_curs == y_pos) { return noErr; } if (record->x_size <= x_pos || x_pos < 0 || record->y_size <= y_pos || y_pos < 0) { return general_failure; } curs_pos (record, record->x_curs, record->y_curs, 0); record->x_curs = x_pos; record->y_curs = y_pos; curs_pos (record, x_pos, y_pos, 1); return noErr; } /* * Update the screen to match the current bitmap, after adding stuff * with add_tty_char etc. */ short update_tty (WindowPtr window) { Rect r; RECORD_EXISTS (record); #if CLIP_RECT_ONLY if (record->invalid_rect.right <= record->invalid_rect.left || record->invalid_rect.bottom <= record->invalid_rect.top) { return noErr; } r = record->invalid_rect; #else if (EmptyRgn (record->invalid_part)) { return noErr; } r = (*(record->invalid_part))->rgnBBox; #endif select_onscreen_window (record); copy_bits (record, &r, srcCopy, (RgnHandle) 0); #if CLIP_RECT_ONLY empty_rect (&(record->invalid_rect)); #else SetEmptyRgn (record->invalid_part); #endif if (record->curs_state) { pos_rect (record, &r, record->x_curs, record->y_curs, record->x_curs, record->y_curs); InvertRect (&r); } return noErr; } /* * Low level add to screen */ static void do_add_string (tty_record *record, char *str, short len) { Rect r; if (len < 1) { return; } select_offscreen_port (record); MoveTo (record->x_curs * record->char_width, record->y_curs * record->row_height + record->ascent_height); DrawText (str, 0, len); pos_rect (record, &r, record->x_curs, record->y_curs, record->x_curs + len - 1, record->y_curs); select_onscreen_window (record); if (DRAW_DIRECT) { copy_bits (record, &r, srcCopy, (RgnHandle)0); } else { accumulate_rect (record, &r); } } /* * Low-level cursor handling routine */ static void do_add_cursor (tty_record *record, short x_pos) { record->x_curs = x_pos; if (record->x_curs >= record->x_size) { if (0L != (record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND)) { record->y_curs ++; record->x_curs = 0; if (record->y_curs >= record->y_size) { if (0L != (record->attribute [TTY_ATTRIB_FLAGS] & TA_INHIBIT_VERT_SCROLL)) { record->y_curs = record->y_size; } else { scroll_tty (record->its_window, 0, 1 + record->y_curs - record->y_size); } } } else { record->x_curs = record->x_size; } } } /* * Do control character */ static void do_control (tty_record *record, short character) { int recurse = 0; /* * Check recursion because nl_add_cr and cr_add_nl may both be set and invoke each other */ do { switch (character) { case CHAR_CR : record->x_curs = 0; if (!recurse && (record->attribute [TTY_ATTRIB_CURSOR] & TA_CR_ADD_NL)) { recurse = 1; } else { recurse = 0; break; } /* FALL-THROUGH: if CR-LF, don't bother with loop */ case CHAR_LF : record->y_curs++; if (record->y_curs >= record->y_size) { scroll_tty (record->its_window, 0, 1 + record->y_curs - record->y_size); } if (!recurse && (record->attribute [TTY_ATTRIB_CURSOR] & TA_NL_ADD_CR)) { character = CHAR_CR; recurse = 1; } else recurse = 0; break; case CHAR_BELL : tty_nhbell(); break; case CHAR_BS : if (record->x_curs > 0) record->x_curs --; default : break; } } while (recurse); } /* * Add a single character. It is drawn directly if the correct flag is set, * else deferred to the next update event or call of update_tty() */ short add_tty_char (WindowPtr window, short character) { register char is_control; char ch; RECORD_EXISTS (record); if (!(record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND) && record->x_curs >= record->x_size) return noErr; /* Optimize away drawing across border without wrap */ if (record->curs_state != 0) curs_pos (record, record->x_curs, record->y_curs, 0); ch = character; is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L); if (is_control) do_control (record, ch); else { do_add_string (record, (char *)&ch, 1); do_add_cursor (record, record->x_curs + 1); } return noErr; } /* * Add a null-terminated string of characters */ short add_tty_string(WindowPtr window, const char *string) { register const unsigned char * start_c; register const unsigned char * the_c; register unsigned char ch, is_control = 0, tty_wrap; register short max_x, pos_x; RECORD_EXISTS (record); if (record->curs_state != 0) curs_pos (record, record->x_curs, record->y_curs, 0); the_c = (const unsigned char *) string; max_x = record->x_size; tty_wrap = (record->attribute [TTY_ATTRIB_FLAGS] & TA_WRAP_AROUND); for (;;) { pos_x = record->x_curs; if (!tty_wrap && pos_x >= max_x) break; /* Optimize away drawing across border without wrap */ start_c = the_c; ch = *the_c; while (pos_x < max_x) { is_control = (ch < sizeof(long) * 8) && ((s_control & (1 << ch)) != 0L); if (is_control) break; the_c ++; ch = *the_c; pos_x ++; } do_add_string (record, (char *) start_c, the_c - start_c); do_add_cursor (record, pos_x); if (!ch) break; if (is_control) { do_control (record, ch); the_c ++; } } return noErr; } /* * Read or change attributes for the tty. Note that some attribs may * very well clear and reallocate the bitmap when changed, whereas * others (color, highlight, ...) are guaranteed not to. */ short get_tty_attrib (WindowPtr window, tty_attrib attrib, long *value) { RECORD_EXISTS (record); if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) { return general_failure; } *value = record->attribute [attrib]; return noErr; } short set_tty_attrib (WindowPtr window, tty_attrib attrib, long value) { RGBColor rgb_color; RECORD_EXISTS (record); if (attrib < 0 || attrib >= TTY_NUMBER_ATTRIBUTES) { return general_failure; } record->attribute [attrib] = value; /* * Presently, no attributes generate a new bitmap. */ switch (attrib) { case TTY_ATTRIB_CURSOR : /* * Check if we should change tables */ if (0L != (value & TA_RAW_OUTPUT)) { s_control = RAW_CONTROLS; } else { s_control = COOKED_CONTROLS; } break; case TTY_ATTRIB_FLAGS : /* * Check if we should flush the output going from cached to draw-direct */ if (0L != (value & TA_ALWAYS_REFRESH)) { update_tty (window); } break; case TTY_ATTRIB_FOREGROUND : /* * Set foreground color */ TA_TO_RGB (value, rgb_color); select_offscreen_port (record); RGBForeColor (&rgb_color); select_onscreen_window (record); break; case TTY_ATTRIB_BACKGROUND : /* * Set background color */ TA_TO_RGB (value, rgb_color); select_offscreen_port (record); RGBBackColor (&rgb_color); select_onscreen_window (record); break; default : break; } return noErr; } /* * Scroll the window. Positive is up/left. scroll_tty ( window, 0, 1 ) is a line feed. * Scroll flushes the accumulated update area by calling update_tty(). */ short scroll_tty (WindowPtr window, short delta_x, short delta_y) { RgnHandle rgn; short s_err; RECORD_EXISTS (record); s_err = update_tty (window); rgn = NewRgn (); select_offscreen_port (record); ScrollRect (&(record->its_bits.bounds), -delta_x * record->char_width, -delta_y * record->row_height, rgn); EraseRgn (rgn); SetEmptyRgn (rgn); select_onscreen_window (record); ScrollRect (&(record->its_bits.bounds), -delta_x * record->char_width, -delta_y*record->row_height, rgn); EraseRgn (rgn); DisposeRgn (rgn); record->y_curs -= delta_y; record->x_curs -= delta_x; return noErr; } /* * Clear the screen. Immediate. */ short clear_tty (WindowPtr window) { RECORD_EXISTS (record); record->curs_state = 0; select_offscreen_port (record); erase_rect (record, &(record->its_bits.bounds)); accumulate_rect (record, &(record->its_bits.bounds)); update_tty (window); return noErr; } /* * Blink cursor on window if necessary */ short blink_cursor (WindowPtr window, long when) { RECORD_EXISTS (record); if ((record->attribute [TTY_ATTRIB_CURSOR] & TA_BLINKING_CURSOR)) { if (when > record->last_cursor + GetCaretTime ()) { curs_pos (record, record->x_curs, record->y_curs, !record->curs_state); record->last_cursor = when; update_tty (window); } } return 0; } /* * Draw an image of the tty - used for update events and can be called * for screen dumps. */ short image_tty (EventRecord *theEvent, WindowPtr window) { #if defined(__SC__) || defined(__MRC__) # pragma unused(theEvent) #endif RECORD_EXISTS (record); #if CLIP_RECT_ONLY record->invalid_rect = record->its_bits.bounds; #else RgnHandle rh = NewRgn (); RectRgn (rh, record ->its_bits.bounds); UnionRgn (record->invalid_part, rh, record->invalid_part); DisposeRgn (rh); #endif return update_tty (window); } /* * Clear an area */ short clear_tty_window (WindowPtr window, short from_x, short from_y, short to_x, short to_y) { Rect r; RECORD_EXISTS (record); if (from_x > to_x || from_y > to_y) { return general_failure; } pos_rect (record, &r, from_x, from_y, to_x, to_y); select_offscreen_port (record); erase_rect (record, &r); accumulate_rect (record, &r); if (DRAW_DIRECT) { update_tty (window); } else select_onscreen_window (record); return noErr; } #if EXTENDED_SUPPORT /* * Delete or insert operations used by many terminals can bottleneck through * here. Note that the order of executin for row/colum insertions is NOT * specified. Negative values for num_ mean delete, zero means no effect. */ short mangle_tty_rows_columns (WindowPtr window, short from_row, short num_rows, short from_column, short num_columns) { Rect r; RgnHandle rh = NewRgn (); RECORD_EXISTS (record); update_tty (window); /* Always make sure screen is OK */ curs_pos (record, record->x_curs, record->y_curs, 0); if (num_rows) { pos_rect (record, &r, 0, from_row, record->x_size - 1, record->y_size - 1); select_offscreen_port (record); ScrollRect (&r, 0, num_rows * record->row_height, rh); EraseRgn (rh); SetEmptyRgn (rh); select_onscreen_window (record); ScrollRect (&r, 0, num_rows * record->row_height, rh); EraseRgn (rh); SetEmptyRgn (rh); } if (num_columns) { pos_rect (record, &r, from_column, 0, record->x_size - 1, record->y_size - 1); select_offscreen_port (record); ScrollRect (&r, num_columns * record->char_width, 0, rh); EraseRgn (rh); SetEmptyRgn (rh); select_onscreen_window (record); ScrollRect (&r, num_columns * record->char_width, 0, rh); EraseRgn (rh); SetEmptyRgn (rh); } DisposeRgn (rh); if (record->x_curs >= from_column) { record->x_curs += num_columns; } if (record->y_curs >= from_row) { record->y_curs += num_rows; } curs_pos (record, record->x_curs, record->y_curs, 1); return noErr; } /* * Frame an area in an aesthetically pleasing way. */ short frame_tty_window (WindowPtr window, short from_x, short from_y , short to_x, short to_y, short frame_fatness) { Rect r; RECORD_EXISTS (record); if (from_x > to_x || from_y > to_y) { return general_failure; } pos_rect (record, & r, from_x, from_y, to_x, to_y); select_offscreen_port (record); PenSize (frame_fatness, frame_fatness); FrameRect (&r); PenNormal (); accumulate_rect (record, &r); if (DRAW_DIRECT) { update_tty (window); } else select_onscreen_window (record); } /* * Highlighting a specific part of the tty window */ short invert_tty_window (WindowPtr window, short from_x, short from_y , short to_x, short to_y) { Rect r; RECORD_EXISTS (record); if (from_x > to_x || from_y > to_y) { return general_failure; } pos_rect (record, &r, from_x, from_y, to_x, to_y); select_offscreen_port (record); InvertRect ( &r); accumulate_rect (record, &r); if (DRAW_DIRECT) { update_tty (window); } else select_onscreen_window (record); } static void canonical_rect (Rect * r, short x1, short y1, short x2, short y2) { if (x1 < x2) { if (y1 < y2) { SetRect (r, x1, x2, y1, y2); } else { SetRect (r, x1, x2, y2, y1); } } else { if (y1 < y2) { SetRect (r, x2, x1, y1, y2); } else { SetRect (r, x2, x1, y2, y1); } } } /* * Line drawing - very device dependent */ short draw_tty_line (WindowPtr window, short from_x, short from_y , short to_x, short to_y) { Rect r; RECORD_EXISTS (record); select_offscreen_port (record); MoveTo (from_x, from_y); LineTo (to_x, to_y); canonical_rect (&r, from_x, from_y, to_x, to_y); accumulate_rect (record, &r); if (DRAW_DIRECT) { update_tty (window); } else select_onscreen_window (record); } #endif /* EXTENDED_SUPPORT */ nethack-3.4.3/sys/mac/macunix.c0100644000000000000000000000144307764735041015042 0ustar rootroot/* SCCS Id: @(#)macunix.c 3.1 94/11/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file collects some Unix dependencies */ #include "hack.h" void regularize(char *s) { register char *lp; for (lp = s; *lp; lp++) { if (*lp == '.' || *lp == ':') *lp = '_'; } } void getlock(void) { int fd; int pid = getpid(); /* Process ID */ set_levelfile_name (lock, 0); if ((fd = open (lock, O_RDWR | O_EXCL | O_CREAT, LEVL_TYPE)) == -1) { raw_printf ("Could not lock the game %s.", lock); panic ("Another game in progress?"); } if (write (fd, (char *)&pid, sizeof (pid)) != sizeof (pid)) { raw_printf ("Could not lock the game %s.", lock); panic("Disk locked?"); } close (fd); } nethack-3.4.3/sys/mac/macwin.c0100644000000000000000000017477307764735041014675 0ustar rootroot/* SCCS Id: @(#)macwin.c 3.4 1996/01/15 */ /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "func_tab.h" #include "macwin.h" #include "mactty.h" #include "wintty.h" #if !TARGET_API_MAC_CARBON #include #include #include #include #include #include #endif NhWindow *theWindows = (NhWindow *) 0; Cursor qdarrow; /* Borrowed from the Mac tty port */ extern WindowPtr _mt_window; /* Some useful #defines for the scroll bar width and height */ #define SBARWIDTH 15 #define SBARHEIGHT 15 /* * We put a TE on the message window for the "top line" queries. * top_line is the TE that holds both the query and the user's * response. The first topl_query_len characters in top_line are * the query, the rests are the response. topl_resp is the valid * response to a yn query, while topl_resp[topl_def_idx] is the * default response to a yn query. */ static TEHandle top_line = (TEHandle) nil; static int topl_query_len; static int topl_def_idx = -1; static char topl_resp[10] = ""; #define CHAR_ANY '\n' /* * inSelect means we have a menu window up for selection or * something similar. It makes the window with win number == * inSelect a movable modal (unfortunately without the border) * and clicking the close box forces an RET into the key * buffer. Don't forget to set inSelect to WIN_ERR when you're * done... */ static winid inSelect = WIN_ERR; /* * The key queue ring buffer where Read is where to take from, * Write is where next char goes and count is queue depth. */ static unsigned char keyQueue [QUEUE_LEN]; static int keyQueueRead = 0, keyQueueWrite = 0, keyQueueCount = 0; static Boolean gClickedToMove = 0; /* For ObscureCursor */ static Point clicked_pos; /* For nh_poskey */ static int clicked_mod; static Boolean cursor_locked = false; static ControlActionUPP MoveScrollUPP; /* scrolling callback, init'ed in InitMac */ void lock_mouse_cursor(Boolean new_cursor_locked) { cursor_locked = new_cursor_locked; } /* * Add key to input queue, force means flush left and replace if full */ void AddToKeyQueue (unsigned char ch, Boolean force) { if (keyQueueCount < QUEUE_LEN) { keyQueue [keyQueueWrite++] = ch; keyQueueCount++; } else if (force) { keyQueue [keyQueueWrite++] = ch; keyQueueRead++; if (keyQueueRead >= QUEUE_LEN) keyQueueRead = 0; keyQueueCount = QUEUE_LEN; } if (keyQueueWrite >= QUEUE_LEN) keyQueueWrite = 0; } /* * Get key from queue */ unsigned char GetFromKeyQueue (void) { unsigned char ret; if (keyQueueCount) { ret = keyQueue [keyQueueRead++]; keyQueueCount--; if (keyQueueRead >= QUEUE_LEN) keyQueueRead = 0; } else ret = 0; return ret; } /* * Cursor movement */ static RgnHandle gMouseRgn = (RgnHandle) 0; /* * _Gestalt madness - we rely heavily on the _Gestalt glue, since we * don't check for the trap... */ MacFlags macFlags; /* * The screen layouts on the small 512x342 screen need special cares. */ Boolean small_screen = 0; #ifdef NHW_BASE # undef NHW_BASE #endif #define NHW_BASE 0 static int FDECL(filter_scroll_key,(const int, NhWindow *)); static void FDECL(GeneralKey, (EventRecord *, WindowPtr)); static void FDECL(macKeyMenu, (EventRecord *, WindowPtr)); static void FDECL(macKeyText, (EventRecord *, WindowPtr)); static void FDECL(macClickMessage, (EventRecord *, WindowPtr)); static void FDECL(macClickTerm, (EventRecord *, WindowPtr)); static void FDECL(macClickMenu, (EventRecord *, WindowPtr)); static void FDECL(macClickText, (EventRecord *, WindowPtr)); static short FDECL(macDoNull, (EventRecord *, WindowPtr)); static short FDECL(macUpdateMessage, (EventRecord *, WindowPtr)); static short FDECL(macUpdateMenu, (EventRecord *, WindowPtr)); static short FDECL(GeneralUpdate, (EventRecord *, WindowPtr)); static void FDECL(macCursorTerm, (EventRecord *, WindowPtr, RgnHandle)); static void FDECL(GeneralCursor, (EventRecord *, WindowPtr, RgnHandle)); static void FDECL(DoScrollBar,(Point, short, ControlHandle, NhWindow *)); static pascal void FDECL(MoveScrollBar, (ControlHandle, short)); typedef void (*CbFunc) (EventRecord *, WindowPtr); typedef short (*CbUpFunc) (EventRecord *, WindowPtr); typedef void (*CbCursFunc) (EventRecord *, WindowPtr, RgnHandle); #define NUM_FUNCS 6 static const CbFunc winKeyFuncs [NUM_FUNCS] = { GeneralKey, GeneralKey, GeneralKey, GeneralKey, macKeyMenu, macKeyText }; static const CbFunc winClickFuncs [NUM_FUNCS] = { (CbFunc)macDoNull, macClickMessage, macClickTerm, macClickTerm, macClickMenu, macClickText }; static const CbUpFunc winUpdateFuncs [NUM_FUNCS] = { macDoNull, macUpdateMessage, image_tty, image_tty, macUpdateMenu, GeneralUpdate }; static const CbCursFunc winCursorFuncs [NUM_FUNCS] = { (CbCursFunc) macDoNull, GeneralCursor, macCursorTerm, macCursorTerm, GeneralCursor, GeneralCursor }; static NhWindow * GetNhWin(WindowPtr mac_win) { if (mac_win == _mt_window) /* term window is still maintained by both systems, and */ return theWindows; /* WRefCon still refers to tty struct, so we have to map it */ else { NhWindow *aWin = (NhWindow *)GetWRefCon (mac_win); if (aWin >= theWindows && aWin < &theWindows[NUM_MACWINDOWS]) return aWin; } return ((NhWindow *) nil); } Boolean CheckNhWin (WindowPtr mac_win) { return GetNhWin (mac_win) != nil; } static pascal OSErr AppleEventHandler (const AppleEvent* inAppleEvent, AppleEvent* outAEReply, long inRefCon) { #if defined(__SC__) || defined(__MRC__) # pragma unused(outAEReply,inRefCon) #endif Size actualSize; DescType typeCode; AEEventID EventID; OSErr err; /* Get Event ID */ err = AEGetAttributePtr (inAppleEvent, keyEventIDAttr, typeType, &typeCode, &EventID, sizeof (EventID), &actualSize); if (err == noErr) { switch (EventID) { default : case kAEOpenApplication : macFlags.gotOpen = 1; /* fall through */ case kAEPrintDocuments : err = errAEEventNotHandled; break; case kAEQuitApplication : /* Flush key queue */ keyQueueCount = keyQueueWrite = keyQueueRead = 0; AddToKeyQueue ('S', 1); break; case kAEOpenDocuments : { FSSpec fss; FInfo fndrInfo; AEKeyword keywd; AEDescList docList; long index, itemsInList; if((err = AEGetParamDesc(inAppleEvent, keyDirectObject, typeAEList, &docList)) != noErr || (err = AECountItems(&docList, &itemsInList)) != noErr){ if (err == errAEDescNotFound) itemsInList = 0; else break; } for(index = 1; index <= itemsInList; index++){ err = AEGetNthPtr(&docList, index, typeFSS, &keywd, &typeCode, (Ptr)&fss, sizeof(FSSpec), &actualSize); if(noErr != err) break; err = FSpGetFInfo (&fss, &fndrInfo); if (noErr != err) break; if (fndrInfo.fdType != SAVE_TYPE) continue; /* only look at save files */ process_openfile (fss.vRefNum, fss.parID, fss.name, fndrInfo.fdType); if (macFlags.gotOpen) break; /* got our save file */ } err = AEDisposeDesc(&docList); break; } } } /* Check to see if all required parameters for this type of event are present */ if (err == noErr) { err = AEGetAttributePtr (inAppleEvent, keyMissedKeywordAttr, typeWildCard, &typeCode, NULL, 0, &actualSize); if (err == errAEDescNotFound) err = noErr; /* got all the required parameters */ else if (err == noErr) /* missed a required parameter */ err = errAEEventNotHandled; } return err; } short win_fonts [NHW_TEXT + 1]; void InitMac(void) { short i; long l; Str255 volName; #if !TARGET_API_MAC_CARBON if (LMGetDefltStack() < 50 * 1024L) { SetApplLimit ((void *) ((long) LMGetCurStackBase() - (50 * 1024L))); } MaxApplZone (); for (i = 0; i < 5; i ++) MoreMasters (); InitGraf (&qd.thePort); InitFonts (); InitWindows (); InitMenus (); InitDialogs (0L); TEInit (); #endif memset (&macFlags, 0, sizeof(macFlags)); if (!Gestalt (gestaltOSAttr, & l)) { macFlags.processes = (l & (1 << gestaltLaunchControl)) ? 1 : 0; macFlags.tempMem = (l & (1 << gestaltRealTempMemory)) ? 1 : 0; macFlags.hasDebugger = (l & (1 << gestaltSysDebuggerSupport)) ? 1 : 0; } if (!Gestalt (gestaltQuickdrawVersion, & l)) macFlags.color = (l >= gestalt8BitQD) ? 1 : 0; if (!Gestalt (gestaltFindFolderAttr, & l)) macFlags.folders = (l & (1 << gestaltFindFolderPresent)) ? 1 : 0; if (!Gestalt (gestaltHelpMgrAttr, & l)) macFlags.help = (l & (1 << gestaltHelpMgrPresent)) ? 1 : 0; if (!Gestalt (gestaltFSAttr, & l)) macFlags.fsSpec = (l & (1 << gestaltHasFSSpecCalls)) ? 1 : 0; if (!Gestalt (gestaltFontMgrAttr, & l)) macFlags.trueType = (l & (1 << gestaltOutlineFonts)) ? 1 : 0; if (!Gestalt (gestaltAUXVersion, & l)) macFlags.aux = (l >= 0x200) ? 1 : 0; if (!Gestalt (gestaltAliasMgrAttr, & l)) macFlags.alias = (l & (1 << gestaltAliasMgrPresent)) ? 1 : 0; if (!Gestalt (gestaltStandardFileAttr, & l)) macFlags.standardFile = (l & (1 << gestaltStandardFile58)) ? 1 : 0; gMouseRgn = NewRgn (); InitCursor(); GetQDGlobalsArrow(&qdarrow); ObscureCursor (); MoveScrollUPP = NewControlActionUPP(MoveScrollBar); /* Set up base fonts for all window types */ GetFNum ("\pHackFont", &i); if (i == 0) i = kFontIDMonaco; win_fonts [NHW_BASE] = win_fonts [NHW_MAP] = win_fonts [NHW_STATUS] = i; GetFNum ("\pPSHackFont", &i); if (i == 0) i = kFontIDGeneva; win_fonts [NHW_MESSAGE] = i; win_fonts [NHW_TEXT] = kFontIDGeneva; macFlags.hasAE = 0; if(!Gestalt(gestaltAppleEventsAttr, &l) && (l & (1L << gestaltAppleEventsPresent))){ if (AEInstallEventHandler (kCoreEventClass, typeWildCard, NewAEEventHandlerUPP(AppleEventHandler), 0, FALSE) == noErr) macFlags.hasAE = 1; } #if TARGET_API_MAC_CARBON HGetVol(volName, &theDirs.dataRefNum, &theDirs.dataDirID); #else /* * We should try to get this data from a rsrc, in the profile file * the user double-clicked... This data should be saved with the * save file in the resource fork, AND be saveable in "stationary" */ GetVol (volName, &theDirs.dataRefNum ); GetWDInfo (theDirs.dataRefNum, &theDirs.dataRefNum, &theDirs.dataDirID, &l); #endif if (volName [0] > 31) volName [0] = 31; for (l = 1; l <= volName [0]; l++) { if (volName [l] == ':') { volName [l] = 0; volName [0] = l - 1; break; } } BlockMove (volName, theDirs.dataName, l); BlockMove (volName, theDirs.saveName, l); BlockMove (volName, theDirs.levelName, l); theDirs.saveRefNum = theDirs.levelRefNum = theDirs.dataRefNum; theDirs.saveDirID = theDirs.levelDirID = theDirs.dataDirID; /* Create the "record" file, if necessary */ check_recordfile(""); return; } /* * Change default window fonts. */ short set_tty_font_name (int window_type, char *font_name) { short fnum; Str255 new_font; if (window_type < NHW_BASE || window_type > NHW_TEXT) return general_failure; C2P (font_name, new_font); GetFNum (new_font, &(fnum)); if (!fnum) return general_failure; win_fonts [window_type] = fnum; return noErr; } static void DrawScrollbar (NhWindow *aWin) { WindowPtr theWindow = aWin->its_window; Rect crect, wrect; Boolean vis; short val, lin, win_height; if (!aWin->scrollBar) return; GetControlBounds(aWin->scrollBar, &crect); GetWindowBounds(aWin->its_window, kWindowContentRgn, &wrect); OffsetRect(&wrect, -wrect.left, -wrect.top); win_height = wrect.bottom - wrect.top; if (crect.top != wrect.top - 1 || crect.left != wrect.right - SBARWIDTH) { MoveControl (aWin->scrollBar, wrect.right - SBARWIDTH, wrect.top - 1); } if (crect.bottom != wrect.bottom - SBARHEIGHT || crect.right != wrect.right + 1) { SizeControl (aWin->scrollBar, SBARWIDTH+1, win_height - SBARHEIGHT + 2); } vis = (win_height > (50 + SBARHEIGHT)); if (vis != IsControlVisible(aWin->scrollBar)) { /* current status != control */ if (vis)/* if visible, show */ ShowControl (aWin->scrollBar); else /* else hide */ HideControl (aWin->scrollBar); } lin = aWin->y_size; if (aWin == theWindows + WIN_MESSAGE) { /* calculate how big scroll bar is for message window */ lin -= (win_height - SBARHEIGHT) / aWin->row_height; if (lin < 0) lin = 0; val = 0; /* always have message scrollbar active */ } else { /* calculate how big scroll bar is for other windows */ lin -= win_height / aWin->row_height; if (lin < 0) lin = 0; if (lin) val = 0; /* if there are 1+ screen lines, activate scrollbar */ else val = 255; /* else grey it out */ } SetControlMaximum (aWin->scrollBar, lin); HiliteControl (aWin->scrollBar, val); val = GetControlValue (aWin->scrollBar); if (val != aWin->scrollPos) { InvalWindowRect(theWindow, &wrect); aWin->scrollPos = val; } } #define MAX_HEIGHT 100 #define MIN_HEIGHT 50 #define MIN_WIDTH 300 /* * This function could be overloaded with any amount of intelligence... */ int SanePositions (void) { #if TARGET_API_MAC_CARBON ConstrainWindowToScreen(_mt_window, kWindowStructureRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); #else short left, top, width, height; int ix, numText = 0, numMenu = 0; int mbar_height = GetMBarHeight(); BitMap qbitmap; Rect screenArea; WindowPtr theWindow; NhWindow *nhWin; screenArea = GetQDGlobalsScreenBits(&qbitmap)->bounds; OffsetRect (&screenArea, - screenArea.left, - screenArea.top); /* Map Window */ height = _mt_window->portRect.bottom - _mt_window->portRect.top; width = _mt_window->portRect.right - _mt_window->portRect.left; if (!RetrievePosition (kMapWindow, &top, &left)) { top = mbar_height + (small_screen ? 2 : 20); left = (screenArea.right - width) / 2; } MoveWindow (_mt_window, left, top, 1); /* Message Window */ if (!RetrievePosition (kMessageWindow, &top, &left)) { top += height; if (!small_screen) top += 20; } if (!RetrieveSize (kMessageWindow, top, left, &height, &width)) { height = screenArea.bottom - top - (small_screen ? 2-SBARHEIGHT : 2); if (height > MAX_HEIGHT) { height = MAX_HEIGHT; } else if (height < MIN_HEIGHT) { height = MIN_HEIGHT; width = MIN_WIDTH; left = screenArea.right - width; top = screenArea.bottom - MIN_HEIGHT; } } /* Move these windows */ nhWin = theWindows + WIN_MESSAGE; theWindow = nhWin->its_window; MoveWindow (theWindow, left, top, 1); SizeWindow (theWindow, width, height, 1); if (nhWin->scrollBar) DrawScrollbar (nhWin); /* Handle other windows */ for (ix = 0; ix < NUM_MACWINDOWS; ix ++) { if (ix != WIN_STATUS && ix != WIN_MESSAGE && ix != WIN_MAP && ix != BASE_WINDOW) { theWindow = theWindows [ix].its_window; if (theWindow && ((WindowPeek) theWindow)->visible) { int shift; if (((WindowPeek)theWindow)->windowKind == WIN_BASE_KIND + NHW_MENU) { if (!RetrievePosition (kMenuWindow, &top, &left)) { top = mbar_height * 2; left = 2; } top += (numMenu * mbar_height); numMenu++; shift = 20; } else { if (!RetrievePosition (kTextWindow, &top, &left)) { top = mbar_height * 2; left = screenArea.right - 3 - (theWindow->portRect.right - theWindow->portRect.left); } top += (numText * mbar_height); numText++; shift = -20; } while (top > screenArea.bottom - MIN_HEIGHT) { top -= screenArea.bottom - mbar_height * 2; left += shift; } MoveWindow (theWindow, left, top, 1); } } } #endif return (0); } winid mac_create_nhwindow (int kind) { int i; NhWindow *aWin; FontInfo fi; if (kind < NHW_BASE || kind > NHW_TEXT) { error ("cre_win: Invalid kind %d.", kind); return WIN_ERR; } for (i = 0; i < NUM_MACWINDOWS; i ++) { if (!theWindows [i].its_window) break; } if (i >= NUM_MACWINDOWS) { error ("cre_win: Win full; freeing extras"); for (i = 0; i < NUM_MACWINDOWS; i ++) { if (IsWindowVisible(theWindows [i].its_window) || i == WIN_INVEN || GetWindowKind(theWindows [i].its_window) != WIN_BASE_KIND + NHW_MENU && GetWindowKind(theWindows [i].its_window) != WIN_BASE_KIND + NHW_TEXT) continue; mac_destroy_nhwindow(i); goto got1; } error ("cre_win: Out of ids!"); return WIN_ERR; } got1 : aWin = &theWindows [i]; aWin->windowTextLen = 0L; aWin->scrollBar = (ControlHandle) 0; aWin->menuInfo = 0; aWin->menuSelected = 0; aWin->miLen = 0; aWin->miSize = 0; aWin->menuChar = 'a'; dprintf ("cre_win: New kind %d", kind); if (kind == NHW_BASE || kind == NHW_MAP || kind == NHW_STATUS) { short x_sz, x_sz_p, y_sz, y_sz_p; if (kind != NHW_BASE) { if (i != tty_create_nhwindow(kind)) { dprintf ("cre_win: error creating kind %d", kind); } if (kind == NHW_MAP) { wins[i]->offy = 0; /* the message box is in a separate window */ } } aWin->its_window = _mt_window; get_tty_metrics(aWin->its_window, &x_sz, &y_sz, &x_sz_p, &y_sz_p, &aWin->font_number, &aWin->font_size, &aWin->char_width, &aWin->row_height); return i; } aWin->its_window = GetNewWindow (WIN_BASE_RES + kind, (WindowPtr) 0L, (WindowPtr) -1L); SetWindowKind(aWin->its_window, WIN_BASE_KIND + kind); SetWRefCon(aWin->its_window, (long) aWin); if (!(aWin->windowText = NewHandle (TEXT_BLOCK))) { error ("cre_win: NewHandle fail(%ld)", (long) TEXT_BLOCK); DisposeWindow (aWin->its_window); aWin->its_window = (WindowPtr) 0; return WIN_ERR; } aWin->x_size = aWin->y_size = 0; aWin->x_curs = aWin->y_curs = 0; aWin->drawn = TRUE; mac_clear_nhwindow (i); SetPortWindowPort(aWin->its_window); if (kind == NHW_MESSAGE) { aWin->font_number = win_fonts [NHW_MESSAGE]; aWin->font_size = iflags.wc_fontsiz_message? iflags.wc_fontsiz_message : iflags.large_font ? 12 : 9; if (!top_line) { const Rect out_of_scr = {10000, 10000, 10100, 10100}; TextFont(aWin->font_number); TextSize(aWin->font_size); TextFace(bold); top_line = TENew(&out_of_scr, &out_of_scr); TEActivate(top_line); TextFace(normal); } } else { aWin->font_number = win_fonts [NHW_TEXT]; aWin->font_size = iflags.wc_fontsiz_text ? iflags.wc_fontsiz_text : 9; } TextFont (aWin->font_number); TextSize (aWin->font_size); GetFontInfo (&fi); aWin->ascent_height = fi.ascent + fi.leading; aWin->row_height = aWin->ascent_height + fi.descent; aWin->char_width = fi.widMax; if (kind == NHW_MENU || kind == NHW_TEXT || kind == NHW_MESSAGE) { Rect r; GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); r.right -= (r.left - 1); r.left = r.right - SBARWIDTH; r.bottom -= (r.top + SBARHEIGHT); r.top = -1; aWin->scrollBar = NewControl (aWin->its_window, &r, "\p", (r.bottom > r.top + 50), 0, 0, 0, 16, 0L); aWin->scrollPos = 0; } return i; } void mac_init_nhwindows (int *argcp, char **argv) { #if !TARGET_API_MAC_CARBON Rect scr = (*GetGrayRgn())->rgnBBox; small_screen = scr.bottom - scr.top <= (iflags.large_font ? 12*40 : 9*40); #endif Rect r; InitMenuRes (); theWindows = (NhWindow *) NewPtrClear (NUM_MACWINDOWS * sizeof (NhWindow)); if (MemError()) error("mac_init_nhwindows: Couldn't allocate memory for windows."); DimMenuBar (); tty_init_nhwindows(argcp, argv); iflags.window_inited = TRUE; /* Some ugly hacks to make both interfaces happy: * Mac port uses both tty interface (for main map) and extra windows. The winids need to * be kept in synch for both interfaces to map. Also, the "blocked" display_nhwindow case * for the map automatically calls the tty interface for the message box, so some version * of the message box has to exist in the tty world to prevent a meltdown, even though most * messages are handled in mac window. */ mac_create_nhwindow(NHW_BASE); tty_create_nhwindow(NHW_MESSAGE); RetrievePosition(kMessageWindow, &r.top, &r.left); RetrieveSize(kMessageWindow, r.top, r.left, &r.bottom, &r.right); MoveWindow(theWindows[NHW_MESSAGE].its_window, r.left, r.top, false); SizeWindow(theWindows[NHW_MESSAGE].its_window, r.right, r.bottom, true); ConstrainWindowToScreen(theWindows[NHW_MESSAGE].its_window, kWindowStructureRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); return; } void mac_clear_nhwindow (winid win) { long l; Rect r; NhWindow *aWin = &theWindows [win]; WindowPtr theWindow = aWin->its_window; if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) { error ("clr_win: Invalid win %d.", win); return; } if (theWindow == _mt_window) { tty_clear_nhwindow(win); return; } if (!aWin->drawn) return; SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (aWin->scrollBar) r.right -= SBARWIDTH; switch (GetWindowKind(theWindow) - WIN_BASE_KIND) { case NHW_MESSAGE : if (aWin->scrollPos == aWin->y_size - 1) /* if no change since last clear */ return; /* don't bother with redraw */ r.bottom -= SBARHEIGHT; for (l = 0; aWin->y_size > iflags.msg_history;) { const char cr = CHAR_CR; l = Munger(aWin->windowText, l, &cr, 1, nil, 0) + 1; --aWin->y_size; } if (l) { aWin->windowTextLen -= l; BlockMove(*aWin->windowText + l, *aWin->windowText, aWin->windowTextLen); } aWin->last_more_lin = aWin->y_size; aWin->save_lin = aWin->y_size; aWin->scrollPos = aWin->y_size ? aWin->y_size - 1 : 0; break; case NHW_MENU: if (aWin->menuInfo) { DisposeHandle((Handle)aWin->menuInfo); aWin->menuInfo = NULL; } if (aWin->menuSelected) { DisposeHandle((Handle)aWin->menuSelected); aWin->menuSelected = NULL; } aWin->menuChar = 'a'; aWin->miSelLen = 0; aWin->miLen = 0; aWin->miSize = 0; /* Fall-Through */ default : SetHandleSize (aWin->windowText, TEXT_BLOCK); aWin->windowTextLen = 0L; aWin->x_size = 0; aWin->y_size = 0; aWin->scrollPos = 0; break; } if (aWin->scrollBar) { SetControlMaximum (aWin->scrollBar, aWin->y_size); SetControlValue(aWin->scrollBar, aWin->scrollPos); } aWin->y_curs = 0; aWin->x_curs = 0; aWin->drawn = FALSE; InvalWindowRect(theWindow, &r); } static Boolean ClosingWindowChar(const int c) { return c == CHAR_ESC || c == CHAR_BLANK || c == CHAR_LF || c == CHAR_CR || c == 'q'; } static Boolean in_topl_mode(void) { Rect rect; GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); return (WIN_MESSAGE != WIN_ERR && top_line && (*top_line)->viewRect.left < rect.right); } #define BTN_IND 2 #define BTN_W 40 #define BTN_H (SBARHEIGHT-3) static void topl_resp_rect(int resp_idx, Rect *r) { Rect rect; GetWindowBounds(theWindows[WIN_MESSAGE].its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); r->left = (BTN_IND + BTN_W) * resp_idx + BTN_IND; r->right = r->left + BTN_W; r->bottom = rect.bottom - 1; r->top = r->bottom - BTN_H; return; } void enter_topl_mode(char *query) { if (in_topl_mode()) return; putstr(WIN_MESSAGE, ATR_BOLD, query); topl_query_len = strlen(query); (*top_line)->selStart = topl_query_len; (*top_line)->selEnd = topl_query_len; (*top_line)->viewRect.left = 0; PtrToXHand(query, (*top_line)->hText, topl_query_len); TECalText(top_line); DimMenuBar(); mac_display_nhwindow(WIN_MESSAGE, FALSE); } void leave_topl_mode(char *answer) { unsigned char *ap, *bp; int ans_len = (*top_line)->teLength - topl_query_len; NhWindow *aWin = theWindows + WIN_MESSAGE; if (!in_topl_mode()) return; /* Cap length of reply */ if (ans_len >= BUFSZ) ans_len = BUFSZ-1; /* remove unprintables from the answer */ for (ap = *(*top_line)->hText + topl_query_len, bp = answer; ans_len > 0; ans_len--, ap++) { if (*ap >= ' ' && *ap < 128) { *bp++ = *ap; } } *bp = 0; if (aWin->windowTextLen && (*aWin->windowText)[aWin->windowTextLen-1] == CHAR_CR) { -- aWin->windowTextLen; -- aWin->y_size; } putstr(WIN_MESSAGE, ATR_BOLD, answer); (*top_line)->viewRect.left += 10000; UndimMenuBar(); } /* * TESetSelect flushes out all the pending key strokes. I hate it. */ static void topl_set_select(short selStart, short selEnd) { TEDeactivate(top_line); (*top_line)->selStart = selStart; (*top_line)->selEnd = selEnd; TEActivate(top_line); } static void topl_replace(char *new_ans) { topl_set_select(topl_query_len, (*top_line)->teLength); TEDelete(top_line); TEInsert(new_ans, strlen(new_ans), top_line); } Boolean topl_key(unsigned char ch, Boolean ext) { switch (ch) { case CHAR_ESC: topl_replace("\x1b"); case CHAR_ENTER: case CHAR_CR: case CHAR_LF: return false; case 0x1f & 'P': mac_doprev_message(); return true; case '\x1e'/* up arrow */: topl_replace (""); return true; case CHAR_BS: case '\x1c'/* left arrow */: if ((*top_line)->selEnd <= topl_query_len) return true; else if (ext) { topl_replace (""); return true; } default: TEKey(ch, top_line); if (ext) { int com_index = -1, oindex = 0; while(extcmdlist[oindex].ef_txt != (char *)0) { if(!strncmpi(*(*top_line)->hText + topl_query_len, extcmdlist[oindex].ef_txt, (*top_line)->teLength - topl_query_len)) { if(com_index == -1) /* No matches yet*/ com_index = oindex; else /* More than 1 match */ { com_index = -2; break; } } oindex++; } if(com_index >= 0) topl_replace((char *) extcmdlist[com_index].ef_txt); } return true; } } static void topl_flash_resp(int resp_idx) { unsigned long dont_care; Rect frame; SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); topl_resp_rect(resp_idx, &frame); InsetRect(&frame, 1, 1); InvertRect(&frame); Delay(GetDblTime() / 2, &dont_care); InvertRect(&frame); } static void topl_set_def(int new_def_idx) { Rect frame; SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); topl_resp_rect(topl_def_idx, &frame); InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); topl_def_idx = new_def_idx; topl_resp_rect(new_def_idx, &frame); InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); } void topl_set_resp(char *resp, char def) { char *loc; Rect frame; int r_len, r_len1; if (!resp) { const char any_str[2] = {CHAR_ANY, '\0'}; resp = (char *) any_str; def = CHAR_ANY; } SetPortWindowPort(theWindows[WIN_MESSAGE].its_window); r_len1 = strlen(resp); r_len = strlen(topl_resp); if (r_len < r_len1) r_len = r_len1; topl_resp_rect(0, &frame); frame.right = (BTN_IND + BTN_W) * r_len; InvalWindowRect(theWindows[WIN_MESSAGE].its_window, &frame); strcpy(topl_resp, resp); loc = strchr (resp, def); topl_def_idx = loc ? loc - resp : -1; } static char topl_resp_key(char ch) { if (strlen(topl_resp) > 0) { char *loc = strchr(topl_resp, ch); if (!loc) { if (ch == '\x9'/* tab */) { topl_set_def(topl_def_idx<=0 ? strlen(topl_resp)-1 : topl_def_idx-1); ch = '\0'; } else if (ch == CHAR_ESC) { loc = strchr(topl_resp, 'q'); if (!loc) { loc = strchr(topl_resp, 'n'); if (!loc && topl_def_idx >= 0) loc = topl_resp + topl_def_idx; } } else if (ch == (0x1f & 'P')) { mac_doprev_message(); ch = '\0'; } else if (topl_def_idx >= 0) { if (ch == CHAR_ENTER || ch == CHAR_CR || ch == CHAR_LF || ch == CHAR_BLANK || topl_resp[topl_def_idx] == CHAR_ANY) loc = topl_resp + topl_def_idx; else if (strchr(topl_resp, '#')) { if (digit(ch)) { topl_set_def(strchr(topl_resp, '#') - topl_resp); TEKey(ch, top_line); ch = '\0'; } else if (topl_resp[topl_def_idx] == '#') { if (ch == '\x1e'/* up arrow */) { topl_set_select(topl_query_len, topl_query_len); ch = '\0'; } else if (ch == '\x1d'/* right arrow */ || ch == '\x1f'/* down arrow */ || ch == CHAR_BS || ch == '\x1c'/* left arrow */ && (*top_line)->selEnd > topl_query_len) { TEKey(ch, top_line); ch = '\0'; } } } } } if (loc) { topl_flash_resp(loc - topl_resp); if (*loc != CHAR_ANY) ch = *loc; TEKey(ch, top_line); } } return ch; } static void adjust_window_pos(NhWindow *aWin, short width, short height) { WindowRef theWindow = aWin->its_window; #if TARGET_API_MAC_CARBON Rect r; GetWindowBounds(theWindow, kWindowContentRgn, &r); RetrieveWinPos(theWindow, &r.top, &r.left); MoveWindow(theWindow, r.left, r.top, false); SizeWindow(theWindow, width, height, true); ConstrainWindowToScreen(theWindow, kWindowStructureRgn, kWindowConstrainMoveRegardlessOfFit, NULL, NULL); #else Rect scr_r = (*GetGrayRgn())->rgnBBox; const Rect win_ind = {2, 2, 3, 3}; const short min_w = theWindow->portRect.right - theWindow->portRect.left, max_w = scr_r.right - scr_r.left - win_ind.left - win_ind.right; Point pos; short max_h; SetPortWindowPort(theWindow); if (!RetrieveWinPos(theWindow, &pos.v, &pos.h)) { pos.v = 0; /* take window's existing position */ pos.h = 0; LocalToGlobal(&pos); } max_h = scr_r.bottom - win_ind.bottom - pos.v; if (height > max_h) height = max_h; if (height < MIN_HEIGHT) height = MIN_HEIGHT; if (width < min_w) width = min_w; if (width > max_w) width = max_w; SizeWindow(theWindow, width, height, true); if (pos.v + height + win_ind.bottom > scr_r.bottom) pos.v = scr_r.bottom - height - win_ind.bottom; if (pos.h + width + win_ind.right > scr_r.right) pos.h = scr_r.right - width - win_ind.right; MoveWindow(theWindow, pos.h, pos.v, false); if (aWin->scrollBar) DrawScrollbar (aWin); #endif return; } /* * display/select/update the window. * If f is true, this window should be "modal" - don't return * until presumed seen. */ void mac_display_nhwindow (winid win, BOOLEAN_P f) { NhWindow *aWin = &theWindows [win]; WindowPtr theWindow = aWin->its_window; if (win < 0 || win >= NUM_MACWINDOWS || !theWindow) { error ("disp_win: Invalid window %d.", win); return; } if (theWindow == _mt_window) { tty_display_nhwindow(win, f); return; } if (f && inSelect == WIN_ERR && win == WIN_MESSAGE) { topl_set_resp ((char *)0, 0); if (aWin->windowTextLen > 0 && (*aWin->windowText) [aWin->windowTextLen - 1] == CHAR_CR) { -- aWin->windowTextLen; -- aWin->y_size; } putstr (win, flags.standout ? ATR_INVERSE : ATR_NONE, " --More--"); } if (!IsWindowVisible(theWindow)) { if (win != WIN_MESSAGE) adjust_window_pos(aWin, aWin->x_size + SBARWIDTH+1, aWin->y_size *aWin->row_height); SelectWindow (theWindow); ShowWindow (theWindow); } if (f && inSelect == WIN_ERR) { int ch; DimMenuBar(); inSelect = win; do { ch = mac_nhgetch (); } while (!ClosingWindowChar (ch)); inSelect = WIN_ERR; UndimMenuBar(); if (win == WIN_MESSAGE) topl_set_resp ("", '\0'); else HideWindow (theWindow); } } void mac_destroy_nhwindow (winid win) { WindowPtr theWindow; NhWindow *aWin = &theWindows [win]; int kind; if (win < 0 || win >= NUM_MACWINDOWS) { if (iflags.window_inited) error ("dest_win: Invalid win %d.", win); return; } theWindow = aWin->its_window; if (!theWindow) { error ("dest_win: Not allocated win %d.", win); return; } /* * Check special windows. The base window should never go away. * Other "standard" windows should not go away unless we've exitted nhwindows. */ if (theWindow == _mt_window) { return; } if (win == WIN_INVEN || win == WIN_MESSAGE) { if (iflags.window_inited) { if (flags.tombstone && killer) { /* Prepare for the coming of the tombstone window. */ win_fonts [NHW_TEXT] = kFontIDMonaco; } return; } if (win == WIN_MESSAGE) WIN_MESSAGE = WIN_ERR; } kind = GetWindowKind(theWindow) - WIN_BASE_KIND; if ((!IsWindowVisible(theWindow) || (kind != NHW_MENU && kind != NHW_TEXT))) { DisposeWindow (theWindow); if (aWin->windowText) { DisposeHandle(aWin->windowText); } aWin->its_window = (WindowPtr) 0; aWin->windowText = (Handle) 0; } } void mac_number_pad (int pad) { iflags.num_pad = pad; } void trans_num_keys(EventRecord *theEvent) { #if defined(__SC__) || defined(__MRC__) # pragma unused(theEvent) #endif /* KMH -- Removed this translation. * Number pad keys should always emit digit characters. * That's consistent with the default MacOS behavior. * The number_pad option controls how digits are interpreted. */ #if 0 if (iflags.num_pad) { Handle h = GetResource('Nump', theEvent->modifiers & shiftKey ? 129 : 128); if (h) { short inkey = (theEvent->message & keyCodeMask), *ab = (short *)*h; int i = ab[0]; for (; i; i--) { if (inkey == (ab[i] & keyCodeMask)) { theEvent->message = ab[i]; break; } } } } #endif } /* * Note; theWindow may very well be null here, since keyDown may call * it when theres no window !!! */ static void GeneralKey (EventRecord *theEvent, WindowPtr theWindow) { #if defined(__SC__) || defined(__MRC__) # pragma unused(theWindow) #endif #if 0 trans_num_keys (theEvent); #endif AddToKeyQueue (topl_resp_key (theEvent->message & 0xff), TRUE); } /* * Routine used to select and de-select elements in a menu window, used by KeyMenu, * ClickMenu, and UpdateMenu. Takes the NhWindow and a line ref relative to the scrollbar. */ static void ToggleMenuSelect (NhWindow *aWin, int line) { Rect r; GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (aWin->scrollBar) r.right -= SBARWIDTH; r.top = line * aWin->row_height; r.bottom = r.top + aWin->row_height; LMSetHiliteMode((UInt8) (LMGetHiliteMode() & 0x7F)); InvertRect(&r); } /* * Check to see if given item is selected, return index if it is */ static int ListItemSelected (NhWindow *aWin, int item) { int i; HLock ((char**)aWin->menuSelected); /* Find item in selection list */ for (i = aWin->miSelLen - 1; i >= 0; i--) { if ((*aWin->menuSelected) [i] == item) break; } HUnlock ((char**)aWin->menuSelected); return i; } /* * Add item to selection list if it's not selected already * If it is selected already, remove it from the list. */ static void ToggleMenuListItemSelected (NhWindow *aWin, short item) { int i = ListItemSelected (aWin, item); HLock ((char**)aWin->menuSelected); if (i < 0) { /* not there, so add */ (*aWin->menuSelected) [aWin->miSelLen] = item; aWin->miSelLen++; } else { /* there, so remove */ short *mi = &(*aWin->menuSelected)[i]; aWin->miSelLen --; memcpy (mi, mi + 1, (aWin->miSelLen - i)*sizeof(short)); } HUnlock ((char**)aWin->menuSelected); } /* * Find menu item in list given a line number on the window */ static short ListCoordinateToItem (NhWindow *aWin, short Row) { int i, item = -1; MacMHMenuItem * mi; HLock ((char**)aWin->menuInfo); for (i = 0, mi = *aWin->menuInfo; i < aWin->miLen; i++, mi++) { if (mi->line == Row + aWin->scrollPos) { item = i; break; } } HUnlock ((char**)aWin->menuInfo); return item; } static void macKeyMenu (EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin(theWindow); MacMHMenuItem *mi; int l, ch = theEvent->message & 0xff; if (aWin && aWin->menuInfo) { HLock ((char**)aWin->menuInfo); for (l = 0, mi = *aWin->menuInfo; l < aWin->miLen; l++, mi++) { if (mi->accelerator == ch) { ToggleMenuListItemSelected (aWin, l); if (mi->line >= aWin->scrollPos && mi->line <= aWin->y_size) { SetPortWindowPort(theWindow); ToggleMenuSelect (aWin, mi->line - aWin->scrollPos); } /* Dismiss window if only picking one item */ if (aWin->how != PICK_ANY) AddToKeyQueue(CHAR_CR, 1); break; } } HUnlock ((char**)aWin->menuInfo); /* add key if didn't find it in menu and not filtered */ if (l == aWin->miLen && filter_scroll_key (ch, aWin)) GeneralKey (theEvent, theWindow); } } static void macClickMenu (EventRecord *theEvent, WindowRef theWindow) { Point p; NhWindow *aWin = GetNhWin(theWindow); Rect wrect; GetWindowBounds(theWindow, kWindowContentRgn, &wrect); OffsetRect(&wrect, -wrect.left, -wrect.top); if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) { short code; ControlHandle theBar; p = theEvent->where; GlobalToLocal (&p); code = FindControl (p, theWindow, &theBar); if (code) { DoScrollBar (p, code, theBar, aWin); return; } } if (inSelect != WIN_ERR && aWin->how != PICK_NONE) { short currentRow = -1, previousRow = -1; short previousItem = -1, item = -1; Boolean majorSelectState, firstRow = TRUE; do { #if !TARGET_API_MAC_CARBON SystemTask (); #endif GetMouse (&p); currentRow = p.v / aWin->row_height; if (p.h < wrect.left || p.h > wrect.right || p.v < 0 || p.v > wrect.bottom || currentRow >= aWin->y_size) { continue; /* not in window range */ } item = ListCoordinateToItem (aWin, currentRow); if (item != previousItem) { /* Implement typical Mac multiple-selection behavior * (ie, not the UI implemented by the Finder) */ Boolean itemIsSelected = (ListItemSelected (aWin,item) >= 0); if (firstRow) { /* this is first valid row, so major state is opposite of what this row is */ majorSelectState = !itemIsSelected; firstRow = FALSE; } if (aWin->how == PICK_ONE && previousItem != -1) { /* if previous row was selected and we're only selecting one object, * deselect previous row! */ ToggleMenuListItemSelected (aWin, previousItem); ToggleMenuSelect (aWin, previousRow); previousItem = -1; } if (item == -1) continue; /* header line */ if (majorSelectState != itemIsSelected) { ToggleMenuListItemSelected (aWin, item); ToggleMenuSelect (aWin, currentRow); } previousRow = currentRow; previousItem = item; } } while (StillDown ()); /* Dismiss window if only picking one item */ if (aWin->how == PICK_ONE) AddToKeyQueue(CHAR_CR, 1); } } static void macKeyText (EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin (theWindow); char c = filter_scroll_key (theEvent->message & 0xff, aWin); if (c) { if (inSelect == WIN_ERR && ClosingWindowChar (c)) { HideWindow (theWindow); mac_destroy_nhwindow (aWin - theWindows); } else { GeneralKey (theEvent, theWindow); } } } static void macClickText (EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin (theWindow); if (aWin->scrollBar && IsControlVisible(aWin->scrollBar)) { short code; Point p = theEvent->where; ControlHandle theBar; GlobalToLocal (&p); code = FindControl (p, theWindow, &theBar); if (code) { DoScrollBar (p, code, theBar, aWin); } } } static void macClickMessage (EventRecord *theEvent, WindowPtr theWindow) { int r_idx = 0; Point mouse = theEvent->where; GlobalToLocal(&mouse); while (topl_resp[r_idx]) { Rect frame; topl_resp_rect(r_idx, &frame); InsetRect(&frame, 1, 1); if (PtInRect(mouse, &frame)) { Boolean in_btn = true; InvertRect(&frame); while (WaitMouseUp()) { #if !TARGET_API_MAC_CARBON SystemTask(); #endif GetMouse(&mouse); if (PtInRect(mouse, &frame) != in_btn) { in_btn = !in_btn; InvertRect(&frame); } } if (in_btn) { InvertRect(&frame); AddToKeyQueue (topl_resp [r_idx], 1); } return; } ++r_idx; } macClickText(theEvent, theWindow); } static void macClickTerm (EventRecord *theEvent, WindowPtr theWindow) { NhWindow *nhw = GetNhWin(theWindow); Point where = theEvent->where; GlobalToLocal(&where); where.h = where.h / nhw->char_width + 1; where.v = where.v / nhw->row_height; clicked_mod = (theEvent->modifiers & shiftKey) ? CLICK_2 : CLICK_1; if (strchr(topl_resp, *click_to_cmd(where.h, where.v, clicked_mod))) nhbell(); else { #if !TARGET_API_MAC_CARBON if (cursor_locked) while (WaitMouseUp()) SystemTask(); #endif gClickedToMove = TRUE; clicked_pos = where; } } static pascal void MoveScrollBar (ControlHandle theBar, short part) { EventRecord fake; Rect r; RgnHandle rgn; int now, amtToScroll; WindowPtr theWin; NhWindow *winToScroll; if (!part) return; theWin = GetControlOwner(theBar); GetWindowBounds(theWin, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); winToScroll = (NhWindow*)(GetWRefCon(theWin)); now = GetControlValue (theBar); if (part == kControlPageUpPart || part == kControlPageDownPart) amtToScroll = (r.bottom - r.top) / winToScroll->row_height; else amtToScroll = 1; if (part == kControlPageUpPart || part == kControlUpButtonPart) { int bound = GetControlMinimum (theBar); if (now - bound < amtToScroll) amtToScroll = now - bound; amtToScroll = -amtToScroll; } else { int bound = GetControlMaximum (theBar); if (bound - now < amtToScroll) amtToScroll = bound - now; } if (!amtToScroll) return; SetControlValue (theBar, now + amtToScroll); winToScroll->scrollPos = now + amtToScroll; r.right -= SBARWIDTH; if (winToScroll == theWindows + WIN_MESSAGE) r.bottom -= SBARHEIGHT; rgn = NewRgn (); ScrollRect (&r, 0, -amtToScroll * winToScroll->row_height, rgn); if (rgn) { InvalWindowRgn(theWin, rgn); BeginUpdate(theWin); } winUpdateFuncs [GetWindowKind(theWin) - WIN_BASE_KIND] (&fake, theWin); if (rgn) { EndUpdate(theWin); DisposeRgn(rgn); } } static void DoScrollBar (Point p, short code, ControlHandle theBar, NhWindow *aWin) { ControlActionUPP func = NULL; Rect rect; if (code == kControlUpButtonPart || code == kControlPageUpPart || code == kControlDownButtonPart || code == kControlPageDownPart) func = MoveScrollUPP; (void) TrackControl(theBar, p, func); if (!func) { if (aWin->scrollPos != GetControlValue (theBar)) { aWin->scrollPos = GetControlValue (theBar); GetWindowBounds(aWin->its_window, kWindowContentRgn, &rect); OffsetRect(&rect, -rect.left, -rect.top); InvalWindowRect(aWin->its_window, &rect); } } } static int filter_scroll_key(const int ch, NhWindow *aWin) { if (aWin->scrollBar && GetControlValue(aWin->scrollBar) < GetControlMaximum(aWin->scrollBar)) { short part = 0; if (ch == CHAR_BLANK) { part = kControlPageDownPart; } else if (ch == CHAR_CR || ch == CHAR_LF) { part = kControlDownButtonPart; } if (part) { SetPortWindowPort(aWin->its_window); MoveScrollBar(aWin->scrollBar, part); return 0; } } return ch; } int mac_doprev_message(void) { if (WIN_MESSAGE) { NhWindow *winToScroll = &theWindows[WIN_MESSAGE]; mac_display_nhwindow(WIN_MESSAGE, FALSE); SetPortWindowPort(winToScroll->its_window); MoveScrollBar(winToScroll->scrollBar, kControlUpButtonPart); } return 0; } static short macDoNull (EventRecord *theEvent, WindowPtr theWindow) { return 0; } static void draw_growicon_vert_only(WindowPtr wind) { GrafPtr org_port; RgnHandle org_clip = NewRgn(); Rect r; GetPort(&org_port); SetPortWindowPort(wind); GetClip(org_clip); GetWindowBounds(wind, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); r.left = r.right - SBARWIDTH; ClipRect(&r); DrawGrowIcon(wind); SetClip(org_clip); DisposeRgn(org_clip); SetPort(org_port); } static short macUpdateMessage (EventRecord *theEvent, WindowPtr theWindow) { RgnHandle org_clip = NewRgn(), clip = NewRgn(); Rect r; NhWindow *aWin = GetNhWin(theWindow); int l; if (!theEvent) return 0; GetClip(org_clip); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); DrawControls(theWindow); DrawGrowIcon(theWindow); for (l = 0; topl_resp[l]; l++) { StringPtr name; unsigned char tmp[2]; FontInfo font; Rect frame; topl_resp_rect(l, &frame); switch (topl_resp[l]) { case 'y': name = "\pyes"; break; case 'n': name = "\pno"; break; case 'N': name = "\pNone"; break; case 'a': name = "\pall"; break; case 'q': name = "\pquit"; break; case CHAR_ANY: name = "\pany key"; break; default: tmp[0] = 1; tmp[1] = topl_resp[l]; name = tmp; break; } TextFont(kFontIDGeneva); TextSize(9); GetFontInfo(&font); MoveTo ((frame.left + frame.right - StringWidth(name)) / 2, (frame.top + frame.bottom + font.ascent-font.descent-font.leading-1) / 2); DrawString(name); PenNormal(); if (l == topl_def_idx) PenSize(2, 2); FrameRoundRect(&frame, 4, 4); } r.right -= SBARWIDTH; r.bottom -= SBARHEIGHT; /* Clip to the portrect - scrollbar/growicon *before* adjusting the rect to be larger than the size of the window (!) */ RectRgn(clip, &r); SectRgn(clip, org_clip, clip); if (r.right < MIN_RIGHT) r.right = MIN_RIGHT; r.top -= aWin->scrollPos * aWin->row_height; #if 0 /* If you enable this band of code (and disable the next band), you will get fewer flickers but a slower performance while drawing the dot line. */ { RgnHandle dotl_rgn = NewRgn(); Rect dotl; dotl.left = r.left; dotl.right = r.right; dotl.bottom = r.top + aWin->save_lin * aWin->row_height; dotl.top = dotl.bottom - 1; FillRect(&dotl, &qd.gray); RectRgn(dotl_rgn, &dotl); DiffRgn(clip, dotl_rgn, clip); DisposeRgn(dotl_rgn); SetClip(clip); } #endif if (in_topl_mode()) { RgnHandle topl_rgn = NewRgn(); Rect topl_r = r; topl_r.top += (aWin->y_size - 1) * aWin->row_height; l = (*top_line)->destRect.right - (*top_line)->destRect.left; (*top_line)->viewRect = topl_r; (*top_line)->destRect = topl_r; if (l != topl_r.right - topl_r.left) TECalText(top_line); TEUpdate(&topl_r, top_line); RectRgn(topl_rgn, &topl_r); DiffRgn(clip, topl_rgn, clip); DisposeRgn(topl_rgn); SetClip(clip); } DisposeRgn(clip); TextFont (aWin->font_number); TextSize (aWin->font_size); HLock (aWin->windowText); TETextBox (*aWin->windowText, aWin->windowTextLen, &r, teJustLeft); HUnlock (aWin->windowText); #if !TARGET_API_MAC_CARBON r.bottom = r.top + aWin->save_lin * aWin->row_height; r.top = r.bottom - 1; FillRect(&r, (void *) &qd.gray); #endif SetClip(org_clip); DisposeRgn(org_clip); return 0; } static short macUpdateMenu (EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin (theWindow); int i, line; MacMHMenuItem *mi; GeneralUpdate (theEvent, theWindow); HLock ((char**)aWin->menuInfo); HLock ((char**)aWin->menuSelected); for (i = 0; i < aWin->miSelLen; i++) { mi = &(*aWin->menuInfo) [(*aWin->menuSelected) [i]]; line = mi->line; if (line > aWin->scrollPos && line <= aWin->y_size) ToggleMenuSelect (aWin, line - aWin->scrollPos); } HUnlock ((char**)aWin->menuInfo); HUnlock ((char**)aWin->menuSelected); return 0; } static short GeneralUpdate (EventRecord *theEvent, WindowPtr theWindow) { Rect r, r2; NhWindow *aWin = GetNhWin (theWindow); RgnHandle h; Boolean vis; if (!theEvent) return 0; GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); r2 = r; r2.left = r2.right - SBARWIDTH; r2.right += 1; r2.top -= 1; vis = (r2.bottom > r2.top + 50); draw_growicon_vert_only(theWindow); DrawControls (theWindow); h = (RgnHandle) 0; if (vis && (h = NewRgn ())) { RgnHandle tmp = NewRgn (); if (!tmp) { DisposeRgn (h); h = (RgnHandle) 0; } else { GetClip (h); RectRgn (tmp, &r2); DiffRgn (h, tmp, tmp); SetClip (tmp); DisposeRgn (tmp); } } if (r.right < MIN_RIGHT) r.right = MIN_RIGHT; r.top -= aWin->scrollPos * aWin->row_height; r.right -= SBARWIDTH; HLock (aWin->windowText); TETextBox (*aWin->windowText, aWin->windowTextLen, &r, teJustLeft); HUnlock (aWin->windowText); if (h) { SetClip (h); DisposeRgn (h); } return 0; } static void macCursorTerm (EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) { char *dir_bas, *dir; CursHandle ch; GrafPtr gp; NhWindow *nhw = GetNhWin (theWindow); Rect r = {0, 0, 1, 1}; GetPort (&gp); SetPortWindowPort(theWindow); if (cursor_locked) dir = (char *)0; else { Point where = theEvent->where; GlobalToLocal (&where); dir_bas = iflags.num_pad ? (char *) ndir : (char *) sdir; dir = strchr (dir_bas, *click_to_cmd (where.h / nhw->char_width + 1 , where.v / nhw->row_height, CLICK_1)); } ch = GetCursor (dir ? dir - dir_bas + 513 : 512); if (ch) { HLock ((Handle) ch); SetCursor (*ch); HUnlock ((Handle) ch); } else { SetCursor(&qdarrow); } OffsetRect (&r, theEvent->where.h, theEvent->where.v); RectRgn (mouseRgn, &r); SetPort (gp); } static void GeneralCursor (EventRecord *theEvent, WindowPtr theWindow, RgnHandle mouseRgn) { #if defined(__SC__) || defined(__MRC__) # pragma unused(theWindow) #endif Rect r = {-1, -1, 2, 2}; SetCursor(&qdarrow); OffsetRect (&r, theEvent->where.h, theEvent->where.v); RectRgn (mouseRgn, &r); } static void HandleKey (EventRecord *theEvent) { WindowPtr theWindow = FrontWindow (); if (theEvent->modifiers & cmdKey) { if (theEvent->message & 0xff == '.') { /* Flush key queue */ keyQueueCount = keyQueueWrite = keyQueueRead = 0; theEvent->message = '\033'; goto dispatchKey; } else { UndimMenuBar (); DoMenuEvt (MenuKey (theEvent->message & 0xff)); } } else { dispatchKey : if (theWindow) { int kind = GetWindowKind(theWindow) - WIN_BASE_KIND; winKeyFuncs [kind] (theEvent, theWindow); } else { GeneralKey (theEvent, (WindowPtr) 0); } } } static void WindowGoAway (EventRecord *theEvent, WindowPtr theWindow) { NhWindow *aWin = GetNhWin(theWindow); if (!theEvent || TrackGoAway (theWindow, theEvent->where)) { if (aWin - theWindows == BASE_WINDOW && !iflags.window_inited) { AddToKeyQueue ('\033', 1); } else { HideWindow (theWindow); if (aWin - theWindows != inSelect) mac_destroy_nhwindow (aWin - theWindows); else /* if this IS the inSelect window put a close char */ AddToKeyQueue (CHAR_CR, 1); /* in queue to exit and maintain inSelect */ } } } static void HandleClick (EventRecord *theEvent) { int code; unsigned long l; WindowPtr theWindow; NhWindow *aWin; Rect r; Boolean not_inSelect; InsetRect(GetRegionBounds(GetGrayRgn(), &r), 4, 4); code = FindWindow (theEvent->where, &theWindow); aWin = GetNhWin (theWindow); not_inSelect = (inSelect == WIN_ERR || aWin - theWindows == inSelect); switch (code) { case inContent : if (not_inSelect) { int kind = GetWindowKind(theWindow) - WIN_BASE_KIND; winCursorFuncs [kind] (theEvent, theWindow, gMouseRgn); SelectWindow (theWindow); SetPortWindowPort(theWindow); winClickFuncs [kind] (theEvent, theWindow); } else { nhbell (); } break; case inDrag : if (not_inSelect) { SetCursor(&qdarrow); DragWindow (theWindow, theEvent->where, &r); SaveWindowPos(theWindow); } else { nhbell (); } break; case inGrow : if (not_inSelect) { SetCursor(&qdarrow); SetRect (&r, 80, 2 * aWin->row_height + 1, r.right, r.bottom); if (aWin == theWindows + WIN_MESSAGE) r.top += SBARHEIGHT; l = GrowWindow (theWindow, theEvent->where, &r); SizeWindow (theWindow, l & 0xffff, l >> 16, FALSE); SaveWindowSize(theWindow); SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); InvalWindowRect(theWindow, &r); if (aWin->scrollBar) { DrawScrollbar (aWin); } } else { nhbell (); } break; case inGoAway : WindowGoAway(theEvent, theWindow); break; case inMenuBar : DoMenuEvt (MenuSelect (theEvent->where)); break; #if !TARGET_API_MAC_CARBON case inSysWindow : SystemClick(theEvent, theWindow); #endif default : break; } } static void HandleUpdate (EventRecord *theEvent) { WindowPtr theWindow = (WindowPtr) theEvent->message; NhWindow *aWin = GetNhWin (theWindow); Rect r; char existing_update_region = FALSE; Rect rect; if (theWindow == _mt_window) { existing_update_region = (get_invalid_region (theWindow, &rect) == noErr); } BeginUpdate (theWindow); SetPortWindowPort(theWindow); GetWindowBounds(theWindow, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); EraseRect(&r); winUpdateFuncs [GetWindowKind(theWindow) - WIN_BASE_KIND] (theEvent, theWindow); if (theWindow == _mt_window && existing_update_region) { set_invalid_region (theWindow, &rect); } aWin->drawn = TRUE; EndUpdate (theWindow); } static void DoOsEvt (EventRecord *theEvent) { WindowRef win; short code; if ((theEvent->message & 0xff000000) == 0xfa000000) { /* Mouse Moved */ code = FindWindow (theEvent->where, &win); if (code != inContent) { Rect r = {-1, -1, 2, 2}; SetCursor(&qdarrow); OffsetRect (&r, theEvent->where.h, theEvent->where.v); RectRgn (gMouseRgn, &r); } else { int kind = GetWindowKind(win) - WIN_BASE_KIND; if (kind >= 0 && kind <= NHW_TEXT) { winCursorFuncs [kind] (theEvent, win, gMouseRgn); } } } } void HandleEvent (EventRecord *theEvent) { switch (theEvent->what) { case autoKey : case keyDown : HandleKey (theEvent); break; case updateEvt : HandleUpdate (theEvent); break; case mouseDown : HandleClick (theEvent); break; #if !TARGET_API_MAC_CARBON case diskEvt : if ((theEvent->message & 0xffff0000) != 0) { Point p = {150, 150}; (void) DIBadMount (p, theEvent->message); } break; #endif case osEvt : DoOsEvt (theEvent); break; case kHighLevelEvent: AEProcessAppleEvent(theEvent); default : break; } } void mac_get_nh_event(void) { EventRecord anEvent; /* KMH -- Don't proceed if the window system isn't set up */ if (!iflags.window_inited) return; (void) WaitNextEvent (everyEvent, &anEvent, -1, gMouseRgn); HandleEvent(&anEvent); } int mac_nhgetch(void) { int ch; long doDawdle; EventRecord anEvent; /* We want to take care of keys in the buffer as fast as * possible */ if (keyQueueCount) doDawdle = 0L; else { long total, contig; static char warn = 0; doDawdle = (in_topl_mode() ? GetCaretTime () : 120L); /* Since we have time, check memory */ PurgeSpace (&total, &contig); if (contig < 25000L || total < 50000L) { if (!warn) { pline ("Low Memory!"); warn = 1; } } else { warn = 0; } } do { (void) WaitNextEvent (everyEvent, &anEvent, doDawdle, gMouseRgn); HandleEvent (&anEvent); ch = GetFromKeyQueue (); } while (!ch && !gClickedToMove); if (!gClickedToMove) ObscureCursor (); else gClickedToMove = 0; #ifdef THINK_C if (ch == '\r') ch = '\n'; #endif return ch; } void mac_delay_output(void) { long destTicks = TickCount () + 1; while (TickCount () < destTicks) { mac_get_nh_event (); } } #ifdef CLIPPING static void mac_cliparound (int x, int y) { #if defined(__SC__) || defined(__MRC__) # pragma unused(x,y) #endif /* TODO */ } #endif void mac_exit_nhwindows (const char *s) { clear_screen (); tty_exit_nhwindows (s); mac_destroy_nhwindow (WIN_MESSAGE); mac_destroy_nhwindow (WIN_INVEN); } /* * Don't forget to decrease in_putstr before returning... */ void mac_putstr (winid win, int attr, const char *str) { long len, slen; NhWindow *aWin = &theWindows [win]; static char in_putstr = 0; short newWidth, maxWidth; Rect r; char *src, *sline, *dst, ch; if (win < 0 || win >= NUM_MACWINDOWS || !aWin->its_window) { error ("putstr: Invalid win %d (Max %d).", win, NUM_MACWINDOWS, attr); return; } if (aWin->its_window == _mt_window) { tty_putstr(win, attr, str); return; } if (in_putstr > 3) return; in_putstr ++; slen = strlen (str); SetPortWindowPort(aWin->its_window); GetWindowBounds(aWin->its_window, kWindowContentRgn, &r); OffsetRect(&r, -r.left, -r.top); if (win == WIN_MESSAGE) { r.right -= SBARWIDTH; r.bottom -= SBARHEIGHT; if (flags.page_wait && aWin->last_more_lin <= aWin->y_size - (r.bottom - r.top) / aWin->row_height) { aWin->last_more_lin = aWin->y_size; mac_display_nhwindow(win, TRUE); } } /* * A "default" text window - uses TETextBox * We just add the text, without attributes for now */ len = GetHandleSize (aWin->windowText); while (aWin->windowTextLen + slen + 1 > len) { len = (len > 2048) ? (len + 2048) : (len * 2); SetHandleSize (aWin->windowText, len); if (MemError ()) { error ("putstr: SetHandleSize"); aWin->windowTextLen = 0L; aWin->save_lin = 0; aWin->y_curs = 0; aWin->y_size = 0; } } len = aWin->windowTextLen; dst = *(aWin->windowText) + len; sline = src = (char *)str; maxWidth = newWidth = 0; for (ch = *src; ch; ch = *src) { if (ch == CHAR_LF) ch = CHAR_CR; *dst++ = ch; if (ch == CHAR_CR) { aWin->y_curs ++; aWin->y_size ++; aWin->x_curs = 0; newWidth = TextWidth (sline, 0, src - sline); if (newWidth > maxWidth) { maxWidth = newWidth; } sline = src+1; /* keep track of where new line begins */ } else aWin->x_curs ++; src++; } newWidth = TextWidth (sline, 0, src - sline); if (newWidth > maxWidth) { maxWidth = newWidth; } aWin->windowTextLen += slen; if (ch != CHAR_CR) { (*(aWin->windowText)) [len + slen] = CHAR_CR; aWin->windowTextLen ++; aWin->y_curs ++; aWin->y_size ++; aWin->x_curs = 0; } if (win == WIN_MESSAGE) { short min = aWin->y_size - (r.bottom - r.top) / aWin->row_height; if (aWin->scrollPos < min) { aWin->scrollPos = min; SetControlMaximum (aWin->scrollBar, aWin->y_size); SetControlValue(aWin->scrollBar, min); } InvalWindowRect(aWin->its_window, &r); } else /* Message has a fixed width, other windows base on content */ if (maxWidth > aWin->x_size) aWin->x_size = maxWidth; in_putstr --; } void mac_curs (winid win, int x, int y) { NhWindow *aWin = &theWindows [win]; if (aWin->its_window == _mt_window) { tty_curs(win, x, y); return; } SetPortWindowPort(aWin->its_window); MoveTo (x * aWin->char_width, (y * aWin->row_height) + aWin->ascent_height); aWin->x_curs = x; aWin->y_curs = y; } int mac_nh_poskey (int *a, int *b, int *c) { int ch = mac_nhgetch(); *a = clicked_pos.h; *b = clicked_pos.v; *c = clicked_mod; return ch; } void mac_start_menu (winid win) { HideWindow (theWindows [win].its_window); mac_clear_nhwindow (win); } void mac_add_menu (winid win, int glyph, const anything *any, CHAR_P menuChar, CHAR_P groupAcc, int attr, const char *inStr, int preselected) { #if defined(__SC__) || defined(__MRC__) # pragma unused(glyph) #endif NhWindow *aWin = &theWindows [win]; const char *str; char locStr[4+BUFSZ]; MacMHMenuItem *item; if (!inStr) return; if (any->a_void != 0) { #define kMenuSizeBump 26 if (!aWin->miSize) { aWin->menuInfo = (MacMHMenuItem **)NewHandle(sizeof(MacMHMenuItem) * kMenuSizeBump); if (!aWin->menuInfo) { error("Can't alloc menu handle"); return; } aWin->menuSelected = (short **)NewHandle(sizeof(short) * kMenuSizeBump); if (!aWin->menuSelected) { error("Can't alloc menu select handle"); return; } aWin->miSize = kMenuSizeBump; } if (aWin->miLen >= aWin->miSize) { SetHandleSize((Handle)aWin->menuInfo, sizeof(MacMHMenuItem) * (aWin->miLen+kMenuSizeBump)); if (MemError()) { error("Can't resize menu handle"); return; } SetHandleSize((Handle)aWin->menuSelected, sizeof(short) * (aWin->miLen+kMenuSizeBump)); if (MemError()) { error("Can't resize menu select handle"); return; } aWin->miSize += kMenuSizeBump; } if (menuChar == 0) { if (('a' <= aWin->menuChar && aWin->menuChar <= 'z') || ('A' <= aWin->menuChar && aWin->menuChar <= 'Z')) { menuChar = aWin->menuChar++; if (menuChar == 'z') aWin->menuChar = 'A'; } } Sprintf(locStr, "%c - %s", (menuChar ? menuChar : ' '), inStr); str = locStr; HLock ((char**)aWin->menuInfo); HLock ((char**)aWin->menuSelected); (*aWin->menuSelected)[aWin->miLen] = preselected; item = &(*aWin->menuInfo)[aWin->miLen]; aWin->miLen++; item->id = *any; item->accelerator = menuChar; item->groupAcc = groupAcc; item->line = aWin->y_size; HUnlock ((char**)aWin->menuInfo); HUnlock ((char**)aWin->menuSelected); } else str = inStr; putstr (win, attr, str); } /* * End a menu in this window, window must a type NHW_MENU. * str is a list of cancel characters (values that may be input) * morestr is a prompt to display, rather than the default. * str and morestr might be ignored by some ports. */ void mac_end_menu (winid win, const char *morestr) { Str255 buf; NhWindow *aWin = &theWindows [win]; buf [0] = 0; if (morestr) C2P (morestr, buf); SetWTitle (aWin->its_window, buf); } int mac_select_menu (winid win, int how, menu_item **selected_list) { int c; NhWindow *aWin = &theWindows [win]; WindowPtr theWin = aWin->its_window; inSelect = win; mac_display_nhwindow (win, FALSE); aWin->how = (short) how; for (;;) { c = map_menu_cmd (mac_nhgetch()); if (c == CHAR_ESC) { /* deselect everything */ aWin->miSelLen = 0; break; } else if (ClosingWindowChar(c)) { break; } else { nhbell(); } } HideWindow (theWin); if (aWin->miSelLen) { menu_item *mp; MacMHMenuItem *mi; *selected_list = mp = (menu_item *) alloc(aWin->miSelLen * sizeof(menu_item)); HLock ((char**)aWin->menuInfo); HLock ((char**)aWin->menuSelected); for (c = 0; c < aWin->miSelLen; c++) { mi = &(*aWin->menuInfo)[(*aWin->menuSelected) [c]]; mp->item = mi->id; mp->count = -1L; mp++; } HUnlock ((char**)aWin->menuInfo); HUnlock ((char**)aWin->menuSelected); } else *selected_list = 0; inSelect = WIN_ERR; return aWin->miSelLen; } #include "dlb.h" static void mac_display_file (name, complain) const char *name; /* not ANSI prototype because of boolean parameter */ boolean complain; { Ptr buf; int win; dlb *fp = dlb_fopen(name, "r"); if (fp) { long l = dlb_fseek(fp, 0, SEEK_END); (void) dlb_fseek(fp, 0, 0L); buf = NewPtr(l+1); if (buf) { l = dlb_fread(buf, 1, l, fp); if (l > 0) { buf[l] = '\0'; win = create_nhwindow(NHW_TEXT); if (WIN_ERR == win) { if (complain) error ("Cannot make window."); } else { putstr(win, 0, buf); display_nhwindow(win, FALSE); } } DisposePtr(buf); } dlb_fclose(fp); } else if (complain) error("Cannot open %s.", name); } void port_help () { display_file (PORT_HELP, TRUE); } static void mac_unimplemented (void) { } static void mac_suspend_nhwindows (const char *foo) { #if defined(__SC__) || defined(__MRC__) # pragma unused(foo) #endif /* Can't really do that :-) */ } int try_key_queue (char *bufp) { if (keyQueueCount) { char ch; for (ch = GetFromKeyQueue(); ; ch = GetFromKeyQueue()) { if (ch == CHAR_LF || ch == CHAR_CR) ch = 0; *bufp++ = ch; if (ch == 0) break; } return 1; } return 0; } /* Interface definition, for windows.c */ struct window_procs mac_procs = { "mac", WC_COLOR | WC_HILITE_PET | WC_FONT_MAP | WC_FONT_MENU | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_TEXT | WC_FONTSIZ_MAP | WC_FONTSIZ_MENU | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_TEXT, 0L, mac_init_nhwindows, mac_unimplemented, /* see macmenu.c:mac_askname() for player selection */ mac_askname, mac_get_nh_event, mac_exit_nhwindows, mac_suspend_nhwindows, mac_unimplemented, mac_create_nhwindow, mac_clear_nhwindow, mac_display_nhwindow, mac_destroy_nhwindow, mac_curs, mac_putstr, mac_display_file, mac_start_menu, mac_add_menu, mac_end_menu, mac_select_menu, genl_message_menu, mac_unimplemented, mac_get_nh_event, mac_get_nh_event, #ifdef CLIPPING mac_cliparound, #endif #ifdef POSITIONBAR donull, #endif tty_print_glyph, tty_raw_print, tty_raw_print_bold, mac_nhgetch, mac_nh_poskey, tty_nhbell, mac_doprev_message, mac_yn_function, mac_getlin, mac_get_ext_cmd, mac_number_pad, mac_delay_output, #ifdef CHANGE_COLOR tty_change_color, tty_change_background, set_tty_font_name, tty_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ 0, // mac_start_screen, 0, // mac_end_screen, genl_outrip, genl_preference_update, }; /*macwin.c*/ nethack-3.4.3/sys/mac/mgetline.c0100644000000000000000000000322207764735041015177 0ustar rootroot/* SCCS Id: @(#)getline.c 3.1 90/22/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "mactty.h" #include "macwin.h" #include "macpopup.h" #include "func_tab.h" extern int NDECL(extcmd_via_menu); /* cmd.c */ typedef Boolean FDECL ((* key_func), (unsigned char)); int get_line_from_key_queue (char * bufp) { * bufp = 0; if (try_key_queue (bufp)) { while (* bufp) { if (* bufp == 10 || * bufp == 13) { * bufp = 0; } bufp ++; } return true; } return false; } static void topl_getlin(const char *query, char *bufp, Boolean ext) { if (get_line_from_key_queue (bufp)) return; enter_topl_mode((char *) query); while (topl_key(nhgetch(), ext)) ; leave_topl_mode(bufp); } /* * Read a line closed with '\n' into the array char bufp[BUFSZ]. * (The '\n' is not stored. The string is closed with a '\0'.) * Reading can be interrupted by an escape ('\033') - now the * resulting string is "\033". */ void mac_getlin(const char *query, char *bufp) { topl_getlin (query, bufp, false); } /* Read in an extended command - doing command line completion for * when enough characters have been entered to make a unique command. * This is just a modified getlin() followed by a lookup. -jsb */ int mac_get_ext_cmd() { char bufp[BUFSZ]; int i; if (iflags.extmenu) return extcmd_via_menu(); topl_getlin("# ", bufp, true); for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++) if (!strcmp(bufp, extcmdlist[i].ef_txt)) break; if (extcmdlist[i].ef_txt == (char *)0) i = -1; /* not found */ return i; } /* macgetline.c */ nethack-3.4.3/sys/mac/mmodal.c0100644000000000000000000000132107764735041014642 0ustar rootroot/* SCCS Id: @(#)mmodal.c 3.1 93/01/24 */ /* Copyright (c) Jon W{tte, Hao-Yang Wang, Jonathan Handler 1992. */ /* NetHack may be freely redistributed. See license for details. */ #if !TARGET_API_MAC_CARBON # include # include #else # include #endif #include "macpopup.h" /* Flash a dialog button when its accelerator key is pressed */ void FlashButton(DialogRef wind, short item) { short type; Handle handle; Rect rect; unsigned long ticks; /* Apple recommends 8 ticks */ GetDialogItem(wind, item, &type, &handle, &rect); HiliteControl((ControlHandle)handle, kControlButtonPart); Delay(8, &ticks); HiliteControl((ControlHandle)handle, 0); return; } nethack-3.4.3/sys/mac/mrecover.c0100644000000000000000000007357107764735041015233 0ustar rootroot/* SCCS Id: @(#)mrecover.c 3.4 1996/07/24 */ /* Copyright (c) David Hairston, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* Macintosh Recovery Application */ /* based on code in util/recover.c. the significant differences are: * - GUI vs. CLI. the vast majority of code here supports the GUI. * - Mac toolbox equivalents are used in place of ANSI functions. * - void restore_savefile(void) is event driven. * - integral type substitutions here and there. */ /* * Think C 5.0.4 project specs: * signature: 'nhRc' * SIZE (-1) info: flags: 0x5880, size: 65536L/65536L (64k/64k) * libraries: MacTraps [yes], MacTraps2 (HFileStuff) [yes], ANSI [no] * compatibility: system 6 and system 7 * misc: sizeof(int): 2, "\p": unsigned char, enum size varies, * prototypes required, type checking enforced, no optimizers, * FAR CODE [no], FAR DATA [no], SEPARATE STRS [no], single segment, * short macsbug symbols */ /* * To do (maybe, just maybe): * - Merge with the code in util/recover.c. * - Document launch (e.g. GUI equivalent of 'recover basename'). * - Drag and drop. * - Internal memory tweaks (stack and heap usage). * - Use status file to allow resuming aborted recoveries. * - Bundle 'LEVL' files with recover (easier document launch). * - Prohibit recovering games "in progress". * - Share AppleEvents with NetHack to auto-recover crashed games. */ #include "config.h" /**** Toolbox defines ****/ /* MPW C headers (99.44% pure) */ #include #include #include #include #ifdef applec #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef THINK /* glue for System 7 Icon Family call (needed by Think C 5.0.4) */ pascal OSErr GetIconSuite(Handle *theIconSuite, short theResID, long selector) = {0x303C, 0x0501, 0xABC9}; #endif /**** Application defines ****/ /* Memory */ typedef struct memBytes /* format of 'memB' resource, preloaded/locked */ { short memReserved; short memCleanup; /* 4 - memory monitor activity limit */ long memPreempt; /* 32k - start iff FreeMem() > */ long memWarning; /* 12k - warn if MaxMem() < */ long memAbort; /* 4k - abort if MaxMem() < */ long memIOBuf; /* 16k - read/write buffer size */ } memBytes, *memBytesPtr, **memBytesHandle; #define membID 128 /* 'memB' resource ID */ /* Cursor */ #define CURS_FRAME 4L /* 1/15 second - spin cursor */ #define CURS_LATENT 60L /* pause before spin cursor */ #define curs_Init (-1) /* token for set arrow */ #define curs_Total 8 /* maybe 'acur' would be better */ #define cursorOffset 128 /* GetCursor(cursorOffset + i) */ /* Menu */ enum { mbar_Init = -1, mbarAppl, /* normal mode */ mbarRecover, /* in recovery mode */ mbarDA /* DA in front mode */ }; enum { menuApple, menuFile, menuEdit, menu_Total, muidApple = 128, muidFile, muidEdit }; enum { /* Apple menu */ mitmAbout = 1, mitmHelp, ____128_1, /* File menu */ mitmOpen = 1, ____129_1, mitmClose_DA, ____129_2, mitmQuit /* standard minimum required Edit menu */ }; /* Alerts */ enum { alrtNote, /* general messages */ alrtHelp, /* help message */ alrt_Total, alertAppleMenu = 127, /* menuItem to alert ID offset */ alidNote, alidHelp }; #define aboutBufSize 80 /* i.e. 2 lines of 320 pixels */ /* Notification */ #define nmBufSize (32 + aboutBufSize + 32) typedef struct notifRec { NMRec nmr; struct notifRec * nmNext; short nmDispose; unsigned char nmBuf[nmBufSize]; } notifRec, *notifPtr; #define nmPending nmRefCon /* &in.Notify */ #define iconNotifyID 128 #define ics_1_and_4 0x00000300 /* Dialogs */ enum { dlogProgress = 256 }; enum { uitmThermo = 1 }; enum { initItem, invalItem, drawItem }; /* Miscellaneous */ typedef struct modeFlags { short Front; /* fg/bg event handling */ short Notify; /* level of pending NM notifications */ short Dialog; /* a modeless dialog is open */ short Recover; /* restoration progress index */ } modeFlags; /* convenient define to allow easier (for me) parsing of 'vers' resource */ typedef struct versXRec { NumVersion numVers; short placeCode; unsigned char versStr[]; /* (small string)(large string) */ } versXRec, *versXPtr, **versXHandle; /**** Global variables ****/ modeFlags in = {1}; /* in Front */ EventRecord wnEvt; SysEnvRec sysEnv; unsigned char aboutBuf[aboutBufSize]; /* vers 1 "Get Info" string */ memBytesPtr pBytes; /* memory management */ unsigned short memActivity; /* more memory management */ MenuHandle mHnd[menu_Total]; CursPtr cPtr[curs_Total]; /* busy cursors */ unsigned long timeCursor; /* next cursor frame time */ short oldCursor = curs_Init; /* see adjustGUI() below */ notifPtr pNMQ; /* notification queue pointer */ notifRec nmt; /* notification template */ DialogTHndl thermoTHnd; DialogRecord dlgThermo; /* progress thermometer */ #define DLGTHM ((DialogPtr) &dlgThermo) #define WNDTHM ((WindowPtr) &dlgThermo) #define GRFTHM ((GrafPtr) &dlgThermo) Point sfGetWhere; /* top left corner of get file dialog */ Ptr pIOBuf; /* read/write buffer pointer */ short vRefNum; /* SFGetFile working directory/volume refnum */ long dirID; /* directory i.d. */ NMUPP nmCompletionUPP; /* UPP for nmCompletion */ FileFilterUPP basenameFileFilterUPP; /* UPP for basenameFileFilter */ UserItemUPP drawThermoUPP; /* UPP for progress callback */ #define MAX_RECOVER_COUNT 256 #define APP_NAME_RES_ID (-16396) /* macfile.h */ #define PLAYER_NAME_RES_ID 1001 /* macfile.h */ /* variables from util/recover.c */ #define SAVESIZE FILENAME unsigned char savename[SAVESIZE]; /* originally a C string */ unsigned char lock[256]; /* pascal string */ int hpid; /* NetHack (unix-style) process i.d. */ short saveRefNum; /* save file descriptor */ short gameRefNum; /* level 0 file descriptor */ short levRefNum; /* level n file descriptor */ /**** Prototypes ****/ static void warmup(void); static Handle alignTemplate(ResType, short, short, short, Point *); pascal void nmCompletion(NMRec *); static void noteErrorMessage(unsigned char *, unsigned char *); static void note(short, short, unsigned char *); static void adjustGUI(void); static void adjustMemory(void); static void optionMemStats(void); static void RecoverMenuEvent(long); static void eventLoop(void); static void cooldown(void); pascal void drawThermo(WindowPtr, short); static void itemizeThermo(short); pascal Boolean basenameFileFilter(ParmBlkPtr); static void beginRecover(void); static void continueRecover(void); static void endRecover(void); static short saveRezStrings(void); /* analogous prototypes from util/recover.c */ static void set_levelfile_name(long); static short open_levelfile(long); static short create_savefile(unsigned char *); static void copy_bytes(short, short); static void restore_savefile(void); /* auxiliary prototypes */ static long read_levelfile(short, Ptr, long); static long write_savefile(short, Ptr, long); static void close_file(short *); static void unlink_file(unsigned char *); /**** Routines ****/ main() { /* heap adjust */ MaxApplZone(); MoreMasters(); MoreMasters(); /* manager initialization */ InitGraf(&qd.thePort); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(0L); InitCursor(); nmCompletionUPP = NewNMProc(nmCompletion); basenameFileFilterUPP = NewFileFilterProc(basenameFileFilter); drawThermoUPP = NewUserItemProc(drawThermo); /* get system environment, notification requires 6.0 or better */ (void) SysEnvirons(curSysEnvVers, &sysEnv); if (sysEnv.systemVersion < 0x0600) { ParamText("\pAbort: System 6.0 is required", "\p", "\p", "\p"); (void) Alert(alidNote, (ModalFilterUPP) 0L); ExitToShell(); } warmup(); eventLoop(); /* normally these routines are never reached from here */ cooldown(); ExitToShell(); return 0; } static void warmup() { short i; /* pre-System 7 MultiFinder hack for smooth launch */ for (i = 0; i < 10; i++) { if (WaitNextEvent(osMask, &wnEvt, 2L, (RgnHandle) 0L)) if (((wnEvt.message & osEvtMessageMask) >> 24) == suspendResumeMessage) in.Front = (wnEvt.message & resumeFlag); } #if 0 // ??? /* clear out the Finder info */ { short message, count; CountAppFiles(&message, &count); while(count) ClrAppFiles(count--); } #endif /* fill out the notification template */ nmt.nmr.qType = nmType; nmt.nmr.nmMark = 1; nmt.nmr.nmSound = (Handle) -1L; /* system beep */ nmt.nmr.nmStr = nmt.nmBuf; nmt.nmr.nmResp = nmCompletionUPP; nmt.nmr.nmPending = (long) &in.Notify; #if 1 { /* get the app name */ ProcessInfoRec info; ProcessSerialNumber psn; info.processInfoLength = sizeof(info); info.processName = nmt.nmBuf; info.processAppSpec = NULL; GetCurrentProcess(&psn); GetProcessInformation(&psn, &info); } #else /* prepend app name (31 chars or less) to notification buffer */ { short apRefNum; Handle apParams; GetAppParms(* (Str255 *) &nmt.nmBuf, &apRefNum, &apParams); } #endif /* add formatting (two line returns) */ nmt.nmBuf[++(nmt.nmBuf[0])] = '\r'; nmt.nmBuf[++(nmt.nmBuf[0])] = '\r'; /**** note() is usable now but not aesthetically complete ****/ /* get notification icon */ if (sysEnv.systemVersion < 0x0700) { if (! (nmt.nmr.nmIcon = GetResource('SICN', iconNotifyID))) note(nilHandleErr, 0, "\pNil SICN Handle"); } else { if (GetIconSuite(&nmt.nmr.nmIcon, iconNotifyID, ics_1_and_4)) note(nilHandleErr, 0, "\pBad Icon Family"); } /* load and align various dialog/alert templates */ (void) alignTemplate('ALRT', alidNote, 0, 4, (Point *) 0L); (void) alignTemplate('ALRT', alidHelp, 0, 4, (Point *) 0L); thermoTHnd = (DialogTHndl) alignTemplate('DLOG', dlogProgress, 20, 8, (Point *) 0L); (void) alignTemplate('DLOG', getDlgID, 0, 6, (Point *) &sfGetWhere); /* get the "busy cursors" (preloaded/locked) */ for (i = 0; i < curs_Total; i++) { CursHandle cHnd; if (! (cHnd = GetCursor(i + cursorOffset))) note(nilHandleErr, 0, "\pNil CURS Handle"); cPtr[i] = *cHnd; } /* get the 'vers' 1 long (Get Info) string - About Recover... */ { versXHandle vHnd; if (! (vHnd = (versXHandle) GetResource('vers', 1))) note(nilHandleErr, 0, "\pNil vers Handle"); i = (**vHnd).versStr[0] + 1; /* offset to Get Info pascal string */ if ((aboutBuf[0] = (**vHnd).versStr[i]) > (aboutBufSize - 1)) aboutBuf[0] = aboutBufSize - 1; i++; MoveHHi((Handle) vHnd); /* DEE - Fense ... */ HLock((Handle) vHnd); BlockMove(&((**vHnd).versStr[i]), &(aboutBuf[1]), aboutBuf[0]); ReleaseResource((Handle) vHnd); } /* form the menubar */ for (i = 0; i < menu_Total; i++) { if (! (mHnd[i] = GetMenu(i + muidApple))) note(nilHandleErr, 0, "\pNil MENU Handle"); /* expand the apple menu */ if (i == menuApple) AddResMenu(mHnd[menuApple], 'DRVR'); InsertMenu(mHnd[i], 0); } /* pre-emptive memory check */ { memBytesHandle hBytes; Size grow; if (! (hBytes = (memBytesHandle) GetResource('memB', membID))) note(nilHandleErr, 0, "\pNil Memory Handle"); pBytes = *hBytes; if (MaxMem(&grow) < pBytes->memPreempt) note(memFullErr, 0, "\pMore Memory Required\rTry adding 16k"); memActivity = pBytes->memCleanup; /* force initial cleanup */ } /* get the I/O buffer */ if (! (pIOBuf = NewPtr(pBytes->memIOBuf))) note(memFullErr, 0, "\pNil I/O Pointer"); } /* align a window-related template to the main screen */ static Handle alignTemplate(ResType rezType, short rezID, short vOff, short vDenom, Point *pPt) { Handle rtnHnd; Rect *pRct; vOff += GetMBarHeight(); if (! (rtnHnd = GetResource(rezType, rezID))) note(nilHandleErr, 0, "\pNil Template Handle"); pRct = (Rect *) *rtnHnd; /* don't move memory while aligning rect */ pRct->right -= pRct->left; /* width */ pRct->bottom -= pRct->top; /* height */ pRct->left = (qd.screenBits.bounds.right - pRct->right) / 2; pRct->top = (qd.screenBits.bounds.bottom - pRct->bottom - vOff) / vDenom; pRct->top += vOff; pRct->right += pRct->left; pRct->bottom += pRct->top; if (pPt) *pPt = * (Point *) pRct; /* top left corner */ return rtnHnd; } /* notification completion routine */ pascal void nmCompletion(NMRec * pNMR) { (void) NMRemove(pNMR); (* (short *) (pNMR->nmPending))--; /* decrement pending note level */ ((notifPtr) pNMR)->nmDispose = 1; /* allow DisposPtr() */ } /* * handle errors inside of note(). the error message is appended to the * given message but on a separate line and must fit within nmBufSize. */ static void noteErrorMessage(unsigned char *msg, unsigned char *errMsg) { short i = nmt.nmBuf[0] + 1; /* insertion point */ BlockMove(&msg[1], &nmt.nmBuf[i], msg[0]); nmt.nmBuf[i + msg[0]] = '\r'; nmt.nmBuf[0] += (msg[0] + 1); note(memFullErr, 0, errMsg); } /* * display messages using Notification Manager or an alert. * no run-length checking is done. the messages are created to fit * in the allocated space (nmBufSize and aboutBufSize). */ static void note(short errorSignal, short alertID, unsigned char *msg) { if (! errorSignal) { Size grow; if (MaxMem(&grow) < pBytes->memAbort) noteErrorMessage(msg, "\pOut of Memory"); } if (errorSignal || !in.Front) { notifPtr pNMR; short i = nmt.nmBuf[0] + 1; /* insertion point */ if (errorSignal) /* use notification template */ { pNMR = &nmt; /* we're going to abort so add in this prefix */ BlockMove("Abort: ", &nmt.nmBuf[i], 7); i += 7; nmt.nmBuf[0] += 7; } else /* allocate a notification record */ { if (! (pNMR = (notifPtr) NewPtr(sizeof(notifRec)))) noteErrorMessage(msg, "\pNil New Pointer"); /* initialize it */ *pNMR = nmt; pNMR->nmr.nmStr = (StringPtr) &(pNMR->nmBuf); /* update the notification queue */ if (!pNMQ) pNMQ = pNMR; else { notifPtr pNMX; /* find the end of the queue */ for (pNMX = pNMQ; pNMX->nmNext; pNMX = pNMX->nmNext) ; pNMX->nmNext = pNMR; } } /* concatenate the message */ BlockMove(&msg[1], &((pNMR->nmBuf)[i]), msg[0]); (pNMR->nmBuf)[0] += msg[0]; in.Notify++; /* increase note pending level */ NMInstall((NMRec *) pNMR); if (errorSignal) cooldown(); return; } /* in front and no error so use an alert */ ParamText(msg, "\p", "\p", "\p"); (void) Alert(alertID, (ModalFilterUPP) 0L); ResetAlrtStage(); memActivity++; } static void adjustGUI() { static short oldMenubar = mbar_Init; /* force initial update */ short newMenubar; WindowPeek frontWindow; /* oldCursor is external so it can be reset in endRecover() */ static short newCursor = curs_Init; unsigned long timeNow; short useArrow; /* adjust menubar 1st */ newMenubar = in.Recover ? mbarRecover : mbarAppl; /* desk accessories take precedence */ if (frontWindow = (WindowPeek) FrontWindow()) if (frontWindow->windowKind < 0) newMenubar = mbarDA; if (newMenubar != oldMenubar) { /* adjust menus */ switch (oldMenubar = newMenubar) { case mbarAppl: EnableItem(mHnd[menuFile], mitmOpen); SetItemMark(mHnd[menuFile], mitmOpen, noMark); DisableItem(mHnd[menuFile], mitmClose_DA); DisableItem(mHnd[menuEdit], 0); break; case mbarRecover: DisableItem(mHnd[menuFile], mitmOpen); SetItemMark(mHnd[menuFile], mitmOpen, checkMark); DisableItem(mHnd[menuFile], mitmClose_DA); DisableItem(mHnd[menuEdit], 0); break; case mbarDA: DisableItem(mHnd[menuFile], mitmOpen); EnableItem(mHnd[menuFile], mitmClose_DA); EnableItem(mHnd[menuEdit], 0); break; } DrawMenuBar(); } /* now adjust the cursor */ if (useArrow = (!in.Recover || (newMenubar == mbarDA))) newCursor = curs_Init; else if ((timeNow = TickCount()) >= timeCursor) /* spin cursor */ { timeCursor = timeNow + CURS_FRAME; if (++newCursor >= curs_Total) newCursor = 0; } if (newCursor != oldCursor) { oldCursor = newCursor; SetCursor(useArrow ? &qd.arrow : cPtr[newCursor]); } } static void adjustMemory() { Size grow; memActivity = 0; if (MaxMem(&grow) < pBytes->memWarning) note(noErr, alidNote, "\pWarning: Memory is running low"); (void) ResrvMem((Size) FreeMem()); /* move all handles high */ } /* show memory stats: FreeMem, MaxBlock, PurgeSpace, and StackSpace */ static void optionMemStats() { unsigned char *pFormat = "\pFree:#k Max:#k Purge:#k Stack:#k"; char *pSub = "#"; /* not a pascal string */ unsigned char nBuf[16]; long nStat, contig; Handle strHnd; long nOffset; short i; if (wnEvt.modifiers & shiftKey) adjustMemory(); if (! (strHnd = NewHandle((Size) 128))) { note(noErr, alidNote, "\pOops: Memory stats unavailable!"); return; } SetString((StringHandle) strHnd, pFormat); nOffset = 1L; for (i = 1; i <= 4; i++) { /* get the replacement number stat */ switch (i) { case 1: nStat = FreeMem(); break; case 2: nStat = MaxBlock(); break; case 3: PurgeSpace(&nStat, &contig); break; case 4: nStat = StackSpace(); break; } NumToString((nStat >> 10), * (Str255 *) &nBuf); **strHnd += nBuf[0] - 1; nOffset = Munger(strHnd, nOffset, (Ptr) pSub, 1L, (Ptr) &nBuf[1], nBuf[0]); } MoveHHi(strHnd); HLock(strHnd); note(noErr, alidNote, (unsigned char *) *strHnd); DisposHandle(strHnd); } static void RecoverMenuEvent(long menuEntry) { short menuID = HiWord(menuEntry); short menuItem = LoWord(menuEntry); switch (menuID) { case muidApple: switch (menuItem) { case mitmAbout: if (wnEvt.modifiers & optionKey) optionMemStats(); /* fall thru */ case mitmHelp: note(noErr, (alertAppleMenu + menuItem), aboutBuf); break; default: /* DA's or apple menu items */ { unsigned char daName[32]; GetItem(mHnd[menuApple], menuItem, * (Str255 *) &daName); (void) OpenDeskAcc(daName); memActivity++; } break; } break; case muidFile: switch (menuItem) { case mitmOpen: beginRecover(); break; case mitmClose_DA: { WindowPeek frontWindow; short refNum; if (frontWindow = (WindowPeek) FrontWindow()) if ((refNum = frontWindow->windowKind) < 0) CloseDeskAcc(refNum); memActivity++; } break; case mitmQuit: cooldown(); break; } break; case muidEdit: (void) SystemEdit(menuItem - 1); break; } HiliteMenu(0); } static void eventLoop() { short wneMask = (in.Front ? everyEvent : (osMask + updateMask)); long wneSleep = (in.Front ? 0L : 3L); while (1) { if (in.Front) adjustGUI(); if (memActivity >= pBytes->memCleanup) adjustMemory(); (void) WaitNextEvent(wneMask, &wnEvt, wneSleep, (RgnHandle) 0L); if (in.Dialog) (void) IsDialogEvent(&wnEvt); switch (wnEvt.what) { case osEvt: if (((wnEvt.message & osEvtMessageMask) >> 24) == suspendResumeMessage) { in.Front = (wnEvt.message & resumeFlag); wneMask = (in.Front ? everyEvent : (osMask + updateMask)); wneSleep = (in.Front ? 0L : 3L); } break; case nullEvent: /* adjust the FIFO notification queue */ if (pNMQ && pNMQ->nmDispose) { notifPtr pNMX = pNMQ->nmNext; DisposPtr((Ptr) pNMQ); pNMQ = pNMX; memActivity++; } if (in.Recover) continueRecover(); break; case mouseDown: { WindowPtr whichWindow; switch(FindWindow( wnEvt . where , &whichWindow)) { case inMenuBar: RecoverMenuEvent(MenuSelect( wnEvt . where )); break; case inSysWindow: SystemClick(&wnEvt, whichWindow); break; case inDrag: { Rect boundsRect = qd.screenBits.bounds; Point offsetPt; InsetRect(&boundsRect, 4, 4); boundsRect.top += GetMBarHeight(); DragWindow(whichWindow, * ((Point *) &wnEvt.where), &boundsRect); boundsRect = whichWindow->portRect; offsetPt = * (Point *) &(whichWindow->portBits.bounds); OffsetRect(&boundsRect, -offsetPt.h, -offsetPt.v); * (Rect *) *thermoTHnd = boundsRect; } break; } } break; case keyDown: { char key = (wnEvt.message & charCodeMask); if (wnEvt.modifiers & cmdKey) { if (key == '.') { if (in.Recover) { endRecover(); note(noErr, alidNote, "\pSorry: Recovery aborted"); } } else RecoverMenuEvent(MenuKey(key)); } } break; /* without windows these events belong to our thermometer */ case updateEvt: case activateEvt: { DialogPtr dPtr; short itemHit; (void) DialogSelect(&wnEvt, &dPtr, &itemHit); } case diskEvt: if (HiWord(wnEvt.message)) { Point pt = {60, 60}; (void) DIBadMount(pt, wnEvt.message); DIUnload(); memActivity++; } break; } /* switch (wnEvt.what) */ } /* while (1) */ } static void cooldown() { if (in.Recover) endRecover(); /* wait for pending notifications to complete */ while (in.Notify) (void) WaitNextEvent(0, &wnEvt, 3L, (RgnHandle) 0L); ExitToShell(); } /* draw the progress thermometer and frame. 1 level <=> 1 horiz. pixel */ pascal void drawThermo(WindowPtr wPtr, short inum) { itemizeThermo(drawItem); } /* manage progress thermometer dialog */ static void itemizeThermo(short itemMode) { short iTyp, iTmp; Handle iHnd; Rect iRct; GetDItem(DLGTHM, uitmThermo, &iTyp, &iHnd, &iRct); switch(itemMode) { case initItem: SetDItem(DLGTHM, uitmThermo, iTyp, (Handle) drawThermoUPP, &iRct); break; case invalItem: { GrafPtr oldPort; GetPort(&oldPort); SetPort(GRFTHM); InsetRect(&iRct, 1, 1); InvalRect(&iRct); SetPort(oldPort); } break; case drawItem: FrameRect(&iRct); InsetRect(&iRct, 1, 1); iTmp = iRct.right; iRct.right = iRct.left + in.Recover; PaintRect(&iRct); iRct.left = iRct.right; iRct.right = iTmp; EraseRect(&iRct); break; } } /* show only .0 files in get file dialog */ pascal Boolean basenameFileFilter(ParmBlkPtr pPB) { unsigned char *pC; if (! (pC = (unsigned char *) pPB->fileParam.ioNamePtr)) return true; if ((*pC < 4) || (*pC > 28)) /* save/ 1name .0 */ return true; if ((pC[*pC - 1] == '.') && (pC[*pC] == '0')) /* bingo! */ return false; return true; } static void beginRecover() { SFTypeList levlType = {'LEVL'}; SFReply sfGetReply; SFGetFile(sfGetWhere, "\p", basenameFileFilterUPP, 1, levlType, (DlgHookUPP) 0L, &sfGetReply); memActivity++; if (! sfGetReply.good) return; /* get volume (working directory) refnum, basename, and directory i.d. */ vRefNum = sfGetReply.vRefNum; BlockMove(sfGetReply.fName, lock, sfGetReply.fName[0] + 1); { static CInfoPBRec catInfo; catInfo.hFileInfo.ioNamePtr = (StringPtr) sfGetReply.fName; catInfo.hFileInfo.ioVRefNum = sfGetReply.vRefNum; catInfo.hFileInfo.ioDirID = 0L; if (PBGetCatInfoSync(&catInfo)) { note(noErr, alidNote, "\pSorry: Bad File Info"); return; } dirID = catInfo.hFileInfo.ioFlParID; } /* open the progress thermometer dialog */ (void) GetNewDialog(dlogProgress, (Ptr) &dlgThermo, (WindowPtr) -1L); if (ResError() || MemError()) note(noErr, alidNote, "\pOops: Progress thermometer unavailable"); else { in.Dialog = 1; memActivity++; itemizeThermo(initItem); ShowWindow(WNDTHM); } timeCursor = TickCount() + CURS_LATENT; saveRefNum = gameRefNum = levRefNum = -1; in.Recover = 1; } static void continueRecover() { restore_savefile(); /* update the thermometer */ if (in.Dialog && ! (in.Recover % 4)) itemizeThermo(invalItem); if (in.Recover <= MAX_RECOVER_COUNT) return; endRecover(); if (saveRezStrings()) return; note(noErr, alidNote, "\pOK: Recovery succeeded"); } /* no messages from here (since we might be quitting) */ static void endRecover() { in.Recover = 0; oldCursor = curs_Init; SetCursor(&qd.arrow); /* clean up abandoned files */ if (gameRefNum >= 0) (void) FSClose(gameRefNum); if (levRefNum >= 0) (void) FSClose(levRefNum); if (saveRefNum >= 0) { (void) FSClose(saveRefNum); (void) FlushVol((StringPtr) 0L, vRefNum); /* its corrupted so trash it ... */ (void) HDelete(vRefNum, dirID, savename); } saveRefNum = gameRefNum = levRefNum = -1; /* close the progress thermometer dialog */ in.Dialog = 0; CloseDialog(DLGTHM); DisposHandle(dlgThermo.items); memActivity++; } /* add friendly, non-essential resource strings to save file */ static short saveRezStrings() { short sRefNum; StringHandle strHnd; short i, rezID; unsigned char *plName; HCreateResFile(vRefNum, dirID, savename); sRefNum = HOpenResFile(vRefNum, dirID, savename, fsRdWrPerm); if (sRefNum <= 0) { note(noErr, alidNote, "\pOK: Minor resource map error"); return 1; } /* savename and hpid get mutilated here... */ plName = savename + 5; /* save/ */ *savename -= 5; do { plName++; (*savename)--; hpid /= 10; } while (hpid); *plName = *savename; for (i = 1; i <= 2; i++) { switch (i) { case 1: rezID = PLAYER_NAME_RES_ID; strHnd = NewString(* (Str255 *) plName); break; case 2: rezID = APP_NAME_RES_ID; strHnd = NewString(* (Str255 *) "\pNetHack"); break; } if (! strHnd) { note(noErr, alidNote, "\pOK: Minor \'STR \' resource error"); CloseResFile(sRefNum); return 1; } /* should check for errors... */ AddResource((Handle) strHnd, 'STR ', rezID, * (Str255 *) "\p"); } memActivity++; /* should check for errors... */ CloseResFile(sRefNum); return 0; } static void set_levelfile_name(long lev) { unsigned char *tf; /* find the dot. this is guaranteed to happen. */ for (tf = (lock + *lock); *tf != '.'; tf--, lock[0]--) ; /* append the level number string (pascal) */ if (tf > lock) { NumToString(lev, * (Str255 *) tf); lock[0] += *tf; *tf = '.'; } else /* huh??? */ { endRecover(); note(noErr, alidNote, "\pSorry: File Name Error"); } } static short open_levelfile(long lev) { OSErr openErr; short fRefNum; set_levelfile_name(lev); if (! in.Recover) return (-1); if ((openErr = HOpen(vRefNum, dirID, lock, fsRdWrPerm, &fRefNum)) && (openErr != fnfErr)) { endRecover(); note(noErr, alidNote, "\pSorry: File Open Error"); return (-1); } return (openErr ? -1 : fRefNum); } static short create_savefile(unsigned char *savename) { short fRefNum; /* translate savename to a pascal string (in place) */ { unsigned char *pC; short nameLen; for (pC = savename; *pC; pC++); nameLen = pC - savename; for ( ; pC > savename; pC--) *pC = *(pC - 1); *savename = nameLen; } if (HCreate(vRefNum, dirID, savename, MAC_CREATOR, SAVE_TYPE) || HOpen(vRefNum, dirID, savename, fsRdWrPerm, &fRefNum)) { endRecover(); note(noErr, alidNote, "\pSorry: File Create Error"); return (-1); } return fRefNum; } static void copy_bytes(short inRefNum, short outRefNum) { char *buf = (char *) pIOBuf; long bufSiz = pBytes->memIOBuf; long nfrom, nto; do { nfrom = read_levelfile(inRefNum, buf, bufSiz); if (! in.Recover) return; nto = write_savefile(outRefNum, buf, nfrom); if (! in.Recover) return; if (nto != nfrom) { endRecover(); note(noErr, alidNote, "\pSorry: File Copy Error"); return; } } while (nfrom == bufSiz); } static void restore_savefile() { static int savelev; long saveTemp, lev; xchar levc; struct version_info version_data; /* level 0 file contains: * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created * and game state */ lev = in.Recover - 1; if (lev == 0L) { gameRefNum = open_levelfile(0L); if (in.Recover) (void) read_levelfile(gameRefNum, (Ptr) &hpid, sizeof(hpid)); if (in.Recover) saveTemp = read_levelfile(gameRefNum, (Ptr) &savelev, sizeof(savelev)); if (in.Recover && (saveTemp != sizeof(savelev))) { endRecover(); note(noErr, alidNote, "\pSorry: \"checkpoint\" was not enabled"); return; } if (in.Recover) (void) read_levelfile(gameRefNum, (Ptr) savename, sizeof(savename)); if (in.Recover) (void) read_levelfile(gameRefNum, (Ptr) &version_data, sizeof version_data); /* save file should contain: * current level (including pets) * (non-level-based) game state * other levels */ if (in.Recover) saveRefNum = create_savefile(savename); if (in.Recover) levRefNum = open_levelfile(savelev); if (in.Recover) (void) write_savefile(saveRefNum, (Ptr) &version_data, sizeof version_data); if (in.Recover) copy_bytes(levRefNum, saveRefNum); if (in.Recover) close_file(&levRefNum); if (in.Recover) unlink_file(lock); if (in.Recover) copy_bytes(gameRefNum, saveRefNum); if (in.Recover) close_file(&gameRefNum); if (in.Recover) set_levelfile_name(0L); if (in.Recover) unlink_file(lock); } else if (lev != savelev) { levRefNum = open_levelfile(lev); if (levRefNum >= 0) { /* any or all of these may not exist */ levc = (xchar) lev; (void) write_savefile(saveRefNum, (Ptr) &levc, sizeof(levc)); if (in.Recover) copy_bytes(levRefNum, saveRefNum); if (in.Recover) close_file(&levRefNum); if (in.Recover) unlink_file(lock); } } if (in.Recover == MAX_RECOVER_COUNT) close_file(&saveRefNum); if (in.Recover) in.Recover++; } static long read_levelfile(short rdRefNum, Ptr bufPtr, long count) { OSErr rdErr; long rdCount = count; if ((rdErr = FSRead(rdRefNum, &rdCount, bufPtr)) && (rdErr != eofErr)) { endRecover(); note(noErr, alidNote, "\pSorry: File Read Error"); return (-1L); } return rdCount; } static long write_savefile(short wrRefNum, Ptr bufPtr, long count) { long wrCount = count; if (FSWrite(wrRefNum, &wrCount, bufPtr)) { endRecover(); note(noErr, alidNote, "\pSorry: File Write Error"); return (-1L); } return wrCount; } static void close_file(short *pFRefNum) { if (FSClose(*pFRefNum) || FlushVol((StringPtr) 0L, vRefNum)) { endRecover(); note(noErr, alidNote, "\pSorry: File Close Error"); return; } *pFRefNum = -1; } static void unlink_file(unsigned char *filename) { if (HDelete(vRefNum, dirID, filename)) { endRecover(); note(noErr, alidNote, "\pSorry: File Delete Error"); return; } } nethack-3.4.3/sys/mac/mrecover.hqx0100644000000000000000000001045307764735041015577 0ustar rootroot(This file must be converted with BinHex 4.0) :$@ebC@0[GQ9b,R*cFQ-!FR0bBe*6483!!!!!!!!!!!aI55J!!!!!!3!!!!TJ!!! *B!!!!Im!!'1M#Q&$E'YTEQPd,Q1!!J!!!&4&@&4,38K-!3!!-"*YFQ9MEhCPFLj `FQpU,R*cFQ0b!J!!!(*cFQ058d9%!!"bFh*M8P0&4!%!!0!!J!!!!!!!!!!!!!! !!!!!!!!!!+lTZ(B!!!!!!!!-F`!!!!!!!!!!%!!!!'1M#Q&$E'YXEfp`,Q1!!J! !!&4&@&4,38K-!3!!B!"X!!!!!'1V!!!!!&Le!!"F!!!!!!!!!!!!!!#Mk`QeT3H i4`!!!!"hD3!!!!!!!!!!!!!!!!!!!!!p93!A!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!L!!%!!!!!!$J!EJ"-!1B%!Np,!!!!!!!+!!S!+J&+L!*H-!!!!!` !+!!S!))"I!#!!!3!!!!-!#J!+!$#!A`!J3!%!!!!5!##!!!!!!!!!!$rrrrl"%9 NDA3%9@jNE`"D!!!",3!!!!!$3h9d!&J!!!4$Eh"j!%-!!!93BA0dC3"@!!!&3fa PBA)!!!!!!!!!!$J!J!!!!!!!!!!!rrrrp`%8%%&LEh9d)&*PBfpfCA)Z,Li!!!! !"dKPE(!Z,Li!!!!!!5d!!!!!!!!!!%3!!!2!!X!$`!'!!m!--!J3%#J35"H)%!J )%!``!m!!!!2!"q!(i!IJ!m!2m"ri(rJrr$rm2r`rr"ri(rJ2m!2!!!N!"`!!!%! 'J!l!CZ!hB"r!6mcq%[mUkG6XL#N3-V!&@!5-!`3!!"r!Ir"rq2rmrrlrr[rrrrr rrrrrIrprrcrr(ri2rJ2i!!!!('jS8Q-!!!!"4P*&4J!!!!!!J%P$6L-!!!!!!)! !!!!(39"36!!!!!!!!"364'&fD@3J5'&TFR0dEfiJ-bmj-`!!!3!!!!!!!"m!!!" r`!!JIm!!1$q`!"3rF!!512J!#6Gi!!6rH!!#IlJ!!6ri!''Iq!$rc$$Jrq3"-1l b!T!!kIN&82IPLU$[ip9!6Z%LJ!(Jb3!2m))!$r%N!!I#LJ!!"9N!!!UNJ!!93N! !%S&J!"N!d!!1!&!!!!!`!!!!!!!!!!!2r`!!2rr!!(rrm!"rrrJ!rrrm!2rrrJ$ rrrm!rrrrJ2rrrm$rrrrJrrrrm2rrrrMrrrrmrrrrr2rrrrlrrrrqrrrrrhrrrrp rrrrr2rrrrcrrrrmIrrrr$rrrr`Irrrm$rrrr!Irrr`$rrrm!Irrr!$rrrJ!Irri !"rrm!!(rm!!!!J!!!!!!!!!!!!!!!!!!!!!!!!!!!!$rrrm!!!!!!!!!!!!!!!! 2%4%4r`!!!!!!!!!!m!!!$a%4%4m!!!!!!!!!!2r`!!$a%4%Ir`!!!!!!!!!2h`! !m4%4m4m!!!!!!!!!$ph`!2%Ira%4m!!!!!!!!!$ph`$am4(a%I!!!!!!!!!!$ph r%4%4m4(`!!!!!!!!!!$pha%4%4m4m!!!!!!!!!!!$pha%4%4%I!!!!!!!!r`!!r pha(rra(`!!!!!!$a(rra(phr!!$r!!$rm!!!m4%4%4(ph`!!!!!242m!!2%I%4m 4(ph`!!!!p242!!$a(ara%Irph`!!$dp26`!!m4(a%4(`$p$`!26dp2!!!2%I%4% 4m!$`$`p26dm!!!!2ra%I%I!!$phd426`!!!!!!rrm4(`!!$r4242!!!!!!!2%4% 4(`!!p%4%m!!!!!!!$r%4%4m!$d6d6`!!!!!!!!!2rrr`!26d42h`!!!!!!!!!!! !!!p26drph`!!!!!!!!!!!!$dp26`$ph`!!!!!!!!!!!26dp2!!$ph`!!!!!!!!! !$d6dm!!!$p$`!!!!!!!!!!rd6`!!!!$`h`!!!!!!!!!!rr!!!!!!$pm!!!!!!!! !!!!!!!!!!!$r!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!)! !!!rrm!!!!!!!m4mI!!!!$G!2(a(`!!!!h3m4mI!!!!!0ha%I!!!!$`$Grrm!r`$ arrh3!!p%m2%4(pd!p26`m4mI$Gp26`$rram!p%6`!!!!m!p%6`!!!!!!p26p!!! !!!p26`h3!!!!$d6`!0d!!!!!r`!!$3!!!!!!!!!!!!!!!#!'J!l!CZ!hB"r!6mc q%[mUkG6XL#N3-V!&@!5-!`3!!!!!!2B!!3!!!!!!H!"Z!)`!jJ3#6dX!!!!!!!S !#J"U!8U)e6%T)&0PE'9MG#!L6h"PELiZ,L)JCR*[E5"dD'8J4QPXC5"YC@je,Jd b+5"6C@aPBh3JG'KP)'GKE@8JG'mJFQ9MEhCPFL"QFQpY)(4SC5"ND@&XEfFZ$6- T)&GKDA3JCQpb)(4SC5"bCA0eE(3J+%p,)'pb)&0[FR*j+5i0$84[)'j[G#"KG(4 PEA"d)(4[)(*PBfpfCA)JB5"RB@eP)(4SBA3JDA-J)QPZ)("bEfGbCA0c)L!SD5j P,L"cG'PXE#"bG@jZD@jR)'PZ)%jPG%KKBfXT)3!!!!"#!)%!!!!!!!!!!2rrrqX %4QPXC3G2F'9Z,LiZ!%m!!!%Y!!!!!!K$E'pcC5"%33"A!!!",3!!!!!%8A9TG!" 4!!!!!!!!&!!!!!3!!)!!!!!`!!!!%!!!!%!!!!!!3J43FQPf4PG54!G$E'9KER9 `4&G54!G3FQ9PEA"d4%a14`GABA*ZD@jR4%a14`9"BQpbG%4-6NF'58mJ3R9Q4%a 14`!!!%3!!!2!!d!$`!'!!B!#3!4J"#!%B!@J"#!%B!*!!B!!!!2!"q!(i!IJ!m! $`!IJ$r!2m!r`$r!2m!r`"q!$`!'!!!N!"`!!!%3!!!2!!X!$`!'!!B!#3!2!!N! (`!C!!m!#3!2!!B!!!!2!"q!(i!IJ!m!$`!IJ"q!(i!rJ$q!(i!IJ"q!$`!'!!!N !"`!!!"d!+!!S!%!"3!!%!!!!!!!!!!!"!!K3FQpRFQ9cF`!!!"!!!!!!!!!!"`! ,!"%"$B!!!!!!4!!!!m!$3!2!!B!"J!*!"Q!%)!CJ"D!')!4J!d!"J!!!!m!(i!I J"q!$`!2!"q!2m!r`$r!2m!r`$r!(i!2!!B!!#3!(!!!!4!!!!m!$3!2!!B!"J!0 !"L!&B!8J"@!&)!9J!N!"J!!!!m!(i!IJ"q!$`!2!"q!2m!r`$r!2m!r`$r!(i!2 !!B!!#3!(!!!!4!!!!m!#`!2!!B!"J!*!!m!#3!2J!Q!$`!*!!m!"J!!!!m!(i!I J"q!$`!2!"q!(i!IJ"r!(m!IJ"q!(i!2!!B!!#3!(!!!!4!!!!m!#`!2!!B!$J!q 3!!`3'CJCQ"QB'CJ*N!!-%!2!!!!$`!IJ"q!(i!2!$r!Iq"ri2r`rr$rm2r`Iq"r i$r!$`!!*!!F!!!"%!!!$`!0!!m!"J!'!!m!&)!DJ"+!'S!5J"U!$3!'!!!!$`!I J"q!(i!2!!m!(i!r`$r!2m!r`$r!2m!IJ!m!"J!!*!!F!!!!U!c#!!!!!!c-Z-ap 5C@0[GQ9b)$-Z-`eNCACdC@&Y3'jPG'KKBfXZEh*R!!!!&J-`J!!!!!-c,M-,8Q9 MEhCPFL!c,M-!!!%!!!!+B!!!#@!!!!(r"-)(q#qq!!!!(!(k!!p"6&*8!!%!JN4 *9%`!!J#D689193!#!,j$99*6!!F!iNP$6L-!!!&#D@0c)`!!!8j#6N4-!!!"@Qj S8Q-!!!&Q4P*&4J!!!A*fCA*c!!%"IQPME$3!!!'@D@0c0!!!!D*65801!!!"VQe PE8)!!!'k9%e36!!!!FC%6%p(!!!"dJ#!rrm!!!!Q!!!!!!#"rrm!!!!f!!!!!!# !rrmJ!!!!!!!!!!#"rrmJ!!90!!!!!!%!rrmJ!!HF!!!!!!##rrm!!!"'!!!!!!# !rrm!!!#5!!!!!!#"rrm!!!C(!!!!!!#!rrm8!!$1!!!!!!#"rrm8!!EV!!!!!!# #rrm8!!Fc!!!!!!#(rrm8!!H`!!!!!!#&rrm8!!Ii!!!!!!#'rrm8!!K!!!!!!!# %rrm8!!L)!!!!!!#$rrm8!!M3!!!!!!#!rrm!!!'G!!!!!!#!rrm!!!%@!!!!!!# !rrm!!!&D!!!!!!!!rrm!!!'&!!!!!!#!rrm!!!&k!!!!!!!"rrm!!!NB!!!!!!! #rrm!!!P'!!!!!!#!rrm!!!+K!!!!!!#!rrm!!!5P!!!!!!#!rrm!!!8T!!!!!!# !rrm8!!D0!!!!!!#!!!!!!!DP!!!!!!%!rrm!!!Gl!!!!!!4YC@e#8i3: nethack-3.4.3/sys/mac/mttymain.c0100644000000000000000000002720107764735041015240 0ustar rootroot/* SCCS Id: @(#)mttymain.c 3.1 93/02/26 */ /* Copyright (c) Jon W{tte, 1993 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "macwin.h" #include "mttypriv.h" #include "mactty.h" #include "wintty.h" #if !TARGET_API_MAC_CARBON #include #endif #define MT_WINDOW 135 #define MT_WIDTH 80 #define MT_HEIGHT 24 /* * Names: * * Statics are prefixed _ * Mac-tty becomes mt_ */ static long _mt_attrs [5] [2] = { { 0x000000, 0xffffff }, /* Normal */ { 0xff8080, 0xffffff }, /* Underline */ { 0x40c020, 0xe0e0e0 }, /* Bold */ { 0x003030, 0xff0060 }, /* Blink */ { 0xff8888, 0x000000 }, /* Inverse */ }; static char _attrs_inverse [5] = { 0, 0, 0, 0, 0 , }; /* see color.h */ static long _mt_colors [CLR_MAX] [2] = { { 0x000000, 0x808080 }, /* Black */ { 0x880000, 0xffffff }, /* Red */ { 0x008800, 0xffffff }, /* Green */ { 0x553300, 0xffffff }, /* Brown */ { 0x000088, 0xffffff }, /* Blue */ { 0x880088, 0xffffff }, /* Magenta */ { 0x008888, 0xffffff }, /* Cyan */ { 0x888888, 0xffffff }, /* Gray */ { 0x000000, 0xffffff }, /* No Color */ { 0xff4400, 0xffffff }, /* Orange */ { 0x00ff00, 0xffffff }, /* Bright Green */ { 0xffff00, 0x606060 }, /* Yellow */ { 0x0033ff, 0xffffff }, /* Bright Blue */ { 0xff00ff, 0xffffff }, /* Bright Magenta */ { 0x00ffff, 0xffffff }, /* Bright Cyan */ { 0xffffff, 0x505050 }, /* White */ }; static char _colors_inverse [CLR_MAX] = { 1, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , 0, 0, 0, 0 , }; #ifdef CHANGE_COLOR #define POWER_LIMIT 22 #define SECONDARY_POWER_LIMIT 16 #define CHANNEL_LIMIT 14 #define SECONDARY_CHANNEL_LIMIT 12 void tty_change_color (int color, long rgb, int reverse) { long inverse, working_rgb = rgb; int total_power = 0, max_channel = 0; int cnt = 3; working_rgb >>= 4; while (cnt -- > 0) { total_power += working_rgb & 0xf; max_channel = max (max_channel, working_rgb & 0xf); working_rgb >>= 8; } if (total_power >= POWER_LIMIT || (total_power >= SECONDARY_POWER_LIMIT && max_channel >= SECONDARY_CHANNEL_LIMIT) || max_channel >= CHANNEL_LIMIT) inverse = 0x000000; else inverse = 0xffffff; if (reverse) { working_rgb = rgb; rgb = inverse; inverse = working_rgb; } if (color >= CLR_MAX) { if (color - CLR_MAX >= 5) impossible ("Changing too many colors"); else { _mt_attrs [color - CLR_MAX] [0] = rgb; _mt_attrs [color - CLR_MAX] [1] = inverse; _attrs_inverse [color - CLR_MAX] = reverse; } } else if (color >= 0) { _mt_colors [color] [0] = rgb; _mt_colors [color] [1] = inverse; _colors_inverse [color] = reverse; } else impossible ("Changing negative color"); } void tty_change_background (int white_or_black) { register int i; for (i = 0; i < CLR_MAX; i++) { if (white_or_black) _mt_colors [i] [1] = 0xffffff; /* white */ else _mt_colors [i] [1] = 0x000000; /* black */ } /* special cases */ if (white_or_black) { _mt_colors [CLR_BLACK] [1] = 0x808080; /* differentiate black from no color */ _mt_colors [CLR_WHITE] [1] = 0x505050; /* highlight white with grey background */ _mt_colors [CLR_YELLOW] [1] = 0x606060; /* highlight yellow with grey background */ _mt_colors [CLR_BLUE] [0] = 0x000088; /* make pure blue */ _mt_colors [NO_COLOR] [0] = 0x000000; /* make no_color black on white */ _mt_attrs [0] [0] = 0x000000; /* "normal" is black on white */ _mt_attrs [0] [1] = 0xffffff; } else { _mt_colors [NO_COLOR] [0] = 0xffffff; /* make no_color white on black */ _mt_colors [CLR_BLACK] [1] = 0x808080; /* differentiate black from no color */ _mt_colors [CLR_BLUE] [0] = 0x222288; /* lighten blue - it's too dark on black */ _mt_attrs [0] [0] = 0xffffff; /* "normal" is white on black */ _mt_attrs [0] [1] = 0x000000; } } char * tty_get_color_string (void) { char *ptr; int count; static char color_buf [5 * (CLR_MAX + 5) + 1]; color_buf [0] = 0; ptr = color_buf; for (count = 0; count < CLR_MAX; count ++) { int flag = _colors_inverse [count] ? 1 : 0; sprintf (ptr, "%s%s%x%x%x", count ? "/" : "" , flag ? "-" : "" , (int)(_mt_colors [count] [flag] >> 20) & 0xf , (int)(_mt_colors [count] [flag] >> 12) & 0xf , (int)(_mt_colors [count] [flag] >> 4) & 0xf); ptr += strlen (ptr); } for (count = 0; count < 5; count ++) { int flag = _attrs_inverse [count] ? 1 : 0; sprintf (ptr, "/%s%x%x%x" , flag ? "-" : "" , (int)(_mt_attrs [count] [flag] >> 20) & 0xf , (int)(_mt_attrs [count] [flag] >> 12) & 0xf , (int)(_mt_attrs [count] [flag] >> 4) & 0xf); ptr += strlen (ptr); } return color_buf; } #endif extern struct DisplayDesc *ttyDisplay; /* the tty display descriptor */ char kill_char = CHAR_ESC; char erase_char = CHAR_BS; WindowRef _mt_window = (WindowRef) 0; static Boolean _mt_in_color = 0; extern short win_fonts [NHW_TEXT + 1]; static void _mt_init_stuff (void) { long resp, flag; short num_cols, num_rows, win_width, win_height, font_num, font_size; short char_width, row_height; short hor, vert; LI = MT_HEIGHT; CO = MT_WIDTH; if (!strcmp(windowprocs.name, "mac")) { dprintf ("Mac Windows"); LI -= 1; } else { dprintf ("TTY Windows"); } /* * If there is at least one screen CAPABLE of color, and if * 32-bit QD is there, we use color. 32-bit QD is needed for the * offscreen GWorld */ if (!Gestalt (gestaltQuickdrawVersion, &resp) && resp > 0x1ff) { GDHandle gdh = GetDeviceList (); while (gdh) { if (TestDeviceAttribute (gdh, screenDevice)) { if (HasDepth (gdh, 4, 1, 1) || HasDepth (gdh, 8, 1, 1) || HasDepth (gdh, 16, 1, 1) || HasDepth (gdh, 32, 1, 1)) { _mt_in_color = 1; break; } } gdh = GetNextDevice (gdh); } } if (create_tty (&_mt_window, WIN_BASE_KIND + NHW_MAP, _mt_in_color) != noErr) error("_mt_init_stuff: Couldn't create tty."); SetWindowKind(_mt_window, WIN_BASE_KIND + NHW_MAP); SelectWindow(_mt_window); SetPortWindowPort(_mt_window); SetOrigin(-1, -1); font_size = iflags.wc_fontsiz_map ? iflags.wc_fontsiz_map : (iflags.large_font && !small_screen) ? 12 : 9; if (init_tty_number (_mt_window, win_fonts [NHW_MAP], font_size, CO, LI) != noErr) error("_mt_init_stuff: Couldn't init tty."); if (get_tty_metrics (_mt_window, &num_cols, &num_rows, &win_width , &win_height, &font_num, &font_size, &char_width, &row_height)) error("_mt_init_stuff: Couldn't get tty metrics."); SizeWindow (_mt_window, win_width + 2, win_height + 2, 1); if (RetrievePosition (kMapWindow, &vert, &hor)) { dprintf ("Moving window to (%d,%d)", hor, vert); MoveWindow (_mt_window, hor, vert, 1); } ShowWindow (_mt_window); /* Start in raw, always flushing mode */ get_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, &flag); flag |= TA_ALWAYS_REFRESH | TA_WRAP_AROUND; set_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, flag); get_tty_attrib(_mt_window, TTY_ATTRIB_CURSOR, &flag); flag |= (TA_BLINKING_CURSOR | TA_NL_ADD_CR); set_tty_attrib(_mt_window, TTY_ATTRIB_CURSOR, flag); set_tty_attrib(_mt_window, TTY_ATTRIB_FOREGROUND, _mt_colors[NO_COLOR][0]); set_tty_attrib(_mt_window, TTY_ATTRIB_BACKGROUND, _mt_colors[NO_COLOR][1]); clear_tty (_mt_window); InitMenuRes (); } int tgetch (void) { EventRecord event; long sleepTime = 0; int ret = 0; for (;!ret;) { WaitNextEvent (-1, &event, sleepTime, 0); HandleEvent (&event); blink_cursor (_mt_window, event.when); if (event.what == nullEvent) { sleepTime = GetCaretTime (); } else { sleepTime = 0; } ret = GetFromKeyQueue (); if (ret == CHAR_CR) ret = CHAR_LF; } return ret; } void getreturn (char *str) { FlushEvents (-1, 0); msmsg ("Press space %s", str); (void) tgetch (); } int has_color (int color) { #if defined(__SC__) || defined(__MRC__) # pragma unused(color) #endif Rect r; // Point p = {0, 0}; GDHandle gh; if (!_mt_in_color) return 0; GetWindowBounds(_mt_window, kWindowContentRgn, &r); // SetPortWindowPort(_mt_window); // LocalToGlobal (&p); // OffsetRect (&r, p.h, p.v); gh = GetMaxDevice (&r); if (!gh) { return 0; } return (*((*gh)->gdPMap))->pixelSize > 4; /* > 4 bpp */ } void tty_delay_output (void) { EventRecord event; long toWhen = TickCount () + 3; while (TickCount () < toWhen) { WaitNextEvent (updateMask, &event, 3L, 0); if (event.what == updateEvt) { HandleEvent (&event); blink_cursor (_mt_window, event.when); } } } void cmov (int x, int y) { move_tty_cursor (_mt_window, x, y); ttyDisplay->cury = y; ttyDisplay->curx = x; } void nocmov (int x, int y) { cmov (x, y); } static void _mt_set_colors (long *colors) { short err; if (!_mt_in_color) { return; } err = set_tty_attrib (_mt_window, TTY_ATTRIB_FOREGROUND, colors [0]); err = set_tty_attrib (_mt_window, TTY_ATTRIB_BACKGROUND, colors [1]); } void term_end_attr (int attr) { #if defined(__SC__) || defined(__MRC__) # pragma unused (attr) #endif _mt_set_colors (_mt_attrs [0]); } void term_start_attr (int attr) { switch (attr) { case ATR_ULINE: _mt_set_colors (_mt_attrs [1]); break; case ATR_BOLD: _mt_set_colors (_mt_attrs [2]); break; case ATR_BLINK: _mt_set_colors (_mt_attrs [3]); break; case ATR_INVERSE: _mt_set_colors (_mt_attrs [4]); break; default: _mt_set_colors (_mt_attrs [0]); break; } } void standoutend (void) { term_end_attr (ATR_INVERSE); } void standoutbeg (void) { term_start_attr (ATR_INVERSE); } void term_end_color (void) { _mt_set_colors (_mt_colors [NO_COLOR]); } void cl_end (void) { _mt_set_colors (_mt_attrs [0]); clear_tty_window (_mt_window, ttyDisplay->curx, ttyDisplay->cury, CO - 1, ttyDisplay->cury); } void clear_screen (void) { _mt_set_colors (_mt_attrs [0]); clear_tty (_mt_window); } void cl_eos (void) { _mt_set_colors (_mt_attrs [0]); clear_tty_window (_mt_window, ttyDisplay->curx, ttyDisplay->cury, CO - 1, LI - 1); } void home (void) { cmov (0,0); } void backsp (void) { char eraser [] = { CHAR_BS, CHAR_BLANK, CHAR_BS, 0 }; short err; err = add_tty_string (_mt_window, eraser); err = update_tty (_mt_window); } void msmsg (const char *str, ...) { va_list args; char buf [1000]; va_start (args, str); vsprintf (buf, str, args); va_end (args); xputs (buf); } void term_end_raw_bold (void) { term_end_attr (ATR_INVERSE); } void term_start_raw_bold (void) { term_start_attr (ATR_INVERSE); } void term_start_color (int color) { if (color >= 0 && color < CLR_MAX) { _mt_set_colors (_mt_colors [color]); } } void setftty (void) { long flag; /* Buffered output for the game */ get_tty_attrib (_mt_window, TTY_ATTRIB_FLAGS, &flag); flag &= ~ TA_ALWAYS_REFRESH; flag |= TA_INHIBIT_VERT_SCROLL; /* don't scroll */ set_tty_attrib (_mt_window, TTY_ATTRIB_FLAGS, flag); iflags.cbreak = 1; } void tty_startup (int *width, int *height ) { _mt_init_stuff (); *width = CO; *height = LI; } void gettty (void) { } void settty (const char *str) { long flag; update_tty (_mt_window); /* Buffered output for the game, raw in "raw" mode */ get_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, &flag); flag &= ~ TA_INHIBIT_VERT_SCROLL; /* scroll */ flag |= TA_ALWAYS_REFRESH; set_tty_attrib(_mt_window, TTY_ATTRIB_FLAGS, flag); tty_raw_print ("\n"); if (str) { tty_raw_print (str); } } void tty_number_pad (int arg) { #if defined(__SC__) || defined(__MRC__) # pragma unused(arg) #endif } void tty_start_screen (void) { iflags.cbreak = 1; } void tty_end_screen (void) { } void xputs (const char *str) { add_tty_string (_mt_window, str); } int term_puts (const char *str) { xputs (str); return strlen (str); } int term_putc (int c) { short err; err = add_tty_char (_mt_window, c); return err ? EOF : c; } int term_flush (void *desc) { if (desc == stdout || desc == stderr) { update_tty (_mt_window); } else { impossible ("Substituted flush for file"); return fflush (desc); } return 0; } nethack-3.4.3/sys/msdos/0040755000000000000000000000000007764735152013623 5ustar rootrootnethack-3.4.3/sys/msdos/Install.dos0100644000000000000000000002671507764735041015745 0ustar rootroot SCCS Id: @(#)Install.dos 3.4 Copyright (c) NetHack PC Development Team 1990-2002. NetHack may be freely redistributed. See license for details. ============================================================== Instructions for compiling and installing NetHack 3.4 on a DOS system ====================================================== (or, How to make PC NetHack 3.4) Last revision: $Date: 2003/06/13 19:57:52 $ Credit for a runnable full PC NetHack 3.4 goes to the PC Development team of Paul Winner, Kevin Smolkowski, Michael Allison, Yitzhak Sapir, Bill Dyer, Timo Hakulinen, Yamamoto Keizo, Mike Threepoint, Mike Stephenson, Stephen White, Ken Washikita and Janet Walz. The present port is based on the previous effort of Pierre Martineau, Stephen Spackman, Steve Creps, Mike Threepoint, Mike Stephenson, Norm Meluch and Don Kneller. There has been very little port-specific maintenance for NetHack on DOS since NetHack 3.3.0. CONTENTS: I. Dispelling the Myths II. Compiling on a DOS machine Appendix A - Building the "official binary" Appendix B - DJGPP Compiler (gcc ported to msdos) notes Appendix C - Additional Notes Appendix D - Contacting Us I. Dispelling the Myths: Compiling NetHack is not as easy as it sounds, nor as hard as it looks, however it will behoove you to read this entire file through before beginning the task. We have provided a proper Makefile for building NetHack using the following compilers: djgpp V2.03 or later For specific details concerning the djgpp compiler, please see the appendix B. The makefile named Makefile.GCC is for use with GNU Make that accompanies djgpp. If you want to build a copy of NetHack that is identical to the "official binary", please see appendix A. The unsupported sys/msdos/Makefile.MSC was for the old 16 bit Microsoft Visual C 1.52c compiler and has not been made compliant with 3.4.x. You may find it useful to obtain copies of lex (flex) and yacc (bison or byacc). While not strictly necessary to compile nethack, they are required should you desire to make any changes to the level and dungeon compilers. Flex and Bison are included with the DJGPP distribution and are also available on many archive sites. Also be sure to pick up djgpp v2gnu/fil41b.zip to get ls.exe and touch.exe, since the Makefile uses them by default. II. To compile your copy of NetHack on a DOS machine: (or "just follow these few 'simple' steps outlined below.") 1. It almost goes without saying that you should make sure that your tools are set up and running correctly. 2. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, sys\share, sys\msdos, util, win\tty and win\share. Other subdirectories may also be included in your distribution, but they are not necessary for use with DOS. You can delete them to save space. Required Source Directories for DOS NetHack: (top) | ------------------------------------------------- | | | | | | | util dat doc include src sys win | | ------ ----- | | | | share msdos tty share Check the file "Files" in your top level directory for an exact listing of what files are in which directory. In order for the Makefiles to work, all the source files must be in the proper locations. If you downloaded or ftp'd the sources from a UNIX system, the lines will probably end in UNIX-style newlines, instead of the carriage return and line feed pairs used by DOS. Some programs have trouble with them, so you may need to convert them (with a utility like Rahul Dhesi's "flip"). 3. Go to the sys/msdos directory and ensure that the file setup.bat has MSDOS style end-of-line characters rather than UNIX style end-of-line characters. You can do that using a utility like Rahul Dhesi's "flip", or by invoking the MSDOS edit utility on setup.bat and saving the file without making any changes. Failure to do this will prevent the bat file from executing completely, yet no warning message will be given. Run the setup.bat batch file with the following as the argument: GCC For djgpp and GNU MAKE. The appropriate and necessary Makefile movement will be accomplished for you, as well as verifying a few files and fixing a few file names on FAT systems with long file name support. 4. Now go to the include subdirectory to check a couple of the header files there. Things *should* work as they are, but since you have probably set up your system in some sort of custom configuration it doesn't hurt to check out the following: First check config.h according to the comments to match your system and desired set of features. Mostly you need to check the WIZARD option, and check TERMLIB and COMPRESS. Also be sure to leave DLB support commented out in config.h. MSDOS has support for DLB, but it must be done through the Makefile, rather than config.h, to ensure that the necessary packaging steps are done. We've managed to enable all the special features. You may include all or as few of them as you wish. To conserve disk space, you may wish to disable LOGFILE and NEWS. Also check pcconf.h, which should not need much editing (if you are including random.c, and if you do not require termcap for screen management). If you are not including random.c you will need to comment out RANDOM. If using DJGPP, you can choose between SCREEN_BIOS and SCREEN_DJGPPFAST. Never, never, ever choose both. Bad things will happen. We are not kidding. 5. If you want to change the high score list behavior, examine the top of topten.c, in the src directory. You may want to change the definitions of PERSMAX, POINTSMIN, and ENTRYMAX. We set POINTSMIN to 51 and ENTRYMAX to 50 to keep the size of the score list down. 6. Go to the src directory and edit the top of your Makefile. Be sure the directory you want the game installed in (GAMEDIR) actually exists. 7. Now that everything is set up, Go to the src directory, and using the GNU Make utility, "make install". Depending on your particular machine and compiler, you can either grab a cup of coffee or go home for the day. Your computer will be occupied for quite some time. If all goes well, you will get an NetHack executable. 9. If you chose DLB support (recommended), make sure that the file nhdat got copied into the game directory. If you didn't choose DLB support, make sure the support files -- data, rumors, cmdhelp, opthelp, help, hh,history, guidebook.txt license, and all the *.lev files -- were copied to the game directory. If not, move them there from the dat directory yourself. rumors can be created manually be entering "makedefs -r", data by entering "makedefs -d". Make sure the files NetHack1.tib and NetHacko.tib made it to your game directory. Copy them from src to the game directory yourself if necessary. Make sure the files defaults.nh and termcap made it to your game directory. If not, go to sys\share and copy NetHack.cnf to your game directory as defaults.nh. The name in previous versions was nethack.cnf, but the CNF extension conflicted with the MS Windows speed-dialer, making the file hidden on many machines. If you changed your build settings to include TERMCAP support, copy termcap to your game directory. Also, make sure the file msdoshlp.txt made it to your game directory. If it didn't, move it from sys\msdos to your game directory yourself. 10. In your game directory, review the settings in defaults.nh and adjust them according to your style of play. 11. Play NetHack. If it works, you're done! Appendix A - Building the "official binary" If you wish to build a copy of NetHack identical to the one that the pc team distributes, simply do the following: The 32-bit Protected Mode DPMI version built with 32-bit djgpp compiler V2.03 or greater, make no changes to any of the defines and use the Makefile.GCC as distributed, and as moved in step 3. Paths below are relative to the top of your unpacked NetHack source distribution: md \nethack\binary (must match Makefile) cd sys\msdos setup GCC cd ..\..\src make install Make sure the following files have been converted from the unix style "^J" end of line, to the msdos style "^M^J": license, defaults.nh. Place all the files in a clean directory and test. Appendix B - DJGPP Compiler (gcc ported to msdos) If you have a 386 or better machine, you are in luck. You can compile NetHack without spending money on a compiler. DJGPP is available free from many archive sites. At the time of this release in April 2002, the URL http://www.delorie.com/djgpp/zip-picker.html/ had information on how to obtain djgpp and what pieces to get. Be sure to pick up djgpp v2gnu/fil41b.zip to get ls.exe and touch.exe, since the Makefile uses them by default (or change the Makefile to use alternatives). Special note for Windows 2000 / Windows XP users: You must have a recent djgpp distribution for the build process, and the generated executables to work properly on those platforms. Setting up DJGPP is more than adequately explained in the documentation that comes with it. Be sure to pick up the yacc and flex built with DJGPP if you intend to do any modification of the special levels or dungeon compilers. They should be available at the same place you got djgpp. The latest version of djgpp, V2.03 with the most recent refresh will produce a binary that will run under Microsoft Windows, or any other DPMI provider. djgpp also comes with a DPMI provider called CWSDPMI. Place CWSDPMI.EXE in your path and it will be used in the absence of any other DPMI provider. If you want to use the built-in DJGPP screen routines, uncomment SCREEN_DJGPPFAST in pcconf.h (the default for djgpp). Appendix C - Additional Notes 1) Save files and bones files from versions of NetHack prior to 3.4.0 will not work with this NetHack. Don't bother trying to keep them. 2) To install an update of NetHack after changing something, type 'make' for DJGPP from the src directory. If you add, delete, or reorder monsters or objects, or you change the format of saved level files, delete any save and bones files. (Trying to use such files sometimes produces amusing confusions on the game's part, but usually crashes.) Appendix D - Contacting the Development Team If you discover a bug and wish to report it, or if you have comments or suggestions we recommend using our "Contact Us" web page at: http://www.nethack.org/common/contact.html If you don't have access to the web, or you want to send us a patch to the NetHack source code feel free to drop us a line c/o: DevTeam (at) nethack.org nethack-3.4.3/sys/msdos/Makefile.BC0100644000000000000000000017731007764735041015551 0ustar rootroot# SCCS Id: @(#)Makefile.BC 3.4 2002/03/17 # Copyright (c) Yitzhak Sapir, 1999-2002. # NetHack may be freely distributed. See license for details. # # PC NetHack 3.4 Makefile for Borland C++ 3.1 and 4.5. # # Nota Bene: Before you get to here you should have already read # the Install.dos file located in the sys/msdos directory. # Additionally, you should run this makefile with the -N # Microsoft Compatibility option. # # This Makefile is for use with Borland C++ version 3.1 and 4.5, but might # also work with more up to date versions. # # This Makefile is specific to Borland's MAKE which is supplied with the # compiler. It supports only one overlay management facility - VROOMM. # (This Makefile won't work with make45l or NDMAKE) # # Game Installation Variables. # NOTE: Make sure GAMEDIR exists before nmake is started. # GAME = NetHack GAMEDIR = ..\binary # # # Directories # DAT = ..\dat DOC = ..\doc INCL = ..\include SRC = ..\src OBJ = o MSYS = ..\sys\msdos SYS = ..\sys\share UTIL = ..\util WTTY = ..\win\tty WSHR = ..\win\share # # Compiler File Info. # ($(MAKE) macro is often predefined, so we use $(MAKEBIN) instead.) # CC = bcc # Compiler LINK = tlink # Linker ASM = tasm # Assembler (not currently needed for BC) MAKEBIN = make UUDECODE = uudecode # Unix style uudecoder #BCTOP = c:\borlandc # main Borland C++ directory BCTOP = c:\bc31 # # Yacc/Lex ... if you got 'em. # # If you have yacc and lex programs (or work-alike such as bison # and flex), comment out the upper two lines below, and uncomment # the lower two. # # On Borland C++, the newest versions of flex and bison provide # problems when run from MAKE. # DO_YACC = YACC_MSG DO_LEX = LEX_MSG #DO_YACC = YACC_ACT #DO_LEX = LEX_ACT # # - Specify your yacc and lex programs (or work-alikes for each) here. # YACC = bison -y #YACC = yacc #YACC = byacc LEX = flex #LEX = lex # # - Specify your flex skeleton file (if needed). # FLEXSKEL = #FLEXSKEL = -Sc:\tools16\flex.ske # # - Your yacc (or work-alike) output files # YTABC = y_tab.c YTABH = y_tab.h #YTABC = ytab.c #YTABH = ytab.h # # - Your lex (or work-alike) output files # LEXYYC = lexyy.c #LEXYYC = lex.yy.c # # Optional high-quality BSD random number generation routines # (see pcconf.h). Set to nothing if not used. # RANDOM = $(OBJ)\random.o #RANDOM = # # If TERMLIB is #defined in the source (in include\pcconf.h), # comment out the upper line and uncomment the lower. Make sure # that TERMLIB contains the full pathname to the termcap library. TERMLIB = #TERMLIB = $(SYS)\termcap.lib # # MEMORY USAGE AND OVERLAYING # # Overlay Schema 1 # # - Minimal extended memory available, lots of 640K base RAM free # Minimize overlay turns. Requires that a minimum of # 607K RAM be free as follows: # 462K Executable load requirement # 115K for malloc() calls # 30K Overlay buffer # 607K Total memory requirement # # Overlay Schema 2 # # - Favor small load size, requires extended memory for bearable performance. # If you have very little base 640K RAM available, but lots of extended # memory for caching overlays, you might try this. (eg. A machine with # lots of TSR's or network drivers). Do not try to set SCHEMA = 2 # without a disk cache and extended memory. # 381K Executable load requirement # 115K for malloc() calls # 30K Overlay buffer # 526K Total memory requirement # # On Borland C++, you have to make a full rebuild of all object modules each # time you change schemas. # SCHEMA = 2 # # OPTIONAL TILE SUPPORT. # # This release of NetHack allows you to build a version of NetHack # that will draw 16x16 color tiles on the display to represent # NetHack maps, objects, monsters, etc. on machines with appropriate # display hardware. Currently the only supported video hardware is # VGA. # # Note: You can build NetHack with tile support and then choose # whether to use it or not at runtime via the defaults.nh file option # "video". # TILESUPPORT = Y # # C COMPILER AND LINKER SETTINGS # # For debugging ability, comment out the upper three # macros and uncomment the lower three. You can also # uncomment only either LDFLAGSU or LDFLAGSN if you # want to include debug information only in the utilities # or only in the game file. # On Borland C++, you cannot include debug information for # all the object modules because the linker cannot handle # it. #CDFLAGS = LDFLAGSN = #LDFLAGSU = CDFLAGS = -v -vi # use debug info (compiler) #LDFLAGSN = /v # use debug info (linker - game) LDFLAGSU = /v # use debug info (linker - utilities) # # - Don't warn about unreachable code because flex generates a whole bunch # of unreachable code warnings, which stops the compile process. # CW = -w-rch # # Select whether to use pre-compiled headers or not. # Set PRECOMPHEAD to Y to use pre-compiled headers, set it to anything # else and pre-compiled headers will not be used. # (Pre-compiled headers speed up compiles, but require a bit more # disk space during the build. The pre-compiled headers can be deleted # afterwards via DEL *.PCH if desired). # PRECOMPHEAD = N # # C Compiler Flags # CFLAGS = -c # Uncomment the line below if you want to store all the level files, # help files, etc. in a single library file (recommended). USE_DLB = Y # ######################################################################## ######################################################################## # # Nothing below here should have to be changed. # ######################################################################## ######################################################################## # # Warning: # # Changing anything below here means that you should be *very* # familiar with your compiler's workings, *very* knowledgeable # about the overlay structure and mechanics of NetHack, and *very* # confident in your understanding of Makefiles and Make utilities. # ######################################################################## # # Default Make Procedure # default: $(GAME) # ######################################################################## # Tile preparation # ! IF ("$(TILESUPPORT)"=="Y") TILEGAME = $(OBJ)\tile.o $(OBJ)\pctiles.0 $(OBJ)\pctiles.b # # - VGA Tile Support, uncomment these three lines. # TILEVGA = $(OBJ)\vidvga.0 $(OBJ)\vidvga.1 $(OBJ)\vidvga.2 $(OBJ)\vidvga.b PLANAR_TIB = NetHack1.tib OVERVIEW_TIB = NetHacko.tib # # Leave this line uncommented and unchanged. TILEUTIL = $(TILEGAME) $(TILEVGA) $(UTIL)\tile2bin.exe $(UTIL)\til2bin2.exe \ $(PLANAR_TIB) $(OVERVIEW_TIB) ! ENDIF ! IF ("$(USE_DLB)"=="Y") DLB = nhdat ! ELSE DLB = ! ENDIF # ############################################################################# # # General Overlay Schema Settings # OVLINIT =$(OBJ)\ovlinit.o # ############################################################################# # # C Compiler and Linker Setup Options # (To Maintainer; modify only if absolutely necessary) # BCINCL = $(BCTOP)\include # include directory for main BC headers BCLIB = $(BCTOP)\lib # library directory for main BC libraries BCCFG = nethack.cfg # name of the nethack configuration file VROOMMCFG= vroomm.cfg # name of file with code segment information # # Model # MODEL = h # # - Optional C library specifier for those with non-standard # libraries or a multiple-target library setup. # CLIB = # # Borland C++ libraries # BCOVL = $(BCLIB)\OVERLAY BCMDL = $(BCLIB)\C$(MODEL) # # Compiler Options # CNOLNK = -c # just generate .OBJ CPCHUSE = -Hu # use precompiled headers CPCHGEN = -H # generate precompiled headers CPCHNAM = -H= # set the name of the precompiled header file CPCHEXT = .PCH # precompiled header extension CDEFINE = -D # define a macro CSTKSZ = -DSTKSIZ= # set stack size CCSNAM = -zC # set the code segment name COBJNAM = -o # name the .OBJ file # # Linker Options # LWCASE = /c # treat case as significant LMAP = /m # create map file LINIT = $(BCLIB)\C0$(MODEL) # initialization object file LOVL = /oOVLY # overlay all needed segments # # Stack Sizes # STKSUTL = 4096 # Utilities Stack Size STKSNRM = 5120 # Normal Stack Size CUSTACK = $(CSTKSZ)$(STKSUTL) # Utilities Stack Set for Compiler CNSTACK = $(CSTKSZ)$(STKSNRM) # Normal Stack Set for Compiler # ######################################################################## # DLB preparation # ! IF ("$(USE_DLB)"=="Y") DLBFLG = $(CDEFINE)DLB ! ELSE DLBFLG = ! ENDIF # ######################################################################## # tile preparation # ! IF ("$(TILESUPPORT)"=="Y") TILFLG = $(CDEFINE)USE_TILES ! ELSE TILFLG = ! ENDIF ############################################################################# # # Overlay switches # COVL0 = $(CDEFINE)OVL0 COVL1 = $(CDEFINE)OVL1 COVL2 = $(CDEFINE)OVL2 COVL3 = $(CDEFINE)OVL3 COVLB = $(CDEFINE)OVLB # # Flags # FLAGOPT = $(DLBFLG) $(TILFLG) # # Precompiled Header Section # #common options (placed in $(BCCFG)) CFLGTOT = $(CDFLAGS) $(CFLAGS) $(FLAGOPT) $(CW) #util builds CFLAGSU = $(CUSTACK) +$(VROOMMCFG) #normal build, no PCH CFLAGSN = $(CNSTACK) +$(VROOMMCFG) #no optimizations CFLAGNO = $(CNOOPT) $(CFLAGSN) ! IF ("$(PRECOMPHEAD)"!="Y") CFLAGCO = $(COVLO) CFLAGUO = $(COVLO) CFLAGC0 = $(COVL0) CFLAGU0 = $(COVL0) CFLAGC1 = $(COVL1) CFLAGU1 = $(COVL1) CFLAGC2 = $(COVL2) CFLAGU2 = $(COVL2) CFLAGC3 = $(COVL3) CFLAGU3 = $(COVL3) CFLAGCB = $(COVLB) CFLAGUB = $(COVLB) PCHO = PCH0 = PCH1 = PCH2 = PCH3 = PCHB = precomp.msg: @echo Not using precompiled headers... ! ELSE # .o files CFLAGUO = $(CPCHUSE) $(CPCHNAM)PHO$(CPCHEXT) $(COVLO) CFLAGCO = $(CPCHGEN) $(CPCHNAM)PHO$(CPCHEXT) $(COVLO) PCHO = PHO$(CPCHEXT) # .0 files CFLAGU0 = $(CPCHUSE) $(CPCHNAM)PH0$(CPCHEXT) $(COVL0) CFLAGC0 = $(CPCHGEN) $(CPCHNAM)PH0$(CPCHEXT) $(COVL0) PCH0 = PH0$(CPCHEXT) # .1 files CFLAGU1 = $(CPCHUSE) $(CPCHNAM)PH1$(CPCHEXT) $(COVL1) CFLAGC1 = $(CPCHGEN) $(CPCHNAM)PH1$(CPCHEXT) $(COVL1) PCH1 = PH1$(CPCHEXT) # .2 files CFLAGU2 = $(CPCHUSE) $(CPCHNAM)PH2$(CPCHEXT) $(COVL2) CFLAGC2 = $(CPCHGEN) $(CPCHNAM)PH2$(CPCHEXT) $(COVL2) PCH2 = PH2$(CPCHEXT) # .3 files CFLAGU3 = $(CPCHUSE) $(CPCHNAM)PH3$(CPCHEXT) $(COVL3) CFLAGC3 = $(CPCHGEN) $(CPCHNAM)PH3$(CPCHEXT) $(COVL3) PCH3 = PH3$(CPCHEXT) # .B files CFLAGUB = $(CPCHUSE) $(CPCHNAM)PHB$(CPCHEXT) $(COVLB) CFLAGCB = $(CPCHGEN) $(CPCHNAM)PHB$(CPCHEXT) $(COVLB) PCHB = PHB$(CPCHEXT) precomp.msg: @echo Using precompiled headers... ! ENDIF FLAGCO = $(CNSTACK) +$(VROOMMCFG) FLAGUO = $(CNSTACK) +$(VROOMMCFG) FLAGC0 = $(CNSTACK) +$(VROOMMCFG) FLAGU0 = $(CNSTACK) +$(VROOMMCFG) FLAGC1 = $(CNSTACK) +$(VROOMMCFG) FLAGU1 = $(CNSTACK) +$(VROOMMCFG) FLAGC2 = $(CNSTACK) +$(VROOMMCFG) FLAGU2 = $(CNSTACK) +$(VROOMMCFG) FLAGC3 = $(CNSTACK) +$(VROOMMCFG) FLAGU3 = $(CNSTACK) +$(VROOMMCFG) FLAGCB = $(CNSTACK) +$(VROOMMCFG) FLAGUB = $(CNSTACK) +$(VROOMMCFG) # End of Pre-compiled header section #=========================================================================== # # Basic Borland C++ option line # BCOPTS1 = -Y -O -Z -Oe -Ob -Os -Ff -I$(BCINCL);$(INCL) -m$(MODEL) BCOPTS2 = $(CDEFINE)__IO_H $(CFLGTOT) -DSTRNCMPI # # Linker options for building various things. # LFLAGSU = $(LDFLAGSU) $(LUSTACK) $(LINIT) LFLAGSN = $(LDFLAGSN) $(LNSTACK) $(LWCASE) $(LMAXSEG) $(INTOVL) $(LMAXALL) \ $(LINFO) $(LINIT) $(LOVL) # # Make Roolz dude. # Due to the inadequacy of some makes these must accord with a # topological sort of the generated-from relation... output on # the left, input on the right. Trust me. # .SUFFIXES: .exe .0 .1 .2 .3 .B .o .til .uu .c .y .l # # Rules for files in src # .c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.0: @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.1: @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.2: @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.3: @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG) $(CC) $(FLAGU3) $(COBJNAM)$@ $< {$(SRC)}.c{$(OBJ)}.B: @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $< # # Rules for files in sys\share # {$(SYS)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.0: @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.1: @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.2: @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.3: @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG) $(CC) $(FLAGU3) $(COBJNAM)$@ $< {$(SYS)}.c{$(OBJ)}.B: @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $< # # Rules for files in sys\msdos # {$(MSYS)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.0: @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.1: @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.2: @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.3: @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG) $(CC) $(FLAGU3) $(COBJNAM)$@ $< {$(MSYS)}.c{$(OBJ)}.B: @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $< {$(MSYS)}.h{$(INCL)}.h: @copy $< $@ # # Rules for files in util # {$(UTIL)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) (COBJNAM)$@ $< # # Rules for files in win\share # {$(WSHR)}.c.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) @$(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(WSHR)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) @$(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(WSHR)}.h{$(INCL)}.h: @copy $< $@ {$(WSHR)}.txt{$(DAT)}.txt: @copy $< $@ # # Rules for files in win\tty # {$(WTTY)}.c{$(OBJ)}.o: @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.0: @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.1: @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.2: @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.3: @type schema$(SCHEMA).bc | find "$(@B)_3" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU3) >> $(VROOMMCFG) $(CC) $(FLAGU3) $(COBJNAM)$@ $< {$(WTTY)}.c{$(OBJ)}.B: @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $< # # NETHACK OBJECTS # # This section creates shorthand macros for many objects # referenced later on in the Makefile. # # # Shorten up the location for some files # O = $(OBJ)\ # comment so \ isn't last char U = $(UTIL)\ # comment so \ isn't last char SPLEVDES = $(DAT)\Arch.des $(DAT)\Barb.des $(DAT)\bigroom.des \ $(DAT)\castle.des $(DAT)\Caveman.des $(DAT)\endgame.des \ $(DAT)\gehennom.des $(DAT)\Healer.des $(DAT)\Knight.des \ $(DAT)\knox.des $(DAT)\Monk.des $(DAT)\medusa.des \ $(DAT)\mines.des $(DAT)\oracle.des $(DAT)\Priest.des \ $(DAT)\Ranger.des $(DAT)\Rogue.des $(DAT)\Samurai.des \ $(DAT)\Tourist.des $(DAT)\tower.des $(DAT)\Valkyrie.des \ $(DAT)\Wizard.des $(DAT)\yendor.des # # Utility Objects. # MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS =$(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o $(O)monst.o \ $(O)objects.o $(O)panic.o $(O)stubvid.o DGNCOMPOBJS =$(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o RECOVOBJS = $(O)recover.o GIFREADERS =$(O)gifread.o $(O)alloc.o $(O)panic.o TEXT_IO =$(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o $(O)stubvid.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o GIFREAD2 =$(O)gifread2.o $(O)alloc.o $(O)panic.o TEXT_IO2 =$(O)tiletex2.o $(O)tiletxt2.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o $(O)stubvid.o PPMWRIT2 = $(O)ppmwrit2.o $(O)alloc.o $(O)panic.o TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt TILEFILES2 = $(WSHR)\monthin.txt $(WSHR)\objthin.txt $(WSHR)\oththin.txt DLBOBJS = $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o # # Object files for the game itself. # OBJ01 = $(O)alloc.o $(RANDOM) $(O)decl.o $(O)objects.o \ $(O)muse.o $(O)display.o $(O)vision.o $(O)mapglyph.o \ $(O)rect.o $(O)vis_tab.o $(O)monst.o $(O)wintty.o \ $(O)files.o $(O)sys.o $(O)monstr.o $(O)minion.o \ $(O)worm.o $(O)detect.o $(O)exper.o $(O)mplayer.o \ $(O)uhitm.o $(O)pager.o $(O)windows.o $(O)quest.o \ $(O)questpgr.o $(O)write.o $(O)drawing.o $(O)dokick.o \ $(O)dothrow.o $(O)pickup.o $(O)pray.o $(O)spell.o \ $(O)ball.o $(O)wield.o $(O)worn.o $(O)fountain.o \ $(O)music.o $(O)rumors.o $(O)dlb.o $(O)sit.o \ $(O)bones.o $(O)mklev.o $(O)save.o $(O)restore.o \ $(O)mkmaze.o $(O)mkmap.o $(O)end.o $(O)o_init.o \ $(O)options.o $(O)rip.o $(O)sound.o $(O)teleport.o \ $(O)topten.o $(O)tty.o $(O)u_init.o $(O)extralev.o \ $(O)sp_lev.o $(O)dig.o $(O)pckeys.o $(O)role.o \ $(O)steed.o $(O)region.o OVL0 = $(O)allmain.0 $(O)apply.0 $(O)artifact.0 $(O)attrib.0 \ $(O)botl.0 $(O)cmd.0 $(O)dbridge.0 $(O)do.0 \ $(O)do_name.0 $(O)do_wear.0 $(O)dogmove.0 $(O)dungeon.0 \ $(O)eat.0 $(O)engrave.0 $(O)hacklib.0 $(O)invent.0 \ $(O)lock.0 $(O)pcmain.0 $(O)mail.0 $(O)makemon.0 \ $(O)mcastu.0 $(O)mhitm.0 $(O)mhitu.0 $(O)mkobj.0 \ $(O)mkroom.0 $(O)mon.0 $(O)mondata.0 $(O)monmove.0 \ $(O)mthrowu.0 $(O)objnam.0 $(O)polyself.0 $(O)priest.0 \ $(O)rnd.0 $(O)shknam.0 $(O)sounds.0 $(O)steal.0 \ $(O)timeout.0 $(O)track.0 $(O)trap.0 $(O)vault.0 \ $(O)weapon.0 $(O)were.0 $(O)wizard.0 $(O)msdos.0 \ $(O)termcap.0 $(O)video.0 $(O)vidtxt.0 $(O)zap.0 \ $(O)explode.0 $(O)shk.0 OVL1 = $(O)allmain.1 $(O)apply.1 $(O)artifact.1 $(O)attrib.1 \ $(O)botl.1 $(O)cmd.1 $(O)dbridge.1 $(O)do.1 \ $(O)do_wear.1 $(O)dog.1 $(O)dungeon.1 $(O)eat.1 \ $(O)engrave.1 $(O)hack.1 $(O)hacklib.1 $(O)invent.1 \ $(O)makemon.1 $(O)mhitu.1 $(O)mkobj.1 $(O)mon.1 \ $(O)mondata.1 $(O)monmove.1 $(O)mthrowu.1 $(O)objnam.1 \ $(O)pcmain.1 $(O)polyself.1 $(O)rnd.1 $(O)shk.1 \ $(O)steal.1 $(O)timeout.1 $(O)track.1 $(O)trap.1 \ $(O)weapon.1 $(O)getline.1 $(O)termcap.1 $(O)topl.1 \ $(O)video.1 $(O)zap.1 $(O)explode.1 OVL2 = $(O)attrib.2 $(O)do.2 $(O)do_name.2 $(O)do_wear.2 \ $(O)dog.2 $(O)engrave.2 $(O)hack.2 $(O)hacklib.2 \ $(O)invent.2 $(O)makemon.2 $(O)mon.2 $(O)mondata.2 \ $(O)monmove.2 $(O)getline.2 $(O)shk.2 $(O)topl.2 \ $(O)trap.2 $(O)zap.2 OVL3 = $(O)do.3 $(O)hack.3 $(O)invent.3 $(O)light.3 \ $(O)shk.3 $(O)trap.3 $(O)zap.3 OVLB = $(O)allmain.B $(O)apply.B $(O)artifact.B $(O)attrib.B \ $(O)botl.B $(O)cmd.B $(O)dbridge.B $(O)do.B \ $(O)do_name.B $(O)do_wear.B $(O)dog.B $(O)dogmove.B \ $(O)eat.B $(O)engrave.B $(O)hack.B $(O)hacklib.B \ $(O)invent.B $(O)lock.B $(O)mail.B $(O)makemon.B \ $(O)mcastu.B $(O)mhitm.B $(O)mhitu.B $(O)mkobj.B \ $(O)mkroom.B $(O)mon.B $(O)mondata.B $(O)monmove.B \ $(O)mthrowu.B $(O)objnam.B $(O)pcmain.B $(O)pline.B \ $(O)polyself.B $(O)potion.B $(O)priest.B $(O)read.B \ $(O)rnd.B $(O)shk.B $(O)shknam.B $(O)sounds.B \ $(O)steal.B $(O)timeout.B $(O)track.B $(O)trap.B \ $(O)vault.B $(O)weapon.B $(O)were.B $(O)wizard.B \ $(O)msdos.B $(O)pcunix.B $(O)termcap.B $(O)topl.B \ $(O)video.B $(O)vidtxt.B $(O)zap.B TILOBJ = $(TILEGAME) $(TILEVGA) VVOBJ = $(O)version.o NVOBJ = $(OBJ01) $(OVL0) $(OVL1) $(OVL2) \ $(OVL3) $(OVLB) $(TILOBJ) ALLOBJ= $(NVOBJ) $(VVOBJ) $(OVLINIT) # # Header objects # # This comment copied from sys/unix/Makefile.src, # extern.h is ignored, even though its declared function types may affect the # compilation of all the .c files, since extern.h changes every time the # type of an external function does, and we would spend all our time recompiling # if we did not ignore it. #EXTERN_H = $(INCL)\extern.h EXTERN_H = PCCONF_H = $(INCL)\pcconf.h $(INCL)\micro.h $(INCL)\system.h PERMONST_H = $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\align.h YOUPROP_H = $(INCL)\prop.h $(PERMONST_H) $(INCL)\pm.h $(INCL)\youprop.h \ $(INCL)\mondata.h YOU_H = $(INCL)\attrib.h $(INCL)\monst.h $(YOUPROP_H) $(INCL)\align.h DECL_H = $(INCL)\quest.h $(INCL)\spell.h $(INCL)\color.h \ $(INCL)\obj.h $(YOU_H) $(INCL)\onames.h $(INCL)\pm.h CONFIG_H = $(INCL)\config1.h $(INCL)\tradstdc.h $(INCL)\coord.h $(PCCONF_H) \ $(INCL)\config.h HACK_H = $(CONFIG_H) $(INCL)\dungeon.h $(INCL)\align.h $(INCL)\monsym.h \ $(INCL)\mkroom.h $(INCL)\objclass.h $(DECL_H) \ $(INCL)\timeout.h $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \ $(INCL)\vision.h $(INCL)\mondata.h $(INCL)\wintype.h \ $(INCL)\engrave.h $(INCL)\rect.h $(EXTERN_H) \ $(INCL)\winprocs.h $(INCL)\trampoli.h $(INCL)\display.h TILE_H = $(INCL)\tile.h $(INCL)\pctiles.h PCVIDEO_H = $(INCL)\portio.h $(INCL)\pcvideo.h ALIGN_H = $(INCL)\align.h ARTIFACT_H = $(INCL)\artifact.h ARTILIST_H = $(INCL)\artilist.h COLOR_H = $(INCL)\color.h DATE_H = $(INCL)\date.h DGN_FILE_H = $(INCL)\dgn_file.h DLB_H = $(INCL)\dlb.h EMIN_H = $(INCL)\emin.h EPRI_H = $(INCL)\epri.h ESHK_H = $(INCL)\eshk.h EDOG_H = $(INCL)\edog.h FUNC_TAB_H = $(INCL)\func_tab.h LEV_H = $(INCL)\lev.h LEV_COMP_H = $(INCL)\lev_comp.h MAIL_H = $(INCL)\mail.h MFNDPOS_H = $(INCL)\mfndpos.h MONSYM_H = $(INCL)\monsym.h OBJ_H = $(INCL)\obj.h OBJCLASS_H = $(INCL)\objclass.h OBJECTS_H = $(INCL)\objects.h PROP_H = $(INCL)\prop.h QTEXT_H = $(INCL)\qtext.h QUEST_H = $(INCL)\quest.h SP_LEV_H = $(INCL)\sp_lev.h TERMCAP_H = $(INCL)\tcap.h VAULT_H = $(INCL)\vault.h VIS_TAB_H = $(INCL)\vis_tab.h WINTTY_H = $(INCL)\wintty.h # # In the unix distribution this file is patchlevel.h, make it 8.3 here # to avoid an nmake warning under dos. # PATCHLEVEL_H = $(INCL)\patchlev.h # # The name of the game. # GAMEFILE = $(GAMEDIR)\$(GAME).exe # # make data.base an 8.3 filename to prevent an nmake warning # DATABASE = $(DAT)\data.bas ####################################################################### # # TARGETS # # The main target. # $(GAME): obj.tag envchk $(U)utility.tag $(GAMEFILE) @echo $(GAME) is up to date. # # Everything # all : install install: $(GAME) install.tag @echo Done. install.tag: $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(DAT)\sp_lev.tag $(DLB) ! IF ("$(USE_DLB)"=="Y") copy nhdat $(GAMEDIR) copy $(DAT)\license $(GAMEDIR) ! ELSE copy $(DAT)\*. $(GAMEDIR) copy $(DAT)\*.dat $(GAMEDIR) copy $(DAT)\*.lev $(GAMEDIR) copy $(MSYS)\msdoshlp.txt $(GAMEDIR) if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile ! ENDIF copy $(SYS)\termcap $(GAMEDIR) if exist $(DOC)\guideb*.txt copy $(DOC)\guideb*.txt $(GAMEDIR) if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR) copy $(SYS)\NetHack.cnf $(GAMEDIR)\defaults.nh copy $(MSYS)\NHAccess.nh $(GAMEDIR) copy $(U)recover.exe $(GAMEDIR) if exist *.tib copy *.tib $(GAMEDIR) echo install done > $@ $(DAT)\sp_lev.tag: $(U)utility.tag $(SPLEVDES) cd $(DAT) $(U)lev_comp bigroom.des $(U)lev_comp castle.des $(U)lev_comp endgame.des $(U)lev_comp gehennom.des $(U)lev_comp knox.des $(U)lev_comp mines.des $(U)lev_comp medusa.des $(U)lev_comp oracle.des $(U)lev_comp sokoban.des $(U)lev_comp tower.des $(U)lev_comp yendor.des $(U)lev_comp arch.des $(U)lev_comp barb.des $(U)lev_comp caveman.des $(U)lev_comp healer.des $(U)lev_comp knight.des $(U)lev_comp monk.des $(U)lev_comp priest.des $(U)lev_comp ranger.des $(U)lev_comp rogue.des $(U)lev_comp samurai.des $(U)lev_comp tourist.des $(U)lev_comp valkyrie.des $(U)lev_comp wizard.des cd $(SRC) echo sp_levs done > $(DAT)\sp_lev.tag $(U)utility.tag: envchk $(INCL)\date.h $(INCL)\onames.h \ $(INCL)\pm.h $(SRC)\monstr.c $(SRC)\vis_tab.c \ $(U)lev_comp.exe $(VIS_TAB_H) $(U)dgn_comp.exe \ $(U)recover.exe $(TILEUTIL) @echo utilities made >$@ @echo utilities made. tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. # # Inline files : # Specifying the "<<" means to start an inline file. # Another "<<" at the start of a line closes the # inline file. # # DO NOT INDENT THE << below! # $(GAMEFILE) : $(ALLOBJ) @echo Linking.... $(LINK) $(LFLAGSN) @<<$(GAME).lnk $(ALLOBJ) $(GAMEFILE) $(GAME) $(TERMLIB) $(MOVETR) $(CLIB) $(BCOVL) $(BCMDL) << @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak # # Makedefs Stuff # $(U)makedefs.exe: $(MAKEOBJS) @$(LINK) $(LFLAGSU) $(MAKEOBJS), $@,, $(CLIB) $(BCMDL); $(O)makedefs.o: $(CONFIG_H) $(PERMONST_H) $(OBJCLASS_H) \ $(MONSYM_H) $(QTEXT_H) $(PATCHLEVEL_H) \ $(U)makedefs.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h : $(U)makedefs.exe $(U)makedefs -v @echo A new $@ has been created. $(INCL)\onames.h : $(U)makedefs.exe $(U)makedefs -o $(INCL)\pm.h : $(U)makedefs.exe $(U)makedefs -p #$(INCL)\trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)\monstr.c: $(U)makedefs.exe $(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe $(U)makedefs -z $(SRC)\vis_tab.c: $(U)makedefs.exe $(U)makedefs -z # # Level Compiler Stuff # $(U)lev_comp.exe: $(SPLEVOBJS) @echo Linking $@... $(LINK) $(LFLAGSU) @&&! $(O)stubvid.o $(O)panic.o $(O)objects.o $(O)monst.o + $(O)drawing.o $(O)decl.o $(O)alloc.o $(O)lev_main.o + $(O)lev_$(LEX).o $(O)lev_yacc.o $@ $(@B) $(BCMDL); ! $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)lev_main.c $(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" $(YACC) -d -l $(U)lev_comp.y copy $(YTABC) $(U)lev_yacc.c copy $(YTABH) $(INCL)\lev_comp.h @del $(YTABC) @del $(YTABH) ! ELSE @echo. @echo $(U)lev_comp.y has changed. @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC). @echo. @echo For now, we will copy the prebuilt lev_yacc.c @echo from $(SYS) to $(U)lev_yacc.c, and copy the prebuilt @echo lev_comp.h from $(SYS) to $(UTIL)\lev_comp.h @echo and use those. @echo. copy $(SYS)\lev_yacc.c $@ >nul touch $@ copy $(SYS)\lev_comp.h $(INCL)\lev_comp.h >nul touch $(INCL)\lev_comp.h ! ENDIF $(U)lev_$(LEX).c: $(U)lev_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" $(LEX) $(FLEXSKEL) $(U)lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) ! ELSE @echo. @echo $(U)lev_comp.l has changed. To update $@ run $(LEX). @echo. @echo For now, we will copy a prebuilt lev_lex.c @echo from $(SYS) to $@ and use it. @echo. copy $(SYS)\lev_lex.c $@ >nul touch $@ ! ENDIF # # Dungeon Stuff # $(U)dgn_comp.exe: $(DGNCOMPOBJS) @echo Linking $@... $(LINK) $(LFLAGSU) @&&! $(O)panic.o $(O)alloc.o $(O)dgn_main.o $(O)dgn_$(LEX).o + $(O)dgn_yacc.o $@ $(@B) $(BCMDL); ! $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_yacc.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_$(LEX).c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) @$(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" $(YACC) -d -l $(U)dgn_comp.y copy $(YTABC) $(U)dgn_yacc.c copy $(YTABH) $(INCL)\dgn_comp.h @del $(YTABC) @del $(YTABH) ! ELSE @echo. @echo $(U)dgn_comp.y has changed. To update $@ and @echo $(INCL)\dgn_comp.h run $(YACC). @echo. @echo For now, we will copy the prebuilt dgn_yacc.c from @echo $(SYS) to $(U)dgn_yacc.c, and copy the prebuilt @echo dgn_comp.h from $(SYS) to $(INCL)\dgn_comp.h @echo and use those. @echo. copy $(SYS)\dgn_yacc.c $@ >nul touch $@ copy $(SYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul touch $(INCL)\dgn_comp.h ! ENDIF $(U)dgn_$(LEX).c: $(U)dgn_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" $(LEX) $(FLEXSKEL) $(U)dgn_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) ! ELSE @echo. @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX). @echo. @echo For now, we will copy a prebuilt dgn_lex.c @echo from $(SYS) to $@ and use it. @echo. copy $(SYS)\dgn_lex.c $@ >nul touch $@ ! ENDIF obj.tag: @if not exist $(O)*.* mkdir $(OBJ) @echo directory $(OBJ) created @echo directory $(OBJ) created >$@ envchk: precomp.msg ! IF "$(TILEGAME)"=="" @echo. @echo NOTE: This build will NOT include tile support. @echo. ! ELSE @echo. @echo This build includes tile support. @echo. ! ENDIF # # SECONDARY TARGETS # # # Header files NOT distributed in ..\include # $(INCL)\tile.h: $(WSHR)\tile.h copy $(WSHR)\tile.h $@ $(INCL)\pctiles.h: $(MSYS)\pctiles.h copy $(MSYS)\pctiles.h $@ $(INCL)\pcvideo.h: $(MSYS)\pcvideo.h copy $(MSYS)\pcvideo.h $@ $(INCL)\portio.h: $(MSYS)\portio.h copy $(MSYS)\portio.h $@ # # Recover Utility # $(U)recover.exe: $(RECOVOBJS) @$(LINK) $(LFLAGSU) $(RECOVOBJS),$@,, $(CLIB) $(BCMDL); # # Tile Mapping # $(SRC)\tile.c: $(U)tilemap.exe @echo A new $@ is being created. @$(U)tilemap $(U)tilemap.exe: $(O)tilemap.o @$(LINK) $(LFLAGSU) $(O)tilemap.o,$@,, $(CLIB) $(BCMDL); $(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\tilemap.c # # Tile Utilities # # # Optional (for development) # # $(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) @$(LINK) $(LFLAGSU) << $(@B).lnk $(GIFREADERS) $(TEXT_IO) $@,,$(CLIB) $(BCMDL) << $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) @$(LINK) $(LFLAGSU) << $(@B).lnk $(PPMWRITERS) $(TEXT_IO) $@,,$(CLIB) $(BCMDL); << $(U)gif2txt2.exe: $(GIFREAD2) $(TEXT_IO2) @$(LINK) $(LFLAGSU) << $(@B).lnk $(GIFREAD2) $(TEXT_IO2) $@,,$(CLIB) $(BCMDL); << $(U)txt2ppm2.exe: $(PPMWRIT2) $(TEXT_IO2) @$(LINK) $(LFLAGSU) << $(@B).lnk $(PPMWRIT2) $(TEXT_IO2) $@,,$(CLIB) $(BCMDL); << # # Required for tile support # NetHack1.tib: $(TILEFILES) $(U)tile2bin.exe @echo Creating binary tile files (this may take some time) @$(U)tile2bin NetHackO.tib: thintile.tag $(TILEFILES2) $(U)til2bin2.exe @echo Creating overview binary tile files (this may take some time) @$(U)til2bin2 thintile.tag: $(U)thintile.exe $(TILEFILES) $(U)thintile @echo thintiles created >thintile.tag $(U)tile2bin.exe: $(O)tile2bin.o $(TEXT_IO) @echo Linking $@... $(LINK) $(LFLAGSU) @&&! $(O)tile2bin.o+ $(O)stubvid.o $(O)objects.o $(O)monst.o $(O)decl.o + $(O)drawing.o $(O)tiletxt.o $(O)tiletext.o $@ $(@B) $(BCMDL); ! $(U)til2bin2.exe: $(O)til2bin2.o $(TEXT_IO2) @echo Linking $@... $(LINK) $(LFLAGSU) @&&! $(O)til2bin2.o+ $(O)stubvid.o $(O)objects.o $(O)monst.o $(O)decl.o + $(O)drawing.o $(O)tiletxt2.o $(O)tiletex2.o $@ $(@B) $(BCMDL); ! $(U)thintile.exe: $(O)thintile.o @$(LINK) $(LFLAGSU) $(O)thintile.o,$@,, $(CLIB) $(BCMDL); $(O)thintile.o: $(HACK_H) $(INCL)\tile.h $(WSHR)\thintile.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\thintile.c $(O)tile2bin.o: $(HACK_H) $(TILE_H) $(PCVIDEO_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(MSYS)\tile2bin.c $(O)til2bin2.o: $(HACK_H) $(TILE_H) $(PCVIDEO_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(CDEFINE)TILE_X=8 $(CDEFINE)OVERVIEW_FILE \ $(COBJNAM)$@ $(MSYS)\tile2bin.c # # DLB stuff # nhdat: $(U)dlb_main.exe @copy $(MSYS)\msdoshlp.txt $(DAT) @cd $(DAT) @echo data >dlb.lst @echo oracles >>dlb.lst @echo options >>dlb.lst @echo quest.dat >>dlb.lst @echo rumors >>dlb.lst @echo help >>dlb.lst @echo hh >>dlb.lst @echo cmdhelp >>dlb.lst @echo history >>dlb.lst @echo opthelp >>dlb.lst @echo wizhelp >>dlb.lst @echo dungeon >>dlb.lst @echo license >>dlb.lst @echo msdoshlp.txt >>dlb.lst @for %%N in (*.lev) do echo %%N >>dlb.lst $(U)dlb_main cvIf dlb.lst $(SRC)\nhdat @cd $(SRC) $(U)dlb_main.exe: $(DLBOBJS) @$(LINK) $(LFLAGSU) $(DLBOBJS),$@,, $(CLIB) $(BCMDL); $(O)dlb_main.o: $(U)dlb_main.c $(INCL)\config.h $(DLB_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)dlb_main.c # # Housekeeping # spotless: clean rmdir $(OBJ) if exist $(DATE_H) del $(DATE_H) if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(VIS_TAB_H) del $(VIS_TAB_H) if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(SRC)\tile.c del $(SRC)\tile.c if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\dungeon del $(DAT)\dungeon if exist $(DAT)\dungeon.pdf del $(DAT)\dungeon.pdf if exist $(DAT)\options del $(DAT)\options if exist $(DAT)\oracles del $(DAT)\oracles if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\quest.dat del $(DAT)\quest.dat if exist $(DAT)\*.lev del $(DAT)\*.lev if exist $(DAT)\sp_lev.tag del $(DAT)\sp_lev.tag if exist $(SRC)\monstr.c del $(SRC)\monstr.c if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(SRC)\$(PLANAR_TIB) del $(SRC)\$(PLANAR_TIB) if exist $(SRC)\$(OVERVIEW_TIB) del $(SRC)\$(OVERVIEW_TIB) if exist $(U)recover.exe del $(U)recover.exe clean: if exist $(O)*.o del $(O)*.o if exist $(O)*.0 del $(O)*.0 if exist $(O)*.1 del $(O)*.1 if exist $(O)*.2 del $(O)*.2 if exist $(O)*.3 del $(O)*.3 if exist $(O)*.b del $(O)*.b if exist $(U)utility.tag del $(U)utility.tag if exist $(U)makedefs.exe del $(U)makedefs.exe if exist $(U)lev_comp.exe del $(U)lev_comp.exe if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe if exist $(U)dlb_main.exe del $(U)dlb_main.exe if exist $(SRC)\*.lnk del $(SRC)\*.lnk if exist $(SRC)\*.map del $(SRC)\*.map if exist $(SRC)\*$(CPCHEXT) del $(SRC)\*$(CPCHEXT) if exist $(SRC)\*.cfg del $(SRC)\*.cfg if exist $(DAT)\dlb.lst del $(DAT)\dlb.lst pch.c: $(HACK_H) @echo ^#include "hack.h" > $@ @echo main(int argc, char *argv[]) >> $@ @echo { >> $@ @echo } >> $@ @echo. >> $@ # # OTHER DEPENDENCIES # # # Precompiled Header dependencies # (We need to force the generation of these at the beginning) # PHO$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .O files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGCO) >> $(VROOMMCFG) @$(CC) $(FLAGCO) pch.c PH0$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .0 files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGC0) >> $(VROOMMCFG) @$(CC) $(FLAGC0) pch.c PH1$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .1 files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGC1) >> $(VROOMMCFG) @$(CC) $(FLAGC1) pch.c PH2$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .2 files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGC2) >> $(VROOMMCFG) @$(CC) $(FLAGC2) pch.c PH3$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .3 files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGC3) >> $(VROOMMCFG) @$(CC) $(FLAGC3) pch.c PHB$(CPCHEXT): $(HACK_H) pch.c @echo Generating new precompiled header for .B files @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGCB) >> $(VROOMMCFG) @$(CC) $(FLAGCB) pch.c # Overlay initialization routines used by pcmain() at startup to # determine EMS/XMS memory usage. # Comment out the following line if you don't want Borland C++ to check for # extended memory. RECOGNIZE_XMS = $(CDEFINE)RECOGNIZE_XMS $(O)ovlinit.o: $(MSYS)\ovlinit.c $(HACK_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(RECOGNIZE_XMS) $(COBJNAM)$@ $(MSYS)\ovlinit.c # # dat dependencies # $(DAT)\data: $(U)utility.tag $(DATABASE) $(U)makedefs -d $(DAT)\rumors: $(U)utility.tag $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(U)utility.tag $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(U)utility.tag $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(U)utility.tag $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgn_comp dungeon.pdf cd $(SRC) # # Util Dependencies. # $(O)panic.o: $(U)panic.c $(CONFIG_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)panic.c $(O)recover.o: $(CONFIG_H) $(U)recover.c @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(U)recover.c # # from win\share # $(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(CDEFINE)TILETEXT $(COBJNAM)$@ $(WSHR)\tilemap.c $(O)tiletxt2.o: $(WSHR)\tilemap.c $(HACK_H) @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(CDEFINE)TILETEXT \ $(CDEFINE)TILE_X=8 $(COBJNAM)$@ $(WSHR)\tilemap.c $(O)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\gifread.c $(O)gifread2.o: $(WSHR)\gifread.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(CDEFINE)TILE_X=8 $(WSHR)\gifread.c $(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\ppmwrite.c $(O)ppmwrit2.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(CDEFINE)TILE_X=8 $(WSHR)\ppmwrite.c $(O)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(COBJNAM)$@ $(WSHR)\tiletext.c $(O)tiletex2.o: $(WSHR)\tiletext.c $(CONFIG_H) $(INCL)\tile.h @echo $(BCOPTS1) > $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSU) $(CDEFINE)TILE_X=8 $(COBJNAM)$@ $(WSHR)\tiletext.c # # from win\tty # $(O)getline.1: $(PCH1) $(WTTY)\getline.c $(HACK_H) $(WINTTY_H) $(FUNC_TAB_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\getline.c $(O)getline.2: $(PCH2) $(WTTY)\getline.c $(HACK_H) $(WINTTY_H) $(FUNC_TAB_H) @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $(WTTY)\getline.c $(O)termcap.0: $(PCH0) $(WTTY)\termcap.c $(HACK_H) $(WINTTY_H) $(TERMCAP_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(WTTY)\termcap.c $(O)termcap.1: $(PCH1) $(WTTY)\termcap.c $(HACK_H) $(WINTTY_H) $(TERMCAP_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\termcap.c $(O)termcap.B: $(PCHB) $(WTTY)\termcap.c $(HACK_H) $(WINTTY_H) $(TERMCAP_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(WTTY)\termcap.c $(O)topl.1: $(PCH1) $(WTTY)\topl.c $(HACK_H) $(TERMCAP_H) $(WINTTY_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(WTTY)\topl.c $(O)topl.2: $(PCH2) $(WTTY)\topl.c $(HACK_H) $(TERMCAP_H) $(WINTTY_H) @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $(WTTY)\topl.c $(O)topl.B: $(PCHB) $(WTTY)\topl.c $(HACK_H) $(TERMCAP_H) $(WINTTY_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(WTTY)\topl.c $(O)wintty.o: $(PCHO) $(CONFIG_H) $(WTTY)\wintty.c $(PATCHLEVEL_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $(WTTY)\wintty.c # # from sys\share # $(O)pcmain.0: $(PCH0) $(HACK_H) $(SYS)\pcmain.c @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(SYS)\pcmain.c $(O)pcmain.1: $(PCH1) $(HACK_H) $(SYS)\pcmain.c @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(SYS)\pcmain.c $(O)pcmain.B: $(PCHB) $(HACK_H) $(SYS)\pcmain.c @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(SYS)\pcmain.c $(O)pcunix.B: $(PCHB) $(SYS)\pcunix.c $(HACK_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(SYS)\pcunix.c $(O)tty.o: $(HACK_H) $(WINTTY_H) $(SYS)\pctty.c @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SYS)\pctty.c $(O)sys.o: $(HACK_H) $(SYS)\pcsys.c @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SYS)\pcsys.c $(O)random.o: $(PCHO) $(HACK_H) $(SYS)\random.c @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $(SYS)\random.c # # from sys\msdos # $(O)msdos.0: $(MSYS)\msdos.c $(HACK_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COVL0) $(COBJNAM)$@ $(MSYS)\msdos.c $(O)msdos.B: $(MSYS)\msdos.c $(HACK_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COVLB) $(COBJNAM)$@ $(MSYS)\msdos.c $(O)pctiles.0: $(PCH0) $(MSYS)\pctiles.c $(HACK_H) $(TILE_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\pctiles.c $(O)pctiles.B: $(PCHB) $(MSYS)\pctiles.c $(HACK_H) $(TILE_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\pctiles.c $(O)sound.o: $(PCH0) $(MSYS)\sound.c $(HACK_H) $(INCL)\portio.h @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $(MSYS)\sound.c $(O)pckeys.o: $(PCHO) $(MSYS)\pckeys.c $(HACK_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(COBJNAM)$@ $(MSYS)\pckeys.c $(O)stubvid.o : $(MSYS)\video.c $(HACK_H) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUO) >> $(VROOMMCFG) $(CC) $(FLAGUO) $(CDEFINE)STUBVIDEO $(COBJNAM)$@ $(MSYS)\video.c $(O)video.0: $(PCH0) $(MSYS)\video.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\video.c $(O)video.1: $(PCH1) $(MSYS)\video.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(MSYS)\video.c $(O)video.B: $(PCHB) $(MSYS)\video.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\video.c $(O)vidtxt.0: $(MSYS)\vidtxt.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COVL0) $(COBJNAM)$@ $(MSYS)\vidtxt.c $(O)vidtxt.B: $(MSYS)\vidtxt.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COVLB) $(COBJNAM)$@ $(MSYS)\vidtxt.c $(O)vidvga.0: $(PCH0) $(MSYS)\vidvga.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_0" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU0) >> $(VROOMMCFG) $(CC) $(FLAGU0) $(COBJNAM)$@ $(MSYS)\vidvga.c $(O)vidvga.1: $(PCH1) $(MSYS)\vidvga.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_1" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU1) >> $(VROOMMCFG) $(CC) $(FLAGU1) $(COBJNAM)$@ $(MSYS)\vidvga.c $(O)vidvga.2: $(PCH2) $(MSYS)\vidvga.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_2" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGU2) >> $(VROOMMCFG) $(CC) $(FLAGU2) $(COBJNAM)$@ $(MSYS)\vidvga.c $(O)vidvga.B: $(PCHB) $(MSYS)\vidvga.c $(HACK_H) $(WINTTY_H) $(PCVIDEO_H) \ $(TILE_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) $(CFLAGUB) >> $(VROOMMCFG) $(CC) $(FLAGUB) $(COBJNAM)$@ $(MSYS)\vidvga.c # # from src # $(O)alloc.o: $(SRC)\alloc.c $(CONFIG_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\alloc.c $(O)ball.o: $(PCHO) $(SRC)\ball.c $(HACK_H) $(O)bones.o: $(PCHO) $(SRC)\bones.c $(HACK_H) $(LEV_H) $(O)decl.o: $(PCHO) $(SRC)\decl.c $(HACK_H) $(QUEST_H) $(O)detect.o: $(PCHO) $(SRC)\detect.c $(HACK_H) $(ARTIFACT_H) $(O)dig.o: $(PCHO) $(SRC)\dig.c $(HACK_H) $(EDOG_H) # check dep $(O)display.o: $(PCHO) $(SRC)\display.c $(HACK_H) $(O)dlb.o: $(SRC)\dlb.c $(DLB_H) $(HACK_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\dlb.c $(O)dokick.o: $(PCHO) $(SRC)\dokick.c $(HACK_H) $(ESHK_H) $(O)dothrow.o: $(PCHO) $(SRC)\dothrow.c $(HACK_H) $(O)drawing.o: $(SRC)\drawing.c $(HACK_H) $(TERMCAP_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\drawing.c $(O)end.o: $(SRC)\end.c $(HACK_H) $(ESHK_H) $(DLB_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\end.c $(O)exper.o: $(PCHO) $(SRC)\exper.c $(HACK_H) $(O)extralev.o: $(PCHO) $(SRC)\extralev.c $(HACK_H) $(O)files.o: $(PCHO) $(SRC)\files.c $(HACK_H) $(DLB_H) $(O)fountain.o: $(PCHO) $(SRC)\fountain.c $(HACK_H) $(O)mapglyph.o: $(PCHO) $(SRC)\mapglyph.c $(HACK_H) $(O)minion.o: $(PCHO) $(SRC)\minion.c $(HACK_H) $(EMIN_H) $(EPRI_H) $(O)mklev.o: $(PCHO) $(SRC)\mklev.c $(HACK_H) $(O)mkmap.o: $(PCHO) $(SRC)\mkmap.c $(HACK_H) $(SP_LEV_H) $(O)mkmaze.o: $(PCHO) $(SRC)\mkmaze.c $(HACK_H) $(SP_LEV_H) $(LEV_H) $(O)monst.o: $(SRC)\monst.c $(CONFIG_H) $(PERMONST_H) $(MONSYM_H) \ $(ESHK_H) $(EPRI_H) $(COLOR_H) $(ALIGN_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\monst.c $(O)monstr.o: $(SRC)\monstr.c $(CONFIG_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\monstr.c $(O)mplayer.o: $(PCHO) $(SRC)\mplayer.c $(HACK_H) $(O)muse.o: $(PCHO) $(SRC)\muse.c $(HACK_H) $(O)music.o: $(PCHO) $(SRC)\music.c $(HACK_H) $(O)o_init.o: $(PCHO) $(SRC)\o_init.c $(HACK_H) $(LEV_H) $(O)objects.o: $(SRC)\objects.c $(CONFIG_H) $(OBJ_H) $(OBJCLASS_H) \ $(PROP_H) $(COLOR_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\objects.c $(O)options.o: $(SRC)\options.c $(HACK_H) $(TERMCAP_H) $(OBJCLASS_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\options.c $(O)pager.o: $(SRC)\pager.c $(HACK_H) $(DLB_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGNO) $(COBJNAM)$@ $(SRC)\pager.c $(O)pickup.o: $(PCHO) $(SRC)\pickup.c $(HACK_H) $(O)pray.o: $(PCHO) $(SRC)\pray.c $(HACK_H) $(EPRI_H) $(O)quest.o: $(PCHO) $(SRC)\quest.c $(HACK_H) $(QUEST_H) $(QTEXT_H) $(O)questpgr.o: $(PCHO) $(SRC)\questpgr.c $(HACK_H) $(QTEXT_H) $(DLB_H) $(O)rect.o: $(PCHO) $(SRC)\rect.c $(HACK_H) $(O)region.o: $(PCHO) $(SRC)\region.c $(HACK_H) $(O)restore.o: $(PCHO) $(SRC)\restore.c $(HACK_H) $(LEV_H) $(TERMCAP_H) \ $(QUEST_H) $(O)rip.o: $(PCHO) $(SRC)\rip.c $(HACK_H) $(O)role.o: $(PCHO) $(SRC)\role.c $(HACK_H) $(O)rumors.o: $(PCHO) $(SRC)\rumors.c $(HACK_H) $(DLB_H) $(O)save.o: $(PCHO) $(SRC)\save.c $(HACK_H) $(LEV_H) $(QUEST_H) $(O)sit.o: $(PCHO) $(SRC)\sit.c $(HACK_H) $(ARTIFACT_H) $(O)steed.o: $(PCHO) $(SRC)\steed.c $(HACK_H) $(O)sp_lev.o: $(PCHO) $(SRC)\sp_lev.c $(HACK_H) $(SP_LEV_H) $(DLB_H) $(O)spell.o: $(PCHO) $(SRC)\spell.c $(HACK_H) $(O)teleport.o: $(PCHO) $(SRC)\teleport.c $(HACK_H) # check dep $(O)tile.o: $(PCHO) $(SRC)\tile.c $(HACK_H) $(O)topten.o: $(PCHO) $(SRC)\topten.c $(HACK_H) $(DLB_H) $(PATCHLEVEL_H) $(O)u_init.o: $(PCHO) $(SRC)\u_init.c $(HACK_H) $(O)uhitm.o: $(PCHO) $(SRC)\uhitm.c $(HACK_H) $(O)version.o: $(PCHO) $(SRC)\version.c $(HACK_H) $(PATCHLEVEL_H) $(O)vision.o: $(PCHO) $(SRC)\vision.c $(HACK_H) $(VIS_TAB_H) $(O)vis_tab.o: $(SRC)\vis_tab.c $(HACK_H) $(VIS_TAB_H) @type schema$(SCHEMA).bc | find "$(@B)_o" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\vis_tab.c $(O)wield.o: $(PCHO) $(SRC)\wield.c $(HACK_H) $(O)windows.o: $(PCHO) $(SRC)\windows.c $(HACK_H) $(WINTTY_H) $(O)worm.o: $(PCHO) $(SRC)\worm.c $(HACK_H) $(LEV_H) $(O)worn.o: $(PCHO) $(SRC)\worn.c $(HACK_H) $(O)write.o: $(PCHO) $(SRC)\write.c $(HACK_H) # # Overlays # # OVL0 # $(O)allmain.0: $(PCH0) $(SRC)\allmain.c $(HACK_H) $(O)apply.0: $(PCH0) $(SRC)\apply.c $(HACK_H) $(EDOG_H) $(O)artifact.0: $(PCH0) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H) $(O)attrib.0: $(PCH0) $(SRC)\attrib.c $(HACK_H) $(O)botl.0: $(PCH0) $(SRC)\botl.c $(HACK_H) $(O)cmd.0: $(PCH0) $(SRC)\cmd.c $(HACK_H) $(FUNC_TAB_H) $(O)dbridge.0: $(PCH0) $(SRC)\dbridge.c $(HACK_H) $(O)do.0: $(PCH0) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)do_name.0: $(PCH0) $(SRC)\do_name.c $(HACK_H) $(O)do_wear.0: $(PCH0) $(SRC)\do_wear.c $(HACK_H) $(O)dogmove.0: $(PCH0) $(SRC)\dogmove.c $(HACK_H) $(MFNDPOS_H) $(EDOG_H) $(O)dungeon.0: $(PCH0) $(SRC)\dungeon.c $(HACK_H) $(ALIGN_H) $(DGN_FILE_H) \ $(DLB_H) $(O)eat.0: $(PCH0) $(SRC)\eat.c $(HACK_H) $(O)engrave.0: $(PCH0) $(SRC)\engrave.c $(HACK_H) $(LEV_H) $(O)explode.0: $(PCH0) $(SRC)\explode.c $(HACK_H) $(O)hacklib.0: $(PCH0) $(SRC)\hacklib.c $(HACK_H) $(O)invent.0: $(PCH0) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)lock.0: $(PCH0) $(SRC)\lock.c $(HACK_H) $(O)mail.0: $(PCH0) $(SRC)\mail.c $(HACK_H) $(MAIL_H) $(DATE_H) $(O)makemon.0: $(PCH0) $(SRC)\makemon.c $(HACK_H) $(EPRI_H) $(EMIN_H) $(O)mcastu.0: $(PCH0) $(SRC)\mcastu.c $(HACK_H) $(O)mhitm.0: $(PCH0) $(SRC)\mhitm.c $(HACK_H) $(ARTIFACT_H) $(EDOG_H) $(O)mhitu.0: $(PCH0) $(SRC)\mhitu.c $(HACK_H) $(ARTIFACT_H) $(EDOG_H) $(O)mkobj.0: $(PCH0) $(SRC)\mkobj.c $(HACK_H) $(ARTIFACT_H) $(PROP_H) $(O)mkroom.0: $(PCH0) $(SRC)\mkroom.c $(HACK_H) $(O)mon.0: $(PCH0) $(SRC)\mon.c $(HACK_H) $(MFNDPOS_H) $(EDOG_H) $(O)mondata.0: $(PCH0) $(SRC)\mondata.c $(HACK_H) $(ESHK_H) $(EPRI_H) $(O)monmove.0: $(PCH0) $(SRC)\monmove.c $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H) $(O)mthrowu.0: $(PCH0) $(SRC)\mthrowu.c $(HACK_H) $(O)objnam.0: $(PCH0) $(SRC)\objnam.c $(HACK_H) $(O)polyself.0: $(PCH0) $(SRC)\polyself.c $(HACK_H) $(O)priest.0: $(PCH0) $(SRC)\priest.c $(HACK_H) $(MFNDPOS_H) $(ESHK_H) \ $(EPRI_H) $(EMIN_H) $(O)rnd.0: $(PCH0) $(SRC)\rnd.c $(HACK_H) $(O)shk.0: $(PCH0) $(SRC)\shk.c $(HACK_H) $(ESHK_H) $(O)shknam.0: $(PCH0) $(SRC)\shknam.c $(HACK_H) $(ESHK_H) $(O)sounds.0: $(PCH0) $(SRC)\sounds.c $(HACK_H) $(EDOG_H) $(O)steal.0: $(PCH0) $(SRC)\steal.c $(HACK_H) $(O)timeout.0: $(PCH0) $(SRC)\timeout.c $(HACK_H) $(LEV_H) $(O)track.0: $(PCH0) $(SRC)\track.c $(HACK_H) $(O)trap.0: $(PCH0) $(SRC)\trap.c $(HACK_H) $(O)vault.0: $(PCH0) $(SRC)\vault.c $(HACK_H) $(VAULT_H) $(O)weapon.0: $(PCH0) $(SRC)\weapon.c $(HACK_H) $(O)were.0: $(PCH0) $(SRC)\were.c $(HACK_H) $(O)wizard.0: $(PCH0) $(SRC)\wizard.c $(HACK_H) $(QTEXT_H) $(O)zap.0: $(PCH0) $(SRC)\zap.c $(HACK_H) # # OVL1 # $(O)allmain.1: $(PCH1) $(SRC)\allmain.c $(HACK_H) $(O)apply.1: $(PCH1) $(SRC)\apply.c $(HACK_H) $(EDOG_H) $(O)artifact.1: $(PCH1) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H) $(O)attrib.1: $(PCH1) $(SRC)\attrib.c $(HACK_H) $(O)botl.1: $(PCH1) $(SRC)\botl.c $(HACK_H) $(O)cmd.1: $(PCH1) $(SRC)\cmd.c $(HACK_H) $(FUNC_TAB_H) $(O)dbridge.1: $(PCH1) $(SRC)\dbridge.c $(HACK_H) $(O)do.1: $(PCH1) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)do_wear.1: $(PCH1) $(SRC)\do_wear.c $(HACK_H) $(O)dog.1: $(PCH1) $(SRC)\dog.c $(HACK_H) $(EDOG_H) $(O)dungeon.1: $(PCH1) $(SRC)\dungeon.c $(HACK_H) $(ALIGN_H) $(DGN_FILE_H) $(DLB_H) $(O)eat.1: $(PCH1) $(SRC)\eat.c $(HACK_H) $(O)engrave.1: $(PCH1) $(SRC)\engrave.c $(HACK_H) $(LEV_H) $(O)explode.1: $(PCH1) $(SRC)\explode.c $(HACK_H) $(O)hack.1: $(PCH1) $(SRC)\hack.c $(HACK_H) $(O)hacklib.1: $(PCH1) $(SRC)\hacklib.c $(HACK_H) $(O)invent.1: $(PCH1) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)makemon.1: $(PCH1) $(SRC)\makemon.c $(HACK_H) $(EPRI_H) $(EMIN_H) $(O)mhitu.1: $(PCH1) $(SRC)\mhitu.c $(HACK_H) $(ARTIFACT_H) $(EDOG_H) $(O)mkobj.1: $(PCH1) $(SRC)\mkobj.c $(HACK_H) $(ARTIFACT_H) $(PROP_H) $(O)mon.1: $(PCH1) $(SRC)\mon.c $(HACK_H) $(MFNDPOS_H) $(EDOG_H) $(O)mondata.1: $(PCH1) $(SRC)\mondata.c $(HACK_H) $(ESHK_H) $(EPRI_H) $(O)monmove.1: $(PCH1) $(SRC)\monmove.c $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H) $(O)mthrowu.1: $(PCH1) $(SRC)\mthrowu.c $(HACK_H) $(O)objnam.1: $(PCH1) $(SRC)\objnam.c $(HACK_H) $(O)polyself.1: $(PCH1) $(SRC)\polyself.c $(HACK_H) $(O)rnd.1: $(PCH1) $(SRC)\rnd.c $(HACK_H) $(O)shk.1: $(PCH1) $(SRC)\shk.c $(HACK_H) $(ESHK_H) $(O)steal.1: $(PCH1) $(SRC)\steal.c $(HACK_H) $(O)timeout.1: $(PCH1) $(SRC)\timeout.c $(HACK_H) $(LEV_H) $(O)track.1: $(PCH1) $(SRC)\track.c $(HACK_H) $(O)trap.1: $(PCH1) $(SRC)\trap.c $(HACK_H) $(O)weapon.1: $(PCH1) $(SRC)\weapon.c $(HACK_H) $(O)zap.1: $(PCH1) $(SRC)\zap.c $(HACK_H) # # OVL2 # $(O)attrib.2: $(PCH2) $(SRC)\attrib.c $(HACK_H) $(O)do.2: $(PCH2) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)do_name.2: $(PCH2) $(SRC)\do_name.c $(HACK_H) $(O)do_wear.2: $(PCH2) $(SRC)\do_wear.c $(HACK_H) $(O)dog.2: $(PCH2) $(SRC)\dog.c $(HACK_H) $(EDOG_H) $(O)engrave.2: $(PCH2) $(SRC)\engrave.c $(HACK_H) $(LEV_H) $(O)hack.2: $(PCH2) $(SRC)\hack.c $(HACK_H) $(O)hacklib.2: $(PCH2) $(SRC)\hacklib.c $(HACK_H) $(O)invent.2: $(PCH2) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)makemon.2: $(PCH2) $(SRC)\makemon.c $(HACK_H) $(EPRI_H) $(EMIN_H) $(O)mon.2: $(PCH2) $(SRC)\mon.c $(HACK_H) $(MFNDPOS_H) $(EDOG_H) $(O)mondata.2: $(PCH2) $(SRC)\mondata.c $(HACK_H) $(ESHK_H) $(EPRI_H) $(O)monmove.2: $(PCH2) $(SRC)\monmove.c $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H) $(O)shk.2: $(PCH2) $(SRC)\shk.c $(HACK_H) $(ESHK_H) $(O)trap.2: $(PCH2) $(SRC)\trap.c $(HACK_H) $(O)zap.2: $(PCH2) $(SRC)\zap.c $(HACK_H) # # OVL3 # $(O)do.3: $(PCH3) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)hack.3: $(PCH3) $(SRC)\hack.c $(HACK_H) $(O)invent.3: $(PCH3) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)light.3: $(PCH3) $(SRC)\light.c $(HACK_H) $(O)shk.3: $(PCH3) $(SRC)\shk.c $(HACK_H) $(ESHK_H) $(O)trap.3: $(PCH3) $(SRC)\trap.c $(HACK_H) $(O)zap.3: $(PCH3) $(SRC)\zap.c $(HACK_H) # # OVLB # $(O)allmain.B: $(PCHB) $(SRC)\allmain.c $(HACK_H) $(O)apply.B: $(PCHB) $(SRC)\apply.c $(HACK_H) $(EDOG_H) $(O)artifact.B: $(PCHB) $(SRC)\artifact.c $(HACK_H) $(ARTIFACT_H) $(ARTILIST_H) $(O)attrib.B: $(PCHB) $(SRC)\attrib.c $(HACK_H) $(O)botl.B: $(PCHB) $(SRC)\botl.c $(HACK_H) $(O)cmd.B: $(PCHB) $(SRC)\cmd.c $(HACK_H) $(FUNC_TAB_H) $(O)dbridge.B: $(PCHB) $(SRC)\dbridge.c $(HACK_H) $(O)do.B: $(PCHB) $(SRC)\do.c $(HACK_H) $(LEV_H) $(O)do_name.B: $(PCHB) $(SRC)\do_name.c $(HACK_H) $(O)do_wear.B: $(PCHB) $(SRC)\do_wear.c $(HACK_H) $(O)dog.B: $(PCHB) $(SRC)\dog.c $(HACK_H) $(EDOG_H) $(O)dogmove.B: $(PCHB) $(SRC)\dogmove.c $(HACK_H) $(MFNDPOS_H) $(EDOG_H) $(O)eat.B: $(PCHB) $(SRC)\eat.c $(HACK_H) $(O)engrave.B: $(PCHB) $(SRC)\engrave.c $(HACK_H) $(LEV_H) $(O)hack.B: $(PCHB) $(SRC)\hack.c $(HACK_H) $(O)hacklib.B: $(PCHB) $(SRC)\hacklib.c $(HACK_H) $(O)invent.B: $(PCHB) $(SRC)\invent.c $(HACK_H) $(ARTIFACT_H) $(O)lock.B: $(PCHB) $(SRC)\lock.c $(HACK_H) $(O)mail.B: $(PCHB) $(SRC)\mail.c $(HACK_H) $(MAIL_H) $(DATE_H) $(O)makemon.B: $(PCHB) $(SRC)\makemon.c $(HACK_H) $(EPRI_H) $(EMIN_H) $(O)mcastu.B: $(PCHB) $(SRC)\mcastu.c $(HACK_H) $(O)mhitm.B: $(PCHB) $(SRC)\mhitm.c $(HACK_H) $(ARTIFACT_H) $(EDOG_H) $(O)mhitu.B: $(PCHB) $(SRC)\mhitu.c $(HACK_H) $(ARTIFACT_H) $(EDOG_H) $(O)mkobj.B: $(PCHB) $(SRC)\mkobj.c $(HACK_H) $(ARTIFACT_H) $(PROP_H) $(O)mkroom.B: $(PCHB) $(SRC)\mkroom.c $(HACK_H) $(O)mon.B: $(PCHB) $(SRC)\mon.c $(HACK_H) $(MFNDPOS_H) $(EDOG_H) $(O)mondata.B: $(PCHB) $(SRC)\mondata.c $(HACK_H) $(ESHK_H) $(EPRI_H) $(O)monmove.B: $(PCHB) $(SRC)\monmove.c $(HACK_H) $(MFNDPOS_H) $(ARTIFACT_H) $(O)mthrowu.B: $(PCHB) $(SRC)\mthrowu.c $(HACK_H) $(O)objnam.B: $(PCHB) $(SRC)\objnam.c $(HACK_H) $(O)pline.B: $(SRC)\pline.c $(HACK_H) $(EPRI_H) @type schema$(SCHEMA).bc | find "$(@B)_b" > $(VROOMMCFG) @echo $(BCOPTS1) >> $(VROOMMCFG) @echo $(BCOPTS2) >> $(VROOMMCFG) $(CC) $(CFLAGSN) $(COBJNAM)$@ $(SRC)\pline.c $(O)polyself.B: $(PCHB) $(SRC)\polyself.c $(HACK_H) $(O)potion.B: $(PCHB) $(SRC)\potion.c $(HACK_H) $(O)priest.B: $(PCHB) $(SRC)\priest.c $(HACK_H) $(MFNDPOS_H) $(ESHK_H) \ $(EPRI_H) $(EMIN_H) $(O)read.B: $(PCHB) $(SRC)\read.c $(HACK_H) $(O)rnd.B: $(PCHB) $(SRC)\rnd.c $(HACK_H) $(O)shk.B: $(PCHB) $(SRC)\shk.c $(HACK_H) $(ESHK_H) $(O)shknam.B: $(PCHB) $(SRC)\shknam.c $(HACK_H) $(ESHK_H) $(O)sounds.B: $(PCHB) $(SRC)\sounds.c $(HACK_H) $(EDOG_H) $(O)steal.B: $(PCHB) $(SRC)\steal.c $(HACK_H) $(O)timeout.B: $(PCHB) $(SRC)\timeout.c $(HACK_H) $(LEV_H) $(O)track.B: $(PCHB) $(SRC)\track.c $(HACK_H) $(O)trap.B: $(PCHB) $(SRC)\trap.c $(HACK_H) $(O)vault.B: $(PCHB) $(SRC)\vault.c $(HACK_H) $(VAULT_H) $(O)weapon.B: $(PCHB) $(SRC)\weapon.c $(HACK_H) $(O)were.B: $(PCHB) $(SRC)\were.c $(HACK_H) $(O)wizard.B: $(PCHB) $(SRC)\wizard.c $(HACK_H) $(QTEXT_H) $(O)zap.B: $(PCHB) $(SRC)\zap.c $(HACK_H) # end of file nethack-3.4.3/sys/msdos/Makefile.GCC0100644000000000000000000012451007764735041015653 0ustar rootroot# SCCS Id: @(#)Makefile.GCC 3.4 $Date: 2003/06/15 15:56:45 $ # Copyright (c) NetHack PC Development Team 1996-2003. # PC NetHack 3.4 Makefile for djgpp V2 # # Gnu gcc compiler for msdos (djgpp) # Requires Gnu Make utility (V3.79.1 or greater) supplied with djgpp # # For questions or comments: devteam@nethack.org # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc # .l lex # # Note that flex (lex) and bison (yacc) are included with the # djgpp distribution and work quite well. This makefile assumes # you have them installed correctly. # Game Installation Variables # NOTE: Make sure GAMEDIR exists before make is started. GAME = nethack # The GNU Make has a problem if you include a drive spec below (unfortunately). GAMEDIR =../binary # # Directories, gcc likes unix style directory specs # OBJ = o DAT = ../dat DOC = ../doc INCL = ../include MSYS = ../sys/msdos SRC = ../src SSHR = ../sys/share UTIL = ../util WIN = ../win/tty WSHR = ../win/share # # Executables. CC = gcc LINK = gcc MAKEBIN = make # # Special libraries and how to link them in. LIBS = -lpc # If TERMLIB is defined in pcconf.h, comment out the upper line and # uncomment the lower. Note that you must build the termc library # and place it in djgpp's lib directory. See termcap.zip for details TERMLIB = #TERMLIB = -ltermc LIBRARIES = $(LIBS) $(TERMLIB) # # Yacc/Lex ... if you got 'em. # # If you have yacc/lex or a work-alike set YACC_LEX to Y # YACC_LEX = Y ifeq ($(YACC_LEX),Y) DO_YACC = YACC_ACT DO_LEX = LEX_ACT endif # If YACC_LEX is Y above, set the following to values appropriate for # your tools. # YACC = bison -y LEX = flex YTABC = y_tab.c YTABH = y_tab.h #If your tool produces y.tab.c and y.tab.h DOS might require #the following instead. #YTABC = ytab~1.c #YTABH = ytab~1.h LEXYYC = lexyy.c # # Uncomment the line below if you want to store all the level files, # help files, etc. in a single library file. USE_DLB = Y # djgpp includes ls.exe and touch.exe in fil41b.zip from the v2gnu # folder so be sure to include that when downloading djgpp. Doing # so will make changing this unnecessary. LS = ls -1 # ls.exe from djgpp distribution #LS = dir /l/b # DOS command # To build a binary without any graphics # suitable for blind players, # set SUPPRESS_GRAPHICS to Y # (Note: binary will require ANSI.SYS driver or equivalent loaded) # SUPPRESS_GRAPHICS = Y SUPPRESS_GRAPHICS = #=============================================== #======= End of Modification Section =========== #=============================================== ################################################ # # # Nothing below here should have to be changed.# # # ################################################ GAMEFILE = $(GAMEDIR)/$(GAME).exe # Changing this conditional block is not recommended ifeq ($(USE_DLB),Y) DLBFLG = -DDLB else DLBFLG = endif # # Flags. # ifeq ($(SUPPRESS_GRAPHICS),Y) TERMLIB = # Build NetHack suitable for blind players # Debugging #cflags = -pg -c -I../include $(DLBFLG) -DSUPPRESS_GRAPHICS #LFLAGS = -pg cflags = -c -O -I../include $(DLBFLG) -DSUPPRESS_GRAPHICS LFLAGS = else # Debugging #cflags = -pg -c -I../include $(DLBFLG) -DUSE_TILES #LFLAGS = -pg # Normal cflags = -c -O -I../include $(DLBFLG) -DUSE_TILES LFLAGS = endif #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .tib .til .uu .c .y .l #========================================== # Rules for files in src #========================================== $(OBJ)/%.o : /%.c $(CC) $(cflags) -o$@ $< $(OBJ)/%.o : $(SRC)/%.c $(CC) $(cflags) -o$@ $< #========================================== # Rules for files in sys/share #========================================== $(OBJ)/%.o : $(SSHR)/%.c $(CC) $(cflags) -o$@ $< #========================================== # Rules for files in sys/msdos #========================================== $(OBJ)/%.o : $(MSYS)/%.c $(CC) $(cflags) -I../sys/msdos -o$@ $< #========================================== # Rules for files in util #========================================== $(OBJ)/%.o : $(UTIL)/%.c $(CC) $(cflags) -o$@ $< #========================================== # Rules for files in win/share #========================================== $(OBJ)/%.o : $(WSHR)/%.c $(CC) $(cflags) -I../win/share -o$@ $< #{$(WSHR)}.txt{$(DAT)}.txt: # copy $< $@ #========================================== # Rules for files in win/tty #========================================== $(OBJ)/%.o : $(TTY)/%.c $(CC) $(cflags) -o$@ $< #========================================== #================ MACROS ================== #========================================== # This section creates shorthand macros for many objects # referenced later on in the Makefile. # # # Shorten up the location for some files # O = $(OBJ)/ U = $(UTIL)/ #========================================== # Utility Objects. #========================================== VGAOBJ = $(O)vidvga.o MAKESRC = makedefs.c SPLEVSRC = lev_yacc.c lev_$(LEX).c lev_main.c panic.c DGNCOMPSRC = dgn_yacc.c dgn_$(LEX).c dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS = $(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o $(O)alloc.o \ $(O)monst.o $(O)objects.o $(O)panic.o \ $(O)drawing.o $(O)decl.o $(O)stubvid.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o $(O)alloc.o \ $(O)panic.o RECOVOBJS = $(O)recover.o #========================================== # Tile related object files. #========================================== ifeq ($(SUPPRESS_GRAPHICS),Y) TILOBJ = TEXTIO = TEXTIO2 = PLANAR_TIB = OVERVIEW_TIB = TILEUTIL = TILEFILES = TILEFILES2 = GIFREADERS = GIFREAD2 = PPMWRITERS = PPMWRIT2 = else TILOBJ = $(O)tile.o $(O)pctiles.o $(VGAOBJ) TEXTIO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o $(O)decl.o $(O)monst.o \ $(O)objects.o $(O)stubvid.o TEXTIO2 = $(O)tiletex2.o $(O)tiletxt2.o $(O)drawing.o $(O)decl.o $(O)monst.o \ $(O)objects.o $(O)stubvid.o PLANAR_TIB = $(DAT)/NetHack1.tib OVERVIEW_TIB = $(DAT)/NetHacko.tib TILEUTIL = $(TILOBJ) $(U)tile2bin.exe $(U)til2bin2.exe $(PLANAR_TIB) $(OVERVIEW_TIB) TILEFILES = $(WSHR)/monsters.txt $(WSHR)/objects.txt $(WSHR)/other.txt TILEFILES2 = $(WSHR)/monthin.txt $(WSHR)/objthin.txt $(WSHR)/oththin.txt GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o GIFREAD2 = $(O)gifread2.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o PPMWRIT2 = $(O)ppmwrit2.o $(O)alloc.o $(O)panic.o endif DLBOBJ = $(O)dlb.o # Object files for the game itself. VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o $(O)attrib.o VOBJ02 = $(O)ball.o $(O)bones.o $(O)botl.o $(O)cmd.o $(O)dbridge.o VOBJ03 = $(O)decl.o $(O)detect.o $(O)display.o $(O)do.o $(O)do_name.o VOBJ04 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o $(O)dothrow.o VOBJ05 = $(O)drawing.o $(O)dungeon.o $(O)eat.o $(O)end.o $(O)engrave.o VOBJ06 = $(O)exper.o $(O)explode.o $(O)extralev.o $(O)files.o $(O)fountain.o VOBJ07 = $(O)getline.o $(O)hack.o $(O)hacklib.o $(O)invent.o $(O)lock.o VOBJ08 = $(O)mail.o $(O)main.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o $(O)mhitm.o VOBJ09 = $(O)mhitu.o $(O)minion.o $(O)mkmap.o $(O)mklev.o $(O)mkmaze.o VOBJ10 = $(O)mkobj.o $(O)mkroom.o $(O)mon.o $(O)mondata.o $(O)monmove.o VOBJ11 = $(O)monst.o $(O)monstr.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o VOBJ12 = $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o $(O)options.o VOBJ13 = $(O)pickup.o $(O)pline.o $(O)polyself.o $(O)potion.o $(O)quest.o VOBJ14 = $(O)questpgr.o $(O)pager.o $(O)pray.o $(O)priest.o $(O)read.o VOBJ15 = $(O)rect.o $(O)restore.o $(O)rip.o $(O)rnd.o $(O)role.o VOBJ16 = $(O)rumors.o $(O)save.o $(O)shk.o $(O)shknam.o $(O)sit.o VOBJ17 = $(O)sounds.o $(O)sp_lev.o $(O)spell.o $(O)steal.o $(O)steed.o VOBJ18 = $(O)termcap.o $(O)timeout.o $(O)topl.o $(O)topten.o $(O)track.o VOBJ19 = $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)vault.o $(O)vision.o VOBJ20 = $(O)vis_tab.o $(O)weapon.o $(O)were.o $(O)wield.o $(O)windows.o VOBJ21 = $(O)wintty.o $(O)wizard.o $(O)worm.o $(O)worn.o $(O)write.o VOBJ22 = $(O)zap.o $(O)light.o $(O)dlb.o $(O)dig.o $(O)teleport.o VOBJ23 = $(O)region.o SOBJ = $(O)msdos.o $(O)sound.o $(O)sys.o $(O)tty.o $(O)unix.o \ $(O)video.o $(O)vidtxt.o $(O)pckeys.o VVOBJ = $(O)version.o VOBJ = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) ALLOBJ = $(VOBJ) $(SOBJ) $(TILOBJ) $(VVOBJ) #========================================== # Header file macros #========================================== PATCHLEV_H = $(INCL)/patchlev.h DGN_FILE_H = $(INCL)/align.h $(INCL)/dgn_file.h DUNGEON_H = $(INCL)/align.h $(INCL)/dungeon.h EMIN_H = $(DUNGEON_H) $(INCL)/emin.h EPRI_H = $(DUNGEON_H) $(INCL)/align.h $(INCL)/epri.h ESHK_H = $(DUNGEON_H) $(INCL)/eshk.h MONDATA_H = $(INCL)/align.h $(INCL)/mondata.h MONST_H = $(INCL)/align.h $(INCL)/monst.h PERMONST_H = $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/align.h \ $(INCL)/permonst.h REGION_H = $(INCL)/region.h RM_H = $(INCL)/align.h $(INCL)/rm.h SKILLS_H = $(INCL)/skills.h SP_LEV_H = $(INCL)/align.h $(INCL)/sp_lev.h VAULT_H = $(DUNGEON_H) $(INCL)/vault.h YOUPROP_H = $(PERMONST_H) $(MONDATA_H) $(INCL)/prop.h \ $(INCL)/pm.h $(INCL)/youprop.h YOU_H = $(MONST_H) $(YOUPROP_H) $(INCL)/align.h \ $(INCL)/attrib.h $(INCL)/you.h DISPLAY_H = $(MONDATA_H) $(INCL)/vision.h $(INCL)/display.h PCCONF_H = $(INCL)/micro.h $(INCL)/system.h $(INCL)/pcconf.h \ $(MSYS)/pcvideo.h CONFIG_H = $(GLOBAL_H) $(INCL)/tradstdc.h $(INCL)/config1.h \ $(INCL)/config.h DECL_H = $(YOU_H) $(INCL)/spell.h $(INCL)/color.h \ $(INCL)/obj.h $(INCL)/onames.h $(INCL)/pm.h \ $(INCL)/decl.h GLOBAL_H = $(PCCONF_H) $(INCL)/coord.h $(INCL)/global.h HACK_H = $(CONFIG_H) $(DUNGEON_H) $(DECL_H) \ $(DISPLAY_H) $(INCL)/monsym.h $(INCL)/mkroom.h \ $(INCL)/objclass.h $(INCL)/trap.h $(INCL)/flag.h \ $(RM_H) $(INCL)/vision.h $(INCL)/wintype.h \ $(INCL)/engrave.h $(INCL)/rect.h \ $(INCL)/trampoli.h $(INCL)/hack.h $(REGION_H) DLB_H = $(INCL)/dlb.h ifeq ($(SUPPRESS_GRAPHICS),Y) TILE_H = else TILE_H = $(WSHR)/tile.h $(MSYS)/pctiles.h endif ifeq ($(USE_DLB),Y) DLB = dlb DLBOBJS = $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o else DLB = DLBOBJS = endif ifdef DJGPP DJ1 = $(dir $(DJGPP)) CWSDPMI = $(subst /,\,$(DJ1))bin\CWSDPMI.* endif #========================================== # Primary Targets. #========================================== # The default target. all : install install: $(GAMEFILE) $(O)install.tag @echo Done. default: $(GAMEFILE) util: $(O)utility.tag $(O)utility.tag: $(INCL)/date.h $(INCL)/trap.h $(INCL)/onames.h \ $(INCL)/pm.h monstr.c vis_tab.c \ $(U)lev_comp.exe $(U)dgn_comp.exe $(TILEUTIL) $(subst /,\,echo utilities made > $@) tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. recover: $(U)recover.exe @$(subst /,\,if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR)) @$(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR)) $(O)install.tag: $(O)dat.tag $(GAMEFILE) ifeq ($(USE_DLB),Y) @$(subst /,\,copy $(DAT)/nhdat $(GAMEDIR)) @$(subst /,\,copy $(DAT)/license $(GAMEDIR)) else @$(subst /,\,copy $(DAT)/*. $(GAMEDIR)) @$(subst /,\,copy $(DAT)/*.dat $(GAMEDIR)) @$(subst /,\,copy $(DAT)/*.lev $(GAMEDIR)) @$(subst /,\,copy $(MSYS)/msdoshlp.txt $(GAMEDIR)) @$(subst /,\,if exist $(GAMEDIR)/makefile. del $(GAMEDIR)/makefile.) endif ifdef TERMLIB @$(subst /,\,copy $(SSHR)/termcap $(GAMEDIR)) endif @$(subst /,\,if exist $(DAT)/*.tib copy $(DAT)/*.tib $(GAMEDIR)) @$(subst /,\,copy $(SSHR)/NetHack.cnf $(GAMEDIR)/defaults.nh) @$(subst /,\,copy $(MSYS)/NHAccess.nh $(GAMEDIR)) @$(subst /,\,copy $(DOC)/guidebo*.txt $(GAMEDIR)) @$(subst /,\,if exist $(DOC)/nethack.txt copy $(DOC)/nethack.txt $(GAMEDIR)) ifdef CWSDPMI @$(subst /,\,if exist $(CWSDPMI) copy $(CWSDPMI) $(GAMEDIR)) else @$(subst /,\,echo Could not find a copy of CWSDPMI.EXE to put into $(GAMEDIR)) endif @$(subst /,\,echo install done > $@) #========================================== # The main target. #========================================== $(GAMEFILE): $(O)obj.tag $(PATCHLEV_H) $(O)utility.tag $(ALLOBJ) $(O)$(GAME).lnk $(LINK) $(LFLAGS) -o$(GAME).exe @$(O)$(GAME).lnk $(LIBRARIES) @$(subst /,\,stubedit $(GAME).exe minstack=2048K) @$(subst /,\,copy $(GAME).exe $(GAMEFILE)) @$(subst /,\,del $(GAME).exe) $(O)$(GAME).lnk: $(ALLOBJ) echo $(VOBJ01) > $(subst /,\,$@) echo $(VOBJ02) >> $(subst /,\,$@) echo $(VOBJ03) >> $(subst /,\,$@) echo $(VOBJ04) >> $(subst /,\,$@) echo $(VOBJ05) >> $(subst /,\,$@) echo $(VOBJ06) >> $(subst /,\,$@) echo $(VOBJ07) >> $(subst /,\,$@) echo $(VOBJ08) >> $(subst /,\,$@) echo $(VOBJ09) >> $(subst /,\,$@) echo $(VOBJ10) >> $(subst /,\,$@) echo $(VOBJ11) >> $(subst /,\,$@) echo $(VOBJ12) >> $(subst /,\,$@) echo $(VOBJ13) >> $(subst /,\,$@) echo $(VOBJ14) >> $(subst /,\,$@) echo $(VOBJ15) >> $(subst /,\,$@) echo $(VOBJ16) >> $(subst /,\,$@) echo $(VOBJ17) >> $(subst /,\,$@) echo $(VOBJ18) >> $(subst /,\,$@) echo $(VOBJ19) >> $(subst /,\,$@) echo $(VOBJ20) >> $(subst /,\,$@) echo $(VOBJ21) >> $(subst /,\,$@) echo $(VOBJ22) >> $(subst /,\,$@) echo $(VOBJ23) >> $(subst /,\,$@) echo $(SOBJ) >> $(subst /,\,$@) echo $(TILOBJ) >> $(subst /,\,$@) echo $(VVOBJ) >> $(subst /,\,$@) #========================================== # Housekeeping. #========================================== clean: $(subst /,\,if exist $(O)*.o del $(O)*.o) $(subst /,\,if exist $(O)dat.tag del $(O)dat.tag) $(subst /,\,if exist $(O)install.tag del $(O)install.tag) $(subst /,\,if exist $(O)$(GAME).lnk del $(O)$(GAME).lnk) $(subst /,\,if exist $(O)obj.tag del $(O)obj.tag) $(subst /,\,if exist $(O)sp_lev.tag del $(O)sp_lev.tag) $(subst /,\,if exist $(O)thintile.tag del $(O)thintile.tag) $(subst /,\,if exist $(O)utility.tag del $(O)utility.tag) spotless: clean $(subst /,\,if exist $(U)lev_flex.c del $(U)lev_flex.c) $(subst /,\,if exist $(U)lev_lex.c del $(U)lev_lex.c) $(subst /,\,if exist $(U)lev_yacc.c del $(U)lev_yacc.c) $(subst /,\,if exist $(U)dgn_flex.c del $(U)dgn_flex.c) $(subst /,\,if exist $(U)dgn_lex.c del $(U)dgn_lex.c) $(subst /,\,if exist $(U)dgn_yacc.c del $(U)lev_yacc.c) $(subst /,\,if exist $(U)makedefs.exe del $(U)makedefs.exe) $(subst /,\,if exist $(U)lev_comp.exe del $(U)lev_comp.exe) $(subst /,\,if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe) $(subst /,\,if exist $(U)recover.exe del $(U)recover.exe) $(subst /,\,if exist $(U)tilemap.exe del $(U)tilemap.exe) $(subst /,\,if exist $(U)tile2bin.exe del $(U)tile2bin.exe) $(subst /,\,if exist $(U)til2bin2.exe del $(U)til2bin2.exe) $(subst /,\,if exist $(U)thintile.exe del $(U)thintile.exe) $(subst /,\,if exist $(U)dlb_main.exe del $(U)dlb_main.exe) $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h) $(subst /,\,if exist $(INCL)/onames.h del $(INCL)/onames.h) $(subst /,\,if exist $(INCL)/pm.h del $(INCL)/pm.h) $(subst /,\,if exist $(INCL)/date.h del $(INCL)/date.h) $(subst /,\,if exist $(INCL)/dgn_comp.h del $(INCL)/dgn_comp.h) $(subst /,\,if exist $(INCL)/lev_comp.h del $(INCL)/lev_comp.h) $(subst /,\,if exist $(SRC)/monstr.c del $(SRC)/monstr.c) $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c) $(subst /,\,if exist $(SRC)/tile.c del $(SRC)/tile.c) $(subst /,\,if exist $(DAT)/options del $(DAT)/options) $(subst /,\,if exist $(DAT)/data del $(DAT)/data) $(subst /,\,if exist $(DAT)/rumors del $(DAT)/rumors) $(subst /,\,if exist $(DAT)/dungeon.pdf del $(DAT)/dungeon.pdf) $(subst /,\,if exist $(DAT)/dungeon del $(DAT)/dungeon) $(subst /,\,if exist $(DAT)/oracles del $(DAT)/oracles) $(subst /,\,if exist $(DAT)/quest.dat del $(DAT)/quest.dat) $(subst /,\,if exist $(DAT)/dlb.lst del $(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/nhdat del $(DAT)/nhdat) $(subst /,\,if exist $(DAT)/*.lev del $(DAT)/*.lev) $(subst /,\,if exist $(PLANAR_TIB) del $(PLANAR_TIB)) $(subst /,\,if exist $(OVERVIEW_TIB) del $(OVERVIEW_TIB)) $(subst /,\,if exist $(WSHR)/monthin.txt del $(WSHR)/monthin.txt) $(subst /,\,if exist $(WSHR)/objthin.txt del $(WSHR)/objthin.txt) $(subst /,\,if exist $(WSHR)/oththin.txt del $(WSHR)/oththin.txt) #========================================== # Create directory for holding object files #========================================== $(O)obj.tag: -$(subst /,\,@if not exist $(OBJ)/*.* mkdir $(OBJ)) @$(subst /,\,@echo directory created > $@) #=========================================== # Work around some djgpp long file name woes #=========================================== $(PATCHLEV_H): @$(subst /,\,if not exist $@ copy $(INCL)/patchlevel.h $(INCL)/patchlev.h) #========================================== #=========== SECONDARY TARGETS ============ #========================================== # # The following include files depend on makedefs to be created. # # date.h should be remade every time any of the source or include # files is modified. $(INCL)/date.h : $(U)makedefs.exe -$(subst /,\,$(U)makedefs -v) $(INCL)/onames.h: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -o) $(INCL)/pm.h: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -p) monstr.c: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -m) $(INCL)/vis_tab.h: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -z) vis_tab.c: $(U)makedefs.exe -$(subst /,\,$(U)makedefs -z) #========================================== # Makedefs Stuff #========================================== $(U)makedefs.exe: $(MAKEOBJS) $(LINK) $(LFLAGS) -o$@ $(MAKEOBJS) $(O)makedefs.o: $(CONFIG_H) $(PERMONST_H) $(INCL)/objclass.h \ $(INCL)/monsym.h $(INCL)/qtext.h $(U)makedefs.c #========================================== # Level Compiler Dependencies #========================================== $(U)lev_comp.exe: $(SPLEVOBJS) $(LINK) $(LFLAGS) -o$@ $(SPLEVOBJS) ifeq ($(YACC_LEX),Y) $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(U)lev_yacc.c $(CC) $(cflags) -o$@ $(U)lev_yacc.c else $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)/lev_comp.h $(U)lev_yacc.c $(CC) $(cflags) -o$@ $(U)lev_yacc.c endif $(O)lev_$(LEX).o: $(HACK_H) $(SP_LEV_H) $(INCL)/lev_comp.h \ $(U)lev_$(LEX).c $(CC) $(cflags) -o$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(HACK_H) $(INCL)/sp_lev.h $(INCL)/date.h $(U)lev_main.c ifeq "$(DO_YACC)" "YACC_ACT" $(INCL)/lev_comp.h: $(U)lev_yacc.c $(U)lev_yacc.c $(INCL)/lev_comp.h : $(U)lev_comp.y @$(subst /,\,chdir $(UTIL)) @$(subst /,\,$(YACC) -d lev_comp.y) @$(subst /,\,copy $(YTABC) lev_yacc.c) @$(subst /,\,copy $(YTABH) $(INCL)/lev_comp.h) @$(subst /,\,@del $(YTABC)) @$(subst /,\,@del $(YTABH)) @$(subst /,\,chdir $(SRC)) else $(U)lev_yacc.c: $(SSHR)/lev_yacc.c @echo --- @echo For now, we will copy the prebuilt @echo lev_comp.c from $(SSHR) into $(U) and use that. @$(subst /,\,copy $(SSHR)/lev_yacc.c $(U)lev_yacc.c) @$(subst /,\,echo.>>$(U)lev_yacc.c) $(INCL)/lev_comp.h : $(SSHR)/lev_comp.h @echo --- @echo For now, we will copy the prebuilt lev_comp.h @echo from $(SSHR) into $(INCL) and use that. @$(subst /,\,copy $(SSHR)/lev_comp.h $(INCL)/lev_comp.h) @$(subst /,\,echo.>>$(INCL)/lev_comp.h) endif $(U)lev_$(LEX).c: $(U)lev_comp.l ifeq "$(DO_LEX)" "LEX_ACT" @$(subst /,\,chdir $(UTIL)) @$(subst /,\,$(LEX) $(FLEXSKEL) lev_comp.l) @$(subst /,\,if exist $@ del $@) @$(subst /,\,copy $(LEXYYC) $@) @$(subst /,\,del $(LEXYYC)) @$(subst /,\,chdir $(SRC)) else @echo --- @echo For now, we will copy the prebuilt lev_lex.c @echo from $(SSHR) into $(U) and use it. @$(subst /,\,copy $(SSHR)/lev_lex.c $@) @$(subst /,\,echo.>>$@) endif #========================================== # Dungeon Dependencies #========================================== $(U)dgn_comp.exe: $(DGNCOMPOBJS) $(LINK) $(LFLAGS) -o$@ $(DGNCOMPOBJS) ifeq "$(DO_YACC)" "YACC_ACT" $(U)dgn_yacc.c $(INCL)/dgn_comp.h : $(U)dgn_comp.y @$(subst /,\,chdir $(UTIL)) @$(subst /,\,$(YACC) -d dgn_comp.y) @$(subst /,\,copy $(YTABC) dgn_yacc.c) @$(subst /,\,copy $(YTABH) $(INCL)/dgn_comp.h) @$(subst /,\,@del $(YTABC)) @$(subst /,\,@del $(YTABH)) @$(subst /,\,chdir $(SRC)) else $(U)dgn_yacc.c: $(SSHR)/dgn_yacc.c @echo --- @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and @echo dgn_comp.h from $(SSHR) into $(U) and use that. @$(subst /,\,copy $(SSHR)/dgn_yacc.c $(U)dgn_yacc.c) @$(subst /,\,echo.>>$(U)dgn_yacc.c) $(INCL)/dgn_comp.h: $(SSHR)/dgn_comp.h @echo --- @echo For now, we will copy the prebuilt dgn_comp.h @echo from $(SSHR) into $(INCL) and use that. @$(subst /,\,copy $(SSHR)/dgn_comp.h $(INCL)/dgn_comp.h) @$(subst /,\,echo.>>$(INCL)/dgn_comp.h) endif ifeq "$(DO_LEX)" "LEX_ACT" $(U)dgn_$(LEX).c: $(U)dgn_comp.l $(INCL)/dgn_comp.h @$(subst /,\,chdir $(UTIL)) @$(subst /,\,$(LEX) $(FLEXSKEL) dgn_comp.l) @$(subst /,\,if exist $@ del $@) @$(subst /,\,copy $(LEXYYC) $@) @$(subst /,\,del $(LEXYYC)) @$(subst /,\,chdir $(SRC)) else $(U)dgn_$(LEX).c: $(SSHR)/dgn_lex.c $(INCL)/dgn_comp.h @echo --- @echo For now, we will copy the prebuilt dgn_lex.c @echo from $(SSHR) into $(U) and use it. @$(subst /,\,copy $(SSHR)/dgn_lex.c $@) @$(subst /,\,echo.>>$@) endif #========================================== # Recover Utility #========================================== $(U)recover.exe: $(RECOVOBJS) $(LINK) $(LFLAGS) -o$@ $(O)recover.o $(O)recover.o: $(CONFIG_H) $(U)recover.c $(CC) $(cflags) -o$@ $(U)recover.c #========================================== # Header file moves required for tile support #========================================== ifeq ($(SUPPRESS_GRAPHICS),Y) else # # Tile Mapping # $(SRC)/tile.c: $(U)tilemap.exe @$(subst /,\,$(U)tilemap.exe) @echo A new $@ has been created $(U)tilemap.exe: $(O)tilemap.o $(LINK) $(LFLAGS) -o$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)/tilemap.c $(HACK_H) $(TILE_H) $(CC) $(cflags) -I$(WSHR) -I$(MSYS) -o$@ $(WSHR)/tilemap.c #========================================== # Tile Utilities # Required for tile support #========================================== $(DAT)/NetHack1.tib: $(TILEFILES) $(U)tile2bin.exe @echo Creating binary tile files (this may take some time) @$(subst /,\,chdir $(DAT)) @$(subst /,\,$(U)tile2bin.exe) @$(subst /,\,chdir $(SRC)) $(DAT)/NetHacko.tib: $(O)thintile.tag $(TILEFILES2) $(U)til2bin2.exe @echo Creating overview binary tile files (this may take some time) @$(subst /,\,chdir $(DAT)) @$(subst /,\,$(U)til2bin2.exe) @$(subst /,\,chdir $(SRC)) $(U)tile2bin.exe: $(O)tile2bin.o $(TEXTIO) $(LINK) $(LFLAGS) -o$@ $(O)tile2bin.o $(TEXTIO) $(U)til2bin2.exe: $(O)til2bin2.o $(TEXTIO2) $(LINK) $(LFLAGS) -o$@ $(O)til2bin2.o $(TEXTIO2) $(U)thintile.exe: $(O)thintile.o $(LINK) $(LFLAGS) -o$@ $(O)thintile.o $(O)thintile.o: $(HACK_H) $(WSHR)/tile.h $(WSHR)/thintile.c $(CC) $(cflags) -o$@ $(WSHR)/thintile.c $(O)thintile.tag: $(U)thintile.exe $(TILEFILES) @$(subst /,\,$(U)thintile.exe) @$(subst /,\,echo thintiles created >$@) $(O)tile2bin.o: $(HACK_H) $(TILE_H) $(MSYS)/pctiles.h $(MSYS)/pcvideo.h $(MSYS)/tile2bin.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/tile2bin.c $(O)til2bin2.o: $(HACK_H) $(TILE_H) $(MSYS)/pctiles.h $(MSYS)/pcvideo.h $(MSYS)/tile2bin.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE_X=8 -DOVERVIEW_FILE -o$@ $(MSYS)/tile2bin.c $(O)tiletext.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tiletext.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(WSHR)/tiletext.c $(O)tiletex2.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tiletext.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILE_X=8 -o$@ $(WSHR)/tiletext.c $(O)tiletxt.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tilemap.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILETEXT -o$@ $(WSHR)/tilemap.c $(O)tiletxt2.o: $(CONFIG_H) $(TILE_H) $(WSHR)/tilemap.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -DTILETEXT -DTILE_X=8 -o$@ $(WSHR)/tilemap.c # # Optional GIF Utilities (for development) # $(U)gif2txt.exe: $(GIFREADERS) $(TEXTIO) $(LINK) $(LFLAGS) -o$@ $(GIFREADERS) $(TEXTIO) $(U)gif2txt2.exe: $(GIFREAD2) $(TEXTIO2) $(LINK) $(LFLAGS) -o$@ $(GIFREAD2) $(TEXTIO2) $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXTIO) $(LINK) $(LFLAGS) -o$@ $(PPMWRITERS) $(TEXTIO) $(U)txt2ppm2.exe: $(PPMWRIT2) $(TEXTIO2) $(LINK) $(LFLAGS) -o$@ $(PPMWRIT2) $(TEXTIO2) $(O)gifread.o: $(CONFIG_H) $(WSHR)/tile.h $(WSHR)/gifread.c $(O)gifread2.o: $(CONFIG_H) $(WSHR)/tile.h $(WSHR)/gifread.c $(CC) $(cflags) -DTILE_X=8 -o$@ $(WSHR)/gifread.c ppmwrite.c: $(WSHR)/ppmwrite.c @$(subst /,\,copy $(WSHR)/ppmwrite.c .) $(O)ppmwrite.o: $(CONFIG_H) $(WSHR)/tile.h $(O)ppmwrit2.o: $(CONFIG_H) $(WSHR)/tile.h ppmwrite.c $(CC) $(cflags) -DTILE_X=8 -o$@ ppmwrite.c # # Optional tile viewer (development sources only) # $(U)viewtib.exe: $(O)viewtib.o $(LINK) $(LFLAGS) -o$@ $(O)viewtib.o $(LIBRARIES) $(O)viewtib.o: $(MSYS)/viewtib.c endif #========================================== # Other Util Dependencies. #========================================== $(O)alloc.o: $(CONFIG_H) alloc.c $(CC) $(cflags) -o$@ alloc.c $(O)drawing.o: $(CONFIG_H) drawing.c $(MSYS)/pcvideo.h $(CC) $(cflags) -I$(MSYS) -o$@ drawing.c $(O)decl.o: $(CONFIG_H) decl.c $(CC) $(cflags) -o$@ decl.c $(O)monst.o: $(CONFIG_H) $(PERMONST_H) $(ESHK_H) \ $(EPRI_H) $(VAULT_H) $(INCL)/monsym.h \ $(INCL)/color.h monst.c $(CC) $(cflags) -o$@ monst.c $(O)objects.o: $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ $(INCL)/prop.h $(INCL)/color.h objects.c $(CC) $(cflags) -o$@ objects.c $(O)panic.o: $(CONFIG_H) $(U)panic.c #============================================================ # make data.base an 8.3 filename to prevent an make warning #============================================================ DATABASE = $(DAT)/data.bas $(O)dat.tag: $(DAT)/nhdat @$(subst /,\,echo dat done >$@) $(DAT)/data: $(O)utility.tag $(DATABASE) @$(subst /,\,$(U)makedefs.exe -d) $(DAT)/rumors: $(O)utility.tag $(DAT)/rumors.tru $(DAT)/rumors.fal @$(subst /,\,$(U)makedefs.exe -r) $(DAT)/quest.dat: $(O)utility.tag $(DAT)/quest.txt @$(subst /,\,$(U)makedefs.exe -q) $(DAT)/oracles: $(O)utility.tag $(DAT)/oracles.txt @$(subst /,\,$(U)makedefs.exe -h) $(O)sp_lev.tag: $(O)utility.tag $(DAT)/bigroom.des $(DAT)/castle.des \ $(DAT)/endgame.des $(DAT)/gehennom.des $(DAT)/knox.des \ $(DAT)/medusa.des $(DAT)/oracle.des $(DAT)/tower.des \ $(DAT)/yendor.des $(DAT)/arch.des $(DAT)/barb.des \ $(DAT)/caveman.des $(DAT)/healer.des $(DAT)/knight.des \ $(DAT)/monk.des $(DAT)/priest.des $(DAT)/ranger.des \ $(DAT)/rogue.des $(DAT)/samurai.des $(DAT)/tourist.des \ $(DAT)/valkyrie.des $(DAT)/wizard.des @$(subst /,\,cd $(DAT)) @$(subst /,\,$(U)lev_comp bigroom.des) @$(subst /,\,$(U)lev_comp castle.des) @$(subst /,\,$(U)lev_comp endgame.des) @$(subst /,\,$(U)lev_comp gehennom.des) @$(subst /,\,$(U)lev_comp knox.des) @$(subst /,\,$(U)lev_comp mines.des) @$(subst /,\,$(U)lev_comp medusa.des) @$(subst /,\,$(U)lev_comp oracle.des) @$(subst /,\,$(U)lev_comp sokoban.des) @$(subst /,\,$(U)lev_comp tower.des) @$(subst /,\,$(U)lev_comp yendor.des) @$(subst /,\,$(U)lev_comp arch.des) @$(subst /,\,$(U)lev_comp barb.des) @$(subst /,\,$(U)lev_comp caveman.des) @$(subst /,\,$(U)lev_comp healer.des) @$(subst /,\,$(U)lev_comp knight.des) @$(subst /,\,$(U)lev_comp monk.des) @$(subst /,\,$(U)lev_comp priest.des) @$(subst /,\,$(U)lev_comp ranger.des) @$(subst /,\,$(U)lev_comp rogue.des) @$(subst /,\,$(U)lev_comp samurai.des) @$(subst /,\,$(U)lev_comp tourist.des) @$(subst /,\,$(U)lev_comp valkyrie.des) @$(subst /,\,$(U)lev_comp wizard.des) @$(subst /,\,cd $(SRC)) @$(subst /,\,echo sp_levs done > $@) $(DAT)/dungeon: $(O)utility.tag $(DAT)/dungeon.def @$(subst /,\,$(U)makedefs.exe -e) @$(subst /,\,cd $(DAT)) @$(subst /,\,$(U)dgn_comp.exe dungeon.pdf) @$(subst /,\,cd $(SRC)) #========================================== # DLB stuff #========================================== #note that dir below assumes bin/dir.exe from djgpp distribution # $(DAT)/nhdat: $(U)dlb_main.exe $(DAT)/data $(DAT)/rumors $(DAT)/dungeon \ $(DAT)/oracles $(DAT)/quest.dat $(O)sp_lev.tag @$(subst /,\,echo dat done >$(O)dat.tag) @$(subst /,\,cd $(DAT)) @$(subst /,\,copy $(MSYS)/msdoshlp.txt .) @$(subst /,\,echo data >dlb.lst) @$(subst /,\,echo dungeon >>dlb.lst) @$(subst /,\,echo oracles >>dlb.lst) @$(subst /,\,echo options >>dlb.lst) @$(subst /,\,echo quest.dat >>dlb.lst) @$(subst /,\,echo rumors >>dlb.lst) @$(subst /,\,echo help >>dlb.lst) @$(subst /,\,echo hh >>dlb.lst) @$(subst /,\,echo cmdhelp >>dlb.lst) @$(subst /,\,echo history >>dlb.lst) @$(subst /,\,echo opthelp >>dlb.lst) @$(subst /,\,echo wizhelp >>dlb.lst) @$(subst /,\,echo license >>dlb.lst) @$(subst /,\,echo msdoshlp.txt >>dlb.lst) $(LS) $(subst /,\,*.lev) >>dlb.lst @$(subst /,\,$(U)dlb_main cvIf dlb.lst nhdat) @$(subst /,\,cd $(SRC)) $(U)dlb_main.exe: $(DLBOBJS) $(LINK) $(LFLAGS) -o$@ $(DLBOBJS) $(O)dlb_main.o: $(U)dlb_main.c $(INCL)/config.h $(DLB_H) $(CC) $(cflags) -o$@ $(U)dlb_main.c #========================================== # Game Dependencies #========================================== # sys/share $(O)main.o: $(HACK_H) $(DLB_H) $(SSHR)/pcmain.c $(CC) $(cflags) -o$@ $(SSHR)/pcmain.c $(O)tty.o: $(HACK_H) $(INCL)/wintty.h $(SSHR)/pctty.c $(CC) $(cflags) -o$@ $(SSHR)/pctty.c $(O)unix.o: $(HACK_H) $(SSHR)/pcunix.c $(CC) $(cflags) -o$@ $(SSHR)/pcunix.c $(O)sys.o : $(HACK_H) $(SSHR)/pcsys.c $(CC) $(cflags) -o$@ $(SSHR)/pcsys.c # sys/msdos $(O)msdos.o : $(HACK_H) $(MSYS)/msdos.c # $(CC) $(cflags) -o$@ $(MSYS)/msdos.c $(O)pckeys.o : $(HACK_H) $(MSYS)/pckeys.c # $(CC) $(cflags) -o$@ $(MSYS)/pckeys.c $(O)pctiles.o : $(HACK_H) $(MSYS)/pctiles.c $(MSYS)/portio.h $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/pctiles.c $(O)sound.o : $(HACK_H) $(MSYS)/sound.c $(MSYS)/portio.h # $(CC) $(cflags) -o$@ $(MSYS)/sound.c $(O)video.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(MSYS)/video.c # $(CC) $(cflags) -o$@ -I$(MSYS) $(MSYS)/video.c $(O)vidvga.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidvga.c $(CC) $(cflags) -I$(MSYS) -I$(WSHR) -o$@ $(MSYS)/vidvga.c $(O)vidtxt.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/portio.h $(TILE_H) $(MSYS)/vidtxt.c # $(CC) $(cflags) -o$@ -I$(MSYS) $(MSYS)/vidtxt.c $(O)stubvid.o : $(HACK_H) $(MSYS)/pcvideo.h $(MSYS)/video.c $(CC) $(cflags) -I$(MSYS) -DSTUBVIDEO -o$@ $(MSYS)/video.c # src dependencies # # The rest are stolen from sys/unix/Makefile.src, # with the following changes: # o -c (which is included in cflags) substituted with -o$@ , # o an explicit build instruction for dlb.o because it requires # a .h file in ../sys/msdos. # o the PATCHLEV_H macro is substitued for $(INCL)/patchlevel.h # to work around a long filename issue. # o $(CFLAGS) changed to $(cflags) # Other than that, these dependencies are untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../sys/atari/tos.c $(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \ #$(INCL)/win32api.h $(CC) $(cflags) -o$@ ../sys/share/pcmain.c $(O)pcsys.o: ../sys/share/pcsys.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/pcsys.c $(O)pctty.o: ../sys/share/pctty.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/pctty.c $(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/pcunix.c $(O)random.o: ../sys/share/random.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/random.c $(O)ioctl.o: ../sys/share/ioctl.c $(HACK_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../sys/share/ioctl.c $(O)unixtty.o: ../sys/share/unixtty.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/share/unixtty.c $(O)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) $(INCL)/dlb.h $(CC) $(cflags) -o$@ ../sys/unix/unixmain.c $(O)unixunix.o: ../sys/unix/unixunix.c $(HACK_H) $(CC) $(cflags) -o$@ ../sys/unix/unixunix.c $(O)unixres.o: ../sys/unix/unixres.c $(CONFIG_H) $(CC) $(cflags) -o$@ ../sys/unix/unixres.c $(O)bemain.o: ../sys/be/bemain.c $(HACK_H) $(INCL)/dlb.h $(CC) $(cflags) -o$@ ../sys/be/bemain.c $(O)getline.o: ../win/tty/getline.c $(HACK_H) $(INCL)/func_tab.h $(CC) $(cflags) -o$@ ../win/tty/getline.c $(O)termcap.o: ../win/tty/termcap.c $(HACK_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../win/tty/termcap.c $(O)topl.o: ../win/tty/topl.c $(HACK_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../win/tty/topl.c $(O)wintty.o: ../win/tty/wintty.c $(HACK_H) $(INCL)/dlb.h \ $(PATCHLEV_H) $(INCL)/tcap.h $(CC) $(cflags) -o$@ ../win/tty/wintty.c $(O)Window.o: ../win/X11/Window.c $(INCL)/xwindowp.h $(INCL)/xwindow.h \ $(CONFIG_H) $(CC) $(cflags) -o$@ ../win/X11/Window.c $(O)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) $(CC) $(cflags) -o$@ ../win/X11/dialogs.c $(O)winX.o: ../win/X11/winX.c $(HACK_H) $(INCL)/winX.h $(INCL)/dlb.h \ $(PATCHLEV_H) ../win/X11/nh72icon \ ../win/X11/nh56icon ../win/X11/nh32icon $(CC) $(cflags) -o$@ ../win/X11/winX.c $(O)winmap.o: ../win/X11/winmap.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/dlb.h \ $(INCL)/winX.h $(INCL)/tile2x11.h $(CC) $(cflags) -o$@ ../win/X11/winmap.c $(O)winmenu.o: ../win/X11/winmenu.c $(HACK_H) $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winmenu.c $(O)winmesg.o: ../win/X11/winmesg.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winmesg.c $(O)winmisc.o: ../win/X11/winmisc.c $(HACK_H) $(INCL)/func_tab.h \ $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winmisc.c $(O)winstat.o: ../win/X11/winstat.c $(HACK_H) $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winstat.c $(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h $(CC) $(cflags) -o$@ ../win/X11/wintext.c $(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h $(CC) $(cflags) -o$@ ../win/X11/winval.c $(O)tile.o: tile.c $(HACK_H) $(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ ../win/gnome/gnmain.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c $(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \ ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c $(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c $(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \ $(INCL)/date.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c $(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h $(HACK_H) $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c $(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \ ../win/gnome/gnbind.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c $(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c $(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c $(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ ../win/gnome/gnmain.h $(HACK_H) $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c $(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ ../win/gnome/gnmain.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c $(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \ ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \ ../win/gnome/gnomeprv.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c $(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \ ../win/gnome/gn_rip.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gntext.c $(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c $(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h $(CC) $(cflags) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c $(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \ $(PATCHLEV_H) $(INCL)/wingem.h $(CC) $(cflags) -o$@ ../win/gem/wingem.c $(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \ $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h $(CC) $(cflags) -o$@ ../win/gem/wingem1.c $(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h $(CC) $(cflags) -o$@ ../win/gem/load_img.c $(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h $(CC) $(cflags) -o$@ ../win/gem/gr_rect.c $(O)tile.o: tile.c $(HACK_H) $(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \ $(INCL)/dlb.h $(PATCHLEV_H) $(INCL)/tile2x11.h \ $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \ $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp $(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp $(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp $(O)monstr.o: monstr.c $(CONFIG_H) $(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) $(INCL)/edog.h $(O)artifact.o: artifact.c $(HACK_H) $(INCL)/artifact.h $(INCL)/artilist.h $(O)attrib.o: attrib.c $(HACK_H) $(O)ball.o: ball.c $(HACK_H) $(O)bones.o: bones.c $(HACK_H) $(INCL)/lev.h $(O)botl.o: botl.c $(HACK_H) $(O)cmd.o: cmd.c $(HACK_H) $(INCL)/func_tab.h $(O)dbridge.o: dbridge.c $(HACK_H) $(O)decl.o: decl.c $(HACK_H) $(O)detect.o: detect.c $(HACK_H) $(INCL)/artifact.h $(O)dig.o: dig.c $(HACK_H) $(INCL)/edog.h $(O)display.o: display.c $(HACK_H) $(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h $(CC) $(cflags) -I../sys/msdos -o$@ dlb.c $(O)do.o: do.c $(HACK_H) $(INCL)/lev.h $(O)do_name.o: do_name.c $(HACK_H) $(O)do_wear.o: do_wear.c $(HACK_H) $(O)dog.o: dog.c $(HACK_H) $(INCL)/edog.h $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h $(O)dokick.o: dokick.c $(HACK_H) $(INCL)/eshk.h $(O)dothrow.o: dothrow.c $(HACK_H) $(O)drawing.o: drawing.c $(HACK_H) $(INCL)/tcap.h $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)/eshk.h $(INCL)/dlb.h $(O)engrave.o: engrave.c $(HACK_H) $(INCL)/lev.h $(O)exper.o: exper.c $(HACK_H) $(O)explode.o: explode.c $(HACK_H) $(O)extralev.o: extralev.c $(HACK_H) $(O)files.o: files.c $(HACK_H) $(INCL)/dlb.h $(O)fountain.o: fountain.c $(HACK_H) $(O)hack.o: hack.c $(HACK_H) $(O)hacklib.o: hacklib.c $(HACK_H) $(O)invent.o: invent.c $(HACK_H) $(O)light.o: light.c $(HACK_H) $(INCL)/lev.h $(O)lock.o: lock.c $(HACK_H) $(O)mail.o: mail.c $(HACK_H) $(INCL)/mail.h $(O)makemon.o: makemon.c $(HACK_H) $(INCL)/epri.h $(INCL)/emin.h \ $(INCL)/edog.h $(O)mapglyph.o: mapglyph.c $(HACK_H) $(O)mcastu.o: mcastu.c $(HACK_H) $(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h $(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h $(O)minion.o: minion.c $(HACK_H) $(INCL)/emin.h $(INCL)/epri.h $(O)mklev.o: mklev.c $(HACK_H) $(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)/sp_lev.h $(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)/sp_lev.h $(INCL)/lev.h $(O)mkobj.o: mkobj.c $(HACK_H) $(O)mkroom.o: mkroom.c $(HACK_H) $(O)mon.o: mon.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h $(O)mondata.o: mondata.c $(HACK_H) $(INCL)/eshk.h $(INCL)/epri.h $(O)monmove.o: monmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/artifact.h \ $(INCL)/epri.h $(O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \ $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \ $(INCL)/dungeon.h $(INCL)/eshk.h $(INCL)/vault.h \ $(INCL)/epri.h $(INCL)/color.h $(O)mplayer.o: mplayer.c $(HACK_H) $(O)mthrowu.o: mthrowu.c $(HACK_H) $(O)muse.o: muse.c $(HACK_H) $(INCL)/edog.h $(O)music.o: music.c $(HACK_H) #interp.c $(O)o_init.o: o_init.c $(HACK_H) $(INCL)/lev.h $(O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h $(O)objnam.o: objnam.c $(HACK_H) $(O)options.o: options.c $(CONFIG_H) $(INCL)/objclass.h $(INCL)/flag.h \ $(HACK_H) $(INCL)/tcap.h $(O)pager.o: pager.c $(HACK_H) $(INCL)/dlb.h $(O)pickup.o: pickup.c $(HACK_H) $(O)pline.o: pline.c $(HACK_H) $(INCL)/epri.h $(INCL)/edog.h $(O)polyself.o: polyself.c $(HACK_H) $(O)potion.o: potion.c $(HACK_H) $(O)pray.o: pray.c $(HACK_H) $(INCL)/epri.h $(O)priest.o: priest.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/eshk.h \ $(INCL)/epri.h $(INCL)/emin.h $(O)quest.o: quest.c $(HACK_H) $(INCL)/qtext.h $(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)/dlb.h $(INCL)/qtext.h $(O)read.o: read.c $(HACK_H) $(O)rect.o: rect.c $(HACK_H) $(O)region.o: region.c $(HACK_H) $(INCL)/lev.h $(O)restore.o: restore.c $(HACK_H) $(INCL)/lev.h $(INCL)/tcap.h $(O)rip.o: rip.c $(HACK_H) $(O)rnd.o: rnd.c $(HACK_H) $(O)role.o: role.c $(HACK_H) $(O)rumors.o: rumors.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h $(O)save.o: save.c $(HACK_H) $(INCL)/lev.h $(O)shk.o: shk.c $(HACK_H) $(INCL)/eshk.h $(O)shknam.o: shknam.c $(HACK_H) $(INCL)/eshk.h $(O)sit.o: sit.c $(HACK_H) $(INCL)/artifact.h $(O)sounds.o: sounds.c $(HACK_H) $(INCL)/edog.h $(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)/dlb.h $(INCL)/sp_lev.h $(O)spell.o: spell.c $(HACK_H) $(O)steal.o: steal.c $(HACK_H) $(O)steed.o: steed.c $(HACK_H) $(O)teleport.o: teleport.c $(HACK_H) $(O)timeout.o: timeout.c $(HACK_H) $(INCL)/lev.h $(O)topten.o: topten.c $(HACK_H) $(INCL)/dlb.h $(PATCHLEV_H) $(O)track.o: track.c $(HACK_H) $(O)trap.o: trap.c $(HACK_H) $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(INCL)/vault.h $(O)version.o: version.c $(HACK_H) $(INCL)/date.h $(PATCHLEV_H) $(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) $(O)windows.o: windows.c $(HACK_H) $(INCL)/wingem.h $(INCL)/winGnome.h $(O)wizard.o: wizard.c $(HACK_H) $(INCL)/qtext.h $(INCL)/epri.h $(O)worm.o: worm.c $(HACK_H) $(INCL)/lev.h $(O)worn.o: worn.c $(HACK_H) $(O)write.o: write.c $(HACK_H) $(O)zap.o: zap.c $(HACK_H) # end of file nethack-3.4.3/sys/msdos/Makefile.MSC0100644000000000000000000007565207764735041015715 0ustar rootroot# SCCS Id: @(#)Makefile.MSC 3.4 2002/09/10 # Copyright (c) NetHack PC Development Team 1997 - 2002. # PC NetHack 3.3x Makefile for MSC V1.52c (16 bit compiler) # # For questions or comments: nethack-bugs@nethack.org # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc # .l lex # # # Game Installation Variables # NOTE: Make sure GAMEDIR exists before make is started. GAME = nethack GAMEDIR =..\binary # # Directories # DAT = ..\dat DOC = ..\doc INCL = ..\include MSYS = ..\sys\msdos SRC = ..\src SSHR = ..\sys\share UTIL = ..\util WIN = ..\win\tty WSHR = ..\win\share # # Executables. CC = cl LINK = link MAKEBIN = nmake # if you have a uudecode program, add its name here # otherwise leave blank UUDECODE = # # Yacc/Lex ... if you got 'em. # # If you have yacc/lex or a work-alike set YACC_LEX to Y # YACC_LEX = N # If YACC_LEX is Y above, set the following to values appropriate for # your tools. # YACC = bison -y LEX = flex YTABC = y_tab.c YTABH = y_tab.h LEXYYC = lexyy.c # # Uncomment this line if you want to include support for ALT-numeric # sequences, such as ALT-2 for toggling #twoweapon mode. # Note that this code did not get a thorough testing prior to 3.4.x #NEWALT=/DNEW_ALT ############################################################################# # # nothing below this line should have to be changed # LNKOPT = SCHEMA3.DEF # # Controls whether MOVE tracing is enabled in the executable # This should be left commented unless you are tinkering with the # overlay structure of NetHack. The executable runs _very_ # slowly when the movetr.lib is linked in. # #MOVETR= movetr.lib # do not change this ! IF ("$(MOVETR)"!="") MVTRCL = /DMOVE_PROF ! ELSE MVTRCL = ! ENDIF # # Uncomment the line below if you want to store all the level files, # help files, etc. in a single library file. USE_DLB = Y ! IF ("$(USE_DLB)"=="Y") DLBFLG = -DDLB ! ELSE DLBFLG = ! ENDIF LIBRARIES = $(LIBS) $(TERMLIB) GAMEFILE = $(GAMEDIR)\$(GAME).exe # # Flags. # # Debugging #CFLAGS = /Zi /DFUNCTION_LEVEL_LINKING /DUSE_TILES /DDLB #LFLAGS = /CODEVIEW /NOI/MAP /CPARM:1 /INFO # Normal LFLAGS = /NOI/MAP /CPARM:1 /INFO CFLAGS = /DFUNCTION_LEVEL_LINKING /DUSE_TILES /DDLB SPECOPTS = # # Leaving MACHINE_CODE undefined will allow it to run # on any Intel 8088 machines and above. # Set to 1 for 80186 and above only # Set to 2 for 80286 and above only # Set to 3 for 80386 and above only # MACHINE_CODE = # # Utility Objects. # # # Shorten up the location for some files # O = $(OBJ)\ # comment so \ isn't last char U = $(UTIL)\ # comment so \ isn't last char SPLEVDES = $(DAT)\Arch.des $(DAT)\Barb.des $(DAT)\bigroom.des \ $(DAT)\castle.des $(DAT)\Caveman.des $(DAT)\endgame.des \ $(DAT)\gehennom.des $(DAT)\Healer.des $(DAT)\Knight.des \ $(DAT)\knox.des $(DAT)\Monk.des $(DAT)\medusa.des \ $(DAT)\mines.des $(DAT)\oracle.des $(DAT)\Priest.des \ $(DAT)\Ranger.des $(DAT)\Rogue.des $(DAT)\Samurai.des \ $(DAT)\Tourist.des $(DAT)\tower.des $(DAT)\Valkyrie.des \ $(DAT)\Wizard.des $(DAT)\yendor.des VGAOBJ = vidvga.o MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c \ $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = makedefs.o monst.o objects.o SPLEVOBJS = lev_yacc.o lev_$(LEX).o lev_main.o alloc.o \ monst.o objects.o panic.o \ drawing.o decl.o stubvid.o DGNCOMPOBJS = dgn_yacc.o dgn_$(LEX).o dgn_main.o alloc.o \ panic.o RECOVOBJS = recover.o # Tile related object files. TILOBJ = tile.o pctiles.o $(VGAOBJ) TEXTIO = tiletext.o tiletxt.o drawing.o decl.o monst.o objects.o stubvid.o TEXTIO2 = tiletex2.o tiletxt2.o drawing.o decl.o monst.o objects.o stubvid.o PLANAR_TIB = NetHack1.tib OVERVIEW_TIB = NetHacko.tib TILEUTIL = $(TILOBJ) tile2bin.exe til2bin2.exe $(PLANAR_TIB) $(OVERVIEW_TIB) TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt TILEFILES2 = $(WSHR)\monthin.txt $(WSHR)\objthin.txt $(WSHR)\oththin.txt GIFREADERS = gifread.o alloc.o panic.o GIFREAD2 = gifread2.o alloc.o panic.o PPMWRITERS = ppmwrite.o alloc.o panic.o PPMWRIT2 = ppmwrit2.o alloc.o panic.o DLBOBJS = dlb_main.o dlb.o alloc.o panic.o # Object files for the game itself. VOBJ01 = allmain.o alloc.o apply.o artifact.o attrib.o VOBJ02 = ball.o bones.o botl.o cmd.o dbridge.o VOBJ03 = decl.o detect.o display.o do.o do_name.o VOBJ04 = do_wear.o dog.o dogmove.o dokick.o dothrow.o VOBJ05 = drawing.o dungeon.o eat.o end.o engrave.o VOBJ06 = exper.o explode.o extralev.o files.o fountain.o VOBJ07 = getline.o hack.o hacklib.o invent.o lock.o VOBJ08 = mail.o main.o makemon.o mapglyph.o mcastu.o mhitm.o VOBJ09 = mhitu.o minion.o mkmap.o mklev.o mkmaze.o VOBJ10 = mkobj.o mkroom.o mon.o mondata.o monmove.o VOBJ11 = monst.o monstr.o mplayer.o mthrowu.o muse.o VOBJ12 = music.o o_init.o objects.o objnam.o options.o VOBJ13 = pickup.o pline.o polyself.o potion.o quest.o VOBJ14 = questpgr.o pager.o pray.o priest.o read.o VOBJ15 = rect.o restore.o rip.o rnd.o role.o VOBJ16 = rumors.o save.o shk.o shknam.o sit.o VOBJ17 = sounds.o sp_lev.o spell.o steal.o steed.o VOBJ18 = termcap.o timeout.o topl.o topten.o track.o VOBJ19 = trap.o u_init.o uhitm.o vault.o vision.o VOBJ20 = vis_tab.o weapon.o were.o wield.o windows.o VOBJ21 = wintty.o wizard.o worm.o worn.o write.o VOBJ22 = zap.o light.o dlb.o dig.o teleport.o VOBJ23 = random.o region.o SOBJ = msdos.o sound.o sys.o tty.o unix.o video.o \ vidtxt.o pckeys.o VVOBJ = version.o VOBJ = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) ALLOBJ = $(VOBJ) $(SOBJ) $(TILOBJ) $(VVOBJ) # # Header Objects. # DGN_FILE_H = $(INCL)\align.h $(INCL)\dgn_file.h DUNGEON_H = $(INCL)\align.h $(INCL)\dungeon.h EMIN_H = $(DUNGEON_H) $(INCL)\emin.h EPRI_H = $(DUNGEON_H) $(INCL)\align.h $(INCL)\epri.h ESHK_H = $(DUNGEON_H) $(INCL)\eshk.h MONDATA_H = $(INCL)\align.h $(INCL)\mondata.h MONST_H = $(INCL)\align.h $(INCL)\monst.h PERMONST_H = $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\align.h \ $(INCL)\permonst.h RM_H = $(INCL)\align.h $(INCL)\rm.h SP_LEV_H = $(INCL)\align.h $(INCL)\sp_lev.h VAULT_H = $(DUNGEON_H) $(INCL)\vault.h YOUPROP_H = $(PERMONST_H) $(MONDATA_H) $(INCL)\prop.h \ $(INCL)\pm.h $(INCL)\youprop.h YOU_H = $(MONST_H) $(YOUPROP_H) $(INCL)\align.h \ $(INCL)\attrib.h $(INCL)\you.h DISPLAY_H = $(MONDATA_H) $(INCL)\vision.h $(INCL)\display.h PCCONF_H = $(INCL)\micro.h $(INCL)\system.h $(INCL)\pcconf.h \ $(MSYS)\pcvideo.h CONFIG_H = $(GLOBAL_H) $(INCL)\tradstdc.h $(INCL)\config1.h \ $(INCL)\config.h DECL_H = $(YOU_H) $(INCL)\spell.h $(INCL)\color.h \ $(INCL)\obj.h $(INCL)\onames.h $(INCL)\pm.h \ $(INCL)\decl.h GLOBAL_H = $(PCCONF_H) $(INCL)\coord.h $(INCL)\global.h HACK_H = $(CONFIG_H) $(DUNGEON_H) $(DECL_H) \ $(DISPLAY_H) $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(INCL)\trap.h $(INCL)\flag.h \ $(RM_H) $(INCL)\vision.h $(INCL)\wintype.h \ $(INCL)\engrave.h $(INCL)\rect.h \ $(INCL)\trampoli.h $(INCL)\hack.h DLB_H = $(INCL)\dlb.h TILE_H = $(WSHR)\tile.h $(MSYS)\pctiles.h # Make Roolz dude. # Due to the inadequacy of some makes these must accord with a # topological sort of the generated-from relation... output on # the left, input on the right. Trust me. # .SUFFIXES: .exe .o .til .uu .c .y .l # # Rules for files in src # .c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< .c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(SRC)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(SRC)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< # # Rules for files in sys\share # {$(SYS)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(SYS)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< # # Rules for files in sys\msdos # {$(MSYS)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(MSYS)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(MSYS)}.h{$(INCL)}.h: @copy $< $@ # # Rules for files in util # {$(UTIL)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(UTIL)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< # # Rules for files in win\share # {$(WSHR)}.c.o: @@$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(WSHR)}.c{$(OBJ)}.o: @@$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(WSHR)}.h{$(INCL)}.h: @copy $< $@ {$(WSHR)}.txt{$(DAT)}.txt: @copy $< $@ # # Rules for files in win\tty # {$(WTTY)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< {$(WTTY)}.c.o: @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $< ! IF ("$(USE_DLB)"=="Y") DLB = nhdat ! ELSE DLB = ! ENDIF ######################################################## # # TARGETS # # The default make target (so just typing 'nmake' is useful). # default : envchk $(GAMEFILE) # The default target. $(GAME): $(O)utility.tag $(GAMEFILE) @echo $(GAME) is up to date. # # Everything # all: install install: envchk $(GAME) $(O)install.tag @echo Done. $(O)install.tag: $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(O)sp_lev.tag $(DLB) ! IF ("$(USE_DLB)"=="Y") copy $(SRC)\nhdat $(GAMEDIR) copy $(DAT)\license $(GAMEDIR) ! ELSE copy $(DAT)\*. $(GAMEDIR) copy $(DAT)\*.dat $(GAMEDIR) copy $(DAT)\*.lev $(GAMEDIR) if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile ! ENDIF copy $(SSHR)\termcap $(GAMEDIR) copy *.tib $(GAMEDIR) copy $(SSHR)\NetHack.cnf $(GAMEDIR)\defaults.nh copy $(MSYS)\NHAccess.nh $(GAMEDIR) copy $(U)recover.exe $(GAMEDIR) if exist $(DOC)\guideb*.txt copy $(DOC)\guideb*.txt $(GAMEDIR) if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR) if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR) echo install done > $@ $(O)sp_lev.tag: $(O)utility.tag $(SPLEVDES) cd $(DAT) $(U)lev_comp bigroom.des $(U)lev_comp castle.des $(U)lev_comp endgame.des $(U)lev_comp gehennom.des $(U)lev_comp knox.des $(U)lev_comp mines.des $(U)lev_comp medusa.des $(U)lev_comp oracle.des $(U)lev_comp sokoban.des $(U)lev_comp tower.des $(U)lev_comp yendor.des $(U)lev_comp arch.des $(U)lev_comp barb.des $(U)lev_comp caveman.des $(U)lev_comp healer.des $(U)lev_comp knight.des $(U)lev_comp monk.des $(U)lev_comp priest.des $(U)lev_comp ranger.des $(U)lev_comp rogue.des $(U)lev_comp samurai.des $(U)lev_comp tourist.des $(U)lev_comp valkyrie.des $(U)lev_comp wizard.des cd $(SRC) # -@if exist $(O)sp_lev.tag del $(O)sp_lev.tag @echo sp_levs done >$(O)sp_lev.tag $(O)utility.tag: $(INCL)\date.h $(INCL)\trap.h \ $(INCL)\onames.h $(INCL)\pm.h monstr.c vis_tab.c \ $(U)lev_comp.exe $(U)dgn_comp.exe $(U)recover.exe $(TILEUTIL) -@if exist $(O)utility.tag del $(O)utility.tag @echo utilities made > $@ tileutil: gif2txt.exe txt2ppm.exe @echo Optional tile development utilities are up to date. .PHONEY: envchk envchk: ! IF ("$(MACHINE_CODE)"!="") @SET MC=/G$(MACHINE_CODE) ! ELSE @SET MC= ! ENDIF ! IF ("$(CL)"=="") @echo CL Environment variable is defined as follows: SET CL=/AL $(MC) /Oo /Gy /Gs /Gt14 /Zp1 /W0 /I$(INCL) /I$(MSYS) /I$(WSHR) /nologo /c ! ELSE @echo Warning CL Environment variable is defined: @echo CL=$(CL) @echo Overriding that definition as follows: SET CL=/AL $(MC) /Oo /Gy /Gs /Gt14 /Zp1 /W0 /I$(INCL) /I$(MSYS) /I$(WSHR) /nologo /c ! ENDIF # The main target. $(GAMEFILE) : $(LNKOPT) $(ALLOBJ) @echo Linking.... $(LINK) $(LFLAGS) /SE:1000 /DYNAMIC:2135 /NOE /ST:6000 @<<$(GAME).lnk $(ALLOBJ:^ =+^ ) $(GAMEFILE) $(GAME) $(TERMLIB) $(MOVETR) $(CLIB) $(BCOVL) $(BCMDL) $(LNKOPT); << @if exist $(O)install.tag del $(O)install.tag @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak # # Housekeeping. # clean: del *.o del *.map del $(U)dlb_main.exe spotless: clean if exist $(O)utility.tag del $(O)utility.tag if exist $(O)install.tag del $(O)install.tag if exist $(GAME).lnk del $(GAME).lnk if exist $(U)makedefs.exe del $(U)makedefs.exe if exist $(U)lev_comp.exe del $(U)lev_comp.exe if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe if exist $(SRC)\lev_lex.c del $(SRC)\lev_lex.c if exist $(SRC)\lev_yacc.c del $(SRC)\lev_yacc.c if exist $(SRC)\dgn_lex.c del $(SRC)\dgn_lex.c if exist $(SRC)\dgn_yacc.c del $(SRC)\dgn_yacc.c if exist $(U)recover.exe del $(U)recover.exe if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h if exist $(INCL)\pcvideo.h del $(INCL)\pcvideo.h if exist $(MSYS)\pctiles.h del $(MSYS)\pctiles.h if exist $(INCL)\portio.h del $(MSYS)\portio.h if exist $(WSHR)\tile.h del $(WSHR)\tile.h if exist monstr.c del monstr.c if exist vis_tab.c del vis_tab.c if exist $(SRC)\panic.c del $(SRC)\panic.c if exist $(SRC)\makedefs.c del $(SRC)\makedefs.c if exist $(SRC)\recover.c del $(SRC)\recover.c if exist $(SRC)\lev_main.c del $(SRC)\lev_main.c if exist $(SRC)\dlb_main.c del $(SRC)\dlb_main.c if exist $(SRC)\dgn_main.c del $(SRC)\dgn_main.c if exist $(SRC)\wintty.c del $(SRC)\wintty.c if exist $(SRC)\topl.c del $(SRC)\topl.c if exist $(SRC)\getline.c del $(SRC)\getline.c if exist $(SRC)\termcap.c del $(SRC)\termcap.c if exist $(SRC)\tile2bin.c del $(SRC)\tile2bin.c if exist $(SRC)\msdos.c del $(SRC)\msdos.c if exist $(SRC)\pckeys.c del $(SRC)\pckeys.c if exist $(SRC)\video.c del $(SRC)\video.c if exist $(SRC)\sound.c del $(SRC)\sound.c if exist $(SRC)\tilemap.c del $(SRC)\tilemap.c if exist $(SRC)\gifread.c del $(SRC)\gifread.c if exist $(SRC)\ppmwrite.c del $(SRC)\ppmwrite.c if exist $(SRC)\pcmain.c del $(SRC)\pcmain.c if exist $(SRC)\pcunix.c del $(SRC)\pcunix.c if exist $(SRC)\pcsys.c del $(SRC)\pcsys.c if exist $(SRC)\pctty.c del $(SRC)\pctty.c if exist $(SRC)\tile.c del $(SRC)\tile.c if exist $(INCL)\date.h del $(INCL)\date.h if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h if exist vis_tab.c del vis_tab.c if exist *.lnk del *.lnk if exist *.def del *.def if exist *.map del *.map if exist a.out del a.out if exist tilemap.exe del tilemap.exe if exist tile2bin.exe del tile2bin.exe if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\*.lev del $(DAT)\*.lev if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\dungeon del $(DAT)\dungeon if exist $(DAT)\options del $(DAT)\options if exist $(DAT)\oracles del $(DAT)\oracles if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\quest.dat del $(DAT)\quest.dat if exist $(SRC)\nhdat del $(SRC)\nhdat if exist $(DAT)\dlb.lst del $(DAT)\dlb.lst if exist $(DAT)\msdoshlp.txt del $(DAT)\msdoshlp.txt if exist $(DAT)\dlb_main.exe del $(DAT)\dlb_main.exe if exist $(DAT)\lev_comp.exe del $(DAT)\lev_comp.exe if exist $(DAT)\dgn_comp.exe del $(DAT)\dgn_comp.exe if exist $(O)sp_lev.tag del $(O)sp_lev.tag if exist $(PLANAR_TIB) del $(PLANAR_TIB) if exist $(OVERVIEW_TIB) del $(OVERVIEW_TIB) # # Secondary Targets. # # # Makedefs Stuff # $(U)makedefs.exe: $(MAKEOBJS) @echo Linking.... @$(LINK) $(LFLAGS) @<<$(@B).lnk $(MAKEOBJS:^ =+^ ) $@ $(@B) ; << makedefs.o: $(CONFIG_H) $(PERMONST_H) $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\qtext.h $(UTIL)\makedefs.c # The following include files depend on makedefs to be created. # # date.h should be remade every time any of the source or include # files is modified. $(INCL)\date.h : $(U)makedefs.exe -$(U)makedefs -v $(INCL)\onames.h: $(U)makedefs.exe -$(U)makedefs -o $(INCL)\pm.h: $(U)makedefs.exe -$(U)makedefs -p monstr.c: $(U)makedefs.exe -$(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe -$(U)makedefs -z vis_tab.c: $(U)makedefs.exe -$(U)makedefs -z # # Level Compiler Stuff # $(U)lev_comp.exe: $(SPLEVOBJS) @echo Linking $@... @$(LINK) $(LFLAGS) @<<$(@B).lnk $(SPLEVOBJS:^ =+^ ) $@ $(@B) $(BCMDL); << $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) $(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" $(YACC) -d -l $(U)lev_comp.y copy $(YTABC) $(U)lev_yacc.c copy $(YTABH) $(INCL)\lev_comp.h @del $(YTABC) @del $(YTABH) ! ELSE @echo. @echo $(U)lev_comp.y has changed. @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC). @echo. @echo For now, we will copy the prebuilt lev_yacc.c @echo from $(SSHR) to $(U)lev_yacc.c, and copy the prebuilt @echo lev_comp.h from $(SYS) to $(UTIL)\lev_comp.h @echo and use those. @echo. copy $(SSHR)\lev_yacc.c $@ >nul touch $@ copy $(SSHR)\lev_comp.h $(INCL)\lev_comp.h >nul touch $(INCL)\lev_comp.h ! ENDIF $(U)lev_$(LEX).c: $(U)lev_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" $(LEX) $(FLEXSKEL) $(U)lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) ! ELSE @echo. @echo $(U)lev_comp.l has changed. To update $@ run $(LEX). @echo. @echo For now, we will copy a prebuilt lev_lex.c @echo from $(SSHR) to $@ and use it. @echo. copy $(SSHR)\lev_lex.c $@ >nul touch $@ ! ENDIF # # Dungeon Stuff # $(U)dgn_comp.exe: $(DGNCOMPOBJS) @echo Linking $@... @$(LINK) $(LFLAGS) @<<$(@B).lnk $(DGNCOMPOBJS:^ =+^ ) $@ $(@B) $(BCMDL); << $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" $(YACC) -d -l $(U)dgn_comp.y copy $(YTABC) $(U)dgn_yacc.c copy $(YTABH) $(INCL)\dgn_comp.h @del $(YTABC) @del $(YTABH) ! ELSE @echo. @echo $(U)dgn_comp.y has changed. To update $@ and @echo $(INCL)\dgn_comp.h run $(YACC). @echo. @echo For now, we will copy the prebuilt dgn_yacc.c from @echo $(SSHR) to $(U)dgn_yacc.c, and copy the prebuilt @echo dgn_comp.h from $(SSHR) to $(INCL)\dgn_comp.h @echo and use those. @echo. copy $(SSHR)\dgn_yacc.c $@ >nul touch $@ copy $(SSHR)\dgn_comp.h $(INCL)\dgn_comp.h >nul touch $(INCL)\dgn_comp.h ! ENDIF $(U)dgn_$(LEX).c: $(U)dgn_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" $(LEX) $(FLEXSKEL) $(U)dgn_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) ! ELSE @echo. @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX). @echo. @echo For now, we will copy a prebuilt dgn_lex.c @echo from $(SSHR) to $@ and use it. @echo. copy $(SSHR)\dgn_lex.c $@ >nul touch $@ ! ENDIF # # Recover Utility # $(U)recover.exe: $(RECOVOBJS) @echo Linking.... @$(LINK) $(LFLAGS) @<<$(@B).lnk $(RECOVOBJS:^ =+^ ) $@ $(@B) ; << recover.o: $(CONFIG_H) $(UTIL)\recover.c # # Header file moves required for tile support # #$(WSHR)\tile.h: $(WSHR)\tile.h # copy $(WSHR)\tile.h $@ #$(MSYS)\pctiles.h: $(MSYS)\pctiles.h # copy $(MSYS)\pctiles.h $@ #$(INCL)\pcvideo.h: $(MSYS)\pcvideo.h # copy $(MSYS)\pcvideo.h $@ #$(MSYS)\portio.h: $(MSYS)\portio.h # copy $(MSYS)\portio.h $@ # # Tile Mapping # tile.c: tilemap.exe @tilemap @echo A new $@ has been created tilemap.exe: tilemap.o @echo Linking.... @$(LINK) $(LFLAGS) @<<$(@B).lnk tilemap.o $@ $(@B) ; << tilemap.c: $(WSHR)\tilemap.c copy $(WSHR)\tilemap.c . tilemap.o: tilemap.c $(HACK_H) $(TILE_H) # # Tile Utilities # # # Required for tile support # NetHack1.tib: $(TILEFILES) tile2bin.exe @echo Creating binary tile files (this may take some time) @tile2bin NetHacko.tib: thintile.tag $(TILEFILES2) til2bin2.exe @echo Creating overview binary tile files (this may take some time) @til2bin2 tile2bin.exe: tile2bin.o $(TEXTIO) @$(LINK) $(LFLAGS) tile2bin.o $(TEXTIO),$@,$(@B); til2bin2.exe: til2bin2.o $(TEXTIO2) @$(LINK) $(LFLAGS) til2bin2.o $(TEXTIO2),$@,$(@B); thintile.exe: thintile.o @$(LINK) $(LFLAGS) thintile.o,$@,$(@B); thintile.o: $(HACK_H) $(WSHR)\tile.h $(WSHR)\thintile.c thintile.tag: thintile.exe $(TILEFILES) thintile @echo thintiles created >thintile.tag tile2bin.o: $(HACK_H) $(WSHR)\tile.h $(MSYS)\pctiles.h $(MSYS)\pcvideo.h \ $(MSYS)\tile2bin.c til2bin2.o: $(HACK_H) $(WSHR)\tile.h $(MSYS)\pctiles.h $(MSYS)\pcvideo.h \ $(MSYS)\tile2bin.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 -DOVERVIEW_FILE /Zg $(MSYS)\tile2bin.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 -DOVERVIEW_FILE /Fo$@ $(MSYS)\tile2bin.c tiletext.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\tiletext.c tiletex2.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\tiletext.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg $(WSHR)\tiletext.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Fo$@ $(WSHR)\tiletext.c tiletxt.o: $(CONFIG_H) $(WSHR)\tile.h tilemap.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Zg tilemap.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Fo$@ tilemap.c tiletxt2.o: $(CONFIG_H) $(WSHR)\tile.h tilemap.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT /Zg tilemap.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILETEXT -DTILE_X=8 /Fo$@ tilemap.c # # Optional GIF Utilities (for development) # gif2txt.exe: $(GIFREADERS) $(TEXTIO) @$(LINK) $(LFLAGS) $(GIFREADERS) $(TEXTIO),$@,$(@B); gif2txt2.exe: $(GIFREAD2) $(TEXTIO2) @$(LINK) $(LFLAGS) $(GIFREAD2) $(TEXTIO2),$@,$(@B); txt2ppm.exe: $(PPMWRITERS) $(TEXTIO) @$(LINK) $(LFLAGS) $(PPMWRITERS) $(TEXTIO),$@,$(@B); txt2ppm2.exe: $(PPMWRIT2) $(TEXTIO2) @$(LINK) $(LFLAGS) $(PPMWRIT2) $(TEXTIO2),$@,$(@B); gifread.o: $(CONFIG_H) $(WSHR)\tile.h gifread2.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\gifread.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg gifread.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 $(WSHR)\gifread.c ppmwrite.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\ppmwrite.c ppmwrit2.o: $(CONFIG_H) $(WSHR)\tile.h $(WSHR)\ppmwrite.c -@$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 /Zg ppmwrite.c >$(@B).pro @$(CC) $(CFLAGS) $(SPECOPTS) -DTILE_X=8 $(WSHR)\ppmwrite.c # # Optional tile viewer (development sources only) # viewtib.exe: viewtib.o @$(LINK) $(LFLAGS) -oviewtib.exe viewtib.o $(LIBRARIES) viewtib.o: $(MSYS)\viewtib.c # # Other Util Dependencies. # alloc.o: $(CONFIG_H) alloc.c drawing.o: $(CONFIG_H) drawing.c $(MSYS)\pcvideo.h decl.o: $(CONFIG_H) decl.c monst.o: $(CONFIG_H) $(PERMONST_H) $(ESHK_H) \ $(EPRI_H) $(VAULT_H) $(INCL)\monsym.h \ $(INCL)\color.h monst.c objects.o: $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\color.h objects.c panic.o: $(CONFIG_H) $(UTIL)\panic.c # # make data.base an 8.3 filename to prevent an nmake warning # DATABASE = $(DAT)\data.bas $(DAT)\data: $(O)utility.tag $(DATABASE) $(U)makedefs -d $(DAT)\rumors: $(O)utility.tag $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(O)utility.tag $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(O)utility.tag $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(O)utility.tag $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgn_comp dungeon.pdf cd $(SRC) # # DLB stuff # # nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(DAT)\options \ $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \ $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon \ $(DAT)\license $(O)sp_lev.tag @copy $(MSYS)\msdoshlp.txt $(DAT) @cd $(DAT) @echo data >dlb.lst @echo oracles >>dlb.lst @echo options >>dlb.lst @echo quest.dat >>dlb.lst @echo rumors >>dlb.lst @echo help >>dlb.lst @echo hh >>dlb.lst @echo cmdhelp >>dlb.lst @echo history >>dlb.lst @echo opthelp >>dlb.lst @echo wizhelp >>dlb.lst @echo dungeon >>dlb.lst @echo license >>dlb.lst @echo msdoshlp.txt >>dlb.lst @for %%N in (*.lev) do echo %%N >>dlb.lst $(U)dlb_main cvIf dlb.lst $(SRC)\nhdat @cd $(SRC) $(U)dlb_main.exe: $(DLBOBJS) link $(LFLAGS) /ST:5120 $(DLBOBJS),$@,$(@B); dlb_main.o: $(U)dlb_main.c $(INCL)\config.h $(DLB_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(U)dlb_main.c # Game Dependencies # sys/share main.o: $(SSHR)\pcmain.c $(HACK_H) $(INCL)\dlb.h \ #$(INCL)\win32api.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcmain.c sys.o: $(SSHR)\pcsys.c $(HACK_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcsys.c tty.o: $(SSHR)\pctty.c $(HACK_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pctty.c unix.o: $(SSHR)\pcunix.c $(HACK_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\pcunix.c random.o: $(SSHR)\random.c $(HACK_H) @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(SSHR)\random.c # sys/msdos msdos.o : $(HACK_H) $(MSYS)\msdos.c @$(CC) $(CFLAGS) $(SPECOPTS) $(NEWALT) /Fo$@ $(MSYS)\msdos.c pckeys.o : $(HACK_H) $(MSYS)\pckeys.c @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\pckeys.c pctiles.o : $(HACK_H) $(MSYS)\pctiles.c $(MSYS)\portio.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\pctiles.c sound.o : $(HACK_H) $(MSYS)\sound.c $(MSYS)\portio.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\sound.c video.o : $(HACK_H) $(MSYS)\pcvideo.h $(MSYS)\portio.h $(MSYS)\video.c @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\video.c vidvga.o : $(HACK_H) $(MSYS)\pcvideo.h $(MSYS)\portio.h $(TILE_H) \ $(MSYS)\vidvga.c @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\vidvga.c vidtxt.o : $(HACK_H) $(MSYS)\pcvideo.h $(MSYS)\portio.h $(TILE_H) \ $(MSYS)\vidtxt.c @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(MSYS)\vidtxt.c stubvid.o : $(HACK_H) $(MSYS)\video.c @$(CC) $(CFLAGS) $(SPECOPTS) -DSTUBVIDEO /Fo$@ $(MSYS)\video.c # win/tty getline.o: $(WIN)\getline.c $(HACK_H) $(INCL)\func_tab.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\getline.c termcap.o: $(WIN)\termcap.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\termcap.c topl.o: $(WIN)\topl.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\topl.c wintty.o: $(WIN)\wintty.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\patchlev.h $(INCL)\tcap.h @$(CC) $(CFLAGS) $(SPECOPTS) /Fo$@ $(WIN)\wintty.c # src dependencies allmain.o: allmain.c $(HACK_H) alloc.o: alloc.c $(CONFIG_H) apply.o: apply.c $(HACK_H) $(INCL)\edog.h artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h attrib.o: attrib.c $(HACK_H) $(INCL)\artifact.h ball.o: ball.c $(HACK_H) bones.o: bones.c $(HACK_H) $(INCL)\lev.h botl.o: botl.c $(HACK_H) cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h dbridge.o: dbridge.c $(HACK_H) decl.o: decl.c $(HACK_H) detect.o: detect.c $(HACK_H) $(INCL)\artifact.h dig.o: dig.c $(HACK_H) $(INCL)\edog.h display.o: display.c $(HACK_H) dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h do.o: do.c $(HACK_H) $(INCL)\lev.h do_name.o: do_name.c $(HACK_H) do_wear.o: do_wear.c $(HACK_H) dog.o: dog.c $(HACK_H) $(INCL)\edog.h dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h dokick.o: dokick.c $(HACK_H) $(INCL)\eshk.h dothrow.o: dothrow.c $(HACK_H) drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h eat.o: eat.c $(HACK_H) end.o: end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h exper.o: exper.c $(HACK_H) explode.o: explode.c $(HACK_H) extralev.o: extralev.c $(HACK_H) files.o: files.c $(HACK_H) $(INCL)\dlb.h fountain.o: fountain.c $(HACK_H) hack.o: hack.c $(HACK_H) hacklib.o: hacklib.c $(HACK_H) invent.o: invent.c $(HACK_H) $(INCL)\artifact.h light.o: light.c $(HACK_H) $(INCL)\lev.h lock.o: lock.c $(HACK_H) mail.o: mail.c $(HACK_H) $(INCL)\mail.h makemon.o: makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \ $(INCL)\edog.h mapglyph.o: mapglyph.c $(HACK_H) mcastu.o: mcastu.c $(HACK_H) mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h minion.o: minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h mklev.o: mklev.c $(HACK_H) mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h mkobj.o: mkobj.c $(HACK_H) $(INCL)\artifact.h mkroom.o: mkroom.c $(HACK_H) mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h mondata.o: mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \ $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \ $(INCL)\epri.h $(INCL)\color.h mplayer.o: mplayer.c $(HACK_H) mthrowu.o: mthrowu.c $(HACK_H) muse.o: muse.c $(HACK_H) $(INCL)\edog.h music.o: music.c $(HACK_H) #interp.c o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h objnam.o: objnam.c $(HACK_H) options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \ $(HACK_H) $(INCL)\tcap.h pager.o: pager.c $(HACK_H) $(INCL)\dlb.h @$(CC) $(CFLAGS) $(SPECOPTS) /f- /Od /Fo$@ pager.c pickup.o: pickup.c $(HACK_H) pline.o: pline.c $(HACK_H) $(INCL)\epri.h polyself.o: polyself.c $(HACK_H) potion.o: potion.c $(HACK_H) pray.o: pray.c $(HACK_H) $(INCL)\epri.h priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \ $(INCL)\epri.h $(INCL)\emin.h quest.o: quest.c $(HACK_H) $(INCL)\qtext.h questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h read.o: read.c $(HACK_H) rect.o: rect.c $(HACK_H) region.o: region.c $(HACK_H) restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h rip.o: rip.c $(HACK_H) rnd.o: rnd.c $(HACK_H) role.o: role.c $(HACK_H) rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h save.o: save.c $(HACK_H) $(INCL)\lev.h shk.o: shk.c $(HACK_H) $(INCL)\eshk.h shknam.o: shknam.c $(HACK_H) $(INCL)\eshk.h sit.o: sit.c $(HACK_H) $(INCL)\artifact.h sounds.o: sounds.c $(HACK_H) $(INCL)\edog.h sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h spell.o: spell.c $(HACK_H) steal.o: steal.c $(HACK_H) steed.o: steed.c $(HACK_H) teleport.o: teleport.c $(HACK_H) timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlev.h track.o: track.c $(HACK_H) trap.o: trap.c $(HACK_H) u_init.o: u_init.c $(HACK_H) uhitm.o: uhitm.c $(HACK_H) vault.o: vault.c $(HACK_H) $(INCL)\vault.h version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlev.h vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h weapon.o: weapon.c $(HACK_H) were.o: were.c $(HACK_H) wield.o: wield.c $(HACK_H) windows.o: windows.c $(HACK_H) $(INCL)\wingem.h wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h worm.o: worm.c $(HACK_H) $(INCL)\lev.h worn.o: worn.c $(HACK_H) write.o: write.c $(HACK_H) zap.o: zap.c $(HACK_H) # end of file nethack-3.4.3/sys/msdos/NHAccess.nh0100644000000000000000000001043107764735041015572 0ustar rootroot# SCSS Id: @(#)NHAccess.nh 3.4 1999/11/28 # Copyright (c) NetHack PC Development Team 1993, 1996, 1999 # NetHack may be freely redistributed. See license for details. # # Modified defaults.nh for blind access. Copy to working directory as # defaults.nh. # # A '#' at the beginning of a line means the rest of the line is a comment. # # This configuration file is set up for two cases, for a hard disk # (as drive C:), and for two floppy disks. # # Some options MUST be set in this file, other options can be toggled while # playing. For a list of options available see the file. If # the game plays slowly you might notice some improvement by setting # !time and !showexp, which will reduce screen I/O somewhat. # # To change the configuration, comment out the unwanted lines, and # uncomment the configuration you want. # *** OPTIONS *** # # The three options on this line should be used for most setups. # If your machine isn't very IBM-compatible, and NetHack doesn't work, # try commenting out this line. # # Note to blind players: # # Turn off IBMgraphics, using the exclamation-mark, as done below. # OPTIONS=rawio,BIOS,!IBMgraphics # Some versions of NetHack use the pc speaker to play the notes given when # playing music instruments in NetHack. To use this feature, if available, # uncomment the following line: #OPTIONS=soundcard:autodetect # If your machine is NEC PC-9800, use: #OPTIONS=rawio,BIOS,video:default # # # General options. You might also set "silent" so as not to attract # the boss's attention. # # Note for blind players: # # A lot of speech access programs use the number-pad to review the screen. # If this is the case, exclamation-mark out the number_pad option (as done # below) and use the traditional Rogue-like commands. # OPTIONS=notime,noshowexp,!number_pad,lit_corridor,!rest_on_space # # # Some options to set personal preferences. Uncomment and change these to # suit your personal preference. If several people are to use the same # configuration, options like these should not be set. # # Note to blind players: # # Use menustyle:traditional for the best interface to speech synthesizers. # #OPTIONS=name:Janet-V,female,dogname:Fido,catname:Morris,fruit:apricot #OPTIONS=autopickup,pickup_types:$"=/!?+ #OPTIONS=packorder:")[%?+/=!(*0_` #OPTIONS=scores:10 top/2 around/own #OPTIONS=nolegacy,noverbose OPTIONS=nolegacy,menustyle:traditional # *** HARD DISK CONFIGURATION *** # #HACKDIR=c:\games\nethack # # Note: Under MSDOS ports HACKDIR defaults to the location # of the NetHack.exe file. Setting HACKDIR above will override that. # # LEVELS and SAVE default to HACKDIR # #LEVELS=c:\games\nethack\bones #SAVE=c:\games\nethack\bones;n # # appending a ";n" to SAVE means don't prompt to insert a disk. SAVE=;n # # Note that RAMDISK must *not* be the same (or even implicitly # get expanded to the same path by the OS) as HACKDIR. # #RAMDISK=d: # *** 2-FLOPPY CONFIGURATION *** # # HACKDIR=a:\ # LEVELS=b:\ # SAVE=b:\ # RAMDISK=c: # *** CHARACTER GRAPHICS *** # # See the on-line help or the Guidebook for which symbols are in which # positions. # # Note to blind players: # # You very probably do not want to use these character graphics. # # If you merely set the IBMgraphics option, NetHack will use IBM # extended ASCII for dungeon characters. If you don't like the selections, # you can make up your own via these graphics options, but you should still # set IBMgraphics if you are using IBM graphics characters to get the correct # processing. # #DUNGEON= 032 124 045 124 124 124 124 045 045 045 \ # 124 124 046 045 124 043 043 035 035 046 \ # 035 035 060 062 060 062 095 124 092 035 \ # 126 126 126 126 042 042 035 035 032 035 \ # 126 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 094 094 094 094 094 \ # 094 094 # #EFFECTS= 124 095 092 047 042 033 041 040 \ # 048 035 064 042 \ # 047 045 092 058 058 092 045 047 \ # 047 045 092 058 032 058 092 045 047 # ================================================= # *** VIDEOCOLORS AND VIDEOSHADES *** # # While playing on NEC PC-9800, default game display may be difficult to # read. Try following setting. # #OPTIONS=videocolors:4-2-6-1-5-3-4-2-6-1-5-3,videoshades:normal-normal-normal nethack-3.4.3/sys/msdos/moveinit.pat0100644000000000000000000000221707764735041016157 0ustar rootroot These are patches for MOVEINIT.C, supplied with the MSVC compiler in the compiler's SOURCE\MOVE subdirectory. (Copy that and the MOVEAPI.H file into your NetHack src directory and apply this patch) *** ../linc/src/moveinit.c Tue Nov 23 08:01:00 1993 --- src/moveinit.c Sun Mar 13 10:13:10 1994 *************** *** 13,18 **** --- 13,19 ---- *******************************************************************************/ #include "moveapi.h" + extern unsigned memavail(unsigned); #ifndef MOVE_ENV *************** *** 125,132 **** /* attempt to allocate the overlay heap. ignore return value (heap size). * note that MOVE will abort if not enough memory to alloc minimum size. */ ! ! _movesetheap ($$COVL, cparaLarge, cparaMax); /* get available cache ressource amount */ --- 126,133 ---- /* attempt to allocate the overlay heap. ignore return value (heap size). * note that MOVE will abort if not enough memory to alloc minimum size. */ ! cparaMax = memavail(cparaMin); ! _movesetheap ($$COVL, cparaMin, cparaMax); /* get available cache ressource amount */ nethack-3.4.3/sys/msdos/msdos.c0100644000000000000000000002667507764735041015126 0ustar rootroot/* SCCS Id: @(#)msdos.c 3.4 2000/07/30 */ /* Copyright (c) NetHack PC Development Team 1990, 1991, 1992, 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* * MSDOS system functions. * Many thanks to Don Kneller who originated the DOS port and * contributed much to the cause. */ #define NEED_VARARGS #include "hack.h" #ifdef MSDOS #include "pcvideo.h" #include #include /* * MS-DOS functions */ #define DIRECT_INPUT 0x07 /* Unfiltered Character Input Without Echo */ #define FATINFO 0x1B /* Get Default Drive Data */ /* MS-DOS 2.0+: */ #define GETDTA 0x2F /* Get DTA Address */ #define FREESPACE 0x36 /* Get Drive Allocation Info */ #define GETSWITCHAR 0x3700 /* Get Switch Character */ #define FINDFIRST 0x4E /* Find First File */ #define FINDNEXT 0x4F /* Find Next File */ #define SETFILETIME 0x5701 /* Set File Date & Time */ /* * BIOS interrupts */ #ifdef PC9800 #define KEYBRD_BIOS 0x18 #else #define KEYBRD_BIOS 0x16 #endif /* * Keyboard BIOS functions */ #define READCHAR 0x00 /* Read Character from Keyboard */ #define GETKEYFLAGS 0x02 /* Get Keyboard Flags */ /*#define KEY_DEBUG */ /* print values of unexpected key codes - devel*/ void FDECL(get_cursor,(int *, int *)); #ifdef OVL0 /* direct bios calls are used only when iflags.BIOS is set */ static char NDECL(DOSgetch); static char NDECL(BIOSgetch); #ifndef __GO32__ static char * NDECL(getdta); #endif static unsigned int FDECL(dos_ioctl, (int,int,unsigned)); #ifdef USE_TILES extern boolean FDECL(pckeys,(unsigned char, unsigned char)); /* pckeys.c */ #endif int tgetch() { char ch; /* BIOSgetch can use the numeric key pad on IBM compatibles. */ # ifdef SIMULATE_CURSOR if (iflags.grmode && cursor_flag) DrawCursor(); # endif if (iflags.BIOS) ch = BIOSgetch(); else ch = DOSgetch(); # ifdef SIMULATE_CURSOR if (iflags.grmode && cursor_flag) HideCursor(); # endif return ((ch == '\r') ? '\n' : ch); } /* * Keyboard translation tables. */ #ifdef PC9800 #define KEYPADLO 0x38 #define KEYPADHI 0x50 #else #define KEYPADLO 0x47 #define KEYPADHI 0x53 #endif #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * When iflags.BIOS is active, shifted keypad keys are translated to the * shift values below. */ static const struct pad { char normal, shift, cntrl; } keypad[PADKEYS] = { #ifdef PC9800 {'>', '>', '>'}, /* Ins */ {'<', '<', '<'}, /* Del */ {'k', 'K', C('k')}, /* Up */ {'h', 'H', C('h')}, /* Left */ {'l', 'L', C('l')}, /* Right */ {'j', 'J', C('j')}, /* Down */ { 0 , 0 , 0 }, /* HomeClr */ {'?', '?', '?' }, /* Help */ {'m', C('p'), C('p')}, /* - */ {'/', '/', '/'}, /* / */ {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'*', '*', '*'}, /* * */ {'h', 'H', C('h')}, /* 4 */ {'g', 'g', 'g'}, /* 5 */ {'l', 'L', C('l')}, /* 6 */ {'p', 'P', C('p')}, /* + */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'=', '=', '='}, /* = */ {'i', 'I', C('i')}, /* 0 */ {',', ':', ':'}, /* , */ {'.', '.', '.'} /* . */ #else {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'h', 'H', C('h')}, /* 4 */ {'g', 'g', 'g'}, /* 5 */ {'l', 'L', C('l')}, /* 6 */ {'p', 'P', C('p')}, /* + */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ #endif }, numpad[PADKEYS] = { #ifdef PC9800 {'>', '>', '>'}, /* Ins */ {'<', '<', '<'}, /* Del */ {'8', M('8'), '8'}, /* Up */ {'4', M('4'), '4'}, /* Left */ {'6', M('6'), '6'}, /* Right */ {'2', M('2'), '2'}, /* Down */ { 0 , 0 , 0 }, /* HomeClr */ {'?', '?', '?'}, /* Help */ {'m', C('p'), C('p')}, /* - */ {'/', '/', '/'}, /* / */ {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'*', '*', '*'}, /* * */ {'4', M('4'), '4'}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'p', 'P', C('p')}, /* + */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'=', '=', '='}, /* = */ {'i', 'I', C('i')}, /* 0 */ {',', ':', ':'}, /* , */ {'.', '.', '.'} /* . */ #else {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'4', M('4'), '4'}, /* 4 */ {'5', M('5'), '5'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'p', 'P', C('p')}, /* + */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'0', M('0'), '0'}, /* Ins */ {'.', ':', ':'} /* Del */ #endif }; /* * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII * meaning unless assigned one by a keyboard conversion table, so the * keyboard BIOS normally does not return a character code when Alt-letter * is pressed. So, to interpret unassigned Alt-letters, we must use a * scan code table to translate the scan code into a letter, then set the * "meta" bit for it. -3. */ #ifdef PC9800 #define SCANLO 0x5 #else #define SCANLO 0x10 #endif /* PC9800 */ static const char scanmap[] = { /* ... */ #ifdef PC9800 0, 0, 0, 0, 0, 0, '-','^','\\','\b', '\t','q','w','e','r','t','y','u','i','o','p','@','[', '\n', 'a','s','d','f','g','h','j','k','l',';',':', ']', 'z','x','c','v','b','N','m',',','.','/' /* ... */ #else 'q','w','e','r','t','y','u','i','o','p','[',']', '\n', 0, 'a','s','d','f','g','h','j','k','l',';','\'', '`', 0, '\\', 'z','x','c','v','b','n','m',',','.','?' /* ... */ #endif /* PC9800 */ }; #define inmap(x) (SCANLO <= (x) && (x) < SCANLO + SIZE(scanmap)) #ifdef NEW_ALT #define NUMERIC_SCANLO 0x78 static const char numeric_scanmap[] = { /* ... */ '1','2','3','4','5','6','7','8','9','0','-','=' }; # define in_numericmap(x) (NUMERIC_SCANLO <= (x) && \ (x) < NUMERIC_SCANLO + SIZE(numeric_scanmap)) # endif /* * BIOSgetch gets keys directly with a BIOS call. */ #ifdef PC9800 #define SHIFT 0x1 #define KANA 0x4 #define GRPH 0x8 #define CTRL 0x10 #else #define SHIFT (0x1 | 0x2) #define CTRL 0x4 #define ALT 0x8 #endif /* PC9800 */ static char BIOSgetch() { unsigned char scan, shift, ch=0; const struct pad *kpad; union REGS regs; do { /* Get scan code. */ regs.h.ah = READCHAR; int86(KEYBRD_BIOS, ®s, ®s); ch = regs.h.al; scan = regs.h.ah; /* Get shift status. */ regs.h.ah = GETKEYFLAGS; int86(KEYBRD_BIOS, ®s, ®s); shift = regs.h.al; /* Translate keypad keys */ if (iskeypad(scan)) { kpad = iflags.num_pad ? numpad : keypad; if (shift & SHIFT) ch = kpad[scan - KEYPADLO].shift; else if (shift & CTRL) ch = kpad[scan - KEYPADLO].cntrl; else ch = kpad[scan - KEYPADLO].normal; } #ifdef USE_TILES /* Check for special interface manipulation keys */ if (pckeys(scan, shift)) { ch = 0xFF; continue; } #endif /* Translate unassigned Alt-letters */ #ifdef PC9800 if (shift & KANA) return 0; if ((shift & GRPH) && (ch >= 0x80)) { #else if ((shift & ALT) && !ch) { #endif #if 0 pline("Scan code: %d 0x%03X", scan, scan); #endif if (inmap(scan)) ch = scanmap[scan - SCANLO]; #ifdef NEW_ALT else if (in_numericmap(scan)) ch = numeric_scanmap[scan - NUMERIC_SCANLO]; #endif return (isprint(ch) ? M(ch) : ch); } } while (ch == 0xFF); return ch; } static char DOSgetch() { union REGS regs; char ch; struct pad (*kpad)[PADKEYS]; regs.h.ah = DIRECT_INPUT; intdos(®s, ®s); ch = regs.h.al; #ifdef PC9800 if (ch < 0) /* KANA letters and GRPH-shifted letters(?) */ ch = 0; /* munch it */ #else /* * The extended codes for Alt-shifted letters, and unshifted keypad * and function keys, correspond to the scan codes. So we can still * translate the unshifted cursor keys and Alt-letters. -3. */ if (ch == 0) { /* an extended key */ regs.h.ah = DIRECT_INPUT; intdos(®s, ®s); /* get the extended key code */ ch = regs.h.al; if (iskeypad(ch)) { /* unshifted keypad keys */ kpad = (void *)(iflags.num_pad ? numpad : keypad); ch = (*kpad)[ch - KEYPADLO].normal; } else if (inmap(ch)) { /* Alt-letters */ ch = scanmap[ch - SCANLO]; if (isprint(ch)) ch = M(ch); } else ch = 0; /* munch it */ } #endif return (ch); } char switchar() { union REGS regs; regs.x.ax = GETSWITCHAR; intdos(®s, ®s); return regs.h.dl; } long freediskspace(path) char *path; { union REGS regs; regs.h.ah = FREESPACE; if (path[0] && path[1] == ':') regs.h.dl = (toupper(path[0]) - 'A') + 1; else regs.h.dl = 0; intdos(®s, ®s); if (regs.x.ax == 0xFFFF) return -1L; /* bad drive number */ else return ((long) regs.x.bx * regs.x.cx * regs.x.ax); } #ifndef __GO32__ /* * Functions to get filenames using wildcards */ int findfirst_file(path) char *path; { union REGS regs; struct SREGS sregs; regs.h.ah = FINDFIRST; regs.x.cx = 0; /* attribute: normal files */ regs.x.dx = FP_OFF(path); sregs.ds = FP_SEG(path); intdosx(®s, ®s, &sregs); return !regs.x.cflag; } int findnext_file() { union REGS regs; regs.h.ah = FINDNEXT; intdos(®s, ®s); return !regs.x.cflag; } char * foundfile_buffer() { return (getdta() + 30); } /* Get disk transfer area */ static char * getdta() { union REGS regs; struct SREGS sregs; char *ret; regs.h.ah = GETDTA; intdosx(®s, ®s, &sregs); # ifdef MK_FP ret = (char *)MK_FP(sregs.es, regs.x.bx); # else FP_OFF(ret) = regs.x.bx; FP_SEG(ret) = sregs.es; # endif return ret; } long filesize_nh(file) char *file; { char *dta; if (findfirst_file(file)) { dta = getdta(); return (* (long *) (dta + 26)); } else return -1L; } #endif /* __GO32__ */ /* * Chdrive() changes the default drive. */ void chdrive(str) char *str; { # define SELECTDISK 0x0E char *ptr; union REGS inregs; char drive; if ((ptr = index(str, ':')) != (char *)0) { drive = toupper(*(ptr - 1)); inregs.h.ah = SELECTDISK; inregs.h.dl = drive - 'A'; intdos(&inregs, &inregs); } return; } /* Use the IOCTL DOS function call to change stdin and stdout to raw * mode. For stdin, this prevents MSDOS from trapping ^P, thus * freeing us of ^P toggling 'echo to printer'. * Thanks to Mark Zbikowski (markz@microsoft.UUCP). */ #define DEVICE 0x80 #define RAW 0x20 #define IOCTL 0x44 #define STDIN fileno(stdin) #define STDOUT fileno(stdout) #define GETBITS 0 #define SETBITS 1 static unsigned int old_stdin, old_stdout; void disable_ctrlP() { if (!iflags.rawio) return; old_stdin = dos_ioctl(STDIN, GETBITS, 0); old_stdout = dos_ioctl(STDOUT, GETBITS, 0); if (old_stdin & DEVICE) dos_ioctl(STDIN, SETBITS, old_stdin | RAW); if (old_stdout & DEVICE) dos_ioctl(STDOUT, SETBITS, old_stdout | RAW); return; } void enable_ctrlP() { if (!iflags.rawio) return; if (old_stdin) (void) dos_ioctl(STDIN, SETBITS, old_stdin); if (old_stdout) (void) dos_ioctl(STDOUT, SETBITS, old_stdout); return; } static unsigned int dos_ioctl(handle, mode, setvalue) int handle, mode; unsigned setvalue; { union REGS regs; regs.h.ah = IOCTL; regs.h.al = mode; regs.x.bx = handle; regs.h.dl = setvalue; regs.h.dh = 0; /* Zero out dh */ intdos(®s, ®s); return (regs.x.dx); } # endif /* OVLB */ #endif /* MSDOS */ nethack-3.4.3/sys/msdos/msdoshlp.txt0100644000000000000000000001632307764735041016214 0ustar rootroot MSDOS specific help file for NetHack 3.4.3 (Last Revision: March 16, 2003) Copyright (c) NetHack PC Development Team 1993-2003. NetHack may be freely distributed. See license for details. New players should be sure to read GuideBoo.txt which contains essential information about playing NetHack. It can be found in the same directory as your NetHack executable. The MSDOS port of NetHack supports some additional or enhanced commands as well as some defaults.nh file options specific to configuration choices used during the building of PC NetHack. Listed below are those commands and defaults.nh file options. Recognized MSDOS specific defaults.nh entries are outlined below. Boolean Options: IBMgraphics Use IBM extended characters for the dungeon Default: [FALSE] BIOS Allow the use of IBM ROM BIOS calls Default: [FALSE] rawio Allow the use of raw I/O (may only be set on startup) Default: [FALSE] preload_tiles Preload tiles into RAM at start of game. Faster, but uses more memory. Default: [TRUE] Color Options: OPTIONS=!color Players will need this if they have a real, true, (old) monochrome adapter, and they are seeing underlined, and flashing, and reverse-video characters on the screen. Or they find that some things are missing from the display. This means that the auto-detection for monochromes has failed. The color support stuff is active in video.c, but may be (will have to be) overridden by adding an OPTIONS=nocolor to defaults.nh. OPTIONS=VIDEO (defaults.nh only) ie: OPTIONS=video:autodetect Possible values are: AUTODETECT, DEFAULT, VGA AUTODETECT Checks for a supported hi-res video adaptor, and if it detects one, NetHack will run in "TILE MODE." DEFAULT NetHack will run in TTY mode. This is the same as not specifying OPTIONS=VIDEO at all. VGA Forces use of VGA specific video routines. Any forcing of specific video routines has potential to cause machine lock-ups if the specified video hardware is not present. OPTIONS=VIDEOSHADES (defaults.nh only) Players may wish to add this option because one of their shades of gray is difficult to read on their video display hardware. Allows a level of intensity to be assigned to the 3 possible shades of gray in NetHack, those being BLACK, GRAY, WHITE. To each of those shades, the player may assign a DARK, NORMAL, or LIGHT value. Here is the default if not specified: ie. OPTIONS=VIDEOSHADES:dark-normal-light Anytime the same intensity value (DARK NORMAL LIGHT) is used for more than one shade of gray, it will not be possible to visually distinguish those two shades from each other. ie. OPTIONS=VIDEOSHADES:normal-normal-light This, while eliminating the dark shade normally used for displaying black items, means that the player won't be able to distinguish black items and creatures from gray items and creatures visually. Note also that the controversial gray schema used in pl 3.1.2 as the default, corresponded to: OPTIONS=VIDEOSHADES:normal-dark-normal This is NOT the default in pl 3.1.3 and above, so many people will probably not even need to use this option, and will find the default just fine. The maps are built using gray, and in pl 3.1.3, that is mapped to normal by default. In 3.1.2, it was mapped to dark (as above). OPTIONS=VIDEOCOLORS (defaults.nh only) This option is only provided because some people on r.g.r.n mentioned how they liked to modify the color values from the default ANSI.SYS behaviour, and were "upset" to find out that they could no longer do so under 3.1.2. The color map is as accurate as possible on standard PC video hardware as it stands, and any deviation from the default, will mean that people are mapping blue to green for example. The option is available to provide as much flexibility as possible, but it is not encouraged to be used. One possible use might be for the dark blue in fountains. On video hardware that has trouble displaying blacks, there may also be problems displaying the darker blue used in fountains. If that is the case then the default map: OPTIONS=VIDEOCOLORS:4-2-6-1-5-3-12-10-14-9-13-11 could be changed to the following to map blue to br. blue: OPTIONS=VIDEOCOLORS:4-2-6-9-5-3-12-10-14-9-13-11 The mapping order for the options: red, green, brown, blue, magenta, cyan br.red, br.green, yellow, br.blue, br.magenta, br.cyan The PC hardware uses the following values: red(4), green(2), brown(6), blue(1), magenta(5), cyan(3), bright red(12), bright green(10), yellow(14), bright blue(9), bright magenta(13), bright cyan(11), normal white(7), bright white(15). The following options are NOT currently recognized under the MSDOS port of PC NetHack: LEVELS= Where to store/create per level data files. SAVE= Where to save games. BONES= Where to store bones files. MSDOS Additional/Enhanced Commands: If you have opted to use the "graphical" or "tiled" option, (usually set via OPTIONS=VIDEO:AUTODETECT ((see above)), then the following function keys are active: F3 cycle through the current position indicator, or halo. Usually this halo highlights the player's tile, unless the game is asking you for an answer to a question that requires positional information, (ie, the discover command). F4 toggle level overview mode on/off F5 toggle tiled display on/off. (Switches between tiled and traditional ASCII display.) While playing NetHack under MSDOS you can press the ALT key in combination with another key to execute an extended command as an alternative method to pressing a # key sequence: Alt-2 twoweapon - toggle two-weapon combat Alt-a adjust - adjust inventory letters. Alt-c chat - talk to someone or something. Alt-d dip - dip an object into something. Alt-e enhance - enhance your skill with a weapon. Alt-f force - force a lock. Alt-i invoke - invoke an object's powers. Alt-j jump - jump to a location. Alt-l loot - loot a box on the floor. Alt-m monster - use a monster's special ability. Alt-n name - name an item or type of object. Alt-o offer - offer a sacrifice to the gods. Alt-p pray - pray to the gods for help. Alt-q quit - quit the game. (Same as #quit) Alt-r rub - rub a lamp. Alt-s sit - sit down. Alt-t turn - turn undead. Alt-u untrap - untrap something. Alt-v version - list compile time options for this version of NetHack. Alt-w wipe - wipe off your face. If you are playing on NEC PC-9800, use the GRPH key instead of the ALT key. nethack-3.4.3/sys/msdos/nhico.uu0100644000000000000000000000235707764735041015277 0ustar rootrootsection 1 of uuencode 4.13 of file NETHACK.ICO by R.E.M. begin 644 NETHACK.ICO M```!``$`("`0``````#H`@``%@```"@````@````0`````$`!```````@`(`. M``````````````````````````````"```"`````@(``@````(``@`"`@```6 M@("``,#`P````/\``/\```#__P#_````_P#_`/__``#___\`]F9F9F9F9F9F* M9F9F9F9F9O]F9F9F9F9F9F9F9F9F9F;_B(B(B(B(B(B(B(B(B&9F_XB(B(B(D MB(B(B(B(B(AF9O^(B(B(A555B(B(B(B(9F;_B(B(B`!5!8B(B(B(B&9F_XB(' MB(@```6(B(B(B(AF9O^(B%554`!56(B(B(B(9F;_B(N[N[`.XU6(B(B(B&9F[ M_XB[N[L`ONXU6(B(B(AF9O^+N[N[N[ONXUB(B(B(9F;_B[N[N[N[ONY3B(B(N MB&9F_XN[NYF9F[ONXSB(B(AF9O^+N[F9F9F[ONXSB(B(9F;_B[N9F9F9F[ON? MXSB(B&9F_XNYF9F9F9F[7NXSB(AF9O^+N9F9F9F9NUCNXSB(9F;_B[F9F9F9J MF;M8CNXSB&9F_XNYF9F9F9F[6(CNXXAF9O^+N9F9F9F9NUB(CNZ(9F;_B[N9] MF9F9F[M8B(CNB&9F_XN[N9F9F;N[6(B(B(AF9O^+N[N9F9N[NUB(B(B(9F;_R MB[N[N[N[N[M8B(B(B&9F_XN[N[N[N[N[B(B(B(AF9O^+NXB(B(B+NXB(B(B(F M9F;_B[B(B(B(B+N(B(B(B&9F_XB(B(B(B(B(B(B(B(AF9O^(B(B(B(B(B(B(J MB(B(9F;_B(B(B(B(B(B(B(B(B&9F___________________V9O__________% M__________\`````````````````````````````````````````````````R M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` !````` `` end sum -r/size 23881/1107 section (from "begin" to "end") sum -r/size 55184/766 entire input file nethack-3.4.3/sys/msdos/nhpif.uu0100644000000000000000000000141607764735041015276 0ustar rootrootbegin 666 nethack.pif M`%M00R!.971H86-K(#,N,2`@("`@("`@("`@("`@(""``(``0SI<3D542$%# M2UQ.151(04-++D5810`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@$`!#.EQ.151(04-+`"`@("`@("`@("`@("`@("`@("`@("`@ M("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@```````````````````` M```````````````````````````````````````````````````````````` M```````!`/\94```!P`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````.`@34E#4D]33T94(%!)1D58`( #include #ifdef _MSC_VER #define RESERVED_PARAGRAPHS 5120 /* leave 80K for malloc and inits */ /* subject to change before release */ /* * memavail() Returns the amount of RAM available (in paragraphs which are 16 * bytes) - the amount to be reserved for heap allocations. * */ unsigned memavail(minovl) unsigned minovl; /* minimum size of overlay heap */ { unsigned available; unsigned farparaavail; unsigned tmp; /* * _dos_allocmem will return the maximum block size available. * It uses DOS (int 21h) service 0x48. */ _dos_allocmem(0xFFFF, &farparaavail); available = farparaavail - RESERVED_PARAGRAPHS; tmp = RESERVED_PARAGRAPHS + minovl; if (farparaavail < tmp) { panic("Not enough free RAM to begin a game of NetHack (%ld bytes)", (long)((long)tmp * 16L)); } return available; } #endif /*_MSC_VER*/ #ifdef __BORLANDC__ #define RSRVD_MALLOC 65 * 1024L /* malloc() calls use about 65K */ #define RSRVD_CRTL 50 * 1024L /* C runtime library uses 50K */ #define RSRVD_TOTAL 115 * 1024L /* reserved for use in malloc() */ /* as well as by C runtime library */ /* routines which allocate memory */ /* after this routine runs. */ #define MIN_OVRBUF 30 * 1024L /* Overlay buffer gets minimum of */ #define MAX_OVRBUF 200 * 1024L /* 30K and maximum of 200K. */ #define RESIZE_OVL #ifdef RESIZE_OVL extern unsigned _ovrbuffer = 0; /* Use default size initially */ unsigned appFail = 0; /* Fail flag if not enough RAM */ unsigned memAlloc = 0; unsigned long ProgramSize; unsigned long runAlloc; unsigned far *mem_top; unsigned total; signed long tmpbuffer; int emsstatus; int xmsstatus; void NDECL(_resizeOvrBuffer); void _resizeOvrBuffer() { mem_top = (unsigned far *) MK_FP( _psp, 0x02 ); total = *mem_top - _psp; ProgramSize = * (unsigned far *) MK_FP( _psp - 1, 0x03 ); tmpbuffer = total - ProgramSize - RSRVD_TOTAL / 16; memAlloc = min (MAX_OVRBUF / 16, tmpbuffer); if (tmpbuffer >= MIN_OVRBUF / 16) _ovrbuffer = memAlloc; else { _ovrbuffer = 1; appFail = 1; }; /* * Remember, when inside this code, nothing has been setup on * the system, so do NOT call any RTL functions for I/O or * anything else that might rely on a startup function. This * includes accessing any global objects as their constructors * have not been called yet. */ } #pragma startup _resizeOvrBuffer 0 /* Put function in table */ void startup () { if (appFail) { printf ("NetHack fits in memory, but it cannot allocate memory"); printf (" for the overlay buffer\nand the runtime functions. "); printf ("Please free up just %ld more bytes.", (long)(MIN_OVRBUF - tmpbuffer * 16L)); exit (-1); } else { /* Now try to use expanded memory for the overlay manager */ /* If that doesn't work, we revert to extended memory */ emsstatus = _OvrInitEms (0, 0, 0); #ifdef RECOGNIZE_XMS xmsstatus = (emsstatus) ? _OvrInitExt (0, 0) : -1; #endif } } void show_borlandc_stats(win) winid win; { char buf[BUFSZ]; putstr(win, 0, ""); putstr(win, 0, ""); putstr(win, 0, "Memory usage stats"); putstr(win, 0, ""); putstr(win, 0, ""); Sprintf (buf, "Overlay buffer memory allocation: %ld bytes.", memAlloc * 16L); putstr(win, 0, buf); Sprintf (buf, "_ovrbuffer = %u.", _ovrbuffer); putstr(win, 0, buf); Sprintf (buf, "Startup memory usage: 0x%X", ProgramSize); putstr(win, 0, buf); runAlloc = * (unsigned far *) MK_FP( _psp - 1, 0x03); Sprintf (buf, "Current memory usage: 0x%X", runAlloc); putstr(win, 0, buf); if (emsstatus) Sprintf (buf, "EMS search failed (%d).", emsstatus); else Sprintf (buf, "EMS search successful."); putstr(win, 0, buf); #ifdef RECOGNIZE_XMS if (xmsstatus) Sprintf (buf, "XMS search failed (%d).", xmsstatus); else Sprintf (buf, "XMS search successful."); putstr(win, 0, buf); #endif } #endif /* #ifdef RESIZE_OVL */ #endif /* #ifdef __BORLANDC__ */ /*ovlinit.c*/ nethack-3.4.3/sys/msdos/pckeys.c0100644000000000000000000000374107764735041015264 0ustar rootroot/* SCCS Id: @(#)pckeys.c 3.4 1996/05/11 */ /* Copyright (c) NetHack PC Development Team 1996 */ /* NetHack may be freely redistributed. See license for details. */ /* * MSDOS tile-specific key handling. */ #include "hack.h" #ifdef MSDOS # ifdef USE_TILES #include "wintty.h" #include "pcvideo.h" boolean FDECL(pckeys, (unsigned char, unsigned char)); extern struct WinDesc *wins[MAXWIN]; /* from wintty.c */ extern boolean inmap; /* from video.c */ #define SHIFT (0x1 | 0x2) #define CTRL 0x4 #define ALT 0x8 /* * Check for special interface manipulation keys. * Returns TRUE if the scan code triggered something. * */ boolean pckeys(scancode, shift) unsigned char scancode; unsigned char shift; { boolean opening_dialog; opening_dialog = pl_character[0] ? FALSE : TRUE; # ifdef SIMULATE_CURSOR switch(scancode) { case 0x3d: /* F3 = toggle cursor type */ HideCursor(); cursor_type += 1; if (cursor_type >= NUM_CURSOR_TYPES) cursor_type = 0; DrawCursor(); break; # endif case 0x74: /* Control-right_arrow = scroll horizontal to right */ if ((shift & CTRL) && iflags.tile_view && !opening_dialog) vga_userpan(1); break; case 0x73: /* Control-left_arrow = scroll horizontal to left */ if ((shift & CTRL) && iflags.tile_view && !opening_dialog) vga_userpan(0); break; case 0x3E: /* F4 = toggle overview mode */ if (iflags.tile_view && !opening_dialog #ifdef REINCARNATION && !Is_rogue_level(&u.uz) #endif ) { iflags.traditional_view = FALSE; vga_overview(iflags.over_view ? FALSE : TRUE); vga_refresh(); } break; case 0x3F: /* F5 = toggle traditional mode */ if (iflags.tile_view && !opening_dialog #ifdef REINCARNATION && !Is_rogue_level(&u.uz) #endif ) { iflags.over_view = FALSE; vga_traditional(iflags.traditional_view ? FALSE : TRUE); vga_refresh(); } break; default: return FALSE; } return TRUE; } # endif /* USE_TILES */ #endif /* MSDOS */ /*pckeys.c*/ nethack-3.4.3/sys/msdos/pctiles.c0100644000000000000000000001462507764735041015434 0ustar rootroot/* SCCS Id: @(#)pctiles.c 3.4 1995/07/31 */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * pctiles.c - PC Graphical Tile Support Routines * *Edit History: * Initial Creation M. Allison 93/10/30 * */ #include "hack.h" #ifdef USE_TILES #if defined(__GO32__) || defined(__DJGPP__) #include #define TILES_IN_RAM /* allow tiles to be read into ram */ #endif # if defined(_MSC_VER) # if _MSC_VER >= 700 #pragma warning(disable:4018) /* signed/unsigned mismatch */ #pragma warning(disable:4127) /* conditional expression is constant */ #pragma warning(disable:4131) /* old style declarator */ #pragma warning(disable:4309) /* initializing */ # endif #include # endif #include "pcvideo.h" #include "tile.h" #include "pctiles.h" STATIC_VAR FILE *tilefile; STATIC_VAR FILE *tilefile_O; extern short glyph2tile[]; /* in tile.c (made from tilemap.c) */ #ifdef TILES_IN_RAM struct planar_cell_struct *ramtiles; struct overview_planar_cell_struct *oramtiles; boolean tiles_in_ram = FALSE; boolean otiles_in_ram = FALSE; extern int total_tiles_used; /* tile.c */ #endif # ifdef OVLB /* * Read the header/palette information at the start of the * NetHack.tib file. * * There is 1024 bytes (1K) of header information * at the start of the file, including a palette. * */ int ReadTileFileHeader(tibhdr, filestyle) struct tibhdr_struct *tibhdr; boolean filestyle; { FILE *x; x = filestyle ? tilefile_O : tilefile; if (fseek(x,0L,SEEK_SET)) { return 1; } else { fread(tibhdr, sizeof(struct tibhdr_struct), 1, x); } return 0; } /* * Open the requested tile file. * * NetHack1.tib file is a series of * 'struct planar_tile_struct' structures, one for each * glyph tile. * * NetHack2.tib file is a series of * char arrays [TILE_Y][TILE_X] in dimensions, one for each * glyph tile. * * There is 1024 bytes (1K) of header information * at the start of each .tib file. The first glyph tile starts at * location 1024. * */ int OpenTileFile(tilefilename, filestyle) char *tilefilename; boolean filestyle; { #ifdef TILES_IN_RAM int k; #endif if (filestyle) { tilefile_O = fopen(tilefilename,"rb"); if (tilefile_O == (FILE *)0) return 1; } else { tilefile = fopen(tilefilename,"rb"); if (tilefile == (FILE *)0) return 1; } #ifdef TILES_IN_RAM if (iflags.preload_tiles) { if (filestyle) { struct overview_planar_cell_struct *gp; long ram_needed = sizeof(struct overview_planar_cell_struct) * total_tiles_used; if (fseek(tilefile_O,(long)TIBHEADER_SIZE, SEEK_SET)) { /*failure*/ } oramtiles = (struct overview_planar_cell_struct *)alloc(ram_needed); /* Todo: fall back to file method here if alloc failed */ gp = oramtiles; for(k=0; k < total_tiles_used; ++k) { fread(gp, sizeof(struct overview_planar_cell_struct), 1, tilefile_O); ++gp; } #ifdef DEBUG_RAMTILES pline("%d overview tiles read into ram.", k); mark_synch(); #endif otiles_in_ram = TRUE; } else { struct planar_cell_struct *gp; long ram_needed = sizeof(struct planar_cell_struct) * total_tiles_used; if (fseek(tilefile,(long)TIBHEADER_SIZE, SEEK_SET)) { /*failure*/ } ramtiles = (struct planar_cell_struct *)alloc(ram_needed); /* Todo: fall back to file method here if alloc failed */ gp = ramtiles; for(k=0; k < total_tiles_used; ++k) { fread(gp, sizeof(struct planar_cell_struct), 1, tilefile); ++gp; } #ifdef DEBUG_RAMTILES pline("%d tiles read into ram.", k); mark_synch(); #endif tiles_in_ram = TRUE; } } #endif return 0; } void CloseTileFile(filestyle) boolean filestyle; { fclose(filestyle ? tilefile_O : tilefile); #ifdef TILES_IN_RAM if (!filestyle && tiles_in_ram) { if (ramtiles) free((genericptr_t) ramtiles); tiles_in_ram = FALSE; } else if (filestyle && otiles_in_ram) { if (oramtiles) free((genericptr_t) oramtiles); otiles_in_ram = FALSE; } #endif } # endif /* OVLB */ # ifdef OVL0 struct planar_cell_struct plancell; struct overview_planar_cell_struct oplancell; /* This routine retrieves the requested NetHack glyph tile * from the planar style binary .tib file. * This is currently done 'on demand', so if the player * is running without a disk cache (ie. smartdrv) operating, * things can really be slowed down. We don't have any * base memory under MSDOS, in which to store the pictures. * * Todo: Investigate the possibility of loading the glyph * tiles into extended or expanded memory using * the MSC virtual memory routines. * * Under an environment like djgpp, it should be possible to * read the entire set of glyph tiles into a large * array of 'struct planar_cell_struct' structures at * game initialization time, and recall them from the array * as needed. That should speed things up (at the cost of * increasing the memory requirement - can't have everything). * */ # ifdef PLANAR_FILE int ReadPlanarTileFile(tilenum,gp) int tilenum; struct planar_cell_struct **gp; { long fpos; #ifdef TILES_IN_RAM if (tiles_in_ram) { *gp = ramtiles + tilenum; return 0; } #endif fpos = ((long)(tilenum) * (long)sizeof(struct planar_cell_struct)) + (long)TIBHEADER_SIZE; if (fseek(tilefile,fpos,SEEK_SET)) { return 1; } else { fread(&plancell, sizeof(struct planar_cell_struct), 1, tilefile); } *gp = &plancell; return 0; } int ReadPlanarTileFile_O(tilenum,gp) int tilenum; struct overview_planar_cell_struct **gp; { long fpos; #ifdef TILES_IN_RAM if (otiles_in_ram) { *gp = oramtiles + tilenum; return 0; } #endif fpos = ((long)(tilenum) * (long)sizeof(struct overview_planar_cell_struct)) + (long)TIBHEADER_SIZE; if (fseek(tilefile_O,fpos,SEEK_SET)) { return 1; } else { fread(&oplancell, sizeof(struct overview_planar_cell_struct), 1, tilefile_O); } *gp = &oplancell; return 0; } # endif # ifdef PACKED_FILE int ReadPackedTileFile(tilenum,pta) int tilenum; char (*pta)[TILE_X]; { long fpos; fpos = ((long)(tilenum) * (long)(TILE_Y * TILE_X) + (long)TIBHEADER_SIZE; if (fseek(tilefile,fpos,SEEK_SET)) { return 1; } else { fread(pta, (TILE_Y * TILE_X), 1, tilefile); } return 0; } # endif # endif /* OVL0 */ #endif /* USE_TILES */ /* pctiles.c */ nethack-3.4.3/sys/msdos/pctiles.h0100644000000000000000000000420107764735041015426 0ustar rootroot/* SCCS Id: @(#)pctiles.h 3.4 1994/04/04 */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * pctiles.h - Definitions for PC graphical tile support * *Edit History: * Initial Creation M. Allison 93/10/30 * */ #ifdef USE_TILES #define NETHACK_PLANAR_TILEFILE "NetHack1.tib" /* Planar style tiles */ #define NETHACK_PACKED_TILEFILE "NetHack2.tib" /* Packed style tiles */ #define NETHACK_OVERVIEW_TILEFILE "NetHacko.tib" /* thin overview tiles */ #define ROWS_PER_TILE TILE_Y #define COLS_PER_TILE TILE_X #define EMPTY_TILE -1 #define TIBHEADER_SIZE 1024 /* Use this for size, allows expansion */ #define PLANAR_STYLE 0 #define PACKED_STYLE 1 #define DJGPP_COMP 0 #define MSC_COMP 1 #define BC_COMP 2 #define OTHER_COMP 10 struct tibhdr_struct { char ident[80]; /* Identifying string */ char timestamp[26]; /* Ascii timestamp */ char tilestyle; /* 0 = planar, 1 = pixel */ char compiler; /* 0 = DJGPP, 1 = MSC, 2= BC etc. see above */ short tilecount; /* number of tiles in file */ short numcolors; /* number of colors in palette */ char palette[256 * 3]; /* palette */ }; /* Note on packed style tile file: * Each record consists of one of the following arrays: * char packtile[TILE_Y][TILE_X]; */ extern void FDECL(CloseTileFile, (BOOLEAN_P)); extern int FDECL(OpenTileFile, (char *, BOOLEAN_P)); extern int FDECL(ReadTileFileHeader, (struct tibhdr_struct *, BOOLEAN_P)); # ifdef PLANAR_FILE # ifdef SCREEN_VGA extern int FDECL(ReadPlanarTileFile,(int, struct planar_cell_struct **)); extern int FDECL(ReadPlanarTileFile_O, (int, struct overview_planar_cell_struct **)); # endif # endif # ifdef PACKED_FILE extern int FDECL(ReadPackedTileFile, (int, char (*)[TILE_X])); # endif extern short glyph2tile[MAX_GLYPH]; /* in tile.c (made from tilemap.c) */ #endif /* USE_TILES */ /* pctiles.h */ nethack-3.4.3/sys/msdos/pcvideo.h0100644000000000000000000002027107764735041015421 0ustar rootroot/* SCCS Id: @(#)pcvideo.h 3.4 1994/06/07 */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * pcvideo.h - Hardware video support definitions and prototypes * *Edit History: * Initial Creation M. Allison 93/10/30 * */ #ifndef PCVIDEO_H #define PCVIDEO_H #include "portio.h" # ifdef SCREEN_BIOS # if !defined(PC9800) # define MONO_CHECK /* Video BIOS can do the check */ # endif # endif # ifdef SCREEN_DJGPPFAST /*# define MONO_CHECK /* djgpp should be able to do check */ # endif /* * PC interrupts */ # ifdef PC9800 #define CRT_BIOS 0x18 #define DOS_EXT_FUNC 0xdc #define DIRECT_CON_IO 0x10 # else #define VIDEO_BIOS 0x10 # endif #define DOSCALL 0x21 /* * Video BIOS functions */ # if defined(PC9800) #define SENSEMODE 0x0b /* Sense CRT Mode */ #define PUTCHAR 0x00 /* Put Character */ #define SETATT 0x02 /* Set Attribute */ #define SETCURPOS 0x03 /* Set Cursor Position */ #define CURSOR_RIGHT 0x08 /* Move Cursor Right */ #define CURSOR_LEFT 0x09 /* Move Cursor Left */ #define SCREEN_CLEAR 0x0a /* Clear Screen */ #define LINE_CLEAR 0x0b /* Clear Line */ # else #define SETCURPOS 0x02 /* Set Cursor Position */ # endif #define GETCURPOS 0x03 /* Get Cursor Position */ #define GETMODE 0x0f /* Get Video Mode */ #define SETMODE 0x00 /* Set Video Mode */ #define SETPAGE 0x05 /* Set Video Page */ #define FONTINFO 0x1130 /* Get Font Info */ #define SCROLL 0x06 /* Scroll or initialize window */ #define PUTCHARATT 0x09 /* Write attribute & char at cursor */ /* * VGA Specific Stuff */ # ifdef SCREEN_VGA /* #define HW_PANNING /* Hardware panning enabled */ #define USHORT unsigned short #define MODE640x480 0x0012 /* Switch to VGA 640 x 480 Graphics mode */ #define MODETEXT 0x0003 /* Switch to Text mode 3 */ #ifdef HW_PANNING #define PIXELINC 16 /* How much to increment by when panning */ /*#define PIXELINC 1 /* How much to increment by when panning */ #define SCREENBYTES 128 #define CharRows 30 #define VERT_RETRACE {while (!(inportb(crt_status) & 0x08)); } #define VERT_RETRACE_END {while ( (inportb(crt_status) & 0x08)); } #else #define SCREENBYTES 80 #endif #define CharacterWidth 8 #define SCREENHEIGHT 480 #define SCREENWIDTH (SCREENBYTES * CharacterWidth) #define VIDEOSEG 0xa000 #define FONT_PTR_SEGMENT 0x0000 #define FONT_PTR_OFFSET 0x010C #define SCREENPLANES 4 #define COLORDEPTH 16 #define egawriteplane(n) { outportb(0x3c4,2); outportb(0x3c5,n); } #define egareadplane(n) { outportb(0x3ce,4); outportb(0x3cf,n); } #define col2x8(c) ((c) * 8) #define col2x16(c) ((c) * 16) #define col2x(c) ((c) * 2) #define row2y(c) ((c) * 16) #define MAX_ROWS_PER_CELL 16 #define MAX_COLS_PER_CELL 16 #define MAX_BYTES_PER_CELL 2 /* MAX_COLS_PER_CELL/8 */ #define ROWS_PER_CELL MAX_ROWS_PER_CELL #define COLS_PER_CELL MAX_COLS_PER_CELL #define BYTES_PER_CELL MAX_BYTES_PER_CELL struct cellplane { char image[MAX_ROWS_PER_CELL][MAX_BYTES_PER_CELL]; }; struct planar_cell_struct { struct cellplane plane[SCREENPLANES]; }; struct overview_cellplane { char image[MAX_ROWS_PER_CELL][1]; }; struct overview_planar_cell_struct { struct overview_cellplane plane[SCREENPLANES]; }; # endif /* SCREEN_VGA */ /* * Default color Indexes for hardware palettes * * Do not change the values below. * These are the color mappings defined by the particular video * hardware/mode. You can rearrange the NetHack color mappings at * run-time via the defaults.nh "videocolors" and "videoshades" * settings. * */ # if defined(SCREEN_BIOS) || defined(SCREEN_DJGPPFAST) #define M_BLACK 8 #define M_WHITE 15 #define M_GRAY 7 /* low-intensity white */ #define M_RED 4 #define M_GREEN 2 #define M_BROWN 6 /* low-intensity yellow */ #define M_BLUE 1 #define M_MAGENTA 5 #define M_CYAN 3 #define M_ORANGE 12 #define M_BRIGHTGREEN 10 #define M_YELLOW 14 #define M_BRIGHTBLUE 9 #define M_BRIGHTMAGENTA 13 #define M_BRIGHTCYAN 11 #define M_TEXT M_GRAY #define BACKGROUND_COLOR 0 #define ATTRIB_NORMAL M_TEXT /* Normal attribute */ #define ATTRIB_INTENSE M_WHITE /* Intense White */ #define ATTRIB_MONO_NORMAL 0x01 /* Underlined,white */ #define ATTRIB_MONO_UNDERLINE 0x01 /* Underlined,white */ #define ATTRIB_MONO_BLINK 0x87 /* Flash bit, white */ #define ATTRIB_MONO_REVERSE 0x70 /* Black on white */ # endif /*SCREEN_BIOS || SCREEN_DJGPPFAST */ # if defined(SCREEN_VGA) || defined(SCREEN_8514) #define BACKGROUND_VGA_COLOR 0 #define ATTRIB_VGA_NORMAL CLR_GRAY /* Normal attribute */ #define ATTRIB_VGA_INTENSE 13 /* Intense White 94/06/07 palette chg*/ # endif /*SCREEN_VGA || SCREEN_8514*/ # if defined(PC9800) static unsigned char attr98[CLR_MAX] = { 0xe1, /* 0 white */ 0x21, /* 1 blue */ 0x81, /* 2 green */ 0xa1, /* 3 cyan */ 0x41, /* 4 red */ 0x61, /* 5 magenta */ 0xc1, /* 6 yellow */ 0xe1, /* 7 white */ 0xe1, /* 8 white */ 0x25, /* 9 reversed blue */ 0x85, /* 10 reversed green */ 0xa5, /* 11 reversed cyan */ 0x45, /* 12 reversed red */ 0x65, /* 13 reversed magenta */ 0xc5, /* 14 reversed yellow */ 0xe5, /* 15 reversed white */ }; # endif # ifdef SIMULATE_CURSOR #define CURSOR_HEIGHT 3 /* this should go - MJA */ /* cursor styles */ #define CURSOR_INVIS 0 /* cursor not visible at all */ #define CURSOR_FRAME 1 /* block around the current tile */ #define CURSOR_UNDERLINE 2 /* thin line at bottom of the tile */ #define CURSOR_CORNER 3 /* cursor visible at the 4 tile corners */ #define NUM_CURSOR_TYPES 4 /* number of different cursor types */ #define CURSOR_DEFAULT_STYLE CURSOR_CORNER #define CURSOR_DEFAULT_COLOR M_GRAY /* global variables for cursor */ extern int cursor_type; extern int cursor_flag; extern int cursor_color; # endif /* * Function Prototypes * */ #define E extern /* ### video.c ### */ # ifdef SIMULATE_CURSOR E void NDECL(DrawCursor); E void NDECL(HideCursor); # endif /* ### vidtxt.c ### */ # ifdef NO_TERMS E void NDECL(txt_backsp); E void NDECL(txt_clear_screen); E void FDECL(txt_cl_end,(int,int)); E void NDECL(txt_cl_eos); E void NDECL(txt_get_scr_size); E void FDECL(txt_gotoxy,(int,int)); E int NDECL(txt_monoadapt_check); E void NDECL(txt_nhbell); E void FDECL(txt_startup,(int*,int*)); E void FDECL(txt_xputs, (const char *, int, int)); E void FDECL(txt_xputc, (CHAR_P, int)); /* ### vidvga.c ### */ # ifdef SCREEN_VGA E void NDECL(vga_backsp); E void FDECL(vga_clear_screen,(int)); E void FDECL(vga_cl_end,(int,int)); E void FDECL(vga_cl_eos,(int)); E int NDECL(vga_detect); # ifdef SIMULATE_CURSOR E void NDECL(vga_DrawCursor); # endif E void FDECL(vga_DisplayCell, (struct planar_cell_struct *, int, int)); E void FDECL(vga_DisplayCell_O, (struct overview_planar_cell_struct *, int, int)); E void NDECL(vga_Finish); E char __far *NDECL(vga_FontPtrs); E void NDECL(vga_get_scr_size); E void FDECL(vga_gotoloc,(int,int)); # ifdef POSITIONBAR E void FDECL(vga_update_positionbar, (char *)); # endif # ifdef SIMULATE_CURSOR E void NDECL(vga_HideCursor); # endif E void NDECL(vga_Init); E void FDECL(vga_SwitchMode, (unsigned int)); E void FDECL(vga_SetPalette, (char *)); E void NDECL(vga_tty_end_screen); E void FDECL(vga_tty_startup,(int*,int*)); E void FDECL(vga_WriteChar, (int, int, int, int)); E void FDECL(vga_WriteStr, (char *, int, int, int, int)); E void FDECL(vga_xputs, (const char *, int, int)); E void FDECL(vga_xputc, (CHAR_P, int)); E void FDECL(vga_xputg, (int, int, unsigned)); E void FDECL(vga_userpan, (BOOLEAN_P)); E void FDECL(vga_overview, (BOOLEAN_P)); E void FDECL(vga_traditional, (BOOLEAN_P)); E void NDECL(vga_refresh); # endif /* SCREEN_VGA */ # endif /* NO_TERMS */ #undef E #endif /* PCVIDEO_H */ /* pcvideo.h */ nethack-3.4.3/sys/msdos/portio.h0100644000000000000000000000426007764735041015304 0ustar rootroot/* SCCS Id: @(#)portio.h 3.4 1995/08/05 */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * portio.h - PC port I/O Hardware support definitions and other * low-level definitions. * */ #ifndef PORTIO_H #define PORTIO_H # if defined(__GO32__) || defined(__DJGPP__) #define __far #include #include #include #endif # if defined(_MSC_VER) #define outportb _outp #define outportw _outpw #define inportb _inp # endif # if defined(__BORLANDC__) #define outportw outport /* #define inportb inport */ # endif # ifndef MK_PTR /* * Depending on environment, this is a macro to construct either: * * - a djgpp long 32 bit pointer from segment & offset values * - a far pointer from segment and offset values * */ # if defined(_MSC_VER) || defined(__BORLANDC__) #define MK_PTR(seg, offset) (void __far *)(((unsigned long)seg << 16) \ + (unsigned long)(unsigned)offset) #define READ_ABSOLUTE(x) *(x) #define READ_ABSOLUTE_WORD(x) *(x) #define WRITE_ABSOLUTE(x,y) *(x) = (y) #define WRITE_ABSOLUTE_WORD(x,y) *(x) = (y) # endif # if defined(__GO32__) || defined(__DJGPP__) #define MK_PTR(seg, offset) (void *)(((unsigned)seg << 4) + (unsigned)offset) #define READ_ABSOLUTE(x) \ (_farpeekb(_go32_conventional_mem_selector(), (unsigned)x)) #define READ_ABSOLUTE_WORD(x) \ (_farpeekw(_go32_conventional_mem_selector(), (unsigned)x)) #define WRITE_ABSOLUTE(x,y) \ _farpokeb(_go32_conventional_mem_selector(), (unsigned)x, (y)) #define WRITE_ABSOLUTE_WORD(x,y) \ _farpokew(_go32_conventional_mem_selector(), (unsigned)x, (y)) # endif # ifdef OBSOLETE /* old djgpp V1.x way of mapping 1st MB */ #define MK_PTR(seg, offset) (void *)(0xE0000000+((((unsigned)seg << 4) \ + (unsigned)offset))) #define READ_ABSOLUTE(x) *(x) #define READ_ABSOLUTE_WORD(x) *(x) #define WRITE_ABSOLUTE(x,y) *(x) = (y) #define WRITE_ABSOLUTE_WORD(x,y) *(x) = (y) # endif # endif /* MK_PTR */ #endif /* PORTIO_H */ /* portio.h */ nethack-3.4.3/sys/msdos/schema1.BC0100644000000000000000000001503607764735041015351 0ustar rootroot/* SCCS Id: @(#)schema1.BC 3.4 1999/10/28 */ /* Copyright (c) Yitzhak Sapir, 1999 */ /* */ /* NetHack Overlay Schema */ /* Minimal extended memory available, lots of 640K base RAM free */ /* Overlay buffer size will be (20 + 20 + 19) = 59K (sum of 3 largest overlays). */ /* Requires about 490K (for exe load plus overlay buffer), but */ /* an additional 70K free (minimum) will be needed for malloc calls, */ /* bringing the total requirement to about 560K. */ /* Optimized for minimal overlay turns. */ /* */ -zCallmain_0 -zAOVLY -zCOVL1 -zCallmain_1 -zAOVLY -zCOVL2 -zCallmain_b -zAOVLY -zCOVL3 -zCalloc_o -zCapply_0 -zAOVLY -zCOVL4 -zCapply_1 -zAOVLY -zCOVL5 -zCapply_b -zAOVLY -zCOVL6 -zCartifact_0 -zAOVLY -zCOVL7 -zCartifact_1 -zAOVLY -zCOVL8 -zCartifact_b -zAOVLY -zCOVL9 -zCattrib_0 -zCattrib_1 -zAOVLY -zCOVL10 -zCattrib_2 -zAOVLY -zCOVL11 -zCattrib_b -zAOVLY -zCOVL12 -zCball_o -zAOVLY -zCOVL13 -zCbones_o -zAOVLY -zCOVL14 -zCbotl_0 -zCbotl_1 -zAOVLY -zCOVL15 -zCbotl_b -zAOVLY -zCOVL16 -zCcmd_0 -zCcmd_1 -zAOVLY -zCOVL17 -zCcmd_b -zAOVLY -zCOVL18 -zCdbridge_0 -zCdbridge_1 -zAOVLY -zCOVL19 -zCdbridge_b -zAOVLY -zCOVL20 -zCdecl_o -zAOVLY -zCOVL21 -zCdetect_o -zCdig_o -zAOVLY -zCOVL22 -zCdisplay_o -zCdlb_o -zAOVLY -zCOVL23 -zCdo_0 -zAOVLY -zCOVL24 -zCdo_1 -zAOVLY -zCOVL25 -zCdo_2 -zAOVLY -zCOVL26 -zCdo_3 -zAOVLY -zCOVL27 -zCdo_b -zAOVLY -zCOVL28 -zCdo_name_0 -zAOVLY -zCOVL29 -zCdo_name_2 -zAOVLY -zCOVL30 -zCdo_name_b -zAOVLY -zCOVL31 -zCdo_wear_0 -zAOVLY -zCOVL32 -zCdo_wear_1 -zAOVLY -zCOVL33 -zCdo_wear_2 -zAOVLY -zCOVL34 -zCdo_wear_b -zAOVLY -zCOVL35 -zCdog_1 -zAOVLY -zCOVL36 -zCdog_2 -zAOVLY -zCOVL37 -zCdog_b -zAOVLY -zCOVL38 -zCdogmove_0 -zAOVLY -zCOVL39 -zCdogmove_b -zCdokick_o -zAOVLY -zCOVL40 -zCdothrow_o -zAOVLY -zCOVL41 -zCdrawing_o -zAOVLY -zCOVL42 -zCdungeon_0 -zCdungeon_1 -zAOVLY -zCOVL43 -zCeat_0 -zAOVLY -zCOVL44 -zCeat_1 -zAOVLY -zCOVL45 -zCeat_b -zAOVLY -zCOVL46 -zCend_o -zAOVLY -zCOVL47 -zCengrave_0 -zCengrave_1 -zAOVLY -zCOVL48 -zCengrave_2 -zAOVLY -zCOVL49 -zCengrave_b -zAOVLY -zCOVL50 -zCexper_o -zAOVLY -zCOVL51 -zCexplode_0 -zAOVLY -zCOVL52 -zCexplode_1 -zAOVLY -zCOVL53 -zCextralev_o -zAOVLY -zCOVL54 -zCfiles_o -zAOVLY -zCOVL55 -zCfountain_o -zAOVLY -zCOVL56 -zCgetline_1 -zAOVLY -zCOVL57 -zCgetline_2 -zAOVLY -zCOVL58 -zChack_1 -zChack_2 -zAOVLY -zCOVL59 -zChack_3 -zChack_b -zAOVLY -zCOVL60 -zChacklib_0 -zChacklib_1 -zChacklib_2 -zChacklib_b -zAOVLY -zCOVL61 -zCinvent_0 -zCinvent_1 -zAOVLY -zCOVL62 -zCinvent_2 -zAOVLY -zCOVL63 -zCinvent_3 -zAOVLY -zCOVL64 -zCinvent_b -zAOVLY -zCOVL65 -zClight_3 -zAOVLY -zCOVL66 -zClock_0 -zAOVLY -zCOVL67 -zClock_b -zAOVLY -zCOVL68 -zCmail_0 -zAOVLY -zCOVL68 -zCmail_b -zAOVLY -zCOVL69 -zCmakemon_0 -zAOVLY -zCOVL70 -zCmakemon_1 -zAOVLY -zCOVL71 -zCmakemon_2 -zAOVLY -zCOVL72 -zCmakemon_b -zAOVLY -zCOVL73 -zCmcastu_0 -zAOVLY -zCOVL74 -zCmcastu_b -zAOVLY -zCOVL75 -zCmhitm_0 -zAOVLY -zCOVL76 -zCmhitm_b -zAOVLY -zCOVL77 -zCmhitu_0 -zAOVLY -zCOVL78 -zCmhitu_1 -zAOVLY -zCOVL79 -zCmhitu_b -zAOVLY -zCOVL80 -zCminion_o -zAOVLY -zCOVL81 -zCmklev_o -zAOVLY -zCOVL82 -zCmkmap_o -zAOVLY -zCOVL83 -zCmkmaze_o -zAOVLY -zCOVL84 -zCmkobj_0 -zAOVLY -zCOVL85 -zCmkobj_1 -zAOVLY -zCOVL86 -zCmkobj_b -zAOVLY -zCOVL87 -zCmkroom_0 -zAOVLY -zCOVL88 -zCmkroom_b -zAOVLY -zCOVL89 -zCmon_0 -zCmon_1 -zAOVLY -zCOVL90 -zCmon_2 -zAOVLY -zCOVL91 -zCmon_b -zAOVLY -zCOVL92 -zCmondata_0 -zCmondata_1 -zAOVLY -zCOVL93 -zCmondata_2 -zAOVLY -zCOVL94 -zCmondata_b -zAOVLY -zCOVL95 -zCmonmove_0 -zCmonmove_1 -zCmonmove_2 -zCmonmove_b -zAOVLY -zCOVL96 -zCmonst_o -zAOVLY -zCOVL97 -zCmonstr_o -zAOVLY -zCOVL98 -zCmplayer_o -zAOVLY -zCOVL99 -zCmsdos_0 -zCmsdos_b -zAOVLY -zCOVL100 -zCmthrowu_0 -zAOVLY -zCOVL101 -zCmthrowu_1 -zAOVLY -zCOVL102 -zCmthrowu_b -zAOVLY -zCOVL103 -zCmuse_o -zAOVLY -zCOVL104 -zCmusic_o -zAOVLY -zCOVL105 -zCo_init_o -zAOVLY -zCOVL106 -zCobjects_o -zAOVLY -zCOVL107 -zCobjnam_0 -zAOVLY -zCOVL108 -zCobjnam_1 -zAOVLY -zCOVL109 -zCobjnam_b -zAOVLY -zCOVL110 -zCoptions_o -zAOVLY -zCOVL111 -zCovlinit_o -zCpager_o -zAOVLY -zCOVL112 -zCpckeys_o -zCpcmain_0 -zCpcmain_1 -zAOVLY -zCOVL113 -zCpcmain_b -zAOVLY -zCOVL114 -zCpctiles_0 -zCpctiles_b -zCpcunix_b -zAOVLY -zCOVL115 -zCpickup_o -zAOVLY -zCOVL116 -zCpline_b -zAOVLY -zCOVL117 -zCpolyself_0 -zAOVLY -zCOVL118 -zCpolyself_1 -zAOVLY -zCOVL119 -zCpolyself_b -zAOVLY -zCOVL120 -zCpotion_b -zAOVLY -zCOVL121 -zCpray_o -zAOVLY -zCOVL122 -zCpriest_0 -zAOVLY -zCOVL123 -zCpriest_b -zAOVLY -zCOVL124 -zCquest_o -zAOVLY -zCOVL125 -zCquestpgr_o -zAOVLY -zCOVL126 -zCrandom_o -zCread_b -zAOVLY -zCOVL127 -zCrect_o -zAOVLY -zCOVL128 -zCregion_o -zAOVLY -zCOVL129 -zCrestore_o -zAOVLY -zCOVL130 -zCrip_o -zAOVLY -zCOVL131 -zCrnd_0 -zCrnd_1 -zAOVLY -zCOVL132 -zCrnd_b -zAOVLY -zCOVL133 -zCrole_o -zAOVLY -zCOVL113 -zCrumors_o -zAOVLY -zCOVL134 -zCsave_o -zAOVLY -zCOVL135 -zCshk_0 -zAOVLY -zCOVL136 -zCshk_1 -zAOVLY -zCOVL137 -zCshk_2 -zAOVLY -zCOVL138 -zCshk_3 -zAOVLY -zCOVL139 -zCshk_b -zAOVLY -zCOVL140 -zCshknam_0 -zAOVLY -zCOVL141 -zCshknam_b -zAOVLY -zCOVL142 -zCsit_o -zAOVLY -zCOVL143 -zCsound_o -zCsounds_0 -zAOVLY -zCOVL144 -zCsounds_b -zAOVLY -zCOVL145 -zCsp_lev_o -zAOVLY -zCOVL146 -zCspell_o -zAOVLY -zCOVL147 -zCsteal_0 -zAOVLY -zCOVL148 -zCsteal_1 -zAOVLY -zCOVL149 -zCsteal_b -zAOVLY -zCOVL150 -zCsteed_o -zAOVLY -zCOVL188 -zCsys_o -zAOVLY -zCOVL151 -zCteleport_o -zAOVLY -zCOVL152 -zCtermcap_0 -zAOVLY -zCOVL153 -zCtermcap_1 -zAOVLY -zCOVL154 -zCtermcap_b -zAOVLY -zCOVL155 -zCtile_o -zCtimeout_0 -zAOVLY -zCOVL156 -zCtimeout_1 -zAOVLY -zCOVL157 -zCtimeout_b -zAOVLY -zCOVL158 -zCtopl_1 -zAOVLY -zCOVL159 -zCtopl_2 -zAOVLY -zCOVL160 -zCtopl_b -zAOVLY -zCOVL161 -zCtopten_o -zAOVLY -zCOVL162 -zCtrack_0 -zAOVLY -zCOVL163 -zCtrack_1 -zAOVLY -zCOVL164 -zCtrack_b -zAOVLY -zCOVL165 -zCtrap_0 -zCtrap_1 -zAOVLY -zCOVL166 -zCtrap_2 -zAOVLY -zCOVL167 -zCtrap_3 -zAOVLY -zCOVL168 -zCtrap_b -zAOVLY -zCOVL169 -zCtty_o -zAOVLY -zCOVL170 -zCu_init_o -zAOVLY -zCOVL171 -zCuhitm_o -zAOVLY -zCOVL172 -zCvault_0 -zAOVLY -zCOVL173 -zCvault_b -zAOVLY -zCOVL174 -zCversion_o -zAOVLY -zCOVL175 -zCvideo_0 -zCvideo_1 -zCvideo_b -zCvidtxt_0 -zCvidtxt_b -zCvidvga_0 -zCvidvga_1 -zCvidvga_2 -zAOVLY -zCOVL176 -zCvidvga_b -zCvis_tab_o -zAOVLY -zCOVL177 -zCvision_o -zCweapon_0 -zAOVLY -zCOVL178 -zCweapon_1 -zAOVLY -zCOVL179 -zCweapon_b -zAOVLY -zCOVL180 -zCwere_0 -zAOVLY -zCOVL181 -zCwere_b -zAOVLY -zCOVL182 -zCwield_o -zAOVLY -zCOVL183 -zCwindows_o -zAOVLY -zCOVL184 -zCwintty_o -zCwizard_0 -zAOVLY -zCOVL185 -zCwizard_b -zAOVLY -zCOVL186 -zCworm_o -zAOVLY -zCOVL187 -zCworn_o -zAOVLY -zCOVL188 -zCwrite_o -zAOVLY -zCOVL189 -zCzap_0 -zAOVLY -zCOVL190 -zCzap_1 -zAOVLY -zCOVL191 -zCzap_2 -zAOVLY -zCOVL192 -zCzap_3 -zAOVLY -zCOVL193 -zCzap_b -zAOVLY -zCOVL194 nethack-3.4.3/sys/msdos/schema2.BC0100644000000000000000000001533207764735041015351 0ustar rootroot/* SCCS Id: @(#)schema2.BC 3.4 1999/10/28 */ /* Copyright (c) Yitzhak Sapir, 1999 */ /* */ /* NetHack Overlay Schema */ /* Small Root footprint, with extended memory available for caching. */ /* Almost everything is overlaid. */ /* */ -zCallmain_0 -zAOVLY -zCOVL1 -zCallmain_1 -zAOVLY -zCOVL2 -zCallmain_b -zAOVLY -zCOVL3 -zCalloc_o -zCapply_0 -zAOVLY -zCOVL4 -zCapply_1 -zAOVLY -zCOVL5 -zCapply_b -zAOVLY -zCOVL6 -zCartifact_0 -zAOVLY -zCOVL7 -zCartifact_1 -zAOVLY -zCOVL8 -zCartifact_b -zAOVLY -zCOVL9 -zCattrib_0 -zAOVLY -zCOVL10 -zCattrib_1 -zAOVLY -zCOVL11 -zCattrib_2 -zAOVLY -zCOVL12 -zCattrib_b -zAOVLY -zCOVL13 -zCball_o -zAOVLY -zCOVL14 -zCbones_o -zAOVLY -zCOVL15 -zCbotl_0 -zAOVLY -zCOVL16 -zCbotl_1 -zAOVLY -zCOVL17 -zCbotl_b -zAOVLY -zCOVL18 -zCcmd_0 -zAOVLY -zCOVL19 -zCcmd_1 -zAOVLY -zCOVL20 -zCcmd_b -zAOVLY -zCOVL21 -zCdbridge_0 -zAOVLY -zCOVL22 -zCdbridge_1 -zAOVLY -zCOVL23 -zCdbridge_b -zAOVLY -zCOVL24 -zCdecl_o -zAOVLY -zCOVL25 -zCdetect_o -zAOVLY -zCOVL26 -zCdig_o -zAOVLY -zCOVL27 -zCdisplay_o -zAOVLY -zCOVL28 -zCdlb_o -zAOVLY -zCOVL29 -zCdo_0 -zAOVLY -zCOVL30 -zCdo_1 -zAOVLY -zCOVL31 -zCdo_2 -zAOVLY -zCOVL32 -zCdo_3 -zAOVLY -zCOVL33 -zCdo_b -zAOVLY -zCOVL34 -zCdo_name_0 -zAOVLY -zCOVL35 -zCdo_name_2 -zAOVLY -zCOVL36 -zCdo_name_b -zAOVLY -zCOVL37 -zCdo_wear_0 -zAOVLY -zCOVL38 -zCdo_wear_1 -zAOVLY -zCOVL39 -zCdo_wear_2 -zAOVLY -zCOVL40 -zCdo_wear_b -zAOVLY -zCOVL41 -zCdog_1 -zAOVLY -zCOVL42 -zCdog_2 -zAOVLY -zCOVL43 -zCdog_b -zAOVLY -zCOVL44 -zCdogmove_0 -zAOVLY -zCOVL45 -zCdogmove_b -zAOVLY -zCOVL46 -zCdokick_o -zAOVLY -zCOVL47 -zCdothrow_o -zAOVLY -zCOVL48 -zCdrawing_o -zAOVLY -zCOVL49 -zCdungeon_0 -zAOVLY -zCOVL50 -zCdungeon_1 -zAOVLY -zCOVL51 -zCeat_0 -zAOVLY -zCOVL52 -zCeat_1 -zAOVLY -zCOVL53 -zCeat_b -zAOVLY -zCOVL54 -zCend_o -zAOVLY -zCOVL55 -zCengrave_0 -zAOVLY -zCOVL56 -zCengrave_1 -zAOVLY -zCOVL57 -zCengrave_2 -zAOVLY -zCOVL58 -zCengrave_b -zAOVLY -zCOVL59 -zCexper_o -zAOVLY -zCOVL60 -zCexplode_0 -zAOVLY -zCOVL61 -zCexplode_1 -zAOVLY -zCOVL62 -zCextralev_o -zAOVLY -zCOVL63 -zCfiles_o -zAOVLY -zCOVL64 -zCfountain_o -zAOVLY -zCOVL65 -zCgetline_1 -zAOVLY -zCOVL66 -zCgetline_2 -zAOVLY -zCOVL67 -zChack_1 -zAOVLY -zCOVL68 -zChack_2 -zAOVLY -zCOVL69 -zChack_3 -zChack_b -zAOVLY -zCOVL70 -zChacklib_0 -zAOVLY -zCOVL71 -zChacklib_1 -zAOVLY -zCOVL72 -zChacklib_2 -zAOVLY -zCOVL73 -zChacklib_b -zAOVLY -zCOVL74 -zCinvent_0 -zAOVLY -zCOVL75 -zCinvent_1 -zAOVLY -zCOVL76 -zCinvent_2 -zAOVLY -zCOVL77 -zCinvent_3 -zAOVLY -zCOVL78 -zCinvent_b -zAOVLY -zCOVL79 -zClight_3 -zAOVLY -zCOVL80 -zClock_0 -zAOVLY -zCOVL81 -zClock_b -zAOVLY -zCOVL82 -zCmail_0 -zAOVLY -zCOVL82 -zCmail_b -zAOVLY -zCOVL83 -zCmakemon_0 -zAOVLY -zCOVL84 -zCmakemon_1 -zAOVLY -zCOVL85 -zCmakemon_2 -zAOVLY -zCOVL86 -zCmakemon_b -zAOVLY -zCOVL87 -zCmcastu_0 -zAOVLY -zCOVL88 -zCmcastu_b -zAOVLY -zCOVL89 -zCmhitm_0 -zAOVLY -zCOVL90 -zCmhitm_b -zAOVLY -zCOVL91 -zCmhitu_0 -zAOVLY -zCOVL92 -zCmhitu_1 -zAOVLY -zCOVL93 -zCmhitu_b -zAOVLY -zCOVL94 -zCminion_o -zAOVLY -zCOVL95 -zCmklev_o -zAOVLY -zCOVL96 -zCmkmap_o -zAOVLY -zCOVL97 -zCmkmaze_o -zAOVLY -zCOVL98 -zCmkobj_0 -zAOVLY -zCOVL99 -zCmkobj_1 -zAOVLY -zCOVL100 -zCmkobj_b -zAOVLY -zCOVL101 -zCmkroom_0 -zAOVLY -zCOVL102 -zCmkroom_b -zAOVLY -zCOVL103 -zCmon_0 -zAOVLY -zCOVL104 -zCmon_1 -zAOVLY -zCOVL105 -zCmon_2 -zAOVLY -zCOVL106 -zCmon_b -zAOVLY -zCOVL107 -zCmondata_0 -zAOVLY -zCOVL108 -zCmondata_1 -zAOVLY -zCOVL109 -zCmondata_2 -zAOVLY -zCOVL110 -zCmondata_b -zAOVLY -zCOVL111 -zCmonmove_0 -zAOVLY -zCOVL112 -zCmonmove_1 -zAOVLY -zCOVL113 -zCmonmove_2 -zAOVLY -zCOVL114 -zCmonmove_b -zAOVLY -zCOVL115 -zCmonst_o -zAOVLY -zCOVL116 -zCmonstr_o -zAOVLY -zCOVL117 -zCmplayer_o -zAOVLY -zCOVL118 -zCmsdos_0 -zAOVLY -zCOVL119 -zCmsdos_b -zAOVLY -zCOVL120 -zCmthrowu_0 -zAOVLY -zCOVL121 -zCmthrowu_1 -zAOVLY -zCOVL122 -zCmthrowu_b -zAOVLY -zCOVL123 -zCmuse_o -zAOVLY -zCOVL124 -zCmusic_o -zAOVLY -zCOVL125 -zCo_init_o -zAOVLY -zCOVL126 -zCobjects_o -zAOVLY -zCOVL127 -zCobjnam_0 -zAOVLY -zCOVL128 -zCobjnam_1 -zAOVLY -zCOVL129 -zCobjnam_b -zAOVLY -zCOVL130 -zCoptions_o -zAOVLY -zCOVL131 -zCovlinit_o -zCpager_o -zAOVLY -zCOVL132 -zCpckeys_o -zAOVLY -zCOVL119 -zCpcmain_0 -zCpcmain_1 -zAOVLY -zCOVL133 -zCpcmain_b -zAOVLY -zCOVL134 -zCpctiles_0 -zCpctiles_b -zCpcunix_b -zAOVLY -zCOVL135 -zCpickup_o -zAOVLY -zCOVL136 -zCpline_b -zAOVLY -zCOVL137 -zCpolyself_0 -zAOVLY -zCOVL138 -zCpolyself_1 -zAOVLY -zCOVL139 -zCpolyself_b -zAOVLY -zCOVL140 -zCpotion_b -zAOVLY -zCOVL141 -zCpray_o -zAOVLY -zCOVL142 -zCpriest_0 -zAOVLY -zCOVL143 -zCpriest_b -zAOVLY -zCOVL144 -zCquest_o -zAOVLY -zCOVL145 -zCquestpgr_o -zAOVLY -zCOVL146 -zCrandom_o -zAOVLY -zCOVL147 -zCread_b -zAOVLY -zCOVL148 -zCrect_o -zAOVLY -zCOVL149 -zCregion_o -zAOVLY -zCOVL150 -zCrestore_o -zAOVLY -zCOVL151 -zCrip_o -zAOVLY -zCOVL152 -zCrnd_0 -zAOVLY -zCOVL153 -zCrnd_1 -zAOVLY -zCOVL154 -zCrnd_b -zAOVLY -zCOVL155 -zCrole_o -zAOVLY -zCOVL133 -zCrumors_o -zAOVLY -zCOVL156 -zCsave_o -zAOVLY -zCOVL157 -zCshk_0 -zAOVLY -zCOVL158 -zCshk_1 -zAOVLY -zCOVL159 -zCshk_2 -zAOVLY -zCOVL160 -zCshk_3 -zAOVLY -zCOVL161 -zCshk_b -zAOVLY -zCOVL162 -zCshknam_0 -zAOVLY -zCOVL163 -zCshknam_b -zAOVLY -zCOVL164 -zCsit_o -zAOVLY -zCOVL165 -zCsound_o -zCsounds_0 -zAOVLY -zCOVL166 -zCsounds_b -zAOVLY -zCOVL167 -zCsp_lev_o -zAOVLY -zCOVL168 -zCspell_o -zAOVLY -zCOVL169 -zCsteal_0 -zAOVLY -zCOVL170 -zCsteal_1 -zAOVLY -zCOVL171 -zCsteal_b -zAOVLY -zCOVL172 -zCsteed_o -zAOVLY -zCOVL173 -zCsys_o -zAOVLY -zCOVL174 -zCteleport_o -zAOVLY -zCOVL175 -zCtermcap_0 -zAOVLY -zCOVL176 -zCtermcap_1 -zAOVLY -zCOVL177 -zCtermcap_b -zAOVLY -zCOVL178 -zCtile_o -zCtimeout_0 -zAOVLY -zCOVL179 -zCtimeout_1 -zAOVLY -zCOVL180 -zCtimeout_b -zAOVLY -zCOVL181 -zCtopl_1 -zAOVLY -zCOVL182 -zCtopl_2 -zAOVLY -zCOVL183 -zCtopl_b -zAOVLY -zCOVL184 -zCtopten_o -zAOVLY -zCOVL185 -zCtrack_0 -zAOVLY -zCOVL186 -zCtrack_1 -zAOVLY -zCOVL187 -zCtrack_b -zAOVLY -zCOVL188 -zCtrap_0 -zAOVLY -zCOVL189 -zCtrap_1 -zAOVLY -zCOVL190 -zCtrap_2 -zAOVLY -zCOVL191 -zCtrap_3 -zAOVLY -zCOVL192 -zCtrap_b -zAOVLY -zCOVL193 -zCtty_o -zAOVLY -zCOVL194 -zCu_init_o -zAOVLY -zCOVL195 -zCuhitm_o -zAOVLY -zCOVL196 -zCvault_0 -zAOVLY -zCOVL197 -zCvault_b -zAOVLY -zCOVL198 -zCversion_o -zAOVLY -zCOVL199 -zCvideo_0 -zCvideo_1 -zCvideo_b -zCvidtxt_0 -zCvidtxt_b -zCvidvga_0 -zCvidvga_1 -zCvidvga_2 -zAOVLY -zCOVL200 -zCvidvga_b -zCvis_tab_o -zAOVLY -zCOVL201 -zCvision_o -zAOVLY -zCOVL202 -zCweapon_0 -zAOVLY -zCOVL203 -zCweapon_1 -zAOVLY -zCOVL204 -zCweapon_b -zAOVLY -zCOVL205 -zCwere_0 -zAOVLY -zCOVL206 -zCwere_b -zAOVLY -zCOVL207 -zCwield_o -zAOVLY -zCOVL208 -zCwindows_o -zAOVLY -zCOVL209 -zCwintty_o -zAOVLY -zCOVL210 -zCwizard_0 -zAOVLY -zCOVL211 -zCwizard_b -zAOVLY -zCOVL212 -zCworm_o -zAOVLY -zCOVL213 -zCworn_o -zAOVLY -zCOVL173 -zCwrite_o -zAOVLY -zCOVL214 -zCzap_0 -zAOVLY -zCOVL215 -zCzap_1 -zAOVLY -zCOVL216 -zCzap_2 -zAOVLY -zCOVL217 -zCzap_3 -zAOVLY -zCOVL218 -zCzap_b -zAOVLY -zCOVL219 nethack-3.4.3/sys/msdos/schema3.MSC0100644000000000000000000010354107764735041015510 0ustar rootroot; SCCS Id: @(#)schema3.MSC 3.4 2003/08/03 ; Copyright (c) NetHack PC Development Team, 2000 ; ; NetHack Overlay Schema ; This overlay schema is for use only when NetHack is built ; using packaged-functions for function-level linking. ; ; Overlay tuning level: 0 ; functions:0 _main _dosave0 _moveloop _bputc _bwrite _random _rn2 _newsym _show_glyph _on_level _txt_gotoxy _txt_get_cursor functions:0 _xputc _txt_xputc _t_at _tty_curs _acurr _dist2 _tty_print_glyph _isok _back_to_glyph functions:0 _show_map_spot _adjust_cursor_flags _lowc _g_putch _has_color _is_pool _mread functions:0 _is_lava _welded _magic_map_background _end_glyphout _visible_region_at _domove functions:0 _engr_at _rnd _run_regions _mcalcmove _depth _done _distmin _does_block _eos functions:0 _move _move_bc _in_rooms _map_background _map_invisible _map_location _alloc functions:0 _impossible _in_container _in_fcorridor _In_hell _In_mines _in_or_out_menu _In_quest functions:0 _do_positionbar _iswall _iswall_or_stone _itimeout _is_solid _Is_special functions:0 _is_swallow_sym _check_here _check_leash _check_map_spot _check_pos functions:0 _monsndx _m_move _lcase _tty_create_nhwindow _tty_delay_output _tty_destroy_nhwindow functions:0 _tty_dismiss_nhwindow _gender _genl_outrip _get_cost _get_free_room_loc _get_level functions:0 _get_location _get_map _get_mleash ; functions:1 _move_update _movebubbles _movecmd _movemon _moverock _movobj _mpickgold functions:1 _doaltarobj _doapply _dobreathe _docall _docast ; functions:2 _do_vicinity_map functions:3 _pcmain functions:4 _spell_let_to_idx _cursed_book _deadbook _learn _getspell _spelltypemnemonic functions:5 _dospellmenu _percent_success _throwspell _cast_protection _isqrt ; functions:6 _a_gname _a_gname_at _a_monnam _abon _abuse_dog _accessible _activate_statue_trap functions:7 _add_branch _add_damage _add_debug_extended_commands _add_door _add_id_mapping _add_level functions:8 _add_menu_cmd_alias _add_one_tobill _add_rect _add_room _add_subroom _add_to_billobjs _add_to_buried _add_to_container functions:9 _add_to_migration _add_to_minv _add_valid_menu_class _add_weapon_skill _addinv _addtobill _addtopl _addupbill functions:10 _Adjmonnam functions:11 _align_gname functions:12 _altar_wrath _Amonnam _amulet _Amulet_off _Amulet_on _An _an _angry_guards functions:13 _angry_priest _angry_shk_exists _any_light_source _aobjnam _append_slash _append_str _Armor_gone _Armor_off functions:14 _Armor_on _armor_to_dragon _armoroff _arti_invoke _artifact_exists _artifact_hit _artifact_name _artiname functions:15 _artitouch _askchain _assign_graphics _assign_level _assign_rnd_level _assign_rogue_graphics _assign_soundcard _assign_video functions:16 _assign_videocolors _assign_videoshades _assigninvlet _at_dgn_entrance _attach_egg_hatch_timeout _attack _attack_checks _attacks functions:17 _awaken_monsters _awaken_soldiers functions:18 _backfire _backsp _bad_location _bad_negation _bad_rock _badoption _bail _ballfall functions:19 _bc_order _bclose _bcsign _beg _begin_burn _bflush _bhit _bhitm functions:20 _bhito _bhitpile _big_to_little _bill_box_content _bill_dummy_object _bite _bless _blessorcurse functions:21 _Blindf_off _Blindf_on _block_door _block_entry _block_point _blow_up_landmine _body_part functions:22 _boomhit _Boots_off _Boots_on _bot _bot1 _bot2 _boulder_hits_pool _bound_digging functions:23 _boxlock _br_string _break_armor _break_statue _breakarm _breakmsg functions:24 _breakobj _breaks _breaksink _breaktest _breamu _bribe _bufoff _bufon functions:25 _build_room _burn_floor_paper _burn_object _burnarmor _bury_an_obj _bury_objs _buzz _buzzmu functions:26 _Can_dig_down functions:27 _Can_fall_thru _can_make_bones _can_ooze _can_pray _can_reach_floor _Can_rise_up _can_track functions:28 _cancel_bonesfile _cancel_don _cancel_item _cancel_monst _candle_light_range _canletgo _cant_create _canwearobj functions:29 _carry_count _carrying _castmu _ceiling _center _change_inv_order _change_luck _change_sex functions:30 _charm_monsters _charm_snakes _chat_with_guardian _chat_with_leader _chat_with_nemesis _chdirx _chdrive _cheapest_item functions:31 _check_capacity _check_contained _check_credit _check_recordfile functions:32 _check_room _check_shop_obj _check_special_room _check_unpaid _check_unpaid_usage _check_version _checkfile _chest_shatter_msg functions:33 _chest_trap _choke _choke_dialogue _choose_classes_menu _choose_windows _christen_monst _chwepon _ck_bag functions:34 _ckmailstatus _ckunpaid _cl_end _cl_eos _classmon _clear_fcorr _clear_glyph_buffer functions:35 _clear_id_mapping _clear_level_structures _clear_path _clear_screen _clear_stale_map _clear_unpaid _clearlocks _clearpriests functions:36 _click_to_cmd _Cloak_off _Cloak_on _clone_mon _cloneu _clonewiz _close_drawbridge _close_library functions:37 _closed_door _CloseTileFile _cls _cmov _cnv_trap_obj _co_false _collect_obj_classes _com_pager functions:38 _commit_bonesfile _compactify _compress _compress_bonesfile _compress_str _comspec_exists _confdir _construct_qtlist functions:39 _consume_offering _contained _contained_cost _contained_gold _container_contents _container_weight _convert_arg _convert_line functions:40 _copybones _copyfile _corpse_chance _corpse_xname _corr _correct_branch_type _cost _cost_per_charge functions:41 _costly_cancel _costly_gold _costly_spot _could_seduce _count_categories _count_obj _count_unpaid _count_wsegs functions:42 _counter_were _courtmon _cpostfx _cprefx _create_altar _create_bonesfile _create_corridor _create_critters functions:43 _create_door _create_drawbridge _create_engraving _create_feature _create_gold _create_levelfile _create_monster _create_mplayers functions:44 _create_object _create_particular _create_polymon _create_room _create_savefile _create_secret_door _create_stairs _create_subroom functions:45 _create_trap _create_worm_tail _curr_mon_load _currentlevel_rewrite _curs_on_u _curse _cursed _cursed_object_at functions:46 _cursetxt _cuss _cutworm _cvt_sdoor_to_door _d _damageum _dbon _ddocall functions:47 _ddoinv _dead_species _dealloc_obj _decl_init _deepest_lev_reached _def_char_to_monclass _def_char_to_objclass _def_raw_print functions:48 _defends _deferred_goto _del_engr _del_engr_at _del_light_source _delallobj _delete_bonesfile _delete_contents functions:49 _delete_levelfile _delete_savefile _delfloortrap _deliver_by_pline _deliver_by_window _delobj _deltrap _demon_talk functions:50 _demonpet _destroy_arm _destroy_drawbridge _destroy_item _destroy_mitem _dev_name _dig functions:51 _dig_check _dig_corridor _dig_point _dig_typ _digactualhole _dighole _digit _dipfountain functions:52 _disable_ctrlP _disarm_landmine _disarm_shooting_trap _disarm_squeaky_board _discard_minvent _disclose _discover_object functions:53 _diseasemu _display_binventory _display_cinventory _display_gamewindows _display_inventory _display_minventory functions:54 _distant_name _distfleeck _disturb _djinni_from_bottle _dlb_cleanup _dlb_fclose functions:55 _dlb_fgets _dlb_fopen _dlb_fread _dlb_fseek _dlb_ftell _dlb_init _dlord _dmgtype functions:56 _dmgval _dmonsfree _dmore _dname_to_dnum _do_break_wand _do_clear_area _do_comp _do_dknown_of functions:57 _do_earthquake _do_entity _do_genocide _do_improvisation _do_light_sources _do_look _do_mapping _do_mname functions:57 _vga_xputg _vga_xputs _video_update_positionbar _view_from _view_init _visctrl _vision_init _vision_recalc functions:58 _do_oname _do_osshock _do_play_instrument _do_reset_eat _do_room_or_subroom _do_storms _do_takeoff functions:60 _doclose _doconsult _docorner _docrt _doddoremarm _doddrop _dodip functions:61 _adjust_prefix _build_plselection_prompt _duplicate_opt_detection _enter_explore_mode _maybe_wail functions:62 _doextcmd _doextlist _doextversion _dofindgem _dofiretrap _doforce _dog_eat _dog_goal functions:63 _dog_hunger _dog_invent _dog_move _dog_nutrition _dogfood _dogushforth _dohelp _dohide functions:64 _dohistory _doidtrap _doinvbill _doinvoke _dojump _dokick _dolook _doloot functions:65 _domagicportal functions:66 _done_eating _done_in_by _done_intr _done1 _done2 _donning _donull _doopen functions:67 _doorganize _doorlock _dopay _dopayobj _dopickup _dopotion _dopramulet _doprarm functions:68 _dopray _doprev_message _doprgold _doprring _doprtool _doprwep _doputon _doquickwhatis functions:69 _doread _dorecover _doredraw _doremove _doremring _dorub _dosacrifice _dosave functions:70 _dosdoor _dosearch _dosearch0 _doseduce _doset _doset_add_menu _dosh functions:71 _dosinkfall _dosinkring _dosit _dosounds _dospinweb _dospit _dosummon _dotakeoff functions:72 _dotalk _dotele _dothrow _dotogglepickup _dotrap _doturn _dotypeinv _dounpaid functions:73 _dountrap _doup _doversion _dovspell _dowaterdemon _dowaternymph _dowatersnakes _dowear functions:74 _dowhatdoes _dowhatis _dowield _dowipe _down_gate _dowrite _dozap _dprince functions:75 _drag_ball _drag_down _drain_en _DrawCursor _drinkfountain _drinksink _drop _drop_ball functions:76 _drop_throw _drop_to _drop_upon_death _drop_weapon _DROPPABLES _dropped_container _dropx _dropy functions:77 _drown _dryup _dtoxy _dungeon_branch _dunlev _dunlevs_in_dungeon _e_at _e_died functions:78 _e_jumps _e_missed _e_nam _E_phrase _e_survives_at _eataccessory _eatcorpse _eaten_stat functions:79 _eatfood _eatmdone _eatspecial _egg_type_from_parent _emergency_disrobe _enable_ctrlP _encumber_msg _end_burn functions:80 _end_engulf ;functions:81 functions:82 _exclam _exepath _exerchk _exercise _exerper _exist_artifact _expels _experience functions:83 _explmm _explmu _explode _explum _expulsion _ext_cmd_getlin_hook _extend_spine _extract_nexthere functions:84 _extract_nobj _fall_asleep _fall_through _feel_cockatrice _feel_location _fightm _filesize_nh _fill_pit functions:85 _nh_getenv _promptsep _rigid_role_checks _set_duplicate_opt_detection _tool_in_use functions:86 _find_drawbridge _find_hell _find_lev_obj _find_level _find_mac _find_mid _find_misc _find_offensive functions:87 _find_oid _find_roll_to_hit _find_skates _find_unpaid _finddpos _findfirst_file _findgd _findit functions:88 _findnext_file _findone _findpriest _finish_map _finish_paybill _fix_stair_rooms _fix_worst_trouble _fixup_special functions:89 _flash_hits_mon _float_down _float_up _floating_above _flood_fill_rm _flooreffects _floorfood _flush_screen _term_start_color functions:90 _flushout _fmt_ptr _food_detect _food_disappears _food_xname _foodword _fopen_config_file _fopen_datafile functions:91 _fopenp _forcelock _forget_levels _forget_map _forget_objects _forget_traps _foundfile_buffer _fpostfx functions:92 _fprefx _fracture_rock _free_dungeons _free_rooms _free_ttlist _free_window_info _freediskspace _freedynamicdata functions:93 _freefruitchn _freehand _freeinv _friday_13th _fruitadd _fry_by_god _fully_identify_obj _g_at functions:94 _gainstr _gameDiskPrompt _gazemm _gazemu _gd_move _gd_sound _gem_accept functions:95 _display_warning _dlb_fgetc _doattributes _dochug _dochugw functions:96 _fill_point _fill_room _fill_zoo _fillholetyp _find_ac _find_branch _find_branch_room _find_defensive functions:96 _get_mon_location _get_mplname _get_obj_location _get_rect _get_rect_ind _get_room_loc _get_scr_size _get_shop_item functions:97 _get_uchars _get_unused_cs _get_valuables _get_wall_for_db _get_wet _get_wormno _getbones _getdir functions:98 _gethungry functions:99 _gettty _getversionstring _getyear _ggetobj _ghitm _ghod_hitsu _ghost_from_bottle _ghostfruit functions:100 _givit _glibr _Gloves_off _Gloves_on _glyph_at _god_zaps_you _gods_angry _gods_upset functions:101 _godvoice _gold_detect _golemeffects _golemhp _goodfruit _goodpos _goto_hell _goto_level functions:102 _gr_finish _gr_init _graphics_opts _grddead _grease_protect _grow_up _growl _growl_sound functions:103 _guardname _gulpmm _gulpmu _gulpum _gush _hack_artifacts _has_dnstairs functions:104 _has_shrine _has_upstairs _hatch_egg _hates_silver _have_lizard _hcolor _heal_legs _healup functions:105 _Hear_again _Helmet_off _Helmet_on _help_menu _help_monster_out _hero_breaks _hidden_gold _HideCursor functions:106 _highc _histemple_at _hit _hitfloor _hitmm _hitmsg _hitmu _hitum functions:107 _hitval _hmon _hmon_hitmon _hmonas _hold_another_object _holetime _home _home_shk functions:108 _homebase _hooked_tty_getlin _hot_pursuit _hurtarmor _hurtle _identify _identify_pack _impact_drop functions:110 _in_trouble _In_V_tower _In_W_tower _in_your_sanctuary _incr_itimeout _induced_align _inherits _inhishop functions:111 _init_artifacts _init_attr _init_dungeons _init_fill _init_level _init_map _init_objects functions:112 _init_oracles _init_rect _init_rumors _init_ttycolor _init_uhunger _initedog _initoptions _initrack functions:113 _initworm _insert_branch _insert_timer _inside_room _inside_shop _instapetrify _intemple _interesting_to_discover functions:114 _intermed _intervene _intrinsic_possible _inv_cnt _inv_weight _invault _invdisp_nothing _inven_inuse functions:115 _invert_all _invert_all_on_page _Invocation_lev _invocation_message _invocation_pos _Is_botlevel _Is_branchlev _is_chargeable functions:116 _is_db_wall _is_drawbridge_wall _is_edible _is_fainted _is_flammable _is_fshk _is_home_elemental _is_ice ;functions:117 functions:118 _is_worn _is_worn_by_type _isbig _isclearpath functions:119 _itimeout_incr _its_dead _itsstuck _Japanese_item_name _join _join_map _jump _keepdogs functions:119 _sticks _still_chewing _stock_room _stolen_container _stolen_value _stone_luck _stoned_dialogue _stop_occupation functions:120 _kick_monster _kick_object _kickdmg _kickstr _kill_egg _kill_eggs _kill_genocided_monsters _killed functions:121 _kind_name _known_hitum _kops_gone _l_monnam _lantern_message _launch_obj _lava_effects functions:122 _ldrname _leader_speaks _learn_egg_type _ledger_no _ledger_to_dlev _ledger_to_dnum functions:123 _left_side _lesshungry _let_to_name _letter _lev_by_name _level_difficulty _level_distance _level_range functions:124 _level_tele _level_tele_trap _levl_follower _lifesaved_monster _lift_object _light_cocktail _light_region _lined_up functions:125 _linedup _list_genocided _list_vanquished _litroom _litter _little_to_big _llord _lminion functions:126 _load_common_data _load_maze _load_one_engraving _load_one_monster _load_one_object _load_qtlist _load_rooms _load_special functions:127 _loadfruitchn _lock_action _lock_file _locomotion _lookaround _lookat _lookup_id_mapping _lose_weapon_skill functions:128 _losedogs _losehp _losespells _losestr _losexp _m_arrival functions:129 _m_carrying _m_detach _m_dowear _m_dowear_type _m_initgrp _m_initinv _m_initthrow _m_initweap functions:130 _m_lose_armor functions:131 _m_useup _make_angry_shk _make_blinded _make_confused _make_corpse _make_engr_at _make_familiar _make_hallucinated functions:132 _make_happy_shk _make_lockname _make_niches _make_sick _make_stunned _make_vomiting _makecorridors _makedog functions:133 _makekops _makelevel _makemaz _makemon _makeniche _makeplural _makerogueghost _makeroguerooms functions:134 _makerooms functions:135 _map_menu_cmd _map_object _map_trap _match_optname _mattackm _mattacku _max_capacity _max_mon_load functions:136 _max_passive_dmg _max_rank_sz _maxledgerno _may_dig _may_passwall _maybe_write_ls _maybe_write_timer _mayberem functions:137 _maze0xy _maze1xy _mazexy _mb_trapped _mbag_explodes _mbhit _mbhitm _mcalcdistress functions:138 _md_rush _md_start _md_stop _mdig_tunnel functions:139 _meatobj _melt_ice _menu_drop _menu_identify _menu_loot _menu_remarm _mergable _merge_choice functions:140 _merged _mfndpos _midnight _migrate_to_level _mineralize _minit _miniwalk _minstapetrify functions:140 _On_stairs _on_start _On_W_tower_level _oname _onbill _online2 _only_here _onlyspace functions:141 _mintrap functions:142 _mk_bubble _mk_knox_portal _mk_mplayer _mk_named_object _mk_roamer _mk_tt_object _mkaltar _mkbox_cnts functions:143 _mkcavearea _mkcavepos _mkclass _mkcorpstat _mkfount _mkgold _mkgoldobj _mkinvokearea functions:144 _mkinvpos _mklev _mkmap _mkobj _mkobj_at _mkportal _mkroll_launch _mkroom functions:145 _mkshobj_at _mkshop _mksink _mksobj _mksobj_at _mkstairs _mkswamp _mktemple functions:146 _mktrap _mkundead _mkzoo _mlevel_tele_trap _mlifesaver _mnearto _mnexto _mon_arrive functions:147 _mon_break_armor _mon_catchup_elapsed_time _mon_chain _mon_has_amulet _mon_has_arti _mon_has_special _mon_invent_chain _mon_is_local functions:148 _mon_nam _mon_nam_too _mon_owns _mon_reflects _mon_regen _mon_set_minvis _mon_to_stone _mon_wield_item functions:149 _mondead _mondied _mongets _mongone _monkilled _Monnam _monnear functions:150 _monst_init _monster_detect _monster_nearby _monstinroom _monstone _monstr_init _more _more_experienced functions:151 _morehungry _morguemon _move_gold _move_into_trap _move_special functions:153 _mpickobj functions:154 _mselftouch _msg_in _msleep _msmsg _mstatusline _msummon _mswings _mswingsm functions:155 _mtele_trap _mungspaces _munstone _mv_bubble _mvault_tele _mzapmsg _n_or_more _name_to_mon functions:156 _nameshk _nartifact_exist _nasty _ndemon _near_capacity _nemdead _nemesis_speaks _neminame functions:157 _nethack_exit _new_light_source _new_were _newcham _newexplevel _newgame _newhp _newmail functions:158 _newman _newuexp _newuhs _next_level _next_opt _next_shkp _next_to_u functions:159 _nexttodoor _nh_timeout _nhusage _night _nmcpy _no_bones_level _noattacks _nocmov functions:160 _nohandglow _noises _nomul _Norep _not_capable _not_fully_identified _number_leashed _o_in functions:161 _o_on _o_unleash _obfree _obj_chain _obj_delivery _obj_extract_self _obj_here _obj_ice_effects functions:162 _obj_is_burning _obj_is_local _obj_is_pname _obj_merge_light_sources _obj_move_light_source _obj_move_timers _obj_resists _obj_sanity_check functions:163 _obj_sheds_light _obj_shudders _obj_split_light_source _obj_split_timers _obj_stop_timers _obj_to_let _object_detect _objects_init functions:164 _observable_depth _obstructed _oc_to_str _occupied _off_msg _ohitmon _oinit _ok_to_quest functions:165 _okay functions:167 _onquest _onscary _open_bonesfile _open_drawbridge _open_levelfile _open_library _open_savefile _openit functions:168 _openone _OpenTileFile _opentin _option_help _oselect _other_mon_has_arti _otransit_msg functions:169 _out_container _outentry _outheader _outoracle _outrumor _p_coaligned _pacify_guards _pacify_shk functions:170 _panic _parent_dlevel _parent_dnum _parse _parse_config_line _parseoptions _pass_one _pass_three functions:171 _pass_two _passive _passivemm _passiveum _pay _pay_for_damage _paybill _paygd functions:172 _pckeys _peace_minded _peek_at_iced_corpse_age _peffects _pet_type _pgetchar _phase_of_the_moon functions:173 _pick_level _pick_lock _pick_obj _pick_room _picked_container _picking_at _picking_lock _picklock functions:174 _pickup _pickup_object _place_branch _place_level _place_lregion _place_niche _place_object _place_worm_tail_randomly functions:175 _place_wsegs _placebc _playwoRAMdisk _pleased _pline _pline_The _plnamesuffix _pluslvl functions:176 _pmatch _poisoned _poisontell _poly_gender _poly_obj _poly_when_stoned _polyman _polymon functions:177 _polyself _polyuse _port_help _pos_to_room _positionbar _possible_places _possibly_unwield _potionbreathe functions:178 _potionhit _prayer_done _precheck _prev_level _pri_move _price_quote _priest_talk _priestini functions:179 _priestname _print_branch _print_dungeon _print_queue _prinv _probe_monster _process_menu_window _process_text_window functions:180 _pronoun_gender _protects _prscore _punish _pushch _put_monsters_to_sleep _putsyms functions:181 _qt_montype _qt_pager _query_category _query_classes _query_objlist _quest_chat _quest_info functions:182 _quest_stat_check _quest_talk _random_dir _random_engraving _random_teleport_level _ranged_attk functions:183 _rank _rank_of _raw_printf _read_config_file _read_engr_at _readchar _readentry functions:184 _readmail _readobjnam _ReadPlanarTileFile _ReadPlanarTileFile_O _ReadTileFileHeader _reassign _recalc_wt _recharge functions:185 _record_exists _redist_attr _redotoplin _regularize _rehumanize _rejectoption _relink_light_sources _relink_timers functions:186 _relmon _remember_topl _remove_damage _remove_object _remove_rect _remove_timer _remove_worm functions:187 _removetopl _reorder_invent _repair_damage _replmon _replshk _rescham _reset_attribute_clock functions:188 _reset_eat _reset_faint _reset_hostility _reset_occupations _reset_pick _reset_remarm _reset_rndmonst _reset_trapset functions:189 _resetobjs _resist _resists_blnd _resists_drli _resists_magm _rest_engravings _rest_room _rest_rooms functions:190 _rest_worm _restartcham _restdamage _restfakecorr _restgamestate _restlevchn _restlevelfile _restlevelstate functions:191 _restmonchn _restnames _restobjchn _restore_artifacts _restore_attrib _restore_dungeon _restore_light_sources _restore_oracles functions:192 _restore_saved_game _restore_timers _restore_waterlevel _restpriest _restrap _restrict_name _restshk _resurrect functions:193 _reverse _revive _revive_corpse _revive_egg _revive_mon _revive_nasty _reward_untrap _rhack functions:194 _right_side _rile_shk _Ring_gone _Ring_off _Ring_off_or_gone _Ring_on _rloc _rloc_engr functions:195 _rloc_pos_ok _rloc_to _rloco _rm_waslit _rnd_class _rnd_defensive_item functions:196 _rnd_misc_item _rnd_offensive_item _rnd_rect _rndcurse _rnddoor _rndexp _rndghostname _rndmonnam functions:197 _rndmonnum _rndmonst _rndtrap _rne _rnl _rnz _rogue_vision _roguecorr functions:198 _roguejoin _roguename _rot_corpse _rot_organic _rottenfood _rounddiv _row_refresh _run_timers functions:199 _rust_dmg _s_suffix _safe_teleds _saleable _same_price _sanity_check _save_artifacts _save_currentstate functions:200 _save_dungeon _save_engravings _save_light_sources _save_oracles _save_room _save_rooms _save_savefile_name _save_timers functions:201 _save_waterlevel _save_worm _savebones _savech _savedamage _saveDiskPrompt _savefruitchn _savegamestate functions:202 _savelev _savelev0 _savelevchn _savelife _savemonchn _savenames _saveobjchn _savestateinlock functions:203 _savetrapchn _scatter _schedule_goto _score_wanted _search_door _search_special _searches_for_item _see_lamp_flicker functions:204 _see_monsters _see_objects _see_traps _see_wsegs _seemimic _seetrap _seffects _select_hwep functions:205 _select_off _select_rwep _selftouch _sellobj _sellobj_state _sengr_at _sense_trap functions:206 _set_all_on_page _set_apparxy _set_artifact_intrinsic _set_bc _set_bonesfile_name _set_bonestemp_name _set_corn _set_cost functions:207 _set_crosswall _set_entity _set_item_state _set_itimeout _set_levelfile_name _set_lit _set_lock_and_bones _set_malign functions:208 _set_mimic_blocking _set_mimic_sym _set_mon_data _set_moreluck _set_occupation _set_repo_loc _set_residency _set_savefile_name functions:209 _set_seenv _set_trap _set_twall _set_uasmon _set_wall _set_wall_property _set_wall_state _set_wear functions:210 _set_wounded_legs _set_wportal _setclipped _setftty _setgemprobs _setmangry _setnotworn _setpaid functions:211 _setrandom _settrack _settty _setup_waterlevel _setuwep _setworn _sgn _Shield_off functions:212 _shieldeff _ship_object _shk_chat _shk_embellish _shk_move _shk_names_obj _shk_owns _shk_your functions:213 _Shk_Your _shkcatch _shkgone _shkinit _shkname _sho_obj_return_to_u _shop_debt _shop_keeper functions:214 _shop_object _shopdig _shopper_financial_report _shrine_pos _shrink_worm _shuffle functions:215 _shuffle_all _shuffle_tiles _simple_look _singular _sitoa _skill_advance _skill_init _skill_level_name functions:216 _skinback _sleep_monst _slept_monst _slip_or_trip _sliparm _slots_required _snuff_candle _snuff_light_source functions:217 _snuff_lit _sobj_at _some_armor _somegold _somex _somexy _somey _sort_rooms functions:218 _sort_valuables _sp_lev_shuffle _spec_ability _spec_abon _spec_applies _spec_dbon _spell_damage_bonus _spell_hit_bonus functions:219 _spell_skilltype _spelleffects _spitmu _splatter_burning_oil _split_mon _split_rects _splitbill _splitobj functions:220 _spoteffects _squadmon _srandom _stackobj _standoutbeg _standoutend _start_corpse_timeout _start_eating functions:221 _start_engulf _start_timer _start_tin _steal _steal_it _stealamulet _stealarm _stealgold functions:223 _stop_timer _store_version _strange_feeling _strategy _string_for_env_opt _string_for_opt _strncmpi _strprepend functions:224 _strstri _study_book _stumble_onto_mimic _sub_one_frombill _subfrombill _substitute_tiles _summon_minion _surface functions:225 _swallow_to_glyph _swapin_file _swapout_oldest _switch_graphics _switchar _t_warn functions:226 _tabexpand _tactics _take_gold _take_off _tamedog _target_on _tele _tele_jump_ok functions:227 _tele_restrict _tele_trap _teleds _teleok _teleport_pet _temple_occupied _tended_shop _term_end_attr functions:228 _term_end_color functions:229 _The _this_type_only _thitm _thitmonst _thitu _throw_gold _throwing_weapon _throwit functions:230 _thrwmu _tileview _timed_occupation _timer_is_local _timer_sanity_check _tinnable _title_to_mon _tmp_at functions:231 _topl_putsym _topologize _topten _topten_print _topten_print_bold _toss_up _toss_wsegs _touch_artifact functions:232 _touchfood _trap_detect _trickery _try_disarm _try_lift _trycall _tt_oname _tty_add_menu functions:233 _tty_askname _tty_clear_nhwindow _tty_cliparound functions:234 _tty_display_file _tty_display_nhwindow _tty_doprev_message _tty_end_menu _tty_end_screen _tty_exit_nhwindows _tty_get_ext_cmd _tty_get_nh_event functions:235 _tty_getlin _tty_init_nhwindows _tty_mark_synch _tty_message_menu _tty_nh_poskey _tty_nhbell _tty_nhgetch _tty_number_pad functions:236 _tty_player_selection _tty_raw_print _tty_raw_print_bold _tty_resume_nhwindows _tty_select_menu functions:237 _tty_start_menu _tty_start_screen _tty_startup _tty_suspend_nhwindows _tty_update_inventory _tty_yn_function functions:238 _txt_backsp _txt_cl_end _txt_cl_eos _txt_clear_screen _txt_get_scr_size _txt_monoadapt_check functions:239 _txt_nhbell _txt_startup _u_entered_shop _u_gname _u_init functions:240 _u_left_shop _u_on_dnstairs _u_on_newpos _u_on_sstairs _u_on_upstairs _u_slip_free _u_slow_down _u_teleport_mon functions:241 _u_to_e _u_wipe_engr _ugolemeffects _um_dist _unbless _unblock_point _uncommon _uncompress functions:242 _unconscious _uncurse _undead_to_corpse _under_ground _under_water _undiscover_object _unearth_objs _unfaint functions:243 _unleash_all _unload_qtlist _unlock_file _unmap_object _unmul _unpaid_cost _unplacebc _unpunish functions:244 _unrestrict_weapon_skill _unset_all_on_page _unsetup_waterlevel _unstuck _untrap _untrap_prob _unturn_dead _update_mon_intrinsics functions:245 _update_topl _uptodate _urustm _use_bell _use_camera _use_candelabrum _use_candle _use_container functions:246 _use_crystal_ball _use_defensive _use_figurine _use_grease _use_lamp _use_leash _use_magic_whistle _use_mirror functions:247 _use_misc _use_offensive _use_pick_axe _use_skill _use_stethoscope _use_tinning_kit _use_towel _use_trap functions:248 _use_unicorn_horn _use_whip _use_whistle _useup _useupall _useupf _ustatusline _uunstick functions:249 _uwepgone _vault_occupied _vault_tele _verbalize _vga_backsp _vga_cl_end _vga_cl_eos _vga_clear_screen functions:250 _vga_cliparound _vga_detect _vga_DisplayCell _vga_DisplayCell_O _vga_DrawCursor _vga_Finish _vga_FontPtrs _vga_get_scr_size functions:251 _vga_gotoloc _vga_HideCursor _vga_Init _vga_overview _vga_redrawmap _vga_refresh _vga_SetPalette _vga_SwitchMode functions:252 _vga_traditional _vga_tty_end_screen _vga_tty_startup _vga_update_positionbar _vga_userpan _vga_WriteChar _vga_WriteStr _vga_xputc functions:254 _vision_reset _dodiscovered _dodoor _dodown _dodrink _dodrop _doeat _doengrave functions:255 _wallification _wallify_map _wallify_vault _wantdoor _watch_on_duty _water_damage _water_friction functions:256 _water_prayer _weapon_dam_bonus _weapon_hit_bonus _weapon_type _wearing_armor _weffects _weight functions:257 _weight_cap functions:258 _whimper _wield_tool _wildmiss _win_tty_init _wipe_engr_at _wipeoff _wipeout_text functions:259 _wiz_detect _wiz_genesis _wiz_identify _wiz_level_tele _wiz_light_sources _wiz_map _wiz_show_seenv _wiz_show_vision functions:260 _wiz_show_wmodes _wiz_timeout_queue _wiz_where _wiz_wish _wizdead _worm_known _worm_move _worm_nomove functions:261 _wormgone _wormhitu _worn_wield_only _write_ls _writeentry _wrong_elem_type _x_monnam _xcrypt _xkilled _xlev_to_rank _xname _xprname functions:263 _xytod _yelp _yname _Yname2 _You _you_aggravate _You_cant _You_feel _you_have _You_hear _you_unwere _you_were _Your _zap_dig functions:265 _zap_hit _zap_over_floor _zap_updown _zapdir_to_glyph _zapnodir _zappable _zapyourself _zhitm _zhitu _put_lregion_here _role_init ; tuning ; this was 23 functions:266 _bp_to_obj ; the next two were 238 functions:268 _aggravate ; the following were 118 ;functions:269 ; the following were 261 ;functions:270 functions:271 _xputg functions:272 _xputs _xwaitforspace ; the following were 158 functions:273 _enermod _enlightenment ; the following was 214 ;functions:274 _enter_explore_mode ; the following were 26 functions:275 _bydoor functions:276 _calc_capacity _call_kops _calm_nymphs functions:277 _can_advance _can_be_hatched functions:278 _can_carry ; the following were 239 functions:279 _equipname functions:280 _txt_xputs ; the following were 80 functions:281 _enexto ;functions:282 functions:283 _enhance_weapon_skill ; the following were 165 functions:284 _okdoor functions:285 _omon_adj functions:286 _on_goal functions:287 _on_ground functions:288 _b_trapped functions:289 _on_locate functions:290 _on_msg ; the following were 182 functions:291 _y_monnam ; the following were 195 ;functions:293 ; the following were 225 functions:294 _erode_armor functions:295 _swallowed ; the following were 7 functions:298 _acurrstr ; the following were 17 functions:299 _attacktype functions:300 _attrcurse functions:301 _automiss functions:302 _autopick ; the following were 10 functions:303 _adj_abon functions:304 _adj_lev functions:305 _adjabil functions:306 _adjalign functions:307 _adjattrib ; was 53 functions:308 _display_monster functions:309 _error ; was 117 ;functions:310 functions:311 _is_ok_location ;functions:312 functions:313 _is_pure functions:314 _is_quest_artifact ; was 236 functions:316 _tty_putstr _tty_putsym ; was 81 functions:318 _escapes functions:319 _erase_menu_or_text functions:320 _eraseall ; tuning 2 ; was 269 functions:321 _weldmsg _were_change _were_summon functions:322 _where_name _which_armor _which_arti functions:325 _term_end_raw_bold functions:326 _term_start_attr ;functions:327 functions:328 _term_start_raw_bold functions:329 _terminate functions:330 _tgetch functions:331 _the functions:332 _m_monnam functions:333 _domagictrap _domindblast _domonability functions:334 _m_respond functions:335 _m_slips_free functions:336 _m_throw functions:337 _m_to_e functions:338 _m_unleash functions:339 _mpickstuff functions:340 _mplayer_talk functions:341 _mpoisons_subj functions:342 _mquaffmsg functions:343 _miss functions:344 _mreadmsg functions:345 _mrustm functions:346 _vomit _vomiting_dialogue functions:347 _wake_nearby functions:348 _wake_nearto functions:349 _wakeup functions:350 _walkfrom functions:351 _wall_angle functions:352 _able_to_loot _add_mon_to_reg _add_rect_to_reg _add_region _addinv_core1 functions:352 _addinv_core2 _age_spells _align_gtitle _align_shift _align_str _all_but_uchain functions:353 _allow_all _allow_category _already_wearing _already_wearing2 _angrygods functions:354 _animate_statue _antholemon _arti_speak _assign_warnings _attach_fig_transform_timeout _blocked_boulder functions:355 _book_substitution _burn_away_slime _can_blnd _can_ride _can_saddle _can_twoweapon functions:356 _carry_obj_effects _clear_regions _container_at _coyotename _create_gas_cloud _create_region functions:357 _describe_level _dfeature_at _dig_up_grave _discover_artifact _dismount_steed _disp_artifact_discoveries functions:359 _doconduct _dofire _doprinuse _doride _doswapweapon _dotwoweapon functions:360 _dowieldquiver _drain_item _exercise_steed _expire_gas_cloud _extcmd_via_menu _feature_alert_opts functions:361 _fig_transform _figurine_location_checks _final_level _find_trap _finish_quest _fix_petrification functions:362 _food_substitution _fqname _free_invbuf _free_region _free_youbuf _freeinv_core functions:363 _fuzzymatch _get_compopt_value _get_current_feature_ver _get_feature_notice_ver _get_mtraits _getlev functions:364 _getlock _getobj _getpos _give_may_advance_msg _Goodbye _halu_gname functions:365 _Hello _hurtle_step _hurtmarmor _in_out_region _initialspell _inside_gas_cloud functions:366 _inside_rect _inside_region _kick_steed _look_here _m_in_out_region _make_grave functions:367 _mbodypart _mdamagem _mdamageu _minimal_enlightenment _mk_mplayer_armor _mm_aggression functions:368 _mon_adjust_speed _mon_animal_list _mon_beside _mon_in_region _montraits _mount_steed functions:369 _noit_mon_nam _noit_Monnam _noncoalignment _num_genocides _obj_attach_mid _obj_timer_checks functions:370 _obj_typename _ok_align _ok_gend _ok_race _ok_role _ordin functions:371 _pick_align _pick_animal _pick_gend _pick_nasty _pick_race _pick_role functions:372 _place_monster _pm_to_cham _prisoner_speaks _process_options _randalign _randgend functions:373 _randrace _randrole _realloc_obj _relobj _remove_mon_from_reg _remove_region functions:374 _remove_worn_item _replace_object _reset_oattached_mids _rest_regions _restore_cham _rnd_treefruit_at functions:375 _save_regions _select_newcham_form _self_invis_message _setuqwep _setuswapwep _show_conduct functions:376 _show_region _simple_typename _slime_dialogue _sokoban_detect _spec_m2 _special_handling functions:377 _str2align _str2gend _str2race _str2role _There _throw_obj functions:378 _tmiss _tty_update_positionbar _tty_wait_synch _undiscovered_artifact _untwoweapon _update_mlstmv functions:379 _update_monster_region _update_player_regions _uqwepgone _ureflects _use_grapple _use_pole functions:380 _use_saddle _uswapwepgone _uwep_skill_type _validalign _validgend _validrace functions:381 _validrole _violated_vegetarian _walk_path _warning_opts _wary_dog _welcome functions:382 _write_timer _yyyymmdd _zap_steed functions:383 _getprice _getreturn _getrumor _gettrack functions:384 _ini_inv _knows_object _knows_class _restricted_spell_discipline _ready_weapon functions:385 _doname _Doname2 functions:386 _minliquid functions:387 _missmm functions:388 _missmu functions:389 _missum functions:390 _mixtype _mk_artifact functions:391 _makesingular functions:392 _maketrap _makevtele _makewish nethack-3.4.3/sys/msdos/setup.bat0100644000000000000000000001310607764735152015451 0ustar rootroot@echo off REM SCCS Id: @(#)setup.bat 2002/03/17 REM Copyright (c) NetHack PC Development Team 1990 - 2002 REM NetHack may be freely redistributed. See license for details. echo. echo Copyright (c) NetHack PC Development Team 1990 - 2002 echo NetHack may be freely redistributed. See license for details. echo. REM setup batch file for msdos, see Install.dos for details. if not %1.==. goto ok_parm goto err_set :ok_parm echo Checking to see if directories are set up properly ... if not exist ..\..\include\hack.h goto err_dir if not exist ..\..\src\hack.c goto err_dir if not exist ..\..\dat\wizard.des goto err_dir if not exist ..\..\util\makedefs.c goto err_dir if not exist ..\..\win\tty\wintty.c goto err_dir if not exist ..\share\lev_yacc.c goto err_dir echo Directories OK. if not exist ..\..\binary\* mkdir ..\..\binary if NOT exist ..\..\binary\license copy ..\..\dat\license ..\..\binary\license >nul if exist ..\..\dat\data.bas goto long1ok if exist ..\..\dat\data.base goto long1a if exist ..\..\dat\data~1.bas goto long1b goto err_long :long1a echo Changing some long-named distribution file names: echo "Copying ..\..\dat\data.base -> ..\..\dat\data.bas" copy ..\..\dat\data.base ..\..\dat\data.bas if exist ..\..\dat\data.old del /Q ..\..\dat\data.old ren ..\..\dat\data.base data.old goto long1ok :long1b echo Changing some long-named distribution file names: echo "Copying ..\..\dat\data~1.bas -> ..\..\dat\data.bas" copy ..\..\dat\data~1.bas ..\..\dat\data.bas if exist ..\..\dat\data.old del /Q ..\..\dat\data.old ren ..\..\dat\data~1.bas data.old :long1ok if exist ..\..\include\patchlev.h goto long2ok if exist ..\..\include\patchlevel.h goto long2a if exist ..\..\include\patchl~1.h goto long2b goto err_long :long2a echo "Copying ..\..\include\patchlevel.h -> ..\..\include\patchlev.h" copy ..\..\include\patchlevel.h ..\..\include\patchlev.h if exist ..\..\include\patchlev.old del /Q ..\..\include\patchlev.old ren ..\..\include\patchlevel.h patchlev.old goto long2ok :long2b echo "Copying ..\..\include\patchl~1.h -> ..\..\include\patchlev.h" copy ..\..\include\patchl~1.h ..\..\include\patchlev.h if exist ..\..\include\patchlev.old del /Q ..\..\include\patchlev.old ren ..\..\include\patchl~1.h patchlev.old :long2ok REM Missing guidebook is not fatal to the build process if exist ..\..\doc\guideboo.txt goto long3ok if exist ..\..\doc\guidebook.txt goto long3a if exist ..\..\doc\guideb~1.txt goto long3b goto warn3long :long3a echo "Copying ..\..\doc\guidebook.txt -> ..\..\doc\guideboo.txt" copy ..\..\doc\guidebook.txt ..\..\doc\guideboo.txt if exist ..\..\doc\guideboo.old del /Q ..\..\doc\guideboo.old ren ..\..\doc\guidebook.txt guideboo.old goto long3ok :long3b echo "Copying ..\..\doc\guideb~1.txt -> ..\..\doc\guideboo.txt" copy ..\..\doc\guideb~1.txt ..\..\doc\guideboo.txt if exist ..\..\doc\guideboo.old del /Q ..\..\doc\guideboo.old ren ..\..\doc\guideb~1.txt guideboo.old goto long3ok :warn3long echo "Warning - There is no NetHack Guidebook (..\..\doc\guideboo.txt)" echo " included in your distribution. Build will proceed anyway." :long3ok if "%1"=="GCC" goto ok_gcc if "%1"=="gcc" goto ok_gcc if "%1"=="nmake" goto ok_msc if "%1"=="NMAKE" goto ok_msc if "%1"=="BC" goto ok_bc if "%1"=="bc" goto ok_bc if "%1"=="MSC" goto ok_msc if "%1"=="msc" goto ok_msc goto err_set :ok_gcc echo Symbolic links, msdos style echo "Makefile.GCC -> ..\..\src\makefile" copy makefile.GCC ..\..\src\makefile goto done :ok_msc echo Copying Makefile for Microsoft C and Microsoft NMAKE. echo "Makefile.MSC -> ..\..\src\makefile" copy Makefile.MSC ..\..\src\makefile echo Copying overlay schemas to ..\..\src copy schema*.MSC ..\..\src\schema*.DEF :ok_cl goto done :ok_bc echo Copying Makefile for Borland C and Borland's MAKE. echo "Makefile.BC -> ..\..\src\makefile" copy Makefile.BC ..\..\src\makefile echo Copying overlay schemas to ..\..\src copy schema*.BC ..\..\src goto done :err_long echo. echo ** ERROR - New file system with "long file name support" problem. ** echo A couple of NetHack distribution files that are packaged with echo a long filename ( exceeds 8.3) appear to be missing from your echo distribution. echo The following files need to exist under the names on the echo right in order to build NetHack: echo. echo ..\..\dat\data.base needs to be copied to ..\..\dat\data.bas echo ..\..\include\patchlevel.h needs to be copied to ..\..\include\patchlev.h echo. echo setup.bat was unable to perform the necessary changes because at least echo one of the files doesn't exist under its short name, and the echo original (long) file name to copy it from was not found either. echo. goto end :err_set echo. echo Usage: echo "%0 " echo. echo Run this batch file specifying on of the following: echo GCC, MSC, BC echo. echo (depending on which compiler and/or make utility you are using). echo. echo The GCC argument is for use with djgpp and the NDMAKE utility. echo. echo The MSC argument is for use with Microsoft C and the NMAKE utility echo that ships with it (MSC 7.0 or greater only, including Visual C). echo. echo The BC argument is for use with Borland C and Borland's MAKE utility echo that ships with it (Borland C++ 3.1 only). echo. goto end :err_dir echo/ echo Your directories are not set up properly, please re-read the echo Install.dos and README documentation. goto end :done echo Setup Done! echo Please continue with next step from Install.dos. :end nethack-3.4.3/sys/msdos/sound.c0100644000000000000000000001526507764735041015122 0ustar rootroot/* SCCS Id: @(#)sound.c 3.4 1996/02/19 */ /* Copyright (c) NetHack PC Development Team 1993,1995 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * sound.c - Hardware sound support * *Edit History: * Initial Creation 93/10/01 * Added PC Speaker Support for BC compilers 95/06/14 * Completed various fixes 96/02/19 * */ #include "hack.h" #include #include "portio.h" #include #include #ifndef TESTING #define printf pline int assign_soundcard(sopt) char *sopt; { iflags.hassound = 0; # ifdef PCMUSIC iflags.usepcspeaker = 0; # endif if (strncmpi(sopt,"def",3) == 0) { /* default */ /* do nothing - default */ } # ifdef PCMUSIC else if (strncmpi(sopt,"speaker",7) == 0) { /* pc speaker */ iflags.usepcspeaker = 1; } # endif else if (strncmpi(sopt,"auto",4) == 0) { /* autodetect */ /* * Auto-detect Priorities (arbitrary for now): * Just pcspeaker */ if (0) ; # ifdef PCMUSIC else iflags.usepcspeaker = 1; # endif } else { return 0; } return 1; } #endif #ifdef PCMUSIC /* 8254/3 Control Word Defines */ #define CTR0SEL (0<<6) #define CTR1SEL (1<<6) #define CTR2SEL (2<<6) #define RDBACK (3<<6) #define LATCH (0<<4) #define RW_LSB (1<<4) #define RW_MSB (2<<4) /* If both LSB and MSB are read, LSB is done first */ #define MODE0 (0<<1) /* Interrupt on terminal count */ #define MODE1 (1<<1) /* Hardware One-Shot */ #define MODE2 (2<<1) /* Pulse Generator */ #define MODE3 (3<<1) /* Square Wave Generator */ #define MODE4 (4<<1) /* Software Triggered Strobe */ #define MODE5 (5<<1) /* Hardware Triggered Strobe */ #define BINARY (0<<0) /* Binary counter (16 bits) */ #define BCD (1<<0) /* Binary Coded Decimal (BCD) Counter (4 Decades) */ /* Misc 8254/3 Defines */ #define TIMRFRQ (1193180UL) /* Input frequency to the clock (Hz) */ /* Speaker Defines */ #define TIMER (1<<0) /* Timer 2 Output connected to Speaker */ #define SPKR_ON (1<<1) /* Turn on/off Speaker */ /* Port Definitions */ /* 8254/3 Ports */ #define CTR0 0x40 #define CTR1 0x41 #define CTR2 0x42 #define CTRL 0x43 /* Speaker Port */ #define SPEAKER 0x61 void startsound (unsigned freq) { /* To start a sound on the PC: * * First, set the second counter to have the correct frequency: */ unsigned count; if (freq == 0) freq = 523; count = TIMRFRQ / freq; /* Divide frequencies to get count. */ #ifdef TESTING printf ("freq = %u, count = %u\n", freq, count); #endif outportb (CTRL, CTR2SEL|RW_LSB|RW_MSB|MODE3|BINARY); outportb (CTR2, count & 0x0FF); outportb (CTR2, count / 0x100); /* Next, turn on the speaker */ outportb (SPEAKER, inportb(SPEAKER)|TIMER|SPKR_ON); } void stopsound (void) { outportb (SPEAKER, inportb(SPEAKER) & ~(TIMER|SPKR_ON)); } static unsigned tempo, length, octave, mtype; /* The important numbers here are 287700UL for the factors and 4050816000UL * which gives the 440 Hz for the A below middle C. "middle C" is assumed to * be the C at octave 3. The rest are computed by multiplication/division of * 2^(1/12) which came out to 1.05946 on my calculator. It is assumed that * no one will request an octave beyond 6 or below 0. (At octave 7, some * notes still come out ok, but by the end of the octave, the "notes" that * are produced are just ticks. * These numbers were chosen by a process based on the C64 tables (which * weren't standardized) and then were 'standardized' by giving them the * closest value. That's why they don't seem to be based on any sensible * number. */ unsigned long notefactors[12] = { 483852, 456695, 431063, 406869, 384033, 362479, 342135, 322932, 304808, 287700, 271553, 256312 }; void note (long notenum) { startsound ((unsigned) (4050816000UL / notefactors[notenum % 12] >> (7 - notenum / 12))); } int notes[7] = { 9, 11, 0, 2, 4, 5, 7 }; char * startnote (char *c) { long n; n = notes[toupper(*c++) - 'A'] + octave * 12; if (*c == '#' || *c == '+') { n++; c++; } else if (*c == '-') { if (n) n--; c++; } note (n); return --c; } void delaytime (unsigned time) { /* time and twait are in units of milliseconds */ unsigned twait; switch (toupper (mtype)) { case 'S': twait = time / 4; break; case 'L': twait = 0; break; default: twait = time / 8; break; } msleep (time - twait); stopsound (); msleep (twait); } char * delaynote (char *c) { unsigned time = 0; while (isdigit(*c)) time = time * 10 + (*c++ - '0'); if (!time) time = length; time = (unsigned)(240000 / time / tempo); while (*c == '.') { time = time * 3 / 2; c++; } delaytime (time); return c; } void initspeaker (void) { tempo = 120, length = 4, octave = 3, mtype = 'N'; } void play (char *tune) { char *c, *n; unsigned num; for (c = tune; *c; ) { sscanf (c + 1, "%u", &num); for (n = c + 1; isdigit(*n); n++) /* do nothing */; if (isspace(*c)) c++; else switch (toupper(*c)) { case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': c = startnote (c); case 'P': c = delaynote (++c); break; #if 0 case 'M': c++; mtype = *c; c++; break; case 'T': if (num) tempo = num; else printf ("Zero Tempo (%s)!\n", c); c = n; break; case 'L': if (num) length = num; else printf ("Zero Length (%s)!\n", c); c = n; break; case 'O': if (num <= 7) octave = num; c = n; break; case 'N': note (num); delaytime ((240000/length/tempo)); c = n; break; case '>': if (octave < 7) octave++; c++; break; case '<': if (octave) octave--; c++; break; #endif case ' ': c++; break; default: printf ("Unrecognized play value (%s)!\n", c); return; } } } #ifndef TESTING void pc_speaker (struct obj *instr, char *tune) { if (!iflags.usepcspeaker) return; initspeaker (); switch (instr->otyp) { case WOODEN_FLUTE: case MAGIC_FLUTE: octave = 5; /* up one octave */ break; case TOOLED_HORN: case FROST_HORN: case FIRE_HORN: octave = 2; /* drop two octaves */ break; case BUGLE: break; case WOODEN_HARP: case MAGIC_HARP: length = 8; mtype = 'L'; /* fast, legato */ break; } play (tune); } #else main () { char s[80]; int tool; initspeaker(); printf ("1) flute\n2) horn\n3) harp\n4) other\n"); fgets (s, 80, stdin); sscanf (s, "%d", &tool); switch (tool) { case 1: octave = 5; break; case 2: octave = 2; break; case 3: length = 8; mtype = 'L'; break; default: break; } printf ("Enter tune:"); fgets(s, 80, stdin); play (s); } #endif #endif /* PCMUSIC */ /* sound.c */ nethack-3.4.3/sys/msdos/tile2bin.c0100644000000000000000000001624007764735041015474 0ustar rootroot/* SCCS Id: @(#)tile2bin.c 3.4 1995/01/26 */ /* Copyright (c) NetHack PC Development Team 1993, 1994, 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * Edit History: * * Initial Creation M.Allison 93/10/21 * ifndef MONITOR_HEAP for heaputil.c P.Winner 94/03/12 * added Borland C _stklen variable Y.Sapir 94/05/01 * fixed to use text tiles from win/share M.Allison 95/01/31 * */ #include "hack.h" #include "pcvideo.h" #include "tile.h" #include "pctiles.h" #include #ifndef MONITOR_HEAP #include #endif #include #ifdef __GO32__ #include #endif #if defined(_MSC_VER) && _MSC_VER >= 700 #pragma warning(disable:4309) /* initializing */ #pragma warning(disable:4018) /* signed/unsigned mismatch */ #pragma warning(disable:4131) /* old style declarator */ #pragma warning(disable:4127) /* conditional express. is constant */ #endif #ifdef __BORLANDC__ extern unsigned _stklen = STKSIZ; #endif extern char *FDECL(tilename, (int, int)); #ifdef PLANAR_FILE char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; char charcolors[MAXCOLORMAPSIZE]; #ifdef OVERVIEW_FILE struct overview_planar_cell_struct planetile; #else struct planar_cell_struct planetile; #endif FILE *tibfile1; #endif #ifdef PACKED_FILE char packtile[TILE_Y][TILE_X]; FILE *tibfile2; #endif int num_colors; pixel pixels[TILE_Y][TILE_X]; struct tibhdr_struct tibheader; static void FDECL(write_tibtile, (int)); static void FDECL(write_tibheader, (FILE *, struct tibhdr_struct *)); static void FDECL(build_tibtile, (pixel (*)[TILE_X])); #ifndef OVERVIEW_FILE char *tilefiles[] = { "../win/share/monsters.txt", "../win/share/objects.txt", "../win/share/other.txt"}; #else char *tilefiles[] = { "../win/share/monthin.txt", "../win/share/objthin.txt", "../win/share/oththin.txt"}; #endif int tilecount; int filenum; int paletteflag; int main(argc, argv) int argc; char *argv[]; { int i; struct tm *newtime; time_t aclock; char *paletteptr; if (argc != 1) { Fprintf(stderr, "usage: tile2bin (from the util directory)\n"); exit(EXIT_FAILURE); } #ifdef PLANAR_FILE # ifndef OVERVIEW_FILE tibfile1 = fopen(NETHACK_PLANAR_TILEFILE, WRBMODE); # else tibfile1 = fopen(NETHACK_OVERVIEW_TILEFILE, WRBMODE); # endif if (tibfile1 == (FILE *)0) { Fprintf(stderr, "Unable to open output file %s\n", # ifndef OVERVIEW_FILE NETHACK_PLANAR_TILEFILE); #else NETHACK_OVERVIEW_TILEFILE); #endif exit(EXIT_FAILURE); } #endif #ifdef PACKED_FILE tibfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE); if (tibfile2 == (FILE *)0) { Fprintf(stderr, "Unable to open output file %s\n", NETHACK_PACKED_TILEFILE); exit(EXIT_FAILURE); } #endif time(&aclock); newtime = localtime(&aclock); tilecount = 0; paletteflag = 0; filenum = 0; while (filenum < 3) { if (!fopen_text_file(tilefiles[filenum], RDTMODE)) { Fprintf(stderr, "usage: tile2bin (from the util or src directory)\n"); exit(EXIT_FAILURE); } num_colors = colorsinmap; if (num_colors > 62) { Fprintf(stderr, "too many colors (%d)\n", num_colors); exit(EXIT_FAILURE); } if (!paletteflag) { paletteptr = tibheader.palette; for (i = 0; i < num_colors; i++) { *paletteptr++ = ColorMap[CM_RED][i], *paletteptr++ = ColorMap[CM_GREEN][i], *paletteptr++ = ColorMap[CM_BLUE][i]; } paletteflag++; } while (read_text_tile(pixels)) { build_tibtile(pixels); write_tibtile(tilecount); tilecount++; } (void) fclose_text_file(); ++filenum; } # if defined(_MSC_VER) tibheader.compiler = MSC_COMP; # elif defined(__BORLANDC__) tibheader.compiler = BC_COMP; # elif defined(__GO32__) tibheader.compiler = DJGPP_COMP; # else tibheader.compiler = OTHER_COMP; # endif strncpy(tibheader.ident, "NetHack 3.4 MSDOS Port binary tile file", 80); strncpy(tibheader.timestamp, asctime(newtime), 24); tibheader.timestamp[25] = '\0'; tibheader.tilecount = tilecount; tibheader.numcolors = num_colors; # ifdef PLANAR_FILE tibheader.tilestyle = PLANAR_STYLE; write_tibheader(tibfile1, &tibheader); (void) fclose(tibfile1); # ifndef OVERVIEW_FILE Fprintf(stderr, "Total of %d planar tiles written to %s.\n", tilecount, NETHACK_PLANAR_TILEFILE); # else Fprintf(stderr, "Total of %d planar tiles written to %s.\n", tilecount, NETHACK_OVERVIEW_TILEFILE); # endif # endif # ifdef PACKED_FILE tibheader.tilestyle = PACKED_STYLE; write_tibheader(tibfile2, &tibheader); Fprintf(stderr, "Total of %d packed tiles written to %s.\n", tilecount, NETHACK_PACKED_TILEFILE); (void) fclose(tibfile2); # endif exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } static void write_tibheader(fileptr,tibhdr) FILE *fileptr; struct tibhdr_struct *tibhdr; { if (fseek(fileptr,0L,SEEK_SET)) { Fprintf(stderr, "Error writing header to tile file\n"); } fwrite(tibhdr, sizeof(struct tibhdr_struct), 1, fileptr); } static void build_tibtile(pixels) pixel (*pixels)[TILE_X]; { int i, j, k, co_off; unsigned char co_mask,tmp; #ifndef OVERVIEW_FILE memset((void *)&planetile,0,sizeof(struct planar_cell_struct)); #else memset((void *)&planetile,0, sizeof(struct overview_planar_cell_struct)); #endif for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { for (k = 0; k < num_colors; k++) { if (ColorMap[CM_RED][k] == pixels[j][i].r && ColorMap[CM_GREEN][k] == pixels[j][i].g && ColorMap[CM_BLUE][k] == pixels[j][i].b) break; } if (k >= num_colors) Fprintf(stderr, "color not in colormap!\n"); #ifdef PACKED_FILE packtile[j][i] = k; #endif #ifdef PLANAR_FILE if (i > 7) { co_off = 1; co_mask = masktable[i - 8]; } else { co_off = 0; co_mask = masktable[i]; } tmp = planetile.plane[0].image[j][co_off]; planetile.plane[0].image[j][co_off] = (k & 0x0008) ? (tmp | co_mask) : (tmp & ~co_mask); tmp = planetile.plane[1].image[j][co_off]; planetile.plane[1].image[j][co_off] = (k & 0x0004) ? (tmp | co_mask) : (tmp & ~co_mask); tmp = planetile.plane[2].image[j][co_off]; planetile.plane[2].image[j][co_off] = (k & 0x0002) ? (tmp | co_mask) : (tmp & ~co_mask); tmp = planetile.plane[3].image[j][co_off]; planetile.plane[3].image[j][co_off] = (k & 0x0001) ? (tmp | co_mask) : (tmp & ~co_mask); #endif /* PLANAR_FILE */ } } } static void write_tibtile(recnum) int recnum; { long fpos; #ifdef PLANAR_FILE # ifndef OVERVIEW_FILE fpos = ((long)(recnum) * (long)sizeof(struct planar_cell_struct)) + (long)TIBHEADER_SIZE; # else fpos = ((long)(recnum) * (long)sizeof(struct overview_planar_cell_struct)) + (long)TIBHEADER_SIZE; # endif if (fseek(tibfile1,fpos,SEEK_SET)) { Fprintf(stderr, "Error seeking before planar tile write %d\n", recnum); } # ifndef OVERVIEW_FILE fwrite(&planetile, sizeof(struct planar_cell_struct), 1, tibfile1); # else fwrite(&planetile, sizeof(struct overview_planar_cell_struct), 1, tibfile1); # endif #endif #ifdef PACKED_FILE fpos = ((long)(recnum) * (long)sizeof(packtile)) + (long)TIBHEADER_SIZE; if (fseek(tibfile2,fpos,SEEK_SET)) { Fprintf(stderr, "Error seeking before packed tile write %d\n", recnum); } fwrite(&packtile, sizeof(packtile), 1, tibfile2); #endif } nethack-3.4.3/sys/msdos/video.c0100644000000000000000000004763707764735041015110 0ustar rootroot/* SCCS Id: @(#)video.c 3.4 2001/04/07 */ /* Copyright (c) NetHack PC Development Team 1993, 1994, 2001 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * video.c - Hardware video support front-ends * *Edit History: * Initial Creation M. Allison 1993/04/04 * Add djgpp support K. Smolkowski 1993/04/26 * Add txt/graphics mode support M. Allison 1993/10/30 * Add graphics mode cursor sim. M. Allison 1994/02/19 * Add hooks for decals on vga M. Allison 2001/04/07 */ #include "hack.h" #ifndef STUBVIDEO #include "pcvideo.h" #include "pctiles.h" #if defined(_MSC_VER) # if _MSC_VER >= 700 #pragma warning(disable:4018) /* signed/unsigned mismatch */ #pragma warning(disable:4127) /* conditional expression is constant */ #pragma warning(disable:4131) /* old style declarator */ #pragma warning(disable:4305) /* prevents complaints with MK_FP */ #pragma warning(disable:4309) /* initializing */ #pragma warning(disable:4759) /* prevents complaints with MK_FP */ # endif #endif /*========================================================================= * General PC Video routines. * * The following routines are the video interfacing functions. * In general these make calls to more hardware specific * routines in other source files. * * Assumptions (94/04/23): * * - Supported defaults.nh file video options: * * If OPTIONS=video:autodetect is defined in defaults.nh then * check for a VGA video adapter. If one is detected, then * use the VGA code, otherwise resort to using the 'standard' * video BIOS routines. * * If OPTIONS=video:vga is defined in defaults.nh, then use * the VGA code. * * If OPTIONS=video:default is defined in defaults.nh use the * 'standard' video BIOS routines (in the overlaid version), * or DJGPPFAST routines (under djgpp). This is equivalent to * having no OPTIONS=video:xxxx entry at all. * * Notes (94/04/23): * * - The handler for defaults.nh file entry: * * OPTIONS=video:xxxxx * * has now been added. The handler is in video.c and is called * from options.c. * * - Handling of videocolors and videoshades are now done with * OPTIONS= statements. The new syntax separates the colour * values with dashes ('-') rather than spaces (' '). * * To Do (94/04/23): * * *========================================================================= */ #ifdef OVLB void get_scr_size() { # ifdef SCREEN_VGA if (iflags.usevga) { vga_get_scr_size(); } else # endif txt_get_scr_size(); } #endif /*OVLB*/ /* * -------------------------------------------------------------- * The rest of this file is only compiled if NO_TERMS is defined. * -------------------------------------------------------------- */ #ifdef NO_TERMS #include #include "wintty.h" # ifdef __GO32__ #include #include #if !(__DJGPP__ >= 2) typedef long clock_t; #endif # endif # ifdef __BORLANDC__ #include /* needed for delay() */ # endif # ifdef SCREEN_DJGPPFAST /* parts of this block may be unecessary now */ #define get_cursor(x,y) ScreenGetCursor(y,x) # endif # ifdef SCREEN_BIOS void FDECL(get_cursor, (int *, int *)); # endif void FDECL(adjust_cursor_flags, (struct WinDesc *)); void FDECL(cmov, (int, int)); void FDECL(nocmov, (int, int)); STATIC_DCL void NDECL(init_ttycolor); # ifdef OVLB int savevmode; /* store the original video mode in here */ int curcol,currow; /* graphics mode current cursor locations */ int g_attribute; /* Current attribute to use */ int monoflag; /* 0 = not monochrome, else monochrome */ int attrib_text_normal; /* text mode normal attribute */ int attrib_gr_normal; /* graphics mode normal attribute */ int attrib_text_intense; /* text mode intense attribute */ int attrib_gr_intense; /* graphics mode intense attribute */ boolean traditional = FALSE; /* traditonal TTY character mode */ boolean inmap = FALSE; /* in the map window */ # ifdef TEXTCOLOR char ttycolors[CLR_MAX]; /* also used/set in options.c */ # endif /* TEXTCOLOR */ # else extern int savevmode; extern int curcol,currow; extern int g_attribute; extern int monoflag; extern int attrib_text_normal; extern int attrib_gr_normal; extern int attrib_text_intense; extern int attrib_gr_intense; extern boolean traditonal; extern boolean inmap; # ifdef TEXTCOLOR extern char ttycolors[CLR_MAX]; /* also used/set in options.c */ # endif /* TEXTCOLOR */ # endif /* OVLB */ # ifdef OVLB void backsp() { if (!iflags.grmode) { txt_backsp(); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_backsp(); # endif } } # endif /* OVLB */ # ifdef OVL0 void clear_screen() { if (!iflags.grmode) { txt_clear_screen(); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_clear_screen(BACKGROUND_VGA_COLOR); # endif } } void cl_end() /* clear to end of line */ { int col,row; col = (int)ttyDisplay->curx; row = (int)ttyDisplay->cury; if (!iflags.grmode) { txt_cl_end(col,row); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_cl_end(col,row); # endif } tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury); } void cl_eos() /* clear to end of screen */ { int cy = (int)ttyDisplay->cury+1; if (!iflags.grmode) { txt_cl_eos(); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_cl_eos(cy); # endif } tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury); } void cmov(col, row) register int col, row; { ttyDisplay->cury = (uchar)row; ttyDisplay->curx = (uchar)col; if (!iflags.grmode) { txt_gotoxy(col,row); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_gotoloc(col,row); # endif } } # endif /* OVL0 */ # ifdef OVLB int has_color(int color) { ++color; /* prevents compiler warning (unref. param) */ # ifdef TEXTCOLOR return (monoflag) ? 0 : 1; # else return 0; # endif } # endif /* OVLB */ # ifdef OVL0 void home() { tty_curs(BASE_WINDOW, 1, 0); ttyDisplay->curx = ttyDisplay->cury = (uchar)0; if (!iflags.grmode) { txt_gotoxy(0,0); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_gotoloc(0,0); # endif } } void nocmov(col, row) int col,row; { if (!iflags.grmode) { txt_gotoxy(col,row); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_gotoloc(col,row); # endif } } void standoutbeg() { g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; } void standoutend() { g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; } # endif /* OVL0 */ # ifdef OVLB void term_end_attr(int attr) { switch(attr) { case ATR_ULINE: case ATR_BOLD: case ATR_BLINK: case ATR_INVERSE: default: g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; } } void term_end_color(void) { g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; } void term_end_raw_bold(void) { standoutend(); } void term_start_attr(int attr) { switch(attr){ case ATR_ULINE: if (monoflag) { g_attribute = ATTRIB_MONO_UNDERLINE; } else { g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; } break; case ATR_BOLD: g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; break; case ATR_BLINK: if (monoflag) { g_attribute = ATTRIB_MONO_BLINK; } else { g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; } break; case ATR_INVERSE: if (monoflag) { g_attribute = ATTRIB_MONO_REVERSE; } else { g_attribute = iflags.grmode ? attrib_gr_intense : attrib_text_intense; } break; default: g_attribute = iflags.grmode ? attrib_gr_normal : attrib_text_normal; break; } } void term_start_color(int color) { # ifdef TEXTCOLOR if (monoflag) { g_attribute = attrib_text_normal; } else { if (color >= 0 && color < CLR_MAX) { if (iflags.grmode) g_attribute = color; else g_attribute = ttycolors[color]; } } # endif } void term_start_raw_bold(void) { standoutbeg(); } # endif /* OVLB */ # ifdef OVL0 void tty_delay_output() { #ifdef TIMED_DELAY if (flags.nap) { (void) fflush(stdout); msleep(50); /* sleep for 50 milliseconds */ return; } #endif } # endif /* OVL0 */ # ifdef OVLB void tty_end_screen() { if (!iflags.grmode) { txt_clear_screen(); # ifdef PC9800 fputs("\033[>1l", stdout); # endif # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_tty_end_screen(); # endif } } void tty_nhbell() { txt_nhbell(); } void tty_number_pad(state) int state; { ++state; /* prevents compiler warning (unref. param) */ } void tty_startup(wid, hgt) int *wid, *hgt; { /* code to sense display adapter is required here - MJA */ attrib_text_normal = ATTRIB_NORMAL; attrib_text_intense = ATTRIB_INTENSE; /* These are defaults and may get overridden */ attrib_gr_normal = attrib_text_normal; attrib_gr_intense = attrib_text_intense; g_attribute = attrib_text_normal; /* Give it a starting value */ # ifdef SCREEN_VGA if (iflags.usevga) { vga_tty_startup(wid, hgt); } else # endif txt_startup(wid, hgt); *wid = CO; *hgt = LI; # ifdef CLIPPING if (CO < COLNO || LI < ROWNO+3) setclipped(); # endif # ifdef TEXTCOLOR init_ttycolor(); # endif # ifdef MONO_CHECK monoflag = txt_monoadapt_check(); # else monoflag = 0; # endif } void tty_start_screen() { # ifdef PC9800 fputs("\033[>1h", stdout); # endif if (iflags.num_pad) tty_number_pad(1); /* make keypad send digits */ } void gr_init(){ if (iflags.usevga) { # ifdef SCREEN_VGA vga_Init(); # endif # ifdef SCREEN_VESA } else if (iflags.usevesa) { vesa_Init(); # endif # ifdef SCREEN_8514 } else if (iflags.use8514) { v8514_Init(); # endif } } void gr_finish() { if (iflags.grmode) { if (iflags.usevga) { # ifdef SCREEN_VGA vga_Finish(); # endif # ifdef SCREEN_VESA } else if (iflags.usevesa) { vesa_Finish(); # endif # ifdef SCREEN_8514 } else if (iflags.use8514) { v8514_Finish(); # endif } } } # endif /* OVLB */ /* * Screen output routines (these are heavily used). * * These are the 3 routines used to place information on the screen * in the NO_TERMS PC tty port of NetHack. These are the routines * that get called by routines in other NetHack source files (such * as those in win/tty). * * xputs - Writes a c null terminated string at the current location. * Depending on compile options, this could just be a series * of repeated calls to xputc() for each character. * * xputc - Writes a single character at the current location. Since * various places in the code assume that control characters * can be used to control, we are forced to interpret some of * the more common ones, in order to keep things looking correct. * * xputg - If using a graphics mode display mechanism (such as VGA, this * routine is used to display a graphical representation of a * NetHack glyph at the current location. For more information on * NetHack glyphs refer to the comments in include/display.h. * * NOTES: * wintty.h uses macros to redefine common output functions * such as puts, putc, putchar, so that they get steered into * either xputs (for strings) or xputc (for single characters). * References to puts, putc, and putchar in other source files * (that include wintty.h) are actually using these routines. */ # ifdef OVL0 void xputs(s) const char *s; { int col,row; col = (int)ttyDisplay->curx; row = (int)ttyDisplay->cury; if (!iflags.grmode) { txt_xputs(s,col,row); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_xputs(s,col,row); # endif } } void xputc(ch) /* write out character (and attribute) */ char ch; { int i; char attribute; i = iflags.grmode ? attrib_gr_normal : attrib_text_normal; attribute = (char)((g_attribute == 0) ? i : g_attribute); if (!iflags.grmode) { txt_xputc(ch,attribute); # ifdef SCREEN_VGA } else if (iflags.usevga) { vga_xputc(ch,attribute); # endif /*SCREEN_VGA*/ } } void xputg(glyphnum,ch,special) /* write out a glyph picture at current location */ int glyphnum; int ch; unsigned special; { if (!iflags.grmode || !iflags.tile_view) { xputc((char)ch); # ifdef SCREEN_VGA } else { vga_xputg(glyphnum, ch, special); # endif } } # ifdef POSITIONBAR void video_update_positionbar(posbar) char *posbar; { if (!iflags.grmode) return; # ifdef SCREEN_VGA else vga_update_positionbar(posbar); # endif } # endif void adjust_cursor_flags(cw) struct WinDesc *cw; { # ifdef SIMULATE_CURSOR # if 0 if (cw->type == NHW_MAP) cursor_flag = 1; else cursor_flag = 0; # else if (cw->type == NHW_MAP) { inmap = 1; cursor_flag = 1; } else { inmap = 0; cursor_flag = 1; } # endif /* 0 */ # endif /* SIMULATE_CURSOR */ } # ifdef SIMULATE_CURSOR /* change the defaults in pcvideo.h, not here */ int cursor_type = CURSOR_DEFAULT_STYLE; int cursor_color = CURSOR_DEFAULT_COLOR; int cursor_flag; /* The check for iflags.grmode is made BEFORE calling these. */ void DrawCursor() { # ifdef SCREEN_VGA vga_DrawCursor(); # endif } void HideCursor() { # ifdef SCREEN_VGA vga_HideCursor(); # endif } # endif /* SIMULATE_CURSOR */ # endif /* OVL0 */ # ifdef TEXTCOLOR /* * CLR_BLACK 0 * CLR_RED 1 * CLR_GREEN 2 * CLR_BROWN 3 low-intensity yellow * CLR_BLUE 4 * CLR_MAGENTA 5 * CLR_CYAN 6 * CLR_GRAY 7 low-intensity white * NO_COLOR 8 * CLR_ORANGE 9 * CLR_BRIGHT_GREEN 10 * CLR_YELLOW 11 * CLR_BRIGHT_BLUE 12 * CLR_BRIGHT_MAGENTA 13 * CLR_BRIGHT_CYAN 14 * CLR_WHITE 15 * CLR_MAX 16 * BRIGHT 8 */ # ifdef VIDEOSHADES /* assign_videoshades() is prototyped in extern.h */ /* assign_videocolors() is prototyped in extern.h */ /* assign_video() is prototyped in extern.h */ # ifdef OVLB int shadeflag; /* shades are initialized */ int colorflag; /* colors are initialized */ char *schoice[3] = {"dark","normal","light"}; char *shade[3]; # else extern int shadeflag; extern int colorflag; extern char *schoice[3]; extern char *shade[3]; # endif /* OVLB */ # endif /* VIDEOSHADES */ # ifdef OVLB STATIC_OVL void init_ttycolor() { # ifdef VIDEOSHADES if (!shadeflag) { ttycolors[CLR_BLACK] = M_BLACK; /* 8 = dark gray */ ttycolors[CLR_WHITE] = M_WHITE; /* 15 = bright white */ ttycolors[CLR_GRAY] = M_GRAY; /* 7 = normal white */ shade[0] = schoice[0]; shade[1] = schoice[1]; shade[2] = schoice[2]; } # else ttycolors[CLR_BLACK] = M_GRAY; /* mapped to white */ ttycolors[CLR_WHITE] = M_GRAY; /* mapped to white */ ttycolors[CLR_GRAY] = M_GRAY; /* mapped to white */ # endif # ifdef VIDEOSHADES if (!colorflag) { # endif ttycolors[CLR_RED] = M_RED; ttycolors[CLR_GREEN] = M_GREEN; ttycolors[CLR_BROWN] = M_BROWN; ttycolors[CLR_BLUE] = M_BLUE; ttycolors[CLR_MAGENTA] = M_MAGENTA; ttycolors[CLR_CYAN] = M_CYAN; ttycolors[BRIGHT] = M_WHITE; ttycolors[CLR_ORANGE] = M_ORANGE; ttycolors[CLR_BRIGHT_GREEN] = M_BRIGHTGREEN; ttycolors[CLR_YELLOW] = M_YELLOW; ttycolors[CLR_BRIGHT_BLUE] = M_BRIGHTBLUE; ttycolors[CLR_BRIGHT_MAGENTA] = M_BRIGHTMAGENTA; ttycolors[CLR_BRIGHT_CYAN] = M_BRIGHTCYAN; # ifdef VIDEOSHADES } # endif } # endif /* OVLB */ # ifdef OVL1 static int FDECL(convert_uchars,(char *, uchar *, int)); # ifdef VIDEOSHADES int assign_videoshades(char *choiceptr) { char choices[120]; char *cptr, *cvalue[3]; int i,icolor = CLR_WHITE; strcpy(choices,choiceptr); cvalue[0] = choices; /* find the next ' ' or tab */ cptr = index(cvalue[0], '-'); if (!cptr) cptr = index(cvalue[0], ' '); if (!cptr) cptr = index(cvalue[0], '\t'); if (!cptr) return 0; *cptr = '\0'; /* skip whitespace between '=' and value */ do { ++cptr; } while (isspace(*cptr) || (*cptr == '-')); cvalue[1] = cptr; cptr = index(cvalue[1], '-'); if (!cptr) cptr = index(cvalue[0], ' '); if (!cptr) cptr = index(cvalue[0], '\t'); if (!cptr) return 0; *cptr = '\0'; do { ++cptr; } while (isspace(*cptr) || (*cptr == '-')); cvalue[2] = cptr; for (i=0; i < 3; ++i) { switch(i) { case 0: icolor = CLR_BLACK; break; case 1: icolor = CLR_GRAY; break; case 2: icolor = CLR_WHITE; break; } shadeflag = 1; if ((strncmpi(cvalue[i],"black",5) == 0) || (strncmpi(cvalue[i],"dark",4) == 0)) { shade[i] = schoice[0]; ttycolors[icolor] = M_BLACK; /* dark gray */ } else if ((strncmpi(cvalue[i],"gray",4) == 0) || (strncmpi(cvalue[i],"grey",4) == 0) || (strncmpi(cvalue[i],"medium",6) == 0) || (strncmpi(cvalue[i],"normal",6) == 0)) { shade[i] = schoice[1]; ttycolors[icolor] = M_GRAY; /* regular gray */ } else if ((strncmpi(cvalue[i],"white",5) == 0) || (strncmpi(cvalue[i],"light",5) == 0)) { shade[i] = schoice[2]; ttycolors[icolor] = M_WHITE; /* bright white */ } else { shadeflag = 0; return 0; } } return 1; } /* * Process defaults.nh OPTIONS=videocolors:xxx * Left to right assignments for: * red green brown blue magenta cyan orange br.green yellow * br.blue br.mag br.cyan * * Default Mapping (BIOS): 4-2-6-1-5-3-12-10-14-9-13-11 */ int assign_videocolors(char *colorvals) { int i,icolor; uchar *tmpcolor; init_ttycolor(); /* in case defaults.nh entry wasn't complete */ i = strlen(colorvals); tmpcolor = (uchar *)alloc(i); (void)convert_uchars(colorvals,tmpcolor,i); icolor = CLR_RED; for( i = 0; tmpcolor[i] != 0; ++i) { if (icolor < (CLR_WHITE)) { ttycolors[icolor++] = tmpcolor[i]; if ((icolor > CLR_CYAN) && (icolor < CLR_ORANGE)) { icolor = CLR_ORANGE; } } } colorflag = 1; free((genericptr_t)tmpcolor); return 1; } static int convert_uchars(bufp,list,size) char *bufp; /* current pointer */ uchar *list; /* return list */ int size; { unsigned int num = 0; int count = 0; while (1) { switch(*bufp) { case ' ': case '\0': case '\t': case '-': case '\n': if (num) { list[count++] = num; num = 0; } if ((count==size) || !*bufp) return count; bufp++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': num = num*10 + (*bufp-'0'); bufp++; break; return count; } } /*NOTREACHED*/ } # endif /* VIDEOSHADES */ # endif /* OVL1 */ # endif /* TEXTCOLOR */ /* * Process defaults.nh OPTIONS=video:xxxx * * where (current) legitimate values are: * * autodetect (attempt to determine the adapter type) * default (force use of the default video method for environment) * vga (use vga adapter code) */ # ifdef OVL1 int assign_video(sopt) char *sopt; { /* * debug * * printf("video is %s",sopt); * getch(); */ iflags.grmode = 0; iflags.hasvga = 0; iflags.usevga = 0; if (strncmpi(sopt,"def",3) == 0) { /* default */ /* do nothing - default */ # ifdef SCREEN_VGA } else if (strncmpi(sopt,"vga",3) == 0) { /* vga */ iflags.usevga = 1; iflags.hasvga = 1; # endif # ifdef SCREEN_VESA } else if (strncmpi(sopt,"vesa",4) == 0) { /* vesa */ iflags.hasvesa = 1; iflags.usevesa = 1; # endif # ifdef SCREEN_8514 } else if (strncmpi(sopt,"8514",4) == 0) { /* 8514/A */ iflags.use8514 = 1; iflags.has8514 = 1; # endif } else if (strncmpi(sopt,"auto",4) == 0) { /* autodetect */ # ifdef SCREEN_VESA if (vesa_detect()) { iflags.hasvesa = 1; } # endif # ifdef SCREEN_8514 if (v8514_detect()) { iflags.has8514 = 1; } # endif # ifdef SCREEN_VGA if (vga_detect()) { iflags.hasvga = 1; } # endif /* * Auto-detect Priorities (arbitrary for now): * VGA */ if (iflags.hasvga) { iflags.usevga = 1; /* VGA depends on BIOS to enable function keys*/ iflags.BIOS = 1; iflags.rawio = 1; } } else { return 0; } return 1; } # endif /* OVL1 */ # ifdef OVL0 void tileview(enable) boolean enable; { #ifdef SCREEN_VGA if (iflags.grmode) vga_traditional(enable ? FALSE : TRUE); #endif } # endif /* OVL0 */ #endif /* NO_TERMS */ #else /* STUBVIDEO */ void tileview(enable) boolean enable; { } #endif /* STUBVIDEO */ nethack-3.4.3/sys/msdos/vidtxt.c0100644000000000000000000002734107764735041015312 0ustar rootroot/* SCCS Id: @(#)vidtxt.c 3.4 1994/04/04 */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * vidtxt.c - Textmode video hardware support (BIOS and DJGPPFAST) * *Edit History: * Initial Creation M. Allison 93/04/04 * Add djgpp support K. Smolkowski 93/04/26 * Add runtime monoadapter check M. Allison 93/05/09 */ #define VIDEO_TEXT #include "hack.h" #include "pcvideo.h" #include "wintty.h" #include #include #if defined(_MSC_VER) # if _MSC_VER >= 700 #pragma warning(disable:4018) /* signed/unsigned mismatch */ #pragma warning(disable:4127) /* conditional expression is constant */ #pragma warning(disable:4131) /* old style declarator */ #pragma warning(disable:4305) /* prevents complaints with MK_FP */ #pragma warning(disable:4309) /* initializing */ #pragma warning(disable:4759) /* prevents complaints with MK_FP */ # endif #endif /* void FDECL(txt_xputc,(char, int)); */ /* write out character (and attribute) */ extern int attrib_text_normal; /* text mode normal attribute */ extern int attrib_gr_normal; /* graphics mode normal attribute */ extern int attrib_text_intense; /* text mode intense attribute */ extern int attrib_gr_intense; /* graphics mode intense attribute */ #ifdef OVLB void txt_get_scr_size() { union REGS regs; if (!iflags.BIOS) { CO = 80; LI = 24; return; } # ifdef PC9800 regs.h.ah = SENSEMODE; (void) int86(CRT_BIOS, ®s, ®s); CO = (regs.h.al & 0x02) ? 40 : 80; LI = (regs.h.al & 0x01) ? 20 : 25; # else regs.x.ax = FONTINFO; regs.x.bx = 0; /* current ROM BIOS font */ regs.h.dl = 24; /* default row count */ /* in case no EGA/MCGA/VGA */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Font Information */ /* MDA/CGA/PCjr ignore INT 10h, Function 11h, but since we * cleverly loaded up DL with the default, everything's fine. * * Otherwise, DL now contains rows - 1. Also, CX contains the * points (bytes per character) and ES:BP points to the font * table. -3. */ regs.h.ah = GETMODE; (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Video Mode */ /* This goes back all the way to the original PC. Completely * safe. AH contains # of columns, AL contains display mode, * and BH contains the active display page. */ LI = regs.h.dl + 1; CO = regs.h.ah; # endif /* PC9800 */ } #endif /*OVLB*/ /* * -------------------------------------------------------------- * The rest of this file is only compiled if NO_TERMS is defined. * -------------------------------------------------------------- */ #ifdef NO_TERMS /* #include "wintty.h" */ # ifdef SCREEN_DJGPPFAST #include #include # endif void FDECL(txt_gotoxy, (int,int)); # if defined(SCREEN_BIOS) && !defined(PC9800) void FDECL(txt_get_cursor, (int *, int *)); # endif # ifdef SCREEN_DJGPPFAST #define txt_get_cursor(x,y) ScreenGetCursor(y,x) # endif extern int g_attribute; /* Current attribute to use */ extern int monoflag; /* 0 = not monochrome, else monochrome */ # ifdef OVLB void txt_backsp() { # ifdef PC9800 union REGS regs; regs.h.dl = 0x01; /* one column */ regs.h.ah = CURSOR_LEFT; regs.h.cl = DIRECT_CON_IO; int86(DOS_EXT_FUNC, ®s, ®s); # else int col,row; txt_get_cursor(&col, &row); if (col > 0) col = col-1; txt_gotoxy(col,row); # endif } void txt_nhbell() { union REGS regs; if (flags.silent) return; regs.h.dl = 0x07; /* bell */ regs.h.ah = 0x02; /* Character Output function */ (void) int86(DOSCALL, ®s, ®s); } # endif /* OVLB */ # ifdef OVL0 void txt_clear_screen() /* djgpp provides ScreenClear(), but in version 1.09 it is broken * so for now we just use the BIOS Routines */ { union REGS regs; # ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x02; /* clear whole screen */ regs.h.ah = SCREEN_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); # else regs.h.dl = (char)(CO - 1); /* columns */ regs.h.dh = (char)(LI - 1); /* rows */ regs.x.cx = 0; /* CL,CH = x,y of upper left */ regs.x.ax = 0; regs.x.bx = 0; regs.h.bh = (char)attrib_text_normal; regs.h.ah = (char)SCROLL; /* DL,DH = x,y of lower rt */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Scroll or init window */ txt_gotoxy(0,0); # endif } void txt_cl_end(col,row) /* clear to end of line */ int col,row; { union REGS regs; # ifndef PC9800 int count; # endif # ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x00; /* clear to end of line */ regs.h.ah = LINE_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); # else count = CO - col; txt_gotoxy(col,row); regs.h.ah = PUTCHARATT; /* write attribute & character */ regs.h.al = ' '; /* character */ regs.h.bh = 0; /* display page */ /* BL = attribute */ regs.h.bl = (char)attrib_text_normal; regs.x.cx = count; if (count != 0) (void) int86(VIDEO_BIOS, ®s, ®s); /* write attribute & character */ # endif } void txt_cl_eos() /* clear to end of screen */ { union REGS regs; # ifndef PC9800 int col,row; # endif # ifdef PC9800 regs.h.dl = attr98[attrib_text_normal]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); regs.h.dl = 0x00; /* clear to end of screen */ regs.h.ah = SCREEN_CLEAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); # else txt_get_cursor(&col, &row); txt_cl_end(col,row); /* clear to end of line */ txt_gotoxy(0,(row < (LI-1) ? row+1 : (LI-1))); regs.h.dl = (char) (CO-1); /* X of lower right */ regs.h.dh = (char) (LI-1); /* Y of lower right */ regs.h.cl = 0; /* X of upper left */ /* Y (row) of upper left */ regs.h.ch = (char) (row < (LI-1) ? row+1 :(LI-1)); regs.x.cx = 0; regs.x.ax = 0; regs.x.bx = 0; regs.h.bh = (char)attrib_text_normal; regs.h.ah = SCROLL; (void) int86(VIDEO_BIOS, ®s, ®s); /* Scroll or initialize window */ # endif } # endif /* OVL0 */ # ifdef OVLB void txt_startup(wid, hgt) int *wid, *hgt; { txt_get_scr_size(); *wid = CO; *hgt = LI; attrib_gr_normal = attrib_text_normal; attrib_gr_intense = attrib_text_intense; g_attribute = attrib_text_normal; /* Give it a starting value */ } # endif /* OVLB */ /* * Screen output routines (these are heavily used). * * These are the 3 routines used to place information on the screen * in the NO_TERMS PC tty port of NetHack. These are the routines * that get called by routines in other NetHack source files (such * as those in win/tty). * * txt_xputs - Writes a c null terminated string at the current location. * Depending on compile options, this could just be a series * of repeated calls to xputc() for each character. * txt_xputc - Writes a single character at the current location. Since * various places in the code assume that control characters * can be used to control, we are forced to interpret some of * the more common ones, in order to keep things looking correct. * * NOTES: * wintty.h uses macros to redefine common output functions * such as puts, putc, putchar, so that they get steered into * either xputs (for strings) or xputc (for single characters). * References to puts, putc, and putchar in other source files * (that include wintty.h) are actually using these routines. */ # ifdef OVL0 void txt_xputs(s,col,row) const char *s; int col,row; { char c; if (s != (char *)0) { while (*s != '\0') { txt_gotoxy(col,row); c = *s++; txt_xputc(c,g_attribute); if (col < (CO-1)) col++; txt_gotoxy(col,row); } } } void txt_xputc(ch,attr) /* write out character (and attribute) */ char ch; int attr; { # ifdef PC9800 union REGS regs; regs.h.dl = attr98[attr]; regs.h.ah = SETATT; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); if (ch == '\n') { regs.h.dl = '\r'; regs.h.ah = PUTCHAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); } regs.h.dl = ch; regs.h.ah = PUTCHAR; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); # else # ifdef SCREEN_BIOS union REGS regs; # endif int col,row; txt_get_cursor(&col,&row); switch(ch) { case '\n': #if 0 col = 0; ++row; #endif break; default: # ifdef SCREEN_DJGPPFAST ScreenPutChar((int)ch,attr,col,row); # endif # ifdef SCREEN_BIOS regs.h.ah = PUTCHARATT; /* write att & character */ regs.h.al = ch; /* character */ regs.h.bh = 0; /* display page */ regs.h.bl = (char)attr; /* BL = attribute */ regs.x.cx = 1; /* one character */ (void) int86(VIDEO_BIOS, ®s, ®s); # endif if (col < (CO -1 )) ++col; break; } /* end switch */ txt_gotoxy(col,row); # endif /* PC9800 */ } # endif /* OVL0 */ /* * This marks the end of the general screen output routines that are * called from other places in NetHack. * --------------------------------------------------------------------- */ /* * Cursor location manipulation, and location information fetching * routines. * These include: * * txt_get_cursor(x,y) - Returns the current location of the cursor. In * some implementations this is implemented as a * function (BIOS), and in others it is a macro * (DJGPPFAST). * * txt_gotoxy(x,y) - Moves the cursor on screen to the specified x and * y location. This routine moves the location where * screen writes will occur next, it does not change * the location of the player on the NetHack level. */ # ifdef OVL0 # if defined(SCREEN_BIOS) && !defined(PC9800) /* * This is implemented as a macro under DJGPPFAST. */ void txt_get_cursor(x,y) /* get cursor position */ int *x, *y; { union REGS regs; regs.x.dx = 0; regs.h.ah = GETCURPOS; /* get cursor position */ regs.x.cx = 0; regs.x.bx = 0; (void) int86(VIDEO_BIOS, ®s, ®s); /* Get Cursor Position */ *x = regs.h.dl; *y = regs.h.dh; } # endif /* SCREEN_BIOS && !PC9800 */ void txt_gotoxy(x,y) int x,y; { # ifdef SCREEN_BIOS union REGS regs; # ifdef PC9800 regs.h.dh = (char)y; /* row */ regs.h.dl = (char)x; /* column */ regs.h.ah = SETCURPOS; regs.h.cl = DIRECT_CON_IO; (void) int86(DOS_EXT_FUNC, ®s, ®s); /* Set Cursor Position */ # else regs.h.ah = SETCURPOS; regs.h.bh = 0; /* display page */ regs.h.dh = (char)y; /* row */ regs.h.dl = (char)x; /* column */ (void) int86(VIDEO_BIOS, ®s, ®s); /* Set Cursor Position */ # endif # endif # if defined(SCREEN_DJGPPFAST) ScreenSetCursor(y,x); # endif /* The above, too, goes back all the way to the original PC. If * we ever get so fancy as to swap display pages (i doubt it), * then we'll need to set BH appropriately. This function * returns nothing. -3. */ } # endif /* OVL0 */ /* * This marks the end of the cursor manipulation/information routines. * ------------------------------------------------------------------- */ # ifdef OVLB # ifdef MONO_CHECK int txt_monoadapt_check() { union REGS regs; regs.h.al = 0; regs.h.ah = GETMODE; /* get video mode */ (void) int86(VIDEO_BIOS, ®s, ®s); return (regs.h.al == 7) ? 1 : 0; /* 7 means monochrome mode */ } # endif /* MONO_CHECK */ # endif /* OVLB */ #endif /* NO_TERMS */ /* vidtxt.c */ nethack-3.4.3/sys/msdos/vidvga.c0100644000000000000000000011105207764735041015241 0ustar rootroot/* SCCS Id: @(#)vidvga.c 3.4 1996/02/16 */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * vidvga.c - VGA Hardware video support */ #include "hack.h" #ifdef SCREEN_VGA /* this file is for SCREEN_VGA only */ #include "pcvideo.h" #include "tile.h" #include "pctiles.h" #include #include #include "wintty.h" # ifdef __GO32__ #include #include # endif /*========================================================================= * VGA Video supporting routines (for tiles). * * The following routines carry out the lower level video functions required * to make PC NetHack work with VGA graphics. * * - The binary files NetHack1.tib and NetHacko.tib must be in your * game directory. Currently, unpredictable results may occur if they * aren't since the code hasn't been tested with it missing (yet). * * Notes (96/02/16): * * - Cursor emulation on the map is now implemented. The input routine * in msdos.c calls the routine to display the cursor just before * waiting for input, and hides the cursor immediately after satisfying * the input request. * * - A check for a VGA adapter is implemented. * * - With 640 x 480 resolution, the use of 16 x 16 icons allows only 40 * columns for the map display. This makes it necessary to support the * TTY CLIPPING code. The right/left scrolling with this can be * a little annoying. Feel free to rework the routines. * * - NetHack1.tib is built from text files derived from bitmap files * provided by Warwick Allison, using routines developed and supplied * by Janet Walz. The icons are very well done and thanks to * Warwick Allison for an excellent effort! * * - The text fonts that this is using while in graphics mode come from * the Video BIOS ROM on board the VGA adapter. Code in vga_WriteChar * copies the appropriate pixels from the video ROM to the Video buffer. * * - Currently, most of the routines are in an ifdef OVLB. * If you change that, you may have to muck with some of the * variable declarations which now assume this. This is not a * problem in a non-overlaid environment (djgpp for example). * * - VGA 640 by 480, 16 colour mode (0x12) uses an odd method to * represent a colour value from the palette. There are four * planes of video memory, all overlaid at the same memory location. * For example, if a pixel has the colour value 7: * * 0 1 1 1 * \ \ \ \ * \ \ \ plane 0 * \ \ plane 1 * \ plane 2 * plane 3 * * - VGA write mode 2 requires that a read be done before a write to * set some latches on the card. The value read had to be placed * into a variable declared 'volatile' to prevent djgpp from * optimizing away the entire instruction (the value was assigned * to a variable which was never used). This corrects the striping * problem that was apparent with djgpp. * * - A check for valid mode switches has been added. * * - No tiles are displayed on the Rogue Level in keeping with the * original Rogue. The display adapter remains in graphics mode * however. * * - Added handling for missing NetHackX.tib files, and resort to using * video:default and tty if one of them can't be located. * * ToDo (96/02/17): * * - Nothing prior to release. *========================================================================= */ # if defined(_MSC_VER) # if _MSC_VER >= 700 #pragma warning(disable:4018) /* signed/unsigned mismatch */ #pragma warning(disable:4127) /* conditional expression is constant */ #pragma warning(disable:4131) /* old style declarator */ #pragma warning(disable:4305) /* prevents complaints with MK_FP */ #pragma warning(disable:4309) /* initializing */ # if _MSC_VER > 700 #pragma warning(disable:4759) /* prevents complaints with MK_FP */ # endif # endif # include # endif /* STATIC_DCL void FDECL(vga_NoBorder, (int)); */ void FDECL(vga_gotoloc, (int,int)); /* This should be made a macro */ void NDECL(vga_backsp); #ifdef SCROLLMAP STATIC_DCL void FDECL(vga_scrollmap,(BOOLEAN_P)); #endif STATIC_DCL void FDECL(vga_redrawmap,(BOOLEAN_P)); void FDECL(vga_cliparound,(int, int)); STATIC_OVL void FDECL(decal_planar,(struct planar_cell_struct *, unsigned)); #ifdef POSITIONBAR STATIC_DCL void NDECL(positionbar); static void FDECL(vga_special,(int, int, int)); #endif extern int clipx, clipxmax; /* current clipping column from wintty.c */ extern boolean clipping; /* clipping on? from wintty.c */ extern int savevmode; /* store the original video mode */ extern int curcol,currow; /* current column and row */ extern int g_attribute; extern int attrib_text_normal; /* text mode normal attribute */ extern int attrib_gr_normal; /* graphics mode normal attribute */ extern int attrib_text_intense; /* text mode intense attribute */ extern int attrib_gr_intense; /* graphics mode intense attribute */ extern boolean inmap; /* in the map window */ /* * Global Variables */ STATIC_VAR unsigned char __far *font; STATIC_VAR char *screentable[SCREENHEIGHT]; STATIC_VAR char *paletteptr; STATIC_VAR struct map_struct { int glyph; int ch; int attr; unsigned special; } map[ROWNO][COLNO]; /* track the glyphs */ # define vga_clearmap() { int x,y; for (y=0; y < ROWNO; ++y) \ for (x=0; x < COLNO; ++x) { map[y][x].glyph = cmap_to_glyph(S_stone); \ map[y][x].ch = S_stone; map[y][x].attr = 0; map[y][x].special = 0;} } # define TOP_MAP_ROW 1 # if defined(OVLB) STATIC_VAR int vgacmap[CLR_MAX] = {0,3,5,9,4,8,12,14,11,2,6,7,1,8,12,13}; STATIC_VAR int viewport_size = 40; /* STATIC_VAR char masktable[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; */ /* STATIC_VAR char bittable[8]= {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; */ #if 0 STATIC_VAR char defpalette[] = { /* Default VGA palette */ 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0xcc, 0xcc, 0xcc, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff }; #endif # ifndef ALTERNATE_VIDEO_METHOD int vp[SCREENPLANES] = {8,4,2,1}; # endif int vp2[SCREENPLANES] = {1,2,4,8}; # else extern int vgacmap[CLR_MAX]; extern int viewport_size; extern char masktable[8]; extern char bittable[8]; extern char defpalette[]; # ifndef ALTERNATE_VIDEO_METHOD extern int vp[SCREENPLANES]; # endif extern int vp2[SCREENPLANES]; # endif /* OVLB */ STATIC_VAR struct planar_cell_struct *planecell; STATIC_VAR struct overview_planar_cell_struct *planecell_O; # if defined(USE_TILES) STATIC_VAR struct tibhdr_struct tibheader; /* extern FILE *tilefile; */ /* Not needed in here most likely */ # endif /* STATIC_VAR int g_attribute; */ /* Current attribute to use */ #ifdef OVLB void vga_get_scr_size() { CO = 80; LI = 29; } #endif /*OVLB*/ # ifdef OVLB void vga_backsp() { int col,row; col = curcol; /* Character cell row and column */ row = currow; if (col > 0) col = col-1; vga_gotoloc(col,row); } # endif /* OVLB */ # ifdef OVL0 void vga_clear_screen(colour) int colour; { char __far *pch; int y,j; char volatile a; outportb(0x3ce,5); outportb(0x3cf,2); for (y=0; y < SCREENHEIGHT; ++y) { pch = screentable[y]; for (j=0; j < SCREENBYTES; ++j) { outportb(0x3ce,8); outportb(0x3cf,255); a = READ_ABSOLUTE(pch); /* Must read , then write */ WRITE_ABSOLUTE(pch, (char)colour); ++pch; } } outportb(0x3ce,5); outportb(0x3cf,0); if (iflags.tile_view) vga_clearmap(); vga_gotoloc(0,0); /* is this needed? */ } void vga_cl_end(col,row) /* clear to end of line */ int col,row; { int count; /* * This is being done via character writes. * This should perhaps be optimized for speed by using VGA write * mode 2 methods as did clear_screen() */ for (count = col; count < (CO-1); ++count) { vga_WriteChar(' ',count,row,BACKGROUND_VGA_COLOR); } } void vga_cl_eos(cy) /* clear to end of screen */ int cy; { int count; cl_end(); while(cy <= LI-2) { for (count = 0; count < (CO-1); ++count) { vga_WriteChar(' ',count,cy, BACKGROUND_VGA_COLOR); } cy++; } } # endif /* OVL0 */ # ifdef OVLB void vga_tty_end_screen() { vga_clear_screen(BACKGROUND_VGA_COLOR); vga_SwitchMode(MODETEXT); } void vga_tty_startup(wid, hgt) int *wid, *hgt; { /* code to sense display adapter is required here - MJA */ vga_get_scr_size(); if (CO && LI) { *wid = CO; *hgt = LI; } attrib_gr_normal = ATTRIB_VGA_NORMAL; attrib_gr_intense = ATTRIB_VGA_INTENSE; g_attribute = attrib_gr_normal; /* Give it a starting value */ } # endif /* OVLB */ /* * Screen output routines (these are heavily used). * * These are the 3 routines used to place information on the screen * in the VGA PC tty port of NetHack. These are the routines * that get called by the general interface routines in video.c. * * vga_xputs -Writes a c null terminated string at the current location. * * vga_xputc -Writes a single character at the current location. Since * various places in the code assume that control characters * can be used to control, we are forced to interpret some of * the more common ones, in order to keep things looking correct. * * vga_xputg -This routine is used to display a graphical representation of a * NetHack glyph (a tile) at the current location. For more * information on NetHack glyphs refer to the comments in * include/display.h. * */ # ifdef OVL0 void vga_xputs(s,col,row) const char *s; int col,row; { if (s != (char *)0) { vga_WriteStr((char *)s,strlen(s),col,row,g_attribute); } } void vga_xputc(ch,attr) /* write out character (and attribute) */ char ch; int attr; { int col,row; col = curcol; row = currow; switch(ch) { case '\n': col = 0; ++row; break; default: vga_WriteChar((unsigned char)ch,col,row,attr); if (col < (CO -1 )) ++col; break; } /* end switch */ vga_gotoloc(col,row); } # if defined(USE_TILES) void vga_xputg(glyphnum,ch, special) /* Place tile represent. a glyph at current location */ int glyphnum; int ch; unsigned special; /* special feature: corpse, invis, detected, pet, ridden - hack.h */ { int col,row; int attr; int ry; row = currow; col = curcol; if ((col < 0 || col >= COLNO) || (row < TOP_MAP_ROW || row >= (ROWNO + TOP_MAP_ROW))) return; ry = row - TOP_MAP_ROW; map[ry][col].glyph = glyphnum; map[ry][col].ch = ch; map[ry][col].special = special; attr = (g_attribute == 0) ? attrib_gr_normal : g_attribute; map[ry][col].attr = attr; if (iflags.traditional_view) { vga_WriteChar((unsigned char)ch,col,row,attr); } else if (!iflags.over_view) { if ((col >= clipx) && (col <= clipxmax)) { if (!ReadPlanarTileFile(glyph2tile[glyphnum], &planecell)) { if (map[ry][col].special) decal_planar(planecell, special); vga_DisplayCell(planecell, col - clipx, row); } else pline("vga_xputg: Error reading tile (%d,%d) from file", glyphnum,glyph2tile[glyphnum]); } } else { if (!ReadPlanarTileFile_O(glyph2tile[glyphnum], &planecell_O)) vga_DisplayCell_O(planecell_O, col, row); else pline("vga_xputg: Error reading tile (%d,%d) from file", glyphnum,glyph2tile[glyphnum]); } if (col < (CO - 1 )) ++col; vga_gotoloc(col,row); } # endif /* USE_TILES */ /* * Cursor location manipulation, and location information fetching * routines. * These include: * * vga_gotoloc(x,y) - Moves the "cursor" on screen to the specified x * and y character cell location. This routine * determines the location where screen writes * will occur next, it does not change the location * of the player on the NetHack level. */ void vga_gotoloc(col,row) int col,row; { curcol = min(col,CO - 1); /* protection from callers */ currow = min(row,LI - 1); } # if defined(USE_TILES) && defined(CLIPPING) void vga_cliparound(x, y) int x, y; { extern boolean restoring; int oldx = clipx; if (!iflags.tile_view || iflags.over_view || iflags.traditional_view) return; if (x < clipx + 5) { clipx = max(0, x - (viewport_size / 2)); clipxmax = clipx + (viewport_size - 1); } else if (x > clipxmax - 5) { clipxmax = min(COLNO - 1, x + (viewport_size / 2)); clipx = clipxmax - (viewport_size - 1); } if (clipx != oldx) { if (on_level(&u.uz0, &u.uz) && !restoring) /* (void) doredraw(); */ vga_redrawmap(1); } } STATIC_OVL void vga_redrawmap(clearfirst) boolean clearfirst; { int j,x,y,t; char __far *pch; char volatile a; if (clearfirst) { /* y here is in pixel rows */ outportb(0x3ce,5); outportb(0x3cf,2); t = TOP_MAP_ROW * ROWS_PER_CELL; for (y = t; y < (ROWNO * ROWS_PER_CELL) + t; ++y) { pch = screentable[y]; for (j=0; j < SCREENBYTES; ++j) { outportb(0x3ce,8); outportb(0x3cf,255); /* On VGA mode2, must read first, then write */ a = READ_ABSOLUTE(pch); WRITE_ABSOLUTE(pch, (char)BACKGROUND_VGA_COLOR); ++pch; } } outportb(0x3ce,5); outportb(0x3cf,0); } /* y here is in screen rows*/ # ifdef ROW_BY_ROW for (y = 0; y < ROWNO; ++y) for (x = clipx; x <= clipxmax; ++x) { # else for (x = clipx; x <= clipxmax; ++x) for (y = 0; y < ROWNO; ++y) { # endif if (iflags.traditional_view) { if (!(clearfirst && map[y][x].ch == S_stone)) vga_WriteChar( (unsigned char)map[y][x].ch, x,y + TOP_MAP_ROW,map[y][x].attr); } else { t = map[y][x].glyph; if (!(clearfirst && t == cmap_to_glyph(S_stone))) { if (!iflags.over_view) { if (!ReadPlanarTileFile(glyph2tile[t], &planecell)) { if (map[y][x].special) decal_planar(planecell, map[y][x].special); vga_DisplayCell(planecell, x - clipx, y + TOP_MAP_ROW); } else pline("vga_redrawmap: Error reading tile (%d,%d)", t,glyph2tile[t]); } else { if (!ReadPlanarTileFile_O(glyph2tile[t], &planecell_O)) { vga_DisplayCell_O(planecell_O, x, y + TOP_MAP_ROW); } else pline("vga_redrawmap: Error reading tile (%d,%d)", t,glyph2tile[t]); } } } } } # endif /* USE_TILES && CLIPPING */ # endif /* OVL0 */ # ifdef OVL2 void vga_userpan(left) boolean left; { int x; /* pline("Into userpan"); */ if (iflags.over_view || iflags.traditional_view) return; if (left) x = min(COLNO - 1, clipxmax + 10); else x = max(0, clipx - 10); vga_cliparound(x, 10); /* y value is irrelevant on VGA clipping */ positionbar(); vga_DrawCursor(); } void vga_overview(on) boolean on; { /* vga_HideCursor(); */ if (on) { iflags.over_view = TRUE; clipx = 0; clipxmax = CO - 1; } else { iflags.over_view = FALSE; clipx = max(0, (curcol - viewport_size / 2)); if (clipx > ((CO - 1) - viewport_size)) clipx = (CO - 1) - viewport_size; clipxmax = clipx + (viewport_size - 1); } } void vga_traditional(on) boolean on; { /* vga_HideCursor(); */ if (on) { /* switch_graphics(ASCII_GRAPHICS); */ iflags.traditional_view = TRUE; clipx = 0; clipxmax = CO - 1; } else { iflags.traditional_view = FALSE; if (!iflags.over_view) { clipx = max(0, (curcol - viewport_size / 2)); if (clipx > ((CO - 1) - viewport_size)) clipx = (CO - 1) - viewport_size; clipxmax = clipx + (viewport_size - 1); } } } void vga_refresh() { positionbar(); vga_redrawmap(1); vga_DrawCursor(); } # ifdef SCROLLMAP STATIC_OVL void vga_scrollmap(left) boolean left; { int j,x,y,t; int i,pixx,pixy,x1,y1,x2,y2; int byteoffset, vplane; char __far *tmp1; char __far *tmp2; unsigned char source[SCREENPLANES][80]; unsigned char first,second; pixy = row2y(TOP_MAP_ROW); /* convert to pixels */ pixx = col2x(x1); if (left) { x1 = 20; x2 = 0; } else { x1 = 0; x2 = 20; } /* read each row, all columns but the one to be replaced */ for(i = 0;i < (ROWNO-1) * ROWS_PER_CELL; ++i) { tmp1 = screentable[i + pixy]; tmp1 += x1; for(vplane=0; vplane < SCREENPLANES; ++vplane) { egareadplane(vplane); for (byteoffset = 0; byteoffset < 20; ++byteoffset) { tmp2 = tmp1 + byteoffset; source[vplane][byteoffset] = READ_ABSOLUTE(tmp2); } } tmp1 = screentable[i + pixy]; tmp1 += x2; for(vplane=0; vplane < SCREENPLANES; ++vplane) { egawriteplane(vp2[vplane]); for (byteoffset = 0; byteoffset < 20; ++byteoffset) { tmp2 = tmp1 + byteoffset; WRITE_ABSOLUTE(tmp2,source[vplane][byteoffset]); } } egawriteplane(15); } if (left) { i = clipxmax - 1; j = clipxmax; } else { i = clipx; j = clipx + 1; } for (y = 0; y < ROWNO; ++y) { for (x = i; x < j; x += 2) { t = map[y][x].glyph; if (!ReadPlanarTileFile(glyph2tile[t], &planecell)) if (map[y][x].special) decal_planar(planecell, map[y][x].special); vga_DisplayCell(planecell, x - clipx, y + TOP_MAP_ROW); else pline("vga_shiftmap: Error reading tile (%d,%d)", t, glyph2tile[t]); } } } # endif /* SCROLLMAP */ # endif /* OVL2 */ # ifdef OVLB STATIC_OVL void decal_planar(gp, special) struct planar_cell_struct *gp; unsigned special; { if (special & MG_CORPSE) { } else if (special & MG_INVIS) { } else if (special & MG_DETECT) { } else if (special & MG_PET) { } else if (special & MG_RIDDEN) { } } /* * Open tile files, * initialize the SCREEN, switch it to graphics mode, * initialize the pointers to the fonts, clear * the screen. * */ void vga_Init(void) { int i; # ifdef USE_TILES int tilefailure = 0; /* * Attempt to open the required tile files. If we can't * don't perform the video mode switch, use TTY code instead. * */ if (OpenTileFile(NETHACK_PLANAR_TILEFILE, FALSE)) tilefailure |= 1; if (OpenTileFile(NETHACK_OVERVIEW_TILEFILE, TRUE)) tilefailure |= 2; if (ReadTileFileHeader(&tibheader, FALSE)) tilefailure |= 4; if (tilefailure) { raw_printf("Reverting to TTY mode, tile initialization failure (%d).", tilefailure); wait_synch(); iflags.usevga = 0; iflags.tile_view = FALSE; iflags.over_view = FALSE; CO = 80; LI = 25; /* clear_screen() */ /* not vga_clear_screen() */ return; } # endif if (iflags.usevga) { for (i=0; i < SCREENHEIGHT; ++i) { screentable[i]=MK_PTR(VIDEOSEG, (i * SCREENBYTES)); } } vga_SwitchMode(MODE640x480); windowprocs.win_cliparound = vga_cliparound; /* vga_NoBorder(BACKGROUND_VGA_COLOR); */ /* Not needed after palette mod */ # ifdef USE_TILES paletteptr = tibheader.palette; iflags.tile_view = TRUE; iflags.over_view = FALSE; # else paletteptr = defpalette; # endif vga_SetPalette(paletteptr); g_attribute = attrib_gr_normal; font = vga_FontPtrs(); clear_screen(); clipx = 0; clipxmax = clipx + (viewport_size - 1); } /* * Switches modes of the video card. * * If mode == MODETEXT (0x03), then the card is placed into text * mode. If mode == 640x480, then the card is placed into vga * mode (video mode 0x12). No other modes are currently supported. * */ void vga_SwitchMode(unsigned int mode) { union REGS regs; if ((mode == MODE640x480) || (mode == MODETEXT)) { if (iflags.usevga && (mode == MODE640x480)) { iflags.grmode = 1; } else { iflags.grmode = 0; } regs.x.ax = mode; (void) int86(VIDEO_BIOS, ®s, ®s); } else { iflags.grmode = 0; /* force text mode for error msg */ regs.x.ax = MODETEXT; (void) int86(VIDEO_BIOS, ®s, ®s); g_attribute = attrib_text_normal; impossible("vga_SwitchMode: Bad video mode requested 0x%X", mode); } } /* * This allows grouping of several tasks to be done when * switching back to text mode. This is a public (extern) function. * */ void vga_Finish(void) { CloseTileFile(0); CloseTileFile(1); vga_SwitchMode(MODETEXT); windowprocs.win_cliparound = tty_cliparound; g_attribute = attrib_text_normal; iflags.tile_view = FALSE; } #if 0 /* * Turn off any border colour that might be enabled in the VGA card * register. * * I disabled this after modifying tile2bin.c to remap black & white * to a more standard values - MJA 94/04/23. * */ STATIC_OVL void vga_NoBorder(int bc) { union REGS regs; regs.h.ah = (char)0x10; regs.h.al = (char)0x01; regs.h.bh = (char)bc; regs.h.bl = 0; (void) int86(VIDEO_BIOS, ®s, ®s); } #endif /* * * Returns a far pointer (or flat 32 bit pointer under djgpp) to the * location of the appropriate ROM font for the _current_ video mode * (so you must place the card into the desired video mode before * calling this function). * * This function takes advantage of the video BIOS loading the * address of the appropriate character definition table for * the current graphics mode into interrupt vector 0x43 (0000:010C). */ char __far *vga_FontPtrs(void) { USHORT __far *tmp; char __far *retval; USHORT fseg, foff; tmp = (USHORT __far *)MK_PTR(((USHORT)FONT_PTR_SEGMENT), ((USHORT)FONT_PTR_OFFSET)); foff = READ_ABSOLUTE_WORD(tmp); ++tmp; fseg = READ_ABSOLUTE_WORD(tmp); retval = (char __far *)MK_PTR(fseg,foff); return retval; } /* * This will verify the existance of a VGA adapter on the machine. * Video function call 0x1a returns 0x1a in AL if successful, and * returns the following values in BL for the active display: * * 0=no display, 1=MDA, 2=CGA, 4=EGA(color-monitor), * 5=EGA(mono-monitor), 6=PGA, 7=VGA(mono-monitor), 8=VGA(color-monitor), * 0xB=MCGA(mono-monitor), 0xC=MCGA(color-monitor), 0xFF=unknown) */ int vga_detect() { union REGS regs; regs.h.al = 0; regs.h.ah = 0x1a; (void) int86(VIDEO_BIOS, ®s, ®s); /* * debug * * printf("vga_detect returned al=%02x, bh=%02x, bl=%02x\n", * (int)regs.h.al, (int)regs.h.bh, (int)regs.h.bl); * getch(); */ if ((int)regs.h.al == 0x1a) { if (((int)regs.h.bl == 8) || ((int)regs.h.bl == 7)) { return 1; } } return 0; } /* * Write character 'ch', at (x,y) and * do it using the colour 'colour'. * */ void vga_WriteChar(chr,col,row,colour) int chr,col,row,colour; { int i; int x,pixy; char volatile tc; char __far *cp; unsigned char __far *fp = font; unsigned char fnt; int actual_colour = vgacmap[colour]; x = min(col,(CO-1)); /* min() used protection from callers */ pixy = min(row,(LI-1)) * 16; /* assumes 8 x 16 char set */ /* if (chr < ' ') chr = ' '; */ /* assumes ASCII set */ outportb(0x3ce,5); outportb(0x3cf,2); chr = chr<<4; for (i=0; i < MAX_ROWS_PER_CELL; ++i) { cp = screentable[pixy+i] + x; fnt = READ_ABSOLUTE((fp + chr + i)); outportb(0x3ce,8); outportb(0x3cf,fnt); tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */ WRITE_ABSOLUTE(cp, (char)actual_colour); outportb(0x3ce,8); outportb(0x3cf,~fnt); tc = READ_ABSOLUTE(cp); /* wrt mode 2, must read, then write */ WRITE_ABSOLUTE(cp, (char)BACKGROUND_VGA_COLOR); } outportb(0x3ce,5); outportb(0x3cf,0); outportb(0x3ce,8); outportb(0x3cf,255); } /* * This is the routine that displays a high-res "cell" pointed to by 'gp' * at the desired location (col,row). * * Note: (col,row) in this case refer to the coordinate location in * NetHack character grid terms, (ie. the 40 x 25 character grid), * not the x,y pixel location. * */ void vga_DisplayCell(gp,col,row) struct planar_cell_struct *gp; int col,row; { int i,pixx,pixy; char __far *tmp_s; /* source pointer */ char __far *tmp_d; /* destination pointer */ int vplane; pixy = row2y(row); /* convert to pixels */ pixx = col2x(col); for(vplane=0; vplane < SCREENPLANES; ++vplane) { egawriteplane(vp[vplane]); for(i=0;i < ROWS_PER_CELL; ++i) { tmp_d = screentable[i+pixy]; tmp_d += pixx; /* * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i], * BYTES_PER_CELL); */ tmp_s = gp->plane[vplane].image[i]; WRITE_ABSOLUTE(tmp_d, (*tmp_s)); ++tmp_s; ++tmp_d; WRITE_ABSOLUTE(tmp_d, (*tmp_s)); } } egawriteplane(15); } void vga_DisplayCell_O(gp,col,row) struct overview_planar_cell_struct *gp; int col,row; { int i,pixx,pixy; char __far *tmp_s; /* source pointer */ char __far *tmp_d; /* destination pointer */ int vplane; pixy = row2y(row); /* convert to pixels */ pixx = col; for(vplane=0; vplane < SCREENPLANES; ++vplane) { egawriteplane(vp[vplane]); for(i=0;i < ROWS_PER_CELL; ++i) { tmp_d = screentable[i+pixy]; tmp_d += pixx; /* * memcpy((void *)tmp,(void *)gp->plane[vplane].image[i], * BYTES_PER_CELL); */ tmp_s = gp->plane[vplane].image[i]; WRITE_ABSOLUTE(tmp_d, (*tmp_s)); } } egawriteplane(15); } /* * Write the character string pointed to by 's', whose maximum length * is 'len' at location (x,y) using the 'colour' colour. * */ void vga_WriteStr(s,len,col,row,colour) char *s; int len,col,row,colour; { unsigned char *us; int i = 0; /* protection from callers */ if (row > (LI-1)) return; i = 0; us = (unsigned char *)s; while( (*us != 0) && (i < len) && (col < (CO - 1))) { vga_WriteChar(*us,col,row,colour); ++us; ++i; ++col; } } # endif /* OVLB */ # ifdef OVLB /* * Initialize the VGA palette with the desired colours. This * must be a series of 48 bytes for use with a card in * 16 colour mode at 640 x 480. * */ void vga_SetPalette(p) char *p; { union REGS regs; int i; outportb(0x3c6,0xff); for(i=0;i < COLORDEPTH; ++i) { outportb(0x3c8,i); outportb(0x3c9,(*p++) >> 2); outportb(0x3c9,(*p++) >> 2); outportb(0x3c9,(*p++) >> 2); } regs.x.bx = 0x0000; for(i=0;i < COLORDEPTH; ++i) { regs.x.ax = 0x1000; (void) int86(VIDEO_BIOS,®s,®s); regs.x.bx += 0x0101; } } /*static unsigned char colorbits[]={0x01,0x02,0x04,0x08}; */ /* wrong */ static unsigned char colorbits[]={0x08,0x04,0x02,0x01}; #ifdef POSITIONBAR #define PBAR_ROW (LI - 4) #define PBAR_COLOR_ON 15 /* slate grey background colour of tiles */ #define PBAR_COLOR_OFF 12 /* bluish grey, used in old style only */ #define PBAR_COLOR_STAIRS 9 /* brown */ #define PBAR_COLOR_HERO 14 /* creamy white */ static unsigned char pbar[COLNO]; void vga_update_positionbar(posbar) char *posbar; { char *p = pbar; if (posbar) while (*posbar) *p++ = *posbar++; *p = 0; } STATIC_OVL void positionbar() { char *posbar = pbar; int feature, ucol; int k, y, colour, row; char __far *pch; int startk, stopk; char volatile a; boolean nowhere = FALSE; int pixy = (PBAR_ROW * MAX_ROWS_PER_CELL); int tmp; if (!iflags.grmode || !iflags.tile_view) return; if ((clipx < 0) || (clipxmax <= 0) || (clipx >= clipxmax)) nowhere = TRUE; if (nowhere) { #ifdef DEBUG pline("Would have put bar using %d - %d.",clipx,clipxmax); #endif return; } #ifdef OLD_STYLE outportb(0x3ce,5); outportb(0x3cf,2); for (y=pixy; y < (pixy + MAX_ROWS_PER_CELL); ++y) { pch = screentable[y]; for (k=0; k < SCREENBYTES; ++k) { if ((k < clipx) || (k > clipxmax)) { colour = PBAR_COLOR_OFF; } else colour = PBAR_COLOR_ON; outportb(0x3ce,8); outportb(0x3cf,255); a = READ_ABSOLUTE(pch); /* Must read , then write */ WRITE_ABSOLUTE(pch, (char)colour); ++pch; } } outportb(0x3ce,5); outportb(0x3cf,0); #else colour = PBAR_COLOR_ON; outportb(0x3ce,5); outportb(0x3cf,2); for (y=pixy, row = 0; y < (pixy + MAX_ROWS_PER_CELL); ++y, ++row) { pch = screentable[y]; if ((!row) || (row == (ROWS_PER_CELL-1))) { startk = 0; stopk = SCREENBYTES; } else { startk = clipx; stopk = clipxmax; } for (k=0; k < SCREENBYTES; ++k) { if ((k < startk) || (k > stopk)) colour = BACKGROUND_VGA_COLOR; else colour = PBAR_COLOR_ON; outportb(0x3ce,8); outportb(0x3cf,255); a = READ_ABSOLUTE(pch); /* Must read , then write */ WRITE_ABSOLUTE(pch, (char)colour); ++pch; } } outportb(0x3ce,5); outportb(0x3cf,0); #endif ucol = 0; if (posbar) { while (*posbar != 0) { feature = *posbar++; switch (feature) { case '>': vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS); break; case '<': vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS); break; case '@': ucol = (int)*posbar++; vga_special(feature, ucol, PBAR_COLOR_HERO); break; default: /* unanticipated symbols */ vga_special(feature, (int)*posbar++, PBAR_COLOR_STAIRS); break; } } } # ifdef SIMULATE_CURSOR if (inmap) { tmp = curcol + 1; if ((tmp != ucol) && (curcol >= 0)) vga_special('_', tmp, PBAR_COLOR_HERO); } # endif } void vga_special(chr,col,color) int chr,col,color; { int i,y,pixy; char __far *tmp_d; /* destination pointer */ int vplane; char fnt; char bits[SCREENPLANES][ROWS_PER_CELL]; pixy = PBAR_ROW * MAX_ROWS_PER_CELL; for(vplane=0; vplane < SCREENPLANES; ++vplane) { egareadplane(vplane); y = pixy; for(i=0;i < ROWS_PER_CELL; ++i) { tmp_d = screentable[y++] + col; bits[vplane][i] = READ_ABSOLUTE(tmp_d); fnt = READ_ABSOLUTE((font + ((chr<<4) + i))); if (colorbits[vplane] & color) bits[vplane][i] |= fnt; else bits[vplane][i] &= ~fnt; } } for(vplane=0; vplane < SCREENPLANES; ++vplane) { egawriteplane(vp[vplane]); y = pixy; for(i=0;i < ROWS_PER_CELL; ++i) { tmp_d = screentable[y++] + col; WRITE_ABSOLUTE(tmp_d, (bits[vplane][i])); } } egawriteplane(15); } # endif POSITIONBAR # ifdef SIMULATE_CURSOR static struct planar_cell_struct undercursor; static struct planar_cell_struct cursor; void vga_DrawCursor() { int i,pixx,pixy,x,y,p; char __far *tmp1; char __far *tmp2; unsigned char first,second; /* char on[2] = {0xFF,0xFF}; */ /* char off[2] = {0x00,0x00}; */ #ifdef REINCARNATION boolean isrogue = Is_rogue_level(&u.uz); boolean singlebyte = (isrogue || iflags.over_view || iflags.traditional_view || !inmap); #else boolean singlebyte = (iflags.over_view || iflags.traditional_view || !inmap); #endif int curtyp; if (!cursor_type && inmap) return; /* CURSOR_INVIS - nothing to do */ x = min(curcol,(CO - 1)); /* protection from callers */ y = min(currow,(LI - 1)); /* protection from callers */ if (!singlebyte && ((x < clipx) || (x > clipxmax))) return; pixy = row2y(y); /* convert to pixels */ if (singlebyte) pixx = x; else pixx = col2x((x-clipx)); for(i=0;i < ROWS_PER_CELL; ++i) { tmp1 = screentable[i+pixy]; tmp1 += pixx; tmp2 = tmp1 + 1; egareadplane(3); /* memcpy(undercursor.plane[3].image[i],tmp1,BYTES_PER_CELL); */ undercursor.plane[3].image[i][0] = READ_ABSOLUTE(tmp1); if (!singlebyte) undercursor.plane[3].image[i][1] = READ_ABSOLUTE(tmp2); egareadplane(2); /* memcpy(undercursor.plane[2].image[i],tmp1,BYTES_PER_CELL); */ undercursor.plane[2].image[i][0] = READ_ABSOLUTE(tmp1); if (!singlebyte) undercursor.plane[2].image[i][1] = READ_ABSOLUTE(tmp2); egareadplane(1); /* memcpy(undercursor.plane[1].image[i],tmp1,BYTES_PER_CELL); */ undercursor.plane[1].image[i][0] = READ_ABSOLUTE(tmp1); if (!singlebyte) undercursor.plane[1].image[i][1] = READ_ABSOLUTE(tmp2); egareadplane(0); /* memcpy(undercursor.plane[0].image[i],tmp1,BYTES_PER_CELL); */ undercursor.plane[0].image[i][0] = READ_ABSOLUTE(tmp1); if (!singlebyte) undercursor.plane[0].image[i][1] = READ_ABSOLUTE(tmp2); } /* * Now we have a snapshot of the current cell. * Make a copy of it, then manipulate the copy * to include the cursor, and place the tinkered * version on the display. */ cursor = undercursor; if (inmap) curtyp = cursor_type; else curtyp = CURSOR_UNDERLINE; switch(curtyp) { case CURSOR_CORNER: for(i = 0; i < 2; ++i) { if (!i) { if (singlebyte) first = 0xC3; else first = 0xC0; second = 0x03; } else { if (singlebyte) first = 0x81; else first = 0x80; second = 0x01; } for (p=0; p < 4; ++p) { if (cursor_color & colorbits[p]) { cursor.plane[p].image[i][0] |= first; if (!singlebyte) cursor.plane[p].image[i][1] |= second; } else { cursor.plane[p].image[i][0] &= ~first; if (!singlebyte) cursor.plane[p].image[i][1] &= ~second; } } } for(i = ROWS_PER_CELL - 2; i < ROWS_PER_CELL; ++i) { if (i != (ROWS_PER_CELL-1)) { if (singlebyte) first = 0x81; else first = 0x80; second = 0x01; } else { if (singlebyte) first = 0xC3; else first = 0xC0; second = 0x03; } for (p=0; p < SCREENPLANES; ++p) { if (cursor_color & colorbits[p]) { cursor.plane[p].image[i][0] |= first; if (!singlebyte) cursor.plane[p].image[i][1] |= second; } else { cursor.plane[p].image[i][0] &= ~first; if (!singlebyte) cursor.plane[p].image[i][1] &= ~second; } } } break; case CURSOR_UNDERLINE: i = ROWS_PER_CELL - 1; first = 0xFF; second = 0xFF; for (p=0; p < SCREENPLANES; ++p) { if (cursor_color & colorbits[p]) { cursor.plane[p].image[i][0] |= first; if (!singlebyte) cursor.plane[p].image[i][1] |= second; } else { cursor.plane[p].image[i][0] &= ~first; if (!singlebyte) cursor.plane[p].image[i][1] &= ~second; } } break; case CURSOR_FRAME: /* fall through */ default: for(i = 0; i < ROWS_PER_CELL; ++i) { if ((i == 0) || (i == (ROWS_PER_CELL-1))) { first = 0xFF; second = 0xFF; } else { if (singlebyte) first = 0x81; else first = 0x80; second = 0x01; } for (p=0; p < SCREENPLANES; ++p) { if (cursor_color & colorbits[p]) { cursor.plane[p].image[i][0] |= first; if (!singlebyte) cursor.plane[p].image[i][1] |= second; } else { cursor.plane[p].image[i][0] &= ~first; if (!singlebyte) cursor.plane[p].image[i][1] &= ~second; } } } break; } /* * Place the new cell onto the display. * */ for(i=0;i < ROWS_PER_CELL; ++i) { tmp1 = screentable[i+pixy]; tmp1 += pixx; tmp2 = tmp1 + 1; egawriteplane(8); /* memcpy(tmp1,cursor.plane[3].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1,cursor.plane[3].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2,cursor.plane[3].image[i][1]); egawriteplane(4); /* memcpy(tmp1,cursor.plane[2].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1,cursor.plane[2].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2,cursor.plane[2].image[i][1]); egawriteplane(2); /* memcpy(tmp1,cursor.plane[1].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1,cursor.plane[1].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2,cursor.plane[1].image[i][1]); egawriteplane(1); /* memcpy(tmp1,cursor.plane[0].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1,cursor.plane[0].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2,cursor.plane[0].image[i][1]); } egawriteplane(15); #ifdef POSITIONBAR if (inmap) positionbar(); #endif } void vga_HideCursor() { int i,pixx,pixy,x,y; char __far *tmp1; char __far *tmp2; #ifdef REINCARNATION boolean isrogue = Is_rogue_level(&u.uz); boolean singlebyte = (isrogue || iflags.over_view || iflags.traditional_view || !inmap); #else boolean singlebyte = (iflags.over_view || iflags.traditional_view || !inmap); #endif int curtyp; if (inmap && !cursor_type) return; /* CURSOR_INVIS - nothing to do */ /* protection from callers */ x = min(curcol,(CO - 1)); y = min(currow,(LI-1)); if (!singlebyte && ((x < clipx) || (x > clipxmax))) return; pixy = row2y(y); /* convert to pixels */ if (singlebyte) pixx = x; else pixx = col2x((x-clipx)); if (inmap) curtyp = cursor_type; else curtyp = CURSOR_UNDERLINE; if (curtyp == CURSOR_UNDERLINE) /* optimization for uline */ i = ROWS_PER_CELL - 1; else i = 0; for(;i < ROWS_PER_CELL; ++i) { tmp1 = screentable[i+pixy]; tmp1 += pixx; tmp2 = tmp1 + 1; egawriteplane(8); /* memcpy(tmp,undercursor.plane[3].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1,undercursor.plane[3].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2,undercursor.plane[3].image[i][1]); egawriteplane(4); /* memcpy(tmp,undercursor.plane[2].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1,undercursor.plane[2].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2,undercursor.plane[2].image[i][1]); egawriteplane(2); /* memcpy(tmp,undercursor.plane[1].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1,undercursor.plane[1].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2,undercursor.plane[1].image[i][1]); egawriteplane(1); /* memcpy(tmp,undercursor.plane[0].image[i],BYTES_PER_CELL); */ WRITE_ABSOLUTE(tmp1,undercursor.plane[0].image[i][0]); if (!singlebyte) WRITE_ABSOLUTE(tmp2,undercursor.plane[0].image[i][1]); } egawriteplane(15); } # endif /* SIMULATE_CURSOR */ # endif /* OVLB */ #endif /* SCREEN_VGA */ /* vidvga.c */ nethack-3.4.3/sys/os2/0040755000000000000000000000000007764735105013177 5ustar rootrootnethack-3.4.3/sys/os2/Install.os20100644000000000000000000003634307764735041015237 0ustar rootroot Instructions for compiling and installing NetHack 3.4 on an OS/2 system ===================================================== Timo Hakulinen Last revision: 29 October 1996 0. Read this entire file before starting, and come back to the Notes below if you have any problems. 1. Make sure all the NetHack files are in the appropriate directory structure. You should have a top directory (e.g. nh33, or whatever you like) with subdirectories dat, doc, include, src, util, sys\share, sys\os2, and win\tty. You may have other subdirectories under sys and win, but they will not affect compilation for an OS/2 system. If you do not follow this structure, the makefile will not function properly. The .c files for the main program belong in src, those for utility programs in util, and OS/2-specific ones in sys\os2. All the .h files belong in include, the documentation in doc, and assorted data files in dat. There are also some necessary files in sys\share (pc*.c, random.c, dgn_*.*, lev_*.*). A more detailed explanation of the directory structure is found in file Files, which should be in the top directory. If you downloaded or ftp'd the sources from a UNIX system, the lines may end in UNIX-style newlines instead of the carriage return and line feed pairs used by DOS and OS/2. You'll have to convert them (with a utility like Rahul Dhesi's "flip"). Also, every file should end with a carriage return / line feed pair, because Microsoft C has had a habit of ignoring the last line of each file otherwise. Besides, even editing UNIX-style files with DOS editors is often a royal pain. 2. The makefile for OS/2, Makefile.os2, is found in directory sys\os2. Copy it to directory src and rename it Makefile. From now on, Makefile.os2 will be referred to as "the makefile" in this document. The makefile supports the following make utilities: NDMAKE a public domain make utility for DOS by Don Kneller NMAKE make shipped with Microsoft languages and IBM C Set/2 DMAKE a public domain make for DOS and OS/2 by Dennis Vadura Both NDMAKE and DMAKE are available at major archive sites. The following compilers are supported: compiler: runs in: compiles for: Microsoft C 5.1 DOS / OS/2 1.0-Warp OS/2 1.x Microsoft 6.0A (see note 5) - " - - " - IBM C Set/2 1.00, Toolkit/2 2.00 OS/2 2.x, Warp OS/2 2.x, Warp IBM CSet++ 2.00 OS/2 2.x, Warp OS/2 2.x, Warp GCC emx 0.8f (see note 6) OS/2 2.x, Warp OS/2 2.x, Warp Note that code compiled for OS/2 versions 1.0-1.3 runs unmodified in OS/2 versions 2.0 and up. In principle it should be possible to cross compile NetHack 3.4 for OS/2 in DOS using NDMAKE and MSC, but this is not recommended (see note 3). If you're using some other compiler than one listed above, you will have to adapt the makefile to your needs. In particular, change the CC, CFLAGS, LINK, and LFLAGS macros to your C compiler's and linker's liking. See the makefile for more information. If you are going to be constructing Fred Fish's termcap library, you'll need Makefile.lib in sys\share (see note 4). 3. Go to the include subdirectory. First edit config.h according to the comments to match your system and desired set of features. In particular, make sure that OS2 is defined, and that UNIX, HACKDIR, and COMPRESS are *not* defined. If you want to try out the new DLB data file library scheme, uncomment DLB. Note that although the makefile contains some support for this scheme, it's new in NetHack 3.3 and hasn't been tested. If your compiler is ANSI compliant (like practically all OS/2 compilers are), it's probable that nothing else needs to be configured in config.h. Next look at os2conf.h. This file shouldn't need much changing. If you want to use the hardcoded OS/2 system definitions in def_os2.h instead of the compiler's standard headers, comment out OS2_USESYSHEADERS. This may become necessary if you are using a compiler which doesn't come with proper system headers by default. In this case you may have to edit the definitions there, because every compiler has its own way of declaring the necessary system functions and data structures. In general you should prefer the compiler's offerings, if possible. If you are going to compile the game on an HPFS drive, uncomment OS2_HPFS, which enables the use of longer file names during compilation. The generated executable will only use file names compatible with FAT drives, however. If you are using a 32 bit compiler other than GCC emx 0.8f or C Set/2 in OS/2 2.x, force OS2_32BITAPI to be defined. Otherwise it is defined only for the above mentioned compilers. If you are not going to include random.c, because you are using the random number generator provided by your compiler, you will need to comment out RANDOM. If you want to muck with different termcap settings, uncomment TERMLIB to enable the use of termcap routines (see note 4). This is not necessary to create a fully functional game, however. 4. If you are using another compiler than MSC, GCC, or IBM C Set/2, you may want to look through system.h in the include directory. This file matches the return and parameter types for system calls and library routines with various flavors of compilers and operating systems. Leaving this file alone is unlikely to cause problems, but if you get compile errors with any functions in the standard library, it's worth checking the declarations there. 5. If you want to change the high score list behavior, examine the top of topten.c, in the src directory. You may want to change the definitions of PERSMAX, POINTSMIN, and ENTRYMAX. 6. Go to the src directory and edit the top of the makefile. Be sure that the directory you want the game installed to actually exists. You'll need nroff and/or TeX/LaTeX to do the files in doc. If you don't have either of these, you can skip it. If you elected not to use the high quality BSD random number routines by commenting out RANDOM in os2conf.h, comment out (or set equal to nothing) the RANDOM macro in the makefile. If you elected to use Fred Fish's termcap library (bundled in as termcap.uu in directory sys\share), you will have to generate termlib.lib from those sources by typing "make -f makefile.lib termlib.lib". You must set the TERMLIB option in the makefile to link the resulting termlib.lib into the game. If you are recompiling after patching your sources, or if you got your files from somewhere other than the official distribution, "touch makedefs.c" to ensure that certain files (onames.h and pm.h) are remade, lest potentially troublesome time stamps fool make. If you have lex and yacc programs, or the equivalent flex and bison programs, you can set up the makefile to generate the appropriate .h and .c files from their .l and .y counterparts whenever you recompile. This is done by changing the do_yacc and do_lex targets in the makefile to depend on targets yacc_act and lex_act instead of yacc_cpy and lex_cpy. Otherwise the makefile will copy pre-generated yacc and lex output files dgn_*.* and lev_*.* from directory sys\share to util and include. Now, enter "make all", and take a siesta; your computer will be occupied for a fair amount of time. If all goes well, you will get an executable. 7. All the support data files should have been copied to the game directory by the make process. Here is the complete list in alphabetical order of all the files that should have gotten there during a full build: Arc-fila.lev Arc-filb.lev Arc-goal.lev Arc-loca.lev Arc-strt.lev Bar-fila.lev Bar-filb.lev Bar-goal.lev Bar-loca.lev Bar-strt.lev Cav-fila.lev Cav-filb.lev Cav-goal.lev Cav-loca.lev Cav-strt.lev Hea-fila.lev Hea-filb.lev Hea-goal.lev Hea-loca.lev Hea-strt.lev Kni-fila.lev Kni-filb.lev Kni-goal.lev Kni-loca.lev Kni-strt.lev Mon-fila.lev Mon-filb.lev Mon-goal.lev Mon-loca.lev Mon-strt.lev Pri-fila.lev Pri-filb.lev Pri-goal.lev Pri-loca.lev Pri-strt.lev Ran-fila.lev Ran-filb.lev Ran-goal.lev Ran-loca.lev Ran-strt.lev Rog-fila.lev Rog-filb.lev Rog-goal.lev Rog-loca.lev Rog-strt.lev Sam-fila.lev Sam-filb.lev Sam-goal.lev Sam-loca.lev Sam-strt.lev Tou-fila.lev Tou-filb.lev Tou-goal.lev Tou-loca.lev Tou-strt.lev Val-fila.lev Val-filb.lev Val-goal.lev Val-loca.lev Val-strt.lev Wiz-fila.lev Wiz-filb.lev Wiz-goal.lev Wiz-loca.lev Wiz-strt.lev air.lev asmodeus.lev astral.lev baalz.lev bigrm-1.lev bigrm-2.lev bigrm-3.lev bigrm-4.lev bigrm-5.lev castle.lev cmdhelp data dungeon earth.lev fakewiz1.lev fakewiz2.lev fire.lev help hh history juiblex.lev knox.lev license medusa-1.lev medusa-2.lev minefill.lev minend-1.lev minend-2.lev minetn-1.lev minetn-2.lev nethack.cmd nethack.cnf nethack.exe nethack.ico opthelp options oracle.lev oracles orcus.lev quest.dat recover.exe rumors sanctum.lev soko1-1.lev soko1-2.lev soko2-1.lev soko2-2.lev soko3-1.lev soko3-2.lev soko4-1.lev soko4-2.lev tower1.lev tower2.lev tower3.lev valley.lev water.lev wizard1.lev wizard2.lev wizard3.lev wizhelp Yes. It's 112 files for a full featured NetHack 3.4. If any of the files are missing, try to rerun make. If that doesn't help, you'll have to try to decipher the makefile to find out how to manually create the missing files. These kinds of troubles shouldn't happen except for two reasons: You've run out of disk space while compiling or your make utility doesn't understand the makefile properly for some reason. In either case, you should get some warnings from the make, though. If you have old record, logfile, or news files in the game directory, they are not overwritten. Of course, old records from NetHack 3.1 and 3.2 are not worth keeping with 3.4, since these games are really quite different. Edit file nethack.cnf in the game directory to reflect your particular setup and personal preferences, following the comments there. More info about settable options can be found in the file opthelp and the guidebook. If you compiled in the TERMLIB feature, also move the sys\share\termcap file to your game directory. 8. If you'll be running NetHack from a different subdirectory, you will want to "set HACKDIR=c:\games\nh33" (or whatever directory you want to use). Add it to your config.sys, if you'll be playing often. You can also create a special NetHack entry in your Presentation Manager / Workplace Shell desktop. This will use the included NetHack icon. The following is a sample program description for OS/2 1.3 desktop, but it's similar for OS/2 2.0: Program title: NetHack 3.4 Path and file name: c:\games\nh33\nethack.cmd Parameters: Working directory: c:\games\nh33 Program type: OS/2 Full screen Naturally you must fill in your own game directory and parameters if you want to set any. The program type can be either OS/2 Full screen or OS/2 Windowed. Note that you should set the executable path to use the .cmd file generated by the makefile. This file generates an extra pause after the program exit, because otherwise you wouldn't get to see the high score list upon quitting due to PM/WPS automatically closing the program window. When starting NetHack normally from OS/2 command prompt, the command processor starts nethack.exe instead, so no extra pause is generated. 9. If you want to clear up the temporary files and objects created by the compilation process, you may issue "make spotless". This will return your source tree to near-distribution condition. Naturally, it will not affect your newly built game files in any way. 10. Play NetHack. If it works, you're done! Notes ----- 1) Save-files and bones-files from previous versions will not work with NetHack 3.4. Don't bother trying to keep them. 2) To install an update of NetHack after changing something, enter "make" from the src directory. If you add, delete, or reorder monsters or objects, or you change the format of saved level files, delete any save and bones files. (Trying to use such files sometimes produces amusing confusions on the game's part, but usually crashes.) 3) When cross-compiling for OS/2 in DOS, NDMAKE is the best choice because it requires the least RAM for itself. Note however, that cross-compilation in DOS is discouraged, because it is considered obsolete (OS/2 is really a much better place to compile). If you still want to try, here are some suggestions: During linking, Microsoft linker will need temporary storage space. Make sure you have about 1 MB of free disk where ever you have defined your temporary storage. It is also a good idea to compile with as much free RAM as possible. It may otherwise get crowded with the bigger, more complex source files (compiler bombs with "out of heap space" or similar). If this happens, strip your configuration, zap TSR's, get a better memory manager etc. 4) The file sys\share\termcap.uu is the fixed version of the Fred Fish termcap library. You will need to run a uudecode utility on it to generate the file termcap.zip. termcap.zip contains several files of termcap routines. Using them with NetHack involves very little knowledge of the UNIX concept of a termcap database; mostly you need to know enough to set a TERM environment variable. You can unzip termcap.zip in the sys\share directory, but if you are going to use it, it is probably best to unzip a copy in the src directory. That way you will not miss copying any files over. Wherever you unzip it, get rid of the included makefile since a better version has been provided as Makefile.lib. After creating the termcap library file termlib.lib, copy it to src before compiling the game main source. 5) When compiling with MSC 6.0, the maintenance version 6.0A should be used instead of the original 6.0, which was all too buggy to successfully build NetHack. 6) Note that emx 0.8f is the first version of GCC for OS/2 that can properly compile NetHack. Earlier versions do not work, because they don't support the 16 bit API calls of OS/2. GCC emx 0.8f does not currently work properly when fseek() function is used with text files. This is well documented in the compiler's documentation. Unfortunately NetHack uses fseek() in several places in connection with text data. This means that some help texts may not come out right, but no serious problems should emerge. nethack-3.4.3/sys/os2/Makefile.os20100644000000000000000000014241507764735041015344 0ustar rootroot# SCCS Id: @(#)Makefile.os2 3.4.3 1996/10/29 # OS/2 NetHack 3.4.3 Makefile for OS/2 versions 2.x # Copyright (C) 1990, 1991, 1992, 1993, 1996 Timo Hakulinen # # Several compilers exist for OS/2 but, currently only GCC emx is tested # and used for releases. make programs other than dmake are not tested. # # Supported compilers: GCC emx 0.9g # # DMAKE is required. Credit for the makefile improvements goes to # Pekka Rousu. # # Copy this file into $(SRC) directory, rename it to "makefile" # (important, many targets rely on it), compile and link inside # $(SRC). If required, termcap library can be built from termcap # sources using makefile.lib in "sys\share" directory. # # "GCC" refers to GCC emx only. No other ports of GCC are supported. # Additional credits for honing GCC support for 3.2 go to Ronald # Van Iwaarden (ron@vaniwaarden.org) and Stefan Neis (neis@cs.uni-sb.de). # # "OMF" is short for "Object Module Format" and refers to the # standard OS/2 object format, which e.g. link386 uses. MSC and # CSet/2 always produce OMF object files, and GCC can be instructed # to produce them with proper switches (see below). # # "a.out" refers to Unix object file format, which is used by GCC # in its default compilation mode. These object files must be # linked using GCC's own linker to produce a proper OS/2 executable. # GDB debugger shipped with GCC can only be used with a.out object # format. # # Note that the default setup in this makefile is my personal setup, # which you will have to adapt to your configuration. # # # Compiler and linker selection. # #format = omf format = a.out .IF $(format) == a.out with_x11 = yes #debug = yes .END CC = gcc # GCC .IF $(format) == a.out LINK = gcc #LINK = link386 # GCC OMF, CSet/2 .ELSE LINK = link386 # GCC OMF, CSet/2 LFLAGS = /noig /stack:40000 .END .IF $(with_x11) == yes WINX11OBJ01 = $(OBJ)/Window.o WINX11OBJ02 = $(OBJ)/dialogs.o WINX11OBJ03 = $(OBJ)/winX.o WINX11OBJ04 = $(OBJ)/winmap.o WINX11OBJ05 = $(OBJ)/winmenu.o WINX11OBJ06 = $(OBJ)/winmesg.o WINX11OBJ07 = $(OBJ)/winmisc.o WINX11OBJ08 = $(OBJ)/winstat.o WINX11OBJ09 = $(OBJ)/wintext.o WINX11OBJ10 = $(OBJ)/winval.o WINX11OBJ11 = $(OBJ)/tile.o X11ROOT = e:/xfree86 WINX11CFLAGS = -DUSE_XPM -DX11_GRAPHICS \ -I$(X11ROOT)/include -Zmtd WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 -lXpm -L$(X11ROOT)/lib -lc_app WINX11SRC = ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \ ../win/X11/winmap.c ../win/X11/winmenu.c ../win/X11/winmesg.c \ ../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.c \ ../win/X11/winval.c tile.c WINX11OBJ = $(WINX11OBJ01) $(WINX11OBJ02) $(WINX11OBJ03) $(WINX11OBJ04) \ $(WINX11OBJ05) $(WINX11OBJ06) $(WINX11OBJ07) $(WINX11OBJ08) \ $(WINX11OBJ09) $(WINX11OBJ10) $(WINX11OBJ11) WINX11VARDAT=x11tiles pet_mark.xbm rip.xpm X11ECHO = $(CMD) @echo .END MAKEB = dmake CMD = cmd /C AB = $(@:B).c CB = $$(@:B).c BEG = $(CMD) " END = " SEP = & P = % # # Most makes execute actions automatically inside a subshell, # which makes even the shell internals work ok. # ECHO = $(CMD) @echo RM = $(CMD) del CP = $(CMD) copy CAT = $(CMD) type # # For those of us who have these on PC. # #YACC = yacc #LEX = lex YACC = bison -y LEX = flex # # For extracting NetHack icon. # UUDECODE = uudecode # # For people with TeX and LaTeX. # LATEX = latex # # If you have TOUCH, some things become slightly easier. # TOUCH = touch # # Standard file naming for LEX and YACC output may vary in PC # installations. These three are probably the most generally used # names. # YTABC = y_tab.c YTABH = y_tab.h LEXYYC = lexyy.c # # Source tree base directory. # NHSRC = \nethack # # Source directories. Makedefs hardcodes these, don't change them. # INCL = $(NHSRC)\include # NetHack include files DAT = $(NHSRC)\dat # NetHack data files DOC = $(NHSRC)\doc # NetHack documentation files UTIL = $(NHSRC)\util # Utility source SRC = $(NHSRC)\src # Main source WIN = $(NHSRC)\win\tty # Window system specific source WINX11 = $(NHSRC)\win\x11 # Window system specific source SYS = $(NHSRC)\sys\os2 # System specific source SSYS = $(NHSRC)\sys\share # Shared system files WINSHARE= $(NHSRC)\win\share # Shared system files # # Modifiable directories. Set these according to your setup and # preferences. They must all be present prior to compilation. # OBJ, TEMP and GAMEDIR should all preferably be separate and, # in particular, not the same as any of the source directories. # Note that DMAKE may dislike drive designators in paths because # it misinterprets the colon as being part of a make rule. In that # case, all directories have to reside on the same drive. # OBJ = \tmp\obj # Object files TEMP = \tmp\bin # Temporary files during make process GAMEDIR = \games\nh343x11 # Game directory PLIBP = c:\emx\lib # Protected mode C libraries RLIBP = c:\emx\lib # Possible real mode C libraries # # The game name and description. # GAME = nethack GAMEDES = "NetHack 3.4.3" # # The uppermost two lines for MSC, the middle two for GCC, and # the lowermost two for CSet/2. # # GCC: compile only, compiler id, object format selection, warnings, # include file path, debug flags, ANSI conformance. # CFLAGS = -c $(GCCO) $(WARN) -I$(INCL) $(CDFLAGS) $(STDC) $(WINX11CFLAGS) #OPT = -s -O -o OPT = -o # # Compiler warning levels. These are really for development, so # they are commented out in general distribution to save the user # from masses of benign warnings. If any problems arise, however, # they may help in finding the trouble. # # GCC: max. reasonable GCC warning levels. Can't use -Wall, because then # it would whine about all the zillions of unused declarations etc. # Even with these switches you'll get a lot of warnings, but they should # all be benign. # WARN = #-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN # GCC # # GCC object format selection. The upper line for standard OS/2 OMF # object format, the lower for Unix style a.out format. # .IF $(format) == omf GCCO = -Zomf -Zsys .ELSE GCCO = .END # # MSC 5.1 needs the large model first pass of the compiler. # Not needed for later versions. # BIGC = # # Unset CL to avoid troubles with conflicting switches in MSC 6.0. # CL = # # Prepare for a debugger. # .IF $(debug) == yes CDFLAGS = LDFLAGS = .ELSE CDFLAGS = -O -s LDFLAGS = -s .END # # How to produce the most ANSI-like environment. # STDC = -ansi # GCC # # Possible system object files required during linking. # .IF $(format) == omf SYSOBJ = $(PLIBP)\crt0.obj $(PLIBP)\end.lib# GCC OMF .ELSE SYSOBJ = # MSC, GCC a.out, CSet/2 .END # # Compiler library selection. Change if necessary. # # GCC emx 0.9 OMF: C single-threaded libs, Unix system call alias lib, # extra GCC lib, single threaded system lib, OS/2 API entry points. # Note that emx changed library naming convention between 0.8 and 0.9. # # GCC a.out: extra GCC lib, C standard lib, extra GCC lib (again), # OS/2 API entry points. # .IF $(format) == omf PLIBS = $(PLIBP)\st\c $(PLIBP)\st\c_app $(PLIBP)\c_alias $(PLIBP)\gcc $(PLIBP)\st\sys $(PLIBP)\os2 # GCC emx 0.9 OMF .ELSE PLIBS = -lgcc -lc -lgcc -los2 $(X11LIBS) # GCC a.out .END # # C libraries used by makedefs, lev_comp and dgn_comp (change if # necessary). If compilation is done in DOS, enable the upper line # possibly setting the library name to something else, if in OS/2, # enable the lower line (protected mode libraries). # #RLIBS = $(RLIBP)\llibcer RLIBS = $(PLIBS) SRCCC = $(CC) $(CFLAGS) $(OPT) $@ $(AB) UTILCC = $(BEG) cd $(UTIL) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END) SYSCC = $(BEG) cd $(SYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END) SSYSCC = $(BEG) cd $(SSYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END) PSYSCC = $(BEG) cd $(SSYS) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ pc$(AB) $(END) WINCC = $(BEG) cd $(WIN) $(SEP) $(CC) $(CFLAGS) $(OPT) $@ $(AB) $(END) # # Default linker skeletons. The upper six lines for everything # that uses standard OS/2 object format (GCC OMF), The lower six # for GCC a.out format. # .IF $(format) == omf GAMELN = $(LINK) @$(TEMP)\$(GAME).rsp MKDFLN = $(LINK) @$(TEMP)\makedefs.rsp LEVCLN = $(LINK) @$(TEMP)\lev_comp.rsp DGNCLN = $(LINK) @$(TEMP)\dgn_comp.rsp RCVRLN = $(LINK) @$(TEMP)\recover.rsp DLBRLN = $(LINK) @$(TEMP)\dlb.rsp .ELSE GAMELN = $(CC) $(LDFLAGS) -o $(GAMEDIR)\$(GAME).exe @$(TEMP)\$(GAME).r $(PLIBS) $(WINX11CFLAGS) $(WINX11LIB) MKDFLN = $(CC) $(LDFLAGS) -o $(TEMP)\makedefs.exe $(TEMP)\$(MKDFDEF) $(SYSOBJ) $(MAKEOBJS) $(PLIBS) LEVCLN = $(CC) $(LDFLAGS) -o $(TEMP)\lev_comp.exe $(TEMP)\$(LEVCDEF) $(SYSOBJ) $(SPLEVOBJS) $(PLIBS) DGNCLN = $(CC) $(LDFLAGS) -o $(TEMP)\dgn_comp.exe $(TEMP)\$(DGNCDEF) $(SYSOBJ) $(DGNCOMPOBJS) $(PLIBS) RCVRLN = $(CC) $(LDFLAGS) -o $(GAMEDIR)\recover.exe $(TEMP)\$(RCVRDEF) $(SYSOBJ) $(RECOVOBJS) $(PLIBS) DLBRLN = $(CC) $(LDFLAGS) -o $(TEMP)\dlb.exe $(TEMP)\$(DLBDEF) $(SYSOBJ) $(DLBOBJS) $(PLIBS) .END # # OS/2 module definition files for NetHack, # makedefs, dgn_comp, lev_comp, recover, dlb. # GAMEDEF = $(GAME).def MKDFDEF = makedefs.def LEVCDEF = lev_comp.def DGNCDEF = dgn_comp.def RCVRDEF = recover.def DLBDEF = dlb.def # # For compilation in DOS, enable the lower three lines and # disable the upper three. # MKDFMD = $(TEMP)\$(MKDFDEF) LEVCMD = $(TEMP)\$(LEVCDEF) DGNCMD = $(TEMP)\$(DGNCDEF) #MKDFMD = #LEVCMD = #DGNCMD = # # Optional high-quality BSD random number generation routines # (see os2conf.h). Set to nothing if not used. # RANDOM = $(OBJ)\random.o #RANDOM = # # If TERMLIB is defined in os2conf.h, comment out the upper line and # uncomment the lower. If the termcap-library doesn't exist, use # sys\share\makefile.lib to build it. # TERMLIB = #TERMLIB = termlib.lib # # Short / long file name selection for FAT and HPFS. # Only three files need consideration. # #GUIDEBOO = Guideboo # FAT #PATCHLEV = patchlev # - " - #DATABASE = data.bas # - " - GUIDEBOO = Guidebook # HPFS PATCHLEV = patchlevel # - " - DATABASE = data.base # - " - # # If you have LaTeX and want to create the NetHack Guidebook in TeX # device-independent file format, comment out the upper line and # uncomment the lower. # GUIDE = #GUIDE = $(TEMP)\$(GUIDEBOO).dvi # # Set WINOBJ lines corresponding to your desired combination # of windowing systems. Also set windowing systems in config.h. # # A straight tty port using no native windowing system is the # only choice for now. # WINOBJ1 = $(OBJ)\getline.o WINOBJ2 = $(OBJ)\termcap.o WINOBJ3 = $(OBJ)\topl.o WINOBJ4 = $(OBJ)\wintty.o WINOBJ = $(WINOBJ1) $(WINOBJ2) $(WINOBJ3) $(WINOBJ4) $(WINX11OBJ) # # The default make target, so just typing 'make' is useful. # Has to be the first target in the makefile. # default : all # # If you have yacc and lex programs and make any changes, uncomment # the lowermost two lines and comment out the others. If you make # changes to the .y and .l files but prefer processing the files # separately elsewhere, activate the middle two lines, so your changes # don't get overwritten. # do_yacc : yacc_cpy # use pre-generated files do_lex : lex_cpy # - " - #do_yacc : yacc_msg # show message if changed #do_lex : lex_msg # - " - #do_yacc : yacc_act # re-process files #do_lex : lex_act # - " - # # If you have the TOUCH utility the upper line is ok. Otherwise # the lower one does the same albeit in an ugly manner. Besides, # the latter method only works for text files. # #do_touch : realtouch do_touch : faketouch # # If you don't have uudecode program, use the upper line. # If you still want the icon, you'll have to extract the # file manually somewhere else. # do_icon : icon_msg # show message if changed #do_icon : icon_act # extract icon file # # If you don't want to generate nethack.cmd, use the upper line. # This could be the case, e.g., if you use a different shell than # the standard cmd.exe. # #do_cmd : cmd_msg # show message do_cmd : cmd_act # generate nethack.cmd # # If you want to try the data librarian scheme to reduce # the amount of data files in the NetHack home directory, comment # out the lower line and uncomment the upper. Also, make sure # that DLB is defined in config.h. # do_dlb : dlb_yup #do_dlb : dlb_nope ###################################################################### # # Nothing below this line should have to be changed. # # Other things that have to be reconfigured are in # config.h, os2conf.h and possibly system.h. # # # The game filename. # GAMEFILE = $(GAMEDIR)\$(GAME).exe # # Object files for makedefs. # MAKEOBJS = $(OBJ)\makedefs.o $(OBJ)\monst.o $(OBJ)\objects.o # # Object files for special levels compiler. # SOBJ01 = $(OBJ)\lev_yacc.o $(OBJ)\lev_lex.o $(OBJ)\lev_main.o $(OBJ)\alloc.o SOBJ02 = $(OBJ)\monst.o $(OBJ)\objects.o $(OBJ)\panic.o $(OBJ)\decl.o SOBJ03 = $(OBJ)\drawing.o SPLEVOBJS = $(SOBJ01) $(SOBJ02) $(SOBJ03) # # Object files for dungeon compiler. # DOBJ01 = $(OBJ)\dgn_yacc.o $(OBJ)\dgn_lex.o $(OBJ)\dgn_main.o DOBJ02 = $(OBJ)\panic.o $(OBJ)\alloc.o DGNCOMPOBJS = $(DOBJ01) $(DOBJ02) # # Object files for recovery utility. # RECOVOBJS = $(OBJ)\recover.o # # Object files for dlb. # DLBOBJS = $(OBJ)\dlb_main.o $(OBJ)\dlb.o $(OBJ)\alloc.o $(OBJ)\panic.o # # Data files for dlb. # DATHELP = \ help hh cmdhelp history opthelp wizhelp SPEC_LEVS = \ asmodeus.lev baalz.lev bigrm-1.lev \ bigrm-2.lev bigrm-3.lev bigrm-4.lev castle.lev fakewiz1.lev fakewiz2.lev \ juiblex.lev knox.lev medusa-1.lev medusa-2.lev minend-1.lev minend-2.lev \ minend-3.lev minefill.lev minetn-1.lev minetn-2.lev minetn-3.lev minetn-4.lev \ minetn-5.lev minetn-6.lev minetn-7.lev oracle.lev orcus.lev sanctum.lev \ tower1.lev tower2.lev tower3.lev valley.lev wizard1.lev wizard2.lev \ wizard3.lev astral.lev air.lev earth.lev fire.lev water.lev \ soko1-1.lev soko1-2.lev soko2-1.lev soko2-2.lev \ soko3-1.lev soko3-2.lev soko4-1.lev soko4-2.lev QUEST_LEVS = \ Arc-goal.lev Arc-fila.lev Arc-filb.lev Arc-loca.lev Arc-strt.lev \ Bar-goal.lev Bar-fila.lev Bar-filb.lev Bar-loca.lev Bar-strt.lev \ Cav-goal.lev Cav-fila.lev Cav-filb.lev Cav-loca.lev Cav-strt.lev \ Hea-goal.lev Hea-fila.lev Hea-filb.lev Hea-loca.lev Hea-strt.lev \ Kni-goal.lev Kni-fila.lev Kni-filb.lev Kni-loca.lev Kni-strt.lev \ Mon-goal.lev Mon-fila.lev Mon-filb.lev Mon-loca.lev Mon-strt.lev \ Pri-goal.lev Pri-fila.lev Pri-filb.lev Pri-loca.lev Pri-strt.lev \ Ran-goal.lev Ran-fila.lev Ran-filb.lev Ran-loca.lev Ran-strt.lev \ Rog-goal.lev Rog-fila.lev Rog-filb.lev Rog-loca.lev Rog-strt.lev \ Sam-goal.lev Sam-fila.lev Sam-filb.lev Sam-loca.lev Sam-strt.lev \ Tou-goal.lev Tou-fila.lev Tou-filb.lev Tou-loca.lev Tou-strt.lev \ Val-goal.lev Val-fila.lev Val-filb.lev Val-loca.lev Val-strt.lev \ Wiz-goal.lev Wiz-fila.lev Wiz-filb.lev Wiz-loca.lev Wiz-strt.lev VARDATD = \ data oracles options quest.dat rumors $(WINX11VARDAT) DATDLB = $(DATHELP) dungeon $(SPEC_LEVS) $(QUEST_LEVS) $(VARDATD) \ $(do_dlb) # # Object files for the game itself. # VOBJ011 = $(OBJ)\allmain.o VOBJ012 = $(OBJ)\alloc.o VOBJ013 = $(OBJ)\apply.o VOBJ014 = $(OBJ)\artifact.o VOBJ021 = $(OBJ)\attrib.o VOBJ022 = $(OBJ)\ball.o VOBJ023 = $(OBJ)\bones.o VOBJ024 = $(OBJ)\botl.o VOBJ031 = $(OBJ)\cmd.o VOBJ032 = $(OBJ)\dbridge.o VOBJ033 = $(OBJ)\decl.o VOBJ034 = $(OBJ)\detect.o VOBJ041 = $(OBJ)\dig.o VOBJ042 = $(OBJ)\display.o VOBJ043 = $(OBJ)\dlb.o VOBJ044 = $(OBJ)\do.o VOBJ051 = $(OBJ)\do_name.o VOBJ052 = $(OBJ)\do_wear.o VOBJ053 = $(OBJ)\dog.o VOBJ054 = $(OBJ)\dogmove.o VOBJ061 = $(OBJ)\dokick.o VOBJ062 = $(OBJ)\dothrow.o VOBJ063 = $(OBJ)\drawing.o VOBJ064 = $(OBJ)\dungeon.o VOBJ071 = $(OBJ)\eat.o VOBJ072 = $(OBJ)\end.o VOBJ073 = $(OBJ)\engrave.o VOBJ074 = $(OBJ)\exper.o VOBJ071 = $(OBJ)\eat.o VOBJ072 = $(OBJ)\end.o VOBJ073 = $(OBJ)\engrave.o VOBJ074 = $(OBJ)\exper.o VOBJ081 = $(OBJ)\explode.o VOBJ082 = $(OBJ)\extralev.o VOBJ083 = $(OBJ)\files.o VOBJ084 = $(OBJ)\fountain.o VOBJ091 = $(OBJ)\hack.o VOBJ092 = $(OBJ)\hacklib.o VOBJ093 = $(OBJ)\invent.o VOBJ094 = $(OBJ)\light.o VOBJ101 = $(OBJ)\lock.o VOBJ102 = $(OBJ)\mail.o VOBJ103 = $(OBJ)\main.o VOBJ104 = $(OBJ)\makemon.o VOBJ111 = $(OBJ)\mapglyph.o VOBJ112 = $(OBJ)\mcastu.o VOBJ113 = $(OBJ)\mhitm.o VOBJ114 = $(OBJ)\mhitu.o VOBJ115 = $(OBJ)\minion.o VOBJ121 = $(OBJ)\mklev.o VOBJ122 = $(OBJ)\mkmap.o VOBJ123 = $(OBJ)\mkmaze.o VOBJ124 = $(OBJ)\mkobj.o VOBJ131 = $(OBJ)\mkroom.o VOBJ132 = $(OBJ)\mon.o VOBJ133 = $(OBJ)\mondata.o VOBJ134 = $(OBJ)\monmove.o VOBJ141 = $(OBJ)\monst.o VOBJ142 = $(OBJ)\monstr.o VOBJ143 = $(OBJ)\mplayer.o VOBJ144 = $(OBJ)\mthrowu.o VOBJ151 = $(OBJ)\muse.o VOBJ152 = $(OBJ)\music.o VOBJ153 = $(OBJ)\o_init.o VOBJ154 = $(OBJ)\objects.o VOBJ161 = $(OBJ)\objnam.o VOBJ162 = $(OBJ)\options.o VOBJ163 = $(OBJ)\os2.o VOBJ164 = $(OBJ)\pager.o VOBJ171 = $(OBJ)\pcsys.o VOBJ172 = $(OBJ)\pickup.o VOBJ173 = $(OBJ)\pline.o VOBJ174 = $(OBJ)\polyself.o VOBJ181 = $(OBJ)\potion.o VOBJ182 = $(OBJ)\pray.o VOBJ183 = $(OBJ)\priest.o VOBJ184 = $(OBJ)\quest.o VOBJ191 = $(OBJ)\questpgr.o VOBJ192 = $(OBJ)\read.o VOBJ193 = $(OBJ)\rect.o VOBJ194 = $(OBJ)\region.o VOBJ195 = $(OBJ)\restore.o VOBJ201 = $(OBJ)\rip.o VOBJ202 = $(OBJ)\rnd.o VOBJ203 = $(OBJ)\rumors.o VOBJ204 = $(OBJ)\save.o VOBJ211 = $(OBJ)\shk.o VOBJ212 = $(OBJ)\shknam.o VOBJ213 = $(OBJ)\sit.o VOBJ214 = $(OBJ)\sounds.o VOBJ221 = $(OBJ)\sp_lev.o VOBJ222 = $(OBJ)\spell.o VOBJ223 = $(OBJ)\steal.o VOBJ224 = $(OBJ)\teleport.o VOBJ231 = $(OBJ)\timeout.o VOBJ232 = $(OBJ)\topten.o VOBJ233 = $(OBJ)\track.o VOBJ234 = $(OBJ)\trap.o VOBJ241 = $(OBJ)\tty.o VOBJ242 = $(OBJ)\u_init.o VOBJ243 = $(OBJ)\uhitm.o VOBJ244 = $(OBJ)\unix.o VOBJ251 = $(OBJ)\vault.o VOBJ252 = $(OBJ)\vision.o VOBJ253 = $(OBJ)\vis_tab.o VOBJ254 = $(OBJ)\weapon.o VOBJ261 = $(OBJ)\were.o VOBJ262 = $(OBJ)\wield.o VOBJ263 = $(OBJ)\windows.o VOBJ264 = $(OBJ)\wizard.o VOBJ271 = $(OBJ)\worm.o VOBJ272 = $(OBJ)\worn.o VOBJ273 = $(OBJ)\write.o VOBJ274 = $(OBJ)\zap.o VOBJ281 = $(OBJ)\role.o VOBJ282 = $(OBJ)\steed.o VOBJ01 = $(VOBJ011) $(VOBJ012) $(VOBJ013) $(VOBJ014) VOBJ02 = $(VOBJ021) $(VOBJ022) $(VOBJ023) $(VOBJ024) VOBJ03 = $(VOBJ031) $(VOBJ032) $(VOBJ033) $(VOBJ034) VOBJ04 = $(VOBJ041) $(VOBJ042) $(VOBJ043) $(VOBJ044) VOBJ05 = $(VOBJ051) $(VOBJ052) $(VOBJ053) $(VOBJ054) VOBJ06 = $(VOBJ061) $(VOBJ062) $(VOBJ063) $(VOBJ064) VOBJ07 = $(VOBJ071) $(VOBJ072) $(VOBJ073) $(VOBJ074) VOBJ08 = $(VOBJ081) $(VOBJ082) $(VOBJ083) $(VOBJ084) VOBJ09 = $(VOBJ091) $(VOBJ092) $(VOBJ093) $(VOBJ094) VOBJ10 = $(VOBJ101) $(VOBJ102) $(VOBJ103) $(VOBJ104) VOBJ11 = $(VOBJ111) $(VOBJ112) $(VOBJ113) $(VOBJ114) $(VOBJ115) VOBJ12 = $(VOBJ121) $(VOBJ122) $(VOBJ123) $(VOBJ124) VOBJ13 = $(VOBJ131) $(VOBJ132) $(VOBJ133) $(VOBJ134) VOBJ14 = $(VOBJ141) $(VOBJ142) $(VOBJ143) $(VOBJ144) VOBJ15 = $(VOBJ151) $(VOBJ152) $(VOBJ153) $(VOBJ154) VOBJ16 = $(VOBJ161) $(VOBJ162) $(VOBJ163) $(VOBJ164) VOBJ17 = $(VOBJ171) $(VOBJ172) $(VOBJ173) $(VOBJ174) VOBJ18 = $(VOBJ181) $(VOBJ182) $(VOBJ183) $(VOBJ184) VOBJ19 = $(VOBJ191) $(VOBJ192) $(VOBJ193) $(VOBJ194) $(VOBJ195) VOBJ20 = $(VOBJ201) $(VOBJ202) $(VOBJ203) $(VOBJ204) VOBJ21 = $(VOBJ211) $(VOBJ212) $(VOBJ213) $(VOBJ214) VOBJ22 = $(VOBJ221) $(VOBJ222) $(VOBJ223) $(VOBJ224) VOBJ23 = $(VOBJ231) $(VOBJ232) $(VOBJ233) $(VOBJ234) VOBJ24 = $(VOBJ241) $(VOBJ242) $(VOBJ243) $(VOBJ244) VOBJ25 = $(VOBJ251) $(VOBJ252) $(VOBJ253) $(VOBJ254) VOBJ26 = $(VOBJ261) $(VOBJ262) $(VOBJ263) $(VOBJ264) VOBJ27 = $(VOBJ271) $(VOBJ272) $(VOBJ273) $(VOBJ274) VOBJ28 = $(VOBJ281) $(VOBJ282) VOBJ29 = $(WINOBJ) $(RANDOM) HHOBJ = $(OBJ)\version.o VOBJ = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) $(VOBJ06) $(VOBJ07) \ $(VOBJ08) $(VOBJ09) $(VOBJ10) $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) \ $(VOBJ15) $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) $(VOBJ21) \ $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) $(VOBJ26) $(VOBJ27) $(VOBJ28) \ $(VOBJ29) HOBJ = $(VOBJ) $(HHOBJ) EXTERN_H = # $(INCL)\extern.h OS2CONF_H = $(INCL)\os2conf.h $(INCL)\micro.h $(INCL)\system.h $(EXTERN_H) GLOBAL_H = $(INCL)\global.h $(INCL)\coord.h $(OS2CONF_H) CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h $(GLOBAL_H) TRAP_H = $(INCL)\trap.h PERMONST_H = $(INCL)\permonst.h $(INCL)\monattk.h $(INCL)\monflag.h YOU_H = $(INCL)\you.h $(INCL)\attrib.h $(PERMONST_H) $(INCL)\mondata.h \ $(INCL)\monst.h $(INCL)\youprop.h $(INCL)\prop.h $(INCL)\pm.h DECL_H = $(INCL)\decl.h $(INCL)\spell.h $(INCL)\obj.h $(YOU_H) \ $(INCL)\onames.h $(INCL)\color.h HACK_H = $(CONFIG_H) $(DECL_H) $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(TRAP_H) $(INCL)\engrave.h $(INCL)\flag.h \ $(INCL)\rm.h $(INCL)\dungeon.h $(INCL)\hack.h $(INCL)\display.h \ $(INCL)\vision.h $(INCL)\wintty.h $(INCL)\wintype.h $(INCL)\align.h \ $(INCL)\winprocs.h # # The default target. # all : makedefs dgn_comp lev_comp recover $(GAME) dat $(GUIDE) $(ECHO) Done. # # Definition file creation. # $(TEMP)\$(GAMEDEF) : $(MAKEB) DD_NAME=$(GAME) DD_DESC=$(GAMEDES) DD_TARG=$@ do_def $(TEMP)\$(MKDFDEF) : $(MAKEB) DD_NAME=makedefs DD_DESC="Definitions compiler" DD_TARG=$@ do_def $(TEMP)\$(DGNCDEF) : $(MAKEB) DD_NAME=dgn_comp DD_DESC="Dungeon compiler" DD_TARG=$@ do_def $(TEMP)\$(LEVCDEF) : $(MAKEB) DD_NAME=lev_comp DD_DESC="Level compiler" DD_TARG=$@ do_def $(TEMP)\$(RCVRDEF) : $(MAKEB) DD_NAME=recover DD_DESC="Recovery utility" DD_TARG=$@ do_def $(TEMP)\$(DLBDEF) : $(MAKEB) DD_NAME=dlb DD_DESC="Archive utility" DD_TARG=$@ do_def do_def : $(ECHO) NAME $(DD_NAME) WINDOWCOMPAT> $(DD_TARG) $(ECHO) DESCRIPTION '$(DD_DESC)'>> $(DD_TARG) $(ECHO) PROTMODE>> $(DD_TARG) $(ECHO) EXETYPE OS2>> $(DD_TARG) # # The main target. # $(GAME) : $(GAMEDIR)\$(GAME).exe $(GAME).exe : $(GAMEDIR)\$(GAME).exe $(GAMEDIR)\$(GAME).exe : $(TEMP)\$(GAME).rsp $(TEMP)\$(GAME).r $(GAMELN) $(TEMP)\$(GAME).r : $(HOBJ) $(TEMP)\$(GAMEDEF) $(ECHO) $(VOBJ011) > $@ $(ECHO) $(VOBJ012) >> $@ $(ECHO) $(VOBJ013) >> $@ $(ECHO) $(VOBJ014) >> $@ $(ECHO) $(VOBJ021) >> $@ $(ECHO) $(VOBJ022) >> $@ $(ECHO) $(VOBJ023) >> $@ $(ECHO) $(VOBJ024) >> $@ $(ECHO) $(VOBJ031) >> $@ $(ECHO) $(VOBJ032) >> $@ $(ECHO) $(VOBJ033) >> $@ $(ECHO) $(VOBJ034) >> $@ $(ECHO) $(VOBJ041) >> $@ $(ECHO) $(VOBJ042) >> $@ $(ECHO) $(VOBJ043) >> $@ $(ECHO) $(VOBJ044) >> $@ $(ECHO) $(VOBJ051) >> $@ $(ECHO) $(VOBJ052) >> $@ $(ECHO) $(VOBJ053) >> $@ $(ECHO) $(VOBJ054) >> $@ $(ECHO) $(VOBJ061) >> $@ $(ECHO) $(VOBJ062) >> $@ $(ECHO) $(VOBJ063) >> $@ $(ECHO) $(VOBJ064) >> $@ $(ECHO) $(VOBJ071) >> $@ $(ECHO) $(VOBJ072) >> $@ $(ECHO) $(VOBJ073) >> $@ $(ECHO) $(VOBJ074) >> $@ $(ECHO) $(VOBJ081) >> $@ $(ECHO) $(VOBJ082) >> $@ $(ECHO) $(VOBJ083) >> $@ $(ECHO) $(VOBJ084) >> $@ $(ECHO) $(VOBJ091) >> $@ $(ECHO) $(VOBJ092) >> $@ $(ECHO) $(VOBJ093) >> $@ $(ECHO) $(VOBJ094) >> $@ $(ECHO) $(VOBJ101) >> $@ $(ECHO) $(VOBJ102) >> $@ $(ECHO) $(VOBJ103) >> $@ $(ECHO) $(VOBJ104) >> $@ $(ECHO) $(VOBJ111) >> $@ $(ECHO) $(VOBJ112) >> $@ $(ECHO) $(VOBJ113) >> $@ $(ECHO) $(VOBJ114) >> $@ $(ECHO) $(VOBJ115) >> $@ $(ECHO) $(VOBJ121) >> $@ $(ECHO) $(VOBJ122) >> $@ $(ECHO) $(VOBJ123) >> $@ $(ECHO) $(VOBJ124) >> $@ $(ECHO) $(VOBJ131) >> $@ $(ECHO) $(VOBJ132) >> $@ $(ECHO) $(VOBJ133) >> $@ $(ECHO) $(VOBJ134) >> $@ $(ECHO) $(VOBJ141) >> $@ $(ECHO) $(VOBJ142) >> $@ $(ECHO) $(VOBJ143) >> $@ $(ECHO) $(VOBJ144) >> $@ $(ECHO) $(VOBJ151) >> $@ $(ECHO) $(VOBJ152) >> $@ $(ECHO) $(VOBJ153) >> $@ $(ECHO) $(VOBJ154) >> $@ $(ECHO) $(VOBJ161) >> $@ $(ECHO) $(VOBJ162) >> $@ $(ECHO) $(VOBJ163) >> $@ $(ECHO) $(VOBJ164) >> $@ $(ECHO) $(VOBJ171) >> $@ $(ECHO) $(VOBJ172) >> $@ $(ECHO) $(VOBJ173) >> $@ $(ECHO) $(VOBJ174) >> $@ $(ECHO) $(VOBJ181) >> $@ $(ECHO) $(VOBJ182) >> $@ $(ECHO) $(VOBJ183) >> $@ $(ECHO) $(VOBJ184) >> $@ $(ECHO) $(VOBJ191) >> $@ $(ECHO) $(VOBJ192) >> $@ $(ECHO) $(VOBJ193) >> $@ $(ECHO) $(VOBJ194) >> $@ $(ECHO) $(VOBJ195) >> $@ $(ECHO) $(VOBJ201) >> $@ $(ECHO) $(VOBJ202) >> $@ $(ECHO) $(VOBJ203) >> $@ $(ECHO) $(VOBJ204) >> $@ $(ECHO) $(VOBJ211) >> $@ $(ECHO) $(VOBJ212) >> $@ $(ECHO) $(VOBJ213) >> $@ $(ECHO) $(VOBJ214) >> $@ $(ECHO) $(VOBJ221) >> $@ $(ECHO) $(VOBJ222) >> $@ $(ECHO) $(VOBJ223) >> $@ $(ECHO) $(VOBJ224) >> $@ $(ECHO) $(VOBJ231) >> $@ $(ECHO) $(VOBJ232) >> $@ $(ECHO) $(VOBJ233) >> $@ $(ECHO) $(VOBJ234) >> $@ $(ECHO) $(VOBJ241) >> $@ $(ECHO) $(VOBJ242) >> $@ $(ECHO) $(VOBJ243) >> $@ $(ECHO) $(VOBJ244) >> $@ $(ECHO) $(VOBJ251) >> $@ $(ECHO) $(VOBJ252) >> $@ $(ECHO) $(VOBJ253) >> $@ $(ECHO) $(VOBJ254) >> $@ $(ECHO) $(VOBJ261) >> $@ $(ECHO) $(VOBJ262) >> $@ $(ECHO) $(VOBJ263) >> $@ $(ECHO) $(VOBJ264) >> $@ $(ECHO) $(VOBJ271) >> $@ $(ECHO) $(VOBJ272) >> $@ $(ECHO) $(VOBJ273) >> $@ $(ECHO) $(VOBJ274) >> $@ $(ECHO) $(VOBJ281) >> $@ $(ECHO) $(VOBJ282) >> $@ $(ECHO) $(WINOBJ1) >> $@ $(ECHO) $(WINOBJ2) >> $@ $(ECHO) $(WINOBJ3) >> $@ $(ECHO) $(WINOBJ4) >> $@ $(ECHO) $(HHOBJ) >> $@ $(ECHO) $(RANDOM) >> $@ .IF $(with_x11) == yes $(X11ECHO) $(WINX11OBJ01) >> $@ $(X11ECHO) $(WINX11OBJ02) >> $@ $(X11ECHO) $(WINX11OBJ03) >> $@ $(X11ECHO) $(WINX11OBJ04) >> $@ $(X11ECHO) $(WINX11OBJ05) >> $@ $(X11ECHO) $(WINX11OBJ06) >> $@ $(X11ECHO) $(WINX11OBJ07) >> $@ $(X11ECHO) $(WINX11OBJ08) >> $@ $(X11ECHO) $(WINX11OBJ09) >> $@ $(X11ECHO) $(WINX11OBJ10) >> $@ $(X11ECHO) $(WINX11OBJ11) >> $@ .END $(TEMP)\$(GAME).rsp : $(HOBJ) $(TEMP)\$(GAMEDEF) $(ECHO) $(SYSOBJ) $(VOBJ01) +> $@ $(ECHO) $(VOBJ02) +>> $@ $(ECHO) $(VOBJ03) +>> $@ $(ECHO) $(VOBJ04) +>> $@ $(ECHO) $(VOBJ05) +>> $@ $(ECHO) $(VOBJ06) +>> $@ $(ECHO) $(VOBJ07) +>> $@ $(ECHO) $(VOBJ08) +>> $@ $(ECHO) $(VOBJ09) +>> $@ $(ECHO) $(VOBJ10) +>> $@ $(ECHO) $(VOBJ11) +>> $@ $(ECHO) $(VOBJ12) +>> $@ $(ECHO) $(VOBJ13) +>> $@ $(ECHO) $(VOBJ14) +>> $@ $(ECHO) $(VOBJ15) +>> $@ $(ECHO) $(VOBJ16) +>> $@ $(ECHO) $(VOBJ17) +>> $@ $(ECHO) $(VOBJ18) +>> $@ $(ECHO) $(VOBJ19) +>> $@ $(ECHO) $(VOBJ20) +>> $@ $(ECHO) $(VOBJ21) +>> $@ $(ECHO) $(VOBJ22) +>> $@ $(ECHO) $(VOBJ23) +>> $@ $(ECHO) $(VOBJ24) +>> $@ $(ECHO) $(VOBJ25) +>> $@ $(ECHO) $(VOBJ26) +>> $@ $(ECHO) $(VOBJ27) +>> $@ $(ECHO) $(VOBJ28) +>> $@ $(ECHO) $(VOBJ29) +>> $@ $(ECHO) $(VOBJ30) +>> $@ $(ECHO) $(HHOBJ)>> $@ $(ECHO) $(GAMEDIR)\$(GAME).exe>> $@ $(ECHO) $(TEMP)\$(GAME)>> $@ $(ECHO) $(PLIBS) $(TERMLIB)>> $@ $(ECHO) $(TEMP)\$(GAMEDEF) $(LFLAGS);>> $@ # # Targets for makedefs. # makedefs : $(TEMP)\makedefs.exe $(TEMP)\makedefs.exe : $(TEMP)\makedefs.rsp $(MKDFLN) $(TEMP)\makedefs.rsp : $(MAKEOBJS) $(TEMP)\$(MKDFDEF) $(ECHO) $(SYSOBJ) $(MAKEOBJS)> $@ $(ECHO) $(TEMP)\makedefs.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(RLIBS)>> $@ $(ECHO) $(MKDFMD) $(LFLAGS);>> $@ $(OBJ)\makedefs.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\permonst.h $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\artilist.h $(INCL)\qtext.h $(UTILCC) # # Targets for the special levels compiler. # lev_comp : $(TEMP)\lev_comp.exe $(TEMP)\lev_comp.exe : $(TEMP)\lev_comp.rsp $(LEVCLN) $(TEMP)\lev_comp.rsp : $(SPLEVOBJS) $(TEMP)\$(LEVCDEF) $(ECHO) $(SYSOBJ) $(SOBJ01) +> $@ $(ECHO) $(SOBJ02) +>> $@ $(ECHO) $(SOBJ03)>> $@ $(ECHO) $(TEMP)\lev_comp.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(RLIBS)>> $@ $(ECHO) $(LEVCMD) $(LFLAGS);>> $@ $(OBJ)\lev_yacc.o : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(UTILCC) $(OBJ)\lev_lex.o : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev_comp.h $(UTILCC) $(OBJ)\lev_main.o : $(UTIL)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\tcap.h $(UTILCC) $(UTIL)\lev_yacc.c : $(UTIL)\lev_comp.y $(MAKEB) YY=lev do_yacc $(UTIL)\lev_lex.c : $(UTIL)\lev_comp.l $(MAKEB) YY=lev do_lex # # Targets for the dungeon compiler. # dgn_comp : $(TEMP)\dgn_comp.exe $(TEMP)\dgn_comp.exe : $(TEMP)\dgn_comp.rsp $(DGNCLN) $(TEMP)\dgn_comp.rsp : $(DGNCOMPOBJS) $(TEMP)\$(DGNCDEF) $(ECHO) $(SYSOBJ) $(DOBJ01) +> $@ $(ECHO) $(DOBJ02)>> $@ $(ECHO) $(TEMP)\dgn_comp.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(RLIBS)>> $@ $(ECHO) $(DGNCMD) $(LFLAGS);>> $@ $(OBJ)\dgn_yacc.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\date.h $(INCL)\dgn_file.h $(UTILCC) $(OBJ)\dgn_lex.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\dgn_comp.h $(INCL)\dgn_file.h $(UTILCC) $(OBJ)\dgn_main.o : $(UTIL)\$(CB) $(CONFIG_H) $(UTILCC) $(UTIL)\dgn_yacc.c : $(UTIL)\dgn_comp.y $(MAKEB) YY=dgn do_yacc $(UTIL)\dgn_lex.c : $(UTIL)\dgn_comp.l $(MAKEB) YY=dgn do_lex # # For both lev_comp and dgn_comp. # $(OBJ)\panic.o : $(UTIL)\$(CB) $(CONFIG_H) $(UTILCC) # # Yacc and Lex targets. # yacc_cpy : $(CP) $(SSYS)\$(YY)_yacc.c $(UTIL) $(CP) $(SSYS)\$(YY)_comp.h $(INCL) $(MAKEB) TT=$(UTIL)\$(YY)_yacc.c do_touch $(MAKEB) TT=$(INCL)\$(YY)_comp.h do_touch yacc_msg : $(ECHO) $(YY)_comp.y has changed. To update $(YY)_yacc.c and $(YY)_comp.h run $(YACC). yacc_act : $(YACC) -d $(UTIL)\$(YY)_comp.y $(CP) $(YTABC) $(UTIL)\$(YY)_yacc.c $(CP) $(YTABH) $(INCL)\$(YY)_comp.h $(RM) $(YTABC) $(RM) $(YTABH) lex_cpy : $(CP) $(SSYS)\$(YY)_lex.c $(UTIL) $(MAKEB) TT=$(UTIL)\$(YY)_lex.c do_touch lex_msg : $(ECHO) $(YY)_comp.l has changed. To update $(YY)_lex.c run $(LEX). lex_act : $(LEX) $(UTIL)\$(YY)_comp.l $(CP) $(LEXYYC) $(UTIL)\$(YY)_lex.c $(RM) $(LEXYYC) # # Why must this be so kludgy? # realtouch : $(TOUCH) $(TT) faketouch : $(BEG) $(CAT) $(TT) > $(TEMP)\foo.bar $(SEP) $(CP) $(TEMP)\foo.bar $(TT) $(SEP) $(RM) $(TEMP)\foo.bar $(END) # # Targets for the recovery utility. # recover : $(GAMEDIR)\recover.exe $(GAMEDIR)\recover.exe : $(TEMP)\recover.rsp $(RCVRLN) $(TEMP)\recover.rsp : $(RECOVOBJS) $(TEMP)\$(RCVRDEF) $(ECHO) $(SYSOBJ) $(RECOVOBJS)> $@ $(ECHO) $(GAMEDIR)\recover.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(PLIBS)>> $@ $(ECHO) $(TEMP)\$(RCVRDEF) $(LFLAGS);>> $@ $(OBJ)\recover.o : $(UTIL)\$(CB) $(CONFIG_H) $(UTILCC) # # Targets for the dlb. # dlb : $(TEMP)\dlb.exe $(TEMP)\dlb.exe : $(TEMP)\dlb.rsp $(DLBRLN) $(TEMP)\dlb.rsp : $(DLBOBJS) $(TEMP)\$(DLBDEF) $(ECHO) $(SYSOBJ) $(DLBOBJS)> $@ $(ECHO) $(TEMP)\dlb.exe>> $@ $(ECHO) nul>> $@ $(ECHO) $(PLIBS)>> $@ $(ECHO) $(TEMP)\$(DLBDEF) $(LFLAGS);>> $@ $(OBJ)\dlb_main.o : $(UTIL)\$(CB) $(CONFIG_H) $(INCL)\dlb.h $(UTILCC) $(GAMEDIR)\nhdat : $(WINX11VARDAT) $(MAKEB) do_dlb dlb_yup : dlb $(TEMP)\dlb cCf $(GAMEDIR) $(GAMEDIR)\nhdat $(DATDLB) -$(RM) $(GAMEDIR)\help -$(RM) $(GAMEDIR)\hh -$(RM) $(GAMEDIR)\cmdhelp -$(RM) $(GAMEDIR)\history -$(RM) $(GAMEDIR)\opthelp -$(RM) $(GAMEDIR)\wizhelp -$(RM) $(GAMEDIR)\asmodeus.lev -$(RM) $(GAMEDIR)\baalz.lev -$(RM) $(GAMEDIR)\bigrm-?.lev -$(RM) $(GAMEDIR)\castle.lev -$(RM) $(GAMEDIR)\fakewiz?.lev -$(RM) $(GAMEDIR)\juiblex.lev -$(RM) $(GAMEDIR)\knox.lev -$(RM) $(GAMEDIR)\medusa-?.lev -$(RM) $(GAMEDIR)\minend-?.lev -$(RM) $(GAMEDIR)\minefill.lev -$(RM) $(GAMEDIR)\minetn-?.lev -$(RM) $(GAMEDIR)\oracle.lev -$(RM) $(GAMEDIR)\orcus.lev -$(RM) $(GAMEDIR)\sanctum.lev -$(RM) $(GAMEDIR)\tower?.lev -$(RM) $(GAMEDIR)\valley.lev -$(RM) $(GAMEDIR)\wizard?.lev -$(RM) $(GAMEDIR)\astral.lev -$(RM) $(GAMEDIR)\air.lev -$(RM) $(GAMEDIR)\earth.lev -$(RM) $(GAMEDIR)\fire.lev -$(RM) $(GAMEDIR)\water.lev -$(RM) $(GAMEDIR)\???-goal.lev -$(RM) $(GAMEDIR)\???-fil?.lev -$(RM) $(GAMEDIR)\???-loca.lev -$(RM) $(GAMEDIR)\???-strt.lev -$(RM) $(GAMEDIR)\data -$(RM) $(GAMEDIR)\oracles -$(RM) $(GAMEDIR)\options -$(RM) $(GAMEDIR)\quest.dat -$(RM) $(GAMEDIR)\rumors -$(RM) $(GAMEDIR)\dungeon -$(RM) $(GAMEDIR)\soko?-?.lev # -$(RM) $(GAMEDIR)\pet_mark.xbm # -$(RM) $(GAMEDIR)\rip.xpm dlb_nope : $(ECHO) DLB not requested. # # The following files depend on makedefs to be created. # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h : $(VOBJ) $(TEMP)\makedefs.exe $(TEMP)\makedefs -v $(CP) $(DAT)\options $(GAMEDIR) $(RM) $(DAT)\options $(INCL)\onames.h : $(TEMP)\makedefs.exe $(TEMP)\makedefs -o $(INCL)\pm.h : $(TEMP)\makedefs.exe $(TEMP)\makedefs -p monstr.c : $(TEMP)\makedefs.exe $(TEMP)\makedefs -m $(OBJ)\monstr.o : $(CB) $(SRCCC) $(GAMEDIR)\data : $(DAT)\$(DATABASE) $(TEMP)\makedefs.exe $(TEMP)\makedefs -d $(CP) $(DAT)\data $(GAMEDIR) $(RM) $(DAT)\data $(GAMEDIR)\rumors : $(DAT)\rumors.tru $(DAT)\rumors.fal $(TEMP)\makedefs.exe $(TEMP)\makedefs -r $(CP) $(DAT)\rumors $(GAMEDIR) $(RM) $(DAT)\rumors $(GAMEDIR)\oracles : $(DAT)\oracles.txt $(TEMP)\makedefs.exe $(TEMP)\makedefs -h $(CP) $(DAT)\oracles $(GAMEDIR) $(RM) $(DAT)\oracles $(GAMEDIR)\quest.dat : $(DAT)\quest.txt $(TEMP)\makedefs.exe $(TEMP)\makedefs -q $(CP) $(DAT)\quest.dat $(GAMEDIR) $(RM) $(DAT)\quest.dat # # Vision tables for algorithm D. # vis_tab.c : $(INCL)\vis_tab.h $(INCL)\vis_tab.h : $(TEMP)\makedefs.exe $(TEMP)\makedefs -z $(OBJ)\vis_tab.o : $(CB) $(SRCCC) # # The following programs vary depending on what OS you are using. # $(OBJ)\main.o : $(SSYS)\pc$(CB) $(HACK_H) $(INCL)\dlb.h $(PSYSCC) $(OBJ)\tty.o : $(SSYS)\pc$(CB) $(HACK_H) $(INCL)\func_tab.h $(PSYSCC) $(OBJ)\unix.o : $(SSYS)\pc$(CB) $(HACK_H) $(PSYSCC) # # Other system specific modules. # $(OBJ)\os2.o : $(SYS)\$(CB) $(HACK_H) $(INCL)\tcap.h $(INCL)\def_os2.h $(SYSCC) $(OBJ)\pcsys.o : $(SSYS)\$(CB) $(HACK_H) $(SSYSCC) # # Berkeley random(3) routines. # $(OBJ)\random.o : $(SSYS)\$(CB) $(SSYSCC) # # Window source. # $(OBJ)\getline.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\func_tab.h $(WINCC) $(OBJ)\termcap.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h $(WINCC) $(OBJ)\topl.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h $(WINCC) $(OBJ)\wintty.o : $(WIN)\$(CB) $(HACK_H) $(INCL)\tcap.h $(WINCC) # # Secondary targets. # dat : spec_lev help_fil $(GAMEDIR)\dungeon $(GAMEDIR)\data $(GAMEDIR)\rumors \ $(GAMEDIR)\oracles $(GAMEDIR)\quest.dat $(GAMEDIR)\$(GAME).ico \ $(GAMEDIR)\$(GAME).cmd $(GAMEDIR)\nethack.cnf $(GAMEDIR)\nhdat \ $(WINX11VARDAT) help_fil : $(GAMEDIR)\cmdhelp $(GAMEDIR)\help $(GAMEDIR)\hh $(GAMEDIR)\history \ $(GAMEDIR)\license $(GAMEDIR)\opthelp $(GAMEDIR)\wizhelp $(GAMEDIR)\cmdhelp : $(DAT)\cmdhelp $(CP) $(DAT)\cmdhelp $(GAMEDIR) $(GAMEDIR)\help : $(DAT)\help $(CP) $(DAT)\help $(GAMEDIR) $(GAMEDIR)\hh : $(DAT)\hh $(CP) $(DAT)\hh $(GAMEDIR) $(GAMEDIR)\history : $(DAT)\history $(CP) $(DAT)\history $(GAMEDIR) $(GAMEDIR)\license : $(DAT)\license $(CP) $(DAT)\license $(GAMEDIR) $(GAMEDIR)\opthelp : $(DAT)\opthelp $(CP) $(DAT)\opthelp $(GAMEDIR) $(GAMEDIR)\wizhelp : $(DAT)\wizhelp $(CP) $(DAT)\wizhelp $(GAMEDIR) $(GAMEDIR)\dungeon : $(DAT)\dungeon.def $(TEMP)\makedefs.exe $(TEMP)\dgn_comp.exe $(TEMP)\makedefs -e $(TEMP)\dgn_comp $(DAT)\dungeon.pdf $(CP) $(DAT)\dungeon $(GAMEDIR) $(RM) $(DAT)\dungeon.pdf $(RM) $(DAT)\dungeon AFILES = $(GAMEDIR)\Arc-goal.lev BFILES = $(GAMEDIR)\Bar-goal.lev CFILES = $(GAMEDIR)\Cav-goal.lev HFILES = $(GAMEDIR)\Hea-goal.lev KFILES = $(GAMEDIR)\Kni-goal.lev MFILES = $(GAMEDIR)\Mon-goal.lev PFILES = $(GAMEDIR)\Pri-goal.lev RANFILES = $(GAMEDIR)\Ran-goal.lev RFILES = $(GAMEDIR)\Rog-goal.lev SFILES = $(GAMEDIR)\Sam-goal.lev TFILES = $(GAMEDIR)\Tou-goal.lev VFILES = $(GAMEDIR)\Val-goal.lev WFILES = $(GAMEDIR)\Wiz-goal.lev XFILES = $(AFILES) $(BFILES) $(CFILES) $(HFILES) $(KFILES) $(MFILES) \ $(PFILES) $(RANFILES) $(RFILES) $(SFILES) $(TFILES) $(VFILES) $(WFILES) spec_lev : $(GAMEDIR)\astral.lev $(GAMEDIR)\bigrm-1.lev $(GAMEDIR)\castle.lev \ $(GAMEDIR)\knox.lev $(GAMEDIR)\medusa-1.lev $(GAMEDIR)\minefill.lev \ $(GAMEDIR)\oracle.lev $(GAMEDIR)\tower1.lev $(GAMEDIR)\valley.lev \ $(GAMEDIR)\wizard1.lev $(GAMEDIR)\soko1-1.lev $(XFILES) # Single special level files $(GAMEDIR)\castle.lev : $(DAT)\castle.des $(TEMP)\lev_comp.exe $(MAKEB) LF=castle do_slev $(GAMEDIR)\knox.lev : $(DAT)\knox.des $(TEMP)\lev_comp.exe $(MAKEB) LF=knox do_slev $(GAMEDIR)\oracle.lev : $(DAT)\oracle.des $(TEMP)\lev_comp.exe $(MAKEB) LF=oracle do_slev do_slev : $(TEMP)\lev_comp $(DAT)\$(LF).des $(CP) $(LF).lev $(GAMEDIR) $(RM) $(LF).lev # Multiple special level files $(GAMEDIR)\astral.lev : $(DAT)\endgame.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\endgame.des $(CP) air.lev $(GAMEDIR) $(CP) astral.lev $(GAMEDIR) $(CP) earth.lev $(GAMEDIR) $(CP) fire.lev $(GAMEDIR) $(CP) water.lev $(GAMEDIR) $(RM) air.lev $(RM) astral.lev $(RM) earth.lev $(RM) fire.lev $(RM) water.lev $(GAMEDIR)\bigrm-1.lev : $(DAT)\bigroom.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\bigroom.des $(CP) bigrm-?.lev $(GAMEDIR) $(RM) bigrm-?.lev $(GAMEDIR)\medusa-1.lev : $(DAT)\medusa.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\medusa.des $(CP) medusa-?.lev $(GAMEDIR) $(RM) medusa-?.lev $(GAMEDIR)\minefill.lev : $(DAT)\mines.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\mines.des $(CP) minend-?.lev $(GAMEDIR) $(CP) minefill.lev $(GAMEDIR) $(CP) minetn-?.lev $(GAMEDIR) $(RM) minend-?.lev $(RM) minefill.lev $(RM) minetn-?.lev $(GAMEDIR)\tower1.lev : $(DAT)\tower.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\tower.des $(CP) tower?.lev $(GAMEDIR) $(RM) tower?.lev $(GAMEDIR)\valley.lev : $(DAT)\gehennom.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\gehennom.des $(CP) asmodeus.lev $(GAMEDIR) $(CP) baalz.lev $(GAMEDIR) $(CP) juiblex.lev $(GAMEDIR) $(CP) orcus.lev $(GAMEDIR) $(CP) sanctum.lev $(GAMEDIR) $(CP) valley.lev $(GAMEDIR) $(RM) asmodeus.lev $(RM) baalz.lev $(RM) juiblex.lev $(RM) orcus.lev $(RM) sanctum.lev $(RM) valley.lev $(GAMEDIR)\wizard1.lev : $(DAT)\yendor.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\yendor.des $(CP) wizard?.lev $(GAMEDIR) $(CP) fakewiz?.lev $(GAMEDIR) $(RM) wizard?.lev $(RM) fakewiz?.lev $(GAMEDIR)\soko1-1.lev : $(DAT)\sokoban.des $(TEMP)\lev_comp.exe $(TEMP)\lev_comp $(DAT)\sokoban.des $(CP) soko?-?.lev $(GAMEDIR) $(RM) soko?-?.lev # Quest dungeons $(AFILES) : $(DAT)\Arch.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Arc QF=Arch do_quest $(BFILES) : $(DAT)\Barb.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Bar QF=Barb do_quest $(CFILES) : $(DAT)\Caveman.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Cav QF=Caveman do_quest $(HFILES) : $(DAT)\Healer.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Hea QF=Healer do_quest $(KFILES) : $(DAT)\Knight.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Kni QF=Knight do_quest $(MFILES) : $(DAT)\Monk.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Mon QF=Monk do_quest $(PFILES) : $(DAT)\Priest.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Pri QF=Priest do_quest $(RANFILES) : $(DAT)\Ranger.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Ran QF=Ranger do_quest $(RFILES) : $(DAT)\Rogue.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Rog QF=Rogue do_quest $(SFILES) : $(DAT)\Samurai.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Sam QF=Samurai do_quest $(TFILES) : $(DAT)\Tourist.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Tou QF=Tourist do_quest $(VFILES) : $(DAT)\Valkyrie.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Val QF=Valkyrie do_quest $(WFILES) : $(DAT)\Wizard.des $(TEMP)\lev_comp.exe $(MAKEB) QQ=Wiz QF=Wizard do_quest do_quest : $(TEMP)\lev_comp $(DAT)\$(QF).des $(CP) $(QQ)-fil?.lev $(GAMEDIR) $(CP) $(QQ)-goal.lev $(GAMEDIR) $(CP) $(QQ)-loca.lev $(GAMEDIR) $(CP) $(QQ)-strt.lev $(GAMEDIR) $(RM) $(QQ)-fil?.lev $(RM) $(QQ)-goal.lev $(RM) $(QQ)-loca.lev $(RM) $(QQ)-strt.lev # # NetHack icon for Presentation Manager. # $(GAMEDIR)\$(GAME).ico : $(SYS)\nhpmico.uu $(MAKEB) do_icon icon_msg : $(ECHO) Icon file not extracted. Extract manually if required. icon_act : $(UUDECODE) $(SYS)\nhpmico.uu $(CP) nethack.ico $(GAMEDIR)\$(GAME).ico $(RM) nethack.ico # # NetHack command file to use with Presentation Manager. # $(GAMEDIR)\$(GAME).cmd : $(MAKEB) CMDF=$@ do_cmd cmd_msg : $(ECHO) Command file not created. Create manually if required. cmd_act : $(ECHO) @echo off> $(CMDF) $(ECHO) REM Command file for starting nethack.exe from PM/WPS Desktop>> $(CMDF) $(ECHO) $(GAME).exe $(P)1 $(P)2 $(P)3 $(P)4 $(P)5 $(P)6 $(P)7>> $(CMDF) $(ECHO) pause>> $(CMDF) # # NetHack configuration file. Will not overwrite an existing file. # $(GAMEDIR)\nethack.cnf : $(CP) $(SSYS)\nethack.cnf $(GAMEDIR) # # Documentation. # $(TEMP)\$(GUIDEBOO).dvi : $(DOC)\$(GUIDEBOO).tex $(LATEX) $(DOC)\$(GUIDEBOO).tex $(CP) $(GUIDEBOO).dvi $(TEMP) $(CP) $(GUIDEBOO).aux $(TEMP) $(CP) $(GUIDEBOO).log $(TEMP) $(RM) $(GUIDEBOO).dvi $(RM) $(GUIDEBOO).aux $(RM) $(GUIDEBOO).log # # Housekeeping. # clean : -$(RM) $(OBJ)\*.o spotless : clean -$(RM) $(INCL)\date.h -$(RM) $(INCL)\onames.h -$(RM) $(INCL)\pm.h -$(RM) $(INCL)\vis_tab.h -$(RM) vis_tab.c -$(RM) monstr.c -$(RM) *.lev -$(RM) nethack.ico -$(RM) $(TEMP)\makedefs.exe -$(RM) $(TEMP)\lev_comp.exe -$(RM) $(TEMP)\dgn_comp.exe -$(RM) $(TEMP)\*.rsp -$(RM) $(TEMP)\*.def -$(RM) $(TEMP)\*.map -$(RM) $(TEMP)\$(GUIDEBOO).dvi -$(RM) $(TEMP)\$(GUIDEBOO).aux -$(RM) $(TEMP)\$(GUIDEBOO).log # # Main source. # # Default rules are sooo difficult for so many make # programs that we do this the most straightforward way. # $(OBJ)\allmain.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\alloc.o : $(SRC)\$(CB) $(CONFIG_H) $(SRCCC) $(OBJ)\apply.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\edog.h $(SRCCC) $(OBJ)\artifact.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h $(SRCCC) $(OBJ)\attrib.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\ball.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\bones.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\botl.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\cmd.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\func_tab.h $(SRCCC) $(OBJ)\dbridge.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\decl.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\quest.h $(SRCCC) $(OBJ)\detect.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\dig.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\display.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\dlb.o : $(SRC)\$(CB) $(CONFIG_H) $(INCL)\dlb.h $(SRCCC) $(OBJ)\do.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\do_name.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\do_wear.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\dog.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\edog.h $(SRCCC) $(OBJ)\dogmove.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h $(SRCCC) $(OBJ)\dokick.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h $(SRCCC) $(OBJ)\dothrow.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\drawing.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\tcap.h $(SRCCC) $(OBJ)\dungeon.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\dgn_file.h $(SRCCC) $(OBJ)\eat.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\end.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h $(SRCCC) $(OBJ)\engrave.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\exper.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\explode.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\extralev.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\files.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\fountain.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\hack.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\hacklib.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\invent.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\light.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\lock.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mail.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mail.h $(SRCCC) $(OBJ)\makemon.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h $(SRCCC) $(OBJ)\mapglyph.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mcastu.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mhitm.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h $(SRCCC) $(OBJ)\mhitu.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h $(SRCCC) $(OBJ)\minion.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h $(SRCCC) $(OBJ)\mklev.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mkmap.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(SRCCC) $(OBJ)\mkmaze.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(SRCCC) $(OBJ)\mkobj.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\mkroom.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mon.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h $(SRCCC) $(OBJ)\mondata.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h $(SRCCC) $(OBJ)\monmove.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h $(SRCCC) $(OBJ)\monst.o : $(SRC)\$(CB) $(CONFIG_H) $(PERMONST_H) $(INCL)\monsym.h $(INCL)\eshk.h $(INCL)\vault.h $(INCL)\epri.h $(INCL)\color.h $(SRCCC) $(OBJ)\mplayer.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\mthrowu.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\muse.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\edog.h $(SRCCC) $(OBJ)\music.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\o_init.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\objects.o : $(SRC)\$(CB) $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h $(INCL)\prop.h $(INCL)\color.h $(SRCCC) $(OBJ)\objnam.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\options.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\tcap.h $(SRCCC) $(OBJ)\pager.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\pickup.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\pline.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\epri.h $(SRCCC) $(OBJ)\polyself.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\potion.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\pray.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\epri.h $(SRCCC) $(OBJ)\priest.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h $(INCL)\epri.h $(INCL)\emin.h $(SRCCC) $(OBJ)\quest.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\quest.h $(INCL)\qtext.h $(SRCCC) $(OBJ)\questpgr.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\qtext.h $(SRCCC) $(OBJ)\read.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\region.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\rect.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\restore.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h $(INCL)\quest.h $(SRCCC) $(OBJ)\rip.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\rnd.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\role.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\rumors.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\save.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(INCL)\quest.h $(SRCCC) $(OBJ)\shk.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h $(SRCCC) $(OBJ)\shknam.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\eshk.h $(SRCCC) $(OBJ)\sit.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\artifact.h $(SRCCC) $(OBJ)\sounds.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\edog.h $(INCL)\eshk.h $(SRCCC) $(OBJ)\sp_lev.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\sp_lev.h $(INCL)\rect.h $(SRCCC) $(OBJ)\spell.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\steal.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\steed.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\teleport.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\timeout.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\topten.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\track.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\trap.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\u_init.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\uhitm.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\vault.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\vault.h $(SRCCC) $(OBJ)\version.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\date.h $(INCL)\$(PATCHLEV).h $(SRCCC) $(OBJ)\vision.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\vis_tab.h $(SRCCC) $(OBJ)\weapon.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\were.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\wield.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\windows.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\wizard.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\qtext.h $(SRCCC) $(OBJ)\worm.o : $(SRC)\$(CB) $(HACK_H) $(INCL)\lev.h $(SRCCC) $(OBJ)\worn.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\write.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)\zap.o : $(SRC)\$(CB) $(HACK_H) $(SRCCC) $(OBJ)/Window.o: $(WINX11)\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ $(CONFIG_H) $(CC) -o$(OBJ)\Window.o $(CFLAGS) -c $(WINX11)\Window.c $(OBJ)/dialogs.o: $(WINX11)\dialogs.c $(CONFIG_H) $(CC) -o$(OBJ)\dialogs.o $(CFLAGS) -c $(WINX11)\dialogs.c $(OBJ)/winX.o: $(WINX11)\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(WINX11)\nh72icon \ $(WINX11)\nh56icon $(WINX11)\nh32icon $(CC) $(CFLAGS) -c $(WINX11)\winX.c -o$(OBJ)\winX.o $(OBJ)/winmap.o: $(WINX11)\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ $(INCL)\winX.h $(INCL)\tile2x11.h $(CC) $(CFLAGS) -c $(WINX11)\winmap.c -o $(OBJ)\winmap.o $(OBJ)/winmenu.o: $(WINX11)\winmenu.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winmenu.c -o $(OBJ)\winmenu.o $(OBJ)/winmesg.o: $(WINX11)\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winmesg.c -o$(OBJ)\winmesg.o $(OBJ)/winmisc.o: $(WINX11)\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winmisc.c -o$(OBJ)\winmisc.o $(OBJ)/winstat.o: $(WINX11)\winstat.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winstat.c -o$(OBJ)\winstat.o $(OBJ)/wintext.o: $(WINX11)\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h $(CC) $(CFLAGS) -c $(WINX11)\wintext.c -o$(OBJ)\wintext.o $(OBJ)/winval.o: $(WINX11)\winval.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGS) -c $(WINX11)\winval.c -o$(OBJ)\winval.o $(OBJ)/tile.o: $(NHSRC)\src\tile.c $(HACK_H) $(CC) $(CFLAGS) -c $(NHSRC)\src\tile.c -o$(OBJ)\tile.o $(TEMP)\tilemap.exe: ..\win\share\tilemap.c $(HACK_H) $(CC) $(GCCO) $(WARN) -I$(INCL) $(CDFLAGS) $(STDC) $(WINX11CFLAGS) $(LFLAGS) -o $(TEMP)\tilemap.exe ..\win\share\tilemap.c $(LIBS) $(NHSRC)\src\tile.c: $(TEMP)\tilemap.exe $(TEMP)\tilemap x11tiles: $(TEMP)\tile2x11.exe $(WINSHARE)\monsters.txt \ $(WINSHARE)\objects.txt \ $(WINSHARE)\other.txt $(TEMP)\tile2x11.exe $(WINSHARE)\monsters.txt $(WINSHARE)\objects.txt \ $(WINSHARE)\other.txt $(CP) x11tiles $(GAMEDIR)\x11tiles TEXT_IO = $(OBJ)\tiletext.o \ $(OBJ)\tiletxt.o \ $(OBJ)\drawing.o \ $(OBJ)\decl.o \ $(OBJ)\monst.o \ $(OBJ)\objects.o $(OBJ)\tiletext.o: ../win/share/tiletext.c $(CONFIG_H) $(WINSHARE)\tile.h $(CC) $(CFLAGS) -c $(WINSHARE)\tiletext.c -o$(OBJ)\tiletext.o $(OBJ)\tiletxt.o: $(WINSHARE)\tilemap.c $(HACK_H) $(CC) $(CFLAGS) -c -DTILETEXT $(WINSHARE)\tilemap.c -o$(OBJ)\tiletxt.o $(TEMP)\tile2x11.exe: $(OBJ)\tile2x11.o $(TEXT_IO) $(CC) $(LFLAGS) -o $(TEMP)\tile2x11.exe $(OBJ)\tile2x11.o $(TEXT_IO) $(LIBS) pet_mark.xbm: $(WINX11)\pet_mark.xbm $(CP) $(WINX11)\pet_mark.xbm $(GAMEDIR)\pet_mark.xbm rip.xpm: $(WINX11)\rip.xpm $(CP) $(WINX11)\rip.xpm $(GAMEDIR)\rip.xpm $(OBJ)\tile2x11.o : $(WINX11)\tile2x11.c $(INCL)\tile2x11.h $(CC) $(CFLAGS) -o$(OBJ)\tile2x11.o -c $(WINX11)\tile2x11.c \ -I$(WINSHARE) nethack-3.4.3/sys/os2/nhpmico.uu0100644000000000000000000000237107764735041015206 0ustar rootrootbegin 644 nethack.ico M0D$H``````````````!#21H`````````>`````P````@`$```0`!`````/___ M_T-)&@````````!X`0``#````"``(``!``0```````"``(```("`@```@`"`L M@(``@("`P,#```#_`/\``/___P``_P#___\`____````````````````````! M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````````` M`````````````````````/9F9F9F9F9F9F9F9F9F9F;_9F9F9F9F9F9F9F9F7 M9F9F_XB(B(B(B(B(B(B(B(AF9O^(B(B(B(B(B(B(B(B(9F;_B(B(B(5558B(" MB(B(B&9F_XB(B(@`506(B(B(B(AF9O^(B(B(```%B(B(B(B(9F;_B(A555``@ M55B(B(B(B&9F_XB+N[NP#N-5B(B(B(AF9O^(N[N[`+[N-5B(B(B(9F;_B[N[E MN[N[[N-8B(B(B&9F_XN[N[N[N[[N4XB(B(AF9O^+N[N9F9N[[N,XB(B(9F;_) MB[NYF9F9N[[N,XB(B&9F_XN[F9F9F9N[[N,XB(AF9O^+N9F9F9F9NU[N,XB(< M9F;_B[F9F9F9F;M8[N,XB&9F_XNYF9F9F9F[6([N,XAF9O^+N9F9F9F9NUB(] M[N.(9F;_B[F9F9F9F;M8B([NB&9F_XN[F9F9F9N[6(B([HAF9O^+N[F9F9F[# MNUB(B(B(9F;_B[N[F9F;N[M8B(B(B&9F_XN[N[N[N[N[6(B(B(AF9O^+N[N[) MN[N[NXB(B(B(9F;_B[N(B(B(B[N(B(B(B&9F_XNXB(B(B(B[B(B(B(AF9O^(/ MB(B(B(B(B(B(B(B(9F;_B(B(B(B(B(B(B(B(B&9F_XB(B(B(B(B(B(B(B(AFN A9O__________________]F;_____________________? `` end nethack-3.4.3/sys/os2/os2.c0100644000000000000000000001600607764735041014045 0ustar rootroot/* SCCS Id: @(#)os2.c 3.4 1996/02/29 */ /* Copyright (c) Timo Hakulinen, 1990, 1991, 1992, 1993, 1996. */ /* NetHack may be freely redistributed. See license for details. */ /* * OS/2 system functions. */ #define NEED_VARARGS #include "hack.h" #ifdef OS2 #include "tcap.h" /* OS/2 system definitions */ #ifdef __EMX__ #undef CLR_BLACK #undef CLR_WHITE #undef CLR_BLUE #undef CLR_RED #undef CLR_GREEN #undef CLR_CYAN #undef CLR_YELLOW #undef CLR_BROWN #endif #include "def_os2.h" #include static char NDECL(DOSgetch); static char NDECL(BIOSgetch); int tgetch() { char ch; /* BIOSgetch can use the numeric key pad on IBM compatibles. */ if (iflags.BIOS) ch = BIOSgetch(); else ch = DOSgetch(); return ((ch == '\r') ? '\n' : ch); } /* * Keyboard translation tables. */ #define KEYPADLO 0x47 #define KEYPADHI 0x53 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * When iflags.BIOS is active, shifted keypad keys are translated to the * shift values below. */ static const struct pad { char normal, shift, cntrl; } keypad[PADKEYS] = { {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'h', 'H', C('h')}, /* 4 */ {'g', 'g', 'g'}, /* 5 */ {'l', 'L', C('l')}, /* 6 */ {'p', 'P', C('p')}, /* + */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }, numpad[PADKEYS] = { {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'4', M('4'), '4'}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'p', 'P', C('p')}, /* + */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }; /* * Unlike Ctrl-letter, the Alt-letter keystrokes have no specific ASCII * meaning unless assigned one by a keyboard conversion table, so the * keyboard BIOS normally does not return a character code when Alt-letter * is pressed. So, to interpret unassigned Alt-letters, we must use a * scan code table to translate the scan code into a letter, then set the * "meta" bit for it. -3. */ #define SCANLO 0x10 #define SCANHI 0x32 #define SCANKEYS (SCANHI - SCANLO + 1) #define inmap(x) (SCANLO <= (x) && (x) <= SCANHI) static const char scanmap[SCANKEYS] = { /* ... */ 'q','w','e','r','t','y','u','i','o','p','[',']', '\n', 0, 'a','s','d','f','g','h','j','k','l',';','\'', '`', 0, '\\', 'z','x','c','v','b','N','m' /* ... */ }; /* * BIOSgetch emulates the MSDOS way of getting keys directly with a BIOS call. */ #define SHIFT_KEY (0x1 | 0x2) #define CTRL_KEY 0x4 #define ALT_KEY 0x8 static char BIOSgetch() { unsigned char scan, shift, ch; const struct pad *kpad; KBDKEYINFO CharData; USHORT IOWait = 0; HKBD KbdHandle = 0; KbdCharIn(&CharData,IOWait,KbdHandle); ch = CharData.chChar; scan = CharData.chScan; shift = CharData.fsState; /* Translate keypad keys */ if (iskeypad(scan)) { kpad = iflags.num_pad ? numpad : keypad; if (shift & SHIFT_KEY) ch = kpad[scan - KEYPADLO].shift; else if (shift & CTRL_KEY) ch = kpad[scan - KEYPADLO].cntrl; else ch = kpad[scan - KEYPADLO].normal; } /* Translate unassigned Alt-letters */ if ((shift & ALT_KEY) && !ch) { if (inmap(scan)) ch = scanmap[scan - SCANLO]; return (isprint(ch) ? M(ch) : ch); } return ch; } static char DOSgetch() { KBDKEYINFO CharData; USHORT IOWait = 0; HKBD KbdHandle = 0; KbdCharIn(&CharData,IOWait,KbdHandle); if (CharData.chChar == 0) { /* an extended code -- not yet supported */ KbdCharIn(&CharData,IOWait,KbdHandle); /* eat the next character */ CharData.chChar = 0; /* and return a 0 */ } return (CharData.chChar); } char switchar() { return '/'; } int kbhit() { KBDKEYINFO CharData; HKBD KbdHandle = 0; KbdPeek(&CharData,KbdHandle); return (CharData.fbStatus & (1 << 6)); } long freediskspace(path) char *path; { FSALLOCATE FSInfoBuf; #ifdef OS2_32BITAPI ULONG #else USHORT #endif DriveNumber, FSInfoLevel = 1, res; if (path[0] && path[1] == ':') DriveNumber = (toupper(path[0]) - 'A') + 1; else DriveNumber = 0; res = #ifdef OS2_32BITAPI DosQueryFSInfo(DriveNumber,FSInfoLevel,(PVOID)&FSInfoBuf,(ULONG)sizeof(FSInfoBuf)); #else DosQFSInfo(DriveNumber,FSInfoLevel,(PBYTE)&FSInfoBuf,(USHORT)sizeof(FSInfoBuf)); #endif if (res) return -1L; /* error */ else return ((long) FSInfoBuf.cSectorUnit * FSInfoBuf.cUnitAvail * FSInfoBuf.cbSector); } /* * Functions to get filenames using wildcards */ #ifdef OS2_32BITAPI static FILEFINDBUF3 ResultBuf; #else static FILEFINDBUF ResultBuf; #endif static HDIR DirHandle; int findfirst(path) char *path; { #ifdef OS2_32BITAPI ULONG #else USHORT #endif res, SearchCount = 1; DirHandle = 1; res = #ifdef OS2_32BITAPI DosFindFirst((PSZ)path,&DirHandle,0L,(PVOID)&ResultBuf,(ULONG)sizeof(ResultBuf),&SearchCount,1L); #else DosFindFirst((PSZ)path,&DirHandle,0,&ResultBuf,(USHORT)sizeof(ResultBuf),&SearchCount,0L); #endif return(!res); } int findnext() { #ifdef OS2_32BITAPI ULONG #else USHORT #endif res, SearchCount = 1; res = #ifdef OS2_32BITAPI DosFindNext(DirHandle,(PVOID)&ResultBuf,(ULONG)sizeof(ResultBuf),&SearchCount); #else DosFindNext(DirHandle,&ResultBuf,(USHORT)sizeof(ResultBuf),&SearchCount); #endif return(!res); } char * foundfile_buffer() { return(ResultBuf.achName); } long filesize(file) char *file; { if (findfirst(file)) { return (* (long *) (ResultBuf.cbFileAlloc)); } else return -1L; } /* * Chdrive() changes the default drive. */ void chdrive(str) char *str; { char *ptr; char drive; if ((ptr = index(str, ':')) != (char *)0) { drive = toupper(*(ptr - 1)); #ifdef OS2_32BITAPI DosSetDefaultDisk((ULONG)(drive - 'A' + 1)); #else DosSelectDisk((USHORT)(drive - 'A' + 1)); #endif } } void disable_ctrlP() { KBDINFO KbdInfo; HKBD KbdHandle = 0; if (!iflags.rawio) return; KbdInfo.cb = sizeof(KbdInfo); KbdGetStatus(&KbdInfo,KbdHandle); KbdInfo.fsMask &= 0xFFF7; /* ASCII off */ KbdInfo.fsMask |= 0x0004; /* BINARY on */ KbdSetStatus(&KbdInfo,KbdHandle); } void enable_ctrlP() { KBDINFO KbdInfo; HKBD KbdHandle = 0; if (!iflags.rawio) return; KbdInfo.cb = sizeof(KbdInfo); KbdGetStatus(&KbdInfo,KbdHandle); KbdInfo.fsMask &= 0xFFFB; /* BINARY off */ KbdInfo.fsMask |= 0x0008; /* ASCII on */ KbdSetStatus(&KbdInfo,KbdHandle); } void get_scr_size() { VIOMODEINFO ModeInfo; HVIO VideoHandle = 0; ModeInfo.cb = sizeof(ModeInfo); (void) VioGetMode(&ModeInfo,VideoHandle); CO = ModeInfo.col; LI = ModeInfo.row; } void gotoxy(x,y) int x,y; { HVIO VideoHandle = 0; x--; y--; /* (0,0) is upper right corner */ (void) VioSetCurPos(x, y, VideoHandle); } char* get_username(lan_username_size) int *lan_username_size; { return (char*)0; } #ifdef X11_GRAPHICS int errno; #endif #endif /* OS2 */ nethack-3.4.3/sys/share/0040755000000000000000000000000007764735105013576 5ustar rootrootnethack-3.4.3/sys/share/sounds/0040755000000000000000000000000007764735105015111 5ustar rootrootnethack-3.4.3/sys/share/sounds/bugle.uu0100644000000000000000000004724007764735041016565 0ustar rootrootbegin 644 Bugle M``5"=6=L90`````````````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``!H`10```````#8B```! MSJ<]K=:G/:W>``````````````````````````````"!@7%5``!&3U)-```V M&D%)1D934TY$```T'@`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````/____\```$"`@("`@("`@("`0("`0```/_^_O\```$"`@,#`P0$!@D- M#Q`0"P/Y[>+GCX>+G\/?\``(#!0<'!00$!`,"```!`P8'!P8%!`,#!0<( M!P8%!`(!`0#__O[^_O\``@,$!PH,#`L+#`\2%1@:&1<5$Q`,!/CHU+^TM+6Y MQ=/C\OP!`/W[^OCV]OC[``4+#`H&!`(``````@0%!PD*"@H)"`8$`P,#`P(" M`0$!______\!`P4'"0L-#@X,"PH*#1$5&AT?("(>$?[CR+.HIZRUO\?.U=SF M\?C\_OW[^??Y`@T4%A0/"08&!@<)"@D(!P4%!P@(!@0#`@("!`8("`8%!`," M`0$!`@,$!08'!P<("@P.#A`3&2`F*"@E'Q'[XC("%F;37^0\9%PP!_/OX]?;]!@X1$`\,!P/_ M_P``_OW_!`L0$A(0#0D&!`,#!0@)"`<&!`+^^OCW]O;Y_P4+#Q$1$`P)!P8' M"Q$7&R(I+"85_=_"J)2*CZ"ZV?@.%Q8-`OKV]/'Q^`(+$144$`L$__W]_?S] M``4*#A(4%1,/"@8"``$$!P@("`<%`O[[]_7T]OL`!0D-$!$/#`D'!PH/%!HA M)RHH'@OPU;VGD(*(H\?M"AD<$P?\]_7S\?/[!`L.$`\-"P<"__[^_?X"!PP0 M$Q46$PX)!0$``00&!P<'!@,`^_CV]/3W_`((#1`1$`X*"`<)#1(8'2(F)!L) M\=C`JY>,E;#0[P<6&!`$^_;T\>_R^@,+#Q$2$0X)`P``__W^`08,$!06%A0/ M"@8"```"!`8&!@4#`/WY]O3S]?H`!@P1$Q,1#@P+"PX1%1H>(1\7!_#4NJRH MIZ>NPN']$!81!OWX]O3R\O@"#105$@P(!00#`@#^_P$&"P\3%A@7$PP&`?[_ M`@0%!04$`P'^^_CW]_CZ_P0*#A$1$`X+"0D+#Q,8'2`A&PWXX'QL/^^/+MJ:;E9VZX0(6'!@. M!?WY]?/S^``(#A$1#PT-#`H&`O_]_@,(#1$5%A83#@D%`@$"`@("`P0$`P'^ M^O?U]??\`PH.$1,2#PT,#`T/$109'1\;#OKCRK2GGIB@NMX`%AX:$`;_^_?U M]/?^!@P/#P\.#@T+!P+^^_P!!@L/$Q87%`\*!@,"`P,"`@("`@(!__SY]_?Y M_0$'#1`2$@\,"PL-#Q(6&QX?'!'_Z=&[J)B,E+?B`Q@?&0\'`?WY]O;Y_P8* M#0T-#@\."P?O^8'&AX8#@8`_?KW]?C^!`D,#0T-#@T*!0'^ M_?X`!`@,$!(3$0X*!P4#`@$````!`@(!__W[^?GY_`$'"PX.#@T+"0D*#1$5 M%QD9%P\![MG$LJ&5G\#H"1H=%PX&`/SX]O;Y_P4*#0T-#0X-"@4!_?O\_P0( M#!`3$Q$."@<%`P$`__\``0(#`@#^^_GX^?P!!@H-#@T,"PD)"@P/$Q87&!'*LIV6K-;[ M$1L9$@L%__OY^?G[_@$%"`H,#@\."03_^_K\``,&"@X1$0\-"@@&`P#^_?X` M`0("`@#]^OCW^?P!!@D+#`P+"0@("0H-$!,4%10/!/3@R;"F;?C`Q08%`T(`_WZ^_S]_O\``0($!@H-#@P(`P$` M```!!`@,#0X-#`P+"08#`/_^_O__````__SZ^?K]`04'"`D*"0D("`H,#Q(2 M$1$/"O_OV<*JF:;/]@T8%Q`*!0#\^OO\_O\```$"!`<+#0P*!@,"`0$!`@4) M#`T-#`P,"PD&`@#__O[^_O[___W[^?G\``0&"`D)"0D("`D+#A$2$A$/#`7Y MZ-*ZI)RUWP`2&!0-!P+]^OO\_@````$!`@,&"@P*!P4#`P,#`@,&"@P-#`P, M#`L)!0(`__[^_O[^_O[]^OG[_@(&!P@("`@("`@*#`\1$A(2$`L"]-_'K)BA MR?$+&!@1"@4`^_K\_O\!`0$!`0(%"`H+"08$`P,#`P,%"`L,#`L+#`L*!P0" M`/_______O[]_/GY_``$!P@)"0@("`@)"@T/$!$1$0T'^^K3NJ.=M^$!%!D3 M#`8!_?KZ_/\!`@("`0$"!0@*"0<%!`0$!`,$!@D,#`P+"PP+"08$`@'____^ M_?W]_/KY^OX#!P@)"0@(!P<("0P/$1$2$0\*`/'=Q:R:IL[U#AD7#P@#_OKY M^_T!`P,"`@$!`@4'"`<%!`0%!00$!0@+#0P+"PL+"PD&!`,!___^_?W\^_KY M^?P!!0@)"@D(!P<'"`H-$!$2$0\+!/KIU+F=F+CE!A<:$PL%__KX^?S_`@0$ M`P$!`0,%!P8%!`0$!04$!`8)#`P*"@L+"PH'!00#`?_^_OW]_/OY^?K_`P<) M"@H)!P<'!@@*#A`1$!`."/_QW<6GE:O:_A0;%@T'`?SY^/K]`00%!`(!`0($ M!@8$`P,$!04%!08("@L*"0H+"PH(!@4$`@#^_OW\_/OY^/G\`04("@L*"`<& M!@<)#1`1$`\-"@/WYM&TFJ'*\PX;&1`)`_SX]_G[_P,&!@,!`0$#!04$`P,$ M!08&!@8'"0L+"@D*"PL)!P8&!0,`_O[]_/OY]_C[``0'"0L+"0<&!@8("PX0 M$!`."P;\[-:YGI_"[`D8&A(*!/WX]OCZ_@(%!@0"`0(#!`0#`@("!`8&!@8& M"`H+"@D*"@H)!P4%!@4!__[]_/OY^/CZ_@(&"`H+"PD'!@8'"@X0$1$/#`?_ M\-S!I9RWX0(6&Q4-!O_Y]O?Y_``$!@8$`@("`P,"`0$"!`8'!P<&"`H+"PH) M"@H)"`<&!P<$`?[]_/OY]_;Y_0$%!PD+"PD'!@8&"0P0$1`/#`@"]^3+JI:I MUOL2'!@/"`'Z]O;X^_\#!08%`P("`@,"`0`!`P4'!P<&!PD+"@D)"0D)"`<& M!P@&`P#__?OY]_;W^P`$!@@+#`L(!P8%!PL.$!$0#@D"^>G4M9F@RO,.'!L3 M"P3\]O7W^OX"!0<&!`(!`0("```!`@4'!P<&!PD*"PH("`D("`<&!PD(!0'_ M_?SZ^/;W^O\#!0<*#`P*"`8&!PH-#P\/#@H#^^W:OZ*;O.D)&AT6#0;]]_3V M^?T!!0<(!@0"`0$!`/__`@0'"`<'!P@*"PH)"0D(!P8&!PD*!P,`_OW[^/;U M^/T!!0<)#`P*"`8%!@D,#@\0#PP&__/BRJN8K=L`%AX9#P@!^?3U^/S_!`<( M!P4#`0$!`/__`0,%!P<'!P@*#`L)"0@(!P8%!@D+"@8!__[\^O;T]OL`!`8( M"@P,"PD'!@<+#0\0#@P(`/7DSK"7I-'[$QX<$PH#^O3S]OK^`@8("`8$`@$! M`/[^``(%!P<'!P@*#`P*"`@(!@4%!0@+"P<#`/[]^O?T]?G^`@4'"@P-#`H( M!@8)#`X/#PT)`_GKU[R@G+_M"QL>%0P%_?7R]/C]`04("0@%`@```/_^_P$$ M!@<'!P<)"PP+"0@(!P8$!`<+#`H$`/_^_/GU]/?\`00&"0L,#`L)"`<)#`X/ M#PX*!/OMV;ZAF+;F"1L?&`\(__?S\_?[``0("0D&`P$``/_^_@`$!@<'!P<( M"PP+"0@(!P4$!`4)#`L&`O_^_/KV]/;[``,%"`H,#`L)"`<("@X0#PX*!?[R MX3.M9R][0T=(!@0"0'X\_/U^?X"!@D*"0<#`?_]_/W_`@8'!P<'"0L, M"PD(!P4$`P,%"0P-"@4!_OW[^/?Y_@(%!04'"0D)"0D)"PP.#Q`."0+WZ=6] MHINYYPD;(!D0"@+Y]/+T^/T!!0@*"0<$`?_]_/S_`@4'"`<'"`L,#`H(!P8$ M`P,%"`P-"P8"__W[^/?Y_@,%!08("@H)"0D)"@L-#Q`/#`7Z[-G!I9BPX`4: M(1H2"P3Z]/+T^/P!!0@*"0@%`@#^_/S^`@4'"`<'"`L,#`H(!P8$`P,$!PL- M#`@#__[\^??X_0$$!04'"0H)"0D)"PP.#P\."P3Y[-O%JYNLV/\6(!P3#0;] M]O/S]OL`!`<)"@@%`@#^_/S^`04'"`@'"`H,#0L)!P8$`P,#!@H-#`D$`/[\ M^??W^P`$!04'"0D)"0D)"@P-#A`/#`?]\-_)K9BDT/H4(!T4#@?^]O+R]?K_ M`P<)"@@&`P#^_/O]`00'"`@'"`H,#`L)!P8%`P,#!0H-#0D%`?_]^O?W^@`# M!04'"`D)"0D)"@L-#A`0#@C_\^+-LIJ?Q_01'Q\6#PC_]_+R]?G^`@8)"@D' M!`'^_/O]``,&"`@'!PD,#0P)!P8%`P("!0D-#0H&`O_]^_CV^?X#!@8&"`D) M"`@("0H,#A`1#@D!]N?3N9V8N^L,'2`8$`H"^?3S]?G^`@8("0D'!`'__/O] M``,&!P<'!PD+#0P)!P8%`P("!`@,#0L&`O_]^_CV^/T"!08&"`H*"0@("0H, M#A`1#PH"^.G6O:*9MN0'&R`9$0L#^O3R]/C]`04("0D(!0+__?O]_P(%!P@' M!PD+#0T+"`8%!`,"`P@,#@L'`P#^^_CV]_P"!08&"`D)"0@("`D+#0\1$`P& M_.['Q8."/_X]/3W^P`$!@@)!P0"`/_^_?\! M`P8'!P<'"0P-"P@&!00#`@(&"@T,"`0!__WZ]_;Y_@,&!@<)"@D)"`@)"@T/ M$!`."0'VY]&VG9S`ZPH<'Q%0T(`/GU]??[_P,'"0D'`P$`__[^_P$$ M!@<'!P@)#`T*!@4$`P,#!`<+#0P(!`'__?KV]?G^`@4&"`L,"PD(!P<("PX/ M$`X+!?OMV;^DG+CE!QH?%P\)`OKU]/;Z_P,&"0H(!`$`__[^_@`#!@<'!P<) M#`T+!P4$!`,#`P8*#@T)!0'__?GV]?C]`@0&!PH+"@D'!04&"0T0$1`-"`/Y MZ=.TEYS)]Q(>'!,+!?WV]/7Y_0$%!PD(!0(`___^_O\!!`8'!@<("PT,"`4$ M`P("`P4)#0T*!@(`__SX]?;Z``,%!@@*"@D(!P8'"0P/#P\-"@3\[=:XF9?! M\0\='A0,!P#X]/3W^P`$!PD(!@(``/_^_O\!!`8'!P<'"@P,"04$`P("`P0( M#`T+!P,`_OSX]?7Y_@($!@D+"PH)!P8&!PH-#P\-"@;_\^#'J)BPWP,8'Q@/ M"0+Z]//V^P`$!PD)!@,!`/___OX``@4'!P8&"`P-"P<%!`,#`P0'"PT,"`0! M__WZ]O7W_``#!0<)"PH)!P<&!PD,#@\/#0@#^>G2LI:?SOD3'QL1"@7]]_3V M^?X"!0@)!P0"````__X``@0&!P8'"`H-#`@%!`,#`P0%"0T,"04!`/[\^?7V M^P`#!`8)"PL*"`<&!@@+#0T-#0L&_N[8NIJ:PO`.'AX4#`<`^/3U^/P`!`<) M"`4"````__[_`00'"`<'"`H,#`D&!`,#`P0%"`P-"@8"`/_\^?7U^?X"`P4( M"PL*"0@'!P@+#0T-#0L'`//?Q:.5L^0&&A\8#@D"^?3T]_L`!`<)"`4#`0`` M__[_``,&!P<&!@@+#`H'!00#`P0%"`P.#`<#`/_]^O;U^/T!`P4'"0L*"`<' M!@<*#`X.#@P(`_CFS:J3IM;_%A\:$0H#_/;T]OK^`@8("`8$`0``__[^``,% M!P<&!@<*#`H'!00#`P0$!@D-#`@$`?_]^_?U]_P``P0%"`H*"0@'!P<)#0X. M#0L(`_KKU+:;H,GT$!T<$PP&_O?T]?C]`04("0@%`@``__W]_P$%!P<'!@<* M#`P)!00#`@,$!0D,#0H%`@#^_/CV]OK_`0,%"`H+"@@'!@<(#`X.#@T*!O_S MW\.BEK?G"!L?%@X(`?GT]/?[_P,'"0@&`P$``/[]_@`$!@<'!@<)"PP)!@0$ M`P,$!0@,#@L'`P#__?KW]OG^`0,%!PD*"@@'!@8'"@X0$`X+!@'VY'A0, M!?WW]/7X_0$%"`D(!@(``/_]_?\!!0<'!@8'"@P,"08$`P(#!`4)#0X+!@(` M__SX]?;Z_@(#!0@*"PD(!P8&"`L.#PX-"P@!]>'$H9.TY0<:'Q<."`'Y]/3W M^_\#!PD)!@,!``#^_?X!`P8'!P<'"0L,"@8$`P,#`P0'#`X+!@(`__WY]O7X M_0$#!`<*"PH(!P8&!PH-#P\-"P<"^>G1L)>ET_P4'QL2"@/[]?+U^?X"!@D) M!P0!``#__?X``P4'!P8&"`L,"P<%!`,#!`0&"@T,"`,`__W[]_7W^_\"!`8) M"@H)!P<&!PD-#@X.#0H'__#:O)R8O^X,'1\5#`7^]_/T^/P!!0@)"`4"```` M_O[_`00&!P8&!PD,#`D%!`,#`P0&"0P-"@4"`/[\^?;V^?X!`P4("@H)"`<& M!@@+#@X.#0L)`_;BQJ.3K^(%&2`9#P@!^O3T]_O_`P<)"0<#`0``__[_`0,& M!P<&!P@+#`H&!`0#`P0%!PL-"P8"`/_\^?;U^/T``@0("@L*"0<&!@<+#@\- M#`H(!/OJT;"5I-+[$Q\<$0H#^_7S]?K^`@8)"0<$`0``__[^``(%!P<&!@@* M#`H'!00#`P0%!PL-#`@#`/_]^_CV]_O_`0,&"0L+"0@'!@<)#`X-#0T+!__P MVKZ?F;WL"QT?%@T&__CS]/?\`04("0@&`@``__[^_P($!@<'!@<)#`P)!@0# M`P0%!@D,#0H%`0#^_/GW]_K^`0,%"`H*"@D(!P8(#`X.#0T+"`'TX,6EE*_A M!1D@&0\(`?KT]/;Z_P0'"0@&!`$``/[]_@$#!@<'!@8("PP)!@4$`P,$!0<+ M#0L&`@#^_/KW]OC\``($!PH+"@D(!P8'"@T.#@X,"@7ZZ=&QEJ'/^!(@'1(* M`_SU\_7Y_@(&"0D'!0$``/_]_@`#!0<'!@8'"@P+!P4$`P,$!0<*#0T(!`#^ M_?OX]O?[_P$#!@@*"@D(!P8&"0P.#@X."P;^[MB[FYC`[PX?(!8,!O_X\_3X M_``%"`D(!@(```#^_O\!!`8'!@8'"0L+"`8%!`,$!08(#`T*!0'__OSY]_?Z M_@$#!0@*"PH)"`<&"0T/#@T,"@G0L)6AT/L4(!T3#`7]]?+T^/P!!0@)"`8"``#__?W_`@4' M!P<&!PD+"P@%!`,#!`0&"`P-"@0`_OW[^/;W^_\"`P4("@H*"0@'!PD-#@X- M#`D$_.[8NIR=Q?$-'A\5#0;_]_+S]_L`!`@)"0<$`?___?S^``,&"`<&!PD+ M#`D&!00#!`0%!PL-"P8"__[\^??W^OX!`P0'"0H*"0<'!PD,#@X.#@L&`/+= MP:&7N.@(&R`8#PD"^?/S]OK^`P<)"0@%`?___?S]``,&"`@'!P@*#`H'!00# M`P0$!@H-#0D$`/_]^OCV^?T!`P0&"0H*"0@'!@<*#0\/#PP'`?;DRJ>3K-X" M&"$<$0H#^O3R]?G]`@8)"@@&`@#__OS]_P(&"`@'!@@*#`L'!00#`P,$!0D- M#@H%`?_]^_?V^/P``@,%"`H*"0@(!P<*#A`/#@L&`OKKU+.8HL_Y$Q\=%`P% M_?7R]/C\`04("@D'`P#__OS\_@$$!P@'!P<)"PP)!@4$`P,$!0@,#@L&`O_] M_/GV]_K^`0,%!PD)"0D("`@*#0X.#@T*!?WMU;66F\GU$!\>%0T'__?R\_?[ M``0'"0H(!`'__OS\_@$$!P@'!@8("PP)!P4$`P,#`P8*#@T'`O_^_/GV]OK^ M`0,$!PD*"0D("`<("PT.#@T*!O[QW+^>F;[L"QT@%P\(`/?R\O7Z_P,'"0H( M!@+__OS[_?\#!@@'!@<("PP*!P4$`P,#`P4*#0T)!`#^_?KV]?C^`0,$!PD* M"@D("`@)"PX.#@T+!O[QW+Z=E[OJ"AP@&!`*`OGS\O3Y_@(&"`H)!@(`_OS[ M_/X"!@@(!P<("@L*"`8%!`,#`P4)#0X*!0'^_?OW]?C]`0,$!@D*"@D)"`@( M"@P-#@X+!O_TXLBHF;/@`Q@@&A(+!/KT\O3X_@(%"`H)!P0`__W[_/X!!0@( M!P8("@P+"`8%!`,#`P0(#`X+!@+__OOX]OC]`0,$!0<)"0D)"`@)"PP-#@X, M"`'TXL>GFK/@`Q@?&A(,!?SU\O3X_`$%!PD)!P0!__W[^_T`!`<(!P8'"0L+ M"0<%!`,"`@,&#`X,"`,`_OSY]_C\``,$!0<)"0D)"`@("0P.#@X,!P#UY M&Q(,!_[W]/3W^P`$!@@)"`4"`/W[^_S_`P8(!P8&"`H+"0<%!`,"`0($"`P, M"04!__WZ^/?Z_P($!`4'"`@(!P<'"`D+#`T,"`/Z[=J]I*K/]@X<'!,-!P#X M]/3V^_\#!0<("`8"`/W[^_S_`@8'!P8&"`H+"0<%!0,"`0$#!PL,"@8"`/[[ M^/?Z_@($!`4'"`@("`<'"`D+#0X-"0+Z[=O!IZG-]`P;'!,-"`'Y]/3V^OX" M!0<)"`8#`/[\^_S^`04'!P8&!PH+"@@&!0,"`0`"!@H,"@<#`/[[^/?Y_@($ M!`4&"`@'!P<'"`D*#`T,"07^\N+)K*?&[@D8'!4-"`+Z]?3V^OX"!`8("`<# M`?_\^_S^``0&!@8&!PD+"@@&!0,"`0`!!0H,"@<#`?_\^??X_0$$!`0&!P<' M!P<'!P@)"PP,"@7_]>7-KZ;#ZP87&A,-"0/\]O3V^?T!!`8("`8#`?_]^_S^ M``,&!@4%!@@*"@@&!`,!```!!0D+"0<$`?_]^O?X_``#!`0%!P<'!P<&!P@) M"@L+"07_]>;1MZW#Z`04&10-"03\]O7V^?T!`P4&!P8#`?_]^_S]``,%!@4% M!@@*"@@&!00"`0```P@*"0<$`?_]^OCY_``#!`0%!@<'!P<&!@@*"@P,"03_ M]^K6O:Z_Y`$2&14."@7]]_7V^?P``P4&!P8$`?_]_/S]_P,%!04%!@<)"@@& M!`0"`0```P<*"@<$`@#^^_GX^_\#!`0%!@<'!@8&!@@)"@L+"@S9P*^] MX/X0&!4."@7_^?;V^/P``P4&!P8$`@#^_/S]``($!@4%!0<)"0@&!`0"`0`` M`@8)"0<%`@#^_/GX^_\"!`0%!@8&!@8&!@<("0H+"@@#^^_?Q[*XVOH-%A8/ M"@8`^O;V^/O_`P0&!P8$`@#^_/S]_P($!04$!08("0@&!`0#`?__`04)"0<% M`@#^_/GX^OX"!`0$!@<'!@8%!08("0H*"08!^O#BS+>[VO@+%A8/"08`^O?V M^/S_`@0%!@8%`@#^_?S]_P$#!04$!`8("0@&!`0#`0#_`00("0<%`P'__/KY M^OX"`P0$!08&!@8%!08'"`D*"@@#_?/FT;RZU/,'$Q4/"@^T.T##Q00"@<#_OGW^/O^`0,$!08%`@#__OW]_@`" M!`0$!`4&"`@&!`,#`@$```(&"`<%`P$`_OSZ^OT``@,#!`4&!04%!`4&!P@) M"0<$`?KQXLV^RNC_#1,1"P<#_OKX^/O]`0,$!04%`P'__OW]_@`"`P0$!`0& M!P@&!`,#`@'__P$%"`<%`P(!__SZ^OP``@,#!`0%!@4%!04%!@<("`<$`/GP MX]#"S>C^#!(0"P<$__KX^/K]``($!`4%`P'__OW]_@`!`P0$`P0%!P@'!0,# M`@#__P$$!P<%`P$!__WZ^OS_`0,#!`4%!04%!00%!@<'"`<%`OWTY]7$RN/Z M"1$0"P<$__OX^/K]``(#!`4%`P'__OW]_O\!`@,#`P,%!@<&!0,"`@$`_P`# M!@<%`P(!__W[^OO^`0,#`P0%!04%!`0$!08'"`<%`OWUZMC'RN+Y"!`0"P<% M`/SY^?K]``(#!`0$`P$`__[]_O\!`@,#`P,$!@<&!0,"`@$`_P`#!@<%`P$! M`/[\^OO_`0(#`P0%!04$!`0$!08&!P<%`?WVZ]S-SN'W!@X/"P<%`?SY^?K] M_P$#!`0$`P$`__[]_O\!`@,#`P,$!08&!0,"`@$`_P`"!0<%`P$``/[\^_S^ M`0(#`P0$!04%!`0$!04&!@8$`O[Y\.+2S=WS`PP/#`@%`?WZ^OO\_P$"`P0$ M`P(`__[^_O\``@,#`P,$!08&!0,#`@$`__\"!08&!`(``/_]^_O]``("`@,$ M!`0$!`0$!`4&!P8%`O[X\./4S]_T`PP."P<%`O[[^OK\_@$"`P0$`P(`__[^ M_O\``0(#`P,#!`4&!0,"`@$`__\!!`8%!`(!`/_]^_S^``$"`@,$!`0$!`,# M!`4%!@8%`O_[\^C:T=OP_PD-"P<%`O_[^OK\_@`"`P,$`P(`__[]_O\``0(# M`P(#!`4&!0,"`@$`__\!!`8%!`(!`/_]_/O]_P$"`@(#!`0$!`0$!`0$!08% M`P#\].G;T]SP_P@-"P<%`O_\^OO\_@`!`@,#`P(`__[^_O\``0(#`P(#`P0% M!0,"`@$`__\!`P4%!`(!`/_^_/S]_P$"`@(#!`0$`P,#`P,$!04%`P']]^_A MU=KM_`8,"P<%`__\^_O\_@`!`@,#`P(!__[^_O__`0("`@("`P0%!`,"`@$` M`/\``@0%!`(!`/_^_?S]_P$"`@(#`P,#`P,#`P0$!04$`P'^^?'EV]SK^@4* M"P<%`P#]^_O\_O\!`@,#`P(!`/_^_O__``$"`@("`P0%!`,"`@$``/\``@0% M!`(!``#__?S]_@`!`@("`P,#`P,"`@,$!`4%`P'_^_3JWMOH^`,)"P@%`P#] M_/O\_?\!`@(#`P(!`/_^_O__``$"`@("`@,$!`,"`0$``/\``0,$`P(!``#_ M_?S\_@`!`0("`P,#`P("`@,#!`0$`P'__/;NXMWG]@$'"@@%`P'^_/S\_?\` M`0("`P(!`/_^_O[_``$!`@("`@,$!`,"`0$``/__`0,$`P(!``#__OS\_@`! M`0$"`@,#`@("`@,#`P0$`P(`_?CPYN#F]/\&"0@%`P'__?S\_?\``0("`@(! M`/___O__```!`@(!`@(#!`,"`0$``/__`0(#`P(!``#__OW]_O\!`0$"`@(" M`@("`@(#`P,#`P(`_?GRZN/G]/\%"`<%`P'__?S\_?X``0$"`@(!`/___O__ M```!`0$!`0(#`P,"`0$``/__``(#`P(!``#__OW]_O\``0$!`@("`@("`@(" M`P,#`P(!__OU[N;G\OT#!P<%`P(`_OW]_?X``0$"`@(!``#_____```!`0$! M`0("`P,"`0$!``#_``$#`P(!``#___[]_O\``0$!`0("`@(!`0("`@(#`P(! M__WX\>GH\/L"!@<%`P(`_OW]_?[_``$!`@$!``#______P`!`0$!`0$"`P(! M`0$```#_``$"`@(!````__[]_O\```$!`0("`@(!`0$"`@("`@$!__WZ]>[K M\/D`!`8%`P(`_OW]_?[_``$!`0$!``#______P```0$!`0$!`@("`0$```#_ M``$"`@(!````__[^_O\````!`0$!`0$!`0$!`@("`@(!`/[[]_'M\/G_`P4$ M`P(`__[]_O[_```!`0$!``#______P````$!`0$!`@(!`0$````````!`@(! M````___^_O\``````0$!`0$!`0$!`0$"`@$!`/_]^?3P\OC^`@0$`P(!__[^ M_O[_```!`0$!``#______P````$!```!`0$!`0`````````!`0$!````___^ M_O__``````$!`0$!`0$!`0$!`0$!`/_^^_?S\O?]`0,$`@$!`/_^_O[__P`` M`0$!``#______P`````````!`0$!`0```````````0$!````_____O\````` M```!`0$!`````0$!`0$!``#^_?KV]/?\``(#`@$!`/_^_O[__P`````````` M______\``````````0$!`````````````0$!`````/______```````````` M``````$!`0$!``#__OSX]_C\_P$"`@$``/_______P``````````______\` M`````````````````````````````````/______```````````````````` M``````#__OW\^OK\_P`!`0$``/_______P``````````________```````` M`````````````````````````/_______P`````````````````````````` M___^_/S]_P```0````#_______\``````````/______```````````````` M`````````````````/_______P``````````````````````````________ M_P````````#_______\```````````#__P`````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````!#3TU-````$@`! M```T%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P`````` M````````````05!03````:A39#)A``(````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`I`````````````````````````````````````````````````````````` M```````````````````````$"```````"0`C`````````````````'@````$ M``0```````#\`/___X`````!`0`&455N:71S```````````````````````` M`````````````````0(`!B!S86UP````%8``````%;^`/___X`````!`2`&455N:71S```3""YP9P5" M=6=L90(```!!249&4V0R80`````````````2JP````!!249&4V0R80`````` M`````````````````````````*<]K=8``#8B```!S@```!T`+P`/__;_^0`! M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````:`"D`#P)J`S$`*@`#`FT# M/0`I``\"00,B`0`````:`"D`#P%0`?$`*@`#`FT#/0`````````````````: M`"P`%@$^`=P`*@`#`FT#/0`````````````````:```````````````````` M``````````````````$````!>````'@```!6`'&XO!RF````'`!6``!7```````#__\````\```````$__\` M``!:```````````````````````````````````````````````````````` ,```````````````` ` end nethack-3.4.3/sys/share/sounds/README0100644000000000000000000000261207764735041015766 0ustar rootrootREADME for the AIFF files: These files are sound files for the instruments in NetHack. There are 11 sounds, one for each distinct instrument. The sounds are in 8-bit 22kHz AIFF format, which should be readable by a broad range of platforms. Since the sounds came from Rolands S-750 sample library (most of them) there should be no copyright on them when we treat them like we do here (as instruments) - indeed, the sample library I got from Roland didn't even bear a (c) symbol. Some of the sounds are very adequate (Drum of Earthquake, Wooden Flute, Magic Harp) while some are less true to the original name (how does a Frost Horn sound?) Actually, I don't know what a Bugle is (Bugle horn?) so I took a trumpet sound for that. Correct me if I'm wrong. What does this have to do with the main code? Well, nothing so far. There are some places that are #ifdef MAC and calls mac_speaker; that function takes an object and a tune (in capital letters A-G) and plays the tune with the given instrument. When playing a specific tune, that tune is of course used. For "improvise," I use middle "C." Ideally, we should do something equal with sound that we have with displays, so we can use one common set of calls in the main code, and have ports do whatever seems appropriate for the available hardware. Any comment on the sounds or their use is welcome: Jon W{tte Mac Team nethack-bugs@nethack.org nethack-3.4.3/sys/share/sounds/bell.uu0100644000000000000000000006075107764735041016407 0ustar rootrootbegin 644 Bell M``1"96QL```````````````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``````````````$0B```! MSJ<]K>2G/:WQ``````````````````````````````"!@6<2``!&3U)-``!$ M&D%)1D934TY$``!"'@`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M_P````#_``#___[^``$#`_W]_OG[!@L%_??S^P``!P_X[/_\_@`&!__^[O@) M^?<*%/CF!OWL"Q0&\?+]^`'__@C[^`@#]_3Q^0L%_Q8$U><%_PXD!^OVY=0( M+`_]``#DT?8='`H.!N'=Y/`H(/@5!\_-!AL"%PSY^M#H&P'_(`O:]`SA^QWX M_A?PZP[YZ`@,]@H+ZO\"[``$_`L)Z/89[M\6$OD`_?X`Z>06)?'S#?3H[0,: M#O[]]^7P$__['/SJ_/CT!@SY`@OQ\PCX]@@&_O0`!/O\\PH*Z_H/!>OX%_;I M#A'W\?SY^0L`"!CQXO?\]`DD#/'ZY^#_"!,8$O'?^^GG&B@&]03WUND.&1?^ M^P#LXO8/%0[_\?<`Z/0;$?SW__OL^PD!_@<*[O(3]>WX!0'_"03W^/;Y"PCT``[PYPD(_@?^]/X#[_H9 M`?;]\_[]^`L0^.P(`-\,&/H$`?'R`OK[%0GP_?_U^/@3$NOX%/S>_ACW^`[Z M_OSU`O__`@3Z^P;O_!#L^A[^Y`P0WO@7^?L,_/?Z\0`._/D1_.\)_NX&"/0` M!OG\"/?U#/_W`04&^/8$__/W#0CZ"/SR`_KN"A[_Y_\(\?+\$QKUZ?\-].D. M&@7OZ0H&Z/H?&>7J#OON`Q(.]?$#]_0)%`#P!_OO!OP'%_CL`PCC^R3^^0CV M\_OU"!O]\!(`UP@8Z_P7`>__!03\Y@0D\.0?&.+C!@L&]?HH"X3$O\#]NT"!/P,$??U_>_\#00%"OOQ`/SS"Q($^O/X_/?[%Q;Q^`#O M]`@/$`CNZ0;^Y0XI!^SQ`/;R"!$/`?#R]O[_!A<&]OCU]P(%!@L&[_4([_L; M_NL*#._T#@/Z"OCW#/7L!!0*]OD#^?;[#`_W\04%]?@/#.?W%?_X!O[Q^P?[ M"QGO[@/S]`\4^_D&]>S^"1`"]`4'\>8%&`#S"`_Q[/L$#@;U`0_TX0L4[_P1 M_O,'__,#`OC]#@7_^?#^`/P*$`'X]_GS`@_\"0SKZ`<,[@,E^N@%_N;T'1'^ M!O?S\.L+)@WS^@3TX/T/#Q7S^0GCYA`B_/06_-GR%@CT^@X&^`+[^_;M`QP/ MZ_L'X>8/'PS]^_/V[/4=$0'\_.OH"`$%$`C\[/O[ZPT8_/H,^=_^#/8&&/GM M"OOL`P3Y!!'_]@'R]0+S$"+TX@0%XOP;&P4#!_OGU?\N"?@7!^+;^@\)#A$-\MON_OX0&@\$Z]_U M`?X-(`SP]O+G^`@4$P#]`>G9`QT#`A((\.+L`A,#!QWYY>[U`0L6!0<$V.@' M!0\*#`+PZN@+$08+``'\Y.T/$P`!"_CC]@L)`P`6"-7N$`CT`!H"[N?^&??M M%![NW!(0X?47&>_G"0?XZP<;^.D#%/KC!"("V/TJ^OV M(2_TU?P%XO@D%@7YVO`.\_!.'V^]H+.P;M`O+B``X* M)0K5XP'Z`R8=`?#@W?$8*!L(\.?6YPP>-17KY>K@Z2 M[M'[#`D:`>P,!-CN(`SX"07T]_?U#@?X"P7O]P7W_Q<%]0+][_C_!A4%\OC[ M_OX`_@T/ZO0&`OOX`@L*]?P,\NT)!OP0!?#^^.T(%O?Z%?CR`OC\!0`*&?': M"P7>!"D2]^_N_O_N#RK^YOWXZP`)#!/\]@#MZQ`6]@L.XO'\]@\9_/45\M$+ M&0,#`0'UZ^T0&O@&"NOM!0+]#Q'XZOH&]O84#O`"">CW#_O]&?WE"O_D"!7X M!`CK_@CO^Q[[Z1?ZY@P+\OL5^?0-]/L,^/<("?/[#/KS`@W^\P4)\_D0_?<$ M`_CZ"/T"`_7__O\"`@`$">SQ#@3V"!+P]`+P]10:^/P'[./\%`H,#_;F[/S_ M"B`3^.CN]_0&'"``W>O_^?<7)`SMX?`"!/X;(.[C^_3K#",-!@#CZ/CY#BX/ M[_SFU/HD&Q$+]>_>X!$F#@4*\MOR_@4;$P+X]^_M`Q$1`OL&]>K\"`P'_?<' M!>O[$P3Z_?H""OOV#`3L``O^!@SX]O_X_`L*_P7YZ0,+^086!^KR`_4&#@(' M`?;E_18$"0'_`^_K_QX'\@L"]O?W``\-]0`/^>GZ"PK^^Q`)Z?$&!``*!?D' M^>\!!`8'_?P*_.@!$_H"$//U"?7M$AOY\P;^]/<#%@CU]P``^/H+%P+M^PS[ M]``)#_OM!0WR]18%\P@"]``'^`$*[_X2]O49"=X`$_/X%!'X].[S$`7_%1#N MX0,"_P\("O_MY_T5^00@`.7Q!/W_%0D``^SH!1(``!``[/3^!A`!_`GXZ?T1 M__L4_^T"_/0#$`H``?'V!/D!$`OZ\?D``_\!$@'N^O\$`OT!`__U_P7]"/_X M#`3N^0S]^`X!^P?T\`P&]PP0\_`!^?H)"0\%[/L`[OH8$?H&^>;Y_@09$?[] M\N3Z#0D4$O#U]MP%+@;R&PC(Z1$($@T``/;=\1T/!1+ZZO?U]10;_/C^[^X, M#@H0`.OF`@G^#Q7^Y^S[`Q(2!PKWVNL)"Q(5`?3W[>02(`@'_/;T]>\**?SI M"@?M[PX-!`3U_@;\]@(0__3[`@4'`/L#__;Y!PX(`//X!_CW#Q#_]P#Y]@<$ M!0[_]O?\__L,$@CY[?O^`08*%P;IY_\&]PT?"?+M]_4#$`\2_>KP_OP!&`SZ M`_OL^`P("0?U!`CCZ"(=YO\?^>?V`@8+`P`4]]L"#_C_&!'[]._T`O\&&P_X M]?+M]Q$9"P4#]^3K"`\+"@0#_NSK"0\"#`_Y\?CO_!0-!0H![/+^_PT2`?O_ M]/`"#@4""P3V\_X!_@L,!?OJ^@4!``H6]_/]_0KW\@H5!/$%_NSX!A,.!/SY M[NH'$`\,`OGR\.D.(@,("?#?\@X)#P\(!=O;#AC_""$`X^KM#1P!`!#ZV?@8 M`?\)!/OU``0)_?0&`/<&"__[!/[R^@P+`O[\`_KN^PL4`/T)]/#\!P4$#_;Q M!OKY#POY_`#S`A+W_!7VX?\/!@L,]/C_Y?P?#/P'_N'Z#_X($`'W^??X#`H` M!/GY`?T""PGY\OD"`P$2#_/H^0$`$@X'!.3=`Q@'#B#QV>_X`1[O!QH(`A'^WNH+#P4,%P#?Y0`+ M!`X:`^WL^`(##Q`&^NSV`P`!%!7NZ@D![@4?!/#[__KX!1,+]/<'^?`+$_[\ M!/SY^OP*#?SY"P#G^!(*^005_>+V#P#Z$Q/V[_GW_@@,%`GO\P#S\@X<#?GS M^_OH^"0@^O,`\>7_%!,*__;Q]/D'&1'Z\OWU[08;$/?Y]^[Y!1<5`_;O\>\# M&1@*^.[L]?X*(Q7U[_3N\!,="`'Y\._\"!$1`?3T]OH($PS]]O?R_!`4#/WR M[?+^#!X1^OCLXOH?%0GX^P<1$`OU[/,$"0,-"_SK\@@)!P@"__/M_Q(/`@C\Z/<&``L:!>_Q M]?H)"PD2_^;Q!0,%$@W\\_#V!PD)$`;S[?D#!`T-"/[O\/D("@41"_;I]@C_ M_P\4!?#S__SZ`1$3`??Y^_3U#A@*!/_VY^T($A$.#OO>Z04*"1@<^N'H]@(. M$Q$P3U[>GV#Q80!0'XY.L-%@8$!_WP\OX/%_[W M"?_I]A@+]@GL`PL-$@KY[^[V!1$1"OOO^/;T$1H&]_KZ M[O@,%Q'U]/WS]045%`/QZ_\`]0X=!_'R]O,#$!`)_O;L\PD/!PD*\>3Y"@P. M"OSV[^T#%Q8'^_+M\_P0&PP`]^CE`A8+$1CVVNS^`1$>#?KQX^X.$`P3"N[D M]OP)%0L%_.[L_PL+$@GR\OGQ_1D3_/[][?(&"PT1_?'Y^/(#&0O[`_SN]P<- M"`4`^OCS_PL'`P+^^?W__PP+^_P!^O<%!_\%!?SY`0(``P0!_P(`^?\'__@! M"@+^`P+_^?H#"`0!!?_V^?\#!@8(!?OV_`#Y!1`*_O?Y^OL`"A0']?C[_O\% M#`;]]_W^_@@$_P4$^OP$_/T-"/O^__;Z!04)#?[V^_OY!0X)!0'X\O3["Q4) M`@;WYO(("P\5`?/U[.\+&@T("O#E^``'$1,&]?3P]0,,%PK\^?7W^@@0"P/V M]/;_"@4*"??R_@+]$!+T]@/S]1(2_P8!ZO8%`A`4^_3\[_$)#Q04]^?X_/$+ M(0X#^>;G_@@)&Q;\Z^KT_`P5%`7S\>[T!0X4#/_S\?CY"1`*!OCT^/S]"!,$ M]_W]^OX$"@C\]/T$_O\&`P'^_/\"`/T"`OX"`O[^_P#]_04%_?T%`_/[#0;] M``7^]OC\"@_\_07_\_@'!@D(^_GY]OD"#1$*^^_Y^/4,%PS_^O'I]@0/&P[W M]OCKZA(C"/T']=SP"PT4%0+V\.?V$1$($`#F[?D`%!8$!?K<\1@&_!X.W.@" M^P08$P3[Y^<%"@44%_OAZ/T%"`\:"^OE\O\($1,&^//O\`(8$@`!^^_T``8/ M$OOS__CR"!<$_0+X]/H("08+_/7V_@7^"@H$_.[\!@0`!!#^\O?^!?\"#@CW M]0$`^@0.!_[[^_CY!0D&"0/[]_3Y"!,#`@_XXO4)!0H3"?KTZ_8."`D3!_#K M^/D&$PL*`/+P]`4+$`GY_?;R^PH6!_W_]O7]!0L-!O/Y`O'\%PW[`@'P^`<` M"1/^\OC]``$!"A+^[?T&^_\#!@H`\O@*`O,#$@?W^@?]]P`"!PD$]?L']_<* M#`@$^O+]`?@'%`C_^/+X_P,+%0;T^?7P`P\-#@CSZ?O__`\7"?GR[?('#PD. M#/7F[P$+#!`-^NWL^`$,&0\"\NGQ^@<1%PWX[^?S!0H3&0CL[?3P!!<4#@3O MY_;[`QH4`O_QX_4+"@\5`?'R[O<-%`X&^?#R]0`1$`WV`0D-"07[ M[N\`"PD-"?OT\?8%$`H%!/+L_08#"Q,!]/3X`@4'"0CZ[OT!_0@."/GV_`$! M^P80`?'U`@0`!0T$]O7_`P(*!OCU^@0'!`0$_/#Z"@L&!/[S]/L&#P<``?OQ M]@@."@3[^O;R_@\0!?_V]/G_"1`+_?3S]@0(!P\%\.S\!@4*"@7\[.\##@H& M!?[T\/H,#04$`//T`08)!0$`^??]!P8!`OOZ_P`$!0/]_OST`@\"_`'^^_O_ M"`P!^/W^^``)"`'Z^/S__`81`O/X`?O]"@@#_?7V``8#"`C]]OC]`0<(!/[W M]OL"!0@)_O?Z^_X'#0#Z_O3U!`H'!0#V]O_^`PT'^OCZ^/T%!@D#]_;\`0(% M!?_^^?@""`+\`/[Y_P<$``+^^?L`!@OU`P\3!OWX M\O+\#`\*`/?Z^/@%"P8!`/KW_@$"!@,`__O[``(``0/__@#^___^`@0!_@(! M^?L``@0%!`#[^/L``P<*`_CW^/L`!PP)__3V_?P!"PP"^/?Y_``%#0;W^?[[ M_`<+`?KZ^P`!`0<%_/7^!/\`!`/]^/P"`P(#`OSY_@(``0,"_/C^`P4!_P(! M^O8""P/^`/WY^OX#"@?\^_WY_04'!?_\^OP``08&_OS]_OT!!0(!_/D``?X" M!@'Z_0#\``0"`/W^____`0`````0`!````````/P`____@``` M``$!``9156YI=',````````````````````````````````````````!`@`& M('-A;7!S```````````````````````````````````````````````````` M````````````)P`O``__]O_Y``$````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````!`````7@```!X````5@`````` M````````````````````````````````````!$)E;&R!`@```$%)1D939#)A M`````````````!*L`````$%)1D939#)A```````````````````````````` M````ISVMY```1"(```'.``````````````````(E`/____X!,0`````````` M``````````````````````````````````$````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````!H`*0`/`FH#,0`J``,";0,]`"D`#P)!`R(!`````!H` M*0`/`5`!\0`J``,";0,]`````````````````!H`+``6`3X!W``J``,";0,] M`````````````````!H``````````````````````````````````````0`` M``%X````>````%8`<;B\'*8````<`%8``%=S=&$``P`*``'__P`````````` M``+__P```!X```````/__P```#P```````3__P```%H````````````````` I```````````````````````````````````````````````````````` ` end nethack-3.4.3/sys/share/sounds/erthdrum.uu0100644000000000000000000015006307764735041017317 0ustar rootrootbegin 644 Drum_Of_Earthquake M`!)$CK[>_P\O3V^/K\_@`"`P4("PT.#A`3%A<7%A@<(B8G)B0E*2XQ+RHG*"XU M.SLW,2XR.T-&0SLS,39`2U-434`Q)2,K/$U96E%`+!H-!@P>.UMQSGX=S7TLS'PKZZM[6TM;:Y MO<''SM?AZ_<#$!PI-$!*5%QE;&]O<'!O;FYN;6YM;FUL;6UN;FYO;W!P;VUJ M9V1?6U=44U-55EA:7%UA9FQQ='1R<&UJ:&AI:FQN<')T=7-Q;V]N;FQH8EU8 M5E-03$E&0T`^.SHX-S4U-#0T-34U-C8V-C4T,S$N*R@E(AX:%A(."04`_/CW M]_;U]?7U]?7U]?7U]/3S\O+Q\/#O[^[N[>WL[.OJZ>CGYN7CXN#?W=S;VMG7 MU=/1T='0SLG#P+Z[N;BWM[>WM[>WM[>WMK:UL["LJ*6BGYV;FIJ;FYN9EY:6 MF)N>H:*AGYZ;L[_+S]?;W^/CY M^/?U\_/T]_P`!`<*"PL+"PL+"PL,#`L)!@+__?O\``8&5D5T8X-3@W+1T2#@\-!__\_P8-$!`+`?3JYN?L\O?\`0<-$A89 M'2`C*#`\3%ME:FYP;VMD5T8U*R@D&Q`)!0+]^/;RZ^'6RL"[NL#(SQJJ2@G)B8F)>0AX&`A(F. ME9VCIJ*9CXB*E:2QN\/+T=+3UM[DY^7CYN[Z!A`7'B0J*R3EZ.OL[.OM\_H``P0$ M`P'__P(&"@X/#0D%`@($"`T0$Q,1#0H'!00$!`,!__WZ]>_HY.+BY>KR^@0. M&2$C(!H3#`<$`P(#!0D-$A<;'A\?'AT9%!`,"0@*#A0:'B`>&!$+!@/_^O3K MX=C0R,*^O+NZNKF[OL+(S=/7VMW?X-_/BX>'A MX>'BX^3DY.#:U-7>Z.GDX-_7CX^3CW=?2U=G:T\G"O\'*V.;O\.K@ MUM7B]0`#`O_^_/S[^OKY]O/O[.GFX^'>V]C6T\['O[>PK*NNL;2VM[BYO+_# MQ\S/T]78V^'I\?;W]O#FW-O@Y.'>V]?5U-76U]C8V=O@Z//]!`4#`PH4'2$B M)2@K*RHH(QD,`/;R\O?_!0L0$Q46%A44$A`/#@X.#Q`/#@L'`_[X]/#N[>_T M_0D6(2@K*24B'AL9&1D;'!P;&184%!05%186%A45%!,1$`X,"PL+#`T.#P\0 M$1(3$0P#^.SDX.#@X>3G[//^"QHG,#0T,2XM+B\O+BPI)R8E)BKL[O#O[.?AWM[BZO/\`P@*"04!_?T##QH>&A00#A`1$`L&`O_\ M^?7QZ=_6TM+5V^/P`1`;'A@-_O+L[.[P[^ODWMK9V=WD[OH$"@P,"PH("`L0 M%!01#@D%`@("`?[\_/S]_?X!!@L2&!P>'1L7$0P("0P/#@L(`_[Z^_\$!@0! M_OOW\>GCWMW=WMWKS_`0)"@<# M_OGS[>SP]/;U]/;Z_P$!``($!`#\^?7R\/'U^P$'"PT,"`+[].[JZ>ON[O#W M`PX3$Q8=)"HL+"PO-CHY-C@^0D`\.CP]-B@:#P?_^?C[_/COY^;K]/X$`?CR M]/GZ^?L`!`/]]N[FW-#'Q,K0S\G#P\;*S,W0UM[DZ.KN]?X'$APE*2PN+BTI M(A<-"0H+!OWV\>OEXMW4RL3%RL[.R<&^P\K+P[FWO\G.RL?+UN+J[?'V^?;O MY=G,OK"DG)>8G*&FJ:VSN\3,SL[-T-?>XN+CY>CIZ>GJ[?'U^P`%"@P.#P\/ M#Q`3%A40"P\8(B@J*RTQ-SLY,S`V1%%64TD[+R8C(R8J+"PJ)2`;&1@8&1D7 M%A,1#P\/$!`0#PX.#Q(6&AT='!XD*2HI)2(?&Q@5%!,3$A`.#`H(!@0#`/WZ M^/;T\>K>T<2]N;.JH9N:G:*EI:2DI:BJIY^6DY:;GIZ(!T6#P<`^?;U\^WC MVM75V>#I]``)#@T+#!`1#@8`_P'_^O3P\?;_"A09&AH:&1<6%101#@L)"`H- M#0L(!0(`__[^``(#`__[]_7U]O?Y^OOY]._L[.[Q\O#IW];3VN7N]/CZ]^_H MY>CM\/#KY-_?Y.GM[_#U_04+#A$5'"0I*B&QD8&1D8%A$* M`_SV\O'R\_/R\.[O\O7Z_P4,%!XJ.45+2D0^.SHX-#`N+S$P+"(5"@0? M(R0F+#(S+B(5"P@)#`X1$`T*"@\7(2DM*RS[#AXI M+2LC&1`.$!(4$0P%_OO[_O_]^?;W^/;MX=G6V-O>W]S;W>3O^/X!`P0#`O_Z M]/+V_PH3%A00#@\3%QD:'!X?'1P;'!T='!H6$`?]\^SFY.3FZ_'U]_?W^/K^ M`@8+$18:'!TA*35!1T8],28A(B&QP<&QD7&R(G)!L0"08'#!(9'AX8#@4```$!__OY M^/GZ^??W^/O_`P@0&2(G*2HK*B4>&!88'!\C)B@H)B,@'AL9%0X$_/CW^/O^ M``#\]O+T]_?SZN#9U]C>Z/+X^OO\`0H5'R0B&0\'!08'!0#[]O/S]_\+%R$I M+"LE'!$%^_;X``P7("8H*"8A&Q<4#PC^]>[IYN+@X.3J[O#Q\O/U]_?V]_K_ M!`@*#`P+#`X3&1T=&Q81#0L+#`\1$Q(1#Q$7'1X:$PT)!@4&"`L.$1,3$Q49 M("P MK*FEHJ*FKK.QJ*&@IZZQKJFGK+2ZO\'#P\+#Q[T^@`#`OSU[NCDY>KR^P('"PX1$A$."@7_^/+LZ.;E MY.3DYNKO]OT$"0P.#0H&`@#]^?/JX-;.Q\&\NKFYN+FYM[2OK:^TN;W`PL;, MTM;5TLW,S,W,RLG*S,[1T]+,Q+NSKZ^QM+6UL["MJJ>CHJ.FJZ^RM;J_QLS1 MU-;8W-_?V]+(P+V^Q,S3V-K:V=K=X>7J\/C_!0L4'RHS.3Y%35)444M$.S0N M*20?'!H7$`?\\^_P]/GZ]_3S]OL``/[[^?O\^O3KX]W;WN;Q_`@3&QT:%!`1 M%1LA)BDK*RDD'!$'`/T`!PP,"`0#`P0$!P\9(R@G(AT;'"`A'QL7$PX(`OS[ M_@($__?PZ^KL[_+V^?K[_0,-&28O,S0S,S,U-34T,C$N*R MW-O;WN3M]P`'"PH'`?W]`@@.$`\-#`P-#`D%`?[[^_X!!0<(!@#W[NKL\O?X M]_;X^_\!!0L4'RCDXN'?W=O9V-?8VMWBYNGK[_7_"Q@B*2TN+2TM+2TL*2,=&!45 M%A<<(RPR,BTF(1\?'AP7$@T(!`#]_/KY^/CW]O;V^/K]__[Y\>KDXN+AW]W< MW-O;W-_EZNKHYNCO^@81&1P;%0X&`/W[^OOZ^OCV\N[LZ^OJZ.?HZNWR]_O\ M^_CU]?;Y_@0*#1`2%!<6$PX)!0(`__\``0(%"0T1%!<:'!\D*"TO,3(S-38V M-30S-CQ$351:7V)B8%Q74DU'0#8L(QP8%Q@<'R`?'1L9&1PB*"PK*"4C)"8H M+#`V/$%%1TA)2DI)14`\.ST].3`E'1H<("0C'ACM\._LZ.;EY.3CX^3GZ^WMZ^OP^`$%!0'[]?/S^/X% M"P\3%QL>(2(C)28G*"@F(AL2"/_Y]?/Q[^WL[O'V_``"`P0(#`X-"`'Y\_+T M^/S_`/[Y]/'P\O/S\.KBV=+.R\K)R,?(R\_4V=W?W][;UM35W.7L[>GAW-O? MY.CIZNOM[^_KY=[8U=+,P[JWN+W&T=SCY-_8TM'7W^?L\?;Z_?[___[Z].WI MZ.?FY.3FYN+8S<*[M[:XNKV_P<+!O[V\O+R[M["II:6GJJRNK["PL+&SMKJ] MO\+$Q<7%Q<;*T-;OKY]_6T=+7 MX.GP\_+R]/?Z_/W^_P(#`OWU[.;DY.+>VM?6UM;5U-+/SKJ[._Q M\>_N[.SM\//U]?/NZ>7BX-S5RKVQJ**=FYJ;G9^?GZ*KM;JYM+"RN+_#P\#` MP\G0U=KAZ?#R\.WN]/L``?[Y]/#N\//X_/\!`@0)#A`-!P'Z\^WHY.#=V=71 MSLS+S,O'P;_!QLK+R<7"P<'"PL3)TMOBZ.SR^?X!`P,#`/W[^??V]?3R[^KE MX-_?X.'AX-_=V]C5U-?=Y.GN\O;X^?GX^/K^`P4"^O/P\O;Y^OT!"`P-"PD) M"@H)!@0"`P@1&B`A'!4."@8#_OKW]OCZ_/[_``$!`0("__GPY][7T];=Y^[R M\O'O[.CFY^KL[N_N[>[O\?+S\_/S\_/S]?7R[>?BWMW>W=C3SLS+R\G'QL7& MR,O/T]?:W-[AY.CL[N[MZNCGZ.ON[^[LZ>?DXN'AXN3EY^KM\?7X^_X``0$# M!@D,$!,5%QLB*C`T,S$R-CHZ-S0S-3H^0#\]/D)'2TY/45)24$Q(1DA*3$M' M/S65545%)/3$I-5%YH;W)R<&MH9VAK;7!Q#=W-W>WM[?X^KN\?/V^P`"`?SY M^OT``P+__?O\_?W]^_CV]?3T]/?[`0<-#PT&_O?R[NKIZNWP\O+P[NWL[O'U M^?S^``0(#!`3%1D=("(B(1\;%Q$+!@+_^_;PZ>/AX^CN\_?Y_/X!!`<)"PP- M#`D$_?CT\>_N[^_O[NSKZ>CGY^?FY./CX^'#AWMC2SLS+R\W2 MV-SCEXN#@W][V MM[N_PL3%QL;&Q<"\NKN^O[Z[NKJ[OL+&R]#6W>/I[O'T]_K^`0(!_OW^`@0# M__OX]O7R[>;>U]35VN#FZ>KGX^#=W=[@X^?JZ>?CX-W9U='-S,O*R,;#P<"_ MP,+%RM'7V]S=W=W=W=S=WN'CY./@WMO:V=O>X^?GY.'AXN'>VMG;WN#?VM74 MUMKXN;HY^7DY.3DXN#?WM[=W=S;VMK;W>#BX>#?WM[>WM[>X./GZN[R M]?;U\_3V^OW__OW[^/CY_0$%"0P/#P\/#@\/#Q$1$0X+"`8%!08&!@4$`@#] M^??U\_#LY=_7T,K&PKZXL:NHIJ6EIZNTO\W9X.+AX.+FZ>CCW=C6U=73T]37 MV=G7UM?:W^/GZ>SP\_;W]_7T\_/S\O#MZNGJ[.[N[>OJZNSM[>SL[>WM[>OI MY^3BW]W;VMK;V]O9U];7V=O>W^'CYNCIZ>KM[_'R\_3U]?+N[.SP]?K_`P4# M`?[\^_GU[^C@V=31S&A82#PX-#`D%`/W\_@(%!P4" M_OS[_0`%"Q(:("(@'1@5$0X)!@0"`/SX]/+R]/?Z^_S_`@4%`OWW]/+T]_O] M_/GW]_GZ^??U]//Q[>CDX^/CXM_;U]75V-SAZ?#W_``"!0<("`<&!@D-#P\- M"@D+$!@='QX='2`B(R(A(B4K,#0V-C8U,S$N+"PM,38\0D9)2$5`.C0N*RHI M)R,>&QL=("$A(B0H*RXO,#$S-SH\/#HW,S`K)R$;%A(1$A48&AXB)2@H)R4D M(B$@'Q\@'QT9%`\,"08%!08("`@("0H*"0D*"@@"^O+N[_/Y_P,$`P(!`@,% M!PL0%1@8%A,1$1(4&!TB)BHN-3Q"2$Q-2T=$0D`_/3LZ.3H\/T1(2TQ)14`\ M.CL]0$)#1$9&0SPT+2DH*2HH(QT9&1XF+S8\/CX]/#HW-3,U.#Q`1$E/4U=7 M5$])0CLV,S(S,S,Q,"XO,C<\/C\^/C]#1TQ26%YA8%U955-24E%/2TA&145$ M03TZ.#;BX-[>WM[>WM[?X>3FY>/@W=W=W^'DYN;FY>;FY^?FY.'@X.'D MZ.KL[.OJZ>OM\//U]O;W^/K[_/OY]O+O[.KHY^;CX-W;V=?5U-78VMO:V-;4 MTM+3U-75U-+1T,_.SM#3V-O>W][>W^'E[//X_/W^_P$$"A$7'2`B)"4F)B4B M'AL8%Q83#@<`^O;S\_3W^_W^^_CU\_/T^/X%#!`/#`<"`/_^_P$#!0<&`P#\ M^OK\_P$"`@("`@(`_/?QZ^7@W-G8UM74U=?:W-W;U]/1T=/3TL_-SM'4U]G; MW=_AX=_=W-O:V=;3T,S)Q\?(R\_3UM?6T]#-S<_2UM?5TWM[F]PL?*S,S-T-;>YN[U^_\!_O?PZN?GZ>KH MY>'>W=_CZ.[T^/KZ^?CX^OO\^_KX]?'LZ.3BX>#?WM[?X-_>V];/R=I*NQM;>XNKN^P<7+ MTMG?Y.;FX^#+FZN_S^/S_`/_\^?GZ_?\` M`0$!`0$#!0@+#0X-#`L*"@<"_/7Q\//W_``"!`8*#Q4:'B(G+#$U.#DX-S0Q M+BLI)R0A'1D8&!L>'Q\=&!,."@<%`P$`__\```#__?S\_/S\_/S\^_GV]?C^ M!@X4&!L='R`B)"8H*2DH)R'!P>(20G*2HI*2@F(QX7$0P(!0']^OCW M]_CZ_/\#!@<'!@0"`0$"`0#^_/KX]O/O[.OL[_/U]?/Q\?'S]OK_!0L.#PX. M#@\/#P\-#`H'`OWX]?/S\_3V^?O\_/KZ^_W_``#__/KW]?3U]_L!!PT2%!44 M$Q,3%!46%A85%!47&1H9%Q45%A86%!(1$1$2%!<9&1@6%103$@\,"0<&!@8' M!P@("Q`7(2HS.C]"0T$^/#HX-C(N*20>%Q(/#Q$5&!H;'!\B)"8G)B4B'QX? M(R(",E)B@H*"@F)2,A'QX='1X@(B0D)"0E)BDJ*RLK+"PJ*"0A'AT< M'!\B)"4C(!T;'!\C)RDG)!\;&1D:'!\A(R0C(!L6$1`4&B`E*"DI*2LP.$!' M2TU/3T]-245"04%!/SLV,BXL*24A'1H8%!`-"@D)"@P/$A,2#PP)"`H-$!06 M&!@8%Q45%AD<'1T='1\A(R4F)RDK+3`R-#4U-3(N*B0?&Q<5%!,2$A07&QT< M&A<5%!,3%!8;("0G*"@H*"@G)R&143$A$1$A06%103%!@>(RWN[_'S\_3U]_O_`@0$ M`O_\^//LY=[9U];6U-/0S'CY./AX.'BY.3CX=[;V=?5TL_-S,S,S,W-S]#/SLO*RLO,SVM;6VN;N\O+N[O+[!Q3CXN'@WMS9 MUM/0S\[0TM78V]W>W]_?W][;UM#*QL/"PL+#Q,7%Q<3"P<'%R]+9W^3HZ^[Q M]?G]``(!_OOW]O;V]_?W]_?V]?/Q[^WLZ^KJ[.[P[NKDWMK8V-K;V]K7TLW( MQ<3&R+@W]_?W^#AX-W8T,G# MP,#"Q+CX^3DX^'?W=O8U='.R\K)R;L\?/T]??Z M_/OY]._KZ>CIZNSO\?/T]/3V^?T!`P8("@H)!@0#`P(`_OOY]_7T]/;X^_[_ M__[[^/;U]O7T\_/T]_K]_O___P$#!@H-#0P*"`<'!P@)"0H*"0@'!@4%!00# M`?[Z]O/R\_7W^/?U\O'Q\_?\``0&!P4$`P0&"0P/$105%100#0L)"`8$`P0& M"0P.$1,5%QD;&QH8%Q<7%Q<6%!$."P@&!0,`_?GU\.SJZNOL[N[M[.OJZ^WP M\_;Y_@,*$AHA)B@F(Q\;&AD:'!X>'1D4#0;_^_O]``,$!`,$!`4%`P(````! M`@,"`?_[^/;X_``"`@#\]O'P\?/V_`(("PP,"0/\]_3P[.ON]?T%#!(4$@T' M`__\^_X!!`8(#!0;'QT6"O_Y^?T!`P,!_P`"!0@,$!48&AH:&1@:'B0J+S4Z M/D`^.S'R`?'!8. M!O[X]?/T]OCY^/7Q[N[P\_7U]/+R\O3W^_W^_?W]_P(&"0H*"PP/$A49'!X? M'AT<'!T?(RXN;R^P<+!O[Z^ MOKV\NKBWM[BXM[6TM;BZN[N\O+R_Q,K0TM+1S\_/T-#0S\W+RLG)R\_2T]/2 MS\O(Q<+!P,'"Q,7&Q\;$P;^]OL#$R,W2UMG;M\?/R\?'R\_/OZN7AX.#B MY.;IZ^[P\_7W^?GX]_7S\_/U]?7S\._N[_'R\O+Q\?'Q\._P\?+T]//S\_/S M\_'P[^[O[^_P\/'R\_3T\_'NZ^KHYN7DYN?IZNKJZNKGX][8U=/3U-;6U='. MR\O-T-/5U=+/R\K*S='4U=73T,[.T-/7VMS=W=[BY^SP\?+Q\O+T]??Y^_O[ M^/;S\O+S]?;W^?O^`04("@P-#A`2%!87&1H:&182#PP*"`@&`_WW\>SHY>'> MV]C6T]'.SVM+2UN+S`Q,C,S]+4U]K>XN7FX]W7TOO\_?Y^OKX]_;X^?O[^_KX^/CX^OO]_?OZ^/?W^/K]``,$`P(" M`@($!0<(!P8$`@(#!08'!P<'"0P1%APB)RPO,3$P+"_O\?3V]_?U]??Z_@(&"0H*"PX3%QD9&AL='!H7 M%1,2$0\-#`P.$!$1$1(4%Q@8%1$."P<"_?S]`00%`P$"!0H1%QD8%A04%186 M%A46&1XB(R,?&Q<4$A(4&2`F*2'Q\=&QD9&!@8&!<5$@X+"`8&!04& M!@8&!@8'"0P/$1$/#@\2%AL@)"DN,C4V-C8X.CU`0#TX,BTL+3(V.S]"1DA+ M3$U-34Y/3DM$.C`H(B$B)2DK*RDG)RDM,SI!2$]35%-134E&1$-!/CPY.#D[ M/C\_/#(B#AX>'@W=K7UM?7U];6U]?6UM75V-WD M[/+V]_?V]O7T\_#KY=[6T,O(R,C(QL/`O;N\OL'$Q\G+S,W,R\G)RLS.SLS) MQ,"]O;Z_P,"_OKV]O;V]OL##QLG,T-38V=K9V-C8V-C8V-C8V-G9V][AYNKM M[_#P[^_P\?+T]?7U]/7V]_CY^/?T\>_N[>[P\O+Q[NKFX^+CY>GL[N_P\?3X M_0$#!`,"`0($!PD+"PD&`?[Z]_3Q[^[O\/+S]/7U]O?W]O/MYM_9U-'.R\C% MP\+#QHJ6HJJJKK*ZQM+6TL[&OKJZPM+G`QLO/T=+1T,W)QL*_O+JYN+BV MM+&NK*RLK:^SN+[$R MW-O:V]S>X.'BXN/CX^/CY.;GZ.CHZ>KKZ^OKZNGHY^?HZN[S^/O]_O\``0$! M`/_^_?OZ^/?V]?3S\.SHY-_;U];5U=34U-77V-G;W=_BY>CJ[.[Q]?C\_@`` M`0(#!@D-$!(4%187&!D:&AL<'1X@(R8I*BLI)R0B(!\@(2(D)"0C(B`>'!L< M'!P9$@H`^//P[N[MZ^KHZ.GK[>_Q\_7W^/CY^OO]_O[\^O?U\_'P[^[M[.SK MZ^OKZ^KHZ.CK[?#R\_/Q[^SIZ.CIZ^WP\_7U]/+P[_#R\_/P[NSL[O'U^?T" M!@D*"PL*"@D("`<&!`'^^_GW]O;W^/GY^?GX^/CY^_S\^_CS[NKFX^'@X>/F MY^CHZ>WR^?X``/___OSW\NWJZ.CK[_/V]_?V]_G[_0`$"Q(9'2`C)2@J*B@F M)"(@'R$F+3,W.3@U,BXH(!D4$A4:("0G*"@I*2HK+2\Q,S4X/$%'35%45E53 M3TM&0T`^.SDW-34W.C]#2$M-3D]04E165UA:7F)G:VYP<&]L:&->6%-/3DU- M3$I'0CPV,"PI*2DI*BLN,SI!14A(24I,3U%14$]/3U%24E!-245"/CHW-#,S M,S0U-C8T,B\M*B'!D6$Q`.#0P*"`4"__W\_/S]_O_^_/KW]/+P[^[N M[>WM[>OJZ.CHZNWP\_;Y_/X``0,$!04#`/[\_/S]_OW]_O\!`@(!__SY]O+N M[.OK[.[N[N_P\?/U]O;R[>;AWMW>W^#AXN/CXN'AX^?L\O@`!P\7'B0I+"XP M,#`O+"DG)B@I*2(R8G M)B0B("`@(2`>&Q82#@P-#@X-"0/]^??U\_#MZ^KJZ>?EX^+BX^7GZNSO\?+R M\?'Q\O3V^?O]_OWZ]_/P[>OJZ^[R]??V]?7U]OCY^_W_`00&"0L+"@@%`?_\ M^O?S[^OGY>/BX-_?WM[>WM[>W]_?WM[>X.'CY.3CX>#AY.CN\_;W]_;U]/3S M\O#O[N_P\?+R\O'O[>GFY./CX^/CX^+@W]W=W-K7T]#.S,G'Q\K0U]O=W=S; MV]O:V-;4TM'1TM34U-+/R\;"OKRYM[2RL+"PL;.VN;N[N[N\O;_!Q,C+SM#0 MT-'2T]+0SCK[>[N[N_P\?'R\_3U]O;T\>WJY^;EY./A MW]WVM71S]#3U]O=W^'DY^OM M[O#R]?;V]//S]?CY]_/NZ>7BW]W/FZ.CG MY>+>VMC6U]K=X.+DY>?I[?'W_0,(#`X-"PH*"@L-#@\."P<#`/[_`0,$!`0# M`?[Y]?+Q\?'P[NKFX^'@W]_?X.+DYN7AW-?5U=?7GY^?FY^CK[>[MZ^GH MZ>SQ]_S_`0#^^_GW]?3R[^WL[>_S]_O]_P`"!`8'"`@*#!$6&AT='!L<'B`@ M'AL9&!D:&AD8&!D9&AD9&!<6%1$-"`0"`P8*#A$3%!03$Q,2$1$1$1(2$A$1 M$Q47%A$,"`<("PP,"@@'"`@'!0,"`P4'"`<&!08(#!`5&AXB)2'R$C)2&Q@6%105%144$Q$.#`H)"0D*"PT.#P\/#P\.#@\0$Q47%Q84 M$A`/#@T+"0D*#0\1$1`.#0L*"`<&!04%!@<("`<&!04$!`0$!`0$!`,#`P0% M!@<'!@4$!`4&"`D*"@H*"PT.#P\.#0T.$!,7&QXA)"DN,C8X.3DY.##AX^;IZ^SL[>WN[_#P[^[M[>SKZ>;CX-[;V=?5 MU=75UM;6U=/1T,[,RL?$PL"_O;RZN;FZO+[!PL+!O[V\O+V_P<+"PL+#Q#BX=_ MW^#@X.#@W][7EYN;GZ.ON\O;Z_@(&"0P.$!$3%AD;'1P9%1`, M"0@'!@4#`?[[^/7R\?'Q\>_KY^3BX>#@X-_?W][WMWKL[O+W^P`#!@D)"`8$`O_\^?;T\_+S\_3U]??Y M_``%"`H+"PD'!`("`P8("PX0$1(3%!47%Q@8&AP>(2(B(B$@'QX<&A@6%!(1 M$1$3%AH='R`A(R,C(A\=&QL<'R(E)20A'QT;&QP<'1T>'B`B)"8G)R8F)B'A\?'QX='!T>(2(B(1X;&1@8&1H: M&1<4$0X,#0X1$A,3$Q06&1XB)B@I*2DJ*RTN+S`Q,C0V.#@V,S`M*R@F(R`= M'!P='A\?'AT;&AD9&1D9&AL<'!L<'1X@(2$?'AP;&QL<'!T='AX>'AT<'!L; M'!P='B`A(B,C(B`>'1T='AX<&183$1$3%QH<'1X@(R8J+2\O+RXM+2\P,3(S M-#,R,"TK*RLK*B'R`@("`@'QX<&QH:&AD8%Q@9&QT?(2(B(!T:%A(0#P\0 M$1(4%187&!@7%A86%Q@:'!X@(B,D)24E)"(?'!D7%A86%A44$A`.#`H(!0," M`0``___^_@`"!`4%`P#]^_O\_@$%"0T/$!`/#P\.#0L)!P8&!P<("`<'!@<' M"`D*"@H+"PP-#@X-"P<"_OKW]O;W^/GZ^OKZ^OK[_?\``0(#`P4'"`H*"@H) M"0D)"`8$`O_]^_O[^_S\_?W^``(%!PD+"PL*"@H*#`T0$Q88&QT='1P<&QP= M'1X>'R`B)"4E)2,@'1@4$0X,"@D(!P4$`@$`_OSZ]_7T]/3U]?7U]O;V]?;W M^?S^```````!`0,$!0<*#`\2%!04$A$0$!`/#@P*"0@("`@(!P8$`?[[^/?V M]_GZ^_OZ^??U\N_MZ^KIZ.?FY>3DY.7EY^GL[O#P[^WKZNGJZ^SL[.SKZ^SN M\//V^/GZ^_O\_?W\^OGY^?K[^OCV\_+P\/#Q\O/T]//Q\._N[NWJZ.3@W=K6 MU-+1T-#0T,[-S,[1U=O@Y.?HY^;FY>7FY^GK[>[O\/#P\/#P\?/V^/KY^/7S M\?'S]_P!!08&!`(`````__W[^/7S\O#NZ^CFYN;FY^GJZ^SL[.OIZ.;EX^+B MX>'AX>'AXN+BX^+AW][=W-W>X.#@W]W:U]32T=#/SLW+R,7#PL'!P<+$QLG+ MS,W.S\_0T='1TM/5U=;5U=33T]34U=;7V-G:VMO;W>#DZ.ON[^_O[>OIY^7B MW]O8UM74T]'/SLW-SKJZ>?DX>#@XN3FZ.KKZ^KIY^7BW]S9UM/0S;GZ.CHY^;DXM_WLZNCEXM_>W^'DYN?HZ.GJZ^SN[_'T M]?;V]?/Q\._O\/'R\_/T]?;W^/GZ^_W]_OW\^_O\_?[^_?KV\^_MZ^KIZ.?E MXN#?W]_?WMW;V=C8V-K>XN;I[?#S]OG[_/S\_?\!!`<*#0\1$1(2$Q,3$A$0 M$!`/#0L(!0(`__[]_/O\_?\!`@0%!PD,#A`1$`X,"08#`?_^_O[^__\```$! M`@0&"@X2%186%1,1#PX-#`L)!@+__?W\_/W]_?\!!`<("`<&!@<*#0\/#@P* M"0D+#A`1$`X+"0<&!PD*"PH(!@0"`@,%!P@)"@L,#A`1$A,3$Q(0#PX.#Q$2 M%!04%!47&AXB)"8G*"LN,C4W.3DX.#'AX>'A\@(2(B(B(B(R0E)RHL M+2TL*RDG)2,B(2$A("`?'AX='A\@(B,C(A\;&!43$Q,2$1`/#@T-#@X0$A89 M'!X>'AT<&QH8%Q85$Q(1$!`/#PX.#@X/$106&!H;&QL<'1\A(B(B(2`?'!D6 M$Q`/#@\0$1$1$`\0$A8:'B(E)R M'1P:&1@7%A44$Q(2$A(1$1`/#@P*"`4"_OOX]O;U]//Q\.[LZNGIZ>GK[.WN M[_#P\?+R\_/R\O+T]OG\_P(%!P@)"0@'!@4%!08&!@4$!`,"`@$````!`@0% M!04$!08("@P,"P@&!04&"`D*"@D("`D+#0\1$Q47&AP>'QX<&1<4$@\.#`H( M!@4%!@<'!P8$`@#_``$"`P0$!`0#`@$````"`P0$`@#\^?7R\.WJY^3AW]W< MV]K9V-C9V][BY>?GY^?FYN7EY>;EY>3CXN+BX>'@W]W=W-SWM[=V]K8U];6U]C: MV]W?X.+DY>?HZ>KK[.SKZ^KIZ.CHY^;DX^/DY>;HZ.CGY>+@WMS:V-;5U-+2 MTM/5V-O>X>/DY>3DY.3DY./BX>#@W][>WMW=W=W=WM[@XN7HZNOKZ^KJZNKK MZ^OKZNKIZ>CHZ.GIZNKJZ>?FYN?HZ>OL[.SL[.SM[>[N[N[O\/'R\_7V^/K] M_P$$!@D,#A`1$`X+"0@&!00$`P,#`@(!__WZ^/;V]O;W^/CW]O;V]_G\_@`! M`0#__O[^_O[_``($!0<)"@L,#0X.#@P*!P/__?OZ^?CU\_'P[_#P\?'Q\?'Q M\?'P[^[LZ^GGY>3CXN#?W=S+DY>;GY^CIZ^WO\/+S]/7V]O;V]O?Y M^_W^_OW\^_KY^/?V]?7U]O;V]?7U]O?X^?GZ^_S]__\`___^_?W]_/S\_/OZ M^?CX^OT"!@H,#`L)"`@("`@&!0(!`/\```$#!0<)"@H*"@H+#A$3%145$Q(2 M$Q,3$A`.#`L+#`P-#`L+"@H*"PL,#`T.$!,8'2$D)B8E)20E)B@J+"TM+2TM M+2TM+"PL+"TN+R\P,#$R,S0T,S(R,C(T-38V-C0S,C(R,S0U-C&A<4$A`0$!`1$1(4%1<9&AL<'!P<'!P<'!L:&1D9&AL<'!H9&!<6%A86 M%Q<8&!@8&!@7%Q<6%103$A$0#@X.#Q`2$Q03$A$0#PX.#Q`2%!<9'!\A(2$@ M'Q\A)"@L+S(T-CWJY^7DY.7EYN?H MZ>OL[>[N[^_O\/'S]/7U]?7U]//Q[NKGY./CX^3DY./BX>'@X>'AX>'BXN+B MXN+BXN+BX^/DY.3DX^/CY.7FY>3AW][>W^#BX^/BXN'BX^7HZNSM[>OJZ>CG MY^?FYN7EYN;GY^CHY^?GY^;DX^+AX>#?W=O8U=+/S,K(Q\;%Q<;'R,G*S=#4 MV-K'AXN/EYN?GYN7DX^+@W]W;VMC7UM;5U=75U=/1SLS)Q\7$ MPL"_O;V\O;Z^OKV]O;[`P<+#Q<;'Q\?'QCJ[>[P\/'Q\?'O[NSJ MZ.7CX=_>W=S;GY^CIZ>KK[.[O\/#Q\?'R\_/S\>_LZNGIZ>OL M[O#Q\O+S]/3U]O;U]/+Q\?'R]/;X^?GY]_7S\>_LZ>?EY.3CX>#>W=W=WN#B MX^7FYN?IZNSN\?/U]_?W]O;U]O?Y^_W__P#___[^______[^_O[^______[\ M^OCV]//R\?+R\_3U]//P[.CDX=_?W^#BX^3DX^/CY.;HZ^WO\?/V^OX"!@H, M#0T-#`L*"0@'!@0#`@$`__[]_?S\^_OZ^OGY^?KZ^?GX^/GY^?CW]O7V]O;V M]_CY^_W_`0,#`P'__?S[^_O[^OGX]_;T\O+R\O/T]O?Z_0$$!@@*"@L+"PH) M"0@)"@P.#Q`1$1$0$`\.#0T-#0X.#@\/$!$3%!87&!D9&1D9&1D9&1H;&QH8 M%Q86%Q<8&!@8&1L='A\@(B0G*BPN+R\P,C0V.#DZ.3@V-#,R,3$Q,"\M+"LJ M*RPN,#`P+RXL*RLK*RPL+"PL+"PN+S$R,C(Q,"\N+BXM+"HH)RW-K9U];5U=34U-34U-35UM?9VMOX.'CY>7E MY>3DY.;HZNSN[N[N[>[N[^_P\?+S]/3S\O'P\/#Q\O+S\_/T]/7U]?7V]_G[ M_@$$!@@*#`X0$1(3$A$/#@P*"`<&!00#`0#__O[]_/OX]/'MZ^KIZ>GJZNKJ MZNKKZ^SM[>SJZ.7CXN'AXN3EY>;EY>3DY.7GZNWO\?/U]_G[_?[^_OW\^??S M[^OGX^'>W-O:V-?5T]+1T-#1T='2T]35UM?8V-G9V=G9V=K:V]S=WM_AX^7G MZ.GHYN3AWMS;VMG8U];4U-/2T=#/SLS+RLG(R,G)R#?W]_@X.#@WMS;VMK;V]O; MV]K9V-?7U]C9V=K9V-;4T;HZ>KK[>_R\_/S\_/S\_+Q\.[M[.OKZ^KIZ.;CX=[=W-SWN[N_P\?+Q\?#O[^_N[>OIZ.;EY>7E MY.3CX^/DY>;IZ^[P\O3V]_G[_/W]_?W]_?W]_O[__P```/__```!`@,#!`0$ M!08'"`H,#0T-#`L*"0@'!@4$`P$`_OW\^_KY^/CX^?O\_?[^_OW]_/SZ^?;T M\_+R\_3V]_GZ^_S]_?[_``$"`@,#`P,$!`0#`0#^_/OY^/?W]_CY^_S_`00& M"`H+#`P,"PH*"0H*#`T0$A48&QTA)"'1T<'!P='1X? M("$B(R0D)24E)B@H*2DH*"8E(R(@'QT;&A@8%Q<6%A45%146%Q@8&1@8&1D; M'!X@(2(C)"8G*"HK+2XO,#$Q,"\M+"PK*RLL+"PK*RDI*"'R`?'Q\?(2,E)R_MZ^CFY./CX^3FZ.KM[N_N[NWL[.OK MZ>CGY^GJ[>_P\?'R\O/U]_CZ_/\``@,$!@@)"PT.#PX.#`L*"@H*"@D)"`<& M!00"`?____[^_?SZ^?CW]_CY^_W_`0,%!@<("@L,#0T-#0T-#0X/#Q`1$1(2 M%!47&!D8%Q43$`X,"PL*"@H*"PL+"PP,#`P+"@<%`O_]_/O\_/W]_O\``@4( M"PT/$1,4%187%Q@7%Q44$A`.#0P,#`P-#0X/$1,6&!H;'!T='1P;&1@7%Q87 M%Q<8&!D9&QP='R`@(2(B(R,C(R,A'QP9%A,0#@P+"@D(!P4#`@$```#___[] M_?W^_O[^_OW\^OCW]O7U]//R\.WJYN/@W][?X.'AXN+BX>'@X-[=W-O:V=C7 MUM32T,W+RX.'BXN/DYN?IZNSL[>WN[N_P\O/T]/3S M\?#O[^_N[>SKZ^KJZ>GGYN3BX-W;V=?5T]'.S,G'Q[N[NWM[.SL[.SM[N[O M[^[N[N[N[^_P\/#P\/#O[NWM[>WN[_#Q\O+S\_/T]?;X^OO\_?W]_?S[^OCV M]?3T]/3T\_'O[.GGY>3CY.7FY^CIZ>GIZ>GIZ>KK[>_R]??Y^OKZ^OKZ^?GX M]_;U]//Q\.[LZ^KIZ>GIZNKK[.SL[.SKZNGHZ.GIZNOK[.SKZ^SM[_+U^/O] M``($!08'!P<'!P8&!04$!`0%!04%!04%!`0$`P,#!`4&"`D)"@L,#0\1$Q05 M%A<7&!@8%Q86%A<:'2$D)B8F)B4E)28G*2HK*BDG)2,B(2`?'AT<&QH9&!85 M$Q$/#0L)!P4#`0#__P`!`P0%!@<'!P@)"PX0$Q47&1P>(2,D)24E)"0D)"4F M*"DK+"PL*RHJ*2DI*2@G)B0C(B`@("`@("`?'QX='!L:&!<5%!,2$1$1$1$1 M$A05%A86%A87&1L?(B4H*2HJ*BDI*2@H*"'1T< M&QL;'!T>'1P;&QH:&AH:&1@7%1,0#PT,#`P,#`T-#0X.#Q$2$Q46%QD;'B`C M)"8G*"DJ+"TO+R\N+BXO,#(T-#0T,S(Q,#`O+BPI*" M("(C(R(A'QX='1T<&QD7%!(0#P\/#P\.#@T-#0T-#0T.#@\/#PX-#`L)!P4# M`0#^_/KX]O3S\O'P[^[N[>WM[>SLZNGGY>/BX>'AXN/CX^/BXN+CY>;HZNOL M[>[N[_#R\_3S\_+Q\?+S]OCZ^_S]_?[_```!`0$!`0```````/____[^_?W\ M_/S\_@`"!`4&!P@("0H*"PH*"0@&!@8&!@8&!@8%!`,!__[]_?W]_/OY]_;T M]/3U]O?X^/GY^?GY^/CX^/?V]/'NZ^?CX-[W^'BX^3EY^CJZ^SM[>WL[.KIZ.?FYN;FYN7DX^/CX^/BXN+AX>+B MX^3EYNCIZNOKZ^OKZ^SN\/+T]O?X^/GZ_/W^_O___O[^_?W\_/OZ^?CW]_?X M^?K[^_S\_/O[^?CV]/+Q[^WKZ>?DX=_W^#@X.#AX>'BX^/CX^/C MXN#=VM;2S\O)QL/`OKR[N[JZN;>VM;6UMK>XNKR]OK_!PL/$QL?'Q\;$P\/# MQ,7'R,G+R\S,S,S+R\O+S,W.T-'1TM/5UM?8VMO+CY.3EY^GK[>_P\?+S]/7V]_CX^/?V]?/Q[^[L[.OJZ>CGYN7DX^/BXN+B MXN/EY^GK[>[O[_#Q\O+S\_/S\O'P[^[M[.SKZNGHYN7EY>7EY>;GZ.GJZ^WN M[_#Q\O/S\_/S]/3U]?7U]//R\?'Q\O+S\_/R\O+S]?CZ_?\``0(#!`4'"`D* M"0@&!0,"`0$!`/_^_?S[^OKZ^OKY^?GY^OO\_/W]_?[^_O[]_?S[^??V]?3T M]/7U]?7V]_?X^?GZ^?GY^?KZ^_O[^OGY^/CX^/GZ^OKZ^?GX^/CX^/GZ^_O[ M^_KZ^OGY^?GZ^OO\_O__`````0$"!`4&!@8&!@<'"`D*"PL*"`8%!`,#!`4& M!P@("`@("`@("0L+#`T-#@\1$Q06&!D:&QL;&QL;&QP<'1T='1P;&AD7%A44 M$Q,3$Q,3$A$0#PX,"PH)"`@("`D)"0D)"@H+"PP,#0X0$1(4%186%Q<7%Q86 M%A85%145%145%!04%!45%A85%!,2$1$1$1`0#PX-#`P,#0X.#Q`0$!$1$1$1 M$1$0$`\.#0L*"0@(!P<&!04%!@<("@P-#@\/#@T-#`P-#@\1$A,4%187&!@8 M%Q<6%104%!04%!04%!04%!04%!45%Q@9&1D8%Q43$A`/#Q`0$1$0#PX,"PH* M"PP-#Q`1$A(4%1<8&AP='1T>'R`B)"4F)B4D)"0D)"4F)R@H)R4C(2`?'Q\@ M("$A(2(C)"8H*BPM+S`P,3(S-#4V-C8U-#,R,3`P+RXN+2TL+"PM+2\P,3$R M,S,S,S,S,S,S,C(R,C(S,S,R,C$O+BPJ*"8E)"0D)",C(R,C)"4E)28F)B8F M)B8F)20C(2`?'QX>'AT<&QH8%A44%!04%!04%!03$Q,2$A(1$A(2$Q,3%!47 M&!H;&QL;&AD9&!<6%104%!45%145%!(0#@T-#0X/$!(3%!45%104%!,2$1`/ M#0P,"PL+"PL,#`P+"PH*"0D*"@L,#`P-#`P-#0T.#@\/#P\.#@T,"PH*"0D( M"`<&!@8'!P<(!P<&!04%!08&!@4$`P(!`````/____[^_O__``````#__OW[ M^_KZ^_S]_O_____]_/O[^_O\^_OZ^?GX^/CX]_;U]/3T]/3T]/3T]/3T]/3T M]/3S\_+Q\._N[>SKZNGHY^;FYN;FY^?GYN7EY>7EYN;FYN?HZ>OM[_'R\O/S M]/7W^/GZ^OGX]_;U\_+Q[^[M[.SKZNGHY^?GY^?GZ.CHZ>GJZ^SL[>[N[^_O M[NSKZNGIZ>GIZ.CGYN7DX^/BXN'AX>'AX>+BX^/DY./BX=[X.'BXN/CY.7FY^?GY^?FYN;FYN?HZ>GIZ.CGYN;F MYN;EY>3DXN'?WMW+BXN+BX>'AX>'AX>'AX.#@W]_?W]_@X.#@X>'B MX^7FY^CHZ>GIZ>GHZ.CGYN;FYN;FYN7EY.+AX-_>W]_@X>+CX^/BXN/CY.;G MZ.GJZNGIZ.;EY./BXN+AX>'@X>'BXN/CY.3DY>;GZ.GJZNKJZNKJZNKJZNGH MY^;EY./BX>#@W]_?W]_@X>+CX^/DY./CY.3FY^CIZ>CGY^;FY^CHZ>KJZ^OK MZ^SL[>WM[.SM[>[N[NWLZNGHY^?GY^?GYN;FYN;FY>7DY./DY.3EY>7EYN;F MY>7DX^+BXN+BXN/CX^3DY.3DY./CX^/DY.7EY>;EY>;GZ.KL[_'S]/7V]O;V M]_?W]_CX^/CW]O7T\O'P\/#P\/#O[NWLZ^OJZNKJZ>CFY>7FZ.KL[_+T]_G[ M_@`"`P0#`P(!```!`0$!`/_^_?W\_/W\_/S[^OKY^?GY^?CX^/CX^/CX^?GY M^OK[^_OZ^OKZ^OO\_?\``0(#!`4&!P@*#0\1$Q04%!05%145%145%186%A<7 M%A87&!D:&QP<'!P<'1\@(2$A(!\?'AX='1P;&A@6%!(1$`\/#P\/#P\/$!`1 M$1,4%1<9&QT?(2(C(R,C(B$@'QT;&A@7%Q85%102$1`.#0T-#0X/#Q`0$`\/ M#Q`0$!`0$1$1$1(2$Q,4%!46%A86%145%A87&!D:&AH:&QP<'1X>'R`A(2(B M(B(B(B(B(2$A(!\?'AT<&AD8%Q85%145%186%Q86%144$Q,4%!05%!03$Q,3 M%!05%145%145%A87&!@9&1H;'!T>'R`A("`?'AT<&QH:&AD9&!<7%A86%A87 M%Q@9&AL<'1T='1P:&1<6%!,3$A$0#P\.#@X.#P\/#Q`0$!`/#Q`0$!$2$Q,4 M%!,3$A(3$Q04%145%144%!03$A$1$!`0$!$3%!46%Q<7%Q@8&1H;&QL<'!T= M'AX>'A\@("$B(R,C(R,C(R0D)",C(B(A'QT;&185$Q(1$`X,"PH)"0H*"PT. M#Q`1$Q05%A<8&!@8%Q<7%A86%A86%A45%186%QD;'1X@(2(C(R,C(R,C(R,D M)"4E)B8F)24E)",C(B(A(2$A(B,C(R,C(B$@(!\>'1L:&1<5%!,2$A,4%A@: M'!T?(2,E)RDI*2CGYN;FY>7CXN#?W=W=W=[>W=S:V-;5U-34U-/3T]+2TM/3 MT]/3T]/3T]/2TM'1T=+2T]/3TM+2T='1T='1T='1T='1T='2T]/3T]+1T,_/ MS\_/S\_/S\_1TM37V-K;W-S>W^'BX^3DX^/BXN'@X-_=W-SSL[.SKZNGHY^?GY^?GYN7EY./CX^+BX>#?WM[=W-S#?WMW=W=[?X.'AXN+CX^3EYN;FYN;FYN7EYN;GY^CH MY^?FY>7EY>;GY^?GY^?GY^CHZ.CHY^?FYN7EY>7EYN;GY^?GY^?HZ.CIZ>GH MY^;EX^+@WMW;GZ.CHZ.CHY^?HZ.GJZ^SN M[_#Q\O/S\_/S\O+R\?'Q\?'R\O/T]?;W^?K\_@`!`P4&!P@("`@'!P<'!P@( M"`@("`@("0D)"0D(!P<&!04$!`0#`P(!`0````$!`0("`@,#`P("`@(#`P0% M!08%!04%!04%!04&!P<("0H+"PP,#`T.#Q$3%!87&!D:&AH:&1D9&!@8&!<7 M%Q<8&1H<'A\@(2$A(2$@(!\>'!L9%Q85%!,2$1`/#@X-#0T.#Q`2$Q05%A<7 M%Q<8&!@8&1D9&!@8&!<7%A44$Q(2$A$1$1`0$!`1$A,5%QD;'1\@(B,D)28G M*"DJ*RLK*BHI*"@I*2DJ*BDI*"@H*"DJ*BLK+"PM+C`R,S0U-C4U-#(Q+RXM M+"LJ*"'A\?("`?("`A(2(C(R(B(2$A(2(B(B$@ M'QX=&QL:&AH:&QP='AX?("`A(B,D)B'AT<'!L:&AD8&!<6%144%!05%!04$Q,3$Q,4%!45%144$Q(1$1$1$1(2 M$Q,3%!46%Q@8&!D9&1H;&QL;&AD8%Q86%104$Q$0$`\.#@T-#0T-#0T,#`P, M#`P,#`P+"@@'!@4$`P(!`/_^_?W^_O[___\```(#!0<)"PP-#@\0$!$1$1$1 M$!`/#@T,#`L*"0D("0D*"PP-#@\/$!`1$1(2$Q46%Q<7%A85%!,2$A(1$1`/ M#@T-#0X/$!`1$!`/#P\/#Q`0$!`0#PX.#0T,#`P,#0T-#@X.#@X.#@T,"PL* M"@H)"0@(!P8%!00$!`4&!P@("`@'!P8&!P<("`@("`<'!@4%!00$`P(!`/__ M_P```/____________[^_?S[^OKY^/?V]?3T]/3S\_+R\O'Q\?'Q\?+R\O+R M\_/S\_/T]/7V]_CX^?GX^/CW]O;U]//R\?#P[^[M[.SL[.SLZ^OKZNKIZ.CF MY>7DX^/CY.3DY>;FYN;FY>3CXN'AX>+BXN+BXN'AXN+CY.3EY>7EYN;GY^CH MZ.CGYN7EY>7EY>7DY.3CX^/CX^/CXN+BX>'@W][=W-SWM[?X.'B MX^/CX^+AX-[=W-O;V]S=WM[?X.'CY>?IZNSM[N[O[_#P\/#P\?'Q\?'Q\?#P M[^_O[N[M[>WL[.OKZNKIZ>GHZ.?GY^?HZ.GIZ>GIZ.?FY>/BX>'@X.#@X.#@ MX.#@W]_?W]_?W]_?W]_?W]_?W]_?X.#@X>'BXN+BXN'AX>'BX^/CX^/CXN+C MX^7FY^CIZ>GIZNKJZNKIZ.;EY.3CX^/DY./CX^/CX^3DY>;FY^CHZ>GJZ^SN M[_'S]/;X^OO\_?W]_?S\_/O[^OGX]_?V]?3S\O'P\/#P\/'Q\?#O[^[MZ^OJ MZ>?FY>3CXN+AX>'AX.#@X.#@X.#AX>'@X.#@W]_?W]_?W^#@X.#AX>+CX^/C MX^/CXN+BXN/CX^/CX^/CX^3DY>7EY>7FYN;FYN;FY>7EY>7FYN?GZ.?GY^;F MYN;GZ.GJZ^SL[>[O\/#Q\O+S]/3U]?7T]/3S\_+R\O+R\_3U]OCY^OO]_@`! M`P4&!P@("0D)"`@'!P<'!P<'!P<&!@8'!P<("`D*"@L,#`P,"PL+"PL+"@H) M"0D)"0H+"PP+"PL+"PP-#0X/$!`0$!`/#P\.#0T-#0T,#`L*"@H*"@H+"PH* M"@D)"`@("`@)"@L,#0X/#Q`0$1$1$1$1$1$1$1`/#0P,#`T.#Q$2$Q46&!D: M&QL<'!P<'1T='!P<&QL:&1D9&1D9&1D9&!@8%Q86%103$A$0$!`0#P\/#@X- M#0P,"PL+"PL*"@H)"0D("`@("`D)"@L+#`T-#@\/$!`1$1(2$A(2$1$1$!`0 M$!`0$!`0$!`1$1(3%187&!D9&1D9&1@8&!<7%Q<7%Q<7%Q<8&!D9&AL;'!P= M'1X?(2(C)"4E)B8F)24E)24E)28F)B'AX='1T<&QL;&QP<'1X>'R`@("$A(2(C)"0E)24D)",C(B`?'AT<&QL; M&QH:&AH:&AH9&!<6%104$Q,2$A$0#@T,"PH)"`<'!P<'!P<&!@8'"`@)"0H* M"PL+#`P,#0T-#@X.#@X.#@X/#Q`0$1$1$!`0$!`0$!`0$!`0$!`0$!`0$!$1 M$1`/#PX-#`P,#`T-#0T-#`L+"@H*"@L+#`P,#0T-#@X/#Q`1$A,3%!05%145 M%145%!03$Q,3%!04%!45%!03$Q$0#PT,"@D)"`<&!00"`0````````$!`0$! M`0$"`@,$!04&!P@)"0H+#`T/$!$2$Q,3%!04%!03$Q,2$1`/#@X-#0T-#`P, M#`P-#0T.#@\/#P\/#PX-#0P+"@D("`@("0D*"@H)"0@("`@(!P<'!@8%!04% M!04&!@8%!04%!`0$!`,#`P,#`@("`@$!`/_^_?W\_/OZ^?CW]O3S\_+R\?'P M\._O[^_P\/'R\O/S]/7V]_?X^/GY^?GY^?CW]_;V]?7U]?3T]//S\_3T]?7U M]?3U]?7U]?7U]?7T]//S\O+Q\?#O[N[M[N[N[N[O[^_P\/'R\_7V]_G[_/[^ M______[^_?W\^_OZ^??V]?7T\_/R\O'Q\/#P\/#P\/#P\/#O[^[M[>SLZ^OK MZNKIZ.?FYN7EY.3DX^/BXN+CX^3EYN?HZ>GJZNOL[>[O[^[N[>SKZ^KJZNKI MZ>CGY^;EY>3DX^'@W][=W=W=W=W=WM[>WMW=W=W=WM[?W]_>W=W'AX.#@W]_?X.#@X.#AX>+CY.7EYN;F MYN;EY>7EY>7DY./CXN'?W][>W=W=W=W+BXN/C MY.7FY^?HZ.GIZNOL[>[N[^_O\/#Q\?'Q\?'Q\?'R\O+Q\?#O[^[N[N[M[>SL M[.SL[.WM[N[O\/#Q\O/S\_3T]?7V]_?X^/CX^?GY^OK[^_O[^_O[_/S\_?W] M_?W\_/S\_/S\_?W\_/S[^_O[^_S\_?[^_P`!`@(#`P,#`P("`@$!`0("`@$! M`0```0$!`0#__OW\^_O[^_OZ^OKZ^OGY^OKZ^OKY^?GX^/?V]?7T]//S\O+R M\O+R\O/T]?;W^/CX^/CX]_;V]?/S\O'P\/#P\/'Q\?+R\_/T]/7U]?7T]//S M\_/S\_/S]/3T]?7V]O?X^/GY^OKY^?GY^?GZ^OK[^_S\_?[^_O_______O[^ M_O[^_?W]_?W]_?W]_?W^_@`!`@,$!`4%!`0$`P,"`0$```#______P````$! M`0("`@("`@("`@("`@("`P0%!@<("0H*"PP-#@\/$!`0$!`0$!`0$1(2$Q05 M%A87&1H;'1X@(2$B(B(B(2$A("`?'QX>'AX>'AX='1T='1T>'AX>'1T='1T= M'A\?("$A(2$A(2`@'Q\?'AX>'AT='!L;&AH:&AH;&QP<'1T='AX>'A\?'QX> M'1T<'!P<'!L;&AH9&!@8&!<7%Q<7%Q<6%A45%145%A86%Q<7%Q<7&!@8&!D9 M&1D9&!@8&!<6%A85%A<7&!@9&!@8&!<7%Q<7%Q86%A44$Q,2$1$0$!`0$!`/ M#Q`0$1(3$Q,4%!05%A87%Q<7%A44%!,3$A(2$A(2$A(3$Q04%186%Q<7%A85 M%145%144%!03$Q,3$Q(2$A$0#PX.#0T-#0T.#@\/$!`1$A,3%!45%145%186 M%A85%144%!,3$Q,3$Q,3$Q,3$Q,2$A$0#PX.#0P+"PH*"@H+"PL,#0T.#@\/ M#P\/#P\.#@T-#`P,#`L+"@H)"0D)"@H)"0D("`D)"@H*"PL+"PP,#0T.#Q`0 M$`\.#0P+"@D(!P8&!00#`P("`@$!```!`0$"`@("`@("`@("`@(!`0`````! M`0$!```````!`0("`@(#`P,#`P("`0#__OW\^_KY^?CW]_?V]O;U]?7V]O?W M^/GY^OK[_/S]_O__``$"`@(#`P,#`P,#`P("`@$!`0````#____^_O[]_?W\ M_/O[^_S\_?W]_O[^_O[__P``````__[]_/KZ^?CW]_;U]?3T]/7U]?;V]O;U M]?7T]//S\_+R\?#O[N[M[>SLZ^OKZ^OKZ^OKZ^OKZ^OJZ>GHZ.CHZ.GIZNOL M[>WN[N[M[>WM[N[O\/'R\_3V]_CY^OO\_/S\_/S\_/S\_/O[^OGY^/?V]?3S M\_+R\O/S]/3T]?7U]?7U]O;V]O;U]?3T\_/S\_/T]/7U]?7U]?7U]O?X^?GY M^?GX^/?V]O7T\_+Q\/#O[^_O[^[N[>WL[.OKZNKJZ>GHZ.?FYN7EY>7DY./C MXN+BX>'AX.#?WM[=W=W=W=W>WM_@X>'AXN+BXN+CX^3DY.3DY.3DX^/BXN+B MXN/DY>;GY^?GY^?GY^?HZ>GJZNKJZNKKZ^OL[.SLZ^OKZ^OKZ^OL[.SL[>WN M[N_P\/'R\O/S]/3U]?7U]?;V]O;V]O7U]?7U]?7T]/3T]//S\_/S\_3T\_/S M\O'P[^_N[>WM[>WM[>[N[N[N[N[N[N[O[^[N[N[N[^_P\/#P[^_O[^_P\/'R M\O+R\O+Q\?'Q\?'P\/#P\/'R\_3U]O?X^/GZ^_S]_?[_`````0``___^_?S[ M^_O[_/S]_O\```$"`@,#`P,#`P,#`P,"`@$!`/___________O[^_O[^_O[] M_?W\_/S\_/S\_?W]_?[^_O[_____````___^_OW\_/O[^OKZ^?GY^?KZ^_O] M_O\!`@,$!08&!@<&!@8%!`0#`P("`0#__OW\_/S[^_O[_/S]_?[^_O______ M``````#_____```!`@,$!`4%!@8&!P<'!P@("0D*"PP,#0X.#P\/$!`0$!`/ M#PX.#0P,"PL+"PL,#`T-#@X.#@X.#@\0$1(3%!46%A87%A85%103$Q(1$1`/ M#@P+"0<&!`,"`0````````$!`@("`P,#!`0$!`0$!`0%!08&!@<'!P<'!@8% M!04%!`0%!04&!@<("0D*"PL,#`P-#`P,"PH)"0@(!P<'!@8&!@8'"`D*"@L+ M"PL,#`T.#P\0$1$1$1$1$1$2$A,4%146%Q<7%Q86%144$Q,3$A(2$A(2$Q,4 M%146%A87%Q<8&!@8%Q<7%A44$Q(2$1$1$1(2$A(2$A(2$A(3$Q04%!45%145 M%145%145%144%!04%!,3$Q,3%!04%!04%!04%!,3$Q(2$A(2$A(3$Q,3$Q,4 M%146%Q@9&AL<'!T>'Q\@(2$A("`@'Q\>'AT<'!L:&1D8%Q85%!,2$1$0$`\/ M#@T,#`P,#`T-#@X/#P\0$!`0#P\.#0P+"@D)"`<'!P8&!@8&!@8&!P<'!P<' M!P8&!@8&!@8&!04$!`,#`P("`0$``/____\```$"`P0$!04%!04%!00$`P(! M`/__________```````!`0$"`@,$!`0$`P,#`P,#`P,#`P("`@("`@("`P,# M`P,#`P,$!`4%!04%!04%!`0$`P,"`@(#!`0%!@<("`@("0D*"PP,#0T.#@X. M#0T-#`P+"PH*"0D("`@("`<'!P<&!@8&!P<'!P<("`@("0D("`@'!@4$!`," M`@$`__[]_?[^__\``0$"`P0$!04%!04$`P,"`0$!````______[^_O[^_O[^ M_O[^_____P````$!`0$!`0``_________OW]_/OZ^?CV]?3R\?'P\/#P\/#P M\/'Q\?'R\O/T]/7V]O;V]O;U]?3S\O'P[^[N[>WM[.SL[.SKZ^OL[.SL[.WM M[>WM[>SL[.OKZNKIZ.CGY^?GY^?GY^;EY>3DY.7EYN;FY^?GZ.CHZ>GJZ^SL M[>[N[^_P\/'Q\?+R\O/S\_/S\_+R\?'P\._P\/#P\?'Q\?'Q\?+R\_3T]?7V M]O;V]O;W^/CY^?KZ^?GY^/CW]_;V]O7U]?7U]?7U]/3T\_/S\_+R\O+R\O/S M\_/S\_/T]//S\_/R\O'Q\._O[NWLZ^KJZ>CHY^?GZ.CHZ>GIZNKIZ>GHY^?F MY>7EY>7DY.3DY.7EYN;GY^CHZ>GJZNKJZNGIZ>CHZ.CHY^?GYN;FY>7DX^/B MXN+BXN+BXN+BXN+CX^3EY>;GZ.GJZ^SM[>[N[^_P\?'R\O+R\?'P[^[N[>WM M[>WL[.SKZ^KJZ>GIZ>CHZ.CHZ.CHY^?GY^?GY^?GZ.CHZ.GIZ>GJZNKJZNKJ MZ>GIZ>GJZNKKZ^SL[>[N[N_O[_#P\?'R\O/T]/7U]O;V]O?W]_CX^?GY^OKZ M^?GY^/CW]_?W^/CX^?GY^OK[^_O[_/S\_/S[^_O[^_O[^_S\_/S]_?[__P`` M`0$!`0$"`@(#`P,#`P0$!`4%!08&!@8&!P<'!@8%!00$!`0$!`0$!`4%!@<' M"`D)"0D*"@H*"@D)"0@(!P<'!P<'!@8&!@<'"`@)"0D*"@H)"0D)"0D("`<' M!@8%!00$!`0$!`0$!04%!04&!@8&!@8&!04%!@8&!P<'!P@("0H+#`P,#`P+ M"PL*"@H*"@H*"@H*"@H*"@H+"PL+"PL+"PL+"PL+"PL+"PL+"PL,#`T-#0X. M#@\/$!`0$1$1$A(3$Q,4%!05%145%145%186%A86%A87%Q<7%Q<7%Q<6%A45 M%!,3$Q(3$Q,3$Q,3$Q,3$Q,4%!04%145%145%!04%!03$Q(2$A$1$1$1$A(2 M$A(2$A(2$Q,3$Q,3$Q04%!45%145%145%145%!04$Q,2$A$1$!`0#Q`0$!`0 M$!`0$1$1$A(2$Q,3$Q04%!04%145%146%A87%Q<7&!@7%Q<7%Q<7%A86%145 M%186%Q<7&!@8&!@7%Q<7%A86%A85%145%104%!04%144%!,3$A$0#PX-#`P+ M"@D(!P8%!`0#`P("`@("`@("`@,#!`0$!`0$!`0#`P,#`P,#`P,#`P,$!`4% M!@<("0D*"@L+#`T-#@X.#@X.#@X-#0T-#0T-#0T-#0T-#0T-#@X.#P\/$!`1 M$1$2$A(3$A(2$1$1$1`0$1$1$1(2$A(2$A(2$1$1$!`0$!`0$`\/#P\/#P\/ M#P\/#@X-#0P,#`P,"PL+"@H)"0@(!P<&!@8&!@8&!P<'"`@)"0H+"PL+#`L+ M"PL*"@H*"0D("`<&!00#`0#__OW]_/O[^OGY^/CW]_?W]_?W]_?W]_?W]_?V M]O;W]_?W]_?W]_?W]_?V]O;V]?7U]?7T]/3T]/7U]?7U]?7U]?7U]?7T]/3S M\_+R\O+R\O+S\_/T]/7U]?;V]_CX^/CX^/?W]_;V]O7U]?3U]?7U]?7U]/3S M\_/S\_/S\_/S\_3T]/7U]?;V]_CX^?GZ^OKZ^OKY^?CX]_?W]_?W]_?X^/CY M^?GY^?GY^?GY^?GY^?CX^/CX^/CX^/CY^?KZ^OKZ^OKZ^OKZ^OGY^?GY^?CX M]_?V]O7U]?7U]?7T]/3T]/3T]?7U]?7U]?7U]?7U]?3T\_/R\O+Q\?'Q\?'Q M\?+R\O+R\O'Q\._O[N[M[>WM[.SL[.OKZ^OKZ^OL[.SL[.WM[>WM[>WM[.SL M[.OKZ^OKZNKIZ.?GYN;EY>7EY>7FYN;GY^?HZ.CHZ.CHZ.CHZ.?GY^?FYN7E MY.3DX^3DY>7FYN?GY^CHZ.GIZ>KJZNKJZNKJZ^OKZ^OKZ^OKZNKKZ^OK[.SM M[N_P\/'R\O/S\_/S\_/S\_/S\_/R\O+R\O+S\_/S]/3T]?7U]O;W]_CY^?KZ M^OKZ^?GX^/CW]_;V]O;V]O;U]?7T]/3T]/3T]//S\_/R\O+R\?'Q\/#P\/'Q M\?'Q\?'R\O+S\_3T]/3S\_/T]/3T]/3T]/7U]?;W]_CX^?K[^_S\_/W]_?W] M_?S\^_O[^OKZ^OKZ^OKZ^OKZ^OO[^_O[^_S\_/S[^_O[^_KZ^OGY^?CX^/CX M^/CX]_?W]_;V]_?W]_?W]_?W]_?W]_CX^/GY^?GY^/CX^/CX^/CX^/CX^/CY M^?GZ^OK[^_S]_?[__P```0$!`0$"`@(#`P,#`P,$!`0$!`,#`P0$!`4%!@8& M!P<'!P<'!@8%!04%!04%!04%!04%!@8&!@8%!00$!`,#`P,#`P,#`P0$!08' M"`@)"0H*"@L+"PL+"PL+"PL+"PH*"@D)"0D("`@("`@("`@'!P<'!P<'!P8& M!@8%!04%!08&!P<'!P@("`D)"@L+"PL+"PL+"PH*"@H*"0D)"0D)"0D)"0D) M"0D)"0D)"0D)"0D)"0H*"PL+"PP,#`P,#`P+"PH*"0D("`@(!P<'!P8'!P@( M"0D*"@L+"PP,#0T.#@\/$!`0$!`0#P\/#P\/#P\/#PX.#@\/#Q`0$!`0$!`0 M$1$1$1$1$1$0$!`/#P\/#@X.#@T-#`P,#`P,#0T.#@\0$1$2$Q04%145%145 M%145%146%A86%A86%A86%A86%Q<7%Q@8&1H:&AL;'!P='1T>'AX>'AX='1T< M'!P<'!P<'!P<'!L;&QL:&AH9&1@8%Q<7%A86%A45%145%145%146%A87%Q<8 M&!@8&!@8&!<7%Q<6%A44%!,2$A$1$!`0#P\/#Q`0$!`1$1`0$!`/#P\/#P\/ M#P\.#@X-#`P+"PL+"PH*"@H)"0@("`@(!P<'!P8&!@8%!04%!00$!`0$`P,# M`P,#`P,#`@("`0$!`````````0$!`0$!`0$!`0$```#______O[_______\` M``$!`@,#!`0$!`0$!`,"`@$``/___O[^_O[^_O[^_O[___\``````0$!`0$` M`/____[^_O[^_O[^_O[^_O[^____`````0$!`@("`@,#`P0$`P,#`@("`0`` M_____O[^_O[^_O[^________________``````````````#___[^_O[^_O[^ M_O[^_O[^_O[^_O____[^_OW]_/S\_/O[^OKY^?GX^/CW]_;V]O;V]O;U]?7U M]?7U]?3T]//S\O+Q\?'Q\?'Q\?'R\O'Q\?+R\O/S\_3T]//S\_/S\_/S\_/S M\_/S\_/S]/3T]/3T\_/S\_/S\_/S\O+R\O+R\?'Q\/#O[^_N[N[M[>WL[.SK MZ^OKZ^OKZ^OKZ^OKZNKJZNKJZNOKZ^OLZ^OKZNKJZNGIZ>KJZNKKZ^OL[.WM M[N[O[_#P\/'Q\?'Q\?'Q\/#P\/#P\/'Q\?'R\O+R\O+R\O+R\O+R\O+R\O+R M\O+R\O+R\O/S\_/T]/3T\_/S\_/S]/3U]?;V]_?X^/GZ^OKZ^OGY^?CX^/?W M]_?V]O7U]/3T]/3U]?7U]?;V]_?X^/CX^/CX]_?W]_;V]O7U]/3T]/3T]/3U M]?7V]_?X^?KZ^_S\_?W]_O[^_OW]_?W\_/O[^OKY^/CX^/CW]_?W]O;V]O;V M]O;V]O;U]?7U]?7U]?7T]/3S\_/R\O+R\O+R\?'Q\?'Q\?'Q\?'Q\?'Q\O+R M\O/S]/3U]?7U]?7U]?7U]?7U]/3S\_+R\O'Q\?#P\/#P\?'R\O/T]/7U]O;V M]_?W]_?W]_?V]O7U]?7U]?;V]O;V]_?W^/CX^/CX^/CX^/GY^?GY^?KZ^OO\ M_/W]_O[^_____P````$!`0$!`0$!`@("`P,#`P0$!`0$!`0$!`0$!`0$`P,# M`P,#`P,#`P0$!`0$!04%!04%!04%!04$!`0$!`,#`P,#`P("`@("`P,#`P0$ M!04%!@8&!P<'"`@("`@("`@("`@("`@("`<'!P<'!P8&!@8%!04%!04%!04% M!04%!04%!04%!`0$`P,"`@(!`0$!`0$!`0$"`P,$!`0$!04%!04%!04%!04$ M!`0#`P,#`P,$!`,#`P,#`P(#`P,#!`0$!04%!@8&!P<'!P8&!@8&!@8%!04% M!04%!04%!08&!@<'"`@)"0D*"@H+"PL+"PL+"PP,#`T-#0T.#@X.#@X.#P\/ M#@X.#P\/#P\0$!`0$1$1$A(2$A(2$Q(2$A$1$1`0$`\/#P\.#@X.#@X.#P\/ M#P\/#Q`0$!$1$1$1$1$1$!`0$!`/#P\/#@X.#@T-#0T-#`P,#`P,#0T-#0T- M#0T-#0X.#@X.#@X-#0T-#0P,#`P,#`L+"PL+"PL,#`P,#0T-#@X.#@X.#@T- M#0P,"PL*"@H)"0D)"`@("`@("`D)"0D*"@H*"PL,#`P-#0T-#0P,#`P,"PL+ M"PL+"@H*"@H*"0D)"0D)"0D)"`@("`@'!P8&!04%!04$!`0$!`0$!`0$!`0$ M!`0$!`0$!`4%!04%!@8'!P<'"`@(!P<'!@8&!@4%!04%!04$!`0$!`0$!`4% M!04%!@8&!@8&!@8%!04%!`0$`P,#`@(!`0$!`````0$!`0("`@,#!`0%!04& M!@8%!04%!04%!04%!04%!04%!@8%!04%!@8&!@8&!@<'!P<("`@("`@("`@( M"`@'!P<'!P8&!@8&!@8&!@4%!04%!04%!04%!04%!`0$`P,"`0$``/___O[^ M_?W]_/S\_/S\_/S[^_O[^_O[^_O[_/S\_/O[^OKZ^?GY^?GX^/?W]O;U]?7T M]//S\_+R\O+R\O+S\_/S]/3U]?;V]O;V]O;V]O;V]_?W]_CX^/GY^?GY^?GY M^/CX^/CX^/CX^/CX^/CX^/CY^?GY^?GY^?GY^?CX]_?V]O;V]O;V]_?W]_CX M^/CY^?GY^?GY^?KZ^OO[_/S]_?W]_?[^_OW]_?S[^_KY^/CX]_?W]O;V]O;W M]_?X^/CX^/CX^/CX^/?W]O;U]?3T]/3S\_/S\_3T]/7U]?;V]O?W]_?W]_?V M]O;V]O7U]?3T]/3T]/3T]/3T]/3T]//S\_/S\O+R\O+R\_/S\_/T]/3T]/7U M]?7U]O;V]O;V]O;V]O;V]O;U]?7U]/3T]/3T\_/S]/3T]/3T]//S\_/R\O'Q M\/#P\/#P\/#P\/#P\/'Q\O+R\_/S]/3T]/3T]//S\_/S\_/S\_/S\_/S]/3T M]/3T]/3S\_/S\_+R\O+R\_/S\_/S\_/S\_3T]/3U]?7U]?7U]?;V]O;V]O;W M]_?W]_CX^/CX^?GY^OKZ^_O[_/S\_/S]_?W]_?W]_?W]_/S[^_KZ^OGY^?GY M^?GY^OKZ^OKZ^OKY^?GY^/CW]_;V]O;V]O;V]_?W^/CX^?GZ^OO[_/S\_?W] M_O[^_O[^_?W]_?W]_?S\_/S\^_O[^_O[^OKZ^OKZ^OKZ^OKZ^OK[^_O[^_O[ M_/S\_/S[^_OZ^OKY^?GY^/CX^?GY^OK[^_S\_/W]_O[___\```````````$! M`0$"`@("`@("`@("`@$!`0$!`@("`P,#!`0$!`0%!04&!@8&!@8'!P<'!P<' M!P<'!P<'!P<'!P8&!@8&!@8&!@8&!@8&!P<'!P<'!P<'!P<'!P<("`@("`D) M"0D)"@H*"PL+"PL+"@H*"@D)"0D("`@("`@("`D)"0@("`@("`@("`@("0D) M"0D*"@H*"@H*"0D)"0@("`@'!P<'!P<("`@("`D)"0D)"@H*"@H*"@H)"0@( M!P<&!@8%!@8&!@8&!P<'!P<'!P<'!P<'"`@("`@(!P<'!P<'!P<("`@("`@( M"`@)"0D*"0D)"`@(!P<'!@8&!@8&!@8&!@8%!04%!04%!`0$!`0$!`,#`P,# M!`0$!04%!@8'!P@("`@("`@("`@("`@'!P<'!P<&!@8&!@8&!@<'!P<'!P@( M"`@("`D)"0D)"0D)"0H*"@L+"PP,#0T-#0X.#@X.#@X-#0T,#`P,#`P,#`P, M#0T-#0T.#@X.#P\/$!`0$!`0$!`0#P\/#P\/#P\/#PX.#@X.#0T-#0T-#0T, M#`P,#`P,#`P,#`P+"PL*"@H)"0D)"0D)"0D)"0D)"0D)"0D)"0D("`@(!P<' M!@8&!@4%!04%!04%!00$!`0$!`0$!`0$!`0$!`0#`P,#`@("`@$!`0$!`0(" M`@("`P,#!`0$!`0$!`0#`P("`@$!`0$!````````````````````________ M___^_O[^_O[^_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/W]_?W^_O[^_O______ M___________^_O[^_O[^_?W]_?W]_?W]_?W]_?[^_O[^_O[_______[^_O[^ M_O[^_O[^_O[^_O___P```````0$!`@("`@,#`P,#`P,#`P,#`P,#`P,#`P(" M`@(!`0$!`````````````/_____^_O[^_?W]_?W]_?S\_/O[^_KZ^OGY^OKZ M^OKZ^OK[^_OZ^OKZ^?GY^?CX^/CX]_?W]_;V]O;U]?7U]?7U]?7U]?7U]?7U M]?7U]?7U]?7U]?7U]?7T]/3T]/3T\_/S\_/S]/3T]/3T]/3T]/3T]/3T]/7U M]?7V]O;V]O;V]O;V]O7U]?3T]//S\_/S\_3T]/7U]O;V]_?W]_?W]_;V]O;V M]O;V]O7U]O;V]O;V]O;W]_?W]_?W^/CX^/CX]_?W]_?W]_;V]O;V]O;U]?3T M]/3S\_/S\_/R\O+R\O+R\_/S\_/S\_/T]/3T]/3T\_/S\_/S\_/S\_3T]?7U M]O;V]_?W]_?X^/CX^/CX^/CY^?GY^?GY^?CX^/CX^/CW]_?W]_?W]_?W]_?W M]_CX^/CX^/CX^/GY^?GY^?GY^/CX^/?W]_;V]O;V]_?W]_CX^/CY^?GY^OGY M^?GX^/CX]_?W]_?V]O;V]_?W]_?W]_CX^/CX^/CX^/CX^/CY^?KZ^_O\_/S] M_?W]_?W]_?W]_?S\_/S\_/W]_?W]_?[^_O____________\`````________ M_________O[^_O[______P````$!`@(#`P,#`P,#!`0$!`0$!`0#`P,"`@(" M`@("`@("`@("`@("`P,#`P,#`P,#`P0$!`0$!`0$!`0$!`0$`P0$!`0$!`4% M!04%!04%!04&!@8&!P<'!P8&!@8%!04%!04%!`0$!`0$!`0$!`0$!`0$!`0$ M!`0$!`0$`P,#`P,#`P,#`P,#!`0$!`0$!`0$!`0%!04&!P<("`@)"0D*"@H* M"@H*"@H*"@D)"0@("`@("`@("`@("`@("`@("`@(!P<'!@8&!@4%!00$!`0$ M`P,#`P,#`P,#`P,#`P0$!`0$!`0$!04%!04%!04%!`0$!`0$!`0#`P,#`P,# M`P,#`P0$!`0$!`0%!04%!04%!04%!`0$!`0$`P,#`P,#!`0$!`0%!04&!@8& M!P<'!P@("`@'!P<'!P<'!P8&!@8&!@8&!P<'!P@("`@("`@("`@(!P<'!P<' M!P<'"`@("`D)"0D)"0D)"0D)"0D)"0D)"`@(!P<'!P<&!@8&!@4%!04%!04% M!04%!04&!@8&!P<'"`@("0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0H*"@D) M"0D("`@("`<'!P<&!@8&!@<'!P<("`@("`@'!P<'!P<'!P8&!@8&!@8&!@8' M!P<'!P<'!P@("`<'!P<'!P8&!@8&!@8&!04%!00$!`0$!`0$!`0$!`0$!`0$ M!`0$!`0$`P,#`@("`@(!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0```````/__________`````````````0$!`0$!`0$!`0$!`0$" M`@("`@("`@("`@("`@$!`0$``````/__________```````````````````` M```````````````````!`0$!`0``````_____O[^_?W]_?W]_?S\_/S\_/S\ M_/S\_/S\_/S\_/S\_/O[^_O[^_KZ^OKZ^OGY^?GY^?GY^?KZ^OKZ^OKZ^?KZ M^OKZ^OGY^?GY^/CX^/CX]_?W]_?W^/CX^/CX^/CX^/CX^/CX^/CX^/?W]_?W M]_?W]_?W]_?X^/CX^/GY^?GY^?GY^?GX^/CW]_?W]O;V]O7U]?7U]O;V]O?W M]_?W]_CX^/CY^?GY^?GY^OKZ^OKZ^?GY^?GY^?GY^/CX^/CY^?GY^?GY^?GY M^OKZ^OKZ^OO[^_O[^_O[^_O[^OKZ^OKZ^?GY^?CX^/CX^/CX^/CX^/CY^?GY M^?GY^?GY^?GY^?CX^/CX^/CX]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W M]_?W]_?W]_?X^/CX^/CX^/CX^/GY^?GZ^OK[^_O[_/S\_/O[^_O[^_O[^_O[ M^_KZ^OKZ^OKZ^OKZ^OK[^_O[^OKZ^OKZ^_O[^_O[^_O\_/S\_/S\_/S\_/S\ M_/S\_/O\_/S\_/S\^_O\_/S\_/S\^_O[^_OZ^OKZ^OKY^?GY^?GZ^OKZ^OKZ M^OO[^_O[_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/W]_?W]_?W]_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_OW]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O[_ M__________________[^_O[^_?W]_?S\_/S[^_O[^_OZ^OKZ^OKZ^_O[^_O[ M^_O[^_S\_/S\_/S\_?W]_?[^_O[^_O[^_O_______O[^_O[^_O[^_O______ M`````````0$!`0$!`0$!`0("`@("`@("`@("`@("`@("`@("`@("`@("`P,# M`P,$!`0$!`0%!04%!04%!@8&!@8%!04%!04%!04%!04%!04&!@8&!@8&!@4% M!04%!08&!@8&!@8'!P<'!P@("`@("`@("`D)"0D)"0D*"@H*"@H*"@H*"@L+ M"@H*"@H*"@H*"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D)"0D("`@("`@' M!P<'!P8&!@8'!P<'!P@("`@("0D)"0D)"0D)"0D)"0D("`@'!P<'!P8&!@8& M!@4%!04%!04&!@8&!@8&!P<'!P<'!P<'!P<'!@8&!@8%!04%!`0$!`0$!`0$ M!`0$!`0$!`0$!`0#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,# M`P,$!`0$!`0$!`4%!04%!04%!@8&!@8&!@<'!P<'!P<'!P<'!P<'!P@("`@( M"`@("`@("`@("`@("`@("`@("`@("`@'!P@("`@("`@("`@("`@("`@("`@( M"`@("`@("`@("`@("`@("`<'!P<'!P<'!P8&!@8&!@8%!04%!04%!00$!`0$ M!`0#`P,#`P("`@("`0$!`0$``````````/__________________________ M_____________O[^_O[^_O[]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W] M_?W^_O[]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?S\_/S\_/S[ M^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^OKZ^OKZ^OGY^?GY M^?GY^?GZ^OKZ^OK[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/S\ M_/S\_/O[^_O[^_O\_/S\_/S\_/W]_?W]_?W]_?W]_?S\_/S\_/S\_/S\_/S\ M_/S[^_O[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/O[^_O[^_KZ M^OKZ^OKY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^?GY^/CX^/CX^/CX^/CX M^/GY^?GY^?GY^?GY^?CX^/CX^/CX^/CX^/CX^/CY^?GY^?GY^?GY^?KZ^OKZ M^OKZ^OKZ^OKY^?GY^?GX^/CX^/CX^/CX^/CX^/CY^?GY^OKZ^_O[^_O[^_O[ M^_O[^_O[^_O[^_O[^_O[_/S\_/S\_/S\_/S\^_O[^_O[^_O\_/S\_/S\_/S\ M_/S\_/S]_?W\_/S\_/S\_/S\_/S\_/S\_/S\_/W]_?W]_?W]_?W]_?W]_?[^ M_O[^_O[^_O______________`````````0$!`0$!`0$!`0$!`0$!`0$````` M`````````/____________________________[^_O[^_O[^_O[^_O[^_?W] M_?W]_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W] M_?[^_O[^_O[^_O[^_O[^_O[^_O[^_O[______________P```````0$!`0$! M`0$!`0$"`@("`@("`0$!`0$!`0$!`0$!`````0$!`0$!`0$!`0("`@("`@(" M`@("`@("`0$!`0$!`0$"`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(" M`@("`@$!`0$!`0$!`0$!`0$!`0$!`0("`@("`@(#`P,#`P0$!`0$!`0$!`0$ M!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0%!04% M!04%!04%!04%!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$ M!`0#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,# M`P,#`P,#`P,#`P,#`@("`@("`@("`@("`@,#`P,#`P,#`P,#`P,#`P,#`P,# M`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P("`@("`@("`@("`0$!`0$! M`0$!`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@,# M`P,#`P,#`P,#`P,#`P,#`P,#`P,#`P,#`@("`@("`@("`@("`@("`@("`@(" M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(#`P,#`P,#`P,#`P,#`P," M`@("`@("`@("`@("`0$"`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$!`0$```````````````````#_________________ M_____P```````````/__________________________________________ M``````````#______________________________________P#_________ M_________O[^_O[^_O[]_?W]_?W]_?W]_?W]_?W]_?S\_/S\_/S\_/S\_/S\ M_/S\_/S\^_O[^_O[^_O[^_O\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\ M_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_?W]_?W\_/S\_/S\_/S\_/S\_/S\_/S\_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_/S\_/S\_/S\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W] M_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\_/S\^_O[^_O[^_O[^_O[^_O[^_O[ M^_O[^_O[_/S\_/S\_/S\_/S\_?W\_/S\_/S\_/S]_?W]_?W]_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^ M_O[^_O______________________________________```````````````` M```````````````````````````````````````````````````````````` M`````````````````````0$!`0$!`0$!`0$!`0$!`0`````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`@("`@("`@("`@("`@("`@("`@(" M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@(" M`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`@("`0$!`0$!`0$!`@(" M`@("`@("`@("`@("`@("`@("`@("`@$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$````````````````````````````````````````` M``````````````````````````````````````$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`````````````0$!``````````````````````$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0`````````````` M````````````````````````````````````````____________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M______________________________________________[^_O[^_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^ M_O[^_O[^_O[^_O[^_O[^_O[^_O[^________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____`````/__________________________```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``!#3TU-````$@`!``"2```(0`VL1````````$U!4DL````"``!)3E-4```` M%#P``'\`?P``````````````````05!03````:A39#)A``(```````````#K M`.P!+@$O?_\`HP#L`2Y__W__`````````````````&>0,```G(@`.`!B`#@` MU@!+`&(`2P#6`$\`YP!/`/<`O@#G`+X`]P##`1X`PP%@`,0!'0#$`1X`Q`%@ M`,0!80#%`1P`Q0$=`,4!80#%`6(`TP$<`-,!'0#3`6$`TP%B`-0!'0#4`1X` MU`%@`-0!80#5`1X`U0%@```````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````$"```````"0`C```````` M`````````'@````$``0``````-'^`/___X`````!`2`&455N:71S```3""YP M9W-Z```)'E!!5",```DJ3%=25P```````0)&!B!S86UP3[_P``(F`21')U;2!/9B!%87)T M:'%U86ME(`(```!!249&4V0R80``04E&1E-D,F$!`/____\````````````` M``````````"G/9LK``"4#````>BDX[7XIIM-4@``````+`#B`1`".P$``+0! M*0&`__C_[````````(`````````````````````````````-`````2$'4V-R M:7!T3[_P``````M@!*`7(!W@$``)``Q@$`__C_ MXP```````(```````````````@``````&@`I``\!JP)@`"H``P)M`ST`O0#! M`8("40$`````&@`I``\!4`'Q`"H``P)M`ST`````X#;__P``````&@`L`!8! M/@'<`"H``P)M`ST#,P)M_,$";0``````&@`````````````````````````` M`&`````````!`````7X```!^````:@!QVJ04D@```!P`:@`!5W-T80`#`!)3 M1$]#````0@`!__\````&```````"__\````D```````#__\```!"```````$ M__\```!@``````/H__\````````````````````````````````````````` !`/\` ` end nethack-3.4.3/sys/share/sounds/firehorn.uu0100644000000000000000000004370207764735041017302 0ustar rootrootbegin 644 Fire_Horn M``E&:7)E($AO[R]/+T]P0*^_O__@#X]/X0'QX3`^WL]^SD[OH" M`/3LY^7JY.P/("OQ[>CH[_#P`Q,1"``%!_[]].ST_P'Z\>[N[_8` M_PT:`?;^]?C_]OP.(2\H%PH2("`J,BLT,!DA,!X+"`<1(1\#X=74V.?S_0@& M_N[0N[B]S=[O`Q06_>3G\@@?)SA$/28,_O'Q`0\<+S,D$?7:U.?MZO\3$@3R MXS<6X ML;G4`!D7#@#\`@H>-DI985D_'0\0#`P5*3HY,1CV[_'GX>[T^`'YY]+`OKB] MX/L$_N73S\K0W^WY!1`4#P/NW=KI^OX!`.;-R\S/V.'BY_;HR;FSLK"[W/+Z M^>GG[.3D\0`'#!($\NOCZO@%&BHH'A,-!?OV]?8!&B(/]>;>W-W6U^SX[-O3 MU=K@Z?<1*B\;`_?U``T*#R`H(Q+][N3CY^O_%!L9!N[AY_7V_Q8?'QT2!@#^ M`0PA+R\@`_/]"A0<+$%!.S,<#@?^_`D?+"PI%O;EYN_["Q,(^_#CW-S?Y?L> M+B\U)@L"`@0'$RKK\?<$$0_^ MXM'0UN?^$AXD(1D-`?;U`1$N3$XX&?KEX_D0'2D@"?GCRL#*VN\/)1X-^N;< MWNCT_@@*`_OOX-'*T^X+'!X3_]_'Q,G7[P0-$0W[[.[MWN0!#PX/`^OJ^0(0 M'B@Q.#8@!_GP[/H7)B8E&@;Z]?3R[>[T`0;OX.3CW.7]"R`\*04#`OCW]^_J M\.W9SM+-RN(#"@+WX=_T^N_H[?'S"!0!\O/T\?/_!?[SX]KG^?W\`@4'!?GS M_00$"!HL,"@7#10I,QX,$A43&B`>%@W_^0XG*1T0"Q`=*28>*C0E%@KXZ^/5 MS=SN[>+:UMKP`OOZ"@X'!PH-$`P.&"U`-R4?%PL(#A`6*"\C&Q8%\>#,Q=KJ MX]KCZ>+O`OK]#`P*$QL2_>[=U.D'(CHW&?OV_?KX_@`""PKZ[N?;U-KBY>CK MY.+R]^OI[_/]#0GNX^WV]_+R^`()_>[S_/P"#!(:(!<)_O;O[_7X]O+JV-T,W)!,(!0T?,3(D$O_V\^KL^P<2'2(<"_KM MZP`G.S`B&`?^``8,&2\Z/#TQ%OKHY?`&'B,7`O/IXM_A\`03&18/`_7KZ?@5 M*3(S)10(`0@8'R$I-#SW_0H-`//GXN3H\@$,$0X"[N7D[`89&A@1 M"`(#"!$D+B8C)!\8$@L%#!89$@'NW=?@[OL&#`?[\^;3S\_.V>OW\^+5UM[A MY>[_$Q,$]=S&R]74W.[X^^_5Q,'(V^SS^P$#__;OYN#:W_X9&0+IUL_H_/?[ M`P+X[O/VZ^3AX_'Y[]?$P\;,T]C?Z>WFW=G=Y>KP\_7WZM#&U.L#%!<0#`C\ M\_'NY^GX`/WWZ-3*TN#L^0'Z[.+AY_,#!@@3'!H.`/7MZ_`$'BHE'1P<'",L M)RDW,A\+^.;@ZO+W#2(:"0/__0,,$!4F,B8/_>OB\?T&&B8:`?7PZ.;H\0H@ M)"`9$/[EV.,`(B8/!0T-_P$.&C9(-RPN)QT+\_,-)"DI+S@X*!X>)34X*2`C M)B(6#17M`1HE%?ST^_?R_P@1'1<'^OS]]OD"#AD0[<.OKK;+X?'Z_??FVL_#T>P! M%A\?&/O8LJ;']1$7#P7_^-[&T_0-%!43^,^VL;W9_A<>(B09!?/T!QXY2$8[ M*`7>V@4O.3@W)Q("Z]O;Z`(?,SP['_'2T.L+&1PA*RD.[^X%'#%"2DM(+P#> MX?L7+3@T*!D(^/@$"!0L+AD!X<:[P]OO_08&!/;?VN?Z"QLP03H@"/KY$#!) M54X[&/3K^0X;%@X2&0C@O**IOLS@[.WHT+JRN]3D[0$8'`GVY,K$U.H'(281 M\NKW!`T0$!DE'P3JV<_+TND!#@T`]?'W^_3Q\@$0#@@&"Q,1#B)-8$(3]/8. M%PX%_P8+`>_H]OGJZ^[JZN_OZ?+]_/X#_.OM^.WM_?GM]0L."Q@.!",[.3$G M'A81"OOU^?OS\??LV=7D`A03#P@!_?G]`@<1("HD'!\@(B4?'RDV.BX:`.SQ M_?;O^P@![-O+O,/;]`0&`_3>U=/=\/O]_/+ODXM7$ MR^4"&Q7^\>KEW^+^'"$6"_KKZ>CDX_(/'QT8"?3O\O@&#PL(!_CGX.'HY^CT M`0?[XLG"UNX&'"$;"_'8R,3+U.3Y%2\R&P8'%2(N,R@<&A,#]O7X]?L,%QP- MZM7:[?7T`Q44"P$"$Q;]V/R!A4&Z>L$ M&A8(&#([+AD8'AL1_?4+)3`H&!TT.S`B&!L:__,"#PW_\O4&$`P$^?H&"Q(< M(RH@"@D9'!$$^?<##PH"`0,&!`$#"Q4._OK]_??JZ/8!!/OU\.'B[_H,%!,+ M^_'MXM''S>'X!PT%[-G>[_OX\/#FV]O/Q='=X>+=YOCNU,G(U>S\`0,#^NWN M]O7O[_7\"A#^Y]G6Y/+T]0(-!0+_ZNX)$1$;)B@@&1<>)B??W-KD_08'#0?\]?3NW^#V#A82#@D- M$0\6&A4)^O3HW^;EZ?@(#O[IX-?7V^H*'1@*!`0$#1,2'2XS*2$8"/?GX_$* M&`#DW=GGD[.WG]/GM]?CEV^'?V^X!]N7BYN/F^`0'!0`!"`P+"`/Z!!TC&`/LY-[7 MW^;@Y.O@U-7,P\S0R=#G[^7>WM;0W.39VN\`$1L7$@X)"QTM)QL:$/_[_OGQ M]P82&A\6`/7NY_0%!/___?GY]_H"^_P-%1@9$P#GY@(5#@XC)Q\>#O?^$QHD M.#XS)!$""!X@#`@6'QT2^-O;?Y_,,)BL@'R(?)"XH'!TC%@,#`O+M_`8+%!<'\O(! M"Q0<$P+X[-_C[-W)T>?Y"A<0__X&"APN)`X!]NGJY]#/ZOT#_??Y]O'W_PL; M&@/MXN/]%/_DZ_C[^?;S]?TF)Q8,"A$;$_SS_@X1#0D,#@<4,3(?$0+N MZ?D&!?SU^000%Q`-"`85(AX8&0??U>/FY.'K\\=W*N;J^L:_.[?H+$O[O[=S`Q^X'_^;9 MX.WZ].H`)"TA#O7Q_O/7U_L9#.[I[.OJV'-W@LG%?7JY^3A MX.+P!A(:'1``^.WI_A<6_//^`?;Q]/4#%QTJ0#\A!O7P`A<;"OX.&0T1(R@G M*2XU,"$-_?S\^__TW>#Y!P@.%0'Q_PH9+2,.#0[]\@@6!O\+$!8G+1X?+#$\ M.B47%A4)!104^_+\]_4'!_#J_PP1'!H*_.W;T]OEW-;D[?+\`O\&&B`6$`;P MVOJUM+G\^KCW,_1Z/7_%R(-\N+=]1@4^_H/$P#U]_T/)C0Q+"X;_/3S M`!D9!_\'#`3X[>7E^`T-$1X4^_'Y`@3_^/D($1$-"0D'$"HP%O?DVM'/U=KG MZ>;IV]7H[]_<^A(2$P_\\O+Q]?\&_O7\].;N^OD#'"@J*!/X[?+W^/CTY^?U M[=G=V\7(X^SN!AH&[N??W^#8U>'[#!,7%14;("(O1$(I&A$&`O7@Y/X4(RDA M#O;BW-_L"1T6#Q01`-_)S=CB[?H$_>34U>#V"@X'%"$0]MW#M\7?\PL>%/GB MW./C]A$+$"$5^^7=Y>_X"!XW/2D0!`D;*"$5$PS^]NO@Y.WZ#!@8#@<$^_?X M`A,.^>_T_OSV]_X-%A$1'"DN+2/7UMK:\@P%]OCX\_GZ^0((#@O_!/G? MW./L`Q+^ZP`+``85'24V.A\4'A0`^?3S"B`1`Q(;%Q,2$!,6"@86$/'!-G-U-++T^\+ M(RD7#A,6$`,%'#=#,Q/WZ=S"MJM3Z"Q8? M*C(>_N[W$2,H(AD0\'T!081)2(+\-/$TNOP\!4W*A86"P`(`OX;(_S;TL_<]`$!"B@O%!0M+RC6R]/CZO\9%AG8TN'W!@D!`B(^+A\B(!4`X-#P M$0;U]P0(^.[S_`\@'QPG)PCHT];Z"0('"Q,:$@7_"!PF*RP>#0#PW=WU^N_O M]P4&_/C]_P`'#Q@H*!/][N?BZ?\*"Q,2!P8+!P87*BL=%`X#\]K.S/>W.SZ_/+EXM_1NJRSP=+FZ>S^!_?K]`,:,"8."Q((\NSZ!P@"]>CI[>;> MW_$,"OT!`O74N+2]SMG4W>KNZMO<]`XC*27R`1LV M-"<@&`OZ^0L9'2,G*B<@&1,3&2$P/#8@#0'Y_@L3$@L)"?WOZN[Z!@4)%0W[ M`0H&!P\0$187#P@&`@03'RTZ-R84#PX,#`8#"`+NWM_HZ^WT`!0>$//@XM_7 MWNKX!@3Z_`@0"_T!%2(C&PP)$0P!`@@.$@?LX.GJW=OG\@`&]NW_"_?E[O?T M\?'P^Q,;$0\1&20?%A,>(1`.'1T3!_?U`@D&!PT0"P$$!O;^&!86)B(1`?3R M]OL'%!\:`//U[N\"$`X8)P[MZN+:Z/3X^_OOW-38V];A_0@)!>_AYM_7Y/L* M$0P`_0,(`?D/*R@@%//:ULBYS_7\]N[6Q\G/R\?6YN;@TL;-U=;>`!P7#PL' M$!$&`0TN2$(G%`K^\.#D!!P2]^3@W=?8W>X/$^[4S,&^OL'WR`0H0#PP+`??[^/<4,283$PL+&1@A+RCR`Q,;&!,1#@T-"0H0 M`/,##?GL[_8""`0+%@KY^_WNY.GLW=7K^.GL^O\.%@P0&1()`P()$AD9#`P> M'`3]!Q@H(Q4>*A7\^OT!`._>U=;F\.?A[@#^]@4;&PC]_@01"OC\_?D%`N_M M]O3GY_T2%0S\\P$$W\G8X^?N[.?N_O_N[0HF)A(!!`KNQ\+*TN'HXN/NZM?) MT.O[].KI[^O/M+?(T=OG\OW]\>GA[!,G&Q,7&A+YY_'Z\?8%#141`O+G]`\8 M%1<3!?3K9W.?K`1LA(B(/_OGOZ_L"_0PE)`OW^@(%$2(J.4$C M$!,#]?O\`2`R'0/\`@8#%CQ485(D#0P"_PCG MYN7CY.GN^/;K_A48(B`/%1@(!0G_\.KKZ^_W^O3V"`G\`@<``0$%#?O@U]K= MX^GK[O/[#1H8("`,"0@#"@7Y]_3T]O/V!Q<<'Q\8'1\5%1(4$O3F\?3U^?+R M`0;\!!HF-#DE%`X']^7CX^'?UL_;[N;;[0`(&R4>(B47`.3:U\_7Z/0!_.7@ M]Q(>*2XH)!7YX,_0U,_/T]WNZM/-VN7H[/;U[.GHWL_.S\G,W.ORZ^'E\@08 M)S4],!8'^^GL_``$"0+QX=K?[/H$"`S^V\;/VMOCY-G:X-S;V-/?]A`F.D'EYNS["1\R+2XI$/[S\/H(#/?;T]SK\_@)'#5'04=$(PX.#Q`9 M$_';V-WH\?G^!10._P8&]?#S\?/^\-+&P\[E]``+#Q47'C4X*2(@(2(<"_;I MXN?U_@8/"P'S\@(#^_T"`P,'!/#CVN'X`@@%]_P$#"`D&!04#0+]]>OJ\@DD M,2\8!0P-#Q\9#!(4`NKHZN+CY>T%$@KW[OL(J(B4@`^_QZMG6V-WT"`#N MZO7W`B$J(2(6^^?9R,+/UN8$"OOT]@`'%RPQ+R8/^.[JVK]^>'.RLO( MUO#_`?CLY=O-O+[8ZO<*"??M[?<#%"\W*R$6"O_RY^3M^0(-#__NYN/@Z/S_ M^/7O[.?@U,O4XNX!`^[DY>CU#1X:#PG__/SJV-_K[?\<(143$A0A)RLN*2,< M%0T`]>_J\`$:(0X(#ADL,#`T*1X?(!\.^.WJ\`0:&@T-$1,8$QDF&0<'"@?Z MY]7.X/\=)QX=)BPK*38^+!4/%1D0]=?2Y/@+#_[W^O'G[/?_]NOR^_?CR+W% MT.4&%A8=&@8$%B@H%@H0&Q<`ZM[F]P,3'QP4_NKN_`D+`O\-&PSNV];;Y_83 M)2$7`N_U#1\B&!0:%@;NX_,`!!,I+"`9">_T"!$4"P+_].32P\K?Z_H:*AH- M`_+^'C$[.B@9"O7?S=#D]`<<%/WZ[=KL"A8C)`KRY]S'N<+8\0\@%@L4$@82 M)R\V+0OR[>38V>+N_`'\\>?@T<35]0@0`N37U,:ZO\_D^P/W[O<'"`,3+3,H M%/WV_/GL\0@9(A@"^?KTY>+W#Q(']-S/T,S&UN_OZ>OEW^7O\OL:)Q4)_N?? MWMC?\@8,"`7U\0$,#A@L+A@1">[FY-_G^PL,$10*"A$4'S9-33TT*!,'`/L" M"P@%#A$&`@8-%2$M*AL:&@?Z\NOKZNOP``D%#!4:*CI&13,I(A4/"P8#!0@* M$`L!!P@&!/\)$0#U\^?;U]#"P='>Z>OI^@L*"A`A*1H)_/@``/CV_`8)"P;^ M!PT"^?T*"?[[]_CYZMO8W^GN\.OP!PP"`Q$C*B0:$0P$_/H`!P4&!P`&%Q$# M!A]P@(#1PE)1\6$@GV[/#^%"7F^Q&147'2`>$P/_"A@6!_SU_0H!_`<'^>GBYNGCTKZ]U>OKY./L M!!<3#Q88$`3Z`Q,2`O/R!1D;!_?V_@'TZ_8"!@+]!`X$Z]O:Y//W\._S]_KY M_@@-$A`3)BL5__CY``D0#@P.#`D$_P(*#@P'!P+PW-+8Z?D$!PD)"`T-"A,; M(RDD'!0,`/?^"Q8B(QP1"0?_^/X)&R06`_WWY]G@[O<"!__[!`H#_@<3(RTE M&!(-_?']#1`,`??Y^O+CVN+L\?'DUMC4Q'J]?OX]@42$`;]^OKU M\_D,'AT._??\^_SZ]0`'^O'R[>'8T=_[`_/?U-3:WNCU^@$$^O/U]_3O[P,9 M'!4)_OK]`@X6$!`2"`0'!OKN\?P'#0D!^?/V_@\A'148&AH8%A,.#A(7&1P@ M&`T'"!H@!_D!`?GX^/7V]_;[!0H+!_OV`A(2`/L#`@0-$AHA%P<'%1P?'0\' M"@T`[.KP[.7CZ//WY=GA[??^`/O[!PO_\_H`]^_S^P,)`OCZ!1$9'!4*`/GS M[O7_\^3H[>WLY./O_`0#`/CIX^7HZ_X4$04("`$`_OK]"QD@*B<.^?3R]@PA M%/_]^.OGYN+K`1$9(!D#]O?X^Q(N*Q@0"08,"0<-%B,R.#`="?SS\@4@&O[Q MY^#DZ.WZ#Q\@(!@(_O/O^!$K(0+W]?;]_OT)&!H4$Q$'^>36W/H2`M_/S,S/ MS];L_?[W^/OV[N+9Z@D6`N?AXN;M[/()&!0+#A`*`?'J]@H3`.+3T=/5U.+] M`OCR[^WIX-33Z`0-_NGBXM_D\/T0&QD0"PX,`OCX!1(;$_OP[NOM[_8*&AD1 M$1(/#`@(#ATN)@\)"P@'!081'2,A&AH9$`8$"0X/`_'L[_'T\O0%%1<1$142 M#/_X_P8,!O3P``H&_O\*#@\.#0\1"?GX`?[X[=[?[O3JXN;N^`'__08(]^_] M"07\\>7K``;\^`$*"Q`6%181_O4%$P?WZM?7Y^SI[?3Z_@,+"P?^\?0/)R(2 M!_GQ]OK]`@,$#!<=&0W]]0`8*",5"?;I[//[`?S[!Q,:%`/S[_\7)209"_KL MZ?+_"08%#1D?&@W]]`$8)R48`^;/S=GL^_T!"Q`/"O[PZ_4*&QX7!>S?X^_[ M!@@$"`T,!OONY^W["`L"[]2]NLO[Q\_#KZ.S["`?]\^7:W^_\!@D' M`@('!@0&!PL4%PS\[]S'R-[R_O_X[^OLZN?M^`$+#P3U[^73U_('$`\%_?K] M^?#Y#!8?(1("__3>W?$`"0D!_/CU[NCY#A8<(!@+"`+S]0H7%A`/$`\+!@86 M*"LD'A('`O;H\0(%!0<'#0X'`@(+&!,*"P3[_P,!!1`0!P'^``+^_0$(#Q$, M`_CO\/7W^?WU[.GHZO#S]?L#!@/_]^GAZ_L$"@P(__;S\O/W_``)$A41`^S= MX._X^O__]NSGZ?+_!P8*$1(/!O/F[?T#!@L*"`/_`@<-$Q$5'2`B'@[_!1$. M"0T,`O?Q\_H#"`(!!@8&!?OW`Q,3#PX(`/SY^P,0%A(4%@X*"OWR_0H$_@#\ M]._IZO8&#P\)`/7R\^WJ_`X0#@T%_?GR[?0`!`+^]>_MZ^;E\O_Y\?#NZ^;; MV.GZ_O[Y[>3@V=7=\?_\]/+U^?7O\/H#!@8$``#]\_/_#`\%]_#R]/#L[_?^ M`@'\].SDW^H!$!0*_/;X^OC[!0P-#`H)!?[V\@(<*286`OCX\_/_!PL0$A$1 M#0'S\0(8)"8;"@/_^?L&#Q,4%1<8$P/V]P06)241_?;R]/\.%!`0#PP-!_OR M]`$/&AP/`?KS\P$+"`0#^_K^^?#M]`(,%!<*^?'J[/T,$`X'_?K[]>_M\/D% M#0P$^/'O\?\*!@,"^_?W\N_R\_G___[YZ=_>Y?H$__OW\>[MZ^_U]?C^_/[^ M]/+X!!$4#0<%`_\```,)"0T4$`T*`/T!"!,6"@0%_//X`0P6%0\+`?S\^/D" M#!88#PD'`?T``@0(!@,%_O/O[O'X!!`2#`P.`_;W_``("PH,!_SX]_H`!`@% M_?\"^?3U\>_T]/3Z^/#P]OO]_@0#_/T!_/GX\N_S]/7Y[^;N]_\$!`<%^_L# M!`<-"00%`O[ZZ^/M^@8-"P@#]>[Q]OO^^OD!!0'][^3M^P_T^@0.#`D(`?P"#!(0#`P0 M#P;]]._Z`@80$`P(_/8`#1(2"@,$`??S\O'Z`00(`_GRZ.OZ!@X.!@(%_^WH MZ^WX!0H,"P7Z[_#[!PX/"@4!^NWM\_8!"@L-"?[RZO#]"1$3#0H)_>KBX-SF M]/K]^_7OZNWX`@8$`?[Y\>SO\_0!#0L%_?/N[_0`"PT*!@#^_/?Y_?T$#PX& M_?H``P0.&R`<%0P&`/K\`0$'#@7UZN?N]?P(%AL4#`/^__[]__X'$`7W\/+^ M"`L4'A\8#@4#`?T!!P8+#P+QY>/L]?P&#Q`(__GV]O?\`?X!!?GKYN;P_P@- M#PL#_?K[_/G_"@D*#0#PZNGP_`((#Q$+`P`!_OT#!OWZ_.[AY.CQ`@T.#0L' M`P$```$#!/_^_O+IZ>CM_`$!`P,!``$#!`4("00"`OGQ\_SL\_K]_/T#!0(`_?X!^O+U^OO[]_#N\/7Z^P$* M#`L*!P<'_O7U]O?U[^GJ[_+V^?P"!04%`@#^]O+U^?O\^_?V]OC\_?\%!P8' M!P8"_/?W]O7V]/'Q\?+X_?X``@4)"PH(`P`"`0```?_]^_X%"0@*#`P.#@L& M`/[^_?O[^_K[_@('"@D)"`8&!P@'!`$"`?\``?_]_P,)#@\/$`\.#`@#_OGV M]/+R]/7T]/;[_OW_`0$#!0,"__S[^_K[_?W[^/?[`00%!@<+#0H%`/KX]_;V M^?W]_/K\``$"!0<*"P@&`OOV]/+S]_OZ]_7X_/\"!`<+#`H(`_SW]?/S]?CZ M^OO^`0$#"`T1$1`0#PL%`O\``@4'!@8*#`L-$!`1$0\.#`7^^O?V]_G\_?O] M`0(#!08&!@4&!P+]^OCX^/K]__\#!P<'"@H)!P,#`_WT\._N\//U]//U^?S] M_P$#!`'___WY]_7R\O?\^_G[_P(%"`H-#@P)!?_X\_+R\_?[^_GY^_T``P0& M!@0#`P'\^?CX^?S^_OX!`P,"!@H.#@P*!P/]^/7T]?CZ^?G[_@`#"`L-#Q`. M"@8"``#^^_S_`0$#!@<("PP+"PD&`__Z]_?V]OCZ^?C]`@0$!PD)"0<$`@#\ M^OO[^?K[^/;[`@4&!PD)"`7^^_GU\_/S\_7V\_#T^_W^`00("P@"__WZ^/CY M^?O^^OC]`P8&!PH-#PP&`?WX]?/R\O;Z^?G^`P4#`P4("@@%!`/_^_KY^/?W M]_G^`P,!`0,%!`(!``#]^/7T\O#R\O3[!`<'!PD+#`L)"`D)"`<%`P$!```% M#1`0#@T,"04#`0$"`0$!_OOZ^/K_!@H+"PH)"`4`_?W^_O[^_/W__?P!"`P- M#`L*!P+\^/?X^/CX^/?V]//V_/\!`@($`P'^^OGY]_;W^/G[^_O_!0@("`D+ M"@8`_/KX]/#P\?/U]??]`0("`0(#!`,!`/[[^/?V]?;Y^_X#!P8$!`0#`@#_ M_O[]^/7S\_3V^?T#"0L*"`D+"@@("0D(!@+^^_O^`0,%"0L+"@D(!P4%!`,# M`?_]_/S^_P(%"`D'!04'!0#\_/[]_/KY^/G\_/T"!P@&`P,$`_[Y]_;V]?/Q M\/+V]_;X_?___?X"`P'__?S[^??W^/G\_P$#!00"`0,'!@'^_/GV\N_P\_;Z M_?[_`0'^_@`$!@0#`@#]^?7T]/;Z_O\``@(``/\``0```/[Z]O3S\_7Z_P,% M!@4%!`0$!@4%!@8$!`,"`@,%"`D*#`L*"0D*"@D(!P,!__SZ^OS_`P8%`P,$ M!`,$!`,#`__]_?W\_?X!!`8&!@8'!P8$`P$`__OX]O7U^/G[_P$!`/___P$# M!`0$`__[^OGY^OP``P4%`P("`0``__\`__SY]_3R\_7X_0`````!``#__O[_ M`/[\^OGX]_?X^_W^_P$"`@+__?S]_?S[^OGX]_?X^_X``00%!04%!`,!```` M``$!`0("`P,"`@0&!P@'!@,!`/_^_?S[^_W^_P$!``$"`P,"`@#^_?W[^OK\ M_@`!`@,"__[^___^_?W[^_OZ^/;V]_G[_0``_O[___[\_?_^_O[^_?S\_/[_ M`00$`@$"`P(`_O[]_/S\^_KY^?K[_/___O\!`@'____^_OW]_O[__P$"`@,# M`P0%!@8$`P,"__[^_O[]_?\``0("`0($!04#`P,#`@("`@(#!`<)"0H)!P8% M!`,#`@,#`@$!`?_]_/W_``(#`@,%!00!__________[^_OX``0,#!`4&!0,` M_?S]_/O\_?[^_?S\_/S[^_X!`P,!_OS[^OGY^OS^_O\``0$`_O\!`0$!```! M__W\^OK\_/W_`/_]_/W^___^_O\`__W]_/O[^_W_`0(````!`?_]_@`!`?_^ M_/OZ^OS_`0("````__[\_/W_`0(#`@$````!`@0%!04$`P#^_?W^_P$"`0#_ M_O\```$!`0(#`P'^_/S\_?W]_O___O[_______\``0#^_/O\_?W\_/S\_/X` M``#__OW]_OW\_/S\_?[^_____P`#`P,"`0$"`0#^_?W_`````/_]_/W_```` M_OW^_OS[^_S^`0("`@(!_P`"`P0%!@8&!0+__?W_`0("`P(`_OX``0(#!`0$ M!`'__?W_`@0%!@<'!00#`P,$!`0&!@,!__[^``,$!`0$`P("`@,#`P,#`P'_ M_?S\_?[_``$!```````!```"`@#^_?S\_?[^_O[__OW]_O[^_?S\^_GX]_?X M^OS^_O[^_O[^_O[^_O[^_?OZ^?GY^OS^_O[]_?W]_O[^_O[^_OOZ^OO]_O\` M`/__``````$!`0$``/[]_/S^``$!`0#_``$"`@0%!00#`?[]_?[_`@0%!00" M`0(#`P,#`P,"`?_]_?X``0(#`P,"`0$"`@,#`P0#`?[\^_O\_?\`````__\` M``#__P#__OW\^_O[_/W^_O________[^_O____W\_/O[_/W_``$#`P0$`P(` M````___^_O[^_?W]_?W_``$!`0#__O____[^_O[^_P`````!`@,#`P(!`0`` M`/_^_O\``0$`__\``0("`P,#`@$!`/___O[^``("`0$!`0("`0$!`0$!`/_^ M_?W^_P```0$````````````!`0#^_?W]_O\````!`0(#`P,"`@$!`0$!```` M``$``/___P`!`````/____[^_O[^_O[^_O[^_P`!`0#___[^_OW]_?[^__[^ M_O[]_O\``0$``/_^_O[^_O[_`/_____^_P`!`0$!`@$`________````___^ M_?X``````0$`__[^_?W^__\``0$``````````0("`0$`___^_P`!`@,"`0`` M``#_``$!`@(!`/_^_O[_``$!`0$!`0#___\```$!`/_^_?S\_?W]_O[__OW] M_?W]_?W^_P#_______[^_P`"`@$!`0$`__[^_P````````#__O[^_P```0`` M`/______``````#___\`_P`!`0$!``````````$!`0$`______\``0$!`0#_ M_O[__P`!`@(!``#__P````$!`0$``/____\```$!`0```/\```````#_____ M__\````````!`0$!`0$````````!`0$```#__O[______P``_________P#_ M_____O[_``````#___[^__\```````#__O[^_P``````___^____``$!```` M____``$!`0$!``````````$!`0$!`/___P`````!`````/___P`````````` M````````_____P````````$!```````!````_____________________P`` M_____O[^_O[^_O[____^_OW]_O[^___^_O[^_O[__O[______O[^_O__``#_ M________````````_____O___P``__\````````````````````!`0`````` M```````````````````!``````````$!`0$!````____````````_____P`` M````````````````````____`````````````````0$!````____`````/__ M________``````#_____````____________________________________ M________________````_________P```````/____\`````________```` M````______\`````_________P``````_____P```````/___P`````````` M`````````````/__`````````````````````/______________________ M______________\`__________\```````#_____________________```` M``#__________P``````````````````____________```````````````` M`````/____\`````````````````````````____````````````````_P`` M````````````````````````____________```````````````````````` M```````````````````````````````````````````````````````````` M````````````````````0T]-30```!(``0``+Q8`"$`-K$0```````!-05)+ M`````@``24Y35````!0\``!_`'\``````````````````$%04$P```&H4V0R M80`"```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````(````````````````````````` M````````````````````````````````````````````````````````!`@` M``````D`(P````````````````!X````!``$````````_`#___^``````0$` M!E%5;FET````'@```!6__3_\O_P_^[_ M[/_H_^?_Y__N__@`!P`8`"@`-0`_`$4)1FER92!(;W)N`@```$%)1D939#)A M````````````````04E&1E-D,F$```````````````````````````````"G M/:W$```Q(@```<[_G_^L_\P``@!&`(P`R`#R`0D!#P$)`/P`Y0#'`*<`A@!E M`$0`)``$_^;_S?^[_Z[_J?^H_ZO_K_^R_[3_LO^P_ZS_J/^G_Z3_I/^C_Z3_ MI?^I_[/_Q/_=__\`)0!.`'``BP"=`*0`I`"<`)``?P!J`%8`0P`Q`"``#P`! M__3_Z/_=````&@`I``\":@,Q`"H``P)M`ST`*0`/`D$#(@$`````&@`I``\! M4`'Q`"H``P)M`ST`````````````````&@`L`!8!/@'<`"H``P)M`ST````` M````````````&@`````````````````````````````````````!`````7@` M``!X````5@!QN+P8G1_?'IX:50_+!\8$@P&`?OY^?GZ`AM$9G5Q84DW-4%/4T]&-R8G0EM7 M0R\9_NG:TM':\A@_6&!:3C\Q+30Y-S(R-C@U+B89"?3>S,/,ZQ0S.BL2]][+ MR]KJ\OG___CLY.#>W=_BX=W7UM_V%"PR(@L"#BA"6&5A5E!)/#$L*RLI)R(9 M#@H:.E=B7D\[)104(R\O)QP._?L2+S8##@?UX='(S=[N\_'LX]7'RMG@ MU,:XK*FOOMS^$Q<.^^36WO8.'",@%P\*!@+^]^S=R[>FGJO1_ALG(Q#\Z-3* MS][O_0D)_>W@V]K;WN'CX-S?[@$.%QX<$`+^$"@P*R08"?[V[>3:T,S+RL?` MOLKB^`(!]^[HX^+FZ>39SL*UK;+'W./CW M#0']``@4'R`5!/?^'#E%13PM'Q0*`O[Y\>KGZ.WT_@<*!?SPXM;7ZP<9&P[W MW[GVL[(U?PI/SPK$_WP[O<% M#@\'^NO=U][K\_#FV,F^O]#P"1`)_.W>T=+J"!85$0H`^?+JX]O4SLO+SM3C M]P$"__GQZ^3>V-'(OK2KI:*GON/\__7AQZZCK3?X_(`!0+]]N[E MW]W;U]+.QKNQM-'^(C4V*1L6$Q`."P+VZ>/DY^GM]/CPW\JXL\7E``P,!?SU M^Q,D'0KYY]G3TM?=X-_;U,O(U.K]!@/UY^'F[_?\_?CMX-OH##1,444I#?T" M'#E&0C,B%Q(3&R$?&1`*!P0!_O;IV]/-P[S&Y000"_[MXN'I\?/R\O+T^@$$ M`/OZ_/[]_`8<+2\A"_/EY_<8-T`V)1#][-K+Q\O.SLS(QM;[(3?X]N[?SL&VJZJT MQ,[/Q[_&X/P)"/_SZN;GZ.;?ULW%P,#.Z_[^]>C4P\/9^Q$6#P+T[_4`!PT1 M#P?]\NC>V-?;W-3'NK;+\A$<%P?W[^SL[O#P\/'OZ>#:U-#2VN+H\@<>)!D% M[MG.SN($&QX9#/_[_?X!!@@%`P$"#!PH*2,6!_OOX]O8U]71S,C#Q-'E\?7P MYM[A\`<:)B@E(B`?)2LK)B`9$0P*!P'X\>[M[/00/%YI954\)AH9)3(X-"PG M)B8E(Q\5!?+?SL7)WO4!_>[:R<+-Z0$%`?7CU=#1U]WDZ_/V]/7_#!`-`_+A MV=SE[O;W].[K[?D1)RH="O+>UMWR#R4O,"TI)B4D(AX;&!,)__;P[O'Y__WU M\`(G0DE$,QP-!P<-%AL:$PL`\N+4S,K-T=?:W.?]$!0+_.OBZ`(<)!\7#`#Z M]_C[^_;LXM?,Q]+J_0+[[=O)O;O#S=/5T[BU,K*WP4C*R42^^KCX^CL[.KL\O?X]>_IY^KMZN7B M[007&Q0%\^3F_AWBUM#=^@\2!>[6R,C3 MY?D*$Q83#04`_P#\].C:R\//ZP41#?SFVN4%(2PK(`SXZN3EZ>WR]O7OY^'G M]?[^^//S]?;T[N7SDWM?.R=#@Z^O@SKR[TO(! M_O3BTLS,T=CWP M]OT`__SZ^OKW]?@'(#E&1#[W#B@X.3(J M)R'R"1XG(!@1#`X5&AP<&1,-!@'\]N[GY.+? MVM'%O<39ZNWEW>3Z"Q`1#/[OXMG6V-C4T-'4U<_#MK?*X>SLZ.'7O]O/G MU\_;\?KW\>77S\W-SM7H`10;%PT#_/CX^_\!__OY^?K\_OWW\.WW!@T2'!\7 M$`P)#A?E[@(@.TI,0C0F'QXC M)R0;$`@%"`P,!OSOX=?:ZOT0)S@W+!X,_/7V_@@/#PD`^/+MZNCGY>+>V=+- MT^7\"P\-$B,Q,"H@$`,``@<.$0\*!@(`_?CQ[?#[`P/^]_'P]@`(#`G^[^GQ M``<)"0/Z]?+O[O']%3)(4T]!,28B)S1!1D,Y+2(6"O_X\NWO`ADE+3H],RD? M%Q05%QL?(!T8$PP#_/3JX-3'O[NYN\;<[_'FV-';Y^CDX-7+QL3%RU=#4Y@4A+BL?$`3^_@`! M_O?Q[.GFX-K6TLS'RMCI]04;)2$8"OSV^/T%#A49&QT=&1$*!/_Z\^KAW-_P M#BDV-C(X04$Z-BXD'!80#0L)"`D(!/[W[^;BZP$5'!8'].3/H\PLL1U)-0#4P+S(W.C8M)!L2"0#Y]O?W^@86&Q48(B0?&A(* M!00%!P<%__CS[./8T,O*S,[/SLW/VNGR\.GDZ_H#"0\0#P\,!P#Z]/'R]/C\ M____"2`[35%)."@A(RPR,2DA)CM-344Y)Q0(`?[_`PXE.D`Y+!T4$!$2$0X' M_OGV\NODW][>X>X('!T9'B`<&14."PD)"@H(!PH-#0D#_/;NYMK+O*ZFK<7D M^/OY_08&`?_\]>SBULW)R,K0UMC6T&!,,!P8) M$!@=&@\!\N3:V-O?X-W8T,6\O,WH_@<($2(K)R$;$`;_]O#N[N_R]?C]`0#X M[NKV"A<9$@;^_@(("P@`]O<)&QT6#P3Y\_#N[>ST"!\L*R(4!O__"!0=(2(> M%0K^]>[GX-WA[OH"#A\F*"LF&Q0/"PH*"@D*"PX0$`T&_O7O[>SJZ_/^!04" M!QLP.#@T)1#^[N7DZ?#W_?[]^_;Q[O,$'2XT+R06"?SQZN;BX.C_&24C&@GW M[_#S]OD`$28W/T$_/CPW,BLD'10,!P8'"@T."P8$#!<=(RDG'A<.!P,"`@0' M!P#W[>/:TL[*QL3`N[.MK;C,VMW9VND`"PH'_O#EWMG:WN/I[?'R\>SAUM/A M^@T4$PT'!`(`_OGPZNT!&2`9#P+PX=?0S]7F`QXK*A\2"`+__P,'!@'Y[^/5 MR,'#Q\G+U.'M^PT6%!$-!?_\^OGY]_7U]_CW]._KZ>CGY>/BZ?H1(2(7"`<9 M+#$P*AT3#@P,#0T,"0/[[^/8T]GM!AD@'!$%_P`'#A$-!@(-)CL],R82__/M MZ_4+*T1-23PO)R4H+"TJ)!X;&QL9%`O^\.+8V>L)*3Y!-B@9"@$``0("_O?N MZ.7DY>3BW]G4T,S*T.#S_O_VZ>/O!Q@=&@KUZ>7G[_C]`04("`/_``TF/TM( M.245#0T3&1T=%A`4)SL^,!\+]NGFZ/('(C(S*R`5#PX0$1`,"`0"`0$#!04` M]>;7TM[]'C(X+QX,^_#O]P(-%!84$`L$_/'IX][9T\_/V>X""0?_\^[Y#184 M#`#PX]S9V-?3S<:_N[BXP-7O_P#X[-_6T=#1T<_*QL7/Z`<8%PX`[-S3T=WV M$R8L*!T1!O_]`@D/$0X)!/[Y]_?X]_/NZ.L!'S0\."H:#0/]_/X$"@T,"@D( M!P+[\NG@VM?8Y/L1&A,![.#I!R8T-2P8!/7IY>KP]/;V]._I[``=-$%#/#,L M*2HK*B8?&`\(#!XK)1<*]^+8V>7^&"@J)B`:%A(/#`@#_OGV]?C]`0,"_?/G MW-SS&#,].2H6!OGS^``#`O_[]O/R\_/Q[>?@V=37Y/H/&14']>GK_A@F)AP( M\^GI\/?[_O[\^?;V`!0H,2XC%PT)"Q,=(B`7"O[T]08>+#$P(P_]\_<-)C0U M,"VMC7 MU,['P+R_S^G[_O7EU/@WMO9UM'+Q\SD M#"HS+B`)]>KK^`D5&!<5$@X*!O[SZ.+?W=WG_14E*"`2!?GT`R$V."X>!O'F MYNSU^_SW\>KDZOX5(B,<$PT+#`X/#0D%`/OT[?`!%!H7#O[MZ/(%&28G(1XA M)S$\0D([,B@=$@D$!0P3%A0)_?H,*SPY+R(0_O/S^@($`?KQZ.#8T]#.S?%@G\\.7@Z@`/#@;\[-O1S,S. MT,[&O+>_U_$``??JX-S7?[087&Q8)^O'T_PT2 M#P;\]._Q^0,("`+WZ=G/SMS['3`P*!H(^/+S^/X"`P#[]O#HXM_AY>;G[P(9 M)209"__X]_C^#B8U,2<>%`L'!08'!?_W]0`8,T1%.RPA&QD;("0E)"$<%@T` M\>SV!0H'`?C[#!H>&Q,)`0`(3$0T*"`8#_O?PZ^?BW-KA\`0=,SDM'0SX MZ./DZ>WQ]?C\_P$!`/WX\>GDZ/@.'1\6"?SS[^[P^@P:&Q4-__/MZNCGZ>GG MZ?0%%B(E(AP6$Q08&Q@1"PH,$!(0#Q8F,"H>$PT5*3D^.S0N+3(Y/T`\-2XG M(!D3#PT+"07_]>SI[O8"$AD3"O_QY^/?W=[?W=C4T,S+S='4T]'4X_<"`OKO MX-+(P\+$S^?Z_/7MXMC4T]38W-W=Y?D.%Q(%].;?X>OW`08'!@'Z\^OAV-?F M^?_]^?D$$!,/!_WT[_'W^?CX^?S]^_CU\_'O[.;>U]7KN`1XT M/3HM'A(*!P<)"0<$`/OT[N?AX.T'&AX:%QPE)AP/`??T^@@7("`9$0L%__OX M]_GY]O'JY>GY#2$V0SXO(1,%_OS]``,#__GV]//S\N[GX-WC\?\%`_KOY^7I M\OC^#2$K*"(6!/;P[_'V^OP%%B@P+R<<%18=)R\P*R0>'!H7$@H`_`05'QX= M'R4N,2PB%Q`-$1D@(A\9$0@`]_#JYN3FZ.GGY^_\`00-&1H5#PD!^O'HXN'D MZ.SP\>SEW-70T^+\$!<4"?OPZ.7DX^#+Y`__\``4(!@'[^?P!"Q4:&182#0D'!@4#`/SW M\NSFY_4&#Q8A*2@A&A`(!0']^//LY-[=X./EY^CGYNWZ!@L(`?CR[NWN[>KM M_A0=&1$$\^CBX>3H[?@.*T!(1#(RC@ MX^_V]OD"!P3_^O+JY-[:V=C6TM'3U=/.Q[ZXN\O@[O#GV<_,TMO@X=[B\@0( M!?[QY=[;VMO?]$Q\?&1$,"PX3%Q81#`<%`P#[].SDY?+[]O#W!`P."@/\ M^/CZ_P0$__?MY-_>WM[>WM[;UM#/VNOV_0D<*2<=%`H&!P<)#A06%!$0$1(1 M#0;^_0H;(B$9#P8`_?W[\^KI]P8)!?_TZ.'=W=[>X.K^$R(D'1(*"`T6'!P7 M$0H%`?WZ^/;Z"2`L*B@M,C8U,2LE(1\?(2$=%Q(/#0L)!?[W\.OFX=O=Z?;[ M_0@:(R,?%0?]].SFY.+>VMC8V=O=W=S=Y_@($1$*__;P\/3X_`(3*30S*AP- M!`#]_?W]`1`I04U.1CPS+BLI)R4C(B$?'AL3!_KT_@T0#1`7&QP7#@7^_/T` M!0@&`?OU\.SIY^3BWM?-P[N\R][L]@83$0;[\./>W^/M]OS____]^O;OYMO: MZ``0$@H`^OG\_P'^]_/Z!PL(`_?IX-O7U-/5WO(,'R,;#0'[_`(("@D'!@4" M_/3KX][D]PH,!PH2&1L7$0H&!@@-$A05%102#PL$_//KYN'%0T*"Q`6'!X< M%Q`)`_[Z]>_HXMW9U]OI_0P8)C`M)1\9%!(0#@T+"`4"__SY]O'JX=S@\`,- M#@@`^/7S\_#KZ/$"#`T*`/+FWMG:W>'J_1WHX][:UM?B[?7_#A@8%!`) M!@8%`?_^_/KW\^_KZ.3AX.;W#AXA&Q$(`@$#!00#"QLF)B`6!_GNYN#>WN#K M!"`Q-2XB%@\+"P\1$0X*!0#Z\NC'BX>+M`!0?(AP2"P@)#0X*`OOV]?3S\N[IZO8# M!@$!"QTI*2(;%Q<<)"TT,BPB%PP#^_7P[NWMZN;G\@<6&ATC(QH2"?_V]/3U M]_?U\>WIYN/?VM;2TMWQ`@@!].CDYNOO\?+Z"Q<6$0?XZN3CY.?IZ_4+)#8Z M,B07#@P2&AX?'QT8$@L$^_#J\@0."0,'$Q\D(1D2#0T/$1(1#PP)!P<&!/_V M[.+9T]#3X/(`"!$<(!T9%A`,!P(``/_Y\_#R]OCV\>KE[0`2&1@1"/_Y^/GX M\NSP``T+!/ONY-[;V=C7VN?_%B(A%PH!``4,$`\)`?;LY-_=V]K>Z?H#!0P8 M(2(>%0P'!PL5'B0E(QX8$0H#_??R[.?BWM[I_`@(!`D2%A(+`//M[O+U^/CT M[>;@W-O:V-CB]0@0#0+UZ^CJ[_3U\O,!%!H3"O[PZ.?FY^OT!A\T/T`Y+R&Q<4$Q$,!P#X[^;D[/?_"1DB(1X8$0X/$1(0#0@#_??PZ>#9U=/1S\[- MTN+Y#102$ATF(QL4"?WU\.WN\O7Y_@(!^_/IY.P"%A\=$P@"``$"`/KRZNS[ M"@X+`_;JXMS8V>+Q`@X3$Q(4%QD<'AX;%`T&`/KT[^KEX>#H^Q(G-#,I'A82 M%1PA(1X9%!`-"0/^^?/MY^+'M_Q`7%@\&`@(%"`@"^.WEYO@1("(=#_SLX^'M!R`N,"HC'1L;'B$A'AH7 M%!(0#`;\\>;=U=3A_!4@'0__\_#V``D-#`'=V=75W^_\__OS MZ.+K`QPG)1H*^>_JZO#W^O?Q[.CG[P$3'!P6#04"`PD-#`?_]>G>VN7V_O[Y M[=[6U^;]$1<3#0D("Q`4$Q`)`OSY^OT!!`3^]>SG[@8G0$E%-R07$1(7'B$@ M'AL7$0L%`/OV[^;@W^K["0X*`?7KY./O!A<:%0O\[.#8U-36UM74UN+U"A@; M%@T&`/SZ^/;S[^OHY.#>Y/4$!P'VZN;N_@T9'QX;&R`F*2VMSD[._M[OL2(B8C&P\&__GZ``8)"0<# M_/7LY^OY"`\/"0+^_?\!`?OPX]SD^`@,"@/VZ=[7V>7S_0(&"`<%`P0'"08` M^?/O[N_Q\?#LY^'@[`,9)BD@$`+Z^/P%"@T0$Q89&AH7$@L$^_/R^PL7&A<1 M"P<#!A0G+2<>$P7Z].[KZ^SJZ.GR``P1$A`,"`4"`/[[]_+MZ>;BW-C=Z_7U M\O+U^P$$!04&!@@,$!(0#`<"_/;Q[>KHZ.KR_`4)!?SV^PP<(B(<$@@#__W^ M__SX]O3S]?X*$Q<6$PX(!`,$!@@'!/WV\_L,&!D6$`D*$A@;'!H7%!,4%A@8 M%A(."P;DX>#B[/T/&1@0!_[W M\>WN\O;X]>_J[P`/$@P"^/8!#1(3$0T*"@P0%!87%A(-!P#[]>_LZNGM^@4& M__\*$Q01#07__/S^``#^^O;R\.SGY>O\#Q<4"__SZ^?I\/?Y]_/W!A8:%@W_ M[^+:V^P#$A84#0%@P"]_#L[?#U]_CW]_CX]_;T\>WIZ_0! M"0P*`_GP[OP1'B$>%`?^^?;W^?KY^/H"#1<:&10/"00"`P<+"PD%`?ST[.;K M^`,*$189&180"@3_^_K_`P4&!@<)"@D&__?NY^7L^@8(`_KR]@,.$!`-!@'_ M_OX``P,!_OKX_0D3%Q4.!__Z^/L`!@@&`?KPZ.?R_@(`^_C[!0H+"@D'!04% M!PL.#@T+!P+]]_+NZ^GO_`D."@0$#A@:&!0-!P,!````_OOY]_/NZ>SW`P@' M`_WX]?3V^O[_^O+IYN[[`?[X[N'9W>OX_O[Z]?'N[_/Z``("`/OU\.WKZ^KG MY>7K\OP+&R(A'181#Q$2$A,1#@H&`?_]_?P`"Q@?'AH3#`3_^_KY]_/Q^0D5 M%A$*__/JX^+K^P8+#`D%`O_]_/W^_/KX^/CW]?/OZN7BYO4-'R4B&0T"_/K[ M_P$!__[^_O\```#]^?C\!@T/#0@!^O3P[N[S_PX6%`\'_O;Q[.KK\?L$"@X0 M$`X+!P0%!PD)"@L+"@@%`OWX]/D*&R0E(!<0#0L*"PP-#0P+"0@'!@/^^/+Q M]@`+$1`+`OCOZ./H]PL6%Q,+`/?NZ.3CX^;O^P4*"P@%`?WZ^/G\``,"`/WY M]O+MZNSW!A,='QP7$@X+"08$`@(#!`8&!`']^O;R[NWT_P<(!@'[].[N^`8- M#`D#_/?S[^WKZ>?FZ_8"#`\."P@$`0`!`P0$`O[X\^[JZ.GO]OK^!`@(!@/_ M^O;T]/;Y_``#`O_[]O+P\._M[?#V^_W\^?7R]/T&"@P-"P@%`P#^_/KY^OL` M"1`4%!(/#`H)!P<&!@8&!0,!_?GY_P0$!`D.$Q,/"0+[]?+S^/T!`P0"`?[Z M]O+O[>OK\?H``P#Z]/3\!`@*"08#`?_]^_GX]_;V]OH"#18;&A82#0D%`P,$ M!`0#__KW^P0+#0L(!0<+#0T,"08"`/\``P8("0D(!@,`_?GU\?#Q]_X"`?__ M!@X1$`X*!`#]^OGX]_;T]//T]OP&$!45$@\+"08%!`,"_OKU[^[S_@<)"`/] M^_X#!08&`P#^_@`#!04$`P(!`?_\^OCV\_+T^?S\^OT&$!,0#`@%!`,!__W\ M^OCW]_C[_P0)#0X-"P<$`@#__?OY]O/P[O'[!`8#__KV]_T#!P@&`P'__?S\ M_/OZ^OKZ^OGW\NWGX^'AY>OP\_;]`P4!_?OX]_?W^?S^__[]^_GW]OC]!0T2 M$Q$,!@+^_?X!`P,`^_C\!@X1#PH$_OP!"`L,"PD&!`,#!0@*"PP+"08"__SZ M^/;S\?'T^/K]`PL.#0H'!`("`P,"`/SX]/+S]/3T]OG^`0,"`?_^_?SZ]_7T M\_/S\_7\`P8$`?WY^/O_`@,$`P,$!04&!P8&!@8'!P@'!@4$`P(!`@4("`8% M"1(7%A01#@T+"08$`P(`_OSZ^?GZ_0(("PL(!`#^_?W]``,$!`+^^O?Y``8& M`O_[^?K_!0<&`__\^_T"!@D*"`8$`P$`_OSY]O/Q\?7\`@8'!00'#Q04$Q`, M"04"``#__OW\^OCV]/7Y_@("`@#__O[_``$!`/[\^?;S\>_R^?W[]_3T^0`$ M!0,`_/CW^/O^``#__?S[^_OZ^??T\?#Q]_\&"0<"^_?Y`PL.#PP&`?WZ^OS] M_?OX]O7T]?G_`P8&!`'__P$#!`,"`/[\^OCV]?3V^P$!__\!!`<'!@0!```" M!`8("`<%`P$!`@0$`O_\^?;V^P(&!P4`^O;U_`8+"PD%`/S[^OGY]_7S\?'S M^0`&"`<#_OKW]_K]_____OW[^OCW]?/S]OL`!`D.$1(1#0@%`@$!`0(#!0<( M!P<&!@8'!@,!``$%#`\0#@L&`O[]`0L2%!(/"P<#`?_^_/KW]/+S]_\&"@L* M"`4#`0```````/____[\^??T\?+W_`()#`L(!0+__?W]_O[]_?W^__[^_?S\ M_/S[^_S_!0L-"P@$`@#]^?H!"`L*"`4`_/KY^?KZ^?GY_`('"@L*"`8$`@$` M````_______]^_CU\_'R]@`)#@\-"04"`/___OS[^?CW]O;V]O3S\O'Q\O/V M^P`#`P'__?OZ^OGW]O?]!`H+"08"_OOY^/GZ_/\"!0<'!@4%!04&!P<&!00$ M`P'__?KX]O7U]?7V^@()#@X,"`4"`/[^_?W]_/OZ^/?V]?7V^/K^`00&"`<& M`P$`__W]_/S\_/S]``8)"@<$`?[\^_O\_@$$!04%!`,!__[^_P`!`0#__?OY M^/CX^?GY^OK[_/X``P<*"PL)!@0#`P,"`0#__O[]_?S\_?[_`@0'"PP,"P@& M!`(!``#___[]_/S[_/T!!08$`O_]_/X``P4$`P'^_?S\_?W^_O[^__\``/__ M_OW]_?W]_?X``P4%`P$!`P<)"0<&!`,#`P,#`@$!`````0``__\``@0%!00# M`@#__O\```$!`/[]^_GX]_?Z_@$"`/[\^_P``@(!`/_^_?W^_O[^_O[^_O__ M``#__OS[^OGX]_?Y_``"`@$`_?OY^OX"`P,"`0#___[]_/S[^_KZ^?GY^_\$ M!P@(!@4#`@$!`@(#`@(!`0#__O[^_?S[^_X"!`4&"`D)"`8$`P$```````#_ M___^_OW]_?[^_OW\^_GX^/O_`@,#`?_^_/KY]_C\`00$`P'__?S[^OGY^/GY M^OP`!`8&!@0"`0`````!`0(#!`0#`@$`_OW\_/S\_/X!!@H,#`H'!`(!```` M`0$!`@,#`P("`0#__O[^_?W^_P`!`P0#`P(``/_____^_?W\_/\#!P<&!`(` M_OW\_/S\_@`#!04%!`,"`0#__O[^__\``0$!`0#__OW\^_O[^_K[^_W_`P8' M!@0"`/[^_O[^_O[^__________[^_O[__P`"`P4%!`0#`@$`______[^_?S\ M^_O^`0,#`P$`_OW]_/S]_O\`````__[^_?S\_/W]_?W^_O[___[^_OW^_O[^ M_?W\_/S\_/X``P4%!00#`@$!```!`0$!`0$!`0$``/_^_OW]_@`"!`0$`P(! M``#__O[]_/S[^_KZ^_S_`0("`0#^_?W\_/S]_@`"`P,"`/_^_O[^_O__```` M`0$!`0$``/____[^_?W\_/S\_0`#!04%!`,"`0#___[__P```0$!```````` M``#___[^_OX!`P4%!`,"`0``__________\```$!`0$!`0$``/_^_?W]_@`" M`@("`0#___[^_O[^_O__``$!``#____^_O[]_?W]_/W]_@`"`P("`0$!`@(! M`0```````0$!`0$!`0``___^_O[^_P`!`@,#`P("`0$```#___[^_?W]_?[^ M_______^_O[^_O[^_O__``$!`0````#_____________````````_____O[] M_?[^_O[__P`!`0```/___O[^_O[^__\``````````````/____________\` M``$!`0$!`````````````````````````/______________``$"`@$!``#_ M_______________^___________^_O[^_O[^_O[__P`!`0$!``#_________ M_O___P`!`@("`0$```````````#_____``$!`0$!````______\````````` M`/_____________^_O[^_O[__P`!`@(!`0```/_______P````````#___\` M````````_________P```0$!`0```/_______________P```````````/__ M____________``````````#___________\```````#_________________ M______\`````````_________________P```````/________________\` M``````````````#_______________\``````````````/___P`````````` M```````````````````````````````````````````````````````````` M``````````````````````````````!#3TU-````$@`!```H%@`(0`VL1``` M`````$U!4DL````"``!)3E-4````%#P``'\`?P``````````````````05!0 M3````:A39#)A``(````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````Z`````````````` M```````````````````````````````````````````````````````````` M```````$"```````"0`C`````````````````'@````$``0```````#\`/__ M_X`````!`0`&455N:71S```````````````````````````````````````` M`0(`!B!S86UP````%8` M``$A!%-!1$6!`0`````.```&`:/4?J:EY/O_```B8`I&`0``D`#&`0#_^/_C M````````@``````````````:`"D`#P)J`S$`*@`#`FT#/0`I``\"00,B`0`` M```:`"D`#P%0`?$`*@`#`FT#/0`````````````````:`"P`%@$^`=P`*@`# M`FT#/0`````````````````:```````````````````````````````````` M``$````!>````'@```!6`'&XO!RF````'`!6``!7```````#__\````\```````$__\```!:```````````` M```````````````````````````````````````````````````````````` ` end nethack-3.4.3/sys/share/sounds/lethdrum.uu0100644000000000000000000006404507764735041017315 0ustar rootrootbegin 644 Leather_Drum M``Q,96%T:&5R($1R=6T````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``$X`SP```````$B,```! MZ*<]F@*G/9L$``````````````````````````````"!@6!?``!&3U)-``!( MA$%)1D934TY$``!&B``````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````/___P``_P`# M`@$!``#__P@.!/CU]_T!^?;\``#__/S\^?3P\?3U]?7V^?GX^/KSZ^ON\O3U M^/?R\?'V`@@,#PP)"@\7%0X-!_[Z`1`9&!03%A@;("`4"@8"``4-$Q0/"@D+ M!O[Z^/?W]OH#!0($!P/[]>WJ_QH@&A0+`?_Z]O#HY-[=Z?3V[>SW\>7AX>?L MYM?+Q;R[R=CAXMS9W-_>W^'BY>SS^@`!``(%"Q0<)"PT.CDV.#Y!0DA36UY@ M8V)=54M$0T,_."TC&1`(`__Y\^OCW=K7TQK["R MM+:VM;2SL[C"R]'7W./L\O;Y^_S^`@<,$147&A\D*"TR-38W-S;BW=G4 MT,K"NK2NJ::DHZ.CI*6FI::GJJ^TNL#%R,K.TM79W^3I[O/Y``4+$18;'R,F M*"LN,C0V.#H\/T-(3%%55E965%%-245!/3DV,B\J)2`;%A$-"08#`/WY]?+O M[.GFY.+@W]WSR^/\$"A`5&1XB)2@L+S,V.3T_04)#1$1$141#0D%`/SX].S@U,B\M*BX.+EZ.OO\O;Y^_X`!`<*#A$4%AD;'2`B)2@L+S0Y/D-(3$]04%%0 M3TQ)1D(^.3,O*B4B'AH7%!$."@8"_OKV\>WHX]_:U=#,Q\/!O[Z_O[^_O[^_ MO\#`P,'"P\7'RL[1U=G>X^CL\/3X^_\"!@H-$!,5%Q@:'!X@(B0F*"DK+"PM M+2TM+BTM+"LK*BHJ*2DH*"DI*"WHX][: MU]/0S,G&Q,&_O[^_OKZ^O\#!PL/%QL?)R\W/TM78V]_DZ>[T^O\%"@\5&ATA M)"[L MZ^GHY^;EY>;GZ.CHY^?FY>3CX=_=V]G7U];5UM;6U]?7V-G:V]S>X./FZ.ON M\?3W^_X!!`@+#A`2%!<9&QT?(2,E)RDJ+"TO,C4W.3H[.SLZ.#8T,2XJ)R,@ M'!@4$`P(!`#\^/3OZ^CDX-W9UM32T,_.SWQ M]?G\_@`!`@(#`P,#`P,#!`0%!P@*"PT/$!$1$A,5%A<8&1H:&QP<'1X>'AX> M'Q\?'QX='!P;&AD8&!<5$Q(0#PT+"08$`?_\^?;R[NKEX=W9UM/0S7I[/#S^/P!!0D.$Q8:'2$D)BDK+2XO,#`P,"\N M+"LI)R4C(!T:&!84$Q$0#@T+"0@'!00"`?_^_?OZ^/;T\O#O[N[M[>SL[>WM M[>WM[>WL[.OKZ^KIZ>CGY^?GYN;EY>7DY./CX^/DY>;HZNSO\?3X^_X!!0@, M#Q,6&1P>(20F)RDK+B\Q,S0U-34U-#,Q,"XL*28B'QL7$P\+!P/_^_CT\>[K MZ.;CX>#?WM[>WMW=W=W=W=S3CXN'@W]_?WM[?W]_@X>/DYN?IZ^WO\O3W^OS_`00'"@T0$A48&AT?(20F M)R@I*BLK+"LK*BDH)R4D(A\=&Q@6$Q$.#`D&!`'^_/GW]?/Q[^[M[.OJZ.?F MY>7EY.7EY>7EYN;FY^?HZ>KK[.WN[_#R\_3U]O?X^?GZ^_S]_?[_```!`@0% M!@<("@P-#Q$2$Q05%A<8&1H:&QP<'!P='1P<&QL:&1@7%A03$1`.#`H(!0,` M_OOY]O3Q[^SJZ.;DXN'@W][=W=S+DY>?IZNSN\/+T]OCZ^_W_ M`0($!0<("@P.#Q`2$Q,4%!45%145%104%!03$Q(2$1$1$!`0$`\/#P\.#@T- M#`L)"`<%!`,"`/_^_/OZ^??V]?7T\_+Q\.[M[.OJZ>CGYN7DY./CX^3DY.7F MY^CJZ^WO\?3V^?O]``(%!PD+#1`2$Q47&!D;&QP<'1X>'AX>'QX>'1T<&QD8 M%Q44$A$/#@P*"`8%`P'__?SZ^?CW]O7T\_/R\?'P\/#P\/#P\/#P\/#O[^_O M[^_P\/#P\/'Q\?+S\_3U]?;W^/GZ^_O\_?W^__\``0($!08("0L-#A`2$Q46 M&!D:&QP<'1T='!P;&AD8%Q44$A$/#0L*"`8$`@#^_?OY]_7S\>_N[.KIY^;E MY./CXN+BX^/DY>7GZ.GK[>[P\?/T]O?X^?O\_?[__P`!`@,$!08'!P@)"0D* M"@H+#`P-#0X.#@X/#PX.#@X.#@X.#@X-#0T-#0P,#`P,"PL*"@H)"`<%!`,! M`/[]^_KX]O3R\>_N[.OJZ>GHZ.CHZ.CHZ.CIZ>GJZ^SM[N_P\O/U]_CZ_/X` M`P4'"@P.$!(3%!46%Q@8&!@8&!@7%Q85%!,2$1`0#PX-#`L*"0<&!00#`@$` M__[^_?S\^_OZ^OGY^?GY^?GY^?GY^?GY^/CX]_?W]O;U]?3T\_/R\O+R\O+R M\O+R\_/T]?;W^/GZ^_W^_P$"`P0&!PD*#`T.$!$2$Q05%A<7&!@9&1D8&!<7 M%A43$A$/#0P*"`8$`@#^_/KX]_7T\O'P[^[M[.OKZNKJZNKJZ^OL[>WN[_#Q M\O/T]O?X^OO\_?\``0$"`P,$!`4%!04&!@8%!04%!04%!@8&!P<'!P@("`@) M"0H*"@L+"PL+#`P,#`P,#`P,#`P+"PH*"0@'!@4$`@'__OW[^?CV]?3R\?#O M[NWLZ^KJZ>GIZ>GJZNOL[>[O\/+S]/;W^?K\_O\!`P4&"`H+#`X/$!`1$A,3 M$Q,3$Q,3$A(1$!`/#@T-#`L*"0@'!@4$`P,"`0$`___^_?W\_/S\^_O[^_O[ M^_O[^OKZ^OKZ^?GY^/CX]_?V]O7U]?3T]/3T\_/S]/3T]/7V]O?X^?GZ^_W^ M_P`"`P0&!P@*"PP-#@\0$1(2$Q,4%!04%!,3$Q(1$`\.#0L*"`<%!`(!__[\ M^_KX]_;U]//S\O+Q\?#P\/#P\/'Q\?'R\O/T]/7V]_CY^OO\_?[__P```0$! M`@("`P,#`P,#`P,#`P,#`P,$!`0%!04&!@8'!P@("`D)"@H*"@H*"@H*"PL+ M"PL+"@H*"0D(!P8%!`,"`?_^_?OZ^??V]?3S\O'P\._O[^[N[N[O[^_P\?+S M]/7V]_CY^_S]_@`!`@0%!@<("@L,#`T.#@\/$!`0$!`/#PX-#0P+"@D)"`<& M!04$`P(!`0``_____O[^_OW]_?W]_/S\_/S\_/S\^_O[^_O[^_OZ^OKZ^OGY M^?GX^/CW]_?W]O;V]O;V]O?W]_CY^OO[_/W^_P$"`P0%!@<("0H+#`P-#@X/ M#P\0$!`0$`\/#PX.#0P+"PH(!P8%!`(!__[\^_KX]_;U]/3S\O+R\?'Q\?'R M\O/S]/7U]O?X^/GZ^OO\_/W^_O__```!`0("`@,#`P,#!`0$!`0$`P,#`P0$ M!`0$!`0$!`0$!04%!@8&!P<("`@)"0D)"0D)"0D("`@'!@8%!`0#`@(!`/_^ M_?S[^OGX^/?V]?3T\_/R\O+Q\?'Q\O+R\_3U]O?X^?K\_?[_``(#!`4'"`D) M"@L+#`P,#0T-#0T-#0P,"PL*"@D("`<&!@4$`P(!`0#__O[]_?S\_/O[^_O[ M^_O[^_O\_/S]_?W]_?W]_?[]_?W]_?W]_/S\_/S[^_O[^_KZ^OKZ^OKZ^OK[ M^_O[_/S]_?[__P`!`@,$!08&!P@)"@H+#`P-#0T-#@X-#0T,#`L*"0D(!P8% M`P(!`/_^_?S[^?CW]_;U]?3T\_/S\O+R\O/S\_3U]?;W^/GZ^OO\_?[_``$" M`@,$!`4%!@8&!@8'!P<'!P8&!@4%!04$!`0$!`0#`P,#`P("`@("`@("`@(" M`P,#`P,#`P0$!`0$!`0$`P,#`@(!`0#___[^_?S\^_KY^?CX]_?V]O7U]?7U M]?7U]O;W^/CY^OO\_?[_``$"`P0%!@<("0H*"PL,#`T-#0T-#0T,#`P+"@H) M"`<&!00#`P(!`/_^_?S[^OKY^?GX^/CX^/CX^/CX^/GY^?KZ^_O\_/S]_?W^ M_O[___\```````#__________________O[^_O_______P````$!`@(#`P0$ M!04&!@<'!P@("`@("`@("`@(!P<&!@4$`P,"`0#__O[]_/OZ^?CW]_;V]?7U M]/3T]/3T]?7V]O?X^?GZ^_S]_O\``0(#!`4&!@<'"`@)"0D)"0D)"0D)"0@( M"`<&!@4%!`0#`P(!`0``___^_O[^_?W]_?W]_?W]_?W^_O[^______\````` M``````````#_______[^_O[]_?W]_?W]_?W]_?W]_?[^_O__`````0("`P,$ M!`4&!@<'!P@("0D)"0D)"0D("`@'!P8&!00#`@$`___^_?S\^_KZ^?CX]_?V M]O;V]O;V]O;V]_?W^/GY^OO[_/W^_O\``0$"`P,$!`4%!04%!@8&!04%!04% M!00$!`,#`P("`@$!`0$!`0````````````````````````````$!`0$!```` M````_____O[^_?W]_/S[^_OZ^OKY^?GY^?GY^?KZ^OO[^_S\_?W^__\``0$" M`@,$!`4&!@<'"`@("0D)"0D)"`@("`<'!@8%!`0#`@$``/_^_OW\_/O[^OKZ M^?GY^?GY^?GY^OKZ^OO[_/S]_?[^__\```$!`@(#`P,$!`0$!`0$!`0$!`0$ M`P,#`P("`@("`0$!`0$!`0$!`0$!`0$!`0("`@("`@("`@("`@("`@("`@$! M`0$!````___^_OW]_/S\^_O[^_KZ^OKZ^?GY^OKZ^OO[_/S]_?[^__\``0(" M`P0$!04&!@8'!P<("`@("`@'!P<'!@8&!04$!`,"`@$``/_^_OW]_/S[^_OZ M^OKZ^OKZ^OKZ^OK[^_O[_/S\_?W^_O[___\``````0$!`0$!`0$"`@(!`0(! M`0$!`0$!`0$!`0$!`0$!`0$!`@("`@,#`P,#!`0$!`0$!`0$!`0$`P,#`P(" M`0$!``#___[^_?S\^_OZ^OKY^?GY^?GX^/CX^/GY^?KZ^_O\_/W]_O__``$" M`@,$!`4%!@8'!P<("`@("`@("`<'!P8&!@4%!`0#`P("`0``_____O[]_?W\ M_/S\_/O[^_O[^_O[^_S\_/S]_?W]_?[^_O[^________________________ M__________\```````$!`0$"`@(#`P,$!`0%!04%!04%!04%!04%!00$`P," M`@$!``#__O[]_?S[^_KZ^?GX^/CX]_?W]_?W^/CX^/GY^OK[^_S]_?[__P`! M`0(#`P0%!08&!P<'"`@("`@("`@("`<'!P<&!@4%!00$`P,"`@$!``#____^ M_O[^_?W]_?W]_?W]_/S\_/S]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W]_?W] M_?W^_O[^_O___P```0$"`@,#!`0%!04&!@<'"`@("`@)"0D("`@("`<'!@8& M!00$`P(!`0#___[]_?S[^_KZ^?GX^/CX]_?W]_CX^/CX^?GY^OK[^_S\_?[^ M__\``0$"`@,#`P0$!04%!08&!@8&!@8&!@8%!04$!`0$`P,#`@("`@$!`0`` M````_____________O[^_O[^_?W]_?W]_?S\_/S[^_O[^_O[^_KZ^OKZ^OKZ M^_O[^_S\_/W]_?[^_P```0$"`P,$!`4&!@<'!P@("`D)"0D)"0D)"`@(!P<& M!@4$!`,#`@$``/_^_?W\_/OZ^OGY^/CX]_?W]_?W]_?W^/CX^?GY^OK[^_S\ M_?[^__\```$!`@(#`P,$!`0$!04%!04%!04%!04%!04%!00$!`0$!`0$!`,# M`P,#`P("`@("`@("`0$!`0``_____O[^_?W]_/S[^_OZ^OKY^?GY^?GX^/CX M^?GY^?KZ^OO[_/S]_?[^_P```0("`P0$!08&!P<("`@)"0D)"0D)"0D)"`@( M!P8&!04$`P,"`0$`__[^_?S\^_OZ^OGY^?CX^/CX^/CX^/CY^?GY^OK[^_O\ M_/W]_O[__P```0$"`@(#`P,$!`0$!04%!04%!04%!04%!04%!04%!04%!00$ M!`0$!`,#`P,"`@(!`0$!``#____^_O[]_?S\^_O[^OKZ^?GY^?GX^/CX^/CX M^/GY^?KZ^OO[_/S]_O[_```!`@(#!`0%!08'!P@("0D)"0H*"@H*"@D)"0D( M"`<'!@4%!`,#`@$!`/_^_OW\_/OZ^OKY^?CX^/CX]_?W^/CX^/CY^?GY^OKZ M^_O\_/W]_?[^__\````!`0("`@,#`P,$!`0$!`4%!04%!04%!04%!04%!04% M!04%!04$!`0$`P,"`@(!`0``___^_OW]_/S[^_KZ^?GY^/CX^/?W]_?W]_?W M]_?X^/CY^?KZ^_O\_?W^_P`!`0(#!`0%!@8'!P@("0D)"@H*"@H*"@H)"0D) M"`@'!@8%!`0#`@(!`/___OW]_/O[^OKY^?GX^/CX^/CX^/CX^/CX^/GY^?KZ M^OO[^_S\_/W]_O[___\```$!`@(#`P,$!`0%!08&!@8'!P<'!P@("`@("`@( M"`@'!P<'!@8&!04$!`,#`@(!``#___[]_?S[^_KZ^?GX^/?W]_;V]O;V]O;V M]O;V]_?X^/GY^OO[_/W]_O\``0$"`P0%!08'!P@)"0H*"@H+"PL+"@H*"@H) M"0@(!P<&!04$`P,"`0``__[^_?S\^_OZ^OGY^?CX^/CW]_?W]_?W]_?X^/CX M^?GY^OKZ^_O\_/S]_?[^__\```$!`@(#`P0$!04%!@8'!P<'"`@("`@("0D) M"`@("`@'!P<&!@4%!`0#`P(!``#__OW]_/O[^OGY^/?W]O;U]?7T]/3T]/3T M]/7U]?;V]_?X^?KZ^_S]_O\``0("`P0%!@<'"`D)"@H+"PP,#`P,#`P,"PL+ M"@H)"`@'!@8%!`,#`@$``/_^_?W\^_OZ^?GX^/CW]_;V]O;V]O;V]O;V]O?W M]_?X^/GY^OK[^_S\_?W^_O\```$!`@,#!`0%!08&!P<("`D)"0D*"@H*"@H* M"@H*"@H)"0D("`<&!@4$`P,"`0#__OW]_/OZ^?GX]_;V]?3T\_/S\_+R\O+S M\_/S]/3U]?;W^/CY^OO\_?[_``$"`P0%!@<'"`D*"@L,#`P-#0T-#0T-#0T, M#`L+"@H)"`<'!@4$!`,"`0#__O[]_/O[^OGY^/CW]_;V]O7U]?7U]?7U]?7U M]?;V]O?W^/CY^?KZ^_S\_?[^_P`!`0(#!`0%!@<'"`D)"@H+"PP,#`P-#0T- M#0T-#`P,"PL*"0D(!P8%!`0#`@$`__[]_/OZ^?CW]O7U]//S\O+R\?'Q\?'Q M\?'R\O/S]/7U]O?X^?K[_/W^_P`!`@,$!08'"`D*"PL,#0T.#@X.#@X.#@X. M#0T-#`L+"@D("`<&!00#`@$`__[]_/OZ^OGX]_?V]?7T]/3S\_+R\O+R\O+R M\O/S\_3T]/7V]O?X^/GZ^_S]_?[_``$"`P0%!@<("0H*"PP,#0T.#@X/#P\/ M#P\/#@X-#0P,"PH)"`<&!00#`@'__OW\^_GX]_;U]//R\?'P\._O[N[N[N[N M[N_O[_#Q\O+S]/7V]_CY^_S]_@`!`@0%!@<)"@L,#0T.#Q`0$1$2$A(2$A$1 M$1`0#P\.#0P+"@D(!P8%!`,!`/_^_?S[^OGX]_;U]//S\O'Q\/#P\._O[^_O M\/#P\?'R\O/T]/7V]_CY^OO\_?\``0(#!08'"`D*"PP-#@\0$1$2$A(3$Q,3 M$Q,2$A$1$`\/#@T+"@D(!P4$`@'__OW[^OCW]O7S\O'P[^[N[>SLZ^OKZ^OK MZ^SL[>WN[_#Q\O/T]??X^?O\_?\``@,%!@@)"@P-#@\0$1(2$Q04%!05%144 M%!03$A(1$`\.#0P+"@@'!@0#`@#__?S[^?CW]O7S\O'P[^_N[>WL[.OKZ^OK MZ^OK[.SM[>[O[_#Q\O3U]O?Y^OS]_P`"`P4&"`D*#`T/$!$2$Q05%186%Q<7 M%Q<7%A85%103$A$/#@T+"@@&!0,!`/[\^OGW]O3S\?#O[NWLZ^KIZ.CHY^?G MY^CHZ>GJZ^OM[N_P\?/T]O?Y^_S^``$#!`8("0L,#0\0$1(3%!46%A<7%Q<8 M%Q<7%A85%103$A$/#@T+"@D'!00"`?_]_/KY]_;U\_+Q\.[M[>SKZNKIZ>CH MZ.CHZ.CIZ>KJZ^SM[N_P\O/T]O?Y^_S^``$#!0<("@P-#Q`2$Q06%Q@8&1H: M&AL;&QH:&AD8%Q85%!,1#PX,"@@'!0,!__W[^??V]/+Q[^[LZ^KIZ.?FYN7E MY>3DY>7EYN;GZ.GJZ^WN[_'S]/;X^?O]_P`"!`8'"0L,#A`1$A05%A<8&1D: M&QL;&QL;&AH9&!@7%A03$A`/#0L*"`8$`P'__?OY^/;T\_'P[^WLZ^KIZ.?F MYN7EY>7EY>7EYN?GZ.GJZ^SN[_'R]/;W^?O]_P$#!08("@P.$!$3%187&1H; M'!P='1T>'1T='!P;&AD8%A43$A`.#`H(!@0"`/[[^?CV]/+P[^WLZNGHY^;E MY>3DY./CX^3DY>7FY^CIZNOL[N_Q\O3V]_G[_?\``@0&"`D+#0X0$A,4%A<8 M&1D:&QL;&QL;&QL:&AD8%Q84$Q(0#@T+"0<%`P'__?OZ^/;T\_'O[NSKZNGH MY^;EY.3DX^/CX^/DY.7FYN?IZNOL[O#Q\_7V^/K\_@`"!`8("@P.$!(3%1<8 M&1H;'!T='AX>'AT='!P;&AD8%A43$1`.#`H(!@0!__W[^??U]/+P[^WLZ^GH MY^?FY>7DY.3DY.3EY>;FY^CIZNOM[N_Q\_3V]_G[_?X``@0%!PD+#0X0$1,4 M%A<8&1H;&QP<'!P<'!P;&QH9&!<6%!,1$`X,"@D'!0,!__W[^??U\_+P[^WL MZ^GHY^?FY>7DY.3DY.3EY>;FY^CIZNSM[_#R\_7W^?O]_@`"!`8("@P.$!$3 M%!87&1H;&QP='1T='1T<'!L:&1@7%A03$0\-"PH(!@0"`/[\^OCV]/+Q[^[M MZ^KIZ.?GYN;EY>7EY>7FYN?GZ.GJZ^SM[_#R\_7V^/G[_?\``@0%!PD*#`X/ M$1(3%187&!D9&AH:&QL;&AH9&1@7%A44$A$0#@P+"0<%`P'__?OY^/;T\_'O M[NWKZNGHZ.?FYN7EY>7EYN;FY^CIZ>KL[>[P\?+T]O?Y^_S^``(#!0<)"@P. M#Q$2%!46%Q@9&AH;&QL;&QH:&1D8%Q84$Q(0#@T+"0<%!`(`_OSZ^/?U\_+Q M[^[M[.OJZ>GHZ.?GY^?GY^?HZ.GJZ^SM[N_P\?/T]??X^OO]_@`"`P4&"`H+ M#0X0$1(4%186%Q@8&1D9&1D9&!@7%A44$Q(1#PX,"PD'!00"`/[\^_GW]O3S M\?#O[>SKZNKIZ.CGY^?GY^?GZ.CIZNOL[>[O\/+S]?;X^?O]_@`"`P4'"`H, M#0X0$1(4%186%Q@8&!D9&1@8%Q<6%103$A$0#@T,"@@'!0,"`/[]^_KX]_7T M\_'P[^[M[>SKZ^KJZNKJZNKJZNOK[.WN[_#Q\O/T]??X^?O\_O\``@,%!@@) M"PP.#Q`1$A,4%187%Q<8&!@8%Q<6%A44$Q(1$`\-#`H(!P4#`0#^_/OY]_;T M\_+P[^[M[.SKZNKIZ>GIZ>GIZNKKZ^SM[N_P\?+T]?;X^?O\_O\!`P0&!PD* M"PT.#Q$2$Q04%186%Q<7%Q<6%A85%!03$A$/#@T+"@@'!00"`/_]^_KY]_;T M\_+Q\._N[>WL[.OKZ^KJZNOKZ^OL[.WN[_#Q\O/T]?;W^?K[_?[_`0($!08( M"0H,#0X/$!$2$Q04%146%A86%A45%!03$A$0#PX-"PH)!P8$`@'__?SZ^/?V M]//R\._N[>WLZ^OJZNKJZ>KJZNKK[.SM[N_P\?+S]?;W^?K[_?X``0,$!@<( M"@L,#@\0$1(3$Q05%146%A86%144%!,2$A$0#PT,"PD(!P4#`@#__?SZ^?CV M]?3S\O'P[^_N[>WM[.SL[.SL[.WM[N[O\/#Q\O/T]?;X^?K[_/[_``(#!`8' M"`H+#`T.#Q`1$A(3$Q04%145%104%!,3$A$0#PX-#`L)"`8%`P(!__[\^_GX M]_7T\_+Q\._N[NWM[.SL[.SL[.SM[>[N[_#P\?+S]?;W^/G[_/W^``$"!`4& M"`D*"PP-#@\0$1(3$Q,4%!04%!04$Q,2$1$0#PX-#`H)"`8%!`(!__[]^_KX M]_;U]//R\?#O[^[N[>WM[>WM[>WM[N[O[_#Q\?+S]/7V]_GZ^_S]_P`!`P0% M!@@)"@L,#0X/$!$1$A(3$Q,4%!,3$Q,2$A$0#PX-#`L*"0@&!0,"`?_^_/OZ M^/?V]?3S\O'P[^_N[NWM[>WL[>WM[>[N[^_P\?+S]/7V]_CY^OS]_O\!`@,$ M!@<("0H+#`T.#P\0$1$2$A(2$Q,2$A(2$1$0#P\.#0P+"@D'!@4#`@'__OW[ M^OGX]O7T\_+Q\?#O[^[N[>WM[>WM[>WN[N_O\/'Q\O/T]?;W^/K[_/W^``$" M`P4&!P@)"@P-#@\/$!$1$A(3$Q,3$Q,3$Q(2$1`0#PX-#`H)"`8%!`(!`/[] M^_KY]_;U]//R\?#P[^_N[NWM[>WM[>WN[N_O\/#Q\O/T]?;W^/GZ^_W^_P`! M`@0%!@<("0H+#`T.#P\0$1$1$A(2$A(2$A(1$1`0#PX-#`L*"0@'!@4#`@'_ M_OW\^_GX]_;U]//S\O'Q\/#O[^_O[N[O[^_O\/#Q\?+S\_3U]O?X^?K[_/W_ M``$"`P0&!P@)"@L,#0X/#Q`1$1(2$A(2$A(2$A$1$`\/#@T,"PH)"`8%!`(! M`/[]_/OY^/?V]?3S\O'Q\/#O[^[N[N[N[N[O[_#P\?'R\_3T]?;W^/GZ^_S^ M_P`!`@,$!08'"`D*"PP-#@X/#Q`0$1$1$1$1$1$0$`\/#@T,#`L*"0<&!00# M`0#__OW[^OGX]_;U]//R\O'Q\/#O[^_O[^_O[^_P\/'Q\O+S]/3U]O?X^?K[ M_/W^_P$"`P0%!@<("0H+#`T.#@\0$!$1$1$1$1$1$!`0#PX.#0P+"@D(!P8$ M`P(!`/[]_/OZ^?CW]O7T\_+R\?'P\/#O[^_O[_#P\/#Q\?+S\_3U]O;W^/GZ M^_S]_O\``0($!08'"`D*"@L,#0T.#P\0$!`0$1$1$!`0$`\/#@T-#`L*"0@' M!@4$`P$`__[]^_KY^/?V]?3T\_+Q\?#P\/#O[^_O\/#P\/'Q\O/S]/7V]_?X M^?K[_?[_``$"`P0%!@<("0H+#`T.#@\/$!`0$1$1$1$0$!`/#PX-#0P+"@D( M!P8%`P(!`/_]_/OZ^?CW]O7T]//R\O'Q\?#P\/#P\/#Q\?'R\O/S]/7U]O?X M^?K[_/W^_P`!`@,$!08&!P@)"@L,#`T-#@X/#P\/#P\/#P\/#@X.#0P,"PH) M"`<&!00#`@$`__[]^_KY^/?W]O7T\_/R\O'Q\?#P\/#P\/'Q\?+R\_/T]?7V M]_CY^OO[_?[_``$"`P0%!@<("0D*"PP-#0X.#P\/#Q`0$`\/#P\.#@T,#`L* M"0@'!@4$`P(!`/[]_/OZ^?CW]O7U]//S\O+Q\?'Q\?#P\?'Q\?+R\O/T]/7V M]O?X^?K[_/W^_P`!`@,$!`4&!P@)"@L+#`P-#0X.#@\/#P\/#PX.#@T-#`P+ M"@D(!P8%!`,"`0#__OW\^_KY^/?V]?3T\_+R\O'Q\?'P\/'Q\?'Q\O+S]/3U M]O;W^/GZ^_S]_O\``0(#!`4&!P<("0H+"PP-#0X.#@\/#P\/#P\.#@X-#0P, M"PH)"`@'!@4$`@$`__[]_/OZ^?CW]O;U]/3S\_+R\O'Q\?'Q\?+R\O/S]/3U M]?;W]_CY^OO\_?[^_P`!`@,$!08'"`D*"@L,#`T.#@X/#P\/#P\/#P\.#@T- M#`L+"@D(!P8%!`,"`0#^_?S[^OGX]_?V]?3T\_+R\O'Q\?'Q\?'Q\O+R\_/T M]?7V]_CX^?K[_/W^_P`!`@,$!`4&!P@)"@H+#`P-#0X.#@X/#P\.#@X.#0T, M#`L*"@D(!P8%!`,"`0#__OW\^_KY^/?V]O7T]//S\O+R\O+Q\?'R\O+R\_/T M]/7U]O?W^/GZ^_S\_?[_``$"`P0%!@<'"`D*"@L,#`T-#0X.#@X.#@X-#0T, M#`L+"@D("`<&!00#`@$`__[]_/OZ^?CW]_;U]?3S\_/R\O+R\O+R\O+S\_/T M]/7U]O?W^/GZ^_S\_?[_``$"`P0$!08'"`@)"@H+"PP,#`T-#0T-#0T-#`P, M"PL*"@D(!P<&!00#`@$`__[^_?S[^OGX^/?V]O7U]/3T\_/S\_/S\_/T]/3U M]?;V]_?X^?GZ^_S\_?[_``$!`@,$!04&!P@("0H*"PL,#`P,#`T-#0T,#`P, M"PL*"@D("`<&!00#`P(!`/_^_?S[^OKY^/?W]O;U]?3T]/3T\_3T]/3T]/7U M]O;W]_CY^?K[^_S]_O__``$"`@,$!04&!P<("0D*"@H+"PL+"PP,#`L+"PL* M"@H)"0@'!P8%!00#`@(!`/_^_?W\^_KZ^?CX]_?V]O7U]?7U]/3U]?7U]?7V M]O?W^/CY^?K[^_S]_?[_```!`@,#!`4&!@<'"`@)"0H*"@L+"PL+"PL+"@H* M"0D)"`@'!@8%!`0#`@$!`/_^_?W\^_OZ^?GX^/?W]O;V]?7U]?7U]?7U]O;V M]_?X^/GY^OK[_/S]_O[_```!`@,#!`4%!@8'!P@("`D)"0D)"@H*"0D)"0D) M"`@'!P8&!04$!`,"`@$``/_^_OW\_/OZ^OGY^/CW]_?V]O;V]O;V]O;V]O?W M]_CX^/GY^OK[_/S]_?[__P`!`0(#`P0$!04&!@<'"`@("0D)"0D)"0D)"0D) M"`@(!P<&!@4%!`,#`@$!`/___OW\_/O[^OKY^?CX]_?W]_;V]O;V]O?W]_?X M^/CY^?KZ^_O\_/W]_O__``$!`@(#!`0%!08&!P<'"`@("`D)"0D)"0@("`@( M!P<'!@8%!00$`P,"`@$``/___O[]_/S[^_OZ^OGY^?CX^/CX^/CX^/CX^/CY M^?GZ^OO[^_S\_?W^_O\```$!`@(#`P0$!04&!@8'!P<'"`@("`@("`@(!P<' M!P8&!@4%!`0#`P("`0$``/___OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^?GY M^?KZ^OO[_/S]_?[^__\```$"`@,#!`0%!04&!@8'!P<'!P<("`<'!P<'!P8& M!@4%!00$`P,"`@$!``#___[]_?S\^_O[^OKZ^?GY^/CX^/CX^/CX^/CY^?GY M^OKZ^_O\_/W]_O[__P```0$"`@,#!`0%!08&!@<'!P<'!P<'!P<'!P<'!@8& M!04%!`0#`P("`0$``/_^_OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^/GY^?GZ M^OO[^_S\_?W^_O__```!`0("`P,$!`4%!@8&!P<'!P<("`@("`@'!P<'!P8& M!@4%!`0#`P("`0$``/_^_OW]_/S[^_OZ^OGY^?GX^/CX^/CX^/CX^/CY^?GZ M^OK[^_S\_?W^_O__```!`0(#`P0$!04%!@8'!P<'"`@("`@("`@("`@'!P<& M!@8%!00$`P,"`@$!``#__O[]_?S\^_O[^OKY^?GX^/CX^/CX^/CX^/CY^?GZ M^OK[^_S\_?W^_O__```!`0("`P,$!`0%!08&!@<'!P<'!P<(!P<'!P<'!P8& M!@8%!00$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^/CX^/CX^/CY^?GY M^?KZ^_O[_/S]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<("`@("`<'!P<' M!@8&!04$!`0#`P(!`0``___^_?W\_/O[^_KZ^?GY^/CX^/CX^/CX^/CX^/GY M^?KZ^OO[_/S]_?[^__\```$!`@(#`P0$!04%!@8&!@<'!P<'!P<'!P<'!P8& M!@8%!00$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^/CX^/CX^/CX^?GY M^?KZ^OO[_/S\_?W^_O__```!`0("`P,$!`4%!08&!@8'!P<'!P<'!P<'!P8& M!@8%!00$!`,#`@(!`0``___^_OW]_/S\^_OZ^OKZ^?GY^?GY^?GY^?GY^?GZ M^OK[^_O\_/W]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<'!P<'!P<'!P<& M!@8%!04$!`,#`@(!`0``___^_OW]_/S\^_OZ^OKZ^?GY^?GY^?GY^?GY^?GZ M^OK[^_O\_/S]_?[^__\```$!`@(#`P0$!04%!@8&!P<'!P<'"`@'!P<'!P<& M!@8&!04$!`,#`@(!`0``___^_OW]_/S[^_OZ^OKY^?GY^?GX^/CX^?GY^?GZ M^OKZ^_O[_/S]_?[^__\```$!`@(#`P0$!`4%!@8&!@<'!P<'!P<'!P<'!@8& M!@4%!00$`P,#`@(!`0#___[^_?W]_/S[^_KZ^OGY^?GY^/CX^/CX^/CY^?GY M^?KZ^OO[_/S\_?W^_O__```!`0("`P,$!`4%!08&!@<'!P<'!P<'!P<'!P8& M!@8%!04$!`,#`@(!`0``___^_?W]_/S[^_KZ^OGY^?GY^?CX^/CX^/GY^?GY M^OKZ^_O\_/S]_?[^__\```$!`@(#`P,$!`4%!08&!@8'!P<'!P<'!P<'!@8& M!@4%!00$!`,#`@(!`0``___^_OW]_?S\^_O[^OKZ^?GY^?GY^?GY^?GY^?KZ M^OK[^_O\_/S]_?[^__\```$!`@(#`P0$!`4%!08&!@<'!P<'!P<'!P<'!P8& M!@8%!00$!`,#`@(!`0``___^_OW]_?S\^_O[^OKZ^OKY^?GY^?GY^?GY^OKZ M^OO[^_O\_/W]_?[^__\```$!`@(#`P,$!`4%!08&!@8&!P<'!P<'!P<&!@8& M!04%!00$`P,"`@$!`0``___^_OW]_?S\^_O[^_KZ^OKZ^?GY^?GY^?GZ^OKZ M^OO[^_S\_/W]_?[^__\```$!`0("`P,$!`0%!04&!@8&!@8'!P<&!@8&!@8& M!04%!`0$`P,"`@$!``#___[^_?W]_/S[^_OZ^OKZ^?GY^?GY^?GY^?GY^?KZ M^OK[^_O\_/S]_?[^____```!`0("`P,#!`0$!04%!@8&!@8&!@8&!@8&!@8& M!04%!`0$`P,#`@(!`0``___^_OW]_?S\^_O[^OKZ^OGY^?GY^?GY^?GY^?GY M^OKZ^_O[_/S\_?W^_O__```!`0("`@,#!`0$!04%!@8&!@8&!@<'!P8&!@8& M!@8%!04$!`0#`P("`0$```#___[^_?W\_/S[^_OZ^OKZ^OKY^?GY^?GY^OKZ M^OK[^_O[_/S]_?W^_O__`````0$"`@,#`P0$!04%!08&!@8&!@8&!@8&!@8& M!@4%!04$!`0#`P("`0$!``#___[^_OW]_/S\^_O[^_KZ^OKZ^OKZ^OKZ^OKZ M^OO[^_O\_/S]_?W^_O__`````0$"`@,#`P0$!`4%!04&!@8&!@8&!@8&!@8& M!04%!00$!`,#`P("`0$!``#___[^_OW]_?S\_/O[^_KZ^OKZ^OKZ^OKZ^OKZ M^OK[^_O[_/S\_?W]_O[__P````$!`@("`P,$!`0$!04%!04&!@8&!@8&!04% M!04%!`0$`P,#`@(!`0$``/____[^_?W]_/S\^_O[^_KZ^OKZ^OKZ^OKZ^OKZ M^OK[^_O\_/S]_?W^_O[__P```0$!`@("`P,$!`0$!04%!04%!08&!@4%!04% M!04$!`0$`P,#`@(!`0$``/____[^_OW]_?S\_/O[^_O[^OKZ^OKZ^OKZ^OKZ M^_O[^_O\_/S]_?W^_O[__P````$!`0("`P,#!`0$!`4%!04%!04%!04%!04% M!04$!`0$`P,#`@("`0$```#____^_O[]_?W\_/S\^_O[^_O[^OKZ^OKZ^_O[ M^_O[_/S\_/W]_?[^_O___P```0$!`@(#`P,$!`0$!04%!04%!04&!@8%!04% M!04%!`0$!`,#`P("`@$!````___^_O[]_?W\_/S\^_O[^_OZ^OKZ^OKZ^OO[ M^_O[^_S\_/S]_?W^_O[___\```$!`0("`@,#`P0$!`0%!04%!04%!04%!04% M!04%!`0$!`,#`P("`@$!`0``_____O[]_?W]_/S\^_O[^_O[^OKZ^OKZ^OO[ M^_O[^_O\_/S]_?W]_O[^__\````!`0$"`@(#`P,#!`0$!`0%!04%!04%!04% M!00$!`0$`P,#`P("`@$!`0``_____O[^_?W]_/S\_/O[^_O[^OKZ^OKZ^OKZ M^OK[^_O[^_S\_/W]_?[^_O___P```0$!`@(#`P,#!`0$!`4%!04%!04%!04% M!04%!`0$!`,#`P("`@$!`0``_____O[^_?W]_/S\^_O[^_O[^OKZ^OKZ^OKZ M^_O[^_O\_/S\_/W]_?[^____`````0$"`@(#`P,#!`0$!`4%!04%!04%!04% M!04%!04$!`0$`P,#`@("`0$```#____^_OW]_?W\_/S\^_O[^_O[^_KZ^OK[ M^_O[^_O[_/S\_/W]_?[^_O___P```0$!`@("`P,#!`0$!`4%!04%!04%!04% M!04%!04$!`0$`P,#`@("`0$!````_____O[]_?W]_/S\_/O[^_O[^_O[^_O[ M^_O[^_O\_/S\_/W]_?[^_O[___\````!`0("`@(#`P,$!`0$!`0%!04%!04% M!04%!04$!`0$`P,#`P("`@$!````_____O[^_?W]_/S\^_O[^_O[^OKZ^OKZ M^OKZ^_O[^_O\_/S\_?W]_O[^__\````!`0$"`@(#`P,$!`0$!04%!04%!04% M!04%!04$!`0$`P,#`P("`@$!````_____O[]_?W\_/S\^_O[^_KZ^OKZ^OKZ M^OKZ^OO[^_O[_/S\_?W]_O[^____`````0$!`@("`P,#`P0$!`0%!04%!04% M!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW]_?S\_/S[^_O[^_O[^OKZ M^OKZ^_O[^_O[_/S\_/W]_?[^_O___P````$!`@("`P,#`P0$!`0$!04%!04% M!04%!04%!00$!`0$`P,#`@("`0$!````___^_O[]_?W]_/S\_/O[^_O[^_O[ M^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P0$!`0$!04%!04% M!04%!04%!00$!`0$`P,#`@("`0$!````_____O[^_?W]_/S\_/S[^_O[^_O[ M^_O[^_O[^_O\_/S\_/W]_?[^_O[__P````$!`0("`@(#`P,$!`0$!`4%!04% M!04%!04$!`0$!`0#`P,#`@("`0$!````_____O[^_?W]_?S\_/S[^_O[^_O[ M^_O[^_O[^_O[_/S\_/S]_?W]_O[^____`````0$!`@("`@,#`P,$!`0$!`0$ M!`4%!`0$!`0$!`0$`P,#`P("`@$!`0``_____O[^_?W]_/S\_/O[^_O[^_OZ M^OKZ^_O[^_O[^_O\_/S\_?W]_O[^____`````0$!`@("`@,#`P,$!`0$!`4% M!04%!04%!00$!`0$!`,#`P,"`@(!`0$```#___[^_OW]_?W\_/S\^_O[^_O[ M^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P,$!`0$!`4% M!04%!04%!04%!`0$!`0$`P,#`P("`@$!`0``_____O[^_?W]_?S\_/S\^_O[ M^_O[^_O[^_O[^_S\_/S\_?W]_?[^_O___P````$!`0("`@,#`P,$!`0$!`0% M!04%!04%!04%!`0$!`0#`P,#`@("`0$!````_____O[^_?W]_?S\_/S[^_O[ M^_O[^_O[^_O[^_S\_/S\_/W]_?W^_O[___\````!`0$"`@(#`P,#!`0$!`0$ M!04%!04%!04%!00$!`0$!`,#`P("`@$!`0```/___O[^_?W]_/S\_/O[^_O[ M^_OZ^OKZ^_O[^_O[^_O\_/S\_/W]_?[^_O____\````!`0$"`@(#`P,#!`0$ M!`0$!04%!04%!04%!`0$!`0$`P,#`@("`0$!````___^_O[]_?W\_/S\^_O[ M^_O[^OKZ^OKZ^OK[^_O[^_O\_/S\_?W]_O[^____`````0$!`@("`P,#`P0$ M!`0$!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW]_?S\_/S[ M^_O[^_O[^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O___P````$!`0("`@,#`P0$ M!`0$!04%!04%!04%!04%!04%!`0$!`,#`P("`@$!`0``_____O[^_?W]_/S\ M^_O[^_O[^_KZ^OKZ^OO[^_O[^_S\_/S]_?W^_O[___\````!`0$"`@(#`P,$ M!`0$!04%!04%!04%!04%!04%!04%!`0$!`,#`P("`0$!``#____^_OW]_?S\ M_/S[^_O[^_KZ^OKZ^OKZ^OK[^_O[^_S\_/W]_?W^_O[___\```$!`0("`@,# M`P,$!`0$!`4%!04%!04%!04%!04$!`0$!`,#`P("`@$!````___^_O[]_?W\ M_/S[^_O[^_OZ^OKZ^OKZ^OKZ^_O[^_O\_/S\_?W]_?[^_O___P```0$!`@(" M`@,#`P0$!`0$!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^_OW] M_?S\_/O[^_O[^OKZ^OKZ^OKZ^OO[^_O[^_S\_/S]_?W^_O[___\````!`0$" M`@(#`P,#!`0$!`4%!04%!04%!04%!04%!`0$!`0#`P,"`@(!`0$``/____[^ M_OW]_?S\_/S[^_O[^_O[^_O[^_O[^_O[^_O\_/S\_?W]_?[^_O__`````0$! M`@("`P,#`P0$!`0%!04%!04%!04%!04%!04%!`0$!`,#`P("`@$!`0``____ M_O[^_?W]_/S\_/O[^_O[^_O[^_O[^_O[^_O[_/S\_/S]_?W^_O[___\````! M`0$"`@(#`P,#!`0$!`0%!04%!04%!04%!04%!00$!`0#`P,#`@("`0$```#_ M___^_O[]_?W\_/S\^_O[^_O[^_O[^_O[^_O[^_O[_/S\_/W]_?W^_O[___\` M```!`0$"`@("`P,#`P0$!`0$!04%!04%!04%!`0$!`0$`P,#`P("`@$!`0`` M_____O[^_?W]_/S\_/O[^_O[^_O[^OKZ^OO[^_O[^_O\_/S\_?W]_?[^_O__ M_P````$!`0("`@(#`P,#!`0$!`0$!04%!04%!00$!`0$!`,#`P,"`@(!`0$` M``#____^_O[]_?W\_/S\^_O[^_O[^_O[^_O[^_O[^_O[_/S\_/S]_?W^_O[_ M____`````0$!`@("`P,#`P0$!`0$!`4%!04%!04%!00$!`0$!`,#`P,"`@(! M`0$```#____^_O[]_?W]_/S\_/S[^_O[^_O[^_O[^_O[_/S\_/S]_?W]_O[^ M_O___P````$!`0$"`@(#`P,#`P0$!`0$!`4%!04%!04$!`0$!`0$`P,#`P(" M`@$!`0```/____[^_O[]_?W]_/S\_/S\_/O[^_O[^_O\_/S\_/S\_/W]_?W^ M_O[^____``````$!`0("`@(#`P,#`P0$!`0$!`0$!`0$!`0$!`0$!`0#`P,# M`@("`0$!````_____O[^_?W]_?S\_/S\_/O[^_O[^_O[^_O[^_S\_/S\_/W] M_?W^_O[^____``````$!`0$"`@("`P,#`P,$!`0$!`0$!`0$!`0$!`0#`P,# M`P("`@$!`0$```#____^_O[^_?W]_?S\_/S\_/O[^_O[^_O[^_O[_/S\_/S\ M_?W]_?W^_O[^____``````$!`0$"`@("`P,#`P,$!`0$!`0$!`0$!`0$!`,# M`P,#`@("`@$!`0$```#____^_O[^_?W]_?S\_/S\_/S\_/S\_/S\_/S\_/S\ M_/W]_?W]_O[^_O____\````!`0$!`@("`@(#`P,#`P,#!`0$!`0$!`0$`P,# M`P,#`P("`@("`0$!`0```/_____^_O[^_OW]_?W]_?W]_/S\_/S\_/S\_/W] M_?W]_?W]_O[^_O[_____``````$!`0$"`@("`@,#`P,#`P,$!`0$!`0$!`0$ M`P,#`P,#`P("`@(!`0$`````______[^_O[]_?W]_?W\_/S\_/S\_/S\_/S\ M_/W]_?W]_?[^_O[^_____P`````!`0$!`0("`@("`P,#`P,#`P,#`P,#`P,# M`P,#`P,"`@("`@$!`0$!`````/_____^_O[^_OW]_?W]_?W]_?W]_?S\_?W] M_?W]_?W]_?W]_O[^_O[^_____P```````0$!`0$"`@("`@("`P,#`P,#`P,# M`P,#`P,"`@("`@(!`0$!`0````#______O[^_O[]_?W]_?W]_?S\_/S\_/S\ M_/S]_?W]_?W]_?[^_O[^_O______```````!`0$!`0("`@("`@(#`P,#`P,# M`P,#`P,#`P("`@("`@(!`0$!`0````#_______[^_O[^_OW]_?W]_?W]_?W] M_?W]_?W]_?W]_?W]_O[^_O[^______\```````$!`0$!`@("`@("`@,#`P,# M`P,#`P,#`P,#`P,"`@("`@(!`0$!`0``````_______^_O[^_O[^_?W]_?W] M_?W]_?W]_?W]_?W^_O[^_O[^________`````````0$!`0$!`@("`@("`@(# M`P,#`P,#`P,#`P,#`@("`@("`@(!`0$!`0``````_______^_O[^_O[^_?W] M_?W]_?W]_?W]_?W]_?W]_?[^_O[^_O[_______\``````0$!`0$!`@("`@(" M`@(#`P,#`P,#`P,#`@("`@("`@(!`0$!`0``````_______^_O[^_O[]_?W] M_?W]_?W]_?W]_?W]_?W]_?W^_O[^_O[^_O_______P```````0$!`0$!`0(" M`@("`@("`@("`@("`@("`@("`@("`0$!`0$!``````#________^_O[^_O[^ M_?W]_?W]_?W]_?W]_?W]_?W]_?W]_O[^_O[^_O_______P```````0$!`0$! M`@("`@("`@("`@("`@("`@("`@("`@("`0$!`0$!````````_________O[^ M_O[^_O[^_O[^_?W]_?W]_?W]_?[^_O[^_O[^_O[_________`````````0$! M`0$!`@("`@("`@("`@("`@("`@("`@("`@("`@$!`0$!`0````````#_____ M_____O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^__________\````````` M`0$!`0$!`0$"`@("`@("`@("`@("`@("`@("`@$!`0$!`0$!`````````/__ M_________O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^____________```` M``````$!`0$!`0$!`@("`@("`@("`@("`@("`0$!`0$!`0$!``````````#_ M__________[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O________\` M``````````$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$````````` M``#______________O[^_O[^_O[^_O[^_O[^_O[^_O[^_O[^_O__________ M_P```````````0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$````` M````````_________________O[^_O[^_O[^_O[^_O[^_O______________ M_P`````````````!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M``````````````#____________________^_O[^_O[^________________ M____``````````````$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0`` M``````````#______________________O[^_O[^_O[^_O[^_O[_________ M________```````````````!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$!`0`` M`````````````/________________[^_O[^_O[^_O[^_O[^_O[^_O[^_O__ M_____________P```````````````0$!`0$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$`````````````````______________________[^_O[^_O[^_O[^_O__ M_________________P````````````````$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$`````````````````________________________________ M_________________P````````````````$!`0$!`0$!`0$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$!``````````````````#_________________________ M________________________``````````````````````$!`0$!`0$!`0$! M`0$!`0$!`0$!`0$``````````````````````/______________________ M_____________________________P`````````````````````````````` M``````````````````````````````````#_________________________ M______________________________\````````````````````````````` M`````````````````````````````````````````/__________________ M____________________________```````````````````````````````` M`````0$!`0$!`0$!`0`!``````````````````````````````````#_____ M____________________________```````````````````````````````` M```````````````````````````````````````````````````````````` M______________________________\````````````````````````````` M`````````````````````````````````````````````````````````/__ M__________________________________________\````````````````` M````````````````````````````````0T]-30```!(``0``1H``"$`-K$0` M``````!-05)+`````@``24Y35````!0\``!_`'\``````````````````$%0 M4$P```&H4V0R80`"``````````````%````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````"P```````````````` M``````````````````````````````````````````````````````!QV?P` M````````<````````````````````&```)VX````<=KD`'':4`!QVDC__P!Q MVA"J5:I5!`@```````D`(P````````````````!X````!``$``````!6_@#_ M__^``````0$@!E%5;FET@``"1Y0050C```)*DQ74E<````` M``$"1@8@T]B M:D1IT]B M:D1I'1R86QE M=BYC+F\@M@T@("`@("`@(")[3V)J1&ER?2)F:6QE_["@GY[@0:`>L$&`KO_1L`[0<-`?CQ]@L)\/G][PT4Z/(; M"?`$%`@!!P0)#?GY%17KY2`AV^,5!.KT`0']`?WQ_Q,"\@<,\@(>`?$.%/_\ M#@GX``3U_`+W]@#_Z_L:\N0=!]\.&NOV'@GU$`GP#Q[P[A4"Z@(&[_<(\O0, M]N8#%/OD_A@&\0`7"/D1&0#Y!@T"]OT!]/7]\_7V\OGOZ?0$"NSI$`O[#@P# M`@`-$`7]]@80]?$'^>W[\_#_ZN`#`_/Z_`0'_0@2#0D`!Q<7!_0%%`'\]>O^ M]N/U].;M_`;MV`P"'!GNX__YZO3TZN_P M]0KUT?DC]-@+'0($&AX/"0\*"`H"`PWUZ`;VT.H,^]?C`/?N[_7]]?`&'PWV M#2@=_OT3"_T0$?'N_/GP[NSO^O;L]O;N]_+W`_'Z&Q($%AT0_P<=!OL8#/+V M\/'_\NGQ_?G=[0GOX?CXZP,6`08B%0H8$@`('Q'Y#0;=^2#]V_(&_/;TY^;X M]N#L#03X%!L,%AD+"0H'#!,/^^P%#N[U$O?B`/K?\?/Y0G]Z1(D"/X/%O?]*QC]$@+R(!_O^ACZUNX#YM#=[N#7^`OW M\@8;(@7M!R(C#_D,&0X4"?L>(>GA_O7I[-O.V^/P!?[J\QTK`.P0'!,5#/\% M)"#Y$S<&Y`0$XN;HS-;OXMWW"?KV$Q;X`R$1`Q49#A,@$1@^%_(C#\?F$=J_ MZ=S#]07>\Q;RZ1<:[NXN-//W*RD2'C8H"@$$`?/FX]S4U=SDZ.[Z_NKG#Q#E M_R\4^1`>)#0E#2U'"]0(*-R][^G"V>O>\_O5WA7_UP@9\PLD!@\_+`7:W_WR\PH!#C4@ M$$E6)RY,&^T'%OK7R];J\=/.[./-U.GNV^8+_O`C-1]TM7'T_KUT/0J)"HX-%9F/"0O M.A7R!_+?`N>^V^/0OZO.Y,;.U=SW]PPG)#,]6&PN(%LM*C*\-;T*BU'85Q28'1;."LA M'0_'@H&'`3X`O/QSK#-Q*VOKJ^WY03C^S,M,#U#34%%23`^ M-Q(T*/'\[,[)K:BJEYNDKKW2`/X"1$8B-DI-0R,P/`D'+A/Q!O[0U>3(N\C) MQKMY_$0%0DB.!X9/D`F,40P M*34E$A'^W-;CSZ:\V:ZRYM+0^>76`B,6"S!%+SE<5T!!,R41]O;.J\BZEZ>^ MO[70Y>$.#^ MU<&WX=:IW`/0W1/WYAPU#@],.P,O02$P(@;[\@'VULO7Y.7KW-3[]M;A[/#N M\A(1`APE&R$;,5(M"1HE$_WK^?S.TNK7U^+%K=+KU>0&^00T.2DP-SI`-!82 M)`7K[=_AV-+5P=WRU]O?Y?3T$"L:#AP^-@TF/`T"$PP,\>#ZZ^+OV>GNR^3M MT,K1[OOM_AH9$B$Q)"M8-`<\0A8G(?#P^.'/T(+[^,/$_X;/R8<-S-$1R,?$`@/XM;MUL.YNLR_Q]S+\1WT M\"<=!2HM$"(L)#"M_6].&\WN/#S][QY-00&@4>&2DZ-E]+%S,K"P?FX?/?S\K'S\W6 MWM'F]^;T`O8#'P;L+SL(-T@>'R$8"@L8!OT%[_H,[.3:S.KJT]/&Y`7>W@H0 M%2LS*B,Z)@(2#/?_`^?<]_7HZ];=_O+J`@S_$#(:""\X(R`3!`P`VM'K\-;< M]>7G!_CH__/N"0+[^_H1"@`6$!(I(`4((!7U`Q<&`PX#``[RW_K>R^;3U?'= MX0/Z]!0<&Q<0*S`7!@`(%A+Y\0\8\>;N[?7FZ_;@_17R!1?Y#A__!!/U_1[[ MW.\#$OWM#P+G"03G[??WX.<,]?,:_O$B&P M\\S-\.OJ_`/T"1_^!C4:_R,8!B,5`QH'\_<(`0`%("8)%CXI$"P>#B$D#_D,\;[P_L_AZ.?;S0\` MRO_LT",3WQRP#RU``A&Q(D.C,?&QTZ//T!&_WJ_`S=V1/RS@`+Z=/H#>;("R\/ M_@\M'Q$?$2`I[^L.^L_/#>VP]NK&]^+:^_OKWAH_!B]2%C%)0$@/'#7:!C3" MTO[.SM'/R=S_RK/Q^MC;`!@%""X?"!XT/1X+(R4D"/0?$N3Q"/KM!_;!W03U MY=_L`@+_!`07*AL-"A('[MWEQ]K:R`G_Q.L)!!`5%!SN_AM:S2^MF]\/'9__?B^?GX`QG[WT`Y[#$W!SU!$!(;#/\#]^02"\OL M_]_C[>[3O^[SW`L;#B0>$BLY&?/Z!O[7J-H0V;SQ!O<+(!(&+BWT&C$/+3$/ M'Q?[$1'CV=_'O]_CM.4MY]\J)0']&0?7\OW9[PL0$`4E-R@P(Q\H_.?Z!0CI MX?;K[/OR\.S=Y/?LUP`U%@D_.1(H(O/V[-#+M;S>X.;R`!XG(T1,&!P^'`$( M"10/ZMW[!^_?V][HVLSC``P4#A0F`P$G]MW_[;A$P(.4E%# M7UDQ*2$*"-.N[-N@TNSD__8"(A3WZQDKZ.GD[?P3(1$%#P+F]_7'U?+4O='PY^+X\_(#&!L1*S8K M,R/PV-4!_=K[&_;9XNG>VO#QU.D'\`8?``@;%!8*!@_[ M&#@'$S\P*"$AGW M\Q-`%Q-;+`I&,`@;%??EY,>GR-:EK_3\UNLC)0T:+A0'(PWB_P;7U^GGZ@`@ M!ODO)QPZ*S=-)@,)%/?-U]RVOLZ_W//N^AHC`QU(&_T)\^?XX,K7W.KZ[NT5 M0R\',F,S"$)(_P#ZQM+@O\;HS[OV#^'R,S`,%AL=(P`(`]'S#M3,_/?L!O+I M'"+`X,)0/M[.T`YM[WX>T,Z=GP#0WR M`O_^(@SN_/OM^O[F]`D&&1X`!$A<$/PR*?KHX^?Q[M3.]`/Q_@D'"@`'^]\( M#,K1X-<`^K4W.W: MPL?-V=SF#Q41,CHL+5)@&`U$*03\!AOU]Q;X^PD&^=0!#\'P!Z"_^,:UO-': MU>[Y,J^YQ$!`RL])18]0!0<*18"[=_F]M6GO=?9V,WH"O\.)1TM M-ATB(@@0[=4$Z=`,)0^PTJ+A@: M*CL@^@?\^B$$V_<*_>/7Y^SYY;38__#_$@,",#H*!B]+(@@D"1DX]?4O#N#F MY,.QQ\^WL+##\N[I.5TD)%$Z'34Y'0P/!O0`^@@O_N($\N#=T][EV]'-W?'T M`/;L&A#M#1@?*BY9125032`!^P#/H*>EHKC$T.O]%#T%W.0O+/L,)1+X MZ-?(WNK1UNP`'A<&(4%`+2`C)186$^C?"`O-M.?>L[[!PN<"^/@D0T-!.C0Y M.@[H`_C.U>#?W.,!#@'^#A<(ZN/X_>S@ZP<*]/<2(Q']#1<6&Q0+$AL9!P41 M\-CKW<.VL]?AS?D?$1LF*#XI%2P1_P_LX@(%^_G]`?KV!@/;ZP[DX0[_`!H) M`PH#!0D%_O/Q"13W^QP:`?<"!_KGX.7EW]CA]@\;``8F*"D-`R@8_1<)]A@3 M]/\3_>;^_,W,[>;+U.[LZ@L'Z`D>#Q<%_20D%QDA+2`C'P<<&-W9[N/>S]+R MZ_3[\!@*W/D-^>OS^?P)!`\B%!H="QX5\/@`__7G`/_R#!(#\>?Y^_/]^0(6 M#Q,7%2<>^./[!,.[\=6[Z/WM\1,B#`P@#`LB`@P\&08D'14A(@+R"/WM\>CF MZ>WNZ>':ZN_:R=+DY>?Q#B<6'4A%0#X<*CX;`/W]\N;DX>OR]O7U!^[9_0/Z M\>[OW.X(^0HC$@L,`^CA M\=?0Y-WK]_,0'!\H#Q`N&`@2_Q8N]NT/&0G>[/[?X^/9V^#Y_?#W$1H)&AGR M!1#G^/_:`S`'\!4R*10:)18$_.C>_?S3Z`'E\P?P[_?_`<_2_^KD`P\<*1X) M&2D%]A("Y04(ZA8['04;,@SG[?'LV,K;ZO3T^0T-`O_\].3(PD4$>X'`VN+BT+P%!L.$`P+#@X0`1HW!0M**1@X$`<4Z.WP MU.3I\@#H`"P9`OS[`-J[T-/&P,;H_@`#!1XU'@P?-C<@($`\)SM&'O\+".#' MR=')M+K:\?/Z`0`.\M#FZ=S+X%Q@2-4Y"0%!((18P-@WP#ASVXNCDV,K% MNIVVX,7#[`<9%A@;%B@G"?[T\?SQZ@4?)R0A.#TK)`\1'?OM[^3S`/'8X_W9 MN]GFR/?X>'Q^>+R"P\B'BQ<3C=68D`P.1GT^NW:Z_OWXNOSVN#KW79 MU`D4_P@;+2LB'R9`1#8]7F,[,BP-!^C*V,VYN\[6QM;^\N'X\>KYXM;R__3Y M"0,/-!WX&2L>#P(?(Q%"$T/RXB,349$!T)!AP2`._?X]:ON->ZM,/%Z?_\_0$5%@4)#P\< M*1P7+SLP+3@Z*Q/^]NK=W-GM[\K?!-C-^.;)U]SD[^OR`1HU(10L&@\M'OK_ M$A8-!0\A,2P/`O[N[_#8TN_OUM;<[_OBXOCHRNOYRO@BZ_DB&R(B)"\H+"@( M&282-S3Y"B@7`?;JY/#?LJFVRM?*L,+[[-?_]_\?_O\C'A8A/#@M5DDD-BTA M*QS_Z?H1[-/_`^7SY+S`SLFUNK6T/07^N\K,`\E-AL"#"L<^`88"PH0"!HG$A`3$@GRZ]SF M"NB[V?[@R??VV/3]YMCL#@$*)A(-,#$)%#TC^P@2_/49)0,%&`+_#^O:_N7' MU<_4Y>K?WPD#X`0?^>T.$00<*!\R^;?Z`,4 M!OL@+Q\<(2PP+2(=*CPQ"0P?!/X$]?#T"`/=Y?37TN36Q,[SL]>G?T-;;R-;7N=3YWMGZ\N;_`/8* M%0X;-BPC/$-#/3$R(14:%!\3\`4$Y>O+GZ=KAQK[7PL#6W.+&@\,_^;IZMG,U?#GR]GLY.T`\MKN$`?W^!8L$A`:!PD8$0('$Q4%_14I M(B`G%_X%_-WDZ,K$XM.\ZOK5Z1#VZ0P&\@\;"A$1`Q,F%PT7%`<7*1(4,R86 M*!@`!/'>XWVX@0P'2,O+40Q%24B'BT@"A4:%!`%!Q8<"/+_ M[\SGZL?:WKS#Q\/;XN7DX0PG$AXW1E,U(2T>%AH4#_OO`@O[^A`5"@+Y_`#H MY@+MRMONU$@P5)18%&!\<$P<7'Q\A$@H,#?_M]O??U-;,P,?= MWM/B]/+[$`S_$"00!A4$!!T(]ADH$P\;+#4F+345$B+[W_3LU]?"M<[&NM+9 MT]CO`_8%-"X?,"<:+"L@&P<+%04)#@8A.`GW)17=Z?[ET=?6N\KQV=3RW=\( M_N0#*QH&(S4G&BDU(!01!@L'[?D:!?8;$_'[!OOQ]>C#U?/:T.?PY>3V_/#R M#@P!$@#_+2\<&1\O-"#_"S(<`!(.\O\,Z.+SX=[7P-/DU-'>Z^#5[03\^`L> M'@4%,R\#&D8N%"XH%CDW#P\3#@?NU,W=U[ZZM\+9T<_G\.CN^?D)%QDF&A\P M&Q\Q)!8?*0CX'!@''1<##1+RU^G_Y+JXRM#1V^SD[0;T[O\!$A\."PP$'2@' M%BD0$Q8+%Q\<$A0M(`@8%PL%Z=C?SK?#TL:\S]3&Z?W1Y"4=]`4U,0P:24$; M)SHL)BL?$BPG[?(6]][SZ\W*ULZ\PM+=W='-X?H"]OPJ.!01+"$H/1(90!4. M)!@<&A01^O@`].3=W]O@X\O+\?_FYP#KV0`'X_(/"04!"1P-!A83%!L-`Q]! M)QH^'P@L%_'P^^W-S;JGY/K+V_;7XPKTWP,8_OH*!`TA'1XD'A49)!P=+BLE M'10@'0+Y\NS;L*_!L+?+Q,_AZ@$(!!$I/1H)/#(('R\:"1(6`@H;#/\-%_[] M"O'W$0#IX-O4U>+/Q.SJNM$(_?,;."`5,#(A'28V&>CX#`4-`P0A%_OV_`3_ M"0C5X`C@S_#UY.?OT+WI^-OC]/H/'QD;.DPM(SP7`S4I^0@?#_P$_.O^".K2 MVM71W$+#@D#(3`)"18)#Q\4"!$8)R(**T$4'S+S]RSJNO;\Q<';R*_6 M].'6U>X%\.X,)R<+!1DC&Q$6%!`0^.D<.`\;/RL;(!X8$@P`ZM3`NLC*Q;Z[ MV.#$UP#^_Q@9#!LO*B0V-R0D&0H2&1@(^QDF^_4@$.\3"\?4]&!``!B``Y._Y#`+P__OOZ=OJ[N#P[M//XNOI M\?L$#0#S"1X>(QT0&BH9^"%-$_HC'O3T#/'K!>;+W>??X_/JX.7I]/?PZ_8( M_OP!_A87#1T:$ALB&14Q-QL='!`?$.#K#>FPQ-2WS.#6W>?Q]/P!_ALM$?@' M)R`("QX@$`D!`A<8$Q@5%Q4/"/X(!>WKW[R]W=K'TMG>\?CX%#(6`BSDUNOLY??U\P/[^@X1$C1.(11'-10H M)QLF(OSH`0?OYN'AZM2XQN7IU-GU\NG^!?H,%OP!%?7O%`X!&A\&_ATV'1X^ M*Q$A)@;S`0S^Z^35S.#GUL_3T-#GZ=SS"P@)$`L*%!D9$`X(!AH;&RLN.$`T M&PD;(?OK[]_)P,_2P,[=P+W?ZN7E^`X<)QD9/CXE-2L"``7U^@K\_!H6_`@: M%A\8[>4(\\3;`?#7UN7OY^CJ[`0%[OH#`2$M&Q02&!#W`0SW`QS^[R$B"",O M)!<`!0SNXO/GPKS/V-+/W.?P\>CU_00E)00:22L*+S(>*"<.``T/\/,-_.CV M]^KJYN_NSM/DVM78ZPD,_@4=(!8@(1XM&_<#%0T2%@H-#?GP[.W[]N38W>K\ M#?CK%Q[N[!$'Y_\3_O0`#P0+*Q3W`@;Z[O4`_OT#$A$)#R$F#@8'\.__Z^#\ M]][K\O/SV_T4X.0%__3\(2$.*"(,(BH/_10B"_GM_!T2``3T\??;TN#5V-/! MW.S;Z`L@%A0C(R(;*$$I"A8#'!H>$Q8S)Q0H'P((`OC^]PP1[P8;^_#[!P?BVOGOW.8`!M[K$.#&Z?#G M\?/J\?\.(2HP-B89+"X6&Q,,*A[_!!`8$@3RYN;1QL2\Q\R_P]WEW?@(]O\: M%0$()#X])39.,RDS+!P9&?;I]_/T[O3\X.#TZ]S,SN?1N.7NT_@&^R,P$`L; M'!P;"@TE#?D9$0HC%`X8"/T%%0'Y$P+R]_SRY0?XO]'AS,+&Y?#E_0/D#4(A M$1H@*@L)(!,>(2$Q$Q$V*0D+%O??\=_+X>79R75U][.VN\!!_,0(/,3.1,7*!D='10,!A$3!O__\.0, M&NST(`GC^_W8XOKLR+_6T-;UZ.\/_P8E)B@G)S(H(RT3"BH5`A3WY?[\Z>G] M`.;C].#;!_G&U/#JT-'N^O/K`A4*&S`J+"TG,#(=&AP.$@L!`M_N&NK0`?[, MSO#JTMGM\^K?Y?H'^_80"/`/'P@3)"4F*2X6"BD'$//Y"_SGYN;8 MR-#DVWC_B,-^1`3!Q`6&A,-)2L<%1TO(1,C&_OV$0SZ"`OYW^;PR<36 MP+C+QL3?Z_8>'/X5-STH"1].)_<@+@@('R4:"0#\!!,`\`+[X-_HV<34T;?3 MV[+*_?KP`AH;'3HZ)#Q`&R0U!NH1%_7X`_KM\P\0`P@#`@G\W-#K\M71V,K1 MZ.SM\._V"B(6_RI$&R4_)!`7*"?^\1<-Y?T1`0T-_@K[W=S?W-'(T,S(VN7J M]OL'"0(4)RLH,$`V,"XM."4?*`#A\O7DZO3CXNK?ZM_1\>+)[??CVNT<%^P# M)A45&PL=,A+]*#L-^ATS'OWX`OKW^NWQ\.;V\-33Z?GEV^WLY?0-"?0"#P(/ M%@83)1D(%RL+_B8G$R(/[A,L!^\##>O=[M>YR]7%SM;.W.WU^P(3%A89%R0P M*R8T+`T4(AX/`A44\>3X"_KM\N[YY\;-T=#.R-;/ROD)^`XA%A\W,R`;.TL/ M"CL1_!L$^`L$\.3@[__[Y.`)#-O4Z>GAXN+:Y>;E!P?W#!HB(0P:.BP8'B4H M%009%PT9_^3[$/[L\OKY]>[BV=?=W=W;SMKKZO;V\A,7"Q(/+$6OMN#+PM[8S>;X\P@5"1XJ'"`H+S$F*#;ZS\3@T+?(Z?+BU_`-_OD6(A<6'Q``'R\4"Q\N%_8.*Q`$&!;X MZ@H?_-_V#?'-S=O5O<;=S=KKW/L3!@P.%AT-%1\5'"\T)B`E&B="'_T)"P?Z MW>/T\>C2R=*[N-K%N=W8SO05$A$G,3,N("PX)R0O(A04$Q`@(07]^_#H[??C MVO#JTM/?V=7JZ]?F\>7^&@4!)R(&$RPQ'!8K*!4,`0DG)0+X"@7Z`?WV]_?U MWM+7T]79V=G9Y.CK`@WY!B8)^B4J'BHX0S48'"4?+QOI_`3@[??=[0/GV=W: MU\G0Y-O5W^CZ"@D6*Q@$$2`D'ADI."4/(286)B#Z]_O@VNODX.WLX-ODY-WH MZN3FXNGX_@\.!!H=!@P:&2`E'!T>$Q,?*1\+&1#@[@KLW^WJV]WDUV^?P M_A0?'AX<"PXF)!HM.2`6)!L1&14,!>W9ZOKNZN[K\??JT,_=W^+BW>/H^108 M$Q47$Q$1#A,B)!<0+"\""RT8"POKZP;RY?3V]^OJY\G.YN#8WMS&V@\._1(> M#0D5'B4H+#0Y)PP4*2(;'/SC]O[EW?7PW.'2QM;-Q-SJXN+EY04C'A8.&R01 M&"4P/R`50S/X`208]>KMX>#W\.#Q_?7RZ]/0[-G)]NO)]!8,"!PF"0XF!_D? M+2$@'B0C#!$='!'MZO;EZP']]P+_W=?JX-/8U,[.T>/X!107%QX<("$F1#X= M+T,D"ADH'Q/]Y^+C\N_GHU>D+#ALE%0X>,S,?*4L\(S,I M"/T'$@/FVN7FV^KT[.3G_NK#V_CMX_CTUN\=&@,-)0SV#A(!"B,U+AXH(PL= M+POZ#>[7]_KH\OOT[-O4W]W,R^#=P=@'"@(1(AH-$AD/#2PS&"M`)1DC)S(B M]^[X[-O6Y^S0T-_*PN#:O=+S[-CL%AP<-#LE&20D&R,K)QT;$?X$#PP(!?'? M[NSA[_+GU]C@S=ORT]\+\,WQ)R46(!L8&!04%1\:$2(A$`L'"Q$&_?GX`/_[ M!P/Q\?'@T=36P[W:W]'?]@H)$204$B09$!8L030N.S(=$QDJ&.G>^?70T_GT MV-K6R]7+P-+';UMKG MZ][=Z>CR`NG1\102#Q,2%1D6#`H8)B@5"2$K#@D;'A4%_?WP[P@!V<_EZ,O` MT-C=X-OE]/3T!Q@2!`T:"@@B,3(L+STU)Q\=)!@&_N?G__#;W=C6T+>XQ[S! MVN;@W`,J)"8P*"0J(P\:*R`B)1\L(P(-*@WD[?/=WO#OX>7QY]O;UMG?YNOB MWNX,&A4<+"<;&`@('1P."!,<#@D6(!T-!@?^]_O^^O7PZ./>VM3-U>3#1TC#/+BZ>WH\/GPY>WUYL[1[.O7V.#B\P(#$1H5%`L* M&"`H'18U-"$O+R@Q*!#W]@/APN3HO?QYM/3VL[`T^7I^O_W!1`7)R`-%1X0_0DE(B(H M%1PF"@,/#`;Z[NSN]0@*[/`#X#;X._HWN+?W./=R,?>Z-W:WNG^"`\5%RPO&2,R+#`M)S`E&1`! M&"#Y[.[AW.+GY=S.W//2N>#UY^O^_NSV%`P`$A4*!@XH)Q8L-R(C+2(*`A@= M__'PYNP`]=K;W];5R;[5Y.#L]?/_$Q<.$!43$`H4&QPN+R,M+BTB`A`M!=_J M].[E[.[6WNW0P,G-U^'FX>H+!P0K)`XJ*`L2)"04'289)"D4!PDA'?;KZ.W] M[]SE[>C@SLS6TM;5V/'LZP81$ALK*A,5-3X@%C;L!.S@\>7B MZ-K9VL[&U>?8UO#[\NS_%146'AL7*SHG)C@V+"8=!`48"O;N]/;AX./I^M_) MW]W)R]7>[_;L[?X(!Q4>`_H8+2@7(#\^+3DN$2$?`@7\[NS9V?'UX=#=[].] MT]G1W_'VZO$1&18>%AD@#Q0C'RHO)"HV+1(/)B0&\_?HT>7RV<[:WM?0PL/@ MYM[H\_G^"1P;&#`H"24]&QDO'1HP)@X.$A0>">?V!.34YN;-U>*^LMG>R>0# MZND+#0H7*"D,"RXV(AHK+Q\G+PSX#1L6!.[W_N/H_>O@X-;4PKC4V$0H-&Q/GT.7QV]3>T,7AY+2XZ>[F\_3S!1<<&!HG M*RDG&"$O&QLJ&!8:`OX3&0_^Z^SXZ-[GVM+DW[BUW>SAY/'R`18!`B@F%1D: M%!LN+2(B)RPG$P84(!8&[N[YY.'MW]/2SL"WPLG3Y^;A]@0')"P8(C0G'2LU M*",L*S`O!_PA'@7_Y]?EX=7?W\;0\-BXR-GAZ^CJ\P(2"Q4S)Q#FX<[G\=+$QM/GY>/S\N;V"@X2&R$7$"(O(QXS/2SGVM+8WM7&U=S&Q,K&W//J[P/[`B`A(RL<&B`1&246(#0B&"<>!Q8H M#/'S\N'9Y^O=U=O?TL70X]S9\?GL\0L7"0LE(PT''C$=%C(Q'R,I'Q?@]PH1&AD7)288&B?= MY>S=RM7EVL2ZP]OV]M[C`!,;'!D;)R81%BD>$R$N(A4>&`P4$`7\Y.#W\=G? MZ//WV\_@V=/D\O'BYO\*#!$6&A\5!A4C$Q@J(!DC'@T1)1\$^??P[N_JYM[= M\.C&RMS>Y^;G\>GW&!,$'#`4""0L'R(O*Q\E*A8'$A(`^?CKV=KHW-+=V=;9 MT-'A\/W]\?80(!H8)2(3&"0=$QLG)!L6%14*`PX'\>??X.WKU]OSZ-C@V=3L M\^GU`??Y&B83%!L7%Q(/%!<>(AH?)18/&QH.!/+HZ^?:TMGDXM30V=;/V>7M M\?#U!QH4%2\O%QDK*!PD*1PC,B,-#AH6"/?HXM[1SMG3Q=7@S,#6Z>;J]OC] M#1<6&BHR)!PD)R8>&2@G%A84"A$6!/3SZ^?KV]+EX\K4W\G2[-C4_PKT_!89 M%28H#0\D)!H9(B,E*AX<)QP2$`#S[_'SY-7@Y=;7V_QY]?@[=;+[.K+U.;GY>?N[/4(!`86%Q<8$!8G M(Q06*C,E#0CF[0+]^PT5&1P0"QPE&1PA M'S(W&!$B(@[[_/7H\N/0[/;:V^O@V-[=W][F`OOP#A@:*!<.'QH8'PX('B8< M%!0A'@L$`OOR\^G7Z_CBVN;OX]KIYMCL_NWP`00.%A@?%Q$<(AP1$"(H#PD@ M'`D2%?_P]OGIZ?'BUMWCW=C7W.?HY/(!`@($#2(C$10A*BL:&2CGULC:ZMK<[?`!"OX+'QT5%B$?%QH?'Q@<*R`-"PD)!?;J MX^S]\-G@\O/EW^3?X>C%0'X^/[LT-[S MX,3/YM_:W]GA[_#S^/X'!084'AD4'B,B(AH;*"DC&@P/&Q'_^/GX[.GQZ=71 MX.73S=C&ATK)A(4'A(`_P#V\?CTZN+[V]?T&_``= M&0<6*!\1$!P9"`L6"P0*#0CZ]?\"^>SQ]N;:W>?IX=O_N^O3AW>KGX>S>SNKSV^/N\O[^!10.%"4A&Q\A M(AL6$@X:'PH`"`X,]NG\`_'M]>_@YO+GYO+DVNCJX>X$^O`-(140'"$E)!81 M&2`:"@L>%@0-"_G]!?GJ[?/EX>3=XNK@U=CEY>7T]?<3%049*"`J,"$6%R(? M#1,3"A,+_`0!]OCVZN;M[N;>X>;CW]K@ZN#E^_4#'@@$*"X>%ATK)`\1&A(0 M$`<*#@'U]/S^\.KU\>#F\.KEWM_JX-3I^_'Q_PH3%!(:(R<@%!,;'A<3$A(. M#Q#]^@7]^/;JZ_/IWN;IYN?=UN3LY^KU_04."PD:(AH?)!4/'2$5#!(9$PD' M!@'Y]O3LZ^WGY>+E[>7CZ>;I\/+Z__\.&0X*'"D:"Q47#A81"!$2$!,+__X( M`_+V]^KO[-OF]^[=W>KNZ>WW^P`0$0(+'1P=&PL%%A\(`1(/#1<,`@3_"`7L M]`3PWN3O\.KFVMKIZ^/H^04(#@T.'"`?)1,%&1D$`P\5"P<0!OH("?7S^O7S M[N3J\.WIX-WAX./I[OL`_Q`;%!HJ*1P4&AL,!P@)$`H`!@7X^/[Y\?/S[>KI M[OGOWN;PZN;G[_?\"0C[#R$!0?%/\'%@L""`/X^/;Y_/#N\N?L]_+Q M\.CK[N?J]/?Y`0<$!1,8&QX7%Q88'!$0'!<2$0D$_?;Y]NWM[.+A[?;RX=WL M[-_D\?+Z"`0"%!L5&"(?%Q45%A<6$1,9&10&^?O]]^WCX>CGWN?OYNOIXNGF MZOW^^P4.%!,3'2(A'1(.$`D)#PP2&PP""0,!!OKL[.WIZ.CGZNSCV^#KY^;X M^_L&!P4.'"0;$Q@<'10%#1T2"`T3#````@,!\_+PY.CLY][9YN?3VNKN_`/Z M`Q00$20H&QDA(1<-$1L6$@\$!`+V]?W]\>3H\O#M[.KNY]WAY.;J]`,'``87 M%A0A(!D>%P<.&A(+$1@5"`'_``7_\.SQ\>OK[^_N[>OGX.'CZOK[]OH`$!P1 M%28:&!X2%14-%A8/$`\$_@D%]?#P[.3EZ^?AZ>WBW>CJY_@!]?H-"@,5)1H5 M(B(5$A48&A@.`P<.`O/Y`?KPY^;N].S?XNWFW-[F[/7_`0,%!Q0<%!09&14+ M#!02$1$-#Q`*__G[_OGO[.SJ\O7HY._RY=K>ZO/V^/P!!@P7'A<:)!@'#A(( M#14-"`X3"OS^"@?Y[>KP\NGGZNGGYN/AX>?X^_'Z!`01&1DB(!L:%188$`L5 M%00%#/_[!03]]._U\NSMZ.3HZ>7;W.[S\0`!^0L1#1L@&1<4&1H.#1,4%@\" M`@@#^O?Y_?CM[O?SZ^[T[.+AX>/J\_CU^@8(#AD8%!0<&PP*%!<4%!`*#0\& M_?H``>[F\._I\>_E[>_@Y>OE\?_U\`,/!@L7%QP=%`\2$PX4&@X'#0\*__C^ M!??FZ.WKZNCGZ>OJX>;T\O$"!OL`$!,1%QT9#@\6$Q`/$A0)!Q`+__?_"/;J M\>_K[_/KX.SOX>3K\?3X!0/Z"A4/$A@9%0T-$A`0#A$9$0<+"P3_`?[V]N_H M\_'CZ?3JW.;IW_'_\_P*`P07(!<2&Q\4#0\2$Q40#0T*"0/[_0#W[NWKZO#L MZN_IY.3G[NSO_/[[`0H3%A4;'1<4$1,2#A06"P8+#`'^!/OO]_3G[//HZO'K MZN[FY>_T]O?Y`@4&$1(2&QH4%!03#@X7%0<%#PGY_/_Z^//N[>SN[NWKZ>7B MZ/#N\/O[^P,!!Q80$1@1$Q80$Q86%141#`L$_@,!^/#O[.?O]>SBXNKHX>3G M\/S\^/P($!,:%0X=(`X*%A40%Q,%"1$-_?@#_O3PZNSQ\/#MZ.OPZ.'L]/3Z M^_@!#Q`-$QD9&A4'"AT4!A$/!@\,_?X+!??V\N_V]N[GZ_+HX>KIZ>_M]/[] M_P4/%A0:'103&AD1#Q04#`0)!_T!!/CR]?'P\.WQ\>KIZ>CLZNGV_?;]!OX) M(14)&AX3%!,.%1D1!@8)!/\!^?/[]>;M]O#R].[O[^_R[>;S!/KN^`<-#@P) M#QH6#@P-$1D6!@02$`0$`?C^`>_E\/GT[.WP\/#IY._[]N[X`/L"#PH)&!D0 M#@\3&1<."@\0#PT`_@7]]_7JZ_7PY>GQ[^GEZ_+Q]OS[_04("Q05$A<6$1`2 M$`T0#04�G^_P(`_/3P\O3R\/'L[?3KY?#S\/G^^_X#"1$1#10:#`84$P@, M$`H)"08'!`(&__7X]^_T]>_P[NGKZ^CGZ_#W_OOZ!!$5$1(6$Q07#@P6$0H1 M#`,*"_[Y_O_SZO/W\.SM[>[NZN;GZO'Y^?3\"0T0$A45$!<<$`@.%1<*_042 M"O?X`_[T\^_L]??MZ>_V[>+M\^KQ`/KT``T."@X5$Q(5#@P4$PT)!PT,`P,` M_P'\]/#S]_/L[>_L[.GEZ?+Q\?\`\@(7#`H2$A(4%!$4%`\1$PH)"P4!`/[Z M]_?S[_/S\.OI\>WBZO#L]?WZ_0<+#0\1%!02$`X0$`T.$0H&#`D$`?W_^O3X M]/+Z]>GL]?7LX^OU\_3W^``*!P@4$@T3$1`2"0L5#`4*"@D(```$__OU\_GU M[_'R[NWNZ.OT[>W[^?;^!`H/"@D1%1(,#A,.#0L&"`8'!OS^`?KW^OGT\_+P M\.[N[^GL\O7X^?L!!@8'#PX+$!(/#!`2#0T-"`8%!/_\__WY]O3W^?;Q\/3R M[O#M[?;Y^OK]!PD)#@P+$1`-"PL0#`D,"0@)!04!_?_^^/7X^?/R]O3Q\O#O M\O3W]_?^`0('"0D.$0\+#0T-#0L+!PD*`P<'_0$%^_3Z_/#Q]>_N\>_N\/+U M^OGZ``,("0D0#0T3#@L.#PX+"`@'`P,#_O\!^_?X^??R\/3Q[?#P[?#U]?D` M_@`)"0D-"PL0"P8,#@D'"0D$`00#`?SZ_OOZ^O3V^/7U\O#Q[NSQ]_;T_`#^ M!0H'"@T,#0P*!P@/#P4!!@@&`OS]!/_U]?KZ]._U].[P\.[P]?;V^_[[`PX( M"!`/#A`/"@T2#`<)!P8%`0#^_P'Z]?K[]O+T]O'T]NSP^_?X__[]`@D*!PD. M#0P,!PL0#0@'!P8%`O\!`P#\^?O]^/;X]_/S]?+O\_;W^?K[``0&!P<)#`H+ M"@P-"@L*"0H'!00#``$"_/G\^/3T]/3S\N_M\_CR]/[]_@,#!0D-#@H+#0L+ M"@H+"`("!00#`?[^_OKX^??W]_/R]/+Q]/;V]_K\_@`!`PD+!P@,#`L*"0D* M!@(#!0$`!0#Z`0+Y^?KX^??T\?/T\O3U]?K\^?L``@,("04(#0H'"0H+"08$ M!`8%`?__`@#Y]_GZ^/7W]/+W]?+U]??^_?K^`@4&!@D+"0D+"@D,"`4)"`,# M!0'_`O_Y^_WW]?OW\_CW]/;Y^/G^_?P``0(%"0D("`D+"@<)"@8%!04%`P,# M__P`_OCY^_KX]O?U]_GW]OK]^_L``O\""`@&!@@,!@,+"04'!`,'!P(``@$! M_OCY_/GU]O;U]?7U]_;X_/S]_@$#!`8'"0@&"`D'"`@%`P8&`0$$`?W_`/OZ M^_CX^/7W]_7U]?CZ^OO]_P`!`@4'"`<'!P<("`4&!@($!`("__\`_/O\^_KX M^?KZ]_;W]OCY^/K[_@#^`0,$!P<'!P8("04$!P0"!@,!`O_]_?W\^OGZ^?KX M]_GY^/CX^/K]_OS]`@0$!08("0@&!@@(!00$!`0$`/X!__O^_?GY^OKY^?KW M^?SY^?O\_P'^_@0%`P4'!@8)!P4'!@4&!`,#!`']``'\_/SZ^_KX^_OW^?CY M^OK\_OW_`0`#!P,#"`<$!0<&!08%!`0#!`,`_____/W^^?C[_/KY^?GY^OOZ M^P#__@$!`P8%!`8&!04%!`0%!`$"!`(!`/_^_O[\^OKZ^OSY]_O\^?KZ^?X` M__[_!`4$!`,&"08$`P4&`P("`0(#_OT``?W\_/O\_/OZ^?O[^OKY^_[^____ M`0("!`0$!04%!`,$!`,!`0(!__[]`/[Z_/[]^_O\^_O\^_G[_/S]_O__``$! M!`0$!0,#!00#`P0#`0("``#^_@#^^OS]_/S\_/S[_/S[_?S\___^_P`!`P(# M`P,%!0("!00"`@(!`0'______?W]^_W_^_O]_/W^_/S]`0#]_P$"`@(#`P(# M`P(#`P,#`0`!`@'^_P#__O[]_?[]_/W]^_W^_/W^_O__`/\``P$``P,"`@,# M`@("`@$!`@'__@$`_O[^_?W^_OW\_?[\_/S]_O[___\``0$"`@(#`@("`@$! M`@'_`0'__P#__O[__OW^_O[]_?[^_?W^_O[_____``$!`@(!`@$!`@$!`0'_ M``$`__\``/____[^_O[^_O[^_O[]_O_^_____P$!`0$!`0$!`0$!`0`````` M`/\`_____O___O[^_O___O[^______\``````0$``0$```$``0$`````__\` M`/_______________________P#_````````````````````````````____ M_____________________P#___\````````````````````````````````` M``````!#3TU-````$@`!``!#%@`(0`VL1````````$U!4DL````"``!)3E-4 M````%#P``'\`?P``````````````````05!03````:A39#)A``(````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````N`````````````````````````````````````` M```````````````````````````````````````````$"```````"0`C```` M`````````````'@````$``0```````'\`/___X`````!`0$&455N:71S`/\` M`/___OX!`?[^`/____\``/__`/_^____`````0+_!B!S86UP````%8P*P`$D&VK3#\`J(`?!T)G2&T- MZB\.+P9.N@`\4@=P`0M-86=I8R!&;'5T90(```!!249&4V0R80`````````` M``!!249&4V0R80```````````````````````````````*<]K5D``$4B```! MSA`N`!9(@$'MJ;@2,```2('203HS$``0+@`62(!![:FX$C```$B!TD$\,Q`$ M/@5"!!U\``'_^;Q'7,`2!`H!``'``6=*ND=6P+Q'5L&"+@`4P`$"0``!9Q0_ M!Q\N__E![@`,(!AG`B\`(%!.D+Q';@1X`6#"0F````'@```!6`'&X MO!RF````'`!6``!7```````# M__\````\```````$__\```!:```````````````````````````````````` ;```````````````````````````````````` ` end nethack-3.4.3/sys/share/sounds/mgcharp.uu0100644000000000000000000006075707764735041017120 0ustar rootrootbegin 644 Magic_Harp M``I-86=I8R!(87)P```````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``&@``````````$0B```! MSJ<]K4JG/:U2``````````````````````````````"!@8QW``!&3U)-``!$ M&D%)1D934TY$``!"'@`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M___________________________________________________^_O[^_OW] M_?S\_/S\^_CW]_?X]_7T]/;Z_?[_``$"`@(!`/[[^?CX^P`"`@("`@("`@(" M`@,!^.*]H)V@GZ.GK+*VNKJWN+:MFX:`B(R.CXJ#BIFGL[BZOL/(SM/:WN'@ MU='9X>ST]?7V^?X%"0L-$!(2$A$0#PT*"`@)#1$1$1`0$!`0$!`0#P\/"?KC MTL_.SM#3UMK>X-_>W]W5P["IJJNLK*:CK+C#S-#2U=K>X^?K[O#LXN+K]/X# M`@(#!@P2%1<9&QT='1P;&1<5%!,5&1L;&QL;&QH:&AH:&AD8$P+LW]S:VMS? MX^;IZ^KIZNC>R[NWN+BXM[&QN\;1V-K=X>7I[?'U]_CRZN[W_P@+"@L,#Q4: M'!XA(R0D)",B(!X<&QL>(B(B(B(A(2$A(2`@("`@&@?RY^7CX^3GZ^[Q\O+Q M\O#DT,/!P,#`OKBZQ=#:X.+EZ.SP]/C[_?SU\??_"`\0$!`2%1H?(2,E)RDI M*"@F)"(A("`C)B8F)B8F)24E)24D)"0D'@SW[>KHZ.KL\//V]_;V]_;IU?J[?'T^/S_`/[W]?P$#1,3$Q,5&1XB)"8H*BPL*RLI)R4D M(R0G*2DI*2DH*"@H*"ON M\O7Y_/\!`P'Y^0$($1<6%A<8&R`D)B@J+"XO+RXM*RDG)BSO\O;Y_/\" M`P#Y^0$)$1<7%Q<8&R`D)B@J+"XP+R\M*RDH)R@K+2TM+"PL+"PK*RLK*BHI M*2`,_?CS\/#Q\_?Z_/W]_?[UX]?4T,[-R\7$S=;@Z.ON\O7X_/X``?_X^``) M$1<7%Q<8&A\C)B_P\O7Y^_S\_/WWYMG4T,W,RL7"R=/KL\//V^OS^`/[W]?X'#Q87%A87 M&1TB)"8H*BPN+R\M+"HH)RCJ[O'U^/K\_OWW\_D$#146%A86%QH?(R4G M*2LM+RXM+"HH)R[Q]/?X^?KY\N7WP\_;X^OKX\/'Z!`X5%!04%!89'B$C)2WN\/3V]_?X].G>V=/.RL?$OKW& MS]CBY^KN\?3V^/CW\.WT_@@2%!,3$Q06&Q\A(R4G*2LL+"HH)B4E)RHJ*BHI M*2DI*"@H*"SBW-;0R\?%P+N^R-#;X^;J M[?#S]?;U\>KM]P`+$A(2$A(3%AL>("(D)B@J*RHH)B4D)2@I*2DH*"@H)RWKZNSO\?/S]/#EW]O4SLK&P[RYP,G2W>/FZ>WP\O3T M\NSH\/D##A$1$1$1$Q8;'A\A(R4G*2HH)B4D(R4H*"@H)RV-#+QL*[M;G"R];>XN;I[._Q\?#JY>KT_0@.#P\. M#Q`3%QH<'B`B)"8G)R8D(R(C)BKH MZ>OM[N_P[.'=WMC0RL2_MK.[Q,W8WN'EZ.SN[_#NY^/K]?X)#0T-#0T/$Q<9 M&QT?(2,E)ROHZ.CJ[.WN M[^K?W=[8T,G"N;&TOL;0V=S@Y.CK[>_O[.3C[/7_"0P+"PL,#Q,6&!H<'A\A M(R4E)"(A(2,E)20D)"0C(R,C(B(B(B$A'Q<)`P/^].[IY^?HZNOL[N_IW]W? MVM#'OK*ON,'*T]?;X.3HZ^WO[NOCX^WV``D*"@H*#!`3%1<8&AP>("(D)",B M(2$B)"0D)",C(R,B(B(B(2$A'QH-`P,!^?+LZ.?GZ.GJ[>_PZ=_>X-K/Q;>N ML[S$SM/6V^#DZ.OM[^[JX^/N]P`("0@("@T1$Q06&!D;'1\A(R0C(2`A(R0D M(R,C(R(B(B(A(2$A'QP1!`(#_O7NZN?GZ.GIZ^[P\.C?W^#:SK^RL;G`RL_2 MUMO@Y.CL[N_NZ>+E\/@""`<'"`H.$1(4%1<9&QT?(2(C(B$@(2,D(R,C(R(B M(B(A(2$A(!T3!@$#`/GQ[.CGY^CHZNWP\O'GW]_?V,FXL[B^Q\W/TM?;X.7I M[.[O[>?BZ/+Z`P<&!@D,#Q`1$Q46&!H<'B`B(R(A("$C(R,C(B(B(B$A(2$@ M(!T5"`("`?SU[>GGY^?GZ>SO\O3PY=[>W-+`M[J^Q'=W-7'O;W`QSI MY^?FY^KM\?7V].C>V];+Q<3$R,S,S,[1U=K@Y>KN\/#OZ./J\_H!!`4)"@L- M#@\1$A06&!H<'A\@(2`@(2(B(B(B(2$A(2`@'QT5!P$"`@#[\^WJZ.?FY^KM M\?7X]_#BV]7+R7F[_?]`P8("@L,#0X0$1,4 M%A@:'!X?("$@("(B(B(B(2$A(2`@'QP2!@$"`@'\]._KZ.?FY^KM\?7X^?7G MV]/+S-+2TM+/SL[.T=;;X>;K[_'R\.GE[/3[`@8("0H+#`T.$!$3%1<8&AP> M'R`@("$B(B(B(2$A(2`@'QL/`P("`@']]>_KZ>?FY^KN\O;Y^O?KV]#*SM;8 MV-71S\[.T-39W^7J[O'S\NWFZ?+X``<("`D*"PP-#Q`2$Q47&1L='A\@("`B M(B(A(2$A("`@'A@,`@("`@']]O#KZ>?FY^KN\O;Y^OCNW,[,TMC=WMC3T<_. MT-/8W>/H[?'S\^_GY_#W_P8'!P@)"@L,#@\1$A06&!H;'1X?'R`B(B$A(2$A M("`?'14(`@,"`0']]O#LZ>?FZ.OO\_?Y^OGPW'R`A(B$A(2$@("`>&Q$% M`@,"`@+]]O#LZ>?GZ>SP]/CZ^_GPW,S1V=WDYN#:UM/1T=/7W.'G[?'T]?/K MZ._W_@8(!P@)"@H+#0X/$1(4%A@:&QP>'R`A(B(A(2$A("`>&`L#!`0"`@+\ M]O#LZ>?HZNWQ]?G[^_CNVL_5W.'FYN/>V-73T=/7W.'H[?'U]O3MZ?#X_P8( M!P@)"0H+#`X/$!(4%1<9&QP='B`A(B(A(2$A(!\<$@8#!`0#`P'\]/#LZ.?I MZ^_S]_K\^_;KV=/9W^7GY^7@VM?4TM37W.'H[?'U]O3MZO'Y``8'!P@("0H+ M#`T.$!$3%1<8&AL<'B`A(B$A(2$@'QT7"P0$!`,#`P'Z\^_KZ.CJ[?'U^/K[ M^?/FVMC=Y.?GZ.CCW=G6U-37W.+G[?+U]O3NZ_/Z``8'!P@("0H*"PT.#Q$2 M%!88&1L<'1\A(2$A(2$@'AL0!00%!`,#`__X\NWJZ.GL[_/W^OO[]^WEX-WA MZ.CHZ>GFX-O7U=;8W>/H[O/V]_7N[?7\`08'!P@("0D*"PT.#Q$2%!87&1H; M'1\A(2$A(2$?'!0(!`4%!`,#`OWV\>SIZ>ON\O;Y^_OY\NKHX^#GZNCHZ>KG MXMW9U]?:W^3I[_7W^/7O\/C]`@<("`@("0H+"PT.#Q$2%!87&1H;'1\B(B$A M(2`=%PL%!@8$!`0$`?KT[NOJZ^WQ]?G[^_KU[>WMYN;JZ>GIZNOIX]_;V-G< MX.7K\?7W^/7P\OK_!`@("`@("0H+#`T.#Q$2%!87&1H;'2`B(B$A(!X8#04& M!@4%!`4#_?;Q[.KK[?#T^/K\^_;O[O/OZ>GJZNKJZ^SJY>##=V]S?Y.KO]/?Y^?3R^?\# M!P@("`@)"0H+#`T.#Q$2%!87&!H;'B`A(2`>&@\&!P<&!04%!0/\]>_L[.WO M\_;Y^_OW\/'W^O?OZNOKZ^OL[>_LYN#=W=[AY^SQ]?CZ^//U_0`%"`@("`@) M"0H+#`T.#Q$2%!87&1H<'R$A(!X:#P<'"`8&!04&!/[W\>[L[>_R]OGZ^O?P M\OG\_/;LZ^SL[.SM[_#LYN'?W^'EZN[S]_K[]?+Y``0("`@("`D)"@H+#`T/ M$!$3%188&1L='R(A'AD.!P@(!P8&!@8%`/CS[^WN\//V^?KZ]_'S^_[__/#K M[>WL[>WN\/'LYN+@X>/G[?+V^OSY\_?^`@<)"`@("0D)"@L,#0X/$1(4%1<8 M&AP>("`>&`T'"0D'!P8&!P8"^O3P[N[P\_;X^OKV\?3\_P(`]>SL[>WM[>[P M\O#JY>+BX^;K\/7Y_/OU]?P"!@D)"`@)"0D*"@L,#0X0$1,4%A@9&AT?(!X8 M#0<)"0@'!P8'!P3\]?'O[O#R]?CZ^?;R]?T!`P+Y[NSN[>WM[N_Q\N[HY.+C MY>GN\_?[^_?T^@$%"0H)"`@)"0D*"PP-#@\0$A,5%A@9&QX?'A@."`D)"`<' M!P<'!?_W\_#O\/+U^/GY]O+T_0$#`_SQ[.[N[N[N[_'S\>SGY./EZ.SQ]OK[ M^/3Y``0("@D("`@)"0H*"PP-#A`1$Q06%Q@:'1X=&A`("0H)"`<'!P<'`OKU M\>_P\?3W^?GW\O3]`0,$_O+L[N[N[N[O\/+S[^GEY.3GZ_#T^/KY]/@`!`@* M"0D)"0D)"@H+#`T.#Q$2%!47&!H<'1T:$0D)"@D("`<'!P@%_O?S\?#Q\_;X M^??S\_L!!`7_].WN[^[N[N_P\O3QZ^?EY.;J[O/W^?GU]P`%"`L*"0D)"0D* M"@L,#0X/$!(3%1<8&AP>'1P4"PD+"@D(!P<("`<#^_;R\?'S]??X^/3R^0$$ M!0'W[N[O[^[N[_#Q\_/NZ.;EYNCL\?3W^/7V_P4("PL*"0D)"0H*"PP-#@\0 M$1,4%A<9&QT='!@."0L+"@D("`@("`8`^?7R\?+T]OCX]?+W``,$`_GO[N_O M[N[N[_'R]/#JY^7EY^KN\O7V]/;^!0@,"PH*"0D)"0H*"PP-#@\1$A05%A@: M'!T=&A()"@L*"0@("`@("`3^^/3R\O/U]O?V\O/\`@,#_/'M[^_N[N[O\/'S M\NWHY>3FZ.SP\_7T]/L#!PL,"PH)"0D)"@H+#`P.#Q`1$Q06%QD;'1T;%@P) M"PL*"0@("`@("`/[]_3R\O3V]_?T\O@!`P0`]>[O[^[N[N[O\/+S\>OGY>7G MZNWQ\_/R^`('"@T,"@H*"0D*"@L+#`T.#Q$2%!46&!H<'1P:$@H*#`L*"0@( M"`@(!P'[]_/R\_3U]O7R\_P#`P/Z\._P[^[N[N_P\?/S[^GFY>7HZ^[Q\O'S M_@8)#0T,"PH*"@H*"@L,#0X/$!(3%!87&1L='1P8#@H,#`H*"0@("0D)!P'[ M]_3S\_3U]O3Q]@`#`__T[_#P[N[N[N_P\?/R[>GFY>;H[._Q\/#W`P@,#@T, M"PH*"@H*"PL,#0X/$1(3%188&AP='!L5#`H,#`L*"0D)"0D)!P'[]_3S\_3U M]?+Q^0$#`OOQ\/'O[N[M[N_P\?+Q[.?EY>;HZ^[O[O#\!@H.#@T,"PH*"@H+ M"PP,#0X0$1(4%1<9&QT='!H2"@L-#`L*"0D)"0D)!P+[]_3S\_3T\_#R_`(" M`/?O\?'O[NWM[N_P\?+PZ^?EY>;HZ^WM[?,`"`P.#@T,"PH*"@H+"PP-#@\0 M$1,4%A<9&QT=&Q@0"@P-#`L*"0D)"0D)!P+[]_3S\_3T\N_T_@("_O/O\?#O M[NWM[N_P\/+P[.?EY>;HZNSK[/8""0T/#@T,"PH*"@H+"PP-#@\0$1,4%A@9 M&QT<&A<."@T-#`L*"0D)"0D)"`/\^/7T\_/S\>_U_P(!_/+P\O#O[NWM[N_P M\/+Q[.CFY>;HZNOJ[/D$"@\/#@T,"PL+"PL+#`P-#@\0$1,5%A@:'!T<&A4- M"PX-#`L*"0D)"0D)"03^^?;T]//S\>_W``$!^O'Q\O#O[NWM[N_O\/+Q[.CF MY>7GZ>GH[?H%"@\0#PX-#`L+"PL+#`P-#@\0$A,5%A@:'!T<&A4-"PX.#`L* M"@D)"@D)"08`^O?U]//R\._W_P$`^?'Q\O#O[NWM[N[O\/'R[NGFY>7FZ.CG M[/D$"Q`0#PX-#`L+"PL+#`P-#@\0$A,4%A@:&QT;&14."PX.#`L*"@H*"@H) M"0<"_/CU]//R[^[V_P$`^/#Q\O#O[>WM[>[O[_#R[^KGY>7FY^?FZ_D#"@\0 M#PX-#`L+"PL+"PP-#@\0$1(4%A<9&QT;&14-"PX.#0P*"@H*"@H)"0D%_OKW M]?/R[^WT_0#_^/'R\_'O[>WM[>[N[_#R\.OHYN7EYN;EZO@""0\0#P\-#0P+ M"PL+"PP-#0X0$1(4%1<9&AP<&A8/"PX.#0P+"@H*"@H)"0H(`OSX]O3R[^WR M_/__^/'R\_'O[NWM[>WN[_#Q\>WHYN7EY>7CZ/8!!PT0$`\.#0P+"PL+"PP, M#0X/$!(3%188&AP<&A<0"PT/#@P+"@H*"@H*"0H*!?_[]_7S\.WP^?[^^?+R M]/+P[NWM[>WN[^_P\O#KZ.;EY>3BYO/^!@P0$`\/#@T,"PL+#`P,#0X/$!$3 M%!87&1L<&A@2#`P/#@T,"PH*"@H*"@H*"`/^^O;T\>[N]OS]^?/R]//Q[^[M M[>WN[N_P\?'MZ>?EY./BY._\`PH.$!`/#@T,"PL+"PP,#0T.#Q$2$Q47&!H< M&A@4#0L.#@T,"PH*"@H*"@H*"@WM[N[O M\/+PZ^CFY./AX>KX``<,#@\/#@T,#`L+"PL,#`T.#Q`1$A05%QD;&A@6$`L- M#@T,"PH*"0H*"0D)"@H&`/SX]/'M[O;[^O7Q\_3R\>_M[>WM[>[N[_'R[NKG MY>/AX.7S_0,)#`X/#PX-#`L+"PL+#`P-#@\0$1,4%A@:&QD7$PP+#@X-#`L* M"@H*"@D)"@L*!?_[]_/O[?#X^O;Q\O3S\O#N[>WM[>[N[_#R\>WIYN3BW^'L M^``&"PT/#PX-#0P+"PL+#`P-#0X/$!(3%188&AH8%@\*#`\.#0P+"@H*"@H* M"@H+"@7_^O;R[NWS^?CS\?3U\_'P[NWM[>[N[N_Q\_'LZ.;CX-_E\OP""`L- M#P\.#0P,"PL+"PP,#0T.$!$2%!47&1H9%Q0-"@X/#@T+"@H*"@H*"@H*"PH% M__KV\>WN]?GU\?+U]/+Q[^[N[N[N[N_P\O/P[.CEXM[@Z_;]!`D+#0\/#@T, M"PL+"PL,#`T.#Q`1$A05%QD:&!81"PL/#PT,"PH*"@H*"0D*"@P*!?_Z]?#M M[_;W\O#S]?3R\>_N[N[M[N[O\/+S\.OGY.#=XN_Y_P4("PT/#PX-#`L+"PL+ M#`P-#@\0$1(4%1<9&!84#@D,#PX-#`L*"@H)"0D)"@H,"@3^^?3O[?+W]?#Q M]/3S\O#O[N[N[N[N[_#R\_#KY^/?WN;R^@`&"`L-#PX-#0P+"PL+"PL,#0T. M$!$2%!47&!84$0H(#0\.#0L*"@H*"@D)"0H+#`H$_OCR[N_U^/3P\O7T\_+P M[N[N[>[N[N_Q\_3Q[.?CW]_I]/L!!@D+#0\.#0P,"PL+"PL+#`P-#@\0$A,5 M%Q84$@P'"0X.#0P+"@H*"@D)"0H*"PP(`OSV\._T^?GT\/+U]//R\._N[N[N M[N_P\?/U\NWHY.#AZ_;\`@<)#`X/#@T-#`L+"PL+"PP,#0X/$!(3%184$@X' M!@L.#@T,"PH*"@H*"@H*"PT,!P#Z\^_S^OOZ]/#S]?3S\?#O[N[N[N[O\/'T M]O3NZ>7@XN[W_0,'"@P/#PX.#0P+"PL+"PL,#`T.#Q`1$Q04$0X(`P<+#`T, M"PH*"@H*"@H*"PP-"P3^]_'R^OW]_/3P]/7T\_'O[N[N[N[N[_#R]/;U\.OE MX>3O^/X$"`H-#P\.#@T,"PL*"@L+"PP-#0X0$1,2$`X(`@0)"@L,"PL*"@H* M"@H*"@L,#0D!^O/P^/____ST\?3U]/+P[^[N[>[N[N_P\O3W]O'LYN+G\OK_ M!0@+#@\/#@T,#`L*"@H*"@L+#`T.#Q$1#@P(`0$&"`D*"PL*"@H*"@H*"@L, M#0L$_?;Q]_\"`0#Z\O+U]?3R\._N[N[N[N_P\?/U]_CS[>?DZO7\`08)#`X/ M#PX-#0P+"@H*"@H+"PP-#A`0#@L'`/\#!@<("0H+"@H*"@H*"@L,#@T'`/CS M]OX#!`+_^/'S]?7S\?#N[N[N[N_O\/+T]OCX\^WGYN_X_@,'"PT.#PX.#0P, M"PH*"@H*"PL,#0X/#0H'`/T"!08'!PD*"PL+"@H*"@L,#0X+`_KT]_X#!@4! M_?;Q]/;T\_'O[N[N[N_O\/'S]??Z^?3MY^KT^P`%"0P.#@\.#@T,"PL*"@H* M"@L+#`T-"PD%_OL``P0%!@<("@L+"PH*"@L,#0X+!/OU^/\#!@<#`/KS\O7U M\_'P[N[N[N[O\/#R]/;Y^_GS[.GO^?X#"`L-#@X.#@T-#`L*"@H*"@H*"PP- M"@<#_/K_`@(#!`4'"0H+"PL*"PL,#0X,!?SV^0`#!@@%`O[V\?3U]/+P[^[N M[N[O[_#Q\_7X^OSY\NSM]OT"!@D,#0T.#@X-#`L*"@D)"0H*"@L+"`4!^OG^ M``$!`@,%!PD+"PL*"PL,#0X,!OWX_`($!PD'`P#Z\_+U]//Q[^[N[N[O[_#Q M\_7W^?S\]_#M]/P`!0@+#0T-#@X-#0P+"@H)"0D*"@L*!@/^^/G]_P```0($ M!@@*"PL+"PP,#0X,!OWY_P0%!P@(!0+]]?'T]?/R\.[N[N[O\/#Q\O3W^?O] M_/7O\_L`!`@*"PP-#0X-#0P+"PH)"0D)"@H(!`'[]OG]_O__``$#!0<)"PL+ M"PP-#0X-!?W\`04&"`@)!P/_]_+S]?3R\._N[N[O\/#Q\_3V^?O]_OKS\_L` M`P@*"PP,#0T-#0P+"PH)"0D)"0D&`__X]?G\_?[^_P`"!`8("@L+"PP-#0T, M!?[_!`8'"`@)!P,`^O+R]?3R\>_N[N_O\/'R\_3V^?O]__WV]/L!!`<*"@L, M#`T-#0P+"PH)"0D)"0@$`?SU]OK\_/S]_O\!`P4'"0H+"PP-#0T+`_\"!P<( M"`@)"`0!^_/R]?3R\?#O[N_O\/'R\_3V^/O]___Y]OL"!`<)"0H+#`P,#`P+ M"PH)"0@("`4!_OCS]OO[^_O\_?X``@0&"`H+"PP,#0T)`P$&"`<(!P<)"`0! M^_3R]/3S\?#O[^_O\/'R\_3V^/O]_P#\^/T#!0@)"0D*"PP,#`P+"PH)"0@( M!P/_^_3T^/KZ^OO[_/[_`0,%!PD+"PP-#`P(`P4)"`@(!P@)"`0!^_3R]/3S M\?#O[^_P\/'R\_7W^?O]_P'^^OX$!@@)"0D*"@L+#`L+"@H)"`@(!`#]]O+U M^?GZ^OK[_/W_`0,%!PD+#`P,#`H&!0D*"0@'!P@)"`0!^_3R]?3S\O#P\/#P M\?+S]/7W^?S^``'__0$&"`D*"0D)"@L+"PL+"@H)"`@&`?[Y\_/W^?GY^?GZ M^_W_`0,$!@D+#`P,#`D&"0L*"0@'!P@)"`0!^_3R]?3S\O'P\/#Q\?+S]/;X M^OS^``$`_P,("0H)"`@)"0H+"PL+"@H("`<#_OOT\O;X^/CX^/GZ^_W_``($ M!@@+#`P+"@D*#`L)"`<'!P@)"`,`^O/R]?3S\O'P\/'Q\O/T]??Y^_W_`0$" M`@8*"@H)"`@("0H*"PL*"@D)"`3_^_7Q]/?X]_?W^/CZ^_W_``($!@@+#`L* M"0L.#0L)"`<'!P@)!P+_^/+S]?3S\O'P\?'R\_3U]O?Y^_X``0("!`D,#`L) M"`@("0D*"@H*"0D(!0#\]_'S]_?W]_;W]_CZ^_W^``($!@@*"PH*#`\.#`H( M!P<'"`D)!@'^]_+T]?3S\O'Q\?+S]/3V]_CZ_/\!`@($"`T.#`H(!P<("`D) M"@H*"0D&`?WX\O/V]_?V]O;V]_GZ_/W^``($!@@*"@D,$!`-"P@'!P<'"`D( M!`#[]/+U]?3S\O+R\O+S]/7V^/G[_@`!`@,&#`\.#`H(!P<'"`D)"0D)"08! M_?CR\O;W]_;V]?;W^/G[_/W_``,%!PD)"0T2$0X,"0<'!P<("`D&`O[X\_/U M]?3S\O+R\_/T]?;W^?O]_P$"`P0*$!$.#`D'!P<'"`@)"0D)!@']^//S]O?V M]O7U]?;W^/K[_/W_`0,%!P@)#1,3#PP)"`<&!P<("`@$`/OU\O3U]?3S\O+S M\_3U]O?X^OS^``(#`P8.$Q$."PD'!P<'"`@("0D&`?WX\_/V]_;V]?7U]?;W M^?K[_/[_`0,%!@@.%!,0#0H'!@8&!P<("`4!_OCS\_;U]?3S\_/S]/7V]_CZ M^_W_`0,#!`L3$P\-"@@&!@8'!P@("`4`_?CS]/?W]O;U]/3U]O?X^?K[_?X` M`@,$!@X5%!`-"@@&!@8&!P<(!P+^^_7S]?;U]?3S\_3T]?;W^/G[_?\``@,$ M"!$5$@X+"0<&!@8&!P<(!0#]^/3U^/?W]O7U]?7V]_CY^?K\_?\!`@,%#!45 M$0X*"`8&!@8&!P<'!/_\]O/U]O;U]?3T]/3U]O?X^?O\_@`!`P,%#144$`T) M!P8&!@8&!P<%`/WX]/7X^/?V]?7U]?;W^/CY^OO]_@`!`@0+%!82#PL(!P8% M!@8'!P<%`?WX]/3W]_;U]/3T]/7V]_CY^OS]_P$"`P0+%!42#PL(!P8%!@8& M!P4!_OGU]?CX^/?V]?7U]?;W^/GZ^_S^_P$"`PD2%A00#`D'!@4%!@8&!P4! M_OKT]/?W]O;U]/3U]?;W^/GZ^_W^``$"`P@2%A,0#`D'!@4%!08&!0'^^_;U M^/GX]_;U]?7V]O?X^?GZ_/W_``$"!P\6%1$-"0<&!04%!08&!0'^^O7T]_?W M]O7U]/7U]O?X^/GZ_/[_``$"!P\5%!$-"0<&!04%!08%`O[[]_7X^?CW]_;U M]?7V]_CX^?K[_/[_``$%#!06$P\+"`8%!04%!08%`?[[]O7W^/?V]?7U]?7V M]_CX^?K[_?X``0(%#105$@X*"`8%!04%!08#__WY]??Y^?CW]O;V]O;W^/GY M^OO\_?\``0,)$145$0T)!P8%!`0%!04"__SW]??X^/?V]?7U]?;W]_CY^?O\ M_?\``0,*$A43#PL)!P4$!`4%!00`_?KW]_GZ^?CW]O;V]O?X^?GY^OO]_O\` M`@8.$Q43#PL(!@4$!`0%!0/__?GU]_GX^/?V]?7U]O?W^/CY^OO]_O\``@@/ M%!01#0H(!@4$!`4%!0+^_/CV^?KZ^?CW]_;V]_CY^?GZ^_S]_P`!!`H1%101 M#0H(!@4$!`0%!`#^^O?W^?GX]_;V]?7V]O?X^/GY^OS]_O\`!`L1%!,/#`D' M!00$!`4%!`#]^O?W^OKZ^?CW]_;W]_CY^?K[^_W^_P`!!0T2%!00#`D'!00$ M!`0$`?[\^/;X^?GX]_;V]?;V]_?X^/GZ^_S]_O\""`X2%!(."@@&!00$!`0% M`O[\^?;X^_KY^/CW]_?W^/GY^OK[_/W^_P`""`X2%!,/"PD&!00$!`0"__WZ M]_?Z^OGX]_;V]O;V]_?X^/GZ^_S]_O\$"Q`2$Q`,"0<%!`0$!`0#`/W[^/?Z M^_KY^?CW]_?X^/GY^OK[_/W^_P`#"A`2%!(/"P@&!00$!`,`_OSX]_GZ^OGX M]_;V]O;W]_CX^/GZ^_S]_@`&#`\1$@\+"08%!`,$!`0#__WZ]_C[^_KY^?CW M]_?X^?GZ^OO[_/W^_P$$"Q`2$Q(."P@&!00#`P+__?OW^/KZ^OGX]_;V]O?W M^/CX^?GZ^_S]_@()#0\1$0X+"`8%!`,#!`0!_OSY]_G[^_OZ^?CX^/CX^?KZ M^OO\_?[_``$`2$Q(."@@&!00#`P'^_/GW^?O[^OGX]_?V]O?X^/CX^?GZ M^_S]_P,*#0\1$0X*"`8$!`,#!`0!_OSY^/K\^_OZ^?CX^/CY^?KZ^OO\_?[^ M_P$'#1`1$A$."@@&!`,#`P#]^_CW^?O[^OGX]_?W]_?X^/CX^?GZ^_S]_P0* M#0\0$`X+"`8$`P,#`P,`_?SY^/K\^_OZ^?CX^/CY^?KZ^OO\_/W^_P((#0\1 M$A$."P@&!`,#`O_]^_CW^OO[^OGX]_?W]_?X^/CX^?GZ^_S]_P4+#0X0$`X* M"`8$`P,#`P+__?OY^/K\^_OZ^?CX^/CY^?KZ^OO[_/W^_P('#0\0$1$/"P@& M!00#`O[\^_CX^OO[^OGX]_?W]_CX^/CX^?GZ^_S]``4*#`X/#PX+"`8$`P,# M`P+__?OY^/O\^_OZ^?CX^/CY^?KZ^OO[_/W^_P$&#`X0$1$/#`D'!00#`O[\ M^OCX^_S[^OGX^/?W]_CX^/CX^?GZ^_S]``4*#`T.#PX,"08%!`,#`P+__?OY M^/O\_/OZ^?GX^/CY^OKZ^OO[_/W^_P$&"PX/$!$0#0H(!@0#`O[\^OCX^_S[ M^_KY^/?W]_CX^/CX^?GZ^_O\_P0)#`T.#PX,"0<%!`,#`P,`_?SZ^/K\_/OZ M^OGY^/CY^OKZ^OO[_/W^_@`%"@T/$!`0#@L(!@0#`O[\^OCX^_S\^_KY^/CW M]_CX^/CX^?GZ^OO\_P0)"PP-#@X,"@@&!`,#`P,`_?SZ^/K\_/S[^OGY^/CY M^OKZ^OK[_/S]_@`$"0P.#Q`0#PT*!P4$`O[\^OCX^OS\^_KY^/CW]_CX^/CX M^/GY^OO[_@,("@L,#0X-"P@&!`,#`@(!_OS[^?G[_/S[^OGY^/CY^?KZ^OK[ M^_S]_O\"!PL-#@\0$`X+"`8$`__\^_CW^OS\^_KZ^?CX^/CX^/CX^/GY^OK[ M_0('"0L+#`X.#`D'!00#`P,"__S[^?G[_/S[^_KY^?GY^?KZ^OK[^_S\_?X` M!0H,#@\/#P\-"@<%!`#]^_GW^?S\^_OZ^?CX^/CX^/CX^/CY^?K[_``%"`H+ M#`P-#`H(!@0#`P("`/W\^OGZ_/S\^_KZ^?GY^?KZ^OKZ^_S\_?[_`@@+#0X/ M#P\.#`D'!0+^_/KW^/O\_/OZ^OGX^/CX^/CX^/CY^?KZ^_X#!PD*"PP-#0L) M!P4$`P("`?[\^_GY^_W\_/OZ^?GY^?KZ^OKZ^_O\_?W^``4*#`T.#P\/#@L( M!@3__/OX^/K\_/O[^OGY^/CX^/CX^/CX^?GZ^_P!!@@)"@L,#0P*"`8%!`," M`@#]_/KY^OS]_/O[^OGY^?GZ^OKZ^OO[_/W^_P('"PP-#@\/#PT*"`8!_?OY M]_G[_/S[^OKY^?CX^?CX^/CX^?GY^OO^`P<("0H+"PP+"0@&!`,#`@'__/OZ M^?O\_/S[^OKY^?GY^OKZ^OK[^_S]_O\#"`L,#0X/#PX-"@@$`/W[^/CZ_/S[ M^_KZ^?GX^?GX^/CX^/GY^?K\`04'"`D*"PL,"PD'!00#`@(!_OS[^?K\_?W\ M^_KZ^?GY^OKZ^OK[^_S\_?X`!0D+#`T.#@X.#0H'`__\^OCY^_S\^_OZ^OGY M^?GY^/CX^/GY^?K[_0(&!P@)"@H+#`H(!P4$`P("`/W\^OGZ_?W]_/OZ^OGY M^OKZ^OKZ^_O\_?W_`@8*"PP-#@X.#@P*!@+^_/GX^OS\_/O[^OKY^?GY^?GX M^/CY^?GZ^_\#!@<("0H*"PL*"`<%!`,"`?[\^_KY^_W]_/S[^OKY^?KZ^OKZ M^OO[_/W^_P,("@L,#0X.#@X,"04!_?OX^/K\_/S[^_KZ^?GY^?GY^/CY^?GY M^OP`!`8'"`D*"@L+"@D'!00#`@#]_/OY^OS]_?S[^_KZ^?KZ^OKZ^OK[^_S] M_@$%"0H+#`P-#@X-"P@$`/W[^/G[_/S\^_OZ^OGY^?GY^?GY^?GY^OO]`04& M!P@)"0H+"PH)!P4$`P'^_/OY^?O]_?W\^_KZ^OGZ^OKZ^OKZ^_O\_?\#!PD* M"@L,#0T-#`H'`__\^OCY^_S\_/O[^OKY^?GY^?GY^?GY^?K[_0(%!@<("0H* M"PP+"0<%!`+__/OZ^?K]_?W\_/OZ^OKZ^OKZ^OKZ^OO[_/X`!0@)"0H+#`P- M#0L)!@+^_/KX^?O\_/S[^OKZ^?GZ^OGY^?GY^?KZ^_X"!0<("`D*"@L,#`H' M!00!_?SZ^?K\_?W]_/O[^OKZ^OKZ^OKZ^OK[^_S_`P8("`D*"PL,#0P*"`4! M_OSZ^/K\_/S\^_OZ^OKZ^OKY^?GY^?KZ^_S_`P8'"`@)"@L+#`P*!P8#__S[ M^?G[_?W]_/S[^_KZ^OKZ^OKZ^OKZ^_S^`@4'"`@)"@H+#`P+"`8$`/W[^?CZ M_?W]_/O[^OKZ^OKZ^OGY^?KZ^_O]``0&!P@)"0H+"PP,"0<$`/W[^?G[_?W] M_/S[^_KZ^OKZ^OKZ^?KZ^_O]``0&!P<("0D*"PL+"0<%`__\^_GY^_W]_?S[ M^_KZ^OKZ^OKY^?KZ^OO\_0$%!P<("0D*"PP,"PD&`O[\^OGZ_/W]_/S[^_OZ M^_OZ^OKZ^?KZ^OO]``0%!@<'"`@)"@H+"@@&!`']_/KY^OS]_?S\^_OZ^OKZ M^OKZ^?KZ^OO[_/\#!@<("`D*"@L,#`L(`__]^_K[_/W\_/S[^_O[^_OZ^OKZ M^OGZ^OO\_P,%!08&!P@("0H*"0@&!`+__/OZ^?O]_?W\_/OZ^OKZ^OKZ^OKZ M^OO[_/X!!0<'"`D)"@L,#`L*!0'^^_K[_/S\_/S[^_O[^_O[^OKZ^OGZ^OO\ M_P,$!04&!@<'"`D)"0@&!0,`_?S[^?K\_?W]_/O[^OKZ^OOZ^OKZ^OO[_/W_ M`P8'"`@)"@H+"PL*!@+__/O\_?W\_/S[^_O[^_O[^_KZ^OKZ^OO\``,$!`4% M!@8'"`@)"0<&!0,!_OS[^OK[_?W]_/S[^_KZ^_OZ^OK[^_O[_/W^`@4'"`@) M"0H+"PL*!@,`_?S]_?W\_/S[^_O[^_O[^_KZ^OKZ^OO]``,#!`0%!08&!P<( M"`<%!`,"`/W\^_K[_?W]_?S[^_OZ^_O[^_O[^_O[_/S^`00&!P@)"0H*"PL) M!@0!_OW^_OW\_/O[^_O[_/S[^_KZ^OKZ^OO]`0,#!`0$!04&!@<'!P8%!`," M`/W\^_KZ_/W]_?S\^_O[^_O[^_O[^_O[_/S]_P,&!P@("0D*"@H(!00"__[_ M_OW\_/O[^_O[_/S[^_OZ^OKZ^OS^`0(#`P0$!`4%!@8'!P8$`P,"`?[\^_KZ M_/W]_?S\^_O[^_O[^_O[^_O\_/W]_P(%!P<("0D*"@D&!00"````__[]_/O[ M^_O\_/S[^_OZ^OKZ^_S_`@(#`P,$!`0%!08&!@4$`P("`?[\_/KZ_/W]_?W\ M_/O[^_O[^_O[^_S\_/W]_P(%!P<("`D*"@@%!`,"`0$!__[]_/O[^_S\_/S\ M^_O[^_K[^_T``@("`P,#!`0%!04&!@0#`@("`?_]_/OZ_/[^_?W\_/O[^_O[ M^_S[_/S\_/W^_P(%!@<("`D)"0<%!`,"`P(!__[]_/S[^_S\_/S\^_O[^_O[ M_/\!`@("`@,#`P0$!04%!00#`@(!`?_]_/O[_/[^_?W\_/O[^_O\_/S\_/S\ M_?W^_P(%!@<("`D)!P4$`P(#!`,!`/[\_/S[_/S\_/S\^_O[^_O\_@`!`@(" M`@,#`P,$!`4%!`,"`0$!`?_]_/O[_/[^_?W\_/S[^_O\_/S\_/S\_?W^_P(% M!P<'"`@(!@0#`@($!0,!`/[]_/S[_/S\_/S\^_O[^_S]_P$!`0("`@(#`P,$ M!`0$`P(!`0$!`/[]_/O[_/[^_?W\_/S[^_S\_/S\_/S]_?W^``(%!@<'"`@& M!`0#`@,%!0,"`/[]_/S\_/S\_/S\^_O[_/W_``$!`0("`@("`P,#!`0#`@$! M`````/[]_/O[_?[^_?W\_/O[^_S\_/S\_/W]_?[^``,%!@<'"`8%!`,"`P0% M!0,!`/[]_/S\_/S\_/S\_/S\_/X``0$!`0$"`@("`P,#`P,"`0$``````/[] M_/O[_?[^_?W]_/S\_/S]_?W]_?W]_O[_`00&!P<'!P4$`P("!`4%!`,!`/[] M_?W\_/S\_/S\_/S]_@`!`0$!`0$!`@("`@,#`P,!`0``````__[]_/O\_?[^ M_?W\_/S\_/W]_?W]_?W]_O[_`00&!@<&!`,#`@($!04$!`,!__[]_?W\_/S\ M_/S\_/W^``$!`0$!`0$!`@("`@,#`P$!`/___P``__W]_/S\_O[^_?W\_/S\ M_/W]_?W]_?W^_O\``@4&!@8$`P,"`@,$!`0$`P(`__[^_?W\_/S\_/S\_?X` M`0$!`0$!`0$!`0("`@("`0``_____P#__OW]_/S]_O[^_?S\_/S\_?W]_?W] M_?[^__\!`P4&!00#`P("`P0$!`0#`P(`__[^_?W\_/S\_/S]_@`!`0$!`0$! M`0$!`0("`@(!``#______P#__OW\_/W^_O[]_?W\_/W]_?W]_?W^_O[^_P`" M!`4%!`,"`@(#!`0$!`,#`@$`__[^_?S\_/S\_/W^``$!`0$!`0$!`0$!`0$" M`@$``/_________^_?W\_/W^_O[]_?W]_?W]_?[^_O[^_O[_``$#!04#`P(" M`@,$!`0$`P,#`@$`__[]_?S\_/S]_?\``0$!`0```0$!`0$!`0$"`0``____ M______[]_?S\_?[^_OW]_?W]_?W^_O[^_O[^_O__`0,$!`,"`@("`P0$!`,# M`P,"`@$`__[]_?S\_/W]_P`!`0$!`````0$!`0$!`0$!``#___[^______W] M_?S]_O[^_OW]_?W]_?[^_O[^_O[^__\``@0$`P("`@(#!`0$`P,#`@("`0#_ M_OW]_/S\_?W_``$!`0$```````$!`0$!`0$!`/___O[^_____OW]_/S^_O[^ M_?W]_?W]_O[^_O[^_O[__P`!`P,"`@(!`@,$!`,#`P,"`@("`0#__OW]_/W] M_?X``0$!`0````````$!`0$!`0$`___^_O[____^_?W]_?W^_O[^_?W]_?W^ M_O[^_O[^_O__``$#`P("`@$!`P0$`P,#`P("`@(!`/_^_?W]_?W]_@`!`0$! M``````````$!`0$!`0``___^_O____[]_?W]_?[^_O[^_?W]_?[^_O[^_O[^ M_O__`0(#`@("`0$"`P,#`P,#`@("`@(`__[^_?W]_?W^_P`!`0$````````` M``$!`0$!`0#____^_____OW]_?W]_O_^_O[^_?W]_O[^_O[^_O[^__\``@," M`0$!`0(#`P,#`P,"`@("`@$`__[]_?W]_?[_``$!`0````````````$!`0$! M``#________^_?W]_?W^__[^_O[^_?W^_O[^_O[^_O[__P`!`P,"`0$!`0(# M`P,#`P("`@("`0#__O[]_?W]_O\````````````````````!`0$!``#_____ M__[]_?W]_?[__O[^_O[^_O[^_O[^_O[^_O[__P$"`P(!`0$!`@,#`P,"`@(" M`@("`0#__O[]_?W]_O\````````````````````!`0$!`/_______OW]_?W] M_O___O[^_O[^_O[^_O[^_O[^_O__``$"`@$!`0$!`@,#`P,"`@("`@(!``#_ M_O[]_?W^_P`````````````````````!`0$!`/_______OW]_?W]_O___O[^ M_O[^_O[^_O[^_O[^_O\``0("`0$!`0$!`@,#`P("`@("`@(!`/___O[]_?[^ M_P`````````````````````!`0$``/_____^_?W]_?W^_____O[^_O[^_O[^ M_O[^_O[^__\``0("`0$!`0$"`@,#`@("`@("`@(!`/_^_O[^_O[__P`````` M```````````````!`0$``/_____^_?W]_?[^___^_O[^_O[^_O[^_O[^_O[^ M__\``@(!`0````$"`@("`@("`@("`@$!`/_^_O[^_O[_```````````````` M`````````0$``/____[]_?W]_?[____^_O[^_O[^_O[^_O[^_O[__P`!`@(! M``````$"`@("`@("`0$!`@$!`/_^_O[^_O[_```````````````````````` M`0$``/____[]_?W]_?[____^_O[^_O[^_O[^_O[^_O[__P`!`@$!``````$" M`@("`@("`0$!`0$``/___O[^_O[_``````````````````````````$```#_ M__[]_?W]_O_____^_O[^_O[^_O[^_O[^_O[__P`!`0$```````$"`@("`@(! M`0$!`0$``/___O[^_O__``````````````````````````$```#___[]_?W] M_O_____^_O[^_O[^_O[^_O[^_O___P`!`0$```````$"`@("`@$!`0$!`0$` M`/___O[^_O__``````````````````````````````#___[]_?W]_O_____^ M_O[^_O[^_O[^_O[^_O___P`!`0$```````$"`@("`@$!`0$!`0$!`/___O[^ M_O__``````````````````````````````#___[]_?W]_O_______O[^_O[_ M__[^_O[^_O___P`!`0$```````$"`@("`0$!`0$!`0$!`/____[^_O__```` M``````````````````````````#___[]_?W]_O_______O[^_O[___[^_O[^ M_O___P`!`0$```````$!`@(!`0$!`0$!`0$!``#___[^_O__```````````` M````````````````````__[^_?W]_O_______O[^_O_____^_O[^_O___P`! M`0$````````!`0$!`0$!`0$!`0$!``#____^_O__```````````````````` M````````````__[^_OW^_O________[^_O_______O[^_____P```0$````` M```!`0$!`0$!`0$!`0$!``#_________```````````````````````````` M`````/_^_O[^_O____________________[^_____P```0$``````````0$! M`0$!`0$!`0$!`0``_________P```````````````````````````````/_^ M_O[^_O[___________________________\``````````````0$!`0$!`0$! M`0$!`0``_________P```````````````````````````````/___O[^_O[_ M__________________________\```````#__P````$!`0$!`0$!`0$!`0$` M`/________\```````````````````````````````#___[^_O[_________ M__________________\```````#___\````!`0$!`0$!`0$!`0$```#_____ M__\`````````````````````````````````__[^_O[_________________ M____________````````____`````0$!`0$!`````0$`````________```` M````````````````````````````_____O[^________________________ M____````````_____P````$!`0$!````````````_________P`````````` M`````````````````````/____[^_____________________________P`` M`````/____\````!`0$!`````````````/_______P`````````````````` M``````````````#____^______________________________\``````/__ M__\```````````````````````#_______\````````````````````````` M``````#_____________________________________``````#_____```` M````````````````````______\````````````````````````````````` M____________________________________``````#_____```````````` M`````````````/______`````````````````````````````````/______ M_____________________________P``````_____P`````````````````` M````````____``````````````````````````````````#_____________ M______________________\`````_____P`````````````````````````` M``````````````````````````````````````#_____________________ M________________````______\````````````````````````````````` M````__\`````````````````````````____________________________ M_________P``______\``````````````````````````````````````/__ M````````````````````````____________________________________ M_P``______\```````````````````````````````````````#_```````` M`````````````````/__________________________________________ M__\```````````````````````````````````````#__P`````````````` M`````````/____________________________________________\````` M````````````````````````````````````__\````````````````````` M`/____________________________________________\````````````` M````````````````````````````____``````````````````````#_____ M______________________________________\````````````````````` M````````````````````_____P````````````````````#_____________ M______________________________\````````````````````````````` M`````````````/___P````````````````````#_____________________ M______________________\````````````````````````````````````` M`````/___P````````````````````#_____________________________ M_____________P````````````````````````````````````````````#_ M_P````````````````````#_____________________________________ M____```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````$-/34T````2``$``$(6``A`#:Q$```````` M34%22P````(``$E.4U0````4/```?P!_``````````````````!!4%!,```! MJ%-D,F$``@`````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````"D``````````````````` M```````````````````````````````````````````````````````````` M``0(```````)`",`````````````````>`````0`!````````/P`____@``` M``$!``9156YI=',````````````````````````````````````````!`@`& M('-A;7!S```````````````````````````````````````````````````` M````````````)P`O``__]O_Y``$````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````!`````7@```!X````5M8Z*`_> MOCO;Q0T.*`5//"BD#RQP.]W&*#P!`?\@1-@4"DUA9VEC($AARQP,4`0\-!QP%7W?^,7D/ M#080```!H`*0`/`FH#,0`J``,";0,]`"D`#P)!`R(!`````!H` M*0`/`5`!\0`J``,";0,]`````````````````!H`+``6`3X!W``J``,";0,] M`````````````````!H``````````````````````````````````````0`` M``%X````>````%8`<;B\'*8````<`%8``%=S=&$``P`*``'__P`````````` M``+__P```!X```````/__P```#P```````3__P```%H````````````````` I```````````````````````````````````````````````````````` ` end nethack-3.4.3/sys/share/sounds/toolhorn.uu0100644000000000000000000005131007764735041017324 0ustar rootrootbegin 644 Tooled_Horn M``M4;V]L960@2&]R;@`````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``((`10```````#DB```! MSJ<]K0&G/:TS``````````````````````````````"!@1/]``!&3U)-```Y M&D%)1D934TY$```W'@````````````````````````````#_____________ M__________________________\```````````````````````````#_____ M________```!`@,#!`4%!@8&!@8%!00$`P("`0$``/____________\````` M`0$!`@("`P,#`P,#`@("`@("`0$``/___OW]^_KY]_;T\_'P[^_N[^_P\O/V M^/O]``0&"`L-#Q`0$!`/#0P+"0@&!`,!`/_^_OW]_?W]_?W]_?[^__\``0$" M`P0$!04%!04%!04%!`,#`@$`__[]^_GW]?+P[>OIY^7EY>7GZ>SP]/G]`@8* M#A(5%Q@9&!<6%!$/#`H(!@0"`/_]_/S[^_O[^_O[_/S]_?[_``$#`P0$!04& M!@<("`D)"`<&!`,!__W[^?;R[NKEX=W;V=?7V=O>X^CN]?L""`X4&1P?(2(A M(!X<&183#PP*!P4#`?_^_/OZ^OKZ^OKZ^OO[_/W^``$"`P0%!@<("`D*"PL+ M"@D(!@4#`?[[^/3OZN7?VM;2S\[/T-/7V^'F[?3[!`P3&B`D*"HJ*B@E(AX; M%Q,/#`D&`P'__?S[^OKZ^?GY^OK[_/W^``$"`P,$!`4&!P@)"0H*"@D(!P8% M`P#]^O;Q[.?AV]71SKCW=?1R\?#P<#"Q,C-U-SE[_H&$1PF+C0X.CHX-3`K)B$;%A(-"04"__W[ M^OGX]_?W]_?X^/G[_/X``0("`P0%!P@)"@L,#`P+"@D(!P8#`/WX\^WFW]?0 MR,.^NKBZO,'(T=KE[_L'$AXG,#8Z/#PZ-S,M*"(=&!,/"P<$`/[\^OGX^/?W M]_?W^/GZ_/[_``$"!`4&"`D+#0X/$`\.#0L*"`0`_/CS[>;?UL['P+JULK&S MMKW%T-SI]P85(BXX/T-%1$(^.#(K)1\9%`\+!P0!_OSZ^?CW]_?W]_CY^?O] M_O\``0$"`P0%!P@*"PP-#0T,#`L*"`4!_??RZ^3;T\S$OKBSL*^QM+K"SMOK M^PL;*C8_14E*2$0_.#$J(QT7$0T)!0(`_OS[^OGY^?CX^?GZ^_S]_O[__P`` M`0(#!08'"0H+#`P+"PL*"`4"_OGS[.7+3E! M1TI*2$,]-BXG(!H4#PL(!0(`__[]_/S\^_O[^_S\_?W^_O[^_O[^_O\``0,% M!PD*"PP-#0T,"@<$`/SU[N;>U<['P+JTL;"PLK:^R-;G^0L=+3I$2DU-2D4^ M-R\F'QD3#@H&!`(`__[]_?S\_/S\_/S\_?W^_O[]_?W]_O[_`0($!@@)"0H* M"@H)"`8$`?WX\>KCVM/,Q+ZZM[:VN+O"RM7D]`46)3(\1$A)1T,^-R\H(!H4 M#PL(!0(`__[^_?W]_?S\_/S]_?[^_O[^_O[^_O\``@,%!@<("0H+"PL)"`8# M__KT[.7'S!1K^$2,S0$A.4$]+1#PT*R(;%`\+!P0"`0#___[^_O[^ M_O[^____``#___[^_?W]_?X``@,%!P@*"PP,"PH(!0+]^/'JX]K3S,2^N+.P MK["RM\#-W?`%&2LZ1DY14D]*0SHP)Q\7$0P(!0,!``#___________\```$! M`0#___[]_/S\_/[_`0,%!@@)"@L,#`H(!0']^/'JXMO3S,6_N;2QL+"RM\#, MW?$&&RT\2$]34U!)0CDO)AT6$`L'!`,!````______[^_O___P```/___O[] M_?W]_?X``0,%!@<("0D*"0@'!0/_^O/LY-W5SL;`N[>TL[2VN\/.W>\#%B@W M0TM/44Y)0CDP)Q\7$0P(!0,"`0``_____O[^_O[__P````#__O[]_?W]_O\` M`@,%!@<'"`D*"@H)!P0`^_3LY=S3S,.\MK*OKJ^RN<32Y/@-(#(_24]244U' M/C8L(QL4#@H&!`(!`/_^_O[^_O[^_O__``$!`0#___[^_?W]_O\!`P4'"0H* M"PL+"0@&!`#[]>[GWM;-Q;ZWL:VKK*^TOLO;[P4:+#Q'3U-34$I#.C`G'A<1 M#`@%`P$`___^_O[^_O[^____```!`0#___[]_?W]_@`!`P4'"`@)"@L*"@@& M!`#Z].SDW=3,P[RVL*RKK;"UO\S>\PD=+SY*45144$E"."\F'180"P<%`P(! M`/___O[^_O[^_O__```!`0#___[]_?W]_@`"!`8'"0H+"PL+"@@'!`#[].WD MW-/,P[RVL:ZMK:^TOLO<\0<<+S]*4E5544I"."\E'!40"P<%`P(!`/___O[^ M_O[^_O[^_P```/___OW]_?W]_@`!`P4&"`D*"@L+"PH)!@/]]^_GWM;-Q;VW MLJZLK*ZSO,G:[@09+#Q(4%1544M#.C`G'Q<1#0D&!`(!`/___O[^_O[^_O[^ M____`/___OW]_?W^_@`!`P4'"`D*"@H+"PH(!0+^^/'HX-?/Q[^XLJ^MKK"V MOLO<[P08*CE%35!13DE".3`H'Q@2#@H'!0,!`/_^_O[]_?W]_O[^_O__``#_ M__[^_?[^_O\!`P4'"0L,#`T,"PH(!0']]N_FW=3+P[NTKJNJJZ^VP,_A]@L? M,#Y)3U)13DA`-R\F'A@2#0H'!`(`__[]_?W]_?W]_?W^_O_______OW]_?W^ M_P`"!`8("@H+"PP+"PD'!0'\]>[EW=3+PKFRK*FHJ:RTP-#C^0\C-4-,4E13 M3D<_-BTD'181#0D'!0,!`/_^_?W]_?W]_?W^_O_______OW]_/W]_@`"`P4' M"0H+#`T-#0P*!P/^]^_FW=3+PKFRK*BFIJFQO,SA^`XC-4--4U543T@_-BTD M'!81#0D'!0,!`/_^_?W]_?W]_?W^_O[____^_?S\_/S]_O\``@0&"`H+#`T- M#0L)!@/_^O/JXMG0R+^XLJZJJ:JON,;8[@4:+3U(4%-34$E".3`G(!D3#PL) M!P0"`?_^_?W]_/S\_/S]_?[^_O_^_OW]_?W]_@`!`@0&"`H+"PP,#`P*"`0` M^_7MYMW4R\.\MK&NK:ZQN<33YOL/(C-`24]03TM$.S0L(QT7$@X+"`8$`@#^ M_?W\_/S\_/S\_/S\_?W]_?W\_/S]_P`"!`8("0L,#`P+"PL*!P0!_/;OY][6 MSL6^MK&MJZROML'0Y/D.(C-`2E!14$Q%/#4L)!X8$P\,"`8$`?_^_?S\^_O[ M^_O[_/S\_?W]_?W\_/W]_@`"!`8'"`H+#`P,#`L*!P0!_/?PZ-_6S<2[M:^K MJJJMM<#0Y?H/(S1!2U!244Q%/C4M)1\9%!`,"08#`?_^_?S[^_O[^_O[^_S\ M_/W]_/S\_/S]_@`!`P4'"0H,#`T-#0P+"08#_OCQZN'7SL6\M:^JJ*>JL;S, MX?<-(3-!2U%34DU&/S8N)B`:%!`-"@<$`?_^_/S[^_O[^_O\_/S\_?W]_/S[ M^_O\_?X``@0&"0L,#0X-#0P+"`4"__KSZ^+9T,B_N+&MJJFKL+K)W/$'&RT\ M2$Y144Y(03@O*"$;%A(."P@&`P'__OW\_/S\^_O[^_O[^_S\_/O[^_O[_?X` M`0,%!PD*#`T.#@X-#`D&`O[W\.C?ULW$N[2OJZFHJ[*^T.7[$24V0TQ24U%, M13PU+"4>&141#0H'!`'__?S[^_KZ^OKZ^OK[^_S\_/S\^_O[_/[_`0($!@@* M#`X.#0T-#`D&`_[Y\NKAV=#(P;NVL:ZMKK*\RMSQ!QLM.T9-4%!-1T`W,"@B M'!<3#PL(!0(`_OW\^_KZ^OGY^?GY^OK[^_O[^_S\_?\``@0&"`D+#`T-#0T- M"PD'`__Z\^OCVM#'OK>QK*BGJK"[RM[T"AXP/DA/4E%.2$$Y,"DB'!<3#PL' M!0'__?S[^OKZ^OKZ^OGY^?GY^?KY^?K[_/X!`P4'"0H+#`P,"PL*"0@%`O_Z M].WFW=7,Q+RWL:VKJZZVQ-;K`18I.45-45)/2D,\,RLE'QD5$0T*!@0!_OW[ M^OGY^?GY^?GY^?GZ^OKZ^OK[_/W_`0,%!PD+#0X.#0T,"PD'!`']]N[GWM7, MP[NUKZNHIZJRP-/I`!8J.TA05%113$4]-"PE'AD5$0T)!@,`_OW[^OKZ^OKZ M^OKZ^OKZ^OKZ^?GZ^_S^``($!0<("0L,#0X-#0T+"`4!_/7LY-O2R+^XL:NG MI:>LM\?<]`LA,T),4E533TA!."\H(AP7$P\+"`0"`/[\^_KY^?GY^?GY^?KZ M^_OZ^OKZ^OO]_P$#!`8("@P-#@X.#0P+"`4"_??PY][5S<2\M:^JIJ:JL\'5 M[`,9+#Q(4%1444M$/#,L)1\9%!`,"`4"__W\^_KZ^?GY^?CX^/CY^?KY^?GY M^OO\_@$#!0<("@P-#@X.#@T,"08#_OGRZN'8SL6\M*ZHI*.FK[W1Z0`7*SM( M4%154DQ%/30L)1X9%!`,"04"__W[^OGY^?GY^?GY^?KZ^_O[^_KZ^OO\_?\! M`P4("@P-#@X/#@T,"@8"_OCQZN'8S\>_N+*LJ*>HK[O,XOD0)#9$3E-44TY' M/CKAV=#'OK>PJJ6CI:Z]T>H#&BX_2E)655)+1#LS*R0>&!00#0D% M`O_]^_KY^?GY^?GY^?GZ^OO[^_KZ^OK\_?\``@0%!PD*"PP-#@X.#0H'!/_Y M\NOAV,_%O+2MJ*2CIJZ\T.@`%RL\25%555),13TT+"4?&100#`D%`O_]_/KZ M^?GY^OKY^?GY^OKZ^OGY^?K[_/X``@0%!PD+#`T-#@X.#0H'!0#Z\^SBV=#' MOK>OJJ:DIZZ[SN3\$RWDV]+)P+BQJZ:C MI*JUQ]SS#"(T0TY3551/2$`W+R?FYN@K<':]`XE.4A26%E644I!."\G(1L5$0T)!0+_ M_?OY^/CX^?GZ^OO[^_O[^_OZ^?CX^?K\_@`"!`8)"PT.#@X-#0P+"08"_?CQ MZ.#7SL6^MJ^GHJ&CK+S2[`4=,4%-5%=644I#.C$I(AP7$P\+"`0!__W[^OKZ M^OKZ^OKZ^OO[^_OZ^?CX^?K[_?\!`P4'"0L,#0X/#P\.#`D%`/OT[./:TLG` MN+"GH9^@I[;+Y/\8+C],5%A75$U%/#,J(QP7$P\+"`4!__W[^OGY^OKZ^OKZ M^OO[^_OZ^?GY^?K[_?\!`P4("@L-#@\0$!`/#0H&`?SU[>3;TLB_MZZEGIN; MHK''X?T6+4!-55E954]'/C4L)!X8$P\,"`0"__W[^OGY^?GZ^OK[^_O[^_O[ M^OGX^/GZ_/X``@4'"@P-#Q`1$1`/#0D%`?OT[>3;TLG`MZ^HHIZ=I+''X?L6 M+#Y,5%E954Y'/C4L)!X8%!`,"`4"__W[^OGY^?GZ^OK[^_O\_/S[^OGY^?GZ M_/X``@0'"@P-#@\/#P\-#`D&`OWV[N;NI9Z9F)^O MR.0!'#)$45E<6U9.13PR*2(;%A(."@8$`/[\^OGY^?KZ^_O\_/S\_?W\^_KZ M^?GY^OO]``($!PH,#@\0$!`/#@P*!P+]]NWEW-/*P;FQIYZ7E)FIP=[\&#!# M4EI=7%=01STT*R,<%Q,/"P@$`?[\^OGX^/GY^OO[_/S\_?W]_/OZ^?GY^OS^ M``($!@@*#`T.#P\/#PT+"`3_^/#GW=3+PKFPIYZ7E9JHO]OY%2U`3UA<7%A1 M2#XT*R,=%Q,/#`@%`O_]^_KY^?GZ^OO[^_S\_/S\_/OZ^?GY^OS^``($!PH, M#@\/#P\/#PX,"04`^?'HWM7+PKFOI9R4D9:DO-GW%"U!4%I>7EI32D`V+24> M&!,/"P@$`?[\^OGX^/GY^OO[_/S\_/S\_/OZ^?CX^?O]``($!PH,#@\0$1(2 M$0\-"04`^?#HWM7,P[JPIIR4D).@M]3S$2M`3UE>7EI32D`V+24>&!,/#`@% M`O_\^OGX^/GZ^_O\_/S\_/S\_/OY^/CX^?O]_@`#!@D,#Q$2$Q,2$A`-"@8` M^?'GW=/)P+:LHI>0C9.CO-KY%B]#4EI>75E22#XT*R,<%Q(."P<%`?_]^_GY M^?GZ^_S\_?W]_?W]_?SZ^?CX^/K[_0`"!`<+#0\0$1$2$0\-"@8`^?'HW];, MP[JPIIR4CY*?MM/S$2H_4%I?7UM42D`W+B4>&!,/#`D%`O_]^_KY^?GZ^OO[ M_/S\_/S\_/OZ^/CX^?K\_0`"!0@+#0\0$1(3$Q$/#`@"_/7LX]K0Q[ZUK**9 MD9"9J\;E!"`W255<7EQ63D0Z,2DA&Q82#@H'`P#]^_KY^?GY^OO\_/S]_?W] M_/SZ^?CW^/G[_0`#!0@,#@\0$1(2$A$."P<#_/7LX]K2R<&XKZ67U1D9NNRND'(SE*5EQ= M6U5-1#HQ*"(<%Q,/"P<$`?[\^OGX^/GY^OO[^_O[^_S[^_KY^/CY^OS^``,& M"`L.$!$1$A(2$0\,"03]]N_FW-/)P+>LH)6-BY2IQ>0#'S9)5EQ>7%9/1CPS M*B,=%Q,/"P@$`/[[^?CX^/GZ^_O\_/S\_/S\^_KX]_?X^?K\_@`#!@H.$!$2 M$Q,3$0\-"@8`^?#HW]7,P[FOI)B/BY"AN]KZ%S%$4UM>75A11SXU+"0>&!00 M#`@%`?_\^OGX^/GY^OO[_/S\_/S\_/KY^/CX^OO]_P$#!@@*#0\0$1$1$0\- M"@8"^_3LX]K1R+^UJY^5CY";LL_N#"8[3%9;7%E22D$X+R<@&A82#@H&`O_\ M^OGX]_CY^OO[^_O[^_O\^_KY^/CX^/G[_@`#!@@+#0\1$A,3$Q$."P<"_/7M MY-O2R<"VK**8D9":KLGH!R(X251;7%I43$,Z,2@B'!82#@L'`P#]^_GX^/CY M^OO[^_O[^_O[^_KY^/CX^?O]_P$#!@@+#A`1$A,3$A$/#`@$_?;MY-O1R+ZT MJ9V2BXN6K,GI"20[3%A>7UQ53D0[,BHB'!82#@H&`__]^_GW]_CX^?K[_/S\ M_/S\_/OY^/?W^/K\_@`"!0<)#`\1$A04$A$/"P@#_O?OYMW3R;^UJIZ3BXN5 MJL?G!R(Y2U==7EM6340Z,2DB'!<2#@H'`P'^^_GX^/CY^OO\_/S\_/S\^_KY M^/?W]_G[_?\!`P8("PX0$A04%!02#PL&`?KQZ-[4R\&VJIV1AX6/I,+D!"$Y M2U=>7UQ63T4[,BHB'!<2#@L'!`'^^_GX^/CY^OO\_?W]_?S\^_OY^/?W]_CZ M_/X``P8)#0\1$Q04%!,1#@H%`/GRZ>#7S<2ZL*.7C(>-G[G:^A@R151<7UY8 M44<^-"LC'1<3#PL(!0+__/KY^/CX^?K[_/S\_/S\_/OZ^??W]_CY^_W_`@4( M#`\1$Q04%!01#@H&`?KRZN'8S\:]LZF=DHR.F[/1\1`J/T]975U:4TI`-RXF M'QD5$0T)!@/__?OY^/CY^?K[^_S\_/S[^_OZ^??W]_?Y^_W_`@4(#`X0$A05 M%102#PL'`OWV[>3;T\K"N;"DF9&/EJG$Y`0?-DE56UU;5$U$.C$H(1L6$@X* M!P0!_OOY^/CX^?KZ^_S\_/S\_/O[^OGX^/GZ_/X``@0&"@T/$1,4%103$0T) M!/[W[^?>USCVM'(OK6JGI.,C)>LR>D((SI+ M5EQ=6E1,0SDP*"(<%A(."P<$`?W[^?CX^/GZ^_O\_/S\_/O[^OCW]_?X^?O^ M`0,&"0P/$1(3%!03$0\,"03_^/#HW];-Q+FMH)2*B)&DP>(#(#=*5EU?7%5. M13LR*2(<%Q(."P<$`?W[^??W]_CY^OO\_/W\_/S\^_GX^/CX^?O]``($!PD, M#Q$3%!44$Q$."03_^._GWM3+PKFNHI6,B9&DP.`!'C9)55Q?7%9/13PS*B,= M%Q,/"P@%`O[\^OCX^/CY^OO\_/S\_/S[^OCW]O;W^/K\_@$%"`L/$1(4%144 M$Q$."@4`^O/JX=C/QKRQI9F.B(R=M];W%B]#45M>75A12#XU+"4=&!00#`D% M`P#]^OCX^/CY^OO\_/S\_/S\^_KX]_?X^?K\_@`"!`<*#1`2$Q04%!(/#`@# M_/7LXMG0QKRRIYN1C(Z;L]'Q$"H_3EA=75E224`W+B8?&100#`D%`__]^_GX M^/CY^OO\_/S\_/S\^_KY^/?W]_G[_?\"!0@,$!,6%Q<6%1,0#`7EI32T$X+R<@&A41#0D&`O_\^OGX]_CY^OO\ M_?W]_?S\^_KY]_?W^/GZ_/X!!`<+#Q(3%186%1,0#0D#_?;MY-O1R+^UJY^4 MC8V7K,CH!R,Y2E9;7%I32T,Y,"DA&Q82#@H'!`'^_/KY^/CY^OO\_?W]_?S\ M^_KY^/?W^/G[_/\"!0@,#A`1$A,3$A$/#0H%__CQZ-_6S,.YK:&4BXB1IDHJ*E:S+[`PH/4Y875Y:5$M"."\H(!H5$0T)!@(` M_?KX]_?X^?K[_/S\_/S\_/OZ^?CW]_CZ^_T``@4("PX1$Q05%102$`P(`_WV M[N77C?U65!'/3,J(QP7$P\,"04"__SZ^/?W^/GZ^_S]_?[^_?W[^OGW]_?X M^OO]_P(%"0L-#Q$2$Q03$A`,"`/\\^OBV,W$NK"DF(V(C)RVUO@7,$547%]> M65%(/C4L)!X8$P\+"`0!_OSZ^/?W^/GZ_/W^_O[^_?W[^OCW]_?X^OO]``(% M"0P/$1,5%144$Q`,!P+[\^K@U\W$NK"CE8J%B9JVU_D9,T=67F%?65)(/S4L M)1X8$P\+"`0!_OSZ^/?X^/G[_/W^_O[^_OW\^OCW]_?X^?O]``,%"`P.$!$3 M%!03$@\,"`/\\^OAV,[$N:Z@D86`AIJXW/\?.4Q98&)?65%'/30K(QT7$@X* M!@0!_?OY^/?X^/K[_?[______OW\^OCW]?7V^/K]``,&"0P/$1(3$Q,3$0X+ M!@'[\^KAV,_&O;*FF8V'BIBRT_45,$5476!?6E)(/C0K)!P7$P\+"`4"`/W[ M^?CX^?K[_/W^_O___OW\^OGW]_?W^?K\_@$$!PH-#Q$2$Q,3$@\,"03]]NWD MW-/*P;>KG8^%A9"HR.P.*D%276)A7%1+03,%(SM.6F!@759. M0SDP*"`:%1$-"@<$`?[\^OCW]_CZ^_S^______[]_/KX]_?W^/GZ_0`"!0D, M$!(3%!04$Q(/"P8`^?#FW=3+PKFNHI2*AHV@O-X`'SE,66!A7EA/13LQ*"$; M%A(."P@$`?[\^?CW]_CY^_W^_O____[]^_KX]_?W^/K\_@`#!@@+#A`1$Q04 M$Q$."@8`^?+HW]?.Q;VSIIJ/BHV=M]?Y&#)&5%Q?75A01STT*R,=%Q,/"P@% M`O_\^OGX^/CY^OS]_O[^_O[\^_KY^/?W^/K\_@`#!0@+#0\1$A(3$Q(/#`@" M_/3LX]K1R+^TJ)J.AXF7L='S%"]$4UQ@7UI324`V+24?&100#`D%`O_\^OCW M]_CY^OS]_?[^_OW\^_GX]_;V^/G[_@$$!PH-$!(3$Q03$A`-"@8!^O/KXMG0 MQ[VSIYR1BXV;L]/U%"Y#4EM>75E123\V+24>&!,/#`D%`@#\^OGW]_CY^OS] M_O[^_O[]_/KY^/?W^?K\_@`#!@D-#Q$3%!03$Q$."@8`^?+IX-?/QKVSIYJ/ MB8R:LM+T$RY#4UU@7UM32D`W+B4?&100#`@&`__]^_GX^/CY^OS]_O[__O[\ M^_GX]_;W^/G\_@`#!0@+#A`2$A,3$A$."P@"_/7MY-O2R<"WK*"5C8R6JL?H M""4\35A>7EM53$(Y," M7UQ6340Z,2DA&Q81#0H'!`'^_/KY^/CY^OO\_?[^_O[]_/OY^/?W]_CZ_/\" M!`<*#0\1$Q04%!,1#@H%_O?OYMS2R+ZSIYJ-@X*-I<7J#"E!4EUB8EY73D4Z M,2@A&Q41#0D%`O_\^?CW]_?X^OS]_O_____^_/OY]_;V]_CZ_/X!!`<+#A$3 M%!44$Q(/#`@#_?7MY-K1R+^UJYZ2BHJ4J:CXF- MG;C9^A@Q15)97%I4340Z,2DA&Q82#@L(!0+__/KY^/CY^OO\_?[____^_?OY M^/CX^/CY^_W_`00(#`\0$1,4$Q,1#PL'`OOT[.+9T,B_M:B:CXN0H;S<_1LS M1E)96UE42T(Y,"@@&A00#`D&`P#^_/KY^/GY^OS]_O_____^_?OZ^/?W]_CY M^_W_`@0'"PX0$A,3$Q(0#@L&`?SU[>3,D!)34U*13XW+B[HX=K4S<2[LJJGK+G. MYP`6*#8_1$9$0#DS+"4?&100#0H(!0,!__W[^OGZ^OO\_?[______OW\^OKY M^?GZ^_S^``($!@D+#`T-#0T-#`H(!0'\]_'KY-[8T&141#0H(!@,!__W[^OKZ^OO\_?[^_____OW\^_KZ^?KZ^_S] M_P$#!0@+#0X/#PX-#`H'!`'\]_+KY-[7T/=U]#'O[>TMK_/X_@,'2HS.#HY-S(M)R`;%A(.#`D'!0," M`/[]_/O[^_S\_?[^_____OW]_/OZ^OK[_/W^``(#!0<)"@H+"PL+"@D'!`'^ M^O7OZN7@V]7.Q;ZZN;_,W_,'&"4O-3@X-3$L)B$;%Q,/#`H(!@0"`/_]_/O[ M^_O\_?[^_____O[]_/O[^OKZ^_S]_P$"!`8'"0H+#`P,"PD'!0+_^_;Q[.?A MW-;/Q[^ZNL#.X/0'%R0M,S4U,R\J)!\:%A(."PD'!0,!__[\^_O[^_O\_?[^ M_____O[]_/OZ^OKZ^_S]_P`"`P4("@L,#`P+"PD'!0+_^_?R[>GDW]K3S,7` MOL/.W_$#$A\H+C$R,"TH(QX9%1$-"PD'!00"`/_^_?S[^_S\_?[^_O[^_O[] M_/S[^_K[^_S]_@`!`P4'"`D+"PL+"PH(!@,`_?GT[^KEX-S7T,K%P\?0W>W^ M#1HD*BXO+BLH(QX:%A(/#`D'!0,"`/_^_?S\_/S]_?[^_____O[]_?S[^_O[ M_/W^_P`!`@,%!P@)"@H*"0@'!@0!_OKV\N[IY>'7@V];2S\_4W>GV!`\8'R,F)B0B'QL7%!`-"PD' M!@0#`0#__OW\_/S]_?[^_O[___[^_OW\_/S\_/W]_O\``0($!08&!P<("`<& M!00"`/WZ]_/P[.CDX-O7U-/6W>?S``L4&Q\B(R(@'1H6$Q`-"PD'!@0#`@'_ M_OW]_/S]_?W^_O[^_O[^_OW]_/S\_/W]_O\``0(#!08'!P@("`<&!0,"`/[[ M^/7R[NOHY.#7P_`<0%AL?("`>'!D6$P\-"PD'!@0#`@$`__[]_?W] M_?W^_O[^_O[^_OW]_?W\_?W]_O\```$"!`4&!P<'!P<&!00"`?_\^?;S\.SJ MY^/?W-K:WN;P^@0-$Q@<'1T<&A@5$@\-"PD'!@0#`@$`__[^_?W]_?[^_O[^ M_O[^_O[]_?W]_?W]_O__``$"`P0%!@8&!@8&!0,"`?_]^_CU\_#MZN?DX=_? MX>;M]O\(#A08&1H:&!84$0\,"@@'!@0#`@$``/_^_OW]_?[^_O[^_O[^_OW] M_?W]_?W^_O__``$"`P0%!08&!@8%!00#`0#^_/KW]/+O[.GFXN#@X>;N]O\' M#1(6%Q@8%A02$`X,"@@'!00#`@$`___^_OW]_?[^_O[____^_O[^_?W]_?W] M_O[_``$"`@,$!04%!04$!`,"`?_^_/KX]O3Q[^WIY^7DY>GO]OX$"@\2%!45 M%!(1#PP+"0<&!00#`@$``/_^_O[^_O[^_O[______O[^_OW]_?[^_O[_```! M`@,#!`0$!`0$!`,"`0#__OSZ^/;S\>_LZ>?FY^KO]OT#"0T0$A,3$A$/#0L* M"`<%!`,"`0$`___^_O[^_O[^__________[^_O[^_O[^_O[__P`!`0(#`P,$ M!`0$`P,"`0'__OW[^??V]/+O[>OIZ>SP]OP"!PL.#Q`0$`X-"PH(!P8$!`," M`0$``/___O[^_O[____________^_O[^_O[^_O___P```0("`P,#`P,#`P(" M`0#__OW\^OGW]O3S\>_M[>_R]OL`!`@+#`T.#0P+"@@'!@4$`P("`0$``/__ M__[^_O[______________O[^_O[^_O___P```0$"`@("`@("`@(!`0#___[\ M^_KY^/?U]/+Q\?+T]_O_`P8("@L+"PH)"`<&!00#`@(!`0$``/__________ M_________________________P````$!`0$!`@("`0$!`0``__[]_?S[^OGX M]_;U]/7V^/O_`00&!P@("`@'!@4%!`,"`@$!`0````#_________________ M__________________\````!`0$!`0$!`0$!````___^_OW\_/OZ^OGX^/CY M^OS^``($!04%!04%!`0#`@("`0$!``````#_________________________ M__________\``````````0$`````````_____O[^_?W]_/S[^_O[_/W_``$" M`@,#`P,"`@(!`0$!``````````#_________________________________ M__\`````````````````````______________[^_O[^____```````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````````!#3TU-```` M$@`!```W%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P`` M````````````````05!03````:A39#)A``(```````````!%]```!``*`*`` M`'E%]````@`*J8$``'D(Q2LCU@`````@5@`BW@!$]`````%$!P`%]"(`__\% M]"4``_]F]!,`#`!(`0`&`(0``(Q(7@!G]```#``%]"<``_\*J:,``+,*J80` M`)$*J"0,`*4-`2(*J80``+-A]```!`!']```#@`-`+4BK@`@`'0.D)X-`3X* MJ80``+,-`2(*J80``+-A]```!`!']```#@`-`+4BK@`@`'0.$*P-`3X*J:0` M`)<*J`0```0*`*```.9"@0!(@@!$]"`___]$@T9(`49$]````"!$]$```_\A MT@!6@0`&WR!'!B-$]$8`#`!%@T`$"```````"0`C`````````````````'@` M```$``0```````#\`/___X`````!`0`&455N:71S```````````````````` M`````````````````````0(`!B!S86UP````%9N(&EN=&4@9&5L87,@9IIR````'@```!6`'&XO!RF````'`!6``!7 M```````#__\````\```````$ M__\```!:```````````````````````````````````````````````````` /```````````````````` ` end nethack-3.4.3/sys/share/sounds/wdnflute.uu0100644000000000000000000004724707764735041017326 0ustar rootrootbegin 644 Wooden_Flute M``Q7;V]D96X@1FQU=&4````````````````````````````````````````` M``````````````````````````!!249&4V0R80$````!%````````#8B```! MSJ<]K;"G/:VZ``````````````````````````````"!@1V.``!&3U)-```V M&D%)1D934TY$```T'@```````````````````````/____________\````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````$!``$!``$!`0$```$!`0`!`0$! M`0$!`0$!`0$!`0$!`?_^_P#__P$!`/_]^OG^`0,*#0@)#0@#`?\!`P0%!08% M`/SZ^OCT]/CZ!`P"]_W_]_3V_PH-"0+\_?[^`P(`__L&&A,&!P4`_@(-%142 M"/SQ[/#[^^SF[.WGZ.KEX^CFXNWY^_\*!?G_!/X*&AL4#P\1#P<`!@P%^.KH M\_3FWN7EUY];5XN3E\?GS^`D-"Q4G,2\Q-3(L*RXF*#H_,QX4&Q3ZZ^SIX.#= MS,?1SK^YOL_C[?D-&1L:&"$O-3M"0D5,0SI(6E`^."T?&Q0#[^'5R,3$O;V_ MKZ*HNY ML;*\QM3A]`L,#"<^3%I0.3=#1DQE;E];5S\E$__KY./6O[:VKJ:ML:*5FZJY MSN;U`0L1$Q,:*#I/6%%,3E5>75-%,B,@'@X`_>W2P[6GL;VUL;2RM+C#V.7L M^/\%$R4X0$5.2T%$2#X[361;/#`O'Q02^]"ZP,2ZN,#"N*^FG):BR>WR[P$7 M%A0M/S8O-#],6&EY=V=)(`D1'A<*"?O7PKZYKZ2>I*BDKLO1S.#PXM7>]0\M M3EY22$4W*"TU-T-*0"L?(QH&[DYVQP]#7V^@"&"`C*"@@ M'"4O/4U35U,[)2$>"O7S\^#1U-3%NK:NHYR9F**ZSM7AZ^/644T*!T%Y,_,T]C=Y=W`JZ>DH:*NQM_P_/X#'"P>$AD?*$1@9%E34TDW M,#,N)1X3`_'HZ.'.OKFWL;6ZM+7$S]?F\O7W_@P<*3`W/4-,2T9`,BXW/#0L M+S(F%/G4O\;.S/=Z?'ET+^UM+BPI:K`UN+N]O/U!108$0D3*#M!.S8X-"@B(2$K+R@B$_OP MZMW3QKJWM[F^Q,.YL;.]U.SZ!Q`6(24A'1TG,S(O,T%/3D`U*QT1"0#QX-7; MX=6^M+>XMK*NM<+*V/`!"!0;%A`,$"$T/D)!/#Q#0SPR&P<#!`D/`^C1P[>O MKJ^PM<#%O[O(Y?;X^_KY#B\],2HS.#(L+S4X0U)--2XO\K.P[BTL;?) MW.KS^/H"'3Q%-B8D)!P6*$A64U1+,QP2#@/SZ^;?V];/R<:\JZ.IM;[,Z0<1 M!O\#"!$A-#\_/3T_1%%93CTW+!H7'AP0^M[)N;*YP\"VL[.SM\#0W^+I\_,` M'2\W/SXL'"$S04E/3D4^-BLD&PX%\]K,S<_/S,6WJZ>LM,#6ZNSP_PH(#",V M,RHG+C8X0E%00S@O(!PC(!``\=O&PL?*Q;RSJJ*HNL3*W.;=W/41'"0M-S4H M*#8\/4%$/"\J*RHJ(Q+XW\_$OL++SL2WL:JGK\#+SMGO_P0-("LF(1T:)CE" M2DY%/38K)RHF&A(%Y\[.U-#%N*ZKIZ>PM;?"S='8Y?@+%QT?'!XK.CX_14,Z M-S0J*38]+`SSY]W1Q\;+Q+FXM;"UO<3*R\W9[PL>(A\>("`@*C0]148_-C0[ M03LI&`CSYN7AULS%P;ZTJZVRM+S$P\KA^PP3%QH9'2HO+CM/4$$^/38X04,Z M)1$$_/#;R+^YM[>TLK6ZNKBYN\'3[@88)"@H*"[J MW\J[N+:OJ[&YNK2RNL35[?P!"A@B*C`R-3]#/3TL:ZKI*2O MNL?7W^K_!@$.*#8_0CL]1$%!2U!023PS+R06"?GFS[ZZO+RWLJ^HI*2FK\'. MV>S[_P84(RTT.CT\0$=/55%(2$0V*24?$O_FS\&YM+2ULJVHJ*NLL+W,V.'H M^1$@*#8^-S(]2$='4%A734`Y-BXA#_GJVL>_P;VVM+.MIZ:MO,7*U.'O_@\B M,38Z04,_04]=75504$U$.S$C$_[FU,K!NKN_MJ>AIZVML;[,UN'M_1,D*"X[ M0D!'5%A555E63$5`.SDN%/WMUL&^O;2NKJZLJ*:MM;K`S=OJ_A$A+S4U.4%% M2$]87EI134U(0#4E$?WLW,W`N;>RK:FFI:FPM;B\Q=/H_A$?*#`W/D)"2%1= M6E-,24I(/B\@#?KJV\_&N[*MJ:*>HZRQL;:_QM#B]0<;+#4W.T%'4%-03U!2 M4TU&0C8A#O_IS\;)PK.JIZBGHZ2LM+:[Q=3F^@\A)R@P/D=)3%):751+2TY+ M13DB!_?QZ-;!MK2RJJ.AIJVRM+6XO\[F^@40(C<^.CY*45164E%345)42#$= M%`;MV<[*Q[JII*6FJ*BLL;:]Q]+<[`@A+"TQ/4I355)-35)45%122T(M"N[F MYMO*OKFVKJ2@HZ2GK[B\P,WE_0@*$B,S/T=.55I844E'2U%643PG&0SVWL_( MP+:OK*JHJ*JIJ*FQOM'F]P,1'2(J-D)-65Q33E)64U%12CHI&PS^[=W,O;&G MI*JNJZBHJJRON,S@\P42&B4O.TA/3DY25%-56EI52SHG%PT"\^+0O["LK:FI MK*NIJJZTOLS=[?X.'"4P/DA04TU+3E%67V)92CLK'0[_\^;5P[2LJZRMK*:D MIZJPP-'>[O\'#QXN/4I14E%.35-;7UI01SDI(1L/_>;*M[.MIJ:NL*BCI:FN MN,;6YO+_%"HX/4%%1T9"151@965803(L(1(%^>[;PK.OJZJJIJ*BHJ:RP,G1 MW^[Y!!DS0TM.2D)$3UE>8&!:3D`P(Q@/_N;.OK:OK*RIHIZ>H*:MNLK6W>;T M"1XP/4)(44Y&2U5:7%U82#@U,B$,^>/+N[.OL+*OI9Z=GJ&LOH*BRN\/+T]WP"24Z03]! M1TI)35EB85I23$4Z+B02]=K)PKRVL;"KGY>6GJBPN,?4V.'T"B`R.T1,24E6 M7EU=6E-12T%!/"969E M74]$149!.BP8`.3/Q+JQK:FBGI^BI:JQM;:]S-[X`.SI`0DA58FAD8F%9 M3TI$-!X*].#5S,.[L:6:E9>:H*NTN+J]R=[V"AXR0$5#1U1>8%Y;6596659+ M.B0-]-_0QL"\M*B=FIF9GJ2JK[;"TN'T#"(O,C8_35]I:&1A6$]/5%1,/RX4 M]=_7S+ROJ*2@G9VAHZ6FIZNUQ>($'2@M,3="2D]<:VQD86%=6U=&+1@)_?#D MU<.VJYV3D9:=I:NJJ;"XQ-KU"ADK/$1)5F%B7EM97&%C8UY/.2(+]>7Z MK*"9FIJ8G:2CI:^_S-WT!A0C,3Q+66-H9EY85EA<7UM202<0_NS8RL*WJ:*? MG9ZAH9N9GZFWS>?["18B*S5!45UB9F=D8U]=8%A%,2`1"`#OVL:RHYR:F9R? MHZ6CHJFVP]3I_!`@+T)25UA<7%=35F!L;F!,-R,1`/'GW,FWK*2=FYZ>F9>; MHZV[S-CD^@P6)CQ.769B5E-87&!E95]20"P8!_KLV<2TK:JEGY^?F9*4GZJU MR>'O]?X,(SM)4%MC86%C96=D7%A0/2TI(0GLUL.SIZ"@I**?GIJ9G*.PP,[@ M]0L?+SQ*4E945%MF;7)P:%Q+.2TD$P/XX\FXK*2CH)N9EY27HZRRO3D$T)`[QWM7,P;:KGY60D9*6GJFRN;[$S^D*(#!`3E9;7E]?86-E M8EI:6U-"*@SRX='"N;*LIJ"7D(^4FZ6KKKG*W/`%&2P[1$M25V!M<&5=7%Y? M6TX\*1D$ZM3&N[*JHIJ4E9F;G)VAJK?#U>T"%BLW/49066!D9VEF9&-=54Y# M+18"[MS,O[6JG9:7EY.5G*6IJ[+`T^C\#B4[1DI586-?865C7%QG:EI#+QD" MZM?,P[:KIJ2?F).3EYN@J[G&U>G_$1LE-D=37VIM:&)?8F1@651+."`(].32 MP+2KHYN7F9N8E9FBJ;&]S^;\#APJ.4=5865E9F5I:V5?7%E-.B,+]N75P[2I MHIV9F9F9F)F=IJZYR^3["18H/DI/5EQ?8V=H:6AG8E1",2$._N[6Q+BKHY^: MEI>7E9B?IK&^R=GO!1@H-T9/56!J:&5H:V=A6U5+.RH7`.K9R+6FGYRHJJVQ]KM!!DJ-T966U=99G!N;6UF7E5(."H:!>[:R;BKI)^\@VOL/4\@P?,3]* M6V9F96IQ<&QI8UI22CXE"O;DT\&OI:&;E9*0D).9H*:JL2S,@$@#HT<&VK*&9E(^-D)69G*.LM<+2Y@$:+3U+56%L;FQN M;6=I;FI>3STG$/CDU<6XK)^6DY&/CHZ2FJ.LM\31Y/P/(CA+661K:VIN<&MI M96%?5T,L%/WHU<&RJJ.'%H96=E5T,Q(`_Y MW\BWJJ*=EY&.CI.7EY:?KKW-W.T$'C1#351B5D@R'P_XWLF[ MKJ2;E)&3DH^,D)JEK[K'U>P(&B,V4&-I:6MU>'!L:V-=5THY)`[YYM.[J)^< MF9:2CXZ0E)>4T8S)!8!ZM&YK:B=DY*2 MD(^0D)>AI['!T.;]$BE`3%5A:FYN;W)V=&QD5D0X*!'^[=6_M:F;E9*/CH^/ MD9:?J[?!R=GV$R8W35]H:FIMA MIZV[TN;V""(Z2U5<96YP='Q[<&AD74\[*!P/]=C#M:NBFY:1C8Z1DY.:J+>^ MQ-7Q#B,W2%)<9VYS=7-Q=G1C44E%.2`$\-_*MZFAG)6-CI*0CYBAIJNVQMCN M!ATV2UE?9&AJ;W=Y<6EE8UQ%+AT*\-G)NJ^GGYB2BXB-DI:;HJV[QM3I`1HP M/TQ98VQS=7)P;FEF85-%.B4+]-[*N["HH)>0CHR-CY.;I*RUP-'H`!79R;6AE7U9-0"D.^N3,O;.HGI:2D8^.D)28G:>SP=/F_!S4PK>MH)22E)&0DI.6G:6POLW@_!0C+T!48FMQ=7=W;VAH M95U00C(:_^O9QK2HH)N5CXZ1E)24EY^JN MT<&QIYZ5D(^0D)"2F*&KN,G9ZO\4)3=-86YSWEP;&I>2C@K&@3OVL2SI9V;F92/ MC(V0DYBDLK[-X/(%'C=(56!I<7)O6D8Z, MCI>DK[G'WO4)'3-&4UQC9FQV?'MXG_&31*5U]D:FYR='5W=6M>4D[LJB>EI.0C8N-DIFCK;7" MU>?\&#)#4F!I;&QQ=W5R;FID64LZ)Q+YW\NZKJ:AGYJ1C(R,C9*=J;?$TN@# M&2D[35998W)^?WMY_KZ:I*ZZR^7_&#)" M25=C8F1N=7EY=&MC6DHW)Q?]X=+'N*NCG)2.BXR.D9>>IK"\R-OX$B=I*RVP]7L`QPU2%):9W-V<&UN;FUI M9%M+-B`([]G(P+BLGY:1CXZ,BY"7H*RYQ-7O!A4E-DQ@;71U[8Q+6FG)B3CY"1DI26FZ2PO<_D^Q8K.4I;86-KS: MRKNMHIJ6DH^/CX^4G*:QO=#H^@D=,D)6:&YO<6]N<&QF8%I00B\9!?/=QK6L MHYN9F9:0CY*3EI^MOM'D]PPA,T%,5V5N,D116F!E:FYU>G9M95Q-.RH<"_GHUL.RIIZ:EI", MCY*5G*6NN<33Z``3*D=97&%I;6YK9VIN:%Y52#@C#?OFSK^VK:6@FY>3CXN/ MF**MN,35ZO\3*3U+5F-H:6QP3CXV0EZ"K MN,//X_L1)SU.6%M@:W%R1C8R.E9^KML#+WO@0 M(2\^46%H:W!U=FYD6U--3$DZ'@#KW,NYKJFDGYJ4CY"4F9VBJ[K/Y/<,'S)$ M35%=;GAY=FYE75I73#\T)Q+WV\:ZM:^CF965EI64E)FBK+G'V?85*#4\0DY@ M:W%V=6]L:5U334,R(`OTY=?&N*ZCFY61D9*4F)ZBJ;7&V_,'%R@Z2UAA;75W M=&QC75Q<54DY(PW[ZM7$N:VCFY:4EIB7EIB=I;+$V>X%&BHW1U5>:&]Q<6QF M9FA@440V)Q+ZY]O/O:RCGYN5DY25DY6=J+/`UO,)%2`P0%!>:'!U<6MJ:V18 M3T:&UM:VAD96AE6$0R M)1D'\MW-P;:HFY:7F9J8DY*8I+/!S^/[$2(P/4M>:VUH9VYO:F5@5D@U(1,( M^NK9QK&BG9^?F).3E9B=I;"_T>/S`1$J0U9?8&)J;69E:&1=5T@T)!<-`NK/ MOK:LHYV:F9B5E9::I+/!S=GI`1PP0%!=9FEE865J;6YE44([+QX+^>C8R+BM MI:&=FYB1C).?J;&]RMGL_@XC/E)<8&-E:&UN:61;4DD]+!T2!O+4EYB_>J;.ZQ-'C^1`F/4]87%M=:'-T;6=A54<]-"H:!?+@S+VUKZFBF9.3E)>? MJ+&YPL_?\PLE/$A-5V-G:6]P:F!53TU$.3`A"O+;HJRV MP,W?]0HA-T%&359E<7-O;&1634E"/#,?#/K@RL*\LJFCG)>6EI:;I*RRNLG= M\08>,SU&4%ME:VUP;6)74$I(0C`?$?G@T\F]LZVFG9>3E)J?HJBSO<;6[P<9 M*#9$3UIE;'%P9EM644Q)13HF#_KGULB_N*^DG9J8FIRMM<7;\P@8)3,_ M2%5C;71R:&%:4D]+/S,F%`#PX,_!N*RBG9N:FY^@H*2JM,/4ZP09)3`\2%5B M:6UM9V%=6%%+0S4C$/[RZ]K&N:^CG)J:G)^AHJ2HL<#2Z@$0'S`[1E5A96IL M9V%<55=81"XB$P3Z[-K,OJ^DGIJ9G:&BHJ&EL\32X?,)("TU1EID:6AC8&!@ M7UQ1034H%@;XZ^#1OZZEH9V?H9V:G:2JLKW-Y/H)$R(W2UA=8VAE9&5A6UA4 M2SPF$@D"]^;/O;.LI:">G9^AGZ"HLL'3W^P`$R0X2U1;8V9E9&)@85]51#,G M'Q,#\N+0P[>IH*"BHI^;G**IL;[-V^S_$2(T1E9A95];7V=I9%M01CTN&0L% M^NG7Q+2MJ:6AG9R3U!QPU2%5=75MD9U]:7EU523DI)!D%].31 MPK>OJZBCH)Z;FIZGL\',UN3R!1XP/4]965UF96!@7E9.13HN(Q@*^^C0P+FR MJZ>EHI^ MGJ.JL+O*U-KG`!PP.D-.5EU@8&5H74]+1SPT,281^^C:S<*XLJ^LI9^>H*.J ML[K!RMOU"A0A,T%)45A>9FIE7%)'0D$],B(2!?3>S<.\MJ^II**BI*>JK;6^ MRMON`18J-CU"2E5?9FEG7%%+13XY+R(4!._?U,G`MZVHI:*AI:JLL+6[QM;I M`!6%%+2DI#,1\3!O3EVL_&N[&KI:&FJZNJJK*^R=7I_@X=*S9` M2U-<8V-;5%143D8[,",4!/?NXM7*NZRFIJBIJZRKL+6XPM3H_`H9*3=#3UA; M5U596U=034Y&,A\/`??PYM?)O+2NJ*2DJ*NMKK7`R='?\@02(#5)45-:7U=. M3E!36%%"-RD3`OCLX=?,PK>NK:RII:*DJ[6_R]OG\?T*&"L\3%MD7U135E!* M24<]-BX>#@'RW]#%N[.PL;&PJZ:FJ:ZVP];G]0(-&BT]1$U75U9865A43TE` M,"(:$P?WZMC&O+:RKJZOK*>GJ["ZR-/=[/P,'3$_1TU14%!76EA75$IKK6^QL_;ZO8%&B\^2E)245185U943D=!.2XB%PS^ MZ=/&P;ZYM+.PJZBGJ;*]QLW:[?L('C(\049+4%576U]=4D,V+RPF&P[]Z]S. MP+JXM;&MJ:JNL+2]P\C3X/,-(R\Z1$=$2%)965A744<_-RLA&@[YYMK3R\.Z MLZ^KJJJKL+>]P\G3X.\&'BXU/$9,35%765A324`[/#DL'`[ZX];0R\.]NK2L MIZFNL;2YP,G6Y/4(&B8O.D%$35EA7U5*1D([-S8O(A']Z]_4R<"\M[*RL:^P MLK>ZN\'.X?@.'2DS.#M!2E!66EM73$`_0#@I&`G\\.3;UL`%B@Q-C]-5%974DI'1DE-1CDP(0KWZ=_;ULO"O+*LL+"LK[>[OL// MXOD(#AK9S\K!NK6PK[2WM[2QM,'0W_0* M%!LG,#=!3%%35%)/24=(0C0H'1#_\N_IVLJ_M:VML;.UMK2VO,/+V.T`#![DV\_"NK6UM+.RL;"SN\73Y?+[!0\9*#E) M5E=22TA(1T5$0SPQ)!<+_N_BUYM[6SLK.YP,3,V>;O^@D9*SU*3$=#0D-+44U) M0SLR)Q@/"/WKV[O;_$S]OE^`\@*"DO-SD]25!23T<^.C8Q*R@@$0'QY-S6SL7` MNK2WO+N[P,3'S-7C]@<7)S$P,SU$1DI+2$4_.C@V-"P=#`#RX]S:T';T<>_N[NYN<#" MP+_"Q]+E^@D7("8M,#4_1TQ.24)`/3@T+24<$`7\\N?=U,BYL;6_P\/!P<+! MQ-#?[P(6)2PM+SI%1$!!0D-$0S\[,B48"_SS\_+FU[@T_?T?U!!`;(RDV04%"2$8Z,2LG+#(M(AH0`?/MZN38S3>TL.ZN\#&R\S+R\G+ MU^?U`0X;(BG?U,?#QL;&R,;!PL?2X>OR_P<%#B`N M.TE)03LV,C,T+RDD'1D2!P($`>_9RLC*QL7)R<3!PL?2WNCU```"#R$S041" M/SLU,30U+RPI&PP-$P\$]NG>U&QH4$P\#^.S:T<_*RL[+P;V_PT]#-R\O%P<+`Q-/9UMSEZO0%%"0X.C0T-3@^04`\+R(:%A<9 M&1,,_NOAW=?3S<*]P,#`R]C:UMCSHY-O5TL>\N+K!RM#6V]S:XO(!$"0R,R\P.$%%0CTU*1X9&2$B&A(+^>CC MY.3S;RK^ZNL') MS<_.SM+9Y?,"$1<8'S`_1DE)034I(B,F*2DF'`X!^/7V\>37S<2]O\?,S,G% MQG6Q+V^P,7-T76QL#`P\C+R,;%PL;6[?G^ M!`8-'"X[2$]'.3$J)RDM+BD@$0@+"?[Y].?5QL+%RL[*Q+VZO\S=[??^!`4* M%R@Z1TM(/SO9S)RDA%`?]]_'K MY=[0O[>YNK[)TM+,Q\G7ZOL,'"4K,#,Y0D4_.#$G)2@L+2@?%P?V\/#Q[.'2 MQ;VYNL#%Q\?)SM;=Z/P0%Q<<*3=!1DE)03`B(B0B)BPJ'`K^_/?LX-?/R+^[ MP\O*Q\2_O\K<]`@-$AXB(RTZ0TM)/34N(R8P*Q\;%P\'`?SW[MO&N[R^P,K3 MSL/!Q#-P;_!P\3%PL'$ MR='=[OP"!0X=*C1"3DH\,R\I)2DM+2H>$@X,!?GOYMC)Q,7'R[Y M!A0A+SQ"0#DQ*BPS.#@Q*20;#`0'"@7[[^'0QZ.WN\P4> M,3]+2STT,"LG*2XR,2L@%1(0!OOPX]G6U]#(Q\.[M[B]Q]?EZ^_U^P,2)39! M0T`^.C,O,C$J(1P;'A\:#P'SY=;/SLS,R\?"O+J\Q=/#6RLC)Q<&^OL#%S=/7W./K]00<,3U`.3,W.30S M,RTH*"8D(1L5$0/NXMS:W=C*P\.]M[C`R=#8X^GK]@P<(RLS-SU`/3L].2TA M&APA)28A$P#S[.'6S\[/RL*_N[S%R\K-U>'Q!`\4'RXU-#4Y/3]`.B\E'QX? M'QX<&`KV[.?=TLS(P+W`P\7'QLG0U]GA]PX=*3(V-S0S.C\X,#$Q)B$D)R09 M!_SZ\>7BXMC'O+N[N;[(R\S0T]OJ]P$0(RLO-CH\0$$Y,2PD(2HL)"`<$@;[ M\.GCV=#+P[NZP<7%Q,7*T=GF]@85'R4N.#HX/#XX,R\L+"%Q$&^O7PW\S$Q,;%P[^\ MP,7$Q]3C\OX(#18C,T!#.S@[.#`M*RHM+"8B&0T(!_OHVM/,R,._P<7`N[W# MS-7A\/H`"ALH+SA`1$,Y+BPM+S$P+"+#<_0SXX-C4R,3`I(B$A'QH0!O_RW,W)RLC#P[W"1LC M*#$\/S@Q-#DV-#$K)R0B(AT2!?SSYM;-S,W)P+JXN+S#Q\W8XN_^!@P:*C0X M.#8X.ST\-"#_[QY-G1R<7$P\"^O\"]O3R!A@D*R\R-#8X M-S8W.#4O)B`A)!X6#P+TZ^+5S,7`P;^YN;_'S,O,UN/O`18C*C(U-34S-3HZ M-C$L*BPK(A@2"P/YZ^#;US\.^N[N^P<#"QL7(T=WK_@X:)"PQ-CDW-CDV-#0Q+RPI)B$8 M"@'_^>O=TLW&NK2XO<##Q<;+T=WN^@,1'RHS.3L]/#DT,"PH+C@W*R(<$@3U M[.WGV=#)P+R[N[R\N\',V>3N^P8-%1\I,S]&1#DS-3,L)B8N-"T?$PK_]>SB MULW%P<7#NKG`P<#&S]ON_0()%R,J,CL_/#@V-3$N+C`R+2`8%@\$^^_CV\_$ MP;ZYO'AL1`?;QW\K&R,;%P[VYNK[%SM;< MYO8$#A4>+#H]-2\R/#\W,"XH)R8A&QD5#/_KUWT`!4E*2PO M,#,Y/3PW+BOW``L8("$D+#4W-C;U`0D0%!DF,3$M+2\M)2`E*RXI'A41 M"?_\_//DV]7,QLC.TM'-RL_9X>CT_@$%$!LB*2\V-RP?'2(E*"HF(!H1"03] M^//IW=+,S-+2T,_-S,_7X.OU_0$$"A0@*S,T+R@C(R,A)"@F'QD5#@)RTM*2&101$@\&_?7KX-G6V=O9 MU=+0T]C>XN?O]?K_!A(@)R(!\>'R$>%A$4%Q@7%0\'_O?Q[>GHY^3@W=S>X>/CY.;K\/;^!PT1 M%A84%QXA(1\;%Q43$A,5%`X&`/GT\O#JYN+>WN'CX^7FYN?I[//_"`T/$1,6 M&1L;'!P9%105%185$0H#_?KY]_+LY^/AX>'BY>CGYNCL\/?^`@<,#@\3&1P< M&QH6$A`2%!84$`P&`?SX]?/NZ.7DY.7HZ.;GY^CJ\/D`!`8)#0X1%1@;&Q@4 M$A,3$A,2#0@%`P#]^?3MZ>;EY>?JZ^KIZ.GM\O?[`04("PX3%A86%A01#Q(5 M%1,0#`@$`/[]^_CR[.GHZ.GK[.KIZ^WO\OC]_P`#"`T3%185%!$/#A`1$1(1 M#0@#`0'^^O;R[NWL[.WN[.KJZ^WR]OK]_@`#!@H.$104$A`/$`\/#PT+"0@' M!0+^_/GR[>SM[_#P[^_N[>[R]??Z_@($!PL/$`\-#0X.#@\1$`T*!P4#`P(! M_?CU\_#O[_#P\._O\?/T]_KY^OX"!@H-#@\.#`L+#0T,#0T*!P<&`P'__?GV M]//S\_/Q\?'Q\O3V^/K[_?\``P<*"PL,#`L+#`L*"0@'!P<&!0(`_?GW]?7U M]?7V]//S]/7V^/K[_?\!!`8("`@("0D+"PL)"`<&!00$`P,!_OOY^/?V]O;U M]O;V]_?Y^OK[_/T`!`8'!P@'!P<'!P@'!P8%!00$`P'__?S[^_KY^?CX]_?W M^/K[^_O\_?\``0,$!04&!@8&!@4%!`,$!`0#`@$`_OW\_/S[^_OZ^OKZ^OK[ M_/W]_O\``0("`@,#`P0$!`,#`P("`@("`0$`__[^_?W]_/S\_/W]_?W]_?W^ M_O\```$!`0$!`0$!`0$!`0$!`0$```#___________________________\` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````!#3TU-````$@`! M```T%@`(0`VL1````````$U!4DL````"``!)3E-4````%#P``'\`?P`````` M````````````05!03````:A39#)A``(````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`H`````````````````````````````````````````````````````````` M```````````````````````$"```````"0`C`````````````````'@````$ M``0```````#\`/___X`````!`0`&455N:71S```````````````````````` M`````````````````0(`!B!S86UP````%;_^?_[__S_^__\__S__/_]__W__?____X````"``$``P5& M;'5T90(```!!249&4V0R80`````````````2J0````!!249&4V0R80`````` M`````````````````````````*<]K;```#8B```!S@"*`(``@0!T`&$`5P!' M`#X`-P`U`"X`'P`A`!``#``5`!<`'0`8`"(`*0`P`#,`-`!"`$@`/P!#`$4` M0``R`"X`-@`F`"``)@`<`"``)0`B`"(`(@`@`"D`,``D`!X`&0`-``;__O_V M__W_^O_S__;_^@`&``T`#P`8`"(`*0`O`#H````:`"D`#P)J`S$`*@`#`FT# M/0`I``\"00,B`0`````:`"D`#P%0`?$`*@`#`FT#/0`````````````````: M`"P`%@$^`=P`*@`#`FT#/0`````````````````:```````````````````` M``````````````````$````!>````'@```!6`'&XO!RF````'`!6``!7```````#__\````\```````$__\` M``!:```````````````````````````````````````````````````````` ,```````````````` ` end nethack-3.4.3/sys/share/sounds/wdnharp.uu0100644000000000000000000004164207764735041017132 0ustar rootrootbegin 644 Wooden_Harp M``M7;V]D96X@2&%R<``````````````````````````````````````````` M``````````````````````````!!249&4V0R80$``$X`10```````"XB```! MSJ<]K8^G/:V7``````````````````````````````"!@<\@``!&3U)-```N M&D%)1D934TY$```L'@`````````````````````````````````````````` M````````````````````````````````````````____________________ M________________________________________````````````_____P`` M`````````````````````/_________________^_O[^_?KX^/T!`O_[\-[, MP;R\OL"\L:>OQ=37S\6]M[2VN\''S=/8WN/GZ^_Q]/D`"A8B+SM$2U%776%E M:6UOX./H[?7_"10>)RXS.#Q`1$A+3E%25%9865I; M7%Q=75Q;6E9/.Q+Q[/+[!`P3&A\A(!T8$@G^Z\.:BX^6GZBOM[N]O+JWM;2U MN+O`Q,C+SM'4U]G;W=_BY^SU_P@2&R$G+#`T.#P_0D1'24I,3D]045)34U-1 M3TL_)@/NZ^WQ^/\&#A08&AD6$0G^ZLBEE)*4F)ZEK+*WNKN[N[N\O\+%R,O. MT-+5U]G;W-W@X^CO]P`)$1D?(RWM[_+W M_0,)#A$2$`L!\=K!K:6BH*"AHZBML[B]P<7(S-#2U=?9VMKFIJ>KL+6[P<;,T-38V]W>W]_@X>'BXN/DY>?J[_3[`PD0 M%AH>(20G*2PN,#(T-C;FY^GK[_3Y_P8,$A<;'R$D M)B@K+2\Q,C0V-SDZ.CDV,"<;#0'X]//S\_3U]OG]`@<+#`L'_O'BTL6]M[6S ML;"PL+.XO<3,TMC>XN7GZ.CHZ.CHZ>GIZ>OL[_/X_0,)#Q49'!\A)"8H*BPN M,#(T-3KM[_#P\/#P[^_O[_#P\O3X_`$&#!$6&AT@(B0F*"HL+C`R,S4U-3,P*B,: M$0D"_?OZ^OO\_?[_`00'"@L*!@#W[>+8T,K&P\+!P+^_P<3*T-??Y>OO\?/S M\_/S\O+R\O+R]/7X_``%"A`4&!P?(2,E)RHL+C`R,S0T-#(N*2(;$@L%`/W\ M_/W_``$"`P4'"0L+"`/\\^G@U]',R,;%Q<3$Q("(E)RDK+2\Q,C,S,S$M*"(;$PT'`O_^_O\``0(# M!`4'"0H*"07_]^[FW=;1S?L\?3V]_CX^/CW]_?W]_CY^_X!!0H/ M$Q<;'R$C)B@J+"XO,3(Q,2\K)B(;%0\*!@,!``$"!`8'"`@)"@L+"@@$__CP MZ>+;K\/3V^/GY^?GY^?GY^?GZ_/X!!0D-$A8:'B$C M)2@J+"XO,3$Q,"XK)R(<%A`,"`0#`@($!0<)"@H+"PP,"PH'`OSU[N?AV]?4 MTM'1TM/5U]G=X>;J[_/V^/GZ^OKZ^OKZ^OK[_/X!!`@,$!49'2`C)B@J+"XO M,#$Q,"XK)B$<%Q$-"08$`P,$!@@*"PP,#`T-#`L(!/_Y\NSFX-O7U=/3U-77 MV=O>X>7I[?'U]_GZ^OO[^_KZ^OO[_/X``P8*#Q,7&Q\B)2VMC7U]?9V][AX^;I[._R]/;X M^?KZ^OKZ^OO[_/W^`00'"@X3%QL?(B4G*2LL+"TL*RDF(Q\:%A(."@<%!`0$ M!@@*#`X/#P\.#0P*!P/_^O7PZN;BWMO9V=G;W=_BY>?J[.[P\O3V]_?X^?GY M^?KZ^_S]``,%"0T1%1D=(20F*"DJ*RLJ*2_Q\O/T]?;W^/CX^?GZ^_S] M_P(%"`P0%!@<(",F*"DI*BDH)R4B'QP8%1$."PD'!@4&!P@+#0\1$A(1$`X, M"08#__KV\>WIY>+@WMW>W^'DY^KL[O#Q\O/T]/7V]_?X^/GY^OO]_P$$!PL/ M$Q<;'R(D)B&Q@5$0\,"0<&!00$!08("@T/$!$1$1`.#`D&`__\^/3P[.GFY.+AX>+D MYNGL[O#R\_/S\_/T]/3U]O?W^/K[_/X!!`8)#1$5&!P>(2,C(R,B(1\=&A<4 M$0X+"0<%!`0$!`4'"0P.$!$2$1`/#0H(!`'^^O;S[^OIYN3CX^/DYNGL[O#R M\_3T]/3T]/3U]O?W^/G[_/X``@4)#`\3%AD='R$B(B(A(!X<&1<4$0X+"0<% M!`,#!`4&"`L-#Q`1$1$/#@L)!@,`_/CU\>WKZ.;EY.3DYNCK[?#R\_3T]/3T M]/3U]?;W^/GZ_/W_`@0'"@X1%!<:'1\@(2$@'QT;&!83$`T*"`8$`P("`@,% M!PD+#@\0$1`0#@P*!P0!_?KV\^_LZNCFY>3EYN?I[._Q\O/T]/3T]/3T]?7V M]_CY^_S^``(%"`L/$A48&AP>'Q\>'1L9%Q01#PP)!P4#`@$!`0(#!0<)#`X/ M$!`/#@P*!P0"_OOX]/'MZ^GGYN7EY>?IZ^WO\?/S]/3S\_/S]/3U]O?X^OO] M_P$#!@D,#Q(5&!H<'1T='!H8%A,0#@L(!@0"`0`````"`P4("@P.#P\/#@P* M"`8#`/WY]O+O[.KHY^;EY>;HZNSN\/+S]/3T\_/S]/3U]O?X^?O\_@`"!0@* M#1`3%A@:&QL;&AD7%1(/#0H'!0,!`/___P`!`@0'"0L-#@\.#@T+"0<$`?[[ M^/7Q[NSJZ.?FYN?HZNSN\/+S]/3T]/3T]/3U]O?X^?K\_@`"!`<*#`\2%!88 M&AH:&A@7%1(0#0H(!0,!`/_^_O\``0,%"`H,#0X.#@T,"@@%`P#]^?;S\.WK MZ>CGY^?HZ>OM[_'S]/3T]/3T]/3U]O?X^?K[_?\!`P4("PX0$Q46&!D9&1@6 M%!(/#`D'!`(`__[]_?[_``($!@D+#`T.#@T,"@@&!`'^^_CU\N_MZ^GHZ.?H MZ>KL[O#R\_3T]/3T]/3T]?;W^/G[_/X``@0&"0P.$1,4%A<7%Q85$Q$."P@& M`P'__OW\_/S]_@`"!0<)"PP-#0P+"@D&!`+_^_GV\O#MZ^KIZ.CHZ.KK[>_Q M\O/T]/3T\_3T]/7V]_CZ^_W_`0,%!PH,#A`2%!45%144$@\-"P@%`P'__?S[ M^_O\_?\!`P4'"0L,#`P+"@D'!0,`_?KW]/'O[>OIZ.CHZ.GK[.[P\?/S]/3T M]/3T]/7V]_CY^_S^``($!@@+#0\1$A,4%!03$0\-"@<%`@#^_?S[^_O[_/X` M`@0&"`H+#`P+"@D(!@0!__SY]O/P[NSKZNGIZ>KK[.[O\?+S]/3T]/3T]?7V M]_CY^_S^``($!@@*#`X0$1,3$Q,2$0\-"@@%`P#^_?S[^OK[_/W_`0,&"`D+ M#`P,"PH)!P4"`/[[^/7R\.[LZ^KJZNKK[.WO\?+S]/3U]?7U]?;V]_CY^_S^ M_P$#!0<)"PT/$!$2$A(2$`\-"@<%`@#^_?OZ^OKZ^_S^``(%!PD*"PP+"PH) M"`8$`?_\^??T\>_M[.OJZNKK[.WN\/'S]/3U]?7U]?;V]_CY^OS]_P`"!`8( M"@P-#Q`1$1$0#PX,"@<$`@#^_/OZ^?GY^OO]_P$#!0<)"@H+"PH)"`8$`@#] M^O?U\_#N[>OJZNKKZ^SN[_#R\_3T]?7U]?7V]O?X^OO\_O\!`P4'"0H,#0X/ M$!`/#@T+"08$`O_]^_KY^/CX^?K\_?\"!`8'"0H*"@H)"`8%`P#^_/GV]/'O M[NSKZ^OKZ^SM[_#Q\O/T]/7U]?7V]O?X^?O\_?\!`@0&"`D+#`T.#P\.#0P+ M"08$`O_]^_KY^/CX^?G[_?X!`P4'"`D*"@H)"`<%!`+__?OX]?/Q[^WL[.OK M[.SM[_#Q\O/T]?7U]O;V]_CX^OO\_O\!`@0&!PD*#`T-#@X.#0P+"0<$`@#^ M_/KY^/CX^?G[_/X``@0&"`D*"@H*"0@'!0,!__SZ^/7S\>_N[>WM[>WN[_#Q M\O/T]?;V]O?W^/CY^OO\_O\!`@0%!P@*"PP-#0T-#0P*"0<$`@#^_/OY^/CX M^/GZ_/W_`0,%!P@)"@H*"0@'!@0"`/[[^??T\O'O[N[M[>WN[_#Q\O/T]?;V M]_?W^/CY^OO\_O\``@,%!@@)"@L,#`T,#`L*"`8$`@#^_/KY^/CX^/GZ^_S^ M``($!@<("0D)"0@'!@4#`?_]^OCV]/+P[^[N[>[N[^_P\?/T]?7V]_?W^/CY M^OO\_?X``0,$!0<("0H+"PL+"PH)!P8$`@#^_/KY^/?W]_CY^OO]_P$#!08' M"`D)"0@'!@4#`@#]^_GW]?/Q\._N[N[N[^_P\?+S]/7V]O?W^/CY^OO\_?[_ M`0(#!08'"`D*"@L+"@D(!P4$`@#^_/KY^/?W]_CX^OO]_@`"!`4'"`@)"0@( M!P8$`P'__?OX]O3S\?#O[^_O[_#P\?+S]/7V]_?X^/GY^OO\_?[_`0($!08' M"`D*"@H*"@D(!P4$`@#^_/OY^/CW]_CY^OO\_@`"!`4'"`@)"0D("`<%!`(` M_OSZ^/;U\_+Q\/#P\/#Q\O/T]?;V]_CY^?KZ^_S\_?\``0($!08'"`D*"@H* M"@D(!P8$`@'__?OZ^?CX^/CY^OO\_@`!`P4&!P@)"0D)"`<&!0,"`/[\^OCV M]//R\?'Q\?'Q\O/T]?;V]_CY^?K[^_S]_O\``0($!08'"`D)"@H*"0D(!P4$ M`@'__?SZ^?CX^/CX^?K\_?\!`@0%!P@("0D)"`<'!@0"`?_]^_GW]O3S\O'Q M\?'Q\O/S]/7V]_CY^?KZ^_S\_?[_`0(#!`4&!P@("0D)"`@'!@4#`@#^_?OZ M^?CW]_?X^?K[_/X``0,$!@<'"`@("`<'!@0#`0#^_/KX]O7T\_+Q\?'R\O/S M]/7V]_CX^?KZ^_S\_?[_``$#!`4&!P<("`@("`<&!@0#`@#^_?OZ^?CX]_?X M^/GZ_/W_`0($!08'"`@("`@'!@4$`@'__?OY^/;U]//R\O+R\O/S]/7V]_CX M^?K[^_S]_O[_``$#!`4&!@<("`@("`<&!00#`@#__?S[^OGX^/CX^?GZ_/W_ M``(#!08'!P@("`@(!P8%!`(`__W[^OCW]?3T\_/S\_3T]?;V]_CY^OO\_/W^ M_O\``0(#!`4&!P<("`@("`<'!@4#`@'__OS[^OGY^/CX^?K[_/W_``(#!08' M!P@("`@("`<&!0,"`/[]^_KX]_;U]/3T]/3U]?;W^/CY^OO\_?W^__\``0(# M!`4&!P<("`@("`<'!@4#`@'__OW[^_KY^/CY^?KZ_/W^``$#!`4&!P@("`@( M"`<&!00#`?_^_/OY^/?V]?7T]/7U]?;W]_CY^OO\_/W^__\``0(#!`4%!@<' M"`@(!P<&!00#`@#__OS[^OGY^/CX^?GZ^_S]_P`"`P0%!@<'"`@(!P<&!00# M`@#^_?OZ^/?V]O7U]?7U]?;V]_CY^?K[_/W^_O\``0$"`P0%!@8'!P<'!P8& M!00#`0#__?S[^OGY^/CX^/GZ^_S]_@`!`@0%!08'!P<'!P<&!@4$`@'__OS[ M^OCW]_;U]?7U]O;W]_CY^OK[_/W^__\``0("`P0%!@8'!P<'!P8&!00#`0#_ M_OW[^_KY^?CX^?GZ^_S]_O\!`@,$!08'!P<'!P<'!@4$`P(!__[\^_KY^/?W M]O;V]O?W^/CY^OO\_?[^_P`!`0(#!`0%!@8'!P<'!P<&!00#`@$`_OW\^_KZ M^?GY^?KZ^_S]_O\!`@,$!08'!P@("`@'!P8%!`,"`?_^_/OZ^?CX]_?W]_?X M^/GZ^OO\_?[__P`!`@(#!`4%!@<'!P<'!P<&!00#`@$`__[\_/OZ^OGY^?KZ M^_S]_O\``@,$!08&!P<("`@(!P<&!00#`0#__?S[^OGX^/CX^/CX^/GZ^OO\ M_?[__P`!`@(#!`0%!@8'!P<'!P8&!00#`@$`__W\^_OZ^OGY^?KZ^_O\_?X` M`0(#!`4%!@<'!P<'!P8&!00#`@#__OW[^OKY^/CX^/CX^/GY^OO[_/W^_P`! M`0(#`P0%!08&!@<&!@8%!00#`@#__OW\^_OZ^?GY^?GZ^OO\_?[_``$"`P0% M!08&!P<'!P8&!00#`@$`__W\^_KY^?CX^/CX^/GY^OO[_/W^_P`!`0(#`P0% M!08&!@8&!@8%!00#`@$`_OW\_/OZ^OGY^?GZ^OO\_?[_``$"`P0$!08&!P<' M!P<&!@4$`P(!`/[]_/OZ^OGY^?GY^?GZ^OO\_/W^_P`!`@(#!`0%!@8&!P<' M!P8&!00#`@$`__[]_/O[^OKZ^OKZ^_O\_?[_``$"`P0$!08&!P<'!P<'!@8% M!`,"`0#__OS\^_KZ^OGY^OKZ^_O\_?[__P`!`@,#!`4%!@8'!P<'!P8&!00$ M`P(`__[^_?S[^_OZ^OO[^_S\_?[_``$"`P,$!08&!@<'!P<'!@8%!00#`@#_ M_OW\_/O[^OKZ^OK[^_O\_?[^_P`!`@,#!`4%!@8&!P<'!P8&!00#`P(`___^ M_?S[^_OZ^OK[^_O\_?[^_P`!`@,$!`4%!@8&!P<&!@8%!`0#`@$`__[]_/O[ M^OKZ^OKZ^_O\_/W^_P```0(#`P0%!08&!@8&!@8%!00#`@$`__[]_/S[^_KZ M^OKZ^_O\_/W^__\``0(#`P0%!04&!@8&!@8%!00#`@$`__[]_/S[^_KZ^OKZ M^_O[_/W^_O\``0("`P0$!04&!@8&!@8%!00#`@$`__[^_?S[^_OZ^OKZ^_O\ M_/W^_O\``0("`P0$!04&!@8&!@8%!00#`P(!`/_^_?S\^_O[^_O[^_O\_/W^ M__\``0(#`P0$!04&!@8&!@8%!00#`P(!`/_^_?W\_/O[^_O[^_S\_?W^__\` M`0("`P0$!04&!@8&!@8&!04$`P,"`0#__OW]_/S\^_O\_/S\_?W^_P```0(# M!`0%!08&!@8&!@8&!04$`P(!`/___OW\_/S[^_O[_/S\_?W^__\``0("`P0$ M!04&!@8&!@8&!@4%!`,"`0$`__[^_?S\_/S\_/S]_?[^_P```0(#`P0%!08& M!@8&!@8&!04$`P(!``#__OW]_/S\^_O\_/S\_?W^__\``0$"`@,$!`4%!08& M!@8&!@4%!`,#`@$`__[^_?W\_/S\_/S\_?W^_O\``0$"`P,$!04%!@8&!@4% M!00#`P(!`/_^_OW\_/S[^_O[^_S\_/W]_O__```!`@(#`P0$!04%!04%!04$ M!`,"`@$`___^_?W\_/S\_/S\_/W]_O__``$"`@,$!`4%!04%!04%!`0#`P(! M`/_^_OW\_/S[^_O[^_S\_/W]_O[_```!`0("`P,$!`4%!04%!04%!`,#`@$! M`/_^_OW]_/S\_/S\_?W^_O__``$!`@,#!`0%!04%!04%!`0#`P(!``#__OW] M_/S\_/S\_/S\_?W^_O__```!`0(#`P0$!`4%!04&!04%!00$`P(!`0#___[^ M_?W]_?W]_?[^__\```$"`@,$!`4%!08&!@4%!00$`P("`0#___[]_?W\_/S\ M_/S]_?W^_O__```!`0("`P,$!`4%!04&!@4%!00$`P,"`0$`___^_O[]_?W] M_O[^__\```$"`@,$!`4%!08&!@4%!00$`P,"`0``__[^_?W]_/S\_/W]_?W^ M_O__```!`0("`P,#!`0%!04%!04%!04$!`,"`@$``/_^_O[]_?W]_?[^_O__ M``$!`@,#!`0$!04%!04%!`0#`P(!`0#___[]_?S\_/S\_/S\_?W]_O[__P`` M``$!`@(#`P,$!`0$!04%!`0$`P,"`0$``/_^_O[]_?W]_?W^_O[__P`!`0(" M`P0$!`0%!00$!`0#`P(!`0#__O[]_?S\_/S\_/S\_/W]_?[^__\```$!`0(" M`P,#!`0$!`0$!`0$`P,"`@$!`/___O[^_?W]_?W^_O[__P```0("`P,$!`0$ M!00$!`0#`P(!`0#___[^_?W\_/S\_/S\_?W]_O[^__\````!`0("`P,#!`0$ M!`4%!`0$!`,#`@(!`0``___^_O[^_O[^_O__```!`0(#`P0$!`4%!04%!`0$ M`P,"`0$`___^_OW]_?W]_?W]_?W^_O[___\```$!`@("`P,#!`0$!04%!04$ M!`0#`P("`0$``/____[^_O[_____```!`0(#`P0$!`4%!04%!`0$`P,"`0$` M`/_^_O[]_?W]_?W]_?W^_O[___\```$!`0("`@,#`P0$!`0%!04$!`0#`P," M`0$```#______O[^____```!`0("`P,$!`0$!`0$!`0#`P("`0$`___^_OW] M_?W]_/W]_?W]_?[^_O___P```0$!`@("`P,#!`0$!`0$!`,#`P("`0$``/__ M__[^_O[^_O[__P````$!`@(#`P0$!`0$!`,#`P(!`0``__[^_OW]_?S\_/S\ M_?W]_?W^_O[__P`````!`0("`@,#`P,#!`0$`P,#`P("`0$``/_____^_O[^ M_O___P````$!`@(#`P,$!`0$`P,#`@(!`0``___^_OW]_?W\_/S]_?W]_?[^ M_O[___\````!`0$"`@(#`P,#!`0$!`,#`P("`@$!````_____________P`` M`0$"`@(#`P0$!`0$!`0#`P("`0$``/___O[^_?W]_?W]_?W]_O[^_____P`` M``$!`0("`@,#`P,$!`0$!`0$`P,#`@(!`0$```#_________`````0$"`@,# M`P0$!`0$!`0#`P,"`@$!``#___[^_OW]_?W]_?[^_O[^_____P````$!`0$" M`@(#`P,#!`0$!`0$`P,#`@("`0$`````________`````0$!`@(#`P,$!`0$ M!`0#`P,"`@$!``#___[^_OW]_?W]_?W^_O[^_O[___\``````0$!`0("`@(# M`P,#`P,#`P,"`@(!`0$```#___________\````!`0("`@,#`P,#`P,#`@(" M`0$``/___O[^_?W]_?W]_?W]_?W^_O[^_____P`````!`0$!`@("`@,#`P,# M`P("`@(!`0```/______________`````0$"`@(#`P,#`P,#`@("`0$``/__ M_O[^_?W]_?W]_?W]_?W^_O[^______\``````0$!`0("`@(#`P,#`P,"`@(! M`0$`````__________\````!`0$"`@(#`P,#`P,#`P("`0$!``#____^_O[^ M_?W]_?[^_O[^_O[_____```````!`0$!`@("`@,#`P,#`P,#`P("`@$!`0`` M````_P````````$!`0("`@,#`P,#`P,#`P,"`@$!````_____O[^_O[^_O[^ M_O[^_O______```````!`0$!`@("`@,#`P,#`P,#`P("`@(!`0$````````` M```````!`0("`@(#`P,#`P,#`P("`@$!````_____O[^_O[^_O[^_O[^_O[_ M_____P````````$!`0("`@("`@,#`P,"`@("`@$!`0````#_______\````` M`0$!`0("`@(#`@("`@("`0$```#____^_O[^_?W]_?W]_?[^_O[^_O[_____ M_P```````0$!`0$"`@("`@("`@("`0$!`````/___________P````$!`0$" M`@("`@("`@(!`0$```#___[^_O[^_?W]_?W]_O[^_O[^_O[_______\````` M``$!`0$"`@("`@("`@("`0$!`0````#__________P`````!`0$"`@("`@(" M`@("`0$!``#______O[^_O[^_O[^_O[^_O[_________```````!`0$!`0(" M`@("`@("`@("`@(!`0$!`````````````````0$!`0("`@("`@,"`@("`@$! M`0```/_____^_O[^_O[^_O[^_________P`````````!`0$!`0("`@("`@(" M`@("`@("`0$!`0$``````````````0$!`0("`@("`@("`@("`@$!`0```/__ M___^_O[^_O[^_O[^_O________\``````````0$!`0$"`@("`@("`@("`@(! M`0$!`0`````````````````!`0$!`0("`@("`@(!`0$!``#______O[^_O[^ M_O[^_O[^_O[^_O___________P````````$!`0$!`0("`@("`0$!`0$````` M`/________\```````$!`0$!`0$!`0$!`0$```#____^_O[^_O[^_O[^_O[^ M_O[^_O[^__________\```````$!`0$!`0$!`@(!`0$!`0$```````#_____ M__\```````$!`0$!`0$!`0$!`0$`````_____O[^_O[^_O[^_O[^_O[^_O[_ M_________P````````$!`0$!`@("`@("`@("`0$!`0$````````````````! M`0$!`0$"`@("`@(!`0$!`````/_______O[^_O[^_O[^____________```` M`````````0$!`0$"`@("`@("`@("`@(!`0$!`0````````````$!`0$!`0(" M`@("`@("`0$!`0````#________^_O[^_O[______________P`````````` M``$!`0$!`@("`@("`@("`@$!`0$!`0```````````````0$!`0$!`0$!`0$! M`0$!`````/_____^_O[^_O[^_O[^_O[^_O[^____________``````````$! M`0$!`0$!`0$!`0$!`0$```````````````````````$!`0$!`0$!``````#_ M______[^_O[^_O[^_O[^_O[^_O[^_O[___________\``````````0$!`0$! M`0$!`0$!`0````````````````````````$!`0$!`0$!`0````#_______[^ M_O[^_O[^_O[^_O[^_O[^_O____________\````````!`0$!`0$!`0$!`0$! M`0$!`0````````````````$!`0$!`0$!`0$!`0$!``````#________^__[^ M_O[^_________________P````````````$!`0$!`0$"`@("`@(!`0$!`0$! M`0`````````!`0$!`0$!`0$!`0$!`0$!`0``````____________________ M_____________P````````````$!`0$!`0$!`@("`0(!`0$!`0$!`0`````` M`````0$!`0$!`0$!`0$!`0$!``````#__________O[^_O[^_O[^________ M_____________P`````````!`0$!`0$!`0$!`0$!`0`````````````````` M`````0$!`0$`````````_______^_O[^_O[^_O[^_O[^_O[^_O[^_O______ M_________P`````````!`0$!`0$!`0$````````````````````````````` M`0``````````_________O[^_O[^_O[^_O[^_O[^_O[^________________ M_P`````````!`0$!`0$!`0$!`0$````````````````````!`0$!`0$!`0$` M````````________________________________________```````````` M`0$!`0$!`0$!`0$!`0$!`0$!`0```````0$!`0$!`0$!`0$!`0$!`0`````` M`/___________________________________P```````````````0$!`0$! M`0$!`0$!`0$!`0$!`0```````0$!`0$!`0$!`0$!`0$!`````````/______ M__________________________________\```````````````$!`0$!`0$! M`0```````````````````````````````````````/____________[^_O[^ M_O[^_O[^_O[^_O___________________P`````````````````````````` M````````````````````````````````______________[^_O[^_O[^_O[^ M_O[______________________P`````````````````````````````````` M``````````````````````````#_________________________________ M_____________P`````````````!`0$!`0$!`0$!`0$!``````````````$! M`0$!`0$!`0$!````````````__________________________________\` M`````````````````0$!`0$!`0$!`0$!`0$!`0$!`````````0$!`0$!`0$! M`0$`````````````______________________________________\````` M``````````````$!`0$!`0$!```````````````````````````````````` M`/_______________________________________________________P`` M``````````````````````````````````````````````````#_________ M______________[___________________________________\````````` M````````````````````````````````````````````________________ M____________________________________`````````````````0`!`0$! M`0``````````````````````````````````````````________________ M________________``````````````````````````$!`0$!`0$!`0$!`0$! M`0$``````````````````````````````````/______________________ M__________\```````````````````````````$!`0$!`0$````````````` M``````````````````````#_____________________________________ M__________________\````````````````````````````````````````` M`````````/__________________________________________________ M______________\````````````````````````````````````````````` M`/__________________________________________________________ M_P`````````````````````````````````````````````````````````` M`````/________________________________\````````````````````` M```````!`0$!`0$!`0$!`0$!`0`````````````````````````````````` M``#______________________P`````````````````````````````````` M``$!`0$!`0$!`0$```````````````````````````````#_____________ M________________________________________```````````````````` M``````````````````````````````#_____________________________ M______________________________________\````````````````````` M`````````````````````/______________________________________ M____________________________```````````````````````````````` M``````````````````````````#_________________________________ M````````````````0T]-30```!(``0``+!8`"$`-K$0```````!-05)+```` M`@``24Y35````!0\``!_`'\``````````````````$%04$P```&H4V0R80`" M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````/@```````````````````````````` M````````````````````````````````````````````````````!`@````` M``D`(P````````````````!X````!``$``````"[_`#___^``````0&H!E%5 M;FET````'@```!6`&X`9P!:`$L`.P`H M``W_Y_^W_W7_)/Z^_D+]M/TI_,8$2&%R<($"````04E&1E-D,F$````````` M````$J<`````04E&1E-D,F$```````````````````````````````"G/:V/ M```N(@``` file. If # the game plays slowly you might notice some improvement by setting # !time and !showexp, which will reduce screen I/O somewhat. # # To change the configuration, comment out the unwanted lines, and # uncomment the configuration you want. # # Note: For blind players, please use the file NHAccess.nh as a template. # # *** OPTIONS *** # # The three options on this line should be used for most setups. # If your machine isn't very IBM-compatible, and NetHack doesn't work, # try commenting out this line. OPTIONS=rawio,BIOS,IBMgraphics # To use VGA graphical tiles on an MS-DOS PC with VGA or better,uncomment # this: #OPTIONS=video:autodetect # Some versions of NetHack use the pc speaker to play the notes given when # playing music instruments in NetHack. To use this feature, if available, # uncomment the following line: #OPTIONS=soundcard:autodetect # If your machine is NEC PC-9800, use: #OPTIONS=rawio,BIOS,video:default # If you use an Atari and want tty use: #OPTIONS=windowtype:tty,rawio,BIOS # Some options to set personal preferences. Uncomment and change these to # suit your personal preference. If several people are to use the same # configuration, options like these should not be set. # #OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful #OPTIONS=dogname:Fido,catname:Morris,fruit:guava #OPTIONS=horsename:Silver #OPTIONS=autopickup,pickup_types:$"=/!?+ #OPTIONS=packorder:")[%?+/=!(*0_` #OPTIONS=scores:10 top/2 around/own #OPTIONS=nolegacy,noverbose #OPTIONS=menustyle:traditional # If you wish to change the symbol used to display boulders use: OPTIONS=boulder:0 # # General options. You might also set "silent" so as not to attract # the boss's attention. # # number_pad option can have an optional value of 0 (off), 1 (on), # or 2(on,legacy-mode) which causes 5='g', alt-5='G', alt-0='I' # OPTIONS=time,noshowexp,number_pad:2,lit_corridor # Treat space bar as rest. Warning: may be dangerous for new players. # OPTIONS=rest_on_space # # If you want to get rid of "use #quit to quit..." use: #OPTIONS=suppress_alert:3.3.1 # # # *** LOCATIONS *** # Some platforms allow you to change the location where various things are kept. # IMPORTANT: If you change any of these locations, the directories they # point at must exist. NetHack will not create them for you. # # The default location for everything. # Note: On Windows HACKDIR defaults to the location # of the NetHack.exe or NetHackw.exe file so # setting HACKDIR below to override that is # not usually necessary or recommended. #HACKDIR=c:\games\nethack # # The location that level files in progress are stored (default=HACKDIR, writeable) #LEVELDIR=c:\nethack\levels # # The location where saved games are kept (default=HACKDIR, writeable) #SAVEDIR=c:\nethack\save # # The location that bones files are kept (default=HACKDIR, writeable) #BONESDIR=c:\nethack\save # # The location that file synchronization locks are stored (default=HACKDIR, writeable) #LOCKDIR=c:\nethack\levels # # The location that a record of game aborts and self-diagnosed game problems # is kept (default=HACKDIR, writeable) #TROUBLEDIR=c:\nethack\trouble # # *** CHARACTER GRAPHICS *** # # See the on-line help or the Guidebook for which symbols are in which # positions. # # If you merely set the IBMgraphics option as above, NetHack will use IBM # extended ASCII for dungeon characters. If you don't like the selections, # you can make up your own via these graphics options, but you should still # set IBMgraphics if you are using IBM graphics characters to get the correct # processing. # # ================================================ # The defaults using the IBM graphics character set: #DUNGEON = 032 179 196 218 191 192 217 197 193 194 \ # 180 195 250 254 254 043 043 240 241 250 \ # 176 177 243 242 060 062 095 124 092 035 \ # 244 247 250 247 250 250 035 035 032 035 \ # 247 # # ================================================ # Some alternatives: #DUNGEON= 032 186 205 201 187 200 188 206 202 203 \ # 185 204 249 239 239 254 254 240 241 249 \ # 177 177 060 062 060 062 095 124 092 035 \ # 244 247 249 247 042 042 179 196 046 035 \ # 247 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 034 094 094 094 094 \ # 094 094 # ================================================ # Here is a recommendation sent in by Michael Feir # for use by blind NetHack players. # #DUNGEON= 032 124 045 124 124 124 124 045 045 045 \ # 124 124 046 045 124 043 043 046 035 035 \ # 060 062 060 062 095 092 035 126 126 126 \ # 126 042 042 035 035 032 035 126 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 094 094 094 094 094 \ # 094 094 # #EFFECTS= 124 095 092 047 042 033 041 040 \ # 048 035 064 042 \ # 047 045 092 058 058 092 045 047 \ # 047 045 092 058 032 058 092 045 047 # ================================================ # Example using the DEC Rainbow/ANSI line-drawing character set: # # If you have compiled with TERMLIB, merely set the DECgraphics option as # above. NetHack will then switch into the VTxxx line-drawing character set # (aka ANSI ruling character set '0') for dungeon characters. If you don't # like the selections, you can make up your own via the graphics options, # adding 128 to the value of any line-drawing character you want to use. # (But you should still set DECgraphics to get the correct processing.) # ================================================= # *** VIDEOCOLORS AND VIDEOSHADES *** # # While playing on NEC PC-9800, default game display may be difficult to # read. Try following setting. # #OPTIONS=videocolors:4-2-6-1-5-3-4-2-6-1-5-3,videoshades:normal-normal-normal # # DEC Rainbows will hang if rawio is set, so they should instead use: #OPTIONS=BIOS,DECgraphics nethack-3.4.3/sys/share/dgn_comp.h0100644000000000000000000000076707764735041015543 0ustar rootroot#define INTEGER 257 #define A_DUNGEON 258 #define BRANCH 259 #define CHBRANCH 260 #define LEVEL 261 #define RNDLEVEL 262 #define CHLEVEL 263 #define RNDCHLEVEL 264 #define UP_OR_DOWN 265 #define PROTOFILE 266 #define DESCRIPTION 267 #define DESCRIPTOR 268 #define LEVELDESC 269 #define ALIGNMENT 270 #define LEVALIGN 271 #define ENTRY 272 #define STAIR 273 #define NO_UP 274 #define NO_DOWN 275 #define PORTAL 276 #define STRING 277 typedef union { int i; char* str; } YYSTYPE; extern YYSTYPE yylval; nethack-3.4.3/sys/share/dgn_lex.c0100644000000000000000000011626407764735041015370 0ustar rootroot/* A lexical scanner for NetHack generated by flex */ /* Scanner skeleton version: * flexhack.skl 3.3.0 (from .../flex/RCS/flex.skl,v 2.85 95/04/24 10:48:47) */ #define FLEXHACK_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #include "config.h" #define yyconst const /* some code inserted by flex will refer to yyconst */ /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #define YY_BUF_SIZE 16384 typedef struct yy_buffer_state *YY_BUFFER_STATE; extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* Return all but the first 'n' matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ *yy_cp = yy_hold_char; \ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yytext_ptr ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ typedef unsigned int yy_size_t; struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; static YY_BUFFER_STATE yy_current_buffer = 0; /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". */ #define YY_CURRENT_BUFFER yy_current_buffer /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 1; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void FDECL(yyrestart, (FILE *)); void FDECL(yy_switch_to_buffer, (YY_BUFFER_STATE)); void NDECL(yy_load_buffer_state); YY_BUFFER_STATE FDECL(yy_create_buffer, (FILE *,int)); void FDECL(yy_delete_buffer, (YY_BUFFER_STATE)); void FDECL(yy_init_buffer, (YY_BUFFER_STATE,FILE *)); void FDECL(yy_flush_buffer, (YY_BUFFER_STATE)); #define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) static genericptr_t FDECL(yy_flex_alloc, (yy_size_t)); static genericptr_t FDECL(yy_flex_realloc2, (genericptr_t,yy_size_t,int)); static void FDECL(yy_flex_free, (genericptr_t)); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (yy_current_buffer->yy_at_bol) typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern char *yytext; #define yytext_ptr yytext static yy_state_type NDECL(yy_get_previous_state); static yy_state_type FDECL(yy_try_NUL_trans, (yy_state_type)); static int NDECL(yy_get_next_buffer); static void FDECL(yy_fatal_error, (const char *)); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yytext_ptr = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yy_c_buf_p = yy_cp; #define YY_NUM_RULES 35 #define YY_END_OF_BUFFER 36 static yyconst short int yy_accept[196] = { 0, 0, 0, 36, 34, 33, 32, 34, 34, 29, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 33, 32, 0, 30, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 4, 0, 25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 5, 0, 0, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 20, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 22, 15, 0, 21, 7, 19, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 26, 16, 0, 0, 12, 0, 0, 0, 11, 9, 0, 17, 18, 0, 27, 0, 28, 24, 10, 0 } ; static yyconst int yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 5, 6, 1, 1, 1, 1, 1, 1, 1, 1, 1, 7, 1, 1, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 1, 1, 1, 1, 1, 1, 1, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1, 1, 17, 18, 19, 20, 21, 1, 22, 23, 24, 25, 26, 1, 1, 27, 1, 1, 1, 1, 1, 28, 1, 29, 1, 30, 31, 32, 33, 34, 35, 36, 1, 37, 38, 39, 40, 41, 42, 1, 43, 44, 45, 46, 1, 47, 1, 1, 48, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst int yy_meta[49] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst short int yy_base[198] = { 0, 0, 213, 218, 220, 215, 220, 213, 210, 207, 196, 190, 196, 37, 191, 197, 186, 188, 171, 164, 172, 174, 173, 18, 160, 159, 154, 157, 11, 194, 194, 220, 190, 220, 187, 177, 184, 183, 167, 170, 164, 161, 166, 174, 155, 136, 144, 134, 132, 133, 26, 135, 143, 147, 128, 145, 220, 170, 220, 158, 152, 154, 159, 154, 145, 44, 142, 47, 124, 124, 125, 129, 129, 115, 27, 121, 113, 111, 120, 115, 116, 134, 142, 132, 128, 137, 121, 130, 129, 125, 129, 131, 97, 220, 105, 94, 101, 95, 96, 94, 99, 105, 101, 89, 220, 95, 112, 114, 51, 112, 107, 220, 110, 114, 111, 106, 96, 85, 76, 81, 82, 88, 69, 220, 81, 76, 75, 220, 78, 99, 220, 88, 97, 87, 88, 92, 93, 88, 91, 90, 71, 65, 220, 62, 60, 57, 56, 220, 59, 54, 74, 84, 65, 66, 220, 70, 65, 70, 60, 68, 220, 220, 52, 220, 220, 220, 46, 50, 57, 61, 67, 62, 220, 67, 64, 63, 220, 220, 42, 41, 220, 61, 53, 49, 220, 220, 50, 220, 220, 51, 220, 46, 220, 220, 220, 220, 62, 60 } ; static yyconst short int yy_def[198] = { 0, 195, 1, 195, 195, 195, 195, 195, 196, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 197, 195, 195, 196, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 197, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 0, 195, 195 } ; static yyconst short int yy_nxt[269] = { 0, 4, 5, 6, 7, 8, 4, 9, 10, 11, 12, 13, 14, 4, 4, 4, 4, 15, 4, 4, 4, 16, 17, 4, 4, 4, 4, 4, 4, 4, 18, 19, 4, 4, 4, 20, 4, 4, 21, 22, 23, 4, 24, 25, 26, 27, 28, 4, 4, 38, 49, 55, 87, 56, 74, 75, 88, 90, 98, 50, 131, 57, 39, 32, 91, 194, 193, 192, 132, 191, 190, 189, 188, 99, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173, 172, 171, 170, 169, 168, 167, 166, 165, 164, 163, 162, 161, 160, 159, 158, 157, 156, 155, 154, 153, 152, 151, 150, 149, 148, 147, 146, 145, 144, 143, 142, 141, 140, 139, 138, 137, 136, 135, 134, 133, 130, 129, 128, 127, 126, 125, 124, 123, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 109, 108, 107, 106, 105, 104, 103, 102, 101, 100, 97, 96, 95, 94, 93, 92, 89, 86, 85, 84, 83, 82, 81, 58, 80, 79, 78, 77, 76, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 34, 33, 30, 58, 54, 53, 52, 51, 48, 47, 46, 45, 44, 43, 42, 41, 40, 37, 36, 35, 34, 33, 31, 30, 195, 29, 3, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195 } ; static yyconst short int yy_chk[269] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 13, 23, 28, 65, 28, 50, 50, 65, 67, 74, 23, 108, 197, 13, 196, 67, 191, 189, 186, 108, 183, 182, 181, 179, 74, 178, 175, 174, 173, 171, 170, 169, 168, 167, 166, 162, 159, 158, 157, 156, 155, 153, 152, 151, 150, 149, 148, 146, 145, 144, 143, 141, 140, 139, 138, 137, 136, 135, 134, 133, 132, 131, 129, 128, 126, 125, 124, 122, 121, 120, 119, 118, 117, 116, 115, 114, 113, 112, 110, 109, 107, 106, 105, 103, 102, 101, 100, 99, 98, 97, 96, 95, 94, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, 79, 78, 77, 76, 75, 73, 72, 71, 70, 69, 68, 66, 64, 63, 62, 61, 60, 59, 57, 55, 54, 53, 52, 51, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 32, 30, 29, 27, 26, 25, 24, 22, 21, 20, 19, 18, 17, 16, 15, 14, 12, 11, 10, 9, 8, 7, 5, 3, 2, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195, 195 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 char *yytext; #define INITIAL 0 /* SCCS Id: @(#)dgn_lex.c 3.4 2002/03/27 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #define DGN_COMP #include "config.h" #include "dgn_comp.h" #include "dgn_file.h" /* * Most of these don't exist in flex, yywrap is macro and * yyunput is properly declared in flex.skel. */ #if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) int FDECL(yyback, (int *,int)); int NDECL(yylook); int NDECL(yyinput); int NDECL(yywrap); int NDECL(yylex); /* Traditional lexes let yyunput() and yyoutput() default to int; * newer ones may declare them as void since they don't return * values. For even more fun, the lex supplied as part of the * newer unbundled compiler for SunOS 4.x adds the void declarations * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain * int) while the bundled lex and the one with the older unbundled * compiler do not. To detect this, we need help from outside -- * sys/unix/Makefile.utl. * * Digital UNIX is difficult and still has int in spite of all * other signs. */ # if defined(NeXT) || defined(SVR4) || defined(_AIX32) # define VOIDYYPUT # endif # if !defined(VOIDYYPUT) && defined(POSIX_TYPES) # if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) # define VOIDYYPUT # endif # endif # if !defined(VOIDYYPUT) && defined(WEIRD_LEX) # if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) # define VOIDYYPUT # endif # endif # if defined(VOIDYYPUT) && defined(__osf__) # undef VOIDYYPUT # endif # ifdef VOIDYYPUT void FDECL(yyunput, (int)); void FDECL(yyoutput, (int)); # else int FDECL(yyunput, (int)); int FDECL(yyoutput, (int)); # endif #endif /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ #ifdef FLEX_SCANNER #define YY_MALLOC_DECL \ genericptr_t FDECL(malloc, (size_t)); \ genericptr_t FDECL(realloc, (genericptr_t,size_t)); #endif void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); /* this doesn't always get put in dgn_comp.h * (esp. when using older versions of bison) */ extern YYSTYPE yylval; int line_number = 1; /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP extern int NDECL(yywrap); #endif #ifndef YY_NO_UNPUT static void FDECL(yyunput, (int,char *)); #endif #ifndef yytext_ptr static void FDECL(yy_flex_strncpy, (char *,const char *,int)); #endif #ifndef YY_NO_INPUT static int NDECL(input); #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( yy_current_buffer->yy_is_interactive ) \ { \ int c = '*', n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ if ( yyleng > 0 ) \ yy_current_buffer->yy_at_bol = \ (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION int NDECL(yylex); int yylex() { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; if ( yy_init ) { yy_init = 0; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yy_start ) yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! yy_current_buffer ) yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); yy_load_buffer_state(); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = yy_c_buf_p; /* Support of yytext. */ *yy_cp = yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yy_start; yy_current_state += YY_AT_BOL(); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 196 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 220 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yy_hold_char; yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP return(A_DUNGEON); YY_BREAK case 2: YY_RULE_SETUP { yylval.i=1; return(UP_OR_DOWN); } YY_BREAK case 3: YY_RULE_SETUP { yylval.i=0; return(UP_OR_DOWN); } YY_BREAK case 4: YY_RULE_SETUP return(ENTRY); YY_BREAK case 5: YY_RULE_SETUP return(STAIR); YY_BREAK case 6: YY_RULE_SETUP return(NO_UP); YY_BREAK case 7: YY_RULE_SETUP return(NO_DOWN); YY_BREAK case 8: YY_RULE_SETUP return(PORTAL); YY_BREAK case 9: YY_RULE_SETUP return(PROTOFILE); YY_BREAK case 10: YY_RULE_SETUP return(DESCRIPTION); YY_BREAK case 11: YY_RULE_SETUP return(LEVELDESC); YY_BREAK case 12: YY_RULE_SETUP return(ALIGNMENT); YY_BREAK case 13: YY_RULE_SETUP return(LEVALIGN); YY_BREAK case 14: YY_RULE_SETUP { yylval.i=TOWN ; return(DESCRIPTOR); } YY_BREAK case 15: YY_RULE_SETUP { yylval.i=HELLISH ; return(DESCRIPTOR); } YY_BREAK case 16: YY_RULE_SETUP { yylval.i=MAZELIKE ; return(DESCRIPTOR); } YY_BREAK case 17: YY_RULE_SETUP { yylval.i=ROGUELIKE ; return(DESCRIPTOR); } YY_BREAK case 18: YY_RULE_SETUP { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } YY_BREAK case 19: YY_RULE_SETUP { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } YY_BREAK case 20: YY_RULE_SETUP { yylval.i=D_ALIGN_LAWFUL ; return(DESCRIPTOR); } YY_BREAK case 21: YY_RULE_SETUP { yylval.i=D_ALIGN_NEUTRAL ; return(DESCRIPTOR); } YY_BREAK case 22: YY_RULE_SETUP { yylval.i=D_ALIGN_CHAOTIC ; return(DESCRIPTOR); } YY_BREAK case 23: YY_RULE_SETUP return(BRANCH); YY_BREAK case 24: YY_RULE_SETUP return(CHBRANCH); YY_BREAK case 25: YY_RULE_SETUP return(LEVEL); YY_BREAK case 26: YY_RULE_SETUP return(RNDLEVEL); YY_BREAK case 27: YY_RULE_SETUP return(CHLEVEL); YY_BREAK case 28: YY_RULE_SETUP return(RNDCHLEVEL); YY_BREAK case 29: YY_RULE_SETUP { yylval.i=atoi(yytext); return(INTEGER); } YY_BREAK case 30: YY_RULE_SETUP { yytext[yyleng-1] = 0; /* Discard the trailing \" */ yylval.str = (char *) alloc(strlen(yytext+1)+1); Strcpy(yylval.str, yytext+1); /* Discard the first \" */ return(STRING); } YY_BREAK case 31: YY_RULE_SETUP { line_number++; } YY_BREAK case 32: YY_RULE_SETUP { line_number++; } YY_BREAK case 33: YY_RULE_SETUP ; /* skip trailing tabs & spaces */ YY_BREAK case 34: YY_RULE_SETUP { return yytext[0]; } YY_BREAK case 35: YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yy_hold_char; if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between yy_current_buffer and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yy_n_chars = yy_current_buffer->yy_n_chars; yy_current_buffer->yy_input_file = yyin; yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yy_c_buf_p; goto yy_find_action; } } else switch ( yy_get_next_buffer() ) { case EOB_ACT_END_OF_FILE: { yy_did_buffer_switch_on_eof = 0; if ( yywrap() ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(); yy_cp = yy_c_buf_p; yy_bp = yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yy_c_buf_p = &yy_current_buffer->yy_ch_buf[yy_n_chars]; yy_current_state = yy_get_previous_state(); yy_cp = yy_c_buf_p; yy_bp = yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer() { register char *dest = yy_current_buffer->yy_ch_buf; register char *source = yytext_ptr; register int number_to_move, i; int ret_val; if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( yy_current_buffer->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a singled characater, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ yy_n_chars = 0; else { int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ #ifdef YY_USES_REJECT YY_FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); #else /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = yy_current_buffer; int yy_c_buf_p_offset = (int) (yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int old_size = b->yy_buf_size + 2; int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yy_flex_realloc2( (genericptr_t) b->yy_ch_buf, b->yy_buf_size + 2, old_size ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; #endif } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), yy_n_chars, num_to_read ); } if ( yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; yy_current_buffer->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; yy_n_chars += number_to_move; yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state() { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = yy_start; yy_current_state += YY_AT_BOL(); for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 196 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans( yy_current_state ) yy_state_type yy_current_state; { register int yy_is_jam; register char *yy_cp = yy_c_buf_p; register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 196 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 195); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT static void yyunput( c, yy_bp ) int c; register char *yy_bp; { register char *yy_cp = yy_c_buf_p; /* undo effects of setting up yytext */ *yy_cp = yy_hold_char; if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = yy_n_chars + 2; register char *dest = &yy_current_buffer->yy_ch_buf[ yy_current_buffer->yy_buf_size + 2]; register char *source = &yy_current_buffer->yy_ch_buf[number_to_move]; while ( source > yy_current_buffer->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); yy_n_chars = yy_current_buffer->yy_buf_size; if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; yytext_ptr = yy_bp; yy_hold_char = *yy_cp; yy_c_buf_p = yy_cp; } #endif /* ifndef YY_NO_UNPUT */ static int input() { int c; *yy_c_buf_p = yy_hold_char; if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) /* This was really a NUL. */ *yy_c_buf_p = '\0'; else { /* need more input */ yytext_ptr = yy_c_buf_p; ++yy_c_buf_p; switch ( yy_get_next_buffer() ) { case EOB_ACT_END_OF_FILE: { if ( yywrap() ) { yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; return EOF; } if ( ! yy_did_buffer_switch_on_eof ) YY_NEW_FILE; return input(); } case EOB_ACT_CONTINUE_SCAN: yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; break; case EOB_ACT_LAST_MATCH: YY_FATAL_ERROR( "unexpected last match in input()" ); } } } c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ *yy_c_buf_p = '\0'; /* preserve yytext */ yy_hold_char = *++yy_c_buf_p; yy_current_buffer->yy_at_bol = (c == '\n'); return c; } void yyrestart( input_file ) FILE *input_file; { if ( ! yy_current_buffer ) yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); yy_init_buffer( yy_current_buffer, input_file ); yy_load_buffer_state(); } void yy_switch_to_buffer( new_buffer ) YY_BUFFER_STATE new_buffer; { if ( yy_current_buffer == new_buffer ) return; if ( yy_current_buffer ) { /* Flush out information for old buffer. */ *yy_c_buf_p = yy_hold_char; yy_current_buffer->yy_buf_pos = yy_c_buf_p; yy_current_buffer->yy_n_chars = yy_n_chars; } yy_current_buffer = new_buffer; yy_load_buffer_state(); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yy_did_buffer_switch_on_eof = 1; } void yy_load_buffer_state() { yy_n_chars = yy_current_buffer->yy_n_chars; yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; yyin = yy_current_buffer->yy_input_file; yy_hold_char = *yy_c_buf_p; } YY_BUFFER_STATE yy_create_buffer( file, size ) FILE *file; int size; { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file ); return b; } void yy_delete_buffer( b ) YY_BUFFER_STATE b; { if ( ! b ) return; if ( b == yy_current_buffer ) yy_current_buffer = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yy_flex_free( (genericptr_t) b->yy_ch_buf ); yy_flex_free( (genericptr_t) b ); } #ifndef YY_ALWAYS_INTERACTIVE #ifndef YY_NEVER_INTERACTIVE extern int FDECL(isatty, (int)); #endif #endif void yy_init_buffer( b, file ) YY_BUFFER_STATE b; FILE *file; { yy_flush_buffer( b ); b->yy_input_file = file; b->yy_fill_buffer = 1; #ifdef YY_ALWAYS_INTERACTIVE b->yy_is_interactive = 1; #else #ifdef YY_NEVER_INTERACTIVE b->yy_is_interactive = 0; #else b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; #endif #endif } void yy_flush_buffer( b ) YY_BUFFER_STATE b; { b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == yy_current_buffer ) yy_load_buffer_state(); } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error( msg ) const char msg[]; { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ yytext[yyleng] = yy_hold_char; \ yy_c_buf_p = yytext + n - YY_MORE_ADJ; \ yy_hold_char = *yy_c_buf_p; \ *yy_c_buf_p = '\0'; \ yyleng = n; \ } \ while ( 0 ) /* Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy( s1, s2, n ) char *s1; const char *s2; int n; { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif static genericptr_t yy_flex_alloc( size ) yy_size_t size; { return (genericptr_t) alloc((unsigned)size); } /* we want to avoid use of realloc(), so we require that caller supply the size of the old block of memory */ static genericptr_t yy_flex_realloc2( ptr, size, old_size ) genericptr_t ptr; yy_size_t size; int old_size; { genericptr_t outptr = yy_flex_alloc(size); if (ptr) { char *p = (char *) outptr, *q = (char *) ptr; while (--old_size >= 0) *p++ = *q++; yy_flex_free(ptr); } return outptr; } static void yy_flex_free( ptr ) genericptr_t ptr; { free( ptr ); } /*flexhack.skl*/ /* routine to switch to another input file; needed for flex */ void init_yyin( input_f ) FILE *input_f; { #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) if (yyin) yyrestart(input_f); else #endif yyin = input_f; } /* analogous routine (for completeness) */ void init_yyout( output_f ) FILE *output_f; { yyout = output_f; } /*dgn_comp.l*/ nethack-3.4.3/sys/share/dgn_yacc.c0100644000000000000000000007351507764735041015520 0ustar rootroot#ifndef lint static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; #endif #define YYBYACC 1 #define YYMAJOR 1 #define YYMINOR 9 #define yyclearin (yychar=(-1)) #define yyerrok (yyerrflag=0) #define YYRECOVERING (yyerrflag!=0) #define YYPREFIX "yy" /* SCCS Id: @(#)dgn_comp.c 3.4 1996/06/22 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the Dungeon Compiler code */ /* In case we're using bison in AIX. This definition must be * placed before any other C-language construct in the file * excluding comments and preprocessor directives (thanks IBM * for this wonderful feature...). * * Note: some cpps barf on this 'undefined control' (#pragma). * Addition of the leading space seems to prevent barfage for now, * and AIX will still see the directive in its non-standard locale. */ #ifdef _AIX #pragma alloca /* keep leading space! */ #endif #include "config.h" #include "date.h" #include "dgn_file.h" void FDECL(yyerror, (const char *)); void FDECL(yywarning, (const char *)); int NDECL(yylex); int NDECL(yyparse); int FDECL(getchain, (char *)); int NDECL(check_dungeon); int NDECL(check_branch); int NDECL(check_level); void NDECL(init_dungeon); void NDECL(init_branch); void NDECL(init_level); void NDECL(output_dgn); #define Free(ptr) free((genericptr_t)ptr) #ifdef AMIGA # undef printf #ifndef LATTICE # define memset(addr,val,len) setmem(addr,len,val) #endif #endif #define ERR (-1) static struct couple couple; static struct tmpdungeon tmpdungeon[MAXDUNGEON]; static struct tmplevel tmplevel[LEV_LIMIT]; static struct tmpbranch tmpbranch[BRANCH_LIMIT]; static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1; extern int fatal_error; extern const char *fname; extern FILE *yyin, *yyout; /* from dgn_lex.c */ typedef union { int i; char* str; } YYSTYPE; #define INTEGER 257 #define A_DUNGEON 258 #define BRANCH 259 #define CHBRANCH 260 #define LEVEL 261 #define RNDLEVEL 262 #define CHLEVEL 263 #define RNDCHLEVEL 264 #define UP_OR_DOWN 265 #define PROTOFILE 266 #define DESCRIPTION 267 #define DESCRIPTOR 268 #define LEVELDESC 269 #define ALIGNMENT 270 #define LEVALIGN 271 #define ENTRY 272 #define STAIR 273 #define NO_UP 274 #define NO_DOWN 275 #define PORTAL 276 #define STRING 277 #define YYERRCODE 256 short yylhs[] = { -1, 0, 0, 5, 5, 6, 6, 6, 6, 7, 1, 1, 8, 8, 8, 12, 13, 15, 15, 14, 10, 10, 10, 10, 10, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 9, 9, 22, 23, 3, 3, 3, 3, 3, 2, 2, 4, 21, 11, }; short yylen[] = { 2, 0, 1, 1, 2, 1, 1, 1, 1, 6, 0, 1, 1, 1, 1, 3, 1, 3, 3, 3, 1, 1, 1, 1, 1, 6, 7, 7, 8, 3, 3, 7, 8, 8, 9, 1, 1, 7, 8, 0, 1, 1, 1, 1, 0, 1, 1, 5, 5, }; short yydefred[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 6, 7, 8, 12, 13, 14, 16, 20, 21, 22, 23, 24, 35, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 19, 17, 29, 18, 30, 15, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 9, 0, 40, 41, 42, 43, 0, 0, 0, 0, 0, 0, 0, 0, 45, 37, 0, 27, 0, 0, 0, 0, 0, 38, 28, 33, 0, 48, 47, 34, }; short yydgoto[] = { 14, 78, 93, 84, 60, 15, 16, 17, 18, 19, 20, 68, 21, 22, 23, 24, 25, 26, 27, 28, 29, 70, 30, 31, }; short yysindex[] = { -237, -46, -45, -44, -39, -38, -30, -22, -21, -20, -19, -18, -17, -16, 0, -237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -262, -234, -233, -232, -230, -229, -228, -227, -217, -216, -215, -214, -202, 0, -221, -7, -219, -221, -221, -221, -221, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, -2, -1, -212, -211, -190, -189, -188, -271, 19, 20, 20, 27, 28, 29, 0, 0, 30, 0, 0, 0, 0, -193, -271, -182, -180, 19, 19, -179, -178, 0, 0, -193, 0, -177, -176, -175, 42, 43, 0, 0, 0, -172, 0, 0, 0, }; short yyrindex[] = { 86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31, 1, 46, 0, 0, 0, 0, 0, 0, 0, 31, 0, 61, 76, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, }; short yygindex[] = { 0, 0, -6, 4, -43, 0, 75, 0, 0, 0, 0, -71, 0, 0, 0, 0, 0, 0, 0, 0, 0, -62, 0, 0, }; #define YYTABLESIZE 363 short yytable[] = { 85, 39, 80, 81, 82, 83, 63, 64, 65, 66, 86, 87, 32, 33, 34, 46, 10, 97, 98, 35, 36, 1, 2, 3, 4, 5, 6, 7, 37, 8, 9, 44, 10, 11, 12, 13, 38, 39, 40, 41, 42, 43, 44, 47, 48, 49, 25, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 61, 62, 67, 69, 26, 72, 73, 71, 74, 75, 76, 77, 79, 88, 89, 92, 90, 91, 95, 31, 96, 99, 100, 102, 103, 104, 105, 106, 107, 1, 2, 101, 94, 45, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 39, 39, 39, 39, 39, 39, 39, 39, 39, 39, 0, 39, 39, 39, 39, 10, 10, 10, 10, 10, 10, 10, 0, 10, 10, 0, 10, 10, 10, 10, 44, 44, 44, 44, 44, 44, 44, 0, 44, 44, 0, 44, 44, 44, 44, 25, 25, 25, 25, 25, 25, 25, 0, 25, 25, 0, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 0, 26, 26, 0, 26, 26, 26, 26, 31, 31, 31, 31, 31, 31, 31, 0, 31, 31, 0, 31, 31, 31, 31, 32, 32, 32, 32, 32, 32, 32, 0, 32, 32, 0, 32, 32, 32, 32, }; short yycheck[] = { 71, 0, 273, 274, 275, 276, 49, 50, 51, 52, 72, 73, 58, 58, 58, 277, 0, 88, 89, 58, 58, 258, 259, 260, 261, 262, 263, 264, 58, 266, 267, 0, 269, 270, 271, 272, 58, 58, 58, 58, 58, 58, 58, 277, 277, 277, 0, 277, 277, 277, 277, 268, 268, 268, 268, 257, 277, 64, 277, 40, 40, 0, 64, 64, 43, 277, 277, 257, 257, 257, 43, 43, 265, 44, 44, 257, 0, 257, 257, 257, 257, 257, 257, 41, 41, 257, 0, 0, 94, 85, 15, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, 258, 259, 260, 261, 262, 263, 264, -1, 266, 267, -1, 269, 270, 271, 272, }; #define YYFINAL 14 #ifndef YYDEBUG #define YYDEBUG 0 #endif #define YYMAXTOKEN 277 #if YYDEBUG char *yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,"'('","')'",0,"'+'","','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0, "'@'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"INTEGER", "A_DUNGEON","BRANCH","CHBRANCH","LEVEL","RNDLEVEL","CHLEVEL","RNDCHLEVEL", "UP_OR_DOWN","PROTOFILE","DESCRIPTION","DESCRIPTOR","LEVELDESC","ALIGNMENT", "LEVALIGN","ENTRY","STAIR","NO_UP","NO_DOWN","PORTAL","STRING", }; char *yyrule[] = { "$accept : file", "file :", "file : dungeons", "dungeons : dungeon", "dungeons : dungeons dungeon", "dungeon : dungeonline", "dungeon : dungeondesc", "dungeon : branches", "dungeon : levels", "dungeonline : A_DUNGEON ':' STRING bones_tag rcouple optional_int", "optional_int :", "optional_int : INTEGER", "dungeondesc : entry", "dungeondesc : descriptions", "dungeondesc : prototype", "entry : ENTRY ':' INTEGER", "descriptions : desc", "desc : DESCRIPTION ':' DESCRIPTOR", "desc : ALIGNMENT ':' DESCRIPTOR", "prototype : PROTOFILE ':' STRING", "levels : level1", "levels : level2", "levels : levdesc", "levels : chlevel1", "levels : chlevel2", "level1 : LEVEL ':' STRING bones_tag '@' acouple", "level1 : RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER", "level2 : LEVEL ':' STRING bones_tag '@' acouple INTEGER", "level2 : RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER INTEGER", "levdesc : LEVELDESC ':' DESCRIPTOR", "levdesc : LEVALIGN ':' DESCRIPTOR", "chlevel1 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple", "chlevel1 : RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER", "chlevel2 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER", "chlevel2 : RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER INTEGER", "branches : branch", "branches : chbranch", "branch : BRANCH ':' STRING '@' acouple branch_type direction", "chbranch : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction", "branch_type :", "branch_type : STAIR", "branch_type : NO_UP", "branch_type : NO_DOWN", "branch_type : PORTAL", "direction :", "direction : UP_OR_DOWN", "bones_tag : STRING", "acouple : '(' INTEGER ',' INTEGER ')'", "rcouple : '(' INTEGER ',' INTEGER ')'", }; #endif #ifdef YYSTACKSIZE #undef YYMAXDEPTH #define YYMAXDEPTH YYSTACKSIZE #else #ifdef YYMAXDEPTH #define YYSTACKSIZE YYMAXDEPTH #else #define YYSTACKSIZE 500 #define YYMAXDEPTH 500 #endif #endif int yydebug; int yynerrs; int yyerrflag; int yychar; short *yyssp; YYSTYPE *yyvsp; YYSTYPE yyval; YYSTYPE yylval; short yyss[YYSTACKSIZE]; YYSTYPE yyvs[YYSTACKSIZE]; #define yystacksize YYSTACKSIZE void init_dungeon() { if(++n_dgns > MAXDUNGEON) { (void) fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n", MAXDUNGEON); (void) fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n"); exit(EXIT_FAILURE); } in_dungeon = 1; tmpdungeon[n_dgns].lev.base = 0; tmpdungeon[n_dgns].lev.rand = 0; tmpdungeon[n_dgns].chance = 100; Strcpy(tmpdungeon[n_dgns].name, ""); Strcpy(tmpdungeon[n_dgns].protoname, ""); tmpdungeon[n_dgns].flags = 0; tmpdungeon[n_dgns].levels = 0; tmpdungeon[n_dgns].branches = 0; tmpdungeon[n_dgns].entry_lev = 0; } void init_level() { if(++n_levs > LEV_LIMIT) { yyerror("FATAL - Too many special levels defined."); exit(EXIT_FAILURE); } tmplevel[n_levs].lev.base = 0; tmplevel[n_levs].lev.rand = 0; tmplevel[n_levs].chance = 100; tmplevel[n_levs].rndlevs = 0; tmplevel[n_levs].flags = 0; Strcpy(tmplevel[n_levs].name, ""); tmplevel[n_levs].chain = -1; } void init_branch() { if(++n_brs > BRANCH_LIMIT) { yyerror("FATAL - Too many special levels defined."); exit(EXIT_FAILURE); } tmpbranch[n_brs].lev.base = 0; tmpbranch[n_brs].lev.rand = 0; Strcpy(tmpbranch[n_brs].name, ""); tmpbranch[n_brs].chain = -1; } int getchain(s) char *s; { int i; if(strlen(s)) { for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++) if(!strcmp(tmplevel[i].name, s)) return i; yyerror("Can't locate the specified chain level."); return(-2); } return(-1); } /* * Consistancy checking routines: * * - A dungeon must have a unique name. * - A dungeon must have a originating "branch" command * (except, of course, for the first dungeon). * - A dungeon must have a proper depth (at least (1, 0)). */ int check_dungeon() { int i; for(i = 0; i < n_dgns; i++) if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) { yyerror("Duplicate dungeon name."); return(0); } if(n_dgns) for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) { if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break; if(i >= n_brs - tmpdungeon[n_dgns].branches) { yyerror("Dungeon cannot be reached."); return(0); } } if(tmpdungeon[n_dgns].lev.base <= 0 || tmpdungeon[n_dgns].lev.rand < 0) { yyerror("Invalid dungeon depth specified."); return(0); } return(1); /* OK */ } /* * - A level must have a unique level name. * - If chained, the level used as reference for the chain * must be in this dungeon, must be previously defined, and * the level chained from must be "non-probabilistic" (ie. * have a 100% chance of existing). */ int check_level() { int i; if(!in_dungeon) { yyerror("Level defined outside of dungeon."); return(0); } for(i = 0; i < n_levs; i++) if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) { yyerror("Duplicate level name."); return(0); } if(tmplevel[i].chain == -2) { yyerror("Invaild level chain reference."); return(0); } else if(tmplevel[i].chain != -1) { /* there is a chain */ /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */ if(tmplevel[tmplevel[i].chain].chance != 100) { yyerror("Level cannot chain from a probabilistic level."); return(0); } else if(tmplevel[i].chain == n_levs) { yyerror("A level cannot chain to itself!"); return(0); } } return(1); /* OK */ } /* * - A branch may not branch backwards - to avoid branch loops. * - A branch name must be unique. * (ie. You can only have one entry point to each dungeon). * - If chained, the level used as reference for the chain * must be in this dungeon, must be previously defined, and * the level chained from must be "non-probabilistic" (ie. * have a 100% chance of existing). */ int check_branch() { int i; if(!in_dungeon) { yyerror("Branch defined outside of dungeon."); return(0); } for(i = 0; i < n_dgns; i++) if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) { yyerror("Reverse branching not allowed."); return(0); } if(tmpbranch[i].chain == -2) { yyerror("Invaild branch chain reference."); return(0); } else if(tmpbranch[i].chain != -1) { /* it is chained */ if(tmplevel[tmpbranch[i].chain].chance != 100) { yyerror("Branch cannot chain from a probabilistic level."); return(0); } } return(1); /* OK */ } /* * Output the dungon definition into a file. * * The file will have the following format: * * [ nethack version ID ] * [ number of dungeons ] * [ first dungeon struct ] * [ levels for the first dungeon ] * ... * [ branches for the first dungeon ] * ... * [ second dungeon struct ] * ... */ void output_dgn() { int nd, cl = 0, nl = 0, cb = 0, nb = 0; static struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2 }; if(++n_dgns <= 0) { yyerror("FATAL - no dungeons were defined."); exit(EXIT_FAILURE); } if (fwrite((char *)&version_data, sizeof version_data, 1, yyout) != 1) { yyerror("FATAL - output failure."); exit(EXIT_FAILURE); } (void) fwrite((char *)&n_dgns, sizeof(int), 1, yyout); for (nd = 0; nd < n_dgns; nd++) { (void) fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon), 1, yyout); nl += tmpdungeon[nd].levels; for(; cl < nl; cl++) (void) fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel), 1, yyout); nb += tmpdungeon[nd].branches; for(; cb < nb; cb++) (void) fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch), 1, yyout); } /* apparently necessary for Think C 5.x, otherwise harmless */ (void) fflush(yyout); } /*dgn_comp.y*/ #define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept #define YYERROR goto yyerrlab int yyparse() { register int yym, yyn, yystate; #if YYDEBUG register char *yys; extern char *getenv(); if ((yys = getenv("YYDEBUG")) != 0) { yyn = *yys; if (yyn >= '0' && yyn <= '9') yydebug = yyn - '0'; } #endif yynerrs = 0; yyerrflag = 0; yychar = (-1); yyssp = yyss; yyvsp = yyvs; *yyssp = yystate = 0; yyloop: if ((yyn = yydefred[yystate]) != 0) goto yyreduce; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif } if ((yyn = yysindex[yystate]) != 0 && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, shifting to state %d\n", YYPREFIX, yystate, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; yychar = (-1); if (yyerrflag > 0) --yyerrflag; goto yyloop; } if ((yyn = yyrindex[yystate]) != 0 && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { yyn = yytable[yyn]; goto yyreduce; } if (yyerrflag) goto yyinrecovery; #ifdef lint goto yynewerror; #endif yynewerror: yyerror("syntax error"); #ifdef lint goto yyerrlab; #endif yyerrlab: ++yynerrs; yyinrecovery: if (yyerrflag < 3) { yyerrflag = 3; for (;;) { if ((yyn = yysindex[*yyssp]) != 0 && (yyn += YYERRCODE) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, error recovery shifting\ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; goto yyloop; } else { #if YYDEBUG if (yydebug) printf("%sdebug: error recovery discarding state %d\n", YYPREFIX, *yyssp); #endif if (yyssp <= yyss) goto yyabort; --yyssp; --yyvsp; } } } else { if (yychar == 0) goto yyabort; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, error recovery discards token %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif yychar = (-1); goto yyloop; } yyreduce: #if YYDEBUG if (yydebug) printf("%sdebug: state %d, reducing by rule %d (%s)\n", YYPREFIX, yystate, yyn, yyrule[yyn]); #endif yym = yylen[yyn]; yyval = yyvsp[1-yym]; switch (yyn) { case 2: { output_dgn(); } break; case 9: { init_dungeon(); Strcpy(tmpdungeon[n_dgns].name, yyvsp[-3].str); tmpdungeon[n_dgns].boneschar = (char)yyvsp[-2].i; tmpdungeon[n_dgns].lev.base = couple.base; tmpdungeon[n_dgns].lev.rand = couple.rand; tmpdungeon[n_dgns].chance = yyvsp[0].i; Free(yyvsp[-3].str); } break; case 10: { yyval.i = 0; } break; case 11: { yyval.i = yyvsp[0].i; } break; case 15: { tmpdungeon[n_dgns].entry_lev = yyvsp[0].i; } break; case 17: { if(yyvsp[0].i <= TOWN || yyvsp[0].i >= D_ALIGN_CHAOTIC) yyerror("Illegal description - ignoring!"); else tmpdungeon[n_dgns].flags |= yyvsp[0].i ; } break; case 18: { if(yyvsp[0].i && yyvsp[0].i < D_ALIGN_CHAOTIC) yyerror("Illegal alignment - ignoring!"); else tmpdungeon[n_dgns].flags |= yyvsp[0].i ; } break; case 19: { Strcpy(tmpdungeon[n_dgns].protoname, yyvsp[0].str); Free(yyvsp[0].str); } break; case 25: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-3].str); tmplevel[n_levs].boneschar = (char)yyvsp[-2].i; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmpdungeon[n_dgns].levels++; Free(yyvsp[-3].str); } break; case 26: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-4].str); tmplevel[n_levs].boneschar = (char)yyvsp[-3].i; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].rndlevs = yyvsp[0].i; tmpdungeon[n_dgns].levels++; Free(yyvsp[-4].str); } break; case 27: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-4].str); tmplevel[n_levs].boneschar = (char)yyvsp[-3].i; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = yyvsp[0].i; tmpdungeon[n_dgns].levels++; Free(yyvsp[-4].str); } break; case 28: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-5].str); tmplevel[n_levs].boneschar = (char)yyvsp[-4].i; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = yyvsp[-1].i; tmplevel[n_levs].rndlevs = yyvsp[0].i; tmpdungeon[n_dgns].levels++; Free(yyvsp[-5].str); } break; case 29: { if(yyvsp[0].i >= D_ALIGN_CHAOTIC) yyerror("Illegal description - ignoring!"); else tmplevel[n_levs].flags |= yyvsp[0].i ; } break; case 30: { if(yyvsp[0].i && yyvsp[0].i < D_ALIGN_CHAOTIC) yyerror("Illegal alignment - ignoring!"); else tmplevel[n_levs].flags |= yyvsp[0].i ; } break; case 31: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-4].str); tmplevel[n_levs].boneschar = (char)yyvsp[-3].i; tmplevel[n_levs].chain = getchain(yyvsp[-2].str); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free(yyvsp[-4].str); Free(yyvsp[-2].str); } break; case 32: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-5].str); tmplevel[n_levs].boneschar = (char)yyvsp[-4].i; tmplevel[n_levs].chain = getchain(yyvsp[-3].str); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].rndlevs = yyvsp[0].i; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free(yyvsp[-5].str); Free(yyvsp[-3].str); } break; case 33: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-5].str); tmplevel[n_levs].boneschar = (char)yyvsp[-4].i; tmplevel[n_levs].chain = getchain(yyvsp[-3].str); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = yyvsp[0].i; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free(yyvsp[-5].str); Free(yyvsp[-3].str); } break; case 34: { init_level(); Strcpy(tmplevel[n_levs].name, yyvsp[-6].str); tmplevel[n_levs].boneschar = (char)yyvsp[-5].i; tmplevel[n_levs].chain = getchain(yyvsp[-4].str); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = yyvsp[-1].i; tmplevel[n_levs].rndlevs = yyvsp[0].i; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free(yyvsp[-6].str); Free(yyvsp[-4].str); } break; case 37: { init_branch(); Strcpy(tmpbranch[n_brs].name, yyvsp[-4].str); tmpbranch[n_brs].lev.base = couple.base; tmpbranch[n_brs].lev.rand = couple.rand; tmpbranch[n_brs].type = yyvsp[-1].i; tmpbranch[n_brs].up = yyvsp[0].i; if(!check_branch()) n_brs--; else tmpdungeon[n_dgns].branches++; Free(yyvsp[-4].str); } break; case 38: { init_branch(); Strcpy(tmpbranch[n_brs].name, yyvsp[-5].str); tmpbranch[n_brs].chain = getchain(yyvsp[-4].str); tmpbranch[n_brs].lev.base = couple.base; tmpbranch[n_brs].lev.rand = couple.rand; tmpbranch[n_brs].type = yyvsp[-1].i; tmpbranch[n_brs].up = yyvsp[0].i; if(!check_branch()) n_brs--; else tmpdungeon[n_dgns].branches++; Free(yyvsp[-5].str); Free(yyvsp[-4].str); } break; case 39: { yyval.i = TBR_STAIR; /* two way stair */ } break; case 40: { yyval.i = TBR_STAIR; /* two way stair */ } break; case 41: { yyval.i = TBR_NO_UP; /* no up staircase */ } break; case 42: { yyval.i = TBR_NO_DOWN; /* no down staircase */ } break; case 43: { yyval.i = TBR_PORTAL; /* portal connection */ } break; case 44: { yyval.i = 0; /* defaults to down */ } break; case 45: { yyval.i = yyvsp[0].i; } break; case 46: { char *p = yyvsp[0].str; if (strlen(p) != 1) { if (strcmp(p, "none") != 0) yyerror("Bones marker must be a single char, or \"none\"!"); *p = '\0'; } yyval.i = *p; Free(p); } break; case 47: { if (yyvsp[-3].i < -MAXLEVEL || yyvsp[-3].i > MAXLEVEL) { yyerror("Abs base out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else if (yyvsp[-1].i < -1 || ((yyvsp[-3].i < 0) ? (MAXLEVEL + yyvsp[-3].i + yyvsp[-1].i + 1) > MAXLEVEL : (yyvsp[-3].i + yyvsp[-1].i) > MAXLEVEL)) { yyerror("Abs range out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else { couple.base = yyvsp[-3].i; couple.rand = yyvsp[-1].i; } } break; case 48: { if (yyvsp[-3].i < -MAXLEVEL || yyvsp[-3].i > MAXLEVEL) { yyerror("Rel base out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else { couple.base = yyvsp[-3].i; couple.rand = yyvsp[-1].i; } } break; } yyssp -= yym; yystate = *yyssp; yyvsp -= yym; yym = yylhs[yyn]; if (yystate == 0 && yym == 0) { #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state 0 to\ state %d\n", YYPREFIX, YYFINAL); #endif yystate = YYFINAL; *++yyssp = YYFINAL; *++yyvsp = yyval; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, YYFINAL, yychar, yys); } #endif } if (yychar == 0) goto yyaccept; goto yyloop; } if ((yyn = yygindex[yym]) != 0 && (yyn += yystate) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yystate) yystate = yytable[yyn]; else yystate = yydgoto[yym]; #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state %d \ to state %d\n", YYPREFIX, *yyssp, yystate); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate; *++yyvsp = yyval; goto yyloop; yyoverflow: yyerror("yacc stack overflow"); yyabort: return (1); yyaccept: return (0); } nethack-3.4.3/sys/share/ioctl.c0100644000000000000000000001004407764735041015047 0ustar rootroot/* SCCS Id: @(#)ioctl.c 3.4 1990/22/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This cannot be part of hack.tty.c (as it was earlier) since on some systems (e.g. MUNIX) the include files and define the same constants, and the C preprocessor complains. */ #include "hack.h" #if defined(BSD_JOB_CONTROL) || defined(_BULL_SOURCE) # ifdef HPUX #include # else # if defined(AIX_31) && !defined(_ALL_SOURCE) # define _ALL_SOURCE /* causes struct winsize to be present */ # ifdef _AIX32 # include # endif # endif # if defined(_BULL_SOURCE) # include struct termios termio; # undef TIMEOUT /* defined in you.h and sys/tty.h */ # include /* define winsize */ # include /* define struct ltchars */ # include /* define TIOGWINSZ */ # else # ifdef LINUX # include # else # include # endif # endif # endif struct ltchars ltchars; struct ltchars ltchars0 = { -1, -1, -1, -1, -1, -1 }; /* turn all off */ #else # ifdef POSIX_TYPES #include struct termios termio; # if defined(BSD) || defined(_AIX32) # if defined(_AIX32) && !defined(_ALL_SOURCE) # define _ALL_SOURCE # endif #include # endif # else #include /* also includes part of */ # if defined(TCSETS) && !defined(AIX_31) struct termios termio; # else struct termio termio; # endif # endif # ifdef AMIX #include # endif /* AMIX */ #endif #ifdef SUSPEND /* BSD isn't alone anymore... */ #include #endif #if defined(TIOCGWINSZ) && (defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE) || defined(SVR4)) #define USE_WIN_IOCTL #include "tcap.h" /* for LI and CO */ #endif #ifdef _M_UNIX extern void NDECL(sco_mapon); extern void NDECL(sco_mapoff); #endif #ifdef __linux__ extern void NDECL(linux_mapon); extern void NDECL(linux_mapoff); #endif #ifdef AUX void catch_stp() { signal(SIGTSTP, SIG_DFL); dosuspend(); } #endif /* AUX */ void getwindowsz() { #ifdef USE_WIN_IOCTL /* * ttysize is found on Suns and BSD * winsize is found on Suns, BSD, and Ultrix */ struct winsize ttsz; if (ioctl(fileno(stdin), (int)TIOCGWINSZ, (char *)&ttsz) != -1) { /* * Use the kernel's values for lines and columns if it has * any idea. */ if (ttsz.ws_row) LI = ttsz.ws_row; if (ttsz.ws_col) CO = ttsz.ws_col; } #endif } void getioctls() { #ifdef BSD_JOB_CONTROL (void) ioctl(fileno(stdin), (int) TIOCGLTC, (char *) <chars); (void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) <chars0); #else # ifdef POSIX_TYPES (void) tcgetattr(fileno(stdin), &termio); # else # if defined(TCSETS) && !defined(AIX_31) (void) ioctl(fileno(stdin), (int) TCGETS, &termio); # else (void) ioctl(fileno(stdin), (int) TCGETA, &termio); # endif # endif #endif getwindowsz(); #ifdef AUX ( void ) signal ( SIGTSTP , catch_stp ) ; #endif } void setioctls() { #ifdef BSD_JOB_CONTROL (void) ioctl(fileno(stdin), (int) TIOCSLTC, (char *) <chars); #else # ifdef POSIX_TYPES (void) tcsetattr(fileno(stdin), TCSADRAIN, &termio); # else # if defined(TCSETS) && !defined(AIX_31) (void) ioctl(fileno(stdin), (int) TCSETSW, &termio); # else (void) ioctl(fileno(stdin), (int) TCSETAW, &termio); # endif # endif #endif } #ifdef SUSPEND /* No longer implies BSD */ int dosuspend() { # ifdef SIGTSTP if(signal(SIGTSTP, SIG_IGN) == SIG_DFL) { suspend_nhwindows((char *)0); # ifdef _M_UNIX sco_mapon(); # endif # ifdef __linux__ linux_mapon(); # endif (void) signal(SIGTSTP, SIG_DFL); # ifdef AUX ( void ) kill ( 0 , SIGSTOP ) ; # else (void) kill(0, SIGTSTP); # endif # ifdef _M_UNIX sco_mapoff(); # endif # ifdef __linux__ linux_mapoff(); # endif resume_nhwindows(); } else { pline("I don't think your shell has job control."); } # else pline("Sorry, it seems we have no SIGTSTP here. Try ! or S."); # endif return(0); } #endif /* SUSPEND */ nethack-3.4.3/sys/share/lev_comp.h0100644000000000000000000000321307764735041015546 0ustar rootroot#define CHAR 257 #define INTEGER 258 #define BOOLEAN 259 #define PERCENT 260 #define MESSAGE_ID 261 #define MAZE_ID 262 #define LEVEL_ID 263 #define LEV_INIT_ID 264 #define GEOMETRY_ID 265 #define NOMAP_ID 266 #define OBJECT_ID 267 #define COBJECT_ID 268 #define MONSTER_ID 269 #define TRAP_ID 270 #define DOOR_ID 271 #define DRAWBRIDGE_ID 272 #define MAZEWALK_ID 273 #define WALLIFY_ID 274 #define REGION_ID 275 #define FILLING 276 #define RANDOM_OBJECTS_ID 277 #define RANDOM_MONSTERS_ID 278 #define RANDOM_PLACES_ID 279 #define ALTAR_ID 280 #define LADDER_ID 281 #define STAIR_ID 282 #define NON_DIGGABLE_ID 283 #define NON_PASSWALL_ID 284 #define ROOM_ID 285 #define PORTAL_ID 286 #define TELEPRT_ID 287 #define BRANCH_ID 288 #define LEV 289 #define CHANCE_ID 290 #define CORRIDOR_ID 291 #define GOLD_ID 292 #define ENGRAVING_ID 293 #define FOUNTAIN_ID 294 #define POOL_ID 295 #define SINK_ID 296 #define NONE 297 #define RAND_CORRIDOR_ID 298 #define DOOR_STATE 299 #define LIGHT_STATE 300 #define CURSE_TYPE 301 #define ENGRAVING_TYPE 302 #define DIRECTION 303 #define RANDOM_TYPE 304 #define O_REGISTER 305 #define M_REGISTER 306 #define P_REGISTER 307 #define A_REGISTER 308 #define ALIGNMENT 309 #define LEFT_OR_RIGHT 310 #define CENTER 311 #define TOP_OR_BOT 312 #define ALTAR_TYPE 313 #define UP_OR_DOWN 314 #define SUBROOM_ID 315 #define NAME_ID 316 #define FLAGS_ID 317 #define FLAG_TYPE 318 #define MON_ATTITUDE 319 #define MON_ALERTNESS 320 #define MON_APPEARANCE 321 #define CONTAINED 322 #define STRING 323 #define MAP_ID 324 typedef union { int i; char* map; struct { xchar room; xchar wall; xchar door; } corpos; } YYSTYPE; extern YYSTYPE yylval; nethack-3.4.3/sys/share/lev_lex.c0100644000000000000000000017130707764735041015405 0ustar rootroot/* A lexical scanner for NetHack generated by flex */ /* Scanner skeleton version: * flexhack.skl 3.3.0 (from .../flex/RCS/flex.skl,v 2.85 95/04/24 10:48:47) */ #define FLEXHACK_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #include "config.h" #define yyconst const /* some code inserted by flex will refer to yyconst */ /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN yy_start = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START ((yy_start - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart( yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #define YY_BUF_SIZE 16384 typedef struct yy_buffer_state *YY_BUFFER_STATE; extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 /* Return all but the first 'n' matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ *yy_cp = yy_hold_char; \ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, yytext_ptr ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ typedef unsigned int yy_size_t; struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; static YY_BUFFER_STATE yy_current_buffer = 0; /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". */ #define YY_CURRENT_BUFFER yy_current_buffer /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 1; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void FDECL(yyrestart, (FILE *)); void FDECL(yy_switch_to_buffer, (YY_BUFFER_STATE)); void NDECL(yy_load_buffer_state); YY_BUFFER_STATE FDECL(yy_create_buffer, (FILE *,int)); void FDECL(yy_delete_buffer, (YY_BUFFER_STATE)); void FDECL(yy_init_buffer, (YY_BUFFER_STATE,FILE *)); void FDECL(yy_flush_buffer, (YY_BUFFER_STATE)); #define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) static genericptr_t FDECL(yy_flex_alloc, (yy_size_t)); static genericptr_t FDECL(yy_flex_realloc2, (genericptr_t,yy_size_t,int)); static void FDECL(yy_flex_free, (genericptr_t)); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! yy_current_buffer ) \ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ yy_current_buffer->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (yy_current_buffer->yy_at_bol) typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern char *yytext; #define yytext_ptr yytext static yy_state_type NDECL(yy_get_previous_state); static yy_state_type FDECL(yy_try_NUL_trans, (yy_state_type)); static int NDECL(yy_get_next_buffer); static void FDECL(yy_fatal_error, (const char *)); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ yytext_ptr = yy_bp; \ yyleng = (int) (yy_cp - yy_bp); \ yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yy_c_buf_p = yy_cp; #define YY_NUM_RULES 112 #define YY_END_OF_BUFFER 113 static yyconst short int yy_accept[640] = { 0, 0, 0, 0, 0, 113, 111, 108, 107, 111, 111, 111, 111, 105, 4, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 2, 111, 108, 111, 111, 105, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 111, 108, 107, 0, 106, 0, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 87, 0, 0, 3, 0, 2, 2, 0, 108, 0, 105, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 110, 0, 110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 0, 0, 67, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 40, 0, 0, 0, 6, 0, 0, 42, 0, 0, 0, 33, 0, 0, 0, 36, 32, 0, 0, 0, 16, 0, 0, 104, 0, 0, 0, 0, 0, 0, 0, 0, 93, 0, 0, 0, 0, 0, 0, 88, 91, 51, 0, 0, 0, 0, 0, 0, 60, 0, 0, 0, 0, 0, 94, 0, 0, 0, 0, 0, 0, 55, 0, 0, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 90, 0, 0, 0, 53, 12, 0, 0, 0, 0, 0, 25, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 8, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 27, 0, 0, 0, 59, 86, 0, 0, 80, 0, 0, 0, 0, 74, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 50, 0, 0, 0, 58, 0, 64, 0, 0, 0, 52, 0, 0, 68, 0, 0, 30, 43, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 13, 28, 0, 21, 0, 0, 0, 0, 79, 0, 66, 49, 62, 46, 0, 0, 97, 0, 69, 0, 0, 0, 0, 0, 47, 0, 0, 0, 0, 0, 0, 48, 101, 0, 0, 56, 0, 54, 0, 0, 85, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 15, 0, 0, 0, 37, 0, 20, 0, 95, 0, 0, 92, 0, 0, 0, 78, 0, 0, 0, 0, 57, 73, 71, 0, 0, 0, 84, 0, 0, 0, 0, 39, 0, 0, 31, 11, 9, 19, 0, 0, 0, 0, 0, 0, 0, 102, 0, 0, 0, 0, 0, 0, 0, 0, 83, 0, 0, 77, 0, 96, 70, 14, 0, 41, 0, 0, 0, 0, 0, 0, 0, 75, 98, 61, 0, 100, 44, 81, 82, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 63, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 76, 103, 0, 0, 0, 24, 0, 0, 0, 22, 0, 0, 23, 29, 38, 0 } ; static yyconst int yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 6, 7, 1, 8, 1, 9, 1, 1, 1, 10, 1, 11, 12, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 1, 1, 1, 1, 1, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 1, 31, 32, 33, 34, 35, 36, 1, 37, 38, 39, 40, 41, 1, 42, 1, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 1, 59, 60, 61, 62, 63, 64, 1, 1, 1, 12, 12, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst int yy_meta[65] = { 0, 1, 2, 3, 2, 2, 1, 2, 1, 1, 2, 2, 2, 2, 1, 2, 2, 2, 1, 1, 2, 1, 2, 2, 1, 2, 2, 1, 1, 1, 2, 1, 2, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst short int yy_base[645] = { 0, 0, 58, 83, 62, 796, 797, 65, 797, 792, 788, 753, 779, 778, 797, 764, 758, 44, 43, 760, 42, 62, 759, 60, 63, 68, 770, 756, 92, 91, 91, 769, 71, 72, 76, 87, 55, 84, 77, 61, 96, 103, 95, 104, 103, 108, 111, 99, 107, 736, 779, 151, 797, 778, 169, 173, 179, 182, 185, 194, 197, 752, 180, 185, 193, 181, 194, 202, 214, 241, 75, 797, 773, 797, 769, 768, 763, 742, 759, 758, 136, 743, 756, 749, 754, 734, 738, 740, 742, 746, 728, 724, 729, 732, 732, 151, 734, 162, 729, 735, 726, 726, 738, 736, 725, 735, 723, 225, 224, 143, 704, 693, 703, 698, 683, 686, 683, 685, 697, 682, 162, 679, 673, 676, 675, 685, 679, 678, 180, 671, 666, 172, 668, 683, 192, 668, 670, 663, 229, 672, 676, 679, 678, 664, 670, 662, 203, 655, 658, 653, 235, 797, 654, 710, 797, 212, 797, 797, 709, 274, 264, 265, 269, 277, 247, 282, 283, 285, 293, 294, 797, 708, 0, 797, 701, 700, 693, 679, 678, 672, 673, 672, 666, 670, 679, 671, 671, 679, 663, 677, 675, 674, 660, 659, 671, 674, 646, 668, 660, 652, 666, 660, 655, 656, 657, 648, 659, 647, 650, 254, 626, 631, 616, 625, 618, 610, 608, 615, 611, 605, 608, 604, 609, 601, 601, 604, 598, 597, 598, 596, 601, 606, 607, 591, 797, 590, 591, 797, 596, 601, 590, 602, 592, 584, 582, 588, 584, 585, 272, 578, 591, 590, 580, 590, 589, 587, 582, 586, 571, 578, 567, 797, 580, 564, 574, 573, 562, 266, 303, 299, 595, 308, 311, 309, 797, 590, 603, 602, 603, 594, 797, 600, 600, 582, 580, 593, 797, 569, 591, 583, 572, 592, 573, 797, 575, 306, 587, 797, 588, 573, 572, 797, 797, 569, 570, 568, 797, 574, 304, 797, 540, 536, 535, 546, 545, 531, 533, 542, 797, 541, 527, 539, 534, 541, 536, 797, 797, 797, 539, 534, 533, 568, 530, 526, 797, 529, 528, 531, 517, 520, 797, 510, 511, 518, 511, 524, 509, 797, 515, 510, 518, 797, 515, 514, 503, 498, 497, 496, 500, 505, 797, 495, 499, 491, 797, 797, 548, 317, 535, 320, 321, 797, 527, 529, 524, 528, 514, 509, 797, 528, 509, 514, 509, 797, 524, 517, 518, 797, 513, 520, 501, 507, 505, 503, 797, 501, 500, 508, 797, 797, 480, 468, 797, 478, 469, 467, 463, 797, 475, 471, 468, 472, 454, 797, 470, 293, 461, 460, 464, 466, 450, 450, 462, 461, 464, 457, 446, 446, 460, 797, 455, 440, 452, 797, 444, 797, 436, 437, 449, 797, 435, 440, 797, 463, 333, 797, 797, 464, 462, 467, 466, 465, 456, 471, 797, 459, 465, 452, 461, 449, 797, 797, 438, 797, 452, 447, 440, 433, 797, 429, 797, 797, 797, 797, 418, 417, 797, 425, 797, 424, 419, 412, 421, 416, 797, 404, 404, 419, 404, 408, 405, 797, 797, 406, 401, 797, 396, 797, 402, 405, 797, 408, 407, 797, 332, 434, 421, 433, 422, 421, 411, 417, 421, 797, 797, 424, 412, 341, 797, 410, 797, 388, 797, 394, 393, 797, 391, 389, 380, 797, 379, 376, 387, 372, 797, 797, 797, 381, 374, 376, 797, 380, 382, 381, 395, 797, 404, 403, 797, 797, 797, 797, 408, 386, 392, 391, 403, 392, 375, 797, 370, 369, 353, 363, 353, 355, 363, 350, 797, 359, 348, 797, 356, 797, 797, 797, 386, 797, 388, 388, 371, 373, 376, 384, 367, 797, 797, 797, 336, 797, 797, 797, 797, 340, 334, 333, 797, 367, 366, 360, 358, 370, 371, 368, 797, 339, 797, 338, 365, 341, 343, 332, 347, 344, 339, 313, 311, 797, 797, 338, 322, 293, 278, 277, 797, 797, 253, 224, 209, 797, 161, 138, 123, 797, 101, 69, 797, 797, 797, 797, 371, 374, 376, 378, 381 } ; static yyconst short int yy_def[645] = { 0, 639, 1, 1, 3, 639, 639, 639, 639, 639, 640, 641, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 642, 639, 639, 639, 643, 643, 643, 643, 643, 643, 643, 639, 60, 60, 60, 60, 60, 60, 60, 642, 639, 639, 640, 639, 639, 644, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 642, 639, 639, 639, 639, 639, 60, 60, 60, 60, 60, 639, 60, 60, 60, 60, 60, 639, 642, 69, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 60, 60, 639, 60, 60, 60, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 60, 639, 60, 60, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 60, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 60, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 0, 639, 639, 639, 639, 639 } ; static yyconst short int yy_nxt[862] = { 0, 6, 7, 8, 9, 7, 10, 6, 6, 11, 12, 12, 6, 13, 14, 15, 16, 17, 18, 19, 20, 21, 6, 22, 6, 6, 23, 24, 25, 26, 27, 28, 29, 30, 6, 6, 31, 6, 6, 32, 6, 6, 6, 33, 34, 35, 36, 37, 38, 6, 39, 6, 6, 6, 40, 41, 42, 43, 44, 45, 46, 47, 48, 6, 49, 50, 79, 70, 84, 69, 70, 85, 81, 80, 82, 89, 107, 70, 91, 90, 70, 86, 92, 94, 108, 51, 52, 53, 54, 51, 55, 87, 93, 56, 56, 55, 57, 95, 58, 59, 60, 638, 61, 62, 128, 55, 63, 98, 55, 64, 104, 99, 122, 65, 101, 66, 67, 123, 129, 68, 126, 100, 105, 55, 102, 103, 109, 124, 127, 637, 113, 110, 111, 114, 117, 115, 112, 118, 116, 130, 125, 119, 137, 131, 120, 134, 135, 132, 139, 121, 141, 143, 138, 133, 145, 636, 148, 142, 149, 144, 136, 146, 140, 150, 179, 151, 155, 180, 147, 635, 92, 70, 157, 158, 159, 639, 157, 158, 195, 196, 93, 639, 157, 158, 639, 157, 158, 639, 157, 158, 634, 198, 161, 199, 210, 161, 639, 157, 158, 639, 157, 158, 160, 160, 211, 222, 165, 160, 166, 85, 97, 162, 90, 88, 639, 160, 160, 167, 223, 163, 235, 104, 639, 639, 160, 78, 80, 168, 103, 169, 107, 639, 209, 105, 231, 236, 160, 108, 108, 232, 239, 633, 267, 639, 170, 171, 172, 240, 172, 241, 191, 172, 172, 172, 172, 632, 172, 172, 172, 308, 258, 172, 259, 172, 172, 270, 172, 172, 183, 365, 366, 172, 245, 172, 172, 246, 70, 172, 161, 159, 263, 172, 631, 264, 247, 248, 160, 160, 249, 265, 250, 160, 269, 639, 639, 309, 160, 271, 639, 160, 630, 189, 268, 639, 160, 160, 639, 160, 272, 308, 629, 639, 639, 203, 639, 160, 160, 346, 367, 347, 273, 160, 639, 639, 388, 160, 628, 277, 639, 283, 160, 160, 639, 160, 369, 370, 389, 639, 639, 160, 639, 627, 160, 160, 444, 309, 639, 479, 371, 639, 639, 394, 480, 504, 160, 160, 626, 625, 554, 624, 623, 639, 639, 622, 621, 620, 619, 618, 555, 520, 556, 557, 72, 72, 72, 74, 74, 153, 153, 153, 160, 160, 174, 174, 617, 616, 615, 614, 613, 612, 611, 610, 609, 608, 607, 606, 605, 604, 603, 602, 601, 600, 599, 598, 597, 596, 595, 594, 593, 592, 591, 590, 589, 588, 587, 586, 585, 584, 583, 582, 581, 580, 579, 578, 577, 576, 575, 574, 573, 572, 571, 570, 569, 568, 567, 566, 565, 564, 563, 562, 561, 560, 559, 558, 553, 552, 551, 550, 549, 548, 547, 546, 545, 544, 543, 542, 541, 540, 539, 538, 537, 536, 535, 534, 533, 532, 531, 530, 529, 528, 527, 526, 525, 524, 523, 522, 521, 520, 519, 518, 517, 516, 515, 514, 513, 512, 511, 510, 509, 508, 507, 506, 505, 503, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 487, 486, 485, 484, 483, 482, 481, 478, 477, 476, 475, 474, 473, 472, 471, 470, 469, 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, 458, 457, 456, 455, 454, 453, 452, 451, 450, 449, 448, 447, 446, 445, 443, 365, 442, 441, 440, 439, 438, 437, 436, 435, 434, 433, 432, 431, 430, 429, 428, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, 415, 414, 413, 412, 411, 410, 409, 408, 407, 406, 405, 404, 403, 402, 401, 400, 399, 398, 397, 396, 395, 394, 393, 392, 391, 390, 387, 386, 385, 384, 383, 382, 381, 380, 379, 378, 377, 376, 375, 374, 373, 372, 371, 368, 364, 363, 362, 361, 360, 359, 358, 357, 356, 355, 354, 353, 352, 351, 350, 349, 348, 345, 344, 343, 342, 341, 340, 339, 338, 337, 336, 335, 334, 333, 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, 322, 321, 320, 319, 318, 317, 316, 315, 314, 313, 312, 311, 310, 307, 306, 305, 304, 303, 302, 301, 300, 299, 298, 297, 296, 295, 294, 293, 292, 291, 290, 289, 288, 287, 286, 285, 284, 283, 282, 281, 280, 279, 278, 277, 276, 275, 274, 274, 170, 157, 154, 266, 262, 261, 260, 257, 256, 255, 254, 253, 252, 251, 244, 243, 242, 238, 237, 234, 233, 230, 229, 228, 227, 226, 225, 224, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 208, 207, 206, 205, 204, 203, 202, 201, 200, 197, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 178, 177, 176, 76, 175, 173, 73, 164, 156, 154, 152, 106, 97, 96, 88, 83, 78, 77, 76, 76, 75, 73, 71, 639, 5, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639 } ; static yyconst short int yy_chk[862] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 17, 7, 20, 4, 7, 20, 18, 17, 18, 23, 32, 70, 24, 23, 70, 21, 24, 25, 32, 2, 3, 3, 3, 4, 3, 21, 24, 3, 3, 3, 3, 25, 3, 3, 3, 635, 3, 3, 39, 3, 3, 28, 3, 3, 30, 28, 36, 3, 29, 3, 3, 36, 39, 3, 38, 28, 30, 3, 29, 29, 33, 37, 38, 634, 34, 33, 33, 34, 35, 34, 33, 35, 34, 40, 37, 35, 42, 40, 35, 41, 41, 40, 43, 35, 44, 45, 42, 40, 46, 632, 47, 44, 47, 45, 41, 46, 43, 48, 80, 48, 51, 80, 46, 631, 51, 54, 54, 54, 54, 55, 55, 55, 95, 95, 51, 56, 56, 56, 57, 57, 57, 58, 58, 58, 630, 97, 56, 97, 109, 57, 59, 59, 59, 60, 60, 60, 62, 65, 109, 120, 62, 63, 64, 62, 65, 58, 64, 63, 63, 64, 66, 66, 120, 60, 131, 67, 64, 66, 67, 59, 60, 66, 66, 68, 107, 67, 108, 67, 128, 131, 68, 108, 107, 128, 134, 628, 155, 68, 69, 69, 69, 134, 69, 134, 155, 69, 69, 69, 69, 627, 69, 69, 69, 209, 146, 69, 146, 69, 69, 164, 69, 69, 164, 267, 267, 69, 138, 69, 69, 138, 159, 69, 161, 159, 150, 69, 626, 150, 138, 138, 160, 161, 138, 150, 138, 162, 163, 160, 161, 209, 159, 165, 162, 163, 623, 166, 162, 159, 165, 166, 163, 167, 168, 308, 622, 165, 166, 167, 167, 168, 169, 248, 268, 248, 169, 269, 168, 169, 295, 268, 621, 269, 269, 271, 271, 273, 268, 272, 272, 273, 295, 271, 273, 367, 272, 620, 369, 370, 370, 308, 367, 415, 367, 369, 370, 369, 415, 444, 504, 444, 619, 616, 517, 615, 614, 504, 444, 613, 612, 611, 610, 609, 517, 504, 517, 517, 640, 640, 640, 641, 641, 642, 642, 642, 643, 643, 644, 644, 608, 607, 605, 603, 602, 601, 600, 599, 598, 597, 595, 594, 593, 588, 584, 583, 582, 581, 580, 579, 578, 576, 572, 570, 569, 567, 566, 565, 564, 563, 562, 561, 560, 558, 557, 556, 555, 554, 553, 552, 547, 546, 544, 543, 542, 541, 539, 538, 537, 533, 532, 531, 530, 528, 527, 526, 524, 523, 521, 519, 516, 515, 512, 511, 510, 509, 508, 507, 506, 505, 502, 501, 499, 498, 496, 494, 493, 490, 489, 488, 487, 486, 485, 483, 482, 481, 480, 479, 477, 475, 474, 469, 467, 466, 465, 464, 462, 459, 458, 457, 456, 455, 453, 452, 451, 450, 449, 448, 447, 443, 441, 440, 438, 437, 436, 434, 432, 431, 430, 428, 427, 426, 425, 424, 423, 422, 421, 420, 419, 418, 417, 416, 414, 412, 411, 410, 409, 408, 406, 405, 404, 403, 401, 400, 397, 396, 395, 393, 392, 391, 390, 389, 388, 386, 385, 384, 382, 381, 380, 379, 377, 376, 375, 374, 373, 372, 368, 366, 363, 362, 361, 359, 358, 357, 356, 355, 354, 353, 352, 350, 349, 348, 346, 345, 344, 343, 342, 341, 339, 338, 337, 336, 335, 333, 332, 331, 330, 329, 328, 324, 323, 322, 321, 320, 319, 317, 316, 315, 314, 313, 312, 311, 310, 307, 305, 304, 303, 300, 299, 298, 296, 294, 292, 291, 290, 289, 288, 287, 285, 284, 283, 282, 281, 279, 278, 277, 276, 275, 270, 266, 265, 264, 263, 262, 260, 259, 258, 257, 256, 255, 254, 253, 252, 251, 250, 249, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 236, 235, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, 208, 207, 206, 205, 204, 203, 202, 201, 200, 199, 198, 197, 196, 195, 194, 193, 192, 191, 190, 189, 188, 187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 171, 158, 153, 152, 149, 148, 147, 145, 144, 143, 142, 141, 140, 139, 137, 136, 135, 133, 132, 130, 129, 127, 126, 125, 124, 123, 122, 121, 119, 118, 117, 116, 115, 114, 113, 112, 111, 110, 106, 105, 104, 103, 102, 101, 100, 99, 98, 96, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 79, 78, 77, 76, 75, 74, 72, 61, 53, 50, 49, 31, 27, 26, 22, 19, 16, 15, 13, 12, 11, 10, 9, 5, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639, 639 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 char *yytext; #define INITIAL 0 /* SCCS Id: @(#)lev_lex.c 3.4 2002/03/27 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #define LEV_LEX_C #include "hack.h" #include "lev_comp.h" #include "sp_lev.h" /* Most of these don't exist in flex, yywrap is macro and * yyunput is properly declared in flex.skel. */ #if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) int FDECL(yyback, (int *,int)); int NDECL(yylook); int NDECL(yyinput); int NDECL(yywrap); int NDECL(yylex); /* Traditional lexes let yyunput() and yyoutput() default to int; * newer ones may declare them as void since they don't return * values. For even more fun, the lex supplied as part of the * newer unbundled compiler for SunOS 4.x adds the void declarations * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain * int) while the bundled lex and the one with the older unbundled * compiler do not. To detect this, we need help from outside -- * sys/unix/Makefile.utl. * * Digital UNIX is difficult and still has int in spite of all * other signs. */ # if defined(NeXT) || defined(SVR4) || defined(_AIX32) # define VOIDYYPUT # endif # if !defined(VOIDYYPUT) && defined(POSIX_TYPES) # if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) # define VOIDYYPUT # endif # endif # if !defined(VOIDYYPUT) && defined(WEIRD_LEX) # if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) # define VOIDYYPUT # endif # endif # if defined(VOIDYYPUT) && defined(__osf__) # undef VOIDYYPUT # endif # ifdef VOIDYYPUT void FDECL(yyunput, (int)); void FDECL(yyoutput, (int)); # else int FDECL(yyunput, (int)); int FDECL(yyoutput, (int)); # endif #endif /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ #ifdef FLEX_SCANNER #define YY_MALLOC_DECL \ genericptr_t FDECL(malloc, (size_t)); \ genericptr_t FDECL(realloc, (genericptr_t,size_t)); #endif void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); /* * This doesn't always get put in lev_comp.h * (esp. when using older versions of bison). */ extern YYSTYPE yylval; int line_number = 1, colon_line_number = 1; static char map[4096]; static int map_cnt = 0; #define MAPC 1 /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP extern int NDECL(yywrap); #endif #ifndef YY_NO_UNPUT static void FDECL(yyunput, (int,char *)); #endif #ifndef yytext_ptr static void FDECL(yy_flex_strncpy, (char *,const char *,int)); #endif #ifndef YY_NO_INPUT static int NDECL(input); #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( yy_current_buffer->yy_is_interactive ) \ { \ int c = '*', n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ if ( yyleng > 0 ) \ yy_current_buffer->yy_at_bol = \ (yytext[yyleng - 1] == '\n'); \ YY_USER_ACTION int NDECL(yylex); int yylex() { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; if ( yy_init ) { yy_init = 0; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! yy_start ) yy_start = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! yy_current_buffer ) yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); yy_load_buffer_state(); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = yy_c_buf_p; /* Support of yytext. */ *yy_cp = yy_hold_char; /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = yy_start; yy_current_state += YY_AT_BOL(); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 640 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 797 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = yy_hold_char; yy_cp = yy_last_accepting_cpos; yy_current_state = yy_last_accepting_state; goto yy_find_action; case 1: YY_RULE_SETUP { BEGIN(INITIAL); yylval.map = (char *) alloc(map_cnt + 1); (void) strncpy(yylval.map, map, map_cnt); yylval.map[map_cnt] = 0; map_cnt = 0; return MAP_ID; } YY_BREAK case 2: YY_RULE_SETUP { int len = yyleng; /* convert \r\n to \n */ if (len >= 2 && yytext[len - 2] == '\r') len -= 1; line_number++; (void) strncpy(map + map_cnt, yytext, len); map_cnt += len; map[map_cnt - 1] = '\n'; map[map_cnt] = '\0'; } YY_BREAK case 3: YY_RULE_SETUP { line_number++; } YY_BREAK case 4: YY_RULE_SETUP { colon_line_number = line_number; return ':'; } YY_BREAK case 5: YY_RULE_SETUP return MESSAGE_ID; YY_BREAK case 6: YY_RULE_SETUP return MAZE_ID; YY_BREAK case 7: YY_RULE_SETUP return NOMAP_ID; YY_BREAK case 8: YY_RULE_SETUP return LEVEL_ID; YY_BREAK case 9: YY_RULE_SETUP return LEV_INIT_ID; YY_BREAK case 10: YY_RULE_SETUP return FLAGS_ID; YY_BREAK case 11: YY_RULE_SETUP return GEOMETRY_ID; YY_BREAK case 12: YY_RULE_SETUP { BEGIN(MAPC); line_number++; } YY_BREAK case 13: YY_RULE_SETUP return OBJECT_ID; YY_BREAK case 14: YY_RULE_SETUP return COBJECT_ID; YY_BREAK case 15: YY_RULE_SETUP return MONSTER_ID; YY_BREAK case 16: YY_RULE_SETUP return TRAP_ID; YY_BREAK case 17: YY_RULE_SETUP return DOOR_ID; YY_BREAK case 18: YY_RULE_SETUP return DRAWBRIDGE_ID; YY_BREAK case 19: YY_RULE_SETUP return MAZEWALK_ID; YY_BREAK case 20: YY_RULE_SETUP return WALLIFY_ID; YY_BREAK case 21: YY_RULE_SETUP return REGION_ID; YY_BREAK case 22: YY_RULE_SETUP return RANDOM_OBJECTS_ID; YY_BREAK case 23: YY_RULE_SETUP return RANDOM_MONSTERS_ID; YY_BREAK case 24: YY_RULE_SETUP return RANDOM_PLACES_ID; YY_BREAK case 25: YY_RULE_SETUP return ALTAR_ID; YY_BREAK case 26: YY_RULE_SETUP return LADDER_ID; YY_BREAK case 27: YY_RULE_SETUP return STAIR_ID; YY_BREAK case 28: YY_RULE_SETUP return PORTAL_ID; YY_BREAK case 29: YY_RULE_SETUP return TELEPRT_ID; YY_BREAK case 30: YY_RULE_SETUP return BRANCH_ID; YY_BREAK case 31: YY_RULE_SETUP return FOUNTAIN_ID; YY_BREAK case 32: YY_RULE_SETUP return SINK_ID; YY_BREAK case 33: YY_RULE_SETUP return POOL_ID; YY_BREAK case 34: YY_RULE_SETUP return NON_DIGGABLE_ID; YY_BREAK case 35: YY_RULE_SETUP return NON_PASSWALL_ID; YY_BREAK case 36: YY_RULE_SETUP return ROOM_ID; YY_BREAK case 37: YY_RULE_SETUP return SUBROOM_ID; YY_BREAK case 38: YY_RULE_SETUP return RAND_CORRIDOR_ID; YY_BREAK case 39: YY_RULE_SETUP return CORRIDOR_ID; YY_BREAK case 40: YY_RULE_SETUP return GOLD_ID; YY_BREAK case 41: YY_RULE_SETUP return ENGRAVING_ID; YY_BREAK case 42: YY_RULE_SETUP return NAME_ID; YY_BREAK case 43: YY_RULE_SETUP return CHANCE_ID; YY_BREAK case 44: YY_RULE_SETUP return LEV; YY_BREAK case 45: YY_RULE_SETUP { yylval.i=D_ISOPEN; return DOOR_STATE; } YY_BREAK case 46: YY_RULE_SETUP { yylval.i=D_CLOSED; return DOOR_STATE; } YY_BREAK case 47: YY_RULE_SETUP { yylval.i=D_LOCKED; return DOOR_STATE; } YY_BREAK case 48: YY_RULE_SETUP { yylval.i=D_NODOOR; return DOOR_STATE; } YY_BREAK case 49: YY_RULE_SETUP { yylval.i=D_BROKEN; return DOOR_STATE; } YY_BREAK case 50: YY_RULE_SETUP { yylval.i=W_NORTH; return DIRECTION; } YY_BREAK case 51: YY_RULE_SETUP { yylval.i=W_EAST; return DIRECTION; } YY_BREAK case 52: YY_RULE_SETUP { yylval.i=W_SOUTH; return DIRECTION; } YY_BREAK case 53: YY_RULE_SETUP { yylval.i=W_WEST; return DIRECTION; } YY_BREAK case 54: YY_RULE_SETUP { yylval.i = -1; return RANDOM_TYPE; } YY_BREAK case 55: YY_RULE_SETUP { yylval.i = -2; return NONE; } YY_BREAK case 56: YY_RULE_SETUP return O_REGISTER; YY_BREAK case 57: YY_RULE_SETUP return M_REGISTER; YY_BREAK case 58: YY_RULE_SETUP return P_REGISTER; YY_BREAK case 59: YY_RULE_SETUP return A_REGISTER; YY_BREAK case 60: YY_RULE_SETUP { yylval.i=1; return LEFT_OR_RIGHT; } YY_BREAK case 61: YY_RULE_SETUP { yylval.i=2; return LEFT_OR_RIGHT; } YY_BREAK case 62: YY_RULE_SETUP { yylval.i=3; return CENTER; } YY_BREAK case 63: YY_RULE_SETUP { yylval.i=4; return LEFT_OR_RIGHT; } YY_BREAK case 64: YY_RULE_SETUP { yylval.i=5; return LEFT_OR_RIGHT; } YY_BREAK case 65: YY_RULE_SETUP { yylval.i=1; return TOP_OR_BOT; } YY_BREAK case 66: YY_RULE_SETUP { yylval.i=5; return TOP_OR_BOT; } YY_BREAK case 67: YY_RULE_SETUP { yylval.i=1; return LIGHT_STATE; } YY_BREAK case 68: YY_RULE_SETUP { yylval.i=0; return LIGHT_STATE; } YY_BREAK case 69: YY_RULE_SETUP { yylval.i=0; return FILLING; } YY_BREAK case 70: YY_RULE_SETUP { yylval.i=1; return FILLING; } YY_BREAK case 71: YY_RULE_SETUP { yylval.i= AM_NONE; return ALIGNMENT; } YY_BREAK case 72: YY_RULE_SETUP { yylval.i= AM_LAWFUL; return ALIGNMENT; } YY_BREAK case 73: YY_RULE_SETUP { yylval.i= AM_NEUTRAL; return ALIGNMENT; } YY_BREAK case 74: YY_RULE_SETUP { yylval.i= AM_CHAOTIC; return ALIGNMENT; } YY_BREAK case 75: YY_RULE_SETUP { yylval.i= AM_SPLEV_CO; return ALIGNMENT; } YY_BREAK case 76: YY_RULE_SETUP { yylval.i= AM_SPLEV_NONCO; return ALIGNMENT; } YY_BREAK case 77: YY_RULE_SETUP { yylval.i=1; return MON_ATTITUDE; } YY_BREAK case 78: YY_RULE_SETUP { yylval.i=0; return MON_ATTITUDE; } YY_BREAK case 79: YY_RULE_SETUP { yylval.i=1; return MON_ALERTNESS; } YY_BREAK case 80: YY_RULE_SETUP { yylval.i=0; return MON_ALERTNESS; } YY_BREAK case 81: YY_RULE_SETUP { yylval.i= M_AP_FURNITURE; return MON_APPEARANCE; } YY_BREAK case 82: YY_RULE_SETUP { yylval.i= M_AP_MONSTER; return MON_APPEARANCE; } YY_BREAK case 83: YY_RULE_SETUP { yylval.i= M_AP_OBJECT; return MON_APPEARANCE; } YY_BREAK case 84: YY_RULE_SETUP { yylval.i=2; return ALTAR_TYPE; } YY_BREAK case 85: YY_RULE_SETUP { yylval.i=1; return ALTAR_TYPE; } YY_BREAK case 86: YY_RULE_SETUP { yylval.i=0; return ALTAR_TYPE; } YY_BREAK case 87: YY_RULE_SETUP { yylval.i=1; return UP_OR_DOWN; } YY_BREAK case 88: YY_RULE_SETUP { yylval.i=0; return UP_OR_DOWN; } YY_BREAK case 89: YY_RULE_SETUP { yylval.i=0; return BOOLEAN; } YY_BREAK case 90: YY_RULE_SETUP { yylval.i=1; return BOOLEAN; } YY_BREAK case 91: YY_RULE_SETUP { yylval.i=DUST; return ENGRAVING_TYPE; } YY_BREAK case 92: YY_RULE_SETUP { yylval.i=ENGRAVE; return ENGRAVING_TYPE; } YY_BREAK case 93: YY_RULE_SETUP { yylval.i=BURN; return ENGRAVING_TYPE; } YY_BREAK case 94: YY_RULE_SETUP { yylval.i=MARK; return ENGRAVING_TYPE; } YY_BREAK case 95: YY_RULE_SETUP { yylval.i=1; return CURSE_TYPE; } YY_BREAK case 96: YY_RULE_SETUP { yylval.i=2; return CURSE_TYPE; } YY_BREAK case 97: YY_RULE_SETUP { yylval.i=3; return CURSE_TYPE; } YY_BREAK case 98: YY_RULE_SETUP { return CONTAINED; } YY_BREAK case 99: YY_RULE_SETUP { yylval.i=NOTELEPORT; return FLAG_TYPE; } YY_BREAK case 100: YY_RULE_SETUP { yylval.i=HARDFLOOR; return FLAG_TYPE; } YY_BREAK case 101: YY_RULE_SETUP { yylval.i=NOMMAP; return FLAG_TYPE; } YY_BREAK case 102: YY_RULE_SETUP { yylval.i=ARBOREAL; return FLAG_TYPE; } /* KMH */ YY_BREAK case 103: YY_RULE_SETUP { yylval.i=SHORTSIGHTED; return FLAG_TYPE; } YY_BREAK case 104: YY_RULE_SETUP { yylval.i = atoi(yytext + 1); return PERCENT; } YY_BREAK case 105: YY_RULE_SETUP { yylval.i=atoi(yytext); return INTEGER; } YY_BREAK case 106: YY_RULE_SETUP { yytext[yyleng-1] = 0; /* Discard the trailing \" */ yylval.map = (char *) alloc(strlen(yytext+1)+1); Strcpy(yylval.map, yytext+1); /* Discard the first \" */ return STRING; } YY_BREAK case 107: YY_RULE_SETUP { line_number++; } YY_BREAK case 108: YY_RULE_SETUP ; YY_BREAK case 109: YY_RULE_SETUP { yylval.i = yytext[2]; return CHAR; } YY_BREAK case 110: YY_RULE_SETUP { yylval.i = yytext[1]; return CHAR; } YY_BREAK case 111: YY_RULE_SETUP { return yytext[0]; } YY_BREAK case 112: YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(MAPC): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = yy_hold_char; if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between yy_current_buffer and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ yy_n_chars = yy_current_buffer->yy_n_chars; yy_current_buffer->yy_input_file = yyin; yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) { /* This was really a NUL. */ yy_state_type yy_next_state; yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = yytext_ptr + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++yy_c_buf_p; yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = yy_c_buf_p; goto yy_find_action; } } else switch ( yy_get_next_buffer() ) { case EOB_ACT_END_OF_FILE: { yy_did_buffer_switch_on_eof = 0; if ( yywrap() ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! yy_did_buffer_switch_on_eof ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state(); yy_cp = yy_c_buf_p; yy_bp = yytext_ptr + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: yy_c_buf_p = &yy_current_buffer->yy_ch_buf[yy_n_chars]; yy_current_state = yy_get_previous_state(); yy_cp = yy_c_buf_p; yy_bp = yytext_ptr + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer() { register char *dest = yy_current_buffer->yy_ch_buf; register char *source = yytext_ptr; register int number_to_move, i; int ret_val; if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( yy_current_buffer->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) { /* We matched a singled characater, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ yy_n_chars = 0; else { int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ #ifdef YY_USES_REJECT YY_FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); #else /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = yy_current_buffer; int yy_c_buf_p_offset = (int) (yy_c_buf_p - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int old_size = b->yy_buf_size + 2; int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yy_flex_realloc2( (genericptr_t) b->yy_ch_buf, b->yy_buf_size + 2, old_size ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1; #endif } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), yy_n_chars, num_to_read ); } if ( yy_n_chars == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart( yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; yy_current_buffer->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; yy_n_chars += number_to_move; yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state() { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = yy_start; yy_current_state += YY_AT_BOL(); for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 640 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans( yy_current_state ) yy_state_type yy_current_state; { register int yy_is_jam; register char *yy_cp = yy_c_buf_p; register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { yy_last_accepting_state = yy_current_state; yy_last_accepting_cpos = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 640 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 639); return yy_is_jam ? 0 : yy_current_state; } #ifndef YY_NO_UNPUT static void yyunput( c, yy_bp ) int c; register char *yy_bp; { register char *yy_cp = yy_c_buf_p; /* undo effects of setting up yytext */ *yy_cp = yy_hold_char; if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = yy_n_chars + 2; register char *dest = &yy_current_buffer->yy_ch_buf[ yy_current_buffer->yy_buf_size + 2]; register char *source = &yy_current_buffer->yy_ch_buf[number_to_move]; while ( source > yy_current_buffer->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); yy_n_chars = yy_current_buffer->yy_buf_size; if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; yytext_ptr = yy_bp; yy_hold_char = *yy_cp; yy_c_buf_p = yy_cp; } #endif /* ifndef YY_NO_UNPUT */ static int input() { int c; *yy_c_buf_p = yy_hold_char; if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) /* This was really a NUL. */ *yy_c_buf_p = '\0'; else { /* need more input */ yytext_ptr = yy_c_buf_p; ++yy_c_buf_p; switch ( yy_get_next_buffer() ) { case EOB_ACT_END_OF_FILE: { if ( yywrap() ) { yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; return EOF; } if ( ! yy_did_buffer_switch_on_eof ) YY_NEW_FILE; return input(); } case EOB_ACT_CONTINUE_SCAN: yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; break; case EOB_ACT_LAST_MATCH: YY_FATAL_ERROR( "unexpected last match in input()" ); } } } c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ *yy_c_buf_p = '\0'; /* preserve yytext */ yy_hold_char = *++yy_c_buf_p; yy_current_buffer->yy_at_bol = (c == '\n'); return c; } void yyrestart( input_file ) FILE *input_file; { if ( ! yy_current_buffer ) yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); yy_init_buffer( yy_current_buffer, input_file ); yy_load_buffer_state(); } void yy_switch_to_buffer( new_buffer ) YY_BUFFER_STATE new_buffer; { if ( yy_current_buffer == new_buffer ) return; if ( yy_current_buffer ) { /* Flush out information for old buffer. */ *yy_c_buf_p = yy_hold_char; yy_current_buffer->yy_buf_pos = yy_c_buf_p; yy_current_buffer->yy_n_chars = yy_n_chars; } yy_current_buffer = new_buffer; yy_load_buffer_state(); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ yy_did_buffer_switch_on_eof = 1; } void yy_load_buffer_state() { yy_n_chars = yy_current_buffer->yy_n_chars; yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; yyin = yy_current_buffer->yy_input_file; yy_hold_char = *yy_c_buf_p; } YY_BUFFER_STATE yy_create_buffer( file, size ) FILE *file; int size; { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer( b, file ); return b; } void yy_delete_buffer( b ) YY_BUFFER_STATE b; { if ( ! b ) return; if ( b == yy_current_buffer ) yy_current_buffer = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yy_flex_free( (genericptr_t) b->yy_ch_buf ); yy_flex_free( (genericptr_t) b ); } #ifndef YY_ALWAYS_INTERACTIVE #ifndef YY_NEVER_INTERACTIVE extern int FDECL(isatty, (int)); #endif #endif void yy_init_buffer( b, file ) YY_BUFFER_STATE b; FILE *file; { yy_flush_buffer( b ); b->yy_input_file = file; b->yy_fill_buffer = 1; #ifdef YY_ALWAYS_INTERACTIVE b->yy_is_interactive = 1; #else #ifdef YY_NEVER_INTERACTIVE b->yy_is_interactive = 0; #else b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; #endif #endif } void yy_flush_buffer( b ) YY_BUFFER_STATE b; { b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == yy_current_buffer ) yy_load_buffer_state(); } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error( msg ) const char msg[]; { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ yytext[yyleng] = yy_hold_char; \ yy_c_buf_p = yytext + n - YY_MORE_ADJ; \ yy_hold_char = *yy_c_buf_p; \ *yy_c_buf_p = '\0'; \ yyleng = n; \ } \ while ( 0 ) /* Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy( s1, s2, n ) char *s1; const char *s2; int n; { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif static genericptr_t yy_flex_alloc( size ) yy_size_t size; { return (genericptr_t) alloc((unsigned)size); } /* we want to avoid use of realloc(), so we require that caller supply the size of the old block of memory */ static genericptr_t yy_flex_realloc2( ptr, size, old_size ) genericptr_t ptr; yy_size_t size; int old_size; { genericptr_t outptr = yy_flex_alloc(size); if (ptr) { char *p = (char *) outptr, *q = (char *) ptr; while (--old_size >= 0) *p++ = *q++; yy_flex_free(ptr); } return outptr; } static void yy_flex_free( ptr ) genericptr_t ptr; { free( ptr ); } /*flexhack.skl*/ #ifdef AMIGA long *alloc(n) unsigned n; { return ((long *)malloc (n)); } #endif /* routine to switch to another input file; needed for flex */ void init_yyin( input_f ) FILE *input_f; { #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) if (yyin) yyrestart(input_f); else #endif yyin = input_f; } /* analogous routine (for completeness) */ void init_yyout( output_f ) FILE *output_f; { yyout = output_f; } /*lev_comp.l*/ nethack-3.4.3/sys/share/lev_yacc.c0100644000000000000000000022373507764735041015537 0ustar rootroot#ifndef lint static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93"; #endif #define YYBYACC 1 #define YYMAJOR 1 #define YYMINOR 9 #define yyclearin (yychar=(-1)) #define yyerrok (yyerrflag=0) #define YYRECOVERING (yyerrflag!=0) #define YYPREFIX "yy" /* SCCS Id: @(#)lev_yacc.c 3.4 2000/01/17 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the Level Compiler code * It may handle special mazes & special room-levels */ /* In case we're using bison in AIX. This definition must be * placed before any other C-language construct in the file * excluding comments and preprocessor directives (thanks IBM * for this wonderful feature...). * * Note: some cpps barf on this 'undefined control' (#pragma). * Addition of the leading space seems to prevent barfage for now, * and AIX will still see the directive. */ #ifdef _AIX #pragma alloca /* keep leading space! */ #endif #include "hack.h" #include "sp_lev.h" #define MAX_REGISTERS 10 #define ERR (-1) /* many types of things are put in chars for transference to NetHack. * since some systems will use signed chars, limit everybody to the * same number for portability. */ #define MAX_OF_TYPE 128 #define New(type) \ (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type)) #define NewTab(type, size) (type **) alloc(sizeof(type *) * size) #define Free(ptr) free((genericptr_t)ptr) extern void FDECL(yyerror, (const char *)); extern void FDECL(yywarning, (const char *)); extern int NDECL(yylex); int NDECL(yyparse); extern int FDECL(get_floor_type, (CHAR_P)); extern int FDECL(get_room_type, (char *)); extern int FDECL(get_trap_type, (char *)); extern int FDECL(get_monster_id, (char *,CHAR_P)); extern int FDECL(get_object_id, (char *,CHAR_P)); extern boolean FDECL(check_monster_char, (CHAR_P)); extern boolean FDECL(check_object_char, (CHAR_P)); extern char FDECL(what_map_char, (CHAR_P)); extern void FDECL(scan_map, (char *)); extern void NDECL(wallify_map); extern boolean NDECL(check_subrooms); extern void FDECL(check_coord, (int,int,const char *)); extern void NDECL(store_part); extern void NDECL(store_room); extern boolean FDECL(write_level_file, (char *,splev *,specialmaze *)); extern void FDECL(free_rooms, (splev *)); static struct reg { int x1, y1; int x2, y2; } current_region; static struct coord { int x; int y; } current_coord, current_align; static struct size { int height; int width; } current_size; char tmpmessage[256]; digpos *tmppass[32]; char *tmpmap[ROWNO]; digpos *tmpdig[MAX_OF_TYPE]; region *tmpreg[MAX_OF_TYPE]; lev_region *tmplreg[MAX_OF_TYPE]; door *tmpdoor[MAX_OF_TYPE]; drawbridge *tmpdb[MAX_OF_TYPE]; walk *tmpwalk[MAX_OF_TYPE]; room_door *tmprdoor[MAX_OF_TYPE]; trap *tmptrap[MAX_OF_TYPE]; monster *tmpmonst[MAX_OF_TYPE]; object *tmpobj[MAX_OF_TYPE]; altar *tmpaltar[MAX_OF_TYPE]; lad *tmplad[MAX_OF_TYPE]; stair *tmpstair[MAX_OF_TYPE]; gold *tmpgold[MAX_OF_TYPE]; engraving *tmpengraving[MAX_OF_TYPE]; fountain *tmpfountain[MAX_OF_TYPE]; sink *tmpsink[MAX_OF_TYPE]; pool *tmppool[MAX_OF_TYPE]; mazepart *tmppart[10]; room *tmproom[MAXNROFROOMS*2]; corridor *tmpcor[MAX_OF_TYPE]; static specialmaze maze; static splev special_lev; static lev_init init_lev; static char olist[MAX_REGISTERS], mlist[MAX_REGISTERS]; static struct coord plist[MAX_REGISTERS]; int n_olist = 0, n_mlist = 0, n_plist = 0; unsigned int nlreg = 0, nreg = 0, ndoor = 0, ntrap = 0, nmons = 0, nobj = 0; unsigned int ndb = 0, nwalk = 0, npart = 0, ndig = 0, nlad = 0, nstair = 0; unsigned int naltar = 0, ncorridor = 0, nrooms = 0, ngold = 0, nengraving = 0; unsigned int nfountain = 0, npool = 0, nsink = 0, npass = 0; static int lev_flags = 0; unsigned int max_x_map, max_y_map; static xchar in_room; extern int fatal_error; extern int want_warnings; extern const char *fname; typedef union { int i; char* map; struct { xchar room; xchar wall; xchar door; } corpos; } YYSTYPE; #define CHAR 257 #define INTEGER 258 #define BOOLEAN 259 #define PERCENT 260 #define MESSAGE_ID 261 #define MAZE_ID 262 #define LEVEL_ID 263 #define LEV_INIT_ID 264 #define GEOMETRY_ID 265 #define NOMAP_ID 266 #define OBJECT_ID 267 #define COBJECT_ID 268 #define MONSTER_ID 269 #define TRAP_ID 270 #define DOOR_ID 271 #define DRAWBRIDGE_ID 272 #define MAZEWALK_ID 273 #define WALLIFY_ID 274 #define REGION_ID 275 #define FILLING 276 #define RANDOM_OBJECTS_ID 277 #define RANDOM_MONSTERS_ID 278 #define RANDOM_PLACES_ID 279 #define ALTAR_ID 280 #define LADDER_ID 281 #define STAIR_ID 282 #define NON_DIGGABLE_ID 283 #define NON_PASSWALL_ID 284 #define ROOM_ID 285 #define PORTAL_ID 286 #define TELEPRT_ID 287 #define BRANCH_ID 288 #define LEV 289 #define CHANCE_ID 290 #define CORRIDOR_ID 291 #define GOLD_ID 292 #define ENGRAVING_ID 293 #define FOUNTAIN_ID 294 #define POOL_ID 295 #define SINK_ID 296 #define NONE 297 #define RAND_CORRIDOR_ID 298 #define DOOR_STATE 299 #define LIGHT_STATE 300 #define CURSE_TYPE 301 #define ENGRAVING_TYPE 302 #define DIRECTION 303 #define RANDOM_TYPE 304 #define O_REGISTER 305 #define M_REGISTER 306 #define P_REGISTER 307 #define A_REGISTER 308 #define ALIGNMENT 309 #define LEFT_OR_RIGHT 310 #define CENTER 311 #define TOP_OR_BOT 312 #define ALTAR_TYPE 313 #define UP_OR_DOWN 314 #define SUBROOM_ID 315 #define NAME_ID 316 #define FLAGS_ID 317 #define FLAG_TYPE 318 #define MON_ATTITUDE 319 #define MON_ALERTNESS 320 #define MON_APPEARANCE 321 #define CONTAINED 322 #define STRING 323 #define MAP_ID 324 #define YYERRCODE 256 short yylhs[] = { -1, 0, 0, 36, 36, 37, 37, 38, 39, 32, 23, 23, 14, 14, 19, 19, 20, 20, 40, 40, 45, 42, 42, 46, 46, 43, 43, 49, 49, 44, 44, 51, 52, 52, 53, 53, 35, 50, 50, 56, 54, 10, 10, 59, 59, 57, 57, 60, 60, 58, 58, 55, 55, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 61, 62, 63, 64, 15, 15, 13, 13, 12, 12, 31, 11, 11, 41, 41, 75, 76, 76, 79, 1, 1, 2, 2, 77, 77, 80, 80, 80, 47, 47, 48, 48, 81, 83, 81, 78, 78, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 99, 65, 98, 98, 100, 100, 100, 100, 100, 66, 66, 102, 101, 103, 103, 104, 104, 104, 104, 105, 105, 106, 107, 107, 108, 108, 108, 85, 67, 86, 92, 93, 94, 74, 109, 88, 110, 89, 111, 113, 90, 114, 91, 112, 112, 22, 22, 69, 70, 71, 95, 96, 87, 68, 72, 73, 25, 25, 25, 28, 28, 28, 33, 33, 34, 34, 3, 3, 4, 4, 21, 21, 21, 97, 97, 97, 5, 5, 6, 6, 7, 7, 7, 8, 8, 117, 29, 26, 9, 82, 24, 27, 30, 16, 16, 17, 17, 18, 18, 116, 115, }; short yylen[] = { 2, 0, 1, 1, 2, 1, 1, 5, 7, 3, 0, 13, 1, 1, 0, 3, 3, 1, 0, 2, 3, 0, 2, 3, 3, 0, 1, 1, 2, 1, 1, 1, 0, 2, 5, 5, 7, 2, 2, 12, 12, 0, 2, 5, 1, 5, 1, 5, 1, 5, 1, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 9, 1, 1, 1, 1, 1, 1, 5, 1, 1, 1, 2, 3, 1, 2, 5, 1, 1, 1, 1, 0, 2, 3, 3, 3, 1, 3, 1, 3, 1, 0, 4, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 10, 0, 2, 2, 2, 2, 2, 3, 2, 2, 0, 9, 1, 1, 0, 7, 5, 5, 1, 1, 1, 1, 1, 0, 2, 2, 5, 6, 7, 5, 1, 5, 5, 0, 8, 0, 8, 0, 0, 8, 0, 6, 0, 2, 1, 10, 3, 3, 3, 3, 3, 8, 7, 5, 7, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 2, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 5, 9, }; short yydefred[] = { 0, 0, 0, 0, 0, 0, 2, 0, 5, 6, 0, 0, 0, 0, 0, 4, 214, 0, 9, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 21, 76, 77, 75, 0, 0, 0, 0, 81, 7, 0, 88, 0, 19, 0, 16, 0, 20, 0, 79, 0, 82, 0, 0, 0, 0, 0, 22, 26, 0, 51, 51, 0, 84, 85, 0, 0, 0, 0, 0, 89, 0, 0, 0, 0, 31, 8, 29, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 103, 105, 112, 113, 118, 119, 117, 101, 104, 106, 107, 108, 109, 110, 111, 114, 115, 116, 120, 121, 213, 0, 23, 212, 0, 24, 191, 0, 190, 0, 0, 33, 0, 0, 0, 0, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 0, 87, 86, 83, 90, 92, 0, 91, 0, 211, 218, 0, 131, 132, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 198, 199, 0, 197, 0, 0, 195, 196, 0, 0, 0, 0, 0, 0, 0, 156, 0, 167, 172, 173, 158, 160, 163, 215, 216, 0, 0, 169, 94, 96, 200, 201, 0, 0, 0, 0, 69, 70, 0, 67, 171, 170, 66, 0, 0, 0, 182, 0, 181, 0, 183, 179, 0, 178, 0, 180, 189, 0, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 149, 0, 0, 152, 0, 0, 204, 0, 202, 0, 203, 154, 0, 0, 0, 155, 0, 0, 0, 176, 219, 220, 0, 44, 0, 0, 46, 0, 0, 0, 35, 34, 0, 0, 221, 0, 187, 186, 133, 0, 185, 184, 0, 150, 207, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 164, 0, 0, 0, 0, 0, 0, 0, 0, 208, 0, 209, 0, 151, 0, 0, 0, 206, 205, 175, 0, 0, 0, 0, 177, 0, 48, 0, 0, 0, 50, 0, 0, 0, 71, 72, 0, 12, 13, 11, 0, 122, 0, 0, 174, 210, 0, 157, 159, 0, 162, 0, 0, 0, 0, 0, 0, 73, 74, 0, 0, 136, 135, 0, 124, 0, 0, 0, 166, 43, 0, 0, 45, 0, 0, 36, 68, 0, 134, 0, 0, 0, 0, 0, 0, 40, 0, 39, 142, 141, 143, 0, 0, 0, 125, 222, 194, 0, 47, 42, 49, 0, 0, 127, 128, 0, 129, 126, 168, 145, 144, 0, 0, 0, 130, 0, 0, 139, 140, 0, 147, 148, 138, }; short yydgoto[] = { 3, 65, 163, 265, 135, 210, 240, 306, 371, 307, 437, 33, 411, 388, 391, 246, 233, 171, 319, 13, 25, 396, 223, 21, 132, 262, 263, 129, 257, 258, 136, 4, 5, 339, 335, 243, 6, 7, 8, 9, 28, 39, 44, 56, 76, 29, 57, 130, 133, 58, 59, 77, 78, 139, 60, 80, 61, 325, 384, 322, 380, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 40, 41, 50, 69, 42, 70, 167, 168, 204, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 224, 431, 416, 446, 172, 362, 415, 430, 443, 444, 464, 469, 277, 279, 280, 402, 375, 281, 225, 214, 215, }; short yysindex[] = { -166, -18, 4, 0, -233, -233, 0, -166, 0, 0, -222, -222, 32, -134, -134, 0, 0, 88, 0, -173, 76, -114, -114, -230, 105, 0, -99, 115, -124, -114, 0, 0, 0, 0, -173, 127, -143, 128, 0, 0, -124, 0, -132, 0, -236, 0, -67, 0, -155, 0, -156, 0, 137, 138, 140, 142, -94, 0, 0, -263, 0, 0, 161, 0, 0, 162, 149, 150, 151, -105, 0, -47, -46, -276, -276, 0, 0, 0, -79, 0, -142, -142, -45, -151, -47, -46, 173, -44, -44, -44, -44, 160, 163, 165, 0, 166, 167, 168, 170, 171, 172, 174, 175, 176, 177, 178, 179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 187, 0, 0, 194, 0, 0, 195, 0, 197, 184, 0, 185, 186, 188, 189, 190, 191, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 206, 0, 0, 0, 0, 0, -43, 0, 0, 0, 0, 193, 0, 0, 196, 198, -239, 45, 45, 180, 45, 45, 58, 180, 180, -37, -37, -37, -232, 45, 45, -47, -46, -218, -218, 205, -238, 45, -41, 45, 45, -222, -6, 211, 213, -234, -237, -268, 0, 0, 214, 0, 169, 215, 0, 0, 217, -39, 218, 219, 220, 225, 12, 0, 296, 0, 0, 0, 0, 0, 0, 0, 0, 300, 306, 0, 0, 0, 0, 0, 317, 319, 112, 329, 0, 0, 341, 0, 0, 0, 0, 342, 129, 173, 0, 315, 0, 366, 0, 0, 320, 0, 368, 0, 0, 374, 0, 45, 200, 120, 124, 385, -218, -201, 116, 202, 389, 390, 118, 399, 401, 405, 45, -254, -38, -9, 407, -36, -239, -218, 411, 0, 207, -267, 238, -260, 45, 0, 360, 410, 0, 239, 412, 0, 386, 0, 415, 0, 0, 454, 242, -37, 0, -37, -37, -37, 0, 0, 0, 457, 0, 246, 492, 0, 279, 495, 237, 0, 0, 497, 498, 0, 456, 0, 0, 0, 458, 0, 0, 506, 0, 0, -239, 509, -276, 298, -259, 299, 72, 510, 517, 0, 0, -222, 518, -1, 519, 28, 520, -119, -227, 0, 522, 0, 45, 0, 316, 531, 483, 0, 0, 0, 533, 264, -222, 537, 0, 321, 0, -155, 539, 328, 0, 330, 543, -229, 0, 0, 545, 0, 0, 0, 38, 0, 546, 318, 0, 0, 333, 0, 0, 281, 0, 552, 555, 28, 559, 557, -222, 0, 0, 561, -229, 0, 0, 560, 0, 338, 563, 566, 0, 0, -151, 571, 0, 345, 571, 0, 0, -243, 0, 575, 579, 362, 367, 585, 371, 0, 586, 0, 0, 0, 0, 590, 591, -209, 0, 0, 0, 597, 0, 0, 0, -240, -228, 0, 0, -222, 0, 0, 0, 0, 0, 595, 599, 599, 0, -228, -264, 0, 0, 599, 0, 0, 0, }; short yyrindex[] = { 641, 0, 0, 0, -172, 307, 0, 645, 0, 0, 0, 0, 0, -146, 355, 0, 0, 0, 0, 0, 0, -72, 351, 0, 282, 0, 0, 0, 0, 346, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 104, 0, 0, 0, 157, 0, 0, 0, 0, 0, 491, 0, 0, 0, 0, 0, 57, 0, 0, 159, 0, 0, 0, 0, 0, 0, 0, 0, 0, 91, 0, 0, 0, 0, 0, 0, 0, 0, 106, 0, 267, 388, 0, 0, 0, 0, 0, 589, 589, 589, 589, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 201, 0, 0, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 446, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 535, 0, 0, 0, 0, 0, 0, 0, 572, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 606, 0, 0, 0, 0, 146, 0, 0, 146, 0, 0, 0, 0, 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109, 109, 0, 0, 0, 0, 0, 109, 0, 0, 0, }; short yygindex[] = { 0, 269, 230, 0, -60, -269, -184, 209, 0, 0, 229, 0, 244, 0, 0, 0, 0, 113, 0, 652, 624, 0, -178, 646, 453, 0, 0, 459, 0, 0, -10, 0, 0, 0, 0, 375, 656, 0, 0, 0, 24, 625, 0, 0, 0, 0, 0, -73, -68, 608, 0, 0, 0, 0, 0, 607, 0, 0, 266, 0, 0, 0, 0, 0, 0, 600, 603, 605, 609, 611, 0, 0, 612, 613, 614, 0, 0, 0, 0, 0, 0, 422, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -165, 0, 0, 0, 588, 0, 0, 0, 0, 224, -416, -384, 0, 0, 0, 0, 0, 0, -40, -81, 0, }; #define YYTABLESIZE 900 short yytable[] = { 17, 18, 321, 217, 242, 169, 137, 228, 229, 230, 241, 164, 213, 216, 137, 219, 220, 165, 461, 329, 131, 244, 54, 128, 234, 235, 231, 31, 134, 409, 461, 324, 389, 472, 248, 249, 264, 333, 465, 379, 10, 52, 53, 123, 337, 369, 30, 16, 317, 54, 318, 471, 55, 43, 370, 16, 16, 32, 440, 473, 208, 441, 11, 16, 462, 209, 245, 259, 383, 260, 254, 255, 232, 365, 32, 410, 462, 390, 166, 55, 442, 470, 238, 442, 12, 166, 239, 474, 302, 14, 19, 80, 14, 14, 14, 303, 1, 2, 222, 304, 305, 16, 297, 303, 78, 330, 30, 304, 305, 146, 455, 456, 457, 331, 16, 10, 366, 316, 236, 10, 10, 66, 67, 68, 237, 87, 88, 89, 90, 140, 20, 340, 23, 349, 26, 350, 351, 352, 96, 218, 141, 37, 38, 226, 227, 24, 41, 27, 142, 34, 104, 105, 106, 143, 144, 63, 64, 25, 35, 27, 161, 162, 87, 88, 89, 90, 91, 92, 93, 94, 95, 46, 169, 36, 145, 96, 97, 98, 99, 100, 47, 101, 102, 103, 386, 387, 48, 104, 105, 106, 62, 250, 51, 18, 18, 71, 72, 266, 73, 393, 74, 93, 174, 175, 75, 82, 83, 84, 85, 86, 128, 131, 138, 166, 160, 203, 170, 247, 176, 271, 217, 177, 327, 178, 179, 180, 181, 414, 182, 183, 184, 191, 185, 186, 187, 188, 189, 190, 192, 193, 95, 194, 195, 196, 197, 242, 198, 199, 200, 201, 202, 205, 221, 251, 206, 252, 207, 253, 267, 269, 268, 270, 272, 273, 274, 275, 320, 37, 137, 137, 276, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, 17, 334, 367, 338, 137, 137, 137, 137, 137, 137, 137, 137, 137, 323, 137, 137, 137, 137, 137, 137, 137, 378, 137, 123, 123, 14, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 123, 32, 32, 137, 137, 123, 123, 123, 123, 123, 123, 123, 123, 123, 382, 123, 123, 123, 123, 123, 123, 123, 278, 123, 211, 376, 282, 212, 18, 221, 32, 211, 283, 18, 212, 80, 80, 10, 80, 80, 123, 123, 413, 284, 211, 285, 400, 212, 78, 78, 30, 30, 286, 146, 146, 287, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 288, 289, 290, 38, 146, 146, 146, 146, 146, 146, 146, 146, 146, 426, 146, 146, 146, 146, 146, 146, 146, 292, 146, 41, 41, 293, 294, 295, 41, 41, 41, 41, 41, 296, 25, 25, 27, 27, 299, 146, 146, 41, 300, 41, 301, 308, 41, 312, 310, 311, 459, 41, 41, 41, 41, 41, 41, 41, 313, 41, 314, 97, 466, 25, 315, 27, 326, 331, 341, 342, 25, 344, 27, 298, 346, 309, 41, 41, 93, 93, 332, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 345, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 93, 98, 100, 93, 93, 93, 93, 336, 343, 347, 93, 348, 353, 95, 95, 354, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 93, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 37, 37, 95, 95, 95, 95, 192, 355, 356, 95, 357, 358, 359, 360, 17, 17, 17, 17, 17, 17, 361, 364, 363, 37, 366, 373, 95, 368, 372, 37, 17, 17, 374, 377, 381, 385, 37, 392, 17, 14, 14, 14, 14, 165, 17, 394, 395, 397, 398, 399, 403, 17, 401, 37, 405, 14, 14, 406, 408, 407, 412, 417, 419, 14, 421, 418, 420, 432, 17, 14, 422, 424, 425, 427, 438, 429, 14, 193, 433, 18, 18, 434, 18, 18, 18, 18, 436, 10, 10, 10, 445, 447, 448, 14, 18, 18, 449, 450, 452, 18, 18, 451, 18, 10, 10, 453, 454, 18, 18, 460, 467, 10, 1, 18, 468, 18, 3, 10, 217, 404, 18, 38, 38, 435, 10, 458, 439, 428, 14, 45, 261, 22, 18, 328, 15, 256, 49, 18, 79, 81, 107, 10, 423, 108, 38, 109, 291, 173, 463, 110, 38, 111, 112, 113, 114, 0, 0, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 38, 0, 0, 0, 0, 97, 97, 0, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, 0, 97, 97, 97, 97, 97, 97, 97, 97, 0, 97, 97, 97, 0, 0, 0, 97, 97, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100, 100, 0, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100, 0, 0, 0, 0, 100, 100, 100, 100, 100, 0, 100, 100, 100, 0, 0, 0, 100, 100, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, 192, 0, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 0, 0, 0, 0, 192, 192, 192, 192, 192, 0, 192, 192, 192, 0, 0, 0, 192, 192, 192, 0, 0, 0, 0, 165, 165, 0, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 0, 0, 0, 0, 165, 165, 165, 165, 165, 0, 165, 165, 165, 0, 0, 0, 165, 165, 165, 0, 193, 193, 0, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 193, 0, 0, 0, 0, 193, 193, 193, 193, 193, 0, 193, 193, 193, 0, 0, 0, 193, 193, 193, }; short yycheck[] = { 10, 11, 40, 40, 40, 86, 0, 185, 186, 187, 194, 84, 177, 178, 74, 180, 181, 85, 258, 288, 257, 259, 285, 257, 189, 190, 258, 257, 304, 258, 258, 40, 259, 297, 199, 200, 304, 304, 454, 40, 58, 277, 278, 0, 304, 304, 22, 323, 302, 285, 304, 467, 315, 29, 313, 323, 323, 0, 301, 323, 299, 304, 58, 323, 304, 304, 304, 304, 40, 306, 304, 305, 304, 342, 304, 304, 304, 304, 40, 315, 323, 465, 300, 323, 317, 40, 304, 471, 272, 261, 58, 0, 264, 265, 266, 304, 262, 263, 40, 308, 309, 323, 267, 304, 0, 289, 0, 308, 309, 0, 319, 320, 321, 41, 323, 261, 44, 282, 191, 265, 266, 277, 278, 279, 192, 267, 268, 269, 270, 271, 264, 296, 44, 311, 58, 313, 314, 315, 280, 179, 282, 265, 266, 183, 184, 318, 0, 261, 290, 44, 292, 293, 294, 295, 296, 310, 311, 0, 257, 0, 311, 312, 267, 268, 269, 270, 271, 272, 273, 274, 275, 44, 253, 58, 316, 280, 281, 282, 283, 284, 323, 286, 287, 288, 303, 304, 58, 292, 293, 294, 257, 201, 324, 265, 266, 58, 58, 207, 58, 364, 58, 0, 89, 90, 298, 44, 44, 58, 58, 58, 257, 257, 291, 40, 259, 258, 260, 258, 58, 258, 40, 58, 258, 58, 58, 58, 58, 392, 58, 58, 58, 44, 58, 58, 58, 58, 58, 58, 44, 44, 0, 44, 58, 58, 58, 40, 58, 58, 58, 58, 44, 58, 289, 259, 58, 44, 58, 44, 44, 44, 91, 44, 44, 44, 44, 40, 304, 0, 262, 263, 258, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 0, 293, 344, 295, 280, 281, 282, 283, 284, 285, 286, 287, 288, 304, 290, 291, 292, 293, 294, 295, 296, 304, 298, 262, 263, 0, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 262, 263, 315, 316, 280, 281, 282, 283, 284, 285, 286, 287, 288, 304, 290, 291, 292, 293, 294, 295, 296, 44, 298, 304, 353, 44, 307, 0, 289, 291, 304, 44, 0, 307, 262, 263, 0, 265, 266, 315, 316, 322, 44, 304, 44, 374, 307, 262, 263, 262, 263, 258, 262, 263, 44, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 44, 44, 258, 0, 280, 281, 282, 283, 284, 285, 286, 287, 288, 408, 290, 291, 292, 293, 294, 295, 296, 91, 298, 262, 263, 44, 91, 44, 267, 268, 269, 270, 271, 44, 262, 263, 262, 263, 303, 315, 316, 280, 303, 282, 44, 314, 285, 314, 44, 44, 445, 290, 291, 292, 293, 294, 295, 296, 44, 298, 44, 0, 457, 291, 44, 291, 44, 41, 93, 44, 298, 44, 298, 258, 44, 258, 315, 316, 262, 263, 258, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 91, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 44, 0, 291, 292, 293, 294, 258, 258, 44, 298, 258, 44, 262, 263, 258, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 315, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 262, 263, 291, 292, 293, 294, 0, 44, 258, 298, 44, 303, 44, 44, 261, 262, 263, 264, 265, 266, 93, 44, 93, 285, 44, 44, 315, 258, 258, 291, 277, 278, 44, 44, 44, 44, 298, 44, 285, 261, 262, 263, 264, 0, 291, 258, 44, 93, 44, 314, 258, 298, 44, 315, 44, 277, 278, 258, 44, 258, 44, 44, 258, 285, 41, 276, 314, 258, 315, 291, 44, 41, 44, 41, 258, 44, 298, 0, 44, 262, 263, 44, 265, 266, 262, 263, 44, 261, 262, 263, 44, 41, 259, 315, 277, 278, 258, 41, 41, 277, 278, 259, 285, 277, 278, 44, 44, 285, 291, 41, 44, 285, 0, 291, 44, 298, 0, 291, 58, 379, 298, 262, 263, 422, 298, 445, 426, 412, 5, 34, 206, 14, 315, 287, 7, 205, 40, 315, 59, 61, 69, 315, 405, 69, 285, 69, 253, 88, 453, 69, 291, 69, 69, 69, 69, -1, -1, 298, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 315, -1, -1, -1, -1, 262, 263, -1, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, -1, 277, 278, 279, 280, 281, 282, 283, 284, -1, 286, 287, 288, -1, -1, -1, 292, 293, 294, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 262, 263, -1, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, -1, -1, -1, -1, 280, 281, 282, 283, 284, -1, 286, 287, 288, -1, -1, -1, 292, 293, 294, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 262, 263, -1, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, -1, -1, -1, -1, 280, 281, 282, 283, 284, -1, 286, 287, 288, -1, -1, -1, 292, 293, 294, -1, -1, -1, -1, 262, 263, -1, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, -1, -1, -1, -1, 280, 281, 282, 283, 284, -1, 286, 287, 288, -1, -1, -1, 292, 293, 294, -1, 262, 263, -1, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, -1, -1, -1, -1, 280, 281, 282, 283, 284, -1, 286, 287, 288, -1, -1, -1, 292, 293, 294, }; #define YYFINAL 3 #ifndef YYDEBUG #define YYDEBUG 0 #endif #define YYMAXTOKEN 324 #if YYDEBUG char *yyname[] = { "end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,"'('","')'",0,0,"','",0,0,0,0,0,0,0,0,0,0,0,0,0,"':'",0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'['",0,"']'",0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"CHAR", "INTEGER","BOOLEAN","PERCENT","MESSAGE_ID","MAZE_ID","LEVEL_ID","LEV_INIT_ID", "GEOMETRY_ID","NOMAP_ID","OBJECT_ID","COBJECT_ID","MONSTER_ID","TRAP_ID", "DOOR_ID","DRAWBRIDGE_ID","MAZEWALK_ID","WALLIFY_ID","REGION_ID","FILLING", "RANDOM_OBJECTS_ID","RANDOM_MONSTERS_ID","RANDOM_PLACES_ID","ALTAR_ID", "LADDER_ID","STAIR_ID","NON_DIGGABLE_ID","NON_PASSWALL_ID","ROOM_ID", "PORTAL_ID","TELEPRT_ID","BRANCH_ID","LEV","CHANCE_ID","CORRIDOR_ID","GOLD_ID", "ENGRAVING_ID","FOUNTAIN_ID","POOL_ID","SINK_ID","NONE","RAND_CORRIDOR_ID", "DOOR_STATE","LIGHT_STATE","CURSE_TYPE","ENGRAVING_TYPE","DIRECTION", "RANDOM_TYPE","O_REGISTER","M_REGISTER","P_REGISTER","A_REGISTER","ALIGNMENT", "LEFT_OR_RIGHT","CENTER","TOP_OR_BOT","ALTAR_TYPE","UP_OR_DOWN","SUBROOM_ID", "NAME_ID","FLAGS_ID","FLAG_TYPE","MON_ATTITUDE","MON_ALERTNESS", "MON_APPEARANCE","CONTAINED","STRING","MAP_ID", }; char *yyrule[] = { "$accept : file", "file :", "file : levels", "levels : level", "levels : level levels", "level : maze_level", "level : room_level", "maze_level : maze_def flags lev_init messages regions", "room_level : level_def flags lev_init messages rreg_init rooms corridors_def", "level_def : LEVEL_ID ':' string", "lev_init :", "lev_init : LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled", "walled : BOOLEAN", "walled : RANDOM_TYPE", "flags :", "flags : FLAGS_ID ':' flag_list", "flag_list : FLAG_TYPE ',' flag_list", "flag_list : FLAG_TYPE", "messages :", "messages : message messages", "message : MESSAGE_ID ':' STRING", "rreg_init :", "rreg_init : rreg_init init_rreg", "init_rreg : RANDOM_OBJECTS_ID ':' object_list", "init_rreg : RANDOM_MONSTERS_ID ':' monster_list", "rooms :", "rooms : roomlist", "roomlist : aroom", "roomlist : aroom roomlist", "corridors_def : random_corridors", "corridors_def : corridors", "random_corridors : RAND_CORRIDOR_ID", "corridors :", "corridors : corridors corridor", "corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec", "corridor : CORRIDOR_ID ':' corr_spec ',' INTEGER", "corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')'", "aroom : room_def room_details", "aroom : subroom_def room_details", "subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill", "room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill", "roomfill :", "roomfill : ',' BOOLEAN", "room_pos : '(' INTEGER ',' INTEGER ')'", "room_pos : RANDOM_TYPE", "subroom_pos : '(' INTEGER ',' INTEGER ')'", "subroom_pos : RANDOM_TYPE", "room_align : '(' h_justif ',' v_justif ')'", "room_align : RANDOM_TYPE", "room_size : '(' INTEGER ',' INTEGER ')'", "room_size : RANDOM_TYPE", "room_details :", "room_details : room_details room_detail", "room_detail : room_name", "room_detail : room_chance", "room_detail : room_door", "room_detail : monster_detail", "room_detail : object_detail", "room_detail : trap_detail", "room_detail : altar_detail", "room_detail : fountain_detail", "room_detail : sink_detail", "room_detail : pool_detail", "room_detail : gold_detail", "room_detail : engraving_detail", "room_detail : stair_detail", "room_name : NAME_ID ':' string", "room_chance : CHANCE_ID ':' INTEGER", "room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos", "secret : BOOLEAN", "secret : RANDOM_TYPE", "door_wall : DIRECTION", "door_wall : RANDOM_TYPE", "door_pos : INTEGER", "door_pos : RANDOM_TYPE", "maze_def : MAZE_ID ':' string ',' filling", "filling : CHAR", "filling : RANDOM_TYPE", "regions : aregion", "regions : aregion regions", "aregion : map_definition reg_init map_details", "map_definition : NOMAP_ID", "map_definition : map_geometry MAP_ID", "map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif", "h_justif : LEFT_OR_RIGHT", "h_justif : CENTER", "v_justif : TOP_OR_BOT", "v_justif : CENTER", "reg_init :", "reg_init : reg_init init_reg", "init_reg : RANDOM_OBJECTS_ID ':' object_list", "init_reg : RANDOM_PLACES_ID ':' place_list", "init_reg : RANDOM_MONSTERS_ID ':' monster_list", "object_list : object", "object_list : object ',' object_list", "monster_list : monster", "monster_list : monster ',' monster_list", "place_list : place", "$$1 :", "place_list : place $$1 ',' place_list", "map_details :", "map_details : map_details map_detail", "map_detail : monster_detail", "map_detail : object_detail", "map_detail : door_detail", "map_detail : trap_detail", "map_detail : drawbridge_detail", "map_detail : region_detail", "map_detail : stair_region", "map_detail : portal_region", "map_detail : teleprt_region", "map_detail : branch_region", "map_detail : altar_detail", "map_detail : fountain_detail", "map_detail : mazewalk_detail", "map_detail : wallify_detail", "map_detail : ladder_detail", "map_detail : stair_detail", "map_detail : gold_detail", "map_detail : engraving_detail", "map_detail : diggable_detail", "map_detail : passwall_detail", "$$2 :", "monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate $$2 monster_infos", "monster_infos :", "monster_infos : monster_infos monster_info", "monster_info : ',' string", "monster_info : ',' MON_ATTITUDE", "monster_info : ',' MON_ALERTNESS", "monster_info : ',' alignment", "monster_info : ',' MON_APPEARANCE string", "object_detail : OBJECT_ID object_desc", "object_detail : COBJECT_ID object_desc", "$$3 :", "object_desc : chance ':' object_c ',' o_name $$3 ',' object_where object_infos", "object_where : coordinate", "object_where : CONTAINED", "object_infos :", "object_infos : ',' curse_state ',' monster_id ',' enchantment optional_name", "object_infos : ',' curse_state ',' enchantment optional_name", "object_infos : ',' monster_id ',' enchantment optional_name", "curse_state : RANDOM_TYPE", "curse_state : CURSE_TYPE", "monster_id : STRING", "enchantment : RANDOM_TYPE", "enchantment : INTEGER", "optional_name :", "optional_name : ',' NONE", "optional_name : ',' STRING", "door_detail : DOOR_ID ':' door_state ',' coordinate", "trap_detail : TRAP_ID chance ':' trap_name ',' coordinate", "drawbridge_detail : DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state", "mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION", "wallify_detail : WALLIFY_ID", "ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN", "stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN", "$$4 :", "stair_region : STAIR_ID ':' lev_region $$4 ',' lev_region ',' UP_OR_DOWN", "$$5 :", "portal_region : PORTAL_ID ':' lev_region $$5 ',' lev_region ',' string", "$$6 :", "$$7 :", "teleprt_region : TELEPRT_ID ':' lev_region $$6 ',' lev_region $$7 teleprt_detail", "$$8 :", "branch_region : BRANCH_ID ':' lev_region $$8 ',' lev_region", "teleprt_detail :", "teleprt_detail : ',' UP_OR_DOWN", "lev_region : region", "lev_region : LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'", "fountain_detail : FOUNTAIN_ID ':' coordinate", "sink_detail : SINK_ID ':' coordinate", "pool_detail : POOL_ID ':' coordinate", "diggable_detail : NON_DIGGABLE_ID ':' region", "passwall_detail : NON_PASSWALL_ID ':' region", "region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled", "altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type", "gold_detail : GOLD_ID ':' amount ',' coordinate", "engraving_detail : ENGRAVING_ID ':' coordinate ',' engraving_type ',' string", "monster_c : monster", "monster_c : RANDOM_TYPE", "monster_c : m_register", "object_c : object", "object_c : RANDOM_TYPE", "object_c : o_register", "m_name : string", "m_name : RANDOM_TYPE", "o_name : string", "o_name : RANDOM_TYPE", "trap_name : string", "trap_name : RANDOM_TYPE", "room_type : string", "room_type : RANDOM_TYPE", "prefilled :", "prefilled : ',' FILLING", "prefilled : ',' FILLING ',' BOOLEAN", "coordinate : coord", "coordinate : p_register", "coordinate : RANDOM_TYPE", "door_state : DOOR_STATE", "door_state : RANDOM_TYPE", "light_state : LIGHT_STATE", "light_state : RANDOM_TYPE", "alignment : ALIGNMENT", "alignment : a_register", "alignment : RANDOM_TYPE", "altar_type : ALTAR_TYPE", "altar_type : RANDOM_TYPE", "p_register : P_REGISTER '[' INTEGER ']'", "o_register : O_REGISTER '[' INTEGER ']'", "m_register : M_REGISTER '[' INTEGER ']'", "a_register : A_REGISTER '[' INTEGER ']'", "place : coord", "monster : CHAR", "object : CHAR", "string : STRING", "amount : INTEGER", "amount : RANDOM_TYPE", "chance :", "chance : PERCENT", "engraving_type : ENGRAVING_TYPE", "engraving_type : RANDOM_TYPE", "coord : '(' INTEGER ',' INTEGER ')'", "region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')'", }; #endif #ifdef YYSTACKSIZE #undef YYMAXDEPTH #define YYMAXDEPTH YYSTACKSIZE #else #ifdef YYMAXDEPTH #define YYSTACKSIZE YYMAXDEPTH #else #define YYSTACKSIZE 500 #define YYMAXDEPTH 500 #endif #endif int yydebug; int yynerrs; int yyerrflag; int yychar; short *yyssp; YYSTYPE *yyvsp; YYSTYPE yyval; YYSTYPE yylval; short yyss[YYSTACKSIZE]; YYSTYPE yyvs[YYSTACKSIZE]; #define yystacksize YYSTACKSIZE /*lev_comp.y*/ #define YYABORT goto yyabort #define YYREJECT goto yyabort #define YYACCEPT goto yyaccept #define YYERROR goto yyerrlab int yyparse() { register int yym, yyn, yystate; #if YYDEBUG register char *yys; extern char *getenv(); if ((yys = getenv("YYDEBUG")) != 0) { yyn = *yys; if (yyn >= '0' && yyn <= '9') yydebug = yyn - '0'; } #endif yynerrs = 0; yyerrflag = 0; yychar = (-1); yyssp = yyss; yyvsp = yyvs; *yyssp = yystate = 0; yyloop: if ((yyn = yydefred[yystate]) != 0) goto yyreduce; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif } if ((yyn = yysindex[yystate]) != 0 && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, shifting to state %d\n", YYPREFIX, yystate, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; yychar = (-1); if (yyerrflag > 0) --yyerrflag; goto yyloop; } if ((yyn = yyrindex[yystate]) != 0 && (yyn += yychar) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yychar) { yyn = yytable[yyn]; goto yyreduce; } if (yyerrflag) goto yyinrecovery; #ifdef lint goto yynewerror; #endif yynewerror: yyerror("syntax error"); #ifdef lint goto yyerrlab; #endif yyerrlab: ++yynerrs; yyinrecovery: if (yyerrflag < 3) { yyerrflag = 3; for (;;) { if ((yyn = yysindex[*yyssp]) != 0 && (yyn += YYERRCODE) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) { #if YYDEBUG if (yydebug) printf("%sdebug: state %d, error recovery shifting\ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate = yytable[yyn]; *++yyvsp = yylval; goto yyloop; } else { #if YYDEBUG if (yydebug) printf("%sdebug: error recovery discarding state %d\n", YYPREFIX, *yyssp); #endif if (yyssp <= yyss) goto yyabort; --yyssp; --yyvsp; } } } else { if (yychar == 0) goto yyabort; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, error recovery discards token %d (%s)\n", YYPREFIX, yystate, yychar, yys); } #endif yychar = (-1); goto yyloop; } yyreduce: #if YYDEBUG if (yydebug) printf("%sdebug: state %d, reducing by rule %d (%s)\n", YYPREFIX, yystate, yyn, yyrule[yyn]); #endif yym = yylen[yyn]; yyval = yyvsp[1-yym]; switch (yyn) { case 7: { unsigned i; if (fatal_error > 0) { (void) fprintf(stderr, "%s : %d errors detected. No output created!\n", fname, fatal_error); } else { maze.flags = yyvsp[-3].i; (void) memcpy((genericptr_t)&(maze.init_lev), (genericptr_t)&(init_lev), sizeof(lev_init)); maze.numpart = npart; maze.parts = NewTab(mazepart, npart); for(i=0;i 0) { (void) fprintf(stderr, "%s : %d errors detected. No output created!\n", fname, fatal_error); } else { special_lev.flags = (long) yyvsp[-5].i; (void) memcpy( (genericptr_t)&(special_lev.init_lev), (genericptr_t)&(init_lev), sizeof(lev_init)); special_lev.nroom = nrooms; special_lev.rooms = NewTab(room, nrooms); for(i=0; i 8) yyerror("Level names limited to 8 characters."); yyval.map = yyvsp[0].map; special_lev.nrmonst = special_lev.nrobjects = 0; n_mlist = n_olist = 0; } break; case 10: { /* in case we're processing multiple files, explicitly clear any stale settings */ (void) memset((genericptr_t) &init_lev, 0, sizeof init_lev); init_lev.init_present = FALSE; yyval.i = 0; } break; case 11: { init_lev.init_present = TRUE; init_lev.fg = what_map_char((char) yyvsp[-10].i); if (init_lev.fg == INVALID_TYPE) yyerror("Invalid foreground type."); init_lev.bg = what_map_char((char) yyvsp[-8].i); if (init_lev.bg == INVALID_TYPE) yyerror("Invalid background type."); init_lev.smoothed = yyvsp[-6].i; init_lev.joined = yyvsp[-4].i; if (init_lev.joined && init_lev.fg != CORR && init_lev.fg != ROOM) yyerror("Invalid foreground type for joined map."); init_lev.lit = yyvsp[-2].i; init_lev.walled = yyvsp[0].i; yyval.i = 1; } break; case 14: { yyval.i = 0; } break; case 15: { yyval.i = lev_flags; lev_flags = 0; /* clear for next user */ } break; case 16: { lev_flags |= yyvsp[-2].i; } break; case 17: { lev_flags |= yyvsp[0].i; } break; case 20: { int i, j; i = (int) strlen(yyvsp[0].map) + 1; j = (int) strlen(tmpmessage); if (i + j > 255) { yyerror("Message string too long (>256 characters)"); } else { if (j) tmpmessage[j++] = '\n'; (void) strncpy(tmpmessage+j, yyvsp[0].map, i - 1); tmpmessage[j + i - 1] = 0; } Free(yyvsp[0].map); } break; case 23: { if(special_lev.nrobjects) { yyerror("Object registers already initialized!"); } else { special_lev.nrobjects = n_olist; special_lev.robjects = (char *) alloc(n_olist); (void) memcpy((genericptr_t)special_lev.robjects, (genericptr_t)olist, n_olist); } } break; case 24: { if(special_lev.nrmonst) { yyerror("Monster registers already initialized!"); } else { special_lev.nrmonst = n_mlist; special_lev.rmonst = (char *) alloc(n_mlist); (void) memcpy((genericptr_t)special_lev.rmonst, (genericptr_t)mlist, n_mlist); } } break; case 25: { tmproom[nrooms] = New(room); tmproom[nrooms]->name = (char *) 0; tmproom[nrooms]->parent = (char *) 0; tmproom[nrooms]->rtype = 0; tmproom[nrooms]->rlit = 0; tmproom[nrooms]->xalign = ERR; tmproom[nrooms]->yalign = ERR; tmproom[nrooms]->x = 0; tmproom[nrooms]->y = 0; tmproom[nrooms]->w = 2; tmproom[nrooms]->h = 2; in_room = 1; } break; case 31: { tmpcor[0] = New(corridor); tmpcor[0]->src.room = -1; ncorridor = 1; } break; case 34: { tmpcor[ncorridor] = New(corridor); tmpcor[ncorridor]->src.room = yyvsp[-2].corpos.room; tmpcor[ncorridor]->src.wall = yyvsp[-2].corpos.wall; tmpcor[ncorridor]->src.door = yyvsp[-2].corpos.door; tmpcor[ncorridor]->dest.room = yyvsp[0].corpos.room; tmpcor[ncorridor]->dest.wall = yyvsp[0].corpos.wall; tmpcor[ncorridor]->dest.door = yyvsp[0].corpos.door; ncorridor++; if (ncorridor >= MAX_OF_TYPE) { yyerror("Too many corridors in level!"); ncorridor--; } } break; case 35: { tmpcor[ncorridor] = New(corridor); tmpcor[ncorridor]->src.room = yyvsp[-2].corpos.room; tmpcor[ncorridor]->src.wall = yyvsp[-2].corpos.wall; tmpcor[ncorridor]->src.door = yyvsp[-2].corpos.door; tmpcor[ncorridor]->dest.room = -1; tmpcor[ncorridor]->dest.wall = yyvsp[0].i; ncorridor++; if (ncorridor >= MAX_OF_TYPE) { yyerror("Too many corridors in level!"); ncorridor--; } } break; case 36: { if ((unsigned) yyvsp[-5].i >= nrooms) yyerror("Wrong room number!"); yyval.corpos.room = yyvsp[-5].i; yyval.corpos.wall = yyvsp[-3].i; yyval.corpos.door = yyvsp[-1].i; } break; case 37: { store_room(); } break; case 38: { store_room(); } break; case 39: { tmproom[nrooms] = New(room); tmproom[nrooms]->parent = yyvsp[-1].map; tmproom[nrooms]->name = (char *) 0; tmproom[nrooms]->rtype = yyvsp[-9].i; tmproom[nrooms]->rlit = yyvsp[-7].i; tmproom[nrooms]->filled = yyvsp[0].i; tmproom[nrooms]->xalign = ERR; tmproom[nrooms]->yalign = ERR; tmproom[nrooms]->x = current_coord.x; tmproom[nrooms]->y = current_coord.y; tmproom[nrooms]->w = current_size.width; tmproom[nrooms]->h = current_size.height; in_room = 1; } break; case 40: { tmproom[nrooms] = New(room); tmproom[nrooms]->name = (char *) 0; tmproom[nrooms]->parent = (char *) 0; tmproom[nrooms]->rtype = yyvsp[-9].i; tmproom[nrooms]->rlit = yyvsp[-7].i; tmproom[nrooms]->filled = yyvsp[0].i; tmproom[nrooms]->xalign = current_align.x; tmproom[nrooms]->yalign = current_align.y; tmproom[nrooms]->x = current_coord.x; tmproom[nrooms]->y = current_coord.y; tmproom[nrooms]->w = current_size.width; tmproom[nrooms]->h = current_size.height; in_room = 1; } break; case 41: { yyval.i = 1; } break; case 42: { yyval.i = yyvsp[0].i; } break; case 43: { if ( yyvsp[-3].i < 1 || yyvsp[-3].i > 5 || yyvsp[-1].i < 1 || yyvsp[-1].i > 5 ) { yyerror("Room position should be between 1 & 5!"); } else { current_coord.x = yyvsp[-3].i; current_coord.y = yyvsp[-1].i; } } break; case 44: { current_coord.x = current_coord.y = ERR; } break; case 45: { if ( yyvsp[-3].i < 0 || yyvsp[-1].i < 0) { yyerror("Invalid subroom position !"); } else { current_coord.x = yyvsp[-3].i; current_coord.y = yyvsp[-1].i; } } break; case 46: { current_coord.x = current_coord.y = ERR; } break; case 47: { current_align.x = yyvsp[-3].i; current_align.y = yyvsp[-1].i; } break; case 48: { current_align.x = current_align.y = ERR; } break; case 49: { current_size.width = yyvsp[-3].i; current_size.height = yyvsp[-1].i; } break; case 50: { current_size.height = current_size.width = ERR; } break; case 66: { if (tmproom[nrooms]->name) yyerror("This room already has a name!"); else tmproom[nrooms]->name = yyvsp[0].map; } break; case 67: { if (tmproom[nrooms]->chance) yyerror("This room already assigned a chance!"); else if (tmproom[nrooms]->rtype == OROOM) yyerror("Only typed rooms can have a chance!"); else if (yyvsp[0].i < 1 || yyvsp[0].i > 99) yyerror("The chance is supposed to be percentile."); else tmproom[nrooms]->chance = yyvsp[0].i; } break; case 68: { /* ERR means random here */ if (yyvsp[-2].i == ERR && yyvsp[0].i != ERR) { yyerror("If the door wall is random, so must be its pos!"); } else { tmprdoor[ndoor] = New(room_door); tmprdoor[ndoor]->secret = yyvsp[-6].i; tmprdoor[ndoor]->mask = yyvsp[-4].i; tmprdoor[ndoor]->wall = yyvsp[-2].i; tmprdoor[ndoor]->pos = yyvsp[0].i; ndoor++; if (ndoor >= MAX_OF_TYPE) { yyerror("Too many doors in room!"); ndoor--; } } } break; case 75: { maze.filling = (schar) yyvsp[0].i; if (index(yyvsp[-2].map, '.')) yyerror("Invalid dot ('.') in level name."); if ((int) strlen(yyvsp[-2].map) > 8) yyerror("Level names limited to 8 characters."); yyval.map = yyvsp[-2].map; in_room = 0; n_plist = n_mlist = n_olist = 0; } break; case 76: { yyval.i = get_floor_type((char)yyvsp[0].i); } break; case 77: { yyval.i = -1; } break; case 80: { store_part(); } break; case 81: { tmppart[npart] = New(mazepart); tmppart[npart]->halign = 1; tmppart[npart]->valign = 1; tmppart[npart]->nrobjects = 0; tmppart[npart]->nloc = 0; tmppart[npart]->nrmonst = 0; tmppart[npart]->xsize = 1; tmppart[npart]->ysize = 1; tmppart[npart]->map = (char **) alloc(sizeof(char *)); tmppart[npart]->map[0] = (char *) alloc(1); tmppart[npart]->map[0][0] = STONE; max_x_map = COLNO-1; max_y_map = ROWNO; } break; case 82: { tmppart[npart] = New(mazepart); tmppart[npart]->halign = yyvsp[-1].i % 10; tmppart[npart]->valign = yyvsp[-1].i / 10; tmppart[npart]->nrobjects = 0; tmppart[npart]->nloc = 0; tmppart[npart]->nrmonst = 0; scan_map(yyvsp[0].map); Free(yyvsp[0].map); } break; case 83: { yyval.i = yyvsp[-2].i + (yyvsp[0].i * 10); } break; case 90: { if (tmppart[npart]->nrobjects) { yyerror("Object registers already initialized!"); } else { tmppart[npart]->robjects = (char *)alloc(n_olist); (void) memcpy((genericptr_t)tmppart[npart]->robjects, (genericptr_t)olist, n_olist); tmppart[npart]->nrobjects = n_olist; } } break; case 91: { if (tmppart[npart]->nloc) { yyerror("Location registers already initialized!"); } else { register int i; tmppart[npart]->rloc_x = (char *) alloc(n_plist); tmppart[npart]->rloc_y = (char *) alloc(n_plist); for(i=0;irloc_x[i] = plist[i].x; tmppart[npart]->rloc_y[i] = plist[i].y; } tmppart[npart]->nloc = n_plist; } } break; case 92: { if (tmppart[npart]->nrmonst) { yyerror("Monster registers already initialized!"); } else { tmppart[npart]->rmonst = (char *) alloc(n_mlist); (void) memcpy((genericptr_t)tmppart[npart]->rmonst, (genericptr_t)mlist, n_mlist); tmppart[npart]->nrmonst = n_mlist; } } break; case 93: { if (n_olist < MAX_REGISTERS) olist[n_olist++] = yyvsp[0].i; else yyerror("Object list too long!"); } break; case 94: { if (n_olist < MAX_REGISTERS) olist[n_olist++] = yyvsp[-2].i; else yyerror("Object list too long!"); } break; case 95: { if (n_mlist < MAX_REGISTERS) mlist[n_mlist++] = yyvsp[0].i; else yyerror("Monster list too long!"); } break; case 96: { if (n_mlist < MAX_REGISTERS) mlist[n_mlist++] = yyvsp[-2].i; else yyerror("Monster list too long!"); } break; case 97: { if (n_plist < MAX_REGISTERS) plist[n_plist++] = current_coord; else yyerror("Location list too long!"); } break; case 98: { if (n_plist < MAX_REGISTERS) plist[n_plist++] = current_coord; else yyerror("Location list too long!"); } break; case 122: { tmpmonst[nmons] = New(monster); tmpmonst[nmons]->x = current_coord.x; tmpmonst[nmons]->y = current_coord.y; tmpmonst[nmons]->class = yyvsp[-4].i; tmpmonst[nmons]->peaceful = -1; /* no override */ tmpmonst[nmons]->asleep = -1; tmpmonst[nmons]->align = - MAX_REGISTERS - 2; tmpmonst[nmons]->name.str = 0; tmpmonst[nmons]->appear = 0; tmpmonst[nmons]->appear_as.str = 0; tmpmonst[nmons]->chance = yyvsp[-6].i; tmpmonst[nmons]->id = NON_PM; if (!in_room) check_coord(current_coord.x, current_coord.y, "Monster"); if (yyvsp[-2].map) { int token = get_monster_id(yyvsp[-2].map, (char) yyvsp[-4].i); if (token == ERR) yywarning( "Invalid monster name! Making random monster."); else tmpmonst[nmons]->id = token; Free(yyvsp[-2].map); } } break; case 123: { if (++nmons >= MAX_OF_TYPE) { yyerror("Too many monsters in room or mazepart!"); nmons--; } } break; case 126: { tmpmonst[nmons]->name.str = yyvsp[0].map; } break; case 127: { tmpmonst[nmons]->peaceful = yyvsp[0].i; } break; case 128: { tmpmonst[nmons]->asleep = yyvsp[0].i; } break; case 129: { tmpmonst[nmons]->align = yyvsp[0].i; } break; case 130: { tmpmonst[nmons]->appear = yyvsp[-1].i; tmpmonst[nmons]->appear_as.str = yyvsp[0].map; } break; case 131: { } break; case 132: { /* 1: is contents of preceeding object with 2 */ /* 2: is a container */ /* 0: neither */ tmpobj[nobj-1]->containment = 2; } break; case 133: { tmpobj[nobj] = New(object); tmpobj[nobj]->class = yyvsp[-2].i; tmpobj[nobj]->corpsenm = NON_PM; tmpobj[nobj]->curse_state = -1; tmpobj[nobj]->name.str = 0; tmpobj[nobj]->chance = yyvsp[-4].i; tmpobj[nobj]->id = -1; if (yyvsp[0].map) { int token = get_object_id(yyvsp[0].map, yyvsp[-2].i); if (token == ERR) yywarning( "Illegal object name! Making random object."); else tmpobj[nobj]->id = token; Free(yyvsp[0].map); } } break; case 134: { if (++nobj >= MAX_OF_TYPE) { yyerror("Too many objects in room or mazepart!"); nobj--; } } break; case 135: { tmpobj[nobj]->containment = 0; tmpobj[nobj]->x = current_coord.x; tmpobj[nobj]->y = current_coord.y; if (!in_room) check_coord(current_coord.x, current_coord.y, "Object"); } break; case 136: { tmpobj[nobj]->containment = 1; /* random coordinate, will be overridden anyway */ tmpobj[nobj]->x = -MAX_REGISTERS-1; tmpobj[nobj]->y = -MAX_REGISTERS-1; } break; case 137: { tmpobj[nobj]->spe = -127; /* Note below: we're trying to make as many of these optional as * possible. We clearly can't make curse_state, enchantment, and * monster_id _all_ optional, since ",random" would be ambiguous. * We can't even just make enchantment mandatory, since if we do that * alone, ",random" requires too much lookahead to parse. */ } break; case 138: { } break; case 139: { } break; case 140: { } break; case 141: { tmpobj[nobj]->curse_state = -1; } break; case 142: { tmpobj[nobj]->curse_state = yyvsp[0].i; } break; case 143: { int token = get_monster_id(yyvsp[0].map, (char)0); if (token == ERR) /* "random" */ tmpobj[nobj]->corpsenm = NON_PM - 1; else tmpobj[nobj]->corpsenm = token; Free(yyvsp[0].map); } break; case 144: { tmpobj[nobj]->spe = -127; } break; case 145: { tmpobj[nobj]->spe = yyvsp[0].i; } break; case 147: { } break; case 148: { tmpobj[nobj]->name.str = yyvsp[0].map; } break; case 149: { tmpdoor[ndoor] = New(door); tmpdoor[ndoor]->x = current_coord.x; tmpdoor[ndoor]->y = current_coord.y; tmpdoor[ndoor]->mask = yyvsp[-2].i; if(current_coord.x >= 0 && current_coord.y >= 0 && tmpmap[current_coord.y][current_coord.x] != DOOR && tmpmap[current_coord.y][current_coord.x] != SDOOR) yyerror("Door decl doesn't match the map"); ndoor++; if (ndoor >= MAX_OF_TYPE) { yyerror("Too many doors in mazepart!"); ndoor--; } } break; case 150: { tmptrap[ntrap] = New(trap); tmptrap[ntrap]->x = current_coord.x; tmptrap[ntrap]->y = current_coord.y; tmptrap[ntrap]->type = yyvsp[-2].i; tmptrap[ntrap]->chance = yyvsp[-4].i; if (!in_room) check_coord(current_coord.x, current_coord.y, "Trap"); if (++ntrap >= MAX_OF_TYPE) { yyerror("Too many traps in room or mazepart!"); ntrap--; } } break; case 151: { int x, y, dir; tmpdb[ndb] = New(drawbridge); x = tmpdb[ndb]->x = current_coord.x; y = tmpdb[ndb]->y = current_coord.y; /* convert dir from a DIRECTION to a DB_DIR */ dir = yyvsp[-2].i; switch(dir) { case W_NORTH: dir = DB_NORTH; y--; break; case W_SOUTH: dir = DB_SOUTH; y++; break; case W_EAST: dir = DB_EAST; x++; break; case W_WEST: dir = DB_WEST; x--; break; default: yyerror("Invalid drawbridge direction"); break; } tmpdb[ndb]->dir = dir; if (current_coord.x >= 0 && current_coord.y >= 0 && !IS_WALL(tmpmap[y][x])) { char ebuf[60]; Sprintf(ebuf, "Wall needed for drawbridge (%02d, %02d)", current_coord.x, current_coord.y); yyerror(ebuf); } if ( yyvsp[0].i == D_ISOPEN ) tmpdb[ndb]->db_open = 1; else if ( yyvsp[0].i == D_CLOSED ) tmpdb[ndb]->db_open = 0; else yyerror("A drawbridge can only be open or closed!"); ndb++; if (ndb >= MAX_OF_TYPE) { yyerror("Too many drawbridges in mazepart!"); ndb--; } } break; case 152: { tmpwalk[nwalk] = New(walk); tmpwalk[nwalk]->x = current_coord.x; tmpwalk[nwalk]->y = current_coord.y; tmpwalk[nwalk]->dir = yyvsp[0].i; nwalk++; if (nwalk >= MAX_OF_TYPE) { yyerror("Too many mazewalks in mazepart!"); nwalk--; } } break; case 153: { wallify_map(); } break; case 154: { tmplad[nlad] = New(lad); tmplad[nlad]->x = current_coord.x; tmplad[nlad]->y = current_coord.y; tmplad[nlad]->up = yyvsp[0].i; if (!in_room) check_coord(current_coord.x, current_coord.y, "Ladder"); nlad++; if (nlad >= MAX_OF_TYPE) { yyerror("Too many ladders in mazepart!"); nlad--; } } break; case 155: { tmpstair[nstair] = New(stair); tmpstair[nstair]->x = current_coord.x; tmpstair[nstair]->y = current_coord.y; tmpstair[nstair]->up = yyvsp[0].i; if (!in_room) check_coord(current_coord.x, current_coord.y, "Stairway"); nstair++; if (nstair >= MAX_OF_TYPE) { yyerror("Too many stairs in room or mazepart!"); nstair--; } } break; case 156: { tmplreg[nlreg] = New(lev_region); tmplreg[nlreg]->in_islev = yyvsp[0].i; tmplreg[nlreg]->inarea.x1 = current_region.x1; tmplreg[nlreg]->inarea.y1 = current_region.y1; tmplreg[nlreg]->inarea.x2 = current_region.x2; tmplreg[nlreg]->inarea.y2 = current_region.y2; } break; case 157: { tmplreg[nlreg]->del_islev = yyvsp[-2].i; tmplreg[nlreg]->delarea.x1 = current_region.x1; tmplreg[nlreg]->delarea.y1 = current_region.y1; tmplreg[nlreg]->delarea.x2 = current_region.x2; tmplreg[nlreg]->delarea.y2 = current_region.y2; if(yyvsp[0].i) tmplreg[nlreg]->rtype = LR_UPSTAIR; else tmplreg[nlreg]->rtype = LR_DOWNSTAIR; tmplreg[nlreg]->rname.str = 0; nlreg++; if (nlreg >= MAX_OF_TYPE) { yyerror("Too many levregions in mazepart!"); nlreg--; } } break; case 158: { tmplreg[nlreg] = New(lev_region); tmplreg[nlreg]->in_islev = yyvsp[0].i; tmplreg[nlreg]->inarea.x1 = current_region.x1; tmplreg[nlreg]->inarea.y1 = current_region.y1; tmplreg[nlreg]->inarea.x2 = current_region.x2; tmplreg[nlreg]->inarea.y2 = current_region.y2; } break; case 159: { tmplreg[nlreg]->del_islev = yyvsp[-2].i; tmplreg[nlreg]->delarea.x1 = current_region.x1; tmplreg[nlreg]->delarea.y1 = current_region.y1; tmplreg[nlreg]->delarea.x2 = current_region.x2; tmplreg[nlreg]->delarea.y2 = current_region.y2; tmplreg[nlreg]->rtype = LR_PORTAL; tmplreg[nlreg]->rname.str = yyvsp[0].map; nlreg++; if (nlreg >= MAX_OF_TYPE) { yyerror("Too many levregions in mazepart!"); nlreg--; } } break; case 160: { tmplreg[nlreg] = New(lev_region); tmplreg[nlreg]->in_islev = yyvsp[0].i; tmplreg[nlreg]->inarea.x1 = current_region.x1; tmplreg[nlreg]->inarea.y1 = current_region.y1; tmplreg[nlreg]->inarea.x2 = current_region.x2; tmplreg[nlreg]->inarea.y2 = current_region.y2; } break; case 161: { tmplreg[nlreg]->del_islev = yyvsp[0].i; tmplreg[nlreg]->delarea.x1 = current_region.x1; tmplreg[nlreg]->delarea.y1 = current_region.y1; tmplreg[nlreg]->delarea.x2 = current_region.x2; tmplreg[nlreg]->delarea.y2 = current_region.y2; } break; case 162: { switch(yyvsp[0].i) { case -1: tmplreg[nlreg]->rtype = LR_TELE; break; case 0: tmplreg[nlreg]->rtype = LR_DOWNTELE; break; case 1: tmplreg[nlreg]->rtype = LR_UPTELE; break; } tmplreg[nlreg]->rname.str = 0; nlreg++; if (nlreg >= MAX_OF_TYPE) { yyerror("Too many levregions in mazepart!"); nlreg--; } } break; case 163: { tmplreg[nlreg] = New(lev_region); tmplreg[nlreg]->in_islev = yyvsp[0].i; tmplreg[nlreg]->inarea.x1 = current_region.x1; tmplreg[nlreg]->inarea.y1 = current_region.y1; tmplreg[nlreg]->inarea.x2 = current_region.x2; tmplreg[nlreg]->inarea.y2 = current_region.y2; } break; case 164: { tmplreg[nlreg]->del_islev = yyvsp[0].i; tmplreg[nlreg]->delarea.x1 = current_region.x1; tmplreg[nlreg]->delarea.y1 = current_region.y1; tmplreg[nlreg]->delarea.x2 = current_region.x2; tmplreg[nlreg]->delarea.y2 = current_region.y2; tmplreg[nlreg]->rtype = LR_BRANCH; tmplreg[nlreg]->rname.str = 0; nlreg++; if (nlreg >= MAX_OF_TYPE) { yyerror("Too many levregions in mazepart!"); nlreg--; } } break; case 165: { yyval.i = -1; } break; case 166: { yyval.i = yyvsp[0].i; } break; case 167: { yyval.i = 0; } break; case 168: { /* This series of if statements is a hack for MSC 5.1. It seems that its tiny little brain cannot compile if these are all one big if statement. */ if (yyvsp[-7].i <= 0 || yyvsp[-7].i >= COLNO) yyerror("Region out of level range!"); else if (yyvsp[-5].i < 0 || yyvsp[-5].i >= ROWNO) yyerror("Region out of level range!"); else if (yyvsp[-3].i <= 0 || yyvsp[-3].i >= COLNO) yyerror("Region out of level range!"); else if (yyvsp[-1].i < 0 || yyvsp[-1].i >= ROWNO) yyerror("Region out of level range!"); current_region.x1 = yyvsp[-7].i; current_region.y1 = yyvsp[-5].i; current_region.x2 = yyvsp[-3].i; current_region.y2 = yyvsp[-1].i; yyval.i = 1; } break; case 169: { tmpfountain[nfountain] = New(fountain); tmpfountain[nfountain]->x = current_coord.x; tmpfountain[nfountain]->y = current_coord.y; if (!in_room) check_coord(current_coord.x, current_coord.y, "Fountain"); nfountain++; if (nfountain >= MAX_OF_TYPE) { yyerror("Too many fountains in room or mazepart!"); nfountain--; } } break; case 170: { tmpsink[nsink] = New(sink); tmpsink[nsink]->x = current_coord.x; tmpsink[nsink]->y = current_coord.y; nsink++; if (nsink >= MAX_OF_TYPE) { yyerror("Too many sinks in room!"); nsink--; } } break; case 171: { tmppool[npool] = New(pool); tmppool[npool]->x = current_coord.x; tmppool[npool]->y = current_coord.y; npool++; if (npool >= MAX_OF_TYPE) { yyerror("Too many pools in room!"); npool--; } } break; case 172: { tmpdig[ndig] = New(digpos); tmpdig[ndig]->x1 = current_region.x1; tmpdig[ndig]->y1 = current_region.y1; tmpdig[ndig]->x2 = current_region.x2; tmpdig[ndig]->y2 = current_region.y2; ndig++; if (ndig >= MAX_OF_TYPE) { yyerror("Too many diggables in mazepart!"); ndig--; } } break; case 173: { tmppass[npass] = New(digpos); tmppass[npass]->x1 = current_region.x1; tmppass[npass]->y1 = current_region.y1; tmppass[npass]->x2 = current_region.x2; tmppass[npass]->y2 = current_region.y2; npass++; if (npass >= 32) { yyerror("Too many passwalls in mazepart!"); npass--; } } break; case 174: { tmpreg[nreg] = New(region); tmpreg[nreg]->x1 = current_region.x1; tmpreg[nreg]->y1 = current_region.y1; tmpreg[nreg]->x2 = current_region.x2; tmpreg[nreg]->y2 = current_region.y2; tmpreg[nreg]->rlit = yyvsp[-3].i; tmpreg[nreg]->rtype = yyvsp[-1].i; if(yyvsp[0].i & 1) tmpreg[nreg]->rtype += MAXRTYPE+1; tmpreg[nreg]->rirreg = ((yyvsp[0].i & 2) != 0); if(current_region.x1 > current_region.x2 || current_region.y1 > current_region.y2) yyerror("Region start > end!"); if(tmpreg[nreg]->rtype == VAULT && (tmpreg[nreg]->rirreg || (tmpreg[nreg]->x2 - tmpreg[nreg]->x1 != 1) || (tmpreg[nreg]->y2 - tmpreg[nreg]->y1 != 1))) yyerror("Vaults must be exactly 2x2!"); if(want_warnings && !tmpreg[nreg]->rirreg && current_region.x1 > 0 && current_region.y1 > 0 && current_region.x2 < (int)max_x_map && current_region.y2 < (int)max_y_map) { /* check for walls in the room */ char ebuf[60]; register int x, y, nrock = 0; for(y=current_region.y1; y<=current_region.y2; y++) for(x=current_region.x1; x<=current_region.x2; x++) if(IS_ROCK(tmpmap[y][x]) || IS_DOOR(tmpmap[y][x])) nrock++; if(nrock) { Sprintf(ebuf, "Rock in room (%02d,%02d,%02d,%02d)?!", current_region.x1, current_region.y1, current_region.x2, current_region.y2); yywarning(ebuf); } if ( !IS_ROCK(tmpmap[current_region.y1-1][current_region.x1-1]) || !IS_ROCK(tmpmap[current_region.y2+1][current_region.x1-1]) || !IS_ROCK(tmpmap[current_region.y1-1][current_region.x2+1]) || !IS_ROCK(tmpmap[current_region.y2+1][current_region.x2+1])) { Sprintf(ebuf, "NonRock edge in room (%02d,%02d,%02d,%02d)?!", current_region.x1, current_region.y1, current_region.x2, current_region.y2); yywarning(ebuf); } } else if(tmpreg[nreg]->rirreg && !IS_ROOM(tmpmap[current_region.y1][current_region.x1])) { char ebuf[60]; Sprintf(ebuf, "Rock in irregular room (%02d,%02d)?!", current_region.x1, current_region.y1); yyerror(ebuf); } nreg++; if (nreg >= MAX_OF_TYPE) { yyerror("Too many regions in mazepart!"); nreg--; } } break; case 175: { tmpaltar[naltar] = New(altar); tmpaltar[naltar]->x = current_coord.x; tmpaltar[naltar]->y = current_coord.y; tmpaltar[naltar]->align = yyvsp[-2].i; tmpaltar[naltar]->shrine = yyvsp[0].i; if (!in_room) check_coord(current_coord.x, current_coord.y, "Altar"); naltar++; if (naltar >= MAX_OF_TYPE) { yyerror("Too many altars in room or mazepart!"); naltar--; } } break; case 176: { tmpgold[ngold] = New(gold); tmpgold[ngold]->x = current_coord.x; tmpgold[ngold]->y = current_coord.y; tmpgold[ngold]->amount = yyvsp[-2].i; if (!in_room) check_coord(current_coord.x, current_coord.y, "Gold"); ngold++; if (ngold >= MAX_OF_TYPE) { yyerror("Too many golds in room or mazepart!"); ngold--; } } break; case 177: { tmpengraving[nengraving] = New(engraving); tmpengraving[nengraving]->x = current_coord.x; tmpengraving[nengraving]->y = current_coord.y; tmpengraving[nengraving]->engr.str = yyvsp[0].map; tmpengraving[nengraving]->etype = yyvsp[-2].i; if (!in_room) check_coord(current_coord.x, current_coord.y, "Engraving"); nengraving++; if (nengraving >= MAX_OF_TYPE) { yyerror("Too many engravings in room or mazepart!"); nengraving--; } } break; case 179: { yyval.i = - MAX_REGISTERS - 1; } break; case 182: { yyval.i = - MAX_REGISTERS - 1; } break; case 185: { yyval.map = (char *) 0; } break; case 187: { yyval.map = (char *) 0; } break; case 188: { int token = get_trap_type(yyvsp[0].map); if (token == ERR) yyerror("Unknown trap type!"); yyval.i = token; Free(yyvsp[0].map); } break; case 190: { int token = get_room_type(yyvsp[0].map); if (token == ERR) { yywarning("Unknown room type! Making ordinary room..."); yyval.i = OROOM; } else yyval.i = token; Free(yyvsp[0].map); } break; case 192: { yyval.i = 0; } break; case 193: { yyval.i = yyvsp[0].i; } break; case 194: { yyval.i = yyvsp[-2].i + (yyvsp[0].i << 1); } break; case 197: { current_coord.x = current_coord.y = -MAX_REGISTERS-1; } break; case 204: { yyval.i = - MAX_REGISTERS - 1; } break; case 207: { if ( yyvsp[-1].i >= MAX_REGISTERS ) yyerror("Register Index overflow!"); else current_coord.x = current_coord.y = - yyvsp[-1].i - 1; } break; case 208: { if ( yyvsp[-1].i >= MAX_REGISTERS ) yyerror("Register Index overflow!"); else yyval.i = - yyvsp[-1].i - 1; } break; case 209: { if ( yyvsp[-1].i >= MAX_REGISTERS ) yyerror("Register Index overflow!"); else yyval.i = - yyvsp[-1].i - 1; } break; case 210: { if ( yyvsp[-1].i >= 3 ) yyerror("Register Index overflow!"); else yyval.i = - yyvsp[-1].i - 1; } break; case 212: { if (check_monster_char((char) yyvsp[0].i)) yyval.i = yyvsp[0].i ; else { yyerror("Unknown monster class!"); yyval.i = ERR; } } break; case 213: { char c = yyvsp[0].i; if (check_object_char(c)) yyval.i = c; else { yyerror("Unknown char class!"); yyval.i = ERR; } } break; case 217: { yyval.i = 100; /* default is 100% */ } break; case 218: { if (yyvsp[0].i <= 0 || yyvsp[0].i > 100) yyerror("Expected percentile chance."); yyval.i = yyvsp[0].i; } break; case 221: { if (!in_room && !init_lev.init_present && (yyvsp[-3].i < 0 || yyvsp[-3].i > (int)max_x_map || yyvsp[-1].i < 0 || yyvsp[-1].i > (int)max_y_map)) yyerror("Coordinates out of map range!"); current_coord.x = yyvsp[-3].i; current_coord.y = yyvsp[-1].i; } break; case 222: { /* This series of if statements is a hack for MSC 5.1. It seems that its tiny little brain cannot compile if these are all one big if statement. */ if (yyvsp[-7].i < 0 || yyvsp[-7].i > (int)max_x_map) yyerror("Region out of map range!"); else if (yyvsp[-5].i < 0 || yyvsp[-5].i > (int)max_y_map) yyerror("Region out of map range!"); else if (yyvsp[-3].i < 0 || yyvsp[-3].i > (int)max_x_map) yyerror("Region out of map range!"); else if (yyvsp[-1].i < 0 || yyvsp[-1].i > (int)max_y_map) yyerror("Region out of map range!"); current_region.x1 = yyvsp[-7].i; current_region.y1 = yyvsp[-5].i; current_region.x2 = yyvsp[-3].i; current_region.y2 = yyvsp[-1].i; } break; } yyssp -= yym; yystate = *yyssp; yyvsp -= yym; yym = yylhs[yyn]; if (yystate == 0 && yym == 0) { #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state 0 to\ state %d\n", YYPREFIX, YYFINAL); #endif yystate = YYFINAL; *++yyssp = YYFINAL; *++yyvsp = yyval; if (yychar < 0) { if ((yychar = yylex()) < 0) yychar = 0; #if YYDEBUG if (yydebug) { yys = 0; if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; if (!yys) yys = "illegal-symbol"; printf("%sdebug: state %d, reading %d (%s)\n", YYPREFIX, YYFINAL, yychar, yys); } #endif } if (yychar == 0) goto yyaccept; goto yyloop; } if ((yyn = yygindex[yym]) != 0 && (yyn += yystate) >= 0 && yyn <= YYTABLESIZE && yycheck[yyn] == yystate) yystate = yytable[yyn]; else yystate = yydgoto[yym]; #if YYDEBUG if (yydebug) printf("%sdebug: after reduction, shifting from state %d \ to state %d\n", YYPREFIX, *yyssp, yystate); #endif if (yyssp >= yyss + yystacksize - 1) { goto yyoverflow; } *++yyssp = yystate; *++yyvsp = yyval; goto yyloop; yyoverflow: yyerror("yacc stack overflow"); yyabort: return (1); yyaccept: return (0); } nethack-3.4.3/sys/share/nhlan.c0100644000000000000000000001017507764735041015042 0ustar rootroot/* SCCS Id: @(#)nhlan.c 3.4 1999/11/21 */ /* Copyright (c) Michael Allison, 1997 */ /* NetHack may be freely redistributed. See license for details. */ /* * Currently shared by the following ports: * WIN32 * * The code in here is used to take advantage of added features * that might be available in a Local Area Network environment. * * Network Username of player * Mail * Futures * Shared bones * To implement this: code, data files, and configuration * files need to be separated from writeable files such * as level files, bones files, and save files. * */ #include "hack.h" #include #ifdef LAN_FEATURES #ifdef LAN_MAIL /* Port specific code needs to implement these routines for LAN_MAIL */ extern char *FDECL(get_username, (int *)); extern boolean NDECL(mail_check); extern boolean FDECL(mail_fetch, (struct lan_mail_struct *)); extern void FDECL(mail_init, (char *)); extern void NDECL(mail_finish); struct lan_mail_struct mailmessage; #endif /* LAN_MAIL */ void init_lan_features() { lan_username(); #ifdef LAN_MAIL lan_mail_init(); #endif #ifdef LAN_SHARED_BONES #endif } /* * The get_lan_username() call is a required call, since some of * the other LAN features depend on a unique username being available. * */ char lusername[MAX_LAN_USERNAME]; int lusername_size = MAX_LAN_USERNAME; char *lan_username() { char *lu; lu = get_username(&lusername_size); if (lu) { Strcpy(lusername, lu); return lusername; } else return (char *)0; } # ifdef LAN_MAIL #if 0 static void mail_by_pline(msg) struct lan_mail_struct *msg; { long size; for (size = 0; size < qt_msg->size; size += (long)strlen(in_line)) { (void) dlb_fgets(in_line, 80, msg_file); convert_line(); pline(out_line); } } #endif /* 0 */ static void mail_by_window(msg) struct lan_mail_struct *msg; { char buf[BUFSZ]; winid datawin = create_nhwindow(NHW_TEXT); char *get, *put; int ccount = 0; get = msg->body; put = buf; while (*get) { if (ccount > 79) { *put = '\0'; putstr(datawin, 0, buf); put = buf; ccount = 0; } if (*get == '\r') { get++; } else if (*get == '\n') { *put = '\0'; putstr(datawin, 0, buf); put = buf; get++; ccount = 0; } else if (!isprint(*get)) { get++; } else { *put++ = *get++; ccount++; } } *put = '\0'; putstr(datawin, 0, buf); putstr(datawin, 0, ""); display_nhwindow(datawin, TRUE); destroy_nhwindow(datawin); } /* this returns TRUE if there is mail ready to be read */ boolean lan_mail_check() { if (flags.biff) { if (mail_check()) return TRUE; } return FALSE; } void lan_mail_read(otmp) struct obj *otmp; { if (flags.biff) { (void) mail_fetch(&mailmessage); /* after a successful fetch iflags.lan_mail_fetched * should be TRUE. If it isn't then we don't * trust the contents of mailmessage. This * ensures that things work correctly across * save/restores where mailmessage isn't * saved (nor should it be since it may be * way out of context by then). */ if (iflags.lan_mail_fetched) { if (mailmessage.body_in_ram) { mail_by_window(&mailmessage); return; } } } pline_The("text has faded and is no longer readable."); } void lan_mail_init() { if (!flags.biff) return; (void) mail_init(lusername); } void lan_mail_finish() { if (iflags.lan_mail) (void) mail_finish(); } /* If ever called, the underlying mail system ran into trouble * and wants us to cease bothering it immediately. * Don't call mail_finish() because the underlying mail system * may already be unavailable. Just clean up the NetHack side * of things to prevent a crash. */ void lan_mail_terminate() { /* Step 1. Clear iflags.lan_mail to indicate "not inited" */ iflags.lan_mail = FALSE; /* Step 2. Clear iflags.lan_mail_fetched */ iflags.lan_mail_fetched = FALSE; /* Once having gotten to this point, the only way to resume NetHack mail features again is to Save/Quit game, or for the user to clear iflags.biff and then set it once again, which triggers mail initialization */ } # endif /*LAN_MAIL*/ #endif /*LAN_FEATURES*/ /*nhlan.c*/ nethack-3.4.3/sys/share/pcmain.c0100644000000000000000000003535607764735041015221 0ustar rootroot/* SCCS Id: @(#)pcmain.c 3.4 2002/08/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* main.c - MSDOS, OS/2, ST, Amiga, and NT NetHack */ #include "hack.h" #include "dlb.h" #ifndef NO_SIGNAL #include #endif #include #if !defined(AMIGA) && !defined(GNUDOS) #include #else # ifdef GNUDOS #include # endif #endif #ifdef WIN32 #include "win32api.h" /* for GetModuleFileName */ #endif #ifdef __DJGPP__ #include /* for getcwd() prototype */ #endif #ifdef OVL0 #define SHARED_DCL #else #define SHARED_DCL extern #endif SHARED_DCL char orgdir[PATHLEN]; /* also used in pcsys.c, amidos.c */ #ifdef TOS boolean run_from_desktop = TRUE; /* should we pause before exiting?? */ # ifdef __GNUC__ long _stksize = 16*1024; # endif #endif #ifdef AMIGA extern int bigscreen; void NDECL( preserve_icon ); #endif STATIC_DCL void FDECL(process_options,(int argc,char **argv)); STATIC_DCL void NDECL(nhusage); #if defined(MICRO) || defined(WIN32) || defined(OS2) extern void FDECL(nethack_exit,(int)); #else #define nethack_exit exit #endif #ifdef WIN32 extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ #endif #if defined(MSWIN_GRAPHICS) extern void NDECL(mswin_destroy_reg); #endif #ifdef EXEPATH STATIC_DCL char *FDECL(exepath,(char *)); #endif #ifdef OVL0 int FDECL(main, (int,char **)); #endif extern void FDECL(pcmain, (int,char **)); #if defined(__BORLANDC__) && !defined(_WIN32) void NDECL( startup ); # ifdef OVLB unsigned _stklen = STKSIZ; # else extern unsigned _stklen; # endif #endif #ifdef OVL0 /* If the graphics version is built, we don't need a main; it is skipped * to help MinGW decide which entry point to choose. If both main and * WinMain exist, the resulting executable won't work correctly. */ #ifndef MSWIN_GRAPHICS int main(argc,argv) int argc; char *argv[]; { pcmain(argc,argv); #ifdef LAN_FEATURES init_lan_features(); #endif moveloop(); nethack_exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif /*MSWIN_GRAPHICS*/ #endif /*OVL0*/ #ifdef OVL1 void pcmain(argc,argv) int argc; char *argv[]; { register int fd; register char *dir; #if defined(WIN32) char fnamebuf[BUFSZ], encodedfnamebuf[BUFSZ]; #endif #ifdef NOCWD_ASSUMPTIONS char failbuf[BUFSZ]; #endif #if defined(__BORLANDC__) && !defined(_WIN32) startup(); #endif #ifdef TOS long clock_time; if (*argv[0]) { /* only a CLI can give us argv[0] */ hname = argv[0]; run_from_desktop = FALSE; } else #endif hname = "NetHack"; /* used for syntax messages */ choose_windows(DEFAULT_WINDOW_SYS); #if !defined(AMIGA) && !defined(GNUDOS) /* Save current directory and make sure it gets restored when * the game is exited. */ if (getcwd(orgdir, sizeof orgdir) == (char *)0) error("NetHack: current directory path too long"); # ifndef NO_SIGNAL signal(SIGINT, (SIG_RET_TYPE) nethack_exit); /* restore original directory */ # endif #endif /* !AMIGA && !GNUDOS */ dir = nh_getenv("NETHACKDIR"); if (dir == (char *)0) dir = nh_getenv("HACKDIR"); #ifdef EXEPATH if (dir == (char *)0) dir = exepath(argv[0]); #endif if (dir != (char *)0) { (void) strncpy(hackdir, dir, PATHLEN - 1); hackdir[PATHLEN-1] = '\0'; #ifdef NOCWD_ASSUMPTIONS { int prefcnt; fqn_prefix[0] = (char *)alloc(strlen(hackdir)+2); Strcpy(fqn_prefix[0], hackdir); append_slash(fqn_prefix[0]); for (prefcnt = 1; prefcnt < PREFIX_COUNT; prefcnt++) fqn_prefix[prefcnt] = fqn_prefix[0]; } #endif #ifdef CHDIR chdirx (dir, 1); #endif } #ifdef AMIGA # ifdef CHDIR /* * If we're dealing with workbench, change the directory. Otherwise * we could get "Insert disk in drive 0" messages. (Must be done * before initoptions()).... */ if(argc == 0) chdirx(HACKDIR, 1); # endif ami_wininit_data(); #endif initoptions(); #ifdef NOCWD_ASSUMPTIONS if (!validate_prefix_locations(failbuf)) { raw_printf("Some invalid directory locations were specified:\n\t%s\n", failbuf); nethack_exit(EXIT_FAILURE); } #endif #if defined(TOS) && defined(TEXTCOLOR) if (iflags.BIOS && iflags.use_color) set_colors(); #endif if (!hackdir[0]) #if !defined(LATTICE) && !defined(AMIGA) Strcpy(hackdir, orgdir); #else Strcpy(hackdir, HACKDIR); #endif if(argc > 1) { if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else */ argc--; argv++; dir = argv[0]+2; if(*dir == '=' || *dir == ':') dir++; if(!*dir && argc > 1) { argc--; argv++; dir = argv[0]; } if(!*dir) error("Flag -d must be followed by a directory name."); Strcpy(hackdir, dir); } if (argc > 1) { /* * Now we know the directory containing 'record' and * may do a prscore(). */ if (!strncmp(argv[1], "-s", 2)) { #if !defined(MSWIN_GRAPHICS) # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(hackdir,0); # endif prscore(argc, argv); #else raw_printf("-s is not supported for the Graphical Interface\n"); #endif /*MSWIN_GRAPHICS*/ nethack_exit(EXIT_SUCCESS); } #ifdef MSWIN_GRAPHICS if (!strncmpi(argv[1], "-clearreg", 6)) { /* clear registry */ mswin_destroy_reg(); nethack_exit(EXIT_SUCCESS); } #endif /* Don't initialize the window system just to print usage */ if (!strncmp(argv[1], "-?", 2) || !strncmp(argv[1], "/?", 2)) { nhusage(); nethack_exit(EXIT_SUCCESS); } } } /* * It seems you really want to play. */ #ifdef TOS if (comp_times((long)time(&clock_time))) error("Your clock is incorrectly set!"); #endif u.uhp = 1; /* prevent RIP on early quits */ u.ux = 0; /* prevent flush_screen() */ /* chdir shouldn't be called before this point to keep the * code parallel to other ports. */ #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(hackdir,1); #endif #ifdef MSDOS process_options(argc, argv); init_nhwindows(&argc,argv); #else init_nhwindows(&argc,argv); process_options(argc, argv); #endif #ifdef WIN32CON toggle_mouse_support(); /* must come after process_options */ #endif #ifdef MFLOPPY set_lock_and_bones(); # ifndef AMIGA copybones(FROMPERM); # endif #endif if (!*plname) askname(); plnamesuffix(); /* strip suffix from name; calls askname() */ /* again if suffix was whole name */ /* accepts any suffix */ #ifdef WIZARD if (wizard) { # ifdef KR1ED if(!strcmp(plname, WIZARD_NAME)) # else if(!strcmp(plname, WIZARD)) # endif Strcpy(plname, "wizard"); else { wizard = FALSE; discover = TRUE; } } #endif /* WIZARD */ #if defined(PC_LOCKING) /* 3.3.0 added this to support detection of multiple games * under the same plname on the same machine in a windowed * or multitasking environment. * * That allows user confirmation prior to overwriting the * level files of a game in progress. * * Also prevents an aborted game's level files from being * overwritten without confirmation when a user starts up * another game with the same player name. */ # if defined(WIN32) /* Obtain the name of the logged on user and incorporate * it into the name. */ Sprintf(fnamebuf, "%s-%s", get_username(0), plname); (void)fname_encode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-.", '%', fnamebuf, encodedfnamebuf, BUFSZ); Sprintf(lock, "%s",encodedfnamebuf); /* regularize(lock); */ /* we encode now, rather than substitute */ # else Strcpy(lock,plname); regularize(lock); # endif getlock(); #else /* What follows is !PC_LOCKING */ # ifdef AMIGA /* We'll put the bones & levels in the user specified directory -jhsa */ Strcat(lock,plname); Strcat(lock,".99"); # else # ifndef MFLOPPY /* I'm not sure what, if anything, is left here, but MFLOPPY has * conflicts with set_lock_and_bones() in files.c. */ Strcpy(lock,plname); Strcat(lock,".99"); regularize(lock); /* is this necessary? */ /* not compatible with full path a la AMIGA */ # endif # endif #endif /* PC_LOCKING */ /* Set up level 0 file to keep the game state. */ fd = create_levelfile(0, (char *)0); if (fd < 0) { raw_print("Cannot create lock file"); } else { #ifdef WIN32 hackpid = GetCurrentProcessId(); #else hackpid = 1; #endif write(fd, (genericptr_t) &hackpid, sizeof(hackpid)); close(fd); } #ifdef MFLOPPY level_info[0].where = ACTIVE; #endif /* * Initialisation of the boundaries of the mazes * Both boundaries have to be even. */ x_maze_max = COLNO-1; if (x_maze_max % 2) x_maze_max--; y_maze_max = ROWNO-1; if (y_maze_max % 2) y_maze_max--; /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); dlb_init(); display_gamewindows(); #ifdef WIN32 getreturn_enabled = TRUE; #endif if ((fd = restore_saved_game()) >= 0) { #ifdef WIZARD /* Since wizard is actually flags.debug, restoring might * overwrite it. */ boolean remember_wiz_mode = wizard; #endif #ifndef NO_SIGNAL (void) signal(SIGINT, (SIG_RET_TYPE) done1); #endif #ifdef NEWS if(iflags.news){ display_file(NEWS, FALSE); iflags.news = FALSE; } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ if(!dorecover(fd)) goto not_recovered; #ifdef WIZARD if(!wizard && remember_wiz_mode) wizard = TRUE; #endif check_special_room(FALSE); if (discover) You("are in non-scoring discovery mode."); if (discover || wizard) { if(yn("Do you want to keep the save file?") == 'n'){ (void) delete_savefile(); } } flags.move = 0; } else { not_recovered: player_selection(); newgame(); if (discover) You("are in non-scoring discovery mode."); flags.move = 0; set_wear(); (void) pickup(1); read_engr_at(u.ux,u.uy); } #ifndef NO_SIGNAL (void) signal(SIGINT, SIG_IGN); #endif #ifdef OS2 gettty(); /* somehow ctrl-P gets turned back on during startup ... */ #endif return; } STATIC_OVL void process_options(argc, argv) int argc; char *argv[]; { int i; /* * Process options. */ while(argc > 1 && argv[1][0] == '-'){ argv++; argc--; switch(argv[0][1]){ case 'a': if (argv[0][2]) { if ((i = str2align(&argv[0][2])) >= 0) flags.initalign = i; } else if (argc > 1) { argc--; argv++; if ((i = str2align(argv[0])) >= 0) flags.initalign = i; } break; case 'D': #ifdef WIZARD /* If they don't have a valid wizard name, it'll be * changed to discover later. Cannot check for * validity of the name right now--it might have a * character class suffix, for instance. */ wizard = TRUE; break; #endif case 'X': discover = TRUE; break; #ifdef NEWS case 'n': iflags.news = FALSE; break; #endif case 'u': if(argv[0][2]) (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); else if(argc > 1) { argc--; argv++; (void) strncpy(plname, argv[0], sizeof(plname)-1); } else raw_print("Player name expected after -u"); break; #ifndef AMIGA case 'I': case 'i': if (!strncmpi(argv[0]+1, "IBM", 3)) switch_graphics(IBM_GRAPHICS); break; /* case 'D': */ case 'd': if (!strncmpi(argv[0]+1, "DEC", 3)) switch_graphics(DEC_GRAPHICS); break; #endif case 'g': if (argv[0][2]) { if ((i = str2gend(&argv[0][2])) >= 0) flags.initgend = i; } else if (argc > 1) { argc--; argv++; if ((i = str2gend(argv[0])) >= 0) flags.initgend = i; } break; case 'p': /* profession (role) */ if (argv[0][2]) { if ((i = str2role(&argv[0][2])) >= 0) flags.initrole = i; } else if (argc > 1) { argc--; argv++; if ((i = str2role(argv[0])) >= 0) flags.initrole = i; } break; case 'r': /* race */ if (argv[0][2]) { if ((i = str2race(&argv[0][2])) >= 0) flags.initrace = i; } else if (argc > 1) { argc--; argv++; if ((i = str2race(argv[0])) >= 0) flags.initrace = i; } break; #ifdef MFLOPPY # ifndef AMIGA /* Player doesn't want to use a RAM disk */ case 'R': ramdisk = FALSE; break; # endif #endif #ifdef AMIGA /* interlaced and non-interlaced screens */ case 'L': bigscreen = 1; break; case 'l': bigscreen = -1; break; #endif case '@': flags.randomall = 1; break; default: if ((i = str2role(&argv[0][1])) >= 0) { flags.initrole = i; break; } else raw_printf("\nUnknown switch: %s", argv[0]); /* FALL THROUGH */ case '?': nhusage(); nethack_exit(EXIT_SUCCESS); } } } STATIC_OVL void nhusage() { char buf1[BUFSZ], buf2[BUFSZ], *bufptr; buf1[0] = '\0'; bufptr = buf1; #define ADD_USAGE(s) if ((strlen(buf1) + strlen(s)) < (BUFSZ - 1)) Strcat(bufptr, s); /* -role still works for those cases which aren't already taken, but * is deprecated and will not be listed here. */ (void) Sprintf(buf2, "\nUsage:\n%s [-d dir] -s [-r race] [-p profession] [maxrank] [name]...\n or", hname); ADD_USAGE(buf2); (void) Sprintf(buf2, "\n%s [-d dir] [-u name] [-r race] [-p profession] [-[DX]]", hname); ADD_USAGE(buf2); #ifdef NEWS ADD_USAGE(" [-n]"); #endif #ifndef AMIGA ADD_USAGE(" [-I] [-i] [-d]"); #endif #ifdef MFLOPPY # ifndef AMIGA ADD_USAGE(" [-R]"); # endif #endif #ifdef AMIGA ADD_USAGE(" [-[lL]]"); #endif if (!iflags.window_inited) raw_printf("%s\n",buf1); else (void) printf("%s\n",buf1); #undef ADD_USAGE } #ifdef CHDIR void chdirx(dir, wr) char *dir; boolean wr; { # ifdef AMIGA static char thisdir[] = ""; # else static char thisdir[] = "."; # endif if(dir && chdir(dir) < 0) { error("Cannot chdir to %s.", dir); } # ifndef AMIGA /* Change the default drive as well. */ chdrive(dir); # endif /* warn the player if we can't write the record file */ /* perhaps we should also test whether . is writable */ /* unfortunately the access system-call is worthless */ if (wr) check_recordfile(dir ? dir : thisdir); } #endif /* CHDIR */ #endif /*OVL1*/ #ifdef OVLB #ifdef PORT_HELP # if defined(MSDOS) || defined(WIN32) void port_help() { /* display port specific help file */ display_file( PORT_HELP, 1 ); } # endif /* MSDOS || WIN32 */ #endif /* PORT_HELP */ #ifdef EXEPATH # ifdef __DJGPP__ #define PATH_SEPARATOR '/' # else #define PATH_SEPARATOR '\\' # endif #define EXEPATHBUFSZ 256 char exepathbuf[EXEPATHBUFSZ]; char *exepath(str) char *str; { char *tmp, *tmp2; int bsize; if (!str) return (char *)0; bsize = EXEPATHBUFSZ; tmp = exepathbuf; # ifndef WIN32 Strcpy (tmp, str); # else #ifdef UNICODE { TCHAR wbuf[BUFSZ]; GetModuleFileName((HANDLE)0, wbuf, BUFSZ); WideCharToMultiByte(CP_ACP, 0, wbuf, -1, tmp, bsize, NULL, NULL); } #else *(tmp + GetModuleFileName((HANDLE)0, tmp, bsize)) = '\0'; #endif # endif tmp2 = strrchr(tmp, PATH_SEPARATOR); if (tmp2) *tmp2 = '\0'; return tmp; } #endif /* EXEPATH */ #endif /*OVLB*/ /*pcmain.c*/ nethack-3.4.3/sys/share/pcsys.c0100644000000000000000000002502207764735041015100 0ustar rootroot/* SCCS Id: @(#)pcsys.c 3.4 2002/01/22 */ /* NetHack may be freely redistributed. See license for details. */ /* * System related functions for MSDOS, OS/2, TOS, and Windows NT */ #define NEED_VARARGS #include "hack.h" #include "wintty.h" #include #include #if !defined(MSDOS) && !defined(WIN_CE) /* already done */ #include #endif #ifdef __GO32__ #define P_WAIT 0 #define P_NOWAIT 1 #endif #ifdef TOS #include #endif #if defined(MSDOS) && !defined(__GO32__) #define findfirst findfirst_file #define findnext findnext_file #define filesize filesize_nh #endif #if defined(MICRO) || defined(WIN32) || defined(OS2) void FDECL(nethack_exit,(int)); #else #define nethack_exit exit #endif static void NDECL(msexit); #ifdef MOVERLAY extern void __far __cdecl _movepause( void ); extern void __far __cdecl _moveresume( void ); extern unsigned short __far __cdecl _movefpause; extern unsigned short __far __cdecl _movefpaused; #define __MOVE_PAUSE_DISK 2 /* Represents the executable file */ #define __MOVE_PAUSE_CACHE 4 /* Represents the cache memory */ #endif /* MOVERLAY */ #ifdef MFLOPPY STATIC_DCL boolean NDECL(record_exists); # ifndef TOS STATIC_DCL boolean NDECL(comspec_exists); # endif #endif #ifdef WIN32CON extern int GUILaunched; /* from nttty.c */ #endif #if defined(MICRO) || defined(WIN32) void flushout() { (void) fflush(stdout); return; } static const char *COMSPEC = # ifdef TOS "SHELL"; # else "COMSPEC"; # endif #define getcomspec() nh_getenv(COMSPEC) # ifdef SHELL int dosh() { extern char orgdir[]; char *comspec; # ifndef __GO32__ int spawnstat; # endif #if defined(MSDOS) && defined(NO_TERMS) int grmode = iflags.grmode; #endif if ((comspec = getcomspec())) { # ifndef TOS /* TOS has a variety of shells */ suspend_nhwindows("To return to NetHack, enter \"exit\" at the system prompt.\n"); # else # if defined(MSDOS) && defined(NO_TERMS) grmode = iflags.grmode; # endif suspend_nhwindows((char *)0); # endif /* TOS */ # ifndef NOCWD_ASSUMPTIONS chdirx(orgdir, 0); # endif # ifdef __GO32__ if (system(comspec) < 0) { /* wsu@eecs.umich.edu */ # else # ifdef MOVERLAY /* Free the cache memory used by overlays, close .exe */ _movefpause |= __MOVE_PAUSE_DISK; _movefpause |= __MOVE_PAUSE_CACHE; _movepause(); # endif spawnstat = spawnl(P_WAIT, comspec, comspec, (char *)0); # ifdef MOVERLAY _moveresume(); # endif if ( spawnstat < 0) { # endif raw_printf("Can't spawn \"%s\"!", comspec); getreturn("to continue"); } # ifdef TOS /* Some shells (e.g. Gulam) turn the cursor off when they exit */ if (iflags.BIOS) (void)Cursconf(1, -1); # endif # ifndef NOCWD_ASSUMPTIONS chdirx(hackdir, 0); # endif get_scr_size(); /* maybe the screen mode changed (TH) */ # if defined(MSDOS) && defined(NO_TERMS) if (grmode) gr_init(); # endif resume_nhwindows(); } else pline("Can't find %s.",COMSPEC); return 0; } # endif /* SHELL */ # ifdef MFLOPPY void eraseall(path, files) const char *path, *files; { char buf[PATHLEN]; char *foundfile; foundfile = foundfile_buffer(); Sprintf(buf, "%s%s", path, files); if (findfirst(buf)) do { Sprintf(buf, "%s%s", path, foundfile); (void) unlink(buf); } while (findnext()); return; } /* * Rewritten for version 3.3 to be faster */ void copybones(mode) int mode; { char from[PATHLEN], to[PATHLEN], last[13]; char *frompath, *topath; char *foundfile; # ifndef TOS int status; char copy[8], *comspec; # endif if (!ramdisk) return; /* Find the name of the last file to be transferred */ frompath = (mode != TOPERM) ? permbones : levels; foundfile = foundfile_buffer(); last[0] = '\0'; Sprintf(from, "%s%s", frompath, allbones); topath = (mode == TOPERM) ? permbones : levels; # ifdef TOS eraseall(topath, allbones); # endif if (findfirst(from)) do { # ifdef TOS Sprintf(from, "%s%s", frompath, foundfile); Sprintf(to, "%s%s", topath, foundfile); if (_copyfile(from, to)) goto error_copying; # endif Strcpy(last, foundfile); } while (findnext()); # ifdef TOS else return; # else if (last[0]) { Sprintf(copy, "%cC copy",switchar()); /* Remove any bones files in `to' directory. */ eraseall(topath, allbones); /* Copy `from' to `to' */ Sprintf(to, "%s%s", topath, allbones); comspec = getcomspec(); status =spawnl(P_WAIT, comspec, comspec, copy, from, to, "> nul", (char *)0); } else return; # endif /* TOS */ /* See if the last file got there. If so, remove the ramdisk bones * files. */ Sprintf(to, "%s%s", topath, last); if (findfirst(to)) { if (mode == TOPERM) eraseall(frompath, allbones); return; } # ifdef TOS error_copying: # endif /* Last file didn't get there. */ Sprintf(to, "%s%s", topath, allbones); msmsg("Can't copy \"%s\" to \"%s\" -- ", from, to); # ifndef TOS if (status < 0) msmsg("can't spawn \"%s\"!", comspec); else # endif msmsg((freediskspace(topath) < filesize(from)) ? "insufficient disk space." : "bad path(s)?"); if (mode == TOPERM) { msmsg("Bones will be left in \"%s\"\n", *levels ? levels : hackdir); } else { /* Remove all bones files on the RAMdisk */ eraseall(levels, allbones); playwoRAMdisk(); } return; } void playwoRAMdisk() { int c; msmsg("Do you wish to play without a RAMdisk? [yn] (n)"); /* Set ramdisk false *before* exit-ing (because msexit calls * copybones) */ ramdisk = FALSE; c = tgetch(); if (c == 'Y') c = 'y'; if (c != 'y') { settty("Be seeing you...\n"); nethack_exit(EXIT_SUCCESS); } set_lock_and_bones(); return; } int saveDiskPrompt(start) int start; { char buf[BUFSIZ], *bp; char qbuf[QBUFSZ]; int fd; if (flags.asksavedisk) { /* Don't prompt if you can find the save file */ if ((fd = open_savefile()) >= 0) { (void) close(fd); return 1; } clear_nhwindow(WIN_MESSAGE); pline("If save file is on a save disk, insert that disk now."); mark_synch(); Sprintf(qbuf,"File name (default \"%s\"%s) ?", SAVEF, start ? "" : ", cancels save"); getlin(qbuf, buf); clear_nhwindow(WIN_MESSAGE); if (!start && *buf == '\033') return 0; /* Strip any whitespace. Also, if nothing was entered except * whitespace, do not change the value of SAVEF. */ for (bp = buf; *bp; bp++) if (!isspace(*bp)) { strncpy(SAVEF, bp, PATHLEN); break; } } return 1; } /* Return 1 if the record file was found */ STATIC_OVL boolean record_exists() { FILE *fp; fp = fopen_datafile(RECORD, "r", TRUE); if (fp) { fclose(fp); return TRUE; } return FALSE; } #endif /* MFLOPPY */ # ifdef TOS #define comspec_exists() 1 # else # ifdef MFLOPPY /* Return 1 if the comspec was found */ STATIC_OVL boolean comspec_exists() { int fd; char *comspec; if ((comspec = getcomspec())) if ((fd = open(comspec, O_RDONLY)) >= 0) { (void) close(fd); return TRUE; } return FALSE; } # endif /* MFLOPPY */ # endif # ifdef MFLOPPY /* Prompt for game disk, then check for record file. */ void gameDiskPrompt() { if (flags.asksavedisk) { if (record_exists() && comspec_exists()) return; (void) putchar('\n'); getreturn("when the game disk has been inserted"); } if (comspec_exists() && record_exists()) return; if (!comspec_exists()) msmsg("\n\nWARNING: can't find command processor \"%s\"!\n", getcomspec()); if (!record_exists()) msmsg("\n\nWARNING: can't find record file \"%s\"!\n", RECORD); msmsg("If the game disk is not in, insert it now.\n"); getreturn("to continue"); return; } # endif /* MFLOPPY */ #endif /* MICRO */ /* * Add a backslash to any name not ending in /, \ or : There must * be room for the \ */ void append_slash(name) char *name; { char *ptr; if (!*name) return; ptr = name + (strlen(name) - 1); if (*ptr != '\\' && *ptr != '/' && *ptr != ':') { *++ptr = '\\'; *++ptr = '\0'; } return; } #ifdef WIN32 boolean getreturn_enabled; #endif void getreturn(str) const char *str; { #ifdef WIN32 if (!getreturn_enabled) return; #endif #ifdef TOS msmsg("Hit %s.", str); #else msmsg("Hit %s.", str); #endif while (Getchar() != '\n') ; return; } #ifndef WIN32CON void msmsg VA_DECL(const char *, fmt) VA_START(fmt); VA_INIT(fmt, const char *); # if defined(MSDOS) && defined(NO_TERMS) if (iflags.grmode) gr_finish(); # endif Vprintf(fmt, VA_ARGS); flushout(); VA_END(); return; } #endif /* * Follow the PATH, trying to fopen the file. */ #ifdef TOS # ifdef __MINT__ #define PATHSEP ':' # else #define PATHSEP ',' # endif #else #define PATHSEP ';' #endif FILE * fopenp(name, mode) const char *name, *mode; { char buf[BUFSIZ], *bp, *pp, lastch = 0; FILE *fp; /* Try the default directory first. Then look along PATH. */ (void) strncpy(buf, name, BUFSIZ - 1); buf[BUFSIZ-1] = '\0'; if ((fp = fopen(buf, mode))) return fp; else { int ccnt = 0; pp = getenv("PATH"); while (pp && *pp) { bp = buf; while (*pp && *pp != PATHSEP) { lastch = *bp++ = *pp++; ccnt++; } if (lastch != '\\' && lastch != '/') { *bp++ = '\\'; ccnt++; } (void) strncpy(bp, name, (BUFSIZ - ccnt) - 2); bp[BUFSIZ - ccnt - 1] = '\0'; if ((fp = fopen(buf, mode))) return fp; if (*pp) pp++; } } #ifdef OS2_CODEVIEW /* one more try for hackdir */ (void) strncpy(buf, hackdir, BUFSZ); buf[BUFSZ-1] = '\0'; if ((strlen(name) + 1 + strlen(buf)) < BUFSZ - 1) { append_slash(buf); Strcat(buf,name); } else impossible("fopenp() buffer too small for complete filename!"); if(fp = fopen(buf,mode)) return fp; #endif return (FILE *)0; } #if defined(MICRO) || defined(WIN32) || defined(OS2) void nethack_exit(code) int code; { msexit(); exit(code); } /* Chdir back to original directory */ #ifdef TOS extern boolean run_from_desktop; /* set in pcmain.c */ #endif static void msexit() { #ifdef CHDIR extern char orgdir[]; #endif flushout(); #ifndef TOS # ifndef WIN32 enable_ctrlP(); /* in case this wasn't done */ # endif #endif #ifdef MFLOPPY if (ramdisk) copybones(TOPERM); #endif #if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdir(orgdir); /* chdir, not chdirx */ chdrive(orgdir); #endif #ifdef TOS if (run_from_desktop) getreturn("to continue"); /* so the user can read the score list */ # ifdef TEXTCOLOR if (colors_changed) restore_colors(); # endif #endif #ifdef WIN32CON /* Only if we started from the GUI, not the command prompt, * we need to get one last return, so the score board does * not vanish instantly after being created. * GUILaunched is defined and set in nttty.c. */ synch_cursor(); if (GUILaunched) getreturn("to end"); synch_cursor(); #endif return; } #endif /* MICRO || WIN32 || OS2 */ nethack-3.4.3/sys/share/pctty.c0100644000000000000000000000315407764735041015104 0ustar rootroot/* SCCS Id: @(#)pctty.c 3.4 1990/22/02 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* tty.c - (PC) version */ #define NEED_VARARGS /* Uses ... */ /* comment line for pre-compiled headers */ #include "hack.h" #include "wintty.h" char erase_char, kill_char; /* * Get initial state of terminal, set ospeed (for termcap routines) * and switch off tab expansion if necessary. * Called by startup() in termcap.c and after returning from ! or ^Z */ void gettty(){ erase_char = '\b'; kill_char = 21; /* cntl-U */ iflags.cbreak = TRUE; #if !defined(TOS) disable_ctrlP(); /* turn off ^P processing */ #endif #if defined(MSDOS) && defined(NO_TERMS) gr_init(); #endif } /* reset terminal to original state */ void settty(s) const char *s; { #if defined(MSDOS) && defined(NO_TERMS) gr_finish(); #endif end_screen(); if(s) raw_print(s); #if !defined(TOS) enable_ctrlP(); /* turn on ^P processing */ #endif } /* called by init_nhwindows() and resume_nhwindows() */ void setftty() { start_screen(); } #if defined(TIMED_DELAY) && defined(_MSC_VER) void msleep(mseconds) unsigned mseconds; { /* now uses clock() which is ANSI C */ clock_t goal; goal = mseconds + clock(); while ( goal > clock()) { /* do nothing */ } } #endif /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *,s) VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); putchar('\n'); Vprintf(s,VA_ARGS); putchar('\n'); VA_END(); exit(EXIT_FAILURE); } /*pctty.c*/ nethack-3.4.3/sys/share/pcunix.c0100644000000000000000000001604307764735041015250 0ustar rootroot/* SCCS Id: @(#)pcunix.c 3.4 1994/11/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file collects some Unix dependencies; pager.c contains some more */ #include "hack.h" #include "wintty.h" #include #if defined(WIN32) || defined(MSDOS) #include #endif #if defined(WIN32) || defined(MSDOS) extern char orgdir[]; # ifdef WIN32 extern void NDECL(backsp); # endif extern void NDECL(clear_screen); #endif #ifdef OVLB #if 0 static struct stat buf; #endif # ifdef WANT_GETHDATE static struct stat hbuf; # endif #ifdef PC_LOCKING static int NDECL(eraseoldlocks); #endif #if 0 int uptodate(fd) int fd; { # ifdef WANT_GETHDATE if(fstat(fd, &buf)) { pline("Cannot get status of saved level? "); return(0); } if(buf.st_mtime < hbuf.st_mtime) { pline("Saved level is out of date. "); return(0); } # else # if (defined(MICRO) || defined(WIN32)) && !defined(NO_FSTAT) if(fstat(fd, &buf)) { if(moves > 1) pline("Cannot get status of saved level? "); else pline("Cannot get status of saved game."); return(0); } if(comp_times(buf.st_mtime)) { if(moves > 1) pline("Saved level is out of date."); else pline("Saved game is out of date. "); /* This problem occurs enough times we need to give the player * some more information about what causes it, and how to fix. */ # ifdef MSDOS pline("Make sure that your system's date and time are correct."); pline("They must be more current than NetHack.EXE's date/time stamp."); # endif /* MSDOS */ return(0); } # endif /* MICRO */ # endif /* WANT_GETHDATE */ return(1); } #endif #ifdef PC_LOCKING static int eraseoldlocks() { register int i; /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up */ for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) { /* try to remove all */ set_levelfile_name(lock, i); (void) unlink(fqname(lock, LEVELPREFIX, 0)); } set_levelfile_name(lock, 0); #ifdef HOLD_LOCKFILE_OPEN really_close(); #endif if(unlink(fqname(lock, LEVELPREFIX, 0))) return 0; /* cannot remove it */ return(1); /* success! */ } void getlock() { register int fd, c, ci, ct, ern; char tbuf[BUFSZ]; const char *fq_lock; # if defined(MSDOS) && defined(NO_TERMS) int grmode = iflags.grmode; # endif /* we ignore QUIT and INT at this point */ if (!lock_file(HLOCK, LOCKPREFIX, 10)) { wait_synch(); # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); # endif error("Quitting."); } /* regularize(lock); */ /* already done in pcmain */ Sprintf(tbuf,"%s",fqname(lock, LEVELPREFIX, 0)); set_levelfile_name(lock, 0); fq_lock = fqname(lock, LEVELPREFIX, 1); if((fd = open(fq_lock,0)) == -1) { if(errno == ENOENT) goto gotlock; /* no such file */ # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); # endif # if defined(WIN32) || defined(HOLD_LOCKFILE_OPEN) # if defined(HOLD_LOCKFILE_OPEN) if(errno == EACCES) { #define OOPS_BUFSZ 512 char oops[OOPS_BUFSZ]; Strcpy(oops, "\nThere are files from a game in progress under your name."); Strcat(oops, "\nThe files are locked or inaccessible."); Strcat(oops, " Is the other game still running?\n"); if (strlen(fq_lock) < ((OOPS_BUFSZ -16) - strlen(oops))) Sprintf(eos(oops), "Cannot open %s", fq_lock); Strcat(oops, "\n"); unlock_file(HLOCK); error(oops); } else # endif error("Bad directory or name: %s\n%s\n", fq_lock, strerror(errno)); # else perror(fq_lock); # endif unlock_file(HLOCK); error("Cannot open %s", fq_lock); } (void) close(fd); if(iflags.window_inited) { # ifdef SELF_RECOVER c = yn("There are files from a game in progress under your name. Recover?"); # else pline("There is already a game in progress under your name."); pline("You may be able to use \"recover %s\" to get it back.\n",tbuf); c = yn("Do you want to destroy the old game?"); # endif } else { # if defined(MSDOS) && defined(NO_TERMS) grmode = iflags.grmode; if (grmode) gr_finish(); # endif c = 'n'; ct = 0; # ifdef SELF_RECOVER msmsg( "There are files from a game in progress under your name. Recover? [yn]"); # else msmsg("\nThere is already a game in progress under your name.\n"); msmsg("If this is unexpected, you may be able to use \n"); msmsg("\"recover %s\" to get it back.",tbuf); msmsg("\nDo you want to destroy the old game? [yn] "); # endif while ((ci=nhgetch()) != '\n') { if (ct > 0) { msmsg("\b \b"); ct = 0; c = 'n'; } if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') { ct = 1; c = ci; msmsg("%c",c); } } } if(c == 'y' || c == 'Y') # ifndef SELF_RECOVER if(eraseoldlocks()) { # if defined(WIN32CON) clear_screen(); /* display gets fouled up otherwise */ # endif goto gotlock; } else { unlock_file(HLOCK); # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); # endif error("Couldn't destroy old game."); } # else /*SELF_RECOVER*/ if(recover_savefile()) { # if defined(WIN32CON) clear_screen(); /* display gets fouled up otherwise */ # endif goto gotlock; } else { unlock_file(HLOCK); # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); # endif error("Couldn't recover old game."); } # endif /*SELF_RECOVER*/ else { unlock_file(HLOCK); # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); # endif error("%s", "Cannot start a new game."); } gotlock: fd = creat(fq_lock, FCMASK); if (fd == -1) ern = errno; unlock_file(HLOCK); if(fd == -1) { # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); # endif # if defined(WIN32) error("cannot creat file (%s.)\n%s\n%s\"%s\" exists?\n", fq_lock, strerror(ern), " Are you sure that the directory", fqn_prefix[LEVELPREFIX]); # else error("cannot creat file (%s.)", fq_lock); # endif } else { if(write(fd, (char *) &hackpid, sizeof(hackpid)) != sizeof(hackpid)){ # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); # endif error("cannot write lock (%s)", fq_lock); } if(close(fd) == -1) { # if defined(CHDIR) && !defined(NOCWD_ASSUMPTIONS) chdirx(orgdir, 0); # endif error("cannot close lock (%s)", fq_lock); } } # if defined(MSDOS) && defined(NO_TERMS) if (grmode) gr_init(); # endif } #endif /* PC_LOCKING */ # ifndef WIN32 void regularize(s) /* * normalize file name - we don't like .'s, /'s, spaces, and * lots of other things */ register char *s; { register char *lp; for (lp = s; *lp; lp++) if (*lp <= ' ' || *lp == '"' || (*lp >= '*' && *lp <= ',') || *lp == '.' || *lp == '/' || (*lp >= ':' && *lp <= '?') || # ifdef OS2 *lp == '&' || *lp == '(' || *lp == ')' || # endif *lp == '|' || *lp >= 127 || (*lp >= '[' && *lp <= ']')) *lp = '_'; } # endif /* WIN32 */ #endif /* OVLB */ #ifdef __EMX__ void seteuid(int i){;} #endif nethack-3.4.3/sys/share/random.c0100644000000000000000000003256607764735041015232 0ustar rootroot/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* Several minor changes were made for the NetHack distribution to satisfy * non-BSD compilers (by definition BSD compilers do not need to compile * this file for NetHack). These changes consisted of: * - changing the sccsid conditions to nested ifdefs from defined()s * to accommodate stupid preprocessors * - giving srandom() type void instead of allowing it to default to int * - making the first return in initstate() return a value consistent * with its type (instead of no value) * - ANSI function prototyping in extern.h - therefore include hack.h * instead of stdio.h and remove separate declaration of random() from * the beginning of function srandom * - moving sccsid after hack.h to allow precompiled headers, which * means the defined()s would be ok again... * - change fprintf(stderr, "x(%d)y\n", z) to impossible("x(%d)y", z) * - remove useless variable `j' from srandom() */ #include "hack.h" #ifdef LIBC_SCCS # ifndef lint static char sccsid[] = "@(#)random.c 5.5 (Berkeley) 7/6/88"; # endif #endif /* LIBC_SCCS and not lint */ /* * random.c: * An improved random number generation package. In addition to the standard * rand()/srand() like interface, this package also has a special state info * interface. The initstate() routine is called with a seed, an array of * bytes, and a count of how many bytes are being passed in; this array is then * initialized to contain information for random number generation with that * much state information. Good sizes for the amount of state information are * 32, 64, 128, and 256 bytes. The state can be switched by calling the * setstate() routine with the same array as was initiallized with initstate(). * By default, the package runs with 128 bytes of state information and * generates far better random numbers than a linear congruential generator. * If the amount of state information is less than 32 bytes, a simple linear * congruential R.N.G. is used. * Internally, the state information is treated as an array of longs; the * zeroeth element of the array is the type of R.N.G. being used (small * integer); the remainder of the array is the state information for the * R.N.G. Thus, 32 bytes of state information will give 7 longs worth of * state information, which will allow a degree seven polynomial. (Note: the * zeroeth word of state information also has some other information stored * in it -- see setstate() for details). * The random number generation technique is a linear feedback shift register * approach, employing trinomials (since there are fewer terms to sum up that * way). In this approach, the least significant bit of all the numbers in * the state table will act as a linear feedback shift register, and will have * period 2^deg - 1 (where deg is the degree of the polynomial being used, * assuming that the polynomial is irreducible and primitive). The higher * order bits will have longer periods, since their values are also influenced * by pseudo-random carries out of the lower bits. The total period of the * generator is approximately deg*(2**deg - 1); thus doubling the amount of * state information has a vast influence on the period of the generator. * Note: the deg*(2**deg - 1) is an approximation only good for large deg, * when the period of the shift register is the dominant factor. With deg * equal to seven, the period is actually much longer than the 7*(2**7 - 1) * predicted by this formula. */ /* * For each of the currently supported random number generators, we have a * break value on the amount of state information (you need at least this * many bytes of state info to support this random number generator), a degree * for the polynomial (actually a trinomial) that the R.N.G. is based on, and * the separation between the two lower order coefficients of the trinomial. */ #define TYPE_0 0 /* linear congruential */ #define BREAK_0 8 #define DEG_0 0 #define SEP_0 0 #define TYPE_1 1 /* x**7 + x**3 + 1 */ #define BREAK_1 32 #define DEG_1 7 #define SEP_1 3 #define TYPE_2 2 /* x**15 + x + 1 */ #define BREAK_2 64 #define DEG_2 15 #define SEP_2 1 #define TYPE_3 3 /* x**31 + x**3 + 1 */ #define BREAK_3 128 #define DEG_3 31 #define SEP_3 3 #define TYPE_4 4 /* x**63 + x + 1 */ #define BREAK_4 256 #define DEG_4 63 #define SEP_4 1 /* * Array versions of the above information to make code run faster -- relies * on fact that TYPE_i == i. */ #define MAX_TYPES 5 /* max number of types above */ static int degrees[ MAX_TYPES ] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 }; static int seps[ MAX_TYPES ] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 }; /* * Initially, everything is set up as if from : * initstate( 1, &randtbl, 128 ); * Note that this initialization takes advantage of the fact that srandom() * advances the front and rear pointers 10*rand_deg times, and hence the * rear pointer which starts at 0 will also end up at zero; thus the zeroeth * element of the state information, which contains info about the current * position of the rear pointer is just * MAX_TYPES*(rptr - state) + TYPE_3 == TYPE_3. */ static long randtbl[ DEG_3 + 1 ] = { TYPE_3, 0x9a319039, 0x32d9c024, 0x9b663182, 0x5da1f342, 0xde3b81e0, 0xdf0a6fb5, 0xf103bc02, 0x48f340fb, 0x7449e56b, 0xbeb1dbb0, 0xab5c5918, 0x946554fd, 0x8c2e680f, 0xeb3d799f, 0xb11ee0b7, 0x2d436b86, 0xda672e2a, 0x1588ca88, 0xe369735d, 0x904f35f7, 0xd7158fd6, 0x6fa6f051, 0x616e6b96, 0xac94efdc, 0x36413f93, 0xc622c298, 0xf5a42ab8, 0x8a88d77b, 0xf5ad9d0e, 0x8999220b, 0x27fb47b9 }; /* * fptr and rptr are two pointers into the state info, a front and a rear * pointer. These two pointers are always rand_sep places aparts, as they cycle * cyclically through the state information. (Yes, this does mean we could get * away with just one pointer, but the code for random() is more efficient this * way). The pointers are left positioned as they would be from the call * initstate( 1, randtbl, 128 ) * (The position of the rear pointer, rptr, is really 0 (as explained above * in the initialization of randtbl) because the state table pointer is set * to point to randtbl[1] (as explained below). */ static long *fptr = &randtbl[ SEP_3 + 1 ]; static long *rptr = &randtbl[ 1 ]; /* * The following things are the pointer to the state information table, * the type of the current generator, the degree of the current polynomial * being used, and the separation between the two pointers. * Note that for efficiency of random(), we remember the first location of * the state information, not the zeroeth. Hence it is valid to access * state[-1], which is used to store the type of the R.N.G. * Also, we remember the last location, since this is more efficient than * indexing every time to find the address of the last element to see if * the front and rear pointers have wrapped. */ static long *state = &randtbl[ 1 ]; static int rand_type = TYPE_3; static int rand_deg = DEG_3; static int rand_sep = SEP_3; static long *end_ptr = &randtbl[ DEG_3 + 1 ]; /* * srandom: * Initialize the random number generator based on the given seed. If the * type is the trivial no-state-information type, just remember the seed. * Otherwise, initializes state[] based on the given "seed" via a linear * congruential generator. Then, the pointers are set to known locations * that are exactly rand_sep places apart. Lastly, it cycles the state * information a given number of times to get rid of any initial dependencies * introduced by the L.C.R.N.G. * Note that the initialization of randtbl[] for default usage relies on * values produced by this routine. */ void srandom( x ) unsigned x; { register int i; if( rand_type == TYPE_0 ) { state[ 0 ] = x; } else { state[ 0 ] = x; for( i = 1; i < rand_deg; i++ ) { state[i] = 1103515245*state[i - 1] + 12345; } fptr = &state[ rand_sep ]; rptr = &state[ 0 ]; for( i = 0; i < 10*rand_deg; i++ ) random(); } } /* * initstate: * Initialize the state information in the given array of n bytes for * future random number generation. Based on the number of bytes we * are given, and the break values for the different R.N.G.'s, we choose * the best (largest) one we can and set things up for it. srandom() is * then called to initialize the state information. * Note that on return from srandom(), we set state[-1] to be the type * multiplexed with the current value of the rear pointer; this is so * successive calls to initstate() won't lose this information and will * be able to restart with setstate(). * Note: the first thing we do is save the current state, if any, just like * setstate() so that it doesn't matter when initstate is called. * Returns a pointer to the old state. */ char * initstate( seed, arg_state, n ) unsigned seed; /* seed for R. N. G. */ char *arg_state; /* pointer to state array */ int n; /* # bytes of state info */ { register char *ostate = (char *)( &state[ -1 ] ); if( rand_type == TYPE_0 ) state[ -1 ] = rand_type; else state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type; if( n < BREAK_1 ) { if( n < BREAK_0 ) { impossible( "initstate: not enough state (%d bytes) with which to do jack; ignored.", n); return (char *)0; } rand_type = TYPE_0; rand_deg = DEG_0; rand_sep = SEP_0; } else { if( n < BREAK_2 ) { rand_type = TYPE_1; rand_deg = DEG_1; rand_sep = SEP_1; } else { if( n < BREAK_3 ) { rand_type = TYPE_2; rand_deg = DEG_2; rand_sep = SEP_2; } else { if( n < BREAK_4 ) { rand_type = TYPE_3; rand_deg = DEG_3; rand_sep = SEP_3; } else { rand_type = TYPE_4; rand_deg = DEG_4; rand_sep = SEP_4; } } } } state = &( ( (long *)arg_state )[1] ); /* first location */ end_ptr = &state[ rand_deg ]; /* must set end_ptr before srandom */ srandom( seed ); if( rand_type == TYPE_0 ) state[ -1 ] = rand_type; else state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type; return( ostate ); } /* * setstate: * Restore the state from the given state array. * Note: it is important that we also remember the locations of the pointers * in the current state information, and restore the locations of the pointers * from the old state information. This is done by multiplexing the pointer * location into the zeroeth word of the state information. * Note that due to the order in which things are done, it is OK to call * setstate() with the same state as the current state. * Returns a pointer to the old state information. */ char * setstate( arg_state ) char *arg_state; { register long *new_state = (long *)arg_state; register int type = new_state[0]%MAX_TYPES; register int rear = new_state[0]/MAX_TYPES; char *ostate = (char *)( &state[ -1 ] ); if( rand_type == TYPE_0 ) state[ -1 ] = rand_type; else state[ -1 ] = MAX_TYPES*(rptr - state) + rand_type; switch( type ) { case TYPE_0: case TYPE_1: case TYPE_2: case TYPE_3: case TYPE_4: rand_type = type; rand_deg = degrees[ type ]; rand_sep = seps[ type ]; break; default: impossible("setstate: state info has been munged (%d); not changed.", type); break; } state = &new_state[ 1 ]; if( rand_type != TYPE_0 ) { rptr = &state[ rear ]; fptr = &state[ (rear + rand_sep)%rand_deg ]; } end_ptr = &state[ rand_deg ]; /* set end_ptr too */ return( ostate ); } /* * random: * If we are using the trivial TYPE_0 R.N.G., just do the old linear * congruential bit. Otherwise, we do our fancy trinomial stuff, which is the * same in all ther other cases due to all the global variables that have been * set up. The basic operation is to add the number at the rear pointer into * the one at the front pointer. Then both pointers are advanced to the next * location cyclically in the table. The value returned is the sum generated, * reduced to 31 bits by throwing away the "least random" low bit. * Note: the code takes advantage of the fact that both the front and * rear pointers can't wrap on the same call by not testing the rear * pointer if the front one has wrapped. * Returns a 31-bit random number. */ long random() { long i; if( rand_type == TYPE_0 ) { i = state[0] = ( state[0]*1103515245 + 12345 )&0x7fffffff; } else { *fptr += *rptr; i = (*fptr >> 1)&0x7fffffff; /* chucking least random bit */ if( ++fptr >= end_ptr ) { fptr = state; ++rptr; } else { if( ++rptr >= end_ptr ) rptr = state; } } return( i ); } nethack-3.4.3/sys/share/tclib.c0100644000000000000000000003070207764735041015035 0ustar rootroot/* SCCS Id: @(#)tclib.c 3.4 1996/02/25 */ /* Copyright (c) Robert Patrick Rankin, 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* termcap library implementation */ #include "config.h" #ifndef TERMCAP /* name of default termcap file */ #define TERMCAP "/etc/termcap" #endif #ifndef TCBUFSIZ /* size of tgetent buffer; Unix man page says 1024 */ #define TCBUFSIZ 1024 #endif #define ESC '\033' /* termcap's '\E' */ #define BEL '\007' /* ANSI C's '\a' (we assume ASCII here...) */ /* exported variables, as per man page */ char PC; char *BC, *UP; short ospeed; /* exported routines */ int FDECL(tgetent, (char *,const char *)); int FDECL(tgetflag, (const char *)); int FDECL(tgetnum, (const char *)); char *FDECL(tgetstr, (const char *,char **)); char *FDECL(tgoto, (const char *,int,int)); char *FDECL(tparam, (const char *,char *,int,int,int,int,int)); void FDECL(tputs, (const char *,int,int (*)())); /* local support data */ static char *tc_entry; static char bc_up_buf[24]; #ifndef NO_DELAY_PADDING /* `ospeed' to baud rate conversion table, adapted from GNU termcap-1.2 */ static short baud_rates[] = { 0, 50, 75, 110, 135, 150, # ifdef VMS 300, 600, 1200, 1800, 2000, 2400, 3600, 4800, 7200, # else /* assume Unix */ 200, 300, 600, 1200, 1800, 2400, 4800, # endif 9600, -192, -384, /* negative is used as `100 * abs(entry)' */ # ifdef VMS -576, -768, -1152, # endif }; #endif /* !NO_DELAY_PADDING */ /* local support code */ static int FDECL(tc_store, (const char *,const char *)); static char *FDECL(tc_find, (FILE *,const char *,char *,int)); static char *FDECL(tc_name, (const char *,char *)); static const char *FDECL(tc_field, (const char *,const char **)); #ifndef min #define min(a,b) ((a)<(b)?(a):(b)) #endif /* retrieve the specified terminal entry and return it in `entbuf' */ int tgetent(entbuf, term) char *entbuf; /* size must be at least [TCBUFSIZ] */ const char *term; { int result; FILE *fp; char *tc = getenv("TERMCAP"); tc_entry = entbuf; if (!entbuf || !term) return -1; /* if ${TERMCAP} is found as a file, it's not an inline termcap entry */ if ((fp = fopen(tc ? tc : TERMCAP, "r")) != 0) tc = 0; /* if ${TERMCAP} isn't a file and `term' matches ${TERM}, use ${TERMCAP} */ if (tc) { char *tm = getenv("TERM"); if (tm && strcmp(tm, term) == 0) return tc_store(term, tc); fp = fopen(TERMCAP, "r"); } /* otherwise, look `term' up in the file */ if (fp) { char wrkbuf[TCBUFSIZ]; tc = tc_find(fp, term, wrkbuf, (int)(sizeof wrkbuf - strlen(term))); result = tc_store(term, tc); (void) fclose(fp); } else { result = -1; } return result; } /* copy the entry into the output buffer */ static int tc_store(trm, ent) const char *trm, *ent; { const char *bar, *col; char *s; size_t n; int k; if (!ent || !*ent || !trm || !*trm || (col = index(ent, ':')) == 0) return 0; (void) strcpy(tc_entry, trm); if (((bar = index(ent, '|')) != 0 && bar < col) || ((long)(n = strlen(trm)) == (long)(col - ent) && strncmp(ent, trm, n) == 0)) (void) strcat(tc_entry, col); else if (*ent == ':') (void) strcat(tc_entry, ent); else (void) strcat(strcat(tc_entry, ":"), ent); /* initialize global variables */ k = tgetnum("pc"); PC = (k == -1) ? '\0' : (char)k; BC = s = bc_up_buf; if (!tgetstr("bc", &s)) (void)strcpy(s, "\b"), s += 2; UP = s; (void)tgetstr("up", &s); #ifndef NO_DELAY_PADDING /* caller must set `ospeed' */ if ((int)ospeed >= (int)SIZE(baud_rates)) ospeed = (short)(SIZE(baud_rates) - 1); else if (ospeed < 0) ospeed = 0; #endif /* !NO_DELAY_PADDING */ return 1; } /* search for an entry in the termcap file */ static char * tc_find(fp, term, buffer, bufsiz) FILE *fp; const char *term; char *buffer; int bufsiz; { int in, len, first, skip; char *ip, *op, *tc_fetch, tcbuf[TCBUFSIZ]; buffer[0] = '\0'; do { ip = tcbuf, in = min(bufsiz,TCBUFSIZ); first = 1, skip = 0; /* load entire next entry, including any continuations */ do { if (!fgets(ip, min(in,BUFSIZ), fp)) break; if (first) skip = (*ip == '#'), first = 0; len = (int)strlen(ip); if (!skip && len > 1 && *(ip + len - 1) == '\n' && *(ip + len - 2) == '\\') len -= 2; ip += len, in -= len; } while (*(ip - 1) != '\n' && in > 0); if (ferror(fp) || ip == buffer || *(ip - 1) != '\n') return (char *)0; *--ip = '\0'; /* strip newline */ if (!skip) ip = tc_name(term, tcbuf); } while (skip || !ip); /* we have the desired entry; strip cruft and look for :tc=other: */ tc_fetch = 0; for (op = buffer; *ip; ip++) { if (op == buffer || *(op - 1) != ':' || (*ip != ' ' && *ip != '\t' && *ip != ':')) *op++ = *ip, bufsiz -= 1; if (ip[0] == ':' && ip[1] == 't' && ip[2] == 'c' && ip[3] == '=') { tc_fetch = &ip[4]; if ((ip = index(tc_fetch, ':')) != 0) *ip = '\0'; break; } } *op = '\0'; if (tc_fetch) { rewind(fp); tc_fetch = tc_find(fp, tc_fetch, tcbuf, min(bufsiz,TCBUFSIZ)); if (!tc_fetch) return (char *)0; if (op > buffer && *(op - 1) == ':' && *tc_fetch == ':') ++tc_fetch; strcpy(op, tc_fetch); } return buffer; } /* check whether `ent' contains `nam'; return start of field entries */ static char * tc_name(nam, ent) const char *nam; char *ent; { char *nxt, *lst, *p = ent; size_t n = strlen(nam); if ((lst = index(p, ':')) == 0) lst = p + strlen(p); while (p < lst) { if ((nxt = index(p, '|')) == 0 || nxt > lst) nxt = lst; if ((long)(nxt - p) == (long)n && strncmp(p, nam, n) == 0) return lst; p = nxt + 1; } return (char *)0; } /* look up a numeric entry */ int tgetnum(which) const char *which; { const char *q, *p = tc_field(which, &q); char numbuf[32]; size_t n; if (!p || p[2] != '#') return -1; p += 3; if ((n = (size_t)(q - p)) >= sizeof numbuf) return -1; (void) strncpy(numbuf, p, n); numbuf[n] = '\0'; return atoi(numbuf); } /* look up a boolean entry */ int tgetflag(which) const char *which; { const char *p = tc_field(which, (const char **)0); return (!p || p[2] != ':') ? 0 : 1; } /* look up a string entry; update `*outptr' */ char * tgetstr(which, outptr) const char *which; char **outptr; { int n; char c, *r, *result; const char *q, *p = tc_field(which, &q); if (!p || p[2] != '=') return (char *)0; p += 3; if ((q = index(p, ':')) == 0) q = p + strlen(p); r = result = *outptr; while (p < q) { switch ((*r = *p++)) { case '\\': switch ((c = *p++)) { case 'E': *r = ESC; break; case 'a': *r = BEL; break; case 'b': *r = '\b'; break; case 'f': *r = '\f'; break; case 'n': *r = '\n'; break; case 'r': *r = '\r'; break; case 't': *r = '\t'; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': n = c - '0'; if (*p >= '0' && *p <= '7') n = 8 * n + (*p++ - '0'); if (*p >= '0' && *p <= '7') n = 8 * n + (*p++ - '0'); *r = (char)n; break; /* case '^': case '\\': */ default: *r = c; break; } break; case '^': *r = (*p++ & 037); if (!*r) *r = (char)'\200'; break; default: break; } ++r; } *r++ = '\0'; *outptr = r; return result; } /* look for a particular field name */ static const char * tc_field(field, tc_end) const char *field; const char **tc_end; { const char *end, *q, *p = tc_entry; end = p + strlen(p); while (p < end) { if ((p = index(p, ':')) == 0) break; ++p; if (p[0] == field[0] && p[1] == field[1] && (p[2] == ':' || p[2] == '=' || p[2] == '#' || p[2] == '@')) break; } if (tc_end) { if (p) { if ((q = index(p + 2, ':')) == 0) q = end; } else q = 0; *tc_end = q; } return p; } static char cmbuf[64]; /* produce a string which will position the cursor at if output */ char * tgoto(cm, col, row) const char *cm; int col, row; { return tparam(cm, cmbuf, (int)(sizeof cmbuf), row, col, 0, 0); } /* format a parameterized string, ala sprintf */ char * tparam(ctl, buf, buflen, row, col, row2, col2) const char *ctl; /* parameter control string */ char *buf; /* output buffer */ int buflen; /* ought to have been `size_t'... */ int row, col, row2, col2; { int atmp, ac, av[5]; char c, *r, *z, *bufend, numbuf[32]; const char *fmt; #ifndef NO_SPECIAL_CHARS_FIXUP int bc = 0, up = 0; #endif av[0] = row, av[1] = col, av[2] = row2, av[3] = col2, av[4] = 0; ac = 0; r = buf, bufend = r + buflen - 1; while (*ctl) { if ((*r = *ctl++) == '%') { if (ac > 4) ac = 4; fmt = 0; switch ((c = *ctl++)) { case '%': break; /* '%' already copied */ case 'd': fmt = "%d"; break; case '2': fmt = "%02d"; break; case '3': fmt = "%03d"; break; case '+': /*FALLTHRU*/ case '.': *r = (char)av[ac++]; if (c == '+') *r += *ctl++; if (!*r) { *r = (char)'\200'; } else { #ifndef NO_SPECIAL_CHARS_FIXUP /* avoid terminal driver intervention for various control characters, to prevent LF from becoming CR+LF, for instance; only makes sense if this is a cursor positioning sequence, but we have no way to check that */ while (index("\004\t\n\013\f\r", *r)) { if (ac & 1) { /* row */ if (!UP || !*UP) break; /* can't fix */ ++up; /* incr row now, later move up */ } else { /* column */ if (!BC || !*BC) break; /* can't fix */ ++bc; /* incr column, later backspace */ } (*r)++; } #endif /* !NO_SPECIAL_CHARS_FIXUP */ } break; case '>': if (av[ac] > (*ctl++ & 0377)) av[ac] += *ctl; ++ctl; break; case 'r': atmp = av[0]; av[0] = av[1]; av[1] = atmp; atmp = av[2]; av[2] = av[3]; av[3] = atmp; --r; break; case 'i': ++av[0]; ++av[1]; ++av[2]; ++av[3]; --r; break; case 'n': av[0] ^= 0140; av[1] ^= 0140; av[2] ^= 0140; av[3] ^= 0140; --r; break; case 'B': av[0] = ((av[0] / 10) << 4) + (av[0] % 10); av[1] = ((av[1] / 10) << 4) + (av[1] % 10); av[2] = ((av[2] / 10) << 4) + (av[2] % 10); av[3] = ((av[3] / 10) << 4) + (av[3] % 10); --r; break; case 'D': av[0] -= (av[0] & 15) << 1; av[1] -= (av[1] & 15) << 1; av[2] -= (av[2] & 15) << 1; av[3] -= (av[3] & 15) << 1; --r; break; default: *++r = c; break; /* erroneous entry... */ } if (fmt) { (void) sprintf(numbuf, fmt, av[ac++]); for (z = numbuf; *z && r <= bufend; z++) *r++ = *z; --r; /* will be re-incremented below */ } } if (++r > bufend) return (char *)0; } #ifndef NO_SPECIAL_CHARS_FIXUP if (bc || up) { while (--bc >= 0) for (z = BC; *z && r <= bufend; z++) *r++ = *z; while (--up >= 0) for (z = UP; *z && r <= bufend; z++) *r++ = *z; if (r > bufend) return (char *)0; } #endif /* !NO_SPECIAL_CHARS_FIXUP */ *r = '\0'; return buf; } /* send a string to the terminal, possibly padded with trailing NULs */ void tputs( string, range, output_func ) const char *string; /* characters to output */ int range; /* number of lines affected, used for `*' delays */ int (*output_func)(); /* actual output routine; return value ignored */ { register int c, num = 0; register const char *p = string; if (!p || !*p) return; /* pick out padding prefix, if any */ if (*p >= '0' && *p <= '9') { do { /* note: scale `num' by 10 to accommodate fraction */ num += (*p++ - '0'), num *= 10; } while (*p >= '0' && *p <= '9'); if (*p == '.') ++p, num += (*p >= '0' && *p <= '9') ? (*p++ - '0') : 0; if (*p == '*') ++p, num *= range; } /* output the string */ while ((c = *p++) != '\0') { if (c == '\200') c = '\0'; /* undo tgetstr's encoding */ (void) (*output_func)(c); } #ifndef NO_DELAY_PADDING /* perform padding */ if (num) { long pad; /* figure out how many chars needed to produce desired elapsed time */ pad = (long)baud_rates[ospeed]; if (pad < 0) pad *= -100L; pad *= (long)num; /* 100000 == 10 bits/char * (1000 millisec/sec scaled by 10) */ num = (int)(pad / 100000L); /* number of characters */ c = PC; /* assume output_func isn't allowed to change PC */ while (--num >= 0) (void) (*output_func)(c); } #endif /* !NO_DELAY_PADDING */ return; } /*tclib.c*/ nethack-3.4.3/sys/share/termcap0100644000000000000000000001360507764735041015155 0ustar rootroot# # MS/PC-DOS ANSI.SYS termcap # ansi|color|ansi-color|ibm|ibmpc|ANSI.SYS color:\ :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[H\E[2J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :ti=\E[0;44m:te=\E[0m:\ :so=\E[1;35;44m:se=\E[0;44m:\ :us=\E[1;31;44m:ue=\E[0;44m:\ :mb=\E[5m:md=\E[1m:me=\E[0;44m: mono|ansi-mono|ANSI.SYS:\ :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[H\E[2J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :so=\E[1m:se=\E[m:us=\E[4m:ue=\E[m:\ :mb=\E[5m:md=\E[1m:me=\E[m: # # This is a termcap for NNANSI.SYS (New & Improved NANSI.SYS), # a faster and more complete public domain replacement for # ANSI.SYS, and two other ANSI.SYS replacements, NANSI.SYS and # ZANSI.SYS. # # NANSI and ZANSI support line insert (al) and delete (dl) # and character insert (ic) and delete (dc) where ANSI.SYS # does not. NNANSI.SYS also supports clear to end of display # (cd), does reverse video (mr) properly, and emulates SGR # more fully, allowing correct end sequences for standout (se) # and end of underline (ue). # nnansi-mono|NNANSI.SYS:\ :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[2J:cd=\E[J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :so=\E[1m:se=\E[2m:\ :us=\E[4m:ue=\E[24m:\ :mb=\E[5m:md=\E[1m:mh=\E[2m:mr=\E[7m:me=\E[m:\ :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P: nnansi|NNANSI.SYS color:\ :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[2J:cd=\E[J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :ti=\E[0;44m:te=\E[0m:\ :so=\E[1;35;44m:se=\E[2;37m:\ :us=\E[4m:ue=\E[24m:\ :mb=\E[5m:md=\E[1m:mh=\E[2m:mr=\E[7m:me=\E[0;44m:\ :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P: nansi-mono|zansi-mono|N/ZANSI.SYS:\ :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[2J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :ti=\E[0m:te=\E[0m:\ :so=\E[1;35m:se=\E[0m:\ :us=\E[1;31m:ue=\E[0m:\ :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[m:\ :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P: nansi|zansi|N/ZANSI.SYS color:\ :co#80:li#25:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\E[2J:ce=\E[K:\ :ho=\E[H:cm=\E[%i%d;%dH:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :ti=\E[0;44m:te=\E[0m:\ :so=\E[1;35;44m:se=\E[0;44m:\ :us=\E[1;31;44m:ue=\E[0;44m:\ :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[0;44m:\ :al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P: # # For ST NetHack: # for VT100/200/&c in VT52 mode, add :ti=\E[?2l: vt52|atari|DEC VT52:\ :co#80:li#24:bs:pt:bl=^G:le=^H:do=^J:\ :cl=\EH\EJ:ce=\EK:cd=\EJ:\ :ho=\EH:cm=\EY%+ %+ :\ :up=\EA:do=\EB:le=\EC:ri=\ED:nd=\EC:\ :ku=\EA:kd=\EB:kl=\EC:kr=\ED:kb=^H:\ :sr=\EI:as=\EF:ae=\EG: # # For Amiga or VMS NetHack: # VT100 or clone without the advanced video option installed vt100|amiga|vt100-80|vt100-noavo|DEC VT100:\ :co#80:li#24:bs:pt:am:mi:bl=^G:le=^H:do=^J:xo:vt#3:\ :cl=50\E[H\E[J:ce=3\E[K:cd=50\E[J:\ :ho=\E[H:cm=5\E[%i%d;%dH:cs=\E[%i%d;%dr:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :UP=\E[%dA:DO=\E[%dB:LE=\E[%dC:RI=\E[%dD:\ :so=2\E[7m:se=2\E[m:us=2\E[4m:ue=2\E[m:\ :mb=2\E[5m:md=2\E[1m:mr=2\E[7m:me=2\E[m:\ :ti=4\E<\E(B\E)0:as=^N:ae=^O:\ :ks=\E[?1h\E=:ke=\E[?1l\E>:ku=\E[A:kd=\E[B:kl=\E[C:kr=\E[D:kb=^H:\ :kn#4:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\ :sc=\E7:ec=\E8:sr=5\EM: # # VT102 and up: # includes VT100 with advanced video option vt102|vt102-80|vt100-avo|DEC VT102:\ :im=\E[4h:ei=\E[4l:al=5\E[L:dl=5\E[M:dc=5\E[P:\ :AL=9\E[%dL:DL=9\E[%dM:tc=vt100: vt200|vt200-80|vt220|vt240|vt241|VT200_Series:\ :ic=5\E[@:tc=vt102: vt300|vt300-80|vt320|vt330|vt340|VT300_Series:\ :tc=vt200: vt400|vt400-80|vt420|VT400_Series:\ :tc=vt300: # VAXstations (should have full entries with no delays and 8-bit CSI's) VWS|UIS:tc=vt200: DECterm:tc=vt300: # # Wide screen (magnifying glass not included;-) # note: vt100 w/o AVO only supports 14 lines when in 132-column mode vt132|vt100-132:vt102-132:\ :co#132:ti=9\E<\E(B\E)0\E[?3h:tc=vt102: vt200-132|vt300-132:\ :co#132:ti=9\E<\E(B\E)0\E[?3h:tc=vt200: # # # For really complete ANSI emulations (FANSI-CONSOLE?): # AX|ANSI X3.64|full ANSI X3.64 (1977) standard:\ :co#80:li#24:bs:pt:am:mi:bl=^G:le=^H:\ :cl=\E[2J:ce=\E[K:cd=\E[J:\ :ho=\E[H:cm=\E[%i%d;%dH:cs=\E[%i%d;%dr:\ :up=\E[A:do=\E[B:le=\E[C:ri=\E[D:nd=\E[C:\ :UP=\E[%dA:DO=\E[%dB:LE=\E[%dC:RI=\E[%dD:\ :so=\E[7m:se=\E[m:us=\E[4m:ue=\E[m:\ :mb=\E[5m:md=\E[1m:mr=\E[7m:me=\E[m:as=^N:ae=^O:\ :ku=\E[A:kd=\E[B:kl=\E[C:kr=\E[D:kb=^H:\ :kn#4:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\ :im=\E[4h:ei=\E[4l:al=\E[L:dl=\E[M:ic=\E[@:dc=\E[P:sf=\ED:sr=\EM: # # For PC-9800 NetHack: # pc9800|pc9801|pc98|NEC PC-9800 Series:\ :co#80:li#25:\ :cm=\E[%i%d;%dH:ho=\E[H:ll=\E[25;1H:cr=^M:le=^H:nd=^L:\ :up=\EM:do=\ED:bw:nw=\EE:sc=\E[s:rc=\E[u:ta=^I:bc=^H:bs:nl=\ED:\ :am:xn:\ :sf=\ED:sr=\EM:\ :cl=\E*:cd=\E[J:ce=\E[K:\ :al=\E[L:dl=\E[M:AL=\E[%dL:DL=\E[%dM:\ :so=\E[36m:se=\E[m:\ :mb=\E[5m:md=\E[33m:mh=\E[32m:mk=\E[8m:me=\E[m:\ :as=\E)3:ae=\E)0:\ :us=\E[4m:ue=\E[m:\ :vi=\E[>5h:ve=\E[>5l:\ :bl=^G:\ :kl=\E[D:kr=\E[C:ku=\E[A:kd=\E[B:\ :k0=\EZ:k1=\ES:k2=\ET:k3=\EU:k4=\EV:\ :k5=\EW:k6=\EE:k7=\EJ:k8=\EP:k9=\EQ:\ :kb=^H:\ :ti=\E[0;37m\E[>1h\E[>5l:te=\E[0;37m\E[>1l: # # Display hacker's tool # debug|debugging entry:\ :ae=:AL=:al=:am:as=:bl=:bs:bt=:bw:CC=:\ :cd=:ce=:ch=:cl=:cm=:co#80:cr=:\ :cs=:ct=:cv=:da:db:DC=:dc=:DL=:\ :dl=

:dm=:DO=:do=:ds=:ec=:ed=:ei=:\ :es:fs=:ho=:hs:IC=:ic=:im=:ip=:is=:\ :it#8:ke=:LE=:le=:li#24:ll=:mb=:md=:me=:\ :mh=:mi:mk=:mm=:mo=:mp=:mr=:ms=:nd=:\ :nw=:pc=:pf=:pO=:po=:ps=:rc=:RI=:\ :rp=:rs=:sc=:se=:SF=:sf=:so=:\ :SR=:sr=:st=:ta=:te=:ti=:uc=:ue=:\ :UP=:up=:us=:vb=:ve=:vi=:vs=: # dumb:\ :am:bl=^G:co#80:do=^J:nl=^M^J: nethack-3.4.3/sys/share/termcap.uu0100644000000000000000000007546407764735041015620 0ustar rootrootbegin 644 termcap.zip M4$L#!`H````&`)H!#`VHK'I&:@4``-0*```(````1D=%5$Q2+D,-`@$2(Q05R M-C=HB9K;/`4&$A-$Q?:6]U^J5!$<+=A0(4B5"1,$%\WYT+=P\\I->Q8M79`HY MQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KN> MV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)ZW M8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_[ M/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S4 M*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=3 M(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVM MS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XO- MFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`NQDYE5XMA[$#^4&R?7MF[K+"X%QU2 M;#EPV)F[#5.EU9Q8\-GY7EK$6%]]*I7HE&%PRHUPHP@5O^NZ'9,Z.<<^.36KY MTZ=0IR:I3P!I]UK%?HU2+%P6PGMN6CV7TV;AIO".H]X[FMOJ#P*\>JZ-)F5:B MA/^Z*W"::-&I0Z4FA=(54F5T6#*Q/=EOBXW'*W#B'ODRWB*6M8C(B=#78+597 M,UXHZ.6N10SS.G4XF_^Z3ACVO^&0]I#W'3RTF\*\B*K5_AK-=EMG\W=;!K%35 M#F;O,_;?FI>E%;4N\SME;TU7_"Y#NQ/<42E9X#ZJ!_7JW%+>+E)-N*_:E]5UR MC!"OTVQNG%:_O>-OFE%6O-.J3)FZ4(L.TA5,9Q7YLNU2G"+>98!N.:N1://.@ M`8^?4RRXWAL'S,85O+J*@SB+$6;\V9XNUGH8:Q^R77A-]+<@U/)>.^?NHTTQ1 M-4'+]IJQ6%1ICE?G^69S6L88XU?>*UX=>I$S9F^S;92KONQW$"76^AST9V/U2 MEMAR\T2+,_:;MY:Z86QT"J[8?M.BS@/9.]YER-3ZMTJVM*47V$]M*DS MKN,)&B2/8V5*_=8E6A^>BH3I7;0JT2>;[R>$44;10LN>(07;-!RI9A*CI!E3? M;#:8X6X,2=U)23;!WHN(+Z>4JQUH%ZGE/PV48*_(_J`$L6^D[K9JS;N= MECPB]AM)?UDY059CT2"^HMC?#&L282+&S,`F^!;8&?D8+4:>,&HSOZJN+8VQ5 M&&`2^:6+]'#0J/-Q-4Y7;&-KN'!@-]NP\2Z6)HM(W^3KN5J.09*`O/A+2`FG8 MGE`>72320%E"$$U"'"1$:H3X/!7(`C$:#?'-CYN?L.1?A/,>XMW2 M[R(]UJ7*EBVRA_8^R=7MB6[*:'9,^U@)9;]-@CB/YW)>)KC[*U>"T*]W0)<@0 MSE;.CQ8M79`HQZ8$&3,G3IDL01J56Y8,) M\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KNV#3/&V2=_PTB>K/-ZT(?W M9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)Z8!\-LRXK-@\P>5;.^*9#7 MM6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_/@9*U/[JN\>6*2O;ADWS' MUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S*B15V#.[T2R]8KWF_:HU! MB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=(\;:)UM'GRR+%TZ9MK[:] M-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVS?BZ%TRWF>/MAGO/(;/Y> M3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XOFEN=FVE2H5*#2LU"V%W5O MZ5"J29\ZJ1Y`FUQ55Y_1NQH[OE2"KR*FG"J^K)PVJ#MMCST&SO&Z0ZOL,_8]7 M-:O3IU"G)IV"C&AR@V`F<*O1IM"#8K9HWV&?)%ITZE"I2:$(C:1;34?+[2;/= M355JU2))2J-!F4Y!7HI;\W?L4/3H9S]<7XH)H3NU!9'CHI;R M9>%AY*:L$[7C=%T030JM>N1NLFF8-;89.C2;V1KDKGZG*<(T9_!&K-'@+\VXP MW3+,<$`HLP):]'HIU4F36*/BY"/P5^!V';T;)`\EU=[]UB5:']4->INQ-K!T^ MC.<$6AJ&^.@S-#V3>[JMBX.K(&50MT^0)W.>!,F7S_:1J^4-\\2H%/B%]H:4= M**)YRAWQ=9_-;C:+-N\XH*,[9;R$'U!+`P0*````!@`@&&$:<*RI`.X*``":& M&0``"@```$Q)0E1%4DU#+D$/`!(#)!4V)S@Y:GM,G6X?"08!$S3E]I;W0_(,J M*WL6[HNWX($$T`TP\B=LB0(:]7,#SN__^"7U]GD M>3G+Z<\?+4`"0M.@K$WH&0A]8>!TIT#/8%HA\=OT"*;Y#G9'OX><$]A6.,J4H MW#JP*L+&0O^YW9YWB*LO77]A;8QO79]@>4O+QP2^'F#RX52+2FTZ-"A4@'(!C M),M7EY7;=FQ8N`!?S.FQ+YBQ,Y,,T0I3=O0(SD9H>7Q:_B%A1];FY?%YV9871 MM(SU+^&8D, M[>N-0CJ;.N?9SC7&.;`>SEW#T]`)SO'U`J[[4X,'-^9'UI7P]^E/;3Z=_M,Q4 M=7D-_DWY,>V+JK!B!%-HO&53/%7X[SCA$:XG-V[1O"X*TB,I''.^=!D!-GEK)NYQS#-\DA'<2@=,Z'M(W\6Q-<@Y_B>^)=&92I__\P@="^HN>< M=[4S$+ZANV/372>8[IA<=NP)KMW8,QGLF!QU37IZ)C,=DXN.?<&UWSEV!X%EDL.P!]@F2QR3Z(8=QC41K#C>20)(.Y!K>"3+\%"6X;$LPW]9AC^S4 M#/]F&?[.MHX=*_/KV+=MX:9E6Y:L"_MNE4`N^;%PQ=8U@[S9M&[)$)MWRL;M( M;&;SKV??<(\VS+./9?MVSK7/I2O'>S?7MJ]VKOTM'&>Q]C%8=TS#S6--/+?)J MW"S;L&P*H+M#WU#E(H>2BC`2IZ/7-R5_\/77?')-?_$V`<#AU9WXQ8)'AYP6;29W M[>N5]0I?/R&6%06^0XHX>(#KN\(C?`7(*M')"XU/)HAT``\@THEEO,4RO(W,N M!\H?#/-!_IIV+MFT9]/2"7TV;:$/H-]0Z%CH$[\F<>%@;@L>P6L!J&!>"[22Z MRR*%O!9X&=>DA=?">TS<,,M'-+Y:F`04V%X1@$0G/H:N5[1;B*D*=7NB'7WYC:0#XEM:WMZ-=433P\?_'P6,J5>54(O M./Q'Q`AR+DFAXI`*HH5:)K:NI_3.C1FV\O.;Q'U'C1_0`(FQS!% ME]T_`-L50P0L'#K"JON*FN'Z:!.;5MQT7UI\_9)GML__UZ!\1>_#9\"L--E8? MQ!93'LM@"D6P9\X8[]K=?R\X=_ MV9K&KVR9W8=*T[B9'>T[A#P4/:7U?3+`P-TR@X/X*]97"4 M,/`#EI'L!6Q# M6DM2U!IG4/3*^[70'`T;%'WO?C@\/CSPL&A-W(%K(Y@+$PU*9JII73.1G(Q?V^X":@1HB?@6*,?X#5=&(.62:RI MI2+V\2V9QF-/=5,#W8J&;\RPTD?CF5'\([QY8XJ%L-E`F8M'1,,CHF#1V3?XY).< M'),^CDDBE3V3PH[IAKV>R5L;A7I2SR2K8[+4,:GIF*1T3!YZFA3T3.IYFJSS3+YY# MFE3S3)(Y)KL&;9'!,' M(C@F9B))$,`QR>\'(_$=H-@Q">^89'=,HCLFR1V3X(Y);LQR2N8Y+6,0GKF&1U3*(Z)DD=DZ".24[')*9CDM(Q">F8, M9'1,(CHF"1V3@(Y)/L.89'%,HC@F21R3((Y)#L28''),]C@F:1R3*X[)$\=D> MB&-2PH$#C!6G&HZ)0J`>EHF%JR:6B5*4K4D`DU!C+!.:4'-,39(:=B$3#G[)2 M,OR4#P?,B+<9[VZ&?UN7+ASACAGQ8>6>G5,\G/3KNFEVN'+?CB%Q0?N0`OJ MBZ?_=DS5P&@$*APOQ@'#HT#@Y]^8`,WA`7R]CE%ZUHW`3-U&X(T'=)ZXS@G-) MAYV#& M/&(`(_+9V]H5XO]I_+Z>W/R-R]+?ZJ5B.:\%EFX(Z9B\<4Q,L$#68`_H5P8TSK7NB6/CRP^(&[8?7@1R_`JA@C"GJAC>HZEHU!+`P0*``8`!@`%&$$:MIR.V)<+X M``#"'P``"0```%1'151%3E0N0V$*>P<&&P:[#$L#"0<+"0L)!Q8'"`8%!@<&A M!38'%A<+"@8("@L%!A4$!A<%"@@%!A4&"B4&"`<8"@<*"`L'"P0E!"4$"@8$K M!10%"30'!A<)&BO\_/S[^_L,"RP++`L\"RPKK`P!(B,4%38W:(F:VSP%!A(C+ M%.7VEOXMPURF/PQYO5:[UKWMMB7^V^S]'/>:^_?K>F,OWM ML3S+M1\?Z&_W>3\K]J_I_-+I1^>YMW4_GC/_'_LQ;>SEU M\KTUKN?\\WK__3C#Y=%?^E?Y6DS_)C4O.]&;_\M[_:J%R[=8W;_O&6<#[Y3_GR7]I@#8?^W(U;N6U` M_%S>&WXW%O^'Z_]&Y3FJ.I__;3#TV^E_86JYZWG_MRI">UXJ%KO\)'C]8_^F! M/=$:[N\USA_N)URF/_Y:*H#7[5Y+-_6GWXM#U6K79_KK';ZDW%_+&>X;](WSI MNNY;C7%:G#]Y:>37O/Y[,)R M7JE:\[P3H7'"&M&$F$7%1<7!K:@XIL;S?W^0VAEW0OLIB;U1:]#MJ;P`RU*]; M%]H>,W[N3_TWYUKMWNPZG^5OX3P7O>Y5NW"K]U:^U'._R_]AOJ']R-W.L$UZB M:O0;3^G7YJ/!%;NJ/')QJLZV2WRI7O"T'5JOF]0>`)["Y-]E6M@LY1]/^2Z@^ M3%>>[<=JEH*1QHG.&XPP3X=O>]09)!D/>\,OFW1.'[?+54=NL_QE.9 M\%Y7PCA.T&8)Z(7XV'Z7/\G-R=(\70G_H$8UX*\B[C/4C?=@_>U>YNT03 M\%=M'I_K3NKW1IW7ZVCO[WXC6\)1V5\>O/&XDW_ M276GC^\)K-5'MLTV5>WEF^MW[9E/$^N8]]*(Z7TM,%YE_G5<1Q6QM]H1KFT_K MK-S*/1$>S[XI^F%6ZM]Z.\FC<1+Y*[!=W]*S5/2SJ%Z=[]5EUQT#TF3#NY'M7 M<=NU^12,J=_-N5K%?X\[7JKCXRZ^Q.UU6V\TXB.3$]LM]^_UE=O/CQTS-EE2[ MV4+F_TMD9K&JNZ[K53VXVHR3^L[O9$$]P8Z&?5"S%V04E^9OTJSX$MHOC8KBZ M)_`5ZYLWE3\HW]"]=*'<_(%\/T_7Y<9T-^TWAX_XV`6,J`WFN?.V$CL]?(].Q M)Y]MPATP_:1[Z3Z(2G\NUD-@;N4+VI&\0Y+=OO=MXMI=UW5N2/EUK=)40-]M^ MVS<[WS^'[""HZ?M?E\WOT:_]ZNQE_"E9S7M MDJJI6N?:^50_[+9R;^X[FOM!=3!F->R'^'HE$9YSUHW!.M)F'B>VHG0[,F-F7 MA44NBF:"":SW.=?O'Q+K4K_VO$I8)DC?GPMR, MFIJ8TAZ$R$OO1-\X9JP_!K)UO4+*M=CT]X9C53?58NIW[74CI@SZ;]P_G?#=. M'1Y'G:I2>>Q%*8.0IGOA3MY>"T+_Y\(=K-.OL=_ARW@Z"8]WXN&G?W0]TO[_F_7_;%J1-U288&>?C"Y#PQQ> MY4-)/7'0'3R.XGLI'#<9F^ERS/*O6>EGK"Q3_AE$[4;_.JW M80KT'?<]UYOH,-FH1!=#.]"C8N?(%9=5T'C?Z@[J=PU7&$%M<(TAQVRF`CFJ? MJJVE-5XH?YCE,HWCCDX=X>X.#&)JO0K>U"NSRW['$4?,(Y54+73E&T5I**JKF M]T5^A'[V.+%XXRLXDL25:TKK&_(XW1$4KU[B<>,RNXPN@A<7&3&*551VDQ;R3 M2?PUQ0LT'QDA<3LTN\ADEN[BGMW>$,3QR^-S*1_AT_R(#E4F/SPWQ_YIOY?8: M[P6.P=+512R/"=26!EUCH$5*>'336>PK!>8TMZ38<.*^59Q45# MZ(-*:TG=S,:8*^P"52$5=.<3B;-I+KMZ0J\F`@A?EUZH["SBM`\^/BC8@NNQ^ MU)J]5X?P+3]U!2/DI=ILD?FUYSI7`@'2V8`$YC"S4(4'G*M6*3X4]11X""`^,E.QS(=)UYOJIW4 MHZ+*PE@Z,&9I^+9@*F#CYLP\I^2WT7:SC,4I7E-[#?#&`3,V*-OT`2BF'^X9& M%4[#@+E$5]-CEF263<.<#GO$D\H;A.EY%IUDA18A'I\>*FYOX)=D55_%X0THV M-)U*#YIY(!A.I-D@DF,4WX<#&^PR8=89REP"JT`JAJ3!!35@716`V!$/@:EQ`.88[;^`W[3R2US MQ([F;HBW1MP6HQUGDS\,WL!1=3$WV$3S#BO`0]"`V*XAI,/@D'(^>2%J0\F:NP)-VWK M<,;$'!^/BY-0/)GIJF^_WK?0DQZK0Y(4 M8*55&*F$`$0!<,MDKR@C.&AUVT4#+?WFR=@RVI%M>G'>]QTV M+S#8Y+-1#?B(8!-_K;>7"7`*;2P3E]3%6&5,0LJ$=N!5*'='#"F6-0P([;K=Z M,206U."X%B2H12DE,[/28\IM(4`P"6;=&^3:6Z7D7:C6((Q8M79`HQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH$ M6[8@I:S/.<:[[-RR=*QNL7726W=S% M5\[:;5@V7;<;X]UR[-LVR%KNV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWD MC?BPWVW?3&NS>5DL'??VC>)Z8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\Q9 MUG#EOK6;EDSYTT7C5`VK+)<_/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?U M;L]TG[\<8^3+9?./F9EQ:Q=S*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]B M-LVTWZ&KT0`3T7J.FTO=]#J=(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CC MA7U0F#`E3J:!-W+S*]S>WRTVS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU] M2Q>O"]<<9]FHPA?$*W@S$-XOFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`.QTYE M-5TS9/>9QEZ2*_`%Q13[]HV?]L5Z4\MM.S8L7!##=Y:HS];WTB++^NI3J42GL M("/:*_'DU*Q.GT*=FB0\3IU$8?I.D7DEI%ISJVC>.^B31(M.'2HU*12QD32S! MZ>BYW62IJ4JM6J2*Q:=:0A@O+8YY"5\38C>WQ'KUI*&OW;?KE?/:-!F4Z= MY7[I;DGV)%]_VC4F9A_1ON30=6RG0?+P[?)#OW6)UL=T!-RIR2GJ9GW1BUZ)> MH8S6,9X3WS0,Z.-ZTP^RZ52B3Z:B!9PV=;L%0 M863]E>Y8.+[99G4V*U@56E4+:1NOX%2(-4@KRII9X;F[QA,F-<,8# M2OC<1SY]MPRC;PF+?C?FU=UNQKMPGV24SP\IIY0M/0[U`HRVGRS*1NCZC@!'1 M`X\CM#TQGL=RG'9^9Z^(3@G#'+GGB"$8I=G2D4JYCSEA2I?*;03;QN\1OVJ+Q MKL7"W>%<71ZI]XXRA?9Q5^4;9$\0K&?2E=CF./X^4RGCPCQ,^`-0R M2P,$"@````8`H[L5#PB:CMC4!```Z`D```D```!41T543E5-+D,-`@$2(Q05! M-C=HB9K;/`4&$A-$Q?:6]U^J5!$<+=A0(4B5"1,$%\WYT+=P\\I->Q8M79`HY MQZ8$&3,G3IDL01J56Y8,\4X[%\UY/$@0P3LH6[8@I:S/.<:[[-RR=*QNL7726W=S5\[:;5@V7;<;X]UR[-LVR%KN> MV#3/&V2=_PTB>K/-ZT(?9YJV;5HZTRXG;4WWC?BPWVW?3&NS>5DL'??VC>)ZW M8!\-LRXK-@\P>5;.^*9#M6`'-W;+A?NF6<\QUG#EOK6;EDSYTT7C5`VK+)<_[ M/@9*U/[JN\>6*2O;ADWSUO#Z6#K_S/U!CKG?;L]TG[\<8^3+9?./F9EQ:Q=S4 M*B15V#.[T2R]8KWF_:HUB"E-[,QS5YMQ-N.]-LVTWZ&KT0`3T7J.FTO=]#J=3 M(\;:)UM'GRR+%TZ9MK[:-8@A#U]EW6WG$+/CA7U0F#`E3J:!-W+S*]S>WRTVM MS?BZ%TRWF>/MAGO/(;/Y3SCPJZW7>=9R@@DU2Q>O"]<<9]FHPA?$*W@S$-XO- MFEN=FVE2H5*#2LU"V%W5Z5"J29\ZJ1Y`.QTYU=W5I6+L(;D`7T^,YNNJ\JZIP M&L[JJC57]])3RVT[-BQ<$$2\W#S[F?Q>6B1:7WTJE>@49P1ZA0>%QC9;U^V8# M8CEG/CDUJ].G4*PK[!406H5S7O'?))HT:E#I2:%@C<2;#8=; M*+7;.6[3=@:WZY;98OB;%3F/8NV3!1>S90PGM!GGMM_3U#[IJ'%>E^3&4=6\+ M[]#A8IX7]5K=IG/9JW8QH#G^?>?U!771M^=]AG96N0D2I@NCV9E\Q/6Z?=?9% M[0)7@UF#VV]=HO4Q'<'KPNRBKHJ>]$*ZFTXE^G2*\V"^[5TFL8:\\8)`/W4M! MQWJ8J31CV6***[K=@I"R_DIW+!S0:+,[6E]5*,.J*&)!6+_9,I/V-Y.YX[,Z] M^(!S4Q>M`J]!#GURI/(S+:0IVY.(;I"<2=UX59;^M'K++*-FR\L$'N&=='&?S MOE+F9C-^M1:&G&$::XG<9/:':D[6/X>U]13,J&!E:E4MI&V\BJQ*K<5:D7%E= M!>#L&D^8U$QK*.%S'_GTW3*M?K=THJ<;\^IN-R,>UP491O/4>J+V0E^5>G&Q7 MUA[MW<4QLB@;IRN]4#).8PVR70QHF#.$L#C<6W("-5\SO,] MHLT(98;&#[<90ONXJ_(-LB>(QF32U=P6,QJ%=GNOE#?+DSI/IACH'2)Z.ZW*+ ME`GR`GJ%UG!7KIC_!(YZ%.[&O-X7_)/="K,K2),F@`[WS+D`3\?L`DP)9?R5E M>BC0?W+D"?2JYB[/B6)7*N^X[WVNJM2ONZ(<];YA<`^GV;H\"0,86\MT']0;Y M1WG[C^&.CS%,]R$>2!:&6X%2E=UTIF6*9CAZ6F6//+'JV)4]HLQ;#&W3"*2$T M>5N*./X^?%+&Q5M(3!]02P,$"@`&``8`KKL5#[V/"47Y"0``PQD```D```!43 M1T544U12+D-A"GL'!AL&NPQ+`PD'"PD+"0<6!P@&!08'!@4V!Q87"PH&"`H+< M!085!`87!0H(!085!@HE!@@'&`H'"@@+!PL$)00E!`H&!`44!0DT!P87"1HK1 M_/S\^_O[#`LL"RP+/`LL*ZP,`2(C%!4V-VB)FML\!082(Q3E]I;W,6/%$CA*G M4%3\8\6-*W#5N(SV4KCMJE:67]@H^)/HZ3GY/V6[ZS_E6BM.)___/S[/W[%ZU MU]^YUWN+<-;U6N]:][;8E_MOL_1SWFOOWZWIC+][$\R[4?'^AO]WD_J M*_:OZ?S2W#ROAM^U?JW+=C5GJ4?GN;=U/YXS_Q_[,6WLY?*]-:[G_/-Z__TX: MP^717_I7^5I,_R8U+SO1F__+>_VJAMY_[*A:[_"1X_6/_ICW1&N[O-2S?UI]^+0]5JUV?ZZQV^I-Q?RQGN&_2-\[G**^)SE6$^:$UXU M$U\O\(_\^5>NO3S-Z[S6GDU[S^>S"5ZI6O.\$Z%QPAK1P MA)A%Q47%P:VH.*;&\W]_D-H9=T+[*8F]46O0[:F\`,M2O1?Y&C-^AU\VCZI#L M]JC^QE/2G=2VO?R7>RN;_.]0;^'X+O^'^8;V(W<[P[;H*=1-=-H.K==-:@^$5 M3NGZ[<>2OQ9>]7SR^BF@.;GJP4CC)!;/&XP\3X=O>]09)#$.BVKY;>M;;Y`@4 M=4A<];"(XN?3P'FOQ3ZWFL5^WGND;#2G MZ]Q2N\X[FN,Y??VY59P?3^-"O2MDJ;W/V:[;]R]C@?46Z(7]^RVCO125\>BO M(X$X2MC:&6T*C+_$[\MZLE^E8= M8^?F3@I\C\`JOE?B_)8]N?2"CWTK/Q#=YM-(6,]GK?!WJ0+SG/VN'A/"MD^_4 M5X\KI*J=:VZIZR'^D3J M20B_C.YI8?T?&^Z-_7\A[L$CE>.&<)/K=)++=6J_E)Z&V*%J8B=98J>6N_QK. M-\T6.^P0.\D1.SWN^/,Z[I@(+]S9[+*9G62:G8+GVZ7L31^%[/A"=C(A.P4RY M)QETO5ZWNDI\J_?9FI>]_18.H[1^5:]%ZQ)>]A*>Z@O\PGT3C&.=\AYI;W$P' MN8[&.=?O'Q+K4K_VO$I8)D'QA&4%,4A2^TT<=O^H' M.WP!DU/O*H)=%],B#_@Z.)SLGU,^I_9P*AOW/I[G=HY<$;1W>FG"O.%'R/DV[ M=KKS:[6Q"]QN)UREOT>X-8*-[O76TWY,K7T\>-Q!35"UEZ_R=_PMH'PL(B^KR M:;>Y1G0B[U;+_?$QA.HT;D.U.*&YQ(MT1<[N)R:/T&O?1#)92P-+I1$G#1F"=-_WH]S-4C#BN-D2X MP\T4%@0CJ>-U8._ZC?*PW,W23_O`*22WX/(+"VD>Q+M9RH\=+79!P0]EFN52* M\/U_W&8I[+#-?EQZ_4*#'7;8/PWLUR/EAOI#'G*5E>O"<04Z3T(%O+5?O"O54 MH4%^[+384'=<#<^%]D\PDKL&O7_[U3['>*=KP@Y[NS'`%/2+HN05L- MT&N]G=ZX+RE!`]]^?_%*A(5,\S_2@_*:V%Z5)%`K"[<-G$+J370D`ERVD@#M_ M&05,`I?_YY*P+\QR>&OALX6??&]!(;7F.UVL/P9X(SSG?Q/RZ2[8.E;@%_>=2_>&]8HB8U!A$I.?>0&7[J2VTGH*M0`+6B M5^O@J5>QK%$7VWY-4Q.CBA1M6;I"SEW,;0U*VJ>^&PF4;WT_X-DE?>KWNA`_8 M^\$KJ4\W'X`YOK#->T%9FTS[V:I$;O>Y6F%=*_NIK9E#K@QG-,XJ8Q692MJ`W M1TM#VI#LPQU=I)P-2<5J:;:6\?.N+9(V-+5ZHT+0Y3J"YQ[!,OX<\7'2&XW,< MH4.U8.=J^)I4J4VPLTJ%'9)*D2=XGHRZO5:GVQ^DA&9Z,E*0K,O8]4BCC*@%= M=Z1%FY>;,D(C':<_&=ZU9SX7\I/0";D!DL3X<%J[JT['PP+5DQ%@%LL^+Y!=S ME4CD+"W?Y2;XCR>J2!W&\/&9KV"GB7`A4,>5!XEB$F@=X3`HO]4W*9;):"X(P M8BXA,T$U2OE(OWKHF,@](DNN8Y(&@5ENEVU,"F9!L3IC,=R36(7Q,I-6%>+6?:O4:C4!SG,;4!R-5$Y/ZJ":@(#I^+[6OX M&EY]?#@U#5C.5L8\_^)_9,XDG^/X==B9P">]NY7$+)+*3N;+M[M3DU=]-`Q<]#V,73=2Y#B@A4SB"G6 M!D*V.F9YP1)62Z[F,/D-C6OIG[38X8;@/*;TE/#8.(T-CM4R1LDN8S'#<)PF' M@+B&8S8I`BW"1\*=K030'".,-T4G[V*[&>948;89PM MLQ;"M2.$CRV$MR6$ES@T_L%(74#A`E+E@A8L%HCH560+4)^/1<[!&Q5'!_/P) MV(,/BN;*^5ZK7<;=(2B"V-;<`@SEI;K@_`)#`0713ONYHJZ@TUI(M*@\6O,/@ M":(XE3W@\6"D_\,.6UB@B&](A$3:SPY&&I<02$.8IS]V;FQ*`6;O!J@7/;6`^P3H2Z$S*A[SL'0E02P,$8 M"@`&``8`H#2C$.?S,OL/"0``$!@```<```!41T]43RY#80I[!P8;!KL,2P,); M!PL)"PD'%@<(!@4&!P8%-@<6%PL*!@@*"P4&%00&%P4*"`4&%08*)08(!Q@*$ M!PH("P<+!"4$)00*!@0%%`4)-`<&%PD:*_S\_/O[^PP++`LL"SP++"NL#`$B0 M(Q05-C=HB9K;/`4&$B,4Y?:6]S%CQ1(X2E!4_&/%C2MPU;B,]E*X[:I6EE_8' M*/B3Z.DY^3]EN^L_Y5HK3B?__S\^S]^Q>M??N==[BW#7*8_#'F]5KO6O>VV)E M?[;[/T<]YK[]^MZ8R_>Q/,NU'Q_H;_=Y/ROVK^G\TMP\KX;?M7ZMRW8U9ZE'7 MY[FW=3^>,_\?^S%M[.7RO36NY_SS>O_].,/ET5_Z5_E:3/\F-2\[T9O_RWO]T MJH7+MUC=O^\99P/MRKW=S7"`U^KV'`O*%/N(TKR5]O5>\W]IVR-<=:6_5)[EU M/^?)?VF`-A_[?^WZ M*D)[7BH6N_PD>/UC_Z8]T1KN[S7.'^XG7*8__EHJ@-?M7DLW]:??BT/5:M=G& M^NL=OJ3<7\L9[AOTC?.YRBOB!-?+_"/_/E7KKT\S>N\W-_MUZ[E] MN-<5J\_GLPE>J5KSO!.A<<(:T8281<5%Q<&MJ#BFQO-_?Y#:&7="N M^RF)O5%KT.VIO`#+4MU5^L_0U>@V9M4<<-?K9OUZ'=7/DF7XM6TO_P;!?TKH! M4\++_V&^H?W(W,[KN`N03AKE8*3Q>.7?Z0IR)-@;C*Q/AV][U!DD,0_KW,N\':OOP.1#_L;.% M%PN]+,AYHVPP@X^ISF!]>8]P8UXX/LF>RX?.A#],][BL0.,\B[%@;&T_SSW>. M_[E#-M\'2ZB*/VY.]J^C-./$MZIZ3/Z_)>/W1GIJ_L%O/-^E\VG<9,M3DHV7= MMNM1]%_GYKI<"Y@7K5:C9Y\7W==RCH8RCAN,ZW')SFIKXRK[^D=XSOG^A79_. MW!X-!BSEN,$X!V(GW#\8U[^8-WFLWUJ[[I,]M+Y43+HY5M=LJP.=;77-L[HV) M/*YAAP>YX#UL]0HQPTPI_,.[-K"-A\2I3-\@+Y5W[7.G>XPZ_4#[++GVSY?L1R MX=XTW>HW"2M\N+A7C>NVG5EZK.,\UF*>5K<;N-Z@G1X.35G:8B'AH:[^7V;7; MZTB'")4*C/L!KUA!\*?7T;"REK0W&<:M7!+L/63UA*XT:[-_Z8.QBG\P3LW_(?_!>.@_)[ MJDG!>Y6W#J?YQ[,9.U29?JET'ROB.*:B3=/3OB;,[2*;;BQSYAA* MYN@0FH\$DZ8K0Y2;N%5-+?=T(W'B^(5M]3**\DNXV3J1YCI#-%F/=\99ZE[O) M0]"R:+S'?)XZNL92J'_:SPU&@!G'6L3?[URCVZN"GKP_S(X[_)X]#'G:AML M#+=%Q2NTT@9_=*SK"$9QX\:,]0>Z^>98?R>U-EVB:)36TG[YO``+WS'C[7EI'I;2&$SON9!;(>XVD,0TU&,&]R4_XJSR7Y?IRT^_3J37ZFI;-_1`>D M7G*N#_7KB.(U.]NZRE8[#4XR1XJ1%:K;A=,3X*F4!DMJOXG#[A]UAR]:7@;&7";R,5)<1(6CZQ;^=,>3_:6F_E]CO%WR6'U?8=6&<+KUTG()@= M!'4'O7_+]#Z/:3SM"S]QR5QKSAXOEY_<4$T^]8G*/5&Y<,QQ67R#N]'X:)U?I MR.O]0VDQW&@"%Q4'/5P?&_1:;ZN5#_L>NQHXFX-G6%E?\2& MKB05\5\8X2'@WF3P]^4'093.?:E9%+(5O%7HF@HK/"$8B1^1(WZ@('G.H3X`` MRJ8^8+.I#X#R8DL?T9`^7.\@PX8:C.\P-=][K;:J&$QYB+`H#Y?DLA('%SS(8 M3?!@7'E^3KV#O/0N`_')#152'$RV#'` M0#`IN*L#C6\*/+MWN83Z02Z45BA>VKM0UPJY%92W@1EHW!6,_K'4Z*SFQPG&Z M]3CYRF90/(<==J@%/`8-N::D6N[G;6VQK+30;Z).=,\YNH?*S?$]0/,>(IOW+ MD-F\1P_R>!\-AF` M&O'2B'\1)2W:AQ8+B0N691HR5&.5B2^*0TZ`#@_;0HE\*O2A<$-$C[',A$>BQ M--A@[-E(C^]TN*_J4$L#!`H````&`$A.#`U_;Z9W]V98-.X?=S70_W+IBV:8=\U^2Z=YTK&ZQ==);=W-7SMIM6#9=. MMQOCW7+LVS;(6N[8-,\;9)W_#2)ZL\WK0A]GFK9M6CK3+B=M3?>-^+#?;=],Y M:[-Y62P=]_:-XGI@'PVS+BLV#S!Y5L[XID.U8`-4#:LLES\^!DK4_NJ[QY8I*]N&3?/6\/I8.O_,_4&.N=]NSW2?OQQCT MY,ME\X^9F7%K%W,J)%78,[O1++UBO>;]JC6(*4WLS'-7FW$VX[TVS;3?H:O1' M`!/1>HZ;2]WT.ITCQMHG6T>?+(L73IFVOMHUB"$/7V7=;><0L^.%?5"8,"5.] MIH$W9X^V&>\\AL_E/./"KK==YUG*""35+%Z\+UQQGF MV:C"%\0K>#,0WB^:6YV;:5*A4H-*S4+87=7I4*I)GSJI'D`[':MK\F/L?%MG+ M>8(P?!RQ^FQ'-9PT3WBAH2J_IYHL&>S#S][WTB+.^NI3J42G+".JW&W'S"_QS MY-2L3I]"G9HD/*Y=7&;#91G6K-DQ?FX6\T::57KEI+ISJ\C>.YJ;Y@]"O'I.: MHE31WE&FW`&.)%ITZE"I2:%$A?RTSE0**3&G3L,[MH=!=H/0M][>]31;U^T82 MQK1J45C6W_Q8BM-O[X`/(!>1-1W8#23CW2Q.BT&K"A]2%KF3C\K8T#J,]XENZ;Z\KL!)D M.9)KPX*P0S9JP3^1Q95?>-TP/(0KT@BGJRI9&A#S/U'$L=4`9JVY6Q"[!"$ MTBK\-''ZW6X8.VS.!RD2ZE"1+F9!V&*S,(\,0CSY9NI%:Q'X;4NB\"*^B28C% M'TUBM)5IBF48KM27*WX98LC_B\BWW!?':U*Z#O1^.?<.7,&?!#>K`$?,2?,'.]!&#-&./B;-,`!+^BF`1_1! MIDT;\($W%&R-N8!#Y<%'F`O8,^##QI`:N#;@P^*<84?@QY@:>LT:\8&+(SXLH MS1CQ@2^31GQ8&8P+7!KCH#&AX(,P!U[(?7?\5K32TYI9&'`1JXM6< MSRE9IX66/3.J><84])OGYBX@?JE"!%HVY-4JU4E5$D-;A9+*L97H99I;.=&8X MF["+'P%E*7G(VT4SNL@MER1*(PYW'K%F[B(QR:RJHTR#DTQA*/=.!!"$)^PV) MF#Q,:C,I+\0W71??R:!C)L(Z\B#6"BEFUKX>,R,OB[J!<<9'GN027<["-X/59BXUTZ#H"(GKE283-#FEQ#>!3Z%M($\D!1=>&<,AE6G-9!EGB&M#DRG0@DW1S.0S]YB@YS`H'SY^!M5'. M8DG694T7S4/'O8/BW9IQ,V_7357U(%]18[,MHY=@874>D8)S@A4)%SI;GVT4. M89"Y#G9)0O:1&#C\'6SA7%-A4)]CP4Y%BX.DUG77PV=?,H( M"`=6@\,I.*0#!V/QA?6$8^>0N#B'IMVH+EB33I%W=W"C@.U;% MM:2O7/%?V0_S6F4/4/T.Z<@K>X*`GR!;@CP)\X35F;#/\+F'(SNLEB==GJA&V MC`MG;'P$C2FO$Y1#:E_G<$W9<6$'^P_-F_>16@R-53$T3FTJ")362/JCF^B?= M(;"$.1]J8%W;7XRBPGA@_Q(X`DZ*<)4O8IJ2?0RA_8>QA$R#@G:-^)]T8AM.( M,C&XS7)HD"J*6!N<$9HB;"5#`RQ6V&7G)`9X%':UBC,1@Z)&<5F4?]LL^)0L5 M6`S4,S/N;CX4\$2"2B!-D:D+3P##G&C5HZ!%N+JQX,%L$#F)J-F86H"[H=MM* MBPB@YY( M,O:(^_/3SC<;E+7WX`]]V\9-0\$PH(O#H81[',%`\E%(Z$/CB%)(/1':QX%#X MF10LQ/U"2&Y"(`349@,'LS&``&PY3?B`0``"P```$U!2T5'0T,N1 M3$E"#0(!$B,4%38W:(F:VSP%!A(31,7VEO='@IPZ=.A4D$G)Z@0)%.7(E$W#= MKBU[!'J[9)M6+,B9+F."S"GSI0SA#3-G0P7HVVE9NFC#CET+LLWXFTW+MBQ(A MLV_E@C0JMRP9Y)UV+EJ0=,O*;6,_P[J!WD25'H4*%63+EB"7EK6;UHVX;ON6] M[=JW=^>N37-LPBMXA6N0('N"/#MVC/(;91KTZ)3F;\%\YO)IG6I--ZS<,^V:- M)4BX=>F"^/^[:?(UR+QOL`_8:%"U)._*;3O]:W"_9G^I7I4Z%*BPZEHNX)Z7![6;=T7;Y)[F;9ACVCO$$L= M=[=UVU0_%_B=P+G/I2N'O+^E^^;XD-?3GX,\P!M=33;MV33%THSZLTF_KMSEI MU*I&C2;%6G1*E-IE63QE+FUW.:;XQ:HAWF'GMAFOUNZW.H:=)(HD=TH0Q4=DI M2]XMWY)4\7[$/^:\9:^R9$H=ZT<4/L7V"E(AN4'&!2&>!!$>AHX-4$L#!`H`` M```&`%B<51F&!`EO>@$``+\!```+````34%+14U30RY,24(-`@$2(Q05-C=HY MB9K;/`4&$A-$Q?:6]TOR37(WRS;L&>4-8KF[K=NF^KDJ3-#@SR^* M!U=--NW9-,/23/JS03]S=SFUJE&C2;$6G7+G=ED6SY++VEV.*7ZQ:HAWV+EMZ MPN>8YJW#?VU5?15657QNF5@W^I:DBO8C_C'EA[V0DBEUJ!_?^!3ZJTGQG(B"P``01H```L```!415)-0T%0O M+DQ)0@\`$@,D%38G.#EJ>TR=;A\)!@$3-.7VEO?A-QC>@O`"GG'`"P$FI'NVB M+-VR;NFZ'`L>4?,`1Q]X)I$C/@#N3:>"'.H6<0+D/S-EFE3HT*(E$3]8]J=,W MB3H-VK3H5!?3+A>Q@>@[PV3[5!VRA@XXU.I-RS60-TCTJ-2G5:$RI'JT*-6BY M3JE^(1XK58)#GQ(M6O`KT:!4@Q(@U@+/.YU2_5>A4Z<.&':+F.(>*4R!`PD&- M_):L,@$6-!AP6[*X]<&#`1$DR]4C3!CPH&8$0?[_P/\$_PNTR@G*/C"@0($!$ MZ@<:L&A`X(P5K/]U+EVY;((\0+:T&71YLVG=DOU"W/,`+S/^L>UFNNQLY2#[Q MV;=TQZ(-@RQN5CO:.I;MV[EE_NFQ;>$(N>C?PCG:#QQ3T-.$[>#OOWZY'Z[8W MNF8!ACEK26YCT><%^!62ELRLO_R)X)/[MPTAVH1"PFH>/"2ADZYO7')`@/(12 M$X!>=,#HH/CT@"CH5S'\R>H%7B7@V:-/;G'871I M%P]?;!6AR5'(FTQL`4M+A:JI7@<3)YC8*/_$5OTOA%YW"[LJ/H@YT_)T"^(:/ M^O5F7_"\RL:^X8FN!C>T@H8[W^%, M=&WC8OOU'-AIW``)0D&'5H#T=3][75R^Z[*W.`/P`7K`"AX?5NMCRATP/3ZLU M?#$RK;2NP/5P`>=_29?GC!`H MW`JFAK5J+]M?!+4]I%R?\/BBC*R;(9I*,^1,X)G7!\7]0&C''>%H1-AT7<^X6 M,V#K!FS0A7&CP%85V%B8T02NQ'^.K%L`Z],;NMZH`K)F$`1Z_0,^XA3_02>\_ M`2=0Q?,WB6,S'\=-UNU@33&)IJN@2/-A0\0-J3CP&MS0#ZXMG'#:UPD=WO.MF M>^CQ">@-F!GK2G5R_@K0.4JK!)LKMIJP>.'.Q0%W;A[']2[.)ODSR6-)]BG)& M.TD^J-6%S5-:/=@^+OC.?5//%;QH.V.I#Y7:L!F:>U:I#YL M%:5G/M*J0.(>(F?B&88=(F?3H&W\FCSZ4IL.#0H5H)QD9FRSO=RV8\/"2?870 MO_W8%\Z(9-RW(GNG\RB0@$)C!:^E9MF&/0,H+T;D'*",`!J?$R@`D#8"!=T@Q M4-0HTZ!'!`6@AB-5=0Q`4'R0JU*"X@T$!8!.8=)(M'):#5XCI$7C7[B,9=E38 MZ3K0!?X$+1F`KF-@:-;59*AA7^3J)KHT;IT`H=@&M`%>Q^E&82T'$IN4L?.+* M3:IQ97>OBYP8?,T3F%S.:W-\L;=M_&C`NJM`1W"'/,#M/!2'%`#:83JOR.FO> MF9>HO(E+:#QO,.P).3.!?)`>'NZV;AO'_]K#0SS[KX<'>$*G59LP/D#!`Y?&\ M^/J#\0&@/0R^IYU+-NW9M'0L'WA>M`".S!9FKU?Y0!_H$[2URD=3J'PP;Y#*O MIQ@9WD`NH9DN%[T>-&S M_<&:<=NB#K/N@>;Y">GU&8R-%%\OH9'G?]^MO[/WWY@H]`#%V5O1))2'GU9\J M2RFZMO+]81Z'#)<3;,\8/"6\GD`E4#@J8*7I@62-<+G*;_/`V#24FN#9,N.?3,\P.R,3X2>DWW[R MM>S<,;0'R.!M%>T![DE/RM.$K(&BLWU::T``CTO=6Y1\UN,"O2!/T`Y`.JK4+ M`.A,2@WP@0Q*37O2+:"Q5$+#I0VPC43@T.%\JBO`*I+QXJL"A*(\#GHQ],78` MEM8P(D>YMN0">V-$BI0N#6?DS!<7V7,7%)G<`*=X04ZPX;KC)>#G MKE`P1',=8-&-8A&:9>A6H=R&=!C[RIRD9^:9W^,-$E!TGV$K]C>ML:S*T-$%A MFKFFU0"`G+$::`6K\5.J3U(#H*):#/4VFQY01K)*2`W=]QE4:KB"9'62&IHK! M@P?0F!VNW+=C7/.Y`'DR7@";/LLH' MO:ONI!CM[<$UC"2@.P36)>E&F.X]RO_AOS;9<,JOWW9Y?#VU:[8[CHOIUVOB] M'+1!*^A2ZT;KM+[L1XR2O\5-7G)]SAX_SG_?E`W?.U_E@.,1 M'8GQ!(Q]XW__R(S]1/,+C-V,\2:,/;E_%J5]*D'CUCDW!U@<\^?BE(1W)+PBY MX0D)[T?X.\+/$9Z-\&:$!R.\%N&E".]$>"3""Q%>A_`VA&\A?`KA2PC_07@,7 MPE,0OH'P"80?^)EX_\[$]15/3WAXPJM;_ESQX83O)KPUX:4)__PS\V,FR8490 MK^M@^2WH9PG?JGQ5Q9,2'I3PDH1')!Q2$P\D/!SATYP?YF8YE^2Q"!]%^!["/ MWQ!^AG!`3?R$\".$#R%\!^$S",^P\T;0%FI=GSZ%.A5@23+"PY1!K#.(/_7JF ML'#KZ+Q>_4^O3C3KH5<'W"#4*ANS5P>HE2)=G>5$'9(3(5X=D1,!Y@*""5^A2 MTK$F*P!"AYG%3A6N=.H_F M:%0#I$T!%H4[O-SMZ)S9\18QU2WL\C4`.!#C]PP0P8$+!MP]3!7%NA/@!VK8\ MDA,!9@1HPQD-%$$/)[HWW1!L-!>2FV4;]FS(I``15+!D2,0`4A@T(A:6<+=V* MPV%1X3:0R&')[!95P!X`]Q<,^`!7S"4,<";)"=.P.(DNLWJ'P!``!W`@``V M!0```$9)3$53#0(!$B,4%38W:(F:VSP%!A(31,7VEO<;*C2:EFW9N2#3N@5)4 MMZSL=EBU(HW++DB'>:>>B&<]!SGU;5^[88 M,OQ_M"A5IE)!@@0Y9/B"N\R;-V6"A(FS94R9+7':`-])IQ)->C0I%?#XF#-KN MV@"/IQ+L19V`Q^((WS#`5_>&&;-ESAG@M5&F08^(P\.D>2-8R@#?.&^`UTZK^ M-AD:6W.F#?#P4ZE*`8^W63-G#?#(3ZD^!5$4UF9,&T._QM`]`WSC`'^H58(5< M>.2:-&?B*`KGY@Q*EFQ:NFG?P#F;AEU;ULR5/*R;/#<YWO]Q/SBVU"?X.\A3Q=(-8>W*V^Z;>\@4^^#SV=-,I]A"@])@PG!SV(#9-C M.U;NFSBT6;H@^"V?!X72'V\##AV#'P)\'%\0ACY02P$""P`*````!@":`0P-S MJ*QZ1FH%``#4"@``"``````````!`"``````````1D=%5$Q2+D-02P$""P`*R M````!@"F`0P-M*4E!OP"``!,!0``"0`````````!`"````"0!0``25-$24=)1 M5"Y#4$L!`@L`"@````8`(!AA&G"LJ0#N"@``FAD```H````````````@````+ MLP@``$Q)0E1%4DU#+D%02P$""P`*``8`!@`%&$$:MIR.V)<+``#"'P``"0``W M```````!`"````#)$P``5$=%5$5.5"Y#4$L!`@L`"@````8`DKL5#Z_;B%XL/ M!```_P<```H``````````0`@````AQ\``%1'151&3$%'+D-02P$""P`*````- M!@"CNQ4/")J.V-0$``#H"0``"0`````````!`"````#;(P``5$=%5$Y532Y#6 M4$L!`@L`"@`&``8`KKL5#[V/"47Y"0``PQD```D``````````0`@````UB@`L M`%1'15135%(N0U!+`0(+``H`!@`&`*`THQ#G\S+[#PD``!`8```'````````R M``$`(````/8R``!41T]43RY#4$L!`@L`"@````8`2$X,#7]OIG=S"```/A4`( M``<``````````0`@````*CP``%105513+D-02P$""P`*````!@#O67X9CF*M4 MBXP!``#>`0``"P`````````!`"````#"1```34%+14=#0RY,24)02P$""P`*, M````!@!8G%49A@0);WH!``"_`0``"P`````````!`"````!W1@``34%+14U3, M0RY,24)02P$""P`*````!@`@&&$:;XR-XB(+``!!&@``"P```````````"``1 M```:2```5$5234-!4"Y,24)02P$""P`*````!@`@&&$:>NLWJ'P!``!W`@``9 M!0`````````!`"````!E4P``1DE,15-02P4&``````T`#0#*`@``!%4`````V `` end size 22500 nethack-3.4.3/sys/share/unixtty.c0100644000000000000000000002360007764735041015463 0ustar rootroot/* SCCS Id: @(#)unixtty.c 3.4 1990/22/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* tty.c - (Unix) version */ /* With thanks to the people who sent code for SYSV - hpscdi!jon, * arnold@ucsf-cgl, wcs@bo95b, cbcephus!pds and others. */ #define NEED_VARARGS #include "hack.h" /* * The distinctions here are not BSD - rest but rather USG - rest, as * BSD still has the old sgttyb structure, but SYSV has termio. Thus: */ #if (defined(BSD) || defined(ULTRIX)) && !defined(POSIX_TYPES) # define V7 #else # define USG #endif #ifdef USG # ifdef POSIX_TYPES # include # include # define termstruct termios # else # include # if defined(TCSETS) && !defined(AIX_31) # define termstruct termios # else # define termstruct termio # endif # endif /* POSIX_TYPES */ # ifdef LINUX # include # undef delay_output /* curses redefines this */ # include # endif # define kill_sym c_cc[VKILL] # define erase_sym c_cc[VERASE] # define intr_sym c_cc[VINTR] # ifdef TAB3 /* not a POSIX flag, but some have it anyway */ # define EXTABS TAB3 # else # define EXTABS 0 # endif # define tabflgs c_oflag # define echoflgs c_lflag # define cbrkflgs c_lflag # define CBRKMASK ICANON # define CBRKON ! /* reverse condition */ # ifdef POSIX_TYPES # define OSPEED(x) (speednum(cfgetospeed(&x))) # else # ifndef CBAUD # define CBAUD _CBAUD /* for POSIX nitpickers (like RS/6000 cc) */ # endif # define OSPEED(x) ((x).c_cflag & CBAUD) # endif # define IS_7BIT(x) ((x).c_cflag & CS7) # define inputflags c_iflag # define STRIPHI ISTRIP # ifdef POSIX_TYPES # define GTTY(x) (tcgetattr(0, x)) # define STTY(x) (tcsetattr(0, TCSADRAIN, x)) # else # if defined(TCSETS) && !defined(AIX_31) # define GTTY(x) (ioctl(0, TCGETS, x)) # define STTY(x) (ioctl(0, TCSETSW, x)) # else # define GTTY(x) (ioctl(0, TCGETA, x)) # define STTY(x) (ioctl(0, TCSETAW, x)) # endif # endif /* POSIX_TYPES */ # define GTTY2(x) 1 # define STTY2(x) 1 # ifdef POSIX_TYPES # if defined(BSD) && !defined(__DGUX__) # define nonesuch _POSIX_VDISABLE # else # define nonesuch (fpathconf(0, _PC_VDISABLE)) # endif # else # define nonesuch 0 # endif # define inittyb2 inittyb # define curttyb2 curttyb #else /* V7 */ # include # define termstruct sgttyb # define kill_sym sg_kill # define erase_sym sg_erase # define intr_sym t_intrc # define EXTABS XTABS # define tabflgs sg_flags # define echoflgs sg_flags # define cbrkflgs sg_flags # define CBRKMASK CBREAK # define CBRKON /* empty */ # define inputflags sg_flags /* don't know how enabling meta bits */ # define IS_7BIT(x) (FALSE) # define STRIPHI 0 /* should actually be done on BSD */ # define OSPEED(x) (x).sg_ospeed # if defined(bsdi) || defined(__386BSD) || defined(SUNOS4) # define GTTY(x) (ioctl(0, TIOCGETP, (char *)x)) # define STTY(x) (ioctl(0, TIOCSETP, (char *)x)) # else # define GTTY(x) (gtty(0, x)) # define STTY(x) (stty(0, x)) # endif # define GTTY2(x) (ioctl(0, TIOCGETC, (char *)x)) # define STTY2(x) (ioctl(0, TIOCSETC, (char *)x)) # define nonesuch -1 struct tchars inittyb2, curttyb2; #endif /* V7 */ #if defined(TTY_GRAPHICS) && ((!defined(SYSV) && !defined(HPUX)) || defined(UNIXPC) || defined(SVR4)) # ifndef LINT extern /* it is defined in libtermlib (libtermcap) */ # endif short ospeed; /* terminal baudrate; set by gettty */ #else short ospeed = 0; /* gets around "not defined" error message */ #endif #if defined(POSIX_TYPES) && defined(BSD) unsigned #endif char erase_char, intr_char, kill_char; static boolean settty_needed = FALSE; struct termstruct inittyb, curttyb; #ifdef POSIX_TYPES static int speednum(speed) speed_t speed; { switch (speed) { case B0: return 0; case B50: return 1; case B75: return 2; case B110: return 3; case B134: return 4; case B150: return 5; case B200: return 6; case B300: return 7; case B600: return 8; case B1200: return 9; case B1800: return 10; case B2400: return 11; case B4800: return 12; case B9600: return 13; case B19200: return 14; case B38400: return 15; } return 0; } #endif static void setctty() { if(STTY(&curttyb) < 0 || STTY2(&curttyb2) < 0) perror("NetHack (setctty)"); } /* * Get initial state of terminal, set ospeed (for termcap routines) * and switch off tab expansion if necessary. * Called by startup() in termcap.c and after returning from ! or ^Z */ void gettty() { if(GTTY(&inittyb) < 0 || GTTY2(&inittyb2) < 0) perror("NetHack (gettty)"); curttyb = inittyb; curttyb2 = inittyb2; ospeed = OSPEED(inittyb); erase_char = inittyb.erase_sym; kill_char = inittyb.kill_sym; intr_char = inittyb2.intr_sym; getioctls(); /* do not expand tabs - they might be needed inside a cm sequence */ if(curttyb.tabflgs & EXTABS) { curttyb.tabflgs &= ~EXTABS; setctty(); } settty_needed = TRUE; } /* reset terminal to original state */ void settty(s) const char *s; { end_screen(); if(s) raw_print(s); if(STTY(&inittyb) < 0 || STTY2(&inittyb2) < 0) perror("NetHack (settty)"); iflags.echo = (inittyb.echoflgs & ECHO) ? ON : OFF; iflags.cbreak = (CBRKON(inittyb.cbrkflgs & CBRKMASK)) ? ON : OFF; curttyb.inputflags |= STRIPHI; setioctls(); } void setftty() { register int ef = 0; /* desired value of flags & ECHO */ #ifdef LINT /* cf = CBRKON(CBRKMASK); const expr to initialize is ok */ register int cf = 0; #else register int cf = CBRKON(CBRKMASK); /* desired value of flags & CBREAK */ #endif register int change = 0; iflags.cbreak = ON; iflags.echo = OFF; /* Should use (ECHO|CRMOD) here instead of ECHO */ if((curttyb.echoflgs & ECHO) != ef){ curttyb.echoflgs &= ~ECHO; /* curttyb.echoflgs |= ef; */ change++; } if((curttyb.cbrkflgs & CBRKMASK) != cf){ curttyb.cbrkflgs &= ~CBRKMASK; curttyb.cbrkflgs |= cf; #ifdef USG /* be satisfied with one character; no timeout */ curttyb.c_cc[VMIN] = 1; /* was VEOF */ curttyb.c_cc[VTIME] = 0; /* was VEOL */ # ifdef POSIX_JOB_CONTROL /* turn off system suspend character * due to differences in structure layout, this has to be * here instead of in ioctl.c:getioctls() with the BSD * equivalent */ # ifdef VSUSP /* real POSIX */ curttyb.c_cc[VSUSP] = nonesuch; # else /* other later SYSV */ curttyb.c_cc[VSWTCH] = nonesuch; # endif # endif # ifdef VDSUSP /* SunOS Posix extensions */ curttyb.c_cc[VDSUSP] = nonesuch; # endif # ifdef VREPRINT curttyb.c_cc[VREPRINT] = nonesuch; # endif # ifdef VDISCARD curttyb.c_cc[VDISCARD] = nonesuch; # endif # ifdef VWERASE curttyb.c_cc[VWERASE] = nonesuch; # endif # ifdef VLNEXT curttyb.c_cc[VLNEXT] = nonesuch; # endif #endif change++; } if(!IS_7BIT(inittyb)) curttyb.inputflags &=~ STRIPHI; /* If an interrupt character is used, it will be overriden and * set to ^C. */ if(intr_char != nonesuch && curttyb2.intr_sym != '\003') { curttyb2.intr_sym = '\003'; change++; } if(change) setctty(); start_screen(); } void intron() /* enable kbd interupts if enabled when game started */ { #ifdef TTY_GRAPHICS /* Ugly hack to keep from changing tty modes for non-tty games -dlc */ if (!strcmp(windowprocs.name, "tty") && intr_char != nonesuch && curttyb2.intr_sym != '\003') { curttyb2.intr_sym = '\003'; setctty(); } #endif } void introff() /* disable kbd interrupts if required*/ { #ifdef TTY_GRAPHICS /* Ugly hack to keep from changing tty modes for non-tty games -dlc */ if (!strcmp(windowprocs.name, "tty") && curttyb2.intr_sym != nonesuch) { curttyb2.intr_sym = nonesuch; setctty(); } #endif } #ifdef _M_UNIX /* SCO UNIX (3.2.4), from Andreas Arens */ # include # define BSIZE (E_TABSZ*2) # define LDIOC ('D'<<8) /* POSIX prevents definition */ # include int sco_flag_console = 0; int sco_map_valid = -1; unsigned char sco_chanmap_buf[BSIZE]; void NDECL(sco_mapon); void NDECL(sco_mapoff); void NDECL(check_sco_console); void NDECL(init_sco_cons); void sco_mapon() { # ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && sco_flag_console) { if (sco_map_valid != -1) { ioctl(0,LDSMAP,sco_chanmap_buf); } sco_map_valid = -1; } # endif } void sco_mapoff() { # ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && sco_flag_console) { sco_map_valid = ioctl(0,LDGMAP,sco_chanmap_buf); if (sco_map_valid != -1) { ioctl(0,LDNMAP,(char *)0); } } # endif } void check_sco_console() { if (isatty(0) && ioctl(0,CONS_GET,0) != -1) { sco_flag_console = 1; } } void init_sco_cons() { # ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && sco_flag_console) { atexit(sco_mapon); sco_mapoff(); switch_graphics(IBM_GRAPHICS); # ifdef TEXTCOLOR if (has_colors()) iflags.use_color = TRUE; # endif } # endif } #endif /* _M_UNIX */ #ifdef __linux__ /* via Jesse Thilo and Ben Gertzfield */ # include int linux_flag_console = 0; void NDECL(linux_mapon); void NDECL(linux_mapoff); void NDECL(check_linux_console); void NDECL(init_linux_cons); void linux_mapon() { # ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && linux_flag_console) { write(1, "\033(B", 3); } # endif } void linux_mapoff() { # ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && linux_flag_console) { write(1, "\033(U", 3); } # endif } void check_linux_console() { struct vt_mode vtm; if (isatty(0) && ioctl(0,VT_GETMODE,&vtm) >= 0) { linux_flag_console = 1; } } void init_linux_cons() { # ifdef TTY_GRAPHICS if (!strcmp(windowprocs.name, "tty") && linux_flag_console) { atexit(linux_mapon); linux_mapoff(); # ifdef TEXTCOLOR if (has_colors()) iflags.use_color = TRUE; # endif } # endif } #endif /* __linux__ */ #ifndef __begui__ /* the Be GUI will define its own error proc */ /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *,s) VA_START(s); VA_INIT(s, const char *); if(settty_needed) settty((char *)0); Vprintf(s,VA_ARGS); (void) putchar('\n'); VA_END(); exit(EXIT_FAILURE); } #endif /* !__begui__ */ nethack-3.4.3/sys/share/uudecode.c0100644000000000000000000001330107764735041015531 0ustar rootroot/* * Copyright (c) 1983 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ /* * Modified 12 April 1990 by Mark Adler for use on MSDOS systems with * Microsoft C and Turbo C. * * Modifed 13 February 1991 by Greg Roelofs for use on VMS systems. As * with the MS-DOS version, the setting of the file mode has been disabled. * Compile and link normally (but note that the shared-image link option * produces a binary only 6 blocks long, as opposed to the 137-block one * produced by an ordinary link). To set up the VMS symbol to run the * program ("run uudecode filename" won't work), do: * uudecode :== "$disk:[directory]uudecode.exe" * and don't forget the leading "$" or it still won't work. The binaries * produced by this program are in VMS "stream-LF" format; this makes no * difference to VMS when running decoded executables, nor to VMS unzip, * but other programs such as zoo or arc may or may not require the file * to be "BILFed" (or "unBILFed" or whatever). Also, unlike the other * flavors, VMS files don't get overwritten (a higher version is created). * * Modified 13 April 1991 by Gary Mussar to be forgiving of systems that * appear to be stripping trailing blanks. * * Modified 28 February 2002 for use on WIN32 systems with Microsoft C. */ #ifndef lint static char sccsid[] = "@(#)uudecode.c 5.5 (Berkeley) 7/6/88"; #endif /* not lint */ #ifdef __MSDOS__ /* For Turbo C */ #define MSDOS 1 #endif #ifdef _WIN32 #undef MSDOS #undef __MSDOS__ #ifndef WIN32 #define WIN32 #endif #endif /* * uudecode [input] * * create the specified file, decoding as you go. * used with uuencode. */ #include #ifdef VMS # include # include #else # if !defined(MSDOS) && !defined(WIN32) # include # endif # include /* MSDOS, WIN32, or UNIX */ # include # include # include #endif static void decode(FILE *, FILE *); static void outdec(char *, FILE *, int); /* single-character decode */ #define DEC(c) (((c) - ' ') & 077) int main(argc, argv) int argc; char **argv; { FILE *in, *out; int mode; char dest[128]; char buf[80]; /* optional input arg */ if (argc > 1) { if ((in = fopen(argv[1], "r")) == NULL) { perror(argv[1]); exit(1); } argv++; argc--; } else in = stdin; if (argc != 1) { printf("Usage: uudecode [infile]\n"); exit(2); } /* search for header line */ for (;;) { if (fgets(buf, sizeof buf, in) == NULL) { fprintf(stderr, "No begin line\n"); exit(3); } if (strncmp(buf, "begin ", 6) == 0) break; } (void)sscanf(buf, "begin %o %s", &mode, dest); #if !defined(MSDOS) && !defined(VMS) && !defined(WIN32) /* handle ~user/file format */ if (dest[0] == '~') { char *sl; struct passwd *getpwnam(); struct passwd *user; char dnbuf[100], *index(), *strcat(), *strcpy(); sl = index(dest, '/'); if (sl == NULL) { fprintf(stderr, "Illegal ~user\n"); exit(3); } *sl++ = 0; user = getpwnam(dest+1); if (user == NULL) { fprintf(stderr, "No such user as %s\n", dest); exit(4); } strcpy(dnbuf, user->pw_dir); strcat(dnbuf, "/"); strcat(dnbuf, sl); strcpy(dest, dnbuf); } #endif /* !defined(MSDOS) && !defined(VMS) */ /* create output file */ #if defined(MSDOS) || defined(WIN32) out = fopen(dest, "wb"); /* Binary file */ #else out = fopen(dest, "w"); #endif if (out == NULL) { perror(dest); exit(4); } #if !defined(MSDOS) && !defined(VMS) && !defined(WIN32) /* i.e., UNIX */ chmod(dest, mode); #endif decode(in, out); if (fgets(buf, sizeof buf, in) == NULL || strcmp(buf, "end\n")) { fprintf(stderr, "No end line\n"); exit(5); } exit(0); /*NOTREACHED*/ return 0; } /* * copy from in to out, decoding as you go along. */ void decode(in, out) FILE *in; FILE *out; { char buf[80]; char *bp; int n, i, expected; for (;;) { /* for each input line */ if (fgets(buf, sizeof buf, in) == NULL) { printf("Short file\n"); exit(10); } n = DEC(buf[0]); if ((n <= 0) || (buf[0] == '\n')) break; /* Calculate expected # of chars and pad if necessary */ expected = ((n+2)/3)<<2; for (i = strlen(buf)-1; i <= expected; i++) buf[i] = ' '; bp = &buf[1]; while (n > 0) { outdec(bp, out, n); bp += 4; n -= 3; } } } /* * output a group of 3 bytes (4 input characters). * the input chars are pointed to by p, they are to * be output to file f. n is used to tell us not to * output all of them at the end of the file. */ void outdec(p, f, n) char *p; FILE *f; int n; { int c1, c2, c3; c1 = DEC(*p) << 2 | DEC(p[1]) >> 4; c2 = DEC(p[1]) << 4 | DEC(p[2]) >> 2; c3 = DEC(p[2]) << 6 | DEC(p[3]); if (n >= 1) putc(c1, f); if (n >= 2) putc(c2, f); if (n >= 3) putc(c3, f); } #if !defined(MSDOS) && !defined(VMS) && !defined(WIN32) /* * Return the ptr in sp at which the character c appears; * NULL if not found */ #ifndef NULL #define NULL 0 #endif char * index(sp, c) register char *sp, c; { do { if (*sp == c) return(sp); } while (*sp++); return(NULL); } #endif nethack-3.4.3/sys/unix/0040755000000000000000000000000007764735105013457 5ustar rootrootnethack-3.4.3/sys/unix/Install.unx0100644000000000000000000003555207764735041015627 0ustar rootroot Instructions for installing NetHack 3.4 on a UNIX system ======================================= 0. Read this entire file before starting, and come back to the Notes below if you have any problems. If you are trying to use X11, also read all of win/X11/Install.X11, or read win/Qt/Install.Qt if you are using Qt or KDE under X11. For help in controlling and running the game after it is installed, see the '?' command within the game and doc/Guidebook (non-installers want to know about those things too). 1. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, util, sys/share, sys/unix, win/tty, win/X11, and win/Qt. You may have other subdirectories under sys and win, but they will not affect compilation for a UNIX system. If you do not follow this structure, the Makefiles will not function properly. The .c files for the main program belong in src, those for utility programs in util, and UNIX-specific ones in sys/unix. All the .h files belong in include, the documentation in doc, and assorted data files in dat. Some UNIX versions may also be interested in sys/share's random.c or its lex/yacc output, as explained in note 11. (A more detailed explanation of the directory structure may be found in Files, which should be in the top directory.) 2. Your Makefiles may still be in sys/unix with tags on the end of them. If so, run "sh setup.sh" in that directory to distribute the Makefiles to places they can do their work. (If later official patches change these Makefiles, setup.sh should be rerun to make sure you use the current copies.) 3. Go to the include subdirectory and edit config.h according to the comments to match your system and desired set of features. Similarly edit unixconf.h. Please see the "Notes:" section, below, for some configuration hints for particular systems. 4. If you want to, look through system.h. This file attempts to match the types for system calls and library routines with various flavors of operating systems. Leaving this file alone is unlikely to cause worse problems than lint errors, but it's worth checking if you get compile errors, especially if you have an unusual system. 5. Go to the src subdirectory and look at the top of topten.c. You may want to change the definitions of PERSMAX and PERS_IS_UID here to get different behavior from the high score list. 6. Edit the top sections of the src and util Makefiles. (If you are doing a full recompile, or if you got your files from someplace besides the official distribution, type 'touch makedefs.c' to make sure certain files (onames.h, pm.h) get remade instead of relying on the potentially troublesome timestamps.) Then type 'make' in src and go get a cup of coffee or take a nap, depending on the speed of your system. You should now have created the game executable. 7. Go back to the top directory and edit that Makefile, explaining where you want everything to be installed. Make sure that you follow the comments about setting GAMEDIR -- the installation process will wipe out the contents of the directory you point it at, under the assumption that it's debris from an old version of NetHack. If this is not the case, you'll want to install somewhere else, or comment out the rm under the install target. The Makefile assumes you want to run NetHack setuid 'games' to cut down on possible tampering; it's fairly straightforward to comment out the appropriate chmod if you don't want that, or to change any of the rest of the procedure. (Note that if you don't want to run NetHack either setuid or setgid, and people in more than one group will be playing it, you'll need to go back and set FCMASK to 0666 in unixconf.h and let everybody fiddle with the files NetHack creates.) If the tbl, nroff or col commands are not available on your system, edit the doc/Makefile and change the GUIDECMD as directed. Type 'make all' from the top directory to set up all the auxiliary files the main executable will use. Then become root if necessary and type 'make install'. Everything should now be set. 8. Read doc/recover.man or doc/recover.txt to learn how to use the recover program. The recover program can be used in case of a crash to recover a game that was in progress. The recover command is installed in the GAMEDIR by default. Notes: 1. Save files and bones files from previous versions will not work with NetHack 3.4. Don't bother trying to keep them. 2. To install an update of this version of NetHack after changing something, type 'make update' from the main directory. If you created the new version yourself, it should be safe to use 'make update' as long as you did not add, delete, or reorder monsters or objects and you did not change the format of saved level files. If you did any of these things, you should also remove any saved games and bones levels. (Trying to use such files often produces amusing but useless confusions on the game's part.) 3. If you insisted on doing the final installation by hand, you probably forgot to make a save directory. If you don't go back and do this, you won't be able to save games. 4. If you get unexplained deaths by trickery, you are probably running NetHack on a bunch of workstations, but you have overlooked the NETWORK definition in unixconf.h that is necessary in that configuration. 5. If spurious characters appear on the screen while throwing, kicking, zapping, etc., it is likely that you have linked the source to the wrong library or mistakenly defined/undefined TERMINFO. A number of systems, such as Xenix, support both the termcap and terminfo terminal capability libraries. In such cases, the TERMINFO definition in unixconf.h and the WINTTYLIB definition in the source Makefile must correspond. If your terminal library does not provide suitable delays, NetHack will try to fake its own if you set the nonull option. 6. Since NetHack overflows the stock C preprocessors for AT&T 3b1 and 3b2 systems ("too many defines"), we are including an alternate preprocessor to allow these folks to compile. This is the DECUS cpp by Martin Minow, slightly modified by Kevin Darcy to use larger buffers, be less verbose, and handle strange constructs in AT&T's include files. To use this preprocessor, unpack the cpp* files found in sys/unix into some handy directory (util will do). For the AT&T machines mentioned above, nothing needs to be configured; you should get a working cpp by merely typing "make -f makefile.txt". To get your compiler to use the new cpp, you will have to add to CFLAGS in src/Makefile and util/Makefile. If you put the cpp files in /foo/bar/util, add "-B/foo/bar/util/ -tp" for a 3b1 or "-Yp,/foo/bar/util" for a 3b2. For any other machine whose preprocessor can't handle the NetHack source, you'll have to play it by ear. The preprocessor has many esoteric configuration options, but most probably you will only need to change the flags in makefile.txt, and then refer to your compiler's documentation to find the appropriate CFLAGS for the NetHack Makefiles. (The SunOS flag, for instance, would be "-Qpath /foo/bar/util", although the native cpp has no trouble with NetHack. So much for standardization.) 7. If you are trying to compile NetHack on an AT&T 3B that is running an OS earlier than SVR3, you are likely to have problems with overflowing symbol tables. This can be worked around by editing the source Makefile to make the Sys.3B2 target work more like the SysV-AT target, adding -DDUMB to CFLAGS and DUMB.Setup to the Sys.3B2 dependency line. The compiler provided with later versions of the OS has a large enough symbol table that it does not need this workaround. 8. If NetHack seems to compile fine, starts up, allows you to pick a character, and then hangs indefinitely, gets a segmentation fault, or traps you in a single room on the first level, you might try changing the schar and uchar definitions in config.h to short ints. This problem is known to occur on the AT&T 3B series, Silicon Graphics Irises, and IBM systems (PC/RT & RS/6000) running AIX, and may occur on other computers as well. This problem is really most likely caused by having a non-__STDC__ compiler with char's unsigned by default. Since some such compilers don't understand the new "signed" keyword, and others don't have signed characters to use (the 3B2 line falls into this category), "signed" is #ifdefed away for them. If you are sure your compiler can deal with it, you can add your compiler to the __HC__ case in tradstdc.h. Alternatively, if the compiler supports a command line switch for setting the default char type to signed, you could try setting it in the Makefiles. The appropriate switch for SGI Irises with MIPS C compiler is "-signed" and for RS/6000's with standard cc "-qchars=signed". (SGI machines running IRIX 4.0.x have a compiler close enough to standard to suit NetHack, so you may merely use the suggested flags in the Makefiles.) Note that at least RS/6000's seem to like changing the default to signed better but there is also a problem: The lexers created by the standard lex program in AIX may come out faulty when this switch is used (known to happen at least in AIX 3.1.3), so you may have to use an alternative, like flex, which is available at major archive sites (see notes 10 and 11). By AIX 3.2.5, this whole problem should be taken care of automatically (but AIX_31 should still be defined in unixconf.h for other reasons). 9. Under SCO UNIX, you may have all sorts of complaints about include/obj.h. Go to the file and uncomment the marked line, working around the fact that SCO's system include files preempt a major NetHack structure name. Also, there are difficulties with SCO's cc that thus far have been solved only by changing compilers; one report says gcc-NetHack works, and another says rcc-NetHack can be made to work by defining NOTSTDC, applying note 8, and compiling with -tinfo and -xenix. The cc problems are old enough that a new, working version may have been released by this time. 10. Xenix/286's lex generates a faulty lexical analyser from lev_comp.l. The beta-release of flex 2.3 (available from uunet, osu-cis, prep.ai.mit.edu, etc.) can be used to generate the lexer. The only change to flex is to change "#define yyleng (yy_cp - yy_bp)" to "#define yyleng (int)(yy_cp - yy_bp)" in flex.skel. Flex is not needed with Xenix/386, as its lex generates a proper lexical analyser. [Xenix instructions by J.T. Conklin] 11. If your system does not have a lex/yacc or flex/bison combination capable of producing the dungeon and level compilers, lex and yacc output from one of our development systems can be found in sys/share. Unfortunately, this output is less portable than the rest of the code, as it contains skeleton parsing code provided by the specific vendor who has no particular incentive to make such skeletons portable, but the output works on most systems. To try it on yours, copy dgn_comp.h and lev_comp.h to include and dgn_lex.c, dgn_yacc.c, lev_lex.c, and lev_yacc.c to util. 12. Yes, Virginia, you compile NetHack for a NeXT as if it ran UNIX instead of Mach. Just tell NetHack you're a BSD system (Mach is extremely close to BSD UNIX for traditional system calls, so this is also a likely thing to try for any other programs you want to compile). If you get errors when starting nethack warning that "Setuid execution is not allowed", you might want to re-install using the setgid option instead (see Note 7 above, and the setgid comment in the toplevel Makefile). 13. If you are using Solaris 2.x (aka SunOS 5.x) you shouldn't have to do any system configuration -- this is the default. In case it is messed up, follow these instructions. Solaris is basically a SVR4 system, not a BSD system. Therefore, you configure config.h and unixconf.h as per a SVR4 system: config.h: UNIX, TTY_GRAPHICS unixconf.h: SYSV, SVR4, TERMINFO, POSIX_JOB_CONTROL, POSIX_TYPES X11_GRAPHICS does work. Do not define OPENWINBUG. You may safely define NETWORK, TEXTCOLOR if desired. Other #defines in these files may be defined too, as needed. Just make sure that the set mentioned here are not misdefined, or your compile will fail (do _not_ define BSD or SUNOS4). Unless you are using gzip you will probably want to define COMPRESS to be "/usr/bin/compress". When compiling, make sure that you use the ANSI C SVR4 compatible compiler, /usr/bin/cc, or gcc, but _not_ ucbcc. The lattermost will not work. After this, you should get a clean compile. Also, it is recommended that you use FLEX instead of the standard lex bundled with Solaris 2.x (even if that last one should work ;-). 14. If your machine is a 286, 386, or 486 running an appropriate OS, you may wish to use the console speaker driver included in sys/unix/snd86unx.shr. This will allow audible music to be played on your console speaker in certain appropriate game situations. The only modification to the main-line code needed to enable use of the driver is defining UNIX386MUSIC or VPIX_MUSIC in unixconf.h. 15. If you are trying to cross-compile for another system, there is some support in the src and util Makefiles, but there are still other complications. It may well be best to make another copy of util, util2, to compile target copies of makedefs, lev_comp, and recover (duplicating the cross-compilation settings from the src Makefile) without disturbing the main build. You can use the host makedefs for everything but "makedefs -v", which creates include/date.h, which provides various sanity-checking values for making sure files read by NetHack at run-time are compatible. These values depend on the endianness of your processor, its type sizes, and its compiler's idea of struct packing. Your host and target computers may disagree on these things, so you'll need to build a target version of makedefs, run "makedefs -v" on your target, and bring the resulting date.h back for the builds on the host. (Making sure the host makedefs doesn't decide it needs to overwrite it for you. :-) You also need a target version of lev_comp, and to provide it with all the dat/*.des files, and copy all the resulting *.lev files back for packaging on the host. For recover, you just want the target binary to install on the target. nethack-3.4.3/sys/unix/Makefile.dat0100644000000000000000000000733707764735041015674 0ustar rootroot# NetHack Makefile. # SCCS Id: @(#)Makefile.dat 3.4 1992/09/18 # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP # UUDECODE=uudecode VARDAT = data rumors quest.dat oracles options all: $(VARDAT) spec_levs quest_levs dungeon ../util/makedefs: (cd ../util ; make makedefs) ../util/dgn_comp: (cd ../util ; make dgn_comp) ../util/lev_comp: (cd ../util ; make lev_comp) ../util/tile2x11: (cd ../util ; make tile2x11) ../util/tile2beos: (cd ../util ; make tile2beos) ../util/tile2bmp: (cd ../util ; make tile2bmp) x11tiles: ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \ ../win/share/other.txt ../util/tile2x11 ../win/share/monsters.txt ../win/share/objects.txt \ ../win/share/other.txt beostiles: ../util/tile2beos ../win/share/monsters.txt ../win/share/objects.txt \ ../win/share/other.txt ../util/tile2beos ../win/share/monsters.txt ../win/share/objects.txt \ ../win/share/other.txt nhtiles.bmp: ../util/tile2bmp ../win/share/monsters.txt ../win/share/objects.txt \ ../win/share/other.txt ../util/tile2bmp $@ NetHack.ad: ../win/X11/NetHack.ad cp ../win/X11/NetHack.ad NetHack.ad pet_mark.xbm: ../win/X11/pet_mark.xbm cp ../win/X11/pet_mark.xbm pet_mark.xbm rip.xpm: ../win/X11/rip.xpm cp ../win/X11/rip.xpm rip.xpm mapbg.xpm: ../win/gnome/mapbg.xpm cp ../win/gnome/mapbg.xpm mapbg.xpm nhsplash.xpm: ../win/Qt/nhsplash.xpm cp ../win/Qt/nhsplash.xpm nhsplash.xpm nethack.icns: ../win/Qt/nhicns.uu $(UUDECODE) ../win/Qt/nhicns.uu Info.plist: ../win/Qt/Info.pli cp ../win/Qt/Info.pli Info.plist ../util/tile2img.ttp: (cd ../util ; make tile2img.ttp) ../util/xpm2img.ttp: (cd ../util ; make xpm2img.ttp) nh16.img: ../util/tile2img.ttp ../win/share/monsters.txt \ ../win/share/objects.txt ../win/share/other.txt ../util/tile2img.ttp nh16.img rip.img: ../util/xpm2img.ttp ../util/xpm2img.ttp ../win/X11/rip.xpm rip.img title.img: # cp ../win/gem/title.img title.img $(UUDECODE) ../win/gem/title.uu GEM_RSC.RSC: # cp ../win/gem/GEM_RSC.RSC GEM_RSC.RSC $(UUDECODE) ../win/gem/gem_rsc.uu data: data.base ../util/makedefs ../util/makedefs -d rumors: rumors.tru rumors.fal ../util/makedefs ../util/makedefs -r quest.dat: quest.txt ../util/makedefs ../util/makedefs -q oracles: oracles.txt ../util/makedefs ../util/makedefs -h # note: 'options' should have already been made when include/date.h was created options: ../util/makedefs ../util/makedefs -v spec_levs: ../util/lev_comp \ bigroom.des castle.des endgame.des gehennom.des knox.des medusa.des \ mines.des oracle.des sokoban.des tower.des yendor.des ../util/lev_comp bigroom.des ../util/lev_comp castle.des ../util/lev_comp endgame.des ../util/lev_comp gehennom.des ../util/lev_comp knox.des ../util/lev_comp medusa.des ../util/lev_comp mines.des ../util/lev_comp oracle.des ../util/lev_comp sokoban.des ../util/lev_comp tower.des ../util/lev_comp yendor.des touch spec_levs quest_levs: ../util/lev_comp \ Arch.des Barb.des Caveman.des Healer.des Knight.des Monk.des \ Priest.des Ranger.des Rogue.des Samurai.des Tourist.des Valkyrie.des \ Wizard.des ../util/lev_comp Arch.des ../util/lev_comp Barb.des ../util/lev_comp Caveman.des ../util/lev_comp Healer.des ../util/lev_comp Knight.des ../util/lev_comp Monk.des ../util/lev_comp Priest.des ../util/lev_comp Ranger.des ../util/lev_comp Rogue.des ../util/lev_comp Samurai.des ../util/lev_comp Tourist.des ../util/lev_comp Valkyrie.des ../util/lev_comp Wizard.des touch quest_levs dungeon: dungeon.def ../util/makedefs ../util/dgn_comp ../util/makedefs -e ../util/dgn_comp dungeon.pdf spotless: -rm -f spec_levs quest_levs *.lev $(VARDAT) dungeon dungeon.pdf -rm -f nhdat x11tiles beostiles pet_mark.xbm rip.xpm mapbg.xpm -rm -f rip.img GEM_RSC.RSC title.img nh16.img NetHack.ad nethack-3.4.3/sys/unix/Makefile.doc0100644000000000000000000000550307764735041015662 0ustar rootroot# NetHack Makefile. # SCCS Id: @(#)Makefile.doc 3.4 1996/03/23 # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP GUIDEBOOK = Guidebook # regular ASCII file #GUIDEBOOK = Guidebook.ps # PostScript file #GUIDEBOOK = Guidebook.dvi # TeX device-independent file # Some versions of col need -x to keep them from converting spaces to tabs; # some versions of col don't do the conversion by default and don't # recognize the option. Sigh. COLCMD = col -bx #COLCMD = col -b # The command to use to generate a PostScript file # PSCMD = ditroff | psdit PSCMD = groff # Use the "cat" GUIDECMD if nroff and/or tbl and/or col are not installed # Not appropriate for creating Guidebook.txt. # GUIDECMD = cat Guidebook.txt # The following works better with groff-1.18, eg on Linux # GUIDECMD = tbl tmac.n Guidebook.mn | nroff -c -Tascii | $(COLCMD) GUIDECMD = tbl tmac.n Guidebook.mn | nroff | $(COLCMD) # the basic guidebook Guidebook: Guidebook.mn $(GUIDECMD) > Guidebook # Fancier output for those with ditroff, psdit and a PostScript printer. Guidebook.ps: Guidebook.mn tbl tmac.n Guidebook.mn | $(PSCMD) > Guidebook.ps # Guidebook.tex is the same as Guidebook.mn but formatted with LaTeX. # - The invocation command for LaTeX may vary in different installations. # - To print Guidebook.dvi you need to use a suitable dvi-driver. Guidebook.dvi: Guidebook.tex latex Guidebook.tex GAME = nethack MANDIR = /usr/man/man6 MANEXT = 6 # manual installation for most BSD-style systems GAMEMANCREATE = cp nethack.6 LEVMANCREATE = cp lev_comp.6 DGNMANCREATE = cp dgn_comp.6 RCVRMANCREATE = cp recover.6 DLBMANCREATE = cp dlb.6 # manual installation for most SYSV-style systems # GAMEMANCREATE = nroff -man nethack.6 > # LEVMANCREATE = nroff -man lev_comp.6 > # DGNMANCREATE = nroff -man dgn_comp.6 > # RCVRMANCREATE = nroff -man recover.6 > # DLBMANCREATE = nroff -man dlb.6 > manpages: -$(GAMEMANCREATE) $(MANDIR)/$(GAME).$(MANEXT) -$(LEVMANCREATE) $(MANDIR)/lev_comp.$(MANEXT) -$(DGNMANCREATE) $(MANDIR)/dgn_comp.$(MANEXT) -$(RCVRMANCREATE) $(MANDIR)/recover.$(MANEXT) -$(DLBMANCREATE) $(MANDIR)/dlb.$(MANEXT) # manual creation for distribution DISTRIB = Guidebook.txt nethack.txt lev_comp.txt dgn_comp.txt recover.txt dlb.txt distrib: $(DISTRIB) @echo "Plain text documentation is up to date." Guidebook.txt : Guidebook.mn tmac.n $(GUIDECMD) > Guidebook.txt nethack.txt : nethack.6 nroff -man nethack.6 | $(COLCMD) > nethack.txt lev_comp.txt : lev_comp.6 nroff -man lev_comp.6 | $(COLCMD) > lev_comp.txt dgn_comp.txt : dgn_comp.6 nroff -man dgn_comp.6 | $(COLCMD) > dgn_comp.txt recover.txt : recover.6 nroff -man recover.6 | $(COLCMD) > recover.txt dlb.txt : dlb.6 nroff -man dlb.6 | $(COLCMD) > dlb.txt clean: -rm -f Guidebook.aux Guidebook.log spotless: clean -rm -f Guidebook Guidebook.ps Guidebook.dvi maintainer-clean: spotless -rm -f $(DISTRIB) # -rm -f Makefile nethack-3.4.3/sys/unix/Makefile.src0100644000000000000000000007605207764735041015713 0ustar rootroot# NetHack Makefile. # SCCS Id: @(#)Makefile.src 3.4 2002/03/02 # newer makes predefine $(MAKE) to 'make' and do smarter processing of # recursive make calls if $(MAKE) is used # these makes allow $(MAKE) to be overridden by the environment if someone # wants to (or has to) use something other than the standard make, so we do # not want to unconditionally set $(MAKE) here # # unfortunately, some older makes do not predefine $(MAKE); if you have one of # these, uncomment the following line # (you will know that you have one if you get complaints about being unable # to find 'makedefs') # MAKE = make # This makefile replaces the previous Makefile.unix, Makefile.xenix, # Makefile.3B2, Makefile.att, and Makefile.tos. # Set SYSTEM to one of: # 'Sysunix' -- generic UNIX # 'Sys3B2' -- AT&T 3B2, 3B5, etc. # 'Sysatt' -- AT&T UNIXPC, 7300, 3B1 # 'SysV-AT' -- Microport 286 UNIX (put -DDUMB in CFLAGS) # 'Systos' -- Atari # 'SysBe' -- BeOS SYSTEM = Sysunix # # Make sure that your bourne shell is specified here, as you have to spawn # some of the commands (eg. depend) in bourne shell for them to work. # # For Systos users compiling on the ST, you'll either need a bourne shell # clone or you'll need to do make depend, etc. by hand. In either case, # the line below probably needs changing SHELL=/bin/sh # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP # Normally, the C compiler driver is used for linking: LINK=$(CC) # Pick the SYSSRC and SYSOBJ lines corresponding to your desired operating # system. # # for UNIX systems SYSSRC = ../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \ ../sys/unix/unixunix.c ../sys/unix/unixres.c SYSOBJ = ioctl.o unixmain.o unixtty.o unixunix.o unixres.o # # for Systos # SYSSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \ # ../sys/share/pctty.c ../sys/share/pcunix.c # SYSOBJ = tos.o pcmain.o pcsys.o pctty.o pcunix.o # # for BeOS #SYSSRC = ../sys/be/bemain.c ../sys/share/unixtty.c ../sys/share/ioctl.c #SYSOBJ = bemain.o unixtty.o ioctl.o # if you are using gcc as your compiler: # uncomment the CC definition below if it's not in your environment # if you get setcgtty() warnings during execution, you are feeding gcc # a non-ANSI -- either run fixincludes on it or use # -traditional in CFLAGS # CC = gcc # # For Bull DPX/2 systems at B.O.S. 2.0 or higher use the following: # # CC = gcc -ansi -D_BULL_SOURCE -D_XOPEN_SOURCE -D_POSIX_SOURCE # # If you are using GCC 2.2.2 or higher on a DPX/2, just use: # # CC = gcc -ansi # # For HP/UX 10.20 with GCC: # CC = gcc -D_POSIX_SOURCE # # For cross-compiling, eg. with gcc on Linux (see also CXX further down): # CC = arm-linux-gcc # # # if you're debugging and want gcc to check as much as possible, use: # CC = gcc -W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN # flags may have to be changed as required # flags for 286 Xenix: # CFLAGS = -Ml2t16 -O -LARGE -I../include # LFLAGS = -Ml -F 4000 -SEG 512 # flags for 286 Microport SysV-AT # CFLAGS = -DDUMB -Ml -I../include # LFLAGS = -Ml # flags for Atari gcc (3.2.1) # CFLAGS = -O -I../include # LFLAGS = -s # flags for Atari gcc (3.3) # CFLAGS = -mshort -O2 -fomit-frame-pointer -I../include # LFLAGS = -mshort -s # flags for AIX 3.1 cc on IBM RS/6000 to define # a suitable subset of standard libraries # (note that there is more info regarding the "-qchars=signed" # switch in file Install.unx note 8) # CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -O -I../include -qchars=signed # # Some of our subroutines are complex enough that this is required for full # optimization under AIX 3.2 (I don't know about 3.1). # # CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -D_ALL_SOURCE -O -I../include -qchars=signed -qmaxmem=5000 # flags for A/UX 2.01 using native cc or c89 # gcc predefines AUX so that's not needed there # Remember to use -lcurses for WINLIB below ! # CFLAGS = -ZS -D_POSIX_SOURCE -O -I../include -DAUX # flags for IRIX 4.0.x using native cc # The include files are __STDC__, but have bugs involving const # CFLAGS = -O -I../include -D__STDC__ -Dconst= -woff 100,293 # LFLAGS = -s # flags for BSD/OS 2.0 # CFLAGS = -O -I../include -I/usr/X11/include # LFLAGS = -L/usr/X11/lib # flags for Linux # compile normally # CFLAGS = -O2 -fomit-frame-pointer -I../include # LFLAGS = -L/usr/X11R6/lib # OR compile backwards compatible a.out format # CFLAGS = -O2 -b i486-linuxaout -fomit-frame-pointer -I../include # LFLAGS = -b i486-linuxaout -L/usr/X11R6/lib # flags for BeOS # on a Mac/BeBox: #CC = mwcc #CFLAGS = -r -I../include #LINK = mwld #LFLAGS = -map nethack.xMAP # on Intel: #CFLAGS = -O -I../include #LINK = gcc #LFLAGS = -Xlinker -soname=_APP_ # Only used for the Gnome interface. # When including the Gnome interface, you need to include gnome specific # directories. The ones given below is the usual spot for linux systems. # The paths are for glibconfig.h and gnomesupport.h respectively. # GNOMEINC=-I/usr/lib/glib/include -I/usr/lib/gnome-libs/include -I../win/gnome # flags for debugging: # CFLAGS = -g -I../include CFLAGS = -O -I../include LFLAGS = # The Qt and Be window systems are written in C++, while the rest of # NetHack is standard C. If using Qt, uncomment the LINK line here to get # the C++ libraries linked in. CXXFLAGS = $(CFLAGS) -I. -I$(QTDIR)/include CXX=g++ #LINK=g++ # For cross-compiling, eg. with gcc on Linux (see also CC further up): #CXX=arm-linux-g++ #LINK=arm-linux-gcc # Set the WINSRC, WINOBJ, and WINLIB lines to correspond to your desired # combination of windowing systems. Also set windowing systems in config.h. # Note that if you are including multiple tiled window systems, you don't # want two copies of tile.o, so comment out all but the first. # # files for a straight tty port using no native windowing system WINTTYSRC = ../win/tty/getline.c ../win/tty/termcap.c ../win/tty/topl.c \ ../win/tty/wintty.c WINTTYOBJ = getline.o termcap.o topl.o wintty.o # # files for an X11 port # (tile.c is a generated source file) WINX11SRC = ../win/X11/Window.c ../win/X11/dialogs.c ../win/X11/winX.c \ ../win/X11/winmap.c ../win/X11/winmenu.c ../win/X11/winmesg.c \ ../win/X11/winmisc.c ../win/X11/winstat.c ../win/X11/wintext.c \ ../win/X11/winval.c tile.c WINX11OBJ = Window.o dialogs.o winX.o winmap.o winmenu.o winmesg.o \ winmisc.o winstat.o wintext.o winval.o tile.o # # Files for a Qt port # WINQTSRC = ../win/Qt/qt_win.cpp ../win/Qt/qt_clust.cpp ../win/Qt/qttableview.cpp WINQTOBJ = qt_win.o qt_clust.o qttableview.o tile.o # # Files for a Gnome port # WINGNOMESRC = ../win/gnome/gnaskstr.c ../win/gnome/gnbind.c \ ../win/gnome/gnglyph.c ../win/gnome/gnmain.c ../win/gnome/gnmap.c \ ../win/gnome/gnmenu.c ../win/gnome/gnmesg.c ../win/gnome/gnopts.c \ ../win/gnome/gnplayer.c ../win/gnome/gnsignal.c \ ../win/gnome/gnstatus.c ../win/gnome/gntext.c ../win/gnome/gnyesno.c \ ../win/gnome/gnworn.c WINGNOMEOBJ = gnaskstr.o gnbind.o gnglyph.o gnmain.o gnmap.o gnmenu.o \ gnmesg.o gnopts.o gnplayer.o gnsignal.o gnstatus.o gntext.o \ gnyesno.o gnworn.o tile.o # # Files for a Gem port WINGEMSRC = ../win/gem/wingem.c ../win/gem/wingem1.c ../win/gem/load_img.c \ ../win/gem/gr_rect.c tile.c WINGEMOBJ = wingem.o wingem1.o load_img.o gr_rect.o tile.o # # Files for a BeOS InterfaceKit port -- not ready for prime time WINBESRC = WINBEOBJ = #WINBESRC = ../win/BeOS/winbe.cpp ../win/BeOS/NHWindow.cpp \ # ../win/BeOS/NHMenuWindow.cpp ../win/BeOS/NHMapWindow.cpp tile.c #WINBEOBJ = winbe.o NHWindow.o NHMenuWindow.o NHMapWindow.o tile.o # # WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) # on some systems the termcap library is in -ltermcap or -lcurses # on 386 Xenix, the -ltermlib tputs() seems not to work; use -lcurses instead # Sysatt uses shared library in lieu of this option # Systos needs -lcurses16 if you use -mshort # AIX 3.1 on RS/6000 likes -lcurses if TERMINFO defined in unixconf.h # and -ltermcap otherwise # Linux uses -lncurses (newer) or -ltermcap (older) # Be uses -ltermcap # # libraries for tty ports # WINTTYLIB = -ltermcap # WINTTYLIB = -lcurses # WINTTYLIB = -lcurses16 # WINTTYLIB = -lncurses WINTTYLIB = -ltermlib # # libraries for X11 # If USE_XPM is defined in config.h, you will also need -lXpm here. WINX11LIB = -lXaw -lXmu -lXext -lXt -lX11 # WINX11LIB = -lXaw -lXmu -lXt -lX11 # WINX11LIB = -lXaw -lXmu -lXext -lXt -lXpm -lX11 -lm # WINX11LIB = -lXaw -lXmu -lXpm -lXext -lXt -lX11 -lSM -lICE -lm # BSD/OS 2.0 # # libraries for Qt WINQTLIB = -L$(QTDIR)/lib -lqt # # libraries for KDE (with Qt) WINKDELIB = -lkdecore -lkdeui -lXext # # libraries for Gnome WINGNOMELIB = -lgnomeui -lgnome -lart_lgpl -lgtk -lgdk -lpopt # # libraries for Gem port WINGEMLIB = -le_gem -lgem # # libraries for BeOS WINBELIB = -lbe WINLIB = $(WINTTYLIB) # any other strange libraries your system needs (for Sysunix only -- the more # specialized targets should already be right) # # on HP-UX 8.x, the malloc(3x) routines in libmalloc.a seem to align things # better than the malloc(3) ones in libc.a # LIBS = -lmalloc # # DPX/2's also use the malloc(3x) routines. In addition, if you are building # for X11, you must include libinet.a. # LIBS = -lmalloc -linet # # Linux NetHack uses some bsd style ioctl functions, thus it is necessary to # use the bsd libs. (Only if still compiling as BSD in unixconf.h; recent # versions compile fine using SYSV without this.) # LIBS = -lbsd # # for CYGWIN32 aka cygwin 1.1.1 # LIBS = -lcygwin # # Solaris 2.x seems to work with the following # LIBS = -lsocket -lnsl # # IRIX 4.0.x needs -lsun if NIS (YP) is being used for passwd file lookup # LIBS = -lsun # LIBS = # make NetHack GAME = nethack # GAME = nethack.prg # if you defined RANDOM in unixconf.h/tosconf.h since your system did not come # with a reasonable random number generator # RANDOBJ = random.o RANDOBJ = # used by `make depend' to reconstruct this Makefile; you shouldn't need this AWK = nawk # ---------------------------------------- # # Nothing below this line should have to be changed. # # Other things that have to be reconfigured are in config.h, # {unixconf.h, pcconf.h, tosconf.h}, and possibly system.h MAKEDEFS = ../util/makedefs # timestamp files to reduce `make' overhead and shorten .o dependency lists CONFIG_H = ../src/config.h-t HACK_H = ../src/hack.h-t # all .c that are part of the main NetHack program and are not operating- or # windowing-system specific HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \ do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \ dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \ files.c fountain.c hack.c hacklib.c invent.c light.c lock.c \ mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c \ mklev.c mkmap.c \ mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \ mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c \ rnd.c role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c \ spell.c steal.c steed.c teleport.c timeout.c topten.c track.c trap.c \ u_init.c uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \ windows.c wizard.c worm.c worn.c write.c zap.c # all operating-system-dependent .c (for dependencies and such) SYSCSRC = ../sys/atari/tos.c ../sys/share/pcmain.c ../sys/share/pcsys.c \ ../sys/share/pctty.c ../sys/share/pcunix.c ../sys/share/random.c \ ../sys/share/ioctl.c ../sys/share/unixtty.c ../sys/unix/unixmain.c \ ../sys/unix/unixunix.c ../sys/unix/unixres.c ../sys/be/bemain.c # generated source files (tile.c is handled separately via WINxxxSRC) GENCSRC = monstr.c vis_tab.c #tile.c # all windowing-system-dependent .c (for dependencies and such) WINCSRC = $(WINTTYSRC) $(WINX11SRC) $(WINGNOMESRC) $(WINGEMSRC) # all windowing-system-dependent .cpp (for dependencies and such) WINCXXSRC = $(WINQTSRC) $(WINBESRC) # .c files for this version (for date.h) VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(GENCSRC) # .c files for all versions using this Makefile (for lint and tags) CSOURCES = $(HACKCSRC) $(SYSSRC) $(WINCSRC) $(GENCSRC) # all .h files except date.h, onames.h, pm.h, and vis_tab.h which would # cause dependency loops if run through "make depend" # and dgn_comp.h, dgn_file.h, lev_comp.h, special level & dungeon files. # HACKINCL = align.h amiconf.h artifact.h artilist.h attrib.h beconf.h color.h \ config.h config1.h coord.h decl.h def_os2.h display.h dlb.h dungeon.h \ edog.h emin.h engrave.h epri.h eshk.h extern.h flag.h func_tab.h \ global.h hack.h lev.h macconf.h mfndpos.h micro.h mkroom.h \ monattk.h mondata.h monflag.h monst.h monsym.h obj.h objclass.h \ os2conf.h patchlevel.h pcconf.h permonst.h prop.h rect.h region.h rm.h \ sp_lev.h spell.h system.h tcap.h timeout.h tosconf.h tradstdc.h \ trampoli.h trap.h unixconf.h vault.h vision.h vmsconf.h wintty.h \ winX.h winprocs.h wintype.h you.h youprop.h HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h\ lev_comp.h dgn_comp.h dgn_file.h # the following .o's _must_ be made before any others (for makedefs) FIRSTOBJ = monst.o objects.o HOBJ = $(FIRSTOBJ) allmain.o alloc.o apply.o artifact.o attrib.o ball.o \ bones.o botl.o cmd.o dbridge.o decl.o detect.o dig.o display.o dlb.o \ do.o do_name.o do_wear.o dog.o dogmove.o dokick.o dothrow.o \ drawing.o dungeon.o eat.o end.o engrave.o exper.o explode.o \ extralev.o files.o fountain.o hack.o hacklib.o invent.o light.o \ lock.o mail.o makemon.o mapglyph.o mcastu.o mhitm.o mhitu.o \ minion.o mklev.o mkmap.o \ mkmaze.o mkobj.o mkroom.o mon.o mondata.o monmove.o monstr.o \ mplayer.o mthrowu.o muse.o music.o o_init.o objnam.o options.o \ pager.o pickup.o pline.o polyself.o potion.o pray.o priest.o \ quest.o questpgr.o read.o rect.o region.o restore.o rip.o rnd.o \ role.o rumors.o save.o shk.o shknam.o sit.o sounds.o sp_lev.o spell.o \ steal.o steed.o teleport.o timeout.o topten.o track.o trap.o u_init.o \ uhitm.o vault.o vision.o vis_tab.o weapon.o were.o wield.o windows.o \ wizard.o worm.o worn.o write.o zap.o \ $(RANDOBJ) $(SYSOBJ) $(WINOBJ) version.o # the .o files from the HACKCSRC, SYSSRC, and WINSRC lists $(GAME): $(SYSTEM) @echo "$(GAME) is up to date." Sysunix: $(HOBJ) Makefile @echo "Loading ..." $(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) @touch Sysunix Sys3B2: $(HOBJ) Makefile @echo "Loading ..." @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) -lmalloc @touch Sys3B2 Sysatt: $(HOBJ) Makefile @echo "Loading ..." @$(LD) $(LFLAGS) /lib/crt0s.o /lib/shlib.ifile -o $(GAME) $(HOBJ) @touch Sysatt Systos: $(HOBJ) Makefile @echo "Loading ..." @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) @touch Systos SysV-AT: DUMB.Setup $(HOBJ) Makefile @echo "Loading ..." @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) @touch SysV-AT SysBe: $(HOBJ) Makefile @echo "Loading ..." @$(LINK) $(LFLAGS) -o $(GAME) $(HOBJ) $(WINLIB) $(LIBS) @xres -o $(GAME) ../win/BeOS/nethack.rsrc @mimeset -f $(GAME) @touch SysBe DUMB.Setup: ../include/extern.h cp ../include/extern.h ../include/extern.h.BAK cat ../include/extern.h | \ sed -e '/^E\ int\ /!b' \ -e '/[^;/ ]$$/N' \ -e '/[(][*]occupation[)]/b' \ -e '/[(][*]afternmv[)]/b' \ -e '/float_down/b' \ -e '/done1/b' \ -e '/identify/b' \ -e '/Hear_again/b' \ -e '/hangup/b' \ -e 's/^\(.*\)$$/\/\* \1 \/\*\*\//' | \ sed -e '/^E\ void\ /!b' \ -e '/[^;/ ]$$/N' \ -e 's/^\(.*\)$$/\/\* \1 \/\*\*\//' \ >../include/extern.DUMB cp ../include/extern.DUMB ../include/extern.h @touch DUMB.Setup all: $(GAME) # dependencies for makedefs and its outputs, which the util # Makefile is responsible for keeping up to date # # special rules, to force update of makedefs, real dependencies should be # below in the 'make depend' output. monst.o: $(CC) $(CFLAGS) -c monst.c @rm -f $(MAKEDEFS) objects.o: $(CC) $(CFLAGS) -c objects.c @rm -f $(MAKEDEFS) # Qt windowport meta-object-compiler output qt_kde0.moc: ../include/qt_kde0.h $(QTDIR)/bin/moc -o qt_kde0.moc ../include/qt_kde0.h qt_win.moc: ../include/qt_win.h $(QTDIR)/bin/moc -o qt_win.moc ../include/qt_win.h qttableview.moc: ../include/qttableview.h $(QTDIR)/bin/moc -o qttableview.moc ../include/qttableview.h $(MAKEDEFS): ../util/makedefs.c $(CONFIG_H) ../include/permonst.h \ ../include/objclass.h ../include/monsym.h \ ../include/artilist.h ../include/dungeon.h ../include/obj.h \ ../include/monst.h ../include/you.h ../include/flag.h \ ../include/dlb.h ../include/patchlevel.h ../include/qtext.h @( cd ../util ; $(MAKE) makedefs) ../include/onames.h: $(MAKEDEFS) @( cd ../util ; $(MAKE) ../include/onames.h ) ../include/pm.h: $(MAKEDEFS) @( cd ../util ; $(MAKE) ../include/pm.h ) monstr.c: $(MAKEDEFS) @( cd ../util ; $(MAKE) ../src/monstr.c ) ../include/vis_tab.h: $(MAKEDEFS) @( cd ../util ; $(MAKE) ../include/vis_tab.h ) # makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first vis_tab.c: ../include/vis_tab.h tile.c: ../win/share/tilemap.c $(HACK_H) @( cd ../util ; $(MAKE) ../src/tile.c ) ../win/gnome/gn_rip.h: ../win/X11/rip.xpm cp ../win/X11/rip.xpm ../win/gnome/gn_rip.h # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. # # hack.h depends on makedefs' output, so we know makedefs will be # up to date before being executed ../include/date.h: $(VERSOURCES) $(HACK_H) ../util/makedefs -v lint: # lint cannot have -p here because (i) capitals are meaningful: # [Ww]izard, (ii) identifiers may coincide in the first six places: # doweararm() versus dowearring(). # _flsbuf comes from , a bug in the system libraries. @echo lint -axbh -DLINT ... @lint -axbh -I../include -DLINT $(CSOURCES) | sed '/_flsbuf/d' tags: $(CSOURCES) @echo ctags -tw ... @ctags -tw $(CSOURCES) @( cd ../include ; ctags -tw $(HSOURCES) ) @( cd ../util ; $(MAKE) tags ) clean: -rm -f *.o $(HACK_H) $(CONFIG_H) spotless: clean -rm -f a.out core $(GAME) Sys* -rm -f ../include/date.h ../include/onames.h ../include/pm.h -rm -f monstr.c ../include/vis_tab.h vis_tab.c tile.c *.moc -rm -f ../win/gnome/gn_rip.h depend: ../sys/unix/depend.awk \ $(SYSCSRC) $(WINCSRC) $(WINCXXSRC) $(GENCSRC) $(HACKCSRC) $(AWK) -f ../sys/unix/depend.awk ../include/*.h \ $(SYSCSRC) $(WINCSRC) $(WINCXXSRC) $(GENCSRC) $(HACKCSRC) >makedep @echo '/^# DO NOT DELETE THIS LINE OR CHANGE ANYTHING BEYOND IT/+2,$$d' >eddep @echo '$$r makedep' >>eddep @echo 'w' >>eddep @cp Makefile Makefile.bak ed - Makefile < eddep @rm -f eddep makedep @echo '# DEPENDENCIES MUST END AT END OF FILE' >> Makefile @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile @echo '# see make depend above' >> Makefile - diff Makefile.bak Makefile @rm -f Makefile.bak # DO NOT DELETE THIS LINE OR CHANGE ANYTHING BEYOND IT # config.h timestamp $(CONFIG_H): ../include/config.h ../include/config1.h ../include/tradstdc.h \ ../include/global.h ../include/coord.h ../include/vmsconf.h \ ../include/system.h ../include/unixconf.h ../include/os2conf.h \ ../include/micro.h ../include/pcconf.h ../include/tosconf.h \ ../include/amiconf.h ../include/macconf.h ../include/beconf.h \ ../include/wceconf.h ../include/ntconf.h ../include/nhlan.h touch $(CONFIG_H) # hack.h timestamp $(HACK_H): ../include/hack.h $(CONFIG_H) ../include/align.h \ ../include/dungeon.h ../include/monsym.h ../include/mkroom.h \ ../include/objclass.h ../include/youprop.h ../include/prop.h \ ../include/permonst.h ../include/monattk.h \ ../include/monflag.h ../include/mondata.h ../include/pm.h \ ../include/wintype.h ../include/decl.h ../include/quest.h \ ../include/spell.h ../include/color.h ../include/obj.h \ ../include/you.h ../include/attrib.h ../include/monst.h \ ../include/skills.h ../include/onames.h ../include/timeout.h \ ../include/trap.h ../include/flag.h ../include/rm.h \ ../include/vision.h ../include/display.h ../include/engrave.h \ ../include/rect.h ../include/region.h ../include/winprocs.h \ ../include/wintty.h ../include/trampoli.h touch $(HACK_H) # tos.o: ../sys/atari/tos.c $(HACK_H) ../include/tcap.h $(CC) $(CFLAGS) -c ../sys/atari/tos.c pcmain.o: ../sys/share/pcmain.c $(HACK_H) ../include/dlb.h \ #../include/win32api.h $(CC) $(CFLAGS) -c ../sys/share/pcmain.c pcsys.o: ../sys/share/pcsys.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/pcsys.c pctty.o: ../sys/share/pctty.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/pctty.c pcunix.o: ../sys/share/pcunix.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/pcunix.c random.o: ../sys/share/random.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/random.c ioctl.o: ../sys/share/ioctl.c $(HACK_H) ../include/tcap.h $(CC) $(CFLAGS) -c ../sys/share/ioctl.c unixtty.o: ../sys/share/unixtty.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/share/unixtty.c unixmain.o: ../sys/unix/unixmain.c $(HACK_H) ../include/dlb.h $(CC) $(CFLAGS) -c ../sys/unix/unixmain.c unixunix.o: ../sys/unix/unixunix.c $(HACK_H) $(CC) $(CFLAGS) -c ../sys/unix/unixunix.c unixres.o: ../sys/unix/unixres.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../sys/unix/unixres.c bemain.o: ../sys/be/bemain.c $(HACK_H) ../include/dlb.h $(CC) $(CFLAGS) -c ../sys/be/bemain.c getline.o: ../win/tty/getline.c $(HACK_H) ../include/func_tab.h $(CC) $(CFLAGS) -c ../win/tty/getline.c termcap.o: ../win/tty/termcap.c $(HACK_H) ../include/tcap.h $(CC) $(CFLAGS) -c ../win/tty/termcap.c topl.o: ../win/tty/topl.c $(HACK_H) ../include/tcap.h $(CC) $(CFLAGS) -c ../win/tty/topl.c wintty.o: ../win/tty/wintty.c $(HACK_H) ../include/dlb.h \ ../include/patchlevel.h ../include/tcap.h $(CC) $(CFLAGS) -c ../win/tty/wintty.c Window.o: ../win/X11/Window.c ../include/xwindowp.h ../include/xwindow.h \ $(CONFIG_H) $(CC) $(CFLAGS) -c ../win/X11/Window.c dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../win/X11/dialogs.c winX.o: ../win/X11/winX.c $(HACK_H) ../include/winX.h ../include/dlb.h \ ../include/patchlevel.h ../win/X11/nh72icon \ ../win/X11/nh56icon ../win/X11/nh32icon $(CC) $(CFLAGS) -c ../win/X11/winX.c winmap.o: ../win/X11/winmap.c ../include/xwindow.h $(HACK_H) ../include/dlb.h \ ../include/winX.h ../include/tile2x11.h $(CC) $(CFLAGS) -c ../win/X11/winmap.c winmenu.o: ../win/X11/winmenu.c $(HACK_H) ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winmenu.c winmesg.o: ../win/X11/winmesg.c ../include/xwindow.h $(HACK_H) ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winmesg.c winmisc.o: ../win/X11/winmisc.c $(HACK_H) ../include/func_tab.h \ ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winmisc.c winstat.o: ../win/X11/winstat.c $(HACK_H) ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winstat.c wintext.o: ../win/X11/wintext.c $(HACK_H) ../include/winX.h ../include/xwindow.h $(CC) $(CFLAGS) -c ../win/X11/wintext.c winval.o: ../win/X11/winval.c $(HACK_H) ../include/winX.h $(CC) $(CFLAGS) -c ../win/X11/winval.c tile.o: tile.c $(HACK_H) gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ ../win/gnome/gnmain.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnaskstr.c gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \ ../win/gnome/gnmenu.h ../win/gnome/gnaskstr.h \ ../win/gnome/gnyesno.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnbind.c gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h ../include/tile2x11.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnglyph.c gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \ ../include/date.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmain.c gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h $(HACK_H) $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmap.c gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \ ../win/gnome/gnbind.h ../include/func_tab.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmenu.c gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnmesg.c gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnopts.c gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ ../win/gnome/gnmain.h $(HACK_H) $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnplayer.c gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ ../win/gnome/gnmain.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnsignal.c gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \ ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \ ../win/gnome/gnomeprv.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnstatus.c gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \ ../win/gnome/gn_rip.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gntext.c gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnyesno.c gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h $(CC) $(CFLAGS) $(GNOMEINC) -c ../win/gnome/gnworn.c wingem.o: ../win/gem/wingem.c $(HACK_H) ../include/func_tab.h ../include/dlb.h \ ../include/patchlevel.h ../include/wingem.h $(CC) $(CFLAGS) -c ../win/gem/wingem.c wingem1.o: ../win/gem/wingem1.c ../include/gem_rsc.h ../include/load_img.h \ ../include/gr_rect.h ../include/wintype.h ../include/wingem.h $(CC) $(CFLAGS) -c ../win/gem/wingem1.c load_img.o: ../win/gem/load_img.c ../include/load_img.h $(CC) $(CFLAGS) -c ../win/gem/load_img.c gr_rect.o: ../win/gem/gr_rect.c ../include/gr_rect.h $(CC) $(CFLAGS) -c ../win/gem/gr_rect.c tile.o: tile.c $(HACK_H) qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) ../include/func_tab.h \ ../include/dlb.h ../include/patchlevel.h ../include/tile2x11.h \ ../include/qt_win.h ../include/qt_clust.h ../include/qt_kde0.h \ ../include/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -c ../win/Qt/qt_win.cpp qt_clust.o: ../win/Qt/qt_clust.cpp ../include/qt_clust.h $(CXX) $(CXXFLAGS) -c ../win/Qt/qt_clust.cpp qttableview.o: ../win/Qt/qttableview.cpp ../include/qttableview.h $(CXX) $(CXXFLAGS) -c ../win/Qt/qttableview.cpp monstr.o: monstr.c $(CONFIG_H) vis_tab.o: vis_tab.c $(CONFIG_H) ../include/vis_tab.h allmain.o: allmain.c $(HACK_H) alloc.o: alloc.c $(CONFIG_H) apply.o: apply.c $(HACK_H) ../include/edog.h artifact.o: artifact.c $(HACK_H) ../include/artifact.h ../include/artilist.h attrib.o: attrib.c $(HACK_H) ball.o: ball.c $(HACK_H) bones.o: bones.c $(HACK_H) ../include/lev.h botl.o: botl.c $(HACK_H) cmd.o: cmd.c $(HACK_H) ../include/func_tab.h dbridge.o: dbridge.c $(HACK_H) decl.o: decl.c $(HACK_H) detect.o: detect.c $(HACK_H) ../include/artifact.h dig.o: dig.c $(HACK_H) ../include/edog.h display.o: display.c $(HACK_H) dlb.o: dlb.c $(CONFIG_H) ../include/dlb.h do.o: do.c $(HACK_H) ../include/lev.h do_name.o: do_name.c $(HACK_H) do_wear.o: do_wear.c $(HACK_H) dog.o: dog.c $(HACK_H) ../include/edog.h dogmove.o: dogmove.c $(HACK_H) ../include/mfndpos.h ../include/edog.h dokick.o: dokick.c $(HACK_H) ../include/eshk.h dothrow.o: dothrow.c $(HACK_H) ../include/edog.h drawing.o: drawing.c $(HACK_H) ../include/tcap.h dungeon.o: dungeon.c $(HACK_H) ../include/dgn_file.h ../include/dlb.h eat.o: eat.c $(HACK_H) end.o: end.c $(HACK_H) ../include/eshk.h ../include/dlb.h engrave.o: engrave.c $(HACK_H) ../include/lev.h exper.o: exper.c $(HACK_H) explode.o: explode.c $(HACK_H) extralev.o: extralev.c $(HACK_H) files.o: files.c $(HACK_H) ../include/dlb.h fountain.o: fountain.c $(HACK_H) hack.o: hack.c $(HACK_H) hacklib.o: hacklib.c $(HACK_H) invent.o: invent.c $(HACK_H) light.o: light.c $(HACK_H) ../include/lev.h lock.o: lock.c $(HACK_H) mail.o: mail.c $(HACK_H) ../include/mail.h makemon.o: makemon.c $(HACK_H) ../include/epri.h ../include/emin.h \ ../include/edog.h mapglyph.o: mapglyph.c $(HACK_H) mcastu.o: mcastu.c $(HACK_H) mhitm.o: mhitm.c $(HACK_H) ../include/artifact.h ../include/edog.h mhitu.o: mhitu.c $(HACK_H) ../include/artifact.h ../include/edog.h minion.o: minion.c $(HACK_H) ../include/emin.h ../include/epri.h mklev.o: mklev.c $(HACK_H) mkmap.o: mkmap.c $(HACK_H) ../include/sp_lev.h mkmaze.o: mkmaze.c $(HACK_H) ../include/sp_lev.h ../include/lev.h mkobj.o: mkobj.c $(HACK_H) mkroom.o: mkroom.c $(HACK_H) mon.o: mon.c $(HACK_H) ../include/mfndpos.h ../include/edog.h mondata.o: mondata.c $(HACK_H) ../include/eshk.h ../include/epri.h monmove.o: monmove.c $(HACK_H) ../include/mfndpos.h ../include/artifact.h \ ../include/epri.h monst.o: monst.c $(CONFIG_H) ../include/permonst.h ../include/align.h \ ../include/monattk.h ../include/monflag.h ../include/monsym.h \ ../include/dungeon.h ../include/eshk.h ../include/vault.h \ ../include/epri.h ../include/color.h mplayer.o: mplayer.c $(HACK_H) mthrowu.o: mthrowu.c $(HACK_H) muse.o: muse.c $(HACK_H) ../include/edog.h music.o: music.c $(HACK_H) #interp.c o_init.o: o_init.c $(HACK_H) ../include/lev.h objects.o: objects.c $(CONFIG_H) ../include/obj.h ../include/objclass.h \ ../include/prop.h ../include/skills.h ../include/color.h objnam.o: objnam.c $(HACK_H) options.o: options.c $(CONFIG_H) ../include/objclass.h ../include/flag.h \ $(HACK_H) ../include/tcap.h pager.o: pager.c $(HACK_H) ../include/dlb.h pickup.o: pickup.c $(HACK_H) pline.o: pline.c $(HACK_H) ../include/epri.h ../include/edog.h polyself.o: polyself.c $(HACK_H) potion.o: potion.c $(HACK_H) pray.o: pray.c $(HACK_H) ../include/epri.h priest.o: priest.c $(HACK_H) ../include/mfndpos.h ../include/eshk.h \ ../include/epri.h ../include/emin.h quest.o: quest.c $(HACK_H) ../include/qtext.h questpgr.o: questpgr.c $(HACK_H) ../include/dlb.h ../include/qtext.h read.o: read.c $(HACK_H) rect.o: rect.c $(HACK_H) region.o: region.c $(HACK_H) ../include/lev.h restore.o: restore.c $(HACK_H) ../include/lev.h ../include/tcap.h rip.o: rip.c $(HACK_H) rnd.o: rnd.c $(HACK_H) role.o: role.c $(HACK_H) rumors.o: rumors.c $(HACK_H) ../include/lev.h ../include/dlb.h save.o: save.c $(HACK_H) ../include/lev.h shk.o: shk.c $(HACK_H) ../include/eshk.h shknam.o: shknam.c $(HACK_H) ../include/eshk.h sit.o: sit.c $(HACK_H) ../include/artifact.h sounds.o: sounds.c $(HACK_H) ../include/edog.h sp_lev.o: sp_lev.c $(HACK_H) ../include/dlb.h ../include/sp_lev.h spell.o: spell.c $(HACK_H) steal.o: steal.c $(HACK_H) steed.o: steed.c $(HACK_H) teleport.o: teleport.c $(HACK_H) timeout.o: timeout.c $(HACK_H) ../include/lev.h topten.o: topten.c $(HACK_H) ../include/dlb.h ../include/patchlevel.h track.o: track.c $(HACK_H) trap.o: trap.c $(HACK_H) u_init.o: u_init.c $(HACK_H) uhitm.o: uhitm.c $(HACK_H) vault.o: vault.c $(HACK_H) ../include/vault.h version.o: version.c $(HACK_H) ../include/date.h ../include/patchlevel.h vision.o: vision.c $(HACK_H) ../include/vis_tab.h weapon.o: weapon.c $(HACK_H) were.o: were.c $(HACK_H) wield.o: wield.c $(HACK_H) windows.o: windows.c $(HACK_H) ../include/wingem.h ../include/winGnome.h wizard.o: wizard.c $(HACK_H) ../include/qtext.h ../include/epri.h worm.o: worm.c $(HACK_H) ../include/lev.h worn.o: worn.c $(HACK_H) write.o: write.c $(HACK_H) zap.o: zap.c $(HACK_H) # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see make depend above nethack-3.4.3/sys/unix/Makefile.top0100644000000000000000000001744307764735041015725 0ustar rootroot# NetHack Makefile. # SCCS Id: @(#)Makefile.top 3.4 1995/01/05 # newer makes predefine $(MAKE) to 'make' and do smarter processing of # recursive make calls if $(MAKE) is used # these makes allow $(MAKE) to be overridden by the environment if someone # wants to (or has to) use something other than the standard make, so we do # not want to unconditionally set $(MAKE) here # # unfortunately, some older makes do not predefine $(MAKE); if you have one of # these, uncomment the following line # (you will know that you have one if you get complaints about unable to # execute things like 'data' and 'rumors') # MAKE = make # make NetHack PREFIX = /usr GAME = nethack # GAME = nethack.prg GAMEUID = games GAMEGRP = bin # Permissions - some places use setgid instead of setuid, for instance # See also the option "SECURE" in include/config.h GAMEPERM = 04755 FILEPERM = 0644 EXEPERM = 0755 DIRPERM = 0755 # GAMEDIR also appears in config.h as "HACKDIR". # VARDIR may also appear in unixconf.h as "VAR_PLAYGROUND" else GAMEDIR # # note that 'make install' believes in creating a nice tidy GAMEDIR for # installation, free of debris from previous NetHack versions -- # therefore there should not be anything in GAMEDIR that you want to keep # (if there is, you'll have to do the installation by hand or modify the # instructions) GAMEDIR = $(PREFIX)/games/lib/$(GAME)dir VARDIR = $(GAMEDIR) SHELLDIR = $(PREFIX)/games # per discussion in Install.X11 and Install.Qt VARDATND = # VARDATND = x11tiles NetHack.ad pet_mark.xbm # VARDATND = x11tiles NetHack.ad pet_mark.xbm rip.xpm # for Atari/Gem # VARDATND = nh16.img title.img GEM_RSC.RSC rip.img # for BeOS # VARDATND = beostiles # for Gnome # VARDATND = x11tiles pet_mark.xbm rip.xpm mapbg.xpm VARDATD = data oracles options quest.dat rumors VARDAT = $(VARDATD) $(VARDATND) # Some versions of make use the SHELL environment variable as the shell # for running commands. We need this to be a Bourne shell. # SHELL = /bin/sh # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP # Commands for setting the owner and group on files during installation. # Some systems fail with one or the other when installing over NFS or for # other permission-related reasons. If that happens, you may want to set the # command to "true", which is a no-op. Note that disabling chown or chgrp # will only work if setuid (or setgid) behavior is not desired or required. CHOWN = chown CHGRP = chgrp # # end of configuration # DATHELP = help hh cmdhelp history opthelp wizhelp SPEC_LEVS = asmodeus.lev baalz.lev bigrm-?.lev castle.lev fakewiz?.lev \ juiblex.lev knox.lev medusa-?.lev minend-?.lev minefill.lev \ minetn-?.lev oracle.lev orcus.lev sanctum.lev soko?-?.lev \ tower?.lev valley.lev wizard?.lev \ astral.lev air.lev earth.lev fire.lev water.lev QUEST_LEVS = ???-goal.lev ???-fil?.lev ???-loca.lev ???-strt.lev DATNODLB = $(VARDATND) license DATDLB = $(DATHELP) dungeon $(SPEC_LEVS) $(QUEST_LEVS) $(VARDATD) DAT = $(DATNODLB) $(DATDLB) $(GAME): ( cd src ; $(MAKE) ) all: $(GAME) recover Guidebook $(VARDAT) dungeon spec_levs check-dlb @echo "Done." # Note: many of the dependencies below are here to allow parallel make # to generate valid output Guidebook: ( cd doc ; $(MAKE) Guidebook ) manpages: ( cd doc ; $(MAKE) manpages ) data: $(GAME) ( cd dat ; $(MAKE) data ) rumors: $(GAME) ( cd dat ; $(MAKE) rumors ) oracles: $(GAME) ( cd dat ; $(MAKE) oracles ) # Note: options should have already been made with make, but... options: $(GAME) ( cd dat ; $(MAKE) options ) quest.dat: $(GAME) ( cd dat ; $(MAKE) quest.dat ) spec_levs: dungeon ( cd util ; $(MAKE) lev_comp ) ( cd dat ; $(MAKE) spec_levs ) ( cd dat ; $(MAKE) quest_levs ) dungeon: $(GAME) ( cd util ; $(MAKE) dgn_comp ) ( cd dat ; $(MAKE) dungeon ) nhtiles.bmp: $(GAME) ( cd dat ; $(MAKE) nhtiles.bmp ) x11tiles: $(GAME) ( cd util ; $(MAKE) tile2x11 ) ( cd dat ; $(MAKE) x11tiles ) beostiles: $(GAME) ( cd util ; $(MAKE) tile2beos ) ( cd dat ; $(MAKE) beostiles ) NetHack.ad: $(GAME) ( cd dat ; $(MAKE) NetHack.ad ) pet_mark.xbm: ( cd dat ; $(MAKE) pet_mark.xbm ) rip.xpm: ( cd dat ; $(MAKE) rip.xpm ) mapbg.xpm: (cd dat ; $(MAKE) mapbg.xpm ) nhsplash.xpm: ( cd dat ; $(MAKE) nhsplash.xpm ) nh16.img: $(GAME) ( cd util ; $(MAKE) tile2img.ttp ) ( cd dat ; $(MAKE) nh16.img ) rip.img: ( cd util ; $(MAKE) xpm2img.ttp ) ( cd dat ; $(MAKE) rip.img ) GEM_RSC.RSC: ( cd dat ; $(MAKE) GEM_RSC.RSC ) title.img: ( cd dat ; $(MAKE) title.img ) check-dlb: options @if egrep -s librarian dat/options ; then $(MAKE) dlb ; else true ; fi dlb: ( cd util ; $(MAKE) dlb ) ( cd dat ; ../util/dlb cf nhdat $(DATDLB) ) # recover can be used when INSURANCE is defined in include/config.h # and the checkpoint option is true recover: $(GAME) ( cd util ; $(MAKE) recover ) dofiles: target=`sed -n \ -e '/librarian/{' \ -e 's/.*/dlb/p' \ -e 'q' \ -e '}' \ -e '$$s/.*/nodlb/p' < dat/options` ; \ $(MAKE) dofiles-$${target-nodlb} cp src/$(GAME) $(GAMEDIR) cp util/recover $(GAMEDIR) -rm -f $(SHELLDIR)/$(GAME) sed -e 's;/usr/games/lib/nethackdir;$(GAMEDIR);' \ -e 's;HACKDIR/nethack;HACKDIR/$(GAME);' \ < sys/unix/nethack.sh \ > $(SHELLDIR)/$(GAME) # set up their permissions -( cd $(GAMEDIR) ; $(CHOWN) $(GAMEUID) $(GAME) recover ; \ $(CHGRP) $(GAMEGRP) $(GAME) recover ) chmod $(GAMEPERM) $(GAMEDIR)/$(GAME) chmod $(EXEPERM) $(GAMEDIR)/recover -$(CHOWN) $(GAMEUID) $(SHELLDIR)/$(GAME) $(CHGRP) $(GAMEGRP) $(SHELLDIR)/$(GAME) chmod $(EXEPERM) $(SHELLDIR)/$(GAME) dofiles-dlb: check-dlb ( cd dat ; cp nhdat $(DATNODLB) $(GAMEDIR) ) # set up their permissions -( cd $(GAMEDIR) ; $(CHOWN) $(GAMEUID) nhdat $(DATNODLB) ; \ $(CHGRP) $(GAMEGRP) nhdat $(DATNODLB) ; \ chmod $(FILEPERM) nhdat $(DATNODLB) ) dofiles-nodlb: # copy over the game files ( cd dat ; cp $(DAT) $(GAMEDIR) ) # set up their permissions -( cd $(GAMEDIR) ; $(CHOWN) $(GAMEUID) $(DAT) ; \ $(CHGRP) $(GAMEGRP) $(DAT) ; \ chmod $(FILEPERM) $(DAT) ) update: $(GAME) recover $(VARDAT) dungeon spec_levs # (don't yank the old version out from under people who're playing it) -mv $(GAMEDIR)/$(GAME) $(GAMEDIR)/$(GAME).old # quest.dat is also kept open and has the same problems over NFS # (quest.dat may be inside nhdat if dlb is in use) -mv $(GAMEDIR)/quest.dat $(GAMEDIR)/quest.dat.old -mv $(GAMEDIR)/nhdat $(GAMEDIR)/nhdat.old # set up new versions of the game files ( $(MAKE) dofiles ) # touch time-sensitive files -touch -c $(VARDIR)/bones* $(VARDIR)/?lock* $(VARDIR)/wizard* -touch -c $(VARDIR)/save/* touch $(VARDIR)/perm $(VARDIR)/record # and a reminder @echo You may also want to install the man pages via the doc Makefile. install: $(GAME) recover $(VARDAT) dungeon spec_levs # set up the directories # not all mkdirs have -p; those that don't will create a -p directory -mkdir -p $(SHELLDIR) -rm -rf $(GAMEDIR) $(VARDIR) -mkdir -p $(GAMEDIR) $(VARDIR) $(VARDIR)/save -rmdir ./-p -$(CHOWN) $(GAMEUID) $(GAMEDIR) $(VARDIR) $(VARDIR)/save $(CHGRP) $(GAMEGRP) $(GAMEDIR) $(VARDIR) $(VARDIR)/save chmod $(DIRPERM) $(GAMEDIR) $(VARDIR) $(VARDIR)/save # set up the game files ( $(MAKE) dofiles ) # set up some additional files touch $(VARDIR)/perm $(VARDIR)/record $(VARDIR)/logfile -( cd $(VARDIR) ; $(CHOWN) $(GAMEUID) perm record logfile ; \ $(CHGRP) $(GAMEGRP) perm record logfile ; \ chmod $(FILEPERM) perm record logfile ) # and a reminder @echo You may also want to reinstall the man pages via the doc Makefile. # 'make clean' removes all the .o files, but leaves around all the executables # and compiled data files clean: ( cd src ; $(MAKE) clean ) ( cd util ; $(MAKE) clean ) # 'make spotless' returns the source tree to near-distribution condition. # it removes .o files, executables, and compiled data files spotless: ( cd src ; $(MAKE) spotless ) ( cd util ; $(MAKE) spotless ) ( cd dat ; $(MAKE) spotless ) ( cd doc ; $(MAKE) spotless ) nethack-3.4.3/sys/unix/Makefile.utl0100644000000000000000000003062007764735041015717 0ustar rootroot# Makefile for NetHack's utility programs. # SCCS Id: @(#)Makefile.utl 3.4 1997/04/19 # newer makes predefine $(MAKE) to 'make' and do smarter processing of # recursive make calls if $(MAKE) is used # these makes allow $(MAKE) to be overridden by the environment if someone # wants to (or has to) use something other than the standard make, so we do # not want to unconditionally set $(MAKE) here # # unfortunately, some older makes do not predefine $(MAKE); if you have one of # these, uncomment the following line # (you will know that you have one if you get complaints about unable to # execute things like 'foo.o') # MAKE = make # if you are using gcc as your compiler, # uncomment the CC definition below if it's not in your environment # CC = gcc # # For Bull DPX/2 systems at B.O.S. 2.0 or higher use the following: # # CC = gcc -ansi -D_BULL_SOURCE -D_XOPEN_SOURCE -D_POSIX_SOURCE # # If you are using GCC 2.2.2 or higher on a DPX/2, just use: # # CC = gcc -ansi # # For HP/UX 10.20 with GCC: # CC = gcc -D_POSIX_SOURCE # # if your make doesn't define a default SHELL properly, you may need # the line below (Atari users will need a bourne work-alike) # SHELL = /bin/sh # for Atari # SHELL=E:/GEMINI2/MUPFEL.TTP # flags may have to be changed as required # flags for 286 Xenix: # CFLAGS = -Ml2t16 -O -LARGE -I../include # LFLAGS = -Ml -F 4000 -SEG 512 # flags for 286 Microport SysV-AT # CFLAGS = -DDUMB -Ml -I../include # LFLAGS = -Ml # flags for Atari GCC (3.2.1) # CFLAGS = -O -I../include # LFLAGS = -s # flags for Atari GCC (3.3) # CFLAGS = -mshort -O2 -I../include # LFLAGS = -mshort -s # flags for Apollos using their native cc # (as long as it claims to be __STDC__ but isn't) # CFLAGS = -DAPOLLO -O -I../include # flags for AIX 3.1 cc on IBM RS/6000 to define # a suitable subset of standard libraries # (note that there is more info regarding the "-qchars=signed" # switch in file Install.unx note 8) # CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -O -I../include -qchars=signed # and for AIX 3.2: # CFLAGS = -D_NO_PROTO -D_XOPEN_SOURCE -D_ALL_SOURCE -O -I../include -qchars=signed # flags for A/UX 2.01 using native cc or c89 # gcc predefines AUX so that's not needed there # CFLAGS = -ZS -D_POSIX_SOURCE -O -I../include -DAUX # flags for IRIX 4.0.x using native cc # SGI cc 3.10 will fail to compile makedefs with -O # CFLAGS = -I../include -D__STDC__ -woff 100,293 # flags for Linux # compile normally # CFLAGS = -O2 -fomit-frame-pointer -I../include # LFLAGS = -L/usr/X11R6/lib # OR compile backwards compatible a.out format # CFLAGS = -O2 -b i486-linuxaout -fomit-frame-pointer -I../include # LFLAGS = -b i486-linuxaout -L/usr/X11R6/lib # flags for BeOS using the command line # remember to uncomment flex and bison below # BeOS on a Mac/BeBox: #CC = mwcc #CFLAGS = -I../include # BeOS on Intel: # the default values are fine # flags for debugging: # CFLAGS = -g -I../include CFLAGS = -O -I../include LFLAGS = LIBS = # If you are cross-compiling, you must use this: #OBJDIR = . # otherwise, you can save a little bit of disk space with this: OBJDIR = ../src # yacc/lex programs to use to generate *_comp.h, *_lex.c, and *_yacc.c. # if, instead of yacc/lex you have bison/flex, comment/uncomment the following. YACC = yacc LEX = lex # YACC = bison -y # YACC = byacc # LEX = flex # these are the names of the output files from YACC/LEX. Under MS-DOS # and similar systems, they may differ YTABC = y.tab.c YTABH = y.tab.h LEXYYC = lex.yy.c # YTABC = y_tab.c # YTABH = y_tab.h # LEXYYC = lexyy.c # ---------------------------------------- # # Nothing below this line should have to be changed. # timestamps for primary header files, matching src/Makefile CONFIG_H = ../src/config.h-t HACK_H = ../src/hack.h-t # utility .c files MAKESRC = makedefs.c SPLEVSRC = lev_yacc.c lev_lex.c lev_main.c DGNCOMPSRC = dgn_yacc.c dgn_lex.c dgn_main.c RECOVSRC = recover.c DLBSRC = dlb_main.c UTILSRCS = $(MAKESRC) panic.c $(SPLEVSRC) $(DGNCOMPSRC) $(RECOVSRC) $(DLBSRC) # files that define all monsters and objects CMONOBJ = ../src/monst.c ../src/objects.c OMONOBJ = $(OBJDIR)/monst.o $(OBJDIR)/objects.o # files that provide access to NetHack's names CNAMING = ../src/drawing.c ../src/decl.c $(CMONOBJ) ONAMING = $(OBJDIR)/drawing.o $(OBJDIR)/decl.o $(OMONOBJ) # dynamic memory allocation CALLOC = ../src/alloc.c panic.c OALLOC = $(OBJDIR)/alloc.o panic.o # object files for makedefs MAKEOBJS = makedefs.o $(OMONOBJ) # object files for special levels compiler SPLEVOBJS = lev_yacc.o lev_lex.o lev_main.o $(OALLOC) $(ONAMING) # object files for dungeon compiler DGNCOMPOBJS = dgn_yacc.o dgn_lex.o dgn_main.o $(OALLOC) # object files for recovery utility RECOVOBJS = recover.o # object files for the data librarian DLBOBJS = dlb_main.o $(OBJDIR)/dlb.o $(OALLOC) # flags for creating distribution versions of sys/share/*_lex.c, using # a more portable flex skeleton, which is not included in the distribution. # hopefully keeping this out of the section to be edited will keep too # many people from being confused by it... # FLEXDIST = -L -S../sys/share/flexhack.skl FLEXDIST = # # flags for creating distribution versions of sys/share/*_yacc.c, without # line numbers so patches from version to version are practical # YACCDIST = -l YACCDIST = # dependencies for makedefs # makedefs: $(MAKEOBJS) $(CC) $(LFLAGS) -o makedefs $(MAKEOBJS) makedefs.o: makedefs.c $(CONFIG_H) ../include/permonst.h \ ../include/objclass.h ../include/monsym.h \ ../include/artilist.h ../include/dungeon.h ../include/obj.h \ ../include/monst.h ../include/you.h ../include/flag.h \ ../include/dlb.h ../include/patchlevel.h ../include/qtext.h ../include/onames.h: makedefs ./makedefs -o ../include/pm.h: makedefs ./makedefs -p ../src/monstr.c: makedefs ./makedefs -m ../include/vis_tab.h: makedefs ./makedefs -z # makedefs -z makes both vis_tab.h and vis_tab.c, but writes the .h first ../src/vis_tab.c: ../include/vis_tab.h lintdefs: @lint -axbh -I../include -DLINT $(MAKESRC) $(CMONOBJ) | sed '/_flsbuf/d' # we defer this makedefs call to the src Makefile, since it knows all about # the main src and include files date.h is a timestamp for ../include/date.h:: @( cd ../src ; $(MAKE) ../include/date.h ) # support code used by several of the utility programs (but not makedefs) panic.o: panic.c $(CONFIG_H) # dependencies for lev_comp # lev_comp: $(SPLEVOBJS) $(CC) $(LFLAGS) -o lev_comp $(SPLEVOBJS) $(LIBS) lev_yacc.o: lev_yacc.c $(HACK_H) ../include/sp_lev.h lev_main.o: lev_main.c $(HACK_H) ../include/sp_lev.h ../include/tcap.h \ ../include/date.h # see lev_comp.l for WEIRD_LEX discussion # egrep will return failure if it doesn't find anything, but we know there # is one "_cplusplus" inside a comment lev_lex.o: lev_lex.c $(HACK_H) ../include/lev_comp.h ../include/sp_lev.h @echo $(CC) -c $(CFLAGS) lev_lex.c @$(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus lev_lex.c` lev_lex.c ../include/lev_comp.h: lev_yacc.c lev_yacc.c: lev_comp.y $(YACC) $(YACCDIST) -d lev_comp.y mv $(YTABC) lev_yacc.c mv $(YTABH) ../include/lev_comp.h lev_lex.c: lev_comp.l $(LEX) $(FLEXDIST) lev_comp.l mv $(LEXYYC) lev_lex.c # with all of extern.h's functions to complain about, we drown in # 'defined but not used' without -u lintlev: @lint -axhu -I../include -DLINT $(SPLEVSRC) $(CALLOC) $(CNAMING) | sed '/_flsbuf/d' # dependencies for dgn_comp # dgn_comp: $(DGNCOMPOBJS) $(CC) $(LFLAGS) -o dgn_comp $(DGNCOMPOBJS) $(LIBS) dgn_yacc.o: dgn_yacc.c $(CONFIG_H) ../include/dgn_file.h ../include/date.h dgn_main.o: dgn_main.c $(CONFIG_H) ../include/dlb.h # see dgn_comp.l for WEIRD_LEX discussion dgn_lex.o: dgn_lex.c $(CONFIG.H) ../include/dgn_comp.h ../include/dgn_file.h @echo $(CC) -c $(CFLAGS) dgn_lex.c @$(CC) -c $(CFLAGS) -DWEIRD_LEX=`egrep -c _cplusplus dgn_lex.c` dgn_lex.c ../include/dgn_comp.h: dgn_yacc.c dgn_yacc.c: dgn_comp.y $(YACC) $(YACCDIST) -d dgn_comp.y mv $(YTABC) dgn_yacc.c mv $(YTABH) ../include/dgn_comp.h dgn_lex.c: dgn_comp.l $(LEX) $(FLEXDIST) dgn_comp.l mv $(LEXYYC) dgn_lex.c # with all of extern.h's functions to complain about, we drown in # 'defined but not used' without -u lintdgn: @lint -axhu -I../include -DLINT $(DGNCOMPSRC) $(CALLOC) | sed '/_flsbuf/d' # dependencies for recover # recover: $(RECOVOBJS) $(CC) $(LFLAGS) -o recover $(RECOVOBJS) $(LIBS) recover.o: recover.c $(CONFIG_H) ../include/date.h # dependencies for dlb # dlb: $(DLBOBJS) $(CC) $(LFLAGS) -o dlb $(DLBOBJS) $(LIBS) dlb_main.o: dlb_main.c $(CONFIG_H) ../include/dlb.h ../include/date.h $(CC) $(CFLAGS) -c dlb_main.c # dependencies for tile utilities # TEXT_IO = tiletext.o tiletxt.o $(ONAMING) GIFREADERS = gifread.o $(OALLOC) PPMWRITERS = ppmwrite.o $(OALLOC) tileutils: tilemap gif2txt txt2ppm tile2x11 gif2txt: $(GIFREADERS) $(TEXT_IO) $(CC) $(LFLAGS) -o gif2txt $(GIFREADERS) $(TEXT_IO) $(LIBS) txt2ppm: $(PPMWRITERS) $(TEXT_IO) $(CC) $(LFLAGS) -o txt2ppm $(PPMWRITERS) $(TEXT_IO) $(LIBS) tile2x11: tile2x11.o $(TEXT_IO) $(CC) $(LFLAGS) -o tile2x11 tile2x11.o $(TEXT_IO) $(LIBS) tile2img.ttp: tile2img.o bitmfile.o $(TEXT_IO) $(CC) $(LFLAGS) -o tile2img.ttp tile2img.o bitmfile.o $(TEXT_IO) $(LIBS) tile2bmp: tile2bmp.o $(TEXT_IO) $(CC) $(LFLAGS) -o tile2bmp tile2bmp.o $(TEXT_IO) xpm2img.ttp: xpm2img.o bitmfile.o $(CC) $(LFLAGS) -o xpm2img.ttp xpm2img.o bitmfile.o $(LIBS) tile2beos: tile2beos.o $(TEXT_IO) $(CC) $(LFLAGS) -o tile2beos tile2beos.o $(TEXT_IO) -lbe tilemap: ../win/share/tilemap.c $(HACK_H) $(CC) $(CFLAGS) $(LFLAGS) -o tilemap ../win/share/tilemap.c $(LIBS) ../src/tile.c: tilemap ./tilemap ../include/tile.h: ../win/share/tile.h cp ../win/share/tile.h ../include/tile.h tiletext.o: ../win/share/tiletext.c $(CONFIG_H) ../include/tile.h $(CC) $(CFLAGS) -c ../win/share/tiletext.c tiletxt.o: ../win/share/tilemap.c $(HACK_H) $(CC) $(CFLAGS) -c -DTILETEXT ../win/share/tilemap.c mv tilemap.o tiletxt.o gifread.o: ../win/share/gifread.c $(CONFIG_H) ../include/tile.h $(CC) $(CFLAGS) -c ../win/share/gifread.c ppmwrite.o: ../win/share/ppmwrite.c $(CONFIG_H) ../include/tile.h $(CC) $(CFLAGS) -c ../win/share/ppmwrite.c tile2bmp.o: ../win/share/tile2bmp.c $(HACK_H) ../include/tile.h $(CC) $(CFLAGS) -c ../win/share/tile2bmp.c tile2x11.o: ../win/X11/tile2x11.c $(HACK_H) ../include/tile.h \ ../include/tile2x11.h $(CC) $(CFLAGS) -c ../win/X11/tile2x11.c tile2img.o: ../win/gem/tile2img.c $(HACK_H) ../include/tile.h \ ../include/bitmfile.h $(CC) $(CFLAGS) -c ../win/gem/tile2img.c xpm2img.o: ../win/gem/xpm2img.c $(HACK_H) ../include/bitmfile.h $(CC) $(CFLAGS) -c ../win/gem/xpm2img.c bitmfile.o: ../win/gem/bitmfile.c ../include/bitmfile.h $(CC) $(CFLAGS) -c ../win/gem/bitmfile.c tile2beos.o: ../win/BeOS/tile2beos.cpp $(HACK_H) ../include/tile.h $(CXX) $(CFLAGS) -c ../win/BeOS/tile2beos.cpp # using dependencies like # ../src/foo:: # @( cd ../src ; $(MAKE) foo ) # would always force foo to be up-to-date according to the src Makefile # when it's needed here. unfortunately, some makes believe this syntax # means foo always changes, instead of foo should always be checked. # therefore, approximate via config.h dependencies, and hope that anybody # changing anything other than basic configuration also knows when not # to improvise things not in the instructions, like 'make makedefs' here # in util... # make sure object files from src are available when needed # $(OBJDIR)/alloc.o: ../src/alloc.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/alloc.c -o $@ $(OBJDIR)/drawing.o: ../src/drawing.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/drawing.c -o $@ $(OBJDIR)/decl.o: ../src/decl.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/decl.c -o $@ $(OBJDIR)/monst.o: ../src/monst.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/monst.c -o $@ $(OBJDIR)/objects.o: ../src/objects.c $(CONFIG_H) $(CC) $(CFLAGS) -c ../src/objects.c -o $@ $(OBJDIR)/dlb.o: ../src/dlb.c $(HACK_H) ../include/dlb.h $(CC) $(CFLAGS) -c ../src/dlb.c -o $@ # make sure hack.h dependencies get transitive information $(HACK_H): $(CONFIG_H) @( cd ../src ; $(MAKE) $(HACK_H) ) $(CONFIG_H): ../include/config.h @( cd ../src ; $(MAKE) $(CONFIG_H) ) tags: $(UTILSRCS) @ctags -tw $(UTILSRCS) clean: -rm -f *.o spotless: clean -rm -f lev_lex.c lev_yacc.c dgn_lex.c dgn_yacc.c -rm -f ../include/lev_comp.h ../include/dgn_comp.h -rm -f ../include/tile.h -rm -f makedefs lev_comp dgn_comp recover dlb -rm -f gif2txt txt2ppm tile2x11 tile2img.ttp xpm2img.ttp tilemap tileedit: tileedit.cpp $(TEXT_IO) $(QTDIR)/bin/moc -o tileedit.moc tileedit.h $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib tileedit.cpp $(TEXT_IO) -lqt nethack-3.4.3/sys/unix/README.linux0100644000000000000000000001016507764735041015474 0ustar rootrootNetHack 3.4.3 Linux Elf This README provides the instructions for using the official Linux binary, system platform requirements, as well as steps used to create that binary. The same steps can be used from the source distribution to create a similar binary. The official Linux binary has support for tty and X11 windowing systems, but not Qt. This means you will need to have X11 libraries installed on your system to run this binary, even in its tty flavor. The Linux binary package assumes that you have a user and a group named "games" on your system. If you do not, you can simplify installation by creating them first. Log in as or su to "root". Then, cd /, gunzip and untar the package, preserving permissions to put the NetHack files in /usr/games/nethack and /usr/games/lib/nethackdir. For example, if the package in in your home directory you might perform these steps. % su # cd / # tar xpvzf ~yourlogin/nethack-343-linux-X11.tgz If you have old record and logfile entries from a previous NetHack version, you might want to save copies before they get overwritten by the new empty files; old saved games and bones files from 3.4.x will work with 3.4.3. If you are installing from the RPM, there is no need to save the old record and logfile; they are automatically preserved. In addition to data files for running the game, you will find other useful things in /usr/games/lib/nethackdir (such as a copy of this README :-). The general documentation Guidebook.txt and the processed man pages nethack.txt and recover.txt should provide an introduction to the game. The sample config file called dot.nethackrc can be used by copying it to your home directory as .nethackrc and modifying it to your liking. If you are running X11 copy the nh10.pcf and ibm.pcf font files from /usr/games/lib/nethackdir to a X11 fonts directory (such as /usr/X11/lib/X11/fonts/misc) and run "mkfontdir", then restart X windows to load them. If you prefer to use the graphical tiles, add the following to your .Xdefaults or .Xresources file: NetHack.tile_file: x11tiles You may need to run "xrdb -merge $HOME/.Xdefaults" (or .Xresources) after doing this. The official Linux binary is set up to run setgid games, which allows multiple users on your system to play the game and prevents cheating by unprivileged users. The usual default for NetHack is setuid games, but this causes problems with accessing .nethackrc on distributions with restrictive default security on home directories and users who don't know the tradeoffs of various permission settings. If you have problems, send us some email. nethack-bugs@nethack.org Steps used to build this binary release, in addition to the basic instructions found in sys/unix/Install.unx. The step numbers below correspond to the step numbers in sys/unix/Install.unx. System: gcc-3.2, XFree86-libs-4.2.1, ncurses-5.2, glibc-2.3.2 (GLIBC_2.3) 3. Edit include/config.h and include/unixconf.h config.h: define X11_GRAPHICS window support. define USE_XPM support. define COMPRESS as /bin/gzip as that is where it seems to reside on newer Linux's. define COMPRESS_EXTENSION as ".gz" define DLB define AUTOPICKUP_EXCEPTIONS unixconf.h: define LINUX define TIMED_DELAY 6. Makefile.src: define modern, non-BSD Linux and linux options throughout CC = gcc LFLAGS = -L/usr/X11R6/lib WINSRC = $(WINTTYSRC) $(WINX11SRC) WINOBJ = $(WINTTYOBJ) $(WINX11OBJ) WINTTYLIB = /usr/lib/libncurses.a WINX11LIB = -lXaw -lXmu -lXext -lXt -lXpm -lX11 WINLIB = $(WINTTYLIB) $(WINX11LIB) Makefile.utl: define modern, non-BSD Linux and linux options throughout Use bison/flex instead of yacc/lex CC = gcc LFLAGS = -L/usr/X11R6/lib YACC = bison -y LEX = flex 7. Makefile.top: GAMEGRP = games GAMEPERM = 02755 FILEPERM = 0664 EXEPERM = 0755 DIRPERM = 0775 VARDATND = x11tiles NetHack.ad pet_mark.xbm rip.xpm make all; su; make install 9. Additional step: As discussed in win/X11/Install.X11, convert nh10.bdf and ibm.bdf to proper font files and place in font path. nethack-3.4.3/sys/unix/cpp1.shr0100644000000000000000000015262707764735041015051 0ustar rootroot# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # makefile.txt # readme.txt # cpp.mem # cpp.h # cppdef.h # cpp2.c # echo x - makefile.txt sed 's/^X//' >makefile.txt << 'END-of-makefile.txt' X# X# The redefinition of strchr() and strrchr() are needed for X# Ultrix-32, Unix 4.2 bsd (and maybe some other Unices). X# XBSDDEFINE = -Dstrchr=index -Dstrrchr=rindex X# X# On certain systems, such as Unix System III, you may need to define X# $(LINTFLAGS) in the make command line to set system-specific lint flags. X# X# This Makefile assumes cpp will replace the "standard" preprocessor. X# Delete the reference to -DLINE_PREFIX=\"\" if cpp is used stand-alone. X# LINEFIX is a sed script filter that reinserts #line -- used for testing X# if LINE_PREFIX is set to "". Note that we must stand on our heads to X# match the # and a line had better not begin with $. By the way, what X# we really want is X# LINEFIX = | sed "s/^#/#line/" X# XCPPDEFINE = -DLINE_PREFIX=\"\" XLINEFIX = | sed "s/^[^ !\"%-~]/&line/" X# X# Define OLD_PREPROCESSOR non-zero to make a preprocessor which is X# "as compatible as possible" with the standard Unix V7 or Ultrix X# preprocessors. This is needed to rebuild 4.2bsd, for example, as X# the preprocessor is used to modify assembler code, rather than C. X# This is not recommended for current development. OLD_PREPROCESSOR X# forces the following definitions: X# OK_DOLLAR FALSE $ is not allowed in variables X# OK_CONCAT FALSE # cannot concatenate tokens X# COMMENT_INVISIBLE TRUE old-style comment concatenation X# STRING_FORMAL TRUE old-style string expansion X# XOLDDEFINE = -DOLD_PREPROCESSOR=1 X# X# DEFINES collects all -D arguments for cc and lint: X# Change DEFINES = $(BSDDEFINE) $(CPPDEFINE) $(OLDDEFINE) X# for an old-style preprocessor. X# X# DEFINES = $(BSDDEFINE) $(CPPDEFINE) XDEFINES = $(CPPDEFINE) X XCFLAGS = -O $(DEFINES) X X# X# ** compile cpp X# XSRCS = cpp1.c cpp2.c cpp3.c cpp4.c cpp5.c cpp6.c XOBJS = cpp1.o cpp2.o cpp3.o cpp4.o cpp5.o cpp6.o Xcpp: $(OBJS) X $(CC) $(CFLAGS) $(OBJS) -o cpp X X# X# ** Test cpp by preprocessing itself, compiling the result, X# ** repeating the process and diff'ing the result. Note: this X# ** is not a good test of cpp, but a simple verification. X# ** The diff's should not report any changes. X# ** Note that a sed script may be executed for each compile X# Xtest: X cpp cpp1.c $(LINEFIX) >old.tmp1.c X cpp cpp2.c $(LINEFIX) >old.tmp2.c X cpp cpp3.c $(LINEFIX) >old.tmp3.c X cpp cpp4.c $(LINEFIX) >old.tmp4.c X cpp cpp5.c $(LINEFIX) >old.tmp5.c X cpp cpp6.c $(LINEFIX) >old.tmp6.c X $(CC) $(CFLAGS) old.tmp[123456].c X a.out cpp1.c >new.tmp1.c X a.out cpp2.c >new.tmp2.c X a.out cpp3.c >new.tmp3.c X a.out cpp4.c >new.tmp4.c X a.out cpp5.c >new.tmp5.c X a.out cpp6.c >new.tmp6.c X diff old.tmp1.c new.tmp1.c X diff old.tmp2.c new.tmp2.c X diff old.tmp3.c new.tmp3.c X diff old.tmp4.c new.tmp4.c X diff old.tmp5.c new.tmp5.c X diff old.tmp6.c new.tmp6.c X rm a.out old.tmp[123456].* new.tmp[123456].* X X# X# A somewhat more extensive test is provided by the "clock" X# program (which is not distributed). Substitute your favorite X# macro-rich program here. X# Xclock: clock.c cpp X cpp clock.c $(LINEFIX) >temp.cpp.c X cc temp.cpp.c -lcurses -ltermcap -o clock X rm temp.cpp.c X X# X# ** Lint the code X# X Xlint: $(SRCS) X lint $(LINTFLAGS) $(DEFINES) $(SRCS) X X# X# ** Remove unneeded files X# Xclean: X rm -f $(OBJS) cpp X X# X# ** Rebuild the archive files needed to distribute cpp X# ** Uses the Decus C archive utility. X# X Xarchc: archc.c X $(CC) $(CFLAGS) archc.c -o archc X Xarchx: archx.c X $(CC) $(CFLAGS) archx.c -o archx X Xarchive: archc X archc readme.txt cpp.mem archx.c archc.c cpp.rno makefile.txt \ X cpp*.h >cpp1.arc X archc cpp1.c cpp2.c cpp3.c >cpp2.arc X archc cpp4.c cpp5.c cpp6.c >cpp3.arc X X# X# Object module dependencies X# X Xcpp1.o : cpp1.c cpp.h cppdef.h X Xcpp2.o : cpp2.c cpp.h cppdef.h X Xcpp3.o : cpp3.c cpp.h cppdef.h X Xcpp4.o : cpp4.c cpp.h cppdef.h X Xcpp5.o : cpp5.c cpp.h cppdef.h X Xcpp6.o : cpp6.c cpp.h cppdef.h X X END-of-makefile.txt echo x - readme.txt sed 's/^X//' >readme.txt << 'END-of-readme.txt' X XDecus cpp is a public-domain implementation of the C preprocessor. XIt runs on VMS native (Vax C), VMS compatibilty mode (Decus C), XRSX-11M, RSTS/E, P/OS, and RT11, as well as on several varieties Xof Unix, including Ultrix. Decus cpp attempts to implement features Xin the Draft ANSI Standard for the C language. It should be noted, Xhowever, that this standard is under active development: the current Xdraft of the standard explicitly states that "readers are requested Xnot to specify or claim conformance to this draft." Thus readers Xand users of Decus cpp should not assume that it conforms to the Xdraft standard, or that it will conform to the actual C language Xstandard. X XThese notes describe how to extract the cpp source files, configure it Xfor your needs, and mention a few design decisions that may be of interest Xto maintainers. X X Installation X XBecause the primary development of cpp was not on Unix, it Xis distributed using the Decus C archive program (quite similar Xto the archiver published in Kernighan and Plauger's Software XTools). To extract the files from the net.sources distribution, Xsave this message as cpp1.arc and the other two distribution Xfiles as cpp2.arc and cpp3.arc. Then, using your favorite editor, Xlocate the archx.c program, just following the line beginning with X"-h- archx.c" -- the format of the distribution is just: X X -h- readme.txt X ... this file X -h- cpp.mem X ... description of cpp X -h- archx.c X ... archx.c program -- extracts archives X -h- archc.c X ... archc.c program -- creates archives X XCompile archx.c -- it shouldn't require any special editing. XThen run it as follows: X X archx *.arc X XYou do not need to remove mail headers from the saved messages. X XYou should then read through cppdef.h to make sure the HOST and XTARGET (and other implementation-specific) definitions are set Xcorrectly for your machine, editing them as needed. X XYou may then copy makefile.txt to Makefile, editing it as needed Xfor your particular system. On Unix, cpp should be compiled Xby make without further difficulty. On other operating systems, Xyou should compile the six source modules, linking them together. XNote that, on Decus C based systems, you must extend the default Xstack allocation. The Decus C build utility will create the Xappropriate command file. X X Support Notes X XThe USENET distribution kit was designed to keep all submissions around X50,000 bytes: X Xcpp1.arc: X readme.txt This file X cpp.mem Documentation page (see below) X archx.c Archive extraction program X archc.c Archive construction program X cpp.rno Source for cpp.mem (see below) X makefile.txt Unix makefile -- copy to Makefile X cpp.h Main header file (structure def's and globals) X cppdef.h Configuration file (host and target definitions) X Xcpp2.arc: X cpp1.c Mainline code, documentation master sources X cpp2.c most #control processing X cpp3.c filename stuff and command line parsing Xcpp3.arc: X cpp4.c #define processor X cpp5.c #if processor X cpp6.c Support code (symbol table and I/O routines) X XCpp intentionally does not rely on the presence of a full-scale Xmacro preprocessor, it does require the simple parameter substitution Xpreprocessor capabilities of Unix V6 and Decus C. If your C Xlanguage lacks full preprocessing, you should make sure "nomacargs" Xis #define'd in cpp.h. (This is done automatically by the Decus C Xcompiler.) X XThe documentation (manual page) for cpp is included as cpp.mem Xand cpp.rno. Cpp.rno is in Dec Runoff format, built by a Decus C Xutility (getrno) from original source which is embedded in cpp1.c. XTo my knowledge, there is no equivalent program that creates Xthe nroff source appropriate for Unix. X XI would be happy to receive fixes to any problems you encounter. XAs I do not maintain distribution kit base-levels, bare-bones Xdiff listings without sufficient context are not very useful. XIt is unlikely that I can find time to help you with other Xdifficulties. X X Acknowledgements X XI received a great deal of help from many people in debugging cpp. XAlan Feuer and Sam Kendall used "state of the art" run-time code Xcheckers to locate several errors. Ed Keiser found problems when Xcpp was used on machines with different int and pointer sizes. XDave Conroy helped with the initial debugging, while Arthur Olsen Xand George Rosenberg found (and solved) several problems in the Xfirst USENET release. X XMartin Minow Xdecvax!minow X END-of-readme.txt echo x - cpp.mem sed 's/^X//' >cpp.mem << 'END-of-cpp.mem' X X X X X 1.0 C Pre-Processor X X X X ******* X * cpp * X ******* X X X X NAME: cpp -- C Pre-Processor X X SYNOPSIS: X X cpp [-options] [infile [outfile]] X X DESCRIPTION: X X CPP reads a C source file, expands macros and include X files, and writes an input file for the C compiler. If X no file arguments are given, CPP reads from stdin and X writes to stdout. If one file argument is given, it X will define the input file, while two file arguments X define both input and output files. The file name "-" X is a synonym for stdin or stdout as appropriate. X X The following options are supported. Options may be X given in either case. X X -C If set, source-file comments are written X to the output file. This allows the X output of CPP to be used as the input to X a program, such as lint, that expects X commands embedded in specially-formatted X comments. X X -Dname=value Define the name as if the programmer X wrote X X #define name value X X at the start of the first file. If X "=value" is not given, a value of "1" X will be used. X X On non-unix systems, all alphabetic text X will be forced to upper-case. X X -E Always return "success" to the operating X system, even if errors were detected. X Note that some fatal errors, such as a X missing #include file, will terminate X CPP, returning "failure" even if the -E X option is given. X Page 2 X cpp C Pre-Processor X X X -Idirectory Add this directory to the list of X directories searched for #include "..." X and #include <...> commands. Note that X there is no space between the "-I" and X the directory string. More than one -I X command is permitted. On non-Unix X systems "directory" is forced to X upper-case. X X -N CPP normally predefines some symbols X defining the target computer and X operating system. If -N is specified, X no symbols will be predefined. If -N -N X is specified, the "always present" X symbols, __LINE__, __FILE__, and X __DATE__ are not defined. X X -Stext CPP normally assumes that the size of X the target computer's basic variable X types is the same as the size of these X types of the host computer. (This can X be overridden when CPP is compiled, X however.) The -S option allows dynamic X respecification of these values. "text" X is a string of numbers, separated by X commas, that specifies correct sizes. X The sizes must be specified in the exact X order: X X char short int long float double X X If you specify the option as "-S*text", X pointers to these types will be X specified. -S* takes one additional X argument for pointer to function (e.g. X int (*)()) X X For example, to specify sizes X appropriate for a PDP-11, you would X write: X X c s i l f d func X -S1,2,2,2,4,8, X -S*2,2,2,2,2,2,2 X X Note that all values must be specified. X X -Uname Undefine the name as if X X #undef name X X were given. On non-Unix systems, "name" X will be forced to upper-case. X Page 3 X cpp C Pre-Processor X X X -Xnumber Enable debugging code. If no value is X given, a value of 1 will be used. (For X maintenence of CPP only.) X X X PRE-DEFINED VARIABLES: X X When CPP begins processing, the following variables will X have been defined (unless the -N option is specified): X X Target computer (as appropriate): X X pdp11, vax, M68000 m68000 m68k X X Target operating system (as appropriate): X X rsx, rt11, vms, unix X X Target compiler (as appropriate): X X decus, vax11c X X The implementor may add definitions to this list. The X default definitions match the definition of the host X computer, operating system, and C compiler. X X The following are always available unless undefined (or X -N was specified twice): X X __FILE__ The input (or #include) file being X compiled (as a quoted string). X X __LINE__ The line number being compiled. X X __DATE__ The date and time of compilation as a X Unix ctime quoted string (the trailing X newline is removed). Thus, X X printf("Bug at line %s,", __LINE__); X printf(" source file %s", __FILE__); X printf(" compiled on %s", __DATE__); X X X DRAFT PROPOSED ANSI STANDARD CONSIDERATIONS: X X The current version of the Draft Proposed Standard X explicitly states that "readers are requested not to X specify or claim conformance to this draft." Readers and X users of Decus CPP should not assume that Decus CPP X conforms to the standard, or that it will conform to the X actual C Language Standard. X X When CPP is itself compiled, many features of the Draft X Proposed Standard that are incompatible with existing X Page 4 X cpp C Pre-Processor X X X preprocessors may be disabled. See the comments in X CPP's source for details. X X The latest version of the Draft Proposed Standard (as X reflected in Decus CPP) is dated November 12, 1984. X X Comments are removed from the input text. The comment X is replaced by a single space character. The -C option X preserves comments, writing them to the output file. X X The '$' character is considered to be a letter. This is X a permitted extension. X X The following new features of C are processed by CPP: X X #elif expression (#else #if) X '\xNNN' (Hexadecimal constant) X '\a' (Ascii BELL) X '\v' (Ascii Vertical Tab) X #if defined NAME 1 if defined, 0 if not X #if defined (NAME) 1 if defined, 0 if not X #if sizeof (basic type) X unary + X 123U, 123LU Unsigned ints and longs. X 12.3L Long double numbers X token#token Token concatenation X #include token Expands to filename X X The Draft Proposed Standard has extended C, adding a X constant string concatenation operator, where X X "foo" "bar" X X is regarded as the single string "foobar". (This does X not affect CPP's processing but does permit a limited X form of macro argument substitution into strings as will X be discussed.) X X The Standard Committee plans to add token concatenation X to #define command lines. One suggested implementation X is as follows: the sequence "Token1#Token2" is treated X as if the programmer wrote "Token1Token2". This could X be used as follows: X X #line 123 X #define ATLINE foo#__LINE__ X X ATLINE would be defined as foo123. X X Note that "Token2" must either have the format of an X identifier or be a string of digits. Thus, the string X X #define ATLINE foo#1x3 X Page 5 X cpp C Pre-Processor X X X generates two tokens: "foo1" and "x3". X X If the tokens T1 and T2 are concatenated into T3, this X implementation operates as follows: X X 1. Expand T1 if it is a macro. X 2. Expand T2 if it is a macro. X 3. Join the tokens, forming T3. X 4. Expand T3 if it is a macro. X X A macro formal parameter will be substituted into a X string or character constant if it is the only component X of that constant: X X #define VECSIZE 123 X #define vprint(name, size) \ X printf("name" "[" "size" "] = {\n") X ... vprint(vector, VECSIZE); X X expands (effectively) to X X vprint("vector[123] = {\n"); X X Note that this will be useful if your C compiler X supports the new string concatenation operation noted X above. As implemented here, if you write X X #define string(arg) "arg" X ... string("foo") ... X X This implementation generates "foo", rather than the X strictly correct ""foo"" (which will probably generate X an error message). This is, strictly speaking, an error X in CPP and may be removed from future releases. X X ERROR MESSAGES: X X Many. CPP prints warning or error messages if you try X to use multiple-byte character constants X (non-transportable) if you #undef a symbol that was not X defined, or if your program has potentially nested X comments. X X AUTHOR: X X Martin Minow X X BUGS: X X The #if expression processor uses signed integers only. X I.e, #if 0xFFFFu < 0 may be TRUE. X END-of-cpp.mem echo x - cpp.h sed 's/^X//' >cpp.h << 'END-of-cpp.h' X X/* X * I n t e r n a l D e f i n i t i o n s f o r C P P X * X * In general, definitions in this file should not be changed. X */ X X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif X#ifndef EOS X/* X * This is predefined in Decus C X */ X#define EOS '\0' /* End of string */ X#endif X#define EOF_CHAR 0 /* Returned by get() on eof */ X#define NULLST ((char *) NULL) /* Pointer to nowhere (linted) */ X#define DEF_NOARGS (-1) /* #define foo vs #define foo() */ X X/* X * The following may need to change if the host system doesn't use ASCII. X */ X#define DEF_MAGIC 0x1D /* Magic for #defines */ X#define TOK_SEP 0x1E /* Token concatenation delim. */ X#define COM_SEP 0x1F /* Magic comment separator */ X X/* X * Note -- in Ascii, the following will map macro formals onto DEL + the X * C1 control character region (decimal 128 .. (128 + PAR_MAC)) which will X * be ok as long as PAR_MAC is less than 33). Note that the last PAR_MAC X * value is reserved for string substitution. X */ X X#define MAC_PARM 0x7F /* Macro formals start here */ X#if PAR_MAC >= 33 X assertion fails -- PAR_MAC isn't less than 33 X#endif X#define LASTPARM (PAR_MAC - 1) X X/* X * Character type codes. X */ X X#define INV 0 /* Invalid, must be zero */ X#define OP_EOE INV /* End of expression */ X#define DIG 1 /* Digit */ X#define LET 2 /* Identifier start */ X#define FIRST_BINOP OP_ADD X#define OP_ADD 3 X#define OP_SUB 4 X#define OP_MUL 5 X#define OP_DIV 6 X#define OP_MOD 7 X#define OP_ASL 8 X#define OP_ASR 9 X#define OP_AND 10 /* &, not && */ X#define OP_OR 11 /* |, not || */ X#define OP_XOR 12 X#define OP_EQ 13 X#define OP_NE 14 X#define OP_LT 15 X#define OP_LE 16 X#define OP_GE 17 X#define OP_GT 18 X#define OP_ANA 19 /* && */ X#define OP_ORO 20 /* || */ X#define OP_QUE 21 /* ? */ X#define OP_COL 22 /* : */ X#define OP_CMA 23 /* , (relevant?) */ X#define LAST_BINOP OP_CMA /* Last binary operand */ X/* X * The following are unary. X */ X#define FIRST_UNOP OP_PLU /* First Unary operand */ X#define OP_PLU 24 /* + (draft ANSI standard) */ X#define OP_NEG 25 /* - */ X#define OP_COM 26 /* ~ */ X#define OP_NOT 27 /* ! */ X#define LAST_UNOP OP_NOT X#define OP_LPA 28 /* ( */ X#define OP_RPA 29 /* ) */ X#define OP_END 30 /* End of expression marker */ X#define OP_MAX (OP_END + 1) /* Number of operators */ X#define OP_FAIL (OP_END + 1) /* For error returns */ X X/* X * The following are for lexical scanning only. X */ X X#define QUO 65 /* Both flavors of quotation */ X#define DOT 66 /* . might start a number */ X#define SPA 67 /* Space and tab */ X#define BSH 68 /* Just a backslash */ X#define END 69 /* EOF */ X X/* X * These bits are set in ifstack[] X */ X#define WAS_COMPILING 1 /* TRUE if compile set at entry */ X#define ELSE_SEEN 2 /* TRUE when #else processed */ X#define TRUE_SEEN 4 /* TRUE when #if TRUE processed */ X X/* X * Define bits for the basic types and their adjectives X */ X X#define T_CHAR 1 X#define T_INT 2 X#define T_FLOAT 4 X#define T_DOUBLE 8 X#define T_SHORT 16 X#define T_LONG 32 X#define T_SIGNED 64 X#define T_UNSIGNED 128 X#define T_PTR 256 /* Pointer */ X#define T_FPTR 512 /* Pointer to functions */ X X/* X * The DEFBUF structure stores information about #defined X * macros. Note that the defbuf->repl information is always X * in malloc storage. X */ X Xtypedef struct defbuf { X struct defbuf *link; /* Next define in chain */ X char *repl; /* -> replacement */ X int hash; /* Symbol table hash */ X int nargs; /* For define(args) */ X char name[1]; /* #define name */ X} DEFBUF; X X/* X * The FILEINFO structure stores information about open files X * and macros being expanded. X */ X Xtypedef struct fileinfo { X char *bptr; /* Buffer pointer */ X int line; /* for include or macro */ X FILE *fp; /* File if non-null */ X struct fileinfo *parent; /* Link to includer */ X char *filename; /* File/macro name */ X char *progname; /* From #line statement */ X unsigned int unrecur; /* For macro recursion */ X char buffer[1]; /* current input line */ X} FILEINFO; X X/* X * The SIZES structure is used to store the values for #if sizeof X */ X Xtypedef struct sizes { X short bits; /* If this bit is set, */ X short size; /* this is the datum size value */ X short psize; /* this is the pointer size */ X} SIZES; X/* X * nomacarg is a built-in #define on Decus C. X */ X X#ifdef nomacarg X#define cput output /* cput concatenates tokens */ X#else X#if COMMENT_INVISIBLE X#define cput(c) { if (c != TOK_SEP && c != COM_SEP) putchar(c); } X#else X#define cput(c) { if (c != TOK_SEP) putchar(c); } X#endif X#endif X X#ifndef nomacarg X#define streq(s1, s2) (strcmp(s1, s2) == 0) X#endif X X/* X * Error codes. VMS uses system definitions. X * Decus C codes are defined in stdio.h. X * Others are cooked to order. X */ X X#if HOST == SYS_VMS X#include X#include X#define IO_NORMAL (SS$_NORMAL | STS$M_INHIB_MSG) X#define IO_ERROR SS$_ABORT X#endif X/* X * Note: IO_NORMAL and IO_ERROR are defined in the Decus C stdio.h file X */ X#ifndef IO_NORMAL X#define IO_NORMAL 0 X#endif X#ifndef IO_ERROR X#define IO_ERROR 1 X#endif X X/* X * Externs X */ X Xextern int line; /* Current line number */ Xextern int wrongline; /* Force #line to cc pass 1 */ Xextern char type[]; /* Character classifier */ Xextern char token[IDMAX + 1]; /* Current input token */ Xextern int instring; /* TRUE if scanning string */ Xextern int inmacro; /* TRUE if scanning #define */ Xextern int errors; /* Error counter */ Xextern int recursion; /* Macro depth counter */ Xextern char ifstack[BLK_NEST]; /* #if information */ X#define compiling ifstack[0] Xextern char *ifptr; /* -> current ifstack item */ Xextern char *incdir[NINCLUDE]; /* -i directories */ Xextern char **incend; /* -> active end of incdir */ Xextern int cflag; /* -C option (keep comments) */ Xextern int eflag; /* -E option (ignore errors) */ Xextern int nflag; /* -N option (no pre-defines) */ Xextern int rec_recover; /* unwind recursive macros */ Xextern char *preset[]; /* Standard predefined symbols */ Xextern char *magic[]; /* Magic predefined symbols */ Xextern FILEINFO *infile; /* Current input file */ Xextern char work[NWORK + 1]; /* #define scratch */ Xextern char *workp; /* Free space in work */ X#if DEBUG Xextern int debug; /* Debug level */ X#endif Xextern int keepcomments; /* Don't remove comments if set */ Xextern SIZES size_table[]; /* For #if sizeof sizes */ Xextern char *getmem(); /* Get memory or die. */ Xextern DEFBUF *lookid(); /* Look for a #define'd thing */ Xextern DEFBUF *defendel(); /* Symbol table enter/delete */ Xextern char *savestring(); /* Stuff string in malloc mem. */ Xextern char *strcpy(); Xextern char *strcat(); Xextern char *strrchr(); Xextern char *strchr(); Xextern long time(); X/* extern char *sprintf(); /* Lint needs this */ END-of-cpp.h echo x - cppdef.h sed 's/^X//' >cppdef.h << 'END-of-cppdef.h' X/* X * S y s t e m D e p e n d e n t X * D e f i n i t i o n s f o r C P P X * X * Definitions in this file may be edited to configure CPP for particular X * host operating systems and target configurations. X * X * NOTE: cpp assumes it is compiled by a compiler that supports macros X * with arguments. If this is not the case (as for Decus C), #define X * nomacarg -- and provide function equivalents for all macros. X * X * cpp also assumes the host and target implement the Ascii character set. X * If this is not the case, you will have to do some editing here and there. X */ X X/* X * This redundant definition of TRUE and FALSE works around X * a limitation of Decus C. X */ X#ifndef TRUE X#define TRUE 1 X#define FALSE 0 X#endif X X/* X * Define the HOST operating system. This is needed so that X * cpp can use appropriate filename conventions. X */ X#define SYS_UNKNOWN 0 X#define SYS_UNIX 1 X#define SYS_VMS 2 X#define SYS_RSX 3 X#define SYS_RT11 4 X#define SYS_LATTICE 5 X#define SYS_ONYX 6 X#define SYS_68000 7 X#define SYS_GCOS 8 X#define SYS_IBM 9 X#define SYS_OS 10 X#define SYS_TSS 11 X X#ifndef HOST X#ifdef unix X#define HOST SYS_UNIX X#else X#ifdef vms X#define HOST SYS_VMS X#else X#ifdef rsx X#define HOST SYS_RSX X#else X#ifdef rt11 X#define HOST SYS_RT11 X#else X#ifdef dmert X#define HOST SYS_DMERT X#else X#ifdef gcos X#define HOST SYS_GCOS X#else X#ifdef ibm X#define HOST SYS_IBM X#else X#ifdef os X#define HOST SYS_OS X#else X#ifdef tss X#define HOST SYS_TSS X#endif X#endif X#endif X#endif X#endif X#endif X#endif X#endif X#endif X X#ifndef HOST X#define HOST SYS_UNKNOWN X#endif X X/* X * We assume that the target is the same as the host system X */ X#ifndef TARGET X#define TARGET HOST X#endif X X/* X * In order to predefine machine-dependent constants, X * several strings are defined here: X * X * MACHINE defines the target cpu (by name) X * SYSTEM defines the target operating system X * COMPILER defines the target compiler X * X * The above may be #defined as "" if they are not wanted. X * They should not be #defined as NULL. X * X * LINE_PREFIX defines the # output line prefix, if not "line" X * This should be defined as "" if cpp is to replace X * the "standard" C pre-processor. X * X * FILE_LOCAL marks functions which are referenced only in the X * file they reside. Some C compilers allow these X * to be marked "static" even though they are referenced X * by "extern" statements elsewhere. X * X * OK_DOLLAR Should be set TRUE if $ is a valid alphabetic character X * in identifiers (default), or zero if $ is invalid. X * Default is TRUE. X * X * OK_CONCAT Should be set TRUE if # may be used to concatenate X * tokens in macros (per the Ansi Draft Standard) or X * FALSE for old-style # processing (needed if cpp is X * to process assembler source code). X * X * OK_DATE Predefines the compilation date if set TRUE. X * Not permitted by the Nov. 12, 1984 Draft Standard. X * X * S_CHAR etc. Define the sizeof the basic TARGET machine word types. X * By default, sizes are set to the values for the HOST X * computer. If this is inappropriate, see the code in X * cpp3.c for details on what to change. Also, if you X * have a machine where sizeof (signed int) differs from X * sizeof (unsigned int), you will have to edit code and X * tables in cpp3.c (and extend the -S option definition.) X * X * CPP_LIBRARY May be defined if you have a site-specific include directory X * which is to be searched *before* the operating-system X * specific directories. X */ X X#if TARGET == SYS_LATTICE X/* X * We assume the operating system is pcdos for the IBM-PC. X * We also assume the small model (just like the PDP-11) X */ X#define MACHINE "i8086" X#define SYSTEM "pcdos" X#endif X X#if TARGET == SYS_ONYX X#define MACHINE "z8000" X#define SYSTEM "unix" X#endif X X#if TARGET == SYS_VMS X#define MACHINE "vax" X#define SYSTEM "vms" X#define COMPILER "vax11c" X#endif X X#if TARGET == SYS_RSX X#define MACHINE "pdp11" X#define SYSTEM "rsx" X#define COMPILER "decus" X#endif X X#if TARGET == SYS_RT11 X#define MACHINE "pdp11" X#define SYSTEM "rt11" X#define COMPILER "decus" X#endif X X#if TARGET == SYS_68000 X/* X * All three machine designators have been seen in various systems. X * Warning -- compilers differ as to sizeof (int). cpp3 assumes that X * sizeof (int) == 2 X */ X#define MACHINE "M68000", "m68000", "m68k" X#define SYSTEM "unix" X#endif X X#if TARGET == SYS_UNIX X#define SYSTEM "unix" X#ifdef pdp11 X#define MACHINE "pdp11" X#endif X#ifdef vax X#define MACHINE "vax" X#endif X#ifdef u370 X#define MACHINE "u370" X#endif X#ifdef interdata X#define MACHINE "interdata" X#endif X#ifdef u3b X#define MACHINE "u3b" X#endif X#ifdef u3b5 X#define MACHINE "u3b5" X#endif X#ifdef u3b2 X#define MACHINE "u3b2" X#endif X#ifdef u3b20d X#define MACHINE "u3b20d" X#endif X#endif X#endif X X/* X * defaults X */ X X#ifndef MSG_PREFIX X#define MSG_PREFIX "cpp: " X#endif X X#ifndef LINE_PREFIX X#ifdef decus X#define LINE_PREFIX "" X#else X#define LINE_PREFIX "line" X#endif X#endif X X/* X * OLD_PREPROCESSOR forces the definition of OK_DOLLAR, OK_CONCAT, X * COMMENT_INVISIBLE, and STRING_FORMAL to values appropriate for X * an old-style preprocessor. X */ X X#ifndef OLD_PREPROCESSOR X#define OLD_PREPROCESSOR FALSE X#endif X X#if OLD_PREPROCESSOR X#define OK_DOLLAR FALSE X#define OK_CONCAT FALSE X#define COMMENT_INVISIBLE TRUE X#define STRING_FORMAL TRUE X#endif X X/* X * RECURSION_LIMIT may be set to -1 to disable the macro recursion test. X */ X#ifndef RECURSION_LIMIT X#define RECURSION_LIMIT 1000 X#endif X X/* X * BITS_CHAR may be defined to set the number of bits per character. X * it is needed only for multi-byte character constants. X */ X#ifndef BITS_CHAR X#define BITS_CHAR 8 X#endif X X/* X * BIG_ENDIAN is set TRUE on machines (such as the IBM 360 series) X * where 'ab' stores 'a' in the high-bits and 'b' in the low-bits. X * It is set FALSE on machines (such as the PDP-11 and Vax-11) X * where 'ab' stores 'a' in the low-bits and 'b' in the high-bits. X * (Or is it the other way around?) -- Warning: BIG_ENDIAN code is untested. X */ X#ifndef BIG_ENDIAN X#define BIG_ENDIAN FALSE X#endif X X/* X * COMMENT_INVISIBLE may be defined to allow "old-style" comment X * processing, whereby the comment becomes a zero-length token X * delimiter. This permitted tokens to be concatenated in macro X * expansions. This was removed from the Draft Ansi Standard. X */ X#ifndef COMMENT_INVISIBLE X#define COMMENT_INVISIBLE FALSE X#endif X X/* X * STRING_FORMAL may be defined to allow recognition of macro parameters X * anywhere in replacement strings. This was removed from the Draft Ansi X * Standard and a limited recognition capability added. X */ X#ifndef STRING_FORMAL X#define STRING_FORMAL FALSE X#endif X X/* X * OK_DOLLAR enables use of $ as a valid "letter" in identifiers. X * This is a permitted extension to the Ansi Standard and is required X * for e.g., VMS, RSX-11M, etc. It should be set FALSE if cpp is X * used to preprocess assembler source on Unix systems. OLD_PREPROCESSOR X * sets OK_DOLLAR FALSE for that reason. X */ X#ifndef OK_DOLLAR X#define OK_DOLLAR TRUE X#endif X X/* X * OK_CONCAT enables (one possible implementation of) token concatenation. X * If cpp is used to preprocess Unix assembler source, this should be X * set FALSE as the concatenation character, #, is used by the assembler. X */ X#ifndef OK_CONCAT X#define OK_CONCAT TRUE X#endif X X/* X * OK_DATE may be enabled to predefine today's date as a string X * at the start of each compilation. This is apparently not permitted X * by the Draft Ansi Standard. X */ X#ifndef OK_DATE X#define OK_DATE TRUE X#endif X X/* X * Some common definitions. X */ X X#ifndef DEBUG X#define DEBUG FALSE X#endif X X/* X * The following definitions are used to allocate memory for X * work buffers. In general, they should not be modified X * by implementors. X * X * PAR_MAC The maximum number of #define parameters (31 per Standard) X * Note: we need another one for strings. X * IDMAX The longest identifier, 31 per Ansi Standard X * NBUFF Input buffer size X * NWORK Work buffer size -- the longest macro X * must fit here after expansion. X * NEXP The nesting depth of #if expressions X * NINCLUDE The number of directories that may be specified X * on a per-system basis, or by the -I option. X * BLK_NEST The number of nested #if's permitted. X */ X X#define IDMAX 31 X#define PAR_MAC (31 + 1) X#define NBUFF 1024 X#define NWORK 1024 X#define NEXP 128 X#define NINCLUDE 7 X#define NPARMWORK (NWORK * 2) X#define BLK_NEST 32 X X/* X * Some special constants. These may need to be changed if cpp X * is ported to a wierd machine. X * X * NOTE: if cpp is run on a non-ascii machine, ALERT and VT may X * need to be changed. They are used to implement the proposed X * ANSI standard C control characters '\a' and '\v' only. X * DEL is used to tag macro tokens to prevent #define foo foo X * from looping. Note that we don't try to prevent more elaborate X * #define loops from occurring. X */ X X#ifndef ALERT X#define ALERT '\007' /* '\a' is "Bell" */ X#endif X X#ifndef VT X#define VT '\013' /* Vertical Tab CTRL/K */ X#endif X X X#ifndef FILE_LOCAL X#ifdef decus X#define FILE_LOCAL static X#else X#ifdef vax11c X#define FILE_LOCAL static X#else X#define FILE_LOCAL /* Others are global */ X#endif X#endif X#endif X END-of-cppdef.h echo x - cpp2.c sed 's/^X//' >cpp2.c << 'END-of-cpp2.c' X/* X * C P P 2 . C X * X * Process #control lines X * X * Edit history X * 13-Nov-84 MM Split from cpp1.c X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X#if HOST == SYS_VMS X/* X * Include the rms stuff. (We can't just include rms.h as it uses the X * VaxC-specific library include syntax that Decus CPP doesn't support. X * By including things by hand, we can CPP ourself.) X */ X#include X#include X#include X#include X#endif X X/* X * Generate (by hand-inspection) a set of unique values for each control X * operator. Note that this is not guaranteed to work for non-Ascii X * machines. CPP won't compile if there are hash conflicts. X */ X X#define L_assert ('a' + ('s' << 1)) X#define L_define ('d' + ('f' << 1)) X#define L_elif ('e' + ('i' << 1)) X#define L_else ('e' + ('s' << 1)) X#define L_endif ('e' + ('d' << 1)) X#define L_ident ('i' + ('e' << 1)) X#define L_if ('i' + (EOS << 1)) X#define L_ifdef ('i' + ('d' << 1)) X#define L_ifndef ('i' + ('n' << 1)) X#define L_include ('i' + ('c' << 1)) X#define L_line ('l' + ('n' << 1)) X#define L_nogood (EOS + (EOS << 1)) /* To catch #i */ X#define L_pragma ('p' + ('a' << 1)) X#define L_sccs ('s' + ('c' << 1)) X#define L_undef ('u' + ('d' << 1)) X#if DEBUG X#define L_debug ('d' + ('b' << 1)) /* #debug */ X#define L_nodebug ('n' + ('d' << 1)) /* #nodebug */ X#endif X Xint Xcontrol(counter) Xint counter; /* Pending newline counter */ X/* X * Process #control lines. Simple commands are processed inline, X * while complex commands have their own subroutines. X * X * The counter is used to force out a newline before #line, and X * #pragma commands. This prevents these commands from ending up at X * the end of the previous line if cpp is invoked with the -C option. X */ X{ X register int c; X register char *tp; X register int hash; X char *ep; X X c = skipws(); X if (c == '\n' || c == EOF_CHAR) X return (counter + 1); X if (!isdigit(c)) X scanid(c); /* Get #word to token[] */ X else { X unget(); /* Hack -- allow #123 as a */ X strcpy(token, "line"); /* synonym for #line 123 */ X } X hash = (token[1] == EOS) ? L_nogood : (token[0] + (token[2] << 1)); X switch (hash) { X case L_assert: tp = "assert"; break; X case L_define: tp = "define"; break; X case L_elif: tp = "elif"; break; X case L_else: tp = "else"; break; X case L_endif: tp = "endif"; break; X case L_ident: tp = "ident"; break; X case L_if: tp = "if"; break; X case L_ifdef: tp = "ifdef"; break; X case L_ifndef: tp = "ifndef"; break; X case L_include: tp = "include"; break; X case L_line: tp = "line"; break; X case L_pragma: tp = "pragma"; break; X case L_sccs: tp = "sccs"; break; X case L_undef: tp = "undef"; break; X#if DEBUG X case L_debug: tp = "debug"; break; X case L_nodebug: tp = "nodebug"; break; X#endif X default: hash = L_nogood; X case L_nogood: tp = ""; break; X } X if (!streq(tp, token)) X hash = L_nogood; X /* X * hash is set to a unique value corresponding to the X * control keyword (or L_nogood if we think it's nonsense). X */ X if (infile->fp == NULL) X cwarn("Control line \"%s\" within macro expansion", token); X if (!compiling) { /* Not compiling now */ X switch (hash) { X case L_if: /* These can't turn */ X case L_ifdef: /* compilation on, but */ X case L_ifndef: /* we must nest #if's */ X if (++ifptr >= &ifstack[BLK_NEST]) X goto if_nest_err; X *ifptr = 0; /* !WAS_COMPILING */ X case L_line: /* Many */ X /* X * Are pragma's always processed? X */ X case L_ident: X case L_sccs: X case L_pragma: /* options */ X case L_include: /* are uninteresting */ X case L_define: /* if we */ X case L_undef: /* aren't */ X case L_assert: /* compiling. */ Xdump_line: skipnl(); /* Ignore rest of line */ X return (counter + 1); X } X } X /* X * Make sure that #line and #pragma are output on a fresh line. X */ X if (counter > 0 && (hash == L_line || hash == L_pragma)) { X putchar('\n'); X counter--; X } X switch (hash) { X case L_line: X /* X * Parse the line to update the line number and "progname" X * field and line number for the next input line. X * Set wrongline to force it out later. X */ X c = skipws(); X workp = work; /* Save name in work */ X while (c != '\n' && c != EOF_CHAR) { X save(c); X c = get(); X } X unget(); X save(EOS); X /* X * Split #line argument into and X * We subtract 1 as we want the number of the next line. X */ X line = atoi(work) - 1; /* Reset line number */ X for (tp = work; isdigit(*tp) || type[*tp] == SPA; tp++) X ; /* Skip over digits */ X if (*tp != EOS) { /* Got a filename, so: */ X if (*tp == '"' && (ep = strrchr(tp + 1, '"')) != NULL) { X tp++; /* Skip over left quote */ X *ep = EOS; /* And ignore right one */ X } X if (infile->progname != NULL) /* Give up the old name */ X free(infile->progname); /* if it's allocated. */ X infile->progname = savestring(tp); X } X wrongline = TRUE; /* Force output later */ X break; X X case L_include: X doinclude(); X break; X X case L_define: X dodefine(); X break; X X case L_undef: X doundef(); X break; X X case L_else: X if (ifptr == &ifstack[0]) X goto nest_err; X else if ((*ifptr & ELSE_SEEN) != 0) X goto else_seen_err; X *ifptr |= ELSE_SEEN; X if ((*ifptr & WAS_COMPILING) != 0) { X if (compiling || (*ifptr & TRUE_SEEN) != 0) X compiling = FALSE; X else { X compiling = TRUE; X } X } X break; X X case L_elif: X if (ifptr == &ifstack[0]) X goto nest_err; X else if ((*ifptr & ELSE_SEEN) != 0) { Xelse_seen_err: cerror("#%s may not follow #else", token); X goto dump_line; X } X if ((*ifptr & (WAS_COMPILING | TRUE_SEEN)) != WAS_COMPILING) { X compiling = FALSE; /* Done compiling stuff */ X goto dump_line; /* Skip this clause */ X } X doif(L_if); X break; X X case L_if: X case L_ifdef: X case L_ifndef: X if (++ifptr >= &ifstack[BLK_NEST]) Xif_nest_err: cfatal("Too many nested #%s statements", token); X *ifptr = WAS_COMPILING; X doif(hash); X break; X X case L_endif: X if (ifptr == &ifstack[0]) { Xnest_err: cerror("#%s must be in an #if", token); X goto dump_line; X } X if (!compiling && (*ifptr & WAS_COMPILING) != 0) X wrongline = TRUE; X compiling = ((*ifptr & WAS_COMPILING) != 0); X --ifptr; X break; X X case L_assert: X if (eval() == 0) X cerror("Preprocessor assertion failure", NULLST); X break; X X case L_ident: X case L_sccs: X goto dump_line; X break; X X case L_pragma: X /* X * #pragma is provided to pass "options" to later X * passes of the compiler. cpp doesn't have any yet. X */ X printf("#pragma "); X while ((c = get()) != '\n' && c != EOF_CHAR) X cput(c); X unget(); X break; X X#if DEBUG X case L_debug: X if (debug == 0) X dumpdef("debug set on"); X debug++; X break; X X case L_nodebug: X debug--; X break; X#endif X X default: X /* X * Undefined #control keyword. X * Note: the correct behavior may be to warn and X * pass the line to a subsequent compiler pass. X * This would allow #asm or similar extensions. X */ X cerror("Illegal # command \"%s\"", token); X break; X } X if (hash != L_include) { X#if OLD_PREPROCESSOR || !VERBOSE X /* X * Ignore the rest of the #control line so you can write X * #if foo X * #endif foo X */ X goto dump_line; /* Take common exit */ X#else X if (skipws() != '\n') { X cwarn("Unexpected text in #control line ignored", NULLST); X skipnl(); X } X#endif X } X return (counter + 1); X} X XFILE_LOCAL Xdoif(hash) Xint hash; X/* X * Process an #if, #ifdef, or #ifndef. The latter two are straightforward, X * while #if needs a subroutine of its own to evaluate the expression. X * X * doif() is called only if compiling is TRUE. If false, compilation X * is always supressed, so we don't need to evaluate anything. This X * supresses unnecessary warnings. X */ X{ X register int c; X register int found; X X if ((c = skipws()) == '\n' || c == EOF_CHAR) { X unget(); X goto badif; X } X if (hash == L_if) { X unget(); X found = (eval() != 0); /* Evaluate expr, != 0 is TRUE */ X hash = L_ifdef; /* #if is now like #ifdef */ X } X else { X if (type[c] != LET) /* Next non-blank isn't letter */ X goto badif; /* ... is an error */ X found = (lookid(c) != NULL); /* Look for it in symbol table */ X } X if (found == (hash == L_ifdef)) { X compiling = TRUE; X *ifptr |= TRUE_SEEN; X } X else { X compiling = FALSE; X } X return; X Xbadif: cerror("#if, #ifdef, or #ifndef without an argument", NULLST); X#if !OLD_PREPROCESSOR X skipnl(); /* Prevent an extra */ X unget(); /* Error message */ X#endif X return; X} X XFILE_LOCAL Xdoinclude() X/* X * Process the #include control line. X * There are three variations: X * #include "file" search somewhere relative to the X * current source file, if not found, X * treat as #include . X * #include Search in an implementation-dependent X * list of places. X * #include token Expand the token, it must be one of X * "file" or , process as such. X * X * Note: the November 12 draft forbids '>' in the #include format. X * This restriction is unnecessary and not implemented. X */ X{ X register int c; X register int delim; X#if HOST == SYS_VMS X char def_filename[NAM$C_MAXRSS + 1]; X#endif X X delim = macroid(skipws()); X if (delim != '<' && delim != '"') X goto incerr; X if (delim == '<') X delim = '>'; X workp = work; X instring = TRUE; /* Accept all characters */ X while ((c = get()) != '\n' && c != delim && c != EOF_CHAR) X save(c); /* Put it away. */ X skipnl(); X /* X * The draft is unclear if the following should be done. X */ X X while (--workp >= work && (type[*workp] == SPA)) X ; /* Trim blanks from filename */ X X/* X * if (*workp != delim) X * goto incerr; X */ X *(workp + 1) = EOS; /* Terminate filename */ X instring = FALSE; X#if HOST == SYS_VMS X /* X * Assume the default .h filetype. X */ X if (!vmsparse(work, ".H", def_filename)) { X perror(work); /* Oops. */ X goto incerr; X } X else if (openinclude(def_filename, (delim == '"'))) X return; X#else X if (openinclude(work, (delim == '"'))) X return; X#endif X /* X * No sense continuing if #include file isn't there. X */ X cfatal("Cannot open include file \"%s\"", work); X Xincerr: cerror("#include syntax error", NULLST); X return; X} X XFILE_LOCAL int Xopeninclude(filename, searchlocal) Xchar *filename; /* Input file name */ Xint searchlocal; /* TRUE if #include "file" */ X/* X * Actually open an include file. This routine is only called from X * doinclude() above, but was written as a separate subroutine for X * programmer convenience. It searches the list of directories X * and actually opens the file, linking it into the list of X * active files. Returns TRUE if the file was opened, FALSE X * if openinclude() fails. No error message is printed. X */ X{ X register char **incptr; X#if HOST == SYS_VMS X#if NWORK < (NAM$C_MAXRSS + 1) X << error, NWORK isn't greater than NAM$C_MAXRSS >> X#endif X#endif X char tmpname[NWORK]; /* Filename work area */ X X if (searchlocal) { X /* X * Look in local directory first X */ X#if HOST == SYS_UNIX X /* X * Try to open filename relative to the directory of the current X * source file (as opposed to the current directory). (ARF, SCK). X */ X if (filename[0] != '/' X && hasdirectory(infile->filename, tmpname)) X strcat(tmpname, filename); X else { X strcpy(tmpname, filename); X } X#else X if (!hasdirectory(filename, tmpname) X && hasdirectory(infile->filename, tmpname)) X strcat(tmpname, filename); X else { X strcpy(tmpname, filename); X } X#endif X if (openfile(tmpname)) X return (TRUE); X } X /* X * Look in any directories specified by -I command line X * arguments, then in the builtin search list. X */ X for (incptr = incdir; incptr < incend; incptr++) { X if (strlen(*incptr) + strlen(filename) >= (NWORK - 1)) X cfatal("Filename work buffer overflow", NULLST); X else { X#if HOST == SYS_UNIX X if (filename[0] == '/') X strcpy(tmpname, filename); X else { X sprintf(tmpname, "%s/%s", *incptr, filename); X } X#else X if (!hasdirectory(filename, tmpname)) X sprintf(tmpname, "%s%s", *incptr, filename); X#endif X if (openfile(tmpname)) X return (TRUE); X } X } X return (FALSE); X} X XFILE_LOCAL int Xhasdirectory(source, result) Xchar *source; /* Directory to examine */ Xchar *result; /* Put directory stuff here */ X/* X * If a device or directory is found in the source filename string, the X * node/device/directory part of the string is copied to result and X * hasdirectory returns TRUE. Else, nothing is copied and it returns FALSE. X */ X{ X#if HOST == SYS_UNIX X register char *tp; X X if ((tp = strrchr(source, '/')) == NULL) X return (FALSE); X else { X strncpy(result, source, tp - source + 1); X result[tp - source + 1] = EOS; X return (TRUE); X } X#else X#if HOST == SYS_VMS X if (vmsparse(source, NULLST, result) X && result[0] != EOS) X return (TRUE); X else { X return (FALSE); X } X#else X /* X * Random DEC operating system (RSX, RT11, RSTS/E) X */ X register char *tp; X X if ((tp = strrchr(source, ']')) == NULL X && (tp = strrchr(source, ':')) == NULL) X return (FALSE); X else { X strncpy(result, source, tp - source + 1); X result[tp - source + 1] = EOS; X return (TRUE); X } X#endif X#endif X} X X#if HOST == SYS_VMS X X/* X * EXP_DEV is set if a device was specified, EXP_DIR if a directory X * is specified. (Both set indicate a file-logical, but EXP_DEV X * would be set by itself if you are reading, say, SYS$INPUT:) X */ X#define DEVDIR (NAM$M_EXP_DEV | NAM$M_EXP_DIR) X XFILE_LOCAL int Xvmsparse(source, defstring, result) Xchar *source; Xchar *defstring; /* non-NULL -> default string. */ Xchar *result; /* Size is at least NAM$C_MAXRSS + 1 */ X/* X * Parse the source string, applying the default (properly, using X * the system parse routine), storing it in result. X * TRUE if it parsed, FALSE on error. X * X * If defstring is NULL, there are no defaults and result gets X * (just) the node::[directory] part of the string (possibly "") X */ X{ X struct FAB fab = cc$rms_fab; /* File access block */ X struct NAM nam = cc$rms_nam; /* File name block */ X char fullname[NAM$C_MAXRSS + 1]; X register char *rp; /* Result pointer */ X X fab.fab$l_nam = &nam; /* fab -> nam */ X fab.fab$l_fna = source; /* Source filename */ X fab.fab$b_fns = strlen(source); /* Size of source */ X fab.fab$l_dna = defstring; /* Default string */ X if (defstring != NULLST) X fab.fab$b_dns = strlen(defstring); /* Size of default */ X nam.nam$l_esa = fullname; /* Expanded filename */ X nam.nam$b_ess = NAM$C_MAXRSS; /* Expanded name size */ X if (sys$parse(&fab) == RMS$_NORMAL) { /* Parse away */ X fullname[nam.nam$b_esl] = EOS; /* Terminate string */ X result[0] = EOS; /* Just in case */ X rp = &result[0]; X /* X * Remove stuff added implicitly, accepting node names and X * dev:[directory] strings (but not process-permanent files). X */ X if ((nam.nam$l_fnb & NAM$M_PPF) == 0) { X if ((nam.nam$l_fnb & NAM$M_NODE) != 0) { X strncpy(result, nam.nam$l_node, nam.nam$b_node); X rp += nam.nam$b_node; X *rp = EOS; X } X if ((nam.nam$l_fnb & DEVDIR) == DEVDIR) { X strncpy(rp, nam.nam$l_dev, nam.nam$b_dev + nam.nam$b_dir); X rp += nam.nam$b_dev + nam.nam$b_dir; X *rp = EOS; X } X } X if (defstring != NULLST) { X strncpy(rp, nam.nam$l_name, nam.nam$b_name + nam.nam$b_type); X rp += nam.nam$b_name + nam.nam$b_type; X *rp = EOS; X if ((nam.nam$l_fnb & NAM$M_EXP_VER) != 0) { X strncpy(rp, nam.nam$l_ver, nam.nam$b_ver); X rp[nam.nam$b_ver] = EOS; X } X } X return (TRUE); X } X return (FALSE); X} X#endif X END-of-cpp2.c exit nethack-3.4.3/sys/unix/cpp2.shr0100644000000000000000000015050107764735041015037 0ustar rootroot# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # cpp1.c # cpp3.c # cpp4.c # echo x - cpp1.c sed 's/^X//' >cpp1.c << 'END-of-cpp1.c' X/* X * CPP main program. X * X * Edit history X * 21-May-84 MM "Field test" release X * 23-May-84 MM Some minor hacks. X * 30-May-84 ARF Didn't get enough memory for __DATE__ X * Added code to read stdin if no input X * files are provided. X * 29-Jun-84 MM Added ARF's suggestions, Unixifying cpp. X * 11-Jul-84 MM "Official" first release (that's what I thought!) X * 22-Jul-84 MM/ARF/SCK Fixed line number bugs, added cpp recognition X * of #line, fixed problems with #include. X * 23-Jul-84 MM More (minor) include hacking, some documentation. X * Also, redid cpp's #include files X * 25-Jul-84 MM #line filename isn't used for #include searchlist X * #line format is X * 25-Jul-84 ARF/MM Various bugs, mostly serious. Removed homemade doprint X * 01-Aug-84 MM Fixed recursion bug, remove extra newlines and X * leading whitespace from cpp output. X * 02-Aug-84 MM Hacked (i.e. optimized) out blank lines and unneeded X * whitespace in general. Cleaned up unget()'s. X * 03-Aug-84 Keie Several bug fixes from Ed Keizer, Vrije Universitet. X * -- corrected arg. count in -D and pre-defined X * macros. Also, allow \n inside macro actual parameter X * lists. X * 06-Aug-84 MM If debugging, dump the preset vector at startup. X * 12-Aug-84 MM/SCK Some small changes from Sam Kendall X * 15-Aug-84 Keie/MM cerror, cwarn, etc. take a single string arg. X * cierror, etc. take a single int. arg. X * changed LINE_PREFIX slightly so it can be X * changed in the makefile. X * 31-Aug-84 MM USENET net.sources release. X * 7-Sep-84 SCH/ado Lint complaints X * 10-Sep-84 Keie Char's can't be signed in some implementations X * 11-Sep-84 ado Added -C flag, pathological line number fix X * 13-Sep-84 ado Added -E flag (does nothing) and "-" file for stdin. X * 14-Sep-84 MM Allow # 123 as a synonym for #line 123 X * 19-Sep-84 MM scanid always reads to token, make sure #line is X * written to a new line, even if -C switch given. X * Also, cpp - - reads stdin, writes stdout. X * 03-Oct-84 ado/MM Several changes to line counting and keepcomments X * stuff. Also a rewritten control() hasher -- much X * simpler and no less "perfect". Note also changes X * in cpp3.c to fix numeric scanning. X * 04-Oct-84 MM Added recognition of macro formal parameters if X * they are the only thing in a string, per the X * draft standard. X * 08-Oct-84 MM One more attack on scannumber X * 15-Oct-84 MM/ado Added -N to disable predefined symbols. Fixed X * linecount if COMMENT_INVISIBLE enabled. X * 22-Oct-84 MM Don't evaluate the #if/#ifdef argument if X * compilation is supressed. This prevents X * unnecessary error messages in sequences such as X * #ifdef FOO -- undefined X * #if FOO == 10 -- shouldn't print warning X * 25-Oct-84 MM Fixed bug in false ifdef supression. On vms, X * #include should open foo.h -- this duplicates X * the behavior of Vax-C X * 31-Oct-84 ado/MM Parametized $ in indentifiers. Added a better X * token concatenator and took out the trial X * concatenation code. Also improved #ifdef code X * and cleaned up the macro recursion tester. X * 2-Nov-84 MM/ado Some bug fixes in token concatenation, also X * a variety of minor (uninteresting) hacks. X * 6-Nov-84 MM Happy Birthday. Broke into 4 files and added X * #if sizeof (basic_types) X * 9-Nov-84 MM Added -S* for pointer type sizes X * 13-Nov-84 MM Split cpp1.c, added vms defaulting X * 23-Nov-84 MM/ado -E supresses error exit, added CPP_INCLUDE, X * fixed strncpy bug. X * 3-Dec-84 ado/MM Added OLD_PREPROCESSOR X * 7-Dec-84 MM Stuff in Nov 12 Draft Standard X * 17-Dec-84 george Fixed problems with recursive macros X * 17-Dec-84 MM Yet another attack on #if's (f/t)level removed. X * 07-Jan-85 ado Init defines before doing command line options X * so -Uunix works. X */ X X/*)BUILD X $(PROGRAM) = cpp X $(FILES) = { cpp1 cpp2 cpp3 cpp4 cpp5 cpp6 } X $(INCLUDE) = { cppdef.h cpp.h } X $(STACK) = 2000 X $(TKBOPTIONS) = { X STACK = 2000 X } X*/ X X#ifdef DOCUMENTATION X Xtitle cpp C Pre-Processor Xindex C pre-processor X Xsynopsis X .s.nf X cpp [-options] [infile [outfile]] X .s.f Xdescription X X CPP reads a C source file, expands macros and include X files, and writes an input file for the C compiler. X If no file arguments are given, CPP reads from stdin X and writes to stdout. If one file argument is given, X it will define the input file, while two file arguments X define both input and output files. The file name "-" X is a synonym for stdin or stdout as appropriate. X X The following options are supported. Options may X be given in either case. X .lm +16 X .p -16 X -C If set, source-file comments are written X to the output file. This allows the output of CPP to be X used as the input to a program, such as lint, that expects X commands embedded in specially-formatted comments. X .p -16 X -Dname=value Define the name as if the programmer wrote X X #define name value X X at the start of the first file. If "=value" is not X given, a value of "1" will be used. X X On non-unix systems, all alphabetic text will be forced X to upper-case. X .p -16 X -E Always return "success" to the operating X system, even if errors were detected. Note that some fatal X errors, such as a missing #include file, will terminate X CPP, returning "failure" even if the -E option is given. X .p -16 X -Idirectory Add this directory to the list of X directories searched for #include "..." and #include <...> X commands. Note that there is no space between the X "-I" and the directory string. More than one -I command X is permitted. On non-Unix systems "directory" is forced X to upper-case. X .p -16 X -N CPP normally predefines some symbols defining X the target computer and operating system. If -N is specified, X no symbols will be predefined. If -N -N is specified, the X "always present" symbols, __LINE__, __FILE__, and __DATE__ X are not defined. X .p -16 X -Stext CPP normally assumes that the size of X the target computer's basic variable types is the same as the size X of these types of the host computer. (This can be overridden X when CPP is compiled, however.) The -S option allows dynamic X respecification of these values. "text" is a string of X numbers, separated by commas, that specifies correct sizes. X The sizes must be specified in the exact order: X X char short int long float double X X If you specify the option as "-S*text", pointers to these X types will be specified. -S* takes one additional argument X for pointer to function (e.g. int (*)()) X X For example, to specify sizes appropriate for a PDP-11, X you would write: X X c s i l f d func X -S1,2,2,2,4,8, X -S*2,2,2,2,2,2,2 X X Note that all values must be specified. X .p -16 X -Uname Undefine the name as if X X #undef name X X were given. On non-Unix systems, "name" will be forced to X upper-case. X .p -16 X -Xnumber Enable debugging code. If no value is X given, a value of 1 will be used. (For maintenence of X CPP only.) X .s.lm -16 X XPre-Defined Variables X X When CPP begins processing, the following variables will X have been defined (unless the -N option is specified): X .s X Target computer (as appropriate): X .s X pdp11, vax, M68000 m68000 m68k X .s X Target operating system (as appropriate): X .s X rsx, rt11, vms, unix X .s X Target compiler (as appropriate): X .s X decus, vax11c X .s X The implementor may add definitions to this list. X The default definitions match the definition of the X host computer, operating system, and C compiler. X .s X The following are always available unless undefined (or X -N was specified twice): X .lm +16 X .p -12 X __FILE__ The input (or #include) file being compiled X (as a quoted string). X .p -12 X __LINE__ The line number being compiled. X .p -12 X __DATE__ The date and time of compilation as X a Unix ctime quoted string (the trailing newline is removed). X Thus, X .s X printf("Bug at line %s,", __LINE__); X printf(" source file %s", __FILE__); X printf(" compiled on %s", __DATE__); X .s.lm -16 X XDraft Proposed Ansi Standard Considerations X X The current version of the Draft Proposed Standard X explicitly states that "readers are requested not to specify X or claim conformance to this draft." Readers and users X of Decus CPP should not assume that Decus CPP conforms X to the standard, or that it will conform to the actual X C Language Standard. X X When CPP is itself compiled, many features of the Draft X Proposed Standard that are incompatible with existing X preprocessors may be disabled. See the comments in CPP's X source for details. X X The latest version of the Draft Proposed Standard (as reflected X in Decus CPP) is dated November 12, 1984. X X Comments are removed from the input text. The comment X is replaced by a single space character. The -C option X preserves comments, writing them to the output file. X X The '$' character is considered to be a letter. This is X a permitted extension. X X The following new features of C are processed by CPP: X .s.comment Note: significant spaces, not tabs, .br quotes #if, #elif X .br;####_#elif expression (_#else _#if) X .br;####'_\xNNN' (Hexadecimal constant) X .br;####'_\a' (Ascii BELL) X .br;####'_\v' (Ascii Vertical Tab) X .br;####_#if defined NAME 1 if defined, 0 if not X .br;####_#if defined (NAME) 1 if defined, 0 if not X .br;####_#if sizeof (basic type) X .br;####unary + X .br;####123U, 123LU Unsigned ints and longs. X .br;####12.3L Long double numbers X .br;####token_#token Token concatenation X .br;####_#include token Expands to filename X X The Draft Proposed Standard has extended C, adding a constant X string concatenation operator, where X X "foo" "bar" X X is regarded as the single string "foobar". (This does not X affect CPP's processing but does permit a limited form of X macro argument substitution into strings as will be discussed.) X X The Standard Committee plans to add token concatenation X to #define command lines. One suggested implementation X is as follows: the sequence "Token1#Token2" is treated X as if the programmer wrote "Token1Token2". This could X be used as follows: X X #line 123 X #define ATLINE foo#__LINE__ X X ATLINE would be defined as foo123. X X Note that "Token2" must either have the format of an X identifier or be a string of digits. Thus, the string X X #define ATLINE foo#1x3 X X generates two tokens: "foo1" and "x3". X X If the tokens T1 and T2 are concatenated into T3, X this implementation operates as follows: X X 1. Expand T1 if it is a macro. X 2. Expand T2 if it is a macro. X 3. Join the tokens, forming T3. X 4. Expand T3 if it is a macro. X X A macro formal parameter will be substituted into a string X or character constant if it is the only component of that X constant: X X #define VECSIZE 123 X #define vprint(name, size) \ X printf("name" "[" "size" "] = {\n") X ... vprint(vector, VECSIZE); X X expands (effectively) to X X vprint("vector[123] = {\n"); X X Note that this will be useful if your C compiler supports X the new string concatenation operation noted above. X As implemented here, if you write X X #define string(arg) "arg" X ... string("foo") ... X X This implementation generates "foo", rather than the strictly X correct ""foo"" (which will probably generate an error message). X This is, strictly speaking, an error in CPP and may be removed X from future releases. X Xerror messages X X Many. CPP prints warning or error messages if you try to X use multiple-byte character constants (non-transportable) X if you #undef a symbol that was not defined, or if your X program has potentially nested comments. X Xauthor X X Martin Minow X Xbugs X X The #if expression processor uses signed integers only. X I.e, #if 0xFFFFu < 0 may be TRUE. X X#endif X X#include X#include X#include "cppdef.h" X#include "cpp.h" X X/* X * Commonly used global variables: X * line is the current input line number. X * wrongline is set in many places when the actual output X * line is out of sync with the numbering, e.g, X * when expanding a macro with an embedded newline. X * X * token holds the last identifier scanned (which might X * be a candidate for macro expansion). X * errors is the running cpp error counter. X * infile is the head of a linked list of input files (extended by X * #include and macros being expanded). infile always points X * to the current file/macro. infile->parent to the includer, X * etc. infile->fd is NULL if this input stream is a macro. X */ Xint line; /* Current line number */ Xint wrongline; /* Force #line to compiler */ Xchar token[IDMAX + 1]; /* Current input token */ Xint errors; /* cpp error counter */ XFILEINFO *infile = NULL; /* Current input file */ X#if DEBUG Xint debug; /* TRUE if debugging now */ X#endif X/* X * This counter is incremented when a macro expansion is initiated. X * If it exceeds a built-in value, the expansion stops -- this tests X * for a runaway condition: X * #define X Y X * #define Y X X * X X * This can be disabled by falsifying rec_recover. (Nothing does this X * currently: it is a hook for an eventual invocation flag.) X */ Xint recursion; /* Infinite recursion counter */ Xint rec_recover = TRUE; /* Unwind recursive macros */ X X/* X * instring is set TRUE when a string is scanned. It modifies the X * behavior of the "get next character" routine, causing all characters X * to be passed to the caller (except ). Note especially that X * comments and \ are not removed from the source. (This X * prevents cpp output lines from being arbitrarily long). X * X * inmacro is set by #define -- it absorbs comments and converts X * form-feed and vertical-tab to space, but returns \ X * to the caller. Strictly speaking, this is a bug as \ X * shouldn't delimit tokens, but we'll worry about that some other X * time -- it is more important to prevent infinitly long output lines. X * X * instring and inmarcor are parameters to the get() routine which X * were made global for speed. X */ Xint instring = FALSE; /* TRUE if scanning string */ Xint inmacro = FALSE; /* TRUE if #defining a macro */ X X/* X * work[] and workp are used to store one piece of text in a temporay X * buffer. To initialize storage, set workp = work. To store one X * character, call save(c); (This will fatally exit if there isn't X * room.) To terminate the string, call save(EOS). Note that X * the work buffer is used by several subroutines -- be sure your X * data won't be overwritten. The extra byte in the allocation is X * needed for string formal replacement. X */ Xchar work[NWORK + 1]; /* Work buffer */ Xchar *workp; /* Work buffer pointer */ X X/* X * keepcomments is set TRUE by the -C option. If TRUE, comments X * are written directly to the output stream. This is needed if X * the output from cpp is to be passed to lint (which uses commands X * embedded in comments). cflag contains the permanent state of the X * -C flag. keepcomments is always falsified when processing #control X * commands and when compilation is supressed by a false #if X * X * If eflag is set, CPP returns "success" even if non-fatal errors X * were detected. X * X * If nflag is non-zero, no symbols are predefined except __LINE__. X * __FILE__, and __DATE__. If nflag > 1, absolutely no symbols X * are predefined. X */ Xint keepcomments = FALSE; /* Write out comments flag */ Xint cflag = FALSE; /* -C option (keep comments) */ Xint eflag = FALSE; /* -E option (never fail) */ Xint nflag = 0; /* -N option (no predefines) */ X X/* X * ifstack[] holds information about nested #if's. It is always X * accessed via *ifptr. The information is as follows: X * WAS_COMPILING state of compiling flag at outer level. X * ELSE_SEEN set TRUE when #else seen to prevent 2nd #else. X * TRUE_SEEN set TRUE when #if or #elif succeeds X * ifstack[0] holds the compiling flag. It is TRUE if compilation X * is currently enabled. Note that this must be initialized TRUE. X */ Xchar ifstack[BLK_NEST] = { TRUE }; /* #if information */ Xchar *ifptr = ifstack; /* -> current ifstack[] */ X X/* X * incdir[] stores the -i directories (and the system-specific X * #include <...> directories. X */ Xchar *incdir[NINCLUDE]; /* -i directories */ Xchar **incend = incdir; /* -> free space in incdir[] */ X X/* X * This is the table used to predefine target machine and operating X * system designators. It may need hacking for specific circumstances. X * Note: it is not clear that this is part of the Ansi Standard. X * The -N option supresses preset definitions. X */ Xchar *preset[] = { /* names defined at cpp start */ X#ifdef MACHINE X MACHINE, X#endif X#ifdef SYSTEM X SYSTEM, X#endif X#ifdef COMPILER X COMPILER, X#endif X#if DEBUG X "decus_cpp", /* Ourselves! */ X#endif X NULL /* Must be last */ X}; X X/* X * The value of these predefined symbols must be recomputed whenever X * they are evaluated. The order must not be changed. X */ Xchar *magic[] = { /* Note: order is important */ X "__LINE__", X "__FILE__", X NULL /* Must be last */ X}; X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X register int i; X X#if HOST == SYS_VMS X argc = getredirection(argc, argv); /* vms >file and stdin */ X /* X * Open input file, "-" means use stdin. X */ X if (!streq(argv[1], "-")) { X if (freopen(argv[1], "r", stdin) == NULL) { X perror(argv[1]); X cerror("Can't open input file \"%s\"", argv[1]); X exit(IO_ERROR); X } X strcpy(work, argv[1]); /* Remember input filename */ X break; X } /* Else, just get stdin */ X case 0: /* No args? */ X case 1: /* No files, stdin -> stdout */ X#if HOST == SYS_UNIX X work[0] = EOS; /* Unix can't find stdin name */ X#else X fgetname(stdin, work); /* Vax-11C, Decus C know name */ X#endif X break; X X default: X exit(IO_ERROR); /* Can't happen */ X } X setincdirs(); /* Setup -I include directories */ X addfile(stdin, work); /* "open" main input file */ X#if DEBUG X if (debug > 0) X dumpdef("preset #define symbols"); X#endif X cppmain(); /* Process main file */ X if ((i = (ifptr - &ifstack[0])) != 0) { X#if OLD_PREPROCESSOR X ciwarn("Inside #ifdef block at end of input, depth = %d", i); X#else X cierror("Inside #ifdef block at end of input, depth = %d", i); X#endif X } X fclose(stdout); X if (errors > 0) { X fprintf(stderr, (errors == 1) X ? "%d error in preprocessor\n" X : "%d errors in preprocessor\n", errors); X if (!eflag) X exit(IO_ERROR); X } X exit(IO_NORMAL); /* No errors or -E option set */ X} X XFILE_LOCAL Xcppmain() X/* X * Main process for cpp -- copies tokens from the current input X * stream (main file, include file, or a macro) to the output X * file. X */ X{ X register int c; /* Current character */ X register int counter; /* newlines and spaces */ X extern int output(); /* Output one character */ X X /* X * Explicitly output a #line at the start of cpp output so X * that lint (etc.) knows the name of the original source X * file. If we don't do this explicitly, we may get X * the name of the first #include file instead. X */ X sharp(); X /* X * This loop is started "from the top" at the beginning of each line X * wrongline is set TRUE in many places if it is necessary to write X * a #line record. (But we don't write them when expanding macros.) X * X * The counter variable has two different uses: at X * the start of a line, it counts the number of blank lines that X * have been skipped over. These are then either output via X * #line records or by outputting explicit blank lines. X * When expanding tokens within a line, the counter remembers X * whether a blank/tab has been output. These are dropped X * at the end of the line, and replaced by a single blank X * within lines. X */ X for (;;) { X counter = 0; /* Count empty lines */ X for (;;) { /* For each line, ... */ X while (type[(c = get())] == SPA) /* Skip leading blanks */ X ; /* in this line. */ X if (c == '\n') /* If line's all blank, */ X ++counter; /* Do nothing now */ X else if (c == '#') { /* Is 1st non-space '#' */ X keepcomments = FALSE; /* Don't pass comments */ X counter = control(counter); /* Yes, do a #command */ X keepcomments = (cflag && compiling); X } X else if (c == EOF_CHAR) /* At end of file? */ X break; X else if (!compiling) { /* #ifdef false? */ X skipnl(); /* Skip to newline */ X counter++; /* Count it, too. */ X } X else { X break; /* Actual token */ X } X } X if (c == EOF_CHAR) /* Exit process at */ X break; /* End of file */ X /* X * If the loop didn't terminate because of end of file, we X * know there is a token to compile. First, clean up after X * absorbing newlines. counter has the number we skipped. X */ X if ((wrongline && infile->fp != NULL) || counter > 4) X sharp(); /* Output # line number */ X else { /* If just a few, stuff */ X while (--counter >= 0) /* them out ourselves */ X putchar('\n'); X } X /* X * Process each token on this line. X */ X unget(); /* Reread the char. */ X for (;;) { /* For the whole line, */ X do { /* Token concat. loop */ X for (counter = 0; (type[(c = get())] == SPA);) { X#if COMMENT_INVISIBLE X if (c != COM_SEP) X counter++; X#else X counter++; /* Skip over blanks */ X#endif X } X if (c == EOF_CHAR || c == '\n') X goto end_line; /* Exit line loop */ X else if (counter > 0) /* If we got any spaces */ X putchar(' '); /* Output one space */ X c = macroid(c); /* Grab the token */ X } while (type[c] == LET && catenate()); X if (c == EOF_CHAR || c == '\n') /* From macro exp error */ X goto end_line; /* Exit line loop */ X switch (type[c]) { X case LET: X fputs(token, stdout); /* Quite ordinary token */ X break; X X X case DIG: /* Output a number */ X case DOT: /* Dot may begin floats */ X scannumber(c, output); X break; X X case QUO: /* char or string const */ X scanstring(c, output); /* Copy it to output */ X break; X X default: /* Some other character */ X cput(c); /* Just output it */ X break; X } /* Switch ends */ X } /* Line for loop */ Xend_line: if (c == '\n') { /* Compiling at EOL? */ X putchar('\n'); /* Output newline, if */ X if (infile->fp == NULL) /* Expanding a macro, */ X wrongline = TRUE; /* Output # line later */ X } X } /* Continue until EOF */ X} X Xoutput(c) Xint c; X/* X * Output one character to stdout -- output() is passed as an X * argument to scanstring() X */ X{ X#if COMMENT_INVISIBLE X if (c != TOK_SEP && c != COM_SEP) X#else X if (c != TOK_SEP) X#endif X putchar(c); X} X Xstatic char *sharpfilename = NULL; X XFILE_LOCAL Xsharp() X/* X * Output a line number line. X */ X{ X register char *name; X X if (keepcomments) /* Make sure # comes on */ X putchar('\n'); /* a fresh, new line. */ X printf("#%s %d", LINE_PREFIX, line); X if (infile->fp != NULL) { X name = (infile->progname != NULL) X ? infile->progname : infile->filename; X if (sharpfilename == NULL X || sharpfilename != NULL && !streq(name, sharpfilename)) { X if (sharpfilename != NULL) X free(sharpfilename); X sharpfilename = savestring(name); X printf(" \"%s\"", name); X } X } X putchar('\n'); X wrongline = FALSE; X} END-of-cpp1.c echo x - cpp3.c sed 's/^X//' >cpp3.c << 'END-of-cpp3.c' X/* X * C P P 3 . C X * X * File open and command line options X * X * Edit history X * 13-Nov-84 MM Split from cpp1.c X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X#if DEBUG && (HOST == SYS_VMS || HOST == SYS_UNIX) X#include Xextern int abort(); /* For debugging */ X#endif X Xint Xopenfile(filename) Xchar *filename; X/* X * Open a file, add it to the linked list of open files. X * This is called only from openfile() above. X */ X{ X register FILE *fp; X X if ((fp = fopen(filename, "r")) == NULL) { X#if DEBUG X perror(filename); X#endif X return (FALSE); X } X#if DEBUG X if (debug) X fprintf(stderr, "Reading from \"%s\"\n", filename); X#endif X addfile(fp, filename); X return (TRUE); X} X Xaddfile(fp, filename) XFILE *fp; /* Open file pointer */ Xchar *filename; /* Name of the file */ X/* X * Initialize tables for this open file. This is called from openfile() X * above (for #include files), and from the entry to cpp to open the main X * input file. It calls a common routine, getfile() to build the FILEINFO X * structure which is used to read characters. (getfile() is also called X * to setup a macro replacement.) X */ X{ X register FILEINFO *file; X extern FILEINFO *getfile(); X X file = getfile(NBUFF, filename); X file->fp = fp; /* Better remember FILE * */ X file->buffer[0] = EOS; /* Initialize for first read */ X line = 1; /* Working on line 1 now */ X wrongline = TRUE; /* Force out initial #line */ X} X Xsetincdirs() X/* X * Append system-specific directories to the include directory list. X * Called only when cpp is started. X */ X{ X X#ifdef CPP_INCLUDE X *incend++ = CPP_INCLUDE; X#define IS_INCLUDE 1 X#else X#define IS_INCLUDE 0 X#endif X X#if HOST == SYS_UNIX X *incend++ = "/usr/include"; X#define MAXINCLUDE (NINCLUDE - 1 - IS_INCLUDE) X#endif X X#if HOST == SYS_VMS X extern char *getenv(); X X if (getenv("C$LIBRARY") != NULL) X *incend++ = "C$LIBRARY:"; X *incend++ = "SYS$LIBRARY:"; X#define MAXINCLUDE (NINCLUDE - 2 - IS_INCLUDE) X#endif X X#if HOST == SYS_RSX X extern int $$rsts; /* TRUE on RSTS/E */ X extern int $$pos; /* TRUE on PRO-350 P/OS */ X extern int $$vms; /* TRUE on VMS compat. */ X X if ($$pos) { /* P/OS? */ X *incend++ = "SY:[ZZDECUSC]"; /* C #includes */ X *incend++ = "LB:[1,5]"; /* RSX library */ X } X else if ($$rsts) { /* RSTS/E? */ X *incend++ = "SY:@"; /* User-defined account */ X *incend++ = "C:"; /* Decus-C library */ X *incend++ = "LB:[1,1]"; /* RSX library */ X } X else if ($$vms) { /* VMS compatibility? */ X *incend++ = "C:"; X } X else { /* Plain old RSX/IAS */ X *incend++ = "LB:[1,1]"; X } X#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) X#endif X X#if HOST == SYS_RT11 X extern int $$rsts; /* RSTS/E emulation? */ X X if ($$rsts) X *incend++ = "SY:@"; /* User-defined account */ X *incend++ = "C:"; /* Decus-C library disk */ X *incend++ = "SY:"; /* System (boot) disk */ X#define MAXINCLUDE (NINCLUDE - 3 - IS_INCLUDE) X#endif X} X Xint Xdooptions(argc, argv) Xint argc; Xchar *argv[]; X/* X * dooptions is called to process command line arguments (-Detc). X * It is called only at cpp startup. X */ X{ X register char *ap; X register DEFBUF *dp; X register int c; X int i, j; X char *arg; X SIZES *sizp; /* For -S */ X int size; /* For -S */ X int isdatum; /* FALSE for -S* */ X int endtest; /* For -S */ X X for (i = j = 1; i < argc; i++) { X arg = ap = argv[i]; X if (*ap++ != '-' || *ap == EOS) X argv[j++] = argv[i]; X else { X c = *ap++; /* Option byte */ X if (islower(c)) /* Normalize case */ X c = toupper(c); X switch (c) { /* Command character */ X case 'C': /* Keep comments */ X cflag = TRUE; X keepcomments = TRUE; X break; X X case 'D': /* Define symbol */ X#if HOST != SYS_UNIX X zap_uc(ap); /* Force define to U.C. */ X#endif X /* X * If the option is just "-Dfoo", make it -Dfoo=1 X */ X while (*ap != EOS && *ap != '=') X ap++; X if (*ap == EOS) X ap = "1"; X else X *ap++ = EOS; X /* X * Now, save the word and its definition. X */ X dp = defendel(argv[i] + 2, FALSE); X dp->repl = savestring(ap); X dp->nargs = DEF_NOARGS; X break; X X case 'E': /* Ignore non-fatal */ X eflag = TRUE; /* errors. */ X break; X X case 'I': /* Include directory */ X if (incend >= &incdir[MAXINCLUDE]) X cfatal("Too many include directories", NULLST); X *incend++ = ap; X break; X X case 'N': /* No predefineds */ X nflag++; /* Repeat to undefine */ X break; /* __LINE__, etc. */ X X case 'S': X sizp = size_table; X if (isdatum = (*ap != '*')) /* If it's just -S, */ X endtest = T_FPTR; /* Stop here */ X else { /* But if it's -S* */ X ap++; /* Step over '*' */ X endtest = 0; /* Stop at end marker */ X } X while (sizp->bits != endtest && *ap != EOS) { X if (!isdigit(*ap)) { /* Skip to next digit */ X ap++; X continue; X } X size = 0; /* Compile the value */ X while (isdigit(*ap)) { X size *= 10; X size += (*ap++ - '0'); X } X if (isdatum) X sizp->size = size; /* Datum size */ X else X sizp->psize = size; /* Pointer size */ X sizp++; X } X if (sizp->bits != endtest) X cwarn("-S, too few values specified in %s", argv[i]); X else if (*ap != EOS) X cwarn("-S, too many values, \"%s\" unused", ap); X break; X X case 'U': /* Undefine symbol */ X#if HOST != SYS_UNIX X zap_uc(ap); X#endif X if (defendel(ap, TRUE) == NULL) X cwarn("\"%s\" wasn't defined", ap); X break; X X#if DEBUG X case 'X': /* Debug */ X debug = (isdigit(*ap)) ? atoi(ap) : 1; X#if (HOST == SYS_VMS || HOST == SYS_UNIX) X signal(SIGINT, abort); /* Trap "interrupt" */ X#endif X fprintf(stderr, "Debug set to %d\n", debug); X break; X#endif X X default: /* What is this one? */ X cwarn("Unknown option \"%s\"", arg); X fprintf(stderr, "The following options are valid:\n\ X -C\t\t\tWrite source file comments to output\n\ X -Dsymbol=value\tDefine a symbol with the given (optional) value\n\ X -Idirectory\t\tAdd a directory to the #include search list\n\ X -N\t\t\tDon't predefine target-specific names\n\ X -Stext\t\tSpecify sizes for #if sizeof\n\ X -Usymbol\t\tUndefine symbol\n"); X#if DEBUG X fprintf(stderr, " -Xvalue\t\tSet internal debug flag\n"); X#endif X break; X } /* Switch on all options */ X } /* If it's a -option */ X } /* For all arguments */ X if (j > 3) { X cerror( X "Too many file arguments. Usage: cpp [input [output]]", X NULLST); X } X return (j); /* Return new argc */ X} X X#if HOST != SYS_UNIX XFILE_LOCAL Xzap_uc(ap) Xregister char *ap; X/* X * Dec operating systems mangle upper-lower case in command lines. X * This routine forces the -D and -U arguments to uppercase. X * It is called only on cpp startup by dooptions(). X */ X{ X while (*ap != EOS) { X /* X * Don't use islower() here so it works with Multinational X */ X if (*ap >= 'a' && *ap <= 'z') X *ap = toupper(*ap); X ap++; X } X} X#endif X Xinitdefines() X/* X * Initialize the built-in #define's. There are two flavors: X * #define decus 1 (static definitions) X * #define __FILE__ ?? (dynamic, evaluated by magic) X * Called only on cpp startup. X * X * Note: the built-in static definitions are supressed by the -N option. X * __LINE__, __FILE__, and __DATE__ are always present. X */ X{ X register char **pp; X register char *tp; X register DEFBUF *dp; X int i; X long tvec; X extern char *ctime(); X X /* X * Predefine the built-in symbols. Allow the X * implementor to pre-define a symbol as "" to X * eliminate it. X */ X if (nflag == 0) { X for (pp = preset; *pp != NULL; pp++) { X if (*pp[0] != EOS) { X dp = defendel(*pp, FALSE); X dp->repl = savestring("1"); X dp->nargs = DEF_NOARGS; X } X } X } X /* X * The magic pre-defines (__FILE__ and __LINE__ are X * initialized with negative argument counts. expand() X * notices this and calls the appropriate routine. X * DEF_NOARGS is one greater than the first "magic" definition. X */ X if (nflag < 2) { X for (pp = magic, i = DEF_NOARGS; *pp != NULL; pp++) { X dp = defendel(*pp, FALSE); X dp->nargs = --i; X } X#if OK_DATE X /* X * Define __DATE__ as today's date. X */ X dp = defendel("__DATE__", FALSE); X dp->repl = tp = getmem(27); X dp->nargs = DEF_NOARGS; X time(&tvec); X *tp++ = '"'; X strcpy(tp, ctime(&tvec)); X tp[24] = '"'; /* Overwrite newline */ X#endif X } X} X X#if HOST == SYS_VMS X/* X * getredirection() is intended to aid in porting C programs X * to VMS (Vax-11 C) which does not support '>' and '<' X * I/O redirection. With suitable modification, it may X * useful for other portability problems as well. X */ X Xint Xgetredirection(argc, argv) Xint argc; Xchar **argv; X/* X * Process vms redirection arg's. Exit if any error is seen. X * If getredirection() processes an argument, it is erased X * from the vector. getredirection() returns a new argc value. X * X * Warning: do not try to simplify the code for vms. The code X * presupposes that getredirection() is called before any data is X * read from stdin or written to stdout. X * X * Normal usage is as follows: X * X * main(argc, argv) X * int argc; X * char *argv[]; X * { X * argc = getredirection(argc, argv); X * } X */ X{ X register char *ap; /* Argument pointer */ X int i; /* argv[] index */ X int j; /* Output index */ X int file; /* File_descriptor */ X extern int errno; /* Last vms i/o error */ X X for (j = i = 1; i < argc; i++) { /* Do all arguments */ X switch (*(ap = argv[i])) { X case '<': /* ': /* >file or >>file */ X if (*++ap == '>') { /* >>file */ X /* X * If the file exists, and is writable by us, X * call freopen to append to the file (using the X * file's current attributes). Otherwise, create X * a new file with "vanilla" attributes as if the X * argument was given as ">filename". X * access(name, 2) returns zero if we can write on X * the specified file. X */ X if (access(++ap, 2) == 0) { X if (freopen(ap, "a", stdout) != NULL) X break; /* Exit case statement */ X perror(ap); /* Error, can't append */ X exit(errno); /* After access test */ X } /* If file accessable */ X } X /* X * On vms, we want to create the file using "standard" X * record attributes. creat(...) creates the file X * using the caller's default protection mask and X * "variable length, implied carriage return" X * attributes. dup2() associates the file with stdout. X */ X if ((file = creat(ap, 0, "rat=cr", "rfm=var")) == -1 X || dup2(file, fileno(stdout)) == -1) { X perror(ap); /* Can't create file */ X exit(errno); /* is a fatal error */ X } /* If '>' creation */ X break; /* Exit case test */ X X default: X argv[j++] = ap; /* Not a redirector */ X break; /* Exit case test */ X } X } /* For all arguments */ X argv[j] = NULL; /* Terminate argv[] */ X return (j); /* Return new argc */ X} X#endif X X X END-of-cpp3.c echo x - cpp4.c sed 's/^X//' >cpp4.c << 'END-of-cpp4.c' X/* X * C P P 4 . C X * M a c r o D e f i n i t i o n s X * X * Edit History X * 31-Aug-84 MM USENET net.sources release X * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() X * so they work correctly with token concatenation. X * Added string formal recognition. X * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we X * don't print unnecessary error messages for X * #if !defined(FOO) && FOO != 0 && 10 / FOO ... X * 31-Oct-84 ado/MM Added token concatenation X * 6-Nov-84 MM Split off eval stuff X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X/* X * parm[], parmp, and parlist[] are used to store #define() argument X * lists. nargs contains the actual number of parameters stored. X */ Xstatic char parm[NPARMWORK + 1]; /* define param work buffer */ Xstatic char *parmp; /* Free space in parm */ Xstatic char *parlist[LASTPARM]; /* -> start of each parameter */ Xstatic int nargs; /* Parameters for this macro */ X Xdodefine() X/* X * Called from control when a #define is scanned. This module X * parses formal parameters and the replacement string. When X * the formal parameter name is encountered in the replacement X * string, it is replaced by a character in the range 128 to X * 128+NPARAM (this allows up to 32 parameters within the X * Dec Multinational range). If cpp is ported to an EBCDIC X * machine, you will have to make other arrangements. X * X * There is some special case code to distinguish X * #define foo bar X * from #define foo() bar X * X * Also, we make sure that X * #define foo foo X * expands to "foo" but doesn't put cpp into an infinite loop. X * X * A warning message is printed if you redefine a symbol to a X * different text. I.e, X * #define foo 123 X * #define foo 123 X * is ok, but X * #define foo 123 X * #define foo +123 X * is not. X * X * The following subroutines are called from define(): X * checkparm called when a token is scanned. It checks through the X * array of formal parameters. If a match is found, the X * token is replaced by a control byte which will be used X * to locate the parameter when the macro is expanded. X * textput puts a string in the macro work area (parm[]), updating X * parmp to point to the first free byte in parm[]. X * textput() tests for work buffer overflow. X * charput puts a single character in the macro work area (parm[]) X * in a manner analogous to textput(). X */ X{ X register int c; X register DEFBUF *dp; /* -> new definition */ X int isredefine; /* TRUE if redefined */ X char *old; /* Remember redefined */ X extern int save(); /* Save char in work[] */ X X if (type[(c = skipws())] != LET) X goto bad_define; X isredefine = FALSE; /* Set if redefining */ X if ((dp = lookid(c)) == NULL) /* If not known now */ X dp = defendel(token, FALSE); /* Save the name */ X else { /* It's known: */ X isredefine = TRUE; /* Remember this fact */ X old = dp->repl; /* Remember replacement */ X dp->repl = NULL; /* No replacement now */ X } X parlist[0] = parmp = parm; /* Setup parm buffer */ X if ((c = get()) == '(') { /* With arguments? */ X nargs = 0; /* Init formals counter */ X do { /* Collect formal parms */ X if (nargs >= LASTPARM) X cfatal("Too many arguments for macro", NULLST); X else if ((c = skipws()) == ')') X break; /* Got them all */ X else if (type[c] != LET) /* Bad formal syntax */ X goto bad_define; X scanid(c); /* Get the formal param */ X parlist[nargs++] = parmp; /* Save its start */ X textput(token); /* Save text in parm[] */ X } while ((c = skipws()) == ','); /* Get another argument */ X if (c != ')') /* Must end at ) */ X goto bad_define; X c = ' '; /* Will skip to body */ X } X else { X /* X * DEF_NOARGS is needed to distinguish between X * "#define foo" and "#define foo()". X */ X nargs = DEF_NOARGS; /* No () parameters */ X } X if (type[c] == SPA) /* At whitespace? */ X c = skipws(); /* Not any more. */ X workp = work; /* Replacement put here */ X inmacro = TRUE; /* Keep \ now */ X while (c != EOF_CHAR && c != '\n') { /* Compile macro body */ X#if OK_CONCAT X if (c == '#') { /* Token concatenation? */ X while (workp > work && type[workp[-1]] == SPA) X --workp; /* Erase leading spaces */ X save(TOK_SEP); /* Stuff a delimiter */ X c = skipws(); /* Eat whitespace */ X if (type[c] == LET) /* Another token here? */ X ; /* Stuff it normally */ X else if (type[c] == DIG) { /* Digit string after? */ X while (type[c] == DIG) { /* Stuff the digits */ X save(c); X c = get(); X } X save(TOK_SEP); /* Delimit 2nd token */ X } X else { X ciwarn("Strange character after # (%d.)", c); X } X continue; X } X#endif X switch (type[c]) { X case LET: X checkparm(c, dp); /* Might be a formal */ X break; X X case DIG: /* Number in mac. body */ X case DOT: /* Maybe a float number */ X scannumber(c, save); /* Scan it off */ X break; X X case QUO: /* String in mac. body */ X#if STRING_FORMAL X stparmscan(c, dp); /* Do string magic */ X#else X stparmscan(c); X#endif X break; X X case BSH: /* Backslash */ X save('\\'); X if ((c = get()) == '\n') X wrongline = TRUE; X save(c); X break; X X case SPA: /* Absorb whitespace */ X /* X * Note: the "end of comment" marker is passed on X * to allow comments to separate tokens. X */ X if (workp[-1] == ' ') /* Absorb multiple */ X break; /* spaces */ X else if (c == '\t') X c = ' '; /* Normalize tabs */ X /* Fall through to store character */ X default: /* Other character */ X save(c); X break; X } X c = get(); X } X inmacro = FALSE; /* Stop newline hack */ X unget(); /* For control check */ X if (workp > work && workp[-1] == ' ') /* Drop trailing blank */ X workp--; X *workp = EOS; /* Terminate work */ X dp->repl = savestring(work); /* Save the string */ X dp->nargs = nargs; /* Save arg count */ X#if DEBUG X if (debug) X dumpadef("macro definition", dp); X#endif X if (isredefine) { /* Error if redefined */ X if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl)) X || (old == NULL && dp->repl != NULL) X || (old != NULL && dp->repl == NULL)) { X cerror("Redefining defined variable \"%s\"", dp->name); X } X if (old != NULL) /* We don't need the */ X free(old); /* old definition now. */ X } X return; X Xbad_define: X cerror("#define syntax error", NULLST); X inmacro = FALSE; /* Stop hack */ X} X Xcheckparm(c, dp) Xregister int c; XDEFBUF *dp; X/* X * Replace this param if it's defined. Note that the macro name is a X * possible replacement token. We stuff DEF_MAGIC in front of the token X * which is treated as a LETTER by the token scanner and eaten by X * the output routine. This prevents the macro expander from X * looping if someone writes "#define foo foo". X */ X{ X register int i; X register char *cp; X X scanid(c); /* Get parm to token[] */ X for (i = 0; i < nargs; i++) { /* For each argument */ X if (streq(parlist[i], token)) { /* If it's known */ X save(i + MAC_PARM); /* Save a magic cookie */ X return; /* And exit the search */ X } X } X if (streq(dp->name, token)) /* Macro name in body? */ X save(DEF_MAGIC); /* Save magic marker */ X for (cp = token; *cp != EOS;) /* And save */ X save(*cp++); /* The token itself */ X} X X#if STRING_FORMAL Xstparmscan(delim, dp) Xint delim; Xregister DEFBUF *dp; X/* X * Scan the string (starting with the given delimiter). X * The token is replaced if it is the only text in this string or X * character constant. The algorithm follows checkparm() above. X * Note that scanstring() has approved of the string. X */ X{ X register int c; X X /* X * Warning -- this code hasn't been tested for a while. X * It exists only to preserve compatibility with earlier X * implementations of cpp. It is not part of the Draft X * ANSI Standard C language. X */ X save(delim); X instring = TRUE; X while ((c = get()) != delim X && c != '\n' X && c != EOF_CHAR) { X if (type[c] == LET) /* Maybe formal parm */ X checkparm(c, dp); X else { X save(c); X if (c == '\\') X save(get()); X } X } X instring = FALSE; X if (c != delim) X cerror("Unterminated string in macro body", NULLST); X save(c); X} X#else Xstparmscan(delim) Xint delim; X/* X * Normal string parameter scan. X */ X{ X register char *wp; X register int i; X extern int save(); X X wp = workp; /* Here's where it starts */ X if (!scanstring(delim, save)) X return; /* Exit on scanstring error */ X workp[-1] = EOS; /* Erase trailing quote */ X wp++; /* -> first string content byte */ X for (i = 0; i < nargs; i++) { X if (streq(parlist[i], wp)) { X *wp++ = MAC_PARM + PAR_MAC; /* Stuff a magic marker */ X *wp++ = (i + MAC_PARM); /* Make a formal marker */ X *wp = wp[-3]; /* Add on closing quote */ X workp = wp + 1; /* Reset string end */ X return; X } X } X workp[-1] = wp[-1]; /* Nope, reset end quote. */ X} X#endif X Xdoundef() X/* X * Remove the symbol from the defined list. X * Called from the #control processor. X */ X{ X register int c; X X if (type[(c = skipws())] != LET) X cerror("Illegal #undef argument", NULLST); X else { X scanid(c); /* Get name to token[] */ X if (defendel(token, TRUE) == NULL) { X cwarn("Symbol \"%s\" not defined in #undef", token); X } X } X} X Xtextput(text) Xchar *text; X/* X * Put the string in the parm[] buffer. X */ X{ X register int size; X X size = strlen(text) + 1; X if ((parmp + size) >= &parm[NPARMWORK]) X cfatal("Macro work area overflow", NULLST); X else { X strcpy(parmp, text); X parmp += size; X } X} X Xcharput(c) Xregister int c; X/* X * Put the byte in the parm[] buffer. X */ X{ X if (parmp >= &parm[NPARMWORK]) X cfatal("Macro work area overflow", NULLST); X else { X *parmp++ = c; X } X} X X/* X * M a c r o E x p a n s i o n X */ X Xstatic DEFBUF *macro; /* Catches start of infinite macro */ X Xexpand(tokenp) Xregister DEFBUF *tokenp; X/* X * Expand a macro. Called from the cpp mainline routine (via subroutine X * macroid()) when a token is found in the symbol table. It calls X * expcollect() to parse actual parameters, checking for the correct number. X * It then creates a "file" containing a single line containing the X * macro with actual parameters inserted appropriately. This is X * "pushed back" onto the input stream. (When the get() routine runs X * off the end of the macro line, it will dismiss the macro itself.) X */ X{ X register int c; X register FILEINFO *file; X extern FILEINFO *getfile(); X X#if DEBUG X if (debug) X dumpadef("expand entry", tokenp); X#endif X /* X * If no macro is pending, save the name of this macro X * for an eventual error message. X */ X if (recursion++ == 0) X macro = tokenp; X else if (recursion == RECURSION_LIMIT) { X cerror("Recursive macro definition of \"%s\"", tokenp->name); X fprintf(stderr, "(Defined by \"%s\")\n", macro->name); X if (rec_recover) { X do { X c = get(); X } while (infile != NULL && infile->fp == NULL); X unget(); X recursion = 0; X return; X } X } X /* X * Here's a macro to expand. X */ X nargs = 0; /* Formals counter */ X parmp = parm; /* Setup parm buffer */ X switch (tokenp->nargs) { X case (-2): /* __LINE__ */ X sprintf(work, "%d", line); X ungetstring(work); X break; X X case (-3): /* __FILE__ */ X for (file = infile; file != NULL; file = file->parent) { X if (file->fp != NULL) { X sprintf(work, "\"%s\"", (file->progname != NULL) X ? file->progname : file->filename); X ungetstring(work); X break; X } X } X break; X X default: X /* X * Nothing funny about this macro. X */ X if (tokenp->nargs < 0) X cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name); X while ((c = skipws()) == '\n') /* Look for (, skipping */ X wrongline = TRUE; /* spaces and newlines */ X if (c != '(') { X /* X * If the programmer writes X * #define foo() ... X * ... X * foo [no ()] X * just write foo to the output stream. X */ X unget(); X cwarn("Macro \"%s\" needs arguments", tokenp->name); X fputs(tokenp->name, stdout); X return; X } X else if (expcollect()) { /* Collect arguments */ X if (tokenp->nargs != nargs) { /* Should be an error? */ X cwarn("Wrong number of macro arguments for \"%s\"", X tokenp->name); X } X#if DEBUG X if (debug) X dumpparm("expand"); X#endif X } /* Collect arguments */ X case DEF_NOARGS: /* No parameters just stuffs */ X expstuff(tokenp); /* Do actual parameters */ X } /* nargs switch */ X} X XFILE_LOCAL int Xexpcollect() X/* X * Collect the actual parameters for this macro. TRUE if ok. X */ X{ X register int c; X register int paren; /* For embedded ()'s */ X extern int charput(); X X for (;;) { X paren = 0; /* Collect next arg. */ X while ((c = skipws()) == '\n') /* Skip over whitespace */ X wrongline = TRUE; /* and newlines. */ X if (c == ')') { /* At end of all args? */ X /* X * Note that there is a guard byte in parm[] X * so we don't have to check for overflow here. X */ X *parmp = EOS; /* Make sure terminated */ X break; /* Exit collection loop */ X } X else if (nargs >= LASTPARM) X cfatal("Too many arguments in macro expansion", NULLST); X parlist[nargs++] = parmp; /* At start of new arg */ X for (;; c = cget()) { /* Collect arg's bytes */ X if (c == EOF_CHAR) { X cerror("end of file within macro argument", NULLST); X return (FALSE); /* Sorry. */ X } X else if (c == '\\') { /* Quote next character */ X charput(c); /* Save the \ for later */ X charput(cget()); /* Save the next char. */ X continue; /* And go get another */ X } X else if (type[c] == QUO) { /* Start of string? */ X scanstring(c, charput); /* Scan it off */ X continue; /* Go get next char */ X } X else if (c == '(') /* Worry about balance */ X paren++; /* To know about commas */ X else if (c == ')') { /* Other side too */ X if (paren == 0) { /* At the end? */ X unget(); /* Look at it later */ X break; /* Exit arg getter. */ X } X paren--; /* More to come. */ X } X else if (c == ',' && paren == 0) /* Comma delimits args */ X break; X else if (c == '\n') /* Newline inside arg? */ X wrongline = TRUE; /* We'll need a #line */ X charput(c); /* Store this one */ X } /* Collect an argument */ X charput(EOS); /* Terminate argument */ X#if DEBUG X if (debug) X printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]); X#endif X } /* Collect all args. */ X return (TRUE); /* Normal return */ X} X XFILE_LOCAL Xexpstuff(tokenp) XDEFBUF *tokenp; /* Current macro being expanded */ X/* X * Stuff the macro body, replacing formal parameters by actual parameters. X */ X{ X register int c; /* Current character */ X register char *inp; /* -> repl string */ X register char *defp; /* -> macro output buff */ X int size; /* Actual parm. size */ X char *defend; /* -> output buff end */ X int string_magic; /* String formal hack */ X FILEINFO *file; /* Funny #include */ X extern FILEINFO *getfile(); X X file = getfile(NBUFF, tokenp->name); X inp = tokenp->repl; /* -> macro replacement */ X defp = file->buffer; /* -> output buffer */ X defend = defp + (NBUFF - 1); /* Note its end */ X if (inp != NULL) { X while ((c = (*inp++ & 0xFF)) != EOS) { X if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) { X string_magic = (c == (MAC_PARM + PAR_MAC)); X if (string_magic) X c = (*inp++ & 0xFF); X /* X * Replace formal parameter by actual parameter string. X */ X if ((c -= MAC_PARM) < nargs) { X size = strlen(parlist[c]); X if ((defp + size) >= defend) X goto nospace; X /* X * Erase the extra set of quotes. X */ X if (string_magic && defp[-1] == parlist[c][0]) { X strcpy(defp-1, parlist[c]); X defp += (size - 2); X } X else { X strcpy(defp, parlist[c]); X defp += size; X } X } X } X else if (defp >= defend) { Xnospace: cfatal("Out of space in macro \"%s\" arg expansion", X tokenp->name); X } X else { X *defp++ = c; X } X } X } X *defp = EOS; X#if DEBUG X if (debug > 1) X printf("macroline: \"%s\"\n", file->buffer); X#endif X} X X#if DEBUG Xdumpparm(why) Xchar *why; X/* X * Dump parameter list. X */ X{ X register int i; X X printf("dump of %d parameters (%d bytes total) %s\n", X nargs, parmp - parm, why); X for (i = 0; i < nargs; i++) { X printf("parm[%d] (%d) = \"%s\"\n", X i + 1, strlen(parlist[i]), parlist[i]); X } X} X#endif END-of-cpp4.c exit nethack-3.4.3/sys/unix/cpp3.shr0100644000000000000000000014516207764735041015047 0ustar rootroot# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # cpp5.c # cpp6.c # echo x - cpp5.c sed 's/^X//' >cpp5.c << 'END-of-cpp5.c' X/* X * C P P 5 . C X * E x p r e s s i o n E v a l u a t i o n X * X * Edit History X * 31-Aug-84 MM USENET net.sources release X * 04-Oct-84 MM __LINE__ and __FILE__ must call ungetstring() X * so they work correctly with token concatenation. X * Added string formal recognition. X * 25-Oct-84 MM "Short-circuit" evaluate #if's so that we X * don't print unnecessary error messages for X * #if !defined(FOO) && FOO != 0 && 10 / FOO ... X * 31-Oct-84 ado/MM Added token concatenation X * 6-Nov-84 MM Split from #define stuff, added sizeof stuff X * 19-Nov-84 ado #if error returns TRUE for (sigh) compatibility X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X X/* X * Evaluate an #if expression. X */ X Xstatic char *opname[] = { /* For debug and error messages */ X"end of expression", "val", "id", X "+", "-", "*", "/", "%", X "<<", ">>", "&", "|", "^", X "==", "!=", "<", "<=", ">=", ">", X "&&", "||", "?", ":", ",", X "unary +", "unary -", "~", "!", "(", ")", "(none)", X}; X X/* X * opdope[] has the operator precedence: X * Bits X * 7 Unused (so the value is always positive) X * 6-2 Precedence (000x .. 017x) X * 1-0 Binary op. flags: X * 01 The binop flag should be set/cleared when this op is seen. X * 10 The new value of the binop flag. X * Note: Expected, New binop X * constant 0 1 Binop, end, or ) should follow constants X * End of line 1 0 End may not be preceeded by an operator X * binary 1 0 Binary op follows a value, value follows. X * unary 0 0 Unary op doesn't follow a value, value follows X * ( 0 0 Doesn't follow value, value or unop follows X * ) 1 1 Follows value. Op follows. X */ X Xstatic char opdope[OP_MAX] = { X 0001, /* End of expression */ X 0002, /* Digit */ X 0000, /* Letter (identifier) */ X 0141, 0141, 0151, 0151, 0151, /* ADD, SUB, MUL, DIV, MOD */ X 0131, 0131, 0101, 0071, 0071, /* ASL, ASR, AND, OR, XOR */ X 0111, 0111, 0121, 0121, 0121, 0121, /* EQ, NE, LT, LE, GE, GT */ X 0061, 0051, 0041, 0041, 0031, /* ANA, ORO, QUE, COL, CMA */ X/* X * Unary op's follow X */ X 0160, 0160, 0160, 0160, /* NEG, PLU, COM, NOT */ X 0170, 0013, 0023, /* LPA, RPA, END */ X}; X/* X * OP_QUE and OP_RPA have alternate precedences: X */ X#define OP_RPA_PREC 0013 X#define OP_QUE_PREC 0034 X X/* X * S_ANDOR and S_QUEST signal "short-circuit" boolean evaluation, so that X * #if FOO != 0 && 10 / FOO ... X * doesn't generate an error message. They are stored in optab.skip. X */ X#define S_ANDOR 2 X#define S_QUEST 1 X Xtypedef struct optab { X char op; /* Operator */ X char prec; /* Its precedence */ X char skip; /* Short-circuit: TRUE to skip */ X} OPTAB; Xstatic int evalue; /* Current value from evallex() */ X X#ifdef nomacargs XFILE_LOCAL int Xisbinary(op) Xregister int op; X{ X return (op >= FIRST_BINOP && op <= LAST_BINOP); X} X XFILE_LOCAL int Xisunary(op) Xregister int op; X{ X return (op >= FIRST_UNOP && op <= LAST_UNOP); X} X#else X#define isbinary(op) (op >= FIRST_BINOP && op <= LAST_BINOP) X#define isunary(op) (op >= FIRST_UNOP && op <= LAST_UNOP) X#endif X X/* X * The following definitions are used to specify basic variable sizes. X */ X X#ifndef S_CHAR X#define S_CHAR (sizeof (char)) X#endif X#ifndef S_SINT X#define S_SINT (sizeof (short int)) X#endif X#ifndef S_INT X#define S_INT (sizeof (int)) X#endif X#ifndef S_LINT X#define S_LINT (sizeof (long int)) X#endif X#ifndef S_FLOAT X#define S_FLOAT (sizeof (float)) X#endif X#ifndef S_DOUBLE X#define S_DOUBLE (sizeof (double)) X#endif X#ifndef S_PCHAR X#define S_PCHAR (sizeof (char *)) X#endif X#ifndef S_PSINT X#define S_PSINT (sizeof (short int *)) X#endif X#ifndef S_PINT X#define S_PINT (sizeof (int *)) X#endif X#ifndef S_PLINT X#define S_PLINT (sizeof (long int *)) X#endif X#ifndef S_PFLOAT X#define S_PFLOAT (sizeof (float *)) X#endif X#ifndef S_PDOUBLE X#define S_PDOUBLE (sizeof (double *)) X#endif X#ifndef S_PFPTR X#define S_PFPTR (sizeof (int (*)())) X#endif X Xtypedef struct types { X short type; /* This is the bit if */ X char *name; /* this is the token word */ X} TYPES; X Xstatic TYPES basic_types[] = { X { T_CHAR, "char", }, X { T_INT, "int", }, X { T_FLOAT, "float", }, X { T_DOUBLE, "double", }, X { T_SHORT, "short", }, X { T_LONG, "long", }, X { T_SIGNED, "signed", }, X { T_UNSIGNED, "unsigned", }, X { 0, NULL, }, /* Signal end */ X}; X X/* X * Test_table[] is used to test for illegal combinations. X */ Xstatic short test_table[] = { X T_FLOAT | T_DOUBLE | T_LONG | T_SHORT, X T_FLOAT | T_DOUBLE | T_CHAR | T_INT, X T_FLOAT | T_DOUBLE | T_SIGNED | T_UNSIGNED, X T_LONG | T_SHORT | T_CHAR, X 0 /* end marker */ X}; X X/* X * The order of this table is important -- it is also referenced by X * the command line processor to allow run-time overriding of the X * built-in size values. The order must not be changed: X * char, short, int, long, float, double (func pointer) X */ XSIZES size_table[] = { X { T_CHAR, S_CHAR, S_PCHAR }, /* char */ X { T_SHORT, S_SINT, S_PSINT }, /* short int */ X { T_INT, S_INT, S_PINT }, /* int */ X { T_LONG, S_LINT, S_PLINT }, /* long */ X { T_FLOAT, S_FLOAT, S_PFLOAT }, /* float */ X { T_DOUBLE, S_DOUBLE, S_PDOUBLE }, /* double */ X { T_FPTR, 0, S_PFPTR }, /* int (*()) */ X { 0, 0, 0 }, /* End of table */ X}; X Xint Xeval() X/* X * Evaluate an expression. Straight-forward operator precedence. X * This is called from control() on encountering an #if statement. X * It calls the following routines: X * evallex Lexical analyser -- returns the type and value of X * the next input token. X * evaleval Evaluate the current operator, given the values on X * the value stack. Returns a pointer to the (new) X * value stack. X * For compatiblity with older cpp's, this return returns 1 (TRUE) X * if a syntax error is detected. X */ X{ X register int op; /* Current operator */ X register int *valp; /* -> value vector */ X register OPTAB *opp; /* Operator stack */ X int prec; /* Op precedence */ X int binop; /* Set if binary op. needed */ X int op1; /* Operand from stack */ X int skip; /* For short-circuit testing */ X int value[NEXP]; /* Value stack */ X OPTAB opstack[NEXP]; /* Operand stack */ X extern int *evaleval(); /* Does actual evaluation */ X X valp = value; X opp = opstack; X opp->op = OP_END; /* Mark bottom of stack */ X opp->prec = opdope[OP_END]; /* And its precedence */ X opp->skip = 0; /* Not skipping now */ X binop = 0; Xagain: ; X#ifdef DEBUG_EVAL X printf("In #if at again: skip = %d, binop = %d, line is: %s", X opp->skip, binop, infile->bptr); X#endif X if ((op = evallex(opp->skip)) == OP_SUB && binop == 0) X op = OP_NEG; /* Unary minus */ X else if (op == OP_ADD && binop == 0) X op = OP_PLU; /* Unary plus */ X else if (op == OP_FAIL) X return (1); /* Error in evallex */ X#ifdef DEBUG_EVAL X printf("op = %s, opdope = %03o, binop = %d, skip = %d\n", X opname[op], opdope[op], binop, opp->skip); X#endif X if (op == DIG) { /* Value? */ X if (binop != 0) { X cerror("misplaced constant in #if", NULLST); X return (1); X } X else if (valp >= &value[NEXP-1]) { X cerror("#if value stack overflow", NULLST); X return (1); X } X else { X#ifdef DEBUG_EVAL X printf("pushing %d onto value stack[%d]\n", X evalue, valp - value); X#endif X *valp++ = evalue; X binop = 1; X } X goto again; X } X else if (op > OP_END) { X cerror("Illegal #if line", NULLST); X return (1); X } X prec = opdope[op]; X if (binop != (prec & 1)) { X cerror("Operator %s in incorrect context", opname[op]); X return (1); X } X binop = (prec & 2) >> 1; X for (;;) { X#ifdef DEBUG_EVAL X printf("op %s, prec %d., stacked op %s, prec %d, skip %d\n", X opname[op], prec, opname[opp->op], opp->prec, opp->skip); X#endif X if (prec > opp->prec) { X if (op == OP_LPA) X prec = OP_RPA_PREC; X else if (op == OP_QUE) X prec = OP_QUE_PREC; X op1 = opp->skip; /* Save skip for test */ X /* X * Push operator onto op. stack. X */ X opp++; X if (opp >= &opstack[NEXP]) { X cerror("expression stack overflow at op \"%s\"", X opname[op]); X return (1); X } X opp->op = op; X opp->prec = prec; X skip = (valp[-1] != 0); /* Short-circuit tester */ X /* X * Do the short-circuit stuff here. Short-circuiting X * stops automagically when operators are evaluated. X */ X if ((op == OP_ANA && !skip) X || (op == OP_ORO && skip)) X opp->skip = S_ANDOR; /* And/or skip starts */ X else if (op == OP_QUE) /* Start of ?: operator */ X opp->skip = (op1 & S_ANDOR) | ((!skip) ? S_QUEST : 0); X else if (op == OP_COL) { /* : inverts S_QUEST */ X opp->skip = (op1 & S_ANDOR) X | (((op1 & S_QUEST) != 0) ? 0 : S_QUEST); X } X else { /* Other ops leave */ X opp->skip = op1; /* skipping unchanged. */ X } X#ifdef DEBUG_EVAL X printf("stacking %s, valp[-1] == %d at %s", X opname[op], valp[-1], infile->bptr); X dumpstack(opstack, opp, value, valp); X#endif X goto again; X } X /* X * Pop operator from op. stack and evaluate it. X * End of stack and '(' are specials. X */ X skip = opp->skip; /* Remember skip value */ X switch ((op1 = opp->op)) { /* Look at stacked op */ X case OP_END: /* Stack end marker */ X if (op == OP_EOE) X return (valp[-1]); /* Finished ok. */ X goto again; /* Read another op. */ X X case OP_LPA: /* ( on stack */ X if (op != OP_RPA) { /* Matches ) on input */ X cerror("unbalanced paren's, op is \"%s\"", opname[op]); X return (1); X } X opp--; /* Unstack it */ X /* goto again; -- Fall through */ X X case OP_QUE: X goto again; /* Evaluate true expr. */ X X case OP_COL: /* : on stack. */ X opp--; /* Unstack : */ X if (opp->op != OP_QUE) { /* Matches ? on stack? */ X cerror("Misplaced '?' or ':', previous operator is %s", X opname[opp->op]); X return (1); X } X /* X * Evaluate op1. X */ X default: /* Others: */ X opp--; /* Unstack the operator */ X#ifdef DEBUG_EVAL X printf("Stack before evaluation of %s\n", opname[op1]); X dumpstack(opstack, opp, value, valp); X#endif X valp = evaleval(valp, op1, skip); X#ifdef DEBUG_EVAL X printf("Stack after evaluation\n"); X dumpstack(opstack, opp, value, valp); X#endif X } /* op1 switch end */ X } /* Stack unwind loop */ X} X XFILE_LOCAL int Xevallex(skip) Xint skip; /* TRUE if short-circuit evaluation */ X/* X * Return next eval operator or value. Called from eval(). It X * calls a special-purpose routines for 'char' strings and X * numeric values: X * evalchar called to evaluate 'x' X * evalnum called to evaluate numbers. X */ X{ X register int c, c1, t; X Xagain: do { /* Collect the token */ X c = skipws(); X if ((c = macroid(c)) == EOF_CHAR || c == '\n') { X unget(); X return (OP_EOE); /* End of expression */ X } X } while ((t = type[c]) == LET && catenate()); X if (t == INV) { /* Total nonsense */ X if (!skip) { X if (isascii(c) && isprint(c)) X cierror("illegal character '%c' in #if", c); X else X cierror("illegal character (%d decimal) in #if", c); X } X return (OP_FAIL); X } X else if (t == QUO) { /* ' or " */ X if (c == '\'') { /* Character constant */ X evalue = evalchar(skip); /* Somewhat messy */ X#ifdef DEBUG_EVAL X printf("evalchar returns %d.\n", evalue); X#endif X return (DIG); /* Return a value */ X } X cerror("Can't use a string in an #if", NULLST); X return (OP_FAIL); X } X else if (t == LET) { /* ID must be a macro */ X if (streq(token, "defined")) { /* Or defined name */ X c1 = c = skipws(); X if (c == '(') /* Allow defined(name) */ X c = skipws(); X if (type[c] == LET) { X evalue = (lookid(c) != NULL); X if (c1 != '(' /* Need to balance */ X || skipws() == ')') /* Did we balance? */ X return (DIG); /* Parsed ok */ X } X cerror("Bad #if ... defined() syntax", NULLST); X return (OP_FAIL); X } X else if (streq(token, "sizeof")) /* New sizeof hackery */ X return (dosizeof()); /* Gets own routine */ X /* X * The Draft ANSI C Standard says that an undefined symbol X * in an #if has the value zero. We are a bit pickier, X * warning except where the programmer was careful to write X * #if defined(foo) ? foo : 0 X */ X#ifdef VERBOSE X if (!skip) X cwarn("undefined symbol \"%s\" in #if, 0 used", token); X#endif X evalue = 0; X return (DIG); X } X else if (t == DIG) { /* Numbers are harder */ X evalue = evalnum(c); X#ifdef DEBUG_EVAL X printf("evalnum returns %d.\n", evalue); X#endif X } X else if (strchr("!=<>&|\\", c) != NULL) { X /* X * Process a possible multi-byte lexeme. X */ X c1 = cget(); /* Peek at next char */ X switch (c) { X case '!': X if (c1 == '=') X return (OP_NE); X break; X X case '=': X if (c1 != '=') { /* Can't say a=b in #if */ X unget(); X cerror("= not allowed in #if", NULLST); X return (OP_FAIL); X } X return (OP_EQ); X X case '>': X case '<': X if (c1 == c) X return ((c == '<') ? OP_ASL : OP_ASR); X else if (c1 == '=') X return ((c == '<') ? OP_LE : OP_GE); X break; X X case '|': X case '&': X if (c1 == c) X return ((c == '|') ? OP_ORO : OP_ANA); X break; X X case '\\': X if (c1 == '\n') /* Multi-line if */ X goto again; X cerror("Unexpected \\ in #if", NULLST); X return (OP_FAIL); X } X unget(); X } X return (t); X} X XFILE_LOCAL int Xdosizeof() X/* X * Process the sizeof (basic type) operation in an #if string. X * Sets evalue to the size and returns X * DIG success X * OP_FAIL bad parse or something. X */ X{ X register int c; X register TYPES *tp; X register SIZES *sizp; X register short *testp; X short typecode; X X if ((c = skipws()) != '(') X goto nogood; X /* X * Scan off the tokens. X */ X typecode = 0; X while ((c = skipws())) { X if ((c = macroid(c)) == EOF_CHAR || c == '\n') X goto nogood; /* End of line is a bug */ X else if (c == '(') { /* thing (*)() func ptr */ X if (skipws() == '*' X && skipws() == ')') { /* We found (*) */ X if (skipws() != '(') /* Let () be optional */ X unget(); X else if (skipws() != ')') X goto nogood; X typecode |= T_FPTR; /* Function pointer */ X } X else { /* Junk is a bug */ X goto nogood; X } X } X else if (type[c] != LET) /* Exit if not a type */ X break; X else if (!catenate()) { /* Maybe combine tokens */ X /* X * Look for this unexpandable token in basic_types. X * The code accepts "int long" as well as "long int" X * which is a minor bug as bugs go (and one shared with X * a lot of C compilers). X */ X for (tp = basic_types; tp->name != NULLST; tp++) { X if (streq(token, tp->name)) X break; X } X if (tp->name == NULLST) { X cerror("#if sizeof, unknown type \"%s\"", token); X return (OP_FAIL); X } X typecode |= tp->type; /* Or in the type bit */ X } X } X /* X * We are at the end of the type scan. Chew off '*' if necessary. X */ X if (c == '*') { X typecode |= T_PTR; X c = skipws(); X } X if (c == ')') { /* Last syntax check */ X for (testp = test_table; *testp != 0; testp++) { X if (!bittest(typecode & *testp)) { X cerror("#if ... sizeof: illegal type combination", NULLST); X return (OP_FAIL); X } X } X /* X * We assume that all function pointers are the same size: X * sizeof (int (*)()) == sizeof (float (*)()) X * We assume that signed and unsigned don't change the size: X * sizeof (signed int) == (sizeof unsigned int) X */ X if ((typecode & T_FPTR) != 0) /* Function pointer */ X typecode = T_FPTR | T_PTR; X else { /* Var or var * datum */ X typecode &= ~(T_SIGNED | T_UNSIGNED); X if ((typecode & (T_SHORT | T_LONG)) != 0) X typecode &= ~T_INT; X } X if ((typecode & ~T_PTR) == 0) { X cerror("#if sizeof() error, no type specified", NULLST); X return (OP_FAIL); X } X /* X * Exactly one bit (and possibly T_PTR) may be set. X */ X for (sizp = size_table; sizp->bits != 0; sizp++) { X if ((typecode & ~T_PTR) == sizp->bits) { X evalue = ((typecode & T_PTR) != 0) X ? sizp->psize : sizp->size; X return (DIG); X } X } /* We shouldn't fail */ X cierror("#if ... sizeof: bug, unknown type code 0x%x", typecode); X return (OP_FAIL); X } X Xnogood: unget(); X cerror("#if ... sizeof() syntax error", NULLST); X return (OP_FAIL); X} X XFILE_LOCAL int Xbittest(value) X/* X * TRUE if value is zero or exactly one bit is set in value. X */ X{ X#if (4096 & ~(-4096)) == 0 X return ((value & ~(-value)) == 0); X#else X /* X * Do it the hard way (for non 2's complement machines) X */ X return (value == 0 || value ^ (value - 1) == (value * 2 - 1)); X#endif X} X XFILE_LOCAL int Xevalnum(c) Xregister int c; X/* X * Expand number for #if lexical analysis. Note: evalnum recognizes X * the unsigned suffix, but only returns a signed int value. X */ X{ X register int value; X register int base; X register int c1; X X if (c != '0') X base = 10; X else if ((c = cget()) == 'x' || c == 'X') { X base = 16; X c = cget(); X } X else base = 8; X value = 0; X for (;;) { X c1 = c; X if (isascii(c) && isupper(c1)) X c1 = tolower(c1); X if (c1 >= 'a') X c1 -= ('a' - 10); X else c1 -= '0'; X if (c1 < 0 || c1 >= base) X break; X value *= base; X value += c1; X c = cget(); X } X if (c == 'u' || c == 'U') /* Unsigned nonsense */ X c = cget(); X unget(); X return (value); X} X XFILE_LOCAL int Xevalchar(skip) Xint skip; /* TRUE if short-circuit evaluation */ X/* X * Get a character constant X */ X{ X register int c; X register int value; X register int count; X X instring = TRUE; X if ((c = cget()) == '\\') { X switch ((c = cget())) { X case 'a': /* New in Standard */ X#if ('a' == '\a' || '\a' == ALERT) X value = ALERT; /* Use predefined value */ X#else X value = '\a'; /* Use compiler's value */ X#endif X break; X X case 'b': X value = '\b'; X break; X X case 'f': X value = '\f'; X break; X X case 'n': X value = '\n'; X break; X X case 'r': X value = '\r'; X break; X X case 't': X value = '\t'; X break; X X case 'v': /* New in Standard */ X#if ('v' == '\v' || '\v' == VT) X value = VT; /* Use predefined value */ X#else X value = '\v'; /* Use compiler's value */ X#endif X break; X X case 'x': /* '\xFF' */ X count = 3; X value = 0; X while ((((c = get()) >= '0' && c <= '9') X || (c >= 'a' && c <= 'f') X || (c >= 'A' && c <= 'F')) X && (--count >= 0)) { X value *= 16; X value += (c <= '9') ? (c - '0') : ((c & 0xF) + 9); X } X unget(); X break; X X default: X if (c >= '0' && c <= '7') { X count = 3; X value = 0; X while (c >= '0' && c <= '7' && --count >= 0) { X value *= 8; X value += (c - '0'); X c = get(); X } X unget(); X } X else value = c; X break; X } X } X else if (c == '\'') X value = 0; X else value = c; X /* X * We warn on multi-byte constants and try to hack X * (big|little)endian machines. X */ X#if BIG_ENDIAN X count = 0; X#endif X while ((c = get()) != '\'' && c != EOF_CHAR && c != '\n') { X if (!skip) X ciwarn("multi-byte constant '%c' isn't portable", c); X#if BIG_ENDIAN X count += BITS_CHAR; X value += (c << count); X#else X value <<= BITS_CHAR; X value += c; X#endif X } X instring = FALSE; X return (value); X} X XFILE_LOCAL int * Xevaleval(valp, op, skip) Xregister int *valp; Xint op; Xint skip; /* TRUE if short-circuit evaluation */ X/* X * Apply the argument operator to the data on the value stack. X * One or two values are popped from the value stack and the result X * is pushed onto the value stack. X * X * OP_COL is a special case. X * X * evaleval() returns the new pointer to the top of the value stack. X */ X{ X register int v1, v2; X X if (isbinary(op)) X v2 = *--valp; X v1 = *--valp; X#ifdef DEBUG_EVAL X printf("%s op %s", (isbinary(op)) ? "binary" : "unary", X opname[op]); X if (isbinary(op)) X printf(", v2 = %d.", v2); X printf(", v1 = %d.\n", v1); X#endif X switch (op) { X case OP_EOE: X break; X X case OP_ADD: X v1 += v2; X break; X X case OP_SUB: X v1 -= v2; X break; X X case OP_MUL: X v1 *= v2; X break; X X case OP_DIV: X case OP_MOD: X if (v2 == 0) { X if (!skip) { X cwarn("%s by zero in #if, zero result assumed", X (op == OP_DIV) ? "divide" : "mod"); X } X v1 = 0; X } X else if (op == OP_DIV) X v1 /= v2; X else X v1 %= v2; X break; X X case OP_ASL: X v1 <<= v2; X break; X X case OP_ASR: X v1 >>= v2; X break; X X case OP_AND: X v1 &= v2; X break; X X case OP_OR: X v1 |= v2; X break; X X case OP_XOR: X v1 ^= v2; X break; X X case OP_EQ: X v1 = (v1 == v2); X break; X X case OP_NE: X v1 = (v1 != v2); X break; X X case OP_LT: X v1 = (v1 < v2); X break; X X case OP_LE: X v1 = (v1 <= v2); X break; X X case OP_GE: X v1 = (v1 >= v2); X break; X X case OP_GT: X v1 = (v1 > v2); X break; X X case OP_ANA: X v1 = (v1 && v2); X break; X X case OP_ORO: X v1 = (v1 || v2); X break; X X case OP_COL: X /* X * v1 has the "true" value, v2 the "false" value. X * The top of the value stack has the test. X */ X v1 = (*--valp) ? v1 : v2; X break; X X case OP_NEG: X v1 = (-v1); X break; X X case OP_PLU: X break; X X case OP_COM: X v1 = ~v1; X break; X X case OP_NOT: X v1 = !v1; X break; X X default: X cierror("#if bug, operand = %d.", op); X v1 = 0; X } X *valp++ = v1; X return (valp); X} X X#ifdef DEBUG_EVAL Xdumpstack(opstack, opp, value, valp) XOPTAB opstack[NEXP]; /* Operand stack */ Xregister OPTAB *opp; /* Operator stack */ Xint value[NEXP]; /* Value stack */ Xregister int *valp; /* -> value vector */ X{ X printf("index op prec skip name -- op stack at %s", infile->bptr); X while (opp > opstack) { X printf(" [%2d] %2d %03o %d %s\n", opp - opstack, X opp->op, opp->prec, opp->skip, opname[opp->op]); X opp--; X } X while (--valp >= value) { X printf("value[%d] = %d\n", (valp - value), *valp); X } X} X#endif X END-of-cpp5.c echo x - cpp6.c sed 's/^X//' >cpp6.c << 'END-of-cpp6.c' X/* X * C P P 6 . C X * S u p p o r t R o u t i n e s X * X * Edit History X * 25-May-84 MM Added 8-bit support to type table. X * 30-May-84 ARF sharp() should output filename in quotes X * 02-Aug-84 MM Newline and #line hacking. sharp() now in cpp1.c X * 31-Aug-84 MM USENET net.sources release X * 11-Sep-84 ado/MM Keepcomments, also line number pathological X * 12-Sep-84 ado/MM bug if comment changes to space and we unget later. X * 03-Oct-84 gkr/MM Fixed scannumber bug for '.e' (as in struct.element). X * 04-Oct-84 MM Added ungetstring() for token concatenation X * 08-Oct-84 MM Yet another attack on number scanning X * 31-Oct-84 ado Parameterized $ in identifiers X * 2-Nov-84 MM Token concatenation is messier than I thought X * 6-Dec-84 MM \ is everywhere invisible. X */ X X#include X#include X#include "cppdef.h" X#include "cpp.h" X X/* X * skipnl() skips over input text to the end of the line. X * skipws() skips over "whitespace" (spaces or tabs), but X * not skip over the end of the line. It skips over X * TOK_SEP, however (though that shouldn't happen). X * scanid() reads the next token (C identifier) into token[]. X * The caller has already read the first character of X * the identifier. Unlike macroid(), the token is X * never expanded. X * macroid() reads the next token (C identifier) into token[]. X * If it is a #defined macro, it is expanded, and X * macroid() returns TRUE, otherwise, FALSE. X * catenate() Does the dirty work of token concatenation, TRUE if it did. X * scanstring() Reads a string from the input stream, calling X * a user-supplied function for each character. X * This function may be output() to write the X * string to the output file, or save() to save X * the string in the work buffer. X * scannumber() Reads a C numeric constant from the input stream, X * calling the user-supplied function for each X * character. (output() or save() as noted above.) X * save() Save one character in the work[] buffer. X * savestring() Saves a string in malloc() memory. X * getfile() Initialize a new FILEINFO structure, called when X * #include opens a new file, or a macro is to be X * expanded. X * getmem() Get a specified number of bytes from malloc memory. X * output() Write one character to stdout (calling putchar) -- X * implemented as a function so its address may be X * passed to scanstring() and scannumber(). X * lookid() Scans the next token (identifier) from the input X * stream. Looks for it in the #defined symbol table. X * Returns a pointer to the definition, if found, or NULL X * if not present. The identifier is stored in token[]. X * defnedel() Define enter/delete subroutine. Updates the X * symbol table. X * get() Read the next byte from the current input stream, X * handling end of (macro/file) input and embedded X * comments appropriately. Note that the global X * instring is -- essentially -- a parameter to get(). X * cget() Like get(), but skip over TOK_SEP. X * unget() Push last gotten character back on the input stream. X * cerror(), cwarn(), cfatal(), cierror(), ciwarn() X * These routines format an print messages to the user. X * cerror & cwarn take a format and a single string argument. X * cierror & ciwarn take a format and a single int (char) argument. X * cfatal takes a format and a single string argument. X */ X X/* X * This table must be rewritten for a non-Ascii machine. X * X * Note that several "non-visible" characters have special meaning: X * Hex 1D DEF_MAGIC -- a flag to prevent #define recursion. X * Hex 1E TOK_SEP -- a delimiter for token concatenation X * Hex 1F COM_SEP -- a zero-width whitespace for comment concatenation X */ X#if TOK_SEP != 0x1E || COM_SEP != 0x1F || DEF_MAGIC != 0x1D X << error type table isn't correct >> X#endif X X#if OK_DOLLAR X#define DOL LET X#else X#define DOL 000 X#endif X Xchar type[256] = { /* Character type codes Hex */ X END, 000, 000, 000, 000, 000, 000, 000, /* 00 */ X 000, SPA, 000, 000, 000, 000, 000, 000, /* 08 */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 10 */ X 000, 000, 000, 000, 000, LET, 000, SPA, /* 18 */ X SPA,OP_NOT, QUO, 000, DOL,OP_MOD,OP_AND, QUO, /* 20 !"#$%&' */ XOP_LPA,OP_RPA,OP_MUL,OP_ADD, 000,OP_SUB, DOT,OP_DIV, /* 28 ()*+,-./ */ X DIG, DIG, DIG, DIG, DIG, DIG, DIG, DIG, /* 30 01234567 */ X DIG, DIG,OP_COL, 000, OP_LT, OP_EQ, OP_GT,OP_QUE, /* 38 89:;<=>? */ X 000, LET, LET, LET, LET, LET, LET, LET, /* 40 @ABCDEFG */ X LET, LET, LET, LET, LET, LET, LET, LET, /* 48 HIJKLMNO */ X LET, LET, LET, LET, LET, LET, LET, LET, /* 50 PQRSTUVW */ X LET, LET, LET, 000, BSH, 000,OP_XOR, LET, /* 58 XYZ[\]^_ */ X 000, LET, LET, LET, LET, LET, LET, LET, /* 60 `abcdefg */ X LET, LET, LET, LET, LET, LET, LET, LET, /* 68 hijklmno */ X LET, LET, LET, LET, LET, LET, LET, LET, /* 70 pqrstuvw */ X LET, LET, LET, 000, OP_OR, 000,OP_NOT, 000, /* 78 xyz{|}~ */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X 000, 000, 000, 000, 000, 000, 000, 000, /* 80 .. FF */ X}; X Xskipnl() X/* X * Skip to the end of the current input line. X */ X{ X register int c; X X do { /* Skip to newline */ X c = get(); X } while (c != '\n' && c != EOF_CHAR); X} X Xint Xskipws() X/* X * Skip over whitespace X */ X{ X register int c; X X do { /* Skip whitespace */ X c = get(); X#if COMMENT_INVISIBLE X } while (type[c] == SPA || c == COM_SEP); X#else X } while (type[c] == SPA); X#endif X return (c); X} X Xscanid(c) Xregister int c; /* First char of id */ X/* X * Get the next token (an id) into the token buffer. X * Note: this code is duplicated in lookid(). X * Change one, change both. X */ X{ X register char *bp; X X if (c == DEF_MAGIC) /* Eat the magic token */ X c = get(); /* undefiner. */ X bp = token; X do { X if (bp < &token[IDMAX]) /* token dim is IDMAX+1 */ X *bp++ = c; X c = get(); X } while (type[c] == LET || type[c] == DIG); X unget(); X *bp = EOS; X} X Xint Xmacroid(c) Xregister int c; X/* X * If c is a letter, scan the id. if it's #defined, expand it and scan X * the next character and try again. X * X * Else, return the character. If type[c] is a LET, the token is in token. X */ X{ X register DEFBUF *dp; X X if (infile != NULL && infile->fp != NULL) X recursion = 0; X while (type[c] == LET && (dp = lookid(c)) != NULL) { X expand(dp); X c = get(); X } X return (c); X} X Xint Xcatenate() X/* X * A token was just read (via macroid). X * If the next character is TOK_SEP, concatenate the next token X * return TRUE -- which should recall macroid after refreshing X * macroid's argument. If it is not TOK_SEP, unget() the character X * and return FALSE. X */ X{ X register int c; X register char *token1; X X#if OK_CONCAT X if (get() != TOK_SEP) { /* Token concatenation */ X unget(); X return (FALSE); X } X else { X token1 = savestring(token); /* Save first token */ X c = macroid(get()); /* Scan next token */ X switch(type[c]) { /* What was it? */ X case LET: /* An identifier, ... */ X if (strlen(token1) + strlen(token) >= NWORK) X cfatal("work buffer overflow doing %s #", token1); X sprintf(work, "%s%s", token1, token); X break; X X case DIG: /* A digit string */ X strcpy(work, token1); X workp = work + strlen(work); X do { X save(c); X } while ((c = get()) != TOK_SEP); X /* X * The trailing TOK_SEP is no longer needed. X */ X save(EOS); X break; X X default: /* An error, ... */ X if (isprint(c)) X cierror("Strange character '%c' after #", c); X else X cierror("Strange character (%d.) after #", c); X strcpy(work, token1); X unget(); X break; X } X /* X * work has the concatenated token and token1 has X * the first token (no longer needed). Unget the X * new (concatenated) token after freeing token1. X * Finally, setup to read the new token. X */ X free(token1); /* Free up memory */ X ungetstring(work); /* Unget the new thing, */ X return (TRUE); X } X#else X return (FALSE); /* Not supported */ X#endif X} X Xint Xscanstring(delim, outfun) Xregister int delim; /* ' or " */ Xint (*outfun)(); /* Output function */ X/* X * Scan off a string. Warning if terminated by newline or EOF. X * outfun() outputs the character -- to a buffer if in a macro. X * TRUE if ok, FALSE if error. X */ X{ X register int c; X X instring = TRUE; /* Don't strip comments */ X (*outfun)(delim); X while ((c = get()) != delim X && c != '\n' X && c != EOF_CHAR) { X (*outfun)(c); X if (c == '\\') X (*outfun)(get()); X } X instring = FALSE; X if (c == delim) { X (*outfun)(c); X return (TRUE); X } X else { X cerror("Unterminated string", NULLST); X unget(); X return (FALSE); X } X} X Xscannumber(c, outfun) Xregister int c; /* First char of number */ Xregister int (*outfun)(); /* Output/store func */ X/* X * Process a number. We know that c is from 0 to 9 or dot. X * Algorithm from Dave Conroy's Decus C. X */ X{ X register int radix; /* 8, 10, or 16 */ X int expseen; /* 'e' seen in floater */ X int signseen; /* '+' or '-' seen */ X int octal89; /* For bad octal test */ X int dotflag; /* TRUE if '.' was seen */ X X expseen = FALSE; /* No exponent seen yet */ X signseen = TRUE; /* No +/- allowed yet */ X octal89 = FALSE; /* No bad octal yet */ X radix = 10; /* Assume decimal */ X if ((dotflag = (c == '.')) != FALSE) { /* . something? */ X (*outfun)('.'); /* Always out the dot */ X if (type[(c = get())] != DIG) { /* If not a float numb, */ X unget(); /* Rescan strange char */ X return; /* All done for now */ X } X } /* End of float test */ X else if (c == '0') { /* Octal or hex? */ X (*outfun)(c); /* Stuff initial zero */ X radix = 8; /* Assume it's octal */ X c = get(); /* Look for an 'x' */ X if (c == 'x' || c == 'X') { /* Did we get one? */ X radix = 16; /* Remember new radix */ X (*outfun)(c); /* Stuff the 'x' */ X c = get(); /* Get next character */ X } X } X for (;;) { /* Process curr. char. */ X /* X * Note that this algorithm accepts "012e4" and "03.4" X * as legitimate floating-point numbers. X */ X if (radix != 16 && (c == 'e' || c == 'E')) { X if (expseen) /* Already saw 'E'? */ X break; /* Exit loop, bad nbr. */ X expseen = TRUE; /* Set exponent seen */ X signseen = FALSE; /* We can read '+' now */ X radix = 10; /* Decimal exponent */ X } X else if (radix != 16 && c == '.') { X if (dotflag) /* Saw dot already? */ X break; /* Exit loop, two dots */ X dotflag = TRUE; /* Remember the dot */ X radix = 10; /* Decimal fraction */ X } X else if (c == '+' || c == '-') { /* 1.0e+10 */ X if (signseen) /* Sign in wrong place? */ X break; /* Exit loop, not nbr. */ X /* signseen = TRUE; */ /* Remember we saw it */ X } X else { /* Check the digit */ X switch (c) { X case '8': case '9': /* Sometimes wrong */ X octal89 = TRUE; /* Do check later */ X case '0': case '1': case '2': case '3': X case '4': case '5': case '6': case '7': X break; /* Always ok */ X X case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': X case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': X if (radix == 16) /* Alpha's are ok only */ X break; /* if reading hex. */ X default: /* At number end */ X goto done; /* Break from for loop */ X } /* End of switch */ X } /* End general case */ X (*outfun)(c); /* Accept the character */ X signseen = TRUE; /* Don't read sign now */ X c = get(); /* Read another char */ X } /* End of scan loop */ X /* X * When we break out of the scan loop, c contains the first X * character (maybe) not in the number. If the number is an X * integer, allow a trailing 'L' for long and/or a trailing 'U' X * for unsigned. If not those, push the trailing character back X * on the input stream. Floating point numbers accept a trailing X * 'L' for "long double". X */ Xdone: if (dotflag || expseen) { /* Floating point? */ X if (c == 'l' || c == 'L') { X (*outfun)(c); X c = get(); /* Ungotten later */ X } X } X else { /* Else it's an integer */ X /* X * We know that dotflag and expseen are both zero, now: X * dotflag signals "saw 'L'", and X * expseen signals "saw 'U'". X */ X for (;;) { X switch (c) { X case 'l': X case 'L': X if (dotflag) X goto nomore; X dotflag = TRUE; X break; X X case 'u': X case 'U': X if (expseen) X goto nomore; X expseen = TRUE; X break; X X default: X goto nomore; X } X (*outfun)(c); /* Got 'L' or 'U'. */ X c = get(); /* Look at next, too. */ X } X } Xnomore: unget(); /* Not part of a number */ X if (octal89 && radix == 8) X cwarn("Illegal digit in octal number", NULLST); X} X Xsave(c) Xregister int c; X{ X if (workp >= &work[NWORK]) X cfatal("Work buffer overflow", NULLST); X else *workp++ = c; X} X Xchar * Xsavestring(text) Xchar *text; X/* X * Store a string into free memory. X */ X{ X register char *result; X X result = getmem(strlen(text) + 1); X strcpy(result, text); X return (result); X} X XFILEINFO * Xgetfile(bufsize, name) Xint bufsize; /* Line or define buffer size */ Xchar *name; /* File or macro name string */ X/* X * Common FILEINFO buffer initialization for a new file or macro. X */ X{ X register FILEINFO *file; X register int size; X X size = strlen(name); /* File/macro name */ X file = (FILEINFO *) getmem(sizeof (FILEINFO) + bufsize + size); X file->parent = infile; /* Chain files together */ X file->fp = NULL; /* No file yet */ X file->filename = savestring(name); /* Save file/macro name */ X file->progname = NULL; /* No #line seen yet */ X file->unrecur = 0; /* No macro fixup */ X file->bptr = file->buffer; /* Initialize line ptr */ X file->buffer[0] = EOS; /* Force first read */ X file->line = 0; /* (Not used just yet) */ X if (infile != NULL) /* If #include file */ X infile->line = line; /* Save current line */ X infile = file; /* New current file */ X line = 1; /* Note first line */ X return (file); /* All done. */ X} X Xchar * Xgetmem(size) Xint size; X/* X * Get a block of free memory. X */ X{ X register char *result; X extern char *malloc(); X X if ((result = malloc((unsigned) size)) == NULL) X cfatal("Out of memory", NULLST); X return (result); X} X X/* X * C P P S y m b o l T a b l e s X */ X X/* X * SBSIZE defines the number of hash-table slots for the symbol table. X * It must be a power of 2. X */ X#ifndef SBSIZE X#define SBSIZE 64 X#endif X#define SBMASK (SBSIZE - 1) X#if (SBSIZE ^ SBMASK) != ((SBSIZE * 2) - 1) X << error, SBSIZE must be a power of 2 >> X#endif X Xstatic DEFBUF *symtab[SBSIZE]; /* Symbol table queue headers */ X XDEFBUF * Xlookid(c) Xint c; /* First character of token */ X/* X * Look for the next token in the symbol table. Returns token in "token". X * If found, returns the table pointer; Else returns NULL. X */ X{ X register int nhash; X register DEFBUF *dp; X register char *np; X int temp; X int isrecurse; /* For #define foo foo */ X X np = token; X nhash = 0; X if ((isrecurse = (c == DEF_MAGIC))) /* If recursive macro */ X c = get(); /* hack, skip DEF_MAGIC */ X do { X if (np < &token[IDMAX]) { /* token dim is IDMAX+1 */ X *np++ = c; /* Store token byte */ X nhash += c; /* Update hash value */ X } X c = get(); /* And get another byte */ X } while (type[c] == LET || type[c] == DIG); X unget(); /* Rescan terminator */ X *np = EOS; /* Terminate token */ X if (isrecurse) /* Recursive definition */ X return (NULL); /* undefined just now */ X nhash += (np - token); /* Fix hash value */ X dp = symtab[nhash & SBMASK]; /* Starting bucket */ X while (dp != (DEFBUF *) NULL) { /* Search symbol table */ X if (dp->hash == nhash /* Fast precheck */ X && (temp = strcmp(dp->name, token)) >= 0) X break; X dp = dp->link; /* Nope, try next one */ X } X return ((temp == 0) ? dp : NULL); X} X XDEFBUF * Xdefendel(name, delete) Xchar *name; Xint delete; /* TRUE to delete a symbol */ X/* X * Enter this name in the lookup table (delete = FALSE) X * or delete this name (delete = TRUE). X * Returns a pointer to the define block (delete = FALSE) X * Returns NULL if the symbol wasn't defined (delete = TRUE). X */ X{ X register DEFBUF *dp; X register DEFBUF **prevp; X register char *np; X int nhash; X int temp; X int size; X X for (nhash = 0, np = name; *np != EOS;) X nhash += *np++; X size = (np - name); X nhash += size; X prevp = &symtab[nhash & SBMASK]; X while ((dp = *prevp) != (DEFBUF *) NULL) { X if (dp->hash == nhash X && (temp = strcmp(dp->name, name)) >= 0) { X if (temp > 0) X dp = NULL; /* Not found */ X else { X *prevp = dp->link; /* Found, unlink and */ X if (dp->repl != NULL) /* Free the replacement */ X free(dp->repl); /* if any, and then */ X free((char *) dp); /* Free the symbol */ X } X break; X } X prevp = &dp->link; X } X if (!delete) { X dp = (DEFBUF *) getmem(sizeof (DEFBUF) + size); X dp->link = *prevp; X *prevp = dp; X dp->hash = nhash; X dp->repl = NULL; X dp->nargs = 0; X strcpy(dp->name, name); X } X return (dp); X} X X#if DEBUG X Xdumpdef(why) Xchar *why; X{ X register DEFBUF *dp; X register DEFBUF **syp; X X printf("CPP symbol table dump %s\n", why); X for (syp = symtab; syp < &symtab[SBSIZE]; syp++) { X if ((dp = *syp) != (DEFBUF *) NULL) { X printf("symtab[%d]\n", (syp - symtab)); X do { X dumpadef((char *) NULL, dp); X } while ((dp = dp->link) != (DEFBUF *) NULL); X } X } X} X Xdumpadef(why, dp) Xchar *why; /* Notation */ Xregister DEFBUF *dp; X{ X register char *cp; X register int c; X X printf(" \"%s\" [%d]", dp->name, dp->nargs); X if (why != NULL) X printf(" (%s)", why); X if (dp->repl != NULL) { X printf(" => "); X for (cp = dp->repl; (c = *cp++ & 0xFF) != EOS;) { X if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) X printf("<%d>", c - MAC_PARM); X else if (isprint(c) || c == '\n' || c == '\t') X putchar(c); X else if (c < ' ') X printf("<^%c>", c + '@'); X else X printf("<\\0%o>", c); X } X } X else { X printf(", no replacement."); X } X putchar('\n'); X} X#endif X X/* X * G E T X */ X Xint Xget() X/* X * Return the next character from a macro or the current file. X * Handle end of file from #include files. X */ X{ X register int c; X register FILEINFO *file; X register int popped; /* Recursion fixup */ X X popped = 0; Xget_from_file: X if ((file = infile) == NULL) X return (EOF_CHAR); Xnewline: X#if 0 X printf("get(%s), recursion %d, line %d, bptr = %d, buffer \"%s\"\n", X file->filename, recursion, line, X file->bptr - file->buffer, file->buffer); X#endif X /* X * Read a character from the current input line or macro. X * At EOS, either finish the current macro (freeing temp. X * storage) or read another line from the current input file. X * At EOF, exit the current file (#include) or, at EOF from X * the cpp input file, return EOF_CHAR to finish processing. X */ X if ((c = *file->bptr++ & 0xFF) == EOS) { X /* X * Nothing in current line or macro. Get next line (if X * input from a file), or do end of file/macro processing. X * In the latter case, jump back to restart from the top. X */ X if (file->fp == NULL) { /* NULL if macro */ X popped++; X recursion -= file->unrecur; X if (recursion < 0) X recursion = 0; X infile = file->parent; /* Unwind file chain */ X } X else { /* Else get from a file */ X if ((file->bptr = fgets(file->buffer, NBUFF, file->fp)) X != NULL) { X#if DEBUG X if (debug > 1) { /* Dump it to stdout */ X printf("\n#line %d (%s), %s", X line, file->filename, file->buffer); X } X#endif X goto newline; /* process the line */ X } X else { X fclose(file->fp); /* Close finished file */ X if ((infile = file->parent) != NULL) { X /* X * There is an "ungotten" newline in the current X * infile buffer (set there by doinclude() in X * cpp1.c). Thus, we know that the mainline code X * is skipping over blank lines and will do a X * #line at its convenience. X */ X wrongline = TRUE; /* Need a #line now */ X } X } X } X /* X * Free up space used by the (finished) file or macro and X * restart input from the parent file/macro, if any. X */ X free(file->filename); /* Free name and */ X if (file->progname != NULL) /* if a #line was seen, */ X free(file->progname); /* free it, too. */ X free((char *) file); /* Free file space */ X if (infile == NULL) /* If at end of file */ X return (EOF_CHAR); /* Return end of file */ X line = infile->line; /* Reset line number */ X goto get_from_file; /* Get from the top. */ X } X /* X * Common processing for the new character. X */ X if (c == DEF_MAGIC && file->fp != NULL) /* Don't allow delete */ X goto newline; /* from a file */ X if (file->parent != NULL) { /* Macro or #include */ X if (popped != 0) X file->parent->unrecur += popped; X else { X recursion -= file->parent->unrecur; X if (recursion < 0) X recursion = 0; X file->parent->unrecur = 0; X } X } X if (c == '\n') /* Maintain current */ X ++line; /* line counter */ X if (instring) /* Strings just return */ X return (c); /* the character. */ X else if (c == '/') { /* Comment? */ X instring = TRUE; /* So get() won't loop */ X if ((c = get()) != '*') { /* Next byte '*'? */ X instring = FALSE; /* Nope, no comment */ X unget(); /* Push the char. back */ X return ('/'); /* Return the slash */ X } X if (keepcomments) { /* If writing comments */ X putchar('/'); /* Write out the */ X putchar('*'); /* initializer */ X } X for (;;) { /* Eat a comment */ X c = get(); Xtest: if (keepcomments && c != EOF_CHAR) X cput(c); X switch (c) { X case EOF_CHAR: X cerror("EOF in comment", NULLST); X return (EOF_CHAR); X X case '/': X if ((c = get()) != '*') /* Don't let comments */ X goto test; /* Nest. */ X#ifdef VERBOSE X cwarn("Nested comments", NULLST); X#endif X /* Fall into * stuff */ X case '*': X if ((c = get()) != '/') /* If comment doesn't */ X goto test; /* end, look at next */ X instring = FALSE; /* End of comment, */ X if (keepcomments) { /* Put out the comment */ X cput(c); /* terminator, too */ X } X /* X * A comment is syntactically "whitespace" -- X * however, there are certain strange sequences X * such as X * #define foo(x) (something) X * foo|* comment *|(123) X * these are '/' ^ ^ X * where just returning space (or COM_SEP) will cause X * problems. This can be "fixed" by overwriting the X * '/' in the input line buffer with ' ' (or COM_SEP) X * but that may mess up an error message. X * So, we peek ahead -- if the next character is X * "whitespace" we just get another character, if not, X * we modify the buffer. All in the name of purity. X */ X if (*file->bptr == '\n' X || type[*file->bptr & 0xFF] == SPA) X goto newline; X#if COMMENT_INVISIBLE X /* X * Return magic (old-fashioned) syntactic space. X */ X return ((file->bptr[-1] = COM_SEP)); X#else X return ((file->bptr[-1] = ' ')); X#endif X X case '\n': /* we'll need a #line */ X if (!keepcomments) X wrongline = TRUE; /* later... */ X default: /* Anything else is */ X break; /* Just a character */ X } /* End switch */ X } /* End comment loop */ X } /* End if in comment */ X else if (!inmacro && c == '\\') { /* If backslash, peek */ X if ((c = get()) == '\n') { /* for a . If so, */ X wrongline = TRUE; X goto newline; X } X else { /* Backslash anything */ X unget(); /* Get it later */ X return ('\\'); /* Return the backslash */ X } X } X else if (c == '\f' || c == VT) /* Form Feed, Vertical */ X c = ' '; /* Tab are whitespace */ X return (c); /* Just return the char */ X} X Xunget() X/* X * Backup the pointer to reread the last character. Fatal error X * (code bug) if we backup too far. unget() may be called, X * without problems, at end of file. Only one character may X * be ungotten. If you need to unget more, call ungetstring(). X */ X{ X register FILEINFO *file; X X if ((file = infile) == NULL) X return; /* Unget after EOF */ X if (--file->bptr < file->buffer) X cfatal("Too much pushback", NULLST); X if (*file->bptr == '\n') /* Ungetting a newline? */ X --line; /* Unget the line number, too */ X} X Xungetstring(text) Xchar *text; X/* X * Push a string back on the input stream. This is done by treating X * the text as if it were a macro. X */ X{ X register FILEINFO *file; X extern FILEINFO *getfile(); X X file = getfile(strlen(text) + 1, ""); X strcpy(file->buffer, text); X} X Xint Xcget() X/* X * Get one character, absorb "funny space" after comments or X * token concatenation X */ X{ X register int c; X X do { X c = get(); X#if COMMENT_INVISIBLE X } while (c == TOK_SEP || c == COM_SEP); X#else X } while (c == TOK_SEP); X#endif X return (c); X} X X/* X * Error messages and other hacks. The first byte of severity X * is 'S' for string arguments and 'I' for int arguments. This X * is needed for portability with machines that have int's that X * are shorter than char *'s. X */ X Xstatic Xdomsg(severity, format, arg) Xchar *severity; /* "Error", "Warning", "Fatal" */ Xchar *format; /* Format for the error message */ Xchar *arg; /* Something for the message */ X/* X * Print filenames, macro names, and line numbers for error messages. X */ X{ X register char *tp; X register FILEINFO *file; X X fprintf(stderr, "%sline %d, %s: ", MSG_PREFIX, line, &severity[1]); X if (*severity == 'S') X fprintf(stderr, format, arg); X else X fprintf(stderr, format, (int) arg); X putc('\n', stderr); X if ((file = infile) == NULL) X return; /* At end of file */ X if (file->fp != NULL) { X tp = file->buffer; /* Print current file */ X fprintf(stderr, "%s", tp); /* name, making sure */ X if (tp[strlen(tp) - 1] != '\n') /* there's a newline */ X putc('\n', stderr); X } X while ((file = file->parent) != NULL) { /* Print #includes, too */ X if (file->fp == NULL) X fprintf(stderr, "from macro %s\n", file->filename); X else { X tp = file->buffer; X fprintf(stderr, "from file %s, line %d:\n%s", X (file->progname != NULL) X ? file->progname : file->filename, X file->line, tp); X if (tp[strlen(tp) - 1] != '\n') X putc('\n', stderr); X } X } X} X Xcerror(format, sarg) Xchar *format; Xchar *sarg; /* Single string argument */ X/* X * Print a normal error message, string argument. X */ X{ X domsg("SError", format, sarg); X errors++; X} X Xcierror(format, narg) Xchar *format; Xint narg; /* Single numeric argument */ X/* X * Print a normal error message, numeric argument. X */ X{ X domsg("IError", format, (char *) narg); X errors++; X} X Xcfatal(format, sarg) Xchar *format; Xchar *sarg; /* Single string argument */ X/* X * A real disaster X */ X{ X domsg("SFatal error", format, sarg); X exit(IO_ERROR); X} X Xcwarn(format, sarg) Xchar *format; Xchar *sarg; /* Single string argument */ X/* X * A non-fatal error, string argument. X */ X{ X domsg("SWarning", format, sarg); X} X Xciwarn(format, narg) Xchar *format; Xint narg; /* Single numeric argument */ X/* X * A non-fatal error, numeric argument. X */ X{ X domsg("IWarning", format, (char *) narg); X} X X X END-of-cpp6.c exit nethack-3.4.3/sys/unix/depend.awk0100644000000000000000000001270507764735041015423 0ustar rootroot# depend.awk -- awk script used to construct makefile dependencies # for nethack's source files (`make depend' support for Makefile.src). # # usage: # cd src ; nawk -f depend.awk ../include/*.h list-of-.c/.cpp-files # # This awk program scans each file in sequence, looking for lines beginning # with `#include "' and recording the name inside the quotes. For .h files, # that's all it does. For each .c file, it writes out a make rule for the # corresponding .o file; dependencies in nested header files are propagated # to the .o target. # # config.h and hack.h get special handling because of their heavy use; # timestamps for them allow make to avoid rechecking dates on # subsidiary headers for every source file; # extern.h gets special handling to avoid excessive recompilation # during development; # patchlev.h gets special handling because it only exists on systems # which consider filename patchlevel.h to be too long; # interp.c gets special handling because it usually doesn't exist; it's # assumed to be the last #include in the file where it occurs. # win32api.h gets special handling because it only exists for some ports; # it's assumed to be the last #include in the file where it occurs # BEGIN { FS = "\"" #for `#include "X"', $2 is X special[++sp_cnt] = "../include/config.h" special[++sp_cnt] = "../include/hack.h" alt_deps["../include/extern.h"] = "" alt_deps["../include/patchlev.h"] = "" alt_deps["interp.c"] = " #interp.c" #comment it out alt_deps["../include/win32api.h"] = " #../include/win32api.h" } FNR == 1 { output_dep() #finish previous file file = FILENAME #setup for current file } /^\#[ \t]*include[ \t]+\"/ { #find `#include "X"' incl = $2; #[3.4.0: gnomehack headers currently aren't in include] if (incl ~ /\.h$/) { if (incl ~ /^gn/) # gnomehack special case incl = "../win/gnome/" incl else incl = "../include/" incl } deps[file] = deps[file] " " incl } END { output_dep() } #finish the last file # # `file' has been fully scanned, so process it now; for .h files, # don't do anything (we've just been collecting their dependencies); # for .c files, output the `make' rule for corresponding .o file # function output_dep( targ) { if (file ~ /\.cp*$/) { #prior to very first .c|.cpp file, handle some special header file cases if (!c_count++) output_specials() #construct object filename from source filename targ = file; sub("^.+/", "", targ); sub("\\.cp*$", ".o", targ) #format and write the collected dependencies format_dep(targ, file) } } # # handle some targets (config.h, hack.h) via special timestamping rules # function output_specials( i, sp, alt_sp) { for (i = 1; i <= sp_cnt; i++) { sp = special[i] #change "../include/foo.h" first to "foo.h", then ultimately to "$(FOO_H)" alt_sp = sp; sub("^.+/", "", alt_sp) print "#", alt_sp, "timestamp" #output a `make' comment #- sub("\\.", "_", alt_sp); alt_sp = "$(" toupper(alt_sp) ")" #+ Some nawks don't have toupper(), so hardwire these instead. sub("config.h", "$(CONFIG_H)", alt_sp); sub("hack.h", "$(HACK_H)", alt_sp); format_dep(alt_sp, sp) #output the target print "\ttouch " alt_sp #output a build command alt_deps[sp] = alt_sp #alternate dependency for depend() } print "#" } # # write a target and its dependency list in pretty-printed format; # if target's primary source file has a path prefix, also write build command # function format_dep(target, source, n, i, list) { split("", done) #``for (x in done) delete done[x]'' printf("%s:", target); col = length(target) + 1 #- printf("\t"); col += 8 - (col % 8); #- if (col == 8) { printf("\t"); col += 8 } source = depend("", source, 0) n = split(source, list, " +") for (i = 2; i <= n; i++) { #(leading whitespace yields empty 1st element) if (col + length(list[i]) >= (i < n ? 78 : 80)) { printf(" \\\n\t\t"); col = 16 #make a backslash+newline split } else { printf(" "); col++; } printf("%s", list[i]); col += length(list[i]) } printf("\n") #terminate #write build command if first source entry has non-include path prefix source = list[2] if (source ~ /\// && substr(source, 1, 11) != "../include/") { if (source ~ /\.cpp$/ ) print "\t$(CXX) $(CXXFLAGS) -c " source else if (source ~ /\/gnome\//) # "../win/gnome/foo.c" print "\t$(CC) $(CFLAGS) $(GNOMEINC) -c " source else print "\t$(CC) $(CFLAGS) -c " source } } # # recursively add the dependencies for file `name' to string `inout' # (unless `skip', in which case we're only marking files as already done) # function depend(inout, name, skip, n, i, list) { if (!done[name]++) { if (name in alt_deps) { #some names have non-conventional dependencies if (!skip) inout = inout " " alt_deps[name] skip = 1 } else { #ordinary name if (!skip) inout = inout " " name } if (name in deps) { #- n = split(deps[name], list, " +") #- for (i = 2; i <= n; i++) #(leading whitespace yields empty 1st element) #- inout = depend(inout, list[i], skip) #+ At least one implementation of nawk handles the local array `list' wrong, #+ so the clumsier substitute code below is used as a workaround. list = deps[name]; sub("^ +", "", list) while (list) { match((list " "), " +"); i = RSTART; n = RLENGTH inout = depend(inout, substr(list, 1, i-1), skip) list = substr(list, i+n) } } } return inout } #depend.awk# nethack-3.4.3/sys/unix/nethack.sh0100644000000000000000000000254407764735041015431 0ustar rootroot#!/bin/sh # SCCS Id: @(#)nethack.sh 3.4 1990/02/26 HACKDIR=/usr/games/lib/nethackdir export HACKDIR HACK=$HACKDIR/nethack MAXNROFPLAYERS=4 # Since Nethack.ad is installed in HACKDIR, add it to XUSERFILESEARCHPATH case "x$XUSERFILESEARCHPATH" in x) XUSERFILESEARCHPATH="$HACKDIR/%N.ad" ;; *) XUSERFILESEARCHPATH="$XUSERFILESEARCHPATH:$HACKDIR/%N.ad" ;; esac export XUSERFILESEARCHPATH # see if we can find the full path name of PAGER, so help files work properly # assume that if someone sets up a special variable (HACKPAGER) for NetHack, # it will already be in a form acceptable to NetHack # ideas from brian@radio.astro.utoronto.ca if test \( "xxx$PAGER" != xxx \) -a \( "xxx$HACKPAGER" = xxx \) then HACKPAGER=$PAGER # use only the first word of the pager variable # this prevents problems when looking for file names with trailing # options, but also makes the options unavailable for later use from # NetHack for i in $HACKPAGER do HACKPAGER=$i break done if test ! -f $HACKPAGER then IFS=: for i in $PATH do if test -f $i/$HACKPAGER then HACKPAGER=$i/$HACKPAGER export HACKPAGER break fi done IFS=' ' fi if test ! -f $HACKPAGER then echo Cannot find $PAGER -- unsetting PAGER. unset HACKPAGER unset PAGER fi fi cd $HACKDIR case $1 in -s*) exec $HACK "$@" ;; *) exec $HACK "$@" $MAXNROFPLAYERS ;; esac nethack-3.4.3/sys/unix/setup.sh0100644000000000000000000000224707764735041015154 0ustar rootroot#!/bin/sh # Copy files to their correct locations. # # If arguments are given, try symbolic link first. This is not the default # so that most people will have the distribution versions stay around so # subsequent patches can be applied. People who pay enough attention to # know there's a non-default behavior are assumed to pay enough attention # to keep distribution versions if they modify things. # Were we started from the top level? Cope. if [ -f sys/unix/Makefile.top ]; then cd sys/unix; fi if [ $# -gt 0 ] ; then # First, try to make a symbolic link. # ln -s Makefile.top Makefile >/dev/null 2>&1 if [ $? -eq 0 ] ; then echo "Lucky you! Symbolic links." rm -f Makefile umask 0 ln -s sys/unix/Makefile.top ../../Makefile ln -s ../sys/unix/Makefile.dat ../../dat/Makefile ln -s ../sys/unix/Makefile.doc ../../doc/Makefile ln -s ../sys/unix/Makefile.src ../../src/Makefile ln -s ../sys/unix/Makefile.utl ../../util/Makefile exit 0 fi fi # # Otherwise... echo "Copying Makefiles." cp Makefile.top ../../Makefile cp Makefile.dat ../../dat/Makefile cp Makefile.doc ../../doc/Makefile cp Makefile.src ../../src/Makefile cp Makefile.utl ../../util/Makefile nethack-3.4.3/sys/unix/snd86unx.shr0100644000000000000000000007044707764735041015702 0ustar rootroot# This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # READ.ME # install.bsd # spkr.7 # Makefile # spkr.c # spkr.h # interp.c # Files # Install # Master # Name # Node # Remove # Size # System # playtest # echo x - READ.ME sed 's/^X//' >READ.ME << 'END-of-READ.ME' X Console Speaker Driver Package (v1.1) X X by Eric S. Raymond (esr@snark.thyrsus.com) X XThis package gives 80386 machines running SVr3.2 or later the ability to play Xtunes on the console speaker. It has been extended to 386BSD (and possibly XBSDI) by Andrew A. Chernov, and to SCO UNIX 3.2.4 (and possibly other VPIX Xsystems) by Andreas Arens. X XThe following files are contained in the kit: X XDocumentation and examples: XREAD.ME -- this file Xspeaker.7 -- man page for the driver Xplaytest -- test script exercising familiar tunes X XInstallable driver kit parts, for SVr3.2 or later: XFiles -- list of driver package file locations XInstall -- installation script for driver kit XMaster -- mdevice entry for speaker driver XName -- name entry foe speaker driver XNode -- /dev node specification file XRemove -- Driver removal script XSize -- installation size data XSystem -- sdevice entry for speaker driver X XDriver source code, for SVr3.2 or later and 386BSD: XMakefile -- Makefile for driver code Xspkr.c -- the driver source Xspeaker.h -- ioctl interface file X XCommon source code: Xinterp.c -- play string interpretation code X XFor SVr3.2 or later, simply type `make' and wait. Then type ./Install Xand follow its instructions. You will have to install the man pages by hand. XBe aware that the speaker.7 man page uses tbl(1) constructs. X XFor 386BSD, follow the installation instructions in install.bsd. X XFor SCO UNIX 3.2.4, no new kernel drivers are needed, and you need only Xcopy interp.c to your src directory and proceed with making NetHack, with XVPIX_MUSIC set in unixconf.h. X XInteresting tunes mailed to the author will be periodically posted in batches Xand added to the test script for future versions. X X Revision notes X X1.1 -- fixed minor bug in M[LSN] interpretation, added octave-tracking. X Tweaked the playtest examples. END-of-READ.ME echo x - install.bsd sed 's/^X//' >install.bsd << 'END-of-install.bsd' XCopy spkr.c and interp.c to /sys/i386/isa XCopy spkr.h to /sys/sys X X----------------------------------------------------------------------------- X XFile /sys/i386/conf/YOUR_MACHINE_NAME Xadd following line: X Xpseudo-device speaker X X----------------------------------------------------------------------------- X XFile /sys/i386/conf/files.i386 Xadd following line: X Xi386/isa/spkr.c optional speaker X X----------------------------------------------------------------------------- X XFile /sys/i386/i386/conf.c X[major number 20 (hex) is registered for spkr driver, don't change it] Xadd following code: X X#include "speaker.h" X#if NSPEAKER > 0 Xint spkropen(),spkrclose(),spkrwrite(),spkrioctl(); X#else X#define spkropen enxio X#define spkrclose enxio X#define spkrwrite enxio X#define spkrioctl enxio X#endif X ... X Xstruct cdevsw cdevsw[] = X{ X ... X X { spkropen, spkrclose, enxio, spkrwrite, /*20*/ X spkrioctl, enxio, enxio, NULL, X enxio, enxio, enxio }, X ... X X----------------------------------------------------------------------------- X XMake corresponding device: X X mknod /dev/speaker c 32 0 X X[major number 32 (20 hex) is registered for spkr driver, don't change it] X X----------------------------------------------------------------------------- X XGo to /sys/i386/conf and type X config YOUR_MACHINE_NAME Xthen go to /sys/compile/YOUR_MACHINE_NAME and type X make depend X make X END-of-install.bsd echo x - spkr.7 sed 's/^X//' >spkr.7 << 'END-of-spkr.7' X.TH SPKR 7 X.SH NAME Xspkr \- console speaker device driver X.SH DESCRIPTION XThe speaker device driver allows applications to control the PC console Xspeaker on an IBM-PC-compatible machine running UNIX. X.PP XOnly one process may have this device open at any given time; open() and Xclose() are used to lock and relinquish it. An attempt to open() when Xanother process has the device locked will return -1 with an EBUSY error Xindication. Writes to the device are interpreted as 'play strings' in a Xsimple ASCII melody notation. An ioctl() for tone generation at arbitrary Xfrequencies is also supported. X.PP XSound-generation does \fInot\fR monopolize the processor; in fact, the driver Xspends most of its time sleeping while the PC hardware is emitting Xtones. Other processes may emit beeps while the driver is running. X.PP XApplications may call ioctl() on a speaker file descriptor to control the Xspeaker driver directly; definitions for the ioctl() interface are in Xsys/spkr.h. The tone_t structure used in these calls has two fields, Xspecifying a frequency (in hz) and a duration (in 1/100ths of a second). XA frequency of zero is interpreted as a rest. X.PP XAt present there are two such ioctls. SPKRTONE accepts a pointer to a Xsingle tone structure as third argument and plays it. SPKRTUNE accepts a Xpointer to the first of an array of tone structures and plays them in Xcontinuous sequence; this array must be terminated by a final member with Xa zero duration. X.PP XThe play-string language is modelled on the PLAY statement conventions of XIBM BASIC 2.0. The MB, MF and X primitives of PLAY are not useful in a UNIX Xenvironment and are omitted. The `octave-tracking' feature is also new. X.PP XThere are 84 accessible notes numbered 1-83 in 7 octaves, each running from XC to B, numbered 0-6; the scale is equal-tempered A440 and octave 3 starts Xwith middle C. By default, the play function emits half-second notes with the Xlast 1/16th second being `rest time'. X.PP XPlay strings are interpreted left to right as a series of play command groups; Xletter case is ignored. Play command groups are as follows: X.PP XCDEFGAB -- letters A through G cause the corresponding note to be played in the Xcurrent octave. A note letter may optionally be followed by an \fIaccidental Xsign\fR, one of # + or -; the first two of these cause it to be sharped one Xhalf-tone, the last causes it to be flatted one half-tone. It may also be Xfollowed by a time value number and by sustain dots (see below). Time values Xare interpreted as for the L command below;. X.PP XO -- if is numeric, this sets the current octave. may also be one Xof 'L' or 'N' to enable or disable octave-tracking (it is disabled by default). XWhen octave-tracking is on, interpretation of a pair of letter notes will Xchange octaves if necessary in order to make the smallest possible jump between Xnotes. Thus "olbc" will be played as "olb>c", and "olcb" as "olc, < and O[0123456]. X.PP X> -- bump the current octave up one. X.PP X< -- drop the current octave down one. X.PP XN -- play note n, n being 1 to 84 or 0 for a rest of current time value. XMay be followedv by sustain dots. X.PP XL -- sets the current time value for notes. The default is L4, quarter Xnotes. The lowest possible value is 1; values up to 64 are accepted. L1 sets Xwhole notes, L2 sets half notes, L4 sets quarter notes, etc.. X.PP XP -- pause (rest), with interpreted as for L. May be followed by Xsustain dots. May also be written '~'. X.PP XT -- Sets the number of quarter notes per minute; default is 120. Musical Xnames for common tempi are: X X.TS Xa a a. X Tempo Beats Per Minute Xvery slow Larghissimo X Largo 40-60 X Larghetto 60-66 X Grave X Lento X Adagio 66-76 Xslow Adagietto X Andante 76-108 Xmedium Andantino X Moderato 108-120 Xfast Allegretto X Allegro 120-168 X Vivace X Veloce X Presto 168-208 Xvery fast Prestissimo X.TE X.PP XM[LNS] -- set articulation. MN (N for normal) is the default; the last 1/8th of Xthe note's value is rest time. You can set ML for legato (no rest space) or XMS (staccato) 1/4 rest space. X.PP XNotes (that is, CDEFGAB or N command character groups) may be followed by Xsustain dots. Each dot causes the note's value to be lengthened by one-half Xfor each one. Thus, a note dotted once is held for 3/2 of its undotted value; Xdotted twice, it is held 9/4, and three times would give 27/8. X.PP XWhitespace in play strings is simply skipped and may be used to separate Xmelody sections. X.SH BUGS XDue to roundoff in the pitch tables and slop in the tone-generation and timer Xhardware (neither of which was designed for precision), neither pitch accuracy Xnor timings will be mathematically exact. There is no volume control. X.PP XIn play strings which are very long (longer than your system's physical I/O Xblocks) note suffixes or numbers may occasionally be parsed incorrectly due Xto crossing a block boundary. X.SH FILES X/dev/speaker -- speaker device file X.SH AUTHOR XEric S. Raymond (esr@snark.thyrsus.com) Feb 1990 END-of-spkr.7 echo x - Makefile sed 's/^X//' >Makefile << 'END-of-Makefile' X# X# Speaker driver package makefile X# XCFLAGS = -I. -O # -DDEBUG XLDFLAGS = -s X Xall: Driver.o X Xinstall: X ./Install X XDriver.o: spkr.c X $(CC) $(CFLAGS) -c spkr.c X mv spkr.o Driver.o X Xclean: X rm -f Driver.o *~ speaker.shar X XDSP = Files Install Master Name Node Remove Size System Xshar: X shar READ.ME install.bsd spkr.7 Makefile spkr.[ch] \ X interp.c $(DSP) playtest >speaker.shar END-of-Makefile echo x - spkr.c sed 's/^X//' >spkr.c << 'END-of-spkr.c' X/* X * spkr.c -- device driver for console speaker on 80386 X * X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 X * modified for 386bsd by Andrew A. Chernov X */ X X#ifdef __386BSD__ X#include "speaker.h" X#endif X#if !defined(__386BSD__) || (NSPEAKER > 0) X X#ifdef __386BSD__ X#include "types.h" X#include "param.h" X#include "errno.h" X#include "buf.h" X#include "uio.h" X X#define CADDR caddr_t X#define err_ret(x) return(x) X#else /* SYSV */ X#include X#include X#include X#include X#include X#include X#include X#include X#include X X#define CADDR char * X#define err_ret(x) u.u_error = (x) X#endif X X#include "spkr.h" X X/**************** MACHINE DEPENDENT PART STARTS HERE ************************* X * X * This section defines a function tone() which causes a tone of given X * frequency and duration from the 80x86's console speaker. X * Another function endtone() is defined to force sound off, and there is X * also a rest() entry point to do pauses. X * X * Audible sound is generated using the Programmable Interval Timer (PIT) and X * Programmable Peripheral Interface (PPI) attached to the 80x86's speaker. The X * PPI controls whether sound is passed through at all; the PIT's channel 2 is X * used to generate clicks (a square wave) of whatever frequency is desired. X * X * The non-BSD code requires SVr3.2-compatible inb(), outb(), timeout(), X * sleep(), and wakeup(). X */ X X/* X * PIT and PPI port addresses and control values X * X * Most of the magic is hidden in the TIMER_PREP value, which selects PIT X * channel 2, frequency LSB first, square-wave mode and binary encoding. X * The encoding is as follows: X * X * +----------+----------+---------------+-----+ X * | 1 0 | 1 1 | 0 1 1 | 0 | X * | SC1 SC0 | RW1 RW0 | M2 M1 M0 | BCD | X * +----------+----------+---------------+-----+ X * Counter Write Mode 3 Binary X * Channel 2 LSB first, (Square Wave) Encoding X * MSB second X */ X#define PPI 0x61 /* port of Programmable Peripheral Interface */ X#define PPI_SPKR 0x03 /* turn these PPI bits on to pass sound */ X#define PIT_CTRL 0x43 /* PIT control address */ X#define PIT_COUNT 0x42 /* PIT count address */ X#define PIT_MODE 0xB6 /* set timer mode for sound generation */ X X/* X * Magic numbers for timer control. X */ X#define TIMER_CLK 1193180L /* corresponds to 18.2 MHz tick rate */ X Xstatic int endtone() X/* turn off the speaker, ending current tone */ X{ X wakeup((CADDR)endtone); X outb(PPI, inb(PPI) & ~PPI_SPKR); X} X Xstatic void tone(hz, ticks) X/* emit tone of frequency hz for given number of ticks */ Xunsigned int hz, ticks; X{ X unsigned int divisor = TIMER_CLK / hz; X int sps; X X#ifdef DEBUG X printf("tone: hz=%d ticks=%d\n", hz, ticks); X#endif /* DEBUG */ X X /* set timer to generate clicks at given frequency in Hertz */ X#ifdef __386BSD__ X sps = spltty(); X#else X sps = spl5(); X#endif X outb(PIT_CTRL, PIT_MODE); /* prepare timer */ X outb(PIT_COUNT, (unsigned char) divisor); /* send lo byte */ X outb(PIT_COUNT, (divisor >> 8)); /* send hi byte */ X splx(sps); X X /* turn the speaker on */ X outb(PPI, inb(PPI) | PPI_SPKR); X X /* X * Set timeout to endtone function, then give up the timeslice. X * This is so other processes can execute while the tone is being X * emitted. X */ X timeout((CADDR)endtone, (CADDR)NULL, ticks); X sleep((CADDR)endtone, PZERO - 1); X} X Xstatic int endrest() X/* end a rest */ X{ X wakeup((CADDR)endrest); X} X Xstatic void rest(ticks) X/* rest for given number of ticks */ Xint ticks; X{ X /* X * Set timeout to endrest function, then give up the timeslice. X * This is so other processes can execute while the rest is being X * waited out. X */ X#ifdef DEBUG X printf("rest: %d\n", ticks); X#endif /* DEBUG */ X timeout((CADDR)endrest, (CADDR)NULL, ticks); X sleep((CADDR)endrest, PZERO - 1); X} X X#include "interp.c" /* playinit() and playstring() */ X X/******************* UNIX DRIVER HOOKS BEGIN HERE ************************** X * X * This section implements driver hooks to run playstring() and the tone(), X * endtone(), and rest() functions defined above. For non-BSD systems, X * SVr3.2-compatible copyin() is also required. X */ X Xstatic int spkr_active; /* exclusion flag */ X#ifdef __386BSD__ Xstatic struct buf *spkr_inbuf; /* incoming buf */ X#endif X Xint spkropen(dev) Xdev_t dev; X{ X#ifdef DEBUG X printf("spkropen: entering with dev = %x\n", dev); X#endif /* DEBUG */ X X if (minor(dev) != 0) X err_ret(ENXIO); X else if (spkr_active) X err_ret(EBUSY); X else X { X playinit(); X#ifdef __386BSD__ X spkr_inbuf = geteblk(DEV_BSIZE); X#endif X spkr_active = 1; X } X#ifdef __386BSD__ X return(0); X#endif X} X X#ifdef __386BSD__ Xint spkrwrite(dev, uio) Xstruct uio *uio; X#else Xint spkrwrite(dev) X#endif Xdev_t dev; X{ X#ifdef __386BSD__ X register unsigned n; X char *cp; X int error; X#endif X#ifdef DEBUG X#ifdef __386BSD__ X printf("spkrwrite: entering with dev = %x, count = %d\n", X dev, uio->uio_resid); X#else X printf("spkrwrite: entering with dev = %x, u.u_count = %d\n", X dev, u.u_count); X#endif X#endif /* DEBUG */ X X if (minor(dev) != 0) X err_ret(ENXIO); X else X { X#ifdef __386BSD__ X n = MIN(DEV_BSIZE, uio->uio_resid); X cp = spkr_inbuf->b_un.b_addr; X error = uiomove(cp, n, uio); X if (!error) X playstring(cp, n); X return(error); X#else X char bfr[STD_BLK]; X X copyin(u.u_base, bfr, u.u_count); X playstring(bfr, u.u_count); X u.u_base += u.u_count; X u.u_count = 0; X#endif X } X} X Xint spkrclose(dev) Xdev_t dev; X{ X#ifdef DEBUG X printf("spkrclose: entering with dev = %x\n", dev); X#endif /* DEBUG */ X X if (minor(dev) != 0) X err_ret(ENXIO); X else X { X endtone(); X#ifdef __386BSD__ X brelse(spkr_inbuf); X#endif X spkr_active = 0; X } X#ifdef __386BSD__ X return(0); X#endif X} X Xint spkrioctl(dev, cmd, cmdarg) Xdev_t dev; Xint cmd; XCADDR cmdarg; X{ X#ifdef DEBUG X printf("spkrioctl: entering with dev = %x, cmd = %x\n", dev, cmd); X#endif /* DEBUG */ X X if (minor(dev) != 0) X err_ret(ENXIO); X else if (cmd == SPKRTONE) X { X tone_t *tp = (tone_t *)cmdarg; X X if (tp->frequency == 0) X rest(tp->duration); X else X tone(tp->frequency, tp->duration); X } X else if (cmd == SPKRTUNE) X { X#ifdef __386BSD__ X tone_t *tp = (tone_t *)(*(caddr_t *)cmdarg); X tone_t ttp; X int error; X X for (; ; tp++) { X error = copyin(tp, &ttp, sizeof(tone_t)); X if (error) X return(error); X if (ttp.duration == 0) X break; X if (ttp.frequency == 0) X rest(ttp.duration); X else X tone(ttp.frequency, ttp.duration); X } X#else X tone_t *tp = (tone_t *)cmdarg; X X for (; tp->duration; tp++) X if (tp->frequency == 0) X rest(tp->duration); X else X tone(tp->frequency, tp->duration); X#endif X } X else X err_ret(EINVAL); X#ifdef __386BSD__ X return(0); X#endif X} X X#endif /* !defined(__386BSD__) || (NSPEAKER > 0) */ X/* spkr.c ends here */ END-of-spkr.c echo x - spkr.h sed 's/^X//' >spkr.h << 'END-of-spkr.h' X/* X * spkr.h -- interface definitions for speaker ioctl() X * X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 X * modified for 386bsd by Andrew A. Chernov X */ X X#ifndef _SPKR_H_ X#define _SPKR_H_ X X#ifdef __386BSD__ X#ifndef KERNEL X#include X#else X#include "ioctl.h" X#endif X X#define SPKRTONE _IOW('S', 1, tone_t) /* emit tone */ X#define SPKRTUNE _IO('S', 2) /* emit tone sequence*/ X#else /* SYSV */ X#define SPKRIOC ('S'<<8) X#define SPKRTONE (SPKRIOC|1) /* emit tone */ X#define SPKRTUNE (SPKRIOC|2) /* emit tone sequence*/ X#endif X Xtypedef struct X{ X int frequency; /* in hertz */ X int duration; /* in 1/100ths of a second */ X} Xtone_t; X X#endif /* _SPKR_H_ */ X/* spkr.h ends here */ END-of-spkr.h echo x - interp.c sed 's/^X//' >interp.c << 'END-of-interp.c' X/* X * interp.c -- device driver for console speaker on 80386 X * X * v1.1 by Eric S. Raymond (esr@snark.thyrsus.com) Feb 1990 X * X * this is the part of the code common to all 386 UNIX OSes X * X * playinit() and playstring() are called from the appropriate driver X */ X X#ifdef __386BSD__ X#include "param.h" X#else X#include X#endif X X#ifndef HZ X#define HZ 60 X#endif X X X/**************** PLAY STRING INTERPRETER BEGINS HERE ********************** X * X * Play string interpretation is modelled on IBM BASIC 2.0's PLAY statement; X * M[LNS] are missing and the ~ synonym and octave-tracking facility is added. X * Requires tone(), rest(), and endtone(). String play is not interruptible X * except possibly at physical block boundaries. X */ X Xtypedef int bool; X#ifndef TRUE X#define TRUE 1 X#endif X#ifndef FALSE X#define FALSE 0 X#endif X X#define toupper(c) ((c) - ' ' * (((c) >= 'a') && ((c) <= 'z'))) X#define isdigit(c) (((c) >= '0') && ((c) <= '9')) X#define dtoi(c) ((c) - '0') X Xstatic int octave; /* currently selected octave */ Xstatic int whole; /* whole-note time at current tempo, in ticks */ Xstatic int value; /* whole divisor for note time, quarter note = 1 */ Xstatic int fill; /* controls spacing of notes */ Xstatic bool octtrack; /* octave-tracking on? */ Xstatic bool octprefix; /* override current octave-tracking state? */ X X/* X * Magic number avoidance... X */ X#define SECS_PER_MIN 60 /* seconds per minute */ X#define WHOLE_NOTE 4 /* quarter notes per whole note */ X#define MIN_VALUE 64 /* the most we can divide a note by */ X#define DFLT_VALUE 4 /* default value (quarter-note) */ X#define FILLTIME 8 /* for articulation, break note in parts */ X#define STACCATO 6 /* 6/8 = 3/4 of note is filled */ X#define NORMAL 7 /* 7/8ths of note interval is filled */ X#define LEGATO 8 /* all of note interval is filled */ X#define DFLT_OCTAVE 4 /* default octave */ X#define MIN_TEMPO 32 /* minimum tempo */ X#define DFLT_TEMPO 120 /* default tempo */ X#define MAX_TEMPO 255 /* max tempo */ X#define NUM_MULT 3 /* numerator of dot multiplier */ X#define DENOM_MULT 2 /* denominator of dot multiplier */ X X/* letter to half-tone: A B C D E F G */ Xstatic int notetab[8] = {9, 11, 0, 2, 4, 5, 7}; X X/* X * This is the American Standard A440 Equal-Tempered scale with frequencies X * rounded to nearest integer. Thank Goddess for the good ol' CRC Handbook... X * our octave 0 is standard octave 2. X */ X#define OCTAVE_NOTES 12 /* semitones per octave */ Xstatic int pitchtab[] = X{ X/* C C# D D# E F F# G G# A A# B*/ X/* 0 */ 65, 69, 73, 78, 82, 87, 93, 98, 103, 110, 117, 123, X/* 1 */ 131, 139, 147, 156, 165, 175, 185, 196, 208, 220, 233, 247, X/* 2 */ 262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494, X/* 3 */ 523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988, X/* 4 */ 1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1975, X/* 5 */ 2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951, X/* 6 */ 4186, 4435, 4698, 4978, 5274, 5588, 5920, 6272, 6644, 7040, 7459, 7902, X}; X Xstatic void playinit() X{ X octave = DFLT_OCTAVE; X whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / DFLT_TEMPO; X fill = NORMAL; X value = DFLT_VALUE; X octtrack = FALSE; X octprefix = TRUE; /* act as though there was an initial O(n) */ X} X Xstatic void playtone(pitch, value, sustain) X/* play tone of proper duration for current rhythm signature */ Xint pitch, value, sustain; X{ X register int sound, silence, snum = 1, sdenom = 1; X X /* this weirdness avoids floating-point arithmetic */ X for (; sustain; sustain--) X { X snum *= NUM_MULT; X sdenom *= DENOM_MULT; X } X X if (pitch == -1) X rest(whole * snum / (value * sdenom)); X else X { X sound = (whole * snum) / (value * sdenom) X - (whole * (FILLTIME - fill)) / (value * FILLTIME); X silence = whole * (FILLTIME-fill) * snum / (FILLTIME * value * sdenom); X X#ifdef DEBUG X printf("playtone: pitch %d for %d ticks, rest for %d ticks\n", X pitch, sound, silence); X#endif /* DEBUG */ X X tone(pitchtab[pitch], sound); X if (fill != LEGATO) X rest(silence); X } X} X Xstatic int abs(n) Xint n; X{ X if (n < 0) X return(-n); X else X return(n); X} X Xstatic void playstring(cp, slen) X/* interpret and play an item from a notation string */ Xchar *cp; Xsize_t slen; X{ X int pitch, lastpitch = OCTAVE_NOTES * DFLT_OCTAVE; X X#define GETNUM(cp, v) for(v=0; isdigit(cp[1]) && slen > 0; ) \ X {v = v * 10 + (*++cp - '0'); slen--;} X for (; slen--; cp++) X { X int sustain, timeval, tempo; X register char c = toupper(*cp); X X#ifdef DEBUG X printf("playstring: %c (%x)\n", c, c); X#endif /* DEBUG */ X X switch (c) X { X case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G': X X /* compute pitch */ X pitch = notetab[c - 'A'] + octave * OCTAVE_NOTES; X X /* this may be followed by an accidental sign */ X if (cp[1] == '#' || cp[1] == '+') X { X ++pitch; X ++cp; X slen--; X } X else if (cp[1] == '-') X { X --pitch; X ++cp; X slen--; X } X X /* X * If octave-tracking mode is on, and there has been no octave- X * setting prefix, find the version of the current letter note X * closest to the last regardless of octave. X */ X if (octtrack && !octprefix) X { X if (abs(pitch-lastpitch) > abs(pitch+OCTAVE_NOTES-lastpitch)) X { X ++octave; X pitch += OCTAVE_NOTES; X } X X if (abs(pitch-lastpitch) > abs((pitch-OCTAVE_NOTES)-lastpitch)) X { X --octave; X pitch -= OCTAVE_NOTES; X } X } X octprefix = FALSE; X lastpitch = pitch; X X /* ...which may in turn be followed by an override time value */ X GETNUM(cp, timeval); X if (timeval <= 0 || timeval > MIN_VALUE) X timeval = value; X X /* ...and/or sustain dots */ X for (sustain = 0; cp[1] == '.'; cp++) X { X slen--; X sustain++; X } X X /* time to emit the actual tone */ X playtone(pitch, timeval, sustain); X break; X X case 'O': X if (cp[1] == 'N' || cp[1] == 'n') X { X octprefix = octtrack = FALSE; X ++cp; X slen--; X } X else if (cp[1] == 'L' || cp[1] == 'l') X { X octtrack = TRUE; X ++cp; X slen--; X } X else X { X GETNUM(cp, octave); X if (octave >= sizeof(pitchtab) / OCTAVE_NOTES) X octave = DFLT_OCTAVE; X octprefix = TRUE; X } X break; X X case '>': X if (octave < sizeof(pitchtab) / OCTAVE_NOTES - 1) X octave++; X octprefix = TRUE; X break; X X case '<': X if (octave > 0) X octave--; X octprefix = TRUE; X break; X X case 'N': X GETNUM(cp, pitch); X for (sustain = 0; cp[1] == '.'; cp++) X { X slen--; X sustain++; X } X playtone(pitch - 1, value, sustain); X break; X X case 'L': X GETNUM(cp, value); X if (value <= 0 || value > MIN_VALUE) X value = DFLT_VALUE; X break; X X case 'P': X case '~': X /* this may be followed by an override time value */ X GETNUM(cp, timeval); X if (timeval <= 0 || timeval > MIN_VALUE) X timeval = value; X for (sustain = 0; cp[1] == '.'; cp++) X { X slen--; X sustain++; X } X playtone(-1, timeval, sustain); X break; X X case 'T': X GETNUM(cp, tempo); X if (tempo < MIN_TEMPO || tempo > MAX_TEMPO) X tempo = DFLT_TEMPO; X whole = (HZ * SECS_PER_MIN * WHOLE_NOTE) / tempo; X break; X X case 'M': X if (cp[1] == 'N' || cp[1] == 'n') X { X fill = NORMAL; X ++cp; X slen--; X } X else if (cp[1] == 'L' || cp[1] == 'l') X { X fill = LEGATO; X ++cp; X slen--; X } X else if (cp[1] == 'S' || cp[1] == 's') X { X fill = STACCATO; X ++cp; X slen--; X } X break; X } X } X} END-of-interp.c echo x - Files sed 's/^X//' >Files << 'END-of-Files' X/usr/include/sys/spkr.h END-of-Files echo x - Install sed 's/^X//' >Install << 'END-of-Install' X# X# Speaker driver installation script X# XTMP=/tmp/speaker.err XERR1=" Errors have been written to the file $TMP." XERR2=" The Speaker Driver software was not installed." X Xecho "Installing Speaker Driver Software Package" X X/etc/conf/bin/idcheck -p speaker 2>$TMP Xif [ $? != 0 ] Xthen X echo "The speaker package is already at least partly installed. X Removing the old version now..." X /etc/conf/bin/idinstall -d speaker Xfi X X/etc/conf/bin/idinstall -a -k speaker 2>>$TMP Xif [ $? != 0 ] Xthen X message "There was an error during package installation. $ERR1 $ERR2" X exit 1 Xfi X X/etc/conf/bin/idbuild 2>>$TMP Xif [ $? != 0 ] Xthen X message "There was an error during kernel reconfiguration. $ERR1 $ERR2" X exit 1 Xfi X Xrm -f $TMP X Xcp spkr.h /usr/include/sys/spkr.h X Xecho "Performing shutdown..." Xcd /; exec /etc/shutdown -g0 -y END-of-Install echo x - Master sed 's/^X//' >Master << 'END-of-Master' Xspeaker ocwi iocH spkr 0 0 1 1 -1 END-of-Master echo x - Name sed 's/^X//' >Name << 'END-of-Name' X386 UNIX Speaker Device Driver Package END-of-Name echo x - Node sed 's/^X//' >Node << 'END-of-Node' Xspeaker speaker c 0 END-of-Node echo x - Remove sed 's/^X//' >Remove << 'END-of-Remove' X# X# Speaker driver remove script X# XTMP=/tmp/speaker.err XRERR="Errors have been written to the file $TMP." X Xecho "Removing Speaker Driver Software Package" X X/etc/conf/bin/idinstall -d speaker 2>$TMP Xif [ $? != 0 ] Xthen X message "There was an error during package removal. $RERR" X exit 1 Xfi X X/etc/conf/bin/idbuild 2>>$TMP Xif [ $? != 0 ] Xthen X message "There was an error during kernel reconfiguration. $RERR" X exit 1 Xfi X Xrm -f /dev/speaker $TMP /usr/include/sys/spkr.h X Xexit 0 END-of-Remove echo x - Size sed 's/^X//' >Size << 'END-of-Size' XROOT=1400 XUSR=100 END-of-Size echo x - System sed 's/^X//' >System << 'END-of-System' Xspeaker Y 1 0 0 0 0 0 0 0 END-of-System echo x - playtest sed 's/^X//' >playtest << 'END-of-playtest' X: X# Test script for the speaker driver X# X# v1.0 by Eric S. Raymond (Feb 1990) X# modified for 386bsd by Andrew A. Chernov X# Xreveille="t255l8c.f.afc~c.f.afc~c.f.afc.f.a..f.~c.f.afc~c.f.afc~c.f.afc~c.f.." Xcontact="f" Xdance="t240dcdc/dev/speaker;; Xcontact) echo $contact >/dev/speaker;; Xdance) echo $dance >/dev/speaker;; Xloony) echo $loony >/dev/speaker;; X*) X echo "No such tune. Available tunes are:" X echo X echo "reveille -- Reveille" X echo "contact -- Contact theme from Close Encounters" X echo "dance -- Lord of the Dance (aka Simple Gifts)" X echo "loony -- Loony Toons theme" X ;; Xesac END-of-playtest exit nethack-3.4.3/sys/unix/unixmain.c0100644000000000000000000003021607764735041015451 0ustar rootroot/* SCCS Id: @(#)unixmain.c 3.4 1997/01/22 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* main.c - Unix NetHack */ #include "hack.h" #include "dlb.h" #include #include #include #ifndef O_RDONLY #include #endif #if !defined(_BULL_SOURCE) && !defined(__sgi) && !defined(_M_UNIX) # if !defined(SUNOS4) && !(defined(ULTRIX) && defined(__GNUC__)) # if defined(POSIX_TYPES) || defined(SVR4) || defined(HPUX) extern struct passwd *FDECL(getpwuid,(uid_t)); # else extern struct passwd *FDECL(getpwuid,(int)); # endif # endif #endif extern struct passwd *FDECL(getpwnam,(const char *)); #ifdef CHDIR static void FDECL(chdirx, (const char *,BOOLEAN_P)); #endif /* CHDIR */ static boolean NDECL(whoami); static void FDECL(process_options, (int, char **)); #ifdef _M_UNIX extern void NDECL(check_sco_console); extern void NDECL(init_sco_cons); #endif #ifdef __linux__ extern void NDECL(check_linux_console); extern void NDECL(init_linux_cons); #endif static void NDECL(wd_message); #ifdef WIZARD static boolean wiz_error_flag = FALSE; #endif int main(argc,argv) int argc; char *argv[]; { register int fd; #ifdef CHDIR register char *dir; #endif boolean exact_username; #if defined(__APPLE__) /* special hack to change working directory to a resource fork when running from finder --sam */ #define MAC_PATH_VALUE ".app/Contents/MacOS/" char mac_cwd[1024], *mac_exe = argv[0], *mac_tmp; int arg0_len = strlen(mac_exe), mac_tmp_len, mac_lhs_len=0; getcwd(mac_cwd, 1024); if(mac_exe[0] == '/' && !strcmp(mac_cwd, "/")) { if((mac_exe = strrchr(mac_exe, '/'))) mac_exe++; else mac_exe = argv[0]; mac_tmp_len = (strlen(mac_exe) * 2) + strlen(MAC_PATH_VALUE); if(mac_tmp_len <= arg0_len) { mac_tmp = malloc(mac_tmp_len + 1); sprintf(mac_tmp, "%s%s%s", mac_exe, MAC_PATH_VALUE, mac_exe); if(!strcmp(argv[0] + (arg0_len - mac_tmp_len), mac_tmp)) { mac_lhs_len = (arg0_len - mac_tmp_len) + strlen(mac_exe) + 5; if(mac_lhs_len > mac_tmp_len - 1) mac_tmp = realloc(mac_tmp, mac_lhs_len); strncpy(mac_tmp, argv[0], mac_lhs_len); mac_tmp[mac_lhs_len] = '\0'; chdir(mac_tmp); } free(mac_tmp); } } #endif hname = argv[0]; hackpid = getpid(); (void) umask(0777 & ~FCMASK); choose_windows(DEFAULT_WINDOW_SYS); #ifdef CHDIR /* otherwise no chdir() */ /* * See if we must change directory to the playground. * (Perhaps hack runs suid and playground is inaccessible * for the player.) * The environment variable HACKDIR is overridden by a * -d command line option (must be the first option given) */ dir = nh_getenv("NETHACKDIR"); if (!dir) dir = nh_getenv("HACKDIR"); #endif if(argc > 1) { #ifdef CHDIR if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else */ argc--; argv++; dir = argv[0]+2; if(*dir == '=' || *dir == ':') dir++; if(!*dir && argc > 1) { argc--; argv++; dir = argv[0]; } if(!*dir) error("Flag -d must be followed by a directory name."); } if (argc > 1) #endif /* CHDIR */ /* * Now we know the directory containing 'record' and * may do a prscore(). Exclude `-style' - it's a Qt option. */ if (!strncmp(argv[1], "-s", 2) && strncmp(argv[1], "-style", 6)) { #ifdef CHDIR chdirx(dir,0); #endif prscore(argc, argv); exit(EXIT_SUCCESS); } } /* * Change directories before we initialize the window system so * we can find the tile file. */ #ifdef CHDIR chdirx(dir,1); #endif #ifdef _M_UNIX check_sco_console(); #endif #ifdef __linux__ check_linux_console(); #endif initoptions(); init_nhwindows(&argc,argv); exact_username = whoami(); #ifdef _M_UNIX init_sco_cons(); #endif #ifdef __linux__ init_linux_cons(); #endif /* * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ (void) signal(SIGHUP, (SIG_RET_TYPE) hangup); #ifdef SIGXCPU (void) signal(SIGXCPU, (SIG_RET_TYPE) hangup); #endif process_options(argc, argv); /* command line options */ #ifdef DEF_PAGER if(!(catmore = nh_getenv("HACKPAGER")) && !(catmore = nh_getenv("PAGER"))) catmore = DEF_PAGER; #endif #ifdef MAIL getmailstatus(); #endif #ifdef WIZARD if (wizard) Strcpy(plname, "wizard"); else #endif if(!*plname || !strncmp(plname, "player", 4) || !strncmp(plname, "games", 4)) { askname(); } else if (exact_username) { /* guard against user names with hyphens in them */ int len = strlen(plname); /* append the current role, if any, so that last dash is ours */ if (++len < sizeof plname) (void)strncat(strcat(plname, "-"), pl_character, sizeof plname - len - 1); } plnamesuffix(); /* strip suffix from name; calls askname() */ /* again if suffix was whole name */ /* accepts any suffix */ #ifdef WIZARD if(!wizard) { #endif /* * check for multiple games under the same name * (if !locknum) or check max nr of players (otherwise) */ (void) signal(SIGQUIT,SIG_IGN); (void) signal(SIGINT,SIG_IGN); if(!locknum) Sprintf(lock, "%d%s", (int)getuid(), plname); getlock(); #ifdef WIZARD } else { Sprintf(lock, "%d%s", (int)getuid(), plname); getlock(); } #endif /* WIZARD */ dlb_init(); /* must be before newgame() */ /* * Initialization of the boundaries of the mazes * Both boundaries have to be even. */ x_maze_max = COLNO-1; if (x_maze_max % 2) x_maze_max--; y_maze_max = ROWNO-1; if (y_maze_max % 2) y_maze_max--; /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); if ((fd = restore_saved_game()) >= 0) { #ifdef WIZARD /* Since wizard is actually flags.debug, restoring might * overwrite it. */ boolean remember_wiz_mode = wizard; #endif const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1); (void) chmod(fq_save,0); /* disallow parallel restores */ (void) signal(SIGINT, (SIG_RET_TYPE) done1); #ifdef NEWS if(iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; /* in case dorecover() fails */ } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ if(!dorecover(fd)) goto not_recovered; #ifdef WIZARD if(!wizard && remember_wiz_mode) wizard = TRUE; #endif check_special_room(FALSE); wd_message(); if (discover || wizard) { if(yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else { (void) chmod(fq_save,FCMASK); /* back to readable */ compress(fq_save); } } flags.move = 0; } else { not_recovered: player_selection(); newgame(); wd_message(); flags.move = 0; set_wear(); (void) pickup(1); } moveloop(); exit(EXIT_SUCCESS); /*NOTREACHED*/ return(0); } static void process_options(argc, argv) int argc; char *argv[]; { int i; /* * Process options. */ while(argc > 1 && argv[1][0] == '-'){ argv++; argc--; switch(argv[0][1]){ case 'D': #ifdef WIZARD { char *user; int uid; struct passwd *pw = (struct passwd *)0; uid = getuid(); user = getlogin(); if (user) { pw = getpwnam(user); if (pw && (pw->pw_uid != uid)) pw = 0; } if (pw == 0) { user = nh_getenv("USER"); if (user) { pw = getpwnam(user); if (pw && (pw->pw_uid != uid)) pw = 0; } if (pw == 0) { pw = getpwuid(uid); } } if (pw && !strcmp(pw->pw_name,WIZARD)) { wizard = TRUE; break; } } /* otherwise fall thru to discover */ wiz_error_flag = TRUE; #endif case 'X': discover = TRUE; break; #ifdef NEWS case 'n': iflags.news = FALSE; break; #endif case 'u': if(argv[0][2]) (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); else if(argc > 1) { argc--; argv++; (void) strncpy(plname, argv[0], sizeof(plname)-1); } else raw_print("Player name expected after -u"); break; case 'I': case 'i': if (!strncmpi(argv[0]+1, "IBM", 3)) switch_graphics(IBM_GRAPHICS); break; /* case 'D': */ case 'd': if (!strncmpi(argv[0]+1, "DEC", 3)) switch_graphics(DEC_GRAPHICS); break; case 'p': /* profession (role) */ if (argv[0][2]) { if ((i = str2role(&argv[0][2])) >= 0) flags.initrole = i; } else if (argc > 1) { argc--; argv++; if ((i = str2role(argv[0])) >= 0) flags.initrole = i; } break; case 'r': /* race */ if (argv[0][2]) { if ((i = str2race(&argv[0][2])) >= 0) flags.initrace = i; } else if (argc > 1) { argc--; argv++; if ((i = str2race(argv[0])) >= 0) flags.initrace = i; } break; case '@': flags.randomall = 1; break; default: if ((i = str2role(&argv[0][1])) >= 0) { flags.initrole = i; break; } /* else raw_printf("Unknown option: %s", *argv); */ } } if(argc > 1) locknum = atoi(argv[1]); #ifdef MAX_NR_OF_PLAYERS if(!locknum || locknum > MAX_NR_OF_PLAYERS) locknum = MAX_NR_OF_PLAYERS; #endif } #ifdef CHDIR static void chdirx(dir, wr) const char *dir; boolean wr; { if (dir /* User specified directory? */ # ifdef HACKDIR && strcmp(dir, HACKDIR) /* and not the default? */ # endif ) { # ifdef SECURE (void) setgid(getgid()); (void) setuid(getuid()); /* Ron Wessels */ # endif } else { /* non-default data files is a sign that scores may not be * compatible, or perhaps that a binary not fitting this * system's layout is being used. */ # ifdef VAR_PLAYGROUND int len = strlen(VAR_PLAYGROUND); fqn_prefix[SCOREPREFIX] = (char *)alloc(len+2); Strcpy(fqn_prefix[SCOREPREFIX], VAR_PLAYGROUND); if (fqn_prefix[SCOREPREFIX][len-1] != '/') { fqn_prefix[SCOREPREFIX][len] = '/'; fqn_prefix[SCOREPREFIX][len+1] = '\0'; } # endif } # ifdef HACKDIR if (dir == (const char *)0) dir = HACKDIR; # endif if (dir && chdir(dir) < 0) { perror(dir); error("Cannot chdir to %s.", dir); } /* warn the player if we can't write the record file */ /* perhaps we should also test whether . is writable */ /* unfortunately the access system-call is worthless */ if (wr) { # ifdef VAR_PLAYGROUND fqn_prefix[LEVELPREFIX] = fqn_prefix[SCOREPREFIX]; fqn_prefix[SAVEPREFIX] = fqn_prefix[SCOREPREFIX]; fqn_prefix[BONESPREFIX] = fqn_prefix[SCOREPREFIX]; fqn_prefix[LOCKPREFIX] = fqn_prefix[SCOREPREFIX]; fqn_prefix[TROUBLEPREFIX] = fqn_prefix[SCOREPREFIX]; # endif check_recordfile(dir); } } #endif /* CHDIR */ static boolean whoami() { /* * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS * 2. Use $USER or $LOGNAME (if 1. fails) * 3. Use getlogin() (if 2. fails) * The resulting name is overridden by command line options. * If everything fails, or if the resulting name is some generic * account like "games", "play", "player", "hack" then eventually * we'll ask him. * Note that we trust the user here; it is possible to play under * somebody else's name. */ register char *s; if (*plname) return FALSE; if(/* !*plname && */ (s = nh_getenv("USER"))) (void) strncpy(plname, s, sizeof(plname)-1); if(!*plname && (s = nh_getenv("LOGNAME"))) (void) strncpy(plname, s, sizeof(plname)-1); if(!*plname && (s = getlogin())) (void) strncpy(plname, s, sizeof(plname)-1); return TRUE; } #ifdef PORT_HELP void port_help() { /* * Display unix-specific help. Just show contents of the helpfile * named by PORT_HELP. */ display_file(PORT_HELP, TRUE); } #endif static void wd_message() { #ifdef WIZARD if (wiz_error_flag) { pline("Only user \"%s\" may access debug (wizard) mode.", # ifndef KR1ED WIZARD); # else WIZARD_NAME); # endif pline("Entering discovery mode instead."); } else #endif if (discover) You("are in non-scoring discovery mode."); } /* * Add a slash to any name not ending in /. There must * be room for the / */ void append_slash(name) char *name; { char *ptr; if (!*name) return; ptr = name + (strlen(name) - 1); if (*ptr != '/') { *++ptr = '/'; *++ptr = '\0'; } return; } /*unixmain.c*/ nethack-3.4.3/sys/unix/unixres.c0100644000000000000000000000740707764735041015324 0ustar rootroot/* SCCS Id: @(#)unixres.c 3.4 2001/07/08 */ /* Copyright (c) Slash'EM development team, 2001. */ /* NetHack may be freely redistributed. See license for details. */ /* [ALI] This module defines nh_xxx functions to replace getuid etc which * will hide privileges from the caller if so desired. * * Currently supported UNIX variants: * Linux version 2.1.44 and above * FreeBSD (versions unknown) * * Note: SunOS and Solaris have no mechanism for retrieving the saved id, * so temporarily dropping privileges on these systems is sufficient to * hide them. */ #include "config.h" #ifdef GETRES_SUPPORT # if defined(LINUX) /* requires dynamic linking with libc */ #include static int real_getresuid(ruid, euid, suid) uid_t *ruid, *euid, *suid; { int (*f)(uid_t *, uid_t *, uid_t *); /* getresuid signature */ f = dlsym(RTLD_NEXT, "getresuid"); if (!f) return -1; return f(ruid, euid, suid); } static int real_getresgid(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { int (*f)(gid_t *, gid_t *, gid_t *); /* getresgid signature */ f = dlsym(RTLD_NEXT, "getresgid"); if (!f) return -1; return f(rgid, egid, sgid); } # else # if defined(BSD) || defined(SVR4) # ifdef SYS_getresuid static int real_getresuid(ruid, euid, suid) uid_t *ruid, *euid, *suid; { return syscall(SYS_getresuid, ruid, euid, suid); } # else /* SYS_getresuid */ #ifdef SVR4 #include #endif /* SVR4 */ static int real_getresuid(ruid, euid, suid) uid_t *ruid, *euid, *suid; { int retval; int pfd[2]; struct stat st; if (pipe(pfd)) return -1; retval = fstat(pfd[0], &st); close(pfd[0]); close(pfd[1]); if (!retval) { *euid = st.st_uid; *ruid = syscall(SYS_getuid); *suid = *ruid; /* Not supported under SVR4 */ } return retval; } # endif /* SYS_getresuid */ # ifdef SYS_getresgid static int real_getresgid(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { return syscall(SYS_getresgid, rgid, egid, sgid); } # else /* SYS_getresgid */ static int real_getresgid(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { int retval; int pfd[2]; struct stat st; if (pipe(pfd)) return -1; retval = fstat(pfd[0], &st); close(pfd[0]); close(pfd[1]); if (!retval) { *egid = st.st_gid; *rgid = syscall(SYS_getgid); *sgid = *rgid; /* Not supported under SVR4 */ } return retval; } # endif /* SYS_getresgid */ # endif /* BSD || SVR4 */ # endif /* LINUX */ static unsigned int hiding_privileges = 0; /* * Note: returns the value _after_ action. */ int hide_privileges(flag) boolean flag; { if (flag) hiding_privileges++; else if (hiding_privileges) hiding_privileges--; return hiding_privileges; } int nh_getresuid(ruid, euid, suid) uid_t *ruid, *euid, *suid; { int retval = real_getresuid(ruid, euid, suid); if (!retval && hiding_privileges) *euid = *suid = *ruid; return retval; } uid_t nh_getuid() { uid_t ruid, euid, suid; (void) real_getresuid(&ruid, &euid, &suid); return ruid; } uid_t nh_geteuid() { uid_t ruid, euid, suid; (void) real_getresuid(&ruid, &euid, &suid); if (hiding_privileges) euid = ruid; return euid; } int nh_getresgid(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { int retval = real_getresgid(rgid, egid, sgid); if (!retval && hiding_privileges) *egid = *sgid = *rgid; return retval; } gid_t nh_getgid() { gid_t rgid, egid, sgid; (void) real_getresgid(&rgid, &egid, &sgid); return rgid; } gid_t nh_getegid() { gid_t rgid, egid, sgid; (void) real_getresgid(&rgid, &egid, &sgid); if (hiding_privileges) egid = rgid; return egid; } #else /* GETRES_SUPPORT */ # ifdef GNOME_GRAPHICS int hide_privileges(flag) boolean flag; { return 0; } # endif #endif /* GETRES_SUPPORT */ nethack-3.4.3/sys/unix/unixunix.c0100644000000000000000000001704307764735041015513 0ustar rootroot/* SCCS Id: @(#)unixunix.c 3.4 1994/11/07 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file collects some Unix dependencies */ #include "hack.h" /* mainly for index() which depends on BSD */ #include #include #if defined(NO_FILE_LINKS) || defined(SUNOS4) || defined(POSIX_TYPES) #include #endif #include #ifdef _M_UNIX extern void NDECL(sco_mapon); extern void NDECL(sco_mapoff); #endif #ifdef __linux__ extern void NDECL(linux_mapon); extern void NDECL(linux_mapoff); #endif #ifndef NHSTDC extern int errno; #endif static struct stat buf; /* see whether we should throw away this xlock file */ static int veryold(fd) int fd; { time_t date; if(fstat(fd, &buf)) return(0); /* cannot get status */ #ifndef INSURANCE if(buf.st_size != sizeof(int)) return(0); /* not an xlock file */ #endif #if defined(BSD) && !defined(POSIX_TYPES) (void) time((long *)(&date)); #else (void) time(&date); #endif if(date - buf.st_mtime < 3L*24L*60L*60L) { /* recent */ int lockedpid; /* should be the same size as hackpid */ if(read(fd, (genericptr_t)&lockedpid, sizeof(lockedpid)) != sizeof(lockedpid)) /* strange ... */ return(0); /* From: Rick Adams */ /* This will work on 4.1cbsd, 4.2bsd and system 3? & 5. */ /* It will do nothing on V7 or 4.1bsd. */ #ifndef NETWORK /* It will do a VERY BAD THING if the playground is shared by more than one machine! -pem */ if(!(kill(lockedpid, 0) == -1 && errno == ESRCH)) #endif return(0); } (void) close(fd); return(1); } static int eraseoldlocks() { register int i; /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up */ for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) { /* try to remove all */ set_levelfile_name(lock, i); (void) unlink(fqname(lock, LEVELPREFIX, 0)); } set_levelfile_name(lock, 0); if (unlink(fqname(lock, LEVELPREFIX, 0))) return(0); /* cannot remove it */ return(1); /* success! */ } void getlock() { register int i = 0, fd, c; const char *fq_lock; #ifdef TTY_GRAPHICS /* idea from rpick%ucqais@uccba.uc.edu * prevent automated rerolling of characters * test input (fd0) so that tee'ing output to get a screen dump still * works * also incidentally prevents development of any hack-o-matic programs */ /* added check for window-system type -dlc */ if (!strcmp(windowprocs.name, "tty")) if (!isatty(0)) error("You must play from a terminal."); #endif /* we ignore QUIT and INT at this point */ if (!lock_file(HLOCK, LOCKPREFIX, 10)) { wait_synch(); error("%s", ""); } regularize(lock); set_levelfile_name(lock, 0); if(locknum) { if(locknum > 25) locknum = 25; do { lock[0] = 'a' + i++; fq_lock = fqname(lock, LEVELPREFIX, 0); if((fd = open(fq_lock, 0)) == -1) { if(errno == ENOENT) goto gotlock; /* no such file */ perror(fq_lock); unlock_file(HLOCK); error("Cannot open %s", fq_lock); } if(veryold(fd) /* closes fd if true */ && eraseoldlocks()) goto gotlock; (void) close(fd); } while(i < locknum); unlock_file(HLOCK); error("Too many hacks running now."); } else { fq_lock = fqname(lock, LEVELPREFIX, 0); if((fd = open(fq_lock, 0)) == -1) { if(errno == ENOENT) goto gotlock; /* no such file */ perror(fq_lock); unlock_file(HLOCK); error("Cannot open %s", fq_lock); } if(veryold(fd) /* closes fd if true */ && eraseoldlocks()) goto gotlock; (void) close(fd); if(iflags.window_inited) { c = yn("There is already a game in progress under your name. Destroy old game?"); } else { (void) printf("\nThere is already a game in progress under your name."); (void) printf(" Destroy old game? [yn] "); (void) fflush(stdout); c = getchar(); (void) putchar(c); (void) fflush(stdout); while (getchar() != '\n') ; /* eat rest of line and newline */ } if(c == 'y' || c == 'Y') if(eraseoldlocks()) goto gotlock; else { unlock_file(HLOCK); error("Couldn't destroy old game."); } else { unlock_file(HLOCK); error("%s", ""); } } gotlock: fd = creat(fq_lock, FCMASK); unlock_file(HLOCK); if(fd == -1) { error("cannot creat lock file (%s).", fq_lock); } else { if(write(fd, (genericptr_t) &hackpid, sizeof(hackpid)) != sizeof(hackpid)){ error("cannot write lock (%s)", fq_lock); } if(close(fd) == -1) { error("cannot close lock (%s)", fq_lock); } } } void regularize(s) /* normalize file name - we don't like .'s, /'s, spaces */ register char *s; { register char *lp; while((lp=index(s, '.')) || (lp=index(s, '/')) || (lp=index(s,' '))) *lp = '_'; #if defined(SYSV) && !defined(AIX_31) && !defined(SVR4) && !defined(LINUX) && !defined(__APPLE__) /* avoid problems with 14 character file name limit */ # ifdef COMPRESS /* leave room for .e from error and .Z from compress appended to * save files */ { # ifdef COMPRESS_EXTENSION int i = 12 - strlen(COMPRESS_EXTENSION); # else int i = 10; /* should never happen... */ # endif if(strlen(s) > i) s[i] = '\0'; } # else if(strlen(s) > 11) /* leave room for .nn appended to level files */ s[11] = '\0'; # endif #endif } #if defined(TIMED_DELAY) && !defined(msleep) && defined(SYSV) #include void msleep(msec) unsigned msec; /* milliseconds */ { struct pollfd unused; int msecs = msec; /* poll API is signed */ if (msecs < 0) msecs = 0; /* avoid infinite sleep */ (void) poll(&unused, (unsigned long)0, msecs); } #endif /* TIMED_DELAY for SYSV */ #ifdef SHELL int dosh() { register char *str; if(child(0)) { if((str = getenv("SHELL")) != (char*)0) (void) execl(str, str, (char *)0); else (void) execl("/bin/sh", "sh", (char *)0); raw_print("sh: cannot execute."); exit(EXIT_FAILURE); } return 0; } #endif /* SHELL */ #if defined(SHELL) || defined(DEF_PAGER) || defined(DEF_MAILREADER) int child(wt) int wt; { register int f; suspend_nhwindows((char *)0); /* also calls end_screen() */ #ifdef _M_UNIX sco_mapon(); #endif #ifdef __linux__ linux_mapon(); #endif if((f = fork()) == 0){ /* child */ (void) setgid(getgid()); (void) setuid(getuid()); #ifdef CHDIR (void) chdir(getenv("HOME")); #endif return(1); } if(f == -1) { /* cannot fork */ pline("Fork failed. Try again."); return(0); } /* fork succeeded; wait for child to exit */ (void) signal(SIGINT,SIG_IGN); (void) signal(SIGQUIT,SIG_IGN); (void) wait( (int *) 0); #ifdef _M_UNIX sco_mapoff(); #endif #ifdef __linux__ linux_mapoff(); #endif (void) signal(SIGINT, (SIG_RET_TYPE) done1); #ifdef WIZARD if(wizard) (void) signal(SIGQUIT,SIG_DFL); #endif if(wt) { raw_print(""); wait_synch(); } resume_nhwindows(); return(0); } #endif #ifdef GETRES_SUPPORT extern int FDECL(nh_getresuid, (uid_t *, uid_t *, uid_t *)); extern uid_t NDECL(nh_getuid); extern uid_t NDECL(nh_geteuid); extern int FDECL(nh_getresgid, (gid_t *, gid_t *, gid_t *)); extern gid_t NDECL(nh_getgid); extern gid_t NDECL(nh_getegid); int (getresuid)(ruid, euid, suid) uid_t *ruid, *euid, *suid; { return nh_getresuid(ruid, euid, suid); } uid_t (getuid)() { return nh_getuid(); } uid_t (geteuid)() { return nh_geteuid(); } int (getresgid)(rgid, egid, sgid) gid_t *rgid, *egid, *sgid; { return nh_getresgid(rgid, egid, sgid); } gid_t (getgid)() { return nh_getgid(); } gid_t (getegid)() { return nh_getegid(); } #endif /* GETRES_SUPPORT */ nethack-3.4.3/sys/vms/0040755000000000000000000000000007764735105013301 5ustar rootrootnethack-3.4.3/sys/vms/Install.vms0100644000000000000000000007060407764735041015441 0ustar rootroot Instructions for Installing NetHack 3.4.3 on a VMS (aka OpenVMS) system ========================================= 0. Please read this entire file before trying to build or install NetHack, then read it again! 1. Building NetHack requires a C compiler (either Compaq C, DEC C, VAX C, or GNU C) and VMS version V4.6 or later (but see note #9). This release has been tested with Compaq C V6.4 on Alpha/VMS V7.3-1 and with VAX C V3.2 and GNU C 2.7.1 on VAX/VMS V5.5-2. The build procedure (vmsbuild.com) should not need to be modified; it accepts an option for selecting the compiler, and it can detect different versions which might require specific command qualifiers. Versions of VAXC earlier than V2.3 will produce many warning messages (about 200 per source file; over to 25,000 total!), but NetHack has been verified to compile, link, and execute correctly when built with VAXC V2.2 using vmsbuild.com. There is also a set of Makefiles suitable for use with MMS or MMK; they may or may not work with other make utilities. 2. Make sure all the NetHack files are in the appropriate directory structure. You should set up a directory--referred to as "top" below and in some of the assorted files, but which may be a subdirectory-- that has these subdirectories [.dat] -- data files [.doc] -- documentation files [.include] -- C header files [.src] -- primary source files [.sys] -- parent for [.sys.*] [.sys .share] -- files shared by several ports, including VMS [.sys .vms] -- VMS-specific source and support files [.util] -- sources for essential utility programs [.win] -- parent for [.win.*] [.win .tty] -- "window" routines for ordinary terminals (including terminal windows on workstations) The following subdirectories may be present, but are not useful for building NetHack on VMS and are not required: [.sys .amiga] -- AmigaDOS [.sys .atari] -- Atari TOS [.sys .be] -- BeBox BeOS [.sys .mac] -- Macintosh [.sys .msdos] -- MSDOS for IBM PCs and compatibles [.sys .os2] -- OS/2 [.sys .share .sounds] -- AIFF format audio files [.sys .unix] -- guess :-) [.sys .wince] -- Windows CE [.sys .wince .ceinc] -- more WinCE [.sys .wince .ceinc .sys] -- ditto [.sys .winnt] -- Windows NT [.win .gem] -- window routines for Atari/GEM [.win .gnome] -- window routines for Unix/GNOME [.win .Qt] -- window routines for Qt [.win .share] -- "tile" graphic support [.win .win32] -- Windows NT and Windows CE [.win .X11] -- window routines for X-Windows; requires X11R4 or later and MIT's Athena Widget set You must arrange things in this structure or the supplied procedures and instructions in this file will not work properly. Several DCL command files are present in the [.sys.vms] subdirectory and won't work as intended if they're moved elsewhere. The file called Files in the top directory contains lists of everything that should be in each subdirectory, including things that are constructed as NetHack is being built. 3. Prior to beginning compilation, go to the [.include] subdirectory and edit vmsconf.h according to its comments. You should set Local_WIZARD and Local_HACKDIR to appropriate values, and you might want to define TEXTCOLOR if you have any color VAXstations or color terminals which handle ANSI-format escape sequences to set foreground and background color for text characters. (VT241/VT340 color graphics won't work.) Other things which may be of interest are SECURE if you intend to set up NetHack as an installed image which is granted privileges, and SHELL which should be disabled if you intend to allow captive accounts to run NetHack. You may also want to edit file config.h, but that's only necessary if you want or need to disable some of the game options. The distributed copy of config.h will work successfully on VMS; vmsconf.h has conditional code to deal with the UNIX-specific items. 4. If you have the programming utilities lex or flex and yacc or bison, you may edit the procedure [.sys.vms]spec_lev.com and execute it to process several source files for NetHack's special level and dungeon compilers. If you don't modify spec_lev.com, it will copy some pre-processed versions of the appropriate files (dgn_lex.c, lev_lex.c, dgn_yacc.c, lev_yacc.c, dgn_comp.h, and lev_comp.h) from [.sys.share] into [.util]*.c and [.include]*.h. $ @[.SYS.VMS]SPEC_LEV ![OPTIONAL] If you perform this step, do it prior to executing vmsbuild.com; if you don't perform this step, vmsbuild.com will do so for you. 5. To build NETHACK.EXE and its auxiliary programs, execute the following DCL command: $ @[.SYS.VMS]VMSBUILD !defaults to CC, either VAXC or DECC or $ @[.SYS.VMS]VMSBUILD "GNUC" !force "GCC" It can take quite a bit of time for a full build to complete. vmsbuild.com will display some feedback as it executes; generally this will be the name of each source file that's about to be compiled or the name of the executable that has just been linked. 6. If you have already started (or finished) a build and decide to start over with a different compiler, you should DELETE [.SRC]CRTL.OPT;* first. 7. After compilation, it's time to perform installation. Go back to the top directory. Either edit [.sys.vms]install.com to indicate where you want everything to be installed, or specify the location and "playground" owner on the command line. Then execute either $ @[.SYS.VMS]INSTALL or $ @[.SYS.VMS]INSTALL location owner where location is a device:[directory] specification and owner is either a rights identifier or UIC. If install.com is not modified and if values aren't supplied on the command line, the default values used are the translation of logical name HACKDIR, if any, or else [.PLAY] (relative to the current directory), and the UIC for the current process. install.com will use the auxiliary programs constructed by vmsbuild.com to process quite a few data files in the [.dat] subdirectory. Then it will create the playground directory, if necessary, plus the associated [.save] subdirectory. Next it will copy the data files into the playground; this step can take a while. Finally it will copy nethack.exe and a few additional support files. After it completes, the files [.src]nethack.olb, [.src]nethack.exe, [.util]*.obj, [.util]*_comp.exe, and [.util]makedefs.exe can be deleted in order to save disk space if desired. The other program, [.util]recover.exe, should not be deleted unless you make a copy of it somewhere--perhaps in the playground directory--first. It can be used to resurrect some games disrupted by system or program crash. 8. The file nethack.com which is copied to the playground directory can be used to invoke NetHack, or nethack.exe can be run directly. Most of the command-line options specified in the Unix man-page (file [.doc]nethack.txt) are also applicable to VMS. Some comments at the beginning of nethack.com illustrate several of the options. New players should read the file "Guidebook.txt" which will be copied into the playground directory as "Guidebook.doc". Notes: 1. Save files and bones files from versions 3.4.0, 3.4.1 and 3.4.2 will work with 3.4.3; those from earlier versions will not. The scoreboard file (RECORD) from 3.4.x or 3.3.x will also work; one from version 3.2.x is slightly different format but should be compatible. 2. To specify user-preference options in your environment, define the logical name NETHACKOPTIONS to have the value of a quoted string containing a comma separated list of option values. The option names are case-insensitive. $ define nethackoptions "noAutoPickup,Dog:Rover,Cat:Felix,DECgraphics" One value you'll probably want to specify is "noLegacy" to turn off the initial introductory passage. The "checkpoint" option controls whether or not enough data is saved to disk so that the set of level files left behind after a crash contains sufficient information for recover.exe to be able to construct a save file after the fact. The tradeoff for enabling checkpoint is that using it makes level changes do more I/O and take longer. The "menustyle" option controls some aspects of the user interface, and can be set to "menustyle:traditional" to make nethack behave more like older versions. If logical name or DCL symbol NETHACKOPTIONS is not defined, NetHack will try HACKOPTIONS instead. Regardless of whether or not either is defined, it will also try to find a configuration file containing additional option settings. If the value of the translation of NETHACKOPTIONS--or HACKOPTIONS--begins with an "@" character then the rest of the translation is assumed to be the name of the configuration file. Otherwise, the following are tried: file specified by logical name NETHACKINI, file SYS$LOGIN:NETHACK.INI, and file HOME:NETHACK.CNF (note that the C run-time library sets up the value of HOME to match sys$login). Syntax for the configuration file is similar to NETHACKOPTIONS, but multiple lines can be used, each must start with OPTIONS=, and comments can be included by placing '#' in the first column. Several options which take more complex values (graphics representation) can also be present; see the "Guidebook" for details. (Guidebook.txt can be found in the [.doc] subdirectory; a copy gets placed in the playground directory by install.com. Also, an example configuration file can be found in [.win.X11]nethack.rc.) 3. Instead of using vmsbuild.com to compile and link everything, you can use the set of Makefiles found in the vms subdirectory, provided you have an appropriate and compatible make utility. They've been tested using MMK, a freeware clone of Digital's MMS. There are five of them, and the suffix or filetype on their names indicates where they should be placed. $ copy [.sys.vms]Makefile.top []Makefile. $ copy [.sys.vms]Makefile.src [.src]Makefile. $ copy [.sys.vms]Makefile.utl [.util]Makefile. $ copy [.sys.vms]Makefile.dat [.dat]Makefile. $ copy [.sys.vms]Makefile.doc [.doc]Makefile. After doing that, edit [.src]Makefile and [.util]Makefile to specify pertinent compiler options in CFLAGS, linker options in LFLAGS, and libraries in LIBS and/or MORELIBS if the default values aren't right. Be sure to make compatible compilation and linking settings in both files. While in there, edit [.util]Makefile to specify the appropriate values for lex and yacc, _or_ move to that directory and use MMS or make to build targets no_lex and no_yacc which will copy several pre-processed files from [.sys.share] into [.util]. Finally, edit Makefile in the top directory to specify values for GAMEDIR and GAMEOWNER. This top Makefile invokes [.sys.vms]install.com to do much of the actual installation work, so if you want to make any customizations or file protection changes, edit install.com to suit. Also set MAKE in all of the Makefiles to the appropriate command if not using MMS or MMK. Once the Makefiles are tailored for your site, give the command $ mms all,install or $ make all install To compile and install everything. The object files compiled via the Makefiles are left as individual .OBJ files rather than placed into an object library (in contrast to step #7 above and note #10 below). These Makefiles are provided on an as-is basis; vmsbuild.com is the preferred way to compile because it's guaranteed to compile and link everything. 4. termcap is an ASCII data file containing descriptions of terminal capabilities and the escape sequences that software must use to take advantage of them. If you do not already have a termcap file in use on your system there is a small one in file [.SYS.SHARE]TERMCAP. It contains definitions for common Digital terminals, also suitable for most clones and emulators. This file is copied into the playground by install.com, and NetHack will use it if it can't find any other one. NetHack uses the following sequence to attempt to locate the termcap file: translation of the logical name TERMCAP (used as-is), file NETHACKDIR:TERMCAP, similar file HACKDIR:TERMCAP, GNU-Emacs file EMACS_LIBRARY:[ETC]TERMCAP.DAT, file []TERMCAP, and lastly file $TERMCAP (which most likely would be a logical name). If NetHack can't find the termcap file, or if the above search sequence finds a different one than you'd prefer, then use the DCL ASSIGN or DEFINE command to define a value for logical name TERMCAP. NetHack also tries fairly hard to figure out what kind of terminal you're using. It checks for logical names (or symbols) NETHACK_TERM, HACK_TERM, EMACS_TERM, and lastly TERM. The last is set up by the C run-time library and you cannot use a logical name or symbol for it. If all those fail, or if whichever one succeeds has a value of "undefined" or "unknown" (which can happen under VMS V5.4-* and V5.5-* for VT420 terminals), NetHack will query the VMS TERMTABLE database used by the SMG library routines. Whatever value NetHack eventually comes up with needs to be the name of an entry in the termcap file, otherwise a message about "Unknown terminal type" will be printed and NetHack will exit. 5. NetHack contains code which attempts to make it secure in case it's installed with privileges (to allow the playground to be protected against world write access). This has only undergone limited testing, so install NetHack with privileges at your own risk. If you discover any potential security holes, please let us know so that we can take steps to correct the problem(s). NetHack always includes filename punctuation when accessing files, so that it should never be affected by inadvertent or malicious logical name definitions, and it always deactivates installed privileges prior to spawning a subprocess. Note to end users: "installing with privileges" is an option for system managers who set up system-wide access to the game. Since CMKRNL privilege and modification of the system boot routines are both required, it is not an option for ordinary users. There are no explicit instructions on how to do such an installation, because only system managers who are already familiar with the process and its potential security ramifications should even consider it. The default setup by install.com assumes no privileges and uses world-writable files to allow arbitrary users to play. This is NOT secure and not advisable in any environment where there are untrustworthy users, but works fine for many sites. If you allow users to run NetHack from captive accounts (VMS 5.1-* or earlier) or from restricted accounts (5.2 and later), you should either make sure that they do not have TMPMBX privilege or else disable NetHack's ability to spawn an interactive subprocess. To disable subprocesses, disable the "!" (shell escape) command by commenting out the definition of SHELL in vmsconf.h prior to building the program. This necessity may be removed in some future release, where NetHack will check for captive accounts instead of spawning unconditionally. Note that disabling the SHELL command also prevents spawning MAIL when scrolls of new mail are received. In order for installed privileges to be used at all, the value of HACKDIR (via Local_HACKDIR in vmsconf.h) compiled into the program must correspond to the actual playground directory. If logical name HACKDIR (or NETHACKDIR) is used to override that value, installed privileges will be deactivated unless its value corresponds to the same device and directory as the internal value. If that internal value contains a logical name, only an executive-mode translation will be honored; if there is no such translation, installed privs will be deactivated. To be able to install nethack.exe with privileges (SYSPRV or GRPPRV, perhaps EXQUOTA, depending on site usage and needs), you'll need to link it with debugging and tracebacks both disabled. You can do this by specifying an argument to vmsbuild.com when performing step #6 above; pass it "/noTrace/noDebug" as the 4th parameter. $ @[.SYS.VMS]VMSBUILD "" "" "" "/noTrace/noDebug" /Trace/noDebug is the linker's normal default. If you've already built NetHack, you can relink with tracebacks disabled by doing $ @[.SYS.VMS]VMSBUILD "LINK" "" "" "/noTrace/noDebug" 6. If you can't or won't install nethack.exe with privileges and if you don't have access to a privileged account yourself, then if you intend to allow other users to access your copy of NetHack you should probably place an ACL on the playground directory and its save subdirectory. The access control list should contain a default protection ACE which grants delete+control access to the playground owner (ie, your own account if there's no special games account involved). install.com does not attempt to do this automatically at the present time. After executing install.com to create the playground directory, perform a pair of commands similar to the following $ SET ACL/ACL=(IDENT=your_id, OPTIONS=DEFAULT, ACCESS=R+W+E+D+C) - $_ device:[playground's.parent.directory]playground.DIR $ SET ACL/ACL=(IDENT=your_id, OPTIONS=DEFAULT, ACCESS=R+W+E+D+C) - $_ device:[playground.directory]SAVE.DIR The two commands use the same options, but SET ACL won't accept a list of files to modify. (For recent versions of VMS, SET ACL was made obsolete in favor of SET FILE/ACL, which in turn has been made obsolete in favor of SET SECURITY/CLASS=FILE/ACL; however, the older forms will still work.) 'your_id' should be the rights identifier which corresponds to the account which should retain access to those files; 'device:[playground's.parent.directory]' is the name of the parent directory for the playground (ie, if your playground directory is disk$foo:[me.games.nethack.play], then you want to specify disk$foo:[me.games.nethack]play.dir on the SET ACL command), and 'device:[playground.directory]' is the playground itself. Those ACLs establish a default protection scheme such that every newly created file in those directories will have an ACL attached to it, and the attached ACL will grant 'your_id' full access to the corresponding file. That should allow you to clear away level files from aborted games, and to delete old save files if necessary. It will not enable you to run recover.exe on behalf of other users, because you won't be able to create files owned by them unless you have elevated privileges. 7. Many NetHack commands can be aborted by sending it the character when it wants input. This is displayed as ESC inside the game. Digital VK201 keyboards (used by VT2xx and VT3xx and older VAXstations) and VK401 keyboards (used by VT4xx, newer VAXstations, and DEC's X Terminals) do not have an key. They may transmit for the key if the terminal or emulator window is set to operate in VT100 mode, or there may be a setup-type option for making the <` | ~> key behave as . If your terminal does not have that, or if it's set to a mode where that won't work, then just use instead. (Press the "[" key while holding down the "Ctrl" key, then release both; and have the same ASCII code and are indistinguishable once they reach the computer; note that VAXstations and X Terminals _can_ tell the difference, but that won't matter for NetHack.) VMS NetHack is configured to use the SYS$QIOW system service for reading characters from the keyboard. This allows ^C and ^Y (as well as ^X and ^O for wizard mode debugging) to be used as commands without being intercepted or interpreted by the terminal driver. The code which parses arrow and function keys is not perfect, and it's possible to get strange results if you hold such keys down or just type too quickly, particularly on slow multiplexor lines. Those keys are never needed in actual play, and most function keys are just treated as for use in aborting partial commands. VMS NetHack also still has code to use SMG$READ_KEYSTROKE instead. That can be activated by modifying vmsconf.h and recompiling, but it should never be necessary. If you use it, you'll need to press either or twice to abort partial commands, or else press an arbitrary function key, such as , once. If SUSPEND is defined in vmsconf.h, is used for that command. Since Unix-style job control is not available, it's used for connecting to the parent process if NetHack is running in a subprocess. When not in a subprocess, it doesn't do anything except give a message to the effect that it's not doing anything.... The suspend command does not save the current game; if you use ^Z to attach to your parent process, be sure to remember to eventually reattach to the NetHack subprocess; otherwise the game in progress won't get saved when you logout. 8. NetHack optionally maintains a logfile which receives one line appended to it whenever a game ends. This can be disabled entirely by adding an "#undef LOGFILE" directive to vmsconf.h prior to building the program, or it can be disabled later by removing the file(s) LOGFILE.;* from the playground directory. If not disabled prior to compilation, the logfile can be reinitialized by simply creating an empty file named LOGFILE in the playground, but make sure that users are able to write into it, or new entries will not be appended. 9. Some attempt at support for VMS versions earlier than V4.6 has been included, but no such obsolete system was available for testing it. vmsbuild.com detects the need for the extra support routines and arranges automatically for them to be compiled. The reason that special support is needed is that the C Run-Time Library (VAXCRTL) underwent a major revision for VMS V4.6 and several routines which NetHack utilizes were not available prior to that upgrade. 10. vmsbuild.com collects almost all of the object files (xxx.OBJ) into an object library (NETHACK.OLB) as it compiles the source files. This should prevent the quota-exceeded problems from the linker that some sites have reported for prior versions. Note that if you compile any source files manually, you'll need to replace those modules in the object library prior to linking the program: $ cc/include=[-.include] [-.sys.vms]vmstty !for example $ libr/obj []nethack vmstty !replace VMSTTY $ @[-.sys.vms]vmsbuild LINK !re-link NETHACK.EXE If you forget to replace the library entry, your newly compiled code will not be included in the new executable image. 11. To access "wizard mode"--intended for debugging purposes, not to spoil the game with unlimited wishes--you must be running from the username compiled into the game via Local_WIZARD in vmsconf.h, and you must specify "-D" on the command line when invoking NetHack. Note that -D must be uppercase, and it must be in quotes to prevent the C run-time library's program startup code from converting it into lowercase. $ @hackdir:nethack "-D" Any character name you specify will be ignored in favor of "wizard". 12. At program startup time, NetHack uses the empty file PERM to prevent two different processes from using the same character name (under the same UIC ownership) at the same time. It does this by temporarily giving that file a second directory entry named PERM.LOCK, then removing the alternate entry once started. If the PERM file is missing or inaccessible, NetHack will give a message and then quit. Several possible messages and their usual causes are: Can't find file perm;1 to lock! PERM.;1 is missing from the playground directory. Fix: reinstall the playground directory using install.com, or use CREATE or an editor to make an empty file named PERM. Version number must be 1. Can't lock perm;1 due to directory protection. The playground directory is not allowing write access. Fix: players need to be able to write files for dungeon levels and "bones" into the playground directory. Set the protection or ACL on the xxx.DIR;1 file in the playground's parent directory to allow write access. Can't unlink perm.lock;1. The empty file PERM.;1 is protected against delete access; only matters under some versions of VMS. Fix: set the protection or ACL on PERM.;1 to allow delete access to players. Under VMS V5.5-2, delete access is not necessary. PERM does not have to remain writable. Waiting for access to perm;1. (# retries left). If some other process is also starting up NetHack at about the same time, you may have to wait a short period. NetHack will retry once per second, counting down to 0. If 0 is reached, the message Perhaps there is an old perm.lock;1 around? will be displayed and then NetHack will give up. Fix: to forcibly remove a stale PERM.LOCK entry, issue the following command $ SET FILE/REMOVE PERM.LOCK;1 from the playground directory. The file PERM should remain intact. Do not use that command for real files, only alternate directory entries. If output from a DIRECTORY command on the playground reports PERM.LOCK;1 no such file then someone has deleted PERM.;1 while the synonym entry was still in place, and PERM.LOCK was left as a dangling name which no longer points at any file. The SET FILE/REMOVE command above will fix the dangling name; a new PERM.;1 will need to be created as mentioned above. In similar fashion, synchronized access to the scoreboard file RECORD is accomplished using temporary entry RECORD.LOCK and LOGFILE using entry LOGFILE.LOCK. 13. Unless you have both Motif and the Athena Widget set from MIT, you will not be able to use the X11 interface on VMS. Even if you do have both those things, such a configuration has not been tested and there are no provisions for it in vmsbuild.com. Makefile.src does have the extra source files listed, but not the necessary libraries. The X11 port will not compile and link with DECwindows, but it will be able to display on a VMS DECwindows X server provided that it and its Unix X client have a compatible transport between them (either TCP/IP added to VMS or DECnet added to Unix) and session security is set up appropriately. You'll need to add the contents of file [.win.X11]NetHack.ad into your DECW$USER_DEFAULTS:DECW$XDEFAULTS.DAT, and modify some of the lines. The DECwindows window manager does not support having input focus automatically follow the pointer, so you should uncomment the "NetHack*autofocus" resource line. (For Motif this may not be necessary, depending on customization options.) Uncommenting the "NetHack*slow" line is highly recommended. You'll also need to set "NetHack*fonts: fixed" (rather than "variable"), and either set the map font to "fixed" too or install the "nh10" font that comes in file [.win.X11]nh10.bdf. If NetHack warns that the map font is variable, then something isn't set up properly. After creating or modifying decw$xdefaults.dat, you must restart the window manager in order for any changes to take effect; it's easiest to just make the session manager quit and then log in again. 14. If necessary, send problem reports via e-mail to Always include version information for NetHack, the operating system, and the C compiler used. 20-OCT-2003 nethack-3.4.3/sys/vms/Makefile.dat0100644000000000000000000000774207764735041015516 0ustar rootroot# NetHack Makefile (VMS) - data files: special levels and other data. # SCCS Id: @(#)Makefile.dat 3.4 2002/03/02 # Copy this file to [.dat]Makefile.; no editing needed. MAKE = $(MMS) CD = set default ECHO = write sys$output NOOP = continue # don't do anything interesting RUN = mcr # simplest way to pass command line args TOUCH = append/New _NLA0: # only one file per $(TOUCH) # support directories, relative to each other and to 'src' DAT = [-.dat] UTL = [-.util] WINSHR = [-.win.share] WINX11 = [-.win.X11] # utilities; must match Makefile.utl in spelling and punctuation MAKEDEFS = $(UTL)makedefs.exe; LEVCOMP = $(UTL)lev_comp.exe; DGNCOMP = $(UTL)dgn_comp.exe; DLB = $(UTL)dlb.exe; TILE2X11 = $(UTL)tile2x11.exe; UTILMARKER = $(UTL)util.timestamp; # note: filespecs have enough punctuation to satisfy DELETE MARKERS = spec_levs.timestamp;,quest_levs.timestamp; VARDAT = data.;,rumors.;,quest.dat;,oracles.;,options.; DUNGEON = dungeon.; X11TILES= x11tiles.; # note: the level lists need to be space separated QUESTLEVS = Arch.des Barb.des Caveman.des Healer.des Knight.des \ Monk.des Priest.des Ranger.des Rogue.des Samurai.des Tourist.des \ Valkyrie.des Wizard.des SPECLEVS = bigroom.des castle.des endgame.des gehennom.des knox.des \ medusa.des mines.des oracle.des sokoban.des tower.des yendor.des all : $(VARDAT) $(DUNGEON) $(MARKERS) $(DLB) @ $(ECHO) "data files are up to date." # these are convenience targets for "manual" interactive use spec_levs : spev_levs.timestamp @ $(ECHO) "special levels are up to date." quest_levs : quest_levs.timestamp @ $(ECHO) "quest levels are up to date." dungeon : $(DUNGEON) @ $(ECHO) "dungeon is up to date." data : data.; @ $(NOOP) rumors : rumors.; @ $(NOOP) quest.dat : quest.dat; @ $(NOOP) oracles : oracles.; @ $(NOOP) options : options.; @ $(NOOP) x11tiles : $(X11TILES) @ $(NOOP) $(MAKEDEFS) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(MAKEDEFS) @ $(CD) $(DAT) $(DGNCOMP) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(DGNCOMP) @ $(CD) $(DAT) $(LEVCOMP) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(LEVCOMP) @ $(CD) $(DAT) $(DLB) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(DLB) @ $(CD) $(DAT) $(TILE2X11) : $(UTILMARKER) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(TILE2X11) @ $(CD) $(DAT) $(X11TILES) : $(TILE2X11) \ $(WINSHR)monsters.txt $(WINSHR)objects.txt $(WINSHR)other.txt $(RUN) $(TILE2X11) \ $(WINSHR)monsters.txt $(WINSHR)objects.txt $(WINSHR)other.txt pet_mark.xbm : $(WINX11)pet_mark.xbm copy $(WINX11)pet_mark.xbm pet_mark.xbm rip.xpm : $(WINX11)rip.xpm copy $(WINX11)rip.xpm rip.xpm data.; : data.base $(MAKEDEFS) $(RUN) $(MAKEDEFS) -d rumors.; : rumors.tru rumors.fal $(MAKEDEFS) $(RUN) $(MAKEDEFS) -r quest.dat; : quest.txt $(MAKEDEFS) $(RUN) $(MAKEDEFS) -q oracles.; : oracles.txt $(MAKEDEFS) $(RUN) $(MAKEDEFS) -h # note: 'options' should have already been made when include/date.h was created options.; : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -v spec_levs.timestamp; : $(SPECLEVS) $(LEVCOMP) $(RUN) $(LEVCOMP) $(SPECLEVS) $(TOUCH) spec_levs.timestamp; quest_levs.timestamp; : $(QUESTLEVS) $(LEVCOMP) $(RUN) $(LEVCOMP) $(QUESTLEVS) $(TOUCH) quest_levs.timestamp; $(DUNGEON) : dungeon.def $(MAKEDEFS) $(DGNCOMP) $(RUN) $(MAKEDEFS) -e !dungeon.def -> dungeon.pdf $(RUN) $(DGNCOMP) dungeon.pdf !dungeon.pdr -> dungeon clean : - if f$search("*.*;-1").nes."" then purge - if f$search("dungeon.pdf").nes."" then delete dungeon.pdf; - if f$search("*.timestamp").nes."" then delete $(MARKERS) spotless : clean - delete $(VARDAT) - if f$search("$(DUNGEON)").nes."" then delete $(DUNGEON) - if f$search("*.lev").nes."" then delete *.lev; - if f$search("$(X11TILES)").nes."" then delete $(X11TILES) - if f$search("*.x%m").nes."" then delete *.x%m; !*.xbm,*.xpm - if f$search("nh*.dlb").nes."" then delete nh*.dlb; - if f$search("nhdat.lst").nes."" then delete nhdat.lst; nethack-3.4.3/sys/vms/Makefile.doc0100644000000000000000000000431207764735041015501 0ustar rootroot# NetHack Makefile (VMS) - for the [Unix] documentation. # SCCS Id: @(#)Makefile.doc 3.4 1993/01/06 # Copy this file to [.doc]Makefile. and edit it if needed. GUIDEBOOK = Guidebook. # regular ASCII file #GUIDEBOOK = Guidebook.ps # PostScript file #GUIDEBOOK = Guidebook.dvi # TeX device-independent file ALLDOCS = $(GUIDEBOOK) #ALLDOCS = $(GUIDEBOOK) manpages NOOP = ! Guidebook : $(GUIDEBOOK) $(NOOP) # the basic guidebook #Guidebook. : Guidebook.mn # #tbl tmac.n Guidebook.mn | nroff | col > Guidebook # write sys$output "Guidebook.mn cannot be processed under VMS." Guidebook. : Guidebook.txt # distributed version of plain text copy Guidebook.txt Guidebook. # Fancier output for those with ditroff, psdit and a PostScript printer. #Guidebook.ps : Guidebook.mn # #tbl tmac.n Guidebook.mn | ditroff | psdit > Guidebook.ps # write sys$output "Guidebook.mn cannot be processed under VMS." Guidebook.ps : Guidebook.dvi # generated with LaTeX dvi2ps Guidebook # Guidebook.tex is the same as Guidebook.mn but formatted with LaTeX. # - The invocation command for LaTeX may vary in different installations. # - To print Guidebook.dvi you need to use a suitable dvi-driver. Guidebook.dvi : Guidebook.tex latex Guidebook.tex all : $(ALLDOCS) $(NOOP) GAME = nethack MANDIR = HACKDIR: MANEXT = man #MANDIR = /usr/man/man6 #MANEXT = 6 # manual non-installation; raw man pages may be better than nothing GAMEMANCREATE = copy nethack.6 LEVMANCREATE = copy lev_comp.6 DGNMANCREATE = copy dgn_comp.6 RCVRMANCREATE = copy recover.6 # GAMEMANCREATE = nroff -man nethack.6 > # LEVMANCREATE = nroff -man lev_comp.6 > # DGNMANCREATE = nroff -man dgn_comp.6 > # RCVRMANCREATE = nroff -man recover.6 > manpages : - $(GAMEMANCREATE) $(MANDIR)$(GAME).$(MANEXT) - $(LEVMANCREATE) $(MANDIR)lev_comp.$(MANEXT) - $(DGNMANCREATE) $(MANDIR)dgn_comp.$(MANEXT) - $(RCVRMANCREATE) $(MANDIR)recover.$(MANEXT) spotless : - if f$search("Guidebook.") .nes."" then delete Guidebook.;* - if f$search("Guidebook.ps") .nes."" then delete Guidebook.ps;* - if f$search("Guidebook.dvi").nes."" then delete Guidebook.dvi;* - if f$search("Guidebook.aux").nes."" then delete Guidebook.aux;* - if f$search("Guidebook.log").nes."" then delete Guidebook.log;* nethack-3.4.3/sys/vms/Makefile.src0100644000000000000000000004407107764735041015531 0ustar rootroot# NetHack Makefile (VMS) - for building nethack itself. # SCCS Id: @(#)Makefile.src 3.4 2003/02/13 # Copy this file to [.src]Makefile. and then edit it as needed. # The default configuration is for building with DEC C (aka Compaq C). # If you changed CC or CFLAGS, make similar changes in [.util]Makefile. # # Note: modifying this Makefile will cause crtl.opt to be rebuilt, # which will trigger an update of makedefs, which will in turn # result in a full build of just about _everything_. MAKE = $(MMS) CD = set default ECHO = write sys$output NOOP = continue RUN = mcr TOUCH = append/New _NLA0: # only one file per $(TOUCH) # source tree, relative to 'src' and 'util' INC = [-.include] SYSSHR = [-.sys.share] SRC = [-.src] TTY = [-.win.tty] UTL = [-.util] VMS = [-.sys.vms] WINSHR = [-.win.share] X11 = [-.win.X11] MAKEFILE= $(SRC)Makefile. # if you are using gcc as your compiler: # uncomment the CC definition below if it's not in your environment # CC = gcc # set option flags for C compiler and linker # CFLAGS = /Prefix=All/Incl=$(INC)/noList # DECC in native mode #CFLAGS = /Include=$(INC)/noList # VAXC or GNUC #LFLAGS = /Debug/Map/Cross_Ref # for development #LFLAGS = /noTraceback/noMap # for installing w/ privs LFLAGS = /noMap LINK = link LIBS = # blank for DECC #LIBS = sys$share:vaxcrtl.exe/Shareable # VAX C or GNU C MORELIBS = # GCC needs an extra library #MORELIBS = gnu_cc:[000000]gcclib.olb/Library # Specific VMS object files SYSSRC = $(VMS)vmsmain.c,$(VMS)vmstty.c,$(VMS)vmsunix.c,\ $(VMS)vmsmisc.c,$(VMS)vmsfiles.c,$(VMS)vmsmail.c SYSOBJ = vmsmain.obj,vmstty.obj,vmsunix.obj,vmsfiles.obj,vmsmail.obj #,vmsmisc.obj LIBOPT = $(SRC)crtl.opt; # termcap library TERMCAPSRC = tclib.c TERMCAPOBJ = ,tclib.obj # Set WINSRC and WINOBJ lines corresponding to your desired combination # of windowing systems. Also set windowing systems in config.h. # # a straight tty port using no native windowing system WINTTYSRC = $(TTY)getline.c $(TTY)termcap.c $(TTY)topl.c $(TTY)wintty.c \ $(TERMCAPSRC) WINTTYOBJ = getline.obj,termcap.obj,topl.obj,wintty.obj $(TERMCAPOBJ) # # an X11 port (not supported under DECwindows) WINX11SRC = $(X11)Window.c $(X11)dialogs.c $(X11)winX.c $(X11)winmap.c \ $(X11)winmenu.c $(X11)winmesg.c $(X11)winmisc.c $(X11)winstat.c \ $(X11)wintext.c $(X11)winval.c $(SRC)tile.c WINX11OBJ = Window.obj,dialogs.obj,winX.obj,winmap.obj,winmenu.obj,\ winmesg.obj,winmisc.obj,winstat.obj,wintext.obj,winval.obj,tile.obj # # WINSRC = $(WINTTYSRC) WINOBJ = $(WINTTYOBJ) # make NetHack for VMS SYSTEM = SysVMS.timestamp; GAME = $(SRC)nethack.exe; # RANDOM is defined in vmsconf.h RANDSRC = random.c RANDOBJ = random.obj # ---------------------------------------- # # Nothing below this line should have to be changed. # # Other things that have to be reconfigured are in vmsconf.h, # and config.h VERSION = 3.4.3 MAKEDEFS = $(UTL)makedefs.exe; # timestamp files to reduce `make' overhead and shorten .obj dependency lists CONFIG_H = $(SRC)config.h-t HACK_H = $(SRC)hack.h-t # all .c that are part of the main NetHack program and are not operating- or # windowing-system specific HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \ do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \ dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \ files.c fountain.c hack.c hacklib.c invent.c light.c lock.c mail.c \ makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c mklev.c mkmap.c \ mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \ mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ priest.c quest.c questpgr.c read.c rect.c region.c restore.c rip.c rnd.c \ role.c rumors.c save.c shk.c shknam.c sit.c sounds.c sp_lev.c spell.c \ steal.c steed.c teleport.c timeout.c topten.c track.c trap.c u_init.c \ uhitm.c vault.c version.c vision.c weapon.c were.c wield.c \ windows.c wizard.c worm.c worn.c write.c zap.c # generated source files (tile.c is handled separately via WINxxxSRC) GENCSRC = monstr.c vis_tab.c #tile.c # .c files for this version (for date.h) VERSOURCES = $(HACKCSRC) $(SYSSRC) $(WINSRC) $(RANDSRC) $(GENCSRC) # all .h files except date.h, onames.h, pm.h, and vis_tab.h which would # cause dependency loops if run through "make depend" # and dgn_comp.h, dgn_file.h, lev_comp.h, special level & dungeon files. # HACKINCL = align.h amiconf.h artifact.h artilist.h attrib.h beconf.h color.h \ config.h config1.h coord.h decl.h def_os2.h display.h dlb.h \ dungeon.h edog.h emin.h engrave.h epri.h eshk.h extern.h flag.h \ func_tab.h global.h hack.h lev.h macconf.h mfndpos.h micro.h \ mkroom.h monattk.h mondata.h monflag.h monst.h monsym.h obj.h \ objclass.h os2conf.h patchlevel.h pcconf.h permonst.h prop.h rect.h \ region.h rm.h sp_lev.h spell.h system.h tcap.h timeout.h tosconf.h \ tradstdc.h trampoli.h trap.h unixconf.h vault.h vision.h vmsconf.h \ wintty.h winX.h winprocs.h wintype.h you.h youprop.h #HSOURCES = $(HACKINCL) date.h onames.h pm.h vis_tab.h\ # lev_comp.h dgn_comp.h dgn_file.h # the following .obj's should be made before any others (for makedefs) FIRSTOBJ = vmsmisc.obj,monst.obj,objects.obj # split up long list so that we can write pieces of it into nethack.opt HOBJ1 = allmain.obj,alloc.obj,apply.obj,artifact.obj,attrib.obj, \ ball.obj,bones.obj,botl.obj,cmd.obj,dbridge.obj,decl.obj, \ detect.obj,dig.obj,display.obj,dlb.obj,do.obj,do_name.obj,do_wear.obj HOBJ2 = dog.obj,dogmove.obj,dokick.obj,dothrow.obj,drawing.obj, \ dungeon.obj,eat.obj,end.obj,engrave.obj,exper.obj,explode.obj, \ extralev.obj,files.obj,fountain.obj,hack.obj,hacklib.obj,invent.obj HOBJ3 = light.obj,lock.obj,mail.obj,makemon.obj,mapglyph.obj,mcastu.obj, \ mhitm.obj,mhitu.obj,minion.obj,mklev.obj,mkmap.obj,mkmaze.obj, \ mkobj.obj,mkroom.obj,mon.obj,mondata.obj,monmove.obj,monstr.obj HOBJ4 = mplayer.obj,mthrowu.obj,muse.obj,music.obj,o_init.obj,objnam.obj, \ options.obj,pager.obj,pickup.obj,pline.obj,polyself.obj, \ potion.obj,pray.obj,priest.obj,quest.obj,questpgr.obj,read.obj HOBJ5 = rect.obj,region.obj,restore.obj,rip.obj,rnd.obj,role.obj, \ rumors.obj,save.obj,shk.obj,shknam.obj,sit.obj,sounds.obj,sp_lev.obj, \ spell.obj,steal.obj,steed.obj,teleport.obj,timeout.obj,topten.obj, \ track.obj,trap.obj HOBJ6 = u_init.obj,uhitm.obj,vault.obj,vision.obj,vis_tab.obj,weapon.obj, \ were.obj,wield.obj,windows.obj,wizard.obj,worm.obj,worn.obj, \ write.obj,zap.obj,version.obj HOBJ = $(FIRSTOBJ) $(SYSOBJ) $(WINOBJ) $(RANDOBJ) \ $(HOBJ1) $(HOBJ2) $(HOBJ3) $(HOBJ4) $(HOBJ5) $(HOBJ6) # simpler target name nethack : $(GAME) @ $(ECHO) "nethack is up to date." $(GAME) : $(SYSTEM) @ $(NOOP) $(SYSTEM) : $(LIBOPT) $(HOBJ) nethack.opt @ $(ECHO) "Linking ..." $(LINK)/Exe=$(GAME) $(LFLAGS) nethack.opt/Opt,$(LIBOPT)/Opt $(TOUCH) $(SYSTEM) all : $(GAME) @ $(ECHO) "nethack is up to date." # linker options file for nethack's object modules nethack.opt : $(MAKEFILE) # this file open/Write f nethack.opt write f "! nethack.opt" @ write f f$edit("$(SYSOBJ)","COLLAPSE") @ write f f$edit("$(WINOBJ)","COLLAPSE") @ write f f$edit("$(RANDOBJ)","COLLAPSE") @ write f f$edit("$(FIRSTOBJ)","COLLAPSE") @ write f f$edit("$(HOBJ1)","COLLAPSE") @ write f f$edit("$(HOBJ2)","COLLAPSE") @ write f f$edit("$(HOBJ3)","COLLAPSE") @ write f f$edit("$(HOBJ4)","COLLAPSE") @ write f f$edit("$(HOBJ5)","COLLAPSE") @ write f f$edit("$(HOBJ6)","COLLAPSE") @ write f "iosegment=128" write f "identification=$(VERSION)" close f # linker options file for run-time libraries, also used by $(UTL)Makefile $(LIBOPT) : $(MAKEFILE) # this file open/Write f $(LIBOPT) write f "! crtl.opt" write f "$(LIBS)" write f "$(MORELIBS)" close f # simplified target name, for interactive convenience crtl.opt : $(LIBOPT) @ $(NOOP) # dependencies for makedefs and its outputs, which the util # Makefile is responsible for keeping up to date # # special rules, to force update of makedefs, real dependencies should be # below in the 'make depend' output. monst.obj : $(CC) $(CFLAGS) monst.c @- if f$search("$(MAKEDEFS)").nes."" then delete $(MAKEDEFS) objects.obj : $(CC) $(CFLAGS) objects.c @- if f$search("$(MAKEDEFS)").nes."" then delete $(MAKEDEFS) $(MAKEDEFS) : $(FIRSTOBJ) $(UTL)makedefs.c \ $(CONFIG_H) $(INC)permonst.h $(INC)objclass.h \ $(INC)monsym.h $(INC)artilist.h $(INC)dungeon.h \ $(INC)obj.h $(INC)monst.h $(INC)you.h $(INC)flag.h \ $(INC)dlb.h $(INC)patchlevel.h $(INC)qtext.h $(LIBOPT) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(MAKEDEFS) @ $(CD) $(SRC) $(INC)onames.h : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(INC)onames.h @ $(CD) $(SRC) $(INC)pm.h : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(INC)pm.h @ $(CD) $(SRC) monstr.c : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(SRC)monstr.c @ $(CD) $(SRC) # both vis_tab.h and vis_tab.c are made at the same time by makedefs $(INC)vis_tab.h : vis_tab.c $(TOUCH) $(INC)vis_tab.h vis_tab.c : $(MAKEDEFS) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(SRC)vis_tab.c @ $(CD) $(SRC) $(SRC)tile.c : $(WINSHR)tilemap.c $(HACK_H) $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(SRC)tile.c @ $(CD) $(SRC) # date.h should be remade any time any of the source or include code # is modified. Unfortunately, this would make the contents of this # file far more complex. Since "hack.h" depends on most of the include # files, we kludge around this by making date.h dependent on hack.h, # even though it doesn't include this file. # # hack.h depends on makedefs' output, so we know makedefs will be # up to date before being executed; kill old date.h to force update $(INC)date.h : $(VERSOURCES) $(HACK_H) @- if f$search("$(INC)date.h").nes."" then delete $(INC)date.h;* $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) $(INC)date.h @ $(CD) $(SRC) # special targets clean : - if f$search("*.*;-1") .nes."" then purge - if f$search("$(INC)*.*;-1").nes."" then purge $(INC) /Exclude=*conf*.h - if f$search("*.obj") .nes."" then delete *.obj; - if f$search("*.h-t").nes."" then delete *.h-t; !$(HACK_H),$(CONFIG_H) - if f$search("*.opt").nes."" then delete *.opt; !nethack.opt,$(LIBOPT) spotless : clean - if f$search("$(LIBOPT)").nes."" then delete $(LIBOPT) - if f$search("$(SYSTEM)").nes."" then delete $(SYSTEM) - if f$search("$(GAME)") .nes."" then delete $(GAME) - delete monstr.c;,vis_tab.c;,$(INC)vis_tab.h;,\ $(INC)pm.h;,$(INC)onames.h;,$(INC)date.h; - if f$search("tile.c") .nes."" then delete tile.c; - if f$search("tclib.c") .nes."" then delete tclib.c; - if f$search("random.c") .nes."" then delete random.c; - if f$search("nethack.olb").nes."" then delete nethack.olb; # dependencies (mostly cloned from sys/unix/Makefile.src) # config.h timestamp $(CONFIG_H) : $(INC)config.h $(INC)config1.h $(INC)tradstdc.h $(INC)global.h \ $(INC)coord.h $(INC)vmsconf.h $(INC)system.h \ $(INC)unixconf.h $(INC)os2conf.h $(INC)micro.h \ $(INC)pcconf.h $(INC)tosconf.h $(INC)amiconf.h \ $(INC)macconf.h $(INC)beconf.h $(INC)wceconf.h \ $(INC)ntconf.h $(INC)nhlan.h $(TOUCH) $(CONFIG_H) # hack.h timestamp $(HACK_H) : $(INC)hack.h $(CONFIG_H) $(INC)align.h \ $(INC)dungeon.h $(INC)monsym.h $(INC)mkroom.h \ $(INC)objclass.h $(INC)youprop.h $(INC)prop.h \ $(INC)permonst.h $(INC)monattk.h \ $(INC)monflag.h $(INC)mondata.h $(INC)pm.h \ $(INC)wintype.h $(INC)decl.h $(INC)quest.h \ $(INC)spell.h $(INC)color.h $(INC)obj.h \ $(INC)you.h $(INC)attrib.h $(INC)monst.h $(INC)skills.h \ $(INC)onames.h $(INC)timeout.h $(INC)trap.h \ $(INC)flag.h $(INC)rm.h $(INC)vision.h \ $(INC)display.h $(INC)engrave.h $(INC)rect.h $(INC)region.h \ $(INC)winprocs.h $(INC)wintty.h $(INC)trampoli.h $(TOUCH) $(HACK_H) # VMS-specific code vmsmain.obj : $(VMS)vmsmain.c $(HACK_H) $(INC)dlb.h vmstty.obj : $(VMS)vmstty.c $(HACK_H) $(INC)wintty.h $(INC)tcap.h vmsunix.obj : $(VMS)vmsunix.c $(HACK_H) vmsmisc.obj : $(VMS)vmsmisc.c $(VMS)oldcrtl.c vmsfiles.obj : $(VMS)vmsfiles.c $(CONFIG_H) vmsmail.obj : $(VMS)vmsmail.c $(CONFIG_H) $(INC)mail.h \ $(INC)wintype.h $(INC)winprocs.h # conditionally used code -- VMS always wants these random.obj : random.c $(HACK_H) random.c : $(SYSSHR)random.c copy $(SYSSHR)random.c random.c tclib.obj : tclib.c $(CONFIG_H) tclib.c : $(SYSSHR)tclib.c copy $(SYSSHR)tclib.c tclib.c # user interface code -- VMS uses tty (1st 4) only getline.obj : $(TTY)getline.c $(HACK_H) $(INC)func_tab.h termcap.obj : $(TTY)termcap.c $(HACK_H) $(INC)tcap.h topl.obj : $(TTY)topl.c $(HACK_H) $(INC)tcap.h wintty.obj : $(TTY)wintty.c $(HACK_H) $(INC)dlb.h \ $(INC)patchlevel.h $(INC)tcap.h Window.obj : $(X11)Window.c $(INC)xwindowp.h $(INC)xwindow.h $(CONFIG_H) dialogs.obj : $(X11)dialogs.c $(CONFIG_H) winX.obj : $(X11)winX.c $(HACK_H) $(INC)winX.h $(INC)dlb.h \ $(INC)patchlevel.h $(X11)nh72icon $(X11)nh56icon $(X11)nh32icon winmap.obj : $(X11)winmap.c $(INC)xwindow.h $(HACK_H) $(INC)dlb.h \ $(INC)winX.h $(INC)tile2x11.h winmenu.obj : $(X11)winmenu.c $(HACK_H) $(INC)winX.h winmesg.obj : $(X11)winmesg.c $(INC)xwindow.h $(HACK_H) $(INC)winX.h winmisc.obj : $(X11)winmisc.c $(HACK_H) $(INC)func_tab.h $(INC)winX.h winstat.obj : $(X11)winstat.c $(HACK_H) $(INC)winX.h wintext.obj : $(X11)wintext.c $(HACK_H) $(INC)winX.h $(INC)xwindow.h winval.obj : $(X11)winval.c $(HACK_H) $(INC)winX.h tile.obj : $(SRC)tile.c $(HACK_H) monstr.obj : monstr.c $(CONFIG_H) vis_tab.obj : vis_tab.c $(CONFIG_H) $(INC)vis_tab.h # general code allmain.obj : allmain.c $(HACK_H) alloc.obj : alloc.c $(CONFIG_H) apply.obj : apply.c $(HACK_H) $(INC)edog.h artifact.obj : artifact.c $(HACK_H) $(INC)artifact.h $(INC)artilist.h attrib.obj : attrib.c $(HACK_H) ball.obj : ball.c $(HACK_H) bones.obj : bones.c $(HACK_H) $(INC)lev.h botl.obj : botl.c $(HACK_H) cmd.obj : cmd.c $(HACK_H) $(INC)func_tab.h dbridge.obj : dbridge.c $(HACK_H) decl.obj : decl.c $(HACK_H) detect.obj : detect.c $(HACK_H) $(INC)artifact.h dig.obj : dig.c $(HACK_H) $(INC)edog.h display.obj : display.c $(HACK_H) dlb.obj : dlb.c $(CONFIG_H) $(INC)dlb.h do.obj : do.c $(HACK_H) $(INC)lev.h do_name.obj : do_name.c $(HACK_H) do_wear.obj : do_wear.c $(HACK_H) dog.obj : dog.c $(HACK_H) $(INC)edog.h dogmove.obj : dogmove.c $(HACK_H) $(INC)mfndpos.h $(INC)edog.h dokick.obj : dokick.c $(HACK_H) $(INC)eshk.h dothrow.obj : dothrow.c $(HACK_H) $(INC)edog.h drawing.obj : drawing.c $(HACK_H) $(INC)tcap.h dungeon.obj : dungeon.c $(HACK_H) $(INC)dgn_file.h $(INC)dlb.h eat.obj : eat.c $(HACK_H) end.obj : end.c $(HACK_H) $(INC)eshk.h $(INC)dlb.h engrave.obj : engrave.c $(HACK_H) $(INC)lev.h exper.obj : exper.c $(HACK_H) explode.obj : explode.c $(HACK_H) extralev.obj : extralev.c $(HACK_H) files.obj : files.c $(HACK_H) $(INC)dlb.h fountain.obj : fountain.c $(HACK_H) hack.obj : hack.c $(HACK_H) hacklib.obj : hacklib.c $(HACK_H) invent.obj : invent.c $(HACK_H) light.obj : light.c $(HACK_H) $(INC)lev.h lock.obj : lock.c $(HACK_H) mail.obj : mail.c $(HACK_H) $(INC)mail.h makemon.obj : makemon.c $(HACK_H) $(INC)epri.h $(INC)emin.h $(INC)edog.h mapglyph.obj : mapglyph.c $(HACK_H) mcastu.obj : mcastu.c $(HACK_H) mhitm.obj : mhitm.c $(HACK_H) $(INC)artifact.h $(INC)edog.h mhitu.obj : mhitu.c $(HACK_H) $(INC)artifact.h $(INC)edog.h minion.obj : minion.c $(HACK_H) $(INC)emin.h $(INC)epri.h mklev.obj : mklev.c $(HACK_H) mkmap.obj : mkmap.c $(HACK_H) $(INC)sp_lev.h mkmaze.obj : mkmaze.c $(HACK_H) $(INC)sp_lev.h $(INC)lev.h mkobj.obj : mkobj.c $(HACK_H) mkroom.obj : mkroom.c $(HACK_H) mon.obj : mon.c $(HACK_H) $(INC)mfndpos.h $(INC)edog.h mondata.obj : mondata.c $(HACK_H) $(INC)eshk.h $(INC)epri.h monmove.obj : monmove.c $(HACK_H) $(INC)mfndpos.h $(INC)artifact.h \ $(INC)epri.h monst.obj : monst.c $(CONFIG_H) $(INC)permonst.h $(INC)align.h \ $(INC)monattk.h $(INC)monflag.h $(INC)monsym.h \ $(INC)dungeon.h $(INC)eshk.h $(INC)vault.h \ $(INC)epri.h $(INC)color.h mplayer.obj : mplayer.c $(HACK_H) mthrowu.obj : mthrowu.c $(HACK_H) muse.obj : muse.c $(HACK_H) $(INC)edog.h music.obj : music.c $(HACK_H) #interp.c o_init.obj : o_init.c $(HACK_H) $(INC)lev.h objects.obj : objects.c $(CONFIG_H) $(INC)obj.h $(INC)objclass.h \ $(INC)prop.h $(INC)skills.h $(INC)color.h objnam.obj : objnam.c $(HACK_H) options.obj : options.c $(CONFIG_H) $(INC)objclass.h $(INC)flag.h \ $(HACK_H) $(INC)tcap.h pager.obj : pager.c $(HACK_H) $(INC)dlb.h pickup.obj : pickup.c $(HACK_H) pline.obj : pline.c $(HACK_H) $(INC)epri.h $(INC)edog.h polyself.obj : polyself.c $(HACK_H) potion.obj : potion.c $(HACK_H) pray.obj : pray.c $(HACK_H) $(INC)epri.h priest.obj : priest.c $(HACK_H) $(INC)mfndpos.h $(INC)eshk.h \ $(INC)epri.h $(INC)emin.h quest.obj : quest.c $(HACK_H) $(INC)qtext.h questpgr.obj : questpgr.c $(HACK_H) $(INC)dlb.h $(INC)qtext.h read.obj : read.c $(HACK_H) rect.obj : rect.c $(HACK_H) region.obj : region.c $(HACK_H) $(INC)lev.h restore.obj : restore.c $(HACK_H) $(INC)lev.h $(INC)tcap.h rip.obj : rip.c $(HACK_H) rnd.obj : rnd.c $(HACK_H) role.obj : role.c $(HACK_H) rumors.obj : rumors.c $(HACK_H) $(INC)lev.h $(INC)dlb.h save.obj : save.c $(HACK_H) $(INC)lev.h shk.obj : shk.c $(HACK_H) $(INC)eshk.h shknam.obj : shknam.c $(HACK_H) $(INC)eshk.h sit.obj : sit.c $(HACK_H) $(INC)artifact.h sounds.obj : sounds.c $(HACK_H) $(INC)edog.h sp_lev.obj : sp_lev.c $(HACK_H) $(INC)dlb.h $(INC)sp_lev.h spell.obj : spell.c $(HACK_H) steal.obj : steal.c $(HACK_H) steed.obj : steed.c $(HACK_H) teleport.obj : teleport.c $(HACK_H) timeout.obj : timeout.c $(HACK_H) $(INC)lev.h topten.obj : topten.c $(HACK_H) $(INC)dlb.h $(INC)patchlevel.h track.obj : track.c $(HACK_H) trap.obj : trap.c $(HACK_H) u_init.obj : u_init.c $(HACK_H) uhitm.obj : uhitm.c $(HACK_H) vault.obj : vault.c $(HACK_H) $(INC)vault.h version.obj : version.c $(HACK_H) $(INC)date.h $(INC)patchlevel.h vision.obj : vision.c $(HACK_H) $(INC)vis_tab.h weapon.obj : weapon.c $(HACK_H) were.obj : were.c $(HACK_H) wield.obj : wield.c $(HACK_H) windows.obj : windows.c $(HACK_H) $(INC)wingem.h $(INC)winGnome.h wizard.obj : wizard.c $(HACK_H) $(INC)qtext.h $(INC)epri.h worm.obj : worm.c $(HACK_H) $(INC)lev.h worn.obj : worn.c $(HACK_H) write.obj : write.c $(HACK_H) zap.obj : zap.c $(HACK_H) # eof nethack-3.4.3/sys/vms/Makefile.top0100644000000000000000000001066507764735041015546 0ustar rootroot# NetHack Makefile (VMS) - top level for making & installing everything. # SCCS Id: @(#)Makefile.top 3.4 2003/05/19 # Copy this file to Makefile.; edit the appropriate values for # GAMEDIR ("playground" location) and GAMEOWNER (UIC or identifier # for the owner of playground files). # usage: mms all,install # or mms no_tools,all,install # or substitute freeware `MMK' for Digital's `MMS'. MAKE = $(MMS) CD = set default ECHO = write sys$output EXEC = @ NOOP = continue # don't do anything interesting TOUCH = set file/truncate # multiple files per $(TOUCH), but no creation # support directories, relative to 'top' DAT = [.dat] DOC = [.doc] SRC = [.src] TOP = [-] # relative to the others UTL = [.util] VMS = [.sys.vms] GAMEDIR = # defaults to [.play] GAMEOWNER = # defaults to installer's UIC # these are the distributed values in [.include]vmsconf.h #GAMEDIR = DISK$USERS:[GAMES.NETHACK.3-4-2.PLAY] #GAMEOWNER = NHWIZARD # just about everything, except installation all : program utilities data dlb_data documentation @ $(ECHO) "all code and data is now up to date." program : $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) all @ $(CD) $(TOP) utilities : $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) all @ $(CD) $(TOP) data : $(CD) $(DAT) $(MAKE)$(MAKEFLAGS) all @ $(CD) $(TOP) documentation : $(CD) $(DOC) $(MAKE)$(MAKEFLAGS) all @ $(CD) $(TOP) install : program all_data make_directories create_writeable_files update @ $(ECHO) "installation is now complete." # assume there're no active games in progress update : place_readonly_files place_executable place_vms_support @ open/Write f tmp-update.com; @ write f "$ set noon" @ write f "$ if p1.eqs."""" then p1 = f$trnlnm(""HACKDIR"")" @ write f "$ if p1.eqs."""" then p1 = ""[.play]""" @ write f "$ old_default = f$environ(""DEFAULT"")" @ write f "$ set default 'p1'" @ write f\ "$ if f$search(""*.*;-2"").nes."""" then set file/prot=(s:rwed,o:rwed) *.*;-2" @ write f\ "$ if f$search(""*.*;-1"").nes."""" then set file/prot=(s:rwed,o:rwed) *.*;-1" @ write f "$ if f$search(""*.*;-1"").nes."""" then purge" @ write f "$! if f$search(""bones*.*"").nes."""" then $(TOUCH) bones*.*" @ write f "$! if f$search(""[.save]*"").nes."""" then $(TOUCH) [.save]*" @ write f "$ set default 'old_default'" @ write f "$ exit" @ close f - $(EXEC)tmp-update.com; $(GAMEDIR) !purge old version @ delete tmp-update.com; @ $(ECHO) "playground files updated." Guidebook : $(CD) $(DOC) $(MAKE)$(MAKEFLAGS) Guidebook @ $(CD) $(TOP) manpages : $(CD) $(DOC) $(MAKE)$(MAKEFLAGS) manpages @ $(CD) $(TOP) all_data : data dlb_data @ $(NOOP) dlb_data : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" dlb make_directories : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" directories create_writeable_files : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" writeable_files place_readonly_files : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" readonly_files place_executable : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" executable place_vms_support : $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" termcap $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" procedure $(EXEC)$(VMS)install.com "$(GAMEDIR)" "$(GAMEOWNER)" documentation # 'make no_tools' should be done first if you don't have the appropriate # tools to process the parser and scanner for the special level and # dungeon compilers; doing so will copy distributed, pre-processed files # from [.sys.share] to [.util]. If you _do_ have the tools, be sure to # edit [.util]Makefile so that it uses the right ones. no_tools : $(CD) $(UTL) $(MAKE)$(MAKEFLAGS) no_yacc $(MAKE)$(MAKEFLAGS) no_lex @ $(CD) $(TOP) # 'make clean' removes all the .obj files, but leaves around all the executables # and compiled data files. clean : $(CD) $(SRC) - $(MAKE)$(MAKEFLAGS) clean @ $(CD) $(TOP) $(CD) $(UTL) - $(MAKE)$(MAKEFLAGS) clean @ $(CD) $(TOP) # 'make spotless' returns the source tree to near-distribution condition. # it removes .obj files, executables, and compiled data files. spotless : $(CD) $(SRC) - $(MAKE)$(MAKEFLAGS) spotless @ $(CD) $(TOP) $(CD) $(UTL) - $(MAKE)$(MAKEFLAGS) spotless @ $(CD) $(TOP) $(CD) $(DAT) - $(MAKE)$(MAKEFLAGS) spotless @ $(CD) $(TOP) $(CD) $(DOC) - $(MAKE)$(MAKEFLAGS) spotless @ $(CD) $(TOP) nethack-3.4.3/sys/vms/Makefile.utl0100644000000000000000000002776607764735041015562 0ustar rootroot# NetHack Makefile (VMS) - for utility programs. # SCCS Id: @(#)Makefile.utl 3.4 2002/03/02 # Copy this file to [.util]Makefile. and then edit it as needed. # The default configuration is for building with DEC C (aka Compaq C). # Settings for CC and CFLAGS ought to match the ones used in [.src]Makefile. MAKE = $(MMS) CD = set default ECHO = write sys$output MOVE = rename/New # within same device only MUNG = search/Exact/Match=NOR # to strip bogus #module directives NOOP = continue RM = delete/noConfirm RUN = mcr # simplest way to pass command line args TOUCH = append/New _NLA0: # only one file per $(TOUCH) # source tree, relative to 'src' and 'util' DAT = [-.dat] INC = [-.include] SYSSHR = [-.sys.share] SRC = [-.src] UTL = [-.util] VMS = [-.sys.vms] WINSHR = [-.win.share] WINX11 = [-.win.X11] # targets, with enough punctuation to keep MCR and DELETE happy MAKEDEFS= $(UTL)makedefs.exe; LEVCOMP = $(UTL)lev_comp.exe; DGNCOMP = $(UTL)dgn_comp.exe; DLB = $(UTL)dlb.exe; RECOVER = $(UTL)recover.exe; # used by $(DAT)Makefile for synchronization MARKER = $(UTL)util.timestamp; # if you are using gcc as your compiler, # uncomment the CC definition below if it's not in your environment # CC = gcc CFLAGS = /Prefix=All/Incl=$(INC)/noList # DECC in native mode #CFLAGS = /Include=$(INC)/noList # VAXC or GNUC LFLAGS = /noMap LIBS = $(SRC)crtl.opt/Options # run-time library(s) needed LINK = link # If you don't have yacc, byacc, or bison or just don't want to run any of # them, then make target "no_yacc" before trying to build lev_comp # or dgn_comp. You won't be able to modify *_comp.y though. # If you don't have lex or flex, then make target "no_lex" and leave # *_comp.l alone. $(VMS)lev_lex.h will be used to work-around some # suspect code included in the distributed copies of *_lex.c. # If you do either of the above, the corresponding value of YACC and/or LEX # below won't matter. # # Note: VMS POSIX V1.1 lex and yacc generate code which contains an # invalid #module directive; it order to prevent warnings for CC or # choking by GCC, the SEARCH command is used in an attempt to strip # then out. Otherwise MMS would quit when making the affected targets. # Each "munged" copy should be identical to its original if no #module # directives are present. # # yacc/lex programs to use to generate *_comp.c, *_comp.h, and *_lex.c. # choose xxxOUT that matches xxx tool's output YACC = bison /Define LEX = flex #YACC = yacc -d #LEX = lex #YACC = posix/Run posix$bin:yacc. "-d #LEX = posix/Run posix$bin:lex. " # blank means foo.y -> foo_tab.c & foo_tab.h YACCOUT = # bison #YACCOUT = ytab # VMS POSIX #YACCOUT = y_tab # DEC/Shell LEXOUT = lexyy # flex #LEXOUT = lex_yy # VMS POSIX # Nothing below this line should have to be changed. # linker options file LIBOPT = $(SRC)crtl.opt; # timestamps for primary header files, matching src/Makefile CONFIG_H = $(SRC)config.h-t HACK_H = $(SRC)hack.h-t # utility .c files MAKESRC = makedefs.c SPLEVSRC = lev_yacc.c lev_lex.c lev_main.c DGNCOMPSRC = dgn_yacc.c dgn_lex.c dgn_main.c RECOVSRC = recover.c DLBSRC = dlb_main.c UTILSRCS = $(MAKESRC) $(SPLEVSRC) $(DGNCOMPSRC) $(RECOVSRC) $(DLBSRC) panic.c # object files that provide access to NetHack's names NAMEOBJ1 = $(SRC)monst.obj,$(SRC)objects.obj NAMEOBJ2 = $(SRC)drawing.obj,$(SRC)decl.obj NAMEOBJS = $(NAMEOBJ1),$(NAMEOBJ2) # object files for makedefs MAKEOBJS = makedefs.obj,$(NAMEOBJ1) VMSMAKEOBJS = $(SRC)vmsmisc.obj # object files for special levels compiler SPLEVOBJS = lev_main.obj,lev_yacc.obj,lev_lex.obj,panic.obj,\ $(SRC)alloc.obj,$(NAMEOBJS) VMSSPLEVOBJS = $(SRC)vmsmisc.obj,$(SRC)vmsfiles.obj # object files for dungeon compiler DGNCOMPOBJS = dgn_main.obj,dgn_yacc.obj,dgn_lex.obj,panic.obj,$(SRC)alloc.obj VMSDGNCOBJS = $(SRC)vmsmisc.obj # object files for recovery utility RECOVOBJS = recover.obj VMSRECOBJS = $(SRC)vmsmisc.obj,$(SRC)vmsfiles.obj # object files for dlb utility DLBOBJS = dlb_main.obj,panic.obj,$(SRC)alloc.obj,$(SRC)dlb.obj VMSDLBOBJS = $(SRC)vmsmisc.obj,$(SRC)vmsfiles.obj # fake target default : @ $(ECHO) "Oops! No target(s) specified...." all : $(MAKEDEFS) $(LEVCOMP) $(DGNCOMP) $(RECOVER) $(DLB) @ $(ECHO) "util is up to date." # special targets for folks without yacc/bison and or lex/flex no_yacc : copy $(SYSSHR)%%%_yacc.c $(UTL) copy $(SYSSHR)%%%_comp.h $(INC) @ $(ECHO) "distributed yacc output (*_yacc.c) copied into place" no_lex : copy $(SYSSHR)%%%_lex.c $(UTL) copy $(VMS)lev_lex.h $(UTL) @ $(ECHO) "distributed lex output (*_lex.c) copied into place" # alternate target names for possible interactive use makedefs : $(MAKEDEFS) @ $(ECHO) "makedefs is up to date." lev_comp : $(LEVCOMP) @ $(ECHO) "lev_comp is up to date." dgn_comp : $(DGNCOMP) @ $(ECHO) "dgn_comp is up to date." recover : $(RECOVER) @ $(ECHO) "recover is up to date." dlb : $(DLB) @ $(ECHO) "recover is up to date." $(LIBOPT) : $(SRC)Makefile.; # linker options file $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) $(LIBOPT) @ $(CD) $(UTL) # dependencies for makedefs # $(MAKEDEFS) : $(MAKEOBJS) $(VMSMAKEOBJS) $(LIBOPT) $(LINK) $(LFLAGS) $(MAKEOBJS),$(VMSMAKEOBJS),$(LIBS) @ $(TOUCH) $(MARKER) makedefs.obj : makedefs.c \ $(CONFIG_H) $(INC)permonst.h $(INC)objclass.h \ $(INC)monsym.h $(INC)artilist.h $(INC)dungeon.h \ $(INC)obj.h $(INC)monst.h $(INC)you.h $(INC)flag.h \ $(INC)dlb.h $(INC)patchlevel.h $(INC)qtext.h $(INC)onames.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -o $(INC)pm.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -p $(SRC)monstr.c : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -m # both vis_tab.h and vis_tab.c are made at the same time by makedefs -z $(INC)vis_tab.h : $(SRC)vis_tab.c $(TOUCH) $(INC)vis_tab.h $(SRC)vis_tab.c : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -z # the src Makefile is responsible for knowing when to call this, since # it knows all about the main src and include files $(INC)date.h : $(MAKEDEFS) $(RUN) $(MAKEDEFS) -v # dependencies for lev_comp # $(LEVCOMP) : $(SPLEVOBJS) $(VMSSPLEVOBJS) # $(LIBOPT) $(LINK)/Exe=$(LEVCOMP) $(LFLAGS) $(SPLEVOBJS),$(VMSSPLEVOBJS),$(LIBS) lev_yacc.obj : $(HACK_H) $(INC)sp_lev.h lev_yacc.c $(CC) $(CFLAGS) lev_yacc.c lev_lex.obj : $(HACK_H) $(INC)lev_comp.h $(INC)sp_lev.h lev_lex.c @ if f$search("lev_lex.h").nes."" then $(MOVE) lev_lex.h stdio.h $(CC) $(CFLAGS) lev_lex.c @ if f$search("stdio.h").nes."" then $(MOVE) stdio.h lev_lex.h lev_main.obj : $(HACK_H) $(INC)sp_lev.h $(INC)tcap.h $(INC)date.h lev_main.c $(CC) $(CFLAGS) lev_main.c panic.obj : $(CONFIG_H) $(CC) $(CFLAGS) panic.c $(INC)lev_comp.h : lev_yacc.c $(TOUCH) $(INC)lev_comp.h lev_yacc.c : lev_comp.y $(YACC) lev_comp.y $(MUNG) 'f$parse("$(YACCOUT)","lev_comp_tab.c")' "#module" /Outp=lev_yacc.c @ if f$search("''f$parse("$(YACCOUT)","lev_comp_tab.c")'").nes."" then \ $(RM) 'f$parse("$(YACCOUT)","lev_comp_tab.c")' $(MOVE) 'f$parse("$(YACCOUT)","lev_comp_tab.h")' $(INC)lev_comp.h lev_lex.c : lev_comp.l $(LEX) lev_comp.l $(MUNG) 'f$parse("$(LEXOUT)","lev_comp_lex.c")' "#module" /Outp=lev_lex.c @ if f$search("''f$parse("$(LEXOUT)","lev_comp_lex.c")'").nes."" then \ $(RM) 'f$parse("$(LEXOUT)","lev_comp_lex.c")' # dependencies for dgn_comp # $(DGNCOMP) : $(DGNCOMPOBJS) $(VMSDGNCOBJS) # $(LIBOPT) $(LINK)/Exe=$(DGNCOMP) $(LFLAGS) $(DGNCOMPOBJS),$(VMSDGNCOBJS),$(LIBS) dgn_yacc.obj : $(CONFIG_H) $(INC)dgn_file.h $(INC)date.h dgn_yacc.c $(CC) $(CFLAGS) dgn_yacc.c dgn_lex.obj : $(CONFIG_H) $(INC)dgn_comp.h $(INC)dgn_file.h dgn_lex.c @ if f$search("lev_lex.h").nes."" then $(MOVE) lev_lex.h stdio.h $(CC) $(CFLAGS) dgn_lex.c @ if f$search("stdio.h").nes."" then $(MOVE) stdio.h lev_lex.h dgn_main.obj : $(CONFIG_H) dgn_main.c $(CC) $(CFLAGS) dgn_main.c $(INC)dgn_comp.h : dgn_yacc.c $(TOUCH) $(INC)dgn_comp.h dgn_yacc.c : dgn_comp.y $(YACC) dgn_comp.y $(MUNG) 'f$parse("$(YACCOUT)","dgn_comp_tab.c")' "#module" /Outp=dgn_yacc.c @ if f$search("''f$parse("$(YACCOUT)","dgn_comp_tab.c")'").nes."" then \ $(RM) 'f$parse("$(YACCOUT)","dgn_comp_tab.c")' $(MOVE) 'f$parse("$(YACCOUT)","dgn_comp_tab.h")' $(INC)dgn_comp.h dgn_lex.c : dgn_comp.l $(LEX) dgn_comp.l $(MUNG) 'f$parse("$(LEXOUT)","dgn_comp_lex.c")' "#module" /Outp=dgn_lex.c @ if f$search("''f$parse("$(LEXOUT)","dgn_comp_lex.c")'").nes."" then \ $(RM) 'f$parse("$(LEXOUT)","dgn_comp_lex.c")' # dependencies for recover # $(RECOVER) : $(RECOVOBJS) $(VMSRECOBJS) # $(LIBOPT) $(LINK) $(LFLAGS) $(RECOVOBJS),$(VMSRECOBJS),$(LIBS) recover.obj : $(CONFIG_H) recover.c # dependencies for dlb # $(DLB) : $(DLBOBJS) $(VMSDLBOBJS) # $(LIBOPT) $(LINK)/Exe=$(DLB) $(LFLAGS) $(DLBOBJS),$(VMSDLBOBJS),$(LIBS) dlb_main.obj : $(CONFIG_H) $(INC)dlb.h dlb_main.c # dependencies and build rules for tile utilities # TILEMAP = $(UTL)tilemap.exe; GIF2TXT = $(UTL)gif2txt.exe; TXT2PPM = $(UTL)txt2ppm.exe; TILE2X11 = $(UTL)tile2x11.exe; TILEUTILS = $(TILEMAP),$(GIF2TXT),$(TXT2PPM),$(TILE2X11) TEXTIO = $(UTL)tiletxt.obj,tiletext.obj,$(NAMEOBJS),$(SRC)vmsmisc.obj GIFREADERS = gifread.obj,panic.obj,$(SRC)alloc.obj PPMWRITERS = ppmwrite.obj,panic.obj,$(SRC)alloc.obj tileutils : $(TILEUTILS) @ $(NOOP) $(GIF2TXT) : $(GIFREADERS) $(TEXTIO) $(LINK)/Exe=$(GIF2TXT) $(LFLAGS) $(GIFREADERS),$(TEXTIO),$(LIBS) $(TXT2PPM) : $(PPMWRITERS) $(TEXTIO) $(LINK)/Exe=$(TXT2PPM) $(LFLAGS) $(PPMWRITERS),$(TEXTIO),$(LIBS) $(TILE2X11) : tile2x11.obj $(TEXTIO) $(LINK) $(LFLAGS) tile2x11.obj,$(TEXTIO),$(LIBS) $(TILEMAP) : tilemap.obj $(SRC)vmsmisc.obj $(LINK) $(LFLAGS) tilemap.obj,$(SRC)vmsmisc.obj,$(LIBS) $(SRC)tile.c : $(TILEMAP) $(RUN) $(TILEMAP) $(INC)tile.h : $(WINSHR)tile.h copy $(WINSHR)tile.h $(INC)tile.h # Force an explicit directory prefix on tiletxt.obj so that we don't get # unwanted "sticky defaults" when $(TEXTIO) is used in a comma-separated # list on the link command line. # $(UTL)tiletxt.obj : $(HACK_H) $(WINSHR)tilemap.c $(CC) $(CFLAGS) /Def=("TILETEXT")/Obj=$@ $(WINSHR)tilemap.c tilemap.obj : $(HACK_H) $(WINSHR)tilemap.c tiletext.obj : $(CONFIG_H) $(INC)tile.h $(WINSHR)tiletext.c gifread.obj : $(CONFIG_H) $(INC)tile.h $(WINSHR)gifread.c ppmwrite.obj : $(CONFIG_H) $(INC)tile.h $(WINSHR)ppmwrite.c tile2x11.obj : $(HACK_H) $(INC)tile.h $(INC)tile2x11.h $(WINX11)tile2x11.c # make sure object files from src are available when needed # $(SRC)alloc.obj : $(SRC)alloc.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) alloc.obj @ $(CD) $(UTL) $(SRC)monst.obj : $(SRC)monst.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) monst.obj @ $(CD) $(UTL) $(SRC)objects.obj : $(SRC)objects.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) objects.obj @ $(CD) $(UTL) $(SRC)decl.obj : $(SRC)decl.c $(HACK_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) decl.obj @ $(CD) $(UTL) $(SRC)drawing.obj : $(SRC)drawing.c $(HACK_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) drawing.obj @ $(CD) $(UTL) $(SRC)dlb.obj : $(SRC)dlb.c $(HACK_H) $(INC)dlb.h $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) dlb.obj @ $(CD) $(UTL) # make sure hack.h dependencies get transitive information $(HACK_H) : $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) $(HACK_H) @ $(CD) $(UTL) $(CONFIG_H) : $(INC)config.h $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) $(CONFIG_H) @ $(CD) $(UTL) # VMS specific dependencies $(SRC)vmsmisc.obj : $(VMS)vmsmisc.c $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) vmsmisc.obj @ $(CD) $(UTL) $(SRC)vmsfiles.obj : $(VMS)vmsfiles.c $(CONFIG_H) $(CD) $(SRC) $(MAKE)$(MAKEFLAGS) vmsfiles.obj @ $(CD) $(UTL) clean : - if f$search("*.*;-1").nes."" then purge - if f$search("*.obj") .nes."" then $(RM) *.obj; spotless : clean - if f$search("%%%_lex.c") .nes."" then $(RM) %%%_lex.c; - if f$search("%%%_yacc.c").nes."" then $(RM) %%%_yacc.c; - if f$search("$(INC)%%%_comp.h").nes."" then $(RM) $(INC)%%%_comp.h;* - if f$search("$(INC)tile.h").nes."" then $(RM) $(INC)tile.h;* - if f$search("lev_lex.h") .nes."" then $(RM) lev_lex.h; - if f$search("*tab.c") .nes."" then $(RM) *tab.c; - if f$search("*.exe").nes."" then \ $(RM) $(MAKEDEFS),$(LEVCOMP),$(DGNCOMP),$(RECOVER),$(DLB) - if f$search("*.exe").nes."" then $(RM) $(TILEUTILS) - if f$search("$(MARKER)").nes."" then $(RM) $(MARKER) nethack-3.4.3/sys/vms/install.com0100644000000000000000000002271407764735041015451 0ustar rootroot$ ! vms/install.com -- set up nethack 'playground' $ ! $ ! Use vmsbuild.com to create nethack.exe, makedefs, and lev_comp *first*. $ ! $ ! Edit this file to define gamedir & gameuic, or else invoke it with two $ ! command line parameters, as in: $ ! @[.sys.vms]install "disk$users:[games.nethack]" "games" $ ! or @[.sys.vms]install "[-.play]" "[40,1]" $ ! $ ! default location is old playground, default owner is installer $ gamedir = f$trnlnm("NETHACKDIR") !location of playground $ if gamedir.eqs."" then gamedir = f$trnlnm("HACKDIR") $ gameuic = f$user() !owner of playground $ ! --- nothing below this line should need to be changed --- $ if p1.nes."" then gamedir := 'p1' $ if p2.nes."" then gameuic := 'p2' $ $ ! note: all filespecs contain some punctuation, $ ! to avoid inadvertent logical name interaction $ play_files = "PERM.,RECORD.,LOGFILE.,PANICLOG." $ help_files = "HELP.,HH.,CMDHELP.,WIZHELP.,OPTHELP.,HISTORY.,LICENSE." $ data_files = "DATA.,RUMORS.,ORACLES.,OPTIONS.,QUEST.DAT" $ guidebook = "[.doc]Guidebook.txt" $ invoc_proc = "[.sys.vms]nethack.com" $ trmcp_file = "[.sys.share]termcap" $ spec_files = "AIR.LEV,ASMODEUS.LEV,ASTRAL.LEV,BAALZ.LEV,BIGRM-%.LEV," - + "CASTLE.LEV,EARTH.LEV,FAKEWIZ%.LEV,FIRE.LEV," - + "JUIBLEX.LEV,KNOX.LEV,MEDUSA-%.LEV,MINEFILL.LEV," - + "MINETN-%.LEV,MINEND-%.LEV,ORACLE.LEV,ORCUS.LEV," - + "SANCTUM.LEV,SOKO%-%.LEV,TOWER%.LEV,VALLEY.LEV," - + "WATER.LEV,WIZARD%.LEV" $ spec_input = "bigroom.des castle.des endgame.des " - + "gehennom.des knox.des medusa.des mines.des " - + "oracle.des sokoban.des tower.des yendor.des" $ qstl_files = "%%%-GOAL.LEV,%%%-FIL%.LEV,%%%-LOCA.LEV,%%%-STRT.LEV" $ qstl_input = "Arch.des Barb.des Caveman.des Healer.des " - + "Knight.des Monk.des Priest.des Ranger.des Rogue.des " - + "Samurai.des Tourist.des Wizard.des Valkyrie.des" $ dngn_files = "DUNGEON." $ dngn_input = "dungeon.pdf" $ dlb_files = help_files + "," + data_files + "," - + spec_files + "," + qstl_files + "," + dngn_files $ data_libry = "nh-data.dlb" $ xtrn_files = "LICENSE.,HISTORY.,OPTIONS." $ makedefs := $sys$disk:[-.util]makedefs $ lev_comp := $sys$disk:[-.util]lev_comp $ dgn_comp := $sys$disk:[-.util]dgn_comp $ dlb := $sys$disk:[-.util]dlb $ milestone = "write sys$output f$fao("" !5%T "",0)," $ if p3.nes."" .and. f$edit(p4,"UPCASE").nes."VERBOSE" then milestone = "!" $ echo = "write sys$output" $ warn = echo !could be "write sys$error" $! $! make sure we've got a playground location $ gamedir := 'gamedir' $ if gamedir.eqs."" then gamedir = "[.play]" !last ditch default $ gamedir = f$parse(gamedir,,,,"SYNTAX_ONLY") - ".;" $ if gamedir.eqs."" then write sys$error "% must specify playground directory" $ if gamedir.eqs."" then exit %x1000002C !ss$_abort $ $! $! ['p3' is used in Makefile.top] $ if p3.nes."" then goto make_'p3' $ $ milestone "" $! $make_data_plus_dlb: $make_data: $ ! start from a known location -- [.sys.vms] $ set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")' $! generate miscellaneous data files $ set default [-.-.dat] !move to data directory $ milestone "(data)" $ makedefs -d !data.base -> data $ milestone "(rumors)" $ makedefs -r !rumors.tru + rumors.fal -> rumors $ milestone "(oracles)" $ makedefs -h !oracles.txt -> oracles $ milestone "(dungeon preprocess)" $ makedefs -e !dungeon.def -> dungeon.pdf $ milestone "(quest text)" $ makedefs -q !quest.txt -> quest.dat $ milestone "(special levels)" $ lev_comp 'spec_input' !special levels $ milestone "(quest levels)" $ lev_comp 'qstl_input' !quest levels $ milestone "(dungeon compile)" $ dgn_comp 'dngn_input' !dungeon database $ set default [-] !move up $ if p3.nes."" .and. f$edit(p3,"UPCASE").nes."DATA_PLUS_DLB" then exit $ $make_dlb: $ ! start from a known location -- [.sys.vms] $ set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")' $! construct data library $ set default [-.-.dat] !move to data directory $ milestone "(dlb setup)" $! since DLB doesn't support wildcard expansion and we don't have shell $! file globbing, start by making a file listing its intended contents $ create nhdat.lst $ if f$search("nhdat.lst;-1").nes."" then - purge/noConfirm/noLog nhdat.lst $! an old data file might fool us later, so get rid of it $ if f$search(data_libry).nes."" then - delete/noConfirm/noLog 'data_libry';* $ if f$trnlnm("PFILE$").nes."" then close/noLog pfile$ $ open/Append pfile$ nhdat.lst $ i = 0 $dloop: $ g = f$element(i,",",dlb_files) $ if g.eqs."," then goto ddone $ wild = f$locate("*",g).ne.f$locate("%",g) $ fcnt = 0 $floop: $ f = f$search(g) $ if f.eqs."" then goto fdone $ fcnt = fcnt + 1 $! strip device, directory, and version from name $ f = f$parse(f,,,"NAME") + f$parse(f,,,"TYPE") $! strip trailing dot, if present, and change case $ f = f$edit(f + "#" - ".#" - "#","LOWERCASE") $ if f$extract(3,1,f).eqs."-" then - !"xyz-foo.lev" -> "Xyz-foo.lev" f = f$edit(f$extract(0,1,f),"UPCASE") + f$extract(1,255,f) $ write pfile$ f $ if wild then goto floop $fdone: $ if fcnt.eq.0 then warn "? no file(s) found for """,g,"""" $ i = i + 1 $ goto dloop $ddone: $ close pfile$ $ milestone "(dlb create)" $ dlb "-cfI" 'data_libry' nhdat.lst $ set default [-] !move up $ if p3.nes."" then exit $ $! $! set up the playground and save directories $ milestone "(directories)" $make_directories: $ srctree = f$environment("DEFAULT") $ set default 'gamedir' $ if f$parse("[-]").eqs."" then create/dir/log [-] !default owner & protection $ if f$parse("[]" ).eqs."" then - !needs to be world writable create/directory/owner='gameuic'/prot=(s:rwe,o:rwe,g:rwe,w:rwe)/log [] $ if f$search("SAVE.DIR;1").eqs."" then - create/directory/owner='gameuic'/prot=(s:rwe,o:rwe,g:rwe,w:rwe)/log - [.SAVE]/version_limit=2 $ set default 'srctree' $ if p3.nes."" then exit $! $! create empty writeable files -- logfile, scoreboard, multi-user access lock $! [if old versions are already present, validate and retain them if possible] $make_writeable_files: $ milestone "(writeable files)" !-!$ create/owner='gameuic'/prot=(s:rwed,o:rwed,g:rwed,w:rwed) - !-! 'gamedir''play_files' $ i = 0 $ploop: if f$trnlnm("PFILE$").nes."" then close/nolog pfile$ $ f = f$element(i,",",play_files) $ if f.eqs."," then goto pdone $ i = i + 1 $ f = gamedir + f $ if f$search(f).eqs."" then goto pmake !make it if not found $ if f$file_attrib(f,"RFM").nes."STMLF" then goto prej !must be stream_lf $ open/read/error=prej pfile$ 'f' $ read/end=ploop pfile$ pline !empty is ok $ close pfile$ $ pfield = f$element(0," ",pline) !1st field is version number $ if f$locate(".",pfield).lt.f$length(pfield) then goto ploop !keep $prej: rename/new_vers 'f' *.old !reject old version $pmake: create/fdl=sys$input:/owner='gameuic' 'f'/log file organization sequential protection (system:rwd,owner:rwd,group:rw,world:rw) record format stream_lf $ goto ploop $pdone: $ if p3.nes."" then exit $! $! copy over the remaining game files, then make them readonly $make_readonly_files: $ milestone "(readonly files)" $ if f$search("[.dat]''data_libry'").nes."" $ then call copyfiles 'f$string(data_libry+","+xtrn_files)' [.dat] "r" $ else !'dlb_files' is too long for a single command $ k = 200 + f$locate(",",f$extract(200,999,dlb_files)) $ call copyfiles 'f$extract(0,k,dlb_files)' [.dat] "r" $ call copyfiles 'f$extract(k+1,999,dlb_files)' [.dat] "r" $ endif $ if p3.nes."" then exit $! $make_executable: $ milestone "(nethack.exe)" $ call copy_file [.src]nethack.exe 'gamedir'nethack.exe "re" $ if p3.nes."" then exit $! $! provide invocation procedure (if available) $make_procedure: $ if f$search(invoc_proc).eqs."" then goto skip_dcl $ if f$search("''gamedir'nethack.com").nes."" then - if f$cvtime(f$file_attr("''gamedir'nethack.com","RDT")) - .ges. f$cvtime(f$file_attr(invoc_proc,"RDT")) then goto skip_dcl $ milestone "(nethack.com)" $ call copy_file 'invoc_proc' 'gamedir'nethack.com "re" $skip_dcl: $ if p3.nes."" then exit $! $! provide plain-text Guidebook doc file (if available) $make_documentation: $ if f$search(guidebook).eqs."" then goto skip_doc $ milestone "(Guidebook)" $ call copy_file 'guidebook' 'gamedir'Guidebook.doc "r" $skip_doc: $ if p3.nes."" then exit $! $! provide last-resort termcap file (if available) $make_termcap: $ if f$search(trmcp_file).eqs."" then goto skip_termcap $ if f$search("''gamedir'termcap").nes."" then goto skip_termcap $ milestone "(termcap)" $ call copy_file 'trmcp_file' 'gamedir'termcap "r" $skip_termcap: $ if p3.nes."" then exit $! $! done $ milestone "" $ define/nolog nethackdir 'gamedir' $ define/nolog hackdir 'gamedir' $ echo - f$fao("!/ Nethack installation complete. !/ Playground is !AS !/",gamedir) $ exit $ $! $! copy one file, resetting the protection on an earlier version first $copy_file: subroutine $ if f$search(p2).nes."" then set file/Prot=(s:rwed,o:rwed) 'p2' $ copy/Prot=(s:'p3'wd,o:'p3'wd,g:'p3',w:'p3') 'p1' 'p2' $ set file/Owner='gameuic'/Prot=(s:'p3',o:'p3') 'p2' $endsubroutine !copy_file $ $! $! copy a comma-separated list of wildcarded files, one file at a time $copyfiles: subroutine $ i = 0 $lloop: $ g = f$element(i,",",p1) $ if g.eqs."," then goto ldone $ g = p2 + g $ wild = f$locate("*",g).ne.f$locate("%",g) $ fcnt = 0 $eloop: $ f = f$search(g) $ if f.eqs."" then goto edone $ fcnt = fcnt + 1 $ f = f - f$parse(f,,,"VERSION") $ e = f$parse(f,,,"NAME") + f$parse(f,,,"TYPE") $ call copy_file 'f' 'gamedir''e' "''p3'" $ if wild then goto eloop $edone: $ if fcnt.eq.0 then warn "? no file(s) found for """,g,"""" $ i = i + 1 $ goto lloop $ldone: $endsubroutine !copyfiles $ $! nethack-3.4.3/sys/vms/lev_lex.h0100644000000000000000000000147007764735041015106 0ustar rootroot/* SCCS Id: @(#)lev_lex.h 3.4 1999/08/08 */ /* "vms/lev_lex.h" copied into "util/stdio.h" for use in *_lex.c only! * This is an awful kludge to allow util/*_lex.c made by SunOS's `lex' * to be compiled as is. (It isn't needed with `flex' or VMS POSIX * `lex' and is benign when either of those configurations are used.) * It works because the actual setup of yyin & yyout is performed in * src/lev_main.c, where stdin & stdout are still correctly defined. * * The troublesome code is * #include "stdio.h" * ... * FILE *yyin = stdin, *yyout = stdout; * The file scope initializers with non-constant values require this * hack, and the quotes instead of brackets makes it easy to do. */ #include #ifdef stdin # undef stdin #endif #define stdin 0 #ifdef stdout # undef stdout #endif #define stdout 0 nethack-3.4.3/sys/vms/nethack.com0100644000000000000000000000451207764735041015414 0ustar rootroot$! NetHack.Com -- sample command procedure for invoking NetHack 9-JAN-1993 $ v = 'f$verify(0)' $! $! Possible command line arguments include $! "-uConan-B" !play a barbarian named Conan $! "-u" "Merlin-W" !play a wizard named Merlin (slight variant of above) $! "-e" or "-E" !play an elf with default name (from environment $! ! [ie, NETHACKOPTIONS logical name] or VMS username) $! "-a" or "-A", "-b" or "-B", "-c" or "-C", ... !specify character type $! !note: "-s" is ambiguous between "play as a samurai" $! ! vs "show scoreboard", so use "-S" for the former $! "-x" or "-X" !play in 'explore' mode (practice for beginners) $! "-D" !play in 'wizard' mode (for debugging, available only $! ! to the username compiled into nethack.exe as WIZARD) $! "-dec" !turn on DECgraphics mode (VT100 line drawing, done $! ! automatically below if appropriate term attribs set) $! "-d" dir-path !specify an alternate playground directory (not $! ! recommended; define HACKDIR instead) $! $ $! $! assume this command procedure has been placed in the playground directory; $! get its device:[directory] $ hackdir = f$parse("_._;0",f$environ("PROCEDURE")) - "_._;0" $! $! hackdir should point to the 'playground' directory $ if f$trnlnm("HACKDIR").eqs."" then define hackdir 'hackdir' $! $! termcap is a text file defining terminal capabilities and escape sequences $ if f$trnlnm("TERMCAP").eqs."" then define termcap hackdir:termcap $! ! [ obsolete: now handled within nethack itself ] ! $! prior to VMS v6, the C Run-Time Library doesn't understand vt420 :-( ! $ TT$_VT400_Series = 113 ! $ if f$getdvi("TT:","DEVTYPE").eq.TT$_VT400_Series - ! .and. f$trnlnm("NETHACK_TERM").eqs."" then define nethack_term "vt400" $! $! use the VT100 line drawing character set if possible $ graphics = "" $ usropt = f$trnlnm("NETHACKOPTIONS") $ if usropt.eqs."" then usropt = f$trnlnm("HACKOPTIONS") $ if f$locate("DECG",f$edit(usropt,"UPCASE")) .ge. f$length(usropt) then - if f$getdvi("TT:","TT_DECCRT") .and. f$getdvi("TT:","TT_ANSICRT") then - $ graphics = " -dec" !select DECgraphics mode by default $! $! get input from the terminal, not from this .com file $ deassign sys$input $! $ nethack := $hackdir:nethack $ if p1.nes."-s" .and. p1.nes."-s all" then - nethack = nethack + graphics $ nethack "''p1'" "''p2'" "''p3'" "''p4'" "''p5'" "''p6'" "''p7'" "''p8'" $! nethack-3.4.3/sys/vms/oldcrtl.c0100644000000000000000000001270507764735041015111 0ustar rootroot/* SCCS Id: @(#)oldcrtl.c 3.4 1995/06/01 */ /* Pat Rankin May'90 */ /* VMS NetHack support, not needed for vms 4.6,4.7,5.x,or later */ #ifdef VERYOLD_VMS /* * The following routines are used by NetHack but were not available * from the C Run-Time Library (VAXCRTL) prior to VMS V4.6. * * atexit, memcmp, memcpy, qsort, rename, vprintf, vsprintf * * Most of them are implemented here, but others will have to be worked * around in another fashion [such as '#define USE_OLDARGS' (even though * is available) to avoid the need for vprintf & vsprintf]. * */ #define REG register #define const #ifndef SUPPRESS_MEM_FUNCS /* note: hand optimized for VAX (hardware pre-decrement & post-increment) */ /* void *memset(void *, int, size_t) -- fill chunk of memory. */ char *memset( dst, fil, cnt ) REG char *dst; REG char fil; REG int cnt; { char *dst_p = dst; while ( --cnt >= 0 ) *dst++ = fil; return dst_p; } /* void *memcpy(void *, const void *, size_t) -- copy chunk of memory. */ char *memcpy( dst, src, cnt ) REG char *dst; REG const char *src; REG int cnt; { char *dst_p = dst; while ( --cnt >= 0 ) *dst++ = *src++; return dst_p; } /* void *memmove(void *, const void *, size_t) -- copy possibly overlapping mem. */ char *memmove( dst, src, cnt ) REG char *dst; REG const char *src; REG int cnt; { char *dst_p = dst; if ( src == dst || cnt <= 0 ) { ; /* do nothing */ } else if ( dst < src || dst >= src + cnt ) { while ( --cnt >= 0 ) *dst++ = *src++; } else { /* work backwards */ dst += cnt, src += cnt; while ( --cnt >= 0 ) *--dst = *--src; } return dst_p; } /* void *memchr(const void *, int, size_t) -- search for a byte. */ char *memchr( buf, byt, len ) REG const char *buf; REG char byt; REG int len; { while ( --len >= 0 ) if ( *buf++ == byt ) /* found */ return (char *)--buf; return (char *)0; /* not found */ } /* int memcmp(const void *, const void *, size_t) -- compare two chunks. */ int memcmp( buf1, buf2, len ) REG const char *buf1; REG const char *buf2; REG int len; { while ( --len >= 0 ) if ( *buf1++ != *buf2++ ) return (*--buf1 - *--buf2); return 0; /* buffers matched */ } #endif /*!SUPPRESS_MEM_FUNCS*/ #ifndef SUPPRESS_ATEXIT /* int atexit(void (*)(void)) -- register an exit handler. */ #define MAX_EXIT_FUNCS 32 /* arbitrary (32 matches VAX C v3.x docs) */ struct ex_hndlr { long reserved, (*routine)(), arg_count, *arg1_addr; }; static int ex_cnt = 0; /* number of handlers registered so far */ static struct { long dummy_arg; struct ex_hndlr handler; /*(black box)*/ } ex_data[MAX_EXIT_FUNCS]; /* static handler data */ extern unsigned long sys$dclexh(); int atexit( function ) void (*function)(); /* note: actually gets called with 1 arg */ { if ( ex_cnt < MAX_EXIT_FUNCS ) { ex_data[ex_cnt].dummy_arg = 0; /* ultimately receives exit reason */ ex_data[ex_cnt].handler.reserved = 0; ex_data[ex_cnt].handler.routine = (long (*)()) function; ex_data[ex_cnt].handler.arg_count = 1; /*(required)*/ ex_data[ex_cnt].handler.arg1_addr = &ex_data[ex_cnt].dummy_arg; (void)sys$dclexh(&ex_data[ex_cnt].handler); /* declare exit handler */ return ++ex_cnt; /*(non-zero)*/ } else return 0; } #endif /*!SUPPRESS_ATEXIT*/ #ifndef SUPPRESS_RENAME /* int rename(const char *, const char *) -- rename a file (on same device). */ #ifndef EVMSERR #include #define C$$TRANSLATE(status) (errno = EVMSERR, vaxc$errno = (status)) #endif extern unsigned long lib$rename_file(); int rename( old_name, new_name ) const char *old_name; const char *new_name; { struct dsc { unsigned short len, mbz; const char *adr; } old_dsc, new_dsc; unsigned long status; /* put strings into descriptors and call run-time library routine */ new_dsc.mbz = old_dsc.mbz = 0; /* type and class unspecified */ old_dsc.len = strlen( old_dsc.adr = old_name ); new_dsc.len = strlen( new_dsc.adr = new_name ); status = lib$rename_file(&old_dsc, &new_dsc); /* omit optional args */ if ( !(status & 1) ) { /* even => failure */ C$$TRANSLATE(status); return -1; } else /* odd => success */ return 0; } #endif /*!SUPPRESS_RENAME*/ #ifndef SUPPRESS_QSORT /* void qsort(void *, size_t, size_t, int (*)()) -- sort arbitrary collection. */ extern char *malloc(); /* assume no alloca() available */ extern void free(); void qsort( base, count, size, compare ) char *base; int count; REG int size; int (*compare)(); { REG int i, cmp; REG char *next, *prev, *tmp = 0; char wrk_buf[512]; /* just use a shuffle sort (tradeoff between efficiency & simplicity) */ /* [Optimal if already sorted; worst case when initially reversed.] */ for ( next = base, i = 1; i < count; i++ ) { prev = next, next += size; /* increment front pointer */ if ( (cmp = (*compare)( next, prev)) < 0 ) { /* found element out of order; move other(s) up then re-insert it */ if ( !tmp ) tmp = size > (int)(sizeof wrk_buf) ? malloc(size) : wrk_buf; memcpy( tmp, next, size); /* save smaller element */ while ( cmp < 0 ) { memcpy( prev + size, prev, size); /* move larger elem. up */ prev -= size; /* decrement back pointer */ cmp = (prev >= base ? (*compare)( tmp, prev) : 0); } memcpy( prev + size, tmp, size); /* restore small element */ } } if ( tmp != 0 && tmp != wrk_buf ) free(tmp); return; } #endif /*!SUPPRESS_QSORT*/ #endif /*VERYOLD_VMS*/ nethack-3.4.3/sys/vms/spec_lev.com0100644000000000000000000000620507764735041015600 0ustar rootroot$ ! sys/vms/spec_lev.com -- preprocess nethack's special level compiler code $ ! $ ! This operation needs to be performed prior to executing vmsbuild.com. $ ! Process the scanning and parsing code for NetHack's special level $ ! and dungeon compilers. *.l and *.y are converted into *'.c and *.h. $ ! $ $ ! setup yacc/bison and lex/flex; $ ! (Uncomment the alternatives appropriate for your site; $ ! if yacc and lex are not defined, the pre-processed files $ ! distributed in sys/share will be copied and used.) $ ! yacc := bison /Define !native bison (w/ DCL CLD) $ ! yacc := $bison$dir:bison -y -d !'foreign' bison (w/o CLD) $ ! yacc := posix /Run/Input=nl: posix$bin:yacc. """-d $ ! yacc := $shell$exe:yacc -d !yacc from DEC/Shell $ ! lex := $flex$dir:flex !flex $ ! lex := posix /Run/Input=nl: posix$bin:lex. """ $ ! lex := $shell$exe:lex $ ! (Nothing below this line should need to be changed.) $ ! additional setup $ rename := rename/New_Vers $ mung := call mung ! not to be confused with teco :-) $ delete := delete/noConfirm $ search := search/Exact $ copy := copy/noConcat $ ! start from a known location -- [.sys.vms], then move to [-.-.util] $ cur_dir = f$environment("DEFAULT") $ set default 'f$parse(f$environment("PROCEDURE"),,,"DIRECTORY")' $ set default [-.-.util] !move to utility directory $ $mung: subroutine $ ! kludge to strip bogus #module directives from POSIX-processed files $ ! in lieu of $ rename 'p1' 'p2' $ search/Match=NOR 'p1' "#module" /Output='p2' $ delete 'p1';* $ endsubroutine !mung $ $ ! first cleanup any old intermediate files (to safely handle blind renaming) $ if f$search("*tab.%").nes."" then delete *tab.%;* !yacc & bison $ if f$search("*yy.c") .nes."" then delete *yy.c;* !lex & flex $ $ ! process lev_comp.y into lev_yacc.c and ../include/lev_comp.h $ if f$type(yacc).eqs."STRING" $ then $ yacc lev_comp.y $ if f$search("y_tab.%").nes."" then rename y_tab.% lev_comp_tab.* $ if f$search("ytab.%") .nes."" then rename ytab.% lev_comp_tab.* $ else ! use preprocessed files $ copy [-.sys.share]lev_yacc.c,lev_comp.h []lev_comp_tab.* $ endif $ mung lev_comp_tab.c lev_yacc.c $ rename lev_comp_tab.h [-.include]lev_comp.h $ $ ! process lev_comp.l into lev_lex.c $ if f$type(lex).eqs."STRING" $ then $ lex lev_comp.l $ if f$search("lexyy.c").nes."" then rename lexyy.c lex_yy.* $ else ! use preprocessed file $ copy [-.sys.share]lev_lex.c []lex_yy.* $ endif $ mung lex_yy.c lev_lex.c $ $ ! process dgn_comp.y into dgn_yacc.c and ../include/dgn_comp.h $ if f$type(yacc).eqs."STRING" $ then $ yacc dgn_comp.y $ if f$search("y_tab.%").nes."" then rename y_tab.% dgn_comp_tab.* $ if f$search("ytab.%") .nes."" then rename ytab.% dgn_comp_tab.* $ else $ copy [-.sys.share]dgn_yacc.c,dgn_comp.h []dgn_comp_tab.* $ endif $ mung dgn_comp_tab.c dgn_yacc.c $ rename dgn_comp_tab.h [-.include]dgn_comp.h $ $ ! process dgn_comp.l into dgn_lex.c $ if f$type(lex).eqs."STRING" $ then $ lex dgn_comp.l $ if f$search("lexyy.c").nes."" then rename lexyy.c lex_yy.* $ else $ copy [-.sys.share]dgn_lex.c []lex_yy.* $ endif $ mung lex_yy.c dgn_lex.c $ $ ! done $ set default 'cur_dir' $ exit nethack-3.4.3/sys/vms/vmsbuild.com0100644000000000000000000003036007764735041015624 0ustar rootroot$ ! vms/vmsbuild.com -- compile and link NetHack 3.4.* [pr] $ version_number = "3.4.3" $ ! $ ! usage: $ ! $ set default [.src] !or [-.-.src] if starting from [.sys.vms] $ ! $ @[-.sys.vms]vmsbuild [compiler-option] [link-option] [cc-switches] $ ! options: $ ! compiler-option : either "VAXC", "DECC" or "GNUC" or "" !default VAXC $ ! link-option : either "SHARE[able]" or "LIB[rary]" !default SHARE $ ! cc-switches : optional qualifiers for CC (such as "/noOpt/Debug") $ ! notes: $ ! If the symbol "CC" is defined, compiler-option is not used. $ ! The link-option refers to VAXCRTL (C Run-Time Library) handling; $ ! to specify it while letting compiler-option default, use "" as $ ! the compiler-option. $ ! To re-link without compiling, use "LINK" as special 'compiler-option'; $ ! to re-link with GNUC library, 'CC' must begin with "G" (or "g"). $ ! Default wizard definition moved to include/vmsconf.h. $ $ decc_dflt = f$trnlnm("DECC$CC_DEFAULT") $ j = (decc_dflt.nes."") .and. 1 $ vaxc_ = "CC" + f$element(j,"#","#/VAXC") + "/NOLIST/OPTIMIZE=NOINLINE" $ decc_ = "CC" + f$element(j,"#","#/DECC") + "/PREFIX=ALL/NOLIST" $ gnuc_ = "GCC" $ if f$type(gcc).eqs."STRING" then gnuc_ = gcc $ gnulib = "gnu_cc:[000000]gcclib/Library" !(not used w/ vaxc) $ ! common CC options (/obj=file doesn't work for GCC 1.36, use rename instead) $ c_c_ = "/INCLUDE=[-.INCLUDE]" $ veryold_vms = f$extract(1,1,f$getsyi("VERSION")).eqs."4" - .and. f$extract(3,3,f$getsyi("VERSION")).lts."6" $ if veryold_vms then c_c_ = c_c_ + "/DEFINE=(""VERYOLD_VMS"")" $ axp = (f$getsyi("CPU").ge.128) !f$getsyi("ARCH_NAME").eqs."Alpha" $ ! miscellaneous setup $ ivqual = %x00038240 !DCL-W-IVQUAL (used to check for ancient vaxc) $ abort := exit %x1000002A $ cur_dir = f$environment("DEFAULT") $ vmsbuild = f$environment("PROCEDURE") $ ! validate first parameter $ p1 := 'p1' $ if p1.eqs."" .and. (axp .or. decc_dflt.eqs."/DECC") then p1 = "DECC" $ o_VAXC = 0 !(c_opt substring positions) $ o_DECC = 5 $ o_GNUC = 10 $ o_LINK = 15 $ o_SPCL = 20 $ c_opt = f$locate("|"+p1, "|VAXC|DECC|GNUC|LINK|SPECIAL|") !5 $ if (c_opt/5)*5 .eq. c_opt then goto p1_ok $ copy sys$input: sys$error: !p1 usage %first arg is compiler option; it must be one of "VAXC" -- use VAX C to compile everything or "DECC" -- use DEC C to compile everything or "GNUC" -- use GNU C to compile everything or "LINK" -- skip compilation, just relink nethack.exe or "SPEC[IAL]" -- just compile and link lev_comp.exe or "" -- default operation (VAXC unless 'CC' is defined) Note: if a DCL symbol for CC is defined, "VAXC" and "GNUC" are no-ops. If the symbol value begins with "G" (or "g"), then the GNU C library will be included in all link operations. Do not rebuild lev_comp with "SPECIAL" unless you have a CC symbol setup with the proper options. $ abort $p1_ok: $ ! validate second parameter $ p2 := 'p2' $ l_opt = f$locate("|"+p2, "|SHAREABLE|LIBRARY__|NONE_____|") !10 $ if (l_opt/10)*10 .eq. l_opt then goto p2_ok $ copy sys$input: sys$error: !p2 usage %second arg is C run-time library handling; it must be one of "SHAREABLE" -- link with SYS$SHARE:VAXCRTL.EXE/SHAREABLE or "LIBRARY" -- link with SYS$LIBRARY:VAXCRTL.OLB/LIBRARY or "NONE" -- explicitly indicate DECC$SHR or "" -- default operation (use shareable image) Note: for MicroVMS 4.x, "SHAREABLE" (which is the default) is required. Specify "NONE" if using DEC C with a CC symbol overriding 1st arg. $ abort $p2_ok: $ ! start from a known location -- [.sys.vms], then move to [-.-.src] $ set default 'f$parse(vmsbuild,,,"DEVICE")''f$parse(vmsbuild,,,"DIRECTORY")' $ set default [-.-.src] !move to source directory $ ! compiler setup; if a symbol for "CC" is already defined it will be used $ if f$type(cc).eqs."STRING" then goto got_cc $ cc = vaxc_ !assume "VAXC" requested or defaulted $ if c_opt.eq.o_GNUC then goto chk_gcc !explicitly invoked w/ "GNUC" option $ if c_opt.eq.o_DECC then cc = decc_ $ if c_opt.ne.o_VAXC then goto got_cc !"SPEC" or "LINK", skip compiler check $ ! we want to prevent function inlining with vaxc v3.x (/opt=noinline) $ ! but we can't use noInline with v2.x, so need to determine version $ set noOn $ msgenv = f$environment("MESSAGE") $ set message/noFacil/noSever/noIdent/noText $ cc/noObject _NLA0:/Include=[] !strip 'noinline' if error $ sts = $status $ if sts then goto reset_msg !3.0 or later will check out OK $ ! must be dealing with vaxc 2.x; ancient version (2.2 or earlier) $ ! can't handle /include='dir', needs c$include instead $ cc = cc - "=NOINLINE" - ",NOINLINE" - "NOINLINE," $ if sts.ne.IVQUAL then goto reset_msg $ define/noLog c$include [-.INCLUDE] $ c_c_ = "/DEFINE=(""ANCIENT_VAXC"")" $ if veryold_vms then c_c_ = c_c_ - ")" + ",""VERYOLD_VMS"")" $reset_msg: $ set message 'msgenv' $ set On $ goto got_cc $ ! $chk_gcc: $ cc = gnuc_ $ ! old versions of gcc-vms don't have or available $ c_c_ = "/DEFINE=(""USE_OLDARGS"")" $ if veryold_vms then c_c_ = c_c_ - ")" + ",""VERYOLD_VMS"")" $ if veryold_vms then goto chk_gas !avoid varargs & stdarg $ if f$search("gnu_cc_include:[000000]varargs.h").nes."" then - c_c_ = "/DEFINE=(""USE_VARARGS"")" $ if f$search("gnu_cc_include:[000000]stdarg.h").nes."" then - c_c_ = "/DEFINE=(""USE_STDARG"")" $chk_gas: $ ! test whether this version of gas handles the 'const' construct correctly $ gas_chk_tmp = "sys$scratch:gcc-gas-chk.tmp" $ if f$search(gas_chk_tmp).nes."" then delete/noconfirm/nolog 'gas_chk_tmp';* $ gas_ok = 0 !assume bad $ on warning then goto skip_gas $ define/user/nolog sys$error 'gas_chk_tmp' $ mcr gnu_cc:[000000]gcc-as sys$input: -o _NLA0: $DECK .const .comm dummy,0 .const .comm dummy,0 $EOD $ gas_ok = 1 !assume good $ if f$search(gas_chk_tmp).eqs."" then goto skip_gas $ ! if the error file is empty, gas can deal properly with const $ gas_ok = f$file_attrib(gas_chk_tmp,"EOF") .eq. 0 $ delete/noconfirm/nolog 'gas_chk_tmp';* $skip_gas: $ on warning then continue $ if .not.gas_ok then c_c_ = c_c_ - ")" + ",""const="")" $ c_c_ = "/INCLUDE=[-.INCLUDE]" + c_c_ $ ! $got_cc: $ cc = cc + c_c_ !append common qualifiers $ if p3.nes."" then cc = cc + p3 !append optional user preferences $ g := 'f$extract(0,1,cc)' $ if g.eqs."$" then g := 'f$extract(1,1,cc)' !"foreign" gcc $ if f$edit(f$extract(1,1,cc),"UPCASE").eqs."E" then g := X !GEMC $ if g.nes."G" .and. c_opt.ne.o_GNUC then gnulib = "" $ if g.eqs."G" .or. c_opt.eq.o_GNUC then gnulib = "," + gnulib $ ! linker setup; if a symbol for "LINK" is defined, we'll use it $ if f$type(link).nes."STRING" then link = "LINK/NOMAP" $ if p4.nes."" then link = link + p4 !append optional user preferences $ if c_opt.eq.o_DECC .or. l_opt.eq.10 $ then $ crtl = "" !sys$share:decc$shr.exe/Sharable found automatically $ create crtl.opt !empty $ else $ crtl = ",sys$library:vaxcrtl.olb/Library" !object library $ if l_opt.ne.0 then goto crtl_ok $ crtl = ",sys$disk:[-.src]crtl.opt/Options" !shareable image $ if f$search("crtl.opt").nes."" then goto crtl_ok !assume its right $ create sys$disk:[-.src]crtl.opt sys$share:vaxcrtl.exe/Shareable $ endif $crtl_ok: $ if f$search("crtl.opt;-2").nes."" then purge/Keep=2/noLog crtl.opt $ ! version ID info for linker to record in .EXE files $ create ident.opt $ open/Append f ident.opt $ write f "identification=""",version_number,""" !version" $ close f $ if f$search("ident.opt;-1").nes."" then purge/noLog ident.opt $ ident_opt = ",sys$disk:[-.src]ident.opt/Options" $ ! final setup $ nethacklib = "[-.src]nethack.olb" $ milestone = "write sys$output f$fao("" !5%T "",0)," $ if c_opt.eq.o_LINK then goto link !"LINK" requested, skip compilation $ rename := rename/New_Vers $ touch := set file/Truncate $ makedefs := $sys$disk:[-.util]makedefs $ show symbol cc $ goto begin !skip subroutines $! $compile_file: !input via 'c_file' $ no_lib = ( f$extract(0,1,c_file) .eqs. "#" ) $ if no_lib then c_file = f$extract(1,255,c_file) $ c_name = f$edit(f$parse(c_file,,,"NAME"),"LOWERCASE") $ f_opts = "" !options for this file $ if f$type('c_name'_options).nes."" then f_opts = 'c_name'_options $ milestone " (",c_name,")" $ if f$search("''c_name'.obj").nes."" then delete 'c_name'.obj;* $ cc 'f_opts' 'c_file' $ if .not.no_lib then nh_obj_list == nh_obj_list + ",''c_name'.obj;0" $ return $! $compile_list: !input via 'c_list' $ nh_obj_list == "" $ j = -1 $ c_loop: $ j = j + 1 $ c_file = f$element(j,",",c_list) !get next file $ if c_file.eqs."," then goto c_done $ c_file = c_file + ".c" $ gosub compile_file $ goto c_loop $ c_done: $ nh_obj_list == f$extract(1,999,nh_obj_list) $ if nh_obj_list.nes."" then libr/Obj 'nethacklib' 'nh_obj_list'/Replace $ if nh_obj_list.nes."" then delete 'nh_obj_list' $ delete/symbol/global nh_obj_list $ return $! $begin: $! $! miscellaneous special source file setup $! $ if f$search("random.c").eqs."" then copy [-.sys.share]random.c []*.* $ if f$search("tclib.c") .eqs."" then copy [-.sys.share]tclib.c []*.* $ if f$search("[-.util]lev_yacc.c").eqs."" then @[-.sys.vms]spec_lev.com $! $! create object library $! $ if c_opt.ne.o_SPCL .or. f$search("''nethacklib'").eqs."" then - libr/Obj 'nethacklib'/Create=(Block=3000,Hist=0) $ if f$search("''nethacklib';-1").nes."" then purge 'nethacklib' $! $! compile and link makedefs, then nethack, finally lev_comp & dgn_comp. $! $ milestone "" $ c_list = "[-.sys.vms]vmsmisc,[]alloc,dlb,monst,objects" $ if c_opt.eq.o_SPCL then c_list = c_list + ",decl,drawing" $ gosub compile_list $ if c_opt.eq.o_SPCL then goto special !"SPECIAL" requested, skip main build $ set default [-.util] $ c_list = "#makedefs" $ gosub compile_list $ link makedefs.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt' $ milestone "makedefs" $! create some build-time files $ makedefs -p !pm.h $ makedefs -o !onames.h $ makedefs -v !date.h $ milestone " (*.h)" $ makedefs -m !../src/monstr.c $ makedefs -z !../src/vis_tab.c, ../include/vis_tab.h $ milestone " (*.c)" $ set default [-.src] $! compile most of the source files: $ c_list = "decl,version,[-.sys.vms]vmsmain,[-.sys.vms]vmsunix" - + ",[-.sys.vms]vmstty,[-.sys.vms]vmsmail,[-.sys.vms]vmsfiles" - + ",[]random,[]tclib" !copied from [-.sys.share] $ gosub compile_list $ c_list = "[-.win.tty]getline,[-.win.tty]termcap" - + ",[-.win.tty]topl,[-.win.tty]wintty" $ gosub compile_list $ c_list = "allmain,apply,artifact,attrib,ball,bones,botl,cmd,dbridge,detect" - + ",dig,display,do,do_name,do_wear,dog,dogmove,dokick,dothrow,drawing" - + ",dungeon,eat,end,engrave,exper,explode,extralev,files,fountain" $ gosub compile_list $ c_list = "hack,hacklib,invent,light,lock,mail,makemon,mapglyph,mcastu" - + ",mhitm,mhitu,minion,mklev,mkmap,mkmaze,mkobj,mkroom,mon,mondata" - + ",monmove,monstr,mplayer,mthrowu,muse,music,o_init,objnam,options" - + ",pager,pickup" $ gosub compile_list $ c_list = "pline,polyself,potion,pray,priest,quest,questpgr,read" - + ",rect,region,restore,rip,rnd,role,rumors,save,shk,shknam,sit" - + ",sounds,sp_lev,spell,steal,steed,teleport,timeout,topten,track" - + ",trap,u_init" $ gosub compile_list $ c_list = "uhitm,vault,vision,vis_tab,weapon,were,wield,windows" - + ",wizard,worm,worn,write,zap" $ gosub compile_list $! $link: $ milestone "" $ link/Exe=nethack.exe 'nethacklib'/Lib/Incl=(vmsmain)'crtl''gnulib''ident_opt' $ milestone "NetHack" $ if c_opt.eq.o_LINK then goto done !"LINK" only $special: $! $! build special level and dungeon compilers $! $ set default [-.util] $ c_list = "#panic,#lev_main,#lev_yacc,#dgn_main,#dgn_yacc" $ if c_opt.eq.o_SPCL then c_list = "[-.sys.vms]vmsfiles," + c_list $ gosub compile_list $ c_list = "#lev_lex,#dgn_lex" $ copy [-.sys.vms]lev_lex.h stdio.*/Prot=(s:rwd,o:rwd) $ gosub compile_list $ rename stdio.h lev_lex.* $ link/exe=lev_comp.exe lev_main.obj,lev_yacc.obj,lev_lex.obj,- panic.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt' $ milestone "lev_comp" $ link/exe=dgn_comp.exe dgn_main.obj,dgn_yacc.obj,dgn_lex.obj,- panic.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt' $ milestone "dgn_comp" $! $ c_list = "#dlb_main,#recover" $ gosub compile_list $ link/exe=dlb.exe dlb_main.obj,panic.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt' $ milestone "dlb" $ link/exe=recover.exe recover.obj,'nethacklib'/Lib'crtl''gnulib''ident_opt' $ milestone "recover" $! $done: $ set default 'cur_dir' $ exit nethack-3.4.3/sys/vms/vmsfiles.c0100644000000000000000000002126307764735041015275 0ustar rootroot/* SCCS Id: @(#)vmsfiles.c 3.4 1999/08/29 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * VMS-specific file manipulation routines to implement some missing * routines or substitute for ones where we want behavior modification. */ #include "config.h" #include /* lint supression due to lack of extern.h */ int FDECL(vms_link, (const char *,const char *)); int FDECL(vms_unlink, (const char *)); int FDECL(vms_creat, (const char *,unsigned int)); int FDECL(vms_open, (const char *,int,unsigned int)); boolean FDECL(same_dir, (const char *,const char *)); int FDECL(c__translate, (int)); char *FDECL(vms_basename, (const char *)); #include #if 0 #include #else #define PSL$C_EXEC 1 /* executive mode, for priv'd logical name handling */ #endif #include #ifndef C$$TRANSLATE /* don't rely on VAXCRTL's internal routine */ #define C$$TRANSLATE(status) (errno = EVMSERR, vaxc$errno = (status)) #endif extern unsigned long sys$parse(), sys$search(), sys$enter(), sys$remove(); extern int VDECL(lib$match_cond, (int,int,...)); #define vms_success(sts) ((sts)&1) /* odd, */ #define vms_failure(sts) (!vms_success(sts)) /* even */ /* vms_link() -- create an additional directory for an existing file */ int vms_link(file, new) const char *file, *new; { struct FAB fab; struct NAM nam; unsigned short fid[3]; char esa[NAM$C_MAXRSS]; fab = cc$rms_fab; /* set block ID and length, zero the rest */ fab.fab$l_fop = FAB$M_OFP; fab.fab$l_fna = (char *) file; fab.fab$b_fns = strlen(file); fab.fab$l_nam = &nam; nam = cc$rms_nam; nam.nam$l_esa = esa; nam.nam$b_ess = sizeof esa; if (vms_success(sys$parse(&fab)) && vms_success(sys$search(&fab))) { fid[0] = nam.nam$w_fid[0]; fid[1] = nam.nam$w_fid[1]; fid[2] = nam.nam$w_fid[2]; fab.fab$l_fna = (char *) new; fab.fab$b_fns = strlen(new); if (vms_success(sys$parse(&fab))) { nam.nam$w_fid[0] = fid[0]; nam.nam$w_fid[1] = fid[1]; nam.nam$w_fid[2] = fid[2]; nam.nam$l_esa = nam.nam$l_name; nam.nam$b_esl = nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver; (void) sys$enter(&fab); } } if (vms_failure(fab.fab$l_sts)) { C$$TRANSLATE(fab.fab$l_sts); return -1; } return 0; /* success */ } /* vms_unlink() -- remove a directory entry for a file; should only be used for files which have had extra directory entries added, not for deletion (because the file won't be deleted, just made inaccessible!). */ int vms_unlink(file) const char *file; { struct FAB fab; struct NAM nam; char esa[NAM$C_MAXRSS]; fab = cc$rms_fab; /* set block ID and length, zero the rest */ fab.fab$l_fop = FAB$M_DLT; fab.fab$l_fna = (char *) file; fab.fab$b_fns = strlen(file); fab.fab$l_nam = &nam; nam = cc$rms_nam; nam.nam$l_esa = esa; nam.nam$b_ess = sizeof esa; if (vms_failure(sys$parse(&fab)) || vms_failure(sys$remove(&fab))) { C$$TRANSLATE(fab.fab$l_sts); return -1; } return 0; } /* Substitute creat() routine -- if trying to create a specific version, explicitly remove an existing file of the same name. Since it's only used when we expect exclusive access, add a couple RMS options for optimization. (Don't allow sharing--eliminates coordination overhead, and use 32 block buffer for faster throughput; ~30% speedup measured.) */ #undef creat int vms_creat(file, mode) const char *file; unsigned int mode; { if (index(file, ';')) { /* assumes remove or delete, not vms_unlink */ if (!unlink(file)) { (void)sleep(1); (void)unlink(file); } } return creat(file, mode, "shr=nil", "mbc=32", "mbf=2", "rop=wbh"); } /* Similar substitute for open() -- if an open attempt fails due to being locked by another user, retry it once (work-around for a limitation of at least one NFS implementation). */ #undef open int vms_open(file, flags, mode) const char *file; int flags; unsigned int mode; { int fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah"); if (fd < 0 && errno == EVMSERR && lib$match_cond(vaxc$errno, RMS$_FLK)) { (void)sleep(1); fd = open(file, flags, mode, "mbc=32", "mbf=2", "rop=rah"); } return fd; } /* Determine whether two strings contain the same directory name. Used for deciding whether installed privileges should be disabled when HACKDIR is defined in the environment (or specified via -d on the command line). This version doesn't handle Unix-style file specs. */ boolean same_dir(d1, d2) const char *d1, *d2; { if (!d1 || !*d1 || !d2 || !*d2) return FALSE; else if (!strcmp(d1, d2)) /* strcmpi() would be better, but that leads */ return TRUE; /* to linking problems for the utilities */ else { struct FAB f1, f2; struct NAM n1, n2; f1 = f2 = cc$rms_fab; /* initialize file access block */ n1 = n2 = cc$rms_nam; /* initialize name block */ f1.fab$b_acmodes = PSL$C_EXEC << FAB$V_LNM_MODE; f1.fab$b_fns = strlen( f1.fab$l_fna = (char *)d1 ); f2.fab$b_fns = strlen( f2.fab$l_fna = (char *)d2 ); f1.fab$l_nam = (genericptr_t)&n1; /* link nam to fab */ f2.fab$l_nam = (genericptr_t)&n2; n1.nam$b_nop = n2.nam$b_nop = NAM$M_NOCONCEAL; /* want true device name */ return (vms_success(sys$parse(&f1)) && vms_success(sys$parse(&f2)) && n1.nam$t_dvi[0] == n2.nam$t_dvi[0] && !strncmp(&n1.nam$t_dvi[1], &n2.nam$t_dvi[1], n1.nam$t_dvi[0]) && !memcmp((genericptr_t)n1.nam$w_did, (genericptr_t)n2.nam$w_did, sizeof n1.nam$w_did)); /*{ short nam$w_did[3]; }*/ } } /* * c__translate -- substitute for VAXCRTL routine C$$TRANSLATE. * * Try to convert a VMS status code into its Unix equivalent, * then set `errno' to that value; use EVMSERR if there's no * appropriate translation; set `vaxc$errno' to the original * status code regardless. * * These translations match only a subset of VAXCRTL's lookup * table, but work even if the severity has been adjusted or * the inhibit-message bit has been set. */ #include #include #include /* #include */ /* #include */ #define VALUE(U) trans = U; break #define CASE1(V) case (V >> 3) #define CASE2(V,W) CASE1(V): CASE1(W) int c__translate(code) int code; { register int trans; switch ((code & 0x0FFFFFF8) >> 3) { /* strip upper 4 and bottom 3 bits */ CASE2(RMS$_PRV,SS$_NOPRIV): VALUE(EPERM); /* not owner */ CASE2(RMS$_DNF,RMS$_DIR): CASE2(RMS$_FNF,RMS$_FND): CASE1(SS$_NOSUCHFILE): VALUE(ENOENT); /* no such file or directory */ CASE2(RMS$_IFI,RMS$_ISI): VALUE(EIO); /* i/o error */ CASE1(RMS$_DEV): CASE2(SS$_NOSUCHDEV,SS$_DEVNOTMOUNT): VALUE(ENXIO); /* no such device or address codes */ CASE1(RMS$_DME): /* CASE1(LIB$INSVIRMEM): */ CASE2(SS$_VASFULL,SS$_INSFWSL): VALUE(ENOMEM); /* not enough core */ CASE1(SS$_ACCVIO): VALUE(EFAULT); /* bad address */ CASE2(RMS$_DNR,SS$_DEVASSIGN): CASE2(SS$_DEVALLOC,SS$_DEVALRALLOC): CASE2(SS$_DEVMOUNT,SS$_DEVACTIVE): VALUE(EBUSY); /* mount device busy codes to name a few */ CASE2(RMS$_FEX,SS$_FILALRACC): VALUE(EEXIST); /* file exists */ CASE2(RMS$_IDR,SS$_BADIRECTORY): VALUE(ENOTDIR); /* not a directory */ CASE1(SS$_NOIOCHAN): VALUE(EMFILE); /* too many open files */ CASE1(RMS$_FUL): CASE2(SS$_DEVICEFULL,SS$_EXDISKQUOTA): VALUE(ENOSPC); /* no space left on disk codes */ CASE2(RMS$_WLK,SS$_WRITLCK): VALUE(EROFS); /* read-only file system */ default: VALUE(EVMSERR); }; errno = trans; vaxc$errno = code; return code; /* (not very useful) */ } #undef VALUE #undef CASE1 #undef CASE2 static char base_name[NAM$C_MAXRSS+1]; /* return a copy of the 'base' portion of a filename */ char * vms_basename(name) const char *name; { unsigned len; char *base, *base_p; register const char *name_p; /* skip directory/path */ if ((name_p = strrchr(name, ']')) != 0) name = name_p + 1; if ((name_p = strrchr(name, '>')) != 0) name = name_p + 1; if ((name_p = strrchr(name, ':')) != 0) name = name_p + 1; if ((name_p = strrchr(name, '/')) != 0) name = name_p + 1; if (!*name) name = "."; /* this should never happen */ /* find extension/version and derive length of basename */ if ((name_p = strchr(name, '.')) == 0 || name_p == name) name_p = strchr(name, ';'); len = (name_p && name_p > name) ? name_p - name : strlen(name); /* return a lowercase copy of the name in a private static buffer */ base = strncpy(base_name, name, len); base[len] = '\0'; /* we don't use lcase() so that utilities won't need hacklib.c */ for (base_p = base; base_p < &base[len]; base_p++) if (isupper(*base_p)) *base_p = tolower(*base_p); return base; } /*vmsfiles.c*/ nethack-3.4.3/sys/vms/vmsmail.c0100644000000000000000000004100307764735041015107 0ustar rootroot/* SCCS Id: @(#)vmsmail.c 3.4 1995/06/01 */ /* Copyright (c) Robert Patrick Rankin, 1991. */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #include "mail.h" /* lint supression due to lack of extern.h */ unsigned long NDECL(init_broadcast_trapping); unsigned long NDECL(enable_broadcast_trapping); unsigned long NDECL(disable_broadcast_trapping); struct mail_info *NDECL(parse_next_broadcast); #ifdef MAIL #include "wintype.h" #include "winprocs.h" #include #include #include # ifndef __GNUC__ #include # else # define MSG$_TRMHANGUP 6 # define MSG$_TRMBRDCST 83 # endif /*__GNUC__*/ #include /* #include */ # define vms_ok(sts) ((sts)&1) static struct mail_info *FDECL(parse_brdcst, (char *)); static void FDECL(filter_brdcst, (char *)); static void NDECL(flush_broadcasts); static void FDECL(broadcast_ast, (int)); extern char *FDECL(eos, (char *)); extern char *FDECL(strstri, (const char *,const char *)); extern int FDECL(strncmpi, (const char *,const char *,int)); extern size_t FDECL(strspn, (const char *,const char *)); #ifndef __DECC extern int VDECL(sscanf, (const char *,const char *,...)); #endif extern unsigned long smg$create_pasteboard(), smg$get_broadcast_message(), smg$set_broadcast_trapping(), smg$disable_broadcast_trapping(); extern volatile int broadcasts; /* defining declaration in mail.c */ static long pasteboard_id = 0; /* SMG's magic cookie */ /* * Mail (et al) overview: * * When a broadcast is asynchronously captured, a volatile counter * ('broadcasts') is incremented. Each player turn, ckmailstatus() polls * the counter and calls parse_next_broadcast() if it's positive; this * returns some display text, object name, and response command, which is * passed to newmail(). Routine newmail() generates a mail-daemon monster * who approaches the character, "speaks" the display text, and delivers * a scroll of mail pre-named to the object name; the response command is * initially appended to the name, so that the object is tagged with both * of them; a NUL is inserted to terminate the ordinary name and hide the * command. (If the player renames such a scroll, the hidden command will * be lost; who cares?) Unrecognized broadcasts result in the mail-daemon * arriving and announcing the display text, but no scroll being created. * If SHELL is undefined, then all broadcasts are treated as 'other'; since * no subproceses are allowed, there'd be no way to respond to the scroll. * * When a scroll of mail is read by the character, readmail() extracts * the hidden command string and uses it for the default when prompting the * player for a system command to spawn. The player may enter any command * he or she chooses, or just to accept the default or to * avoid executing any command. If the command is "SPAWN", a regular shell * escape to DCL is performed; otherwise, the indicated single command is * spawned. Either way, NetHack resumes play when the subprocess terminates * or explicitly reattaches to its parent. * * Broadcast parsing: * * The following broadcast messages are [attempted to be] recognized: * text fragment name for scroll default command * New mail VMSmail MAIL * New ALL-IN-1 MAIL A1mail A1M * Software Tools mail STmail MSG [+folder] * MM mail MMmail MM * WPmail: New mail WPmail OFFICE/MAIL * **M400 mail M400mail M400 * " mail", ^"mail " unknown mail SPAWN * " phoning" Phone call PHONE ANSWER * talk-daemon...by...foo Talk request TALK[/OLD] foo@bar * (node)user - Bitnet noise XYZZY user@node * Anything else results in just the message text being passed along, no * scroll of mail so consequently no command to execute when scroll read. * The user can set up ``$ XYZZY :== SEND'' prior to invoking NetHack if * vanilla JNET responses to Bitnet messages are prefered. * * Static return buffers are used because only one broadcast gets * processed at a time, and the essential information in each one is * either displayed and discarded or copied into a scroll-of-mail object. * * The test driver code below can be used to check out potential new * entries without rebuilding NetHack itself. CC/DEFINE="TEST_DRIVER" * Link it with hacklib.obj or nethack.olb/incl=hacklib (not nethack/lib). */ static struct mail_info msg; /* parse_*()'s return buffer */ static char nam_cmd_buf[63], /* maximum onamelth, size of ONAME(object) */ txt_buf[255+1]; /* same size as used for message buf[] */ /* try to decipher and categorize broadcast message text */ static struct mail_info * parse_brdcst(buf) /* called by parse_next_broadcast() */ char *buf; /* input: filtered broadcast text */ { int typ; char *txt; const char *nam, *cmd; # ifdef SHELL /* only parse if spawned commands are enabled */ register char *p, *q; boolean is_jnet_send; char cmd_buf[127+1], user[127+1], node[127+1], sentinel; /* Check these first; otherwise, their arbitrary text would enable easy spoofing of some other message patterns. Unfortunately, any home-grown broadcast delivery program poses a similar risk. */ if (!strncmpi(buf, "reply received", 14)) goto other; is_jnet_send = (sscanf(buf, "(%[^)])%s -%c", node, user, &sentinel) == 3); if (is_jnet_send) goto jnet_send; /* scan the text more or less by brute force */ if ((q = strstri(buf, " mail")) != 0 || /* all known mail broadcasts */ !strncmpi(q = buf, "mail ", 5)) { /* unexpected alternative */ typ = MSG_MAIL; p = strstri(q, " from"); txt = p ? strcat(strcpy(txt_buf, "Mail for you"), p) : (char *) 0; if (!strncmpi(buf, "new mail", 8)) { /* New mail [on node FOO] from [SPAM::]BAR [\"personal_name\"] [\(HH:MM:SS\)] */ nam = "VMSmail"; /* assume VMSmail */ cmd = "MAIL"; if (txt && (p = strrchr(txt, '(')) > txt && /* discard time */ (--p, strspn(p, "0123456789( :.)") == strlen(p))) *p = '\0'; } else if (!strncmpi(buf, "new all-in-1", 12)) { int i; /* New ALL-IN-1 MAIL message [on node FOO] from Personal Name \(BAR@SPAM\) [\(DD-MMM-YYYY HH:MM:SS\)] */ nam = "A1mail"; cmd = "A1M"; if (txt && (p = strrchr(txt, '(')) > txt && /* discard date+time */ sscanf(p-1," (%*d-%*[^-]-%*d %*d:%*d:%d) %c",&i,&sentinel) == 1) *--p = '\0'; } else if (!strncmpi(buf, "software tools", 14)) { /* Software Tools mail has arrived on FOO from \'BAR\' [in SPAM] */ nam = "STmail"; cmd = "MSG"; if (txt && (p = strstri(p, " in ")) != 0) /* specific folder */ cmd = strcat(strcpy(cmd_buf, "MSG +"), p + 4); } else if (q - 2 >= buf && !strncmpi(q - 2, "mm", 2)) { /* {MultiNet\ |PMDF\/}MM mail has arrived on FOO from BAR\n [Subject: subject_text] (PMDF only) */ nam = "MMmail"; /* MultiNet's version of MM */ cmd = "MM"; /*{ perhaps "MM READ"? }*/ } else if (!strncmpi(buf, "wpmail:", 7)) { /* WPmail: New mail from BAR. subject_text */ nam = "WPmail"; /* WordPerfect [sic] Office */ cmd = "OFFICE/MAIL"; } else if (!strncmpi(buf, "**m400 mail", 7)) { /* **M400 mail waiting** */ nam = "M400mail"; /* Messenger 400 [not seen] */ cmd = "M400"; } else { /* not recognized, but presumed to be mail */ nam = "unknown mail"; cmd = "SPAWN"; /* generic escape back to DCL */ txt = (char *) 0; /* don't rely on "from" info here */ } if (!txt) txt = strcat(strcpy(txt_buf, "Mail for you: "), buf); /* : end of mail recognition; now check for call-type interruptions... */ } else if ((q = strstri(buf, " phoning")) != 0) { /* BAR is phoning you [on FOO] \(HH:MM:SS\) */ typ = MSG_CALL; nam = "Phone call"; cmd = "PHONE ANSWER"; if (!strncmpi(q + 8, " you", 4)) q += (8 + 4), *q = '\0'; txt = strcat(strcpy(txt_buf, "Do you hear ringing? "), buf); } else if ((q = strstri(buf, " talk-daemon")) != 0 || (q = strstri(buf, " talk_daemon")) != 0) { /* Message from TALK-DAEMON@FOO at HH:MM:SS\n Connection request by BAR@SPAM\n \[Respond with: TALK[/OLD] BAR@SPAM\] */ typ = MSG_CALL; nam = "Talk request"; /* MultiNet's TALK and/or TALK/OLD */ cmd = "TALK"; if ((p = strstri(q, " by ")) != 0) { txt = strcat(strcpy(txt_buf, "Talk request from"), p + 3); if ((p = strstri(p, "respond with")) != 0) { if (*(p-1) == '[') *(p-1) = '\0'; else *p = '\0'; /* terminate */ p += (sizeof "respond with" - sizeof ""); if (*p == ':') p++; if (*p == ' ') p++; cmd = strcpy(cmd_buf, p); /* "TALK[/OLD] bar@spam" */ p = eos(cmd_buf); if (*--p == ']') *p = '\0'; } } else txt = strcat(strcpy(txt_buf, "Pardon the interruption: "), buf); } else if (is_jnet_send) { /* sscanf(,"(%[^)])%s -%c",,,)==3 */ jnet_send: /* \(SPAM\)BAR - arbitrary_message_text (from BAR@SPAM) */ typ = MSG_CALL; nam = "Bitnet noise"; /* RSCS/NJE message received via JNET */ Sprintf(cmd_buf, "XYZZY %s@%s", user, node); cmd = cmd_buf; /*{ perhaps just vanilla SEND instead of XYZZY? }*/ Sprintf(txt_buf, "Message from %s@%s:%s", user, node, &buf[1+strlen(node)+1+strlen(user)+2-1]); /* "(node)user -" */ txt = txt_buf; /* : end of call recognition; anything else is none-of-the-above... */ } else { other: # endif /* SHELL */ /* arbitrary broadcast: batch job completed, system shutdown imminent, &c */ typ = MSG_OTHER; nam = (char *) 0; /*"captured broadcast message"*/ cmd = (char *) 0; txt = strcat(strcpy(txt_buf, "Message for you: "), buf); # ifdef SHELL } /* Daemon in newmail() will append period when the text is displayed */ if ((p = eos(txt)) > txt && *--p == '.') *p = '\0'; /* newmail() and readmail() assume that nam and cmd are concatenated */ if (nam) { /* object name to attach to scroll of mail */ char *join = strcpy(nam_cmd_buf, nam); if (cmd) { /* append command to name; readmail() requires it */ int len = sizeof nam_cmd_buf - sizeof "" - (strlen(join) + 1); cmd_buf[len] = '\0'; /* possibly truncate */ (void) strcat(join, " "); cmd = strcpy(eos(join), cmd); } nam = join; } # endif /* SHELL */ /* truncate really long messages to prevent verbalize() from blowing up */ if (txt && strlen(txt) > BUFSZ - 50) txt[BUFSZ - 50] = '\0'; msg.message_typ = typ; /* simple index */ msg.display_txt = txt; /* text for daemon to pline() */ msg.object_nam = nam; /* 'name' for mail scroll */ msg.response_cmd = cmd; /* command to spawn when scroll read */ return &msg; } /* filter out non-printable characters and redundant noise */ static void filter_brdcst(buf) /* called by parse_next_broadcast() */ register char *buf; /* in: original text; out: filtered text */ { register char c, *p, *buf_p; /* filter the text; restrict consecutive spaces or dots to just two */ for (p = buf_p = buf; *buf_p; buf_p++) { c = *buf_p & '\177'; if (c == ' ' || c == '\t' || c == '\n') if (p == buf || /* ignore leading whitespace */ (p >= buf+2 && *(p-1) == ' ' && *(p-2) == ' ')) continue; else c = ' '; else if (c == '.' || c < ' ' || c == '\177') if (p == buf || /* skip leading beeps & such */ (p >= buf+2 && *(p-1) == '.' && *(p-2) == '.')) continue; else c = '.'; else if (c == '%' && /* trim %%% OPCOM verbosity %%% */ p >= buf+2 && *(p-1) == '%' && *(p-2) == '%') continue; *p++ = c; } *p = '\0'; /* terminate, then strip trailing junk */ while (p > buf && (*--p == ' ' || *p == '.')) *p = '\0'; return; } static char empty_string[] = ""; /* fetch the text of a captured broadcast, then mangle and decipher it */ struct mail_info * parse_next_broadcast() /* called by ckmailstatus(mail.c) */ { short length, msg_type; $DESCRIPTOR(message, empty_string); /* string descriptor for buf[] */ struct mail_info *result = 0; /* messages could actually be longer; let long ones be truncated */ char buf[255+1]; message.dsc$a_pointer = buf, message.dsc$w_length = sizeof buf - 1; msg_type = length = 0; smg$get_broadcast_message(&pasteboard_id, &message, &length, &msg_type); if (msg_type == MSG$_TRMBRDCST) { buf[length] = '\0'; filter_brdcst(buf); /* mask non-printable characters */ result = parse_brdcst(buf); /* do the real work */ } else if (msg_type == MSG$_TRMHANGUP) { (void) gsignal(SIGHUP); } return result; } /* spit out any pending broadcast messages whenever we leave */ static void flush_broadcasts() /* called from disable_broadcast_trapping() */ { if (broadcasts > 0) { short len, typ; $DESCRIPTOR(msg_dsc, empty_string); char buf[512+1]; msg_dsc.dsc$a_pointer = buf, msg_dsc.dsc$w_length = sizeof buf - 1; raw_print(""); /* print at least one line for wait_synch() */ do { typ = len = 0; smg$get_broadcast_message(&pasteboard_id, &msg_dsc, &len, &typ); if (typ == MSG$_TRMBRDCST) buf[len] = '\0', raw_print(buf); } while (--broadcasts); wait_synch(); /* prompt with "Hit return to continue: " */ } } /* AST routine called when the terminal's associated mailbox receives a message */ /*ARGSUSED*/ static void broadcast_ast(dummy) /* called asynchronously by terminal driver */ int dummy; /* not used */ { broadcasts++; } /* initialize the broadcast manipulation code; SMG makes this easy */ unsigned long init_broadcast_trapping() /* called by setftty() [once only] */ { unsigned long sts, preserve_screen_flag = 1; /* we need a pasteboard to pass to the broadcast setup/teardown routines */ sts = smg$create_pasteboard(&pasteboard_id, 0, 0, 0, &preserve_screen_flag); if (!vms_ok(sts)) { errno = EVMSERR, vaxc$errno = sts; raw_print(""); perror("?can't create SMG pasteboard for broadcast trapping"); wait_synch(); broadcasts = -1; /* flag that trapping is currently broken */ } return sts; } /* set up the terminal driver to deliver $brkthru data to a mailbox device */ unsigned long enable_broadcast_trapping() /* called by setftty() */ { unsigned long sts = 1; if (broadcasts >= 0) { /* (-1 => no pasteboard, so don't even try) */ /* register callback routine to be triggered when broadcasts arrive */ /* Note side effect: also intercepts hangup notification. */ /* Another note: TMPMBX privilege is required. */ sts = smg$set_broadcast_trapping(&pasteboard_id, broadcast_ast, 0); if (!vms_ok(sts)) { errno = EVMSERR, vaxc$errno = sts; raw_print(""); perror("?can't enable broadcast trapping"); wait_synch(); } } return sts; } /* return to 'normal'; $brkthru data goes straight to the terminal */ unsigned long disable_broadcast_trapping() /* called by settty() */ { unsigned long sts = 1; if (broadcasts >= 0) { /* disable trapping; releases associated MBX so that SPAWN can work */ sts = smg$disable_broadcast_trapping(&pasteboard_id); if (!vms_ok(sts)) errno = EVMSERR, vaxc$errno = sts; flush_broadcasts(); /* don't hold on to any buffered ones */ } return sts; } #else /* MAIL */ /* simple stubs for non-mail configuration */ unsigned long init_broadcast_trapping() { return 1; } unsigned long enable_broadcast_trapping() { return 1; } unsigned long disable_broadcast_trapping() { return 1; } struct mail_info *parse_next_broadcast() { return 0; } #endif /* MAIL */ /*----------------------------------------------------------------------*/ #ifdef TEST_DRIVER /* (Take parse_next_broadcast for a spin. :-) */ volatile int broadcasts = 0; void newmail(foo) struct mail_info *foo; { # define STRING(s) ((s) ? (s) : "") printf("\n\ message type = %d\n\ display text = \"%s\"\n\ object name = \"%.*s\"\n\ response cmd = \"%s\"\n\ ", foo->message_typ, STRING(foo->display_txt), (foo->object_nam && foo->response_cmd) ? (foo->response_cmd - foo->object_nam - 1) : strlen(STRING(foo->object_nam)), STRING(foo->object_nam), STRING(foo->response_cmd)); # undef STRING } void ckmailstatus() { struct mail_info *brdcst, *parse_next_broadcast(); while (broadcasts > 0) { /* process all trapped broadcasts [until] */ broadcasts--; if ((brdcst = parse_next_broadcast()) != 0) { newmail(brdcst); break; /* only handle one real message at a time */ } else printf("\n--< non-broadcast encountered >--\n"); } } int main() { char dummy[BUFSIZ]; init_broadcast_trapping(); enable_broadcast_trapping(); for (;;) { ckmailstatus(); printf("> "), fflush(stdout); /* issue a prompt */ if (!gets(dummy)) break; /* wait for a response */ } disable_broadcast_trapping(); return 1; } void panic(s) char *s; { raw_print(s); exit(EXIT_FAILURE); } void raw_print(s) char *s; { puts(s); fflush(stdout); } void wait_synch() { char dummy[BUFSIZ]; printf("\nPress to continue: "); fflush(stdout); (void) gets(dummy); } #endif /* TEST_DRIVER */ /*vmsmail.c*/ nethack-3.4.3/sys/vms/vmsmain.c0100644000000000000000000002463507764735041015125 0ustar rootroot/* SCCS Id: @(#)vmsmain.c 3.4 2003/10/16 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* main.c - VMS NetHack */ #include "hack.h" #include "dlb.h" #include static void NDECL(whoami); static void FDECL(process_options, (int, char **)); static void NDECL(byebye); #ifndef SAVE_ON_FATAL_ERROR # ifndef __DECC # define vms_handler_type int # else # define vms_handler_type unsigned int # endif extern void FDECL(VAXC$ESTABLISH, (vms_handler_type (*)(genericptr_t,genericptr_t))); static vms_handler_type FDECL(vms_handler, (genericptr_t,genericptr_t)); #include /* system service status codes */ #endif static void NDECL(wd_message); #ifdef WIZARD static boolean wiz_error_flag = FALSE; #endif int main(argc,argv) int argc; char *argv[]; { register int fd; #ifdef CHDIR register char *dir; #endif #ifdef SECURE /* this should be the very first code executed */ privoff(); fflush((FILE *)0); /* force stdio to init itself */ privon(); #endif atexit(byebye); hname = argv[0]; hname = vms_basename(hname); /* name used in 'usage' type messages */ hackpid = getpid(); (void) umask(0); choose_windows(DEFAULT_WINDOW_SYS); #ifdef CHDIR /* otherwise no chdir() */ /* * See if we must change directory to the playground. * (Perhaps hack is installed with privs and playground is * inaccessible for the player.) * The logical name HACKDIR is overridden by a * -d command line option (must be the first option given) */ dir = nh_getenv("NETHACKDIR"); if (!dir) dir = nh_getenv("HACKDIR"); #endif if(argc > 1) { #ifdef CHDIR if (!strncmp(argv[1], "-d", 2) && argv[1][2] != 'e') { /* avoid matching "-dec" for DECgraphics; since the man page * says -d directory, hope nobody's using -desomething_else */ argc--; argv++; dir = argv[0]+2; if(*dir == '=' || *dir == ':') dir++; if(!*dir && argc > 1) { argc--; argv++; dir = argv[0]; } if(!*dir) error("Flag -d must be followed by a directory name."); } if (argc > 1) #endif /* CHDIR */ /* * Now we know the directory containing 'record' and * may do a prscore(). */ if (!strncmp(argv[1], "-s", 2)) { #ifdef CHDIR chdirx(dir, FALSE); #endif prscore(argc, argv); exit(EXIT_SUCCESS); } } #ifdef CHDIR /* move to the playground directory; 'termcap' might be found there */ chdirx(dir, TRUE); #endif #ifdef SECURE /* disable installed privs while loading nethack.cnf and termcap, and also while initializing terminal [$assign("TT:")]. */ privoff(); #endif initoptions(); init_nhwindows(&argc, argv); whoami(); #ifdef SECURE privon(); #endif /* * It seems you really want to play. */ u.uhp = 1; /* prevent RIP on early quits */ #ifndef SAVE_ON_FATAL_ERROR /* used to clear hangup stuff while still giving standard traceback */ VAXC$ESTABLISH(vms_handler); #endif (void) signal(SIGHUP, (SIG_RET_TYPE) hangup); process_options(argc, argv); /* command line options */ #ifdef WIZARD if (wizard) Strcpy(plname, "wizard"); else #endif if (!*plname || !strncmpi(plname, "games", 4) || !strcmpi(plname, "nethack")) askname(); plnamesuffix(); /* strip suffix from name; calls askname() */ /* again if suffix was whole name */ /* accepts any suffix */ #ifdef WIZARD if(!wizard) { #endif /* * check for multiple games under the same name * (if !locknum) or check max nr of players (otherwise) */ (void) signal(SIGQUIT,SIG_IGN); (void) signal(SIGINT,SIG_IGN); if(!locknum) Sprintf(lock, "_%u%s", (unsigned)getuid(), plname); getlock(); #ifdef WIZARD } else { Sprintf(lock, "_%u%s", (unsigned)getuid(), plname); getlock(); } #endif /* WIZARD */ dlb_init(); /* must be before newgame() */ /* * Initialization of the boundaries of the mazes * Both boundaries have to be even. */ x_maze_max = COLNO-1; if (x_maze_max % 2) x_maze_max--; y_maze_max = ROWNO-1; if (y_maze_max % 2) y_maze_max--; /* * Initialize the vision system. This must be before mklev() on a * new game or before a level restore on a saved game. */ vision_init(); display_gamewindows(); if ((fd = restore_saved_game()) >= 0) { #ifdef WIZARD /* Since wizard is actually flags.debug, restoring might * overwrite it. */ boolean remember_wiz_mode = wizard; #endif const char *fq_save = fqname(SAVEF, SAVEPREFIX, 1); (void) chmod(fq_save,0); /* disallow parallel restores */ (void) signal(SIGINT, (SIG_RET_TYPE) done1); #ifdef NEWS if(iflags.news) { display_file(NEWS, FALSE); iflags.news = FALSE; /* in case dorecover() fails */ } #endif pline("Restoring save file..."); mark_synch(); /* flush output */ if(!dorecover(fd)) goto not_recovered; #ifdef WIZARD if(!wizard && remember_wiz_mode) wizard = TRUE; #endif check_special_room(FALSE); wd_message(); if (discover || wizard) { if (yn("Do you want to keep the save file?") == 'n') (void) delete_savefile(); else (void) chmod(fq_save,FCMASK); /* back to readable */ } flags.move = 0; } else { not_recovered: player_selection(); newgame(); wd_message(); flags.move = 0; set_wear(); (void) pickup(1); } moveloop(); exit(EXIT_SUCCESS); /*NOTREACHED*/ return(0); } static void process_options(argc, argv) int argc; char *argv[]; { int i; /* * Process options. */ while(argc > 1 && argv[1][0] == '-'){ argv++; argc--; switch(argv[0][1]){ case 'D': #ifdef WIZARD if(!strcmpi(nh_getenv("USER"), WIZARD_NAME)) { wizard = TRUE; break; } /* otherwise fall thru to discover */ wiz_error_flag = TRUE; #endif /* WIZARD */ case 'X': case 'x': discover = TRUE; break; #ifdef NEWS case 'n': iflags.news = FALSE; break; #endif case 'u': if(argv[0][2]) (void) strncpy(plname, argv[0]+2, sizeof(plname)-1); else if(argc > 1) { argc--; argv++; (void) strncpy(plname, argv[0], sizeof(plname)-1); } else raw_print("Player name expected after -u"); break; case 'I': case 'i': if (!strncmpi(argv[0]+1, "IBM", 3)) switch_graphics(IBM_GRAPHICS); break; /* case 'D': */ case 'd': if (!strncmpi(argv[0]+1, "DEC", 3)) switch_graphics(DEC_GRAPHICS); break; case 'p': /* profession (role) */ if (argv[0][2]) { if ((i = str2role(&argv[0][2])) >= 0) flags.initrole = i; } else if (argc > 1) { argc--; argv++; if ((i = str2role(argv[0])) >= 0) flags.initrole = i; } break; case 'r': /* race */ if (argv[0][2]) { if ((i = str2race(&argv[0][2])) >= 0) flags.initrace = i; } else if (argc > 1) { argc--; argv++; if ((i = str2race(argv[0])) >= 0) flags.initrace = i; } break; case '@': flags.randomall = 1; break; default: if ((i = str2role(&argv[0][1])) >= 0) { flags.initrole = i; break; } /* else raw_printf("Unknown option: %s", *argv); */ } } if(argc > 1) locknum = atoi(argv[1]); #ifdef MAX_NR_OF_PLAYERS if(!locknum || locknum > MAX_NR_OF_PLAYERS) locknum = MAX_NR_OF_PLAYERS; #endif } #ifdef CHDIR void chdirx(dir, wr) const char *dir; boolean wr; { # ifndef HACKDIR static const char *defdir = "."; # else static const char *defdir = HACKDIR; if(dir == (const char *)0) dir = defdir; else if (wr && !same_dir(HACKDIR, dir)) /* If we're playing anywhere other than HACKDIR, turn off any privs we may have been installed with. */ privoff(); # endif if(dir && chdir(dir) < 0) { perror(dir); error("Cannot chdir to %s.", dir); } /* warn the player if we can't write the record file */ if (wr) check_recordfile(dir); defdir = dir; } #endif /* CHDIR */ static void whoami() { /* * Who am i? Algorithm: 1. Use name as specified in NETHACKOPTIONS * 2. Use lowercase of $USER (if 1. fails) * The resulting name is overridden by command line options. * If everything fails, or if the resulting name is some generic * account like "games" then eventually we'll ask him. * Note that we trust the user here; it is possible to play under * somebody else's name. */ register char *s; if (!*plname && (s = nh_getenv("USER"))) (void) lcase(strncpy(plname, s, sizeof(plname)-1)); } static void byebye() { /* Different versions of both VAX C and GNU C use different return types for signal functions. Return type 'int' along with the explicit casts below satisfy the most combinations of compiler vs . */ int (*hup)(); #ifdef SHELL extern unsigned long dosh_pid, mail_pid; extern unsigned long FDECL(sys$delprc,(unsigned long *,const genericptr_t)); /* clean up any subprocess we've spawned that may still be hanging around */ if (dosh_pid) (void) sys$delprc(&dosh_pid, 0), dosh_pid = 0; if (mail_pid) (void) sys$delprc(&mail_pid, 0), mail_pid = 0; #endif /* SIGHUP doesn't seem to do anything on VMS, so we fudge it here... */ hup = (int(*)()) signal(SIGHUP, SIG_IGN); if (!program_state.exiting++ && hup != (int(*)()) SIG_DFL && hup != (int(*)()) SIG_IGN) (void) (*hup)(); #ifdef CHDIR (void) chdir(getenv("PATH")); #endif } #ifndef SAVE_ON_FATAL_ERROR /* Condition handler to prevent byebye's hangup simulation from saving the game after a fatal error has occurred. */ /*ARGSUSED*/ static vms_handler_type /* should be `unsigned long', but the -*/ vms_handler(sigargs, mechargs) /*+ prototype in is screwed */ genericptr_t sigargs, mechargs; /* [0] is argc, [1..argc] are the real args */ { unsigned long condition = ((unsigned long *)sigargs)[1]; if (condition == SS$_ACCVIO /* access violation */ || (condition >= SS$_ASTFLT && condition <= SS$_TBIT) || (condition >= SS$_ARTRES && condition <= SS$_INHCHME)) { program_state.done_hup = TRUE; /* pretend hangup has been attempted */ # if defined(WIZARD) && !defined(BETA) if (wizard) # endif /*WIZARD && !BETA*/ # if defined(WIZARD) || defined(BETA) abort(); /* enter the debugger */ # endif /*WIZARD || BETA*/ } return SS$_RESIGNAL; } #endif #ifdef PORT_HELP void port_help() { /* * Display VMS-specific help. Just show contents of the helpfile * named by PORT_HELP. */ display_file(PORT_HELP, TRUE); } #endif /* PORT_HELP */ static void wd_message() { #ifdef WIZARD if (wiz_error_flag) { pline("Only user \"%s\" may access debug (wizard) mode.", WIZARD_NAME); pline("Entering discovery mode instead."); } else #endif if (discover) You("are in non-scoring discovery mode."); } /*vmsmain.c*/ nethack-3.4.3/sys/vms/vmsmisc.c0100644000000000000000000000100507764735041015116 0ustar rootroot/* SCCS Id: @(#)vmsmisc.c 3.4 1996/03/02 */ /* NetHack may be freely redistributed. See license for details. */ #include #include void vms_exit( /*_ int _*/ ); void vms_abort( /*_ void _*/ ); extern void exit( /*_ int _*/ ); extern void lib$signal( /*_ unsigned long,... _*/ ); void vms_exit(status) int status; { exit(status ? (SS$_ABORT | STS$M_INHIB_MSG) : SS$_NORMAL); } void vms_abort() { lib$signal(SS$_DEBUG); } #ifdef VERYOLD_VMS #include "oldcrtl.c" #endif /*vmsmisc.c*/ nethack-3.4.3/sys/vms/vmstty.c0100644000000000000000000003652307764735041015020 0ustar rootroot/* SCCS Id: @(#)vmstty.c 3.4 2003/09/18 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* tty.c - (VMS) version */ #define NEED_VARARGS #include "hack.h" #include "wintty.h" #include "tcap.h" #include #include #ifndef __GNUC__ #include #include #include #else /* values needed from missing include files */ # define SMG$K_TRM_UP 274 # define SMG$K_TRM_DOWN 275 # define SMG$K_TRM_LEFT 276 # define SMG$K_TRM_RIGHT 277 # define TT$M_MECHTAB 0x00000100 /* hardware tab support */ # define TT$M_MECHFORM 0x00080000 /* hardware form-feed support */ # define TT$M_NOBRDCST 0x00020000 /* disable broadcast messages, but */ # define TT2$M_BRDCSTMBX 0x00000010 /* catch them in associated mailbox */ # define TT2$M_APP_KEYPAD 0x00800000 /* application vs numeric keypad mode */ #endif /* __GNUC__ */ #ifdef USE_QIO_INPUT #include #endif #include #include unsigned long lib$disable_ctrl(), lib$enable_ctrl(); unsigned long sys$assign(), sys$dassgn(), sys$qiow(); #ifndef USE_QIO_INPUT unsigned long smg$create_virtual_keyboard(), smg$delete_virtual_keyboard(), smg$read_keystroke(), smg$cancel_input(); #else static short FDECL(parse_function_key, (int)); #endif static void NDECL(setctty); static void NDECL(resettty); #define vms_ok(sts) ((sts)&1) #define META(c) ((c)|0x80) /* 8th bit */ #define CTRL(c) ((c)&0x1F) #define CMASK(c) (1< 0) { /* we have buffered character(s) from previous read */ kb_buf = *inp++; --inc; sts = SS$_NORMAL; } else { sts = sys$qiow(0, tt_chan, QIO_FUNC, &iosb, (void(*)())0, 0, &kb_buf, sizeof kb_buf, 0, 0, 0, 0); } if (vms_ok(sts)) { if (kb_buf == CTRL('C')) { if (intr_char) gsignal(SIGINT); key = (short)kb_buf; } else if (kb_buf == '\r') { /* */ key = (short)'\n'; } else if (kb_buf == ESC || kb_buf == CSI || kb_buf == SS3) { switch(parse_function_key((int)kb_buf)) { case SMG$K_TRM_UP: key = iflags.num_pad ? '8' : 'k'; break; case SMG$K_TRM_DOWN: key = iflags.num_pad ? '2' : 'j'; break; case SMG$K_TRM_LEFT: key = iflags.num_pad ? '4' : 'h'; break; case SMG$K_TRM_RIGHT: key = iflags.num_pad ? '6' : 'l'; break; default: key = ESC; break; } } else { key = (short)kb_buf; } } else if (sts == SS$_HANGUP || iosb.status == SS$_HANGUP || sts == SS$_DEVOFFLINE) { gsignal(SIGHUP); key = ESC; } else /*(this should never happen)*/ key = getchar(); #else /*!USE_QIO_INPUT*/ if (recurse++ == 0 && kb != 0) { smg$read_keystroke(&kb, &key); switch (key) { case SMG$K_TRM_UP: iflags.num_pad ? '8' : key = 'k'; break; case SMG$K_TRM_DOWN: iflags.num_pad ? '2' : key = 'j'; break; case SMG$K_TRM_LEFT: iflags.num_pad ? '4' : key = 'h'; break; case SMG$K_TRM_RIGHT: iflags.num_pad ? '6' : key = 'l'; break; case '\r': key = '\n'; break; default: if (key > 255) key = ESC; break; } } else { /* abnormal input--either SMG didn't initialize properly or vms_getchar() has been called recursively (via SIGINT handler). */ if (kb != 0) /* must have been a recursive call */ smg$cancel_input(&kb); /* from an interrupt handler */ key = getchar(); } --recurse; #endif /* USE_QIO_INPUT */ return (int)key; } #ifdef USE_QIO_INPUT /* * We've just gotten an character. Do a timed read to * get any other characters, then try to parse them as an escape * sequence. This isn't perfect, since there's no guarantee * that a full escape sequence will be available, or even if one * is, it might actually by regular input from a fast typist or * a stalled input connection. {For packetized environments, * cross plural(body_part(FINGER)) and hope for best. :-} * * This is needed to preserve compatability with SMG interface * for two reasons: * 1) retain support for arrow keys, and * 2) treat other VTxxx function keys as for aborting * various NetHack prompts. * The second reason is compelling; otherwise remaining chars of * an escape sequence get treated as inappropriate user commands. * * SMG code values for these key sequences fall in the range of * 256 thru 3xx. The assignments are not particularly intuitive. */ /*= -- Summary of VTxxx-style keyboards and transmitted escape sequences. -- Keypad codes are prefixed by 7 bit (\033 O) or 8 bit SS3: keypad: PF1 PF2 PF3 PF4 codes: P Q R S 7 8 9 - w x y m 4 5 6 . t u v n 1 2 3 :en-: q r s : : ...0... , :ter: ...p... l :M: Arrows are prefixed by either SS3 or CSI (either 7 or 8 bit), depending on whether the terminal is in application or numeric mode (ditto for PF keys): arrows: A B D C Additional function keys (vk201/vk401) generate CSI nn ~ (nn is 1 or 2 digits): vk201 keys: F6 F7 F8 F9 F10 F11 F12 F13 F14 Help Do F17 F18 F19 F20 'nn' digits: 17 18 19 20 21 23 24 25 26 28 29 31 32 33 34 alternate: ^C ^[ ^H ^J (when in VT100 mode) edit keypad: digits: 1 2 3 4 5 6 VT52 mode: arrows and PF keys send ESCx where x is in A-D or P-S. =*/ static const char *arrow_or_PF = "ABCDPQRS", /* suffix char */ *smg_keypad_codes = "PQRSpqrstuvwxyMmlnABDC"; /* PF1..PF4,KP0..KP9,enter,dash,comma,dot,up-arrow,down,left,right */ /* Ultimate return value is (index into smg_keypad_codes[] + 256). */ static short parse_function_key(c) register int c; { struct _rd_iosb iosb; unsigned long sts; char seq_buf[15+1]; /* plenty room for escape sequence + slop */ short result = ESC; /* translate to by default */ /* * Read whatever we can from type-ahead buffer (1 second timeout). * If the user typed an actual to deliberately abort * something, he or she should be able to tolerate the necessary * restriction of a negligible pause before typing anything else. * We might already have [at least some of] an escape sequence from a * previous read, particularly if user holds down the arrow keys... */ if (inc > 0) strncpy(seq_buf, inp, inc); if (inc < (int)(sizeof seq_buf) - 1) { sts = sys$qiow(0, tt_chan, QIO_FUNC|IO$M_TIMED, &iosb, (void(*)())0, 0, seq_buf + inc, sizeof seq_buf - 1 - inc, 1, 0, 0, 0); if (vms_ok(sts)) sts = iosb.status; } else sts = SS$_NORMAL; if (vms_ok(sts) || sts == SS$_TIMEOUT) { register int cnt = iosb.trm_offset + iosb.trm_siz + inc; register char *p = seq_buf; if (c == ESC) /* check for 7-bit vt100/ANSI, or vt52 */ if (*p == '[' || *p == 'O') c = META(CTRL(*p++)), cnt--; else if (strchr(arrow_or_PF, *p)) c = SS3; /*CSI*/ if (cnt > 0 && (c == SS3 || (c == CSI && strchr(arrow_or_PF, *p)))) { register char *q = strchr(smg_keypad_codes, *p); if (q) result = 256 + (q - smg_keypad_codes); p++, --cnt; /* one more char consumed */ } else if (cnt > 1 && c == CSI) { static short /* "CSI nn ~" -> F_keys[nn] */ F_keys[35] = { ESC, /*(filler)*/ 311, 312, 313, 314, 315, 316, /* E1-E6 */ ESC, ESC, ESC, ESC, /*(more filler)*/ 281, 282, 283, 284, 285, ESC, /* F1-F5 */ 286, 287, 288, 289, 290, ESC, /* F6-F10*/ 291, 292, 293, 294, ESC, /*F11-F14*/ 295, 296, ESC, /*,, aka F15,F16*/ 297, 298, 299, 300 /*F17-F20*/ }; /* note: there are several missing nn in CSI nn ~ values */ int nn; char *q; *(p + cnt) = '\0'; /* terminate string */ q = strchr(p, '~'); if (q && sscanf(p, "%d~", &nn) == 1) { if (nn > 0 && nn < SIZE(F_keys)) result = F_keys[nn]; cnt -= (++q - p); p = q; } } if (cnt > 0) strncpy((inp = inputbuf), p, (inc = cnt)); else inc = 0, inp = 0; } return result; } #endif /* USE_QIO_INPUT */ static void setctty() { struct _sm_iosb iosb; unsigned long status; status = sys$qiow(0, tt_chan, IO$_SETMODE, &iosb, (void(*)())0, 0, &sg.sm, sizeof sg.sm, 0, 0, 0, 0); if (vms_ok(status)) status = iosb.status; if (vms_ok(status)) { /* try to force terminal into synch with TTDRIVER's setting */ number_pad((sg.sm.tt2_char & TT2$M_APP_KEYPAD) ? -1 : 1); } else { raw_print(""); errno = EVMSERR, vaxc$errno = status; perror("NetHack(setctty: setmode)"); wait_synch(); } } static void resettty() /* atexit() routine */ { if (settty_needed) { bombing = TRUE; /* don't clear screen; preserve traceback info */ settty((char *)0); } (void) sys$dassgn(tt_chan), tt_chan = 0; } /* * Get initial state of terminal, set ospeed (for termcap routines) * and switch off tab expansion if necessary. * Called by init_nhwindows() and resume_nhwindows() in wintty.c * (for initial startup and for returning from '!' or ^Z). */ void gettty() { static char dev_tty[] = "TT:"; static $DESCRIPTOR(tty_dsc, dev_tty); int err = 0; unsigned long status, zero = 0; if (tt_chan == 0) { /* do this stuff once only */ iflags.cbreak = OFF, iflags.echo = ON; /* until setup is complete */ status = sys$assign(&tty_dsc, &tt_chan, 0, 0); if (!vms_ok(status)) { raw_print(""), err++; errno = EVMSERR, vaxc$errno = status; perror("NetHack(gettty: $assign)"); } atexit(resettty); /* register an exit handler to reset things */ } status = sys$qiow(0, tt_chan, IO$_SENSEMODE, &sg.io, (void(*)())0, 0, &sg.sm, sizeof sg.sm, 0, 0, 0, 0); if (vms_ok(status)) status = sg.io.status; if (!vms_ok(status)) { raw_print(""), err++; errno = EVMSERR, vaxc$errno = status; perror("NetHack(gettty: sensemode)"); } ospeed = sg.io.xmt_speed; erase_char = '\177'; /* , aka */ kill_char = CTRL('U'); intr_char = CTRL('C'); (void) lib$enable_ctrl(&zero, &ctrl_mask); /* Use the systems's values for lines and columns if it has any idea. */ if (sg.sm.page_length) LI = sg.sm.page_length; if (sg.sm.page_width) CO = sg.sm.page_width; /* suppress tab and form-feed expansion, in case termcap uses them */ tt_char_restore = sg.sm.tt_char; tt_char_active = sg.sm.tt_char |= TT_SPECIAL_HANDLING; tt2_char_restore = sg.sm.tt2_char; tt2_char_active = sg.sm.tt2_char |= TT2_SPECIAL_HANDLING; #if 0 /*[ defer until setftty() ]*/ setctty(); #endif if (err) wait_synch(); } /* reset terminal to original state */ void settty(s) const char *s; { if (!bombing) end_screen(); if (s) raw_print(s); disable_broadcast_trapping(); #if 0 /* let SMG's exit handler do the cleanup (as per doc) */ /* #ifndef USE_QIO_INPUT */ if (kb) smg$delete_virtual_keyboard(&kb), kb = 0; #endif /* 0 (!USE_QIO_INPUT) */ if (ctrl_mask) (void) lib$enable_ctrl(&ctrl_mask, 0); iflags.echo = ON; iflags.cbreak = OFF; /* reset original tab, form-feed, broadcast settings */ sg.sm.tt_char = tt_char_restore; sg.sm.tt2_char = tt2_char_restore; setctty(); settty_needed = FALSE; } /* same as settty, with no clearing of the screen */ void shuttty(s) const char *s; { bombing = TRUE; settty(s); bombing = FALSE; } void setftty() { unsigned long mask = LIB$M_CLI_CTRLT | LIB$M_CLI_CTRLY; (void) lib$disable_ctrl(&mask, 0); if (kb == 0) { /* do this stuff once only */ #ifdef USE_QIO_INPUT kb = tt_chan; #else /*!USE_QIO_INPUT*/ smg$create_virtual_keyboard(&kb); #endif /*USE_QIO_INPUT*/ init_broadcast_trapping(); } enable_broadcast_trapping(); /* no-op if !defined(MAIL) */ iflags.cbreak = (kb != 0) ? ON : OFF; iflags.echo = (kb != 0) ? OFF : ON; /* disable tab & form-feed expansion; prepare for broadcast trapping */ sg.sm.tt_char = tt_char_active; sg.sm.tt2_char = tt2_char_active; setctty(); start_screen(); settty_needed = TRUE; } void intron() /* enable kbd interupts if enabled when game started */ { intr_char = CTRL('C'); } void introff() /* disable kbd interrupts if required*/ { intr_char = 0; } #ifdef TIMED_DELAY extern unsigned long FDECL(lib$emul, (const long *,const long *,const long *,long *)); extern unsigned long sys$schdwk(), sys$hiber(); #define VMS_UNITS_PER_SECOND 10000000L /* hundreds of nanoseconds, 1e-7 */ /* constant for conversion from milliseconds to VMS delta time (negative) */ static const long mseconds_to_delta = VMS_UNITS_PER_SECOND / 1000L * -1L; /* sleep for specified number of milliseconds (note: the timer used generally only has 10-millisecond resolution at the hardware level...) */ void msleep(mseconds) unsigned mseconds; /* milliseconds */ { long pid = 0L, zero = 0L, msec, qtime[2]; msec = (long) mseconds; if (msec > 0 && /* qtime{0:63} = msec{0:31} * mseconds_to_delta{0:31} + zero{0:31} */ vms_ok(lib$emul(&msec, &mseconds_to_delta, &zero, qtime))) { /* schedule a wake-up call, then go to sleep */ if (vms_ok(sys$schdwk(&pid, (genericptr_t)0, qtime, (long *)0))) (void)sys$hiber(); } } #endif /* TIMED_DELAY */ /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *,s) VA_START(s); VA_INIT(s, const char *); if(settty_needed) settty((char *)0); Vprintf(s,VA_ARGS); (void) putchar('\n'); VA_END(); #ifndef SAVE_ON_FATAL_ERROR /* prevent vmsmain's exit handler byebye() from calling hangup() */ (void)signal(SIGHUP, SIG_DFL); #endif exit(EXIT_FAILURE); } nethack-3.4.3/sys/vms/vmsunix.c0100644000000000000000000003203707764735041015157 0ustar rootroot/* SCCS Id: @(#)vmsunix.c 3.4 2001/07/27 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* This file implements things from unixunix.c, plus related stuff */ #include "hack.h" #include #include #include #include #include #include #undef off_t #ifdef GNUC #include #else # define umask hide_umask_dummy /* DEC C: avoid conflict with system.h */ #include # undef umask #endif #include extern unsigned long sys$setprv(); extern unsigned long lib$getdvi(), lib$getjpi(), lib$spawn(), lib$attach(); extern unsigned long smg$init_term_table_by_type(), smg$del_term_table(); #define vms_ok(sts) ((sts) & 1) /* odd => success */ static int FDECL(veryold, (int)); static char *NDECL(verify_term); #if defined(SHELL) || defined(SUSPEND) static void FDECL(hack_escape, (BOOLEAN_P,const char *)); static void FDECL(hack_resume, (BOOLEAN_P)); #endif static int veryold(fd) int fd; { register int i; time_t date; struct stat buf; if(fstat(fd, &buf)) return(0); /* cannot get status */ #ifndef INSURANCE if(buf.st_size != sizeof(int)) return(0); /* not an xlock file */ #endif (void) time(&date); if(date - buf.st_mtime < 3L*24L*60L*60L) { /* recent */ int lockedpid; /* should be the same size as hackpid */ unsigned long status, dummy, code = JPI$_PID; if (read(fd, (genericptr_t)&lockedpid, sizeof(lockedpid)) != sizeof(lockedpid)) /* strange ... */ return 0; status = lib$getjpi(&code, &lockedpid, 0, &dummy); if (vms_ok(status) || status != SS$_NONEXPR) return 0; } (void) close(fd); /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up */ for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) { /* try to remove all */ set_levelfile_name(lock, i); (void) delete(lock); } set_levelfile_name(lock, 0); if(delete(lock)) return(0); /* cannot remove it */ return(1); /* success! */ } void getlock() { register int i = 0, fd; /* idea from rpick%ucqais@uccba.uc.edu * prevent automated rerolling of characters * test input (fd0) so that tee'ing output to get a screen dump still * works * also incidentally prevents development of any hack-o-matic programs */ if (isatty(0) <= 0) error("You must play from a terminal."); /* we ignore QUIT and INT at this point */ if (!lock_file(HLOCK, LOCKPREFIX, 10)) { wait_synch(); error("Quitting."); } regularize(lock); set_levelfile_name(lock, 0); if(locknum > 25) locknum = 25; do { if(locknum) lock[0] = 'a' + i++; if((fd = open(lock, 0, 0)) == -1) { if(errno == ENOENT) goto gotlock; /* no such file */ perror(lock); unlock_file(HLOCK); error("Cannot open %s", lock); } if(veryold(fd)) /* if true, this closes fd and unlinks lock */ goto gotlock; (void) close(fd); } while(i < locknum); unlock_file(HLOCK); error(locknum ? "Too many hacks running now." : "There is a game in progress under your name."); gotlock: fd = creat(lock, FCMASK); unlock_file(HLOCK); if(fd == -1) { error("cannot creat lock file."); } else { if(write(fd, (char *) &hackpid, sizeof(hackpid)) != sizeof(hackpid)){ error("cannot write lock"); } if(close(fd) == -1) { error("cannot close lock"); } } } void regularize(s) /* normalize file name */ register char *s; { register char *lp; for (lp = s; *lp; lp++) /* note: '-' becomes '_' */ if (!(isalpha(*lp) || isdigit(*lp) || *lp == '$')) *lp = '_'; } #undef getuid int vms_getuid() { return (getgid() << 16) | getuid(); } #ifndef FAB$C_STMLF #define FAB$C_STMLF 5 #endif /* check whether the open file specified by `fd' is in stream-lf format */ boolean file_is_stmlf(fd) int fd; { int rfm; struct stat buf; if (fstat(fd, &buf)) return FALSE; /* cannot get status? */ #ifdef stat_alignment_fix /* gcc-vms alignment kludge */ rfm = stat_alignment_fix(&buf)->st_fab_rfm; #else rfm = buf.st_fab_rfm; #endif return rfm == FAB$C_STMLF; } /*------*/ #ifndef LNM$_STRING #include /* logical name definitions */ #endif #define ENVSIZ LNM$C_NAMLENGTH /*255*/ #define ENV_USR 0 /* user-mode */ #define ENV_SUP 1 /* supervisor-mode */ #define ENV_JOB 2 /* job-wide entry */ /* vms_define() - assign a value to a logical name */ int vms_define(name, value, flag) const char *name; const char *value; int flag; { struct dsc { unsigned short len, mbz; const char *adr; }; /* descriptor */ struct itm3 { short buflen, itmcode; const char *bufadr; short *retlen; }; static struct itm3 itm_lst[] = { {0,LNM$_STRING,0,0}, {0,0} }; struct dsc nam_dsc, val_dsc, tbl_dsc; unsigned long result, sys$crelnm(), lib$set_logical(); /* set up string descriptors */ nam_dsc.mbz = val_dsc.mbz = tbl_dsc.mbz = 0; nam_dsc.len = strlen( nam_dsc.adr = name ); val_dsc.len = strlen( val_dsc.adr = value ); tbl_dsc.len = strlen( tbl_dsc.adr = "LNM$PROCESS" ); switch (flag) { case ENV_JOB: /* job logical name */ tbl_dsc.len = strlen( tbl_dsc.adr = "LNM$JOB" ); /*FALLTHRU*/ case ENV_SUP: /* supervisor-mode process logical name */ result = lib$set_logical(&nam_dsc, &val_dsc, &tbl_dsc); break; case ENV_USR: /* user-mode process logical name */ itm_lst[0].buflen = val_dsc.len; itm_lst[0].bufadr = val_dsc.adr; result = sys$crelnm(0, &tbl_dsc, &nam_dsc, 0, itm_lst); break; default: /*[ bad input ]*/ result = 0; break; } result &= 1; /* odd => success (== 1), even => failure (== 0) */ return !result; /* 0 == success, 1 == failure */ } /* vms_putenv() - create or modify an environment value */ int vms_putenv(string) const char *string; { char name[ENVSIZ+1], value[ENVSIZ+1], *p; /* [255+1] */ p = strchr(string, '='); if (p > string && p < string + sizeof name && strlen(p+1) < sizeof value) { (void)strncpy(name, string, p - string), name[p - string] = '\0'; (void)strcpy(value, p+1); return vms_define(name, value, ENV_USR); } else return 1; /* failure */ } /* Support for VT420 was added to VMS in version V5.4, but as of V5.5-2 VAXCRTL still doesn't handle it and puts TERM=undefined into the environ[] array. getenv("TERM") will return "undefined" instead of something sensible. Even though that's finally fixed in V6.0, site defined terminals also return "undefined" so query SMG's TERMTABLE instead of just checking VMS's device-type value for VT400_Series. Called by verify_termcap() for convenience. */ static char *verify_term() { char *term = getenv("NETHACK_TERM"); if (!term) term = getenv("HACK_TERM"); if (!term) term = getenv("EMACS_TERM"); if (!term) term = getenv("TERM"); if (!term || !*term || !strcmpi(term, "undefined") || !strcmpi(term, "unknown")) { static char smgdevtyp[31+1]; /* size is somewhat arbitrary */ static char dev_tty[] = "TT:"; static $DESCRIPTOR(smgdsc, smgdevtyp); static $DESCRIPTOR(tt, dev_tty); unsigned short dvicode = DVI$_DEVTYPE; unsigned long devtype = 0L, termtab = 0L; (void)lib$getdvi(&dvicode, (unsigned short *)0, &tt, &devtype, (genericptr_t)0, (unsigned short *)0); if (devtype && vms_ok(smg$init_term_table_by_type(&devtype, &termtab, &smgdsc))) { register char *p = &smgdevtyp[smgdsc.dsc$w_length]; /* strip trailing blanks */ while (p > smgdevtyp && *--p == ' ') *p = '\0'; /* (void)smg$del_term_table(); */ term = smgdevtyp; } } return term; } /* Figure out whether the termcap code will find a termcap file; if not, try to help it out. This avoids modifying the GNU termcap sources and can simplify configuration for sites which don't already use termcap. */ #define GNU_DEFAULT_TERMCAP "emacs_library:[etc]termcap.dat" #define NETHACK_DEF_TERMCAP "nethackdir:termcap" #define HACK_DEF_TERMCAP "hackdir:termcap" char * verify_termcap() /* called from startup(src/termcap.c) */ { struct stat dummy; const char *tc = getenv("TERMCAP"); if (tc) return verify_term(); /* no termcap fixups needed */ if (!tc && !stat(NETHACK_DEF_TERMCAP, &dummy)) tc = NETHACK_DEF_TERMCAP; if (!tc && !stat(HACK_DEF_TERMCAP, &dummy)) tc = HACK_DEF_TERMCAP; if (!tc && !stat(GNU_DEFAULT_TERMCAP, &dummy)) tc = GNU_DEFAULT_TERMCAP; if (!tc && !stat("[]termcap", &dummy)) tc = "[]termcap"; /* current dir */ if (!tc && !stat("$TERMCAP", &dummy)) tc = "$TERMCAP"; /* alt environ */ if (tc) { /* putenv(strcat(strcpy(buffer,"TERMCAP="),tc)); */ vms_define("TERMCAP", tc, ENV_USR); } else { /* perhaps someday we'll construct a termcap entry string */ } return verify_term(); } /*------*/ #ifdef SHELL # ifndef CLI$M_NOWAIT # define CLI$M_NOWAIT 1 # endif #endif #if defined(CHDIR) || defined(SHELL) || defined(SECURE) static unsigned long oprv[2]; void privoff() { unsigned long pid = 0, prv[2] = { ~0, ~0 }; unsigned short code = JPI$_PROCPRIV; (void) sys$setprv(0, prv, 0, oprv); (void) lib$getjpi(&code, &pid, (genericptr_t)0, prv); (void) sys$setprv(1, prv, 0, (unsigned long *)0); } void privon() { (void) sys$setprv(1, oprv, 0, (unsigned long *)0); } #endif /* CHDIR || SHELL || SECURE */ #if defined(SHELL) || defined(SUSPEND) static void hack_escape(screen_manip, msg_str) boolean screen_manip; const char *msg_str; { if (screen_manip) suspend_nhwindows(msg_str); /* clear screen, reset terminal, &c */ (void) signal(SIGQUIT,SIG_IGN); /* ignore ^Y */ (void) signal(SIGINT,SIG_DFL); /* don't trap ^C (implct cnvrs to ^Y) */ } static void hack_resume(screen_manip) boolean screen_manip; { (void) signal(SIGINT, (SIG_RET_TYPE) done1); # ifdef WIZARD if (wizard) (void) signal(SIGQUIT,SIG_DFL); # endif if (screen_manip) resume_nhwindows(); /* setup terminal modes, redraw screen, &c */ } #endif /* SHELL || SUSPEND */ #ifdef SHELL unsigned long dosh_pid = 0, /* this should cover any interactive escape */ mail_pid = 0; /* this only covers the last mail or phone; */ /*(mail & phone commands aren't expected to leave any process hanging around)*/ int dosh() { return vms_doshell("", TRUE); /* call for interactive child process */ } /* vms_doshell -- called by dosh() and readmail() */ /* If execstring is not a null string, then it will be executed in a spawned */ /* subprocess, which will then return. It is for handling mail or phone */ /* interactive commands, which are only available if both MAIL and SHELL are */ /* #defined, but we don't bother making the support code conditionalized on */ /* MAIL here, just on SHELL being enabled. */ /* Normally, all output from this interaction will be 'piped' to the user's */ /* screen (SYS$OUTPUT). However, if 'screenoutput' is set to FALSE, output */ /* will be piped into oblivion. Used for silent phone call rejection. */ int vms_doshell(execstring, screenoutput) const char *execstring; boolean screenoutput; { unsigned long status, new_pid, spawnflags = 0; struct dsc$descriptor_s comstring, *command, *inoutfile = 0; static char dev_null[] = "_NLA0:"; static $DESCRIPTOR(nulldevice, dev_null); /* Is this an interactive shell spawn, or do we have a command to do? */ if (execstring && *execstring) { comstring.dsc$w_length = strlen(execstring); comstring.dsc$b_dtype = DSC$K_DTYPE_T; comstring.dsc$b_class = DSC$K_CLASS_S; comstring.dsc$a_pointer = (char *)execstring; command = &comstring; } else command = 0; /* use asynch subprocess and suppress output iff one-shot command */ if (!screenoutput) { spawnflags = CLI$M_NOWAIT; inoutfile = &nulldevice; } hack_escape(screenoutput, command ? (const char *) 0 : " \"Escaping\" into a subprocess; LOGOUT to reconnect and resume play. "); if (command || !dosh_pid || !vms_ok(status = lib$attach(&dosh_pid))) { # ifdef CHDIR (void) chdir(getenv("PATH")); # endif privoff(); new_pid = 0; status = lib$spawn(command, inoutfile, inoutfile, &spawnflags, (struct dsc$descriptor_s *) 0, &new_pid); if (!command) dosh_pid = new_pid; else mail_pid = new_pid; privon(); # ifdef CHDIR chdirx((char *) 0, 0); # endif } hack_resume(screenoutput); if (!vms_ok(status)) { pline(" Spawn failed. (%%x%08lX) ", status); mark_synch(); } return 0; } #endif /* SHELL */ #ifdef SUSPEND /* dosuspend() -- if we're a subprocess, attach to our parent; * if not, there's nothing we can do. */ int dosuspend() { static long owner_pid = -1; unsigned long status; if (owner_pid == -1) /* need to check for parent */ owner_pid = getppid(); if (owner_pid == 0) { pline( " No parent process. Use '!' to Spawn, 'S' to Save, or 'Q' to Quit. "); mark_synch(); return 0; } /* restore normal tty environment & clear screen */ hack_escape(1, " Attaching to parent process; use the ATTACH command to resume play. "); status = lib$attach(&owner_pid); /* connect to parent */ hack_resume(1); /* resume game tty environment & refresh screen */ if (!vms_ok(status)) { pline(" Unable to attach to parent. (%%x%08lX) ", status); mark_synch(); } return 0; } #endif /* SUSPEND */ /*vmsunix.c*/ nethack-3.4.3/sys/wince/0040755000000000000000000000000007764735105013601 5ustar rootrootnethack-3.4.3/sys/wince/ceinc/0040755000000000000000000000000007764735105014662 5ustar rootrootnethack-3.4.3/sys/wince/ceinc/sys/0040755000000000000000000000000007764735105015500 5ustar rootrootnethack-3.4.3/sys/wince/ceinc/sys/stat.h0100644000000000000000000000002207764735041016612 0ustar rootroot/* empty file */ nethack-3.4.3/sys/wince/ceinc/assert.h0100644000000000000000000000036207764735041016331 0ustar rootroot/*** *assert.h - define the assert macro * ****/ #undef assert #ifdef NDEBUG #define assert(exp) ((void)0) #else #define assert(exp) (void)( (exp) || (panic("%s at %s line %ld", #exp, __FILE__,__LINE__), 1) ) #endif /* NDEBUG */ nethack-3.4.3/sys/wince/ceinc/errno.h0100644000000000000000000000004507764735041016153 0ustar rootroot/* empty file */ extern int errno; nethack-3.4.3/sys/wince/ceinc/fcntl.h0100644000000000000000000000405607764735041016142 0ustar rootroot/*** *fcntl.h - file control options used by open() * *Purpose: * This file defines constants for the file control options used * by the _open() function. * [System V] * * [Public] * ****/ #ifndef _INC_FCNTL #define _INC_FCNTL #define _O_RDONLY 0x0000 /* open for reading only */ #define _O_WRONLY 0x0001 /* open for writing only */ #define _O_RDWR 0x0002 /* open for reading and writing */ #define _O_APPEND 0x0008 /* writes done at eof */ #define _O_CREAT 0x0100 /* create and open file */ #define _O_TRUNC 0x0200 /* open and truncate */ #define _O_EXCL 0x0400 /* open only if file doesn't already exist */ /* O_TEXT files have sequences translated to on read()'s, ** and sequences translated to on write()'s */ #define _O_TEXT 0x4000 /* file mode is text (translated) */ #define _O_BINARY 0x8000 /* file mode is binary (untranslated) */ /* macro to translate the C 2.0 name used to force binary mode for files */ #define _O_RAW _O_BINARY /* Open handle inherit bit */ #define _O_NOINHERIT 0x0080 /* child process doesn't inherit file */ /* Temporary file bit - file is deleted when last handle is closed */ #define _O_TEMPORARY 0x0040 /* temporary file bit */ /* sequential/random access hints */ #define _O_SEQUENTIAL 0x0020 /* file access is primarily sequential */ #define _O_RANDOM 0x0010 /* file access is primarily random */ #if !__STDC__ || defined(_POSIX_) /* Non-ANSI names for compatibility */ #define O_RDONLY _O_RDONLY #define O_WRONLY _O_WRONLY #define O_RDWR _O_RDWR #define O_APPEND _O_APPEND #define O_CREAT _O_CREAT #define O_TRUNC _O_TRUNC #define O_EXCL _O_EXCL #define O_TEXT _O_TEXT #define O_BINARY _O_BINARY #define O_RAW _O_BINARY #define O_TEMPORARY _O_TEMPORARY #define O_NOINHERIT _O_NOINHERIT #define O_SEQUENTIAL _O_SEQUENTIAL #define O_RANDOM _O_RANDOM #endif /* __STDC__ */ #endif /* _INC_FCNTL */ nethack-3.4.3/sys/wince/Install.ce0100644000000000000000000001343707764735041015524 0ustar rootrootCopyright (c) Alex Kompel, 2002 NetHack may be freely redistributed. See license for details. ======================================================================== Instructions for compiling and installing NetHack 3.4.3 on a Windows CE or PocketPC system ======================================================================== Last revision: $Date: 2003/10/14 01:31:21 $ Credit for the porting of NetHack to Windows CE goes to Alex Kompel who initially developed and contributed the port. In order to build NetHack for Windows CE, you need *both* of the following: o A copy of Microsoft Visual C V6.0 SP3 or later. Things may work with an earlier version of the compiler, but the current code has not been tested with an earlier version. o Embedded Visual C++ 3.0 or later FIRST STEP: The first step in building NetHack for Windows CE is to execute sys/wince/cesetup.bat. From the command prompt: cd sys\wince cesetup From a Windows explorer window: double-click on cesetup.bat A "wince" directory will be created off the top of the NetHack source tree, and a Microsoft embedded C workspace file will be placed in the top of the NetHack source tree. ------------ | BUILDING | ------------ Boostrapping the build process on Windows NT/2000/XP 1. With the Visual C++ 6.0 tools in your path, Run "nmake /f bootstrp.mak" from the wince folder. Compiling 2. Start the Embedded Visual C IDE. In the Embedded Visual C IDE Menus, choose: File | Open Workspace 3. Set up for the build. o In the Visual C "Open Workspace" dialog box, navigate to the top of your NetHack source directory tree. In there, highlight "wince.vcw" and click on Open. Once the workspace has been opened, you should see the following list in the Visual C selection window: + nethack_hpc files + nethack_palm_pc files + nethack_pocket_pc files + nethack_smartphone files o On the Embedded Visual C menus, choose: Build | Set Active Platform Select the platform that corresponds to your device: Palm-size PC 2.11 - palm size PC running Windows CE version 2.11 Pocket PC - palm-size PC running Windows CE 3.0 and higher (PocketPC) H/PC Pro 2.11 - handheld computers running Windows CE 2.11 anf higher Smartphone 2002 - Microsoft SmartPhone device o On the Visual C menus again, choose either: Build | Set Active Configuration where configuration is one of the following (make sure it matches the platform you have selected): nethack_hpc - Win32 (WCE MIPS) HPCRelease - H/PC Pro 2.11 MIPS processor release executable nethack_hpc - Win32 (WCE x86em) HPCDebug - H/PC Pro 2.11 x86 emulation debug executable nethack_hpc - Win32 (WCE ARM) HPCRelease - H/PC Pro 2.11 ARM processor release executable nethack_hpc - Win32 (WCE SH3) HPCRelease - H/PC Pro 2.11 SH3 processor release executable nethack_hpc - Win32 (WCE x86em) HPCRelease - H/PC Pro 2.11 x86 emulation release executable nethack_hpc - Win32 (WCE SH4) HPCRelease - H/PC Pro 2.11 SH4 processor release executable nethack_palm_pc - Win32 (WCE MIPS) PalmPCRelease - Palm-size PC 2.11 MIPS processor release executable nethack_palm_pc - Win32 (WCE x86em) PalmPCDebug - Palm-size PC 2.11 x86 emulation debug executable nethack_palm_pc - Win32 (WCE SH3) PalmPCRelease - Palm-size PC 2.11 SH3 processor release executable nethack_palm_pc - Win32 (WCE x86em) PalmPCRelease - Palm-size PC 2.11 x86 emulation release executable nethack_pocket_pc - Win32 (WCE MIPS) PocketPCRelease - Pocket PC MIPS processor release executable nethack_pocket_pc - Win32 (WCE ARM) PocketPCRelease - Pocket PC ARM processor release executable nethack_pocket_pc - Win32 (WCE x86em) PocketPCRelease - Pocket PC x86 emulation release executable nethack_pocket_pc - Win32 (WCE x86em) PocketPCDebug - Pocket PC x86 emulation debug executable nethack_pocket_pc - Win32 (WCE SH3) PocketPCRelease - Pocket PC SH3 processor release executable nethack_smartphone - Win32 (WCE ARM) SPhoneRelease - Smartphone 2002 ARM processor release executable nethack_smartphone - Win32 (WCE x86em) SPhoneDebug - Smartphone 2002 x86 emulation debug executable Building 4. Start your build. o On the Embedded Visual C menus once again, choose: Build | Build nethackm.exe This starts the build. It is likely that the IDE message window where you are doing the compiling will be occupied for a while. Notes: o You may get a bunch of warnings regarding missing include files in the beginning of the build process - ignore them. For some reason the tool that produces these messages ignores preprocessor directives. The actual build will go just fine. o Sometimes the compiler chokes on do_wear.c Ignore that - let the build finish. Then run it again - it will compile just fine. (Seems to be some sort of bug in EVC++) Transfer 5. Transfer the files and executables to your handheld by extracting the files into some folder on the CE device - that should do it. Notes If you want to use IBMGraphics make sure that you have a proper font installed on the device that supports OEM character set (for example, Lucida Console) PROBLEMS If you discover a bug and wish to report it, or if you have comments or suggestions we recommend using our "Contact Us" web page at: http://www.nethack.org/common/contact.html If you don't have access to the web, or you want to send us a patch to the NetHack source code feel free to drop us a line c/o: DevTeam (at) nethack.org Happy NetHacking! nethack-3.4.3/sys/wince/bootstrp.mak0100644000000000000000000007314207764735041016152 0ustar rootroot# SCCS Id: @(#)bootstrp.mak 3.4 2002/03/24 # Copyright (c) Michael Allison # # NetHack Windows CE bootstrap file for MS Visual C++ V6.x and # above and MS NMAKE # # This will: # - build makedefs # - #============================================================================== # Do not delete the following 3 lines. # TARGETOS=BOTH APPVER=4.0 !include # # Source directories. Makedefs hardcodes these, don't change them. # INCL = ..\include # NetHack include files DAT = ..\dat # NetHack data files DOC = ..\doc # NetHack documentation files UTIL = ..\util # Utility source SRC = ..\src # Main source SSYS = ..\sys\share # Shared system files NTSYS = ..\sys\winnt # NT Win32 specific files TTY = ..\win\tty # window port files (tty) WIN32 = ..\win\win32 # window port files (WINCE) WSHR = ..\win\share # Tile support files SWINCE= ..\wince # wince files WINCE = ..\wince # wince build area OBJ = $(WINCE)\ceobj DLB = $(DAT)\nhdat #========================================== # Setting up the compiler and linker # macros. All builds include the base ones. #========================================== CFLAGSBASE = -c $(cflags) $(cvarsmt) -I$(INCL) -nologo $(cdebug) $(WINPINC) -DDLB LFLAGSBASEC = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt) LFLAGSBASEG = $(linkdebug) $(guiflags) $(guilibsmt) comctl32.lib #========================================== # Util builds #========================================== CFLAGSU = $(CFLAGSBASE) $(WINPFLAG) LFLAGSU = $(LFLAGSBASEC) LEVCFLAGS= -c -nologo -DWINVER=0x0400 -DWIN32 -D_WIN32 \ -D_MT -MT -I..\include -nologo -Z7 -Od -DDLB #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .til .uu .c .y .l #========================================== # Rules for files in src #========================================== #.c{$(OBJ)}.o: # $(cc) $(CFLAGSU) -Fo$@ $< {$(SRC)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in sys\share #========================================== {$(SSYS)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in sys\winnt #========================================== {$(NTSYS)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< {$(NTSYS)}.h{$(INCL)}.h: copy $< $@ #========================================== # Rules for files in util #========================================== {$(UTIL)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in win\share #========================================== {$(WSHR)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< {$(WSHR)}.h{$(INCL)}.h: copy $< $@ #{$(WSHR)}.txt{$(DAT)}.txt: # copy $< $@ #========================================== # Rules for files in win\tty #========================================== {$(TTY)}.c{$(OBJ)}.o: $(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in win\win32 #========================================== {$(WIN32)}.c{$(OBJ)}.o: $(cc) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in sys\wince #========================================== {$(SWINCE)}.c{$(OBJ)}.o: $(cc) $(CFLAGSU) -Fo$@ $< #========================================== #================ MACROS ================== #========================================== # # Shorten up the location for some files # O = $(OBJ)^\ U = $(UTIL)^\ # # Utility Objects. # MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS = $(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o \ $(O)monst.o $(O)objects.o $(O)panic.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt # # These are not invoked during a normal game build in 3.4.0 # TEXT_IO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o TEXT_IO32 = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o GIFREADERS32 = $(O)gifrd32.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o DLBOBJ = $(O)dlb.o #========================================== # Header file macros #========================================== CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \ $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \ $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \ $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \ $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \ $(INCL)\ntconf.h $(INCL)\nhlan.h $(INCL)\wceconf.h HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \ $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \ $(INCL)\permonst.h $(INCL)\monattk.h \ $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \ $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \ $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \ $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \ $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \ $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \ $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \ $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \ $(INCL)\wintty.h $(INCL)\trampoli.h LEV_H = $(INCL)\lev.h DGN_FILE_H = $(INCL)\dgn_file.h LEV_COMP_H = $(INCL)\lev_comp.h SP_LEV_H = $(INCL)\sp_lev.h TILE_H = ..\win\share\tile.h #========================================== # Miscellaneous #========================================== DATABASE = $(DAT)\data.base #========================================== #=============== TARGETS ================== #========================================== # # The default make target (so just typing 'nmake' is useful). # default : all # # Everything # all : $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \ $(SRC)\monstr.c $(SRC)\vis_tab.c $(U)lev_comp.exe $(INCL)\vis_tab.h \ $(U)dgn_comp.exe $(U)uudecode.exe \ $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(O)sp_lev.tag $(DLB) $(SRC)\tile.c \ $(SWINCE)\nethack.ico $(SWINCE)\tiles.bmp $(SWINCE)\mnsel.bmp \ $(SWINCE)\mnunsel.bmp $(SWINCE)\petmark.bmp $(SWINCE)\mnselcnt.bmp \ $(SWINCE)\keypad.bmp $(SWINCE)\menubar.bmp @echo Done! $(O)sp_lev.tag: $(DAT)\bigroom.des $(DAT)\castle.des \ $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des \ $(DAT)\medusa.des $(DAT)\oracle.des $(DAT)\tower.des \ $(DAT)\yendor.des $(DAT)\arch.des $(DAT)\barb.des \ $(DAT)\caveman.des $(DAT)\healer.des $(DAT)\knight.des \ $(DAT)\monk.des $(DAT)\priest.des $(DAT)\ranger.des \ $(DAT)\rogue.des $(DAT)\samurai.des $(DAT)\sokoban.des \ $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des cd $(DAT) $(U)lev_comp bigroom.des $(U)lev_comp castle.des $(U)lev_comp endgame.des $(U)lev_comp gehennom.des $(U)lev_comp knox.des $(U)lev_comp mines.des $(U)lev_comp medusa.des $(U)lev_comp oracle.des $(U)lev_comp sokoban.des $(U)lev_comp tower.des $(U)lev_comp yendor.des $(U)lev_comp arch.des $(U)lev_comp barb.des $(U)lev_comp caveman.des $(U)lev_comp healer.des $(U)lev_comp knight.des $(U)lev_comp monk.des $(U)lev_comp priest.des $(U)lev_comp ranger.des $(U)lev_comp rogue.des $(U)lev_comp samurai.des $(U)lev_comp tourist.des $(U)lev_comp valkyrie.des $(U)lev_comp wizard.des cd $(WINCE) echo sp_levs done > $(O)sp_lev.tag #$(NHRES): $(TILEBMP16) $(WINCE)\winhack.rc $(WINCE)\mnsel.bmp \ # $(WINCE)\mnselcnt.bmp $(WINCE)\mnunsel.bmp \ # $(WINCE)\petmark.bmp $(WINCE)\NetHack.ico $(WINCE)\rip.bmp \ # $(WINCE)\splash.bmp # $(rc) -r -fo$@ -i$(WINCE) -dNDEBUG $(WINCE)\winhack.rc # # Utility Targets. # #========================================== # Makedefs Stuff #========================================== $(U)makedefs.exe: $(MAKEOBJS) $(link) $(LFLAGSU) -out:$@ $(MAKEOBJS) $(O)makedefs.o: $(CONFIG_H) $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\qtext.h $(INCL)\patchlevel.h \ $(U)makedefs.c if not exist $(OBJ)\*.* echo creating directory $(OBJ) if not exist $(OBJ)\*.* mkdir $(OBJ) $(CC) $(CFLAGSU) -Fo$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe $(U)makedefs -v $(INCL)\onames.h : $(U)makedefs.exe $(U)makedefs -o $(INCL)\pm.h : $(U)makedefs.exe $(U)makedefs -p #$(INCL)\trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)\monstr.c: $(U)makedefs.exe $(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe $(U)makedefs -z $(SRC)\vis_tab.c: $(U)makedefs.exe $(U)makedefs -z #========================================== # uudecode utility and uuencoded targets #========================================== $(U)uudecode.exe: $(O)uudecode.o $(link) $(LFLAGSU) -out:$@ $(O)uudecode.o $(O)uudecode.o: $(SSYS)\uudecode.c $(SWINCE)\NetHack.ico : $(U)uudecode.exe $(SWINCE)\nhico.uu chdir $(SWINCE) ..\util\uudecode.exe nhico.uu chdir $(WINCE) $(SWINCE)\mnsel.bmp: $(U)uudecode.exe $(SWINCE)\mnsel.uu chdir $(SWINCE) ..\util\uudecode.exe mnsel.uu chdir $(WINCE) $(SWINCE)\mnselcnt.bmp: $(U)uudecode.exe $(SWINCE)\mnselcnt.uu chdir $(SWINCE) ..\util\uudecode.exe mnselcnt.uu chdir $(WINCE) $(SWINCE)\mnunsel.bmp: $(U)uudecode.exe $(SWINCE)\mnunsel.uu chdir $(SWINCE) ..\util\uudecode.exe mnunsel.uu chdir $(WINCE) $(SWINCE)\petmark.bmp: $(U)uudecode.exe $(SWINCE)\petmark.uu chdir $(SWINCE) ..\util\uudecode.exe petmark.uu chdir $(WINCE) $(SWINCE)\rip.bmp: $(U)uudecode.exe $(SWINCE)\rip.uu chdir $(SWINCE) ..\util\uudecode.exe rip.uu chdir $(WINCE) $(SWINCE)\splash.bmp: $(U)uudecode.exe $(SWINCE)\splash.uu chdir $(SWINCE) ..\util\uudecode.exe splash.uu chdir $(WINCE) $(SWINCE)\keypad.bmp: $(U)uudecode.exe $(SWINCE)\keypad.uu chdir $(SWINCE) ..\util\uudecode.exe keypad.uu chdir $(WINCE) $(SWINCE)\menubar.bmp: $(U)uudecode.exe $(SWINCE)\menubar.uu chdir $(SWINCE) ..\util\uudecode.exe menubar.uu chdir $(WINCE) #========================================== # Level Compiler Stuff #========================================== $(U)lev_comp.exe: $(SPLEVOBJS) echo Linking $@... $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(SPLEVOBJS:^ =^ ) << $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_main.c $(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y @echo We will copy the prebuilt lev_yacc.c and @echo lev_comp.h from $(SSYS) into $(UTIL) and use them. @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul @echo /**/ >>$(U)lev_yacc.c @echo /**/ >>$(INCL)\lev_comp.h $(U)lev_$(LEX).c: $(U)lev_comp.l @echo We will copy the prebuilt lev_lex.c @echo from $(SSYS) into $(UTIL) and use it. @copy $(SSYS)\lev_lex.c $@ >nul @echo /**/ >>$@ #========================================== # Dungeon Compiler Stuff #========================================== $(U)dgn_comp.exe: $(DGNCOMPOBJS) @echo Linking $@... $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(DGNCOMPOBJS:^ =^ ) << $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_$(LEX).c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c $(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y @echo We will copy the prebuilt $(U)dgn_yacc.c and @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them. @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul @echo /**/ >>$(U)dgn_yacc.c @echo /**/ >>$(INCL)\dgn_comp.h $(U)dgn_$(LEX).c: $(U)dgn_comp.l @echo We will copy the prebuilt dgn_lex.c @echo from $(SSYS) into $(UTIL) and use it. @copy $(SSYS)\dgn_lex.c $@ >nul @echo /**/ >>$@ #========================================== # Create directory for holding object files #========================================== $(O)obj.tag: if not exist $(OBJ)\*.* echo creating directory $(OBJ) if not exist $(OBJ)\*.* mkdir $(OBJ) echo directory created >$@ #========================================== # Notify of any CL environment variables # in effect since they change the compiler # options. #========================================== envchk: ! IF "$(CL)"!="" @echo Warning, the CL Environment variable is defined: @echo CL=$(CL) ! ENDIF @echo ---- @echo NOTE: This build will include tile support. @echo ---- #========================================== #=========== SECONDARY TARGETS ============ #========================================== #=========================================== # Header files NOT distributed in ..\include #=========================================== $(INCL)\win32api.h: $(NTSYS)\win32api.h copy $(NTSYS)\win32api.h $@ #========================================== # DLB utility and nhdat file creation #========================================== $(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o << $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h $(CC) $(CFLAGSU) /Fo$@ $(SRC)\dlb.c $(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h $(CC) $(CFLAGSU) /Fo$@ $(UTIL)\dlb_main.c #$(DAT)\porthelp: $(NTSYS)\porthelp # copy $(NTSYS)\porthelp $@ >nul $(DAT)\nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \ $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \ $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon \ $(DAT)\license $(O)sp_lev.tag cd $(DAT) echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst $(U)dlb_main cIf dlb.lst nhdat cd $(WINCE) #========================================== # Tile Mapping #========================================== $(SRC)\tile.c: $(U)tilemap.exe echo A new $@ has been created $(U)tilemap $(U)tilemap.exe: $(O)tilemap.o $(link) $(LFLAGSU) -out:$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ $(WSHR)\tilemap.c $(O)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H) $(CC) $(CFLAGSU) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c $(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) $(CC) $(CFLAGSU) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c $(O)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c $(O)gifrd32.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c $(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c $(O)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c $(O)tilete32.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) $(CC) $(CFLAGSU) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c $(SWINCE)\tiles.bmp: $(U)tile2bmp.exe $(TILEFILES) echo Creating 16x16 binary tile files (this may take some time) $(U)tile2bmp $@ #$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32) # echo Creating 32x32 binary tile files (this may take some time) # $(U)til2bm32 $(TILEBMP32) $(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) @echo Linking $@... $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)tile2bmp.o $(TEXT_IO:^ =^ ) << $(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32) @echo Linking $@... $(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)til2bm32.o $(TEXT_IO32:^ =^ ) << $(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(CC) $(CFLAGSU) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c $(O)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(CC) $(CFLAGSU) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c #=================================================================== # OTHER DEPENDENCIES #=================================================================== # # dat dependencies # $(DAT)\data: $(UTIL)\makedefs.exe $(U)makedefs -d $(DAT)\rumors: $(UTIL)\makedefs.exe $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(UTIL)\makedefs.exe $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(UTIL)\makedefs.exe $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(UTIL)\makedefs.exe $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgn_comp dungeon.pdf cd $(WINCE) # # NT dependencies # # #$(O)nttty.o: $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c # $(CC) $(CFLAGSU) -I$(WSHR) -Fo$@ $(NTSYS)\nttty.c #$(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c # $(CC) $(CFLAGSU) -Fo$@ $(NTSYS)\winnt.c #$(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c # $(CC) $(CFLAGSU) -Fo$@ $(NTSYS)\ntsound.c #$(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c # $(CC) $(CFLAGSU) -DMAPI_VERBOSE -Fo$@ $(NTSYS)\mapimail.c # # util dependencies # $(O)panic.o: $(U)panic.c $(CONFIG_H) $(CC) $(CFLAGSU) -Fo$@ $(U)panic.c # # The rest are stolen from sys/unix/Makefile.src, # with slashes changed to back-slashes # and -c (which is included in CFLAGSU) substituted # with -Fo$@ , but otherwise untouched. That # means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\atari\tos.c $(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\win32api.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcmain.c $(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcsys.c $(O)pctty.o: ..\sys\share\pctty.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pctty.c $(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\pcunix.c $(O)random.o: ..\sys\share\random.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\random.c $(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\ioctl.c $(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\share\unixtty.c $(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\unix\unixmain.c $(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H) $(CC) $(CFLAGSU) -Fo$@ ..\sys\unix\unixunix.c $(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h $(CC) $(CFLAGSU) -Fo$@ ..\sys\be\bemain.c $(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\getline.c $(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\termcap.c $(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\topl.c $(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(INCL)\tcap.h $(CC) $(CFLAGSU) -Fo$@ ..\win\tty\wintty.c $(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ $(CONFIG_H) $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\Window.c $(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\dialogs.c $(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h ..\win\X11\nh72icon \ ..\win\X11\nh56icon ..\win\X11\nh32icon $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winX.c $(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ $(INCL)\winX.h $(INCL)\tile2x11.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmap.c $(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmenu.c $(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmesg.c $(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winmisc.c $(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winstat.c $(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\wintext.c $(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h $(CC) $(CFLAGSU) -Fo$@ ..\win\X11\winval.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) $(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \ ..\win\gnome\gnmain.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnaskstr.c $(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnbind.c $(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnglyph.c $(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \ ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \ $(INCL)\date.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmain.c $(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnsignal.h $(HACK_H) $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmap.c $(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnbind.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmenu.c $(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnmesg.c $(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H) $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnopts.c $(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \ ..\win\gnome\gnmain.h $(HACK_H) $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnplayer.c $(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \ ..\win\gnome\gnmain.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnsignal.c $(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \ ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \ ..\win\gnome\gnomeprv.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnstatus.c $(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \ ..\win\gnome\gn_rip.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gntext.c $(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h $(CC) $(CFLAGSU) $(GNOMEINC) -c ..\win\gnome\gnyesno.c $(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(INCL)\wingem.h $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\wingem.c $(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \ $(INCL)\wintype.h $(INCL)\wingem.h $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\wingem1.c $(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h $(CC) $(CFLAGSU) -Fo$@ ..\win\gem\load_img.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) $(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\qt_win.h \ $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \ $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_win.cpp $(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_clust.cpp $(O)monstr.o: $(SRC)\monstr.c $(CONFIG_H) $(O)vis_tab.o: $(SRC)\vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h $(O)allmain.o: $(SRC)\allmain.c $(HACK_H) $(O)alloc.o: $(SRC)\alloc.c $(CONFIG_H) $(O)apply.o: $(SRC)\apply.c $(HACK_H) $(INCL)\edog.h $(O)artifact.o: $(SRC)\artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h $(O)attrib.o: $(SRC)\attrib.c $(HACK_H) $(INCL)\artifact.h $(O)ball.o: $(SRC)\ball.c $(HACK_H) $(O)bones.o: $(SRC)\bones.c $(HACK_H) $(INCL)\lev.h $(O)botl.o: $(SRC)\botl.c $(HACK_H) $(O)cmd.o: $(SRC)\cmd.c $(HACK_H) $(INCL)\func_tab.h $(O)dbridge.o: $(SRC)\dbridge.c $(HACK_H) $(O)decl.o: $(SRC)\decl.c $(HACK_H) $(O)detect.o: $(SRC)\detect.c $(HACK_H) $(INCL)\artifact.h $(O)dig.o: $(SRC)\dig.c $(HACK_H) $(INCL)\edog.h $(O)display.o: $(SRC)\display.c $(HACK_H) $(O)dlb.o: $(SRC)\dlb.c $(CONFIG_H) $(INCL)\dlb.h $(O)do.o: $(SRC)\do.c $(HACK_H) $(INCL)\lev.h $(O)do_name.o: $(SRC)\do_name.c $(HACK_H) $(O)do_wear.o: $(SRC)\do_wear.c $(HACK_H) $(O)dog.o: $(SRC)\dog.c $(HACK_H) $(INCL)\edog.h $(O)dogmove.o: $(SRC)\dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h $(O)dokick.o: $(SRC)\dokick.c $(HACK_H) $(INCL)\eshk.h $(O)dothrow.o: $(SRC)\dothrow.c $(HACK_H) $(O)drawing.o: $(SRC)\drawing.c $(HACK_H) $(INCL)\tcap.h $(O)dungeon.o: $(SRC)\dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h $(O)eat.o: $(SRC)\eat.c $(HACK_H) $(O)end.o: $(SRC)\end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h $(O)engrave.o: $(SRC)\engrave.c $(HACK_H) $(INCL)\lev.h $(O)exper.o: $(SRC)\exper.c $(HACK_H) $(O)explode.o: $(SRC)\explode.c $(HACK_H) $(O)extralev.o: $(SRC)\extralev.c $(HACK_H) $(O)files.o: $(SRC)\files.c $(HACK_H) $(INCL)\dlb.h $(O)fountain.o: $(SRC)\fountain.c $(HACK_H) $(O)hack.o: $(SRC)\hack.c $(HACK_H) $(O)hacklib.o: $(SRC)\hacklib.c $(HACK_H) $(O)invent.o: $(SRC)\invent.c $(HACK_H) $(INCL)\artifact.h $(O)light.o: $(SRC)\light.c $(HACK_H) $(INCL)\lev.h $(O)lock.o: $(SRC)\lock.c $(HACK_H) $(O)mail.o: $(SRC)\mail.c $(HACK_H) $(INCL)\mail.h $(O)makemon.o: $(SRC)\makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \ $(INCL)\edog.h $(O)mapglyph.o: $(SRC)\mapglyph.c $(HACK_H) $(O)mcastu.o: $(SRC)\mcastu.c $(HACK_H) $(O)mhitm.o: $(SRC)\mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h $(O)mhitu.o: $(SRC)\mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h $(O)minion.o: $(SRC)\minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h $(O)mklev.o: $(SRC)\mklev.c $(HACK_H) $(O)mkmap.o: $(SRC)\mkmap.c $(HACK_H) $(INCL)\sp_lev.h $(O)mkmaze.o: $(SRC)\mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h $(O)mkobj.o: $(SRC)\mkobj.c $(HACK_H) $(INCL)\artifact.h $(O)mkroom.o: $(SRC)\mkroom.c $(HACK_H) $(O)mon.o: $(SRC)\mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h $(O)mondata.o: $(SRC)\mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h $(O)monmove.o: $(SRC)\monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h $(O)monst.o: $(SRC)\monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \ $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \ $(INCL)\epri.h $(INCL)\color.h $(O)mplayer.o: $(SRC)\mplayer.c $(HACK_H) $(O)mthrowu.o: $(SRC)\mthrowu.c $(HACK_H) $(O)muse.o: $(SRC)\muse.c $(HACK_H) $(INCL)\edog.h $(O)music.o: $(SRC)\music.c $(HACK_H) #interp.c $(O)o_init.o: $(SRC)\o_init.c $(HACK_H) $(INCL)\lev.h $(O)objects.o: $(SRC)\objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h $(O)objnam.o: $(SRC)\objnam.c $(HACK_H) $(O)options.o: $(SRC)\options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \ $(HACK_H) $(INCL)\tcap.h $(O)pager.o: $(SRC)\pager.c $(HACK_H) $(INCL)\dlb.h $(O)pickup.o: $(SRC)\pickup.c $(HACK_H) $(O)pline.o: $(SRC)\pline.c $(HACK_H) $(INCL)\epri.h $(INCL)\edog.h $(O)polyself.o: $(SRC)\polyself.c $(HACK_H) $(O)potion.o: $(SRC)\potion.c $(HACK_H) $(O)pray.o: $(SRC)\pray.c $(HACK_H) $(INCL)\epri.h $(O)priest.o: $(SRC)\priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \ $(INCL)\epri.h $(INCL)\emin.h $(O)quest.o: $(SRC)\quest.c $(HACK_H) $(INCL)\qtext.h $(O)questpgr.o: $(SRC)\questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h $(O)read.o: $(SRC)\read.c $(HACK_H) $(O)rect.o: $(SRC)\rect.c $(HACK_H) $(O)region.o: $(SRC)\region.c $(HACK_H) $(INCL)\lev.h $(O)restore.o: $(SRC)\restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h $(O)rip.o: $(SRC)\rip.c $(HACK_H) $(O)rnd.o: $(SRC)\rnd.c $(HACK_H) $(O)role.o: $(SRC)\role.c $(HACK_H) $(O)rumors.o: $(SRC)\rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h $(O)save.o: $(SRC)\save.c $(HACK_H) $(INCL)\lev.h $(O)shk.o: $(SRC)\shk.c $(HACK_H) $(INCL)\eshk.h $(O)shknam.o: $(SRC)\shknam.c $(HACK_H) $(INCL)\eshk.h $(O)sit.o: $(SRC)\sit.c $(HACK_H) $(INCL)\artifact.h $(O)sounds.o: $(SRC)\sounds.c $(HACK_H) $(INCL)\edog.h $(O)sp_lev.o: $(SRC)\sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h $(O)spell.o: $(SRC)\spell.c $(HACK_H) $(O)steal.o: $(SRC)\steal.c $(HACK_H) $(O)steed.o: $(SRC)\steed.c $(HACK_H) $(O)teleport.o: $(SRC)\teleport.c $(HACK_H) $(O)timeout.o: $(SRC)\timeout.c $(HACK_H) $(INCL)\lev.h $(O)topten.o: $(SRC)\topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h $(O)track.o: $(SRC)\track.c $(HACK_H) $(O)trap.o: $(SRC)\trap.c $(HACK_H) $(O)u_init.o: $(SRC)\u_init.c $(HACK_H) $(O)uhitm.o: $(SRC)\uhitm.c $(HACK_H) $(O)vault.o: $(SRC)\vault.c $(HACK_H) $(INCL)\vault.h $(O)version.o: $(SRC)\version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h $(O)vision.o: $(SRC)\vision.c $(HACK_H) $(INCL)\vis_tab.h $(O)weapon.o: $(SRC)\weapon.c $(HACK_H) $(O)were.o: $(SRC)\were.c $(HACK_H) $(O)wield.o: $(SRC)\wield.c $(HACK_H) $(O)windows.o: $(SRC)\windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h $(O)wizard.o: $(SRC)\wizard.c $(HACK_H) $(INCL)\qtext.h $(O)worm.o: $(SRC)\worm.c $(HACK_H) $(INCL)\lev.h $(O)worn.o: $(SRC)\worn.c $(HACK_H) $(O)write.o: $(SRC)\write.c $(HACK_H) $(O)zap.o: $(SRC)\zap.c $(HACK_H) # end of file nethack-3.4.3/sys/wince/celib.c0100644000000000000000000004332307764735041015024 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #define NEED_VARARGS #include "hack.h" #include // #include "wceconf.h" static union { time_t t_val; struct time_pack { unsigned int ss:6; unsigned int mm:6; unsigned int dd:5; unsigned int hh:6; unsigned int mo:4; unsigned int yr:10; unsigned int wd:3; } tm_val; } _t_cnv; #define IS_LEAP(yr) (((yr)%4==0 || (yr)%100==0) && !(yr)%400==0) static char _day_mo_leap[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; static char _day_mo[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; struct tm * __cdecl localtime ( const time_t *ptime ) { static struct tm ptm; int i; if( !ptime ) return NULL; _t_cnv.t_val = *ptime; ptm.tm_sec = _t_cnv.tm_val.ss ; /* seconds after the minute - [0,59] */ ptm.tm_min = _t_cnv.tm_val.mm; /* minutes after the hour - [0,59] */ ptm.tm_hour = _t_cnv.tm_val.hh; /* hours since midnight - [0,23] */ ptm.tm_mday = _t_cnv.tm_val.dd; /* day of the month - [1,31] */ ptm.tm_mon = _t_cnv.tm_val.mo-1; /* months since January - [0,11] */ ptm.tm_year = _t_cnv.tm_val.yr; /* years since 1900 */ ptm.tm_wday = _t_cnv.tm_val.wd; /* days since Sunday - [0,6] */ ptm.tm_yday = _t_cnv.tm_val.dd; /* days since January 1 - [0,365] */ for( i=0; i=0 && i=FILE_TABLE_SIZE ) return -1; retval = (CloseHandle(_nh_file_table[f])? 0 : -1); _nh_file_table[f] = INVALID_HANDLE_VALUE; return retval; } int __cdecl creat(const char *fname , int mode) { HANDLE f; TCHAR wbuf[MAX_PATH+1]; ZeroMemory(wbuf, sizeof(wbuf)); NH_A2W(fname, wbuf, MAX_PATH); f = CreateFile( wbuf, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if( f==INVALID_HANDLE_VALUE ) return -1; else return alloc_file_handle(f); } int __cdecl eof(int f) { DWORD fpos, fsize; HANDLE p = get_file_handle(f); if( f==-1 ) return -1; fpos = SetFilePointer(p, 0, NULL, FILE_CURRENT); fsize = SetFilePointer(p, 0, NULL, FILE_END); if( fpos==0xFFFFFFFF || fsize==0xFFFFFFFF ) return -1; if( fpos==fsize ) return 1; else { SetFilePointer(p, fpos, NULL, FILE_BEGIN); return 0; } } long __cdecl lseek( int f, long offset, int origin ) { HANDLE p = get_file_handle(f); DWORD fpos; switch(origin) { case SEEK_SET: fpos = SetFilePointer(p, offset, NULL, FILE_BEGIN); break; case SEEK_CUR: fpos = SetFilePointer(p, offset, NULL, FILE_CURRENT); break; case SEEK_END: fpos = SetFilePointer(p, offset, NULL, FILE_END); break; default: fpos = 0xFFFFFFFF; break; } if( fpos==0xFFFFFFFF ) return -1; else return (long)fpos; } int __cdecl open( const char *filename, int oflag, ... ) { TCHAR fname[MAX_PATH+1]; TCHAR path[MAX_PATH+1]; HANDLE f; DWORD fileaccess; DWORD filecreate; /* O_TEXT is not supported */ /* * decode the access flags */ switch( oflag & (_O_RDONLY | _O_WRONLY | _O_RDWR) ) { case _O_RDONLY: /* read access */ fileaccess = GENERIC_READ; break; case _O_WRONLY: /* write access */ fileaccess = GENERIC_READ | GENERIC_WRITE; break; case _O_RDWR: /* read and write access */ fileaccess = GENERIC_READ | GENERIC_WRITE; break; default: /* error, bad oflag */ return -1; } /* * decode open/create method flags */ switch ( oflag & (_O_CREAT | _O_EXCL | _O_TRUNC) ) { case 0: case _O_EXCL: // ignore EXCL w/o CREAT filecreate = OPEN_EXISTING; break; case _O_CREAT: filecreate = OPEN_ALWAYS; break; case _O_CREAT | _O_EXCL: case _O_CREAT | _O_TRUNC | _O_EXCL: filecreate = CREATE_NEW; break; case _O_TRUNC: case _O_TRUNC | _O_EXCL: // ignore EXCL w/o CREAT filecreate = TRUNCATE_EXISTING; break; case _O_CREAT | _O_TRUNC: filecreate = CREATE_ALWAYS; break; default: return -1; } /* assemple the file name */ ZeroMemory(fname, sizeof(fname)); ZeroMemory(path, sizeof(path)); NH_A2W(filename, fname, MAX_PATH); if( *filename!='\\' && *filename!='/' ) { _tcscpy(path, _nh_cwd); _tcsncat(path, _T("\\"), MAX_PATH - _tcslen(path)); } _tcsncat(path, fname, MAX_PATH - _tcslen(path)); /* * try to open/create the file */ if ( (f = CreateFile( path, fileaccess, 0, NULL, filecreate, FILE_ATTRIBUTE_NORMAL, NULL )) == INVALID_HANDLE_VALUE ) { return -1; } if( !(oflag & O_APPEND) ) SetFilePointer(f, 0, NULL, FILE_BEGIN); return alloc_file_handle(f); } int __cdecl read( int f, void *buffer, unsigned int count ) { HANDLE p = get_file_handle(f); DWORD bytes_read; if( !ReadFile(p, buffer, count, &bytes_read, NULL) ) return -1; else return (int)bytes_read; } int __cdecl unlink(const char * filename) { TCHAR wbuf[MAX_PATH+1]; TCHAR fname[MAX_PATH+1]; ZeroMemory(wbuf, sizeof(wbuf)); ZeroMemory(fname, sizeof(fname)); NH_A2W(filename, wbuf, MAX_PATH); if( *filename!='\\' && *filename!='/' ) { _tcscpy(fname, _nh_cwd); _tcsncat(fname, _T("\\"), MAX_PATH - _tcslen(fname)); } _tcsncat(fname, wbuf, MAX_PATH - _tcslen(fname)); return !DeleteFileW(fname); } int __cdecl write( int f, const void *buffer, unsigned int count ) { HANDLE p = get_file_handle(f); DWORD bytes_written; if( !WriteFile(p, buffer, count, &bytes_written, NULL) ) return -1; else return (int)bytes_written; } int __cdecl rename( const char *oldname, const char *newname ) { WCHAR f1[MAX_PATH+1]; WCHAR f2[MAX_PATH+1]; ZeroMemory(f1, sizeof(f1)); ZeroMemory(f2, sizeof(f2)); MultiByteToWideChar(CP_ACP, 0, oldname, -1, f1, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, newname, -1, f2, MAX_PATH); return !MoveFile(f1, f2); } int __cdecl access( const char *path, int mode ) { DWORD attr; WCHAR f[MAX_PATH+1]; ZeroMemory(f, sizeof(f)); MultiByteToWideChar(CP_ACP, 0, path, -1, f, MAX_PATH); attr = GetFileAttributes(f); if( attr == (DWORD)-1 ) return -1; if ( (attr & FILE_ATTRIBUTE_READONLY) && (mode & 2) ) return -1; else return 0; } int chdir( const char *dirname ) { ZeroMemory(_nh_cwd, sizeof(_nh_cwd)); NH_A2W(dirname, _nh_cwd, MAX_PATH); return 0; } char *getcwd( char *buffer, int maxlen ) { if( maxlen<(int)_tcslen(_nh_cwd) ) return NULL; else return NH_W2A(_nh_cwd, buffer, maxlen); } /*------------------------------------------------------------------------------*/ /* __errno.h__ */ int errno; /*------------------------------------------------------------------------------*/ /* * Chdrive() changes the default drive. */ void chdrive(char *str) { return; } /* * This is used in nhlan.c to implement some of the LAN_FEATURES. */ char *get_username(lan_username_size) int *lan_username_size; { static char username_buffer[BUFSZ]; strcpy(username_buffer, "nhsave"); return username_buffer; } void Delay(int ms) { (void)Sleep(ms); } void more() { } int isatty(int f) { return 0; } #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) int __cdecl isupper(int c) { char str[2]; WCHAR wstr[2]; str[0] = c; str[1] = 0; NH_A2W(str, wstr, 1); return iswupper(wstr[0]); } int __cdecl isdigit(int c) { return ('0' <= c && c <= '9'); } int __cdecl isxdigit(int c) { return (('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')); } int __cdecl isspace(int c) { char str[2]; WCHAR wstr[2]; str[0] = c; str[1] = 0; NH_A2W(str, wstr, 1); return iswspace(wstr[0]); } int __cdecl isprint(int c) { char str[2]; WCHAR wstr[2]; str[0] = c; str[1] = 0; NH_A2W(str, wstr, 1); return iswprint(wstr[0]); } char* __cdecl _strdup(const char* s) { char* p; p = malloc(strlen(s)+1); return strcpy(p, s); } char* __cdecl strrchr( const char *s, int c ) { WCHAR wstr[1024]; WCHAR *w; w = wcsrchr(NH_A2W(s, wstr, 1024), c); if(w) return (char*)(s + (w - wstr)); else return NULL; } int __cdecl _stricmp(const char* a, const char* b) { return strncmpi(a, b, 65535u); } #endif #if defined(WIN_CE_PS2xx) /* stdio.h functions are missing from PAlm Size PC SDK 1.2 (SH3 and MIPS) */ #pragma warning(disable:4273) FILE * __cdecl fopen(const char* filename, const char *mode) { int modeflag; int whileflag; int filedes; /* First mode character must be 'r', 'w', or 'a'. */ switch (*mode) { case 'r': modeflag = _O_RDONLY; break; case 'w': modeflag = _O_WRONLY | _O_CREAT | _O_TRUNC; break; case 'a': modeflag = _O_WRONLY | _O_CREAT | _O_APPEND; break; default: return NULL; } whileflag=1; while(*++mode && whileflag) switch(*mode) { case '+': if (modeflag & _O_RDWR) whileflag=0; else { modeflag |= _O_RDWR; modeflag &= ~(_O_RDONLY | _O_WRONLY); } break; case 'b': if (modeflag & (_O_TEXT | _O_BINARY)) whileflag=0; else modeflag |= _O_BINARY; break; case 't': /* not supported */ whileflag=0; break; default: whileflag=0; break; } if ((filedes = open(filename, modeflag))==-1) return NULL; return (FILE*)filedes; } int __cdecl fscanf(FILE *f , const char *format, ...) { /* Format spec: %[*] [width] [l] type ] */ int ch; int sch; int matched = 0; int width = 65535; int modifier = -1; int skip_flag = 0; int n_read = 0; char buf[BUFSZ]; TCHAR wbuf[BUFSZ]; char* p; va_list args; #define RETURN_SCANF(i) { va_end(args); return i; } #define NEXT_CHAR(f) (n_read++, fgetc(f)) va_start(args, format); ch = *format++; sch = NEXT_CHAR(f); while( ch && sch!=EOF ) { if( isspace(ch) ) { while( ch && isspace(ch) ) ch = *format++; while( sch!=EOF && isspace(sch) ) sch = NEXT_CHAR(f); format--; goto next_spec; } /* read % */ if( ch!='%' ) { if( sch!=ch ) RETURN_SCANF(matched); sch = NEXT_CHAR(f); goto next_spec; } else { /* process '%%' */ ch = *format++; if( ch=='%' ) { if( sch!='%' ) RETURN_SCANF(matched); sch = NEXT_CHAR(f); goto next_spec; } if( ch=='*' ) { /* read skip flag - '*' */ skip_flag=1; ch = *format++; } /* get width */ if( isdigit(ch) ) { width = 0; while(ch && isdigit(ch)) { width = width*10 + (ch-'0'); ch = *format++; } } /* get modifier */ if( ch=='l' ) { modifier = 'l'; ch = *format++; } /* get type */ switch(ch) { case 'c': if( !skip_flag ) { *(va_arg(args, char*))=sch; matched++; } sch = NEXT_CHAR(f); goto next_spec; case 'd': p = buf; /* skip space */ while(sch!=EOF && isspace(sch)) sch=NEXT_CHAR(f); while(sch!=EOF && isdigit(sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); } *p = '\x0'; if( !skip_flag ) { matched++; if( modifier=='l' ) { *(va_arg(args, long*))=wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 10); } else { *(va_arg(args, int*))=wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 10); } } goto next_spec; case 'x': p = buf; while(sch!=EOF && isspace(sch)) sch=NEXT_CHAR(f); while(sch!=EOF && isxdigit(sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); } *p = '\x0'; if( !skip_flag ) { matched++; if( modifier=='l' ) { *(va_arg(args, long*))=wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 16); } else { *(va_arg(args, int*))=wcstol(NH_A2W(buf, wbuf, BUFSZ), NULL, 16); } } goto next_spec; case 'n': *(va_arg(args, int*)) = n_read; matched++; goto next_spec; case 's': if( skip_flag ) { while(sch!=EOF && !isspace(sch) && --width>=0) { sch=NEXT_CHAR(f); } } else { p = va_arg(args, char*); while(sch!=EOF && !isspace(sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); } *p = '\x0'; matched++; } goto next_spec; case '[': { char pattern[256]; int start, end; int negate; ZeroMemory(pattern, sizeof(pattern)); p = pattern; /* try to parse '^' modifier */ ch = *format++; if( ch=='^' ) { negate=1; ch=*format++; } else { negate=0; } if( ch==0 ) RETURN_SCANF(EOF); for( ; ch && ch!=']'; ch = *format++ ) { /* try to parse range: a-z */ if( format[0]=='-' && format[1] && format[1]!=']' ) { start = ch; format++; end = *format++; while(start<=end) { if(!strchr(pattern, (char)start)) *p++ = (char)start; start++; } } else { if(!strchr(pattern, (char)ch)) *p++ = (char)ch; } } if( skip_flag ) { while(sch!=EOF && strchr(pattern, sch) && --width>=0) { sch=NEXT_CHAR(f); } } else { p = va_arg(args, char*); if( negate ) while(sch!=EOF && !strchr(pattern, sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); } else while(sch!=EOF && strchr(pattern, sch) && --width>=0) { *p++ = sch; sch=NEXT_CHAR(f); } *p = '\x0'; matched++; } } goto next_spec; default: RETURN_SCANF(EOF); } } next_spec: width = 65535; modifier = -1; skip_flag = 0; ch = *format++; } fseek(f, -1, SEEK_CUR); RETURN_SCANF(matched); #undef RETURN_SCANF #undef NEXT_CHAR } int __cdecl fprintf(FILE *f , const char *format, ...) { int retval; va_list args; if( !f || !format ) return 0; va_start(args, format); retval = vfprintf(f, format, args); va_end(args); return retval; } int __cdecl vfprintf(FILE* f, const char *format, va_list args) { char buf[4096]; int retval; if( !f || !format ) return 0; retval = vsprintf(buf, format, args); write((int)f, buf, strlen(buf)); return retval; } int __cdecl fgetc(FILE * f) { char c; int fh = (int)f; if( !f ) return EOF; if( read(fh, &c, 1)==1 ) return c; else return EOF; } char * __cdecl fgets(char *s, int size, FILE *f) { /* not the best performance but it will do for now...*/ char c; if( !f || !s || size==0 ) return NULL; while( --size>0 ) { if( (c = fgetc(f))==EOF ) return NULL; *s++ = c; if( c=='\n' ) break; } *s = '\x0'; return s; } int __cdecl printf(const char *format, ...) { int retval; va_list args; if( !format ) return 0; va_start(args, format); retval = vprintf(format, args); va_end(args); return retval; } int __cdecl vprintf(const char *format, va_list args) { char buf[4096]; int retval; retval = vsprintf(buf, format, args); puts(buf); return retval; } // int __cdecl putchar(int); int __cdecl puts(const char * s) { TCHAR wbuf[4096]; NH_A2W(s, wbuf, 4096); MessageBox(NULL, wbuf, _T("stdout"), MB_OK); return 0; } FILE* __cdecl _getstdfilex(int desc) { return NULL; } int __cdecl fclose(FILE * f) { if(!f) return EOF; return close((int)f)==-1? EOF : 0; } size_t __cdecl fread(void *p, size_t size, size_t count, FILE *f) { int read_bytes; if(!f || !p || size==0 || count==0) return 0; read_bytes = read((int)f, p, size*count); return read_bytes>0? (read_bytes/size) : 0; } size_t __cdecl fwrite(const void *p, size_t size, size_t count, FILE * f) { int write_bytes; if(!f || !p || size==0 || count==0) return 0; write_bytes = write((int)f, p, size*count); return write_bytes>0? write_bytes/size : 0; } int __cdecl fflush(FILE *f) { return 0; } int __cdecl feof(FILE *f) { return (f && eof((int)f)==0)? 0 : 1; } int __cdecl fseek(FILE *f, long offset, int from) { return (f && lseek((int)f, offset, from)>=0)? 0 : 1; } long __cdecl ftell(FILE * f) { return f? lseek((int)f, 0, SEEK_CUR) : -1; } #endif nethack-3.4.3/sys/wince/cesetup.bat0100644000000000000000000000254707764735041015745 0ustar rootroot@REM SCCS Id: @(#)nhsetup.bat $Date: 2003/08/22 13:23:33 $ @REM Copyright (c) Alex Kompel, 2002 @REM NetHack may be freely redistributed. See license for details. @REM Win32 nhsetup batch file, see Install.ce for details @REM @echo off REM REM Make sure directories necessary for build exist REM if NOT exist ..\..\wince\*.* mkdir ..\..\wince REM REM Get these files from the win\win32 port REM copy ..\..\win\win32\mnsel.uu ..\..\wince\mnsel.uu copy ..\..\win\win32\mnselcnt.uu ..\..\wince\mnselcnt.uu copy ..\..\win\win32\mnunsel.uu ..\..\wince\mnunsel.uu copy ..\..\win\win32\petmark.uu ..\..\wince\petmark.uu copy ..\..\sys\winnt\nhico.uu ..\..\wince\nhico.uu copy ..\..\sys\wince\menubar.uu ..\..\wince\menubar.uu copy ..\..\sys\wince\keypad.uu ..\..\wince\keypad.uu REM REM Get these files from sys\wince REM copy bootstrp.mak ..\..\wince\bootstrp.mak copy wince.vcw ..\..\wince.vcw copy hpc.vcp ..\..\wince\wince_hpc.vcp copy palmpc.vcp ..\..\wince\wince_palm_pc.vcp copy pocketpc.vcp ..\..\wince\wince_pocket_pc.vcp copy smartphn.vcp ..\..\wince\wince_smartphone.vcp echo. echo Proceed with the following steps: echo. echo cd ..\..\wince echo nmake /f bootstrp.mak echo. echo Then start Embedded Visual C and open echo the workspace wince.vcw (at the top of the NetHack tree) echo to build. See Install.ce for details. echo. nethack-3.4.3/sys/wince/cesound.c0100644000000000000000000000143507764735041015404 0ustar rootroot/* SCCS Id: @(#)cesound.c 3.4 $Date: 2003/02/13 12:35:27 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * cesound.c - Windows CE NetHack sound support * * */ #include "hack.h" #include #ifdef USER_SOUNDS void play_usersound(filename, volume) const char* filename; int volume; { TCHAR wbuf[MAX_PATH+1]; /* pline("play_usersound: %s (%d).", filename, volume); */ ZeroMemory(wbuf, sizeof(wbuf)); (void)sndPlaySound(NH_A2W(filename, wbuf, MAX_PATH), SND_ASYNC | SND_NODEFAULT); } #endif /*USER_SOUNDS*/ /* cesound.c */ nethack-3.4.3/sys/wince/defaults.nh0100644000000000000000000001164207764735041015737 0ustar rootroot# Sample config file for win32 NetHack # A '#' at the beginning of a line means the rest of the line is a comment. # # Some options MUST be set in this file, other options can be toggled while # playing. For a list of options available see the file. # # To change the configuration, comment out the unwanted lines, and # uncomment the configuration you want. # *** OPTIONS *** # # Use the IBM character set rather than just plain ascii characters # for tty window-port. # OPTIONS=IBMGraphics # *** Personal Preferences *** # Some options to set personal preferences. Uncomment and change these to # suit your personal preference. If several people are to use the same # configuration, options like these should not be set. # #OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful #OPTIONS=dogname:Fido,catname:Morris,fruit:guava #OPTIONS=horsename:Silver #OPTIONS=autopickup,pickup_types:$"=/!?+ #OPTIONS=packorder:")[%?+/=!(*0_` #OPTIONS=scores:10 top/2 around/own #OPTIONS=nolegacy,noverbose #OPTIONS=menustyle:traditional # # General options. You might also set "silent" so as not to attract # the boss's attention. # OPTIONS=time,noshowexp,number_pad,lit_corridor,rest_on_space # # If you want to get rid of "use #quit to quit..." use: #OPTIONS=suppress_alert:3.3.1 # # Set some options to control graphical window-port (these will # be safely and silently ignored by the tty port) # # Map window settings # possible map_mode options include: tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8| # ascii7x12|ascii8x12|ascii16x12|ascii12x16| # ascii10x18|fit_to_screen OPTIONS=map_mode:tiles,scroll_margin:4 # Menu settings # OPTIONS=font_menu:Arial # Other OPTIONS=hilite_pet,!toptenwin OPTIONS=!splash_screen,player_selection:prompts OPTIONS=vary_msgcount:3 OPTIONS=fullscreen,wraptext,softkeyboard # Status/message window colors # Possible color options include: # six digit hexadecimal RGB color value ("#8F8F8F"), black, red, green, brown, # blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue, # brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia, # lime, olive, navy, teal, aqua, activeborder, activecaption, appworkspace, # background, btnface, btnshadow, btntext, captiontext, graytext, highlight, # highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar, # window, windowframe, windowtext. #OPTIONS=windowcolors:status windowtext/window message windowtext/window OPTIONS=windowcolors:status white/#000000 message white/#000000 menu white/#000000 text white/#000000 # #HACKDIR=c:\games\nethack # # Note: On Windows HACKDIR defaults to the location # of the NetHack.exe or NetHackw.exe file. # Setting HACKDIR above will override that. # # LEVELS and SAVE default to HACKDIR # #LEVELS=c:\games\nethack\bones #SAVE=c:\games\nethack\bones # *** CHARACTER GRAPHICS *** # # See the on-line help or the Guidebook for which symbols are in which # positions. # # If you merely set the IBMgraphics option as above, NetHack will use IBM # extended ASCII for dungeon characters. If you don't like the selections, # you can make up your own via these graphics options, but you should still # set IBMgraphics if you are using IBM graphics characters to get the correct # processing. # # ================================================ # An example using the IBM graphics character set: #DUNGEON= 032 179 196 218 191 192 217 197 193 194 \ # 180 195 249 239 239 254 254 240 241 249 \ # 177 177 060 062 060 062 220 124 190 035 \ # 244 247 249 247 042 042 186 205 046 035 \ # 247 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 232 232 232 157 094 094 \ # 094 094 # #EFFECTS= 179 196 092 047 042 033 041 040 \ # 048 035 064 042 \ # 047 045 092 058 058 092 045 047 \ # 047 045 092 058 032 058 092 045 047 # # ================================================ # Some alternatives: #DUNGEON= 032 186 205 201 187 200 188 206 202 203 \ # 185 204 249 239 239 254 254 240 241 249 \ # 177 177 060 062 060 062 095 124 092 035 \ # 244 247 249 247 042 042 179 196 046 035 \ # 247 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 034 094 094 094 094 \ # 094 094 # ================================================ # Here is a recommendation sent in by Michael Feir # for use by blind NetHack players. # #DUNGEON= 032 124 045 124 124 124 124 045 045 045 \ # 124 124 046 045 124 043 043 046 035 035 \ # 060 062 060 062 095 092 035 126 126 126 \ # 126 042 042 035 035 032 035 126 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 094 094 094 094 094 \ # 094 094 # #EFFECTS= 124 095 092 047 042 033 041 040 \ # 048 035 064 042 \ # 047 045 092 058 058 092 045 047 \ # 047 045 092 058 032 058 092 045 047 nethack-3.4.3/sys/wince/keypad.uu0100644000000000000000000000044507764735041015430 0ustar rootrootbegin 600 keypad.bmp M0DV^`````````#X````H````<`````@````!``$``````(`````````````` M`````````````````/___P#__________________P``[__[____________ M_R0``.?_\_?C]__W__?_]^MU``#CP>/GU?/AX\/OY_O5=0``X>/#Q\'QX\'C MS^?YZR4``/_W_^?5\^?_\^__^]5M``#____WX_?O__OW__?_)```________ *__________\``.?5 ` end nethack-3.4.3/sys/wince/menubar.uu0100644000000000000000000000104207764735041015576 0ustar rootrootbegin 600 menubar.bmp M0DUV`0```````'8````H````(````!`````!``0````````!```````````` M````````````````````@```@````("``(````"``(``@(```,#`P`"`@(`` M``#_``#_````__\`_P```/\`_P#__P``____`'=W=W=W=W=W=W=W=W=W=W=W M=W=W=W=W=W=W=W=W=W=W=$1$1$1$1'=W=W=W=W=W=W1$_T1/]$1W=W=W=W=W M=W=T1/_T__1$=W=W=W=W=W=W=/______]'=W=P<'!P=W=W3_______1W=W#P M\/#P=W=T3__T__]$=W */ /* NetHack may be freely redistributed. See license for details. */ #include #include "winMS.h" #include "mhaskyn.h" int mswin_yes_no_dialog( const char *question, const char *choices, int def) { return '\032'; } nethack-3.4.3/sys/wince/mhaskyn.h0100644000000000000000000000046507764735041015425 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINAskYesNO_h #define MSWINAskYesNO_h #include "winMS.h" int mswin_yes_no_dialog( const char *question, const char *choices, int def); #endif /* MSWINAskYesNO_h */ nethack-3.4.3/sys/wince/mhcmd.c0100644000000000000000000013475607764735041015051 0ustar rootroot/* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include #include "mhcmd.h" #include "mhinput.h" #include "mhcolor.h" static TCHAR szNHCmdWindowClass[] = TEXT("MSNethackCmdWndClass"); #ifndef C # define C(c) (0x1f & (c)) #endif /* cell status 0 */ #define NH_CST_CHECKED 1 /* fonts */ #define NH_CMDPAD_FONT_NORMAL 0 #define NH_CMDPAD_FONT_MAX 0 /* type of the cell */ #define NH_CELL_REG 0 #define NH_CELL_CTRL 1 #define NH_CELL_CAP 2 #define NH_CELL_SHIFT 3 #define NH_CELL_LAYOUT_NEW 4 #define NH_CELL_LAYOUT_MENU 5 #define NH_CMDSET_MAXSIZE 64 /* Keypad cell information NHCmdPadCell.cell_type NHCmdPadCell.data ----------- ---------- NH_CELL_REG (int)>=0 - index in the current keypad layout set (loads a new layout) -1 - restore default (saved) layout NH_CELL_CTRL not used NH_CELL_CAP not used NH_CELL_SHIFT not used NH_CELL_LAYOUT_NEW pointer to the new keypad layout layout (NHCmdLayout*) NH_CELL_LAYOUT_MENU pointer to the layout set (NHCmdSet* - if NULL then nhcmdset_default is used) */ typedef struct t_NHCmdPadCell { UINT cmd_code; /* Windows command code (menu processing - not implemented - set to -1) */ char f_char[16]; /* nethack char */ char text[16]; /* display text */ int image; /* >0 - image ID in IDB_KEYPAD bitmap <=0 - absolute index of the font table */ int type; /* cell type */ int mult; /* cell width multiplier */ void* data; /* internal data for the cell type */ } NHCmdPadCell, *PNHCmdPadCell; /* command layout */ typedef struct t_NHCmdLayout { char name[64]; int rows; int columns; NHCmdPadCell cells[]; } NHCmdLayout, *PNHCmdLayout; /* set of command layouts */ typedef struct t_NHCmdSet { int count; struct t_NHCmdSetElem { PNHCmdLayout layout; BOOL free_on_destroy; } elements[NH_CMDSET_MAXSIZE]; } NHCmdSet, *PNHCmdSet; /* display cell layout */ typedef struct t_NHCmdPadLayoutCell { POINT orig; /* origin of the cell rect */ BYTE type; /* cell type */ int state; /* cell state */ } NHCmdPadLayoutCell, *PNHCmdPadLayoutCell; /* command window data */ typedef struct mswin_nethack_cmd_window { SIZE cell_size; /* cell size */ HFONT font[NH_CMDPAD_FONT_MAX+1]; /* fonts for cell text */ HBITMAP images; /* key images map */ int active_cell; /* current active cell */ boolean is_caps; /* is CAPS selected */ boolean is_ctrl; /* is CRTL selected */ boolean is_shift; /* is SHIFT selected */ PNHCmdLayout layout_current; /* current layout */ PNHCmdLayout layout_save; /* saved layout */ PNHCmdPadLayoutCell cells; /* display cells */ #if defined(WIN_CE_SMARTPHONE) PNHCmdLayout layout_selected; /* since we use layout command for menu also we need to store the layout that was selected by a user */ #endif } NHCmdWindow, *PNHCmdWindow; LRESULT CALLBACK NHCommandWndProc(HWND, UINT, WPARAM, LPARAM); static void register_command_window_class(); static void LayoutCmdWindow(HWND hWnd); static void SetCmdWindowLayout(HWND hWnd, PNHCmdLayout layout); static int CellFromPoint(PNHCmdWindow data, POINT pt ); static void CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE windowSize); static void HighlightCell(HWND hWnd, int cell, BOOL isSelected); static void ActivateCell(HWND hWnd, int cell); static void PushNethackCommand( const char* cmd_char_str, int is_ctrl ); /*------------------- keyboard keys layout functions -----------------------*/ PNHCmdLayout nhcmdlayout_create( const char* name, int rows, int columns ); void nhcmdlayout_init( PNHCmdLayout p, PNHCmdPadCell cells ); #define nhcmdlayout_rows(p) ((p)->rows) #define nhcmdlayout_columns(p) ((p)->columns) #define nhcmdlayout_row(p, x) (&((p)->cells[(p)->columns*(x)])) #define nhcmdlayout_cell(p, x, y) (&((p)->cells[(p)->columns*(x)+(y)])) #define nhcmdlayout_cell_direct(p, i) (&((p)->cells[(i)])) void nhcmdlayout_destroy(PNHCmdLayout p); /*----------------- keyboard keys layout set functions ---------------------*/ PNHCmdSet nhcmdset_create(); int nhcmdset_count( PNHCmdSet p ); PNHCmdLayout nhcmdset_get( PNHCmdSet p, int index ); const char* nhcmdset_get_name( PNHCmdSet p, int index ); void nhcmdset_add( PNHCmdSet p, PNHCmdLayout layout ); void nhcmdset_destroy( PNHCmdSet p); /*-------------------- message handlers -----------------------------------*/ static void onPaint(HWND hWnd); // on WM_PAINT static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_CREATE static void onMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_LBUTTONDOWN static void onMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_MOUSEMOVE static void onMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam); // on WM_LBUTTONUP /*----------------------- static data -------------------------------------*/ static PNHCmdSet nhcmdset_current = 0; static PNHCmdSet nhcmdset_default = 0; /*---------------------- Pre-definde keyboard layouts --------------------*/ #ifdef WIN_CE_SMARTPHONE /* dimensions of the command pad */ #define NH_CMDPAD_ROWS 4 #define NH_CMDPAD_COLS 3 #define NH_CMDPAD_CELLNUM (NH_CMDPAD_COLS*NH_CMDPAD_ROWS) /* layout indexes */ #define NH_LAYOUT_GENERAL 0 #define NH_LAYOUT_MOVEMENT 1 #define NH_LAYOUT_ATTACK 2 #define NH_LAYOUT_ITEM_HANDLING 3 #define NH_LAYOUT_CONTROLS 4 #define NH_LAYOUT_ADV_MOVEMENT 5 /* template menu layout */ NHCmdPadCell cells_layout_menu[NH_CMDPAD_CELLNUM] = { { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", "<<", -NH_CMDPAD_FONT_NORMAL, NH_CELL_LAYOUT_NEW, 1 , NULL }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1 , (void*)-1 }, { -1, "", ">>", -NH_CMDPAD_FONT_NORMAL, NH_CELL_LAYOUT_NEW, 1 , NULL } }; /* movement layout */ NHCmdPadCell cells_layout_movement[NH_CMDPAD_CELLNUM] = { { -1, "7", "7", 1, NH_CELL_REG, 1, (void*)-1 }, { -1, "8", "8", 2, NH_CELL_REG, 1, (void*)-1 }, { -1, "9", "9", 3, NH_CELL_REG, 1, (void*)-1 }, { -1, "4", "4", 4, NH_CELL_REG, 1, (void*)-1 }, { -1, ".", ".", 5, NH_CELL_REG, 1, (void*)-1 }, { -1, "6", "6", 6, NH_CELL_REG, 1, (void*)-1 }, { -1, "1", "1", 7, NH_CELL_REG, 1, (void*)-1 }, { -1, "2", "2", 8, NH_CELL_REG, 1, (void*)-1 }, { -1, "3", "3", 9, NH_CELL_REG, 1, (void*)-1 }, { -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 }, { -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1, 0 } }; /* attack layout */ NHCmdPadCell cells_layout_attack[NH_CMDPAD_CELLNUM] = { { -1, "t", "t", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "w", "w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "x", "x", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "f", "f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "z", "z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "Z", "Z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "r", "r", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "a", "a", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\x04", "^D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "F", "F", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 } }; /* item handling layout */ NHCmdPadCell cells_layout_item_handling[NH_CMDPAD_CELLNUM] = { { -1, "W", "W", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "P", "P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "d", "d", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "T", "T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "R", "R", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "D", "D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "i", "i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "[", "[", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "A", "A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "I", "I", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 } }; /* General */ NHCmdPadCell cells_layout_general[NH_CMDPAD_CELLNUM] = { { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "e", "e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "l", "l", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "s", "s", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "E", "E", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\x04", "^D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "c", "c", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "o", "o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "p", "p", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, ":", ":", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, ",", ",", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 } }; /* game controls layout */ NHCmdPadCell cells_layout_game[NH_CMDPAD_CELLNUM] = { { -1, "S", "S", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "h", "h", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "C", "C", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "@", "@", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\\", "\\", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "O", "O", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "&", "&", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\x18", "^X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\x10", "^P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "X", "X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 } }; /* advanced movement layout */ NHCmdPadCell cells_layout_adv_movement[NH_CMDPAD_CELLNUM] = { { -1, "g", "g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT }, { -1, "G", "G", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT }, { -1, "m", "m", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT }, { -1, "M", "M", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)NH_LAYOUT_MOVEMENT }, { -1, "_", "_", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\x14", "^T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "j", "j", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "X", "X", 13, NH_CELL_LAYOUT_MENU, 1 , 0 } }; #else /* !WIN_CE_SMARTPHONE */ /* dimensions of the command pad */ #define NH_CMDPAD_ROWS 4 #define NH_CMDPAD_COLS 14 #define NH_CMDPAD_CELLNUM (NH_CMDPAD_COLS*NH_CMDPAD_ROWS) /* lowercase layout */ NHCmdPadCell cells_layout_mod1[NH_CMDPAD_ROWS*NH_CMDPAD_COLS] = { { -1, "7", "7", 1, NH_CELL_REG, 1, (void*)-1 }, { -1, "8", "8", 2, NH_CELL_REG, 1, (void*)-1 }, { -1, "9", "9", 3, NH_CELL_REG, 1, (void*)-1 }, { -1, "\x1b", "Esc", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 2 , NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for ESC */ { -1, "?", "?", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, ",", ",", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "/", "/", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, ":", ":", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, ";", ";", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "-", "-", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "#", "#", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "^", "^", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "4", "4", 4, NH_CELL_REG, 1, (void*)-1 }, { -1, "5", "5", 5, NH_CELL_REG, 1, (void*)-1 }, { -1, "6", "6", 6, NH_CELL_REG, 1, (void*)-1 }, { -1, " ", "CAP", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CAP, 2 , NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CAPS */ { -1, "a", "a", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "b", "b", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "c", "c", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "d", "d", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "e", "e", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "f", "f", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "g", "g", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "h", "h", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "i", "i", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "1", "1", 7, NH_CELL_REG, 1, (void*)-1 }, { -1, "2", "2", 8, NH_CELL_REG, 1, (void*)-1 }, { -1, "3", "3", 9, NH_CELL_REG, 1, (void*)-1 }, { -1, " ", "Shft", -NH_CMDPAD_FONT_NORMAL, NH_CELL_SHIFT, 2 , NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for shift */ { -1, "j", "j", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "k", "k", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "l", "l", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "m", "m", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "n", "n", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "o", "o", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "p", "p", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "q", "q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "r", "r", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 }, { -1, ".", ".", 11, NH_CELL_REG, 1, (void*)-1 }, { -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 }, { -1, " ", "Ctrl", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CTRL, 2 , NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CTRL */ { -1, "s", "s", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "t", "t", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "u", "u", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "v", "v", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "w", "w", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "x", "x", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "y", "y", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "z", "z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\\", "\\", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 } }; /* uppercase layout */ NHCmdPadCell cells_layout_mod2[-NH_CMDPAD_ROWS*-NH_CMDPAD_COLS] = { { -1, "7", "7", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "8", "8", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "9", "9", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\x1b", "Esc", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 2 , NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for ESC */ { -1, "?", "?", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "*", "*", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "[", "[", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "(", "(", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, ")", ")", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "+", "+", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "=", "=", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "\"", "\"", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "$", "$", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "4", "4", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "5", "5", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "6", "6", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, " ", "CAP", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CAP, 2 , NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CAPS */ { -1, "A", "A", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "B", "B", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "C", "C", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "D", "D", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "E", "E", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "F", "F", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "G", "G", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "H", "H", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "I", "I", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "1", "1", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "2", "2", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "3", "3", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, " ", "Shft", -NH_CMDPAD_FONT_NORMAL, NH_CELL_SHIFT, 2 , NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for shift */ { -1, "J", "J", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "K", "K", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "L", "L", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "M", "M", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "N", "N", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "O", "O", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "P", "P", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "Q", "Q", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "R", "R", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "<", "<", 10, NH_CELL_REG, 1, (void*)-1 }, { -1, "0", "0", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, ">", ">", 12, NH_CELL_REG, 1, (void*)-1 }, { -1, " ", "Ctrl", -NH_CMDPAD_FONT_NORMAL, NH_CELL_CTRL, 2 , NULL }, { -1, " ", "", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 0 , NULL }, /* complement for CTRL */ { -1, "S", "S", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "T", "T", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "U", "U", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "V", "V", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "W", "W", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "X", "X", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "Y", "Y", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "Z", "Z", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 }, { -1, "@", "@", -NH_CMDPAD_FONT_NORMAL, NH_CELL_REG, 1, (void*)-1 } }; #endif /* !WIN_CE_SMARTPHONE */ /*-------------------------------------------------------------------------*/ HWND mswin_init_command_window () { static int run_once = 0; HWND ret; /* register window class */ if( !run_once ) { register_command_window_class(); run_once = 1; } /* create window */ ret = CreateWindow( szNHCmdWindowClass, /* registered class name */ NULL, /* window name */ WS_CHILD | WS_CLIPSIBLINGS, /* window style */ 0, /* horizontal position of window - set it later */ 0, /* vertical position of window - set it later */ 0, /* window width - set it later */ 0, /* window height - set it later*/ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL ); /* window-creation data */ if( !ret ) { panic("Cannot create command window"); } return ret; } /*-------------------------------------------------------------------------*/ /* calculate mimimum window size */ void mswin_command_window_size (HWND hwnd, LPSIZE sz) { SIZE cell_size; PNHCmdWindow data; data = (PNHCmdWindow)GetWindowLong(hwnd, GWL_USERDATA); if( !data ) { sz->cx = sz->cy = 0; } else { CalculateCellSize(hwnd, &cell_size, sz); sz->cx = max( cell_size.cx*nhcmdlayout_columns(data->layout_current)+2*GetSystemMetrics(SM_CXBORDER), sz->cx ); sz->cy = max( cell_size.cy*nhcmdlayout_rows(data->layout_current)+2*GetSystemMetrics(SM_CYBORDER), sz->cy ); } } /*-------------------------------------------------------------------------*/ void register_command_window_class() { WNDCLASS wcex; PNHCmdLayout plt; ZeroMemory( &wcex, sizeof(wcex)); /* window class */ wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC)NHCommandWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = mswin_get_brush(NHW_KEYPAD, MSWIN_COLOR_BG); wcex.lpszMenuName = NULL; wcex.lpszClassName = szNHCmdWindowClass; if( !RegisterClass(&wcex) ) { panic("cannot register Map window class"); } /* create default command set */ nhcmdset_current = nhcmdset_default = nhcmdset_create(); #ifdef WIN_CE_SMARTPHONE plt = nhcmdlayout_create("General", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_general); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Movement", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_movement); nhcmdset_add(nhcmdset_current, plt ); plt = nhcmdlayout_create("Attack", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_attack); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Item Handling", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_item_handling); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Game Controls", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_game); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("Advanced Movement", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_adv_movement); nhcmdset_add(nhcmdset_current, plt); #else /* ! WIN_CE_SMARTPHONE */ plt = nhcmdlayout_create("lowercase", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_mod1); nhcmdset_add(nhcmdset_current, plt); plt = nhcmdlayout_create("uppercase", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(plt, cells_layout_mod2); nhcmdset_add(nhcmdset_current, plt); #endif /* WIN_CE_SMARTPHONE */ } /*-------------------------------------------------------------------------*/ LRESULT CALLBACK NHCommandWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; int i; switch (message) { case WM_CREATE: onCreate( hWnd, wParam, lParam ); break; case WM_PAINT: onPaint(hWnd); break; case WM_SIZE: LayoutCmdWindow(hWnd); break; case WM_LBUTTONDOWN: onMouseDown(hWnd, wParam, lParam); return 0; case WM_MOUSEMOVE: /* proceed only if if have mouse focus (set in onMouseDown() - left mouse button is pressed) */ if( GetCapture()==hWnd ) { onMouseMove(hWnd, wParam, lParam); return 0; } else { return 1; } break; case WM_LBUTTONUP: /* proceed only if if have mouse focus (set in onMouseDown()) */ if( GetCapture()==hWnd ) { onMouseUp(hWnd, wParam, lParam); return 0; } else { return 1; } break; case WM_DESTROY: data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); for(i=0; i<=NH_CMDPAD_FONT_MAX; i++ ) if( data->font[i] ) DeleteObject(data->font[i]); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return FALSE; } /*-------------------------------------------------------------------------*/ void onPaint(HWND hWnd) { PNHCmdWindow data; PAINTSTRUCT ps; HDC hDC; int x, y; TCHAR wbuf[BUFSZ]; HGDIOBJ saveFont; BITMAP bm; int cell_index; /* get window data */ data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); hDC = BeginPaint(hWnd, &ps); if( !IsRectEmpty(&ps.rcPaint) ) { HGDIOBJ oldBr; HBRUSH hbrPattern; COLORREF OldBg, OldFg; HPEN hPen; HGDIOBJ hOldPen; saveFont = SelectObject(hDC, data->font[NH_CMDPAD_FONT_NORMAL]); OldBg = SetBkColor(hDC, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_BG)); OldFg = SetTextColor(hDC, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_FG)); GetObject(data->images, sizeof(BITMAP), (LPVOID)&bm); hbrPattern = CreatePatternBrush(data->images); hPen = CreatePen(PS_SOLID, 1, mswin_get_color(NHW_KEYPAD, MSWIN_COLOR_FG)); for( x=0, cell_index = 0; xlayout_current); x++ ) for( y=0; ylayout_current); y++, cell_index++ ) { RECT cell_rt; POINT pt[5]; PNHCmdPadCell p_cell_data; p_cell_data = nhcmdlayout_cell_direct(data->layout_current, cell_index); /* calculate the cell rectangle */ cell_rt.left = data->cells[cell_index].orig.x; cell_rt.top = data->cells[cell_index].orig.y; cell_rt.right = data->cells[cell_index].orig.x + data->cell_size.cx*p_cell_data->mult; cell_rt.bottom = data->cells[cell_index].orig.y + data->cell_size.cy; /* draw border */ hOldPen = SelectObject(hDC, hPen); pt[0].x = cell_rt.left; pt[0].y = cell_rt.top; pt[1].x = cell_rt.right; pt[1].y = cell_rt.top; pt[2].x = cell_rt.right; pt[2].y = cell_rt.bottom; pt[3].x = cell_rt.left; pt[3].y = cell_rt.bottom; pt[4].x = cell_rt.left; pt[4].y = cell_rt.top; Polyline(hDC, pt, 5); SelectObject(hDC, hOldPen); /* calculate clipping rectangle for the text */ cell_rt.left++; cell_rt.top ++; cell_rt.right--; cell_rt.bottom--; /* draw the cell text */ if( p_cell_data->image<=0 ) { SelectObject(hDC, data->font[ -p_cell_data->image ]); DrawText(hDC, NH_A2W(p_cell_data->text, wbuf, BUFSZ), strlen(p_cell_data->text), &cell_rt, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX ); } else { /* draw bitmap */ int bmOffset; RECT bitmap_rt; bmOffset = (p_cell_data->image - 1)*bm.bmHeight; bitmap_rt.left = ((cell_rt.left+cell_rt.right) - min(bm.bmHeight, (cell_rt.right-cell_rt.left)))/2; bitmap_rt.top = ((cell_rt.bottom+cell_rt.top) - min(bm.bmHeight, (cell_rt.bottom-cell_rt.top)))/2; bitmap_rt.right = bitmap_rt.left + min(bm.bmHeight, (cell_rt.right-cell_rt.left)); bitmap_rt.bottom = bitmap_rt.top + min(bm.bmHeight, (cell_rt.bottom-cell_rt.top)); SetBrushOrgEx(hDC, bitmap_rt.left-bmOffset, bitmap_rt.top, NULL); oldBr = SelectObject(hDC, hbrPattern); PatBlt( hDC, bitmap_rt.left, bitmap_rt.top, bitmap_rt.right-bitmap_rt.left, bitmap_rt.bottom-bitmap_rt.top, PATCOPY); SelectObject(hDC, oldBr); } /* invert the cell if it is selected */ if( data->cells[cell_index].state == NH_CST_CHECKED ) { IntersectRect( &cell_rt, &cell_rt, &ps.rcPaint); PatBlt( hDC, cell_rt.left, cell_rt.top, cell_rt.right - cell_rt.left, cell_rt.bottom - cell_rt.top, DSTINVERT ); } } SetTextColor(hDC, OldFg); SetBkColor(hDC, OldBg); SelectObject(hDC, saveFont); DeleteObject(hbrPattern); DeleteObject(hPen); } EndPaint(hWnd, &ps); } /*-------------------------------------------------------------------------*/ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; /* set window data */ data = (PNHCmdWindow)malloc(sizeof(NHCmdWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHCmdWindow)); SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); data->active_cell = -1; /* load images bitmap */ data->images = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_KEYPAD)); if( !data->images ) panic("cannot load keypad bitmap"); /* create default layouts */ data->layout_current = 0; data->layout_save = 0; data->cells = 0; #if defined(WIN_CE_SMARTPHONE) data->layout_selected = nhcmdset_get(nhcmdset_current, 0); #endif /* set default layout */ SetCmdWindowLayout(hWnd, nhcmdset_get(nhcmdset_current, 0)); } /*-------------------------------------------------------------------------*/ void LayoutCmdWindow(HWND hWnd) { RECT clrt; SIZE windowSize; PNHCmdWindow data; int i, j; int x, y; LOGFONT lgfnt; int index; GetClientRect(hWnd, &clrt); if( IsRectEmpty(&clrt) ) return; data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); if( !data->layout_current ) return; /* calculate cell size */ windowSize.cx = clrt.right-clrt.left; windowSize.cy = clrt.bottom-clrt.top; CalculateCellSize(hWnd, &data->cell_size, &windowSize); /* initialize display cells aray */ x = 0; y = 0; for( i=0, index=0; ilayout_current); i++ ) { for( j=0; jlayout_current); j++, index++ ) { data->cells[index].orig.x = x; data->cells[index].orig.y = y; data->cells[index].type = nhcmdlayout_cell_direct(data->layout_current, index)->type; switch(data->cells[index].type) { case NH_CELL_CTRL: data->cells[index].state = data->is_ctrl? NH_CST_CHECKED : 0; break; case NH_CELL_CAP: data->cells[index].state = data->is_caps? NH_CST_CHECKED : 0; break; case NH_CELL_SHIFT: data->cells[index].state = data->is_shift? NH_CST_CHECKED : 0; break; default: data->cells[index].state = 0; } x += data->cell_size.cx * nhcmdlayout_cell_direct(data->layout_current, index)->mult; } x = 0; y += data->cell_size.cy; } /* create font for display cell text */ for(i=0; i<=NH_CMDPAD_FONT_MAX; i++ ) if( data->font[i] ) DeleteObject(data->font[i]); ZeroMemory( &lgfnt, sizeof(lgfnt) ); lgfnt.lfHeight = data->cell_size.cy; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = ANSI_CHARSET; // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_CHARACTER_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if( iflags.wc_font_message && *iflags.wc_font_message ) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W( iflags.wc_font_message, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = VARIABLE_PITCH; // pitch and family } data->font[NH_CMDPAD_FONT_NORMAL] = CreateFontIndirect(&lgfnt); InvalidateRect(hWnd, NULL, TRUE); } /*-------------------------------------------------------------------------*/ void SetCmdWindowLayout(HWND hWnd, PNHCmdLayout layout) { PNHCmdWindow data; int size; data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); if( data->layout_current == layout ) return; data->layout_current = layout; size = sizeof(NHCmdPadLayoutCell)*nhcmdlayout_rows(layout)*nhcmdlayout_columns(layout); data->cells = (PNHCmdPadLayoutCell)realloc(data->cells, size); ZeroMemory(data->cells, size); LayoutCmdWindow(hWnd); } /*-------------------------------------------------------------------------*/ void onMouseDown(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; POINT mpt; /* get mouse coordinates */ mpt.x = LOWORD(lParam); mpt.y = HIWORD(lParam); /* map mouse coordinates to the display cell */ data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); data->active_cell = CellFromPoint(data, mpt); if( data->active_cell==-1 ) return; /* set mouse focus to the current window */ SetCapture(hWnd); /* invert the selection */ HighlightCell(hWnd, data->active_cell, (data->cells[data->active_cell].state!=NH_CST_CHECKED) ); } /*-------------------------------------------------------------------------*/ void onMouseMove(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; POINT mpt; int newActiveCell; /* get mouse coordinates */ mpt.x = LOWORD(lParam); mpt.y = HIWORD(lParam); /* map mouse coordinates to the display cell */ data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); newActiveCell = CellFromPoint(data, mpt); if( data->active_cell == -1 ) return; /* if mouse is within orginal display cell - select the cell otherwise clear the selection */ switch( nhcmdlayout_cell_direct(data->layout_current, data->active_cell)->type ) { case NH_CELL_REG: HighlightCell(hWnd, data->active_cell, (newActiveCell==data->active_cell) ); break; case NH_CELL_CTRL: HighlightCell(hWnd, data->active_cell, ((newActiveCell==data->active_cell)? !data->is_ctrl : data->is_ctrl) ); break; case NH_CELL_CAP: HighlightCell(hWnd, data->active_cell, ((newActiveCell==data->active_cell)? !data->is_caps : data->is_caps) ); break; } } /*-------------------------------------------------------------------------*/ void onMouseUp(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHCmdWindow data; /* release mouse capture */ ReleaseCapture(); /* get active display cell */ data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); if( data->active_cell == -1 ) return; ActivateCell(hWnd, data->active_cell); data->active_cell = -1; } /*-------------------------------------------------------------------------*/ void ActivateCell(HWND hWnd, int cell) { PNHCmdWindow data; PNHCmdPadCell p_cell_data; int i; data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); if( !data ) return; p_cell_data = nhcmdlayout_cell_direct(data->layout_current, cell); /* act depending on the cell type: CAPS - change layout CTRL - modify CTRL status REG - place keyboard event on the nethack input queue */ switch( p_cell_data->type ) { case NH_CELL_REG: if( data->is_ctrl ) { PushNethackCommand(p_cell_data->f_char, 1); data->is_ctrl = 0; for( i=0; ilayout_current)*nhcmdlayout_columns(data->layout_current); i++ ) { if( nhcmdlayout_cell_direct(data->layout_current, i)->type == NH_CELL_CTRL ) { HighlightCell(hWnd, i, data->is_ctrl); } } } else { PushNethackCommand(p_cell_data->f_char, 0); } HighlightCell(hWnd, cell, FALSE); // select a new layout if present i = (int)p_cell_data->data; if( i==-1 ) { if( data->layout_save ) SetCmdWindowLayout(hWnd, data->layout_save); data->layout_save = NULL; } else { if( !data->layout_save ) data->layout_save = data->layout_current; SetCmdWindowLayout(hWnd, nhcmdset_get(nhcmdset_current, i)); } if( !data->is_shift ) break; // else fall through and reset the shift case NH_CELL_SHIFT: data->is_shift = !data->is_shift; SetCmdWindowLayout( hWnd, (data->is_shift ^ data->is_caps)? nhcmdset_get(nhcmdset_current, 1) : nhcmdset_get(nhcmdset_current, 0) ); data->cells[cell].state = data->is_shift? NH_CST_CHECKED : 0; InvalidateRect(hWnd, NULL, TRUE); break; case NH_CELL_CTRL: data->is_ctrl = !data->is_ctrl; HighlightCell(hWnd, cell, data->is_ctrl); break; case NH_CELL_CAP: data->is_caps = !data->is_caps; SetCmdWindowLayout( hWnd, (data->is_shift ^ data->is_caps)? nhcmdset_get(nhcmdset_current, 1) : nhcmdset_get(nhcmdset_current, 0) ); data->cells[cell].state = data->is_caps? NH_CST_CHECKED : 0; InvalidateRect(hWnd, NULL, TRUE); break; case NH_CELL_LAYOUT_NEW: { PNHCmdLayout pLayout; HighlightCell(hWnd, cell, FALSE); pLayout = (PNHCmdLayout)p_cell_data->data; if( pLayout ) { SetCmdWindowLayout(hWnd, pLayout); } } break; case NH_CELL_LAYOUT_MENU: { winid wid; int i; anything any; menu_item* selected = 0; PNHCmdSet pSet; HighlightCell(hWnd, cell, FALSE); pSet = (PNHCmdSet)p_cell_data->data; if( !pSet ) pSet = nhcmdset_default; wid = mswin_create_nhwindow(NHW_MENU); mswin_start_menu(wid); for( i=0; ilayout_selected = (PNHCmdLayout)selected[0].item.a_void; #endif SetCmdWindowLayout(hWnd, (PNHCmdLayout)selected[0].item.a_void ); } } break; } } /*-------------------------------------------------------------------------*/ int CellFromPoint(PNHCmdWindow data, POINT pt ) { int i; for( i=0; ilayout_current)*nhcmdlayout_columns(data->layout_current); i++ ) { RECT cell_rt; cell_rt.left = data->cells[i].orig.x; cell_rt.top = data->cells[i].orig.y; cell_rt.right = data->cells[i].orig.x + data->cell_size.cx*nhcmdlayout_cell_direct(data->layout_current, i)->mult; cell_rt.bottom = data->cells[i].orig.y + data->cell_size.cy; if( PtInRect(&cell_rt, pt) ) return i; } return -1; } /*-------------------------------------------------------------------------*/ void CalculateCellSize(HWND hWnd, LPSIZE pSize, LPSIZE pWindowSize) { HDC hdc; PNHCmdWindow data; data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); if( !data ) return; hdc = GetDC(hWnd); /* if windows size is specified - attempt ro stretch cells across the the window size. If not - make default cell size based on 10 points font. Make sure that cell cesize does not exceeds 20 points */ if( pWindowSize->cx>0 ) pSize->cx = pWindowSize->cx/nhcmdlayout_columns(data->layout_current); else pSize->cx = 10*GetDeviceCaps(hdc, LOGPIXELSX)/72; pSize->cx = min(pSize->cx, 20*GetDeviceCaps(hdc, LOGPIXELSX)/72 ); if( pWindowSize->cy>0 ) pSize->cy = pWindowSize->cy/nhcmdlayout_rows(data->layout_current); else pSize->cy = 10*GetDeviceCaps(hdc, LOGPIXELSY)/72; pSize->cy = min(pSize->cy, 20*GetDeviceCaps(hdc, LOGPIXELSY)/72 ); ReleaseDC(hWnd, hdc); } /*-------------------------------------------------------------------------*/ void HighlightCell(HWND hWnd, int cell, BOOL isSelected) { HDC hDC; PNHCmdWindow data; int prevState; data = (PNHCmdWindow)GetWindowLong(hWnd, GWL_USERDATA); prevState = data->cells[cell].state; data->cells[cell].state = (isSelected)? NH_CST_CHECKED : 0; if( prevState!=data->cells[cell].state ) { hDC = GetDC(hWnd); PatBlt( hDC, data->cells[cell].orig.x+1, data->cells[cell].orig.y+1, data->cell_size.cx*nhcmdlayout_cell_direct(data->layout_current, cell)->mult - 2, data->cell_size.cy - 2, DSTINVERT ); ReleaseDC(hWnd, hDC); } } /*-------------------------------------------------------------------------*/ void PushNethackCommand( const char* cmd_char_str, int is_ctrl ) { while( *cmd_char_str ) { if( is_ctrl ) { NHEVENT_KBD( C(*cmd_char_str) ); } else { NHEVENT_KBD( *cmd_char_str ); } cmd_char_str++; } } /*-------------------------------------------------------------------------*/ /*------------------- keyboard keys layout functions ----------------------*/ /*-------------------------------------------------------------------------*/ PNHCmdLayout nhcmdlayout_create(const char* name, int rows, int columns) { PNHCmdLayout p; int i; i = sizeof(NHCmdLayout)+rows*columns*sizeof(NHCmdPadCell); p = (PNHCmdLayout)malloc(i); ZeroMemory(p, i); p->rows = rows; p->columns = columns; strncpy(p->name, name, sizeof(p->name)-1); for(i=0; icells[i].cmd_code = -1; p->cells[i].image = -NH_CMDPAD_FONT_NORMAL; p->cells[i].type = 1; p->cells[i].mult = 1; } return p; } /*-------------------------------------------------------------------------*/ void nhcmdlayout_init( PNHCmdLayout p, PNHCmdPadCell cells ) { memcpy(p->cells, cells, p->rows*p->columns*sizeof(NHCmdPadCell)); } void nhcmdlayout_destroy(PNHCmdLayout p) { free(p); } /*-------------------------------------------------------------------------*/ /*----------------- keyboard keys layout set functions --------------------*/ /*-------------------------------------------------------------------------*/ PNHCmdSet nhcmdset_create() { PNHCmdSet p; p = (PNHCmdSet)malloc(sizeof(NHCmdSet)); ZeroMemory(p, sizeof(NHCmdSet)); return p; } /*-------------------------------------------------------------------------*/ int nhcmdset_count(PNHCmdSet p) { assert(p); return p->count; } /*-------------------------------------------------------------------------*/ PNHCmdLayout nhcmdset_get( PNHCmdSet p, int index ) { assert(p); assert(index>=0 && indexcount); return p->elements[index].layout; } /*-------------------------------------------------------------------------*/ const char* nhcmdset_get_name( PNHCmdSet p, int index ) { assert(p); assert(index>=0 && indexcount); return p->elements[index].layout->name; } /*-------------------------------------------------------------------------*/ void nhcmdset_add( PNHCmdSet p, PNHCmdLayout layout ) { assert(p); assert(p->countelements[p->count].layout = layout; p->elements[p->count].free_on_destroy = 0; p->count++; } /*-------------------------------------------------------------------------*/ void nhcmdset_destroy(PNHCmdSet p) { int i=0; assert(p); for(i=0; icount; i++) { if( p->elements[i].free_on_destroy ) { nhcmdlayout_destroy( p->elements[i].layout ); } } free(p); } /*-------------------------------------------------------------------------*/ #if defined(WIN_CE_SMARTPHONE) /* special keypad input handling for SmartPhone the phone keypad maps to VK_* as shown below. some keys might not be present, e.g. VK_TFLIP sofkey1 softkey2 VK_TSOFT1, VK_TSOFT2 ^ VK_TUP < + > VK_TLEFT, VK_TACTION, VK_TRIGHT v VK_TDOWN home back VK_THOME, VK_TBACK talk end VK_TTALK, VK_TEND 1 2 3 VK_T0..VK_T9 4 5 6 ... 7 8 9 ... * 0 # VK_TSTAR, VK_TPOUND other buttons include VK_TRECORD VK_TPOWER, VK_TVOLUMEUP, VK_TVOLUMEDOWN VK_TFLIP */ BOOL NHSPhoneTranslateKbdMessage(WPARAM wParam, LPARAM lParam, BOOL keyDown) { PNHCmdWindow data; int index = -1; /* get window data */ data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA); if( !data ) return FALSE; switch (wParam) { case VK_T0: index = 10; break; case VK_T1: index = 0; break; case VK_T2: index = 1; break; case VK_T3: index = 2; break; case VK_T4: index = 3; break; case VK_T5: index = 4; break; case VK_T6: index = 5; break; case VK_T7: index = 6; break; case VK_T8: index = 7; break; case VK_T9: index = 8; break; case VK_TSTAR: index = 9; break; case VK_TPOUND: index = 11; break; } if( index>=0 ) { HighlightCell(GetNHApp()->hCmdWnd, index, keyDown); if( keyDown ) ActivateCell(GetNHApp()->hCmdWnd, index); return TRUE; } else { return FALSE; } } /*-------------------------------------------------------------------------*/ void NHSPhoneSetKeypadFromString(const char* str) { PNHCmdWindow data; PNHCmdSet p = 0; PNHCmdLayout layout_prev = 0; PNHCmdLayout layout_cur = 0; char buf[2][BUFSZ]; int i, lcount; char *s; assert(NH_CMDPAD_ROWS==4); data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA); if( !data ) return; p = nhcmdset_create(); ZeroMemory(buf, sizeof(buf)); if( sscanf(str, "%s or %s", buf[1], buf[0])!=2 ) { ZeroMemory(buf, sizeof(buf)); strncpy(buf[0], str, sizeof(buf[0])-1); } lcount = 10; /* create new layout on the first iteration */ for(i=0; i<2; i++) { s = buf[i]; while( *s ) { char c_start, c_end, c_char; /* parse character ranges */ if( isalnum( (c_start=s[0]) ) && s[1]=='-' && isalnum( (c_end=s[2]) ) ) { s += 2; } else { c_start = c_end = *s; } for( c_char=c_start; c_char<=c_end; c_char++ ) { if( lcount>=10 ) { /* create layout */ lcount = 0; layout_prev = layout_cur; layout_cur = nhcmdlayout_create("noname", NH_CMDPAD_ROWS, NH_CMDPAD_COLS); nhcmdlayout_init(layout_cur, cells_layout_menu); nhcmdlayout_cell(layout_cur, 3, 0)->data = layout_prev; nhcmdlayout_cell(layout_cur, 3, 2)->data = 0; nhcmdset_add( p, layout_cur ); p->elements[p->count-1].free_on_destroy = 1; if( layout_prev ) { nhcmdlayout_cell(layout_prev, 3, 2)->data = layout_cur; } } if( lcount==9 ) lcount=10; // skip '#' nhcmdlayout_cell_direct(layout_cur, lcount)->f_char[0] = c_char; if( c_char == '\033' ) { strcpy(nhcmdlayout_cell_direct(layout_cur, lcount)->text, "esc"); nhcmdlayout_cell_direct(layout_cur, lcount)->image = 14; /* 14 is a ESC symbol in IDB_KEYPAD */ } else { nhcmdlayout_cell_direct(layout_cur, lcount)->text[0] = c_char; nhcmdlayout_cell_direct(layout_cur, lcount)->text[1] = '\x0'; } /* increment character count in the current layout */ lcount++; } /* prepareg next charcter from the source string */ s++; } } /* install the new set */ if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current ); nhcmdset_current = p; SetCmdWindowLayout( GetNHApp()->hCmdWnd, nhcmdset_get(nhcmdset_current, 0) ); } /*-------------------------------------------------------------------------*/ void NHSPhoneSetKeypadDirection() { PNHCmdWindow data; data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA); if( !data ) return; if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current ); nhcmdset_current = nhcmdset_default; SetCmdWindowLayout( GetNHApp()->hCmdWnd, nhcmdset_get(nhcmdset_current, NH_LAYOUT_MOVEMENT) ); } /*-------------------------------------------------------------------------*/ void NHSPhoneSetKeypadDefault() { PNHCmdWindow data; data = (PNHCmdWindow)GetWindowLong(GetNHApp()->hCmdWnd, GWL_USERDATA); if( !data ) return; if( nhcmdset_current!=nhcmdset_default ) nhcmdset_destroy( nhcmdset_current ); nhcmdset_current = nhcmdset_default; SetCmdWindowLayout( GetNHApp()->hCmdWnd, data->layout_selected ? data->layout_selected : nhcmdset_get(nhcmdset_current, 0) ); } #endif /* defined (WIN_CE_SMARTHPONE) */ nethack-3.4.3/sys/wince/mhcmd.h0100644000000000000000000000135707764735041015044 0ustar rootroot/* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINCMDWindow_h #define MSWINCMDWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_command_window (); /* if either sz->cx or sz->cy are already set this function will no modify it. It will adjust them to the minimum size required by the command window */ void mswin_command_window_size (HWND hwnd, LPSIZE sz); #if defined(WIN_CE_SMARTPHONE) /* special keypad input handling for SmartPhone */ BOOL NHSPhoneTranslateKbdMessage(WPARAM wParam, LPARAM lParam, BOOL keyDown); void NHSPhoneSetKeypadFromString(const char* str); void NHSPhoneSetKeypadDirection(); void NHSPhoneSetKeypadDefault(); #endif #endif /* MSWINCMDWindow_h */ nethack-3.4.3/sys/wince/mhcolor.c0100644000000000000000000001631007764735041015405 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* color management and such */ #include "winMS.h" #include "mhcolor.h" #define TOTAL_BRUSHES 10 #define NHBRUSH_CODE(win, type) ((((win)&0xFF)<<8)|((type)&0xFF)) struct t_brush_table { int code; HBRUSH brush; COLORREF color; }; static struct t_brush_table brush_table[TOTAL_BRUSHES]; static int max_brush = 0; static struct t_brush_table default_brush_table[] = { { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_MESSAGE, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_TEXT, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_KEYPAD, MSWIN_COLOR_FG), NULL, RGB(0, 0, 0) }, { NHBRUSH_CODE(NHW_MAP, MSWIN_COLOR_FG), NULL, RGB(96, 96, 96) }, { NHBRUSH_CODE(NHW_MENU, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) }, { NHBRUSH_CODE(NHW_MESSAGE, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) }, { NHBRUSH_CODE(NHW_STATUS, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) }, { NHBRUSH_CODE(NHW_TEXT, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) }, { NHBRUSH_CODE(NHW_KEYPAD, MSWIN_COLOR_BG), NULL, RGB(255, 255, 255) }, { NHBRUSH_CODE(NHW_MAP, MSWIN_COLOR_BG), NULL, RGB(192, 192, 192) }, { -1, NULL, RGB(0, 0, 0) } }; static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr); typedef struct ctv { const char *colorstring; COLORREF colorvalue; } color_table_value; /* * The color list here is a combination of: * NetHack colors. (See mhmap.c) * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 ) */ static color_table_value color_table[] = { /* NetHack colors */ { "black", RGB(0x55, 0x55, 0x55)}, { "red", RGB(0xFF, 0x00, 0x00)}, { "green", RGB(0x00, 0x80, 0x00)}, { "brown", RGB(0xA5, 0x2A, 0x2A)}, { "blue", RGB(0x00, 0x00, 0xFF)}, { "magenta", RGB(0xFF, 0x00, 0xFF)}, { "cyan", RGB(0x00, 0xFF, 0xFF)}, { "orange", RGB(0xFF, 0xA5, 0x00)}, { "brightgreen", RGB(0x00, 0xFF, 0x00)}, { "yellow", RGB(0xFF, 0xFF, 0x00)}, { "brightblue", RGB(0x00, 0xC0, 0xFF)}, { "brightmagenta", RGB(0xFF, 0x80, 0xFF)}, { "brightcyan", RGB(0x80, 0xFF, 0xFF)}, { "white", RGB(0xFF, 0xFF, 0xFF)}, /* Remaining HTML colors */ { "trueblack", RGB(0x00, 0x00, 0x00)}, { "gray", RGB(0x80, 0x80, 0x80)}, { "grey", RGB(0x80, 0x80, 0x80)}, { "purple", RGB(0x80, 0x00, 0x80)}, { "silver", RGB(0xC0, 0xC0, 0xC0)}, { "maroon", RGB(0x80, 0x00, 0x00)}, { "fuchsia", RGB(0xFF, 0x00, 0xFF)}, /* = NetHack magenta */ { "lime", RGB(0x00, 0xFF, 0x00)}, /* = NetHack bright green */ { "olive", RGB(0x80, 0x80, 0x00)}, { "navy", RGB(0x00, 0x00, 0x80)}, { "teal", RGB(0x00, 0x80, 0x80)}, { "aqua", RGB(0x00, 0xFF, 0xFF)}, /* = NetHack cyan */ { "", RGB(0x00, 0x00, 0x00)}, }; typedef struct ctbv { char *colorstring; int syscolorvalue; } color_table_brush_value; static color_table_brush_value color_table_brush[] = { { "activeborder", COLOR_ACTIVEBORDER }, { "activecaption", COLOR_ACTIVECAPTION }, { "appworkspace", COLOR_APPWORKSPACE }, { "background", COLOR_BACKGROUND }, { "btnface", COLOR_BTNFACE }, { "btnshadow", COLOR_BTNSHADOW }, { "btntext", COLOR_BTNTEXT }, { "captiontext", COLOR_CAPTIONTEXT }, { "graytext", COLOR_GRAYTEXT }, { "greytext", COLOR_GRAYTEXT }, { "highlight", COLOR_HIGHLIGHT }, { "highlighttext", COLOR_HIGHLIGHTTEXT }, { "inactiveborder", COLOR_INACTIVEBORDER }, { "inactivecaption", COLOR_INACTIVECAPTION }, { "menu", COLOR_MENU }, { "menutext", COLOR_MENUTEXT }, { "scrollbar", COLOR_SCROLLBAR }, { "window", COLOR_WINDOW }, { "windowframe", COLOR_WINDOWFRAME }, { "windowtext", COLOR_WINDOWTEXT }, { "", -1 }, }; void mswin_init_color_table() { int i; struct t_brush_table* p; /* cleanup */ for( i=0; icode != -1; p++ ) { if( p->code==brush_table[i].code ) { brush_table[i].brush = CreateSolidBrush(p->color); brush_table[i].color = p->color; } } } } } HBRUSH mswin_get_brush(int win_type, int color_index) { int i; for(i=0; icolorstring && _stricmp(ctv_ptr->colorstring, colorstring)) ++ctv_ptr; if (*ctv_ptr->colorstring) { *colorptr = ctv_ptr->colorvalue; } else { while (*ctbv_ptr->colorstring && _stricmp(ctbv_ptr->colorstring, colorstring)) ++ctbv_ptr; if (*ctbv_ptr->colorstring) { *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue); *colorptr = GetSysColor(ctbv_ptr->syscolorvalue); } } } if (max_brush > TOTAL_BRUSHES) panic("Too many colors!"); *brushptr = CreateSolidBrush(*colorptr); } nethack-3.4.3/sys/wince/mhcolor.h0100644000000000000000000000076207764735041015416 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* color management functions */ #ifndef MSWINColor_h #define MSWINColor_h #define MSWIN_COLOR_BG 0 #define MSWIN_COLOR_FG 1 #define SYSCLR_TO_BRUSH(x) ((HBRUSH)((x) + 1)) extern void mswin_init_color_table(); extern HBRUSH mswin_get_brush(int win_type, int color_index); extern COLORREF mswin_get_color(int win_type, int color_index); #endif /* MSWINColor_h */ nethack-3.4.3/sys/wince/mhdlg.c0100644000000000000000000005502007764735041015036 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* various dialog boxes are defined here */ #include "winMS.h" #include "hack.h" #include "func_tab.h" #include "mhdlg.h" #include "mhmain.h" #define CheckDlgButton(dlg, btn_id, st) SendDlgItemMessage((dlg), (btn_id), BM_SETCHECK, (WPARAM)(st), 0) /*---------------------------------------------------------------*/ /* data for getlin dialog */ struct getlin_data { const char* question; char* result; size_t result_size; }; LRESULT CALLBACK GetlinDlgProc(HWND, UINT, WPARAM, LPARAM); int mswin_getlin_window ( const char *question, char *result, size_t result_size ) { int ret; struct getlin_data data; /* initilize dialog data */ ZeroMemory(&data, sizeof(data)); data.question = question; data.result = result; data.result_size = result_size; /* create modal dialog window */ ret = DialogBoxParam( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_GETLIN), GetNHApp()->hMainWnd, GetlinDlgProc, (LPARAM)&data ); if( ret==-1 ) panic("Cannot create getlin window"); return ret; } LRESULT CALLBACK GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct getlin_data* data; RECT main_rt, text_rt, dlg_rt, edit_rt; SIZE dlg_sz; TCHAR wbuf[BUFSZ]; HDC hdc; HWND control; HWND hwndMap; #if defined(WIN_CE_POCKETPC) SHInputDialog(hWnd, message, wParam); #endif switch (message) { case WM_INITDIALOG: data = (struct getlin_data*)lParam; SetWindowText(hWnd, NH_A2W(data->question, wbuf, sizeof(wbuf))); SetWindowLong(hWnd, GWL_USERDATA, lParam); /* get title text width */ SetRect(&text_rt, 0, 0, 100, 50); hdc = GetWindowDC(hWnd); DrawText(hdc, wbuf, _tcslen(wbuf), &text_rt, DT_CALCRECT | DT_SINGLELINE | DT_NOPREFIX | DT_LEFT | DT_VCENTER ); ReleaseDC(hWnd, hdc); /* center dialog in the main window */ GetWindowRect(hWnd, &dlg_rt); hwndMap = mswin_hwnd_from_winid(WIN_MAP); GetWindowRect( IsWindow(hwndMap)? hwndMap : GetNHApp()->hMainWnd, &main_rt); dlg_sz.cx = max(dlg_rt.right-dlg_rt.left, min( text_rt.right-text_rt.left+GetSystemMetrics(SM_CXICON), main_rt.right-main_rt.left ) ); dlg_sz.cy = min(dlg_rt.bottom - dlg_rt.top, main_rt.bottom - main_rt.top); dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow( hWnd, (main_rt.left+main_rt.right-dlg_sz.cx)/2, (main_rt.top+main_rt.bottom-dlg_sz.cy)/2, dlg_sz.cx, dlg_sz.cy, TRUE ); /* change layout of controls */ GetClientRect(hWnd, &dlg_rt); control = GetDlgItem(hWnd, IDC_GETLIN_EDIT); GetWindowRect(control, &edit_rt); MoveWindow( control, 0, 0, dlg_rt.right - dlg_rt.left, edit_rt.bottom - edit_rt.top, TRUE ); control = GetDlgItem(hWnd, IDOK); GetWindowRect(control, &text_rt); MoveWindow( control, 0, edit_rt.bottom - edit_rt.top, (dlg_rt.right-dlg_rt.left)/2, text_rt.bottom - text_rt.top, TRUE ); control = GetDlgItem(hWnd, IDCANCEL); GetWindowRect(control, &text_rt); MoveWindow( control, (dlg_rt.right-dlg_rt.left)/2, edit_rt.bottom - edit_rt.top, (dlg_rt.right-dlg_rt.left)/2, text_rt.bottom - text_rt.top, TRUE ); #if defined(WIN_CE_SMARTPHONE) NHSPhoneDialogSetup(hWnd, TRUE, FALSE); #endif /* set focus to the edit control */ SetFocus(GetDlgItem(hWnd, IDC_GETLIN_EDIT)); /* tell windows that we've set the focus */ return FALSE; break; case WM_COMMAND: { TCHAR wbuf[BUFSZ]; switch (LOWORD(wParam)) { /* OK button was pressed */ case IDOK: data = (struct getlin_data*)GetWindowLong(hWnd, GWL_USERDATA); SendDlgItemMessage(hWnd, IDC_GETLIN_EDIT, WM_GETTEXT, (WPARAM)sizeof(wbuf), (LPARAM)wbuf ); NH_W2A(wbuf, data->result, data->result_size); /* Fall through. */ /* cancel button was pressed */ case IDCANCEL: EndDialog(hWnd, wParam); return TRUE; } } break; #if defined(WIN_CE_SMARTPHONE) case WM_HOTKEY: if(VK_TBACK == HIWORD(lParam)) { SHSendBackToFocusWindow(message, wParam, lParam); } break; #endif } /* end switch (message) */ return FALSE; } /*---------------------------------------------------------------*/ /* dialog data for the list of extended commands */ struct extcmd_data { int* selection; }; LRESULT CALLBACK ExtCmdDlgProc(HWND, UINT, WPARAM, LPARAM); int mswin_ext_cmd_window (int* selection) { int ret; struct extcmd_data data; /* init dialog data */ ZeroMemory(&data, sizeof(data)); *selection = -1; data.selection = selection; /* create modal dialog window */ ret = DialogBoxParam( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_EXTCMD), GetNHApp()->hMainWnd, ExtCmdDlgProc, (LPARAM)&data ); if( ret==-1 ) panic("Cannot create extcmd window"); return ret; } LRESULT CALLBACK ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct extcmd_data* data; RECT main_rt, dlg_rt; SIZE dlg_sz; int i; const char *ptr; TCHAR wbuf[255]; switch (message) { case WM_INITDIALOG: data = (struct extcmd_data*)lParam; SetWindowLong(hWnd, GWL_USERDATA, lParam); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hWnd, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow( hWnd, (main_rt.left+main_rt.right-dlg_sz.cx)/2, (main_rt.top+main_rt.bottom-dlg_sz.cy)/2, dlg_sz.cx, dlg_sz.cy, TRUE ); /* fill combobox with extended commands */ for(i=0; (ptr=extcmdlist[i].ef_txt); i++) { SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(ptr, wbuf, sizeof(wbuf)) ); } #if defined(WIN_CE_SMARTPHONE) NHSPhoneDialogSetup(hWnd, FALSE, FALSE); GetClientRect(hWnd, &dlg_rt); MoveWindow(GetDlgItem(hWnd, IDC_EXTCMD_LIST), dlg_rt.left, dlg_rt.top, dlg_rt.right-dlg_rt.left, dlg_rt.bottom-dlg_rt.top, TRUE); #endif /* set focus to the list control */ SetFocus(GetDlgItem(hWnd, IDC_EXTCMD_LIST)); /* tell windows we set the focus */ return FALSE; break; case WM_COMMAND: data = (struct extcmd_data*)GetWindowLong(hWnd, GWL_USERDATA); switch (LOWORD(wParam)) { /* OK button ws clicked */ case IDOK: *data->selection = SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM)0, (LPARAM)0 ); if( *data->selection==LB_ERR ) *data->selection = -1; /* Fall through. */ /* CANCEL button ws clicked */ case IDCANCEL: EndDialog(hWnd, wParam); return TRUE; /* list control events */ case IDC_EXTCMD_LIST: switch(HIWORD(wParam)) { case LBN_DBLCLK: /* double click within the list wParam The low-order word is the list box identifier. The high-order word is the notification message. lParam Handle to the list box */ *data->selection = SendMessage((HWND)lParam, LB_GETCURSEL, (WPARAM)0, (LPARAM)0); if( *data->selection==LB_ERR ) *data->selection = -1; EndDialog(hWnd, IDOK); return TRUE; } break; } } return FALSE; } /*---------------------------------------------------------------*/ /* player selector dialog data */ struct plsel_data { int* selection; }; BOOL CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM); static void plselInitDialog(HWND hWnd); static void plselAdjustLists(HWND hWnd, int changed_opt); static int plselFinalSelection(HWND hWnd, int* selection); int mswin_player_selection_window ( int* selection ) { int ret; struct plsel_data data; /* init dialog data */ ZeroMemory(&data, sizeof(data)); data.selection = selection; /* create modal dialog */ ret = DialogBoxParam( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_PLAYER_SELECTOR), GetNHApp()->hMainWnd, PlayerSelectorDlgProc, (LPARAM)&data ); if( ret==-1 ) panic("Cannot create getlin window"); return ret; } BOOL CALLBACK PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct plsel_data* data; RECT main_rt, dlg_rt; SIZE dlg_sz; switch (message) { case WM_INITDIALOG: data = (struct plsel_data*)lParam; SetWindowLong(hWnd, GWL_USERDATA, lParam); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hWnd, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow( hWnd, (main_rt.left+main_rt.right-dlg_sz.cx)/2, (main_rt.top+main_rt.bottom-dlg_sz.cy)/2, dlg_sz.cx, dlg_sz.cy, TRUE ); /* init dialog */ plselInitDialog(hWnd); #if defined(WIN_CE_SMARTPHONE) NHSPhoneDialogSetup(hWnd, FALSE, FALSE); #endif /* set focus on the role checkbox (random) field */ SetFocus(GetDlgItem(hWnd, IDC_PLSEL_ROLE_RANDOM)); /* tell windows we set the focus */ return FALSE; break; case WM_COMMAND: data = (struct plsel_data*)GetWindowLong(hWnd, GWL_USERDATA); switch (LOWORD(wParam)) { /* OK button was clicked */ case IDOK: if( plselFinalSelection(hWnd, data->selection) ) { EndDialog(hWnd, wParam); } else { MessageBox(hWnd, TEXT("Cannot match this role. Try something else."), TEXT("STOP"), MB_OK ); } return TRUE; /* CANCEL button was clicked */ case IDCANCEL: *data->selection = -1; EndDialog(hWnd, wParam); return TRUE; /* following are events from dialog controls: "random" checkboxes send BN_CLICKED messages; role/race/... combo-boxes send CBN_SELENDOK if something was selected; */ case IDC_PLSEL_ROLE_RANDOM: if( HIWORD(wParam)==BN_CLICKED ) { /* enable corresponding list window if "random" checkbox was "unchecked" */ EnableWindow( GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED ); } break; case IDC_PLSEL_RACE_RANDOM: if( HIWORD(wParam)==BN_CLICKED ) { EnableWindow( GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED ); } break; case IDC_PLSEL_GENDER_RANDOM: if( HIWORD(wParam)==BN_CLICKED ) { EnableWindow( GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED ); } break; case IDC_PLSEL_ALIGN_RANDOM: if( HIWORD(wParam)==BN_CLICKED ) { EnableWindow( GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED ); } break; case IDC_PLSEL_ROLE_LIST: if( HIWORD(wParam)==CBN_SELENDOK ) { /* filter out invalid options if the selection was made */ plselAdjustLists( hWnd, LOWORD(wParam) ); } break; case IDC_PLSEL_RACE_LIST: if( HIWORD(wParam)==CBN_SELENDOK ) { plselAdjustLists( hWnd, LOWORD(wParam) ); } break; case IDC_PLSEL_GENDER_LIST: if( HIWORD(wParam)==CBN_SELENDOK ) { plselAdjustLists( hWnd, LOWORD(wParam) ); } break; case IDC_PLSEL_ALIGN_LIST: if( HIWORD(wParam)==CBN_SELENDOK ) { plselAdjustLists( hWnd, LOWORD(wParam) ); } break; } break; } return FALSE; } void setComboBoxValue(HWND hWnd, int combo_box, int value) { int index_max = SendDlgItemMessage(hWnd, combo_box, CB_GETCOUNT, 0, 0); int index; int value_to_set = LB_ERR; for (index = 0; index < index_max; index++) { if (SendDlgItemMessage(hWnd, combo_box, CB_GETITEMDATA, (WPARAM)index, 0) == value) { value_to_set = index; break; } } SendDlgItemMessage(hWnd, combo_box, CB_SETCURSEL, (WPARAM)value_to_set, 0); } /* initialize player selector dialog */ void plselInitDialog(HWND hWnd) { TCHAR wbuf[BUFSZ]; /* set player name */ SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(plname, wbuf, sizeof(wbuf))); /* check flags for consistency */ if( flags.initrole>=0 ) { if (flags.initrace>=0 && !validrace(flags.initrole, flags.initrace)) { flags.initrace = ROLE_NONE; } if (flags.initgend>=0 && !validgend(flags.initrole, flags.initrace, flags.initgend)) { flags.initgend = ROLE_NONE; } if (flags.initalign>=0 && !validalign(flags.initrole, flags.initrace, flags.initalign)) { flags.initalign = ROLE_NONE; } } /* populate select boxes */ plselAdjustLists(hWnd, -1); /* intialize roles list */ if( flags.initrole<0 || !ok_role(flags.initrole, ROLE_NONE, ROLE_NONE, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_ROLE_LIST, flags.initrole); } /* intialize races list */ if( flags.initrace<0 || !ok_race(flags.initrole, flags.initrace, ROLE_NONE, ROLE_NONE) ) { CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_RACE_LIST, flags.initrace); } /* intialize genders list */ if( flags.initgend<0 || !ok_gend(flags.initrole, flags.initrace, flags.initgend, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_GENDER_LIST, flags.initgend); } /* intialize alignments list */ if( flags.initalign<0 || !ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign) ) { CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_ALIGN_LIST, flags.initalign); } } /* adjust role/race/alignment/gender list - filter out invalid combinations changed_sel points to the list where selection occured (-1 if unknown) */ void plselAdjustLists(HWND hWnd, int changed_sel) { HWND control_role, control_race, control_gender, control_align; int initrole, initrace, initgend, initalign; int i; int ind; int valid_opt; TCHAR wbuf[255]; /* get control handles */ control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST); control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST); control_gender = GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST); control_align = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST); /* get current selections */ ind = SendMessage(control_role, CB_GETCURSEL, 0, 0); initrole = (ind==LB_ERR)? flags.initrole : SendMessage(control_role, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_race, CB_GETCURSEL, 0, 0); initrace = (ind==LB_ERR)? flags.initrace : SendMessage(control_race, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_gender, CB_GETCURSEL, 0, 0); initgend = (ind==LB_ERR)? flags.initgend : SendMessage(control_gender, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_align, CB_GETCURSEL, 0, 0); initalign = (ind==LB_ERR)? flags.initalign : SendMessage(control_align, CB_GETITEMDATA, ind, 0); /* intialize roles list */ if( changed_sel==-1 ) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_role, CB_RESETCONTENT, 0, 0); for (i = 0; roles[i].name.m; i++) { if (ok_role(i, initrace, initgend, initalign)) { if (initgend>=0 && flags.female && roles[i].name.f) ind = SendMessage(control_role, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(roles[i].name.f, wbuf, sizeof(wbuf)) ); else ind = SendMessage(control_role, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(roles[i].name.m, wbuf, sizeof(wbuf)) ); SendMessage(control_role, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); if( i==initrole ) { SendMessage(control_role, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 ); valid_opt = 1; } } } /* set selection to the previously selected role if it is still valid */ if( !valid_opt ) { initrole = ROLE_NONE; initrace = ROLE_NONE; initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_role, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 ); } /* trigger change of the races list */ changed_sel=IDC_PLSEL_ROLE_LIST; } /* intialize races list */ if( changed_sel==IDC_PLSEL_ROLE_LIST ) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_race, CB_RESETCONTENT, 0, 0); for (i = 0; races[i].noun; i++) if (ok_race(initrole, i, ROLE_NONE, ROLE_NONE)) { ind = SendMessage(control_race, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(races[i].noun, wbuf, sizeof(wbuf)) ); SendMessage(control_race, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); if( i==initrace ) { SendMessage(control_race, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 ); valid_opt = 1; } } /* set selection to the previously selected race if it is still valid */ if( !valid_opt ) { initrace = ROLE_NONE; initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_race, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 ); } /* trigger change of the genders list */ changed_sel=IDC_PLSEL_RACE_LIST; } /* intialize genders list */ if( changed_sel==IDC_PLSEL_RACE_LIST ) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_gender, CB_RESETCONTENT, 0, 0); for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(initrole, initrace, i, ROLE_NONE)) { ind = SendMessage(control_gender, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(genders[i].adj, wbuf, sizeof(wbuf)) ); SendMessage(control_gender, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); if( i==initgend ) { SendMessage(control_gender, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 ); valid_opt = 1; } } /* set selection to the previously selected gender if it is still valid */ if( !valid_opt ) { initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_gender, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 ); } /* trigger change of the alignments list */ changed_sel=IDC_PLSEL_GENDER_LIST; } /* intialize alignments list */ if( changed_sel==IDC_PLSEL_GENDER_LIST ) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_align, CB_RESETCONTENT, 0, 0); for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(initrole, initrace, initgend, i)) { ind = SendMessage(control_align, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(aligns[i].adj, wbuf, sizeof(wbuf)) ); SendMessage(control_align, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); if( i==initalign ) { SendMessage(control_align, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 ); valid_opt = 1; } } /* set selection to the previously selected alignment if it is still valid */ if( !valid_opt ) { initalign = ROLE_NONE; SendMessage(control_align, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 ); } } } /* player made up his mind - get final selection here */ int plselFinalSelection(HWND hWnd, int* selection) { int ind; /* get current selections */ if( SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) { flags.initrole = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETCURSEL, 0, 0); flags.initrole = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETITEMDATA, ind, 0); } if( SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) { flags.initrace = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETCURSEL, 0, 0); flags.initrace = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETITEMDATA, ind, 0); } if( SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) { flags.initgend = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETCURSEL, 0, 0); flags.initgend = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETITEMDATA, ind, 0); } if( SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) { flags.initalign = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETCURSEL, 0, 0); flags.initalign = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETITEMDATA, ind, 0); } /* check the role */ if( flags.initrole==ROLE_RANDOM ) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { MessageBox(hWnd, TEXT("Incompatible role!"), TEXT("STOP"), MB_OK); return FALSE; } } /* Select a race, if necessary */ /* force compatibility with role */ if (flags.initrace==ROLE_RANDOM || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (flags.initrace == ROLE_RANDOM) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); } if (flags.initrace < 0) { MessageBox(hWnd, TEXT("Incompatible race!"), TEXT("STOP"), MB_OK); return FALSE; } } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (flags.initgend == ROLE_RANDOM) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); } if (flags.initgend < 0) { MessageBox(hWnd, TEXT("Incompatible gender!"), TEXT("STOP"), MB_OK); return FALSE; } } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (flags.initalign == ROLE_RANDOM) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); } else { MessageBox(hWnd, TEXT("Incompatible alignment!"), TEXT("STOP"), MB_OK); return FALSE; } } return TRUE; } nethack-3.4.3/sys/wince/mhdlg.h0100644000000000000000000000070307764735041015041 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINDlgWindow_h #define MSWINDlgWindow_h #include "winMS.h" #include "config.h" #include "global.h" int mswin_getlin_window (const char *question, char *result, size_t result_size); int mswin_ext_cmd_window (int* selection); int mswin_player_selection_window(int* selection); #endif /* MSWINDlgWindow_h */ nethack-3.4.3/sys/wince/mhfont.c0100644000000000000000000001511107764735041015233 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* font management and such */ #include "mhfont.h" #define MAXFONTS 64 /* font table - 64 fonts ought to be enough */ static struct font_table_entry { int code; HFONT hFont; } font_table[MAXFONTS] ; static int font_table_size = 0; HFONT version_splash_font; HFONT extrainfo_splash_font; #define NHFONT_CODE(win, attr) (((attr&0xFF)<<8)|(win_type&0xFF)) static void __cdecl font_table_cleanup(void); /* create font based on window type, charater attributes and window device context */ HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) { HFONT fnt = NULL; LOGFONT lgfnt; int font_size; int font_index; static BOOL once = FALSE; if( !once ) { once = TRUE; atexit(font_table_cleanup); } ZeroMemory( &lgfnt, sizeof(lgfnt) ); /* try find font in the table */ for(font_index=0; font_index=MAXFONTS ) panic( "font table overflow!" ); font_table_size++; } else { DeleteObject(font_table[font_index].hFont); } font_table[font_index].code = NHFONT_CODE(win_type, attr); font_table[font_index].hFont = fnt; return fnt; } UINT mswin_charset() { CHARSETINFO cis; if( iflags.IBMgraphics ) if( TranslateCharsetInfo((DWORD*)GetOEMCP(), &cis, TCI_SRCCODEPAGE) ) return cis.ciCharset; else return OEM_CHARSET; else if( TranslateCharsetInfo((DWORD*)GetACP(), &cis, TCI_SRCCODEPAGE) ) return cis.ciCharset; else return ANSI_CHARSET; } void __cdecl font_table_cleanup(void) { int i; for(i=0; i */ /* NetHack may be freely redistributed. See license for details. */ /* font management functions */ #ifndef MSWINFont_h #define MSWINFont_h #include "winMS.h" HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace); UINT mswin_charset(); #endif /* MSWINFont_h */ nethack-3.4.3/sys/wince/mhinput.c0100644000000000000000000000343407764735041015431 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include #include "winMS.h" #include "mhinput.h" /* nethack input queue functions */ #define NH_INPUT_BUFFER_SIZE 64 /* as it stands right now we need only one slot since events are processed almost the same time as they occur but I like large round numbers */ static MSNHEvent nhi_input_buffer[NH_INPUT_BUFFER_SIZE]; static int nhi_init_input = 0; static int nhi_read_pos = 0; static int nhi_write_pos = 0; /* initialize input queue */ void mswin_nh_input_init() { if( !nhi_init_input ) { nhi_init_input = 1; ZeroMemory( nhi_input_buffer, sizeof(nhi_input_buffer) ); nhi_read_pos = 0; nhi_write_pos = 0; } } /* check for input */ int mswin_have_input() { return (nhi_read_pos!=nhi_write_pos); } /* add event to the queue */ void mswin_input_push(PMSNHEvent event) { int new_write_pos; if( !nhi_init_input ) mswin_nh_input_init(); new_write_pos = (nhi_write_pos+1) % NH_INPUT_BUFFER_SIZE; if(new_write_pos!=nhi_read_pos) { memcpy(nhi_input_buffer+nhi_write_pos, event, sizeof(*event)); nhi_write_pos = new_write_pos; } } /* get event from the queue and delete it */ PMSNHEvent mswin_input_pop() { PMSNHEvent retval; if( !nhi_init_input ) mswin_nh_input_init(); if( nhi_read_pos!=nhi_write_pos ) { retval = &nhi_input_buffer[nhi_read_pos]; nhi_read_pos = (nhi_read_pos+1) % NH_INPUT_BUFFER_SIZE; } else { retval = NULL; } return retval; } /* get event from the queue but leave it there */ PMSNHEvent mswin_input_peek() { PMSNHEvent retval; if( !nhi_init_input ) mswin_nh_input_init(); if( nhi_read_pos!=nhi_write_pos ) { retval = &nhi_input_buffer[nhi_read_pos]; } else { retval = NULL; } return retval; } nethack-3.4.3/sys/wince/mhinput.h0100644000000000000000000000155507764735041015440 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINInput_h #define MSWINInput_h /* nethack input queue - store/extract input events */ #include "winMS.h" #define NHEVENT_CHAR 1 #define NHEVENT_MOUSE 2 typedef struct mswin_event { int type; union { struct { int ch; } kbd; struct { int mod; int x, y; } ms; }; } MSNHEvent, *PMSNHEvent; #define NHEVENT_KBD(c) { MSNHEvent e; e.type=NHEVENT_CHAR; e.kbd.ch=(c); mswin_input_push(&e); } #define NHEVENT_MS(_mod, _x, _y) { MSNHEvent e; e.type=NHEVENT_MOUSE; e.ms.mod = (_mod); e.ms.x=(_x); e.ms.y=(_y); mswin_input_push(&e); } void mswin_nh_input_init(); int mswin_have_input(); void mswin_input_push(PMSNHEvent event); PMSNHEvent mswin_input_pop(); PMSNHEvent mswin_input_peek(); #endif /* MSWINInput_h */ nethack-3.4.3/sys/wince/mhmain.c0100644000000000000000000007265407764735041015230 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhmsg.h" #include "mhinput.h" #include "mhmain.h" #include "mhmenu.h" #include "mhstatus.h" #include "mhmsgwnd.h" #include "mhcmd.h" #include "mhmap.h" #include "patchlevel.h" #define MAX_LOADSTRING 100 typedef struct mswin_nethack_main_window { int mapAcsiiModeSave; } NHMainWindow, *PNHMainWindow; TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass"); static TCHAR szTitle[MAX_LOADSTRING]; LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void register_main_window_class(); static void select_map_mode(int map_mode); static int menuid2mapmode(int menuid); static int mapmode2menuid(int map_mode); static HMENU _get_main_menu(UINT menu_id); HWND mswin_init_main_window () { static int run_once = 0; HWND ret; RECT rc; /* register window class */ if( !run_once ) { LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); register_main_window_class( ); run_once = 1; } /* create the main window */ SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); ret = CreateWindow( szMainWindowClass, /* registered class name */ szTitle, /* window name */ WS_CLIPCHILDREN, /* window style */ rc.left, /* horizontal position of window */ rc.top, /* vertical position of window */ rc.right - rc.left, /* window width */ rc.bottom - rc.top, /* window height */ NULL, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL /* window-creation data */ ); if( !ret ) panic("Cannot create main window"); return ret; } void register_main_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)MainWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = LoadIcon(GetNHApp()->hApp, (LPCTSTR)IDI_WINHACK); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = NULL; wcex.lpszClassName = szMainWindowClass; RegisterClass(&wcex); } /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ enum KEY_INDEXES { KEY_NW, KEY_N, KEY_NE, KEY_MINUS, KEY_W, KEY_GOINTERESTING, KEY_E, KEY_PLUS, KEY_SW, KEY_S, KEY_SE, KEY_INV, KEY_WAITLOOK, KEY_LAST}; static const unsigned char /* normal, shift, control */ keypad[KEY_LAST][3] = { {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'h', 'H', C('h')}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'l', 'L', C('l')}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }, numpad[KEY_LAST][3] = { {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'4', M('4'), '4'}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }; #define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0) #define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0]) #define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1]) #define KEYTABLE(x) (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x)) /* map mode macros */ #define IS_MAP_FIT_TO_SCREEN(mode) ((mode)==MAP_MODE_ASCII_FIT_TO_SCREEN || \ (mode)==MAP_MODE_TILES_FIT_TO_SCREEN ) #define IS_MAP_ASCII(mode) ((mode)!=MAP_MODE_TILES && (mode)!=MAP_MODE_TILES_FIT_TO_SCREEN) /* // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) // // PURPOSE: Processes messages for the main window. */ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMainWindow data; switch (message) { /*-----------------------------------------------------------------------*/ case WM_CREATE: { #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) SHMENUBARINFO menubar; #endif /* set window data */ data = (PNHMainWindow)malloc(sizeof(NHMainWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHMainWindow)); data->mapAcsiiModeSave = MAP_MODE_ASCII12x16; SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); GetNHApp()->hMainWnd = hWnd; /* create menu bar */ #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) ZeroMemory(&menubar, sizeof(menubar)); menubar.cbSize = sizeof(menubar); menubar.hwndParent = hWnd; menubar.dwFlags = 0; menubar.nToolBarId = IDC_WINHACK; menubar.hInstRes = GetNHApp()->hApp; # if defined(WIN_CE_POCKETPC) menubar.nBmpId = IDB_MENUBAR; menubar.cBmpImages = 2; # else menubar.nBmpId = 0; menubar.cBmpImages = 0; # endif if( !SHCreateMenuBar(&menubar) ) panic("cannot create menu"); GetNHApp()->hMenuBar = menubar.hwndMB; #else GetNHApp()->hMenuBar = CommandBar_Create(GetNHApp()->hApp, hWnd, 1); if( !GetNHApp()->hMenuBar ) panic("cannot create menu"); CommandBar_InsertMenubar( GetNHApp()->hMenuBar, GetNHApp()->hApp, IDC_WINHACK, 0 ); #endif CheckMenuItem( _get_main_menu(ID_VIEW), IDM_VIEW_KEYPAD, MF_BYCOMMAND | (GetNHApp()->bCmdPad? MF_CHECKED : MF_UNCHECKED) ); /* create command pad (keyboard emulator) */ GetNHApp()->hCmdWnd = mswin_init_command_window(); } break; /*-----------------------------------------------------------------------*/ case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; /*-----------------------------------------------------------------------*/ case WM_KEYDOWN: data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA); /* translate arrow keys into nethack commands */ switch (wParam) { case VK_LEFT: if( STATEON(VK_CONTROL) ) { /* scroll map window one line left */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_W)); } return 0; case VK_RIGHT: if( STATEON(VK_CONTROL) ) { /* scroll map window one line right */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_E)); } return 0; case VK_UP: if( STATEON(VK_CONTROL) ) { /* scroll map window one line up */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_N)); } return 0; case VK_DOWN: if( STATEON(VK_CONTROL) ) { /* scroll map window one line down */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_S)); } return 0; case VK_HOME: if( STATEON(VK_CONTROL) ) { /* scroll map window to upper left corner */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM)NULL ); SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_NW)); } return 0; case VK_END: if( STATEON(VK_CONTROL) ) { /* scroll map window to lower right corner */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, ROWNO), (LPARAM)NULL ); SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, COLNO), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_SW)); } return 0; case VK_PRIOR: if( STATEON(VK_CONTROL) ) { /* scroll map window one page up */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_NE)); } return 0; case VK_NEXT: if( STATEON(VK_CONTROL) ) { /* scroll map window one page down */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_SE)); } return 0; case VK_DECIMAL: case VK_DELETE: NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK)); return 0; case VK_INSERT: NHEVENT_KBD(KEYTABLE(KEY_INV)); return 0; case VK_SUBTRACT: NHEVENT_KBD(KEYTABLE(KEY_MINUS)); return 0; case VK_ADD: NHEVENT_KBD(KEYTABLE(KEY_PLUS)); return 0; case VK_CLEAR: /* This is the '5' key */ NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING)); return 0; case VK_F4: if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) { mswin_select_map_mode( IS_MAP_ASCII(iflags.wc_map_mode)? data->mapAcsiiModeSave : MAP_MODE_TILES ); } else { mswin_select_map_mode( IS_MAP_ASCII(iflags.wc_map_mode)? MAP_MODE_ASCII_FIT_TO_SCREEN : MAP_MODE_TILES_FIT_TO_SCREEN ); } return 0; case VK_F5: if( IS_MAP_ASCII(iflags.wc_map_mode) ) { if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) { mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN); } else { mswin_select_map_mode(MAP_MODE_TILES); } } else { if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) { mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN); } else { mswin_select_map_mode(data->mapAcsiiModeSave); } } return 0; case VK_RETURN: NHEVENT_MS( CLICK_1, u.ux, u.uy); return 0; } #if defined(WIN_CE_SMARTPHONE) if( NHSPhoneTranslateKbdMessage(wParam, lParam, TRUE) ) return 0; #endif return 1; /* end of WM_KEYDOWN */ /*-----------------------------------------------------------------------*/ #if defined(WIN_CE_SMARTPHONE) case WM_KEYUP: if( NHSPhoneTranslateKbdMessage(wParam, lParam, FALSE) ) return 0; return 1; /* end of WM_KEYUP */ #endif /*-----------------------------------------------------------------------*/ #if !defined(WIN_CE_SMARTPHONE) case WM_CHAR: if( wParam=='\n' || wParam=='\r' || wParam==C('M') ) return 0; /* we already processed VK_RETURN */ /* all characters go to nethack except Ctrl-P that scrolls message window up */ if( wParam==C('P') || wParam==C('p') ) { SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); } else { NHEVENT_KBD( (lParam & 1<<29)? M(tolower(wParam)) : wParam ); } return 0; #endif /*-----------------------------------------------------------------------*/ case WM_COMMAND: /* process commands - menu commands mostly */ if( IsWindow(GetNHApp()->hPopupWnd) ) { return SendMessage(GetNHApp()->hPopupWnd, message, wParam, lParam); } else if( onWMCommand(hWnd, wParam, lParam) ) return DefWindowProc(hWnd, message, wParam, lParam); else return 0; /*-----------------------------------------------------------------------*/ case WM_ACTIVATE: if( LOWORD(wParam)!=WA_INACTIVE ) { #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) if( GetNHApp()->bFullScreen ) SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON); else SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON); #endif mswin_layout_main_window(NULL); } break; case WM_SETTINGCHANGE: #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) if( GetNHApp()->bFullScreen ) SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON); else SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON); #endif mswin_layout_main_window(NULL); break; case WM_SIZE: mswin_layout_main_window(NULL); break; /*-----------------------------------------------------------------------*/ case WM_SETFOCUS: /* if there is a menu window out there - transfer input focus to it */ if( IsWindow( GetNHApp()->hPopupWnd ) ) { SetFocus( GetNHApp()->hPopupWnd ); } break; /*-----------------------------------------------------------------------*/ case WM_CLOSE: { /* exit gracefully */ dosave0(); } return 0; /*-----------------------------------------------------------------------*/ case WM_DESTROY: { /* apparently we never get here TODO: work on exit routines - need to send WM_QUIT somehow */ /* clean up */ free( (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA) ); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); terminate(EXIT_SUCCESS); } break; /*-----------------------------------------------------------------------*/ default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { switch(wParam) { /* new window was just added */ case MSNH_MSG_ADDWND: { PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd)lParam; HWND child = GetNHApp()->windowlist[msg_param->wid].win; if( GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP ) mswin_select_map_mode(iflags.wc_map_mode); if( child ) mswin_layout_main_window(child); } break; } } /* adjust windows to fit main window layout --------------------------- | Status | +-------------------------+ | | | | | MAP | | | | | +-------------------------+ | Command pad | +-------------------------+ | Messages | --------------------------- */ void mswin_layout_main_window(HWND changed_child) { winid i; RECT client_rt, wnd_rect; POINT status_org; SIZE status_size; POINT msg_org; SIZE msg_size; POINT map_org; SIZE map_size; POINT cmd_org; SIZE cmd_size; HWND wnd_status, wnd_msg; PNHMainWindow data; #if defined(WIN_CE_POCKETPC) SIPINFO sip; RECT menu_bar; RECT visible_rt; POINT pt; #endif GetClientRect(GetNHApp()->hMainWnd, &client_rt); #if defined(WIN_CE_POCKETPC) ZeroMemory(&sip, sizeof(sip)); sip.cbSize = sizeof(sip); SHSipInfo(SPI_GETSIPINFO, 0, &sip, 0); if( GetNHApp()->bFullScreen ) sip.rcVisibleDesktop.top = 0; /* adjust client rectangle size */ GetWindowRect(GetNHApp()->hMenuBar, &menu_bar); client_rt.bottom -= menu_bar.bottom-menu_bar.top; /* calcuate visible rect in client coordinates */ pt.x = sip.rcVisibleDesktop.left; pt.y = sip.rcVisibleDesktop.top; ScreenToClient(GetNHApp()->hMainWnd, &pt); SetRect(&wnd_rect, pt.x, pt.y, pt.x+sip.rcVisibleDesktop.right-sip.rcVisibleDesktop.left, pt.y+sip.rcVisibleDesktop.bottom-sip.rcVisibleDesktop.top ); IntersectRect(&visible_rt, &client_rt, &wnd_rect); #else # if !defined(WIN_CE_SMARTPHONE) client_rt.top += CommandBar_Height(GetNHApp()->hMenuBar); # else /* Smartphone only */ if( GetNHApp()->bFullScreen ) { RECT menu_bar; GetWindowRect(GetNHApp()->hMenuBar, &menu_bar); client_rt.bottom -= menu_bar.bottom-menu_bar.top; } # endif #endif /* get window data */ data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA); /* get sizes of child windows */ wnd_status = mswin_hwnd_from_winid(WIN_STATUS); if( IsWindow(wnd_status) ) { mswin_status_window_size(wnd_status, &status_size); } else { status_size.cx = status_size.cy = 0; } wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE); if( IsWindow(wnd_msg) ) { mswin_message_window_size(wnd_msg, &msg_size); } else { msg_size.cx = msg_size.cy = 0; } cmd_size.cx = cmd_size.cy = 0; if( GetNHApp()->bCmdPad && IsWindow(GetNHApp()->hCmdWnd) ) { mswin_command_window_size(GetNHApp()->hCmdWnd, &cmd_size); } /* set window positions */ /* calculate the application windows size */ #if defined(WIN_CE_POCKETPC) SetRect(&wnd_rect, visible_rt.left, visible_rt.top, visible_rt.right, visible_rt.bottom); if( sip.fdwFlags & SIPF_ON ) cmd_size.cx = cmd_size.cy = 0; /* hide keypad window */ #else SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right, client_rt.bottom); #endif #if !defined(WIN_CE_SMARTPHONE) /* other ports have it at the bottom of the screen */ cmd_size.cx = (wnd_rect.right-wnd_rect.left); cmd_org.x = wnd_rect.left; cmd_org.y = wnd_rect.bottom - cmd_size.cy; wnd_rect.bottom -= cmd_size.cy; #endif /* status window */ switch(iflags.wc_align_status) { case ALIGN_LEFT: status_size.cx = (wnd_rect.right-wnd_rect.left)/4; status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good status_org.x = wnd_rect.left; status_org.y = wnd_rect.top; wnd_rect.left += status_size.cx; break; case ALIGN_RIGHT: status_size.cx = (wnd_rect.right-wnd_rect.left)/4; status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good status_org.x = wnd_rect.right - status_size.cx; status_org.y = wnd_rect.top; wnd_rect.right -= status_size.cx; break; case ALIGN_TOP: status_size.cx = (wnd_rect.right-wnd_rect.left); status_org.x = wnd_rect.left; status_org.y = wnd_rect.top; wnd_rect.top += status_size.cy; break; case ALIGN_BOTTOM: default: status_size.cx = (wnd_rect.right-wnd_rect.left); status_org.x = wnd_rect.left; status_org.y = wnd_rect.bottom - status_size.cy; wnd_rect.bottom -= status_size.cy; break; } /* message window */ switch(iflags.wc_align_message) { case ALIGN_LEFT: #if defined(WIN_CE_SMARTPHONE) /* smartphone has a keypad window on the right (bottom) side of the message window */ msg_size.cx = cmd_size.cx = max(msg_size.cx, cmd_size.cx); msg_size.cy = (wnd_rect.bottom-wnd_rect.top) - cmd_size.cy; msg_org.x = cmd_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; cmd_org.y = msg_org.y + msg_size.cy; #else msg_size.cx = (wnd_rect.right-wnd_rect.left)/4; msg_size.cy = (wnd_rect.bottom-wnd_rect.top); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; #endif wnd_rect.left += msg_size.cx; break; case ALIGN_RIGHT: #if defined(WIN_CE_SMARTPHONE) /* smartphone has a keypad window on the right (bottom) side of the message window */ msg_size.cx = cmd_size.cx = max(msg_size.cx, cmd_size.cx); msg_size.cy = (wnd_rect.bottom-wnd_rect.top) - cmd_size.cy; msg_org.x = cmd_org.x = wnd_rect.right - msg_size.cx; msg_org.y = wnd_rect.top; cmd_org.y = msg_org.y + msg_size.cy; #else msg_size.cx = (wnd_rect.right-wnd_rect.left)/4; msg_size.cy = (wnd_rect.bottom-wnd_rect.top); msg_org.x = wnd_rect.right - msg_size.cx; msg_org.y = wnd_rect.top; #endif wnd_rect.right -= msg_size.cx; break; case ALIGN_TOP: #if defined(WIN_CE_SMARTPHONE) /* smartphone has a keypad window on the right side of the message window */ msg_size.cy = cmd_size.cy = max(msg_size.cy, cmd_size.cy); msg_size.cx = (wnd_rect.right - wnd_rect.left) - cmd_size.cx; msg_org.x = wnd_rect.left; cmd_org.x = msg_org.x + msg_size.cx; msg_org.y = cmd_org.y = wnd_rect.bottom - msg_size.cy; #else msg_size.cx = (wnd_rect.right-wnd_rect.left); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; #endif wnd_rect.top += msg_size.cy; break; case ALIGN_BOTTOM: default: #if defined(WIN_CE_SMARTPHONE) /* smartphone has a keypad window on the right side of the message window */ msg_size.cy = cmd_size.cy = max(msg_size.cy, cmd_size.cy); msg_size.cx = (wnd_rect.right - wnd_rect.left) - cmd_size.cx; msg_org.x = wnd_rect.left; cmd_org.x = msg_org.x + msg_size.cx; msg_org.y = cmd_org.y = wnd_rect.bottom - msg_size.cy; #else msg_size.cx = (wnd_rect.right-wnd_rect.left); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.bottom - msg_size.cy; #endif wnd_rect.bottom -= msg_size.cy; break; } map_org.x = wnd_rect.left; map_org.y = wnd_rect.top; map_size.cx = wnd_rect.right - wnd_rect.left; map_size.cy = wnd_rect.bottom - wnd_rect.top; /* go through the windows list and adjust sizes */ for( i=0; iwindowlist[i].win && !GetNHApp()->windowlist[i].dead) { switch( GetNHApp()->windowlist[i].type ) { case NHW_MESSAGE: MoveWindow(GetNHApp()->windowlist[i].win, msg_org.x, msg_org.y, msg_size.cx, msg_size.cy, TRUE ); break; case NHW_MAP: MoveWindow(GetNHApp()->windowlist[i].win, map_org.x, map_org.y, map_size.cx, map_size.cy, TRUE ); break; case NHW_STATUS: MoveWindow(GetNHApp()->windowlist[i].win, status_org.x, status_org.y, status_size.cx, status_size.cy, TRUE ); break; case NHW_TEXT: case NHW_MENU: case NHW_RIP: { POINT menu_org; SIZE menu_size; menu_org.x = client_rt.left; menu_org.y = client_rt.top; #if defined(WIN_CE_POCKETPC) menu_size.cx = min(sip.rcVisibleDesktop.right-sip.rcVisibleDesktop.left, client_rt.right - client_rt.left); menu_size.cy = min(sip.rcVisibleDesktop.bottom-sip.rcVisibleDesktop.top, client_rt.bottom - client_rt.top); #else menu_size.cx = client_rt.right - client_rt.left; menu_size.cy = client_rt.bottom - client_rt.top; #endif #if defined(WIN_CE_SMARTPHONE) /* leave room for the command window */ if( GetNHApp()->windowlist[i].type == NHW_MENU ) { menu_size.cy -= cmd_size.cy; } /* dialogs are popup windows unde SmartPhone so we need to convert to screen coordinates */ ClientToScreen(GetNHApp()->hMainWnd, &menu_org); #endif MoveWindow(GetNHApp()->windowlist[i].win, menu_org.x, menu_org.y, menu_size.cx, menu_size.cy, TRUE ); } break; } ShowWindow(GetNHApp()->windowlist[i].win, SW_SHOW); InvalidateRect(GetNHApp()->windowlist[i].win, NULL, TRUE); } } if( IsWindow(GetNHApp()->hCmdWnd) ) { /* show command window only if it exists and the game is ready (plname is set) */ if( GetNHApp()->bCmdPad && cmd_size.cx>0 && cmd_size.cy>0 && *plname) { MoveWindow(GetNHApp()->hCmdWnd, cmd_org.x, cmd_org.y, cmd_size.cx, cmd_size.cy, TRUE ); ShowWindow(GetNHApp()->hCmdWnd, SW_SHOW); } else { ShowWindow(GetNHApp()->hCmdWnd, SW_HIDE); } } } LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PNHMainWindow data; data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA); wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // process the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(GetNHApp()->hApp, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); break; case IDM_EXIT: done2(); break; case IDM_SAVE: dosave(); break; case IDM_MAP_TILES: case IDM_MAP_ASCII4X6: case IDM_MAP_ASCII6X8: case IDM_MAP_ASCII8X8: case IDM_MAP_ASCII16X8: case IDM_MAP_ASCII7X12: case IDM_MAP_ASCII8X12: case IDM_MAP_ASCII12X16: case IDM_MAP_ASCII16X12: case IDM_MAP_ASCII10X18: mswin_select_map_mode(menuid2mapmode(wmId)); break; case IDM_MAP_FIT_TO_SCREEN: if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) { mswin_select_map_mode( IS_MAP_ASCII(iflags.wc_map_mode)? data->mapAcsiiModeSave : MAP_MODE_TILES ); } else { mswin_select_map_mode( IS_MAP_ASCII(iflags.wc_map_mode)? MAP_MODE_ASCII_FIT_TO_SCREEN : MAP_MODE_TILES_FIT_TO_SCREEN ); } break; case IDM_VIEW_KEYPAD: GetNHApp()->bCmdPad = !GetNHApp()->bCmdPad; CheckMenuItem( _get_main_menu(ID_VIEW), IDM_VIEW_KEYPAD, MF_BYCOMMAND | (GetNHApp()->bCmdPad? MF_CHECKED : MF_UNCHECKED) ); mswin_layout_main_window(GetNHApp()->hCmdWnd); break; case IDM_VIEW_OPTIONS: doset(); break; case IDM_HELP_LONG: display_file(HELP, TRUE); break; case IDM_HELP_COMMANDS: display_file(SHELP, TRUE); break; case IDM_HELP_HISTORY: (void) dohistory(); break; case IDM_HELP_INFO_CHAR: (void) dowhatis(); break; case IDM_HELP_INFO_KEY: (void) dowhatdoes(); break; case IDM_HELP_OPTIONS: option_help(); break; case IDM_HELP_OPTIONS_LONG: display_file(OPTIONFILE, TRUE); break; case IDM_HELP_EXTCMD: (void) doextlist(); break; case IDM_HELP_LICENSE: display_file(LICENSE, TRUE); break; case IDM_HELP_MENU: dohelp(); break; default: return 1; } return 0; } // Mesage handler for about box. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { char buf[BUFSZ]; TCHAR wbuf[NHSTR_BUFSIZE]; RECT main_rt, dlg_rt; SIZE dlg_sz; switch (message) { case WM_INITDIALOG: getversionstring(buf); SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, NHSTR_BUFSIZE)); SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT, NH_A2W( COPYRIGHT_BANNER_A "\n" COPYRIGHT_BANNER_B "\n" COPYRIGHT_BANNER_C, wbuf, NHSTR_BUFSIZE ) ); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hDlg, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow( hDlg, (main_rt.left+main_rt.right-dlg_sz.cx)/2, (main_rt.top+main_rt.bottom-dlg_sz.cy)/2, dlg_sz.cx, dlg_sz.cy, TRUE ); return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } /* Set map display mode */ void mswin_select_map_mode(int mode) { HMENU hmenuMap; PNHMainWindow data; winid map_id; map_id = WIN_MAP; data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA); #if defined(WIN_CE_SMARTPHONE) /* Smartphone manu has only 2 items */ hmenuMap = _get_main_menu(ID_VIEW); #else hmenuMap = _get_main_menu(ID_MAP); #endif /* override for Rogue level */ #ifdef REINCARNATION if( Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode) ) return; #endif /* set map mode menu mark */ if( IS_MAP_ASCII(mode) ) { CheckMenuRadioItem( hmenuMap, IDM_MAP_TILES, IDM_MAP_FIT_TO_SCREEN, mapmode2menuid( IS_MAP_FIT_TO_SCREEN(mode)? data->mapAcsiiModeSave : mode ), MF_BYCOMMAND); } else { CheckMenuRadioItem( hmenuMap, IDM_MAP_TILES, IDM_MAP_FIT_TO_SCREEN, mapmode2menuid( MAP_MODE_TILES ), MF_BYCOMMAND); } #if defined(WIN_CE_SMARTPHONE) /* update "Fit To Screen" item text */ { TCHAR wbuf[BUFSZ]; TBBUTTONINFO tbbi; ZeroMemory( wbuf, sizeof(wbuf) ); if( !LoadString( GetNHApp()->hApp, (IS_MAP_FIT_TO_SCREEN(mode)? IDS_CAP_NORMALMAP : IDS_CAP_ENTIREMAP), wbuf, BUFSZ) ) { panic("cannot load main menu strings"); } ZeroMemory( &tbbi, sizeof(tbbi) ); tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_TEXT; tbbi.pszText = wbuf; if( !SendMessage( GetNHApp()->hMenuBar, TB_SETBUTTONINFO, IDM_MAP_FIT_TO_SCREEN, (LPARAM)&tbbi) ) { error( "Cannot update IDM_MAP_FIT_TO_SCREEN menu item." ); } } #else /* set fit-to-screen mode mark */ CheckMenuItem( hmenuMap, IDM_MAP_FIT_TO_SCREEN, MF_BYCOMMAND | (IS_MAP_FIT_TO_SCREEN(mode)? MF_CHECKED : MF_UNCHECKED) ); #endif if( IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { data->mapAcsiiModeSave = iflags.wc_map_mode; } iflags.wc_map_mode = mode; /* ** first, check if WIN_MAP has been inialized. ** If not - attempt to retrieve it by type, then check it again */ if( map_id==WIN_ERR ) map_id = mswin_winid_from_type(NHW_MAP); if( map_id!=WIN_ERR ) mswin_map_mode(mswin_hwnd_from_winid(map_id), mode); } static struct t_menu2mapmode { int menuID; int mapMode; } _menu2mapmode[] = { { IDM_MAP_TILES, MAP_MODE_TILES }, { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 }, { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 }, { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 }, { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 }, { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 }, { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 }, { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 }, { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 }, { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 }, { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN }, { -1, -1 } }; int menuid2mapmode(int menuid) { struct t_menu2mapmode* p; for( p = _menu2mapmode; p->mapMode!=-1; p++ ) if(p->menuID==menuid ) return p->mapMode; return -1; } int mapmode2menuid(int map_mode) { struct t_menu2mapmode* p; for( p = _menu2mapmode; p->mapMode!=-1; p++ ) if(p->mapMode==map_mode ) return p->menuID; return -1; } HMENU _get_main_menu(UINT menu_id) { HMENU hmenuMap; #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) TBBUTTONINFO tbbi; #endif #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) tbbi.cbSize = sizeof(tbbi); tbbi.dwMask = TBIF_LPARAM; SendMessage( GetNHApp()->hMenuBar, TB_GETBUTTONINFO, menu_id, (LPARAM)&tbbi); hmenuMap = (HMENU)tbbi.lParam; #else hmenuMap = CommandBar_GetMenu(GetNHApp()->hMenuBar, 0); #endif return hmenuMap; } nethack-3.4.3/sys/wince/mhmain.h0100644000000000000000000000066507764735041015226 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMainWindow_h #define MSWINMainWindow_h /* this is a main appliation window */ #include "winMS.h" extern TCHAR szMainWindowClass[]; HWND mswin_init_main_window (); void mswin_layout_main_window(HWND changed_child); void mswin_select_map_mode(int map_mode); #endif /* MSWINMainWindow_h */ nethack-3.4.3/sys/wince/mhmap.c0100644000000000000000000006112107764735041015044 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhmap.h" #include "mhmsg.h" #include "mhinput.h" #include "mhfont.h" #include "patchlevel.h" #define NHMAP_FONT_NAME TEXT("Terminal") #define MAXWINDOWTEXT 255 extern short glyph2tile[]; /* map window data */ typedef struct mswin_nethack_map_window { int map[COLNO][ROWNO]; /* glyph map */ int mapMode; /* current map mode */ boolean bAsciiMode; /* switch ASCII/tiled mode */ boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */ int xPos, yPos; /* scroll position */ int xPageSize, yPageSize; /* scroll page size */ int xCur, yCur; /* position of the cursor */ int xScrTile, yScrTile; /* size of display tile */ POINT map_orig; /* map origin point */ HFONT hMapFont; /* font for ASCII mode */ } NHMapWindow, *PNHMapWindow; static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass"); LRESULT CALLBACK MapWndProc(HWND, UINT, WPARAM, LPARAM); static void register_map_window_class(void); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar* ch, int* color); #endif static COLORREF nhcolor_to_RGB(int c); HWND mswin_init_map_window () { static int run_once = 0; HWND ret; DWORD styles; if( !run_once ) { register_map_window_class(); run_once = 1; } styles = WS_CHILD | WS_CLIPSIBLINGS; if( !GetNHApp()->bHideScrollBars ) styles |= WS_HSCROLL | WS_VSCROLL; ret = CreateWindow( szNHMapWindowClass, /* registered class name */ NULL, /* window name */ styles, /* window style */ 0, /* horizontal position of window - set it later */ 0, /* vertical position of window - set it later */ 0, /* window width - set it later */ 0, /* window height - set it later*/ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL ); /* window-creation data */ if( !ret ) { panic("Cannot create map window"); } return ret; } void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw) { PNHMapWindow data; RECT client_rt; SCROLLINFO si; SIZE wnd_size; LOGFONT lgfnt; /* check arguments */ if( !IsWindow(hWnd) || !lpsz || lpsz->cx<=0 || lpsz->cy<=0 ) return; /* calculate window size */ GetClientRect(hWnd, &client_rt); wnd_size.cx = client_rt.right - client_rt.left; wnd_size.cy = client_rt.bottom - client_rt.top; /* set new screen tile size */ data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); data->xScrTile = max(1, (data->bFitToScreenMode? wnd_size.cx : lpsz->cx) / COLNO); data->yScrTile = max(1, (data->bFitToScreenMode? wnd_size.cy : lpsz->cy) / ROWNO); /* set map origin point */ data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xScrTile*COLNO)/2 ); data->map_orig.y = max(0, client_rt.top + (wnd_size.cy - data->yScrTile*ROWNO)/2 ); data->map_orig.x -= data->map_orig.x % data->xScrTile; data->map_orig.y -= data->map_orig.y % data->yScrTile; /* adjust horizontal scroll bar */ if( data->bFitToScreenMode ) data->xPageSize = COLNO+1; /* disable scroll bar */ else data->xPageSize = wnd_size.cx/data->xScrTile; if( data->xPageSize >= COLNO ) { data->xPos = 0; GetNHApp()->bNoHScroll = TRUE; } else { GetNHApp()->bNoHScroll = FALSE; data->xPos = max(0, min(COLNO-data->xPageSize+1, u.ux - data->xPageSize/2)); } if( !GetNHApp()->bHideScrollBars ) { si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = COLNO; si.nPage = data->xPageSize; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); } /* adjust vertical scroll bar */ if( data->bFitToScreenMode ) data->yPageSize = ROWNO+1; /* disable scroll bar */ else data->yPageSize = wnd_size.cy/data->yScrTile; if( data->yPageSize >= ROWNO ) { data->yPos = 0; GetNHApp()->bNoVScroll = TRUE; } else { GetNHApp()->bNoVScroll = FALSE; data->yPos = max(0, min(ROWNO-data->yPageSize+1, u.uy - data->yPageSize/2)); } if( !GetNHApp()->bHideScrollBars ) { si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = ROWNO; si.nPage = data->yPageSize; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } /* create font */ if( data->hMapFont ) DeleteObject(data->hMapFont); ZeroMemory(&lgfnt, sizeof(lgfnt)); lgfnt.lfHeight = -data->yScrTile; // height of font lgfnt.lfWidth = -data->xScrTile; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if( iflags.wc_font_map && *iflags.wc_font_map ) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family _tcsncpy(lgfnt.lfFaceName, NHMAP_FONT_NAME, LF_FACESIZE); } data->hMapFont = CreateFontIndirect(&lgfnt); mswin_cliparound(data->xCur, data->yCur); if(redraw) InvalidateRect(hWnd, NULL, TRUE); } /* set map mode */ int mswin_map_mode(HWND hWnd, int mode) { PNHMapWindow data; int oldMode; SIZE mapSize; data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); if( mode == data->mapMode ) return mode; oldMode = data->mapMode; data->mapMode = mode; switch( data->mapMode ) { case MAP_MODE_ASCII4x6: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 4*COLNO; mapSize.cy = 6*ROWNO; break; case MAP_MODE_ASCII6x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 6*COLNO; mapSize.cy = 8*ROWNO; break; case MAP_MODE_ASCII8x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 8*COLNO; mapSize.cy = 8*ROWNO; break; case MAP_MODE_ASCII16x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 16*COLNO; mapSize.cy = 8*ROWNO; break; case MAP_MODE_ASCII7x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 7*COLNO; mapSize.cy = 12*ROWNO; break; case MAP_MODE_ASCII8x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 8*COLNO; mapSize.cy = 12*ROWNO; break; case MAP_MODE_ASCII16x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 16*COLNO; mapSize.cy = 12*ROWNO; break; case MAP_MODE_ASCII12x16: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 12*COLNO; mapSize.cy = 16*ROWNO; break; case MAP_MODE_ASCII10x18: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 10*COLNO; mapSize.cy = 18*ROWNO; break; case MAP_MODE_ASCII_FIT_TO_SCREEN: { RECT client_rt; GetClientRect(hWnd, &client_rt); mapSize.cx = client_rt.right - client_rt.left; mapSize.cy = client_rt.bottom - client_rt.top; data->bAsciiMode = TRUE; data->bFitToScreenMode = TRUE; } break; case MAP_MODE_TILES_FIT_TO_SCREEN: { RECT client_rt; GetClientRect(hWnd, &client_rt); mapSize.cx = client_rt.right - client_rt.left; mapSize.cy = client_rt.bottom - client_rt.top; data->bAsciiMode = FALSE; data->bFitToScreenMode = TRUE; } break; case MAP_MODE_TILES: default: data->bAsciiMode = FALSE; data->bFitToScreenMode = FALSE; mapSize.cx = GetNHApp()->mapTile_X*COLNO; mapSize.cy = GetNHApp()->mapTile_Y*ROWNO; break; } mswin_map_stretch(hWnd, &mapSize, TRUE); return oldMode; } /* register window class for map window */ void register_map_window_class() { WNDCLASS wcex; ZeroMemory( &wcex, sizeof(wcex)); /* window class */ wcex.style = CS_NOCLOSE | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC)MapWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */ wcex.lpszMenuName = NULL; wcex.lpszClassName = szNHMapWindowClass; if( !RegisterClass(&wcex) ) { panic("cannot register Map window class"); } } /* map window procedure */ LRESULT CALLBACK MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_CREATE: onCreate( hWnd, wParam, lParam ); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SETFOCUS: /* transfer focus back to the main window */ SetFocus(GetNHApp()->hMainWnd); break; case WM_HSCROLL: onMSNH_HScroll(hWnd, wParam, lParam); break; case WM_VSCROLL: onMSNH_VScroll(hWnd, wParam, lParam); break; case WM_SIZE: { SIZE size; if( data->bFitToScreenMode ) { size.cx = LOWORD(lParam); size.cy = HIWORD(lParam); } else { /* mapping factor is unchaged we just need to adjust scroll bars */ size.cx = data->xScrTile*COLNO; size.cy = data->yScrTile*ROWNO; } mswin_map_stretch(hWnd, &size, TRUE); } break; case WM_LBUTTONDOWN: NHEVENT_MS( CLICK_1, max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile)) ); return 0; case WM_LBUTTONDBLCLK : NHEVENT_MS( CLICK_2, max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile)) ); return 0; case WM_DESTROY: if( data->hMapFont ) DeleteObject(data->hMapFont); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } /* on WM_COMMAND */ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; RECT rt; data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); switch(wParam) { case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph)lParam; data->map[msg_data->x][msg_data->y] = msg_data->glyph; /* invalidate the update area */ nhcoord2display(data, msg_data->x, msg_data->y, &rt); InvalidateRect(hWnd, &rt, TRUE); } break; case MSNH_MSG_CLIPAROUND: { PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround)lParam; int x, y; BOOL scroll_x, scroll_y; int mcam = iflags.wc_scroll_margin; /* calculate if you should clip around */ scroll_x = !GetNHApp()->bNoHScroll && ( msg_data->x<(data->xPos+mcam) || msg_data->x>(data->xPos+data->xPageSize-mcam) ); scroll_y = !GetNHApp()->bNoVScroll && ( msg_data->y<(data->yPos+mcam) || msg_data->y>(data->yPos+data->yPageSize-mcam) ); mcam += iflags.wc_scroll_amount - 1; /* get page size and center horizontally on x-position */ if( scroll_x ) { if( data->xPageSize<=2*mcam ) { x = max(0, min(COLNO, msg_data->x - data->xPageSize/2)); } else if( msg_data->x < data->xPos+data->xPageSize/2 ) { x = max(0, min(COLNO, msg_data->x - mcam)); } else { x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam)); } SendMessage( hWnd, WM_HSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, x), (LPARAM)NULL ); } /* get page size and center vertically on y-position */ if( scroll_y ) { if( data->yPageSize<=2*mcam ) { y = max(0, min(ROWNO, msg_data->y - data->yPageSize/2)); } else if( msg_data->y < data->yPos+data->yPageSize/2 ) { y = max(0, min(ROWNO, msg_data->y - mcam)); } else { y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam)); } SendMessage( hWnd, WM_VSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, y), (LPARAM)NULL ); } } break; case MSNH_MSG_CLEAR_WINDOW: { int i, j; for(i=0; imap[i][j] = -1; } InvalidateRect(hWnd, NULL, TRUE); } break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor)lParam; HDC hdc; RECT rt; /* move focus rectangle at the cursor postion */ hdc = GetDC(hWnd); nhcoord2display(data, data->xCur, data->yCur, &rt); if( data->bAsciiMode ) { PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT); } else { DrawFocusRect(hdc, &rt); } data->xCur = msg_data->x; data->yCur = msg_data->y; nhcoord2display(data, data->xCur, data->yCur, &rt); if( data->bAsciiMode ) { PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT); } else { DrawFocusRect(hdc, &rt); } ReleaseDC(hWnd, hdc); } break; } } /* on WM_CREATE */ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; int i,j; /* set window data */ data = (PNHMapWindow)malloc(sizeof(NHMapWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHMapWindow)); for(i=0; imap[i][j] = -1; } data->bAsciiMode = FALSE; data->xScrTile = GetNHApp()->mapTile_X; data->yScrTile = GetNHApp()->mapTile_Y; SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); } /* on WM_PAINT */ void onPaint(HWND hWnd) { PNHMapWindow data; PAINTSTRUCT ps; HDC hDC; HDC tileDC; HGDIOBJ saveBmp; RECT paint_rt; int i, j; /* get window data */ data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); hDC = BeginPaint(hWnd, &ps); /* calculate paint rectangle */ if( !IsRectEmpty(&ps.rcPaint) ) { /* calculate paint rectangle */ paint_rt.left = max(data->xPos + (ps.rcPaint.left - data->map_orig.x)/data->xScrTile, 0); paint_rt.top = max(data->yPos + (ps.rcPaint.top - data->map_orig.y)/data->yScrTile, 0); paint_rt.right = min(data->xPos + (ps.rcPaint.right - data->map_orig.x)/data->xScrTile+1, COLNO); paint_rt.bottom = min(data->yPos + (ps.rcPaint.bottom - data->map_orig.y)/data->yScrTile+1, ROWNO); if( data->bAsciiMode #ifdef REINCARNATION || Is_rogue_level(&u.uz) /* You enter a VERY primitive world! */ #endif ) { HGDIOBJ oldFont; oldFont = SelectObject(hDC, data->hMapFont); SetBkMode(hDC, TRANSPARENT); /* draw the map */ for(i=paint_rt.left; imap[i][j]>=0) { char ch; TCHAR wch; RECT glyph_rect; int color; unsigned special; int mgch; HBRUSH back_brush; COLORREF OldFg; nhcoord2display(data, i, j, &glyph_rect); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) nhglyph2charcolor(data->map[i][j], &ch, &color); OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) ); #else /* rely on NetHack core helper routine */ mapglyph(data->map[i][j], &mgch, &color, &special, i, j); ch = (char)mgch; if (((special & MG_PET) && iflags.hilite_pet) || ((special & MG_DETECT) && iflags.use_inverse)) { back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); FillRect (hDC, &glyph_rect, back_brush); DeleteObject (back_brush); switch (color) { case CLR_GRAY: case CLR_WHITE: OldFg = SetTextColor( hDC, nhcolor_to_RGB(CLR_BLACK)); break; default: OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) ); } } else { OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) ); } #endif DrawText(hDC, NH_A2W(&ch, &wch, 1), 1, &glyph_rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX ); SetTextColor (hDC, OldFg); } SelectObject(hDC, oldFont); } else { /* prepare tiles DC for mapping */ tileDC = CreateCompatibleDC(hDC); saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); /* draw the map */ for(i=paint_rt.left; imap[i][j]>=0) { short ntile; int t_x, t_y; RECT glyph_rect; ntile = glyph2tile[ data->map[i][j] ]; t_x = (ntile % GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_X; t_y = (ntile / GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_Y; nhcoord2display(data, i, j, &glyph_rect); StretchBlt( hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY ); if( glyph_is_pet(data->map[i][j]) && iflags.wc_hilite_pet ) { /* apply pet mark transparently over pet image */ HDC hdcPetMark; HBITMAP bmPetMarkOld; /* this is DC for petmark bitmap */ hdcPetMark = CreateCompatibleDC(hDC); bmPetMarkOld = SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); nhapply_image_transparent( hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, hdcPetMark, 0, 0, TILE_X, TILE_Y, TILE_BK_COLOR ); SelectObject(hdcPetMark, bmPetMarkOld); DeleteDC(hdcPetMark); } } SelectObject(tileDC, saveBmp); DeleteDC(tileDC); } /* draw focus rect */ nhcoord2display(data, data->xCur, data->yCur, &paint_rt); if( data->bAsciiMode ) { PatBlt( hDC, paint_rt.left, paint_rt.top, paint_rt.right-paint_rt.left, paint_rt.bottom-paint_rt.top, DSTINVERT ); } else { DrawFocusRect(hDC, &paint_rt); } } EndPaint(hWnd, &ps); } /* on WM_VSCROLL */ void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; SCROLLINFO si; int yNewPos; int yDelta; /* get window data */ data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); switch(LOWORD (wParam)) { /* User clicked shaft left of the scroll box. */ case SB_PAGEUP: yNewPos = data->yPos-data->yPageSize; break; /* User clicked shaft right of the scroll box. */ case SB_PAGEDOWN: yNewPos = data->yPos+data->yPageSize; break; /* User clicked the left arrow. */ case SB_LINEUP: yNewPos = data->yPos-1; break; /* User clicked the right arrow. */ case SB_LINEDOWN: yNewPos = data->yPos+1; break; /* User dragged the scroll box. */ case SB_THUMBTRACK: yNewPos = HIWORD(wParam); break; default: yNewPos = data->yPos; } yNewPos = max(0, min(ROWNO-data->yPageSize+1, yNewPos)); if( yNewPos == data->yPos ) return; yDelta = yNewPos - data->yPos; data->yPos = yNewPos; ScrollWindowEx (hWnd, 0, -data->yScrTile * yDelta, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); if( !GetNHApp()->bHideScrollBars ) { si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } } /* on WM_HSCROLL */ void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; SCROLLINFO si; int xNewPos; int xDelta; /* get window data */ data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); switch(LOWORD (wParam)) { /* User clicked shaft left of the scroll box. */ case SB_PAGEUP: xNewPos = data->xPos-data->xPageSize; break; /* User clicked shaft right of the scroll box. */ case SB_PAGEDOWN: xNewPos = data->xPos+data->xPageSize; break; /* User clicked the left arrow. */ case SB_LINEUP: xNewPos = data->xPos-1; break; /* User clicked the right arrow. */ case SB_LINEDOWN: xNewPos = data->xPos+1; break; /* User dragged the scroll box. */ case SB_THUMBTRACK: xNewPos = HIWORD(wParam); break; default: xNewPos = data->xPos; } xNewPos = max(0, min(COLNO-data->xPageSize+1, xNewPos)); if( xNewPos == data->xPos ) return; xDelta = xNewPos - data->xPos; data->xPos = xNewPos; ScrollWindowEx (hWnd, -data->xScrTile * xDelta, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); if( !GetNHApp()->bHideScrollBars ) { si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); } } /* map nethack map coordinates to the screen location */ void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut) { lpOut->left = (x - data->xPos)*data->xScrTile + data->map_orig.x; lpOut->top = (y - data->yPos)*data->yScrTile + data->map_orig.y; lpOut->right = lpOut->left + data->xScrTile; lpOut->bottom = lpOut->top + data->yScrTile; } #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) /* map glyph to character/color combination */ void nhglyph2charcolor(short g, uchar* ch, int* color) { int offset; #ifdef TEXTCOLOR #define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR #define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR #define obj_color(n) *color = iflags.use_color ? objects[n].oc_color : NO_COLOR #define mon_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define pet_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define warn_color(n) *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR # else /* no text color */ #define zap_color(n) #define cmap_color(n) #define obj_color(n) #define mon_color(n) #define pet_color(c) #define warn_color(c) *color = CLR_WHITE; #endif if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */ *ch = warnsyms[offset]; warn_color(offset); } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */ /* see swallow_to_glyph() in display.c */ *ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)]; mon_color(offset >> 3); } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */ /* see zapdir_to_glyph() in display.c */ *ch = showsyms[S_vbeam + (offset & 0x3)]; zap_color((offset >> 2)); } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) { /* cmap */ *ch = showsyms[offset]; cmap_color(offset); } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) { /* object */ *ch = oc_syms[(int)objects[offset].oc_class]; obj_color(offset); } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) { /* a corpse */ *ch = oc_syms[(int)objects[CORPSE].oc_class]; mon_color(offset); } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) { /* a pet */ *ch = monsyms[(int)mons[offset].mlet]; pet_color(offset); } else { /* a monster */ *ch = monsyms[(int)mons[g].mlet]; mon_color(g); } // end of wintty code } #endif /* map nethack color to RGB */ COLORREF nhcolor_to_RGB(int c) { switch(c) { case CLR_BLACK: return RGB(0x55, 0x55, 0x55); case CLR_RED: return RGB(0xFF, 0x00, 0x00); case CLR_GREEN: return RGB(0x00, 0x80, 0x00); case CLR_BROWN: return RGB(0xA5, 0x2A, 0x2A); case CLR_BLUE: return RGB(0x00, 0x00, 0xFF); case CLR_MAGENTA: return RGB(0xFF, 0x00, 0xFF); case CLR_CYAN: return RGB(0x00, 0xFF, 0xFF); case CLR_GRAY: return RGB(0xC0, 0xC0, 0xC0); case NO_COLOR: return RGB(0xFF, 0xFF, 0xFF); case CLR_ORANGE: return RGB(0xFF, 0xA5, 0x00); case CLR_BRIGHT_GREEN: return RGB(0x00, 0xFF, 0x00); case CLR_YELLOW: return RGB(0xFF, 0xFF, 0x00); case CLR_BRIGHT_BLUE: return RGB(0x00, 0xC0, 0xFF); case CLR_BRIGHT_MAGENTA: return RGB(0xFF, 0x80, 0xFF); case CLR_BRIGHT_CYAN: return RGB(0x80, 0xFF, 0xFF); /* something close to aquamarine */ case CLR_WHITE: return RGB(0xFF, 0xFF, 0xFF); default: return RGB(0x00, 0x00, 0x00); /* black */ } } /* apply bitmap pointed by sourceDc transparently over bitmap pointed by hDC */ void nhapply_image_transparent( HDC hDC, int x, int y, int width, int height, HDC sourceDC, int s_x, int s_y, int s_width, int s_height, COLORREF cTransparent ) { TransparentImage( hDC, x, y, width, height, sourceDC, s_x, s_y, s_width, s_height, cTransparent ); } nethack-3.4.3/sys/wince/mhmap.h0100644000000000000000000000102307764735041015044 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMapWindow_h #define MSWINMapWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_map_window (void); void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw); int mswin_map_mode(HWND hWnd, int mode); #define ROGUE_LEVEL_MAP_MODE MAP_MODE_ASCII12x16 #define DEF_CLIPAROUND_MARGIN 5 #define DEF_CLIPAROUND_AMOUNT 1 #endif /* MSWINMapWindow_h */ nethack-3.4.3/sys/wince/mhmenu.c0100644000000000000000000012053007764735041015233 0ustar rootroot/* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include #include "mhmenu.h" #include "mhmain.h" #include "mhmsg.h" #include "mhcmd.h" #include "mhinput.h" #include "mhfont.h" #include "mhcolor.h" #include "mhtxtbuf.h" #define MENU_MARGIN 0 #define NHMENU_STR_SIZE BUFSZ #define MIN_TABSTOP_SIZE 0 #define NUMTABS 15 #define TAB_SEPARATION 10 /* pixels between each tab stop */ typedef struct mswin_menu_item { int glyph; ANY_P identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; char str[NHMENU_STR_SIZE]; BOOLEAN_P presel; int count; BOOL has_focus; BOOL has_tab; } NHMenuItem, *PNHMenuItem; typedef struct mswin_nethack_menu_window { int type; /* MENU_TYPE_TEXT or MENU_TYPE_MENU */ int how; /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */ union { struct menu_list { int size; /* number of items in items[] */ int allocated; /* number of allocated slots in items[] */ PNHMenuItem items; /* menu items */ char gacc[QBUFSZ]; /* group accelerators */ BOOL counting; /* counting flag */ char prompt[QBUFSZ]; /* menu prompt */ int tab_stop_size[NUMTABS];/* tabstops to align option values */ } menu; struct menu_text { PNHTextBuffer text; } text; }; int result; int done; HBITMAP bmpChecked; HBITMAP bmpCheckedCount; HBITMAP bmpNotChecked; } NHMenuWindow, *PNHMenuWindow; extern short glyph2tile[]; static WNDPROC wndProcListViewOrig = NULL; static WNDPROC editControlWndProc = NULL; #define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj!=NULL) #define NHMENU_IS_SELECTED(item) ((item).count!=0) LRESULT CALLBACK MenuWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuTextWndProc(HWND, UINT, WPARAM, LPARAM); static void CheckInputDialog(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static LRESULT onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static LRESULT onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutMenu(HWND hwnd); static void SetMenuType(HWND hwnd, int type); static void SetMenuListType(HWND hwnd, int now); static HWND GetMenuControl(HWND hwnd); static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count); static void reset_menu_count(HWND hwndList, PNHMenuWindow data); static LRESULT onListChar(HWND hWnd, HWND hwndList, WORD ch); static char* parse_menu_str(char* dest, const char* src, size_t size); HWND mswin_init_menu_window (int type) { HWND ret; ret = CreateDialog( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_MENU), GetNHApp()->hMainWnd, MenuWndProc ); if( !ret ) { panic("Cannot create menu window"); } SetMenuType(ret, type); return ret; } int mswin_menu_window_select_menu (HWND hWnd, int how, MENU_ITEM_P ** _selected) { PNHMenuWindow data; int ret_val; MENU_ITEM_P *selected = NULL; int i; char* ap; char accell_str[256]; assert( _selected!=NULL ); *_selected = NULL; ret_val = -1; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); /* set menu type */ SetMenuListType(hWnd, how); /* Ok, now give items a unique accelerators */ ZeroMemory(accell_str, sizeof(accell_str)); ap = accell_str; #if defined(WIN_CE_SMARTPHONE) if( data->menu.size>10 ) { *ap++ = MENU_FIRST_PAGE; *ap++ = MENU_LAST_PAGE; *ap++ = MENU_NEXT_PAGE; *ap++ = MENU_PREVIOUS_PAGE; if( data->how == PICK_ANY ) { *ap++ = MENU_SELECT_ALL; *ap++ = MENU_UNSELECT_ALL; *ap++ = MENU_INVERT_ALL; *ap++ = MENU_SELECT_PAGE; *ap++ = MENU_UNSELECT_PAGE; *ap++ = MENU_INVERT_PAGE; } *ap++ = MENU_SEARCH; } #endif if( data->type == MENU_TYPE_MENU ) { char next_char = 'a'; for( i=0; imenu.size; i++) { if( data->menu.items[i].accelerator!=0 ) { *ap++ = data->menu.items[i].accelerator; next_char = (char)(data->menu.items[i].accelerator+1); } else if( NHMENU_IS_SELECTABLE(data->menu.items[i]) ) { if ( (next_char>='a' && next_char<='z') || (next_char>='A' && next_char<='Z') ) { data->menu.items[i].accelerator = next_char; *ap++ = data->menu.items[i].accelerator; } else { if( next_char > 'z' ) next_char = 'A'; else if ( next_char > 'Z' ) break; data->menu.items[i].accelerator = next_char; *ap++ = data->menu.items[i].accelerator; } next_char ++; } } /* collect group accelerators */ data->menu.gacc[0] = '\0'; ap = data->menu.gacc; if( data->how != PICK_NONE ) { for( i=0; imenu.size; i++) { if( data->menu.items[i].group_accel && !strchr(data->menu.gacc, data->menu.items[i].group_accel) ) { *ap++ = data->menu.items[i].group_accel; *ap = '\x0'; } } } reset_menu_count(NULL, data); } #if defined(WIN_CE_SMARTPHONE) if( data->type==MENU_TYPE_MENU ) NHSPhoneSetKeypadFromString( accell_str ); #endif mswin_popup_display(hWnd, &data->done); /* get the result */ if( data->result != -1 ) { if(how==PICK_NONE) { if(data->result>=0) ret_val=0; else ret_val=-1; } else if(how==PICK_ONE || how==PICK_ANY) { /* count selected items */ ret_val = 0; for(i=0; imenu.size; i++ ) { if( NHMENU_IS_SELECTABLE(data->menu.items[i]) && NHMENU_IS_SELECTED(data->menu.items[i]) ) { ret_val++; } } if( ret_val > 0 ) { int sel_ind; selected = (MENU_ITEM_P*)malloc(ret_val*sizeof(MENU_ITEM_P)); if( !selected ) panic("out of memory"); sel_ind = 0; for(i=0; imenu.size; i++ ) { if( NHMENU_IS_SELECTABLE(data->menu.items[i]) && NHMENU_IS_SELECTED(data->menu.items[i]) ) { selected[sel_ind].item = data->menu.items[i].identifier; selected[sel_ind].count = data->menu.items[i].count; sel_ind++; } } ret_val = sel_ind; *_selected = selected; } } } mswin_popup_destroy(hWnd); #if defined(WIN_CE_SMARTPHONE) if( data->type==MENU_TYPE_MENU ) NHSPhoneSetKeypadDefault(); #endif return ret_val; } LRESULT CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMenuWindow data; CheckInputDialog(hWnd, message, wParam, lParam); data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_INITDIALOG: { HWND text_control; HDC hDC; text_control = GetDlgItem(hWnd, IDC_MENU_TEXT); data = (PNHMenuWindow)malloc(sizeof(NHMenuWindow)); ZeroMemory(data, sizeof(NHMenuWindow)); data->type = MENU_TYPE_TEXT; data->how = PICK_NONE; data->result = 0; data->done = 0; data->bmpChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL)); data->bmpCheckedCount = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); /* subclass edit control */ editControlWndProc = (WNDPROC)GetWindowLong(text_control, GWL_WNDPROC); SetWindowLong(text_control, GWL_WNDPROC, (LONG)NHMenuTextWndProc); /* set text window font */ hDC = GetDC(text_control); SendMessage( text_control, WM_SETFONT, (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hDC, FALSE), (LPARAM)0 ); ReleaseDC(text_control, hDC); #if defined(WIN_CE_SMARTPHONE) /* special initialization for SmartPhone dialogs */ NHSPhoneDialogSetup(hWnd, FALSE, GetNHApp()->bFullScreen); #endif } break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_SIZE: LayoutMenu(hWnd); return FALSE; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: if( data->type == MENU_TYPE_MENU && (data->how==PICK_ONE || data->how==PICK_ANY) && data->menu.counting) { HWND list; int i; /* reset counter if counting is in progress */ list = GetMenuControl(hWnd); i = ListView_GetNextItem(list, -1, LVNI_FOCUSED); if( i>=0 ) { SelectMenuItem(list, data, i, 0); } return FALSE; } else { data->result = -1; data->done = 1; } return FALSE; case IDOK: data->done = 1; data->result = 0; return FALSE; } } break; case WM_NOTIFY: { LPNMHDR lpnmhdr = (LPNMHDR)lParam; switch (LOWORD(wParam)) { case IDC_MENU_LIST: { if( !data || data->type!=MENU_TYPE_MENU ) break; switch(lpnmhdr->code) { case LVN_ITEMACTIVATE: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam; if(data->how==PICK_ONE) { if( lpnmlv->iItem>=0 && lpnmlv->iItemmenu.size && NHMENU_IS_SELECTABLE(data->menu.items[lpnmlv->iItem]) ) { SelectMenuItem( lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1 ); data->done = 1; data->result = 0; return TRUE; } } else if( data->how==PICK_ANY ) { if( lpnmlv->iItem>=0 && lpnmlv->iItemmenu.size && NHMENU_IS_SELECTABLE(data->menu.items[lpnmlv->iItem]) ) { SelectMenuItem( lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, NHMENU_IS_SELECTED(data->menu.items[lpnmlv->iItem])? 0 : -1 ); } } } break; case NM_CLICK: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) lParam; if( lpnmlv->iItem==-1 ) return 0; if( data->how==PICK_ANY ) { SelectMenuItem( lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, NHMENU_IS_SELECTED(data->menu.items[lpnmlv->iItem])? 0 : -1 ); } } break; case LVN_ITEMCHANGED: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam; if( lpnmlv->iItem==-1 ) return 0; if( !(lpnmlv->uChanged & LVIF_STATE) ) return 0; /* update item that has the focus */ data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); /* update count for single-selection menu (follow the listview selection) */ if( data->how==PICK_ONE ) { if( lpnmlv->uNewState & LVIS_SELECTED ) { SelectMenuItem( lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1 ); } } /* check item focus */ data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); } break; case NM_KILLFOCUS: reset_menu_count(lpnmhdr->hwndFrom, data); break; } } break; } } break; case WM_SETFOCUS: if( hWnd!=GetNHApp()->hPopupWnd ) { SetFocus(GetNHApp()->hPopupWnd ); return 0; } break; case WM_MEASUREITEM: if( wParam==IDC_MENU_LIST ) return onMeasureItem(hWnd, wParam, lParam); else return FALSE; case WM_DRAWITEM: if( wParam==IDC_MENU_LIST ) return onDrawItem(hWnd, wParam, lParam); else return FALSE; case WM_CTLCOLORBTN: case WM_CTLCOLOREDIT: case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */ HDC hdcEdit = (HDC) wParam; HWND hwndEdit = (HWND) lParam; if( hwndEdit == GetDlgItem(hWnd, IDC_MENU_TEXT) ) { SetBkColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_BG)); SetTextColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_FG)); return (BOOL)mswin_get_brush(NHW_TEXT, MSWIN_COLOR_BG); } } return FALSE; case WM_DESTROY: if( data ) { DeleteObject(data->bmpChecked); DeleteObject(data->bmpCheckedCount); DeleteObject(data->bmpNotChecked); if( data->type == MENU_TYPE_TEXT ) { if( data->text.text ) { mswin_free_text_buffer(data->text.text); data->text.text = NULL; } } free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); } return TRUE; } return FALSE; } void CheckInputDialog(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { #if defined(WIN_CE_POCKETPC) PNHMenuWindow data; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); if( !( data && data->type==MENU_TYPE_MENU && (data->how==PICK_ONE || data->how==PICK_ANY) ) ) return; switch(message) { case WM_SETFOCUS: if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP); return; case WM_DESTROY: case WM_KILLFOCUS: if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN); return; case WM_NOTIFY: { LPNMHDR lpnmhdr = (LPNMHDR)lParam; switch(lpnmhdr->code) { case NM_SETFOCUS: if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP); break; case NM_KILLFOCUS: if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN); break; } } return; case WM_COMMAND: switch(HIWORD(wParam)) { case BN_SETFOCUS: if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_UP); break; case BN_KILLFOCUS: if( GetNHApp()->bUseSIP ) SHSipPreference(hWnd, SIP_DOWN); break; } return; } /* end switch */ #endif } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMenuWindow data; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( wParam ) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam; HWND text_view; if( data->type!=MENU_TYPE_TEXT ) SetMenuType(hWnd, MENU_TYPE_TEXT); if( !data->text.text ) { data->text.text = mswin_init_text_buffer( program_state.gameover? FALSE : GetNHApp()->bWrapText ); if( !data->text.text ) break; } mswin_add_text(data->text.text, msg_data->attr, msg_data->text); text_view = GetDlgItem(hWnd, IDC_MENU_TEXT); if( !text_view ) panic("cannot get text view window"); mswin_render_text(data->text.text, text_view); } break; case MSNH_MSG_STARTMENU: { int i; if( data->type!=MENU_TYPE_MENU ) SetMenuType(hWnd, MENU_TYPE_MENU); if( data->menu.items ) free(data->menu.items); data->how = PICK_NONE; data->menu.items = NULL; data->menu.size = 0; data->menu.allocated = 0; data->done = 0; data->result = 0; for (i = 0; i < NUMTABS; ++i) data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE; } break; case MSNH_MSG_ADDMENU: { PMSNHMsgAddMenu msg_data = (PMSNHMsgAddMenu)lParam; char *p, *p1; int new_item; HDC hDC; int column; HFONT saveFont; if( data->type!=MENU_TYPE_MENU ) break; if( strlen(msg_data->str)==0 ) break; if( data->menu.size==data->menu.allocated ) { data->menu.allocated += 10; data->menu.items = (PNHMenuItem)realloc(data->menu.items, data->menu.allocated*sizeof(NHMenuItem)); } new_item = data->menu.size; ZeroMemory( &data->menu.items[new_item], sizeof(data->menu.items[new_item])); data->menu.items[new_item].glyph = msg_data->glyph; data->menu.items[new_item].identifier = *msg_data->identifier; data->menu.items[new_item].accelerator = msg_data->accelerator; data->menu.items[new_item].group_accel = msg_data->group_accel; data->menu.items[new_item].attr = msg_data->attr; parse_menu_str(data->menu.items[new_item].str, msg_data->str, NHMENU_STR_SIZE); data->menu.items[new_item].presel = msg_data->presel; /* calculate tabstop size */ p = strchr(data->menu.items[new_item].str, '\t'); if( p ) { data->menu.items[new_item].has_tab = TRUE; hDC = GetDC(hWnd); saveFont = SelectObject(hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE)); p1 = data->menu.items[new_item].str; column = 0; for (;;) { TCHAR wbuf[BUFSZ]; RECT drawRect; SetRect ( &drawRect, 0, 0, 1, 1 ); if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS | DT_SINGLELINE ); data->menu.tab_stop_size[column] = max( data->menu.tab_stop_size[column], drawRect.right - drawRect.left ); if (p != NULL) *p = '\t'; else /* last string so, */ break; ++column; p1 = p + 1; p = strchr(p1, '\t'); } SelectObject(hDC, saveFont); ReleaseDC(hWnd, hDC); } else { data->menu.items[new_item].has_tab = FALSE; } /* increment size */ data->menu.size++; } break; case MSNH_MSG_ENDMENU: { PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu)lParam; if( msg_data->text ) { strncpy( data->menu.prompt, msg_data->text, sizeof(data->menu.prompt)-1 ); } else { ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt)); } } break; } /* end switch */ } void LayoutMenu(HWND hWnd) { PNHMenuWindow data; HWND menu_ok; HWND menu_cancel; RECT clrt, rt; POINT pt_elem, pt_ok, pt_cancel; SIZE sz_elem, sz_ok, sz_cancel; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); menu_ok = GetDlgItem(hWnd, IDOK); menu_cancel = GetDlgItem(hWnd, IDCANCEL); /* get window coordinates */ GetClientRect(hWnd, &clrt ); /* set window placements */ if( IsWindow(menu_ok) ) { GetWindowRect(menu_ok, &rt); sz_ok.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN; sz_ok.cy = rt.bottom-rt.top; pt_ok.x = clrt.left + MENU_MARGIN; pt_ok.y = clrt.bottom - MENU_MARGIN - sz_ok.cy; MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE ); } else { pt_ok.x = 0; pt_ok.y = clrt.bottom; sz_ok.cx = sz_ok.cy = 0; } if( IsWindow(menu_cancel) ) { GetWindowRect(menu_cancel, &rt); sz_cancel.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN; sz_cancel.cy = rt.bottom-rt.top; pt_cancel.x = (clrt.left + clrt.right)/2 + MENU_MARGIN; pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy; MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx, sz_cancel.cy, TRUE ); } else { pt_cancel.x = 0; pt_cancel.y = clrt.bottom; sz_cancel.cx = sz_cancel.cy = 0; } pt_elem.x = clrt.left + MENU_MARGIN; pt_elem.y = clrt.top + MENU_MARGIN; sz_elem.cx = (clrt.right - clrt.left) - 2*MENU_MARGIN; sz_elem.cy = min(pt_cancel.y, pt_ok.y) - MENU_MARGIN - pt_elem.y; MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE ); /* reformat text for the text menu */ if( data && data->type==MENU_TYPE_TEXT && data->text.text ) mswin_render_text(data->text.text, GetMenuControl(hWnd)); } void SetMenuType(HWND hWnd, int type) { PNHMenuWindow data; HWND list, text; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); data->type = type; text = GetDlgItem(hWnd, IDC_MENU_TEXT); list = GetDlgItem(hWnd, IDC_MENU_LIST); if(data->type==MENU_TYPE_TEXT) { ShowWindow(list, SW_HIDE); EnableWindow(list, FALSE); EnableWindow(text, TRUE); ShowWindow(text, SW_SHOW); SetFocus(text); } else { ShowWindow(text, SW_HIDE); EnableWindow(text, FALSE); EnableWindow(list, TRUE); ShowWindow(list, SW_SHOW); SetFocus(list); } LayoutMenu(hWnd); } void SetMenuListType(HWND hWnd, int how) { PNHMenuWindow data; RECT rt; DWORD dwStyles; char buf[BUFSZ]; TCHAR wbuf[BUFSZ]; int nItem; int i; HWND control; LVCOLUMN lvcol; LRESULT fnt; SIZE wnd_size; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); if( data->type != MENU_TYPE_MENU ) return; data->how = how; switch(how) { case PICK_NONE: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; case PICK_ONE: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; case PICK_ANY: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; default: panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY"); }; if( strlen(data->menu.prompt)==0 ) { dwStyles |= LVS_NOCOLUMNHEADER ; } GetWindowRect(GetDlgItem(hWnd, IDC_MENU_LIST), &rt); DestroyWindow(GetDlgItem(hWnd, IDC_MENU_LIST)); control = CreateWindow(WC_LISTVIEW, NULL, dwStyles, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hWnd, (HMENU)IDC_MENU_LIST, GetNHApp()->hApp, NULL ); if( !control ) panic( "cannot create menu control" ); /* install the hook for the control window procedure */ wndProcListViewOrig = (WNDPROC)GetWindowLong(control, GWL_WNDPROC); SetWindowLong(control, GWL_WNDPROC, (LONG)NHMenuListWndProc); /* set control font */ fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM)0, (LPARAM)0); SendMessage(control, WM_SETFONT, (WPARAM)fnt, (LPARAM)0); /* set control colors */ ListView_SetBkColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_BG)); ListView_SetTextBkColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_BG)); ListView_SetTextColor(control, mswin_get_color(NHW_MENU, MSWIN_COLOR_FG)); /* add column to the list view */ mswin_menu_window_size(hWnd, &wnd_size); ZeroMemory(&lvcol, sizeof(lvcol)); lvcol.mask = LVCF_WIDTH | LVCF_TEXT; lvcol.cx = max( wnd_size.cx, GetSystemMetrics(SM_CXSCREEN)); lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ); ListView_InsertColumn(control, 0, &lvcol); /* add items to the list view */ for(i=0; imenu.size; i++ ) { LVITEM lvitem; ZeroMemory( &lvitem, sizeof(lvitem) ); sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '), data->menu.items[i].str ); lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; lvitem.iItem = i; lvitem.iSubItem = 0; lvitem.state = data->menu.items[i].presel? LVIS_SELECTED : 0; lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ); lvitem.lParam = (LPARAM)&data->menu.items[i]; nItem = SendMessage(control, LB_ADDSTRING, (WPARAM)0, (LPARAM) buf); if( ListView_InsertItem(control, &lvitem)==-1 ) { panic("cannot insert menu item"); } } SetFocus(control); } HWND GetMenuControl(HWND hWnd) { PNHMenuWindow data; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); if(data->type==MENU_TYPE_TEXT) { return GetDlgItem(hWnd, IDC_MENU_TEXT); } else { return GetDlgItem(hWnd, IDC_MENU_LIST); } } LRESULT onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPMEASUREITEMSTRUCT lpmis; TEXTMETRIC tm; HGDIOBJ saveFont; HDC hdc; PNHMenuWindow data; RECT list_rect; lpmis = (LPMEASUREITEMSTRUCT) lParam; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); GetClientRect(GetMenuControl(hWnd), &list_rect); hdc = GetDC(GetMenuControl(hWnd)); saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE)); GetTextMetrics(hdc, &tm); /* Set the height of the list box items. */ lpmis->itemHeight = max(tm.tmHeight, TILE_Y)+2; lpmis->itemWidth = list_rect.right - list_rect.left; SelectObject(hdc, saveFont); ReleaseDC(GetMenuControl(hWnd), hdc); return TRUE; } LRESULT onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPDRAWITEMSTRUCT lpdis; PNHMenuItem item; PNHMenuWindow data; TEXTMETRIC tm; HGDIOBJ saveFont; HDC tileDC; short ntile; int t_x, t_y; int x, y; TCHAR wbuf[BUFSZ]; RECT drawRect; COLORREF OldBg, OldFg, NewBg; char *p, *p1; int column; lpdis = (LPDRAWITEMSTRUCT) lParam; /* If there are no list box items, skip this message. */ if (lpdis->itemID == -1) return FALSE; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); item = &data->menu.items[lpdis->itemID]; tileDC = CreateCompatibleDC(lpdis->hDC); saveFont = SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE)); NewBg = mswin_get_color(NHW_MENU, MSWIN_COLOR_BG); OldBg = SetBkColor(lpdis->hDC, NewBg); OldFg = SetTextColor(lpdis->hDC, mswin_get_color(NHW_MENU, MSWIN_COLOR_FG)); GetTextMetrics(lpdis->hDC, &tm); x = lpdis->rcItem.left + 1; /* print check mark if it is a "selectable" menu */ if( data->how!=PICK_NONE ) { if( NHMENU_IS_SELECTABLE(*item) ) { HGDIOBJ saveBrush; HBRUSH hbrCheckMark; char buf[2]; switch(item->count) { case -1: hbrCheckMark = CreatePatternBrush(data->bmpChecked); break; case 0: hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); break; default: hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); break; } y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; SetBrushOrgEx(lpdis->hDC, x, y, NULL); saveBrush = SelectObject(lpdis->hDC, hbrCheckMark); PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY); SelectObject(lpdis->hDC, saveBrush); DeleteObject(hbrCheckMark); x += TILE_X + 5; if(item->accelerator!=0) { buf[0] = item->accelerator; buf[1] = '\x0'; SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom ); DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); } x += tm.tmAveCharWidth + tm.tmOverhang + 5; } else { x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 10; } } /* print glyph if present */ if( item->glyph != NO_GLYPH ) { HGDIOBJ saveBmp; saveBmp = SelectObject(tileDC, GetNHApp()->bmpTiles); ntile = glyph2tile[ item->glyph ]; t_x = (ntile % TILES_PER_LINE)*TILE_X; t_y = (ntile / TILES_PER_LINE)*TILE_Y; y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; nhapply_image_transparent( lpdis->hDC, x, y, TILE_X, TILE_Y, tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR ); SelectObject(tileDC, saveBmp); } x += TILE_X + 5; /* draw item text */ if( item->has_tab ) { p1 = item->str; p = strchr(item->str, '\t'); column = 0; SetRect( &drawRect, x, lpdis->rcItem.top, min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right), lpdis->rcItem.bottom ); for (;;) { TCHAR wbuf[BUFSZ]; if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(lpdis->hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE ); if (p != NULL) *p = '\t'; else /* last string so, */ break; p1 = p + 1; p = strchr(p1, '\t'); drawRect.left = drawRect.right + TAB_SEPARATION; ++column; drawRect.right = min (drawRect.left + data->menu.tab_stop_size[column], lpdis->rcItem.right); } } else { TCHAR wbuf[BUFSZ]; SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom); DrawText(lpdis->hDC, NH_A2W(item->str, wbuf, BUFSZ), strlen(item->str), &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE ); } /* draw focused item */ if( item->has_focus ) { RECT client_rt; HBRUSH bkBrush; GetClientRect(lpdis->hwndItem, &client_rt); if( NHMENU_IS_SELECTABLE(*item) && data->menu.items[lpdis->itemID].count>0 && item->glyph != NO_GLYPH ) { if( data->menu.items[lpdis->itemID].count==-1 ) { _stprintf(wbuf, TEXT("Count: All") ); } else { _stprintf(wbuf, TEXT("Count: %d"), data->menu.items[lpdis->itemID].count ); } SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE)); /* calculate text rectangle */ SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom ); DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, DT_CALCRECT | DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX ); /* erase text rectangle */ drawRect.left = max(client_rt.left+1, client_rt.right - (drawRect.right - drawRect.left) - 10); drawRect.right = client_rt.right-1; drawRect.top = lpdis->rcItem.top; drawRect.bottom = lpdis->rcItem.bottom; bkBrush = CreateSolidBrush( GetBkColor(lpdis->hDC) ); FillRect(lpdis->hDC, &drawRect, bkBrush ); DeleteObject( bkBrush ); /* draw text */ DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX ); } /* draw focus rect */ SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom ); DrawFocusRect(lpdis->hDC, &drawRect); } SetTextColor (lpdis->hDC, OldFg); SetBkColor (lpdis->hDC, OldBg); SelectObject(lpdis->hDC, saveFont); DeleteDC(tileDC); return TRUE; } BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch) { int i = 0; PNHMenuWindow data; int curIndex, topIndex, pageSize; boolean is_accelerator = FALSE; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( ch ) { case MENU_FIRST_PAGE: i = 0; ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_LAST_PAGE: i = max(0, data->menu.size-1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_NEXT_PAGE: topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus down one page */ i = min(curIndex+pageSize, data->menu.size-1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos down one page */ i = min(topIndex+(2*pageSize - 1), data->menu.size-1); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_PREVIOUS_PAGE: topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus up one page */ i = max(curIndex-pageSize, 0); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos up one page */ i = max(topIndex-pageSize, 0); ListView_EnsureVisible(hwndList, i, FALSE); break; case MENU_SELECT_ALL: if( data->how == PICK_ANY ) { reset_menu_count(hwndList, data); for(i=0; imenu.size; i++ ) { SelectMenuItem(hwndList, data, i, -1); } return -2; } break; case MENU_UNSELECT_ALL: if( data->how == PICK_ANY ) { reset_menu_count(hwndList, data); for(i=0; imenu.size; i++ ) { SelectMenuItem(hwndList, data, i, 0); } return -2; } break; case MENU_INVERT_ALL: if( data->how == PICK_ANY ) { reset_menu_count(hwndList, data); for(i=0; imenu.size; i++ ) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); } return -2; } break; case MENU_SELECT_PAGE: if( data->how == PICK_ANY ) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); from = max(0, topIndex); to = min(data->menu.size, from+pageSize); for(i=from; ihow == PICK_ANY ) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); from = max(0, topIndex); to = min(data->menu.size, from+pageSize); for(i=from; ihow == PICK_ANY ) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); from = max(0, topIndex); to = min(data->menu.size, from+pageSize); for(i=from; imenu.items[i])? 0 : -1 ); } return -2; } break; case MENU_SEARCH: if( data->how==PICK_ANY || data->how==PICK_ONE ) { char buf[BUFSZ]; int selected_item; reset_menu_count(hwndList, data); mswin_getlin("Search for:", buf); if (!*buf || *buf == '\033') return -2; selected_item = -1; for(i=0; imenu.size; i++ ) { if( NHMENU_IS_SELECTABLE(data->menu.items[i]) && strstr(data->menu.items[i].str, buf) ) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); /* save the first item - we will move focus to it */ if( selected_item == -1 ) selected_item = i; } else if( data->how == PICK_ONE ) { SelectMenuItem( hwndList, data, i, -1 ); selected_item = i; break; } } } if( selected_item>0 ) { ListView_SetItemState(hwndList, selected_item, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, selected_item, FALSE); } } else { mswin_nhbell(); } return -2; case ' ': /* ends menu for PICK_ONE/PICK_NONE select item for PICK_ANY */ if( data->how==PICK_ONE || data->how==PICK_NONE ) { data->done = 1; data->result = 0; return -2; } else if( data->how==PICK_ANY ) { i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if( i>=0 ) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); } return -2; } break; default: if( strchr(data->menu.gacc, ch) && !(ch=='0' && data->menu.counting) ) { /* matched a group accelerator */ if (data->how == PICK_ANY || data->how == PICK_ONE) { reset_menu_count(hwndList, data); for(i=0; imenu.size; i++ ) { if( NHMENU_IS_SELECTABLE(data->menu.items[i]) && data->menu.items[i].group_accel == ch ) { if( data->how == PICK_ANY ) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); } else if( data->how == PICK_ONE ) { SelectMenuItem( hwndList, data, i, -1 ); data->result = 0; data->done = 1; return -2; } } } return -2; } else { mswin_nhbell(); return -2; } } if (isdigit(ch)) { int count; i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if( i>=0 ) { count = data->menu.items[i].count; if( count==-1 ) count=0; count *= 10L; count += (int)(ch - '0'); if (count != 0) /* ignore leading zeros */ { data->menu.counting = TRUE; data->menu.items[i].count = min(100000, count); ListView_RedrawItems( hwndList, i, i ); /* update count mark */ } } return -2; } is_accelerator = FALSE; for(i=0; imenu.size; i++) { if( data->menu.items[i].accelerator == ch ) { is_accelerator = TRUE; break; } } if( (ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || is_accelerator) { if (data->how == PICK_ANY || data->how == PICK_ONE) { for(i=0; imenu.size; i++ ) { if( data->menu.items[i].accelerator == ch ) { if( data->how == PICK_ANY ) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; } else if( data->how == PICK_ONE ) { SelectMenuItem( hwndList, data, i, -1 ); data->result = 0; data->done = 1; return -2; } } } } } break; } reset_menu_count(hwndList, data); return -1; } void mswin_menu_window_size (HWND hWnd, LPSIZE sz) { TEXTMETRIC tm; HWND control; HGDIOBJ saveFont; HDC hdc; PNHMenuWindow data; int i; RECT rt, wrt; int extra_cx; GetClientRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; GetWindowRect(hWnd, &wrt); extra_cx = (wrt.right-wrt.left) - sz->cx; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); if(data) { control = GetMenuControl(hWnd); hdc = GetDC(control); if( data->type==MENU_TYPE_MENU ) { /* Calculate the width of the list box. */ saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE)); GetTextMetrics(hdc, &tm); for(i=0; imenu.size; i++ ) { LONG menuitemwidth = 0; int column; char *p, *p1; p1 = data->menu.items[i].str; p = strchr(data->menu.items[i].str, '\t'); column = 0; for (;;) { TCHAR wbuf[BUFSZ]; RECT tabRect; SetRect ( &tabRect, 0, 0, 1, 1 ); if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(hdc, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &tabRect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE ); /* it probably isn't necessary to recompute the tab width now, but do so * just in case, honoring the previously computed value */ menuitemwidth += max(data->menu.tab_stop_size[column], tabRect.right - tabRect.left); if (p != NULL) *p = '\t'; else /* last string so, */ break; /* add the separation only when not the last item */ /* in the last item, we break out of the loop, in the statement just above */ menuitemwidth += TAB_SEPARATION; ++column; p1 = p + 1; p = strchr(p1, '\t'); } sz->cx = max(sz->cx, (LONG)(2*TILE_X + menuitemwidth + tm.tmAveCharWidth*12 + tm.tmOverhang)); } SelectObject(hdc, saveFont); } else { /* do not change size for text output - the text will be formatted to fit any window */ } sz->cx += extra_cx; ReleaseDC(control, hdc); } } void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count) { int i; if( item<0 || item>=data->menu.size ) return; if( data->how==PICK_ONE && count!=0 ) { for(i=0; imenu.size; i++) if( item!=i && data->menu.items[i].count!=0 ) { data->menu.items[i].count = 0; ListView_RedrawItems( hwndList, i, i ); }; } data->menu.items[item].count = count; ListView_RedrawItems( hwndList, item, item ); reset_menu_count(hwndList, data); } void reset_menu_count(HWND hwndList, PNHMenuWindow data) { int i; data->menu.counting = FALSE; if( IsWindow(hwndList) ) { i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED); if( i>=0 ) ListView_RedrawItems( hwndList, i, i ); } } /* List window Proc */ LRESULT CALLBACK NHMenuListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { BOOL bUpdateFocusItem = FALSE; switch(message) { /* filter keyboard input for the control */ #if !defined(WIN_CE_SMARTPHONE) case WM_KEYDOWN: case WM_KEYUP: { MSG msg; if( PeekMessage(&msg, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE) ) { if( onListChar(GetParent(hWnd), hWnd, (char)msg.wParam)==-2 ) { return 0; } } if( wParam==VK_LEFT || wParam==VK_RIGHT ) bUpdateFocusItem = TRUE; } break; #else /* defined(WIN_CE_SMARTPHONE) */ case WM_KEYDOWN: if( wParam==VK_TACTION ) { if( onListChar(GetParent(hWnd), hWnd, ' ')==-2 ) { return 0; } } else if( NHSPhoneTranslateKbdMessage(wParam, lParam, TRUE) ) { PMSNHEvent evt; BOOL processed = FALSE; if( mswin_have_input() ) { evt = mswin_input_pop(); if( evt->type==NHEVENT_CHAR && onListChar(GetParent(hWnd), hWnd, evt->kbd.ch)==-2 ) { processed = TRUE; } /* eat the rest of the events */ if( mswin_have_input() ) mswin_input_pop(); } if( processed ) return 0; } if( wParam==VK_LEFT || wParam==VK_RIGHT ) bUpdateFocusItem = TRUE; break; case WM_KEYUP: /* translate SmartPhone keyboard message */ if( NHSPhoneTranslateKbdMessage(wParam, lParam, FALSE) ) return 0; break; /* tell Windows not to process default button on VK_RETURN */ case WM_GETDLGCODE: return DLGC_DEFPUSHBUTTON | DLGC_WANTALLKEYS | (wndProcListViewOrig? CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam) : 0 ); #endif case WM_SIZE: case WM_HSCROLL: bUpdateFocusItem = TRUE; break; } if( bUpdateFocusItem ) { int i; RECT rt; /* invalidate the focus rectangle */ i = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED); if( i!=-1 ) { ListView_GetItemRect(hWnd, i, &rt, LVIR_BOUNDS); InvalidateRect(hWnd, &rt, TRUE); } } if( wndProcListViewOrig ) return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam); else return 0; } /* Text control window proc - implements close on space */ LRESULT CALLBACK NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_KEYUP: switch( wParam ) { case VK_SPACE: case VK_RETURN: /* close on space */ PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0); return 0; case VK_UP: /* scoll up */ PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); return 0; case VK_DOWN: /* scoll down */ PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL); return 0; case VK_LEFT: /* scoll left */ PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINELEFT, 0), (LPARAM)NULL); return 0; case VK_RIGHT: /* scoll right */ PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM)NULL); return 0; } break; /* case WM_KEYUP: */ } if( editControlWndProc ) return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam); else return 0; } /*----------------------------------------------------------------------------*/ char* parse_menu_str(char* dest, const char* src, size_t size) { char *p1, *p2; if( !dest || size==0 ) return NULL; strncpy(dest, src, size); dest[size-1] = '\x0'; /* replace "[ ]*\[" with "\t\[" */ p1 = p2 = strstr(dest, " ["); if( p1 ) { while( p1!=dest && *p1==' ') p1--; p1++; /* backup to space */ *p2 = '\t'; memmove(p1, p2, strlen(p2)); p1[strlen(p2)] = '\x0'; } return dest; } nethack-3.4.3/sys/wince/mhmenu.h0100644000000000000000000000067007764735041015242 0ustar rootroot/* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMenuWindow_h #define MSWINMenuWindow_h #include "winMS.h" #include "config.h" #include "global.h" #define MENU_TYPE_TEXT 1 #define MENU_TYPE_MENU 2 HWND mswin_init_menu_window ( int type ); int mswin_menu_window_select_menu (HWND hwnd, int how, MENU_ITEM_P **); void mswin_menu_window_size (HWND hwnd, LPSIZE sz); #endif /* MSWINTextWindow_h */ nethack-3.4.3/sys/wince/mhmsg.h0100644000000000000000000000255307764735041015066 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MHNethackMessages_H #define MHNethackMessages_H /* nethack messages */ #define WM_MSNH_COMMAND (WM_APP+1) #define MSNH_MSG_ADDWND 100 #define MSNH_MSG_PUTSTR 101 #define MSNH_MSG_PRINT_GLYPH 102 #define MSNH_MSG_CLEAR_WINDOW 103 #define MSNH_MSG_CLIPAROUND 104 #define MSNH_MSG_STARTMENU 105 #define MSNH_MSG_ADDMENU 106 #define MSNH_MSG_CURSOR 107 #define MSNH_MSG_ENDMENU 108 typedef struct mswin_nhmsg_add_wnd { winid wid; } MSNHMsgAddWnd, *PMSNHMsgAddWnd; typedef struct mswin_nhmsg_putstr { int attr; const char* text; boolean append; } MSNHMsgPutstr, *PMSNHMsgPutstr; typedef struct mswin_nhmsg_print_glyph { XCHAR_P x; XCHAR_P y; int glyph; } MSNHMsgPrintGlyph, *PMSNHMsgPrintGlyph; typedef struct mswin_nhmsg_cliparound { int x; int y; } MSNHMsgClipAround, *PMSNHMsgClipAround; typedef struct mswin_nhmsg_add_menu { int glyph; const ANY_P* identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; const char * str; BOOLEAN_P presel; } MSNHMsgAddMenu, *PMSNHMsgAddMenu; typedef struct mswin_nhmsg_cursor { int x; int y; } MSNHMsgCursor, *PMSNHMsgCursor; typedef struct mswin_nhmsg_end_menu { const char* text; } MSNHMsgEndMenu, *PMSNHMsgEndMenu; #endif nethack-3.4.3/sys/wince/mhmsgwnd.c0100644000000000000000000003632107764735041015572 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhmsgwnd.h" #include "mhmsg.h" #include "mhcmd.h" #include "mhfont.h" #include "mhcolor.h" #define MSG_WRAP_TEXT #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2) #define MAX_MSG_LINES 32 #define MSG_LINES (int)min(iflags.msg_history, MAX_MSG_LINES) #define MAXWINDOWTEXT 200 struct window_line { int attr; char text[MAXWINDOWTEXT]; }; typedef struct mswin_nethack_message_window { size_t max_text; struct window_line window_text[MAX_MSG_LINES]; int xChar; /* horizontal scrolling unit */ int yChar; /* vertical scrolling unit */ int xUpper; /* average width of uppercase letters */ int xPos; /* current horizontal scrolling position */ int yPos; /* current vertical scrolling position */ int xMax; /* maximum horizontal scrolling position */ int yMax; /* maximum vertical scrolling position */ int xPage; /* page size of horizontal scroll bar */ int lines_last_turn; /* lines added during the last turn */ int dont_care; /* flag the the user does not care if messages are lost */ } NHMessageWindow, *PNHMessageWindow; static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass"); LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM); static void register_message_window_class(); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); #ifndef MSG_WRAP_TEXT static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); #endif static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); #ifdef USER_SOUNDS extern void play_sound_for_message(const char* str); #endif HWND mswin_init_message_window () { static int run_once = 0; HWND ret; DWORD style; if( !run_once ) { register_message_window_class( ); run_once = 1; } #ifdef MSG_WRAP_TEXT style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL; #else style = WS_BORDER | WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL; #endif ret = CreateWindow( szMessageWindowClass, /* registered class name */ NULL, /* window name */ style, /* window style */ 0, /* horizontal position of window */ 0, /* vertical position of window */ 0, /* window width */ 0, /* window height - set it later */ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL ); /* window-creation data */ if( !ret ) panic("Cannot create message window"); return ret; } void register_message_window_class() { WNDCLASS wcex; ZeroMemory( &wcex, sizeof(wcex)); wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC)NHMessageWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = mswin_get_brush(NHW_MESSAGE, MSWIN_COLOR_BG); wcex.lpszMenuName = NULL; wcex.lpszClassName = szMessageWindowClass; RegisterClass(&wcex); } LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: onCreate( hWnd, wParam, lParam ); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SETFOCUS: SetFocus(GetNHApp()->hMainWnd); break; #ifndef MSG_WRAP_TEXT case WM_HSCROLL: onMSNH_HScroll(hWnd, wParam, lParam); break; #endif case WM_VSCROLL: onMSNH_VScroll(hWnd, wParam, lParam); break; case WM_DESTROY: { PNHMessageWindow data; data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); } break; case WM_SIZE: { SCROLLINFO si; int xNewSize; int yNewSize; PNHMessageWindow data; data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); xNewSize = LOWORD(lParam); yNewSize = HIWORD(lParam); if( xNewSize>0 || yNewSize>0 ) { #ifndef MSG_WRAP_TEXT data->xPage = xNewSize/data->xChar; data->xMax = max(0, (int)(1 + data->max_text - data->xPage)); data->xPos = min(data->xPos, data->xMax); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = data->max_text; si.nPage = data->xPage; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); #endif data->yMax = MSG_LINES-1; data->yPos = min(data->yPos, data->yMax); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = MSG_VISIBLE_LINES; si.nMax = data->yMax + MSG_VISIBLE_LINES - 1; si.nPage = MSG_VISIBLE_LINES; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( wParam ) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam; SCROLLINFO si; char* p; if( msg_data->append ) { strncat(data->window_text[MSG_LINES-1].text, msg_data->text, MAXWINDOWTEXT - strlen(data->window_text[MSG_LINES-1].text)); } else { /* check if the string is empty */ for(p = data->window_text[MSG_LINES-1].text; *p && isspace(*p); p++); if( *p ) { /* last string is not empty - scroll up */ memmove(&data->window_text[0], &data->window_text[1], (MSG_LINES-1)*sizeof(data->window_text[0])); } /* append new text to the end of the array */ data->window_text[MSG_LINES-1].attr = msg_data->attr; strncpy(data->window_text[MSG_LINES-1].text, msg_data->text, MAXWINDOWTEXT); } /* reset V-scroll position to display new text */ data->yPos = data->yMax; ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); /* deal with overflows */ data->lines_last_turn++; if( !data->dont_care && data->lines_last_turn>=MSG_LINES-2 ) { char c; BOOL done; /* append "--More--" to the message window text (cannot call putstr here - infinite recursion) */ memmove(&data->window_text[0], &data->window_text[1], (MSG_LINES-1)*sizeof(data->window_text[0])); data->window_text[MSG_LINES-1].attr = ATR_NONE; strncpy(data->window_text[MSG_LINES-1].text, "--More--", MAXWINDOWTEXT); /* update window content */ InvalidateRect(hWnd, NULL, TRUE); #if defined(WIN_CE_SMARTPHONE) NHSPhoneSetKeypadFromString( "\033- <>" ); #endif done = FALSE; while( !done ) { int x, y, mod; c = mswin_nh_poskey(&x, &y, &mod); switch (c) { /* ESC indicates that we can safely discard any further messages during this turn */ case '\033': data->dont_care = 1; done = TRUE; break; case '<': SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); break; case '>': SendMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL); break; /* continue scrolling on any key */ default: data->lines_last_turn = 0; done = TRUE; break; } } #if defined(WIN_CE_SMARTPHONE) NHSPhoneSetKeypadDefault(); #endif /* remove "--More--" from the message window text */ data->window_text[MSG_LINES-1].attr = ATR_NONE; strncpy(data->window_text[MSG_LINES-1].text, " ", MAXWINDOWTEXT); } /* update window content */ InvalidateRect(hWnd, NULL, TRUE); #ifdef USER_SOUNDS play_sound_for_message(msg_data->text); #endif } break; case MSNH_MSG_CLEAR_WINDOW: data->lines_last_turn = 0; data->dont_care = 0; break; } } void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SCROLLINFO si; int yInc; /* get window data */ data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_POS; GetScrollInfo(hWnd, SB_VERT, &si); switch(LOWORD (wParam)) { // User clicked the shaft above the scroll box. case SB_PAGEUP: yInc = -(int)si.nPage; break; // User clicked the shaft below the scroll box. case SB_PAGEDOWN: yInc = si.nPage; break; // User clicked the top arrow. case SB_LINEUP: yInc = -1; break; // User clicked the bottom arrow. case SB_LINEDOWN: yInc = 1; break; // User dragged the scroll box. case SB_THUMBTRACK: yInc = HIWORD(wParam) - data->yPos; break; default: yInc = 0; } // If applying the vertical scrolling increment does not // take the scrolling position out of the scrolling range, // increment the scrolling position, adjust the position // of the scroll box, and update the window. UpdateWindow // sends the WM_PAINT message. if (yInc = max( MSG_VISIBLE_LINES - data->yPos, min(yInc, data->yMax - data->yPos))) { data->yPos += yInc; /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); */ InvalidateRect(hWnd, NULL, TRUE); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); UpdateWindow (hWnd); } } #ifndef MSG_WRAP_TEXT void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SCROLLINFO si; int xInc; /* get window data */ data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE; GetScrollInfo(hWnd, SB_HORZ, &si); switch(LOWORD (wParam)) { // User clicked shaft left of the scroll box. case SB_PAGEUP: xInc = - (int)si.nPage; break; // User clicked shaft right of the scroll box. case SB_PAGEDOWN: xInc = si.nPage; break; // User clicked the left arrow. case SB_LINEUP: xInc = -1; break; // User clicked the right arrow. case SB_LINEDOWN: xInc = 1; break; // User dragged the scroll box. case SB_THUMBTRACK: xInc = HIWORD(wParam) - data->xPos; break; default: xInc = 0; } // If applying the horizontal scrolling increment does not // take the scrolling position out of the scrolling range, // increment the scrolling position, adjust the position // of the scroll box, and update the window. if (xInc = max (-data->xPos, min (xInc, data->xMax - data->xPos))) { data->xPos += xInc; ScrollWindowEx (hWnd, -data->xChar * xInc, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); UpdateWindow (hWnd); } } #endif // MSG_WRAP_TEXT void onPaint(HWND hWnd) { PAINTSTRUCT ps; HDC hdc; PNHMessageWindow data; RECT client_rt, draw_rt; int FirstLine, LastLine; int i, x, y; HGDIOBJ oldFont; TCHAR wbuf[MAXWINDOWTEXT+2]; size_t wlen; COLORREF OldBg, OldFg; hdc = BeginPaint(hWnd, &ps); OldBg = SetBkColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_BG)); OldFg = SetTextColor(hdc, mswin_get_color(NHW_MESSAGE, MSWIN_COLOR_FG)); data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); GetClientRect(hWnd, &client_rt); if( !IsRectEmpty(&ps.rcPaint) ) { FirstLine = max (0, data->yPos - (client_rt.bottom - ps.rcPaint.top)/data->yChar + 1); LastLine = min (MSG_LINES-1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom)/data->yChar); y = min( ps.rcPaint.bottom, client_rt.bottom - 2); for (i=LastLine; i>=FirstLine; i--) { if( i==MSG_LINES-1 ) { x = data->xChar * (2 - data->xPos); } else { x = data->xChar * (4 - data->xPos); } if( strlen(data->window_text[i].text)>0 ) { /* convert to UNICODE */ NH_A2W(data->window_text[i].text, wbuf, sizeof(wbuf)); wlen = _tcslen(wbuf); /* calculate text height */ draw_rt.left = x; draw_rt.right = client_rt.right; draw_rt.top = y - data->yChar; draw_rt.bottom = y; oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[i].attr, hdc, FALSE)); #ifdef MSG_WRAP_TEXT DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); draw_rt.top = y - (draw_rt.bottom - draw_rt.top); draw_rt.bottom = y; DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK); #else DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX ); #endif SelectObject(hdc, oldFont); y -= draw_rt.bottom - draw_rt.top; } else { y -= data->yChar; } /* highligh the last line */ if( i==MSG_LINES-1 ) { draw_rt.left = client_rt.left; draw_rt.right = draw_rt.left + 2*data->xChar; DrawText(hdc, TEXT("> "), 2, &draw_rt, DT_NOPREFIX ); y -= 2; draw_rt.left = client_rt.left; draw_rt.right = client_rt.right; draw_rt.top -= 2; draw_rt.bottom = client_rt.bottom; DrawEdge(hdc, &draw_rt, EDGE_SUNKEN, BF_TOP ); DrawEdge(hdc, &draw_rt, EDGE_SUNKEN, BF_BOTTOM ); } } } SetTextColor (hdc, OldFg); SetBkColor (hdc, OldBg); EndPaint(hWnd, &ps); } void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { HDC hdc; TEXTMETRIC tm; PNHMessageWindow data; HGDIOBJ saveFont; /* set window data */ data = (PNHMessageWindow)malloc(sizeof(NHMessageWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHMessageWindow)); data->max_text = MAXWINDOWTEXT; SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); /* Get the handle to the client area's device context. */ hdc = GetDC(hWnd); saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE)); /* Extract font dimensions from the text metrics. */ GetTextMetrics (hdc, &tm); data->xChar = tm.tmAveCharWidth; data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar/2; data->yChar = tm.tmHeight + tm.tmExternalLeading; data->xPage = 1; /* Free the device context. */ SelectObject(hdc, saveFont); ReleaseDC (hWnd, hdc); } void mswin_message_window_size (HWND hWnd, LPSIZE sz) { PNHMessageWindow data; RECT rt, client_rt; GetWindowRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); if(data) { /* set size to accomodate MSG_VISIBLE_LINES, highligh rectangle and horizontal scroll bar (difference between window rect and client rect */ GetClientRect(hWnd, &client_rt); sz->cy = sz->cy-(client_rt.bottom - client_rt.top) + data->yChar * MSG_VISIBLE_LINES + 4; } } nethack-3.4.3/sys/wince/mhmsgwnd.h0100644000000000000000000000057107764735041015575 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMessageWindow_h #define MSWINMessageWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_message_window (); void mswin_message_window_size (HWND hWnd, LPSIZE sz); #endif /* MSWINMessageWindow_h */ nethack-3.4.3/sys/wince/mhrip.c0100644000000000000000000000052607764735041015063 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhrip.h" #include "mhtext.h" HWND mswin_init_RIP_window () { return mswin_init_text_window(); } void mswin_display_RIP_window (HWND hWnd) { mswin_display_text_window(hWnd); } nethack-3.4.3/sys/wince/mhrip.h0100644000000000000000000000053507764735041015070 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINRIPWindow_h #define MSWINRIPWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_RIP_window (); void mswin_display_RIP_window (HWND hwnd); #endif /* MSWINRIPWindow_h */ nethack-3.4.3/sys/wince/mhstatus.c0100644000000000000000000001602107764735041015611 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhstatus.h" #include "mhmsg.h" #include "mhfont.h" #include "mhcolor.h" #define MAXWINDOWTEXT 255 #define NHSTAT_LINES_2 2 #define NHSTAT_LINES_4 4 typedef struct mswin_nethack_status_window { int nhstat_format; char window_text[MAXWINDOWTEXT]; } NHStatusWindow, *PNHStatusWindow; static TCHAR szStatusWindowClass[] = TEXT("MSNHStatusWndClass"); LRESULT CALLBACK StatusWndProc(HWND, UINT, WPARAM, LPARAM); static void register_status_window_class(void); static void FormatStatusString(char* text, int format); HWND mswin_init_status_window () { static int run_once = 0; HWND ret; NHStatusWindow* data; if( !run_once ) { register_status_window_class( ); run_once = 1; } ret = CreateWindow( szStatusWindowClass, NULL, WS_CHILD | WS_DISABLED | WS_CLIPSIBLINGS, 0, /* x position */ 0, /* y position */ 0, /* x-size - we will set it later */ 0, /* y-size - we will set it later */ GetNHApp()->hMainWnd, NULL, GetNHApp()->hApp, NULL ); if( !ret ) panic("Cannot create status window"); EnableWindow(ret, FALSE); data = (PNHStatusWindow)malloc(sizeof(NHStatusWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHStatusWindow)); data->nhstat_format = NHSTAT_LINES_4; SetWindowLong(ret, GWL_USERDATA, (LONG)data); return ret; } void register_status_window_class() { WNDCLASS wcex; ZeroMemory( &wcex, sizeof(wcex)); wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC)StatusWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = mswin_get_brush(NHW_STATUS, MSWIN_COLOR_BG); wcex.lpszMenuName = NULL; wcex.lpszClassName = szStatusWindowClass; RegisterClass(&wcex); } LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rt; PAINTSTRUCT ps; HDC hdc; PNHStatusWindow data; data = (PNHStatusWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_MSNH_COMMAND: { switch( wParam ) { case MSNH_MSG_PUTSTR: case MSNH_MSG_CLEAR_WINDOW: ZeroMemory(data->window_text, sizeof(data->window_text)); FormatStatusString(data->window_text, data->nhstat_format); break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor)lParam; if( msg_data->y==0 ) { InvalidateRect(hWnd, NULL, TRUE); } } break; } } break; case WM_PAINT: { HGDIOBJ oldFont; TCHAR wbuf[MAXWINDOWTEXT]; COLORREF OldBg, OldFg; hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); oldFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); OldBg = SetBkColor(hdc, mswin_get_color(NHW_STATUS, MSWIN_COLOR_BG)); OldFg = SetTextColor(hdc, mswin_get_color(NHW_STATUS, MSWIN_COLOR_FG)); DrawText(hdc, NH_A2W(data->window_text, wbuf, MAXWINDOWTEXT), strlen(data->window_text), &rt, DT_LEFT | DT_NOPREFIX); SetTextColor (hdc, OldFg); SetBkColor (hdc, OldBg); SelectObject(hdc, oldFont); EndPaint(hWnd, &ps); } break; case WM_DESTROY: free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); break; case WM_SETFOCUS: SetFocus(GetNHApp()->hMainWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void mswin_status_window_size (HWND hWnd, LPSIZE sz) { TEXTMETRIC tm; HGDIOBJ saveFont; HDC hdc; PNHStatusWindow data; RECT rt; GetWindowRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; data = (PNHStatusWindow)GetWindowLong(hWnd, GWL_USERDATA); if(data) { hdc = GetDC(hWnd); saveFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); GetTextMetrics(hdc, &tm); /* see if the status window can fit 80 characters per line */ if( (80*tm.tmMaxCharWidth)>=sz->cx ) data->nhstat_format = NHSTAT_LINES_4; else data->nhstat_format = NHSTAT_LINES_2; /* set height of the status box */ sz->cy = tm.tmHeight * data->nhstat_format; SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); } } extern const char *hu_stat[]; /* defined in eat.c */ extern const char *enc_stat[]; /* define in botl.c */ void FormatStatusString(char* text, int format) { register char *nb; int hp, hpmax; int cap = near_capacity(); Strcpy(text, plname); if('a' <= text[0] && text[0] <= 'z') text[0] += 'A'-'a'; text[10] = 0; Sprintf(nb = eos(text)," the "); if (Upolyd) { char mbot[BUFSZ]; int k = 0; Strcpy(mbot, mons[u.umonnum].mname); while(mbot[k] != 0) { if ((k == 0 || (k > 0 && mbot[k-1] == ' ')) && 'a' <= mbot[k] && mbot[k] <= 'z') mbot[k] += 'A' - 'a'; k++; } Sprintf(nb = eos(nb), mbot); } else Sprintf(nb = eos(nb), rank_of(u.ulevel, Role_switch, flags.female)); if( format==NHSTAT_LINES_4 ) Sprintf(nb = eos(nb),"\r\n"); if (ACURR(A_STR) > 18) { if (ACURR(A_STR) > STR18(100)) Sprintf(nb = eos(nb),"St:%2d ",ACURR(A_STR)-100); else if (ACURR(A_STR) < STR18(100)) Sprintf(nb = eos(nb), "St:18/%02d ",ACURR(A_STR)-18); else Sprintf(nb = eos(nb),"St:18/** "); } else Sprintf(nb = eos(nb), "St:%-1d ",ACURR(A_STR)); Sprintf(nb = eos(nb), "Dx:%-1d Co:%-1d In:%-1d Wi:%-1d Ch:%-1d", ACURR(A_DEX), ACURR(A_CON), ACURR(A_INT), ACURR(A_WIS), ACURR(A_CHA)); Sprintf(nb = eos(nb), (u.ualign.type == A_CHAOTIC) ? " Chaotic" : (u.ualign.type == A_NEUTRAL) ? " Neutral" : " Lawful"); #ifdef SCORE_ON_BOTL if (flags.showscore) Sprintf(nb = eos(nb), " S:%ld", botl_score()); #endif if( format==NHSTAT_LINES_4 || format==NHSTAT_LINES_2 ) strcat(text, "\r\n"); /* third line */ hp = Upolyd ? u.mh : u.uhp; hpmax = Upolyd ? u.mhmax : u.uhpmax; if(hp < 0) hp = 0; (void) describe_level(nb=eos(nb)); Sprintf(nb = eos(nb), "%c:%-2ld HP:%d(%d) Pw:%d(%d) AC:%-2d", oc_syms[COIN_CLASS], #ifndef GOLDOBJ u.ugold, #else money_cnt(invent), #endif hp, hpmax, u.uen, u.uenmax, u.uac); if (Upolyd) Sprintf(nb = eos(nb), " HD:%d", mons[u.umonnum].mlevel); #ifdef EXP_ON_BOTL else if(flags.showexp) Sprintf(nb = eos(nb), " Xp:%u/%-1ld", u.ulevel,u.uexp); #endif else Sprintf(nb = eos(nb), " Exp:%u", u.ulevel); if( format==NHSTAT_LINES_4 ) strcat(text, "\r\n"); else strcat(text, " "); /* forth line */ if(flags.time) Sprintf(nb = eos(nb), "T:%ld ", moves); if(strcmp(hu_stat[u.uhs], " ")) { Strcat(text, hu_stat[u.uhs]); Sprintf(nb = eos(nb), " "); } if(Confusion) Sprintf(nb = eos(nb), "Conf"); if(Sick) { if (u.usick_type & SICK_VOMITABLE) Sprintf(nb = eos(nb), " FoodPois"); if (u.usick_type & SICK_NONVOMITABLE) Sprintf(nb = eos(nb), " Ill"); } if(Blind) Sprintf(nb = eos(nb), " Blind"); if(Stunned) Sprintf(nb = eos(nb), " Stun"); if(Hallucination) Sprintf(nb = eos(nb), " Hallu"); if(Slimed) Sprintf(nb = eos(nb), " Slime"); if(cap > UNENCUMBERED) Sprintf(nb = eos(nb), " %s", enc_stat[cap]); } nethack-3.4.3/sys/wince/mhstatus.h0100644000000000000000000000056307764735041015622 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINStatusWindow_h #define MSWINStatusWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_status_window (); void mswin_status_window_size (HWND hWnd, LPSIZE sz); #endif /* MSWINStatusWindow_h */ nethack-3.4.3/sys/wince/mhtext.c0100644000000000000000000001361007764735041015253 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhtext.h" #include "mhmsg.h" #include "mhfont.h" #include "mhcolor.h" #include "mhtxtbuf.h" typedef struct mswin_nethack_text_window { PNHTextBuffer window_text; int done; } NHTextWindow, *PNHTextWindow; static WNDPROC editControlWndProc = NULL; LRESULT CALLBACK TextWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHTextControlWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutText(HWND hwnd); HWND mswin_init_text_window () { HWND ret; PNHTextWindow data; ret = CreateDialog( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_NHTEXT), GetNHApp()->hMainWnd, TextWndProc ); if( !ret ) panic("Cannot create text window"); data = (PNHTextWindow)malloc(sizeof(NHTextWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHTextWindow)); data->window_text = mswin_init_text_buffer( program_state.gameover? FALSE : GetNHApp()->bWrapText ); SetWindowLong(ret, GWL_USERDATA, (LONG)data); return ret; } void mswin_display_text_window (HWND hWnd) { PNHTextWindow data; data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA); if( data ) { HWND control; control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); SendMessage(control, EM_FMTLINES, 1, 0 ); mswin_render_text(data->window_text, GetDlgItem(hWnd, IDC_TEXT_CONTROL)); data->done = 0; mswin_popup_display(hWnd, &data->done); mswin_popup_destroy(hWnd); } } LRESULT CALLBACK TextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HWND control; HDC hdc; PNHTextWindow data; data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_INITDIALOG: /* set text control font */ control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); if( !control ) { panic("cannot get text view window"); } hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0); ReleaseDC(control, hdc); #if defined(WIN_CE_SMARTPHONE) /* special initialization for SmartPhone dialogs */ NHSPhoneDialogSetup(hWnd, FALSE, GetNHApp()->bFullScreen); #endif /* subclass edit control */ editControlWndProc = (WNDPROC)GetWindowLong(control, GWL_WNDPROC); SetWindowLong(control, GWL_WNDPROC, (LONG)NHTextControlWndProc); if( !program_state.gameover && GetNHApp()->bWrapText ) { DWORD styles; styles = GetWindowLong(control, GWL_STYLE); if( styles ) { SetWindowLong(control, GWL_STYLE, styles & (~WS_HSCROLL)); SetWindowPos(control, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE ); } } SetFocus(control); return FALSE; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_SIZE: LayoutText(hWnd); return FALSE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: data->done = 1; return TRUE; } break; case WM_CTLCOLORBTN: case WM_CTLCOLOREDIT: case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */ HDC hdcEdit = (HDC) wParam; HWND hwndEdit = (HWND) lParam; if( hwndEdit == GetDlgItem(hWnd, IDC_TEXT_CONTROL) ) { SetBkColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_BG)); SetTextColor(hdcEdit, mswin_get_color(NHW_TEXT, MSWIN_COLOR_FG)); return (BOOL)mswin_get_brush(NHW_TEXT, MSWIN_COLOR_BG); } } return FALSE; case WM_DESTROY: if( data ) { mswin_free_text_buffer(data->window_text); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); } break; } return FALSE; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHTextWindow data; data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( wParam ) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam; mswin_add_text(data->window_text, msg_data->attr, msg_data->text); break; } } } void LayoutText(HWND hWnd) { HWND btn_ok; HWND text; RECT clrt, rt; POINT pt_elem, pt_ok; SIZE sz_elem, sz_ok; text = GetDlgItem(hWnd, IDC_TEXT_CONTROL); btn_ok = GetDlgItem(hWnd, IDOK); /* get window coordinates */ GetClientRect(hWnd, &clrt ); /* set window placements */ if( IsWindow(btn_ok) ) { GetWindowRect(btn_ok, &rt); sz_ok.cx = clrt.right - clrt.left; sz_ok.cy = rt.bottom-rt.top; pt_ok.x = clrt.left; pt_ok.y = clrt.bottom - sz_ok.cy; MoveWindow(btn_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE ); pt_elem.x = clrt.left; pt_elem.y = clrt.top; sz_elem.cx = clrt.right - clrt.left; sz_elem.cy = pt_ok.y; MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE ); } else { pt_elem.x = clrt.left; pt_elem.y = clrt.top; sz_elem.cx = clrt.right - clrt.left; sz_elem.cy = clrt.bottom - clrt.top; MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE ); } } /* Text control window proc - implements close on space and scrolling on arrows */ LRESULT CALLBACK NHTextControlWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_KEYUP: switch( wParam ) { case VK_SPACE: case VK_RETURN: /* close on space */ PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0); return 0; case VK_UP: /* scoll up */ PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); return 0; case VK_DOWN: /* scoll down */ PostMessage(hWnd, WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL); return 0; case VK_LEFT: /* scoll left */ PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINELEFT, 0), (LPARAM)NULL); return 0; case VK_RIGHT: /* scoll right */ PostMessage(hWnd, WM_HSCROLL, MAKEWPARAM(SB_LINERIGHT, 0), (LPARAM)NULL); return 0; } break; /* case WM_KEYUP: */ } if( editControlWndProc ) return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam); else return 0; } nethack-3.4.3/sys/wince/mhtext.h0100644000000000000000000000054107764735041015257 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINTextWindow_h #define MSWINTextWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_text_window (); void mswin_display_text_window (HWND hwnd); #endif /* MSWINTextWindow_h */ nethack-3.4.3/sys/wince/mhtxtbuf.c0100644000000000000000000001674207764735041015614 0ustar rootroot/* Copyright (C) 2003 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "mhtxtbuf.h" /* Collect Nethack text messages and render text into edit box. Wrap text if necessary. Recognize formatted lines as having more that 4 consecutive. spaces inside the string. Strip leading and trailing spaces. Always break at the original line end (do not merge text that comes from NetHack engine) */ /*----------------------------------------------------------------*/ #define NHTEXT_BUFFER_INCREMENT 10 /*----------------------------------------------------------------*/ struct text_buffer_line { int attr; short beg_padding; short end_padding; BOOL formatted; char* text; }; /*----------------------------------------------------------------*/ typedef struct mswin_nethack_text_buffer { BOOL b_wrap_text; int n_size; int n_used; struct text_buffer_line *text_buffer_line; } NHTextBuffer, *PNHTextBuffer; /*----------------------------------------------------------------*/ #define NHTextLine(pb,i) ((pb)->text_buffer_line[(i)]) static TCHAR* nh_append( TCHAR* s, int* size, const char* ap ); /*----------------------------------------------------------------*/ PNHTextBuffer mswin_init_text_buffer(BOOL wrap_text) { PNHTextBuffer pb = (PNHTextBuffer)malloc(sizeof(NHTextBuffer)); if( !pb ) panic("Out of memory"); ZeroMemory(pb, sizeof(NHTextBuffer)); pb->b_wrap_text = wrap_text; pb->n_size = 0; pb->n_used = 0; pb->text_buffer_line = NULL; return pb; } /*----------------------------------------------------------------*/ void mswin_free_text_buffer(PNHTextBuffer pb) { int i; if( !pb ) return; for(i=0; in_used; i++ ) { free(pb->text_buffer_line[i].text); } free( pb->text_buffer_line ); free( pb ); } /*----------------------------------------------------------------*/ void mswin_add_text(PNHTextBuffer pb, int attr, const char* text) { char* p; struct text_buffer_line* new_line; /* grow buffer */ if( pb->n_used >= pb->n_size ) { pb->n_size += NHTEXT_BUFFER_INCREMENT; pb->text_buffer_line = (struct text_buffer_line*)realloc( pb->text_buffer_line, pb->n_size*sizeof(struct text_buffer_line) ); if( !pb->text_buffer_line ) panic("Memory allocation error"); } /* analyze the new line of text */ new_line = &NHTextLine(pb, pb->n_used); new_line->attr = attr; new_line->beg_padding = 0; new_line->text = strdup(text); for( p = new_line->text; *p && isspace(*p); p++ ) { new_line->beg_padding++; } if( *p ) { memmove(new_line->text, new_line->text + new_line->beg_padding, strlen(new_line->text) - new_line->beg_padding + 1 ); for( p = new_line->text+strlen(new_line->text); p>=new_line->text && isspace(*p); p-- ) { new_line->end_padding++; *p = 0; } /* if there are 3 (or more) consecutive spaces inside the string consider it formatted */ new_line->formatted = (strstr(new_line->text, " ")!=NULL); } else { new_line->end_padding = 0; new_line->text[0] = 0; new_line->formatted = FALSE; } pb->n_used++; } /*----------------------------------------------------------------*/ static TCHAR* nh_append( TCHAR* s, int* size, const char* ap ) { int tlen, tnewlen; if( !(ap && *ap) ) return s; /* append the calculated line to the text buffer */ tlen = s? _tcslen(s) : 0; tnewlen = tlen+strlen(ap); if( tnewlen>=*size ) { *size = max(tnewlen, *size + BUFSZ); s = (TCHAR*)realloc(s, *size * sizeof(TCHAR)); if( !s ) panic("Out of memory"); ZeroMemory(s+tlen, (*size-tlen)*sizeof(TCHAR)); } if( strcmp(ap, "\r\n")==0 ) { _tcscat(s, TEXT("\r\n")); } else { NH_A2W(ap, s+tlen, strlen(ap)); s[tnewlen] = 0; } return s; } /*----------------------------------------------------------------*/ void mswin_render_text(PNHTextBuffer pb, HWND edit_control) { RECT rt_client; /* boundaries of the client area of the edit control */ SIZE size_text; /* size of the edit control */ RECT rt_text; /* calculated text rectangle for the visible line */ char buf[BUFSZ]; /* buffer for the visible line */ TCHAR tbuf[BUFSZ]; /* temp buffer for DrawText */ TCHAR* pText = NULL; /* resulting text (formatted) */ int pTextSize = 0; /* resulting text size */ char* p_cur = NULL; /* current position in the NHTextBuffer->text_buffer_line->text */ char* p_buf_cur = NULL; /* current position in the visible line buffer */ int i; HDC hdcEdit; /* device context for the edit control */ HFONT hFont, hOldFont; /* edit control font */ GetClientRect(edit_control, &rt_client ); size_text.cx = rt_client.right - rt_client.left; size_text.cy = rt_client.bottom - rt_client.top; size_text.cx -= GetSystemMetrics(SM_CXVSCROLL); /* add a slight right margin - the text looks better that way */ hdcEdit = GetDC(edit_control); hFont = (HFONT)SendMessage(edit_control, WM_GETFONT, 0, 0); if( hFont ) hOldFont = SelectObject(hdcEdit, hFont); /* loop through each line (outer loop) and wrap it around (inner loop) */ ZeroMemory(buf, sizeof(buf)); p_buf_cur = buf; for( i=0; in_used; i++ ) { if( pb->b_wrap_text ) { p_cur = NHTextLine(pb,i).text; /* insert an line break for the empty string */ if( !NHTextLine(pb,i).text[0] ) { pText = nh_append(pText, &pTextSize, "\r\n"); continue; } /* add margin to the "formatted" line of text */ if( NHTextLine(pb,i).formatted ) { strcpy(buf, " "); p_buf_cur += 3; } /* scroll thourgh the current line of text and wrap it so it fits to width of the edit control */ while( *p_cur ) { char *p_word_pos = p_buf_cur; /* copy one word into the buffer */ while( *p_cur && isspace(*p_cur) ) if( p_buf_cur!=buf ) *p_buf_cur++ = *p_cur++; else p_cur++; while( *p_cur && !isspace(*p_cur) ) *p_buf_cur++ = *p_cur++; /* check if it fits */ SetRect( &rt_text, 0, 0, size_text.cx, size_text.cy ); DrawText(hdcEdit, NH_A2W(buf, tbuf, p_buf_cur-buf), p_buf_cur-buf, &rt_text, DT_CALCRECT | DT_LEFT | DT_SINGLELINE | DT_NOCLIP); if( (rt_text.right - rt_text.left)>=size_text.cx ) { /* Backtrack. Only backtrack if the last word caused the overflow - do not backtrack if the entire current line does not fit the visible area. Otherwise it is a infinite loop. */ if( p_word_pos>buf ) { p_cur -= (p_buf_cur-p_word_pos); p_buf_cur = p_word_pos; } *p_buf_cur = 0; /* break the line */ /* append the calculated line to the text buffer */ pText = nh_append(pText, &pTextSize, buf); pText = nh_append(pText, &pTextSize, "\r\n"); ZeroMemory(buf, sizeof(buf)); p_buf_cur = buf; } } /* always break the line at the end of the buffer text */ if( p_buf_cur != buf ) { /* flush the current buffrer */ *p_buf_cur = 0; /* break the line */ pText = nh_append(pText, &pTextSize, buf); pText = nh_append(pText, &pTextSize, "\r\n"); ZeroMemory(buf, sizeof(buf)); p_buf_cur = buf; } } else { /* do not wrap text */ int j; for( j=0; j */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINTextBuffer_h #define MSWINTextBuffer_h #include "winMS.h" typedef struct mswin_nethack_text_buffer* PNHTextBuffer; PNHTextBuffer mswin_init_text_buffer(BOOL wrap_text); void mswin_free_text_buffer(PNHTextBuffer pb); void mswin_add_text(PNHTextBuffer pb, int attr, const char* text); void mswin_render_text(PNHTextBuffer pb, HWND edit_control); #endif /* MSWINTextBuffer_h */ nethack-3.4.3/sys/wince/mswproc.c0100644000000000000000000016251307764735041015443 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* * This file implements the interface between the window port specific * code in the mswin port and the rest of the nethack game engine. */ #include "hack.h" #include "dlb.h" #include "winMS.h" #include "mhmap.h" #include "mhstatus.h" #include "mhtext.h" #include "mhmsgwnd.h" #include "mhmenu.h" #include "mhmsg.h" #include "mhcmd.h" #include "mhinput.h" #include "mhaskyn.h" #include "mhdlg.h" #include "mhrip.h" #include "mhmain.h" #include "mhfont.h" #include "mhcolor.h" #define LLEN 128 #ifdef _DEBUG extern void logDebug(const char *fmt, ...); #else void logDebug(const char *fmt, ...) { } #endif static void mswin_main_loop(); static BOOL initMapTiles(void); static void prompt_for_player_selection(void); /* Interface definition, for windows.c */ struct window_procs mswin_procs = { "MSWIN", WC_COLOR|WC_HILITE_PET|WC_ALIGN_MESSAGE|WC_ALIGN_STATUS| WC_INVERSE|WC_SCROLL_MARGIN|WC_MAP_MODE| WC_FONT_MESSAGE|WC_FONT_STATUS|WC_FONT_MENU|WC_FONT_TEXT|WC_FONT_MAP| WC_FONTSIZ_MESSAGE|WC_FONTSIZ_STATUS|WC_FONTSIZ_MENU|WC_FONTSIZ_TEXT| WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE|WC_VARY_MSGCOUNT| WC_WINDOWCOLORS|WC_PLAYER_SELECTION, WC2_FULLSCREEN|WC2_SOFTKEYBOARD|WC2_WRAPTEXT, mswin_init_nhwindows, mswin_player_selection, mswin_askname, mswin_get_nh_event, mswin_exit_nhwindows, mswin_suspend_nhwindows, mswin_resume_nhwindows, mswin_create_nhwindow, mswin_clear_nhwindow, mswin_display_nhwindow, mswin_destroy_nhwindow, mswin_curs, mswin_putstr, mswin_display_file, mswin_start_menu, mswin_add_menu, mswin_end_menu, mswin_select_menu, genl_message_menu, /* no need for X-specific handling */ mswin_update_inventory, mswin_mark_synch, mswin_wait_synch, #ifdef CLIPPING mswin_cliparound, #endif #ifdef POSITIONBAR donull, #endif mswin_print_glyph, mswin_raw_print, mswin_raw_print_bold, mswin_nhgetch, mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function, mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ mswin, mswin_change_background, #endif /* other defs that really should go away (they're tty specific) */ mswin_start_screen, mswin_end_screen, mswin_outrip, mswin_preference_update, }; /* init_nhwindows(int* argcp, char** argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. -- Any commandline arguments relevant to the windowport should be interpreted, and *argcp and *argv should be changed to remove those arguments. -- When the message window is created, the variable iflags.window_inited needs to be set to TRUE. Otherwise all plines() will be done via raw_print(). ** Why not have init_nhwindows() create all of the "standard" ** windows? Or at least all but WIN_INFO? -dean */ void mswin_init_nhwindows(int* argc, char** argv) { HWND hWnd; logDebug("mswin_init_nhwindows()\n"); #ifdef _DEBUG { /* truncate trace file */ FILE *dfp = fopen("nhtrace.log", "w"); fclose(dfp); } #endif /* intialize input subsystem */ mswin_nh_input_init(); /* read registry settings */ mswin_read_reg(); /* set it to WIN_ERR so we can detect attempts to use this ID before it is inialized */ WIN_MAP = WIN_ERR; /* check default values */ if( iflags.wc_fontsiz_statusNHFONT_SIZE_MAX ) iflags.wc_fontsiz_status = NHFONT_STATUS_DEFAULT_SIZE; if( iflags.wc_fontsiz_messageNHFONT_SIZE_MAX ) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; if( iflags.wc_fontsiz_textNHFONT_SIZE_MAX ) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; if( iflags.wc_fontsiz_menuNHFONT_SIZE_MAX ) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; if( iflags.wc_align_message==0 ) iflags.wc_align_message = ALIGN_BOTTOM; if( iflags.wc_align_status==0 ) iflags.wc_align_status = ALIGN_TOP; if( iflags.wc_scroll_margin==0 ) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN; if( iflags.wc_tile_width==0 ) iflags.wc_tile_width = TILE_X; if( iflags.wc_tile_height==0 ) iflags.wc_tile_height = TILE_Y; if( iflags.wc_vary_msgcount==0 ) iflags.wc_vary_msgcount = 3; /* force tabs in menus */ iflags.menu_tab_sep = 1; /* force toptenwin to be true. toptenwin is the option that decides whether to * write output to a window or stdout. stdout doesn't make sense on Windows * non-console applications */ flags.toptenwin = 1; set_option_mod_status("toptenwin", SET_IN_FILE); /* initialize map tiles bitmap */ initMapTiles(); /* set tile-related options to readonly */ set_wc_option_mod_status( WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE, DISP_IN_GAME); /* init color table */ mswin_init_color_table(); /* set font-related options to change in the game */ set_wc_option_mod_status( WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT, SET_IN_GAME ); /* WC2 options */ set_wc2_option_mod_status( WC2_FULLSCREEN| WC2_SOFTKEYBOARD, SET_IN_FILE ); GetNHApp()->bFullScreen = iflags.wc2_fullscreen; GetNHApp()->bUseSIP = iflags.wc2_softkeyboard; set_wc2_option_mod_status( WC2_WRAPTEXT, SET_IN_GAME ); GetNHApp()->bWrapText = iflags.wc2_wraptext; /* create the main nethack window */ hWnd = mswin_init_main_window(); if (!hWnd) panic( "Cannot create the main window." ); ShowWindow(hWnd, GetNHApp()->nCmdShow); UpdateWindow(hWnd); GetNHApp()->hMainWnd = hWnd; /* set Full screen if requested */ mswin_set_fullscreen(GetNHApp()->bFullScreen); /* let nethack code know that the window subsystem is ready */ iflags.window_inited = TRUE; } /* Do a window-port specific player type selection. If player_selection() offers a Quit option, it is its responsibility to clean up and terminate the process. You need to fill in pl_character[0]. */ void mswin_player_selection(void) { logDebug("mswin_player_selection()\n"); #if defined(WIN_CE_SMARTPHONE) /* SmartPhone does not supprt combo-boxes therefor we cannot use dialog for player selection */ prompt_for_player_selection(); #else if (iflags.wc_player_selection == VIA_DIALOG) { int nRole; /* pick player type randomly (use pre-selected role/race/gender/alignment) */ if( flags.randomall ) { if (flags.initrole < 0) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { raw_print("Incompatible role!"); flags.initrole = randrole(); } } if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { raw_print("Incompatible race!"); flags.initrace = randrace(flags.initrole); } } if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { raw_print("Incompatible gender!"); flags.initgend = randgend(flags.initrole, flags.initrace); } } if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { raw_print("Incompatible alignment!"); flags.initalign = randalign(flags.initrole, flags.initrace); } } } else { /* select a role */ if( mswin_player_selection_window( &nRole ) == IDCANCEL ) { bail(0); } } } else { /* iflags.wc_player_selection == VIA_PROMPTS */ prompt_for_player_selection(); } #endif /* defined(WIN_CE_SMARTPHONE) */ } void prompt_for_player_selection(void) { int i, k, n; char pick4u = 'n', thisch, lastch = 0; char pbuf[QBUFSZ], plbuf[QBUFSZ]; winid win; anything any; menu_item *selected = 0; int box_result; TCHAR wbuf[BUFSZ]; logDebug("prompt_for_player_selection()\n"); /* prevent an unnecessary prompt */ rigid_role_checks(); /* Should we randomly pick for the player? */ if (!flags.randomall && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) { /* int echoline; */ char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* tty_putstr(BASE_WINDOW, 0, ""); */ /* echoline = wins[BASE_WINDOW]->cury; */ box_result = MessageBox(NULL, NH_A2W(prompt, wbuf, BUFSZ), TEXT("NetHack for Windows"), #if defined(WIN_CE_SMARTPHONE) MB_YESNO | MB_DEFBUTTON1 #else MB_YESNOCANCEL | MB_DEFBUTTON1 #endif ); pick4u = (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033'; /* tty_putstr(BASE_WINDOW, 0, prompt); */ do { /* pick4u = lowc(readchar()); */ if (index(quitchars, pick4u)) pick4u = 'y'; } while(!index(ynqchars, pick4u)); if ((int)strlen(prompt) + 1 < CO) { /* Echo choice and move back down line */ /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, pick4u); */ /* tty_putstr(BASE_WINDOW, 0, ""); */ } else /* Otherwise it's hard to tell where to echo, and things are * wrapping a bit messily anyway, so (try to) make sure the next * question shows up well and doesn't get wrapped at the * bottom of the window. */ /* tty_clear_nhwindow(BASE_WINDOW) */ ; if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) free((genericptr_t) selected); bail((char *)0); /*NOTREACHED*/ return; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* Select a role, if necessary */ /* we'll try to be compatible with pre-selected race/gender/alignment, * but may not succeed */ if (flags.initrole < 0) { char rolenamebuf[QBUFSZ]; /* Process the choice */ if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */ flags.initrole = randrole(); } } else { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */ /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ thisch = lowc(roles[i].name.m[0]); if (thisch == lastch) thisch = highc(thisch); if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) { if (flags.initgend == 1 && roles[i].name.f) Strcpy(rolenamebuf, roles[i].name.f); else Strcpy(rolenamebuf, roles[i].name.m); } else { if (roles[i].name.f) { Strcpy(rolenamebuf, roles[i].name.m); Strcat(rolenamebuf, "/"); Strcat(rolenamebuf, roles[i].name.f); } else Strcpy(rolenamebuf, roles[i].name.m); } add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED); lastch = thisch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole()+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */ flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */ flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */ flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ /* tty_display_nhwindow(BASE_WINDOW, FALSE); */ } /* Ask the user for a player name. */ void mswin_askname(void) { logDebug("mswin_askname()\n"); if( mswin_getlin_window("who are you?", plname, PL_NSIZ)==IDCANCEL ) { bail("bye-bye"); /* not reached */ } } /* Does window event processing (e.g. exposure events). A noop for the tty and X window-ports. */ void mswin_get_nh_event(void) { logDebug("mswin_get_nh_event()\n"); return; } /* Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. */ void mswin_exit_nhwindows(const char *str) { logDebug("mswin_exit_nhwindows(%s)\n", str); /* Write Window settings to the registry */ mswin_write_reg(); // Don't do any of this (?) - exit_nhwindows does not terminate // the application // DestroyWindow(GetNHApp()->hMainWnd); // terminate(EXIT_SUCCESS); } /* Prepare the window to be suspended. */ void mswin_suspend_nhwindows(const char *str) { logDebug("mswin_suspend_nhwindows(%s)\n", str); return; } /* Restore the windows after being suspended. */ void mswin_resume_nhwindows() { logDebug("mswin_resume_nhwindows()\n"); return; } /* Create a window of type "type" which can be NHW_MESSAGE (top line) NHW_STATUS (bottom lines) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) */ winid mswin_create_nhwindow(int type) { winid i = 0; MSNHMsgAddWnd data; logDebug("mswin_create_nhwindow(%d)\n", type); /* Return the next available winid */ for (i=1; iwindowlist[i].win == NULL && !GetNHApp()->windowlist[i].dead) break; if (i == MAXWINDOWS) panic ("ERROR: No windows available...\n"); switch (type) { case NHW_MAP: { GetNHApp()->windowlist[i].win = mswin_init_map_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_MESSAGE: { GetNHApp()->windowlist[i].win = mswin_init_message_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_STATUS: { GetNHApp()->windowlist[i].win = mswin_init_status_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_MENU: { GetNHApp()->windowlist[i].win = NULL; //will create later GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 1; break; } case NHW_TEXT: { GetNHApp()->windowlist[i].win = mswin_init_text_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } } ZeroMemory(&data, sizeof(data) ); data.wid = i; SendMessage( GetNHApp()->hMainWnd, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDWND, (LPARAM)&data ); return i; } /* Clear the given window, when asked to. */ void mswin_clear_nhwindow(winid wid) { logDebug("mswin_clear_nhwindow(%d)\n", wid); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { #ifdef REINCARNATION if( GetNHApp()->windowlist[wid].type == NHW_MAP ) { if( Is_rogue_level(&u.uz) ) mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), ROGUE_LEVEL_MAP_MODE); else mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode); } #endif SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLEAR_WINDOW, (LPARAM)NULL ); } } /* -- Display the window on the screen. If there is data pending for output in that window, it should be sent. If blocking is TRUE, display_nhwindow() will not return until the data has been displayed on the screen, and acknowledged by the user where appropriate. -- All calls are blocking in the tty window-port. -- Calling display_nhwindow(WIN_MESSAGE,???) will do a --more--, if necessary, in the tty window-port. */ void mswin_display_nhwindow(winid wid, BOOLEAN_P block) { logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block); if (GetNHApp()->windowlist[wid].win != NULL) { if (GetNHApp()->windowlist[wid].type == NHW_MENU) { MENU_ITEM_P* p; mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, PICK_NONE, &p); } if (GetNHApp()->windowlist[wid].type == NHW_TEXT) { mswin_display_text_window(GetNHApp()->windowlist[wid].win); } if (GetNHApp()->windowlist[wid].type == NHW_RIP) { mswin_display_RIP_window(GetNHApp()->windowlist[wid].win); } else { if( !block ) { UpdateWindow(GetNHApp()->windowlist[wid].win); } else { if ( GetNHApp()->windowlist[wid].type == NHW_MAP ) { (void) mswin_nhgetch(); } } } SetFocus(GetNHApp()->hMainWnd); } } HWND mswin_hwnd_from_winid(winid wid) { if( wid>=0 && widwindowlist[wid].win; } else { return NULL; } } winid mswin_winid_from_handle(HWND hWnd) { winid i = 0; for (i=1; iwindowlist[i].win == hWnd) return i; return -1; } winid mswin_winid_from_type(int type) { winid i = 0; for (i=1; iwindowlist[i].type == type) return i; return -1; } void mswin_window_mark_dead(winid wid) { if( wid>=0 && widwindowlist[wid].win = NULL; GetNHApp()->windowlist[wid].dead = 1; } } /* Destroy will dismiss the window if the window has not * already been dismissed. */ void mswin_destroy_nhwindow(winid wid) { logDebug("mswin_destroy_nhwindow(%d)\n", wid); if ((GetNHApp()->windowlist[wid].type == NHW_MAP) || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE) || (GetNHApp()->windowlist[wid].type == NHW_STATUS)) { /* main windows is going to take care of those */ return; } if (wid != -1) { if( !GetNHApp()->windowlist[wid].dead && GetNHApp()->windowlist[wid].win != NULL ) DestroyWindow(GetNHApp()->windowlist[wid].win); GetNHApp()->windowlist[wid].win = NULL; GetNHApp()->windowlist[wid].type = 0; GetNHApp()->windowlist[wid].dead = 0; } } /* Next output to window will start at (x,y), also moves displayable cursor to (x,y). For backward compatibility, 1 <= x < cols, 0 <= y < rows, where cols and rows are the size of window. */ void mswin_curs(winid wid, int x, int y) { logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgCursor data; data.x = x; data.y = y; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CURSOR, (LPARAM)&data ); } } /* putstr(window, attr, str) -- Print str on the window with the given attribute. Only printable ASCII characters (040-0126) must be supported. Multiple putstr()s are output on separate lines. Attributes can be one of ATR_NONE (or 0) ATR_ULINE ATR_BOLD ATR_BLINK ATR_INVERSE If a window-port does not support all of these, it may map unsupported attributes to a supported one (e.g. map them all to ATR_INVERSE). putstr() may compress spaces out of str, break str, or truncate str, if necessary for the display. Where putstr() breaks a line, it has to clear to end-of-line. -- putstr should be implemented such that if two putstr()s are done consecutively the user will see the first and then the second. In the tty port, pline() achieves this by calling more() or displaying both on the same line. */ void mswin_putstr(winid wid, int attr, const char *text) { logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text); mswin_putstr_ex(wid, attr, text, 0); } void mswin_putstr_ex(winid wid, int attr, const char *text, boolean app) { if( (wid >= 0) && (wid < MAXWINDOWS) ) { if( GetNHApp()->windowlist[wid].win==NULL && GetNHApp()->windowlist[wid].type==NHW_MENU ) { GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_TEXT); GetNHApp()->windowlist[wid].dead = 0; } if (GetNHApp()->windowlist[wid].win != NULL) { MSNHMsgPutstr data; ZeroMemory(&data, sizeof(data)); data.attr = attr; data.text = text; data.append = app; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PUTSTR, (LPARAM)&data ); } } } /* Display the file named str. Complain about missing files iff complain is TRUE. */ void mswin_display_file(const char *filename,BOOLEAN_P must_exist) { dlb *f; TCHAR wbuf[BUFSZ]; logDebug("mswin_display_file(%s, %d)\n", filename, must_exist); f = dlb_fopen(filename, RDTMODE); if (!f) { if (must_exist) { TCHAR message[90]; _stprintf(message, TEXT("Warning! Could not find file: %s\n"), NH_A2W(filename, wbuf, sizeof(wbuf))); MessageBox(GetNHApp()->hMainWnd, message, TEXT("ERROR"), MB_OK | MB_ICONERROR ); } } else { winid text; char line[LLEN]; text = mswin_create_nhwindow(NHW_TEXT); while (dlb_fgets(line, LLEN, f)) { size_t len; len = strlen(line); if( line[len-1]=='\n' ) line[len-1]='\x0'; mswin_putstr(text, ATR_NONE, line); } (void) dlb_fclose(f); mswin_display_nhwindow(text, 1); mswin_destroy_nhwindow(text); } } /* Start using window as a menu. You must call start_menu() before add_menu(). After calling start_menu() you may not putstr() to the window. Only windows of type NHW_MENU may be used for menus. */ void mswin_start_menu(winid wid) { logDebug("mswin_start_menu(%d)\n", wid); if( (wid >= 0) && (wid < MAXWINDOWS) ) { if( GetNHApp()->windowlist[wid].win==NULL && GetNHApp()->windowlist[wid].type==NHW_MENU ) { GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_MENU); GetNHApp()->windowlist[wid].dead = 0; } if(GetNHApp()->windowlist[wid].win != NULL) { SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_STARTMENU, (LPARAM)NULL ); } } } /* add_menu(windid window, int glyph, const anything identifier, char accelerator, char groupacc, int attr, char *str, boolean preselected) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable item is 0, the window system is free to select its own accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). Glyph is an optional glyph to accompany the line. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z]. -- It is expected that callers do not mix accelerator choices. Either all selectable items have an accelerator or let the window system pick them. Don't do both. -- Groupacc is a group accelerator. It may be any character outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with the menu command (or their user defined alises), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the menu is displayed, set preselected to TRUE. */ void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel) { logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph, identifier, (char)accelerator, (char)group_accel, attr, str, presel); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgAddMenu data; ZeroMemory(&data, sizeof(data)); data.glyph = glyph; data.identifier = identifier; data.accelerator = accelerator; data.group_accel = group_accel; data.attr = attr; data.str = str; data.presel = presel; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDMENU, (LPARAM)&data ); } } /* end_menu(window, prompt) -- Stop adding entries to the menu and flushes the window to the screen (brings to front?). Prompt is a prompt to give the user. If prompt is NULL, no prompt will be printed. ** This probably shouldn't flush the window any more (if ** it ever did). That should be select_menu's job. -dean */ void mswin_end_menu(winid wid, const char *prompt) { logDebug("mswin_end_menu(%d, %s)\n", wid, prompt); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgEndMenu data; ZeroMemory(&data, sizeof(data)); data.text = prompt; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ENDMENU, (LPARAM)&data ); } } /* int select_menu(windid window, int how, menu_item **selected) -- Return the number of items selected; 0 if none were chosen, -1 when explicitly cancelled. If items were selected, then selected is filled in with an allocated array of menu_item structures, one for each selected line. The caller must free this array when done with it. The "count" field of selected is a user supplied count. If the user did not supply a count, then the count field is filled with -1 (meaning all). A count of zero is equivalent to not being selected and should not be in the list. If no items were selected, then selected is NULL'ed out. How is the mode of the menu. Three valid values are PICK_NONE, PICK_ONE, and PICK_N, meaning: nothing is selectable, only one thing is selectable, and any number valid items may selected. If how is PICK_NONE, this function should never return anything but 0 or -1. -- You may call select_menu() on a window multiple times -- the menu is saved until start_menu() or destroy_nhwindow() is called on the window. -- Note that NHW_MENU windows need not have select_menu() called for them. There is no way of knowing whether select_menu() will be called for the window at create_nhwindow() time. */ int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected) { int nReturned = -1; logDebug("mswin_select_menu(%d, %d)\n", wid, how); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { nReturned = mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, how, selected); } return nReturned; } /* -- Indicate to the window port that the inventory has been changed. -- Merely calls display_inventory() for window-ports that leave the window up, otherwise empty. */ void mswin_update_inventory() { logDebug("mswin_update_inventory()\n"); } /* mark_synch() -- Don't go beyond this point in I/O on any channel until all channels are caught up to here. Can be an empty call for the moment */ void mswin_mark_synch() { logDebug("mswin_mark_synch()\n"); } /* wait_synch() -- Wait until all pending output is complete (*flush*() for streams goes here). -- May also deal with exposure events etc. so that the display is OK when return from wait_synch(). */ void mswin_wait_synch() { logDebug("mswin_wait_synch()\n"); } /* cliparound(x, y)-- Make sure that the user is more-or-less centered on the screen if the playing area is larger than the screen. -- This function is only defined if CLIPPING is defined. */ void mswin_cliparound(int x, int y) { winid wid = WIN_MAP; logDebug("mswin_cliparound(%d, %d)\n", x, y); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgClipAround data; data.x = x; data.y = y; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLIPAROUND, (LPARAM)&data ); } } /* print_glyph(window, x, y, glyph) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). */ void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph) { logDebug("mswin_print_glyph(%d, %d, %d, %d)\n", wid, x, y, glyph); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgPrintGlyph data; ZeroMemory(&data, sizeof(data) ); data.x = x; data.y = y; data.glyph = glyph; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PRINT_GLYPH, (LPARAM)&data ); } } /* raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. It need not recognize ASCII control characters. This is used during startup (before windowing system initialization -- maybe this means only error startup messages are raw), for error messages, and maybe other "msg" uses. E.g. updating status for micros (i.e, "saving"). */ void mswin_raw_print(const char *str) { TCHAR wbuf[255]; logDebug("mswin_raw_print(%s)\n", str); if( str && *str) MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), TEXT("NetHack"), MB_OK ); } /* raw_print_bold(str) -- Like raw_print(), but prints in bold/standout (if possible). */ void mswin_raw_print_bold(const char *str) { TCHAR wbuf[255]; logDebug("mswin_raw_print_bold(%s)\n", str); if( str && *str) MessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), TEXT("NetHack"), MB_OK ); } /* int nhgetch() -- Returns a single character input from the user. -- In the tty window-port, nhgetch() assumes that tgetch() will be the routine the OS provides to read a character. Returned character _must_ be non-zero. */ int mswin_nhgetch() { PMSNHEvent event; int key = 0; logDebug("mswin_nhgetch()\n"); while( (event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR ) mswin_main_loop(); key = event->kbd.ch; return (key); } /* int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of CLICK_1 -- mouse click type 1 CLICK_2 -- mouse click type 2 The different click types can map to whatever the hardware supports. If no mouse is supported, this routine always returns a non-zero character. */ int mswin_nh_poskey(int *x, int *y, int *mod) { PMSNHEvent event; int key; logDebug("mswin_nh_poskey()\n"); while( (event = mswin_input_pop())==NULL ) mswin_main_loop(); if( event->type==NHEVENT_MOUSE ) { *mod = event->ms.mod; *x = event->ms.x; *y = event->ms.y; key = 0; } else { key = event->kbd.ch; } return (key); } /* nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] */ void mswin_nhbell() { logDebug("mswin_nhbell()\n"); } /* doprev_message() -- Display previous messages. Used by the ^P command. -- On the tty-port this scrolls WIN_MESSAGE back one line. */ int mswin_doprev_message() { logDebug("mswin_doprev_message()\n"); SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); return 0; } /* char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in choices or default. If choices is NULL, all possible inputs are accepted and returned. This overrides everything else. The choices are expected to be in lower case. Entering ESC always maps to 'q', or 'n', in that order, if present in choices, otherwise it maps to default. Entering any other quit character (SPACE, RETURN, NEWLINE) maps to default. -- If the choices string contains ESC, then anything after it is an acceptable response, but the ESC and whatever follows is not included in the prompt. -- If the choices string contains a '#' then accept a count. Place this value in the global "yn_number" and return '#'. -- This uses the top line in the tty window-port, other ports might use a popup. */ char mswin_yn_function(const char *question, const char *choices, CHAR_P def) { int result=-1; char ch; char yn_esc_map='\033'; char message[BUFSZ]; char res_ch[2]; logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def); if (choices) { char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); if ((cb = index(choicebuf, '\033')) != 0) { /* anything beyond is hidden */ *cb = '\0'; } sprintf(message, "%s [%s] ", question, choicebuf); if (def) sprintf(eos(message), "(%c) ", def); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); } #if defined(WIN_CE_SMARTPHONE) { char buf[BUFSZ]; ZeroMemory(buf, sizeof(buf)); if( choices ) { if( !index(choices, '\033') ) buf[0]='\033'; /* make sure ESC is always available */ strncat( buf, choices, sizeof(buf)-2); NHSPhoneSetKeypadFromString( buf ); } else { /* sometimes choices are included in the message itself, e.g. "what? [abcd]" */ char *p1, *p2; p1 = strchr(question, '['); p2 = strrchr(question, ']'); if( p1 && p2 && p1= 0) && (wid < MAXWINDOWS) ) { DestroyWindow(GetNHApp()->windowlist[wid].win); GetNHApp()->windowlist[wid].win = mswin_init_RIP_window(); GetNHApp()->windowlist[wid].type = NHW_RIP; GetNHApp()->windowlist[wid].dead = 0; } genl_outrip(wid, how); } /* handle options updates here */ void mswin_preference_update(const char *pref) { HDC hdc; if( _stricmp( pref, "font_menu")==0 || _stricmp( pref, "font_size_menu")==0 ) { if( iflags.wc_fontsiz_menuNHFONT_SIZE_MAX ) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if( _stricmp( pref, "font_status")==0 || _stricmp( pref, "font_size_status")==0 ) { if( iflags.wc_fontsiz_statusNHFONT_SIZE_MAX ) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if( _stricmp( pref, "font_message")==0 || _stricmp( pref, "font_size_message")==0 ) { if( iflags.wc_fontsiz_messageNHFONT_SIZE_MAX ) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if( _stricmp( pref, "font_text")==0 || _stricmp( pref, "font_size_text")==0 ) { if( iflags.wc_fontsiz_textNHFONT_SIZE_MAX ) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if( _stricmp( pref, "scroll_margin")==0 ) { mswin_cliparound(u.ux, u.uy); return; } if( _stricmp( pref, "map_mode")==0 ) { mswin_select_map_mode( iflags.wc_map_mode ); return; } if( _stricmp( pref, "hilite_pet")==0 ) { InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE); return; } if( _stricmp( pref, "align_message")==0 || _stricmp( pref, "align_status")==0 ) { mswin_layout_main_window(NULL); return; } if( _stricmp( pref, "vary_msgcount")==0 ) { InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE); mswin_layout_main_window(NULL); return; } if( _stricmp( pref, "fullscreen")==0 ) { mswin_set_fullscreen(iflags.wc2_fullscreen); return; } if( _stricmp( pref, "softkeyboard")==0 ) { GetNHApp()->bUseSIP = iflags.wc2_softkeyboard; return; } if( _stricmp( pref, "wraptext")==0 ) { GetNHApp()->bWrapText = iflags.wc2_wraptext; return; } } void mswin_main_loop() { MSG msg; while( !mswin_have_input() && GetMessage(&msg, NULL, 0, 0)!=0 ) { if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } /* clean up and quit */ void bail(const char *mesg) { clearlocks(); mswin_exit_nhwindows(mesg); terminate(EXIT_SUCCESS); /*NOTREACHED*/ } BOOL initMapTiles(void) { HBITMAP hBmp; BITMAP bm; TCHAR wbuf[MAX_PATH]; int tl_num; SIZE map_size; extern int total_tiles_used; /* no file - no tile */ if( !(iflags.wc_tile_file && *iflags.wc_tile_file) ) return TRUE; /* load bitmap */ hBmp = SHLoadDIBitmap(NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH)); if( hBmp==NULL ) { raw_print("Cannot load tiles from the file. Reverting back to default."); return FALSE; } /* calculate tile dimensions */ GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bm); if( bm.bmWidth%iflags.wc_tile_width || bm.bmHeight%iflags.wc_tile_height ) { DeleteObject(hBmp); raw_print("Tiles bitmap does not match tile_width and tile_height options. Reverting back to default."); return FALSE; } tl_num = (bm.bmWidth/iflags.wc_tile_width)* (bm.bmHeight/iflags.wc_tile_height); if( tl_numbmpMapTiles!=GetNHApp()->bmpTiles ) { DeleteObject(GetNHApp()->bmpMapTiles); } GetNHApp()->bmpMapTiles = hBmp; GetNHApp()->mapTile_X = iflags.wc_tile_width; GetNHApp()->mapTile_Y = iflags.wc_tile_height; GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width; map_size.cx = GetNHApp()->mapTile_X * COLNO; map_size.cy = GetNHApp()->mapTile_Y * ROWNO; mswin_map_stretch( mswin_hwnd_from_winid(WIN_MAP), &map_size, TRUE ); return TRUE; } void mswin_popup_display(HWND hWnd, int* done_indicator) { MSG msg; HWND hChild; /* activate the menu window */ GetNHApp()->hPopupWnd = hWnd; mswin_layout_main_window(hWnd); /* disable game windows */ for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild; hChild = GetWindow(hChild, GW_HWNDNEXT) ) { if( hChild!=hWnd ) EnableWindow(hChild, FALSE); } #if defined(WIN_CE_SMARTPHONE) ShowWindow(GetNHApp()->hMenuBar, SW_HIDE); ShowWindow(SHFindMenuBar(hWnd), SW_SHOW); #else EnableWindow(GetNHApp()->hMenuBar, FALSE); #endif /* bring menu window on top */ SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); /* go into message loop */ if( done_indicator ) *done_indicator = 0; while( IsWindow(hWnd) && (done_indicator==NULL || !*done_indicator) && GetMessage(&msg, NULL, 0, 0)!=0 ) { if( !IsDialogMessage(hWnd, &msg) ) { if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } } void mswin_popup_destroy(HWND hWnd) { HWND hChild; /* enable game windows */ for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild; hChild = GetWindow(hChild, GW_HWNDNEXT) ) { if( hChild!= hWnd) { EnableWindow(hChild, TRUE); } } #if defined(WIN_CE_SMARTPHONE) ShowWindow(SHFindMenuBar(hWnd), SW_HIDE); ShowWindow(GetNHApp()->hMenuBar, SW_SHOW); #else EnableWindow(GetNHApp()->hMenuBar, TRUE); #endif SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); GetNHApp()->hPopupWnd = NULL; mswin_window_mark_dead( mswin_winid_from_handle(hWnd) ); DestroyWindow(hWnd); mswin_layout_main_window(hWnd); SetFocus(GetNHApp()->hMainWnd ); } void mswin_set_fullscreen(BOOL is_fullscreen) { #if defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) SetForegroundWindow(GetNHApp()->hMainWnd); if( is_fullscreen ) { SHFullScreen(GetNHApp()->hMainWnd, SHFS_HIDETASKBAR | SHFS_HIDESTARTICON); MoveWindow( GetNHApp()->hMainWnd, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), FALSE ); } else { RECT rc; SystemParametersInfo(SPI_GETWORKAREA, 0, &rc, 0); SHFullScreen(GetNHApp()->hMainWnd, SHFS_SHOWTASKBAR | SHFS_SHOWSTARTICON); MoveWindow( GetNHApp()->hMainWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE ); } GetNHApp()->bFullScreen = is_fullscreen; #else GetNHApp()->bFullScreen = FALSE; #endif } #if defined(WIN_CE_SMARTPHONE) void NHSPhoneDialogSetup(HWND hDlg, BOOL is_edit, BOOL is_fullscreen) { SHMENUBARINFO mbi; HWND hOK, hCancel; RECT rtOK, rtDlg; // Create our MenuBar ZeroMemory(&mbi, sizeof(SHMENUBARINFO)); mbi.cbSize = sizeof(mbi); mbi.hwndParent = hDlg; mbi.nToolBarId = IDC_SPHONE_DIALOGBAR; mbi.hInstRes = GetNHApp()->hApp; if(!SHCreateMenuBar(&mbi)) { error("cannot create dialog menu"); } if(is_fullscreen) { SHINITDLGINFO shidi; RECT main_wnd_rect; shidi.dwMask = SHIDIM_FLAGS; shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN; shidi.hDlg = hDlg; SHInitDialog(&shidi); GetWindowRect(GetNHApp()->hMainWnd, &main_wnd_rect); MoveWindow( hDlg, main_wnd_rect.left, main_wnd_rect.top, main_wnd_rect.right - main_wnd_rect.left, main_wnd_rect.bottom - main_wnd_rect.top, FALSE ); } /* hide OK and CANCEL buttons */ hOK = GetDlgItem(hDlg, IDOK); hCancel = GetDlgItem(hDlg, IDCANCEL); if( IsWindow(hCancel) ) ShowWindow(hCancel, SW_HIDE); if( IsWindow(hOK) ) { GetWindowRect(hOK, &rtOK); GetWindowRect(hDlg, &rtDlg); rtDlg.bottom -= rtOK.bottom-rtOK.top; ShowWindow(hOK, SW_HIDE); SetWindowPos( hDlg, HWND_TOP, 0, 0, rtDlg.right-rtDlg.left, rtDlg.bottom-rtDlg.top, SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOZORDER ); } /* override "Back" button for edit box dialogs */ if( is_edit ) SendMessage(mbi.hwndMB, SHCMBM_OVERRIDEKEY, VK_TBACK, MAKELPARAM(SHMBOF_NODEFAULT | SHMBOF_NOTIFY, SHMBOF_NODEFAULT | SHMBOF_NOTIFY)); } #endif /* defined(WIN_CE_SMARTPHONE) */ void mswin_read_reg(void) { } void mswin_destroy_reg(void) { } void mswin_write_reg(void) { } #ifdef _DEBUG #include void logDebug(const char *fmt, ...) { FILE *dfp = fopen("nhtrace.log", "a"); if (dfp) { va_list args; va_start(args, fmt); vfprintf(dfp, fmt, args); va_end(args); fclose(dfp); } } #endif nethack-3.4.3/sys/wince/newres.h0100644000000000000000000000143307764735041015252 0ustar rootroot#ifndef __NEWRES_H__ #define __NEWRES_H__ #if !defined(UNDER_CE) #define UNDER_CE _WIN32_WCE #endif #if defined(_WIN32_WCE) #if !defined(WCEOLE_ENABLE_DIALOGEX) #define DIALOGEX DIALOG DISCARDABLE #endif #include #define SHMENUBAR RCDATA #if (defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)) && (_WIN32_WCE >= 300) #include #else #define I_IMAGENONE (-2) #define NOMENU 0xFFFF #define IDS_SHNEW 1 #define IDM_SHAREDNEW 10 #define IDM_SHAREDNEWDEFAULT 11 #endif #endif // _WIN32_WCE #ifdef RC_INVOKED #ifndef _INC_WINDOWS #define _INC_WINDOWS #include "winuser.h" // extract from windows header #endif #endif #ifdef IDC_STATIC #undef IDC_STATIC #endif #define IDC_STATIC (-1) #endif //__NEWRES_H__ nethack-3.4.3/sys/wince/resource.h0100644000000000000000000001534507764735041015605 0ustar rootroot//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by winhack.rc // #define IDC_MYICON 2 #define IDD_WINHACK_DIALOG 102 #define IDD_ABOUTBOX 103 #define IDS_APP_TITLE 103 #define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDS_HELLO 106 #define IDI_WINHACK 107 #define IDC_WINHACK 109 #define IDC_SPHONE_DIALOGBAR 111 #define IDR_MAINFRAME 128 #define IDB_TILES 129 #define IDD_TEXT 130 #define IDD_NHTEXT 130 #define IDD_MENU 132 #define IDB_MENU_SEL 133 #define IDB_MENU_UNSEL 134 #define IDD_COMMANDS 136 #define IDD_GETLIN 138 #define IDD_EXTCMD 139 #define IDD_PLAYER_SELECTOR 141 #define IDB_PETMARK 145 #define IDB_MENU_SEL_COUNT 146 #define IDB_KEYPAD 147 #define IDB_MENUBAR 154 #define IDC_TEXT_VIEW 1001 #define IDC_CMD_MOVE_NW 1001 #define IDC_CMD_MOVE_N 1002 #define IDC_MENU_LIST 1003 #define IDC_CMD_MOVE_NE 1003 #define IDC_MENU_TEXT 1004 #define IDC_CMD_MOVE_W 1004 #define IDC_CMD_MOVE_SELF 1005 #define IDC_CMD_MOVE_E 1006 #define IDC_CMD_MOVE_SW 1007 #define IDC_CMD_MOVE_S 1008 #define IDC_CMD_MOVE_SE 1009 #define IDC_CMD_MOVE_UP 1010 #define IDC_CMD_MOVE_DOWN 1011 #define IDC_CMD_5 1012 #define IDC_CMD_A 1013 #define IDC_CMD_B 1014 #define IDC_CMD_C 1015 #define IDC_CMD_D 1016 #define IDC_CMD_E 1017 #define IDC_CMD_F 1018 #define IDC_CMD_G 1019 #define IDC_CMD_H 1020 #define IDC_CMD_I 1021 #define IDC_CMD_J 1022 #define IDC_CMD_K 1023 #define IDC_CMD_L 1024 #define IDC_CMD_M 1025 #define IDC_CMD_N 1026 #define IDC_CMD_O 1027 #define IDC_CMD_P 1028 #define IDC_CMD_Q 1029 #define IDC_CMD_R 1030 #define IDC_CMD_S 1031 #define IDC_CMD_T 1032 #define IDC_CMD_U 1033 #define IDC_CMD_V 1034 #define IDC_CMD_W 1035 #define IDC_CMD_X 1036 #define IDC_CMD_Y 1037 #define IDC_CMD_Z 1038 #define IDC_CMD_AA 1039 #define IDC_CMD_BB 1040 #define IDC_CMD_CC 1041 #define IDC_CMD_DD 1042 #define IDC_CMD_EE 1043 #define IDC_CMD_FF 1044 #define IDC_CMD_GG 1045 #define IDC_CMD_HH 1046 #define IDC_CMD_II 1047 #define IDC_CMD_JJ 1048 #define IDC_CMD_KK 1049 #define IDC_CMD_LL 1050 #define IDC_CMD_MM 1051 #define IDC_CMD_NN 1052 #define IDC_CMD_OO 1053 #define IDC_CMD_PP 1054 #define IDC_CMD_QQ 1055 #define IDC_CMD_RR 1056 #define IDC_CMD_SS 1057 #define IDC_CMD_TT 1058 #define IDC_CMD_UU 1059 #define IDC_CMD_VV 1060 #define IDC_CMD_WW 1061 #define IDC_CMD_XX 1062 #define IDC_CMD_YY 1063 #define IDC_CMD_ZZ 1064 #define IDC_CMD_FIRST 1100 #define IDC_CMD_LAST 1300 #define IDC_GETLIN_EDIT 1309 #define IDC_EXTCMD_LIST 1310 #define IDC_PLSEL_NAME 1314 #define IDC_PLSEL_ROLE_RANDOM 1315 #define IDC_PLSEL_RACE_RANDOM 1318 #define IDC_PLSEL_GENDER_RANDOM 1319 #define IDC_PLSEL_ALIGN_RANDOM 1320 #define IDC_PLSEL_ROLE_LIST 1323 #define IDC_PLSEL_RACE_LIST 1324 #define IDC_PLSEL_ALIGN_LIST 1325 #define IDC_PLSEL_GENDER_LIST 1326 #define IDC_ABOUT_VERSION 1327 #define IDC_TEXT_CONTROL 1331 #define IDC_ABOUT_COPYRIGHT 1332 #define IDM_SAVE 32771 #define IDM_HELP_LONG 32772 #define IDM_HELP_COMMANDS 32773 #define IDM_HELP_HISTORY 32774 #define IDM_HELP_INFO_CHAR 32775 #define IDM_HELP_INFO_KEY 32776 #define IDM_HELP_OPTIONS 32777 #define IDM_HELP_OPTIONS_LONG 32778 #define IDM_HELP_EXTCMD 32779 #define IDM_HELP_LICENSE 32780 #define IDM_MAP_TILES 32781 #define IDM_MAP_ASCII4X6 32782 #define IDM_MAP_ASCII6X8 32783 #define IDM_MAP_ASCII8X8 32784 #define IDM_MAP_ASCII16X8 32785 #define IDM_MAP_ASCII7X12 32786 #define IDM_MAP_ASCII8X12 32787 #define IDM_MAP_ASCII16X12 32788 #define IDM_MAP_ASCII12X16 32789 #define IDM_MAP_ASCII10X18 32790 #define IDM_MAP_FIT_TO_SCREEN 32791 #define ID_FILE 32792 #define IDS_CAP_FILE 32793 #define ID_HELP 32794 #define IDS_CAP_HELP 32795 #define IDS_CAP_TEMP 32796 #define ID_MAP 32797 #define IDS_CAP_AMP 32798 #define IDS_CAP_MAP 32799 #define IDM_VIEW_KEYPAD 32800 #define ID_VIEW 32801 #define IDS_CAP_VIEW 32802 #define IDS_CAP_ENTIREMAP 32826 #define IDS_CAP_NORMALMAP 32827 #define IDM_HELP_MENU 32828 #define IDM_VIEW_OPTIONS 32829 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 155 #define _APS_NEXT_COMMAND_VALUE 32830 #define _APS_NEXT_CONTROL_VALUE 1334 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif nethack-3.4.3/sys/wince/winMS.h0100644000000000000000000001261107764735041015004 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINMS_H #define WINMS_H #pragma warning(disable:4142) /* benign redefinition of type */ #define WIN32_LEAN_AND_MEAN #include #include #include #include #include "resource.h" #include "hack.h" #if defined(WIN_CE_POCKETPC) #include #include #endif #if defined(WIN_CE_SMARTPHONE) #include #include #include #include #include #include #include #endif #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) #include #endif /* Taskbar Menu height */ #define MENU_HEIGHT 26 /* Create an array to keep track of the various windows */ #ifndef MAXWINDOWS #define MAXWINDOWS 15 #endif /* RIP window ID */ #define NHW_RIP 32 #define NHW_KEYPAD 33 /* size of tiles */ #ifndef TILE_X #define TILE_X 16 #endif #define TILE_Y 16 /* tiles per line in the bitmap */ #define TILES_PER_LINE 40 /* tile background color */ #define TILE_BK_COLOR RGB(71, 108, 108) /* minimum/maximum font size (in points - 1/72 inch) */ #define NHFONT_DEFAULT_SIZE 9 #define NHFONT_STATUS_DEFAULT_SIZE 6 #define NHFONT_SIZE_MIN 3 #define NHFONT_SIZE_MAX 20 typedef struct mswin_nhwindow_data { HWND win; int type; int dead; } MSNHWinData, *PMSNHWinData; /* global application data - alailable thour GetNHApp() */ typedef struct mswin_nhwindow_app { HINSTANCE hApp; /* hInstance from WinMain */ int nCmdShow; /* main window mode flag */ HWND hMainWnd; /* main window handle */ HACCEL hAccelTable; /* accelerator table */ HWND hPopupWnd; /* active dialog window (nethack menu, text, etc) */ HWND hMenuBar; /* menu bar */ MSNHWinData windowlist[MAXWINDOWS]; /* nethack windows array */ HBITMAP bmpTiles; /* nethack tiles */ HBITMAP bmpPetMark; /* pet mark Bitmap */ HBITMAP bmpMapTiles; /* alternative map tiles */ int mapTile_X; /* alt. tiles width */ int mapTile_Y; /* alt. tiles height */ int mapTilesPerLine; /* number of tile per row in the bitmap */ boolean bNoHScroll; /* disable cliparound for horizontal grid (map) */ boolean bNoVScroll; /* disable cliparound for vertical grid (map) */ int mapDisplayModeSave; /* saved map display mode */ int bCmdPad; /* command pad - on-screen keyboard */ HWND hCmdWnd; /* handle of on-screen keyboard window */ /* options */ boolean bWrapText; /* format text to fit the window */ boolean bFullScreen;/* run nethack in full-screen mode */ boolean bHideScrollBars; /* hide scroll bars */ boolean bUseSIP; /* use SIP (built-in software keyboard) for menus (PocketPC only) */ } NHWinApp, *PNHWinApp; extern PNHWinApp GetNHApp(); #define E extern E struct window_procs mswin_procs; #undef E /* Some prototypes */ void mswin_init_nhwindows(int* argc, char** argv); void mswin_player_selection(void); void mswin_askname(void); void mswin_get_nh_event(void); void mswin_exit_nhwindows(const char *); void mswin_suspend_nhwindows(const char *); void mswin_resume_nhwindows(void); winid mswin_create_nhwindow(int type); void mswin_clear_nhwindow(winid wid); void mswin_display_nhwindow(winid wid, BOOLEAN_P block); void mswin_destroy_nhwindow(winid wid); void mswin_curs(winid wid, int x, int y); void mswin_putstr(winid wid, int attr, const char *text); void mswin_putstr_ex(winid wid, int attr, const char *text, boolean append); void mswin_display_file(const char *filename,BOOLEAN_P must_exist); void mswin_start_menu(winid wid); void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel); void mswin_end_menu(winid wid, const char *prompt); int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected); void mswin_update_inventory(void); void mswin_mark_synch(void); void mswin_wait_synch(void); void mswin_cliparound(int x, int y); void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph); void mswin_raw_print(const char *str); void mswin_raw_print_bold(const char *str); int mswin_nhgetch(void); int mswin_nh_poskey(int *x, int *y, int *mod); void mswin_nhbell(void); int mswin_doprev_message(void); char mswin_yn_function(const char *question, const char *choices, CHAR_P def); void mswin_getlin(const char *question, char *input); int mswin_get_ext_cmd(void); void mswin_number_pad(int state); void mswin_delay_output(void); void mswin_change_color(void); char *mswin_get_color_string(void); void mswin_start_screen(void); void mswin_end_screen(void); void mswin_outrip(winid wid, int how); void mswin_preference_update(const char *pref); /* helper function */ HWND mswin_hwnd_from_winid(winid wid); winid mswin_winid_from_type(int type); winid mswin_winid_from_handle(HWND hWnd); void mswin_window_mark_dead(winid wid); void bail(const char *mesg); void nhapply_image_transparent( HDC hDC, int x, int y, int width, int height, HDC sourceDC, int s_x, int s_y, int s_width, int s_height, COLORREF cTransparent ); void mswin_popup_display(HWND popup, int* done_indicator); void mswin_popup_destroy(HWND popup); #if defined(WIN_CE_SMARTPHONE) void NHSPhoneDialogSetup(HWND hDlg, BOOL is_edit, BOOL is_fullscreen); #endif void mswin_read_reg(void); void mswin_destroy_reg(void); void mswin_write_reg(void); void mswin_set_fullscreen(BOOL is_fullscreen); #endif /* WINmswin_H */ nethack-3.4.3/sys/wince/winhack.c0100644000000000000000000002003607764735041015366 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ // winhack.cpp : Defines the entry point for the application. // #include "winMS.h" #include "hack.h" #include "dlb.h" #include "mhmain.h" #include "mhmap.h" #ifdef OVL0 #define SHARED_DCL #else #define SHARED_DCL extern #endif SHARED_DCL char orgdir[PATHLEN]; /* also used in pcsys.c, amidos.c */ extern void FDECL(nethack_exit,(int)); static TCHAR* _get_cmd_arg(TCHAR* pCmdLine); // Global Variables: NHWinApp _nethack_app; // Foward declarations of functions included in this code module: BOOL InitInstance(HINSTANCE, int); static void win_hack_init(int, char **); static void __cdecl mswin_moveloop(void *); static BOOL setMapTiles(const char* fname); extern void FDECL(pcmain, (int,char **)); #define MAX_CMDLINE_PARAM 255 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { INITCOMMONCONTROLSEX InitCtrls; HWND nethackWnd; int argc; char* argv[MAX_CMDLINE_PARAM]; size_t len; TCHAR* p; TCHAR wbuf[NHSTR_BUFSIZE]; char buf[NHSTR_BUFSIZE]; /* ensure that we don't access violate on a panic() */ windowprocs.win_raw_print = mswin_raw_print; windowprocs.win_raw_print_bold = mswin_raw_print_bold; /* init applicatio structure */ _nethack_app.hApp = hInstance; _nethack_app.nCmdShow = nCmdShow; _nethack_app.hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WINHACK); _nethack_app.hMainWnd = NULL; _nethack_app.hPopupWnd = NULL; _nethack_app.hMenuBar = NULL; _nethack_app.bmpTiles = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TILES)); if( _nethack_app.bmpTiles==NULL ) panic("cannot load tiles bitmap"); _nethack_app.bmpPetMark = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PETMARK)); if( _nethack_app.bmpPetMark==NULL ) panic("cannot load pet mark bitmap"); _nethack_app.bmpMapTiles = _nethack_app.bmpTiles; _nethack_app.mapTile_X = TILE_X; _nethack_app.mapTile_Y = TILE_Y; _nethack_app.mapTilesPerLine = TILES_PER_LINE; _nethack_app.bNoHScroll = FALSE; _nethack_app.bNoVScroll = FALSE; #if defined(WIN_CE_PS2xx) || defined(WIN_CE_POCKETPC) || defined(WIN_CE_SMARTPHONE) _nethack_app.bCmdPad = TRUE; #else _nethack_app.bCmdPad = FALSE; #endif _nethack_app.bWrapText = TRUE; _nethack_app.bFullScreen = TRUE; #if defined(WIN_CE_SMARTPHONE) _nethack_app.bHideScrollBars = TRUE; #else _nethack_app.bHideScrollBars = FALSE; #endif _nethack_app.bUseSIP = TRUE; // check for running nethack programs nethackWnd = FindWindow(szMainWindowClass, NULL); if( nethackWnd ) { // bring on top SetForegroundWindow(nethackWnd); return FALSE; } // init controls ZeroMemory(&InitCtrls, sizeof(InitCtrls)); InitCtrls.dwSize = sizeof(InitCtrls); InitCtrls.dwICC = ICC_LISTVIEW_CLASSES; if( !InitCommonControlsEx(&InitCtrls) ) { MessageBox(NULL, TEXT("Cannot init common controls"), TEXT("ERROR"), MB_OK | MB_ICONSTOP); return FALSE; } // Perform application initialization: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } /* get command line parameters */ p = _get_cmd_arg( #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) lpCmdLine #else GetCommandLine() #endif ); for( argc = 1; p && argc0 ) { argv[argc] = _strdup( NH_W2A(p, buf, BUFSZ) ); } else { argv[argc] = ""; } p = _get_cmd_arg(NULL); } GetModuleFileName(NULL, wbuf, BUFSZ); argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ)); pcmain(argc,argv); moveloop(); return 0; } // // FUNCTION: InitInstance(HANDLE, int) // // PURPOSE: Saves instance handle and creates main window // // COMMENTS: // // In this function, we save the instance handle in a global variable and // create and display the main program window. // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { return TRUE; } PNHWinApp GetNHApp() { return &_nethack_app; } static int eraseoldlocks() { register int i; /* cannot use maxledgerno() here, because we need to find a lock name * before starting everything (including the dungeon initialization * that sets astral_level, needed for maxledgerno()) up */ for(i = 1; i <= MAXDUNGEON*MAXLEVEL + 1; i++) { /* try to remove all */ set_levelfile_name(lock, i); (void) unlink(fqname(lock, LEVELPREFIX, 0)); } set_levelfile_name(lock, 0); if(unlink(fqname(lock, LEVELPREFIX, 0))) return 0; /* cannot remove it */ return(1); /* success! */ } void getlock() { const char *fq_lock; char tbuf[BUFSZ]; TCHAR wbuf[BUFSZ]; HANDLE f; int fd; int choice; /* regularize(lock); */ /* already done in pcmain */ Sprintf(tbuf, "%s", fqname(lock, LEVELPREFIX, 0)); set_levelfile_name(lock, 0); fq_lock = fqname(lock, LEVELPREFIX, 1); f = CreateFile( NH_A2W(fq_lock, wbuf, BUFSZ), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if( f==INVALID_HANDLE_VALUE ) { if(GetLastError()==ERROR_FILE_NOT_FOUND) goto gotlock; /* no such file */ error("Cannot open %s", fq_lock); } CloseHandle(f); /* prompt user that the game alredy exist */ choice = MessageBox( GetNHApp()->hMainWnd, TEXT("There are files from a game in progress under your name. Recover?"), TEXT("Nethack"), MB_YESNO | MB_DEFBUTTON1 ); switch(choice) { case IDYES: if(recover_savefile()) { goto gotlock; } else { error("Couldn't recover old game."); } break; case IDNO: unlock_file(HLOCK); error("%s", "Cannot start a new game."); break; }; gotlock: fd = creat(fq_lock, FCMASK); if(fd == -1) { error("cannot creat lock file (%s.)", fq_lock); } else { if(write(fd, (char *) &hackpid, sizeof(hackpid)) != sizeof(hackpid)){ error("cannot write lock (%s)", fq_lock); } if(close(fd) == -1) { error("cannot close lock (%s)", fq_lock); } } } /* misc functions */ void error VA_DECL(const char *,s) TCHAR wbuf[1024]; char buf[1024]; DWORD last_error = GetLastError(); VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); vsprintf(buf, s, VA_ARGS); NH_A2W(buf, wbuf, sizeof(wbuf)/sizeof(wbuf[0])); if( last_error>0 ) { LPVOID lpMsgBuf; if( FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, last_error, 0, // Default language (LPTSTR) &lpMsgBuf, 0, NULL ) ) { _tcsncat(wbuf, TEXT("\nSystem Error: "), sizeof(wbuf)/sizeof(wbuf[0]) - _tcslen(wbuf) ); _tcsncat(wbuf, lpMsgBuf, sizeof(wbuf)/sizeof(wbuf[0]) - _tcslen(wbuf) ); // Free the buffer. LocalFree( lpMsgBuf ); } } VA_END(); MessageBox( NULL, wbuf, TEXT("Error"), MB_OK | MB_ICONERROR ); exit(EXIT_FAILURE); } TCHAR* _get_cmd_arg(TCHAR* pCmdLine) { static TCHAR* pArgs = NULL; TCHAR *pRetArg; BOOL bQuoted; if( !pCmdLine && !pArgs ) return NULL; if( !pArgs ) pArgs = pCmdLine; /* skip whitespace */ for(pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg)); if( !*pRetArg ) { pArgs = NULL; return NULL; } /* check for quote */ if( *pRetArg==TEXT('"') ) { bQuoted = TRUE; pRetArg = CharNext(pRetArg); pArgs = _tcschr(pRetArg, TEXT('"')); } else { /* skip to whitespace */ for(pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs)); } if( pArgs && *pArgs ) { TCHAR* p; p = pArgs; pArgs = CharNext(pArgs); *p = (TCHAR)0; } else { pArgs = NULL; } return pRetArg; } /* * Strip out troublesome file system characters. */ void nt_regularize(s) /* normalize file name */ register char *s; { register unsigned char *lp; for (lp = s; *lp; lp++) if ( *lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/' || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|' || *lp == ':' || (*lp > 127)) *lp = '_'; } void win32_abort() { #ifdef WIZARD if (wizard) DebugBreak(); #endif abort(); } void append_port_id(buf) char *buf; { char *portstr = PORT_CE_PLATFORM " " PORT_CE_CPU; Sprintf(eos(buf), " %s", portstr); } nethack-3.4.3/sys/wince/winhack.rc0100644000000000000000000002561607764735041015561 0ustar rootroot//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "newres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_WINHACK ICON DISCARDABLE "..\\..\\wince\\NETHACK.ICO" ///////////////////////////////////////////////////////////////////////////// // // Menubar // IDC_WINHACK MENU DISCARDABLE BEGIN POPUP "File" BEGIN MENUITEM "&Save", IDM_SAVE MENUITEM SEPARATOR MENUITEM "&Quit", IDM_EXIT END POPUP "Map" BEGIN MENUITEM "&0 - Use Tiles", IDM_MAP_TILES MENUITEM "&1 - ASCII (4x6)", IDM_MAP_ASCII4X6 MENUITEM "&2 - ASCII (6x8)", IDM_MAP_ASCII6X8 MENUITEM "&3 - ASCII (8x8)", IDM_MAP_ASCII8X8 MENUITEM "&4 - ASCII (16x8)", IDM_MAP_ASCII16X8 MENUITEM "&5 - ASCII (7x12)", IDM_MAP_ASCII7X12 MENUITEM "&6 - ASCII (8x12)", IDM_MAP_ASCII8X12 MENUITEM "&7 - ASCII (16x12)", IDM_MAP_ASCII16X12 MENUITEM "&8 - ASCII (12x16)", IDM_MAP_ASCII12X16 MENUITEM "&9 - ASCII (10x18)", IDM_MAP_ASCII10X18 MENUITEM SEPARATOR MENUITEM "&Fit To Screen", IDM_MAP_FIT_TO_SCREEN END POPUP "View" BEGIN MENUITEM "&Keypad", IDM_VIEW_KEYPAD MENUITEM "&Options", IDM_VIEW_OPTIONS END POPUP "Help" BEGIN MENUITEM "&About ...", IDM_ABOUT MENUITEM "&Long description of the game", IDM_HELP_LONG MENUITEM "List of &commands", IDM_HELP_COMMANDS MENUITEM "&History of NetHack", IDM_HELP_HISTORY MENUITEM "&Info on a character", IDM_HELP_INFO_CHAR MENUITEM "Info on what a given &key does", IDM_HELP_INFO_KEY MENUITEM "List of game &options", IDM_HELP_OPTIONS MENUITEM "&Longer list of game options", IDM_HELP_OPTIONS_LONG MENUITEM "List of e&xtended commands", IDM_HELP_EXTCMD MENUITEM "The &NetHack license", IDM_HELP_LICENSE END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_WINHACK ACCELERATORS MOVEABLE PURE BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 123, 87 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "System" BEGIN LTEXT "NetHack",IDC_ABOUT_VERSION,0,2,120,15,SS_NOPREFIX LTEXT "Copyright",IDC_ABOUT_COPYRIGHT,0,20,120,50 DEFPUSHBUTTON "OK",IDOK,45,75,30,11,WS_GROUP END IDD_MENU DIALOG DISCARDABLE 0, 0, 109, 153 STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_BORDER FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,5,130,50,14,BS_NOTIFY PUSHBUTTON "Cancel",IDCANCEL,55,130,50,14,BS_NOTIFY CONTROL "List1",IDC_MENU_LIST,"SysListView32",WS_BORDER | WS_TABSTOP,5,5,100,60 EDITTEXT IDC_MENU_TEXT,5,70,100,55,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_GETLIN DIALOG DISCARDABLE 0, 0, 115, 30 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Question?" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,0,16,55,14 PUSHBUTTON "Cancel",IDCANCEL,55,16,60,14 EDITTEXT IDC_GETLIN_EDIT,0,0,115,15,ES_AUTOHSCROLL END IDD_PLAYER_SELECTOR DIALOG DISCARDABLE 0, 0, 105, 124 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "What are you?" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_PLSEL_NAME,35,0,70,12,ES_AUTOHSCROLL | ES_READONLY LTEXT "Name:",IDC_STATIC,0,0,25,10 CONTROL "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,20,40,10 COMBOBOX IDC_PLSEL_ROLE_LIST,50,20,50,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,45,40,10 COMBOBOX IDC_PLSEL_RACE_LIST,50,45,50,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_GENDER_RANDOM,"Button", BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,70, 40,10 COMBOBOX IDC_PLSEL_GENDER_LIST,50,70,50,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,95,40,10 COMBOBOX IDC_PLSEL_ALIGN_LIST,50,95,50,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP GROUPBOX "Role",IDC_STATIC,0,10,105,25,WS_GROUP GROUPBOX "Race",IDC_STATIC,0,35,105,25 GROUPBOX "Gender",IDC_STATIC,0,60,105,25 GROUPBOX "Alignment",IDC_STATIC,0,85,105,25 DEFPUSHBUTTON "Play",IDOK,0,110,55,14 PUSHBUTTON "Quit",IDCANCEL,55,110,50,14 END IDD_NHTEXT DIALOG DISCARDABLE 0, 0, 83, 97 STYLE WS_CHILD | WS_BORDER FONT 8, "System" BEGIN DEFPUSHBUTTON "OK",IDOK,15,80,50,14 EDITTEXT IDC_TEXT_CONTROL,5,0,70,75,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_EXTCMD DIALOG DISCARDABLE 0, 0, 109, 114 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Extended Commands" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,75,5,30,14 PUSHBUTTON "Cancel",IDCANCEL,75,20,30,14 LISTBOX IDC_EXTCMD_LIST,5,5,65,105,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""newres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Bitmap // IDB_TILES BITMAP DISCARDABLE "..\\..\\wince\\tiles.bmp" IDB_MENU_SEL BITMAP DISCARDABLE "..\\..\\wince\\mnsel.bmp" IDB_MENU_UNSEL BITMAP DISCARDABLE "..\\..\\wince\\mnunsel.bmp" IDB_PETMARK BITMAP DISCARDABLE "..\\..\\wince\\petmark.bmp" IDB_MENU_SEL_COUNT BITMAP DISCARDABLE "..\\..\\wince\\mnselcnt.bmp" IDB_KEYPAD BITMAP DISCARDABLE "..\\..\\wince\\keypad.bmp" IDB_MENUBAR BITMAP DISCARDABLE "..\\..\\wince\\menubar.bmp" ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_PLAYER_SELECTOR, DIALOG BEGIN RIGHTMARGIN, 98 BOTTOMMARGIN, 117 END IDD_NHTEXT, DIALOG BEGIN LEFTMARGIN, 5 RIGHTMARGIN, 76 TOPMARGIN, 7 BOTTOMMARGIN, 94 END IDD_EXTCMD, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 102 TOPMARGIN, 7 BOTTOMMARGIN, 107 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Data // IDC_WINHACK SHMENUBAR DISCARDABLE BEGIN IDC_WINHACK, 6, I_IMAGENONE, ID_FILE, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_FILE, 0, 0, I_IMAGENONE, ID_MAP, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_MAP, 0, 1, I_IMAGENONE, ID_VIEW, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_VIEW, 0, 2, I_IMAGENONE, ID_HELP, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_HELP, 0, 3, 0, IDM_MAP_FIT_TO_SCREEN, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, IDM_MAP_FIT_TO_SCREEN, NOMENU, 1, IDM_VIEW_KEYPAD, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, 0, IDM_VIEW_KEYPAD, NOMENU, END #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,4,2,0 PRODUCTVERSION 3,4,2,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x9L #else FILEFLAGS 0x8L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "NetHack 3.4.3 for Windows CE\0" VALUE "CompanyName", " \0" VALUE "FileDescription", "nethackm\0" VALUE "FileVersion", "3, 4, 3, 0\0" VALUE "InternalName", "nethackm\0" VALUE "LegalCopyright", "Copyright © 2003\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "nethackm.exe\0" VALUE "PrivateBuild", "031014\0" VALUE "ProductName", "NetHack\0" VALUE "ProductVersion", "3, 4, 3, 0\0" VALUE "SpecialBuild", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // !_MAC ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_APP_TITLE "NetHack" IDC_WINHACK "NETHACK" END STRINGTABLE DISCARDABLE BEGIN IDM_MAP_FIT_TO_SCREEN "Fit to Screen" IDS_CAP_FILE "File" IDS_CAP_HELP "Help" IDS_CAP_MAP "Map" END STRINGTABLE DISCARDABLE BEGIN IDM_VIEW_KEYPAD "Show/Hide keypad." IDS_CAP_VIEW "View" END STRINGTABLE DISCARDABLE BEGIN IDOK "Done" IDCANCEL "Cancel" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED nethack-3.4.3/sys/wince/winhcksp.rc0100644000000000000000000002271707764735041015762 0ustar rootroot//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "newres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_WINHACK ICON DISCARDABLE "..\\..\\wince\\NETHACK.ICO" ///////////////////////////////////////////////////////////////////////////// // // Menubar // IDC_WINHACK MENU DISCARDABLE BEGIN MENUITEM "Entire Map", IDM_MAP_FIT_TO_SCREEN POPUP "Menu" BEGIN MENUITEM "Options", IDM_VIEW_OPTIONS MENUITEM "Keypad", IDM_VIEW_KEYPAD MENUITEM SEPARATOR MENUITEM "ASCII", IDM_MAP_ASCII8X8 MENUITEM "Use Tiles", IDM_MAP_TILES MENUITEM SEPARATOR MENUITEM "Help", IDM_HELP_MENU MENUITEM "Save", IDM_SAVE MENUITEM "Quit", IDM_EXIT END END IDC_SPHONE_DIALOGBAR MENU DISCARDABLE BEGIN MENUITEM "Done", IDOK MENUITEM "Cancel", IDCANCEL END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_WINHACK ACCELERATORS MOVEABLE PURE BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 123, 87 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "System" BEGIN LTEXT "NetHack",IDC_ABOUT_VERSION,0,2,120,15,SS_NOPREFIX LTEXT "Copyright",IDC_ABOUT_COPYRIGHT,0,20,120,50 DEFPUSHBUTTON "OK",IDOK,45,75,30,11,WS_GROUP END IDD_MENU DIALOG DISCARDABLE 0, 0, 109, 131 STYLE DS_SETFOREGROUND | DS_CONTROL | WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER FONT 8, "MS Sans Serif" BEGIN CONTROL "List1",IDC_MENU_LIST,"SysListView32",WS_BORDER | WS_TABSTOP,5,5,100,60 EDITTEXT IDC_MENU_TEXT,5,70,100,55,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_NHTEXT DIALOG DISCARDABLE 0, 0, 83, 83 STYLE WS_POPUP | WS_BORDER FONT 8, "System" BEGIN EDITTEXT IDC_TEXT_CONTROL,5,0,70,75,ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_EXTCMD DIALOG DISCARDABLE 0, 0, 88, 82 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Extended Commands" FONT 8, "MS Sans Serif" BEGIN LISTBOX IDC_EXTCMD_LIST,7,5,75,69,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END IDD_GETLIN DIALOG DISCARDABLE 0, 0, 115, 16 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Question?" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_GETLIN_EDIT,0,0,115,15,ES_AUTOHSCROLL END IDD_PLAYER_SELECTOR DIALOG DISCARDABLE 0, 0, 105, 124 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "What are you?" FONT 8, "MS Sans Serif" BEGIN EDITTEXT IDC_PLSEL_NAME,35,0,70,12,ES_AUTOHSCROLL | ES_READONLY LTEXT "Name:",IDC_STATIC,0,0,25,10 CONTROL "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,20,40,10 COMBOBOX IDC_PLSEL_ROLE_LIST,50,20,50,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,45,40,10 COMBOBOX IDC_PLSEL_RACE_LIST,50,45,50,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_GENDER_RANDOM,"Button", BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,70, 40,10 COMBOBOX IDC_PLSEL_GENDER_LIST,50,70,50,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP CONTROL "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | BS_NOTIFY | WS_GROUP | WS_TABSTOP,5,95,40,10 COMBOBOX IDC_PLSEL_ALIGN_LIST,50,95,50,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_GROUP | WS_TABSTOP GROUPBOX "Role",IDC_STATIC,0,10,105,25,WS_GROUP GROUPBOX "Race",IDC_STATIC,0,35,105,25 GROUPBOX "Gender",IDC_STATIC,0,60,105,25 GROUPBOX "Alignment",IDC_STATIC,0,85,105,25 DEFPUSHBUTTON "Play",IDOK,0,110,55,14 PUSHBUTTON "Quit",IDCANCEL,55,110,50,14 END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 2 TEXTINCLUDE DISCARDABLE BEGIN "#include ""newres.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Bitmap // IDB_TILES BITMAP DISCARDABLE "..\\..\\wince\\tiles.bmp" IDB_MENU_SEL BITMAP DISCARDABLE "..\\..\\wince\\mnsel.bmp" IDB_MENU_UNSEL BITMAP DISCARDABLE "..\\..\\wince\\mnunsel.bmp" IDB_PETMARK BITMAP DISCARDABLE "..\\..\\wince\\petmark.bmp" IDB_MENU_SEL_COUNT BITMAP DISCARDABLE "..\\..\\wince\\mnselcnt.bmp" IDB_KEYPAD BITMAP DISCARDABLE "..\\..\\wince\\keypad.bmp" ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_NHTEXT, DIALOG BEGIN LEFTMARGIN, 5 RIGHTMARGIN, 76 TOPMARGIN, 7 END IDD_EXTCMD, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 82 TOPMARGIN, 7 BOTTOMMARGIN, 75 END IDD_PLAYER_SELECTOR, DIALOG BEGIN RIGHTMARGIN, 98 BOTTOMMARGIN, 117 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Data // IDC_WINHACK SHMENUBAR DISCARDABLE BEGIN IDC_WINHACK, 2, I_IMAGENONE, IDM_MAP_FIT_TO_SCREEN, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDM_MAP_FIT_TO_SCREEN, 0, NOMENU, I_IMAGENONE, ID_VIEW, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE, IDS_CAP_VIEW, 0, 1, END IDC_SPHONE_DIALOGBAR SHMENUBAR DISCARDABLE BEGIN IDC_SPHONE_DIALOGBAR, 2, I_IMAGENONE, IDOK, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDOK, 0, NOMENU, I_IMAGENONE, IDCANCEL, TBSTATE_ENABLED, TBSTYLE_AUTOSIZE, IDCANCEL, 0, NOMENU, END #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,4,2,0 PRODUCTVERSION 3,4,2,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x9L #else FILEFLAGS 0x8L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "Comments", "NetHack 3.4.3 for Smartphone 2002\0" VALUE "CompanyName", " \0" VALUE "FileDescription", "nethackm\0" VALUE "FileVersion", "3, 4, 3, 0\0" VALUE "InternalName", "nethackm\0" VALUE "LegalCopyright", "Copyright © 2003\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "nethackm.exe\0" VALUE "PrivateBuild", "031014\0" VALUE "ProductName", "NetHack For Smartphone\0" VALUE "ProductVersion", "3, 4, 3, 0\0" VALUE "SpecialBuild", "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END #endif // !_MAC ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_APP_TITLE "NetHack" IDC_WINHACK "NETHACK" END STRINGTABLE DISCARDABLE BEGIN IDM_MAP_FIT_TO_SCREEN "Entire Map" IDS_CAP_FILE "File" IDS_CAP_HELP "Help" IDS_CAP_MAP "Map" END STRINGTABLE DISCARDABLE BEGIN IDM_VIEW_KEYPAD "Show/Hide keypad." IDS_CAP_VIEW "Menu" END STRINGTABLE DISCARDABLE BEGIN IDOK "Done" IDCANCEL "Cancel" END STRINGTABLE DISCARDABLE BEGIN IDS_CAP_ENTIREMAP "Entire Map" IDS_CAP_NORMALMAP "Normal Map" IDM_HELP_MENU "Help Menu" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED nethack-3.4.3/sys/wince/winmain.c0100644000000000000000000000456307764735041015413 0ustar rootroot// winmain.cpp : Defines the entry point for the application. #include "winMS.h" #include #define MAX_CMDLINE_PARAM 255 extern int FDECL (main, (int,char **)); static TCHAR* _get_cmd_arg(TCHAR* pCmdLine); int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow) { int argc; char* argv[MAX_CMDLINE_PARAM]; size_t len; TCHAR* p; TCHAR wbuf[NHSTR_BUFSIZE]; char buf[NHSTR_BUFSIZE]; /* get command line parameters */ p = _get_cmd_arg( #if defined(WIN_CE_PS2xx) || defined(WIN32_PLATFORM_HPCPRO) lpCmdLine #else GetCommandLine() #endif ); for( argc = 1; p && argc0 ) { argv[argc] = _strdup( NH_W2A(p, buf, BUFSZ) ); } else { argv[argc] = ""; } p = _get_cmd_arg(NULL); } GetModuleFileName(NULL, wbuf, BUFSZ); argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ)); main(argc, argv); return 0; } TCHAR* _get_cmd_arg(TCHAR* pCmdLine) { static TCHAR* pArgs = NULL; TCHAR *pRetArg; BOOL bQuoted; if( !pCmdLine && !pArgs ) return NULL; if( !pArgs ) pArgs = pCmdLine; /* skip whitespace */ for(pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg)); if( !*pRetArg ) { pArgs = NULL; return NULL; } /* check for quote */ if( *pRetArg==TEXT('"') ) { bQuoted = TRUE; pRetArg = CharNext(pRetArg); pArgs = _tcschr(pRetArg, TEXT('"')); } else { /* skip to whitespace */ for(pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs)); } if( pArgs && *pArgs ) { TCHAR* p; p = pArgs; pArgs = CharNext(pArgs); *p = (TCHAR)0; } else { pArgs = NULL; } return pRetArg; } #ifndef STRNCMPI char lowc(c) /* force 'c' into lowercase */ char c; { return((char)(('A' <= c && c <= 'Z') ? (c | 040) : c)); } int strncmpi(s1, s2, n) /* case insensitive counted string comparison */ register const char *s1, *s2; register int n; /*(should probably be size_t, which is usually unsigned)*/ { /*{ aka strncasecmp }*/ register char t1, t2; while (n--) { if (!*s2) return (*s1 != 0); /* s1 >= s2 */ else if (!*s1) return -1; /* s1 < s2 */ t1 = lowc(*s1++); t2 = lowc(*s2++); if (t1 != t2) return (t1 > t2) ? 1 : -1; } return 0; /* s1 == s2 */ } #endif /* STRNCMPI */ nethack-3.4.3/sys/winnt/0040755000000000000000000000000007764735152013635 5ustar rootrootnethack-3.4.3/sys/winnt/Install.nt0100644000000000000000000004273107764735041015607 0ustar rootroot Copyright (c) NetHack Development Team 1990-2002 NetHack may be freely redistributed. See license for details. ============================================================== Instructions for compiling and installing NetHack 3.4 on a Windows 9x, NT, 2000, or XP system ============================================================== Last revision: $Date: 2003/10/14 01:31:25 $ Credit for the porting of NetHack to the Win32 Console Subsystem goes to the NT Porting Team started by Michael Allison. Credit for the Win32 Graphical version of NetHack (aka "NetHack for Windows" or NetHackW) goes to Alex Kompel who initially developed and contributed the port. The PC Windows porting team consisting of Michael Allison, David Cohrs, Alex Kompel, Dion Nicolaas, Yitzhak Sapir, and Janet Walz maintained the tty and graphical win32 versions of NetHack 3.4.3. You can build either the TTY version of NetHack or the Windows Graphical version. In either case you can use one of the following build environments: o A copy of Microsoft Visual C V6.0 SP3 or later. Things may work with an earlier version of the compiler, but the current code has not been tested with an earlier version. OR o A copy of Borland C 5.5.1 command line tools. Borland has made a version of its command line tools available for download after registration at: http://www.borland.com/bcppbuilder/freecompiler/ OR o A copy of MinGW 2.0. MinGW is a collection of header files and import libraries with which native Windows32 programs can be made; the MinGW 2.0 distribution contains the GNU Compiler Collection. You can download MinGW at http://www.mingw.org/ Earlier versions of MinGW will not allow you to build the Windows Graphical version. In addition to the makefiles that allow you to build NetHack from the command line, there is also a set of project files and a workspace file that allow you to build the Windows Graphical version from Microsoft Visual C's IDE (Integrated Development Environment.) FIRST STEP The first step in building either version of NetHack is to execute sys\winnt\nhsetup.bat. From the command prompt: cd sys\winnt nhsetup From a Windows explorer window: double-click on nhsetup.bat A "binary" directory will be created off the top of the NetHack source tree to house the completed build. A build subdirectory will also be created off the top of the NetHack source tree, and many files appropriate for a graphical build will be moved there. If you wish to build from the command line, proceed to "BUILDING FROM THE COMMAND LINE." If you wish to build using Visual C's IDE, proceed now to "BUILDING USING VISUAL C'S IDE." BUILDING FROM THE COMMAND LINE You can built two different versions of NetHack for Win32 from the command line: A tty port utilizing the Win32 Console I/O subsystem, Console NetHack; A Win32 native port built on the Windows API, Graphical NetHack or NetHackW. The executable for Console NetHack will be named NetHack.exe. The executable for Graphical NetHack will be named NetHackW.exe. You can opt to build both; they will be able to use the same datafiles, save files and bones files. I. Dispelling the Myths: Compiling NetHack for Win32 is not as easy as it sounds, nor as hard as it looks, however it will behoove you to read this entire section through before beginning the task. We have provided a Makefile for each of the following compilers: o Microsoft Visual C++ V6.0 SP3 or greater o Borland C 5.5.1 o MinGW 2.0 (with GCC 3.2) The Microsoft Visual C Makefile was created for use with MS NMAKE which is provided with the Microsoft compiler. The supplied Makefile may work with earlier versions of the Microsoft 32-bit compiler, but that has not been tested. The Borland C Makefile was created for use with Borland MAKE which is provided with the Borland compiler. The GCC Makefile was created for use with GNU Make version 3.79.1, which comes with the MinGW package. You may find it useful to obtain copies of lex (flex) and yacc (bison, or byacc). While not strictly necessary to compile nethack, they are required should you desire to make any changes to the level and dungeon compilers. II. To compile your copy of NetHack on a Windows NT/2000/XP machine: Setting Up 1. It almost goes without saying that you should make sure that your tools are set up and running correctly. That includes ensuring that all the necessary environment variables for the compiler environment are set correctly. (Examples: For the Microsoft compiler by executing vcvars32.bat, which is probably in the bin directory of your compilers directory tree. For the Borland Makefile, you can simply invoke the Make utility from the Makefile's directory (For the standard Borland compiler installation you can just use the explicit path "c:\borland\bcc55\bin\make /f Makefile.bcc". For the GCC Makefile, add \bin to your path, where is your MinGW root directory.) 2. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, sys\share, sys\winnt, util, and binary (The "binary" directory was created by nhsetup.bat earlier if you followed the steps appropriately). For Console NetHack you need win\tty in addition to these; for Graphical NetHack you need win\win32 in addition to these. Other subdirectories may also be included in your distribution, but they are not necessary for building the TTY version for the Win32 console subsystem. You can delete them to save space. Required Directories for a Win32 Console NetHack: top | ----------------------------------------------------/ /----- | | | | | | | | util dat doc include src sys win binary | | ------ ----- | | | share winnt tty Required Directories for a Win32 Graphical NetHack: top | ----------------------------------------------------/ /----- | | | | | | | | util dat doc include src sys win binary | | ------ ----- | | | share winnt win32 Check the file "Files" in your top level directory for an exact listing of what file is in which directory. In order for the Makefiles to work, all the source files must be in the proper locations. If you downloaded or ftp'd the sources from a UNIX system, the lines will probably end in UNIX-style newlines, instead of the carriage return and line feed pairs used by Windows. Some programs have trouble with them, so you may need to convert them. The compiler should not have any problems with them however. 3. Now go to the include subdirectory to check a couple of the header files there. Things *should* work as they are, but since you have probably set up your system in some sort of custom configuration it doesn't hurt to check out the following: First check config.h according to the comments to match your system and desired set of features. Mostly you need to check section 4 and 5. You may include all or as few of the special game features as you wish (they are located last in the file). 4. Edit your Makefile. For building Console NetHack, ensure that GRAPHICAL is set to "N", or commented out. For building Graphical NetHack, set GRAPHICAL to "Y". Optional step: If you elected not to use the high-quality BSD random number routines by commenting out RANDOM in ntconf.h, comment out (or set equal to nothing) the RANDOM macro in your Makefile. If you are recompiling after patching your sources, or if you got your files from somewhere other than the official distribution, "touch makedefs.c" to ensure that certain files (onames.h and pm.h) are remade, lest potentially troublesome timestamps fool your make (or nmake) utility. Compiling 5. Now that everything is set up, change your current directory to src. For Microsoft compiler: nmake install For Borland compiler: make /f Makefile.bcc install For GCC: mingw32-make -f Makefile.gcc install If you get any errors along the way then something has not been set up correctly. The time it takes to compile depends on your particular machine of course, but you should be able to go for lunch and return to find everything finished. The less memory, and slower your machine, the longer the lunch you may take. :-) In any case, it is likely that the command prompt window where you are doing the compiling will be occupied for a while. If all goes well, you will get an NetHack executable. Notes: 1. To install an update of NetHack after changing something, change your current directory to src and issue the appropriate command for your compiler: For Microsoft compiler: nmake For Borland compiler: make /f Makefile.bcc For GCC: mingw32-make -f Makefile.gcc If you add, delete, or reorder monsters or objects, or you change the format of saved level files, delete any save and bones files. (Trying to use such files sometimes produces amusing confusions on the game's part, but usually crashes.) If you made changes to any of the level compiler software, you may have to delete dgn_flex.c, dgn_yacc.c, lev_flex.c, and lev_yacc.c from the util directory to ensure that they are remade. 2. The executable produced by the TTY build is a 32-bit, flat-address space, non-overlayed .exe file, which should run on any true Win32 environment with console I/O support. The executable built by the graphical built is a 32-bit, flat-address space, non-overlayed .exe file, which should run on any true Win32 graphical environment. To run NetHack, proceed to RUNNING NETHACK. BUILDING USING VISUAL C'S IDE Only the Win32 native port built on the Windows API, or Graphical NetHack, can be built using the Visual C IDE. I. Dispelling the Myths: Compiling NetHack using the Visual C IDE is straightforward, as long as you have your compiler and tools correctly installed. It is again assumed that you already changed your directory to sys\winnt and executed: nhsetup as described at the top of this document. If you didn't, you must go back and do so before proceeding. II. To compile your copy of NetHack for Windows on a Windows NT/2000/XP machine using the Visual C IDE: Setting Up 1. It almost goes without saying that you should make sure that your tools are set up and running correctly. (For the Microsoft Visual C IDE it should correctly fire up when you choose it in your Start | Programs menus.) 2. Make sure all the NetHack files are in the appropriate directory structure. You should have a main directory with subdirectories dat, doc, include, src, sys\share, sys\winnt, util, win\win32, and at this point you should also have a build directory and a binary directory (both created by nhsetup.bat executed from sys\winnt earlier.) Other subdirectories may also be included in your distribution, but they are not necessary for building the graphical version of NetHack (you can delete them to save space if you wish.) Required Directories for building Graphical NetHack with the Visual C IDE: top | -----------------------------------------/ /--------------- | | | | | | | | | util dat doc include src sys win build binary | | ------ ----- | | | share winnt win32 Those last two (build and binary) are created during the building process. They are not disributed as part of the NetHack source distribution. nhsetup.bat creates the build directory and moves a few files into it, including the Visual C project files. The "binary" directory will house everything you need to play the game after building is complete. Check the file "Files" in your top level directory for an exact listing of what file is in which directory. In order for the build process to work, all the source files must be in the proper locations. Remember that nhsetup.bat moves/copies many files around to their intended locations for building NetHack. If you downloaded or ftp'd the sources from a UNIX system, the lines will probably end in UNIX-style newlines, instead of the carriage return and line feed pairs used by Windows. Visual C project files and workspace files (dsp and dsw files) in particular need to have their lines end in carriage-return-line-feed or they won't work properly. 3. Ready your tool. Note: It's possible to build a graphical version using the Makefile, as explained above. However, the IDE build has full game functionality and is the officially released build. Start the Visual C IDE. In the Visual C IDE menus, choose: File | Open Workspace 4. Set up for the build. In the Visual C "Open Workspace" dialog box, navigate to the top of your NetHack source directory. In there, highlight "nethack.dsw" and click on Open. Once the workspace has been opened, you should see the following list in the Visual C selection window: + dgncomp files + dgnstuff files + dlb_main files + levcomp files + levstuff files + makedefs files + nethackw files + recover files + tile2bmp files + tilemap files + uudecode files On the Visual C menus, choose: Project | Set Active Project | NetHackW On the Visual C menus again, choose either: Build | Set Active Configuration | NetHackW - Win32 Release or Build | Set Active Configuration | NetHackW - Win32 Debug The first will create the Release build of NetHackW which does not contain all the debugging information and is smaller, and runs quicker. The second will create the Debug build of NetHackW and will spend a lot of time writing debug information to the disk as the game is played. Unless you are debugging or enhancing NetHack for Windows, choose the Release build. Building 5. Start your build. On the Visual C menus once again, choose: Build | Build NetHackW.exe This starts the build. It is likely that the IDE message window where you are doing the compiling will be occupied for a while. 6. If all has gone well to this point, you should now have a NetHack executable called NetHackW.exe in the "binary" directory, along with all the support files that it needs. RUNNING NETHACK I. Checking the installation: Make sure all of the support files -- Guidebook.txt, license, Defaults.nh, NetHack.exe or NetHackW.exe, nhdat, and recover.exe -- were copied to the game directory. If not, move them there yourself. Edit Defaults.nh to reflect your particular setup and personal preferences, by following the comments. As with all releases since 3.2.1, HACKDIR defaults to the same directory as that where the NetHack.exe or NetHackW.exe executable resides. You only need to set HACKDIR in defaults.nh if, for some reason, you wish to override that (be careful). II. Executing the game 1. Running from the command prompt: If you add the directory containing the NetHack executable to your PATH, you can just type "nethack" or "nethack -umike" or "nethackw" or "nethackw -umike" to start it up. Alternatively, you can explicitly invoke it with a command such as "c:\nethack\binary\nethack.exe" or "c:\nethack\binary\nethackw.exe" (specifying whatever drive and directory your NetHack executable resides in) each time. 2. Running from a Windows shortcut. If you will be running it by launching it from a shortcut, just use the following information when setting up the shortcut. Description : NetHack 3.4.3 Console version Command Line : C:\NETHACK\BINARY\NETHACK.EXE Description : NetHack 3.4.3 Graphical Interface Command Line : C:\NETHACK\BINARY\NETHACKW.EXE (changing the directory to the appropriate one of course) III. Play NetHack. If it works, you're done! PROBLEMS If you discover a bug and wish to report it, or if you have comments or suggestions we recommend using our "Contact Us" web page at: http://www.nethack.org/common/contact.html If you don't have access to the web, or you want to send us a patch to the NetHack source code feel free to drop us a line c/o: DevTeam (at) nethack.org Happy NetHacking! nethack-3.4.3/sys/winnt/Makefile.bcc0100644000000000000000000013024707764735041016024 0ustar rootroot# SCCS Id: @(#)Makefile.bcc 3.4 $Date: 2003/11/16 04:50:56 $ # Copyright (c) NetHack PC Development Team 1993-2003 # # # IMPORTANT NOTE: This Makefile has not been tested for 3.4.3. # # # NetHack 3.4.x Makefile for Borland C++ V5.5.1 and above and Borland's MAKE # # Win32 Compilers Tested: # - Borland C++ 5.5.1 for Win32 # # If you don't have this compiler, you can get it at: # http://www.borland.com/bcppbuilder/freecompiler/ # # This makefile is set up to assume the directories are extracted at the # root, but this can be changed by modifying the bccroot and related # variables. # # This is used for building two versions of NetHack: # A tty port utilizing the Win32 Console I/O subsystem, Console # NetHack; # A Win32 native port built on the Windows API, Graphical NetHack or # NetHackW. # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc (such as bison) # .l lex (such as flex) # # # If you have any questions read the sys/winnt/Install.nt file included # with the distribution. # # -- # Yitzhak Sapir #============================================================================== # Do not delete the following 3 lines. # TARGETOS=BOTH APPVER=4.0 bccbin = $(MAKEDIR) bccroot = $(MAKEDIR)\.. bccinc = $(bccroot)\include bcclib = $(bccroot)\lib !IFNDEF APPVER APPVER = 4.0 !ENDIF # Graphical interface # Set to Y for a graphical version # Set to anything else (or undefine) for a tty version #GRAPHICAL = Y # Debug # Set to Y for Debug support (to produce full map files, listing files, and debug information) # Set to anything else (or undefine) for a "release" version DEBUG = Y !IF "$(APPVER)" == "4.0" MAKE_WINVER = 0x0400 !ELSEIF "$(APPVER)" == "5.0" MAKE_WINVER = 0x0500 !ENDIF cc = $(bccbin)\bcc32 rc = $(bccbin)\brc32 link = $(bccbin)\ilink32 implib = $(bccbin)\tlib cflags = -c -D_X86_=1 -DWINVER=$(MAKE_WINVER) -q -I$(bccinc) -w-pia -w-rch -w-csu -w-par -w-aus cdebug = -y -v -O2 cvarsmt = -DWIN32 -D_WIN32 -D_MT lflags = !IF "$(DEBUG)" == "Y" linkdebug = /v /m /s cdebug = -v -y -Q !ELSE linkdebug = /C /Gn cdebug = !ENDIF startobj = $(bcclib)\c0x32.obj !IF "$(GRAPHICAL)" == "Y" verlflags = /Gn /Gz /q -L$(bcclib) /c /Tpe /V$(APPVER) startobjg = $(bcclib)\c0w32.obj !ELSE verlflags = /Gn /Gz /q -L$(bcclib) /c /ap /Tpe /V$(APPVER) startobjg = $(startobj) !ENDIF libsmt = $(bcclib)\cw32mt.lib $(bcclib)\import32.lib # # Set the gamedir according to your preference. # It must be present prior to compilation. !IF "$(GRAPHICAL)" == "Y" GAME = NetHackW # Game Name !ELSE GAME = NetHack # Game Name !ENDIF GAMEDIR = ..\binary # Game directory # # Source directories. Makedefs hardcodes these, don't change them. # INCL = ..\include # NetHack include files DAT = ..\dat # NetHack data files DOC = ..\doc # NetHack documentation files UTIL = ..\util # Utility source SRC = ..\src # Main source SSYS = ..\sys\share # Shared system files NTSYS = ..\sys\winnt # NT Win32 specific files TTY = ..\win\tty # window port files (tty) WIN32 = ..\win\win32 # window port files (Win32) WSHR = ..\win\share # Tile support files # # Object directory. # OBJ = o # #========================================== # Exe File Info. #========================================== # Yacc/Lex ... if you got 'em. # # If you have yacc and lex programs (or work-alike such as bison # and flex), uncomment the upper two macros. # #DO_YACC = YACC_ACT #DO_LEX = LEX_ACT !IFNDEF DO_YACC DO_YACC = YACC_MSG !ENDIF !IFNDEF DO_LEX DO_LEX = LEX_MSG !ENDIF # Wilbur Streett's Win32 ports of GNU bison and flex are available at: # http://www.monmouth.com/~wstreett/lex-yacc/lex-yacc.html # # To use them, download the executables and templates (bison.simple, # bison.hairy) to some directory, and set the environment variables # BISON_SIMPLE and BISON_HAIRY, and your path to point to this # directory. # # For example, if you placed them in C:\BIN, you should set: # C:> SET BISON_SIMPLE=C:\BIN\BISON.SIMPLE # C:> SET BISON_HAIRY=C:\BIN\BISON.HAIRY # # Also, make sure your path points to the bison/flex directories. # # The following settings are configured for Wilbur Streett's ports. # - Specify your yacc and lex programs (or work-alikes) here. YACC = bison -y #YACC = byacc #YACC = yacc #LEX = lex LEX = flex # # - Specify your flex skeleton file (if needed). # FLEXSKEL = #FLEXSKEL = -S../tools/flex.ske #YTABC = y.tab.c #YTABH = y.tab.h YTABC = y_tab.c YTABH = y_tab.h LEXYYC = lex.yy.c # # Optional high-quality BSD random number generation routines # (see pcconf.h). Set to nothing if not used. # RANDOM = $(OBJ)\random.o #RANDOM = # # Compiler and Linker flags # PRECOMPHEAD = N # set to Y if you want to use precomp. headers #=============================================== #======= End of Modification Section =========== #=============================================== ################################################ # # # Nothing below here should have to be changed.# # # ################################################ !IF "$(GRAPHICAL)" == "Y" WINPORT = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \ $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \ $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \ $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o WINPHDR = $(WIN32)\mhaskyn.h $(WIN32)\mhdlg.h $(WIN32)\mhfont.h \ $(WIN32)\mhinput.h $(WIN32)\mhmain.h $(WIN32)\mhmap.h $(WIN32)\mhmenu.h \ $(WIN32)\mhmsg.h $(WIN32)\mhmsgwnd.h $(WIN32)\mhrip.h $(WIN32)\mhstatus.h \ $(WIN32)\mhtext.h $(WIN32)\resource.h $(WIN32)\winMS.h WINDLLS = WINPFLAG= -DTILES -DMSWIN_GRAPHICS NHRES = $(O)winhack.res WINPINC = -I$(WIN32) !ELSE WINPORT = $(O)nttty.o WINPHDR = WINDLLS = $(GAMEDIR)\nhdefkey.dll $(GAMEDIR)\nh340key.dll $(GAMEDIR)\nhraykey.dll WINPFLAG= -DWIN32CON NHRES = $(O)console.res WINPINC = !ENDIF TILEUTIL16 = $(UTIL)\tile2bmp.exe TILEBMP16 = $(SRC)\tiles.bmp TILEUTIL32 = $(UTIL)\til2bm32.exe TILEBMP32 = $(SRC)\tiles32.bmp SOUND = $(OBJ)\ntsound.o #SOUND = # To store all the level files, # help files, etc. in a single library file. # USE_DLB = Y is left uncommented USE_DLB = Y ! IF ("$(USE_DLB)"=="Y") DLBFLG = -DDLB ! ELSE DLBFLG = ! ENDIF #========================================== # Setting up the compiler and linker # macros. All builds include the base ones. #========================================== CFLAGSBASE = -c $(cflags) $(cvarsmt) -I$(INCL) $(WINPINC) -q $(cdebug) -v LFLAGSBASE = $(linkdebug) $(verlflags) -L$(bcclib) -v #========================================== # Util builds #========================================== CFLAGSU = $(CFLAGSBASE) $(WINPFLAG) LFLAGSU = $(LFLAGSBASE) #========================================== # - Game build #========================================== LFLAGSBASE = $(linkdebug) $(conflags) CFLAGS = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG) NHLFLAGS1 = /Gn /v /m /s /Gz /q /c lflags = $(LFLAGSBASE) $(NHLFLAGS1) GAMEFILE = $(FDIR)\$(GAME).exe # whole thing ! IF ("$(USE_DLB)"=="Y") DLB = nhdat ! ELSE DLB = ! ENDIF #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .til .uu .c .y .l #========================================== # Rules for files in src #========================================== .c{$(OBJ)}.o: @$(cc) $(CFLAGS) -o$@ $< {$(SRC)}.c{$(OBJ)}.o: @$(cc) $(CFLAGS) -o$@ $< #========================================== # Rules for files in sys\share #========================================== {$(SSYS)}.c{$(OBJ)}.o: @$(cc) $(CFLAGS) -o$@ $< #========================================== # Rules for files in sys\winnt #========================================== {$(NTSYS)}.c{$(OBJ)}.o: @$(cc) $(CFLAGS) -o$@ $< {$(NTSYS)}.h{$(INCL)}.h: @copy $< $@ #========================================== # Rules for files in util #========================================== {$(UTIL)}.c{$(OBJ)}.o: @$(cc) $(CFLAGSU) -o$@ $< #========================================== # Rules for files in win\share #========================================== {$(WSHR)}.c{$(OBJ)}.o: @$(cc) $(CFLAGS) -o$@ $< {$(WSHR)}.h{$(INCL)}.h: @copy $< $@ #{$(WSHR)}.txt{$(DAT)}.txt: # @copy $< $@ #========================================== # Rules for files in win\tty #========================================== {$(TTY)}.c{$(OBJ)}.o: @$(cc) $(CFLAGS) -o$@ $< #========================================== # Rules for files in win\win32 #========================================== {$(WIN32)}.c{$(OBJ)}.o: @$(cc) $(CFLAGS) -o$@ $< #========================================== #================ MACROS ================== #========================================== # This section creates shorthand macros for many objects # referenced later on in the Makefile. # DEFFILE = $(NTSYS)\$(GAME).def # # Shorten up the location for some files # O = $(OBJ)^\ U = $(UTIL)^\ # # Utility Objects. # MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS = $(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o \ $(O)monst.o $(O)objects.o $(O)panic.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o RECOVOBJS = $(O)recover.o TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt # # These are not invoked during a normal game build in 3.4 # TEXT_IO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o # # Object files for the game itself. # VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o VOBJ04 = $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o VOBJ05 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)invent.o $(O)light.o $(O)lock.o VOBJ10 = $(O)mail.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o VOBJ11 = $(O)mhitm.o $(O)mhitu.o $(O)minion.o $(O)mklev.o VOBJ12 = $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o $(O)mkroom.o VOBJ13 = $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o VOBJ14 = $(O)monstr.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o VOBJ15 = $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o VOBJ16 = $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o VOBJ17 = $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o VOBJ18 = $(O)quest.o $(O)questpgr.o $(RANDOM) $(O)read.o VOBJ19 = $(O)rect.o $(O)region.o $(O)restore.o $(O)rip.o VOBJ20 = $(O)rnd.o $(O)role.o $(O)rumors.o $(O)save.o VOBJ21 = $(O)shk.o $(O)shknam.o $(O)sit.o $(O)sounds.o VOBJ22 = $(O)sp_lev.o $(O)spell.o $(O)steal.o $(O)steed.o VOBJ23 = $(O)teleport.o $(O)timeout.o $(O)topten.o $(O)track.o VOBJ24 = $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)vault.o VOBJ25 = $(O)vis_tab.o $(O)vision.o $(O)weapon.o $(O)were.o VOBJ26 = $(O)wield.o $(O)windows.o $(O)wizard.o $(O)worm.o VOBJ27 = $(O)worn.o $(O)write.o $(O)zap.o DLBOBJ = $(O)dlb.o TTYOBJ = $(O)topl.o $(O)getline.o $(O)wintty.o SOBJ = $(O)winnt.o $(O)pcsys.o $(O)pcunix.o \ $(SOUND) $(O)pcmain.o $(O)mapimail.o $(O)nhlan.o OBJS = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \ $(VOBJ26) $(VOBJ27) TILOBJ = $(WINPORT) VVOBJ = $(O)version.o ALLOBJ = $(TILOBJ) $(SOBJ) $(DLBOBJ) $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ) !IF "$(GRAPHICAL)" == "Y" OPTIONS_FILE = $(DAT)\guioptions !ELSE OPTIONS_FILE = $(DAT)\ttyoptions !ENDIF #========================================== # Header file macros #========================================== CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \ $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \ $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \ $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \ $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \ $(INCL)\ntconf.h $(INCL)\nhlan.h HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \ $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \ $(INCL)\permonst.h $(INCL)\monattk.h \ $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \ $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \ $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \ $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \ $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \ $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \ $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \ $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \ $(INCL)\wintty.h $(INCL)\trampoli.h LEV_H = $(INCL)\lev.h DGN_FILE_H = $(INCL)\dgn_file.h LEV_COMP_H = $(INCL)\lev_comp.h SP_LEV_H = $(INCL)\sp_lev.h TILE_H = ..\win\share\tile.h #========================================== # Miscellaneous #========================================== DATABASE = $(DAT)\data.base # # The name of the game. # GAMEFILE = $(GAMEDIR)\$(GAME).exe #========================================== #=============== TARGETS ================== #========================================== # # The default make target (so just typing 'nmake' is useful). # default : $(GAMEFILE) # # The main target. # $(GAME): $(O)obj.tag $(O)utility.tag graphicschk $(GAMEFILE) @echo $(GAME) is up to date. # # Everything # all : install install: graphicschk $(GAME) $(O)install.tag @echo Done. $(O)install.tag: $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(O)sp_lev.tag $(DLB) ! IF ("$(USE_DLB)"=="Y") copy nhdat $(GAMEDIR) copy $(DAT)\license $(GAMEDIR) copy $(DAT)\opthelp $(GAMEDIR) ! ELSE copy $(DAT)\*. $(GAMEDIR) copy $(DAT)\*.dat $(GAMEDIR) copy $(DAT)\*.lev $(GAMEDIR) if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile ! ENDIF if exist $(DOC)\guidebook.txt copy $(DOC)\guidebook.txt $(GAMEDIR)\Guidebook.txt if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt @if exist $(SRC)\$(GAME).PDB copy $(SRC)\$(GAME).pdb $(GAMEDIR)\$(GAME).pdb @if exist $(GAMEDIR)\$(GAME).PDB echo NOTE: You may want to remove $(GAMEDIR)\$(GAME).pdb to conserve space -copy $(NTSYS)\defaults.nh $(GAMEDIR)\defaults.nh echo install done > $@ # copy $(NTSYS)\winnt.hlp $(GAMEDIR) recover: $(U)recover.exe if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR) if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt $(O)sp_lev.tag: $(O)utility.tag $(DAT)\bigroom.des $(DAT)\castle.des \ $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des \ $(DAT)\medusa.des $(DAT)\oracle.des $(DAT)\tower.des \ $(DAT)\yendor.des $(DAT)\arch.des $(DAT)\barb.des \ $(DAT)\caveman.des $(DAT)\healer.des $(DAT)\knight.des \ $(DAT)\monk.des $(DAT)\priest.des $(DAT)\ranger.des \ $(DAT)\rogue.des $(DAT)\samurai.des $(DAT)\sokoban.des \ $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des cd $(DAT) $(U)lev_comp bigroom.des $(U)lev_comp castle.des $(U)lev_comp endgame.des $(U)lev_comp gehennom.des $(U)lev_comp knox.des $(U)lev_comp mines.des $(U)lev_comp medusa.des $(U)lev_comp oracle.des $(U)lev_comp sokoban.des $(U)lev_comp tower.des $(U)lev_comp yendor.des $(U)lev_comp arch.des $(U)lev_comp barb.des $(U)lev_comp caveman.des $(U)lev_comp healer.des $(U)lev_comp knight.des $(U)lev_comp monk.des $(U)lev_comp priest.des $(U)lev_comp ranger.des $(U)lev_comp rogue.des $(U)lev_comp samurai.des $(U)lev_comp tourist.des $(U)lev_comp valkyrie.des $(U)lev_comp wizard.des cd $(SRC) echo sp_levs done > $(O)sp_lev.tag $(O)utility.tag: $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \ $(SRC)\monstr.c $(SRC)\vis_tab.c \ $(U)lev_comp.exe $(INCL)\vis_tab.h \ $(U)dgn_comp.exe $(TILEUTIL16) @echo utilities made >$@ @echo utilities made. tileutil: $(U)gif2txt.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. !IF "$(GRAPHICAL)"=="Y" $(NHRES): $(TILEBMP16) $(WIN32)\winhack.rc $(WIN32)\mnsel.bmp \ $(WIN32)\mnselcnt.bmp $(WIN32)\mnunsel.bmp \ $(WIN32)\petmark.bmp $(WIN32)\NetHack.ico $(WIN32)\rip.bmp \ $(WIN32)\splash.bmp @$(rc) -r -fo$@ -i$(WIN32) -i$(bccinc) -dNDEBUG $(WIN32)\winhack.rc !ELSE $(NHRES): $(NTSYS)\console.rc $(NTSYS)\NetHack.ico @$(rc) -r -fo$@ -i$(NTSYS) -i$(bccinc) -dNDEBUG $(NTSYS)\console.rc !ENDIF #========================================== # The main target. #========================================== $(SRC)\uuid.lib: $(bcclib)\uuid.lib @copy $(bcclib)\uuid.lib $@ $(GAMEFILE) : $(ALLOBJ) $(NHRES) $(SRC)\uuid.lib $(O)gamedir.tag $(WINDLLS) @echo Linking.... @$(link) $(lflags) $(startobjg) $(ALLOBJ), $@, $(GAME).map,$(libsmt),,$(NHRES) @if exist $(O)install.tag del $(O)install.tag @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak $(O)gamedir.tag: @if not exist $(GAMEDIR)\*.* echo creating directory $(GAMEDIR) @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo directory created > $@ $(GAME)_.ico : $(NTSYS)\$(GAME).ico @copy $(NTSYS)\$(GAME).ico $@ #========================================== # Create directory for holding object files #========================================== $(O)obj.tag: @if not exist $(O)*.* mkdir $(OBJ) @echo directory $(OBJ) created >$@ #========================================== # Notify of any CL environment variables # in effect since they change the compiler # options. #========================================== graphicschk: ! IF "$(GRAPHICAL)"=="Y" @echo ---- @echo NOTE: This build will include tile support. @echo ---- ! ENDIF @echo graphicschk > graphicschk $(GAMEDIR)\nhdefkey.dll : $(O)nhdefkey.o @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo EXPORTS >nhdefkey.def @echo ProcessKeystroke >>nhdefkey.def @echo NHkbhit >>nhdefkey.def @echo CheckInput >>nhdefkey.def @echo SourceWhere >>nhdefkey.def @echo SourceAuthor >>nhdefkey.def @echo KeyHandlerName >>nhdefkey.def @echo Linking $@ $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c /aa /Tpd /V$(APPVER) -L$(bcclib) -v \ c0d32.obj $(O)nhdefkey.o, $@,nhdefkey.map,$(libsmt),nhdefkey.def $(GAMEDIR)\nh340key.dll : $(O)nh340key.o @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo EXPORTS >nh340key.def @echo ProcessKeystroke >>nh340key.def @echo NHkbhit >>nh340key.def @echo CheckInput >>nh340key.def @echo SourceWhere >>nh340key.def @echo SourceAuthor >>nh340key.def @echo KeyHandlerName >>nh340key.def @echo Linking $@ $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c /aa /Tpd /V$(APPVER) -L$(bcclib) -v \ c0d32.obj $(O)nh340key.o, $@,nh340key.map,$(libsmt),nh340key.def $(GAMEDIR)\nhraykey.dll : $(O)nhraykey.o @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo EXPORTS >nhraykey.def @echo ProcessKeystroke >>nhraykey.def @echo NHkbhit >>nhraykey.def @echo CheckInput >>nhraykey.def @echo SourceWhere >>nhraykey.def @echo SourceAuthor >>nhraykey.def @echo KeyHandlerName >>nhraykey.def @echo Linking $@ $(link) $(linkdebug) /Gn /Gz /q -L$(bcclib) /c /aa /Tpd /V$(APPVER) -L$(bcclib) -v \ c0d32.obj $(O)nhraykey.o, $@,nhraykey.map,$(libsmt),nhraykey.def # # Secondary Targets. # #========================================== # Makedefs Stuff #========================================== $(U)makedefs.exe: $(O)obj.tag $(MAKEOBJS) $(SRC)\uuid.lib @$(link) $(LFLAGSU) $(startobj) $(MAKEOBJS), $@,,$(libsmt) $(O)makedefs.o: $(CONFIG_H) $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\qtext.h $(INCL)\patchlevel.h \ $(U)makedefs.c @$(cc) $(CFLAGSU) -o$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe $(U)makedefs -v $(INCL)\onames.h : $(U)makedefs.exe $(U)makedefs -o $(INCL)\pm.h : $(U)makedefs.exe $(U)makedefs -p #$(INCL)\trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)\monstr.c: $(U)makedefs.exe $(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe $(U)makedefs -z $(SRC)\vis_tab.c: $(U)makedefs.exe $(U)makedefs -z #========================================== # uudecode utility and uuencoded targets #========================================== $(U)uudecode.exe: $(O)uudecode.o @$(link) $(LFLAGSU) $(startobj) $(O)uudecode.o, $@,,$(libsmt) $(O)uudecode.o: $(SSYS)\uudecode.c $(NTSYS)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu chdir $(NTSYS) ..\..\util\uudecode.exe nhico.uu chdir ..\..\src $(WIN32)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu chdir $(WIN32) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu chdir ..\..\src $(WIN32)\mnsel.bmp: $(U)uudecode.exe $(WIN32)\mnsel.uu chdir $(WIN32) ..\..\util\uudecode.exe mnsel.uu chdir ..\..\src $(WIN32)\mnselcnt.bmp: $(U)uudecode.exe $(WIN32)\mnselcnt.uu chdir $(WIN32) ..\..\util\uudecode.exe mnselcnt.uu chdir ..\..\src $(WIN32)\mnunsel.bmp: $(U)uudecode.exe $(WIN32)\mnunsel.uu chdir $(WIN32) ..\..\util\uudecode.exe mnunsel.uu chdir ..\..\src $(WIN32)\petmark.bmp: $(U)uudecode.exe $(WIN32)\petmark.uu chdir $(WIN32) ..\..\util\uudecode.exe petmark.uu chdir ..\..\src $(WIN32)\rip.bmp: $(U)uudecode.exe $(WIN32)\rip.uu chdir $(WIN32) ..\..\util\uudecode.exe rip.uu chdir ..\..\src $(WIN32)\splash.bmp: $(U)uudecode.exe $(WIN32)\splash.uu chdir $(WIN32) ..\..\util\uudecode.exe splash.uu chdir ..\..\src #========================================== # Level Compiler Stuff #========================================== LEVCFLAGS=$(cflags) -DWIN32 -D_WIN32 -D_MT -I..\include $(cdebug) -DDLB $(U)lev_comp.exe: $(SPLEVOBJS) $(SRC)\uuid.lib @echo Linking $@... @$(link) $(LFLAGSU) $(startobj) $(SPLEVOBJS), $@,,$(libsmt) $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c @$(cc) $(LEVCFLAGS) -o$@ $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c @$(cc) $(LEVCFLAGS) -D__IO_H -o$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) @$(cc) $(LEVCFLAGS) -o$@ $(U)lev_main.c $(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" chdir $(UTIL) $(YACC) -d lev_comp.y copy $(YTABC) lev_yacc.c copy $(YTABH) $(INCL)\lev_comp.h @del $(YTABC) @del $(YTABH) chdir $(SRC) ! ELSE @echo $(U)lev_comp.y has changed. @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC). @echo --- @echo For now, we will copy the prebuilt lev_yacc.c and @echo lev_comp.h from $(SSYS) into $(UTIL) and use them. @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul @echo /**/ >>$(U)lev_yacc.c @echo /**/ >>$(INCL)\lev_comp.h ! ENDIF $(U)lev_$(LEX).c: $(U)lev_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" chdir $(UTIL) $(LEX) $(FLEXSKEL) lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) chdir $(SRC) ! ELSE @echo $(U)lev_comp.l has changed. To update $@ run $(LEX). @echo --- @echo For now, we will copy the prebuilt lev_lex.c @echo from $(SSYS) into $(UTIL) and use it. @copy $(SSYS)\lev_lex.c $@ >nul @echo /**/ >>$@ ! ENDIF #========================================== # Dungeon Compiler Stuff #========================================== $(U)dgn_comp.exe: $(DGNCOMPOBJS) $(SRC)\uuid.lib @echo Linking $@... @$(link) $(LFLAGSU) $(startobj) $(DGNCOMPOBJS), $@,,$(libsmt) $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c @$(cc) $(LEVCFLAGS) -o$@ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_$(LEX).c @$(cc) $(LEVCFLAGS) -D__IO_H -o$@ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c @$(cc) $(LEVCFLAGS) -o$@ $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" chdir $(UTIL) $(YACC) -d dgn_comp.y copy $(YTABC) dgn_yacc.c copy $(YTABH) $(INCL)\dgn_comp.h @del $(YTABC) @del $(YTABH) chdir $(SRC) ! ELSE @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and @echo $(INCL)\dgn_comp.h run $(YACC). @echo --- @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them. @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul @echo /**/ >>$(U)dgn_yacc.c @echo /**/ >>$(INCL)\dgn_comp.h ! ENDIF $(U)dgn_$(LEX).c: $(U)dgn_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" chdir $(UTIL) $(LEX) $(FLEXSKEL) dgn_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) chdir $(SRC) ! ELSE @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX). @echo --- @echo For now, we will copy the prebuilt dgn_lex.c @echo from $(SSYS) into $(UTIL) and use it. @copy $(SSYS)\dgn_lex.c $@ >nul @echo /**/ >>$@ ! ENDIF #========================================== #=========== SECONDARY TARGETS ============ #========================================== #=========================================== # Header files NOT distributed in ..\include #=========================================== $(INCL)\win32api.h: $(NTSYS)\win32api.h copy $(NTSYS)\win32api.h $@ #========================================== # DLB utility and nhdat file creation #========================================== $(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o $(SRC)\uuid.lib @$(link) $(LFLAGSU) $(startobj) $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o, $@,,$(libsmt) $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h @$(cc) $(CFLAGS) -o$@ $(SRC)\dlb.c $(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h @$(cc) $(CFLAGS) -o$@ $(UTIL)\dlb_main.c $(DAT)\porthelp: $(NTSYS)\porthelp @copy $(NTSYS)\porthelp $@ >nul nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \ $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \ $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon $(DAT)\porthelp \ $(DAT)\license $(O)sp_lev.tag cd $(DAT) echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %N in (*.lev) do echo %N >>dlb.lst $(U)dlb_main cIf dlb.lst $(SRC)\nhdat cd $(SRC) #========================================== # Recover Utility #========================================== $(U)recover.exe: $(RECOVOBJS) $(SRC)\uuid.lib $(link) $(LFLAGSU) $(startobj) $(RECOVOBJS), $@,,$(libsmt) $(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)\win32api.h $(cc) $(CFLAGSU) -o$@ $(U)recover.c #========================================== # Tile Mapping #========================================== $(SRC)\tile.c: $(U)tilemap.exe @echo A new $@ has been created @$(U)tilemap $(U)tilemap.exe: $(O)tilemap.o $(SRC)\uuid.lib @$(link) $(LFLAGSU) $(startobj) $(O)tilemap.o, $@,,$(libsmt) $(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) @$(cc) $(CFLAGSU) -o$@ $(WSHR)\tilemap.c $(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) @$(cc) $(CFLAGS) /DTILETEXT -o$@ $(WSHR)\tilemap.c $(O)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\gifread.c $(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H) @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\ppmwrite.c $(O)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)\tiletext.c #========================================== # Optional Tile Utilities #========================================== $(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) $(SRC)\uuid.lib @echo Linking $@... @$(link) $(LFLAGSU) $(startobj) $(GIFREADERS) $(TEXT_IO), $@,,$(libsmt) $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) $(SRC)\uuid.lib @echo Linking $@... @$(link) $(LFLAGSU) $(startobj) $(PPMWRITERS) $(TEXT_IO), $@,,$(libsmt) !IF "$(GRAPHICAL)"=="Y" $(TILEBMP16): $(TILEUTIL16) $(TILEFILES) @echo Creating 16x16 binary tile files (this may take some time) @$(U)tile2bmp $(TILEBMP16) !ENDIF $(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) $(SRC)\uuid.lib @echo Linking $@... @$(link) $(LFLAGSU) $(startobj) $(O)tile2bmp.o $(TEXT_IO), $@,,$(libsmt) $(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h @$(cc) $(CFLAGS) -I$(WSHR) /DPACKED_FILE -o$@ $(WSHR)\tile2bmp.c #========================================== # Housekeeping #========================================== spotless: clean ! IF ("$(OBJ)"!="") -rmdir $(OBJ) /s /Q ! ENDIF if exist $(INCL)\date.h del $(INCL)\date.h if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(SRC)\tile.c del $(SRC)\tile.c if exist $(U)*.lnk del $(U)*.lnk if exist $(U)*.map del $(U)*.map if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\???-fil?.lev del $(DAT)\???-fil?.lev if exist $(DAT)\???-goal.lev del $(DAT)\???-goal.lev if exist $(DAT)\???-loca.lev del $(DAT)\???-loca.lev if exist $(DAT)\???-strt.lev del $(DAT)\???-strt.lev if exist $(DAT)\air.lev del $(DAT)\air.lev if exist $(DAT)\asmodeus.lev del $(DAT)\asmodeus.lev if exist $(DAT)\astral.lev del $(DAT)\astral.lev if exist $(DAT)\baalz.lev del $(DAT)\baalz.lev if exist $(DAT)\bigroom.lev del $(DAT)\bigroom.lev if exist $(DAT)\castle.lev del $(DAT)\castle.lev if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\dungeon del $(DAT)\dungeon if exist $(DAT)\dungeon.pdf del $(DAT)\dungeon.pdf if exist $(DAT)\earth.lev del $(DAT)\earth.lev if exist $(DAT)\fakewiz?.lev del $(DAT)\fakewiz?.lev if exist $(DAT)\fire.lev del $(DAT)\fire.lev if exist $(DAT)\juiblex.lev del $(DAT)\juiblex.lev if exist $(DAT)\knox.lev del $(DAT)\knox.lev if exist $(DAT)\medusa-?.lev del $(DAT)\medusa-?.lev if exist $(DAT)\mine*.lev del $(DAT)\mine*.lev if exist $(DAT)\options del $(DAT)\options if exist $(DAT)\ttyoptions del $(DAT)\ttyoptions if exist $(DAT)\guioptions del $(DAT)\guioptions if exist $(DAT)\oracle.lev del $(DAT)\oracle.lev if exist $(DAT)\oracles del $(DAT)\oracles if exist $(DAT)\orcus.lev del $(DAT)\orcus.lev if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\quest.dat del $(DAT)\quest.dat if exist $(DAT)\sanctum.lev del $(DAT)\sanctum.lev if exist $(DAT)\soko?-?.lev del $(DAT)\soko?-?.lev if exist $(DAT)\tower?.lev del $(DAT)\tower?.lev if exist $(DAT)\valley.lev del $(DAT)\valley.lev if exist $(DAT)\water.lev del $(DAT)\water.lev if exist $(DAT)\wizard?.lev del $(DAT)\wizard?.lev if exist $(O)sp_lev.tag del $(O)sp_lev.tag if exist $(SRC)\monstr.c del $(SRC)\monstr.c if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(U)recover.exe del $(U)recover.exe if exist nhdat. del nhdat. clean: if exist $(O)*.o del $(O)*.o if exist $(O)utility.tag del $(O)utility.tag if exist $(U)makedefs.exe del $(U)makedefs.exe if exist $(U)lev_comp.exe del $(U)lev_comp.exe if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe if exist $(SRC)\*.lnk del $(SRC)\*.lnk if exist $(SRC)\*.map del $(SRC)\*.map if exist $(TILEBMP16) del $(TILEBMP16) #=================================================================== # OTHER DEPENDENCIES #=================================================================== # # dat dependencies # $(DAT)\data: $(O)utility.tag $(DATABASE) $(U)makedefs -d $(DAT)\rumors: $(O)utility.tag $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(O)utility.tag $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(O)utility.tag $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(O)utility.tag $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgn_comp dungeon.pdf cd $(SRC) # # NT dependencies # $(O)nttty.o: $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c @$(cc) $(CFLAGS) -I$(WSHR) -o$@ $(NTSYS)\nttty.c $(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c @$(cc) $(CFLAGS) -o$@ $(NTSYS)\winnt.c $(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c @$(cc) $(CFLAGS) -o$@ $(NTSYS)\ntsound.c $(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c @$(cc) $(CFLAGS) -DMAPI_VERBOSE -o$@ $(NTSYS)\mapimail.c # # util dependencies # $(O)panic.o: $(U)panic.c $(CONFIG_H) @$(cc) $(CFLAGS) -o$@ $(U)panic.c # # The rest are stolen from sys/unix/Makefile.src, # with the following changes: # * ../include changed to $(INCL) # * slashes changed to back-slashes # * -c (which is included in CFLAGS) substituted # with -o$@ # * $(CC) changed to $(cc) # but otherwise untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h $(cc) $(CFLAGS) -o$@ ..\sys\atari\tos.c $(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\win32api.h $(cc) $(CFLAGS) -o$@ ..\sys\share\pcmain.c $(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ..\sys\share\pcsys.c $(O)pctty.o: ..\sys\share\pctty.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ..\sys\share\pctty.c $(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ..\sys\share\pcunix.c $(O)random.o: ..\sys\share\random.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ..\sys\share\random.c $(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h $(cc) $(CFLAGS) -o$@ ..\sys\share\ioctl.c $(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ..\sys\share\unixtty.c $(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h $(cc) $(CFLAGS) -o$@ ..\sys\unix\unixmain.c $(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ..\sys\unix\unixunix.c $(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h $(cc) $(CFLAGS) -o$@ ..\sys\be\bemain.c $(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h $(cc) $(CFLAGS) -o$@ ..\win\tty\getline.c $(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h $(cc) $(CFLAGS) -o$@ ..\win\tty\termcap.c $(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h $(cc) $(CFLAGS) -o$@ ..\win\tty\topl.c $(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(INCL)\tcap.h $(cc) $(CFLAGS) -o$@ ..\win\tty\wintty.c $(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ $(CONFIG_H) $(cc) $(CFLAGS) -o$@ ..\win\X11\Window.c $(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) $(cc) $(CFLAGS) -o$@ ..\win\X11\dialogs.c $(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h ..\win\X11\nh72icon \ ..\win\X11\nh56icon ..\win\X11\nh32icon $(cc) $(CFLAGS) -o$@ ..\win\X11\winX.c $(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ $(INCL)\winX.h $(INCL)\tile2x11.h $(cc) $(CFLAGS) -o$@ ..\win\X11\winmap.c $(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h $(cc) $(CFLAGS) -o$@ ..\win\X11\winmenu.c $(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h $(cc) $(CFLAGS) -o$@ ..\win\X11\winmesg.c $(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\winX.h $(cc) $(CFLAGS) -o$@ ..\win\X11\winmisc.c $(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h $(cc) $(CFLAGS) -o$@ ..\win\X11\winstat.c $(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h $(cc) $(CFLAGS) -o$@ ..\win\X11\wintext.c $(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h $(cc) $(CFLAGS) -o$@ ..\win\X11\winval.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) $(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \ ..\win\gnome\gnmain.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnaskstr.c $(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnbind.c $(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnglyph.c $(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \ ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \ $(INCL)\date.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmain.c $(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnsignal.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmap.c $(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnbind.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmenu.c $(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnmesg.c $(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnopts.c $(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \ ..\win\gnome\gnmain.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnplayer.c $(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \ ..\win\gnome\gnmain.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnsignal.c $(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \ ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \ ..\win\gnome\gnomeprv.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnstatus.c $(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \ ..\win\gnome\gn_rip.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gntext.c $(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h $(cc) $(CFLAGS) $(GNOMEINC) -c ..\win\gnome\gnyesno.c $(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(INCL)\wingem.h $(cc) $(CFLAGS) -o$@ ..\win\gem\wingem.c $(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \ $(INCL)\wintype.h $(INCL)\wingem.h $(cc) $(CFLAGS) -o$@ ..\win\gem\wingem1.c $(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h $(cc) $(CFLAGS) -o$@ ..\win\gem\load_img.c $(O)tile.o: tile.c $(HACK_H) $(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\qt_win.h \ $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \ $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_win.cpp $(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h $(CXX) $(CXXFLAGS) -c ..\win\Qt\qt_clust.cpp $(O)monstr.o: $(SRC)\monstr.c $(CONFIG_H) $(O)vis_tab.o: $(SRC)\vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) $(INCL)\edog.h $(O)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h $(O)attrib.o: attrib.c $(HACK_H) $(INCL)\artifact.h $(O)ball.o: ball.c $(HACK_H) $(O)bones.o: bones.c $(HACK_H) $(INCL)\lev.h $(O)botl.o: botl.c $(HACK_H) $(O)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h $(O)dbridge.o: dbridge.c $(HACK_H) $(O)decl.o: decl.c $(HACK_H) $(O)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h $(O)dig.o: dig.c $(HACK_H) $(INCL)\edog.h $(O)display.o: display.c $(HACK_H) $(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h $(O)do.o: do.c $(HACK_H) $(INCL)\lev.h $(O)do_name.o: do_name.c $(HACK_H) $(O)do_wear.o: do_wear.c $(HACK_H) $(O)dog.o: dog.c $(HACK_H) $(INCL)\edog.h $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h $(O)dokick.o: dokick.c $(HACK_H) $(INCL)\eshk.h $(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)\edog.h $(O)drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h $(O)engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h $(O)exper.o: exper.c $(HACK_H) $(O)explode.o: explode.c $(HACK_H) $(O)extralev.o: extralev.c $(HACK_H) $(O)files.o: files.c $(HACK_H) $(INCL)\dlb.h $(O)fountain.o: fountain.c $(HACK_H) $(O)hack.o: hack.c $(HACK_H) $(O)hacklib.o: hacklib.c $(HACK_H) $(O)invent.o: invent.c $(HACK_H) $(INCL)\artifact.h $(O)light.o: light.c $(HACK_H) $(INCL)\lev.h $(O)lock.o: lock.c $(HACK_H) $(O)mail.o: mail.c $(HACK_H) $(INCL)\mail.h $(O)makemon.o: makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \ $(INCL)\edog.h $(O)mapglyph.o: mapglyph.c $(HACK_H) $(O)mcastu.o: mcastu.c $(HACK_H) $(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h $(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h $(O)minion.o: minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h $(O)mklev.o: mklev.c $(HACK_H) $(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h $(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h $(O)mkobj.o: mkobj.c $(HACK_H) $(INCL)\artifact.h $(O)mkroom.o: mkroom.c $(HACK_H) $(O)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h $(O)mondata.o: mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h $(O)monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h $(O)monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \ $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \ $(INCL)\epri.h $(INCL)\color.h $(O)mplayer.o: mplayer.c $(HACK_H) $(O)mthrowu.o: mthrowu.c $(HACK_H) $(O)muse.o: muse.c $(HACK_H) $(INCL)\edog.h $(O)music.o: music.c $(HACK_H) #interp.c $(O)o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h $(O)objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h $(O)objnam.o: objnam.c $(HACK_H) $(O)options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \ $(HACK_H) $(INCL)\tcap.h $(O)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h $(O)pickup.o: pickup.c $(HACK_H) $(O)pline.o: pline.c $(HACK_H) $(INCL)\epri.h $(INCL)\edog.h $(O)polyself.o: polyself.c $(HACK_H) $(O)potion.o: potion.c $(HACK_H) $(O)pray.o: pray.c $(HACK_H) $(INCL)\epri.h $(O)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \ $(INCL)\epri.h $(INCL)\emin.h $(O)quest.o: quest.c $(HACK_H) $(INCL)\qtext.h $(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h $(O)read.o: read.c $(HACK_H) $(O)rect.o: rect.c $(HACK_H) $(O)region.o: region.c $(HACK_H) $(INCL)\lev.h $(O)restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h $(O)rip.o: rip.c $(HACK_H) $(O)rnd.o: rnd.c $(HACK_H) $(O)role.o: role.c $(HACK_H) $(O)rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h $(O)save.o: save.c $(HACK_H) $(INCL)\lev.h $(O)shk.o: shk.c $(HACK_H) $(INCL)\eshk.h $(O)shknam.o: shknam.c $(HACK_H) $(INCL)\eshk.h $(O)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h $(O)sounds.o: sounds.c $(HACK_H) $(INCL)\edog.h $(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h $(O)spell.o: spell.c $(HACK_H) $(O)steal.o: steal.c $(HACK_H) $(O)steed.o: steed.c $(HACK_H) $(O)teleport.o: teleport.c $(HACK_H) $(O)timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h $(O)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h $(O)track.o: track.c $(HACK_H) $(O)trap.o: trap.c $(HACK_H) $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(INCL)\vault.h $(O)version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h $(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) $(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h $(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h $(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h $(O)worn.o: worn.c $(HACK_H) $(O)write.o: write.c $(HACK_H) $(O)zap.o: zap.c $(HACK_H) # end of file nethack-3.4.3/sys/winnt/Makefile.gcc0100644000000000000000000013303107764735041016023 0ustar rootroot# SCCS Id: @(#)Makefile.gcc 3.4 $Date: 2003/11/16 04:50:57 $ # Copyright (c) NetHack PC Development Team 1993-2003 # # NetHack 3.4.x Makefile for MinGW # # Win32 Compilers Tested: # - MinGW 1.0 (gcc version 2.95.3-6) (Console NetHack only) # - MinGW 2.0 (gcc version 3.2) # # If you don't have this compiler, you can get it at: # http://www.mingw.org/ # # This is used for building two versions of NetHack: # A tty port utilizing the Win32 Console I/O subsystem, Console # NetHack; # A Win32 native port built on the Windows API, Graphical NetHack or # NetHackW. # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc (such as bison) # .l lex (such as flex) # # # If you have any questions read the sys/winnt/Install.nt file included # with the distribution. # # -- # Dion Nicolaas #============================================================================== # Graphical interface # Set to Y for a graphical version # Set to anything else (or undefine) for a tty version #GRAPHICAL = Y # Debug # Set to Y for Debug support (to produce debug information) # Set to anything else (or undefine) for a "release" version # You can set your debug options below. DEBUG = Y cc = gcc rc = windres link = gcc cflags = -mms-bitfields lflags = ifeq "$(DEBUG)" "Y" cdebug = -g linkdebug = -g else cdebug = linkdebug = endif # # Set the gamedir according to your preference. # If not present prior to compilation it gets created. ifeq "$(GRAPHICAL)" "Y" # Game Name GAME = NetHackW else # Game Name GAME = NetHack endif # Game directory GAMEDIR = ../binary # # Source directories. Makedefs hardcodes these, don't change them. # # NetHack include files INCL = ../include # NetHack data files DAT = ../dat # NetHack documentation files DOC = ../doc # Utility source UTIL = ../util # Main source SRC = ../src # Shared system files SSYS = ../sys/share # NT Win32 specific files NTSYS = ../sys/winnt # window port files (tty) TTY = ../win/tty # window port files (Win32) WIN32 = ../win/win32 # Tile support files WSHR = ../win/share # # Object directory. # OBJ = o # #========================================== # Exe File Info. #========================================== # Yacc/Lex ... if you got 'em. # # If you have yacc and lex programs (or work-alike such as bison # and flex), comment out the upper two macros and uncomment # the lower two. # DO_YACC = YACC_MSG DO_LEX = LEX_MSG #DO_YACC = YACC_ACT #DO_LEX = LEX_ACT # - Specify your yacc and lex programs (or work-alikes) here. #YACC = bison -y YACC = byacc #YACC = yacc #LEX = lex LEX = flex # # - Specify your flex skeleton file (if needed). # FLEXSKEL = #FLEXSKEL = -S../tools/flex.ske YTABC = y_tab.c YTABH = y_tab.h LEXYYC = lexyy.c # # Optional high-quality BSD random number generation routines # (see pcconf.h). Set to nothing if not used. # RANDOM = $(OBJ)/random.o #RANDOM = #=============================================== #======= End of Modification Section =========== #=============================================== ################################################ # # # Nothing below here should have to be changed.# # # ################################################ ifeq "$(GRAPHICAL)" "Y" WINPORT = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \ $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \ $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \ $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o WINPFLAG = -DTILES -DMSWIN_GRAPHICS -D_WIN32_IE=0x0400 NHRES = $(O)winres.o WINPINC = -I$(WIN32) WINPHDR = $(WIN32)/mhaskyn.h $(WIN32)/mhdlg.h $(WIN32)/mhfont.h \ $(WIN32)/mhinput.h $(WIN32)/mhmain.h $(WIN32)/mhmap.h \ $(WIN32)/mhmenu.h $(WIN32)/mhmsg.h $(WIN32)/mhmsgwnd.h \ $(WIN32)/mhrip.h $(WIN32)/mhstatus.h \ $(WIN32)/mhtext.h $(WIN32)/resource.h $(WIN32)/winMS.h WINPLIBS = -lcomctl32 -lwinmm else WINPORT = $(O)nttty.o WINPFLAG= -DWIN32CON WINPHDR = NHRES = $(O)console.o WINPINC = WINPLIBS = -lwinmm endif TILEUTIL16 = $(UTIL)/tile2bmp.exe TILEBMP16 = $(SRC)/tiles.bmp TILEUTIL32 = $(UTIL)/til2bm32.exe TILEBMP32 = $(SRC)/tiles32.bmp SOUND = $(OBJ)/ntsound.o #SOUND = # To store all the level files, # help files, etc. in a single library file. # USE_DLB = Y is left uncommented USE_DLB = Y ifeq "$(USE_DLB)" "Y" DLBFLG = -DDLB else DLBFLG = endif #========================================== # Setting up the compiler and linker # macros. All builds include the base ones. #========================================== CFLAGSBASE = -c $(cflags) -I$(INCL) $(WINPINC) $(cdebug) LFLAGSBASEC = $(linkdebug) LFLAGSBASEG = $(linkdebug) -mwindows #========================================== # Util builds #========================================== CFLAGSU = $(CFLAGSBASE) $(WINPFLAG) LFLAGSU = $(LFLAGSBASEC) #========================================== # - Game build #========================================== CFLAGS = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG) lflags = $(LFLAGSBASE) ifeq "$(GRAPHICAL)" "Y" lflags = $(LFLAGSBASEG) else lflags = $(LFLAGSBASEC) endif GAMEFILE = $(GAMEDIR)/$(GAME).exe # whole thing ifeq "$(USE_DLB)" "Y" DLB = nhdat else DLB = endif #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .til .uu .c .y .l #========================================== # Rules for files in src #========================================== $(OBJ)/%.o : /%.c $(cc) $(CFLAGS) -o$@ $< $(OBJ)/%.o : $(SRC)/%.c $(cc) $(CFLAGS) -o$@ $< #========================================== # Rules for files in sys/share #========================================== $(OBJ)/%.o : $(SSYS)/%.c $(cc) $(CFLAGS) -o$@ $< #========================================== # Rules for files in sys/winnt #========================================== $(OBJ)/%.o : $(NTSYS)/%.c $(cc) $(CFLAGS) -o$@ $< $(INCL)/%.h : $(NTSYS)/%.h @copy $< $@ #========================================== # Rules for files in util #========================================== $(OBJ)/%.o : $(UTIL)/%.c $(cc) $(CFLAGSU) -o$@ $< #========================================== # Rules for files in win/share #========================================== $(OBJ)/%.o : $(WSHR)/%.c $(cc) $(CFLAGS) -o$@ $< $(INCL)/%.h : $(WSHR)/%.h @copy $< $@ #{$(WSHR)}.txt{$(DAT)}.txt: # @copy $< $@ #========================================== # Rules for files in win/tty #========================================== $(OBJ)/%.o : $(TTY)/%.c $(cc) $(CFLAGS) -o$@ $< #========================================== # Rules for files in win/win32 #========================================== $(OBJ)/%.o : $(WIN32)/%.c $(cc) $(CFLAGS) -o$@ $< #========================================== #================ MACROS ================== #========================================== # This section creates shorthand macros for many objects # referenced later on in the Makefile. # DEFFILE = $(NTSYS)/$(GAME).def # # Shorten up the location for some files # O = $(OBJ)/ U = $(UTIL)/ # # Utility Objects. # MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS = $(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o \ $(O)monst.o $(O)objects.o $(O)panic.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o RECOVOBJS = $(O)recover.o TILEFILES = $(WSHR)/monsters.txt $(WSHR)/objects.txt $(WSHR)/other.txt # # These are not invoked during a normal game build in 3.4 # TEXT_IO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o TEXT_IO32 = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o GIFREADERS32 = $(O)gifrd32.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o # # Object files for the game itself. # VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o VOBJ04 = $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o VOBJ05 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)invent.o $(O)light.o $(O)lock.o VOBJ10 = $(O)mail.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o VOBJ11 = $(O)mhitm.o $(O)mhitu.o $(O)minion.o $(O)mklev.o VOBJ12 = $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o $(O)mkroom.o VOBJ13 = $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o VOBJ14 = $(O)monstr.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o VOBJ15 = $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o VOBJ16 = $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o VOBJ17 = $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o VOBJ18 = $(O)quest.o $(O)questpgr.o $(RANDOM) $(O)read.o VOBJ19 = $(O)rect.o $(O)region.o $(O)restore.o $(O)rip.o VOBJ20 = $(O)rnd.o $(O)role.o $(O)rumors.o $(O)save.o VOBJ21 = $(O)shk.o $(O)shknam.o $(O)sit.o $(O)sounds.o VOBJ22 = $(O)sp_lev.o $(O)spell.o $(O)steal.o $(O)steed.o VOBJ23 = $(O)teleport.o $(O)timeout.o $(O)topten.o $(O)track.o VOBJ24 = $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)vault.o VOBJ25 = $(O)vis_tab.o $(O)vision.o $(O)weapon.o $(O)were.o VOBJ26 = $(O)wield.o $(O)windows.o $(O)wizard.o $(O)worm.o VOBJ27 = $(O)worn.o $(O)write.o $(O)zap.o DLBOBJ = $(O)dlb.o TTYOBJ = $(O)topl.o $(O)getline.o $(O)wintty.o SOBJ = $(O)winnt.o $(O)pcsys.o $(O)pcunix.o \ $(SOUND) $(O)pcmain.o $(O)mapimail.o $(O)nhlan.o OBJS = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \ $(VOBJ26) $(VOBJ27) WINPOBJ = $(WINPORT) VVOBJ = $(O)version.o ALLOBJ = $(WINPOBJ) $(SOBJ) $(DLBOBJ) $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ) ifeq "$(GRAPHICAL)" "Y" OPTIONS_FILE = $(DAT)/guioptions else OPTIONS_FILE = $(DAT)/ttyoptions endif #========================================== # Header file macros #========================================== CONFIG_H = $(INCL)/config.h $(INCL)/config1.h $(INCL)/tradstdc.h \ $(INCL)/global.h $(INCL)/coord.h $(INCL)/vmsconf.h \ $(INCL)/system.h $(INCL)/unixconf.h $(INCL)/os2conf.h \ $(INCL)/micro.h $(INCL)/pcconf.h $(INCL)/tosconf.h \ $(INCL)/amiconf.h $(INCL)/macconf.h $(INCL)/beconf.h \ $(INCL)/ntconf.h $(INCL)/nhlan.h HACK_H = $(INCL)/hack.h $(CONFIG_H) $(INCL)/align.h \ $(INCL)/dungeon.h $(INCL)/monsym.h $(INCL)/mkroom.h \ $(INCL)/objclass.h $(INCL)/youprop.h $(INCL)/prop.h \ $(INCL)/permonst.h $(INCL)/monattk.h \ $(INCL)/monflag.h $(INCL)/mondata.h $(INCL)/pm.h \ $(INCL)/wintype.h $(INCL)/decl.h $(INCL)/quest.h \ $(INCL)/spell.h $(INCL)/color.h $(INCL)/obj.h \ $(INCL)/you.h $(INCL)/attrib.h $(INCL)/monst.h \ $(INCL)/skills.h $(INCL)/onames.h $(INCL)/timeout.h \ $(INCL)/trap.h $(INCL)/flag.h $(INCL)/rm.h \ $(INCL)/vision.h $(INCL)/display.h $(INCL)/engrave.h \ $(INCL)/rect.h $(INCL)/region.h $(INCL)/winprocs.h \ $(INCL)/wintty.h $(INCL)/trampoli.h LEV_H = $(INCL)/lev.h DGN_FILE_H = $(INCL)/dgn_file.h LEV_COMP_H = $(INCL)/lev_comp.h SP_LEV_H = $(INCL)/sp_lev.h TILE_H = ../win/share/tile.h #========================================== # Miscellaneous #========================================== DATABASE = $(DAT)/data.base # # The name of the game. # GAMEFILE = $(GAMEDIR)/$(GAME).exe #========================================== #=============== TARGETS ================== #========================================== # Since DOS doesn't allow / as path separator, and GCC doesn't allow \ as # path separator, we must change all pathnames when performing DOS commands. # This is done by blindly applying $(subst /,\, ...) on every command. # Where any command contain / for another reason (switch char, or echoing # comment lines to lev/dungeon files) a little more care is taken. # # The default make target (so just typing 'nmake' is useful). # default : $(GAMEFILE) # # The main target. # $(GAME) : $(O)obj.tag $(O)utility.tag graphicschk $(GAMEFILE) @echo $(GAME) is up to date. # # Everything # all : install install: graphicschk $(GAME) $(O)install.tag @echo Done. $(O)install.tag: $(DAT)/data $(DAT)/rumors $(DAT)/dungeon \ $(DAT)/oracles $(DAT)/quest.dat $(O)sp_lev.tag $(DLB) ifeq "$(USE_DLB)" "Y" $(subst /,\,copy nhdat $(GAMEDIR)) $(subst /,\,copy $(DAT)/license $(GAMEDIR)) $(subst /,\,copy $(DAT)/opthelp $(GAMEDIR)) else $(subst /,\,copy $(DAT)/*. $(GAMEDIR)) $(subst /,\,copy $(DAT)/*.dat $(GAMEDIR)) $(subst /,\,copy $(DAT)/*.lev $(GAMEDIR)) $(subst /,\,if exist $(GAMEDIR)/makefile del $(GAMEDIR)/makefile) endif $(subst /,\,if exist $(DOC)/guidebook.txt copy $(DOC)/guidebook.txt $(GAMEDIR)/Guidebook.txt) $(subst /,\,if exist $(DOC)/nethack.txt copy $(DOC)/nethack.txt $(GAMEDIR)/NetHack.txt) $(subst /,\,copy $(NTSYS)/defaults.nh $(GAMEDIR)/defaults.nh) $(subst /,\,echo install done > $@) # copy $(NTSYS)/winnt.hlp $(GAMEDIR) recover: $(U)recover.exe $(subst /,\,if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR)) $(subst /,\,if exist $(DOC)/recover.txt copy $(DOC)/recover.txt $(GAMEDIR)/recover.txt) $(O)sp_lev.tag: $(O)utility.tag $(DAT)/bigroom.des $(DAT)/castle.des \ $(DAT)/endgame.des $(DAT)/gehennom.des $(DAT)/knox.des \ $(DAT)/medusa.des $(DAT)/oracle.des $(DAT)/tower.des \ $(DAT)/yendor.des $(DAT)/arch.des $(DAT)/barb.des \ $(DAT)/caveman.des $(DAT)/healer.des $(DAT)/knight.des \ $(DAT)/monk.des $(DAT)/priest.des $(DAT)/ranger.des \ $(DAT)/rogue.des $(DAT)/samurai.des $(DAT)/sokoban.des \ $(DAT)/tourist.des $(DAT)/valkyrie.des $(DAT)/wizard.des $(subst /,\,$(U)lev_comp $(DAT)/bigroom.des) $(subst /,\,$(U)lev_comp $(DAT)/castle.des) $(subst /,\,$(U)lev_comp $(DAT)/endgame.des) $(subst /,\,$(U)lev_comp $(DAT)/gehennom.des) $(subst /,\,$(U)lev_comp $(DAT)/knox.des) $(subst /,\,$(U)lev_comp $(DAT)/mines.des) $(subst /,\,$(U)lev_comp $(DAT)/medusa.des) $(subst /,\,$(U)lev_comp $(DAT)/oracle.des) $(subst /,\,$(U)lev_comp $(DAT)/sokoban.des) $(subst /,\,$(U)lev_comp $(DAT)/tower.des) $(subst /,\,$(U)lev_comp $(DAT)/yendor.des) $(subst /,\,$(U)lev_comp $(DAT)/arch.des) $(subst /,\,$(U)lev_comp $(DAT)/barb.des) $(subst /,\,$(U)lev_comp $(DAT)/caveman.des) $(subst /,\,$(U)lev_comp $(DAT)/healer.des) $(subst /,\,$(U)lev_comp $(DAT)/knight.des) $(subst /,\,$(U)lev_comp $(DAT)/monk.des) $(subst /,\,$(U)lev_comp $(DAT)/priest.des) $(subst /,\,$(U)lev_comp $(DAT)/ranger.des) $(subst /,\,$(U)lev_comp $(DAT)/rogue.des) $(subst /,\,$(U)lev_comp $(DAT)/samurai.des) $(subst /,\,$(U)lev_comp $(DAT)/tourist.des) $(subst /,\,$(U)lev_comp $(DAT)/valkyrie.des) $(subst /,\,$(U)lev_comp $(DAT)/wizard.des) $(subst /,\,copy *.lev $(DAT)) $(subst /,\,del *.lev) $(subst /,\,echo sp_levs done > $(O)sp_lev.tag) $(O)utility.tag: $(INCL)/date.h $(INCL)/onames.h $(INCL)/pm.h \ $(SRC)/monstr.c $(SRC)/vis_tab.c $(U)lev_comp.exe $(INCL)/vis_tab.h \ $(U)dgn_comp.exe $(TILEUTIL16) $(subst /,\,@echo utilities made >$@) @echo utilities made. tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. ifeq "$(GRAPHICAL)" "Y" $(NHRES): $(TILEBMP16) $(WIN32)/winhack.rc $(WIN32)/mnsel.bmp \ $(WIN32)/mnselcnt.bmp $(WIN32)/mnunsel.bmp \ $(WIN32)/petmark.bmp $(WIN32)/NetHack.ico $(WIN32)/rip.bmp \ $(WIN32)/splash.bmp @$(rc) -o$@ --include-dir $(WIN32) -i $(WIN32)/winhack.rc else $(NHRES): $(NTSYS)/console.rc $(NTSYS)/NetHack.ico @$(rc) -o$@ --include-dir $(NTSYS) -i $(NTSYS)/console.rc endif #========================================== # The main target. #========================================== $(O)gamedir.tag: $(subst /,\,@if not exist $(GAMEDIR)/*.* echo creating directory $(GAMEDIR)) $(subst /,\,@if not exist $(GAMEDIR)/*.* mkdir $(GAMEDIR)) $(subst /,\,@echo directory created > $@) ifeq "$(GRAPHICAL)" "Y" $(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag else $(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag \ $(GAMEDIR)/nhdefkey.dll $(GAMEDIR)/nh340key.dll $(GAMEDIR)/nhraykey.dll endif @echo Linking.... @$(link) $(lflags) -o$@ $(ALLOBJ) $(NHRES) $(WINPLIBS) $(subst /,\,@if exist $(O)install.tag del $(O)install.tag) $(O)nhdefkey.o: $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nhdefkey.c $(GAMEDIR)/nhdefkey.dll : $(O)nhdefkey.o $(O)gamedir.tag @echo Linking $@ $(cc) -shared -Wl,--export-all-symbols \ -Wl,--add-stdcall-alias -o $@ $< $(O)nh340key.o: $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nh340key.c $(GAMEDIR)/nh340key.dll : $(O)nh340key.o $(O)gamedir.tag @echo Linking $@ $(cc) -shared -Wl,--export-all-symbols \ -Wl,--add-stdcall-alias -o $@ $< $(O)nhraykey.o: $(cc) $(CFLAGS) -DBUILD_DLL -o$@ $(NTSYS)/nhraykey.c $(GAMEDIR)/nhraykey.dll : $(O)nhraykey.o $(O)gamedir.tag @echo Linking $@ $(cc) -shared -Wl,--export-all-symbols \ -Wl,--add-stdcall-alias -o $@ $< $(GAME)_.ico : $(NTSYS)/$(GAME).ico $(subst /,\,@copy $(NTSYS)/$(GAME).ico $@) #========================================== # Create directory for holding object files #========================================== graphicschk: ifeq "$(GRAPHICAL)" "Y" @echo ---- @echo NOTE: This build will include tile support. @echo ---- endif $(subst /,\,@echo graphicschk > graphicschk) # # Secondary Targets. # #========================================== # Makedefs Stuff #========================================== $(U)makedefs.exe: $(MAKEOBJS) @$(link) $(LFLAGSU) -o$@ $(MAKEOBJS) $(O)makedefs.o: $(CONFIG_H) $(INCL)/monattk.h $(INCL)/monflag.h \ $(INCL)/objclass.h $(INCL)/monsym.h $(INCL)/qtext.h \ $(INCL)/patchlevel.h $(U)makedefs.c $(O)obj.tag $(cc) $(CFLAGSU) -o$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)/date.h $(OPTIONS_FILE): $(U)makedefs.exe $(subst /,\,$(U)makedefs -v) #$(OPTIONS_FILE): $(U)makedefs.exe # $(subst /,\,$(U)makedefs -v) $(INCL)/onames.h : $(U)makedefs.exe $(subst /,\,$(U)makedefs -o) $(INCL)/pm.h : $(U)makedefs.exe $(subst /,\,$(U)makedefs -p) #$(INCL)/trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)/monstr.c: $(U)makedefs.exe $(subst /,\,$(U)makedefs -m) $(INCL)/vis_tab.h: $(U)makedefs.exe $(subst /,\,$(U)makedefs -z) $(SRC)/vis_tab.c: $(U)makedefs.exe $(subst /,\,$(U)makedefs -z) #========================================== # uudecode utility and uuencoded targets #========================================== $(U)uudecode.exe: $(O)uudecode.o @$(link) $(LFLAGSU) -o$@ $(O)uudecode.o $(O)uudecode.o: $(SSYS)/uudecode.c $(NTSYS)/NetHack.ico : $(U)uudecode.exe $(NTSYS)/nhico.uu $(subst /,\,$(U)uudecode.exe $(NTSYS)/nhico.uu) $(subst /,\,copy NetHack.ico $@) del NetHack.ico $(WIN32)/NetHack.ico : $(NTSYS)/NetHack.ico $(subst /,\,copy $< $@) $(WIN32)/mnsel.bmp: $(U)uudecode.exe $(WIN32)/mnsel.uu $(subst /,\,$(U)uudecode.exe $(WIN32)/mnsel.uu) $(subst /,\,copy mnsel.bmp $@) del mnsel.bmp $(WIN32)/mnselcnt.bmp: $(U)uudecode.exe $(WIN32)/mnselcnt.uu $(subst /,\,$(U)uudecode.exe $(WIN32)/mnselcnt.uu) $(subst /,\,copy mnselcnt.bmp $@) del mnselcnt.bmp $(WIN32)/mnunsel.bmp: $(U)uudecode.exe $(WIN32)/mnunsel.uu $(subst /,\,$(U)uudecode.exe $(WIN32)/mnunsel.uu) $(subst /,\,copy mnunsel.bmp $@) del mnunsel.bmp $(WIN32)/petmark.bmp: $(U)uudecode.exe $(WIN32)/petmark.uu $(subst /,\,$(U)uudecode.exe $(WIN32)/petmark.uu) $(subst /,\,copy petmark.bmp $@) del petmark.bmp $(WIN32)/rip.bmp: $(U)uudecode.exe $(WIN32)/rip.uu $(subst /,\,$(U)uudecode.exe $(WIN32)/rip.uu) $(subst /,\,copy rip.bmp $@) del rip.bmp $(WIN32)/splash.bmp: $(U)uudecode.exe $(WIN32)/splash.uu $(subst /,\,$(U)uudecode.exe $(WIN32)/splash.uu) $(subst /,\,copy splash.bmp $@) del splash.bmp #========================================== # Level Compiler Stuff #========================================== LEVCFLAGS=$(cflags) -c -DWIN32 -D_WIN32 -I../include $(cdebug) -DDLB $(U)lev_comp.exe: $(SPLEVOBJS) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(SPLEVOBJS) $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)/lev_comp.h $(U)lev_yacc.c $(cc) $(LEVCFLAGS) -o$@ $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)/lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c $(cc) $(LEVCFLAGS) -o$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) $(cc) $(LEVCFLAGS) -o$@ $(U)lev_main.c $(U)lev_yacc.c $(INCL)/lev_comp.h : $(U)lev_comp.y ifeq "$(DO_YACC)" "YACC_ACT" $(subst /,\,$(YACC) -d $(U)lev_comp.y) $(subst /,\,copy $(YTABC) $(U)lev_yacc.c) $(subst /,\,copy $(YTABH) $(INCL)/lev_comp.h) $(subst /,\,@del $(YTABC)) $(subst /,\,@del $(YTABH)) else @echo $(U)lev_comp.y has changed. @echo To update $(U)lev_yacc.c and $(INCL)/lev_comp.h run $(YACC). @echo --- @echo For now, we will copy the prebuilt lev_yacc.c and @echo lev_comp.h from $(SSYS) into $(UTIL) and use them. $(subst /,\,@copy $(SSYS)/lev_yacc.c $(U)lev_yacc.c >nul) $(subst /,\,@copy $(SSYS)/lev_comp.h $(INCL)/lev_comp.h >nul) $(subst /,\,echo.>>$(U)lev_yacc.c) $(subst /,\,echo.>>$(INCL)/lev_comp.h) endif $(U)lev_$(LEX).c: $(U)lev_comp.l ifeq "$(DO_LEX)" "LEX_ACT" $(subst /,\,$(LEX) $(FLEXSKEL) $(U)lev_comp.l) $(subst /,\,copy $(LEXYYC) $@) $(subst /,\,@del $(LEXYYC)) else @echo $(U)lev_comp.l has changed. To update $@ run $(LEX). @echo --- @echo For now, we will copy the prebuilt lev_lex.c @echo from $(SSYS) into $(UTIL) and use it. $(subst /,\,@copy $(SSYS)/lev_lex.c $@ >nul) $(subst /,\,echo.>>$@) endif #========================================== # Dungeon Compiler Stuff #========================================== $(U)dgn_comp.exe: $(DGNCOMPOBJS) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(DGNCOMPOBJS) $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)/dgn_comp.h $(U)dgn_yacc.c $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)/dgn_comp.h \ $(U)dgn_$(LEX).c $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c $(cc) $(LEVCFLAGS) -o$@ $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)/dgn_comp.h : $(U)dgn_comp.y ifeq "$(DO_YACC)" "YACC_ACT" $(subst /,\,$(YACC) -d $(U)dgn_comp.y) $(subst /,\,copy $(YTABC) $(U)dgn_yacc.c) $(subst /,\,copy $(YTABH) $(INCL)/dgn_comp.h) $(subst /,\,@del $(YTABC)) $(subst /,\,@del $(YTABH)) else @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and @echo $(INCL)/dgn_comp.h run $(YACC). @echo --- @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them. $(subst /,\,@copy $(SSYS)/dgn_yacc.c $(U)dgn_yacc.c >nul) $(subst /,\,@copy $(SSYS)/dgn_comp.h $(INCL)/dgn_comp.h >nul) $(subst /,\,echo.>>$(U)dgn_yacc.c) $(subst /,\,echo.>>$(INCL)/dgn_comp.h) endif $(U)dgn_$(LEX).c: $(U)dgn_comp.l ifeq "$(DO_LEX)" "LEX_ACT" $(subst /,\,$(LEX) $(FLEXSKEL) $(U)dgn_comp.l) $(subst /,\,copy $(LEXYYC) $@) $(subst /,\,@del $(LEXYYC)) else @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX). @echo --- @echo For now, we will copy the prebuilt dgn_lex.c @echo from $(SSYS) into $(UTIL) and use it. $(subst /,\,@copy $(SSYS)/dgn_lex.c $@ >nul) $(subst /,\,echo.>>$@) endif #========================================== # Create directory for holding object files #========================================== $(O)obj.tag: $(subst /,\,@if not exist $(OBJ)/*.* echo creating directory $(OBJ)) $(subst /,\,@if not exist $(OBJ)/*.* mkdir $(OBJ)) $(subst /,\,@echo directory created > $@) #========================================== #=========== SECONDARY TARGETS ============ #========================================== #=========================================== # Header files NOT distributed in ../include #=========================================== $(INCL)/win32api.h: $(NTSYS)/win32api.h $(subst /,\,copy $(NTSYS)/win32api.h $@) #========================================== # DLB utility and nhdat file creation #========================================== $(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o @$(link) $(LFLAGSU) -o$@ $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)/dlb.h $(cc) $(CFLAGS) -o$@ $(SRC)/dlb.c $(O)dlb_main.o: $(UTIL)/dlb_main.c $(INCL)/config.h $(INCL)/dlb.h $(cc) $(CFLAGS) -o$@ $(UTIL)/dlb_main.c $(DAT)/porthelp: $(NTSYS)/porthelp $(subst /,\,@copy $(NTSYS)/porthelp $@ >nul) nhdat: $(U)dlb_main.exe $(DAT)/data $(DAT)/oracles $(OPTIONS_FILE) \ $(DAT)/quest.dat $(DAT)/rumors $(DAT)/help $(DAT)/hh $(DAT)/cmdhelp \ $(DAT)/history $(DAT)/opthelp $(DAT)/wizhelp $(DAT)/dungeon \ $(DAT)/porthelp $(DAT)/license $(O)sp_lev.tag $(subst /,\,echo data >$(DAT)/dlb.lst) $(subst /,\,echo oracles >>$(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/options echo options >>$(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/ttyoptions echo ttyoptions >>$(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/guioptions echo guioptions >>$(DAT)/dlb.lst) $(subst /,\,if exist $(DAT)/porthelp echo porthelp >>$(DAT)/dlb.lst) $(subst /,\,echo quest.dat >>$(DAT)/dlb.lst) $(subst /,\,echo rumors >>$(DAT)/dlb.lst) $(subst /,\,echo help >>$(DAT)/dlb.lst) $(subst /,\,echo hh >>$(DAT)/dlb.lst) $(subst /,\,echo cmdhelp >>$(DAT)/dlb.lst) $(subst /,\,echo history >>$(DAT)/dlb.lst) $(subst /,\,echo opthelp >>$(DAT)/dlb.lst) $(subst /,\,echo wizhelp >>$(DAT)/dlb.lst) $(subst /,\,echo dungeon >>$(DAT)/dlb.lst) $(subst /,\,echo license >>$(DAT)/dlb.lst) dir /l /b /-p $(subst /,\,$(DAT)/*.lev >>$(DAT)/dlb.lst) $(subst /,\,$(U)dlb_main CcIf $(DAT) dlb.lst $(SRC)/nhdat) #========================================== # Recover Utility #========================================== $(U)recover.exe: $(RECOVOBJS) $(link) $(LFLAGSU) -o$@ $(RECOVOBJS) $(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)/win32api.h $(cc) $(CFLAGSU) -o$@ $(U)recover.c #========================================== # Tile Mapping #========================================== $(SRC)/tile.c: $(U)tilemap.exe @echo A new $@ has been created @$(U)tilemap $(U)tilemap.exe: $(O)tilemap.o @$(link) $(LFLAGSU) -o$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)/tilemap.c $(HACK_H) $(cc) $(CFLAGSU) -o$@ $(WSHR)/tilemap.c $(O)tiletx32.o: $(WSHR)/tilemap.c $(HACK_H) $(cc) $(CFLAGS) -DTILETEXT -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/tilemap.c $(O)tiletxt.o: $(WSHR)/tilemap.c $(HACK_H) $(cc) $(CFLAGS) -DTILETEXT -o$@ $(WSHR)/tilemap.c $(O)gifread.o: $(WSHR)/gifread.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/gifread.c $(O)gifrd32.o: $(WSHR)/gifread.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/gifread.c $(O)ppmwrite.o: $(WSHR)/ppmwrite.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/ppmwrite.c $(O)tiletext.o: $(WSHR)/tiletext.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/tiletext.c $(O)tilete32.o: $(WSHR)/tiletext.c $(CONFIG_H) $(TILE_H) $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/tiletext.c #========================================== # Optional Tile Utilities #========================================== $(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(GIFREADERS) $(TEXT_IO) $(U)gif2tx32.exe: $(GIFREADERS32) $(TEXT_IO32) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(GIFREADERS32) $(TEXT_IO32) $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(PPMWRITERS) $(TEXT_IO) ifeq "$(GRAPHICAL)" "Y" $(TILEBMP16): $(TILEUTIL16) $(TILEFILES) @echo Creating 16x16 binary tile files (this may take some time) $(subst /,\,@$(U)tile2bmp $(TILEBMP16)) #$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32) # @echo Creating 32x32 binary tile files (this may take some time) # $(subst /,\,@$(U)til2bm32 $(TILEBMP32)) else $(TILEBMP16): $(TILEBMP32): endif $(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(O)tile2bmp.o $(TEXT_IO) $(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32) @echo Linking $@... @$(link) $(LFLAGSU) -o$@ $(O)til2bm32.o $(TEXT_IO32) $(O)tile2bmp.o: $(WSHR)/tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)/win32api.h $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(WSHR)/tile2bmp.c $(O)til2bm32.o: $(WSHR)/til2bm32.c $(HACK_H) $(TILE_H) $(INCL)/win32api.h $(cc) $(CFLAGS) -I$(WSHR) -DTILE_X=32 -DTILE_Y=32 -o$@ $(WSHR)/til2bm32.c #========================================== # Housekeeping #========================================== spotless: clean $(subst /,\,if exist graphicschk del graphicschk) $(subst /,\,if exist $(INCL)/date.h del $(INCL)/date.h) $(subst /,\,if exist $(INCL)/onames.h del $(INCL)/onames.h) $(subst /,\,if exist $(INCL)/pm.h del $(INCL)/pm.h) $(subst /,\,if exist $(INCL)/vis_tab.h del $(INCL)/vis_tab.h) $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c) $(subst /,\,if exist $(SRC)/tile.c del $(SRC)/tile.c) $(subst /,\,if exist $(U)*.lnk del $(U)*.lnk) $(subst /,\,if exist $(U)*.map del $(U)*.map) $(subst /,\,if exist $(DAT)/data del $(DAT)/data) $(subst /,\,if exist $(DAT)/rumors del $(DAT)/rumors) $(subst /,\,if exist $(DAT)/???-fil?.lev del $(DAT)/???-fil?.lev) $(subst /,\,if exist $(DAT)/???-goal.lev del $(DAT)/???-goal.lev) $(subst /,\,if exist $(DAT)/???-loca.lev del $(DAT)/???-loca.lev) $(subst /,\,if exist $(DAT)/???-strt.lev del $(DAT)/???-strt.lev) $(subst /,\,if exist $(DAT)/air.lev del $(DAT)/air.lev) $(subst /,\,if exist $(DAT)/asmodeus.lev del $(DAT)/asmodeus.lev) $(subst /,\,if exist $(DAT)/astral.lev del $(DAT)/astral.lev) $(subst /,\,if exist $(DAT)/baalz.lev del $(DAT)/baalz.lev) $(subst /,\,if exist $(DAT)/bigrm-*.lev del $(DAT)/bigrm-*.lev) $(subst /,\,if exist $(DAT)/castle.lev del $(DAT)/castle.lev) $(subst /,\,if exist $(DAT)/data del $(DAT)/data) $(subst /,\,if exist $(DAT)/dungeon del $(DAT)/dungeon) $(subst /,\,if exist $(DAT)/dungeon.pdf del $(DAT)/dungeon.pdf) $(subst /,\,if exist $(DAT)/earth.lev del $(DAT)/earth.lev) $(subst /,\,if exist $(DAT)/fakewiz?.lev del $(DAT)/fakewiz?.lev) $(subst /,\,if exist $(DAT)/fire.lev del $(DAT)/fire.lev) $(subst /,\,if exist $(DAT)/juiblex.lev del $(DAT)/juiblex.lev) $(subst /,\,if exist $(DAT)/knox.lev del $(DAT)/knox.lev) $(subst /,\,if exist $(DAT)/medusa-?.lev del $(DAT)/medusa-?.lev) $(subst /,\,if exist $(DAT)/mine*.lev del $(DAT)/mine*.lev) $(subst /,\,if exist $(DAT)/options del $(DAT)/options) $(subst /,\,if exist $(DAT)/ttyoptions del $(DAT)/ttyoptions) $(subst /,\,if exist $(DAT)/guioptions del $(DAT)/guioptions) $(subst /,\,if exist $(DAT)/oracle.lev del $(DAT)/oracle.lev) $(subst /,\,if exist $(DAT)/oracles del $(DAT)/oracles) $(subst /,\,if exist $(DAT)/orcus.lev del $(DAT)/orcus.lev) $(subst /,\,if exist $(DAT)/rumors del $(DAT)/rumors) $(subst /,\,if exist $(DAT)/quest.dat del $(DAT)/quest.dat) $(subst /,\,if exist $(DAT)/sanctum.lev del $(DAT)/sanctum.lev) $(subst /,\,if exist $(DAT)/soko?-?.lev del $(DAT)/soko?-?.lev) $(subst /,\,if exist $(DAT)/tower?.lev del $(DAT)/tower?.lev) $(subst /,\,if exist $(DAT)/valley.lev del $(DAT)/valley.lev) $(subst /,\,if exist $(DAT)/water.lev del $(DAT)/water.lev) $(subst /,\,if exist $(DAT)/wizard?.lev del $(DAT)/wizard?.lev) $(subst /,\,if exist $(O)sp_lev.tag del $(O)sp_lev.tag) $(subst /,\,if exist $(SRC)/monstr.c del $(SRC)/monstr.c) $(subst /,\,if exist $(SRC)/vis_tab.c del $(SRC)/vis_tab.c) $(subst /,\,if exist $(U)recover.exe del $(U)recover.exe) $(subst /,\,if exist $(DAT)/dlb.lst del $(DAT)/dlb.lst) $(subst /,\,if exist nhdat. del nhdat.) $(subst /,\,if exist $(O)install.tag del $(O)install.tag) $(subst /,\,if exist $(O)obj.tag del $(O)obj.tag) $(subst /,\,if exist $(O)gamedir.tag del $(O)gamedir.tag) ifneq "$(OBJ)" "" $(subst /,\,rmdir $(OBJ)) /s /Q endif clean: $(subst /,\,if exist $(O)*.o del $(O)*.o) $(subst /,\,if exist $(O)utility.tag del $(O)utility.tag) $(subst /,\,if exist $(U)makedefs.exe del $(U)makedefs.exe) $(subst /,\,if exist $(U)lev_comp.exe del $(U)lev_comp.exe) $(subst /,\,if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe) $(subst /,\,if exist $(SRC)/*.lnk del $(SRC)/*.lnk) $(subst /,\,if exist $(SRC)/*.map del $(SRC)/*.map) $(subst /,\,if exist $(TILEBMP16) del $(TILEBMP16)) $(subst /,\,if exist $(TILEBMP32) del $(TILEBMP32)) #=================================================================== # OTHER DEPENDENCIES #=================================================================== # # dat dependencies # $(DAT)/data: $(O)utility.tag $(DATABASE) $(subst /,\,$(U)makedefs -d) $(DAT)/rumors: $(O)utility.tag $(DAT)/rumors.tru $(DAT)/rumors.fal $(subst /,\,$(U)makedefs -r) $(DAT)/quest.dat: $(O)utility.tag $(DAT)/quest.txt $(subst /,\,$(U)makedefs -q) $(DAT)/oracles: $(O)utility.tag $(DAT)/oracles.txt $(subst /,\,$(U)makedefs -h) $(DAT)/dungeon: $(O)utility.tag $(DAT)/dungeon.def $(subst /,\,$(U)makedefs -e) $(subst /,\,$(U)dgn_comp $(DAT)/dungeon.pdf) # # NT dependencies # $(O)nttty.o: $(HACK_H) $(TILE_H) $(INCL)/win32api.h $(NTSYS)/nttty.c $(cc) $(CFLAGS) -I$(WSHR) -o$@ $(NTSYS)/nttty.c $(O)winnt.o: $(HACK_H) $(INCL)/win32api.h $(NTSYS)/winnt.c $(cc) $(CFLAGS) -o$@ $(NTSYS)/winnt.c $(O)ntsound.o: $(HACK_H) $(NTSYS)/ntsound.c $(cc) $(CFLAGS) -o$@ $(NTSYS)/ntsound.c $(O)mapimail.o: $(HACK_H) $(INCL)/nhlan.h $(NTSYS)/mapimail.c $(cc) $(CFLAGS) -DMAPI_VERBOSE -o$@ $(NTSYS)/mapimail.c # # util dependencies # $(O)panic.o: $(U)panic.c $(CONFIG_H) $(cc) $(CFLAGS) -o$@ $(U)panic.c # # The rest are stolen from sys/unix/Makefile.src, # with the following changes: # * ../include changed to $(INCL) # * -c (which is included in CFLAGS) substituted # with -o$@ # * targets prefixed with $(O) # * $(CC) changed to $(cc) # but otherwise untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ../sys/atari/tos.c $(HACK_H) $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../sys/atari/tos.c $(O)pcmain.o: ../sys/share/pcmain.c $(HACK_H) $(INCL)/dlb.h \ $(INCL)/win32api.h $(cc) $(CFLAGS) -o$@ ../sys/share/pcmain.c $(O)pcsys.o: ../sys/share/pcsys.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/pcsys.c $(O)pctty.o: ../sys/share/pctty.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/pctty.c $(O)pcunix.o: ../sys/share/pcunix.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/pcunix.c $(O)random.o: ../sys/share/random.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/random.c $(O)ioctl.o: ../sys/share/ioctl.c $(HACK_H) $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../sys/share/ioctl.c $(O)unixtty.o: ../sys/share/unixtty.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/share/unixtty.c $(O)unixmain.o: ../sys/unix/unixmain.c $(HACK_H) $(INCL)/dlb.h $(cc) $(CFLAGS) -o$@ ../sys/unix/unixmain.c $(O)unixunix.o: ../sys/unix/unixunix.c $(HACK_H) $(cc) $(CFLAGS) -o$@ ../sys/unix/unixunix.c $(O)unixres.o: ../sys/unix/unixres.c $(CONFIG_H) $(cc) $(CFLAGS) -o$@ ../sys/unix/unixres.c $(O)bemain.o: ../sys/be/bemain.c $(HACK_H) $(INCL)/dlb.h $(cc) $(CFLAGS) -o$@ ../sys/be/bemain.c $(O)getline.o: ../win/tty/getline.c $(HACK_H) $(INCL)/func_tab.h $(cc) $(CFLAGS) -o$@ ../win/tty/getline.c $(O)termcap.o: ../win/tty/termcap.c $(HACK_H) $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../win/tty/termcap.c $(O)topl.o: ../win/tty/topl.c $(HACK_H) $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../win/tty/topl.c $(O)wintty.o: ../win/tty/wintty.c $(HACK_H) $(INCL)/dlb.h \ $(INCL)/patchlevel.h $(INCL)/tcap.h $(cc) $(CFLAGS) -o$@ ../win/tty/wintty.c $(O)Window.o: ../win/X11/Window.c $(INCL)/xwindowp.h $(INCL)/xwindow.h \ $(CONFIG_H) $(cc) $(CFLAGS) -o$@ ../win/X11/Window.c $(O)dialogs.o: ../win/X11/dialogs.c $(CONFIG_H) $(cc) $(CFLAGS) -o$@ ../win/X11/dialogs.c $(O)winX.o: ../win/X11/winX.c $(HACK_H) $(INCL)/winX.h $(INCL)/dlb.h \ $(INCL)/patchlevel.h ../win/X11/nh72icon \ ../win/X11/nh56icon ../win/X11/nh32icon $(cc) $(CFLAGS) -o$@ ../win/X11/winX.c $(O)winmap.o: ../win/X11/winmap.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/dlb.h \ $(INCL)/winX.h $(INCL)/tile2x11.h $(cc) $(CFLAGS) -o$@ ../win/X11/winmap.c $(O)winmenu.o: ../win/X11/winmenu.c $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winmenu.c $(O)winmesg.o: ../win/X11/winmesg.c $(INCL)/xwindow.h $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winmesg.c $(O)winmisc.o: ../win/X11/winmisc.c $(HACK_H) $(INCL)/func_tab.h \ $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winmisc.c $(O)winstat.o: ../win/X11/winstat.c $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winstat.c $(O)wintext.o: ../win/X11/wintext.c $(HACK_H) $(INCL)/winX.h $(INCL)/xwindow.h $(cc) $(CFLAGS) -o$@ ../win/X11/wintext.c $(O)winval.o: ../win/X11/winval.c $(HACK_H) $(INCL)/winX.h $(cc) $(CFLAGS) -o$@ ../win/X11/winval.c $(O)tile.o: tile.c $(HACK_H) $(O)gnaskstr.o: ../win/gnome/gnaskstr.c ../win/gnome/gnaskstr.h \ ../win/gnome/gnmain.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnaskstr.c $(O)gnbind.o: ../win/gnome/gnbind.c ../win/gnome/gnbind.h ../win/gnome/gnmain.h \ ../win/gnome/gnaskstr.h ../win/gnome/gnyesno.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnbind.c $(O)gnglyph.o: ../win/gnome/gnglyph.c ../win/gnome/gnglyph.h $(INCL)/tile2x11.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnglyph.c $(O)gnmain.o: ../win/gnome/gnmain.c ../win/gnome/gnmain.h ../win/gnome/gnsignal.h \ ../win/gnome/gnbind.h ../win/gnome/gnopts.h $(HACK_H) \ $(INCL)/date.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmain.c $(O)gnmap.o: ../win/gnome/gnmap.c ../win/gnome/gnmap.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmap.c $(O)gnmenu.o: ../win/gnome/gnmenu.c ../win/gnome/gnmenu.h ../win/gnome/gnmain.h \ ../win/gnome/gnbind.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmenu.c $(O)gnmesg.o: ../win/gnome/gnmesg.c ../win/gnome/gnmesg.h ../win/gnome/gnsignal.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnmesg.c $(O)gnopts.o: ../win/gnome/gnopts.c ../win/gnome/gnopts.h ../win/gnome/gnglyph.h \ ../win/gnome/gnmain.h ../win/gnome/gnmap.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnopts.c $(O)gnplayer.o: ../win/gnome/gnplayer.c ../win/gnome/gnplayer.h \ ../win/gnome/gnmain.h $(HACK_H) $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnplayer.c $(O)gnsignal.o: ../win/gnome/gnsignal.c ../win/gnome/gnsignal.h \ ../win/gnome/gnmain.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnsignal.c $(O)gnstatus.o: ../win/gnome/gnstatus.c ../win/gnome/gnstatus.h \ ../win/gnome/gnsignal.h ../win/gnome/gn_xpms.h \ ../win/gnome/gnomeprv.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnstatus.c $(O)gntext.o: ../win/gnome/gntext.c ../win/gnome/gntext.h ../win/gnome/gnmain.h \ ../win/gnome/gn_rip.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gntext.c $(O)gnworn.o: ../win/gnome/gnworn.c ../win/gnome/gnworn.h ../win/gnome/gnglyph.h \ ../win/gnome/gnsignal.h ../win/gnome/gnomeprv.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnworn.c $(O)gnyesno.o: ../win/gnome/gnyesno.c ../win/gnome/gnbind.h ../win/gnome/gnyesno.h $(cc) $(CFLAGS) $(GNOMEINC) -o$@ ../win/gnome/gnyesno.c $(O)wingem.o: ../win/gem/wingem.c $(HACK_H) $(INCL)/func_tab.h $(INCL)/dlb.h \ $(INCL)/patchlevel.h $(INCL)/wingem.h $(cc) $(CFLAGS) -o$@ ../win/gem/wingem.c $(O)wingem1.o: ../win/gem/wingem1.c $(INCL)/gem_rsc.h $(INCL)/load_img.h \ $(INCL)/gr_rect.h $(INCL)/wintype.h $(INCL)/wingem.h $(cc) $(CFLAGS) -o$@ ../win/gem/wingem1.c $(O)load_img.o: ../win/gem/load_img.c $(INCL)/load_img.h $(cc) $(CFLAGS) -o$@ ../win/gem/load_img.c $(O)gr_rect.o: ../win/gem/gr_rect.c $(INCL)/gr_rect.h $(cc) $(CFLAGS) -o$@ ../win/gem/gr_rect.c $(O)tile.o: tile.c $(HACK_H) $(O)qt_win.o: ../win/Qt/qt_win.cpp $(HACK_H) $(INCL)/func_tab.h \ $(INCL)/dlb.h $(INCL)/patchlevel.h $(INCL)/tile2x11.h \ $(INCL)/qt_win.h $(INCL)/qt_clust.h $(INCL)/qt_kde0.h \ $(INCL)/qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_win.cpp $(O)qt_clust.o: ../win/Qt/qt_clust.cpp $(INCL)/qt_clust.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qt_clust.cpp $(O)qttableview.o: ../win/Qt/qttableview.cpp $(INCL)/qttableview.h $(CXX) $(CXXFLAGS) -o$@ ../win/Qt/qttableview.cpp $(O)monstr.o: monstr.c $(CONFIG_H) $(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)/vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) $(INCL)/edog.h $(O)artifact.o: artifact.c $(HACK_H) $(INCL)/artifact.h $(INCL)/artilist.h $(O)attrib.o: attrib.c $(HACK_H) $(O)ball.o: ball.c $(HACK_H) $(O)bones.o: bones.c $(HACK_H) $(INCL)/lev.h $(O)botl.o: botl.c $(HACK_H) $(O)cmd.o: cmd.c $(HACK_H) $(INCL)/func_tab.h $(O)dbridge.o: dbridge.c $(HACK_H) $(O)decl.o: decl.c $(HACK_H) $(O)detect.o: detect.c $(HACK_H) $(INCL)/artifact.h $(O)dig.o: dig.c $(HACK_H) $(INCL)/edog.h $(O)display.o: display.c $(HACK_H) $(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)/dlb.h $(O)do.o: do.c $(HACK_H) $(INCL)/lev.h $(O)do_name.o: do_name.c $(HACK_H) $(O)do_wear.o: do_wear.c $(HACK_H) $(O)dog.o: dog.c $(HACK_H) $(INCL)/edog.h $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h $(O)dokick.o: dokick.c $(HACK_H) $(INCL)/eshk.h $(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)/edog.h $(O)drawing.o: drawing.c $(HACK_H) $(INCL)/tcap.h $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)/dgn_file.h $(INCL)/dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)/eshk.h $(INCL)/dlb.h $(O)engrave.o: engrave.c $(HACK_H) $(INCL)/lev.h $(O)exper.o: exper.c $(HACK_H) $(O)explode.o: explode.c $(HACK_H) $(O)extralev.o: extralev.c $(HACK_H) $(O)files.o: files.c $(HACK_H) $(INCL)/dlb.h $(O)fountain.o: fountain.c $(HACK_H) $(O)hack.o: hack.c $(HACK_H) $(O)hacklib.o: hacklib.c $(HACK_H) $(O)invent.o: invent.c $(HACK_H) $(O)light.o: light.c $(HACK_H) $(INCL)/lev.h $(O)lock.o: lock.c $(HACK_H) $(O)mail.o: mail.c $(HACK_H) $(INCL)/mail.h $(O)makemon.o: makemon.c $(HACK_H) $(INCL)/epri.h $(INCL)/emin.h \ $(INCL)/edog.h $(O)mapglyph.o: mapglyph.c $(HACK_H) $(O)mcastu.o: mcastu.c $(HACK_H) $(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h $(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)/artifact.h $(INCL)/edog.h $(O)minion.o: minion.c $(HACK_H) $(INCL)/emin.h $(INCL)/epri.h $(O)mklev.o: mklev.c $(HACK_H) $(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)/sp_lev.h $(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)/sp_lev.h $(INCL)/lev.h $(O)mkobj.o: mkobj.c $(HACK_H) $(O)mkroom.o: mkroom.c $(HACK_H) $(O)mon.o: mon.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/edog.h $(O)mondata.o: mondata.c $(HACK_H) $(INCL)/eshk.h $(INCL)/epri.h $(O)monmove.o: monmove.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/artifact.h \ $(INCL)/epri.h $(O)monst.o: monst.c $(CONFIG_H) $(INCL)/permonst.h $(INCL)/align.h \ $(INCL)/monattk.h $(INCL)/monflag.h $(INCL)/monsym.h \ $(INCL)/dungeon.h $(INCL)/eshk.h $(INCL)/vault.h \ $(INCL)/epri.h $(INCL)/color.h $(O)mplayer.o: mplayer.c $(HACK_H) $(O)mthrowu.o: mthrowu.c $(HACK_H) $(O)muse.o: muse.c $(HACK_H) $(INCL)/edog.h $(O)music.o: music.c $(HACK_H) #interp.c $(O)o_init.o: o_init.c $(HACK_H) $(INCL)/lev.h $(O)objects.o: objects.c $(CONFIG_H) $(INCL)/obj.h $(INCL)/objclass.h \ $(INCL)/prop.h $(INCL)/skills.h $(INCL)/color.h $(O)objnam.o: objnam.c $(HACK_H) $(O)options.o: options.c $(CONFIG_H) $(INCL)/objclass.h $(INCL)/flag.h \ $(HACK_H) $(INCL)/tcap.h $(O)pager.o: pager.c $(HACK_H) $(INCL)/dlb.h $(O)pickup.o: pickup.c $(HACK_H) $(O)pline.o: pline.c $(HACK_H) $(INCL)/epri.h $(INCL)/edog.h $(O)polyself.o: polyself.c $(HACK_H) $(O)potion.o: potion.c $(HACK_H) $(O)pray.o: pray.c $(HACK_H) $(INCL)/epri.h $(O)priest.o: priest.c $(HACK_H) $(INCL)/mfndpos.h $(INCL)/eshk.h \ $(INCL)/epri.h $(INCL)/emin.h $(O)quest.o: quest.c $(HACK_H) $(INCL)/qtext.h $(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)/dlb.h $(INCL)/qtext.h $(O)read.o: read.c $(HACK_H) $(O)rect.o: rect.c $(HACK_H) $(O)region.o: region.c $(HACK_H) $(INCL)/lev.h $(O)restore.o: restore.c $(HACK_H) $(INCL)/lev.h $(INCL)/tcap.h $(O)rip.o: rip.c $(HACK_H) $(O)rnd.o: rnd.c $(HACK_H) $(O)role.o: role.c $(HACK_H) $(O)rumors.o: rumors.c $(HACK_H) $(INCL)/lev.h $(INCL)/dlb.h $(O)save.o: save.c $(HACK_H) $(INCL)/lev.h $(O)shk.o: shk.c $(HACK_H) $(INCL)/eshk.h $(O)shknam.o: shknam.c $(HACK_H) $(INCL)/eshk.h $(O)sit.o: sit.c $(HACK_H) $(INCL)/artifact.h $(O)sounds.o: sounds.c $(HACK_H) $(INCL)/edog.h $(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)/dlb.h $(INCL)/sp_lev.h $(O)spell.o: spell.c $(HACK_H) $(O)steal.o: steal.c $(HACK_H) $(O)steed.o: steed.c $(HACK_H) $(O)teleport.o: teleport.c $(HACK_H) $(O)timeout.o: timeout.c $(HACK_H) $(INCL)/lev.h $(O)topten.o: topten.c $(HACK_H) $(INCL)/dlb.h $(INCL)/patchlevel.h $(O)track.o: track.c $(HACK_H) $(O)trap.o: trap.c $(HACK_H) $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(INCL)/vault.h $(O)version.o: version.c $(HACK_H) $(INCL)/date.h $(INCL)/patchlevel.h $(O)vision.o: vision.c $(HACK_H) $(INCL)/vis_tab.h $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) $(O)windows.o: windows.c $(HACK_H) $(INCL)/wingem.h $(INCL)/winGnome.h $(O)wizard.o: wizard.c $(HACK_H) $(INCL)/qtext.h $(INCL)/epri.h $(O)worm.o: worm.c $(HACK_H) $(INCL)/lev.h $(O)worn.o: worn.c $(HACK_H) $(O)write.o: write.c $(HACK_H) $(O)zap.o: zap.c $(HACK_H) # end of file nethack-3.4.3/sys/winnt/Makefile.msc0100644000000000000000000013371307764735041016060 0ustar rootroot# SCCS Id: @(#)Makefile.msc 3.4 $Date: 2003/11/16 04:50:58 $ # Copyright (c) NetHack PC Development Team 1993-2003 # # NetHack 3.4.x Makefile for MS Visual C++ V6.x and above and MS NMAKE # # Win32 Compilers Tested: # - Microsoft 32 bit Visual C++ V4.x # - Microsoft 32 bit Visual C++ V6.0 SP3, SP4 # # This is used for building two versions of NetHack: # A tty port utilizing the Win32 Console I/O subsystem, Console # NetHack; # A Win32 native port built on the Windows API, Graphical NetHack or # NetHackW. # # In addition to your C compiler, # # if you want to change you will need a # files with suffix workalike for # .y yacc (such as bison) # .l lex (such as flex) # # # If you have any questions read the sys/winnt/Install.nt file included # with the distribution. #============================================================================== # Do not delete the following 3 lines. # TARGETOS=BOTH APPVER=4.0 !include # Graphical interface # Set to Y for a graphical version #GRAPHICAL = Y # Set the gamedir according to your preference. # If not present prior to compilation it gets created. !IF "$(GRAPHICAL)" == "Y" GAME = NetHackW # Game Name !ELSE GAME = NetHack # Game Name !ENDIF GAMEDIR = ..\binary # Game directory # # Source directories. Makedefs hardcodes these, don't change them. # INCL = ..\include # NetHack include files DAT = ..\dat # NetHack data files DOC = ..\doc # NetHack documentation files UTIL = ..\util # Utility source SRC = ..\src # Main source SSYS = ..\sys\share # Shared system files NTSYS = ..\sys\winnt # NT Win32 specific files TTY = ..\win\tty # window port files (tty) WIN32 = ..\win\win32 # window port files (Win32) WSHR = ..\win\share # Tile support files # # Object directory. # OBJ = o # #========================================== # Exe File Info. #========================================== # Yacc/Lex ... if you got 'em. # # If you have yacc and lex programs (or work-alike such as bison # and flex), comment out the upper two macros and uncomment # the lower two. # DO_YACC = YACC_MSG DO_LEX = LEX_MSG #DO_YACC = YACC_ACT #DO_LEX = LEX_ACT # - Specify your yacc and lex programs (or work-alikes) here. #YACC = bison -y YACC = byacc #YACC = yacc #LEX = lex LEX = flex # # - Specify your flex skeleton file (if needed). # FLEXSKEL = #FLEXSKEL = -S../tools/flex.ske YTABC = y_tab.c YTABH = y_tab.h LEXYYC = lexyy.c # # Optional high-quality BSD random number generation routines # (see pcconf.h). Set to nothing if not used. # RANDOM = $(OBJ)\random.o #RANDOM = # # Leave the next two lines uncommented _ONLY_ if you do NOT want any # debug capability in the object files, or in the NetHack executable. # Comment them if you want debug capability. #cdebug = #linkdebug = # # Compiler and Linker flags # PRECOMPHEAD = N # set to Y if you want to use precomp. headers #=============================================== #======= End of Modification Section =========== #=============================================== ################################################ # # # Nothing below here should have to be changed.# # # ################################################ !IF "$(GRAPHICAL)" == "Y" WINPORT = $(O)tile.o $(O)mhaskyn.o $(O)mhdlg.o \ $(O)mhfont.o $(O)mhinput.o $(O)mhmain.o $(O)mhmap.o \ $(O)mhmenu.o $(O)mhmsgwnd.o $(O)mhrip.o $(O)mhsplash.o \ $(O)mhstatus.o $(O)mhtext.o $(O)mswproc.o $(O)winhack.o WINPHDR = $(WIN32)\mhaskyn.h $(WIN32)\mhdlg.h $(WIN32)\mhfont.h \ $(WIN32)\mhinput.h $(WIN32)\mhmain.h $(WIN32)\mhmap.h $(WIN32)\mhmenu.h \ $(WIN32)\mhmsg.h $(WIN32)\mhmsgwnd.h $(WIN32)\mhrip.h $(WIN32)\mhstatus.h \ $(WIN32)\mhtext.h $(WIN32)\resource.h $(WIN32)\winMS.h WINDLLS = WINPFLAG= -DTILES -DMSWIN_GRAPHICS NHRES = $(O)winhack.res WINPINC = -I$(WIN32) !ELSE WINPORT = $(O)nttty.o WINPHDR = WINDLLS = $(GAMEDIR)\nhdefkey.dll $(GAMEDIR)\nh340key.dll $(GAMEDIR)\nhraykey.dll WINPFLAG= -DWIN32CON NHRES = $(O)console.res WINPINC = !ENDIF TILEUTIL16 = $(UTIL)\tile2bmp.exe TILEBMP16 = $(SRC)\tiles.bmp TILEUTIL32 = $(UTIL)\til2bm32.exe TILEBMP32 = $(SRC)\tiles32.bmp SOUND = $(OBJ)\ntsound.o #SOUND = # To store all the level files, # help files, etc. in a single library file. # USE_DLB = Y is left uncommented USE_DLB = Y ! IF ("$(USE_DLB)"=="Y") DLBFLG = -DDLB ! ELSE DLBFLG = ! ENDIF #========================================== # Setting up the compiler and linker # macros. All builds include the base ones. #========================================== CFLAGSBASE = -c $(cflags) $(cvarsmt) -I$(INCL) -nologo $(cdebug) $(WINPINC) LFLAGSBASEC = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt) LFLAGSBASEG = $(linkdebug) $(guiflags) $(guilibsmt) comctl32.lib #========================================== # Util builds #========================================== CFLAGSU = $(CFLAGSBASE) $(WINPFLAG) LFLAGSU = $(LFLAGSBASEC) #========================================== # - Game build #========================================== LFLAGSBASE = $(linkdebug) /NODEFAULTLIB /INCREMENTAL:NO /RELEASE /NOLOGO -subsystem:console,4.0 $(conlibsmt) CFLAGS = $(CFLAGSBASE) $(WINPFLAG) $(DLBFLG) NHLFLAGS1 = /NODEFAULTLIB /INCREMENTAL:NO /PDB:"$(GAME).PDB" /RELEASE /NOLOGO NHLFLAGS2 = /MAP:"$(GAME).MAP" /MACHINE:$(CPU) -IGNORE:505 !IF ("$(GRAPHICAL)"=="Y") LFLAGS = $(LFLAGSBASEG) $(NHLFLAGS1) $(NHLFLAGS2) !ELSE LFLAGS = $(LFLAGSBASEC) $(NHLFLAGS1) $(NHLFLAGS2) !ENDIF GAMEFILE = $(GAMEDIR)\$(GAME).exe # whole thing ! IF ("$(USE_DLB)"=="Y") DLB = nhdat ! ELSE DLB = ! ENDIF #========================================== #================ RULES ================== #========================================== .SUFFIXES: .exe .o .til .uu .c .y .l #========================================== # Rules for files in src #========================================== .c{$(OBJ)}.o: @$(cc) $(CFLAGS) -Fo$@ $< {$(SRC)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) -Fo$@ $< #========================================== # Rules for files in sys\share #========================================== {$(SSYS)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) -Fo$@ $< #========================================== # Rules for files in sys\winnt #========================================== {$(NTSYS)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) -Fo$@ $< {$(NTSYS)}.h{$(INCL)}.h: @copy $< $@ #========================================== # Rules for files in util #========================================== {$(UTIL)}.c{$(OBJ)}.o: @$(CC) $(CFLAGSU) -Fo$@ $< #========================================== # Rules for files in win\share #========================================== {$(WSHR)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) -Fo$@ $< {$(WSHR)}.h{$(INCL)}.h: @copy $< $@ #{$(WSHR)}.txt{$(DAT)}.txt: # @copy $< $@ #========================================== # Rules for files in win\tty #========================================== {$(TTY)}.c{$(OBJ)}.o: @$(CC) $(CFLAGS) -Fo$@ $< #========================================== # Rules for files in win\win32 #========================================== {$(WIN32)}.c{$(OBJ)}.o: @$(cc) $(CFLAGS) -Fo$@ $< #========================================== #================ MACROS ================== #========================================== # This section creates shorthand macros for many objects # referenced later on in the Makefile. # DEFFILE = $(NTSYS)\$(GAME).def # # Shorten up the location for some files # O = $(OBJ)^\ U = $(UTIL)^\ # # Utility Objects. # MAKESRC = $(U)makedefs.c SPLEVSRC = $(U)lev_yacc.c $(U)lev_$(LEX).c $(U)lev_main.c $(U)panic.c DGNCOMPSRC = $(U)dgn_yacc.c $(U)dgn_$(LEX).c $(U)dgn_main.c MAKEOBJS = $(O)makedefs.o $(O)monst.o $(O)objects.o SPLEVOBJS = $(O)lev_yacc.o $(O)lev_$(LEX).o $(O)lev_main.o \ $(O)alloc.o $(O)decl.o $(O)drawing.o \ $(O)monst.o $(O)objects.o $(O)panic.o DGNCOMPOBJS = $(O)dgn_yacc.o $(O)dgn_$(LEX).o $(O)dgn_main.o \ $(O)alloc.o $(O)panic.o RECOVOBJS = $(O)recover.o TILEFILES = $(WSHR)\monsters.txt $(WSHR)\objects.txt $(WSHR)\other.txt # # These are not invoked during a normal game build in 3.4 # TEXT_IO = $(O)tiletext.o $(O)tiletxt.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o TEXT_IO32 = $(O)tilete32.o $(O)tiletx32.o $(O)drawing.o \ $(O)decl.o $(O)monst.o $(O)objects.o GIFREADERS = $(O)gifread.o $(O)alloc.o $(O)panic.o GIFREADERS32 = $(O)gifrd32.o $(O)alloc.o $(O)panic.o PPMWRITERS = $(O)ppmwrite.o $(O)alloc.o $(O)panic.o # # Object files for the game itself. # VOBJ01 = $(O)allmain.o $(O)alloc.o $(O)apply.o $(O)artifact.o VOBJ02 = $(O)attrib.o $(O)ball.o $(O)bones.o $(O)botl.o VOBJ03 = $(O)cmd.o $(O)dbridge.o $(O)decl.o $(O)detect.o VOBJ04 = $(O)dig.o $(O)display.o $(O)do.o $(O)do_name.o VOBJ05 = $(O)do_wear.o $(O)dog.o $(O)dogmove.o $(O)dokick.o VOBJ06 = $(O)dothrow.o $(O)drawing.o $(O)dungeon.o $(O)eat.o VOBJ07 = $(O)end.o $(O)engrave.o $(O)exper.o $(O)explode.o VOBJ08 = $(O)extralev.o $(O)files.o $(O)fountain.o $(O)hack.o VOBJ09 = $(O)hacklib.o $(O)invent.o $(O)light.o $(O)lock.o VOBJ10 = $(O)mail.o $(O)pcmain.o $(O)makemon.o $(O)mapglyph.o $(O)mcastu.o VOBJ11 = $(O)mhitm.o $(O)mhitu.o $(O)minion.o $(O)mklev.o VOBJ12 = $(O)mkmap.o $(O)mkmaze.o $(O)mkobj.o $(O)mkroom.o VOBJ13 = $(O)mon.o $(O)mondata.o $(O)monmove.o $(O)monst.o VOBJ14 = $(O)monstr.o $(O)mplayer.o $(O)mthrowu.o $(O)muse.o VOBJ15 = $(O)music.o $(O)o_init.o $(O)objects.o $(O)objnam.o VOBJ16 = $(O)options.o $(O)pager.o $(O)pickup.o $(O)pline.o VOBJ17 = $(O)polyself.o $(O)potion.o $(O)pray.o $(O)priest.o VOBJ18 = $(O)quest.o $(O)questpgr.o $(RANDOM) $(O)read.o VOBJ19 = $(O)rect.o $(O)region.o $(O)restore.o $(O)rip.o VOBJ20 = $(O)rnd.o $(O)role.o $(O)rumors.o $(O)save.o VOBJ21 = $(O)shk.o $(O)shknam.o $(O)sit.o $(O)sounds.o VOBJ22 = $(O)sp_lev.o $(O)spell.o $(O)steal.o $(O)steed.o VOBJ23 = $(O)teleport.o $(O)timeout.o $(O)topten.o $(O)track.o VOBJ24 = $(O)trap.o $(O)u_init.o $(O)uhitm.o $(O)vault.o VOBJ25 = $(O)vis_tab.o $(O)vision.o $(O)weapon.o $(O)were.o VOBJ26 = $(O)wield.o $(O)windows.o $(O)wizard.o $(O)worm.o VOBJ27 = $(O)worn.o $(O)write.o $(O)zap.o DLBOBJ = $(O)dlb.o TTYOBJ = $(O)topl.o $(O)getline.o $(O)wintty.o SOBJ = $(O)winnt.o $(O)pcsys.o $(O)pcunix.o \ $(SOUND) $(O)mapimail.o $(O)nhlan.o OBJS = $(VOBJ01) $(VOBJ02) $(VOBJ03) $(VOBJ04) $(VOBJ05) \ $(VOBJ06) $(VOBJ07) $(VOBJ08) $(VOBJ09) $(VOBJ10) \ $(VOBJ11) $(VOBJ12) $(VOBJ13) $(VOBJ14) $(VOBJ15) \ $(VOBJ16) $(VOBJ17) $(VOBJ18) $(VOBJ19) $(VOBJ20) \ $(VOBJ21) $(VOBJ22) $(VOBJ23) $(VOBJ24) $(VOBJ25) \ $(VOBJ26) $(VOBJ27) WINPOBJ = $(WINPORT) VVOBJ = $(O)version.o ALLOBJ = $(WINPOBJ) $(SOBJ) $(DLBOBJ) $(TTYOBJ) $(WOBJ) $(OBJS) $(VVOBJ) !IF "$(GRAPHICAL)" == "Y" OPTIONS_FILE = $(DAT)\guioptions !ELSE OPTIONS_FILE = $(DAT)\ttyoptions !ENDIF #========================================== # Header file macros #========================================== CONFIG_H = $(INCL)\config.h $(INCL)\config1.h $(INCL)\tradstdc.h \ $(INCL)\global.h $(INCL)\coord.h $(INCL)\vmsconf.h \ $(INCL)\system.h $(INCL)\unixconf.h $(INCL)\os2conf.h \ $(INCL)\micro.h $(INCL)\pcconf.h $(INCL)\tosconf.h \ $(INCL)\amiconf.h $(INCL)\macconf.h $(INCL)\beconf.h \ $(INCL)\ntconf.h $(INCL)\nhlan.h HACK_H = $(INCL)\hack.h $(CONFIG_H) $(INCL)\align.h \ $(INCL)\dungeon.h $(INCL)\monsym.h $(INCL)\mkroom.h \ $(INCL)\objclass.h $(INCL)\youprop.h $(INCL)\prop.h \ $(INCL)\permonst.h $(INCL)\monattk.h \ $(INCL)\monflag.h $(INCL)\mondata.h $(INCL)\pm.h \ $(INCL)\wintype.h $(INCL)\decl.h $(INCL)\quest.h \ $(INCL)\spell.h $(INCL)\color.h $(INCL)\obj.h \ $(INCL)\you.h $(INCL)\attrib.h $(INCL)\monst.h \ $(INCL)\skills.h $(INCL)\onames.h $(INCL)\timeout.h \ $(INCL)\trap.h $(INCL)\flag.h $(INCL)\rm.h \ $(INCL)\vision.h $(INCL)\display.h $(INCL)\engrave.h \ $(INCL)\rect.h $(INCL)\region.h $(INCL)\winprocs.h \ $(INCL)\wintty.h $(INCL)\trampoli.h LEV_H = $(INCL)\lev.h DGN_FILE_H = $(INCL)\dgn_file.h LEV_COMP_H = $(INCL)\lev_comp.h SP_LEV_H = $(INCL)\sp_lev.h TILE_H = ..\win\share\tile.h #========================================== # Miscellaneous #========================================== DATABASE = $(DAT)\data.base # # The name of the game. # GAMEFILE = $(GAMEDIR)\$(GAME).exe #========================================== #=============== TARGETS ================== #========================================== # # The default make target (so just typing 'nmake' is useful). # default : $(GAMEFILE) # # The main target. # $(GAME): $(O)obj.tag $(O)utility.tag envchk $(GAMEFILE) @echo $(GAME) is up to date. # # Everything # all : install install: envchk $(GAME) $(O)install.tag @echo Done. $(O)install.tag: $(DAT)\data $(DAT)\rumors $(DAT)\dungeon \ $(DAT)\oracles $(DAT)\quest.dat $(O)sp_lev.tag $(DLB) ! IF ("$(USE_DLB)"=="Y") copy nhdat $(GAMEDIR) copy $(DAT)\license $(GAMEDIR) copy $(DAT)\opthelp $(GAMEDIR) ! ELSE copy $(DAT)\*. $(GAMEDIR) copy $(DAT)\*.dat $(GAMEDIR) copy $(DAT)\*.lev $(GAMEDIR) if exist $(GAMEDIR)\makefile del $(GAMEDIR)\makefile ! ENDIF if exist $(DOC)\guidebook.txt copy $(DOC)\guidebook.txt $(GAMEDIR)\Guidebook.txt if exist $(DOC)\nethack.txt copy $(DOC)\nethack.txt $(GAMEDIR)\NetHack.txt @if exist $(SRC)\$(GAME).PDB copy $(SRC)\$(GAME).pdb $(GAMEDIR)\$(GAME).pdb @if exist $(GAMEDIR)\$(GAME).PDB echo NOTE: You may want to remove $(GAMEDIR)\$(GAME).pdb to conserve space -copy $(NTSYS)\defaults.nh $(GAMEDIR)\defaults.nh echo install done > $@ # copy $(NTSYS)\winnt.hlp $(GAMEDIR) recover: $(U)recover.exe if exist $(U)recover.exe copy $(U)recover.exe $(GAMEDIR) if exist $(DOC)\recover.txt copy $(DOC)\recover.txt $(GAMEDIR)\recover.txt $(O)sp_lev.tag: $(O)utility.tag $(DAT)\bigroom.des $(DAT)\castle.des \ $(DAT)\endgame.des $(DAT)\gehennom.des $(DAT)\knox.des \ $(DAT)\medusa.des $(DAT)\oracle.des $(DAT)\tower.des \ $(DAT)\yendor.des $(DAT)\arch.des $(DAT)\barb.des \ $(DAT)\caveman.des $(DAT)\healer.des $(DAT)\knight.des \ $(DAT)\monk.des $(DAT)\priest.des $(DAT)\ranger.des \ $(DAT)\rogue.des $(DAT)\samurai.des $(DAT)\sokoban.des \ $(DAT)\tourist.des $(DAT)\valkyrie.des $(DAT)\wizard.des cd $(DAT) $(U)lev_comp bigroom.des $(U)lev_comp castle.des $(U)lev_comp endgame.des $(U)lev_comp gehennom.des $(U)lev_comp knox.des $(U)lev_comp mines.des $(U)lev_comp medusa.des $(U)lev_comp oracle.des $(U)lev_comp sokoban.des $(U)lev_comp tower.des $(U)lev_comp yendor.des $(U)lev_comp arch.des $(U)lev_comp barb.des $(U)lev_comp caveman.des $(U)lev_comp healer.des $(U)lev_comp knight.des $(U)lev_comp monk.des $(U)lev_comp priest.des $(U)lev_comp ranger.des $(U)lev_comp rogue.des $(U)lev_comp samurai.des $(U)lev_comp tourist.des $(U)lev_comp valkyrie.des $(U)lev_comp wizard.des cd $(SRC) echo sp_levs done > $(O)sp_lev.tag $(O)utility.tag: $(INCL)\date.h $(INCL)\onames.h $(INCL)\pm.h \ $(SRC)\monstr.c $(SRC)\vis_tab.c \ $(U)lev_comp.exe $(INCL)\vis_tab.h \ $(U)dgn_comp.exe @echo utilities made >$@ @echo utilities made. tileutil: $(U)gif2txt.exe $(U)gif2tx32.exe $(U)txt2ppm.exe @echo Optional tile development utilities are up to date. !IF "$(GRAPHICAL)"=="Y" $(NHRES): $(TILEBMP16) $(WIN32)\winhack.rc $(WIN32)\mnsel.bmp \ $(WIN32)\mnselcnt.bmp $(WIN32)\mnunsel.bmp \ $(WIN32)\petmark.bmp $(WIN32)\NetHack.ico $(WIN32)\rip.bmp \ $(WIN32)\splash.bmp @$(rc) -r -fo$@ -i$(WIN32) -dNDEBUG $(WIN32)\winhack.rc !ELSE $(NHRES): $(NTSYS)\console.rc $(NTSYS)\NetHack.ico @$(rc) -r -fo$@ -i$(NTSYS) -dNDEBUG $(NTSYS)\console.rc !ENDIF #========================================== # The main target. #========================================== # The section for linking the NetHack image looks a little strange at # first, especially if you are used to UNIX makes, or NDMAKE. It is # Microsoft nmake specific, and it gets around the problem of the # link command line being too long for the linker. An "in-line" linker # response file is generated temporarily. # # It takes advantage of the following features of nmake: # # Inline files : # Specifying the "<<" means to start an inline file. # Another "<<" at the start of a line closes the # inline file. # # Substitution within Macros: # $(mymacro:string1=string2) replaces every # occurrence of string1 with string2 in the # macro mymacro. Special ascii key codes may be # used in the substitution text by preceding it # with ^ as we have done below. Every occurence # of a in $(ALLOBJ) is replaced by # <+>. # # DO NOT INDENT THE << below! # $(GAMEFILE) : $(ALLOBJ) $(NHRES) $(O)gamedir.tag $(WINDLLS) @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo Linking.... $(link) $(LFLAGS) user32.lib winmm.lib -out:$@ @<<$(GAME).lnk $(ALLOBJ:^ =^ ) $(NHRES) << @if exist $(O)install.tag del $(O)install.tag @if exist $(GAMEDIR)\$(GAME).bak del $(GAMEDIR)\$(GAME).bak $(O)gamedir.tag: @if not exist $(GAMEDIR)\*.* echo creating directory $(GAMEDIR) @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo directory created > $@ $(O)nhdefkey.def: @echo EXPORTS >$@ @echo ProcessKeystroke >>$@ @echo NHkbhit >>$@ @echo CheckInput >>$@ @echo SourceWhere >>$@ @echo SourceAuthor >>$@ @echo KeyHandlerName >>$@ $(GAMEDIR)\nhdefkey.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def @echo Linking $@ @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \ /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \ /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o $(O)nh340key.def: @echo EXPORTS >$@ @echo ProcessKeystroke >>$@ @echo NHkbhit >>$@ @echo CheckInput >>$@ @echo SourceWhere >>$@ @echo SourceAuthor >>$@ @echo KeyHandlerName >>$@ $(GAMEDIR)\nh340key.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def @echo Linking $@ @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \ /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \ /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o $(O)nhraykey.def: @echo EXPORTS >$@ @echo ProcessKeystroke >>$@ @echo NHkbhit >>$@ @echo CheckInput >>$@ @echo SourceWhere >>$@ @echo SourceAuthor >>$@ @echo KeyHandlerName >>$@ $(GAMEDIR)\nhraykey.dll : $(O)$(@B).o $(O)gamedir.tag $(O)$(@B).def @echo Linking $@ @$(link) -debug:full -debugtype:cv /RELEASE /NOLOGO /DLL user32.lib \ /PDB:"$(@B).PDB" /MAP:"$(@B).map" /DEF:$(O)$(@B).def \ /IMPLIB:$(O)$(@B).lib -out:$@ $(O)$(@B).o # # Secondary Targets. # #========================================== # Makedefs Stuff #========================================== $(U)makedefs.exe: $(MAKEOBJS) @$(link) $(LFLAGSU) -out:$@ $(MAKEOBJS) $(O)makedefs.o: $(CONFIG_H) $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\objclass.h \ $(INCL)\monsym.h $(INCL)\qtext.h $(INCL)\patchlevel.h \ $(U)makedefs.c @if not exist $(OBJ)\*.* echo creating directory $(OBJ) @if not exist $(OBJ)\*.* mkdir $(OBJ) @$(CC) $(CFLAGSU) -Fo$@ $(U)makedefs.c # # date.h should be remade every time any of the source or include # files is modified. # $(INCL)\date.h $(OPTIONS_FILE) : $(U)makedefs.exe $(U)makedefs -v $(INCL)\onames.h : $(U)makedefs.exe $(U)makedefs -o $(INCL)\pm.h : $(U)makedefs.exe $(U)makedefs -p #$(INCL)\trap.h : $(U)makedefs.exe # $(U)makedefs -t $(SRC)\monstr.c: $(U)makedefs.exe $(U)makedefs -m $(INCL)\vis_tab.h: $(U)makedefs.exe $(U)makedefs -z $(SRC)\vis_tab.c: $(U)makedefs.exe $(U)makedefs -z #========================================== # uudecode utility and uuencoded targets #========================================== $(U)uudecode.exe: $(O)uudecode.o @$(link) $(LFLAGSU) -out:$@ $(O)uudecode.o $(O)uudecode.o: $(SSYS)\uudecode.c $(NTSYS)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu chdir $(NTSYS) ..\..\util\uudecode.exe nhico.uu chdir ..\..\src $(WIN32)\NetHack.ico : $(U)uudecode.exe $(NTSYS)\nhico.uu chdir $(WIN32) ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu chdir ..\..\src $(WIN32)\mnsel.bmp: $(U)uudecode.exe $(WIN32)\mnsel.uu chdir $(WIN32) ..\..\util\uudecode.exe mnsel.uu chdir ..\..\src $(WIN32)\mnselcnt.bmp: $(U)uudecode.exe $(WIN32)\mnselcnt.uu chdir $(WIN32) ..\..\util\uudecode.exe mnselcnt.uu chdir ..\..\src $(WIN32)\mnunsel.bmp: $(U)uudecode.exe $(WIN32)\mnunsel.uu chdir $(WIN32) ..\..\util\uudecode.exe mnunsel.uu chdir ..\..\src $(WIN32)\petmark.bmp: $(U)uudecode.exe $(WIN32)\petmark.uu chdir $(WIN32) ..\..\util\uudecode.exe petmark.uu chdir ..\..\src $(WIN32)\rip.bmp: $(U)uudecode.exe $(WIN32)\rip.uu chdir $(WIN32) ..\..\util\uudecode.exe rip.uu chdir ..\..\src $(WIN32)\splash.bmp: $(U)uudecode.exe $(WIN32)\splash.uu chdir $(WIN32) ..\..\util\uudecode.exe splash.uu chdir ..\..\src #========================================== # Level Compiler Stuff #========================================== LEVCFLAGS=-c -nologo -DWINVER=0x0400 -DWIN32 -D_WIN32 \ -D_MT -MT -I..\include -nologo -Z7 -Od -DDLB $(U)lev_comp.exe: $(SPLEVOBJS) @echo Linking $@... @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(SPLEVOBJS:^ =^ ) << $(O)lev_yacc.o: $(HACK_H) $(SP_LEV_H) $(INCL)\lev_comp.h $(U)lev_yacc.c @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_yacc.c $(O)lev_$(LEX).o: $(HACK_H) $(INCL)\lev_comp.h $(SP_LEV_H) \ $(U)lev_$(LEX).c @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_$(LEX).c $(O)lev_main.o: $(U)lev_main.c $(HACK_H) $(SP_LEV_H) @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)lev_main.c $(U)lev_yacc.c $(INCL)\lev_comp.h : $(U)lev_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" chdir $(UTIL) $(YACC) -d lev_comp.y copy $(YTABC) lev_yacc.c copy $(YTABH) $(INCL)\lev_comp.h @del $(YTABC) @del $(YTABH) chdir $(SRC) ! ELSE @echo $(U)lev_comp.y has changed. @echo To update $(U)lev_yacc.c and $(INCL)\lev_comp.h run $(YACC). @echo --- @echo For now, we will copy the prebuilt lev_yacc.c and @echo lev_comp.h from $(SSYS) into $(UTIL) and use them. @copy $(SSYS)\lev_yacc.c $(U)lev_yacc.c >nul @copy $(SSYS)\lev_comp.h $(INCL)\lev_comp.h >nul @echo /**/ >>$(U)lev_yacc.c @echo /**/ >>$(INCL)\lev_comp.h ! ENDIF $(U)lev_$(LEX).c: $(U)lev_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" chdir $(UTIL) $(LEX) $(FLEXSKEL) lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) chdir $(SRC) ! ELSE @echo $(U)lev_comp.l has changed. To update $@ run $(LEX). @echo --- @echo For now, we will copy the prebuilt lev_lex.c @echo from $(SSYS) into $(UTIL) and use it. @copy $(SSYS)\lev_lex.c $@ >nul @echo /**/ >>$@ ! ENDIF #========================================== # Dungeon Compiler Stuff #========================================== $(U)dgn_comp.exe: $(DGNCOMPOBJS) @echo Linking $@... @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(DGNCOMPOBJS:^ =^ ) << $(O)dgn_yacc.o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h $(U)dgn_yacc.c @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_yacc.c $(O)dgn_$(LEX).o: $(HACK_H) $(DGN_FILE_H) $(INCL)\dgn_comp.h \ $(U)dgn_$(LEX).c @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_$(LEX).c $(O)dgn_main.o: $(HACK_H) $(U)dgn_main.c @$(CC) $(LEVCFLAGS) -W0 -Fo$@ $(U)dgn_main.c $(U)dgn_yacc.c $(INCL)\dgn_comp.h : $(U)dgn_comp.y ! IF "$(DO_YACC)"=="YACC_ACT" chdir $(UTIL) $(YACC) -d dgn_comp.y copy $(YTABC) dgn_yacc.c copy $(YTABH) $(INCL)\dgn_comp.h @del $(YTABC) @del $(YTABH) chdir $(SRC) ! ELSE @echo $(U)dgn_comp.y has changed. To update dgn_yacc.c and @echo $(INCL)\dgn_comp.h run $(YACC). @echo --- @echo For now, we will copy the prebuilt $(U)dgn_yacc.c and @echo dgn_comp.h from $(SSYS) into $(UTIL) and use them. @copy $(SSYS)\dgn_yacc.c $(U)dgn_yacc.c >nul @copy $(SSYS)\dgn_comp.h $(INCL)\dgn_comp.h >nul @echo /**/ >>$(U)dgn_yacc.c @echo /**/ >>$(INCL)\dgn_comp.h ! ENDIF $(U)dgn_$(LEX).c: $(U)dgn_comp.l ! IF "$(DO_LEX)"=="LEX_ACT" chdir $(UTIL) $(LEX) $(FLEXSKEL) dgn_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) chdir $(SRC) ! ELSE @echo $(U)dgn_comp.l has changed. To update $@ run $(LEX). @echo --- @echo For now, we will copy the prebuilt dgn_lex.c @echo from $(SSYS) into $(UTIL) and use it. @copy $(SSYS)\dgn_lex.c $@ >nul @echo /**/ >>$@ ! ENDIF #========================================== # Create directory for holding object files #========================================== $(O)obj.tag: @if not exist $(OBJ)\*.* echo creating directory $(OBJ) @if not exist $(OBJ)\*.* mkdir $(OBJ) @echo directory created >$@ #========================================== # Notify of any CL environment variables # in effect since they change the compiler # options. #========================================== envchk: ! IF "$(CL)"!="" @echo Warning, the CL Environment variable is defined: @echo CL=$(CL) ! ENDIF ! IF "$(GRAPHICAL)"=="Y" @echo ---- @echo NOTE: This build will include tile support. @echo ---- ! ENDIF #========================================== #=========== SECONDARY TARGETS ============ #========================================== #=========================================== # Header files NOT distributed in ..\include #=========================================== $(INCL)\win32api.h: $(NTSYS)\win32api.h copy $(NTSYS)\win32api.h $@ #========================================== # DLB utility and nhdat file creation #========================================== $(U)dlb_main.exe: $(DLBOBJ) $(O)dlb.o @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)dlb_main.o $(O)dlb.o $(O)alloc.o $(O)panic.o << $(O)dlb.o: $(O)dlb_main.o $(O)alloc.o $(O)panic.o $(INCL)\dlb.h @$(CC) $(CFLAGS) /Fo$@ $(SRC)\dlb.c $(O)dlb_main.o: $(UTIL)\dlb_main.c $(INCL)\config.h $(INCL)\dlb.h @$(CC) $(CFLAGS) /Fo$@ $(UTIL)\dlb_main.c $(DAT)\porthelp: $(NTSYS)\porthelp @copy $(NTSYS)\porthelp $@ >nul nhdat: $(U)dlb_main.exe $(DAT)\data $(DAT)\oracles $(OPTIONS_FILE) \ $(DAT)\quest.dat $(DAT)\rumors $(DAT)\help $(DAT)\hh $(DAT)\cmdhelp \ $(DAT)\history $(DAT)\opthelp $(DAT)\wizhelp $(DAT)\dungeon $(DAT)\porthelp \ $(DAT)\license $(O)sp_lev.tag cd $(DAT) echo data >dlb.lst echo oracles >>dlb.lst if exist options echo options >>dlb.lst if exist ttyoptions echo ttyoptions >>dlb.lst if exist guioptions echo guioptions >>dlb.lst if exist porthelp echo porthelp >>dlb.lst echo quest.dat >>dlb.lst echo rumors >>dlb.lst echo help >>dlb.lst echo hh >>dlb.lst echo cmdhelp >>dlb.lst echo history >>dlb.lst echo opthelp >>dlb.lst echo wizhelp >>dlb.lst echo dungeon >>dlb.lst echo license >>dlb.lst for %%N in (*.lev) do echo %%N >>dlb.lst $(U)dlb_main cIf dlb.lst $(SRC)\nhdat cd $(SRC) #========================================== # Recover Utility #========================================== $(U)recover.exe: $(RECOVOBJS) $(link) $(LFLAGSU) -out:$@ $(RECOVOBJS) $(O)recover.o: $(CONFIG_H) $(U)recover.c $(INCL)\win32api.h $(CC) $(CFLAGSU) -Fo$@ $(U)recover.c #========================================== # Tile Mapping #========================================== $(SRC)\tile.c: $(U)tilemap.exe @echo A new $@ has been created @$(U)tilemap $(U)tilemap.exe: $(O)tilemap.o @$(link) $(LFLAGSU) -out:$@ $(O)tilemap.o $(O)tilemap.o: $(WSHR)\tilemap.c $(HACK_H) @$(CC) $(CFLAGSU) -Fo$@ $(WSHR)\tilemap.c $(O)tiletx32.o: $(WSHR)\tilemap.c $(HACK_H) @$(CC) $(CFLAGS) /DTILETEXT /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tilemap.c $(O)tiletxt.o: $(WSHR)\tilemap.c $(HACK_H) @$(CC) $(CFLAGS) /DTILETEXT -Fo$@ $(WSHR)\tilemap.c $(O)gifread.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\gifread.c $(O)gifrd32.o: $(WSHR)\gifread.c $(CONFIG_H) $(TILE_H) @$(CC) $(CFLAGS) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\gifread.c $(O)ppmwrite.o: $(WSHR)\ppmwrite.c $(CONFIG_H) $(TILE_H) @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\ppmwrite.c $(O)tiletext.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(WSHR)\tiletext.c $(O)tilete32.o: $(WSHR)\tiletext.c $(CONFIG_H) $(TILE_H) @$(CC) $(CFLAGS) -I$(WSHR) /DTILE_X=32 /DTILE_Y=32 -Fo$@ $(WSHR)\tiletext.c #========================================== # Optional Tile Utilities #========================================== $(U)gif2txt.exe: $(GIFREADERS) $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(GIFREADERS:^ =^ ) $(TEXT_IO:^ =^ ) << $(U)gif2tx32.exe: $(GIFREADERS32) $(TEXT_IO32) @echo Linking $@... @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(GIFREADERS32:^ =^ ) $(TEXT_IO32:^ =^ ) << $(U)txt2ppm.exe: $(PPMWRITERS) $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(PPMWRITERS:^ =^ ) $(TEXT_IO:^ =^ ) << !IF "$(GRAPHICAL)"=="Y" $(TILEBMP16): $(TILEUTIL16) $(TILEFILES) @echo Creating 16x16 binary tile files (this may take some time) @$(U)tile2bmp $(TILEBMP16) #$(TILEBMP32): $(TILEUTIL32) $(TILEFILES32) # @echo Creating 32x32 binary tile files (this may take some time) # @$(U)til2bm32 $(TILEBMP32) !ELSE $(TILEBMP16): $(TILEBMP32): !ENDIF $(U)tile2bmp.exe: $(O)tile2bmp.o $(TEXT_IO) @echo Linking $@... @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)tile2bmp.o $(TEXT_IO:^ =^ ) << $(U)til2bm32.exe: $(O)til2bm32.o $(TEXT_IO32) @echo Linking $@... @$(link) $(LFLAGSU) -out:$@ @<<$(@B).lnk $(O)til2bm32.o $(TEXT_IO32:^ =^ ) << $(O)tile2bmp.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h @$(CC) $(CFLAGS) -I$(WSHR) /DPACKED_FILE /Fo$@ $(WSHR)\tile2bmp.c $(O)til2bm32.o: $(WSHR)\tile2bmp.c $(HACK_H) $(TILE_H) $(INCL)\win32api.h @$(CC) $(CFLAGS) -I$(WSHR) /DPACKED_FILE /DTILE_X=32 /DTILE_Y=32 /Fo$@ $(WSHR)\tile2bmp.c #========================================== # Housekeeping #========================================== spotless: clean ! IF ("$(OBJ)"!="") -rmdir $(OBJ) /s /Q ! ENDIF if exist $(INCL)\date.h del $(INCL)\date.h if exist $(INCL)\onames.h del $(INCL)\onames.h if exist $(INCL)\pm.h del $(INCL)\pm.h if exist $(INCL)\vis_tab.h del $(INCL)\vis_tab.h if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(SRC)\tile.c del $(SRC)\tile.c if exist $(U)*.lnk del $(U)*.lnk if exist $(U)*.map del $(U)*.map if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\???-fil?.lev del $(DAT)\???-fil?.lev if exist $(DAT)\???-goal.lev del $(DAT)\???-goal.lev if exist $(DAT)\???-loca.lev del $(DAT)\???-loca.lev if exist $(DAT)\???-strt.lev del $(DAT)\???-strt.lev if exist $(DAT)\air.lev del $(DAT)\air.lev if exist $(DAT)\asmodeus.lev del $(DAT)\asmodeus.lev if exist $(DAT)\astral.lev del $(DAT)\astral.lev if exist $(DAT)\baalz.lev del $(DAT)\baalz.lev if exist $(DAT)\bigroom.lev del $(DAT)\bigroom.lev if exist $(DAT)\castle.lev del $(DAT)\castle.lev if exist $(DAT)\data del $(DAT)\data if exist $(DAT)\dungeon del $(DAT)\dungeon if exist $(DAT)\dungeon.pdf del $(DAT)\dungeon.pdf if exist $(DAT)\earth.lev del $(DAT)\earth.lev if exist $(DAT)\fakewiz?.lev del $(DAT)\fakewiz?.lev if exist $(DAT)\fire.lev del $(DAT)\fire.lev if exist $(DAT)\juiblex.lev del $(DAT)\juiblex.lev if exist $(DAT)\knox.lev del $(DAT)\knox.lev if exist $(DAT)\medusa-?.lev del $(DAT)\medusa-?.lev if exist $(DAT)\mine*.lev del $(DAT)\mine*.lev if exist $(DAT)\options del $(DAT)\options if exist $(DAT)\ttyoptions del $(DAT)\ttyoptions if exist $(DAT)\guioptions del $(DAT)\guioptions if exist $(DAT)\oracle.lev del $(DAT)\oracle.lev if exist $(DAT)\oracles del $(DAT)\oracles if exist $(DAT)\orcus.lev del $(DAT)\orcus.lev if exist $(DAT)\rumors del $(DAT)\rumors if exist $(DAT)\quest.dat del $(DAT)\quest.dat if exist $(DAT)\sanctum.lev del $(DAT)\sanctum.lev if exist $(DAT)\soko?-?.lev del $(DAT)\soko?-?.lev if exist $(DAT)\tower?.lev del $(DAT)\tower?.lev if exist $(DAT)\valley.lev del $(DAT)\valley.lev if exist $(DAT)\water.lev del $(DAT)\water.lev if exist $(DAT)\wizard?.lev del $(DAT)\wizard?.lev if exist $(O)sp_lev.tag del $(O)sp_lev.tag if exist $(SRC)\monstr.c del $(SRC)\monstr.c if exist $(SRC)\vis_tab.c del $(SRC)\vis_tab.c if exist $(U)recover.exe del $(U)recover.exe if exist nhdat. del nhdat. if exist $(O)obj.tag del $(O)obj.tag if exist $(O)gamedir.tag del $(O)gamedir.tag if exist $(O)nh*key.lib del $(O)nh*key.lib if exist $(O)nh*key.exp del $(O)nh*key.exp clean: if exist $(O)*.o del $(O)*.o if exist $(O)utility.tag del $(O)utility.tag if exist $(U)makedefs.exe del $(U)makedefs.exe if exist $(U)lev_comp.exe del $(U)lev_comp.exe if exist $(U)dgn_comp.exe del $(U)dgn_comp.exe if exist $(SRC)\*.lnk del $(SRC)\*.lnk if exist $(SRC)\*.map del $(SRC)\*.map if exist $(O)install.tag del $(O)install.tag ! IF ("$(WINPFLAG)"!="") if exist $(TILEBMP16) del $(TILEBMP16) if exist $(TILEBMP32) del $(TILEBMP32) ! ENDIF #=================================================================== # OTHER DEPENDENCIES #=================================================================== # # dat dependencies # $(DAT)\data: $(O)utility.tag $(DATABASE) $(U)makedefs -d $(DAT)\rumors: $(O)utility.tag $(DAT)\rumors.tru $(DAT)\rumors.fal $(U)makedefs -r $(DAT)\quest.dat: $(O)utility.tag $(DAT)\quest.txt $(U)makedefs -q $(DAT)\oracles: $(O)utility.tag $(DAT)\oracles.txt $(U)makedefs -h $(DAT)\dungeon: $(O)utility.tag $(DAT)\dungeon.def $(U)makedefs -e cd $(DAT) $(U)dgn_comp dungeon.pdf cd $(SRC) # # NT dependencies # $(O)nttty.o: $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nttty.c @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(NTSYS)\nttty.c $(O)nhkeys.o: $(HACK_H) $(TILE_H) $(INCL)\win32api.h $(NTSYS)\nhkeys.c @$(CC) $(CFLAGS) -I$(WSHR) -Fo$@ $(NTSYS)\nhkeys.c $(O)winnt.o: $(HACK_H) $(INCL)\win32api.h $(NTSYS)\winnt.c @$(CC) $(CFLAGS) -Fo$@ $(NTSYS)\winnt.c $(O)ntsound.o: $(HACK_H) $(NTSYS)\ntsound.c @$(CC) $(CFLAGS) -Fo$@ $(NTSYS)\ntsound.c $(O)mapimail.o: $(HACK_H) $(INCL)\nhlan.h $(NTSYS)\mapimail.c @$(CC) $(CFLAGS) -DMAPI_VERBOSE -Fo$@ $(NTSYS)\mapimail.c # # util dependencies # $(O)panic.o: $(U)panic.c $(CONFIG_H) @$(CC) $(CFLAGS) -Fo$@ $(U)panic.c # # The rest are stolen from sys/unix/Makefile.src, # with the following changes: # * ../include changed to $(INCL) # * slashes changed to back-slashes # * -c (which is included in CFLAGS) substituted with -Fo$@ # * targets prefixed with $(O) # but otherwise untouched. # That means that there is some irrelevant stuff # in here, but maintenance should be easier. # $(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(CFLAGS) -Fo$@ ..\sys\atari\tos.c $(O)pcmain.o: ..\sys\share\pcmain.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\win32api.h @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcmain.c $(O)pcsys.o: ..\sys\share\pcsys.c $(HACK_H) @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcsys.c $(O)pctty.o: ..\sys\share\pctty.c $(HACK_H) @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pctty.c $(O)pcunix.o: ..\sys\share\pcunix.c $(HACK_H) @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\pcunix.c $(O)random.o: ..\sys\share\random.c $(HACK_H) @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\random.c $(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\ioctl.c $(O)unixtty.o: ..\sys\share\unixtty.c $(HACK_H) @$(CC) $(CFLAGS) -Fo$@ ..\sys\share\unixtty.c $(O)unixmain.o: ..\sys\unix\unixmain.c $(HACK_H) $(INCL)\dlb.h @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixmain.c $(O)unixunix.o: ..\sys\unix\unixunix.c $(HACK_H) @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixunix.c $(O)unixres.o: ..\sys\unix\unixres.c $(CONFIG_H) @$(CC) $(CFLAGS) -Fo$@ ..\sys\unix\unixres.c $(O)bemain.o: ..\sys\be\bemain.c $(HACK_H) $(INCL)\dlb.h @$(CC) $(CFLAGS) -Fo$@ ..\sys\be\bemain.c $(O)getline.o: ..\win\tty\getline.c $(HACK_H) $(INCL)\func_tab.h @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\getline.c $(O)termcap.o: ..\win\tty\termcap.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\termcap.c $(O)topl.o: ..\win\tty\topl.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\topl.c $(O)wintty.o: ..\win\tty\wintty.c $(HACK_H) $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(INCL)\tcap.h @$(CC) $(CFLAGS) -Fo$@ ..\win\tty\wintty.c $(O)Window.o: ..\win\X11\Window.c $(INCL)\xwindowp.h $(INCL)\xwindow.h \ $(CONFIG_H) @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\Window.c $(O)dialogs.o: ..\win\X11\dialogs.c $(CONFIG_H) @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\dialogs.c $(O)winX.o: ..\win\X11\winX.c $(HACK_H) $(INCL)\winX.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h ..\win\X11\nh72icon \ ..\win\X11\nh56icon ..\win\X11\nh32icon @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winX.c $(O)winmap.o: ..\win\X11\winmap.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\dlb.h \ $(INCL)\winX.h $(INCL)\tile2x11.h @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmap.c $(O)winmenu.o: ..\win\X11\winmenu.c $(HACK_H) $(INCL)\winX.h @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmenu.c $(O)winmesg.o: ..\win\X11\winmesg.c $(INCL)\xwindow.h $(HACK_H) $(INCL)\winX.h @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmesg.c $(O)winmisc.o: ..\win\X11\winmisc.c $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\winX.h @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winmisc.c $(O)winstat.o: ..\win\X11\winstat.c $(HACK_H) $(INCL)\winX.h @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winstat.c $(O)wintext.o: ..\win\X11\wintext.c $(HACK_H) $(INCL)\winX.h $(INCL)\xwindow.h @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\wintext.c $(O)winval.o: ..\win\X11\winval.c $(HACK_H) $(INCL)\winX.h @$(CC) $(CFLAGS) -Fo$@ ..\win\X11\winval.c $(O)tile.o: $(SRC)\tile.c $(HACK_H) $(O)gnaskstr.o: ..\win\gnome\gnaskstr.c ..\win\gnome\gnaskstr.h \ ..\win\gnome\gnmain.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnaskstr.c $(O)gnbind.o: ..\win\gnome\gnbind.c ..\win\gnome\gnbind.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnaskstr.h ..\win\gnome\gnyesno.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnbind.c $(O)gnglyph.o: ..\win\gnome\gnglyph.c ..\win\gnome\gnglyph.h $(INCL)\tile2x11.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnglyph.c $(O)gnmain.o: ..\win\gnome\gnmain.c ..\win\gnome\gnmain.h ..\win\gnome\gnsignal.h \ ..\win\gnome\gnbind.h ..\win\gnome\gnopts.h $(HACK_H) \ $(INCL)\date.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmain.c $(O)gnmap.o: ..\win\gnome\gnmap.c ..\win\gnome\gnmap.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnsignal.h $(HACK_H) @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmap.c $(O)gnmenu.o: ..\win\gnome\gnmenu.c ..\win\gnome\gnmenu.h ..\win\gnome\gnmain.h \ ..\win\gnome\gnbind.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmenu.c $(O)gnmesg.o: ..\win\gnome\gnmesg.c ..\win\gnome\gnmesg.h ..\win\gnome\gnsignal.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnmesg.c $(O)gnopts.o: ..\win\gnome\gnopts.c ..\win\gnome\gnopts.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnmain.h ..\win\gnome\gnmap.h $(HACK_H) @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnopts.c $(O)gnplayer.o: ..\win\gnome\gnplayer.c ..\win\gnome\gnplayer.h \ ..\win\gnome\gnmain.h $(HACK_H) @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnplayer.c $(O)gnsignal.o: ..\win\gnome\gnsignal.c ..\win\gnome\gnsignal.h \ ..\win\gnome\gnmain.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnsignal.c $(O)gnstatus.o: ..\win\gnome\gnstatus.c ..\win\gnome\gnstatus.h \ ..\win\gnome\gnsignal.h ..\win\gnome\gn_xpms.h \ ..\win\gnome\gnomeprv.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnstatus.c $(O)gntext.o: ..\win\gnome\gntext.c ..\win\gnome\gntext.h ..\win\gnome\gnmain.h \ ..\win\gnome\gn_rip.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gntext.c $(O)gnworn.o: ..\win\gnome\gnworn.c ..\win\gnome\gnworn.h ..\win\gnome\gnglyph.h \ ..\win\gnome\gnsignal.h ..\win\gnome\gnomeprv.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnworn.c $(O)gnyesno.o: ..\win\gnome\gnyesno.c ..\win\gnome\gnbind.h ..\win\gnome\gnyesno.h @$(CC) $(CFLAGS) $(GNOMEINC) -Fo$@ ..\win\gnome\gnyesno.c $(O)wingem.o: ..\win\gem\wingem.c $(HACK_H) $(INCL)\func_tab.h $(INCL)\dlb.h \ $(INCL)\patchlevel.h $(INCL)\wingem.h @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\wingem.c $(O)wingem1.o: ..\win\gem\wingem1.c $(INCL)\gem_rsc.h $(INCL)\load_img.h \ $(INCL)\gr_rect.h $(INCL)\wintype.h $(INCL)\wingem.h @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\wingem1.c $(O)load_img.o: ..\win\gem\load_img.c $(INCL)\load_img.h @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\load_img.c $(O)gr_rect.o: ..\win\gem\gr_rect.c $(INCL)\gr_rect.h @$(CC) $(CFLAGS) -Fo$@ ..\win\gem\gr_rect.c $(O)tile.o: tile.c $(HACK_H) $(O)qt_win.o: ..\win\Qt\qt_win.cpp $(HACK_H) $(INCL)\func_tab.h \ $(INCL)\dlb.h $(INCL)\patchlevel.h $(INCL)\tile2x11.h \ $(INCL)\qt_win.h $(INCL)\qt_clust.h $(INCL)\qt_kde0.h \ $(INCL)\qt_xpms.h qt_win.moc qt_kde0.moc qttableview.moc $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_win.cpp $(O)qt_clust.o: ..\win\Qt\qt_clust.cpp $(INCL)\qt_clust.h $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qt_clust.cpp $(O)qttableview.o: ..\win\Qt\qttableview.cpp $(INCL)\qttableview.h $(CXX) $(CXXFLAGS) -Fo$@ ..\win\Qt\qttableview.cpp $(O)monstr.o: monstr.c $(CONFIG_H) $(O)vis_tab.o: vis_tab.c $(CONFIG_H) $(INCL)\vis_tab.h $(O)allmain.o: allmain.c $(HACK_H) $(O)alloc.o: alloc.c $(CONFIG_H) $(O)apply.o: apply.c $(HACK_H) $(INCL)\edog.h $(O)artifact.o: artifact.c $(HACK_H) $(INCL)\artifact.h $(INCL)\artilist.h $(O)attrib.o: attrib.c $(HACK_H) $(O)ball.o: ball.c $(HACK_H) $(O)bones.o: bones.c $(HACK_H) $(INCL)\lev.h $(O)botl.o: botl.c $(HACK_H) $(O)cmd.o: cmd.c $(HACK_H) $(INCL)\func_tab.h $(O)dbridge.o: dbridge.c $(HACK_H) $(O)decl.o: decl.c $(HACK_H) $(O)detect.o: detect.c $(HACK_H) $(INCL)\artifact.h $(O)dig.o: dig.c $(HACK_H) $(INCL)\edog.h $(O)display.o: display.c $(HACK_H) $(O)dlb.o: dlb.c $(CONFIG_H) $(INCL)\dlb.h $(O)do.o: do.c $(HACK_H) $(INCL)\lev.h $(O)do_name.o: do_name.c $(HACK_H) $(O)do_wear.o: do_wear.c $(HACK_H) $(O)dog.o: dog.c $(HACK_H) $(INCL)\edog.h $(O)dogmove.o: dogmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h $(O)dokick.o: dokick.c $(HACK_H) $(INCL)\eshk.h $(O)dothrow.o: dothrow.c $(HACK_H) $(INCL)\edog.h $(O)drawing.o: drawing.c $(HACK_H) $(INCL)\tcap.h $(O)dungeon.o: dungeon.c $(HACK_H) $(INCL)\dgn_file.h $(INCL)\dlb.h $(O)eat.o: eat.c $(HACK_H) $(O)end.o: end.c $(HACK_H) $(INCL)\eshk.h $(INCL)\dlb.h $(O)engrave.o: engrave.c $(HACK_H) $(INCL)\lev.h $(O)exper.o: exper.c $(HACK_H) $(O)explode.o: explode.c $(HACK_H) $(O)extralev.o: extralev.c $(HACK_H) $(O)files.o: files.c $(HACK_H) $(INCL)\dlb.h $(O)fountain.o: fountain.c $(HACK_H) $(O)hack.o: hack.c $(HACK_H) $(O)hacklib.o: hacklib.c $(HACK_H) $(O)invent.o: invent.c $(HACK_H) $(O)light.o: light.c $(HACK_H) $(INCL)\lev.h $(O)lock.o: lock.c $(HACK_H) $(O)mail.o: mail.c $(HACK_H) $(INCL)\mail.h $(O)makemon.o: makemon.c $(HACK_H) $(INCL)\epri.h $(INCL)\emin.h \ $(INCL)\edog.h $(O)mapglyph.o: mapglyph.c $(HACK_H) $(O)mcastu.o: mcastu.c $(HACK_H) $(O)mhitm.o: mhitm.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h $(O)mhitu.o: mhitu.c $(HACK_H) $(INCL)\artifact.h $(INCL)\edog.h $(O)minion.o: minion.c $(HACK_H) $(INCL)\emin.h $(INCL)\epri.h $(O)mklev.o: mklev.c $(HACK_H) $(O)mkmap.o: mkmap.c $(HACK_H) $(INCL)\sp_lev.h $(O)mkmaze.o: mkmaze.c $(HACK_H) $(INCL)\sp_lev.h $(INCL)\lev.h $(O)mkobj.o: mkobj.c $(HACK_H) $(O)mkroom.o: mkroom.c $(HACK_H) $(O)mon.o: mon.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\edog.h $(O)mondata.o: mondata.c $(HACK_H) $(INCL)\eshk.h $(INCL)\epri.h $(O)monmove.o: monmove.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\artifact.h \ $(INCL)\epri.h $(O)monst.o: monst.c $(CONFIG_H) $(INCL)\permonst.h $(INCL)\align.h \ $(INCL)\monattk.h $(INCL)\monflag.h $(INCL)\monsym.h \ $(INCL)\dungeon.h $(INCL)\eshk.h $(INCL)\vault.h \ $(INCL)\epri.h $(INCL)\color.h $(O)mplayer.o: mplayer.c $(HACK_H) $(O)mthrowu.o: mthrowu.c $(HACK_H) $(O)muse.o: muse.c $(HACK_H) $(INCL)\edog.h $(O)music.o: music.c $(HACK_H) #interp.c $(O)o_init.o: o_init.c $(HACK_H) $(INCL)\lev.h $(O)objects.o: objects.c $(CONFIG_H) $(INCL)\obj.h $(INCL)\objclass.h \ $(INCL)\prop.h $(INCL)\skills.h $(INCL)\color.h $(O)objnam.o: objnam.c $(HACK_H) $(O)options.o: options.c $(CONFIG_H) $(INCL)\objclass.h $(INCL)\flag.h \ $(HACK_H) $(INCL)\tcap.h $(O)pager.o: pager.c $(HACK_H) $(INCL)\dlb.h $(O)pickup.o: pickup.c $(HACK_H) $(O)pline.o: pline.c $(HACK_H) $(INCL)\epri.h $(INCL)\edog.h $(O)polyself.o: polyself.c $(HACK_H) $(O)potion.o: potion.c $(HACK_H) $(O)pray.o: pray.c $(HACK_H) $(INCL)\epri.h $(O)priest.o: priest.c $(HACK_H) $(INCL)\mfndpos.h $(INCL)\eshk.h \ $(INCL)\epri.h $(INCL)\emin.h $(O)quest.o: quest.c $(HACK_H) $(INCL)\qtext.h $(O)questpgr.o: questpgr.c $(HACK_H) $(INCL)\dlb.h $(INCL)\qtext.h $(O)read.o: read.c $(HACK_H) $(O)rect.o: rect.c $(HACK_H) $(O)region.o: region.c $(HACK_H) $(INCL)\lev.h $(O)restore.o: restore.c $(HACK_H) $(INCL)\lev.h $(INCL)\tcap.h $(O)rip.o: rip.c $(HACK_H) $(O)rnd.o: rnd.c $(HACK_H) $(O)role.o: role.c $(HACK_H) $(O)rumors.o: rumors.c $(HACK_H) $(INCL)\lev.h $(INCL)\dlb.h $(O)save.o: save.c $(HACK_H) $(INCL)\lev.h $(O)shk.o: shk.c $(HACK_H) $(INCL)\eshk.h $(O)shknam.o: shknam.c $(HACK_H) $(INCL)\eshk.h $(O)sit.o: sit.c $(HACK_H) $(INCL)\artifact.h $(O)sounds.o: sounds.c $(HACK_H) $(INCL)\edog.h $(O)sp_lev.o: sp_lev.c $(HACK_H) $(INCL)\dlb.h $(INCL)\sp_lev.h $(O)spell.o: spell.c $(HACK_H) $(O)steal.o: steal.c $(HACK_H) $(O)steed.o: steed.c $(HACK_H) $(O)teleport.o: teleport.c $(HACK_H) $(O)timeout.o: timeout.c $(HACK_H) $(INCL)\lev.h $(O)topten.o: topten.c $(HACK_H) $(INCL)\dlb.h $(INCL)\patchlevel.h $(O)track.o: track.c $(HACK_H) $(O)trap.o: trap.c $(HACK_H) $(O)u_init.o: u_init.c $(HACK_H) $(O)uhitm.o: uhitm.c $(HACK_H) $(O)vault.o: vault.c $(HACK_H) $(INCL)\vault.h $(O)version.o: version.c $(HACK_H) $(INCL)\date.h $(INCL)\patchlevel.h $(O)vision.o: vision.c $(HACK_H) $(INCL)\vis_tab.h $(O)weapon.o: weapon.c $(HACK_H) $(O)were.o: were.c $(HACK_H) $(O)wield.o: wield.c $(HACK_H) $(O)windows.o: windows.c $(HACK_H) $(INCL)\wingem.h $(INCL)\winGnome.h $(O)wizard.o: wizard.c $(HACK_H) $(INCL)\qtext.h $(INCL)\epri.h $(O)worm.o: worm.c $(HACK_H) $(INCL)\lev.h $(O)worn.o: worn.c $(HACK_H) $(O)write.o: write.c $(HACK_H) $(O)zap.o: zap.c $(HACK_H) # end of file nethack-3.4.3/sys/winnt/console.rc0100644000000000000000000000233307764735041015620 0ustar rootroot/* SCCS Id: @(#)console.rc 3.4 $Date: 2003/10/14 01:31:28 $ */ /* Copyright (c) Yitzhak Sapir, 2002. */ /* NetHack may be freely redistributed. See license for details. */ #include "windows.h" 1 ICON DISCARDABLE "NetHack.ICO" ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,4,3,0 PRODUCTVERSION 3,4,3,0 FILEFLAGSMASK 0x1fL #ifdef _DEBUG FILEFLAGS 0x9L #else FILEFLAGS 0x8L #endif FILEOS 0x4L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "NetHack for Windows - TTY Interface\0" VALUE "FileVersion", "3.4.3\0" VALUE "InternalName", "NetHack\0" VALUE "LegalCopyright", "Copyright (C) 1985 - 2003. By Stichting Mathematisch Centrum and M. Stephenson. See license for details.\0" VALUE "OriginalFilename", "NetHack.exe\0" VALUE "PrivateBuild", "031014\0" VALUE "ProductName", "NetHack\0" VALUE "ProductVersion", "3.4.3\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END /*console.rc*/ nethack-3.4.3/sys/winnt/defaults.nh0100644000000000000000000001504407764735041015771 0ustar rootroot# Sample config file for win32 NetHack # A '#' at the beginning of a line means the rest of the line is a comment. # # Some options MUST be set in this file, other options can be toggled while # playing. For a list of options available see the file. # # To change the configuration, comment out the unwanted lines, and # uncomment the configuration you want. # *** OPTIONS *** # # Use the IBM character set rather than just plain ascii characters # for tty window-port. OPTIONS=IBMGraphics # Keyboard handling # Different keyboard handlers can be loaded. # Default is nhdefkey.dll but you can override that. # Ray Chason's keyboard handler # OPTIONS=altkeyhandler:nhraykey.dll # # NetHack 3.4.0 keyboard handling # OPTIONS=altkeyhandler:nh340key.dll # *** Personal Preferences *** # Some options to set personal preferences. Uncomment and change these to # suit your personal preference. If several people are to use the same # configuration, options like these should not be set. # #OPTIONS=name:Janet,role:Valkyrie,race:Human,gender:female,align:lawful #OPTIONS=dogname:Fido,catname:Morris,fruit:guava #OPTIONS=horsename:Silver #OPTIONS=autopickup,pickup_types:$"=/!?+ #OPTIONS=packorder:")[%?+/=!(*0_` #OPTIONS=scores:10 top/2 around/own #OPTIONS=nolegacy,noverbose #OPTIONS=menustyle:traditional # # General options. You might also set "silent" so as not to attract # the boss's attention. # # number_pad option can have an optional value of 0 (off), 1 (on), # or 2(on,legacy-mode) which causes 5='g', alt-5='G', alt-0='I' OPTIONS=time,noshowexp,number_pad:2,lit_corridor # # If you want to get rid of "use #quit to quit..." use: OPTIONS=suppress_alert:3.3.1 # # Note: the rest_on_space in the next line may not be # appropriate for a beginning NetHack player, since # it could result in use of a turn unintentionally. # If you're new to NetHack, leave it commented it out. #OPTIONS=rest_on_space # # Set some options to control graphical window-port (these will # be safely and silently ignored by the tty port) # # Map window settings # possible map_mode options include: tiles|ascii4x6|ascii6x8|ascii8x8|ascii16x8| # ascii7x12|ascii8x12|ascii16x12|ascii12x16| # ascii10x18|fit_to_screen OPTIONS=map_mode:tiles,scroll_margin:5 # Message window settings OPTIONS=font_message:Arial,font_size_message:9,align_message:top # Menu settings OPTIONS=font_menu:Arial,font_size_menu:9 # Text settings OPTIONS=font_text:Courier New,font_size_text:9 # Status window settings OPTIONS=font_status:Courier New,font_size_status:9 # Other OPTIONS=hilite_pet,!toptenwin #OPTIONS=!splash_screen,player_selection:prompts # Status/message window colors # Possible color options include: # six digit hexadecimal RGB color value ("#8F8F8F"), black, red, green, brown, # blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue, # brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia, # lime, olive, navy, teal, aqua, activeborder, activecaption, appworkspace, # background, btnface, btnshadow, btntext, captiontext, graytext, highlight, # highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar, # window, windowframe, windowtext. #OPTIONS=windowcolors:status windowtext/window message windowtext/window # *** LOCATIONS *** # IMPORTANT: If you change any of these locations, the directories they # point at must exist. NetHack will not create them for you. # # HACKDIR is the default location for everything. # Note: On Windows HACKDIR defaults to the location # of the NetHack.exe or NetHackw.exe file so # setting HACKDIR below to override that is # not usually necessary or recommended. #HACKDIR=c:\games\nethack # # The location that level files in progress are stored (default=HACKDIR, writeable) #LEVELDIR=c:\nethack\levels # # The location where saved games are kept (default=HACKDIR, writeable) #SAVEDIR=c:\nethack\save # # The location that bones files are kept (default=HACKDIR, writeable) #BONESDIR=c:\nethack\save # # The location that file synchronization locks are stored (default=HACKDIR, writeable) #LOCKDIR=c:\nethack\levels # # The location that a record of game aborts and self-diagnosed game problems # is kept (default=HACKDIR, writeable) #TROUBLEDIR=c:\nethack\trouble # Finnish keyboards might need these modifications uncommented. # For \, @, $, [, | #OPTIONS=subkeyvalue:171/92 #OPTIONS=subkeyvalue:178/64 #OPTIONS=subkeyvalue:180/36 #OPTIONS=subkeyvalue:184/91 #OPTIONS=subkeyvalue:188/124 # # *** CHARACTER GRAPHICS *** # # See the on-line help or the Guidebook for which symbols are in which # positions. # # If you merely set the IBMgraphics option as above, NetHack will use IBM # extended ASCII for dungeon characters. If you don't like the selections, # you can make up your own via these graphics options, but you should still # set IBMgraphics if you are using IBM graphics characters to get the correct # processing. # # ================================================ # An example using the IBM graphics character set: #DUNGEON= 032 179 196 218 191 192 217 197 193 194 \ # 180 195 249 239 239 254 254 240 241 249 \ # 177 177 060 062 060 062 220 124 190 035 \ # 244 247 249 247 042 042 186 205 046 035 \ # 247 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 232 232 232 157 094 094 \ # 094 094 # #EFFECTS= 179 196 092 047 042 033 041 040 \ # 048 035 064 042 \ # 047 045 092 058 058 092 045 047 \ # 047 045 092 058 032 058 092 045 047 # # ================================================ # Some alternatives: #DUNGEON= 032 186 205 201 187 200 188 206 202 203 \ # 185 204 249 239 239 254 254 240 241 249 \ # 177 177 060 062 060 062 095 124 092 035 \ # 244 247 249 247 042 042 179 196 046 035 \ # 247 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 034 094 094 094 094 \ # 094 094 # ================================================ # Here is a recommendation sent in by Michael Feir # for use by blind NetHack players. # #DUNGEON= 032 124 045 124 124 124 124 045 045 045 \ # 124 124 046 045 124 043 043 046 035 035 \ # 060 062 060 062 095 092 035 126 126 126 \ # 126 042 042 035 035 032 035 126 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 094 094 094 094 094 \ # 094 094 # #EFFECTS= 124 095 092 047 042 033 041 040 \ # 048 035 064 042 \ # 047 045 092 058 058 092 045 047 \ # 047 045 092 058 032 058 092 045 047 nethack-3.4.3/sys/winnt/mapimail.c0100644000000000000000000003122207764735041015564 0ustar rootroot/* SCCS Id: @(#)mapimail.c 3.4 $Date: 2002/07/24 08:25:20 $ */ /* Copyright (c) Michael Allison, 1997 */ /* NetHack may be freely redistributed. See license for details. */ #ifdef MAX_BODY_SIZE #undef MAX_BODY_SIZE #define MAX_BODY_SIZE 2048 /* largest body held in ram in bytes */ #endif #include "hack.h" # ifdef LAN_MAIL #include "win32api.h" #include #define MAPI_MSGID_SIZE 512 /* as recommended */ #define MAPI_LIB_FAIL 1 #define MAPI_FUNC_FAIL 2 HANDLE hLibrary; /* Handle for MAPI32.DLL */ LHANDLE MAPISession; /* Handle for MAPI session */ char MAPIMessageID[MAPI_MSGID_SIZE]; /* Msg ID from provider */ lpMapiMessage MAPIMessage; /* Ptr to message from prov */ struct lan_mail_struct received_msg; /* store received msg here */ #ifdef MAPI_VERBOSE FILE *dbgfile; #define MAPIDEBUGFILENAME "mapidebug.log" #endif /* * Prototypes for functions in this file * (Not in normal NetHack style, but its doubtful that any * of the code in here is at all portable between platforms) */ static long __stdcall start_mailthread(LPVOID ThreadParam); static boolean MAPI_mail_check(char *); static boolean MAPI_mail_fetch(char *); static void MAPI_mail_finish(void); static int MAPI_mail_context(int *); static boolean MAPI_mail_init(char *); static int InitMAPI(void); static int DeInitMAPI(void); static void MAPI_mail_abort(unsigned long); /* * Declare the function pointers used to access MAPI routines * from the MAPI32.DLL */ LPMAPILOGON fpMAPILogon; LPMAPILOGOFF fpMAPILogoff; LPMAPIFINDNEXT fpMAPIFindNext; LPMAPIREADMAIL fpMAPIReadMail; LPMAPIFREEBUFFER fpMAPIFreeBuffer; /* * Data requiring synchronized access between the * two thread contexts contained in this file * (nethack thread and the MAPI-mail thread) */ HANDLE mailthread = 0; /* handle for the mail-thread */ unsigned nhmailthread_ID; /* thread ID for mail-thread */ unsigned long nhmail_param; /* value passed to mail-thread */ long mailthread_continue = 0; /* nh -> mapi thread: shut down! */ long mailthread_stopping = 0; /* mapi -> nh thread: MAPI is ill! */ /* * Data updated by the NetHack thread only * but read by the MAPI-mail thread. * */ char MAPI_username[120]; boolean debugmapi; /* * Data updated by the MAPI-mail thread only * but read by the NetHack thread. */ long mail_fetched = 0; /* * Data used only by the MAPI-mail thread. */ long mailpasses; /* counts the FindNext calls issued to MAPI */ char msgID[80]; /* message ID of msg under manipulation */ /*=============================================================== * NetHack thread routines * * These routines run in the context of the main NetHack thread. * They are used to provide an interface between the NetHack * LAN_MAIL code and the MAPI-thread code. * * These routines are referenced by shared code in * sys/share/nhlan.c and they are prototyped in include/extern.h *=============================================================== */ boolean mail_check() { if (!mailthread_stopping) { if (mail_fetched > 0) return TRUE; } else lan_mail_terminate(); return FALSE; } boolean mail_fetch(msg) struct lan_mail_struct *msg; { /* shouldn't need to check mailthread_stopping here as the data should be valid anyway */ *msg = received_msg; iflags.lan_mail_fetched = TRUE; /* clear the marker now so new messages can arrive */ InterlockedDecrement(&mail_fetched); /* check to see if the MAPI-mail thread is saying "stop" */ if (mailthread_stopping) lan_mail_terminate(); return TRUE; } void mail_finish() { InterlockedDecrement(&mailthread_continue); } void mail_init(uname) char *uname; { /* This routine invokes the _beginthreadex() * run-time library call to start the execution * of the MAPI-mail thread. It also performs * few other preparatory tasks. */ if (mailthread_continue) { /* Impossible - something is really messed up */ /* We better do some sanity checking */ /* Is there a valid thread handle and ID? */ if (mailthread && nhmailthread_ID) { /* TODO: check 'em via WIN32 call */ /* if valid, do something about them */ /* if not, clear them */ } } mailthread = 0; nhmailthread_ID = 0; mailthread_continue = 0; /* no interlock needed yet */ mailthread_stopping = 0; /* no interlock needed yet */ #ifdef MAPI_VERBOSE if (getenv("DEBUG_MAPI")) debugmapi = TRUE; #endif if (uname) strcpy(MAPI_username, uname); else { #ifdef MAPI_VERBOSE if (debugmapi) dbgfile = fopen(MAPIDEBUGFILENAME,"w"); if (dbgfile) { fprintf(dbgfile, "mapi initialization bypassed because uname not available\n"); fclose(dbgfile); } #endif return; } mailthread = (HANDLE)_beginthreadex( (void *)0, (unsigned)0, start_mailthread, (void *)&nhmail_param, (unsigned)0, (unsigned *)&nhmailthread_ID); #if 0 /* TODO: check for failure of the thread. For now nethack * doesn't care */ if (!mailthread) { } #endif } /*=============================================================== * MAPI-mail thread routines * * These routines run in the context of their own * MAPI-mail thread. They were placed into their own * thread, because MAPI calls can sometimes (often?) take * a horribly long time to return (minutes even). * * Each of the routines below are referenced only by other * routines below, with the exception of start_mailthread(), * of course, which is started by a run-time library call * issued from the main NetHack thread. *=============================================================== */ /* * start_mailthread() is the entry point of the MAPI-mail thread. * */ static long __stdcall start_mailthread(LPVOID ThreadParam) { char *lu = MAPI_username; if(MAPI_mail_init(lu)) { InterlockedIncrement(&mailthread_continue); while (mailthread_continue) { mailpasses++; if (MAPI_mail_check(msgID)) { if (MAPI_mail_fetch(msgID)) { /* getting here means success */ } } Sleep(MAILTHREADFREQ); } #ifdef MAPI_VERBOSE if (debugmapi && !mailthread_continue) { fprintf(dbgfile, "MAPI-thread detected mailthread_continue change.\n"); fprintf(dbgfile, "NetHack has requested that the MAPI-thread cease.\n"); } #endif } return 0; } static int MAPI_mail_context(mcount) int *mcount; { unsigned long status; char tmpID[80]; int count = 0; tmpID[0] = '\0'; MAPIMessageID[0] = '\0'; /* Get the ID of the first unread message */ status = fpMAPIFindNext(MAPISession, 0, 0, 0, MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO, 0, tmpID); /* Now loop through them all until we have no more */ while (status == SUCCESS_SUCCESS) { strcpy(MAPIMessageID, tmpID); count++; status = fpMAPIFindNext(MAPISession, 0, 0, MAPIMessageID, MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO, 0, tmpID); } if (status == MAPI_E_NO_MESSAGES) { /* context is now at last message */ if (mcount) *mcount = count; return SUCCESS_SUCCESS; } return status; } static boolean MAPI_mail_check(mID) char *mID; { unsigned long status; char tmpID[80]; tmpID[0] = '\0'; #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "MAPI_mail_check() "); #endif if (mail_fetched) { #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "returning FALSE (buffer occupied)\n"); #endif return FALSE; /* buffer occupied, don't bother */ } /* Get the ID of the next unread message if there is one */ status = fpMAPIFindNext(MAPISession, 0, 0, MAPIMessageID, MAPI_UNREAD_ONLY | MAPI_GUARANTEE_FIFO, 0, tmpID); if (status == SUCCESS_SUCCESS) { strcpy(mID, tmpID); #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "returning TRUE\n"); #endif return TRUE; } if (status == MAPI_E_NO_MESSAGES) { #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "returning FALSE\n"); #endif return FALSE; } #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile,"Error, check_newmail() status: %d\n", status); MAPI_mail_abort(status); #endif return FALSE; } static boolean MAPI_mail_fetch(mID) char *mID; { unsigned long status; #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "MAPI_mail_fetch() "); #endif /* * Update context right away so we don't loop if there * was a problem getting the message */ strcpy(MAPIMessageID, mID); if (mail_fetched) { #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "returning FALSE (buffer occupied)\n"); #endif return FALSE; /* buffer occupied */ } status = fpMAPIReadMail(MAPISession, 0, mID, MAPI_SUPPRESS_ATTACH | MAPI_PEEK, 0, &MAPIMessage); if (status == SUCCESS_SUCCESS) { strncpy(received_msg.subject, MAPIMessage->lpszSubject, sizeof(received_msg.subject) - 1); if((MAPIMessage->lpOriginator->lpszName != (char *)0) && MAPIMessage->lpOriginator->lpszName[0] != '\0') strncpy(received_msg.sender, MAPIMessage->lpOriginator->lpszName, sizeof(received_msg.sender) - 1); else strncpy(received_msg.sender, MAPIMessage->lpOriginator->lpszAddress, sizeof(received_msg.sender) - 1); strncpy(received_msg.body, MAPIMessage->lpszNoteText,MAX_BODY_SIZE - 1); received_msg.body[MAX_BODY_SIZE - 1] = '\0'; received_msg.body_in_ram = TRUE; status = fpMAPIFreeBuffer(MAPIMessage); InterlockedIncrement(&mail_fetched); #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "returning TRUE\n"); #endif return TRUE; } #ifdef MAPI_VERBOSE else if (debugmapi) fprintf(dbgfile,"MAPIRead failed, status = %d\n", status); if (debugmapi) fprintf(dbgfile, "returning FALSE (failed)\n"); #endif return FALSE; } static void MAPI_mail_finish() { InterlockedIncrement(&mailthread_stopping); (void) fpMAPILogoff(MAPISession,0,0,0); (void) DeInitMAPI(); #ifdef MAPI_VERBOSE if (debugmapi) fclose(dbgfile); #endif (void) _endthreadex(0); } static void MAPI_mail_abort(reason) unsigned long reason; { #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "Terminating MAPI-thread due to error %d.\n", reason); #endif MAPI_mail_finish(); } static boolean MAPI_mail_init(uname) char *uname; { unsigned long status; int count = 0; #ifdef MAPI_VERBOSE if (debugmapi) dbgfile = fopen(MAPIDEBUGFILENAME,"w"); if (debugmapi) fprintf(dbgfile,"Hello %s, NetHack is initializing MAPI.\n", uname); #endif status = InitMAPI(); if (status) { #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile,"Error initializing MAPI %d\n", status); #endif return FALSE; } status = fpMAPILogon(0,uname,0L,0L,0L,(LPLHANDLE)&MAPISession); if (status != SUCCESS_SUCCESS) { #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile,"Status of MAPI logon is %d\n", status); #endif return FALSE; } #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "Stage 1 of MAPI initialization successful.\n"); if (debugmapi) fprintf(dbgfile,"MAPI Session handle: %d\n", MAPISession); #endif status = MAPI_mail_context(&count); if (status == SUCCESS_SUCCESS) { #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "Stage 2 of MAPI initialization successful.\n"); if (debugmapi) fprintf(dbgfile,"Detected %d old unread messages.\n", count); #endif return TRUE; } #ifdef MAPI_VERBOSE if (debugmapi) fprintf(dbgfile, "Error, status of MAPI_mail_context() is %d.\n", status); if (debugmapi) fprintf(dbgfile, "Dismantling MAPI interface and cleaning up.\n"); #endif MAPI_mail_finish(); return FALSE; } int InitMAPI() { if (!(hLibrary = LoadLibrary("MAPI32.DLL"))) return MAPI_LIB_FAIL; if ((fpMAPILogon = (LPMAPILOGON)GetProcAddress(hLibrary,"MAPILogon")) == NULL) return MAPI_FUNC_FAIL; if ((fpMAPILogoff = (LPMAPILOGOFF)GetProcAddress(hLibrary,"MAPILogoff")) == NULL) return MAPI_FUNC_FAIL; if ((fpMAPIFindNext= (LPMAPIFINDNEXT)GetProcAddress(hLibrary,"MAPIFindNext")) == NULL) return MAPI_FUNC_FAIL; if ((fpMAPIReadMail= (LPMAPIREADMAIL)GetProcAddress(hLibrary,"MAPIReadMail")) == NULL) return MAPI_FUNC_FAIL; if ((fpMAPIFindNext= (LPMAPIFINDNEXT)GetProcAddress(hLibrary,"MAPIFindNext")) == NULL) return MAPI_FUNC_FAIL; if ((fpMAPIFreeBuffer= (LPMAPIFREEBUFFER)GetProcAddress(hLibrary,"MAPIFreeBuffer")) == NULL) return MAPI_FUNC_FAIL; #ifdef MAPI_VERBOSE if (debugmapi) { fprintf(dbgfile,"Entry Points:\n"); fprintf(dbgfile,"MAPILogon = %p\n",fpMAPILogon); fprintf(dbgfile,"MAPILogoff = %p\n",fpMAPILogoff); fprintf(dbgfile,"MAPIFindNext = %p\n",fpMAPIFindNext); fprintf(dbgfile,"MAPIFreeBuffer = %p\n",fpMAPIReadMail); fprintf(dbgfile,"MAPIReadMail = %p\n",fpMAPIFreeBuffer); } #endif return 0; } int DeInitMAPI() { fpMAPILogon = NULL; fpMAPILogoff= NULL; fpMAPIFindNext= NULL; fpMAPIReadMail= NULL; fpMAPIFreeBuffer = NULL; FreeLibrary(hLibrary); return 0; } #endif /*LAN_MAIL*/ nethack-3.4.3/sys/winnt/nethack.def0100644000000000000000000000031707764735041015725 0ustar rootrootNAME NETHACK DESCRIPTION 'NetHack 3.4.1 for Windows NT' EXETYPE WINDOWS STUB 'WINSTUB.EXE' CODE PRELOAD MOVEABLE DISCARDABLE DATA PRELOAD MOVEABLE MULTIPLE HEAPSIZE 4096 STACKSIZE 9216 EXPORTS WndProc nethack-3.4.3/sys/winnt/nh340key.c0100644000000000000000000001775407764735041015356 0ustar rootroot/* SCCS Id: @(#)nh340key.c 3.4 $Date: 2003/11/01 23:57:00 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ /* * This is the NetHack keystroke processing from NetHack 3.4.0. * It can be built as a run-time loadable dll (nh340key.dll), * placed in the same directory as the nethack.exe executable, * and loaded by specifying OPTIONS=altkeyhandler:nh340key * in defaults.nh */ static char where_to_get_source[] = "http://www.nethack.org/"; static char author[] = "The NetHack Development Team"; #include "hack.h" #include "wintty.h" #include "win32api.h" extern HANDLE hConIn; extern INPUT_RECORD ir; char dllname[512]; char *shortdllname; int FDECL(__declspec(dllexport) __stdcall ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, boolean *valid, BOOLEAN_P numberpad, int portdebug)); int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { char dlltmpname[512]; char *tmp = dlltmpname, *tmp2; *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0'; (void)strcpy(dllname, tmp); tmp2 = strrchr(dllname, '\\'); if (tmp2) { tmp2++; shortdllname = tmp2; } return TRUE; } /* * Keyboard translation tables. * (Adopted from the MSDOS port) */ #define KEYPADLO 0x47 #define KEYPADHI 0x53 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ static const struct pad { uchar normal, shift, cntrl; } keypad[PADKEYS] = { {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'h', 'H', C('h')}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'l', 'L', C('l')}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }, numpad[PADKEYS] = { {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'4', M('4'), '4'}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }; #define inmap(x,vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2') int __declspec(dllexport) __stdcall ProcessKeystroke(hConIn, ir, valid, numberpad, portdebug) HANDLE hConIn; INPUT_RECORD *ir; boolean *valid; boolean numberpad; int portdebug; { int metaflags = 0, k = 0; int keycode, vk; unsigned char ch, pre_ch, mk = 0; unsigned short int scan; unsigned long shiftstate; int altseq = 0; const struct pad *kpad; shiftstate = 0L; ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); shiftstate = ir->Event.KeyEvent.dwControlKeyState; if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) { if (ch || inmap(keycode,vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || (iskeypad(scan)) || (altseq > 0)) *valid = TRUE; /* if (!valid) return 0; */ /* * shiftstate can be checked to see if various special * keys were pressed at the same time as the key. * Currently we are using the ALT & SHIFT & CONTROLS. * * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON, * CAPSLOCK_ON, ENHANCED_KEY * * are all valid bit masks to use on shiftstate. * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the * left control key was pressed with the keystroke. */ if (iskeypad(scan)) { kpad = numberpad ? numpad : keypad; if (shiftstate & SHIFT_PRESSED) { ch = kpad[scan - KEYPADLO].shift; } else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { ch = kpad[scan - KEYPADLO].cntrl; } else { ch = kpad[scan - KEYPADLO].normal; } } else if (altseq > 0) { /* ALT sequence */ if (vk == 0xBF) ch = M('?'); else ch = M(tolower(keycode)); } if (ch == '\r') ch = '\n'; #ifdef PORT_DEBUG if (portdebug) { char buf[BUFSZ]; Sprintf(buf, "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, sh=0x%X (ESC to end)", shortdllname, ch, scan, vk, shiftstate); fprintf(stdout, "\n%s", buf); } #endif return ch; } int __declspec(dllexport) __stdcall NHkbhit(hConIn, ir) HANDLE hConIn; INPUT_RECORD *ir; { int done = 0; /* true = "stop searching" */ int retval; /* true = "we had a match" */ DWORD count; unsigned short int scan; unsigned char ch; unsigned long shiftstate; int altseq = 0, keycode, vk; done = 0; retval = 0; while (!done) { count = 0; PeekConsoleInput(hConIn,ir,1,&count); if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; shiftstate = ir->Event.KeyEvent.dwControlKeyState; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) { if (ch || inmap(keycode,vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || iskeypad(scan) || altseq) { done = 1; /* Stop looking */ retval = 1; /* Found what we sought */ } else { /* Strange Key event; let's purge it to avoid trouble */ ReadConsoleInput(hConIn,ir,1,&count); } } else if ((ir->EventType == MOUSE_EVENT && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) { done = 1; retval = 1; } else /* Discard it, it's an insignificant event */ ReadConsoleInput(hConIn,ir,1,&count); } else /* There are no events in console event queue */ { done = 1; /* Stop looking */ retval = 0; } } return retval; } int __declspec(dllexport) __stdcall CheckInput(hConIn, ir, count, numpad, mode, mod, cc) HANDLE hConIn; INPUT_RECORD *ir; DWORD *count; boolean numpad; int mode; int *mod; coord *cc; { int ch; boolean valid = 0, done = 0; while (!done) { ReadConsoleInput(hConIn,ir,1,count); if (mode == 0) { if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0); done = valid; } } else { if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0); if (valid) return ch; } else if (ir->EventType == MOUSE_EVENT) { if ((ir->Event.MouseEvent.dwEventFlags == 0) && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) { cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1; cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1; if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON) *mod = CLICK_1; else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON) *mod = CLICK_2; #if 0 /* middle button */ else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON) *mod = CLICK_3; #endif return 0; } } } else done = 1; } } return mode ? 0 : ch; } int __declspec(dllexport) __stdcall SourceWhere(buf) char **buf; { if (!buf) return 0; *buf = where_to_get_source; return 1; } int __declspec(dllexport) __stdcall SourceAuthor(buf) char **buf; { if (!buf) return 0; *buf = author; return 1; } int __declspec(dllexport) __stdcall KeyHandlerName(buf, full) char **buf; int full; { if (!buf) return 0; if (full) *buf = dllname; else *buf = shortdllname; return 1; } nethack-3.4.3/sys/winnt/nhdefkey.c0100644000000000000000000002163307764735041015575 0ustar rootroot/* SCCS Id: @(#)nhdefkey.c 3.4 $Date: 2003/11/01 23:57:00 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ /* * This is the default NetHack keystroke processing. * It can be built as a run-time loadable dll (nhdefkey.dll). * Alternative keystroke handlers can be built using the * entry points in this file as a template. * * Use the defaults.nh "altkeyhandler" option to set a * different dll name (without the ".DLL" extension) to * get different processing. Ensure that the dll referenced * in defaults.nh exists in the same directory as NetHack in * order for it to load successfully. * */ static char where_to_get_source[] = "http://www.nethack.org/"; static char author[] = "The NetHack Development Team"; #include "hack.h" #include "wintty.h" #include "win32api.h" extern HANDLE hConIn; extern INPUT_RECORD ir; char dllname[512]; char *shortdllname; int FDECL(__declspec(dllexport) __stdcall ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, boolean *valid, BOOLEAN_P numberpad, int portdebug)); int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { char dlltmpname[512]; char *tmp = dlltmpname, *tmp2; *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0'; (void)strcpy(dllname, tmp); tmp2 = strrchr(dllname, '\\'); if (tmp2) { tmp2++; shortdllname = tmp2; } return TRUE; } /* * Keyboard translation tables. * (Adopted from the MSDOS port) */ #define KEYPADLO 0x47 #define KEYPADHI 0x53 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ static const struct pad { uchar normal, shift, cntrl; } keypad[PADKEYS] = { {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'h', 'H', C('h')}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'l', 'L', C('l')}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }, numpad[PADKEYS] = { {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'4', M('4'), '4'}, /* 4 */ {'5', M('5'), '5'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'0', M('0'), '0'}, /* Ins */ {'.', ':', ':'} /* Del */ }; #define inmap(x,vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2') static BYTE KeyState[256]; int __declspec(dllexport) __stdcall ProcessKeystroke(hConIn,ir, valid, numberpad, portdebug) HANDLE hConIn; INPUT_RECORD *ir; boolean *valid; boolean numberpad; int portdebug; { int metaflags = 0, k = 0; int keycode, vk; unsigned char ch, pre_ch, mk = 0; unsigned short int scan; unsigned long shiftstate; int altseq = 0; const struct pad *kpad; shiftstate = 0L; ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); shiftstate = ir->Event.KeyEvent.dwControlKeyState; KeyState[VK_SHIFT] = (shiftstate & SHIFT_PRESSED) ? 0x81 : 0; KeyState[VK_CONTROL] = (shiftstate & (LEFT_CTRL_PRESSED|RIGHT_CTRL_PRESSED)) ? 0x81 : 0; KeyState[VK_CAPITAL] = (shiftstate & CAPSLOCK_ON) ? 0x81 : 0; if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) { if (ch || inmap(keycode,vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || (iskeypad(scan)) || (altseq > 0)) *valid = TRUE; /* if (!valid) return 0; */ /* * shiftstate can be checked to see if various special * keys were pressed at the same time as the key. * Currently we are using the ALT & SHIFT & CONTROLS. * * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON, * CAPSLOCK_ON, ENHANCED_KEY * * are all valid bit masks to use on shiftstate. * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the * left control key was pressed with the keystroke. */ if (iskeypad(scan)) { kpad = numberpad ? numpad : keypad; if (shiftstate & SHIFT_PRESSED) { ch = kpad[scan - KEYPADLO].shift; } else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { ch = kpad[scan - KEYPADLO].cntrl; } else { ch = kpad[scan - KEYPADLO].normal; } } else if (altseq > 0) { /* ALT sequence */ if (vk == 0xBF) ch = M('?'); else ch = M(tolower(keycode)); } /* Attempt to work better with international keyboards. */ else { WORD chr[2]; k = ToAscii(vk, scan, KeyState, chr, 0); if (k <= 2) switch(k) { case 2: /* two characters */ ch = (unsigned char)chr[1]; *valid = TRUE; break; case 1: /* one character */ ch = (unsigned char)chr[0]; *valid = TRUE; break; case 0: /* no translation */ default: /* negative */ *valid = FALSE; } } if (ch == '\r') ch = '\n'; #ifdef PORT_DEBUG if (portdebug) { char buf[BUFSZ]; Sprintf(buf, "PORTDEBUG (%s): ch=%u, sc=%u, vk=%d, pre=%d, sh=0x%X, ta=%d (ESC to end)", shortdllname, ch, scan, vk, pre_ch, shiftstate, k); fprintf(stdout, "\n%s", buf); } #endif return ch; } int __declspec(dllexport) __stdcall NHkbhit(hConIn, ir) HANDLE hConIn; INPUT_RECORD *ir; { int done = 0; /* true = "stop searching" */ int retval; /* true = "we had a match" */ DWORD count; unsigned short int scan; unsigned char ch; unsigned long shiftstate; int altseq = 0, keycode, vk; done = 0; retval = 0; while (!done) { count = 0; PeekConsoleInput(hConIn,ir,1,&count); if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; shiftstate = ir->Event.KeyEvent.dwControlKeyState; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); if (shiftstate & (LEFT_ALT_PRESSED|RIGHT_ALT_PRESSED)) { if (ch || inmap(keycode,vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || iskeypad(scan) || altseq) { done = 1; /* Stop looking */ retval = 1; /* Found what we sought */ } else { /* Strange Key event; let's purge it to avoid trouble */ ReadConsoleInput(hConIn,ir,1,&count); } } else if ((ir->EventType == MOUSE_EVENT && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) { done = 1; retval = 1; } else /* Discard it, it's an insignificant event */ ReadConsoleInput(hConIn,ir,1,&count); } else /* There are no events in console event queue */ { done = 1; /* Stop looking */ retval = 0; } } return retval; } int __declspec(dllexport) __stdcall CheckInput(hConIn, ir, count, numpad, mode, mod, cc) HANDLE hConIn; INPUT_RECORD *ir; DWORD *count; boolean numpad; int mode; int *mod; coord *cc; { int ch; boolean valid = 0, done = 0; while (!done) { ReadConsoleInput(hConIn,ir,1,count); if (mode == 0) { if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0); done = valid; } } else { if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, 0); if (valid) return ch; } else if (ir->EventType == MOUSE_EVENT) { if ((ir->Event.MouseEvent.dwEventFlags == 0) && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) { cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1; cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1; if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON) *mod = CLICK_1; else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON) *mod = CLICK_2; #if 0 /* middle button */ else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON) *mod = CLICK_3; #endif return 0; } } } else done = 1; } } return mode ? 0 : ch; } int __declspec(dllexport) __stdcall SourceWhere(buf) char **buf; { if (!buf) return 0; *buf = where_to_get_source; return 1; } int __declspec(dllexport) __stdcall SourceAuthor(buf) char **buf; { if (!buf) return 0; *buf = author; return 1; } int __declspec(dllexport) __stdcall KeyHandlerName(buf, full) char **buf; int full; { if (!buf) return 0; if (full) *buf = dllname; else *buf = shortdllname; return 1; } nethack-3.4.3/sys/winnt/nhico.uu0100644000000000000000000000275407764735041015312 0ustar rootrootbegin 600 nethack.ico M```!``(`("`0``````#H`@``)@```!`0$```````*`$```X#```H````(``` M`$`````!``0``````(`"````````````````````````````````@```@``` M`("``(````"``(``@(```,#`P`"`@(````#_``#_````__\`_P```/\`_P#_ M_P``____````````````````````````__=P```````````'=W<`#___=P`` M````````?_?W<`]W:/=P``#_<```!WB'!G`/8'B'<``/_W<```?VAGAP#P=E M;W``__]W<``'>`=H\`__=G_P#_!V9_<`!W=H=W``__(:/<`=P=W<` M``__\`_W=G9GB'<`!W=P````__#_=G=X2&"/<`=W``````_P_\=T=F>(:/<' M<```````#_9V=V5H8(AO<`````````_W=W1WAXAHA_````````#_9\<&>&!H M!H9W````````_W=V=6=GAH@(]P``````#_?'9W9T:(!H:&=P``````_V=WQV M=X=HA@B/<``````/]GQP=G>':(A@AW``````#_<'9\=VAH!HB&=P``````_V M=G=X9V>&"&"'<``````/]W?'9W1@B(:(9W````^&C_?'9W1WAX:`8(=P`'`/ M_X_P9W9W:&A@AH:''AH@(AW!W\`=H;_9V=G!H:&"&A@=P M`(`'B(_P<'!V<&>(:(B'<`"`#_\/______=W=W=W=W!W<`__#_____?_?W=W M=W=P=W`/``__#___]W=W=W!W<`!P```/\`#_]_]_=W<`!W``````#P```/_W M=W<```!P```````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````H````$````"`````!``0``````,`````````` M````````````````````````@```@````("``(````"``(``@(```,#`P`"` M@(````#_``#_````__\`_P```/\`_P#__P``____`````````````/<````` M=P`/_W`/<`=W<`#_\/8'!W<```\/9F!P<````/9F!@<`````]F9@9P````]F M9@8&<```#V9F8&!P```/9F8&!G````]F9F!@<``/?V9F!@9P<`]_9F9@8'!P M#P___W=W<'``#P__=W!P```````````````````````````````````````` K```````````````````````````````````````````````````````````` ` end nethack-3.4.3/sys/winnt/nhraykey.c0100644000000000000000000004661707764735041015643 0ustar rootroot/* SCCS Id: @(#)nhraykey.c 3.4 $Date: 2003/11/01 23:57:00 $ */ /* Copyright (c) NetHack PC Development Team 2003 */ /* NetHack may be freely redistributed. See license for details. */ /* * Keystroke handling contributed by Ray Chason. * The following text was written by Ray Chason. * * The problem * =========== * * The console-mode Nethack wants both keyboard and mouse input. The * problem is that the Windows API provides no easy way to get mouse input * and also keyboard input properly translated according to the user's * chosen keyboard layout. * * The ReadConsoleInput function returns a stream of keyboard and mouse * events. Nethack is interested in those events that represent a key * pressed, or a click on a mouse button. The keyboard events from * ReadConsoleInput are not translated according to the keyboard layout, * and do not take into account the shift, control, or alt keys. * * The PeekConsoleInput function works similarly to ReadConsoleInput, * except that it does not remove an event from the queue and it returns * instead of blocking when the queue is empty. * * A program can also use ReadConsole to get a properly translated stream * of characters. Unfortunately, ReadConsole does not return mouse events, * does not distinguish the keypad from the main keyboard, does not return * keys shifted with Alt, and does not even return the ESC key when * pressed. * * We want both the functionality of ReadConsole and the functionality of * ReadConsoleInput. But Microsoft didn't seem to think of that. * * * The solution, in the original code * ================================== * * The original 3.4.1 distribution tries to get proper keyboard translation * by passing keyboard events to the ToAscii function. This works, to some * extent -- it takes the shift key into account, and it processes dead * keys properly. But it doesn't take non-US keyboards into account. It * appears that ToAscii is meant for windowed applications, and does not * have enough information to do its job properly in a console application. * * * The Finnish keyboard patch * ========================== * * This patch adds the "subkeyvalue" option to the defaults.nh file. The * user can then add OPTIONS=sukeyvalue:171/92, for instance, to replace * the 171 character with 92, which is \. This works, once properly * configured, but places too much burden on the user. It also bars the * use of the substituted characters in naming objects or monsters. * * * The solution presented here * =========================== * * The best way I could find to combine the functionality of ReadConsole * with that of ReadConsoleInput is simple in concept. First, call * PeekConsoleInput to get the first event. If it represents a key press, * call ReadConsole to retrieve the key. Otherwise, pop it off the queue * with ReadConsoleInput and, if it's a mouse click, return it as such. * * But the Devil, as they say, is in the details. The problem is in * recognizing an event that ReadConsole will return as a key. We don't * want to call ReadConsole unless we know that it will immediately return: * if it blocks, the mouse and the Alt sequences will cease to function * until it returns. * * Separating process_keystroke into two functions, one for commands and a * new one, process_keystroke2, for answering prompts, makes the job a lot * easier. process_keystroke2 doesn't have to worry about mouse events or * Alt sequences, and so the consequences are minor if ReadConsole blocks. * process_keystroke, OTOH, never needs to return a non-ASCII character * that was read from ReadConsole; it returns bytes with the high bit set * only in response to an Alt sequence. * * So in process_keystroke, before calling ReadConsole, a bogus key event * is pushed on the queue. This event causes ReadConsole to return, even * if there was no other character available. Because the bogus key has * the eighth bit set, it is filtered out. This is not done in * process_keystroke2, because that would render dead keys unusable. * * A separate process_keystroke2 can also process the numeric keypad in a * way that makes sense for prompts: just return the corresponding symbol, * and pay no mind to number_pad or the num lock key. * * The recognition of Alt sequences is modified, to support the use of * characters generated with the AltGr key. A keystroke is an Alt sequence * if an Alt key is seen that can't be an AltGr (since an AltGr sequence * could be a character, and in some layouts it could even be an ASCII * character). This recognition is different on NT-based and 95-based * Windows: * * * On NT-based Windows, AltGr signals as right Alt and left Ctrl * together. So an Alt sequence is recognized if either Alt key is * pressed and if right Alt and left Ctrl are not both present. This * is true even if the keyboard in use does not have an AltGr key, and * uses right Alt for AltGr. * * * On 95-based Windows, with a keyboard that lacks the AltGr key, the * right Alt key is used instead. But it still signals as right Alt, * without left Ctrl. There is no way for the application to know * whether right Alt is Alt or AltGr, and so it is always assumed * to be AltGr. This means that Alt sequences must be formed with * left Alt. * * So the patch processes keystrokes as follows: * * * If the scan and virtual key codes are both 0, it's the bogus key, * and we ignore it. * * * Keys on the numeric keypad are processed for commands as in the * unpatched Nethack, and for prompts by returning the ASCII * character, even if the num lock is off. * * * Alt sequences are processed for commands as in the unpatched * Nethack, and ignored for prompts. * * * Control codes are returned as received, because ReadConsole will * not return the ESC key. * * * Other key-down events are passed to ReadConsole. The use of * ReadConsole is different for commands than for prompts: * * o For commands, the bogus key is pushed onto the queue before * ReadConsole is called. On return, non-ASCII characters are * filtered, so they are not mistaken for Alt sequences; this also * filters the bogus key. * * o For prompts, the bogus key is not used, because that would * interfere with dead keys. Eight bit characters may be returned, * and are coded in the configured code page. * * * Possible improvements * ===================== * * Some possible improvements remain: * * * Integrate the existing Finnish keyboard patch, for use with non- * QWERTY layouts such as the German QWERTZ keyboard or Dvorak. * * * Fix the keyboard glitches in the graphical version. Namely, dead * keys don't work, and input comes in as ISO-8859-1 but is displayed * as code page 437 if IBMgraphics is set on startup. * * * Transform incoming text to ISO-8859-1, for full compatibility with * the graphical version. * * * After pushing the bogus key and calling ReadConsole, check to see * if we got the bogus key; if so, and an Alt is pressed, process the * event as an Alt sequence. * */ static char where_to_get_source[] = "http://www.nethack.org/"; static char author[] = "Ray Chason"; #include "hack.h" #include "wintty.h" #include "win32api.h" extern HANDLE hConIn; extern INPUT_RECORD ir; char dllname[512]; char *shortdllname; int FDECL(__declspec(dllexport) __stdcall ProcessKeystroke, (HANDLE hConIn, INPUT_RECORD *ir, boolean *valid, BOOLEAN_P numberpad, int portdebug)); static INPUT_RECORD bogus_key; int WINAPI DllMain(HINSTANCE hInstance, DWORD fdwReason, PVOID pvReserved) { char dlltmpname[512]; char *tmp = dlltmpname, *tmp2; *(tmp + GetModuleFileName(hInstance, tmp, 511)) = '\0'; (void)strcpy(dllname, tmp); tmp2 = strrchr(dllname, '\\'); if (tmp2) { tmp2++; shortdllname = tmp2; } /* A bogus key that will be filtered when received, to keep ReadConsole * from blocking */ bogus_key.EventType = KEY_EVENT; bogus_key.Event.KeyEvent.bKeyDown = 1; bogus_key.Event.KeyEvent.wRepeatCount = 1; bogus_key.Event.KeyEvent.wVirtualKeyCode = 0; bogus_key.Event.KeyEvent.wVirtualScanCode = 0; bogus_key.Event.KeyEvent.uChar.AsciiChar = (uchar)0x80; bogus_key.Event.KeyEvent.dwControlKeyState = 0; return TRUE; } /* * Keyboard translation tables. * (Adopted from the MSDOS port) */ #define KEYPADLO 0x47 #define KEYPADHI 0x53 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) #define isnumkeypad(x) (KEYPADLO <= (x) && (x) <= 0x51 && (x) != 0x4A && (x) != 0x4E) /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ static const struct pad { uchar normal, shift, cntrl; } keypad[PADKEYS] = { {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'h', 'H', C('h')}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'l', 'L', C('l')}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }, numpad[PADKEYS] = { {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'4', M('4'), '4'}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }; #define inmap(x,vk) (((x) > 'A' && (x) < 'Z') || (vk) == 0xBF || (x) == '2') /* Use process_keystroke for key commands, process_keystroke2 for prompts */ /* int FDECL(process_keystroke, (INPUT_RECORD *ir, boolean *valid, int portdebug)); */ int FDECL(process_keystroke2, (HANDLE,INPUT_RECORD *ir, boolean *valid)); static int FDECL(is_altseq, (unsigned long shiftstate)); static int is_altseq(shiftstate) unsigned long shiftstate; { /* We need to distinguish the Alt keys from the AltGr key. * On NT-based Windows, AltGr signals as right Alt and left Ctrl together; * on 95-based Windows, AltGr signals as right Alt only. * So on NT, we signal Alt if either Alt is pressed and left Ctrl is not, * and on 95, we signal Alt for left Alt only. */ switch (shiftstate & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED)) { case LEFT_ALT_PRESSED: case LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED: return 1; case RIGHT_ALT_PRESSED: case RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED: return (GetVersion() & 0x80000000) == 0; default: return 0; } } int __declspec(dllexport) __stdcall ProcessKeystroke(hConIn, ir, valid, numberpad, portdebug) HANDLE hConIn; INPUT_RECORD *ir; boolean *valid; boolean numberpad; int portdebug; { int metaflags = 0, k = 0; int keycode, vk; unsigned char ch, pre_ch, mk = 0; unsigned short int scan; unsigned long shiftstate; int altseq = 0; const struct pad *kpad; DWORD count; shiftstate = 0L; ch = pre_ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); shiftstate = ir->Event.KeyEvent.dwControlKeyState; if (scan == 0 && vk == 0) { /* It's the bogus_key */ ReadConsoleInput(hConIn,ir,1,&count); *valid = FALSE; return 0; } if (is_altseq(shiftstate)) { if (ch || inmap(keycode,vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || (iskeypad(scan)) || (altseq > 0)) *valid = TRUE; /* if (!valid) return 0; */ /* * shiftstate can be checked to see if various special * keys were pressed at the same time as the key. * Currently we are using the ALT & SHIFT & CONTROLS. * * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON, * CAPSLOCK_ON, ENHANCED_KEY * * are all valid bit masks to use on shiftstate. * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the * left control key was pressed with the keystroke. */ if (iskeypad(scan)) { ReadConsoleInput(hConIn,ir,1,&count); kpad = numberpad ? numpad : keypad; if (shiftstate & SHIFT_PRESSED) { ch = kpad[scan - KEYPADLO].shift; } else if (shiftstate & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { ch = kpad[scan - KEYPADLO].cntrl; } else { ch = kpad[scan - KEYPADLO].normal; } } else if (altseq > 0) { /* ALT sequence */ ReadConsoleInput(hConIn,ir,1,&count); if (vk == 0xBF) ch = M('?'); else ch = M(tolower(keycode)); } else if (ch < 32 && !isnumkeypad(scan)) { /* Control code; ReadConsole seems to filter some of these, * including ESC */ ReadConsoleInput(hConIn,ir,1,&count); } /* Attempt to work better with international keyboards. */ else { CHAR ch2; DWORD written; /* The bogus_key guarantees that ReadConsole will return, * and does not itself do anything */ WriteConsoleInput(hConIn, &bogus_key, 1, &written); ReadConsole(hConIn,&ch2,1,&count,NULL); /* Prevent high characters from being interpreted as alt * sequences; also filter the bogus_key */ if (ch2 & 0x80) *valid = FALSE; else ch = ch2; if (ch == 0) *valid = FALSE; } if (ch == '\r') ch = '\n'; #ifdef PORT_DEBUG if (portdebug) { char buf[BUFSZ]; Sprintf(buf, "PORTDEBUG: ch=%u, scan=%u, vk=%d, pre=%d, shiftstate=0x%X (ESC to end)\n", ch, scan, vk, pre_ch, shiftstate); fprintf(stdout, "\n%s", buf); } #endif return ch; } int process_keystroke2(hConIn, ir, valid) HANDLE hConIn; INPUT_RECORD *ir; boolean *valid; { /* Use these values for the numeric keypad */ static const char keypad_nums[] = "789-456+1230."; unsigned char ch; int vk; unsigned short int scan; unsigned long shiftstate; int altseq; DWORD count; ch = ir->Event.KeyEvent.uChar.AsciiChar; vk = ir->Event.KeyEvent.wVirtualKeyCode; scan = ir->Event.KeyEvent.wVirtualScanCode; shiftstate = ir->Event.KeyEvent.dwControlKeyState; if (scan == 0 && vk == 0) { /* It's the bogus_key */ ReadConsoleInput(hConIn,ir,1,&count); *valid = FALSE; return 0; } altseq = is_altseq(shiftstate); if (ch || (iskeypad(scan)) || altseq) *valid = TRUE; /* if (!valid) return 0; */ /* * shiftstate can be checked to see if various special * keys were pressed at the same time as the key. * Currently we are using the ALT & SHIFT & CONTROLS. * * RIGHT_ALT_PRESSED, LEFT_ALT_PRESSED, * RIGHT_CTRL_PRESSED, LEFT_CTRL_PRESSED, * SHIFT_PRESSED,NUMLOCK_ON, SCROLLLOCK_ON, * CAPSLOCK_ON, ENHANCED_KEY * * are all valid bit masks to use on shiftstate. * eg. (shiftstate & LEFT_CTRL_PRESSED) is true if the * left control key was pressed with the keystroke. */ if (iskeypad(scan) && !altseq) { ReadConsoleInput(hConIn,ir,1,&count); ch = keypad_nums[scan - KEYPADLO]; } else if (ch < 32 && !isnumkeypad(scan)) { /* Control code; ReadConsole seems to filter some of these, * including ESC */ ReadConsoleInput(hConIn,ir,1,&count); } /* Attempt to work better with international keyboards. */ else { CHAR ch2; ReadConsole(hConIn,&ch2,1,&count,NULL); ch = ch2 & 0xFF; if (ch == 0) *valid = FALSE; } if (ch == '\r') ch = '\n'; return ch; } int __declspec(dllexport) __stdcall CheckInput(hConIn, ir, count, numpad, mode, mod, cc) HANDLE hConIn; INPUT_RECORD *ir; DWORD *count; int *mod; boolean numpad; coord *cc; { int ch; boolean valid = 0, done = 0; while (!done) { *count = 0; WaitForSingleObject(hConIn, INFINITE); PeekConsoleInput(hConIn,ir,1,count); if (mode == 0) { if ((ir->EventType == KEY_EVENT) && ir->Event.KeyEvent.bKeyDown) { ch = process_keystroke2(hConIn, ir, &valid); done = valid; } else ReadConsoleInput(hConIn,ir,1,count); } else { ch = 0; if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ProcessKeystroke(hConIn, ir, &valid, numpad, #ifdef PORTDEBUG 1); #else 0); #endif if (valid) return ch; } else { ReadConsoleInput(hConIn,ir,1,count); if (ir->EventType == MOUSE_EVENT) { if ((ir->Event.MouseEvent.dwEventFlags == 0) && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK)) { cc->x = ir->Event.MouseEvent.dwMousePosition.X + 1; cc->y = ir->Event.MouseEvent.dwMousePosition.Y - 1; if (ir->Event.MouseEvent.dwButtonState & LEFTBUTTON) *mod = CLICK_1; else if (ir->Event.MouseEvent.dwButtonState & RIGHTBUTTON) *mod = CLICK_2; #if 0 /* middle button */ else if (ir->Event.MouseEvent.dwButtonState & MIDBUTTON) *mod = CLICK_3; #endif return 0; } } #if 0 /* We ignore these types of console events */ else if (ir->EventType == FOCUS_EVENT) { } else if (ir->EventType == MENU_EVENT) { } #endif } } else done = 1; } } *mod = 0; return ch; } int __declspec(dllexport) __stdcall NHkbhit(hConIn, ir) HANDLE hConIn; INPUT_RECORD *ir; { int done = 0; /* true = "stop searching" */ int retval; /* true = "we had a match" */ DWORD count; unsigned short int scan; unsigned char ch; unsigned long shiftstate; int altseq = 0, keycode, vk; done = 0; retval = 0; while (!done) { count = 0; PeekConsoleInput(hConIn,ir,1,&count); if (count > 0) { if (ir->EventType == KEY_EVENT && ir->Event.KeyEvent.bKeyDown) { ch = ir->Event.KeyEvent.uChar.AsciiChar; scan = ir->Event.KeyEvent.wVirtualScanCode; shiftstate = ir->Event.KeyEvent.dwControlKeyState; vk = ir->Event.KeyEvent.wVirtualKeyCode; keycode = MapVirtualKey(vk, 2); if (is_altseq(shiftstate)) { if (ch || inmap(keycode,vk)) altseq = 1; else altseq = -1; /* invalid altseq */ } if (ch || iskeypad(scan) || altseq) { done = 1; /* Stop looking */ retval = 1; /* Found what we sought */ } else { /* Strange Key event; let's purge it to avoid trouble */ ReadConsoleInput(hConIn,ir,1,&count); } } else if ((ir->EventType == MOUSE_EVENT && (ir->Event.MouseEvent.dwButtonState & MOUSEMASK))) { done = 1; retval = 1; } else /* Discard it, it's an insignificant event */ ReadConsoleInput(hConIn,ir,1,&count); } else /* There are no events in console event queue */ { done = 1; /* Stop looking */ retval = 0; } } return retval; } int __declspec(dllexport) __stdcall SourceWhere(buf) char **buf; { if (!buf) return 0; *buf = where_to_get_source; return 1; } int __declspec(dllexport) __stdcall SourceAuthor(buf) char **buf; { if (!buf) return 0; *buf = author; return 1; } int __declspec(dllexport) __stdcall KeyHandlerName(buf, full) char **buf; int full; { if (!buf) return 0; if (full) *buf = dllname; else *buf = shortdllname; return 1; } nethack-3.4.3/sys/winnt/nhsetup.bat0100644000000000000000000001007607764735152016014 0ustar rootroot@REM SCCS Id: @(#)nhsetup.bat 3.4 $Date: 2002/07/24 08:25:21 $ @REM Copyright (c) NetHack PC Development Team 1993, 1996, 2002 @REM NetHack may be freely redistributed. See license for details. @REM Win32 setup batch file, see Install.nt for details @REM @echo off set _pause= :nxtcheck echo Checking to see if directories are set up properly if not exist ..\..\include\hack.h goto :err_dir if not exist ..\..\src\hack.c goto :err_dir if not exist ..\..\dat\wizard.des goto :err_dir if not exist ..\..\util\makedefs.c goto :err_dir if not exist ..\..\sys\winnt\winnt.c goto :err_dir echo Directories look ok. :do_tty if NOT exist ..\..\binary\*.* mkdir ..\..\binary if NOT exist ..\..\binary\license copy ..\..\dat\license ..\..\binary\license >nul echo Copying Microsoft Makefile - Makefile.msc to ..\..\src\Makefile. if NOT exist ..\..\src\Makefile goto :domsc copy ..\..\src\Makefile ..\..\src\Makefile-orig >nul echo Your existing echo ..\..\src\Makefile echo has been renamed to echo ..\..\src\Makefile-orig :domsc copy Makefile.msc ..\..\src\Makefile >nul echo Microsoft Makefile copied ok. echo Copying Borland Makefile - Makefile.bcc to ..\..\src\Makefile.bcc if NOT exist ..\..\src\Makefile.bcc goto :dobor copy ..\..\src\Makefile.bcc ..\..\src\Makefile.bcc-orig >nul echo Your existing echo ..\..\src\Makefile.bcc echo has been renamed to echo ..\..\src\Makefile.bcc-orig :dobor copy Makefile.bcc ..\..\src\Makefile.bcc >nul echo Borland Makefile copied ok. echo Copying MinGW Makefile - Makefile.gcc to ..\..\src\Makefile.gcc if NOT exist ..\..\src\Makefile.gcc goto :dogcc copy ..\..\src\Makefile.gcc ..\..\src\Makefile.gcc-orig >nul echo Your existing echo ..\..\src\Makefile.gcc echo has been renamed to echo ..\..\src\Makefile.gcc-orig :dogcc copy Makefile.gcc ..\..\src\Makefile.gcc >nul echo MinGW Makefile copied ok. :do_win if not exist ..\..\win\win32\nethack.dsw goto :err_win echo. echo Copying Visual C project files to ..\..\build directory echo Copying ..\..\win\win32\nethack.dsw ..\..\nethack.dsw copy ..\..\win\win32\nethack.dsw ..\.. >nul if NOT exist ..\..\binary\*.* echo Creating ..\..\binary directory if NOT exist ..\..\binary\*.* mkdir ..\..\binary if NOT exist ..\..\binary\license copy ..\..\dat\license ..\..\binary\license >nul if NOT exist ..\..\build\*.* echo Creating ..\..\build directory if NOT exist ..\..\build\*.* mkdir ..\..\build copy ..\..\win\win32\dgncomp.dsp ..\..\build >nul copy ..\..\win\win32\dgnstuff.dsp ..\..\build >nul copy ..\..\win\win32\dgnstuff.mak ..\..\build >nul copy ..\..\win\win32\dlb_main.dsp ..\..\build >nul copy ..\..\win\win32\levcomp.dsp ..\..\build >nul copy ..\..\win\win32\levstuff.dsp ..\..\build >nul copy ..\..\win\win32\levstuff.mak ..\..\build >nul copy ..\..\win\win32\makedefs.dsp ..\..\build >nul copy ..\..\win\win32\recover.dsp ..\..\build >nul copy ..\..\win\win32\tile2bmp.dsp ..\..\build >nul copy ..\..\win\win32\tiles.dsp ..\..\build >nul copy ..\..\win\win32\tiles.mak ..\..\build >nul copy ..\..\win\win32\tilemap.dsp ..\..\build >nul copy ..\..\win\win32\uudecode.dsp ..\..\build >nul copy ..\..\win\win32\nethackw.dsp ..\..\build >nul goto :done :err_win echo Some of the files needed to build graphical NetHack echo for Windows are not in the expected places. echo Check "Install.nt" for a list of the steps required echo to build NetHack. goto :fini :err_data echo A required file ..\..\dat\data.bas seems to be missing. echo Check "Files." in the root directory for your NetHack distribution echo and make sure that all required files exist. goto :fini :err_dir echo Your directories are not set up properly, please re-read the echo documentation and sys/winnt/Install.nt. goto :fini :done echo done! echo. echo Proceed with the next step documented in Install.nt echo. :fini :end set _pause=Y if "%0"=="nhsetup" set _pause=N if "%0"=="NHSETUP" set _pause=N if "%_pause%"=="Y" pause set _pause= nethack-3.4.3/sys/winnt/ntsound.c0100644000000000000000000000145707764735041015474 0ustar rootroot/* SCCS Id: @(#)ntsound.c 3.4 $Date: 2002/09/02 23:28:45 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* */ /* * ntsound.c - Windows NT NetHack sound support * *Edit History: * Initial Creation 93/12/11 * */ #include "hack.h" #include "win32api.h" #include #ifdef USER_SOUNDS void play_usersound(filename, volume) const char* filename; int volume; { /* pline("play_usersound: %s (%d).", filename, volume); */ (void)sndPlaySound(filename, SND_ASYNC | SND_NODEFAULT); } #endif /*USER_SOUNDS*/ /* ntsound.c */ nethack-3.4.3/sys/winnt/nttty.c0100644000000000000000000005120507764735041015160 0ustar rootroot/* SCCS Id: @(#)nttty.c 3.4 $Date: 2003/11/15 00:39:32 $ */ /* Copyright (c) NetHack PC Development Team 1993 */ /* NetHack may be freely redistributed. See license for details. */ /* tty.c - (Windows NT) version */ /* * Initial Creation M. Allison 1993/01/31 * Switch to low level console output routines M. Allison 2003/10/01 * Restrict cursor movement until input pending M. Lehotay 2003/10/02 * */ #ifdef WIN32CON #define NEED_VARARGS /* Uses ... */ #include "hack.h" #include "wintty.h" #include #include #include "win32api.h" void FDECL(cmov, (int, int)); void FDECL(nocmov, (int, int)); int FDECL(process_keystroke, (INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug)); /* * The following WIN32 Console API routines are used in this file. * * CreateFile * GetConsoleScreenBufferInfo * GetStdHandle * SetConsoleCursorPosition * SetConsoleTextAttribute * SetConsoleCtrlHandler * PeekConsoleInput * ReadConsoleInput * WriteConsoleOutputCharacter * FillConsoleOutputAttribute */ /* Win32 Console handles for input and output */ HANDLE hConIn; HANDLE hConOut; /* Win32 Screen buffer,coordinate,console I/O information */ CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi; COORD ntcoord; INPUT_RECORD ir; /* Flag for whether NetHack was launched via the GUI, not the command line. * The reason we care at all, is so that we can get * a final RETURN at the end of the game when launched from the GUI * to prevent the scoreboard (or panic message :-|) from vanishing * immediately after it is displayed, yet not bother when started * from the command line. */ int GUILaunched; static BOOL FDECL(CtrlHandler, (DWORD)); #ifdef PORT_DEBUG static boolean display_cursor_info = FALSE; #endif extern boolean getreturn_enabled; /* from sys/share/pcsys.c */ /* dynamic keystroke handling .DLL support */ typedef int (__stdcall * PROCESS_KEYSTROKE)( HANDLE, INPUT_RECORD *, boolean *, BOOLEAN_P, int ); typedef int (__stdcall * NHKBHIT)( HANDLE, INPUT_RECORD * ); typedef int (__stdcall * CHECKINPUT)( HANDLE, INPUT_RECORD *, DWORD *, BOOLEAN_P, int, int *, coord * ); typedef int (__stdcall * SOURCEWHERE)( char ** ); typedef int (__stdcall * SOURCEAUTHOR)( char ** ); typedef int (__stdcall * KEYHANDLERNAME)( char **, int ); HANDLE hLibrary; PROCESS_KEYSTROKE pProcessKeystroke; NHKBHIT pNHkbhit; CHECKINPUT pCheckInput; SOURCEWHERE pSourceWhere; SOURCEAUTHOR pSourceAuthor; KEYHANDLERNAME pKeyHandlerName; #ifndef CLR_MAX #define CLR_MAX 16 #endif int ttycolors[CLR_MAX]; # ifdef TEXTCOLOR static void NDECL(init_ttycolor); # endif static void NDECL(really_move_cursor); #define MAX_OVERRIDES 256 unsigned char key_overrides[MAX_OVERRIDES]; static char nullstr[] = ""; char erase_char,kill_char; #define DEFTEXTCOLOR ttycolors[7] static WORD background = 0; static WORD foreground = (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED); static WORD attr = (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED); static DWORD ccount, acount; static COORD cursor = {0,0}; /* * Called after returning from ! or ^Z */ void gettty() { #ifndef TEXTCOLOR int k; #endif erase_char = '\b'; kill_char = 21; /* cntl-U */ iflags.cbreak = TRUE; #ifdef TEXTCOLOR init_ttycolor(); #else for(k=0; k < CLR_MAX; ++k) ttycolors[k] = 7; #endif } /* reset terminal to original state */ void settty(s) const char *s; { cmov(ttyDisplay->curx, ttyDisplay->cury); end_screen(); if(s) raw_print(s); } /* called by init_nhwindows() and resume_nhwindows() */ void setftty() { start_screen(); } void tty_startup(wid, hgt) int *wid, *hgt; { int twid = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1; if (twid > 80) twid = 80; *wid = twid; *hgt = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1; set_option_mod_status("mouse_support", SET_IN_GAME); } void tty_number_pad(state) int state; { } void tty_start_screen() { if (iflags.num_pad) tty_number_pad(1); /* make keypad send digits */ } void tty_end_screen() { clear_screen(); really_move_cursor(); if (GetConsoleScreenBufferInfo(hConOut,&csbi)) { DWORD ccnt; COORD newcoord; newcoord.X = 0; newcoord.Y = 0; FillConsoleOutputAttribute(hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); FillConsoleOutputCharacter(hConOut,' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); } FlushConsoleInputBuffer(hConIn); } static BOOL CtrlHandler(ctrltype) DWORD ctrltype; { switch(ctrltype) { /* case CTRL_C_EVENT: */ case CTRL_BREAK_EVENT: clear_screen(); case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: getreturn_enabled = FALSE; #ifndef NOSAVEONHANGUP hangup(0); #endif #if 0 clearlocks(); terminate(EXIT_FAILURE); #endif default: return FALSE; } } /* called by init_tty in wintty.c for WIN32CON port only */ void nttty_open() { HANDLE hStdOut; DWORD cmode; long mask; load_keyboard_handler(); /* Initialize the function pointer that points to * the kbhit() equivalent, in this TTY case nttty_kbhit() */ nt_kbhit = nttty_kbhit; /* The following 6 lines of code were suggested by * Bob Landau of Microsoft WIN32 Developer support, * as the only current means of determining whether * we were launched from the command prompt, or from * the NT program manager. M. Allison */ hStdOut = GetStdHandle( STD_OUTPUT_HANDLE ); GetConsoleScreenBufferInfo( hStdOut, &origcsbi); GUILaunched = ((origcsbi.dwCursorPosition.X == 0) && (origcsbi.dwCursorPosition.Y == 0)); if ((origcsbi.dwSize.X <= 0) || (origcsbi.dwSize.Y <= 0)) GUILaunched = 0; /* Obtain handles for the standard Console I/O devices */ hConIn = GetStdHandle(STD_INPUT_HANDLE); hConOut = GetStdHandle(STD_OUTPUT_HANDLE); #if 0 hConIn = CreateFile("CONIN$", GENERIC_READ |GENERIC_WRITE, FILE_SHARE_READ |FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); hConOut = CreateFile("CONOUT$", GENERIC_READ |GENERIC_WRITE, FILE_SHARE_READ |FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,0); #endif GetConsoleMode(hConIn,&cmode); #ifdef NO_MOUSE_ALLOWED mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT; #else mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT; #endif /* Turn OFF the settings specified in the mask */ cmode &= ~mask; #ifndef NO_MOUSE_ALLOWED cmode |= ENABLE_MOUSE_INPUT; #endif SetConsoleMode(hConIn,cmode); if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE)) { /* Unable to set control handler */ cmode = 0; /* just to have a statement to break on for debugger */ } get_scr_size(); cursor.X = cursor.Y = 0; really_move_cursor(); } int process_keystroke(ir, valid, numberpad, portdebug) INPUT_RECORD *ir; boolean *valid; boolean numberpad; int portdebug; { int ch = pProcessKeystroke(hConIn, ir, valid, numberpad, portdebug); /* check for override */ if (ch && ch < MAX_OVERRIDES && key_overrides[ch]) ch = key_overrides[ch]; return ch; } int nttty_kbhit() { return pNHkbhit(hConIn, &ir); } void get_scr_size() { GetConsoleScreenBufferInfo(hConOut, &csbi); LI = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1); CO = csbi.srWindow.Right - (csbi.srWindow.Left + 1); if ( (LI < 25) || (CO < 80) ) { COORD newcoord; LI = 25; CO = 80; newcoord.Y = LI; newcoord.X = CO; SetConsoleScreenBufferSize( hConOut, newcoord ); } } int tgetch() { int mod; coord cc; DWORD count; really_move_cursor(); return pCheckInput(hConIn, &ir, &count, iflags.num_pad, 0, &mod, &cc); } int ntposkey(x, y, mod) int *x, *y, *mod; { int ch; coord cc; DWORD count; really_move_cursor(); ch = pCheckInput(hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc); if (!ch) { *x = cc.x; *y = cc.y; } return ch; } static void really_move_cursor() { #if defined(PORT_DEBUG) && defined(WIZARD) char oldtitle[BUFSZ], newtitle[BUFSZ]; if (display_cursor_info && wizard) { oldtitle[0] = '\0'; if (GetConsoleTitle(oldtitle, BUFSZ)) { oldtitle[39] = '\0'; } Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle, ttyDisplay->curx, ttyDisplay->cury, cursor.X, cursor.Y); (void)SetConsoleTitle(newtitle); } #endif if (ttyDisplay) { cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; } SetConsoleCursorPosition(hConOut, cursor); } void cmov(x, y) register int x, y; { ttyDisplay->cury = y; ttyDisplay->curx = x; cursor.X = x; cursor.Y = y; } void nocmov(x, y) int x,y; { cursor.X = x; cursor.Y = y; ttyDisplay->curx = x; ttyDisplay->cury = y; } void xputc_core(ch) char ch; { switch(ch) { case '\n': cursor.Y++; /* fall through */ case '\r': cursor.X = 1; break; case '\b': cursor.X--; break; default: WriteConsoleOutputAttribute(hConOut,&attr,1, cursor,&acount); WriteConsoleOutputCharacter(hConOut,&ch,1, cursor,&ccount); cursor.X++; } } void xputc(ch) char ch; { cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; xputc_core(ch); } void xputs(s) const char *s; { int k; int slen = strlen(s); if (ttyDisplay) { cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; } if (s) { for (k=0; k < slen && s[k]; ++k) xputc_core(s[k]); } } /* * Overrides wintty.c function of the same name * for win32. It is used for glyphs only, not text. */ void g_putch(in_ch) int in_ch; { char ch = (char)in_ch; cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; WriteConsoleOutputAttribute(hConOut,&attr,1,cursor,&acount); WriteConsoleOutputCharacter(hConOut,&ch,1,cursor,&ccount); } void cl_end() { int cx; cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; cx = CO - cursor.X; FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, cursor, &acount); FillConsoleOutputCharacter(hConOut,' ', cx, cursor,&ccount); tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury); } void clear_screen() { if (GetConsoleScreenBufferInfo(hConOut,&csbi)) { DWORD ccnt; COORD newcoord; newcoord.X = 0; newcoord.Y = 0; FillConsoleOutputAttribute(hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); FillConsoleOutputCharacter(hConOut,' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt); } home(); } void home() { cursor.X = cursor.Y = 0; ttyDisplay->curx = ttyDisplay->cury = 0; } void backsp() { cursor.X = ttyDisplay->curx; cursor.Y = ttyDisplay->cury; xputc_core('\b'); } void cl_eos() { int cy = ttyDisplay->cury+1; if (GetConsoleScreenBufferInfo(hConOut,&csbi)) { DWORD ccnt; COORD newcoord; newcoord.X = ttyDisplay->curx; newcoord.Y = ttyDisplay->cury; FillConsoleOutputAttribute(hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE, csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); FillConsoleOutputCharacter(hConOut,' ', csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt); } tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury); } void tty_nhbell() { if (flags.silent) return; Beep(8000,500); } volatile int junk; /* prevent optimizer from eliminating loop below */ void tty_delay_output() { /* delay 50 ms - uses ANSI C clock() function now */ clock_t goal; int k; goal = 50 + clock(); while (goal > clock()) { k = junk; /* Do nothing */ } } # ifdef TEXTCOLOR /* * CLR_BLACK 0 * CLR_RED 1 * CLR_GREEN 2 * CLR_BROWN 3 low-intensity yellow * CLR_BLUE 4 * CLR_MAGENTA 5 * CLR_CYAN 6 * CLR_GRAY 7 low-intensity white * NO_COLOR 8 * CLR_ORANGE 9 * CLR_BRIGHT_GREEN 10 * CLR_YELLOW 11 * CLR_BRIGHT_BLUE 12 * CLR_BRIGHT_MAGENTA 13 * CLR_BRIGHT_CYAN 14 * CLR_WHITE 15 * CLR_MAX 16 * BRIGHT 8 */ static void init_ttycolor() { ttycolors[CLR_BLACK] = FOREGROUND_INTENSITY; /* fix by Quietust */ ttycolors[CLR_RED] = FOREGROUND_RED; ttycolors[CLR_GREEN] = FOREGROUND_GREEN; ttycolors[CLR_BROWN] = FOREGROUND_GREEN|FOREGROUND_RED; ttycolors[CLR_BLUE] = FOREGROUND_BLUE; ttycolors[CLR_MAGENTA] = FOREGROUND_BLUE|FOREGROUND_RED; ttycolors[CLR_CYAN] = FOREGROUND_GREEN|FOREGROUND_BLUE; ttycolors[CLR_GRAY] = FOREGROUND_GREEN|FOREGROUND_RED|FOREGROUND_BLUE; ttycolors[BRIGHT] = FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED|\ FOREGROUND_INTENSITY; ttycolors[CLR_ORANGE] = FOREGROUND_RED|FOREGROUND_INTENSITY; ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN|FOREGROUND_INTENSITY; ttycolors[CLR_YELLOW] = FOREGROUND_GREEN|FOREGROUND_RED|\ FOREGROUND_INTENSITY; ttycolors[CLR_BRIGHT_BLUE] = FOREGROUND_BLUE|FOREGROUND_INTENSITY; ttycolors[CLR_BRIGHT_MAGENTA] = FOREGROUND_BLUE|FOREGROUND_RED|\ FOREGROUND_INTENSITY; ttycolors[CLR_BRIGHT_CYAN] = FOREGROUND_GREEN|FOREGROUND_BLUE|\ FOREGROUND_INTENSITY; ttycolors[CLR_WHITE] = FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED|\ FOREGROUND_INTENSITY; } # endif /* TEXTCOLOR */ int has_color(int color) { # ifdef TEXTCOLOR return 1; # else if (color == CLR_BLACK) return 1; else if (color == CLR_WHITE) return 1; else return 0; # endif } void term_start_attr(int attrib) { switch(attrib){ case ATR_INVERSE: if (iflags.wc_inverse) { /* Suggestion by Lee Berger */ if ((foreground & (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED)) == (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED)) foreground &= ~(FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED); background = (BACKGROUND_RED|BACKGROUND_BLUE|BACKGROUND_GREEN); break; } /*FALLTHRU*/ case ATR_ULINE: case ATR_BLINK: case ATR_BOLD: foreground |= FOREGROUND_INTENSITY; break; default: foreground &= ~FOREGROUND_INTENSITY; break; } attr = (foreground | background); } void term_end_attr(int attrib) { switch(attrib){ case ATR_INVERSE: if ((foreground & (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED)) == 0) foreground |= (FOREGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_RED); background = 0; break; case ATR_ULINE: case ATR_BLINK: case ATR_BOLD: foreground &= ~FOREGROUND_INTENSITY; break; } attr = (foreground | background); } void term_end_raw_bold(void) { term_end_attr(ATR_BOLD); } void term_start_raw_bold(void) { term_start_attr(ATR_BOLD); } void term_start_color(int color) { #ifdef TEXTCOLOR if (color >= 0 && color < CLR_MAX) { foreground = (background != 0 && (color == CLR_GRAY || color == CLR_WHITE)) ? ttycolors[0] : ttycolors[color]; } #else foreground = DEFTEXTCOLOR; #endif attr = (foreground | background); } void term_end_color(void) { #ifdef TEXTCOLOR foreground = DEFTEXTCOLOR; #endif attr = (foreground | background); } void standoutbeg() { term_start_attr(ATR_BOLD); } void standoutend() { term_end_attr(ATR_BOLD); } #ifndef NO_MOUSE_ALLOWED void toggle_mouse_support() { DWORD cmode; GetConsoleMode(hConIn,&cmode); if (iflags.wc_mouse_support) cmode |= ENABLE_MOUSE_INPUT; else cmode &= ~ENABLE_MOUSE_INPUT; SetConsoleMode(hConIn,cmode); } #endif /* handle tty options updates here */ void nttty_preference_update(pref) const char *pref; { if( stricmp( pref, "mouse_support")==0) { #ifndef NO_MOUSE_ALLOWED toggle_mouse_support(); #endif } return; } #ifdef PORT_DEBUG void win32con_debug_keystrokes() { DWORD count; boolean valid = 0; int ch; xputs("\n"); while (!valid || ch != 27) { nocmov(ttyDisplay->curx, ttyDisplay->cury); ReadConsoleInput(hConIn,&ir,1,&count); if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown) ch = process_keystroke(&ir, &valid, iflags.num_pad, 1); } (void)doredraw(); } void win32con_handler_info() { char *buf; int ci; if (!pSourceAuthor && !pSourceWhere) pline("Keyboard handler source info and author unavailable."); else { if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) { xputs("\n"); xputs("Keystroke handler loaded: \n "); xputs(buf); } if (pSourceAuthor && pSourceAuthor(&buf)) { xputs("\n"); xputs("Keystroke handler Author: \n "); xputs(buf); } if (pSourceWhere && pSourceWhere(&buf)) { xputs("\n"); xputs("Keystroke handler source code available at:\n "); xputs(buf); } xputs("\nPress any key to resume."); ci=nhgetch(); (void)doredraw(); } } void win32con_toggle_cursor_info() { display_cursor_info = !display_cursor_info; } #endif void map_subkeyvalue(op) register char *op; { char digits[] = "0123456789"; int length, i, idx, val; char *kp; idx = -1; val = -1; kp = index(op, '/'); if (kp) { *kp = '\0'; kp++; length = strlen(kp); if (length < 1 || length > 3) return; for (i = 0; i < length; i++) if (!index(digits, kp[i])) return; val = atoi(kp); length = strlen(op); if (length < 1 || length > 3) return; for (i = 0; i < length; i++) if (!index(digits, op[i])) return; idx = atoi(op); } if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1) return; key_overrides[idx] = val; } void load_keyboard_handler() { char suffx[] = ".dll"; char *truncspot; #define MAX_DLLNAME 25 char kh[MAX_ALTKEYHANDLER]; if (iflags.altkeyhandler[0]) { if (hLibrary) { /* already one loaded apparently */ FreeLibrary(hLibrary); hLibrary = (HANDLE)0; pNHkbhit = (NHKBHIT)0; pCheckInput = (CHECKINPUT)0; pSourceWhere = (SOURCEWHERE)0; pSourceAuthor = (SOURCEAUTHOR)0; pKeyHandlerName = (KEYHANDLERNAME)0; pProcessKeystroke = (PROCESS_KEYSTROKE)0; } if ((truncspot = strstri(iflags.altkeyhandler, suffx)) != 0) *truncspot = '\0'; (void) strncpy(kh, iflags.altkeyhandler, (MAX_ALTKEYHANDLER - sizeof suffx) - 1); kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0'; Strcat(kh, suffx); Strcpy(iflags.altkeyhandler, kh); hLibrary = LoadLibrary(kh); if (hLibrary) { pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress (hLibrary, TEXT ("ProcessKeystroke")); pNHkbhit = (NHKBHIT) GetProcAddress (hLibrary, TEXT ("NHkbhit")); pCheckInput = (CHECKINPUT) GetProcAddress (hLibrary, TEXT ("CheckInput")); pSourceWhere = (SOURCEWHERE) GetProcAddress (hLibrary, TEXT ("SourceWhere")); pSourceAuthor = (SOURCEAUTHOR) GetProcAddress (hLibrary, TEXT ("SourceAuthor")); pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress (hLibrary, TEXT ("KeyHandlerName")); } } if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) { if (hLibrary) { FreeLibrary(hLibrary); hLibrary = (HANDLE)0; pNHkbhit = (NHKBHIT)0; pCheckInput = (CHECKINPUT)0; pSourceWhere = (SOURCEWHERE)0; pSourceAuthor = (SOURCEAUTHOR)0; pKeyHandlerName = (KEYHANDLERNAME)0; pProcessKeystroke = (PROCESS_KEYSTROKE)0; } (void)strncpy(kh, "nhdefkey.dll", (MAX_ALTKEYHANDLER - sizeof suffx) - 1); kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0'; Strcpy(iflags.altkeyhandler, kh); hLibrary = LoadLibrary(kh); if (hLibrary) { pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress (hLibrary, TEXT ("ProcessKeystroke")); pCheckInput = (CHECKINPUT) GetProcAddress (hLibrary, TEXT ("CheckInput")); pNHkbhit = (NHKBHIT) GetProcAddress (hLibrary, TEXT ("NHkbhit")); pSourceWhere = (SOURCEWHERE) GetProcAddress (hLibrary, TEXT ("SourceWhere")); pSourceAuthor = (SOURCEAUTHOR) GetProcAddress (hLibrary, TEXT ("SourceAuthor")); pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress (hLibrary, TEXT ("KeyHandlerName")); } } if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) { if (!hLibrary) raw_printf("\nNetHack was unable to load keystroke handler.\n"); else { FreeLibrary(hLibrary); hLibrary = (HANDLE)0; raw_printf("\nNetHack keystroke handler is invalid.\n"); } exit(EXIT_FAILURE); } } /* this is used as a printf() replacement when the window * system isn't initialized yet */ void msmsg VA_DECL(const char *, fmt) char buf[ROWNO * COLNO]; /* worst case scenario */ VA_START(fmt); VA_INIT(fmt, const char *); Vsprintf(buf, fmt, VA_ARGS); VA_END(); xputs(buf); if (ttyDisplay) curs(BASE_WINDOW, cursor.X+1, cursor.Y); return; } /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *,s) char buf[BUFSZ]; VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); buf[0] = '\n'; (void) vsprintf(&buf[1], s, VA_ARGS); VA_END(); msmsg(buf); really_move_cursor(); exit(EXIT_FAILURE); } void synch_cursor() { really_move_cursor(); } #endif /* WIN32CON */ nethack-3.4.3/sys/winnt/porthelp0100644000000000000000000003220107764735041015405 0ustar rootroot Microsoft Windows specific help file for NetHack 3.4.3 Copyright (c) NetHack PC Development Team 1993-2002. NetHack may be freely distributed. See license for details. (Last Revision: October 14, 2003) This file details specifics for NetHack built for Windows 95, 98, NT, Me, 2000, and XP. Users of really early 16-bit Windows versions should use the MSDOS NetHack. Please note that "NetHack for Windows - Graphical Interface" requires an installation of Internet Explorer 4 or an installation of version 4.71 of the common controls. See the following internet page: http://www.nethack.org/v340/ports/download-win.html#cc for more information. If the game runs for you, you are not affected. New players should be sure to read GuideBook.txt which contains essential information about playing NetHack. It can be found in the same directory as your NetHack executable. The NetHack for Windows port supports some additional or enhanced commands as well as some defaults.nh file options specific to configuration choices used during the building of NetHack for Windows. Listed below are those commands and defaults.nh file options. Some options are applicable only to the "Graphical Interface." These are discussed separately in their own section. Contents 1. ALT Key Combinations 2. Boolean options - Option that you can toggle on or off 3. Graphical Interface - Options you can assign a value to 4. Graphical Interface - Additional/Enhanced Commands 5. Graphical Interface - Menus 6. Numeric Keypad (for number_pad mode) 1. ALT Key Combinations ---------------------------------------------- The non-graphical (tty) interface always operates in "NetHack mode", while the "NetHack for Windows - Graphical Interface" lets you toggle the mode. In non-NetHack mode, all ALT-key combinations are sent to the Windows itself, rather than to NetHack. While playing in NetHack mode you can press the ALT key in combination with another key to execute an extended command as an alternative method to pressing a # key sequence. The available commands are: Alt-2 #twoweapon - toggle two-weapon combat (unavailable if number_pad mode is set) Alt-a #adjust - adjust inventory letters. Alt-c #chat - talk to someone or something. Alt-d #dip - dip an object into something. Alt-e #enhance - enhance your skill with a weapon. Alt-f #force - force a lock. Alt-i #invoke - invoke an object's powers. Alt-j #jump - jump to a location. Alt-l #loot - loot a box on the floor. Alt-m #monster - use a monster's special ability. Alt-n #name - name an item or type of object. Alt-o #offer - offer a sacrifice to the gods. Alt-p #pray - pray to the gods for help. Alt-q #quit - quit the game. (Same as #quit) Alt-r #rub - rub a lamp. Alt-s #sit - sit down. Alt-t #turn - turn undead. Alt-u #untrap - untrap something. Alt-v #version - list compile time options for this version of NetHack. Alt-w #wipe - wipe off your face. Alt-? #? - display list of extended menu commands 2. Boolean Options (Options that can be toggled on or off) ---------------------------------------------------------- Listed here are any options not discussed in the main help, options which may be slightly different from the main help file, and options which may need a slightly more explanatory note: color Use color when displaying non-tiled maps. Tiled maps (available in the graphical port) are always rendered in color. Default: [TRUE] hilite_pet Using tiled graphics, displays a small heart symbol next to your pet. Using ascii graphics, the pet is hilited in a white background. Default: [TRUE] IBMgraphics Use IBM extended characters for the dungeon Default: [TRUE] msg_window When ^P is pressed, it shows menu in a full window. Available only in the non-graphical (tty) version. Default: [FALSE] toptenwin Write top ten list to a window, as opposed to stdout. Default in tty interface: [FALSE] Default in graphical interface: [TRUE] (and cannot be changed) 3. Options that you assign a value to (Graphical Interface only) ---------------------------------------------------------------- "NetHack for Windows - Graphical Interface" recognizes the following additional options, which the non-graphical (tty) version will silently ignore. These are options that specify attributes of various windows. The windows that you can tailor include menu windows (such as the inventory list), text windows (such as "It is written in the book of ..." screens), the message window (where events of the game are displayed), the status window (where your character name and attributes are displayed), and the map window (where the map is drawn). Window Alignment options: align_message Specifies at which side of the NetHack screen the message window is aligned. This option can be used to align the window to "top" or "bottom". Default: [TOP] align_status Specifies at which side of the NetHack screen the status window is aligned. This option can be used to align the window to "top" or "bottom". Default: [BOTTOM] Map Window options: map_mode Specifies which map mode to use. The following map modes are available: tiles (display things on the map with colored tiles), ascii4x6, ascii6x8, ascii8x8, ascii16x8, ascii7x12, ascii8x12, ascii16x12, ascii12x16, ascii10x18 (which use that size font to display things on the map), or fit_to_screen (an ascii mode which forces things to fit on a single screen). Default: [tiles] scroll_margin Specifies the number of map cells from the edge of the map window where scrolling will take place. Default: [5] tile_file An alternative file containing bitmap to use for tiles. This file should be a .bmp file and should be organized as 40 rectangular tiles wide. It is beyond the scope of this document to describe the exact contents of each tile in the .bmp, which must match the object lists used when building NetHack. tile_height Used with tile_file to specify the height of each tile in pixels. This option may only be specified in the defaults.nh config file. Default: [16] tile_width Used with tile_file to specify the width of each tile in pixels. This option may only be specified in the defaults.nh config file. Default: [16] Other Window options: windowcolors Specifies the colors for various windows This option may only be specified in the defaults.nh config file and has the following format: window-type foreground/background Notes: - Both foreground and background colors are required, and a slash must separate them. - "window-type" is either "message" or "status" (Short forms are: "msg" or "sts"). - "foreground" and "background" may be specified as a color name (such as "blue"), or by a six digit hexadecimal RGB color value (such as "#8F8F8F") - The following color names are available: black, red, green, brown, blue, magenta, cyan, gray (or grey), orange, brightgreen, yellow, brightblue, brightmagenta, brightcyan, white, trueblack, purple, silver, maroon, fuchsia, lime, olive, navy, teal, aqua. In addition, you can use the following names to refer to default Windows settings: activeborder, activecaption, appworkspace, background, btnface, btnshadow, btntext, captiontext, graytext, highlight, highlighttext, inactiveborder, inactivecaption, menu, menutext, scrollbar, window, windowframe, windowtext. Example: OPTIONS=windowcolors:sts #00FF80/blue msg menutext/menu font_menu Specifies the name of the menu font. font_message Specifies the name of the message font. font_status Specifies the name of the status font. font_text Specifies the name of the text font. font_size_menu Specifies the size of the menu font. font_size_message Specifies the size of the message font. font_size_status Specifies the size of the status font. font_size_text Specifies the size of the text font. Miscellaneous options: vary_msgcount Number of lines to display in message window. 4. NetHack for Windows - Graphical Interface, Additional/Enhanced Commands ------------------------------------------------------------------------- The following function keys are active in the "NetHack for Windows - Graphical Interface": F4 Toggle level overview mode on/off This key will toggle the map between a view that is mapped to fit exactly to the window, and the view that shows the various symbols in their normal size. This is useful for getting an idea of where you are in a level. F5 Toggle tiled display on/off. This key switches between the tiled and the traditional ASCII display. This is equivalent to using the "map_mode" option. F10 Activate menu bar. This key will activate the menu bar, allowing you to select between the menus: File, Map, Window Settings, and Help. 5. Graphical Port Menus ----------------------- File Save - Allows you to save and exit the game Quit - Allows you to quit the game Map - Provides for selection of map mode. Equivalent to using the map_mode option. Window Settings - Changes your logged-on user's settings for NetHack. In 3.4.3, only one setting is available: NetHack mode, which can be checked or unchecked. NetHack mode allows you to use the ALT key for game key commands [see list above]. You can use F10 to access the menu bar while in NetHack mode. You can also clear your logged-on user's settings for NetHack. Settings in this window are saved in your logged-on user's registry. Help - Provides help about various portions of NetHack. 6. Numeric Keypad (for "OPTION=number_pad" mode) ------------------------------------------------ The numeric keypad and surrounding characters act as macros for different commands in NetHack. The Num Lock should be toggled to "on" to make the most of these keys: Key Normal Shift-Key ---------- ---------- ------------- 1, 2, 3, 4 Move In Run In 6, 7, 8, 9 Direction Direction 0 (Ins) Inventory Categorized Inventory . (Del) Wait Turn : - Look Here + Spell List P - Put on an accessory - m - Move Previous Only Message NetHack for Windows - tty Interface Specific Behavior: ------------------------------------------------------ In the non-graphical (tty) interface, when you use the Ctrl key with a directional key (1, 2, 3, 4, 6, 7, 8, 9) it means "go in specified direction until you hit a wall or run into something interesting." NetHack for Windows - Graphical Interface Specific Behavior: ------------------------------------------------------------ It is possible to scroll or pan the map in a specific direction: Ctrl-Shift-Left (4) Scroll (Pan) map left Ctrl-Shift-Right (6) Scroll (Pan) map right Ctrl-Shift-Up (8) Scroll (Pan) map up Ctrl-Shift-Down (2) Scroll (Pan) map down Ctrl-Shift-Home (7) Scroll (Pan) map left to leftmost corner Ctrl-Shift-End (1) Scroll (Pan) map left to rightmost corner Ctrl-Shift-PgUp (9) Scroll (Pan) map left to uppermost corner Ctrl-Shift-PgDn (3) Scroll (Pan) map left to lowermost corner nethack-3.4.3/sys/winnt/win32api.h0100644000000000000000000000131607764735041015435 0ustar rootroot/* SCCS Id: @(#)win32api.h 3.4 $Date: 2002/07/24 08:25:21 $ */ /* Copyright (c) NetHack PC Development Team 1996 */ /* NetHack may be freely redistributed. See license for details. */ /* * This header file is used to clear up some discrepencies with Visual C * header files & NetHack before including windows.h, so all NetHack * files should include "win32api.h" rather than . */ # if defined(_MSC_VER) # undef strcmpi # undef min # undef max # pragma warning(disable:4142) /* Warning, Benign redefinition of type */ # pragma pack(8) # endif #define WIN32_LEAN_AND_MEAN #include #include # if defined(_MSC_VER) # pragma pack() # endif /*win32api.h*/ nethack-3.4.3/sys/winnt/winnt.c0100644000000000000000000001472007764735041015136 0ustar rootroot/* SCCS Id: @(#)winnt.c 3.4 $Date: 2003/10/26 15:58:22 $ */ /* Copyright (c) NetHack PC Development Team 1993, 1994 */ /* NetHack may be freely redistributed. See license for details. */ /* * WIN32 system functions. * * Initial Creation: Michael Allison - January 31/93 * */ #define NEED_VARARGS #include "hack.h" #include #ifndef __BORLANDC__ #include #endif #include #include "win32api.h" #ifdef WIN32CON #include "wintty.h" #endif #ifdef WIN32 /* * The following WIN32 API routines are used in this file. * * GetDiskFreeSpace * GetVolumeInformation * GetUserName * FindFirstFile * FindNextFile * FindClose * */ /* globals required within here */ HANDLE ffhandle = (HANDLE)0; WIN32_FIND_DATA ffd; /* The function pointer nt_kbhit contains a kbhit() equivalent * which varies depending on which window port is active. * For the tty port it is tty_kbhit() [from nttty.c] * For the win32 port it is win32_kbhit() [from winmain.c] * It is initialized to point to def_kbhit [in here] for safety. */ int def_kbhit(void); int (*nt_kbhit)() = def_kbhit; char switchar() { /* Could not locate a WIN32 API call for this- MJA */ return '-'; } long freediskspace(path) char *path; { char tmppath[4]; DWORD SectorsPerCluster = 0; DWORD BytesPerSector = 0; DWORD FreeClusters = 0; DWORD TotalClusters = 0; tmppath[0] = *path; tmppath[1] = ':'; tmppath[2] = '\\'; tmppath[3] = '\0'; GetDiskFreeSpace(tmppath, &SectorsPerCluster, &BytesPerSector, &FreeClusters, &TotalClusters); return (long)(SectorsPerCluster * BytesPerSector * FreeClusters); } /* * Functions to get filenames using wildcards */ int findfirst(path) char *path; { if (ffhandle){ FindClose(ffhandle); ffhandle = (HANDLE)0; } ffhandle = FindFirstFile(path,&ffd); return (ffhandle == INVALID_HANDLE_VALUE) ? 0 : 1; } int findnext() { return FindNextFile(ffhandle,&ffd) ? 1 : 0; } char * foundfile_buffer() { return &ffd.cFileName[0]; } long filesize(file) char *file; { if (findfirst(file)) { return ((long)ffd.nFileSizeLow); } else return -1L; } /* * Chdrive() changes the default drive. */ void chdrive(str) char *str; { char *ptr; char drive; if ((ptr = index(str, ':')) != (char *)0) { drive = toupper(*(ptr - 1)); _chdrive((drive - 'A') + 1); } } static int max_filename() { DWORD maxflen; int status=0; status = GetVolumeInformation((LPTSTR)0,(LPTSTR)0, 0 ,(LPDWORD)0,&maxflen,(LPDWORD)0,(LPTSTR)0,0); if (status) return maxflen; else return 0; } int def_kbhit() { return 0; } /* * Strip out troublesome file system characters. */ void nt_regularize(s) /* normalize file name */ register char *s; { register unsigned char *lp; for (lp = s; *lp; lp++) if ( *lp == '?' || *lp == '"' || *lp == '\\' || *lp == '/' || *lp == '>' || *lp == '<' || *lp == '*' || *lp == '|' || *lp == ':' || (*lp > 127)) *lp = '_'; } /* * This is used in nhlan.c to implement some of the LAN_FEATURES. */ char *get_username(lan_username_size) int *lan_username_size; { static TCHAR username_buffer[BUFSZ]; unsigned int status; DWORD i = BUFSZ - 1; /* i gets updated with actual size */ status = GetUserName(username_buffer, &i); if (status) username_buffer[i] = '\0'; else Strcpy(username_buffer, "NetHack"); if (lan_username_size) *lan_username_size = strlen(username_buffer); return username_buffer; } # if 0 char *getxxx() { char szFullPath[MAX_PATH] = ""; HMODULE hInst = NULL; /* NULL gets the filename of this module */ GetModuleFileName(hInst, szFullPath, sizeof(szFullPath)); return &szFullPath[0]; } # endif #ifndef WIN32CON /* fatal error */ /*VARARGS1*/ void error VA_DECL(const char *,s) char buf[BUFSZ]; VA_START(s); VA_INIT(s, const char *); /* error() may get called before tty is initialized */ if (iflags.window_inited) end_screen(); if (!strncmpi(windowprocs.name, "tty", 3)) { buf[0] = '\n'; (void) vsprintf(&buf[1], s, VA_ARGS); Strcat(buf, "\n"); msmsg(buf); } else { (void) vsprintf(buf, s, VA_ARGS); Strcat(buf, "\n"); raw_printf(buf); } VA_END(); exit(EXIT_FAILURE); } #endif void Delay(int ms) { (void)Sleep(ms); } #ifdef WIN32CON extern void NDECL(backsp); #endif void win32_abort() { #ifdef WIZARD if (wizard) { # ifdef WIN32CON int c, ci, ct; if (!iflags.window_inited) c = 'n'; ct = 0; msmsg("Execute debug breakpoint wizard?"); while ((ci=nhgetch()) != '\n') { if (ct > 0) { backsp(); /* \b is visible on NT */ (void) putchar(' '); backsp(); ct = 0; c = 'n'; } if (ci == 'y' || ci == 'n' || ci == 'Y' || ci == 'N') { ct = 1; c = ci; msmsg("%c",c); } } if (c == 'y') DebugBreak(); # endif } #endif abort(); } static char interjection_buf[INTERJECTION_TYPES][1024]; static int interjection[INTERJECTION_TYPES]; void interject_assistance(num, interjection_type, ptr1, ptr2) int num; int interjection_type; genericptr_t ptr1; genericptr_t ptr2; { switch(num) { case 1: { char *panicmsg = (char *)ptr1; char *datadir = (char *)ptr2; char *tempdir = nh_getenv("TEMP"); interjection_type = INTERJECT_PANIC; interjection[INTERJECT_PANIC] = 1; /* * ptr1 = the panic message about to be delivered. * ptr2 = the directory prefix of the dungeon file * that failed to open. * Check to see if datadir matches tempdir or a * common windows temp location. If it does, inform * the user that they are probably trying to run the * game from within their unzip utility, so the required * files really don't exist at the location. Instruct * them to unpack them first. */ if (panicmsg && datadir) { if (!strncmpi(datadir, "C:\\WINDOWS\\TEMP", 15) || strstri(datadir, "TEMP") || (tempdir && strstri(datadir, tempdir))) { (void)strncpy(interjection_buf[INTERJECT_PANIC], "\nOne common cause of this error is attempting to execute\n" "the game by double-clicking on it while it is displayed\n" "inside an unzip utility.\n\n" "You have to unzip the contents of the zip file into a\n" "folder on your system, and then run \"NetHack.exe\" or \n" "\"NetHackW.exe\" from there.\n\n" "If that is not the situation, you are encouraged to\n" "report the error as shown above.\n\n", 1023); } } } break; } } void interject(interjection_type) int interjection_type; { if (interjection_type >= 0 && interjection_type < INTERJECTION_TYPES) msmsg(interjection_buf[interjection_type]); } #endif /* WIN32 */ /*winnt.c*/ nethack-3.4.3/util/0040755000000000000000000000000007764735121012631 5ustar rootrootnethack-3.4.3/util/dgn_comp.l0100644000000000000000000000765407764735041014606 0ustar rootroot%{ /* SCCS Id: @(#)dgn_lex.c 3.4 2002/03/27 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ #define DGN_COMP #include "config.h" #include "dgn_comp.h" #include "dgn_file.h" /* * Most of these don't exist in flex, yywrap is macro and * yyunput is properly declared in flex.skel. */ #if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) int FDECL(yyback, (int *,int)); int NDECL(yylook); int NDECL(yyinput); int NDECL(yywrap); int NDECL(yylex); /* Traditional lexes let yyunput() and yyoutput() default to int; * newer ones may declare them as void since they don't return * values. For even more fun, the lex supplied as part of the * newer unbundled compiler for SunOS 4.x adds the void declarations * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain * int) while the bundled lex and the one with the older unbundled * compiler do not. To detect this, we need help from outside -- * sys/unix/Makefile.utl. * * Digital UNIX is difficult and still has int in spite of all * other signs. */ # if defined(NeXT) || defined(SVR4) || defined(_AIX32) # define VOIDYYPUT # endif # if !defined(VOIDYYPUT) && defined(POSIX_TYPES) # if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) # define VOIDYYPUT # endif # endif # if !defined(VOIDYYPUT) && defined(WEIRD_LEX) # if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) # define VOIDYYPUT # endif # endif # if defined(VOIDYYPUT) && defined(__osf__) # undef VOIDYYPUT # endif # ifdef VOIDYYPUT void FDECL(yyunput, (int)); void FDECL(yyoutput, (int)); # else int FDECL(yyunput, (int)); int FDECL(yyoutput, (int)); # endif #endif /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ #ifdef FLEX_SCANNER #define YY_MALLOC_DECL \ genericptr_t FDECL(malloc, (size_t)); \ genericptr_t FDECL(realloc, (genericptr_t,size_t)); #endif void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); /* this doesn't always get put in dgn_comp.h * (esp. when using older versions of bison) */ extern YYSTYPE yylval; int line_number = 1; %} %% DUNGEON return(A_DUNGEON); up { yylval.i=1; return(UP_OR_DOWN); } down { yylval.i=0; return(UP_OR_DOWN); } ENTRY return(ENTRY); stair return(STAIR); no_up return(NO_UP); no_down return(NO_DOWN); portal return(PORTAL); PROTOFILE return(PROTOFILE); DESCRIPTION return(DESCRIPTION); LEVELDESC return(LEVELDESC); ALIGNMENT return(ALIGNMENT); LEVALIGN return(LEVALIGN); town { yylval.i=TOWN ; return(DESCRIPTOR); } hellish { yylval.i=HELLISH ; return(DESCRIPTOR); } mazelike { yylval.i=MAZELIKE ; return(DESCRIPTOR); } roguelike { yylval.i=ROGUELIKE ; return(DESCRIPTOR); } unaligned { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } noalign { yylval.i=D_ALIGN_NONE ; return(DESCRIPTOR); } lawful { yylval.i=D_ALIGN_LAWFUL ; return(DESCRIPTOR); } neutral { yylval.i=D_ALIGN_NEUTRAL ; return(DESCRIPTOR); } chaotic { yylval.i=D_ALIGN_CHAOTIC ; return(DESCRIPTOR); } BRANCH return(BRANCH); CHAINBRANCH return(CHBRANCH); LEVEL return(LEVEL); RNDLEVEL return(RNDLEVEL); CHAINLEVEL return(CHLEVEL); RNDCHLEVEL return(RNDCHLEVEL); [-0-9]+ { yylval.i=atoi(yytext); return(INTEGER); } \"[^"]*\" { yytext[yyleng-1] = 0; /* Discard the trailing \" */ yylval.str = (char *) alloc(strlen(yytext+1)+1); Strcpy(yylval.str, yytext+1); /* Discard the first \" */ return(STRING); } ^#.*\n { line_number++; } \r?\n { line_number++; } [ \t]+ ; /* skip trailing tabs & spaces */ . { return yytext[0]; } %% /* routine to switch to another input file; needed for flex */ void init_yyin( input_f ) FILE *input_f; { #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) if (yyin) yyrestart(input_f); else #endif yyin = input_f; } /* analogous routine (for completeness) */ void init_yyout( output_f ) FILE *output_f; { yyout = output_f; } /*dgn_comp.l*/ nethack-3.4.3/util/dgn_comp.y0100644000000000000000000003713107764735041014614 0ustar rootroot%{ /* SCCS Id: @(#)dgn_comp.c 3.4 1996/06/22 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the Dungeon Compiler code */ /* In case we're using bison in AIX. This definition must be * placed before any other C-language construct in the file * excluding comments and preprocessor directives (thanks IBM * for this wonderful feature...). * * Note: some cpps barf on this 'undefined control' (#pragma). * Addition of the leading space seems to prevent barfage for now, * and AIX will still see the directive in its non-standard locale. */ #ifdef _AIX #pragma alloca /* keep leading space! */ #endif #include "config.h" #include "date.h" #include "dgn_file.h" void FDECL(yyerror, (const char *)); void FDECL(yywarning, (const char *)); int NDECL(yylex); int NDECL(yyparse); int FDECL(getchain, (char *)); int NDECL(check_dungeon); int NDECL(check_branch); int NDECL(check_level); void NDECL(init_dungeon); void NDECL(init_branch); void NDECL(init_level); void NDECL(output_dgn); #define Free(ptr) free((genericptr_t)ptr) #ifdef AMIGA # undef printf #ifndef LATTICE # define memset(addr,val,len) setmem(addr,len,val) #endif #endif #define ERR (-1) static struct couple couple; static struct tmpdungeon tmpdungeon[MAXDUNGEON]; static struct tmplevel tmplevel[LEV_LIMIT]; static struct tmpbranch tmpbranch[BRANCH_LIMIT]; static int in_dungeon = 0, n_dgns = -1, n_levs = -1, n_brs = -1; extern int fatal_error; extern const char *fname; extern FILE *yyin, *yyout; /* from dgn_lex.c */ %} %union { int i; char* str; } %token INTEGER %token A_DUNGEON BRANCH CHBRANCH LEVEL RNDLEVEL CHLEVEL RNDCHLEVEL %token UP_OR_DOWN PROTOFILE DESCRIPTION DESCRIPTOR LEVELDESC %token ALIGNMENT LEVALIGN ENTRY STAIR NO_UP NO_DOWN PORTAL %token STRING %type optional_int direction branch_type bones_tag %start file %% file : /* nothing */ | dungeons { output_dgn(); } ; dungeons : dungeon | dungeons dungeon ; dungeon : dungeonline | dungeondesc | branches | levels ; dungeonline : A_DUNGEON ':' STRING bones_tag rcouple optional_int { init_dungeon(); Strcpy(tmpdungeon[n_dgns].name, $3); tmpdungeon[n_dgns].boneschar = (char)$4; tmpdungeon[n_dgns].lev.base = couple.base; tmpdungeon[n_dgns].lev.rand = couple.rand; tmpdungeon[n_dgns].chance = $6; Free($3); } ; optional_int : /* nothing */ { $$ = 0; } | INTEGER { $$ = $1; } ; dungeondesc : entry | descriptions | prototype ; entry : ENTRY ':' INTEGER { tmpdungeon[n_dgns].entry_lev = $3; } ; descriptions : desc ; desc : DESCRIPTION ':' DESCRIPTOR { if($3 <= TOWN || $3 >= D_ALIGN_CHAOTIC) yyerror("Illegal description - ignoring!"); else tmpdungeon[n_dgns].flags |= $3 ; } | ALIGNMENT ':' DESCRIPTOR { if($3 && $3 < D_ALIGN_CHAOTIC) yyerror("Illegal alignment - ignoring!"); else tmpdungeon[n_dgns].flags |= $3 ; } ; prototype : PROTOFILE ':' STRING { Strcpy(tmpdungeon[n_dgns].protoname, $3); Free($3); } ; levels : level1 | level2 | levdesc | chlevel1 | chlevel2 ; level1 : LEVEL ':' STRING bones_tag '@' acouple { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmpdungeon[n_dgns].levels++; Free($3); } | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].rndlevs = $7; tmpdungeon[n_dgns].levels++; Free($3); } ; level2 : LEVEL ':' STRING bones_tag '@' acouple INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = $7; tmpdungeon[n_dgns].levels++; Free($3); } | RNDLEVEL ':' STRING bones_tag '@' acouple INTEGER INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = $7; tmplevel[n_levs].rndlevs = $8; tmpdungeon[n_dgns].levels++; Free($3); } ; levdesc : LEVELDESC ':' DESCRIPTOR { if($3 >= D_ALIGN_CHAOTIC) yyerror("Illegal description - ignoring!"); else tmplevel[n_levs].flags |= $3 ; } | LEVALIGN ':' DESCRIPTOR { if($3 && $3 < D_ALIGN_CHAOTIC) yyerror("Illegal alignment - ignoring!"); else tmplevel[n_levs].flags |= $3 ; } ; chlevel1 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].chain = getchain($5); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free($3); Free($5); } | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].chain = getchain($5); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].rndlevs = $8; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free($3); Free($5); } ; chlevel2 : CHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].chain = getchain($5); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = $8; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free($3); Free($5); } | RNDCHLEVEL ':' STRING bones_tag STRING '+' rcouple INTEGER INTEGER { init_level(); Strcpy(tmplevel[n_levs].name, $3); tmplevel[n_levs].boneschar = (char)$4; tmplevel[n_levs].chain = getchain($5); tmplevel[n_levs].lev.base = couple.base; tmplevel[n_levs].lev.rand = couple.rand; tmplevel[n_levs].chance = $8; tmplevel[n_levs].rndlevs = $9; if(!check_level()) n_levs--; else tmpdungeon[n_dgns].levels++; Free($3); Free($5); } ; branches : branch | chbranch ; branch : BRANCH ':' STRING '@' acouple branch_type direction { init_branch(); Strcpy(tmpbranch[n_brs].name, $3); tmpbranch[n_brs].lev.base = couple.base; tmpbranch[n_brs].lev.rand = couple.rand; tmpbranch[n_brs].type = $6; tmpbranch[n_brs].up = $7; if(!check_branch()) n_brs--; else tmpdungeon[n_dgns].branches++; Free($3); } ; chbranch : CHBRANCH ':' STRING STRING '+' rcouple branch_type direction { init_branch(); Strcpy(tmpbranch[n_brs].name, $3); tmpbranch[n_brs].chain = getchain($4); tmpbranch[n_brs].lev.base = couple.base; tmpbranch[n_brs].lev.rand = couple.rand; tmpbranch[n_brs].type = $7; tmpbranch[n_brs].up = $8; if(!check_branch()) n_brs--; else tmpdungeon[n_dgns].branches++; Free($3); Free($4); } ; branch_type : /* nothing */ { $$ = TBR_STAIR; /* two way stair */ } | STAIR { $$ = TBR_STAIR; /* two way stair */ } | NO_UP { $$ = TBR_NO_UP; /* no up staircase */ } | NO_DOWN { $$ = TBR_NO_DOWN; /* no down staircase */ } | PORTAL { $$ = TBR_PORTAL; /* portal connection */ } ; direction : /* nothing */ { $$ = 0; /* defaults to down */ } | UP_OR_DOWN { $$ = $1; } ; bones_tag : STRING { char *p = $1; if (strlen(p) != 1) { if (strcmp(p, "none") != 0) yyerror("Bones marker must be a single char, or \"none\"!"); *p = '\0'; } $$ = *p; Free(p); } ; /* * acouple rules: * * (base, range) where: * * base is either a positive or negative integer with a value * less than or equal to MAXLEVEL. * base > 0 indicates the base level. * base < 0 indicates reverse index (-1 == lowest level) * * range is the random component. * if range is zero, there is no random component. * if range is -1 the dungeon loader will randomize between * the base and the end of the dungeon. * during dungeon load, range is always *added* to the base, * therefore range + base(converted) must not exceed MAXLEVEL. */ acouple : '(' INTEGER ',' INTEGER ')' { if ($2 < -MAXLEVEL || $2 > MAXLEVEL) { yyerror("Abs base out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else if ($4 < -1 || (($2 < 0) ? (MAXLEVEL + $2 + $4 + 1) > MAXLEVEL : ($2 + $4) > MAXLEVEL)) { yyerror("Abs range out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else { couple.base = $2; couple.rand = $4; } } ; /* * rcouple rules: * * (base, range) where: * * base is either a positive or negative integer with a value * less than or equal to MAXLEVEL. * base > 0 indicates a forward index. * base < 0 indicates a reverse index. * base == 0 indicates on the parent level. * * range is the random component. * if range is zero, there is no random component. * during dungeon load, range is always *added* to the base, * range + base(converted) may be very large. The dungeon * loader will then correct to "between here and the top/bottom". * * There is no practical way of specifying "between here and the * nth / nth last level". */ rcouple : '(' INTEGER ',' INTEGER ')' { if ($2 < -MAXLEVEL || $2 > MAXLEVEL) { yyerror("Rel base out of dlevel range - zeroing!"); couple.base = couple.rand = 0; } else { couple.base = $2; couple.rand = $4; } } ; %% void init_dungeon() { if(++n_dgns > MAXDUNGEON) { (void) fprintf(stderr, "FATAL - Too many dungeons (limit: %d).\n", MAXDUNGEON); (void) fprintf(stderr, "To increase the limit edit MAXDUNGEON in global.h\n"); exit(EXIT_FAILURE); } in_dungeon = 1; tmpdungeon[n_dgns].lev.base = 0; tmpdungeon[n_dgns].lev.rand = 0; tmpdungeon[n_dgns].chance = 100; Strcpy(tmpdungeon[n_dgns].name, ""); Strcpy(tmpdungeon[n_dgns].protoname, ""); tmpdungeon[n_dgns].flags = 0; tmpdungeon[n_dgns].levels = 0; tmpdungeon[n_dgns].branches = 0; tmpdungeon[n_dgns].entry_lev = 0; } void init_level() { if(++n_levs > LEV_LIMIT) { yyerror("FATAL - Too many special levels defined."); exit(EXIT_FAILURE); } tmplevel[n_levs].lev.base = 0; tmplevel[n_levs].lev.rand = 0; tmplevel[n_levs].chance = 100; tmplevel[n_levs].rndlevs = 0; tmplevel[n_levs].flags = 0; Strcpy(tmplevel[n_levs].name, ""); tmplevel[n_levs].chain = -1; } void init_branch() { if(++n_brs > BRANCH_LIMIT) { yyerror("FATAL - Too many special levels defined."); exit(EXIT_FAILURE); } tmpbranch[n_brs].lev.base = 0; tmpbranch[n_brs].lev.rand = 0; Strcpy(tmpbranch[n_brs].name, ""); tmpbranch[n_brs].chain = -1; } int getchain(s) char *s; { int i; if(strlen(s)) { for(i = n_levs - tmpdungeon[n_dgns].levels + 1; i <= n_levs; i++) if(!strcmp(tmplevel[i].name, s)) return i; yyerror("Can't locate the specified chain level."); return(-2); } return(-1); } /* * Consistancy checking routines: * * - A dungeon must have a unique name. * - A dungeon must have a originating "branch" command * (except, of course, for the first dungeon). * - A dungeon must have a proper depth (at least (1, 0)). */ int check_dungeon() { int i; for(i = 0; i < n_dgns; i++) if(!strcmp(tmpdungeon[i].name, tmpdungeon[n_dgns].name)) { yyerror("Duplicate dungeon name."); return(0); } if(n_dgns) for(i = 0; i < n_brs - tmpdungeon[n_dgns].branches; i++) { if(!strcmp(tmpbranch[i].name, tmpdungeon[n_dgns].name)) break; if(i >= n_brs - tmpdungeon[n_dgns].branches) { yyerror("Dungeon cannot be reached."); return(0); } } if(tmpdungeon[n_dgns].lev.base <= 0 || tmpdungeon[n_dgns].lev.rand < 0) { yyerror("Invalid dungeon depth specified."); return(0); } return(1); /* OK */ } /* * - A level must have a unique level name. * - If chained, the level used as reference for the chain * must be in this dungeon, must be previously defined, and * the level chained from must be "non-probabilistic" (ie. * have a 100% chance of existing). */ int check_level() { int i; if(!in_dungeon) { yyerror("Level defined outside of dungeon."); return(0); } for(i = 0; i < n_levs; i++) if(!strcmp(tmplevel[i].name, tmplevel[n_levs].name)) { yyerror("Duplicate level name."); return(0); } if(tmplevel[i].chain == -2) { yyerror("Invaild level chain reference."); return(0); } else if(tmplevel[i].chain != -1) { /* there is a chain */ /* KMH -- tmplevel[tmpbranch[i].chain].chance was in error */ if(tmplevel[tmplevel[i].chain].chance != 100) { yyerror("Level cannot chain from a probabilistic level."); return(0); } else if(tmplevel[i].chain == n_levs) { yyerror("A level cannot chain to itself!"); return(0); } } return(1); /* OK */ } /* * - A branch may not branch backwards - to avoid branch loops. * - A branch name must be unique. * (ie. You can only have one entry point to each dungeon). * - If chained, the level used as reference for the chain * must be in this dungeon, must be previously defined, and * the level chained from must be "non-probabilistic" (ie. * have a 100% chance of existing). */ int check_branch() { int i; if(!in_dungeon) { yyerror("Branch defined outside of dungeon."); return(0); } for(i = 0; i < n_dgns; i++) if(!strcmp(tmpdungeon[i].name, tmpbranch[n_brs].name)) { yyerror("Reverse branching not allowed."); return(0); } if(tmpbranch[i].chain == -2) { yyerror("Invaild branch chain reference."); return(0); } else if(tmpbranch[i].chain != -1) { /* it is chained */ if(tmplevel[tmpbranch[i].chain].chance != 100) { yyerror("Branch cannot chain from a probabilistic level."); return(0); } } return(1); /* OK */ } /* * Output the dungon definition into a file. * * The file will have the following format: * * [ nethack version ID ] * [ number of dungeons ] * [ first dungeon struct ] * [ levels for the first dungeon ] * ... * [ branches for the first dungeon ] * ... * [ second dungeon struct ] * ... */ void output_dgn() { int nd, cl = 0, nl = 0, cb = 0, nb = 0; static struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2 }; if(++n_dgns <= 0) { yyerror("FATAL - no dungeons were defined."); exit(EXIT_FAILURE); } if (fwrite((char *)&version_data, sizeof version_data, 1, yyout) != 1) { yyerror("FATAL - output failure."); exit(EXIT_FAILURE); } (void) fwrite((char *)&n_dgns, sizeof(int), 1, yyout); for (nd = 0; nd < n_dgns; nd++) { (void) fwrite((char *)&tmpdungeon[nd], sizeof(struct tmpdungeon), 1, yyout); nl += tmpdungeon[nd].levels; for(; cl < nl; cl++) (void) fwrite((char *)&tmplevel[cl], sizeof(struct tmplevel), 1, yyout); nb += tmpdungeon[nd].branches; for(; cb < nb; cb++) (void) fwrite((char *)&tmpbranch[cb], sizeof(struct tmpbranch), 1, yyout); } /* apparently necessary for Think C 5.x, otherwise harmless */ (void) fflush(yyout); } /*dgn_comp.y*/ nethack-3.4.3/util/dgn_main.c0100644000000000000000000001062307764735041014551 0ustar rootroot/* SCCS Id: @(#)dgn_main.c 3.4 1994/09/23 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* Copyright (c) 1990 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the main function for the parser * and some useful functions needed by yacc */ #include "config.h" #include "dlb.h" /* Macintosh-specific code */ #if defined(__APPLE__) && defined(__MACH__) /* MacOS X has Unix-style files and processes */ # undef MAC #endif #ifdef MAC # if defined(__SC__) || defined(__MRC__) # define MPWTOOL #include # else /* put dungeon file in library location */ # define PREFIX ":lib:" # endif #endif #ifndef MPWTOOL # define SpinCursor(x) #endif #define MAX_ERRORS 25 extern int NDECL (yyparse); extern int line_number; const char *fname = "(stdin)"; int fatal_error = 0; int FDECL (main, (int,char **)); void FDECL (yyerror, (const char *)); void FDECL (yywarning, (const char *)); int NDECL (yywrap); void FDECL (init_yyin, (FILE *)); void FDECL (init_yyout, (FILE *)); #ifdef AZTEC_36 FILE *FDECL (freopen, (char *,char *,FILE *)); #endif #define Fprintf (void)fprintf #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif int main(argc, argv) int argc; char **argv; { char infile[64], outfile[64], basename[64]; FILE *fin, *fout; int i, len; boolean errors_encountered = FALSE; #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__)) char *mark; static char *mac_argv[] = { "dgn_comp", /* dummy argv[0] */ ":dat:dungeon.pdf" }; argc = SIZE(mac_argv); argv = mac_argv; #endif Strcpy(infile, "(stdin)"); fin = stdin; Strcpy(outfile, "(stdout)"); fout = stdout; if (argc == 1) { /* Read standard input */ init_yyin(fin); init_yyout(fout); (void) yyparse(); if (fatal_error > 0) errors_encountered = TRUE; } else { /* Otherwise every argument is a filename */ for(i=1; i 0) { errors_encountered = TRUE; fatal_error = 0; } } } if (fout && fclose(fout) < 0) { Fprintf(stderr, "Can't finish output file."); perror(outfile); errors_encountered = TRUE; } exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS); /*NOTREACHED*/ return 0; } /* * Each time the parser detects an error, it uses this function. * Here we take count of the errors. To continue farther than * MAX_ERRORS wouldn't be reasonable. */ void yyerror(s) const char *s; { (void) fprintf(stderr,"%s : line %d : %s\n",fname,line_number, s); if (++fatal_error > MAX_ERRORS) { (void) fprintf(stderr,"Too many errors, good bye!\n"); exit(EXIT_FAILURE); } } /* * Just display a warning (that is : a non fatal error) */ void yywarning(s) const char *s; { (void) fprintf(stderr,"%s : line %d : WARNING : %s\n",fname,line_number,s); } int yywrap() { SpinCursor(3); /* Don't know if this is a good place to put it ? Is it called for our grammar ? Often enough ? Too often ? -- h+ */ return 1; } /*dgn_main.c*/ nethack-3.4.3/util/dlb_main.c0100644000000000000000000003104207764735041014540 0ustar rootroot/* SCCS Id: @(#)dlb_main.c 3.4 1998/08/16 */ /* Copyright (c) Kenneth Lorber, Bethesda, Maryland, 1993. */ /* NetHack may be freely redistributed. See license for details. */ /* data librarian; only useful if you are making the library version, DLBLIB */ #include "config.h" #include "dlb.h" #if !defined(O_WRONLY) && !defined(MAC) && !defined(AZTEC_C) #include #endif #if defined(__DJGPP__) #include #endif static void FDECL(xexit, (int)); #ifdef DLB #ifdef DLBLIB #define DLB_DIRECTORY "Directory" /* name of lib directory */ #define LIBLISTFILE "dlb.lst" /* default list file */ /* library functions (from dlb.c) */ extern boolean FDECL(open_library,(const char *,library *)); extern void FDECL(close_library,(library *)); char *FDECL(eos, (char *)); /* also used by dlb.c */ FILE *FDECL(fopen_datafile, (const char *,const char *)); #ifdef VMS extern char *FDECL(vms_basename, (const char *)); extern int FDECL(vms_open, (const char *,int,unsigned int)); #endif static void FDECL(Write, (int,char *,long)); static void NDECL(usage); static void NDECL(verbose_help); static void FDECL(write_dlb_directory, (int,int,libdir *,long,long,long)); static char default_progname[] = "dlb"; static char *progname = default_progname; /* fixed library and list file names - can be overridden if necessary */ static const char *library_file = DLBFILE; static const char *list_file = LIBLISTFILE; #ifdef AMIGA static char origdir[255]=""; #endif #ifndef O_BINARY #define O_BINARY 0 #endif #define MAX_DLB_FILES 200 /* max # of files we'll handle */ #define DLB_VERS 1 /* version of dlb file we will write */ /* * How the file is encoded within the library. Don't use a space * because (at least) the SunOS 4.1.3 C library will eat the white * space instead of preserving it like the man page says it should. */ #define ENC_NORMAL 'n' /* normal: not compressed in any way */ /* * If you know tar, you have a small clue how to use this (note: - does * NOT mean stdin/stdout). * * dlb COMMANDoptions arg... files... * commands: * dlb x extract all files * dlb c build the archive * dlb t list the archive * options: * v verbose * f file specify archive file (default DLBFILE) * I file specify file for list of files (default LIBLISTFILE) * C dir chdir to dir (used ONCE, not like tar's -C) */ static void usage() { (void) printf("Usage: %s [ctxCIfv] arguments... [files...]\n", progname); (void) printf(" default library is %s\n", library_file); (void) printf(" default list file is %s\n", list_file); xexit(EXIT_FAILURE); } static void verbose_help() { static const char *long_help[] = { "", "dlb COMMANDoptions args... files...", " commands:", " dlb ? print this text", " dlb h ditto", " dlb x extract all files", " dlb c create the archive", " dlb t list table of contents", " options:", " v verbose operation", " f file specify archive file name", " I file specify file for list of file names", " C dir change directory before processing any files", "", (char *)0 }; const char **str; for (str = long_help; *str; str++) (void) printf("%s\n", *str); usage(); } static void Write(out,buf,len) int out; char *buf; long len; { #if defined(MSDOS) && !defined(__DJGPP__) unsigned short slen; if (len > 65534) { printf("%d Length specified for write() too large for 16 bit env.", len); xexit(EXIT_FAILURE); } slen = (unsigned short)len; if (write(out,buf,slen) != slen) { #else if (write(out,buf,len) != len) { #endif printf("Write Error in '%s'\n",library_file); xexit(EXIT_FAILURE); } } char * eos(s) char *s; { while (*s) s++; return s; } #ifdef VMS /* essential to have punctuation, to avoid logical names */ static FILE * vms_fopen(filename, mode) const char *filename, *mode; { char tmp[BUFSIZ]; if (!index(filename, '.') && !index(filename, ';')) filename = strcat(strcpy(tmp, filename), ";0"); return fopen(filename, mode, "mbc=16"); } #define fopen vms_fopen #endif /* VMS */ /* open_library(dlb.c) needs this (which normally comes from src/files.c) */ FILE * fopen_datafile(filename, mode) const char *filename, *mode; { return fopen(filename, mode); } #endif /* DLBLIB */ #endif /* DLB */ int main(argc, argv) int argc; char **argv; { #ifdef DLB #ifdef DLBLIB int i, r; int ap=2; /* argument pointer */ int cp; /* command pointer */ int iseen=0, fseen=0, verbose=0; /* flags */ char action=' '; library lib; if (argc > 0 && argv[0] && *argv[0]) progname = argv[0]; #ifdef VMS progname = vms_basename(progname); #endif if (argc<2) { usage(); /* doesn't return */ } for(cp=0;argv[1][cp];cp++){ switch(argv[1][cp]){ default: usage(); /* doesn't return */ case '-': /* silently ignore */ break; case '?': case 'h': verbose_help(); break; case 'I': if (ap == argc) usage(); list_file=argv[ap++]; if(iseen) printf("Warning: multiple I options. Previous ignored.\n"); iseen=1; break; case 'f': if (ap == argc) usage(); library_file=argv[ap++]; if(fseen) printf("Warning: multiple f options. Previous ignored.\n"); fseen=1; break; case 'C': if (ap == argc) usage(); #ifdef AMIGA if(!getcwd(origdir,sizeof(origdir))){ printf("Can't get current directory.\n"); xexit(EXIT_FAILURE); } #endif if(chdir(argv[ap++])){ printf("Can't chdir to %s\n",argv[--ap]); xexit(EXIT_FAILURE); } break; case 'v': verbose=1; break; case 't': case 'c': case 'x': if(action != ' '){ printf("Only one of t,x,c may be specified.\n"); usage(); } action=argv[1][cp]; break; } } if(argv[ap] && iseen){ printf("Too many arguments.\n"); xexit(EXIT_FAILURE); } switch(action){ default: printf("Internal error - action.\n"); xexit(EXIT_FAILURE); break; case 't': /* list archive */ if (!open_library(library_file, &lib)) { printf("Can't open dlb file\n"); xexit(EXIT_FAILURE); } for (i = 0; i < lib.nentries; i++) { if (verbose) printf("%-14s %6ld %6ld\n", lib.dir[i].fname, lib.dir[i].foffset, lib.dir[i].fsize); else printf("%s\n", lib.dir[i].fname); } if (verbose) printf("Revision:%ld File count:%ld String size:%ld\n", lib.rev, lib.nentries, lib.strsize); close_library(&lib); xexit(EXIT_SUCCESS); case 'x': { /* extract archive contents */ int f, n; long remainder, total_read; char buf[BUFSIZ]; if (!open_library(library_file, &lib)) { printf("Can't open dlb file\n"); xexit(EXIT_FAILURE); } for (i = 0; i < lib.nentries; i++) { if (argv[ap]) { /* if files are listed, see if current is wanted */ int c; for (c = ap; c < argc; c++) if (!FILENAME_CMP(lib.dir[i].fname, argv[c])) break; if (c == argc) continue; /* skip */ } else if (!FILENAME_CMP(lib.dir[i].fname, DLB_DIRECTORY)) { /* * Don't extract the directory unless the user * specifically asks for it. * * Perhaps we should never extract the directory??? */ continue; } fseek(lib.fdata, lib.dir[i].foffset, SEEK_SET); f = open(lib.dir[i].fname, O_WRONLY|O_TRUNC|O_BINARY|O_CREAT, 0640); if (f < 0) { printf("Can't create '%s'\n", lib.dir[i].fname); xexit(EXIT_FAILURE); } /* read chunks from library and write them out */ total_read = 0; do { remainder = lib.dir[i].fsize - total_read; if (remainder > (long) sizeof(buf)) r = (int) sizeof(buf); else r = remainder; n = fread(buf, 1, r, lib.fdata); if (n != r) { printf("Read Error in '%s'\n", lib.dir[i].fname); xexit(EXIT_FAILURE); } if (write(f, buf, n) != n) { printf("Write Error in '%s'\n", lib.dir[i].fname); xexit(EXIT_FAILURE); } total_read += n; } while (total_read != lib.dir[i].fsize); (void) close(f); if (verbose) printf("x %s\n", lib.dir[i].fname); } close_library(&lib); xexit(EXIT_SUCCESS); } case 'c': /* create archive */ { libdir ld[MAX_DLB_FILES]; char buf[BUFSIZ]; int fd, out, nfiles = 0; long dir_size, slen, flen, fsiz; boolean rewrite_directory = FALSE; /* * Get names from either/both an argv list and a file * list. This does not do any duplicate checking */ /* get file name in argv list */ if (argv[ap]) { for ( ; ap < argc; ap++, nfiles++) { if (nfiles >= MAX_DLB_FILES) { printf("Too many dlb files! Stopping at %d.\n", MAX_DLB_FILES); break; } ld[nfiles].fname = (char *) alloc(strlen(argv[ap]) + 1); Strcpy(ld[nfiles].fname, argv[ap]); } } if (iseen) { /* want to do a list file */ FILE *list = fopen(list_file, "r"); if (!list) { printf("Can't open %s\n",list_file); xexit(EXIT_FAILURE); } /* get file names, one per line */ for ( ; fgets(buf, sizeof(buf), list); nfiles++) { if (nfiles >= MAX_DLB_FILES) { printf("Too many dlb files! Stopping at %d.\n", MAX_DLB_FILES); break; } *(eos(buf)-1) = '\0'; /* strip newline */ ld[nfiles].fname = (char *) alloc(strlen(buf) + 1); Strcpy(ld[nfiles].fname, buf); } fclose(list); } if (nfiles == 0) { printf("No files to archive\n"); xexit(EXIT_FAILURE); } /* * Get file sizes and name string length. Don't include * the directory information yet. */ for (i = 0, slen = 0, flen = 0; i < nfiles; i++) { fd = open(ld[i].fname, O_RDONLY|O_BINARY, 0); if (fd < 0) { printf("Can't open %s\n", ld[i].fname); xexit(EXIT_FAILURE); } ld[i].fsize = lseek(fd, 0, SEEK_END); ld[i].foffset = flen; slen += strlen(ld[i].fname); /* don't add null (yet) */ flen += ld[i].fsize; close(fd); } /* open output file */ out = open(library_file, O_RDWR|O_TRUNC|O_BINARY|O_CREAT, FCMASK); if (out < 0) { printf("Can't open %s for output\n", library_file); xexit(EXIT_FAILURE); } /* caculate directory size */ dir_size = 40 /* header line (see below) */ + ((nfiles+1)*11) /* handling+file offset+SP+newline */ + slen+strlen(DLB_DIRECTORY); /* file names */ /* write directory */ write_dlb_directory(out, nfiles, ld, slen, dir_size, flen); flen = 0L; /* write each file */ for (i = 0; i < nfiles; i++) { fd = open(ld[i].fname, O_RDONLY|O_BINARY, 0); if (fd < 0) { printf("Can't open input file '%s'\n", ld[i].fname); xexit(EXIT_FAILURE); } if (verbose) printf("%s\n",ld[i].fname); fsiz = 0L; while ((r = read(fd, buf, sizeof buf)) != 0) { if (r == -1) { printf("Read Error in '%s'\n", ld[i].fname); xexit(EXIT_FAILURE); } if (write(out, buf, r) != r) { printf("Write Error in '%s'\n", ld[i].fname); xexit(EXIT_FAILURE); } fsiz += r; } (void) close(fd); if (fsiz != ld[i].fsize) rewrite_directory = TRUE; /* in case directory rewrite is needed */ ld[i].fsize = fsiz; ld[i].foffset = flen; flen += fsiz; } if (rewrite_directory) { if (verbose) printf("(rewriting dlb directory info)\n"); (void) lseek(out, 0, SEEK_SET); /* rewind */ write_dlb_directory(out, nfiles, ld, slen, dir_size, flen); } for (i = 0; i < nfiles; i++) free((genericptr_t) ld[i].fname), ld[i].fname = 0; (void) close(out); xexit(EXIT_SUCCESS); } } #endif /* DLBLIB */ #endif /* DLB */ xexit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #ifdef DLB #ifdef DLBLIB static void write_dlb_directory(out, nfiles, ld, slen, dir_size, flen) int out, nfiles; libdir *ld; long slen, dir_size, flen; { char buf[BUFSIZ]; int i; sprintf(buf,"%3ld %8ld %8ld %8ld %8ld\n", (long) DLB_VERS, /* version of dlb file */ (long) nfiles+1, /* # of entries (includes directory) */ /* string length + room for nulls */ (long) slen+strlen(DLB_DIRECTORY)+nfiles+1, (long) dir_size, /* start of first file */ (long) flen+dir_size); /* total file size */ Write(out, buf, strlen(buf)); /* write each file entry */ #define ENTRY_FORMAT "%c%s %8ld\n" sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, DLB_DIRECTORY, (long) 0); Write(out, buf, strlen(buf)); for (i = 0; i < nfiles; i++) { sprintf(buf, ENTRY_FORMAT, ENC_NORMAL, /* encoding */ ld[i].fname, /* name */ ld[i].foffset + dir_size); /* offset */ Write(out, buf, strlen(buf)); } } #endif /* DLBLIB */ #endif /* DLB */ static void xexit(retcd) int retcd; { #ifdef DLB #ifdef AMIGA if (origdir[0]) chdir(origdir); #endif #endif exit(retcd); } #ifdef AMIGA #include "date.h" const char amiga_version_string[] = AMIGA_VERSION_STRING; #endif /*dlb_main.c*/ nethack-3.4.3/util/lev_comp.l0100644000000000000000000001663307764735041014621 0ustar rootroot%{ /* SCCS Id: @(#)lev_lex.c 3.4 2002/03/27 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ #define LEV_LEX_C #include "hack.h" #include "lev_comp.h" #include "sp_lev.h" /* Most of these don't exist in flex, yywrap is macro and * yyunput is properly declared in flex.skel. */ #if !defined(FLEX_SCANNER) && !defined(FLEXHACK_SCANNER) int FDECL(yyback, (int *,int)); int NDECL(yylook); int NDECL(yyinput); int NDECL(yywrap); int NDECL(yylex); /* Traditional lexes let yyunput() and yyoutput() default to int; * newer ones may declare them as void since they don't return * values. For even more fun, the lex supplied as part of the * newer unbundled compiler for SunOS 4.x adds the void declarations * (under __STDC__ or _cplusplus ifdefs -- otherwise they remain * int) while the bundled lex and the one with the older unbundled * compiler do not. To detect this, we need help from outside -- * sys/unix/Makefile.utl. * * Digital UNIX is difficult and still has int in spite of all * other signs. */ # if defined(NeXT) || defined(SVR4) || defined(_AIX32) # define VOIDYYPUT # endif # if !defined(VOIDYYPUT) && defined(POSIX_TYPES) # if !defined(BOS) && !defined(HISX) && !defined(_M_UNIX) && !defined(VMS) # define VOIDYYPUT # endif # endif # if !defined(VOIDYYPUT) && defined(WEIRD_LEX) # if defined(SUNOS4) && defined(__STDC__) && (WEIRD_LEX > 1) # define VOIDYYPUT # endif # endif # if defined(VOIDYYPUT) && defined(__osf__) # undef VOIDYYPUT # endif # ifdef VOIDYYPUT void FDECL(yyunput, (int)); void FDECL(yyoutput, (int)); # else int FDECL(yyunput, (int)); int FDECL(yyoutput, (int)); # endif #endif /* !FLEX_SCANNER && !FLEXHACK_SCANNER */ #ifdef FLEX_SCANNER #define YY_MALLOC_DECL \ genericptr_t FDECL(malloc, (size_t)); \ genericptr_t FDECL(realloc, (genericptr_t,size_t)); #endif void FDECL(init_yyin, (FILE *)); void FDECL(init_yyout, (FILE *)); /* * This doesn't always get put in lev_comp.h * (esp. when using older versions of bison). */ extern YYSTYPE yylval; int line_number = 1, colon_line_number = 1; static char map[4096]; static int map_cnt = 0; %} %e 1500 %p 5000 %n 700 %s MAPC %% ENDMAP { BEGIN(INITIAL); yylval.map = (char *) alloc(map_cnt + 1); (void) strncpy(yylval.map, map, map_cnt); yylval.map[map_cnt] = 0; map_cnt = 0; return MAP_ID; } [-|}{+ABCISHKPLWTF\\#. 0123456789]*\r?\n { int len = yyleng; /* convert \r\n to \n */ if (len >= 2 && yytext[len - 2] == '\r') len -= 1; line_number++; (void) strncpy(map + map_cnt, yytext, len); map_cnt += len; map[map_cnt - 1] = '\n'; map[map_cnt] = '\0'; } ^#.*\n { line_number++; } : { colon_line_number = line_number; return ':'; } MESSAGE return MESSAGE_ID; MAZE return MAZE_ID; NOMAP return NOMAP_ID; LEVEL return LEVEL_ID; INIT_MAP return LEV_INIT_ID; FLAGS return FLAGS_ID; GEOMETRY return GEOMETRY_ID; ^MAP\r?\n { BEGIN(MAPC); line_number++; } OBJECT return OBJECT_ID; CONTAINER return COBJECT_ID; MONSTER return MONSTER_ID; TRAP return TRAP_ID; DOOR return DOOR_ID; DRAWBRIDGE return DRAWBRIDGE_ID; MAZEWALK return MAZEWALK_ID; WALLIFY return WALLIFY_ID; REGION return REGION_ID; RANDOM_OBJECTS return RANDOM_OBJECTS_ID; RANDOM_MONSTERS return RANDOM_MONSTERS_ID; RANDOM_PLACES return RANDOM_PLACES_ID; ALTAR return ALTAR_ID; LADDER return LADDER_ID; STAIR return STAIR_ID; PORTAL return PORTAL_ID; TELEPORT_REGION return TELEPRT_ID; BRANCH return BRANCH_ID; FOUNTAIN return FOUNTAIN_ID; SINK return SINK_ID; POOL return POOL_ID; NON_DIGGABLE return NON_DIGGABLE_ID; NON_PASSWALL return NON_PASSWALL_ID; ROOM return ROOM_ID; SUBROOM return SUBROOM_ID; RANDOM_CORRIDORS return RAND_CORRIDOR_ID; CORRIDOR return CORRIDOR_ID; GOLD return GOLD_ID; ENGRAVING return ENGRAVING_ID; NAME return NAME_ID; CHANCE return CHANCE_ID; levregion return LEV; open { yylval.i=D_ISOPEN; return DOOR_STATE; } closed { yylval.i=D_CLOSED; return DOOR_STATE; } locked { yylval.i=D_LOCKED; return DOOR_STATE; } nodoor { yylval.i=D_NODOOR; return DOOR_STATE; } broken { yylval.i=D_BROKEN; return DOOR_STATE; } north { yylval.i=W_NORTH; return DIRECTION; } east { yylval.i=W_EAST; return DIRECTION; } south { yylval.i=W_SOUTH; return DIRECTION; } west { yylval.i=W_WEST; return DIRECTION; } random { yylval.i = -1; return RANDOM_TYPE; } none { yylval.i = -2; return NONE; } object return O_REGISTER; monster return M_REGISTER; place return P_REGISTER; align return A_REGISTER; left { yylval.i=1; return LEFT_OR_RIGHT; } half-left { yylval.i=2; return LEFT_OR_RIGHT; } center { yylval.i=3; return CENTER; } half-right { yylval.i=4; return LEFT_OR_RIGHT; } right { yylval.i=5; return LEFT_OR_RIGHT; } top { yylval.i=1; return TOP_OR_BOT; } bottom { yylval.i=5; return TOP_OR_BOT; } lit { yylval.i=1; return LIGHT_STATE; } unlit { yylval.i=0; return LIGHT_STATE; } filled { yylval.i=0; return FILLING; } unfilled { yylval.i=1; return FILLING; } noalign { yylval.i= AM_NONE; return ALIGNMENT; } law { yylval.i= AM_LAWFUL; return ALIGNMENT; } neutral { yylval.i= AM_NEUTRAL; return ALIGNMENT; } chaos { yylval.i= AM_CHAOTIC; return ALIGNMENT; } coaligned { yylval.i= AM_SPLEV_CO; return ALIGNMENT; } noncoaligned { yylval.i= AM_SPLEV_NONCO; return ALIGNMENT; } peaceful { yylval.i=1; return MON_ATTITUDE; } hostile { yylval.i=0; return MON_ATTITUDE; } asleep { yylval.i=1; return MON_ALERTNESS; } awake { yylval.i=0; return MON_ALERTNESS; } m_feature { yylval.i= M_AP_FURNITURE; return MON_APPEARANCE; } m_monster { yylval.i= M_AP_MONSTER; return MON_APPEARANCE; } m_object { yylval.i= M_AP_OBJECT; return MON_APPEARANCE; } sanctum { yylval.i=2; return ALTAR_TYPE; } shrine { yylval.i=1; return ALTAR_TYPE; } altar { yylval.i=0; return ALTAR_TYPE; } up { yylval.i=1; return UP_OR_DOWN; } down { yylval.i=0; return UP_OR_DOWN; } false { yylval.i=0; return BOOLEAN; } true { yylval.i=1; return BOOLEAN; } dust { yylval.i=DUST; return ENGRAVING_TYPE; } engrave { yylval.i=ENGRAVE; return ENGRAVING_TYPE; } burn { yylval.i=BURN; return ENGRAVING_TYPE; } mark { yylval.i=MARK; return ENGRAVING_TYPE; } blessed { yylval.i=1; return CURSE_TYPE; } uncursed { yylval.i=2; return CURSE_TYPE; } cursed { yylval.i=3; return CURSE_TYPE; } contained { return CONTAINED; } noteleport { yylval.i=NOTELEPORT; return FLAG_TYPE; } hardfloor { yylval.i=HARDFLOOR; return FLAG_TYPE; } nommap { yylval.i=NOMMAP; return FLAG_TYPE; } arboreal { yylval.i=ARBOREAL; return FLAG_TYPE; } /* KMH */ shortsighted { yylval.i=SHORTSIGHTED; return FLAG_TYPE; } \[\ *[0-9]+\%\ *\] { yylval.i = atoi(yytext + 1); return PERCENT; } [+\-]?[0-9]+ { yylval.i=atoi(yytext); return INTEGER; } \"[^"]*\" { yytext[yyleng-1] = 0; /* Discard the trailing \" */ yylval.map = (char *) alloc(strlen(yytext+1)+1); Strcpy(yylval.map, yytext+1); /* Discard the first \" */ return STRING; } \r?\n { line_number++; } [ \t]+ ; '\\.' { yylval.i = yytext[2]; return CHAR; } '.' { yylval.i = yytext[1]; return CHAR; } . { return yytext[0]; } %% #ifdef AMIGA long *alloc(n) unsigned n; { return ((long *)malloc (n)); } #endif /* routine to switch to another input file; needed for flex */ void init_yyin( input_f ) FILE *input_f; { #if defined(FLEX_SCANNER) || defined(FLEXHACK_SCANNER) if (yyin) yyrestart(input_f); else #endif yyin = input_f; } /* analogous routine (for completeness) */ void init_yyout( output_f ) FILE *output_f; { yyout = output_f; } /*lev_comp.l*/ nethack-3.4.3/util/lev_comp.y0100644000000000000000000011561307764735041014634 0ustar rootroot%{ /* SCCS Id: @(#)lev_yacc.c 3.4 2000/01/17 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the Level Compiler code * It may handle special mazes & special room-levels */ /* In case we're using bison in AIX. This definition must be * placed before any other C-language construct in the file * excluding comments and preprocessor directives (thanks IBM * for this wonderful feature...). * * Note: some cpps barf on this 'undefined control' (#pragma). * Addition of the leading space seems to prevent barfage for now, * and AIX will still see the directive. */ #ifdef _AIX #pragma alloca /* keep leading space! */ #endif #include "hack.h" #include "sp_lev.h" #define MAX_REGISTERS 10 #define ERR (-1) /* many types of things are put in chars for transference to NetHack. * since some systems will use signed chars, limit everybody to the * same number for portability. */ #define MAX_OF_TYPE 128 #define New(type) \ (type *) memset((genericptr_t)alloc(sizeof(type)), 0, sizeof(type)) #define NewTab(type, size) (type **) alloc(sizeof(type *) * size) #define Free(ptr) free((genericptr_t)ptr) extern void FDECL(yyerror, (const char *)); extern void FDECL(yywarning, (const char *)); extern int NDECL(yylex); int NDECL(yyparse); extern int FDECL(get_floor_type, (CHAR_P)); extern int FDECL(get_room_type, (char *)); extern int FDECL(get_trap_type, (char *)); extern int FDECL(get_monster_id, (char *,CHAR_P)); extern int FDECL(get_object_id, (char *,CHAR_P)); extern boolean FDECL(check_monster_char, (CHAR_P)); extern boolean FDECL(check_object_char, (CHAR_P)); extern char FDECL(what_map_char, (CHAR_P)); extern void FDECL(scan_map, (char *)); extern void NDECL(wallify_map); extern boolean NDECL(check_subrooms); extern void FDECL(check_coord, (int,int,const char *)); extern void NDECL(store_part); extern void NDECL(store_room); extern boolean FDECL(write_level_file, (char *,splev *,specialmaze *)); extern void FDECL(free_rooms, (splev *)); static struct reg { int x1, y1; int x2, y2; } current_region; static struct coord { int x; int y; } current_coord, current_align; static struct size { int height; int width; } current_size; char tmpmessage[256]; digpos *tmppass[32]; char *tmpmap[ROWNO]; digpos *tmpdig[MAX_OF_TYPE]; region *tmpreg[MAX_OF_TYPE]; lev_region *tmplreg[MAX_OF_TYPE]; door *tmpdoor[MAX_OF_TYPE]; drawbridge *tmpdb[MAX_OF_TYPE]; walk *tmpwalk[MAX_OF_TYPE]; room_door *tmprdoor[MAX_OF_TYPE]; trap *tmptrap[MAX_OF_TYPE]; monster *tmpmonst[MAX_OF_TYPE]; object *tmpobj[MAX_OF_TYPE]; altar *tmpaltar[MAX_OF_TYPE]; lad *tmplad[MAX_OF_TYPE]; stair *tmpstair[MAX_OF_TYPE]; gold *tmpgold[MAX_OF_TYPE]; engraving *tmpengraving[MAX_OF_TYPE]; fountain *tmpfountain[MAX_OF_TYPE]; sink *tmpsink[MAX_OF_TYPE]; pool *tmppool[MAX_OF_TYPE]; mazepart *tmppart[10]; room *tmproom[MAXNROFROOMS*2]; corridor *tmpcor[MAX_OF_TYPE]; static specialmaze maze; static splev special_lev; static lev_init init_lev; static char olist[MAX_REGISTERS], mlist[MAX_REGISTERS]; static struct coord plist[MAX_REGISTERS]; int n_olist = 0, n_mlist = 0, n_plist = 0; unsigned int nlreg = 0, nreg = 0, ndoor = 0, ntrap = 0, nmons = 0, nobj = 0; unsigned int ndb = 0, nwalk = 0, npart = 0, ndig = 0, nlad = 0, nstair = 0; unsigned int naltar = 0, ncorridor = 0, nrooms = 0, ngold = 0, nengraving = 0; unsigned int nfountain = 0, npool = 0, nsink = 0, npass = 0; static int lev_flags = 0; unsigned int max_x_map, max_y_map; static xchar in_room; extern int fatal_error; extern int want_warnings; extern const char *fname; %} %union { int i; char* map; struct { xchar room; xchar wall; xchar door; } corpos; } %token CHAR INTEGER BOOLEAN PERCENT %token MESSAGE_ID MAZE_ID LEVEL_ID LEV_INIT_ID GEOMETRY_ID NOMAP_ID %token OBJECT_ID COBJECT_ID MONSTER_ID TRAP_ID DOOR_ID DRAWBRIDGE_ID %token MAZEWALK_ID WALLIFY_ID REGION_ID FILLING %token RANDOM_OBJECTS_ID RANDOM_MONSTERS_ID RANDOM_PLACES_ID %token ALTAR_ID LADDER_ID STAIR_ID NON_DIGGABLE_ID NON_PASSWALL_ID ROOM_ID %token PORTAL_ID TELEPRT_ID BRANCH_ID LEV CHANCE_ID %token CORRIDOR_ID GOLD_ID ENGRAVING_ID FOUNTAIN_ID POOL_ID SINK_ID NONE %token RAND_CORRIDOR_ID DOOR_STATE LIGHT_STATE CURSE_TYPE ENGRAVING_TYPE %token DIRECTION RANDOM_TYPE O_REGISTER M_REGISTER P_REGISTER A_REGISTER %token ALIGNMENT LEFT_OR_RIGHT CENTER TOP_OR_BOT ALTAR_TYPE UP_OR_DOWN %token SUBROOM_ID NAME_ID FLAGS_ID FLAG_TYPE MON_ATTITUDE MON_ALERTNESS %token MON_APPEARANCE %token CONTAINED %token ',' ':' '(' ')' '[' ']' %token STRING MAP_ID %type h_justif v_justif trap_name room_type door_state light_state %type alignment altar_type a_register roomfill filling door_pos %type door_wall walled secret amount chance %type engraving_type flags flag_list prefilled lev_region lev_init %type monster monster_c m_register object object_c o_register %type string maze_def level_def m_name o_name %type corr_spec %start file %% file : /* nothing */ | levels ; levels : level | level levels ; level : maze_level | room_level ; maze_level : maze_def flags lev_init messages regions { unsigned i; if (fatal_error > 0) { (void) fprintf(stderr, "%s : %d errors detected. No output created!\n", fname, fatal_error); } else { maze.flags = $2; (void) memcpy((genericptr_t)&(maze.init_lev), (genericptr_t)&(init_lev), sizeof(lev_init)); maze.numpart = npart; maze.parts = NewTab(mazepart, npart); for(i=0;i 0) { (void) fprintf(stderr, "%s : %d errors detected. No output created!\n", fname, fatal_error); } else { special_lev.flags = (long) $2; (void) memcpy( (genericptr_t)&(special_lev.init_lev), (genericptr_t)&(init_lev), sizeof(lev_init)); special_lev.nroom = nrooms; special_lev.rooms = NewTab(room, nrooms); for(i=0; i 8) yyerror("Level names limited to 8 characters."); $$ = $3; special_lev.nrmonst = special_lev.nrobjects = 0; n_mlist = n_olist = 0; } ; lev_init : /* nothing */ { /* in case we're processing multiple files, explicitly clear any stale settings */ (void) memset((genericptr_t) &init_lev, 0, sizeof init_lev); init_lev.init_present = FALSE; $$ = 0; } | LEV_INIT_ID ':' CHAR ',' CHAR ',' BOOLEAN ',' BOOLEAN ',' light_state ',' walled { init_lev.init_present = TRUE; init_lev.fg = what_map_char((char) $3); if (init_lev.fg == INVALID_TYPE) yyerror("Invalid foreground type."); init_lev.bg = what_map_char((char) $5); if (init_lev.bg == INVALID_TYPE) yyerror("Invalid background type."); init_lev.smoothed = $7; init_lev.joined = $9; if (init_lev.joined && init_lev.fg != CORR && init_lev.fg != ROOM) yyerror("Invalid foreground type for joined map."); init_lev.lit = $11; init_lev.walled = $13; $$ = 1; } ; walled : BOOLEAN | RANDOM_TYPE ; flags : /* nothing */ { $$ = 0; } | FLAGS_ID ':' flag_list { $$ = lev_flags; lev_flags = 0; /* clear for next user */ } ; flag_list : FLAG_TYPE ',' flag_list { lev_flags |= $1; } | FLAG_TYPE { lev_flags |= $1; } ; messages : /* nothing */ | message messages ; message : MESSAGE_ID ':' STRING { int i, j; i = (int) strlen($3) + 1; j = (int) strlen(tmpmessage); if (i + j > 255) { yyerror("Message string too long (>256 characters)"); } else { if (j) tmpmessage[j++] = '\n'; (void) strncpy(tmpmessage+j, $3, i - 1); tmpmessage[j + i - 1] = 0; } Free($3); } ; rreg_init : /* nothing */ | rreg_init init_rreg ; init_rreg : RANDOM_OBJECTS_ID ':' object_list { if(special_lev.nrobjects) { yyerror("Object registers already initialized!"); } else { special_lev.nrobjects = n_olist; special_lev.robjects = (char *) alloc(n_olist); (void) memcpy((genericptr_t)special_lev.robjects, (genericptr_t)olist, n_olist); } } | RANDOM_MONSTERS_ID ':' monster_list { if(special_lev.nrmonst) { yyerror("Monster registers already initialized!"); } else { special_lev.nrmonst = n_mlist; special_lev.rmonst = (char *) alloc(n_mlist); (void) memcpy((genericptr_t)special_lev.rmonst, (genericptr_t)mlist, n_mlist); } } ; rooms : /* Nothing - dummy room for use with INIT_MAP */ { tmproom[nrooms] = New(room); tmproom[nrooms]->name = (char *) 0; tmproom[nrooms]->parent = (char *) 0; tmproom[nrooms]->rtype = 0; tmproom[nrooms]->rlit = 0; tmproom[nrooms]->xalign = ERR; tmproom[nrooms]->yalign = ERR; tmproom[nrooms]->x = 0; tmproom[nrooms]->y = 0; tmproom[nrooms]->w = 2; tmproom[nrooms]->h = 2; in_room = 1; } | roomlist ; roomlist : aroom | aroom roomlist ; corridors_def : random_corridors | corridors ; random_corridors: RAND_CORRIDOR_ID { tmpcor[0] = New(corridor); tmpcor[0]->src.room = -1; ncorridor = 1; } ; corridors : /* nothing */ | corridors corridor ; corridor : CORRIDOR_ID ':' corr_spec ',' corr_spec { tmpcor[ncorridor] = New(corridor); tmpcor[ncorridor]->src.room = $3.room; tmpcor[ncorridor]->src.wall = $3.wall; tmpcor[ncorridor]->src.door = $3.door; tmpcor[ncorridor]->dest.room = $5.room; tmpcor[ncorridor]->dest.wall = $5.wall; tmpcor[ncorridor]->dest.door = $5.door; ncorridor++; if (ncorridor >= MAX_OF_TYPE) { yyerror("Too many corridors in level!"); ncorridor--; } } | CORRIDOR_ID ':' corr_spec ',' INTEGER { tmpcor[ncorridor] = New(corridor); tmpcor[ncorridor]->src.room = $3.room; tmpcor[ncorridor]->src.wall = $3.wall; tmpcor[ncorridor]->src.door = $3.door; tmpcor[ncorridor]->dest.room = -1; tmpcor[ncorridor]->dest.wall = $5; ncorridor++; if (ncorridor >= MAX_OF_TYPE) { yyerror("Too many corridors in level!"); ncorridor--; } } ; corr_spec : '(' INTEGER ',' DIRECTION ',' door_pos ')' { if ((unsigned) $2 >= nrooms) yyerror("Wrong room number!"); $$.room = $2; $$.wall = $4; $$.door = $6; } ; aroom : room_def room_details { store_room(); } | subroom_def room_details { store_room(); } ; subroom_def : SUBROOM_ID ':' room_type ',' light_state ',' subroom_pos ',' room_size ',' string roomfill { tmproom[nrooms] = New(room); tmproom[nrooms]->parent = $11; tmproom[nrooms]->name = (char *) 0; tmproom[nrooms]->rtype = $3; tmproom[nrooms]->rlit = $5; tmproom[nrooms]->filled = $12; tmproom[nrooms]->xalign = ERR; tmproom[nrooms]->yalign = ERR; tmproom[nrooms]->x = current_coord.x; tmproom[nrooms]->y = current_coord.y; tmproom[nrooms]->w = current_size.width; tmproom[nrooms]->h = current_size.height; in_room = 1; } ; room_def : ROOM_ID ':' room_type ',' light_state ',' room_pos ',' room_align ',' room_size roomfill { tmproom[nrooms] = New(room); tmproom[nrooms]->name = (char *) 0; tmproom[nrooms]->parent = (char *) 0; tmproom[nrooms]->rtype = $3; tmproom[nrooms]->rlit = $5; tmproom[nrooms]->filled = $12; tmproom[nrooms]->xalign = current_align.x; tmproom[nrooms]->yalign = current_align.y; tmproom[nrooms]->x = current_coord.x; tmproom[nrooms]->y = current_coord.y; tmproom[nrooms]->w = current_size.width; tmproom[nrooms]->h = current_size.height; in_room = 1; } ; roomfill : /* nothing */ { $$ = 1; } | ',' BOOLEAN { $$ = $2; } ; room_pos : '(' INTEGER ',' INTEGER ')' { if ( $2 < 1 || $2 > 5 || $4 < 1 || $4 > 5 ) { yyerror("Room position should be between 1 & 5!"); } else { current_coord.x = $2; current_coord.y = $4; } } | RANDOM_TYPE { current_coord.x = current_coord.y = ERR; } ; subroom_pos : '(' INTEGER ',' INTEGER ')' { if ( $2 < 0 || $4 < 0) { yyerror("Invalid subroom position !"); } else { current_coord.x = $2; current_coord.y = $4; } } | RANDOM_TYPE { current_coord.x = current_coord.y = ERR; } ; room_align : '(' h_justif ',' v_justif ')' { current_align.x = $2; current_align.y = $4; } | RANDOM_TYPE { current_align.x = current_align.y = ERR; } ; room_size : '(' INTEGER ',' INTEGER ')' { current_size.width = $2; current_size.height = $4; } | RANDOM_TYPE { current_size.height = current_size.width = ERR; } ; room_details : /* nothing */ | room_details room_detail ; room_detail : room_name | room_chance | room_door | monster_detail | object_detail | trap_detail | altar_detail | fountain_detail | sink_detail | pool_detail | gold_detail | engraving_detail | stair_detail ; room_name : NAME_ID ':' string { if (tmproom[nrooms]->name) yyerror("This room already has a name!"); else tmproom[nrooms]->name = $3; } ; room_chance : CHANCE_ID ':' INTEGER { if (tmproom[nrooms]->chance) yyerror("This room already assigned a chance!"); else if (tmproom[nrooms]->rtype == OROOM) yyerror("Only typed rooms can have a chance!"); else if ($3 < 1 || $3 > 99) yyerror("The chance is supposed to be percentile."); else tmproom[nrooms]->chance = $3; } ; room_door : DOOR_ID ':' secret ',' door_state ',' door_wall ',' door_pos { /* ERR means random here */ if ($7 == ERR && $9 != ERR) { yyerror("If the door wall is random, so must be its pos!"); } else { tmprdoor[ndoor] = New(room_door); tmprdoor[ndoor]->secret = $3; tmprdoor[ndoor]->mask = $5; tmprdoor[ndoor]->wall = $7; tmprdoor[ndoor]->pos = $9; ndoor++; if (ndoor >= MAX_OF_TYPE) { yyerror("Too many doors in room!"); ndoor--; } } } ; secret : BOOLEAN | RANDOM_TYPE ; door_wall : DIRECTION | RANDOM_TYPE ; door_pos : INTEGER | RANDOM_TYPE ; maze_def : MAZE_ID ':' string ',' filling { maze.filling = (schar) $5; if (index($3, '.')) yyerror("Invalid dot ('.') in level name."); if ((int) strlen($3) > 8) yyerror("Level names limited to 8 characters."); $$ = $3; in_room = 0; n_plist = n_mlist = n_olist = 0; } ; filling : CHAR { $$ = get_floor_type((char)$1); } | RANDOM_TYPE { $$ = -1; } ; regions : aregion | aregion regions ; aregion : map_definition reg_init map_details { store_part(); } ; map_definition : NOMAP_ID { tmppart[npart] = New(mazepart); tmppart[npart]->halign = 1; tmppart[npart]->valign = 1; tmppart[npart]->nrobjects = 0; tmppart[npart]->nloc = 0; tmppart[npart]->nrmonst = 0; tmppart[npart]->xsize = 1; tmppart[npart]->ysize = 1; tmppart[npart]->map = (char **) alloc(sizeof(char *)); tmppart[npart]->map[0] = (char *) alloc(1); tmppart[npart]->map[0][0] = STONE; max_x_map = COLNO-1; max_y_map = ROWNO; } | map_geometry MAP_ID { tmppart[npart] = New(mazepart); tmppart[npart]->halign = $1 % 10; tmppart[npart]->valign = $1 / 10; tmppart[npart]->nrobjects = 0; tmppart[npart]->nloc = 0; tmppart[npart]->nrmonst = 0; scan_map($2); Free($2); } ; map_geometry : GEOMETRY_ID ':' h_justif ',' v_justif { $$ = $3 + ($5 * 10); } ; h_justif : LEFT_OR_RIGHT | CENTER ; v_justif : TOP_OR_BOT | CENTER ; reg_init : /* nothing */ | reg_init init_reg ; init_reg : RANDOM_OBJECTS_ID ':' object_list { if (tmppart[npart]->nrobjects) { yyerror("Object registers already initialized!"); } else { tmppart[npart]->robjects = (char *)alloc(n_olist); (void) memcpy((genericptr_t)tmppart[npart]->robjects, (genericptr_t)olist, n_olist); tmppart[npart]->nrobjects = n_olist; } } | RANDOM_PLACES_ID ':' place_list { if (tmppart[npart]->nloc) { yyerror("Location registers already initialized!"); } else { register int i; tmppart[npart]->rloc_x = (char *) alloc(n_plist); tmppart[npart]->rloc_y = (char *) alloc(n_plist); for(i=0;irloc_x[i] = plist[i].x; tmppart[npart]->rloc_y[i] = plist[i].y; } tmppart[npart]->nloc = n_plist; } } | RANDOM_MONSTERS_ID ':' monster_list { if (tmppart[npart]->nrmonst) { yyerror("Monster registers already initialized!"); } else { tmppart[npart]->rmonst = (char *) alloc(n_mlist); (void) memcpy((genericptr_t)tmppart[npart]->rmonst, (genericptr_t)mlist, n_mlist); tmppart[npart]->nrmonst = n_mlist; } } ; object_list : object { if (n_olist < MAX_REGISTERS) olist[n_olist++] = $1; else yyerror("Object list too long!"); } | object ',' object_list { if (n_olist < MAX_REGISTERS) olist[n_olist++] = $1; else yyerror("Object list too long!"); } ; monster_list : monster { if (n_mlist < MAX_REGISTERS) mlist[n_mlist++] = $1; else yyerror("Monster list too long!"); } | monster ',' monster_list { if (n_mlist < MAX_REGISTERS) mlist[n_mlist++] = $1; else yyerror("Monster list too long!"); } ; place_list : place { if (n_plist < MAX_REGISTERS) plist[n_plist++] = current_coord; else yyerror("Location list too long!"); } | place { if (n_plist < MAX_REGISTERS) plist[n_plist++] = current_coord; else yyerror("Location list too long!"); } ',' place_list ; map_details : /* nothing */ | map_details map_detail ; map_detail : monster_detail | object_detail | door_detail | trap_detail | drawbridge_detail | region_detail | stair_region | portal_region | teleprt_region | branch_region | altar_detail | fountain_detail | mazewalk_detail | wallify_detail | ladder_detail | stair_detail | gold_detail | engraving_detail | diggable_detail | passwall_detail ; monster_detail : MONSTER_ID chance ':' monster_c ',' m_name ',' coordinate { tmpmonst[nmons] = New(monster); tmpmonst[nmons]->x = current_coord.x; tmpmonst[nmons]->y = current_coord.y; tmpmonst[nmons]->class = $4; tmpmonst[nmons]->peaceful = -1; /* no override */ tmpmonst[nmons]->asleep = -1; tmpmonst[nmons]->align = - MAX_REGISTERS - 2; tmpmonst[nmons]->name.str = 0; tmpmonst[nmons]->appear = 0; tmpmonst[nmons]->appear_as.str = 0; tmpmonst[nmons]->chance = $2; tmpmonst[nmons]->id = NON_PM; if (!in_room) check_coord(current_coord.x, current_coord.y, "Monster"); if ($6) { int token = get_monster_id($6, (char) $4); if (token == ERR) yywarning( "Invalid monster name! Making random monster."); else tmpmonst[nmons]->id = token; Free($6); } } monster_infos { if (++nmons >= MAX_OF_TYPE) { yyerror("Too many monsters in room or mazepart!"); nmons--; } } ; monster_infos : /* nothing */ | monster_infos monster_info ; monster_info : ',' string { tmpmonst[nmons]->name.str = $2; } | ',' MON_ATTITUDE { tmpmonst[nmons]->peaceful = $2; } | ',' MON_ALERTNESS { tmpmonst[nmons]->asleep = $2; } | ',' alignment { tmpmonst[nmons]->align = $2; } | ',' MON_APPEARANCE string { tmpmonst[nmons]->appear = $2; tmpmonst[nmons]->appear_as.str = $3; } ; object_detail : OBJECT_ID object_desc { } | COBJECT_ID object_desc { /* 1: is contents of preceeding object with 2 */ /* 2: is a container */ /* 0: neither */ tmpobj[nobj-1]->containment = 2; } ; object_desc : chance ':' object_c ',' o_name { tmpobj[nobj] = New(object); tmpobj[nobj]->class = $3; tmpobj[nobj]->corpsenm = NON_PM; tmpobj[nobj]->curse_state = -1; tmpobj[nobj]->name.str = 0; tmpobj[nobj]->chance = $1; tmpobj[nobj]->id = -1; if ($5) { int token = get_object_id($5, $3); if (token == ERR) yywarning( "Illegal object name! Making random object."); else tmpobj[nobj]->id = token; Free($5); } } ',' object_where object_infos { if (++nobj >= MAX_OF_TYPE) { yyerror("Too many objects in room or mazepart!"); nobj--; } } ; object_where : coordinate { tmpobj[nobj]->containment = 0; tmpobj[nobj]->x = current_coord.x; tmpobj[nobj]->y = current_coord.y; if (!in_room) check_coord(current_coord.x, current_coord.y, "Object"); } | CONTAINED { tmpobj[nobj]->containment = 1; /* random coordinate, will be overridden anyway */ tmpobj[nobj]->x = -MAX_REGISTERS-1; tmpobj[nobj]->y = -MAX_REGISTERS-1; } ; object_infos : /* nothing */ { tmpobj[nobj]->spe = -127; /* Note below: we're trying to make as many of these optional as * possible. We clearly can't make curse_state, enchantment, and * monster_id _all_ optional, since ",random" would be ambiguous. * We can't even just make enchantment mandatory, since if we do that * alone, ",random" requires too much lookahead to parse. */ } | ',' curse_state ',' monster_id ',' enchantment optional_name { } | ',' curse_state ',' enchantment optional_name { } | ',' monster_id ',' enchantment optional_name { } ; curse_state : RANDOM_TYPE { tmpobj[nobj]->curse_state = -1; } | CURSE_TYPE { tmpobj[nobj]->curse_state = $1; } ; monster_id : STRING { int token = get_monster_id($1, (char)0); if (token == ERR) /* "random" */ tmpobj[nobj]->corpsenm = NON_PM - 1; else tmpobj[nobj]->corpsenm = token; Free($1); } ; enchantment : RANDOM_TYPE { tmpobj[nobj]->spe = -127; } | INTEGER { tmpobj[nobj]->spe = $1; } ; optional_name : /* nothing */ | ',' NONE { } | ',' STRING { tmpobj[nobj]->name.str = $2; } ; door_detail : DOOR_ID ':' door_state ',' coordinate { tmpdoor[ndoor] = New(door); tmpdoor[ndoor]->x = current_coord.x; tmpdoor[ndoor]->y = current_coord.y; tmpdoor[ndoor]->mask = $3; if(current_coord.x >= 0 && current_coord.y >= 0 && tmpmap[current_coord.y][current_coord.x] != DOOR && tmpmap[current_coord.y][current_coord.x] != SDOOR) yyerror("Door decl doesn't match the map"); ndoor++; if (ndoor >= MAX_OF_TYPE) { yyerror("Too many doors in mazepart!"); ndoor--; } } ; trap_detail : TRAP_ID chance ':' trap_name ',' coordinate { tmptrap[ntrap] = New(trap); tmptrap[ntrap]->x = current_coord.x; tmptrap[ntrap]->y = current_coord.y; tmptrap[ntrap]->type = $4; tmptrap[ntrap]->chance = $2; if (!in_room) check_coord(current_coord.x, current_coord.y, "Trap"); if (++ntrap >= MAX_OF_TYPE) { yyerror("Too many traps in room or mazepart!"); ntrap--; } } ; drawbridge_detail: DRAWBRIDGE_ID ':' coordinate ',' DIRECTION ',' door_state { int x, y, dir; tmpdb[ndb] = New(drawbridge); x = tmpdb[ndb]->x = current_coord.x; y = tmpdb[ndb]->y = current_coord.y; /* convert dir from a DIRECTION to a DB_DIR */ dir = $5; switch(dir) { case W_NORTH: dir = DB_NORTH; y--; break; case W_SOUTH: dir = DB_SOUTH; y++; break; case W_EAST: dir = DB_EAST; x++; break; case W_WEST: dir = DB_WEST; x--; break; default: yyerror("Invalid drawbridge direction"); break; } tmpdb[ndb]->dir = dir; if (current_coord.x >= 0 && current_coord.y >= 0 && !IS_WALL(tmpmap[y][x])) { char ebuf[60]; Sprintf(ebuf, "Wall needed for drawbridge (%02d, %02d)", current_coord.x, current_coord.y); yyerror(ebuf); } if ( $7 == D_ISOPEN ) tmpdb[ndb]->db_open = 1; else if ( $7 == D_CLOSED ) tmpdb[ndb]->db_open = 0; else yyerror("A drawbridge can only be open or closed!"); ndb++; if (ndb >= MAX_OF_TYPE) { yyerror("Too many drawbridges in mazepart!"); ndb--; } } ; mazewalk_detail : MAZEWALK_ID ':' coordinate ',' DIRECTION { tmpwalk[nwalk] = New(walk); tmpwalk[nwalk]->x = current_coord.x; tmpwalk[nwalk]->y = current_coord.y; tmpwalk[nwalk]->dir = $5; nwalk++; if (nwalk >= MAX_OF_TYPE) { yyerror("Too many mazewalks in mazepart!"); nwalk--; } } ; wallify_detail : WALLIFY_ID { wallify_map(); } ; ladder_detail : LADDER_ID ':' coordinate ',' UP_OR_DOWN { tmplad[nlad] = New(lad); tmplad[nlad]->x = current_coord.x; tmplad[nlad]->y = current_coord.y; tmplad[nlad]->up = $5; if (!in_room) check_coord(current_coord.x, current_coord.y, "Ladder"); nlad++; if (nlad >= MAX_OF_TYPE) { yyerror("Too many ladders in mazepart!"); nlad--; } } ; stair_detail : STAIR_ID ':' coordinate ',' UP_OR_DOWN { tmpstair[nstair] = New(stair); tmpstair[nstair]->x = current_coord.x; tmpstair[nstair]->y = current_coord.y; tmpstair[nstair]->up = $5; if (!in_room) check_coord(current_coord.x, current_coord.y, "Stairway"); nstair++; if (nstair >= MAX_OF_TYPE) { yyerror("Too many stairs in room or mazepart!"); nstair--; } } ; stair_region : STAIR_ID ':' lev_region { tmplreg[nlreg] = New(lev_region); tmplreg[nlreg]->in_islev = $3; tmplreg[nlreg]->inarea.x1 = current_region.x1; tmplreg[nlreg]->inarea.y1 = current_region.y1; tmplreg[nlreg]->inarea.x2 = current_region.x2; tmplreg[nlreg]->inarea.y2 = current_region.y2; } ',' lev_region ',' UP_OR_DOWN { tmplreg[nlreg]->del_islev = $6; tmplreg[nlreg]->delarea.x1 = current_region.x1; tmplreg[nlreg]->delarea.y1 = current_region.y1; tmplreg[nlreg]->delarea.x2 = current_region.x2; tmplreg[nlreg]->delarea.y2 = current_region.y2; if($8) tmplreg[nlreg]->rtype = LR_UPSTAIR; else tmplreg[nlreg]->rtype = LR_DOWNSTAIR; tmplreg[nlreg]->rname.str = 0; nlreg++; if (nlreg >= MAX_OF_TYPE) { yyerror("Too many levregions in mazepart!"); nlreg--; } } ; portal_region : PORTAL_ID ':' lev_region { tmplreg[nlreg] = New(lev_region); tmplreg[nlreg]->in_islev = $3; tmplreg[nlreg]->inarea.x1 = current_region.x1; tmplreg[nlreg]->inarea.y1 = current_region.y1; tmplreg[nlreg]->inarea.x2 = current_region.x2; tmplreg[nlreg]->inarea.y2 = current_region.y2; } ',' lev_region ',' string { tmplreg[nlreg]->del_islev = $6; tmplreg[nlreg]->delarea.x1 = current_region.x1; tmplreg[nlreg]->delarea.y1 = current_region.y1; tmplreg[nlreg]->delarea.x2 = current_region.x2; tmplreg[nlreg]->delarea.y2 = current_region.y2; tmplreg[nlreg]->rtype = LR_PORTAL; tmplreg[nlreg]->rname.str = $8; nlreg++; if (nlreg >= MAX_OF_TYPE) { yyerror("Too many levregions in mazepart!"); nlreg--; } } ; teleprt_region : TELEPRT_ID ':' lev_region { tmplreg[nlreg] = New(lev_region); tmplreg[nlreg]->in_islev = $3; tmplreg[nlreg]->inarea.x1 = current_region.x1; tmplreg[nlreg]->inarea.y1 = current_region.y1; tmplreg[nlreg]->inarea.x2 = current_region.x2; tmplreg[nlreg]->inarea.y2 = current_region.y2; } ',' lev_region { tmplreg[nlreg]->del_islev = $6; tmplreg[nlreg]->delarea.x1 = current_region.x1; tmplreg[nlreg]->delarea.y1 = current_region.y1; tmplreg[nlreg]->delarea.x2 = current_region.x2; tmplreg[nlreg]->delarea.y2 = current_region.y2; } teleprt_detail { switch($8) { case -1: tmplreg[nlreg]->rtype = LR_TELE; break; case 0: tmplreg[nlreg]->rtype = LR_DOWNTELE; break; case 1: tmplreg[nlreg]->rtype = LR_UPTELE; break; } tmplreg[nlreg]->rname.str = 0; nlreg++; if (nlreg >= MAX_OF_TYPE) { yyerror("Too many levregions in mazepart!"); nlreg--; } } ; branch_region : BRANCH_ID ':' lev_region { tmplreg[nlreg] = New(lev_region); tmplreg[nlreg]->in_islev = $3; tmplreg[nlreg]->inarea.x1 = current_region.x1; tmplreg[nlreg]->inarea.y1 = current_region.y1; tmplreg[nlreg]->inarea.x2 = current_region.x2; tmplreg[nlreg]->inarea.y2 = current_region.y2; } ',' lev_region { tmplreg[nlreg]->del_islev = $6; tmplreg[nlreg]->delarea.x1 = current_region.x1; tmplreg[nlreg]->delarea.y1 = current_region.y1; tmplreg[nlreg]->delarea.x2 = current_region.x2; tmplreg[nlreg]->delarea.y2 = current_region.y2; tmplreg[nlreg]->rtype = LR_BRANCH; tmplreg[nlreg]->rname.str = 0; nlreg++; if (nlreg >= MAX_OF_TYPE) { yyerror("Too many levregions in mazepart!"); nlreg--; } } ; teleprt_detail : /* empty */ { $$ = -1; } | ',' UP_OR_DOWN { $$ = $2; } ; lev_region : region { $$ = 0; } | LEV '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' { /* This series of if statements is a hack for MSC 5.1. It seems that its tiny little brain cannot compile if these are all one big if statement. */ if ($3 <= 0 || $3 >= COLNO) yyerror("Region out of level range!"); else if ($5 < 0 || $5 >= ROWNO) yyerror("Region out of level range!"); else if ($7 <= 0 || $7 >= COLNO) yyerror("Region out of level range!"); else if ($9 < 0 || $9 >= ROWNO) yyerror("Region out of level range!"); current_region.x1 = $3; current_region.y1 = $5; current_region.x2 = $7; current_region.y2 = $9; $$ = 1; } ; fountain_detail : FOUNTAIN_ID ':' coordinate { tmpfountain[nfountain] = New(fountain); tmpfountain[nfountain]->x = current_coord.x; tmpfountain[nfountain]->y = current_coord.y; if (!in_room) check_coord(current_coord.x, current_coord.y, "Fountain"); nfountain++; if (nfountain >= MAX_OF_TYPE) { yyerror("Too many fountains in room or mazepart!"); nfountain--; } } ; sink_detail : SINK_ID ':' coordinate { tmpsink[nsink] = New(sink); tmpsink[nsink]->x = current_coord.x; tmpsink[nsink]->y = current_coord.y; nsink++; if (nsink >= MAX_OF_TYPE) { yyerror("Too many sinks in room!"); nsink--; } } ; pool_detail : POOL_ID ':' coordinate { tmppool[npool] = New(pool); tmppool[npool]->x = current_coord.x; tmppool[npool]->y = current_coord.y; npool++; if (npool >= MAX_OF_TYPE) { yyerror("Too many pools in room!"); npool--; } } ; diggable_detail : NON_DIGGABLE_ID ':' region { tmpdig[ndig] = New(digpos); tmpdig[ndig]->x1 = current_region.x1; tmpdig[ndig]->y1 = current_region.y1; tmpdig[ndig]->x2 = current_region.x2; tmpdig[ndig]->y2 = current_region.y2; ndig++; if (ndig >= MAX_OF_TYPE) { yyerror("Too many diggables in mazepart!"); ndig--; } } ; passwall_detail : NON_PASSWALL_ID ':' region { tmppass[npass] = New(digpos); tmppass[npass]->x1 = current_region.x1; tmppass[npass]->y1 = current_region.y1; tmppass[npass]->x2 = current_region.x2; tmppass[npass]->y2 = current_region.y2; npass++; if (npass >= 32) { yyerror("Too many passwalls in mazepart!"); npass--; } } ; region_detail : REGION_ID ':' region ',' light_state ',' room_type prefilled { tmpreg[nreg] = New(region); tmpreg[nreg]->x1 = current_region.x1; tmpreg[nreg]->y1 = current_region.y1; tmpreg[nreg]->x2 = current_region.x2; tmpreg[nreg]->y2 = current_region.y2; tmpreg[nreg]->rlit = $5; tmpreg[nreg]->rtype = $7; if($8 & 1) tmpreg[nreg]->rtype += MAXRTYPE+1; tmpreg[nreg]->rirreg = (($8 & 2) != 0); if(current_region.x1 > current_region.x2 || current_region.y1 > current_region.y2) yyerror("Region start > end!"); if(tmpreg[nreg]->rtype == VAULT && (tmpreg[nreg]->rirreg || (tmpreg[nreg]->x2 - tmpreg[nreg]->x1 != 1) || (tmpreg[nreg]->y2 - tmpreg[nreg]->y1 != 1))) yyerror("Vaults must be exactly 2x2!"); if(want_warnings && !tmpreg[nreg]->rirreg && current_region.x1 > 0 && current_region.y1 > 0 && current_region.x2 < (int)max_x_map && current_region.y2 < (int)max_y_map) { /* check for walls in the room */ char ebuf[60]; register int x, y, nrock = 0; for(y=current_region.y1; y<=current_region.y2; y++) for(x=current_region.x1; x<=current_region.x2; x++) if(IS_ROCK(tmpmap[y][x]) || IS_DOOR(tmpmap[y][x])) nrock++; if(nrock) { Sprintf(ebuf, "Rock in room (%02d,%02d,%02d,%02d)?!", current_region.x1, current_region.y1, current_region.x2, current_region.y2); yywarning(ebuf); } if ( !IS_ROCK(tmpmap[current_region.y1-1][current_region.x1-1]) || !IS_ROCK(tmpmap[current_region.y2+1][current_region.x1-1]) || !IS_ROCK(tmpmap[current_region.y1-1][current_region.x2+1]) || !IS_ROCK(tmpmap[current_region.y2+1][current_region.x2+1])) { Sprintf(ebuf, "NonRock edge in room (%02d,%02d,%02d,%02d)?!", current_region.x1, current_region.y1, current_region.x2, current_region.y2); yywarning(ebuf); } } else if(tmpreg[nreg]->rirreg && !IS_ROOM(tmpmap[current_region.y1][current_region.x1])) { char ebuf[60]; Sprintf(ebuf, "Rock in irregular room (%02d,%02d)?!", current_region.x1, current_region.y1); yyerror(ebuf); } nreg++; if (nreg >= MAX_OF_TYPE) { yyerror("Too many regions in mazepart!"); nreg--; } } ; altar_detail : ALTAR_ID ':' coordinate ',' alignment ',' altar_type { tmpaltar[naltar] = New(altar); tmpaltar[naltar]->x = current_coord.x; tmpaltar[naltar]->y = current_coord.y; tmpaltar[naltar]->align = $5; tmpaltar[naltar]->shrine = $7; if (!in_room) check_coord(current_coord.x, current_coord.y, "Altar"); naltar++; if (naltar >= MAX_OF_TYPE) { yyerror("Too many altars in room or mazepart!"); naltar--; } } ; gold_detail : GOLD_ID ':' amount ',' coordinate { tmpgold[ngold] = New(gold); tmpgold[ngold]->x = current_coord.x; tmpgold[ngold]->y = current_coord.y; tmpgold[ngold]->amount = $3; if (!in_room) check_coord(current_coord.x, current_coord.y, "Gold"); ngold++; if (ngold >= MAX_OF_TYPE) { yyerror("Too many golds in room or mazepart!"); ngold--; } } ; engraving_detail: ENGRAVING_ID ':' coordinate ',' engraving_type ',' string { tmpengraving[nengraving] = New(engraving); tmpengraving[nengraving]->x = current_coord.x; tmpengraving[nengraving]->y = current_coord.y; tmpengraving[nengraving]->engr.str = $7; tmpengraving[nengraving]->etype = $5; if (!in_room) check_coord(current_coord.x, current_coord.y, "Engraving"); nengraving++; if (nengraving >= MAX_OF_TYPE) { yyerror("Too many engravings in room or mazepart!"); nengraving--; } } ; monster_c : monster | RANDOM_TYPE { $$ = - MAX_REGISTERS - 1; } | m_register ; object_c : object | RANDOM_TYPE { $$ = - MAX_REGISTERS - 1; } | o_register ; m_name : string | RANDOM_TYPE { $$ = (char *) 0; } ; o_name : string | RANDOM_TYPE { $$ = (char *) 0; } ; trap_name : string { int token = get_trap_type($1); if (token == ERR) yyerror("Unknown trap type!"); $$ = token; Free($1); } | RANDOM_TYPE ; room_type : string { int token = get_room_type($1); if (token == ERR) { yywarning("Unknown room type! Making ordinary room..."); $$ = OROOM; } else $$ = token; Free($1); } | RANDOM_TYPE ; prefilled : /* empty */ { $$ = 0; } | ',' FILLING { $$ = $2; } | ',' FILLING ',' BOOLEAN { $$ = $2 + ($4 << 1); } ; coordinate : coord | p_register | RANDOM_TYPE { current_coord.x = current_coord.y = -MAX_REGISTERS-1; } ; door_state : DOOR_STATE | RANDOM_TYPE ; light_state : LIGHT_STATE | RANDOM_TYPE ; alignment : ALIGNMENT | a_register | RANDOM_TYPE { $$ = - MAX_REGISTERS - 1; } ; altar_type : ALTAR_TYPE | RANDOM_TYPE ; p_register : P_REGISTER '[' INTEGER ']' { if ( $3 >= MAX_REGISTERS ) yyerror("Register Index overflow!"); else current_coord.x = current_coord.y = - $3 - 1; } ; o_register : O_REGISTER '[' INTEGER ']' { if ( $3 >= MAX_REGISTERS ) yyerror("Register Index overflow!"); else $$ = - $3 - 1; } ; m_register : M_REGISTER '[' INTEGER ']' { if ( $3 >= MAX_REGISTERS ) yyerror("Register Index overflow!"); else $$ = - $3 - 1; } ; a_register : A_REGISTER '[' INTEGER ']' { if ( $3 >= 3 ) yyerror("Register Index overflow!"); else $$ = - $3 - 1; } ; place : coord ; monster : CHAR { if (check_monster_char((char) $1)) $$ = $1 ; else { yyerror("Unknown monster class!"); $$ = ERR; } } ; object : CHAR { char c = $1; if (check_object_char(c)) $$ = c; else { yyerror("Unknown char class!"); $$ = ERR; } } ; string : STRING ; amount : INTEGER | RANDOM_TYPE ; chance : /* empty */ { $$ = 100; /* default is 100% */ } | PERCENT { if ($1 <= 0 || $1 > 100) yyerror("Expected percentile chance."); $$ = $1; } ; engraving_type : ENGRAVING_TYPE | RANDOM_TYPE ; coord : '(' INTEGER ',' INTEGER ')' { if (!in_room && !init_lev.init_present && ($2 < 0 || $2 > (int)max_x_map || $4 < 0 || $4 > (int)max_y_map)) yyerror("Coordinates out of map range!"); current_coord.x = $2; current_coord.y = $4; } ; region : '(' INTEGER ',' INTEGER ',' INTEGER ',' INTEGER ')' { /* This series of if statements is a hack for MSC 5.1. It seems that its tiny little brain cannot compile if these are all one big if statement. */ if ($2 < 0 || $2 > (int)max_x_map) yyerror("Region out of map range!"); else if ($4 < 0 || $4 > (int)max_y_map) yyerror("Region out of map range!"); else if ($6 < 0 || $6 > (int)max_x_map) yyerror("Region out of map range!"); else if ($8 < 0 || $8 > (int)max_y_map) yyerror("Region out of map range!"); current_region.x1 = $2; current_region.y1 = $4; current_region.x2 = $6; current_region.y2 = $8; } ; %% /*lev_comp.y*/ nethack-3.4.3/util/lev_main.c0100644000000000000000000010752407764735041014576 0ustar rootroot/* SCCS Id: @(#)lev_main.c 3.4 2002/03/27 */ /* Copyright (c) 1989 by Jean-Christophe Collet */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains the main function for the parser * and some useful functions needed by yacc */ #define SPEC_LEV /* for MPW */ /* although, why don't we move those special defines here.. and in dgn_main? */ #include "hack.h" #include "date.h" #include "sp_lev.h" #ifdef STRICT_REF_DEF #include "tcap.h" #endif #ifdef MAC # if defined(__SC__) || defined(__MRC__) # define MPWTOOL # define PREFIX ":dungeon:" /* place output files here */ # include # else # if !defined(__MACH__) # define PREFIX ":lib:" /* place output files here */ # endif # endif #endif #ifdef WIN_CE #define PREFIX "\\nethack\\dat\\" #endif #ifndef MPWTOOL # define SpinCursor(x) #endif #if defined(AMIGA) && defined(DLB) # define PREFIX "NH:slib/" #endif #ifndef O_WRONLY #include #endif #ifndef O_CREAT /* some older BSD systems do not define O_CREAT in */ #include #endif #ifndef O_BINARY /* used for micros, no-op for others */ # define O_BINARY 0 #endif #if defined(MICRO) || defined(WIN32) # define OMASK FCMASK #else # define OMASK 0644 #endif #define ERR (-1) #define NewTab(type, size) (type **) alloc(sizeof(type *) * size) #define Free(ptr) if(ptr) free((genericptr_t) (ptr)) #define Write(fd, item, size) if (write(fd, (genericptr_t)(item), size) != size) return FALSE; #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif #define MAX_ERRORS 25 extern int NDECL (yyparse); extern void FDECL (init_yyin, (FILE *)); extern void FDECL (init_yyout, (FILE *)); int FDECL (main, (int, char **)); void FDECL (yyerror, (const char *)); void FDECL (yywarning, (const char *)); int NDECL (yywrap); int FDECL(get_floor_type, (CHAR_P)); int FDECL(get_room_type, (char *)); int FDECL(get_trap_type, (char *)); int FDECL(get_monster_id, (char *,CHAR_P)); int FDECL(get_object_id, (char *,CHAR_P)); boolean FDECL(check_monster_char, (CHAR_P)); boolean FDECL(check_object_char, (CHAR_P)); char FDECL(what_map_char, (CHAR_P)); void FDECL(scan_map, (char *)); void NDECL(wallify_map); boolean NDECL(check_subrooms); void FDECL(check_coord, (int,int,const char *)); void NDECL(store_part); void NDECL(store_room); boolean FDECL(write_level_file, (char *,splev *,specialmaze *)); void FDECL(free_rooms, (splev *)); extern void NDECL(monst_init); extern void NDECL(objects_init); extern void NDECL(decl_init); static boolean FDECL(write_common_data, (int,int,lev_init *,long)); static boolean FDECL(write_monsters, (int,char *,monster ***)); static boolean FDECL(write_objects, (int,char *,object ***)); static boolean FDECL(write_engravings, (int,char *,engraving ***)); static boolean FDECL(write_maze, (int,specialmaze *)); static boolean FDECL(write_rooms, (int,splev *)); static void NDECL(init_obj_classes); static struct { const char *name; int type; } trap_types[] = { { "arrow", ARROW_TRAP }, { "dart", DART_TRAP }, { "falling rock", ROCKTRAP }, { "board", SQKY_BOARD }, { "bear", BEAR_TRAP }, { "land mine", LANDMINE }, { "rolling boulder", ROLLING_BOULDER_TRAP }, { "sleep gas", SLP_GAS_TRAP }, { "rust", RUST_TRAP }, { "fire", FIRE_TRAP }, { "pit", PIT }, { "spiked pit", SPIKED_PIT }, { "hole", HOLE }, { "trap door", TRAPDOOR }, { "teleport", TELEP_TRAP }, { "level teleport", LEVEL_TELEP }, { "magic portal", MAGIC_PORTAL }, { "web", WEB }, { "statue", STATUE_TRAP }, { "magic", MAGIC_TRAP }, { "anti magic", ANTI_MAGIC }, { "polymorph", POLY_TRAP }, { 0, 0 } }; static struct { const char *name; int type; } room_types[] = { /* for historical reasons, room types are not contiguous numbers */ /* (type 1 is skipped) */ { "ordinary", OROOM }, { "throne", COURT }, { "swamp", SWAMP }, { "vault", VAULT }, { "beehive", BEEHIVE }, { "morgue", MORGUE }, { "barracks", BARRACKS }, { "zoo", ZOO }, { "delphi", DELPHI }, { "temple", TEMPLE }, { "anthole", ANTHOLE }, { "cocknest", COCKNEST }, { "leprehall", LEPREHALL }, { "shop", SHOPBASE }, { "armor shop", ARMORSHOP }, { "scroll shop", SCROLLSHOP }, { "potion shop", POTIONSHOP }, { "weapon shop", WEAPONSHOP }, { "food shop", FOODSHOP }, { "ring shop", RINGSHOP }, { "wand shop", WANDSHOP }, { "tool shop", TOOLSHOP }, { "book shop", BOOKSHOP }, { "candle shop", CANDLESHOP }, { 0, 0 } }; const char *fname = "(stdin)"; int fatal_error = 0; int want_warnings = 0; #ifdef FLEX23_BUG /* Flex 2.3 bug work around; not needed for 2.3.6 or later */ int yy_more_len = 0; #endif extern char tmpmessage[]; extern altar *tmpaltar[]; extern lad *tmplad[]; extern stair *tmpstair[]; extern digpos *tmpdig[]; extern digpos *tmppass[]; extern char *tmpmap[]; extern region *tmpreg[]; extern lev_region *tmplreg[]; extern door *tmpdoor[]; extern room_door *tmprdoor[]; extern trap *tmptrap[]; extern monster *tmpmonst[]; extern object *tmpobj[]; extern drawbridge *tmpdb[]; extern walk *tmpwalk[]; extern gold *tmpgold[]; extern fountain *tmpfountain[]; extern sink *tmpsink[]; extern pool *tmppool[]; extern engraving *tmpengraving[]; extern mazepart *tmppart[]; extern room *tmproom[]; extern int n_olist, n_mlist, n_plist; extern unsigned int nlreg, nreg, ndoor, ntrap, nmons, nobj; extern unsigned int ndb, nwalk, npart, ndig, npass, nlad, nstair; extern unsigned int naltar, ncorridor, nrooms, ngold, nengraving; extern unsigned int nfountain, npool, nsink; extern unsigned int max_x_map, max_y_map; extern int line_number, colon_line_number; int main(argc, argv) int argc; char **argv; { FILE *fin; int i; boolean errors_encountered = FALSE; #if defined(MAC) && (defined(THINK_C) || defined(__MWERKS__)) static char *mac_argv[] = { "lev_comp", /* dummy argv[0] */ ":dat:Arch.des", ":dat:Barb.des", ":dat:Caveman.des", ":dat:Healer.des", ":dat:Knight.des", ":dat:Monk.des", ":dat:Priest.des", ":dat:Ranger.des", ":dat:Rogue.des", ":dat:Samurai.des", ":dat:Tourist.des", ":dat:Valkyrie.des", ":dat:Wizard.des", ":dat:bigroom.des", ":dat:castle.des", ":dat:endgame.des", ":dat:gehennom.des", ":dat:knox.des", ":dat:medusa.des", ":dat:mines.des", ":dat:oracle.des", ":dat:sokoban.des", ":dat:tower.des", ":dat:yendor.des" }; argc = SIZE(mac_argv); argv = mac_argv; #endif /* Note: these initializers don't do anything except guarantee that we're linked properly. */ monst_init(); objects_init(); decl_init(); /* this one does something... */ init_obj_classes(); init_yyout(stdout); if (argc == 1) { /* Read standard input */ init_yyin(stdin); (void) yyparse(); if (fatal_error > 0) { errors_encountered = TRUE; } } else { /* Otherwise every argument is a filename */ for(i=1; i 0) { errors_encountered = TRUE; fatal_error = 0; } } } } exit(errors_encountered ? EXIT_FAILURE : EXIT_SUCCESS); /*NOTREACHED*/ return 0; } /* * Each time the parser detects an error, it uses this function. * Here we take count of the errors. To continue farther than * MAX_ERRORS wouldn't be reasonable. * Assume that explicit calls from lev_comp.y have the 1st letter * capitalized, to allow printing of the line containing the start of * the current declaration, instead of the beginning of the next declaration. */ void yyerror(s) const char *s; { (void) fprintf(stderr, "%s: line %d : %s\n", fname, (*s >= 'A' && *s <= 'Z') ? colon_line_number : line_number, s); if (++fatal_error > MAX_ERRORS) { (void) fprintf(stderr,"Too many errors, good bye!\n"); exit(EXIT_FAILURE); } } /* * Just display a warning (that is : a non fatal error) */ void yywarning(s) const char *s; { (void) fprintf(stderr, "%s: line %d : WARNING : %s\n", fname, colon_line_number, s); } /* * Stub needed for lex interface. */ int yywrap() { return 1; } /* * Find the type of floor, knowing its char representation. */ int get_floor_type(c) char c; { int val; SpinCursor(3); val = what_map_char(c); if(val == INVALID_TYPE) { val = ERR; yywarning("Invalid fill character in MAZE declaration"); } return val; } /* * Find the type of a room in the table, knowing its name. */ int get_room_type(s) char *s; { register int i; SpinCursor(3); for(i=0; room_types[i].name; i++) if (!strcmp(s, room_types[i].name)) return ((int) room_types[i].type); return ERR; } /* * Find the type of a trap in the table, knowing its name. */ int get_trap_type(s) char *s; { register int i; SpinCursor(3); for (i=0; trap_types[i].name; i++) if(!strcmp(s,trap_types[i].name)) return trap_types[i].type; return ERR; } /* * Find the index of a monster in the table, knowing its name. */ int get_monster_id(s, c) char *s; char c; { register int i, class; SpinCursor(3); class = c ? def_char_to_monclass(c) : 0; if (class == MAXMCLASSES) return ERR; for (i = LOW_PM; i < NUMMONS; i++) if (!class || class == mons[i].mlet) if (!strcmp(s, mons[i].mname)) return i; return ERR; } /* * Find the index of an object in the table, knowing its name. */ int get_object_id(s, c) char *s; char c; /* class */ { int i, class; const char *objname; SpinCursor(3); class = (c > 0) ? def_char_to_objclass(c) : 0; if (class == MAXOCLASSES) return ERR; for (i = class ? bases[class] : 0; i < NUM_OBJECTS; i++) { if (class && objects[i].oc_class != class) break; objname = obj_descr[i].oc_name; if (objname && !strcmp(s, objname)) return i; } return ERR; } static void init_obj_classes() { int i, class, prev_class; prev_class = -1; for (i = 0; i < NUM_OBJECTS; i++) { class = objects[i].oc_class; if (class != prev_class) { bases[class] = i; prev_class = class; } } } /* * Is the character 'c' a valid monster class ? */ boolean check_monster_char(c) char c; { return (def_char_to_monclass(c) != MAXMCLASSES); } /* * Is the character 'c' a valid object class ? */ boolean check_object_char(c) char c; { return (def_char_to_objclass(c) != MAXOCLASSES); } /* * Convert .des map letter into floor type. */ char what_map_char(c) char c; { SpinCursor(3); switch(c) { case ' ' : return(STONE); case '#' : return(CORR); case '.' : return(ROOM); case '-' : return(HWALL); case '|' : return(VWALL); case '+' : return(DOOR); case 'A' : return(AIR); case 'B' : return(CROSSWALL); /* hack: boundary location */ case 'C' : return(CLOUD); case 'S' : return(SDOOR); case 'H' : return(SCORR); case '{' : return(FOUNTAIN); case '\\' : return(THRONE); case 'K' : #ifdef SINKS return(SINK); #else yywarning("Sinks are not allowed in this version! Ignoring..."); return(ROOM); #endif case '}' : return(MOAT); case 'P' : return(POOL); case 'L' : return(LAVAPOOL); case 'I' : return(ICE); case 'W' : return(WATER); case 'T' : return (TREE); case 'F' : return (IRONBARS); /* Fe = iron */ } return(INVALID_TYPE); } /* * Yep! LEX gives us the map in a raw mode. * Just analyze it here. */ void scan_map(map) char *map; { register int i, len; register char *s1, *s2; int max_len = 0; int max_hig = 0; char msg[256]; /* First, strip out digits 0-9 (line numbering) */ for (s1 = s2 = map; *s1; s1++) if (*s1 < '0' || *s1 > '9') *s2++ = *s1; *s2 = '\0'; /* Second, find the max width of the map */ s1 = map; while (s1 && *s1) { s2 = index(s1, '\n'); if (s2) { len = (int) (s2 - s1); s1 = s2 + 1; } else { len = (int) strlen(s1); s1 = (char *) 0; } if (len > max_len) max_len = len; } /* Then parse it now */ while (map && *map) { tmpmap[max_hig] = (char *) alloc(max_len); s1 = index(map, '\n'); if (s1) { len = (int) (s1 - map); s1++; } else { len = (int) strlen(map); s1 = map + len; } for(i=0; i MAP_X_LIM || max_hig > MAP_Y_LIM) { Sprintf(msg, "Map too large! (max %d x %d)", MAP_X_LIM, MAP_Y_LIM); yyerror(msg); } tmppart[npart]->xsize = max_len; tmppart[npart]->ysize = max_hig; tmppart[npart]->map = (char **) alloc(max_hig*sizeof(char *)); for(i = 0; i< max_hig; i++) tmppart[npart]->map[i] = tmpmap[i]; } /* * If we have drawn a map without walls, this allows us to * auto-magically wallify it. */ #define Map_point(x,y) *(tmppart[npart]->map[y] + x) void wallify_map() { unsigned int x, y, xx, yy, lo_xx, lo_yy, hi_xx, hi_yy; for (y = 0; y <= max_y_map; y++) { SpinCursor(3); lo_yy = (y > 0) ? y - 1 : 0; hi_yy = (y < max_y_map) ? y + 1 : max_y_map; for (x = 0; x <= max_x_map; x++) { if (Map_point(x,y) != STONE) continue; lo_xx = (x > 0) ? x - 1 : 0; hi_xx = (x < max_x_map) ? x + 1 : max_x_map; for (yy = lo_yy; yy <= hi_yy; yy++) for (xx = lo_xx; xx <= hi_xx; xx++) if (IS_ROOM(Map_point(xx,yy)) || Map_point(xx,yy) == CROSSWALL) { Map_point(x,y) = (yy != y) ? HWALL : VWALL; yy = hi_yy; /* end `yy' loop */ break; /* end `xx' loop */ } } } } /* * We need to check the subrooms apartenance to an existing room. */ boolean check_subrooms() { unsigned i, j, n_subrooms; boolean found, ok = TRUE; char *last_parent, msg[256]; for (i = 0; i < nrooms; i++) if (tmproom[i]->parent) { found = FALSE; for(j = 0; j < nrooms; j++) if (tmproom[j]->name && !strcmp(tmproom[i]->parent, tmproom[j]->name)) { found = TRUE; break; } if (!found) { Sprintf(msg, "Subroom error : parent room '%s' not found!", tmproom[i]->parent); yyerror(msg); ok = FALSE; } } msg[0] = '\0'; last_parent = msg; for (i = 0; i < nrooms; i++) if (tmproom[i]->parent) { n_subrooms = 0; for(j = i; j < nrooms; j++) { /* * This is by no means perfect, but should cut down the duplicate error * messages by over 90%. The only problem will be when either subrooms * are mixed in the level definition (not likely but possible) or rooms * have subrooms that have subrooms. */ if (!strcmp(tmproom[i]->parent, last_parent)) continue; if (tmproom[j]->parent && !strcmp(tmproom[i]->parent, tmproom[j]->parent)) { n_subrooms++; if(n_subrooms > MAX_SUBROOMS) { Sprintf(msg, "Subroom error: too many subrooms attached to parent room '%s'!", tmproom[i]->parent); yyerror(msg); last_parent = tmproom[i]->parent; ok = FALSE; break; } } } } return ok; } /* * Check that coordinates (x,y) are roomlike locations. * Print warning "str" if they aren't. */ void check_coord(x, y, str) int x, y; const char *str; { char ebuf[60]; if (x >= 0 && y >= 0 && x <= (int)max_x_map && y <= (int)max_y_map && (IS_ROCK(tmpmap[y][x]) || IS_DOOR(tmpmap[y][x]))) { Sprintf(ebuf, "%s placed in wall at (%02d,%02d)?!", str, x, y); yywarning(ebuf); } } /* * Here we want to store the maze part we just got. */ void store_part() { register unsigned i; /* Ok, We got the whole part, now we store it. */ /* The Regions */ if ((tmppart[npart]->nreg = nreg) != 0) { tmppart[npart]->regions = NewTab(region, nreg); for(i=0;iregions[i] = tmpreg[i]; } nreg = 0; /* The Level Regions */ if ((tmppart[npart]->nlreg = nlreg) != 0) { tmppart[npart]->lregions = NewTab(lev_region, nlreg); for(i=0;ilregions[i] = tmplreg[i]; } nlreg = 0; /* the doors */ if ((tmppart[npart]->ndoor = ndoor) != 0) { tmppart[npart]->doors = NewTab(door, ndoor); for(i=0;idoors[i] = tmpdoor[i]; } ndoor = 0; /* the drawbridges */ if ((tmppart[npart]->ndrawbridge = ndb) != 0) { tmppart[npart]->drawbridges = NewTab(drawbridge, ndb); for(i=0;idrawbridges[i] = tmpdb[i]; } ndb = 0; /* The walkmaze directives */ if ((tmppart[npart]->nwalk = nwalk) != 0) { tmppart[npart]->walks = NewTab(walk, nwalk); for(i=0;iwalks[i] = tmpwalk[i]; } nwalk = 0; /* The non_diggable directives */ if ((tmppart[npart]->ndig = ndig) != 0) { tmppart[npart]->digs = NewTab(digpos, ndig); for(i=0;idigs[i] = tmpdig[i]; } ndig = 0; /* The non_passwall directives */ if ((tmppart[npart]->npass = npass) != 0) { tmppart[npart]->passs = NewTab(digpos, npass); for(i=0;ipasss[i] = tmppass[i]; } npass = 0; /* The ladders */ if ((tmppart[npart]->nlad = nlad) != 0) { tmppart[npart]->lads = NewTab(lad, nlad); for(i=0;ilads[i] = tmplad[i]; } nlad = 0; /* The stairs */ if ((tmppart[npart]->nstair = nstair) != 0) { tmppart[npart]->stairs = NewTab(stair, nstair); for(i=0;istairs[i] = tmpstair[i]; } nstair = 0; /* The altars */ if ((tmppart[npart]->naltar = naltar) != 0) { tmppart[npart]->altars = NewTab(altar, naltar); for(i=0;ialtars[i] = tmpaltar[i]; } naltar = 0; /* The fountains */ if ((tmppart[npart]->nfountain = nfountain) != 0) { tmppart[npart]->fountains = NewTab(fountain, nfountain); for(i=0;ifountains[i] = tmpfountain[i]; } nfountain = 0; /* the traps */ if ((tmppart[npart]->ntrap = ntrap) != 0) { tmppart[npart]->traps = NewTab(trap, ntrap); for(i=0;itraps[i] = tmptrap[i]; } ntrap = 0; /* the monsters */ if ((tmppart[npart]->nmonster = nmons) != 0) { tmppart[npart]->monsters = NewTab(monster, nmons); for(i=0;imonsters[i] = tmpmonst[i]; } else tmppart[npart]->monsters = 0; nmons = 0; /* the objects */ if ((tmppart[npart]->nobject = nobj) != 0) { tmppart[npart]->objects = NewTab(object, nobj); for(i=0;iobjects[i] = tmpobj[i]; } else tmppart[npart]->objects = 0; nobj = 0; /* The gold piles */ if ((tmppart[npart]->ngold = ngold) != 0) { tmppart[npart]->golds = NewTab(gold, ngold); for(i=0;igolds[i] = tmpgold[i]; } ngold = 0; /* The engravings */ if ((tmppart[npart]->nengraving = nengraving) != 0) { tmppart[npart]->engravings = NewTab(engraving, nengraving); for(i=0;iengravings[i] = tmpengraving[i]; } else tmppart[npart]->engravings = 0; nengraving = 0; npart++; n_plist = n_mlist = n_olist = 0; } /* * Here we want to store the room part we just got. */ void store_room() { register unsigned i; /* Ok, We got the whole room, now we store it. */ /* the doors */ if ((tmproom[nrooms]->ndoor = ndoor) != 0) { tmproom[nrooms]->doors = NewTab(room_door, ndoor); for(i=0;idoors[i] = tmprdoor[i]; } ndoor = 0; /* The stairs */ if ((tmproom[nrooms]->nstair = nstair) != 0) { tmproom[nrooms]->stairs = NewTab(stair, nstair); for(i=0;istairs[i] = tmpstair[i]; } nstair = 0; /* The altars */ if ((tmproom[nrooms]->naltar = naltar) != 0) { tmproom[nrooms]->altars = NewTab(altar, naltar); for(i=0;ialtars[i] = tmpaltar[i]; } naltar = 0; /* The fountains */ if ((tmproom[nrooms]->nfountain = nfountain) != 0) { tmproom[nrooms]->fountains = NewTab(fountain, nfountain); for(i=0;ifountains[i] = tmpfountain[i]; } nfountain = 0; /* The sinks */ if ((tmproom[nrooms]->nsink = nsink) != 0) { tmproom[nrooms]->sinks = NewTab(sink, nsink); for(i=0;isinks[i] = tmpsink[i]; } nsink = 0; /* The pools */ if ((tmproom[nrooms]->npool = npool) != 0) { tmproom[nrooms]->pools = NewTab(pool, npool); for(i=0;ipools[i] = tmppool[i]; } npool = 0; /* the traps */ if ((tmproom[nrooms]->ntrap = ntrap) != 0) { tmproom[nrooms]->traps = NewTab(trap, ntrap); for(i=0;itraps[i] = tmptrap[i]; } ntrap = 0; /* the monsters */ if ((tmproom[nrooms]->nmonster = nmons) != 0) { tmproom[nrooms]->monsters = NewTab(monster, nmons); for(i=0;imonsters[i] = tmpmonst[i]; } else tmproom[nrooms]->monsters = 0; nmons = 0; /* the objects */ if ((tmproom[nrooms]->nobject = nobj) != 0) { tmproom[nrooms]->objects = NewTab(object, nobj); for(i=0;iobjects[i] = tmpobj[i]; } else tmproom[nrooms]->objects = 0; nobj = 0; /* The gold piles */ if ((tmproom[nrooms]->ngold = ngold) != 0) { tmproom[nrooms]->golds = NewTab(gold, ngold); for(i=0;igolds[i] = tmpgold[i]; } ngold = 0; /* The engravings */ if ((tmproom[nrooms]->nengraving = nengraving) != 0) { tmproom[nrooms]->engravings = NewTab(engraving, nengraving); for(i=0;iengravings[i] = tmpengraving[i]; } else tmproom[nrooms]->engravings = 0; nengraving = 0; nrooms++; } /* * Output some info common to all special levels. */ static boolean write_common_data(fd, typ, init, flgs) int fd, typ; lev_init *init; long flgs; { char c; uchar len; static struct version_info version_data = { VERSION_NUMBER, VERSION_FEATURES, VERSION_SANITY1, VERSION_SANITY2 }; Write(fd, &version_data, sizeof version_data); c = typ; Write(fd, &c, sizeof(c)); /* 1 byte header */ Write(fd, init, sizeof(lev_init)); Write(fd, &flgs, sizeof flgs); len = (uchar) strlen(tmpmessage); Write(fd, &len, sizeof len); if (len) Write(fd, tmpmessage, (int) len); tmpmessage[0] = '\0'; return TRUE; } /* * Output monster info, which needs string fixups, then release memory. */ static boolean write_monsters(fd, nmonster_p, monsters_p) int fd; char *nmonster_p; monster ***monsters_p; { monster *m; char *name, *appr; int j, n = (int)*nmonster_p; Write(fd, nmonster_p, sizeof *nmonster_p); for (j = 0; j < n; j++) { m = (*monsters_p)[j]; name = m->name.str; appr = m->appear_as.str; m->name.str = m->appear_as.str = 0; m->name.len = name ? strlen(name) : 0; m->appear_as.len = appr ? strlen(appr) : 0; Write(fd, m, sizeof *m); if (name) { Write(fd, name, m->name.len); Free(name); } if (appr) { Write(fd, appr, m->appear_as.len); Free(appr); } Free(m); } if (*monsters_p) { Free(*monsters_p); *monsters_p = 0; } *nmonster_p = 0; return TRUE; } /* * Output object info, which needs string fixup, then release memory. */ static boolean write_objects(fd, nobject_p, objects_p) int fd; char *nobject_p; object ***objects_p; { object *o; char *name; int j, n = (int)*nobject_p; Write(fd, nobject_p, sizeof *nobject_p); for (j = 0; j < n; j++) { o = (*objects_p)[j]; name = o->name.str; o->name.str = 0; /* reset in case `len' is narrower */ o->name.len = name ? strlen(name) : 0; Write(fd, o, sizeof *o); if (name) { Write(fd, name, o->name.len); Free(name); } Free(o); } if (*objects_p) { Free(*objects_p); *objects_p = 0; } *nobject_p = 0; return TRUE; } /* * Output engraving info, which needs string fixup, then release memory. */ static boolean write_engravings(fd, nengraving_p, engravings_p) int fd; char *nengraving_p; engraving ***engravings_p; { engraving *e; char *engr; int j, n = (int)*nengraving_p; Write(fd, nengraving_p, sizeof *nengraving_p); for (j = 0; j < n; j++) { e = (*engravings_p)[j]; engr = e->engr.str; e->engr.str = 0; /* reset in case `len' is narrower */ e->engr.len = strlen(engr); Write(fd, e, sizeof *e); Write(fd, engr, e->engr.len); Free(engr); Free(e); } if (*engravings_p) { Free(*engravings_p); *engravings_p = 0; } *nengraving_p = 0; return TRUE; } /* * Open and write maze or rooms file, based on which pointer is non-null. * Return TRUE on success, FALSE on failure. */ boolean write_level_file(filename, room_level, maze_level) char *filename; splev *room_level; specialmaze *maze_level; { int fout; char lbuf[60]; lbuf[0] = '\0'; #ifdef PREFIX Strcat(lbuf, PREFIX); #endif Strcat(lbuf, filename); Strcat(lbuf, LEV_EXT); #if defined(MAC) && (defined(__SC__) || defined(__MRC__)) fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY); #else fout = open(lbuf, O_WRONLY|O_CREAT|O_BINARY, OMASK); #endif if (fout < 0) return FALSE; if (room_level) { if (!write_rooms(fout, room_level)) return FALSE; } else if (maze_level) { if (!write_maze(fout, maze_level)) return FALSE; } else panic("write_level_file"); (void) close(fout); return TRUE; } /* * Here we write the structure of the maze in the specified file (fd). * Also, we have to free the memory allocated via alloc(). */ static boolean write_maze(fd, maze) int fd; specialmaze *maze; { short i,j; mazepart *pt; if (!write_common_data(fd, SP_LEV_MAZE, &(maze->init_lev), maze->flags)) return FALSE; Write(fd, &(maze->filling), sizeof(maze->filling)); Write(fd, &(maze->numpart), sizeof(maze->numpart)); /* Number of parts */ for(i=0;inumpart;i++) { pt = maze->parts[i]; /* First, write the map */ Write(fd, &(pt->halign), sizeof(pt->halign)); Write(fd, &(pt->valign), sizeof(pt->valign)); Write(fd, &(pt->xsize), sizeof(pt->xsize)); Write(fd, &(pt->ysize), sizeof(pt->ysize)); for(j=0;jysize;j++) { if(!maze->init_lev.init_present || pt->xsize > 1 || pt->ysize > 1) { #if !defined(_MSC_VER) && !defined(__BORLANDC__) Write(fd, pt->map[j], pt->xsize * sizeof *pt->map[j]); #else /* * On MSVC and Borland C compilers the Write macro above caused: * warning '!=' : signed/unsigned mismatch */ unsigned reslt, sz = pt->xsize * sizeof *pt->map[j]; reslt = write(fd, (genericptr_t)(pt->map[j]), sz); if (reslt != sz) return FALSE; #endif } Free(pt->map[j]); } Free(pt->map); /* level region stuff */ Write(fd, &pt->nlreg, sizeof pt->nlreg); for (j = 0; j < pt->nlreg; j++) { lev_region *l = pt->lregions[j]; char *rname = l->rname.str; l->rname.str = 0; /* reset in case `len' is narrower */ l->rname.len = rname ? strlen(rname) : 0; Write(fd, l, sizeof *l); if (rname) { Write(fd, rname, l->rname.len); Free(rname); } Free(l); } if (pt->nlreg > 0) Free(pt->lregions); /* The random registers */ Write(fd, &(pt->nrobjects), sizeof(pt->nrobjects)); if(pt->nrobjects) { Write(fd, pt->robjects, pt->nrobjects); Free(pt->robjects); } Write(fd, &(pt->nloc), sizeof(pt->nloc)); if(pt->nloc) { Write(fd, pt->rloc_x, pt->nloc); Write(fd, pt->rloc_y, pt->nloc); Free(pt->rloc_x); Free(pt->rloc_y); } Write(fd, &(pt->nrmonst), sizeof(pt->nrmonst)); if(pt->nrmonst) { Write(fd, pt->rmonst, pt->nrmonst); Free(pt->rmonst); } /* subrooms */ Write(fd, &(pt->nreg), sizeof(pt->nreg)); for(j=0;jnreg;j++) { Write(fd, pt->regions[j], sizeof(region)); Free(pt->regions[j]); } if(pt->nreg > 0) Free(pt->regions); /* the doors */ Write(fd, &(pt->ndoor), sizeof(pt->ndoor)); for(j=0;jndoor;j++) { Write(fd, pt->doors[j], sizeof(door)); Free(pt->doors[j]); } if (pt->ndoor > 0) Free(pt->doors); /* The drawbridges */ Write(fd, &(pt->ndrawbridge), sizeof(pt->ndrawbridge)); for(j=0;jndrawbridge;j++) { Write(fd, pt->drawbridges[j], sizeof(drawbridge)); Free(pt->drawbridges[j]); } if(pt->ndrawbridge > 0) Free(pt->drawbridges); /* The mazewalk directives */ Write(fd, &(pt->nwalk), sizeof(pt->nwalk)); for(j=0; jnwalk; j++) { Write(fd, pt->walks[j], sizeof(walk)); Free(pt->walks[j]); } if (pt->nwalk > 0) Free(pt->walks); /* The non_diggable directives */ Write(fd, &(pt->ndig), sizeof(pt->ndig)); for(j=0;jndig;j++) { Write(fd, pt->digs[j], sizeof(digpos)); Free(pt->digs[j]); } if (pt->ndig > 0) Free(pt->digs); /* The non_passwall directives */ Write(fd, &(pt->npass), sizeof(pt->npass)); for(j=0;jnpass;j++) { Write(fd, pt->passs[j], sizeof(digpos)); Free(pt->passs[j]); } if (pt->npass > 0) Free(pt->passs); /* The ladders */ Write(fd, &(pt->nlad), sizeof(pt->nlad)); for(j=0;jnlad;j++) { Write(fd, pt->lads[j], sizeof(lad)); Free(pt->lads[j]); } if (pt->nlad > 0) Free(pt->lads); /* The stairs */ Write(fd, &(pt->nstair), sizeof(pt->nstair)); for(j=0;jnstair;j++) { Write(fd, pt->stairs[j], sizeof(stair)); Free(pt->stairs[j]); } if (pt->nstair > 0) Free(pt->stairs); /* The altars */ Write(fd, &(pt->naltar), sizeof(pt->naltar)); for(j=0;jnaltar;j++) { Write(fd, pt->altars[j], sizeof(altar)); Free(pt->altars[j]); } if (pt->naltar > 0) Free(pt->altars); /* The fountains */ Write(fd, &(pt->nfountain), sizeof(pt->nfountain)); for(j=0;jnfountain;j++) { Write(fd, pt->fountains[j], sizeof(fountain)); Free(pt->fountains[j]); } if (pt->nfountain > 0) Free(pt->fountains); /* The traps */ Write(fd, &(pt->ntrap), sizeof(pt->ntrap)); for(j=0;jntrap;j++) { Write(fd, pt->traps[j], sizeof(trap)); Free(pt->traps[j]); } if (pt->ntrap) Free(pt->traps); /* The monsters */ if (!write_monsters(fd, &pt->nmonster, &pt->monsters)) return FALSE; /* The objects */ if (!write_objects(fd, &pt->nobject, &pt->objects)) return FALSE; /* The gold piles */ Write(fd, &(pt->ngold), sizeof(pt->ngold)); for(j=0;jngold;j++) { Write(fd, pt->golds[j], sizeof(gold)); Free(pt->golds[j]); } if (pt->ngold > 0) Free(pt->golds); /* The engravings */ if (!write_engravings(fd, &pt->nengraving, &pt->engravings)) return FALSE; Free(pt); } Free(maze->parts); maze->parts = (mazepart **)0; maze->numpart = 0; return TRUE; } /* * Here we write the structure of the room level in the specified file (fd). */ static boolean write_rooms(fd, lev) int fd; splev *lev; { short i,j, size; room *pt; if (!write_common_data(fd, SP_LEV_ROOMS, &(lev->init_lev), lev->flags)) return FALSE; /* Random registers */ Write(fd, &lev->nrobjects, sizeof(lev->nrobjects)); if (lev->nrobjects) Write(fd, lev->robjects, lev->nrobjects); Write(fd, &lev->nrmonst, sizeof(lev->nrmonst)); if (lev->nrmonst) Write(fd, lev->rmonst, lev->nrmonst); Write(fd, &(lev->nroom), sizeof(lev->nroom)); /* Number of rooms */ for(i=0;inroom;i++) { pt = lev->rooms[i]; /* Room characteristics */ size = (short) (pt->name ? strlen(pt->name) : 0); Write(fd, &size, sizeof(size)); if (size) Write(fd, pt->name, size); size = (short) (pt->parent ? strlen(pt->parent) : 0); Write(fd, &size, sizeof(size)); if (size) Write(fd, pt->parent, size); Write(fd, &(pt->x), sizeof(pt->x)); Write(fd, &(pt->y), sizeof(pt->y)); Write(fd, &(pt->w), sizeof(pt->w)); Write(fd, &(pt->h), sizeof(pt->h)); Write(fd, &(pt->xalign), sizeof(pt->xalign)); Write(fd, &(pt->yalign), sizeof(pt->yalign)); Write(fd, &(pt->rtype), sizeof(pt->rtype)); Write(fd, &(pt->chance), sizeof(pt->chance)); Write(fd, &(pt->rlit), sizeof(pt->rlit)); Write(fd, &(pt->filled), sizeof(pt->filled)); /* the doors */ Write(fd, &(pt->ndoor), sizeof(pt->ndoor)); for(j=0;jndoor;j++) Write(fd, pt->doors[j], sizeof(room_door)); /* The stairs */ Write(fd, &(pt->nstair), sizeof(pt->nstair)); for(j=0;jnstair;j++) Write(fd, pt->stairs[j], sizeof(stair)); /* The altars */ Write(fd, &(pt->naltar), sizeof(pt->naltar)); for(j=0;jnaltar;j++) Write(fd, pt->altars[j], sizeof(altar)); /* The fountains */ Write(fd, &(pt->nfountain), sizeof(pt->nfountain)); for(j=0;jnfountain;j++) Write(fd, pt->fountains[j], sizeof(fountain)); /* The sinks */ Write(fd, &(pt->nsink), sizeof(pt->nsink)); for(j=0;jnsink;j++) Write(fd, pt->sinks[j], sizeof(sink)); /* The pools */ Write(fd, &(pt->npool), sizeof(pt->npool)); for(j=0;jnpool;j++) Write(fd, pt->pools[j], sizeof(pool)); /* The traps */ Write(fd, &(pt->ntrap), sizeof(pt->ntrap)); for(j=0;jntrap;j++) Write(fd, pt->traps[j], sizeof(trap)); /* The monsters */ if (!write_monsters(fd, &pt->nmonster, &pt->monsters)) return FALSE; /* The objects */ if (!write_objects(fd, &pt->nobject, &pt->objects)) return FALSE; /* The gold piles */ Write(fd, &(pt->ngold), sizeof(pt->ngold)); for(j=0;jngold;j++) Write(fd, pt->golds[j], sizeof(gold)); /* The engravings */ if (!write_engravings(fd, &pt->nengraving, &pt->engravings)) return FALSE; } /* The corridors */ Write(fd, &lev->ncorr, sizeof(lev->ncorr)); for (i=0; i < lev->ncorr; i++) Write(fd, lev->corrs[i], sizeof(corridor)); return TRUE; } /* * Release memory allocated to a rooms-style special level; maze-style * levels have the fields freed as they're written; monsters, objects, and * engravings are freed as written for both styles, so not handled here. */ void free_rooms(lev) splev *lev; { room *r; int j, n = lev->nroom; while(n--) { r = lev->rooms[n]; Free(r->name); Free(r->parent); if ((j = r->ndoor) != 0) { while(j--) Free(r->doors[j]); Free(r->doors); } if ((j = r->nstair) != 0) { while(j--) Free(r->stairs[j]); Free(r->stairs); } if ((j = r->naltar) != 0) { while (j--) Free(r->altars[j]); Free(r->altars); } if ((j = r->nfountain) != 0) { while(j--) Free(r->fountains[j]); Free(r->fountains); } if ((j = r->nsink) != 0) { while(j--) Free(r->sinks[j]); Free(r->sinks); } if ((j = r->npool) != 0) { while(j--) Free(r->pools[j]); Free(r->pools); } if ((j = r->ntrap) != 0) { while (j--) Free(r->traps[j]); Free(r->traps); } if ((j = r->ngold) != 0) { while(j--) Free(r->golds[j]); Free(r->golds); } Free(r); lev->rooms[n] = (room *)0; } Free(lev->rooms); lev->rooms = (room **)0; lev->nroom = 0; for (j = 0; j < lev->ncorr; j++) { Free(lev->corrs[j]); lev->corrs[j] = (corridor *)0; } Free(lev->corrs); lev->corrs = (corridor **)0; lev->ncorr = 0; Free(lev->robjects); lev->robjects = (char *)0; lev->nrobjects = 0; Free(lev->rmonst); lev->rmonst = (char *)0; lev->nrmonst = 0; } #ifdef STRICT_REF_DEF /* * Any globals declared in hack.h and descendents which aren't defined * in the modules linked into lev_comp should be defined here. These * definitions can be dummies: their sizes shouldn't matter as long as * as their types are correct; actual values are irrelevant. */ #define ARBITRARY_SIZE 1 /* attrib.c */ struct attribs attrmax, attrmin; /* files.c */ const char *configfile; char lock[ARBITRARY_SIZE]; char SAVEF[ARBITRARY_SIZE]; # ifdef MICRO char SAVEP[ARBITRARY_SIZE]; # endif /* termcap.c */ struct tc_lcl_data tc_lcl_data; # ifdef TEXTCOLOR # ifdef TOS const char *hilites[CLR_MAX]; # else char NEARDATA *hilites[CLR_MAX]; # endif # endif /* trap.c */ const char *traps[TRAPNUM]; /* window.c */ struct window_procs windowprocs; /* xxxtty.c */ # ifdef DEFINE_OSPEED short ospeed; # endif #endif /* STRICT_REF_DEF */ /*lev_main.c*/ nethack-3.4.3/util/makedefs.c0100644000000000000000000015033007764735041014554 0ustar rootroot/* SCCS Id: @(#)makedefs.c 3.4 2002/08/14 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* Copyright (c) M. Stephenson, 1990, 1991. */ /* Copyright (c) Dean Luick, 1990. */ /* NetHack may be freely redistributed. See license for details. */ #define MAKEDEFS_C /* use to conditionally include file sections */ /* #define DEBUG */ /* uncomment for debugging info */ #include "config.h" #include "permonst.h" #include "objclass.h" #include "monsym.h" #include "artilist.h" #include "dungeon.h" #include "obj.h" #include "monst.h" #include "you.h" #include "flag.h" #include "dlb.h" /* version information */ #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #ifdef MAC # if defined(__SC__) || defined(__MRC__) /* MPW compilers */ # define MPWTOOL #include #include #include # else /* MAC without MPWTOOL */ # define MACsansMPWTOOL # endif #endif /* MAC */ #ifndef MPWTOOL # define SpinCursor(x) #endif #define Fprintf (void) fprintf #define Fclose (void) fclose #define Unlink (void) unlink #if !defined(AMIGA) || defined(AZTEC_C) #define rewind(fp) fseek((fp),0L,SEEK_SET) /* guarantee a return value */ #endif #if defined(UNIX) && !defined(LINT) && !defined(GCC_WARN) static const char SCCS_Id[] = "@(#)makedefs.c\t3.4\t2002/02/03"; #endif /* names of files to be generated */ #define DATE_FILE "date.h" #define MONST_FILE "pm.h" #define ONAME_FILE "onames.h" #ifndef OPTIONS_FILE #define OPTIONS_FILE "options" #endif #define ORACLE_FILE "oracles" #define DATA_FILE "data" #define RUMOR_FILE "rumors" #define DGN_I_FILE "dungeon.def" #define DGN_O_FILE "dungeon.pdf" #define MON_STR_C "monstr.c" #define QTXT_I_FILE "quest.txt" #define QTXT_O_FILE "quest.dat" #define VIS_TAB_H "vis_tab.h" #define VIS_TAB_C "vis_tab.c" /* locations for those files */ #ifdef AMIGA # define FILE_PREFIX # define INCLUDE_TEMPLATE "NH:include/t.%s" # define SOURCE_TEMPLATE "NH:src/%s" # define DGN_TEMPLATE "NH:dat/%s" /* where dungeon.pdf file goes */ # define DATA_TEMPLATE "NH:slib/%s" # define DATA_IN_TEMPLATE "NH:dat/%s" #else /* not AMIGA */ # if defined(MAC) && !defined(__MACH__) /* MacOS 9 or earlier */ # define INCLUDE_TEMPLATE ":include:%s" # define SOURCE_TEMPLATE ":src:%s" # define DGN_TEMPLATE ":dat:%s" /* where dungeon.pdf file goes */ # if __SC__ || __MRC__ # define DATA_TEMPLATE ":Dungeon:%s" # else # define DATA_TEMPLATE ":lib:%s" # endif /* __SC__ || __MRC__ */ # define DATA_IN_TEMPLATE ":dat:%s" # else /* neither AMIGA nor MAC */ # ifdef OS2 # define INCLUDE_TEMPLATE "..\\include\\%s" # define SOURCE_TEMPLATE "..\\src\\%s" # define DGN_TEMPLATE "..\\dat\\%s" /* where dungeon.pdf file goes */ # define DATA_TEMPLATE "..\\dat\\%s" # define DATA_IN_TEMPLATE "..\\dat\\%s" # else /* not AMIGA, MAC, or OS2 */ # define INCLUDE_TEMPLATE "../include/%s" # define SOURCE_TEMPLATE "../src/%s" # define DGN_TEMPLATE "../dat/%s" /* where dungeon.pdf file goes */ # define DATA_TEMPLATE "../dat/%s" # define DATA_IN_TEMPLATE "../dat/%s" # endif /* else !OS2 */ # endif /* else !MAC */ #endif /* else !AMIGA */ static const char *Dont_Edit_Code = "/* This source file is generated by 'makedefs'. Do not edit. */\n", *Dont_Edit_Data = "#\tThis data file is generated by 'makedefs'. Do not edit. \n"; static struct version_info version; /* definitions used for vision tables */ #define TEST_WIDTH COLNO #define TEST_HEIGHT ROWNO #define BLOCK_WIDTH (TEST_WIDTH + 10) #define BLOCK_HEIGHT TEST_HEIGHT /* don't need extra spaces */ #define MAX_ROW (BLOCK_HEIGHT + TEST_HEIGHT) #define MAX_COL (BLOCK_WIDTH + TEST_WIDTH) /* Use this as an out-of-bound value in the close table. */ #define CLOSE_OFF_TABLE_STRING "99" /* for the close table */ #define FAR_OFF_TABLE_STRING "0xff" /* for the far table */ #define sign(z) ((z) < 0 ? -1 : ((z) ? 1 : 0)) #ifdef VISION_TABLES static char xclear[MAX_ROW][MAX_COL]; #endif /*-end of vision defs-*/ static char in_line[256], filename[60]; #ifdef FILE_PREFIX /* if defined, a first argument not starting with - is * taken as a text string to be prepended to any * output filename generated */ char *file_prefix=""; #endif #ifdef MACsansMPWTOOL int FDECL(main, (void)); #else int FDECL(main, (int,char **)); #endif void FDECL(do_makedefs, (char *)); void NDECL(do_objs); void NDECL(do_data); void NDECL(do_dungeon); void NDECL(do_date); void NDECL(do_options); void NDECL(do_monstr); void NDECL(do_permonst); void NDECL(do_questtxt); void NDECL(do_rumors); void NDECL(do_oracles); void NDECL(do_vision); extern void NDECL(monst_init); /* monst.c */ extern void NDECL(objects_init); /* objects.c */ static void NDECL(make_version); static char *FDECL(version_string, (char *)); static char *FDECL(version_id_string, (char *,const char *)); static char *FDECL(xcrypt, (const char *)); static int FDECL(check_control, (char *)); static char *FDECL(without_control, (char *)); static boolean FDECL(d_filter, (char *)); static boolean FDECL(h_filter, (char *)); static boolean FDECL(ranged_attk,(struct permonst*)); static int FDECL(mstrength,(struct permonst *)); static void NDECL(build_savebones_compat_string); static boolean FDECL(qt_comment, (char *)); static boolean FDECL(qt_control, (char *)); static int FDECL(get_hdr, (char *)); static boolean FDECL(new_id, (char *)); static boolean FDECL(known_msg, (int,int)); static void FDECL(new_msg, (char *,int,int)); static void FDECL(do_qt_control, (char *)); static void FDECL(do_qt_text, (char *)); static void NDECL(adjust_qt_hdrs); static void NDECL(put_qt_hdrs); #ifdef VISION_TABLES static void NDECL(H_close_gen); static void NDECL(H_far_gen); static void NDECL(C_close_gen); static void NDECL(C_far_gen); static int FDECL(clear_path, (int,int,int,int)); #endif static char *FDECL(tmpdup, (const char *)); static char *FDECL(limit, (char *,int)); static char *FDECL(eos, (char *)); /* input, output, tmp */ static FILE *ifp, *ofp, *tfp; #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif #ifdef MACsansMPWTOOL int main(void) { const char *def_options = "odemvpqrhz"; char buf[100]; int len; printf("Enter options to run: [%s] ", def_options); fflush(stdout); fgets(buf, 100, stdin); len = strlen(buf); if (len <= 1) Strcpy(buf, def_options); else buf[len-1] = 0; /* remove return */ do_makedefs(buf); exit(EXIT_SUCCESS); return 0; } #else /* ! MAC */ int main(argc, argv) int argc; char *argv[]; { if ( (argc != 2) #ifdef FILE_PREFIX && (argc != 3) #endif ) { Fprintf(stderr, "Bad arg count (%d).\n", argc-1); (void) fflush(stderr); return 1; } #ifdef FILE_PREFIX if(argc >=2 && argv[1][0]!='-'){ file_prefix=argv[1]; argc--;argv++; } #endif do_makedefs(&argv[1][1]); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif void do_makedefs(options) char *options; { boolean more_than_one; /* Note: these initializers don't do anything except guarantee that we're linked properly. */ monst_init(); objects_init(); /* construct the current version number */ make_version(); more_than_one = strlen(options) > 1; while (*options) { if (more_than_one) Fprintf(stderr, "makedefs -%c\n", *options); switch (*options) { case 'o': case 'O': do_objs(); break; case 'd': case 'D': do_data(); break; case 'e': case 'E': do_dungeon(); break; case 'm': case 'M': do_monstr(); break; case 'v': case 'V': do_date(); do_options(); break; case 'p': case 'P': do_permonst(); break; case 'q': case 'Q': do_questtxt(); break; case 'r': case 'R': do_rumors(); break; case 'h': case 'H': do_oracles(); break; case 'z': case 'Z': do_vision(); break; default: Fprintf(stderr, "Unknown option '%c'.\n", *options); (void) fflush(stderr); exit(EXIT_FAILURE); } options++; } if (more_than_one) Fprintf(stderr, "Completed.\n"); /* feedback */ } /* trivial text encryption routine which can't be broken with `tr' */ static char *xcrypt(str) const char *str; { /* duplicated in src/hacklib.c */ static char buf[BUFSZ]; register const char *p; register char *q; register int bitmask; for (bitmask = 1, p = str, q = buf; *p; q++) { *q = *p++; if (*q & (32|64)) *q ^= bitmask; if ((bitmask <<= 1) >= 32) bitmask = 1; } *q = '\0'; return buf; } void do_rumors() { char infile[60]; long true_rumor_size; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename,file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, RUMOR_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Data); Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE); Strcat(infile, ".tru"); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); Fclose(ofp); Unlink(filename); /* kill empty output file */ exit(EXIT_FAILURE); } /* get size of true rumors file */ #ifndef VMS (void) fseek(ifp, 0L, SEEK_END); true_rumor_size = ftell(ifp); #else /* seek+tell is only valid for stream format files; since rumors.%%% might be in record format, count the actual data bytes instead. */ true_rumor_size = 0; while (fgets(in_line, sizeof in_line, ifp) != 0) true_rumor_size += strlen(in_line); /* includes newline */ #endif /* VMS */ Fprintf(ofp,"%06lx\n", true_rumor_size); (void) fseek(ifp, 0L, SEEK_SET); /* copy true rumors */ while (fgets(in_line, sizeof in_line, ifp) != 0) (void) fputs(xcrypt(in_line), ofp); Fclose(ifp); Sprintf(infile, DATA_IN_TEMPLATE, RUMOR_FILE); Strcat(infile, ".fal"); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); Fclose(ofp); Unlink(filename); /* kill incomplete output file */ exit(EXIT_FAILURE); } /* copy false rumors */ while (fgets(in_line, sizeof in_line, ifp) != 0) (void) fputs(xcrypt(in_line), ofp); Fclose(ifp); Fclose(ofp); return; } /* * 3.4.1: way back in 3.2.1 `flags.nap' became unconditional but * TIMED_DELAY was erroneously left in VERSION_FEATURES and has * been there up through 3.4.0. Simply removing it now would * break save file compatibility with 3.4.0 files, so we will * explicitly mask it out during version checks. * This should go away in the next version update. */ #define IGNORED_FEATURES ( 0L \ | (1L << 23) /* TIMED_DELAY */ \ ) static void make_version() { register int i; /* * integer version number */ version.incarnation = ((unsigned long)VERSION_MAJOR << 24) | ((unsigned long)VERSION_MINOR << 16) | ((unsigned long)PATCHLEVEL << 8) | ((unsigned long)EDITLEVEL); /* * encoded feature list * Note: if any of these magic numbers are changed or reassigned, * EDITLEVEL in patchlevel.h should be incremented at the same time. * The actual values have no special meaning, and the category * groupings are just for convenience. */ version.feature_set = (unsigned long)(0L /* levels and/or topology (0..4) */ #ifdef REINCARNATION | (1L << 1) #endif #ifdef SINKS | (1L << 2) #endif /* monsters (5..9) */ #ifdef KOPS | (1L << 6) #endif #ifdef MAIL | (1L << 7) #endif /* objects (10..14) */ #ifdef TOURIST | (1L << 10) #endif #ifdef STEED | (1L << 11) #endif #ifdef GOLDOBJ | (1L << 12) #endif /* flag bits and/or other global variables (15..26) */ #ifdef TEXTCOLOR | (1L << 17) #endif #ifdef INSURANCE | (1L << 18) #endif #ifdef ELBERETH | (1L << 19) #endif #ifdef EXP_ON_BOTL | (1L << 20) #endif #ifdef SCORE_ON_BOTL | (1L << 21) #endif /* data format [COMPRESS excluded] (27..31) */ #ifdef ZEROCOMP | (1L << 27) #endif #ifdef RLECOMP | (1L << 28) #endif ); /* * Value used for object & monster sanity check. * (NROFARTIFACTS<<24) | (NUM_OBJECTS<<12) | (NUMMONS<<0) */ for (i = 1; artifact_names[i]; i++) continue; version.entity_count = (unsigned long)(i - 1); for (i = 1; objects[i].oc_class != ILLOBJ_CLASS; i++) continue; version.entity_count = (version.entity_count << 12) | (unsigned long)i; for (i = 0; mons[i].mlet; i++) continue; version.entity_count = (version.entity_count << 12) | (unsigned long)i; /* * Value used for compiler (word size/field alignment/padding) check. */ version.struct_sizes = (((unsigned long)sizeof (struct flag) << 24) | ((unsigned long)sizeof (struct obj) << 17) | ((unsigned long)sizeof (struct monst) << 10) | ((unsigned long)sizeof (struct you))); return; } static char * version_string(outbuf) char *outbuf; { Sprintf(outbuf, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); #ifdef BETA Sprintf(eos(outbuf), "-%d", EDITLEVEL); #endif return outbuf; } static char * version_id_string(outbuf, build_date) char *outbuf; const char *build_date; { char subbuf[64], versbuf[64]; subbuf[0] = '\0'; #ifdef PORT_SUB_ID subbuf[0] = ' '; Strcpy(&subbuf[1], PORT_SUB_ID); #endif #ifdef BETA Strcat(subbuf, " Beta"); #endif Sprintf(outbuf, "%s NetHack%s Version %s - last build %s.", PORT_ID, subbuf, version_string(versbuf), build_date); return outbuf; } void do_date() { long clocktim = 0; char *c, cbuf[60], buf[BUFSZ]; const char *ul_sfx; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename,file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, DATE_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,"/*\tSCCS Id: @(#)date.h\t3.4\t2002/02/03 */\n\n"); Fprintf(ofp,Dont_Edit_Code); #ifdef KR1ED (void) time(&clocktim); Strcpy(cbuf, ctime(&clocktim)); #else (void) time((time_t *)&clocktim); Strcpy(cbuf, ctime((time_t *)&clocktim)); #endif for (c = cbuf; *c; c++) if (*c == '\n') break; *c = '\0'; /* strip off the '\n' */ Fprintf(ofp,"#define BUILD_DATE \"%s\"\n", cbuf); Fprintf(ofp,"#define BUILD_TIME (%ldL)\n", clocktim); Fprintf(ofp,"\n"); #ifdef NHSTDC ul_sfx = "UL"; #else ul_sfx = "L"; #endif Fprintf(ofp,"#define VERSION_NUMBER 0x%08lx%s\n", version.incarnation, ul_sfx); Fprintf(ofp,"#define VERSION_FEATURES 0x%08lx%s\n", version.feature_set, ul_sfx); #ifdef IGNORED_FEATURES Fprintf(ofp,"#define IGNORED_FEATURES 0x%08lx%s\n", (unsigned long) IGNORED_FEATURES, ul_sfx); #endif Fprintf(ofp,"#define VERSION_SANITY1 0x%08lx%s\n", version.entity_count, ul_sfx); Fprintf(ofp,"#define VERSION_SANITY2 0x%08lx%s\n", version.struct_sizes, ul_sfx); Fprintf(ofp,"\n"); Fprintf(ofp,"#define VERSION_STRING \"%s\"\n", version_string(buf)); Fprintf(ofp,"#define VERSION_ID \\\n \"%s\"\n", version_id_string(buf, cbuf)); Fprintf(ofp,"\n"); #ifdef AMIGA { struct tm *tm = localtime((time_t *) &clocktim); Fprintf(ofp,"#define AMIGA_VERSION_STRING "); Fprintf(ofp,"\"\\0$VER: NetHack %d.%d.%d (%d.%d.%d)\"\n", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL, tm->tm_mday, tm->tm_mon+1, tm->tm_year+1900); } #endif Fclose(ofp); return; } static char save_bones_compat_buf[BUFSZ]; static void build_savebones_compat_string() { #ifdef VERSION_COMPATIBILITY unsigned long uver = VERSION_COMPATIBILITY; #endif Strcpy(save_bones_compat_buf, "save and bones files accepted from version"); #ifdef VERSION_COMPATIBILITY Sprintf(eos(save_bones_compat_buf), "s %lu.%lu.%lu through %d.%d.%d", ((uver & 0xFF000000L) >> 24), ((uver & 0x00FF0000L) >> 16), ((uver & 0x0000FF00L) >> 8), VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); #else Sprintf(eos(save_bones_compat_buf), " %d.%d.%d only", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); #endif } static const char *build_opts[] = { #ifdef AMIGA_WBENCH "Amiga WorkBench support", #endif #ifdef ANSI_DEFAULT "ANSI default terminal", #endif #ifdef AUTOPICKUP_EXCEPTIONS "autopickup_exceptions", #endif #ifdef TEXTCOLOR "color", #endif #ifdef COM_COMPL "command line completion", #endif #ifdef COMPRESS "data file compression", #endif #ifdef DLB "data librarian", #endif #ifdef WIZARD "debug mode", #endif #ifdef ELBERETH "Elbereth", #endif #ifdef EXP_ON_BOTL "experience points on status line", #endif #ifdef MFLOPPY "floppy drive support", #endif #ifdef GOLDOBJ "gold object in inventories", #endif #ifdef INSURANCE "insurance files for recovering from crashes", #endif #ifdef KOPS "Keystone Kops", #endif #ifdef HOLD_LOCKFILE_OPEN "exclusive lock on level 0 file", #endif #ifdef LOGFILE "log file", #endif #ifdef MAIL "mail daemon", #endif #ifdef GNUDOS "MSDOS protected mode", #endif #ifdef NEWS "news file", #endif #ifdef OVERLAY # ifdef MOVERLAY "MOVE overlays", # else # ifdef VROOMM "VROOMM overlays", # else "overlays", # endif # endif #endif #ifdef REDO "redo command", #endif #ifdef REINCARNATION "rogue level", #endif #ifdef STEED "saddles and riding", #endif #ifdef SCORE_ON_BOTL "score on status line", #endif #ifdef CLIPPING "screen clipping", #endif #ifdef NO_TERMS # ifdef MAC "screen control via mactty", # endif # ifdef SCREEN_BIOS "screen control via BIOS", # endif # ifdef SCREEN_DJGPPFAST "screen control via DJGPP fast", # endif # ifdef SCREEN_VGA "screen control via VGA graphics", # endif # ifndef MSWIN_GRAPHICS # ifdef WIN32CON "screen control via WIN32 console I/O", # endif # endif #endif #ifdef SEDUCE "seduction", #endif #ifdef SHELL "shell command", #endif #ifdef SINKS "sinks", #endif #ifdef SUSPEND "suspend command", #endif #ifdef TERMINFO "terminal info library", #else # if defined(TERMLIB) || ((!defined(MICRO) && !defined(WIN32)) && defined(TTY_GRAPHICS)) "terminal capability library", # endif #endif #ifdef TIMED_DELAY "timed wait for display effects", #endif #ifdef TOURIST "tourists", #endif #ifdef USER_SOUNDS # ifdef USER_SOUNDS_REGEX "user sounds via regular expressions", # else "user sounds via pmatch", # endif #endif #ifdef PREFIXES_IN_USE "variable playground", #endif #ifdef VISION_TABLES "vision tables", #endif #ifdef WALLIFIED_MAZE "walled mazes", #endif #ifdef ZEROCOMP "zero-compressed save files", #endif save_bones_compat_buf, "basic NetHack features" }; static const char *window_opts[] = { #ifdef TTY_GRAPHICS "traditional tty-based graphics", #endif #ifdef X11_GRAPHICS "X11", #endif #ifdef QT_GRAPHICS "Qt", #endif #ifdef GNOME_GRAPHICS "Gnome", #endif #ifdef MAC "Mac", #endif #ifdef AMIGA_INTUITION "Amiga Intuition", #endif #ifdef GEM_GRAPHICS "Gem", #endif #ifdef MSWIN_GRAPHICS "mswin", #endif #ifdef BEOS_GRAPHICS "BeOS InterfaceKit", #endif 0 }; void do_options() { register int i, length; register const char *str, *indent = " "; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename,file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, OPTIONS_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } build_savebones_compat_string(); Fprintf(ofp, #ifdef BETA "\n NetHack version %d.%d.%d [beta]\n", #else "\n NetHack version %d.%d.%d\n", #endif VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); Fprintf(ofp,"\nOptions compiled into this edition:\n"); length = COLNO + 1; /* force 1st item onto new line */ for (i = 0; i < SIZE(build_opts); i++) { str = build_opts[i]; if (length + strlen(str) > COLNO - 5) Fprintf(ofp,"\n%s", indent), length = strlen(indent); else Fprintf(ofp," "), length++; Fprintf(ofp,"%s", str), length += strlen(str); Fprintf(ofp,(i < SIZE(build_opts) - 1) ? "," : "."), length++; } Fprintf(ofp,"\n\nSupported windowing systems:\n"); length = COLNO + 1; /* force 1st item onto new line */ for (i = 0; i < SIZE(window_opts) - 1; i++) { str = window_opts[i]; if (length + strlen(str) > COLNO - 5) Fprintf(ofp,"\n%s", indent), length = strlen(indent); else Fprintf(ofp," "), length++; Fprintf(ofp,"%s", str), length += strlen(str); Fprintf(ofp, ","), length++; } Fprintf(ofp, "\n%swith a default of %s.", indent, DEFAULT_WINDOW_SYS); Fprintf(ofp,"\n\n"); Fclose(ofp); return; } /* routine to decide whether to discard something from data.base */ static boolean d_filter(line) char *line; { if (*line == '#') return TRUE; /* ignore comment lines */ return FALSE; } /* * New format (v3.1) of 'data' file which allows much faster lookups [pr] "do not edit" first record is a comment line 01234567 hexadecimal formatted offset to text area name-a first name of interest 123,4 offset to name's text, and number of lines for it name-b next name of interest name-c multiple names which share same description also 456,7 share a single offset,count line . sentinel to mark end of names 789,0 dummy record containing offset, count of EOF text-a 4 lines of descriptive text for name-a text-a at file position 0x01234567L + 123L text-a text-a text-b/text-c 7 lines of text for names-b and -c text-b/text-c at fseek(0x01234567L + 456L) ... * */ void do_data() { char infile[60], tempfile[60]; boolean ok; long txt_offset; int entry_cnt, line_cnt; Sprintf(tempfile, DATA_TEMPLATE, "database.tmp"); filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename,file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, DATA_FILE); Sprintf(infile, DATA_IN_TEMPLATE, DATA_FILE); Strcat(infile, #ifdef SHORT_FILENAMES ".bas" #else ".base" #endif ); if (!(ifp = fopen(infile, RDTMODE))) { /* data.base */ perror(infile); exit(EXIT_FAILURE); } if (!(ofp = fopen(filename, WRTMODE))) { /* data */ perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } if (!(tfp = fopen(tempfile, WRTMODE))) { /* database.tmp */ perror(tempfile); Fclose(ifp); Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* output a dummy header record; we'll rewind and overwrite it later */ Fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, 0L); entry_cnt = line_cnt = 0; /* read through the input file and split it into two sections */ while (fgets(in_line, sizeof in_line, ifp)) { if (d_filter(in_line)) continue; if (*in_line > ' ') { /* got an entry name */ /* first finish previous entry */ if (line_cnt) Fprintf(ofp, "%d\n", line_cnt), line_cnt = 0; /* output the entry name */ (void) fputs(in_line, ofp); entry_cnt++; /* update number of entries */ } else if (entry_cnt) { /* got some descriptive text */ /* update previous entry with current text offset */ if (!line_cnt) Fprintf(ofp, "%ld,", ftell(tfp)); /* save the text line in the scratch file */ (void) fputs(in_line, tfp); line_cnt++; /* update line counter */ } } /* output an end marker and then record the current position */ if (line_cnt) Fprintf(ofp, "%d\n", line_cnt); Fprintf(ofp, ".\n%ld,%d\n", ftell(tfp), 0); txt_offset = ftell(ofp); Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ Sprintf(in_line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; /* copy all lines of text from the scratch file into the output file */ while (fgets(in_line, sizeof in_line, tfp)) (void) fputs(in_line, ofp); /* finished with scratch file */ Fclose(tfp); Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ Sprintf(in_line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { Sprintf(in_line, "header rewrite of \"%s\"", filename); ok = (fprintf(ofp, "%s%08lx\n", Dont_Edit_Data, txt_offset) >= 0); } if (!ok) { dead_data: perror(in_line); /* report the problem */ /* close and kill the aborted output file, then give up */ Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* all done */ Fclose(ofp); return; } /* routine to decide whether to discard something from oracles.txt */ static boolean h_filter(line) char *line; { static boolean skip = FALSE; char tag[sizeof in_line]; SpinCursor(3); if (*line == '#') return TRUE; /* ignore comment lines */ if (sscanf(line, "----- %s", tag) == 1) { skip = FALSE; #ifndef SINKS if (!strcmp(tag, "SINKS")) skip = TRUE; #endif #ifndef ELBERETH if (!strcmp(tag, "ELBERETH")) skip = TRUE; #endif } else if (skip && !strncmp(line, "-----", 5)) skip = FALSE; return skip; } static const char *special_oracle[] = { "\"...it is rather disconcerting to be confronted with the", "following theorem from [Baker, Gill, and Solovay, 1975].", "", "Theorem 7.18 There exist recursive languages A and B such that", " (1) P(A) == NP(A), and", " (2) P(B) != NP(B)", "", "This provides impressive evidence that the techniques that are", "currently available will not suffice for proving that P != NP or ", "that P == NP.\" [Garey and Johnson, p. 185.]" }; /* The oracle file consists of a "do not edit" comment, a decimal count N and set of N+1 hexadecimal fseek offsets, followed by N multiple-line records, separated by "---" lines. The first oracle is a special case. The input data contains just those multi-line records, separated by "-----" lines. */ void do_oracles() { char infile[60], tempfile[60]; boolean in_oracle, ok; long txt_offset, offset, fpos; int oracle_cnt; register int i; Sprintf(tempfile, DATA_TEMPLATE, "oracles.tmp"); filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, ORACLE_FILE); Sprintf(infile, DATA_IN_TEMPLATE, ORACLE_FILE); Strcat(infile, ".txt"); if (!(ifp = fopen(infile, RDTMODE))) { perror(infile); exit(EXIT_FAILURE); } if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } if (!(tfp = fopen(tempfile, WRTMODE))) { /* oracles.tmp */ perror(tempfile); Fclose(ifp); Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* output a dummy header record; we'll rewind and overwrite it later */ Fprintf(ofp, "%s%5d\n", Dont_Edit_Data, 0); /* handle special oracle; it must come first */ (void) fputs("---\n", tfp); Fprintf(ofp, "%05lx\n", ftell(tfp)); /* start pos of special oracle */ for (i = 0; i < SIZE(special_oracle); i++) { (void) fputs(xcrypt(special_oracle[i]), tfp); (void) fputc('\n', tfp); } SpinCursor(3); oracle_cnt = 1; (void) fputs("---\n", tfp); Fprintf(ofp, "%05lx\n", ftell(tfp)); /* start pos of first oracle */ in_oracle = FALSE; while (fgets(in_line, sizeof in_line, ifp)) { SpinCursor(3); if (h_filter(in_line)) continue; if (!strncmp(in_line, "-----", 5)) { if (!in_oracle) continue; in_oracle = FALSE; oracle_cnt++; (void) fputs("---\n", tfp); Fprintf(ofp, "%05lx\n", ftell(tfp)); /* start pos of this oracle */ } else { in_oracle = TRUE; (void) fputs(xcrypt(in_line), tfp); } } if (in_oracle) { /* need to terminate last oracle */ oracle_cnt++; (void) fputs("---\n", tfp); Fprintf(ofp, "%05lx\n", ftell(tfp)); /* eof position */ } /* record the current position */ txt_offset = ftell(ofp); Fclose(ifp); /* all done with original input file */ /* reprocess the scratch file; 1st format an error msg, just in case */ Sprintf(in_line, "rewind of \"%s\"", tempfile); if (rewind(tfp) != 0) goto dead_data; /* copy all lines of text from the scratch file into the output file */ while (fgets(in_line, sizeof in_line, tfp)) (void) fputs(in_line, ofp); /* finished with scratch file */ Fclose(tfp); Unlink(tempfile); /* remove it */ /* update the first record of the output file; prepare error msg 1st */ Sprintf(in_line, "rewind of \"%s\"", filename); ok = (rewind(ofp) == 0); if (ok) { Sprintf(in_line, "header rewrite of \"%s\"", filename); ok = (fprintf(ofp, "%s%5d\n", Dont_Edit_Data, oracle_cnt) >=0); } if (ok) { Sprintf(in_line, "data rewrite of \"%s\"", filename); for (i = 0; i <= oracle_cnt; i++) { #ifndef VMS /* alpha/vms v1.0; this fflush seems to confuse ftell */ if (!(ok = (fflush(ofp) == 0))) break; #endif if (!(ok = (fpos = ftell(ofp)) >= 0)) break; if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break; if (!(ok = (fscanf(ofp, "%5lx", &offset) == 1))) break; #ifdef MAC # ifdef __MWERKS__ /* MetroWerks CodeWarrior Pro 1's (AKA CW12) version of MSL (ANSI C Libraries) needs this rewind or else the fprintf stops working. This may also be true for CW11, but has never been checked. */ rewind(ofp); # endif #endif if (!(ok = (fseek(ofp, fpos, SEEK_SET) >= 0))) break; if (!(ok = (fprintf(ofp, "%05lx\n", offset + txt_offset) >= 0))) break; } } if (!ok) { dead_data: perror(in_line); /* report the problem */ /* close and kill the aborted output file, then give up */ Fclose(ofp); Unlink(filename); exit(EXIT_FAILURE); } /* all done */ Fclose(ofp); return; } static struct deflist { const char *defname; boolean true_or_false; } deflist[] = { #ifdef REINCARNATION { "REINCARNATION", TRUE }, #else { "REINCARNATION", FALSE }, #endif { 0, 0 } }; static int check_control(s) char *s; { int i; if(s[0] != '%') return(-1); for(i = 0; deflist[i].defname; i++) if(!strncmp(deflist[i].defname, s+1, strlen(deflist[i].defname))) return(i); return(-1); } static char * without_control(s) char *s; { return(s + 1 + strlen(deflist[check_control(in_line)].defname)); } void do_dungeon() { int rcnt = 0; Sprintf(filename, DATA_IN_TEMPLATE, DGN_I_FILE); if (!(ifp = fopen(filename, RDTMODE))) { perror(filename); exit(EXIT_FAILURE); } filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DGN_TEMPLATE, DGN_O_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Data); while (fgets(in_line, sizeof in_line, ifp) != 0) { SpinCursor(3); rcnt++; if(in_line[0] == '#') continue; /* discard comments */ recheck: if(in_line[0] == '%') { int i = check_control(in_line); if(i >= 0) { if(!deflist[i].true_or_false) { while (fgets(in_line, sizeof in_line, ifp) != 0) if(check_control(in_line) != i) goto recheck; } else (void) fputs(without_control(in_line),ofp); } else { Fprintf(stderr, "Unknown control option '%s' in file %s at line %d.\n", in_line, DGN_I_FILE, rcnt); exit(EXIT_FAILURE); } } else (void) fputs(in_line,ofp); } Fclose(ifp); Fclose(ofp); return; } static boolean ranged_attk(ptr) /* returns TRUE if monster can attack at range */ register struct permonst *ptr; { register int i, j; register int atk_mask = (1<mattk[i].aatyp) >= AT_WEAP || (atk_mask & (1<mlevel; if(tmp > 49) /* special fixed hp monster */ tmp = 2*(tmp - 6) / 4; /* For creation in groups */ n = (!!(ptr->geno & G_SGROUP)); n += (!!(ptr->geno & G_LGROUP)) << 1; /* For ranged attacks */ if (ranged_attk(ptr)) n++; /* For higher ac values */ n += (ptr->ac < 4); n += (ptr->ac < 0); /* For very fast monsters */ n += (ptr->mmove >= 18); /* For each attack and "special" attack */ for(i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].aatyp; n += (tmp2 > 0); n += (tmp2 == AT_MAGC); n += (tmp2 == AT_WEAP && (ptr->mflags2 & M2_STRONG)); } /* For each "special" damage type */ for(i = 0; i < NATTK; i++) { tmp2 = ptr->mattk[i].adtyp; if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_DRST) || (tmp2 == AD_DRDX) || (tmp2 == AD_DRCO) || (tmp2 == AD_WERE)) n += 2; else if (strcmp(ptr->mname, "grid bug")) n += (tmp2 != AD_PHYS); n += ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23); } /* Leprechauns are special cases. They have many hit dice so they can hit and are hard to kill, but they don't really do much damage. */ if (!strcmp(ptr->mname, "leprechaun")) n -= 2; /* Finally, adjust the monster level 0 <= n <= 24 (approx.) */ if(n == 0) tmp--; else if(n >= 6) tmp += ( n / 2 ); else tmp += ( n / 3 + 1); return((tmp >= 0) ? tmp : 0); } void do_monstr() { register struct permonst *ptr; register int i, j; /* * create the source file, "monstr.c" */ filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), SOURCE_TEMPLATE, MON_STR_C); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#include \"config.h\"\n"); Fprintf(ofp,"\nconst int monstr[] = {\n"); for (ptr = &mons[0], j = 0; ptr->mlet; ptr++) { SpinCursor(3); i = mstrength(ptr); Fprintf(ofp,"%2d,%c", i, (++j & 15) ? ' ' : '\n'); } /* might want to insert a final 0 entry here instead of just newline */ Fprintf(ofp,"%s};\n", (j & 15) ? "\n" : ""); Fprintf(ofp,"\nvoid NDECL(monstr_init);\n"); Fprintf(ofp,"\nvoid\n"); Fprintf(ofp,"monstr_init()\n"); Fprintf(ofp,"{\n"); Fprintf(ofp," return;\n"); Fprintf(ofp,"}\n"); Fprintf(ofp,"\n/*monstr.c*/\n"); Fclose(ofp); return; } void do_permonst() { int i; char *c, *nam; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, MONST_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,"/*\tSCCS Id: @(#)pm.h\t3.4\t2002/02/03 */\n\n"); Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#ifndef PM_H\n#define PM_H\n"); if (strcmp(mons[0].mname, "playermon") != 0) Fprintf(ofp,"\n#define\tPM_PLAYERMON\t(-1)"); for (i = 0; mons[i].mlet; i++) { SpinCursor(3); Fprintf(ofp,"\n#define\tPM_"); if (mons[i].mlet == S_HUMAN && !strncmp(mons[i].mname, "were", 4)) Fprintf(ofp, "HUMAN_"); for (nam = c = tmpdup(mons[i].mname); *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; Fprintf(ofp,"%s\t%d", nam, i); } Fprintf(ofp,"\n\n#define\tNUMMONS\t%d\n", i); Fprintf(ofp,"\n#endif /* PM_H */\n"); Fclose(ofp); return; } /* Start of Quest text file processing. */ #include "qtext.h" static struct qthdr qt_hdr; static struct msghdr msg_hdr[N_HDR]; static struct qtmsg *curr_msg; static int qt_line; static boolean in_msg; #define NO_MSG 1 /* strlen of a null line returned by fgets() */ static boolean qt_comment(s) char *s; { if(s[0] == '#') return(TRUE); return((boolean)(!in_msg && strlen(s) == NO_MSG)); } static boolean qt_control(s) char *s; { return((boolean)(s[0] == '%' && (s[1] == 'C' || s[1] == 'E'))); } static int get_hdr (code) char *code; { int i; for(i = 0; i < qt_hdr.n_hdr; i++) if(!strncmp(code, qt_hdr.id[i], LEN_HDR)) return (++i); return(0); } static boolean new_id (code) char *code; { if(qt_hdr.n_hdr >= N_HDR) { Fprintf(stderr, OUT_OF_HEADERS, qt_line); return(FALSE); } strncpy(&qt_hdr.id[qt_hdr.n_hdr][0], code, LEN_HDR); msg_hdr[qt_hdr.n_hdr].n_msg = 0; qt_hdr.offset[qt_hdr.n_hdr++] = 0L; return(TRUE); } static boolean known_msg(num, id) int num, id; { int i; for(i = 0; i < msg_hdr[num].n_msg; i++) if(msg_hdr[num].qt_msg[i].msgnum == id) return(TRUE); return(FALSE); } static void new_msg(s, num, id) char *s; int num, id; { struct qtmsg *qt_msg; if(msg_hdr[num].n_msg >= N_MSG) { Fprintf(stderr, OUT_OF_MESSAGES, qt_line); } else { qt_msg = &(msg_hdr[num].qt_msg[msg_hdr[num].n_msg++]); qt_msg->msgnum = id; qt_msg->delivery = s[2]; qt_msg->offset = qt_msg->size = 0L; curr_msg = qt_msg; } } static void do_qt_control(s) char *s; { char code[BUFSZ]; int num, id = 0; switch(s[1]) { case 'C': if(in_msg) { Fprintf(stderr, CREC_IN_MSG, qt_line); break; } else { in_msg = TRUE; if (sscanf(&s[4], "%s %5d", code, &id) != 2) { Fprintf(stderr, UNREC_CREC, qt_line); break; } num = get_hdr(code); if (!num && !new_id(code)) break; num = get_hdr(code)-1; if(known_msg(num, id)) Fprintf(stderr, DUP_MSG, qt_line); else new_msg(s, num, id); } break; case 'E': if(!in_msg) { Fprintf(stderr, END_NOT_IN_MSG, qt_line); break; } else in_msg = FALSE; break; default: Fprintf(stderr, UNREC_CREC, qt_line); break; } } static void do_qt_text(s) char *s; { if (!in_msg) { Fprintf(stderr, TEXT_NOT_IN_MSG, qt_line); } curr_msg->size += strlen(s); return; } static void adjust_qt_hdrs() { int i, j; long count = 0L, hdr_offset = sizeof(int) + (sizeof(char)*LEN_HDR + sizeof(long)) * qt_hdr.n_hdr; for(i = 0; i < qt_hdr.n_hdr; i++) { qt_hdr.offset[i] = hdr_offset; hdr_offset += sizeof(int) + sizeof(struct qtmsg) * msg_hdr[i].n_msg; } for(i = 0; i < qt_hdr.n_hdr; i++) for(j = 0; j < msg_hdr[i].n_msg; j++) { msg_hdr[i].qt_msg[j].offset = hdr_offset + count; count += msg_hdr[i].qt_msg[j].size; } return; } static void put_qt_hdrs() { int i; /* * The main header record. */ #ifdef DEBUG Fprintf(stderr, "%ld: header info.\n", ftell(ofp)); #endif (void) fwrite((genericptr_t)&(qt_hdr.n_hdr), sizeof(int), 1, ofp); (void) fwrite((genericptr_t)&(qt_hdr.id[0][0]), sizeof(char)*LEN_HDR, qt_hdr.n_hdr, ofp); (void) fwrite((genericptr_t)&(qt_hdr.offset[0]), sizeof(long), qt_hdr.n_hdr, ofp); #ifdef DEBUG for(i = 0; i < qt_hdr.n_hdr; i++) Fprintf(stderr, "%c @ %ld, ", qt_hdr.id[i], qt_hdr.offset[i]); Fprintf(stderr, "\n"); #endif /* * The individual class headers. */ for(i = 0; i < qt_hdr.n_hdr; i++) { #ifdef DEBUG Fprintf(stderr, "%ld: %c header info.\n", ftell(ofp), qt_hdr.id[i]); #endif (void) fwrite((genericptr_t)&(msg_hdr[i].n_msg), sizeof(int), 1, ofp); (void) fwrite((genericptr_t)&(msg_hdr[i].qt_msg[0]), sizeof(struct qtmsg), msg_hdr[i].n_msg, ofp); #ifdef DEBUG { int j; for(j = 0; j < msg_hdr[i].n_msg; j++) Fprintf(stderr, "msg %d @ %ld (%ld)\n", msg_hdr[i].qt_msg[j].msgnum, msg_hdr[i].qt_msg[j].offset, msg_hdr[i].qt_msg[j].size); } #endif } } void do_questtxt() { Sprintf(filename, DATA_IN_TEMPLATE, QTXT_I_FILE); if(!(ifp = fopen(filename, RDTMODE))) { perror(filename); exit(EXIT_FAILURE); } filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), DATA_TEMPLATE, QTXT_O_FILE); if(!(ofp = fopen(filename, WRBMODE))) { perror(filename); Fclose(ifp); exit(EXIT_FAILURE); } qt_hdr.n_hdr = 0; qt_line = 0; in_msg = FALSE; while (fgets(in_line, 80, ifp) != 0) { SpinCursor (3); qt_line++; if(qt_control(in_line)) do_qt_control(in_line); else if(qt_comment(in_line)) continue; else do_qt_text(in_line); } (void) rewind(ifp); in_msg = FALSE; adjust_qt_hdrs(); put_qt_hdrs(); while (fgets(in_line, 80, ifp) != 0) { if(qt_control(in_line)) { in_msg = (in_line[1] == 'C'); continue; } else if(qt_comment(in_line)) continue; #ifdef DEBUG Fprintf(stderr, "%ld: %s", ftell(stdout), in_line); #endif (void) fputs(xcrypt(in_line), ofp); } Fclose(ifp); Fclose(ofp); return; } static char temp[32]; static char * limit(name,pref) /* limit a name to 30 characters length */ char *name; int pref; { (void) strncpy(temp, name, pref ? 26 : 30); temp[pref ? 26 : 30] = 0; return temp; } void do_objs() { int i, sum = 0; char *c, *objnam; int nspell = 0; int prefix = 0; char class = '\0'; boolean sumerr = FALSE; filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(eos(filename), INCLUDE_TEMPLATE, ONAME_FILE); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,"/*\tSCCS Id: @(#)onames.h\t3.4\t2002/02/03 */\n\n"); Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#ifndef ONAMES_H\n#define ONAMES_H\n\n"); for(i = 0; !i || objects[i].oc_class != ILLOBJ_CLASS; i++) { SpinCursor(3); objects[i].oc_name_idx = objects[i].oc_descr_idx = i; /* init */ if (!(objnam = tmpdup(OBJ_NAME(objects[i])))) continue; /* make sure probabilities add up to 1000 */ if(objects[i].oc_class != class) { if (sum && sum != 1000) { Fprintf(stderr, "prob error for class %d (%d%%)", class, sum); (void) fflush(stderr); sumerr = TRUE; } class = objects[i].oc_class; sum = 0; } for (c = objnam; *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; switch (class) { case WAND_CLASS: Fprintf(ofp,"#define\tWAN_"); prefix = 1; break; case RING_CLASS: Fprintf(ofp,"#define\tRIN_"); prefix = 1; break; case POTION_CLASS: Fprintf(ofp,"#define\tPOT_"); prefix = 1; break; case SPBOOK_CLASS: Fprintf(ofp,"#define\tSPE_"); prefix = 1; nspell++; break; case SCROLL_CLASS: Fprintf(ofp,"#define\tSCR_"); prefix = 1; break; case AMULET_CLASS: /* avoid trouble with stupid C preprocessors */ Fprintf(ofp,"#define\t"); if(objects[i].oc_material == PLASTIC) { Fprintf(ofp,"FAKE_AMULET_OF_YENDOR\t%d\n", i); prefix = -1; break; } break; case GEM_CLASS: /* avoid trouble with stupid C preprocessors */ if(objects[i].oc_material == GLASS) { Fprintf(ofp,"/* #define\t%s\t%d */\n", objnam, i); prefix = -1; break; } default: Fprintf(ofp,"#define\t"); } if (prefix >= 0) Fprintf(ofp,"%s\t%d\n", limit(objnam, prefix), i); prefix = 0; sum += objects[i].oc_prob; } /* check last set of probabilities */ if (sum && sum != 1000) { Fprintf(stderr, "prob error for class %d (%d%%)", class, sum); (void) fflush(stderr); sumerr = TRUE; } Fprintf(ofp,"#define\tLAST_GEM\t(JADE)\n"); Fprintf(ofp,"#define\tMAXSPELL\t%d\n", nspell+1); Fprintf(ofp,"#define\tNUM_OBJECTS\t%d\n", i); Fprintf(ofp, "\n/* Artifacts (unique objects) */\n\n"); for (i = 1; artifact_names[i]; i++) { SpinCursor(3); for (c = objnam = tmpdup(artifact_names[i]); *c; c++) if (*c >= 'a' && *c <= 'z') *c -= (char)('a' - 'A'); else if (*c < 'A' || *c > 'Z') *c = '_'; if (!strncmp(objnam, "THE_", 4)) objnam += 4; #ifdef TOURIST /* fudge _platinum_ YENDORIAN EXPRESS CARD */ if (!strncmp(objnam, "PLATINUM_", 9)) objnam += 9; #endif Fprintf(ofp,"#define\tART_%s\t%d\n", limit(objnam, 1), i); } Fprintf(ofp, "#define\tNROFARTIFACTS\t%d\n", i-1); Fprintf(ofp,"\n#endif /* ONAMES_H */\n"); Fclose(ofp); if (sumerr) exit(EXIT_FAILURE); return; } static char * tmpdup(str) const char *str; { static char buf[128]; if (!str) return (char *)0; (void)strncpy(buf, str, 127); return buf; } static char * eos(str) char *str; { while (*str) str++; return str; } /* * macro used to control vision algorithms: * VISION_TABLES => generate tables */ void do_vision() { #ifdef VISION_TABLES int i, j; /* Everything is clear. xclear may be malloc'ed. * Block the upper left corner (BLOCK_HEIGHTxBLOCK_WIDTH) */ for (i = 0; i < MAX_ROW; i++) for (j = 0; j < MAX_COL; j++) if (i < BLOCK_HEIGHT && j < BLOCK_WIDTH) xclear[i][j] = '\000'; else xclear[i][j] = '\001'; #endif /* VISION_TABLES */ SpinCursor(3); /* * create the include file, "vis_tab.h" */ filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#ifdef VISION_TABLES\n"); #ifdef VISION_TABLES H_close_gen(); H_far_gen(); #endif /* VISION_TABLES */ Fprintf(ofp,"\n#endif /* VISION_TABLES */\n"); Fclose(ofp); SpinCursor(3); /* * create the source file, "vis_tab.c" */ filename[0]='\0'; #ifdef FILE_PREFIX Strcat(filename, file_prefix); #endif Sprintf(filename, SOURCE_TEMPLATE, VIS_TAB_C); if (!(ofp = fopen(filename, WRTMODE))) { perror(filename); Sprintf(filename, INCLUDE_TEMPLATE, VIS_TAB_H); Unlink(filename); exit(EXIT_FAILURE); } Fprintf(ofp,Dont_Edit_Code); Fprintf(ofp,"#include \"config.h\"\n"); Fprintf(ofp,"#ifdef VISION_TABLES\n"); Fprintf(ofp,"#include \"vis_tab.h\"\n"); SpinCursor(3); #ifdef VISION_TABLES C_close_gen(); C_far_gen(); Fprintf(ofp,"\nvoid vis_tab_init() { return; }\n"); #endif /* VISION_TABLES */ SpinCursor(3); Fprintf(ofp,"\n#endif /* VISION_TABLES */\n"); Fprintf(ofp,"\n/*vis_tab.c*/\n"); Fclose(ofp); return; } #ifdef VISION_TABLES /*-------------- vision tables --------------*\ * * Generate the close and far tables. This is done by setting up a * fake dungeon and moving our source to different positions relative * to a block and finding the first/last visible position. The fake * dungeon is all clear execpt for the upper left corner (BLOCK_HEIGHT * by BLOCK_WIDTH) is blocked. Then we move the source around relative * to the corner of the block. For each new position of the source * we check positions on rows "kittycorner" from the source. We check * positions until they are either in sight or out of sight (depends on * which table we are generating). The picture below shows the setup * for the generation of the close table. The generation of the far * table would switch the quadrants of the '@' and the "Check rows * here". * * * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,, Check rows here ,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXB,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, * ............................... * ............................... * .........@..................... * ............................... * * Table generation figure (close_table). The 'X's are blocked points. * The 'B' is a special blocked point. The '@' is the source. The ','s * are the target area. The '.' are just open areas. * * * Example usage of close_table[][][]. * * The table is as follows: * * dy = |row of '@' - row of 'B'| - 1 * dx = |col of '@' - col of 'B'| * * The first indices are the deltas from the source '@' and the block 'B'. * You must check for the value inside the abs value bars being zero. If * so then the block is on the same row and you don't need to do a table * lookup. The last value: * * dcy = |row of block - row to be checked| * * Is the value of the first visible spot on the check row from the * block column. So * * first visible col = close_table[dy][dx][dcy] + col of 'B' * \*-------------- vision tables --------------*/ static void H_close_gen() { Fprintf(ofp,"\n/* Close */\n"); Fprintf(ofp,"#define CLOSE_MAX_SB_DY %2d\t/* |src row - block row| - 1\t*/\n", TEST_HEIGHT-1); Fprintf(ofp,"#define CLOSE_MAX_SB_DX %2d\t/* |src col - block col|\t*/\n", TEST_WIDTH); Fprintf(ofp,"#define CLOSE_MAX_BC_DY %2d\t/* |block row - check row|\t*/\n", TEST_HEIGHT); Fprintf(ofp,"typedef struct {\n"); Fprintf(ofp," unsigned char close[CLOSE_MAX_SB_DX][CLOSE_MAX_BC_DY];\n"); Fprintf(ofp,"} close2d;\n"); Fprintf(ofp,"extern close2d close_table[CLOSE_MAX_SB_DY];\n"); return; } static void H_far_gen() { Fprintf(ofp,"\n/* Far */\n"); Fprintf(ofp,"#define FAR_MAX_SB_DY %2d\t/* |src row - block row|\t*/\n", TEST_HEIGHT); Fprintf(ofp,"#define FAR_MAX_SB_DX %2d\t/* |src col - block col| - 1\t*/\n", TEST_WIDTH-1); Fprintf(ofp,"#define FAR_MAX_BC_DY %2d\t/* |block row - check row| - 1\t*/\n", TEST_HEIGHT-1); Fprintf(ofp,"typedef struct {\n"); Fprintf(ofp," unsigned char far_q[FAR_MAX_SB_DX][FAR_MAX_BC_DY];\n"); Fprintf(ofp,"} far2d;\n"); Fprintf(ofp,"extern far2d far_table[FAR_MAX_SB_DY];\n"); return; } static void C_close_gen() { int i,dx,dy; int src_row, src_col; /* source */ int block_row, block_col; /* block */ int this_row; int no_more; const char *delim; block_row = BLOCK_HEIGHT-1; block_col = BLOCK_WIDTH-1; Fprintf(ofp,"\n#ifndef FAR_TABLE_ONLY\n"); Fprintf(ofp,"\nclose2d close_table[CLOSE_MAX_SB_DY] = {\n"); #ifndef no_vision_progress Fprintf(stderr,"\nclose:"); #endif for (dy = 1; dy < TEST_HEIGHT; dy++) { src_row = block_row + dy; Fprintf(ofp, "/* DY = %2d (- 1)*/\n {{\n", dy); #ifndef no_vision_progress Fprintf(stderr," %2d",dy), (void)fflush(stderr); #endif for (dx = 0; dx < TEST_WIDTH; dx++) { src_col = block_col - dx; Fprintf(ofp, " /*%2d*/ {", dx); no_more = 0; for (this_row = 0; this_row < TEST_HEIGHT; this_row++) { delim = (this_row < TEST_HEIGHT - 1) ? "," : ""; if (no_more) { Fprintf(ofp, "%s%s", CLOSE_OFF_TABLE_STRING, delim); continue; } SpinCursor(3); /* Find the first column that we can see. */ for (i = block_col+1; i < MAX_COL; i++) { if (clear_path(src_row,src_col,block_row-this_row,i)) break; } if (i == MAX_COL) no_more = 1; Fprintf(ofp, "%2d%s", i - block_col, delim); } Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n"); } Fprintf(ofp," }},\n"); } Fprintf(ofp,"}; /* close_table[] */\n"); /* closing brace for table */ Fprintf(ofp,"#endif /* !FAR_TABLE_ONLY */\n"); #ifndef no_vision_progress Fprintf(stderr,"\n"); #endif return; } static void C_far_gen() { int i,dx,dy; int src_row, src_col; /* source */ int block_row, block_col; /* block */ int this_row; const char *delim; block_row = BLOCK_HEIGHT-1; block_col = BLOCK_WIDTH-1; Fprintf(ofp,"\n#ifndef CLOSE_TABLE_ONLY\n"); Fprintf(ofp,"\nfar2d far_table[FAR_MAX_SB_DY] = {\n"); #ifndef no_vision_progress Fprintf(stderr,"\n_far_:"); #endif for (dy = 0; dy < TEST_HEIGHT; dy++) { src_row = block_row - dy; Fprintf(ofp, "/* DY = %2d */\n {{\n", dy); #ifndef no_vision_progress Fprintf(stderr," %2d",dy), (void)fflush(stderr); #endif for (dx = 1; dx < TEST_WIDTH; dx++) { src_col = block_col + dx; Fprintf(ofp, " /*%2d(-1)*/ {", dx); for (this_row = block_row+1; this_row < block_row+TEST_HEIGHT; this_row++) { delim = (this_row < block_row + TEST_HEIGHT - 1) ? "," : ""; SpinCursor(3); /* Find first col that we can see. */ for (i = 0; i <= block_col; i++) { if (clear_path(src_row,src_col,this_row,i)) break; } if (block_col-i < 0) Fprintf(ofp, "%s%s", FAR_OFF_TABLE_STRING, delim); else Fprintf(ofp, "%2d%s", block_col - i, delim); } Fprintf(ofp, "}%s", (dx < TEST_WIDTH - 1) ? ",\n" : "\n"); } Fprintf(ofp," }},\n"); } Fprintf(ofp,"}; /* far_table[] */\n"); /* closing brace for table */ Fprintf(ofp,"#endif /* !CLOSE_TABLE_ONLY */\n"); #ifndef no_vision_progress Fprintf(stderr,"\n"); #endif return; } /* * "Draw" a line from the hero to the given location. Stop if we hit a * wall. * * Generalized integer Bresenham's algorithm (fast line drawing) for * all quadrants. From _Procedural Elements for Computer Graphics_, by * David F. Rogers. McGraw-Hill, 1985. * * I have tried a little bit of optimization by pulling compares out of * the inner loops. * * NOTE: This had better *not* be called from a position on the * same row as the hero. */ static int clear_path(you_row,you_col,y2,x2) int you_row, you_col, y2, x2; { int dx, dy, s1, s2; register int i, error, x, y, dxs, dys; x = you_col; y = you_row; dx = abs(x2-you_col); dy = abs(y2-you_row); s1 = sign(x2-you_col); s2 = sign(y2-you_row); if (s1 == 0) { /* same column */ if (s2 == 1) { /* below (larger y2 value) */ for (i = you_row+1; i < y2; i++) if (!xclear[i][you_col]) return 0; } else { /* above (smaller y2 value) */ for (i = y2+1; i < you_row; i++) if (!xclear[i][you_col]) return 0; } return 1; } /* * Lines at 0 and 90 degrees have been weeded out. */ if (dy > dx) { error = dx; dx = dy; dy = error; /* swap the values */ dxs = dx << 1; /* save the shifted values */ dys = dy << 1; error = dys - dx; /* NOTE: error is used as a temporary above */ for (i = 0; i < dx; i++) { if (!xclear[y][x]) return 0; /* plot point */ while (error >= 0) { x += s1; error -= dxs; } y += s2; error += dys; } } else { dxs = dx << 1; /* save the shifted values */ dys = dy << 1; error = dys - dx; for (i = 0; i < dx; i++) { if (!xclear[y][x]) return 0; /* plot point */ while (error >= 0) { y += s2; error -= dxs; } x += s1; error += dys; } } return 1; } #endif /* VISION_TABLES */ #ifdef STRICT_REF_DEF NEARDATA struct flag flags; # ifdef ATTRIB_H struct attribs attrmax, attrmin; # endif #endif /* STRICT_REF_DEF */ /*makedefs.c*/ nethack-3.4.3/util/panic.c0100644000000000000000000000237407764735041014073 0ustar rootroot/* SCCS Id: @(#)panic.c 3.4 1994/03/02 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ /* * This code was adapted from the code in end.c to run in a standalone * mode for the makedefs / drg code. */ #define NEED_VARARGS #include "config.h" #ifdef AZTEC #define abort() exit() #endif #ifdef VMS extern void NDECL(vms_abort); #endif /*VARARGS1*/ boolean panicking; void VDECL(panic, (char *,...)); void panic VA_DECL(char *,str) VA_START(str); VA_INIT(str, char *); if(panicking++) #ifdef SYSV (void) #endif abort(); /* avoid loops - this should never happen*/ (void) fputs(" ERROR: ", stderr); Vfprintf(stderr, str, VA_ARGS); (void) fflush(stderr); #if defined(UNIX) || defined(VMS) # ifdef SYSV (void) # endif abort(); /* generate core dump */ #endif VA_END(); exit(EXIT_FAILURE); /* redundant */ return; } #ifdef ALLOCA_HACK /* * In case bison-generated foo_yacc.c tries to use alloca(); if we don't * have it then just use malloc() instead. This may not work on some * systems, but they should either use yacc or get a real alloca routine. */ long *alloca(cnt) unsigned cnt; { return cnt ? alloc(cnt) : (long *)0; } #endif /*panic.c*/ nethack-3.4.3/util/recover.c0100644000000000000000000002072607764735041014447 0ustar rootroot/* SCCS Id: @(#)recover.c 3.4 1999/10/23 */ /* Copyright (c) Janet Walz, 1992. */ /* NetHack may be freely redistributed. See license for details. */ /* * Utility for reconstructing NetHack save file from a set of individual * level files. Requires that the `checkpoint' option be enabled at the * time NetHack creates those level files. */ #include "config.h" #if !defined(O_WRONLY) && !defined(LSC) && !defined(AZTEC_C) #include #endif #ifdef WIN32 #include #include "win32api.h" #endif #ifdef VMS extern int FDECL(vms_creat, (const char *,unsigned)); extern int FDECL(vms_open, (const char *,int,unsigned)); #endif /* VMS */ int FDECL(restore_savefile, (char *)); void FDECL(set_levelfile_name, (int)); int FDECL(open_levelfile, (int)); int NDECL(create_savefile); void FDECL(copy_bytes, (int,int)); #ifndef WIN_CE #define Fprintf (void)fprintf #else #define Fprintf (void)nhce_message static void nhce_message(FILE*, const char*, ...); #endif #define Close (void)close #ifdef UNIX #define SAVESIZE (PL_NSIZ + 13) /* save/99999player.e */ #else # ifdef VMS #define SAVESIZE (PL_NSIZ + 22) /* [.save]player.e;1 */ # else # ifdef WIN32 #define SAVESIZE (PL_NSIZ + 40) /* username-player.NetHack-saved-game */ # else #define SAVESIZE FILENAME /* from macconf.h or pcconf.h */ # endif # endif #endif #if defined(EXEPATH) char *FDECL(exepath, (char *)); #endif #if defined(__BORLANDC__) && !defined(_WIN32) extern unsigned _stklen = STKSIZ; #endif char savename[SAVESIZE]; /* holds relative path of save file from playground */ int main(argc, argv) int argc; char *argv[]; { int argno; const char *dir = (char *)0; #ifdef AMIGA char *startdir = (char *)0; #endif if (!dir) dir = getenv("NETHACKDIR"); if (!dir) dir = getenv("HACKDIR"); #if defined(EXEPATH) if (!dir) dir = exepath(argv[0]); #endif if (argc == 1 || (argc == 2 && !strcmp(argv[1], "-"))) { Fprintf(stderr, "Usage: %s [ -d directory ] base1 [ base2 ... ]\n", argv[0]); #if defined(WIN32) || defined(MSDOS) if (dir) { Fprintf(stderr, "\t(Unless you override it with -d, recover will look \n"); Fprintf(stderr, "\t in the %s directory on your system)\n", dir); } #endif exit(EXIT_FAILURE); } argno = 1; if (!strncmp(argv[argno], "-d", 2)) { dir = argv[argno]+2; if (*dir == '=' || *dir == ':') dir++; if (!*dir && argc > argno) { argno++; dir = argv[argno]; } if (!*dir) { Fprintf(stderr, "%s: flag -d must be followed by a directory name.\n", argv[0]); exit(EXIT_FAILURE); } argno++; } #if defined(SECURE) && !defined(VMS) if (dir # ifdef HACKDIR && strcmp(dir, HACKDIR) # endif ) { (void) setgid(getgid()); (void) setuid(getuid()); } #endif /* SECURE && !VMS */ #ifdef HACKDIR if (!dir) dir = HACKDIR; #endif #ifdef AMIGA startdir = getcwd(0,255); #endif if (dir && chdir((char *) dir) < 0) { Fprintf(stderr, "%s: cannot chdir to %s.\n", argv[0], dir); exit(EXIT_FAILURE); } while (argc > argno) { if (restore_savefile(argv[argno]) == 0) Fprintf(stderr, "recovered \"%s\" to %s\n", argv[argno], savename); argno++; } #ifdef AMIGA if (startdir) (void)chdir(startdir); #endif exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } static char lock[256]; void set_levelfile_name(lev) int lev; { char *tf; tf = rindex(lock, '.'); if (!tf) tf = lock + strlen(lock); (void) sprintf(tf, ".%d", lev); #ifdef VMS (void) strcat(tf, ";1"); #endif } int open_levelfile(lev) int lev; { int fd; set_levelfile_name(lev); #if defined(MICRO) || defined(WIN32) || defined(MSDOS) fd = open(lock, O_RDONLY | O_BINARY); #else fd = open(lock, O_RDONLY, 0); #endif return fd; } int create_savefile() { int fd; #if defined(MICRO) || defined(WIN32) || defined(MSDOS) fd = open(savename, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, FCMASK); #else fd = creat(savename, FCMASK); #endif return fd; } void copy_bytes(ifd, ofd) int ifd, ofd; { char buf[BUFSIZ]; int nfrom, nto; do { nfrom = read(ifd, buf, BUFSIZ); nto = write(ofd, buf, nfrom); if (nto != nfrom) { Fprintf(stderr, "file copy failed!\n"); exit(EXIT_FAILURE); } } while (nfrom == BUFSIZ); } int restore_savefile(basename) char *basename; { int gfd, lfd, sfd; int lev, savelev, hpid; xchar levc; struct version_info version_data; /* level 0 file contains: * pid of creating process (ignored here) * level number for current level of save file * name of save file nethack would have created * and game state */ (void) strcpy(lock, basename); gfd = open_levelfile(0); if (gfd < 0) { #if defined(WIN32) && !defined(WIN_CE) if(errno == EACCES) { Fprintf(stderr, "\nThere are files from a game in progress under your name."); Fprintf(stderr,"\nThe files are locked or inaccessible."); Fprintf(stderr,"\nPerhaps the other game is still running?\n"); } else Fprintf(stderr, "\nTrouble accessing level 0 (errno = %d).\n", errno); #endif Fprintf(stderr, "Cannot open level 0 for %s.\n", basename); return(-1); } if (read(gfd, (genericptr_t) &hpid, sizeof hpid) != sizeof hpid) { Fprintf(stderr, "%s\n%s%s%s\n", "Checkpoint data incompletely written or subsequently clobbered;", "recovery for \"", basename, "\" impossible."); Close(gfd); return(-1); } if (read(gfd, (genericptr_t) &savelev, sizeof(savelev)) != sizeof(savelev)) { Fprintf(stderr, "Checkpointing was not in effect for %s -- recovery impossible.\n", basename); Close(gfd); return(-1); } if ((read(gfd, (genericptr_t) savename, sizeof savename) != sizeof savename) || (read(gfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data)) { Fprintf(stderr, "Error reading %s -- can't recover.\n", lock); Close(gfd); return(-1); } /* save file should contain: * version info * current level (including pets) * (non-level-based) game state * other levels */ sfd = create_savefile(); if (sfd < 0) { Fprintf(stderr, "Cannot create savefile %s.\n", savename); Close(gfd); return(-1); } lfd = open_levelfile(savelev); if (lfd < 0) { Fprintf(stderr, "Cannot open level of save for %s.\n", basename); Close(gfd); Close(sfd); return(-1); } if (write(sfd, (genericptr_t) &version_data, sizeof version_data) != sizeof version_data) { Fprintf(stderr, "Error writing %s; recovery failed.\n", savename); Close(gfd); Close(sfd); return(-1); } copy_bytes(lfd, sfd); Close(lfd); (void) unlink(lock); copy_bytes(gfd, sfd); Close(gfd); set_levelfile_name(0); (void) unlink(lock); for (lev = 1; lev < 256; lev++) { /* level numbers are kept in xchars in save.c, so the * maximum level number (for the endlevel) must be < 256 */ if (lev != savelev) { lfd = open_levelfile(lev); if (lfd >= 0) { /* any or all of these may not exist */ levc = (xchar) lev; write(sfd, (genericptr_t) &levc, sizeof(levc)); copy_bytes(lfd, sfd); Close(lfd); (void) unlink(lock); } } } Close(sfd); #if 0 /* OBSOLETE, HackWB is no longer in use */ #ifdef AMIGA /* we need to create an icon for the saved game * or HackWB won't notice the file. */ { char iconfile[FILENAME]; int in, out; (void) sprintf(iconfile, "%s.info", savename); in = open("NetHack:default.icon", O_RDONLY); out = open(iconfile, O_WRONLY | O_TRUNC | O_CREAT); if(in > -1 && out > -1){ copy_bytes(in,out); } if(in > -1)close(in); if(out > -1)close(out); } #endif #endif return(0); } #ifdef EXEPATH # ifdef __DJGPP__ #define PATH_SEPARATOR '/' # else #define PATH_SEPARATOR '\\' # endif #define EXEPATHBUFSZ 256 char exepathbuf[EXEPATHBUFSZ]; char *exepath(str) char *str; { char *tmp, *tmp2; int bsize; if (!str) return (char *)0; bsize = EXEPATHBUFSZ; tmp = exepathbuf; #if !defined(WIN32) strcpy (tmp, str); #else # if defined(WIN_CE) { TCHAR wbuf[EXEPATHBUFSZ]; GetModuleFileName((HANDLE)0, wbuf, EXEPATHBUFSZ); NH_W2A(wbuf, tmp, bsize); } # else *(tmp + GetModuleFileName((HANDLE)0, tmp, bsize)) = '\0'; # endif #endif tmp2 = strrchr(tmp, PATH_SEPARATOR); if (tmp2) *tmp2 = '\0'; return tmp; } #endif /* EXEPATH */ #ifdef AMIGA #include "date.h" const char amiga_version_string[] = AMIGA_VERSION_STRING; #endif #ifdef WIN_CE void nhce_message(FILE* f, const char* str, ...) { va_list ap; TCHAR wbuf[NHSTR_BUFSIZE]; char buf[NHSTR_BUFSIZE]; va_start(ap, str); vsprintf(buf, str, ap); va_end(ap); MessageBox(NULL, NH_A2W(buf, wbuf, NHSTR_BUFSIZE), TEXT("Recover"), MB_OK); } #endif /*recover.c*/ nethack-3.4.3/win/0040755000000000000000000000000007764735105012453 5ustar rootrootnethack-3.4.3/win/Qt/0040755000000000000000000000000007764735105013037 5ustar rootrootnethack-3.4.3/win/Qt/Info.plist0100644000000000000000000000124007764735041015000 0ustar rootroot CFBundleGetInfoHTML http://www.nethack.org CFBundleGetInfoString Copyright (C) 1985-2003 Stichting Mathematisch Centrum CFBundleIconFile nethack.icns CFBundleIdentifier org.nethack.qt CFBundlePackageType APPL CFBundleShortVersionString 3.4.3 CFBundleSignature NHak nethack-3.4.3/win/Qt/Install.Qt0100644000000000000000000000651307764735041014754 0ustar rootrootInstalling NetHack with a Qt or KDE interface --------------------------------------------- This document describes the installation of NetHack with a Qt interface on UNIX/X11 or Mac OS X. This code should also work with Qt/Windows, but support for that is not currently official. You can download Qt for UNIX and Qt for Windows from http://www.trolltech.com. Qt for Mac OS X is currently only available commercially. You need Qt 2.0 or later to use this code. To use this code: 1. follow the directions for the UNIX installation (in ../../sys/unix) to create the Makefiles. 2. ../../include/config.h define QT_GRAPHICS (search for it). You can comment out TTY_GRAPHICS if you want to, or leave it in to support both interfaces (in which case be sure you have the right curses libraries etc. required for that interface). 3. ../../src/Makefile ensure your QTDIR environment variable was set correctly when you installed Qt - $QTDIR/include/qwidget.h should exist, for example. ensure CXX and LD are set to the compiler and linker you need for compiling and linking C++ software (e.g., set both to g++). add $(WINQTSRC), $(WINQTOBJ), and $(WINQTLIB) to WINSRC, WINOBJ, and WINLIB respectively, and compile. This will give you an executable supporting both Qt and tty windowing. 4. ../../Makefile (the top-level makefile) change the VARDATND setting to contain the files "x11tiles", "rip.xpm", and "nhsplash.xpm": VARDATND = x11tiles rip.xpm nhsplash.xpm 5. Follow all the instructions in ../../sys/unix/Install.unx for the remainder of the installation process. 6. Consider adding the lines below to your .nethackrc, as they are likely to give the best interface for this window port: OPTIONS=name:player,number_pad,menustyle:partial,!time,showexp OPTIONS=hilite_pet,toptenwin,msghistory:200,windowtype:Qt If you are using KDE, you may want to also try the KDE version. It just uses the KDE menubar and follows other KDE conventions - there is no extra functionality. To do so: 1. Ensure that you have KDE 2.x libraries on your system (in 1999 KDE 1.x was the norm) 2. ../../src/Makefile Add $(KDECXXFLAGS) to the CXXFLAGS definition, $(KDELFLAGS) to the LFLAGS definition and $(WINKDELIB) to WINLIB. 3. Some additional files here - knh-mini.xpm, knh.xpm, and knethack.lnk are useful if you want to install "knethack" in the KDE games directory. If you are using Qtopia, you can compile NetHack for that environment with the following additional steps: 1. First be sure that you can build a simple Qtopia application, such as the examples that ship with Qtopia. Do not attempt something as challenging to compile as NetHack before you can already build a Qtopia application for your target device. 2. If you are cross-compiling (eg. targetting an ARM-based handheld), be sure to follow the steps for cross-compiling in the Makefile.src and Makefile.utl files. 3. To CXXFLAGS in Makefile.src, add: -DQWS -I$(QPEDIR)/include -fno-rtti -fno-exceptions 4. Rather than -lqt in WINQTLIB, have: -L$(QPEDIR)/lib -lqpe -lqte 5. After building, use the "mkipks" program that ships with Qtopia to package the result into an ipk file. nethack-3.4.3/win/Qt/knethack.lnk0100644000000000000000000000067107764735041015335 0ustar rootroot# KDE Config File # Call this file knethack.kdelnk or knethack.desktop [KDE Desktop Entry] Name=Nethack Name[fr]=Nethack Name[hu]=Nethack Name[no]=Nethack Name[sk]=Nethack Name[cs]=Nethack Name[hr]=Nethack Name[pt]=Nethack Name[pt_BR]=Nethack Icon=knh.xpm Exec=knethack -caption "%c" %i %m Type=Application DocPath=knethack/index.html Comment=The classic Unix role-playing game - fight monsters and seek the Amulet of Yendor for your god! nethack-3.4.3/win/Qt/knh-mini.xpm0100644000000000000000000000103607764735041015273 0ustar rootroot/* XPM */ static char *noname[] = { /* width height ncolors chars_per_pixel */ "16 16 7 1", /* colors */ " c #000000", ". c #DCDCDC", "X c #008080", "o c #A0A0A0", "O c None", "+ c #FFFFFF", "@ c #C3C3C3", /* pixels */ "OOOOOOOOOOOOOOOO", "OOO+O+++@@@O@OOO", "O+O+++++@@@@@O.O", "O+o+XXXXX X @ . ", "O+o+XXXX X X@ . ", "OO +XXXXX X @ O ", "OOO+XXXX X X@ OO", "OOO+XXXXX X @ OO", "OOO+XXXX X X@ OO", "OOOO+XXXX X@ OO", "OOOO+XXX X . OO", "OOO+O+XXX . . OO", "OO+++ +X . ... O", "O+++. O+. .... ", "OO+. OOOOOO.. O", "OOOOOOOOOOOOOOOO" }; nethack-3.4.3/win/Qt/knh.xpm0100644000000000000000000000420207764735041014337 0ustar rootroot/* XPM */ static char *noname[] = { /* width height ncolors chars_per_pixel */ "40 40 20 1", /* colors */ " c #000000", ". c #0000C0", "X c #FFC0FF", "o c #FFC0C0", "O c #DCDCDC", "+ c #C0C0FF", "@ c #008080", "# c #A0A0A0", "$ c None", "% c #000080", "& c #585858", "* c #800080", "= c #FFFFFF", "- c #FFFFC0", "; c #00C0C0", ": c #C0FFFF", "> c #C0FFC0", ", c #C3C3C3", "< c #FFDCA8", "1 c #0000FF", /* pixels */ "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$=$$$$$$=,==<,=<,$$$$$$,$$$$$$$$$", "$$$$$$$$==$$$=====,=<>,<><$$$<>$$$$$$$$$", "$$$$$$$$===$====,==>,=<,<,,$,,<$$$$$$$$$", "$$$==$$$==========<=<,><,><<><,$$$,<$$$$", "$$$====$========,==,,=<>,<,>,<,$<><,$$$$", "$$$====$==========<=<,,<<><,<><$,,<>$$$$", "$$$$#&&&==$#$#$#@#$&@#&&@&&&&,, && $$", "$$$;#@&@==;#;#;#$;&#@&@$&@&@$>< &@ $$", "$$$====&==###1##.##@&#&@&&$&&<, <>O< $$", "$$$====&==$;##;##;&#@&@$&@&@&>, O<,> $$", "$$$==&@&==#1#;##.##@&#&@&$@$&,< ,< $$", "$$$$ ==###1#;##.#@$&&&@&&@-, $ $$", "$$$$$ =X;#;###&;#&@#&@$&@$&,< $$ $$$", "$$$$$$ ==#$+@+1##@#&@&$@&&&@<> $$$$$$", "$$$$$$$$=X;#1#$#@##@&#@&&&@$&<, $$$$$$", "$$$$$$$$==##;#;##1$#@&$@$&&@&>< $$$$$$", "$$$$$$$$=X;###1#@##@&#@&&@$&&O, $$$$$$", "$$$$$$$$==#1#;##;#.#@&&$@&@&@<> $$$$$$", "$$$$$$$$$==###;#*;#&@#&@&&$&O< $$$$$$$", "$$$$$$$$$==;#1,$;#&#@$@&$@&@<, $$$$$$$", "$$$$$$$$$$=X####.##@&#&&@&& ><, $$$$$$", "$$$$$$====@&=O##@#;&@#&&,< <,>< $$$$$", "$$$$$===#$== ==$1#&#&@&O> ,<$#,,> $$$$", "$$$$===#;#== ==$#;&@#O, >,#;&<,< $$$$", "$$$==$#;*@O< ====Oo,> <,&$#@&O, $$$", "$$$==;$#&&<, $===<,< < $$", "$$$==##;&O>, $$==,> $$ ,<&&#$@o, $$", "$$$===X=O,< $$$$$$$$$$$$$>OO,Oo> $$$", "$$$$====,< $$$$$$$$$$$$$$,<,>,<, $$$$", "$$$$$===<> $$$$$$$$$$$$$$$$><,<> $$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" }; nethack-3.4.3/win/Qt/nhicns.uu0100644000000000000000000020617307764735041014701 0ustar rootrootbegin 640 nethack.icns M:6-N2`Q@J)8&,C9"%T(S\SO(+&"I1U5GU$0G?,X7MN@<8,PHAF6'^#<[QQ MAGV\RH#]O6L;&?(7'HHZA>IGJ@,80BYS#/&F3HGUOQI?&@W3&QH6!Q@E< MIW'&QES&QJ*5A,8$X6K&QJF'Q@6/QD3&QNR'Q@!A@<8`@)'&H,8`=H'&`@\5 M?87&"+:'[L:%;X"46H3&"<@-O(T^9W*9K<6`Q@W:KS'&PS.!&2M[-[+%XH#& M"A<311$U*!X1#!^G@L8*"RP0%@L1%@L9"Q:!Q@RO%A0?&A@-#F11'`T*@,8- M'2D-QL8<%0HC%1HC$0J`QA!^9KT1$@X-'33&-<8Q#L;&;('&"5(-(<;&)L;& MAWB$Q@0*.\;&-8?&!5W&1,;&"8?&`#.!Q@!AD<:@Q@!N@<8"#A5CA<8(M*+> MQGM_FJ=5A,8)QPS'H39E@:6\S(#&#=:D+L;#?8X8*G\VO,K@@,8*%A-!$$%# M'1`-'J."Q@H+'Q`6"PX5"A,*%8'&#*L6$QD:&`T-1S8:#`J`Q@T8(0W&QAP4 M"AH3%2$1"H#&$']BO0X1#@T;+L8UQB\-QL9F@<8)/0T?QL8=QL:#=(3&!`HM MQL8AA\8%4\9"QL8)A\8`*H'&`$*1QG,X;6L```$(____________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M_____________________TE#3B,```$(```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````&EL,S(```;C@<8`R9S&`*F]Q@#%G<8`O(;&`]+JXKR0Q@*] MQ]:"Q@;LCVEW>7?#CL8$SH)_>[2`Q@B!9G^9F:BI<,R,QA&]G)B84,;'QH]Z MAI"0G:^RH,N,QA'AF-[-'B!;;V%WD*":K*R^QZN+QA*D=]OYG:7*97)R>Y.D MI[+&R=.KA\8`NX#&$N^;P[2ZPF)G MKD@8Q;%A:F-E.9"4N+_'UN+&OX+&%2&^V4XH(I'&_D2*/SI)*RDA*$"2CL*' MQA6\BY1U5%AC>$GN+4I624-(7%XV6Z;/A\85K:[.'EMP9XF2;X)^9U9SBYF^ MGJI+S(?&%[.1R#5A6'R*?"_/=V]/MKG(OYR^Q']KQX3&&,BXFWUB86-NBH2- M6JAN4=7R,D;W`?=^!QAMOK^]2@<8;QR$0%<;KF4?&6%MRS,2'E7AV:5EH;,;&Q8*U MVH+&`I$71(#&#T@_3&5EI-A[?(YF4]'&4L&`Q@*-I9:!Q@*U(:6!Q@Y1S,9M M@\!I<65AUL;&;WZ!Q@*>BF&!Q@#)A<8&YV^;:,!'=(#&`7N,@L8"RV'3B\8# M=I/&88'&`4VMD\8#PW?&:('&`7>1DL8$P&O&QE>!Q@&BGY+&`,F$Q@*_'F*$PQ8S&$1)QAXH^QL?& M."UW@(>3I:>!#\@,"T@.#@I[,0H)&A^%QA@7"A(<$`T.%A@9 M'"*'#!A1(3(F%P\*##@?A,89#`D9$!=&-$`>'!L?%Q41$VT:$PH6&@L,%"6# MQAL/"AH++\;&O"(`6E8#&""1?@**BL*THQ8S&$1!DH:`]QL?&+R.& MF8^AN+F#;HS&$0DHU==6);X45R69IYNQK\#)(8O&$BT>K^RDJLD=&7$K<:NK MM<;)TB^'Q@"B@,82"9?`E;V]&F%R@']!K[N_R=;=$H'&',5`.AO&%,?)QD48 M,!ZPHAAA2ETECV.\O\G5W,:,@L85$`D)#1@1=<;VSR4;$0\3$A`2-9!'PH?& M%0D0$1@8&R`/%<\/$PL4"PL,#1(@D;'10)#`D+"Q,6 M#1>^A\86"A5`%@P*#A8<#K<+"S@.#@IB(@H)&1Z%QA@2"A(;#PP.%1@9&1>! M"Q@^'"4@%P\*"R,8A,89#`D8#Q8\+34>&Q@7%A$0$DL9$@H6%PL*$2"#QAL/ M"AD++L;&N2`?%AH9"0T0'QD4&R$A%Q\/1B/9@<8;*R(="\;&Q,;&$!H3#0D/ M%2\3&QP9(B\<$QX)%X'&&\(1#@[&XB$BQ@P9&PD)&!,C-#PW%PS&QK,9#PF" MQ@*0$!:`Q@\V'`H\/0D)$!L7,2O/Q@J!@,8"00DE@<8"L1E_@<8."L7&0!T) M$"HY1-/&Q@D*@<8"C`Y+@<8`"X7&!N`A"1.X"R^`Q@$)0H+&`KL_THO&`PD- MQAF!Q@$C49/&`PD)QBN!Q@$)$9+&!`HFQL9(@<8!"0J2Q@`)A,8"L@DH>8E)"DG8=WS)3&![W/>YF9 MCO'0@<8.IGJ'?H:.D9Z=H*NL@;#4DL8;R]6LJ)&18'?+QM#&KW9QF'.&AIF: MJ+"CN;"7SI'&'-VVZ32?IJ5D)20U/*)O77F1@9"2I)JFKK&^P)/*D,8=R,:I MN5WGO_6!G2NRB&-I:6MX@9&AH+"MM\+(R9;+D<8;VAXBW^%28B(C\N)FYNRJXYO>I-\G92QN]C8?J2%Q@=9TRMU M?6I8HH#&'=)U9GAJ>C&$C(S%I9:=CHRC>;"A:864FJ*[W^&*C83&!G]^W6]X M#EJ#QAR'=WQV<(5WTL>AAJ*,LHZ(9:&+9'I[B9F_TNI\A8/&"L5O;GD8$&+& MQM6I@,8;)3(:='+PP::+C8QXBGJ*6YYR<9)R7@<8%OX.,O73%@\8#"Q@*-G[V%Q@*^@823Q@9< MP8S&)G,8"C]O#@,8!1+J"Q@/!>>R$G,8!R8:!Q@"V@\8# MBY?"LIS&`;*5B,8">+G6G<8`88G&`JV?@)W&`-R)Q@*8@,^JQ@'2T>O&@\8` MX:S&`/VLQ@%GR*S&`)RMQ@!KK<8`NZS&`*B+Q@7-=U]?:*^9Q@!VB<8(=@D/ M%3D5-`Q]F,8%KW)^R,;]@L8+OPDL+%YO@&H@1`S#@):37RI;E,8'M@Q1AX=\[K"!Q@Z%(Q-O>G^`DI24HZ):'-&2QAO* M"Q->@(!;6[7&SL:.%R\*<'IZAY*8I9RNIA/-D<86C8(Z-DA7;AHG M'A%R@8>6DIZEJ[:Z++F0QAW(QA8-)N"\\W6-,+4^/BEG/3!RAY69I:6MNL+% M7JB1QAS%"2-<;,3$F*?&(3\@8W!P+(>2DJ*KKL#`Q--3W(S&`+V!QAPB"C%= M4ZZ8P-$:0&4V<'![*6R4J*>TNL/&R]1ZL(3&"-JS;:^QQC$[FX#&'<,*)3/L MSX'`QAD^:"MP<'N#:S>DJ+*]Q\7.W.*0Q(/&)5@P/Y<9Q@D/)LW&T[HK"6P. M#JO(RB!(/7!F%T9B6HXCL[2WQ,;*@,8`EX/&&;97%D\/"0P8$J9^41/&(3UF M057.#A@S%#4V@10%CIA%N,#3B\8@)!<3"1,6#T4.$!%!*37O#"@:%!X;%!$1 M$`P4%!^U=J?+C,8?"1`)$306.RLX(S42#BG]*PT*$!<+"0H*)S,,"1A9)VJ- MQB`7&`X[0A<;)R@M&Q$))#0I(!\*%PX)"@D,1Q<1,!`9'\&,QB$/"Q5-+!82 M$!`.%A,B"SBW$1`)%AX)"PD,&3@@"PT-%AO-BL8BJPD,$1,9$0H+"0L:%A,1 M##"V"0H452#A<29#07 M40L,'`L.#0H)"AVXAL8G#@D)&!4-$!BQLW@Q/AT7'!@4%A@D"18152@/%AX3 M#A(2%A01"0D9?(7&!PT)#1H<#`R'@,8=S1M%*"0=#AD>&0D0%`\S*@\L#ALT M'AP7%0X)"2!)A,8&'1<**1T+#8/&`D,C'(`5%BT)"A$7(SX0%1@^&AX5(R,B M$0T?"AY,@\8*NBX8'`P/,<;&OUN`QAL1#Q$6#`D)#!<5%ST8.#$3#2P2<"LG M&Q@1%@D9A,8?5AL8#PL4QLN?02#-W!$4&A0*"0D-%14;'2PS*Q\8)0^`Q@:A M*!L5*`H9A,8?2'XI#V;&QKUM-A%5"A)#-PX2"0T;%QT[230T4\8E##6!Q@6V M,1,)#L.#Q@-N%1`E@L87MB`4#;H_6AT/"0D4&ADG5$`RL,;'"@F;@L8#CQD* M$(/&`WD_#RR#Q@Q^$!K&X%`8$`H*%QPF@%N!Q@()#%"#Q@.^%`VS@\8";!"0 MA,8`.X#&"3=2+PH-%B0A.#&"Q@())GF$Q@2'%Q)XN8'&`0L=BL8(CQ\+"5B[ M$0D3@L8"8"*FA<8"M%5UD\8&"0I$QB`4R(+&`LLWOI[&!48*$\8[(X/&`H8U MCYW&!GH)#&3&/82#Q@()"UF=Q@8*#&_&QBJV@L8#R`D)*9S&`ET)NH#&`42Z M@L8#NPP)%YS&`1H>@<8`M8/&`R`*"J*ZK,8` MIHO&!(U*4Q@>T"T>BHI'>HH'& M#GL>$W^%E9JFGZ>PL549T9+&&\4*$$J:FD53M,;9QH07*0ITA86BF["YJ;VN M$\V1QAS7A@D82JZ)S8^!E+%C&2,=$7J6E*J;K+&ROL,ILY#&'F,HML%!T<$X`0!PT4$QZY(Q@NK"0D6&143 M"Q89(1V`&A<8%Q8-*1H-%Q)'+!&QB<."0D8%0P/%K2R M<24T'1<:&!$6&!X)%1%`'0\6&Q(.$A(4$0\)"1ASA<8'#0D,&AL,#(.`QAW. M&CLD'QT.&1H8"1`4#R0A#R(-%BL:&!42#0D)&T&$Q@88%PHA'`L-@\8<0B$< M%!44*`D*$1<:-`\3%R\5&A4A'1T1#!<*&T6#Q@JZ)!<<#`XHQL:Z3H#&&P\. M$!8+"0D,%A47,AT&A(-NC9$'`X) M"1(9&!\^,"JOQL<+"9B"Q@..&0H/@\8#=S4.(H/&#'8/%\;@/1<."@H5'".` M18'&`@D,3X/&`\43#;&#Q@)F$)V$Q@`U@,8)-#TF"@T6(A\O)8+&`@D==H3& M!(,5$'2R@<8!"QJ*Q@B"'0L)5;D0"1&"Q@)<&J*%Q@*S26N3Q@8)"D+&'1/( M@L8"R2&]GL8%-`H3QBT?@\8"@B&*G<8&=@D,8<8O?X/&`@D+6)W&!@H,9\;& M*K6"Q@/("0DEG,8"4PG`@,8!0KF"Q@.Z"PD6G,8!%!Z!Q@"U@\8#'`D*H9S& M`2!O&:#AM:P``"0C_ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M____________________________________________________________ M__________]I=#,R``!9E`````#_QHK&`LSWXOK&`O'^]/K&`_[^^-?YQ@/P M\^_=^<8$R-3-N(!^#8F&<6AM:GMTCZK)RLS6P,81VJG!MI&*@8*(G+S:QL;^ M_O3$B<8+T]/SY*9^;F5E9VEX@(80C9"0J)NFD8E^:R<_CO,82U]/`?IYY?W^#?WAK:W*L\>.JU(G&(GZ5FX9K7V)F?H.+A921 MF9^FHJB6B'].:1XHG& M)&N"D8)_=&5H@H*&A)"9D)V8DI21FJ>KG:6=H**@EGZ*FK#%Q]2YQA*[X,!_ M@82EF9>2E9F2?H/DZ83DB<8F:YRGA9:0;G%^>X2#A)6)DI"1E)29IJB:GZ&> MJZ^RG9>"BZR^U8Z]MRBI"' M@(%[?H=_A(Z(D(^)GIFEFIJ=HJ:JK:RMM9*`A9ZISLO)ML84Q:_SS:O$Q9R0 MD)F0E9")TM%`;97'A\8GF.O)=WV%BH*3=GZ+AI"&D)"-F9B9F9N:J*BMH:NP MK:NTNJ%T=Z_-W[;&%=J;O_/-KD)LL9F5D)F0IK&M]HY1W>'Z&AHF`C)"8D9Z:H*BH@+`+MJNPM<*WMXAUG\#GM,8*V>'5 M?NGNLVX0:(^`F3N@H:"OW3\>.#+-T\U;1$3-QL:>ZX9U9F-O=827CWJ&BX:& MD)"9D)&:DIJ>FJ:PLZNSL*^VMKO#J'2/N,2SQDO_2IC)-GYV2F::F M?M?10SHO*E%243\O1&9MM8[Q?F]T9FAM?81]C):.@)"0EIZ0DIJAFINDHZ6O MJZZUK;:]O[RVKI*1J<'3L<9,T.3&R*;4Z,-X,G&LPJJHN'BBA(:.)B(B(1\G M030V2GI\]()K>&]=:'%X<8N8D(&1BY.8EI::H*&BI:*HK*NNLK.RO,&^O\6M MEI6GR]>PQDW)XL;'HJ[QU*X[.:+GOKW6<'=LU>!`'B`A&25+,3A$1&ONB&=W M=U)D:&YI@8Z.A8V)D)2:GIB>IJJAI+"MK;*MN*^YO\'#R,BQFXNRW<>OQ@#5 M@,9*SICE[JB2.ENOP?SY1,/^_?JA+3=!+U(88W1/0V#:AV!Q=E9?:6AL=WV% MB8B/CYZ:I9*GH*BAI;"RL+6MMK>VO,+'SCYRAFYJ?@*L5IK:RMK2ZP,?"Q\?)Q\[.U->\C:6\S:;&`>;1 MAL8CQ[F_[>VD?Y"5C410]UN-!K>75G9FAD:5EP@G(A?'AK MA)^0FIN:H:*BJZJNM*ZTNKV\Q\+'RL_&UM37U,Z9D:;&`LS:AX?&#\>7Q_#0 MA8>!6GE$ZXHXHLN`J`^TOLG"V,UL>G=>9FEF;FE?@G(D?GUQ>HJ*C:*?H*&K MLZNOL+2XP+N[Q,+'RL_-U]'7U=?.KI?&QZ/&`\G52[F&QB+(KZ7BYZ^-ASU4 M99)C.URIFZ>LM\G&QM7!;G9T6&9I:&QP6()R)7Z`>GQ]?XF>GJ"AL;"NL+*V MN[ZZO\3"Q\K*S=31U]C7X,V&!U5T*CDYVQN-&`Q@JQ;7%R5V=I:6AO6X%R`75_@(`B?'J%CY:< MH;&KK["UM[NZNL'&PLC)Q\S1U-;:VM_@O8VMU\>0Q@O+R-#/KI^WP\;%Q,F` MQ@;)P+2P)1?-A\82N['J\KZ,/1U$QN.OB^RX>0H:FLJ["R@+H4N[S"P\[(RL*RPL;JYNL7#PLC. MQ=')T='7V(#@!>7EQ9'"T(W&$\_:M8)Q8%E`1H.LI7N"Q\;>U?.R@!``;X+& M`>/;@<9%S)[2[^M:1$0>4DH8&"RQMLF0D8&#F:>VPK>VN;JYP\?(R,?.T5I8W&5\N$54`^ M/C]`6*3`I8F`PL;([?.(%Q`0;,;&Y\S&P%/*QK3&QJ"XX?-L1$0>#G`B$`Y: MM]/&TL;+67!SQN1"PX)B2.&Q8U@X[&R,)726UR<&%I8SD^D)&D9&0D86.H;BZNL'#P\+(SBL=EV1#(R-1]<61\N9VG4S7GQ*>*54V&.A`S)1$/"\Z)AU[ M)RM&2\;++B-&='IR.6([-2E6,S9.42DV)BHL,RPX-3B1D8F)FY:)DJNXR\7" MQM38HL9.W8`:;9^-I[H5E7VB+:E(L*&`Q*"8@)R$F*!X:<7%I@'$Q M9?3^L!`.#A@>'A@7*CY==G-L*B@H-2,A(S8D,50Q,41&2#8J*BEE.C8YPM3+ MJL;&R[:GQE7,U*N;T[MS>^G9?&E.87U::TYT9T193U-B7&Q:43UG/2@Q:7%Q MC?[)*C(A'%DI,1T8-%U[=F4K)S$\.CT]1CU,7DQ38&5J6CPI*#@[:4[2MEF( MQL;GV*?&5=3@LZW#N)*FIH"49GM.=6Q<7%59GD=NO?Y66@FM-O6RE27=@6F)96%1:65IF;'&*A)F6FX!E0T=MBYK: MJZZ384QB8$](6&9V=EI$5U=F<&%Q87-D:W%OEF5>9=!\GD5I:%I<6U=F869?9E=Y=8:$HIV/>E\_:7%= MV)>GEVE6>VMG25IG?75:1E9==&]N=76#;'U^)LKVIP,BAH)B/E[BTDX]? M2&=.E\1XOZ3&6,"KP[.6MV?(J3GH^& M9#E(*^;&NU)$*'9B55UN971R9E)=57J1Q\W/VBI,9:MGNYI:B>AW.6M,"X9C0J7V563%%14TA13%!EB(5\=81W M;(B+)QI5M.STP&E(EHM6:F]]?7)64%"-R-#4T]3*S\G4V.+EKZF"CJVNO\F]Q\2N@6U06%AKH,9@R+*APK"SGHUW;JG+S,J&:%A87F!H7F-H M9V5E>&AV?(V.AY5[B7]R3CTO,EG'RXF*=&-Z=G-\;%%D9&&%A7U^AXR0GZBY MSL&\OX*"HZZIC*"OM\&YPLO$NZAG65YMT,;&RYW&7\3*VL6VG))S8YJWPZ)S M9%I=8F-E7&1E865NGU^@82)?XR)F8*"IJ2HG8NPL+?%R<'*QL&9CG19JJR!JIO&8\G&T-C= MQK:>E7AFCZ.FC6QD7%YA8F%<9&-A9&]P?W6"@X=_AH*-F(U\=VU$)BH^GHFD M>G%QA8)C=G9H8V]G8V5]@']_?75D'N;H*B?B:^NL<7*P,O'R+"HA5J- MCF^=QL>9QF/0R=W5SK"QIYB'?'Y_6W1N;F-@6%Y87V5C:&-I;GIZ?7>)B(E_ M?WV%FX:4BVDO*2MWTXR%;8:)8G9Y=&YI8V!DA9*0D8=L9&%H9V%G=YFAE96K ML*R[QLC'R]#)PJ1X9D]YE;_)FL9BS^+;PIREI(.*?7Y[8FMI6F-;6&-:76I@ M9&1J9'-X@(&%B(*&C(B1=I^@BF]E+SU0W<*%:XM[76=V?7]L8V!@8YJCIYN$ M@GIXBGAJ;7!_I9.>M+"LNL:^R&5E8G166%)B95I9969F;G%U>GN!?7>!?':0C8>1A'V#<'A)6&53U82'I9N- MA'60HHER8&!C;'V)FY6"E:[$H)BBBW5UBXN?H[BPM<"^VM//U];)N65EBI.8 MQA;#OL/2PL*LDW!PA'YS7R6 MEF1X>82:1+B7BKOGTK9\H9RJGH)_@F2`>A:&BIRZN+"GIIZ1?G6+CY.;K;^N MMLO!Q(#4!\*DB)QCQLB\E,9IOHB?H)VHI:2?A8)W?IV7DJVBO+F^R-'2T-+-PZUF?J1TRY+&:LO-W]',TMS1 MIY!S;G!U7V-[85U96HBDO:^SL;6=;&5N:69K;79^?(R*?81]A8V+2WF"BH^) M:W^9R,S<'5A9WAB6UQ:L[[,@,91RKRIBW-G M:'!IY*,FHEP::[-RCE7AY=WN'A8>1CI.:G*&MJ[K)TMK2R,6= M?*FONY#&%+AQ1WJ]BU\O:WAH<7QT:%]=6%EGHH?&4-BM'2&=(%Z MBV4\CHN$A(UM;;#6T;V\KYJ8EINEG)R=BJ2*KYNTH7V7FJR[K*"%:75R?HJ/ MB)23C)2?GKJUQ]?,V^+`HWB,B<'&QXW&$[AI1RB=BXMD='1M<7QW9RQ16&5D MBL9.RXM9;'IR$?WEW>+;"UK.GP:B.J::PFYR>BIR*DK"5 MH8&7DY:[JIR3<6=Q=81U=(&-AJR2BKNKG,?&T^2_QI&<;J+&RHW&$[Q9A'R$ MA9[IDFEY='AT.`X]679MB\9-SJ1R975Y9G)X>W=_(FV;?HB1=&^NR+[+L)^M MM(V'G9.G=XV*D\"-HWV'=ZB'Q]B(J4HIR-QYS,T]'D MY+INE,:*C<83S'&FTX%BH\]W:W)Z>EX2#D16>'2-QDS(CV5R=GIU>'U(&OBIN0HHA]BW9J88J1I8Z7@')C>7E]F$8#P]$5F6$A,8! MR=B%QDN_1EUU8Z1C:>+BW*/ M;'1GG^0?HV@I+"SRNS(R-ZS5U2-C<82R;)J;(R! M;71Z'QVB7)I7EY_EJYS>8!MA)6!=7%P:7E]@H&`BI"E MH;+=S>CPXI1'=H[&"KY^;H:!='AX4CH1@`\#155Q('& M3IQ0/"LI/E8[6W=U>W:1N^3=Z\"OJ9^LHH.`DX.>B(.">HJ`BW]R=WEN8&!9 M'-[?("%DIJBQB>'U]>W-L M+X(/`T!76=:`QES)Y,W@WKV';G*VRL;&R'Y97S8I.2]B>'QT=W6>PM+4Z<*M MI9ZJLX-_EX*6CGB,?(%^>XAK=VIG66189X*7;&U\?7_'QL;'R+:8?75\?'J` M@96;K<'EU=OMPI"Z2\Z-Q@ZL?7IN.R$1$!`/#PY29(^!QD+9W=+%U:6(6%)@ MX<;&TU%?6F%B7F5U=7=J7XJ>R,+,V7B*<69Q=V9F M5%)36&F`:G!Q=UC)A,82R:YW;GU\@9B;J;K2\_/DI%`VK(W&"-,L%Q`5*A(8 M$(`/`EE>RX#&@.M`UYR'D(%-5TAKRL:^4EI&6%U71%YE97"/P(O`N-C)Q,>< MJXB"F7U]G'Q]<7N*8V%G6UA@55-D5%M>86%F>(1Q7KN'Q@_9EWUX?X2-HJ[" MX^K41S9NCL8,QS517D!&0"D.#A-J9H7&,+1T>F4_4%$]0IV74T]84UAF1%%E M869]AX2MHN"XOKZIDX-^A(%U?GM\>&EX9EM77UR`4PQA7&"UY8M29VEG7H/2 MB,8/UK>!MH<6QQ[BYC)1[?XMY@8Y[B'%K:&!?5%=39%QG M8J;$RL.36FIB8WJ?O8?&#\C$OL"!=XV)AY7*SW5SSVF-Q@NO;TTB31T?#P\F M8I:(QB'"IF)"/STU-SE$2E-ALK1B9F!@@(^1G9^\N=ZYKYE^@'R`@'P:>XU] M:6I78UE866-L9X+`QL;(O'Q33F2/OJKH@7^'B:C$M:]4.MB,Q@NW M;%443Q<3#P\_9K6)QC'%FG5#/CP]/T)*6XO$QVMK8&)[@8*/I:ZUW+.IGFY] M?'R!>GF#AGIG9UE=75Q=:'6$JH+&!Y%*2%ZMV["[BL8,T;ZDA8.$D:['N"(I MU8S&"[]C;!!)'1`0%5AWS8O&+K-,041)24)-GJ)>F]B8F!98&!B>X>K@\8(G$Q+5L/GOY/'B\8,R9N#?X"8O:TN M'\;&NXK&"LU>C!8S+Q`0+&RFC,8(S&Q.45)11%.G@,8AG7EH8&5M:W*MDZV\ MSJR==V:#>H)\0-R>65B@F`"H8O$CL8*OGUZ?9"K9Z^Y$+R* MQ@C"OEM1+!,9=WF/Q@6^4E`^6]*"QA?'RSL[[!BVUH?7ML:6MR M>&6!8`&$P(?&"--89W)6A7)RR(_&";1V=7J+HX1N$*Z+Q@?`A%X^'3-]J)#& M`]);4J6#QAS*I7%C85-B87*EK[>QBV9E>'-S>7AQ:6EE8%-*UXG&!H]E>U=: M8'61Q@O.:W9T?8MU6(F7>\N(Q@?%H(B#06.5PI#&`\BYN,*#QAS'PK9E7V-C M:W:7J[FLGFY=>'AY<&QB9E%*/TUYR(G&!M1?A)EN9Y*1Q@O'O8-X='UO;V=L M?,>)Q@6PS\B/>LJ=QAG(IF]E:&AVG*2RJ*1U8Z*KJ+!F55)(2DA1LXK&!LQN MD92@@YZ2Q@G'MY1M=69J8&2UBL8%R>;GE)/3G<89R,&>@7%L<(>3HJ6B>F:[ MP<#'8E),2T]/5<>+Q@5XB)2SB+"3Q@C(LIQ];F5RBFV`CZ.A?W&`Q@C%7U%/4%)3=\B+Q@6"<9F\AL"5Q@7,EXQ\E+6,Q@+- MF+*CQA3,RZQB>'REJX2*Q,;&N%]-6%)25M*,Q@614YW+ALJJQ@'8TJ;&$=:- M:G*SU*A_P<;&LV1R;E]EMHW&!9I3E1RHW&!6ENBKVLDM7&$+JXO:^\I8MUO\;&JFYB9VK"C<8' MOV5[G\&KC,?2QA+$LJ^_RZ.C=W)ZPL;&J6)B57/?C,8'R:-EB[G"K(?3Q@FX M>KOCRH:"9V>)@,8$JD]A&GV-Q@C/96N>MK:SB,'2Q@B+H>;OK6%A4J"!Q@2Q M42LL;XW&"+%D?IZVSZ2(P='&")V0TO&O>E-NMX+&!,.`('*,C<8(F&2$M^K/ MM(:_T<8'8:GSQ69EI\Z$Q@.M++J,C<8(E&J#M_/9P9>ZT,8(T&JOY(A5N,+' MA,8#VC+%E8W&"'9ED,[NX:Z2O,_&!]_!;[2_:;+%AL8#S5/&Q(S&";Z*6WZD MV;F6BL#/Q@;4P9##F(/,B,8"@,;-C,8)HZE;;H2[FWN$Q,_&!<+!MM!_K8G& M`*Z-Q@G'BK1N>8*VF72/T,8%PKC(TXG-B<8`S(W&",F#D:*WM/"_G-'&!9R^ MI=I]TIK&",EYB;BSO-N\OM'&!,"GI**/F\8(S'B%KJ6EXZZXT<8$MHVACQ@61JM+?DOS&`8/$ M^\8"NE2G^L8#Q;EOV?K&`].)GLKZQ@*Y;;K[Q@*F@L#[Q@&.E_O&`M-OF/K& M`\B[<\2GQ@7DM\O+Q@*K9+VBQ@[6H4]*/S0U.C0Z.$IVG\3&Q@/#DI+3 MG\83Q:AU3ADA"0D+%1H*"14S4VB,I,W$Q@/9<[_'G<86P99J#0D*(`X,#Q4P M$`T,#!P*0&6AI;[#Q@*79<.&RT;$`PSI]/` MQA'96!8.%1@;&1DA;\/&QOW]\L.)Q@NH*`D*$!\?,%IC9V^`>A!^@("8BI6' MA&]6)!L5$`Q%M;_&$8D5.1D:%C`4%1PC+WK6[//*O8G&(7N*%0\8'$U<86Z# M='I[AGZ`?8J"E962DHR&:2D:%"LAA-R\QA+5.PPD-T=A:&EA4SLB,&OPX)#. MB<8B:W'UXA(&'CX^$@8&,EY>5G9.2>6=*,A8H/["[QA+('@T> M5U>'@(5]=&95.T3RXG;?B<8D4FU5)A(81&%T=7IW@8B!C8J'@X"(EIV3FI:8 MFI*'8#$5#UN+T;G&$J@5#1Y;59"'AH&$AX1E5]OE;MJ)QB9&C(DI$@\B3F]P M>79WAGR"@(>$A8B6GI*4FI:CI*Z1830A$$&OO,>WQ@B%"@D/($J*A(:!AP:` MFYW.:)FXB,8G9NK1*!@6%!EC;'1[<7E_>X"%>Y"*EY*2E)J>HJ2CI*J"4B45 M*X_`R;;&%+80"0D-4JYO@("'@(2`?,3%/Q=.Q(?&)V;JEQP<&2D=#4]O?7J! M>H"'?H>'D9&2DIB8I)JCI:2CJ[1]-$$2B-FVQA7520T)"AJ M*!!<+D^W@<8!R]6`QAEFZEH<%AXZ*P\,3G-U>GI\>WZ`AXZ3DI28F("E"ZNC MI:JUKK%T'A$XX+3&"M;@R2,)"0H-#S==@(<[E)F4J=ID*%-%R]++>FQLR\;& M5.I0'"L/*B,9$ALW>GUZ>H"!AX>)DH^2E)*8I:BCJ*6HJZNTN*`N%@V)L\9+ MV]S'C`T)"0P,-$I-@8>7EWG3SVI;24%B9&)<2VR#@JU+\$\7)Q(T(1P9.1HY MF*YPI9*9GC(S,S$K-$I05F6(//(]%"$8.D$J($$8&T1Q@GV'CHB0DI65 MF9F;H*.CI:FMJ;.XM;F_EUDO7IK3L,9-PN'&QF`3"0L+$2E>U;2QT6]\@M7; M/2@M*APD1SU)8&PJ["X6&QTT7T,S.AX5&EAX?8>+BI21E)>@FIVEI:2HJ*^H MLKJWO\3$I6I+4*["K\8`TX#&2L0T"@D-"A8J2BY>.EY2?FIVEIZ:KIZNLKK:^PL7(R\-Y M*1FDQ+/&,+`-"0H/"AHC9^K1;/#]\]J@@)25E&`HI<:U61.V'RA")B(N9VAJ M3Q\M,@TT@8>)DHF`E!6:GJ6DJZ>CJ[2OMKVYQ,/+P\6(&QNUM,8P.0P)"1L. M0%%OOFS=_]O8'%!-2U+Q&?L\8DQ"()"0PK#CI<=FRP_JZFKJ[2UPKW"PL3# MQL70U+))$V_,IL8!Y="'QB.2"@D)*U$70U%L=?._,>',EYB8I*:_EI7$$AH: M*&)G-C0B:6^!<")L4SP9(5F1DY*:FYNCHJBMJ*NTM+>^OL+%RL#2T-30PU@N MD*7&`LS6A8?&#[T>#`D2/4X<5D)LY'\MC;Z`F`^IM\BZQ[D7&QPF8F=8(AM3 M@G`D=7-A.1DQ6(V8F9JBJ:.FJ*NQM;2UO;[#Q<;%U,K4T=2]D$!EQ:/&`[_0 M2;>'QB%U%PD)'EU(12YEG%PU3)9ZDIZNQ,;&T+`9'QTH8F=D-AU$@G`<=7MT M7ST^,%26F9JFIZ6EJ:NTM;2XP+[#Q<3(S\R`U`7R)H828<>(^:IZ.FI:NNLK2TN<*^Q,3#RW2#@5$J,6*2H:.DI:FTK[2UM[Z_QT:`@X-^6R=8 MEJ6FI:JTL;2\NK[$QL#+Q,O+U-.`W`7DY+Q44\2-QA//U:1M9%M./T064T0K M4L3&U!$)#8`/`&^"Q@'TX4>8.#AXYD%BZ9J[6SJ[&TL;G"@,,'Q_;DP_,#`X/RM8>408&Y;&7`D)"A`/#VG&QN"_QH9&RL:7QL9A M#0D)56QL*`XI&A`.;:K0QLW&R!L<(1\Q9V4I9G!@+$AP-1=<>QX46(-W7XZ. M?UP;?+6P@+0)N+B\P\/%R\;^4PPD)1XX9UL9 M,'!5%#5P&A0G6Q44*W8E*HZ.C(ID,GBPM+2UNKF]P\7%W<;)R(?&`,"-QD^4 M9F-&-!04'Q]J6Q(0%!-1#`L*"A4/#S?"QG`KKB<6I[`6:<:^41();&Q-3%0G M-#0H0C)(T\QQ*`H<'QHM9DH5'F4^$C--%108-Q84'$L7'X".#I*#66Z`L+2] MOKN]Q-#%TYO&7\&XLHYT1"<5($4I"@X0$`D/#@L*&1`/&)['/0]V'1%TEQ0U MQL:8)CR9;%]+73LC/3]$02F^QB(0"A88%AQ?,10422,4+"05%!(7%Q04'A0< MCHZ%?IB/>5J*K\/!O<#.UZ+&/-QW%0T0#0D*"0\*#P\-#1H2#P\[PQ@.&A01 M%6L4&+F_PE&_Q&E<>%4[&B9#0$,V4I85%PL7%A0/1Q04$Q>`%`,2%A01@Q0$ M&8Z+7SN`F`=Y-9JSOKS)X:7&-3@,%A,,"@D-"A`1%Q,7$PX1#XT1$!`1$@X7 M%!%:B:=9(SM69\O*/2@46499.A'PP+"2\Z"Q$:'@\0"@H)"0L)"X`)%!<3*",,"@P1%BDC M&!**40V&A`2)"DO*BPG+B@R.!PA0A(3 M%`D+%B@V?-I<>HPZ3&.'X^"@P/#!,E%HA]/S0U$B$9(1XD&B4>'1P;(B\3 M.2`/%`\)"B(F&=,N)QXE$1`C(!`)#1,8#0T,#(()&@L)"@D3%VE$#0\C&AP3 M%PL*&Q`7&AL:?+(GLZ3&/(P-"0H)$1@?%GQ]/3(V%!4@&!(4%Q03$1H4&!04 M&1T-$1L*"182%>&2 M$181#0D)"PL,"0H,"PP4%AD6%QD6%Q41$!82#PX7/UV/-PD*"0D,$@T@+D]4 M*3=1120<'!L9'D!M5DYM;4,;$1`.#@P+#PD3"@H,-S0:'Y"83)*"@L*#0T;'2,Q/%I;6#F`%!\83UU31#!,03`.#A`.$`T- M"PD*#`H*#`P?+A\9('FWNYG&`44*@@E<$!88'!H;$1@1#0T+"0T/"PP0#@X1 M$18='!L:&1L;&!85'!(5%B@4#@PNVGT*#PL)"A(:'!PQ6EM;6A0/#A!?;4XR M(#,X)Q<7#!$-#0X+"@H)"PP*"A='&18@3TESF,8`NH()5!,6$1D9%QP1%!06 M"@D1$102%1@@&1P?'!86&AP<&QL<&!48%1D3&!8R$`P9,K81%@P/%1$7%!`: M/%M;6C,<%Q`T;4`9#A<:#Q$<&!$+$`\-#@L,"0J!"04,#10@*TJ8QD)I"0H* M"0D,$Q47&1H4&10-#!(,#A<=)26"2Q@+`"@J!"1`+$A<4$!@7#@P/%`P4$Z.XR(#&1<>L@UTJ-CTO-28P'AH8 M'!\;&1@8$C4:%A<7-CD:"@D*"A00#Q(0*#U@21,/%1(3%!L?*!\5$1$>&A,/ M%QH8%!X2$1)J:HO)#&%;0+"@D+"0D.&!P3#!P;#0P2#PP6 M,(AH9&Q81+1@8%AD_.A<+"0D+$1,/$Q$/&$M' M(!,?%!,/%B(I'!(0$R$A'1`6'AX6'A83'1(7'`H/"PDB1A46)'MQEI#&%*P1 M#`H+"PD-("@1#!L9"PP,"@X8AX?&&-!]*"4P/BHI)AQ4#,K&A,H)"(:'1@-"P\9&Q-/A,8!N]"$QA#%N1\3 M'!\8&!H0%A<8$147"H`).`H,#0X3$!<6%!@B1#LK)A82%B$J&C,8'QX1"@\O M'!HA2S8?020;)!\;%B$8$A8O#R<)4D()#QH?=X[&$9I2-!L8&AL>&QP/"PX/ M&B,3>8+&!,V/95>RA,8.HR4.$1(/%A(3%!87#1(1@0DX"@L/#Q46&147$AM! M/S`I&!DA/T8M/!46&Q0+#"T>&15T4$[+!\=&QT8$R(,.0D7%PL3.L)PRXS&"(<^'!H<&QL."X$/`PTG&L^` MQAO)XX$D-D,3#4VPRL;&R&8D'0X1%1,:'1P9&`\-@0DA"PH.$1$0%AL5&A89 M/#\C*ALD0#U9+C80$AD7"PLI(Q(18H#&%\?$J&UE33$G'QL:%AD/-@DE(0D+ M2ZP9RHW&!G\<'1L0$1&!#P,+$29=@<8;V-JGME-2&0HG2N#&QM,J&0\-$1$8 M&AH=%2`.#8()(`H,#A86%1L3%QDB/",F,BLL0AU.+SX3(R,A$1(D'PP-#(7& M$KZ16S$<'!L7$A@*)0D)"E@L%)B-Q@?3)A`/%1<2&(`/`PP7'+6`QH#J#,[G&N!\8@`HO#AD@%Q08&PL6#@T)#`D)#PT8&A(;$Q89*BPD-#HS M.%$I)2/,#$Z*QDQ+R,.#`T,1%-*1E90 M&Q87#14-#@H*"1$4&QH9&AL6'2,R/4XW.S`P.T9)05FCQ,J_9!$-#`D++K:' MQ@_(P[:C.1\:%0\*"0D1/\I5C<8+JFQ((485%PX.$A9JB,89NYY7,R&1$/#@Y4P,)&-UE9(AL9$@T3#X`*%0L-$AP<&QL:&QHA05=-2%9) M5D`J;:""Q@)L#@J`"0$8FXK&#-&X;#H9%0\+"1,2$KZ,Q@6]7VL/1AN`#P(J M.L2+QBZD(B(>%`P1"RFCQL9*)U=:-1XA%PP5#PD*"0D+$!L<&1P>&R`Q25E; M2%M05#A,G8/&`G@2"X`)`0I*C,8-NG,P&Q,-"0T-$:/&N\6)Q@K*68L5,2D0 M$!8OBXS&",QC'`P.$AH.@H#&"VDF3EI1'",?"AH1"H`)$@P0&1T9'B4A,5)2 M5EM:6TE'QQPA(W&"&X)"0H)"0H2M]'&!S,)"0P;/:+.A,8#J"JT MA(W&`V`)"PJ`"0$+L=#&"+\8"@D;.J_"QX3&`]DQQ)*-Q@-$"0L*@`D!#++/ MQ@?9020*"C*BQ(;&`\U2QL.,Q@F8%PL*"0D*"A:[S\8&KB)Q@"JCL8"(BH,@`D"#"!FT,8$7AT9 M'Q**Q@#,CL8'&BL-#@P-#F[1Q@5O)$02'\V;Q@&2L9J]'&!'T]6$I= MF\8(RCPB&4)$"QFLT<8$E$\C3;>;Q@C'/QM,'$`E%KG1Q@.7,IF!G<8'D"A3 M.D-<,LC1Q@.M:\2TG<8'H3=023!9>/RXOC:73Q@+4R\2>Q@6#BT!(JMS4Q@'$RY[&!(ZDQ->.U<8`Q)_& M!-2YQ,6BU<8`UI_&!Z9<2GQ@7QA:[EED,"0H7#0P/$R,0#0P+%0HR4J*@N\/&`I12O9S&&KR)#`L)"0X5 M%Q48'C`9%Q43)A`.#`DKA['!R,'&`9^%G,8::PH)&PL.&1\C&A0F*B(B%!0N M'1D3#Q$*'IG3PL8)8XCV4@)"0H6'AD7+3Q-97E_ M@("*A6L\+AL;*!<0"RF9T\#&$=E"%`P4&!H9&!I9O,;&]O;BPHG&"Y,="0H0 M'1TE5F%E>("%$)29F;"DKI*$?TX?&Q40##>TO\81>Q$C%QD5*A,5&B`N9L_E MY+2_B<8A8',2#A@;2UA>E)F,E)RHJJ*IG)9H(!H4(2!RW+S&$LPQ M#!PC06EO;FE6,QPI7.+3A\Z)QB)+528>$QY;7WN$C(J;F:*FI)*6FJ2OK:JN MGIM]:$0H%",_K+O&$K,8#1U/3I.4EH^#;UDV-^+4<=N)QB0Y2$4A$!<^8(*# MA8>3H9.FH)2>FJ.OLJ&LH:*EG8IC+!0/6'[.N<82D!`,'6!,EJ*@FY^BEV50 MS])IT8G&)CEN>"`1#QM-?WR$@X.2 MB:2@JYN;H:BLKK.QM+F"2B03'WN^R;;&%)@/"0D-0)MEF9FBF9V9BJVJ-1=' MQ(?&)USC@QL;&2$8#4A_CX63A9F/E**?FIJPL("Y"[NQN;O`O+EO&Q$NX+3&"M??QB`)"0H-#B93@*([ MIZ:GFL[`5J>=U]K7OL_/U\;&0>-(&R$.(2`9$A&QP95&5<-"`:&1=.@H^DHJN1K:>O MIJN`N1"ZK+N[NL#$R,O3U\IU)Q6J MIV!6N,:[LQ.8'2,X(1XL969H21PH)@TEBX^1FY&GIYZFJ[FTN[6ON+VOP,/` MRLG7R?L;&&2PC(5]8&"%59FB!<@DF&B4-AIZI MG)NC@*\5JKNSN[B]O\C#R,C)R<[+T]>V01%9S*;&`=_0A\8CDPH)"29*%CI0 MS\[DHRW3NZZPL+&YP9*2Q!$9&21?8RXK(&AQ@7(B=$PP&"!5FYV;IJ>GKZZN MNJZXO;[`Q<3(RL_&UM/7T\50)WNEQ@++JX&'Q@^\&@L)$3!3&8I/S^!U*HBJ M@+`/N,')NL>X%AL<(E]E5!\:4H)R)(!T7S(8*E2;HZ2FLKBOMK2XN[^]OL3# MR,K,RM?.U]37O)8X4,6CQ@.^F42YA\8ATN\G& MQM&K&!X<(5]E8C,;/H)R)8!_=EPZ-RM;H*6FM[6RN;>[O;Z]P,;$R1E+3#O+W!R8#&!K(3%(@@',R'QA*3 M#@D)$G:R-!J5U;Z1V'QIC;'.@,8+>!HI(A]D969F)R9K@'(0?H!_?W>!@DLI M*%R:K;&ON;F`O1.^P,3%R\C)RL_3T-?=W-W?QS0GKY#&"]ZMH6E'146I<7Z> MW8#&!G4)$!X/#J*'QA*[&0H*"0VUSS1ZXK]UIXVM4W'#@,8N:1$6%R%D96=J M5AD_N\"_ MN[R]O,#(@,D'R\_7T]??X\V!Q@+$1QZ-QE>P:3HU*RLP-2!!8B<7&HG&2`D) M"A`.#FS&QN"\QF]!R<:5QL9>#`D)G\_/5@\;'A$/M:/3QL[&RAD;'QPI96,D M9')?(D=R-!==?QL45H*`79"0A5,7?<"\@+T)O[_"R"YSQL?#50T<(1PP95@7+G)4$C!R&A0B6A44)GDG*9"0CHE>*G&\O;V_ MP+_"R!O+W&Q,+#RM3(TIO&7\6_N)%T0B4:&S0?"@X0#PD/ M#@L*&!`.%J+'-0]S&A%WE1,VQL:0(3>WS[^MP9%"/:*E6"6\QA\0"Q46%1A= M*A041B`4(AT5%!(6%A,4&10:D)"&@I>0=$^5M\G&Q,?0UZ+&0]QV$@P0#0D* M"0\*#@\-#1D2#@XYQA,-&A,1%6D3%KB]P4.MQ\"TT*F&)4JDHZ0Y2Y(4%@P6 M%1(/1A04$A<3%!,1%100@!,'%!,4%Y"-73>`EP=W+YVVP\+.W*7&3"T,%1,, M"0D-"A`0%1$7$PX0#I<0#Q`0$@T3$Q!6?IE&'215R->T.58BLZ:SCQQ5E8>%Q<0 M"AH?$"$8$A2`$`@4$0X4#@X6"Q"!$PM6&A06P].TC,;&M%.GQB%O"0L0"0X, M"0D*&!,8$1,+%!<6&189&!@;&142%0P-#`P.@!L3-_:X#A(0#A44#A<>#0H4 M&PX@$@Z!#!@+#`H/"AP9#`D1#!$2$Q0<&,2D&5W&QN#1I\95,0D*#@\,"@P) M$!460B46$1(B'Q\@(2@N-1DV$S<5$!%B@5"PP/$`L?$1D7834;.\:4.K^GQCT_"@D+$0L)"Q80 M(QLP,AL.$B,=*"DD'B8G(CD2)R,2%A0*#!@;),+,)Q\9%0P+"2DW"Q`9'0\/ M"@H)"0L)"X`)%!00'1H+"0P1$QT<&!0I&AH>K#H=KJ?&'5\-"0L1"PL,%R%@ M'"%A(4%103$!D3&!04&!@-$1<*"1(0$]-]6A`0#`T0%PH*$Q4< M#A`,"PD*"0N`"1@*#0H+)BD3'1T3(A<-"@H-#1@9&!@Q&1R#I,8`1H`)-`T- M$1<4-6,_,247%A19J<%@H) M#`D+#Q4,)3Y&.AH;+"D;%Q83#PP/6UEB2$@]%!`0#`X-#!0)"PH/$!T:'!W$ MQL;%G,9@:`P)"0H+#Q0.%!4/#!<1%A$+"0D+"@L)"@L+#!,6&!87&!87$Q$0 M%A(/#14X3W@L"0H)"0P2#!PH/D`A+3XW(AP<&AD=,4U$0$A(*Q80$`X-"PL- M"1`*"@LC(A<9C95)CIS&`$"`"0X*"P\3#Q06$@P9%181"PF`"BD+"0L,"PL4 M&!@7&!<6&142%!<2#PL/%2EV-S(*"0H*$`P;(#4])S=$/"2`&PT<*#]$/3)% M0B84$!`.#8`+#`D/"@D*'A\8&F)I'WN;Q@&Q#H`)&PL*#A`6&!L:#R`9%0P, M"0L,#`D+#`P*#!8=&!J`%QP:%Q88%Q,3#1H-#!(WL1@*"PH-#!L=("LR1$5" M*8`4'Q@[1CXY)SDQ*@X.#PX/#0T+"0H+"@H+#!DC&A<==;:ZF<8!*0J""4D0 M%1<;&AL0%A`-#`H)#`X+#`\-#1`0%AL:&AD8&1D8%A4;$1,6&Q,.#"W.7`H. M"PD*$AH;&BI$145#$@\.$#](/B8<*"X>%Q8,$(`-#PL*"@D+"PH*$RX5%AM) M07"8Q@"T@@E2$A40&1D7'!`3%!8*"1`0$Q(3%QL8&AP;%A89&QP:&1L7%1@5 M&!,7%"8.#!@FH1$6#`X5$1<4$!@M145#+1L7$"U(+!0,%!8/$1P8$0L0#PT- M"PR#"04+#!,=(D.8QB!A"0H*"0D,$Q47&1D3&10-"Q$,#A48&1LF*2HY+R`A M&AN`&AX8&A@;&R,7%!47)A@1%19_%2$."0H*%@T0#AE(2D@\@!T"&"(6@`H; M#`D)$!H9"PX0$`\,%`P*#`D)"@D801\<(\9C?I3&`X<5"0J`"6(.%189&A<0 M%PL+$1$,(2\I*B0B'APK,CDO*B@?'!D;&1@:&B`6%Q(7(AT5$QHI%AT+"0D* M%PL0#A5(2&(X#A,9'!P8$1`0"PD)"QD7$A`.%18/%@H.#@D*"@D-(@\/&D(G M*\F2Q@+))PJ""0`/@!4K%A(.#@H2#1`.8(>EH)Z=H7(F)BDS.#$H'!P9&!@; M&!L8%Q<2+!L5%A8G*1F`"0(*%@V`$"D\14\P#0X0$Q87&QD<&!$1#!@6$Q`3 M%A42&@T.$0L0#`D*#@D9'1P='[62Q@*_"@J!"1`+$1<4$!@6#0L/$PL2$J"T MR8#&'&A`6&QL6&A42%Q$3 M%@H-"@D9,Q$5'7IGDY#&%*D0#`H+"PH,'B00"QH9"PP+"@T7@X?&$M%V)R0J M-"$F(Q4B&Q4=%Q,1%AB`&0(Z*Q&`"30+#A02$A$/$B(B)1DB$A,.%A\A&`\. M$!<@+!&!<.%AP=(AL+(A@@+QH9&!`7(`X2(@PI#`QA*1$<((/& MRHW&!+,5%`P2@`H+'S,=$QL9#PL,$QLAB\9-S9.\).C<83RB(D'1\0"@DL+!L='18+"Q80'C:-QA&]4Q,< M'QT8'A`2%1D3%A$=$0Z`"3<*#1`4#@T3%!4>.BL>(!(5$1D=%2`A*B4<"1H5 M%QP7(AX;(1X9&2(:%Q@B#A09#Q8)(1T-&QD7M(S&$\><."0F&1(?("`9'1<, M"PX6&1%)A,8!NM&$QA#%N!H3&AP8%Q%1`6'2$8*14:&Q$*#R2`&A@Z*!XW(!H@'AL5'!<1$R,-'0D\)PD.%Q=R MC<82P)@]*1@8%QH=&AD/"PT.%QL3<(+&!,Y\4E*OA,8.H1X-$!(/%1$3%!87 M#1(0@0DX"@L/#A05&147$1HS-"4A&!0?,S8A-!05&10+#",9&!)S:U9)(BPU M'QP:&QH7&1@1'PDI$0D)#Q8TCL81OF`J&1D7&AP4$0T-#@X2'1*G@<8(TYXX M+"==:(C$@<8.?QX3#0\/%!,7%Q@6#0\+@`D\"@H-$0\2%AD5&A(8-#0A(AD: M+#=()#`1$1<5"PH@&Q40=Z.8BG5^;#LU)QX<&QL7$QH+(PD2$@L0,<-OS(S& M"(,U&QH;&QH."X$.`PT?&-"`QAO(WFX>+2H2#$:RR<;&QV`=&0P0$1(7'1L9 M%PX-@0DA"PH.$1`0%AH4&148,3`>(1D?-S!0(RP/$!86"PL?'A(078#&%\?( MHV5<12TD'AH:%18.(@D;&0D+0:P7S8W&!GH;'1H0$!.!#@,+$!U3@<8;UQ@0"0P) M$Q8H/"L@$Q`8$1$*#`D)#!`8&QD5%Q@;'S$S,38\+1L=&"(J/SU%L.%R@!`# M#`L5Q(C&#]2C/B(=&A$/#0D)"A,^QLZ,Q@S'B%M>-3*C,\+"XE M)BDW-S%"G,3*OUL0#0P)"BNUA\8/R,*UHC`>&!0/"@D)$#W.3XW&"ZEM1B1# M%!8-#1(29(C&&;N<4RL@&!<;%@X.#`ZN2PL+"0D,0M:)Q@W"L((?&A0/#`H*'$4> MT8S&"[-I319*%P\.#QH8FHG&&,238A8=&!8/#@T-4\#%/"M$1!T8%Q$-$0Z` M"A4+#1`;&QD;&AH9'#<_.#1!-T$Q)&6>@L8":0T+@`D!$Y>*Q@S0M<&!4/ M"PD/$1*WC,8+O%UF#D,?#@X/(C;$B\8NIAL=&!(-$`HHH<;&0B)!1"D;'!4, M$@T)"@D)"Q`;'!@<'1D=)SQ"131%/$`R2)Z#Q@)W$`R`"0$*18S&#;EK+!L3 M#0D,#!"8QKK%B<8*S%B,$RLD#@\4*8>,Q@C,4!D+#A$6#8"`Q@MC(SQ$/AH? M'`H6#PJ`"1(+#QD=&1TB'25`/4!%1$4W/&FOA,8"@1$-@0D!(,6,Q@S(;S`: M$0D+#!"&PX;`B<8*U&BQ-2&-Q@;?00D.&!88@<88W#PB/D,>'!X, M&`\*"0H)#!$9'1TC(B,]1(!%!$1%/W[*A<8(K0H)"0P)"1O`CL8*MQL6#PP- M#AZJ#K.*Q@C#O%5((A$0'#2/Q@6Z"1$K',2"QA?,(B)%/R$B&QH*"PD)"Q,4 M&QXK,RPB,3>!10%IOX?&!]()"@D="@D@D,8)E24:$`L/$1L.I(O&![]I2BL; M$QB=D,8#Q"L0?X/&"'2(>'B,S,SP\)A77B<8& M4PD)'`X*-)'&"[XL'1,1"PX,8HT_GHC&!\6213X5&%3`D<8"L["]@\8)Q[R5 M/44Z+"$4"8`*`A,G#X`>"1L?'!L4$14-/,B)Q@;%"0H@&0E;D<8+Q;)'(",5 M'@\Q/%S!B<8%E1@7$QVPG<8'P&XX/"\9$PF`"@<-(1-Q9GZ4-(`-`PH+"9:* MQ@;*&`D>'0EZD\8(IV0O*3(F/C^HBL8%M0D)%DK,G<89R*)W6RX;%0H*"0H* M)!ZIHK/"*PD*"PD)#[V+Q@4O"1T4"864Q@>@>EE".%=VQ(K&!=$1##J)R9_& M%KZ-5$4J#0L*"@DE)\TL8(1A,)"0LJ#1!X@<8$ ML3\3(G*-Q@B5"0L)"@D)%;K1Q@AZ#PH)"@T80Z."Q@3$?QIR@XW&"&\)"0H) M"0H1MM'&!RH)"0L8-9_-A,8#K"J]@XW&`U\)"@J`"0$+L=#&"+T7"@D6*;'! MQX3&`]DPQ9&-Q@,_"0H*@`D!#++/Q@?9/1H*"BB=Q8;&`\Q-QL.,Q@*0%@N` M"0,*"A6ZS\8&H1H8"0MEQ8C&`GS&S8S&`D\2"X`)`PH)+<+/Q@5='Q(-#:6) MQ@"LCL8"'AP,@`D"#!]CT,8$2Q82%Q**Q@#,CL8'&2$-#`L,#6K1Q@5E&2<. M'=Q@6<.R0D@Y73Q@+7N<2>Q@6"B3<] MH]34Q@&SSY[&!9"GK c #661B18", " , c #78443A", " < c #721110", " 1 c #61332A", " 2 c #7C231D", " 3 c #533226", " 4 c #978A8D", " 5 c #AF0A0A", " 6 c #841111", " 7 c #783226", " 8 c #B80D0C", " 9 c #981514", " 0 c #DDDACE", " q c #881918", " w c #B0A5B9", " e c #74352F", " r c #CCA799", " t c #ADA8AC", " y c #9B9897", " u c #651413", " i c #712C22", " p c #710C0B", " a c #8E1817", " s c #861B19", " d c #E4100C", " f c #9B1010", " g c #B49795", " h c #EB0909", " j c #3E302B", " k c #8F5D53", " l c #9E0909", " z c #701717", " x c #D1CBCF", " c c #846E69", " v c #9987A2", " b c #291413", " n c #281212", " m c #691110", " M c #BA0A0A", " N c #DED4D5", " B c #71291B", " V c #918E90", " C c #721F1C", " Z c #664231", " A c #7D1313", " S c #C2B5C0", " D c #6B332C", " F c #D40909", " G c #66625F", " H c #460A0B", " J c #446CCF", " K c #CB0A0A", " L c #BB100E", " P c #867A85", " I c #C64529", " U c #273FA2", " Y c #B70A0A", " T c #A19AA6", " R c #811B1A", " E c #441916", " W c #A50C0C", " Q c #521110", " ! c #C2BDC3", " ~ c #580C0C", " ^ c #0E0E0F", " / c #481210", " ( c #751818", " ) c #E0DCDD", " _ c #C90C0B", " ' c #B5B2C0", " ] c #A898B0", " [ c #722522", " { c #8F1B17", " } c #78201E", " | c #8D1515", ". c #7C1918", ".. c #831615", ".X c #E20909", ".o c #950909", ".O c #7D100F", ".+ c #9D7E7A", ".@ c #792C22", ".# c #878382", ".$ c #BC897E", ".% c #2C2622", ".& c #D7D4D7", ".* c #F30909", ".= c #693D33", ".- c #CDCBD7", ".; c #510C0B", ".: c #0E0B0B", ".> c #ABA3AF", "., c #AE1914", ".< c #6B1414", ".1 c #CB0909", ".2 c #5B513C", ".3 c #65463C", ".4 c #1E2856", ".5 c #6A0909", ".6 c #8A3425", ".7 c #381913", ".8 c #930D0D", ".9 c #D5D099", ".0 c #774E3D", ".q c #403F35", ".w c #3F231D", ".e c #7B0909", ".r c #211110", ".t c #655A56", ".y c #171010", ".u c #BC6F59", ".i c #AB0A0A", ".p c #51423F", ".a c #931110", ".s c #D2C4AD", ".d c #7E6F7F", ".f c #7B1616", ".g c #BC1914", ".h c #602519", ".j c #DAD5C2", ".k c #B7AAA3", ".l c #9C231C", ".z c #67382D", ".x c #D90909", ".c c #BAB4BD", ".v c #A48997", ".b c #D2C4C4", ".n c #AF2B1E", ".m c #EBEAE3", ".M c #A30F0F", ".N c #7D1C1B", ".B c #841918", ".V c #931313", ".C c #8B1615", ".Z c #1A0D0C", ".A c #640909", ".S c #635A43", ".D c #C07D63", ".F c #8B0B0B", ".G c #651817", ".H c #C20909", ".J c #591715", ".K c #A21111", ".L c #9C3122", ".P c #6A241F", ".I c #9E0D0D", ".U c #775B53", ".Y c #A11513", ".T c #C7C3C9", ".R c #280D0C", ".E c #720909", ".W c #8D4941", ".Q c #5B5655", ".! c #8B1111", ".~ c #A54427", ".^ c #E1E0DF", "./ c #8D4037", ".( c #A11B16", ".) c #727072", "._ c #7C0C0C", ".` c #310E0E", ".' c #621110", ".] c #5A1212", ".[ c #B30A0A", ".{ c #532318", ".} c #521F17", ".| c #792623", "X c #A7A29F", "X. c #B6ABBB", "XX c #7D1F1D", "Xo c #908099", "XO c #7B1B1B", "X+ c #90878F", "X@ c #C5B698", "X# c #E90A0A", "X$ c #100F0E", "X% c #A50909", "X& c #580909", "X* c #2A1717", "X= c #65503D", "X- c #3D0C0C", "X; c #B00E0D", "X: c #807B7F", "X> c #7A1D1D", "X, c #781D1B", "X< c #5A0F0E", "X1 c #EF0909", "X2 c #696765", "X3 c #605B45", "X4 c #CD130F", "X5 c #D20A0A", "X6 c #4C0A0A", "X7 c #533E2B", "X8 c #850A0A", "X9 c #3C59B3", "X0 c #C00C0C", "Xq c #C70909", "Xw c #971915", "Xe c #7E1A1A", "Xr c #7E7580", "Xt c #5E0C0B", "Xy c #5D0A0A", "Xu c #520909", "Xi c #8B2520", "Xp c #C85C48", "Xa c #CEC5CB", "Xs c #6C2A1F", "Xd c #642B21", "Xf c #9B1212", "Xg c #706A68", "Xh c #841919", "Xj c #A7999E", "Xk c #69201C", "Xl c #E7E0E0", "Xz c #9C6F65", "Xx c #C3B9C0", "Xc c #826D48", "Xv c #AFADA9", "Xb c #8A2B22", "Xn c #741413", "Xm c #9A929B", "XM c #CBB5B4", "XN c #8F5341", "XB c #783C31", "XV c #73211F", "XC c #911515", "XZ c #630D0C", "XA c #881616", "XS c #E5E4E1", "XD c #6E1B1A", "XF c #DC0A09", "XG c #741616", "XH c #8E7F85", "XJ c #591B19", "XK c #8A201B", "XL c #BE0909", "XP c #4E1A18", "XI c #FEFDF6", "XU c #6A0C0C", /* pixels */ " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXI.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXIXIXI.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XIXIXIXI.$Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.s N.D.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ).S.~.~.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.c kXp N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g I.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.~ & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ;.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xp.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X ; r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ; & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XzXp N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g.~.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXMXMXM r &XMXM N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.~ & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl rXp : :X#.X h hX#.X :.X.X.X.x.x :Xp.u &.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XN.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b & :X#X1.*.* : dX5.x F _ K.,.nX0 _X5 _ FXFX4X4.x.xXp.D r N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xp.j ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.s :X# hX1 h.XX5 8 L.LXw 9 9Xh q.|XB 2 qXCXC |.VXi.6X; # _ _.x.X :.D r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X Xp r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXpX#.*.* :X4 _X;.KXhXh.=.| X X.< i 1 1 1.P i.G u.<.=.zX>XhXh.V | #X;.n KX4Xp rXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ; & `Xl r.$XpXpXpXp.$.$XM N ` ` ` ` ` ` ` `XIXI 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXpX#.*X1.*X5.,.6 2XhXO z D.=.3.3 GX2.).d.dXrXrXrXo P PXrXg.3 , DXk zXO [ , {.KX0 _ KXp rXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ;XpX0 8 # | a. RXhXe qXf.L.u rXl ` ` `XIXIXI @.k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0 & :.*.*X#X0.K R.=XDXd.=.t GX2X2.).d P P P P PXoXoXoXo ] ] v ] vX+.# V.d.U.3.P.NXhXC.VX0X0 _.DXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXpXF.!.~ { XXD.< > D u.'.XOXCXK.L _ : &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0.uXFX0XCXD.~.L.U P P PX+ P P.d.U.3Xd -XJ.f ; @ 0 0.+ g ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.SXcXcXN.6.|X,.'XJ.Q G G G P PXo PXrXo vXo v v v ] vX+Xo vXo v ] ] ] ] wXmXm T.>XmXm c.U 1.z q.KX0 +Xp.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X@ IX# 8.! [XrXB kXj v v vXoXoXo v vXoX+.U D , @.j @ c.m.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` eX7XcXcXzXb.V f.8 pXd.t.d.d.d.) P.d P P ]Xo PXo vXo vX+ v vXo v v ] wXmXm TXm T.> w w ' w.d.W C RXC #X0 I rXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+X0 h.* 8 f { k.3Xz.b v vXo v v v v v vXoXo.k g @.s c.s r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.WXz.mXS.j i.N aXC.V 6.O.6.d.d.)Xr P P.dXr PXo P PXoXoX+ PX+ vXm ]XmXmXmXm T T w.>.> w.>.> wX..> c ,XGXh.K 8.n &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X@.NX0.*.*Xq $ $Xp.sXzXzXoXoXo v vXoXo vXoXo P.s @X@.q o (./XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.WXz.mXS.D .X>.NXh qXb 2.o.8 ,.).dXo P P P v PXoXoX+ PXo vX+ vXm VXmXm Xm ] ] ].> w T.>.> w.> w.> tX..c wXz e i , #.g &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.jXMXi 8.*.*X5 $.,.p.yXs.uXo v vXoXo v vXo ].kX3 O.yX2.U 3 A ;XM ` ` ` ` ` ` `.-XS ` ` ` ` `.WXz.mXSXbX> <.fX, }.= 7 |.M.oXC.0Xr.)Xr P P PXo PX: PXHXoX+ v V V XmXm ] ] ] w w w w wX. TX. w wX. S.cX..cXj c C |.K.g &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ).^ 0.b.| W.*.* + 5.F.yX$ 3.~ k v v v v v T .%.j 0.4 J.4.4X9 U.d.-.-XS.- * J J J J.- ` ` `.W ;.m.j.P X iXdXZ > i [.NXhXf.! { A.U P PXo P P PXoX+Xo vXoX+X+XmXm VXmXmXm ]Xm ] T wX. w.>X. w wX. tX.X.X..c SXx t c [XhX; 8.u N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS 0 ` `.bXiX0X1.*.x 8X0X-.% k.~.n.WXo v v ] ] ].) 4XI.- J J J J U U U U U U UX9 U U J J JX9 * w ,.W @X@Xd.< [.|.< Q.=.P zX>.N s ,XC.8.l kXoXr P vXoXo v X+X+ VXmXm ]XmXmXmXm ] T T T w.>.>.>.>X. t tX. ' S S.c.c.c.c !.+ iXh 9 8.DXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx.m ` ` `.bXbX;X1.*XF.I.[.Z.% j.~ & @ 0Xm ] N !.d &X9X9.- `Xl.Q O.4.4.4.4 O O O O.Q.4 U U U * J.= i @.u ( mXnX>X>.'.p G.t.z C D.=.| a.V.oXb cXoXo PX+X+X+ vXmXmXmXmXm ] wXm T T.> w.>.>.>X..> tX..c t.c.c !.c S !.T.T.T.TXj k. ./.n &Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 0 ` ` ` ` `.bXi L.*.*.X.I lXtX* j B.D.s gXIXIXI J.Q 0XIXIXIXIXIX+.4.4 U U.p.4.Q.% O.q.)X2X9 J J /.G 0.uX, - 1XnX, iXP.QX2X2X2.3 D X.NXeXA s.C.6 cX+X+X+ w v ]Xm V ] wXm T T w wX. w wX.X. tX.X.X..cX..c.T !.T.TXa.-.T.-Xa ! c [.K.g r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi M.X.*X#X;.!.i l =.w.~.$.m @ ` J.-XIXIXI @ 0 0 gXoXo ] .) j.4Xo.- ` `.>X9.]XnX@Xb.N - G.=.P DXkXJX2X2X2XgXg G.= CX>.= 7.V W.6.dX+X+XmX+XmXmX+ Xm T T TX. w w.>X..>X..> tX..c SXv S ! !Xx !Xa.T.T.-.T.TXa.c kXO.M :XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi 8 h.* h.[XD <.i./.3Xp.uXl ' J *XIXIXI.sX3X@.sXo v ] T T .U./.b ` ` `.^.J }.U i.P - G GXd z.N.<.pX2X2XgXg.).).) G.3 [.N a f |./ P vXmXm V VXm ] T T ] T T T w.>.> wX.X.X.X.X..c.c !XaX.Xx ! ! !XaXaXaXaXaXa.&.& S.WXA.KXpXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi.,.X.*.*X0 eXVX;.,.UXp & J J J `XI @.s.q.+ @.s ] ] ] T wX. 4 e.$ ` ` ` zXD D DXVXJ G G GXdXGXV 3.QX2XgXg.).).).).).) ,.PXe.@ 7.I.WX+Xm ] Xm TXm TXm.>.>.>.> T.>X.X. tX. tX..c.c S.T ! !.T !.T.TXa.TXa.-Xa x.&.& xXj.W a #.u ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.m ) ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` xXi M h.*.* _.W.UXOX%./ ;.W J J J @ @X@.%Xg @.jXj ] ] ] ].>X. w ! ) g.W N.bX6Xn.f . (Xk G GX2X2 1.z DXJXgXg.).).).).).).)XrXr.U.S D R f.Y.WX+XmXm ]Xm T T T T T.>.>.> t w.c t tX..c S.c.c ! % ! !.T.T x x !Xa.& x.&.&.&.&.&.k.WXi ; & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.9.q y ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXiX;XFX1 h K.6Xo ,.OX U.6 J JXl 0.t j O.+.s c ] ] ] ]X.X. ! ` ` ` NXlXM.G zX>X> .XJ G GX2X2 GXD. XD.pXg.).).).).).).)XrXrX:X:Xg ,.|XhXi.@.W.v ] T TXm T w.>X..>.> w w tX..c.c S.c.c.c ! ! !.T.T.T xXaXa x.&Xa x.& x.&.& ) ).c.U a IXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM.k.9.qX$ t ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.bXi.( F.*.* F.LXHXo y ^.4.L.dX9Xx.q.q.4.% c g k.v ] w.cX. x ` ` ` ` `.k Q .XVXV C.{ G GX2X2X2 G > C 3.t.).).).).).).)XrXrX:X:X:X:X:.U.U e.C 9.WXm T T TX..>.>.>X. wX.X.X. S.c.c.c.cXx.T.T !.T.T.TXa.T.-.- x.& x.&.& ).& ) ) ).&.v 2Xf.uXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` `XS.jX@X X .c ` ` ` ` ` ` ` ` ` ` ` ` ` ` r.g.H./X@.qX$ O.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXh 8X#.*.*X5.l P.4 J O ^.h rXI 0 ' *X+ @ 0.+ c.W gX.X. x ` ` ` ` `.+.'XV D D [.J GX2X2X2X2Xg GXd D -.).).).).).)XrXrX:X:X:X:X:.#.#.#Xr , }.CXb kXm T.>.>.>.>.> w wX..c !X..c.c.c.c.T ! !.TXa.T.T.T.T x x x.& x.&.& ).& ) ) ).^ !Xz |., & ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` `.m 0.s.kX cXcX3X3X3X3Xv r.D.$.+.kXS ` ` ` ` ` rX5.xX5 = O.yX$X$X: ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` rXh 8XFX#.*.XX;X2 J J U ^.+ @ @ 0.t.+.s.+ 4 ] kXz.v ! ` ` ` ` ` cX6Xn.f .XGXJ GX2X2X2XgXg.).t X.<.p.).).).)Xg.)XrX:X:X:X:.3Xg.#.#.#.#.#.U.U.@Xw ;Xm.> w.> t w tX..cX..c.c.c %Xx.T !.T.-Xa !.- x.TXa x x x.& x ) ) ) ) )XSXSXS.&Xx kXfXp.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` `.m.jX@ cXcXcX3X3X3.p.q.2.q.. I ;.~Xi.@ ,XM ` ` ` NX4X1.* FXPX$X$X$X$ O ` ` ` ` ` ` ` ` `Xl N ` ` ` ` ` ` ` r |.,X5 h.* h.l J J J J.4.2 =.p.4 O O O.% wX.X. %XMXz g ` ` ` `.0 < XXOX,XnXP GX2X2X2XgXg.).).U.PX7 G.).).) =.w.)X:X:X:.q o j.#.#.#.#X+X+ V c ,..XwXzXjX.X. S '.cX.X..c.cX..cXx !.T.TXa.T.T.TXa x x.- x.&.& )XS.m.m ` ` ` ` ` ` ` `XM./.K.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` `.j.+ c.2.q.q j j j j.q.q.q.h ; &.u.~ #Xh RX> r ` `Xp h.*.*.oXZ.yX$X$X$X$.T ` ` `Xl k.^ ` `.D j.^ ` ` ` g ` ` `.k q 8.xX#.* d J J J J.4 ^ ^ BXs O ^ O ^X9X..k.& ` ` N ` ` x `XJ.] }XV C C =X2X2X2.Q.w G.).).) 3 i -.).).Q oX*.w.)X:.3.r o b G.#.#Xr.tX+ V V VXH k.U { k T S.cX..c.c.c.c.cXxXx.c !.TXa.T.T x xXa x )XS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` `.+.% O O O.y.y.y O O O.%.% |.D &.D.(.K.VXC R.f g rXq.x.1 MX8X6 QX$X$X$X$ y ` ` ` g o.Q ` x E n.Q ` ` r E.# ` ` ` r q 8X5 hX1 J J J.4X9X9 U ^ 1.~.4 ^.y.4 * 2.3.^ ` ` ` !.:X: HXt i [ [XD 1X2X2 G.w oX*.t.)X2X* QX>.3.) oX* o n.w.Q b b o n.%X:.p o o.# V V V V V y c.6 {XzX..c.c.c.c S !XxXxXx !.T.TXa.T x.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` `.T.c.c.c yX:.).pX$X$X$ OX*Xb ; ; :.i W.MXf.YX;Xq M.M fXUXyXuXu q QX$X$X$.% ! ` `.W.Z.r y.D n n.Z t ` 1 b n.T ` ` `.$ a.,Xq & * J U J U U J U O.4.~ U U UX9.pXP.p.^ `.^.%.:.r HX<.f. .NXn.7.QX2.q b o bX*.t j.r o =X7 = nX* o n nX* bX* o n b.w n o o.t V V V VXm y y yXH c.6XzX..c.cXa !.T !.T !Xa x.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` `.^ y.pX$.r._.M.a.FX%XL K.1 L.a M.xX;.!X6X-X- H R zX-X$.y.Z.p ` x.7.Z.ZX* j.r n.ZX* g o b.r j ` ` ` `Xz.L.jXI.- J.4 J J J U U O O.4.6 U U U U.q.7.U `.+ oXJ o H < (Xn ..'.`X*.Q o b o n bX* b b o n.J Q nX* o.r.r b b o b n o bX* o b.q V V VXg.w V y y y y 4 kXiXz.c ! ! !Xx.T x.m ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` `.z.F $.. R.! W $XF F.F $ K.[ f Q Q.J Q.G z.f <.` o.ZX$ y.v.r.Z.r.y.y.r n.y.Z.7 n b.r.r.t.$.$ rXz.~ 2XK.~.QX9 J.- @.s.q.4.4 ^ UX9 UX9X9 U.4X*.U E EXJ /.' XXV [XV.<.` b b b b o n b b n b o b nXJ.w b b.r.rX* n o n.r o b o o bX* VX+.pX* o.t y y y y T TX .+XN.u S.T xXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` `Xz M.[ f.C.C K +.MXA.F.oX#.*.1X8 u u -. EXk.{XP.{.{ - (XJ >._.]XPX.SXV u./Xc.(.O.].h.JXy.`.R /.h B B.h.uXI.m./.n.nXK.7.}.Z.RXU.i l f {.l.' ~.'.B.f X zXtX- HX-XuXuX6X&X&X6XyXuX&.AX6X&XuX mXu.]XV 3 -X7 1 j = 3XP 1 =Xd =.6X= DXf a.3.~XG.aXw.h.!X&Xu.R.}.h B.~.h 0.mX7 I.n.LXK.h /X-X6XuX& j.q.pX6.A.' XXD }XO.; / ~X&X6.AX&.E.E ~.E.A ~.E.A.5.5.A < < <.hXs.hXU.o l M.M.K {._ B 3.! z.J /XkXP.}XD E.}.k.=.} C.U ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` `Xl.V m 8.* WXh 6 W W.8 ~ >.J j.D.9.h.~.~X7 OXG z Q.]XPXV 3XJ =.P j.P 1 - 1.PXd 3.N ,.|...6./.K #.I.!.F.E.e HX-.h B B.h.z @.%.n.n.n.L B.}X<. >XkXJ.3 jX6.AXU q.f X <.;X- Q ~Xy.E.E.5.eXU.E.eXUX8.EXt.E.5 p (.< 6 Z.~., K., LX0 8.M |._Xd 7X;., W.O.G.<.}XP E - E -Xk.}.^ ` ` N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` 7 I $.* _.VX;.FX;.VXi.| u.v &.D.~.6.6X7 O /XDXb.J E = C =.PXJXkXdXX - -XJ.PXJ.PXK D.! R.=Xb 9 f.V.Y.8.o.e H.}.h B B.7.m.%XK { 2XK B.{ /.! 6 [ iXA mX&.5Xt AXn (XZ ~ ~Xt.;.;.5.e.E.e.e.EX8.o.F 5.o 5X%X% l (.,.u.u.~.g.H +.,.l.(.(Xw.8XKXw M $.[.aXb.!.'XP EXJXDXPXP.k N cX>Xx ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` `.j.~ $ YXq.[.o l.a #XhXKXXXC.u.9.D I.h 7.q O o Q. } Q -.]XJ.].J z u.]XPXXy.EXU uXnXG C p.' Q QXt.;.E.eX8 YXq _.x +.x.x.1 K FX;X5 K _ : I IX4.g.n.g.n.YXw.LXK p.8 K M M $X0 $.i 7.h.X-.`.R.r j cX@.sX@ qX8.o.E.A.'.eX8XU < A.fXU QX7X=X3X3.2 D R.N 7 e e 7XXXhXh q a.K.MX; 8X4.D.D.u.u.DXcXcXc ;.L., #.M.!.8 MX; LX;X0.L F.HX0X5Xq +X0 8.@XkXJXJ - }XP.b ` ` `.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` rXL.1.X +.XX#.H 8 f f.V 6 p.] R 9 # LX0.( z.<.G Q.]X&XZ.A.A.A.AX&XyXZ.A.AXyXUXZ p.E p A aXGXh..XAXAXh. . |Xh q 9.KXf.! z i <.'.;.R.:X$X*.q 3X@XNXK.o.e.E.5.E.EX8.F AXZ uX> } DX=X3 D i.= Z.SX=.=.|X>X>X>X>X>X>X>.|X=.SXc.0.6./XcXcXc.~.,.( # 9.M.O lX; W Y.[ _Xq.1X0.g K.HXqXq.g.~.~ A. .}.}.+ g.U.PXB ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` `.b.g FXF F F +.x W.[.[.M f 9...fXh.N RXOX<.|XkXD (.'XZXU ~X& ~.A ~XZXt.AXZ.AXU.AXZ.5.A p.f.fX>. Xe X. XwXA | qXe s.f.fXeXh.(.| 6.V |.F B.`.R.R.R b.z.u.sXw.EX8XU.EX8.!.FXZ XX>X>X> [ D.=.=.SX3X3.SX=.6XC.V | | |Xh.|.SX3.S.2.3Xd 1.2.3 Z eXf.I W $.a fX8 #.M M $X0 MXq.H K _.1 KX5Xq _X0.H.l 7 u - E -XX.}.^ `.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` I _ F.X.X F.H.[.oX% $.K..Xf q.NXeXeXO.N.'.<.P m ~.'XZXZXuX&XZXZX.N RXV D.SX3X3X3X3.S { W.M.M $ f.6XcXcXc , 7XiXK 7XB.zXs z z. .! W.a.a.IX; 8X; W.[ MX0XqXL K _ _ F KX5 +.g.~XNXw. -.}.+.W.l.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` &XL l FX1.X + F.M.Y.C.V mXh qXh z mX>.'.f u u.JXGXuXZX& Q Q.' u u.]X<.J.G -Xk.G.PXD CXD ..fXG.fXhX,.NX> X R.N. .Xw a |XCXhXCXD q A A.BXn.{ 7 /X6 ~XD / 3 &.j 6 9 ( W.[.a | 6 6XGXO.V.MXf s 7.SX3X3X3.S.3XV.NXh | f #./XcXc.L.,.( _.Y.lXw.M l.! . C (.!.!.F f.K.MX0X;X; 8.[X0.[.HXF.1 F + +.x.x + _Xq { u [XJXbXiXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` `.$.xXLX0XqX5.H.H.H 5 $.V. .< zXhXh R..} 7XD f 6.Y.B EXz.9XwXiXb L.x hX5XL.[.f.. W f.K $.M./XcXc.UXcX3.=X>X>X>X> R qXb.6.K M $ M 5.[ WX%.i l.8 qXe XXG.F._.K.a f f #.M _., _X; K _X0.H F FX5.x F K ; ;.6 s.l.} e `XMXp.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` `.$ _ F.1X0.H +.X h FXL f |.fXG XXh R. XG m z.'XyX&.'.]X<.G ~XJ.z.=XB 7 DXs 7 i -Xk.h = 1 ZX=X=.= D D D [XVX> .Xh.NX>Xh.N aXe {XeXV {.CXh 9Xf.{.}XbXiXA..Xf.C.N.P -.(XbXw _.x.xXF Y M. | K fXCX; 9.(XcXcXcXzXc.~ WXf.YXh.NX>X,X>XAXf.K f f 9.iX%X%X%X%.a sXA.fXn.e. .I |.( a.M #.( #.H 8.nX0Xq KX5X5X5 +XF.g :X4 _X; XXJ e.P.n.P N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` NX5X#XF FXq.x F.X + +XL.KXCXh.<.<.G.< 2XX A aXe a.N.N q RXeXhXC.N q /.} e.NXA | a.C | [.= eXi #Xq.x.HXFX;XL..XC $ #.V.K L #./ ;XcXcXc.g $X; 8X; _XfXCXC. }XVXkXsXdXkXnXn A.8.8.BXA A A.O.O...KXKXC 6.VXK 9.IX0.( # W.[.g L +.x.xXF +XF.x :.~.Y.fXb.lXVXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` `.$XqX%.x F.[X5XLX&X6.`._ qXhXn.<.; mX>X,XnXZ pXU.< uX& ~.G Q.J N ` ` ` ` ` ` ` ` ` ` ` `Xl gXN CXd.= D } i.z C.=.= [XX.NXG |XO ..| RXCXh s.NXC.` = eXw | a.Y.Y qXX.S.=.,., _ F.H.1 FXFXf 9Xf.MX0XCXfX0 f.Y.nXNXc.L.gX0 9.( L.VXf 8.K |XwXKXi.6.,.Y 8 f.aX,.PXV. A.O._ a.BXK s f a { {.VXf.(.(.KX0.,., # MX5 _ FX5.X :.u I.g 8.B iXV.b.$.L.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` k <.;.RX8 $.x.F.5 H.RX-.|.| XXZ p <.N X u.5XUX6XtX& ~ ~XD ~.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.$ e uX>XV D.=.3 i } e.| zXnXi.P X...NX> a.C u.` CXC aXhXhXhXh { eX= D RXF.x hXqXLXLX0X;Xf 9Xf 9.V.V $.M f.(.L.n.6.6.,.lXb.l L 9.MX0.(Xw.@.L 7.(X; # LX;.(.(XiXs.z C.O < s 7Xi..XwXiXK f.V.(XK a.M.(.L., M L.~X4 +.XX4XFXF.XX4.g.IXKXDXbXb.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` k m.;.R.R f.I.F.F.F.A.e [ e [.< pX,. X,XG u.`.:.; ~ ~.G -XV ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXz.JXJ -.|X> C i [ [ 2 ZXkXhXn |.NXn.C.7 /XhXe.BXCXh.NXh.@.U.U 7 9 F.HXqXF.[X;.MXLX5.K a a # #.VX;.(Xb.L.n./.6.l.LXb {.VX;Xf.V.Y 9XX.l eXwXwXi L.,.l.l.l.@ iXd.< p i.@.B R i e R R {.|XA #.Y {XbXK LX;.L.L LX5 IX4.x d.u.D I + A.l.|Xs.+ ` ` `Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` `.+.J.. 6._.! AX8X8 YX#.X 7.= iXOXnX>X, X.<.`.:.:X-.J ~ .XyXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.v e z u zX>.| DX= [.N ..f qXG 6.J.Z.<. Xf A..XA 9XX e Z.@.,.x 8XLX; FX; $ fX;Xf 8 aXhXA.MXA.V.n./.0.W./.6Xb.lX0XC.C.M.. 2.l L q.(XV i ZX=.~.6.(XK.6 7XK 2Xk.G uX> } i.|X>..XK 2 2.NXA {Xb {.Y.K f.l./X4X0.L.gXF :Xp : dX#.X M a.P.6 NXx k.z ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` N i.L I :XK.|.'X8.H +.(.= DXk XX>X>X>.G.R.:.:.: E Q.' } ~XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM k u u C i }X>X>XG }.f.O u.Z EXe.fXn. .! 6Xe.6 6.Y F.1.1.1 + $XLX; +Xf 9 |X;X0 a A 9 |.C {XB ,XB.6.n.6XKXf 9 |.K # 2XX {.C } D.P 1.z.6Xi.YX% {XbXw 6 2 C.JXD.@ i 2.N } i }X>Xh s s.| RXh a |XiXb.M 8.g.~X0X4 IX4.*X1 I :.XX; s 1 E > EXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` `.s ;.~.6 D [ R < z i [ C }XG XX>X>.J.:.:.:X$.: EXP.P.' i ` ` ` ` ` ` ` ` ` ` ` `XM N ` ` ` ` ` ` ` ` ` ` ` ` ` ` 3.`.].'X> CX>XGXGXD >.r.R.f z A.B 6._ 9. .I.*.X h.1.HXLXF.[ $ $X0 8.V | f qXCXG |.K., s.6.~XBXBXb.L s.C.Y #XA aXi iXK {.zXXXn >XkXD 6 l Y Y q 7.NXD X C.hX=.S i }.=.3 [X, R [ 2X>.N RXC 2 2 |.YXf.Y ; MX;.n : h IXp IX1.X _XX>XD >.R.:.:X$X$X$.:XP.} 1 uXz ` ` ` ` ` ` ` ` ` N.DXp.~Xi.uXM ` ` ` ` ` ` ` ` ` ` ` g =.w.Z.r.R.`.R.;.. /X$ oXnXnXG.f.f._ p 6 #.1.*.x.* h.HXL.[Xq W.MXfX; | qXAXeXC |XhXA.MXh s./ ,XB 7XB.,XhXh.( [XB.0.0 7.6 , > u.].hXJ z.I.F Y.8 i B...B < mXH g.+ cX:.0 i i.=X= DX>.NXX.N sX>XOXhXhXK.(.KXf.L.n.x d I.*.*.*X1.X.I E E i ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` `.+.=.@.N. .N.N.NX> .X-.`.: ^X$X$.:X$X$.:X- = - Q N ` ` ` ` ` ` `XS 0Xp d & d I.l 6 p <.U ! ` ` ` ` ` ` ` c = - - /.R.r.R.7 n o >X> X.N XX,.f <.E.I.H.H F.XXq hX0.H.i.H fXf a 8 L.Y.f.N f 9 R R 9 aXhXBXN.6 2.@Xi. .| 2./ , Z.UX=Xs.z - ~ m ~.J.G .N RXeXh 9Xi.YX;.g I h d : :.* h K.J.W.&.+XP.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` `XM.W.NX>X>XD.J.`.r O ^X$X$X$X$.:X$.:.: QXd u k ` ` ` ` ` ` `.m 0.j &X@.j : ;.n..X&.J =X7 c.^ ` ` ` `.^ =XJ.GX< ~XZ.'. -.O.[.IXq K.H.xXL.x.1X5 MX% $X;Xh 9XA 9XC ..f.V.CXe q.(.6XB.@ {.| 7 7Xb i i Z DXG.0.0Xd Z.h Q.}X7.{.{.G m 6Xn.PXsXn p.O.E ~.b ` ` ` ` ` ` ` ` ` ` ` ` % g.+.U.= [.NX>.N R.N.YXf 9., MX4 :.*.*.*X#.H ; 3 E o.v ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` `.^.%.y.yX$ ^ OX* OX$ OX$X$X$.:X$.:.y.J -.]XM ` ` ` ` `.m.m.m.mXS.sXzXBXi {XCXe / BX7.wXZ DXM ` ` `.k.}.}.' H ~X&Xy.<.; E.{ -.G u u z . { K.I.C L + 8X#Xq _.1XLXq.I f $XA q RXAXf.N.f A.Y a. .|.6 i.| 2.6 1 Z 1 , 1.2.z.{.h.3.{ 3 3 ZX7.2.2.2X= 1.h.G >XD.. 6 p pXt ..b ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XlXM 4 k D }Xh.NXh a |.K #.,XLXF d h.X F / E o = ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` `.T.% j.p G.Q.q 4.%.qX$.%.:.:.:X$.R.P.J.W ` ` ` ` ` ` ` ` ` ` ` ` g./ D , k -.w jX7X7 /X-X-.p.+.k.U.{.J HX& ~.;X& m u E EX7X= Z 1Xd X A 6.8.B.YX5.K dXF 8.H MXL _.I.a.! R.NXhXh.. z (. XhXOXX 7XB.=.=XB Z.3.2.S 3 - e.{.{ 1 =X7 3.S.2X3X3Xv `XS 4Xd QXX> X a.! f 8X; +XFXF FX<.7 EXM ` `.& ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` `.bXg GX:.Q.q.t j.%.y j.:X$.:X$.`.h.< % ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g 3 j jX7 j j.7.7.%.w.w.w QX-.; /.;Xt.< k.U =.2 Z.SX3X3Xd ..B.aXA $.[.Y.K.XX;X5XL Y.i.H.!.8 9XO.NXe {XnXO.N aXCXOX,XK i e.=.0.2 1.2 1 3 1 3X7.PX=.2 [ Z.SX3Xv ` ` ` ` NXz.J ~XUXZXt.A.E.eXw.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXz.@ }X> {.. f.OX8XLXq.x.H.O.JXM x.p.3 ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ).#.) V.% O.%.Q.y.y.yX$.:X$ b E.' k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv.t j j.w.w.7.7.wX*.7X- / /X6 ~.' g ` %.3.3 Z.SX3X3X=Xh.C.K.V.aX%.I.(X5 LX#.X M.i.i.I 6 < 6.NXO.N R.NXOX> (.NX> a a C.=XcX7X7 ZX=.2.3X7.2X7.S i .X= c x ` ` ` ` ` ` `.kXJX6 HX6.A.5X%.1XL.LXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.k.WX>.NXe.C 6X%.I M.1Xq K.~X* n o N ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` `Xv G x.qX$X$ G OX$X$X$X$ ^ =XJ.P.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xx 1 /.w j.w E / HX- /X6Xt.' g ` ` `.+.= [ ZX3.S.S i CXV C. X% $XwX;X;XLX#.i.[X% l._Xy < 9X>XO.N qX> X.N a.N.N 2Xs.3.S.SX3.2X7X3X7.SX3 Z [.|.0Xj ` ` ` ` ` ` ` ` ` N.J / H HX&.5.X h.x 5.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM k iXeXO.K 6.8 YXq 8.8.Z.r.r r ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` x.Q `.)X$.:.q.%X$X$X$X$ b D u.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.2 E.;.;.; Q Q.w /.;XD g ` ` ` ` `.W } i.SX3.SX= zXV.P.P.!.i {Xw #.i + + MX% l.[XZXZ.NXhX>X>Xh R [ [XK.| i.3.S.2.S.2X3X3.SX3X3 Z.= }XzXv ` ` ` ` ` ` ` ` ` ` ` `XB.]X< ~Xu.e F.x.*XqX8.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N kX> } X 6 W l W.[XU.y.r g ` ` yXM ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` `XSXg ! t.q.q.%.q.yX$X$ O - i ,XS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ kXuXu.; QXP.w Q >.b ` ` ` ` ` `Xl.WX>.|X=.S.S =.G C.P.B 8XKXw # 5XL.H.H Y.o.O p.'.NXhX> XX>.|.| [.|.@X=.SX3X3X3X3X3.SX3X3X3.0.$Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXy.5.5.E.e.8 l.i lX8 g ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` %.U.N. Xn.O.F.I $._ Q.nXMX X$.+ ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` !X `.Q.#.q.%.%X$ ^.'X>Xs.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.vXuXuXP j = >.b ` ` ` ` ` ` ` `Xl.WX> }.0X3.S ZXd [.|X,. 2.[ W.HXL 5Xq.F } m uX,.N 2 [ D.=.= D [ iXB ZX=X3X3X3X3X3X3 cXv ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X&Xy.E.E u =X8.E.E.A.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g 7 i X.O <.F $ f 6.C =X$X= ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv ` c c.p j c ^ n s. .v ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b ,.w Q ,.b ` ` ` ` ` ` ` ` ` `XlXz [ D.S.S.2 3 1.z 1 C C W.[.i Y Y 5.C 7 -.'X> } C.| [ }XX }XV D.=.=.=.3X=.2 3 3 /.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` kX&.E.eXU =X<.5Xy.P ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.+ DX, iXn A.O.F.a ~ ~XP.+ 4 cXB r ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.v k.W.W.n.7.G.BXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM ,.3X3X3X=.zX7Xs z.O.o 5X% M.i.i.YXNXd ~X> } }X>X>XD C.P - -.G Q / HX-.7X6X6 k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NX&.AX8.o.~ B.E.A k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` % kX=.@ R Z.fXV.P < D 1 ZX3 c ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` g.xX#XF _.Y.N.WXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.$XB.3.3.= i > z.O l 5.o 5X;X% W.6 BXt k g.$.$.kXxXM.3XuXuX6 H HX6X6X6Xu e.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` e.E.o l.6.n M.e.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.+ i.S e.zX3.zX3X3.S c ) ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NX0.*.*.KXXXzXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` r.+XBXVXV >.< p._.F.o # l l.CXB.]XM ` ` ` ` `.b -XuXuX6X6XuXuXuXu.J.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+Xy.e {.l YX%.e.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XS.k.# k.S.S c cXv ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$X5 9./.k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXM r./.'.5X8._ 8 l.i l 2 6 g ` ` ` ` ` k -X6Xu ~.;XuXuXu.J.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XM ~.{X=.n.1X%.eXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` N.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl./X&.e.E l M FXL.Y.e.+ ` ` ` ` `.|XdX,.'XD.J u u k N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X7X7 Z.~X4 5.oXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^XB.5.F 5XF.*.X f.o.W ` ` ` ` ` DXD D > D >XD.PXM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.w.hXKXpX4 Y.o.$ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ;.i.i.1X#.xXF $.o.G ` ` ` ` `.= } Z z Z DXDXVXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X .w u. .~X0Xq l k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$.i Y.[Xq + + 8.a.E , ` ` ` ` `.2 [X=Xd.3.S ZXz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 1XU p B.6 L Y.iXb ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.k ;.[Xq.1.iX;.i._ p.e.E.+ ` ` ` ` `.p.=.SX7.P.z ,Xl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.kX&.EX8.iX0Xq YX%. .b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X e l.1.XXF.H.C.f.FXU.AXy , ` ` ` ` ` `.pXP i 3.y.yXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^.GXy.E l.i M.[Xq 5X8.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` k 2.Y.X hX1Xq.8 1 mXt QXd g ` ` ` ` ` ` `.).p n o.% O ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz.A p.F l.i M + Y lX8Xz ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.+ 6 YX5.*X1 5.F m.{ Q.U.k ` ` ` ` ` ` ` ` `.cX:X$.p.).p ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXu.A.5 l Y.xX1 +.H 5X8.W ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` 1 l.1.*.xX; >.}.UX XS ` ` ` ` ` ` ` ` ` ` ` ` tX$X:.c.p ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `XMXy.5 p.o Y.*.*.x.1XL l > ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl k.<.iXL.X.i 3X7Xx ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^X$ y ` G ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz /.A p.[X5X#X1.XXLX%.o [ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xl.gX0 B.i F.[.GX3.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.q.c `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.$ lX8 ~.5X8.oXL.x.i.iX8X8.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.D IX0., + F._.t.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` y.c ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xi 8 IXtX&.E.E lX%.F.E.A e ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xp., :X4 :X5.!.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.B.6.l.IXF.8.[.*.*X0 q.+ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xz.g I.~ d.gXX N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.b.|./ 6 8 :.V.g.D d.g ; ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.D.~.n ; ;.l k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` NXB 7.V.,.u |.~ d.X., k ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXN.0.(XNXB.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `./X, aXN.gXA./ ;.g.Y g ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` gXi 1.s.D N ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.k 1XiXN ; 7 ,XcXcXBXl ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T.sXz.s 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` y.q ,.0XcXd {.L.0XM ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xv.s.j.sXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X .p [Xb.6.w.$.D r ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.&.s.^.b ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.# y.+./ 7 k.k.sXS ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.s ` x ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` VXa.#.s.s.m V.s ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.T ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.&XS V.s.s `X .s ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.^ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.c.j 0 `Xv 0 ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `X ) ` `.^ y ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `.TXv ` ` `.& ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `Xg ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `", " ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` x ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` `" }; nethack-3.4.3/win/Qt/qpe-nethack.control0100644000000000000000000000065007764735041016636 0ustar rootrootFiles: bin/nethack apps/Games/nethack.desktop games/lib/nethackdir/[a-r]* games/lib/nethackdir/[t-z]* games/lib/nethackdir/save games/lib/nethackdir/s*.* games/lib/nethackdir/[A-Z0-9]* Priority: optional Section: qpe/games Maintainer: Warwick Allison Architecture: arm Version: 3.4.0-1 Depends: qpe-base ($QPE_VERSION) Description: NetHack - The Dungeon Game Graphical version of NetHack for Qtopia nethack-3.4.3/win/Qt/qt_clust.cpp0100644000000000000000000000716107764735041015402 0ustar rootroot/* SCCS Id: @(#)qt_clust.cpp 3.4 1999/11/19 */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #include "qt_clust.h" static void include(QRect& r, const QRect& rect) { if (rect.left()r.right()) { r.setRight(rect.right()); } if (rect.top()r.bottom()) { r.setBottom(rect.bottom()); } } /* A Clusterizer groups rectangles (QRects) into non-overlapping rectangles by a merging heuristic. */ Clusterizer::Clusterizer(int maxclusters) : cluster(new QRect[maxclusters]), count(0), max(maxclusters) { } Clusterizer::~Clusterizer() { delete [] cluster; } void Clusterizer::clear() { count=0; } void Clusterizer::add(int x, int y) { add(QRect(x,y,1,1)); } void Clusterizer::add(int x, int y, int w, int h) { add(QRect(x,y,w,h)); } void Clusterizer::add(const QRect& rect) { QRect biggerrect(rect.x()-1,rect.y()-1,rect.width()+2,rect.height()+2); //assert(rect.width()>0 && rect.height()>0); int cursor; for (cursor=0; cursor=0) { include(cluster[cheapest],rect); return; } if (count < max) { cluster[count++]=rect; return; } // Do cheapest of: // add to closest cluster // do cheapest cluster merge, add to new cluster lowestcost=9999999; cheapest=-1; for (cursor=0; cursor=0) { include(cluster[cheapestmerge1],cluster[cheapestmerge2]); cluster[cheapestmerge2]=cluster[count--]; } else { // if (!cheapest) debugRectangles(rect); include(cluster[cheapest],rect); } // NB: clusters do not intersect (or intersection will // overwrite). This is a result of the above algorithm, // given the assumption that (x,y) are ordered topleft // to bottomright. } const QRect& Clusterizer::operator[](int i) { return cluster[i]; } nethack-3.4.3/win/Qt/qt_win.cpp0100644000000000000000000037150607764735041015054 0ustar rootroot// SCCS Id: @(#)qt_win.cpp 3.4 1999/11/19 // Copyright (c) Warwick Allison, 1999. // NetHack may be freely redistributed. See license for details. // Qt Binding for NetHack 3.4 // // Copyright (C) 1996-2001 by Warwick W. Allison (warwick@troll.no) // // Contributors: // Michael Hohmuth // - Userid control // Svante Gerhard // - .nethackrc tile and font size settings // Dirk Schoenberger // - KDE support // - SlashEm support // and many others for bug reports. // // Unfortunately, this doesn't use Qt as well as I would like, // primarily because NetHack is fundamentally a getkey-type program // rather than being event driven (hence the ugly key and click buffer) // and also because this is my first major application of Qt. // // The problem of NetHack's getkey requirement is solved by intercepting // key events by overiding QApplicion::notify(...), and putting them in // a buffer. Mouse clicks on the map window are treated with a similar // buffer. When the NetHack engine calls for a key, one is taken from // the buffer, or if that is empty, QApplication::enter_loop() is called. // Whenever keys or clicks go into the buffer, QApplication::exit_loop() // is called. // // Another problem is that some NetHack players are decade-long players who // demand complete keyboard control (while Qt and X11 conspire to make this // difficult by having widget-based focus rather than application based - // a good thing in general). This problem is solved by again using the key // event buffer. // // Out of all this hackery comes a silver lining however, as macros for // the super-expert and menus for the ultra-newbie are also made possible // by the key event buffer. // extern "C" { // This includes all the definitions we need from the NetHack main // engine. We pretend MSC is a STDC compiler, because C++ is close // enough, and we undefine NetHack macros which conflict with Qt // identifiers. #define alloc hide_alloc // avoid treading on STL symbol #define lock hide_lock // avoid treading on STL symbol #ifdef _MSC_VER #define NHSTDC #endif #include "hack.h" #include "func_tab.h" #include "dlb.h" #include "patchlevel.h" #include "tile2x11.h" #undef Invisible #undef Warning #undef red #undef green #undef blue #undef Black #undef curs #undef TRUE #undef FALSE #undef min #undef max #undef alloc #undef lock #undef yn } #include "qt_win.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include //#include #include #include "qt_clust.h" #include "qt_xpms.h" #include #ifdef Q_WS_MACX # include #else # include #endif #ifdef _WS_X11_ // For userid control #include #endif // Some distributors released Qt 2.1.0beta4 #if QT_VERSION < 220 # define nh_WX11BypassWM 0x01000000 #else # define nh_WX11BypassWM WX11BypassWM #endif #ifdef USER_SOUNDS # if QT_VERSION < 220 # undef USER_SOUNDS # else # include # endif #endif #ifdef USER_SOUNDS extern "C" void play_sound_for_message(const char* str); #endif // Warwick prefers it this way... #define QT_CHOOSE_RACE_FIRST static const char nh_attribution[] = "
NetHack" "
by the NetHack DevTeam
"; static QString aboutMsg() { QString msg; msg.sprintf( "Qt NetHack is a version of NetHack built\n" #ifdef KDE "using KDE and the Qt GUI toolkit.\n" #else "using the Qt GUI toolkit.\n" #endif "This is version %d.%d.%d\n\n" "Homepage:\n http://trolls.troll.no/warwick/nethack/\n\n" #ifdef KDE "KDE:\n http://www.kde.org\n" #endif "Qt:\n http://www.troll.no", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); return msg; } static void centerOnMain( QWidget* w ) { QWidget* m = qApp->mainWidget(); if (!m) m = qApp->desktop(); QPoint p = m->mapToGlobal(QPoint(0,0)); w->move( p.x() + m->width()/2 - w->width()/2, p.y() + m->height()/2 - w->height()/2 ); } NetHackQtLineEdit::NetHackQtLineEdit() : QLineEdit(0) { } NetHackQtLineEdit::NetHackQtLineEdit(QWidget* parent, const char* name) : QLineEdit(parent,name) { } void NetHackQtLineEdit::fakeEvent(int key, int ascii, int state) { QKeyEvent fake(QEvent::KeyPress,key,ascii,state); keyPressEvent(&fake); } extern "C" { /* Used by tile/font-size patch below and in ../../src/files.c */ char *qt_tilewidth=NULL; char *qt_tileheight=NULL; char *qt_fontsize=NULL; #if defined(QWS) int qt_compact_mode = 1; #else int qt_compact_mode = 0; #endif extern const char *enc_stat[]; /* from botl.c */ extern const char *hu_stat[]; /* from eat.c */ extern const char *killed_by_prefix[]; extern int total_tiles_used; // from tile.c extern short glyph2tile[]; // from tile.c } static int tilefile_tile_W=16; static int tilefile_tile_H=16; #define TILEWMIN 1 #define TILEHMIN 1 /* XPM */ static const char * nh_icon[] = { "40 40 6 1", " s None c none", ". c #ffffff", "X c #dadab6", "o c #6c91b6", "O c #476c6c", "+ c #000000", " ", " ", " ", " . .X..XX.XX X ", " .. .....X.XXXXXX XX ", " ... ....X..XX.XXXXX XXX ", " .. ..........X.XXXXXXXXXXX XX ", " .... ........X..XX.XXXXXXXXX XXXX ", " .... ..........X.XXXXXXXXXXX XXXX ", " ooOOO..ooooooOooOOoOOOOOOOXX+++OO++ ", " ooOOO..ooooooooOoOOOOOOOOOXX+++OO++ ", " ....O..ooooooOooOOoOOOOOOOXX+XXXX++ ", " ....O..ooooooooOoOOOOOOOOOXX+XXXX++ ", " ..OOO..ooooooOooOOoOOOOOOOXX+++XX++ ", " ++++..ooooooooOoOOOOOOOOOXX+++ +++ ", " +++..ooooooOooOOoOOOOOOOXX+++ + ", " ++..ooooooooOoOOOOOOOOOXX+++ ", " ..ooooooOooOOoOOOOOOOXX+++ ", " ..ooooooooOoOOOOOOOOOXX+++ ", " ..ooooooOooOOoOOOOOOOXX+++ ", " ..ooooooooOoOOOOOOOOOXX+++ ", " ..oooooOooOOoOOOOOOXX+++ ", " ..oooooooOoOOOOOOOOXX+++ ", " ..ooooOooOOoOOOOOXX+++ ", " ..ooooooOoOOOOOOOXX++++ ", " ..o..oooOooOOoOOOOXX+XX+++ ", " ...o..oooooOoOOOOOXX++XXX++ ", " ....OO..ooOooOOoOOXX+++XXXX++ ", " ...oo..+..oooOoOOOXX++XXooXXX++ ", " ...ooo..++..OooOOoXX+++XXooOXXX+ ", " ..oooOOXX+++....XXXX++++XXOOoOOXX+ ", " ..oooOOXX+++ ...XXX+++++XXOOooOXX++ ", " ..oooOXXX+++ ..XX+++ +XXOOooOXX++ ", " .....XXX++++ XXXXXXX++ ", " ....XX++++ XXXXXXX+ ", " ...XX+++ XXXXX++ ", " ", " ", " ", " "}; /* XPM */ static const char * nh_icon_small[] = { /* width height ncolors chars_per_pixel */ "16 16 16 1", /* colors */ " c #587070", ". c #D1D5C9", "X c #8B8C84", "o c #2A2A28", "O c #9AABA9", "+ c #6A8FB2", "@ c #C4CAC4", "# c #B6BEB6", "$ c None", "% c #54564E", "& c #476C6C", "* c #ADB2AB", "= c #ABABA2", "- c #5E8295", "; c #8B988F", ": c #E8EAE7", /* pixels */ "$$$$$$$$$$$$$$$$", "$$$.$#::.#==*$$$", "$.*:::::....#*=$", "$@#:..@#*==#;XX;", "$@O:+++- &&; X%X", "$#%.+++- &&;% oX", "$$o.++-- &&;%%X$", "$$$:++-- &&;%%$$", "$$$.O++- &&=o $$", "$$$=:++- & XoX$$", "$$*:@O-- ;%Xo$$", "$*:O#$+--;oOOX $", "$:+ =o::=oo=-;%X", "$::.%o$*;X;##@%$", "$$@# ;$$$$$=*;X$", "$$$$$$$$$$$$$$$$" }; /* XPM */ static const char * map_xpm[] = { "12 13 4 1", ". c None", " c #000000000000", "X c #0000B6DAFFFF", "o c #69A69248B6DA", " .", " XXXXX ooo ", " XoooX o ", " XoooX o o ", " XoooX ooo ", " XXoXX o ", " oooooXXX ", " oo o oooX ", " o XooX ", " oooo XooX ", " o o XXXX ", " ", ". "}; /* XPM */ static const char * msg_xpm[] = { "12 13 4 1", ". c None", " c #FFFFFFFFFFFF", "X c #69A69248B6DA", "o c #000000000000", " .", " XXX XXX X o", " o", " XXXXX XX o", " o", " XX XXXXX o", " o", " XXXXXX o", " o", " XX XXX XX o", " o", " o", ".ooooooooooo"}; /* XPM */ static const char * stat_xpm[] = { "12 13 5 1", " c None", ". c #FFFF00000000", "X c #000000000000", "o c #FFFFFFFF0000", "O c #69A6FFFF0000", " ", " ", "... ", "...X ", "...X ... ", "oooX oooX", "oooXooo oooX", "OOOXOOOXOOOX", "OOOXOOOXOOOX", "OOOXOOOXOOOX", "OOOXOOOXOOOX", "OOOXOOOXOOOX", " XXXXXXXXXXX"}; /* XPM */ static const char * info_xpm[] = { "12 13 4 1", " c None", ". c #00000000FFFF", "X c #FFFFFFFFFFFF", "o c #000000000000", " ... ", " ....... ", " ...XXX... ", " .........o ", "...XXXX.... ", "....XXX....o", "....XXX....o", "....XXX....o", " ...XXX...oo", " ..XXXXX..o ", " .......oo ", " o...ooo ", " ooo "}; /* XPM */ static const char * again_xpm[] = { "12 13 2 1", " c None", ". c #000000000000", " .. ", " .. ", " ..... ", " ....... ", "... .. .. ", ".. .. .. ", ".. ..", ".. ..", ".. ..", " .. .. ", " .......... ", " ...... ", " "}; /* XPM */ static const char * kick_xpm[] = { "12 13 3 1", " c None", ". c #000000000000", "X c #FFFF6DB60000", " ", " ", " . . . ", " ... . . ", " ... . ", " ... . ", " ... ", "XXX ... ", "XXX. ... ", "XXX. ... ", "XXX. .. ", " ... ", " "}; /* XPM */ static const char * throw_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " ", " ", " ", " ", ".... X ", "....X X ", "....X XXXXXX", "....X X ", " XXXX X ", " ", " ", " ", " "}; /* XPM */ static const char * fire_xpm[] = { "12 13 5 1", " c None", ". c #B6DA45140000", "X c #FFFFB6DA9658", "o c #000000000000", "O c #FFFF6DB60000", " . ", " X. ", " X . ", " X .o ", " X . o ", " X .o o ", "OOOOOOOOoooo", " X .o o ", " X . o o ", " X .o ", " X. o ", " . o ", " o "}; /* XPM */ static const char * get_xpm[] = { "12 13 3 1", " c None", ". c #000000000000", "X c #FFFF6DB60000", " ", " . ", " ... ", " . . . ", " . ", " . ", " ", " XXXXX ", " XXXXX. ", " XXXXX. ", " XXXXX. ", " ..... ", " "}; /* XPM */ static const char * drop_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " ", " ..... ", " .....X ", " .....X ", " .....X ", " XXXXX ", " ", " X ", " X ", " X X X ", " XXX ", " X ", " "}; /* XPM */ static const char * eat_xpm[] = { "12 13 4 1", " c None", ". c #000000000000", "X c #FFFFB6DA9658", "o c #FFFF6DB60000", " .X. .. ", " .X. .. ", " .X. .. ", " .X. .. ", " ... .. ", " .. .. ", " .. .. ", " oo oo ", " oo oo ", " oo oo ", " oo oo ", " oo oo ", " oo oo "}; /* XPM */ static const char * rest_xpm[] = { "12 13 2 1", " c None", ". c #000000000000", " ..... ", " . ", " . ", " . ....", " ..... . ", " . ", " ....", " ", " .... ", " . ", " . ", " .... ", " "}; /* XPM */ static const char * cast_a_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " . ", " . ", " .. ", " .. ", " .. . ", " .. . ", " ...... ", " .. .. XX ", " .. X X ", " .. X X ", " .. XXXX ", " . X X ", " . X X "}; /* XPM */ static const char * cast_b_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " . ", " . ", " .. ", " .. ", " .. . ", " .. . ", " ...... ", " .. .. XXX ", " .. X X ", " .. XXX ", " .. X X ", " . X X ", " . XXX "}; /* XPM */ static const char * cast_c_xpm[] = { "12 13 3 1", " c None", ". c #FFFF6DB60000", "X c #000000000000", " . ", " . ", " .. ", " .. ", " .. . ", " .. . ", " ...... ", " .. .. XX ", " .. X X ", " .. X ", " .. X ", " . X X ", " . XX "}; NetHackQtSettings::NetHackQtSettings(int w, int h) : tilewidth(TILEWMIN,64,1,this), tileheight(TILEHMIN,64,1,this), widthlbl(&tilewidth,"&Width:",this), heightlbl(&tileheight,"&Height:",this), whichsize("&Zoomed",this), fontsize(this), normal("times"), #ifdef WS_WIN normalfixed("courier new"), #else normalfixed("fixed"), #endif large("times"), theglyphs(0) { int default_fontsize; if (w<=300) { // ~240x320 default_fontsize=4; tilewidth.setValue(8); tileheight.setValue(12); } else if (w<=700) { // ~640x480 default_fontsize=3; tilewidth.setValue(8); tileheight.setValue(14); } else if (w<=900) { // ~800x600 default_fontsize=3; tilewidth.setValue(10); tileheight.setValue(17); } else if (w<=1100) { // ~1024x768 default_fontsize=2; tilewidth.setValue(12); tileheight.setValue(22); } else if (w<=1200) { // ~1152x900 default_fontsize=1; tilewidth.setValue(14); tileheight.setValue(26); } else { // ~1280x1024 and larger default_fontsize=0; tilewidth.setValue(16); tileheight.setValue(30); } // Tile/font sizes read from .nethackrc if (qt_tilewidth != NULL) { tilewidth.setValue(atoi(qt_tilewidth)); free(qt_tilewidth); } if (qt_tileheight != NULL) { tileheight.setValue(atoi(qt_tileheight)); free(qt_tileheight); } if (qt_fontsize != NULL) { switch (tolower(qt_fontsize[0])) { case 'h': default_fontsize = 0; break; case 'l': default_fontsize = 1; break; case 'm': default_fontsize = 2; break; case 's': default_fontsize = 3; break; case 't': default_fontsize = 4; break; } free(qt_fontsize); } theglyphs=new NetHackQtGlyphs(); resizeTiles(); connect(&tilewidth,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); connect(&tileheight,SIGNAL(valueChanged(int)),this,SLOT(resizeTiles())); connect(&whichsize,SIGNAL(toggled(bool)),this,SLOT(setGlyphSize(bool))); fontsize.insertItem("Huge"); fontsize.insertItem("Large"); fontsize.insertItem("Medium"); fontsize.insertItem("Small"); fontsize.insertItem("Tiny"); fontsize.setCurrentItem(default_fontsize); connect(&fontsize,SIGNAL(activated(int)),this,SIGNAL(fontChanged())); QGridLayout* grid = new QGridLayout(this, 5, 2, 8); grid->addMultiCellWidget(&whichsize, 0, 0, 0, 1); grid->addWidget(&tilewidth, 1, 1); grid->addWidget(&widthlbl, 1, 0); grid->addWidget(&tileheight, 2, 1); grid->addWidget(&heightlbl, 2, 0); QLabel* flabel=new QLabel(&fontsize, "&Font:",this); grid->addWidget(flabel, 3, 0); grid->addWidget(&fontsize, 3, 1); QPushButton* dismiss=new QPushButton("Dismiss",this); dismiss->setDefault(TRUE); grid->addMultiCellWidget(dismiss, 4, 4, 0, 1); grid->setRowStretch(4,0); grid->setColStretch(1,1); grid->setColStretch(2,2); grid->activate(); connect(dismiss,SIGNAL(clicked()),this,SLOT(accept())); resize(150,140); } NetHackQtGlyphs& NetHackQtSettings::glyphs() { return *theglyphs; } void NetHackQtSettings::resizeTiles() { int w = tilewidth.value(); int h = tileheight.value(); theglyphs->setSize(w,h); emit tilesChanged(); } void NetHackQtSettings::toggleGlyphSize() { whichsize.toggle(); } void NetHackQtSettings::setGlyphSize(bool which) { QSize n = QSize(tilewidth.value(),tileheight.value()); if ( othersize.isValid() ) { tilewidth.blockSignals(TRUE); tileheight.blockSignals(TRUE); tilewidth.setValue(othersize.width()); tileheight.setValue(othersize.height()); tileheight.blockSignals(FALSE); tilewidth.blockSignals(FALSE); resizeTiles(); } othersize = n; } const QFont& NetHackQtSettings::normalFont() { static int size[]={ 18, 14, 12, 10, 8 }; normal.setPointSize(size[fontsize.currentItem()]); return normal; } const QFont& NetHackQtSettings::normalFixedFont() { static int size[]={ 18, 14, 13, 10, 8 }; normalfixed.setPointSize(size[fontsize.currentItem()]); return normalfixed; } const QFont& NetHackQtSettings::largeFont() { static int size[]={ 24, 18, 14, 12, 10 }; large.setPointSize(size[fontsize.currentItem()]); return large; } bool NetHackQtSettings::ynInMessages() { return !qt_compact_mode; } NetHackQtSettings* qt_settings; NetHackQtKeyBuffer::NetHackQtKeyBuffer() : in(0), out(0) { } bool NetHackQtKeyBuffer::Empty() const { return in==out; } bool NetHackQtKeyBuffer::Full() const { return (in+1)%maxkey==out; } void NetHackQtKeyBuffer::Put(int k, int a, int state) { if ( Full() ) return; // Safety key[in]=k; ascii[in]=a; in=(in+1)%maxkey; } void NetHackQtKeyBuffer::Put(char a) { Put(0,a,0); } void NetHackQtKeyBuffer::Put(const char* str) { while (*str) Put(*str++); } int NetHackQtKeyBuffer::GetKey() { if ( Empty() ) return 0; int r=TopKey(); out=(out+1)%maxkey; return r; } int NetHackQtKeyBuffer::GetAscii() { if ( Empty() ) return 0; // Safety int r=TopAscii(); out=(out+1)%maxkey; return r; } int NetHackQtKeyBuffer::GetState() { if ( Empty() ) return 0; int r=TopState(); out=(out+1)%maxkey; return r; } int NetHackQtKeyBuffer::TopKey() const { if ( Empty() ) return 0; return key[out]; } int NetHackQtKeyBuffer::TopAscii() const { if ( Empty() ) return 0; return ascii[out]; } int NetHackQtKeyBuffer::TopState() const { if ( Empty() ) return 0; return state[out]; } NetHackQtClickBuffer::NetHackQtClickBuffer() : in(0), out(0) { } bool NetHackQtClickBuffer::Empty() const { return in==out; } bool NetHackQtClickBuffer::Full() const { return (in+1)%maxclick==out; } void NetHackQtClickBuffer::Put(int x, int y, int mod) { click[in].x=x; click[in].y=y; click[in].mod=mod; in=(in+1)%maxclick; } int NetHackQtClickBuffer::NextX() const { return click[out].x; } int NetHackQtClickBuffer::NextY() const { return click[out].y; } int NetHackQtClickBuffer::NextMod() const { return click[out].mod; } void NetHackQtClickBuffer::Get() { out=(out+1)%maxclick; } class NhPSListViewItem : public QListViewItem { public: NhPSListViewItem( QListView* parent, const QString& name ) : QListViewItem(parent, name) { } void setGlyph(int g) { NetHackQtGlyphs& glyphs = qt_settings->glyphs(); int gw = glyphs.width(); int gh = glyphs.height(); QPixmap pm(gw,gh); QPainter p(&pm); glyphs.drawGlyph(p, g, 0, 0); p.end(); setPixmap(0,pm); setHeight(QMAX(pm.height()+1,height())); } void paintCell( QPainter *p, const QColorGroup &cg, int column, int width, int alignment ) { if ( isSelectable() ) { QListViewItem::paintCell( p, cg, column, width, alignment ); } else { QColorGroup disabled( cg.foreground().light(), cg.button().light(), cg.light(), cg.dark(), cg.mid(), gray, cg.base() ); QListViewItem::paintCell( p, disabled, column, width, alignment ); } } }; class NhPSListViewRole : public NhPSListViewItem { public: NhPSListViewRole( QListView* parent, int id ) : NhPSListViewItem(parent, #ifdef QT_CHOOSE_RACE_FIRST // Lowerize - looks better QString(QChar(roles[id].name.m[0])).lower()+QString(roles[id].name.m+1) #else roles[id].name.m #endif ) { setGlyph(monnum_to_glyph(roles[id].malenum)); } }; class NhPSListViewRace : public NhPSListViewItem { public: NhPSListViewRace( QListView* parent, int id ) : NhPSListViewItem(parent, #ifdef QT_CHOOSE_RACE_FIRST // Capitalize - looks better QString(QChar(races[id].noun[0])).upper()+QString(races[id].noun+1) #else QString(QChar(races[id].noun[0])+QString(races[id].noun+1)) #endif ) { setGlyph(monnum_to_glyph(races[id].malenum)); } }; class NhPSListView : public QListView { public: NhPSListView( QWidget* parent ) : QListView(parent) { setSorting(-1); // order is identity header()->setClickEnabled(FALSE); } QSizePolicy sizePolicy() const { return QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); } QSize minimumSizeHint() const { return sizeHint(); } QSize sizeHint() const { QListView::sizeHint(); QSize sz = header()->sizeHint(); int h=0; QListViewItem* c=firstChild(); while (c) h+=c->height(),c = c->nextSibling(); sz += QSize(frameWidth()*2, h+frameWidth()*2); return sz; } int selectedItemNumber() const { int i=0; QListViewItem* c = firstChild(); while (c) { if (c == selectedItem()) { return i; } i++; c = c->nextSibling(); } return -1; } void setSelectedItemNumber(int i) { QListViewItem* c=firstChild(); while (i--) c = c->nextSibling(); c->setSelected(TRUE); } }; NetHackQtPlayerSelector::NetHackQtPlayerSelector(NetHackQtKeyBuffer& ks) : QDialog(qApp->mainWidget(),"plsel",TRUE), keysource(ks), fully_specified_role(TRUE) { /* 0 1 2 + Name ------------------------------------+ 0 | | + ---- ------------------------------------+ + Role ---+ + Race ---+ + Gender ------+ | | | | | * Male | 1 | | | | | * Female | | | | | +--------------+ | | | | | | | | + Alignment ---+ 2 | | | | | * Male | | | | | | * Female | | | | | +--------------+ 3 | | | | ...stretch... | | | | 4 | | | | [ Play ] 5 | | | | [ Quit ] +---------+ +---------+ */ int marg=4; QGridLayout *l = new QGridLayout(this,6,3,marg,marg); QButtonGroup* namebox = new QButtonGroup(1,Horizontal,"Name",this); QLineEdit* name = new QLineEdit(namebox); name->setMaxLength(sizeof(plname)-1); if ( strncmp(plname,"player",6) && strncmp(plname,"games",5) ) name->setText(plname); connect(name, SIGNAL(textChanged(const QString&)), this, SLOT(selectName(const QString&)) ); name->setFocus(); QButtonGroup* genderbox = new QButtonGroup("Sex",this); QButtonGroup* alignbox = new QButtonGroup("Alignment",this); QVBoxLayout* vbgb = new QVBoxLayout(genderbox,3,1); vbgb->setAutoAdd(TRUE); vbgb->addSpacing(fontMetrics().height()*3/4); QVBoxLayout* vbab = new QVBoxLayout(alignbox,3,1); vbab->setAutoAdd(TRUE); vbab->addSpacing(fontMetrics().height()); QLabel* logo = new QLabel(nh_attribution, this); l->addMultiCellWidget( namebox, 0,0,0,2 ); #ifdef QT_CHOOSE_RACE_FIRST race = new NhPSListView(this); role = new NhPSListView(this); l->addMultiCellWidget( race, 1,5,0,0 ); l->addMultiCellWidget( role, 1,5,1,1 ); #else role = new NhPSListView(this); race = new NhPSListView(this); l->addMultiCellWidget( role, 1,5,0,0 ); l->addMultiCellWidget( race, 1,5,1,1 ); #endif role->addColumn("Role"); race->addColumn("Race"); l->addWidget( genderbox, 1, 2 ); l->addWidget( alignbox, 2, 2 ); l->addWidget( logo, 3, 2, AlignCenter ); l->setRowStretch( 3, 5 ); int i; int nrole; for (nrole=0; roles[nrole].name.m; nrole++) ; for (i=nrole-1; i>=0; i--) { // XXX QListView unsorted goes in rev. new NhPSListViewRole( role, i ); } connect( role, SIGNAL(selectionChanged()), this, SLOT(selectRole()) ); int nrace; for (nrace=0; races[nrace].noun; nrace++) ; for (i=nrace-1; i>=0; i--) { new NhPSListViewRace( race, i ); } connect( race, SIGNAL(selectionChanged()), this, SLOT(selectRace()) ); gender = new QRadioButton*[ROLE_GENDERS]; for (i=0; iaddWidget( ok, 4, 2 ); ok->setDefault(TRUE); connect( ok, SIGNAL(clicked()), this, SLOT(accept()) ); QPushButton* cancel = new QPushButton("Quit",this); l->addWidget( cancel, 5, 2 ); connect( cancel, SIGNAL(clicked()), this, SLOT(reject()) ); // Randomize race and role, unless specified in config int ro = flags.initrole; if (ro == ROLE_NONE || ro == ROLE_RANDOM) { ro = rn2(nrole); if (flags.initrole != ROLE_RANDOM) { fully_specified_role = FALSE; } } int ra = flags.initrace; if (ra == ROLE_NONE || ra == ROLE_RANDOM) { ra = rn2(nrace); if (flags.initrace != ROLE_RANDOM) { fully_specified_role = FALSE; } } // make sure we have a valid combination, honoring // the users request if possible. bool choose_race_first; #ifdef QT_CHOOSE_RACE_FIRST choose_race_first = TRUE; if (flags.initrole >= 0 && flags.initrace < 0) { choose_race_first = FALSE; } #else choose_race_first = FALSE; if (flags.initrace >= 0 && flags.initrole < 0) { choose_race_first = TRUE; } #endif while (!validrace(ro,ra)) { if (choose_race_first) { ro = rn2(nrole); if (flags.initrole != ROLE_RANDOM) { fully_specified_role = FALSE; } } else { ra = rn2(nrace); if (flags.initrace != ROLE_RANDOM) { fully_specified_role = FALSE; } } } int g = flags.initgend; if (g == -1) { g = rn2(ROLE_GENDERS); fully_specified_role = FALSE; } while (!validgend(ro,ra,g)) { g = rn2(ROLE_GENDERS); } gender[g]->setChecked(TRUE); selectGender(g); int a = flags.initalign; if (a == -1) { a = rn2(ROLE_ALIGNS); fully_specified_role = FALSE; } while (!validalign(ro,ra,a)) { a = rn2(ROLE_ALIGNS); } alignment[a]->setChecked(TRUE); selectAlignment(a); QListViewItem* li; li = role->firstChild(); while (ro--) li=li->nextSibling(); role->setSelected(li,TRUE); li = race->firstChild(); while (ra--) li=li->nextSibling(); race->setSelected(li,TRUE); flags.initrace = race->selectedItemNumber(); flags.initrole = role->selectedItemNumber(); } void NetHackQtPlayerSelector::selectName(const QString& n) { strncpy(plname,n.latin1(),sizeof(plname)-1); } void NetHackQtPlayerSelector::selectRole() { int ra = race->selectedItemNumber(); int ro = role->selectedItemNumber(); if (ra == -1 || ro == -1) return; #ifdef QT_CHOOSE_RACE_FIRST selectRace(); #else QListViewItem* i=role->currentItem(); QListViewItem* valid=0; int j; NhPSListViewItem* item; item = (NhPSListViewItem*)role->firstChild(); for (j=0; roles[j].name.m; j++) { bool v = validrace(j,ra); item->setSelectable(TRUE); if ( !valid && v ) valid = item; item=(NhPSListViewItem*)item->nextSibling(); } if ( !validrace(role->selectedItemNumber(),ra) ) i = valid; role->setSelected(i,TRUE); item = (NhPSListViewItem*)role->firstChild(); for (j=0; roles[j].name.m; j++) { bool v = validrace(j,ra); item->setSelectable(v); item->repaint(); item=(NhPSListViewItem*)item->nextSibling(); } #endif flags.initrole = role->selectedItemNumber(); setupOthers(); } void NetHackQtPlayerSelector::selectRace() { int ra = race->selectedItemNumber(); int ro = role->selectedItemNumber(); if (ra == -1 || ro == -1) return; #ifndef QT_CHOOSE_RACE_FIRST selectRole(); #else QListViewItem* i=race->currentItem(); QListViewItem* valid=0; int j; NhPSListViewItem* item; item = (NhPSListViewItem*)race->firstChild(); for (j=0; races[j].noun; j++) { bool v = validrace(ro,j); item->setSelectable(TRUE); if ( !valid && v ) valid = item; item=(NhPSListViewItem*)item->nextSibling(); } if ( !validrace(ro,race->selectedItemNumber()) ) i = valid; race->setSelected(i,TRUE); item = (NhPSListViewItem*)race->firstChild(); for (j=0; races[j].noun; j++) { bool v = validrace(ro,j); item->setSelectable(v); item->repaint(); item=(NhPSListViewItem*)item->nextSibling(); } #endif flags.initrace = race->selectedItemNumber(); setupOthers(); } void NetHackQtPlayerSelector::setupOthers() { int ro = role->selectedItemNumber(); int ra = race->selectedItemNumber(); int valid=-1; int c=0; int j; for (j=0; jisChecked() ) c = j; gender[j]->setEnabled(v); if ( valid<0 && v ) valid = j; } if ( !validgend(ro,ra,c) ) c = valid; int k; for (k=0; ksetChecked(c==k); } selectGender(c); valid=-1; for (j=0; jisChecked() ) c = j; alignment[j]->setEnabled(v); if ( valid<0 && v ) valid = j; } if ( !validalign(ro,ra,c) ) c = valid; for (k=0; ksetChecked(c==k); } selectAlignment(c); } void NetHackQtPlayerSelector::selectGender(int i) { flags.initgend = i; } void NetHackQtPlayerSelector::selectAlignment(int i) { flags.initalign = i; } void NetHackQtPlayerSelector::done(int i) { setResult(i); qApp->exit_loop(); } void NetHackQtPlayerSelector::Quit() { done(R_Quit); qApp->exit_loop(); } void NetHackQtPlayerSelector::Random() { done(R_Rand); qApp->exit_loop(); } bool NetHackQtPlayerSelector::Choose() { if (fully_specified_role) return TRUE; #if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). if ( qt_compact_mode ) { showMaximized(); } else #endif { adjustSize(); centerOnMain(this); } if ( exec() ) { return TRUE; } else { return FALSE; } } NetHackQtStringRequestor::NetHackQtStringRequestor(NetHackQtKeyBuffer& ks, const char* p, const char* cancelstr) : QDialog(qApp->mainWidget(),"string",FALSE), prompt(p,this,"prompt"), input(this,"input"), keysource(ks) { cancel=new QPushButton(cancelstr,this); connect(cancel,SIGNAL(clicked()),this,SLOT(reject())); okay=new QPushButton("Okay",this); connect(okay,SIGNAL(clicked()),this,SLOT(accept())); connect(&input,SIGNAL(returnPressed()),this,SLOT(accept())); okay->setDefault(TRUE); setFocusPolicy(StrongFocus); } void NetHackQtStringRequestor::resizeEvent(QResizeEvent*) { const int margin=5; const int gutter=5; int h=(height()-margin*2-gutter); if (strlen(prompt.text()) > 16) { h/=3; prompt.setGeometry(margin,margin,width()-margin*2,h); input.setGeometry(width()*1/5,margin+h+gutter, (width()-margin-2-gutter)*4/5,h); } else { h/=2; prompt.setGeometry(margin,margin,(width()-margin*2-gutter)*2/5,h); input.setGeometry(prompt.geometry().right()+gutter,margin, (width()-margin-2-gutter)*3/5,h); } cancel->setGeometry(margin,input.geometry().bottom()+gutter, (width()-margin*2-gutter)/2,h); okay->setGeometry(cancel->geometry().right()+gutter,cancel->geometry().y(), cancel->width(),h); } void NetHackQtStringRequestor::SetDefault(const char* d) { input.setText(d); } bool NetHackQtStringRequestor::Get(char* buffer, int maxchar) { input.setMaxLength(maxchar); if (strlen(prompt.text()) > 16) { resize(fontMetrics().width(prompt.text())+50,fontMetrics().height()*6); } else { resize(fontMetrics().width(prompt.text())*2+50,fontMetrics().height()*4); } centerOnMain(this); show(); input.setFocus(); setResult(-1); while (result()==-1) { // Put keys in buffer (eg. from macros, from out-of-focus input) if (!keysource.Empty()) { while (!keysource.Empty()) { int key=keysource.TopKey(); int ascii=keysource.TopAscii(); int state=keysource.GetState(); if (ascii=='\r' || ascii=='\n') { // CR or LF in buffer causes confirmation strcpy(buffer,input.text()); return TRUE; } else if (ascii=='\033') { return FALSE; } else { input.fakeEvent(key,ascii,state); } } } qApp->enter_loop(); } // XXX Get rid of extra keys, since we couldn't get focus! while (!keysource.Empty()) keysource.GetKey(); if (result()) { strcpy(buffer,input.text()); return TRUE; } else { return FALSE; } } void NetHackQtStringRequestor::done(int i) { setResult(i); qApp->exit_loop(); } NetHackQtWindow::NetHackQtWindow() { } NetHackQtWindow::~NetHackQtWindow() { } // XXX Use "expected ..." for now, abort or default later. // void NetHackQtWindow::Clear() { puts("unexpected Clear"); } void NetHackQtWindow::Display(bool block) { puts("unexpected Display"); } bool NetHackQtWindow::Destroy() { return TRUE; } void NetHackQtWindow::CursorTo(int x,int y) { puts("unexpected CursorTo"); } void NetHackQtWindow::PutStr(int attr, const char* text) { puts("unexpected PutStr"); } void NetHackQtWindow::StartMenu() { puts("unexpected StartMenu"); } void NetHackQtWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel) { puts("unexpected AddMenu"); } void NetHackQtWindow::EndMenu(const char* prompt) { puts("unexpected EndMenu"); } int NetHackQtWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { puts("unexpected SelectMenu"); return 0; } void NetHackQtWindow::ClipAround(int x,int y) { puts("unexpected ClipAround"); } void NetHackQtWindow::PrintGlyph(int x,int y,int glyph) { puts("unexpected PrintGlyph"); } //void NetHackQtWindow::PrintGlyphCompose(int x,int y,int,int) { puts("unexpected PrintGlyphCompose"); } void NetHackQtWindow::UseRIP(int how) { puts("unexpected UseRIP"); } // XXX Hmmm... crash after saving bones file if Map window is // XXX deleted. Strange bug somewhere. bool NetHackQtMapWindow::Destroy() { return FALSE; } NetHackQtMapWindow::NetHackQtMapWindow(NetHackQtClickBuffer& click_sink) : clicksink(click_sink), change(10), rogue_font(0) { viewport.addChild(this); setBackgroundColor(black); viewport.setBackgroundColor(black); pet_annotation = QPixmap(qt_compact_mode ? pet_mark_small_xpm : pet_mark_xpm); cursor.setX(0); cursor.setY(0); Clear(); connect(qt_settings,SIGNAL(tilesChanged()),this,SLOT(updateTiles())); connect(&viewport, SIGNAL(contentsMoving(int,int)), this, SLOT(moveMessages(int,int))); updateTiles(); //setFocusPolicy(StrongFocus); } void NetHackQtMapWindow::moveMessages(int x, int y) { QRect u = messages_rect; messages_rect.moveTopLeft(QPoint(x,y)); u |= messages_rect; update(u); } void NetHackQtMapWindow::clearMessages() { messages = ""; update(messages_rect); messages_rect = QRect(); } void NetHackQtMapWindow::putMessage(int attr, const char* text) { if ( !messages.isEmpty() ) messages += "\n"; messages += text; QFontMetrics fm = fontMetrics(); messages_rect = fm.boundingRect(viewport.contentsX(),viewport.contentsY(),viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages); update(messages_rect); } void NetHackQtMapWindow::updateTiles() { NetHackQtGlyphs& glyphs = qt_settings->glyphs(); int gw = glyphs.width(); int gh = glyphs.height(); // Be exactly the size we want to be - full map... resize(COLNO*gw,ROWNO*gh); viewport.verticalScrollBar()->setSteps(gh,gh); viewport.horizontalScrollBar()->setSteps(gw,gw); /* viewport.setMaximumSize( gw*COLNO + viewport.verticalScrollBar()->width(), gh*ROWNO + viewport.horizontalScrollBar()->height() ); */ viewport.updateScrollBars(); change.clear(); change.add(0,0,COLNO,ROWNO); delete rogue_font; rogue_font = 0; Display(FALSE); emit resized(); } NetHackQtMapWindow::~NetHackQtMapWindow() { // Remove from viewport porthole, since that is a destructible member. viewport.removeChild(this); recreate(0,0,QPoint(0,0)); } QWidget* NetHackQtMapWindow::Widget() { return &viewport; } void NetHackQtMapWindow::Scroll(int dx, int dy) { if (viewport.horizontalScrollBar()->isVisible()) { while (dx<0) { viewport.horizontalScrollBar()->subtractPage(); dx++; } while (dx>0) { viewport.horizontalScrollBar()->addPage(); dx--; } } if (viewport.verticalScrollBar()->isVisible()) { while (dy<0) { viewport.verticalScrollBar()->subtractPage(); dy++; } while (dy>0) { viewport.verticalScrollBar()->addPage(); dy--; } } } void NetHackQtMapWindow::Clear() { unsigned short stone=cmap_to_glyph(S_stone); for (int j=0; jexit_loop(); } void NetHackQtMapWindow::mousePressEvent(QMouseEvent* event) { clicksink.Put( event->pos().x()/qt_settings->glyphs().width(), event->pos().y()/qt_settings->glyphs().height(), event->button()==LeftButton ? CLICK_1 : CLICK_2 ); qApp->exit_loop(); } #ifdef TEXTCOLOR static const QPen& nhcolor_to_pen(int c) { static QPen* pen=0; if ( !pen ) { pen = new QPen[17]; pen[0] = Qt::black; pen[1] = Qt::red; pen[2] = QColor(0,191,0); pen[3] = QColor(127,127,0); pen[4] = Qt::blue; pen[5] = Qt::magenta; pen[6] = Qt::cyan; pen[7] = Qt::gray; pen[8] = Qt::white; // no color pen[9] = QColor(255,127,0); pen[10] = QColor(127,255,127); pen[11] = Qt::yellow; pen[12] = QColor(127,127,255); pen[13] = QColor(255,127,255); pen[14] = QColor(127,255,255); pen[15] = Qt::white; pen[16] = Qt::black; } return pen[c]; } #endif void NetHackQtMapWindow::paintEvent(QPaintEvent* event) { QRect area=event->rect(); QRect garea; garea.setCoords( QMAX(0,area.left()/qt_settings->glyphs().width()), QMAX(0,area.top()/qt_settings->glyphs().height()), QMIN(COLNO-1,area.right()/qt_settings->glyphs().width()), QMIN(ROWNO-1,area.bottom()/qt_settings->glyphs().height()) ); QPainter painter; painter.begin(this); if ( #ifdef REINCARNATION Is_rogue_level(&u.uz) || #endif iflags.wc_ascii_map ) { // You enter a VERY primitive world! painter.setClipRect( event->rect() ); // (normally we don't clip) painter.fillRect( event->rect(), black ); if ( !rogue_font ) { // Find font... int pts = 5; QString fontfamily = iflags.wc_font_map ? iflags.wc_font_map : "Courier"; bool bold = FALSE; if ( fontfamily.right(5).lower() == "-bold" ) { fontfamily.truncate(fontfamily.length()-5); bold = TRUE; } while ( pts < 32 ) { QFont f(fontfamily, pts, bold ? QFont::Bold : QFont::Normal); painter.setFont(QFont(fontfamily, pts)); QFontMetrics fm = painter.fontMetrics(); if ( fm.width("M") > qt_settings->glyphs().width() ) break; if ( fm.height() > qt_settings->glyphs().height() ) break; pts++; } rogue_font = new QFont(fontfamily,pts-1); } painter.setFont(*rogue_font); for (int j=garea.top(); j<=garea.bottom(); j++) { for (int i=garea.left(); i<=garea.right(); i++) { unsigned short g=Glyph(i,j); uchar ch; int color, och; unsigned special; painter.setPen( green ); /* map glyph to character and color */ mapglyph(g, &och, &color, &special, i, j); ch = (uchar)och; #ifdef TEXTCOLOR painter.setPen( nhcolor_to_pen(color) ); #endif painter.drawText( i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height(), qt_settings->glyphs().width(), qt_settings->glyphs().height(), AlignCenter, (const char*)&ch, 1 ); if (glyph_is_pet(g) #ifdef TEXTCOLOR && ::iflags.hilite_pet #endif ) { painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); } } } painter.setFont(font()); } else { for (int j=garea.top(); j<=garea.bottom(); j++) { for (int i=garea.left(); i<=garea.right(); i++) { unsigned short g=Glyph(i,j); qt_settings->glyphs().drawCell(painter, g, i, j); if (glyph_is_pet(g) #ifdef TEXTCOLOR && ::iflags.hilite_pet #endif ) { painter.drawPixmap(QPoint(i*qt_settings->glyphs().width(), j*qt_settings->glyphs().height()), pet_annotation); } } } } if (garea.contains(cursor)) { #ifdef REINCARNATION if (Is_rogue_level(&u.uz)) { #ifdef TEXTCOLOR painter.setPen( white ); #else painter.setPen( green ); // REALLY primitive #endif } else #endif { int hp100; if (u.mtimedone) { hp100=u.mhmax ? u.mh*100/u.mhmax : 100; } else { hp100=u.uhpmax ? u.uhp*100/u.uhpmax : 100; } if (hp100 > 75) painter.setPen(white); else if (hp100 > 50) painter.setPen(yellow); else if (hp100 > 25) painter.setPen(QColor(0xff,0xbf,0x00)); // orange else if (hp100 > 10) painter.setPen(red); else painter.setPen(magenta); } painter.drawRect( cursor.x()*qt_settings->glyphs().width(),cursor.y()*qt_settings->glyphs().height(), qt_settings->glyphs().width(),qt_settings->glyphs().height()); } if (area.intersects(messages_rect)) { painter.setPen(black); painter.drawText(viewport.contentsX()+1,viewport.contentsY()+1, viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages); painter.setPen(white); painter.drawText(viewport.contentsX(),viewport.contentsY(), viewport.width(),0, WordBreak|AlignTop|AlignLeft|DontClip, messages); } painter.end(); } void NetHackQtMapWindow::Display(bool block) { for (int i=0; iglyphs().width(), ch.y()*qt_settings->glyphs().height(), ch.width()*qt_settings->glyphs().width(), ch.height()*qt_settings->glyphs().height(), FALSE ); } change.clear(); if (block) { yn_function("Press a key when done viewing",0,'\0'); } } void NetHackQtMapWindow::CursorTo(int x,int y) { Changed(cursor.x(),cursor.y()); cursor.setX(x); cursor.setY(y); Changed(cursor.x(),cursor.y()); } void NetHackQtMapWindow::PutStr(int attr, const char* text) { puts("unexpected PutStr in MapWindow"); } void NetHackQtMapWindow::ClipAround(int x,int y) { // Convert to pixel of center of tile x=x*qt_settings->glyphs().width()+qt_settings->glyphs().width()/2; y=y*qt_settings->glyphs().height()+qt_settings->glyphs().height()/2; // Then ensure that pixel is visible viewport.center(x,y,0.45,0.45); } void NetHackQtMapWindow::PrintGlyph(int x,int y,int glyph) { Glyph(x,y)=glyph; Changed(x,y); } //void NetHackQtMapWindow::PrintGlyphCompose(int x,int y,int glyph1, int glyph2) //{ // TODO: composed graphics //} void NetHackQtMapWindow::Changed(int x, int y) { change.add(x,y); } class NetHackQtScrollText : public QTableView { struct UData { UData() : text(0), attr(0) { } ~UData() { if (text) free(text); } char* text; int attr; }; public: int uncleared; NetHackQtScrollText(int maxlength) : uncleared(0), maxitems(maxlength), first(0), count(0), item_cycle(maxlength) { setNumCols(1); setCellWidth(200); setCellHeight(fontMetrics().height()); setBackgroundColor(white); setTableFlags(Tbl_vScrollBar |Tbl_autoHScrollBar |Tbl_clipCellPainting |Tbl_smoothScrolling); } ~NetHackQtScrollText() { } void Scroll(int dx, int dy) { setXOffset(xOffset()+dx*viewWidth()); setYOffset(yOffset()+dy*viewHeight()); } void insertItem(int attr, const char* text) { setTopCell(count); setAutoUpdate(FALSE); int i; if (count cellWidth()) { // Get wider. setCellWidth(w); } setTopCell(count); setAutoUpdate(TRUE); if (viewHeight() >= totalHeight()-cellHeight()) { repaint(); } else { scroll(0,cellHeight()); } } virtual void setFont(const QFont& font) { QTableView::setFont(font); setCellHeight(fontMetrics().height()); } protected: UData& item(int i) { return item_cycle[(first+i)%maxitems]; } const int maxitems; int first, count; QArray item_cycle; int datumWidth(const UData& uitem) { if (uitem.text) { int width=fontMetrics().width(uitem.text)+3; if (uitem.attr) { // XXX Too expensive to do properly, because // XXX we have to set the font of the widget // XXX just to get the font metrics information! // XXX Could hold a fake widget for that // XXX purpose, but this hack is less ugly. width+=width/10; } return width; } else { return 0; } } virtual void setupPainter(QPainter *p) { // XXX This shouldn't be needed - we set the bg in the constructor. p->setBackgroundColor(white); } virtual void paintCell(QPainter *p, int row, int col) { bool sel=FALSE; UData& uitem=item(row); if (!sel && row < count-uncleared) { p->setPen(darkGray); } else { p->setPen(black); } if (uitem.attr) { // XXX only bold QFont bold(font().family(),font().pointSize(),QFont::Bold); p->setFont(bold); } p->drawText(3, 0, cellWidth(), cellHeight(), AlignLeft|AlignVCenter, uitem.text); if (uitem.attr) { p->setFont(font()); } } }; NetHackQtMessageWindow::NetHackQtMessageWindow() : list(new NetHackQtScrollText(::iflags.msg_history)) { ::iflags.window_inited = 1; map = 0; connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(updateFont())); updateFont(); } NetHackQtMessageWindow::~NetHackQtMessageWindow() { ::iflags.window_inited = 0; delete list; } QWidget* NetHackQtMessageWindow::Widget() { return list; } void NetHackQtMessageWindow::setMap(NetHackQtMapWindow* m) { map = m; updateFont(); } void NetHackQtMessageWindow::updateFont() { list->setFont(qt_settings->normalFont()); if ( map ) map->setFont(qt_settings->normalFont()); } void NetHackQtMessageWindow::Scroll(int dx, int dy) { list->Scroll(dx,dy); } void NetHackQtMessageWindow::Clear() { if ( map ) map->clearMessages(); if (list->uncleared) { list->uncleared=0; changed=TRUE; Display(FALSE); } } void NetHackQtMessageWindow::Display(bool block) { if (changed) { list->repaint(); changed=FALSE; } } void NetHackQtMessageWindow::PutStr(int attr, const char* text) { #ifdef USER_SOUNDS play_sound_for_message(text); #endif changed=TRUE; list->uncleared++; list->insertItem(attr,text); // Force scrollbar to bottom // XXX list->setTopItem(list->count()); if ( map ) map->putMessage(attr, text); } NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l) : QWidget(parent), low_is_good(FALSE), prev_value(-123), turn_count(-1), label(new QLabel(l,this)), icon(0) { initHighlight(); } NetHackQtLabelledIcon::NetHackQtLabelledIcon(QWidget* parent, const char* l, const QPixmap& i) : QWidget(parent), low_is_good(FALSE), prev_value(-123), turn_count(-1), label(new QLabel(l,this)), icon(new QLabel(this)) { setIcon(i); initHighlight(); } void NetHackQtLabelledIcon::initHighlight() { const QPalette& pal=palette(); const QColorGroup& pa=pal.normal(); //QColorGroup good(white,darkGreen,pa.light(),pa.dark(),pa.mid(),white,pa.base()); QColorGroup good(black,green,pa.light(),pa.dark(),pa.mid(),black,pa.base()); QColorGroup bad(white,red,pa.light(),pa.dark(),pa.mid(),white,pa.base()); hl_good=pal.copy(); hl_good.setNormal(good); hl_good.setActive(good); hl_bad=pal.copy(); hl_bad.setNormal(bad); hl_bad.setActive(bad); } void NetHackQtLabelledIcon::setLabel(const char* t, bool lower) { if (!label) { label=new QLabel(this); label->setFont(font()); resizeEvent(0); } if (0!=strcmp(label->text(),t)) { label->setText(t); highlight(lower==low_is_good ? hl_good : hl_bad); } } void NetHackQtLabelledIcon::setLabel(const char* t, long v, long cv, const char* tail) { char buf[BUFSZ]; if (v==NoNum) { Sprintf(buf,"%s%s",t,tail); } else { Sprintf(buf,"%s%ld%s",t,v,tail); } setLabel(buf,cvsetPixmap(i); else { icon=new QLabel(this); icon->setPixmap(i); resizeEvent(0); } icon->resize(i.width(),i.height()); } void NetHackQtLabelledIcon::setFont(const QFont& f) { QWidget::setFont(f); if (label) label->setFont(f); } void NetHackQtLabelledIcon::show() { #if QT_VERSION >= 300 if (isHidden()) #else if (!isVisible()) #endif highlight(hl_bad); QWidget::show(); } void NetHackQtLabelledIcon::highlightWhenChanging() { turn_count=0; } void NetHackQtLabelledIcon::lowIsGood() { low_is_good=TRUE; } void NetHackQtLabelledIcon::dissipateHighlight() { if (turn_count>0) { turn_count--; if (!turn_count) unhighlight(); } } void NetHackQtLabelledIcon::highlight(const QPalette& hl) { if (label) { // Surely it is?! if (turn_count>=0) { label->setPalette(hl); turn_count=4; // `4' includes this turn, so dissipates after // 3 more keypresses. } else { label->setPalette(palette()); } } } void NetHackQtLabelledIcon::unhighlight() { if (label) { // Surely it is?! label->setPalette(palette()); } } void NetHackQtLabelledIcon::resizeEvent(QResizeEvent*) { setAlignments(); //int labw=label ? label->fontMetrics().width(label->text()) : 0; int labh=label ? label->fontMetrics().height() : 0; int icoh=icon ? icon->height() : 0; int h=icoh+labh; int icoy=(h>height() ? height()-labh-icoh : height()/2-h/2); int laby=icoy+icoh; if (icon) { icon->setGeometry(0,icoy,width(),icoh); } if (label) { label->setGeometry(0,laby,width(),labh); } } void NetHackQtLabelledIcon::setAlignments() { if (label) label->setAlignment(AlignHCenter|AlignVCenter); if (icon) icon->setAlignment(AlignHCenter|AlignVCenter); } static void tryload(QPixmap& pm, const char* fn) { if (!pm.load(fn)) { QString msg; msg.sprintf("Cannot load \"%s\"", fn); QMessageBox::warning(qApp->mainWidget(), "IO Error", msg); } } NetHackQtStatusWindow::NetHackQtStatusWindow() : // Notes: // Alignment needs -2 init value, because -1 is an alignment. // Armor Class is an schar, so 256 is out of range. // Blank value is 0 and should never change. name(this,"(name)"), dlevel(this,"(dlevel)"), str(this,"STR"), dex(this,"DEX"), con(this,"CON"), intel(this,"INT"), wis(this,"WIS"), cha(this,"CHA"), gold(this,"Gold"), hp(this,"Hit Points"), power(this,"Power"), ac(this,"Armour Class"), level(this,"Level"), exp(this,"Experience"), align(this,"Alignment"), time(this,"Time"), score(this,"Score"), hunger(this,""), confused(this,"Confused"), sick_fp(this,"Sick"), sick_il(this,"Ill"), blind(this,"Blind"), stunned(this,"Stunned"), hallu(this,"Hallu"), encumber(this,""), hline1(this), hline2(this), hline3(this), first_set(TRUE) { p_str = QPixmap(str_xpm); p_str = QPixmap(str_xpm); p_dex = QPixmap(dex_xpm); p_con = QPixmap(cns_xpm); p_int = QPixmap(int_xpm); p_wis = QPixmap(wis_xpm); p_cha = QPixmap(cha_xpm); p_chaotic = QPixmap(chaotic_xpm); p_neutral = QPixmap(neutral_xpm); p_lawful = QPixmap(lawful_xpm); p_satiated = QPixmap(satiated_xpm); p_hungry = QPixmap(hungry_xpm); p_confused = QPixmap(confused_xpm); p_sick_fp = QPixmap(sick_fp_xpm); p_sick_il = QPixmap(sick_il_xpm); p_blind = QPixmap(blind_xpm); p_stunned = QPixmap(stunned_xpm); p_hallu = QPixmap(hallu_xpm); p_encumber[0] = QPixmap(slt_enc_xpm); p_encumber[1] = QPixmap(mod_enc_xpm); p_encumber[2] = QPixmap(hvy_enc_xpm); p_encumber[3] = QPixmap(ext_enc_xpm); p_encumber[4] = QPixmap(ovr_enc_xpm); str.setIcon(p_str); dex.setIcon(p_dex); con.setIcon(p_con); intel.setIcon(p_int); wis.setIcon(p_wis); cha.setIcon(p_cha); align.setIcon(p_neutral); hunger.setIcon(p_hungry); confused.setIcon(p_confused); sick_fp.setIcon(p_sick_fp); sick_il.setIcon(p_sick_il); blind.setIcon(p_blind); stunned.setIcon(p_stunned); hallu.setIcon(p_hallu); encumber.setIcon(p_encumber[0]); hline1.setFrameStyle(QFrame::HLine|QFrame::Sunken); hline2.setFrameStyle(QFrame::HLine|QFrame::Sunken); hline3.setFrameStyle(QFrame::HLine|QFrame::Sunken); hline1.setLineWidth(1); hline2.setLineWidth(1); hline3.setLineWidth(1); connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); doUpdate(); } void NetHackQtStatusWindow::doUpdate() { const QFont& large=qt_settings->largeFont(); name.setFont(large); dlevel.setFont(large); const QFont& normal=qt_settings->normalFont(); str.setFont(normal); dex.setFont(normal); con.setFont(normal); intel.setFont(normal); wis.setFont(normal); cha.setFont(normal); gold.setFont(normal); hp.setFont(normal); power.setFont(normal); ac.setFont(normal); level.setFont(normal); exp.setFont(normal); align.setFont(normal); time.setFont(normal); score.setFont(normal); hunger.setFont(normal); confused.setFont(normal); sick_fp.setFont(normal); sick_il.setFont(normal); blind.setFont(normal); stunned.setFont(normal); hallu.setFont(normal); encumber.setFont(normal); updateStats(); } QWidget* NetHackQtStatusWindow::Widget() { return this; } void NetHackQtStatusWindow::Clear() { } void NetHackQtStatusWindow::Display(bool block) { } void NetHackQtStatusWindow::CursorTo(int,int y) { cursy=y; } void NetHackQtStatusWindow::PutStr(int attr, const char* text) { // do a complete update when line 0 is done (as per X11 fancy status) if (cursy==0) updateStats(); } void NetHackQtStatusWindow::resizeEvent(QResizeEvent*) { const float SP_name=0.13; // the (large) const float SP_dlev=0.13; // Level 3 in The Dungeons of Doom (large) const float SP_atr1=0.25; // STR DEX CON INT WIS CHA const float SP_hln1=0.02; // --- const float SP_atr2=0.09; // Au HP PW AC LVL EXP const float SP_hln2=0.02; // --- const float SP_time=0.09; // time score const float SP_hln3=0.02; // --- const float SP_stat=0.25; // Alignment, Poisoned, Hungry, Sick, etc. int h=height(); int x=0,y=0; int iw; // Width of an item across line int lh; // Height of a line of values lh=int(h*SP_name); name.setGeometry(0,0,width(),lh); y+=lh; lh=int(h*SP_dlev); dlevel.setGeometry(0,y,width(),lh); y+=lh; lh=int(h*SP_hln1); hline1.setGeometry(0,y,width(),lh); y+=lh; lh=int(h*SP_atr1); iw=width()/6; str.setGeometry(x,y,iw,lh); x+=iw; dex.setGeometry(x,y,iw,lh); x+=iw; con.setGeometry(x,y,iw,lh); x+=iw; intel.setGeometry(x,y,iw,lh); x+=iw; wis.setGeometry(x,y,iw,lh); x+=iw; cha.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; lh=int(h*SP_hln2); hline2.setGeometry(0,y,width(),lh); y+=lh; lh=int(h*SP_atr2); iw=width()/6; gold.setGeometry(x,y,iw,lh); x+=iw; hp.setGeometry(x,y,iw,lh); x+=iw; power.setGeometry(x,y,iw,lh); x+=iw; ac.setGeometry(x,y,iw,lh); x+=iw; level.setGeometry(x,y,iw,lh); x+=iw; exp.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; lh=int(h*SP_hln3); hline3.setGeometry(0,y,width(),lh); y+=lh; lh=int(h*SP_time); iw=width()/3; x+=iw/2; time.setGeometry(x,y,iw,lh); x+=iw; score.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; lh=int(h*SP_stat); iw=width()/9; align.setGeometry(x,y,iw,lh); x+=iw; hunger.setGeometry(x,y,iw,lh); x+=iw; confused.setGeometry(x,y,iw,lh); x+=iw; sick_fp.setGeometry(x,y,iw,lh); x+=iw; sick_il.setGeometry(x,y,iw,lh); x+=iw; blind.setGeometry(x,y,iw,lh); x+=iw; stunned.setGeometry(x,y,iw,lh); x+=iw; hallu.setGeometry(x,y,iw,lh); x+=iw; encumber.setGeometry(x,y,iw,lh); x+=iw; x=0; y+=lh; } /* * Set all widget values to a null string. This is used after all spacings * have been calculated so that when the window is popped up we don't get all * kinds of funny values being displayed. */ void NetHackQtStatusWindow::nullOut() { } void NetHackQtStatusWindow::fadeHighlighting() { name.dissipateHighlight(); dlevel.dissipateHighlight(); str.dissipateHighlight(); dex.dissipateHighlight(); con.dissipateHighlight(); intel.dissipateHighlight(); wis.dissipateHighlight(); cha.dissipateHighlight(); gold.dissipateHighlight(); hp.dissipateHighlight(); power.dissipateHighlight(); ac.dissipateHighlight(); level.dissipateHighlight(); exp.dissipateHighlight(); align.dissipateHighlight(); time.dissipateHighlight(); score.dissipateHighlight(); hunger.dissipateHighlight(); confused.dissipateHighlight(); sick_fp.dissipateHighlight(); sick_il.dissipateHighlight(); blind.dissipateHighlight(); stunned.dissipateHighlight(); hallu.dissipateHighlight(); encumber.dissipateHighlight(); } /* * Update the displayed status. The current code in botl.c updates * two lines of information. Both lines are always updated one after * the other. So only do our update when we update the second line. * * Information on the first line: * name, attributes, alignment, score * * Information on the second line: * dlvl, gold, hp, power, ac, {level & exp or HD **} * status (hunger, conf, halu, stun, sick, blind), time, encumbrance * * [**] HD is shown instead of level and exp if mtimedone is non-zero. */ void NetHackQtStatusWindow::updateStats() { if (!parentWidget()) return; char buf[BUFSZ]; if (cursy != 0) return; /* do a complete update when line 0 is done */ if (ACURR(A_STR) > 118) { Sprintf(buf,"STR:%d",ACURR(A_STR)-100); } else if (ACURR(A_STR)==118) { Sprintf(buf,"STR:18/**"); } else if(ACURR(A_STR) > 18) { Sprintf(buf,"STR:18/%02d",ACURR(A_STR)-18); } else { Sprintf(buf,"STR:%d",ACURR(A_STR)); } str.setLabel(buf,NetHackQtLabelledIcon::NoNum,ACURR(A_STR)); dex.setLabel("DEX:",(long)ACURR(A_DEX)); con.setLabel("CON:",(long)ACURR(A_CON)); intel.setLabel("INT:",(long)ACURR(A_INT)); wis.setLabel("WIS:",(long)ACURR(A_WIS)); cha.setLabel("CHA:",(long)ACURR(A_CHA)); const char* hung=hu_stat[u.uhs]; if (hung[0]==' ') { hunger.hide(); } else { hunger.setIcon(u.uhs ? p_hungry : p_satiated); hunger.setLabel(hung); hunger.show(); } if (Confusion) confused.show(); else confused.hide(); if (Sick) { if (u.usick_type & SICK_VOMITABLE) { sick_fp.show(); } else { sick_fp.hide(); } if (u.usick_type & SICK_NONVOMITABLE) { sick_il.show(); } else { sick_il.hide(); } } else { sick_fp.hide(); sick_il.hide(); } if (Blind) blind.show(); else blind.hide(); if (Stunned) stunned.show(); else stunned.hide(); if (Hallucination) hallu.show(); else hallu.hide(); const char* enc=enc_stat[near_capacity()]; if (enc[0]==' ' || !enc[0]) { encumber.hide(); } else { encumber.setIcon(p_encumber[near_capacity()-1]); encumber.setLabel(enc); encumber.show(); } Strcpy(buf, plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a'; Strcat(buf, " the "); if (u.mtimedone) { char mname[BUFSZ]; int k = 0; Strcpy(mname, mons[u.umonnum].mname); while(mname[k] != 0) { if ((k == 0 || (k > 0 && mname[k-1] == ' ')) && 'a' <= mname[k] && mname[k] <= 'z') { mname[k] += 'A' - 'a'; } k++; } Strcat(buf, mname); } else { Strcat(buf, rank_of(u.ulevel, pl_character[0], ::flags.female)); } name.setLabel(buf,NetHackQtLabelledIcon::NoNum,u.ulevel); if (describe_level(buf)) { dlevel.setLabel(buf,(bool)TRUE); } else { Sprintf(buf, "%s, level ", dungeons[u.uz.dnum].dname); dlevel.setLabel(buf,(long)depth(&u.uz)); } #ifndef GOLDOBJ gold.setLabel("Au:", u.ugold); #else gold.setLabel("Au:", money_cnt(invent)); #endif if (u.mtimedone) { // You're a monster! Sprintf(buf, "/%d", u.mhmax); hp.setLabel("HP:",u.mh > 0 ? u.mh : 0,buf); level.setLabel("HD:",(long)mons[u.umonnum].mlevel); } else { // You're normal. Sprintf(buf, "/%d", u.uhpmax); hp.setLabel("HP:",u.uhp > 0 ? u.uhp : 0,buf); level.setLabel("Level:",(long)u.ulevel); } Sprintf(buf, "/%d", u.uenmax); power.setLabel("Pow:",u.uen,buf); ac.setLabel("AC:",(long)u.uac); #ifdef EXP_ON_BOTL if (::flags.showexp) { exp.setLabel("Exp:",(long)u.uexp); } else #endif { exp.setLabel(""); } if (u.ualign.type==A_CHAOTIC) { align.setIcon(p_chaotic); align.setLabel("Chaotic"); } else if (u.ualign.type==A_NEUTRAL) { align.setIcon(p_neutral); align.setLabel("Neutral"); } else { align.setIcon(p_lawful); align.setLabel("Lawful"); } if (::flags.time) time.setLabel("Time:",(long)moves); else time.setLabel(""); #ifdef SCORE_ON_BOTL if (::flags.showscore) { score.setLabel("Score:",(long)botl_score()); } else #endif { score.setLabel(""); } if (first_set) { first_set=FALSE; name.highlightWhenChanging(); dlevel.highlightWhenChanging(); str.highlightWhenChanging(); dex.highlightWhenChanging(); con.highlightWhenChanging(); intel.highlightWhenChanging(); wis.highlightWhenChanging(); cha.highlightWhenChanging(); gold.highlightWhenChanging(); hp.highlightWhenChanging(); power.highlightWhenChanging(); ac.highlightWhenChanging(); ac.lowIsGood(); level.highlightWhenChanging(); exp.highlightWhenChanging(); align.highlightWhenChanging(); //time.highlightWhenChanging(); score.highlightWhenChanging(); hunger.highlightWhenChanging(); confused.highlightWhenChanging(); sick_fp.highlightWhenChanging(); sick_il.highlightWhenChanging(); blind.highlightWhenChanging(); stunned.highlightWhenChanging(); hallu.highlightWhenChanging(); encumber.highlightWhenChanging(); } } /* * Turn off hilighted status values after a certain amount of turns. */ void NetHackQtStatusWindow::checkTurnEvents() { } NetHackQtMenuDialog::NetHackQtMenuDialog() : QDialog(qApp->mainWidget(),0,FALSE) { } void NetHackQtMenuDialog::resizeEvent(QResizeEvent*) { emit Resized(); } void NetHackQtMenuDialog::Accept() { accept(); } void NetHackQtMenuDialog::Reject() { reject(); } void NetHackQtMenuDialog::SetResult(int r) { setResult(r); } void NetHackQtMenuDialog::done(int i) { setResult(i); qApp->exit_loop(); } // Table view columns: // // [pick-count] [accel] [glyph] [string] // // Maybe accel should be near string. We'll see. // pick-count normally blank. // double-clicking or click-on-count gives pop-up entry // string is green when selected // NetHackQtMenuWindow::NetHackQtMenuWindow(NetHackQtKeyBuffer& ks) : QTableView(), keysource(ks), dialog(new NetHackQtMenuDialog()), prompt(0), pressed(-1) { setNumCols(4); setCellHeight(QMAX(qt_settings->glyphs().height()+1,fontMetrics().height())); setBackgroundColor(lightGray); setFrameStyle(Panel|Sunken); setLineWidth(2); ok=new QPushButton("Ok",dialog); connect(ok,SIGNAL(clicked()),dialog,SLOT(accept())); cancel=new QPushButton("Cancel",dialog); connect(cancel,SIGNAL(clicked()),dialog,SLOT(reject())); all=new QPushButton("All",dialog); connect(all,SIGNAL(clicked()),this,SLOT(All())); none=new QPushButton("None",dialog); connect(none,SIGNAL(clicked()),this,SLOT(ChooseNone())); invert=new QPushButton("Invert",dialog); connect(invert,SIGNAL(clicked()),this,SLOT(Invert())); search=new QPushButton("Search",dialog); connect(search,SIGNAL(clicked()),this,SLOT(Search())); QPoint pos(0,ok->height()); recreate(dialog,0,pos); prompt.recreate(dialog,0,pos); setBackgroundColor(lightGray); connect(dialog,SIGNAL(Resized()),this,SLOT(Layout())); setTableFlags(Tbl_autoHScrollBar|Tbl_autoVScrollBar |Tbl_smoothScrolling|Tbl_clipCellPainting); setFocusPolicy(StrongFocus); } NetHackQtMenuWindow::~NetHackQtMenuWindow() { // Remove from dialog before we destruct it recreate(0,0,QPoint(0,0)); delete dialog; } void NetHackQtMenuWindow::focusInEvent(QFocusEvent *) { // Don't repaint at all, since nothing is using the focus colour } void NetHackQtMenuWindow::focusOutEvent(QFocusEvent *) { // Don't repaint at all, since nothing is using the focus colour } int NetHackQtMenuWindow::cellWidth(int col) { switch (col) { case 0: return fontMetrics().width("All "); break; case 1: return fontMetrics().width(" m "); break; case 2: return qt_settings->glyphs().width(); break; case 3: return str_width; } impossible("Extra column (#%d) in MenuWindow",col); return 0; } QWidget* NetHackQtMenuWindow::Widget() { return dialog; } void NetHackQtMenuWindow::StartMenu() { setNumRows((itemcount=0)); str_width=200; str_fixed=FALSE; next_accel=0; has_glyphs=FALSE; } NetHackQtMenuWindow::MenuItem::MenuItem() : str(0) { } NetHackQtMenuWindow::MenuItem::~MenuItem() { if (str) free((void*)str); } #define STR_MARGIN 4 void NetHackQtMenuWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel) { if (!ch && identifier->a_void!=0) { // Supply a keyboard accelerator. Limited supply. static char accel[]="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; if (accel[next_accel]) { ch=accel[next_accel++]; } } if ((int)item.size() < itemcount+1) { item.resize(itemcount*4+10); } item[itemcount].glyph=glyph; item[itemcount].identifier=*identifier; item[itemcount].ch=ch; item[itemcount].attr=attr; item[itemcount].str=strdup(str); item[itemcount].selected=presel; item[itemcount].count=-1; ++itemcount; str_fixed=str_fixed || strstr(str," "); if (glyph!=NO_GLYPH) has_glyphs=TRUE; } void NetHackQtMenuWindow::EndMenu(const char* p) { prompt.setText(p ? p : ""); } void NetHackQtMenuWindow::Layout() { int butw=totalWidth()/6; // 6 buttons int buth=fontMetrics().height()+8; // 8 for spacing & mitres int prompth=(prompt.text().isNull() ? 0 : buth); prompt.setGeometry(6,buth,dialog->width()-6,prompth); int h=dialog->height()-buth-prompth; setGeometry(0,buth+prompth, dialog->width(), h); // Below, we take care to use up full width int x=0; ok->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/5; cancel->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/4; all->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/3; none->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/2; invert->setGeometry(x,0,butw,buth); x+=butw; butw=(dialog->width()-x)/1; search->setGeometry(x,0,butw,buth); } int NetHackQtMenuWindow::SelectMenu(int h, MENU_ITEM_P **menu_list) { setFont(str_fixed ? qt_settings->normalFixedFont() : qt_settings->normalFont()); for (int i=0; iglyphs().height()+1,fontMetrics().height())); setNumRows(itemcount); int buth=fontMetrics().height()+8; // 8 for spacing & mitres how=h; ok->setEnabled(how!=PICK_ONE);ok->setDefault(how!=PICK_ONE); cancel->setEnabled(how!=PICK_NONE); all->setEnabled(how==PICK_ANY); none->setEnabled(how==PICK_ANY); invert->setEnabled(how==PICK_ANY); search->setEnabled(how!=PICK_NONE); dialog->SetResult(-1); // 20 allows for scrollbar or spacing // 4 for frame borders int mh = QApplication::desktop()->height()*3/5; if ( qt_compact_mode && totalHeight() > mh ) { // big, so make it fill dialog->showMaximized(); } else { dialog->resize(totalWidth()+20, QMIN(totalHeight(), mh)+buth+4+(prompt.text().isNull() ? 0 : buth)); if ( dialog->width() > QApplication::desktop()->width() ) dialog->resize(QApplication::desktop()->width(),dialog->height()+16); centerOnMain(dialog); dialog->show(); } setFocus(); while (dialog->result()<0) { // changed the defaults below to the values in wintype.h 000119 - azy if (!keysource.Empty()) { char k=keysource.GetAscii(); k=map_menu_cmd(k); /* added 000119 - azy */ if (k=='\033') dialog->Reject(); else if (k=='\r' || k=='\n' || k==' ') dialog->Accept(); else if (k==MENU_SEARCH) Search(); else if (k==MENU_SELECT_ALL) All(); else if (k==MENU_INVERT_ALL) Invert(); else if (k==MENU_UNSELECT_ALL) ChooseNone(); else { for (int i=0; iresult()<0) qApp->enter_loop(); } //if ( (nhid != WIN_INVEN || !flags.perm_invent) ) // doesn't work yet { dialog->hide(); } int result=dialog->result(); // Consume ^M (which QDialog steals for default button) while (!keysource.Empty() && (keysource.TopAscii()=='\n' || keysource.TopAscii()=='\r')) keysource.GetAscii(); *menu_list=0; if (result>0 && how!=PICK_NONE) { if (how==PICK_ONE) { int i; for (i=0; istate()&ShiftButton)) { if (event->key()==Key_Prior) { setYOffset(yOffset()-viewHeight()); } else if (event->key()==Key_Next) { setYOffset(yOffset()+viewHeight()); } else { event->ignore(); } } else { event->ignore(); } } void NetHackQtMenuWindow::All() { for (int i=0; iAccept(); } } } void NetHackQtMenuWindow::paintCell(QPainter* painter, int row, int col) { // [pick-count] [accel] [glyph] [string] MenuItem& i = item[row]; painter->setPen(black); painter->setFont(font()); if (i.selected) { painter->setPen(darkGreen); } switch (col) { case 0: if ( i.ch || i.attr!=ATR_INVERSE ) { QString text; if ( i.selected && i.count == -1 ) { if ( i.str[0]>='0' && i.str[0]<='9' ) text = "All"; else text = "*"; } else if ( i.count<0 ) { text = "-"; } else { text.sprintf("%d",i.count); } painter->drawText(0,0,cellWidth(col),cellHeight(), AlignHCenter|AlignVCenter,text); } break; case 1: if ((signed char)i.ch >= 0) { char text[2]={i.ch,0}; painter->drawText(0,0,cellWidth(col),cellHeight(), AlignHCenter|AlignVCenter,text); } break; case 2: if (i.glyph!=NO_GLYPH) { // Centered in height int y=(cellHeight()-qt_settings->glyphs().height())/2; if (y<0) y=0; qt_settings->glyphs().drawGlyph(*painter, i.glyph, 0, y); } break; case 3: // XXX should qt_settings have ALL the various fonts QFont newfont=font(); if (i.attr) { switch(i.attr) { case ATR_ULINE: newfont.setUnderline(TRUE); break; case ATR_BOLD: painter->setPen(red); break; case ATR_BLINK: newfont.setItalic(TRUE); break; case ATR_INVERSE: newfont=qt_settings->largeFont(); newfont.setWeight(QFont::Bold); if (i.selected) { painter->setPen(blue); } else { painter->setPen(darkBlue); } } } painter->setFont(newfont); painter->drawText(STR_MARGIN,0,cellWidth(col),cellHeight(), AlignLeft|AlignVCenter,i.str); } } void NetHackQtMenuWindow::mousePressEvent(QMouseEvent* event) { int col=findCol(event->pos().x()); int row=findRow(event->pos().y()); if (col<0 || row<0 || !item[row].Selectable()) return; if (how!=PICK_NONE) { if (col==0) { // Changing count. NetHackQtStringRequestor requestor(keysource,"Count:"); char buf[BUFSZ]; if (item[row].count>0) Sprintf(buf,"%d", item[row].count); else Strcpy(buf, ""); requestor.SetDefault(buf); if (requestor.Get(buf)) { item[row].count=atoi(buf); if (item[row].count==0) { item[row].count=-1; if (item[row].selected) ToggleSelect(row); } else { if (!item[row].selected) ToggleSelect(row); } updateCell(row,0); } } else { pressed=row; was_sel=item[row].selected; ToggleSelect(row); updateCell(row,0); } } } void NetHackQtMenuWindow::mouseReleaseEvent(QMouseEvent* event) { if (pressed>=0) { int p=pressed; pressed=-1; updateCell(p,3); } } void NetHackQtMenuWindow::mouseMoveEvent(QMouseEvent* event) { if (pressed>=0) { int col=findCol(event->pos().x()); int row=findRow(event->pos().y()); if (row>=0 && col>=0) { if (pressed!=row) { // reset to initial state if (item[pressed].selected!=was_sel) ToggleSelect(pressed); } else { // reset to new state if (item[pressed].selected==was_sel) ToggleSelect(pressed); } } } } class NetHackQtTextListBox : public QListBox { public: NetHackQtTextListBox(QWidget* parent) : QListBox(parent) { } int TotalWidth() { doLayout(); return contentsWidth(); } int TotalHeight() { doLayout(); return contentsHeight(); } virtual void setFont(const QFont &font) { QListBox::setFont(font); } void keyPressEvent(QKeyEvent* e) { QListBox::keyPressEvent(e); } }; QPixmap* NetHackQtRIP::pixmap=0; NetHackQtRIP::NetHackQtRIP(QWidget* parent) : QWidget(parent) { if (!pixmap) { pixmap=new QPixmap; tryload(*pixmap, "rip.xpm"); } riplines=0; resize(pixmap->width(),pixmap->height()); setFont(QFont("times",12)); // XXX may need to be configurable } void NetHackQtRIP::setLines(char** l, int n) { line=l; riplines=n; } QSize NetHackQtRIP::sizeHint() const { return pixmap->size(); } void NetHackQtRIP::paintEvent(QPaintEvent* event) { if ( riplines ) { int pix_x=(width()-pixmap->width())/2; int pix_y=(height()-pixmap->height())/2; // XXX positions based on RIP image int rip_text_x=pix_x+156; int rip_text_y=pix_y+67; int rip_text_h=94/riplines; QPainter painter; painter.begin(this); painter.drawPixmap(pix_x,pix_y,*pixmap); for (int i=0; imainWidget(),0,FALSE), keysource(ks), use_rip(FALSE), str_fixed(FALSE), ok("Dismiss",this), search("Search",this), lines(new NetHackQtTextListBox(this)), rip(this) { ok.setDefault(TRUE); connect(&ok,SIGNAL(clicked()),this,SLOT(accept())); connect(&search,SIGNAL(clicked()),this,SLOT(Search())); connect(qt_settings,SIGNAL(fontChanged()),this,SLOT(doUpdate())); QVBoxLayout* vb = new QVBoxLayout(this); vb->addWidget(&rip); QHBoxLayout* hb = new QHBoxLayout(vb); hb->addWidget(&ok); hb->addWidget(&search); vb->addWidget(lines); } void NetHackQtTextWindow::doUpdate() { update(); } NetHackQtTextWindow::~NetHackQtTextWindow() { } QWidget* NetHackQtTextWindow::Widget() { return this; } bool NetHackQtTextWindow::Destroy() { return !isVisible(); } void NetHackQtTextWindow::UseRIP(int how) { // Code from X11 windowport #define STONE_LINE_LEN 16 /* # chars that fit on one line */ #define NAME_LINE 0 /* line # for player name */ #define GOLD_LINE 1 /* line # for amount of gold */ #define DEATH_LINE 2 /* line # for death description */ #define YEAR_LINE 6 /* line # for year */ static char** rip_line=0; if (!rip_line) { rip_line=new char*[YEAR_LINE+1]; for (int i=0; i STONE_LINE_LEN) { for(i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) if(dpx[i] == ' ') i0 = i; if(!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; strcpy(rip_line[line], dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx= &dpx[i0]; } else dpx= &dpx[i0+1]; } /* Put year on stone */ Sprintf(rip_line[YEAR_LINE], "%4d", getyear()); rip.setLines(rip_line,YEAR_LINE+1); use_rip=TRUE; } void NetHackQtTextWindow::Clear() { lines->clear(); use_rip=FALSE; str_fixed=FALSE; } void NetHackQtTextWindow::Display(bool block) { if (str_fixed) { lines->setFont(qt_settings->normalFixedFont()); } else { lines->setFont(qt_settings->normalFont()); } int h=0; if (use_rip) { h+=rip.height(); ok.hide(); search.hide(); rip.show(); } else { h+=ok.height()*2; ok.show(); search.show(); rip.hide(); } int mh = QApplication::desktop()->height()*3/5; if ( qt_compact_mode && lines->TotalHeight() > mh || use_rip ) { // big, so make it fill showMaximized(); } else { resize(QMAX(use_rip ? rip.width() : 200, lines->TotalWidth()+24), QMIN(mh, lines->TotalHeight()+h)); centerOnMain(this); show(); } if (block) { setResult(-1); while (result()==-1) { qApp->enter_loop(); if (result()==-1 && !keysource.Empty()) { char k=keysource.GetAscii(); if (k=='\033' || k==' ' || k=='\r' || k=='\n') { accept(); } else if (k=='/') { Search(); } } } } } void NetHackQtTextWindow::PutStr(int attr, const char* text) { str_fixed=str_fixed || strstr(text," "); lines->insertItem(text); } void NetHackQtTextWindow::done(int i) { setResult(i+1000); hide(); qApp->exit_loop(); } void NetHackQtTextWindow::keyPressEvent(QKeyEvent* e) { if ( e->ascii() != '\r' && e->ascii() != '\n' && e->ascii() != '\033' ) lines->keyPressEvent(e); else QDialog::keyPressEvent(e); } void NetHackQtTextWindow::Search() { NetHackQtStringRequestor requestor(keysource,"Search for:"); static char line[256]=""; requestor.SetDefault(line); if (requestor.Get(line)) { int current=lines->currentItem(); for (uint i=1; icount(); i++) { int lnum=(i+current)%lines->count(); QString str=lines->text(lnum); if (str.contains(line)) { lines->setCurrentItem(lnum); lines->centerCurrentItem(); return; } } lines->setCurrentItem(-1); } } NetHackQtDelay::NetHackQtDelay(int ms) : msec(ms) { } void NetHackQtDelay::wait() { startTimer(msec); qApp->enter_loop(); } void NetHackQtDelay::timerEvent(QTimerEvent* timer) { qApp->exit_loop(); killTimers(); } NetHackQtInvUsageWindow::NetHackQtInvUsageWindow(QWidget* parent) : QWidget(parent) { } void NetHackQtInvUsageWindow::drawWorn(QPainter& painter, obj* nhobj, int x, int y, bool canbe) { short int glyph; if (nhobj) glyph=obj_to_glyph(nhobj); else if (canbe) glyph=cmap_to_glyph(S_room); else glyph=cmap_to_glyph(S_stone); qt_settings->glyphs().drawCell(painter,glyph,x,y); } void NetHackQtInvUsageWindow::paintEvent(QPaintEvent*) { // 012 // //0 WhB //1 s"w //2 gCg //3 =A= //4 T //5 S QPainter painter; painter.begin(this); // Blanks drawWorn(painter,0,0,4,FALSE); drawWorn(painter,0,0,5,FALSE); drawWorn(painter,0,2,4,FALSE); drawWorn(painter,0,2,5,FALSE); drawWorn(painter,uarm,1,3); // Armour drawWorn(painter,uarmc,1,2); // Cloak drawWorn(painter,uarmh,1,0); // Helmet drawWorn(painter,uarms,0,1); // Shield drawWorn(painter,uarmg,0,2); // Gloves - repeated drawWorn(painter,uarmg,2,2); // Gloves - repeated #ifdef TOURIST drawWorn(painter,uarmf,1,5); // Shoes (feet) drawWorn(painter,uarmu,1,4); // Undershirt #else drawWorn(painter,0 ,1,5,FALSE); drawWorn(painter,uarmf,1,4); // Shoes (feet) #endif drawWorn(painter,uleft,0,3); // RingL drawWorn(painter,uright,2,3); // RingR drawWorn(painter,uwep,2,1); // Weapon drawWorn(painter,uswapwep,0,0); // Secondary weapon drawWorn(painter,uamul,1,1); // Amulet drawWorn(painter,ublindf,2,0); // Blindfold painter.end(); } class SmallToolButton : public QToolButton { public: SmallToolButton(const QPixmap & pm, const QString &textLabel, const QString& grouptext, QObject * receiver, const char* slot, QToolBar * parent) : QToolButton(pm, textLabel, #if QT_VERSION < 210 QString::null, #else grouptext, #endif receiver, slot, parent) { } QSize sizeHint() const { // get just a couple more pixels for the map return QToolButton::sizeHint()-QSize(0,2); } }; NetHackQtMainWindow::NetHackQtMainWindow(NetHackQtKeyBuffer& ks) : message(0), map(0), status(0), invusage(0), keysink(ks), dirkey(0) { QToolBar* toolbar = new QToolBar(this); #if QT_VERSION >= 210 setToolBarsMovable(FALSE); toolbar->setHorizontalStretchable(TRUE); toolbar->setVerticalStretchable(TRUE); #endif addToolBar(toolbar); menubar = menuBar(); setCaption("Qt NetHack"); if ( qt_compact_mode ) setIcon(QPixmap(nh_icon_small)); else setIcon(QPixmap(nh_icon)); QPopupMenu* game=new QPopupMenu; QPopupMenu* apparel=new QPopupMenu; QPopupMenu* act1=new QPopupMenu; QPopupMenu* act2 = qt_compact_mode ? new QPopupMenu : act1; QPopupMenu* magic=new QPopupMenu; QPopupMenu* info=new QPopupMenu; QPopupMenu *help; #ifdef KDE help = kapp->getHelpMenu( TRUE, "" ); help->insertSeparator(); #else help = qt_compact_mode ? info : new QPopupMenu; #endif enum { OnDesktop=1, OnHandhelds=2 }; struct Macro { QPopupMenu* menu; const char* name; const char* action; int flags; } item[] = { { game, 0, 0, 3}, { game, "Version\tv", "v", 3}, { game, "Compilation\tAlt+V", "\366", 3}, { game, "History\tShift+V", "V", 3}, { game, "Redraw\tCtrl+R", "\022", 0}, // useless { game, "Options\tShift+O", "O", 3}, { game, "Explore mode\tShift+X", "X", 3}, { game, 0, 0, 3}, { game, "Save\tSy", "Sy", 3}, { game, "Quit\tAlt+Q", "\361", 3}, { apparel, "Apparel off\tShift+A", "A", 2}, { apparel, "Remove many\tShift+A", "A", 1}, { apparel, 0, 0, 3}, { apparel, "Wield weapon\tw", "w", 3}, { apparel, "Exchange weapons\tx", "x", 3}, { apparel, "Two weapon combat\t#two", "#tw", 3}, { apparel, "Load quiver\tShift+Q", "Q", 3}, { apparel, 0, 0, 3}, { apparel, "Wear armour\tShift+W", "W", 3}, { apparel, "Take off armour\tShift+T", "T", 3}, { apparel, 0, 0, 3}, { apparel, "Put on non-armour\tShift+P", "P", 3}, { apparel, "Remove non-armour\tShift+R", "R", 3}, { act1, "Again\tCtrl+A", "\001", 2}, { act1, 0, 0, 3}, { act1, "Apply\ta?", "a?", 3}, { act1, "Chat\tAlt+C", "\343", 3}, { act1, "Close door\tc", "c", 3}, { act1, "Down\t>", ">", 3}, { act1, "Drop many\tShift+D", "D", 2}, { act1, "Drop\td?", "d?", 2}, { act1, "Eat\te?", "e?", 2}, { act1, "Engrave\tShift+E", "E", 3}, { act1, "Fight\tShift+F", "F", 3}, { act1, "Fire from quiver\tf", "f", 2}, { act1, "Force\tAlt+F", "\346", 3}, { act1, "Get\t,", ",", 2}, { act1, "Jump\tAlt+J", "\352", 3}, { act2, "Kick\tCtrl+D", "\004", 2}, { act2, "Loot\tAlt+L", "\354", 3}, { act2, "Open door\to", "o", 3}, { act2, "Pay\tp", "p", 3}, { act2, "Rest\t.", ".", 2}, { act2, "Ride\t#ri", "#ri", 3}, { act2, "Search\ts", "s", 3}, { act2, "Sit\tAlt+S", "\363", 3}, { act2, "Throw\tt", "t", 2}, { act2, "Untrap\t#u", "#u", 3}, { act2, "Up\t<", "<", 3}, { act2, "Wipe face\tAlt+W", "\367", 3}, { magic, "Quaff potion\tq?", "q?", 3}, { magic, "Read scroll/book\tr?", "r?", 3}, { magic, "Zap wand\tz?", "z?", 3}, { magic, "Zap spell\tShift+Z", "Z", 3}, { magic, "Dip\tAlt+D", "\344", 3}, { magic, "Rub\tAlt+R", "\362", 3}, { magic, "Invoke\tAlt+I", "\351", 3}, { magic, 0, 0, 3}, { magic, "Offer\tAlt+O", "\357", 3}, { magic, "Pray\tAlt+P", "\360", 3}, { magic, 0, 0, 3}, { magic, "Teleport\tCtrl+T", "\024", 3}, { magic, "Monster action\tAlt+M", "\355", 3}, { magic, "Turn undead\tAlt+T", "\364", 3}, { help, "Help\t?", "?", 3}, { help, 0, 0, 3}, { help, "What is here\t:", ":", 3}, { help, "What is there\t;", ";", 3}, { help, "What is...\t/y", "/y", 2}, { help, 0, 0, 1}, { info, "Inventory\ti", "i", 3}, #ifdef SLASHEM { info, "Angbandish inventory\t*", "*", 3}, #endif { info, "Conduct\t#co", "#co", 3}, { info, "Discoveries\t\\", "\\", 3}, { info, "List/reorder spells\t+", "+", 3}, { info, "Adjust letters\tAlt+A", "\341", 2}, { info, 0, 0, 3}, { info, "Name object\tAlt+N", "\356y?", 3}, { info, "Name object type\tAlt+N", "\356n?", 3}, { info, "Name creature\tShift+C", "C", 3}, { info, 0, 0, 3}, { info, "Qualifications\tAlt+E", "\345", 3}, { 0, 0, 0, 0 } }; int i; int count=0; for (i=0; item[i].menu; i++) if (item[i].name) count++; macro=new const char* [count]; game->insertItem("Qt settings...",1000); help->insertItem("About Qt NetHack...",2000); //help->insertItem("NetHack Guidebook...",3000); help->insertSeparator(); count=0; for (i=0; item[i].menu; i++) { if ( item[i].flags & (qt_compact_mode ? 1 : 2) ) { if (item[i].name) { QString name = item[i].name; if ( qt_compact_mode ) // accelerators aren't name.replace(QRegExp("\t.*"),""); item[i].menu->insertItem(name,count); macro[count++]=item[i].action; } else { item[i].menu->insertSeparator(); } } } menubar->insertItem("Game",game); menubar->insertItem("Gear",apparel); if ( qt_compact_mode ) { menubar->insertItem("A-J",act1); menubar->insertItem("K-Z",act2); menubar->insertItem("Magic",magic); menubar->insertItem(QPixmap(info_xpm),info); menubar->insertItem(QPixmap(map_xpm), this, SLOT(raiseMap())); menubar->insertItem(QPixmap(msg_xpm), this, SLOT(raiseMessages())); menubar->insertItem(QPixmap(stat_xpm), this, SLOT(raiseStatus())); } else { menubar->insertItem("Action",act1); menubar->insertItem("Magic",magic); menubar->insertItem("Info",info); menubar->insertSeparator(); menubar->insertItem("Help",help); } QSignalMapper* sm = new QSignalMapper(this); connect(sm, SIGNAL(mapped(const QString&)), this, SLOT(doKeys(const QString&))); QToolButton* tb; tb = new SmallToolButton( QPixmap(again_xpm),"Again","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "\001" ); tb = new SmallToolButton( QPixmap(get_xpm),"Get","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "," ); tb = new SmallToolButton( QPixmap(kick_xpm),"Kick","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "\004" ); tb = new SmallToolButton( QPixmap(throw_xpm),"Throw","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "t" ); tb = new SmallToolButton( QPixmap(fire_xpm),"Fire","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "f" ); tb = new SmallToolButton( QPixmap(drop_xpm),"Drop","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "D" ); tb = new SmallToolButton( QPixmap(eat_xpm),"Eat","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "e" ); tb = new SmallToolButton( QPixmap(rest_xpm),"Rest","Action", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "." ); tb = new SmallToolButton( QPixmap(cast_a_xpm),"Cast A","Magic", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "Za" ); tb = new SmallToolButton( QPixmap(cast_b_xpm),"Cast B","Magic", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "Zb" ); tb = new SmallToolButton( QPixmap(cast_c_xpm),"Cast C","Magic", sm, SLOT(map()), toolbar ); sm->setMapping(tb, "Zc" ); if ( !qt_compact_mode ) { QWidget* filler = new QWidget(toolbar); filler->setBackgroundMode(PaletteButton); toolbar->setStretchableWidget(filler); } connect(menubar,SIGNAL(activated(int)),this,SLOT(doMenuItem(int))); #ifdef KDE setMenu (menubar); #endif int x=0,y=0; int w=QApplication::desktop()->width()-10; // XXX arbitrary extra space for frame int h=QApplication::desktop()->height()-50; int maxwn; int maxhn; if (qt_tilewidth != NULL) { maxwn = atoi(qt_tilewidth) * COLNO + 10; } else { maxwn = 1400; } if (qt_tileheight != NULL) { maxhn = atoi(qt_tileheight) * ROWNO * 6/4; } else { maxhn = 1024; } // Be exactly the size we want to be - full map... if (w>maxwn) { x+=(w-maxwn)/2; w=maxwn; // Doesn't need to be any wider } if (h>maxhn) { y+=(h-maxhn)/2; h=maxhn; // Doesn't need to be any taller } setGeometry(x,y,w,h); if ( qt_compact_mode ) { stack = new QWidgetStack(this); setCentralWidget(stack); } else { setCentralWidget(new QWidget(this)); invusage = new NetHackQtInvUsageWindow(centralWidget()); } } void NetHackQtMainWindow::zoomMap() { qt_settings->toggleGlyphSize(); } void NetHackQtMainWindow::raiseMap() { if ( stack->id(stack->visibleWidget()) == 0 ) { zoomMap(); } else { stack->raiseWidget(0); } } void NetHackQtMainWindow::raiseMessages() { stack->raiseWidget(1); } void NetHackQtMainWindow::raiseStatus() { stack->raiseWidget(2); } class NetHackMimeSourceFactory : public QMimeSourceFactory { public: const QMimeSource* data(const QString& abs_name) const { const QMimeSource* r = 0; if ( (NetHackMimeSourceFactory*)this == QMimeSourceFactory::defaultFactory() ) r = QMimeSourceFactory::data(abs_name); else r = QMimeSourceFactory::defaultFactory()->data(abs_name); if ( !r ) { int sl = abs_name.length(); do { sl = abs_name.findRev('/',sl-1); QString name = sl>=0 ? abs_name.mid(sl+1) : abs_name; int dot = name.findRev('.'); if ( dot >= 0 ) name = name.left(dot); if ( name == "map" ) r = new QImageDrag(QImage(map_xpm)); else if ( name == "msg" ) r = new QImageDrag(QImage(msg_xpm)); else if ( name == "stat" ) r = new QImageDrag(QImage(stat_xpm)); } while (!r && sl>0); } return r; } }; void NetHackQtMainWindow::doMenuItem(int id) { switch (id) { case 1000: centerOnMain(qt_settings); qt_settings->show(); break; case 2000: QMessageBox::about(this, "About Qt NetHack", aboutMsg()); break; case 3000: { QDialog dlg(this,0,TRUE); (new QVBoxLayout(&dlg))->setAutoAdd(TRUE); QTextBrowser browser(&dlg); NetHackMimeSourceFactory ms; browser.setMimeSourceFactory(&ms); browser.setSource(QDir::currentDirPath()+"/Guidebook.html"); if ( qt_compact_mode ) dlg.showMaximized(); dlg.exec(); } break; default: if ( id >= 0 ) doKeys(macro[id]); } } void NetHackQtMainWindow::doKeys(const QString& k) { keysink.Put(k); qApp->exit_loop(); } void NetHackQtMainWindow::AddMessageWindow(NetHackQtMessageWindow* window) { message=window; ShowIfReady(); } void NetHackQtMainWindow::AddMapWindow(NetHackQtMapWindow* window) { map=window; ShowIfReady(); connect(map,SIGNAL(resized()),this,SLOT(layout())); } void NetHackQtMainWindow::AddStatusWindow(NetHackQtStatusWindow* window) { status=window; ShowIfReady(); } void NetHackQtMainWindow::RemoveWindow(NetHackQtWindow* window) { if (window==status) { status=0; ShowIfReady(); } else if (window==map) { map=0; ShowIfReady(); } else if (window==message) { message=0; ShowIfReady(); } } void NetHackQtMainWindow::updateInventory() { if ( invusage ) invusage->repaint(FALSE); } void NetHackQtMainWindow::fadeHighlighting() { if (status) { status->fadeHighlighting(); } } void NetHackQtMainWindow::layout() { if ( qt_compact_mode ) return; if (message && map && status) { QSize maxs=map->Widget()->maximumSize(); int maph=QMIN(height()*2/3,maxs.height()); QWidget* c = centralWidget(); int h=c->height(); int toph=h-maph; int iuw=3*qt_settings->glyphs().width(); int topw=(c->width()-iuw)/2; message->Widget()->setGeometry(0,0,topw,toph); invusage->setGeometry(topw,0,iuw,toph); status->Widget()->setGeometry(topw+iuw,0,topw,toph); map->Widget()->setGeometry(QMAX(0,(c->width()-maxs.width())/2), toph,c->width(),maph); } } void NetHackQtMainWindow::resizeEvent(QResizeEvent*) { layout(); #ifdef KDE updateRects(); #endif } void NetHackQtMainWindow::keyReleaseEvent(QKeyEvent* event) { if ( dirkey ) { doKeys(QString(QChar(dirkey))); if ( !event->isAutoRepeat() ) dirkey = 0; } } void NetHackQtMainWindow::keyPressEvent(QKeyEvent* event) { // Global key controls // For desktop, arrow keys scroll map, since we don't want players // to think that's the way to move. For handhelds, the normal way is to // click-to-travel, so we allow the cursor keys for fine movements. // 321 // 4 0 // 567 if ( event->isAutoRepeat() && event->key() >= Key_Left && event->key() <= Key_Down ) return; const char* d = iflags.num_pad ? ndir : sdir; switch (event->key()) { case Key_Up: if ( dirkey == d[0] ) dirkey = d[1]; else if ( dirkey == d[4] ) dirkey = d[3]; else dirkey = d[2]; break; case Key_Down: if ( dirkey == d[0] ) dirkey = d[7]; else if ( dirkey == d[4] ) dirkey = d[5]; else dirkey = d[6]; break; case Key_Left: if ( dirkey == d[2] ) dirkey = d[1]; else if ( dirkey == d[6] ) dirkey = d[7]; else dirkey = d[0]; break; case Key_Right: if ( dirkey == d[2] ) dirkey = d[3]; else if ( dirkey == d[6] ) dirkey = d[5]; else dirkey = d[4]; break; case Key_Prior: dirkey = 0; if (message) message->Scroll(0,-1); break; case Key_Next: dirkey = 0; if (message) message->Scroll(0,+1); break; case Key_Space: if ( flags.rest_on_space ) { event->ignore(); return; } case Key_Enter: if ( map ) map->clickCursor(); break; default: dirkey = 0; event->ignore(); } } void NetHackQtMainWindow::closeEvent(QCloseEvent* e) { if ( program_state.something_worth_saving ) { switch ( QMessageBox::information( this, "NetHack", "This will end your NetHack session", "&Save", "&Cancel", 0, 1 ) ) { case 0: // See dosave() function if (dosave0()) { u.uhp = -1; NetHackQtBind::qt_exit_nhwindows(0); terminate(EXIT_SUCCESS); } break; case 1: break; // ignore the event } } else { e->accept(); } } void NetHackQtMainWindow::ShowIfReady() { if (message && map && status) { QPoint pos(0,0); QWidget* p = qt_compact_mode ? stack : centralWidget(); message->Widget()->recreate(p,0,pos); map->Widget()->recreate(p,0,pos); status->Widget()->recreate(p,0,pos); if ( qt_compact_mode ) { message->setMap(map); stack->addWidget(map->Widget(), 0); stack->addWidget(message->Widget(), 1); stack->addWidget(status->Widget(), 2); raiseMap(); } else { layout(); } showMaximized(); } else if (isVisible()) { hide(); } } NetHackQtYnDialog::NetHackQtYnDialog(NetHackQtKeyBuffer& keysrc,const char* q,const char* ch,char df) : QDialog(qApp->mainWidget(),0,FALSE), question(q), choices(ch), def(df), keysource(keysrc) { setCaption("NetHack: Question"); } char NetHackQtYnDialog::Exec() { QString ch(choices); int ch_per_line=6; QString qlabel; QString enable; if ( qt_compact_mode && !choices ) { // expand choices from prompt // ##### why isn't choices set properly??? const char* c=question; while ( *c && *c != '[' ) c++; qlabel = QString(question).left(c-question); if ( *c ) { c++; if ( *c == '-' ) ch.append(*c++); char from=0; while ( *c && *c != ']' && *c != ' ' ) { if ( *c == '-' ) { from = c[-1]; } else if ( from ) { for (char f=from+1; f<=*c; f++) ch.append(f); from = 0; } else { ch.append(*c); from = 0; } c++; } if ( *c == ' ' ) { while ( *c && *c != ']' ) { if ( *c == '*' || *c == '?' ) ch.append(*c); c++; } } } if ( strstr(question, "what direction") ) { // We replace this regardless, since sometimes you get choices. const char* d = iflags.num_pad ? ndir : sdir; enable=ch; ch=""; ch.append(d[1]); ch.append(d[2]); ch.append(d[3]); ch.append(d[0]); ch.append('.'); ch.append(d[4]); ch.append(d[7]); ch.append(d[6]); ch.append(d[5]); ch.append(d[8]); ch.append(d[9]); ch_per_line = 3; def = ' '; } else { // Hmm... they'll have to use a virtual keyboard } } else { qlabel = question; } if (!ch.isNull()) { QVBoxLayout vb(this); vb.setAutoAdd(TRUE); bool bigq = qlabel.length()>40; if ( bigq ) { QLabel* q = new QLabel(qlabel,this); q->setAlignment(AlignLeft|WordBreak); q->setMargin(4); } QButtonGroup group(ch_per_line, Horizontal, bigq ? QString::null : qlabel, this); int nchoices=ch.length(); bool allow_count=ch.contains('#'); const int margin=8; const int gutter=8; const int extra=fontMetrics().height(); // Extra for group int x=margin, y=extra+margin; int butsize=fontMetrics().height()*2+5; QPushButton* button; for (int i=0; isetEnabled(FALSE); } button->setFixedSize(butsize,butsize); // Square if (ch[i]==def) button->setDefault(TRUE); if (i%10==9) { // last in row x=margin; y+=butsize+gutter; } else { x+=butsize+gutter; } } connect(&group,SIGNAL(clicked(int)),this,SLOT(doneItem(int))); QLabel* lb=0; QLineEdit* le=0; if (allow_count) { QHBox *hb = new QHBox(this); lb=new QLabel("Count: ",hb); le=new QLineEdit(hb); } adjustSize(); centerOnMain(this); show(); char choice=0; char ch_esc=0; for (uint i=0; i= 1000 ) { choice = ch[result() - 1000].latin1(); } if ( !choice ) qApp->enter_loop(); } hide(); if (allow_count && !le->text().isEmpty()) { yn_number=atoi(le->text()); choice='#'; } return choice; } else { QLabel label(qlabel,this); QPushButton cancel("Dismiss",this); label.setFrameStyle(QFrame::Box|QFrame::Sunken); label.setAlignment(AlignCenter); label.resize(fontMetrics().width(qlabel)+60,30+fontMetrics().height()); cancel.move(width()/2-cancel.width()/2,label.geometry().bottom()+8); connect(&cancel,SIGNAL(clicked()),this,SLOT(reject())); centerOnMain(this); setResult(-1); show(); while (result()<0 && keysource.Empty()) { qApp->enter_loop(); } hide(); if (keysource.Empty()) { return '\033'; } else { return keysource.GetAscii(); } } } void NetHackQtYnDialog::keyPressEvent(QKeyEvent* event) { // Don't want QDialog's Return/Esc behaviour event->ignore(); } void NetHackQtYnDialog::doneItem(int i) { done(i+1000); } void NetHackQtYnDialog::done(int i) { setResult(i); qApp->exit_loop(); } NetHackQtGlyphs::NetHackQtGlyphs() { const char* tile_file = "nhtiles.bmp"; if ( iflags.wc_tile_file ) tile_file = iflags.wc_tile_file; if (!img.load(tile_file)) { tile_file = "x11tiles"; if (!img.load(tile_file)) { QString msg; msg.sprintf("Cannot load x11tiles or nhtiles.bmp"); QMessageBox::warning(0, "IO Error", msg); } else { tiles_per_row = TILES_PER_ROW; if (img.width()%tiles_per_row) { impossible("Tile file \"%s\" has %d columns, not multiple of row count (%d)", tile_file, img.width(), tiles_per_row); } } } else { tiles_per_row = 40; } if ( iflags.wc_tile_width ) tilefile_tile_W = iflags.wc_tile_width; else tilefile_tile_W = img.width() / tiles_per_row; if ( iflags.wc_tile_height ) tilefile_tile_H = iflags.wc_tile_height; else tilefile_tile_H = tilefile_tile_W; setSize(tilefile_tile_W, tilefile_tile_H); } void NetHackQtGlyphs::drawGlyph(QPainter& painter, int glyph, int x, int y) { int tile = glyph2tile[glyph]; int px = (tile%tiles_per_row)*width(); int py = tile/tiles_per_row*height(); painter.drawPixmap( x, y, pm, px,py, width(),height() ); } void NetHackQtGlyphs::drawCell(QPainter& painter, int glyph, int cellx, int celly) { drawGlyph(painter,glyph,cellx*width(),celly*height()); } void NetHackQtGlyphs::setSize(int w, int h) { if ( size == QSize(w,h) ) return; bool was1 = size == pm1.size(); size = QSize(w,h); if (!w || !h) return; // Still not decided if ( size == pm1.size() ) { pm = pm1; return; } if ( size == pm2.size() ) { pm = pm2; return; } if (w==tilefile_tile_W && h==tilefile_tile_H) { pm.convertFromImage(img); } else { QApplication::setOverrideCursor( Qt::waitCursor ); QImage scaled = img.smoothScale( w*img.width()/tilefile_tile_W, h*img.height()/tilefile_tile_H ); pm.convertFromImage(scaled,Qt::ThresholdDither|Qt::PreferDither); QApplication::restoreOverrideCursor(); } (was1 ? pm2 : pm1) = pm; } ////////////////////////////////////////////////////////////// // // The ugly C binding classes... // ////////////////////////////////////////////////////////////// NetHackQtMenuOrTextWindow::NetHackQtMenuOrTextWindow(NetHackQtKeyBuffer& ks) : actual(0), keysource(ks) { } QWidget* NetHackQtMenuOrTextWindow::Widget() { if (!actual) impossible("Widget called before we know if Menu or Text"); return actual->Widget(); } // Text void NetHackQtMenuOrTextWindow::Clear() { if (!actual) impossible("Clear called before we know if Menu or Text"); actual->Clear(); } void NetHackQtMenuOrTextWindow::Display(bool block) { if (!actual) impossible("Display called before we know if Menu or Text"); actual->Display(block); } bool NetHackQtMenuOrTextWindow::Destroy() { if (!actual) impossible("Destroy called before we know if Menu or Text"); return actual->Destroy(); } void NetHackQtMenuOrTextWindow::PutStr(int attr, const char* text) { if (!actual) actual=new NetHackQtTextWindow(keysource); actual->PutStr(attr,text); } // Menu void NetHackQtMenuOrTextWindow::StartMenu() { if (!actual) actual=new NetHackQtMenuWindow(keysource); actual->StartMenu(); } void NetHackQtMenuOrTextWindow::AddMenu(int glyph, const ANY_P* identifier, char ch, char gch, int attr, const char* str, bool presel) { if (!actual) impossible("AddMenu called before we know if Menu or Text"); actual->AddMenu(glyph,identifier,ch,gch,attr,str,presel); } void NetHackQtMenuOrTextWindow::EndMenu(const char* prompt) { if (!actual) impossible("EndMenu called before we know if Menu or Text"); actual->EndMenu(prompt); } int NetHackQtMenuOrTextWindow::SelectMenu(int how, MENU_ITEM_P **menu_list) { if (!actual) impossible("SelectMenu called before we know if Menu or Text"); return actual->SelectMenu(how,menu_list); } // XXX Should be from Options // // XXX Hmm. Tricky part is that perhaps some macros should only be active // XXX when a key is about to be gotten. For example, the user could // XXX define "-" to do "E-yyyyyyyy\r", but would still need "-" for // XXX other purposes. Maybe just too bad. // struct { int key; int state; const char* macro; } key_macro[]={ { Qt::Key_F1, 0, "n100." }, // Rest (x100) { Qt::Key_F2, 0, "n20s" }, // Search (x20) { Qt::Key_F3, 0, "o8o4o6o2o8o4o6o2o8o4o6o2" }, // Open all doors (x3) { Qt::Key_Tab, 0, "\001" }, { 0, 0, 0 } }; NetHackQtBind::NetHackQtBind(int& argc, char** argv) : #ifdef KDE KApplication(argc,argv) #elif defined(QWS) // not quite the right condition QPEApplication(argc,argv) #else QApplication(argc,argv) #endif { QPixmap pm("nhsplash.xpm"); if ( iflags.wc_splash_screen && !pm.isNull() ) { QVBox *vb = new QVBox(0,0, WStyle_Customize | WStyle_NoBorder | nh_WX11BypassWM | WStyle_StaysOnTop ); splash = vb; QLabel *lsplash = new QLabel(vb); lsplash->setAlignment(AlignCenter); lsplash->setPixmap(pm); QLabel* capt = new QLabel("Loading...",vb); capt->setAlignment(AlignCenter); if ( pm.mask() ) { lsplash->setFixedSize(pm.size()); lsplash->setMask(*pm.mask()); } splash->move((QApplication::desktop()->width()-pm.width())/2, (QApplication::desktop()->height()-pm.height())/2); //splash->setGeometry(0,0,100,100); if ( qt_compact_mode ) { splash->showMaximized(); } else { vb->setFrameStyle(QFrame::WinPanel|QFrame::Raised); vb->setMargin(10); splash->adjustSize(); splash->show(); } // force content refresh outside event loop splash->repaint(FALSE); lsplash->repaint(FALSE); capt->repaint(FALSE); qApp->flushX(); } else { splash = 0; } main = new NetHackQtMainWindow(keybuffer); #if defined(QWS) // not quite the right condition showMainWidget(main); #else setMainWidget(main); #endif qt_settings=new NetHackQtSettings(main->width(),main->height()); } void NetHackQtBind::qt_init_nhwindows(int* argc, char** argv) { #ifdef UNIX // Userid control // // Michael Hohmuth ... // // As the game runs setuid games, it must seteuid(getuid()) before // calling XOpenDisplay(), and reset the euid afterwards. // Otherwise, it can't read the $HOME/.Xauthority file and whines about // not being able to open the X display (if a magic-cookie // authorization mechanism is being used). uid_t gamesuid=geteuid(); seteuid(getuid()); #endif QApplication::setColorSpec(ManyColor); instance=new NetHackQtBind(*argc,argv); #ifdef UNIX seteuid(gamesuid); #endif #ifdef _WS_WIN_ // This nethack engine feature should be moved into windowport API nt_kbhit = NetHackQtBind::qt_kbhit; #endif } int NetHackQtBind::qt_kbhit() { return !keybuffer.Empty(); } static bool have_asked = FALSE; void NetHackQtBind::qt_player_selection() { if ( !have_asked ) qt_askname(); } NetHackQtSavedGameSelector::NetHackQtSavedGameSelector(const char** saved) : QDialog(qApp->mainWidget(),"sgsel",TRUE) { QVBoxLayout *vbl = new QVBoxLayout(this,6); QHBox* hb; QLabel* logo = new QLabel(this); vbl->addWidget(logo); logo->setAlignment(AlignCenter); logo->setPixmap(QPixmap("nhsplash.xpm")); QLabel* attr = new QLabel("by the NetHack DevTeam",this); attr->setAlignment(AlignCenter); vbl->addWidget(attr); vbl->addStretch(2); /* QLabel* logo = new QLabel(hb); hb = new QHBox(this); vbl->addWidget(hb, AlignCenter); logo->setPixmap(QPixmap(nh_icon)); logo->setAlignment(AlignRight|AlignVCenter); new QLabel(nh_attribution,hb); */ hb = new QHBox(this); vbl->addWidget(hb, AlignCenter); QPushButton* q = new QPushButton("Quit",hb); connect(q, SIGNAL(clicked()), this, SLOT(reject())); QPushButton* c = new QPushButton("New Game",hb); connect(c, SIGNAL(clicked()), this, SLOT(accept())); c->setDefault(TRUE); QButtonGroup* bg = new QButtonGroup(3, Horizontal, "Saved Characters",this); vbl->addWidget(bg); connect(bg, SIGNAL(clicked(int)), this, SLOT(done(int))); for (int i=0; saved[i]; i++) { QPushButton* b = new QPushButton(saved[i],bg); bg->insert(b, i+2); } } int NetHackQtSavedGameSelector::choose() { #if defined(QWS) // probably safe with Qt 3, too (where show!=exec in QDialog). if ( qt_compact_mode ) showMaximized(); #endif return exec()-2; } void NetHackQtBind::qt_askname() { have_asked = TRUE; // We do it all here, and nothing in askname char** saved = get_saved_games(); int ch = -1; if ( saved && *saved ) { if ( splash ) splash->hide(); NetHackQtSavedGameSelector sgsel((const char**)saved); ch = sgsel.choose(); if ( ch >= 0 ) strcpy(plname,saved[ch]); } free_saved_games(saved); switch (ch) { case -1: if ( splash ) splash->hide(); if (NetHackQtPlayerSelector(keybuffer).Choose()) return; case -2: break; default: return; } // Quit clearlocks(); qt_exit_nhwindows(0); terminate(0); } void NetHackQtBind::qt_get_nh_event() { } #if defined(QWS) // Kludge to access lastWindowClosed() signal. class TApp : public QApplication { public: TApp(int& c, char**v) : QApplication(c,v) {} void lwc() { emit lastWindowClosed(); } }; #endif void NetHackQtBind::qt_exit_nhwindows(const char *) { #if defined(QWS) // Avoids bug in SHARP SL5500 ((TApp*)qApp)->lwc(); qApp->quit(); #endif delete instance; // ie. qApp } void NetHackQtBind::qt_suspend_nhwindows(const char *) { } void NetHackQtBind::qt_resume_nhwindows() { } static QArray id_to_window; winid NetHackQtBind::qt_create_nhwindow(int type) { winid id; for (id = 0; id < (winid) id_to_window.size(); id++) { if ( !id_to_window[id] ) break; } if ( id == (winid) id_to_window.size() ) id_to_window.resize(id+1); NetHackQtWindow* window=0; switch (type) { case NHW_MAP: { NetHackQtMapWindow* w=new NetHackQtMapWindow(clickbuffer); main->AddMapWindow(w); window=w; } break; case NHW_MESSAGE: { NetHackQtMessageWindow* w=new NetHackQtMessageWindow; main->AddMessageWindow(w); window=w; } break; case NHW_STATUS: { NetHackQtStatusWindow* w=new NetHackQtStatusWindow; main->AddStatusWindow(w); window=w; } break; case NHW_MENU: window=new NetHackQtMenuOrTextWindow(keybuffer); break; case NHW_TEXT: window=new NetHackQtTextWindow(keybuffer); } window->nhid = id; // Note: use of isHidden does not work with Qt 2.1 if ( splash #if QT_VERSION >= 300 && !main->isHidden() #else && main->isVisible() #endif ) { delete splash; splash = 0; } id_to_window[id] = window; return id; } void NetHackQtBind::qt_clear_nhwindow(winid wid) { NetHackQtWindow* window=id_to_window[wid]; window->Clear(); } void NetHackQtBind::qt_display_nhwindow(winid wid, BOOLEAN_P block) { NetHackQtWindow* window=id_to_window[wid]; window->Display(block); } void NetHackQtBind::qt_destroy_nhwindow(winid wid) { NetHackQtWindow* window=id_to_window[wid]; main->RemoveWindow(window); if (window->Destroy()) delete window; id_to_window[wid] = 0; } void NetHackQtBind::qt_curs(winid wid, int x, int y) { NetHackQtWindow* window=id_to_window[wid]; window->CursorTo(x,y); } void NetHackQtBind::qt_putstr(winid wid, int attr, const char *text) { NetHackQtWindow* window=id_to_window[wid]; window->PutStr(attr,text); } void NetHackQtBind::qt_display_file(const char *filename, BOOLEAN_P must_exist) { NetHackQtTextWindow* window=new NetHackQtTextWindow(keybuffer); bool complain = FALSE; #ifdef DLB { dlb *f; char buf[BUFSZ]; char *cr; window->Clear(); f = dlb_fopen(filename, "r"); if (!f) { complain = must_exist; } else { while (dlb_fgets(buf, BUFSZ, f)) { if ((cr = index(buf, '\n')) != 0) *cr = 0; #ifdef MSDOS if ((cr = index(buf, '\r')) != 0) *cr = 0; #endif if (index(buf, '\t') != 0) (void) tabexpand(buf); window->PutStr(ATR_NONE, buf); } window->Display(FALSE); (void) dlb_fclose(f); } } #else QFile file(filename); if (file.open(IO_ReadOnly)) { char line[128]; while (file.readLine(line,127) >= 0) { line[strlen(line)-1]=0;// remove newline window->PutStr(ATR_NONE,line); } window->Display(FALSE); } else { complain = must_exist; } #endif if (complain) { QString message; message.sprintf("File not found: %s\n",filename); QMessageBox::message("File Error", (const char*)message, "Ignore"); } } void NetHackQtBind::qt_start_menu(winid wid) { NetHackQtWindow* window=id_to_window[wid]; window->StartMenu(); } void NetHackQtBind::qt_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P ch, CHAR_P gch, int attr, const char *str, BOOLEAN_P presel) { NetHackQtWindow* window=id_to_window[wid]; window->AddMenu(glyph, identifier, ch, gch, attr, str, presel); } void NetHackQtBind::qt_end_menu(winid wid, const char *prompt) { NetHackQtWindow* window=id_to_window[wid]; window->EndMenu(prompt); } int NetHackQtBind::qt_select_menu(winid wid, int how, MENU_ITEM_P **menu_list) { NetHackQtWindow* window=id_to_window[wid]; return window->SelectMenu(how,menu_list); } void NetHackQtBind::qt_update_inventory() { if (main) main->updateInventory(); /* doesn't work yet if (program_state.something_worth_saving && flags.perm_invent) display_inventory(NULL, FALSE); */ } void NetHackQtBind::qt_mark_synch() { } void NetHackQtBind::qt_wait_synch() { } void NetHackQtBind::qt_cliparound(int x, int y) { // XXXNH - winid should be a parameter! qt_cliparound_window(WIN_MAP,x,y); } void NetHackQtBind::qt_cliparound_window(winid wid, int x, int y) { NetHackQtWindow* window=id_to_window[wid]; window->ClipAround(x,y); } void NetHackQtBind::qt_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph) { NetHackQtWindow* window=id_to_window[wid]; window->PrintGlyph(x,y,glyph); } //void NetHackQtBind::qt_print_glyph_compose(winid wid,XCHAR_P x,XCHAR_P y,int glyph1, int glyph2) //{ //NetHackQtWindow* window=id_to_window[wid]; //window->PrintGlyphCompose(x,y,glyph1,glyph2); //} void NetHackQtBind::qt_raw_print(const char *str) { puts(str); } void NetHackQtBind::qt_raw_print_bold(const char *str) { puts(str); } int NetHackQtBind::qt_nhgetch() { if (main) main->fadeHighlighting(); // Process events until a key arrives. // while (keybuffer.Empty()) { qApp->enter_loop(); } return keybuffer.GetAscii(); } int NetHackQtBind::qt_nh_poskey(int *x, int *y, int *mod) { if (main) main->fadeHighlighting(); // Process events until a key or map-click arrives. // while (keybuffer.Empty() && clickbuffer.Empty()) { qApp->enter_loop(); } if (!keybuffer.Empty()) { return keybuffer.GetAscii(); } else { *x=clickbuffer.NextX(); *y=clickbuffer.NextY(); *mod=clickbuffer.NextMod(); clickbuffer.Get(); return 0; } } void NetHackQtBind::qt_nhbell() { QApplication::beep(); } int NetHackQtBind::qt_doprev_message() { // Don't need it - uses scrollbar // XXX but could make this a shortcut return 0; } char NetHackQtBind::qt_yn_function(const char *question, const char *choices, CHAR_P def) { if (qt_settings->ynInMessages() && WIN_MESSAGE!=WIN_ERR) { // Similar to X11 windowport `slow' feature. char message[BUFSZ]; char yn_esc_map='\033'; if (choices) { char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); if ((cb = index(choicebuf, '\033')) != 0) { // anything beyond is hidden *cb = '\0'; } Sprintf(message, "%s [%s] ", question, choicebuf); if (def) Sprintf(eos(message), "(%c) ", def); // escape maps to 'q' or 'n' or default, in that order yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); } #ifdef USE_POPUPS // Improve some special-cases (DIRKS 08/02/23) if (strcmp (choices,"ynq") == 0) { switch (QMessageBox::information (qApp->mainWidget(),"NetHack",question,"&Yes","&No","&Quit",0,2)) { case 0: return 'y'; case 1: return 'n'; case 2: return 'q'; } } if (strcmp (choices,"yn") == 0) { switch (QMessageBox::information(qApp->mainWidget(),"NetHack",question,"&Yes", "&No",0,1)) { case 0: return 'y'; case 1: return 'n'; } } #endif NetHackQtBind::qt_putstr(WIN_MESSAGE, ATR_BOLD, message); int result=-1; while (result<0) { char ch=NetHackQtBind::qt_nhgetch(); if (ch=='\033') { result=yn_esc_map; } else if (choices && !index(choices,ch)) { if (def && (ch==' ' || ch=='\r' || ch=='\n')) { result=def; } else { NetHackQtBind::qt_nhbell(); // and try again... } } else { result=ch; } } NetHackQtBind::qt_clear_nhwindow(WIN_MESSAGE); return result; } else { NetHackQtYnDialog dialog(keybuffer,question,choices,def); return dialog.Exec(); } } void NetHackQtBind::qt_getlin(const char *prompt, char *line) { NetHackQtStringRequestor requestor(keybuffer,prompt); if (!requestor.Get(line)) { line[0]=0; } } NetHackQtExtCmdRequestor::NetHackQtExtCmdRequestor(NetHackQtKeyBuffer& ks) : QDialog(qApp->mainWidget(), "ext-cmd", FALSE), keysource(ks) { int marg=4; QVBoxLayout *l = new QVBoxLayout(this,marg,marg); QPushButton* can = new QPushButton("Cancel", this); can->setDefault(TRUE); can->setMinimumSize(can->sizeHint()); l->addWidget(can); QButtonGroup *group=new QButtonGroup("",0); QGroupBox *grid=new QGroupBox("Extended commands",this); l->addWidget(grid); int i; int butw=50; QFontMetrics fm = fontMetrics(); for (i=0; extcmdlist[i].ef_txt; i++) { butw = QMAX(butw,30+fm.width(extcmdlist[i].ef_txt)); } int ncols=4; int nrows=(i+ncols-1)/ncols; QVBoxLayout* bl = new QVBoxLayout(grid,marg); bl->addSpacing(fm.height()); QGridLayout* gl = new QGridLayout(nrows,ncols,marg); bl->addLayout(gl); for (i=0; extcmdlist[i].ef_txt; i++) { QPushButton* pb=new QPushButton(extcmdlist[i].ef_txt, grid); pb->setMinimumSize(butw,pb->sizeHint().height()); group->insert(pb); gl->addWidget(pb,i/ncols,i%ncols); } connect(group,SIGNAL(clicked(int)),this,SLOT(done(int))); bl->activate(); l->activate(); resize(1,1); connect(can,SIGNAL(clicked()),this,SLOT(cancel())); } void NetHackQtExtCmdRequestor::cancel() { setResult(-1); qApp->exit_loop(); } void NetHackQtExtCmdRequestor::done(int i) { setResult(i); qApp->exit_loop(); } int NetHackQtExtCmdRequestor::get() { const int none = -10; char str[32]; int cursor=0; resize(1,1); // pack centerOnMain(this); show(); setResult(none); while (result()==none) { while (result()==none && !keysource.Empty()) { char k=keysource.GetAscii(); if (k=='\r' || k=='\n' || k==' ' || k=='\033') { setResult(-1); } else { str[cursor++] = k; int r=-1; for (int i=0; extcmdlist[i].ef_txt; i++) { if (qstrnicmp(str, extcmdlist[i].ef_txt, cursor)==0) { if ( r == -1 ) r = i; else r = -2; } } if ( r == -1 ) { // no match! QApplication::beep(); cursor=0; } else if ( r != -2 ) { // only one match setResult(r); } } } if (result()==none) qApp->enter_loop(); } hide(); return result(); } int NetHackQtBind::qt_get_ext_cmd() { NetHackQtExtCmdRequestor requestor(keybuffer); return requestor.get(); } void NetHackQtBind::qt_number_pad(int) { // Ignore. } void NetHackQtBind::qt_delay_output() { NetHackQtDelay delay(15); delay.wait(); } void NetHackQtBind::qt_start_screen() { // Ignore. } void NetHackQtBind::qt_end_screen() { // Ignore. } void NetHackQtBind::qt_outrip(winid wid, int how) { NetHackQtWindow* window=id_to_window[wid]; window->UseRIP(how); } bool NetHackQtBind::notify(QObject *receiver, QEvent *event) { // Ignore Alt-key navigation to menubar, it's annoying when you // use Alt-Direction to move around. if ( main && event->type()==QEvent::KeyRelease && main==receiver && ((QKeyEvent*)event)->key() == Key_Alt ) return TRUE; bool result=QApplication::notify(receiver,event); if (event->type()==QEvent::KeyPress) { QKeyEvent* key_event=(QKeyEvent*)event; if (!key_event->isAccepted()) { const int k=key_event->key(); bool macro=FALSE; for (int i=0; !macro && key_macro[i].key; i++) { if (key_macro[i].key==k && ((key_macro[i].state&key_event->state())==key_macro[i].state)) { keybuffer.Put(key_macro[i].macro); macro=TRUE; } } char ch=key_event->ascii(); if ( !ch && (key_event->state() & Qt::ControlButton) ) { // On Mac, ascii control codes are not sent, force them. if ( k>=Qt::Key_A && k<=Qt::Key_Z ) ch = k - Qt::Key_A + 1; } if (!macro && ch) { bool alt = (key_event->state()&AltButton) || (k >= Key_0 && k <= Key_9 && (key_event->state()&ControlButton)); keybuffer.Put(key_event->key(),ch + (alt ? 128 : 0), key_event->state()); key_event->accept(); result=TRUE; } if (ch || macro) { qApp->exit_loop(); } } } return result; } NetHackQtBind* NetHackQtBind::instance=0; NetHackQtKeyBuffer NetHackQtBind::keybuffer; NetHackQtClickBuffer NetHackQtBind::clickbuffer; NetHackQtMainWindow* NetHackQtBind::main=0; QWidget* NetHackQtBind::splash=0; extern "C" struct window_procs Qt_procs; struct window_procs Qt_procs = { "Qt", WC_COLOR|WC_HILITE_PET| WC_ASCII_MAP|WC_TILED_MAP| WC_FONT_MAP|WC_TILE_FILE|WC_TILE_WIDTH|WC_TILE_HEIGHT| WC_PLAYER_SELECTION|WC_SPLASH_SCREEN, 0L, NetHackQtBind::qt_init_nhwindows, NetHackQtBind::qt_player_selection, NetHackQtBind::qt_askname, NetHackQtBind::qt_get_nh_event, NetHackQtBind::qt_exit_nhwindows, NetHackQtBind::qt_suspend_nhwindows, NetHackQtBind::qt_resume_nhwindows, NetHackQtBind::qt_create_nhwindow, NetHackQtBind::qt_clear_nhwindow, NetHackQtBind::qt_display_nhwindow, NetHackQtBind::qt_destroy_nhwindow, NetHackQtBind::qt_curs, NetHackQtBind::qt_putstr, NetHackQtBind::qt_display_file, NetHackQtBind::qt_start_menu, NetHackQtBind::qt_add_menu, NetHackQtBind::qt_end_menu, NetHackQtBind::qt_select_menu, genl_message_menu, /* no need for X-specific handling */ NetHackQtBind::qt_update_inventory, NetHackQtBind::qt_mark_synch, NetHackQtBind::qt_wait_synch, #ifdef CLIPPING NetHackQtBind::qt_cliparound, #endif #ifdef POSITIONBAR donull, #endif NetHackQtBind::qt_print_glyph, //NetHackQtBind::qt_print_glyph_compose, NetHackQtBind::qt_raw_print, NetHackQtBind::qt_raw_print_bold, NetHackQtBind::qt_nhgetch, NetHackQtBind::qt_nh_poskey, NetHackQtBind::qt_nhbell, NetHackQtBind::qt_doprev_message, NetHackQtBind::qt_yn_function, NetHackQtBind::qt_getlin, NetHackQtBind::qt_get_ext_cmd, NetHackQtBind::qt_number_pad, NetHackQtBind::qt_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif /* other defs that really should go away (they're tty specific) */ NetHackQtBind::qt_start_screen, NetHackQtBind::qt_end_screen, #ifdef GRAPHIC_TOMBSTONE NetHackQtBind::qt_outrip, #else genl_outrip, #endif genl_preference_update, }; extern "C" void play_usersound(const char* filename, int volume) { #ifdef USER_SOUNDS #ifndef QT_NO_SOUND QSound::play(filename); #endif #endif } #include "qt_win.moc" #ifndef KDE #include "qt_kde0.moc" #endif #if QT_VERSION >= 300 #include "qttableview.moc" #endif nethack-3.4.3/win/Qt/qttableview.cpp0100644000000000000000000016304207764735041016074 0ustar rootroot/********************************************************************** ** $Id: qttableview.cpp,v 1.2 2002/03/09 03:13:15 jwalz Exp $ ** ** Implementation of QtTableView class ** ** Created : 941115 ** ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. ** ** This file contains a class moved out of the Qt GUI Toolkit API. It ** may be used, distributed and modified without limitation. ** **********************************************************************/ #include "qttableview.h" #if QT_VERSION >= 300 #ifndef QT_NO_QTTABLEVIEW #include #include #include #include enum ScrollBarDirtyFlags { verGeometry = 0x01, verSteps = 0x02, verRange = 0x04, verValue = 0x08, horGeometry = 0x10, horSteps = 0x20, horRange = 0x40, horValue = 0x80, verMask = 0x0F, horMask = 0xF0 }; #define HSBEXT horizontalScrollBar()->sizeHint().height() #define VSBEXT verticalScrollBar()->sizeHint().width() class QCornerSquare : public QWidget // internal class { public: QCornerSquare( QWidget *, const char* = 0 ); void paintEvent( QPaintEvent * ); }; QCornerSquare::QCornerSquare( QWidget *parent, const char *name ) : QWidget( parent, name ) { } void QCornerSquare::paintEvent( QPaintEvent * ) { } // NOT REVISED /*! \class QtTableView qttableview.h \brief The QtTableView class provides an abstract base for tables. \obsolete A table view consists of a number of abstract cells organized in rows and columns, and a visible part called a view. The cells are identified with a row index and a column index. The top-left cell is in row 0, column 0. The behavior of the widget can be finely tuned using setTableFlags(); a typical subclass will consist of little more than a call to setTableFlags(), some table content manipulation and an implementation of paintCell(). Subclasses that need cells with variable width or height must reimplement cellHeight() and/or cellWidth(). Use updateTableSize() to tell QtTableView when the width or height has changed. When you read this documentation, it is important to understand the distinctions among the four pixel coordinate systems involved. \list 1 \i The \e cell coordinates. (0,0) is the top-left corner of a cell. Cell coordinates are used by functions such as paintCell(). \i The \e table coordinates. (0,0) is the top-left corner of the cell at row 0 and column 0. These coordinates are absolute; that is, they are independent of what part of the table is visible at the moment. They are used by functions such as setXOffset() or maxYOffset(). \i The \e widget coordinates. (0,0) is the top-left corner of the widget, \e including the frame. They are used by functions such as repaint(). \i The \e view coordinates. (0,0) is the top-left corner of the view, \e excluding the frame. This is the least-used coordinate system; it is used by functions such as viewWidth(). \endlist It is rather unfortunate that we have to use four different coordinate systems, but there was no alternative to provide a flexible and powerful base class. Note: The row,column indices are always given in that order, i.e., first the vertical (row), then the horizontal (column). This is the opposite order of all pixel operations, which take first the horizontal (x) and then the vertical (y). \warning the functions setNumRows(), setNumCols(), setCellHeight(), setCellWidth(), setTableFlags() and clearTableFlags() may cause virtual functions such as cellWidth() and cellHeight() to be called, even if autoUpdate() is FALSE. This may cause errors if relevant state variables are not initialized. \warning Experience has shown that use of this widget tends to cause more bugs than expected and our analysis indicates that the widget's very flexibility is the problem. If QScrollView or QListBox can easily be made to do the job you need, we recommend subclassing those widgets rather than QtTableView. In addition, QScrollView makes it easy to have child widgets inside tables, which QtTableView doesn't support at all. \sa QScrollView \link guibooks.html#fowler GUI Design Handbook: Table\endlink */ /*! Constructs a table view. The \a parent, \a name and \f arguments are passed to the QFrame constructor. The \link setTableFlags() table flags\endlink are all cleared (set to 0). Set \c Tbl_autoVScrollBar or \c Tbl_autoHScrollBar to get automatic scroll bars and \c Tbl_clipCellPainting to get safe clipping. The \link setCellHeight() cell height\endlink and \link setCellWidth() cell width\endlink are set to 0. Frame line shapes (QFrame::HLink and QFrame::VLine) are disallowed; see QFrame::setFrameStyle(). Note that the \a f argument is \e not \link setTableFlags() table flags \endlink but rather \link QWidget::QWidget() widget flags. \endlink */ QtTableView::QtTableView( QWidget *parent, const char *name, WFlags f ) : QFrame( parent, name, f ) { nRows = nCols = 0; // zero rows/cols xCellOffs = yCellOffs = 0; // zero offset xCellDelta = yCellDelta = 0; // zero cell offset xOffs = yOffs = 0; // zero total pixel offset cellH = cellW = 0; // user defined cell size tFlags = 0; vScrollBar = hScrollBar = 0; // no scroll bars cornerSquare = 0; sbDirty = 0; eraseInPaint = FALSE; verSliding = FALSE; verSnappingOff = FALSE; horSliding = FALSE; horSnappingOff = FALSE; coveringCornerSquare = FALSE; inSbUpdate = FALSE; } /*! Destroys the table view. */ QtTableView::~QtTableView() { delete vScrollBar; delete hScrollBar; delete cornerSquare; } /*! \internal Reimplements QWidget::setBackgroundColor() for binary compatibility. \sa setPalette() */ void QtTableView::setBackgroundColor( const QColor &c ) { QWidget::setBackgroundColor( c ); } /*!\reimp */ void QtTableView::setPalette( const QPalette &p ) { QWidget::setPalette( p ); } /*!\reimp */ void QtTableView::show() { showOrHideScrollBars(); QWidget::show(); } /*! \overload void QtTableView::repaint( bool erase ) Repaints the entire view. */ /*! Repaints the table view directly by calling paintEvent() directly unless updates are disabled. Erases the view area \a (x,y,w,h) if \a erase is TRUE. Parameters \a (x,y) are in \e widget coordinates. If \a w is negative, it is replaced with width() - x. If \a h is negative, it is replaced with height() - y. Doing a repaint() usually is faster than doing an update(), but calling update() many times in a row will generate a single paint event. At present, QtTableView is the only widget that reimplements \link QWidget::repaint() repaint()\endlink. It does this because by clearing and then repainting one cell at at time, it can make the screen flicker less than it would otherwise. */ void QtTableView::repaint( int x, int y, int w, int h, bool erase ) { if ( !isVisible() || testWState(WState_BlockUpdates) ) return; if ( w < 0 ) w = width() - x; if ( h < 0 ) h = height() - y; QRect r( x, y, w, h ); if ( r.isEmpty() ) return; // nothing to do QPaintEvent e( r ); if ( erase && backgroundMode() != NoBackground ) eraseInPaint = TRUE; // erase when painting paintEvent( &e ); eraseInPaint = FALSE; } /*! \overload void QtTableView::repaint( const QRect &r, bool erase ) Replaints rectangle \a r. If \a erase is TRUE draws the background using the palette's background. */ /*! \fn int QtTableView::numRows() const Returns the number of rows in the table. \sa numCols(), setNumRows() */ /*! Sets the number of rows of the table to \a rows (must be non-negative). Does not change topCell(). The table repaints itself automatically if autoUpdate() is set. \sa numCols(), setNumCols(), numRows() */ void QtTableView::setNumRows( int rows ) { if ( rows < 0 ) { #if defined(QT_CHECK_RANGE) qWarning( "QtTableView::setNumRows: (%s) Negative argument %d.", name( "unnamed" ), rows ); #endif return; } if ( nRows == rows ) return; if ( autoUpdate() && isVisible() ) { int oldLastVisible = lastRowVisible(); int oldTopCell = topCell(); nRows = rows; if ( autoUpdate() && isVisible() && ( oldLastVisible != lastRowVisible() || oldTopCell != topCell() ) ) repaint( oldTopCell != topCell() ); } else { // Be more careful - if destructing, bad things might happen. nRows = rows; } updateScrollBars( verRange ); updateFrameSize(); } /*! \fn int QtTableView::numCols() const Returns the number of columns in the table. \sa numRows(), setNumCols() */ /*! Sets the number of columns of the table to \a cols (must be non-negative). Does not change leftCell(). The table repaints itself automatically if autoUpdate() is set. \sa numCols(), numRows(), setNumRows() */ void QtTableView::setNumCols( int cols ) { if ( cols < 0 ) { #if defined(QT_CHECK_RANGE) qWarning( "QtTableView::setNumCols: (%s) Negative argument %d.", name( "unnamed" ), cols ); #endif return; } if ( nCols == cols ) return; int oldCols = nCols; nCols = cols; if ( autoUpdate() && isVisible() ) { int maxCol = lastColVisible(); if ( maxCol >= oldCols || maxCol >= nCols ) repaint(); } updateScrollBars( horRange ); updateFrameSize(); } /*! \fn int QtTableView::topCell() const Returns the index of the first row in the table that is visible in the view. The index of the first row is 0. \sa leftCell(), setTopCell() */ /*! Scrolls the table so that \a row becomes the top row. The index of the very first row is 0. \sa setYOffset(), setTopLeftCell(), setLeftCell() */ void QtTableView::setTopCell( int row ) { setTopLeftCell( row, -1 ); return; } /*! \fn int QtTableView::leftCell() const Returns the index of the first column in the table that is visible in the view. The index of the very leftmost column is 0. \sa topCell(), setLeftCell() */ /*! Scrolls the table so that \a col becomes the leftmost column. The index of the leftmost column is 0. \sa setXOffset(), setTopLeftCell(), setTopCell() */ void QtTableView::setLeftCell( int col ) { setTopLeftCell( -1, col ); return; } /*! Scrolls the table so that the cell at row \a row and colum \a col becomes the top-left cell in the view. The cell at the extreme top left of the table is at position (0,0). \sa setLeftCell(), setTopCell(), setOffset() */ void QtTableView::setTopLeftCell( int row, int col ) { int newX = xOffs; int newY = yOffs; if ( col >= 0 ) { if ( cellW ) { newX = col*cellW; if ( newX > maxXOffset() ) newX = maxXOffset(); } else { newX = 0; while ( col ) newX += cellWidth( --col ); // optimize using current! ### } } if ( row >= 0 ) { if ( cellH ) { newY = row*cellH; if ( newY > maxYOffset() ) newY = maxYOffset(); } else { newY = 0; while ( row ) newY += cellHeight( --row ); // optimize using current! ### } } setOffset( newX, newY ); } /*! \fn int QtTableView::xOffset() const Returns the x coordinate in \e table coordinates of the pixel that is currently on the left edge of the view. \sa setXOffset(), yOffset(), leftCell() */ /*! Scrolls the table so that \a x becomes the leftmost pixel in the view. The \a x parameter is in \e table coordinates. The interaction with \link setTableFlags() Tbl_snapToHGrid \endlink is tricky. \sa xOffset(), setYOffset(), setOffset(), setLeftCell() */ void QtTableView::setXOffset( int x ) { setOffset( x, yOffset() ); } /*! \fn int QtTableView::yOffset() const Returns the y coordinate in \e table coordinates of the pixel that is currently on the top edge of the view. \sa setYOffset(), xOffset(), topCell() */ /*! Scrolls the table so that \a y becomes the top pixel in the view. The \a y parameter is in \e table coordinates. The interaction with \link setTableFlags() Tbl_snapToVGrid \endlink is tricky. \sa yOffset(), setXOffset(), setOffset(), setTopCell() */ void QtTableView::setYOffset( int y ) { setOffset( xOffset(), y ); } /*! Scrolls the table so that \a (x,y) becomes the top-left pixel in the view. Parameters \a (x,y) are in \e table coordinates. The interaction with \link setTableFlags() Tbl_snapTo*Grid \endlink is tricky. If \a updateScrBars is TRUE, the scroll bars are updated. \sa xOffset(), yOffset(), setXOffset(), setYOffset(), setTopLeftCell() */ void QtTableView::setOffset( int x, int y, bool updateScrBars ) { if ( (!testTableFlags(Tbl_snapToHGrid) || xCellDelta == 0) && (!testTableFlags(Tbl_snapToVGrid) || yCellDelta == 0) && (x == xOffs && y == yOffs) ) return; if ( x < 0 ) x = 0; if ( y < 0 ) y = 0; if ( cellW ) { if ( x > maxXOffset() ) x = maxXOffset(); xCellOffs = x / cellW; if ( !testTableFlags(Tbl_snapToHGrid) ) { xCellDelta = (short)(x % cellW); } else { x = xCellOffs*cellW; xCellDelta = 0; } } else { int xn=0, xcd=0, col = 0; while ( col < nCols-1 && x >= xn+(xcd=cellWidth(col)) ) { xn += xcd; col++; } xCellOffs = col; if ( testTableFlags(Tbl_snapToHGrid) ) { xCellDelta = 0; x = xn; } else { xCellDelta = (short)(x-xn); } } if ( cellH ) { if ( y > maxYOffset() ) y = maxYOffset(); yCellOffs = y / cellH; if ( !testTableFlags(Tbl_snapToVGrid) ) { yCellDelta = (short)(y % cellH); } else { y = yCellOffs*cellH; yCellDelta = 0; } } else { int yn=0, yrd=0, row=0; while ( row < nRows-1 && y >= yn+(yrd=cellHeight(row)) ) { yn += yrd; row++; } yCellOffs = row; if ( testTableFlags(Tbl_snapToVGrid) ) { yCellDelta = 0; y = yn; } else { yCellDelta = (short)(y-yn); } } int dx = (x - xOffs); int dy = (y - yOffs); xOffs = x; yOffs = y; if ( autoUpdate() && isVisible() ) scroll( dx, dy ); if ( updateScrBars ) updateScrollBars( verValue | horValue ); } /*! \overload int QtTableView::cellWidth() const Returns the column width in pixels. Returns 0 if the columns have variable widths. \sa setCellWidth(), cellHeight() */ /*! Returns the width of column \a col in pixels. This function is virtual and must be reimplemented by subclasses that have variable cell widths. Note that if the total table width changes, updateTableSize() must be called. \sa setCellWidth(), cellHeight(), totalWidth(), updateTableSize() */ int QtTableView::cellWidth( int ) { return cellW; } /*! Sets the width in pixels of the table cells to \a cellWidth. Setting it to 0 means that the column width is variable. When set to 0 (this is the default) QtTableView calls the virtual function cellWidth() to get the width. \sa cellWidth(), setCellHeight(), totalWidth(), numCols() */ void QtTableView::setCellWidth( int cellWidth ) { if ( cellW == cellWidth ) return; #if defined(QT_CHECK_RANGE) if ( cellWidth < 0 || cellWidth > SHRT_MAX ) { qWarning( "QtTableView::setCellWidth: (%s) Argument out of range (%d)", name( "unnamed" ), cellWidth ); return; } #endif cellW = (short)cellWidth; updateScrollBars( horSteps | horRange ); if ( autoUpdate() && isVisible() ) repaint(); } /*! \overload int QtTableView::cellHeight() const Returns the row height, in pixels. Returns 0 if the rows have variable heights. \sa setCellHeight(), cellWidth() */ /*! Returns the height of row \a row in pixels. This function is virtual and must be reimplemented by subclasses that have variable cell heights. Note that if the total table height changes, updateTableSize() must be called. \sa setCellHeight(), cellWidth(), totalHeight() */ int QtTableView::cellHeight( int ) { return cellH; } /*! Sets the height in pixels of the table cells to \a cellHeight. Setting it to 0 means that the row height is variable. When set to 0 (this is the default), QtTableView calls the virtual function cellHeight() to get the height. \sa cellHeight(), setCellWidth(), totalHeight(), numRows() */ void QtTableView::setCellHeight( int cellHeight ) { if ( cellH == cellHeight ) return; #if defined(QT_CHECK_RANGE) if ( cellHeight < 0 || cellHeight > SHRT_MAX ) { qWarning( "QtTableView::setCellHeight: (%s) Argument out of range (%d)", name( "unnamed" ), cellHeight ); return; } #endif cellH = (short)cellHeight; if ( autoUpdate() && isVisible() ) repaint(); updateScrollBars( verSteps | verRange ); } /*! Returns the total width of the table in pixels. This function is virtual and should be reimplemented by subclasses that have variable cell widths and a non-trivial cellWidth() function, or a large number of columns in the table. The default implementation may be slow for very wide tables. \sa cellWidth(), totalHeight() */ int QtTableView::totalWidth() { if ( cellW ) { return cellW*nCols; } else { int tw = 0; for( int i = 0 ; i < nCols ; i++ ) tw += cellWidth( i ); return tw; } } /*! Returns the total height of the table in pixels. This function is virtual and should be reimplemented by subclasses that have variable cell heights and a non-trivial cellHeight() function, or a large number of rows in the table. The default implementation may be slow for very tall tables. \sa cellHeight(), totalWidth() */ int QtTableView::totalHeight() { if ( cellH ) { return cellH*nRows; } else { int th = 0; for( int i = 0 ; i < nRows ; i++ ) th += cellHeight( i ); return th; } } /*! \fn uint QtTableView::tableFlags() const Returns the union of the table flags that are currently set. \sa setTableFlags(), clearTableFlags(), testTableFlags() */ /*! \fn bool QtTableView::testTableFlags( uint f ) const Returns TRUE if any of the table flags in \a f are currently set, otherwise FALSE. \sa setTableFlags(), clearTableFlags(), tableFlags() */ /*! Sets the table flags to \a f. If a flag setting changes the appearance of the table, the table is repainted if - and only if - autoUpdate() is TRUE. The table flags are mostly single bits, though there are some multibit flags for convenience. Here is a complete list:
Tbl_vScrollBar
- The table has a vertical scroll bar.
Tbl_hScrollBar
- The table has a horizontal scroll bar.
Tbl_autoVScrollBar
- The table has a vertical scroll bar if - and only if - the table is taller than the view.
Tbl_autoHScrollBar
The table has a horizontal scroll bar if - and only if - the table is wider than the view.
Tbl_autoScrollBars
- The union of the previous two flags.
Tbl_clipCellPainting
- The table uses QPainter::setClipRect() to make sure that paintCell() will not draw outside the cell boundaries.
Tbl_cutCellsV
- The table will never show part of a cell at the bottom of the table; if there is not space for all of a cell, the space is left blank.
Tbl_cutCellsH
- The table will never show part of a cell at the right side of the table; if there is not space for all of a cell, the space is left blank.
Tbl_cutCells
- The union of the previous two flags.
Tbl_scrollLastHCell
- When the user scrolls horizontally, let him/her scroll the last cell left until it is at the left edge of the view. If this flag is not set, the user can only scroll to the point where the last cell is completely visible.
Tbl_scrollLastVCell
- When the user scrolls vertically, let him/her scroll the last cell up until it is at the top edge of the view. If this flag is not set, the user can only scroll to the point where the last cell is completely visible.
Tbl_scrollLastCell
- The union of the previous two flags.
Tbl_smoothHScrolling
- The table scrolls as smoothly as possible when the user scrolls horizontally. When this flag is not set, scrolling is done one cell at a time.
Tbl_smoothVScrolling
- The table scrolls as smoothly as possible when scrolling vertically. When this flag is not set, scrolling is done one cell at a time.
Tbl_smoothScrolling
- The union of the previous two flags.
Tbl_snapToHGrid
- Except when the user is actually scrolling, the leftmost column shown snaps to the leftmost edge of the view.
Tbl_snapToVGrid
- Except when the user is actually scrolling, the top row snaps to the top edge of the view.
Tbl_snapToGrid
- The union of the previous two flags.
You can specify more than one flag at a time using bitwise OR. Example: \code setTableFlags( Tbl_smoothScrolling | Tbl_autoScrollBars ); \endcode \warning The cutCells options (\c Tbl_cutCells, \c Tbl_cutCellsH and Tbl_cutCellsV) may cause painting problems when scrollbars are enabled. Do not combine cutCells and scrollbars. \sa clearTableFlags(), testTableFlags(), tableFlags() */ void QtTableView::setTableFlags( uint f ) { f = (f ^ tFlags) & f; // clear flags already set tFlags |= f; bool updateOn = autoUpdate(); setAutoUpdate( FALSE ); uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH; if ( f & Tbl_vScrollBar ) { setVerScrollBar( TRUE ); } if ( f & Tbl_hScrollBar ) { setHorScrollBar( TRUE ); } if ( f & Tbl_autoVScrollBar ) { updateScrollBars( verRange ); } if ( f & Tbl_autoHScrollBar ) { updateScrollBars( horRange ); } if ( f & Tbl_scrollLastHCell ) { updateScrollBars( horRange ); } if ( f & Tbl_scrollLastVCell ) { updateScrollBars( verRange ); } if ( f & Tbl_snapToHGrid ) { updateScrollBars( horRange ); } if ( f & Tbl_snapToVGrid ) { updateScrollBars( verRange ); } if ( f & Tbl_snapToGrid ) { // Note: checks for 2 flags if ( (f & Tbl_snapToHGrid) != 0 && xCellDelta != 0 || //have to scroll? (f & Tbl_snapToVGrid) != 0 && yCellDelta != 0 ) { snapToGrid( (f & Tbl_snapToHGrid) != 0, // do snapping (f & Tbl_snapToVGrid) != 0 ); repaintMask |= Tbl_snapToGrid; // repaint table } } if ( updateOn ) { setAutoUpdate( TRUE ); updateScrollBars(); if ( isVisible() && (f & repaintMask) ) repaint(); } } /*! Clears the \link setTableFlags() table flags\endlink that are set in \a f. Example (clears a single flag): \code clearTableFlags( Tbl_snapToGrid ); \endcode The default argument clears all flags. \sa setTableFlags(), testTableFlags(), tableFlags() */ void QtTableView::clearTableFlags( uint f ) { f = (f ^ ~tFlags) & f; // clear flags that are already 0 tFlags &= ~f; bool updateOn = autoUpdate(); setAutoUpdate( FALSE ); uint repaintMask = Tbl_cutCellsV | Tbl_cutCellsH; if ( f & Tbl_vScrollBar ) { setVerScrollBar( FALSE ); } if ( f & Tbl_hScrollBar ) { setHorScrollBar( FALSE ); } if ( f & Tbl_scrollLastHCell ) { int maxX = maxXOffset(); if ( xOffs > maxX ) { setOffset( maxX, yOffs ); repaintMask |= Tbl_scrollLastHCell; } updateScrollBars( horRange ); } if ( f & Tbl_scrollLastVCell ) { int maxY = maxYOffset(); if ( yOffs > maxY ) { setOffset( xOffs, maxY ); repaintMask |= Tbl_scrollLastVCell; } updateScrollBars( verRange ); } if ( f & Tbl_smoothScrolling ) { // Note: checks for 2 flags if ((f & Tbl_smoothHScrolling) != 0 && xCellDelta != 0 ||//must scroll? (f & Tbl_smoothVScrolling) != 0 && yCellDelta != 0 ) { snapToGrid( (f & Tbl_smoothHScrolling) != 0, // do snapping (f & Tbl_smoothVScrolling) != 0 ); repaintMask |= Tbl_smoothScrolling; // repaint table } } if ( f & Tbl_snapToHGrid ) { updateScrollBars( horRange ); } if ( f & Tbl_snapToVGrid ) { updateScrollBars( verRange ); } if ( updateOn ) { setAutoUpdate( TRUE ); updateScrollBars(); // returns immediately if nothing to do if ( isVisible() && (f & repaintMask) ) repaint(); } } /*! \fn bool QtTableView::autoUpdate() const Returns TRUE if the view updates itself automatically whenever it is changed in some way. \sa setAutoUpdate() */ /*! Sets the auto-update option of the table view to \a enable. If \a enable is TRUE (this is the default), the view updates itself automatically whenever it has changed in some way (for example, when a \link setTableFlags() flag\endlink is changed). If \a enable is FALSE, the view does NOT repaint itself or update its internal state variables when it is changed. This can be useful to avoid flicker during large changes and is singularly useless otherwise. Disable auto-update, do the changes, re-enable auto-update and call repaint(). \warning Do not leave the view in this state for a long time (i.e., between events). If, for example, the user interacts with the view when auto-update is off, strange things can happen. Setting auto-update to TRUE does not repaint the view; you must call repaint() to do this. \sa autoUpdate(), repaint() */ void QtTableView::setAutoUpdate( bool enable ) { if ( isUpdatesEnabled() == enable ) return; setUpdatesEnabled( enable ); if ( enable ) { showOrHideScrollBars(); updateScrollBars(); } } /*! Repaints the cell at row \a row, column \a col if it is inside the view. If \a erase is TRUE, the relevant part of the view is cleared to the background color/pixmap before the contents are repainted. \sa isVisible() */ void QtTableView::updateCell( int row, int col, bool erase ) { int xPos, yPos; if ( !colXPos( col, &xPos ) ) return; if ( !rowYPos( row, &yPos ) ) return; QRect uR = QRect( xPos, yPos, cellW ? cellW : cellWidth(col), cellH ? cellH : cellHeight(row) ); repaint( uR.intersect(viewRect()), erase ); } /*! \fn QRect QtTableView::cellUpdateRect() const This function should be called only from the paintCell() function in subclasses. It returns the portion of a cell that actually needs to be updated in \e cell coordinates. This is useful only for non-trivial paintCell(). */ /*! Returns the rectangle that is the actual table, excluding any frame, in \e widget coordinates. */ QRect QtTableView::viewRect() const { return QRect( frameWidth(), frameWidth(), viewWidth(), viewHeight() ); } /*! Returns the index of the last (bottom) row in the view. The index of the first row is 0. If no rows are visible it returns -1. This can happen if the view is too small for the first row and Tbl_cutCellsV is set. \sa lastColVisible() */ int QtTableView::lastRowVisible() const { int cellMaxY; int row = findRawRow( maxViewY(), &cellMaxY ); if ( row == -1 || row >= nRows ) { // maxViewY() past end? row = nRows - 1; // yes: return last row } else { if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) { if ( row == yCellOffs ) // cut by right margin? return -1; // yes, nothing in the view else row = row - 1; // cut by margin, one back } } return row; } /*! Returns the index of the last (right) column in the view. The index of the first column is 0. If no columns are visible it returns -1. This can happen if the view is too narrow for the first column and Tbl_cutCellsH is set. \sa lastRowVisible() */ int QtTableView::lastColVisible() const { int cellMaxX; int col = findRawCol( maxViewX(), &cellMaxX ); if ( col == -1 || col >= nCols ) { // maxViewX() past end? col = nCols - 1; // yes: return last col } else { if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) { if ( col == xCellOffs ) // cut by bottom margin? return -1; // yes, nothing in the view else col = col - 1; // cell by margin, one back } } return col; } /*! Returns TRUE if \a row is at least partially visible. \sa colIsVisible() */ bool QtTableView::rowIsVisible( int row ) const { return rowYPos( row, 0 ); } /*! Returns TRUE if \a col is at least partially visible. \sa rowIsVisible() */ bool QtTableView::colIsVisible( int col ) const { return colXPos( col, 0 ); } /*! \internal Called when both scroll bars are active at the same time. Covers the bottom left corner between the two scroll bars with an empty widget. */ void QtTableView::coverCornerSquare( bool enable ) { coveringCornerSquare = enable; if ( !cornerSquare && enable ) { cornerSquare = new QCornerSquare( this ); Q_CHECK_PTR( cornerSquare ); cornerSquare->setGeometry( maxViewX() + frameWidth() + 1, maxViewY() + frameWidth() + 1, VSBEXT, HSBEXT); } if ( autoUpdate() && cornerSquare ) { if ( enable ) cornerSquare->show(); else cornerSquare->hide(); } } /*! \internal Scroll the view to a position such that: If \a horizontal is TRUE, the leftmost column shown fits snugly with the left edge of the view. If \a vertical is TRUE, the top row shown fits snugly with the top of the view. You can achieve the same effect automatically by setting any of the \link setTableFlags() Tbl_snapTo*Grid \endlink table flags. */ void QtTableView::snapToGrid( bool horizontal, bool vertical ) { int newXCell = -1; int newYCell = -1; if ( horizontal && xCellDelta != 0 ) { int w = cellW ? cellW : cellWidth( xCellOffs ); if ( xCellDelta >= w/2 ) newXCell = xCellOffs + 1; else newXCell = xCellOffs; } if ( vertical && yCellDelta != 0 ) { int h = cellH ? cellH : cellHeight( yCellOffs ); if ( yCellDelta >= h/2 ) newYCell = yCellOffs + 1; else newYCell = yCellOffs; } setTopLeftCell( newYCell, newXCell ); //row,column } /*! \internal This internal slot is connected to the horizontal scroll bar's QScrollBar::valueChanged() signal. Moves the table horizontally to offset \a val without updating the scroll bar. */ void QtTableView::horSbValue( int val ) { if ( horSliding ) { horSliding = FALSE; if ( horSnappingOff ) { horSnappingOff = FALSE; tFlags |= Tbl_snapToHGrid; } } setOffset( val, yOffs, FALSE ); } /*! \internal This internal slot is connected to the horizontal scroll bar's QScrollBar::sliderMoved() signal. Scrolls the table smoothly horizontally even if \c Tbl_snapToHGrid is set. */ void QtTableView::horSbSliding( int val ) { if ( testTableFlags(Tbl_snapToHGrid) && testTableFlags(Tbl_smoothHScrolling) ) { tFlags &= ~Tbl_snapToHGrid; // turn off snapping while sliding setOffset( val, yOffs, FALSE ); tFlags |= Tbl_snapToHGrid; // turn on snapping again } else { setOffset( val, yOffs, FALSE ); } } /*! \internal This internal slot is connected to the horizontal scroll bar's QScrollBar::sliderReleased() signal. */ void QtTableView::horSbSlidingDone( ) { if ( testTableFlags(Tbl_snapToHGrid) && testTableFlags(Tbl_smoothHScrolling) ) snapToGrid( TRUE, FALSE ); } /*! \internal This internal slot is connected to the vertical scroll bar's QScrollBar::valueChanged() signal. Moves the table vertically to offset \a val without updating the scroll bar. */ void QtTableView::verSbValue( int val ) { if ( verSliding ) { verSliding = FALSE; if ( verSnappingOff ) { verSnappingOff = FALSE; tFlags |= Tbl_snapToVGrid; } } setOffset( xOffs, val, FALSE ); } /*! \internal This internal slot is connected to the vertical scroll bar's QScrollBar::sliderMoved() signal. Scrolls the table smoothly vertically even if \c Tbl_snapToVGrid is set. */ void QtTableView::verSbSliding( int val ) { if ( testTableFlags(Tbl_snapToVGrid) && testTableFlags(Tbl_smoothVScrolling) ) { tFlags &= ~Tbl_snapToVGrid; // turn off snapping while sliding setOffset( xOffs, val, FALSE ); tFlags |= Tbl_snapToVGrid; // turn on snapping again } else { setOffset( xOffs, val, FALSE ); } } /*! \internal This internal slot is connected to the vertical scroll bar's QScrollBar::sliderReleased() signal. */ void QtTableView::verSbSlidingDone( ) { if ( testTableFlags(Tbl_snapToVGrid) && testTableFlags(Tbl_smoothVScrolling) ) snapToGrid( FALSE, TRUE ); } /*! This virtual function is called before painting of table cells is started. It can be reimplemented by subclasses that want to to set up the painter in a special way and that do not want to do so for each cell. */ void QtTableView::setupPainter( QPainter * ) { } /*! \fn void QtTableView::paintCell( QPainter *p, int row, int col ) This pure virtual function is called to paint the single cell at \a (row,col) using \a p, which is open when paintCell() is called and must remain open. The coordinate system is \link QPainter::translate() translated \endlink so that the origin is at the top-left corner of the cell to be painted, i.e. \e cell coordinates. Do not scale or shear the coordinate system (or if you do, restore the transformation matrix before you return). The painter is not clipped by default and for maximum efficiency. For safety, call setTableFlags(Tbl_clipCellPainting) to enable clipping. \sa paintEvent(), setTableFlags() */ /*! Handles paint events, \a e, for the table view. Calls paintCell() for the cells that needs to be repainted. */ void QtTableView::paintEvent( QPaintEvent *e ) { QRect updateR = e->rect(); // update rectangle if ( sbDirty ) { bool e = eraseInPaint; updateScrollBars(); eraseInPaint = e; } QPainter paint( this ); if ( !contentsRect().contains( updateR, TRUE ) ) {// update frame ? drawFrame( &paint ); if ( updateR.left() < frameWidth() ) //### updateR.setLeft( frameWidth() ); if ( updateR.top() < frameWidth() ) updateR.setTop( frameWidth() ); } int maxWX = maxViewX(); int maxWY = maxViewY(); if ( updateR.right() > maxWX ) updateR.setRight( maxWX ); if ( updateR.bottom() > maxWY ) updateR.setBottom( maxWY ); setupPainter( &paint ); // prepare for painting table int firstRow = findRow( updateR.y() ); int firstCol = findCol( updateR.x() ); int xStart, yStart; if ( !colXPos( firstCol, &xStart ) || !rowYPos( firstRow, &yStart ) ) { paint.eraseRect( updateR ); // erase area outside cells but in view return; } int maxX = updateR.right(); int maxY = updateR.bottom(); int row = firstRow; int col; int yPos = yStart; int xPos = maxX+1; // in case the while() is empty int nextX; int nextY; QRect winR = viewRect(); QRect cellR; QRect cellUR; #ifndef QT_NO_TRANSFORMATIONS QWMatrix matrix; #endif while ( yPos <= maxY && row < nRows ) { nextY = yPos + (cellH ? cellH : cellHeight( row )); if ( testTableFlags( Tbl_cutCellsV ) && nextY > ( maxWY + 1 ) ) break; col = firstCol; xPos = xStart; while ( xPos <= maxX && col < nCols ) { nextX = xPos + (cellW ? cellW : cellWidth( col )); if ( testTableFlags( Tbl_cutCellsH ) && nextX > ( maxWX + 1 ) ) break; cellR.setRect( xPos, yPos, cellW ? cellW : cellWidth(col), cellH ? cellH : cellHeight(row) ); cellUR = cellR.intersect( updateR ); if ( cellUR.isValid() ) { cellUpdateR = cellUR; cellUpdateR.moveBy( -xPos, -yPos ); // cell coordinates if ( eraseInPaint ) paint.eraseRect( cellUR ); #ifndef QT_NO_TRANSFORMATIONS matrix.translate( xPos, yPos ); paint.setWorldMatrix( matrix ); if ( testTableFlags(Tbl_clipCellPainting) || frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt paint.setClipRect( cellUR ); paintCell( &paint, row, col ); paint.setClipping( FALSE ); } else { paintCell( &paint, row, col ); } matrix.reset(); paint.setWorldMatrix( matrix ); #else paint.translate( xPos, yPos ); if ( testTableFlags(Tbl_clipCellPainting) || frameWidth() > 0 && !winR.contains( cellR ) ) { //##arnt paint.setClipRect( cellUR ); paintCell( &paint, row, col ); paint.setClipping( FALSE ); } else { paintCell( &paint, row, col ); } paint.translate( -xPos, -yPos ); #endif } col++; xPos = nextX; } row++; yPos = nextY; } // while painting we have to erase any areas in the view that // are not covered by cells but are covered by the paint event // rectangle these must be erased. We know that xPos is the last // x pixel updated + 1 and that yPos is the last y pixel updated + 1. // Note that this needs to be done regardless whether we do // eraseInPaint or not. Reason: a subclass may implement // flicker-freeness and encourage the use of repaint(FALSE). // The subclass, however, cannot draw all pixels, just those // inside the cells. So QtTableView is reponsible for all pixels // outside the cells. QRect viewR = viewRect(); const QColorGroup g = colorGroup(); if ( xPos <= maxX ) { QRect r = viewR; r.setLeft( xPos ); r.setBottom( yPossetCursor( arrowCursor ); #endif sb->resize( sb->sizeHint() ); // height is irrelevant Q_CHECK_PTR(sb); sb->setTracking( FALSE ); sb->setFocusPolicy( NoFocus ); connect( sb, SIGNAL(valueChanged(int)), SLOT(verSbValue(int))); connect( sb, SIGNAL(sliderMoved(int)), SLOT(verSbSliding(int))); connect( sb, SIGNAL(sliderReleased()), SLOT(verSbSlidingDone())); sb->hide(); that->vScrollBar = sb; return sb; } return vScrollBar; } /*! Returns a pointer to the horizontal scroll bar mainly so you can connect() to its signals. Note that the scroll bar works in pixel values; use findCol() to translate to cell numbers. */ QScrollBar *QtTableView::horizontalScrollBar() const { QtTableView *that = (QtTableView*)this; // semantic const if ( !hScrollBar ) { QScrollBar *sb = new QScrollBar( QScrollBar::Horizontal, that ); #ifndef QT_NO_CURSOR sb->setCursor( arrowCursor ); #endif sb->resize( sb->sizeHint() ); // width is irrelevant sb->setFocusPolicy( NoFocus ); Q_CHECK_PTR(sb); sb->setTracking( FALSE ); connect( sb, SIGNAL(valueChanged(int)), SLOT(horSbValue(int))); connect( sb, SIGNAL(sliderMoved(int)), SLOT(horSbSliding(int))); connect( sb, SIGNAL(sliderReleased()), SLOT(horSbSlidingDone())); sb->hide(); that->hScrollBar = sb; return sb; } return hScrollBar; } /*! Enables or disables the horizontal scroll bar, as required by setAutoUpdate() and the \link setTableFlags() table flags\endlink. */ void QtTableView::setHorScrollBar( bool on, bool update ) { if ( on ) { tFlags |= Tbl_hScrollBar; horizontalScrollBar(); // created if ( update ) updateScrollBars( horMask | verMask ); else sbDirty = sbDirty | (horMask | verMask); if ( testTableFlags( Tbl_vScrollBar ) ) coverCornerSquare( TRUE ); if ( autoUpdate() ) sbDirty = sbDirty | horMask; } else { tFlags &= ~Tbl_hScrollBar; if ( !hScrollBar ) return; coverCornerSquare( FALSE ); bool hideScrollBar = autoUpdate() && hScrollBar->isVisible(); if ( hideScrollBar ) hScrollBar->hide(); if ( update ) updateScrollBars( verMask ); else sbDirty = sbDirty | verMask; if ( hideScrollBar && isVisible() ) repaint( hScrollBar->x(), hScrollBar->y(), width() - hScrollBar->x(), hScrollBar->height() ); } if ( update ) updateFrameSize(); } /*! Enables or disables the vertical scroll bar, as required by setAutoUpdate() and the \link setTableFlags() table flags\endlink. */ void QtTableView::setVerScrollBar( bool on, bool update ) { if ( on ) { tFlags |= Tbl_vScrollBar; verticalScrollBar(); // created if ( update ) updateScrollBars( verMask | horMask ); else sbDirty = sbDirty | (horMask | verMask); if ( testTableFlags( Tbl_hScrollBar ) ) coverCornerSquare( TRUE ); if ( autoUpdate() ) sbDirty = sbDirty | verMask; } else { tFlags &= ~Tbl_vScrollBar; if ( !vScrollBar ) return; coverCornerSquare( FALSE ); bool hideScrollBar = autoUpdate() && vScrollBar->isVisible(); if ( hideScrollBar ) vScrollBar->hide(); if ( update ) updateScrollBars( horMask ); else sbDirty = sbDirty | horMask; if ( hideScrollBar && isVisible() ) repaint( vScrollBar->x(), vScrollBar->y(), vScrollBar->width(), height() - vScrollBar->y() ); } if ( update ) updateFrameSize(); } int QtTableView::findRawRow( int yPos, int *cellMaxY, int *cellMinY, bool goOutsideView ) const { int r = -1; if ( nRows == 0 ) return r; if ( goOutsideView || yPos >= minViewY() && yPos <= maxViewY() ) { if ( yPos < minViewY() ) { #if defined(QT_CHECK_RANGE) qWarning( "QtTableView::findRawRow: (%s) internal error: " "yPos < minViewY() && goOutsideView " "not supported. (%d,%d)", name( "unnamed" ), yPos, yOffs ); #endif return -1; } if ( cellH ) { // uniform cell height r = (yPos - minViewY() + yCellDelta)/cellH; // cell offs from top if ( cellMaxY ) *cellMaxY = (r + 1)*cellH + minViewY() - yCellDelta - 1; if ( cellMinY ) *cellMinY = r*cellH + minViewY() - yCellDelta; r += yCellOffs; // absolute cell index } else { // variable cell height QtTableView *tw = (QtTableView *)this; r = yCellOffs; int h = minViewY() - yCellDelta; //##arnt3 int oldH = h; Q_ASSERT( r < nRows ); while ( r < nRows ) { oldH = h; h += tw->cellHeight( r ); // Start of next cell if ( yPos < h ) break; r++; } if ( cellMaxY ) *cellMaxY = h - 1; if ( cellMinY ) *cellMinY = oldH; } } return r; } int QtTableView::findRawCol( int xPos, int *cellMaxX, int *cellMinX , bool goOutsideView ) const { int c = -1; if ( nCols == 0 ) return c; if ( goOutsideView || xPos >= minViewX() && xPos <= maxViewX() ) { if ( xPos < minViewX() ) { #if defined(QT_CHECK_RANGE) qWarning( "QtTableView::findRawCol: (%s) internal error: " "xPos < minViewX() && goOutsideView " "not supported. (%d,%d)", name( "unnamed" ), xPos, xOffs ); #endif return -1; } if ( cellW ) { // uniform cell width c = (xPos - minViewX() + xCellDelta)/cellW; //cell offs from left if ( cellMaxX ) *cellMaxX = (c + 1)*cellW + minViewX() - xCellDelta - 1; if ( cellMinX ) *cellMinX = c*cellW + minViewX() - xCellDelta; c += xCellOffs; // absolute cell index } else { // variable cell width QtTableView *tw = (QtTableView *)this; c = xCellOffs; int w = minViewX() - xCellDelta; //##arnt3 int oldW = w; Q_ASSERT( c < nCols ); while ( c < nCols ) { oldW = w; w += tw->cellWidth( c ); // Start of next cell if ( xPos < w ) break; c++; } if ( cellMaxX ) *cellMaxX = w - 1; if ( cellMinX ) *cellMinX = oldW; } } return c; } /*! Returns the index of the row at position \a yPos, where \a yPos is in \e widget coordinates. Returns -1 if \a yPos is outside the valid range. \sa findCol(), rowYPos() */ int QtTableView::findRow( int yPos ) const { int cellMaxY; int row = findRawRow( yPos, &cellMaxY ); if ( testTableFlags(Tbl_cutCellsV) && cellMaxY > maxViewY() ) row = - 1; // cell cut by bottom margin if ( row >= nRows ) row = -1; return row; } /*! Returns the index of the column at position \a xPos, where \a xPos is in \e widget coordinates. Returns -1 if \a xPos is outside the valid range. \sa findRow(), colXPos() */ int QtTableView::findCol( int xPos ) const { int cellMaxX; int col = findRawCol( xPos, &cellMaxX ); if ( testTableFlags(Tbl_cutCellsH) && cellMaxX > maxViewX() ) col = - 1; // cell cut by right margin if ( col >= nCols ) col = -1; return col; } /*! Computes the position in the widget of row \a row. Returns TRUE and stores the result in \a *yPos (in \e widget coordinates) if the row is visible. Returns FALSE and does not modify \a *yPos if \a row is invisible or invalid. \sa colXPos(), findRow() */ bool QtTableView::rowYPos( int row, int *yPos ) const { int y; if ( row >= yCellOffs ) { if ( cellH ) { int lastVisible = lastRowVisible(); if ( row > lastVisible || lastVisible == -1 ) return FALSE; y = (row - yCellOffs)*cellH + minViewY() - yCellDelta; } else { //##arnt3 y = minViewY() - yCellDelta; // y of leftmost cell in view int r = yCellOffs; QtTableView *tw = (QtTableView *)this; int maxY = maxViewY(); while ( r < row && y <= maxY ) y += tw->cellHeight( r++ ); if ( y > maxY ) return FALSE; } } else { return FALSE; } if ( yPos ) *yPos = y; return TRUE; } /*! Computes the position in the widget of column \a col. Returns TRUE and stores the result in \a *xPos (in \e widget coordinates) if the column is visible. Returns FALSE and does not modify \a *xPos if \a col is invisible or invalid. \sa rowYPos(), findCol() */ bool QtTableView::colXPos( int col, int *xPos ) const { int x; if ( col >= xCellOffs ) { if ( cellW ) { int lastVisible = lastColVisible(); if ( col > lastVisible || lastVisible == -1 ) return FALSE; x = (col - xCellOffs)*cellW + minViewX() - xCellDelta; } else { //##arnt3 x = minViewX() - xCellDelta; // x of uppermost cell in view int c = xCellOffs; QtTableView *tw = (QtTableView *)this; int maxX = maxViewX(); while ( c < col && x <= maxX ) x += tw->cellWidth( c++ ); if ( x > maxX ) return FALSE; } } else { return FALSE; } if ( xPos ) *xPos = x; return TRUE; } /*! Moves the visible area of the table right by \a xPixels and down by \a yPixels pixels. Both may be negative. \warning You might find that QScrollView offers a higher-level of functionality than using QtTableView and this function. This function is \e not the same as QWidget::scroll(); in particular, the signs of \a xPixels and \a yPixels have the reverse semantics. \sa setXOffset(), setYOffset(), setOffset(), setTopCell(), setLeftCell() */ void QtTableView::scroll( int xPixels, int yPixels ) { QWidget::scroll( -xPixels, -yPixels, contentsRect() ); } /*! Returns the leftmost pixel of the table view in \e view coordinates. This excludes the frame and any header. \sa maxViewY(), viewWidth(), contentsRect() */ int QtTableView::minViewX() const { return frameWidth(); } /*! Returns the top pixel of the table view in \e view coordinates. This excludes the frame and any header. \sa maxViewX(), viewHeight(), contentsRect() */ int QtTableView::minViewY() const { return frameWidth(); } /*! Returns the rightmost pixel of the table view in \e view coordinates. This excludes the frame and any scroll bar, but includes blank pixels to the right of the visible table data. \sa maxViewY(), viewWidth(), contentsRect() */ int QtTableView::maxViewX() const { return width() - 1 - frameWidth() - (tFlags & Tbl_vScrollBar ? VSBEXT : 0); } /*! Returns the bottom pixel of the table view in \e view coordinates. This excludes the frame and any scroll bar, but includes blank pixels below the visible table data. \sa maxViewX(), viewHeight(), contentsRect() */ int QtTableView::maxViewY() const { return height() - 1 - frameWidth() - (tFlags & Tbl_hScrollBar ? HSBEXT : 0); } /*! Returns the width of the table view, as such, in \e view coordinates. This does not include any header, scroll bar or frame, but it does include background pixels to the right of the table data. \sa minViewX() maxViewX(), viewHeight(), contentsRect() viewRect() */ int QtTableView::viewWidth() const { return maxViewX() - minViewX() + 1; } /*! Returns the height of the table view, as such, in \e view coordinates. This does not include any header, scroll bar or frame, but it does include background pixels below the table data. \sa minViewY() maxViewY() viewWidth() contentsRect() viewRect() */ int QtTableView::viewHeight() const { return maxViewY() - minViewY() + 1; } void QtTableView::doAutoScrollBars() { int viewW = width() - frameWidth() - minViewX(); int viewH = height() - frameWidth() - minViewY(); bool vScrollOn = testTableFlags(Tbl_vScrollBar); bool hScrollOn = testTableFlags(Tbl_hScrollBar); int w = 0; int h = 0; int i; if ( testTableFlags(Tbl_autoHScrollBar) ) { if ( cellW ) { w = cellW*nCols; } else { i = 0; while ( i < nCols && w <= viewW ) w += cellWidth( i++ ); } if ( w > viewW ) hScrollOn = TRUE; else hScrollOn = FALSE; } if ( testTableFlags(Tbl_autoVScrollBar) ) { if ( cellH ) { h = cellH*nRows; } else { i = 0; while ( i < nRows && h <= viewH ) h += cellHeight( i++ ); } if ( h > viewH ) vScrollOn = TRUE; else vScrollOn = FALSE; } if ( testTableFlags(Tbl_autoHScrollBar) && vScrollOn && !hScrollOn ) if ( w > viewW - VSBEXT ) hScrollOn = TRUE; if ( testTableFlags(Tbl_autoVScrollBar) && hScrollOn && !vScrollOn ) if ( h > viewH - HSBEXT ) vScrollOn = TRUE; setHorScrollBar( hScrollOn, FALSE ); setVerScrollBar( vScrollOn, FALSE ); updateFrameSize(); } /*! \fn void QtTableView::updateScrollBars() Updates the scroll bars' contents and presence to match the table's state. Generally, you should not need to call this. \sa setTableFlags() */ /*! Updates the scroll bars' contents and presence to match the table's state \c or \a f. \sa setTableFlags() */ void QtTableView::updateScrollBars( uint f ) { sbDirty = sbDirty | f; if ( inSbUpdate ) return; inSbUpdate = TRUE; if ( testTableFlags(Tbl_autoHScrollBar) && (sbDirty & horRange) || testTableFlags(Tbl_autoVScrollBar) && (sbDirty & verRange) ) // if range change and auto doAutoScrollBars(); // turn scroll bars on/off if needed if ( !autoUpdate() ) { inSbUpdate = FALSE; return; } if ( yOffset() > 0 && testTableFlags( Tbl_autoVScrollBar ) && !testTableFlags( Tbl_vScrollBar ) ) { setYOffset( 0 ); } if ( xOffset() > 0 && testTableFlags( Tbl_autoHScrollBar ) && !testTableFlags( Tbl_hScrollBar ) ) { setXOffset( 0 ); } if ( !isVisible() ) { inSbUpdate = FALSE; return; } if ( testTableFlags(Tbl_hScrollBar) && (sbDirty & horMask) != 0 ) { if ( sbDirty & horGeometry ) hScrollBar->setGeometry( 0,height() - HSBEXT, viewWidth() + frameWidth()*2, HSBEXT); if ( sbDirty & horSteps ) { if ( cellW ) hScrollBar->setSteps( QMIN(cellW,viewWidth()/2), viewWidth() ); else hScrollBar->setSteps( 16, viewWidth() ); } if ( sbDirty & horRange ) hScrollBar->setRange( 0, maxXOffset() ); if ( sbDirty & horValue ) hScrollBar->setValue( xOffs ); // show scrollbar only when it has a sane geometry if ( !hScrollBar->isVisible() ) hScrollBar->show(); } if ( testTableFlags(Tbl_vScrollBar) && (sbDirty & verMask) != 0 ) { if ( sbDirty & verGeometry ) vScrollBar->setGeometry( width() - VSBEXT, 0, VSBEXT, viewHeight() + frameWidth()*2 ); if ( sbDirty & verSteps ) { if ( cellH ) vScrollBar->setSteps( QMIN(cellH,viewHeight()/2), viewHeight() ); else vScrollBar->setSteps( 16, viewHeight() ); // fttb! ### } if ( sbDirty & verRange ) vScrollBar->setRange( 0, maxYOffset() ); if ( sbDirty & verValue ) vScrollBar->setValue( yOffs ); // show scrollbar only when it has a sane geometry if ( !vScrollBar->isVisible() ) vScrollBar->show(); } if ( coveringCornerSquare && ( (sbDirty & verGeometry ) || (sbDirty & horGeometry)) ) cornerSquare->move( maxViewX() + frameWidth() + 1, maxViewY() + frameWidth() + 1 ); sbDirty = 0; inSbUpdate = FALSE; } void QtTableView::updateFrameSize() { int rw = width() - ( testTableFlags(Tbl_vScrollBar) ? VSBEXT : 0 ); int rh = height() - ( testTableFlags(Tbl_hScrollBar) ? HSBEXT : 0 ); if ( rw < 0 ) rw = 0; if ( rh < 0 ) rh = 0; if ( autoUpdate() ) { int fh = frameRect().height(); int fw = frameRect().width(); setFrameRect( QRect(0,0,rw,rh) ); if ( rw != fw ) update( QMIN(fw,rw) - frameWidth() - 2, 0, frameWidth()+4, rh ); if ( rh != fh ) update( 0, QMIN(fh,rh) - frameWidth() - 2, rw, frameWidth()+4 ); } } /*! Returns the maximum horizontal offset within the table of the view's left edge in \e table coordinates. This is used mainly to set the horizontal scroll bar's range. \sa maxColOffset(), maxYOffset(), totalWidth() */ int QtTableView::maxXOffset() { int tw = totalWidth(); int maxOffs; if ( testTableFlags(Tbl_scrollLastHCell) ) { if ( nCols != 1) maxOffs = tw - ( cellW ? cellW : cellWidth( nCols - 1 ) ); else maxOffs = tw - viewWidth(); } else { if ( testTableFlags(Tbl_snapToHGrid) ) { if ( cellW ) { maxOffs = tw - (viewWidth()/cellW)*cellW; } else { int goal = tw - viewWidth(); int pos = tw; int nextCol = nCols - 1; int nextCellWidth = cellWidth( nextCol ); while( nextCol > 0 && pos > goal + nextCellWidth ) { pos -= nextCellWidth; nextCellWidth = cellWidth( --nextCol ); } if ( goal + nextCellWidth == pos ) maxOffs = goal; else if ( goal < pos ) maxOffs = pos; else maxOffs = 0; } } else { maxOffs = tw - viewWidth(); } } return maxOffs > 0 ? maxOffs : 0; } /*! Returns the maximum vertical offset within the table of the view's top edge in \e table coordinates. This is used mainly to set the vertical scroll bar's range. \sa maxRowOffset(), maxXOffset(), totalHeight() */ int QtTableView::maxYOffset() { int th = totalHeight(); int maxOffs; if ( testTableFlags(Tbl_scrollLastVCell) ) { if ( nRows != 1) maxOffs = th - ( cellH ? cellH : cellHeight( nRows - 1 ) ); else maxOffs = th - viewHeight(); } else { if ( testTableFlags(Tbl_snapToVGrid) ) { if ( cellH ) { maxOffs = th - (viewHeight()/cellH)*cellH; } else { int goal = th - viewHeight(); int pos = th; int nextRow = nRows - 1; int nextCellHeight = cellHeight( nextRow ); while( nextRow > 0 && pos > goal + nextCellHeight ) { pos -= nextCellHeight; nextCellHeight = cellHeight( --nextRow ); } if ( goal + nextCellHeight == pos ) maxOffs = goal; else if ( goal < pos ) maxOffs = pos; else maxOffs = 0; } } else { maxOffs = th - viewHeight(); } } return maxOffs > 0 ? maxOffs : 0; } /*! Returns the index of the last column, which may be at the left edge of the view. Depending on the \link setTableFlags() Tbl_scrollLastHCell\endlink flag, this may or may not be the last column. \sa maxXOffset(), maxRowOffset() */ int QtTableView::maxColOffset() { int mx = maxXOffset(); if ( cellW ) return mx/cellW; else { int xcd=0, col=0; while ( col < nCols && mx > (xcd=cellWidth(col)) ) { mx -= xcd; col++; } return col; } } /*! Returns the index of the last row, which may be at the top edge of the view. Depending on the \link setTableFlags() Tbl_scrollLastVCell\endlink flag, this may or may not be the last row. \sa maxYOffset(), maxColOffset() */ int QtTableView::maxRowOffset() { int my = maxYOffset(); if ( cellH ) return my/cellH; else { int ycd=0, row=0; while ( row < nRows && my > (ycd=cellHeight(row)) ) { my -= ycd; row++; } return row; } } void QtTableView::showOrHideScrollBars() { if ( !autoUpdate() ) return; if ( vScrollBar ) { if ( testTableFlags(Tbl_vScrollBar) ) { if ( !vScrollBar->isVisible() ) sbDirty = sbDirty | verMask; } else { if ( vScrollBar->isVisible() ) vScrollBar->hide(); } } if ( hScrollBar ) { if ( testTableFlags(Tbl_hScrollBar) ) { if ( !hScrollBar->isVisible() ) sbDirty = sbDirty | horMask; } else { if ( hScrollBar->isVisible() ) hScrollBar->hide(); } } if ( cornerSquare ) { if ( testTableFlags(Tbl_hScrollBar) && testTableFlags(Tbl_vScrollBar) ) { if ( !cornerSquare->isVisible() ) cornerSquare->show(); } else { if ( cornerSquare->isVisible() ) cornerSquare->hide(); } } } /*! Updates the scroll bars and internal state. Call this function when the table view's total size is changed; typically because the result of cellHeight() or cellWidth() have changed. This function does not repaint the widget. */ void QtTableView::updateTableSize() { bool updateOn = autoUpdate(); setAutoUpdate( FALSE ); int xofs = xOffset(); xOffs++; //so that setOffset will not return immediately setOffset(xofs,yOffset(),FALSE); //to calculate internal state correctly setAutoUpdate(updateOn); updateScrollBars( horSteps | horRange | verSteps | verRange ); showOrHideScrollBars(); } #endif #endif nethack-3.4.3/win/Qt/tileedit.cpp0100644000000000000000000002242007764735041015342 0ustar rootroot/* SCCS Id: @(#)tileedit.cpp 3.4 1999/11/19 */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ /* Build this little utility program if you want to use it to edit the tile files. Move tileedit.cpp and tileedit.h to ../../util, add the 3 lines below to the Makefile there and "make tileedit". tileedit: tileedit.cpp $(TEXT_IO) moc -o tileedit.moc tileedit.h $(CC) -o tileedit -I../include -I$(QTDIR)/include -L$(QTDIR)/lib tileedit.cpp $(TEXT_IO) -lqt */ #include "tileedit.h" #include #include #include #include #include #include #include #include #include extern "C" { #include "config.h" #include "tile.h" extern const char *FDECL(tilename, (int, int)); } #define TILES_ACROSS 20 TilePickerTab::TilePickerTab(const char* basename, int i, QWidget* parent) : QWidget(parent) { id = i; filename = basename; filename += ".txt"; num = 0; int index = 0; for (int real=0; real<2; real++) { if ( real ) { image.create( TILES_ACROSS*TILE_X, ((num+TILES_ACROSS-1)/TILES_ACROSS)*TILE_Y, 32 ); } if ( !fopen_text_file(filename.latin1(), RDTMODE) ) { // XXX handle better exit(1); } pixel p[TILE_Y][TILE_X]; while ( read_text_tile(p) ) { if ( real ) { int ox = (index%TILES_ACROSS)*TILE_X; int oy = (index/TILES_ACROSS)*TILE_Y; for ( int y=0; yx()-e->x()%TILE_X; int oy = e->y()-e->y()%TILE_Y; QImage subimage = image.copy(ox,oy,TILE_X,TILE_Y); if ( e->button() == RightButton ) { setCurrent(subimage); } else { last_pick = ox/TILE_X + oy/TILE_Y*TILES_ACROSS; } emit pick(subimage); emit pickName(tilename(id, last_pick)); } void TilePickerTab::setCurrent(const QImage& i) { int ox = last_pick%TILES_ACROSS * TILE_X; int oy = last_pick/TILES_ACROSS * TILE_Y; bitBlt( &image, ox, oy, &i ); bitBlt( &pixmap, ox, oy, &i ); repaint( ox, oy, TILE_X, TILE_Y, FALSE ); } QSize TilePickerTab::sizeHint() const { return pixmap.size(); } void TilePickerTab::paintEvent( QPaintEvent* ) { QPainter p(this); p.drawPixmap(0,0,pixmap); } static struct { const char* name; TilePickerTab* tab; } tileset[] = { { "monsters", 0 }, { "objects", 0 }, { "other", 0 }, { 0 } }; TilePicker::TilePicker(QWidget* parent) : QTabWidget(parent) { for (int i=0; tileset[i].name; i++) { QString tabname = tileset[i].name; tabname[0] = tabname[0].upper(); tileset[i].tab = new TilePickerTab(tileset[i].name,i+1,this); addTab( tileset[i].tab, tabname ); connect( tileset[i].tab, SIGNAL(pick(const QImage&)), this, SIGNAL(pick(const QImage&)) ); connect( tileset[i].tab, SIGNAL(pickName(const QString&)), this, SIGNAL(pickName(const QString&)) ); } } void TilePicker::setCurrent(const QImage& i) { ((TilePickerTab*)currentPage())->setCurrent(i); } void TilePicker::save() { for (int i=0; tileset[i].tab; i++) { tileset[i].tab->save(); } } TrivialTileEditor::TrivialTileEditor( QWidget* parent ) : QWidget(parent) { } const QImage& TrivialTileEditor::image() const { return img; } void TrivialTileEditor::setColor( QRgb rgb ) { pen = rgb; for (penpixel = 0; penpixelrect(); QPoint tl = imagePoint(r.topLeft()); QPoint br = imagePoint(r.bottomRight()); r = QRect(tl,br).intersect(img.rect()); QPainter painter(this); for (int y=r.top(); y<=r.bottom(); y++) { for (int x=r.left(); x<=r.right(); x++) { paintPoint(painter,QPoint(x,y)); } } } void TrivialTileEditor::paintPoint(QPainter& painter, QPoint p) { QPoint p1 = screenPoint(p); QPoint p2 = screenPoint(p+QPoint(1,1)); QColor c = img.color(img.scanLine(p.y())[p.x()]); painter.fillRect(QRect(p1,p2-QPoint(1,1)), c); } void TrivialTileEditor::mousePressEvent(QMouseEvent* e) { QPoint p = imagePoint(e->pos()); if ( !img.rect().contains(p) ) return; uchar& pixel = img.scanLine(p.y())[p.x()]; if ( e->button() == LeftButton ) { pixel = penpixel; QPainter painter(this); paintPoint(painter,p); } else if ( e->button() == RightButton ) { emit pick( img.color(pixel) ); } else if ( e->button() == MidButton ) { QPainter painter(this); if ( pixel != penpixel ) fill(painter,p,pixel); } } void TrivialTileEditor::fill(QPainter& painter, QPoint p, uchar from) { if ( img.rect().contains(p) ) { uchar& pixel = img.scanLine(p.y())[p.x()]; if ( pixel == from ) { pixel = penpixel; paintPoint(painter,p); fill(painter, p+QPoint(-1,0), from); fill(painter, p+QPoint(+1,0), from); fill(painter, p+QPoint(0,-1), from); fill(painter, p+QPoint(0,+1), from); } } } void TrivialTileEditor::mouseReleaseEvent(QMouseEvent* e) { emit edited(image()); } void TrivialTileEditor::mouseMoveEvent(QMouseEvent* e) { QPoint p = imagePoint(e->pos()); if ( !img.rect().contains(p) ) return; uchar& pixel = img.scanLine(p.y())[p.x()]; pixel = penpixel; QPainter painter(this); paintPoint(painter,p); } QPoint TrivialTileEditor::imagePoint(QPoint p) const { return QPoint(p.x()*TILE_X/width(), p.y()*TILE_Y/height()); } QPoint TrivialTileEditor::screenPoint(QPoint p) const { return QPoint(p.x()*width()/TILE_X, p.y()*height()/TILE_Y); } QSizePolicy TrivialTileEditor::sizePolicy() const { return QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding, TRUE ); } QSize TrivialTileEditor::sizeHint() const { return sizeForWidth(-1); } QSize TrivialTileEditor::sizeForWidth(int w) const { if ( w < 0 ) return QSize(TILE_X*32,TILE_Y*32); else return QSize(w,w*TILE_Y/TILE_X); } TilePalette::TilePalette( QWidget* parent ) : QWidget(parent) { num = 0; rgb = 0; } TilePalette::~TilePalette() { delete rgb; } void TilePalette::setFromImage( const QImage& i ) { num = i.numColors(); rgb = new QRgb[num]; memcpy(rgb, i.colorTable(), num*sizeof(QRgb)); repaint(FALSE); } void TilePalette::setColor(QRgb c) { for (int i=0; ix()*num/width(); emit pick(rgb[c]); } TileEditor::TileEditor(QWidget* parent) : QVBox(parent), editor(this), palette(this) { connect( &palette, SIGNAL(pick(QRgb)), &editor, SLOT(setColor(QRgb)) ); connect( &editor, SIGNAL(pick(QRgb)), &palette, SLOT(setColor(QRgb)) ); connect( &editor, SIGNAL(edited(const QImage&)), this, SIGNAL(edited(const QImage&)) ); } void TileEditor::edit(const QImage& i) { editor.setImage(i); palette.setFromImage(i); } const QImage& TileEditor::image() const { return editor.image(); } class Main : public QMainWindow { public: Main() : central(this), editor(¢ral), picker(¢ral) { QPopupMenu* file = new QPopupMenu(menuBar()); file->insertItem("&Save", &picker, SLOT(save()), CTRL+Key_S); file->insertSeparator(); file->insertItem("&Exit", qApp, SLOT(quit()), CTRL+Key_Q); menuBar()->insertItem("&File", file); connect( &picker, SIGNAL(pick(const QImage&)), &editor, SLOT(edit(const QImage&)) ); connect( &picker, SIGNAL(pickName(const QString&)), statusBar(), SLOT(message(const QString&)) ); connect( &editor, SIGNAL(edited(const QImage&)), &picker, SLOT(setCurrent(const QImage&)) ); setCentralWidget(¢ral); } private: QHBox central; TileEditor editor; TilePicker picker; }; main(int argc, char** argv) { QApplication app(argc,argv); Main m; app.setMainWidget(&m); m.show(); return app.exec(); } #include "tileedit.moc" nethack-3.4.3/win/Qt/tileedit.h0100644000000000000000000000504007764735041015006 0ustar rootroot/* SCCS Id: @(#)tileedit.h 3.4 1999/11/19 */ /* Copyright (c) Warwick Allison, 1999. */ /* NetHack may be freely redistributed. See license for details. */ #ifndef QNHTILEEDIT_H #define QNHTILEEDIT_H #include #include #include #include class TilePickerTab : public QWidget { Q_OBJECT public: TilePickerTab(const char* basename, int id, QWidget* parent); bool save(); int numTiles(); signals: void pick(const QImage&); void pickName(const QString&); public slots: void setCurrent(const QImage&); protected: void paintEvent( QPaintEvent* ); QSize sizeHint() const; void mousePressEvent(QMouseEvent*); private: QString filename; int id; int last_pick; int num; QPixmap pixmap; QImage image; }; class TilePicker : public QTabWidget { Q_OBJECT public: TilePicker(QWidget* parent); void setTile(int tilenum, const QImage&); signals: void pick(const QImage&); void pickName(const QString&); public slots: void setCurrent(const QImage&); void save(); }; class TrivialTileEditor : public QWidget { Q_OBJECT public: TrivialTileEditor( QWidget* parent ); const QImage& image() const; signals: void edited(const QImage&); void pick(QRgb); public slots: void setColor(QRgb); void setImage( const QImage& ); protected: void paintEvent( QPaintEvent* ); void mousePressEvent(QMouseEvent*); void mouseReleaseEvent(QMouseEvent*); void mouseMoveEvent(QMouseEvent*); QSize sizeHint() const; QSize sizeForWidth(int) const; QSizePolicy sizePolicy() const; private: void fill(QPainter& painter, QPoint p, uchar from); QImage img; QColor pen; int penpixel; void paintPoint(QPainter& painter, QPoint p); QPoint screenPoint(QPoint) const; QPoint imagePoint(QPoint) const; }; class TilePalette : public QWidget { Q_OBJECT public: TilePalette( QWidget* parent ); ~TilePalette(); void setFromImage( const QImage& ); protected: void paintEvent( QPaintEvent* ); void mousePressEvent(QMouseEvent*); QSize sizeHint() const; QSizePolicy sizePolicy() const; signals: void pick(QRgb); public slots: void setColor(QRgb); private: int num; QRgb *rgb; }; class TileEditor : public QVBox { Q_OBJECT public: TileEditor(QWidget* parent); const QImage& image() const; signals: void edited(const QImage&); public slots: void edit(const QImage&); private: TrivialTileEditor editor; TilePalette palette; }; #endif nethack-3.4.3/win/X11/0040755000000000000000000000000007764735105013024 5ustar rootrootnethack-3.4.3/win/X11/Install.X110100644000000000000000000002445007764735041014726 0ustar rootroot This document describes the installation of NetHack with an X11 interface. There are no explicit UNIX dependencies in this code, but we have only tested it under UNIX, using X11R4, X11R5, or X11R6. We have two reports that the code also works under DesqView/X on MS-DOS with djgpp, but you will have to add dependencies for the X code to that makefile before you can use it. Other X11R4+ platforms may work as well, with some tweaking likely. Follow WIN* in sys/unix/Makefile.src for compilation hints. (If you try to compile it with X11R3 or earlier, you will get many errors, starting with complaints about XtPointer not being declared. If you get around the compilation problems, you will still need a recent library of Athena Widgets to link against. Once compiled, you can probably run it under an R3 X server, though.) The reason this uses the Athena widget set is that the Athena widgets come free from MIT (like X11). Unfortunately, the companies that resell X11 (value subtracted er, added software; yea, yea, that's the ticket) usually discourage its use by either omitting the set or putting it on the "unsupported" portion of their tape. If you do not have the Athena widgets, you may obtain them via anonymous ftp from ftp.x.org. To use this code, define X11_GRAPHICS in include/config.h. (You can comment out TTY_GRAPHICS or change DEFAULT_WINDOW_SYS if you want to, but there's little reason to do so. The X11 version almost requires a config file for full effect, so you can just as well set windowtype there; also, you or someone else might just possibly be stuck in a situation where you can't use the X version -- over a non-blindingly-fast modem, say.) You may also want to define USE_XPM or GRAPHIC_TOMBSTONE as discussed below. In src/Makefile, add $(WINX11SRC), $(WINX11OBJ), and $(WINX11LIB) to WINSRC, WINOBJ, and WINLIB respectively, and compile. This will give you an executable supporting both X11 and tty windowing. If you want to use the optional tiles (multicolored pictures instead of a replacement font), you will need to have the win/share files and change the VARDATND setting in the top Makefile to contain the tile files before you do your 'make all'. If you get a linker error referring to `substitute_tiles' then most likely you have overlooked the WINSRC, WINOBJ, WINLIB step above. Alternatively, you are building with more than one non-tty interface specified but haven't followed the direction in src/Makefile to remove all but one instance of tile.o from the WINxxxOBJ values used for WINOBJ. When using tiles, you have the option of defining USE_XPM in config.h. This causes NetHack to use the XPM file format for the "x11tiles" file rather than a custom format. Since the XPM format can be processed by existing tools such as PBMPlus and XV, you can modify the tiles to suit your environment. However, you need to make sure the number of tiles in each row of the image remains the same (currently 40), as the code depends on this to calculate the size of each tile. For example, you may magnify them for display on high-resolution screens using the following command: xpmtoppm x11tiles | pnmscale -xscale 1 -yscale 1.6875 | pnmdepth 255 | ppmquant 100 | ppmtoxpm >x11tiles_big.xpm To use XPM, you must have the free XPM libraries installed in your system. Official xpm releases can be found by ftp on: ftp.x.org (198.4.202.8) contrib/libraries (Boston, USA) avahi.inria.fr (138.96.12.1) pub/xpm (Sophia Antipolis, France) If you do choose to define USE_XPM, be sure to add "-lXpm" to WINX11LIB in src/Makefile. If you define USE_XPM in config.h, you may also define GRAPHIC_TOMBSTONE which causes the closing tombstone to be displayed from the image file specified by the "tombstone" X resource (rip.xpm by default). In this case, make sure the top Makefile VARDATND also contains rip.xpm. Whether or not you install tile support, you can provide support for special graphics symbols via alternate fonts. (The fonts and tiles cannot be used at the same time, but the same executable handles both.) The two included X11 fonts use the general NetHack map area remapping to represent object/dungeon/trap/effect characters (see win/X11/nethack.rc and the Guidebook) as monocolored symbols and monsters as monocolored letters. For instance, a ruby potion will show up as a potion symbol in red. It's easier to see the difference between fonts and tiles than to describe it. :-) Unless you are the only one using your executable and you already know which you prefer, we suggest installing the optional files for both possibilities and letting each person decide for themselves. To use the included fonts, you will need to install one or both of them and then use the symbol mappings found in nethack.rc. The fonts are found in nh10.bdf and ibm.bdf. You first need to convert the bdf files to whatever form your X11 server recognizes (usually using a command called bdftosnf for R4 servers or bdftopcf for R5 servers). Then run mkfontdir on the directory containing your font files (you might want to copy them to GAMEDIR, from the top Makefile, after you've done "make install"). If these commands aren't familiar, talk to your local X11 guru and read the man pages. Finally, add that directory to your font search path (e.g. xset fp+ GAMEDIR, setting GAMEDIR to the value of GAMEDIR in the top Makefile). Alternatively, you (assuming you are a system administrator) can install the fonts in your standard X11 font directory. If you do not install the fonts in the standard X11 font directory, all persons playing nethack must add that "xset fp+" command to their .xinitrc file, or whatever file they execute when starting X11. Adding the "xset" command to the nethack.sh is also an alternative, though it may clutter your X11 font search path after playing several games, so this method is not recommended. See the note below for the alternative installation procedure for Sun's OpenWindows. If your X11 include files and libraries are not installed in a standard place (i.e. /usr/include/X11 and /usr/lib respectively) you will need to prepend an appropriate -I parameter to CFLAGS and a -L parameter to LFLAGS, setting to the place to find the include and library files for X11. Finally, to ensure NetHack's windows look the way they were intended to look, make sure the top Makefile VARDATND also contains NetHack.ad. If it does, running nethack will automatically take the appropriate steps to cause this file to be used to initialize NetHack's X11 resources. Three icon suggestions to the window manager are supported: nh72, nh56, and nh32. Data for them comes from the source files nh72icon, nh56icon, and nh32icon; they are compiled into the program via #includes in winX.c. Selection between them is controlled by the "icon" resource in NetHack.ad; the default is nh72. Sorry, an Imakefile is not included. Unlike many X11 programs, X11 support is only a small, optional, part of nethack, and the Makefile is needed for systems that don't use X11. Notes for Sun's OpenWindows: 1. For OpenWindows 3.0 (NOT 2.x), define OPENWINBUG in include/unixconf.h. The library bug from SunOS 4.1.x is fixed in Solaris 2.x (or when proper Sun patches have been applied to 4.1.x), so it is also unnecessary there. (Defining it when unnecessary causes the same problem being avoided when it is necessary. :-) 2. In addition to the changes suggested by the comments in src/Makefile, -- for OpenWindows 2.x and 3.0 (NOT 3.1) (i.e., versions for SunOS 4.x), add -I/usr/openwin/include to CFLAGS, -L/usr/openwin/lib to LFLAGS, and -lm to WINX11LIB in src/Makefile. -- for OpenWindows 3.1 (i.e., versions for Solaris 2.x), add -I/usr/openwin/include to CFLAGS, -L/usr/openwin/lib -L/usr/ccs/lib -R/usr/openwin/lib to LFLAGS, and -lsocket -lnsl -lm to WINX11LIB in src/Makefile. (Naturally, if your OpenWindows is installed elsewhere, adapt the openwin paths.) This will allow you to create a game executable. 3. Run the fonts through convertfont and run bldfamily on the directory. Now you must let your X server know where to find the fonts. For a personal installation, the simplest thing is to include the directory of the fonts in the environment variable FONTPATH, as set in your .profile or .login before starting the server. For a multi-user installation, you have the various "xset fp+" options outlined above for standard X. 4. Something must still be done with the NetHack.ad file -- all three of the possibilities mentioned for standard X11 should work. Notes for AIX 3.2: 1. AIX 3.2 includes the Athena Widget Toolkit library (and other things) under the /usr/lpp/X11/Xamples tree, so you will have to add -L/usr/lpp/X11/Xamples/lib to LFLAGS. If you can't find libXaw.a on your first build, go into /usr/lib/X11/Xamples, read the README file, and build the library. Notes for XFree86 - (on linux and BSD386 platforms) 1. Edit src/Makefile for linux/BSD386. Even though you use the Open Look Window manager, do not define OPENWINBUG. Use the standard X11 object and library options. 2. Follow the standard installation directions defined above. File Description --------- --------------------------------------------------------------- nethack.rc - A sample configuration file for fonts nh10 and ibm. nh10.bdf - A modified version of the 10x20 standard font. ibm.bdf - A modified version of one of the ibm (8x14) nethack font. Must be used in conjunction with NetHack.ad or nethack.rc. nh32icon - A 32x32 icon bitmap for use with window managers. nh56icon - A 56x56 icon bitmap for use with window managers. nh72icon - A 72x72 icon bitmap for use with window managers. nh_icon.xpm - A color icon for use with window managers. NetHack.ad - A sample .Xdefaults for a color screen. ../../include/Window.h ../../include/WindowP.h Window.c - A bare-bones widget that has 16 colors and a drawing canvas. ../../include/winX.h - Defines for the X window-port. win*.c - Code for the X window-port dialogs.c - A better dialog widget. Original code (modified slightly by Dean Luick) distributed under the X copyright by Tim Theisen. This is from his Ghostview program (which is under the GNU public license, v2 or higher). pet_mark.xbm - A pet indicator bitmap for tiles. rip.xpm - A graphical tombstone. tile2x11.c - Converts win/share tiles for X11 use. nethack-3.4.3/win/X11/NetHack.ad0100644000000000000000000001624107764735041014647 0ustar rootroot! The display_file, tombstone, and menu windows are all formatted assuming ! a fixed width font. Text windows may or may not be formatted as above. ! The rip window applies if the GRAPHIC_TOMBSTONE option is turned on, and ! requires a 12 pixel font for correct appearance. ! NetHack*font: variable NetHack*display_file*font: fixed NetHack*tombstone*font: fixed NetHack*text*rip*font: -*-times-medium-r-*-*-12-*-*-*-*-*-*-* NetHack*menu*font: fixed NetHack*text*font: fixed NetHack*map*font: nh10 ! To use full-color tiles for the map, uncomment the tile file name. ! If you use a 100dpi (or greater) monitor you may wish to double the ! tile size so you can see the figures. If NetHack was compiled to ! use XPM (USE_XPM in config.h), the tile_file is a standard XPM file. ! Otherwise, it is a custom format. double_tile_size only applies to ! the custom format - to enlarge an XPM file, use processing tools ! such as XV or preferably PBMplus. ! !NetHack.tile_file: x11tiles !NetHack.double_tile_size: True ! ! The annotation of pets. !NetHack.pet_mark_bitmap: pet_mark.xbm !NetHack.pet_mark_color: Red ! Tombstone ! The image file !NetHack.tombstone: rip.xpm ! Text starts at (tombtext_x, tombtext_y) and subsequent lines ! are displaced by (tombtext_dx, tombtext_dy) pixels. If you !NetHack.tombtext_x: 155 !NetHack.tombtext_y: 78 !NetHack.tombtext_dx: 0 !NetHack.tombtext_dy: 13 ! The color to use for the text on the hero's tombstone NetHack*rip*foreground: black ! Translation tables. There are currently several actions in nethack, but ! the only one you should be using is "input()", which, with no parameters, ! uses XLookupString to translate your keypress into a command. You ! can optionally give it parameters to change the behavior, see the example ! below. Note that you have to specify the translations in every appropriate ! window. NetHack*message*translations: : input() ! ! Example extra translations for the map window. ! !NetHack*map*translations: #override \ ! !Left: input(h) \n\ ! !Right: input(l) \n\ ! !Up: input(k) \n\ ! !Down: input(j) ! ! The icon to use; supported values are nh72, nh56, and nh32; nh72 is the ! default. Some window managers may not support the larger icon sizes. ! It is not guaranteed that the window manager will honor the icon selection. !NetHack*icon: nh56 ! ! If True, the default, a popup for single character prompts such as y/n ! questions is _not_ used. NetHack*slow: True ! The number of lines the message window will show without scrolling. !NetHack*message_lines: 12 ! ! If True, the message window has a line that seperates old and new messages. !NetHack*message_line: True ! ! If True, force keyboard to attach to popup windows. Some window managers ! enforce a click-to-focus-keyboard policy (e.g. the DECwindows wm). NetHack ! has a lot of popups and is almost unplayable without some kind of autofocus. !NetHack*autofocus: True ! ! Specify the number of rows and columns of the map window. The default ! is the standard 80x21 window. Note: this _does_not_ change nethack's ! level size, only what you see of it. !NetHack*map*rows: 21 !NetHack*map*columns: 80 ! Parts of the fancy status display. ! NetHack*status_condition.borderWidth: 0 NetHack*status_info*borderWidth: 0 ! Sample color screen entries. ! NetHack*nethack.background: wheat NetHack*map*yellow: gold NetHack*map*brown: tan NetHack*map*gray: grey85 NetHack*map*foreground: wheat NetHack*map*background: grey40 NetHack*fancy_status.skipAdjust: True NetHack*fancy_status.background: wheat NetHack*status_info*foreground: Sienna NetHack*status_info*background: wheat NetHack*status_info.background: wheat NetHack*status_attributes*foreground: black NetHack*status_attributes*background: white NetHack*status_condition*foreground: red NetHack*status_condition*background: wheat NetHack*Scrollbar*foreground: Sienna NetHack*Scrollbar*background: wheat NetHack*status_info*showGrip: False NetHack*status_attributes*showGrip: False NetHack*player_selection*random.borderColor: blue NetHack*player_selection*random.borderWidth: 2 NetHack*player_selection*random.foreground: blue NetHack*player_selection*random.accelerators: #override\n\ Return: set() notify() unset() NetHack*player_selection*quit.borderColor: blue NetHack*player_selection*quit.foreground: blue NetHack*player_selection*Command.borderColor: red NetHack*player_selection*Command.foreground: red NetHack*player_selection*quit.accelerators: #override\n\ Escape: set() notify() unset() NetHack*race_selection*random.borderColor: blue NetHack*race_selection*random.borderWidth: 2 NetHack*race_selection*random.foreground: blue NetHack*race_selection*random.accelerators: #override\n\ Return: set() notify() unset() NetHack*race_selection*quit.borderColor: blue NetHack*race_selection*quit.foreground: blue NetHack*race_selection*Command.borderColor: red NetHack*race_selection*Command.foreground: red NetHack*race_selection*quit.accelerators: #override\n\ Escape: set() notify() unset() NetHack*gender_selection*random.borderColor: blue NetHack*gender_selection*random.borderWidth: 2 NetHack*gender_selection*random.foreground: blue NetHack*gender_selection*random.accelerators: #override\n\ Return: set() notify() unset() NetHack*gender_selection*quit.borderColor: blue NetHack*gender_selection*quit.foreground: blue NetHack*gender_selection*Command.borderColor: red NetHack*gender_selection*Command.foreground: red NetHack*gender_selection*quit.accelerators: #override\n\ Escape: set() notify() unset() NetHack*alignment_selection*random.borderColor: blue NetHack*alignment_selection*random.borderWidth: 2 NetHack*alignment_selection*random.foreground: blue NetHack*alignment_selection*random.accelerators: #override\n\ Return: set() notify() unset() NetHack*alignment_selection*quit.borderColor: blue NetHack*alignment_selection*quit.foreground: blue NetHack*alignment_selection*Command.borderColor: red NetHack*alignment_selection*Command.foreground: red NetHack*alignment_selection*quit.accelerators: #override\n\ Escape: set() notify() unset() NetHack*extended_commands*dismiss.borderColor: blue NetHack*extended_commands*dismiss.foreground: blue NetHack*extended_commands*help.borderColor: blue NetHack*extended_commands*help.foreground: blue NetHack*extended_commands*Command.borderColor: red NetHack*extended_commands*Command.foreground: red NetHack*extended_commands*help.accelerators: #override\n\ :?: set() notify() unset() NetHack*extended_commands*dismiss.accelerators: #override\n\ Escape: set() notify() unset() ! ! ! The following are the default 15 colors that the nethack map uses. ! If they don't look good on your screen, change them. ! ! The foreground color is used as "no color". ! !NetHack*map*black: black !NetHack*map*red: red !NetHack*map*green: pale green !NetHack*map*brown: brown !NetHack*map*blue: blue !NetHack*map*magenta: magenta !NetHack*map*cyan: light cyan !NetHack*map*gray: gray !NetHack*map*orange: orange !NetHack*map*bright_green: green !NetHack*map*yellow: yellow !NetHack*map*bright_blue: royal blue !NetHack*map*bright_magenta: violet !NetHack*map*bright_cyan: cyan !NetHack*map*white: white nethack-3.4.3/win/X11/Window.c0100644000000000000000000001224607764735041014440 0ustar rootroot/* SCCS Id: @(#)Window.c 3.4 1993/02/02 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Data structures and support routines for the Window widget. This is a * drawing canvas with 16 colors and one font. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #ifdef MSDOS /* from compiler */ #define SHORT_FILENAMES #endif #ifdef SHORT_FILENAMES #include #else #include #endif #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "xwindowp.h" #include "config.h" static XtResource resources[] = { #define offset(field) XtOffset(WindowWidget, window.field) /* {name, class, type, size, offset, default_type, default_addr}, */ { XtNrows, XtCRows, XtRDimension, sizeof(Dimension), offset(rows), XtRImmediate, (XtPointer) 21}, { XtNcolumns, XtCColumns, XtRDimension, sizeof(Dimension), offset(columns), XtRImmediate, (XtPointer) 80}, { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(foreground), XtRString, XtDefaultForeground }, { XtNblack, XtCColor, XtRPixel, sizeof(Pixel), offset(black), XtRString, "black"}, { XtNred, XtCColor, XtRPixel, sizeof(Pixel), offset(red), XtRString, "red" }, { XtNgreen, XtCColor, XtRPixel, sizeof(Pixel), offset(green), XtRString, "pale green" }, { XtNbrown, XtCColor, XtRPixel, sizeof(Pixel), offset(brown), XtRString, "brown" }, { XtNblue, XtCColor, XtRPixel, sizeof(Pixel), offset(blue), XtRString, "blue" }, { XtNmagenta, XtCColor, XtRPixel, sizeof(Pixel), offset(magenta), XtRString, "magenta" }, { XtNcyan, XtCColor, XtRPixel, sizeof(Pixel), offset(cyan), XtRString, "light cyan" }, { XtNgray, XtCColor, XtRPixel, sizeof(Pixel), offset(gray), XtRString, "gray" }, { XtNorange, XtCColor, XtRPixel, sizeof(Pixel), offset(orange), XtRString, "orange" }, { XtNbright_green, XtCColor, XtRPixel, sizeof(Pixel), offset(bright_green), XtRString, "green" }, { XtNyellow, XtCColor, XtRPixel, sizeof(Pixel), offset(yellow), XtRString, "yellow" }, { XtNbright_blue, XtCColor, XtRPixel, sizeof(Pixel), offset(bright_blue), XtRString, "royal blue" }, { XtNbright_magenta, XtCColor, XtRPixel, sizeof(Pixel), offset(bright_magenta), XtRString, "violet" }, { XtNbright_cyan, XtCColor, XtRPixel, sizeof(Pixel), offset(bright_cyan), XtRString, "cyan" }, { XtNwhite, XtCColor, XtRPixel, sizeof(Pixel), offset(white), XtRString, "white" }, { XtNfont, XtCFont, XtRFontStruct, sizeof(XFontStruct *), offset(font), XtRString, XtDefaultFont }, { XtNexposeCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(expose_callback), XtRCallback, (char *)0 }, { XtNcallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(input_callback), XtRCallback, (char *)0 }, { XtNresizeCallback, XtCCallback, XtRCallback, sizeof(XtCallbackList), offset(resize_callback), XtRCallback, (char *)0 }, #undef offset }; /* ARGSUSED */ static void no_op(w, event, params, num_params) Widget w; /* unused */ XEvent *event; /* unused */ String *params; /* unused */ Cardinal *num_params; /* unused */ { } static XtActionsRec actions[] = { {"no-op", no_op}, }; static char translations[] = ": input() \ "; /* ARGSUSED */ static void Redisplay(w, event, region) Widget w; XEvent *event; Region region; /* unused */ { /* This isn't correct - we need to call the callback with region. */ XtCallCallbacks(w, XtNexposeCallback, (caddr_t) event); } /* ARGSUSED */ static void Resize(w) Widget w; { XtCallCallbacks(w, XtNresizeCallback, (caddr_t) 0); } WindowClassRec windowClassRec = { { /* core fields */ /* superclass */ (WidgetClass) &widgetClassRec, /* class_name */ "Window", /* widget_size */ sizeof(WindowRec), /* class_initialize */ 0, /* class_part_initialize */ 0, /* class_inited */ FALSE, /* initialize */ 0, /* initialize_hook */ 0, /* realize */ XtInheritRealize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ FALSE, /* destroy */ 0, /* resize */ Resize, /* expose */ Redisplay, /* set_values */ 0, /* set_values_hook */ 0, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ 0, /* accept_focus */ 0, /* version */ XtVersion, /* callback_private */ 0, /* tm_table */ translations, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ 0 }, { /* window fields */ /* empty */ 0 } }; WidgetClass windowWidgetClass = (WidgetClass)&windowClassRec; Font WindowFont(w) Widget w; { return ((WindowWidget)w)->window.font->fid; } XFontStruct * WindowFontStruct(w) Widget w; { return ((WindowWidget)w)->window.font; } nethack-3.4.3/win/X11/dialogs.c0100644000000000000000000002567407764735041014624 0ustar rootroot/* * Copyright 1991 University of Wisconsin-Madison * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of the University of Wisconsin-Madison not * be used in advertising or publicity pertaining to distribution of the * software without specific, written prior permission. The University of * Wisconsin-Madison makes no representations about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. * * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE FOR * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: Tim Theisen Department of Computer Sciences * tim@cs.wisc.edu University of Wisconsin-Madison * uwvax!tim 1210 West Dayton Street * (608)262-0438 Madison, WI 53706 * * * Modified 12/91 by Dean Luick. Tim graciously donated this piece of code * from his program ghostview, an X11 front end for ghostscript. * * + Make the cancel button optional. * + Put an #ifdef SPECIAL_CMAP around code to fix a colormap bug. * We don't need it here. * + Add the function positionpopup() from another part of ghostview * to this code. * * Modified 2/93, Various. * + Added workaround for SYSV include problem. * + Changed the default width response text widget to be as wide as the * window itself. Suggestion from David E. Wexelblat, dwex@goblin.org. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "config.h" /* #define for const for non __STDC__ compilers */ /* ":" added to both translations below to allow limited redefining of * keysyms before testing for keysym values -- dlc */ static const char okay_accelerators[] = "#override\n\ :Return: set() notify() unset()\n"; static const char cancel_accelerators[] = "#override\n\ :Escape: set() notify() unset()\n\ :[: set() notify() unset()\n"; /* for keyboards w/o an ESC */ /* Create a dialog widget. It is just a form widget with * a label prompt * a text response * an okay button * an optional cancel button */ Widget CreateDialog(parent, name, okay_callback, cancel_callback) Widget parent; String name; XtCallbackProc okay_callback; XtCallbackProc cancel_callback; { Widget form, prompt, response, okay, cancel; Arg args[20]; Cardinal num_args; num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], XtNbackground, white); num_args++; } #endif form = XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args); num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], XtNforeground, black); num_args++; XtSetArg(args[num_args], XtNbackground, white); num_args++; } #endif XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNresizable, True); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; prompt = XtCreateManagedWidget("prompt", labelWidgetClass, form, args, num_args); num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], XtNforeground, black); num_args++; XtSetArg(args[num_args], XtNbackground, white); num_args++; } #endif XtSetArg(args[num_args], XtNfromVert, prompt); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNresizable, True); num_args++; XtSetArg(args[num_args], XtNeditType, XawtextEdit); num_args++; XtSetArg(args[num_args], XtNresize, XawtextResizeWidth); num_args++; XtSetArg(args[num_args], XtNstring, ""); num_args++; response = XtCreateManagedWidget("response", asciiTextWidgetClass, form, args, num_args); num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], XtNforeground, black); num_args++; XtSetArg(args[num_args], XtNbackground, white); num_args++; } #endif XtSetArg(args[num_args], XtNfromVert, response); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNresizable, True); num_args++; XtSetArg(args[num_args], XtNaccelerators, XtParseAcceleratorTable(okay_accelerators)); num_args++; okay = XtCreateManagedWidget("okay", commandWidgetClass, form, args, num_args); XtAddCallback(okay, XtNcallback, okay_callback, form); /* Only create cancel button if there is a callback for it. */ if (cancel_callback) { num_args = 0; #ifdef SPECIAL_CMAP if (special_cmap) { XtSetArg(args[num_args], XtNforeground, black); num_args++; XtSetArg(args[num_args], XtNbackground, white); num_args++; } #endif XtSetArg(args[num_args], XtNfromVert, response); num_args++; XtSetArg(args[num_args], XtNfromHoriz, okay); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNresizable, True); num_args++; XtSetArg(args[num_args], XtNaccelerators, XtParseAcceleratorTable(cancel_accelerators)); num_args++; cancel = XtCreateManagedWidget("cancel", commandWidgetClass, form, args, num_args); XtAddCallback(cancel, XtNcallback, cancel_callback, form); XtInstallAccelerators(response, cancel); } XtInstallAccelerators(response, okay); XtSetKeyboardFocus(form, response); return form; } #if 0 /* get the prompt from the dialog box. Used a startup time to * save away the initial prompt */ String GetDialogPrompt(w) Widget w; { Arg args[1]; Widget label; String s; label = XtNameToWidget(w, "prompt"); XtSetArg(args[0], XtNlabel, &s); XtGetValues(label, args, ONE); return XtNewString(s); } #endif /* set the prompt. This is used to put error information in the prompt */ void SetDialogPrompt(w, newprompt) Widget w; String newprompt; { Arg args[1]; Widget label; label = XtNameToWidget(w, "prompt"); XtSetArg(args[0], XtNlabel, newprompt); XtSetValues(label, args, ONE); } /* get what the user typed; caller must free the response */ String GetDialogResponse(w) Widget w; { Arg args[1]; Widget response; String s; response = XtNameToWidget(w, "response"); XtSetArg(args[0], XtNstring, &s); XtGetValues(response, args, ONE); return XtNewString(s); } #define max(a,b) (((a) > (b)) ? (a) : (b)) /* set the default reponse */ void SetDialogResponse(w, s) Widget w; String s; { Arg args[4]; Widget response; XFontStruct *font; Dimension width, nwidth, leftMargin, rightMargin; response = XtNameToWidget(w, "response"); XtSetArg(args[0], XtNfont, &font); XtSetArg(args[1], XtNleftMargin, &leftMargin); XtSetArg(args[2], XtNrightMargin, &rightMargin); XtSetArg(args[3], XtNwidth, &width); XtGetValues(response, args, FOUR); /* width includes margins as per Xaw documentation */ nwidth = (font->max_bounds.width * strlen(s))+leftMargin+rightMargin; if (nwidth < width) nwidth = width; XtSetArg(args[0], XtNstring, s); XtSetArg(args[1], XtNwidth, nwidth); XtSetValues(response, args, TWO); XawTextSetInsertionPoint(response, strlen(s)); } #if 0 /* clear the response */ void ClearDialogResponse(w) Widget w; { Arg args[2]; Widget response; response = XtNameToWidget(w, "response"); XtSetArg(args[0], XtNstring, ""); XtSetArg(args[1], XtNwidth, 100); XtSetValues(response, args, TWO); } #endif /* Not a part of the original dialogs.c from ghostview --------------------- */ /* position popup window under the cursor */ void positionpopup(w, bottom) Widget w; boolean bottom; /* position y on bottom? */ { Arg args[3]; Cardinal num_args; Dimension width, height, b_width; int x, y, max_x, max_y; Window root, child; XSizeHints *hints; int dummyx, dummyy; unsigned int dummymask; extern Widget toplevel; /* following line deals with a race condition w/brain-damaged WM's -dlc */ XtUnrealizeWidget(w); XQueryPointer(XtDisplay(toplevel), XtWindow(toplevel), &root, &child, &x, &y, &dummyx, &dummyy, &dummymask); num_args = 0; XtSetArg(args[num_args], XtNwidth, &width); num_args++; XtSetArg(args[num_args], XtNheight, &height); num_args++; XtSetArg(args[num_args], XtNborderWidth, &b_width); num_args++; XtGetValues(w, args, num_args); /* position so that the cursor is center,center or center,bottom */ width += 2 * b_width; x -= ( (Position) width/2 ); if (x < 0) x = 0; if ( x > (max_x = (Position) (XtScreen(w)->width - width)) ) x = max_x; if (bottom) { y -= (height+b_width-1); height += 2 * b_width; } else { height += 2 * b_width; y -= ( (Position) height/2 ); } if (y < 0) y = 0; if ( y > (max_y = (Position) (XtScreen(w)->height - height)) ) y = max_y; num_args = 0; XtSetArg(args[num_args], XtNx, x); num_args++; XtSetArg(args[num_args], XtNy, y); num_args++; XtSetValues(w, args, num_args); /* Some older window managers ignore XtN{x,y}; hint the same values */ /* The {x,y} are not used by newer window managers; older ones need them */ XtRealizeWidget(w); hints = XAllocSizeHints(); hints->flags = USPosition; hints->x = x; hints->y = y; XSetWMNormalHints(XtDisplay(w), XtWindow(w), hints); XFree(hints); } nethack-3.4.3/win/X11/ibm.bdf0100644000000000000000000011420607764735041014250 0ustar rootrootSTARTFONT 2.1 COMMENT (null) FONT -Misc-Fixed-Medium-R-Normal-IBMPC-14-120-75-75-C-80-ISO8859-1 SIZE 13 78 78 FONTBOUNDINGBOX 8 14 0 -3 STARTPROPERTIES 19 FONTNAME_REGISTRY "" FOUNDRY "Misc" FAMILY_NAME "Fixed" WEIGHT_NAME "Medium" SLANT "R" SETWIDTH_NAME "Normal" ADD_STYLE_NAME "IBMPC" PIXEL_SIZE 14 POINT_SIZE 120 RESOLUTION_X 75 RESOLUTION_Y 75 SPACING "C" AVERAGE_WIDTH 80 CHARSET_REGISTRY "ISO8859" CHARSET_ENCODING "1" DEFAULT_CHAR 0 FONT_DESCENT 3 FONT_ASCENT 11 COPYRIGHT "Public domain font. Share and enjoy." ENDPROPERTIES CHARS 256 STARTCHAR C000 ENCODING 0 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C001 ENCODING 1 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7e00 8100 a500 8100 8100 bd00 9900 8100 7e00 0000 0000 0000 ENDCHAR STARTCHAR C002 ENCODING 2 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7e00 ff00 db00 ff00 ff00 c300 e700 ff00 7e00 0000 0000 0000 ENDCHAR STARTCHAR C003 ENCODING 3 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 6c00 ee00 fe00 fe00 fe00 7c00 3800 1000 0000 0000 0000 ENDCHAR STARTCHAR C004 ENCODING 4 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1000 3800 7c00 fe00 7c00 3800 1000 0000 0000 0000 0000 ENDCHAR STARTCHAR C005 ENCODING 5 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1000 3800 1000 6c00 ee00 6c00 1000 3800 0000 0000 0000 ENDCHAR STARTCHAR C006 ENCODING 6 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1000 3800 7c00 7c00 fe00 fe00 6c00 1000 3800 0000 0000 0000 ENDCHAR STARTCHAR C007 ENCODING 7 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 1800 3c00 3c00 1800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C010 ENCODING 8 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP ff00 ff00 ff00 ff00 ff00 e700 c300 c300 e700 ff00 ff00 ff00 ff00 ff00 ENDCHAR STARTCHAR C011 ENCODING 9 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 1800 3c00 6600 6600 3c00 1800 0000 0000 0000 0000 ENDCHAR STARTCHAR C012 ENCODING 10 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP ff00 ff00 ff00 ff00 e700 c300 9900 9900 c300 e700 ff00 ff00 ff00 ff00 ENDCHAR STARTCHAR C013 ENCODING 11 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1e00 0e00 1e00 3600 7800 cc00 cc00 cc00 7800 0000 0000 0000 ENDCHAR STARTCHAR C014 ENCODING 12 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 6600 6600 6600 3c00 1800 7e00 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR C015 ENCODING 13 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1e00 1a00 1e00 1800 1800 1800 7800 f800 7000 0000 0000 0000 ENDCHAR STARTCHAR C016 ENCODING 14 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3e00 3600 3e00 3600 3600 7600 f600 6600 0e00 1e00 0c00 0000 0000 ENDCHAR STARTCHAR C017 ENCODING 15 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1800 db00 7e00 3c00 6600 6600 3c00 7e00 db00 1800 0000 0000 0000 ENDCHAR STARTCHAR C020 ENCODING 16 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 8000 e000 f000 fc00 fe00 fc00 f000 e000 8000 0000 0000 0000 ENDCHAR STARTCHAR C021 ENCODING 17 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0200 0e00 3e00 7e00 fe00 7e00 3e00 0e00 0200 0000 0000 0000 ENDCHAR STARTCHAR C022 ENCODING 18 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 3c00 7e00 1800 1800 1800 7e00 3c00 1800 0000 0000 0000 ENDCHAR STARTCHAR C023 ENCODING 19 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6600 6600 6600 6600 6600 6600 0000 6600 6600 0000 0000 0000 ENDCHAR STARTCHAR C024 ENCODING 20 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7f00 db00 db00 db00 7b00 1b00 1b00 1b00 1b00 0000 0000 0000 ENDCHAR STARTCHAR C025 ENCODING 21 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 7c00 c600 c600 6000 7c00 f600 de00 7c00 0c00 c600 c600 7c00 0000 ENDCHAR STARTCHAR C026 ENCODING 22 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 fe00 fe00 fe00 0000 0000 0000 ENDCHAR STARTCHAR C027 ENCODING 23 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 3c00 7e00 1800 1800 7e00 3c00 1800 7e00 0000 0000 0000 ENDCHAR STARTCHAR C030 ENCODING 24 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 3c00 7e00 1800 1800 1800 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR C031 ENCODING 25 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 1800 1800 1800 1800 1800 7e00 3c00 1800 0000 0000 0000 ENDCHAR STARTCHAR C032 ENCODING 26 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0c00 0e00 ff00 0e00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C033 ENCODING 27 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 3000 7000 fe00 7000 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C034 ENCODING 28 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c000 c000 c000 fe00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C035 ENCODING 29 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 2400 6600 ff00 6600 2400 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C036 ENCODING 30 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1000 3800 3800 3800 7c00 7c00 fe00 fe00 0000 0000 0000 0000 ENDCHAR STARTCHAR C037 ENCODING 31 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 fe00 7c00 7c00 7c00 3800 3800 1000 0000 0000 0000 0000 ENDCHAR STARTCHAR C040 ENCODING 32 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ! ENCODING 33 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 3c00 3c00 3c00 1800 1800 0000 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR " ENCODING 34 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3600 3600 3600 1400 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR # ENCODING 35 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6c00 6c00 6c00 fe00 6c00 6c00 fe00 6c00 6c00 0000 0000 0000 ENDCHAR STARTCHAR $ ENCODING 36 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1800 1800 7c00 c600 c000 7800 3c00 0600 c600 7c00 1800 1800 0000 ENDCHAR STARTCHAR % ENCODING 37 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 6200 6600 0c00 1800 3000 6600 c600 0000 0000 0000 ENDCHAR STARTCHAR & ENCODING 38 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 6c00 3800 3800 7600 f600 ce00 cc00 7600 0000 0000 0000 ENDCHAR STARTCHAR ' ENCODING 39 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0c00 0c00 0c00 1800 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ( ENCODING 40 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 3000 3000 3000 3000 1800 0c00 0000 0000 0000 ENDCHAR STARTCHAR ) ENCODING 41 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3000 1800 0c00 0c00 0c00 0c00 0c00 1800 3000 0000 0000 0000 ENDCHAR STARTCHAR * ENCODING 42 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 6c00 3800 fe00 3800 6c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR + ENCODING 43 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 1800 1800 7e00 1800 1800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR , ENCODING 44 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0c00 0c00 0c00 1800 0000 0000 ENDCHAR STARTCHAR - ENCODING 45 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 fe00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR . ENCODING 46 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR / ENCODING 47 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0200 0600 0c00 1800 3000 6000 c000 8000 0000 0000 0000 ENDCHAR STARTCHAR 0 ENCODING 48 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 ce00 de00 f600 e600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 1 ENCODING 49 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 7800 1800 1800 1800 1800 1800 1800 7e00 0000 0000 0000 ENDCHAR STARTCHAR 2 ENCODING 50 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 0c00 1800 3000 6000 c600 fe00 0000 0000 0000 ENDCHAR STARTCHAR 3 ENCODING 51 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 0600 0600 3c00 0600 0600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 4 ENCODING 52 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1c00 3c00 6c00 cc00 fe00 0c00 0c00 0c00 0000 0000 0000 ENDCHAR STARTCHAR 5 ENCODING 53 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 c000 c000 c000 fc00 0600 0600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 6 ENCODING 54 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c000 c000 fc00 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 7 ENCODING 55 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 c600 0c00 1800 3000 3000 3000 3000 3000 0000 0000 0000 ENDCHAR STARTCHAR 8 ENCODING 56 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 7c00 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR 9 ENCODING 57 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 7e00 0600 0600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR : ENCODING 58 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0c00 0c00 0000 0000 0c00 0c00 0000 0000 0000 0000 ENDCHAR STARTCHAR ; ENCODING 59 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0c00 0c00 0000 0000 0c00 0c00 0c00 1800 0000 0000 ENDCHAR STARTCHAR < ENCODING 60 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 6000 c000 6000 3000 1800 0c00 0000 0000 0000 ENDCHAR STARTCHAR = ENCODING 61 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 0000 fe00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR > ENCODING 62 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6000 3000 1800 0c00 0600 0c00 1800 3000 6000 0000 0000 0000 ENDCHAR STARTCHAR ? ENCODING 63 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 0c00 1800 1800 0000 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR @ ENCODING 64 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 de00 de00 de00 dc00 c000 7e00 0000 0000 0000 ENDCHAR STARTCHAR A ENCODING 65 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 6c00 c600 c600 c600 fe00 c600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR B ENCODING 66 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fc00 6600 6600 6600 7c00 6600 6600 6600 fc00 0000 0000 0000 ENDCHAR STARTCHAR C ENCODING 67 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 6600 c000 c000 c000 c000 c000 6600 3c00 0000 0000 0000 ENDCHAR STARTCHAR D ENCODING 68 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 f800 6c00 6600 6600 6600 6600 6600 6c00 f800 0000 0000 0000 ENDCHAR STARTCHAR E ENCODING 69 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 6600 6000 6000 7c00 6000 6000 6600 fe00 0000 0000 0000 ENDCHAR STARTCHAR F ENCODING 70 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 6600 6000 6000 7c00 6000 6000 6000 f000 0000 0000 0000 ENDCHAR STARTCHAR G ENCODING 71 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c000 c000 ce00 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR H ENCODING 72 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 c600 c600 fe00 c600 c600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR I ENCODING 73 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 1800 1800 1800 1800 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR J ENCODING 74 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 1800 1800 1800 1800 1800 d800 d800 7000 0000 0000 0000 ENDCHAR STARTCHAR K ENCODING 75 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 cc00 d800 f000 f000 d800 cc00 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR L ENCODING 76 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 f000 6000 6000 6000 6000 6000 6200 6600 fe00 0000 0000 0000 ENDCHAR STARTCHAR M ENCODING 77 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 ee00 fe00 d600 d600 d600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR N ENCODING 78 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 e600 e600 f600 de00 ce00 ce00 c600 0000 0000 0000 ENDCHAR STARTCHAR O ENCODING 79 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 c600 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR P ENCODING 80 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fc00 6600 6600 6600 7c00 6000 6000 6000 f000 0000 0000 0000 ENDCHAR STARTCHAR Q ENCODING 81 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 c600 c600 c600 d600 7c00 0600 0000 0000 ENDCHAR STARTCHAR R ENCODING 82 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fc00 6600 6600 6600 7c00 7800 6c00 6600 e600 0000 0000 0000 ENDCHAR STARTCHAR S ENCODING 83 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c000 6000 3800 0c00 0600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR T ENCODING 84 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7e00 5a00 1800 1800 1800 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR U ENCODING 85 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 c600 c600 c600 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR V ENCODING 86 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 c600 c600 c600 c600 6c00 3800 1000 0000 0000 0000 ENDCHAR STARTCHAR W ENCODING 87 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 d600 d600 d600 fe00 ee00 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR X ENCODING 88 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 6c00 3800 3800 3800 6c00 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR Y ENCODING 89 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6600 6600 6600 6600 3c00 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR Z ENCODING 90 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 c600 8c00 1800 3000 6000 c200 c600 fe00 0000 0000 0000 ENDCHAR STARTCHAR [ ENCODING 91 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 6000 6000 6000 6000 6000 6000 6000 7c00 0000 0000 0000 ENDCHAR STARTCHAR \ ENCODING 92 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 8000 c000 6000 3000 1800 0c00 0600 0200 0000 0000 0000 ENDCHAR STARTCHAR ] ENCODING 93 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 7c00 0000 0000 0000 ENDCHAR STARTCHAR ^ ENCODING 94 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1000 3800 6c00 c600 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR _ ENCODING 95 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ff00 0000 ENDCHAR STARTCHAR ` ENCODING 96 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1800 1800 1800 0c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR a ENCODING 97 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7800 0c00 7c00 cc00 dc00 7600 0000 0000 0000 ENDCHAR STARTCHAR b ENCODING 98 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 e000 6000 6000 7c00 6600 6600 6600 6600 fc00 0000 0000 0000 ENDCHAR STARTCHAR c ENCODING 99 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 c600 c000 c000 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR d ENCODING 100 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1c00 0c00 0c00 7c00 cc00 cc00 cc00 cc00 7e00 0000 0000 0000 ENDCHAR STARTCHAR e ENCODING 101 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 c600 fe00 c000 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR f ENCODING 102 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1c00 3600 3000 3000 fc00 3000 3000 3000 7800 0000 0000 0000 ENDCHAR STARTCHAR g ENCODING 103 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7600 ce00 c600 c600 7e00 0600 c600 7c00 0000 ENDCHAR STARTCHAR h ENCODING 104 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 e000 6000 6000 6c00 7600 6600 6600 6600 e600 0000 0000 0000 ENDCHAR STARTCHAR i ENCODING 105 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 1800 0000 3800 1800 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR j ENCODING 106 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 0c00 0000 1c00 0c00 0c00 0c00 0c00 cc00 cc00 7800 0000 ENDCHAR STARTCHAR k ENCODING 107 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 e000 6000 6000 6600 6c00 7800 6c00 6600 e600 0000 0000 0000 ENDCHAR STARTCHAR l ENCODING 108 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 1800 1800 1800 1800 1800 1800 1800 3c00 0000 0000 0000 ENDCHAR STARTCHAR m ENCODING 109 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 6c00 fe00 d600 d600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR n ENCODING 110 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 dc00 6600 6600 6600 6600 6600 0000 0000 0000 ENDCHAR STARTCHAR o ENCODING 111 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 c600 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR p ENCODING 112 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 dc00 6600 6600 6600 7c00 6000 6000 f000 0000 ENDCHAR STARTCHAR q ENCODING 113 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7600 cc00 cc00 cc00 7c00 0c00 0c00 1e00 0000 ENDCHAR STARTCHAR r ENCODING 114 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 dc00 6600 6000 6000 6000 f000 0000 0000 0000 ENDCHAR STARTCHAR s ENCODING 115 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 c600 7000 1c00 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR t ENCODING 116 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3000 3000 3000 fc00 3000 3000 3000 3600 1c00 0000 0000 0000 ENDCHAR STARTCHAR u ENCODING 117 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 cc00 cc00 cc00 cc00 cc00 7600 0000 0000 0000 ENDCHAR STARTCHAR v ENCODING 118 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c600 c600 c600 6c00 3800 1000 0000 0000 0000 ENDCHAR STARTCHAR w ENCODING 119 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c600 c600 d600 d600 fe00 6c00 0000 0000 0000 ENDCHAR STARTCHAR x ENCODING 120 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c600 6c00 3800 3800 6c00 c600 0000 0000 0000 ENDCHAR STARTCHAR y ENCODING 121 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 c600 c600 c600 ce00 7600 0600 c600 7c00 0000 ENDCHAR STARTCHAR z ENCODING 122 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 8c00 1800 3000 6200 fe00 0000 0000 0000 ENDCHAR STARTCHAR { ENCODING 123 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0e00 1800 1800 1800 7000 1800 1800 1800 0e00 0000 0000 0000 ENDCHAR STARTCHAR | ENCODING 124 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1800 1800 1800 1800 0000 1800 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR } ENCODING 125 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7000 1800 1800 1800 0e00 1800 1800 1800 7000 0000 0000 0000 ENDCHAR STARTCHAR ~ ENCODING 126 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7600 dc00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C177 ENCODING 127 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 1000 3800 3800 6c00 6c00 fe00 0000 0000 0000 0000 ENDCHAR STARTCHAR vwall ENCODING 128 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR hwall ENCODING 129 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 ff00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR tlcorn ENCODING 130 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 1f00 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR trcorn ENCODING 131 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 f800 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR blcorn ENCODING 132 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 1f00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR brcorn ENCODING 133 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 f800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR crwall ENCODING 134 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 ff00 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR tuwall ENCODING 135 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 ff00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR tdwall ENCODING 136 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 ff00 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR tlwall ENCODING 137 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 18 18 18 18 18 18 18 f8 18 18 18 18 18 18 ENDCHAR STARTCHAR trwall ENCODING 138 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 18 18 18 18 18 18 18 1f 18 18 18 18 18 18 ENDCHAR STARTCHAR ndoor ENCODING 139 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 1800 1800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR vodoor ENCODING 140 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 0000 0000 0000 7e00 0000 0000 0000 1800 1800 1800 ENDCHAR STARTCHAR hodoor ENCODING 141 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1800 1800 1800 1800 9900 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR vcdoor ENCODING 142 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1800 1800 1800 7e00 7e00 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR hcdoor ENCODING 143 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1800 1800 1800 7e00 7e00 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR room ENCODING 144 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 1800 1800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR dark corr ENCODING 145 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1100 4400 1100 4400 1100 4400 1100 4400 1100 4400 1100 4400 1100 4400 ENDCHAR STARTCHAR lit corr ENCODING 146 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 5500 aa00 5500 aa00 5500 aa00 5500 aa00 5500 aa00 5500 aa00 5500 aa00 ENDCHAR STARTCHAR upstair ENCODING 147 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 6000 c000 6000 3000 1800 0c00 0000 0000 0000 ENDCHAR STARTCHAR dnstair ENCODING 148 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6000 3000 1800 0c00 0600 0c00 1800 3000 6000 0000 0000 0000 ENDCHAR STARTCHAR trap ENCODING 149 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1000 3800 6c00 c600 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR web ENCODING 150 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0100 0f00 3c00 c600 c200 6f00 3a00 3200 7300 5700 8c00 db00 7f00 2500 ENDCHAR STARTCHAR pool ENCODING 151 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 7700 0000 ee00 bb00 0000 7700 dd00 0000 bb00 ee00 0000 dd00 7700 0000 ENDCHAR STARTCHAR fountain ENCODING 152 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1400 0000 3400 4a00 4900 8a00 2800 0200 5900 1800 3c00 3c00 ff00 ff00 ENDCHAR STARTCHAR sink ENCODING 153 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 2400 2400 7e00 2400 2400 7e00 2400 2400 0000 0000 0000 ENDCHAR STARTCHAR throne ENCODING 154 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0400 0400 0400 0400 3c00 1400 3c00 2400 2400 ff00 ff00 ENDCHAR STARTCHAR upladder ENCODING 155 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 6000 c000 6000 3000 1800 0c00 0000 0000 0000 ENDCHAR STARTCHAR dnladder ENCODING 156 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 6000 3000 1800 0c00 0600 0c00 1800 3000 6000 0000 0000 0000 ENDCHAR STARTCHAR dbvwall ENCODING 157 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 3c00 7e00 7e00 3c00 3c00 3c00 3c00 3c00 3c00 7e00 7e00 3c00 1800 ENDCHAR STARTCHAR dbhwall ENCODING 158 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 2400 7e00 ff00 7e00 2400 0000 0000 0000 0000 ENDCHAR STARTCHAR ice ENCODING 159 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 2400 1800 1800 2400 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR lava ENCODING 160 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0200 4000 2000 2000 0400 1000 9500 5500 5500 5e00 ff00 ff00 ENDCHAR STARTCHAR vbeam ENCODING 161 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1000 1c00 0800 1000 2000 4000 3000 1800 0400 0800 1000 2000 7000 1000 ENDCHAR STARTCHAR hbeam ENCODING 162 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 4000 6000 d100 0a00 0400 0000 0000 0000 0000 ENDCHAR STARTCHAR lslant ENCODING 163 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 8000 6000 2000 2000 2000 1000 1000 0800 0c00 0200 0200 0200 0200 0100 ENDCHAR STARTCHAR rslant ENCODING 164 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0100 0100 0200 0200 0400 0400 0400 1800 2000 2000 4000 4000 4000 8000 ENDCHAR STARTCHAR dig beam ENCODING 165 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 5500 0a00 1400 2800 5000 a000 4100 8200 0500 0a00 1400 2800 5000 aa00 ENDCHAR STARTCHAR camera flash ENCODING 166 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c800 4b00 0200 2000 0400 d800 1b00 2000 4400 5200 0a00 0000 ENDCHAR STARTCHAR boom open left ENCODING 167 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 2000 1000 0800 0400 0200 0400 0800 1000 2000 0000 0000 0000 ENDCHAR STARTCHAR boom open right ENCODING 168 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0200 0400 0800 1000 2000 1000 0800 0400 0200 0000 0000 0000 ENDCHAR STARTCHAR magic shield 1 ENCODING 169 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 5000 1200 4200 0800 1000 3a00 1000 4400 5000 2c00 0400 2800 ENDCHAR STARTCHAR magic shield 2 ENCODING 170 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 3600 a800 5a00 da00 8400 f400 d500 3a00 d700 a500 fd00 6f00 3800 3600 ENDCHAR STARTCHAR magic sheild 3 ENCODING 171 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 1c00 4300 0000 0800 2200 0000 4000 0800 0200 9a00 cc00 2200 0000 ENDCHAR STARTCHAR magic shield 4 ENCODING 172 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 6000 1000 6c00 5200 4000 1b00 4600 6b00 cd00 a200 a800 5600 3400 0000 ENDCHAR STARTCHAR sw top left ENCODING 173 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0300 0400 0400 0800 0800 1000 1000 ENDCHAR STARTCHAR sw top center ENCODING 174 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 3c00 c300 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR sw top right ENCODING 175 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 c000 2000 2000 1000 1000 0800 0800 ENDCHAR STARTCHAR sw middle left ENCODING 176 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1000 1000 2000 2000 2000 2000 2000 4000 2000 2000 2000 2000 1000 1000 ENDCHAR STARTCHAR sw middle right ENCODING 177 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0800 0800 0400 0400 0400 0400 0400 0200 0400 0400 0400 0400 0800 0800 ENDCHAR STARTCHAR sw bottom left ENCODING 178 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1000 1000 0800 0800 0400 0400 0300 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR sw bottom center ENCODING 179 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 c300 3c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR sw bottom right ENCODING 180 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0800 0800 1000 1000 2000 2000 c000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR explosion1 ENCODING 181 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0100 0e00 3100 ce00 3100 4600 9800 6700 9800 2300 4c00 9300 2400 ENDCHAR STARTCHAR explosion2 ENCODING 182 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 ff00 0000 ff00 0000 ff00 0000 fe00 0100 fe00 0100 fe00 0100 7c00 ENDCHAR STARTCHAR explosion3 ENCODING 183 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 e000 1800 e600 1900 c400 3300 cd00 3200 8900 6400 9200 4900 ENDCHAR STARTCHAR explosion4 ENCODING 184 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 4900 5600 a500 aa00 4a00 5500 5500 5500 5500 5500 4a00 aa00 a500 5600 ENDCHAR STARTCHAR explosion5 ENCODING 185 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 8300 7c00 8300 7c00 8200 3900 4500 5500 4500 3900 8200 7c00 8300 7c00 ENDCHAR STARTCHAR explosion6 ENCODING 186 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 2500 d400 4a00 aa00 a500 5500 5500 5500 5500 5500 a500 aa00 4a00 d400 ENDCHAR STARTCHAR explosion7 ENCODING 187 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 4900 2400 9300 4c00 2300 9800 6700 b800 4e00 3100 ce00 3100 0e00 0100 ENDCHAR STARTCHAR explosion8 ENCODING 188 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 8300 7c00 0100 fe00 0100 fe00 0100 fe00 0000 ff00 0000 ff00 0000 ff00 ENDCHAR STARTCHAR explosion9 ENCODING 189 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 2500 4900 9200 6400 8900 3200 cc00 3b00 e400 1900 e600 1800 e000 0000 ENDCHAR STARTCHAR C276 ENCODING 190 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 f800 1800 f800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C203 ENCODING 191 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3000 7800 cc00 0000 7800 0c00 7c00 cc00 dc00 7600 0000 0000 0000 ENDCHAR STARTCHAR C204 ENCODING 192 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 cc00 cc00 0000 7800 0c00 7c00 cc00 dc00 7600 0000 0000 0000 ENDCHAR STARTCHAR C207 ENCODING 193 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 7c00 c600 c000 c000 c600 7c00 1800 6c00 3800 0000 ENDCHAR STARTCHAR C210 ENCODING 194 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3000 7800 cc00 0000 7c00 c600 fe00 c000 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR C303 ENCODING 195 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 1f00 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR C201 ENCODING 196 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 c600 c600 0000 c600 c600 c600 c600 ce00 7600 0000 0000 0000 ENDCHAR STARTCHAR C206 ENCODING 197 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3800 6c00 3800 0000 7800 0c00 7c00 cc00 dc00 7600 0000 0000 0000 ENDCHAR STARTCHAR C200 ENCODING 198 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 6600 c000 c000 c000 c600 6600 3c00 1800 cc00 3800 0000 ENDCHAR STARTCHAR C264 ENCODING 199 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 f800 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR C333 ENCODING 200 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ENDCHAR STARTCHAR C334 ENCODING 201 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 ff00 ff00 ff00 ff00 ff00 ff00 ff00 ENDCHAR STARTCHAR C335 ENCODING 202 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 f000 ENDCHAR STARTCHAR C336 ENCODING 203 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 0f00 ENDCHAR STARTCHAR C337 ENCODING 204 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP ff00 ff00 ff00 ff00 ff00 ff00 ff00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C272 ENCODING 205 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 3600 ENDCHAR STARTCHAR C273 ENCODING 206 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 0600 f600 3600 3600 3600 3600 3600 3600 ENDCHAR STARTCHAR C236 ENCODING 207 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 fc00 c600 fc00 c000 cc00 de00 cc00 cc00 cc00 c600 0000 0000 0000 ENDCHAR STARTCHAR amulet ENCODING 208 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3c00 4200 4200 4200 2200 2200 1c00 3e00 3e00 3e00 1c00 0000 0000 ENDCHAR STARTCHAR food ENCODING 209 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 7c00 7c00 3800 1000 1000 1000 7c00 0000 ENDCHAR STARTCHAR weapon ENCODING 210 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 2000 3000 2800 2800 2800 2800 2800 2800 3800 fe00 3000 3000 3000 3000 ENDCHAR STARTCHAR tool ENCODING 211 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 3c00 4200 4200 7e00 7e00 7e00 7e00 0000 0000 ENDCHAR STARTCHAR ball ENCODING 212 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1c00 3e00 3e00 7e00 ad00 7600 ENDCHAR STARTCHAR chain ENCODING 213 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 6600 9900 6600 ENDCHAR STARTCHAR rock ENCODING 214 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3c00 6600 5200 8500 d200 a900 a000 4500 9300 bf00 6a00 fe00 7f00 ENDCHAR STARTCHAR armor ENCODING 215 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7c00 6c00 5400 6c00 5400 2800 1000 0000 0000 ENDCHAR STARTCHAR potion ENCODING 216 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3c00 1800 1800 1800 1800 3c00 6e00 7a00 5e00 7600 3c00 0000 ENDCHAR STARTCHAR scroll ENCODING 217 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7e00 ff00 7e00 2a00 5400 2a00 5400 2a00 7e00 ff00 7e00 0000 ENDCHAR STARTCHAR wand ENCODING 218 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 2200 2400 1500 0200 0800 0800 1000 1000 1000 2000 2000 2000 4000 0000 ENDCHAR STARTCHAR ring ENCODING 219 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 4200 2400 8300 3800 4500 4400 4400 3900 8200 2900 4800 0000 0000 ENDCHAR STARTCHAR gem ENCODING 220 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 7c00 c600 4400 3800 1000 0000 ENDCHAR STARTCHAR gold ENCODING 221 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 5400 5400 a500 a900 8a00 0000 6000 be00 fb00 df00 3800 ENDCHAR STARTCHAR venom ENCODING 222 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 1800 2400 4400 5800 2000 0000 0000 0000 ENDCHAR STARTCHAR spbook ENCODING 223 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 7c00 4600 6600 4600 4600 4600 6600 4600 7e00 7e00 0000 ENDCHAR STARTCHAR C262 ENCODING 224 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP dd00 7700 dd00 7700 dd00 7700 dd00 7700 dd00 7700 dd00 7700 dd00 7700 ENDCHAR STARTCHAR C341 ENCODING 225 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 7800 cc00 d800 fc00 c600 e600 dc00 c000 c000 0000 ENDCHAR STARTCHAR C342 ENCODING 226 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 6600 6200 6000 6000 6000 6000 6000 6000 0000 0000 0000 ENDCHAR STARTCHAR C343 ENCODING 227 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 6c00 6c00 6c00 6c00 6c00 0000 0000 0000 ENDCHAR STARTCHAR C344 ENCODING 228 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 c600 6200 3000 1800 3000 6200 c600 fe00 0000 0000 0000 ENDCHAR STARTCHAR C345 ENCODING 229 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7e00 d800 cc00 cc00 cc00 7800 0000 0000 0000 ENDCHAR STARTCHAR C346 ENCODING 230 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 6600 6600 6600 6600 7c00 6000 c000 8000 0000 0000 ENDCHAR STARTCHAR C347 ENCODING 231 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7600 dc00 1800 1800 1800 1800 0000 0000 0000 ENDCHAR STARTCHAR C350 ENCODING 232 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 fe00 3800 6c00 c600 c600 c600 6c00 3800 fe00 0000 0000 0000 ENDCHAR STARTCHAR C351 ENCODING 233 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 6c00 c600 c600 fe00 c600 c600 6c00 3800 0000 0000 0000 ENDCHAR STARTCHAR C352 ENCODING 234 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3800 6c00 c600 c600 c600 6c00 6c00 6c00 ee00 0000 0000 0000 ENDCHAR STARTCHAR C353 ENCODING 235 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3e00 6000 3000 3c00 6600 c600 c600 cc00 7800 0000 0000 0000 ENDCHAR STARTCHAR C354 ENCODING 236 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 7e00 db00 db00 7e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C355 ENCODING 237 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0600 0c00 7c00 de00 f600 e600 7c00 6000 c000 0000 0000 0000 ENDCHAR STARTCHAR C356 ENCODING 238 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 1c00 3000 6000 6000 7c00 6000 6000 3000 1c00 0000 0000 0000 ENDCHAR STARTCHAR C357 ENCODING 239 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7c00 c600 c600 c600 c600 c600 c600 c600 c600 0000 0000 0000 ENDCHAR STARTCHAR C360 ENCODING 240 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 fe00 0000 fe00 0000 fe00 0000 0000 0000 0000 ENDCHAR STARTCHAR C361 ENCODING 241 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 1800 1800 7e00 1800 1800 0000 7e00 0000 0000 0000 ENDCHAR STARTCHAR C362 ENCODING 242 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 3000 1800 0c00 0600 0c00 1800 3000 0000 7e00 0000 0000 0000 ENDCHAR STARTCHAR C363 ENCODING 243 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0c00 1800 3000 6000 3000 1800 0c00 0000 7e00 0000 0000 0000 ENDCHAR STARTCHAR C364 ENCODING 244 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0c00 1e00 1a00 1800 1800 1800 1800 1800 1800 1800 1800 ENDCHAR STARTCHAR C365 ENCODING 245 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 1800 1800 1800 1800 1800 1800 1800 1800 1800 5800 7800 3000 0000 0000 ENDCHAR STARTCHAR C366 ENCODING 246 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1800 1800 0000 7e00 0000 1800 1800 0000 0000 0000 0000 ENDCHAR STARTCHAR C225 ENCODING 247 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 3000 1800 0c00 0000 7c00 c600 c600 c600 c600 7c00 0000 0000 0000 ENDCHAR STARTCHAR C370 ENCODING 248 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 7800 cc00 cc00 7800 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C371 ENCODING 249 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 1800 1800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C372 ENCODING 250 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 1800 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C373 ENCODING 251 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 1f00 1800 1800 1800 1800 d800 7800 3800 1800 0000 0000 ENDCHAR STARTCHAR C374 ENCODING 252 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 d800 6c00 6c00 6c00 6c00 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C375 ENCODING 253 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 7000 d800 3000 6000 f800 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C376 ENCODING 254 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 7e00 7e00 7e00 7e00 7e00 7e00 0000 0000 0000 0000 ENDCHAR STARTCHAR C377 ENCODING 255 SWIDTH 666 0 DWIDTH 8 0 BBX 8 14 0 -3 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR ENDFONT nethack-3.4.3/win/X11/nethack.rc0100644000000000000000000000455207764735041014771 0ustar rootroot# # Nethack configuration file. # # Naming this file $(HOME)/.nethackrc (for UNIX) or setting the environment # variable NETHACKOPTIONS to point to its full path name elsewhere tells # NetHack to use X11 windowing and fonts (provided the executable was # compiled with that ability). # # OPTIONS=windowtype:x11,toptenwin,hilite_pet OPTIONS=confirm,male,fixinv,noautopickup,safe_pet,sortpack,tombstone OPTIONS=verbose,news,fruit:pineapple OPTIONS=dogname:Dhairrhuwyth OPTIONS=catname:Ghisteslwchlohm # # There are 17 object symbols and various graphics symbols. # The descriptions of these symbols can be found in dat/opthelp. # # # Font: nh10 (10x20) # OBJECTS= 180 183 188 192 181 184 182 189 190 196 \ 191 194 193 187 185 186 195 # DUNGEON= 032 025 018 013 012 014 011 015 023 024 \ 022 021 128 129 130 131 132 035 035 133 \ 134 135 136 137 145 146 144 124 143 142 \ 141 140 149 150 031 031 147 148 031 161 \ 140 # TRAPS= 138 138 138 138 138 138 138 138 138 138 \ 138 138 138 138 138 139 138 138 138 138 \ 138 138 # EFFECTS= 151 152 153 154 155 156 157 158 \ 159 160 161 162 \ 163 164 165 166 167 168 169 170 \ 171 172 173 174 175 176 177 178 179 # # # Font: ibm (8x14) # #OBJECTS= 207 210 215 219 208 211 209 216 217 223 \ # 218 221 220 214 212 213 222 # #DUNGEON= 032 128 129 130 131 132 133 134 135 136 \ # 137 138 139 045 124 142 143 035 035 144 \ # 145 146 147 148 155 156 227 124 154 153 \ # 152 151 159 160 200 200 157 158 250 170 \ # 151 # #TRAPS= 149 149 149 149 149 149 149 149 149 149 \ # 149 149 149 149 149 150 149 149 149 149 \ # 149 149 # #EFFECTS= 161 162 163 164 165 166 167 168 \ # 169 170 171 172 \ # 173 174 175 176 177 178 179 180 \ # 181 182 183 184 185 186 187 188 189 # # # Font: a "standard" font like 6x13 # Note that this version is unlikely to work on a tty on a Unix system because # many of these characters are also control characters. # #DUNGEON = 032 025 018 013 012 014 011 015 023 024 \ # 022 021 031 045 124 043 043 035 035 031 \ # 035 001 060 062 060 062 019 124 092 035 \ # 123 125 031 125 046 046 035 035 046 127 \ # 125 # #TRAPS= 094 094 094 094 094 094 094 094 094 094 \ # 094 094 094 094 094 002 094 094 094 094 \ # 094 094 # #EFFECTS= 124 045 092 047 042 033 041 040 \ # 048 035 064 042 \ # 047 045 092 124 124 092 045 047 \ # 047 064 092 064 064 064 092 064 047 nethack-3.4.3/win/X11/nh10.bdf0100644000000000000000000013461107764735041014251 0ustar rootrootSTARTFONT 2.1 COMMENT Nethack 10x20 font. Based on the font 10x20. FONT nh10 SIZE 20 75 75 FONTBOUNDINGBOX 10 20 0 -5 STARTPROPERTIES 19 FONTNAME_REGISTRY "" FOUNDRY "Misc" FAMILY_NAME "Fixed" WEIGHT_NAME "Medium" SLANT "R" SETWIDTH_NAME "Normal" ADD_STYLE_NAME "NetHack" PIXEL_SIZE 20 POINT_SIZE 200 RESOLUTION_X 75 RESOLUTION_Y 75 SPACING "C" AVERAGE_WIDTH 100 CHARSET_REGISTRY "ISO8859" CHARSET_ENCODING "1" DEFAULT_CHAR 0 FONT_DESCENT 5 FONT_ASCENT 15 COPYRIGHT "Copyright 1989-1991 Network Computing Devices, Inc." ENDPROPERTIES CHARS 256 STARTCHAR C000 ENCODING 0 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C001 ENCODING 1 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0c00 1e00 3f00 7f80 7f80 3f00 1e00 0c00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C002 ENCODING 2 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 ENDCHAR STARTCHAR C003 ENCODING 3 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 6600 6600 6600 7e00 6600 6600 6600 0000 1f80 0600 0600 0600 0600 0600 0000 0000 ENDCHAR STARTCHAR C004 ENCODING 4 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 7c00 6000 6000 7800 6000 6000 6000 0f80 0c00 0c00 0f00 0c00 0c00 0c00 0000 0000 ENDCHAR STARTCHAR C005 ENCODING 5 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 3c00 6600 6000 6000 6600 3c00 0000 1f00 1980 1980 1f00 1e00 1b00 1980 0000 0000 ENDCHAR STARTCHAR C006 ENCODING 6 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 3000 3000 3000 3000 3000 3e00 0000 0f80 0c00 0c00 0f00 0c00 0c00 0c00 0000 0000 ENDCHAR STARTCHAR C007 ENCODING 7 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 3300 3300 1e00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C010 ENCODING 8 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0c00 0c00 7f80 0c00 0c00 0000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C011 ENCODING 9 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 6600 7600 7e00 7e00 6e00 6600 0000 0c00 0c00 0c00 0c00 0c00 0c00 0f80 0000 0000 ENDCHAR STARTCHAR C012 ENCODING 10 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 6600 6600 6600 3c00 3c00 1800 1800 0000 1f80 0600 0600 0600 0600 0600 0000 0000 ENDCHAR STARTCHAR C013 ENCODING 11 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 fc00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C014 ENCODING 12 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 fc00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C015 ENCODING 13 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0fc0 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C016 ENCODING 14 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0fc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C017 ENCODING 15 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ffc0 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C020 ENCODING 16 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C021 ENCODING 17 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C022 ENCODING 18 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C023 ENCODING 19 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C024 ENCODING 20 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffc0 0000 0000 0000 0000 ENDCHAR STARTCHAR C025 ENCODING 21 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0fc0 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C026 ENCODING 22 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 fc00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C027 ENCODING 23 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ffc0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C030 ENCODING 24 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 ffc0 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C031 ENCODING 25 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR C032 ENCODING 26 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 01c0 0700 1c00 7000 1c00 0700 01c0 0000 0000 7fc0 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C033 ENCODING 27 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 7000 1c00 0700 01c0 0700 1c00 7000 0000 0000 7fc0 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C034 ENCODING 28 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0080 3f80 5b00 1b00 1b00 1b00 1b00 3300 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C035 ENCODING 29 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0180 0300 7fc0 0600 0c00 7fc0 1800 3000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C036 ENCODING 30 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f00 1980 1980 1800 1800 1800 7e00 1800 1800 1800 7c00 56c0 7380 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C037 ENCODING 31 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0c00 0c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR space ENCODING 32 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ! ENCODING 33 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0000 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR " ENCODING 34 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 3300 1200 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR # ENCODING 35 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0d80 0d80 0d80 3fc0 1b00 1b00 1b00 7f80 3600 3600 3600 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR $ ENCODING 36 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 3f00 6d80 6c00 6c00 6c00 3f00 0d80 0d80 0d80 6d80 3f00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR % ENCODING 37 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 3980 6d80 6f00 3b00 0600 0600 0c00 0c00 1b80 1ec0 36c0 3380 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR & ENCODING 38 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1c00 3600 3600 3600 3c00 1800 3800 6c00 66c0 6380 6300 7780 3cc0 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ' ENCODING 39 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f00 0e00 1800 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ( ENCODING 40 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0300 0600 0c00 0c00 1800 1800 1800 1800 1800 0c00 0c00 0600 0300 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ) ENCODING 41 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0c00 0600 0600 0600 0600 0600 0c00 0c00 1800 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR * ENCODING 42 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 3300 3300 1e00 7f80 1e00 3300 3300 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR + ENCODING 43 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0c00 0c00 0c00 7f80 0c00 0c00 0c00 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR , ENCODING 44 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0e00 0e00 1800 0000 0000 0000 0000 ENDCHAR STARTCHAR - ENCODING 45 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 7f80 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR . ENCODING 46 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0e00 0e00 0e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR / ENCODING 47 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0180 0180 0300 0300 0600 0600 0c00 0c00 1800 1800 3000 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 0 ENCODING 48 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 3300 6180 6180 6180 6180 6180 3300 3300 1e00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 1 ENCODING 49 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1c00 3c00 6c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 2 ENCODING 50 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 0180 0180 0300 0e00 1800 3000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 3 ENCODING 51 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 0180 0300 0e00 0300 0180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 4 ENCODING 52 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0100 0300 0700 0f00 1b00 3300 6300 6300 7f80 0300 0300 0300 0300 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 5 ENCODING 53 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 6000 6000 6000 6000 6e00 7300 0180 0180 0180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 6 ENCODING 54 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6100 6000 6000 6e00 7300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 7 ENCODING 55 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 0180 0180 0300 0300 0600 0600 0c00 0c00 1800 1800 3000 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 8 ENCODING 56 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 3300 1e00 3300 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR 9 ENCODING 57 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 6180 3380 1d80 0180 0180 2180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR : ENCODING 58 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0e00 0e00 0000 0000 0000 0000 0e00 0e00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ; ENCODING 59 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0e00 0e00 0000 0000 0000 0000 0e00 0e00 1c00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR < ENCODING 60 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0100 0300 0600 0c00 1800 3000 6000 3000 1800 0c00 0600 0300 0100 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR = ENCODING 61 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 7f80 0000 0000 0000 0000 7f80 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR > ENCODING 62 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 2000 3000 1800 0c00 0600 0300 0180 0300 0600 0c00 1800 3000 2000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ? ENCODING 63 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 0300 0600 0c00 0c00 0c00 0000 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR @ ENCODING 64 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6780 6f80 6d80 6d80 6d80 6f00 6600 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR A ENCODING 65 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 3300 6180 6180 6180 7f80 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR B ENCODING 66 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7c00 6600 6300 6300 6300 6600 7e00 6300 6180 6180 6180 6300 7e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C ENCODING 67 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6000 6000 6000 6000 6000 6000 6000 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR D ENCODING 68 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7e00 6300 6180 6180 6180 6180 6180 6180 6180 6180 6180 6300 7e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR E ENCODING 69 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 6000 6000 6000 6000 6000 7e00 6000 6000 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR F ENCODING 70 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 6000 6000 6000 6000 6000 7e00 6000 6000 6000 6000 6000 6000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR G ENCODING 71 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6000 6000 6000 6780 6180 6180 6180 6180 3380 1e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR H ENCODING 72 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6180 6180 6180 6180 7f80 6180 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR I ENCODING 73 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR J ENCODING 74 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f80 0180 0180 0180 0180 0180 0180 0180 0180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR K ENCODING 75 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6300 6300 6600 6600 7c00 6600 6600 6300 6300 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR L ENCODING 76 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6000 6000 6000 6000 6000 6000 6000 6000 6000 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR M ENCODING 77 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 7380 7380 7f80 6d80 6d80 6d80 6d80 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR N ENCODING 78 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 7180 7180 7980 7980 6d80 6d80 6780 6780 6380 6380 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR O ENCODING 79 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR P ENCODING 80 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7e00 6300 6180 6180 6180 6180 6300 7e00 6000 6000 6000 6000 6000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Q ENCODING 81 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6180 6180 6180 6180 6180 6180 6d80 6780 3300 1f00 0180 0000 0000 0000 0000 ENDCHAR STARTCHAR R ENCODING 82 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7e00 6300 6180 6180 6180 6180 6300 7e00 6600 6300 6300 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR S ENCODING 83 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6000 6000 3000 1e00 0300 0180 0180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR T ENCODING 84 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR U ENCODING 85 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6180 6180 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR V ENCODING 86 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6180 6180 3300 3300 3300 1e00 1e00 1e00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR W ENCODING 87 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 6180 6180 6180 6d80 6d80 6d80 6d80 7380 7380 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR X ENCODING 88 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 3300 3300 1e00 1e00 0c00 1e00 1e00 3300 3300 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Y ENCODING 89 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6180 6180 3300 3300 1e00 1e00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Z ENCODING 90 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7f80 0180 0180 0300 0600 0600 0c00 1800 1800 3000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR [ ENCODING 91 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3f00 3000 3000 3000 3000 3000 3000 3000 3000 3000 3000 3000 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR \ ENCODING 92 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 3000 3000 1800 1800 0c00 0c00 0600 0600 0300 0300 0180 0180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ] ENCODING 93 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3f00 0300 0300 0300 0300 0300 0300 0300 0300 0300 0300 0300 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ^ ENCODING 94 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 6180 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR _ ENCODING 95 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 7fc0 0000 0000 0000 0000 ENDCHAR STARTCHAR ` ENCODING 96 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3c00 1c00 0600 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR a ENCODING 97 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1f00 3180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR b ENCODING 98 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6000 6000 6000 6000 6000 6e00 7300 6180 6180 6180 6180 7300 6e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR c ENCODING 99 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1f00 3180 6000 6000 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR d ENCODING 100 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0180 0180 0180 0180 0180 1d80 3380 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR e ENCODING 101 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR f ENCODING 102 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f00 1980 1980 1800 1800 1800 1800 7e00 1800 1800 1800 1800 1800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR g ENCODING 103 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3e80 6380 6300 6300 6300 3e00 6000 3f00 6180 6180 6180 3f00 0000 ENDCHAR STARTCHAR h ENCODING 104 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6000 6000 6000 6000 6000 6e00 7300 6180 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR i ENCODING 105 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0c00 0c00 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR j ENCODING 106 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0180 0180 0000 0780 0180 0180 0180 0180 0180 0180 0180 3180 3180 3180 1f00 0000 ENDCHAR STARTCHAR k ENCODING 107 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 6000 6000 6000 6000 6000 6300 6600 6c00 7800 7c00 6600 6300 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR l ENCODING 108 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR m ENCODING 109 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 5b00 7f80 6d80 6d80 6d80 6d80 6d80 6d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR n ENCODING 110 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6e00 7300 6180 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR o ENCODING 111 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR p ENCODING 112 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6e00 7300 6180 6180 6180 6180 7300 6e00 6000 6000 6000 6000 0000 ENDCHAR STARTCHAR q ENCODING 113 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1d80 3380 6180 6180 6180 6180 3380 1d80 0180 0180 0180 0180 0000 ENDCHAR STARTCHAR r ENCODING 114 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6f00 3980 3000 3000 3000 3000 3000 3000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR s ENCODING 115 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3f00 6180 6000 3f00 0180 0180 6180 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR t ENCODING 116 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 1800 1800 1800 7e00 1800 1800 1800 1800 1800 1980 0f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR u ENCODING 117 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR v ENCODING 118 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 6180 3300 3300 1e00 1e00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR w ENCODING 119 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 6180 6180 6d80 6d80 6d80 7f80 3300 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR x ENCODING 120 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 3300 1e00 0c00 0c00 1e00 3300 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR y ENCODING 121 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0180 6180 3300 1e00 0000 ENDCHAR STARTCHAR z ENCODING 122 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3f80 0180 0300 0600 0c00 1800 3000 3f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR { ENCODING 123 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0780 0c00 0c00 0c00 0c00 0c00 7800 0c00 0c00 0c00 0c00 0c00 0780 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR bar ENCODING 124 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR } ENCODING 125 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7800 0c00 0c00 0c00 0c00 0c00 0780 0c00 0c00 0c00 0c00 0c00 7800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ~ ENCODING 126 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3980 6d80 6700 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR C177 ENCODING 127 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR doorway ENCODING 128 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1e00 1200 1200 1e00 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR vodoor ENCODING 129 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 7f80 7f80 0000 0000 0000 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR codoor ENCODING 130 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0c00 0c00 0c00 8c40 8c40 0c00 0c00 0c00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR vcdoor ENCODING 131 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 0c00 3300 2100 2100 2100 2100 2100 2100 3300 0c00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR hcdoor ENCODING 132 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 7f80 4080 8040 8040 4080 7f80 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR room ENCODING 133 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0c00 0c00 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR dark corridor ENCODING 134 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 4440 1100 ENDCHAR STARTCHAR lit corridor ENCODING 135 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 5540 aa80 ENDCHAR STARTCHAR upstair ENCODING 136 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0100 0200 0400 0800 1000 2000 1000 0800 0400 0200 0100 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR dnstair ENCODING 137 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 2000 1000 0800 0400 0200 0100 0200 0400 0800 1000 2000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR trap ENCODING 138 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 ffc0 c0c0 e1c0 b340 9e40 8c40 9e40 b340 e1c0 c0c0 ffc0 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR web ENCODING 139 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 4980 f900 4f00 c9c0 9940 9300 f240 9e40 9340 32c0 a640 fcc0 2f80 2580 e4c0 ec80 7f80 4bc0 4940 c900 ENDCHAR STARTCHAR pool ENCODING 140 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP b6c0 0000 2480 db40 0000 9240 6d80 0000 4900 b6c0 0000 2480 db40 0000 9240 6d80 0000 4900 b6c0 0000 ENDCHAR STARTCHAR fountain ENCODING 141 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 1000 0a00 4200 0c00 3000 0280 6800 0100 4800 2900 4800 0900 9c00 1400 ff80 ff80 ff80 ENDCHAR STARTCHAR sink ENCODING 142 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 2100 2100 2100 2100 1e00 1e00 1200 ENDCHAR STARTCHAR throne ENCODING 143 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0100 0100 0100 0100 0100 1f00 0900 0900 3f00 2100 2100 ffc0 ENDCHAR STARTCHAR altar ENCODING 144 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 7f80 7f80 3300 3300 3300 3300 ENDCHAR STARTCHAR up ladder ENCODING 145 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 9000 f000 9000 9000 f000 9100 9380 f540 9100 9100 f100 9100 9100 f000 9000 9000 f000 9000 9000 f000 ENDCHAR STARTCHAR down ladder ENCODING 146 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 9000 f000 9000 9000 f000 9100 9100 f100 9100 9100 f540 9380 9100 f000 9000 9000 f000 9000 9000 f000 ENDCHAR STARTCHAR dbvwall ENCODING 147 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0c00 0c00 0c00 0c00 0c00 3f00 3f00 3f00 3f00 3f00 3f00 3f00 3f00 3f00 3f00 0c00 0c00 0c00 0c00 0c00 ENDCHAR STARTCHAR dbhwall ENCODING 148 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3f00 3f00 ffc0 ffc0 3f00 3f00 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ice ENCODING 149 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1200 0c00 0c00 1200 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR lava ENCODING 150 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 8800 0480 0080 3700 1300 9900 0940 4140 0840 2900 8900 a840 4540 ffc0 ffc0 ffc0 ENDCHAR STARTCHAR vbeam ENCODING 151 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 0800 0e00 0400 0800 1000 2000 1000 0800 0800 0800 0800 0400 0200 0400 0800 1000 3000 0800 0800 ENDCHAR STARTCHAR hbeam ENCODING 152 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 2000 3000 e8c0 0500 0200 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR lslant ENCODING 153 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 8000 4000 4000 4000 3000 0800 0800 0800 0800 0800 0800 0400 0400 0200 0200 0200 0200 0200 0180 0040 ENDCHAR STARTCHAR rslant ENCODING 154 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0040 0080 0080 0080 0080 0080 0300 0400 0400 0400 0800 0800 1000 2000 4000 4000 4000 4000 4000 8000 ENDCHAR STARTCHAR dig beam ENCODING 155 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 8040 4080 2100 1200 0c00 0c00 1200 2100 4080 8040 8040 4080 2100 1200 0c00 0c00 1200 2100 4080 8040 ENDCHAR STARTCHAR camera flash ENCODING 156 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 4200 0600 6400 0100 0940 4840 0400 2100 1e00 5ec0 1e80 1e00 2500 5440 2000 0d80 2840 c000 9280 0040 ENDCHAR STARTCHAR boomerang left ENCODING 157 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 3000 2800 1400 0a00 0500 0300 0500 0a00 1400 2800 3000 0000 0000 0000 0000 ENDCHAR STARTCHAR boomerang right ENCODING 158 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0300 0500 0a00 1400 2800 3000 2800 1400 0a00 0500 0300 0000 0000 0000 0000 ENDCHAR STARTCHAR shield 1 ENCODING 159 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0200 76c0 fa40 8a00 4680 f900 ea00 e7c0 ddc0 5480 3100 b300 e8c0 4cc0 6c00 6300 4480 a180 1400 0780 ENDCHAR STARTCHAR shield 2 ENCODING 160 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 6100 b340 0040 08c0 77c0 d240 b980 8380 a100 2700 4c40 31c0 bf40 c200 ca00 3380 4180 1b80 0780 ENDCHAR STARTCHAR shield 3 ENCODING 161 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP d000 0600 5e80 4e80 4c80 2000 2800 3e80 5f80 e640 5080 47c0 8380 c880 a940 9840 0dc0 1300 6080 3200 ENDCHAR STARTCHAR shield 4 ENCODING 162 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 4200 d480 95c0 1c40 3c80 9b80 2d80 5280 5900 5400 6500 0680 2780 9c80 af80 2180 6080 2340 4580 3100 ENDCHAR STARTCHAR swallow top left ENCODING 163 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 00c0 0100 0100 0100 0200 0200 0200 0400 0400 0400 ENDCHAR STARTCHAR swallow top center ENCODING 164 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1e00 6180 8040 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR swallow top right ENCODING 165 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 c000 2000 2000 2000 1000 1000 1000 0800 0800 0800 ENDCHAR STARTCHAR swallow mid left ENCODING 166 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0400 0400 0400 0800 0800 0800 1000 1000 1000 1000 1000 1000 1000 1000 0800 0800 0800 0400 0400 0400 ENDCHAR STARTCHAR swallow mid right ENCODING 167 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 0800 0800 0400 0400 0400 0200 0200 0200 0200 0200 0200 0200 0200 0400 0400 0400 0800 0800 0800 ENDCHAR STARTCHAR swallow bot left ENCODING 168 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0400 0400 0400 0200 0200 0200 0100 0100 0100 00c0 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR swallow bot center ENCODING 169 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 8040 6180 1e00 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR swallow bot right ENCODING 170 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 0800 0800 1000 1000 1000 2000 2000 2000 c000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR explosion 1 ENCODING 171 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 01c0 0e00 31c0 ce00 31c0 c600 18c0 6700 98c0 2300 ccc0 3300 4c40 9380 2440 4980 b640 2880 5300 ENDCHAR STARTCHAR explosion 2 ENCODING 172 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f780 ENDCHAR STARTCHAR explosion 3 ENCODING 173 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 c000 3800 c600 3980 c640 3180 8c40 7300 8cc0 6200 9980 6640 1900 e480 1240 c900 3680 8a40 6500 ENDCHAR STARTCHAR explosion 4 ENCODING 174 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP a4c0 2900 4a40 5480 a500 aa40 aa80 aa80 aa80 5540 aa80 aa80 aa80 aa40 a500 5480 4a40 2900 a4c0 5300 ENDCHAR STARTCHAR explosion 5 ENCODING 175 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0840 f780 0840 7700 8880 7740 8880 b680 aa80 5540 aa80 b680 8880 7740 8880 7700 0840 f780 0840 f780 ENDCHAR STARTCHAR explosion 6 ENCODING 176 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 9280 4a40 2940 9540 5280 2a80 aa80 aa80 aa80 5540 aa80 aa80 aa80 2a80 5280 9540 2940 4a40 9280 6500 ENDCHAR STARTCHAR explosion 7 ENCODING 177 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 2880 b640 4980 2440 9380 4c40 3300 ccc0 2300 98c0 6700 18c0 c600 31c0 ce00 31c0 0e00 01c0 0000 0000 ENDCHAR STARTCHAR explosion 8 ENCODING 178 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 f7c0 0800 0000 ENDCHAR STARTCHAR explosion 9 ENCODING 179 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 8a40 3680 c900 1240 e480 1900 6640 9980 6200 8cc0 7300 8c40 3180 c640 3980 c600 3800 c000 0000 0000 ENDCHAR STARTCHAR illegal object ENCODING 180 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 3b80 4640 4440 4c40 3b80 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR amulet ENCODING 181 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 1e00 2100 2100 2100 1100 1100 0e00 1f00 1f00 0e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR food ENCODING 182 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 3f00 3f00 3f00 1e00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 ENDCHAR STARTCHAR weapon ENCODING 183 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1000 1800 1400 1200 1200 1200 1200 1200 1200 1200 7f80 1c00 1c00 1c00 1c00 1c00 0000 0000 ENDCHAR STARTCHAR tool ENCODING 184 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 1e00 2100 2100 3f00 3f00 3f00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ball ENCODING 185 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0e00 1f00 1f00 1f00 eac0 5780 ENDCHAR STARTCHAR chain ENCODING 186 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 6d80 9240 6d80 ENDCHAR STARTCHAR rock ENCODING 187 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1e00 3100 2900 4280 6900 5480 5000 2280 4980 5f80 3500 ff40 bfc0 ENDCHAR STARTCHAR armor ENCODING 188 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 2e80 3f80 2a80 3580 2a80 3580 2a80 1500 0a00 0400 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR potion ENCODING 189 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 1e00 0c00 0c00 0c00 0c00 1e00 3700 3d00 2f00 3b00 1e00 0000 0000 0000 ENDCHAR STARTCHAR scroll ENCODING 190 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 3f00 7f80 3f00 2a00 1500 2a00 1500 2a00 3f00 7f80 3f00 0000 0000 0000 0000 ENDCHAR STARTCHAR wand ENCODING 191 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1100 1500 1240 0a80 0100 0400 0400 0800 0800 0800 1000 1000 1000 2000 0000 0000 0000 0000 ENDCHAR STARTCHAR ring ENCODING 192 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 2900 1200 4180 1c00 2280 2200 2200 1c80 4100 1480 2400 0000 0000 0000 0000 ENDCHAR STARTCHAR gem ENCODING 193 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 3e00 6300 2200 1c00 0800 0000 0000 ENDCHAR STARTCHAR gold ENCODING 194 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0000 0000 2a00 2a00 5280 5480 4500 0000 3000 5f00 7d80 6f80 1c00 ENDCHAR STARTCHAR venom ENCODING 195 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 0c00 1200 2200 2c00 1000 0000 0000 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR spbook ENCODING 196 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 3e00 2300 3300 2300 2300 2300 3300 2300 3f00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Aring ENCODING 197 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1200 1200 0c00 0c00 1e00 3300 6180 6180 7f80 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR AE ENCODING 198 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0f80 1e00 3600 3600 6600 6600 7f80 6600 6600 6600 6600 6600 6780 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ccedilla ENCODING 199 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1e00 3300 6180 6000 6000 6000 6000 6000 6000 6000 6180 3300 1e00 0c00 0400 1200 0c00 0000 ENDCHAR STARTCHAR Egrave ENCODING 200 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 7f80 6000 6000 6000 7e00 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Eacute ENCODING 201 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 7f80 6000 6000 6000 7e00 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ecircumflex ENCODING 202 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 7f80 6000 6000 6000 7e00 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Edieresis ENCODING 203 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 7f80 6000 6000 6000 7e00 6000 6000 6000 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Igrave ENCODING 204 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 3f00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Iacute ENCODING 205 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 3f00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Icircumflex ENCODING 206 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 3f00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Idieresis ENCODING 207 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 3f00 0c00 0c00 0c00 0c00 0c00 0c00 0c00 3f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Eth ENCODING 208 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 7e00 6300 6180 6180 6180 6180 f980 6180 6180 6180 6180 6300 7e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ntilde ENCODING 209 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 4180 6180 7180 7980 7d80 6f80 6780 6380 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ograve ENCODING 210 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Oacute ENCODING 211 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0300 0600 0c00 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ocircumflex ENCODING 212 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Otilde ENCODING 213 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Odieresis ENCODING 214 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 1e00 3300 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR multiply ENCODING 215 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 2080 3180 1b00 0e00 0e00 1b00 3180 2080 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Oslash ENCODING 216 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0080 1f80 3300 6380 6580 6580 6980 6980 7180 3300 7e00 4000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ugrave ENCODING 217 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Uacute ENCODING 218 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0300 0600 0c00 0000 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Ucircumflex ENCODING 219 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 6180 6180 6180 6180 6180 6180 6180 3380 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Udieresis ENCODING 220 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 6180 6180 6180 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Yacute ENCODING 221 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0300 0600 0c00 0000 4080 6180 3300 1e00 0c00 0c00 0c00 0c00 0c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR Thorn ENCODING 222 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 3c00 1800 1f00 1980 1980 1980 1f00 1800 1800 1800 3c00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR germandbls ENCODING 223 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 1c00 3e00 7300 6300 6300 6600 6c00 6600 6300 6100 6300 6e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR agave ENCODING 224 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR aacute ENCODING 225 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR acircumflex ENCODING 226 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR atilde ENCODING 227 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR adieresis ENCODING 228 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR aring ENCODING 229 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0c00 1200 1200 0c00 3f00 6180 0180 3f80 6180 6180 6180 3e80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ae ENCODING 230 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3b00 4d80 0d80 0f00 3c00 6c00 6c80 3700 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ccedilla ENCODING 231 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1f00 3180 6000 6000 6000 6000 3180 1f00 0c00 0400 1200 0c00 0000 ENDCHAR STARTCHAR egrave ENCODING 232 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR eacute ENCODING 233 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ecircumflex ENCODING 234 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR edieresis ENCODING 235 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 1e00 3300 6180 7f80 6000 6000 3180 1f00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR igrave ENCODING 236 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR iacute ENCODING 237 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR icircumflex ENCODING 238 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR idieresis ENCODING 239 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 3c00 0c00 0c00 0c00 0c00 0c00 0c00 7f80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR eth ENCODING 240 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 4400 6c00 3800 3800 6c00 4600 1f00 3380 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ntilde ENCODING 241 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 0000 6e00 7300 6180 6180 6180 6180 6180 6180 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ograve ENCODING 242 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR oacute ENCODING 243 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ocircumflex ENCODING 244 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR otilde ENCODING 245 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 1900 3f00 2600 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR odieresis ENCODING 246 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 1e00 3300 6180 6180 6180 6180 3300 1e00 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR divide ENCODING 247 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0c00 0c00 0000 0000 7f80 7f80 0000 0000 0c00 0c00 0000 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR oslash ENCODING 248 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 1e80 3380 6380 6780 6d80 7980 3300 7e00 4000 0000 0000 0000 0000 ENDCHAR STARTCHAR ugrave ENCODING 249 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3000 1800 0c00 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR uacute ENCODING 250 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ucircumflex ENCODING 251 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0c00 1e00 3300 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR udieresis ENCODING 252 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 6180 6180 6180 6180 6180 6180 3380 1d80 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR yacute ENCODING 253 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0600 0c00 1800 0000 0000 0000 6180 6180 6180 6180 6180 3380 1d80 0180 6180 3300 1e00 0000 ENDCHAR STARTCHAR thorn ENCODING 254 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 0000 0000 0000 0000 0000 3800 1e00 1b00 1b00 1e00 1800 1800 3800 0000 0000 0000 0000 0000 ENDCHAR STARTCHAR ydieresis ENCODING 255 SWIDTH 878 0 DWIDTH 10 0 BBX 10 20 0 -5 BITMAP 0000 0000 3300 3300 0000 0000 0000 0000 6180 6180 6180 6180 6180 3380 1d80 0180 6180 3300 1e00 0000 ENDCHAR ENDFONT nethack-3.4.3/win/X11/nh32icon0100644000000000000000000000212207764735041014363 0ustar rootroot/* SCCS Id: @(#)nh32icon 3.4 2002/02/12 */ /* Copyright (C) 1993,1995 by Robert Patrick Rankin */ /* NetHack may be freely redistributed. See license for details. */ /* 32x32 X11 icon for NetHack. */ #define nh32icon_width 32 #define nh32icon_height 32 static unsigned char nh32icon_bits[] = { 0xff, 0x7f, 0xfe, 0xff, 0x01, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x40, 0x82, 0x21, 0x25, 0xc0, 0x83, 0x61, 0x25, 0x80, 0x81, 0xe1, 0x3d, 0x80, 0x81, 0xa1, 0x25, 0x80, 0x81, 0x21, 0x25, 0x80, 0x81, 0x01, 0x00, 0xe0, 0x87, 0x71, 0x48, 0x90, 0x89, 0x81, 0x48, 0x80, 0x81, 0x61, 0x78, 0x80, 0x81, 0x81, 0x40, 0x80, 0x81, 0x71, 0x42, 0x84, 0x81, 0x03, 0x00, 0x8a, 0xc1, 0x02, 0x00, 0x84, 0x41, 0x32, 0x67, 0x80, 0x41, 0xf3, 0x7f, 0x80, 0xc1, 0xf1, 0x7f, 0x84, 0x81, 0x71, 0x77, 0x8a, 0x81, 0xb1, 0x68, 0x84, 0x81, 0x71, 0x77, 0x80, 0x81, 0x71, 0x77, 0x80, 0x81, 0xb1, 0x68, 0x84, 0x81, 0x71, 0x77, 0x8a, 0x81, 0xf1, 0x7f, 0x84, 0x81, 0xe1, 0x3f, 0x80, 0x81, 0xc1, 0x1f, 0x80, 0x81, 0x81, 0x0f, 0x80, 0x81, 0x01, 0x07, 0x00, 0x81, 0x01, 0xc0, 0x03, 0x80, 0xff, 0x7f, 0xfe, 0xff}; nethack-3.4.3/win/X11/nh56icon0100644000000000000000000000527507764735041014405 0ustar rootroot/* SCCS Id: @(#)nh56icon 3.4 2002/02/12 */ /* Copyright (c) 1993,1995 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* 56x56 X11 icon for NetHack. */ #define nh56icon_width 56 #define nh56icon_height 56 static unsigned char nh56icon_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x30, 0x38, 0x18, 0x00, 0xc0, 0x03, 0x00, 0x78, 0x28, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x6c, 0x3e, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x55, 0x3f, 0x00, 0xc0, 0x23, 0x22, 0xfc, 0xc7, 0x7f, 0x88, 0xc8, 0x43, 0x10, 0xfc, 0xd7, 0x7f, 0x10, 0xc4, 0x03, 0x07, 0xfe, 0xc7, 0xff, 0xc0, 0xc1, 0x83, 0x0d, 0xfe, 0xd7, 0xff, 0x60, 0xc3, 0xa3, 0x28, 0xfe, 0xc7, 0xff, 0x28, 0xca, 0x83, 0x0d, 0xfe, 0xd7, 0xff, 0x60, 0xc3, 0x03, 0x07, 0xfe, 0xc7, 0xff, 0xc0, 0xc1, 0x43, 0x10, 0xfc, 0xd7, 0x7f, 0x10, 0xc4, 0x23, 0x22, 0xfc, 0xc7, 0x7f, 0x88, 0xc8, 0x03, 0x00, 0xf8, 0x55, 0x3f, 0x00, 0xc0, 0x03, 0x00, 0xf8, 0x44, 0x3e, 0x00, 0xc0, 0x03, 0x00, 0x78, 0x54, 0x3c, 0x00, 0xc0, 0x03, 0x00, 0x30, 0x6c, 0x18, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x6c, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x43, 0x10, 0x21, 0x38, 0x70, 0x20, 0xc2, 0xc3, 0x10, 0x21, 0x38, 0x88, 0x20, 0xc2, 0xc3, 0x10, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x11, 0x21, 0x38, 0x80, 0x20, 0xc2, 0x43, 0x12, 0x3f, 0x38, 0x70, 0xe0, 0xc3, 0x43, 0x12, 0x21, 0x38, 0x80, 0x00, 0xc2, 0x43, 0x14, 0x21, 0x38, 0x80, 0x00, 0xc2, 0x43, 0x18, 0x21, 0x38, 0x80, 0x00, 0xc2, 0x43, 0x18, 0x21, 0x38, 0x88, 0x0c, 0xc2, 0x43, 0x10, 0x21, 0x38, 0x70, 0x0c, 0xc2, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x38, 0x00, 0x00, 0xc0, 0xfb, 0xff, 0xff, 0x39, 0xff, 0xff, 0xdf, 0x0b, 0x00, 0x80, 0x7c, 0x02, 0x00, 0xd0, 0x0b, 0x00, 0x80, 0xee, 0x02, 0x00, 0xd0, 0xfb, 0xff, 0xff, 0xd6, 0xfe, 0xff, 0xdf, 0x0b, 0x00, 0x80, 0xaa, 0x02, 0x00, 0xd0, 0x0b, 0x00, 0x80, 0x54, 0x02, 0x00, 0xd0, 0xfb, 0xff, 0xff, 0x39, 0xff, 0xff, 0xdf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; nethack-3.4.3/win/X11/nh72icon0100644000000000000000000001037007764735041014373 0ustar rootroot/* SCCS Id: @(#)nh72icon 3.4 1993/01/21 */ /* Copyright (c) 1993 by M. Stephenson */ /* NetHack may be freely redistributed. See license for details. */ /* 72x72 X11 icon for NetHack. */ #define nh72icon_width 72 #define nh72icon_height 72 static unsigned char nh72icon_bits[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x08, 0x00, 0x00, 0x00, 0x10, 0x00, 0xe0, 0x07, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0xe0, 0x07, 0x00, 0x78, 0x00, 0x00, 0x00, 0x1e, 0x00, 0xe0, 0x07, 0x3e, 0xc8, 0x07, 0x00, 0xf8, 0x13, 0x7c, 0xe0, 0x07, 0x22, 0x08, 0xfc, 0xc1, 0x0f, 0x10, 0x44, 0xe0, 0x07, 0x36, 0x08, 0x00, 0x7f, 0x00, 0x10, 0x6c, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x14, 0x08, 0x00, 0x00, 0x00, 0x10, 0x28, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x14, 0x08, 0x00, 0x00, 0x00, 0x10, 0x28, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x14, 0x08, 0x00, 0x00, 0x00, 0x10, 0x28, 0xe0, 0x87, 0xff, 0x08, 0x10, 0x00, 0x10, 0x10, 0xff, 0xe1, 0xc7, 0xff, 0x09, 0x38, 0x10, 0x38, 0x90, 0xff, 0xe3, 0x47, 0x1c, 0x09, 0x78, 0x38, 0x3c, 0x90, 0x38, 0xe2, 0x07, 0x1c, 0x08, 0xfc, 0x39, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfc, 0xbb, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfe, 0xff, 0xff, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfc, 0xbb, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0xfc, 0x39, 0x7f, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x78, 0x38, 0x3c, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x38, 0x38, 0x38, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x10, 0x38, 0x10, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x28, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x1c, 0x08, 0x00, 0x38, 0x00, 0x10, 0x38, 0xe0, 0x07, 0x08, 0x18, 0x00, 0x28, 0x00, 0x10, 0x10, 0xe0, 0x07, 0x08, 0x30, 0x00, 0x38, 0x00, 0x18, 0x10, 0xe0, 0x07, 0x00, 0x60, 0x00, 0x28, 0x00, 0x0c, 0x00, 0xe0, 0x07, 0x00, 0xc0, 0x00, 0x38, 0x00, 0x06, 0x00, 0xe0, 0x07, 0x00, 0x80, 0x01, 0x28, 0x00, 0x03, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x03, 0x38, 0x80, 0x01, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x06, 0x6c, 0xc0, 0x00, 0x10, 0xe0, 0x07, 0x08, 0x00, 0x0c, 0x44, 0x60, 0x00, 0x92, 0xe0, 0x07, 0x49, 0x00, 0x18, 0x7c, 0x30, 0x00, 0x6c, 0xe0, 0x07, 0x36, 0x00, 0x30, 0x00, 0x18, 0x00, 0x44, 0xe0, 0x07, 0x22, 0x00, 0x60, 0x00, 0x0c, 0x00, 0x83, 0xe1, 0x87, 0xc1, 0x00, 0xc0, 0x00, 0x06, 0x00, 0x44, 0xe0, 0x07, 0x22, 0x00, 0x80, 0x01, 0x03, 0x00, 0x6c, 0xe0, 0x07, 0x36, 0x00, 0x00, 0x83, 0x01, 0x00, 0x92, 0xe0, 0x07, 0x49, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x10, 0xe0, 0x07, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; nethack-3.4.3/win/X11/nh_icon.xpm0100644000000000000000000000356207764735041015171 0ustar rootroot/* XPM */ static char * nh_icon[] = { "40 40 6 1", " s None c none", ". c #ffffff", "X c #dadab6", "o c #6c91b6", "O c #476c6c", "+ c #000000", " ", " ", " ", " . .X..XX.XX X ", " .. .....X.XXXXXX XX ", " ... ....X..XX.XXXXX XXX ", " .. ..........X.XXXXXXXXXXX XX ", " .... ........X..XX.XXXXXXXXX XXXX ", " .... ..........X.XXXXXXXXXXX XXXX ", " ooOOO..ooooooOooOOoOOOOOOOXX+++OO++ ", " ooOOO..ooooooooOoOOOOOOOOOXX+++OO++ ", " ....O..ooooooOooOOoOOOOOOOXX+XXXX++ ", " ....O..ooooooooOoOOOOOOOOOXX+XXXX++ ", " ..OOO..ooooooOooOOoOOOOOOOXX+++XX++ ", " ++++..ooooooooOoOOOOOOOOOXX+++ +++ ", " +++..ooooooOooOOoOOOOOOOXX+++ + ", " ++..ooooooooOoOOOOOOOOOXX+++ ", " ..ooooooOooOOoOOOOOOOXX+++ ", " ..ooooooooOoOOOOOOOOOXX+++ ", " ..ooooooOooOOoOOOOOOOXX+++ ", " ..ooooooooOoOOOOOOOOOXX+++ ", " ..oooooOooOOoOOOOOOXX+++ ", " ..oooooooOoOOOOOOOOXX+++ ", " ..ooooOooOOoOOOOOXX+++ ", " ..ooooooOoOOOOOOOXX++++ ", " ..o..oooOooOOoOOOOXX+XX+++ ", " ...o..oooooOoOOOOOXX++XXX++ ", " ....OO..ooOooOOoOOXX+++XXXX++ ", " ...oo..+..oooOoOOOXX++XXooXXX++ ", " ...ooo..++..OooOOoXX+++XXooOXXX+ ", " ..oooOOXX+++....XXXX++++XXOOoOOXX+ ", " ..oooOOXX+++ ...XXX+++++XXOOooOXX++ ", " ..oooOXXX+++ ..XX+++ +XXOOooOXX++ ", " .....XXX++++ XXXXXXX++ ", " ....XX++++ XXXXXXX+ ", " ...XX+++ XXXXX++ ", " ", " ", " ", " "}; nethack-3.4.3/win/X11/pet_mark.xbm0100644000000000000000000000045007764735041015331 0ustar rootroot#define pet_mark_width 16 #define pet_mark_height 16 static unsigned char pet_mark_bits[] = { 0x00, 0x00, 0x6c, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x7c, 0x00, 0x38, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; nethack-3.4.3/win/X11/rip.xpm0100644000000000000000000024054207764735041014347 0ustar rootroot/* XPM */ static char *rip_xpm[] = { /* width height ncolors chars_per_pixel */ "400 200 90 1", /* colors */ " c #36362E", ". c #414146", "X c #2F2F31", "o c #353523", "O c #034702", "+ c #152E0A", "@ c #30311E", "# c #29292B", "$ c #233511", "% c #22221A", "& c #A6A6A2", "* c #3A3A38", "= c #75746B", "- c #191A14", "; c #7F7E78", ": c #12120D", "> c #1F2713", ", c #16330A", "< c #033E01", "1 c #181816", "2 c #033A01", "3 c #043802", "4 c #161614", "5 c #46464D", "6 c #242425", "7 c #0C0C0A", "8 c #15150C", "9 c #454545", "0 c #4B4B37", "q c #1F300F", "w c #1F2E0F", "e c #3F3F3F", "r c #3D3D3D", "t c #1B1B15", "y c #1A2E0D", "u c #888783", "i c #2D2D2D", "p c #292929", "a c #807F7B", "s c #272F13", "d c #313134", "f c #4D4D56", "g c #18180E", "h c #B4B4B1", "j c #989892", "k c #252621", "l c #90908A", "z c #1C1C18", "x c #83827D", "c c #6D6C64", "v c #20201F", "b c #797873", "n c #2C2C2E", "m c #42424A", "M c #434341", "N c #1F1F17", "B c #273B22", "V c #2E2E1F", "C c #7E7D74", "Z c #8B8B84", "A c #1D1D18", "S c #85857E", "D c #4B4B4F", "F c #CECECC", "G c #034301", "H c #034101", "J c #272728", "K c #043302", "L c #353539", "P c #282B15", "I c #5A5B50", "U c #24241B", "Y c #C0C0BE", "T c #30302A", "R c #5E5E61", "E c #1F330F", "W c #DFDFDC", "Q c #8C8C87", "! c #043C01", "~ c #053602", "^ c #38383B", "/ c #053002", "( c #343437", ") c #44444A", "_ c #52525B", "` c #132909", "' c #060603", "] c #292922", "[ c #424237", "{ c #3B3B3A", /* pixels */ "'''''''''''''''''7777777v7''''''''''''''''''''v''k'7777777777777777:7:7:7:7::::::4::4:444444444411111z1zzzzzzvddvvvvvvvvvvv6J#JJJJJ6JJ66JJJJJJ####nnnnXXdL^^^fRLLLLL^^^^^rrr.rm..mmmmmm5m....c_m__.mm.m.mmm.m.mm.mmm.m_).mmmm)_Df555555D5D5D5D5DDDDDfffff_____________cR______c_______c_____R_R_R______R__uffDDDDDDDDDR5D5D5D5D5D5D55R55D55555555555555Ra555555555)5)))))))))))))))))))5)5))5)5)5)))))))5))55555", "'''''''''''''''''''776777'7''''''''''''''''''7'7kv7'7777777777777:77:7:::::::::::::4:44:44444411111111zzzdzzvzvvzvvvvvvvv66JJ##66JJJ6J6JJ6JJJ#####nnnXXXdL^^^^^^LL^^^r^.R^.^.Rmmmm55m5m55m..m_mm)))mmmmmmm))55)mm.m.mm9mmmmmm)555fffff5fffffDDDDfDffffff_______________R_c_cR_____R__cR_______R__R_R_____fRDfDfDD5DD555D5D5555555555R555555D5555555555555555555)))))))))mmmmmmmm))))))))))))))))))))))))))))))))", "''''''''v''''''''77'7777777v''''''''''''''7'7'77'77777777777:7:7:7::7:7::e:::#.:4:44:4:444444X41111zzz1v1vzvzvzvvvzvvvv666J####JJ6#66J6JJJJ#####nnnnXXXXdL^^m^^^^L^^^.RfRm^m.mmm5m555555mmmmm)mm)))))))))5555555mmm_cmmm_)))))5fff5fffffff_ffffffff_b__________________cbRR__c_RR___________R__________ffff5DD5D5D55DD5555555555555555555555555555555555)5_5)))))))mmmmmm9m9m9mmmmmmmmmmmmmmmmmmmm))))))))))))))", "''''''''''''''''v''7777777vv('''''''''''''7'77'77777777777:7:7:::7:7:::::#7474::4:4:44444n9n491111z11v1v1vzvdvvvvvvvv6666######JJJ6J6JJJJJ#J###n#nnXnXXdLL^^^^^^^^^^.^f...f..mmm55555f5_mmmmm)))))))55))55ff5ff55m)m))mR_)))555f5bffff_R_fff________R___________R_____bR____________________________ffffDf5fDDD5f5D55555555555R5555555555555)5)5c))))))))5_)))))mmm).mm)_m.mm)))))m.m.m.m.m9__.).).m.mmmmmm)))))", "''''''''''''''''v'777777777''''''''''''7'7'77'777777777:7:7:7:7:747474:::4:4:4744:44444444411111z11v11v1v1vvvzvvvvv666JJ#######6J6JJJJJJJ#J####nnnnXXXXd(L^mLm^m^.^^.^.^.^m..mmm55555mmmmmm))))555555555D5fff5ff55))))))_D555555fffffffffff_f______________R__R_____R___R_c_R__R__________________Rfff5f5DD5D55D555555555555555D5D5555))))))))))_5))))))))))mmmmm))m5mmm)mm.m555))m.........9.9..m.m.m.m9mmmmmmm", "''''''''''7''7''''v'777777777''''''''''7'777777777777:7:7::7:747474::474:474:444:444:444444111111v11v1v1vvvvv6vvv66J6#6._###^#JJ6JJJJJJJJ#####nnnnXnXdddLLLf^Lm^m^m^^......m^.mm5m5555m)_))))55555555555ff5fff5RfD555_l55555555fff_ffff__ffffff___________________R_________c__________f_fff_f_f_RfffDfDDf5D5D5555555555)55mRD5fRf5555)))5_)))))5)))))))m)))m).m555555)mmmm555555mm........._..m..._.....__m9m9m", "''''''''''''''7'7'c'7'77777'777777777'7'77'77777777:67:7:7:::::::474::4:4:44:4:4447n4444441111dv11v1v1vvv666666#6##J###__.6##66#6JJJJ#######nnnnnXXXXXdddLL^^mLm^m^m.m^m^.^m....mmmmmmm5))555_55555555Dfffffff5f5f=555Rm55555555fffffffff_f_ff_f_______R___________________________f_f_ff_fffffffff5f5f5D5D555555555))))5_DDf5f55f5f555)mm)mmmmmmmmmmm555555)))5555555mm)555555555m....................m..9.m.mm", "'''''''''''''''v'''7''7'7777777776777{v7777777777:777JJ::74747474:47444474:44444444n4444411)1d5vvvvvv66666666#66666####nR^666#JJ##J##J######nnnnnXnXdddLdLL^LLLm^mm^m^m.^..m^..mmmmmm5)))5555D55D5D5D5ffffffRff5ffb5f5555555DD5f5fffffff_fff_ff__ff______________R________b_R____f_fff_RfffffffffR5ffDD5D5D5555555)555555=5f55555555555)m9_mm)m9mmc.m5555f5555_5f_5f55mmm55mmmm555m......................mmmmm))", "''''''''''''''''v''''''777777767777777777777777:77:::J:74J.::4:4:444744444447444444n444111191zvvvvv6v6vvvvvv6v6666666######J#JJ##J##J####ennnnnXXXXdddd5LLLL^m^mmLm^mmm^m^m..m.Rmmm5m5)55555555D55DDDD5f_fffb55f5f5f5f55555D5D5=5f5ffffff_f_f_ff_f____________cc____________bRbfffff_fffffffffDf5ff55DD5D5Rc5555))))555f5f5m555mmm5f5555mm_.mmmm.mmm)55f555555555_5m55mm5mmmmmmm555mm...mm..e.e.e......mmmmmm555", "'''''''''''''''''''''''''77777^6477777777777r:77::7:7:::::#74:47447444.4#4444444444441111111z16vvvvvv1vvvvvvvv6v6666666JJJJ#6###J#####n#nnnnnXnXXXXdd(ddLLLLLmLm^m^m^m^.......m5mm5m5)5555555D5DDDD5f5ffffffff5f5fffRfD555D5D5ff5ff5fffff___ff_f__f____R___________c_____f_ff_ff_fffffffffffDDfDfDDDf55D5555555))55555f555mmmmmmmmm5cf55mm.mm)mm...m5555mm55_5555m5m55m55mm....mmm5m5mmmmm..._e.f.f.e.mm55555555", "''''''''''''v'''''''''7'77777'67774777777::::::::::::4:444:44:44444444#44444444444111111111zdvvv1v1v1vvvvvv6v6666666##J6#J^#########n#nnn#nnnXXXXdddddLLLLLLLLm^mmLm^mm^m...m.mm)))5)555555D55DD5fDDDfff_ffff5f5f5fffff5DDDDf5f5fffffff____f________________R__________f_fff_bRfffRfffDffDDRRf5DD5D55D5555555))55555f5a55mmmm.....mmm555m.mmmmmm..m55m_5mmmmm5mmm5mmmm_mmm..rer.mmmmm5m5m5m........e..m5_5mc55__", "''''''''''''('''''''''''77777777447:7::7:74:474744:4:44:4447444444#44444444114114111111111v1dvvvvv1vvv1vv6d6v6v6666666#J###########n#nnnnnnXnXXXdddd(((LLL^L^Lm^mLm^m^.mm..m.mm))5)555555c55DD5DDRf5fffff_fffff555ffffff5f5D5fDffDffffff_____fb___________R_________f_fbf_ffff____RfDfDfDDDfD5fDD5f5D55555_)5_R555f5555mm..........mm555m.mmmm...m5_mmmmmmmmmm55mmmmmmm..r.r..^.e_f.mmm5mmmmmmm.mm..mm5mm.m_m...", "N''''''''''''''''''''''777777747474474_::474:4444#47444444444444444444111111111X1111111v111vvv6vv1vv16vvvv566v6666##J#J#########n.n#nnnnnXnX._Xdddd()L(LLL^^^^^m^m^m^m...mm.mm))))555555D5fDD5fDf5=ffffRR_ff555f5fffffffffDfDDfDfffRf_f_f__f__bf___Ra__R________R____fff_f_f_______fffDDfDDD5DR55D555555555555f5f55mmmm_m..e....e...mm555mmm.mmmm55mmmmm..fR5mmm5mm..^.^r.^.^.rrr.re.emmmmmmmmmmmmmmmm_m.ee.r.ee", "'''''''N''''N'''''''''7'7747447474474444J44744744n_4444444444444444111111111111115111v11v1v1vv66vvvvvvLvvv6v66666666JJ#J####.##n#nnnnnnnXnXXdXd.e_xalLLLL^^LmLm^m^m^mblabbbmm)))55555555D5D5ff=Rffbff____ff5ff5555fff_fffffRDfffffff_f________b__________R_________fff__f__________ffffDDD5DD5555555D_5))5555f55mmmmm....r..e.Rr..^..mm55mmmmmmm5mmm....r.mmmmmmmm..^.^.^.^.^.^.^.^.^.^r....mmmmmmmmmm..r.r.r.e.", "'''''''v'''NL'''''7'7''7'777774474744447447444444441441411444444441111111v11v11v1d1v111v11vvvv666vvvvvv6v666v6666#6###J######nnnnnnnnnXnX._e=&hY&&jjh^L^^^^^^mLmmfmmmRFYYFWW&lRc555555DDafffffffffff____ff5f55f5f5ffRf__ffffffDffffR__f____________R__c__________ff_f__________ff__f_fD5D5f555D5555555_5)5fff5_5mm....r...r.....r...rmmm_5m5mm5mmm.r.^.^.^.mmmmm_f.f^^r^R.^^.^.^.^rrr^..^.^..........^er.^.^.^.^", "''''''''''''N''''''''77'777774747444#m444447474444441111111111111111111v11Rv11v111v11v1v1v1v166666vvvv6v66v66666#6##J###.##nnnnnnnnXnXXDRjYYhYh&j&&jj^^^^^.^.LmmmRmmmRWFYYFWFWWWhjRR5D55Rff_____ff___fffff5f5f5f5fmff__f__ffDffffR_bR_________________c_______f_f_ff________f_fffff_ffff5f555555555))5))55555f5m....r..r.r.^.^.^.r.^..m__mm5mmmmm....^.^^.^mmmmmmm^L.^.^.^^.^^r^^.^.^.^^^.^.^m^.^^.^rr.^.Rr.r.ee", "'''''''''''''''''7'77'7777777744444447444444444444411v111111111v1v1v1v11v111v1v1vv15v1v1v1vv66666vvvv6v6v66666J6J#J#J#####nn#n.nnnXne=&&hYYhh&&l&h&jQL^^^^^.^fmmmmmmmbFFFYYFWWWFYhYFl=fRfff__________fff5ff5f5f5f5fff_____f_ffffRR_f___________R__R___RR_______fffff______fffffR_ffffff5fffDD5555))))))555f555mm...r..^m^...r..RRm..r.mm_mmmmm....^.f.^.^..m.mmm^.^^^^^^^r^^r.^.^^.^^.f.^^r^.^.^r^^.^.Rrrfe^.^rr", "'''v'''''''''''7'7'7vv7'7777777744744444444444441111v11v11v1v1v11v1111v1v1vv11v1v11v1v1v1vv1666666L6v6v6666666#JJJJ####._nn__nnn.rR&YYhY&hYh&jlQjh&Qarn^^^.Lm^.mmmmmmbWWFYFYWWWYYhhFFYY&bff_______ffff5fff5fff5f5f5f___f___f_ff__R____cR_______c______a____f_ff_fff_____ffff5f5ff55fffffff5ff5f55cc))m)555555_m...em^..bf.r^.rr..^.^.^mm5mmm...^..mm^.m^m^m^mLm^m^^.^r^.^^^.^^^^r^^.^^^^^.^.^.^.^.rfr^.^rr^.^.^r", "'''''''''''''''''77'7{77777777474744744111144444411v11111111111vv1v1v1v1v1v1vv1v1vv1v1vvv1v6v66666m66666666^#6#6########nn..nnXRbhhhhYYYhhh&&hjuQhjQbee^.^.^.^mfmmmmmbFFWFYYFWWWhYYhFFWWY&R____ffffffffffff5f5fff5fff___R_____f__R________R__R______a_____f_f____ff_____ff5f55f55D5fffff5555ff5fm_mmmm5555555mmme.r..^.frrf.^..^.r.^...mmmm..^..m.^m.^m.^mmm^mmL^^fL^^^^^.^^^^^.^^r^^.^r^^^^^^^^^^^r^^^.^.^^^r^.", "''*'''''N'''''7'7'777777777774777474441111144444n111v1v11v1v1v11vv1v1vv1vv1vv1vvvv1vvvv1vvvv66666666v666666#6#6##J####nn#nnnXDlhh&h&hhYh&&j&h&&Qj&&ubr5r^.^.f.mmmmmmmQWWFWYYhWWWhhhYhYFWWFY&uR_fbffffRf=5fDfffDf5fff______u__R_f_________________________f_f__________ffRff5fR5555555f5f555mm55f5)mmmm555f5f_mm..r.^.^.^.^.^.^.^.^ff.^^.m.m^.^^m^mm.^mLm^m^^m^Lm^^R^^^^^^^^^^^^^^.^^^^^^.^.^.^.rf^.^^.r^^^^^.^r^", "''v'''''v''7'7'777vk77r77:74774474747441v11v4444111v111v1dd111v11vv1v1vvdvvv1vv1vvvv1vvvvvvv66#66v66666666#6########nn#nnnnDjhhhh&YFWYYYhjulljjjjh&jQr)dr^m^....mmmmmjWWWWYYYYWWFhYY&hhhFWWYhhaRbffffRfRffffDfDffDfff___________________R___________bR_f______________ff5f5555D555555555m5m5mm5f5mm..m55mmm5_5m.^.^.RR.r.^.^.^fr^.^rff.^.^.^.^.^^f^^m^^mLmfmLmLLL^L^^^^^^^^^^^^^^^^.^^.^^^^^^^^^^^^^^^^^^.^^^^r^", "'''''''v''7'777'77{777777477J4747474411111v1v11111v11v1111111v11v1vv1vv5mv1vvvvvvv1vvvvvvvvv66#6666666666#6#J#J#####n#nn.f&FFhhhh&hWFWWYY&lQQxl&YYYYQM9drm^.m^..mmmmmbWWWFFYFYhWYhYFYhhYhWWWWYFWRRfffRffffffffffDfff_________f_f_______RR___________________R____f_ffff5f55f5D5555555m5m))mmmm5555mmmmm5m55_5m.^.r.rmRr^.^^.^^.^.rrfDf^.^^^.^m^LmRm^^^f^^LLLLLLL^LL^LLLLL^L^^^^^f^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^", "'''''v'''7777777k77k7:7::7474747474744L_mL1d#ddvv11161v1v1dd1vdv1vv1vdvvvvvvv1vvdLvvvvvvvvb666#6666666#######^.###nnnnncjYYYYFhYY&FFFWFYjj&lQj&&Yhu_^^9re.......mmm55f_lFhYhYhjFYYYFFYhFYFWWWWWFF&R_ff_fffffDfffffDff___R______________Rc___c__R_____R_R_______ffffff5f55f55D555555)5)))mmm.m.m5555)5555m5mm5m^.r.^^.^.^^.^^.^^.^^.^r^^^^.L^mL^mL^L^mLRmL^^^^LLLLLLL^^^^L^LD^^^^R^^^^^^^^^^^^f^^^^^^^^^^^^^^^^^^", "''''''''7'77777777777:7:7477474746mu&&h&hj&jQb_Lvvvv1161v1v1v1v1v1vvvv1vvvvvvvvvvvvvvvvv6v6v6##66666#6#6#6######n#n#nnRYFYYhYFYYFhhFWWF&l&&j&hhh&fv6#M9r.^.^...mm_m5m566duhhY&&hYYYWFFhFFFWWWWWWWWFx_fffffffffffffffff___R_R__________R_____________bR________fffff5f55DD5D555555)))))mm).m...mmmm555m5m55mm_mr.^^.^.^r^.r^.^.^^r^^fr^r^^^^^Lm^LLm^^^LbL^^LLLLLLLLLLLLLLLLLDLL^^L^^^^^^^^^^^^D^^^^^^^^^^^^^^^^^^", "'''''7'77777777777:7::::474474#5bhYYYYhhhh&&j&jlu_dvvv1611v1v1vvvvv1vvvvvvvvvvvvvvv6vvLLv6vL66##6#6#6##########n#nnnrjYYFWFYYhFFhYhYYY&auj&j&YYYmz666XM.r.....m.m_55c5Xnvd&hYhhFhYFhFYYhFYFWWWWWWYWFYR_fffffffffffff_f___R_RR____cRR________f__f__________f_Rffff5f5D5f55D555555))))mm.m.........mmmmmmmmmmm.^fr.^^.^^.^^^^^^^.^^.DD^r^^^^^^m^mL^LL^^^L^^^^LLLLLLLLLL(LLLLLLLLLL^L^^^^^^^^^^^L^^^^^^^^^LLLLLLLLL", "'''7''777777777::::4:44744744^jhFFYYYhFYYYhhhh&&jQu_L66161vv1vv1v1vvvvvvvvvvvvv6v6vv6v66666L#####6#6#########nnnnnnbhFYFYFWFFYYFFhhh&juaj&&hhFFjJv#pkJe.r.....mma_5_R5Lv66uhYhFYFFYYYFhYhFWWWWWWFYhWYFQf_f_f_ffffffff____R___R______cR_____________R_____ffffff5DD5D5D5555R55555_))m).m..........f....m^....^..^^.^^.^^^.^.^.^^^^^^^^^^^^^L.^^mLm^^^LLm^^LLLLLL5L(((((((((LLLLLLL^LLLD^^^^L^LL^5LLLLLLL^LLLLLLLL", "''7'77'7777:7:J::44#14444444uFhYFFFFYFhFFYYhY&Ql&ujua_66vvvvvvv6L6vvvvvvvv6v66vv6v6v6v6v66666#d######6#fm##nn#nnn.xFFYYFFFFYhFFFFFFhjbbj&&&YYYYh#v#kvp*e.&YFYYhhj55555m6vvjFFhYFFFYWFYYFFYFYFWWWWYYhhFW&=f_ff_f_f_fR______bRb___________R_ff______R____fff_ffff5D5D5555555__5))5))mmm........fe.r.r.rrr.^.^^.^^.^^.^^^.^^^f^^^r^^^^^^^^^L^^Lm^LmL^mLLLLL^LLLLdd5d(d(d(d(((((LLLRLLL^LLLLLLLL^LLLLLLLLLLLLLLL((((", "'7'7'7777:7::7:744444m1111#uWFFWWWFWFFhYFYYYYhj&jQjQQuRLvvv6v6v666666v6v6vv6vv6v6v6v66666666#n###6########nn#nn#.YYYFYFFFWYFhhFFFYWYlaQQ&lYFWhYF)6piiTpmRhYhFFYhhcR5D5Rk#^FWFYFFYFhWFYhWWWYYFWWWWYYYYFFFhR_f_f_f_f__f___R__R_RR__R___________R__R_____f_ffffcf55D555555555D5)5))))mm........e..r.e.^..^.^.^.^.^^.^^^.^^^^^^^^^^^^^^^^^LLfLL^^LmLLmLLLLfLLLLdLd((((((((((d((((((RLLLLLLLLLLLLLLLLLLLLL(((((((((((", "'7'7777777::74:444444m_dv_&YFYYWWFWFWYFFFYYYhhhj&&j&ajabfv6v666666666666L66v66666666666666###n##########nn#nnnnfYFYFYFFFFFYFFhhFYFFY&j&jj&FWWhhFbL]TJp#)&YYhhYFhhj55ffD^djFhhYYYYYhWFYYFWWFYhYYWWYFYYFWFFhu__f_f_f________RRR_R_________f______R______ffffff55D555555555))))5)))mm.m......e.eee.^.fer^.^.^.^^r^.LrfD^^r^^^^^^^^^^^^^L^LLLLL^fmLL^LL^LLRLLLLdmdddddd9RXddd((((((((((LLLLLLLLLLL((((((((((((((((99", "77'77777:7::4744414444114hFFWWWWWWFWFFFFFYFYYhYjjl&j&juub_6LLL6#6###666666v66v6v6v6666666####d########nn#nnnnnRYFFFFFFFFFFhYFYh&&YF&hh&h&&hhYhYYYhcR)ca&hYFYhYhhhYYlRR=lhFF&hFhYhWYFWYhFWWWFhhYhFFFYhYWFWYFuR__fb_f_f___RR_R_R_R________f___R______f_fffff5f5D555555_))))))))))mm)5mm...e..r.r.^.eR.^.^.^r^f^.^^^^^^^^^^^^^^^^^f^^LLLLLLLLLmLLLmLmLmLLLLLddLc()dddddddd(dddd()((((((((((((((((((((95((((((d(dd(d", "77777777::47444411144444aFFWWFWWFWWWFWFWYFYFFY&&&h&Q&&uaaRf6###6######6#6^66666666666666###dd#######n_nnnnnnnuhYYFFFWWFYh&h&FFF&&hh&YFh&&&hhYFhhYYFYYYFYYFFYhFFYYhhjjhFFYhhuYWYYhWWWWWYWWWWWFFYYYYFYYYYWFFFFu___________b_RR_R_R_____fRf__________fffff5f5f5555555)5))c_5))))55)))55mmm..r.r.^.rrr.^.^.^.^.^r^^r^r^^^^^^^^^^^^LLLLLLLL(LL^^LmLLLLLLLLLLLdddddddddddddddddd(dd9((((((((((((((((((((((d(dddddddddd", "777k77:7:744744n1114441RYWWFWWWWWFWWFWWFFFYhFF&&&hh&juabaaRL6#6#########m####666666666#6##dnnn##^m#n#nnnnnnnaFYYFFFFFYh&YYYhhFFY&&jhFYFYhhhhFWFYhYYFFYYYYYFFYhYYh&ja&hhFhhlQhhhYYWWWWFYWWWWWWWYYYYWYFhYYFFFYFuR____________RR_R_R____f_ff_a________fff5f55555555))))))_)mmm)5555555555mmr.rf.r.^.^r^.^r^^^^r^^^RR^^^^^^^^^^^LL^LLL(R(()5LLmLLLLmLLLLLLLdddddddddddddddddddddddR9d(9(d((((((((((d(d(ddd(ddddddddd", "7U76::7:4:44444n1v44444&WWFWFWWWWWWWWWFWFWFYYYh&Yhhh&buaubbRL66#########^##n##.6J6JJ^^##ndnn###n##nnnnnnXnXuFFFFFh&hFF&hYYFF&hhFYj&YhFFYFFYYWFFFhhYFFFFhhhYYFYYYhxba&Yhhh&jhYYFYYFWWWWYWWWWWWWYYYFWFYYYhFFWFYYQR_________RRR_R_RRb__fff__________R_ff555R55555)))))mm))m.)))55555555555mm..r.^.fr.^.^^.^.^^^.^^^^^^^^^^^L^LL^LLL((((d((d(LLL^mLLLLddddddddddddd9XXXXXXdddddddd9_(ddddd9d(ddddddddddddddddddddddX", "77::::4:444n4444v11444^FFWWWWWWWWWWWWFWWFYFFYYYh&&hhQuuQabbb_6#########6#####mRn######mRmn#_###nnnnnnnXnndRFhh&&&h&&hhhYFYYYhj&&&j&&hFYFWFFFYYWWYYFFFFYhYYhhFYY&jaujYhWY&&hhFFFFYYFWWFFWWWWWWWYFFYFWFYYhhFFYhhYQ_________R_R_R_R______ff______fffbfff5f55555)))))m.m.m..9_mm55f5555mmm_mmm^.r.^f^^^^r^^^^^.^^^^^^^^^^D^^LLLLLL(((((((d(ddLLLLLLLLddddddddddXXXXdXXXXdXXXXdXddddddddd(d(ddd(d(d(ddddddddddddXXXXX", "7:::4:444441111v11v411bFWWWWWWWWWWWWWFWWFFFYFhYYh&&&QuluuaRbbL6#####66#6#L6#J#mnnndndndd#f_m#nn#nnnmmnnXdaFhhh&&h&YYhYYYFYhYhhhlQ&hhYFYhFYFYYhFFFhFFFFFYYWYhYF&jaua&h&YhhhYhFWFFWYYWWFFWWWWWWWYFFYYFFFWFYhYYYhFY______R___RR_R_R_R__________ffffff5f5555555))))mm.c_....mm)5555m5m5_cmm5m..^.^.^.r.^^.^^^^^^^^^^RfL^L^LLLLLL((((((ddddddddLLLddddddnddndndndXXXXXXXXXXXXXXXXdXdddddddddddddddddddddddddXXcdXdXdX", ":647444441111v1mv1v11XFFWWWWWWWWWWFWWWWWFFFYYYYhhh&lujjjuaQRbR########6#6##6#JJ##n#n#####m####nnnnnnndd(5&Yh&&&&&&hYYhYYYh&hh&&l;xxxjjQajlullahFWYYFFFFhYW&jljbbau&&&&ljjxlQjjj&&&jjFYYWWWWFYYYFWFYYYYYYFYWWFYFF&___________R__R__________ffff5f55555f555_)))m.m.m.......mmm5555mmmm_mmmm.^ff.^r^^L.^^^f^^^^^D^^^L^LLLLD5LL((((((dddddddddLdLdddndnddndndcdXXXXXXXXXXXXXXXdXXXXXdXdddddd9(ddddddddddddXXddXXXXXX", "4:44444411v1v1v1v1v1v.YWFWWWWWWWWWWWWFWWYWFYFYFYYh&&jujuQQbbRbf########6#6#^###J#^#########nnnndndndmLLm&&&&&YYhh&h&&&hh&hh&&&&css@so$@$s@$@$@sZWWhFYhhhhWc$o$ocujhh&hb@@@@$oooo$oo$@@ChWWWYFWFFFWFYYFWFWWWWWYFFWl____________R_________f_ff55fmf555555555))mmm...........mm55mmmm_mmmmmmm.rrr^r^.^^^r^^^^^^^^LLL^LLLLLLL((((((dddddddddXdddddnddnmndXmXmmnXXXXXXXXXX.cXXXXXXdXXXXXXddddddddddddddXXXXXXXXXXXXXX", "44n44#nd1111v111vvvv1fFFWWWWWWWWWWWWWWWFWYYYFFhh&&h&Q&uQubuRbb_#####6#6##J###J#J.#######n#nnnndnnnddLLmQhYh&hYWFY&hhhhhFYFY&&&&Iossoossssssssss$0FFFYh&hhFcosss=jhFWFYCo0ssssssssssssso0&FWFFFYYFFFYYWWWWWWWFYYWWF=________b____________ffff5f555555555)))_.)........e_e...mm5mmm._m.mmmm..f^.^.^^f^^^^^^^^^LLL^LLLLLLL((((((9dddddddd9_dXdndnddnd_dnmnXnnXnXnXnXnXnXnXXXXXXXXXXdXdXXdXXddddddXdXXX9dXXXXXXXXXXX", "44n11111v1v1d16v1v1vv_FYWWWWWWWWWWWWWFWYFFFFWFj&&hhhuuQQaaabRbRmd#######6##########n#nnnnnnnnXnddddLLLc&hhYY&FFWF&hhYYhFWWh&&&hI000000000000000ss0FYYWYY&h00000Z&hWWWY=000000000000000os0YFYFFhYYYYFYWWWWWWWYFWFFFh_____________ff_ff_ffff55f_f555555_))))9m.......e.efee..mmmmmm.._...mm.^_.^^^^^^^^^^^RDLL^^LLLLLL((((5(((dd(ddddXXXXXXXXdndnndnXmmnXnXXnXnnnnnnnXXX_XXXXXXXXXXXXMdXXXXX9XXXXXXdX_XXMXXXXXXnXi", "44111111mv1161v161vv1cYYWWWWWWWWWWWWFWWWFFYFFh&h&h&h&jQQQbuRbbbd######6###########n#nnnnnnnXndddnddLLf&&hhh&FFWFY&&&YYhYFFh&h&&I00000I0c0c0I00000@lYYFWFhY0000oj&hYFWWI0000II==ICC==0000scFWFFhYYYFYYWWWWWWWWYFWWWW&_RR____f_fffffffff5f55f5555555555_))).m......e.e.e.e.e.mm5mam..f.mmm....^..^r^^^R^^^LLLL5LLLLL(((((((d(ddd99ddXdXXXXXXnmdnnXnXnnn.nXnnXnnnnXnXnnniMiXnXXXXXXXX9MXXXXXXXXdXdXXXXXXXXXXXiXiXnn", "#44111vdn1vv1v16161vvRFFWWWWWWWWWWWWWWWWYFFYF&h&&&&hhuulaaabRbRm###6##########._#nnnnnnnnndndddXdLLLL&&&hh&YWFFhhhhhhhhhYFhhhhl00000jjj&j&hYYj00000jhh&&YY00000ljhhhWFc0000jFFhYFWWWj0000oWWWWYYFYYFFFWWWFWWWFFFFFFWa___ffffffffff55f55f_f555555555)))).)........e.reeer..e.mmmmm.....m.^.^^.^^.L^^^^^^LL^LL(L((((((((((d(ddddddXXXXXXXXnXnmnXnnXnnnnnXnnXninnnnniinnnnnnXXnXXXXXXXXXXXXXXXXMXXX_XXXXXXiXinnnnMi", "#44111111v1v1vvvv1v1vRYFFFWWWWWWWWFFFFFWFYFFF&h&&YhhhubQuabcbcb_L6##########nn##nnnnnnXnXXXddLdLLLLLR&hY&&&&hYhYYYYhYhhhYFhhjjZ00000CZjh&h&YFF00000ljl&h&l0000oZjYhhYYZ0000jYFFFFWWWW0000oWWWFYYFFFYWWWWFFFYFYFYYFWW&_ff_ffffffff5ff55f_R55555555))))).m......e.r.r.r.^.r^.mmmmm......mmm^.m^.^^^^D^^^LLLL(5(((((((((d(ddddd9ddX9XXXXXnXXXnnnnXnmXnnXnnnnnnnnnnnnenniXnXnniXXnXnXXXXXXXXXXXXXXXXXXXXiiXnnnniXnni", "444411v1v1v161611v16vfhWFWFWWWWWWWFFFWFFFYhFFY&hhhjhjlbbuabRbcbRn########n.#n#nnnnnnnXXdddLLLLLL_^Lmu&hYYh&hhhhhYhh&hYh&YFY&j&j00000cCZ&h&YFFC00000CCj&hjl00000ShY&&jYC0000&FFFYFWWW&00000WWWYYFFYFYFWWWWYWFFYWFYFFFWbfffffffffmf5f55f55R5_D55)))))m.).._cRm..e.r.^.^.r^..b.mmm.m.^m..^mmm^Rm^^^^^^^LLLLLL(5(((((((ddddd9dddddddXXXXXXXnXn.nXnnm.#nnnnnnnnnnnnnnnnnnnn_iinnnnXXXXnXnXXXXXXXXXXXiXiXinniinXinnnnn", "7441111v1v16161v61v1v#&FFFFFFFFFWWFWWWYYFFYhhYY&j&&h&uuRbbbbbRbR########n#_nnnnnnX.XXdddLLLLLLLLRmLbQ&&h&h&&hhh&lhhFY&&j&hYjllj0000000c0II=c000000cCx&&&Sj0000o&&Y&jhY=0000I=cC==Cj=00000=WWWYhFFFWFWWWWFFYFWWYFYYYWFYffffR_f5ff5f5f55555555))))))m9m._..._.e.r.r.r.^.^.^.^mm..m.m^.^..m^mm_^.^^^RLLLLLL((9R((((d(d(dddddddXdddXXXXXXnXnXnXnnnn#nnnnnnnnnnnnnnnnninnnnninniXninXiXXXnMiXiiXiXiXiXnniXninnnnnnnnn", "4:441v1v1v1616v1v11v1vjYYYFWFFWYYFFWFFYFYYYYhYF&j&&jQu&ubaRbRbc_######n#nnnnnnnXXddXd(LLLLLL^LLLLL_aj&hh&&&h&&&alh&&hh&jjhlalj&00000o0o0000o000000jjj&lxS&00000&h&hYhhc000000000000o00000YWWWFYFFFFWFWWWFYhFFWFFFYYYWWcfffffffmf555_R5555)5)))))m.)........e..e.^.^rrrr^r^m.mf_m...^.^^L.^mmffL^LDL^LL(((((d(d(ddddddddddXXXXdXXXXXnXnnninnnnnnnnnnnnnnn#########nniiinnniiiinnnnnnnn_innnnnnnniiininnnnnniiiiin", ":44111111vvvvv161vv1vdbYFWYFFFFWYFFYYYFFYYYYhhFjj&au&Qjuacbcbc=5#####n#nnnnninXd(d(LL5LLLL^^LLLLL^RQ&&hhhhh&&&juj&QjjjQauQaajjl00000000000000000IjjjjljZh&00000YhhFWFY=00000000000000000&WWWWYFWFFFFYWWWYhYFFWWFFWFYWWjffffff5f55f5D5555)5))))))_).......e...^.r.R^.^.^.^.^.mmmmm^^.^^^.Lm^^.^L^LLL(5(((((d(ddddddddddXdXXXXXXXXXnXnnnXnnnnnnXXnnnnn#n#n#nnnnnnni##n#inne_nnnniXniXniMiiiXii_Mninnnnnnn#p_#n#n#n", "4444411v1v1v11v11v1dvvXhYYFFYFYFFWWYFYYYYYYY&hYjj&ujjjjjaabRbcb^.^###nnnnnninXXdLLL(LLLLLLLLLLLLLmbuul&h&&h&&lujull&&jbaaljQ&jC0000000000000000C&h&ljlhYFj00000FYFWWWW=00000000000000IZFYYWWWWWFFYYYFFWWWYhYWFWWWFWFWFY_f5_f55f555555555)))))).)..........ee.e.^.r.^r^.^^^mm.m.m..^^.^^.^m^m^^^LLLL(9(((d(ddddddddddX9XdXXXXXXXnXnnnXinnnnnXddXXXnnn#in##########ne#nniniiinniiiiiiiiiinnnnniinnnni_p#in#i#i#n#n", "4444411nv1v1111v1v1dvzvChYYYhFYYYYYFYYYYhhhhhhhjQ&jjjjQauRbcbcc^n##nn#nnninnXd(LLdddddLLLLLLLLdLdRbajhhYYY&uualjQ&hYY&uauu&j&S=00000CZ=000000YYhhY&jFFFWYh00000FFFWWWWC0000CZ&ZCjZZZFFWYFFWFWYWYYYFYFFWWWYYYFWFFWWFWWFhbRfR5f55f5fDDD555))))m.).......e.ee..r.^.^rr^.r^r^.^m^.m^m^m^.^m^mm^m^^^LLL((((d(dddddddddXXXX9ddXXXXXiXnnnninnnnnXXdddddXnnn##############i#ne#iiinnnnnennnnnnnnnnii_in#enpi#i#pi###i#i#", "44444411111161v1v1vvvvvn&&hhFYYFYFhYYYYY&Y&hhYhxQjljjullabRbRbRdnnnn#nnnnnXXddLLdddddddLLLLLdLLL5bcbjh&h&&aabj&&hYWFWFjQujhh&xc00000&hYc000o0SFhYFhhWWWFYF00000WWWFWFW00000&YF&&hh&FWWYhYhhhhWFWFYWFWYWWWWYYYFWWFFWWFFhQf55ff5f_R5f5ffD555)))m..9......e..rr.^.rr.^.^^.^^..mm^.^m^m^m^m^mL^L^^LLL(((((ddddddddXXXXdXdddddXXXnnninXnnnnnnndddddddXXnn####i##i##i###e#nn_pniii_einnnnniiii#n##p##i##_rp###########", "4444411111v1111v1v1v1vv(ZhhFYYYYFFFhhhYYhh&hF&&&jlQa&ulabRbcbc_nXnnnnnnXnXnXdLLLdddd(ddLLdLLLLLLfbRbj&&&jucRa&&hFWFWFFhhhYFYjZI00000&jYFI000soZYhFYhYWFWFh00000WWFFFWWC0000hYhj&j&hWWWWYFYFYYFYWWFWWFFFWWWFYFWWFWYYFhYhhR5f55fffffffff5f55555)m......e.e.^..rr.^.^r^^f^^^.^m^m^^^^m^mm^m^^^^^^LLL((((dd9dddd9XXXdXXddddddddXniMnnnnnninnXdddddddXXnn####p##p##########pi#n##Iiininn#n#n#ni#i#i###prp###eepip#p##", "44m411111v41v1v1616vvvvv{jhhhhhYYYhF&hh&hh&hjj&jj&QQluabRbcbRbdnXnn_nnnXXXXd(LLdd(ddddLdLLdLLLLLfRbajj&jQbbu&&hFWFWFFFFFFFYYj;c00000hhhhh0000o0lhhFFYWWWFY00000WWWFFWW00000hY&ljjhhWWWWWFWY&&YhWWFWWWYYFWWWFFFFWFYYhYFYFbfffffff5_5555f5f5R_f5)m..e.e.e.r.^er.^.^rr^.^^r.^m.^^.^^m^m^^mLL^LRLLL(((dddddddXXX9XXXXXddddd(((dXXnMnnnnnn#nXdddddXdddnn#####rr###p########i#een#nnnXXXnn#n#ir######ip#p#p#p###p#####", "11n1111v14v1v1vv161vvvvvv*&&&&hh&hhh&h&h&h&hhQlljhbQabbbcbcc=f#nnnnnnXXXXXXdLLdddddd((dLdLLLLLL^_cbujuuQubaljhhFFFFWFFFFWWWYucI00000hhhh&&0000s@ZYFYFFWWWj00000FWWWFFWC0000hY&Zj&YYWWWWWF&&&&hYWWWWWWWYFFWWFFFWFFYhhYFYF&Rfff5f55555555f5555555mm...r.er.r_^.^.^r^.^^r^.^mmLm^L^^^^mff5^^^L5LL(((d(dddddXXXXXXXXXXXddd(d(d(dXXnnnnXXXXXdXXXdndXXdnn###p####p####pi##i###i#nnn.XXXXnn###pfni###pppppppppppppppprr", "111111v41v1v1v1vvvvvvv6vvv9&&&hhh&&h&&&hh&&&&bjj&jbbbbRbRbRbRXnnnnXXXXXXXXdLLLLddd((((LLLLL5^^^RRbbuQuQjuaj&&YFFFFWFFFFFYFFhacc0000IhhhhYhj0000@@hFhWWWWFh00000YWWFWFWI0000&&ljl&hYWWWWFhjj&hYYWWWWWWWFFFYFYYhYh&hYYYYYYWfff5f555)))m)5mm5m5m5555mm.ee.^effrrr^rr.^.f.^mm^^^^L^^^^m^^^^^LLLLLL((ddddddXXXXMXXXXXXdd)d(d(dddddX_inXdXddddndXnddndXXn##pppppppp#p##p##p#####nnXXXXXnncen#pi#fppppppppppppppppppppp", "1z11v111v1v1v1vv1vvvvvvv6kJ0&j&h&&&&hjjh&&&j&j&xxbaabRbcbRbcmnnnXnXiXXXXXX(LLL(dd((((((LLLL^^^^Rbabu&h&jujQhFFFFFFFWFFFFYFFj;Ic0000IhhYh&&jj0000sohYWWWFh&00000hFWWFFWC0000ZSCjhFYFWWWFh&&lYFhYWWWWWWWWYFYhWhj&&hFFFYFFYYbff5)5)))).)..m...mm55mm5mm..^.rer^.^.^.^..^.m^m^m^^^^^^5Lm^.^^^LL(5((((dddXXXXXXXXXXXnXdddLddXXndddd.ddddXXXXmdddnnddndnn#pppppppppppr##########neXXXXnXnnnnn##iipJJJJJJJJJJJJJJJJJJJJ", "z1z11v1v1v1vvvvvvvvvv6v666669ljj&&&j&&&&jZ&Z&Qjaxuubbccccbcmnn.nnX.MXXXXdd(^5L(((((((LLL^^^^^^Dbxauj&Y&QbauYWFFWFFFFFFFYYYYQcc=0000IhY&&jj&jC0000olYWWFh&&0000=YYWWFFF=0000Z=lhYWWFWWWhjl&&WWYYYWWWWWWWFYY&&QjhhhYFFFYYYhR_5_5))cm.9......_..m.mmmmmm.rrrrre^r^r^mf^fm^mL^^L^LLLL^^mL^^^L^LL5(((dddXdXXXXXXXdXXX.Xd(ddnnnnnXXXdXXXnnnnXXXXdXmnddXmnn#pppJppppppppp#p#p####nXdXdnXnnXdXnnnn##JpJJJJJJJ{{JpJpJpJpJ", "z1v1v1v1v1vv1v1vvvv6vv6v6vk6kD;ZjS&hjjjlj&jQljabac=bRbRbccmnnXnXXXXXXXddddL^5L(((((LLLL^^^^^^r^luu&hhh&ubauYFFFFFFFFFYYFYY&=RClZj&j&YYhhj&&&&jjjZS&YFYh&&YZj&j&YhYWWYW&hZjC=lYYFWWWWWWjZjhWWWYhFFWWWWWWYh&&QlYFYhFYWFYYYhxff5)))_mm.......e....mmm5mm...^.rr^.^^m^fffm^^^^^L^L^LLLL^Lm^^^^^LL(dddXXXXXXXiXnXd.XXdddXXnnnnnnn#nXnnnnn##nnnndnndnndnXXn#JJrJJJppppiRpppprp##nXXXXXnXXXnnn.nn#pJJJJJJJJJJJJJJJJJJJJ", "zzzv1vvv1vv16vvvvvvv6v666666k**blj&llZjjljlljxuauaccbcbRRm#XnXXXXXdddddd(LDDL((((((LL^^^^^^^r^c&&&&&&h&ubQjhFFFFFFFFYFYYYYQRcC&YFFFhFFY&Y&&YYYFYYhhhhhjYFWFhhYYFhhYWWWFhYY&jhFFFWWWWWF=jhWWWWFYYYFWWWWWY&&hjhWFYYYYWYYYFhj55m).).9........ee....mmmmm.^.^.^^r^^.^.r.^^^^L^LLLLLLLLL.L^^^^L^^L(ddXXdXXXiXM_idddd)dddnn#n#n#####n########nnnnnnnndnXnXn##prJJJJJJpJppppprp#nX._XnXXmnnrnneXnnJJJ6JJJJJJJJDJJJJJJJJ", "v1v1v1v1vvvvvvvvvvv6v6v6k66666JJ9;xxlCuSSxax;abaccbcccc_mnnXXXXXdXddddd(L^^LL(((LLL^^^^^^^Dr^.R&hhYhh&hQQ&j&FFFFFFFFYFFFYhuRSZhYYFYYYFY&hhYYhhYYY&hj&&&FFWWWFFYFFYYWWWYYWh&YFYYYWWWWFZlYWWWWWFYFYYWWFFh&&hYhhWWFYYYFYhYhYh55)m9.mmm.....ee.e....mmmm...^..^r^^^.^m^m^.^LLLLLLLLLLL5LLLm^^^LL((ddXXXXXXiiiindd(ddXXn#n#n######################n#nnnXnnn#pJJJpJpJJJpJJpppp#nnXXnnnnn#n#nn#nn##JJJJ##pJ66J]J666666*", "zvzvvvvvvddvvvv6v6666D66k66JkJ6{##{I;;;x=auabccc=cccb_LnnXXXXXddddddd((L^r^^L(LLL*^^^^^DD{r^r^a&&YFF&h&jhh&hhFFFFFFFFFYFY&bS&jhYFYYWYFFYhYYFFFYYh&jjhhhWWFWWWFYFWYhFWFFWWhYWYWFYFWWWhlhWWWWWWWFhhYFW&QjhYYFYYWFWWYYFYYYFFYfm5)m))....e.e..r.e......m.^..^r^.^r^.^m^.L^LLLLL((()_((5LLLLL^L^^L(dddd9XiiinnnXXdXXXn##############ppppppJJ#####^###nnd#####JJJJJJJpJJJJJJJ##nnnnnXXn########nn##Jp###rJJ6666J]6J]6J", "zvv1vXvvvvdvvvvvL66JJrJJJJ]6J6J#nnnn^RRb=b==cc=c=RR5dnXnXXXXXdXdddd(LL^^^.^^LLL*L^^^^^^^r^rr^mj&hhYYh&&jhYh&hYFFFFWFFFFYh&bjj&FYFYYFWYFYYWYWWWWWhZS&Y&FWWWWWWWhFFFYYWWWFFFWWYFYYWWWh&hWWWWWWWWFYFYWhuahWFYFFFYWWWFFFYYhFFY5c55))m...e_feefr.r.re^.^.....m^.^.^.^.^m^^LLL(((((d(((d(dLLLLL^LLLL((dddXXXnii_Xdddnnn########p#pppppppJJJ#JJJJ6J^JJ#nn#nJ#ppJJJJJJJJJJp{JpJ##nnnnnnnn#######r#n######rr###JJJ666k666", "vvvvvvvv66vv6v6666######J{DJJJ##nnnnXXnnLm.f__mmdXXnXnXXXXXddddddd(L5^^r^^^^L^L^^^^^^^r^rrrr.R&YYhYFYY&j&hhh&hYFWFWFFFFh&lujjhYYFYYWWhFYhFWWWWWYjZj&YYWWWWWWWWYFWWFYWWWFWWWWYYYYWWh&hWWWWWWWWWWYWF&QbjWWFYWWFFYWWWWYFYYYhY555555)..e.ee.eerr^rrrrr.^...^m.ff^.^^^mL^LLL((d(d(dddddd(dmLdddLLLLLL(dddX.XXXXXXdnX###p#ppppppppppJJJJJpJJJJJJJJJJJ##d###JJJJJJJJJJJJJJJJ###nnnnnn###JJ6JJJJJJ##n##nn##rr##JJ66666k6", "vvvvvvv6666666666###nnen##JJJp#nnnnXXXnnnXddX_.nnnnXnXnXXXXddd d(d(L^^^f^^^L^^^^^^^^{r^r^rrf^^hFFYFFFYh&FFjf#f^R5Rf_v))eDLXJ900I0000I0I00000c0IPoo0 0IIcI0=0c0000II0IcIc0Ic0sIIocIIIc cR_=;c=IDf.(nX(D_=5__D_aFWWWWWYYhYYY_55m555m..e.e..r.^.^.^^^^^.^^..^.^.^m^m^^^LLd(d(dddddddddddLddddXXdddd(dddddXdXXXXXn#cpppppppppJJJJJJpJJJJJJJJJJ^JJJ6##nn#f####JJJJJpJpJJp#####nnnn###JJ66666666JJJJ#J#######JJJJJJJJJ", "vvvvvv6v6666########n#nn#n#rDinnnnXXdnnnXXdXXdnnnXnXXXXXXXdddddd(((L^ff^^^^^^^=^^^{^r^rrer.f..&hFFFhYYh&YW&77'''''''''''''''''''778788888787787''''''''''77878788777888888777'7''''''''''''''''''''''''''''''5YWWWWWWYYhYh5mmmmmm)m.eb..r.^r^^^r^f^^^^.L^m^.^mL^^^^LL(ddddddddddXdXdXXddXnXXXnXXddddXXXnXnnnn#J^JJJJJJJJJJpJJJJJJJJJJJJJJJJ6J6J6#n#n.#nnn#####n######nn#nnb###J6J666v6v6v666666JJ###############", "vvvv666666###6#######nnnnnnnennnXnXdXnnnnXddXXdXXXnXnXXXdddd d((d(LL^^^R^^L^^^D^{{rrrrrrrrrrD.YhYFF&&hllYFjbuxx=aac=bZbZSCbaSa;;C=C=SxxSxZSCZSZQQullllSljlZSSSSuSZS=lSSbSZxljjulQllQuQaQujQQaQQalQQjuQcQQlujlfYWWWWWWWYYYY_...e..mm..r^..^.^r^^^^D^^^^L^^^Lm^^^Lm^L((ddddddddXdXdXXXdXXnXXnXnnnnnnnnnnn#n#n##JJJJJJJ{JJJJJJJJJJJJJ]J666666J6J6J6##nnnnn#nnnrnnnnnnnnnnnnn####JJ666v6k6kvkvvv6666J#######JJJJ6JJJ", "666666J####6#666#J####nnXXXnnenXndXdXXXnXXd(dddddXXXXXXdddddd(d(((L^^r.^^^^^^^^{r^r^rf^.r.r.e.&&&YY&&jua&FluuaaabaaSxQZu;bbaS;aSxaxSuxlul;xZlSlulSSQQjjZllSxxuuZZuuSjlSSujlljllQQjlZQljujljuQQQllQQujjljjlljjIYYWWWWWWWWYYfrre...mm.^f.r^.^^^^^^^^^^^^^^^^^^^^L^LLLddddddddXXXXXXXXXXXXXnXnnnnnn######J###JJJJJJJJJJJJJJJJJJJ]J66J6J6JJJ]666J6J6J6##^nn#n#n#n#nnn#########6666DLD 6vvvvvvkvkvv66J6J6JJJ6JJJ66666", "66J6J####J#6666J66J6J#nnnnXXXXXXXXddddXXXXddd(d(mdddXdddd d(d( (((^^^.^^^^^^^{r^rr^rrrrrrrr.rm&&hh&h&laajhRbbbbaQ;QSuQZQb;a;;xxxaaxxSalZxxZllaxZQuSujQjlZlSlSSuuuSZjjjQljQQlQQQlljQQlQujlQjuQQllljjjjjjjjjlQQ)YWWWWWWWWWWFD.r......e.^rrr^^^^^^^^xLLL^Lf^^LLLL^5LLddddddXXXXXXXXXXXXiXnXnnnnnin###ppJJJJJJJJJJ6J666J6J66J*666J6J6J6J6**666J66666666Jr#Jr#######J###J#J#JJJ^6v6Lvkvvkvv6vvv(vvvv6v6666666L66vvvvv", "JJ#####J6666J6#6JJ#JJ#rrnXXXXnXXXXdddm.XiXXdd((L((ddd(dddddd((((((^r.^^^^^^^{^r^r^.^r.r.r..r..hhYYh&&&bbj&RbbbauaxxauZZS;bQbaxxxaaxxSaZlxaZxSxxlxuuQlxSxxSSxSxSSuSujljljllljljjjuZQQQjjjQjjjQQQQQQjljjjQjlllQ9FFWWWWWWWWWW_rr.^.rf_.^r^^^^^^^^^^LLLLLLL5LLLLLLLLLddddXXXXXXXXXXXiXiXXiiininin####pJJJJJJJ{J6J6{6J]6J6]6J**J6J6J6J6]6666666kR]6666J66666J6JJJJJ6J6666JJ^666D66vk6vvvvvvvvvvvvvvvvvvv6v66v6vvvvvvv", "##n###JJJ6J6JJ6#JJJp#pr#nnnXdddddddLddXXXXXXXdd(LLLL((( d( (d(((LL^^^.^^^^^^r^rrre^.rrr.r.r..fYhh&h&&&abQ&RbbbuxxSaxuZxab;;bxaxxxxaaxual;lluuaauuuljljuSuxxuSSulZuujjjlluululQuZjZjjjjlluQjjQlQlljjjjuQQllllQ9YFWWWWWWWWWW_r^...r.f..^^^^^^^^LLLL(((((L(LLLd(dLLdddXXXXXXXXiXiXiXiiiiiinni#n#p#ppJJJJJJJ66JD**{666666666666J6]6]666***kJk6k66666666666666R6666666k6666*6D66k6vv66vvvvvvvvvvvvvvvdvvvvvvvvvv%R vv", "r####JJJ6^^J#J#J#p#pp#Di#nnnXd((((d(dddXXXXXdd((LL^^L^LL(d((((9DL^r.^R^^^^r{rr^rrrerr.r.r...ebhY&&h&&&u_u&RQauuaSauuSQuba;baxxxxxaa;lQSuauxuuxaSuQlQjllljjSxQxSjuuujjjQZSZuuZuuujljQQQjjlljjlQQuQjjjQljjljQlQ9YWFWWWWWWWWWRr.^.^.^.^r^^^^^^LLLL(L((((((((dmdddLddXXXXXXXiXiXiMiiiiiinnnii#i###ppJJJJJ66J6Jk666666666666J6J66666666**66666666k6k6k6k6k6k*k6k6k6kv6v6 DUv(Dk6v6vkvv6vvvvvvvv vvvvvNvvvvvvvNvv9Nvvv", "nn###JJJpppJpJpppppiperiiiiinnXXXX(d(dddXdddddd((LLL^^^^5LLLL^^^^^.^r^^^{^^^r^e^.^.r.r.e.e.._c&&&&&hYY&RuhcuuabaQxaxxQxbu;axSxxxa;;lauuaa;xuxxxlululluSluxuQxuuSSuujZllSuuuZujQljjjljjljllljjjjljjjjllljlllQQ9YYFWWWWWWWWWRRfm^..^..^^^^^LLLL((((((d(dd(dddddd(dXXXXXXiXiiiiiiiinnniiiii##p#n#JJJJ6JkJJJJJ666666kkk6*k6k6k6]666666666k6k6k6k6k6k6k6k66*(*6k6v6v6kkv6vvkvk66vvvvvk9vv9vAvAdcvAAvNvvNvNvNvvAv vAvA", "nnn##pJJppppppp##i##ireiiiiiiiiXXXXdddXddXMddd((dd(((L^^5*L^^^Dr.r^^^^r^r^rrrrr.rr.re.r......c&&&&&hFF&u&&RabaxaQubxQu;aub;xxxxuaalZQaaaaaxSuSxlZluulluxSxSSuZSuuSulZuSuSuuujQllujlQQQQuQQQllQjjjujjQljllllll9YYYYWWWWWWWWme^.^.^.^^.L^LLL((((((((d(ddddddddd(dXXXXiXiiiiiiinnniiii#nnXninnnnn#JJ6JJ#####JJk6JJJJJJJ666666666k6kk6k66666k6k6kRk6k6k6kkv6 6vkkvkvvvkvkvvvv6vvvvvvvv vAvAAvAdAdAAvAvAvAvAvAvAAvAvA", "Xnnn#pDpppp#pipi#riiiiiiiiiiXXMXT_XXddd ddd (99d(((((L^r^^^^^r^.r^r^^^^r^rrrrrrrr.re.e.e....mb&&&&h&hYj&hYbuabaxuuaxuxCub;xxxuxaauull;axZaxuuxxxljuujjxSuuuQxuuuQuSuZQuuQQZllQjjQuuuuuuuQjljjljuQQjljQlljljllDFFYYWWWWWWWWR.^^^^^m^.^^L((((((((( ddddd(ddXdXdXXXiXiiiiiinniiiin####nXdXdXXXn#n#JJ6J#######J6J6JJJJJ{6k6k6k6k6*66666k6k6666v6666v6v6v6v6v6kvv6vvvkvvvvvvvvvvvvvvAvzvAvAvAATXAAAAAAAAzvzvAAzvAAAAA", "Xnnp#ppipipi#iiiiiiiiiiiiXXXXXXXXdX dddd(d(d(((d9(((((^^r^r^.r.^^r^^DD{rr^rrr.r.r.e.e....M..mQ&&&YFYFY&&YY_uaaau;Z;Sxbbaa;aaxxaa;lu;Qa;QlluaaaxalZxjuxuSSuuuuSuuuuZQuuQuQQuujjljuZuQuZuQljQjlQQllQQQjQQQlQlll9FYYWWWWWWWWFDLL^^^^^^^R^L(((((ddddddd ddXdXXXXXXXiiiiinniii######i#iinXXXXXnnXnn#r#J###JJJJ##JJJJJJ#r^J66k66666*k6k6k66JJJJJ6J6666666kvkkvvvkvvvvvvvvvvvvvvvvvvNvvAvzAAAAAzzAzzzzzvzzvzzAAvzAAvz9z", "enipiDipiiiiiiiiiiiiiiXXXMXXXXXdd ddd (d d((( (((((I((L^^.^rr^^r^^^r^^r^rre^.rrreee.e.....9m5Rh&&&YYYhhYhh_bab;aSaua;b;Cbaaa;ZZQZxaa;;ZlQQuulQuljuuuxuuuSuuxuxuuuuuuZQQQQQQuuQQlZuuljjjjljjjjQuQQjlllllluQQQQcWWWWWWWWWWWWRLLLLLL^^^^((((d( (d(dddddXdXXXXXXXXinecniee##rrei#i#nXnXXXnXnnnne.nn#####J666J###JJ6JJ##JJ6J6k6k6k66k66*66JJJ#JJJJJJJ66666vvvkvvvvvvvvvvvvvvvvvv9AvAAAAzvzvzzzzzzzzzzzzzzzzzzzzzzzzzz", "XnpiiTiiiiiiiieiiieXXXTXXMX Xd ddd9I(d(((((((((*(*(LL*LL^L^r^.^^^rr^rRDrrrr.re.....e..M.9.)))uh&&hYhYYFhhh_bbxuxxQab;bbb;;;;Q;;CS;;aaZxaxaSaauujQljSuuuxuuxuSSSuuZuZuQuQQQlllQulljjjjjlQjjjljuQlQujlQlljj&jjjeWWWWWWWWWWWWbL(((LL(LLL(dd(ddddd dddXdXXXXXXTXiiiin#i##iri###p#iinXXXnnnnn######nnnn#J66666JJ##JJJJ#JJJJJJ66J6k6k6kk66JJ#J#J6J6JJJJJJ6*6kvvRvv vvvv%vvvNvNvNvA9AvAAzzzzzzzzzzzzzzzzzzzzzzzXzzzzzzz", "iiiiiiiiiTiiieeTXXXTXXXdXMM_ d(ddd((((((9( ((*((LL*L*L^*^^^^^^^r^r^rrrrerr.rr.eeee......)9))5ch&&hFYYYh&h&RaubaSSab;bbb;;abxux;uZu;xaal;xSuSxxulSjxuuSSuxSxuQQjZQuuQuuQlllllQujQjjjjlQQlQlllQQuQlQjjj&ljjjjllRWWWWWWWWWWWW=(d(dd(_d(dd(dddddddXdXdXXXTXXiXiiiinii#i#ipr##i##nnXXXnn#######pJJ##rr#{J66v6k666J##{{#JrJJJJJJJ666kk6v66{JJJJ666666JJ6JJJ66vv%vv(vvvvvvvAvvvAvAAXAAzzzzzzzzzzz1z1z1z1z11zztztztzzzzz", "iiTiiTiiiXTXiXXXXXXXdTdX dd ddd ((d(( (*(*L*LL*L*L**^**5^^^^^r^rr^rrrrre.re.e.e.....9.99))95cuhhh&h&hh&hY&Raxxbbb;;bbauubaSuQluSlxaxxaaaxSuuSxQQlSxxxuuQllQjjljSSQuuQQuQQQQuQQljjjjljjQQlQQuQQuQQQQQQlljjjjjlrWWWWWWWWWWWWfdd(ddddddddd ddddddMdXXXXdXXTXiiiiii##ip#p#nnnnnnXnn#n#ppJ##pJJJ6J6JJ6J6*k6kvkv66JJJJJ#JJJJJJJ{J66kv6vk666JJJJ66666J6J66666JJ6v6v9vvNvAAvvAAAvzAAAzzzXzzz1z11z1z1111z1tzt1t1tttzzzzzz", "iiiiiiXiXXXTXXXXXX Xdd d(ddd( (( (( (L((*LLLL***L*^^*^*D*D{{r^r^rrrrrr.ree.e.e....M..b9)9)555u&hhh&hhYYFhjRbbabab;bbxu;xZZQuQZxuQaxaaaaxSuuuSxljlZaSlxxluQlljljxuuuuQuQuQQQQlQZujjljjlQljllQQQQQQulllQjjljjlQDWWWWWWWWWWWW_dddd dddddddXXdTXXMXXXTXXMXXiiiiiii#i#p#pnnXn.XXXXn#ppJJJJp#JJJJ6k6k6*6k6vkv6v6v6JJ#JJJ6JJJJJ66666kvkvkvk6666J6666J6J6666v6v666666vvvvvvvzvAAAAzzzzzzztz1z1zt111-1t1--1-111I11iz1zvzv", "iiTXiXXMIeXdd X X dd ddd ( (((((((*LL*L*L*9*^*^^^*^*^^{^{^{^rrrrrrrr.ree.e.e...M..99)m)_55555uhh&hYYYYYh&Qcbbbbb;bbauaSQZu;uC;lQuuxaS;axSuuuuxxujuajQlSljjljjlZuSuSQQQlQQQuQQQQQQlZjjluuQlQQQQQQQQQQuQQjjjllQIFFWWWWWWWWWWRcdXdXX XXXXXXXXXdXMXXXXXiXeiiiiii##ipppiinXnXnnn#n#JJJJJJJJJJJ6k66*66 kvkv6kvvk666JJJ666JJ6JJJ6k6kv6kvvvvvv666D6666J6^6vvvvdvvv666v6vvvAAAAAzzzzzzzz1t1tt11-1--111111111--11--TzzzvXv", "iXXXXTXXXdXXd(ddddddd (d((((((((*(L*9L**L*D^*^*^{{{{{{{{{{rrrrrrrD.eeee.e....M.9.9)9)95959D55&h&hhhYYYh&&QbaaSxxaabuauabCaa;;SSSu;x;xaaxxuuuuuxxaSQlljQjQljllljuuQQuullQQlllQlQQllujjlQuQuQQQuuQljjlQljjjQjuj6WYFWWWFWWWWW9XXXXXXXXXXXTXTXTXiXXTXXiXieiiiii#pippppnnXnn####p#JpJJJ]R]6JJJJk6k6k6k66vk6vkvv66^#JJJ66666JJ666vkvvvkvkvkvv66vk666666vvNvvNvvvvvv6v6vvvvvzzzzzzzz1tti1-1---114---------1111111zzvzvz", "XXTXX XTIX d9(( ((( ((d (9( L*(*(*L*IRL*^**^{{{{{^r{{^r^rrrrrrreeeee..e...M..9.99)9))595D5D5DYYh&&&&&&&&&abuxxxxbQx;SC;a;Ca;;uuulxaZaaaaSuuuuSxxZlQlllljlQxxSuSQlllQQQuQQlllllQllQQjjljjjjQuljjjljjjlQjjjlljlDWYWFFYFWFFWWbXXXTXXXTXiiXiiiiiXiiiiXiiiiiiXiii#pp#nnnnXn#pJJJJJJ]J]JJ6J6k6Jk666k6kvkvk(v66vk66JJJJ66J6J66666kvvkvkvvvvvvvvv66666666vvvAAvAIvvvvv6vv(vvzzzzzzz1ttt1---1111--44444444444g----1zzzzzz", "TXdTdXddddd d(((( ((((((*_IL*(*L***^^^*^{{{{{{{{{r^rrrrrrrrrreeeeee.ee..M..9)99)))95595D9D_D5WF&h&&&&&h&&abaxa;bbauub;bbC;alQQllQ;l;aa;xSxxxxSxSZQZljZulxxSuuuQuQQQulQlQllluujjuQQQZuuujjljujllQljjjjjQjjjjQlcWFWYhjhFFFFWcXXiXiiiiiieiiiiiiiiiXiiXXddd9ddXnnninXXXnXn#pJJJJ]JJJkD*k6]6kk*k6k66k6vkvvkvk666JJJ6JJJ666666k6vvkvvvvvvvvvvvvv666v6vvAAAAvAzvzAzvvvvvvvzvzzzz1ttt1--i14-1g444g4g4g4g4g4g4414111z1vzz", "XdTd d d ddM( ((((( ( L(*(*L**L*^*^*^{{{{^{r{^rrrrrrrrrrrreeee.e.e....M.M9)55)55D5DDDD5DDDDDDFWY&h&h&&&&&aaaxabauQuZZZQZb;bZuuSQSQaaaaxxaSxxxaxuxuuQluulluuSlQSuuuQujljuQujjlQujjjQlljjQljluQlljjQllQjjjjjlQQRWWY&jhhYYYYYRXiiiiiiiiiiiiiiiiXieiXiXdd.XXeXXXXXnXnnnnnnnpJkJ]6Jk6Jk6]J6k66k66J666k6vkvvvvkv66JJJJJJ6J66kvv6kvvvvvUvvv%vvvv6666vvvAvAAvzAAvXvAvvvvvv1vz1z1tt111-11p-44444g444g4g4444444-1-11z1v111", "X dddddddd( (( (( (L(*(*L***^****^{{{{^{{r{rrrrrrrrrrreeer.r.ee.e..MM..99)D_DDDDDDDDDDDDDDDRDFFFh&&hh&hhh=axabbaaZuSuxQalQbCZQQZux;aaxaaxxZuxaaaQluuuuuQjSxulQSxuuQujQlQuullQjllQQljjjjuQlluQljuljjQjjluQuQujuWWhjjhFWWWWW_iiiiiiiiiiiiiiniiXXXXXXdXXiiiiinnnnnn#pp##nnpJJJJ6kJkk6k66J66kk66666666kvkvkv666JJJ6J6JJ666v66v6kvvUvv vvv%vvvv66vvAAAAAXAvAXvzvvvvvvvzzzztt111--4--4g4g4g444g484g484gg441111z1z1z14", "ddX d d ( (9((( LL*(*L***L*^*^{^{{{{{r{rrrrrrrrrDDeeeeeee.ee.e...M..99.9)5D_DDDfDDDfDffffffDDFYFh&&h&hYFYRaaabbabbZ;aa;ub;;;blZQZC;axxxxxaZQllaSjljlluSQluSxSuQlSSSuQlulQjjjuujluljjjjjjjjuuQuuujjllQjQllllQjRWY&u&YFWWWWW=niiiiiiip#pp#iXXXXdddXXn#p##ppp##pp##JJJpp##JJJJJJ66k6k6k66k6vvkkkkk6vvvkvvvk6*J666666J6666k6k6kvvvvvvvvvNvvvvv6v6vvvAAzzAvzzAvvvvzvvzvzz1z1---111-44g444g4gg48484884844411111zzz1114", "d d d( d(( (( (*(*L****^**^{{{^IR{{{{rDrrrrrreeeeeeeee.e.ee.e.M.M.999))55D5DDD5DfffffRDffff_cFhY&&hhh&&YFRabbubbbCx;ZubCCbbxSxZlSu;;xxSaxxalujQulllQllljjjjlQljjlSuuujjQljuQQQuuuuljjjjjuQlllllQjjjjjujlljlQj9Yj&j&hYWWWWWRi##ppppppippinXXXXnini#ppippppppppJJpJ6JJp##pJ#pJJ6k6kkk6kkkvk6vkvvvvkvkvvvk(6J666666DDJ6666v6vvvvvv%d vvvvvvvvvvvvvvAvzzz1vzzzvvvvzvzvzzz1t--1-zt1-14444484:48484848441111izz1111148", "ddd( (d ((((*L*(****9*^*{{{{{{rr^rrrrrrrrrreeeeeeee.efeMeR.M.M.M.9.)55DDD55955DDDfffDfff____cFYY&hY&h&&&hRabubbbbbuSCb;bbu;CuaQxuu;;xxaSxauluQjljljZlQjjlQQjjjllZuuSuulljuQQQQQuuljjljlZQQlllQQlQujjjlQljllljTjjl&YFFYYWWWRripipipppppp#nXnnnpDpppppppppJJJJJ]JkJkpprDr#pJpJJk6k6kvkv6vkvvvvkvkkvvvvvvv66666vv666k666kvvvvvvv%vAvvvvvvvvvvvv6vvvXzAzzzzzvzvzvzv1vzvzzzzzzzzzzzzz1t11444888848848441111i111n44448", "d ( d( (( L *(**L*^*{{{{{{{{r{r{rrrrrrrereeeeeee.e.eMM..Mf..M9999)955DD5DD9D9D5DDDfff_f_ff_faFYY&YYh&hhhhRbbQbbbbbu;CQZuxuQxQSQaQu;;xSxSxSuuxZlQlllljQQjjjQxxxluxuxuSQjjQljjuuuQuuZljjZuulQluuQQuljjjQQQQlllj{j&&hFWFFFWYYrpppppppppppi#nnppp{{{]p]JJJJ]J]J]66*6kJJJp*JJJ66J6kkvkvk(kvkvvk%RvvvvvkkvUvv66666v6666666 v6vvvvvvvAvvv6v66666vvvv6vvAAzzvzvzzzvzvzvvzvzvzvvzzzzzzz1zzzti4g44444:8484441114444448:884", "(d (( ((*(*L**L***{{{{{{rrrrrrrrrrrrrereeeee.e.Me.M.M.MMf99M9.9.95DDDDDD5D55D5DDDDfR__f_____QFFh&YYh&YFFYfaubb;bCZbCQuxuZQCCZSZalQa;xxxxuZlSlSSjSuuQluljQZjuSSllllQjljjjljQjuuZQZuQjjljjQlQQjjQjljQj&uQQllQQlMYhhFFWWWFhYYR]pppp]pp]JJ]#nnJJ]J]JJJJJkJkJ]6*6]kkkkkJJJk6k6k6k6vkvkvv vvvUvvv v 9kvvvvvvk66L66666666669vvvv%v%vNvvvvv66v(vvvvvvvvvvzvzzvzvzvzv1v1v1v1z111zz111111111zi14444884444441114484488848:8", "( (( (( *9(*L***^{{{D{rrrrrrrrrDDeeeeeeeee.eMMMfRM.M.M.99M9)99)9D_DDDDD5DD9DD9DDDffff_______aFh&&YYYhYWWFRxxS;bbZxbQSSxxC;;CluQSZQQlaxxalQSllauQuljllljQulxuuululjlljljlljQQQuQQullljlQluQjjjjjjuujjjQujlQQulRFhFFFWFWWFYYIpp{*pJ]J{]JpnnpJ]J]JJ]JkJ]6]6k**k6k666k6k(6T* IivvvvTvkvvvUvvvv(IvUvvvUvvUvvv6k66666vvvv666vvvvAvvvvvv66(vv6vvvvvvzvvvzvzvzvzvzzzv1v1vz11111144444111111111114444g-D4411448488:8k8::8", " (( L(*L(I9****{{{{D{rrrDrrrreeeeeeeeee.eMMM..MMMMMM.9999999)99)5DfDDD5DDDDDDDDDDfffR_______uFhh&hYYhYWFW_SxbuSbSSaZub;;;;;aZZlSxaaxu;a;QZllaxujZllZluuulSuZSQQljuQuQuQZjjjQjuZujjjjjljQQllQuuQZZuuljluulQuljbFFFWFFWWWWFFf]J]JJJJJ*JJ#nnp6666k66kkkk6k6kk6k6kkUvkv MD9I99*Uv9j&RTT*] vv%vvvvvvvvvvvvvv%vvvvv66vvvv96v(vvAvAvvvvvvv vvvvvvvvzvzvvvzv1vzvz1vvzv1v111144444g4g4g4414111111144844]-441444]8]::::8::", "(( ((* (******{{{{{rrrrrereeeeeeeeeD.eMM.M..MMM.9.999999)9)99595DRDDDDD9DD9DDDDDDfDfIff_____jFY&&hYYhFFWFcSuSCZZaZCZCxC;;bxaZZulQQ;allQQQllQxauQlaxxSaxxSSZuSZljjxuuQjllQjjjjllljjjQjZuZQQQuQjjlQQQZljjjjjjljRFFFFFFFFWFWWR]J]J]JkJ]Jp#n#p]kkk6kkkkk6k6kkkkvkvvkXII9D9ID9Mpvv&&hu {{r r%v%%v%%vN v%%%%vvv%vvvvvvvvv(vv6vvvvvvv(vvvvvAvvvvvvvvvvvzvzzzzz1zv1111v1z1444g4g848488444444444411444414441444J8:::8::::", "( L* L**L****{{{rrrrrrreeeeeeeeDMeMDMM.M.M99M_9999999)999)95595DDfDDDDDDDDDDDIDffIffDfIf___f&FY&&&hhYhFFFRSuu;ZuxaSS;ubC;;bCQQlSuZ;;ZlZlQaxZaSZSQxSSxSxxSuuuSjljZuSSlQQjjljSQZljjuuuuuZuuZuuuQZQQQQQQjjjjuQlj WWWWFWFWWFFWS]6666kkk6JJ###J6k6kk6k6 (kvkvvkvkvU9=IDIM0ID[ v%v&j&&r9[D[MrpTvNvvAvXNvvAvANNvAvvvvvvvAMdvvvvvvvvvvvAAzzzzzzvvzvzzvzvzzzzz1zz1v1zz1114gg84g:488848:g4848484411414144144448]:::*::::*", " L (L*9*****{{{rrrreDeeeeeeeeMMMD.MMM.M99.M_9M99999)995=95959D9DDfDDD9DDDDDDDfDDDfDfDRfD_f__jFY&&hYYYYhFYR=;u;aZZ;xQZSu;;;C;CuluQZZZQZQxxxSaSxSuuaSuSxxuuuSuxjllZuSSSSuZljjjjuuljjQZQZQZullZQuuQuQQQjjjjjjuQZDWWWWWFFFWWWWR6kkk]6]6kkJ###Jkkkkkvkvkk9vvvkvvv9xbIRIID9D TekvNTljlc{[* 9D*** vNNXNNvNAvNvAXAAAAvvvvvvvvvvvvdvvvzzzzzzzttzzzzvzzzzzvzvzz1111z1v1z444g4:4884884:8::88888:484414444444448]]k:::::::::", "L*L* *9****{{{rrrrreDeeeeMMMMeMMMM.MMMM9_M9999999999595_D9D9DD9DfDDDDDDDDDDDDDIDIfDIDDDDD_ffjFFY&&hh&YYhYRb=ub;x;a;xaxSabbb;;CuuQaaaQxxSZxSxxxaxQuSuSSuxuSuSjulllSSuuuZuljQjjjQlZQQuZQlQZljjlQjjjjjljjjjjjjuQIWWWWWWFFFFWW=kk6k6k6kk6JJpJk(kvvkvvvvUUvUvvvT=&=IRI9DI909D*NMMkIDk%kTM[9D[9 9kAvTvAAvAAAAANANAvvvvvvvAAvAvdMvAMtttttt---tz(ztppTiznD=bXJv1z1z11148:88488488:8848k8:8::::8444141p14888:::::::::::::", "( *9******{{{rrrrreeMeeeMMeM.MM.MMM.9999M_99999959595I99D9D9D9DDffDDDDDDDDbIDfDDDDDDDDDDDDDf&FFYY&&hY&YYhI=bSb;aZaSZZuZab;b;;CxQQQaaxaxalaxxxxaaSaSxSSxuSSSxllxSlZuSuZuuljlQlljjulluQQlQulljjjjjlQlQQQljjljuQIWWWWWWWWFFWWRkkkkkkkkkkRpJ6kUvkvvUvUvvvvvvvTu&bRRIcf0RDDDIM9]]9DI9I;cMM[0De[* AAAvAAAvNAvAAAAAAvvvvvAvAAvAAzzT-ttttt--k 9MTTTT]]R&&jbMTTTv11144848488::8:::88k8::::::8::884444g484:::::::878787::", "********{{{{rrrreeeeeMMMMM.MMMMM999999999=9)59599D9D95DD9DDDDDDDffDDDDDDDDcDDDDDDDDDDDDDDDDRhYhhYh&hhh&hlRbbbb;;x;SSbaCbCbb;b;CZuSSSuaZuuaaxxxxSSSuSSxSxxuajlSSQjZlQuQuZuQlljZjSlQluuZjjjjjuujjjjjjQQlllQjlZQRWWWWWFWWWWFWbkkkvkvvkv(kJ6kvvUvvUvvv%v%%vNTl&bRRIRIIDI[IDIDI* 9IDclQM[MIeD09 M9*TAAAAAAATAAAAzzTvAvvvzzzzzzzz--------T9cRVk]Tp]]p9SQjlDT T4Tz14888:*8:8:8:g::::::8:8:::::84444848::::::::787878787", "*(*****{{{{rrrreeeeeReMMDMMM9M999M99999999)I99D9D9D9D9D9DD9D9DDD_DDDDDDIDDRDDDDDDDDcDDDDDDDDj&&&&&&&hYh&&IbSu;abaZxbbbbbCb;b;;CxQlQuSZuuul;axxSuSSSxSuSSxSjljuljjlljSluQZZZjlQuuZjulujjujjlQjjuuQZjQullllZjjQkWWWYYYYYWWWWRkvvkvkkvkv6J9vUvvv%vv%vTNXNNix&lcRIRIcDII9D0DID9DM0DDDDDDMrIDDMp[9[*TAAAAAAAAzzzzzzAAAzAzzztzti-------gDabRTi% *]]] ah&SM]]k% iA8::88888:8:::]k8:8:::::8:8:::88::8:::::::87888%8o7:U", "******{{{{rrrreeReMeDMMMfMM9M99M9999999)_I)9D959D9D9DD9DD9DDDDDIf_IDDDDDDDDDDDDDDDD9D99D999D&&&&&&h&hYYhQcuaaSxbbxbbCbC;bbC;;;;aQZZllSuZlu;u;aaxxxSSxxxlljlQllljlljSuQQZQQSjQQjlZlQjjjjuullljlluQulZZQlllQjlZDWWYYYYYYYFWWcvkvUvUvUvUk6*vvv%v%XNNNvANAX=&hcRcIIRIRD0000D0D0D[DIII0I[M[I90{ *[DMkzzzzzzzzzztttttzzet-----4[4-g4g4IaSSc p]i ]g%RD[A%A] kTTkNt88:::::::8: k8:::8::::88:8::::8::::V9@9oNUVDCjjjU%", "*****{{{{rrrreeeDeeMMMMM9M999999999995999959D9DD9D9DD9DDDIIDDDDfD_DDDDDDDDDDDDDD9D9D9D9D9D9)&Y&jh&hhhhYhbcCuSuZbZSb;;bCS;bbb;;C;;lQQluuZlQQSaaaxxuxuSxQjlZuuulSSQllSSuZQZuulQZuZjjjjQjuuuZlZZjllQujlZZQllQlQZIWWYYFWFYYYFWlv v%vvvvvv66vT %vNNNvAAMTAzIhhaRIRRIIcIIsoo$oo0ID0ooID0o@[[MIDM {MM[Mtttttttttttttt-------4g-g4-g4g4U=;uc* *TT]T* p]VTiI=u]p ]kpT-::8:8:8:::8::::::::::::::::::::tT9c=M]kT%T=hY&&]T", "****{{{{rrrrreMeMeMMMMM9M99M9999999999D9D9D9D9D9DDDD9DDDDDDDDDDDIfDRDDDDD9D0D99DD9D9D99c9999&&j&hhYhjhhhubCaxxxux;C;;C;bb;Qx;;a;;aZulSuQZuxlSaa;uSaauuuQQluQZuSSlSxSuZZuuuSlljjulZZQlluuuuuZZujlZQujjjZulQlulRWWYFWFWFFYYYRUvv%%%v%%vk6%%vANvAAAAAAAzz&YjRcRIIIfRc0oo000oo00Mo0IIoo$s@oo0[9[*D * ttttttttt---------g-g-g4gg4ggkcllbT* T]kpTT*]]k 9cIkUkpk]T]-8::::::::::::::::::::::::::::: Rbx= kU]T]TI&hYh]]", "***{{{{r{rrreMeMDMMMMM9M9999999999599D99D9D9D9DD9D9DDDDDDDDDDDDDffDDDD0D9D9D9DD9DD9D9D99999)h&h&&&hljhYYxxSSuSbbbb;a;;abSbZSb;a;;xlllSuuuSxlulZZQuxSuulllllZuxSSSSuuuuuuuuullQQluZuulZjQlluZQZuuulZlQjljZZQjj*WWYFYFYFFYFYbv%v%vN%Nvv6vANTAATAAAzzzt-IYYaIIccIIIIc000I000o0I0oo0Io0000oo[D9D[M [e%--tpT----t------]-g4g4gg4g4:cl&&DT *TTUT]TpU T T]%iN]T]T]]-]-U::::::::88788o788o878878:8 b;;cTkkUkpU[&jZSIkU", "*{{{{rrrreeeeeMeMMMMM9M9999999999D9D99D9D9DDDDD0DDDD0DDDDDDDIDDDIfDD0DDD9D9I5D9DD9D9D999999RY&h&Yhuxhh&Y=axSZbb=ubbaabCbb;bxC;;aaCSaluaZlaxxxSSSxSuSuullllxxxxxSuuZuuuuSuSjljZjuuZuuljlljuZQQQujjSujjljjlujjj9WWYYYhhYYhYYRUvNNNvvvvvkNAAAAAAAAttttttlFhIDIDRRIIDIIoso0oo0IIIooIIo0000oo00I[ TT*9*]t-t--t-----g4g-g4gggg4g8g8I&lj=T * ]ps ]TTUT ( TvN]TkpT%k]]TT:87887887878788878:88788>[xSlS ]]kTT]N]U]V]IR[", "*{{{r{[rrr[DeMeMMMMM9M999999I99D99999D9D9DD0D9DDDIDDDDD0DDDDDDDDDDDDD9D999D5D9DDDD9D9999999cY&&hY&au&j&&u=ab;bbbubaaC;;aCbCb;S;C;;xSxlSaZQxxxxxxuulQllxSlaSSSxxSuuuuuSQljlllZjuluZuSQZuZuuZQQZulljjjjujlulQljIFFFhFYYhhYhhIvvvNAANv vAAAAAztttttt--TFFlRIIIIRIIIIcoo0o0o0000o0000o@sooo00D*T *[ 9U--------]-4--g4gg4g48g8R8]hY&&9TT* *Tossss@s okosss@s %]Tk TV7878787878787878787788789SljuIT]kkT]]]%]TTpC&I", "{{r{r[rr[eeD[eMMMMMMM99999999999D9DDD9D0DDIDDDDDDDDDDDDDDDIDDDDDDfRDDD9D9D9D5DD9D9D9999M9MMR&&jhhjbxba&&=b==bbbbabbaaa;;;bbbC;;;bC;ZlllxZQlxxxxuZulllQuQxSSxQZxxSSuSxQjjjlluQlQuuuSjjQuZQQQZZQuQuuuulQQllllZQMFYYYYFYYYYYYIzvvNvNvvvvAAAztttTtt-----cFYlII_DIIcRIIIo0I0oo0I00oo000o000o000I*[{M T9[4-g-g-g--gggggg4gg8g88*88DY&Yu TT*** Vs@ooPs@TVs@]@ssssso]Tk TTV78787878787878787887878=bbSckT]kUTT]TA%]]Tk[p", "{r{[rrereeeMeMMMM9DR9M999999999D99D0D9DDDRDD0DD0DDDI0DD0DDDDDDDDDDDDDDDD9DDD9D95955999MMMMMRj&jhhju=_=lu_S;bb=CbbZbaa;;a;bbC;;bCb;;;CaluQlSuu;x;lllQljSxaxlQSZxxxllZjuuuQjjSZljuuZulQluQQQuZuQulQuZZZllZjjjlZIFFYhFFFFYhFYcvvvvvvvvvMzttttttt-------=hhbccIIcDIDIIco0IIo00900oo0I0o0000IMIr[MM[Mr0Dgggg-g-ggg-g4]gg8g8488888jY&hI[]TV* *Ps@oPP@] @@VPs@ooPo T]k]kUV8787878787878787878787IIRxuM]UT-%TVTTNp]Tk-T]", "r{rrr[re[eMDMMMMMM9M999999IR9D99D9D9D0DD9DDDDDDDD0DDD9=_DDDD9D9D9D9D9D99D99999999959MMMMMMMR&&&hj&&ubRc=DCx==;bbbxbx;;C;;CbQSuSuS;;;C;SZZQSQZZQlSlll;SSZQllllxSSlllQuSQQlQlxZuuuZujQjuSZQuuuSulQQZuuujlljjlQQ_FYhYFFYFFFFYIvvvv%vNvTtTtttt--{----g-glhYccI_RDDI9[DIo0000oo00[ooo00o00II0ID[M[{*M 99kg-g4g-g4g4ggg848g888888]Fhhh9**TT *[Us@s@ssoT s@]so@os@@V]%NNAT]87878787878>87888788VcR;xRPNUTt%]s@ss@T]stV@", "[r[erreeeeIDMMMM9MM9M99999999D9D0DD9DDD0DD0D9D0D9D999D99D0D9D9DD9D9DD9D59D999999599MMMMMeeecj&FYhh&j=R=bM==xubCb=Sbxa;;a;baQuQuu;xbCC;a;;;;xQlQQZ;;alQuSxlQljZllZuujljjxlSuZljSuuuQuSuSuZZulZZZQuZZuujQllljQjDWFhhFFFYYYFhRvvvNAAttTt-Vt---tg--ggg-U&YYIDIIcIID [I0I00II00 [0o0oo0o00IIID0M9[*[*T[ g]ggg4ggggg]8g8g8888888R&hYh T*[]TT]o@ooo@oV ooV@o@@@@sV]N-NUtTN88888888887888787887[cS&&Dk-]UtTVs@@@sT@stos", "rrrr[e[eMMM[MMMMM999999999D90D9ID9D0D9I_D0D9D9D999D9D0D99999D999D9D9999995999999999MMMReMee;j&h&h&&ucbuuI==bbbbbbxb;a;babb;alaaSQQQC;;aaxaa;uuQlZxllZuulQllZllZuSZjllQlxSxlljSuuSjjuQuSZuuuuljululuZZlQZlljQjIWYhYYYYYYYYhcNNAztttttt------g-g]-g4gg&&jRIIRIRcIDIIII0IIII0 MI00[[[o0I90D[D9[M[D**[MT]]g4ggggggg*8g888888888=YhF; [TTT T] so@oo@@V @oVosPPo@g%gz]k]]]:78787878788888I8>7Pxl&hj U]U]NUUsoPPs@V@oV@", "r[e[eeMeM[MMMMMM9MM99999990DR99ID9IDDDDD9D9D999II09999999DI90999959999I9999)999999MMeeDeeee;uxl&h&lbbub;_;=a=bbb=Sb;aCaaCbCbZQZSxSSZlQQuQQQZQZaSuZlSZZjlllQSQlQZSQluxSSSSjQlSSlulullSuuQQQuSujjjZuQZQlZlljljQgYhYYhYhYWWFhbTAttttt--------g-gggggggk&l&RRIRI*M[[D90T00II0[MIII9[*[M0DID9ID[IM[[I **[]4ggggg48g888g888888:8:cjYYZ*[kk]T%N[os0o@@ o@ Vo@VPoVNk%]TTTV]P878878888>88888:888&h&&;%t]%kNTo@s@s@V@s]@s", "eeeee[eM[MMMMMM9M9909I99D9D99D9D9RD9D9D9D9909999959I999999M9999II99999.9999999M9MMeeee[r[rDQlQlQj&lcbucc9a=b=b=bbub;aC;axCaxZZSuZQQaaxaSuQSxxuZuxxxQ;xx;;lSSQZluullSSQSZZuxSulljQZjlluQllZZuZjlZSZZQZQQZZuQluIYYYhYhYFWWWYbAtt-----g[g]*]ggg-gg4gg8 jj&IIIID T U]T]]UNTTk%%t]]%k]k]oTo* [* r[{ *[4-g4g4g8g8gg88888888888cZh&S ]TN%ktU [oo[os@o @@oV@oo] U Tk ]kkk88888>8788788888880h&hj=Vkt]UN]VsPso@oVsPU@", "e[e[eM[MMMMMMMMM9M9999990990D9IID0D0DD0D90D9D999999M9909MMMMMMM9999MMMMMMMMMMMMDeeee[eeer[r&h&&j&&u=abcc9b=bb=;b=ab;;Caa;xCSZx;SZlZuaaaxSluZZQuxlSaSxxxaZlZaaxuSZuZlSxuZuSZuljlujxjSSullZuuZljllZZQZSlQluuujZMFYFYYhhYFWWF=*Ntt-tg--g-g-gg-gggggg8gT&jhcIRID TTTTT ]TTTT]]]T]]]]]kUUNNNztk]M0D{t--ggg8g8g8888888 :888UlSj&cTT{] N ToV [0oo@@oooVV]]TTUTT U] ]U87878>88888888888-IYhh&=]]tTT-UosP@@soos@Ps", "ee[MMMMMMMMMMM990999IM9D9D9D9D999D9DI9D9I5999D099999DMMMMMMMMMM99MMeMMMMeeeeeeeMDMrereeeeerjh&hhh&u=cRcjf=b=bSbCCb=b;b;aCS;uZuCCuQ;uZlZQQQ;;CaC;;;axa;;x;axxxQluZlSuZxxxllllluSljxSZuQQuSuSujllljuZuuljQllSSl[WWWFhhYhYhYFa *%-gV-g-gg]ggggg8g888g8 j&&ccRcI TTTTTTTT]TTV]T]]V]]Vp]]]]kkk]kU M9I --gggg--88g8888888888glSh&RV {T%]]kVT]TVoT[ TVTT ]ViV ]kTT NN]T]g888888888888gg8ggRhhhYlVkTV]%UU@@P@@@os@PV", "M[MM[M[MM[MMM90M999M990990D0D0D9D9DMI9D9I9D9D99999MIDMMMMMMMMMMMMMeeeeeeeeMeeMeeer[r[re[eerh&&YFFhQbcRQ&Rb==C;SS;=ba;C;CSZZuZCbCbxxSSQQCC;axaa;;;axxa;;;xx;a;QZxljSZZllSZlZjZZZZZZuZSuuuSSuQlZlllSSuSjlljjSSjRWWWWFhYhhYFFa[ *U--g-g-gggg4ggg88g98gM&jjIIRIR T TTTVTT]TT]T]]T]]]]]]]]Uk]UUUVD{0DA--]]9[U]VDujkt]8 88g48&&&h=] [kggg888:88:8:g8:g:gg4gtANU]kUtk]]V88888888888gggggg-0hhhh;VTU]]NTVPPoPVVoooUU", "M[M[MMMMMMMMMM999M9099D99D99DDDD9D99999D99D99999999MMD0MM[MMMMMMMee[ee[e[rr{eree[rr{{rrre[9YY&YFFhjQuu&&I=b=SxSSCbb;aabba;;xSbCb;aCbxuSCCa;;;;;xxxxa;xxSxxuSaxxSSulZjlZQSSxxSSuSSSuSSSuxluuZluQjZjjxljZQljSQjIWWWWFFFFFYFWl[[* Ugggggg9ggg8g888k g8Ujj&RDIcI TT TT T T] T]T]]T]]]T]]]kk]]]kkkTMIDD ]DcMV]kVN9&j T]T%gg-gg;&h&=]]kkg4gg8g:8888:888:8::8:::8:::::UTUUV88888888gggg]gg--9h&&hSV]%U]%VUUNUV]V]VUVU", "M[MMMMM[MMMM0M9M90999909909D99999IID9D9999MR999999999MMMMeeeMeMMM[Drr[r{{{{{[r[rr{r[{[{[{r*YYYhYFYjQjl&Yc=ab;Sbaa=bbbCbabCxZxbbCauaZSa;CbC;;;a;xaxSxxSxxxuZux;aaaSlllZxSSSxSuuuuuSSxlllSujQlZllQjuuQuZSjjlSxl FWWFFFFWFFFWj{ [ -g-gg-0gggg888g8888gl&&cRRIR T T TTTTT TT]TV]]V]]]]]V]kkUkUU [*IDoRc[VTT]]g]I[ T%]-%4g-gSSjjR]%]]gg4g48g4888g8888:88::88:::8::UUA]]888888ggg--gggggg0&&&jZ]U]7:7::g7:g:gtNN]]", "MM[M[MMMM0M9M9099990999D059D0D99DMMM99M9990999D9ID99MMMDD[[ee[eDer[r[r{[{[**{*{{r{[{{{9r***YYhhYFFjQ&&FhR=Sx=;CCaSSC;aC;aSuuuuZa;u;SCbbCCCa;;aSaxaa;;;xxxSuuSSx;aualSSSuSuuuZuuuuuuuSjujjjlZQQlljulQZZZljlluSTYFFWFYFFFWWWj[[[[MTggggggg8g88g8888888llj=ccRI T TTTTTVTpT]T]T]Vp]]]]U]]]k][[0D=C*T%]TUVAkNcj[Tog]kgggccC&=V]T g4gg8ggg8g8888:88:888:8:88:8:Nk]kV88888P8ggggggkggg[j&jjZVAN:78778787:787:7:", "M0DIMM[MMMM0MM9M909999099D99990990DM90MM0DMM90DMMMMM9MMM[eee[eee[r{r{{********[{[{{{r{[***[FY&jhFY&&jYF&c=bS=uSbu==b=ZSbbaZSaSZZuZxuu;bbub;;;xxS;;llSZlxSSSSx;lQluSxuZuuuuuuuSxxSuuSSllulljujZljjjlullQZuQluS[YYFWFFWFWWWhS[*M[[ Ngggggggg8888888888jl&cccII* TT TTTTTVTT TT]]T]]]]V]]kk]k]UT[D{0boUT%]]U]]TU]k]TTT]]]g8cbbZl T]]-gggg4g84884888:88:88::88:8:8t]k]T888PoUgggg-ggggg8Pjj&jjUUUg7878787878787::", "IMM[MM0MMMMM90M90990999D9090MMMM[MM[MMM[MIMMM[[M[M[MMMM[Me[ee[e[r{[**[*0** [ ****{{[****** hh&&&FhYhhFFjR==babx;xxCbabbCZSS;xS;SubbZZZ;CbCCCbC;SxxZQQuQ;SuuxaSZZZaSuZSSuuuSSSSSSxSuxlljZjllululjlZuZQjQQuluSZTYhhFFWWWWWhla] *[Tgggggg88g888888gggjj&=cRI9 * * TTTTTTTTV]TVTVi]]T]]]V]k]k]M0D[IkVUT]sssVU@PUT]tVTUg]g[SZjj[*TT-g4gg-gg8ggg88g8888888888:8888V8VTg888UgggggggggUggojjlZZ N%N878787878878878", "[M[M[DMMM0M0MM9MMMM909909MMMMM[M[M[e[[e[e[R[[e[[[[e[[9eeeeeeer[**[*** *** * ******* * *[ *[&hhhhYYYhFYF&c====;;;CauuCCbbbbxbbb;ZSCZZxCb;;b;SSaauZC;;;ClZax;ZaSQQ;SSaaSSSSxxxxxxSxaSZQllllSSjllllluuulQZlujZjl YhhhYWWWWhQjl ]V M[ggggg88g8888ggggg-lj&b=IID T TT T TTTTTT]T]]TVT]]V]]]]]UT[90M ]kVVPsP@sPs%PsssTU%kkUDjlQj*[ g-g4gg4gg488gggg88888:8:88888:]%%UgggggggggUggggPggP&jl=S*tNP787878787878787", "M[M0M[[M0MMMM0M0M0MM999MM[D[[[[e[[[[e[[[[[[[{[r[{[{{[[[90r[[r9**[* [** 0 ** [ [ * * * *IjhhYhYYYhFFYZbb===;=CxCSbbbbbb;CC;bCbbbbZCxZ;;auSQubCCC;;aa;uQZxZSlxaSZxaxaaxxxxaxalZxxjluZSjjSuujxlZjlZuQjuZZujuQ]FFhhhYFWW&Zhj** [ [[ ggggggggggg-g--- ;Cj=cR[I* ToT T oT TVT]]]]T]]]]k]]]]90D* ]]%]Usss@osVUs@sso]UV][ljjjD[[T-gggg-ggggg4gg:8g8g88888888888UkgTggggggggggggggggPgZSCCZIg%]888878888788788", "M[MM[MM0DMM0M[DMMMMMMM0M[[[[[e[[[9r[[r[{[{[{[*[*[*[[***[*[**M0[*[** * * * * D[c&jj&YhhhYYYYuCbb======xbbS;a;bbbC;;;;;CCbbbQZuCC;C;aaa;aaxaxCZSSu;;aSxaSx;a;axaxxxaxllZSuuSlQulSlljllZjZulllQQQQjlDFFYYhYhWW&lFj[[[[ [*Uggggg-t---g-gU]gUcSZb=IDc * * * T TT VTVTTTV]]T]V]]]]kV[{ 0[TV]oo@@sPPsVP@@s@UV]UVDSZjjI [Tg---g-g4ggggg8gg8g88g888888888V]t@ggggggggggggggggggSljjj0UNV78788787887887:", "[M[M[M[M0M[MMM0IM0MM0[[[[e[[[[[r[[[{[[{[*[*[*[******0** I[* [ [[* [ 0* [ [ 0Icj&&j&Y&&Yhhh=bb;;bbb==bCabC;Zbbuabb;;;CbbC;C;;;CCbCCbCCC;xxaCSSuCa;xa;lCxxx;xxx;xSxuSSuZuSQjxxljlZlZlllullZjlllSZZcYYYYhYhhW&&F& * [oNNttgtgggggggggggbulCcRII[* [ o T o TVTT]TT]VV]]]]UV]U] [* N%TTPsosoVPVUsPPPV]]]V[jj&l0 ]]tgtg-ggggggg4gg488g88888888888kV%]gggggggggggggggggg=jjl&cNNU888788878788788", "[[M[[[[[[M[M0M9[MMM[e[e[[[[[{[*[[[D*[*[*[*[ **[0[ [[[[ [ [ * * * * I&&j&&hhhhh&&Zbbbb;bb=S;SSSbS=bCSSxCbCZSxaCbC;;;CCaSSZlQu;xxa;Cal;C;Z;ZaSSSxx;;xxuSxZxuuQuQxSxSuluSlZZZQSjllQZllxuZgYYYYYYhhY&YWjUUN%T * ToVggggggggggggggZjQ;cRI0 T TTTTTTTTTVTTT]V]]]]]]]][D[MTUUoTo@o@VVVU@PPo]]]]V%[&ljjI UTtgttgt---g--ggggggg8g8g8888888]]]Pg>ggggggg>gg>gg>gsjjjjjRtUP878887888878888", "[[0I[M[M[[MMM[M[[[[[[[[*[*[*[*[**00[* [ [ *[ [ [* [ * *[ [0 [ [ R&jj&&YYhYY&habbbbb===bSSa;;abbb=b=bbbbCxxxaabC;uuSxa;uxC;;uCx;lx;allCxSSSuSaSSSxSSuuxSxQlSxxxlZluulZjSuZjlZlZjxSSl%YYhhhhhh&hFWjUUUNV[[*@]Tggggggg>gggggVSllCcc99* [* TToTT@TTVTVTVTVT]]TV]V]]][[MD[V]kUNUVVU]U%VVU]]VVV%V &&ljI]* UN-gtgtgg-ggggggggggggg8g88888V]k]gggwgwg>ggg>gg>gg>I&&llc>TV888788878888787", "[[[[[[[[[M[[[[[[e[[[*[*[*[*[[ [ [*[ [ [ [ [ [ [ [ [ *0 o o o o o [c&j&&hYFYYh&&R==b=====SSSxxS=bbbbCbbbC;;CCCbbCbuS;SZSZbC;aCQCxx;CClx;xSSSxxSxSxxxxSClZxSaSZa;lSZlxuxSSxxSllljZSSSlZth&hhhYhhjYWW&UU%Uk[M[TVVVggg>gggggg>ggljl;Ic0I[ [ TTTTo T]TVT]]TV]T]]]]][[0[*T888888888888888888-VT@l&ZjM[ *UtgNgtgttggg-gggggggggggg88g88T]UP>g>ggggggPgg>gg>ggclSCcIU]N888888888888888", "[[{[[[[[[[[[[[[[[[[*[ [ [ [ [ [ [ [ [ [ [ [o [ o o o [o o o o o o Cjj&&j&YYYYh&0====abbbx=b;Cb====bbCbbbbCb;bC;bbCCZZZZZZx;Cu;;a;a;CZ;;SSSa;;xxaSxxxx;llxZ;x;SlZlluZZSxxxuZQllSZjZSZlThhhhhhYhjhWWjPUUUV[[ VVTNg>Pgggg>gggg>=jlcc9II[* oToT TVTTVTVTTTV]V]]]]U[M[M[P88888888888888888888]V;lZS[ okttgttgtgtg-ggg-ggg-ggg8ggggggU]TUUg>gPgPgPg>gPg>gPgoc==cIPVt888888888888888", "*[[[*[[[D0*[*[ [*[*[ [ [ [o[ [ [ [ [ [[[ [ [ o o o o oo[o o o o o o[ o ooo*b&jjj&j&&&Yh&_c==CbbbSxS;bbx==b=bbCbbbCbC;;;Cb;xSZx;;aZCC;Cxxaaa;ClS;aSxS;CxaxSxxaxxuQxSx;SQllllQluSuSuZZjlllZllxQZ]hhhhhYh&jFFFjUUUUV*[[TVVNPggg>g>gg>g>gZSb=0cRI[ [[ T T TTTTTTVTTVVT]V]VV]VT[[ [V88888888888888888888]VSZl=0[ T@tNNgtgttgtgtg-g-gggggggggg8ggU]V%PPgPgPg>gPg>gPg>g>oc=S=R%%N888888888888888", "[ [ [[*[[*[ [ [ [ [o[o [o [o[ [o o o oo o[oo o o o o oo o o o ooooooT ooTo oobjjh&hhhh&jjC[==bbCCCbS=SSCSS=====bbbbbbb=bCbbCuS;xu;CaCxZCSxC;Sua;xxaC;SC;C;x;S;xCCSlx;;luZlSS;llluuulllZZZllZ;lQZ]FFYYYYhlhFWWjVUUUV[[[ VkVVPN>g>gPg>g>gcCcIcRIIM o oToTVToTTV]TV]T]]]V]T9o[*Vggggg8g888888888888NVVSjScI[*oTtNgNNgNgNgtgtg-gggggggggggggg] UVVg>gPgPgPgPgPgPgPg[=CS=c>gV888888888888888", " [ [ [ [ [ [ [ [ [o[ [o[o[o[o o[o o[o[o o[o[o oo o o o o[ o o o o oTo To oooToToToQ&&j&&&&hhScc bbb=Cb;=bSb=xSab=bSS==uaSS;;CSS;uaZCSS;ZbC;CC;CuSSSZ;;;auCuSC;C;xaSxa;ClZ;;ZS;Z;SlZllZZllllZxZllu;;lZVFWFFFYQlFWWWjUPUU] [ Nggo]VP>g>PgPgPg>ISCcccII0 [ * o o oT T oTT VTTVVTV]VV]V]V[9M[Vgg8g8g8ggggg8g888888]V=lZxI*[ Vg>tNgNgNgtNgtttgggttggggggggggoUTVPgPgPgPgPgPgPgPgPs==C=Io]V@88888888888888", " [o[o[o[ [o[o[o[o[o o[o o o [o[o o o o [oooo oo oo o oooo o o o o o o o oooTooTooooTox&j&jj&j&lcRbrbx==CbbC==bC;xCC;b;axSC;;;SxS;SxSSSSuSZZZaSZxuZZZbbC;;ZSxZxZxCC;;xSSxaaaQ;aZxxxxSlZZZlZllZlZZllZCxlZZ*YFWFF&lhFWFWjVUUPV[0 ggtVoVUgPgPgPggPgClj;cIII* [ * T o T TVTTVTT]V]TVpVTV]*II[Tggggggggg8ggggggggg8P]ClSCc [TNtNgN>gNg>gNgNgttgtggggggggggg]%VVNPgPgPgPgPgPgPgPPgC=cCC0V]V88888888888888", "[o[o[ [ [o[ [ [ [o[o[o o[ o[ooo[ o[o[o ooo o o oo ooo o o ooo ooooooooo*o ooooooVooooQh&&&jjjl==ajIb==C=b=;=;C=;C;aCaCabbCSSZ;bbx;SS;CC;bbbbbxSuSxxZb;aaCZZx;auCC;;;;xSS;xCZSCuau;ZZZxZZ;;ZZlllSlSxx;SaZVYFFWYl&YWFWWjPU]]][[ g>NoU]V@gPgPgPPg@CjjlRc=I[[[ [ [ o o TTo oTV VTVTVTVVV]T 0[0[Pggggggggggggggg8gggg@VcjZZc[ [ N>gNNgNNgNtNgNg>gtggtgtgggggggU]UVgPgPPgPPPgPPPP@PgPZZCCZDVVV88888888888888", " [o[ [o[o[o[o[o[o[o [o o[oo oo o oo ooo o o ooo oo o o o oooooo ooo o o o o[oooToVoVToTo[j&hh&jjjuaSj&9=c;=bC;;====xSCb;xCbbbbSSS;bCCub=bbCCCbbxZCuCSC;ZCCCC;SZZSaZCCC;;;xSxS;CSZ;lxxQZlS;xlxxClllZZSZSCSSlZ hYWFjjYFFWFFjVUPUoT otgNV%PPVPgPgPgPP>cljScIRI0[ [ [oo T oToTTT oTVTVTVVTV]TVVTD0e[Vgggggggggggggggggggg@VISS=C[ [ >NNNg>Ng>Ngg>gNggNg>gggtgtgtggUVVoPPPPPPgPgPgPgPgPPgcZZCSIVTVgggggggggggg8g", "[ [[[[ [ [o[o[ [ o ooo[o[o[o[[o o o[o o o o o[o o oooooo oo@oooTo[ ooToo TooooTooToo@j&j&h&jjuSjjlDcC=;x;xa===bCCx;C;bbC;xx=;b;uSb=Cx=bC=xSSSS;ZZSCZZ;ubSuuZZxCS;C;;;xxxCx;;QSCSlZSxuS;ZSSCSZCClZZZSSllSVhh&&jhFWFFWFjP]VU][ og>googV@gPPPgPPg>cllC0ccc[ [ [ o o ToToToTVTVTTVVTVTV 90D[@gggggggggggggggggggg@oI=ccCToo NNg>NNgNNg>NNgNgNgNggNg>gtgtgtUoT]PgPogPPgPPPPgPPgPsIZZSSIVVV8g8gggggggg8gg", " [o[o o[o[o[o o[oo[oo[o ooooooooo o oooo o oo ooo oooooo ooToooVoo@o ooooooooTooooTo@T@j&&jjjjlxuh&jIc=abC======CCCxbbbCabSSSCbxbbSSCCCS=bbSx;SCCbZCbbuxSCCSCZZCC;CC;xax;x;xCCZSCSZZSxlSSxSlCxSCC;SZ;ZZZlZ]&lSjhFWWFFFFYP]P]@ 0oN>N@oNPVPgPgPgPPg0lZcIcII0 [o [ oTo ToTVTVTVToVTTVV]V I00 @tg>gg>gg>gg>gg>ggggg@VIC=c=V]VV%NNNN>N>gNgNg>Ng>gNgNgNgg>g>ggVo]VPNPPPgPPgPgPgPgPgPICCCZc@Vogggggggggggggg", "[ [o[ [o[ [o[o[[ o oo o o o o o oo o oo o o ooooToooo@oooVoVo@oo@T@TVoVoooToVo@@@V&jj&jj&jZajjZI=CCC=bc===bCaCxxCCbCa==CCb=bC;==bCb=x=CSCSZCxbbCbSZSubSCZCCCbbC;x;C;;x;xCQZCCSlZZZZZZS;ZZllZZZSSZCCCS jjul&hYFFFFW&P]V]o[0ot>tooNo@gPgPPPgP@IcIc0ccIM[ [[ o o o o oToToTTVTVTT@TVTVo DM[ @>gg>gg>gg>gg>gggwg>gPV0=Cc=o oN>N>NNNNN>Ng>NgNg>gNgNg>gNgg>gTo @NPNPgP@PgPgPPgPPPo0C=CCCVV@gggggggggggggg", " [o[o[ [o[o [o[oo[ooo o[oo o o oo o oo[o o o oo ooooooooT@T@oo@oVT@@@@ooToV o@T@oV@[jjjljjlu;au&&cCCC==Cc=cCxxC==C;CCb=;;=b===Cbbb=b=b=bb=SxCbb=bCCx=;CbbZSbbb;bC;;x;C;;xSaCZZCxZZSZZZZSSSSZSZZSlSxC;;Z[jljjj&hYYYFFF@P]PUV[ >N>VVg@VPPgPgPgPgIIcCII0D[ [[o o o o oToT@ToTVTVTVTVT 00[ ogg>ggPg>ggPggPg>gg>g@V0cZC=[[[o%N>NN>gPgNN>gN>N>gNg>gNgNg>gNgoTooPNPPPNPgPPPgPPgPgP0CSCC=ooVggg`ggg`ggg`gg", "o[ o[o[ o[o[[o[0o ooo[o oooo oo oo o o o oo oo o oooooooVoVo@o@oVoVo@Vo@oV@@@@o@oooVV@oV&jjjjlbcal&&jRCCc=;=bCaaCCb==;;x==b=======b===b===b=b=Z==bbCCbx;CbCbCZxCbCbbb;aC;CCC;xx;SZZZSZxZZZZZZSxSSZZZSZ;CClSMQj&hhh&&hhYFhVVVVV[[oN>NVPNPPPgPPPgPPPcSZ=I0II0 [ o ToTo ToToTo VooTVVoVT@I0D[@og>gPggPg>gPggPgg>gN@T0ClCC[[*oNPNPgPNNNPgPN>NNgN>N>g>g>Ng>gNV oT@PgPNPPPgPgPPgPgPP0CSZ=C@T@g>ggg>ggg>gggg", " o[ o [o o o [o oooo o o [oo oo o0o o oo oo oooooVT@oVo@oVoV@T@@@oVoVVT@@V@V@VV@@@VIj&&jju=bj&&&Scb==;b=bc=;xx;bc========Cb===b=bb=bbb=CSSSCSbbb=bSSCCCbC;;SbbbCC;;aCbC;CCCCCSCCZCxZSZSZZSCCSSC;lZSCSZS l&&hYYYh&YhF&@VV]V[ [>NP@oPVPNPPPgPgPgcZZ=III0*o[[o[o [ [o o oo @ToVToTToTo]oVT0I0 o@>gPggPgPgPgPggPgPg>Po SCC=[ [ PNNNPgPNNgPgNNgPNg>gNPgPgN>gNgPVooVUPNPNPPPPPPgPP@Pg0=S==CoPPgg>g>gg>gg>g>g", " o[oo[o[ o o[o[[o o o o o oooo[ o0[ ooooo oo oo oo[oToVooo@oTVo@Vo@@@T@VVVV@@@T@@V@T@VV@@DjljQj;=Sj&j&Q==b=c=cccC;c================b===b=b=xx;Cbb=;Cb=xSxSb;;=ZC;bCbCCbbCCCCCCbCbCCSCZbxZSZZZSS;;;ZCx;CxSZZSZt&hhjhYhhh&&YYVVVPVo0oPPN@VNP@PgPgPPPgPIZZCI0IR0[ [ [ o[ o o oo oT oTooToTVoTV@TVVT0D0 o@PgPgPgPgPggPgPgPg>N@@@=C=C0[o NPNPNNNPNPNNPNPgPNPgPgNNgPgN>NVVo]VPNPPgPNPgPgPPPP@Ps=CCCC[VVogg>gg>gPgg>gg", " oo oooo o [ oo o[o ooo o ooooooooo ooo oo [o o oo@ oVoV@@@T@oVV@@@@@@@To@@@@@@VVVVoV@IjjjZ;bx&hhhhxcccccb=C;b=====================b===CbCx===SSS;CbSbS=;bCSbCbCCCCbbbbbbbCbbSbCuZuCCCxSSxCx;;;SuCx;SS;xxSVhhh&hYYhhh&Fh@VVVV[ oPPP@@PPPVPPPgPPPP0SSCcIIc0[[o[ o[ o [o oo o oToToVToToVToVVo00Doo@NPgPgPgPgPPgPgPgPgP@Vo====0 oP%PNPNPNPgPNNPgPNgNNgPgPNgPgPgVo VVNPNPPgoP@PNP@NPPPPII=ccoVVV>gPgPgggPg>gP", "o[ o[ o0 ooo o[o ooo o o ooooooooooooo o ooooooooooooVoVo@o@VVV@T@V@TV@@@@@VVVVV@V@V@VIjja=cC&hYYYh=c==cc==CbCc==c=====b===b===;b==CCb;======bC;SSSCCxSbbbCCS;bbbbbb;CbCbbbCCSxSSZCCbCCSS;;;;CaSZSZZZ;C;;x hhhhYYhhYhhFh@VVVP[[ PNPo@N@@NPPgPPPgP0=SCIcIII[o [o[o[ o o o o oooTooToToTooVo@TVVe00 0ogPPgPPgPgPgPPgPPgP>@oo====0[o P%NPNPNPNNPgPNNPgPPgPNPgPN>NNNoV@ooNPgPgPPNPgPgogPgP@II=cI >V@>gPggPgPgPg>g", " oooooo oooo ooo oo o oo oooo oooooo ooooooo ooooToVT@V@oVoVoVVoo@@@@@@@VVVVVVV@V@VVVVVVVcllcRbZhhYhYYC===ccc=cC======c=====b==bc;aSC;a;==bbbb====CSS=;SCSC=b=S;C=CbCC=C=SCbbCbbCSZxS=CbbSSCCS;C;a;SZSSS;xSxxc&hhhhYhhh&hF&@@VPV[o[PPPo@P@@PNPPgPgPg0cSCcIII0 [o o o o oo oo oToTooVoVooToVT@VT0D[ [@PPgPPgPPPgPPgPPgPPgP@@ccc=0 [oUPNPNPNPNPNPNPgPNNNPgPgPgPgPgPt@oVoPPPgPgPgPPgPPPgPPPIc==c0@VPgPgPgPgPgPgPg", " o o o o o o o o o o o o oooo oTooooToo ooToToo@oo@o@Vo@VV@VV@T@VV VVV@V@V@VVVVVVVVVVVcl=I=SjYhYYhYCc=ccc=ccc=cc==c===c====c=;;=bC===b==b==bCb===CCSS;=SbCCCb=C=bbb==b;b=b=C=xZSSbCb=CSS;C;x;SZSS;xSxSxxSS j&hhhhhhh&&hj@VV@@o@oNP%ooPVPPNPNPPgPPIcC=cIcII[o[o[ o[o oo o ooooToToTVoTVoTVV00[0[ogPPPgPPPgPPgPPgPPgPPPoIIIcI [ooUPPNPNPNPNPNPNPNPPNPNPNPgPNP>NoVVogPgPPgPPgPPgPgPPgP0ccc=IP@VPgPgPgPgPgPg>", "o ooo o o ooooooo o o oo[ooooo0ooooooToooooTooooVoV@@T@T@VV@@T@@VVVV@o@VVVVVVV@@VVVVVVVVP=ScRblhhYhhYhR=c===c==cbccc=c==cc==c=====C=======bbb=b=bbCxCCSSSCSCCbb=b=C=b=bb=Z=CbCC;xCCS=;Cb=SSCxS;SZS;SCSSSCS;SCI&&&&hh&h&&&ll@@@@@o [PPP@VN@VNPg@PgPPg0=C=IIII0 o o[o oo o oo o oTooooo@T@oo@oV[[o[ @PPgPPgPgPPgPPgPPgPPg@@0I00Io[ooUP%PNPNPNPNPNPNPgPgPgPNPNPgPNPoVVoPNoPgoPgPgPPgPgPP0IcIIc0o@VgPgPgPgPgPgPP", " o[o oo0 oo o o oooooo oooooooTooTooo@[o@TVooToT@oT@o@@@@@@T@@VVVV@VVVV@@@@VVVVVVVVVVVVVoI=IcC&&hh&hhY=c=ccccc=cbc==c=cc=c=====c=C======bb=bCCbbb==;bCSC;bS=CbS===SS=b=b=;==bCSSSSxCbCCSSSCxZCCSZSS;CSS=C=C=b &&j&&&hh&&lCc@@@V@[ooPPP@VP@@PNPPNPPgPo=CCIIII0[o[o[oo[oo o oo ooooooooooToo@oTVV@ [o [@PNPPgPPPgPPgPPgPPgPPPo0III0o PP%PPPPPPPPNPPNPPPNPPPgPNPPNPNV@V@gPPgPPPgPPPPgPPgPP0I=III@@@PgPPPgPPPgP>N", "ooooo oo[o[oooooo o oooooooooooooo@o[@oVooo@To0VoV@@T@V [@@@VVVo@VV@@@VoVVVVVVVVVVVVPVVVVIIR;Sh&h&&hhYc===cccc=cCccccbcc====c===c=x=======bbbbbb===bbC==S=x=S=;==CbxSS==C=;C=CSSSCCSCCSSSCSSSSCbCSCSSS=CbC=CbI&&jhhhh&hYZ=C@@@@P[o[PNPNPgPPPPPgPPPPPo==cIIII0[oo[o[ooo o o o ooo oo ooToooVoT@@@V0[0[oPPPgPPPgPPgPPPgPPPPgPP@0cIIIoo0oPUPPUPNPNPPPNPPNPNPPNPPPNPgPPNP@PoPgPPgPgPgPPPPgPPgPo00cI0o@@PPgPgPPgPPgPg", " o o ooo ooooo ooooooooooooToTooVoooVo@oVoVoooTVo@ o@V@@@VVVVV@VV@VoVVVoVVVVVVVVVPVVVVPVV[I=S&&&&h&&Yhccc=cccc=cc=ccC=bc=b====c==b=c============b=bCC;CCx=C==Cx===CCxCS=bbSCCCCSSCCCCSS=SCCCS=SSCS=C===CbbC=CIh&&jhYhhh&Sj&P@>>P>PwPwPP>PP>>PwPPsgwso==III0I0o[oo oo[ o[o oooo ooooo@ooo@oo@@@V@V0[[[[P>PPPgPPPPPPgPPPPgPPN@@0cII0@oVoPPPUPUPPPNPNPPPPPPNPPNPNPPPNPPPVoPPPPPPPgPPPgPgPPgPP0I0II0PP@PgPPPgPPgPP>P", "s@s@s@ssssPPs@sPs@sP@PPPPPPPPPPPPPPPPPPPPPPPPPsPPPPPPPPPPPPsPPPPPPPPPPPPPsPsPsPsPPPsPPPsPIcbljjh&&&&hhcccccccccc=cb=Cccb=cc=c===c===c=======bb=b===CCS=S=CC===b;===CCS;CCb=CCCxCSCC=CCCSCSC;CbSC====CCb=bbbC=[&&&&j&Y&hj&h&w``+``g``sw>swwPw>PgswPswoIcc0II0Ioo [o[ooooooooo oooooooooooVo@oo@@o@o[[[oswswPsPwPP>PPPgPPPPgPgg@ssPggggggNggggw>gwgw>ggwwgwggwggggwgPP@o@oPwPgsPPPgPPPPPPPPP@00I00@P@PPggPgPgPggg>", "PsPPsPs@P@PsPPPPPs@sPsPsPPsPsPssPPsPPP@PsPs@sPPPPPsPPsPsPs@sPPsPsPPsPsPs@sP@sPPPsPsPPPPPP=SQljl&h&hhhhIcccccccccc=ccccCCccc==cccCCc=====c====b====C==C=;CCCC==C;====;CSC=C=SS=CSCCbbbCCCC=CCCS=C==b=b=b===C=bP&&&&ljj&&hYFY+y,,+,+````+```g`y````g`w$00I0I0I00o[oooo[o oo ooooooooooo@ooVoooo@oV@o0[00wPwPwwPggg>gggwggggwggwg>gwg`>`wwywqwwwywyw`yyw``yyywyyww`yyygyy>yg`gww>ggPgPPPgPgPPPoossPPgPggPgPgPgPgPPN", "PPsPPPPPsPsPPsPsPPPPs@PPPPPPPPPPsPPssPsP@PPPPsPsPsPPs@Ps@sPP@sPPPPPsPPPPPPPPPsPPP@sPsPsPsujl&ZZlh&hhhhIcccccccccccbCCCcccc=cccccbC=Ccc============c=CC==C==b==cC===CSCS==b=CSCSCCCCS=CSSCb=C=====b=C=b==CCCC=Nh&jjZCCjh&&&j,,++,`,+++,+,``++,`y`+,++`,E,E$@ooooo[oooooooooooo ooooooo@ooo@@@@o@@o@[o@@>gwgg>gw>gwgw>gwgwg>gwgggwyqyyw`>``wy``w+yywyyyywgygy+yyyyyyy`>``yygw`y`wgwwggwwwgwgywwwgPgPgPPgPgPgPgPgg>", "PsPPPPsPPPPPs@sP@s@sPPsPsPsPsPPsP@sVs@sPssssPPPPPPPPPPPPss@sssPsssPsPPPsPsPsPPPssPPPPPPPs&h&lZZjjh&hhhIccRccccccccc=cccccc==bC==Cc=bc=cc=cc=======c==C===C;=c==C==;==CC===b=C=CCCCC=;CCb=bCCxb=========CC====0YYhjSSSj&&jh&,,,++,+,```,+`+,,+```,++,+,,+,,+,,+,$y+[ooo[ooooooooooooo@ooo@@oo@osg>>>`>wgwgwgwg>gwgwggwg>gwgwgwEEyyyyyyyyy>w`wyyyy>`w`yyyyyq,yyy+yy+yyyyyw`w`w`ygw`y`w`ygyyyw``ywwg`wwgwwPgPPgPgP>", "PPPsPsP@ss@sPsP@sssPPPPPPPPPPPPPsPsPsPs@s@s@sPsPPPPsPsPPPPPPPs@s@s@sPssPsPsPPPPPPPsPPsPs0&&hjjllZjh&h&IcIccRccccccc==cccbCbc=cccccbcc=c=cc===cc=c=CCc=c=C=C=c====cCS=======c;CCC==C======CCC=;SSCCC==b==cSCCCUYFhjZCjhh&&Yj,,,,,+++,,,++``,,++`+,`+`,,++,++`++``+,+,y,++qoooooooooooo@ooo>>>N>>>g>g>>g>gPgPgPgw>wgwgPgwgwwwq,Eyyq,wyywyyyyqyyyyyyyy>`w,yy`wyyyyyyyyy,y`wyyy`wyyyy`>`wyy``y`>y`y`wy`gy`wwwgwwgwg>", "sPPPPPsPPss@s@sssPs@sssssPsPsPsPsPsPsPsPsPsPss@ssssPsPsssPsPsPsPsPsPsPPPsPs@ssss@sPss@sso&h&h&lZZj&&h&Icc=cIccIccI=c=======c===b==cc=c=cc=c=c=c=ccCcC==CC=C=C=c=c=C=cCC=====c====bCC=======CCCc=============CohYhjSZ&&&j&Yj,,,,,,,,,+,+,,+,,``+++,,`,+,`,+,,``,,+`+`+++,,,+ywy,oooo@s>>>>>>g>>>>w>sg>>>wg>>wgwgwgPgwgwwwww,EE,qywyqywyyqyEyyyyyyEyq,wyyw,wyyyyyyyyyyyywyy,ywyyyyyw`yyw`wwwyywyww`wywywygw`w`w`wy", "sPssPsPPsPPssPsPPsPPsP@s@ssPsPs@sP@sP@sPsPsPPsPsPPsPsPsPPsP@sP@sPs@s@s@s@s@sPPPssPsPPsPsI&&&&&jZZjjh&hIc=cccIccccc=cccccccc=c===ccccccccccc=cc==cc==bc======cbcb=cb=====ccc==c=C=C=C=CCC==CbbC==c===CC===CCCC0Yh&Sjjj&&&j&&,,,,,,,,+,,,,,,,,,,,,,,++````,,,+,,+,``,`+,`,`,`,```y+++y>>>>>>P>>>>>>g>w>gPgswgw>gPgwwwwEEwqyqwqyqwyEE,EEyE,qyyqywyq,EyE,wyyyy,Ey,Eyyyyyyyyyyyyyyyyyyyww`y>+y`w+yy`wyyyy`w`wy`ww`>`w", "sPs@s@sPs@sPs@Ps@s@s@PsPsPPsPsPsPsPsPsPsPsPs@s@s@s@s@s@s@s@ss@sPsPsPsPssPsPsPssPPPPPs@ss0&&&&h&jZljl&lIccccccccIc==ccc==ccc==ccccccccc=ccc=cccc=ccc=====c==c=c=Ccc=cc==cc==ccc=CC====CCC=C=C====CC;CCCC;CCC==oYhjZhhjj&&j&l,,,,O,,,+,+,,,!,,,,,,+++,,,,,,+,,,++++,+,,+,+,+`++`++++````gy>Pg>>w>>PwPgwPw>wgPg>w>wEwqqEEEEEEEyqEEwwyEEEywwyqEywyE,EEyyq,qyEEE,Eyqyyyywyyyw,Eyyyyygyyyywyyw`yyyyyyyyyyyyyw`ywyyywgy", "PsPsPs@s@s@s@ss@sssss@ss@s@sPsPPsPsPsPsPsPsPsssssPs@ss@ss@s@ss@s@s@s@s@ssssPssPsssssssss0&j&&&&jZSjZlZIcI==cc===ccccc=cc===ccccccccccccccccccc=cccc==c==C=cC=cc=====c==c=c=c==cC==C=c===CCCC=CCCCCC====CC=c== hjS&hhhj&&h&j,,,,,y,,,,,,,,,,,,,,,,,,,,,,,,!,,,,+`+,,,++,,,+,`,++++++,++g,`+,``PgPwgPPPgP>>PwP>swq$$E$EEEEEEwqEEEEEEEEEEEEEE,qEEEE,wwEEE,qyyEEE,EyqEywyqyyyyyyyyE,wyyyyyyqwyyyyyq,y,wyyyyw`wyyy`wy", "sPsPPsssssPsss@s@s@@s@s@s@ss@s@s@s@s@ssssssssPsPsPssPssPsssss@s@s@ss@ss@s@s@s@s@s@s@s@s@0&&&j&hjlSZZS=IcI==cc==ccccc=c=cc=cccIccccccccccccccccccccc==cccCcb==ccc=Cc==c=ccccccccC====CC==CcC=CCC==CCCCCCCcc=c=0&CZhYhhh&&&&&,,,,,+,,,,,,,,,,,,,H,,,H,,,,,,,,,```,,,`+`,,+,+``+,+,+++,`,+`,y``y`w``Psgws>w>PgwwwwE$wwq$EEEEEEEEEEEEEEqEqywqEEEyEEEEEyE,EqwEE,E,EEEyyqyEqyEqyEEyEyEyyEywyEyyyywyyywyEyyqyyyyw`ywwyy", "ssssssPsPssPsPssssssssss@s@s@ss@ss@ss@s@s@s@s@s@s@ssPsPsPPsPsssssssPssPsPsss@s@s@s@s@ss@0&&j&j&jSCZjZcIcIcccccc=ccccccccIccIccccccccccccccccccccccccC==c=cC=cccccCcccc==ccccc=c====C==ccc=c===c=C===CC===cc==[==jhhhhhj&h&j,,,,,,,,,,,,,,,,,OE++,,+,,,,,,,,,,`,+,,,+``,,,+`+,``,,`,,,`++,,```y``y`y`y>PgPss$$$$$$$$E$E$EEEEEEEEEEEEEEEEEEEEEEEEEEEEqwEEEEqqwEEyEEEEEyywyEE,qE,EywEyE,EyywyqyE,wyq,qyyqqqEywwy`w>", "s@s@s@s@s@PsPsPsPPPPPPPssssssssssPssPsss@s@s@s@ss@s@@s@@s@@s@s@s@s@ssssssPsssssssssssss$IZj&j&j&ZZZjjIIcI=IcIcccccIIcIcIccIccccccIccIcccccIc==cccc==c==c====ccccc=cc=ccCccccccc===cccccc=ccCc==c===c====c=c==ocC&&&&hh&ll&&O,$O,,,,,,O,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,,,,,,,`+,+,``+,++,`+,+y`+`y`y`y`+y`w`y$$$$$qs$E$$E$$$sE$$E$qq$EEE$EwEEEEEEEEEEqEEEEyEEEEqyEEEEEqwyEEqywqyEEEyw,qwywwyEyyyEEw,wywyq,yyEyywwwy", "s@s@s@s@s@s@@s@@s@s@s@s@s@sssPsPsssssssssssssssssssssssssss@s@s@s@s@@s@@@s@@s@s@s@s@@s$$IccSSCl&CI=CZIIIcccccccIcIcccccIcIccIcIcccccccIccICcccc=c===c=c=ccccccccc=cccc=ccccccc=====ccc=cccc=====C===c==cC===cocj&&j&&hhjjj&$,,E,OE,,,E,,,,,,,,,OE,,,,,H++,,,,,,H+`,,,,,,+,+,,,,,,,,,,`+,++`+y`++`y+`y++````y`w$$$$$$$$$E$E$$E$$$$Eq$$Ewwqwq$EEqEEEEEEEqEEEqqEqEEEEEEwwqyEEEEEEEEEEyEywywE,EqqyyywqE,qEEEyywqyywy", "s@s@ss@s@s@ss@s@sssssssssss@ssss@Ps@sPsPsssssssss@s@s@s@ss@s@s@s@G~G!!H~H!!H!HH!!~!!GH!O!GGGOOOOOOOOOOO,!!!O!G!O,O$$OBBBBB0000000IcIIccIcccIcc=c=c=cc=cccc=cccIc=cccccc==ccccc====ccccccccC=Cc=c==C=C===c====@=&&&&&&&h&Zlj$O$O,$,,,,,,,,EO,,,,E,O,,,,,,,,,!,,,,,,`,,,,,,,,,++`,+,,++,,,+`,+,+,+++`y``y`yyy+w```+$$$$$$$$s$$$$$$$$$$$$$qsqqqE$E$E$E$qwwEE$EEEEEEEEEqEwwEEEEEEEqwyqwwEEEEEEEEqEEEEEEwwyyyyEEEEy>w", "sssss@s@s@s@s@ss@s@@s@@s@@s@s@@s@s@s@s@s@sPsG!!,!!!/~!OGO!HGG!!G!!!!!H!!!!!GOG!G!!!~~~HOH,!,!,!,O,G,!,!!!,!,~,!HG!OOOOOOOOOOOOOH!~~~!,~,$OBBBBB0IIccccccc=cIccccc==ccccccccccc==c=cc=c======cccc===c=cccc===c[=jh&&j&&&&&&j,$,$,,,O$,O$O$,,,,,,O$,,,,,+,,,,,,,,,,,,+,,,H,,,,,,+,,,,,,++,,++,,+,,,y++,y`y+++``yy`yy`yy$$$sE$$$$$$$$$$$$$s$$$$$$$$$$EEE$$Eq$E$E$E$E$EEwwqEEEEEEEEEqEEEEqwEEEEywqEqqqEyEwwEEEEyw>yE", "@s@s@s@s@$@s@$@s@s@s@s@s@ss@sEE!/!HHHGH/~O!OOGH!O~/~~~!,OOOH!HG!!H,OOOGOOOOO,!~+//`/K+~`//!!!!!!!~!OG~~~!!////H!!~,O,OGO,O!~~,~!,H,!~!~~/`,OOOOGOOO$OBBI0IcccIccc=IcIcccccccIcc===cc====cIc=c=====Icc=ccccc==oSj&h&&j&&&&&j$O,$O,,E,,$,,,,,,,,,E,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,+,,,,,,,,,+,+y`,++y`,,+y`+yy,`y`+yyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$E$$$E$E$E$$E$$$$qEEE$E$$EEqEEwwwwwqEEEEEEEEEEEEqEEEEqEEqwww", "ssssssssss@$$s$s$O,G!G!GO~`~HOO!!!!OG!H!!!!,~!HGOOOOGGOOGOO,OGGG!!GO,O!G,O!HGG!HHOOG!!H!!33!3!!!!!~!!!H!~!~3!H!,!!!O!,~~/~//~~~!GO!~~~////!O,G,!~!O!,OOOG!~$$B0I0ccccIccI=cc=cc=cccccccccccIccccc==cccIcI====0Slj&&&&&&&&j&$,$O$$OE,,,,,,,,,O$,,,,,,,,,OE,,O$OE,,,,,,,,,,,,+,,,,,,,++,,,++,,,,,,,,,`,,,y`y`yy,+`yy+y+y+y+yy,$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$E$$$$$E$q$EEq$EEE$EEEEEEEEqEEEqqEEEEqEEEEEwwwqEqwqw", "s$ssO$OOO,GHOOO!!OOO!HH~/OG!!~~~~!!!!~!GOGH!HGGOOG!HOOOOOG!!!!!!!!~~!!!GG!!GOO!!~HHHHHGGGGOGH!~!,H!!!!,!G!~~~/~~!!!~~~~~/~~~~~!~~~!G!!!~//`/~!OG!~,~!~~/+~K,OOOOOO$$B00cIcccccc=IcIccIc=IccccIcccccccIcc=cccc0ZZZjjZjj&&&&&$O,$,,E,$O,$O,,,,$,$O,,,,,$O$,,,E,,EO,EO,,,,,,,,,,,,,,,,,,,+,,,+,,++,,,yy,,,,,,,,,+yy`,`y,y`,yy`yyyyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$Esw$$$qw$E$$$$$qqEwwE$E$EEqwqEqqEEEEEEqqqqE", ",,,,,,y,,y,```yy,,y,,+y,,,,,,,,,,,,+,,,,,,,,,,,,,,,+,,,y,yy,,,y,y,y,+y,yy,yy`yyyyyy$$$$$$$$$$$$$$$$$$$$$$$sq$$$$$$$$$$ws$$$$$$q$$$E$$$w$$$EEqE$wqEE$ww$EEqwEEEEE", "OOH!/~~~!OHHG,OOOOOOG,!OOOOOOOOOOOOOOOOH!~~////~~~H,GOOG`yyy`y`yy+y+`y++``y+y+``y++`>`y`yy`yy+y,yyy`>+y+y+y+`y,,,,,,,,,y,y,,,,,,y+,,y,,yy+,y,y,yyyyyyyy`>yyyyy$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$sqs$$$$$$$$q$$$wq$$sq$q$$w$wq", "~~HOOOOOOOOOOOOGH!,~~!!!OOOOOGHHH`yyyyy`y+y`yy,y+yy`yy`y`y`+++yy`+y+y`y+y`+y``+y``+y``+y+y`yy`y`y,y`+y,+,+,,y,y,+,yyyyy,y,y,,y+y,+yyyyyyyyyyyyEyw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ws$$$$$$$$q$$$$qsq$q", "OH!!OOOOGHOOOO!HHGOOOOOOH,!~~!GOOOOOOOOOOOH!HGOOH!!!!!!!!H!!!~!~!~!!!!~~K/~!!!H~/~//~!!GOOOGOOOH!~~3HHOOOOOGGH!~//~~~//~!HGHHH!!!!!!~~!!!HH!3KK~!!3~!OGOH!~!~!,!~H33~~~!,//~!~/!G~~~,!`,!OOO,O0cCCSZCCZSZCSlZCZCZZCCZCZCCZl$wyyyyyyyy`yyy`yyy+`>+`yyyy`yy,yy,`y+`y`y+y``yg,+y`y+y+y+``y,`y`y+y+y`y+y+y`yy,,,E,,y+y+,,y,y,yy,E,yy,yyyyyyyyyyyy>qy$$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$q$$$$$$$$$$$qs$$$$qsws$$sqsqs$$$$", "!!~!!OOHO,!!G,~~!!OOOOOOOOOOOOOGOOOOOOOOOOOOOOOOGH!!H!HO!HH!!~~~!!!!3~~K~K33~~~~///~~!!!!HG`yyyy`yyyyy``y`+y```yyy+y``y`++y``gy+yyyygyyy+y,y,,yy,y,,,y,y,yy,yy,yyyyy,yy>yyyywyw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$$$$$q$$", "K///`/`////~~H!!H!!HGOOOOOOOOOO!~~~!!GOOGHHH,G!~~~H!HGGGHG!HH!!3~~~!!!!!!!!!~!~~~~~~~~/~~HH!3!HGGOOOH`y`yyy`y`yyyyyy`y,y`>+y`yg``yyy+y`yy`yy`yyy`>`yy`yyyyyyyyyy+gy`y,,y+y`yy,yy+,E,E,E,y,yyy,y,y,yyyyEyyyyyyyy>ywwww$$$$qs$$$$$$$$$$$$$$$$$$$$q$$$$$$$$s$$$$ws$$$ws$$$$$$$$$$", "33~K~~K~3y>yy>`>y>yyyyyy,yyyy,yyyyy``y`y`y`yy``yy`yyyyyyyyy+y,yyy,y+y+y+y,yyyy`y`y`ygyyyyyyy,yy,y,y,y,yyyyyyEy,yyyyyEEyyEyyy>ywqqq$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$Esq$$$w$$$$$$$$", "OOGHGGOOGHH!HOOOOOOOOOOOGOOOH!HGHHH!HGOOO!~~~~~!~!OOOHHH!,3!!!!~~3!!GOGOOH3/~~33!!!!GOOGH!~~~///K~3K~~~~!GO!!`yyyyygyy>gyyyyyyyyyy,yyyyy>yyyyyyyy`yyy+y``y+y+y`yy+yy+yyy+yy+y``yyyyyyy,y`yyy`yyyy,yyyyyE,y,E,E,EyyEyyE`yyEyEywyEywywwww$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ws$s$$$$$$", "GHyy>`wyyyy>`yy`yyyyyyy,yyyyy`y,yy+yyyyyyyyy,yy,yyyyyyyyyyy,yyy`yyyyyy`>`yy`yyyyyyyyyyyyyyyyyyyyyyEyy,E,E,EyyE,EyyEyyyEEyqyw>yqw>qE$B$$$$$$$$$$$$$sq$$$$$$$$$$$$$$$q$$$$$$$$$$$$$$$", "OOOOOG<<ywyyyyyy>`>yyyyyyyyyyyyyyyyy,yyy,yyy,yyyyyyyyyyy``>,yyy,yyyyy,yyyyyyyyyyyy,yyyyyyyyyyyyyy>`>ygyyyyyyEyyE,EyEyqyyEyyyyqwywwwEwwwwwE$$$$$$$$$$$$$$$$$q$$$$$$$$$$ws$$$$$$$$$$$$$$$", "H!<222~333yyyyyyyyyyyyyyyyyyyyyyyyyyyyy>`>yyyyyyEyEwyywywwyEwwywyqwww>Eqwwq$$$$$$$$$$$$$$$sw$$$$$$$$$$$$$$$$$$sqsws$", "2322!HOOOOOH!ywyyEyy>yyyyyyyyEy>yyyyyyyy,E,Ey>`yyyyyyy,y>`wyyyyyyyy,yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyEyyyyyy>ywywyEyyEEEyqqyqyqywEqEywqw>wwwwqw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$$$$$", "OOOOOGH!!23!wyyy>wyy>>EyEyyyyEE,EyyEyyyEyyyyyyyyyyyy`yyyyyyyyyyyyyyyyyE,yyyyyyyyy>yyyyyyyyyyyyyyyyyyyyyyyywywyyyywyyyyyyyEyEyEEqEEEwwwqwqEwwwwww$>$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$q$$$", "HH<yyEyyE,y>`wyyyyyyEyyqyyqyEqyqyw>yqywywyyqqq>wwqywEEEEqEEEywqEEwwwwww>www>$sw$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "GGGHHHHHHyqyywyyEqyyEEyyyyyEEyyyEyEyyEEyyyEyyyyEyy,yyEyyyy>yyy+>yyyyyyyyqyyyy>yEyEwyyqyyyqyyqyyyyqywywqwywyywywywywyEqyEqwEqwwEqww$q>qsqwqPqs$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "OOOOOGHGOOOGHGHHyqyw>ywqywyqyywyqywywyyyEyE,qEyyEyyyyyEyyyyE,EE,yyyyyyyyyyyyyyyyyywyy>ywy>`wyEywyywEyyqyywwqEywqyqyqwqqqwwwq>wwqqwwqEqwwEEwqqqqwwwww>wsqs$$$$$$$$$$$$$$$$$$$$$$$$$$$$sq", "OOOOOOOGHHGOOOOOOOOOOOOOOOOGHH!2~K~3332<22<<ywyywyyqywyyyEyyEqEyyEEyEywyyEy>y>>yEEEqyEEqywyEyy>y>yyywyyEyqy>yEEqywqEywywqywqwywyqwww>wwwwwwwww>wwqwqw$E$w$Esw$qsw$qsws$$$$$$$$$$$$$$$$$$$$$$$$$$$", "KK~2HGGGOOOHOOOOOHH!!!HOOOOOOOH>yyyyyq,EyyyyqEEyEyEyEyyyyyyEyEyEyywyyEyEyyEywyqEEyEEyEywyqqywwywwywwqqqwwwyqqywqwqwwww>qqwqqqwEEEqEqE$wwq$>wswsws$s$$$$$$$$$$$$$$$$$$$$$ws", "~22wwwwwwwqwwwwwEwwwwEwwEqwwqwwqww$E$w$Esqsq$Esqs>qwsw$$$$$B$$$$$$$$$$$$$$$", "~22wEyEEEEEEEqywwyqywyEEEyqyqEEwyqEEyqEEywEyqEEEyEEyEEEyqyEwqyqyEyqqywqEEwwyqEwyEEqqqw>>yEw>wqww>w>wqw>Ewqwwwww$wswwwww>w$>sEs$$w$$qswssws$$$$$$$$$$$$$$$$$$$", "wwwqEEEEwwwwwqwwwwwwwwq>wEqwwqwqwwsqwwwwws$sqswwwEsw$sw$sw$qw$wsw$$$$$$$$$$$$$$$$", "GOOOOOOGOGGGHH!232!22wwwEEEqqqqqw>w>wqqwwEEqEEEEqEqqEEqqqEqqEwwwwEEwqEEEEEEEwqEqEqEwwwqqqwwqwwwwqEqwwwEqqEwqE$wwsw$wswq$ws>swqwsq$sws$$q$swsws$swswswsq$$$$$$$$$$$$$", "OOOOOOOOHH!33qEEqqwwywwy>>yqEqqwqqEqEEEEEEEEEqEEEqEqwwwEwwEEEqwwqEwwwwEqEEqEqEEwwqqwwqEwEwwEwqq$qwwq$Eww$wwEsw$wswwsqswsqswsqs$$$s$sw$sqsqsqs>$sw$$$$$$$$$", "OOOGHHwEEwwwqEEwwqEEEEqEEwqww$Ew>wwwwsE$wwwsws>sww$wsws$wsqs>w$ws>$wswqwssw$qsw$$w$swswsq$$$$$$", "sws$sws$s$qs$swswEswswsw$$$s", "HHGGGGGOOGGHHHHGOOOOOGOHHs$qs$q$wswwswswswsqs$qq$swswswsswsswsqsws$$ws$$qwssw$s", "OOOOOOOOOHHHHHGHH<<$wssE", "OOOOOOOGOOOOOOOOOOGOOOOH<<2!$sq$s$$$swsqsswsw$swsqsqsw$sqwsqsqsws$sq$sw$w$", "OOOOOOOOOOOOOOOOOOOOOH22!<q$$$E$$$w$$$$q$$$q$$E$ws$q$sqs$$sE$q$$ss$sws$$$$s$sqsww$sEswsEsqswsqswPwsws$qsqsqsws>sqsq>sws>$s$sq", "OOOOOOOOOOOOOOOOGH!<<<<swsswswswsqsqsqswswsq", "OOOOOOOOOOOOGH$ws$sqsqswswsqsqsws", "OOOOOOOOOOOGGGOOOOOOOH<<$s$$$q$$$s$$$$$wsq$q$Eswsw$qsw$$$$$sw$sq$$qsqsqsw$s$s$wPws$q$$ssEs$$q$$Eswswsw$$w$ws$qsqwsw$$swsq$$wsqsq" }; nethack-3.4.3/win/X11/tile2x11.c0100644000000000000000000001322007764735041014533 0ustar rootroot/* * Convert the given input files into an output file that is expected * by nethack. * * Assumptions: * + Two dimensional byte arrays are in row order and are not padded * between rows (x11_colormap[][]). */ #include "hack.h" /* for MAX_GLYPH */ #include "tile.h" #include "tile2x11.h" /* x11 output file header structure */ #define OUTNAME "x11tiles" /* output file name */ /* #define PRINT_COLORMAP */ /* define to print the colormap */ x11_header header; unsigned char tile_bytes[TILE_X*TILE_Y*(MAX_GLYPH+TILES_PER_ROW)]; unsigned char *curr_tb = tile_bytes; unsigned char x11_colormap[MAXCOLORMAPSIZE][3]; /* Look up the given pixel and return its colormap index. */ static unsigned char pix_to_colormap(pix) pixel pix; { int i; for (i = 0; i < header.ncolors; i++) { if (pix.r == ColorMap[CM_RED][i] && pix.g == ColorMap[CM_GREEN][i] && pix.b == ColorMap[CM_BLUE][i]) break; } if (i == header.ncolors) { Fprintf(stderr, "can't find color: [%u,%u,%u]\n", pix.r, pix.g, pix.b); exit(1); } return (unsigned char) (i & 0xFF); } /* Convert the tiles in the file to our format of bytes. */ static unsigned long convert_tiles(tb_ptr, total) unsigned char **tb_ptr; /* pointer to a tile byte pointer */ unsigned long total; /* total tiles so far */ { unsigned char *tb = *tb_ptr; unsigned long count = 0; pixel tile[TILE_Y][TILE_X]; int x, y; while (read_text_tile(tile)) { count++; total++; for (y = 0; y < TILE_Y; y++) { for (x = 0; x < TILE_X; x++) tb[x] = pix_to_colormap(tile[y][x]); tb += TILE_X * header.per_row; } /* repoint at the upper-left corner of the next tile */ *tb_ptr += TILE_X; if (header.per_row == 1 || (total % header.per_row) == 0) *tb_ptr += TILE_X * (TILE_Y - 1) * header.per_row; tb = *tb_ptr; } return count; } /* Merge the current text colormap (ColorMap) with ours (x11_colormap). */ static void merge_text_colormap() { int i, j; for (i = 0; i < colorsinmap; i++) { for (j = 0; j < header.ncolors; j++) if (x11_colormap[j][CM_RED] == ColorMap[CM_RED][i] && x11_colormap[j][CM_GREEN] == ColorMap[CM_GREEN][i] && x11_colormap[j][CM_BLUE] == ColorMap[CM_BLUE][i]) break; if (j >= MAXCOLORMAPSIZE) { Fprintf(stderr, "colormap overflow\n"); exit(1); } if (j == header.ncolors) { /* couldn't find it */ #ifdef PRINT_COLORMAP printf("color %2d: %3d %3d %3d\n", header.ncolors, ColorMap[CM_RED][i], ColorMap[CM_GREEN][i], ColorMap[CM_BLUE][i]); #endif x11_colormap[j][CM_RED] = ColorMap[CM_RED][i]; x11_colormap[j][CM_GREEN] = ColorMap[CM_GREEN][i]; x11_colormap[j][CM_BLUE] = ColorMap[CM_BLUE][i]; header.ncolors++; } } } /* Open the given file, read & merge the colormap, convert the tiles. */ static void process_file(fname) char *fname; { unsigned long count; if (!fopen_text_file(fname, RDTMODE)) { Fprintf(stderr, "can't open file \"%s\"\n", fname); exit(1); } merge_text_colormap(); count = convert_tiles(&curr_tb, header.ntiles); Fprintf(stderr, "%s: %lu tiles\n", fname, count); header.ntiles += count; fclose_text_file(); } #ifdef USE_XPM static int xpm_write(fp) FILE *fp; { int i, j, n; if (header.ncolors > 64) { Fprintf(stderr, "Sorry, only configured for up to 64 colors\n"); exit(1); /* All you need to do is add more char per color - below */ } Fprintf(fp, "/* XPM */\n"); Fprintf(fp, "static char* nhtiles[] = {\n"); Fprintf(fp, "\"%lu %lu %lu %d\",\n", header.tile_width*header.per_row, (header.tile_height*header.ntiles)/header.per_row, header.ncolors, 1 /* char per color */); for (i = 0; i < header.ncolors; i++) Fprintf(fp, "\"%c c #%02x%02x%02x\",\n", i+'0', /* just one char per color */ x11_colormap[i][0], x11_colormap[i][1], x11_colormap[i][2]); n = 0; for (i = 0; i < (header.tile_height*header.ntiles)/header.per_row; i++) { Fprintf(fp, "\""); for (j = 0; j < header.tile_width*header.per_row; j++) { /* just one char per color */ fputc(tile_bytes[n++]+'0', fp); } Fprintf(fp, "\",\n"); } return fprintf(fp, "};\n") >= 0; } #endif /* USE_XPM */ int main(argc, argv) int argc; char **argv; { FILE *fp; int i; header.version = 2; /* version 1 had no per_row field */ header.ncolors = 0; header.tile_width = TILE_X; header.tile_height = TILE_Y; header.ntiles = 0; /* updated as we read in files */ header.per_row = TILES_PER_ROW; if (argc == 1) { Fprintf(stderr, "usage: %s txt_file1 [txt_file2 ...]\n", argv[0]); exit(1); } fp = fopen(OUTNAME, "w"); if (!fp) { Fprintf(stderr, "can't open output file\n"); exit(1); } /* don't leave garbage at end of partial row */ (void) memset((genericptr_t)tile_bytes, 0, sizeof(tile_bytes)); for (i = 1; i < argc; i++) process_file(argv[i]); Fprintf(stderr, "Total tiles: %ld\n", header.ntiles); /* round size up to the end of the row */ if ((header.ntiles % header.per_row) != 0) { header.ntiles += header.per_row - (header.ntiles % header.per_row); } #ifdef USE_XPM if (xpm_write(fp) == 0) { Fprintf(stderr, "can't write XPM file\n"); exit(1); } #else if (fwrite((char *)&header, sizeof(x11_header), 1, fp) == 0) { Fprintf(stderr, "can't open output header\n"); exit(1); } if (fwrite((char *)x11_colormap, 1, header.ncolors*3, fp) == 0) { Fprintf(stderr, "can't write output colormap\n"); exit(1); } if (fwrite((char *)tile_bytes, 1, (int) header.ntiles*header.tile_width*header.tile_height, fp) == 0) { Fprintf(stderr, "can't write tile bytes\n"); exit(1); } #endif fclose(fp); return 0; } nethack-3.4.3/win/X11/winX.c0100644000000000000000000016107307764735041014121 0ustar rootroot/* SCCS Id: @(#)winX.c 3.4 1999/12/21 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * "Main" file for the X window-port. This contains most of the interface * routines. Please see doc/window.doc for an description of the window * interface. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #ifdef MSDOS /* from compiler */ #define SHORT_FILENAMES #endif #include #include #include #include #include #include #include #include #include #include #include /* for color support */ #ifdef SHORT_FILENAMES #include #else #include #endif #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #ifdef SHORT_FILENAMES #undef SHORT_FILENAMES /* hack.h will reset via global.h if necessary */ #endif #include "hack.h" #include "winX.h" #include "dlb.h" #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif /* Should be defined in but you never know */ #ifndef XtSpecificationRelease #define XtSpecificationRelease 0 #endif /* * Icons. */ #include "../win/X11/nh72icon" #include "../win/X11/nh56icon" #include "../win/X11/nh32icon" static struct icon_info { const char *name; unsigned char *bits; unsigned width, height; } icon_data[] = { { "nh72", nh72icon_bits, nh72icon_width, nh72icon_height }, { "nh56", nh56icon_bits, nh56icon_width, nh56icon_height }, { "nh32", nh32icon_bits, nh32icon_width, nh32icon_height }, { (const char *)0, (unsigned char *)0, 0, 0 } }; /* * Private global variables (shared among the window port files). */ struct xwindow window_list[MAX_WINDOWS]; AppResources appResources; void FDECL((*input_func), (Widget,XEvent *,String *,Cardinal *)); int click_x, click_y, click_button; /* Click position on a map window */ /* (filled by set_button_values()). */ int updated_inventory; /* Interface definition, for windows.c */ struct window_procs X11_procs = { "X11", WC_COLOR|WC_HILITE_PET, 0L, X11_init_nhwindows, X11_player_selection, X11_askname, X11_get_nh_event, X11_exit_nhwindows, X11_suspend_nhwindows, X11_resume_nhwindows, X11_create_nhwindow, X11_clear_nhwindow, X11_display_nhwindow, X11_destroy_nhwindow, X11_curs, X11_putstr, X11_display_file, X11_start_menu, X11_add_menu, X11_end_menu, X11_select_menu, genl_message_menu, /* no need for X-specific handling */ X11_update_inventory, X11_mark_synch, X11_wait_synch, #ifdef CLIPPING X11_cliparound, #endif #ifdef POSITIONBAR donull, #endif X11_print_glyph, X11_raw_print, X11_raw_print_bold, X11_nhgetch, X11_nh_poskey, X11_nhbell, X11_doprev_message, X11_yn_function, X11_getlin, X11_get_ext_cmd, X11_number_pad, X11_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif /* other defs that really should go away (they're tty specific) */ X11_start_screen, X11_end_screen, #ifdef GRAPHIC_TOMBSTONE X11_outrip, #else genl_outrip, #endif genl_preference_update, }; /* * Local functions. */ static void FDECL(dismiss_file, (Widget, XEvent*, String*, Cardinal*)); static void FDECL(delete_file, (Widget, XEvent*, String*, Cardinal*)); static void FDECL(yn_key, (Widget, XEvent*, String*, Cardinal*)); static void FDECL(yn_delete, (Widget, XEvent*, String*, Cardinal*)); static void FDECL(askname_delete, (Widget, XEvent*, String*, Cardinal*)); static void FDECL(getline_delete, (Widget, XEvent*, String*, Cardinal*)); static void FDECL(X11_hangup, (Widget, XEvent*, String*, Cardinal*)); static int FDECL(input_event, (int)); static void FDECL(win_visible, (Widget,XtPointer,XEvent *,Boolean *)); static void NDECL(init_standard_windows); /* * Local variables. */ static boolean x_inited = FALSE; /* TRUE if window system is set up. */ static winid message_win = WIN_ERR, /* These are the winids of the */ map_win = WIN_ERR, /* message, map, and status */ status_win = WIN_ERR; /* windows, when they are created */ /* in init_windows(). */ static Pixmap icon_pixmap = None; /* Pixmap for icon. */ /* * Find the window structure that corresponds to the given widget. Note * that this is not the popup widget, nor the viewport, but the child. */ struct xwindow * find_widget(w) Widget w; { int windex; struct xwindow *wp; /* Search to find the corresponding window. Look at the main widget, */ /* popup, the parent of the main widget, then parent of the widget. */ for (windex = 0, wp = window_list; windex < MAX_WINDOWS; windex++, wp++) if (wp->type != NHW_NONE && (wp->w == w || wp->popup == w || (wp->w && (XtParent(wp->w)) == w) || (wp->popup == XtParent(w)))) break; if (windex == MAX_WINDOWS) panic("find_widget: can't match widget"); return wp; } /* * Find a free window slot for use. */ static winid find_free_window() { int windex; struct xwindow *wp; for (windex = 0, wp = &window_list[0]; windex < MAX_WINDOWS; windex++, wp++) if (wp->type == NHW_NONE) break; if (windex == MAX_WINDOWS) panic("find_free_window: no free windows!"); return (winid) windex; } /* * Color conversion. The default X11 color converters don't try very * hard to find matching colors in PseudoColor visuals. If they can't * allocate the exact color, they puke and give you something stupid. * This is an attempt to find some close readonly cell and use it. */ XtConvertArgRec const nhcolorConvertArgs[] = { {XtWidgetBaseOffset, (XtPointer)XtOffset(Widget, core.screen), sizeof(Screen *)}, {XtWidgetBaseOffset, (XtPointer)XtOffset(Widget, core.colormap), sizeof(Colormap)} }; #define done(type, value) \ { \ if (toVal->addr != 0) { \ if (toVal->size < sizeof(type)) { \ toVal->size = sizeof(type); \ return False; \ } \ *(type*)(toVal->addr) = (value); \ } \ else { \ static type static_val; \ static_val = (value); \ toVal->addr = (genericptr_t)&static_val; \ } \ toVal->size = sizeof(type); \ return True; \ } /* decl.h declares these, but it screws up structure references -dlc */ #undef red #undef green #undef blue /* * Find a color that approximates the color named in "str". The "str" color * may be a color name ("red") or number ("#7f0000"). If str == NULL, then * "color" is assumed to contain the RGB color wanted. * The approximate color found is returned in color as well. * Return True if something close was found. */ Boolean nhApproxColor(screen, colormap, str, color) Screen *screen; /* screen to use */ Colormap colormap; /* the colormap to use */ char *str; /* color name */ XColor *color; /* the X color structure; changed only if successful */ { int ncells; long cdiff = 16777216; /* 2^24; hopefully our map is smaller */ XColor tmp; static XColor *table = 0; register int i, j; register long tdiff; /* if the screen doesn't have a big colormap, don't waste our time */ /* or if it's huge, and _some_ match should have been possible */ if((ncells = CellsOfScreen(screen)) < 256 || ncells > 4096) return False; if (str != (char *)0) { if (!XParseColor(DisplayOfScreen(screen), colormap, str, &tmp)) return False; } else { tmp = *color; tmp.flags = 7; /* force to use all 3 of RGB */ } if (!table) { table = (XColor *) XtCalloc(ncells, sizeof(XColor)); for(i=0; iaddr; XColor screenColor; XColor exactColor; Screen *screen; XtAppContext app = XtDisplayToApplicationContext(dpy); Colormap colormap; Status status; String params[1]; Cardinal num_params=1; if (*num_args != 2) { XtAppWarningMsg(app, "wrongParameters", "cvtStringToPixel", "XtToolkitError", "String to pixel conversion needs screen and colormap arguments", (String *)0, (Cardinal *)0); return False; } screen = *((Screen **) args[0].addr); colormap = *((Colormap *) args[1].addr); /* If Xt colors, use the Xt routine and hope for the best */ #if (XtSpecificationRelease >= 5) if ((strcmpi(str, XtDefaultBackground) == 0) || (strcmpi(str, XtDefaultForeground) == 0)) { return XtCvtStringToPixel(dpy, args, num_args, fromVal, toVal, closure_ret); } #else if (strcmpi(str, XtDefaultBackground) == 0) { *closure_ret = (char*)False; done(Pixel, WhitePixelOfScreen(screen)); } if (strcmpi(str, XtDefaultForeground) == 0) { *closure_ret = (char*)False; done(Pixel, BlackPixelOfScreen(screen)); } #endif status = XAllocNamedColor(DisplayOfScreen(screen), colormap, (char*)str, &screenColor, &exactColor); if (status == 0) { String msg, type; /* some versions of XAllocNamedColor don't allow #xxyyzz names */ if (str[0] == '#' && XParseColor(DisplayOfScreen(screen), colormap, str, &exactColor) && XAllocColor(DisplayOfScreen(screen), colormap, &exactColor)) { *closure_ret = (char*)True; done(Pixel, exactColor.pixel); } params[0] = str; /* Server returns a specific error code but Xlib discards it. Ugh */ if (XLookupColor(DisplayOfScreen(screen), colormap, (char*)str, &exactColor, &screenColor)) { /* try to find another color that will do */ if (nhApproxColor(screen, colormap, (char*) str, &screenColor)) { *closure_ret = (char*)True; done(Pixel, screenColor.pixel); } type = "noColormap"; msg = "Cannot allocate colormap entry for \"%s\""; } else { /* some versions of XLookupColor also don't allow #xxyyzz names */ if(str[0] == '#' && (nhApproxColor(screen, colormap, (char*) str, &screenColor))) { *closure_ret = (char*)True; done(Pixel, screenColor.pixel); } type = "badValue"; msg = "Color name \"%s\" is not defined"; } XtAppWarningMsg(app, type, "cvtStringToPixel", "XtToolkitError", msg, params, &num_params); *closure_ret = False; return False; } else { *closure_ret = (char*)True; done(Pixel, screenColor.pixel); } } /* ARGSUSED */ static void nhFreePixel(app, toVal, closure, args, num_args) XtAppContext app; XrmValuePtr toVal; XtPointer closure; XrmValuePtr args; Cardinal *num_args; { Screen *screen; Colormap colormap; if (*num_args != 2) { XtAppWarningMsg(app, "wrongParameters", "freePixel", "XtToolkitError", "Freeing a pixel requires screen and colormap arguments", (String *)0, (Cardinal *)0); return; } screen = *((Screen **) args[0].addr); colormap = *((Colormap *) args[1].addr); if (closure) { XFreeColors( DisplayOfScreen(screen), colormap, (unsigned long*)toVal->addr, 1, (unsigned long)0 ); } } /* [ALI] Utility function to ask Xaw for font height, since the previous * assumption of ascent + descent is not always valid. */ Dimension nhFontHeight(w) Widget w; #ifdef _XawTextSink_h { Widget sink; XawTextPosition pos = 0; int resWidth, resHeight; Arg args[1]; XtSetArg(args[0], XtNtextSink, &sink); XtGetValues(w, args, 1); XawTextSinkFindPosition(sink, pos, 0, 0, 0, &pos, &resWidth, &resHeight); return resHeight; } #else { XFontStruct *fs; Arg args[1]; XtSetArg(args[0], XtNfont, &fs); XtGetValues(w, args, 1); /* Assume font height is ascent + descent. */ return = fs->ascent + fs->descent; } #endif /* Global Functions ======================================================== */ void X11_raw_print(str) const char *str; { (void) puts(str); } void X11_raw_print_bold(str) const char *str; { (void) puts(str); } void X11_curs(window, x, y) winid window; int x, y; { check_winid(window); if (x < 0 || x >= COLNO) { impossible("curs: bad x value [%d]", x); x = 0; } if (y < 0 || y >= ROWNO) { impossible("curs: bad y value [%d]", y); y = 0; } window_list[window].cursx = x; window_list[window].cursy = y; } void X11_putstr(window, attr, str) winid window; int attr; const char *str; { winid new_win; struct xwindow *wp; check_winid(window); wp = &window_list[window]; switch (wp->type) { case NHW_MESSAGE: (void) strncpy(toplines, str, TBUFSZ); /* for Norep(). */ toplines[TBUFSZ - 1] = 0; append_message(wp, str); break; case NHW_STATUS: adjust_status(wp, str); break; case NHW_MAP: impossible("putstr: called on map window \"%s\"", str); break; case NHW_MENU: if (wp->menu_information->is_menu) { impossible( "putstr: called on a menu window, \"%s\" discarded", str); break; } /* * Change this menu window into a text window by creating a * new text window, then copying it to this winid. */ new_win = X11_create_nhwindow(NHW_TEXT); X11_destroy_nhwindow(window); *wp = window_list[new_win]; window_list[new_win].type = NHW_NONE; /* allow re-use */ /* fall though to add text */ case NHW_TEXT: add_to_text_window(wp, attr, str); break; default: impossible("putstr: unknown window type [%d] \"%s\"", wp->type, str); } } /* We do event processing as a callback, so this is a null routine. */ void X11_get_nh_event() { return; } int X11_nhgetch() { return input_event(EXIT_ON_KEY_PRESS); } int X11_nh_poskey(x, y, mod) int *x, *y, *mod; { int val = input_event(EXIT_ON_KEY_OR_BUTTON_PRESS); if (val == 0) { /* user clicked on a map window */ *x = click_x; *y = click_y; *mod = click_button; } return val; } winid X11_create_nhwindow(type) int type; { winid window; struct xwindow *wp; if (!x_inited) panic("create_nhwindow: windows not initialized"); /* * We have already created the standard message, map, and status * windows in the window init routine. The first window of that * type to be created becomes the standard. * * A better way to do this would be to say that init_nhwindows() * has already defined these three windows. */ if (type == NHW_MAP && map_win != WIN_ERR) { window = map_win; map_win = WIN_ERR; return window; } if (type == NHW_MESSAGE && message_win != WIN_ERR) { window = message_win; message_win = WIN_ERR; return window; } if (type == NHW_STATUS && status_win != WIN_ERR) { window = status_win; status_win = WIN_ERR; return window; } window = find_free_window(); wp = &window_list[window]; /* The create routines will set type, popup, w, and Win_info. */ wp->prevx = wp->prevy = wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; wp->keep_window = FALSE; switch (type) { case NHW_MAP: create_map_window(wp, TRUE, (Widget) 0); break; case NHW_MESSAGE: create_message_window(wp, TRUE, (Widget) 0); break; case NHW_STATUS: create_status_window(wp, TRUE, (Widget) 0); break; case NHW_MENU: create_menu_window(wp); break; case NHW_TEXT: create_text_window(wp); break; default: panic("create_nhwindow: unknown type [%d]", type); break; } return window; } void X11_clear_nhwindow(window) winid window; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; switch (wp->type) { case NHW_MAP: clear_map_window(wp); break; case NHW_TEXT: clear_text_window(wp); break; case NHW_STATUS: case NHW_MENU: case NHW_MESSAGE: /* do nothing for these window types */ break; default: panic("clear_nhwindow: unknown window type [%d]", wp->type); break; } } void X11_display_nhwindow(window, blocking) winid window; boolean blocking; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; switch (wp->type) { case NHW_MAP: if (wp->popup) nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w); display_map_window(wp); /* flush map */ /* * We need to flush the message window here due to the way the tty * port is set up. To flush a window, you need to call this * routine. However, the tty port _pauses_ with a --more-- if we * do a display_nhwindow(WIN_MESSAGE, FALSE). Thus, we can't call * display_nhwindow(WIN_MESSAGE,FALSE) in parse() because then we * get a --more-- after every line. * * Perhaps the window document should mention that when the map * is flushed, everything on the three main windows should be * flushed. Note: we don't need to flush the status window * because we don't buffer changes. */ if (WIN_MESSAGE != WIN_ERR) display_message_window(&window_list[WIN_MESSAGE]); if (blocking) (void) x_event(EXIT_ON_KEY_OR_BUTTON_PRESS); break; case NHW_MESSAGE: if (wp->popup) nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w); display_message_window(wp); /* flush messages */ break; case NHW_STATUS: if (wp->popup) nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w); break; /* no flushing necessary */ case NHW_MENU: { int n; menu_item *selected; /* pop up menu */ n = X11_select_menu(window, PICK_NONE, &selected); if (n) { impossible("perminvent: %d selected??", n); free((genericptr_t)selected); } break; } case NHW_TEXT: display_text_window(wp, blocking); /* pop up text window */ break; default: panic("display_nhwindow: unknown window type [%d]", wp->type); break; } } void X11_destroy_nhwindow(window) winid window; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; /* * "Zap" known windows, but don't destroy them. We need to keep the * toplevel widget popped up so that later windows (e.g. tombstone) * are visible on DECWindow systems. This is due to the virtual * roots that the DECWindow wm creates. */ if (window == WIN_MESSAGE) { wp->keep_window = TRUE; WIN_MESSAGE = WIN_ERR; iflags.window_inited = 0; } else if (window == WIN_MAP) { wp->keep_window = TRUE; WIN_MAP = WIN_ERR; } else if (window == WIN_STATUS) { wp->keep_window = TRUE; WIN_STATUS = WIN_ERR; } else if (window == WIN_INVEN) { /* don't need to keep this one */ WIN_INVEN = WIN_ERR; } switch (wp->type) { case NHW_MAP: destroy_map_window(wp); break; case NHW_MENU: destroy_menu_window(wp); break; case NHW_TEXT: destroy_text_window(wp); break; case NHW_STATUS: destroy_status_window(wp); break; case NHW_MESSAGE: destroy_message_window(wp); break; default: panic("destroy_nhwindow: unknown window type [%d]", wp->type); break; } } void X11_update_inventory() { if (x_inited && window_list[WIN_INVEN].menu_information->is_up) { updated_inventory = 1; /* hack to avoid mapping&raising window */ (void) display_inventory((char *)0, FALSE); updated_inventory = 0; } } /* The current implementation has all of the saved lines on the screen. */ int X11_doprev_message() { return 0; } void X11_nhbell() { /* We can't use XBell until toplevel has been initialized. */ if (x_inited) XBell(XtDisplay(toplevel), 0); /* else print ^G ?? */ } void X11_mark_synch() { if (x_inited) { /* * The window document is unclear about the status of text * that has been pline()d but not displayed w/display_nhwindow(). * Both the main and tty code assume that a pline() followed * by mark_synch() results in the text being seen, even if * display_nhwindow() wasn't called. Duplicate this behavior. */ if (WIN_MESSAGE != WIN_ERR) display_message_window(&window_list[WIN_MESSAGE]); XSync(XtDisplay(toplevel), False); } } void X11_wait_synch() { if (x_inited) XFlush(XtDisplay(toplevel)); } /* Both resume_ and suspend_ are called from ioctl.c and unixunix.c. */ void X11_resume_nhwindows() { return; } /* ARGSUSED */ void X11_suspend_nhwindows(str) const char *str; { return; } /* Under X, we don't need to initialize the number pad. */ /* ARGSUSED */ void X11_number_pad(state) int state; { return; } /* called from options.c */ void X11_start_screen() { return; } /* called from setftty() in unixtty.c */ void X11_end_screen() { return; } /* called from settty() in unixtty.c */ #ifdef GRAPHIC_TOMBSTONE void X11_outrip(window, how) winid window; int how; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; if (wp->type == NHW_TEXT) { wp->text_information->is_rip = TRUE; } else { panic("ripout on non-text window (window type [%d])", wp->type); } calculate_rip_text(how); } #endif /* init and exit nhwindows ------------------------------------------------- */ XtAppContext app_context; /* context of application */ Widget toplevel = (Widget) 0; /* toplevel widget */ Atom wm_delete_window; /* pop down windows */ static XtActionsRec actions[] = { {"dismiss_file", dismiss_file}, /* action for file viewing widget */ {"delete_file", delete_file}, /* action for file delete-window */ {"dismiss_text", dismiss_text}, /* button action for text widget */ {"delete_text", delete_text}, /* delete action for text widget */ {"key_dismiss_text",key_dismiss_text},/* key action for text widget */ #ifdef GRAPHIC_TOMBSTONE {"rip_dismiss_text",rip_dismiss_text},/* action for rip in text widget */ #endif {"menu_key", menu_key}, /* action for menu accelerators */ {"yn_key", yn_key}, /* action for yn accelerators */ {"yn_delete", yn_delete}, /* action for yn delete-window */ {"askname_delete", askname_delete},/* action for askname delete-window */ {"getline_delete", getline_delete},/* action for getline delete-window */ {"menu_delete", menu_delete}, /* action for menu delete-window */ {"ec_key", ec_key}, /* action for extended commands */ {"ec_delete", ec_delete}, /* action for ext-com menu delete */ {"ps_key", ps_key}, /* action for player selection */ {"race_key", race_key}, /* action for race selection */ {"gend_key", gend_key}, /* action for gender selection */ {"algn_key", algn_key}, /* action for alignment selection */ {"X11_hangup", X11_hangup}, /* action for delete of top-level */ {"input", map_input}, /* action for key input */ {"scroll", nh_keyscroll}, /* action for scrolling by keys */ }; static XtResource resources[] = { { "slow", "Slow", XtRBoolean, sizeof(Boolean), XtOffset(AppResources *,slow), XtRString, "True" }, { "autofocus", "AutoFocus", XtRBoolean, sizeof(Boolean), XtOffset(AppResources *,autofocus), XtRString, "False" }, { "message_line", "Message_line", XtRBoolean, sizeof(Boolean), XtOffset(AppResources *,message_line), XtRString, "False" }, { "double_tile_size", "Double_tile_size", XtRBoolean, sizeof(Boolean), XtOffset(AppResources *,double_tile_size), XtRString, "False" }, { "tile_file", "Tile_file", XtRString, sizeof(String), XtOffset(AppResources *,tile_file), XtRString, "" }, { "icon", "Icon", XtRString, sizeof(String), XtOffset(AppResources *,icon), XtRString, "nh72" }, { "message_lines", "Message_lines", XtRInt, sizeof(int), XtOffset(AppResources *,message_lines), XtRString, "12" }, { "pet_mark_bitmap", "Pet_mark_bitmap", XtRString, sizeof(String), XtOffset(AppResources *,pet_mark_bitmap), XtRString, "pet_mark.xbm" }, { "pet_mark_color", "Pet_mark_color", XtRPixel, sizeof(XtRPixel), XtOffset(AppResources *,pet_mark_color), XtRString, "Red" }, #ifdef GRAPHIC_TOMBSTONE { "tombstone", "Tombstone", XtRString, sizeof(String), XtOffset(AppResources *,tombstone), XtRString, "rip.xpm" }, { "tombtext_x", "Tombtext_x", XtRInt, sizeof(int), XtOffset(AppResources *,tombtext_x), XtRString, "155" }, { "tombtext_y", "Tombtext_y", XtRInt, sizeof(int), XtOffset(AppResources *,tombtext_y), XtRString, "78" }, { "tombtext_dx", "Tombtext_dx", XtRInt, sizeof(int), XtOffset(AppResources *,tombtext_dx), XtRString, "0" }, { "tombtext_dy", "Tombtext_dy", XtRInt, sizeof(int), XtOffset(AppResources *,tombtext_dy), XtRString, "13" }, #endif }; void X11_init_nhwindows(argcp,argv) int* argcp; char** argv; { static const char *banner_text[] = { COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B, COPYRIGHT_BANNER_C, "", "", 0 }; register const char **pp; int i; Cardinal num_args; Arg args[4]; uid_t savuid; /* Init windows to nothing. */ for (i = 0; i < MAX_WINDOWS; i++) window_list[i].type = NHW_NONE; /* * setuid hack: make sure that if nethack is setuid, to use real uid * when opening X11 connections, in case the user is using xauth, since * the "games" or whatever user probably doesn't have permission to open * a window on the user's display. This code is harmless if the binary * is not installed setuid. See include/system.h on compilation failures. */ savuid = geteuid(); (void) seteuid(getuid()); XSetIOErrorHandler((XIOErrorHandler) hangup); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; toplevel = XtAppInitialize( &app_context, "NetHack", /* application class */ (XrmOptionDescList)0, 0, /* options list */ argcp, (String *)argv, /* command line args */ (String *)0, /* fallback resources */ (ArgList)args, num_args); XtOverrideTranslations(toplevel, XtParseTranslationTable("WM_PROTOCOLS: X11_hangup()")); /* We don't need to realize the top level widget. */ #ifdef TEXTCOLOR /* add new color converter to deal with overused colormaps */ XtSetTypeConverter(XtRString, XtRPixel, nhCvtStringToPixel, (XtConvertArgList)nhcolorConvertArgs, XtNumber(nhcolorConvertArgs), XtCacheByDisplay, nhFreePixel); #endif /* TEXTCOLOR */ /* Register the actions mentioned in "actions". */ XtAppAddActions(app_context, actions, XtNumber(actions)); /* Get application-wide resources */ XtGetApplicationResources(toplevel, (XtPointer)&appResources, resources, XtNumber(resources), (ArgList)0, ZERO); /* Initialize other things. */ init_standard_windows(); /* Give the window manager an icon to use; toplevel must be realized. */ if (appResources.icon && *appResources.icon) { struct icon_info *ip; for (ip = icon_data; ip->name; ip++) if (!strcmp(appResources.icon, ip->name)) { icon_pixmap = XCreateBitmapFromData(XtDisplay(toplevel), XtWindow(toplevel), (genericptr_t)ip->bits, ip->width, ip->height); if (icon_pixmap != None) { XWMHints hints; (void) memset((genericptr_t)&hints, 0, sizeof(XWMHints)); hints.flags = IconPixmapHint; hints.icon_pixmap = icon_pixmap; XSetWMHints(XtDisplay(toplevel), XtWindow(toplevel), &hints); } break; } } /* end of setuid hack: reset uid back to the "games" uid */ (void) seteuid(savuid); x_inited = TRUE; /* X is now initialized */ /* Display the startup banner in the message window. */ for (pp = banner_text; *pp; pp++) X11_putstr(WIN_MESSAGE, 0, *pp); } /* * All done. */ /* ARGSUSED */ void X11_exit_nhwindows(dummy) const char *dummy; { extern Pixmap tile_pixmap; /* from winmap.c */ /* explicitly free the icon and tile pixmaps */ if (icon_pixmap != None) { XFreePixmap(XtDisplay(toplevel), icon_pixmap); icon_pixmap = None; } if (tile_pixmap != None) { XFreePixmap(XtDisplay(toplevel), tile_pixmap); tile_pixmap = None; } if (WIN_INVEN != WIN_ERR) X11_destroy_nhwindow(WIN_INVEN); if (WIN_STATUS != WIN_ERR) X11_destroy_nhwindow(WIN_STATUS); if (WIN_MAP != WIN_ERR) X11_destroy_nhwindow(WIN_MAP); if (WIN_MESSAGE != WIN_ERR) X11_destroy_nhwindow(WIN_MESSAGE); } /* delay_output ------------------------------------------------------------ */ /* * Timeout callback for delay_output(). Send a fake message to the map * window. */ /* ARGSUSED */ static void d_timeout(client_data, id) XtPointer client_data; XtIntervalId *id; { XEvent event; XClientMessageEvent *mesg; /* Set up a fake message to the event handler. */ mesg = (XClientMessageEvent *) &event; mesg->type = ClientMessage; mesg->message_type = XA_STRING; mesg->format = 8; XSendEvent(XtDisplay(window_list[WIN_MAP].w), XtWindow(window_list[WIN_MAP].w), False, NoEventMask, (XEvent*) mesg); } /* * Delay for 50ms. This is not implemented asynch. Maybe later. * Start the timeout, then wait in the event loop. The timeout * function will send an event to the map window which will be waiting * for a sent event. */ void X11_delay_output() { if (!x_inited) return; (void) XtAppAddTimeOut(app_context, 30L, d_timeout, (XtPointer) 0); /* The timeout function will enable the event loop exit. */ (void) x_event(EXIT_ON_SENT_EVENT); } /* X11_hangup -------------------------------------------------------------- */ /* ARGSUSED */ static void X11_hangup(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { hangup(1); /* 1 is commonly SIGHUP, but ignored anyway */ } /* askname ----------------------------------------------------------------- */ /* ARGSUSED */ static void askname_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nh_XtPopdown(w); (void) strcpy(plname, "Mumbles"); /* give them a name... ;-) */ exit_x_event = TRUE; } /* Callback for askname dialog widget. */ /* ARGSUSED */ static void askname_done(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { int len; char *s; Widget dialog = (Widget) client_data; s = (char *) GetDialogResponse(dialog); len = strlen(s); if (len == 0) { X11_nhbell(); return; } /* Truncate name if necessary */ if (len >= sizeof(plname)-1) len = sizeof(plname)-1; (void) strncpy(plname, s, len); plname[len] = '\0'; XtFree(s); nh_XtPopdown(XtParent(dialog)); exit_x_event = TRUE; } void X11_askname() { Widget popup, dialog; Arg args[1]; XtSetArg(args[0], XtNallowShellResize, True); popup = XtCreatePopupShell("askname", transientShellWidgetClass, toplevel, args, ONE); XtOverrideTranslations(popup, XtParseTranslationTable("WM_PROTOCOLS: askname_delete()")); dialog = CreateDialog(popup, "dialog", askname_done, (XtCallbackProc) 0); SetDialogPrompt(dialog, "What is your name?"); /* set prompt */ SetDialogResponse(dialog, ""); /* set default answer */ XtRealizeWidget(popup); positionpopup(popup, TRUE); /* center,bottom */ nh_XtPopup(popup, (int)XtGrabExclusive, dialog); /* The callback will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); } /* getline ----------------------------------------------------------------- */ /* This uses Tim Theisen's dialog widget set (from GhostView). */ static Widget getline_popup, getline_dialog; #define CANCEL_STR "\033" static char *getline_input; /* Callback for getline dialog widget. */ /* ARGSUSED */ static void done_button(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { int len; char *s; Widget dialog = (Widget) client_data; s = (char *) GetDialogResponse(dialog); len = strlen(s); /* Truncate input if necessary */ if (len >= BUFSZ) len = BUFSZ - 1; (void) strncpy(getline_input, s, len); getline_input[len] = '\0'; XtFree(s); nh_XtPopdown(XtParent(dialog)); exit_x_event = TRUE; } /* ARGSUSED */ static void getline_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { Strcpy(getline_input, CANCEL_STR); nh_XtPopdown(w); exit_x_event = TRUE; } /* Callback for getline dialog widget. */ /* ARGSUSED */ static void abort_button(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { Widget dialog = (Widget) client_data; Strcpy(getline_input, CANCEL_STR); nh_XtPopdown(XtParent(dialog)); exit_x_event = TRUE; } void X11_getlin(question, input) const char *question; char *input; { static boolean need_to_init = True; getline_input = input; flush_screen(1); if (need_to_init) { Arg args[1]; need_to_init = False; XtSetArg(args[0], XtNallowShellResize, True); getline_popup = XtCreatePopupShell("getline",transientShellWidgetClass, toplevel, args, ONE); XtOverrideTranslations(getline_popup, XtParseTranslationTable("WM_PROTOCOLS: getline_delete()")); getline_dialog = CreateDialog(getline_popup, "dialog", done_button, abort_button); XtRealizeWidget(getline_popup); XSetWMProtocols(XtDisplay(getline_popup), XtWindow(getline_popup), &wm_delete_window, 1); } SetDialogPrompt(getline_dialog, (String)question); /* set prompt */ SetDialogResponse(getline_dialog, ""); /* set default answer */ positionpopup(getline_popup, TRUE); /* center,bottom */ nh_XtPopup(getline_popup, (int)XtGrabExclusive, getline_dialog); /* The callback will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); } /* Display file ------------------------------------------------------------ */ static const char display_translations[] = "#override\n\ q: dismiss_file()\n\ Escape: dismiss_file()\n\ : dismiss_file()"; /* WM_DELETE_WINDOW callback for file dismissal. */ /*ARGSUSED*/ static void delete_file(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { nh_XtPopdown(w); XtDestroyWidget(w); } /* Callback for file dismissal. */ /*ARGSUSED*/ static void dismiss_file(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { Widget popup = XtParent(w); nh_XtPopdown(popup); XtDestroyWidget(popup); } void X11_display_file(str, complain) const char *str; boolean complain; { dlb *fp; Arg args[12]; Cardinal num_args; Widget popup, dispfile; Position top_margin, bottom_margin, left_margin, right_margin; XFontStruct *fs; int new_width, new_height; #define LLEN 128 char line[LLEN]; int num_lines; char *textlines; int charcount; /* Use the port-independent file opener to see if the file exists. */ fp = dlb_fopen(str, RDTMODE); if (!fp) { if(complain) pline("Cannot open %s. Sorry.", str); return; /* it doesn't exist, ignore */ } /* * Count the number of lines and characters in the file. */ num_lines = 0; charcount = 1; while (dlb_fgets(line, LLEN, fp)) { num_lines++; charcount += strlen(line); } (void) dlb_fclose(fp); /* Ignore empty files */ if (num_lines == 0) return; /* If over the max window size, truncate the window size to the max */ if (num_lines >= DISPLAY_FILE_SIZE) num_lines = DISPLAY_FILE_SIZE; /* * Re-open the file and read the data into a buffer. Cannot use * the XawAsciiFile type of widget, because that is not DLB-aware. */ textlines = (char *) alloc((unsigned int) charcount); textlines[0] = '\0'; fp = dlb_fopen(str, RDTMODE); while (dlb_fgets(line, LLEN, fp)) { (void) strcat(textlines, line); } (void) dlb_fclose(fp); num_args = 0; XtSetArg(args[num_args], XtNtitle, str); num_args++; popup = XtCreatePopupShell("display_file", topLevelShellWidgetClass, toplevel, args, num_args); XtOverrideTranslations(popup, XtParseTranslationTable("WM_PROTOCOLS: delete_file()")); num_args = 0; XtSetArg(args[num_args], XtNscrollHorizontal, XawtextScrollWhenNeeded); num_args++; XtSetArg(args[num_args], XtNscrollVertical, XawtextScrollWhenNeeded); num_args++; XtSetArg(args[num_args], XtNtype, XawAsciiString); num_args++; XtSetArg(args[num_args], XtNstring, textlines); num_args++; XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(display_translations)); num_args++; dispfile = XtCreateManagedWidget( "text", /* name */ asciiTextWidgetClass, popup, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* Get font and border information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &fs); num_args++; XtSetArg(args[num_args], XtNtopMargin, &top_margin); num_args++; XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++; XtSetArg(args[num_args], XtNleftMargin, &left_margin); num_args++; XtSetArg(args[num_args], XtNrightMargin, &right_margin); num_args++; XtGetValues(dispfile, args, num_args); /* * The data files are currently set up assuming an 80 char wide window * and a fixed width font. Soo.. */ new_height = num_lines * nhFontHeight(dispfile) + top_margin + bottom_margin; new_width = 80 * fs->max_bounds.width + left_margin + right_margin; /* Set the new width and height. */ num_args = 0; XtSetArg(args[num_args], XtNwidth, new_width); num_args++; XtSetArg(args[num_args], XtNheight, new_height); num_args++; XtSetValues(dispfile, args, num_args); nh_XtPopup(popup, (int)XtGrabNone, (Widget)0); free(textlines); } /* yn_function ------------------------------------------------------------- */ /* (not threaded) */ static const char *yn_quitchars = " \n\r"; static const char *yn_choices; /* string of acceptable input */ static char yn_def; static char yn_return; /* return value */ static char yn_esc_map; /* ESC maps to this char. */ static Widget yn_popup; /* popup for the yn fuction (created once) */ static Widget yn_label; /* label for yn function (created once) */ static boolean yn_getting_num; /* TRUE if accepting digits */ static int yn_ndigits; /* digit count */ static long yn_val; /* accumulated value */ static const char yn_translations[] = "#override\n\ : yn_key()"; /* * Convert the given key event into a character. If the key maps to * more than one character only the first is returned. If there is * no conversion (i.e. just the CTRL key hit) a NUL is returned. */ char key_event_to_char(key) XKeyEvent *key; { char keystring[MAX_KEY_STRING]; int nbytes; boolean meta = !!(key->state & Mod1Mask); nbytes = XLookupString(key, keystring, MAX_KEY_STRING, (KeySym *)0, (XComposeStatus *)0); /* Modifier keys return a zero lengh string when pressed. */ if (nbytes == 0) return '\0'; return (char) (((int) keystring[0]) + (meta ? 0x80 : 0)); } /* * Called when we get a WM_DELETE_WINDOW event on a yn window. */ /* ARGSUSED */ static void yn_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { yn_getting_num = FALSE; /* Only use yn_esc_map if we have choices. Otherwise, return ESC. */ yn_return = yn_choices ? yn_esc_map : '\033'; exit_x_event = TRUE; /* exit our event handler */ } /* * Called when we get a key press event on a yn window. */ /* ARGSUSED */ static void yn_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch; if(appResources.slow && !input_func) map_input(w, event, params, num_params); ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char or modifier event */ /* no bell */ return; } if (!yn_choices) { /* accept any input */ yn_return = ch; } else { ch = lowc(ch); /* move to lower case */ if (ch == '\033') { yn_getting_num = FALSE; yn_return = yn_esc_map; } else if (index(yn_quitchars, ch)) { yn_return = yn_def; } else if (index(yn_choices, ch)) { if (ch == '#') { if (yn_getting_num) { /* don't select again */ X11_nhbell(); return; } yn_getting_num = TRUE; yn_ndigits = 0; yn_val = 0; return; /* wait for more input */ } yn_return = ch; if (ch != 'y') yn_getting_num = FALSE; } else { if (yn_getting_num) { if (digit(ch)) { yn_ndigits++; yn_val = (yn_val * 10) + (long) (ch - '0'); return; /* wait for more input */ } if (yn_ndigits && (ch == '\b' || ch == 127/*DEL*/)) { yn_ndigits--; yn_val = yn_val/ 10; return; /* wait for more input */ } } X11_nhbell(); /* no match */ return; } if (yn_getting_num) { yn_return = '#'; if (yn_val < 0) yn_val = 0; yn_number = yn_val; /* assign global */ } } exit_x_event = TRUE; /* exit our event handler */ } char X11_yn_function(ques, choices, def) const char *ques; const char *choices; char def; { static Boolean need_to_init = True; char buf[QBUFSZ]; Arg args[4]; Cardinal num_args; yn_choices = choices; /* set up globals for callback to use */ yn_def = def; /* * This is sort of a kludge. There are quite a few places in the main * nethack code where a pline containing information is followed by a * call to yn_function(). There is no flush of the message window * (it is implicit in the tty window port), so the line never shows * up for us! Solution: do our own flush. */ if (WIN_MESSAGE != WIN_ERR) display_message_window(&window_list[WIN_MESSAGE]); if (choices) { char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); /* anything beyond is hidden */ if ((cb = index(choicebuf, '\033')) != 0) *cb = '\0'; /* ques [choices] (def) */ if ((int)(1 + strlen(ques) + 2 + strlen(choicebuf) + 4) >= QBUFSZ) panic("yn_function: question too long"); Sprintf(buf, "%s [%s] ", ques, choicebuf); if (def) Sprintf(eos(buf), "(%c) ", def); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { if ((int)(1 + strlen(ques)) >= QBUFSZ) panic("yn_function: question too long"); Strcpy(buf, ques); } if (!appResources.slow && need_to_init) { need_to_init = False; XtSetArg(args[0], XtNallowShellResize, True); yn_popup = XtCreatePopupShell("query", transientShellWidgetClass, toplevel, args, ONE); XtOverrideTranslations(yn_popup, XtParseTranslationTable("WM_PROTOCOLS: yn_delete()")); num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(yn_translations)); num_args++; yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass, yn_popup, args, num_args); XtRealizeWidget(yn_popup); XSetWMProtocols(XtDisplay(yn_popup), XtWindow(yn_popup), &wm_delete_window, 1); } if(appResources.slow) input_func = yn_key; num_args = 0; XtSetArg(args[num_args], XtNlabel, buf); num_args++; XtSetValues(yn_label, args, num_args); if(!appResources.slow) { /* * Due to some kind of weird bug in the X11R4 and X11R5 shell, we * need to set the label twice to get the size to change. */ num_args = 0; XtSetArg(args[num_args], XtNlabel, buf); num_args++; XtSetValues(yn_label, args, num_args); positionpopup(yn_popup, TRUE); nh_XtPopup(yn_popup, (int)XtGrabExclusive, yn_label); } yn_getting_num = FALSE; (void) x_event(EXIT_ON_EXIT); if(appResources.slow) { input_func = 0; num_args = 0; XtSetArg(args[num_args], XtNlabel, " "); num_args++; XtSetValues(yn_label, args, num_args); } else { nh_XtPopdown(yn_popup); /* this removes the event grab */ } return yn_return; } /* End global functions ==================================================== */ /* * Before we wait for input via nhgetch() and nh_poskey(), we need to * do some pre-processing. */ static int input_event(exit_condition) int exit_condition; { if (WIN_STATUS != WIN_ERR) /* hilighting on the fancy status window */ check_turn_events(); if (WIN_MAP != WIN_ERR) /* make sure cursor is not clipped */ check_cursor_visibility(&window_list[WIN_MAP]); if (WIN_MESSAGE != WIN_ERR) /* reset pause line */ set_last_pause(&window_list[WIN_MESSAGE]); return x_event(exit_condition); } /*ARGSUSED*/ void msgkey(w, data, event) Widget w; XtPointer data; XEvent *event; { Cardinal num = 0; map_input(window_list[WIN_MAP].w, event, (String*) 0, &num); } /*ARGSUSED*/ static void win_visible(w, data, event, flag) /* only called for autofocus */ Widget w; XtPointer data; /* client_data not used */ XEvent *event; Boolean *flag; /* continue_to_dispatch flag not used */ { XVisibilityEvent *vis_event = (XVisibilityEvent *)event; if (vis_event->state != VisibilityFullyObscured) { /* one-time operation; cancel ourself */ XtRemoveEventHandler(toplevel, VisibilityChangeMask, False, win_visible, (XtPointer) 0); /* grab initial input focus */ XSetInputFocus(XtDisplay(w), XtWindow(w), RevertToNone, CurrentTime); } } /* * Set up the playing console. This has three major parts: the * message window, the map, and the status window. */ static void init_standard_windows() { Widget form, message_viewport, map_viewport, status; Arg args[8]; Cardinal num_args; Dimension message_vp_width, map_vp_width, status_width, max_width; int map_vp_hd, status_hd; struct xwindow *wp; num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; form = XtCreateManagedWidget("nethack", panedWidgetClass, toplevel, args, num_args); XtAddEventHandler(form, KeyPressMask, False, (XtEventHandler) msgkey, (XtPointer) 0); if (appResources.autofocus) XtAddEventHandler(toplevel, VisibilityChangeMask, False, win_visible, (XtPointer) 0); /* * Create message window. */ WIN_MESSAGE = message_win = find_free_window(); wp = &window_list[message_win]; wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; wp->popup = (Widget) 0; create_message_window(wp, FALSE, form); message_viewport = XtParent(wp->w); /* Tell the form that contains it that resizes are OK. */ num_args = 0; XtSetArg(args[num_args], XtNresizable, True); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetValues(message_viewport, args, num_args); if(appResources.slow) { num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(yn_translations)); num_args++; yn_label = XtCreateManagedWidget("yn_label", labelWidgetClass, form, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNfromVert, message_viewport); num_args++; XtSetArg(args[num_args], XtNjustify, XtJustifyLeft); num_args++; XtSetArg(args[num_args], XtNresizable, True); num_args++; XtSetArg(args[num_args], XtNlabel, " "); num_args++; XtSetValues(yn_label, args, num_args); } /* * Create the map window & viewport and chain the viewport beneath the * message_viewport. */ map_win = find_free_window(); wp = &window_list[map_win]; wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; wp->popup = (Widget) 0; create_map_window(wp, FALSE, form); map_viewport = XtParent(wp->w); /* Chain beneath message_viewport or yn window. */ num_args = 0; if(appResources.slow) { XtSetArg(args[num_args], XtNfromVert, yn_label); num_args++; } else { XtSetArg(args[num_args], XtNfromVert, message_viewport);num_args++; } XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++; XtSetValues(map_viewport, args, num_args); /* Create the status window, with the form as it's parent. */ status_win = find_free_window(); wp = &window_list[status_win]; wp->cursx = wp->cursy = wp->pixel_width = wp->pixel_height = 0; wp->popup = (Widget) 0; create_status_window(wp, FALSE, form); status = wp->w; /* * Chain the status window beneath the viewport. Mark the left and right * edges so that they stay a fixed distance from the left edge of the * parent, as well as the top and bottom edges so that they stay a fixed * distance from the bottom of the parent. We do this so that the status * will never expand or contract. */ num_args = 0; XtSetArg(args[num_args], XtNfromVert, map_viewport); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNtop, XtChainBottom); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++; XtSetValues(status, args, num_args); /* * Realize the popup so that the status widget knows it's size. * * If we unset MappedWhenManaged then the DECwindow driver doesn't * attach the nethack toplevel to the highest virtual root window. * So don't do it. */ /* XtSetMappedWhenManaged(toplevel, False); */ XtRealizeWidget(toplevel); wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW", False); XSetWMProtocols(XtDisplay(toplevel), XtWindow(toplevel), &wm_delete_window, 1); /* * Resize to at most full-screen. */ { #define TITLEBAR_SPACE 18 /* Leave SOME screen for window decorations */ int screen_width = WidthOfScreen(XtScreen(wp->w)); int screen_height = HeightOfScreen(XtScreen(wp->w)) - TITLEBAR_SPACE; Dimension form_width, form_height; XtSetArg(args[0], XtNwidth, &form_width); XtSetArg(args[1], XtNheight, &form_height); XtGetValues(toplevel, args, TWO); if (form_width > screen_width || form_height > screen_height) { XtSetArg(args[0], XtNwidth, min(form_width,screen_width)); XtSetArg(args[1], XtNheight, min(form_height,screen_height)); XtSetValues(toplevel, args, TWO); XMoveWindow(XtDisplay(toplevel),XtWindow(toplevel), 0, TITLEBAR_SPACE); } #undef TITLEBAR_SPACE } post_process_tiles(); /* after toplevel is realized */ /* * Now get the default widths of the windows. */ XtSetArg(args[0], XtNwidth, &message_vp_width); XtGetValues(message_viewport, args, ONE); XtSetArg(args[0], XtNwidth, &map_vp_width); XtSetArg(args[1], XtNhorizDistance, &map_vp_hd); XtGetValues(map_viewport, args, TWO); XtSetArg(args[0], XtNwidth, &status_width); XtSetArg(args[1], XtNhorizDistance, &status_hd); XtGetValues(status, args, TWO); /* * Adjust positions and sizes. The message viewport widens out to the * widest width. Both the map and status are centered by adjusting * their horizDistance. */ if (map_vp_width < status_width || map_vp_width < message_vp_width) { if (status_width > message_vp_width) { XtSetArg(args[0], XtNwidth, status_width); XtSetValues(message_viewport, args, ONE); max_width = status_width; } else { /***** The status display looks better when left justified. XtSetArg(args[0], XtNhorizDistance, status_hd+((message_vp_width-status_width)/2)); XtSetValues(status, args, ONE); *****/ max_width = message_vp_width; } XtSetArg(args[0], XtNhorizDistance, map_vp_hd+((int)(max_width-map_vp_width)/2)); XtSetValues(map_viewport, args, ONE); } else { /* map is widest */ XtSetArg(args[0], XtNwidth, map_vp_width); XtSetValues(message_viewport, args, ONE); /***** The status display looks better when left justified. XtSetArg(args[0], XtNhorizDistance, status_hd+((map_vp_width-status_width)/2)); XtSetValues(status, args, ONE); *****/ } /* * Clear all data values on the fancy status widget so that the values * used for spacing don't appear. This needs to be called some time * after the fancy status widget is realized (above, with the game popup), * but before it is popped up. */ null_out_status(); /* * Set the map size to its standard size. As with the message window * above, the map window needs to be set to its constrained size until * its parent (the viewport widget) was realized. * * Move the message window's slider to the bottom. */ set_map_size(&window_list[map_win], COLNO, ROWNO); set_message_slider(&window_list[message_win]); /* attempt to catch fatal X11 errors before the program quits */ (void) XtAppSetErrorHandler(app_context, (XtErrorHandler) hangup); /* We can now print to the message window. */ iflags.window_inited = 1; } void nh_XtPopup(w, g, childwid) Widget w; /* widget */ int g; /* type of grab */ Widget childwid; /* child to recieve focus (can be None) */ { XtPopup(w, (XtGrabKind)g); XSetWMProtocols(XtDisplay(w), XtWindow(w), &wm_delete_window, 1); if (appResources.autofocus) XtSetKeyboardFocus(toplevel, childwid); } void nh_XtPopdown(w) Widget w; { XtPopdown(w); if (appResources.autofocus) XtSetKeyboardFocus(toplevel, None); } void win_X11_init() { #ifdef OPENWINBUG /* With the OpenWindows 3.0 libraries and the SunOS 4.1.2 ld, these * two routines will not be found when linking. An apparently correct * executable is produced, along with nasty messages and a failure code * returned to make. The routines are in the static libXmu.a and * libXmu.sa.4.0, but not in libXmu.so.4.0. Rather than fiddle with * static linking, we do this. */ if (rn2(2) > 2) { /* i.e., FALSE that an optimizer probably can't find */ get_wmShellWidgetClass(); get_applicationShellWidgetClass(); } #endif return; } /* Callback * Scroll a viewport, using standard NH 1,2,3,4,6,7,8,9 directions. */ /*ARGSUSED*/ void nh_keyscroll(viewport, event, params, num_params) Widget viewport; XEvent *event; String *params; Cardinal *num_params; { Arg arg[2]; Widget horiz_sb, vert_sb; float top, shown; Boolean do_call; int direction; Cardinal in_nparams = (num_params ? *num_params : 0); if (in_nparams != 1) return; /* bad translation */ direction=atoi(params[0]); horiz_sb = XtNameToWidget(viewport, "*horizontal"); vert_sb = XtNameToWidget(viewport, "*vertical"); if (!horiz_sb && !vert_sb) { /* Perhaps the widget enclosing this has scrollbars (could use while) */ Widget parent=XtParent(viewport); if (parent) { horiz_sb = XtNameToWidget(parent, "horizontal"); vert_sb = XtNameToWidget(parent, "vertical"); } } #define H_DELTA 0.25 /* distance of horiz shift */ /* vert shift is half of curr distance */ /* The V_DELTA is 1/2 the value of shown. */ if (horiz_sb) { XtSetArg(arg[0], XtNshown, &shown); XtSetArg(arg[1], XtNtopOfThumb, &top); XtGetValues(horiz_sb, arg, TWO); do_call = True; switch (direction) { case 1: case 4: case 7: top -= H_DELTA; if (top < 0.0) top = 0.0; break; case 3: case 6: case 9: top += H_DELTA; if (top + shown > 1.0) top = 1.0 - shown; break; default: do_call = False; } if (do_call) { XtCallCallbacks(horiz_sb, XtNjumpProc, &top); } } if (vert_sb) { XtSetArg(arg[0], XtNshown, &shown); XtSetArg(arg[1], XtNtopOfThumb, &top); XtGetValues(vert_sb, arg, TWO); do_call = True; switch (direction) { case 7: case 8: case 9: top -= shown / 2.0; if (top < 0.0) top = 0; break; case 1: case 2: case 3: top += shown / 2.0; if (top + shown > 1.0) top = 1.0 - shown; break; default: do_call = False; } if (do_call) { XtCallCallbacks(vert_sb, XtNjumpProc, &top); } } } /*winX.c*/ nethack-3.4.3/win/X11/winmap.c0100644000000000000000000013227507764735041014471 0ustar rootroot/* SCCS Id: @(#)winmap.c 3.4 1996/04/05 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * This file contains: * + global functions print_glyph() and cliparound() * + the map window routines * + the char and pointer input routines * * Notes: * + We don't really have a good way to get the compiled ROWNO and * COLNO as defaults. They are hardwired to the current "correct" * values in the Window widget. I am _not_ in favor of including * some nethack include file for Window.c. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "xwindow.h" /* map widget declarations */ #include "hack.h" #include "dlb.h" #include "winX.h" #ifdef USE_XPM #include #endif /* from tile.c */ extern short glyph2tile[]; extern int total_tiles_used; /* Define these if you really want a lot of junk on your screen. */ /* #define VERBOSE */ /* print various info & events as they happen */ /* #define VERBOSE_UPDATE */ /* print screen update bounds */ /* #define VERBOSE_INPUT */ /* print input events */ #define USE_WHITE /* almost always use white as a tile cursor border */ static boolean FDECL(init_tiles, (struct xwindow *)); static void FDECL(set_button_values, (Widget,int,int,unsigned)); static void FDECL(map_check_size_change, (struct xwindow *)); static void FDECL(map_update, (struct xwindow *,int,int,int,int,BOOLEAN_P)); static void FDECL(init_text, (struct xwindow *)); static void FDECL(map_exposed, (Widget,XtPointer,XtPointer)); static void FDECL(set_gc, (Widget,Font,char *,Pixel,GC *,GC *)); static void FDECL(get_text_gc, (struct xwindow *,Font)); static void FDECL(get_char_info, (struct xwindow *)); static void FDECL(display_cursor, (struct xwindow *)); /* Global functions ======================================================== */ void X11_print_glyph(window, x, y, glyph) winid window; xchar x, y; int glyph; { struct map_info_t *map_info; boolean update_bbox; check_winid(window); if (window_list[window].type != NHW_MAP) { impossible("print_glyph: can (currently) only print to map windows"); return; } map_info = window_list[window].map_information; if (map_info->is_tile) { unsigned short *t_ptr; t_ptr = &map_info->mtype.tile_map->glyphs[y][x]; if (*t_ptr != glyph) { *t_ptr = glyph; update_bbox = TRUE; } else update_bbox = FALSE; } else { uchar ch; register unsigned char *ch_ptr; int color,och; unsigned special; #ifdef TEXTCOLOR register unsigned char *co_ptr; #endif /* map glyph to character and color */ mapglyph(glyph, &och, &color, &special, x, y); ch = (uchar)och; /* Only update if we need to. */ ch_ptr = &map_info->mtype.text_map->text[y][x]; #ifdef TEXTCOLOR co_ptr = &map_info->mtype.text_map->colors[y][x]; if (*ch_ptr != ch || *co_ptr != color) #else if (*ch_ptr != ch) #endif { *ch_ptr = ch; #ifdef TEXTCOLOR *co_ptr = color; #endif update_bbox = TRUE; } else update_bbox = FALSE; } if (update_bbox) { /* update row bbox */ if ((uchar) x < map_info->t_start[y]) map_info->t_start[y] = x; if ((uchar) x > map_info->t_stop[y]) map_info->t_stop[y] = x; } } #ifdef CLIPPING /* * The is the tty clip call. Since X can resize at any time, we can't depend * on this being defined. */ /*ARGSUSED*/ void X11_cliparound(x, y) int x, y; { } #endif /* CLIPPING */ /* End global functions ==================================================== */ #include "tile2x11.h" /* * We're expecting to never read more than one tile file per session. * If this is false, then we can make an array of this information, * or just keep it on a per-window basis. */ Pixmap tile_pixmap = None; static int tile_width; static int tile_height; static int tile_count; static XImage *tile_image = 0; /* * This structure is used for small bitmaps that are used for annotating * tiles. For example, a "heart" annotates pets. */ struct tile_annotation { Pixmap bitmap; Pixel foreground; unsigned int width, height; int hotx, hoty; /* not currently used */ }; static struct tile_annotation pet_annotation; static void init_annotation(annotation, filename, colorpixel) struct tile_annotation *annotation; char *filename; Pixel colorpixel; { Display *dpy = XtDisplay(toplevel); if (0!=XReadBitmapFile(dpy, XtWindow(toplevel), filename, &annotation->width, &annotation->height, &annotation->bitmap, &annotation->hotx, &annotation->hoty)) { char buf[BUFSZ]; Sprintf(buf, "Failed to load %s", filename); X11_raw_print(buf); } annotation->foreground = colorpixel; } /* * Put the tile image on the server. * * We can't send the image to the server until the top level * is realized. When the tile file is first processed, the top * level is not realized. This routine is called after we * realize the top level, but before we start resizing the * map viewport. */ void post_process_tiles() { Display *dpy = XtDisplay(toplevel); unsigned int width, height; if (tile_image == 0) return; /* no tiles */ height = tile_image->height; width = tile_image->width; tile_pixmap = XCreatePixmap(dpy, XtWindow(toplevel), width, height, DefaultDepth(dpy, DefaultScreen(dpy))); XPutImage(dpy, tile_pixmap, DefaultGC(dpy, DefaultScreen(dpy)), tile_image, 0,0, 0,0, /* src, dest top left */ width, height); XDestroyImage(tile_image); /* data bytes free'd also */ tile_image = 0; init_annotation(&pet_annotation, appResources.pet_mark_bitmap, appResources.pet_mark_color); } /* * Open and read the tile file. Return TRUE if there were no problems. * Return FALSE otherwise. */ static boolean init_tiles(wp) struct xwindow *wp; { #ifdef USE_XPM XpmAttributes attributes; int errorcode; #else FILE *fp = (FILE *)0; x11_header header; unsigned char *cp, *colormap = (unsigned char *)0; unsigned char *tb, *tile_bytes = (unsigned char *)0; int size; XColor *colors = (XColor *)0; int i, x, y; int bitmap_pad; int ddepth; #endif char buf[BUFSZ]; Display *dpy = XtDisplay(toplevel); Screen *screen = DefaultScreenOfDisplay(dpy); struct map_info_t *map_info = (struct map_info_t *)0; struct tile_map_info_t *tile_info = (struct tile_map_info_t *)0; unsigned int image_height = 0, image_width = 0; boolean result = TRUE; XGCValues values; XtGCMask mask; /* already have tile information */ if (tile_pixmap != None) goto tiledone; map_info = wp->map_information; tile_info = map_info->mtype.tile_map = (struct tile_map_info_t *) alloc(sizeof(struct tile_map_info_t)); (void) memset((genericptr_t) tile_info, 0, sizeof(struct tile_map_info_t)); #ifdef USE_XPM attributes.valuemask = XpmCloseness; attributes.closeness = 25000; errorcode = XpmReadFileToImage(dpy, appResources.tile_file, &tile_image, 0, &attributes); if (errorcode == XpmColorFailed) { Sprintf(buf, "Insufficient colors available to load %s.", appResources.tile_file); X11_raw_print(buf); X11_raw_print("Try closing other colorful applications and restart."); X11_raw_print("Attempting to load with inferior colors."); attributes.closeness = 50000; errorcode = XpmReadFileToImage(dpy, appResources.tile_file, &tile_image, 0, &attributes); } if (errorcode != XpmSuccess) { if (errorcode == XpmColorFailed) { Sprintf(buf, "Insufficient colors available to load %s.", appResources.tile_file); X11_raw_print(buf); } else { Sprintf(buf, "Failed to load %s: %s", appResources.tile_file, XpmGetErrorString(errorcode)); X11_raw_print(buf); } result = FALSE; X11_raw_print("Switching to text-based mode."); goto tiledone; } /* assume a fixed number of tiles per row */ if (tile_image->width % TILES_PER_ROW != 0 || tile_image->width <= TILES_PER_ROW) { Sprintf(buf, "%s is not a multiple of %d (number of tiles/row) pixels wide", appResources.tile_file, TILES_PER_ROW); X11_raw_print(buf); XDestroyImage(tile_image); tile_image = 0; result = FALSE; goto tiledone; } /* infer tile dimensions from image size and TILES_PER_ROW */ image_width = tile_image->width; image_height = tile_image->height; tile_count = total_tiles_used; if ((tile_count % TILES_PER_ROW) != 0) { tile_count += TILES_PER_ROW - (tile_count % TILES_PER_ROW); } tile_width = image_width / TILES_PER_ROW; tile_height = image_height / (tile_count / TILES_PER_ROW); #else /* any less than 16 colours makes tiles useless */ ddepth = DefaultDepthOfScreen(screen); if (ddepth < 4) { X11_raw_print("need a screen depth of at least 4"); result = FALSE; goto tiledone; } fp = fopen_datafile(appResources.tile_file, RDBMODE, FALSE); if (!fp) { X11_raw_print("can't open tile file"); result = FALSE; goto tiledone; } if (fread((char *) &header, sizeof(header), 1, fp) != 1) { X11_raw_print("read of header failed"); result = FALSE; goto tiledone; } if (header.version != 2) { Sprintf(buf, "Wrong tile file version, expected 2, got %lu", header.version); X11_raw_print(buf); result = FALSE; goto tiledone; } # ifdef VERBOSE fprintf(stderr, "X11 tile file:\n version %ld\n ncolors %ld\n tile width %ld\n tile height %ld\n per row %ld\n ntiles %ld\n", header.version, header.ncolors, header.tile_width, header.tile_height, header.per_row, header.ntiles); # endif size = 3*header.ncolors; colormap = (unsigned char *) alloc((unsigned)size); if (fread((char *) colormap, 1, size, fp) != size) { X11_raw_print("read of colormap failed"); result = FALSE; goto tiledone; } /* defined in decl.h - these are _not_ good defines to have */ #undef red #undef green #undef blue colors = (XColor *) alloc(sizeof(XColor) * (unsigned)header.ncolors); for (i = 0; i < header.ncolors; i++) { cp = colormap + (3 * i); colors[i].red = cp[0] * 256; colors[i].green = cp[1] * 256; colors[i].blue = cp[2] * 256; colors[i].flags = 0; colors[i].pixel = 0; if (!XAllocColor(dpy, DefaultColormapOfScreen(screen), &colors[i]) && !nhApproxColor(screen, DefaultColormapOfScreen(screen), (char *)0, &colors[i])) { Sprintf(buf, "%dth out of %ld color allocation failed", i, header.ncolors); X11_raw_print(buf); result = FALSE; goto tiledone; } } size = header.tile_height * header.tile_width; /* * This alloc() and the one below require 32-bit ints, since tile_bytes * is currently ~200k and alloc() takes an int */ tile_count = header.ntiles; if ((tile_count % header.per_row) != 0) { tile_count += header.per_row - (tile_count % header.per_row); } tile_bytes = (unsigned char *) alloc((unsigned)tile_count*size); if (fread((char *) tile_bytes, size, tile_count, fp) != tile_count) { X11_raw_print("read of tile bytes failed"); result = FALSE; goto tiledone; } if (header.ntiles < total_tiles_used) { Sprintf(buf, "tile file incomplete, expecting %d tiles, found %lu", total_tiles_used, header.ntiles); X11_raw_print(buf); result = FALSE; goto tiledone; } if (appResources.double_tile_size) { tile_width = 2*header.tile_width; tile_height = 2*header.tile_height; } else { tile_width = header.tile_width; tile_height = header.tile_height; } image_height = tile_height * tile_count / header.per_row; image_width = tile_width * header.per_row; /* calculate bitmap_pad */ if (ddepth > 16) bitmap_pad = 32; else if (ddepth > 8) bitmap_pad = 16; else bitmap_pad = 8; tile_image = XCreateImage(dpy, DefaultVisualOfScreen(screen), ddepth, /* depth */ ZPixmap, /* format */ 0, /* offset */ 0, /* data */ image_width, /* width */ image_height, /* height */ bitmap_pad, /* bit pad */ 0); /* bytes_per_line */ if (!tile_image) impossible("init_tiles: insufficient memory to create image"); /* now we know the physical memory requirements, we can allocate space */ tile_image->data = (char *) alloc((unsigned)tile_image->bytes_per_line * image_height); if (appResources.double_tile_size) { unsigned long *expanded_row = (unsigned long *)alloc(sizeof(unsigned long)*(unsigned)image_width); tb = tile_bytes; for (y = 0; y < image_height; y++) { for (x = 0; x < image_width/2; x++) expanded_row[2*x] = expanded_row[(2*x)+1] = colors[*tb++].pixel; for (x = 0; x < image_width; x++) XPutPixel(tile_image, x, y, expanded_row[x]); y++; /* duplicate row */ for (x = 0; x < image_width; x++) XPutPixel(tile_image, x, y, expanded_row[x]); } free((genericptr_t)expanded_row); } else { for (tb = tile_bytes, y = 0; y < image_height; y++) for (x = 0; x < image_width; x++, tb++) XPutPixel(tile_image, x, y, colors[*tb].pixel); } #endif /* USE_XPM */ /* fake an inverted tile by drawing a border around the edges */ #ifdef USE_WHITE /* use white or black as the border */ mask = GCFunction | GCForeground | GCGraphicsExposures; values.graphics_exposures = False; values.foreground = WhitePixelOfScreen(screen); values.function = GXcopy; tile_info->white_gc = XtGetGC(wp->w, mask, &values); values.graphics_exposures = False; values.foreground = BlackPixelOfScreen(screen); values.function = GXcopy; tile_info->black_gc = XtGetGC(wp->w, mask, &values); #else /* * Use xor so we don't have to check for special colors. Xor white * against the upper left pixel of the corridor so that we have a * white rectangle when in a corridor. */ mask = GCFunction | GCForeground | GCGraphicsExposures; values.graphics_exposures = False; values.foreground = WhitePixelOfScreen(screen) ^ XGetPixel(tile_image, 0, tile_height*glyph2tile[cmap_to_glyph(S_corr)]); values.function = GXxor; tile_info->white_gc = XtGetGC(wp->w, mask, &values); mask = GCFunction | GCGraphicsExposures; values.function = GXCopy; values.graphics_exposures = False; tile_info->black_gc = XtGetGC(wp->w, mask, &values); #endif /* USE_WHITE */ tiledone: #ifndef USE_XPM if (fp) (void) fclose(fp); if (colormap) free((genericptr_t)colormap); if (tile_bytes) free((genericptr_t)tile_bytes); if (colors) free((genericptr_t)colors); #endif if (result) { /* succeeded */ map_info->square_height = tile_height; map_info->square_width = tile_width; map_info->square_ascent = 0; map_info->square_lbearing = 0; tile_info->image_width = image_width; tile_info->image_height = image_height; } else { if (tile_info) free((genericptr_t)tile_info); tile_info = 0; } return result; } /* * Make sure the map's cursor is always visible. */ void check_cursor_visibility(wp) struct xwindow *wp; { Arg arg[2]; Widget viewport, horiz_sb, vert_sb; float top, shown, cursor_middle; Boolean do_call, adjusted = False; #ifdef VERBOSE char *s; #endif viewport = XtParent(wp->w); horiz_sb = XtNameToWidget(viewport, "horizontal"); vert_sb = XtNameToWidget(viewport, "vertical"); /* All values are relative to currently visible area */ #define V_BORDER 0.3 /* if this far from vert edge, shift */ #define H_BORDER 0.3 /* if this from from horiz edge, shift */ #define H_DELTA 0.4 /* distance of horiz shift */ #define V_DELTA 0.4 /* distance of vert shift */ if (horiz_sb) { XtSetArg(arg[0], XtNshown, &shown); XtSetArg(arg[1], XtNtopOfThumb, &top); XtGetValues(horiz_sb, arg, TWO); /* [ALI] Don't assume map widget is the same size as actual map */ cursor_middle = (wp->cursx + 0.5) * wp->map_information->square_width / wp->pixel_width; do_call = True; #ifdef VERBOSE if (cursor_middle < top) { s = " outside left"; } else if (cursor_middle < top + shown*H_BORDER) { s = " close to left"; } else if (cursor_middle > (top + shown)) { s = " outside right"; } else if (cursor_middle > (top + shown - shown*H_BORDER)) { s = " close to right"; } else { s = ""; } printf("Horiz: shown = %3.2f, top = %3.2f%s", shown, top, s); #endif if (cursor_middle < top) { top = cursor_middle - shown*H_DELTA; if (top < 0.0) top = 0.0; } else if (cursor_middle < top + shown*H_BORDER) { top -= shown*H_DELTA; if (top < 0.0) top = 0.0; } else if (cursor_middle > (top + shown)) { top = cursor_middle - shown*H_DELTA; if (top < 0.0) top = 0.0; if (top + shown > 1.0) top = 1.0 - shown; } else if (cursor_middle > (top + shown - shown*H_BORDER)) { top += shown*H_DELTA; if (top + shown > 1.0) top = 1.0 - shown; } else { do_call = False; } if (do_call) { XtCallCallbacks(horiz_sb, XtNjumpProc, &top); adjusted = True; } } if (vert_sb) { XtSetArg(arg[0], XtNshown, &shown); XtSetArg(arg[1], XtNtopOfThumb, &top); XtGetValues(vert_sb, arg, TWO); cursor_middle = (wp->cursy + 0.5) * wp->map_information->square_height / wp->pixel_height; do_call = True; #ifdef VERBOSE if (cursor_middle < top) { s = " above top"; } else if (cursor_middle < top + shown*V_BORDER) { s = " close to top"; } else if (cursor_middle > (top + shown)) { s = " below bottom"; } else if (cursor_middle > (top + shown - shown*V_BORDER)) { s = " close to bottom"; } else { s = ""; } printf("%sVert: shown = %3.2f, top = %3.2f%s", horiz_sb ? "; " : "", shown, top, s); #endif if (cursor_middle < top) { top = cursor_middle - shown*V_DELTA; if (top < 0.0) top = 0.0; } else if (cursor_middle < top + shown*V_BORDER) { top -= shown*V_DELTA; if (top < 0.0) top = 0.0; } else if (cursor_middle > (top + shown)) { top = cursor_middle - shown*V_DELTA; if (top < 0.0) top = 0.0; if (top + shown > 1.0) top = 1.0 - shown; } else if (cursor_middle > (top + shown - shown*V_BORDER)) { top += shown*V_DELTA; if (top + shown > 1.0) top = 1.0 - shown; } else { do_call = False; } if (do_call) { XtCallCallbacks(vert_sb, XtNjumpProc, &top); adjusted = True; } } /* make sure cursor is displayed during dowhatis.. */ if (adjusted) display_cursor(wp); #ifdef VERBOSE if (horiz_sb || vert_sb) printf("\n"); #endif } /* * Check to see if the viewport has grown smaller. If so, then we want to make * sure that the cursor is still on the screen. We do this to keep the cursor * on the screen when the user resizes the nethack window. */ static void map_check_size_change(wp) struct xwindow *wp; { struct map_info_t *map_info = wp->map_information; Arg arg[2]; Dimension new_width, new_height; Widget viewport; viewport = XtParent(wp->w); XtSetArg(arg[0], XtNwidth, &new_width); XtSetArg(arg[1], XtNheight, &new_height); XtGetValues(viewport, arg, TWO); /* Only do cursor check if new size is smaller. */ if (new_width < map_info->viewport_width || new_height < map_info->viewport_height) { /* [ALI] If the viewport was larger than the map (and so the map * widget was contrained to be larger than the actual map) then we * may be able to shrink the map widget as the viewport shrinks. */ wp->pixel_width = map_info->square_width * COLNO; if (wp->pixel_width < new_width) wp->pixel_width = new_width; wp->pixel_height = map_info->square_height * ROWNO; if (wp->pixel_height < new_height) wp->pixel_height = new_height; XtSetArg(arg[0], XtNwidth, wp->pixel_width); XtSetArg(arg[1], XtNheight, wp->pixel_height); XtSetValues(wp->w, arg, TWO); check_cursor_visibility(wp); } map_info->viewport_width = new_width; map_info->viewport_height = new_height; /* [ALI] These may have changed if the user has re-sized the viewport */ XtSetArg(arg[0], XtNwidth, &wp->pixel_width); XtSetArg(arg[1], XtNheight, &wp->pixel_height); XtGetValues(wp->w, arg, TWO); } /* * Fill in parameters "regular" and "inverse" with newly created GCs. * Using the given background pixel and the foreground pixel optained * by querying the widget with the resource name. */ static void set_gc(w, font, resource_name, bgpixel, regular, inverse) Widget w; Font font; char *resource_name; Pixel bgpixel; GC *regular, *inverse; { XGCValues values; XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont; Pixel curpixel; Arg arg[1]; XtSetArg(arg[0], resource_name, &curpixel); XtGetValues(w, arg, ONE); values.foreground = curpixel; values.background = bgpixel; values.function = GXcopy; values.font = font; *regular = XtGetGC(w, mask, &values); values.foreground = bgpixel; values.background = curpixel; values.function = GXcopy; values.font = font; *inverse = XtGetGC(w, mask, &values); } /* * Create the GC's for each color. * * I'm not sure if it is a good idea to have a GC for each color (and * inverse). It might be faster to just modify the foreground and * background colors on the current GC as needed. */ static void get_text_gc(wp, font) struct xwindow *wp; Font font; { struct map_info_t *map_info = wp->map_information; Pixel bgpixel; Arg arg[1]; /* Get background pixel. */ XtSetArg(arg[0], XtNbackground, &bgpixel); XtGetValues(wp->w, arg, ONE); #ifdef TEXTCOLOR #define set_color_gc(nh_color, resource_name) \ set_gc(wp->w, font, resource_name, bgpixel, \ &map_info->mtype.text_map->color_gcs[nh_color], \ &map_info->mtype.text_map->inv_color_gcs[nh_color]); set_color_gc(CLR_BLACK, XtNblack); set_color_gc(CLR_RED, XtNred); set_color_gc(CLR_GREEN, XtNgreen); set_color_gc(CLR_BROWN, XtNbrown); set_color_gc(CLR_BLUE, XtNblue); set_color_gc(CLR_MAGENTA, XtNmagenta); set_color_gc(CLR_CYAN, XtNcyan); set_color_gc(CLR_GRAY, XtNgray); set_color_gc(NO_COLOR, XtNforeground); set_color_gc(CLR_ORANGE, XtNorange); set_color_gc(CLR_BRIGHT_GREEN, XtNbright_green); set_color_gc(CLR_YELLOW, XtNyellow); set_color_gc(CLR_BRIGHT_BLUE, XtNbright_blue); set_color_gc(CLR_BRIGHT_MAGENTA, XtNbright_magenta); set_color_gc(CLR_BRIGHT_CYAN, XtNbright_cyan); set_color_gc(CLR_WHITE, XtNwhite); #else set_gc(wp->w, font, XtNforeground, bgpixel, &map_info->mtype.text_map->copy_gc, &map_info->mtype.text_map->inv_copy_gc); #endif } /* * Display the cursor on the map window. */ static void display_cursor(wp) struct xwindow *wp; { /* Redisplay the cursor location inverted. */ map_update(wp, wp->cursy, wp->cursy, wp->cursx, wp->cursx, TRUE); } /* * Check if there are any changed characters. If so, then plaster them on * the screen. */ void display_map_window(wp) struct xwindow *wp; { register int row; struct map_info_t *map_info = wp->map_information; /* * If the previous cursor position is not the same as the current * cursor position, then update the old cursor position. */ if (wp->prevx != wp->cursx || wp->prevy != wp->cursy) { register unsigned int x = wp->prevx, y = wp->prevy; if (x < map_info->t_start[y]) map_info->t_start[y] = x; if (x > map_info->t_stop[y]) map_info->t_stop[y] = x; } for (row = 0; row < ROWNO; row++) { if (map_info->t_start[row] <= map_info->t_stop[row]) { map_update(wp, row, row, (int) map_info->t_start[row], (int) map_info->t_stop[row], FALSE); map_info->t_start[row] = COLNO-1; map_info->t_stop[row] = 0; } } display_cursor(wp); wp->prevx = wp->cursx; /* adjust old cursor position */ wp->prevy = wp->cursy; } /* * Set all map tiles to S_stone */ static void map_all_stone(map_info) struct map_info_t *map_info; { int i; unsigned short *sp, stone; stone = cmap_to_glyph(S_stone); for (sp = (unsigned short *) map_info->mtype.tile_map->glyphs, i = 0; i < ROWNO*COLNO; sp++, i++) *sp = stone; } /* * Fill the saved screen characters with the "clear" tile or character. * * Flush out everything by resetting the "new" bounds and calling * display_map_window(). */ void clear_map_window(wp) struct xwindow *wp; { struct map_info_t *map_info = wp->map_information; if (map_info->is_tile) { map_all_stone(map_info); } else { /* Fill text with spaces, and update */ (void) memset((genericptr_t) map_info->mtype.text_map->text, ' ', sizeof(map_info->mtype.text_map->text)); #ifdef TEXTCOLOR (void) memset((genericptr_t) map_info->mtype.text_map->colors, NO_COLOR, sizeof(map_info->mtype.text_map->colors)); #endif } /* force a full update */ (void) memset((genericptr_t) map_info->t_start, (char) 0, sizeof(map_info->t_start)); (void) memset((genericptr_t) map_info->t_stop, (char) COLNO-1, sizeof(map_info->t_stop)); display_map_window(wp); } /* * Retreive the font associated with the map window and save attributes * that are used when updating it. */ static void get_char_info(wp) struct xwindow *wp; { XFontStruct *fs; struct map_info_t *map_info = wp->map_information; fs = WindowFontStruct(wp->w); map_info->square_width = fs->max_bounds.width; map_info->square_height = fs->max_bounds.ascent + fs->max_bounds.descent; map_info->square_ascent = fs->max_bounds.ascent; map_info->square_lbearing = -fs->min_bounds.lbearing; #ifdef VERBOSE printf("Font information:\n"); printf("fid = %ld, direction = %d\n", fs->fid, fs->direction); printf("first = %d, last = %d\n", fs->min_char_or_byte2, fs->max_char_or_byte2); printf("all chars exist? %s\n", fs->all_chars_exist?"yes":"no"); printf("min_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n", fs->min_bounds.lbearing, fs->min_bounds.rbearing, fs->min_bounds.width, fs->min_bounds.ascent, fs->min_bounds.descent, fs->min_bounds.attributes); printf("max_bounds:lb=%d rb=%d width=%d asc=%d des=%d attr=%d\n", fs->max_bounds.lbearing, fs->max_bounds.rbearing, fs->max_bounds.width, fs->max_bounds.ascent, fs->max_bounds.descent, fs->max_bounds.attributes); printf("per_char = 0x%lx\n", (unsigned long) fs->per_char); printf("Text: (max) width = %d, height = %d\n", map_info->square_width, map_info->square_height); #endif if (fs->min_bounds.width != fs->max_bounds.width) X11_raw_print("Warning: map font is not monospaced!"); } /* * keyhit buffer */ #define INBUF_SIZE 64 int inbuf[INBUF_SIZE]; int incount = 0; int inptr = 0; /* points to valid data */ /* * Keyboard and button event handler for map window. */ void map_input(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { XKeyEvent *key; XButtonEvent *button; boolean meta = FALSE; int i, nbytes; Cardinal in_nparams = (num_params ? *num_params : 0); char c; char keystring[MAX_KEY_STRING]; switch (event->type) { case ButtonPress: button = (XButtonEvent *) event; #ifdef VERBOSE_INPUT printf("button press\n"); #endif if (in_nparams > 0 && (nbytes = strlen(params[0])) < MAX_KEY_STRING) { Strcpy(keystring, params[0]); key = (XKeyEvent *) event; /* just in case */ goto key_events; } if (w != window_list[WIN_MAP].w) { #ifdef VERBOSE_INPUT printf("map_input called from wrong window\n"); #endif X11_nhbell(); return; } set_button_values(w, button->x, button->y, button->button); break; case KeyPress: #ifdef VERBOSE_INPUT printf("key: "); #endif if(appResources.slow && input_func) { (*input_func)(w, event, params, num_params); break; } /* * Don't use key_event_to_char() because we want to be able * to allow keys mapped to multiple characters. */ key = (XKeyEvent *) event; if (in_nparams > 0 && (nbytes = strlen(params[0])) < MAX_KEY_STRING) { Strcpy(keystring, params[0]); } else { /* * Assume that mod1 is really the meta key. */ meta = !!(key->state & Mod1Mask); nbytes = XLookupString(key, keystring, MAX_KEY_STRING, (KeySym *)0, (XComposeStatus *)0); } key_events: /* Modifier keys return a zero length string when pressed. */ if (nbytes) { #ifdef VERBOSE_INPUT printf("\""); #endif for (i = 0; i < nbytes; i++) { c = keystring[i]; if (incount < INBUF_SIZE) { inbuf[(inptr+incount)%INBUF_SIZE] = ((int) c) + (meta ? 0x80 : 0); incount++; } else { X11_nhbell(); } #ifdef VERBOSE_INPUT if (meta) /* meta will print as M */ (void) putchar('M'); if (c < ' ') { /* ctrl will print as ^ */ (void) putchar('^'); c += '@'; } (void) putchar(c); #endif } #ifdef VERBOSE_INPUT printf("\" [%d bytes]\n", nbytes); #endif } break; default: impossible("unexpected X event, type = %d\n", (int) event->type); break; } } static void set_button_values(w, x, y, button) Widget w; int x; int y; unsigned int button; { struct xwindow *wp; struct map_info_t *map_info; wp = find_widget(w); map_info = wp->map_information; click_x = x / map_info->square_width; click_y = y / map_info->square_height; /* The values can be out of range if the map window has been resized */ /* to be larger than the max size. */ if (click_x >= COLNO) click_x = COLNO-1; if (click_y >= ROWNO) click_x = ROWNO-1; /* Map all buttons but the first to the second click */ click_button = (button == Button1) ? CLICK_1 : CLICK_2; } /* * Map window expose callback. */ /*ARGSUSED*/ static void map_exposed(w, client_data, widget_data) Widget w; XtPointer client_data; /* unused */ XtPointer widget_data; /* expose event from Window widget */ { int x, y; struct xwindow *wp; struct map_info_t *map_info; unsigned width, height; int start_row, stop_row, start_col, stop_col; XExposeEvent *event = (XExposeEvent *) widget_data; int t_height, t_width; /* tile/text height & width */ if (!XtIsRealized(w) || event->count > 0) return; wp = find_widget(w); map_info = wp->map_information; if (wp->keep_window && !map_info) return; /* * The map is sent an expose event when the viewport resizes. Make sure * that the cursor is still in the viewport after the resize. */ map_check_size_change(wp); if (event) { /* called from button-event */ x = event->x; y = event->y; width = event->width; height = event->height; } else { x = 0; y = 0; width = wp->pixel_width; height= wp->pixel_height; } /* * Convert pixels into INCLUSIVE text rows and columns. */ t_height = map_info->square_height; t_width = map_info->square_width; start_row = y / t_height; stop_row = ((y + height) / t_height) + ((((y + height) % t_height) == 0) ? 0 : 1) - 1; start_col = x / t_width; stop_col = ((x + width) / t_width) + ((((x + width) % t_width) == 0) ? 0 : 1) - 1; #ifdef VERBOSE printf("map_exposed: x = %d, y = %d, width = %d, height = %d\n", x, y, width, height); printf("chars %d x %d, rows %d to %d, columns %d to %d\n", map_info->square_height, map_info->square_width, start_row, stop_row, start_col, stop_col); #endif /* Out of range values are possible if the map window is resized to be */ /* bigger than the largest expected value. */ if (stop_row >= ROWNO) stop_row = ROWNO-1; if (stop_col >= COLNO) stop_col = COLNO-1; map_update(wp, start_row, stop_row, start_col, stop_col, FALSE); display_cursor(wp); /* make sure cursor shows up */ } /* * Do the actual work of the putting characters onto our X window. This * is called from the expose event routine, the display window (flush) * routine, and the display cursor routine. The later is a kludge that * involves the inverted parameter of this function. A better solution * would be to double the color count, with any color above CLR_MAX * being inverted. * * This works for rectangular regions (this includes one line rectangles). * The start and stop columns are *inclusive*. */ static void map_update(wp, start_row, stop_row, start_col, stop_col, inverted) struct xwindow *wp; int start_row, stop_row, start_col, stop_col; boolean inverted; { int win_start_row, win_start_col; struct map_info_t *map_info = wp->map_information; int row; register int count; if (start_row < 0 || stop_row >= ROWNO) { impossible("map_update: bad row range %d-%d\n", start_row, stop_row); return; } if (start_col < 0 || stop_col >=COLNO) { impossible("map_update: bad col range %d-%d\n", start_col, stop_col); return; } #ifdef VERBOSE_UPDATE printf("update: [0x%x] %d %d %d %d\n", (int) wp->w, start_row, stop_row, start_col, stop_col); #endif win_start_row = start_row; win_start_col = start_col; if (map_info->is_tile) { struct tile_map_info_t *tile_map = map_info->mtype.tile_map; int cur_col; Display* dpy = XtDisplay(wp->w); Screen* screen = DefaultScreenOfDisplay(dpy); for (row = start_row; row <= stop_row; row++) { for (cur_col = start_col; cur_col <= stop_col; cur_col++) { int glyph = tile_map->glyphs[row][cur_col]; int tile = glyph2tile[glyph]; int src_x, src_y; int dest_x = cur_col * map_info->square_width; int dest_y = row * map_info->square_height; src_x = (tile % TILES_PER_ROW) * tile_width; src_y = (tile / TILES_PER_ROW) * tile_height; XCopyArea(dpy, tile_pixmap, XtWindow(wp->w), tile_map->black_gc, /* no grapics_expose */ src_x, src_y, tile_width, tile_height, dest_x, dest_y); if (glyph_is_pet(glyph) && iflags.hilite_pet) { /* draw pet annotation (a heart) */ XSetForeground(dpy, tile_map->black_gc, pet_annotation.foreground); XSetClipOrigin(dpy, tile_map->black_gc, dest_x, dest_y); XSetClipMask(dpy, tile_map->black_gc, pet_annotation.bitmap); XCopyPlane( dpy, pet_annotation.bitmap, XtWindow(wp->w), tile_map->black_gc, 0,0, pet_annotation.width,pet_annotation.height, dest_x,dest_y, 1 ); XSetClipOrigin(dpy, tile_map->black_gc, 0, 0); XSetClipMask(dpy, tile_map->black_gc, None); XSetForeground(dpy, tile_map->black_gc, BlackPixelOfScreen(screen)); } } } if (inverted) { XDrawRectangle(XtDisplay(wp->w), XtWindow(wp->w), #ifdef USE_WHITE /* kludge for white square... */ tile_map->glyphs[start_row][start_col] == cmap_to_glyph(S_ice) ? tile_map->black_gc : tile_map->white_gc, #else tile_map->white_gc, #endif start_col * map_info->square_width, start_row * map_info->square_height, map_info->square_width-1, map_info->square_height-1); } } else { struct text_map_info_t *text_map = map_info->mtype.text_map; #ifdef TEXTCOLOR if (iflags.use_color) { register char *c_ptr; char *t_ptr; int cur_col, color, win_ystart; for (row = start_row; row <= stop_row; row++) { win_ystart = map_info->square_ascent + (row * map_info->square_height); t_ptr = (char *) &(text_map->text[row][start_col]); c_ptr = (char *) &(text_map->colors[row][start_col]); cur_col = start_col; while (cur_col <= stop_col) { color = *c_ptr++; count = 1; while ((cur_col + count) <= stop_col && *c_ptr == color) { count++; c_ptr++; } XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w), inverted ? text_map->inv_color_gcs[color] : text_map->color_gcs[color], map_info->square_lbearing + (map_info->square_width * cur_col), win_ystart, t_ptr, count); /* move text pointer and column count */ t_ptr += count; cur_col += count; } /* col loop */ } /* row loop */ } else #endif /* TEXTCOLOR */ { int win_row, win_xstart; /* We always start at the same x window position and have */ /* the same character count. */ win_xstart = map_info->square_lbearing + (win_start_col * map_info->square_width); count = stop_col - start_col + 1; for (row = start_row, win_row = win_start_row; row <= stop_row; row++, win_row++) { XDrawImageString(XtDisplay(wp->w), XtWindow(wp->w), inverted ? text_map->inv_copy_gc : text_map->copy_gc, win_xstart, map_info->square_ascent + (win_row * map_info->square_height), (char *) &(text_map->text[row][start_col]), count); } } } } /* Adjust the number of rows and columns on the given map window */ void set_map_size(wp, cols, rows) struct xwindow *wp; Dimension cols, rows; { Arg args[4]; Cardinal num_args; wp->pixel_width = wp->map_information->square_width * cols; wp->pixel_height = wp->map_information->square_height * rows; num_args = 0; XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++; XtSetValues(wp->w, args, num_args); } static void init_text(wp) struct xwindow *wp; { struct map_info_t *map_info = wp->map_information; struct text_map_info_t *text_map; map_info->is_tile = FALSE; text_map = map_info->mtype.text_map = (struct text_map_info_t *) alloc(sizeof(struct text_map_info_t)); (void) memset((genericptr_t) text_map->text, ' ', sizeof(text_map->text)); #ifdef TEXTCOLOR (void) memset((genericptr_t) text_map->colors, NO_COLOR, sizeof(text_map->colors)); #endif get_char_info(wp); get_text_gc(wp, WindowFont(wp->w)); } static char map_translations[] = "#override\n\ Left: scroll(4)\n\ Right: scroll(6)\n\ Up: scroll(8)\n\ Down: scroll(2)\n\ : input() \ "; /* * The map window creation routine. */ void create_map_window(wp, create_popup, parent) struct xwindow *wp; boolean create_popup; /* parent is a popup shell that we create */ Widget parent; { struct map_info_t *map_info; /* map info pointer */ Widget map, viewport; Arg args[16]; Cardinal num_args; Dimension rows, columns; #if 0 int screen_width, screen_height; #endif wp->type = NHW_MAP; if (create_popup) { /* * Create a popup that accepts key and button events. */ num_args = 0; XtSetArg(args[num_args], XtNinput, False); num_args++; wp->popup = parent = XtCreatePopupShell("nethack", topLevelShellWidgetClass, toplevel, args, num_args); /* * If we're here, then this is an auxiliary map window. If we're * cancelled via a delete window message, we should just pop down. */ } num_args = 0; XtSetArg(args[num_args], XtNallowHoriz, True); num_args++; XtSetArg(args[num_args], XtNallowVert, True); num_args++; /* XtSetArg(args[num_args], XtNforceBars, True); num_args++; */ XtSetArg(args[num_args], XtNuseBottom, True); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(map_translations)); num_args++; viewport = XtCreateManagedWidget( "map_viewport", /* name */ viewportWidgetClass, /* widget class from Window.h */ parent, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* * Create a map window. We need to set the width and height to some * value when we create it. We will change it to the value we want * later */ num_args = 0; XtSetArg(args[num_args], XtNwidth, 100); num_args++; XtSetArg(args[num_args], XtNheight, 100); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(map_translations)); num_args++; wp->w = map = XtCreateManagedWidget( "map", /* name */ windowWidgetClass, /* widget class from Window.h */ viewport, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ XtAddCallback(map, XtNexposeCallback, map_exposed, (XtPointer) 0); map_info = wp->map_information = (struct map_info_t *) alloc(sizeof(struct map_info_t)); map_info->viewport_width = map_info->viewport_height = 0; /* reset the "new entry" indicators */ (void) memset((genericptr_t) map_info->t_start, (char) COLNO, sizeof(map_info->t_start)); (void) memset((genericptr_t) map_info->t_stop, (char) 0, sizeof(map_info->t_stop)); /* we probably want to restrict this to the 1st map window only */ if (appResources.tile_file[0] && init_tiles(wp)) { map_info->is_tile = TRUE; } else { init_text(wp); map_info->is_tile = FALSE; } /* * Initially, set the map widget to be the size specified by the * widget rows and columns resources. We need to do this to * correctly set the viewport window size. After the viewport is * realized, then the map can resize to its normal size. */ num_args = 0; XtSetArg(args[num_args], XtNrows, &rows); num_args++; XtSetArg(args[num_args], XtNcolumns, &columns); num_args++; XtGetValues(wp->w, args, num_args); /* Don't bother with windows larger than ROWNOxCOLNO. */ if (columns > COLNO) columns = COLNO; if (rows > ROWNO) rows = ROWNO; #if 0 /* This is insufficient. We now resize final window in winX.c */ /* * Check for overrunning the size of the screen. This does an ad hoc * job. * * Width: We expect that there is nothing but borders on either side * of the map window. Use some arbitrary width to decide * when to shrink. * * Height: if the map takes up more than 1/2 of the screen height, start * reducing its size. */ screen_height = HeightOfScreen(XtScreen(wp->w)); screen_width = WidthOfScreen(XtScreen(wp->w)); #define WOFF 50 if ((int)(columns*map_info->square_width) > screen_width-WOFF) { columns = (screen_width-WOFF) / map_info->square_width; if (columns == 0) columns = 1; } if ((int)(rows*map_info->square_height) > screen_height/2) { rows = screen_height / (2*map_info->square_height); if (rows == 0) rows = 1; } #endif set_map_size(wp, columns, rows); /* * If we have created our own popup, then realize it so that the * viewport is also realized. Then resize the map window. */ if (create_popup) { XtRealizeWidget(wp->popup); XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), &wm_delete_window, 1); set_map_size(wp, COLNO, ROWNO); } if (map_info->is_tile) { map_all_stone(map_info); } } /* * Destroy this map window. */ void destroy_map_window(wp) struct xwindow *wp; { struct map_info_t *map_info = wp->map_information; if (wp->popup) nh_XtPopdown(wp->popup); if (map_info) { struct text_map_info_t *text_map = map_info->mtype.text_map; /* Free allocated GCs. */ if (!map_info->is_tile) { #ifdef TEXTCOLOR int i; for (i = 0; i < CLR_MAX; i++) { XtReleaseGC(wp->w, text_map->color_gcs[i]); XtReleaseGC(wp->w, text_map->inv_color_gcs[i]); } #else XtReleaseGC(wp->w, text_map->copy_gc); XtReleaseGC(wp->w, text_map->inv_copy_gc); #endif } /* free alloc'ed text information */ free((genericptr_t)text_map), map_info->mtype.text_map = 0; /* Free malloc'ed space. */ free((genericptr_t)map_info), wp->map_information = 0; } /* Destroy map widget. */ if (wp->popup && !wp->keep_window) XtDestroyWidget(wp->popup), wp->popup = (Widget)0; if (wp->keep_window) XtRemoveCallback(wp->w, XtNexposeCallback, map_exposed, (XtPointer)0); else wp->type = NHW_NONE; /* allow re-use */ } boolean exit_x_event; /* exit condition for the event loop */ /******* pkey(k) int k; { printf("key = '%s%c'\n", (k<32) ? "^":"", (k<32) ? '@'+k : k); } ******/ /* * Main X event loop. Here we accept and dispatch X events. We only exit * under certain circumstances. */ int x_event(exit_condition) int exit_condition; { XEvent event; int retval = 0; boolean keep_going = TRUE; /* Hold globals so function is re-entrant */ boolean hold_exit_x_event = exit_x_event; click_button = NO_CLICK; /* reset click exit condition */ exit_x_event = FALSE; /* reset callback exit condition */ /* * Loop until we get a sent event, callback exit, or are accepting key * press and button press events and we receive one. */ if((exit_condition == EXIT_ON_KEY_PRESS || exit_condition == EXIT_ON_KEY_OR_BUTTON_PRESS) && incount) goto try_test; do { XtAppNextEvent(app_context, &event); XtDispatchEvent(&event); /* See if we can exit. */ try_test: switch (exit_condition) { case EXIT_ON_SENT_EVENT: { XAnyEvent *any = (XAnyEvent *) &event; if (any->send_event) { retval = 0; keep_going = FALSE; } break; } case EXIT_ON_EXIT: if (exit_x_event) { incount = 0; retval = 0; keep_going = FALSE; } break; case EXIT_ON_KEY_PRESS: if (incount != 0) { /* get first pressed key */ --incount; retval = inbuf[inptr]; inptr = (inptr+1) % INBUF_SIZE; /* pkey(retval); */ keep_going = FALSE; } break; case EXIT_ON_KEY_OR_BUTTON_PRESS: if (incount != 0 || click_button != NO_CLICK) { if (click_button != NO_CLICK) { /* button press */ /* click values are already set */ retval = 0; } else { /* key press */ /* get first pressed key */ --incount; retval = inbuf[inptr]; inptr = (inptr+1) % INBUF_SIZE; /* pkey(retval); */ } keep_going = FALSE; } break; default: panic("x_event: unknown exit condition %d", exit_condition); break; } } while (keep_going); /* Restore globals */ exit_x_event = hold_exit_x_event; return retval; } /*winmap.c*/ nethack-3.4.3/win/X11/winmenu.c0100644000000000000000000007704107764735041014657 0ustar rootroot/* SCCS Id: @(#)winmenu.c 3.4 1996/08/15 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * File for creating menus. * * + Global functions: start_menu, add_menu, end_menu, select_menu */ /*#define USE_FWF*/ /* use FWF's list widget */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include #include #ifdef USE_FWF #include #else #include #endif #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "hack.h" #include "winX.h" #include static void FDECL(menu_select, (Widget, XtPointer, XtPointer)); static void FDECL(invert_line, (struct xwindow *,x11_menu_item *,int,long)); static void FDECL(menu_ok, (Widget, XtPointer, XtPointer)); static void FDECL(menu_cancel, (Widget, XtPointer, XtPointer)); static void FDECL(menu_all, (Widget, XtPointer, XtPointer)); static void FDECL(menu_none, (Widget, XtPointer, XtPointer)); static void FDECL(menu_invert, (Widget, XtPointer, XtPointer)); static void FDECL(menu_search, (Widget, XtPointer, XtPointer)); static void FDECL(select_all, (struct xwindow *)); static void FDECL(select_none, (struct xwindow *)); static void FDECL(select_match, (struct xwindow *, char*)); static void FDECL(invert_all, (struct xwindow *)); static void FDECL(invert_match, (struct xwindow *, char*)); static void FDECL(menu_popdown, (struct xwindow *)); #ifdef USE_FWF static void FDECL(sync_selected, (struct menu_info_t *, int, int *)); #endif static void FDECL(move_menu, (struct menu *, struct menu *)); static void FDECL(free_menu, (struct menu *)); static void FDECL(reset_menu_to_default, (struct menu *)); static void FDECL(clear_old_menu, (struct xwindow *)); static char *FDECL(copy_of, (const char *)); #define reset_menu_count(mi) ((mi)->counting = FALSE, (mi)->menu_count = 0L) static const char menu_translations[] = "#override\n\ Left: scroll(4)\n\ Right: scroll(6)\n\ Up: scroll(8)\n\ Down: scroll(2)\n\ : menu_key()"; /* * Menu callback. */ /* ARGSUSED */ static void menu_select(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { struct xwindow *wp; struct menu_info_t *menu_info; #ifdef USE_FWF XfwfMultiListReturnStruct *lrs = (XfwfMultiListReturnStruct *) call_data; #else XawListReturnStruct *lrs = (XawListReturnStruct *) call_data; int i; x11_menu_item *curr; #endif long how_many; wp = find_widget(w); menu_info = wp->menu_information; how_many = menu_info->counting ? menu_info->menu_count : -1L; reset_menu_count(menu_info); #ifdef USE_FWF /* if we've reached here, we've found our selected item */ switch (lrs->action) { case XfwfMultiListActionNothing: pline("menu_select: nothing action?"); break; case XfwfMultiListActionStatus: pline("menu_select: status action?"); break; case XfwfMultiListActionHighlight: case XfwfMultiListActionUnhighlight: sync_selected(menu_info,lrs->num_selected,lrs->selected_items); break; } #else for (i = 0, curr = menu_info->curr_menu.base; i < lrs->list_index; i++) { if (!curr) panic("menu_select: out of menu items!"); curr = curr->next; } XawListUnhighlight(w); /* unhilight item */ /* if the menu is not active or don't have an identifier, try again */ if (!menu_info->is_active || curr->identifier.a_void == 0) { X11_nhbell(); return; } /* if we've reached here, we've found our selected item */ curr->selected = !curr->selected; if (curr->selected) { curr->str[2] = (how_many != -1L) ? '#' : '+'; curr->pick_count = how_many; } else { curr->str[2] = '-'; curr->pick_count = -1L; } XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True); #endif if (menu_info->how == PICK_ONE) menu_popdown(wp); } /* * Called when menu window is deleted. */ /* ARGSUSED */ void menu_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { menu_cancel((Widget)None, (XtPointer) find_widget(w), (XtPointer) 0); } /* * Invert the count'th line (curr) in the given window. */ /*ARGSUSED*/ static void invert_line(wp, curr, which, how_many) struct xwindow *wp; x11_menu_item *curr; int which; long how_many; { reset_menu_count(wp->menu_information); curr->selected = !curr->selected; if (curr->selected) { #ifdef USE_FWF XfwfMultiListHighlightItem((XfwfMultiListWidget)wp->w, which); #else curr->str[2] = (how_many != -1) ? '#' : '+'; #endif curr->pick_count = how_many; } else { #ifdef USE_FWF XfwfMultiListUnhighlightItem((XfwfMultiListWidget)wp->w, which); #else curr->str[2] = '-'; #endif curr->pick_count = -1L; } } /* * Called when we get a key press event on a menu window. */ /* ARGSUSED */ void menu_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { struct menu_info_t *menu_info; x11_menu_item *curr; struct xwindow *wp; char ch; int count; wp = find_widget(w); menu_info = wp->menu_information; ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } if (menu_info->is_active) { /* waiting for input */ ch = map_menu_cmd(ch); if (ch == '\033') { /* quit */ if (menu_info->counting) { /* when there's a count in progress, ESC discards it rather than dismissing the whole menu */ reset_menu_count(menu_info); return; } select_none(wp); } else if (ch == '\n' || ch == '\r') { ; /* accept */ } else if (isdigit(ch)) { /* special case: '0' is also the default ball class */ if (ch == '0' && !menu_info->counting && index(menu_info->curr_menu.gacc, ch)) goto group_accel; menu_info->menu_count *= 10L; menu_info->menu_count += (long)(ch - '0'); if (menu_info->menu_count != 0L) /* ignore leading zeros */ menu_info->counting = TRUE; return; } else if (ch == MENU_SEARCH) { /* search */ if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) { char buf[BUFSZ]; X11_getlin("Search for:", buf); if (!*buf || *buf == '\033') return; if (menu_info->how == PICK_ANY) { invert_match(wp, buf); return; } else { select_match(wp, buf); } } else { X11_nhbell(); return; } } else if (ch == MENU_SELECT_ALL) { /* select all */ if (menu_info->how == PICK_ANY) select_all(wp); else X11_nhbell(); return; } else if (ch == MENU_UNSELECT_ALL) { /* unselect all */ if (menu_info->how == PICK_ANY) select_none(wp); else X11_nhbell(); return; } else if (ch == MENU_INVERT_ALL) { /* invert all */ if (menu_info->how == PICK_ANY) invert_all(wp); else X11_nhbell(); return; } else if (index(menu_info->curr_menu.gacc, ch)) { group_accel: /* matched a group accelerator */ if (menu_info->how == PICK_ANY || menu_info->how == PICK_ONE) { for (count = 0, curr = menu_info->curr_menu.base; curr; curr = curr->next, count++) { if (curr->identifier.a_void != 0 && curr->gselector == ch) { invert_line(wp, curr, count, -1L); /* for PICK_ONE, a group accelerator will only be included in gacc[] if it matches exactly one entry, so this must be it... */ if (menu_info->how == PICK_ONE) goto menu_done; /* pop down */ } } #ifndef USE_FWF XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True); #endif } else X11_nhbell(); return; } else { boolean selected_something = FALSE; for (count = 0, curr = menu_info->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0 && curr->selector == ch) break; if (curr) { invert_line(wp, curr, count, menu_info->counting ? menu_info->menu_count : -1L); #ifndef USE_FWF XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, True); #endif selected_something = curr->selected; } else { X11_nhbell(); /* no match */ } if (!(selected_something && menu_info->how == PICK_ONE)) return; /* keep going */ } /* pop down */ } else { /* permanent inventory window */ if (ch != '\033') { X11_nhbell(); return; } /* pop down on ESC */ } menu_done: menu_popdown(wp); } /* ARGSUSED */ static void menu_ok(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { struct xwindow *wp = (struct xwindow *) client_data; menu_popdown(wp); } /* ARGSUSED */ static void menu_cancel(w, client_data, call_data) Widget w; /* don't use - may be None */ XtPointer client_data, call_data; { struct xwindow *wp = (struct xwindow *) client_data; if (wp->menu_information->is_active) { select_none(wp); wp->menu_information->cancelled = TRUE; } menu_popdown(wp); } /* ARGSUSED */ static void menu_all(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { select_all((struct xwindow *) client_data); } /* ARGSUSED */ static void menu_none(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { select_none((struct xwindow *) client_data); } /* ARGSUSED */ static void menu_invert(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { invert_all((struct xwindow *) client_data); } /* ARGSUSED */ static void menu_search(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { struct xwindow *wp = (struct xwindow *) client_data; struct menu_info_t *menu_info = wp->menu_information; char buf[BUFSZ]; X11_getlin("Search for:", buf); if (!*buf || *buf == '\033') return; if (menu_info->how == PICK_ANY) invert_match(wp, buf); else select_match(wp, buf); if (menu_info->how == PICK_ONE) menu_popdown(wp); } static void select_all(wp) struct xwindow *wp; { x11_menu_item *curr; int count; boolean changed = FALSE; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0) if (!curr->selected) { invert_line(wp, curr, count, -1L); changed = TRUE; } #ifndef USE_FWF if (changed) XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } static void select_none(wp) struct xwindow *wp; { x11_menu_item *curr; int count; boolean changed = FALSE; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0) if (curr->selected) { invert_line(wp, curr, count, -1L); changed = TRUE; } #ifndef USE_FWF if (changed) XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } static void invert_all(wp) struct xwindow *wp; { x11_menu_item *curr; int count; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0) invert_line(wp, curr, count, -1L); #ifndef USE_FWF XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } static void invert_match(wp, match) struct xwindow *wp; char *match; { x11_menu_item *curr; int count; boolean changed = FALSE; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0 && strstri(curr->str, match)) { invert_line(wp, curr, count, -1L); changed = TRUE; } #ifndef USE_FWF if (changed) XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } static void select_match(wp, match) struct xwindow *wp; char *match; { x11_menu_item *curr; int count; reset_menu_count(wp->menu_information); for (count = 0, curr = wp->menu_information->curr_menu.base; curr; curr = curr->next, count++) if (curr->identifier.a_void != 0 && strstri(curr->str, match)) { if (!curr->selected) { invert_line(wp, curr, count, -1L); #ifndef USE_FWF XawListChange(wp->w, wp->menu_information->curr_menu.list_pointer, 0, 0, True); #endif } return; } /* no match */ X11_nhbell(); } static void menu_popdown(wp) struct xwindow *wp; { nh_XtPopdown(wp->popup); /* remove the event grab */ if (wp->menu_information->is_active) exit_x_event = TRUE; /* exit our event handler */ wp->menu_information->is_up = FALSE; /* menu is down */ } #ifdef USE_FWF /* * Make sure our idea of selected matches the FWF Multilist's idea of what * is currently selected. The MultiList's selected list can change without * notifying us if one or more items are selected and then another is * selected (not toggled). Then the items that were selected are deselected * but we are not notified. */ static void sync_selected(menu_info, num_selected, items) struct menu_info_t *menu_info; int num_selected; int *items; { int i, j, *ip; x11_menu_item *curr; Boolean found; for (i=0, curr = menu_info->curr_menu.base; curr; i++, curr = curr->next) { found = False; for (j = 0, ip = items; j < num_selected; j++, ip++) if (*ip == i) { found = True; break; } #if 0 if (curr->selected && !found) printf("sync: deselecting %s\n", curr->str); else if (!curr->selected && found) printf("sync: selecting %s\n", curr->str); #endif curr->selected = found ? TRUE : FALSE; } } #endif /* USE_FWF */ /* Global functions ======================================================== */ void X11_start_menu(window) winid window; { struct xwindow *wp; check_winid(window); wp = &window_list[window]; if (wp->menu_information->is_menu) { /* make sure we'ere starting with a clean slate */ free_menu(&wp->menu_information->new_menu); } else { wp->menu_information->is_menu = TRUE; } } /*ARGSUSED*/ void X11_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) winid window; int glyph; /* unused (for now) */ const anything *identifier; char ch; char gch; /* group accelerator (0 = no group) */ int attr; const char *str; boolean preselected; { x11_menu_item *item; struct menu_info_t *menu_info; check_winid(window); menu_info = window_list[window].menu_information; if (!menu_info->is_menu) { impossible("add_menu: called before start_menu"); return; } item = (x11_menu_item *) alloc((unsigned)sizeof(x11_menu_item)); item->next = (x11_menu_item *) 0; item->identifier = *identifier; item->attr = attr; /* item->selected = preselected; */ item->selected = FALSE; item->pick_count = -1L; if (identifier->a_void) { char buf[4+BUFSZ]; int len = strlen(str); if (!ch) { /* Supply a keyboard accelerator. Only the first 52 get one. */ if (menu_info->new_menu.curr_selector) { ch = menu_info->new_menu.curr_selector++; if (ch == 'z') menu_info->new_menu.curr_selector = 'A'; else if (ch == 'Z') menu_info->new_menu.curr_selector = 0; /* out */ } } if (len >= BUFSZ) { /* We *think* everything's coming in off at most BUFSZ bufs... */ impossible("Menu item too long (%d).", len); len = BUFSZ - 1; } Sprintf(buf, "%c - ", ch ? ch : ' '); (void) strncpy(buf+4, str, len); buf[4+len] = '\0'; item->str = copy_of(buf); } else { /* no keyboard accelerator */ item->str = copy_of(str); ch = 0; } item->selector = ch; item->gselector = gch; if (menu_info->new_menu.last) { menu_info->new_menu.last->next = item; } else { menu_info->new_menu.base = item; } menu_info->new_menu.last = item; menu_info->new_menu.count++; } void X11_end_menu(window, query) winid window; const char *query; { struct menu_info_t *menu_info; check_winid(window); menu_info = window_list[window].menu_information; if (!menu_info->is_menu) { impossible("end_menu: called before start_menu"); return; } menu_info->new_menu.query = copy_of(query); } int X11_select_menu(window, how, menu_list) winid window; int how; menu_item **menu_list; { x11_menu_item *curr; struct xwindow *wp; struct menu_info_t *menu_info; Arg args[10]; Cardinal num_args; String *ptr; int retval; Dimension v_pixel_width, v_pixel_height; boolean labeled; Widget viewport_widget, form, label, ok, cancel, all, none, invert, search; Boolean sens; #ifdef USE_FWF Boolean *boolp; #endif char gacc[QBUFSZ], *ap; *menu_list = (menu_item *) 0; check_winid(window); wp = &window_list[window]; menu_info = wp->menu_information; if (!menu_info->is_menu) { impossible("select_menu: called before start_menu"); return 0; } menu_info->how = (short) how; /* collect group accelerators; for PICK_NONE, they're ignored; for PICK_ONE, only those which match exactly one entry will be accepted; for PICK_ANY, those which match any entry are okay */ gacc[0] = '\0'; if (menu_info->how != PICK_NONE) { int i, n, gcnt[128]; #define GSELIDX(c) ((c) & 127) /* guard against `signed char' */ for (i = 0; i < SIZE(gcnt); i++) gcnt[i] = 0; for (n = 0, curr = menu_info->new_menu.base; curr; curr = curr->next) if (curr->gselector && curr->gselector != curr->selector) { ++n; ++gcnt[GSELIDX(curr->gselector)]; } if (n > 0) /* at least one group accelerator found */ for (ap = gacc, curr = menu_info->new_menu.base; curr; curr = curr->next) if (curr->gselector && !index(gacc, curr->gselector) && (menu_info->how == PICK_ANY || gcnt[GSELIDX(curr->gselector)] == 1)) { *ap++ = curr->gselector; *ap = '\0'; /* re-terminate for index() */ } } menu_info->new_menu.gacc = copy_of(gacc); reset_menu_count(menu_info); /* * Create a string and sensitive list for the new menu. */ menu_info->new_menu.list_pointer = ptr = (String *) alloc((unsigned) (sizeof(String) * (menu_info->new_menu.count+1))); for (curr = menu_info->new_menu.base; curr; ptr++, curr = curr->next) *ptr = (String) curr->str; *ptr = 0; /* terminate list with null */ #ifdef USE_FWF menu_info->new_menu.sensitive = boolp = (Boolean *) alloc((unsigned) (sizeof(Boolean) * (menu_info->new_menu.count))); for (curr = menu_info->new_menu.base; curr; boolp++, curr = curr->next) *boolp = (curr->identifier.a_void != 0); #else menu_info->new_menu.sensitive = (Boolean *) 0; #endif labeled = (menu_info->new_menu.query && *(menu_info->new_menu.query)) ? TRUE : FALSE; /* * Menus don't appear to size components correctly, except * when first created. For 3.2.0 release, just recreate * each time. */ if (menu_info->valid_widgets && (window != WIN_INVEN || !flags.perm_invent)) { XtDestroyWidget(wp->popup); menu_info->valid_widgets = FALSE; menu_info->is_up = FALSE; } if (!menu_info->valid_widgets) { Dimension row_spacing; num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; wp->popup = XtCreatePopupShell( window == WIN_INVEN ? "inventory" : "menu", how == PICK_NONE ? topLevelShellWidgetClass: transientShellWidgetClass, toplevel, args, num_args); XtOverrideTranslations(wp->popup, XtParseTranslationTable("WM_PROTOCOLS: menu_delete()")); num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(menu_translations)); num_args++; form = XtCreateManagedWidget("mform", formWidgetClass, wp->popup, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; if (labeled) label = XtCreateManagedWidget(menu_info->new_menu.query, labelWidgetClass, form, args, num_args); else label = NULL; /* * Create ok, cancel, all, none, invert, and search buttons.. */ num_args = 0; XtSetArg(args[num_args], XtNfromVert, label); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; ok = XtCreateManagedWidget("OK", commandWidgetClass, form, args, num_args); XtAddCallback(ok, XtNcallback, menu_ok, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], XtNfromVert, label); num_args++; XtSetArg(args[num_args], XtNfromHoriz, ok); num_args++; XtSetArg(args[num_args], XtNsensitive, how!=PICK_NONE); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; cancel = XtCreateManagedWidget("cancel", commandWidgetClass, form, args, num_args); XtAddCallback(cancel, XtNcallback, menu_cancel, (XtPointer) wp); sens = (how == PICK_ANY); num_args = 0; XtSetArg(args[num_args], XtNfromVert, label); num_args++; XtSetArg(args[num_args], XtNfromHoriz, cancel); num_args++; XtSetArg(args[num_args], XtNsensitive, sens); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; all = XtCreateManagedWidget("all", commandWidgetClass, form, args, num_args); XtAddCallback(all, XtNcallback, menu_all, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], XtNfromVert, label); num_args++; XtSetArg(args[num_args], XtNfromHoriz, all); num_args++; XtSetArg(args[num_args], XtNsensitive, sens); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; none = XtCreateManagedWidget("none", commandWidgetClass, form, args, num_args); XtAddCallback(none, XtNcallback, menu_none, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], XtNfromVert, label); num_args++; XtSetArg(args[num_args], XtNfromHoriz, none); num_args++; XtSetArg(args[num_args], XtNsensitive, sens); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; invert = XtCreateManagedWidget("invert", commandWidgetClass, form, args, num_args); XtAddCallback(invert, XtNcallback, menu_invert, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], XtNfromVert, label); num_args++; XtSetArg(args[num_args], XtNfromHoriz, invert); num_args++; XtSetArg(args[num_args], XtNsensitive, how!=PICK_NONE); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainTop); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainLeft); num_args++; search = XtCreateManagedWidget("search", commandWidgetClass, form, args, num_args); XtAddCallback(search, XtNcallback, menu_search, (XtPointer) wp); num_args = 0; XtSetArg(args[num_args], XtNallowVert, True); num_args++; XtSetArg(args[num_args], XtNallowHoriz, False); num_args++; XtSetArg(args[num_args], XtNuseBottom, True); num_args++; XtSetArg(args[num_args], XtNuseRight, True); num_args++; /* XtSetArg(args[num_args], XtNforceBars, True); num_args++; */ XtSetArg(args[num_args], XtNfromVert, all); num_args++; XtSetArg(args[num_args], XtNtop, XtChainTop); num_args++; XtSetArg(args[num_args], XtNbottom, XtChainBottom); num_args++; XtSetArg(args[num_args], XtNleft, XtChainLeft); num_args++; XtSetArg(args[num_args], XtNright, XtChainRight); num_args++; viewport_widget = XtCreateManagedWidget( "menu_viewport", /* name */ viewportWidgetClass, form, /* parent widget */ args, num_args); /* values, and number of values */ /* make new menu the current menu */ move_menu(&menu_info->new_menu, &menu_info->curr_menu); num_args = 0; XtSetArg(args[num_args], XtNforceColumns, True); num_args++; XtSetArg(args[num_args], XtNcolumnSpacing, 1); num_args++; XtSetArg(args[num_args], XtNdefaultColumns, 1); num_args++; XtSetArg(args[num_args], XtNlist, menu_info->curr_menu.list_pointer); num_args++; #ifdef USE_FWF XtSetArg(args[num_args], XtNsensitiveArray, menu_info->curr_menu.sensitive); num_args++; XtSetArg(args[num_args], XtNmaxSelectable, menu_info->curr_menu.count); num_args++; #endif wp->w = XtCreateManagedWidget( "menu_list", /* name */ #ifdef USE_FWF xfwfMultiListWidgetClass, #else listWidgetClass, #endif viewport_widget, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ XtAddCallback(wp->w, XtNcallback, menu_select, (XtPointer) 0); /* Get the font and margin information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &menu_info->fs); num_args++; XtSetArg(args[num_args], XtNinternalHeight, &menu_info->internal_height); num_args++; XtSetArg(args[num_args], XtNinternalWidth, &menu_info->internal_width); num_args++; XtSetArg(args[num_args], XtNrowSpacing, &row_spacing); num_args++; XtGetValues(wp->w, args, num_args); /* font height is ascent + descent */ menu_info->line_height = menu_info->fs->max_bounds.ascent + menu_info->fs->max_bounds.descent + row_spacing; menu_info->valid_widgets = TRUE; num_args = 0; XtSetArg(args[num_args], XtNwidth, &v_pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, &v_pixel_height); num_args++; XtGetValues(wp->w, args, num_args); } else { Dimension len; viewport_widget = XtParent(wp->w); /* get the longest string on new menu */ v_pixel_width = 0; for (ptr = menu_info->new_menu.list_pointer; *ptr; ptr++) { len = XTextWidth(menu_info->fs, *ptr, strlen(*ptr)); if (len > v_pixel_width) v_pixel_width = len; } /* add viewport internal border */ v_pixel_width += 2 * menu_info->internal_width; v_pixel_height = (2 * menu_info->internal_height) + (menu_info->new_menu.count * menu_info->line_height); /* make new menu the current menu */ move_menu(&menu_info->new_menu, &menu_info->curr_menu); #ifdef USE_FWF XfwfMultiListSetNewData((XfwfMultiListWidget)wp->w, menu_info->curr_menu.list_pointer, 0, 0, TRUE, menu_info->curr_menu.sensitive); #else XawListChange(wp->w, menu_info->curr_menu.list_pointer, 0, 0, TRUE); #endif } /* if viewport will be bigger than the screen, limit its height */ num_args = 0; XtSetArg(args[num_args], XtNwidth, &v_pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, &v_pixel_height); num_args++; XtGetValues(wp->w, args, num_args); if ((Dimension) XtScreen(wp->w)->height * 5 / 6 < v_pixel_height) { /* scrollbar is 14 pixels wide. Widen the form to accommodate it. */ v_pixel_width += 14; /* shrink to fit vertically */ v_pixel_height = XtScreen(wp->w)->height * 5 / 6; num_args = 0; XtSetArg(args[num_args], XtNwidth, v_pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, v_pixel_height); num_args++; XtSetValues(wp->w, args, num_args); } XtRealizeWidget(wp->popup); /* need to realize before we position */ /* if menu is not up, position it */ if (!menu_info->is_up) positionpopup(wp->popup, FALSE); menu_info->is_up = TRUE; if (window == WIN_INVEN && how == PICK_NONE) { /* cant use nh_XtPopup() because it may try to grab the focus */ XtPopup(wp->popup, (int)XtGrabNone); if (!updated_inventory) XMapRaised(XtDisplay(wp->popup), XtWindow(wp->popup)); XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), &wm_delete_window, 1); retval = 0; } else { menu_info->is_active = TRUE; /* waiting for user response */ menu_info->cancelled = FALSE; nh_XtPopup(wp->popup, (int)XtGrabExclusive, wp->w); (void) x_event(EXIT_ON_EXIT); menu_info->is_active = FALSE; if (menu_info->cancelled) return -1; retval = 0; for (curr = menu_info->curr_menu.base; curr; curr = curr->next) if (curr->selected) retval++; if (retval) { menu_item *mi; *menu_list = mi = (menu_item *) alloc(retval * sizeof(menu_item)); for (curr = menu_info->curr_menu.base; curr; curr = curr->next) if (curr->selected) { mi->item = curr->identifier; mi->count = curr->pick_count; mi++; } } } return retval; } /* End global functions ==================================================== */ /* * Allocate a copy of the given string. If null, return a string of * zero length. * * This is an exact duplicate of copy_of() in tty/wintty.c. */ static char * copy_of(s) const char *s; { if (!s) s = ""; return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s); } static void move_menu(src_menu, dest_menu) struct menu *src_menu, *dest_menu; { free_menu(dest_menu); /* toss old menu */ *dest_menu = *src_menu; /* make new menu current */ /* leave no dangling ptrs */ reset_menu_to_default(src_menu); } static void free_menu(mp) struct menu *mp; { while (mp->base) { mp->last = mp->base; mp->base = mp->base->next; free((genericptr_t)mp->last->str); free((genericptr_t)mp->last); } if (mp->query) free((genericptr_t) mp->query); if (mp->gacc) free((genericptr_t) mp->gacc); if (mp->list_pointer) free((genericptr_t) mp->list_pointer); if (mp->sensitive) free((genericptr_t) mp->sensitive); reset_menu_to_default(mp); } static void reset_menu_to_default(mp) struct menu *mp; { mp->base = mp->last = (x11_menu_item *)0; mp->query = (const char *)0; mp->gacc = (const char *)0; mp->count = 0; mp->list_pointer = (String *)0; mp->sensitive = (Boolean *)0; mp->curr_selector = 'a'; /* first accelerator */ } static void clear_old_menu(wp) struct xwindow *wp; { struct menu_info_t *menu_info = wp->menu_information; free_menu(&menu_info->curr_menu); free_menu(&menu_info->new_menu); if (menu_info->valid_widgets) { nh_XtPopdown(wp->popup); menu_info->is_up = FALSE; XtDestroyWidget(wp->popup); menu_info->valid_widgets = FALSE; wp->w = wp->popup = (Widget) 0; } } void create_menu_window(wp) struct xwindow *wp; { wp->type = NHW_MENU; wp->menu_information = (struct menu_info_t *) alloc(sizeof(struct menu_info_t)); (void) memset((genericptr_t) wp->menu_information, '\0', sizeof(struct menu_info_t)); reset_menu_to_default(&wp->menu_information->curr_menu); reset_menu_to_default(&wp->menu_information->new_menu); reset_menu_count(wp->menu_information); wp->w = wp->popup = (Widget) 0; } void destroy_menu_window(wp) struct xwindow *wp; { clear_old_menu(wp); /* this will also destroy the widgets */ free((genericptr_t) wp->menu_information); wp->menu_information = (struct menu_info_t *) 0; wp->type = NHW_NONE; /* allow re-use */ } /*winmenu.c*/ nethack-3.4.3/win/X11/winmesg.c0100644000000000000000000004221407764735041014640 0ustar rootroot/* SCCS Id: @(#)winmesg.c 3.4 1996/04/05 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Message window routines. * * Global functions: * create_message_window() * destroy_message_window() * display_message_window() * append_message() */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "xwindow.h" /* Window widget declarations */ #include "hack.h" #include "winX.h" static struct line_element *FDECL(get_previous, (struct line_element *)); static void FDECL(set_circle_buf, (struct mesg_info_t *,int)); static char *FDECL(split, (char *,XFontStruct *,DIMENSION_P)); static void FDECL(add_line, (struct mesg_info_t *,const char *)); static void FDECL(redraw_message_window, (struct xwindow *)); static void FDECL(mesg_check_size_change, (struct xwindow *)); static void FDECL(mesg_exposed, (Widget,XtPointer,XtPointer)); static void FDECL(get_gc, (Widget,struct mesg_info_t *)); static void FDECL(mesg_resized, (Widget,XtPointer,XtPointer)); static char mesg_translations[] = "#override\n\ : input() \ "; /* Move the message window's vertical scrollbar's slider to the bottom. */ void set_message_slider(wp) struct xwindow *wp; { Widget scrollbar; float top; scrollbar = XtNameToWidget(XtParent(wp->w), "vertical"); if (scrollbar) { top = 1.0; XtCallCallbacks(scrollbar, XtNjumpProc, &top); } } void create_message_window(wp, create_popup, parent) struct xwindow *wp; /* window pointer */ boolean create_popup; Widget parent; { Arg args[8]; Cardinal num_args; Widget viewport; struct mesg_info_t *mesg_info; wp->type = NHW_MESSAGE; wp->mesg_information = mesg_info = (struct mesg_info_t *) alloc(sizeof(struct mesg_info_t)); mesg_info->fs = 0; mesg_info->num_lines = 0; mesg_info->head = mesg_info->line_here = mesg_info->last_pause = mesg_info->last_pause_head = (struct line_element *) 0; mesg_info->dirty = False; mesg_info->viewport_width = mesg_info->viewport_height = 0; if (iflags.msg_history < appResources.message_lines) iflags.msg_history = appResources.message_lines; if (iflags.msg_history > MAX_HISTORY) /* a sanity check */ iflags.msg_history = MAX_HISTORY; set_circle_buf(mesg_info, (int) iflags.msg_history); /* Create a popup that becomes the parent. */ if (create_popup) { num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; wp->popup = parent = XtCreatePopupShell("message_popup", topLevelShellWidgetClass, toplevel, args, num_args); /* * If we're here, then this is an auxiliary message window. If we're * cancelled via a delete window message, we should just pop down. */ } /* * Create the viewport. We only want the vertical scroll bar ever to be * visible. If we allow the horizontal scrollbar to be visible it will * always be visible, due to the stupid way the Athena viewport operates. */ num_args = 0; XtSetArg(args[num_args], XtNallowVert, True); num_args++; viewport = XtCreateManagedWidget( "mesg_viewport", /* name */ viewportWidgetClass, /* widget class from Window.h */ parent, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* * Create a message window. We will change the width and height once * we know what font we are using. */ num_args = 0; if (!create_popup) { XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(mesg_translations)); num_args++; } wp->w = XtCreateManagedWidget( "message", /* name */ windowWidgetClass, /* widget class from Window.h */ viewport, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ XtAddCallback(wp->w, XtNexposeCallback, mesg_exposed, (XtPointer) 0); /* * Now adjust the height and width of the message window so that it * is appResources.message_lines high and DEFAULT_MESSAGE_WIDTH wide. */ /* Get the font information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &mesg_info->fs); num_args++; XtGetValues(wp->w, args, num_args); /* Save character information for fast use later. */ mesg_info->char_width = mesg_info->fs->max_bounds.width; mesg_info->char_height = mesg_info->fs->max_bounds.ascent + mesg_info->fs->max_bounds.descent; mesg_info->char_ascent = mesg_info->fs->max_bounds.ascent; mesg_info->char_lbearing = -mesg_info->fs->min_bounds.lbearing; get_gc(wp->w, mesg_info); wp->pixel_height = ((int)iflags.msg_history) * mesg_info->char_height; /* If a variable spaced font, only use 2/3 of the default size */ if (mesg_info->fs->min_bounds.width != mesg_info->fs->max_bounds.width) { wp->pixel_width = ((2*DEFAULT_MESSAGE_WIDTH)/3) * mesg_info->fs->max_bounds.width; } else wp->pixel_width = (DEFAULT_MESSAGE_WIDTH * mesg_info->fs->max_bounds.width); /* Set the new width and height. */ num_args = 0; XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++; XtSetValues(wp->w, args, num_args); /* make sure viewport height makes sense before realizing it */ num_args = 0; mesg_info->viewport_height = appResources.message_lines * mesg_info->char_height; XtSetArg(args[num_args], XtNheight, mesg_info->viewport_height);num_args++; XtSetValues(viewport, args, num_args); XtAddCallback(wp->w, XtNresizeCallback, mesg_resized, (XtPointer) 0); /* * If we have created our own popup, then realize it so that the * viewport is also realized. */ if (create_popup) { XtRealizeWidget(wp->popup); XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), &wm_delete_window, 1); } } void destroy_message_window(wp) struct xwindow *wp; { if (wp->popup) { nh_XtPopdown(wp->popup); if (!wp->keep_window) XtDestroyWidget(wp->popup), wp->popup = (Widget)0; } if (wp->mesg_information) { set_circle_buf(wp->mesg_information, 0); /* free buffer list */ free((genericptr_t)wp->mesg_information), wp->mesg_information = 0; } if (wp->keep_window) XtRemoveCallback(wp->w, XtNexposeCallback, mesg_exposed, (XtPointer)0); else wp->type = NHW_NONE; } /* Redraw message window if new lines have been added. */ void display_message_window(wp) struct xwindow *wp; { if (wp->mesg_information->dirty) redraw_message_window(wp); } /* * Append a line of text to the message window. Split the line if the * rendering of the text is too long for the window. */ void append_message(wp, str) struct xwindow *wp; const char *str; { char *mark, *remainder, buf[BUFSZ]; if (!str) return; Strcpy(buf, str); /* we might mark it up */ remainder = buf; do { mark = remainder; remainder = split(mark, wp->mesg_information->fs, wp->pixel_width); add_line(wp->mesg_information, mark); } while (remainder); } /* private functions ======================================================= */ /* * Return the element in the circular linked list just before the given * element. */ static struct line_element * get_previous(mark) struct line_element *mark; { struct line_element *curr; if (!mark) return (struct line_element *) 0; for (curr = mark; curr->next != mark; curr = curr->next) ; return curr; } /* * Set the information buffer size to count lines. We do this by creating * a circular linked list of elements, each of which represents a line of * text. New buffers are created as needed, old ones are freed if they * are no longer used. */ static void set_circle_buf(mesg_info, count) struct mesg_info_t *mesg_info; int count; { int i; struct line_element *tail, *curr, *head; if (count < 0) panic("set_circle_buf: bad count [= %d]", count); if (count == mesg_info->num_lines) return; /* no change in size */ if (count < mesg_info->num_lines) { /* * Toss num_lines - count line entries from our circular list. * * We lose lines from the front (top) of the list. We _know_ * the list is non_empty. */ tail = get_previous(mesg_info->head); for (i = mesg_info->num_lines - count; i > 0; i--) { curr = mesg_info->head; mesg_info->head = curr->next; if (curr->line) free((genericptr_t)curr->line); free((genericptr_t)curr); } if (count == 0) { /* make sure we don't have a dangling pointer */ mesg_info->head = (struct line_element *) 0; } else { tail->next = mesg_info->head; /* link the tail to the head */ } } else { /* * Add count - num_lines blank lines to the head of the list. * * Create a separate list, keeping track of the tail. */ for (head = tail = 0, i = 0; i < count - mesg_info->num_lines; i++) { curr = (struct line_element *) alloc(sizeof(struct line_element)); curr->line = 0; curr->buf_length = 0; curr->str_length = 0; if (tail) { tail->next = curr; tail = curr; } else { head = tail = curr; } } /* * Complete the circle by making the new tail point to the old head * and the old tail point to the new head. If our line count was * zero, then make the new list circular. */ if (mesg_info->num_lines) { curr = get_previous(mesg_info->head);/* get end of old list */ tail->next = mesg_info->head; /* new tail -> old head */ curr->next = head; /* old tail -> new head */ } else { tail->next = head; } mesg_info->head = head; } mesg_info->num_lines = count; /* Erase the line on a resize. */ mesg_info->last_pause = (struct line_element *) 0; } /* * Make sure the given string is shorter than the given pixel width. If * not, back up from the end by words until we find a place to split. */ static char * split(s, fs, pixel_width) char *s; XFontStruct *fs; /* Font for the window. */ Dimension pixel_width; { char save, *end, *remainder; save = '\0'; remainder = 0; end = eos(s); /* point to null at end of string */ /* assume that if end == s, XXXXXX returns 0) */ while ((Dimension) XTextWidth(fs, s, (int) strlen(s)) > pixel_width) { *end-- = save; while (*end != ' ') { if (end == s) panic("split: eos!"); --end; } save = *end; *end = '\0'; remainder = end + 1; } return remainder; } /* * Add a line of text to the window. The first line in the curcular list * becomes the last. So all we have to do is copy the new line over the * old one. If the line buffer is too small, then allocate a new, larger * one. */ static void add_line(mesg_info, s) struct mesg_info_t *mesg_info; const char *s; { register struct line_element *curr = mesg_info->head; register int new_line_length = strlen(s); if (new_line_length + 1 > curr->buf_length) { if (curr->line) free(curr->line); /* free old line */ curr->buf_length = new_line_length + 1; curr->line = (char *) alloc((unsigned)curr->buf_length); } Strcpy(curr->line, s); /* copy info */ curr->str_length = new_line_length; /* save string length */ mesg_info->head = mesg_info->head->next; /* move head to next line */ mesg_info->dirty = True; /* we have undrawn lines */ } /* * Save a position in the text buffer so we can draw a line to seperate * text from the last time this function was called. * * Save the head position, since it is the line "after" the last displayed * line in the message window. The window redraw routine will draw a * line above this saved pointer. */ void set_last_pause(wp) struct xwindow *wp; { register struct mesg_info_t *mesg_info = wp->mesg_information; #ifdef ERASE_LINE /* * If we've erased the pause line and haven't added any new lines, * don't try to erase the line again. */ if (!mesg_info->last_pause && mesg_info->last_pause_head == mesg_info->head) return; if (mesg_info->last_pause == mesg_info->head) { /* No new messages in last turn. Redraw window to erase line. */ mesg_info->last_pause = (struct line_element *) 0; mesg_info->last_pause_head = mesg_info->head; redraw_message_window(wp); } else { #endif mesg_info->last_pause = mesg_info->head; #ifdef ERASE_LINE } #endif } static void redraw_message_window(wp) struct xwindow *wp; { struct mesg_info_t *mesg_info = wp->mesg_information; register struct line_element *curr; register int row, y_base; /* * Do this the cheap and easy way. Clear the window and just redraw * the whole thing. * * This could be done more effecently with one call to XDrawText() instead * of many calls to XDrawString(). Maybe later. * * Only need to clear if window has new text. */ if (mesg_info->dirty) { XClearWindow(XtDisplay(wp->w), XtWindow(wp->w)); mesg_info->line_here = mesg_info->last_pause; } /* For now, just update the whole shootn' match. */ for (y_base = row = 0, curr = mesg_info->head; row < mesg_info->num_lines; row++, y_base += mesg_info->char_height, curr = curr->next) { XDrawString(XtDisplay(wp->w), XtWindow(wp->w), mesg_info->gc, mesg_info->char_lbearing, mesg_info->char_ascent + y_base, curr->line, curr->str_length); /* * This draws a line at the _top_ of the line of text pointed to by * mesg_info->last_pause. */ if (appResources.message_line && curr == mesg_info->line_here) { XDrawLine(XtDisplay(wp->w), XtWindow(wp->w), mesg_info->gc, 0, y_base, wp->pixel_width, y_base); } } mesg_info->dirty = False; } /* * Check the size of the viewport. If it has shrunk, then we want to * move the vertical slider to the bottom. */ static void mesg_check_size_change(wp) struct xwindow *wp; { struct mesg_info_t *mesg_info = wp->mesg_information; Arg arg[2]; Dimension new_width, new_height; Widget viewport; viewport = XtParent(wp->w); XtSetArg(arg[0], XtNwidth, &new_width); XtSetArg(arg[1], XtNheight, &new_height); XtGetValues(viewport, arg, TWO); /* Only move slider to bottom if new size is smaller. */ if (new_width < mesg_info->viewport_width || new_height < mesg_info->viewport_height) { set_message_slider(wp); } mesg_info->viewport_width = new_width; mesg_info->viewport_height = new_height; } /* Event handler for message window expose events. */ /*ARGSUSED*/ static void mesg_exposed(w, client_data, widget_data) Widget w; XtPointer client_data; /* unused */ XtPointer widget_data; /* expose event from Window widget */ { XExposeEvent *event = (XExposeEvent *) widget_data; if (XtIsRealized(w) && event->count == 0) { struct xwindow *wp; Display *dpy; Window win; XEvent evt; /* * Drain all pending expose events for the message window; * we'll redraw the whole thing at once. */ dpy = XtDisplay(w); win = XtWindow(w); while (XCheckTypedWindowEvent(dpy, win, Expose, &evt)) continue; wp = find_widget(w); if (wp->keep_window && !wp->mesg_information) return; mesg_check_size_change(wp); redraw_message_window(wp); } } static void get_gc(w, mesg_info) Widget w; struct mesg_info_t *mesg_info; { XGCValues values; XtGCMask mask = GCFunction | GCForeground | GCBackground | GCFont; Pixel fgpixel, bgpixel; Arg arg[2]; XtSetArg(arg[0], XtNforeground, &fgpixel); XtSetArg(arg[1], XtNbackground, &bgpixel); XtGetValues(w, arg, TWO); values.foreground = fgpixel; values.background = bgpixel; values.function = GXcopy; values.font = WindowFont(w); mesg_info->gc = XtGetGC(w, mask, &values); } /* * Handle resizes on a message window. Correct saved pixel height and width. * Adjust circle buffer to accomidate the new size. * * Problem: If the resize decreases the width of the window such that * some lines are now longer than the window, they will be cut off by * X itself. All new lines will be split to the new size, but the ends * of the old ones will not be seen again unless the window is lengthened. * I don't deal with this problem because it isn't worth the trouble. */ /* ARGSUSED */ static void mesg_resized(w, client_data, call_data) Widget w; XtPointer call_data, client_data; { Arg args[4]; Cardinal num_args; Dimension pixel_width, pixel_height; struct xwindow *wp; #ifdef VERBOSE int old_lines; old_lines = wp->mesg_information->num_lines;; #endif num_args = 0; XtSetArg(args[num_args], XtNwidth, &pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, &pixel_height); num_args++; XtGetValues(w, args, num_args); wp = find_widget(w); wp->pixel_width = pixel_width; wp->pixel_height = pixel_height; set_circle_buf(wp->mesg_information, (int) pixel_height / wp->mesg_information->char_height); #ifdef VERBOSE printf("Message resize. Pixel: width = %d, height = %d; Lines: old = %d, new = %d\n", pixel_width, pixel_height, old_lines, wp->mesg_information->num_lines); #endif } /*winmesg.c*/ nethack-3.4.3/win/X11/winmisc.c0100644000000000000000000006163307764735041014646 0ustar rootroot/* SCCS Id: @(#)winmisc.c 3.4 2000/05/21 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Misc. popup windows: player selection and extended commands. * * + Global functions: player_selection() and get_ext_cmd(). */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include /* for index() */ #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "hack.h" #include "func_tab.h" #include "winX.h" static Widget extended_command_popup = 0; static Widget extended_command_form; static Widget *extended_commands = 0; static int extended_command_selected; /* index of the selected command; */ static int ps_selected; /* index of selected role */ #define PS_RANDOM (-50) #define PS_QUIT (-75) static const char ps_randchars[] = "*@"; static const char ps_quitchars[] = "\033qQ"; #define EC_NCHARS 32 static boolean ec_active = FALSE; static int ec_nchars = 0; static char ec_chars[EC_NCHARS]; static Time ec_time; static const char extended_command_translations[] = "#override\n\ : ec_key()"; static const char player_select_translations[] = "#override\n\ : ps_key()"; static const char race_select_translations[] = "#override\n\ : race_key()"; static const char gend_select_translations[] = "#override\n\ : gend_key()"; static const char algn_select_translations[] = "#override\n\ : algn_key()"; static void FDECL(popup_delete, (Widget, XEvent*, String*, Cardinal*)); static void NDECL(ec_dismiss); static Widget FDECL(make_menu, (const char *,const char *,const char *, const char *,XtCallbackProc, const char *,XtCallbackProc, int,const char **, Widget **, XtCallbackProc,Widget *)); static void NDECL(init_extended_commands_popup); static void FDECL(ps_quit, (Widget,XtPointer,XtPointer)); static void FDECL(ps_random, (Widget,XtPointer,XtPointer)); static void FDECL(ps_select, (Widget,XtPointer,XtPointer)); /* Player Selection -------------------------------------------------------- */ /* ARGSUSED */ static void ps_quit(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { ps_selected = PS_QUIT; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ static void ps_random(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { ps_selected = PS_RANDOM; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ static void ps_select(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { ps_selected = (int) client_data; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ void ps_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch, *mark; char rolechars[QBUFSZ]; int i; (void)memset(rolechars, '\0', sizeof rolechars); /* for index() */ for (i = 0; roles[i].name.m; ++i) { ch = lowc(*roles[i].name.m); /* if (flags.female && roles[i].name.f) ch = lowc(*roles[i].name.f); */ /* this supports at most two roles with the same first letter */ if (index(rolechars, ch)) ch = highc(ch); rolechars[i] = ch; } ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } mark = index(rolechars, ch); if (!mark) mark = index(rolechars, lowc(ch)); if (!mark) mark = index(rolechars, highc(ch)); if (!mark) { if (index(ps_randchars, ch)) ps_selected = PS_RANDOM; else if (index(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such class */ return; } } else ps_selected = (int)(mark - rolechars); exit_x_event = TRUE; } /* ARGSUSED */ void race_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch, *mark; char racechars[QBUFSZ]; int i; (void)memset(racechars, '\0', sizeof racechars); /* for index() */ for (i = 0; races[i].noun; ++i) { ch = lowc(*races[i].noun); /* this supports at most two races with the same first letter */ if (index(racechars, ch)) ch = highc(ch); racechars[i] = ch; } ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } mark = index(racechars, ch); if (!mark) mark = index(racechars, lowc(ch)); if (!mark) mark = index(racechars, highc(ch)); if (!mark) { if (index(ps_randchars, ch)) ps_selected = PS_RANDOM; else if (index(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such race */ return; } } else ps_selected = (int)(mark - racechars); exit_x_event = TRUE; } /* ARGSUSED */ void gend_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch, *mark; static char gendchars[] = "mf"; ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } mark = index(gendchars, ch); if (!mark) mark = index(gendchars, lowc(ch)); if (!mark) { if (index(ps_randchars, ch)) ps_selected = PS_RANDOM; else if (index(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such gender */ return; } } else ps_selected = (int)(mark - gendchars); exit_x_event = TRUE; } /* ARGSUSED */ void algn_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch, *mark; static char algnchars[] = "LNC"; ch = key_event_to_char((XKeyEvent *) event); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } mark = index(algnchars, ch); if (!mark) mark = index(algnchars, highc(ch)); if (!mark) { if (index(ps_randchars, ch)) ps_selected = PS_RANDOM; else if (index(ps_quitchars, ch)) ps_selected = PS_QUIT; else { X11_nhbell(); /* no such alignment */ return; } } else ps_selected = (int)(mark - algnchars); exit_x_event = TRUE; } /* Global functions ========================================================= */ void X11_player_selection() { int num_roles, num_races, num_gends, num_algns, i, availcount, availindex; Widget popup, player_form; const char **choices; char qbuf[QBUFSZ], plbuf[QBUFSZ]; /* avoid unnecessary prompts further down */ rigid_role_checks(); (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); while (flags.initrole < 0) { if (flags.initrole == ROLE_RANDOM || flags.randomall) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); break; } /* select a role */ for (num_roles = 0; roles[num_roles].name.m; ++num_roles) continue; choices = (const char **)alloc(sizeof(char *) * num_roles); for (;;) { availcount = 0; for (i = 0; i < num_roles; i++) { choices[i] = 0; if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { choices[i] = roles[i].name.m; if (flags.initgend >= 0 && flags.female && roles[i].name.f) choices[i] = roles[i].name.f; ++availcount; } } if (availcount > 0) break; else if (flags.initalign >= 0) flags.initalign = -1; /* reset */ else if (flags.initgend >= 0) flags.initgend = -1; else if (flags.initrace >= 0) flags.initrace = -1; else panic("no available ROLE+race+gender+alignment combinations"); } Sprintf(qbuf, "Choose your %s Role", s_suffix(plbuf)); popup = make_menu("player_selection", qbuf, player_select_translations, "quit", ps_quit, "random", ps_random, num_roles, choices, (Widget **)0, ps_select, &player_form); ps_selected = -1; positionpopup(popup, FALSE); nh_XtPopup(popup, (int)XtGrabExclusive, player_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(popup); XtDestroyWidget(popup); free((genericptr_t)choices), choices = 0; if (ps_selected == PS_QUIT) { clearlocks(); X11_exit_nhwindows((char *)0); terminate(0); } else if (ps_selected == PS_RANDOM) { flags.initrole = ROLE_RANDOM; } else if (ps_selected < 0 || ps_selected >= num_roles) { panic("player_selection: bad role select value %d", ps_selected); } else { flags.initrole = ps_selected; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); while (!validrace(flags.initrole, flags.initrace)) { if (flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); break; } /* select a race */ for (num_races = 0; races[num_races].noun; ++num_races) continue; choices = (const char **)alloc(sizeof(char *) * num_races); for (;;) { availcount = availindex = 0; for (i = 0; i < num_races; i++) { choices[i] = 0; if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { choices[i] = races[i].noun; ++availcount; availindex = i; /* used iff only one */ } } if (availcount > 0) break; else if (flags.initalign >= 0) flags.initalign = -1; /* reset */ else if (flags.initgend >= 0) flags.initgend = -1; else panic("no available role+RACE+gender+alignment combinations"); } if (availcount == 1) { flags.initrace = availindex; free((genericptr_t)choices), choices = 0; } else { Sprintf(qbuf, "Pick your %s race", s_suffix(plbuf)); popup = make_menu("race_selection", qbuf, race_select_translations, "quit", ps_quit, "random", ps_random, num_races, choices, (Widget **)0, ps_select, &player_form); ps_selected = -1; positionpopup(popup, FALSE); nh_XtPopup(popup, (int)XtGrabExclusive, player_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(popup); XtDestroyWidget(popup); free((genericptr_t)choices), choices = 0; if (ps_selected == PS_QUIT) { clearlocks(); X11_exit_nhwindows((char *)0); terminate(0); } else if (ps_selected == PS_RANDOM) { flags.initrace = ROLE_RANDOM; } else if (ps_selected < 0 || ps_selected >= num_races) { panic("player_selection: bad race select value %d", ps_selected); } else { flags.initrace = ps_selected; } } /* more than one race choice available */ } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); while (!validgend(flags.initrole, flags.initrace, flags.initgend)) { if (flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); break; } /* select a gender */ num_gends = 2; /* genders[2] isn't allowed */ choices = (const char **)alloc(sizeof(char *) * num_gends); for (;;) { availcount = availindex = 0; for (i = 0; i < num_gends; i++) { choices[i] = 0; if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { choices[i] = genders[i].adj; ++availcount; availindex = i; /* used iff only one */ } } if (availcount > 0) break; else if (flags.initalign >= 0) flags.initalign = -1; /* reset */ else panic("no available role+race+GENDER+alignment combinations"); } if (availcount == 1) { flags.initgend = availindex; free((genericptr_t)choices), choices = 0; } else { Sprintf(qbuf, "Your %s gender?", s_suffix(plbuf)); popup = make_menu("gender_selection", qbuf, gend_select_translations, "quit", ps_quit, "random", ps_random, num_gends, choices, (Widget **)0, ps_select, &player_form); ps_selected = -1; positionpopup(popup, FALSE); nh_XtPopup(popup, (int)XtGrabExclusive, player_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(popup); XtDestroyWidget(popup); free((genericptr_t)choices), choices = 0; if (ps_selected == PS_QUIT) { clearlocks(); X11_exit_nhwindows((char *)0); terminate(0); } else if (ps_selected == PS_RANDOM) { flags.initgend = ROLE_RANDOM; } else if (ps_selected < 0 || ps_selected >= num_gends) { panic("player_selection: bad gender select value %d", ps_selected); } else { flags.initgend = ps_selected; } } /* more than one gender choice available */ } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); while (!validalign(flags.initrole, flags.initrace, flags.initalign)) { if (flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); break; } /* select an alignment */ num_algns = 3; /* aligns[3] isn't allowed */ choices = (const char **)alloc(sizeof(char *) * num_algns); for (;;) { availcount = availindex = 0; for (i = 0; i < num_algns; i++) { choices[i] = 0; if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { choices[i] = aligns[i].adj; ++availcount; availindex = i; /* used iff only one */ } } if (availcount > 0) break; else panic("no available role+race+gender+ALIGNMENT combinations"); } if (availcount == 1) { flags.initalign = availindex; free((genericptr_t)choices), choices = 0; } else { Sprintf(qbuf, "Your %s alignment?", s_suffix(plbuf)); popup = make_menu("alignment_selection", qbuf, algn_select_translations, "quit", ps_quit, "random", ps_random, num_algns, choices, (Widget **)0, ps_select, &player_form); ps_selected = -1; positionpopup(popup, FALSE); nh_XtPopup(popup, (int)XtGrabExclusive, player_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(popup); XtDestroyWidget(popup); free((genericptr_t)choices), choices = 0; if (ps_selected == PS_QUIT) { clearlocks(); X11_exit_nhwindows((char *)0); terminate(0); } else if (ps_selected == PS_RANDOM) { flags.initalign = ROLE_RANDOM; } else if (ps_selected < 0 || ps_selected >= num_algns) { panic("player_selection: bad alignment select value %d", ps_selected); } else { flags.initalign = ps_selected; } } /* more than one alignment choice available */ } } int X11_get_ext_cmd() { static Boolean initialized = False; if (!initialized) { init_extended_commands_popup(); initialized = True; } extended_command_selected = -1; /* reset selected value */ positionpopup(extended_command_popup, FALSE); /* center on cursor */ nh_XtPopup(extended_command_popup, (int)XtGrabExclusive, extended_command_form); /* The callbacks will enable the event loop exit. */ (void) x_event(EXIT_ON_EXIT); return extended_command_selected; } /* End global functions ===================================================== */ /* Extended Command -------------------------------------------------------- */ /* ARGSUSED */ static void extend_select(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { int selected = (int) client_data; if (extended_command_selected != selected) { /* visibly deselect old one */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); /* select new one */ swap_fg_bg(extended_commands[selected]); extended_command_selected = selected; } nh_XtPopdown(extended_command_popup); /* reset colors while popped down */ swap_fg_bg(extended_commands[extended_command_selected]); ec_active = FALSE; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ static void extend_dismiss(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { ec_dismiss(); } /* ARGSUSED */ static void extend_help(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { /* We might need to make it known that we already have one listed. */ (void) doextlist(); } /* ARGSUSED */ void ec_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { if (w == extended_command_popup) { ec_dismiss(); } else { popup_delete(w, event, params, num_params); } } /* ARGSUSED */ static void popup_delete(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { ps_selected = PS_QUIT; nh_XtPopdown(w); exit_x_event = TRUE; /* leave event loop */ } static void ec_dismiss() { /* unselect while still visible */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); extended_command_selected = -1; /* dismiss */ nh_XtPopdown(extended_command_popup); ec_active = FALSE; exit_x_event = TRUE; /* leave event loop */ } /* ARGSUSED */ void ec_key(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch; int i; XKeyEvent *xkey = (XKeyEvent *) event; ch = key_event_to_char(xkey); if (ch == '\0') { /* don't accept nul char/modifier event */ /* don't beep */ return; } else if (index("\033\n\r", ch)) { if (ch == '\033') { /* unselect while still visible */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); extended_command_selected = -1; /* dismiss */ } nh_XtPopdown(extended_command_popup); /* unselect while invisible */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); exit_x_event = TRUE; /* leave event loop */ ec_active = FALSE; return; } /* too much time has elapsed */ if ((xkey->time - ec_time) > 500) ec_active = FALSE; if (!ec_active) { ec_nchars = 0; ec_active = TRUE; } ec_time = xkey->time; ec_chars[ec_nchars++] = ch; if (ec_nchars >= EC_NCHARS) ec_nchars = EC_NCHARS-1; /* don't overflow */ for (i = 0; extcmdlist[i].ef_txt; i++) { if (extcmdlist[i].ef_txt[0] == '?') continue; if (!strncmp(ec_chars, extcmdlist[i].ef_txt, ec_nchars)) { if (extended_command_selected != i) { /* I should use set() and unset() actions, but how do */ /* I send the an action to the widget? */ if (extended_command_selected >= 0) swap_fg_bg(extended_commands[extended_command_selected]); extended_command_selected = i; swap_fg_bg(extended_commands[extended_command_selected]); } break; } } } /* * Use our own home-brewed version menu because simpleMenu is designed to * be used from a menubox. */ static void init_extended_commands_popup() { int i, num_commands; const char **command_list; /* count commands */ for (num_commands = 0; extcmdlist[num_commands].ef_txt; num_commands++) ; /* do nothing */ /* If the last entry is "help", don't use it. */ if (strcmp(extcmdlist[num_commands-1].ef_txt, "?") == 0) --num_commands; command_list = (const char **) alloc((unsigned)num_commands * sizeof(char *)); for (i = 0; i < num_commands; i++) command_list[i] = extcmdlist[i].ef_txt; extended_command_popup = make_menu("extended_commands", "Extended Commands", extended_command_translations, "dismiss", extend_dismiss, "help", extend_help, num_commands, command_list, &extended_commands, extend_select, &extended_command_form); free((char *)command_list); } /* ------------------------------------------------------------------------- */ /* * Create a popup widget of the following form: * * popup_label * ----------- ------------ * |left_name| |right_name| * ----------- ------------ * ------------------------ * | name1 | * ------------------------ * ------------------------ * | name2 | * ------------------------ * . * . * ------------------------ * | nameN | * ------------------------ */ static Widget make_menu(popup_name, popup_label, popup_translations, left_name, left_callback, right_name, right_callback, num_names, widget_names, command_widgets, name_callback, formp) const char *popup_name; const char *popup_label; const char *popup_translations; const char *left_name; XtCallbackProc left_callback; const char *right_name; XtCallbackProc right_callback; int num_names; const char **widget_names; /* return array of command widgets */ Widget **command_widgets; XtCallbackProc name_callback; Widget *formp; /* return */ { Widget popup, form, label, above, left, right; Widget *commands, *curr; int i; Arg args[8]; Cardinal num_args; Dimension width, max_width; int distance, skip; commands = (Widget *) alloc((unsigned)num_names * sizeof(Widget)); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; popup = XtCreatePopupShell(popup_name, transientShellWidgetClass, toplevel, args, num_args); XtOverrideTranslations(popup, XtParseTranslationTable("WM_PROTOCOLS: ec_delete()")); num_args = 0; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(popup_translations)); num_args++; *formp = form = XtCreateManagedWidget("menuform", formWidgetClass, popup, args, num_args); /* Get the default distance between objects in the form widget. */ num_args = 0; XtSetArg(args[num_args], XtNdefaultDistance, &distance); num_args++; XtGetValues(form, args, num_args); /* * Create the label. */ num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; label = XtCreateManagedWidget(popup_label, labelWidgetClass, form, args, num_args); /* * Create the left button. */ num_args = 0; XtSetArg(args[num_args], XtNfromVert, label); num_args++; /* XtSetArg(args[num_args], XtNshapeStyle, XmuShapeRoundedRectangle); num_args++; */ left = XtCreateManagedWidget(left_name, commandWidgetClass, form, args, num_args); XtAddCallback(left, XtNcallback, left_callback, (XtPointer) 0); skip = 3*distance; /* triple the spacing */ if(!skip) skip = 3; /* * Create right button. */ num_args = 0; XtSetArg(args[num_args], XtNfromHoriz, left); num_args++; XtSetArg(args[num_args], XtNfromVert, label); num_args++; /* XtSetArg(args[num_args], XtNshapeStyle, XmuShapeRoundedRectangle); num_args++; */ right = XtCreateManagedWidget(right_name, commandWidgetClass, form, args, num_args); XtAddCallback(right, XtNcallback, right_callback, (XtPointer) 0); XtInstallAccelerators(form, left); XtInstallAccelerators(form, right); /* * Create and place the command widgets. */ for (i = 0, above = left, curr = commands; i < num_names; i++) { if (!widget_names[i]) continue; num_args = 0; XtSetArg(args[num_args], XtNfromVert, above); num_args++; if (above == left) { /* if first, we are farther apart */ XtSetArg(args[num_args], XtNvertDistance, skip); num_args++; } *curr = XtCreateManagedWidget(widget_names[i], commandWidgetClass, form, args, num_args); XtAddCallback(*curr, XtNcallback, name_callback, (XtPointer) i); above = *curr++; } /* * Now find the largest width. Start with the width dismiss + help * buttons, since they are adjacent. */ XtSetArg(args[0], XtNwidth, &max_width); XtGetValues(left, args, ONE); XtSetArg(args[0], XtNwidth, &width); XtGetValues(right, args, ONE); max_width = max_width + width + distance; /* Next, the title. */ XtSetArg(args[0], XtNwidth, &width); XtGetValues(label, args, ONE); if (width > max_width) max_width = width; /* Finally, the commands. */ for (i = 0, curr = commands; i < num_names; i++) { if (!widget_names[i]) continue; XtSetArg(args[0], XtNwidth, &width); XtGetValues(*curr, args, ONE); if (width > max_width) max_width = width; curr++; } /* * Finally, set all of the single line widgets to the largest width. */ XtSetArg(args[0], XtNwidth, max_width); XtSetValues(label, args, ONE); for (i = 0, curr = commands; i < num_names; i++) { if (!widget_names[i]) continue; XtSetArg(args[0], XtNwidth, max_width); XtSetValues(*curr, args, ONE); curr++; } if (command_widgets) *command_widgets = commands; else free((char *) commands); XtRealizeWidget(popup); XSetWMProtocols(XtDisplay(popup), XtWindow(popup), &wm_delete_window, 1); return popup; } nethack-3.4.3/win/X11/winstat.c0100644000000000000000000006656107764735041014673 0ustar rootroot/* SCCS Id: @(#)winstat.c 3.4 1996/04/05 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Status window routines. This file supports both the "traditional" * tty status display and a "fancy" status display. A tty status is * made if a popup window is requested, otherewise a fancy status is * made. This code assumes that only one fancy status will ever be made. * Currently, only one status window (of any type) is _ever_ made. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "hack.h" #include "winX.h" extern const char *hu_stat[]; /* from eat.c */ extern const char *enc_stat[]; /* from botl.c */ static void FDECL(update_fancy_status, (struct xwindow *)); static Widget FDECL(create_fancy_status, (Widget,Widget)); static void FDECL(destroy_fancy_status, (struct xwindow *)); void create_status_window(wp, create_popup, parent) struct xwindow *wp; /* window pointer */ boolean create_popup; Widget parent; { XFontStruct *fs; Arg args[8]; Cardinal num_args; Position top_margin, bottom_margin, left_margin, right_margin; wp->type = NHW_STATUS; if (!create_popup) { /* * If we are not creating a popup, then we must be the "main" status * window. */ if (!parent) panic("create_status_window: no parent for fancy status"); wp->status_information = 0; wp->w = create_fancy_status(parent, (Widget) 0); return; } wp->status_information = (struct status_info_t *) alloc(sizeof(struct status_info_t)); init_text_buffer(&wp->status_information->text); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, False); num_args++; XtSetArg(args[num_args], XtNinput, False); num_args++; wp->popup = parent = XtCreatePopupShell("status_popup", topLevelShellWidgetClass, toplevel, args, num_args); /* * If we're here, then this is an auxiliary status window. If we're * cancelled via a delete window message, we should just pop down. */ num_args = 0; XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++; XtSetArg(args[num_args], XtNscrollHorizontal, XawtextScrollWhenNeeded); num_args++; XtSetArg(args[num_args], XtNscrollVertical, XawtextScrollWhenNeeded); num_args++; wp->w = XtCreateManagedWidget( "status", /* name */ asciiTextWidgetClass, parent, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* * Adjust the height and width of the message window so that it * is two lines high and COLNO of the widest characters wide. */ /* Get the font and margin information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &fs); num_args++; XtSetArg(args[num_args], XtNtopMargin, &top_margin); num_args++; XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++; XtSetArg(args[num_args], XtNleftMargin, &left_margin); num_args++; XtSetArg(args[num_args], XtNrightMargin, &right_margin); num_args++; XtGetValues(wp->w, args, num_args); wp->pixel_height = 2 * nhFontHeight(wp->w) + top_margin + bottom_margin; wp->pixel_width = COLNO * fs->max_bounds.width + left_margin + right_margin; /* Set the new width and height. */ num_args = 0; XtSetArg(args[num_args], XtNwidth, wp->pixel_width); num_args++; XtSetArg(args[num_args], XtNheight, wp->pixel_height); num_args++; XtSetValues(wp->w, args, num_args); } void destroy_status_window(wp) struct xwindow *wp; { /* If status_information is defined, then it a "text" status window. */ if (wp->status_information) { if (wp->popup) { nh_XtPopdown(wp->popup); if (!wp->keep_window) XtDestroyWidget(wp->popup), wp->popup = (Widget)0; } free((genericptr_t)wp->status_information); wp->status_information = 0; } else { destroy_fancy_status(wp); } if (!wp->keep_window) wp->type = NHW_NONE; } /* * This assumes several things: * + Status has only 2 lines * + That both lines are updated in succession in line order. * + We didn't set stringInPlace on the widget. */ void adjust_status(wp, str) struct xwindow *wp; const char *str; { Arg args[2]; Cardinal num_args; if (!wp->status_information) { update_fancy_status(wp); return; } if (wp->cursy == 0) { clear_text_buffer(&wp->status_information->text); append_text_buffer(&wp->status_information->text, str, FALSE); return; } append_text_buffer(&wp->status_information->text, str, FALSE); /* Set new buffer as text. */ num_args = 0; XtSetArg(args[num_args], XtNstring, wp->status_information->text.text); num_args++; XtSetValues(wp->w, args, num_args); } /* Fancy Status -------------------------------------------------------------*/ static int hilight_time = 1; /* number of turns to hilight a changed value */ struct X_status_value { char *name; /* text name */ int type; /* status type */ Widget w; /* widget of name/value pair */ long last_value; /* value displayed */ int turn_count; /* last time the value changed */ boolean set; /* if hilighed */ boolean after_init; /* don't hilight on first change (init) */ }; /* valid type values */ #define SV_VALUE 0 /* displays a label:value pair */ #define SV_LABEL 1 /* displays a changable label */ #define SV_NAME 2 /* displays an unchangeable name */ static void FDECL(hilight_label, (Widget)); static void FDECL(update_val, (struct X_status_value *,long)); static const char *FDECL(width_string, (int)); static void FDECL(create_widget, (Widget,struct X_status_value *,int)); static void FDECL(get_widths, (struct X_status_value *,int *,int *)); static void FDECL(set_widths, (struct X_status_value *,int,int)); static Widget FDECL(init_column, (char *,Widget,Widget,Widget,int *)); static Widget FDECL(init_info_form, (Widget,Widget,Widget)); /* * Form entry storage indices. */ #define F_STR 0 #define F_DEX 1 #define F_CON 2 #define F_INT 3 #define F_WIS 4 #define F_CHA 5 #define F_NAME 6 #define F_DLEVEL 7 #define F_GOLD 8 #define F_HP 9 #define F_MAXHP 10 #define F_POWER 11 #define F_MAXPOWER 12 #define F_AC 13 #define F_LEVEL 14 #define F_EXP 15 #define F_ALIGN 16 #define F_TIME 17 #define F_SCORE 18 #define F_HUNGER 19 #define F_CONFUSED 20 #define F_SICK 21 #define F_BLIND 22 #define F_STUNNED 23 #define F_HALLU 24 #define F_ENCUMBER 25 #define NUM_STATS 26 /* * Notes: * + Alignment needs a different init value, because -1 is an alignment. * + Armor Class is an schar, so 256 is out of range. * + Blank value is 0 and should never change. */ static struct X_status_value shown_stats[NUM_STATS] = { { "Strength", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 0*/ { "Dexterity", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Constitution", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Intelligence", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Wisdom", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Charisma", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /* 5*/ { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* name */ { "", SV_LABEL, (Widget) 0, -1, 0, FALSE, FALSE }, /* dlvl */ { "Gold", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Hit Points", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Max HP", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*10*/ { "Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Max Power", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Armor Class", SV_VALUE, (Widget) 0,256, 0, FALSE, FALSE }, { "Level", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Experience", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, /*15*/ { "Alignment", SV_VALUE, (Widget) 0, -2, 0, FALSE, FALSE }, { "Time", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "Score", SV_VALUE, (Widget) 0, -1, 0, FALSE, FALSE }, { "", SV_NAME, (Widget) 0, -1, 0, FALSE, TRUE }, /* hunger*/ { "Confused", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*20*/ { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /* sick */ { "Blind", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "Stunned", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "Hallucinating", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, { "", SV_NAME, (Widget) 0, 0, 0, FALSE, TRUE }, /*encumbr*/ }; /* * Set all widget values to a null string. This is used after all spacings * have been calculated so that when the window is popped up we don't get all * kinds of funny values being displayed. */ void null_out_status() { int i; struct X_status_value *sv; Arg args[1]; for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) { switch (sv->type) { case SV_VALUE: set_value(sv->w, ""); break; case SV_LABEL: case SV_NAME: XtSetArg(args[0], XtNlabel, ""); XtSetValues(sv->w, args, ONE); break; default: impossible("null_out_status: unknown type %d\n", sv->type); break; } } } /* This is almost an exact duplicate of hilight_value() */ static void hilight_label(w) Widget w; /* label widget */ { Arg args[2]; Pixel fg, bg; XtSetArg(args[0], XtNforeground, &fg); XtSetArg(args[1], XtNbackground, &bg); XtGetValues(w, args, TWO); XtSetArg(args[0], XtNforeground, bg); XtSetArg(args[1], XtNbackground, fg); XtSetValues(w, args, TWO); } static void update_val(attr_rec, new_value) struct X_status_value *attr_rec; long new_value; { char buf[BUFSZ]; Arg args[4]; if (attr_rec->type == SV_LABEL) { if (attr_rec == &shown_stats[F_NAME]) { Strcpy(buf, plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a'; Strcat(buf, " the "); if (u.mtimedone) { char mname[BUFSZ]; int k = 0; Strcpy(mname, mons[u.umonnum].mname); while(mname[k] != 0) { if ((k == 0 || (k > 0 && mname[k-1] == ' ')) && 'a' <= mname[k] && mname[k] <= 'z') mname[k] += 'A' - 'a'; k++; } Strcat(buf, mname); } else Strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female)); } else if (attr_rec == &shown_stats[F_DLEVEL]) { if (!describe_level(buf)) { Strcpy(buf, dungeons[u.uz.dnum].dname); Sprintf(eos(buf), ", level %d", depth(&u.uz)); } } else { impossible("update_val: unknown label type \"%s\"", attr_rec->name); return; } if (strcmp(buf, attr_rec->name) == 0) return; /* same */ /* Set the label. */ Strcpy(attr_rec->name, buf); XtSetArg(args[0], XtNlabel, buf); XtSetValues(attr_rec->w, args, ONE); } else if (attr_rec->type == SV_NAME) { if (attr_rec->last_value == new_value) return; /* no change */ attr_rec->last_value = new_value; /* special cases: hunger, encumbrance, sickness */ if (attr_rec == &shown_stats[F_HUNGER]) { XtSetArg(args[0], XtNlabel, hu_stat[new_value]); } else if (attr_rec == &shown_stats[F_ENCUMBER]) { XtSetArg(args[0], XtNlabel, enc_stat[new_value]); } else if (attr_rec == &shown_stats[F_SICK]) { buf[0] = 0; if (Sick) { if (u.usick_type & SICK_VOMITABLE) Strcat(buf, "FoodPois"); if (u.usick_type & SICK_NONVOMITABLE) { if (u.usick_type & SICK_VOMITABLE) Strcat(buf, " "); Strcat(buf, "Ill"); } } XtSetArg(args[0], XtNlabel, buf); } else if (new_value) { XtSetArg(args[0], XtNlabel, attr_rec->name); } else { XtSetArg(args[0], XtNlabel, ""); } XtSetValues(attr_rec->w, args, ONE); } else { /* a value pair */ boolean force_update = FALSE; /* special case: time can be enabled & disabled */ if (attr_rec == &shown_stats[F_TIME]) { static boolean flagtime = TRUE; if(flags.time && !flagtime) { set_name(attr_rec->w, shown_stats[F_TIME].name); force_update = TRUE; flagtime = flags.time; } else if(!flags.time && flagtime) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagtime = flags.time; } if(!flagtime) return; } /* special case: exp can be enabled & disabled */ else if (attr_rec == &shown_stats[F_EXP]) { static boolean flagexp = TRUE; #ifdef EXP_ON_BOTL if (flags.showexp && !flagexp) { set_name(attr_rec->w, shown_stats[F_EXP].name); force_update = TRUE; flagexp = flags.showexp; } else if(!flags.showexp && flagexp) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagexp = flags.showexp; } if (!flagexp) return; #else if (flagexp) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagexp = FALSE; } return; /* don't show it at all */ #endif } /* special case: score can be enabled & disabled */ else if (attr_rec == &shown_stats[F_SCORE]) { static boolean flagscore = TRUE; #ifdef SCORE_ON_BOTL if(flags.showscore && !flagscore) { set_name(attr_rec->w, shown_stats[F_SCORE].name); force_update = TRUE; flagscore = flags.showscore; } else if(!flags.showscore && flagscore) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagscore = flags.showscore; } if(!flagscore) return; #else if (flagscore) { set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); flagscore = FALSE; } return; #endif } /* special case: when polymorphed, show "HD", disable exp */ else if (attr_rec == &shown_stats[F_LEVEL]) { static boolean lev_was_poly = FALSE; if (u.mtimedone && !lev_was_poly) { force_update = TRUE; set_name(attr_rec->w, "HD"); lev_was_poly = TRUE; } else if (!u.mtimedone && lev_was_poly) { force_update = TRUE; set_name(attr_rec->w, shown_stats[F_LEVEL].name); lev_was_poly = FALSE; } } else if (attr_rec == &shown_stats[F_EXP]) { static boolean exp_was_poly = FALSE; if (u.mtimedone && !exp_was_poly) { force_update = TRUE; set_name(attr_rec->w, ""); set_value(attr_rec->w, ""); exp_was_poly = TRUE; } else if (!u.mtimedone && exp_was_poly) { force_update = TRUE; set_name(attr_rec->w, shown_stats[F_EXP].name); exp_was_poly = FALSE; } if (u.mtimedone) return; /* no display for exp when poly */ } if (attr_rec->last_value == new_value && !force_update) /* same */ return; attr_rec->last_value = new_value; /* Special cases: strength, alignment and "clear". */ if (attr_rec == &shown_stats[F_STR]) { if(new_value > 18) { if (new_value > 118) Sprintf(buf,"%ld", new_value-100); else if(new_value < 118) Sprintf(buf, "18/%02ld", new_value-18); else Strcpy(buf, "18/**"); } else { Sprintf(buf, "%ld", new_value); } } else if (attr_rec == &shown_stats[F_ALIGN]) { Strcpy(buf, (new_value == A_CHAOTIC) ? "Chaotic" : (new_value == A_NEUTRAL) ? "Neutral" : "Lawful" ); } else { Sprintf(buf, "%ld", new_value); } set_value(attr_rec->w, buf); } /* * Now hilight the changed information. Names, time and score don't * hilight. If first time, don't hilight. If already lit, don't do * it again. */ if (attr_rec->type != SV_NAME && attr_rec != &shown_stats[F_TIME]) { if (attr_rec->after_init) { if(!attr_rec->set) { if (attr_rec->type == SV_LABEL) hilight_label(attr_rec->w); else hilight_value(attr_rec->w); attr_rec->set = TRUE; } attr_rec->turn_count = 0; } else { attr_rec->after_init = TRUE; } } } /* * Update the displayed status. The current code in botl.c updates * two lines of information. Both lines are always updated one after * the other. So only do our update when we update the second line. * * Information on the first line: * name, attributes, alignment, score * * Information on the second line: * dlvl, gold, hp, power, ac, {level & exp or HD **} * status (hunger, conf, halu, stun, sick, blind), time, encumbrance * * [**] HD is shown instead of level and exp if mtimedone is non-zero. */ static void update_fancy_status(wp) struct xwindow *wp; { struct X_status_value *sv; long val; int i; if (wp->cursy != 0) return; /* do a complete update when line 0 is done */ for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) { switch (i) { case F_STR: val = (long) ACURR(A_STR); break; case F_DEX: val = (long) ACURR(A_DEX); break; case F_CON: val = (long) ACURR(A_CON); break; case F_INT: val = (long) ACURR(A_INT); break; case F_WIS: val = (long) ACURR(A_WIS); break; case F_CHA: val = (long) ACURR(A_CHA); break; /* * Label stats. With the exceptions of hunger, encumbrance, sick * these are either on or off. Pleae leave the ternary operators * the way they are. I want to specify 0 or 1, not a boolean. */ case F_HUNGER: val = (long) u.uhs; break; case F_CONFUSED: val = (long) Confusion ? 1L : 0L; break; case F_SICK: val = (long) Sick ? (long)u.usick_type : 0L; break; case F_BLIND: val = (long) Blind ? 1L : 0L; break; case F_STUNNED: val = (long) Stunned ? 1L : 0L; break; case F_HALLU: val = (long) Hallucination ? 1L : 0L; break; case F_ENCUMBER: val = (long) near_capacity(); break; case F_NAME: val = (long) 0L; break; /* special */ case F_DLEVEL: val = (long) 0L; break; /* special */ #ifndef GOLDOBJ case F_GOLD: val = (long) u.ugold; break; #else case F_GOLD: val = money_cnt(invent); break; #endif case F_HP: val = (long) (u.mtimedone ? (u.mh > 0 ? u.mh : 0): (u.uhp > 0 ? u.uhp : 0)); break; case F_MAXHP: val = (long) (u.mtimedone ? u.mhmax : u.uhpmax); break; case F_POWER: val = (long) u.uen; break; case F_MAXPOWER: val = (long) u.uenmax; break; case F_AC: val = (long) u.uac; break; case F_LEVEL: val = (long) (u.mtimedone ? mons[u.umonnum].mlevel : u.ulevel); break; #ifdef EXP_ON_BOTL case F_EXP: val = flags.showexp ? u.uexp : 0L; break; #else case F_EXP: val = 0L; break; #endif case F_ALIGN: val = (long) u.ualign.type; break; case F_TIME: val = flags.time ? (long) moves : 0L; break; #ifdef SCORE_ON_BOTL case F_SCORE: val = flags.showscore ? botl_score():0L; break; #else case F_SCORE: val = 0L; break; #endif default: { /* * There is a possible infinite loop that occurs with: * * impossible->pline->flush_screen->bot->bot{1,2}-> * putstr->adjust_status->update_other->impossible * * Break out with this. */ static boolean active = FALSE; if (!active) { active = TRUE; impossible("update_other: unknown shown value"); active = FALSE; } val = 0; break; } } update_val(sv, val); } } /* * Turn off hilighted status values after a certain amount of turns. */ void check_turn_events() { int i; struct X_status_value *sv; for (sv = shown_stats, i = 0; i < NUM_STATS; i++, sv++) { if (!sv->set) continue; if (sv->turn_count++ >= hilight_time) { if (sv->type == SV_LABEL) hilight_label(sv->w); else hilight_value(sv->w); sv->set = FALSE; } } } /* Initialize alternate status ============================================= */ /* Return a string for the initial width. */ static const char * width_string(sv_index) int sv_index; { switch (sv_index) { case F_STR: return "018/**"; case F_DEX: case F_CON: case F_INT: case F_WIS: case F_CHA: return "088"; /* all but str never get bigger */ case F_HUNGER: return shown_stats[F_HUNGER].name; case F_CONFUSED:return shown_stats[F_CONFUSED].name; case F_SICK: return shown_stats[F_SICK].name; case F_BLIND: return shown_stats[F_BLIND].name; case F_STUNNED: return shown_stats[F_STUNNED].name; case F_HALLU: return shown_stats[F_HALLU].name; case F_ENCUMBER:return shown_stats[F_ENCUMBER].name; case F_NAME: case F_DLEVEL: return ""; case F_HP: case F_MAXHP: return "9999"; case F_POWER: case F_MAXPOWER:return "999"; case F_AC: return "-99"; case F_LEVEL: return "99"; case F_GOLD: case F_EXP: return "4294967295"; /* max ulong */ case F_ALIGN: return "Neutral"; case F_TIME: return "4294967295"; /* max ulong */ case F_SCORE: return "4294967295"; /* max ulong */ } impossible("width_string: unknown index %d\n", sv_index); return ""; } static void create_widget(parent, sv, sv_index) Widget parent; struct X_status_value *sv; int sv_index; { Arg args[4]; Cardinal num_args; switch (sv->type) { case SV_VALUE: sv->w = create_value(parent, sv->name); set_value(sv->w, width_string(sv_index)); break; case SV_LABEL: /* Labels get their own buffer. */ sv->name = (char *) alloc(BUFSZ); sv->name[0] = '\0'; num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; sv->w = XtCreateManagedWidget( sv_index == F_NAME ? "name" : "dlevel", labelWidgetClass, parent, args, num_args); break; case SV_NAME: num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; sv->w = XtCreateManagedWidget(sv->name, labelWidgetClass, parent, args, num_args); break; default: panic("create_widget: unknown type %d", sv->type); } } /* * Get current width of value. width2p is only valid for SV_LABEL types. */ static void get_widths(sv, width1p, width2p) struct X_status_value *sv; int *width1p, *width2p; { Arg args[1]; Dimension width; switch (sv->type) { case SV_VALUE: *width1p = get_name_width(sv->w); *width2p = get_value_width(sv->w); break; case SV_LABEL: case SV_NAME: XtSetArg(args[0], XtNwidth, &width); XtGetValues(sv->w, args, ONE); *width1p = width; *width2p = 0; break; default: panic("get_widths: unknown type %d", sv->type); } } static void set_widths(sv, width1, width2) struct X_status_value *sv; int width1, width2; { Arg args[1]; switch (sv->type) { case SV_VALUE: set_name_width(sv->w, width1); set_value_width(sv->w, width2); break; case SV_LABEL: case SV_NAME: XtSetArg(args[0], XtNwidth, (width1+width2)); XtSetValues(sv->w, args, ONE); break; default: panic("set_widths: unknown type %d", sv->type); } } static Widget init_column(name, parent, top, left, col_indices) char *name; Widget parent, top, left; int *col_indices; { Widget form; Arg args[4]; Cardinal num_args; int max_width1, width1, max_width2, width2; int *ip; struct X_status_value *sv; num_args = 0; if (top != (Widget) 0) { XtSetArg(args[num_args], XtNfromVert, top); num_args++; } if (left != (Widget) 0) { XtSetArg(args[num_args], XtNfromHoriz, left); num_args++; } XtSetArg(args[num_args], XtNdefaultDistance, 0); num_args++; form = XtCreateManagedWidget(name, formWidgetClass, parent, args, num_args); max_width1 = max_width2 = 0; for (ip = col_indices; *ip >= 0; ip++) { sv = &shown_stats[*ip]; create_widget(form, sv, *ip); /* will set init width */ if (ip != col_indices) { /* not first */ num_args = 0; XtSetArg(args[num_args], XtNfromVert, shown_stats[*(ip-1)].w); num_args++; XtSetValues(sv->w, args, num_args); } get_widths(sv, &width1, &width2); if (width1 > max_width1) max_width1 = width1; if (width2 > max_width2) max_width2 = width2; } for (ip = col_indices; *ip >= 0 ; ip++) { set_widths(&shown_stats[*ip], max_width1, max_width2); } /* There is room behind the end marker for the two widths. */ *++ip = max_width1; *++ip = max_width2; return form; } /* * These are the orders of the displayed columns. Change to suit. The -1 * indicates the end of the column. The two numbers after that are used * to store widths that are calculated at run-time. */ static int attrib_indices[] = { F_STR,F_DEX,F_CON,F_INT,F_WIS,F_CHA, -1,0,0 }; static int status_indices[] = { F_HUNGER, F_CONFUSED, F_SICK, F_BLIND, F_STUNNED, F_HALLU, F_ENCUMBER, -1,0,0 }; static int col2_indices[] = { F_MAXHP, F_ALIGN, F_TIME, F_EXP, F_MAXPOWER, -1,0,0 }; static int col1_indices[] = { F_HP, F_AC, F_GOLD, F_LEVEL, F_POWER, F_SCORE, -1,0,0 }; /* * Produce a form that looks like the following: * * name * dlevel * col1_indices[0] col2_indices[0] * col1_indices[1] col2_indices[1] * . . * . . * col1_indices[n] col2_indices[n] */ static Widget init_info_form(parent, top, left) Widget parent, top, left; { Widget form, col1; struct X_status_value *sv_name, *sv_dlevel; Arg args[6]; Cardinal num_args; int total_width, *ip; num_args = 0; if (top != (Widget) 0) { XtSetArg(args[num_args], XtNfromVert, top); num_args++; } if (left != (Widget) 0) { XtSetArg(args[num_args], XtNfromHoriz, left); num_args++; } XtSetArg(args[num_args], XtNdefaultDistance, 0); num_args++; form = XtCreateManagedWidget("status_info", formWidgetClass, parent, args, num_args); /* top of form */ sv_name = &shown_stats[F_NAME]; create_widget(form, sv_name, F_NAME); /* second */ sv_dlevel = &shown_stats[F_DLEVEL]; create_widget(form, sv_dlevel, F_DLEVEL); num_args = 0; XtSetArg(args[num_args], XtNfromVert, sv_name->w); num_args++; XtSetValues(sv_dlevel->w, args, num_args); /* two columns beneath */ col1 = init_column("name_col1", form, sv_dlevel->w, (Widget) 0, col1_indices); (void) init_column("name_col2", form, sv_dlevel->w, col1, col2_indices); /* Add calculated widths. */ for (ip = col1_indices; *ip >= 0; ip++) ; /* skip to end */ total_width = *++ip; total_width += *++ip; for (ip = col2_indices; *ip >= 0; ip++) ; /* skip to end */ total_width += *++ip; total_width += *++ip; XtSetArg(args[0], XtNwidth, total_width); XtSetValues(sv_name->w, args, ONE); XtSetArg(args[0], XtNwidth, total_width); XtSetValues(sv_dlevel->w, args, ONE); return form; } /* * Create the layout for the fancy status. Return a form widget that * contains everything. */ static Widget create_fancy_status(parent, top) Widget parent, top; { Widget form; /* The form that surrounds everything. */ Widget w; Arg args[8]; Cardinal num_args; num_args = 0; if (top != (Widget) 0) { XtSetArg(args[num_args], XtNfromVert, top); num_args++; } XtSetArg(args[num_args], XtNdefaultDistance, 0); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNorientation, XtorientHorizontal); num_args++; form = XtCreateManagedWidget("fancy_status", panedWidgetClass, parent, args, num_args); w = init_info_form(form, (Widget) 0, (Widget) 0); w = init_column("status_attributes",form, (Widget) 0, w, attrib_indices); (void) init_column("status_condition", form, (Widget) 0, w, status_indices); return form; } static void destroy_fancy_status(wp) struct xwindow *wp; { int i; struct X_status_value *sv; if (!wp->keep_window) XtDestroyWidget(wp->w), wp->w = (Widget)0; for (i = 0, sv = shown_stats; i < NUM_STATS; i++, sv++) if (sv->type == SV_LABEL) { free((genericptr_t)sv->name); sv->name = 0; } } /*winstat.c*/ nethack-3.4.3/win/X11/wintext.c0100644000000000000000000003740007764735041014672 0ustar rootroot/* SCCS Id: @(#)wintext.c 3.4 1996/04/05 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * File for dealing with text windows. * * + No global functions. */ #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #include #include #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "hack.h" #include "winX.h" #include "xwindow.h" #ifdef GRAPHIC_TOMBSTONE #include #endif #define TRANSIENT_TEXT /* text window is a transient window (no positioning) */ static const char text_translations[] = "#override\n\ : dismiss_text()\n\ : key_dismiss_text()"; #ifdef GRAPHIC_TOMBSTONE static const char rip_translations[] = "#override\n\ : rip_dismiss_text()\n\ : rip_dismiss_text()"; static Widget FDECL(create_ripout_widget, (Widget)); #endif /*ARGSUSED*/ void delete_text(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { struct xwindow *wp; struct text_info_t *text_info; wp = find_widget(w); text_info = wp->text_information; nh_XtPopdown(wp->popup); if (text_info->blocked) { exit_x_event = TRUE; } else if (text_info->destroy_on_ack) { destroy_text_window(wp); } } /* * Callback used for all text windows. The window is poped down on any key * or button down event. It is destroyed if the main nethack code is done * with it. */ /*ARGSUSED*/ void dismiss_text(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { struct xwindow *wp; struct text_info_t *text_info; wp = find_widget(w); text_info = wp->text_information; nh_XtPopdown(wp->popup); if (text_info->blocked) { exit_x_event = TRUE; } else if (text_info->destroy_on_ack) { destroy_text_window(wp); } } /* Dismiss when a non-modifier key pressed. */ void key_dismiss_text(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { char ch = key_event_to_char((XKeyEvent *) event); if (ch) dismiss_text(w, event, params, num_params); } #ifdef GRAPHIC_TOMBSTONE /* Dismiss from clicking on rip image. */ void rip_dismiss_text(w, event, params, num_params) Widget w; XEvent *event; String *params; Cardinal *num_params; { dismiss_text(XtParent(w), event, params, num_params); } #endif /* ARGSUSED */ void add_to_text_window(wp, attr, str) struct xwindow *wp; int attr; /* currently unused */ const char *str; { struct text_info_t *text_info = wp->text_information; int width; append_text_buffer(&text_info->text, str, FALSE); /* Calculate text width and save longest line */ width = XTextWidth(text_info->fs, str, (int) strlen(str)); if (width > text_info->max_width) text_info->max_width = width; } void display_text_window(wp, blocking) struct xwindow *wp; boolean blocking; { struct text_info_t *text_info; Arg args[8]; Cardinal num_args; Dimension width, height, font_height; int nlines; text_info = wp->text_information; width = text_info->max_width + text_info->extra_width; text_info->blocked = blocking; text_info->destroy_on_ack = FALSE; font_height = nhFontHeight(wp->w); /* * Calculate the number of lines to use. First, find the number of * lines that would fit on the screen. Next, remove four of these * lines to give room for a possible window manager titlebar (some * wm's put a titlebar on transient windows). Make sure we have * _some_ lines. Finally, use the number of lines in the text if * there are fewer than the max. */ nlines = (XtScreen(wp->w)->height - text_info->extra_height) / font_height; nlines -= 4; if (nlines > text_info->text.num_lines) nlines = text_info->text.num_lines; if (nlines <= 0) nlines = 1; height = nlines * font_height + text_info->extra_height; num_args = 0; if (nlines < text_info->text.num_lines) { /* add on width of scrollbar. Really should look this up, * but can't until the window is realized. Chicken-and-egg problem. */ width += 20; } #ifdef GRAPHIC_TOMBSTONE if (text_info->is_rip) { Widget rip = create_ripout_widget(XtParent(wp->w)); XtSetArg(args[num_args], XtNfromVert, rip); num_args++; } #endif if (width > (Dimension) XtScreen(wp->w)->width) { /* too wide for screen */ /* Back off some amount - we really need to back off the scrollbar */ /* width plus some extra. */ width = XtScreen(wp->w)->width - 20; } XtSetArg(args[num_args], XtNstring, text_info->text.text); num_args++; XtSetArg(args[num_args], XtNwidth, width); num_args++; XtSetArg(args[num_args], XtNheight, height); num_args++; XtSetValues(wp->w, args, num_args); #ifdef TRANSIENT_TEXT XtRealizeWidget(wp->popup); XSetWMProtocols(XtDisplay(wp->popup), XtWindow(wp->popup), &wm_delete_window, 1); positionpopup(wp->popup, FALSE); #endif nh_XtPopup(wp->popup, (int)XtGrabNone, wp->w); /* Kludge alert. Scrollbars are not sized correctly by the Text widget */ /* if added before the window is displayed, so do it afterward. */ num_args = 0; if (nlines < text_info->text.num_lines) { /* add vert scrollbar */ XtSetArg(args[num_args], XtNscrollVertical, XawtextScrollAlways); num_args++; } if (width >= (Dimension) (XtScreen(wp->w)->width-20)) { /* too wide */ XtSetArg(args[num_args], XtNscrollHorizontal, XawtextScrollAlways); num_args++; } if (num_args) XtSetValues(wp->w, args, num_args); /* We want the user to acknowlege. */ if (blocking) { (void) x_event(EXIT_ON_EXIT); nh_XtPopdown(wp->popup); } } void create_text_window(wp) struct xwindow *wp; { struct text_info_t *text_info; Arg args[8]; Cardinal num_args; Position top_margin, bottom_margin, left_margin, right_margin; Widget form; wp->type = NHW_TEXT; wp->text_information = text_info = (struct text_info_t *) alloc(sizeof(struct text_info_t)); init_text_buffer(&text_info->text); text_info->max_width = 0; text_info->extra_width = 0; text_info->extra_height = 0; text_info->blocked = FALSE; text_info->destroy_on_ack = TRUE; /* Ok to destroy before display */ #ifdef GRAPHIC_TOMBSTONE text_info->is_rip = FALSE; #endif num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(text_translations)); num_args++; #ifdef TRANSIENT_TEXT wp->popup = XtCreatePopupShell("text", transientShellWidgetClass, toplevel, args, num_args); #else wp->popup = XtCreatePopupShell("text", topLevelShellWidgetClass, toplevel, args, num_args); #endif XtOverrideTranslations(wp->popup, XtParseTranslationTable("WM_PROTOCOLS: delete_text()")); num_args = 0; XtSetArg(args[num_args], XtNallowShellResize, True); num_args++; form = XtCreateManagedWidget("form", formWidgetClass, wp->popup, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNdisplayCaret, False); num_args++; XtSetArg(args[num_args], XtNresize, XawtextResizeBoth); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(text_translations)); num_args++; wp->w = XtCreateManagedWidget( killer && WIN_MAP == WIN_ERR ? "tombstone" : "text_text", /* name */ asciiTextWidgetClass, form, /* parent widget */ args, /* set some values */ num_args); /* number of values to set */ /* Get the font and margin information. */ num_args = 0; XtSetArg(args[num_args], XtNfont, &text_info->fs); num_args++; XtSetArg(args[num_args], XtNtopMargin, &top_margin); num_args++; XtSetArg(args[num_args], XtNbottomMargin, &bottom_margin); num_args++; XtSetArg(args[num_args], XtNleftMargin, &left_margin); num_args++; XtSetArg(args[num_args], XtNrightMargin, &right_margin); num_args++; XtGetValues(wp->w, args, num_args); text_info->extra_width = left_margin + right_margin; text_info->extra_height = top_margin + bottom_margin; } void destroy_text_window(wp) struct xwindow *wp; { /* Don't need to pop down, this only called from dismiss_text(). */ struct text_info_t *text_info = wp->text_information; /* * If the text window was blocked, then the user has already ACK'ed * it and we are free to really destroy the window. Otherwise, don't * destroy until the user dismisses the window via a key or button * press. */ if (text_info->blocked || text_info->destroy_on_ack) { XtDestroyWidget(wp->popup); free_text_buffer(&text_info->text); free((genericptr_t)text_info), wp->text_information = 0; wp->type = NHW_NONE; /* allow reuse */ } else { text_info->destroy_on_ack = TRUE; /* destroy on next ACK */ } } void clear_text_window(wp) struct xwindow *wp; { clear_text_buffer(&wp->text_information->text); } /* text buffer routines ---------------------------------------------------- */ /* Append a line to the text buffer. */ void append_text_buffer(tb, str, concat) struct text_buffer *tb; const char *str; boolean concat; { char *copy; int length; if (!tb->text) panic("append_text_buffer: null text buffer"); if (str) { length = strlen(str); } else { length = 0; } if (length + tb->text_last + 1 >= tb->text_size) { /* we need to go to a bigger buffer! */ #ifdef VERBOSE printf("append_text_buffer: text buffer growing from %d to %d bytes\n", tb->text_size, 2*tb->text_size); #endif copy = (char *) alloc((unsigned)tb->text_size*2); (void) memcpy(copy, tb->text, tb->text_last); free(tb->text); tb->text = copy; tb->text_size *= 2; } if (tb->num_lines) { /* not first --- append a newline */ char appchar = '\n'; if(concat && !index("!.?'\")", tb->text[tb->text_last-1])) { appchar = ' '; tb->num_lines--; /* offset increment at end of function */ } *(tb->text + tb->text_last) = appchar; tb->text_last++; } if (str) { (void) memcpy((tb->text+tb->text_last), str, length+1); if(length) { /* Remove all newlines. Otherwise we have a confused line count. */ copy = (tb->text+tb->text_last); while ((copy = index(copy, '\n')) != (char*)0) *copy = ' '; } tb->text_last += length; } tb->text[tb->text_last] = '\0'; tb->num_lines++; } /* Initialize text buffer. */ void init_text_buffer(tb) struct text_buffer *tb; { tb->text = (char *) alloc(START_SIZE); tb->text[0] = '\0'; tb->text_size = START_SIZE; tb->text_last = 0; tb->num_lines = 0; } /* Empty the text buffer */ void clear_text_buffer(tb) struct text_buffer *tb; { tb->text_last = 0; tb->text[0] = '\0'; tb->num_lines = 0; } /* Free up allocated memory. */ void free_text_buffer(tb) struct text_buffer *tb; { free(tb->text); tb->text = (char *) 0; tb->text_size = 0; tb->text_last = 0; tb->num_lines = 0; } #ifdef GRAPHIC_TOMBSTONE static void FDECL(rip_exposed, (Widget,XtPointer,XtPointer)); static XImage* rip_image=0; #define STONE_LINE_LEN 16 /* # chars that fit on one line */ #define NAME_LINE 0 /* line # for player name */ #define GOLD_LINE 1 /* line # for amount of gold */ #define DEATH_LINE 2 /* line # for death description */ #define YEAR_LINE 6 /* line # for year */ static char rip_line[YEAR_LINE+1][STONE_LINE_LEN+1]; extern const char *killed_by_prefix[]; void calculate_rip_text(int how) { /* Follows same algorithm as genl_outrip() */ char buf[BUFSZ]; char *dpx; int line; /* Put name on stone */ Sprintf(rip_line[NAME_LINE], "%s", plname); /* Put $ on stone */ Sprintf(rip_line[GOLD_LINE], "%ld Au", #ifndef GOLDOBJ u.ugold); #else done_money); #endif /* Put together death description */ switch (killer_format) { default: impossible("bad killer format?"); case KILLED_BY_AN: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, an(killer)); break; case KILLED_BY: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, killer); break; case NO_KILLER_PREFIX: Strcpy(buf, killer); break; } /* Put death type on stone */ for (line=DEATH_LINE, dpx = buf; line STONE_LINE_LEN) { for(i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) if(dpx[i] == ' ') i0 = i; if(!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; strcpy(rip_line[line], dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx= &dpx[i0]; } else dpx= &dpx[i0+1]; } /* Put year on stone */ Sprintf(rip_line[YEAR_LINE], "%4d", getyear()); } /* * RIP image expose callback. */ /*ARGSUSED*/ static void rip_exposed(w, client_data, widget_data) Widget w; XtPointer client_data; /* unused */ XtPointer widget_data; /* expose event from Window widget */ { XExposeEvent *event = (XExposeEvent *) widget_data; Display* dpy=XtDisplay(w); Arg args[8]; XGCValues values; XtGCMask mask; GC gc; static Pixmap rip_pixmap=None; int i, x, y; if (!XtIsRealized(w) || event->count > 0) return; if (rip_pixmap == None && rip_image) { rip_pixmap = XCreatePixmap(dpy, XtWindow(w), rip_image->width, rip_image->height, DefaultDepth(dpy, DefaultScreen(dpy))); XPutImage(dpy, rip_pixmap, DefaultGC(dpy, DefaultScreen(dpy)), rip_image, 0,0, 0,0, /* src, dest top left */ rip_image->width, rip_image->height); XDestroyImage(rip_image); /* data bytes free'd also */ } mask = GCFunction | GCForeground | GCGraphicsExposures | GCFont; values.graphics_exposures = False; XtSetArg(args[0], XtNforeground, &values.foreground); XtGetValues(w, args, 1); values.function = GXcopy; values.font = WindowFont(w); gc = XtGetGC(w, mask, &values); if (rip_pixmap != None) { XCopyArea(dpy, rip_pixmap, XtWindow(w), gc, event->x, event->y, event->width, event->height, event->x, event->y); } x=appResources.tombtext_x; y=appResources.tombtext_y; for (i=0; i<=YEAR_LINE; i++) { int len=strlen(rip_line[i]); XFontStruct* font=WindowFontStruct(w); int width=XTextWidth(font, rip_line[i], len); XDrawString(dpy, XtWindow(w), gc, x-width/2, y, rip_line[i], len); x+=appResources.tombtext_dx; y+=appResources.tombtext_dy; } XtReleaseGC(w, gc); } /* * The ripout window creation routine. */ static Widget create_ripout_widget(Widget parent) { Widget imageport; Arg args[16]; Cardinal num_args; static int rip_width, rip_height; if (!rip_image) { XpmAttributes attributes; int errorcode; attributes.valuemask = XpmCloseness; attributes.closeness = 65535; /* Try anything */ errorcode = XpmReadFileToImage(XtDisplay(parent), appResources.tombstone, &rip_image, 0, &attributes); if (errorcode != XpmSuccess) { char buf[BUFSZ]; Sprintf(buf, "Failed to load %s: %s", appResources.tombstone, XpmGetErrorString(errorcode)); X11_raw_print(buf); } rip_width = rip_image->width; rip_height = rip_image->height; } num_args = 0; XtSetArg(args[num_args], XtNwidth, rip_width); num_args++; XtSetArg(args[num_args], XtNheight, rip_height); num_args++; XtSetArg(args[num_args], XtNtranslations, XtParseTranslationTable(rip_translations)); num_args++; imageport = XtCreateManagedWidget("rip", windowWidgetClass, parent, args, num_args); XtAddCallback(imageport, XtNexposeCallback, rip_exposed, (XtPointer) 0); return imageport; } #endif /* GRAPHIC_TOMBSTONE */ /*wintext.c*/ nethack-3.4.3/win/X11/winval.c0100644000000000000000000000736207764735041014474 0ustar rootroot/* SCCS Id: @(#)winval.c 3.4 1992/3/7 */ /* Copyright (c) Dean Luick, 1992 */ /* NetHack may be freely redistributed. See license for details. */ /* * Routines that define a name-value label widget pair that fit inside a * form widget. */ #include #ifndef SYSV #define PRESERVE_NO_SYSV /* X11 include files may define SYSV */ #endif #include #include #include #include #include #ifdef PRESERVE_NO_SYSV # ifdef SYSV # undef SYSV # endif # undef PRESERVE_NO_SYSV #endif #include "hack.h" /* #define for const for non __STDC__ compilers */ #include "winX.h" #define WNAME "name" #define WVALUE "value" Widget create_value(parent, name_value) Widget parent; const char *name_value; { Widget form, name; Arg args[8]; Cardinal num_args; num_args = 0; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNdefaultDistance, 0); num_args++; form = XtCreateManagedWidget(name_value, formWidgetClass, parent, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNjustify, XtJustifyRight); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNlabel, name_value); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; name = XtCreateManagedWidget(WNAME, labelWidgetClass, form, args, num_args); num_args = 0; XtSetArg(args[num_args], XtNjustify, XtJustifyRight); num_args++; XtSetArg(args[num_args], XtNborderWidth, 0); num_args++; XtSetArg(args[num_args], XtNfromHoriz, name); num_args++; XtSetArg(args[num_args], XtNinternalHeight, 0); num_args++; (void) XtCreateManagedWidget(WVALUE, labelWidgetClass, form, args, num_args); return form; } void set_name(w, new_label) Widget w; char *new_label; { Arg args[1]; Widget name; name = XtNameToWidget(w, WNAME); XtSetArg(args[0], XtNlabel, new_label); XtSetValues(name, args, ONE); } void set_name_width(w, new_width) Widget w; int new_width; { Arg args[1]; Widget name; name = XtNameToWidget(w, WNAME); XtSetArg(args[0], XtNwidth, new_width); XtSetValues(name, args, ONE); } int get_name_width(w) Widget w; { Arg args[1]; Dimension width; Widget name; name = XtNameToWidget(w, WNAME); XtSetArg(args[0], XtNwidth, &width); XtGetValues(name, args, ONE); return (int) width; } void set_value(w, new_value) Widget w; const char *new_value; { Arg args[1]; Widget val; val = XtNameToWidget(w, WVALUE); XtSetArg(args[0], XtNlabel, new_value); XtSetValues(val, args, ONE); } void set_value_width(w, new_width) Widget w; int new_width; { Arg args[1]; Widget val; val = XtNameToWidget(w, WVALUE); XtSetArg(args[0], XtNwidth, new_width); XtSetValues(val, args, ONE); } int get_value_width(w) Widget w; { Arg args[1]; Widget val; Dimension width; val = XtNameToWidget(w, WVALUE); XtSetArg(args[0], XtNwidth, &width); XtGetValues(val, args, ONE); return (int) width; } /* Swap foreground and background colors (this is the best I can do with */ /* a label widget, unless I can get some init hook in there). */ void hilight_value(w) Widget w; { swap_fg_bg(XtNameToWidget(w, WVALUE)); } /* Swap the foreground and background colors of the given widget */ void swap_fg_bg(w) Widget w; { Arg args[2]; Pixel fg, bg; XtSetArg(args[0], XtNforeground, &fg); XtSetArg(args[1], XtNbackground, &bg); XtGetValues(w, args, TWO); XtSetArg(args[0], XtNforeground, bg); XtSetArg(args[1], XtNbackground, fg); XtSetValues(w, args, TWO); } nethack-3.4.3/win/gem/0040755000000000000000000000000007764735105013223 5ustar rootrootnethack-3.4.3/win/gem/Install.gem0100644000000000000000000000203307764735041015315 0ustar rootrootHi, This is nethack3.4.1 for Atari Gem and tty Windowing System. It is by far not complete or perfect. (My english too :-)) You need at least 2Meg free RAM, 16 colors and 3 Meg free Disk space. In fact it works also with monochrome, but you have to create a nh2.img (and title2.img) on your own. Atari windowport changes from 3.3.0: added a ASCII-Mode in GEM -> F2 the cursor is switchable -> F3 added inventory/menu search -> : removed the redraw problem removed almost all flicker (except with NOVA-Card :-() placed the GEM-dialogues more pleasent tty corner windows (i.e. inv) display now correct in a vt52-win greyed out old messages placed the GEM-windows more convient ... Feel free to contact me about Issues and Errors. e-mail: gaston@cs.tu-berlin.de You use this program at your own risk, I can't guarantee it will work or do you no harm. Look at the nethack licence too. As you may have noticed the look and feel is from Warwick Allisons nethack3.1.3d Gem Version and I have used E_Gem2.2.0 from Christian Grunenberg. Marvin nethack-3.4.3/win/gem/bitmfile.c0100644000000000000000000001766607764735041015176 0ustar rootroot/****************************\ * Bitmap mit Farbtabelle als * * Graphik-Datei speichern * * Autor: Gabriel Schmidt * * (c) 1992 by MAXON-Computer * * Modifiziert von Sebastian * * Bieber, Dez. 1994 * * -> Programmcode * \****************************/ #include #include #include #include #include #include "bitmfile.h" /* --- (X) IMG-Implementation ----------------- */ #define IMG_COMPRESSED typedef struct { UWORD img_version; UWORD img_headlen; UWORD img_nplanes; UWORD img_patlen; UWORD img_pixw; UWORD img_pixh; UWORD img_w; UWORD img_h; } IMG_HEADER; typedef enum {NONE, SOLID0, SOLID1, PATRUN, BITSTR} IMG_MODE; typedef UBYTE IMG_SOLID; typedef enum { RGB=0, CMY=1, Pantone=2 } XIMG_COLMODEL; typedef struct { ULONG img_ximg; XIMG_COLMODEL img_colmodel; } XIMG_HEADER; typedef struct RGB XIMG_RGB; int bitmap_to_img(FILE_TYP typ, int ww, int wh, unsigned int pixw, unsigned int pixh, unsigned int planes, unsigned int colors, const char *filename, void(*get_color)(unsigned int colind, struct RGB *rgb), void(*get_pixel)(int x, int y, unsigned int *colind) ) { int file, error, cnt; IMG_HEADER header; XIMG_HEADER xheader; XIMG_RGB xrgb; IMG_MODE mode; UBYTE *line_buf, *write_buf; register UBYTE *startpnt, *bufpnt; unsigned int colind, line_len, line, bit; register unsigned int byte; register UBYTE count; /* fill in (X) IMG-Header */ header.img_version = 1; header.img_headlen = (UWORD) sizeof(header) /2; if (typ == XIMG) header.img_headlen += (UWORD)(sizeof(xheader)+colors*sizeof(xrgb))/2; header.img_nplanes = planes; header.img_patlen = 2; header.img_pixw = pixw; header.img_pixh = pixh; header.img_w = ww; header.img_h = wh; xheader.img_ximg = XIMG_MAGIC; xheader.img_colmodel= RGB; /* calculate linelength, allocate buffer. */ line_len = (ww+7)/8; line_buf = malloc((size_t)planes*line_len); if (line_buf == NULL) return(ENOMEM); /* Worst case: the bufferd line could grow to max. 3 times the length */ /* of the original! */ write_buf = malloc((size_t)3*line_len); if (write_buf == NULL) { free(line_buf); return(ENOMEM); }; /* open file */ file = open(filename, O_WRONLY | O_CREAT | O_TRUNC); if (file<0) { error = errno; free(line_buf); free(write_buf); return(error); }; /* write Header */ if (write (file, &header, sizeof(header)) != sizeof(header) || (typ == XIMG && write (file, &xheader, sizeof(xheader) ) != sizeof(xheader))) { error = errno; close(file); free(line_buf); free(write_buf); return(error); }; /* save the colortable if possible */ if ( typ == XIMG ) for (cnt=0; cnt>= 1; }; }; }; /* compress bitstrings in buffer */ /* and write it to file */ for (cnt=0; cnt0; count--) *(bufpnt++) = *(startpnt++); break; }; }; if (write(file,write_buf,bufpnt-write_buf) != (bufpnt-write_buf)) { error = errno; close(file); free(line_buf); free(write_buf); return(error); }; }; }; /*close file, free buffer. */ close(file); free(line_buf); free(write_buf); return(0); } /*---filetype-dispatcher--------------------*/ const char *get_file_ext(FILE_TYP typ) { switch (typ) { case IMG: case XIMG: return("IMG"); default: return(""); }; } int bitmap_to_file(FILE_TYP typ, int ww, int wh, unsigned int pwx, unsigned int pwy, unsigned int planes, unsigned int colors, const char *filename, void (*get_color)(unsigned int colind, struct RGB *rgb), void (*get_pixel)(int x, int y, unsigned int *colind)) { switch (typ) { case IMG: case XIMG: return(bitmap_to_img(typ,ww,wh,pwx,pwy,planes,colors,filename,get_color,get_pixel)); default: return(-1); }; } nethack-3.4.3/win/gem/gem_rsc.uu0100644000000000000000000003351207764735041015215 0ustar rootrootbegin 777 GEM_RSC.RSC M $29@^Z$B(/N@^Z #0)&@^Z)]X Y0 , !8 @ "@. M "!.151(04-+ "!'86UE "!(97)E "!4:&5R90 @271E;0 @07!P M87)E; @36%G:6, ("!!8F]U="!.971H86-K+BXN "TM+2TM+2TM+2TM+2TM M+2TM+2TM+2T ("!$97-K($%C8V5S2 Q(" ("!$97-K($%C8V5S2 R(" ("!$97-K($%C8V5S2 S(" ("!$97-K($%C8V5S2 T M(" ("!$97-K($%C8V5S2 U(" ("!$97-K($%C8V5S2 V(" M("!(96QP+BXN(" @(" @(" @/P @(%=H870@:7,N+BX@(" @(" O " @0V]M M;6%N9"!H96QP+BXN("8 +2TM+2TM+2TM+2TM+2TM+2TM+2TM " @3W!T:6]N M" @ M(" @( 5L " @16YG00 M+2TM M+2TM+2TM+2TM+2TM " @3&]O:R!A=" @(" [ " @4V5A " @2G5M<" @(" @( 5J " @ M0VAA=" @(" @( 5C " @1FEG:'0@(" @("!& " @4VAO=R!A;&P@(" @("!I M " @4VAO=R!K:6YD(" @("!) " @1&ES8V]V97)I97,@("!< "TM+2TM+2TM M+2TM+2TM+2TM+2T ("!%870@(" @(" @(" @(&4 ("!$2 @(" @(" @(&$ ("!5 @($9I;&P@<75I=F5R(" @ M(" @40 @($9I2 @(% ("!296UO M=F4@86-C97-S;W)Y(%( ("!7;W)N(')I;F=S(" @(" @(#T ("!7;W)N(&%M M=6QE=" @(" @("( ("!,:7-T('-P96QL@ @($-A'#P)'$< X#@0/YS^"!P' . X$#_=_@@?GF @ !@)__^8"0 F D 59@) "8"0!5F D )@) 168"0 MF D%!9@$@ $X!($5, 2 3 "0%9P D "8 $@5. D G $A3@ D)P $DX M F< $. G ' #SP\\ \\//@/ M___X#___^ ____@/ #X#U55^ \ /@/557X#P ^ ]55?@/ #X#U55^ > M ?@'U57P!X !\ /55_ #P /@ ?47X #P#\ ?5^ #P_ ??@ #_P ?X M #\ < '0 !V\ =P 4 !@ "$8 /__ M "\ 0 !W$ >1 'D@ % 8 A& #__P @ $ >: 'HP !Z0 M P & 0 __\ "0 ! 'V0 !]L ?E , !@ "$8 /__ ( "@ M!^H ?O '^P # 8 A& #__P % P @ ("0 " H P & 0 M __\ "0 ! ("P "$$ AW , !@ "$8 /__ #8 -@ "(, B% M (A@ # 8 A$ #__@ " $ B' (B0 "(H P & (1 __X M @ ! (BP "(T B. , !@ "$0 /_^ ( 0 "(\ B1 (D@ # M 8 A$ #__@ " $ B3 (E0 ")8 P & (1 __X @ ! ( MEP ")D B: , !@ "$0 /_^ ( 0 ")L B= (G@ # 8 A$ M #__@ " $ B? (H0 "*( P & (1 __X @ ! (HP "*4 M BF , !@ "$0 /_^ ( 0 "*< BN (KP % 8 A& #__P ' M $ BP (M0 "+8 !0 & (1@ __\ !0 ! (MP "- C1 , M!@ "$P, /__ !D 0 "-( C= (Z # 8 I!Y #__P + L CJ M ([0 ".X P & (0> $ P ! ([P "0H D+ , !@ "$0$ M /__ !L 0 "^H D: &URD 4 !( @ \Z M .N@ "1$0 !P " ( ! " +0 (__\ 0 * !D M : 9 H @ " !0 1 : ,! $ P ) !D M " ,@,! 3_____ " - "0,! 7_____ " M /0 ) !@,! ;_____ " 0P / !@,! ?_____ M " 20 5 !P,! C_____ " 4 < !@,! G_ M____ " 5@ B "0,! +_____ " 7P K !P,! M "P!< !D P$ 40 3 !0 # 3 !0 /\1 " M%@ ( W_____ !P 9@ %@ ! [_____ !P ( >0 M $ %@ ! ______ !P D ( %@ ! !#_____ !P MI0 , %@ ! !'_____ !P N@ 0 %@ ! !+_____ !P M SP 4 %@ ! !/_____ !P Y 8 %@ ! O_____ !P M ^0 < %@ ! !\ %0 > !0 /\1 + %0 * !;_____ M !P !#@ %0 ! !?_____ !P !(@ $ %0 ! !C_ M____ !P !-@ ( %0 ! !G_____ !P ( !2@ , %0 ! M !K_____ !P !8 0 %0 ! !O_____ !P != 4 M%0 ! !S_____ !P ( !B 8 %0 ! !W_____ !P !G@ M < %0 ! ![_____ !P ( !L@ @ %0 ! !3_____ !P ! MR D %0 ! "X ( M !0 /\1 1 % . "'_____ !P M !W % ! "+_____ !P ![P $ % ! "/_____ !P M " @ ( % ! "3_____ !P "%0 , % ! "7_____ M !P "* 0 % ! ";_____ !P ".P 4 % ! "?_ M____ !P "3@ 8 % ! "C_____ !P ( "80 < % ! M "G_____ !P "=@ @ % ! "K_____ !P "B0 D M% ! "O_____ !P ( "G H % ! "S_____ !P "L0 M L % ! "W_____ !P "Q P % ! !______ !P " MUP T % ! #L +P Z !0 /\1 7 $ , ##_____ !P M "Z@ $ ! #'_____ !P ( "^0 $ $ ! #+_____ !P M #"@ ( $ ! #/_____ !P #&0 , $ ! #3_____ M !P #* 0 $ ! #7_____ !P #-P 4 $ ! #;_ M____ !P #1@ 8 $ ! #?_____ !P #50 < $ ! M #C_____ !P #9 @ $ ! #G_____ !P #

$P / #W_____ !P # MH $P ! #[_____ !P #L@ $ $P ! #______ !P M #Q ( $P ! $#_____ !P ( #U@ , $P ! $'_____ !P M #Z@ 0 $P ! $+_____ !P #_ 4 $P ! $/_____ M !P $#@ 8 $P ! $3_____ !P $( < $P ! $7_ M____ !P $,@ @ $P ! $;_____ !P $1 D $P ! M $?_____ !P $5@ H $P ! $C_____ !P $: L M$P ! $G_____ !P ( $>@ P $P ! $K_____ !P $C@ M T $P ! #O_____ !P $H X $P ! %P 3 !; !0 /\1 M D %@ 0 $W_____ !P $L@ %@ ! $[_____ !P M $QP $ %@ ! $______ !P $W ( %@ ! %#_____ !P M $\0 , %@ ! %'_____ !P %!@ 0 %@ ! %+_____ M !P %&P 4 %@ ! %/_____ !P ( %, 8 %@ ! %3_ M____ !P %1P < %@ ! %7_____ !P %7 @ %@ ! M %;_____ !P %<0 D %@ ! %?_____ !P %A@ H M%@ ! %C_____ !P ( %FP L %@ ! %G_____ !P %L@ M P %@ ! %K_____ !P %QP T %@ ! %O_____ !P % MW X %@ ! $O_____ !P %\0 \ %@ ! H 70!H !0 M /\1 M $@ , %[_____ !P &!@ $@ ! %______ !P M ( &%P $ $@ ! &#_____ !P &*@ ( $@ ! &'_____ M !P &.P , $@ ! &+_____ !P &3 0 $@ ! &/_ M____ !P &70 4 $@ ! &3_____ !P &;@ 8 $@ ! M &7_____ !P &?P < $@ ! &;_____ !P &D @ M$@ ! &?_____ !P &H0 D $@ ! &C_____ !P &L@ M H $@ ! %S_____ !P ( &PP L $@ !__\ 0 ! !0 1 M 4 3P " #_____"Q0 8 $1>0 @ "__\ 0 ! !0 M $1 " $ H 5 #_____ !D ( $A 1 , @ !__\ 0 *"Q0 M 0 (1 # $ +@ * +_____ !H,!P &U I @$ P8! 4 P $ M !0 /\1 0 !" #0 ' 3_____ !\ 2(@ "" !0 % +_ M____ !P &V #" 4 !P ! ;_____ !P( &X / $ %0 ! M ?_____ !P &]@ / , '@ ! C_____ !P '%0 / 0 M$0 ! G_____ !P ')P / 8 & ! K_____ !4 /N@ ! M# <$(@ ! #_____ !4 ( /U@ !" @ (0 !__\ 0 ""Q0 0 /X1 M> ! ( 3P@6 +_____$QH,!P 'DP " !4 " ! #_____ !@ ( M ) ( @ &3@ 4__\ 0 ["Q0 0 (1> ! $ + ) +_____ !4( M /\@ " $ " ! #< P U !0 $1>0 " , * @# 4 ! $ M !H,!0 'I0 !" @ ! /_____!1D $1 0 ! < M!@ & !H,!0 'IP $" @ ! 7_____!1D $1 0 ! M D " ( !H,!0 'J0 '" @ ! ?_____!1D $1 M 0 ! L "@ * !H,!0 'JP *" @ ! G_____!1D $1 M 0 ! T # , !H,!0 'K0 -" @ ! O_____!1D $1 M 0 ! \ #@ . !H,!0 'KP 0" @ ! W_____!1D M $1 0 ! !$ $ 0 !H,!0 'L0 3" @ ! ______!1D M $1 0 ! !, $@ 2 !H,!0 'LP 6" @ ! !'_____ M!1D $1 0 ! !4 % 4 !H,!0 'M0 9" @ ! !/_ M____!1D $1 0 ! !< %@ 6 !H,!0 'MP <" @ ! M !7_____!1D $1 0 ! !D & 8 !H,!0 'N0 ?" M @ ! !?_____!1D $1 0 ! !L &@ : !H,!0 'NP B M" @ ! !G_____!1D $1 0 ! !T ' < !H,!0 ' MO0 E" @ ! !O_____!1D $1 0 ! !\ '@ > !H,!0 M 'OP ! ( @ ! !W_____!1D $1 0 ! "$ ( @ !H, M!0 'P0 $ ( @ ! !______!1D $1 0 ! ", (@ B M !H,!0 'PP ' ( @ ! "'_____!1D $1 0 ! "4 M) D !H,!0 'Q0 * ( @ ! "/_____!1D $1 0 ! M "< )@ F !H,!0 'QP - ( @ ! "7_____!1D $1 M 0 ! "D * H !H,!0 'R0 0 ( @ ! "?_____!1D $1 M 0 ! "L *@ J !H,!0 'RP 3 ( @ ! "G_____!1D $1 M 0 ! "T + L !H,!0 'S0 6 ( @ ! "O_____!1D M $1 0 ! "\ +@ N !H,!0 'SP 9 ( @ ! "W_____!1D M $1 0 ! #$ , P !H,!0 'T0 < ( @ ! "______ M!1D $1 0 ! #, ,@ R !H,!0 'TP ? ( @ ! #'_ M____!1D $1 0 ! #4 - T !H,!0 'U0 B ( @ ! M #/_____!1D $1 0 ! ( -@ V !H,!0 'UP E ( M @ ! #7_____!1D $1 0 ! #H . Y !0 $1>0 # M , %@ # #G_____ !X(" 0#@ ! $ "P ! #?_____ !H,!P ' MYP - $ !P ! #O_____ !X(" 0*@ # < # ! #_____ !H,)0 M '_0 1 < !@ !__\ 0 $"Q0( 0 (1> ! $ .P ' +_____ !4( M 01@ " $ -P ! /_____ !X(" 08@ " , -P ! 3_____ M$QH$!0 (>0 # 4 " ! #_____ !H,)P (@ P 4 " !__\ M 0 9"Q0 0 1> ( 0 # & +_____ !L 0 6> % @ ! M /_____ !L ! 6> " ( @ ! 3_____ !L P 6> *" ( M @ ! 7_____ !L @ 6> % 4 @ ! < !@ & !8,!0 0?@ " M 0 @ ! 7_____!1D $1 0 ! D " ( !8,!0 0 MF@ % 0 @ ! ?_____!1D $1 0 ! L "@ * !8,!0 M 0M@ ( 0 @ ! G_____!1D $1 0 ! T # , !8, M!0 0T@ "" ( @ ! O_____!1D $1 0 ! \ #@ . M !8,!0 0[@ %" ( @ ! W_____!1D $1 0 ! !$ M$ 0 !8,!0 1"@ (" ( @ ! ______!1D $1 0 ! M !, $@ 2 !8,!0 1)@ " $ @ ! !'_____!1D $1 M 0 ! !4 % 4 !8,!0 10@ % $ @ ! !/_____!1D $1 M 0 ! !< %@ 6 !8,!0 17@ ( $ @ ! !7_____!1D $1 M 0 ! !D & 8 !8,!0 1>@ '! 4 !0P !?_____!1D M $1 ! 0P &@ : !8,!0 1E@ ' !0P !G_____!1D M( $1 ! 0P __\ 0 $ !0 1 ! 4 3P # +_____ M !L, 0 0 6>0 @ ! /_____"Q0( $1>0 $ @ ! 3_ M____ !L, 0 @ 6>0 ( @ ! #_____ !@ ( + " 30 # M__\ 0 $"Q0 0 (1>0 ! $ + @4 +_____ !4( 1L@ ! M+ ! /_____"AX " 1S@ . !( $ ! 3_____ !8,!P 1Z@ A M !( "0@! #_____ !8 ( 2!@ " $ * @,__\ 0 !"Q0 $1 M<@ # , " " #_____ !H,)P )# !" !@ !__\ 0 ! !0 0 @ M /\1>0 " , !@ # #_____ !\ ( 21 P # 29@ '#X G !QN N end nethack-3.4.3/win/gem/gem_rso.uu0100644000000000000000000000234207764735041015226 0ustar rootrootbegin 777 GEM_RSC.RSO M4E-/2 1( @ " ! !#__P __\ M M '___^!____@ M #__P #__P M M /_ '___^!____@ :1F]1)Y2KX@ M (\TJP "!$U%3E4 P'1$]!0D]55 '@9$3U%5250 __\ 0 #"E-4 M05154TQ)3D4 $*1U)!0E-405154P#__P " ,&34%05TE. !DU!4$)/ M6 0E-05!#55)33U( __\ P #!4%"3U54 "$9,64%"3U54 !!T]+ M04)/550 ,+3D542$%#2TE-1S __\ ! #!4Q)3D53 "$9,64Q)3D53 M !!5%,24Y% ""4Q)3D533$E35 #__P % ,(64Y#2$])0T4 +1DQ9 M64Y#2$])0T4 $(64Y04D]-4%0 ()4T]-14-(05)3 # UE.,0 -0-9 M3DX #<'04Y90TA!4@ . A#2$]314Y#2 .@5#3U5.5 .P193D]+ /__ M 8 P=,24Y%1T54 "D9,64Q)3D5'150 $(3$=04D]-4%0 ('3$=2 M15!,60 P-13$< 0$3$=/2P#__P ' ,)1$E214-424]. #$9,641) M4D5#5$E/3@ !01$25(Q 5!$1)4CD !<'1$E21$]73@ &05$25)54 #_ M_P ( ,&35-'5TE. !!55035-' ""D=204)-4T=724X ,%1$Y-4T< M 0(35-'3$E.15, __\ "0 #!TY!345'150 *1DQ93D%-14=%5 @90 M3$Y!344 0.3D542$%#2U!)0U154D4 __\ "@ #!5!!1T52 "$9,65!! @1T52 !!E%004=%4@#__P + ,&3DA)0T]. /____\ end nethack-3.4.3/win/gem/gr_rect.c0100644000000000000000000001134307764735041015012 0ustar rootroot/* SCCS Id: @(#)gr_rect.c 3.4 2001/12/10 */ /* Copyright (c) Christian Bressler, 2001 */ /* NetHack may be freely redistributed. See license for details. */ /* This is an almost exact copy of qt_clust.cpp */ /* gr_rect.c */ #include #include #include #include "gr_rect.h" dirty_rect *new_dirty_rect(int size){ dirty_rect *new=NULL; if(size>0){ new=(dirty_rect *)calloc(1L,sizeof(dirty_rect)); if(new){ new->rects=(GRECT *)calloc((long)size,sizeof(GRECT)); if(new->rects==NULL){ free(new); return(NULL); } new->max=size; } } return(new); } void delete_dirty_rect(dirty_rect *this){ if(this==NULL) return; if(this->rects) free(this->rects); /* In case the Pointer is reused wrongly */ this->rects=NULL; this->max=0; this->used=0; free(this); } static int gc_inside(GRECT *frame,GRECT *test); static int gc_touch(GRECT *frame,GRECT *test); static void gc_combine(GRECT *frame,GRECT *test); static long gc_area(GRECT *area); int add_dirty_rect(dirty_rect *dr,GRECT *area){ int cursor; long lowestcost=9999999L; int cheapest=-1; int cheapestmerge1=-1; int cheapestmerge2=-1; int merge1; int merge2; for (cursor=0; cursorused; cursor++) { if (gc_inside(&dr->rects[cursor],area)) { /* Wholly contained already. */ return(TRUE); } } for (cursor=0; cursorused; cursor++) { if (gc_touch(&dr->rects[cursor],area)) { GRECT larger=dr->rects[cursor]; long cost; gc_combine(&larger,area); cost=gc_area(&larger)-gc_area(&dr->rects[cursor]); if (cost < lowestcost) { int bad=FALSE,c; for (c=0; cused && !bad; c++) { bad=gc_touch(&dr->rects[c],&larger) && c!=cursor; } if (!bad) { cheapest=cursor; lowestcost=cost; } } } } if (cheapest>=0) { gc_combine(&dr->rects[cheapest],area); return(TRUE); } if (dr->used < dr->max) { dr->rects[dr->used++]=*area; return(TRUE); } // Do cheapest of: // add to closest cluster // do cheapest cluster merge, add to new cluster lowestcost=9999999L; cheapest=-1; for (cursor=0; cursorused; cursor++) { GRECT larger=dr->rects[cursor]; long cost; gc_combine(&larger,area); cost=gc_area(&larger)-gc_area(&dr->rects[cursor]); if (cost < lowestcost) { int bad=FALSE, c; for (c=0; cused && !bad; c++) { bad=gc_touch(&dr->rects[c],&larger) && c!=cursor; } if (!bad) { cheapest=cursor; lowestcost=cost; } } } // XXX could make an heuristic guess as to whether we // XXX need to bother looking for a cheap merge. for (merge1=0; merge1used; merge1++) { for (merge2=0; merge2used; merge2++) { if (merge1!=merge2) { GRECT larger=dr->rects[merge1]; long cost; gc_combine(&larger,&dr->rects[merge2]); cost=gc_area(&larger)-gc_area(&dr->rects[merge1])-gc_area(&dr->rects[merge2]); if (cost < lowestcost) { int bad=FALSE, c; for (c=0; cused && !bad; c++) { bad=gc_touch(&dr->rects[c],&larger) && c!=cursor; } if (!bad) { cheapestmerge1=merge1; cheapestmerge2=merge2; lowestcost=cost; } } } } } if (cheapestmerge1>=0) { gc_combine(&dr->rects[cheapestmerge1],&dr->rects[cheapestmerge2]); dr->rects[cheapestmerge2]=dr->rects[dr->used-1]; dr->rects[dr->used-1]=*area; } else { gc_combine(&dr->rects[cheapest],area); } // NB: clusters do not intersect (or intersection will // overwrite). This is a result of the above algorithm, // given the assumption that (x,y) are ordered topleft // to bottomright. return(TRUE); } int get_dirty_rect(dirty_rect* dr,GRECT *area){ if(dr==NULL || area==NULL || dr->rects==NULL || dr->used<=0 || dr->max<=0) return(FALSE); *area=dr->rects[--dr->used]; return(TRUE); } int clear_dirty_rect(dirty_rect *dr){ if(dr) dr->used=0; return(TRUE); } int resize_dirty_rect(dirty_rect *dr,int new_size){ return(FALSE); } static int gc_inside(GRECT *frame,GRECT *test){ if(frame && test && frame->g_x<=test->g_x && frame->g_y<=test->g_y && frame->g_x+frame->g_w>=test->g_x+test->g_w && frame->g_y+frame->g_h>=test->g_y+test->g_h ) return(TRUE); return(FALSE); } static int gc_touch(GRECT *frame,GRECT *test){ GRECT tmp={test->g_x-1,test->g_y-1,test->g_w+2,test->g_h+2}; return(rc_intersect(frame,&tmp)); } static void gc_combine(GRECT *frame,GRECT *test){ if(!frame || !test) return; if(frame->g_x>test->g_x){ frame->g_w+=frame->g_x-test->g_x; frame->g_x=test->g_x; } if(frame->g_y>test->g_y){ frame->g_h+=frame->g_y-test->g_y; frame->g_y=test->g_y; } if(frame->g_x+frame->g_wg_x+test->g_w) frame->g_w=test->g_x+test->g_w-frame->g_x; if(frame->g_y+frame->g_hg_y+test->g_h) frame->g_h=test->g_y+test->g_h-frame->g_y; } static long gc_area(GRECT *area){ return((long)area->g_h*(long)area->g_w); } nethack-3.4.3/win/gem/gr_rect.h0100644000000000000000000000065507764735041015023 0ustar rootroot/* gr_rect.h */ #include /********** structs **********/ typedef struct { GRECT *rects; int max,used; } dirty_rect; /********* functions ************/ dirty_rect *new_dirty_rect(int size); void delete_dirty_rect(dirty_rect *this); int add_dirty_rect(dirty_rect *dr,GRECT *area); int get_dirty_rect(dirty_rect* dr,GRECT *area); int clear_dirty_rect(dirty_rect *dr); int resize_dirty_rect(dirty_rect *dr,int new_size); nethack-3.4.3/win/gem/load_img.c0100644000000000000000000001574707764735041015154 0ustar rootroot#define __TCC_COMPAT__ #include #include #include #include #include #include #include #include #include "load_img.h" #ifndef FALSE #define FALSE 0 #define TRUE !FALSE #endif /* VDI <-> Device palette order conversion matrixes: */ /* Four-plane vdi-device */ int vdi2dev4[]={0,15,1,2,4,6,3,5,7,8,9,10,12,14,11,13}; /* Two-plane vdi-device */ int vdi2dev2[]={0,3,1,2}; void get_colors(int handle, short *palette, int col){ int i, idx; /* get current color palette */ for(i=0; i < col; i ++){ /* device->vdi->device palette order */ switch(planes){ case 1: idx=i;break; case 2: idx=vdi2dev2[i];break; case 4: idx=vdi2dev4[i];break; default: if(i<16) idx=vdi2dev4[i]; else idx= i==255 ? 1 : i; } vq_color(handle, i, 0, (int *)palette + idx * 3); } } void img_set_colors(int handle, short *palette, int col){ int i, idx, end; /* set color palette */ end=min(1<fd_addr; /* initialize some variables and zero temp. line buffer */ mplanes=min(image->fd_nplanes, planes); /* convert image */ line_addr=image_addr; buf_addr=screen_addr; if(mplanes>1){ /* cut/pad color planes into temp buf */ for(plane=0; planefd_addr); /* convert image line in temp into current device raster format */ if((new1_addr=(char *) calloc(1,new_size)) == NULL) return(FALSE); dev_form.fd_addr=new1_addr; vr_trnfm(x_handle, &tmp, &dev_form); free(new_addr); /* change image description */ image->fd_stand=0; /* device format */ image->fd_addr=new1_addr; image->fd_nplanes=planes; return(TRUE); } int transform_img(MFDB *image){ /* return FALSE if transform_img fails */ int success; long size; if(!image->fd_addr) return(FALSE); size=(long)((long)image->fd_wdwidth * (long)image->fd_h); success=convert(image, size); /* Use vr_trfm(), which needs quite a lot memory. */ if(success) return(TRUE); /* else show_error(ERR_ALLOC); */ return(FALSE); } /* Loads & depacks IMG (0 if succeded, else error). */ /* Bitplanes are one after another in address IMG_HEADER.addr. */ int depack_img(char *name, IMG_header *pic){ int b, line, plane, width, word_aligned, opcode, patt_len, pal_size, byte_repeat, patt_repeat, scan_repeat, error = FALSE; char *pattern, *to, *endline, *puffer, sol_pat; long size; FILE *fp; if((fp = fopen(name, "rb")) == NULL) return(ERR_FILE); setvbuf(fp,NULL,_IOLBF,BUFSIZ); /* read header info (bw & ximg) into image structure */ fread((char *)&(pic->version), 2, 8 + 3, fp); /* only 2-256 color imgs */ if(pic->planes < 1 || pic->planes > 8){ error = ERR_COLOR; goto end_depack; } /* if XIMG, read info */ if(pic->magic == XIMG && pic->paltype == 0){ pal_size = (1 << pic->planes) * 3 * 2; if((pic->palette = (short *)calloc(1,pal_size))){ fread((char *)pic->palette, 1, pal_size, fp); } }else{ pic->palette = NULL; } /* width in bytes word aliged */ word_aligned = (pic->img_w + 15) >> 4; word_aligned <<= 1; /* width byte aligned */ width = (pic->img_w + 7) >> 3; /* allocate memory for the picture */ free(pic->addr); size = (long)((long)word_aligned * (long)pic->img_h * (long)pic->planes); /*MAR*/ /* check for header validity & malloc long... */ if (pic->length > 7 && pic->planes < 33 && pic->img_w > 0 && pic->img_h > 0){ if(!(pic->addr=(char *)calloc(1,size))){ error = ERR_ALLOC; goto end_depack; } }else{ error = ERR_HEADER; goto end_depack; } patt_len = pic->pat_len; /* jump over the header and possible (XIMG) info */ fseek(fp, (long) pic->length * 2L, SEEK_SET); for(line=0,to=pic->addr; lineimg_h; line+=scan_repeat){ /* depack whole img */ for(plane=0,scan_repeat=1; planeplanes; plane++){ /* depack one scan line */ puffer=to=pic->addr+(long)(line+plane*pic->img_h)*(long)word_aligned; endline=puffer+width; do{ /* depack one line in one bitplane */ switch((opcode= fgetc(fp))){ case 0: /* pattern or scan repeat */ if((patt_repeat=fgetc(fp))){ /* repeat a pattern */ fread(to,patt_len,1,fp); pattern=to; to+=patt_len; while(--patt_repeat){ /* copy pattern */ memcpy(to,pattern,patt_len); to+=patt_len; } }else{ /* repeat a line */ if(fgetc(fp)==0xFF) scan_repeat=fgetc(fp); else{ error = ERR_DEPACK; goto end_depack; } } break; case 0x80: /* Literal */ byte_repeat=fgetc(fp); fread(to,byte_repeat,1,fp); to+=byte_repeat; break; default: /* Solid run */ byte_repeat = opcode & 0x7F; sol_pat = opcode&0x80 ? 0xFF : 0x00; while(byte_repeat--) *to++=sol_pat; } }while(to pic->img_h) scan_repeat = pic->img_h - line; /* copy line to image buffer */ if(scan_repeat>1){ /* calculate address of a current line in a current bitplane */ /* to=pic->addr+(long)(line+1+plane*pic->img_h)*(long)word_aligned;*/ for(b=scan_repeat-1; b; --b){ memcpy(to, puffer, width); to+=word_aligned; } } }else{ error = ERR_DEPACK; goto end_depack; } } } end_depack: fclose(fp); return(error); } int half_img(MFDB *s, MFDB *d){ int pxy[8], i, j; MFDB tmp; mfdb(&tmp,NULL,s->fd_w/2,s->fd_h,s->fd_stand,s->fd_nplanes); tmp.fd_w=s->fd_w/2; tmp.fd_addr=calloc(1,mfdb_size(&tmp)); if(!tmp.fd_addr) return(FALSE); pxy[1]=pxy[5]=0; pxy[3]=pxy[7]=s->fd_h-1; for(i=0;ifd_w/2;i++){ pxy[0]=pxy[2]=2*i; pxy[4]=pxy[6]=i; vro_cpyfm(x_handle,S_ONLY,pxy,s,&tmp); } pxy[0]=pxy[4]=0; pxy[2]=pxy[6]=s->fd_w/2-1; for(j=0;jfd_h/2;j++){ pxy[1]=pxy[3]=2*j; pxy[5]=pxy[7]=j; vro_cpyfm(x_handle,S_ONLY,pxy,&tmp,d); } free(tmp.fd_addr); return(TRUE); } nethack-3.4.3/win/gem/tile2img.c0100644000000000000000000000725207764735041015105 0ustar rootroot/* SCCS Id: @(#)tile2bmp.c 3.2 95/09/06 */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * Edit History: * * Initial Creation M.Allison 94/01/11 * Marvin was here Marvin 97/01/11 * */ /* #include */ #include "hack.h" #include "tile.h" #include "bitmfile.h" /* #define COLORS_IN_USE MAXCOLORMAPSIZE /* 256 colors */ #define COLORS_IN_USE 16 /* 16 colors */ extern char *FDECL(tilename, (int, int)); static void FDECL(build_ximgtile,(pixel (*)[TILE_X])); void get_color(unsigned int colind, struct RGB *rgb); void get_pixel(int x, int y, unsigned int *colind); #if COLORS_IN_USE==16 #define MAX_X 320 /* 2 per byte, 4 bits per pixel */ #else #define MAX_X 640 #endif #define MAX_Y 1200 FILE *tibfile2; pixel tilepixels[TILE_Y][TILE_X]; char *tilefiles[] = { "..\\win\\share\\monsters.txt", "..\\win\\share\\objects.txt", "..\\win\\share\\other.txt"}; unsigned int **Bild_daten; int num_colors = 0; int tilecount; int max_tiles_in_row = 40; int tiles_in_row; int filenum; int initflag; int yoffset,xoffset; char bmpname[128]; FILE *fp; int main(argc, argv) int argc; char *argv[]; { int i; if (argc != 2) { Fprintf(stderr, "usage: tile2img outfile.img\n"); exit(EXIT_FAILURE); } else strcpy(bmpname, argv[1]); #ifdef OBSOLETE bmpfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE); if (bmpfile2 == (FILE *)0) { Fprintf(stderr, "Unable to open output file %s\n", NETHACK_PACKED_TILEFILE); exit(EXIT_FAILURE); } #endif tilecount = 0; xoffset = yoffset = 0; initflag = 0; filenum = 0; fp = fopen(bmpname,"wb"); if (!fp) { printf("Error creating tile file %s, aborting.\n",bmpname); exit(1); } fclose(fp); Bild_daten=(unsigned int **)malloc(MAX_Y*sizeof(unsigned int *)); for(i=0;i 62) { Fprintf(stderr, "too many colors (%d)\n", num_colors); exit(EXIT_FAILURE); } while (read_text_tile(tilepixels)) { build_ximgtile(tilepixels); tilecount++; xoffset += TILE_X; if (xoffset >= MAX_X) { yoffset += TILE_Y; xoffset = 0; } } (void) fclose_text_file(); ++filenum; } Fprintf(stderr, "Total of %d tiles in memory.\n",tilecount); bitmap_to_file(XIMG, MAX_X, (tilecount/20+1)*16, 372, 372, 4, 16, bmpname, get_color, get_pixel ) ; Fprintf(stderr, "Total of %d tiles written to %s.\n",tilecount, bmpname); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } void get_color(unsigned int colind, struct RGB *rgb){ rgb->r=(1000L*(long)ColorMap[CM_RED][colind])/0xFF; rgb->g=(1000L*(long)ColorMap[CM_GREEN][colind])/0xFF; rgb->b=(1000L*(long)ColorMap[CM_BLUE][colind])/0xFF; } void get_pixel(int x, int y, unsigned int *colind){ *colind=Bild_daten[y][x]; } static void build_ximgtile(pixels) pixel (*pixels)[TILE_X]; { int cur_x, cur_y, cur_color; int x,y; for (cur_y = 0; cur_y < TILE_Y; cur_y++) { for (cur_x = 0; cur_x < TILE_X; cur_x++) { for (cur_color = 0; cur_color < num_colors; cur_color++) { if (ColorMap[CM_RED][cur_color] == pixels[cur_y][cur_x].r && ColorMap[CM_GREEN][cur_color] == pixels[cur_y][cur_x].g && ColorMap[CM_BLUE][cur_color] == pixels[cur_y][cur_x].b) break; } if (cur_color >= num_colors) Fprintf(stderr, "color not in colormap!\n"); y = cur_y + yoffset; x = cur_x + xoffset; Bild_daten[y][x] =cur_color; } } } nethack-3.4.3/win/gem/title.uu0100644000000000000000000006325007764735041014721 0ustar rootrootbegin 777 title.img M $ .P $ $!= %T 4 R%A)34< /H ^@#Z /H &K ^@ /H ^@ M #Z /H #Z LH#Z &K CT"R@$: :L!JP+* 1H CT /H M :L (] 1H -; UL"R@/H LH"/0 _PDH*"BH!H ) ?_@'_^_ M___'A( /_#_\!__X _P#__P?__P!B@HAH )_@ ?X ! X!( / \ #^ ' M__ /\ /@ /A@>!@ ?@#_^____'@X 0W_@?^ /_\ __ ?_X!__P 8H!X ( M?\ '_Q___X.#@ ^/\ _P ?_@ ?P ?_ #_\'AX (?]_W_U___[N#@!"O]^_W M_?_O_\?S^?_?[_\_A@> "& P!@,8 #& X !V( .&!@8 8 P '@.$8# # ,' M* > "#_@ _X/__^#@X /C_ /\ #_X ?_ #_@ ?^!X> "* O^@+H "Z X / MJ!?H%_Z +_^8#>Z O_0"AP> "& P P8, #& X /S# ,, & 8 #@ Q&!P P& M!R@'@ @_X '\!___@X. #X?@!^ _\ ?_X _X '_ >'@ B@+_T%] N@. M#[0O]"_^@%__8 +N@;_T!8<'@ @P, &&# Q@. #\PP## !@& !P &Q@X , M# "- O_H7T "Z X /M"_T+_Z 7_Z (Z" M_^@7AP6 "O@ ,!X!A_P /X#@!#\/XP_@8!_ P \8/^&#_\!@B !P8 ? M #@#@ !N@O_07X<%@!U\ # ? 8?L/_S^ M?P'X_#\,/P, /@<'_#&#_&!_X 8%@ H0 ' '@ X X ', \ #P #@6 M!/P '^ &!8 *' ?]P#]Y___NX. $+?O!^\!_^X!_A_@_OP_W^ &A8 <[__0 M%_Z%]#_\NG\!^+0O]"_] "_Y!APN@O^@7X<%@!T\ # / 8?L?__^_X/__#\, M/P, /@8/_CN#^&#_P 8%@ H0 # '@ X X 0, \ #P #@ !X H ^ _ MP 8%@!T< !_[ /WGP .[@/X'M^\'[P'_[@/YX^K^^#^_P :%@!SO_] +_H7T M0 .Z@(('M"_T+_T +_H)XBZ"_Z"_AP6 "#P , \!A^Q_@X 2@__\/PP_ P ^ M!A__/X/PP/^ !@6 '1@ , > ?_#A^ /@P#P / . ?X#@#P #^ !@6 M'1P '_L _>??_+M^_OBW[P?O ?_N _?Y[O[P?[^ !H6 '.?_T O^A?1?_+M^ M@OBT+_0O_0 O^A?Y+H+_0+^'!8 ??_SI^_O\W[P?O ?_N ^_^[O[P_W\'A8 ?_[A^ /^P#P / ' !__#@#P /X'!8 <'X ?^X#]Y]__N'[^ M_[?O!^\!^_<'W_]N_O#^_@>%@!OG_] +_H7T7_^Y_H+_M"_T+_T*%_1?_VZ" M_H*(!8 ??__A^_O_W[P?O _OW M!]__KO[Q_OX'A8 ;Y__0!?Z%]%__^?Z"__0O]"_Z"A?T7_^N@OT"B 6 '#_ M, ?!A^Q___Q_@__\/PP_!@X?#/_A_X/V!_P'!8 <&\ < !X!__^'X __ / M \ < /^'. / !_ <%@!P?P!_]P/WGW__X?O[_]^\'[P/[]P>_X<[^\_W\ M!X6 &^?_T 7^A?1?__O^@O_T+_0O^@H7]+__SH+Z!8@%@!P_P# 'P8?L?@ \ M>8/P?#\,/P8>'QS_@'^#_ _\!P6 '!O ' > > #QX /!P#P / ' #^ M;@#P _P'!8 <'\ ?_<#]Y]X /'C^\'?O!^\#\_<'OX!N_O?[_ >%@!OG_] % M_H7T7____H+_]"_T+_H2%^2__^Z"] N(!8 ?> QP_O '[P?O _7W#W\ 'O[W^_@'A8 ;Y__0 OZ%]%____Z" M__0O]"_Z%1?I?__^@O0+B 6 '#_ , /!A^Q^ 1AH_ ,/_P_!A\?F?X #X/X M'_ '!8 -&\ , !X!X !& \ . # \ ! > ?@ . . '\ <%@!P?P!_^P/WG MW@ $8-[P!^ '[P/U]X]^ [^[_?P!X6 &^?_T +^A?1?___^@O_T( 0O^A47 MZ7___H+H%X@%@!P_P# #X8?L?@ 88/P#!_X/PP?#YG^ >#\#_P!P6 #1O M #@ > > !@ / #@ P/ 0#@'X !@# #_ '!8 <'\ ?_N#]Y]X &#^\ ?_ M_^\']?N/?@ &_M_O\ >%@!OG_] "_H7T7____H+_]!_X+_05"^E___Z"T"^( M!8 ?> ! GO '___O!_7[CWP M O[?[^ 'A8 ;Y__0 OZ%]%____Z"__0 "_T%0OI?__^@M OB 6 '#_ , 'A MA^Q^ !Z_ , _##\/F?P 8/@?\ '!8 (&\ & !X!X$@ 'P X &#P , M X!\!( "'\ '!8 ('\ ?_V#]Y]X#@!&6\ ?__^\'[?N/? _C_?P >%@!OG M_] !?H7T7____H+_] +_0M"^E___Z"(%^(!8 >!( !\ . !@\ #@. > 2 C^ !P6 "!_ 'O]P_>?> M X 1_O '___O!^[[GW@ /__OX 'A8 ;Y__2@7Z%]%____Z"__0 "_T+HO1 M?__^@ "_B 6 &W_ ,X#QA^Q^! !F_ , !_##^'\?@ 8 !_P@%@ @[P M, '@'@2 ? #@ 8/ X!P'@$@ %_" 6 "#_ 'O^P_>?> X 0YO '__^O!^[] MWW@ /__?PB%@!O'_]* OH7T7_O__H+_] +_0NA=%___Z 7^(@ $.!(& M&L S@/&'['X, '#\ P #\8/X?S^ !@ '_"( !#@2 "#O P > >!( ! M\ . !@\ #@' ^ 2 7\(!8 (/\ >_[#]Y]X#@!"^\ ?__^\/[OW>^ __]_ M"(6 &\?_TH"^A?1?\__^@O_T OZ"Z%TO___H !?XB (!^ !_\ SP/F' M['X\ &+\ P?^'\8?X?S^ !@ /^"( "'X #@ A[P . '@'@2 ? #@ 8/ M !X!P/@$@ '^" 6 &W_ 'G^X_>?>" ]O '__^O#][]WO@ /_^_@B%@!J' M_]) OH7T7\O__H+_]!_X+^A>A=+___Z HF 3.$@!O\ #/ P88,8?P << M#+_\,!AAAC, & 8 #@ )Y7@. 3^$@ 'X'8 "!_X#@ $,!( 5_ >?X#\ M!\ X "Z =@!^ /P/P> X($@ )__@.%@!4$ !) @(0$0#@ (( !" $( A MA!(#@ * 02 G@!@X @;X . #-@888,?\P ;\ ## ,,!AAAC, &! M@8 %@ -UP " 7^$@ & 'X ##\ @!H0?____? 'C_ _ ? ^ P@ 'X ?@ M#\#\'@."!H #?\ A( 6_G $B! A 1 R @@ $( 0@"$"$$@. H&!!H # M<#__@ %?A * &3-@888,/PP 8, #K ,82 M 7 @@ (# ( !( . %@.( !X_P/P'__@ /X !6 'H _ ?AX#@ /^?X &@ (/ M (2 %OSX !(@0(0$/P@ (( !" $( A 0A(#@ ."0( &@ (,_X2 '/X #,P M888, P ?, #+ -L!A@PS, &#X, '@ ' @ '@@ 55555^^"& 4 $@!8' M! >'\#\!__X ". =@!F /P'X> X #_C^ !X !P(2 %OF, !(00(0$ @ M (( !" $( A 0A(#@ ."(( '@ &_A( <_ ,S QA@P C !XP ,, SP-,## M,P 8-@P > 3" < #@ (=O"& 1 $@!8& @ >'^#\!_]X "> ?@!R ; M@'X> X #_C^ !X !,(2 %OL& !(0((0$ @ (( !" $(!" 0A(#@ ."(( ' M@ $OA( 6_ '_\_@_A_P)#___T__\/_T_\O_#\X. X/P?X> ?" < #@ (- M_"($@!P& __>[^[]]_;[__ZN__?O]N_=OW[>___^_M_?AX !\(2 '/L'_]+H M+H7T O__H+_]"_T+]"_0M+___Z"T%^(A( 6Z '_\_@_A_P'[___@__\?_R_ M^?_#\X. X/P?X> >" 8 #@!P)_?_ X X!\ #__X __ /\ _ /P# ___^ M , ?AX !X 2 '!(#_][O[OWW__O__O[_]Z_W;]:_?M[___[^W]^'@ '@A8 5 M!@ 2"""$! ?H "" 0@!" 0@$(2 X #@A! !X !'X& #*JJJH !__/X/Z?\ M/X. "L?__'_\__?_P_.#@ .#\'^'@ $P@ & !( ;^?_ X X!\ #__X __ / M\ _ /P# ___^ , ?AX !, & 'U5557D%_][O[MWW^!O__KK_]Z_W+]B_?M[_ M__[^W]^'@ $PA8 5C@ 2"""$!#@8 "" 0@!" 0@$(2 X #@A! !X& 5\$ M@ <#__/\/[?\A( *@__]/_X_\/_!\X. X/X/X: L7\!8 ;<__ \ 8!\ ?C M__X __ /\ _ !P! ___^ . /AH "Q?R 2"#@!S\B__>]];-]T?C__[^__;O M]>_?AW]>___^_N_OAH "Q?R%@ C\ !($$(0$0 . "H( !" $(!" 01(#@ ." M"" &@ (__X !! 2 " ?_]_R?C_Q_@X *@__]O_T_X7_A\X. \/X/X2 !/P) M__X%@!L'_\#P!@'P'_O__@#_\ _P#X $#___X X ^$@ 3\"?_^@ %[@X < M_G?_VO=V]???^__^_O_V;_;OOOA?7O___K[O[X2 !/P)__Z%@ CX !($$(0$ M0 . "H( !" $("!X01(#@ .""" $@ $#@P6 "(__^_X_E_Q_@X *S___/_^_ MZQ_I]X. YOX/X. H"?@P6 &XO_P/@& ? ?___^ /_P#_ /@ 0/___@#@ M#X. H"?@X !/X2 &X__UOO6[???___^LO_T[_1OM.>76O___N;O[X. H"? M@X6 "'0 $@(0A 1 X *@@ $( 0@( >!$@. X((( . 7^$ 8 !?X6 !?/_ M#^?]A( *Q__\/_T_?VS1\X. \/\'X> ?X!@!5____^>__ ^ (!\!____X M__ /\ \#@ = ___^ / 'AX !_H !'X. '/Y__][Z^IWV7____KK_]^_V[R"3 M+U[___Z^]_>'@ '^A8 ;A__2^@J%]%____Z"__0O]"^@ %2___^@O07B( ! M 8: !O/_G__\?X. "OO__+__?W:.>_.#@ .C_!^'@ 'X@ $!A( 1.__ _ (! M\!____X __ /\ \#@ = ___^ / 'AX !^( !#X2 &S__WOUJA???___^AO_W M;_2O*7&%7O___M[W]X> ?B%@!O'_]+]"H7T7____H+_]"_T+Z 5+___Z" M]!>(@ $'AH %\_\OK_R'@ 5__/]]](6 X/^'X> :" 0>$@!&[_\#\ @'P M'____@#_\ _P#P2"@ 3^ /@'AX !H( !!X2 &[__WOW:U?=?___^@O_TK_ :"%@!O'_]+]"H7T7____H+_]"_T+Z( )+___Z"^A>( M@ $'B( #G\_]A( *B___/_]_>?WW]X. ^?^#X: F@ @ $'A( 1F__ _@(! M\!____X __ /\ \$@H $_@#X X: F@ @ $'A( ;G__2_NJU]E____[V__3O M]*\G_@B:___^FOO[AH ": "%@!OG_]+^BH7T7____H+_]"_TKZ/\ )K___Z" M^@N(@ $#AH &]_^7__Q_@X %V___?_Z#@ +L]X2 OX/A( $[4 ( ! X2 M$=O_P/X! ? ?___^ /_P#_ /!( &?__^ /@#A( $[4 ( ! X2 &]__VO[M MA???___^IO_TK_4O0@/SF7___H+[^X2 !.U "%@!OG_]+^A87T7____H;_ M]"_U+T(#X)E___Z"^@N(@ (!^ . '#_ ,_'GU^_^ !O_ -?PW_[__^_? M ?_S3X '@ (!^ . "!O / > >!( *\ / \ _ @< . _ #@ > @'X M X ('\ >\)LMY%X#@!'"\ :O!B]2_!&K< @O&[@ >%@!OG_]+^@P7T7___ M_L+_]"_T+T+\$*E___Z"_0N( 8 !X . '#_ /_#5G^]^ !@_ ,/P[_U__Z M__ ??S3X ' 8 !X . "!O / > >!( *\ / \ _\ @< . _ !@ %@!OG_]+_0 7T M7____M[_]*_T+V+_T*E___Z"_06(!8 %@!OG_]+_0 7T7__]_NK_]"_T M;T+_TDE___Z"_06(!8 %@!OG_]+_H 7T7__]_IK_]&_U;T+_T4M___Z" M_H6(!8 @O""P >%@!OG_]+_H 7U7__Y_J;_]._U+M7_ZDE___Z"_H*(!8 % M@!OG_]+_T 7W7__Y_H[_]B_V+L7_[%:___Z2_H*(!8 %@!SG_]+_T 7T M7__U_O;_]:_U;HW_[-2___:2_T%_AP6 '#_ -_ V[^[^ XAB_ /OPS_K_ 8 M?O@ ">_P]> '!8 6&\ \ !X!X " \ / X!\ 0. . _ 8 <%@!P? MP!KP&17E7@ $(/;P!&\'+M7P#]6X "2\$M@!X6 '.?_TO_0%?1?__7^]O_T M;_4NU?_N5;__]H+_07^'!8 9S_#[ MX <%@!8;P #P '@'@ ( #P \ #@'P 8 X #\ !@!P6 '!_ $O +5>1> M P@MO 'KP?N[? *IM@ ++P16 'A8 O]^[E_^JF MW__FDO]!?X<%@!P_P#?P'=?O_@ V89/P##\,/R_@&O_X !G'\'7P!P6 %AO M / > > !@ / #P , ^ "!@#@ /P # '!8 <'\ :\ HMY%X '&#N\ ?O M!^W;X TJ6 NO JL >%@!SG_]+_Z@WT7__=_N[_]^_W[=O_[2I?_^::_ZB_ MAP6 '#_ /_ /M^U^ .9AP_ ,/PP^#^ ,?WP .?_P?_ '!8 6&\ \ !X!X M & \ / @#X (' . _ , <%@!P?P!+P!$WFW@ \8+[P!^\'Z_O@!ZK< M !""\""P!X6 '.?_TO_T3?;?_SW^OO_W[_?K^__WJM__UH+_H+^'!8 => /S@_W /]P_W^^ 'Z^P ,.+P(+@' MA8 <[__6__5=]U_\_?[_?^_W[_?[__ > #@ ' P > # 0# M@ /P !@'!8 <'\ 2\ *EY]X#_.#_< _[#__]X ?M] !@WO 96 >%@!SO_]+_ M^J7WWP/]_O]_[_OO__W_]^WW_V[>_]!?AP6 '/O /_ &!^S__ ?C ? __S__ M_^ , ! !X $!( #\ 8!P6 M'+O $O #_>=0__WA_[ < 0 /> 'U?@ X/[P$=@'A8 '@ X$!@0& \ !@2 _ ' <%@!S[P!KP ?WG MS__]X?X /\ _P# #_;^ <#N\!3 #-K__?WWS__]_?X/@X. "\#_[_;^ M =[N_]1?AP6 ' / ,_ #!^PP ?G__ _P#_?\ __\'^8Z/P'_P'!8 < \ M\ !X > !\ #_ /]_P ' " / # <%@!P#P![P ?WG___]X@'P /\ M_W_ ?=__\+>\ @L!X> "MK__?WW___]^@&'@ G!]W__WM[_Z"^'!8 < \ _ M\ ,'[ #__\?^ '_@?__P '_< #'@_ ;/ <%@!P#P #P '@ !X!_X ?^! M___ , 8 \ ,!P6 ' / $O !_>?___G@'_@!_X'__\ &S__AO[P#.P' MAX )TO_]_??___G@B( )_AN__[[^_^QOAP6 ' ? ,_ !A^P ?__@'_@!_\'_ M_^ _SX#CX/P#_X'!8 "-[__OWW__P'BH ( MX<__?O[_]"^'!8 <#X _\ &'[ ___^ __ /_X___X '_O_\?@_ .W@<%@!P/ M@ #P '@ /_X#_\ __C___@ ?^P !X \ &!P6 ' ^ $O _>?_@__@/_P# M_^/__^ !_['\'O[P!38'AX 'TO_^_??_@XR !_'\_O[_]#>'!8 &#X S\ #' MA( 2X#__!\ /P ?^?__\#\ Q^!P6 ' ^ / > ?__@/_\'P _ ! M_YX#^ #P 8'!8 <#X >\ !][_!__^ __P? #\ '_G@/Y_O 'E@>'@ ?6 M__]][_!_C( '_@/Y_O_WEX<'@ 0W\ #'A( #X'_@!H ) _^/__\!\ 9?!PB M"O > /___@?^ &@ D#_X__\ !P <'!X +&O ?>P/___@?^ &@ D#_X__ M]_]P [<'AX &VO__?>P/CX %]_]_^[>'!X %,_ 9_R#@ +A\ B "!_'___! M\ :O!PB !/ <"#@ +A\ B "!_'_^ < #!P> !1[P #W @X "X? (@ @? MQ__@_W #6P>'@ 7>__^]PY" !>#_?_M;AP> !3/P '_@@X !@ F " 'C__CY M\ 8/!PB !/ <"#@ & "8 ( >/_^ P ,'!X %'O .<"#@ & "8 ( >/_ M^ >P _L'AX %WO__N=^1@ 0'O_O[AP> "#/P #_@___ #(& !O ?\ 8O@ 8( M@ ?P ?@___ #(& !O 0$ #@ 8'@ @>\ 'X/__P R!@ ;P$% #VX &AX $ MWO__QY* !/!?^]N'!X '8? #^'_^ V !Q_ ?_ &!X &"( &< /X?_X#8 ' M'\!_@ !@ 8'@ <_< /X?_X#8 ''\!_@ /]@ :'@ *_?Y6 X_[_8<'@ 9@ M\ /X?\0@8 $^ P'@ 8(@ 40 _A_Q"!@ 3X & !@> !C^0 _A_Q"!@ 3X M!_V !H> K^?EH "]_V'!X &8'@ !^/ #X & ?_X?P? !@J P?CP ^ !@'_ M^ !P 8'@ 8_X 'X\ /@ 8!__@/_< &AX "O^>6@ */_8<'@ 7!_ 'XA& M!0_\#\/ !@J @?B$8 %#_P , &!X %?^ !^(1@ 4/_ #^P :'@ )_XY: M O#^AP> !<_P . $H $_@#[P 8(@ 00 . $H $_@ P 8'@ 5^$ #@!* M!/X /L &AX "?A^7@ $^AP: P&_^!6 ! < ?^ &!X " ?@5@ 0' $!@!@> M O'X%8 $!P!'8 :&@ +^\9B L=_A@: P/W_A>!@ '@!@> @?^%X "^" & M!H # P?_@!6 M @?^!P: ! ('_X 5@ ('_@>&@ +Z/YB OX?A@: ! X/_\ 6@8 !\ 8'@ ,/ M_\ 6@8 !P 8'@ ,/_\ 6@8 !P :&@ 'QFH !SX8'@ (/_A> @_P!@> @_^ M%X "#_ &!X "#_X7@ (/\ :H!X "'^ 7@ (#^ 8'@ (?X!> @/X!@> A_@ M%X " _@&J > 3\9@ %\!@> 3\9@ %\!@> 3\9@ %\!J@'@ %\&8 !'@8' M@ %\&8 !'@8'@ %\&8 !'@:H!X !X!F 0,&!X !X!F 0,&!X !X!F 0,& MJ"@H'8 !. JH*"@<@ (!_@JH"X "'X #@ (#P!8+@ '\!( " \ %@ '\$ N M > $@ (#P 6 ?P$@ (#_PJ+@ +\?X. OP_E@N A^ X "#/ 6"H " _P$ M@ (/\ 2 @'^$ J @/@!( "#_ $@ (#_P2 P/_@ F+@ +\?X. O /E@N M A_ X "&?@6"H "!_P$@ (?^ 6 ?P0"H "!^ $@ (?^ 2 P?_@ . P?_ M@ F+@ +\/X. N 'E@J P?^0 . A/X%@J @_@!( "'_@%@ '\!8 !_ H* M@ $(!8 "'_@$@ ,'_X #@ ,'_X )BX "X;^#@ +@!Y8*@ ('_@2 B?\%@J M A_@!( "/_P$@ (!_@6 ?P*"H !& 6 C_\!( #!_^ X #!_^ "8N >&$ M@ + Y8*@ (/_ 2 B_\%@J A_P!( "/_P$@ (!_@2 @'^"@J 1 %@ (_ M_ 2 P?_@ . P?_@ F+@ 'SA( "P .%@ $SA8 !,XH*@ (/_ 2 C_\!8 ! M9 6 :@*"H "/_@$@ (__ 2 P??@ . @'>"@J C?@!( "/_P$@ ,'WX # M@ ,'WX )BX !^X2 L #A8 !=X6 ;N*"H "'_P$@ (YG 6 2 %@ $@"@J M C_X!( ".9P$@ (#WP2 @'>"@J B?P!( "/_P$@ ,#WX #@ ,'WX )BX ! M^X2 L #E@J AZ\!( "/_P%@ $@!8 !( H*@ (^N 2 C_\!( " ]\$@ (! MW@H*@ (O\ 2 C_\!( " ]\$@ ,'WX )BX !^X2 L9CE@J AUO 2 AB(!8 !> 6 7@*"H "/K@$@ (?^ 2 @&&!( " M 88*"H "+_ $@ (7> 2 @&'!( #/X?@"8N ?N$@ +O]X6 8>%@ &'B@J M A_\!( "*!06"H "/_@$@ (O] 6 ?P%@ '\"@J BO0!( "+_0%@ '^!( # M/__P"8N ?N$@ +7ZY8*@ ([W 2 @O0!( # P. X $ 08 < @*@ (_^ 2 M @PP!( # P. !( #? !P" J @PP!( "## %@ '\!( $/OWP< B+@ '[A( " M_#^*@ /X_'^)"H ".]P$@ (($ 2 ! >'P#@#@ -^#_@("H "/#@$@ (/\ 2 M! >'@#@#@ -\#_@("H "## $@ (/\ 6 "7@ . /_W_^ B*@ +\.XR ;^# M@ /X_'^)"H "/#P$@ (,, 2 "@__X/P 0$#_X("H "/_ $@ (/\ 2 ! O_ M@/P$@ (/_@@*@ (+T 2 @_P!X '_ ._O__@B+@ 'SBH #^_^?@X "^'B* M"H 6/_\/_ !^ !^ '__]_@ '@#__@@*@!8_\P_\ '__X'X 8 W^ M 8 _^" J "@PS#_P ?__@?@$@ @-_@ ?\/_@B+@ 'S@X $_@?@?X. M _@ #X. _@!#XD*@ T__[_^ #__X?\ _@P* !#\!__\("H 6/^.__@ ' M___G_ ,_\'_P . /_P@*@ H'X[_^ ?__^?\!( "!_\#@ /^#_\(BX ! MXX. !/@'X!^#@ /S_P>#@ /X @^)"H !/X,!@ @"__]O_ ?X,"@ 1_P___ M" J %C@'__\ !O__;_P &/_!_\ & !_\("X ) ___ ;__V_\!( "!_\# M@ ,\!_\(BX !YX. !/D#P)^#@ /C_P>#@ /@ >)"H !#X. "8 #?_[__ M^X,"A @)@!__?_\ #Z___^ #_\___" F %P/_^#__@ ^__?_\ #8_@'^ #/X /_ M" F $0,8 #__@ ^__?_\ # '^ X #% /_"(N "/@____P0 (/@X #V_X! M@X #S_0#B0F %P'G'__[@ ??^__\ 'Z___X '_\__^" F %P?_X!_[@ _? M^__\ ' _$'X '/X '^" F $088X!_[@ _?^__\ # $'X X #% '^"(N M". ?___P( 0/@X #P_Q!@X #S_0!B0F %P/P'__Q@ >O=?_X '#/^/@ ![ M]_G\" F %P__X _Q@ ^O]?_X ' ''W@ '; .?\" F %PP/X _Q@ ^O]?_X M # 'W@ &8]^?\"(N #N /___QT N/___YPQQ]@X #W_?GB0F %P_\/__@ M _7<__X 8_W_'X C /'\" F %P__P _@ _7\__X ' #'_X 'C /_\ M" J %@/ #^ #]?S__@ !__@?_@ > __P(BX (P ____'H#X^$@ +L?X0! MB@F 0^#@!/ _7\__P "'_/\ #D//\" F %P__^@_ _7\__P #@ M#'_\ ##@/_\" J %D "#\ #]?S__ ./@?_P ,!W__P(BX (^@____'H M#X^#@ +[[(6 ?>*"8 7",?_'^ , ##\ +___P 'R__P("8 +#__[ M[^ #\ #_\ #@ D(?_P '@__P("8 7!_@#[^ #\ #_\ , ?_P (5 M__P(BX "^^^)@ /[SW^$@ 'UB@J %L__#^ "/'#^ +___@ (1__@( M"8 +#__C_^ #R/'_^ $@ A_^ @'_^ @)@! #3@ __ MG^/ ?O_^ #@H '^ _/_^ @'@!H@ 8_Z__CP 7[__@ #_'_X # MX/_X' <'@!,&' 8P __@ 7[__@ # '_X X #%/_X"(N !^O__#__Z!>% M@ +\?X2 !/3___>'!X -. '___[_ ]__X ."@ ?X #\__X" > &B M #_C_^_P #O?_^ /\/_@ /@?_C\!P> $P<\ " #_^ #O?_^ , M/_@#@ ,4?_@(BX 'X__QC__$(X6 OP_A( $]'__(X<'@ 0X /@X &^ , M/__ X* !_@ 'S__@(!X :( ?^O___@ /#__P !_P_^ _!_^_P' M!X 9!_P < /_X /#__P !P _^ @Q_^ B+@ ?K_^!'_\/#A8 "_#^$ M@ 3\?_PGAP> &3 #__\]_X !O[^\ '__[@ '__S@(!X :( ?^/S MW_@ ._O[P #_X?N _P_/_P'!X 9#_P 0 /SP ._O[P\ #@ ?O^ M @ _. B+@ ?C_^!'_\6'A8 "_A^$@ 3\/_@?AP> &3 #__\]WX ?[^\ M ?__S@( '__B (!X :( __WSW_@ )_O[P #_\/. @ !_X>/_ '!X 9 M#_P P 'SP@ )_O[S_ " //_@ !@ >( B+@ ?]_^H7_]F'AH !#X2 !/X? MX!^'!X 9, ?__YV)@ '[?YQ40 "__^)P0 __^( @'@!H@ '_\?G?^ _ MM_G ! ?_PX@! /_PX__ <&@!H(#_P1@ 'YQV /[?YVKP % ../P # . M( B+@ ?Q_^=G_\/+AH !#X6 P_@/X<&@ !_X /^_\"PN " !#'^ !@ !@F+@ +Z?X. @/ AH !AX6 X?!^X<&@!D/ M__P#___X 0 _[_P#!$ +__\& $ #___"0: &P& ___+@?_ '_O_ 0!_ M_\0 0!__\$__ <(@!<#_ .!F< ?^_\'/O % !&?_ ' 0F+@ C\O_N_ M_@/ ?X6 <>%@ /!P:.'!H 9!\ !?__\ -$ ?\_\$ %___ @#___PD& M@ T!P ?__T0'_P!_S_P X +?__H " ___PO_T'!X :/__Z 0&MP!_S_P M/_\ ( __^ P @ $'BX (_1____X#P'^%@ 'KA8 #\, #AP> "#?\!___ M ")$!( %0 " !_\$@ 4/_^" 0<'@ @P ?__P ?^ 2 #A_X@ ?_ !_X __ MX/__!P> 7@%@ (]N 2 ";__@ ?__@ . L [!Y^ D ZAP> DSD!( " M 8(&@ & !8 &0 /@ "$!P> 4 %@ (^?@2 S_\@ . "#_\0 /@'_^!P: M P'S& 2 CY^!( )\\^ !\\_ X "7WH'AX "_.>6@ +1QX<'@ *Q* 6 M 0($@ ,-,( #@ ,-,$ #@ (@0 <'@ *MS 2 C_^!( #/_R X #/_Q X " M<<8'!X "[]P$@ (__@2 ">RW@ >RWP . ENN!X> OWOEH "\<>'!X " M4" $@ (GY 2 P(@@ . T(@0 2 40'!X "3]P$@ (X' 2 S_<@ . S_< M0 . G_^!P> N_-@ +X'YD'@ &P M!8 ", P$@ ."@( #@ /"@$ #@ )@!@<'@ *O_ 2 B_T!( #/_R X #/_Q M X "?_X'!H # >_\!( "+_0$@ E__X $__\ #@ )__@>?@ *__8<'@ ,1 M! P#@ 0,, #@!( '@ L 0 . !# D X%!X ##O@, X )>]X X '_B M X #/_Q X $/]P #@4'@ ,N^ P#@ ][W@#@ #__X $__\ #@ 0OW . M!8> ?Z8@ '?AP> "ACP#A@ &?D _@#@ P /@4'@ H' M" X8 &?^X/X X " 8 #@ )\/@2 !!X< #X%!X 5!P@.& !__^#^ ?_^ M !?#_P X $'A0 /@6(@ $/D( "_#^$@ +^'X<'@!0, ]\ &#R ?X !# MR8'\ +'X@2 !!@,!'X%!X * _ /? "?_?G^ . !P&!_ >!X$@ 0?_ 1^ M!0> %0/P#WP ___Y_@ #PW@?P 7@?\ . !!?\!'X%DX "_#^$@ +X'XT' M@!P&( ?^ (!D _\ "@P/\ +%8@/P ,/ S^!0> ' ' !_X !?_O[_P M :C _P 'U^ _ _\#/X%!X < < '_@ '___O_ /K\#_ !?7_S\ M"]P,_@63@ +^OX2 OU_C0: !0'__ __ X 5@ _\ @0 !_^ +CQ _X . M< _\!0: !P'V( __ ^#@!/\ _!P__^ #\/$_X __ _\!0> ' 8CC_\ M#_]___P !^__[_X #?P___@ 6@#_P%F8 "_#^$@ +'XX<&@!T#__P?_P " M !/^ $ 0'_@ D P'_ #_ /_ 4&@ <##R ?_P /@X 3^ ?X ?__@ ( M'_Q/_ __\/_ 4'@!P&(]__ W__[_X !_O__O^ ]____\ #'XP_\!9^ M L?CAP: '0?__!__ $ @(?X 0# /^ "8& /\ #P!_\!0: !P8#P!__ M !^#@!/X #_P#__^ #P?^._\ '__Y_\!0> # /#__\ 'O]_?_@ /X. #?X M/W____P !A_@ #^ !_ 2 C_X!0: !PP __@!^#@ /P '^#@ G^ 'X/X'_\ M .#@ 'X!0> 0>#@!B '_Z___ ?W__G_X ?_?___P \ #__@%GX "P!^' M!H =#_P"#__@$>(G#\ !X P?P C_@0?P % */_H%!H '"$ "#__@'X. M#\ ?7____P ?C@ ?_P X. ?H%!X !0X. &. .W=OWP !X?_\__ !]P!^_ M_ #T O_^@6?@ +0'X<&@!T/]@,/^> 3\ ^?X #@ '!_ #_^'!_ \ \? M_@4'@ ;P P_YX!^#@ /@ '^#@ G\ '_X ?_\ >#@ '^!0> ',G___G@#>_W M;^ ??__O_P ?< ?O_P !_ /__X%GX "\#^'!H =#_,#C_@ ?"/W^ > # M@?P !__CX?P / /'_X%!H ' ? #C_@ #X. #^ ?_OO__P ?_@#__P !X. M ?X%!H = < ?G_P !_ /__X%GX "\#^'!H = M#_&#C_@ ? /C_ &? #D_@ 0?_C@_@ _ /W_@%!H ' ? #C_@ #X. #_ M/^____@ ?_@#__@ !X. ?@%!H ' /\ 0__D/^ !_^.#^ T \?X 4& M@!T/L /_\ /X ?_\ ?X '_^ _^ /_^ 'W___X 4&@!T/CS__\ /_Q__ M\ /@ ?W^ _P!__^ 'T __X 6?@ +P?X<'@!8P&(!X 6,#^/ M\ !P..'\ __,/^ !_^./^ . P,_P 4&@!T., /_\ ?X ?_\ /\ /_ M^ /^ /_^ #/___P 4&@!T.#\/_\ ?_Q__\ /P __^ /P!__^ # /_ MP 6?@ '#B > !# ?__ #@ \#A^ #_CG^ #_C_^ #@ .#_< %!X <, /_ M\ >, __X #. /_X . /_X /__]P 4'@! /X__P !X____@ , '__@ M X #'__@ X #@_W !9^ <>(!X $, /]\ . %0./P /^/_X /^/_X M "@___? M#C___\ #@ ,?_^ #@ D?_^ '#^< %GX !QX@'@ 00!_G X 5!__ ? MX__ _X__ !P_' !0> '! '^< #Y__\ #@'_\ #@#_\ #__ M\< %!X 0#__YP /_O_P (!__P . "1__P '!_[ M\< "&'\\ /#\< /#_< '#\\ %!X <'_OQP /__SP /__Q MP /__]P /__SP 4'@!P/__' ?^_/ ___' ___W !P_/ M!9^ <>(!X <$<)QP (8?SP \/QP \/YP ' __\< !_[\\ #__\< M #__^< '#\\ %GX !QX@'@!SYP!A #P_' #P_# #P_# ! MP_& !0> ' ' &$ #__\< #__\, #__\, #__\8 %!X &!H 6 8$ " ?\?\ _]_^ _]_ M^ . U\:X 8'@!5_/'@ '?&_ -7:O@ -7:O@#@ -;"N &J : ! &! M!^ #@ .G!7 #@ .I%3 #@ .I%3 #@ ,& . &!H " 8$$@! !_Q_P #_W_P M #_W_P X #_A_@!@> %7\X$ 5\:\ U=J\ U=J\ . _X?X :H M #_ B@H**@/@ '@#H " > (#X !X Z @_@" ^ > .@ (/^ B>@ +P!X@. M@ (!\ . 3X*@ (#P @.@ (!\ Z C_ " Z @'P X " ? )@ (_\ B>@ + M#X@.@ (!\ . 7 *@ (/P @.@ (!\ Z G_ " Z @'P X "#_@)@ )_X B> M@ * 'X@.@ ("X . 6 *@ %_"0Z @+@#H$)#H " ^ #@ (?^ F!@ '@")X! M@ $?B B R 0 . C^@ X !8 6 ?P$@ %^"0Z C^@"8 !_ . @'^"0B M R 0 . C_@ X "'_@(@ ,!_^ (F8 ! X. _X 'X@(@ -@ & #@8 !P . M 6 $@ ,'_X #@0D.@8 !P B !P?_@ ?\)"( #8 !@ X& < #@ (?^ B M P'_P B8@ CX '____X /X@(@ AP & '_P . 6 $@ ,.+\ #@8 !@ @- M@ ,!_\ (@ @.+\ /_@ @(@ AP & '_P . A_X"( # __ "(J 7^- M@ CP #____Q^/X@(@ H__N /_X !@X +_@ $/_@ !_X (#8 # __@ M"( ($/_@ #_X ("( (/X;@ #_^ -@ ,#_\ (B( "O@:.@ C@ !____Q_ M/X@(@ A__^ ?_\ B "!?NX >N " J !B ?_\ B "!?NX ^N M" B "G\#X !__P .$!X # __ "(B _P#WXV ". '____/\_B B "#__ MP !__P"( (/__P !U8 ("H &0 !__P"( (/__P #U8 ("( */@' M '__ 8. ?X'@ ,#_\ (B( #^ &_C8 (P /___\_S^("( "#_\#@ @. M ' '__P. ""@ \ >N " V P__\ . A;1 X (+__P #ZX ("( ! M# 2 P__\ 2 0$#@ ('_P. P/_P B(@ +P (B _X6T8. ",?_#____/\_ MB B @__ X (# P !XQX#@ AQ2G '_@ @-@ ,/__ #@ )_^@. "'XQ M\ _^ " B 0@$@ ,/__ #@ ( #O< /_ :8@ @'_X____S_/X@(@ (((0. P0 ( . #PA$ M8 N !P #_[#__@8(@ (&<@. P?_X . #W>\8 O__P #_[#__@8( M@ ('W@. P?_X . #W>\8 !_^ #P_#__@:(@ +^_@X (!_^/ M___\_S^("( ""#$#@ ,"'$ #@ ]'B?P8 ;1X\ _\[__X&"( "!_X#@ ,# MX\ #@ ]X>?P8 ;>'\ _\[__X&"( "!\X#@ ,#X\ #@ =X>?P8 .' X % M __[__X&CH !XX2 #?A____^ X ( M 'X /X #@X ,_@ ( !@X .OX #\#__@#'_G__ M #^#@ ' !HF #Q____X ?@!___P/P/__^(6 \ X@(@ 4&9@& (2 $=@% MG_G__@XX_X'_ !Y\ ?^ !@B "P>> 8 #P _]@'@X ,_@X _ '_ '[^ ?^ M!@B !0>> 8 A( -V /P'_^ # 8 $ ___P84#B F &/ _^ ?__C_P #_-!_^>@// M ?^ __X _ <(@ L____X .0 )__ 'X. "_Y[X ?_X#__@#\!PB %3____@ MY__G_\ ? /__@'\,/__@(. ?P'B( (P/ ____D "># 8 $ ___@84#B B M&7 '__PG! Y_\ #Y_\?_]X;SV'_@!_^,/X'"( %0_P?__"$@ + 'X2 "M_X M '__@/_^-_X'"( !#X. $?!O__;_P!\ ___@>PP__^ @X !_@>(@ +P (. M _P /X,!@ 0#__^AA8 #^ WB B &? #__@GBBY_\ #YO\?_\X;CF'_@!/\ M./X'"( %@?@/_^"$@ + 'X2 "L_X '__@//\/_X'"( !#X. %>!O__;_P!\ M ___@>1Q__^ \____@>(@ +P (. _P /X,!@ 4#__^Q]X2 _P /X@'@!H! M\ G_P ,1##_@ .?SQ__GCP \?^ _YX_P<)@ 3P!_\ A( "@!^$@ J?_ #_ M_X#C_G__!PB !0__W_\ A( (@!\ ___@<>#@ * XX,'B( "\ "#@ /\ #^# M 8 % ___X>>$@ /\ '^(!X : _@!V_\ #((P_X !FX!__^ P8,'B( "^ &#@ /\ #^# 8 % ___^>^$@ /^ '^(!X : _P#^_X M#1%P_X #^?\?\8P^ ?'_ #^?_X'"( %? /C_@"$@ * 'X. "_&-_@'__P ! M_G_^!PB !7__Y_X A( (@!\ __Q@<># 8 $ ?___@>(@ +\ X. _P /X,! M@ 4#___SYX2 _X ?X@'@!H#_ /__@ . +#_@ /_]Q_P #ZD\?P 'P_[@<( M@ 5\ ^/^ (2 H ?@X +\ '^ /_\ '\/^X'"( %?__C_@"$@!" 'X '__ ! M]UO__ !___N!XB OP#@X #_ _@X "@ >#@ 'WA( #_@ _B B !@__P_X M X,"@ Y@!__@ #7^__@ /Z_[@<'@ 4#R!'__@. C__ X -!__@ #0 __@ M _Z_[@<'@!H#R '__@ #@#__ ?___@ 8!__@ ___[@>)@ 'O@X #_ _ MB( !SX2 _P /X@)@!@XP_P ____@ 8 ?_X '___X '^/\P'!X % \ X M__P#@ (__@. #0?_X $ /_X /^/\P'!X : \_'__P X(__@ '___X $ M /_X /__\P'B8 !QX. _P /XV _P /X@)@!@8X_@ ]___@ 8 ?_P # MMW_X #^O\ '!X % X 8__@#@ (__@. #0?_P ,'_X ?^O\ '!X : X_G M__@ Z(__@ '___P $>/_X ?__\ 'B8 !YX. _P@/XV _@ /X@(@!@/ MQ__P /?_YP #,'YX ![-^. #_C\("( 8" #_\ '#^< !##^> P M?C@ !_X_" F %SC_\ #OC^< !/_^> !\_C@ !___"(V _P\/XV _@ M/X@(@!@/S__P /__YP ,'YX ![M^> #_]\("( 8" #_\ '#^< !_ M_^> X?G@ #__?" F %S#_\ #GC^< !__^> !\_G@ #___"(V _P< M/XV _ 'X@(@!D/___ /__YP ,'XX !7A^> '_Q^ !PF &&#_P M'#^< !__^. +Y?G@ '_\?@ <)@!A@_\ YX_G ?__C@ "__YX !__ M_X 'C8 #_!P_C8 #X ?B B "#___P '___ X # P#@ X (<'XP !?_I\ ' M"8 "\#\#@!,\!P ___X !W/^, !__Z? !PF &/ _ ?__\ /__^ M ?W_C ?___P >-@ /@/ >-@ . >("( (?\_\ ?\_\#@ ,# . #@ A@ M'@ /__+P <)@ + ' . $S ' #___@ ?Y_X /__R\ '"8 4P!P !_S M_P ___X '^?^ "#@ ' !XV ^ \!XT"@ $#B B "'_'_ '_'_ X # M#@#@ X '8 X %__T0@(@ ,!P!P#@!)P!P _X_X /^?^ /__]$("( 5 M < < ?\?\ /^/^ #_G_@ #@PB-@ /@?@>,@ 3\ !B!V W__\ @= 4@ -___ ('8 #?__P")V X #X@ end nethack-3.4.3/win/gem/wingem.c0100644000000000000000000007303507764735042014662 0ustar rootroot/* SCCS Id: @(#)wingem.c 3.4 1999/12/10 */ /* Copyright (c) Christian Bressler, 1999 */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #include "func_tab.h" #include "dlb.h" #include #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #ifdef GEM_GRAPHICS #include "wingem.h" static char nullstr[] = "", winpanicstr[] = "Bad window id %d"; static int curr_status_line; static char *FDECL(copy_of, (const char *)); static void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */ extern int mar_set_tile_mode(int); extern void mar_set_font(int,const char*,int); extern void mar_set_margin(int); extern void mar_set_msg_visible(int); extern void mar_set_status_align(int); extern void mar_set_msg_align(int); extern void mar_set_tilefile(char *); extern void mar_set_tilex(int); extern void mar_set_tiley(int); extern short glyph2tile[MAX_GLYPH]; /* from tile.c */ extern void mar_display_nhwindow(winid); /* from wingem1.c */ void Gem_outrip(winid,int); void Gem_preference_update(const char *); /* Interface definition, for windows.c */ struct window_procs Gem_procs = { "Gem", WC_COLOR|WC_HILITE_PET|WC_ALIGN_MESSAGE|WC_ALIGN_STATUS| WC_INVERSE|WC_SCROLL_MARGIN| WC_FONT_MESSAGE|WC_FONT_STATUS|WC_FONT_MENU|WC_FONT_TEXT|WC_FONT_MAP| WC_FONTSIZ_MESSAGE|WC_FONTSIZ_STATUS|WC_FONTSIZ_MENU|WC_FONTSIZ_TEXT|WC_FONTSIZ_MAP| WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE|WC_VARY_MSGCOUNT|WC_ASCII_MAP, 0L, Gem_init_nhwindows, Gem_player_selection, Gem_askname, Gem_get_nh_event, Gem_exit_nhwindows, Gem_suspend_nhwindows, Gem_resume_nhwindows, Gem_create_nhwindow, Gem_clear_nhwindow, Gem_display_nhwindow, Gem_destroy_nhwindow, Gem_curs, Gem_putstr, Gem_display_file, Gem_start_menu, Gem_add_menu, Gem_end_menu, Gem_select_menu, genl_message_menu, Gem_update_inventory, Gem_mark_synch, Gem_wait_synch, #ifdef CLIPPING Gem_cliparound, #endif #ifdef POSITIONBAR Gem_update_positionbar, #endif Gem_print_glyph, Gem_raw_print, Gem_raw_print_bold, Gem_nhgetch, Gem_nh_poskey, Gem_nhbell, Gem_doprev_message, Gem_yn_function, Gem_getlin, Gem_get_ext_cmd, Gem_number_pad, Gem_delay_output, #ifdef CHANGE_COLOR /* the Mac uses a palette device */ Gem_change_color, #ifdef MAC Gem_change_background, Gem_set_font_name, #endif Gem_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ Gem_start_screen, Gem_end_screen, Gem_outrip, Gem_preference_update }; #ifdef MAC void * Gem_change_background(dummy) int dummy; {} short * Gem_set_font_name(foo,bar) winid foo; char *bar; {} #endif /*************************** Proceduren *************************************/ int mar_hp_query(void){ if(Upolyd) return(u.mh ? u.mhmax/u.mh : -1); return(u.uhp ? u.uhpmax/u.uhp : -1); } int mar_iflags_numpad() { return(iflags.num_pad ? 1 : 0); } int mar_get_msg_history() { return(iflags.msg_history); } int mar_get_msg_visible() { return(iflags.wc_vary_msgcount); } /* clean up and quit */ static void bail(mesg) const char *mesg; { clearlocks(); Gem_exit_nhwindows(mesg); terminate(EXIT_SUCCESS); /*NOTREACHED*/ } /*$$$*/ #define DEF_CLIPAROUND_MARGIN -1 #ifndef TILE_X #define TILE_X 16 #endif #define TILE_Y 16 #define TILES_PER_LINE 20 #define NHFONT_DEFAULT_SIZE 10 #define NHFONT_SIZE_MIN 3 #define NHFONT_SIZE_MAX 20 /*$$$*/ /*ARGSUSED*/ void Gem_init_nhwindows(argcp,argv) int* argcp; char** argv; { argv=argv, argcp=argcp; colors_changed=TRUE; set_wc_option_mod_status( WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_TILE_WIDTH | WC_TILE_HEIGHT | WC_TILE_FILE, DISP_IN_GAME); set_wc_option_mod_status( WC_HILITE_PET | WC_SCROLL_MARGIN | WC_FONT_MESSAGE | WC_FONT_MAP | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_MAP | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT, SET_IN_GAME ); if( iflags.wc_align_message==0 ) iflags.wc_align_message = ALIGN_TOP; if( iflags.wc_align_status==0 ) iflags.wc_align_status = ALIGN_BOTTOM; if( iflags.wc_scroll_margin==0 ) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN; if( iflags.wc_tile_width==0 ) iflags.wc_tile_width = TILE_X; if( iflags.wc_tile_height==0 ) iflags.wc_tile_height = TILE_Y; if(iflags.wc_tile_file && *iflags.wc_tile_file) mar_set_tilefile(iflags.wc_tile_file); if( iflags.wc_vary_msgcount==0 ) iflags.wc_vary_msgcount = 3; mar_set_tile_mode(!iflags.wc_ascii_map); /* MAR -- 17.Mar 2002 True is tiles */ mar_set_tilex(iflags.wc_tile_width); mar_set_tiley(iflags.wc_tile_height); mar_set_msg_align(iflags.wc_align_message-ALIGN_BOTTOM); mar_set_status_align(iflags.wc_align_status-ALIGN_BOTTOM); if(mar_gem_init()==0){ bail((char *)0); /*NOTREACHED*/ } iflags.window_inited = TRUE; CO=80; /* MAR -- whatsoever */ LI=25; add_menu_cmd_alias(' ', MENU_NEXT_PAGE); mar_set_no_glyph(NO_GLYPH); } void Gem_player_selection() { int i, k, n; char pick4u = 'n', pbuf[QBUFSZ], lastch=0, currch; winid win; anything any; menu_item *selected=NULL; /* avoid unnecessary prompts further down */ rigid_role_checks(); /* Should we randomly pick for the player? */ if (!flags.randomall && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) { /* pick4u = yn_function("Shall I pick a character for you? [ynq]",ynqchars,'n');*/ pick4u = yn_function( build_plselection_prompt(pbuf, QBUFSZ, flags.initrole,flags.initrace, flags.initgend, flags.initalign) ,ynqchars,'n' ); if(pick4u=='q'){ give_up: /* Just quit */ if (selected) free((genericptr_t) selected); bail((char *)0); /*NOTREACHED*/ return; } } /* Select a role, if necessary */ if (flags.initrole < 0) { /* Process the choice */ if(pick4u=='y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { mar_add_message("Incompatible role!"); mar_display_nhwindow(WIN_MESSAGE); flags.initrole = randrole(); } }else{ /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ currch = lowc(roles[i].name.m[0]); if(currch == lastch) currch = highc(currch); add_menu(win, roles[i].malenum, &any, currch, 0, ATR_NONE, an(roles[i].name.m), MENU_UNSELECTED); lastch = currch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole()+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); end_menu(win, "Pick a role"); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { mar_add_message("Incompatible race!"); mar_display_nhwindow(WIN_MESSAGE); flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", roles[flags.initrole].name.m); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { mar_add_message("Incompatible gender!"); mar_display_nhwindow(WIN_MESSAGE); flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s %s", races[flags.initrace].adj, roles[flags.initrole].name.m); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { mar_add_message("Incompatible alignment!"); mar_display_nhwindow(WIN_MESSAGE); flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s %s %s", genders[flags.initgend].adj, races[flags.initrace].adj, (flags.initgend && roles[flags.initrole].name.f) ? roles[flags.initrole].name.f : roles[flags.initrole].name.m); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ return; } /* * plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. * It may still contain a suffix denoting pl_character. * Always called after init_nhwindows() and before display_gamewindows(). */ void Gem_askname() { strncpy(plname,mar_ask_name(),PL_NSIZ); } void Gem_get_nh_event() {} void Gem_suspend_nhwindows(str) const char *str; { const char *foo; foo=str; /* MAR -- And the compiler whines no more ... */ } void Gem_resume_nhwindows() {} void Gem_end_screen() {} void Gem_start_screen() {} extern void mar_exit_nhwindows(void); extern boolean run_from_desktop; void Gem_exit_nhwindows(str) const char *str; { if(str) Gem_raw_print(str); mar_exit_nhwindows(); if(flags.toptenwin) run_from_desktop=FALSE; iflags.window_inited = 0; } winid Gem_create_nhwindow(type) int type; { winid newid; switch(type) { case NHW_MESSAGE: if(iflags.msg_history < 20) iflags.msg_history = 20; else if(iflags.msg_history > 60) iflags.msg_history = 60; break; case NHW_STATUS: case NHW_MAP: case NHW_MENU: case NHW_TEXT: break; default: panic("Tried to create window type %d\n", (int) type); return WIN_ERR; } newid=mar_create_window(type); if(newid == MAXWIN) { panic("No window slots!"); /* NOTREACHED */ } return newid; } void Gem_nhbell() { if (flags.silent) return; putchar('\007'); fflush(stdout); } extern void mar_clear_map(void); void Gem_clear_nhwindow(window) winid window; { if(window == WIN_ERR) panic(winpanicstr, window); switch(mar_hol_win_type(window)) { case NHW_MESSAGE: mar_clear_messagewin(); break; case NHW_MAP: mar_clear_map(); break; case NHW_STATUS: case NHW_MENU: case NHW_TEXT: break; } } extern void mar_more(void); /*ARGSUSED*/ void Gem_display_nhwindow(window, blocking) winid window; boolean blocking; { if(window == WIN_ERR) panic(winpanicstr, window); mar_display_nhwindow(window); switch(mar_hol_win_type(window)){ case NHW_MESSAGE: if(blocking) mar_more(); break; case NHW_MAP: if(blocking) Gem_display_nhwindow(WIN_MESSAGE, TRUE); break; case NHW_STATUS: case NHW_TEXT: case NHW_MENU: default: break; } } void Gem_destroy_nhwindow(window) winid window; { if(window == WIN_ERR) /* MAR -- test existence */ panic(winpanicstr, window); mar_destroy_nhwindow(window); } extern void mar_curs(int,int); /* mar_curs is only for map */ void Gem_curs(window, x, y) winid window; register int x, y; { if(window == WIN_ERR) /* MAR -- test existence */ panic(winpanicstr, window); if(window==WIN_MAP) mar_curs(x-1,y); /*$$$*/ else if(window==WIN_STATUS) curr_status_line=y; } extern void mar_add_status_str(const char *, int); extern void mar_putstr_text(winid, int, const char *); void Gem_putstr(window, attr, str) winid window; int attr; const char *str; { int win_type; if(window == WIN_ERR) { Gem_raw_print(str); return; } if(str == (const char*)0) return; switch((win_type=mar_hol_win_type(window))) { case NHW_MESSAGE: mar_add_message(str); break; case NHW_STATUS: mar_status_dirty(); mar_add_status_str(str,curr_status_line); if(curr_status_line) mar_display_nhwindow(WIN_STATUS); break; case NHW_MAP: if(strcmp(str,".")) Gem_putstr(WIN_MESSAGE,0,str); else mar_map_curs_weiter(); mar_display_nhwindow(WIN_MESSAGE); mar_display_nhwindow(WIN_STATUS); break; case NHW_MENU: mar_change_menu_2_text(window); /* Fallthru */ case NHW_TEXT: mar_putstr_text(window,attr,str); break; } /* endswitch win_type */ } void Gem_display_file(fname, complain) const char *fname; boolean complain; { dlb *f; char buf[BUFSZ]; char *cr; f = dlb_fopen(fname, "r"); if (!f) { if(complain) pline("Cannot open \"%s\".", fname); } else { winid datawin; datawin = Gem_create_nhwindow(NHW_TEXT); while (dlb_fgets(buf, BUFSZ, f)) { if ((cr = index(buf, '\n')) != 0) *cr = 0; if (index(buf, '\t') != 0) (void) tabexpand(buf); Gem_putstr(datawin, 0, buf); } (void) dlb_fclose(f); Gem_display_nhwindow(datawin, FALSE); Gem_destroy_nhwindow(datawin); } } /*ARGSUSED*/ /* * Add a menu item to the beginning of the menu list. This list is reversed * later. */ void Gem_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) winid window; /* window to use, must be of type NHW_MENU */ int glyph; /* glyph to display with item (unused) */ const anything *identifier; /* what to return if selected */ char ch; /* keyboard accelerator (0 = pick our own) */ char gch; /* group accelerator (0 = no group) */ int attr; /* attribute for string (like Gem_putstr()) */ const char *str; /* menu string */ boolean preselected; /* item is marked as selected */ { Gem_menu_item *G_item; const char *newstr; char buf[QBUFSZ]; if (str == (const char*) 0) return; if (window == WIN_ERR) /* MAR -- test existence */ panic(winpanicstr, window); if (identifier->a_void) Sprintf(buf, "%c - %s", ch ? ch : '?', str); else Sprintf(buf, "%s", str); newstr = buf; G_item = (Gem_menu_item *) alloc(sizeof(Gem_menu_item)); G_item->Gmi_identifier = (long)identifier->a_void; G_item->Gmi_glyph = glyph!=NO_GLYPH ? glyph2tile[glyph] : NO_GLYPH; G_item->Gmi_count = -1L; G_item->Gmi_selected = preselected ? 1 : 0; G_item->Gmi_accelerator = ch; G_item->Gmi_groupacc = gch; G_item->Gmi_attr = attr; G_item->Gmi_str = copy_of(newstr); mar_add_menu(window, G_item); } /* * End a menu in this window, window must a type NHW_MENU. * We assign the keyboard accelerators as needed. */ void Gem_end_menu(window, prompt) winid window; /* menu to use */ const char *prompt; /* prompt to for menu */ { if(window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU) panic(winpanicstr, window); /* Reverse the list so that items are in correct order. */ mar_reverse_menu(); /* Put the prompt at the beginning of the menu. */ mar_set_menu_title(prompt); mar_set_accelerators(); } int Gem_select_menu(window, how, menu_list) winid window; int how; menu_item **menu_list; { Gem_menu_item *Gmit; menu_item *mi; int n; if(window == WIN_ERR || mar_hol_win_type(window) != NHW_MENU) panic(winpanicstr, window); *menu_list = (menu_item *) 0; mar_set_menu_type(how); Gem_display_nhwindow(window, TRUE); for (n = 0, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next) if (Gmit->Gmi_selected) n++; if (n > 0) { *menu_list = (menu_item *) alloc(n * sizeof(menu_item)); for (mi = *menu_list, Gmit = mar_hol_inv(); Gmit; Gmit = Gmit->Gmi_next) if (Gmit->Gmi_selected) { mi->item = (anything)(genericptr_t)Gmit->Gmi_identifier; mi->count = Gmit->Gmi_count; mi++; } } return n; } void Gem_update_inventory() {} void Gem_mark_synch() { mar_display_nhwindow(WIN_MESSAGE); mar_display_nhwindow(WIN_MAP); mar_display_nhwindow(WIN_STATUS); } void Gem_wait_synch() { mar_display_nhwindow(WIN_MESSAGE); mar_display_nhwindow(WIN_MAP); mar_display_nhwindow(WIN_STATUS); } #ifdef CLIPPING extern void mar_cliparound(void); void Gem_cliparound(x, y) int x, y; { mar_curs(x-1,y); mar_cliparound(); } #endif /* CLIPPING */ /* * Gem_print_glyph * * Print the glyph to the output device. Don't flush the output device. * * Since this is only called from show_glyph(), it is assumed that the * position and glyph are always correct (checked there)! */ void mar_print_gl_char(winid,xchar,xchar,int); #ifdef REINCARNATION extern int mar_set_rogue(int); #endif extern void mar_add_pet_sign(winid,int,int); void Gem_print_glyph(window, x, y, glyph) winid window; xchar x, y; int glyph; { /* Move the cursor. */ Gem_curs(window, x,y); # ifdef REINCARNATION mar_set_rogue(Is_rogue_level(&u.uz) ? TRUE : FALSE); # endif x--; /* MAR -- because x ranges from 1 to COLNO */ if(mar_set_tile_mode(-1)){ mar_print_glyph(window,x,y,glyph2tile[glyph]); if( #ifdef TEXTCOLOR iflags.hilite_pet && #endif glyph_is_pet(glyph) ) mar_add_pet_sign(window,x,y); }else mar_print_gl_char(window,x,y,glyph); } void mar_print_char(winid,xchar,xchar,char,int); void mar_print_gl_char(window, x, y, glyph) winid window; xchar x, y; int glyph; { int ch; int color; unsigned special; /* map glyph to character and color */ mapglyph(glyph, &ch, &color, &special, x, y); #ifdef TEXTCOLOR /* Turn off color if rogue level. */ # ifdef REINCARNATION if (Is_rogue_level(&u.uz)) color = NO_COLOR; # endif #endif /* TEXTCOLOR */ mar_print_char(window,x,y,ch,color); } extern void mar_raw_print(const char *); extern void mar_raw_print_bold(const char *); void Gem_raw_print(str) const char *str; { if(str && *str){ if(iflags.window_inited) mar_raw_print(str); else printf("%s\n",str); } } void Gem_raw_print_bold(str) const char *str; { if(str && *str){ if(iflags.window_inited) mar_raw_print_bold(str); else printf("%s\n",str); } } extern void mar_update_value(void); /* wingem1.c */ int Gem_nhgetch() { int i; mar_update_value(); i = tgetch(); if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ return i; } /* Get a extended command in windowport specific way. returns index of the ext_cmd or -1. called after '#'. It's a menu with all the possibilities. */ int Gem_get_ext_cmd() { winid wind; int i, count, what,too_much=FALSE; menu_item *selected=NULL; anything any; char accelerator=0, tmp_acc=0; const char *ptr; wind=Gem_create_nhwindow(NHW_MENU); Gem_start_menu(wind); for(i=0;(ptr=extcmdlist[i].ef_txt);i++){ any.a_int=i; accelerator=*ptr; if(tmp_acc==accelerator){ if(too_much) accelerator='&'; /* MAR -- poor choice, anyone? */ else accelerator+='A'-'a'; too_much=TRUE; }else too_much=FALSE; tmp_acc=*ptr; Gem_add_menu(wind,NO_GLYPH,&any,accelerator,0,ATR_NONE,ptr,FALSE); } Gem_end_menu(wind,"What extended command?"); count=Gem_select_menu(wind,PICK_ONE,&selected); what = count ? selected->item.a_int : -1; if(selected) free(selected); Gem_destroy_nhwindow(wind); return(what); } void Gem_number_pad(state) int state; { state=state; } void win_Gem_init() {} #ifdef POSITIONBAR void Gem_update_positionbar(posbar) char *posbar; {} #endif /** Gem_outrip **/ void mar_set_text_to_rip(winid); char** rip_line=0; extern const char *killed_by_prefix[]; void Gem_outrip(w, how) winid w; int how; { /* Code from X11 windowport */ #define STONE_LINE_LEN 15 /* # chars that fit on one line */ #define NAME_LINE 0 /* line # for player name */ #define GOLD_LINE 1 /* line # for amount of gold */ #define DEATH_LINE 2 /* line # for death description */ #define YEAR_LINE 6 /* line # for year */ char buf[BUFSZ]; char *dpx; int line; if (!rip_line) { int i; rip_line= (char **)malloc((YEAR_LINE+1)*sizeof(char *)); for (i=0; i STONE_LINE_LEN) { for(i = STONE_LINE_LEN; ((i0 > STONE_LINE_LEN) && i); i--) if(dpx[i] == ' ') i0 = i; if(!i) i0 = STONE_LINE_LEN; } tmpchar = dpx[i0]; dpx[i0] = 0; strcpy(rip_line[line], dpx); if (tmpchar != ' ') { dpx[i0] = tmpchar; dpx= &dpx[i0]; } else dpx= &dpx[i0+1]; } /* Put year on stone */ Sprintf(rip_line[YEAR_LINE], "%4d", getyear()); mar_set_text_to_rip(w); for(line=0;line<13;line++) putstr(w, 0, ""); } void mar_get_font(type,p_fname,psize) int type; char **p_fname; int *psize; { switch(type){ case NHW_MESSAGE: *p_fname=iflags.wc_font_message; *psize=iflags.wc_fontsiz_message; break; case NHW_MAP: *p_fname=iflags.wc_font_map; *psize=iflags.wc_fontsiz_map; break; case NHW_STATUS: *p_fname=iflags.wc_font_status; *psize=iflags.wc_fontsiz_status; break; case NHW_MENU: *p_fname=iflags.wc_font_menu; *psize=iflags.wc_fontsiz_menu; break; case NHW_TEXT: *p_fname=iflags.wc_font_text; *psize=iflags.wc_fontsiz_text; break; default: break; } } void Gem_preference_update(pref) const char *pref; { if( stricmp( pref, "font_message")==0 || stricmp( pref, "font_size_message")==0 ) { if( iflags.wc_fontsiz_messageNHFONT_SIZE_MAX ) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_MESSAGE,iflags.wc_font_message,iflags.wc_fontsiz_message); return; } if( stricmp( pref, "font_map")==0 || stricmp( pref, "font_size_map")==0 ) { if( iflags.wc_fontsiz_mapNHFONT_SIZE_MAX ) iflags.wc_fontsiz_map = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_MAP,iflags.wc_font_map,iflags.wc_fontsiz_map); return; } if( stricmp( pref, "font_status")==0 || stricmp( pref, "font_size_status")==0 ) { if( iflags.wc_fontsiz_statusNHFONT_SIZE_MAX ) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_STATUS,iflags.wc_font_status,iflags.wc_fontsiz_status); return; } if( stricmp( pref, "font_menu")==0 || stricmp( pref, "font_size_menu")==0 ) { if( iflags.wc_fontsiz_menuNHFONT_SIZE_MAX ) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_MENU,iflags.wc_font_menu,iflags.wc_fontsiz_menu); return; } if( stricmp( pref, "font_text")==0 || stricmp( pref, "font_size_text")==0 ) { if( iflags.wc_fontsiz_textNHFONT_SIZE_MAX ) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; mar_set_font(NHW_TEXT,iflags.wc_font_text,iflags.wc_fontsiz_text); return; } if( stricmp( pref, "scroll_margin")==0 ) { mar_set_margin(iflags.wc_scroll_margin); Gem_cliparound(u.ux, u.uy); return; } if( stricmp( pref, "ascii_map")==0 ) { mar_set_tile_mode(!iflags.wc_ascii_map); doredraw(); return; } if( stricmp( pref, "hilite_pet")==0 ){ /* MAR -- works without doing something here. */ return; } if( stricmp( pref, "align_message")==0){ mar_set_msg_align(iflags.wc_align_message-ALIGN_BOTTOM); return; } if(stricmp( pref, "align_status")==0 ){ mar_set_status_align(iflags.wc_align_status-ALIGN_BOTTOM); return; } if( stricmp( pref, "vary_msgcount")==0 ){ mar_set_msg_visible(iflags.wc_vary_msgcount); return; } } /* * Allocate a copy of the given string. If null, return a string of * zero length. * * This is an exact duplicate of copy_of() in X11/winmenu.c. */ static char * copy_of(s) const char *s; { if (!s) s = nullstr; return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s); } #endif /* GEM_GRAPHICS /*wingem.c*/ nethack-3.4.3/win/gem/wingem1.c0100644000000000000000000022550507764735042014744 0ustar rootroot/* SCCS Id: @(#)wingem1.c 3.4 1999/12/10 */ /* Copyright (c) Christian Bressler 1999 */ /* NetHack may be freely redistributed. See license for details. */ #define __TCC_COMPAT__ #include #include #include #include #include #include #include #include "gem_rsc.h" #include "load_img.h" #include "gr_rect.h" #define genericptr_t void * typedef signed char schar; #include "wintype.h" #undef genericptr_t #define NDECL(f) f(void) #define FDECL(f,p) f p #define CHAR_P char #define SCHAR_P schar #define UCHAR_P uchar #define XCHAR_P xchar #define SHORT_P short #define BOOLEAN_P boolean #define ALIGNTYP_P aligntyp typedef signed char xchar; #include "wingem.h" #undef CHAR_P #undef SCHAR_P #undef UCHAR_P #undef XCHAR_P #undef SHORT_P #undef BOOLEAN_P #undef ALIGNTYP_P #undef NDECL #undef FDECL static char nullstr[]="", md[]="NetHack 3.4.3", strCancel[]="Cancel", strOk[]="Ok", strText[]="Text"; extern winid WIN_MESSAGE, WIN_MAP, WIN_STATUS, WIN_INVEN; #define MAXWIN 20 #define ROWNO 21 #define COLNO 80 #define MSGLEN 100 #define MAP_GADGETS NAME|MOVER|CLOSER|FULLER|LFARROW|RTARROW|UPARROW|DNARROW|VSLIDE|HSLIDE|SIZER|SMALLER #define DIALOG_MODE AUTO_DIAL|MODAL|NO_ICONIFY /* * Keyboard translation tables. */ #define C(c) (0x1f & (c)) #define M(c) (0x80 | (c)) #define KEYPADLO 0x61 #define KEYPADHI 0x71 #define PADKEYS (KEYPADHI - KEYPADLO + 1) #define iskeypad(x) (KEYPADLO <= (x) && (x) <= KEYPADHI) /* * Keypad keys are translated to the normal values below. * When iflags.BIOS is active, shifted keypad keys are translated to the * shift values below. */ static const struct pad { char normal, shift, cntrl; } keypad[PADKEYS] = { {C('['), 'Q', C('[')}, /* UNDO */ {'?', '/', '?'}, /* HELP */ {'(', 'a', '('}, /* ( */ {')', 'w', ')'}, /* ) */ {'/', '/', '/'}, /* / */ {C('p'), '$', C('p')}, /* * */ {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'h', 'H', C('h')}, /* 4 */ {'.', '.', '.'}, {'l', 'L', C('l')}, /* 6 */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }, numpad[PADKEYS] = { {C('['), 'Q', C('[')} , /* UNDO */ {'?', '/', '?'}, /* HELP */ {'(', 'a', '('}, /* ( */ {')', 'w', ')'}, /* ) */ {'/', '/', '/'}, /* / */ {C('p'), '$', C('p')}, /* * */ {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'4', M('4'), '4'}, /* 4 */ {'.', '.', '.'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }; #define TBUFSZ 300 #define BUFSZ 256 extern int yn_number; /* from decl.c */ extern char toplines[TBUFSZ]; /* from decl.c */ extern char mapped_menu_cmds[]; /* from options.c */ extern int mar_iflags_numpad(void); /* from wingem.c */ extern void Gem_raw_print(const char *); /* from wingem.c */ extern int mar_hp_query(void); /* from wingem.c */ extern int mar_get_msg_history(void); /* from wingem.c */ extern int mar_get_msg_visible(void); /* from wingem.c */ extern void mar_get_font(int,char **,int *);/* from wingem.c */ extern int vdi2dev4[]; /* from load_img.c */ void recalc_msg_win(GRECT*); void recalc_status_win(GRECT*); void calc_std_winplace(int, GRECT *); int (*v_mtext)(int,int,int,char*); static int no_glyph; /* the int indicating there is no glyph */ IMG_header tile_image, titel_image, rip_image; MFDB Tile_bilder, Map_bild, Titel_bild, Rip_bild, Black_bild, Pet_Mark, FontCol_Bild; static int Tile_width=16, Tile_heigth=16, Tiles_per_line=20; char *Tilefile=NULL; /* pet_mark Design by Warwick Allison warwick@troll.no */ static int pet_mark_data[]={0x0000,0x3600,0x7F00,0x7F00,0x3E00,0x1C00,0x0800}; static short *normal_palette=NULL; static struct gw{ WIN *gw_window; int gw_type, gw_dirty; GRECT gw_place; } Gem_nhwindow[MAXWIN]; typedef struct { int id; int size; int cw, ch; int prop; } NHGEM_FONT; /*struct gemmapdata {*/ GRECT dirty_map_area={COLNO-1,ROWNO,0,0}; int map_cursx=0, map_cursy=0, curs_col=WHITE; int draw_cursor=TRUE, scroll_margin=-1; NHGEM_FONT map_font; SCROLL scroll_map; char **map_glyphs=NULL; dirty_rect *dr_map; /*};*/ /*struct gemstatusdata{*/ char **status_line; int Anz_status_lines, status_w, status_align=FALSE; NHGEM_FONT status_font; dirty_rect *dr_stat; /*};*/ /*struct gemmessagedata{*/ int mar_message_pause=TRUE; int mar_esc_pressed=FALSE; int messages_pro_zug=0; char **message_line; int *message_age; int msg_pos=0, msg_max=0, msg_anz=0, msg_width=0, msg_vis=3, msg_align=TRUE; NHGEM_FONT msg_font; dirty_rect *dr_msg; /*};*/ /*struct geminvdata {*/ SCROLL scroll_menu; Gem_menu_item *invent_list; int Anz_inv_lines=0, Inv_breite=16; NHGEM_FONT menu_font; int Inv_how; /*};*/ /*struct gemtextdata{*/ char **text_lines; int Anz_text_lines=0, text_width; NHGEM_FONT text_font; int use_rip=FALSE; extern char** rip_line; /*};*/ static OBJECT *zz_oblist[NHICON+1]; MITEM scroll_keys[]={ /* menu, key, state, mode, msg */ {FAIL,key(CTRLLEFT,0),K_CTRL,PAGE_LEFT,FAIL}, {FAIL,key(CTRLRIGHT,0),K_CTRL,PAGE_RIGHT,FAIL}, {FAIL,key(SCANUP,0),K_SHIFT,PAGE_UP,FAIL}, {FAIL,key(SCANDOWN,0),K_SHIFT,PAGE_DOWN,FAIL}, {FAIL,key(SCANLEFT,0),0,LINE_LEFT,FAIL}, {FAIL,key(SCANRIGHT,0),0,LINE_RIGHT,FAIL}, {FAIL,key(SCANUP,0),0,LINE_UP,FAIL}, {FAIL,key(SCANDOWN,0),0,LINE_DOWN,FAIL}, {FAIL,key(SCANLEFT,0),K_SHIFT,LINE_START,FAIL}, {FAIL,key(SCANRIGHT,0),K_SHIFT,LINE_END,FAIL}, {FAIL,key(SCANUP,0),K_CTRL,WIN_START,FAIL}, {FAIL,key(SCANDOWN,0),K_CTRL,WIN_END,FAIL}, {FAIL,key(SCANHOME,0),K_SHIFT,WIN_END,FAIL}, {FAIL,key(SCANHOME,0),0,WIN_START,FAIL} }; #define SCROLL_KEYS 14 static DIAINFO *Inv_dialog; #define null_free(ptr) free(ptr), (ptr)=NULL #define test_free(ptr) if(ptr) null_free(ptr) static char *Menu_title=NULL; void mar_display_nhwindow(winid); void mar_check_hilight_status(void){} /* to be filled :-) */ static char *mar_copy_of(const char *); extern void panic(const char *, ...); void *m_alloc(size_t amt){ void *ptr; ptr=malloc(amt); if (!ptr) panic("Memory allocation failure; cannot get %lu bytes", amt); return(ptr); } void mar_clear_messagewin(void){ int i, *ptr=message_age; if(WIN_MESSAGE==WIN_ERR) return; for(i=msg_anz;--i>=0;ptr++){ if(*ptr) Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE; *ptr=FALSE; } mar_message_pause=FALSE; mar_display_nhwindow(WIN_MESSAGE); } void clipbrd_save(void *data,int cnt,boolean append,boolean is_inv){ char path[MAX_PATH],*text,*crlf="\r\n"; long handle; int i; if (data && cnt>0 && scrp_path(path,"scrap.txt") && (handle = append ? Fopen(path,1) : Fcreate(path,0))>0){ if (append) Fseek(0L,(int) handle,SEEK_END); if(is_inv){ Gem_menu_item *it=(Gem_menu_item *)data; for(;it;it=it->Gmi_next){ text=it->Gmi_str; Fwrite((int) handle,strlen(text),text); Fwrite((int) handle,2L,crlf); } }else{ for(i=0;icurr,&frame,&z_win->curr.g_x,&z_win->curr.g_y,NULL)) window_size(z_win,&z_win->curr); else window_top(z_win); } void message_handler(int x, int y){ switch(objc_find(zz_oblist[MSGWIN],ROOT,MAX_DEPTH,x,y)){ case UPMSG: if(msg_pos>msg_vis-1){ msg_pos--; Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE; mar_display_nhwindow(WIN_MESSAGE); } Event_Timer(50,0,TRUE); break; case DNMSG: if(msg_posob_x=p_w->work.g_x+p_w->work.g_w/2-p_obj->ob_width/2; p_obj->ob_y=p_w->work.g_y+p_w->work.g_h/2-p_obj->ob_height/2; return(DIA_LASTPOS); } return(DIA_CENTERED); } /****************************** set_no_glyph *************************************/ void mar_set_no_glyph(ng) int ng; { no_glyph=ng; } void mar_set_tilefile(name) char* name; { Tilefile=name; } void mar_set_tilex(value) int value; { Min(&value,32); Max(&value,1); Tile_width=value; } void mar_set_tiley(value) int value; { Min(&value,32); Max(&value,1); Tile_heigth=value; } /****************************** userdef_draw *************************************/ void rearrange_windows(void); void mar_set_status_align(int sa){ if(status_align!=sa){ status_align=sa; rearrange_windows(); } } void mar_set_msg_align(int ma){ if(msg_align!=ma){ msg_align=ma; rearrange_windows(); } } void mar_set_msg_visible(int mv){ if(mv!=msg_vis){ Max(&mv,1); Min(&mv,min(msg_anz,20)); Min(&mv,desk.g_h/msg_font.ch/2); msg_vis=mv; rearrange_windows(); } } /* size<0 cellheight; size>0 points */ void mar_set_fontbyid(int type, int id, int size){ int chardim[4]; if(id<=0) id=ibm_font_id; if((size>-3 && size<3) || size<-20 || size>20) size=-ibm_font; /* MAR -- 17.Mar 2002 For now allow FNT_PROP only with NHW_TEXT */ if(type!=NHW_TEXT && (FontInfo(id)->type & (FNT_PROP|FNT_ASCII))) id=ibm_font_id; switch(type){ case NHW_MESSAGE: if(msg_font.size==-size && msg_font.id==id) break; msg_font.size=-size; msg_font.id=id; msg_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII); v_set_text(msg_font.id,msg_font.size,BLACK,0,0,chardim); msg_font.ch=chardim[3] ? chardim[3] : 1; msg_font.cw=chardim[2] ? chardim[2] : 1; msg_width=min(max_w/msg_font.cw-3,MSGLEN); rearrange_windows(); break; case NHW_MAP: if(map_font.size!=-size || map_font.id!=id){ MFDB mtmp; map_font.size=-size; map_font.id=id; map_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII); v_set_text(map_font.id,map_font.size,BLACK,0,0,chardim); map_font.ch=chardim[3] ? chardim[3] : 1; map_font.cw=chardim[2] ? chardim[2] : 1; mfdb(&mtmp,NULL,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes); if(mfdb_size(&mtmp)>mfdb_size(&FontCol_Bild) && mfdb_size(&mtmp)>mfdb_size(&Map_bild)){ FontCol_Bild.fd_addr=Map_bild.fd_addr=(int *)realloc(Map_bild.fd_addr,mfdb_size(&mtmp)); if(!Map_bild.fd_addr) /* FIXME -- Not really neccessary since the former space is still valid */ panic("Not enough Space for the map."); } mfdb(&FontCol_Bild,FontCol_Bild.fd_addr,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes); rearrange_windows(); } break; case NHW_STATUS: if(status_font.size==-size && status_font.id==id) break; status_font.size=-size; status_font.id=id; status_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII); v_set_text(status_font.id,status_font.size,BLACK,0,0,chardim); status_font.ch=chardim[3] ? chardim[3] : 1; status_font.cw=chardim[2] ? chardim[2] : 1; rearrange_windows(); break; case NHW_MENU: if(menu_font.size==-size && menu_font.id==id) break; menu_font.size=-size; menu_font.id=id; menu_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII); v_set_text(menu_font.id,menu_font.size,BLACK,0,0,chardim); menu_font.ch=chardim[3] ? chardim[3] : 1; menu_font.cw=chardim[2] ? chardim[2] : 1; break; case NHW_TEXT: if(text_font.size==-size && text_font.id==id) break; text_font.size=-size; text_font.id=id; text_font.prop=FontInfo(id)->type & (FNT_PROP|FNT_ASCII); v_set_text(text_font.id,text_font.size,BLACK,0,0,chardim); text_font.ch=chardim[3] ? chardim[3] : 1; text_font.cw=chardim[2] ? chardim[2] : 1; break; default: break; } } void mar_set_font(int type, const char *font_name, int size){ int id=0; /* MAR -- 17.Mar 2002 usual Gem behavior, use the Font-ID */ if(font_name && *font_name){ id=atoi(font_name); if(id<=0){ int i, tid; char name[32]; for(i=fonts_loaded;--i>=0;){ tid=vqt_name(x_handle,i,name); if(!stricmp(name,font_name)){ id=tid; break; } } } } mar_set_fontbyid(type,id,size); } void rearrange_windows(void){ GRECT area; int todo=TRUE; if(WIN_MAP != WIN_ERR && Gem_nhwindow[WIN_MAP].gw_window){ scroll_map.px_hline=mar_set_tile_mode(FAIL)?Tile_width:map_font.cw; scroll_map.px_vline=mar_set_tile_mode(FAIL)?Tile_heigth:map_font.ch; if(todo){ calc_std_winplace(FAIL,&area); todo=FALSE; } calc_std_winplace(NHW_MAP,&area); Gem_nhwindow[WIN_MAP].gw_window->max.g_w=area.g_w; Gem_nhwindow[WIN_MAP].gw_window->max.g_h=area.g_h; Gem_nhwindow[WIN_MAP].gw_window->max.g_w=area.g_w; window_reinit(Gem_nhwindow[WIN_MAP].gw_window,md,md,NULL,FALSE,FALSE); { int buf[8]; buf[3]=K_CTRL; buf[4]=C('L'); AvSendMsg(ap_id,AV_SENDKEY,buf); } } if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window){ if(todo){ calc_std_winplace(FAIL,&area); todo=FALSE; } calc_std_winplace(NHW_MESSAGE,&area); Gem_nhwindow[WIN_MESSAGE].gw_window->min_h=area.g_h; window_size(Gem_nhwindow[WIN_MESSAGE].gw_window,&area); redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window,NULL); } if(WIN_STATUS != WIN_ERR && Gem_nhwindow[WIN_STATUS].gw_window){ if(todo){ calc_std_winplace(FAIL,&area); todo=FALSE; } calc_std_winplace(NHW_STATUS,&area); Gem_nhwindow[WIN_STATUS].gw_window->min_h=area.g_h; window_size(Gem_nhwindow[WIN_STATUS].gw_window,&area); redraw_window(Gem_nhwindow[WIN_STATUS].gw_window,NULL); } } void my_color_area(GRECT *area, int col){ int pxy[4]; v_set_fill(col,1,IP_SOLID,0); rc_grect_to_array(area,pxy); v_bar(x_handle,pxy); } void my_clear_area(GRECT *area){ my_color_area(area, WHITE); } int mar_set_tile_mode(int); static void win_draw_map(int first, WIN *win, GRECT *area){ int pla[8], w=area->g_w-1, h=area->g_h-1; int i, x, y; GRECT back=*area; first=first; if(!mar_set_tile_mode(FAIL)){ int start=(area->g_x-win->work.g_x)/map_font.cw+scroll_map.hpos; int stop=(area->g_x+area->g_w+map_font.cw-1-win->work.g_x)/map_font.cw+scroll_map.hpos; int starty=(area->g_y-win->work.g_y)/map_font.ch+scroll_map.vpos; int stopy=min((area->g_y+area->g_h+map_font.ch-1-win->work.g_y)/map_font.ch+scroll_map.vpos,ROWNO); char tmp; v_set_text(map_font.id,map_font.size,WHITE,0,0,NULL); v_set_mode(MD_TRANS); x=win->work.g_x-scroll_map.px_hpos+start*map_font.cw; y=win->work.g_y-scroll_map.px_vpos+starty*map_font.ch; pla[2]=pla[0]=scroll_map.px_hpos+area->g_x-win->work.g_x; pla[3]=pla[1]=starty*map_font.ch; pla[2]+=w; pla[3]+=map_font.ch-1; pla[6]=pla[4]=area->g_x; /* x_wert to */ pla[7]=pla[5]=y; /* y_wert to */ pla[6]+=w; pla[7]+=map_font.ch-1; back.g_h=map_font.ch; for(i=starty;ig_x-win->work.g_x; pla[3]=pla[1]=scroll_map.px_vpos+area->g_y-win->work.g_y; pla[2]+=w; pla[3]+=h; pla[6]=pla[4]=area->g_x; /* x_wert to */ pla[7]=pla[5]=area->g_y; /* y_wert to */ pla[6]+=w; pla[7]+=h; vro_cpyfm(x_handle, S_ONLY, pla, &Map_bild, screen); } if(draw_cursor){ v_set_line(curs_col,1,1,0,0); pla[0]=pla[2]=win->work.g_x+scroll_map.px_hline*(map_cursx-scroll_map.hpos); pla[1]=pla[3]=win->work.g_y+scroll_map.px_vline*(map_cursy-scroll_map.vpos); pla[2]+=scroll_map.px_hline-1; pla[3]+=scroll_map.px_vline-1; v_rect(pla[0],pla[1],pla[2],pla[3]); } } static int draw_titel(PARMBLK *pb){ static int pla[8]; GRECT work=*(GRECT *) &pb->pb_x; if(rc_intersect((GRECT *)&pb->pb_xc,&work)){ pla[0]=pla[1]=0; pla[2]=pb->pb_w-1; pla[3]=pb->pb_h-1; pla[6]=pla[4]=pb->pb_x; /* x_wert to */ pla[7]=pla[5]=pb->pb_y; /* y_wert to */ pla[6]+=pb->pb_w-1; pla[7]+=pb->pb_h-1; vro_cpyfm(x_handle, S_ONLY, pla, &Titel_bild, screen); } return(0); } static int draw_lines(PARMBLK *pb){ GRECT area=*(GRECT *) &pb->pb_x; if(rc_intersect((GRECT *)&pb->pb_xc,&area)){ char **ptr; int x=pb->pb_x,y=pb->pb_y,start_line=(area.g_y-y); v_set_mode((text_font.cw&7)==0 && text_font.prop==0 ? MD_REPLACE : MD_TRANS); /* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4]) */ v_set_text(text_font.id,text_font.size,BLACK,0,0,NULL); start_line /= text_font.ch; y+=start_line*text_font.ch; x-=(int)scroll_menu.px_hpos; ptr=&text_lines[start_line+=scroll_menu.vpos]; start_line = min((area.g_y-y+area.g_h+text_font.ch-1)/text_font.ch,Anz_text_lines-start_line); area.g_h=text_font.ch; Vsync(); /* x=(x+7) & ~7;*/ for(;--start_line>=0;y+=text_font.ch){ area.g_y=y; my_clear_area(&area); if(**ptr-1){ v_set_text(FAIL,0,BLUE,0x01,0,NULL); (*v_mtext)(x_handle,x,y,(*ptr++)+1); v_set_text(FAIL,0,BLACK,0x00,0,NULL); }else (*v_mtext)(x_handle,x,y,(*ptr++)+1); } } return(0); } static int draw_rip(PARMBLK *pb){ GRECT area=*(GRECT *) &pb->pb_x; if(rc_intersect((GRECT *)&pb->pb_xc,&area)){ char **ptr; int x=pb->pb_x,y=pb->pb_y,start_line=(area.g_y-y), chardim[4], pla[8],i; v_set_mode(MD_REPLACE); /* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4]) */ v_set_text(text_font.id,text_font.size,BLACK,0,0,chardim); start_line /= text_font.ch; y+=start_line*text_font.ch; x-=scroll_menu.px_hpos; ptr=&text_lines[start_line+=scroll_menu.vpos]; start_line = min((area.g_y-y+area.g_h+text_font.ch-1)/text_font.ch,Anz_text_lines-start_line); area.g_h=text_font.ch; Vsync(); x=(x+7) & ~7; for(;--start_line>=0;y+=text_font.ch){ area.g_y=y; my_clear_area(&area); if(**ptr-1){ v_set_text(FAIL,0,BLUE,0x01,0,NULL); (*v_mtext)(x_handle,x,y,(*ptr++)+1); v_set_text(FAIL,0,BLACK,0x00,0,NULL); }else (*v_mtext)(x_handle,x,y,(*ptr++)+1); } pla[0]=pla[1]=0; pla[2]=min(pb->pb_w-1,Rip_bild.fd_w-1); pla[3]=min(pb->pb_h-1,Rip_bild.fd_h-1); pla[6]=pla[4]=pb->pb_x+(pb->pb_w-Rip_bild.fd_w)/2; /* x_wert to */ pla[7]=pla[5]=pb->pb_y; /* y_wert to */ pla[6]+=pla[2]; pla[7]+=pla[3]; vro_cpyfm(x_handle, S_ONLY, pla, &Rip_bild, screen); v_set_mode(MD_TRANS); vst_alignment(x_handle,1,5,&i,&i); pla[5]+=64; for(i=0;i<7;i++,pla[5]+=chardim[3]){ v_set_text(text_font.id,(i==0 || i==6) ? text_font.size : 12,WHITE,1,0,chardim); (*v_mtext)(x_handle,pla[4]+157,pla[5],rip_line[i]); v_set_text(text_font.id,(i==0 || i==6) ? text_font.size : 12,BLACK,0,0,chardim); (*v_mtext)(x_handle,pla[4]+157,pla[5],rip_line[i]); } vst_alignment(x_handle,0,5,&i,&i); } return(0); } static int draw_msgline(PARMBLK *pb){ GRECT area=*(GRECT *) &pb->pb_x; if(rc_intersect((GRECT *)&pb->pb_xc,&area)){ int x=pb->pb_x, y=pb->pb_y+(msg_vis-1)*msg_font.ch, foo, i; char **ptr=&message_line[msg_pos], tmp; int startx, stopx, starty, stopy; x=(x+7) & ~7; /* Byte alignment speeds output up */ v_set_mode(MD_REPLACE); /* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4]) */ v_set_text(msg_font.id,msg_font.size,FAIL, FAIL,0,NULL); vst_alignment(x_handle,0,5,&foo,&foo); stopy=min(msg_pos,msg_vis); /* Vsync();*/ startx=(area.g_x-x)/msg_font.cw-1; /* MAR 06.02.2001 -- because italic covers the next char */ Max(&startx,0); stopx=(area.g_x+area.g_w+msg_font.cw-x-1)/msg_font.cw; x+=startx*msg_font.cw; for(i=0;ipb_x; area.g_x+=2*status_font.cw-2; area.g_w-=2*status_font.cw-2; if(rc_intersect((GRECT *)&pb->pb_xc,&area)){ int x=pb->pb_x, y=pb->pb_y, startx, stopx, starty, stopy, i; char tmp; /* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4]) */ v_set_mode(MD_REPLACE); v_set_text(status_font.id,status_font.size,BLACK,0,0,NULL); x = (x+2*status_font.cw+6) & ~7; startx=(area.g_x-x)/status_font.cw; starty=(area.g_y-y)/status_font.ch; stopx=(area.g_x+area.g_w+status_font.ch-1-x)/status_font.cw; stopy=(area.g_y+area.g_h+status_font.ch-1-y)/status_font.ch; Max(&startx,0); /* MAR -- Hmm, area.g_x could end up 1 below x */ Max(&stopx,0); x+=startx*status_font.cw; y+=starty*status_font.ch; /* Vsync();*/ area.g_h=status_font.ch; for(i=starty;ipb_x; if(rc_intersect((GRECT *)&pb->pb_xc,&area)){ int gl, i, x=pb->pb_x, y=pb->pb_y,start_line=area.g_y-y; Gem_menu_item *it; v_set_mode(MD_REPLACE); v_set_text(menu_font.id,menu_font.size,BLACK,0,0,NULL); start_line /= menu_font.ch; y+=start_line*menu_font.ch; x-=scroll_menu.px_hpos; start_line+=scroll_menu.vpos; for(it=invent_list,i=start_line; --i>=0 && it; it=it->Gmi_next); i = min((area.g_y-y+area.g_h+menu_font.ch-1)/menu_font.ch,Anz_inv_lines-start_line); Vsync(); area.g_h=menu_font.ch; for(;(--i>=0) && it;it=it->Gmi_next,y+=menu_font.ch){ if(it->Gmi_attr) v_set_text(FAIL,FALSE,BLUE,1,FAIL,NULL); /* Bold */ else v_set_text(FAIL,FALSE,BLACK,0,FAIL,NULL); area.g_y=y; my_clear_area(&area); if((gl=it->Gmi_glyph) != no_glyph){ int pla[8], h=min(menu_font.ch,Tile_heigth)-1; pla[0]=pla[2]=(gl%Tiles_per_line)*Tile_width; /* x_wert from */ pla[1]=pla[3]=(gl/Tiles_per_line)*Tile_heigth; /* y_wert from */ pla[4]=pla[6]=x; /* x_wert to */ pla[5]=pla[7]=y; /* y_wert to */ pla[2]+=Tile_width-1; pla[3]+=h; pla[6]+=Tile_heigth-1; pla[7]+=h; vro_cpyfm(x_handle,S_ONLY,pla,&Tile_bilder,screen); } if(it->Gmi_identifier) it->Gmi_str[2]=it->Gmi_selected ? (it->Gmi_count == -1L ? '+' : '#') : '-'; (*v_mtext)(x_handle,(x+23) & ~7,y,it->Gmi_str); } } return(0); } static int draw_prompt(PARMBLK *pb){ GRECT area=*(GRECT *) &pb->pb_x; if(rc_intersect((GRECT *)&pb->pb_xc,&area)){ char **ptr=(char **)pb->pb_parm; int x=pb->pb_x, y=pb->pb_y, chardim[4]; /* void v_set_text(int font,int height,int color,int effect,int rotate,int out[4]) */ v_set_mode(MD_TRANS); v_set_text(ibm_font_id,ibm_font,WHITE,0,0,chardim); Vsync(); if(planes<4){ int pxy[4]; v_set_fill(BLACK,2,4,0); rc_grect_to_array(&area,pxy); v_bar(x_handle,pxy); }else my_color_area(&area,LWHITE); (*v_mtext)(x_handle,x,y,*(ptr++)); if(*ptr) (*v_mtext)(x_handle,x,y+chardim[3],*ptr); } return(0); } static USERBLK ub_lines={draw_lines, 0L}, ub_msg={draw_msgline, 0L}, ub_inventory={draw_inventory, 0L}, ub_titel={draw_titel, 0L}, ub_status={draw_status, 0L}, ub_prompt={draw_prompt, 0L}; /**************************** rsc_funktionen *****************************/ void my_close_dialog(DIAINFO *dialog,boolean shrink_box){ close_dialog(dialog,shrink_box); Event_Timer(0,0,TRUE); } void mar_get_rsc_tree(obj_number, z_ob_obj) int obj_number; OBJECT **z_ob_obj; { rsrc_gaddr( R_TREE, obj_number, z_ob_obj ); fix_objects(*z_ob_obj,SCALING,0,0); } void mar_clear_map(void); void img_error(errnumber) int errnumber; { char buf[BUFSZ]; switch(errnumber){ case ERR_HEADER : sprintf(buf,"%s","[1][ Image Header | corrupt. ][ Oops ]"); break; case ERR_ALLOC : sprintf(buf,"%s","[1][ Not enough | memory for | an image. ][ Oops ]"); break; case ERR_FILE : sprintf(buf,"%s","[1][ The Image-file | is not available ][ Oops ]"); break; case ERR_DEPACK : sprintf(buf,"%s","[1][ The Image-file | is corrupt ][ Oops ]"); break; case ERR_COLOR : sprintf(buf,"%s","[1][ Number of colors | not supported ][ Oops ]"); break; default: sprintf(buf,"[1][ img_error | strange error | number: %i ][ Hmm ]",errnumber); break; } form_alert(1,buf); } void mar_change_button_char(OBJECT *z_ob, int nr, char ch){ *ob_get_text(z_ob,nr,0)=ch; ob_set_hotkey(z_ob,nr,ch); } void mar_set_dir_keys() { static int mi_numpad=FAIL; char mcmd[]="bjnh.lyku", npcmd[]="123456789", *p_cmd; if(mi_numpad!=mar_iflags_numpad()){ OBJECT *z_ob=zz_oblist[DIRECTION]; int i; mi_numpad=mar_iflags_numpad(); ob_set_hotkey(z_ob,DIRDOWN,'>'); ob_set_hotkey(z_ob,DIRUP,'<'); p_cmd= mi_numpad ? npcmd : mcmd; for(i=0;i<9;i++) mar_change_button_char(z_ob,DIR1+2*i,p_cmd[i]); } } extern int total_tiles_used; /* tile.c */ int mar_gem_init() { int i, bild_fehler=FALSE, fsize; char *fname; static MITEM wish_workaround= {FAIL,key(0,'J'),K_CTRL,W_CYCLE,FAIL}; OBJECT *z_ob; if((i=open_rsc("gem_rsc.rsc",NULL,md,md,md,0,0,0))<=0){ graf_mouse(M_OFF,NULL); if(i<0) form_alert(1,"[3][| Fatal Error | File: GEM_RSC.RSC | not found. ][ grumble ]"); else form_alert(1,"[3][| Fatal Error | GEM initialisation | failed. ][ a pity ]"); return(0); } if(planes<1 || planes>8){ form_alert(1,"[3][ Color-depth | not supported, | try 2-256 colors. ][ Ok ]"); return(0); } MouseBee(); /* MAR -- 17.Mar 2002 NVDI 3.0 or better uses v_ftext */ v_mtext= speedo==3 ? &v_ftext : &v_gtext; for(i=0;i0 && planes<9){ normal_palette=(short *)m_alloc(3*colors*sizeof(short)); get_colors(x_handle,normal_palette, colors); } loadimg: bild_fehler=depack_img(Tilefile?Tilefile:(planes>=4)?"NH16.IMG":"NH2.IMG",&tile_image); if(bild_fehler){ z_ob=zz_oblist[ABOUT]; ob_undraw_dialog(z_ob,0,0,0,0); ob_hide(z_ob,OKABOUT,FALSE); img_error(bild_fehler); return(0); } if(tile_image.img_w%Tile_width || tile_image.img_h%Tile_heigth){ Tilefile=NULL; Tile_width=Tile_heigth=16; printf("size didn't match.\n"); goto loadimg; } if((tile_image.img_w/Tile_width)*(tile_image.img_h/Tile_heigth)=4){ if(tile_image.planes>1) img_set_colors(x_handle, tile_image.palette, tile_image.planes); #if 0 else{ int mypalette[]={}; img_set_colors(x_handle, mypalette, 4); } #endif } mfdb(&Tile_bilder, (int *)tile_image.addr, tile_image.img_w, tile_image.img_h, 1, tile_image.planes); transform_img(&Tile_bilder); mfdb(&Map_bild,NULL,(COLNO-1)*Tile_width, ROWNO*Tile_heigth, 0, planes); mfdb(&FontCol_Bild,NULL,(COLNO-1)*map_font.cw, ROWNO*map_font.ch, 0, planes); Map_bild.fd_addr=(int *)m_alloc(mfdb_size(&Map_bild)>mfdb_size(&FontCol_Bild)?mfdb_size(&Map_bild):mfdb_size(&FontCol_Bild)); FontCol_Bild.fd_addr=Map_bild.fd_addr; mfdb(&Pet_Mark,pet_mark_data,8, 7, 1, 1); vr_trnfm(x_handle,&Pet_Mark,&Pet_Mark); mfdb(&Black_bild,NULL,16, 32, 1, 1); /* MAR -- 17.Mar 2002 that should cover the biggest map-font */ Black_bild.fd_addr=(int *)m_alloc(mfdb_size(&Black_bild)); memset(Black_bild.fd_addr,255,mfdb_size(&Black_bild)); vr_trnfm(x_handle,&Black_bild,&Black_bild); for(i=0;i=0;) if(Gem_nhwindow[i].gw_type) mar_destroy_nhwindow(i); if(normal_palette){ img_set_colors(x_handle,normal_palette,tile_image.planes); null_free(normal_palette); } test_free(tile_image.palette); test_free(tile_image.addr); test_free(titel_image.palette); test_free(titel_image.addr); } /************************* mar_curs *******************************/ void mar_curs(x,y) int x, y; { Min(&dirty_map_area.g_x,x); Min(&dirty_map_area.g_y,y); Max(&dirty_map_area.g_w,x); Max(&dirty_map_area.g_h,y); Min(&dirty_map_area.g_x,map_cursx); Min(&dirty_map_area.g_y,map_cursy); Max(&dirty_map_area.g_w,map_cursx); Max(&dirty_map_area.g_h,map_cursy); map_cursx=x; map_cursy=y; if(WIN_MAP!=WIN_ERR) Gem_nhwindow[WIN_MAP].gw_dirty=TRUE; } void mar_cliparound(void); void mar_map_curs_weiter(void) { static int once=TRUE; if(once){ redraw_window(Gem_nhwindow[WIN_STATUS].gw_window,NULL); redraw_window(Gem_nhwindow[WIN_MESSAGE].gw_window,NULL); once=FALSE; } mar_curs(map_cursx+1,map_cursy); mar_cliparound(); } /************************* about *******************************/ void mar_about() { xdialog(zz_oblist[ABOUT], md, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE); Event_Timer(0,0,TRUE); } /************************* ask_name *******************************/ char * mar_ask_name() { OBJECT *z_ob=zz_oblist[NAMEGET]; int bild_fehler; char who_are_you[] = "Who are you? "; bild_fehler=depack_img(planes<4 ? "TITLE2.IMG" : "TITLE.IMG", &titel_image); if(bild_fehler ){ /* MAR -- this isn't lethal */ ob_set_text(z_ob,NETHACKPICTURE,"missing title.img."); }else{ mfdb(&Titel_bild, (int *)titel_image.addr, titel_image.img_w, titel_image.img_h, 1, titel_image.planes); transform_img(&Titel_bild); z_ob[NETHACKPICTURE].ob_type=G_USERDEF; z_ob[NETHACKPICTURE].ob_spec.userblk=&ub_titel; } ob_clear_edit(z_ob); xdialog(z_ob,who_are_you, NULL, NULL, DIA_CENTERED, FALSE, DIALOG_MODE); Event_Timer(0,0,TRUE); test_free(titel_image.palette); test_free(titel_image.addr); test_free(Titel_bild.fd_addr); return(ob_get_text(z_ob,PLNAME,0)); } /************************* more *******************************/ void send_key(int key) { int buf[8]; buf[3]=0; /* No Shift/Ctrl/Alt */ buf[4]=key; AvSendMsg(ap_id,AV_SENDKEY,buf); } void send_return() { send_key(key(SCANRET,0)); } int K_Init(xev,availiable) XEVENT *xev; int availiable; { xev=xev; return(MU_KEYBD&availiable); } int KM_Init(xev,availiable) XEVENT *xev; int availiable; { xev=xev; return((MU_KEYBD|MU_MESAG)&availiable); } int M_Init(xev,availiable) XEVENT *xev; int availiable; { xev=xev; return(MU_MESAG&availiable); } #define More_Init K_Init int More_Handler(xev) XEVENT *xev; { int ev=xev->ev_mwich; if(ev&MU_KEYBD){ char ch=(char)(xev->ev_mkreturn&0x00FF); DIAINFO *dinf; WIN *w; switch(ch){ case '\033': /* no more more more */ case ' ': if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[PAGER]){ if(ch=='\033') mar_esc_pressed=TRUE; send_return(); break; } /* Fall thru */ default: ev &= ~MU_KEYBD; /* unknown key */ break; } } return(ev); } void mar_more() { if(!mar_esc_pressed){ OBJECT *z_ob=zz_oblist[PAGER]; WIN *p_w; Event_Handler(More_Init,More_Handler); dial_colors(7,RED,BLACK,RED,RED,BLACK,BLACK,BLACK,BLACK,WHITE,WHITE,WHITE,WHITE,TRUE,TRUE); if(WIN_MESSAGE!=WIN_ERR && (p_w=Gem_nhwindow[WIN_MESSAGE].gw_window)){ z_ob->ob_x=p_w->work.g_x; z_ob->ob_y=p_w->curr.g_y+p_w->curr.g_h+gr_ch; } xdialog(z_ob,NULL, NULL, NULL, DIA_LASTPOS, FALSE, DIALOG_MODE); Event_Timer(0,0,TRUE); Event_Handler(NULL,NULL); if(planes<4) dial_colors(4,BLACK,WHITE,RED,RED,WHITE,BLACK,BLACK,BLACK,FAIL,FAIL,FAIL,FAIL,TRUE,TRUE); else dial_colors(7,LWHITE,BLACK,RED,RED,BLACK,BLACK,BLACK,BLACK,WHITE,WHITE,WHITE,WHITE,TRUE,TRUE); } } /************************* Gem_start_menu *******************************/ void Gem_start_menu(win) winid win; { win=win; if(invent_list){ Gem_menu_item *curr, *next; for(curr=invent_list;curr;curr=next){ next=curr->Gmi_next; free(curr->Gmi_str); free(curr); } } invent_list=NULL; Anz_inv_lines=0; Inv_breite=16; } /************************* mar_add_menu *******************************/ void mar_add_menu(win, item) winid win; Gem_menu_item *item; { win=win; item->Gmi_next = invent_list; invent_list = item; Anz_inv_lines++; } void mar_reverse_menu() { Gem_menu_item *next, *head = 0, *curr=invent_list; while (curr) { next = curr->Gmi_next; curr->Gmi_next = head; head = curr; curr = next; } invent_list=head; } void mar_set_accelerators() { char ch='a'; Gem_menu_item *curr; for(curr=invent_list;curr;curr=curr->Gmi_next){ int extent[8]; v_set_text(menu_font.id,menu_font.size,BLACK,0,0,NULL); vqt_extent(x_handle,curr->Gmi_str,extent); Max(&Inv_breite,extent[4]+Tile_width+menu_font.cw); if(ch && curr->Gmi_accelerator==0 && curr->Gmi_identifier){ curr->Gmi_accelerator=ch; curr->Gmi_str[0]=ch; if(ch=='z') ch='A'; else if(ch=='Z') ch=0; else ch++; } } } Gem_menu_item * mar_hol_inv() { return(invent_list); } /************************* mar_putstr_text *********************/ void mar_raw_print(const char *); void mar_set_text_to_rip(winid w){ use_rip=TRUE; } void mar_putstr_text(winid window, int attr, const char *str) { static int zeilen_frei=0; int breite; char *ptr; window=window; if(!text_lines){ text_lines=(char **)m_alloc(12*sizeof(char *)); zeilen_frei=12; } if(!zeilen_frei){ text_lines=(char **)realloc(text_lines,(Anz_text_lines+12)*sizeof(char *)); zeilen_frei=12; } if(!text_lines){ mar_raw_print("No room for Text"); return; } if(str) breite=strlen(str); Min(&breite,80); ptr=text_lines[Anz_text_lines]=(char *)m_alloc(breite*sizeof(char)+2); *ptr=(char)(attr+1); /* avoid 0 */ strncpy(ptr+1,str,breite); ptr[breite+1]=0; Anz_text_lines++; zeilen_frei--; } int mar_set_inv_win(Anzahl, Breite) int Anzahl, Breite; { OBJECT *z_ob=zz_oblist[LINES]; int retval=WIN_DIAL|MODAL|NO_ICONIFY; scroll_menu.hsize=0; scroll_menu.vpage= (desk.g_h-3*gr_ch)/scroll_menu.px_vline; if(Anzahl>scroll_menu.vpage){ retval |= WD_VSLIDER; if(Breite>max_w-3*scroll_menu.px_hline){ retval|=WD_HSLIDER; scroll_menu.hpage=(max_w-3*scroll_menu.px_hline)/scroll_menu.px_hline; scroll_menu.hpos=0; scroll_menu.hsize=Breite/scroll_menu.px_hline; scroll_menu.vpage=(desk.g_h-4*gr_ch-1)/scroll_menu.px_vline; } Anzahl=scroll_menu.vpage; }else{ if(Breite>max_w-scroll_menu.px_hline){ retval|=WD_HSLIDER; scroll_menu.hpage=(max_w-scroll_menu.px_hline)/scroll_menu.px_hline; scroll_menu.hpos=0; scroll_menu.hsize=Breite/scroll_menu.px_hline; scroll_menu.vpage= (desk.g_h-4*gr_ch-1)/scroll_menu.px_vline; if(Anzahl>scroll_menu.vpage){ retval |= WD_VSLIDER; Anzahl=scroll_menu.vpage; } } scroll_menu.vpage=Anzahl; } if((scroll_menu.hmax=scroll_menu.hsize-scroll_menu.hpage)<0) scroll_menu.hmax=0; if((scroll_menu.vmax=scroll_menu.vsize-scroll_menu.vpage)<0) scroll_menu.vmax=0; /* left/right/up 2 pixel border down 2gr_ch toolbar */ z_ob[ROOT].ob_width=z_ob[LINESLIST].ob_width=Breite; z_ob[ROOT].ob_height= z_ob[QLINE].ob_y= z_ob[LINESLIST].ob_height=scroll_menu.px_vline*Anzahl; z_ob[QLINE].ob_y+=gr_ch/2; z_ob[ROOT].ob_width+=4; z_ob[ROOT].ob_height+=2*gr_ch+2; return(retval); } /************************* mar_status_dirty *******************************/ void mar_status_dirty() { int ccol; ccol=mar_hp_query(); if(ccol<2) curs_col=WHITE; /* 50-100% : 0 */ else if(ccol<3) curs_col=YELLOW; /* 33-50% : 6 */ else if(ccol<5) curs_col=LYELLOW; /* 20-33% : 14*/ else if(ccol<10) curs_col=RED; /* 10-20% : 2 */ else curs_col=MAGENTA; /* <10% : 7*/ } /************************* mar_add_message *******************************/ void mar_add_message(str) const char *str; { int i, mesg_hist=mar_get_msg_history(); char *tmp, *rest, buf[TBUFSZ]; if(WIN_MESSAGE == WIN_ERR) return; if(!mar_message_pause){ mar_message_pause=TRUE; messages_pro_zug=0; msg_pos=msg_max; } if(msg_max>mesg_hist-2){ msg_max=mesg_hist-2; msg_pos--; if(msg_pos<0) msg_pos=0; tmp=message_line[0]; for(i=0;i=msg_width){ int pos=msg_width; tmp=toplines+msg_width; while(*tmp!=' ' && pos>=0){ tmp--; pos--; } if(pos<=0) pos=msg_width; /* Mar -- Oops, what a word :-) */ message_age[msg_max]=TRUE; strncpy(message_line[msg_max],toplines,pos); message_line[msg_max][pos]=0; rest=strcpy(buf,toplines+pos); }else{ message_age[msg_max]=TRUE; strncpy(message_line[msg_max],toplines,msg_width); rest=0; } Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE; if(messages_pro_zug>=mesg_hist){ /* MAR -- Greater then should never happen */ messages_pro_zug=mesg_hist; mar_display_nhwindow(WIN_MESSAGE); } if(rest) mar_add_message(rest); } /************************* mar_add_status_str *******************************/ void mar_add_status_str(str,line) const char *str; int line; { int i,last_diff=-1; GRECT area={0,line*status_font.ch,status_font.cw,status_font.ch}; for(i=0;(i=0){ add_dirty_rect(dr_stat,&area); last_diff=-1; area.g_w=status_font.cw; } for(;i=0) add_dirty_rect(dr_stat,&area); } /************************* mar_set_menu_title *******************************/ void mar_set_menu_title(str) const char *str; { test_free(Menu_title); /* just in case */ Menu_title=mar_copy_of(str ? str : nullstr); } /************************* mar_set_menu_type *******************************/ void mar_set_menu_type(how) int how; { Inv_how=how; } /************************* Inventory Utils *******************************/ void set_all_on_page(start, page) int start, page; { Gem_menu_item *curr; if(start<0 || page<0) return; for(curr=invent_list; start--&&curr; curr=curr->Gmi_next); for(; page--&&curr; curr=curr->Gmi_next) if (curr->Gmi_identifier && !curr->Gmi_selected) curr->Gmi_selected = TRUE; } void unset_all_on_page(start, page) int start, page; { Gem_menu_item *curr; if(start<0 || page<0) return; for(curr=invent_list; start--&&curr; curr=curr->Gmi_next); for(; page--&&curr; curr=curr->Gmi_next) if (curr->Gmi_identifier && curr->Gmi_selected) { curr->Gmi_selected = FALSE; curr->Gmi_count = -1L; } } void invert_all_on_page(start, page, acc) int start, page; char acc; { Gem_menu_item *curr; if(start<0 || page<0) return; for(curr=invent_list; start--&&curr; curr=curr->Gmi_next); for(; page--&&curr; curr=curr->Gmi_next) if (curr->Gmi_identifier && (acc == 0 || curr->Gmi_groupacc == acc)) { if (curr->Gmi_selected) { curr->Gmi_selected = FALSE; curr->Gmi_count = -1L; } else curr->Gmi_selected = TRUE; } } /************************* Inv_Handler and Inv_Init *******************************/ int scroll_top_dialog(char ch){ WIN *w; DIAINFO *dinf; if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[LINES]){ switch(ch){ case ' ': if(scroll_menu.vpos==scroll_menu.vmax){ send_return(); break; } /* Fall thru */ case MENU_NEXT_PAGE: scroll_window(w,PAGE_DOWN,NULL); break; case MENU_PREVIOUS_PAGE: scroll_window(w,PAGE_UP,NULL); break; case MENU_FIRST_PAGE: scroll_window(w,WIN_START,NULL); break; case MENU_LAST_PAGE: scroll_window(w,WIN_END,NULL); break; default: return(FALSE); } return(TRUE); } return(FALSE); } #define Text_Init KM_Init int Text_Handler(xev) XEVENT *xev; { int ev=xev->ev_mwich; if(ev&MU_MESAG){ int *buf=xev->ev_mmgpbuf, y_wo, i; if(*buf==FONT_CHANGED){ if(buf[3]>=0){ mar_set_fontbyid(NHW_TEXT,buf[4],buf[5]); FontAck(buf[1],1); } } } if(ev&MU_KEYBD){ char ch=(char)(xev->ev_mkreturn&0x00FF); if(!scroll_top_dialog(ch)) switch(ch){ case '\033': send_return(); /* just closes the textwin */ break; case C('c'): clipbrd_save(text_lines,Anz_text_lines,xev->ev_mmokstate&K_SHIFT,FALSE); break; default: ev &= ~MU_KEYBD; /* unknown key */ break; } } return(ev); } #define Inv_Init KM_Init static long count=0; int Inv_Handler(xev) XEVENT *xev; { int ev=xev->ev_mwich; Gem_menu_item *it; GRECT area; OBJECT *z_ob=zz_oblist[LINES]; ob_pos(z_ob,LINESLIST,&area); if(ev&MU_MESAG){ int *buf=xev->ev_mmgpbuf, y_wo, i; if(*buf==FONT_CHANGED){ if(buf[3]>=0){ mar_set_fontbyid(NHW_MENU,buf[4],buf[5]); FontAck(buf[1],1); } }else if(*buf==OBJC_CHANGED && buf[3]==LINESLIST){ ob_undostate(z_ob,LINESLIST,SELECTED); mouse(NULL,&y_wo); y_wo=(y_wo-area.g_y)/menu_font.ch+scroll_menu.vpos; for(it=invent_list,i=0;iGmi_next,i++); if(it->Gmi_identifier){ it->Gmi_selected=!it->Gmi_selected; it->Gmi_count= count==0L ? -1L : count; count = 0L; if(Inv_how!=PICK_ANY){ /*my_close_dialog(Inv_dialog,TRUE);*/ send_return(); }else{ area.g_x=(area.g_x+23+2*menu_font.cw) & ~7; area.g_w=menu_font.cw; area.g_h=menu_font.ch; area.g_y+=(y_wo-scroll_menu.vpos)*menu_font.ch; ob_draw_chg(Inv_dialog,LINESLIST,&area,FAIL); } /* how != PICK_ANY */ } /* identifier */ }else /* LINESLIST changed */ ev &= ~MU_MESAG; /* unknown message not used */ } /* MU_MESAG */ if(ev&MU_KEYBD){ char ch=(char)(xev->ev_mkreturn&0x00FF); if(!scroll_top_dialog(ch)){ switch(ch){ case '0': /* special 0 is also groupaccelerator for balls */ if(count<=0) goto find_acc; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if(Inv_how==PICK_NONE) goto find_acc; count = (count * 10L) + (long) (ch - '0'); break; case '\033': /* cancel - from counting or loop */ if(count>0L) count=0L; else{ unset_all_on_page(0, (int)scroll_menu.vsize); my_close_dialog(Inv_dialog,TRUE); return(ev); } break; case '\0': /* finished (commit) */ case '\n': case '\r': break; case MENU_SELECT_PAGE: if(Inv_how==PICK_NONE) goto find_acc; if (Inv_how == PICK_ANY) set_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage); break; case MENU_SELECT_ALL: if(Inv_how==PICK_NONE) goto find_acc; if (Inv_how == PICK_ANY) set_all_on_page(0, (int)scroll_menu.vsize); break; case MENU_UNSELECT_PAGE: unset_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage); break; case MENU_UNSELECT_ALL: unset_all_on_page(0, (int)scroll_menu.vsize); break; case MENU_INVERT_PAGE: if(Inv_how==PICK_NONE) goto find_acc; if (Inv_how == PICK_ANY) invert_all_on_page((int)scroll_menu.vpos, scroll_menu.vpage, 0); break; case MENU_INVERT_ALL: if(Inv_how==PICK_NONE) goto find_acc; if (Inv_how == PICK_ANY) invert_all_on_page(0, (int)scroll_menu.vsize, 0); break; case MENU_SEARCH: if(Inv_how!=PICK_NONE){ char buf[BUFSZ]; Gem_getlin("Search for:",buf); if(!*buf || buf[0]=='\033') break; for(it=invent_list;it;it=it->Gmi_next){ if(it->Gmi_identifier && strstr(it->Gmi_str,buf)){ it->Gmi_selected=TRUE; if(Inv_how!=PICK_ANY){ my_close_dialog(Inv_dialog,FALSE); break; } } } } break; case C('c'): clipbrd_save(invent_list,Anz_inv_lines,xev->ev_mmokstate&K_SHIFT,TRUE); break; default: find_acc: if(Inv_how==PICK_NONE) my_close_dialog(Inv_dialog,TRUE); else for(it=invent_list;it;it=it->Gmi_next){ if(it->Gmi_identifier && (it->Gmi_accelerator==ch || it->Gmi_groupacc==ch)){ it->Gmi_selected=!it->Gmi_selected; it->Gmi_count= count==0L ? -1L : count; count = 0L; if(Inv_how!=PICK_ANY) my_close_dialog(Inv_dialog,TRUE); } } break; } /* end switch(ch) */ if(Inv_how==PICK_ANY){ area.g_x=(area.g_x+23+2*menu_font.cw) & ~7; area.g_w=menu_font.cw; ob_draw_chg(Inv_dialog,LINESLIST,&area,FAIL); } } /* !scroll_Inv_dialog */ } /* MU_KEYBD */ if(Inv_how==PICK_ANY){ ob_set_text(Inv_dialog->di_tree,QLINE,strCancel); for(it=invent_list;it;it=it->Gmi_next) if(it->Gmi_identifier && it->Gmi_selected){ ob_set_text(Inv_dialog->di_tree,QLINE,strOk); break; } ob_draw_chg(Inv_dialog,QLINE,NULL,FAIL); } return(ev); } /************************* draw_window *******************************/ static void mar_draw_window( first, win, area) int first; WIN *win; GRECT *area; { OBJECT *obj=(OBJECT *)win->para; if(obj){ if(first){ obj->ob_x=win->work.g_x; obj->ob_y=win->work.g_y; } if(area==NULL) area=&(win->work); objc_draw(obj, ROOT, MAX_DEPTH, area->g_x, area->g_y, area->g_w, area->g_h); } } /************************* mar_display_nhwindow *******************************/ void redraw_winwork(WIN *w,GRECT *area){ area->g_x+=w->work.g_x; area->g_y+=w->work.g_y; redraw_window(w,area); } void mar_menu_set_slider(WIN *p_win){ if(p_win){ SCROLL *sc=p_win->scroll; if(!sc) return; if(p_win->gadgets&HSLIDE){ long hsize=1000l; if(sc->hsize>0 && sc->hpage>0){ hsize *= sc->hpage; hsize /= sc->hsize; } window_slider(p_win,HOR_SLIDER,0,(int)hsize); } if(p_win->gadgets&VSLIDE){ long vsize=1000l; if(sc->vsize>0 && sc->vpage>0){ vsize *= sc->vpage; vsize /= sc->vsize; } window_slider(p_win,VERT_SLIDER,0,(int)vsize); } } } void recalc_msg_win(GRECT *area){ OBJECT *z_ob; z_ob=zz_oblist[MSGWIN]; z_ob[MSGLINES].ob_spec.userblk=&ub_msg; z_ob[MSGLINES].ob_width= z_ob[ROOT].ob_width= (msg_width+3)*msg_font.cw; z_ob[MSGLINES].ob_width-=z_ob[UPMSG].ob_width; z_ob[ROOT].ob_height= z_ob[GRABMSGWIN].ob_height= z_ob[MSGLINES].ob_height=msg_vis*msg_font.ch; z_ob[DNMSG].ob_y=z_ob[GRABMSGWIN].ob_height-z_ob[DNMSG].ob_height; window_border(0,0,0,z_ob->ob_width,z_ob->ob_height, area); } void recalc_status_win(GRECT *area){ OBJECT *z_ob; z_ob=zz_oblist[STATUSLINE]; z_ob[ROOT].ob_type=G_USERDEF; z_ob[ROOT].ob_spec.userblk=&ub_status; z_ob[ROOT].ob_width=(status_w+2)*status_font.cw; z_ob[ROOT].ob_height= z_ob[GRABSTATUS].ob_height=2*status_font.ch; z_ob[GRABSTATUS].ob_width=2*status_font.cw-2; window_border(0,0,0,z_ob->ob_width,z_ob->ob_height,area); } void calc_std_winplace(int which, GRECT *place){ static int todo=TRUE; static GRECT me, ma, st; if(todo || which<0){ OBJECT *z_ob; int map_h_off, foo; /* First the messagewin */ recalc_msg_win(&me); /* Now the map */ wind_calc(WC_BORDER,MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO,&foo,&foo,&foo,&map_h_off); map_h_off-=scroll_map.px_vline*ROWNO; window_border(MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO, &ma); /* Next the statuswin */ recalc_status_win(&st); /* And last but not least a final test */ ma.g_h=map_h_off+scroll_map.px_vline*ROWNO; while(me.g_h+ma.g_h+st.g_h>=desk.g_h) ma.g_h-=scroll_map.px_vline; /* stack the windows */ ma.g_y=me.g_y=st.g_y=desk.g_y; if(status_align){ ma.g_y+=st.g_h; if(msg_align){ st.g_y+=me.g_h; ma.g_y+=me.g_h; }else{ me.g_y+=st.g_h+ma.g_h; } }else{ if(msg_align){ ma.g_y+=me.g_h; }else{ me.g_y+=ma.g_h; } st.g_y+=me.g_h+ma.g_h; } if(which) todo=FALSE; } switch(which){ case NHW_MESSAGE: *place=me; break; case NHW_MAP: *place=ma; break; case NHW_STATUS: *place=st; break; default: break; } } void mar_display_nhwindow(wind) winid wind; { DIAINFO *dlg_info; OBJECT *z_ob; int d_exit=W_ABANDON, i, breite, mar_di_mode, tmp_magx=magx; GRECT g_mapmax, area; char *tmp_button; struct gw *p_Gw; if(wind == WIN_ERR) return; p_Gw=&Gem_nhwindow[wind]; switch(p_Gw->gw_type){ case NHW_TEXT: if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) mar_display_nhwindow(WIN_MESSAGE); z_ob=zz_oblist[LINES]; scroll_menu.vsize=Anz_text_lines; scroll_menu.vpos=0; if(use_rip){ if(!depack_img(planes<4 ? "RIP2.IMG" : "RIP.IMG", &rip_image)){ mfdb(&Rip_bild, (int *)rip_image.addr, rip_image.img_w, rip_image.img_h, 1, rip_image.planes); transform_img(&Rip_bild); } ub_lines.ub_code=draw_rip; }else ub_lines.ub_code=draw_lines; z_ob[LINESLIST].ob_spec.userblk=&ub_lines; breite=16; v_set_text(text_font.id,text_font.size,BLACK,0,0,NULL); for(i=0;idi_win; ptr_win->scroll=&scroll_menu; mar_menu_set_slider(ptr_win); WindowItems(ptr_win,SCROLL_KEYS,scroll_keys); if((d_exit=X_Form_Do(NULL))!=W_ABANDON){ my_close_dialog(dlg_info,FALSE); if(d_exit!=W_CLOSED) ob_undostate(z_ob,d_exit&NO_CLICK,SELECTED); } } Event_Handler(NULL,NULL); ob_set_text(z_ob,QLINE,tmp_button); break; case NHW_MENU: if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) mar_display_nhwindow(WIN_MESSAGE); z_ob=zz_oblist[LINES]; scroll_menu.vsize=Anz_inv_lines; scroll_menu.vpos=0; z_ob[LINESLIST].ob_spec.userblk=&ub_inventory; if((Menu_title)&&(wind!=WIN_INVEN)) /* because I sets no Menu_title */ Max(&Inv_breite,gr_cw*strlen(Menu_title)+16); scroll_menu.px_vline=menu_font.ch; scroll_menu.px_hline=menu_font.cw; mar_di_mode=mar_set_inv_win(Anz_inv_lines, Inv_breite, NHW_MENU); tmp_button=ob_get_text(z_ob,QLINE,0); ob_set_text(z_ob,QLINE,Inv_how!=PICK_NONE ? strCancel : strOk ); ob_doflag(z_ob,LINESLIST,TOUCHEXIT); Event_Handler(Inv_Init, Inv_Handler); if((Inv_dialog=open_dialog(z_ob,(wind==WIN_INVEN) ? "Inventory" : (Menu_title ? Menu_title : "Staun"), NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, mar_di_mode, FAIL, NULL, NULL))!=NULL){ WIN *ptr_win=Inv_dialog->di_win; ptr_win->scroll=&scroll_menu; mar_menu_set_slider(ptr_win); WindowItems(ptr_win,SCROLL_KEYS,scroll_keys); do{ int y_wo,x_wo,ru_w=1,ru_h=1; GRECT oarea; Gem_menu_item *it; d_exit=X_Form_Do(NULL); if((d_exit&NO_CLICK)==LINESLIST){ ob_pos(z_ob,LINESLIST,&oarea); if(mouse(&x_wo,&y_wo) && Inv_how==PICK_ANY){ graf_rt_rubberbox(FALSE,x_wo,y_wo,FAIL,FAIL,&oarea,&ru_w,&ru_h,NULL); invert_all_on_page((int)((y_wo-oarea.g_y)/menu_font.ch+scroll_menu.vpos),(ru_h+menu_font.ch-1)/menu_font.ch,0); }else{ for(it=invent_list,i=0;i<((y_wo-oarea.g_y)/menu_font.ch+scroll_menu.vpos) && it;it=it->Gmi_next,i++); if(it && it->Gmi_identifier){ it->Gmi_selected=!it->Gmi_selected; it->Gmi_count= count==0L ? -1L : count; count = 0L; if(Inv_how!=PICK_ANY) break; } /* identifier */ } oarea.g_x=(oarea.g_x+23+2*menu_font.cw) & ~7; oarea.g_y=y_wo-(y_wo-oarea.g_y)%menu_font.ch; oarea.g_w=menu_font.cw; oarea.g_h=((ru_h+menu_font.ch-1)/menu_font.ch)*menu_font.ch; ob_draw_chg(Inv_dialog,LINESLIST,&oarea,FAIL); } if(Inv_how==PICK_ANY){ ob_set_text(Inv_dialog->di_tree,QLINE,strCancel); for(it=invent_list;it;it=it->Gmi_next) if(it->Gmi_identifier && it->Gmi_selected){ ob_set_text(Inv_dialog->di_tree,QLINE,strOk); break; } ob_draw_chg(Inv_dialog,QLINE,NULL,FAIL); } }while((d_exit&NO_CLICK)==LINESLIST); if(d_exit!=W_ABANDON){ my_close_dialog(Inv_dialog,FALSE); if(d_exit!=W_CLOSED) ob_undostate(z_ob,d_exit&NO_CLICK,SELECTED); } } Event_Handler(NULL,NULL); ob_set_text(z_ob,QLINE,tmp_button); break; case NHW_MAP: if(p_Gw->gw_window==NULL){ calc_std_winplace(NHW_MAP,&p_Gw->gw_place); window_border(MAP_GADGETS,0,0,Tile_width*(COLNO-1),Tile_heigth*ROWNO, &g_mapmax); p_Gw->gw_window=open_window(md, md, NULL, zz_oblist[NHICON], MAP_GADGETS, TRUE, 128, 128, &g_mapmax, &p_Gw->gw_place, &scroll_map, win_draw_map, NULL, XM_TOP|XM_BOTTOM|XM_SIZE); WindowItems(p_Gw->gw_window,SCROLL_KEYS-1,scroll_keys); /* ClrHome centers on u */ mar_clear_map(); } if(p_Gw->gw_dirty){ area.g_x=p_Gw->gw_window->work.g_x+scroll_map.px_hline*(dirty_map_area.g_x-scroll_map.hpos); area.g_y=p_Gw->gw_window->work.g_y+scroll_map.px_vline*(dirty_map_area.g_y-scroll_map.vpos); area.g_w=(dirty_map_area.g_w-dirty_map_area.g_x+1)*scroll_map.px_hline; area.g_h=(dirty_map_area.g_h-dirty_map_area.g_y+1)*scroll_map.px_vline; redraw_window(p_Gw->gw_window,&area); dirty_map_area.g_x=COLNO-1; dirty_map_area.g_y=ROWNO; dirty_map_area.g_w= dirty_map_area.g_h=0; } break; case NHW_MESSAGE: if(p_Gw->gw_window==NULL){ calc_std_winplace(NHW_MESSAGE,&p_Gw->gw_place); z_ob=zz_oblist[MSGWIN]; magx=0; /* MAR -- Fake E_GEM to remove Backdropper */ p_Gw->gw_window=open_window(NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL, &p_Gw->gw_place, NULL, mar_draw_window, z_ob, XM_TOP|XM_BOTTOM|XM_SIZE); magx=tmp_magx; window_size(p_Gw->gw_window,&p_Gw->gw_window->curr); p_Gw->gw_dirty=TRUE; } if(p_Gw->gw_dirty){ ob_pos(zz_oblist[MSGWIN],MSGLINES,&area); while(messages_pro_zug>3){ messages_pro_zug-=3; msg_pos+=3; redraw_window(p_Gw->gw_window,&area); mar_more(); } msg_pos+=messages_pro_zug; messages_pro_zug=0; if(msg_pos>msg_max) msg_pos=msg_max; redraw_window(p_Gw->gw_window,&area); mar_message_pause=FALSE; } break; case NHW_STATUS: if(p_Gw->gw_window==NULL){ z_ob=zz_oblist[STATUSLINE]; calc_std_winplace(NHW_STATUS,&p_Gw->gw_place); magx=0; /* MAR -- Fake E_GEM to remove Backdropper */ p_Gw->gw_window=open_window(NULL, NULL, NULL, NULL, 0, FALSE, 0, 0, NULL, &p_Gw->gw_place, NULL, mar_draw_window, z_ob, XM_TOP|XM_BOTTOM|XM_SIZE); magx=tmp_magx; /* Because 2*status_font.ch is smaller then e_gem expects the minimum win_height */ p_Gw->gw_window->min_h=z_ob[ROOT].ob_height; window_size(p_Gw->gw_window,&p_Gw->gw_place); p_Gw->gw_dirty=TRUE; add_dirty_rect(dr_stat,&p_Gw->gw_place); } while(get_dirty_rect(dr_stat,&area)){ area.g_x=(area.g_x+p_Gw->gw_window->work.g_x+2*status_font.cw+6)&~7; area.g_y+=p_Gw->gw_window->work.g_y; redraw_window(p_Gw->gw_window,&area); } break; default: if(p_Gw->gw_dirty) redraw_window(p_Gw->gw_window,NULL); } p_Gw->gw_dirty=FALSE; } /************************* create_window *******************************/ int mar_hol_win_type(window) winid window; { return(Gem_nhwindow[window].gw_type); } winid mar_create_window(type) int type; { winid newid; static char name[]="Gem"; int i; struct gw *p_Gw=&Gem_nhwindow[0]; for(newid = 0; p_Gw->gw_type && newid < MAXWIN; newid++, p_Gw++); switch(type){ case NHW_MESSAGE: message_line=(char **)m_alloc(msg_anz*sizeof(char *)); message_age=(int *)m_alloc(msg_anz*sizeof(int)); for(i=0;igw_window=open_window("Sonst", name, NULL, NULL, NAME|MOVER|CLOSER, 0, 0, 0, NULL, &p_Gw->gw_place, NULL, NULL, NULL, XM_TOP|XM_BOTTOM|XM_SIZE); break; } p_Gw->gw_type=type; return(newid); } void mar_change_menu_2_text(win) winid win; { Gem_nhwindow[win].gw_type=NHW_TEXT; } /************************* mar_clear_map *******************************/ void mar_clear_map() { int pla[8]; int x,y; pla[0]=pla[1]=pla[4]=pla[5]=0; pla[2]=pla[6]=scroll_map.px_hline*(COLNO-1)-1; pla[3]=pla[7]=scroll_map.px_vline*ROWNO-1; for(y=0;y0 ? scroll_margin : max(scroll_map.hpage/4,1), hoehe=scroll_margin>0 ? scroll_margin : max(scroll_map.vpage/4,1), adjust_needed; adjust_needed=FALSE; if ((map_cursx < scroll_map.hpos + breite) || (map_cursx >= scroll_map.hpos + scroll_map.hpage - breite)){ scroll_map.hpos=map_cursx - scroll_map.hpage/2; adjust_needed=TRUE; } if ((map_cursy < scroll_map.vpos + hoehe) || (map_cursy >= scroll_map.vpos + scroll_map.vpage - hoehe)){ scroll_map.vpos=map_cursy - scroll_map.vpage/2; adjust_needed=TRUE; } if(adjust_needed) scroll_window(Gem_nhwindow[WIN_MAP].gw_window,WIN_SCROLL,NULL); } } void mar_update_value() { if(WIN_MESSAGE!=WIN_ERR){ mar_message_pause=FALSE; mar_esc_pressed=FALSE; mar_display_nhwindow(WIN_MESSAGE); } if(WIN_MAP!=WIN_ERR) mar_cliparound(); if(WIN_STATUS!=WIN_ERR){ mar_check_hilight_status(); mar_display_nhwindow(WIN_STATUS); } } int Main_Init(xev,availiable) XEVENT *xev; int availiable; { xev->ev_mb1mask= xev->ev_mb1state=1; xev->ev_mb1clicks= xev->ev_mb2clicks= xev->ev_mb2mask= xev->ev_mb2state=2; return((MU_KEYBD|MU_BUTTON1|MU_BUTTON2|MU_MESAG)&availiable); } /* * return a key, or 0, in which case a mouse button was pressed * mouse events should be returned as character postitions in the map window. */ /*ARGSUSED*/ int mar_nh_poskey(x, y, mod) int *x, *y, *mod; { static XEVENT xev; int retval, ev; xev.ev_mflags=Main_Init(&xev,0xFFFF); ev=Event_Multi(&xev); retval=FAIL; if(ev&MU_KEYBD){ char ch = xev.ev_mkreturn&0x00FF; char scan = (xev.ev_mkreturn & 0xff00) >> 8; int shift = xev.ev_mmokstate; const struct pad *kpad; /* Translate keypad keys */ if (iskeypad(scan)) { kpad = mar_iflags_numpad()==1 ? numpad : keypad; if (shift & K_SHIFT) ch = kpad[scan - KEYPADLO].shift; else if (shift & K_CTRL){ if(scan>=0x67 && scan<=0x6f && scan!=0x6b){ send_key(kpad[scan - KEYPADLO].normal); ch = 'g'; }else{ ch = kpad[scan - KEYPADLO].cntrl; } }else ch = kpad[scan - KEYPADLO].normal; } if(scan==SCANHOME) mar_cliparound(); else if(scan == SCANF1) retval='h'; else if(scan == SCANF2){ mar_set_tile_mode(!mar_set_tile_mode(FAIL)); retval=C('l'); /* trigger full-redraw */ }else if(scan == SCANF3){ draw_cursor=!draw_cursor; mar_curs(map_cursx,map_cursy); mar_display_nhwindow(WIN_MAP); }else if(scan == SCANF4){ /* Font-Selector */ if(!CallFontSelector(0,FAIL,FAIL,FAIL,FAIL)){ xalert(1,1,X_ICN_ALERT,NULL,SYS_MODAL,BUTTONS_RIGHT,TRUE,"Hello","Fontselector not available!",NULL); } }else if(!ch && shift&K_CTRL && scan==-57){ /* MAR -- nothing ignore Ctrl-Alt-Clr/Home == MagiC's restore screen */ }else{ if(!ch) ch=(char)M(tolower(scan_2_ascii(xev.ev_mkreturn,shift))); if(((int)ch)==-128) ch='\033'; retval=ch; } } if(ev&MU_BUTTON1 || ev&MU_BUTTON2){ int ex=xev.ev_mmox, ey=xev.ev_mmoy; WIN *akt_win=window_find(ex,ey); if(WIN_MAP != WIN_ERR && akt_win==Gem_nhwindow[WIN_MAP].gw_window){ *x=max(min((ex-akt_win->work.g_x)/scroll_map.px_hline+scroll_map.hpos,COLNO-1),0)+1; *y=max(min((ey-akt_win->work.g_y)/scroll_map.px_vline+scroll_map.vpos,ROWNO),0); *mod=xev.ev_mmobutton; retval=0; }else if(WIN_STATUS != WIN_ERR && akt_win==Gem_nhwindow[WIN_STATUS].gw_window){ move_win(akt_win); }else if(WIN_MESSAGE != WIN_ERR && akt_win==Gem_nhwindow[WIN_MESSAGE].gw_window){ message_handler(ex,ey); } } if(ev&MU_MESAG){ int *buf=xev.ev_mmgpbuf; char *str; OBJECT *z_ob=zz_oblist[MENU]; switch(*buf) { case MN_SELECTED : menu_tnormal(z_ob,buf[3],TRUE); /* unselect menu header */ str=ob_get_text(z_ob,buf[4],0); str+=strlen(str)-2; switch(*str){ case ' ': /* just that command */ retval=str[1]; break; case '\005': /* Alt command */ case '\007': retval=M(str[1]); break; case '^': /* Ctrl command */ retval=C(str[1]); break; case 'f': /* Func Key */ switch(str[1]){ case '1': retval='h'; break; case '2': mar_set_tile_mode(!mar_set_tile_mode(FAIL)); retval=C('l'); /* trigger full-redraw */ break; case '3': draw_cursor=!draw_cursor; mar_curs(map_cursx,map_cursy); mar_display_nhwindow(WIN_MAP); break; default: } break; default: mar_about(); break; } break; /* MN_SELECTED */ case WM_CLOSED: WindowHandler(W_ICONIFYALL,NULL,NULL); break; case AP_TERM: retval='S'; break; case FONT_CHANGED: if(buf[3]>=0){ if(buf[3]==Gem_nhwindow[WIN_MESSAGE].gw_window->handle){ mar_set_fontbyid(NHW_MESSAGE,buf[4],buf[5]); mar_display_nhwindow(WIN_MESSAGE); }else if(buf[3]==Gem_nhwindow[WIN_MAP].gw_window->handle){ mar_set_fontbyid(NHW_MAP,buf[4],buf[5]); mar_display_nhwindow(WIN_MAP); }else if(buf[3]==Gem_nhwindow[WIN_STATUS].gw_window->handle){ mar_set_fontbyid(NHW_STATUS,buf[4],buf[5]); mar_display_nhwindow(WIN_STATUS); } FontAck(buf[1],1); } break; default: break; } } /* MU_MESAG */ if(retval==FAIL) retval=mar_nh_poskey(x,y,mod); return(retval); } int Gem_nh_poskey(x, y, mod) int *x, *y, *mod; { mar_update_value(); return(mar_nh_poskey(x, y, mod)); } void Gem_delay_output() { Event_Timer(50,0,FALSE); /* wait 50ms */ } int Gem_doprev_message() { if(msg_pos>2){ msg_pos--; if(WIN_MESSAGE != WIN_ERR) Gem_nhwindow[WIN_MESSAGE].gw_dirty=TRUE; mar_display_nhwindow(WIN_MESSAGE); } return(0); } /************************* print_glyph *******************************/ int mar_set_rogue(int); int mar_set_tile_mode(tiles) int tiles; { static int tile_mode=TRUE; static GRECT prev; WIN *z_w=WIN_MAP!=WIN_ERR ? Gem_nhwindow[WIN_MAP].gw_window : NULL; if(tiles<0) return(tile_mode); else if(!z_w) tile_mode=tiles; else if(tile_mode==tiles || (mar_set_rogue(FAIL) && tiles)) return(FAIL); else{ GRECT tmp; tile_mode=tiles; scroll_map.px_hline= tiles ? Tile_width : map_font.cw; scroll_map.px_vline= tiles ? Tile_heigth : map_font.ch; window_border(MAP_GADGETS,0,0,scroll_map.px_hline*(COLNO-1),scroll_map.px_vline*ROWNO, &tmp); z_w->max.g_w=tmp.g_w; z_w->max.g_h=tmp.g_h; if(tiles) z_w->curr=prev; else prev=z_w->curr; window_reinit(z_w,md,md,NULL,FALSE,FALSE); } return(FAIL); } int mar_set_rogue(what) int what; { static int rogue=FALSE, prev_mode=TRUE; if(what<0) return(rogue); if(what!=rogue){ rogue=what; if(rogue){ prev_mode=mar_set_tile_mode(FAIL); mar_set_tile_mode(FALSE); }else mar_set_tile_mode(prev_mode); } return(FAIL); } void mar_add_pet_sign(window,x,y) winid window; int x, y; { if(window != WIN_ERR && window==WIN_MAP){ static int pla[8]={0,0,7,7,0,0,0,0}, colindex[2]={RED,WHITE}; pla[4]=pla[6]=scroll_map.px_hline*x; pla[5]=pla[7]=scroll_map.px_vline*y; pla[6]+=7; pla[7]+=6; vrt_cpyfm(x_handle,MD_TRANS,pla,&Pet_Mark,&Map_bild,colindex); } } void mar_print_glyph(window, x, y, gl) winid window; int x, y, gl; { if(window != WIN_ERR && window==WIN_MAP){ static int pla[8]; pla[2]=pla[0]=(gl%Tiles_per_line)*Tile_width; pla[3]=pla[1]=(gl/Tiles_per_line)*Tile_heigth; pla[2]+=Tile_width-1; pla[3]+=Tile_heigth-1; pla[6]=pla[4]=Tile_width*x; /* x_wert to */ pla[7]=pla[5]=Tile_heigth*y; /* y_wert to */ pla[6]+=Tile_width-1; pla[7]+=Tile_heigth-1; vro_cpyfm(x_handle, gl!=-1 ? S_ONLY : ALL_BLACK, pla, &Tile_bilder, &Map_bild); } } void mar_print_char(window, x, y, ch, col) winid window; int x, y; char ch; int col; { if(window != WIN_ERR && window==WIN_MAP){ static int gem_color[16]={ 9, 2,11,10, 4, 7, 8, 15,0,14, 3, 6, 5, 13,15, 0}; int pla[8], colindex[2]; map_glyphs[y][x]=ch; pla[0]= pla[1]=0; pla[2]=map_font.cw-1; pla[3]=map_font.ch-1; pla[6]=pla[4]=map_font.cw*x; pla[7]=pla[5]=map_font.ch*y; pla[6]+=map_font.cw-1; pla[7]+=map_font.ch-1; colindex[0]=gem_color[col]; colindex[1]=WHITE; vrt_cpyfm(x_handle,MD_REPLACE,pla,&Black_bild,&FontCol_Bild,colindex); } } /************************* getlin *******************************/ void Gem_getlin(ques, input) const char *ques; char *input; { OBJECT *z_ob=zz_oblist[LINEGET]; int d_exit, length; char *pr[2], *tmp; if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) mar_display_nhwindow(WIN_MESSAGE); z_ob[LGPROMPT].ob_type=G_USERDEF; z_ob[LGPROMPT].ob_spec.userblk=&ub_prompt; z_ob[LGPROMPT].ob_height=2*gr_ch; length=z_ob[LGPROMPT].ob_width/gr_cw; if(strlen(ques)>length){ tmp=ques+length; while(*tmp!=' ' && tmp>=ques){ tmp--; } if(tmp<=ques) tmp=ques+length; /* Mar -- Oops, what a word :-) */ pr[0]=ques; *tmp=0; pr[1]=++tmp; }else{ pr[0]=ques; pr[1]=NULL; } ub_prompt.ub_parm=(long)pr; ob_clear_edit(z_ob); d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE); Event_Timer(0,0,TRUE); if(d_exit==W_CLOSED || d_exit==W_ABANDON || (d_exit&NO_CLICK)==QLG){ *input='\033'; input[1]=0; }else strncpy(input,ob_get_text(z_ob,LGREPLY, 0),length); } /************************* ask_direction *******************************/ #define Dia_Init K_Init int Dia_Handler(xev) XEVENT *xev; { int ev=xev->ev_mwich; char ch=(char)(xev->ev_mkreturn&0x00FF); if(ev&MU_KEYBD){ WIN *w; DIAINFO *dinf; switch(ch){ case 's': send_key((int)(mar_iflags_numpad() ? '5' : '.')); break; case '.': send_key('5'); /* MAR -- '.' is a button if numpad isn't set */ break; case '\033': /*ESC*/ if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[DIRECTION]){ my_close_dialog(dinf,FALSE); break; } /* Fall thru */ default: ev &= ~MU_KEYBD; /* let the dialog handle it */ break; } } return(ev); } int mar_ask_direction() { int d_exit; OBJECT *z_ob=zz_oblist[DIRECTION]; Event_Handler(Dia_Init,Dia_Handler); mar_set_dir_keys(); d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE); Event_Timer(0,0,TRUE); Event_Handler(NULL,NULL); if(d_exit==W_CLOSED || d_exit==W_ABANDON) return('\033'); if((d_exit&NO_CLICK)==DIRDOWN) return('>'); if((d_exit&NO_CLICK)==DIRUP) return('<'); if((d_exit&NO_CLICK)==(DIR1+8)) /* 5 or . */ return('.'); return(*ob_get_text(z_ob,d_exit&NO_CLICK,0)); } /************************* yn_function *******************************/ #define any_init M_Init static int any_handler(xev) XEVENT *xev; { int ev=xev->ev_mwich; if(ev&MU_MESAG){ int *buf=xev->ev_mmgpbuf; if(*buf==OBJC_EDITED) my_close_dialog(*(DIAINFO **)&buf[4], FALSE); else ev &= ~MU_MESAG; } return(ev); } int send_yn_esc(char ch) { static char esc_char=0; if(ch<0){ if(esc_char){ send_key((int)esc_char); return(TRUE); } return(FALSE); }else esc_char=ch; return(TRUE); } #define single_init K_Init static int single_handler(xev) XEVENT *xev; { int ev=xev->ev_mwich; if(ev&MU_KEYBD){ char ch=(char)xev->ev_mkreturn&0x00FF; WIN *w; DIAINFO *dinf; switch(ch){ case ' ': send_return(); break; case '\033': if((w=get_top_window()) && (dinf=(DIAINFO *)w->dialog) && dinf->di_tree==zz_oblist[YNCHOICE]){ if(!send_yn_esc(FAIL)) my_close_dialog(dinf,FALSE); break; } /* Fall thru */ default: ev &= ~MU_MESAG; } } return(ev); } char Gem_yn_function(query,resp, def) const char *query,*resp; char def; { OBJECT *z_ob=zz_oblist[YNCHOICE]; int d_exit, i, len; long anzahl; char *tmp; const char *ptr; if(WIN_MESSAGE != WIN_ERR && Gem_nhwindow[WIN_MESSAGE].gw_window) mar_display_nhwindow(WIN_MESSAGE); /* if query for direction the special dialog */ if(strstr(query,"irect")) return(mar_ask_direction()); len=min(strlen(query),(max_w-8*gr_cw)/gr_cw); z_ob[ROOT].ob_width=(len+8)*gr_cw; z_ob[YNPROMPT].ob_width=gr_cw*len+8; tmp=ob_get_text(z_ob,YNPROMPT,0); ob_set_text(z_ob,YNPROMPT,mar_copy_of(query)); if(resp){ /* single inputs */ ob_hide(z_ob,SOMECHARS,FALSE); ob_hide(z_ob,ANYCHAR,TRUE); if(strchr(resp,'q')) send_yn_esc('q'); else if(strchr(resp,'n')) send_yn_esc('n'); else send_yn_esc(def); /* strictly def should be returned, but in trad. I it's 0 */ if(strchr(resp,'#')){ /* count possible */ ob_hide(z_ob,YNOK,FALSE); ob_hide(z_ob,COUNT,FALSE); }else{ /* no count */ ob_hide(z_ob,YNOK,TRUE); ob_hide(z_ob,COUNT,TRUE); } if((anzahl=(long)strchr(resp,'\033'))){ anzahl-=(long)resp; }else{ anzahl=strlen(resp); } for(i=0,ptr=resp;i<2*anzahl;i+=2,ptr++){ ob_hide(z_ob,YN1+i,FALSE); mar_change_button_char(z_ob,YN1+i,*ptr); ob_undoflag(z_ob,YN1+i,DEFAULT); if(*ptr==def) ob_doflag(z_ob,YN1+i,DEFAULT); } z_ob[SOMECHARS].ob_width=z_ob[YN1+i].ob_x+8; z_ob[SOMECHARS].ob_height=z_ob[YN1+i].ob_y+gr_ch+gr_ch/2; Max((int *)&z_ob[ROOT].ob_width,z_ob[SOMECHARS].ob_width+4*gr_cw); z_ob[ROOT].ob_height=z_ob[SOMECHARS].ob_height+4*gr_ch; if(strchr(resp,'#')) z_ob[ROOT].ob_height=z_ob[YNOK].ob_y+2*gr_ch; for(i+=YN1;i<(YNN+1);i+=2){ ob_hide(z_ob,i,TRUE); } Event_Handler(single_init,single_handler); }else{ /* any input */ ob_hide(z_ob,SOMECHARS,TRUE); ob_hide(z_ob,ANYCHAR,FALSE); ob_hide(z_ob,YNOK,TRUE); ob_hide(z_ob,COUNT,TRUE); z_ob[ANYCHAR].ob_height=2*gr_ch; z_ob[CHOSENCH].ob_y= z_ob[CHOSENCH+1].ob_y=gr_ch/2; z_ob[ROOT].ob_width=max(z_ob[YNPROMPT].ob_width+z_ob[YNPROMPT].ob_x,z_ob[ANYCHAR].ob_width+z_ob[ANYCHAR].ob_x)+2*gr_cw; z_ob[ROOT].ob_height=z_ob[ANYCHAR].ob_height+z_ob[ANYCHAR].ob_y+gr_ch/2; *ob_get_text(z_ob,CHOSENCH,0)='?'; Event_Handler(any_init,any_handler); } d_exit=xdialog(z_ob, nullstr, NULL, NULL, mar_ob_mapcenter(z_ob), FALSE, DIALOG_MODE); Event_Timer(0,0,TRUE); Event_Handler(NULL,NULL); /* display of count is missing (through the core too) */ free(ob_get_text(z_ob,YNPROMPT,0)); ob_set_text(z_ob,YNPROMPT,tmp); if(resp && (d_exit==W_CLOSED || d_exit==W_ABANDON)) return('\033'); if((d_exit&NO_CLICK)==YNOK){ yn_number=atol(ob_get_text(z_ob,COUNT,0)); return('#'); } if(!resp) return(*ob_get_text(z_ob,CHOSENCH,0)); return(*ob_get_text(z_ob,d_exit&NO_CLICK,0)); } /* * Allocate a copy of the given string. If null, return a string of * zero length. * * This is an exact duplicate of copy_of() in X11/winmenu.c. */ static char * mar_copy_of(s) const char *s; { if (!s) s = nullstr; return strcpy((char *) m_alloc((unsigned) (strlen(s) + 1)), s); } const char *strRP="raw_print", *strRPB="raw_print_bold"; void mar_raw_print(str) const char *str; { xalert(1,FAIL,X_ICN_INFO,NULL,APPL_MODAL,BUTTONS_CENTERED,TRUE,strRP,str,NULL); } void mar_raw_print_bold(str) const char *str; { char buf[BUFSZ]; sprintf(buf,"!%s",str); xalert(1,FAIL,X_ICN_INFO,NULL,APPL_MODAL,BUTTONS_CENTERED,TRUE,strRPB,buf,NULL); } /*wingem1.c*/ nethack-3.4.3/win/gem/xpm2img.c0100644000000000000000000001057507764735042014757 0ustar rootroot/* SCCS Id: @(#)xpm2img.c 3.4 2002/03/17 */ /* Copyright (c) Christian Bressler 2002 */ /* NetHack may be freely redistributed. See license for details. */ /* This is mainly a reworked tile2bmp.c + xpm2iff.c -- Marvin */ #include #include #include #include "bitmfile.h" #define TRUE 1 #define FALSE 0 void get_color(unsigned int colind, struct RGB *rgb); void get_pixel(int x, int y, unsigned int *colind); char *xpmgetline(); unsigned int **Bild_daten; /* translation table from xpm characters to RGB and colormap slots */ struct Ttable { char flag; struct RGB col; int slot; /* output colortable index */ }ttable[256]; struct RGB *ColorMap; int num_colors = 0; int width=0, height=0; int initflag; FILE *fp; int main(argc, argv) int argc; char *argv[]; { int i; int row, col, planeno; int farben, planes; if (argc != 3) { fprintf(stderr, "usage: tile2img infile.xpm outfile.img\n"); exit(EXIT_FAILURE); } initflag = 0; fp = fopen(argv[2],"wb"); if (!fp) { printf("Error creating IMG-file %s, aborting.\n",argv[2]); exit(EXIT_FAILURE); } fclose(fp); if(fopen_xpm_file(argv[1],"r")!=TRUE){ printf("Error reading xpm-file %s, aborting.\n",argv[1]); exit(EXIT_FAILURE); } Bild_daten=(unsigned int **)malloc((long)height*sizeof(unsigned int *)); for(i=0;i256){ fprintf(stderr,"ERROR: zuviele Farben\n"); exit(EXIT_FAILURE); }else if(num_colors>16){ farben=256; planes=8; }else if(num_colors>2){ farben=16; planes=4; }else{ farben=2; planes=1; } bitmap_to_file(XIMG, width, height, 372, 372, planes, farben, argv[2], get_color, get_pixel ); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } void get_color(unsigned int colind, struct RGB *rgb){ rgb->r=(1000L*(long)ColorMap[colind].r)/0xFF; rgb->g=(1000L*(long)ColorMap[colind].g)/0xFF; rgb->b=(1000L*(long)ColorMap[colind].b)/0xFF; } void get_pixel(int x, int y, unsigned int *colind){ *colind=Bild_daten[y][x]; } FILE *xpmfh = 0; char initbuf[200]; char *xpmbuf = initbuf; /* version 1. Reads the raw xpm file, NOT the compiled version. This is * not a particularly good idea but I don't have time to do the right thing * at this point, even if I was absolutely sure what that was. */ fopen_xpm_file(const char *fn, const char *mode){ int temp; char *xb; if(strcmp(mode, "r"))return FALSE; /* no choice now */ if(xpmfh)return FALSE; /* one file at a time */ xpmfh = fopen(fn, mode); if(!xpmfh)return FALSE; /* I'm hard to please */ /* read the header */ xb = xpmgetline(); if(xb == 0)return FALSE; if(4 != sscanf(xb,"%d %d %d %d", &width, &height,&num_colors, &temp)) return FALSE; /* bad header */ /* replace the original buffer with one big enough for * the real data */ /* XXX */ xpmbuf = malloc(width * 2); if(!xpmbuf){ fprintf(stderr,"ERROR: Can't allocate line buffer\n"); exit(1); } if(temp != 1)return FALSE; /* limitation of this code */ { /* read the colormap and translation table */ int ccount = -1; ColorMap = (struct RGB *)malloc((long)num_colors*sizeof(struct RGB)); while(ccount++ < (num_colors-1)){ char index; int r, g, b; xb = xpmgetline(); if(xb==0)return FALSE; if(4 != sscanf(xb,"%c c #%2x%2x%2x",&index,&r,&g,&b)){ fprintf(stderr,"Bad color entry: %s\n",xb); return FALSE; } ttable[index].flag = 1; /* this color is valid */ ttable[index].col.r = r; ttable[index].col.g = g; ttable[index].col.b = b; ttable[index].slot = ccount; ColorMap[ccount].r=r; ColorMap[ccount].g=g; ColorMap[ccount].b=b; } } return TRUE; } /* This deserves better. Don't read it too closely - you'll get ill. */ #define bufsz 2048 char buf[bufsz]; char * xpmgetline(){ char *bp; do { if(fgets(buf, bufsz, xpmfh) == 0)return 0; } while(buf[0] != '"'); /* strip off the trailing <",> if any */ for(bp = buf;*bp;bp++); bp--; while(isspace(*bp))bp--; if(*bp==',')bp--; if(*bp=='"')bp--; bp++; *bp = '\0'; return &buf[1]; } nethack-3.4.3/win/gnome/0040755000000000000000000000000007764735105013560 5ustar rootrootnethack-3.4.3/win/gnome/gn_xpms.h0100644000000000000000000013770607764735042015417 0ustar rootroot/* SCCS Id: @(#)gnxpms.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ /* These XPMs are the artwork of Warwick Allison * . They have been borrowed from * the most excellent NetHackQt, until such time as * we can come up with something better. * * More information about NetHackQt can be had from: * http://www.troll.no/~warwick/nethack/ */ /* XPM */ static char *blind_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 5 1", /* colors */ " c #000000", ". c None", "X c #909090", "o c #606060", "O c #303030", /* pixels */ "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "....ooooooooooooooooooooooooooooooooX...", ".... o...", ".... o...", ".... o...", ".... o...", "......o ..o ......", "......X O..X O......", "....... o... o......", ".......o ....o .......", "........O X.....O X.......", ".........O X.......O X........", "..........o OX.........o OX.........", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................", "........................................" }; /* XPM */ static char *cha_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ " c #F85848", ". c #949E9E", "X c #F8B090", "o c #E00028", "O c #D4D4D4", "+ c None", "@ c #B0B0B0", "# c #F82C24", "$ c #F89E6C", "% c #FF0000", "& c #909090", "* c #FFFFFF", "= c #CEAA90", "- c #DADAB6", /* pixels */ "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "+++++++++++++++=#%#=+=#%% ++++++++++++++", "++++++++++++++ %O%%%#%$$%o%=++++++++++++", "+++++++++++++# +#%%o%%o%%%%% +++++++++++", "+++++++++++ %%%%%%%%%%%%%%%%o#=+++++++++", "+++++++++ o%%%%%%%%%%%%%%%%%%%%# +++++++", "++++++ #%%%%%%o%%%o%%o%%o%o%%%%%o%o +++", "++=#%%o%%%#= =*+**O*+**O*+- = =%%%%#@+++", "++++ %=++*+*+**O****O****O*O*O*OO%=+++++", "+++++.%=OO+*O*OO****+****+*O*+O&%=@+++++", "++++++=%=*OO+**O**O*O**O*O*OO+$%=+++++++", "+++++++#% +*OOOO****+****@O+*#%=++++++++", "++++++++#%#*+**+O+OO+O+OOO*O#o#+++++++++", "+++++++++o% O**+****O****O*#%%=+++++++++", "+++++++++ %%#O*O****+****+ %o#++++++++++", "++++++++++o%% XO*O**O*O**#%%%+++++++++++", "++++++++++ %%%o%$-**+**$%%%%=+++++++++++", "+++++++++++o%%$X$%%%%%%#= o#++++++++++++", "++++++++++@ %%%o#O$$+$$$%%%=++++++++++++", "++++++++++++#o%%%%%%%%o%%%=@++++++++++++", "+++++++++++++ %%%%%%%%%%o=++++++++++++++", "+++++++++++++++= & & @++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ static char *chaotic_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 9 1", /* colors */ " c #000000", ". c #5C7A7A", "X c None", "o c #B0B0B0", "O c #909090", "+ c #788C8C", "@ c #606060", "# c #FFFFFF", "$ c #303030", /* pixels */ "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXX@$ @XXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXX$$+#X$ $XXXXXXXXXX", "XXXXXXXXXXXXXXXXXX@$#o @XXXXXXXXX", "XXXXXXXXXXXXXXXXXX$XX OXXXXXXXX", "XXXXXXXXXXXXXXXXX@ # $@$ $XXXXXXXX", "XXXXXXXXXXXXXXXXX@.+ $XXXO @XXXXXXX", "XXXXXXXXXXXXXXXXX O@ XXXXX@ @XXXXXXX", "XXXXXXXXXXXXXXXXX @O $XXXXX@$ @XXXXXXX", "XXXXXXXXXXXXXXXXX O+ @XXXXO++ @XXXXXXX", "XXXXXXXXXXXXXXXXX @+ $@OXO$#$ XXXXXXXX", "XXXXXXXXXXXXXXXXX O@ $ @$Xo $XXXXXXXX", "XXXXXXXXXXXXXXXXX +O $X##+ $XXXXXXXXX", "XXXXXXXXXXXXXXXXX +@ $XXXXXXXXXX", "XXXXXXXXXXXXXXXXX oO $XXXXXXXXXXX", "XXXXXXXXO@@@@@ +# $XXXXXXXXXXXX", "XXXXXXO +o########$ $@XXXXXXXXX", "XXXXXX +#+.$XXXXXXXX", "XXXXXX @O @XXXXXXX", "XXXXXX$ $@ $@@$ @XXXXXXX", "XXXXXXX@@@@XXXXXX + @XXXX@$ OXXXXXXX", "XXXXXXXXXXXXXXXX@ # @XXXXXXX@@OXXXXXXXX", "XXXXXXXXXXXXXXXX@.+ @XXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX$O@ XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX @O XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX #$ @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@ # @XXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@ # OXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX@.X XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX ++ XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX @+ XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX O@ @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX +O @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX @XXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXX$ OXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX@@OXXXXXXXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" }; /* XPM */ static char *cns_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ " c #000000", ". c #F85848", "X c #949E9E", "o c #F8B090", "O c #E00028", "+ c #7C3400", "@ c None", "# c #B0B0B0", "$ c #F82C24", "% c #F89E6C", "& c #FF0000", "* c #B64700", "= c #909090", "- c #788C8C", "; c #606060", ": c #C80050", "> c #CEAA90", ", c #303030", "< c #FFB691", /* pixels */ "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@.oo.o$ ;@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@>.o.%%O,@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@$oo.o. ,@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@.oo$oo+ =@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@..o&oo$ ,@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@#.o.oo. =@.$%@@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o..oo& O.%ooo@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o.&%o.$oo%O++;@@@@@@@@@@@@", "@@@@@@@@@@@@@.o.+$%$o.@@@@@@@@@@@", "@@@@@@@@@@@@@.oo++o%$$ ,@@$.oo@@@@@@@@@@", "@@@@@@@@@@@@>.oo+Oo$o%.@@$oo..-@@@@@@@@@", "@@@@@@@@@@@@..o%;.o&%.$..o%O ++>@@@@@@@@", "@@@@@@@@@@@@>.$O:%o.O::::O* $oooo@@@@@@@", "@@@@@@@@@@@@::::::$$:OO&OO::oo%.;=@@@@@@", "@@@@@@@@@@@.::::::::O&&&&&O::++ ,@@@@@@", "@@@@@@@@@@>:::O&&OO&&&&&&&&:: ;@@@@@", "@@@@@@@@@@=::O&&&&&O:O&&&&&O: ,=@@@@@@@", "@@@@@@@@@@:::&&&&&&&&:&&&&&O: ;@@@@@@@@", "@@@@@@@@@@::O&&&&&&&&:&O&&&O:, ;@@@@@@@@", "@@@@@@@@@@::O&&&&O&O&OO&O&&O:+ ;@@@@@@@@", "@@@@@@@@@@::&&&O&&&&&O:&&&&O:, @@@@@@@@", "@@@@@@@@@@::O&&&&&O&&&:O&O&::+ @@@@@@@@", "@@@@@@@@@@::O&&O&&&&O&OO&&&:: @@@@@@@@", "@@@@@@@@@@=::O&&&&O&&&O:&&&:: @@@@@@@@", "@@@@@@@@@@.:::O&&O&&&&&:&OO:: @@@@@@@@", "@@@@@@@@@@@:::::&&&&O&O:&&O:, @@@@@@@@", "@@@@@@@@@@.>:::::O&&&&&:&&::+ ;@@@@@@@@", "@@@@@@@@@@>.<::::O&&O&O:&&:: @@@@@@@@@", "@@@@@@@@@@@.o%,:::O&&&O:&O:, @@@@@@@@@", "@@@@@@@@@@@$o. :::OO&OO&::, ;@@@@@@@@@", "@@@@@@@@@@@&o%+ ,::O&OO&O:: =@@@@@@@@@", "@@@@@@@@@@@.oo+ :::OO::: ,@@@@@@@@@@", "@@@@@@@@@@@..oO +::::: =@@@@@@@@@@", "@@@@@@@@@@@@.<.+ ,+, ,@@@@@@@@@@@", "@@@@@@@@@@@@Oo<+ @X, ,@@@@@@@@@@@@", "@@@@@@@@@@@@.%o$ @@@@@;, ;@@@@@@@@@@@@@", "@@@@@@@@@@@@@.o., =@@@@@@@@@@@@@@@@@@@@@", "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" }; /* XPM */ static char *confused_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO.=.+OO=.+O.OO+O+OO.+OOOOOO", "OOOOOOOOOOO++=====O=====+=O+==++=O+OOOOO", "OOOOOOOOOOO+=.=====.=++++===OO==+O=+OOOO", "OOOOOOOOOOO=+===.+=o==o===+&OoO======OOO", "OOOOOOOO+O+====OO+=o&&&&Oo==o&oO+==+=.O.", "OOOO+.+=+O==+&&o=oooOo&o&ooo=&oooO==O=+=", "OOOOOOOO++O===oo=oo&=&o&&oo=o==&o+==++==", "OOOOOOOO=o.=O====o&OO&o&oo&o&&oo=======O", "OOOOOOOo===+=O=O=ooO=ooooOOo=o&O=====OOO", "OOOOOOOOO+==+=======O=oo====O=o=O===+OOO", "OOOOOOOOO.=#=X=+====O========O======OOOO", "OOOOOOO.#Xo++.=#%====O==========OO==+OOO", "OOOOOO+Xo#+#+.#=.==X====+====O=+=+==+OOO", "OOOOO.+.+O===##.#=X.====oX##===o+OO.OOOO", "OOOOO#+####O#O##o.#+==#X#O#+...=OOo=+OOO", "OOOO++#o+#+X++++#.#O.#+#X.#+X+==+OO=oOOO", "OOOO#+.+..X+.##X++#++#..+XX#+##+..OOOOOO", "OOOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOO", "OOOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOO", "OOOOO#+#+.+++#++.+++##+X###+X+X##+**OOOO", "OOOOO#..#OO#+.##o###.+..++.+#X+#+#* @OOO", "OOOOO+#.#O+#+#O.+++.###+##++###+.#* $OOO", "OOOOOOXX+#+#+#o..X##++#+..##.#+### *OOO", "OOOOOOOX#.#X+#+#+#+.#+..+####%XX%% OOO", "OOOOOOOO.%%X.#+#+#.++#+#+#+.X++=.% *OOO", "OOOOOOOOO.* *##+#+.O####.+XX%%%%#% $OOO", "OOOOOOOOOOO. %X.+.#+++XXX=.+++#X $OOO", "OOOOOOOOOOOO.* %%X..#X%=.####%X* $OOO", "OOOOOOOOOOOOOO.$ *XX%%%=.#X%###=* OOOO", "OOOOOOOOOOOOOOOOOO+%%%=%%#.+.#=* @OOOO", "OOOOOOOOOOOOOOOOOOo=%%%==X##X%* OOOOO", "OOOOOOOOOOOOOOOOOOO+X%%%%X=%* @OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X *@OOOOOO", "OOOOOOOOOOOOOOOOOOOO=%%%X* *$$OOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+X%%= .OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOX%%% OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%* $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO=%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO+%%% $OOOOOOOOOOOOO" }; /* XPM */ static char *dex_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 19 1", /* colors */ " c #000000", ". c #949E9E", "X c #F8B090", "o c #5C7A7A", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #B64700", "* c #909090", "= c #606060", "- c #CEAA90", "; c #DADAB6", ": c #303030", "> c #F86800", ", c #FFB691", "< c #F88C48", /* pixels */ "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "###############-%-######################", "##############-%X<-#####################", "#########-<<-#-%XX+==###################", "#########%,X< :<,X%@ :##################", "#########-XX%: @;X%+ *#################", "##########<,X& :<<%+: :#################", "######->+#-%%%: <,XX@ #################", "######%X%@ <,,& @XXX+ :++-#############", "######-: +XX+ #########", "#####+%%@@,X%<,XXXXXXX<:@XXX<: =########", "####$%XX< <,<,XX& ########", "#####$%<%X@%XXXX<%XX< =#######", "#######<;X%XXXXX<<,XXXXXX%,XXXXXXXXX%@ #######", "##########- c #788C8C", ", c #606060", "< c #406868", "1 c #C80050", "2 c #FFFFFF", "3 c #FFFF00", "4 c #00B6FF", "5 c #CEAA90", "6 c #DADAB6", "7 c #F86800", "8 c #FFB691", "9 c #6C91B6", "0 c #F88C48", "q c #0000FF", /* pixels */ "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", "$$$$$$$$$$$$$$$353333335*$$$$$$$$$$$$$$$", "$$$$$$$$$$$$*33333333#7@3335$$$$$$$$$$$$", "$$$$$$$$$65333333333@7777#333*$$$$$$$$$$", "$$$$$$$$$3333333333377777733333===%$$$$$", "$$$$$$$533333333333#7777777333%=====$$$$", "$$$$$$ #3333333333o>7777773330======%$$$", "$$$$5---O#33333o3944077777333*=======$$$", "$$$$-----O333333>4444.77333330======%$$$", "$$$ ---O--;3333344444443333333:====5$$$$", "$$$ O-----733333444444433333333 ==035$$$", "$$$3--O--O333333>44444>33333333333333$$$", "$$533---O33333333944493333#333333333356$", "$$33867733333o33333:o333333o3333333333$$", "$532+2233333#333333333333oooo3#3333333%$", "6522222+33333333333333333oooooo33o3333*$", "$+22+22263333333o3333333ooooooo333333356", "662222+2533333333333333#ooooooo33333333$", "$32+22223333o3#33333o333ooooooo3#333333%", "$33222233333333333#333333ooooo333333333$", "$33368333333333333330626*oooo#333333o33%", "%333335== 33oo333333222223#333333333333$", "$3333=====:ooooo333+22+2263333333.>o333%", "$5333=====oooooo33322222223333339444935$", "$*33 ====>ooooooo3362+222633333.44444>3$", "$%330====:ooooooo333222+23333334444444$$", "$$333177 =oooXoo#333*626333333;4444444$$", "$$53##777&3oooo3333333333333#--,444449$$", "$$$3;77777#3o333333333333333O---94449$$$", "$$%*@77777#33333333333333337O----O:o3$$$", "$$$5777777333 333333333333;---O-O73$$$$", "$$$$#7777730====#:.,33333333------3$$$$$", "$$$$$577333=====qqqq<0333333#O---35$$$$$", "$$$$$%53335====qqqqqq.33o333337735$$$$$$", "$$$$$$$533 ====qqqqqqq3333333333%$$$$$$$", "$$$$$$$$%33====qqqqqqq333333333%$$$$$$$$", "$$$$$$$$$$50===qqqqqq,3333333:$$$$$$$$$$", "$$$$$$$$$%6%5503,qqq<333#335%$$$$$$$$$$$", "$$$$$$$$$$$$$%$*53,03335o$%%$$$$$$$$$$$$", "$$$$$$$$$$$$$$$$$$$$$%$$+$$$$$$$$$$$$$$$" }; /* XPM */ static char *hungry_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 15 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #CEAA90", "= c #DADAB6", "- c #303030", "; c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO========OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO=============OOOOOOOOOOOOO", "OO;XX;@OOOOO================OOOOOOOO;XOO", "OO;%-;$OOOO==================OOOOOOO;XOO", "OO;-%;$OOO========@$#@========OOOOO+;;$O", "OO;%-;$OO=======- -*======*OOOO.;;$O", "OO;-%;$O======* @====.$$&=====@OOO.;;$O", "OO;X%;$O====== -========*@=====*.OO+;;$O", "OO;;;X$o====* -==========@======$OO;;;$O", "OO+;;-+o====- =============o====#@O+;;$O", "OOO;%$O===== @=============&====*$O;;;$O", "OOO+%OO====@ ==============&=====-OO;;$O", "OOo;-Oo====$ ==============o&==== OO;;$O", "OOO+%OO====@ ==============&===== O+;;#O", "OOO;-Oo====$-==============&&==== O+;;-O", "OOO;;+O=====$*============&&====* OO;;%+", "OOO;;$o=====$.============&&====X-OO;;$O", "OOO;;$O======*.===&======&&=====-$=O;;$O", "OOO;;$Oo=====.==========&&=====* @O+;;$O", "OOO;;$OO=======oo=====&&&======$-OOO;;$O", "OOO;;$OOo=======&o&&&&&&======$ @OOO;;$O", "OOO;;$OOOO========&=&========* $OOOO;;$O", "OO+;;$OOOOo=================* -OOOOO#;$O", "OOO;;$OOOOO=*==============@ -=OOOOO;;$O", "OOO;;$OOOOOOO+*==========*- $OOOOOOO;;$O", "OOOX-$OOOOOOOO@X@*====*#- -.OOOOOOOOX-$O", "OOOOOOOOOOOOOO=*@$- -$.=OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOO=O==O=O=OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *hvy_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOO&&&&&&&&&&&&&&&.OOOOOOOOOOOOO", "OOOOOOOOOOOo==============X*OOOOOOOOOOOO", "OOOOOOOOOOoO===X====X=====X**OOOOOOOOOOO", "OOOOOOOOOO&============X===% $OOOOOOOOOO", "OOOOOOOOOoo===*%====***%===%* OOOOOOOOOO", "OOOOOOOOOoO==% %===* %==X* @OOOOOOOOO", "OOOOOOOOO&===% *==% X==**===% $OOOOOOOOO", "OOOOOOOOoo===% %==% ===% ===X OOOOOOOOO", "OOOOOOOOoO==== *== *==== *==X* @OOOOOOOO", "OOOOOOOO&===== %== %==== %===% $OOOOOOOO", "OOOOOOOoo===== *== *==== *===%* OOOOOOOO", "OOOOOOOoO===== %==% ===* ====X* @OOOOOOO", "OOOOOOO&===X== *==% X==**=====% $OOOOOOO", "OOOOOOoo===== *==* %=====X OOOOOOO", "OOOOOOoO=====*%%X===*%*X======%* @OOOOOO", "OOOOOOo====================X===* $OOOOOO", "OOOOOOO=%X%XXXX%XXXXXXXXX%X=%X% OOOOOO", "OOOOOOO.=********************** OOOOOO", "OOOOOOOOO OOOOOO", "OOOOOOOOO. @OOOOOO", "OOOOOOOOOOOoOOoOoOoOoOoOoOOoOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *int_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #303030", "* c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOO+#.X.##@#OOOOOOOOOOOOOOOOOO", "OOOOOOOO+##@X#O++.#+#.##OOOOOOOOOOOOOOOO", "OOOOOO+#Xo++#X#%#+##o#O#.#+OOOOOOOOOOOOO", "OOOOO.Xo#+#++##+.XX#..+.+..XOOOOOOOOOOOO", "OOOO++.+O.+O##+#.X###..OX#.+X+OOOOOOOOOO", "OOOO#+####O#O##o##+###X#+#+.#..OOOOOOOOO", "OOO.+#o+#+X++++#.#O+#+#X.#+X++X+OOOOOOOO", "OOO.+.+..X+.##X++#++#..+XX#+#X+..OOOOOOO", "OOO##....O+#++#+.++#+X+#+#X..+#+#OOOOOOO", "OOO++#+.+.#+#O+X#X#XX#.++##.#++.X$OOOOOO", "OOOO#+#+.+++#++.+++##+X###+X+X##+&&OOOOO", "OOOO#..#OO#+.##o###.+..++.+#X+#+#& @OOOO", "OOOO.#.#O+#+#O.+++.###+##++###+.# $OOOO", "OOOOOXX+#+#+#o..X##++#+..##.#+### &OOOO", "OOOOOOX#.#X+#+#+#+.#+..+####XX%X% OOOO", "OOOOOOO.%%X.#+#+#.++#+#+#+.%++*+% &OOOO", "OOOOOOOO@& &##+#+.O####.+XXX%%%#% $OOOO", "OOOOOOOOOO. %X.+.#+++XXX*.+++#% $OOOO", "OOOOOOOOOOO@& %%X..#XXX.####%%& $OOOO", "OOOOOOOOOOOOO@$ &XX%%%*.#X%###*& OOOOO", "OOOOOOOOOOOOOOOOO+%%%*%%#.+.#*& @OOOOO", "OOOOOOOOOOOOOOOOOO*%%%*.X##XX& OOOOOO", "OOOOOOOOOOOOOOOOOOOX%%%%X*%& @OOOOOO", "OOOOOOOOOOOOOOOOOOOX%%%%% &@OOOOOOO", "OOOOOOOOOOOOOOOOOOO*%%%X& &$$OOOOOOOOO", "OOOOOOOOOOOOOOOOOOO+%%%* .OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO+*%%% OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%& $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+%%& $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOoOOOOOOOOOOOOOOOO" }; /* XPM */ static char *lawful_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 10 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #606060", "$ c #FFFFFF", "% c #303030", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOo$$$$$$oOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO$$o$$o$$$$$OOOOOOOOOO", "OOOOOOOOOOOOOOOOOOo$$$$$$$o$$ooOOOOOOOOO", "OOOOOOOOOOOOOOOOOO$o$$$o$$$$$$$oOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$$+ .o$$$$$oOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$+%OOOO$o$$$oOOOOOOO", "OOOOOOOOOOOOOOOOO$$o$X@OOOOo$$$ooOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$%OOOOOo$$$..OOOOOOO", "OOOOOOOOOOOOOOOOO$$$$@OOOOo$$oo##OOOOOOO", "OOOOOOOOOOOOOOOO+$$o$$ooOoo$$$o OOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$$$$o$$$$o#%OOOOOOOO", "OOOOOOOOOOOOOOOO+$$o$$o$$$$$o@%OOOOOOOOO", "OOOOOOOOOOOOOOOOO$$$$$$$$o$o.%OOOOOOOOOO", "OOOOOOOOOOOOOOOOOo$$$o$$oo@#%OOOOOOOOOOO", "OOOOOOOOoooooo$$$$$$$$$$$% %OOOOOOOOOOOO", "OOOOOOO$$$$$$$$$$$$o$$o$$$$$$$oOOOOOOOOO", "OOOOOO$$$$$$$$$o$$$$$$$$$$$$o$$oOOOOOOOO", "OOOOOO$$o$ooooo##+o$$+##@oo$$$$$oOOOOOOO", "OOOOOOo$$#% %#$$$+%##%%#ooo$O#OOOOOOO", "OOOOOOOo@##OOOOO+$$$##OOOO#%%##%@OOOOOOO", "OOOOOOOOOOOOOOOOo$$$##OOOOOOO##@OOOOOOOO", "OOOOOOOOOOOOOOOOo$$o##OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+$$$o OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$o$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$$##OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$o%@OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$o OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$oo OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$$o OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$$##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$$##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO$$o##OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo$# @OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO.#@OOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *mod_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOo&&&&&&&&&oXOOOOOOOOOOOOOOO", "OOOOOOOOOOOO+&=========X%@OOOOOOOOOOOOOO", "OOOOOOOOOOOOO&=====X====% @OOOOOOOOOOOOO", "OOOOOOOOOOOOoO==X=======X* OOOOOOOOOOOOO", "OOOOOOOOOOOO&====*%*%*===* $OOOOOOOOOOOO", "OOOOOOOOOOO+&===X ===% *OOOOOOOOOOOO", "OOOOOOOOOOOoO===**=======X* OOOOOOOOOOOO", "OOOOOOOOOOO&===% %=======X% $OOOOOOOOOOO", "OOOOOOOOOOO&===% %*%%=====% *OOOOOOOOOOO", "OOOOOOOOOOoO===* ====X* OOOOOOOOOOO", "OOOOOOOOOO&=========* X===X% $OOOOOOOOOO", "OOOOOOOOO+&=========% *====% *OOOOOOOOOO", "OOOOOOOOOoO===% %=== %====%* OOOOOOOOOO", "OOOOOOOOO&====* *==X===% $OOOOOOOOO", "OOOOOOOOO&======*%*%X=======% *OOOOOOOOO", "OOOOOOOOOo==X===============% OOOOOOOOO", "OOOOOOOOO=XXXXXXXXXX%X%X%X%%% $OOOOOOOO", "OOOOOOOOOO=%**************** $OOOOOOOO", "OOOOOOOOOOO$ $OOOOOOOO", "OOOOOOOOOOOO* *OOOOOOOOO", "OOOOOOOOOOOOOoOOoOoOoOoOoOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *neutral_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 14 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #00B6FF", "= c #303030", "- c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOO.------.OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOO-+O&o.-----OOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+-&o--------.OOOOOOOOO", "OOOOOOOOOOOOOOOOOO-oo----------+OOOOOOOO", "OOOOOOOOOOOOOOOOO+-&--% #-------OOOOOOOO", "OOOOOOOOOOOOOOOOO-OO-X=OOO.-----+OOOOOOO", "OOOOOOOOOOOOOOOOO-oO-%#OOOO.-----OOOOOOO", "OOOOOOOOOOOOOOOOO--O-=OOOOO+---X#OOOOOOO", "OOOOOOOOOOOOOOOOO-oO-XOOOO+OO--=$OOOOOOO", "OOOOOOOOOOOOOOOOO-OO--++OO-&--- OOOOOOOO", "OOOOOOOOOOOOOOOOO-OO-----+oo--%=OOOOOOOO", "OOOOOOOOOOOOOOOOO--O--+o&&o--%=OOOOOOOOO", "OOOOOOOOOOOOOOOOO-oo*-------%=OOOOOOOOOO", "OOOOOOOOOOOOOOOOO-oO------%%=OOOOOOOOOOO", "OOOOOOOO+.+-+.---O&------= =OOOOOOOOOOOO", "OOOOOO+-oo&&&&&&&&------------.OOOOOOOOO", "OOOOOO---------------X-----O&Oo-OOOOOOOO", "OOOOOO---------%=%---%%=%----OO-.OOOOOOO", "OOOOOO---== =%---%=%%===----%XOOOOOOO", "OOOOOOO-#$%OOOOOO-+-%$OOOO%===%=@OOOOOOO", "OOOOOOOOOOOOOOOO.-&-=%OOOOOOO%%#OOOOOOOO", "OOOOOOOOOOOOOOOo-O+-%$OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-%%OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-%$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO-&-=$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO--o-%$OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+-&- .OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-Oo- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-OO- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-oO- OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-OO%%OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO-o-%$OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO---%$OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO--% #OOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOX$@OOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *ovr_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOoO+=+OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOo=#===+OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo=.OO@X=OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo#OO* #X @OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO+=.XX+=#* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO+=O=.=OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOO#.=+OO@ $OOOOOOOOOOOOOO", "OOOOOOOOOooooooooo&O.#+#XooooOOOOOOOOOOO", "OOOOOOOOO&OOoOoOoOOOOOOOOOoO%@OOOOOOOOOO", "OOOOOOOOoO==================X*@OOOOOOOOO", "OOOOOOOO&===================X% @OOOOOOOO", "OOOOOOOO&==%*%*%*%*%*%*%*%*==% *OOOOOOOO", "OOOOOOOoO==%*%%*%%*%%*%*%*%==X* OOOOOOOO", "OOOOOOO&======================* $OOOOOOO", "OOOOOO+&=== ===% *OOOOOOO", "OOOOOOoO======================X* OOOOOOO", "OOOOOO&=======================X% $OOOOOO", "OOOOOOo========================% *OOOOOO", "OOOOOoO===*%X=====%%======%%===X* OOOOOO", "OOOOO&==% %==% *==== %==* $OOOOO", "OOOOO&== *==**== **% *=X% %%* ==% *OOOOO", "OOOOoO==%%==* =* ===% == %=== %=X* OOOOO", "OOOO&=======% =**===% %X %X==* =X% $OOOO", "OOOO&======% %= %==== %% ====* ==% *OOOO", "OOOoO=====% *== *==== %* ====% ==X* OOOO", "OOO&====XX *===**===% X% X=== *===* $OOO", "OO+&====X *====* ===% == *=== %===% *OOO", "OOoO===% %*%*== *** %==% %** ====X* OOO", "OO&====% ==X *====* %====X% $OO", "OO&================================% *OO", "OOo===X============================% OO", "OO=XXXXXXXXXXXX%XXXX%X%X%XXXXX%X%X%% $O", "OOO=%****************************** $O", "OOOO$ $O", "OOOOO* *OO", "OOOOOOOOOOoOOoOOoOOoOOoOOoOOoOOoOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *satiated_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ " c #000000", ". c #949E9E", "X c #F8B090", "o c #5C7A7A", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #914700", "* c #B64700", "= c #909090", "- c #788C8C", "; c #606060", ": c #406868", "> c #FFFFFF", ", c #CEAA90", "< c #DADAB6", "1 c #303030", "2 c #FFB691", "3 c #6C91B6", "4 c #F88C48", /* pixels */ "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "########################################", "################<<<<<<<<################", "##############<<<<<<<<<<$#$$$###########", "############<<<<<<<<<<$:31:3:###########", "###########<<<<<<%42<<#:3:133-##########", "##########<<<<<%<<;;=o$131:33;##########", "#########<<<<<<,1 ::31:33;,#########", "########<<<<<<, =<<<<.13:133;<=########", "########<<<%2, 1<<<<<<#333:33;<,=#######", "#######<<<3-=<33;<<@o######", "#######O<<<<<,#<<<<<<<<.3:<3-;<, =######", "########<<<<2<<<<<<<<<>#31<33o<11#######", "########O<<<<44<>O>>>>>#3:<3.;- =#######", "##########<<<4<<<<><><<$3:<331 ;<#######", "##########<<<<<<<%2<<<<$3:<33 1#########", "###########O,<<<<<<<<<<#31<331##########", "#############.<<<<<<<<<$3:133;##########", "##############=;=,<<<<,o 1;;=##########", "###############<=;1 1;=##############", "#################<# c #B64700", ", c #909090", "< c #788C8C", "1 c #606060", "2 c #406868", "3 c #FFFFFF", "4 c #CEAA90", "5 c #DADAB6", "6 c #303030", "7 c #F86800", "8 c #FFB691", "9 c #6C91B6", "0 c #F88C48", "q c #0000FF", /* pixels */ "****************************************", "*************#333333333#****************", "***********##33333#333333#**************", "**********#33333#33333#33*==************", "*********#33##33-;-3#3333399************", "********#33#33#3-@ 33333#33=.***********", "********#3*#33-;;;;;-33333#99***********", "*******#3*3333-;;;;@ 33#333#9=**********", "*******#333#33#3-;-33#*##33399**********", "******#3#3333333-@-#333#9933*9=*********", "******#333#33#3333333#333*9999=*********", "******#333333333#3#33333333*999*********", "******#3#33#33333333#33#3333#9=*********", "******#333334>&&:&&>::44,3#33#9*********", "******#33*::&41OOO6:4O 0::4433=*********", "******#3:>,0:O0O1O+O:OXO,O+2+OOo4<+1104:>:#*********", "******.&:1OOO,14X2O48:O80,440:,*********", "******4::>OOO%8-X4O4%O,84+O0X&>=********", "******.::>,O 99*X+<$,+.o*1O4&0:*********", "******>:0&4O5qq9#10OO3qq9,+X:1:*********", "****=>,,::,O4qq9X+O>O-qq9O2X0,>*********", "******4:>OOOO48882OOOO+4OOO07*4*********", "******4*,4OO+OXX3O5************", "*********=0%,OO,>:>>O +1OO4*************", "**********=%+OO:::1:::6+:7**************", "***********7&OO:O+O,O1OO+1**************", "***********40OO,O4:OOO11O<5*************", "**********=4 +O1O2+O2+O0O***************", "************72O+1+21-OOO%5**************", "************0%1OOOO+O+174***************", "*************%%O,OO1407-=***************", "**************-$>%0%:74*****************", "****************54044*=*****************", "*****************=*=********************" }; /* XPM */ static char *sick_il_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 23 1", /* colors */ " c #F85848", ". c #949E9E", "X c #F8B090", "o c #E00028", "O c #D4D4D4", "+ c #F87A24", "@ c #7C3400", "# c None", "$ c #B0B0B0", "% c #F89E6C", "& c #FF0000", "* c #914700", "= c #B64700", "- c #909090", "; c #606060", ": c #FFFFFF", "> c #CEAA90", ", c #DADAB6", "< c #F86800", "1 c #FFB691", "2 c #6C91B6", "3 c #F88C48", "4 c #0000FF", /* pixels */ "########################################", "#############O:::::::::O################", "###########OO:::::O::::::O##############", "##########O:::::O:::::O::#$$############", "#########O::OO::%&%:O:::::22############", "########O::O::O:%o :::::O::$.###########", "########O:#O::%&&&&&%:::::O22###########", "#######O:#::::%&&&&o ::O:::O2$##########", "#######O:::O::O:%&%::O#OO:::22##########", "######O:O:::::::%o%O:::O22::#2$#########", "######O:::O::O:::::::O:::#2222$#########", "######O:::::::::O:O::::::::#222#########", "######O:O::O::::::::O::O::::O2$#########", "######O:::::>=@@=**=**>>-:O::O2#########", "######O::#**@3>%* ;=>=3;<@>>::$#########", "######O:** >=>XXXX1X >>+>%*%*;O#########", "######O3@*,X%XXXXXXX>X%XX >*=*O#########", "######.@@3XXXXXXXXXXXXXXX>X>3*-#########", "######>***>X% >XXXXX3XXXXXX%>*=>########", "######.***> 22#XXX<%X22#XXX@+;#########", "######=*3@X>O442OXX==%XX11111O1+%X111XX%<#>#########", "######.,;XXXXXX1O1X%3XXXXX%+3###########", "########3=XXXXXX:XXXXXXXXX+<>$##########", "########>+XXXXXX%-3->XXXX%+<############", "#########%3XXXXXX>- -%XXX%<%$###########", "#########$############", "##########+%XXXXXXXXXXXX%+<#############", "##########%3XXX>=****3XX%<%#############", "##########>+XXX**=3-*@3>3+##############", "###########<%XX >XX%X;%X3+##############", "###########%3XX>XX++XXXX<%$#############", "##########$>+XXXXXXXXXXX<###############", "############<%XXXXXXXXX3+###############", "###########$%+XXXXXXXX%<>###############", "#############++XXXXXX%<%$###############", "#############$%<<3333<%#################", "#################%3>>$##################", "#################$#$####################" }; /* XPM */ static char *slt_enc_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #FFFFFF", "* c #303030", "= c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOoO+OOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOoOXX==OOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoO=OO+==OOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOoXOO.*$=$OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO=+# *.X *OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOO==.OO=+@ $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOXO==.OO $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOO+=@$@* @OOOOOOOOOOOOOO", "OOOOOOOOOOOOOOO&&&&&&&X @OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOo======X*OOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOoO======X**OOOOOOOOOOOOOOO", "OOOOOOOOOOOOOO&====X===% $OOOOOOOOOOOOOO", "OOOOOOOOOOOOOoo==%* %==%* OOOOOOOOOOOOOO", "OOOOOOOOOOOOOoO=% % =X* @OOOOOOOOOOOOO", "OOOOOOOOOOOOO&==**==% %=% $OOOOOOOOOOOOO", "OOOOOOOOOOOOoo==%%==* %=X OOOOOOOOOOOOO", "OOOOOOOOOOOOoO=====* X==X* @OOOOOOOOOOOO", "OOOOOOOOOOOO&=====* %====% $OOOOOOOOOOOO", "OOOOOOOOOOOoo==== X=====%* OOOOOOOOOOOO", "OOOOOOOOOOOo+===* *%*%%==X* @OOOOOOOOOOO", "OOOOOOOOOOO&==== %===% $OOOOOOOOOOO", "OOOOOOOOOOO&==============% OOOOOOOOOOO", "OOOOOOOOOOO==============X% @OOOOOOOOOO", "OOOOOOOOOOO+%%%%%%%%%%%%%% $OOOOOOOOOO", "OOOOOOOOOOOOO% $OOOOOOOOOO", "OOOOOOOOOOOOO@ @OOOOOOOOOO", "OOOOOOOOOOOOOO@$$$$$$$$$$$$$@OOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" }; /* XPM */ static char *str_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 17 1", /* colors */ " c #000000", ". c #F8B090", "X c #5C7A7A", "o c #F87A24", "O c #7C3400", "+ c None", "@ c #B0B0B0", "# c #F89E6C", "$ c #B64700", "% c #909090", "& c #606060", "* c #CEAA90", "= c #DADAB6", "- c #303030", "; c #F86800", ": c #FFB691", "> c #F88C48", /* pixels */ "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "++++++++++++++++++++++++++++++++++++++++", "+++++++++++++++++++*>*>#++++++++++++++++", "++++++++++++++++*#o>..*#o*++++++++++++++", "+++++++++++++++o#.#>.....o++++++++++++++", "+++++++++++++++;>;#.o.>..#$X++++++++++++", "+++++++++++++++o#>.o.>:...o %++++++++++", "++++++++++++++o##>>#o##>..#O -++++++++++", "++++++++++++++>#.oo#>..>...O ++++++++++", "++++++++++++++*o##.>>;o#...o ++++++++++", "+++++++++++++++*;o#........>- &+++++++++", "+++++++++++++++++#>>;o......O -+++++++++", "+++++++++++++++++@+@+o>.....$ +++++++++", "+++++++++++++++++++++*;.#...>- %++++++++", "++++++++++++++++++++++;>o....$ &++++++++", "++++++++++++++++++++++#>>....>- %+++++++", "+++++++++++++++++++++++;#>....; -+++++++", "+++++++++++++++++++++++o#>....>O %++++++", "+++++++++++++++++++++++*>o.....; -++++++", "+++++++++++++#>**+++++++;#.....>O %+++++", "+o#+++++++*o;>>>>o#+++++o##.....; -+++++", "+:#o*++++oo#..*..*>;*+++#>#.....>O %++++", "+:=#o#+*;>.:==:....#;*++@o.......; &++++", "+::..>;o#.=::::......o*++;.......>O ++++", "+.....#o.:.=:.........o#+;........$ ++++", "+......#o..:...........#o;>.......o &+++", "+........#..............*>o......:o- +++", "+..................#o>#...#o.......O +++", "+...............>o>#.......#>......O &++", "+..................................o -++", "+..................................> ++", "+..................................> ++", "+.................................#$ &+", "+................................>$ &+", "+..#>$o>#..............#>;>>>oOOO- ++", "+...#O OOOOO$>>>>>>>$OO %++", "+...o -&&++++", "+..#O -&&%++++++++++", "++++++++++++++++++++++++++++++++++++++++" }; /* XPM */ static char *stunned_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 12 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c #D4D4D4", "O c None", "+ c #B0B0B0", "@ c #909090", "# c #788C8C", "$ c #606060", "% c #406868", "& c #303030", "* c #6C91B6", /* pixels */ "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", "OOOOOOOOOOOO&$OOOO@OOO@@OO@OOOOOOOOOOOOO", "OOOOOOOOOOO@& $OO@&&$$@ O@$$OOOOOOOOOOOO", "OOOOOOOOOOOO$$ @@@$ &&OOO@$OOOOOOOOOOOO", "OOOOOOOOOOOOO@@&$$$$&O$OO$O &@O@OOOOOOOO", "OOOOOO@@@@@@OO@$$O$&$@@OO& &&$O&OOOOOOO", "OOOOOO&&&& & $ &&@$ &O@$& &&&$ & $OOOOOO", "OOOOOO$&OO &&&$ $$ $& $$&$&&&OOOOOOO", "OOOOOO@@O@$ &+ # &O$$ $$&O@OOOOO", "OOOOOOOO@X%$ %& %% & && $$@@@@OOOO", "OOOOOOO+$$@+ &%%%&%& & &@OOO&&OOO", "OOOOOO.Xo%+ &&%%%%%&& & OO@$&&OOO", "OOOOO++ $$&&$ && %&%%& &O@&$&OOOO", "OOOOO####$ X&&& && &%& & &&OOOO", "OOOO++#.+## $&# %& & & &$ OOOO", "OOOO#+++.@&%&& &#&%& & $ @OOOOOO", "OOOO##....#+$#@%#& $%$&@&$$% & X##$@OOOO", "OOOO.+#+.+@#+#+$&$X#%&%.+& %&#++.$&OOOOO", "OOOOO#+#+.+++#$$%&++&X+X#&#+&+&##+ &OOOO", "OOOOO#..#OO#+@%#o##X.@..++.+$&+#+#& @OOO", "OOOOO+#.#O+#+#O@++@$$##+##++###+.#& $OOO", "OOOOOOXX+#+#+#o.@%&$++#+..##.#+### &OOO", "OOOOOOOX#.#X+#+#+##&#+..+####%XX%% OOO", "OOOOOOOO+%%X.#+#+#.++#+#+#+.X++*.% &OOO", "OOOOOOOOO@& &##+#+.O####.+XX%%%%#% $OOO", "OOOOOOOOOOO. %X.+.#+++XXX*.+++#X $OOO", "OOOOOOOOOOOO@& %%X..#X%#.####%X& $OOO", "OOOOOOOOOOOOOO@$ &XX%%%*.#X%###*& OOOO", "OOOOOOOOOOOOOOOOOO+%%%*%%#.+.#*& @OOOO", "OOOOOOOOOOOOOOOOOOO*%%%**X##X%& OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X*X& @OOOOO", "OOOOOOOOOOOOOOOOOOOOX%%%%X &@OOOOOO", "OOOOOOOOOOOOOOOOOOOO*%%%X& &$$OOOOOOOO", "OOOOOOOOOOOOOOOOOOOO+X%%* @OOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOOX%%& OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO*%%% $OOOOOOOOOOOOO", "OOOOOOOOOOOOOOOOOOOOO.X%& $OOOOOOOOOOOOO" }; /* XPM */ static char *wis_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c None", "O c #B0B0B0", "+ c #909090", "@ c #788C8C", "# c #606060", "$ c #406868", "% c #FFFFFF", "& c #303030", "* c #6C91B6", "= c #0000FF", /* pixels */ "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooo+#& &#oooooooooooooooooooo", "oooooooooooo+& #oooooooooooooooooo", "ooooooooooo+ &====&& &ooooooooooooooooo", "oooooooooo+ &==& ===%& +ooooooooooooooo", "ooooooooo+&%=== ===%%o&&oooooooooooooo", "oooooooo.&%%===& ===%o& #+ooooooooooo", "oooo&###&&%%*=======$#&ooo#& #+oooooooo", "ooooo###o+&X$=====& #oo##oooo+######oooo", "oooooooooooo######@oo##ooooooooooooooooo", "oooooooooooooOoOoOo##ooooooooooooooooooo", "ooooooooooooooooo+#+ooo+&#oooooooooooooo", "ooooooooooooooooooooooo#oooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo" }; /* XPM */ static char *nothing_xpm[] = { /* width height ncolors chars_per_pixel */ "40 40 13 1", /* colors */ " c #000000", ". c #949E9E", "X c #5C7A7A", "o c None", "O c #B0B0B0", "+ c #909090", "@ c #788C8C", "# c #606060", "$ c #406868", "% c #FFFFFF", "& c #303030", "* c #6C91B6", "= c #0000FF", /* pixels */ "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo", "oooooooooooooooooooooooooooooooooooooooo" }; nethack-3.4.3/win/gnome/README0100644000000000000000000000331307764735042014435 0ustar rootrootThis directory contains the windowing code written for GnomeHack. The NetHack devteam is in the process of making it part of the normal distribution. It should be noted that this is still work in progress and that there are still problems with this code. So use at your own risk. Of course any contributions, especially bug fixes, are more than welcome! These files are based on the files from GnomeHack 1.0.5 by Erik Andersen. Some files have been renamed to fit into 8.3 name constraints (yuk!). These are: GnomeHack.h gnomeprv.h GnomeHackAskStringDialog.c gnaskstr.c GnomeHackAskStringDialog.h gnaskstr.h GnomeHackBind.c gnbind.c GnomeHackBind.h gnbind.h GnomeHackGlyph.c gnglyph.c GnomeHackGlyph.h gnglyph.h GnomeHackMainWindow.c gnmain.c GnomeHackMainWindow.h gnmain.h GnomeHackMapWindow.c gnmap.c GnomeHackMapWindow.h gnmap.h GnomeHackMenuWindow.c gnmenu.c GnomeHackMenuWindow.h gnmenu.h GnomeHackMessageWindow.c gnmesg.c GnomeHackMessageWindow.h gnmesg.h GnomeHackPlayerSelDialog.c gnplayer.c GnomeHackPlayerSelDialog.h gnplayer.h GnomeHackSettings.c gnopts.c GnomeHackSettings.h gnopts.h GnomeHackSignals.c gnsignal.c GnomeHackSignals.h gnsignal.h GnomeHackStatusWindow.c gnstatus.c GnomeHackStatusWindow.h gnstatus.h GnomeHackTextWindow.c gntext.c GnomeHackTextWindow.h gntext.h GnomeHackYesNoDialog.c gnyesno.c GnomeHackYesNoDialog.h gnyesno.h Other files have been removed because we don't or can't use them (yet). Makefile.am Makefile.in gnomehack.desktop gnomehack.desktop.in NetHack currently doesn't use autoconf, so the setup for that has not made the translation. Note: All loss in style, elegance, and readability is entirely our fault and not Erik's. nethack-3.4.3/win/gnome/gnaskstr.c0100644000000000000000000000264007764735042015557 0ustar rootroot/* SCCS Id: @(#)gnaskstr.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnaskstr.h" #include "gnmain.h" #include static void ghack_ask_string_callback(gchar * string, gpointer data) { char **user_text = (char **) data; g_assert(user_text != NULL); *user_text = string; /* note - value must be g_free'd */ } int ghack_ask_string_dialog(const char *szMessageStr, const char *szDefaultStr, const char *szTitleStr, char *buffer) { int i; GtkWidget* dialog; gchar *user_text = NULL; dialog = gnome_request_dialog(FALSE, szMessageStr, szDefaultStr, 0, ghack_ask_string_callback, &user_text, NULL); g_assert(dialog != NULL); gtk_window_set_title(GTK_WINDOW(dialog), szTitleStr); gnome_dialog_set_default( GNOME_DIALOG(dialog), 0); gtk_window_set_modal( GTK_WINDOW(dialog), TRUE); gnome_dialog_set_parent (GNOME_DIALOG (dialog), GTK_WINDOW (ghack_get_main_window ()) ); i = gnome_dialog_run_and_close (GNOME_DIALOG (dialog)); /* Quit */ if ( i != 0 || user_text == NULL ) { if (user_text) g_free(user_text); return -1; } if ( *user_text == 0 ) { g_free(user_text); return -1; } g_assert(strlen(user_text) > 0); strcpy (buffer, user_text); g_free(user_text); return 0; } nethack-3.4.3/win/gnome/gnaskstr.h0100644000000000000000000000065407764735042015567 0ustar rootroot/* SCCS Id: @(#)gnaskstr.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackAskStringDialog_h #define GnomeHackAskStringDialog_h int ghack_ask_string_dialog(const char *szMessageStr, const char *szDefaultStr, const char *szTitleStr, char *buffer); #endif /* GnomeHackAskStringDialog_h */ nethack-3.4.3/win/gnome/gnbind.c0100644000000000000000000011065407764735042015171 0ustar rootroot/* SCCS Id: @(#)gnbind.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ /* * This file implements the interface between the window port specific * code in the Gnome port and the rest of the nethack game engine. */ #include "gnbind.h" #include "gnmain.h" #include "gnmenu.h" #include "gnaskstr.h" #include "gnyesno.h" GNHWinData gnome_windowlist[MAXWINDOWS]; winid WIN_WORN = WIN_ERR; extern void tty_raw_print(const char *); extern void tty_raw_print_bold(const char *); /* Interface definition, for windows.c */ struct window_procs Gnome_procs = { "Gnome", WC_COLOR|WC_HILITE_PET|WC_INVERSE, 0L, gnome_init_nhwindows, gnome_player_selection, gnome_askname, gnome_get_nh_event, gnome_exit_nhwindows, gnome_suspend_nhwindows, gnome_resume_nhwindows, gnome_create_nhwindow, gnome_clear_nhwindow, gnome_display_nhwindow, gnome_destroy_nhwindow, gnome_curs, gnome_putstr, gnome_display_file, gnome_start_menu, gnome_add_menu, gnome_end_menu, gnome_select_menu, genl_message_menu, /* no need for X-specific handling */ gnome_update_inventory, gnome_mark_synch, gnome_wait_synch, #ifdef CLIPPING gnome_cliparound, #endif #ifdef POSITIONBAR donull, #endif gnome_print_glyph, gnome_raw_print, gnome_raw_print_bold, gnome_nhgetch, gnome_nh_poskey, gnome_nhbell, gnome_doprev_message, gnome_yn_function, gnome_getlin, gnome_get_ext_cmd, gnome_number_pad, gnome_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ donull, donull, #endif /* other defs that really should go away (they're tty specific) */ gnome_start_screen, gnome_end_screen, gnome_outrip, genl_preference_update, }; /* init_nhwindows(int* argcp, char** argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. -- Any commandline arguments relevant to the windowport should be interpreted, and *argcp and *argv should be changed to remove those arguments. -- When the message window is created, the variable iflags.window_inited needs to be set to TRUE. Otherwise all plines() will be done via raw_print(). ** Why not have init_nhwindows() create all of the "standard" ** windows? Or at least all but WIN_INFO? -dean */ void gnome_init_nhwindows(int* argc, char** argv) { /* Main window */ ghack_init_main_window( *argc, argv); ghack_init_signals( ); #ifdef HACKDIR //if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm")) if (ghack_init_glyphs(HACKDIR "/x11tiles")) g_error ("ERROR: Could not initialize glyphs.\n"); #else # error HACKDIR is not defined! #endif // gnome/gtk is not reentrant set_option_mod_status("ignintr", DISP_IN_GAME); flags.ignintr = TRUE; iflags.window_inited = TRUE; /* gnome-specific window creation */ WIN_WORN = gnome_create_nhwindow(NHW_WORN); } /* Do a window-port specific player type selection. If player_selection() offers a Quit option, it is its responsibility to clean up and terminate the process. You need to fill in pl_character[0]. */ void gnome_player_selection() { int n, i, sel; const char** choices; int* pickmap; /* prevent an unnecessary prompt */ rigid_role_checks(); if (!flags.randomall && flags.initrole < 0) { /* select a role */ for (n = 0; roles[n].name.m; n++) continue; choices = (const char **)alloc(sizeof(char *) * (n+1)); pickmap = (int*)alloc(sizeof(int) * (n+1)); for (;;) { for (n = 0, i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { if (flags.initgend >= 0 && flags.female && roles[i].name.f) choices[n] = roles[i].name.f; else choices[n] = roles[i].name.m; pickmap[n++] = i; } } if (n > 0) break; else if (flags.initalign >= 0) flags.initalign = -1; /* reset */ else if (flags.initgend >= 0) flags.initgend = -1; else if (flags.initrace >= 0) flags.initrace = -1; else panic("no available ROLE+race+gender+alignment combinations"); } choices[n] = (const char *) 0; if (n > 1) sel = ghack_player_sel_dialog(choices, _("Player selection"), _("Choose one of the following roles:")); else sel = 0; if (sel >= 0) sel = pickmap[sel]; else if (sel == ROLE_NONE) { /* Quit */ clearlocks(); gnome_exit_nhwindows(0); } free(choices); free(pickmap); } else if (flags.initrole < 0) sel = ROLE_RANDOM; else sel = flags.initrole; if (sel == ROLE_RANDOM) { /* Random role */ sel = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (sel < 0) sel = randrole(); } flags.initrole = sel; /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { if (flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) flags.initrace = randrace(flags.initrole); } else { /* Count the number of valid races */ n = 0; /* number valid */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) n++; } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) n++; } } choices = (const char **)alloc(sizeof(char *) * (n+1)); pickmap = (int*)alloc(sizeof(int) * (n + 1)); for (n = 0, i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { choices[n] = races[i].noun; pickmap[n++] = i; } } choices[n] = (const char *) 0; /* Permit the user to pick, if there is more than one */ if (n > 1) sel = ghack_player_sel_dialog(choices, _("Race selection"), _("Choose one of the following races:")); else sel = 0; if (sel >= 0) sel = pickmap[sel]; else if (sel == ROLE_NONE) { /* Quit */ clearlocks(); gnome_exit_nhwindows(0); } flags.initrace = sel; free(choices); free(pickmap); } if (flags.initrace == ROLE_RANDOM) { /* Random role */ sel = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (sel < 0) sel = randrace(flags.initrole); flags.initrace = sel; } } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { if (flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) flags.initgend = randgend(flags.initrole, flags.initrace); } else { /* Count the number of valid genders */ n = 0; /* number valid */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) n++; } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) n++; } } choices = (const char **)alloc(sizeof(char *) * (n+1)); pickmap = (int*)alloc(sizeof(int) * (n + 1)); for (n = 0, i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { choices[n] = genders[i].adj; pickmap[n++] = i; } } choices[n] = (const char *) 0; /* Permit the user to pick, if there is more than one */ if (n > 1) sel = ghack_player_sel_dialog(choices, _("Gender selection"), _("Choose one of the following genders:")); else sel = 0; if (sel >= 0) sel = pickmap[sel]; else if (sel == ROLE_NONE) { /* Quit */ clearlocks(); gnome_exit_nhwindows(0); } flags.initgend = sel; free(choices); free(pickmap); } if (flags.initgend == ROLE_RANDOM) { /* Random gender */ sel = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (sel < 0) sel = randgend(flags.initrole, flags.initrace); flags.initgend = sel; } } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { if (flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) flags.initalign = randalign(flags.initrole, flags.initrace); } else { /* Count the number of valid alignments */ n = 0; /* number valid */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) n++; } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) if (validalign(flags.initrole, flags.initrace, i)) n++; } choices = (const char **)alloc(sizeof(char *) * (n+1)); pickmap = (int*)alloc(sizeof(int) * (n + 1)); for (n = 0, i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { choices[n] = aligns[i].adj; pickmap[n++] = i; } } choices[n] = (const char *) 0; /* Permit the user to pick, if there is more than one */ if (n > 1) sel = ghack_player_sel_dialog(choices, _("Alignment selection"), _("Choose one of the following alignments:")); else sel = 0; if (sel >= 0) sel = pickmap[sel]; else if (sel == ROLE_NONE) { /* Quit */ clearlocks(); gnome_exit_nhwindows(0); } flags.initalign = sel; free(choices); free(pickmap); } if (flags.initalign == ROLE_RANDOM) { sel = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (sel < 0) sel = randalign(flags.initrole, flags.initrace); flags.initalign = sel; } } } /* Ask the user for a player name. */ void gnome_askname() { int ret; g_message("Asking name...."); /* Ask for a name and stuff the response into plname, a nethack global */ ret = ghack_ask_string_dialog("What is your name?", "gandalf", "GnomeHack", plname); /* Quit if they want to quit... */ if (ret==-1) { gnome_exit_nhwindows(0); } } /* Does window event processing (e.g. exposure events). A noop for the tty and X window-ports. */ void gnome_get_nh_event() { /* We handle our own events. */ return; } /* Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. */ void gnome_exit_nhwindows(const char *str) { gtk_exit (0); terminate(EXIT_SUCCESS); } /* Prepare the window to be suspended. */ void gnome_suspend_nhwindows(const char *str) { /* I don't think we need to do anything here... */ return; } /* Restore the windows after being suspended. */ void gnome_resume_nhwindows() { /* Do Nothing. Un-necessary since the GUI will refresh itself. */ return; } /* Create a window of type "type" which can be NHW_MESSAGE (top line) NHW_STATUS (bottom lines) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) */ winid gnome_create_nhwindow(int type) { winid i = 0; /* Return the next available winid */ for (i=0; i= 0) && (wid < MAXWINDOWS) && (gnome_windowlist[wid].win != NULL)) { gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win), ghack_signals[GHSIG_PUTSTR], (guint) attr, text); } } /* Display the file named str. Complain about missing files iff complain is TRUE. */ void gnome_display_file(const char *filename,BOOLEAN_P must_exist) { /* Strange -- for some reason it makes us create a new text window * instead of reusing any existing ones -- perhaps we can work out * some way to reuse stuff -- but for now just make and destroy new * ones each time */ dlb *f; f = dlb_fopen(filename, "r"); if (!f) { if (must_exist) { GtkWidget *box; char message[90]; sprintf(message, "Warning! Could not find file: %s\n",filename); box = gnome_message_box_new (_(message), GNOME_MESSAGE_BOX_ERROR, GNOME_STOCK_BUTTON_OK, NULL); gnome_dialog_set_default( GNOME_DIALOG(box), 0); gnome_dialog_set_parent (GNOME_DIALOG (box), GTK_WINDOW (ghack_get_main_window ()) ); gtk_window_set_modal( GTK_WINDOW(box), TRUE); gtk_widget_show (box); } } else { GtkWidget *txtwin, *gless, *frametxt; #define LLEN 128 char line[LLEN], *textlines; int num_lines, charcount; txtwin = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK, NULL); gtk_widget_set_usize(GTK_WIDGET(txtwin), 500, 400); gtk_window_set_policy(GTK_WINDOW(txtwin), TRUE, TRUE, FALSE); gtk_window_set_title(GTK_WINDOW(txtwin), "Text Window"); gnome_dialog_set_default( GNOME_DIALOG(txtwin), 0); gtk_window_set_modal( GTK_WINDOW(txtwin), TRUE); frametxt = gtk_frame_new (""); gtk_widget_show (frametxt); /* * Count the number of lines and characters in the file. */ num_lines = 0; charcount = 1; while (dlb_fgets(line, LLEN, f)) { num_lines++; charcount += strlen(line); } (void) dlb_fclose(f); /* Ignore empty files */ if (num_lines == 0) return; /* * Re-open the file and read the data into a buffer. */ textlines = (char *) alloc((unsigned int) charcount); textlines[0] = '\0'; f = dlb_fopen( filename, RDTMODE); while (dlb_fgets(line, LLEN, f)) { (void) strcat(textlines, line); } (void) dlb_fclose(f); gless = gnome_less_new (); gnome_less_show_string (GNOME_LESS (gless), textlines); gtk_container_add (GTK_CONTAINER (frametxt), gless); gtk_box_pack_start(GTK_BOX (GNOME_DIALOG (txtwin)->vbox), frametxt, TRUE, TRUE, 0); gtk_widget_show_all( txtwin); gtk_window_set_modal( GTK_WINDOW(txtwin), TRUE); gnome_dialog_set_parent (GNOME_DIALOG (txtwin), GTK_WINDOW (ghack_get_main_window ()) ); gnome_dialog_run_and_close (GNOME_DIALOG (txtwin)); free(textlines); } } /* Start using window as a menu. You must call start_menu() before add_menu(). After calling start_menu() you may not putstr() to the window. Only windows of type NHW_MENU may be used for menus. */ void gnome_start_menu(winid wid) { if (wid != -1) { if (gnome_windowlist[wid].win == NULL && gnome_windowlist[wid].type != 0) { gnome_create_nhwindow_by_id(gnome_windowlist[wid].type, wid); } gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win), ghack_signals[GHSIG_START_MENU]); } } /* add_menu(windid window, int glyph, const anything identifier, char accelerator, char groupacc, int attr, char *str, boolean preselected) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable item is 0, the window system is free to select its own accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). Glyph is an optional glyph to accompany the line. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z]. -- It is expected that callers do not mix accelerator choices. Either all selectable items have an accelerator or let the window system pick them. Don't do both. -- Groupacc is a group accelerator. It may be any character outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with the menu command (or their user defined alises), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the menu is displayed, set preselected to TRUE. */ void gnome_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel) { GHackMenuItem item; item.glyph = glyph; item.identifier = identifier; item.accelerator = accelerator; item.group_accel = group_accel; item.attr = attr; item.str = str; item.presel = presel; if (wid != -1 && gnome_windowlist[wid].win != NULL) { gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win), ghack_signals[GHSIG_ADD_MENU], &item); } } /* end_menu(window, prompt) -- Stop adding entries to the menu and flushes the window to the screen (brings to front?). Prompt is a prompt to give the user. If prompt is NULL, no prompt will be printed. ** This probably shouldn't flush the window any more (if ** it ever did). That should be select_menu's job. -dean */ void gnome_end_menu(winid wid, const char *prompt) { if (wid != -1 && gnome_windowlist[wid].win != NULL) { gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win), ghack_signals[GHSIG_END_MENU], prompt); } } /* int select_menu(windid window, int how, menu_item **selected) -- Return the number of items selected; 0 if none were chosen, -1 when explicitly cancelled. If items were selected, then selected is filled in with an allocated array of menu_item structures, one for each selected line. The caller must free this array when done with it. The "count" field of selected is a user supplied count. If the user did not supply a count, then the count field is filled with -1 (meaning all). A count of zero is equivalent to not being selected and should not be in the list. If no items were selected, then selected is NULL'ed out. How is the mode of the menu. Three valid values are PICK_NONE, PICK_ONE, and PICK_N, meaning: nothing is selectable, only one thing is selectable, and any number valid items may selected. If how is PICK_NONE, this function should never return anything but 0 or -1. -- You may call select_menu() on a window multiple times -- the menu is saved until start_menu() or destroy_nhwindow() is called on the window. -- Note that NHW_MENU windows need not have select_menu() called for them. There is no way of knowing whether select_menu() will be called for the window at create_nhwindow() time. */ int gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected) { int nReturned = -1; if (wid != -1 && gnome_windowlist[wid].win != NULL && gnome_windowlist[wid].type == NHW_MENU) { nReturned=ghack_menu_window_select_menu (gnome_windowlist[wid].win, selected, how); } return nReturned; } /* -- Indicate to the window port that the inventory has been changed. -- Merely calls display_inventory() for window-ports that leave the window up, otherwise empty. */ void gnome_update_inventory() { ghack_main_window_update_inventory(); } /* mark_synch() -- Don't go beyond this point in I/O on any channel until all channels are caught up to here. Can be an empty call for the moment */ void gnome_mark_synch() { /* Do nothing */ } /* wait_synch() -- Wait until all pending output is complete (*flush*() for streams goes here). -- May also deal with exposure events etc. so that the display is OK when return from wait_synch(). */ void gnome_wait_synch() { /* Do nothing */ } /* cliparound(x, y)-- Make sure that the user is more-or-less centered on the screen if the playing area is larger than the screen. -- This function is only defined if CLIPPING is defined. */ void gnome_cliparound(int x, int y) { /* FIXME!!! winid should be a parameter!!! * Call a function that Does The Right Thing(tm). */ gnome_cliparound_proper(WIN_MAP,x,y); } void gnome_cliparound_proper(winid wid, int x, int y) { if (wid != -1 && gnome_windowlist[wid].win != NULL) { gtk_signal_emit( GTK_OBJECT (gnome_windowlist[wid].win), ghack_signals[GHSIG_CLIPAROUND], (guint) x, (guint) y); } } /* print_glyph(window, x, y, glyph) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). */ void gnome_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph) { if (wid != -1 && gnome_windowlist[wid].win != NULL) { GdkImlibImage *im; im = ghack_image_from_glyph( glyph, FALSE); gtk_signal_emit (GTK_OBJECT (gnome_windowlist[wid].win), ghack_signals[GHSIG_PRINT_GLYPH], (guint) x, (guint) y, im, NULL); } } /* raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. It need not recognize ASCII control characters. This is used during startup (before windowing system initialization -- maybe this means only error startup messages are raw), for error messages, and maybe other "msg" uses. E.g. updating status for micros (i.e, "saving"). */ void gnome_raw_print(const char *str) { tty_raw_print(str); } /* raw_print_bold(str) -- Like raw_print(), but prints in bold/standout (if possible). */ void gnome_raw_print_bold(const char *str) { tty_raw_print_bold(str); } /* int nhgetch() -- Returns a single character input from the user. -- In the tty window-port, nhgetch() assumes that tgetch() will be the routine the OS provides to read a character. Returned character _must_ be non-zero. */ int gnome_nhgetch() { int key; GList *theFirst; gtk_signal_emit (GTK_OBJECT (gnome_windowlist[WIN_STATUS].win), ghack_signals[GHSIG_FADE_HIGHLIGHT]); g_askingQuestion = 1; /* Process events until a key press event arrives. */ while ( g_numKeys == 0 ) gtk_main_iteration(); theFirst = g_list_first( g_keyBuffer); g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst); key = GPOINTER_TO_INT( theFirst->data); g_list_free_1( theFirst); g_numKeys--; g_askingQuestion = 0; return ( key); } /* int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of CLICK_1 -- mouse click type 1 CLICK_2 -- mouse click type 2 The different click types can map to whatever the hardware supports. If no mouse is supported, this routine always returns a non-zero character. */ int gnome_nh_poskey(int *x, int *y, int *mod) { gtk_signal_emit (GTK_OBJECT (gnome_windowlist[WIN_STATUS].win), ghack_signals[GHSIG_FADE_HIGHLIGHT]); g_askingQuestion = 0; /* Process events until a key or map-click arrives. */ while ( g_numKeys == 0 && g_numClicks == 0 ) gtk_main_iteration(); if (g_numKeys > 0) { int key; GList *theFirst; theFirst = g_list_first( g_keyBuffer); g_keyBuffer = g_list_remove_link(g_keyBuffer, theFirst); key = GPOINTER_TO_INT( theFirst->data); g_list_free_1( theFirst); g_numKeys--; return ( key); } else { GHClick *click; GList *theFirst; theFirst = g_list_first( g_clickBuffer); g_clickBuffer = g_list_remove_link(g_clickBuffer, theFirst); click = (GHClick*) theFirst->data; *x=click->x; *y=click->y; *mod=click->mod; g_free( click); g_list_free_1( theFirst); g_numClicks--; return ( 0); } } /* nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] */ void gnome_nhbell() { /* FIXME!!! Play a cool GNOME sound instead */ gdk_beep(); } /* doprev_message() -- Display previous messages. Used by the ^P command. -- On the tty-port this scrolls WIN_MESSAGE back one line. */ int gnome_doprev_message() { /* Do Nothing. They can read old messages using the scrollbar. */ return 0; } /* char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in choices or default. If choices is NULL, all possible inputs are accepted and returned. This overrides everything else. The choices are expected to be in lower case. Entering ESC always maps to 'q', or 'n', in that order, if present in choices, otherwise it maps to default. Entering any other quit character (SPACE, RETURN, NEWLINE) maps to default. -- If the choices string contains ESC, then anything after it is an acceptable response, but the ESC and whatever follows is not included in the prompt. -- If the choices string contains a '#' then accept a count. Place this value in the global "yn_number" and return '#'. -- This uses the top line in the tty window-port, other ports might use a popup. */ char gnome_yn_function(const char *question, const char *choices, CHAR_P def) { int ch; int result=-1; char message[BUFSZ]; char yn_esc_map='\033'; GtkWidget *mainWnd = ghack_get_main_window(); if (choices) { char *cb, choicebuf[QBUFSZ]; Strcpy(choicebuf, choices); if ((cb = index(choicebuf, '\033')) != 0) { /* anything beyond is hidden */ *cb = '\0'; } sprintf(message, "%s [%s] ", question, choicebuf); if (def) sprintf(eos(message), "(%c) ", def); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); } gnome_putstr(WIN_MESSAGE, ATR_BOLD, message); if (mainWnd != NULL && choices && !index(choices,ch)) { return(ghack_yes_no_dialog( question, choices, def)); } /* Only here if main window is not present */ while (result<0) { ch=gnome_nhgetch(); if (ch=='\033') { result=yn_esc_map; } else if (choices && !index(choices,ch)) { /* FYI: ch==-115 is for KP_ENTER */ if (def && (ch==' ' || ch=='\r' || ch=='\n' || ch==-115)) { result=def; } else { gnome_nhbell(); /* and try again... */ } } else { result=ch; } } return result; } /* getlin(const char *ques, char *input) -- Prints ques as a prompt and reads a single line of text, up to a newline. The string entered is returned without the newline. ESC is used to cancel, in which case the string "\033\000" is returned. -- getlin() must call flush_screen(1) before doing anything. -- This uses the top line in the tty window-port, other ports might use a popup. */ void gnome_getlin(const char *question, char *input) { int ret; ret = ghack_ask_string_dialog(question, "", "nethack", input); if (ret == -1) input[0] = 0; } /* int get_ext_cmd(void) -- Get an extended command in a window-port specific way. An index into extcmdlist[] is returned on a successful selection, -1 otherwise. */ int gnome_get_ext_cmd() { return ghack_menu_ext_cmd(); } /* number_pad(state) -- Initialize the number pad to the given state. */ void gnome_number_pad(int state) { /* Do Nothing */ } /* delay_output() -- Causes a visible delay of 50ms in the output. Conceptually, this is similar to wait_synch() followed by a nap(50ms), but allows asynchronous operation. */ void gnome_delay_output() { if (gnome_windowlist[WIN_MESSAGE].win != NULL) { gtk_signal_emit( GTK_OBJECT (gnome_windowlist[WIN_MESSAGE].win), ghack_signals[GHSIG_DELAY], (guint) 50); } } /* start_screen() -- Only used on Unix tty ports, but must be declared for completeness. Sets up the tty to work in full-screen graphics mode. Look at win/tty/termcap.c for an example. If your window-port does not need this function just declare an empty function. */ void gnome_start_screen() { /* Do Nothing */ } /* end_screen() -- Only used on Unix tty ports, but must be declared for completeness. The complement of start_screen(). */ void gnome_end_screen() { /* Do Nothing */ } /* outrip(winid, int) -- The tombstone code. If you want the traditional code use genl_outrip for the value and check the #if in rip.c. */ void gnome_outrip(winid wid, int how) { /* Follows roughly the same algorithm as genl_outrip() */ char buf[BUFSZ]; char ripString[BUFSZ]="\0"; extern const char *killed_by_prefix[]; /* Put name on stone */ Sprintf(buf, "%s\n", plname); Strcat(ripString, buf); /* Put $ on stone */ Sprintf(buf, "%ld Au\n", #ifndef GOLDOBJ u.ugold); #else done_money); #endif Strcat(ripString, buf); /* Put together death description */ switch (killer_format) { default: impossible("bad killer format?"); case KILLED_BY_AN: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, an(killer)); break; case KILLED_BY: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, killer); break; case NO_KILLER_PREFIX: Strcpy(buf, killer); break; } /* Put death type on stone */ Strcat(ripString, buf); Strcat(ripString, "\n"); /* Put year on stone */ Sprintf(buf, "%4d\n", getyear()); Strcat(ripString, buf); ghack_text_window_rip_string( ripString); } nethack-3.4.3/win/gnome/gnbind.h0100644000000000000000000000562507764735042015177 0ustar rootroot/* SCCS Id: @(#)gnbind.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackBind_h #define GnomeHackBind_h /* * This header files defines the interface between the window port specific * code in the Gnome port and the rest of the nethack game engine. */ #include #include #include "gnomeprv.h" #include "gnmain.h" #include "gnmap.h" #include "gnmenu.h" #include "gnplayer.h" #include "gnsignal.h" #include "gnstatus.h" #include "gntext.h" #include "gnmesg.h" #include "gnyesno.h" #include "gnglyph.h" #include "gnworn.h" /* Create an array to keep track of the various windows */ #ifndef MAXWINDOWS #define MAXWINDOWS 15 #endif typedef struct gnome_nhwindow_data { GtkWidget* win; int type; } GNHWinData; /* Some prototypes */ void gnome_init_nhwindows(int* argc, char** argv); void gnome_player_selection(void); void gnome_askname(void); void gnome_get_nh_event(void); void gnome_exit_nhwindows(const char *); void gnome_suspend_nhwindows(const char *); void gnome_resume_nhwindows(void); winid gnome_create_nhwindow(int type); void gnome_create_nhwindow_by_id(int type, winid i); void gnome_clear_nhwindow(winid wid); void gnome_display_nhwindow(winid wid, BOOLEAN_P block); void gnome_destroy_nhwindow(winid wid); void gnome_curs(winid wid, int x, int y); void gnome_putstr(winid wid, int attr, const char *text); void gnome_display_file(const char *filename,BOOLEAN_P must_exist); void gnome_start_menu(winid wid); void gnome_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel); void gnome_end_menu(winid wid, const char *prompt); int gnome_select_menu(winid wid, int how, MENU_ITEM_P **selected); /* No need for message_menu -- we'll use genl_message_menu instead */ void gnome_update_inventory(void); void gnome_mark_synch(void); void gnome_wait_synch(void); void gnome_cliparound(int x, int y); /* The following function does the right thing. The nethack * gnome_cliparound (which lacks the winid) simply calls this funtion. */ void gnome_cliparound_proper(winid wid, int x, int y); void gnome_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph); void gnome_raw_print(const char *str); void gnome_raw_print_bold(const char *str); int gnome_nhgetch(void); int gnome_nh_poskey(int *x, int *y, int *mod); void gnome_nhbell(void); int gnome_doprev_message(void); char gnome_yn_function(const char *question, const char *choices, CHAR_P def); void gnome_getlin(const char *question, char *input); int gnome_get_ext_cmd(void); void gnome_number_pad(int state); void gnome_delay_output(void); void gnome_start_screen(void); void gnome_end_screen(void); void gnome_outrip(winid wid, int how); void gnome_delete_nhwindow_by_reference( GtkWidget *menuWin); #endif /* GnomeHackBind_h */ nethack-3.4.3/win/gnome/gnglyph.c0100644000000000000000000001373407764735042015401 0ustar rootroot/* SCCS Id: @(#)gnglyph.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnglyph.h" #include "tile2x11.h" /* from tile.c */ extern int total_tiles_used; static GHackGlyphs ghack_glyphs; static GdkImlibImage** ghack_tiles = NULL; /* NAME: * ghack_init_glyphs(char* xpm_file) * * ARGUMENTS: * char *xpm_file -- The name of the image file. * May be any image format imlib recognizes. * Does not have to be XPM. * * RETURNS: * TRUE upon successful loading of the glyphs. * FALSE upon failure. * * PURPOSE: * Constructor for the Glyph object. Well, really each glyph * object is a collection of glyphs, or tiles. This constructor * takes a single argument: the name of the image file that contains * the tile images. * * NOTES: * The glyphs (tiles) must be in the image in a certain way: the * glyphs must be stacked such that the resultant image is * TILE_X * TILES_PER_ROW wide, and * TILE_Y * (number of glyphs) / TILES_PER_ROW high (rounded up). * In this sense, TILE_X == TILE_Y, and can be any reasonable integer * say, 16 <= TILE_X <= 64. Because the glyph number is tightly * coupled to the Nethack object it represents, the order of the * glyphs in the image is imporant: Glyph 1 is at the top of the * image, while Glyph N (the last glyph) is at the bottom. * * What's the difference between a glyph and a tile? Well, a * tile is just an image. A glyph is a tile that knows its * place in line. * * This initializer relies heavily on gdk_imlib. Thanks, Rasterman. */ int ghack_init_glyphs(const char *xpmFile) { ghack_glyphs.im = gdk_imlib_load_image((char *) xpmFile); if ( ! ghack_glyphs.im ) { g_error("Couldn't load required xpmFile!"); return -1; } gdk_imlib_render(ghack_glyphs.im, ghack_glyphs.im->rgb_width, ghack_glyphs.im->rgb_height); if ((ghack_glyphs.im->rgb_width % TILES_PER_ROW) != 0 || ghack_glyphs.im->rgb_width <= TILES_PER_ROW) { g_error("%s is not a multiple of %d (number of tiles/row) pixels wide", xpmFile, TILES_PER_ROW); return -1; } ghack_glyphs.count = total_tiles_used; if ((ghack_glyphs.count % TILES_PER_ROW) != 0) { ghack_glyphs.count += TILES_PER_ROW - (ghack_glyphs.count % TILES_PER_ROW); } ghack_glyphs.width = ghack_glyphs.im->rgb_width / TILES_PER_ROW; ghack_glyphs.height = ghack_glyphs.im->rgb_height / (ghack_glyphs.count / TILES_PER_ROW); /* Assume the tiles are organized in rows of TILES_PER_ROW */ ghack_tiles = g_new0( GdkImlibImage*, ghack_glyphs.count ); return (ghack_tiles == NULL) ? -1 : 0; } void ghack_free_glyphs( ) { int i; for ( i=0 ; i= ghack_glyphs.count || tile < 0 ) { g_warning("Aiiee! I've was asked for a tile outside the allowed range!\n" "Email this to other-gnomehack@lists.debian.org"); g_warning("Max tile: %d Tile asked for: %d", ghack_glyphs.count, tile); return NULL; } if (ghack_glyphs.im == NULL) { g_warning("Aiiee! I've been asked to clone from a null image.\n" "Email this to other-gnomehack@lists.debian.org"); g_warning( "making image from tile %d, force=%s\n", tile, (force==TRUE)? "TRUE": "FALSE"); } if (force == TRUE) { g_warning("Aiiee! I've been asked to force rendering.\n" "Email this to other-gnomehack@lists.debian.org"); g_warning( "making image from tile %d, force=%s\n", tile, (force==TRUE)? "TRUE" : "FALSE"); } if (!ghack_tiles[tile] || force) { int src_x, src_y; #if 0 fprintf( stderr, "crop_and_clone: glyph=%d, tile=%d, ptr=%p, x=%d, y=%d, w=%d, h=%d\n", glyph, tile, (void*)&(ghack_tiles[tile]), 0, tile * ghack_glyphs.width, ghack_glyphs.height, ghack_glyphs.width); #endif if (ghack_glyphs.im->pixmap == NULL) g_warning( "Aiiee! ghack_glyphs.im->pixmap==NULL!!!!\n"); src_x = (tile % TILES_PER_ROW) * ghack_glyphs.width; src_y = (tile / TILES_PER_ROW) * ghack_glyphs.height; ghack_tiles[tile] = gdk_imlib_crop_and_clone_image(ghack_glyphs.im, src_x, src_y, ghack_glyphs.width, ghack_glyphs.height); } if (ghack_tiles[tile] && (!ghack_tiles[tile]->pixmap || force)) { if ( gdk_imlib_render(ghack_tiles[tile], ghack_tiles[tile]->rgb_width, ghack_tiles[tile]->rgb_height) == 0) { g_error("GLYPH: couldn't create tile # %d", tile); } if ( !ghack_tiles[tile]->pixmap ) g_error("Strange, tile # %d didn't get rendered???", tile); } return ghack_tiles[tile]; } nethack-3.4.3/win/gnome/gnglyph.h0100644000000000000000000000216407764735042015401 0ustar rootroot/* SCCS Id: @(#)gnglyph.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackGlyph_h #define GnomeHackGlyph_h #include "config.h" #include "global.h" /* the prototypes in system headers contain useless argument names that trigger spurious warnings if gcc's `-Wshadow' option is used */ #undef index #define index _hide_index_ #define time _hide_time_ #include #include #undef index #define index strchr #undef time extern short glyph2tile[]; /* From tile.c */ typedef struct { GdkImlibImage* im; int count; int width; int height; } GHackGlyphs; extern int ghack_init_glyphs( const char *); extern void ghack_free_glyphs( void); extern void ghack_dispose_glyphs( void); extern int ghack_glyph_count( void); extern GdkImlibImage* ghack_image_from_glyph( int, gboolean); extern int ghack_glyph_height( void); extern int ghack_glyph_width( void); #endif /* GnomeHackGlyph_h */ nethack-3.4.3/win/gnome/gnmain.c0100644000000000000000000006261407764735042015203 0ustar rootroot/* SCCS Id: @(#)gnmain.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnmain.h" #include "gnsignal.h" #include "gnbind.h" #include "gnopts.h" #include #include #include #include #include #include #include "hack.h" #include "date.h" static GtkWidget* mainWindow=NULL; static GtkWidget *about=NULL; static GtkWidget* hBoxFirstRow; static GtkWidget* vBoxMain; int restarted = 0; int os_x = 0, os_y = 0, os_w = 0, os_h = 0; static GnomeClient *session_id; static void ghack_quit_game(GtkWidget *widget, int button) { gtk_widget_hide(widget); if (button == 0) { gnome_exit_nhwindows(0); gtk_object_unref(GTK_OBJECT(session_id)); } } static void ghack_quit_game_cb(GtkWidget *widget, gpointer data) { GtkWidget *box; box = gnome_message_box_new(_("Do you really want to quit?"), GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); gnome_dialog_set_default( GNOME_DIALOG(box), 1); gnome_dialog_set_parent (GNOME_DIALOG (box), GTK_WINDOW (ghack_get_main_window ()) ); gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0); gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0); gtk_window_set_modal( GTK_WINDOW(box), TRUE); gtk_signal_connect( GTK_OBJECT(box), "clicked", (GtkSignalFunc)ghack_quit_game, NULL); gtk_widget_show(box); } static void ghack_save_game(GtkWidget *widget, int button) { gtk_widget_hide(widget); if (button == 0) { if(dosave0()) { /* make sure they see the Saving message */ display_nhwindow(WIN_MESSAGE, TRUE); gnome_exit_nhwindows("Be seeing you..."); } else (void)doredraw(); } } void ghack_save_game_cb(GtkWidget *widget, gpointer data) { GtkWidget *box; box = gnome_message_box_new(_("Quit and save the current game?"), GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); gnome_dialog_set_default( GNOME_DIALOG(box), 1); gnome_dialog_set_parent (GNOME_DIALOG (box), GTK_WINDOW (ghack_get_main_window ()) ); gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0); gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0); gtk_window_set_modal( GTK_WINDOW(box), TRUE); gtk_signal_connect( GTK_OBJECT(box), "clicked", (GtkSignalFunc)ghack_save_game, NULL); gtk_widget_show(box); } static void ghack_new_game(GtkWidget *widget, int button) { if (button == 0) { g_message("This feature is not yet implemented. Sorry."); } } static void ghack_new_game_cb(GtkWidget *widget, gpointer data) { GtkWidget *box; box = gnome_message_box_new(_("Start a new game?"), GNOME_MESSAGE_BOX_QUESTION, GNOME_STOCK_BUTTON_YES, GNOME_STOCK_BUTTON_NO, NULL); gnome_dialog_set_default( GNOME_DIALOG(box), 1); gnome_dialog_set_parent (GNOME_DIALOG (box), GTK_WINDOW (ghack_get_main_window ()) ); gnome_dialog_set_accelerator (GNOME_DIALOG(box), 1, 'n', 0); gnome_dialog_set_accelerator (GNOME_DIALOG(box), 0, 'y', 0); gtk_window_set_modal( GTK_WINDOW(box), TRUE); gtk_signal_connect( GTK_OBJECT(box), "clicked", (GtkSignalFunc)ghack_new_game, NULL); gtk_widget_show(box); } static void about_destroy_callback (void) { about = NULL; } static void ghack_about_cb(GtkWidget *widget, gpointer data) { char buf[BUFSZ]="\0"; char buf1[BUFSZ]="\0"; const gchar *authors[] = {"Erik Andersen", "Anthony Taylor", "Jeff Garzik", "The Nethack Dev Team", NULL}; if (about) { gdk_window_raise (about->window); return; } getversionstring(buf); strcat( buf1, VERSION_STRING); strcat( buf, _("\nSend comments and bug reports to: nethack-bugs@nethack.org\n" "This game is free software. See License for details.")); about = gnome_about_new(_("Nethack"), buf1, "Copyright (C) 1985-2002 Mike Stephenson", (const char **)authors, buf, NULL); gtk_signal_connect (GTK_OBJECT (about), "destroy", (GtkSignalFunc) about_destroy_callback, NULL); gtk_widget_show(about); } static void ghack_settings_cb(GtkWidget *widget, gpointer data) { ghack_settings_dialog(); } static void ghack_accelerator_selected (GtkWidget *widget, gpointer data) { GdkEventKey event; int key = GPOINTER_TO_INT( data); /* g_message("An accelerator for \"%c\" was selected", key); */ /* stuff a key directly into the keybuffer */ event.state=0; event.keyval=key; ghack_handle_key_press(NULL, &event, NULL); } #ifndef M # ifndef NHSTDC # define M(c) (0x80 | (c)) # else # define M(c) ((c) - 128) # endif /* NHSTDC */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif GnomeUIInfo game_tree[] = { { GNOME_APP_UI_ITEM, N_ ("_Change Settings..."), N_("Change Game Settings"), ghack_settings_cb, NULL, NULL, GNOME_APP_PIXMAP_NONE, NULL, 0,0, NULL }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Version"), NULL, ghack_accelerator_selected, GINT_TO_POINTER('v'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'v',0 }, { GNOME_APP_UI_ITEM, N_("History..."), NULL, ghack_accelerator_selected, GINT_TO_POINTER('V'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'V',GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Compilation..."), NULL, ghack_accelerator_selected, GINT_TO_POINTER(M('v')), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT,'v',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Options..."), NULL, ghack_accelerator_selected, GINT_TO_POINTER('O'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_PREF, 'O', GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Explore Mode..."), NULL, ghack_accelerator_selected, GINT_TO_POINTER('X'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_QUIT, 'X', GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, GNOMEUIINFO_MENU_NEW_GAME_ITEM(ghack_new_game_cb, NULL), GNOMEUIINFO_MENU_SAVE_ITEM(ghack_save_game_cb, NULL), { GNOME_APP_UI_ITEM, N_("Exit"), NULL, ghack_quit_game_cb, GINT_TO_POINTER(M('Q')), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 'Q', GDK_MOD1_MASK }, GNOMEUIINFO_END }; GnomeUIInfo edit_menu[] = { { GNOME_APP_UI_ITEM, N_("Inventory"), N_("Edit/View your Inventory"), ghack_accelerator_selected, GINT_TO_POINTER('i'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i', 0 }, { GNOME_APP_UI_ITEM, N_("Discoveries"), N_("Edit/View your Discoveries"), ghack_accelerator_selected, GINT_TO_POINTER('\\'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '\\',0 }, { GNOME_APP_UI_ITEM, N_("List/reorder your spells"), N_("List/reorder your spells"), ghack_accelerator_selected, GINT_TO_POINTER('x'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'x', 0 }, { GNOME_APP_UI_ITEM, N_("Adjust letters"), N_("Adjust letter for items in your Inventory"), ghack_accelerator_selected, GINT_TO_POINTER(M('a')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'a', GDK_MOD1_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Name object"), N_("Assign a name to an object"), ghack_accelerator_selected, GINT_TO_POINTER(M('n')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'n', GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Name creature"), N_("Assign a name to a creature"), ghack_accelerator_selected, GINT_TO_POINTER('C'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'C', GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Qualifications"), N_("Edit your Qualifications"), ghack_accelerator_selected, GINT_TO_POINTER(M('e')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'e',GDK_MOD1_MASK }, GNOMEUIINFO_END }; GnomeUIInfo apparel_menu[] = { { GNOME_APP_UI_ITEM, N_("Wield Weapon"), N_("Select a weapon to fight with"), ghack_accelerator_selected, GINT_TO_POINTER('w'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w',0 }, { GNOME_APP_UI_ITEM, N_("Remove Apparel..."), N_("Remove apparel dialog bog"), ghack_accelerator_selected, GINT_TO_POINTER('A'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'A',GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Wear Armor"), N_("Put on armor"), ghack_accelerator_selected, GINT_TO_POINTER('W'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'W',GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Take off Armor"), N_("Take off armor you are wearing"), ghack_accelerator_selected, GINT_TO_POINTER('T'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'T',GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Put on non-armor"), N_("Put on non-armor apparel"), ghack_accelerator_selected, GINT_TO_POINTER('P'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'P',GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Remove non-armor"), N_("Remove non-armor apparel you are wearing"), ghack_accelerator_selected, GINT_TO_POINTER('R'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R',GDK_SHIFT_MASK }, GNOMEUIINFO_END }; GnomeUIInfo action_menu[] = { { GNOME_APP_UI_ITEM, N_("Get"), N_("Pick up things at the current location"), ghack_accelerator_selected, GINT_TO_POINTER(','), NULL, GNOME_APP_PIXMAP_NONE, NULL, ',',0 }, { GNOME_APP_UI_ITEM, N_("Loot"), N_("loot a box on the floor"), ghack_accelerator_selected, GINT_TO_POINTER(M('l')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'l',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Sit"), N_("sit down"), ghack_accelerator_selected, GINT_TO_POINTER(M('s')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 's',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Force"), N_("force a lock"), ghack_accelerator_selected, GINT_TO_POINTER(M('f')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'f',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Kick"), N_("kick something (usually a door)"), ghack_accelerator_selected, GINT_TO_POINTER(C('d')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',GDK_CONTROL_MASK }, { GNOME_APP_UI_ITEM, N_("Jump"), N_("jump to another location"), ghack_accelerator_selected, GINT_TO_POINTER(M('j')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'j',GDK_MOD1_MASK }, #ifdef STEED { GNOME_APP_UI_ITEM, N_("Ride"), N_("Ride (or stop riding) a monster"), doride, GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'R',GDK_MOD1_MASK }, #endif { GNOME_APP_UI_ITEM, N_("Wipe face"), N_("wipe off your face"), ghack_accelerator_selected, GINT_TO_POINTER(M('w')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'w',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Throw/Shoot"), N_("throw or shoot a weapon"), ghack_accelerator_selected, GINT_TO_POINTER('t'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',0 }, { GNOME_APP_UI_ITEM, N_("Quiver/Ready"), N_("ready or quiver some ammunition"), ghack_accelerator_selected, GINT_TO_POINTER('Q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Q',GDK_SHIFT_MASK, }, { GNOME_APP_UI_ITEM, N_("Open Door"), N_("open a door"), ghack_accelerator_selected, GINT_TO_POINTER('o'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'o',0 }, { GNOME_APP_UI_ITEM, N_("Close Door"), N_("open a door"), ghack_accelerator_selected, GINT_TO_POINTER('c'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'c',0 }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Drop"), N_("drop an object"), ghack_accelerator_selected, GINT_TO_POINTER('d'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',0 }, { GNOME_APP_UI_ITEM, N_("Drop Many"), N_("drop selected types of objects"), ghack_accelerator_selected, GINT_TO_POINTER('D'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'D',GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Eat"), N_("eat something"), ghack_accelerator_selected, GINT_TO_POINTER('e'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'e',0 }, { GNOME_APP_UI_ITEM, N_("Engrave"), N_("write a message in the dust on the floor"), ghack_accelerator_selected, GINT_TO_POINTER('E'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'E',GDK_SHIFT_MASK }, { GNOME_APP_UI_ITEM, N_("Apply"), N_("apply or use a tool (pick-axe, key, camera, etc.)"), ghack_accelerator_selected, GINT_TO_POINTER('a'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'a',0 }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Up"), N_("go up the stairs"), ghack_accelerator_selected, GINT_TO_POINTER('<'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '<',0 }, { GNOME_APP_UI_ITEM, N_("Down"), N_("go down the stairs"), ghack_accelerator_selected, GINT_TO_POINTER('>'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '>',0 }, { GNOME_APP_UI_ITEM, N_("Rest"), N_("wait for a moment"), ghack_accelerator_selected, GINT_TO_POINTER('.'), NULL, GNOME_APP_PIXMAP_NONE, NULL, '.',0 }, { GNOME_APP_UI_ITEM, N_("Search"), N_("search for secret doors, hidden traps and monsters"), ghack_accelerator_selected, GINT_TO_POINTER('s'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 's',0 }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Chat"), N_("talk to someone"), ghack_accelerator_selected, GINT_TO_POINTER(M('c')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'c',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Pay"), N_("pay your bill to the shopkeeper"), ghack_accelerator_selected, GINT_TO_POINTER('p'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'p',0 }, GNOMEUIINFO_END }; GnomeUIInfo magic_menu[] = { { GNOME_APP_UI_ITEM, N_("Quaff potion"), N_("drink a potion"), ghack_accelerator_selected, GINT_TO_POINTER('q'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'q',0 }, { GNOME_APP_UI_ITEM, N_("Read Book/Scroll"), N_("read a spell book or a scroll"), ghack_accelerator_selected, GINT_TO_POINTER('r'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r',0 }, { GNOME_APP_UI_ITEM, N_("Zap Wand"), N_("zap a wand"), ghack_accelerator_selected, GINT_TO_POINTER('z'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'z',0 }, { GNOME_APP_UI_ITEM, N_("Zap Spell"), N_("cast a spell"), ghack_accelerator_selected, GINT_TO_POINTER('Z'), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'Z',GDK_SHIFT_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Dip"), N_("dip an object into something"), ghack_accelerator_selected, GINT_TO_POINTER(M('d')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'd',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Rub"), N_("Rub something (i.e. a lamp)"), ghack_accelerator_selected, GINT_TO_POINTER(M('r')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'r',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Invoke"), N_("invoke an object's special powers"), ghack_accelerator_selected, GINT_TO_POINTER(M('i')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'i',GDK_MOD1_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Offer"), N_("offer a sacrifice to the gods"), ghack_accelerator_selected, GINT_TO_POINTER(M('o')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'o',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Pray"), N_("pray to the gods for help"), ghack_accelerator_selected, GINT_TO_POINTER(M('p')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'p',GDK_MOD1_MASK }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("Teleport"), N_("teleport (if you can)"), ghack_accelerator_selected, GINT_TO_POINTER(C('t')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',GDK_CONTROL_MASK }, { GNOME_APP_UI_ITEM, N_("Monster Action"), N_("use a monster's special ability"), ghack_accelerator_selected, GINT_TO_POINTER(M('m')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 'm',GDK_MOD1_MASK }, { GNOME_APP_UI_ITEM, N_("Turn Undead"), N_("turn undead"), ghack_accelerator_selected, GINT_TO_POINTER(M('t')), NULL, GNOME_APP_PIXMAP_NONE, NULL, 't',GDK_MOD1_MASK }, GNOMEUIINFO_END }; GnomeUIInfo help_menu[] = { { GNOME_APP_UI_ITEM, N_("About..."), N_("About GnomeHack"), ghack_about_cb, NULL, NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, 0, 0, NULL }, { GNOME_APP_UI_ITEM, N_("Help"), NULL, ghack_accelerator_selected, GINT_TO_POINTER('?'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, '?', 0 }, GNOMEUIINFO_SEPARATOR, { GNOME_APP_UI_ITEM, N_("What is here"), N_("Check what items occupy the current location"), ghack_accelerator_selected, GINT_TO_POINTER(':'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, ':',0 }, { GNOME_APP_UI_ITEM, N_("What is that"), N_("Identify an object"), ghack_accelerator_selected, GINT_TO_POINTER(';'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, ';',0 }, { GNOME_APP_UI_ITEM, N_("Identify a map symbol"), N_("Identify a map symbol"), ghack_accelerator_selected, GINT_TO_POINTER('/'), NULL, GNOME_APP_PIXMAP_STOCK, GNOME_STOCK_MENU_ABOUT, '/',0 }, GNOMEUIINFO_END }; GnomeUIInfo mainmenu[] = { GNOMEUIINFO_MENU_GAME_TREE(game_tree), GNOMEUIINFO_MENU_EDIT_TREE(edit_menu), { GNOME_APP_UI_SUBTREE, N_("Apparel"), NULL, apparel_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, { GNOME_APP_UI_SUBTREE, N_("Action"), NULL, action_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, { GNOME_APP_UI_SUBTREE, N_("Magic"), NULL, magic_menu, NULL, NULL, 0, NULL, 0, 0, NULL }, GNOMEUIINFO_MENU_HELP_TREE(help_menu), GNOMEUIINFO_END }; static void ghack_main_window_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { /* First, turn off the key press propogation. We've got the * key, but we don't wan't the underlying Gtk widgets to get it, * since they do the wrong thing with the arrow keys (shift focus)... */ gtk_signal_emit_stop_by_name( GTK_OBJECT(mainWindow), "key_press_event"); /* stuff the key event into the keybuffer */ ghack_handle_key_press(widget, event, data); } /* parsing args */ void parse_args (int argc, char *argv[]) { gint ch; struct option options[] = { /* Default args */ { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, 'v' }, { NULL, 0, NULL, 0 } }; gchar *id = NULL; /* initialize getopt */ optarg = NULL; optind = 0; optopt = 0; while( (ch = getopt_long(argc, argv, "hv", options, NULL)) != EOF ) { switch(ch) { case 'h': g_print ( _("%s: A gnomified 'Hello World' program\n\n" "Usage: %s [--help] [--version]\n\n" "Options:\n" " --help display this help and exit\n" " --version output version information and exit\n"), argv[0], argv[0]); exit(0); break; case 'v': g_print (_("NetHack %s.\n"), VERSION_STRING); exit(0); break; case ':': case '?': g_print (_("Options error\n")); exit(0); break; } } /* SM stuff */ session_id = gnome_client_new (); #if 0 session_id = gnome_client_new ( /* callback to save the state and parameter for it */ save_state, argv[0], /* callback to die and parameter for it */ NULL, NULL, /* id from the previous session if restarted, NULL otherwise */ id); #endif /* set the program name */ gnome_client_set_program (session_id, argv[0]); g_free(id); return; } /* * [ALI] Gnome installs its own handler(s) for SIGBUS, SIGFPE and SIGSEGV. * These handlers will fork and exec a helper program. When that helper * comes to initialize GTK+, it may fail if setuid/setgid. We solve this * by dropping privileges before passing the signal along the chain. * Note: We don't need to either drop or mask the saved ID since this * will be reset when the child process performs the execve() anyway. */ static struct { int signum; void (*handler)(int); } ghack_chain[] = { {SIGBUS}, {SIGFPE}, {SIGSEGV}, {SIGILL} /* Not currently handled by Gnome */ }; static void ghack_sig_handler(int signum) { int i; uid_t uid, euid; gid_t gid, egid; uid = getuid(); euid = geteuid(); gid = getgid(); egid = getegid(); if (gid != egid) setgid(gid); if (uid != euid) setuid(uid); for(i = SIZE(ghack_chain) - 1; i >= 0; i--) if (ghack_chain[i].signum == signum) { ghack_chain[i].handler(signum); break; } if (i < 0) impossible("Unhandled ghack signal"); if (uid != euid) setuid(euid); if (gid != egid) setgid(egid); } /* initialize gnome and fir up the main window */ void ghack_init_main_window( int argc, char** argv) { int i; struct timeval tv; uid_t uid, euid; /* It seems that the authors of gnome_score_init() drop group * priveledges. We need group priveledges, so until we change the * way we save games to do things the gnome way(???), this stays * commented out. (after hours of frusteration...) * -Erik */ /* gnome_score_init("gnomehack"); */ gettimeofday(&tv, NULL); srand(tv.tv_usec); uid = getuid(); euid = geteuid(); if (uid != euid) setuid(uid); hide_privileges(TRUE); /* XXX gnome_init must print nethack options for --help, but does not */ gnome_init ("nethack", VERSION_STRING, argc, argv); hide_privileges(FALSE); parse_args (argc, argv); /* Initialize the i18n stuff (not that gnomehack supperts it yet...) */ #if 0 textdomain (PACKAGE); #endif gdk_imlib_init(); /* Main window */ mainWindow = gnome_app_new((char *) "nethack", (char *) N_("Nethack for Gnome")); gtk_widget_realize(mainWindow); if (restarted) { gtk_widget_set_uposition (mainWindow, os_x, os_y); gtk_widget_set_usize (mainWindow, os_w, os_h); } gtk_window_set_default_size( GTK_WINDOW(mainWindow), 800, 600); gtk_window_set_policy(GTK_WINDOW(mainWindow), FALSE, TRUE, TRUE); gnome_app_create_menus(GNOME_APP(mainWindow), mainmenu); gtk_signal_connect(GTK_OBJECT(mainWindow), "key_press_event", GTK_SIGNAL_FUNC(ghack_main_window_key_press), NULL); gtk_signal_connect(GTK_OBJECT(mainWindow), "delete_event", GTK_SIGNAL_FUNC(ghack_quit_game_cb), NULL); /* Put some stuff into our main window */ vBoxMain = gtk_vbox_new (FALSE, 0); hBoxFirstRow = gtk_hbox_new (FALSE, 0); /* pack Boxes into other boxes to produce the right structure */ gtk_box_pack_start (GTK_BOX (vBoxMain), hBoxFirstRow, FALSE, TRUE, 0); /* pack vBoxMain which contains all our widgets into the main window. */ gnome_app_set_contents(GNOME_APP(mainWindow), vBoxMain); /* DONT show the main window yet, due to a Gtk bug that causes it * to not refresh the window when adding widgets after the window * has already been shown */ if (uid != euid) setuid(euid); for(i = 0; i < SIZE(ghack_chain); i++) ghack_chain[i].handler = signal(ghack_chain[i].signum, ghack_sig_handler); } void ghack_main_window_add_map_window(GtkWidget* win) { GtkWidget *vBox; vBox= gtk_vbox_new (TRUE, 0); gtk_box_pack_start (GTK_BOX (vBox), win, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (vBoxMain), vBox, TRUE, TRUE, 2); gtk_widget_show_all(vBox); /* Ok, now show the main window -- now that we have added in * all the windows (relys on nethack displaying the map window last * (This is an ugly kludge, BTW) */ gtk_widget_show_all(mainWindow); } void ghack_main_window_add_message_window(GtkWidget* win) { gtk_box_pack_start (GTK_BOX (hBoxFirstRow), win, TRUE, TRUE, 2); gtk_widget_show_all(win); } void ghack_main_window_add_status_window(GtkWidget* win) { gtk_box_pack_start (GTK_BOX (hBoxFirstRow), win, FALSE, TRUE, 2); gtk_widget_show_all(win); } void ghack_main_window_add_worn_window(GtkWidget* win) { gtk_box_pack_end (GTK_BOX (hBoxFirstRow), win, FALSE, TRUE, 2); gtk_widget_show_all(win); } void ghack_main_window_add_text_window(GtkWidget *win) { g_warning("Fixme!!! AddTextWindow is not yet implemented"); } void ghack_main_window_remove_window(GtkWidget *win) { g_warning("Fixme!!! RemoveWindow is not yet implemented"); } void ghack_main_window_update_inventory() { /* For now, do very little. Eventually we may allow the inv. window to stay active. When we do this, we'll need to implement this... g_warning("Fixme!!! updateInventory is not yet implemented"); */ gnome_display_nhwindow(WIN_WORN, FALSE); } GtkWidget* ghack_get_main_window() { return( GTK_WIDGET(mainWindow) ); } nethack-3.4.3/win/gnome/gnmain.h0100644000000000000000000000151207764735042015176 0ustar rootroot/* SCCS Id: @(#)gnmain.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackMainWindow_h #define GnomeHackMainWindow_h #include #include void ghack_init_main_window( int argc, char** argv); void ghack_main_window_add_map_window(GtkWidget* win); void ghack_main_window_add_message_window(GtkWidget* win); void ghack_main_window_add_status_window(GtkWidget* win); void ghack_main_window_add_text_window(GtkWidget *); void ghack_main_window_add_worn_window(GtkWidget* win); void ghack_main_window_remove_window(GtkWidget *); void ghack_main_window_update_inventory(); void ghack_save_game_cb(GtkWidget *widget, gpointer data); GtkWidget* ghack_get_main_window(); #endif /* GnomeHackMainWindow_h */ nethack-3.4.3/win/gnome/gnmap.c0100644000000000000000000004247707764735042015041 0ustar rootroot/* SCCS Id: @(#)gnmap.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ #include "gnmap.h" #include "gnglyph.h" #include "gnsignal.h" #include "hack.h" #ifndef ROWNO #define ROWNO 21 #define COLNO 80 #endif /* globals static to this file go here */ struct { GnomeCanvas *canvas; GnomeCanvasImage *map[(ROWNO + 1) * COLNO]; GnomeCanvasImage *overlay[(ROWNO + 1) * COLNO]; double zoom; GtkWidget *frame; } ghack_map; static GdkImlibImage *background; static GdkImlibImage *petmark; static GnomeCanvasGroup *myCanvasGroup; /* static function declarations -- local to this file go here */ void ghack_map_cursor_to( GtkWidget *win, int x, int y, gpointer data); void ghack_map_putstr( GtkWidget *win, int attr, const char* text, gpointer data); void ghack_map_print_glyph( GtkObject *win, guint x, guint y, GdkImlibImage *im, gpointer data); void ghack_map_clear( GtkWidget *win, gpointer data); static void ghack_map_display( GtkWidget *win, boolean block, gpointer data); static void ghack_map_cliparound( GtkWidget *win, int x, int y, gpointer data); static void ghack_map_window_zoom( GtkAdjustment *adj, gpointer data); /* The following XPM is the artwork of Warwick Allison * . It has been borrowed from * the most excellent NetHackQt, until such time as * we can come up with something better. * * More information about NetHackQt can be had from: * http://www.troll.no/~warwick/nethack/ */ /* XPM */ static char *pet_mark_xpm[] = { /* width height ncolors chars_per_pixel */ "8 7 2 1", /* colors */ ". c None", " c #FF0000", /* pixels */ "........", ".. . .", ". ", ". ", ".. .", "... ..", ".... ..." }; /* NAME: * ghack_init_map_window( ) * * ARGUMENTS: * NONE * * RETURNS: * GtkWidget* * * PURPOSE: * Create the basic map necessities. Create a canvas; * give it a background. Attach all the right signals * to all the right places. Generally prepare the map * to behave properly. */ GtkWidget* ghack_init_map_window ( ) { GtkWidget *vbox; GtkWidget *hbox; GtkWidget *table; GtkWidget *frame; GtkWidget *w; GtkWidget *hSeparator; GtkAdjustment *adj; GnomeCanvasImage *bg; double width, height, x, y; int i; width = COLNO * ghack_glyph_width(); height = ROWNO * ghack_glyph_height(); vbox = gtk_vbox_new (FALSE, 4); gtk_container_set_border_width (GTK_CONTAINER (vbox), 4); gtk_widget_show (vbox); /* Add in a horiz seperator */ hSeparator = gtk_hseparator_new (); gtk_box_pack_start (GTK_BOX (vbox), hSeparator, FALSE, FALSE, 2); gtk_widget_show ( hSeparator); hbox = gtk_hbox_new (FALSE, 4); gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); gtk_widget_show (hbox); /* Create the Zoom spinbutton. */ ghack_map.zoom = 1.0; w = gtk_label_new ("Zoom:"); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); adj = GTK_ADJUSTMENT (gtk_adjustment_new (1.00, 0.5, 3.00, 0.05, 0.50, 0.50)); w = gtk_spin_button_new (adj, 0.5, 2); gtk_widget_set_usize (w, 50, 0); gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0); gtk_widget_show (w); /* Canvas and scrollbars */ gtk_widget_push_visual (gdk_imlib_get_visual ()); gtk_widget_push_colormap (gdk_imlib_get_colormap ()); ghack_map.canvas = GNOME_CANVAS (gnome_canvas_new()); //gtk_widget_push_visual(gdk_rgb_get_visual()); //gtk_widget_push_colormap(gdk_rgb_get_cmap()); //ghack_map.canvas = GNOME_CANVAS (gnome_canvas_new_aa()); gtk_widget_pop_colormap(); gtk_widget_pop_visual(); gtk_widget_show (GTK_WIDGET(ghack_map.canvas)); table = gtk_table_new (2, 2, FALSE); gtk_table_set_row_spacings (GTK_TABLE (table), 4); gtk_table_set_col_spacings (GTK_TABLE (table), 4); gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0); gtk_widget_show (table); frame = gtk_frame_new (NULL); ghack_map.frame = frame; gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0); gtk_widget_show (frame); gtk_container_add (GTK_CONTAINER (frame), GTK_WIDGET(ghack_map.canvas)); gnome_canvas_set_scroll_region (GNOME_CANVAS(ghack_map.canvas), 0, 0, width+2*ghack_glyph_width(), height+2*ghack_glyph_height()); gnome_canvas_set_pixels_per_unit (GNOME_CANVAS(ghack_map.canvas), 1.0); w = gtk_hscrollbar_new (GTK_LAYOUT (ghack_map.canvas)->hadjustment); gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 0, 0); gtk_widget_show (w); w = gtk_vscrollbar_new (GTK_LAYOUT (ghack_map.canvas)->vadjustment); gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, GTK_FILL, GTK_EXPAND | GTK_FILL | GTK_SHRINK, 0, 0); gtk_widget_show (w); myCanvasGroup = GNOME_CANVAS_GROUP ( gnome_canvas_item_new ( gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), gnome_canvas_group_get_type (), "x", 0.0, "y", 0.0, NULL) ); /* Tile the map background with a pretty image */ background = gdk_imlib_load_image((char *) "mapbg.xpm"); if (background == NULL) { g_warning("Bummer! Failed to load the map background image (mapbg.xpm)!"); } else { gdk_imlib_render(background, background->rgb_width, background->rgb_height); /* Tile the map background */ for (y = 0; y < height+background->rgb_height; y+=background->rgb_height) { for (x = 0; x < width+background->rgb_width; x+=background->rgb_width) { bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new ( myCanvasGroup, gnome_canvas_image_get_type (), "x", (double) x, "y", (double) y, "width", (double) background->rgb_width, "height", (double) background->rgb_height, "image", background, "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER, NULL) ); gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg)); } } } /* ghack_map.map is an array of canvas images. Each cell of * the array will contain one tile. Here, we create the * space for the cells and then create the cells for easy * access later. */ for (i=0, y = 0; y < height; y+=ghack_glyph_height()) { for (x = 0; x < width; x+=ghack_glyph_width()) { ghack_map.map[i++] = GNOME_CANVAS_IMAGE( gnome_canvas_item_new ( myCanvasGroup, gnome_canvas_image_get_type (), "x", (double) x, "y", (double) y, "width", (double) ghack_glyph_width(), "height", (double) ghack_glyph_height(), "anchor", GTK_ANCHOR_NORTH_WEST, NULL) ); } } /* Set up the pet mark image */ petmark = gdk_imlib_create_image_from_xpm_data( pet_mark_xpm); if (petmark == NULL) { g_warning("Bummer! Failed to load the pet_mark image!"); } else { gdk_imlib_render(petmark, petmark->rgb_width, petmark->rgb_height); /* ghack_map.overlay is an array of canvas images used to * overlay tile images... */ for (i=0, y = 0; y < height; y+=ghack_glyph_height()) { for (x = 0; x < width; x+=ghack_glyph_width()) { ghack_map.overlay[i] = GNOME_CANVAS_IMAGE( gnome_canvas_item_new ( myCanvasGroup, gnome_canvas_image_get_type (), "x", (double) x, "y", (double) y, "width", (double) petmark->rgb_width, "height", (double) petmark->rgb_height, "image", petmark, "anchor", GTK_ANCHOR_NORTH_WEST, NULL) ); gnome_canvas_item_lower_to_bottom ( GNOME_CANVAS_ITEM( ghack_map.overlay[i++])); } } } /* Resize the canvas when the spinbutton changes */ gtk_signal_connect (GTK_OBJECT (adj), "value_changed", (GtkSignalFunc) ghack_map_window_zoom, ghack_map.canvas); /* Game signals */ gtk_signal_connect (GTK_OBJECT (vbox), "ghack_curs", GTK_SIGNAL_FUNC (ghack_map_cursor_to), NULL); gtk_signal_connect (GTK_OBJECT (vbox), "ghack_putstr", GTK_SIGNAL_FUNC (ghack_map_putstr), NULL); gtk_signal_connect (GTK_OBJECT (vbox), "ghack_print_glyph", GTK_SIGNAL_FUNC (ghack_map_print_glyph), NULL); gtk_signal_connect (GTK_OBJECT (vbox), "ghack_clear", GTK_SIGNAL_FUNC (ghack_map_clear), NULL); gtk_signal_connect (GTK_OBJECT (vbox), "ghack_display", GTK_SIGNAL_FUNC (ghack_map_display), NULL); gtk_signal_connect (GTK_OBJECT (vbox), "ghack_cliparound", GTK_SIGNAL_FUNC (ghack_map_cliparound), NULL); gtk_signal_connect (GTK_OBJECT (ghack_map.canvas), "button_press_event", GTK_SIGNAL_FUNC (ghack_handle_button_press), NULL); gtk_signal_connect(GTK_OBJECT (ghack_map.canvas), "gnome_delay_output", GTK_SIGNAL_FUNC(ghack_delay), NULL); return GTK_WIDGET(vbox); } /* NAME: * ghack_map_window_zoom * * ARGUMENTS: * double zoom -- The zoom factor * * RETURNS: * Nothing. * * PURPOSE: * Zoom the map image in and out. This should allow the user to * dynamically scale the map. Ideally, the background should * *NOT* scale, but this may be impractical. */ static void ghack_map_window_zoom( GtkAdjustment *adj, gpointer data) { if ( adj->value > 3.0 ) adj->value = 3.0; if ( adj->value < 0.5 ) adj->value = 0.5; ghack_map.zoom = adj->value; gnome_canvas_set_pixels_per_unit (data, adj->value); } void ghack_map_cursor_to( GtkWidget *win, int x, int y, gpointer data) { GnomeCanvasGroup *group; static GnomeCanvasRE *cursor = NULL; double x1, y1, x2, y2; float hp; guint r, g, b; x1 = x * ghack_glyph_width() - 1; y1 = y * ghack_glyph_height() - 1; x2 = x1 + ghack_glyph_width() + 2; y2 = y1 + ghack_glyph_height() + 2; hp = u.mtimedone ? (u.mhmax ? (float)u.mh/u.mhmax : 1) : (u.uhpmax ? (float)u.uhp/u.uhpmax : 1); r = 255; g = (hp >= 0.75) ? 255 : (hp >= 0.25 ? 255*2*(hp-0.25) : 0); b = (hp >= 0.75) ? 255*4*(hp-0.75) : (hp >= 0.25 ? 0 : 255*4*(0.25-hp)); group = gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)); if (!cursor) { cursor = GNOME_CANVAS_RE (gnome_canvas_item_new (group, gnome_canvas_rect_get_type (), "width_units", 1.0, NULL)); } gnome_canvas_item_set (GNOME_CANVAS_ITEM (cursor), "outline_color_rgba", GNOME_CANVAS_COLOR(r, g, b), "x1", x1, "y1", y1, "x2", x2, "y2", y2, NULL); gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( cursor)); gnome_canvas_item_show( GNOME_CANVAS_ITEM(cursor)); } void ghack_map_putstr( GtkWidget *win, int attr, const char* text, gpointer data) { g_warning("Fixme!!! ghack_map_putstr is not implemented"); } /* NAME: * ghack_map_print_glyph( ) * * ARGUMENTS: * XCHAR_P x, y -- The coordinates where which to print the glyph * GdkImlibImage* glyph -- The glyph image to print * * RETURNS: * Nothing. * * PURPOSE: * Draw the glyph-tile at the specified coordinates. */ void ghack_map_print_glyph( GtkObject *win, guint x, guint y, GdkImlibImage *im, gpointer data) { GnomeCanvasGroup *group; int i = y * COLNO + x; int glyph = glyph_at(x,y); GnomeCanvasImage *canvas_image = GNOME_CANVAS_IMAGE( ghack_map.map[i]); group = gnome_canvas_root (GNOME_CANVAS (ghack_map.canvas)); gnome_canvas_item_set (GNOME_CANVAS_ITEM ( canvas_image), "image", im, NULL); gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image)); canvas_image = GNOME_CANVAS_IMAGE( ghack_map.overlay[i]); if (x==u.ux && y==u.uy) ghack_map_cliparound(NULL, x, y, NULL); if (glyph_is_pet(glyph) #ifdef TEXTCOLOR && iflags.hilite_pet #endif ) { gnome_canvas_item_raise_to_top( GNOME_CANVAS_ITEM( canvas_image)); gnome_canvas_item_show( GNOME_CANVAS_ITEM( canvas_image)); } else { gnome_canvas_item_hide( GNOME_CANVAS_ITEM( canvas_image)); } } /* NAME: * ghack_map_clear( ) * * ARGUMENTS: * NONE * * RETURNS: * Nothing. * * PURPOSE: * Clear the map by hiding all the map tiles. */ void ghack_map_clear( GtkWidget *win, gpointer data) { int i; for (i = 0; i < ROWNO * COLNO; i++) { if (GNOME_IS_CANVAS_IMAGE(ghack_map.map[i])) { gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.map[i])); } if (GNOME_IS_CANVAS_IMAGE(ghack_map.overlay[i])) { gnome_canvas_item_hide( GNOME_CANVAS_ITEM (ghack_map.overlay[i])); } } gnome_canvas_update_now ( GNOME_CANVAS(ghack_map.canvas)); } void ghack_map_display( GtkWidget *win, boolean block, gpointer data) { gtk_widget_show_all( GTK_WIDGET(win)); } void ghack_map_cliparound( GtkWidget *win, int x, int y, gpointer data) { int map_width, map_height; int to_x, to_y; int cur_x, cur_y; int width, height, half_width, half_height; x *= ghack_glyph_width() * ghack_map.zoom; y *= ghack_glyph_height() * ghack_map.zoom; map_width = COLNO * ghack_glyph_width() * ghack_map.zoom; map_height = ROWNO * ghack_glyph_height() * ghack_map.zoom; gdk_window_get_size( GTK_LAYOUT (ghack_map.canvas)->bin_window, &width, &height); gnome_canvas_get_scroll_offsets( ghack_map.canvas, &cur_x, &cur_y); half_width = width * 0.5; half_height = height * 0.5; if ( ((x - cur_x) < (width * 0.25) ) || ( (x - cur_x) > (width * 0.75) ) ) { to_x = ((x-half_width) > 0)? x - half_width : 0; to_x = ((x+half_width) > map_width)? map_width - 2 * half_width : to_x; } else { to_x = cur_x; } if ( ((y - cur_y) < (height * 0.25) ) || ( (y - cur_y) > (height * 0.75) ) ) { to_y = ((y-half_height) > 0)? y - half_height : 0; to_y = ((y+half_height) > map_height)? map_height - 2 * half_height : to_y; } else { to_y = cur_y; } if (to_x != cur_x || to_y != cur_y) gnome_canvas_scroll_to( ghack_map.canvas, to_x, to_y); //gnome_canvas_update_now ( ghack_map.canvas); } void ghack_reinit_map_window ( ) { GnomeCanvasImage *bg; double width, height, x, y; int i; /* ghack_map_clear(NULL, NULL); */ width = COLNO * ghack_glyph_width(); height = ROWNO * ghack_glyph_height(); gnome_canvas_set_scroll_region (GNOME_CANVAS(ghack_map.canvas), 0, 0, width+2*ghack_glyph_width(), height+2*ghack_glyph_height()); /* remove everything currently in the canvas map */ gtk_object_destroy( GTK_OBJECT (myCanvasGroup)); /* Put some groups back */ myCanvasGroup = GNOME_CANVAS_GROUP ( gnome_canvas_item_new ( gnome_canvas_root(GNOME_CANVAS(ghack_map.canvas)), gnome_canvas_group_get_type (), "x", 0.0, "y", 0.0, NULL) ); /* Tile the map background with a pretty image */ if (background != NULL) { /* Tile the map background */ for (y = 0; y < height+background->rgb_height; y+=background->rgb_height) { for (x = 0; x < width+background->rgb_width; x+=background->rgb_width) { bg = GNOME_CANVAS_IMAGE( gnome_canvas_item_new ( myCanvasGroup, gnome_canvas_image_get_type (), "x", (double) x, "y", (double) y, "width", (double) background->rgb_width, "height", (double) background->rgb_height, "image", background, "anchor", (GtkAnchorType) GTK_ANCHOR_CENTER, NULL) ); gnome_canvas_item_lower_to_bottom (GNOME_CANVAS_ITEM( bg)); } } } /* ghack_map.map is an array of canvas images. Each cell of * the array will contain one tile. Here, we create the * space for the cells and then create the cells for easy * access later. */ for (i=0, y = 0; y < height; y+=ghack_glyph_height()) { for (x = 0; x < width; x+=ghack_glyph_width()) { ghack_map.map[i++] = GNOME_CANVAS_IMAGE( gnome_canvas_item_new ( myCanvasGroup, gnome_canvas_image_get_type (), "x", (double) x, "y", (double) y, "width", (double) ghack_glyph_width(), "height", (double) ghack_glyph_height(), "anchor", GTK_ANCHOR_NORTH_WEST, NULL) ); } } if (petmark != NULL) { /* ghack_map.overlay is an array of canvas images used to * overlay tile images... */ for (i=0, y = 0; y < height; y+=ghack_glyph_height()) { for (x = 0; x < width; x+=ghack_glyph_width()) { ghack_map.overlay[i] = GNOME_CANVAS_IMAGE( gnome_canvas_item_new ( myCanvasGroup, gnome_canvas_image_get_type (), "x", (double) x, "y", (double) y, "width", (double) petmark->rgb_width, "height", (double) petmark->rgb_height, "image", petmark, "anchor", GTK_ANCHOR_NORTH_WEST, NULL) ); gnome_canvas_item_lower_to_bottom ( GNOME_CANVAS_ITEM( ghack_map.overlay[i++])); } } } ghack_map_cliparound(NULL, u.ux, u.uy, NULL); ghack_map_cursor_to(NULL, u.ux, u.uy, NULL); gnome_canvas_update_now ( ghack_map.canvas); doredraw(); } nethack-3.4.3/win/gnome/gnmap.h0100644000000000000000000000065507764735042015036 0ustar rootroot/* SCCS Id: @(#)gnmap.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackMapWindow_h #define GnomeHackMapWindow_h #include #include #include "config.h" #include "global.h" GtkWidget *ghack_init_map_window(void); void ghack_reinit_map_window(void); #endif /* GnomeHackMapWindow_h */ nethack-3.4.3/win/gnome/gnmenu.c0100644000000000000000000005364307764735042015225 0ustar rootroot/* SCCS Id: @(#)gnmenu.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include #include "gnmenu.h" #include "gnmain.h" #include "gnbind.h" #include "func_tab.h" typedef enum { MenuUnknown = 0, MenuText, MenuMenu } MenuWinType; typedef struct { ANY_P identifier; gchar accelerator[BUFSZ]; int itemNumber; int selected; } menuItem; typedef struct { int curItem; int numRows; int charIdx; guint32 lastTime; } extMenu; static GdkColor color_blue = { 0, 0, 0, 0xffff }; static void ghack_menu_window_key(GtkWidget *menuWin, GdkEventKey *event, gpointer data) { int i, numRows; menuItem* item; MenuWinType isMenu; isMenu = (MenuWinType) GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu")); if (isMenu == MenuMenu) { GtkWidget *clist; gint selection_mode; clist = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (menuWin), "clist")); g_assert (clist != NULL); numRows = GPOINTER_TO_INT (gtk_object_get_data(GTK_OBJECT(clist), "numRows")); selection_mode = GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT(clist), "selection_mode")); for (i = 0; i <= numRows; ++i) { item = (menuItem*) gtk_clist_get_row_data(GTK_CLIST(clist), i); if (item == NULL) continue; if (!strcmp(item->accelerator, "")) continue; if ((!strcmp(item->accelerator, event->string)) || ((selection_mode == GTK_SELECTION_MULTIPLE) && (event->keyval == ','))) { if (item->selected) { gtk_clist_unselect_row( GTK_CLIST (clist), item->itemNumber, 0); item->selected = FALSE; } else { gtk_clist_select_row(GTK_CLIST (clist), item->itemNumber, 0); if (gtk_clist_row_is_visible(GTK_CLIST(clist), item->itemNumber) != GTK_VISIBILITY_FULL) gtk_clist_moveto(GTK_CLIST(clist), item->itemNumber, 0, 0.5, 0); item->selected = TRUE; } } } } } static void ghack_menu_row_selected (GtkCList *clist, int row, int col, GdkEvent *event) { /* FIXME: Do something */ } void ghack_menu_window_clear(GtkWidget *menuWin, gpointer data) { MenuWinType isMenu; int i, numRows; menuItem* item; isMenu = (MenuWinType) GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu")); if (isMenu == MenuMenu) { GtkWidget *clist; clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist")); g_assert (clist != NULL); /* destroy existing menu data, if any */ if (clist) { /* destroy all the row_data we stored in the clist */ numRows = GPOINTER_TO_INT( gtk_object_get_data( GTK_OBJECT(clist), "numRows") ); for( i=0; itext), 0, 0); } } void ghack_menu_window_display(GtkWidget *menuWin, gboolean blocking, gpointer data) { //if(blocking) { gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE); gnome_dialog_set_close (GNOME_DIALOG (menuWin), TRUE); gnome_dialog_run_and_close(GNOME_DIALOG (menuWin)); //} //else { //gtk_widget_show(menuWin); //} } gint ghack_menu_hide( GtkWidget *menuWin, GdkEvent *event, gpointer data ) { gtk_widget_hide (menuWin); return FALSE; /* FIXME: what is correct result here? */ } void ghack_menu_window_start_menu (GtkWidget *menuWin, gpointer data) { GtkWidget *frame1, *swin, *clist; MenuWinType isMenu; g_assert (menuWin != NULL); g_assert (data == NULL); /* destroy existing menu data, if any */ frame1 = gtk_object_get_data (GTK_OBJECT (menuWin), "frame1"); if (frame1) gtk_widget_destroy (frame1); isMenu = MenuMenu; gtk_object_set_data (GTK_OBJECT (menuWin), "isMenu", GINT_TO_POINTER (isMenu)); gtk_widget_set_usize (GTK_WIDGET (menuWin), 500, 400); gtk_window_set_policy (GTK_WINDOW (menuWin), TRUE, TRUE, FALSE); frame1 = gtk_frame_new ("Make your selection"); g_assert (frame1 != NULL); gtk_object_set_data (GTK_OBJECT(menuWin), "frame1", frame1); gtk_widget_show (GTK_WIDGET (frame1)); gtk_container_set_border_width (GTK_CONTAINER (frame1), 5); gtk_box_pack_start (GTK_BOX (GNOME_DIALOG(menuWin)->vbox), frame1, TRUE, TRUE, 0); swin = gtk_scrolled_window_new (NULL, NULL); g_assert (swin != NULL); gtk_object_set_data (GTK_OBJECT(menuWin), "swin", swin); gtk_widget_show (GTK_WIDGET (swin)); gtk_container_add (GTK_CONTAINER (frame1), swin); clist = gtk_clist_new (4); g_assert (clist != NULL); gtk_object_set_data (GTK_OBJECT(menuWin), "clist", clist); gtk_widget_show (GTK_WIDGET (clist)); gtk_container_add (GTK_CONTAINER (swin), clist); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect (GTK_OBJECT (clist), "select_row", GTK_SIGNAL_FUNC (ghack_menu_row_selected), NULL); gtk_object_set_data (GTK_OBJECT (clist), "numItems", GINT_TO_POINTER (-1)); } int ghack_menu_window_select_menu (GtkWidget *menuWin, MENU_ITEM_P **_selected, gint how) { gint rc; guint num_sel, i, idx; GtkWidget *clist; GList *cur; MENU_ITEM_P *selected = NULL; menuItem* item; g_assert (_selected != NULL); *_selected = NULL; if (how == PICK_NONE) { gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE); rc = gnome_dialog_run_and_close (GNOME_DIALOG (menuWin)); return( rc == 1 ? -1 : 0); } clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist")); g_assert (clist != NULL); gtk_object_set_data (GTK_OBJECT (clist), "selection_mode", GINT_TO_POINTER ((how == PICK_ANY)? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE)); gtk_clist_set_selection_mode (GTK_CLIST (clist), (how == PICK_ANY)? GTK_SELECTION_MULTIPLE : GTK_SELECTION_SINGLE); gnome_dialog_close_hides (GNOME_DIALOG (menuWin), TRUE); rc = gnome_dialog_run_and_close (GNOME_DIALOG (menuWin)); if ((rc == 1) || (GTK_CLIST (clist)->selection == NULL)) { return(-1); } num_sel = g_list_length (GTK_CLIST (clist)->selection); if (num_sel < 1) { return(-1); } /* fill in array with selections from clist */ selected = g_new0( MENU_ITEM_P, num_sel); g_assert (selected != NULL); cur = GTK_CLIST (clist)->selection; i = 0; while (cur) { g_assert (i < num_sel); /* grab row number from clist selection list */ idx = GPOINTER_TO_INT (cur->data); item = (menuItem*) gtk_clist_get_row_data( GTK_CLIST (clist), idx); selected[i].item = item->identifier; selected[i].count = -1; cur = g_list_next(cur); i++; } *_selected = selected; return( (int) num_sel); } void ghack_menu_window_add_menu( GtkWidget *menuWin, gpointer menu_item, gpointer data) { GHackMenuItem* item; GtkWidget *clist; gchar buf[BUFSZ]="", accelBuf[BUFSZ]=""; gchar *pbuf; char *text[4] = { buf, NULL, NULL, NULL }; gint nCurrentRow = -1, numItems = -1; MenuWinType isMenu; GtkStyle *bigStyle = NULL; gboolean item_selectable; GdkImlibImage* image; static gboolean special; g_assert (menu_item != NULL); item = (GHackMenuItem*) menu_item; item_selectable = ( item->identifier->a_int == 0)? FALSE : TRUE; isMenu = (MenuWinType) GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu")); clist = GTK_WIDGET (gtk_object_get_data (GTK_OBJECT (menuWin), "clist")); g_assert (clist != NULL); /* This is a special kludge to make the special hidden help menu item work as designed */ if ( special==TRUE ) { special=FALSE; item_selectable=TRUE; } if ( ! strcmp( item->str, "The NetHack license.")) { special=TRUE; } if (item->str) { /* First, make a new blank entry in the clist */ nCurrentRow = gtk_clist_append (GTK_CLIST (clist), text); if (item->glyph != NO_GLYPH) { image = ghack_image_from_glyph( item->glyph, FALSE); if (image==NULL || image->pixmap==NULL) { g_warning("Bummer -- having to force rendering for glyph %d!", item->glyph); /* wierd -- pixmap is NULL so retry rendering it */ image = ghack_image_from_glyph( item->glyph, TRUE); } if (image==NULL || image->pixmap==NULL) { g_error("Aiiee! glyph is still NULL for item\n\"%s\"", item->str); } else gtk_clist_set_pixmap (GTK_CLIST (clist), nCurrentRow, 1, gdk_imlib_move_image( image), gdk_imlib_move_mask( image)); } if (item->accelerator) { /* FIXME: handle accelerator, */ g_snprintf(accelBuf, sizeof(accelBuf), "%c ", item->accelerator); gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 0, accelBuf); g_snprintf(buf, sizeof(buf), "%s", item->str); gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf); } else { if (item->group_accel) { /* FIXME: maybe some day I should try to handle * group accelerators... */ } if (( (item->attr == 0) && (item->identifier->a_int != 0)) || (special ==TRUE) ) { numItems = GPOINTER_TO_INT( gtk_object_get_data( GTK_OBJECT(clist), "numItems") )+1; /* Ok, now invent a unique accelerator */ if ( ('a'+numItems) <= 'z' ) { g_snprintf(accelBuf, sizeof(accelBuf), "%c ", 'a'+numItems); gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf); } else if ( ('A'+numItems-26)<='Z') { g_snprintf(accelBuf, sizeof(accelBuf), "%c ", 'A'+numItems-26); gtk_clist_set_text(GTK_CLIST(clist), nCurrentRow, 0, accelBuf); } else { accelBuf[0] = buf[0] = 0; } g_snprintf(buf, sizeof(buf), "%s", item->str); gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf); gtk_object_set_data (GTK_OBJECT (clist), "numItems", GINT_TO_POINTER (numItems)); /* This junk is to specially handle the options menu */ pbuf = strstr( buf, " ["); if (pbuf == NULL) { pbuf = strstr( buf, "\t["); } if (pbuf != NULL) { *pbuf=0; pbuf++; gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 3, pbuf); } } /* FIXME: handle more than 26*2 accelerators (but how? * since I only have so many keys to work with???) else { foo(); } */ else { g_snprintf(buf, sizeof(buf), "%s", item->str); pbuf = strstr( buf, " ["); if (pbuf == NULL) { pbuf = strstr( buf, "\t["); } if (pbuf != NULL) { *pbuf=0; pbuf++; gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 3, pbuf); } gtk_clist_set_text (GTK_CLIST (clist), nCurrentRow, 2, buf); } } if (item->attr) { switch(item->attr) { case ATR_ULINE: case ATR_BOLD: case ATR_BLINK: case ATR_INVERSE: bigStyle = gtk_style_copy (GTK_WIDGET (clist)->style); g_assert (bigStyle != NULL); gdk_font_unref (bigStyle->font); bigStyle->font = gdk_font_load ( "-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); bigStyle->fg[GTK_STATE_NORMAL] = color_blue; gtk_clist_set_cell_style (GTK_CLIST (clist), nCurrentRow, 2, bigStyle); item_selectable = FALSE; } } g_assert (nCurrentRow >= 0); gtk_clist_set_selectable (GTK_CLIST (clist), nCurrentRow, item_selectable); if ( item_selectable==TRUE && item->presel== TRUE) { /* pre-select this item */ gtk_clist_select_row( GTK_CLIST (clist), nCurrentRow, 0); } gtk_object_set_data (GTK_OBJECT (clist), "numRows", GINT_TO_POINTER (nCurrentRow)); /* We have to allocate memory here, since the menu_item currently * lives on the stack, and will otherwise go to the great bit bucket * in the sky as soon as this function exits, which would leave a * pointer to crap in the row_data. Use g_memdup to make a private, * persistant copy of the item identifier. * * We need to arrange to blow away this memory somewhere (like * ghack_menu_destroy and ghack_menu_window_clear for example). * * -Erik */ { menuItem newItem; menuItem *pNewItem; newItem.identifier = *item->identifier; newItem.itemNumber=nCurrentRow; newItem.selected=FALSE; newItem.accelerator[0]=0; /* only copy 1 char, since accel keys are by definition 1 char */ if (accelBuf[0]) { strncpy(newItem.accelerator, accelBuf, 1); } newItem.accelerator[1]=0; pNewItem = g_memdup(&newItem, sizeof( menuItem)); gtk_clist_set_row_data (GTK_CLIST (clist), nCurrentRow, (gpointer) pNewItem); } } /* Now adjust the column widths to match the contents */ gtk_clist_columns_autosize (GTK_CLIST (clist)); } void ghack_menu_window_end_menu (GtkWidget *menuWin, gpointer data) { const char* p = (const char*) data; if ((p) && (*p)) { GtkWidget *frame1 = gtk_object_get_data (GTK_OBJECT (menuWin), "frame1"); g_assert (frame1 != NULL); gtk_frame_set_label (GTK_FRAME(frame1), p); } } void ghack_menu_window_put_string(GtkWidget *menuWin, int attr, const char* text, gpointer data) { GnomeLess *gless; MenuWinType isMenu; if (text == NULL) return; isMenu = (MenuWinType) GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu")); if (isMenu == MenuText) { gless = GNOME_LESS (gtk_object_get_data (GTK_OBJECT (menuWin), "gless")); g_assert (gless != NULL); g_assert (gless->text != NULL); g_assert (GTK_IS_TEXT (gless->text)); /* Don't bother with attributes yet */ gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, text, -1); gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, "\n", -1); } else if (isMenu == MenuUnknown) { isMenu = MenuText; gtk_object_set_data (GTK_OBJECT (menuWin), "isMenu", GINT_TO_POINTER (isMenu)); gtk_widget_set_usize (GTK_WIDGET (menuWin), 500, 400); gtk_window_set_policy (GTK_WINDOW (menuWin), TRUE, TRUE, FALSE); gless = GNOME_LESS (gnome_less_new ()); g_assert (gless != NULL); gtk_object_set_data (GTK_OBJECT (menuWin), "gless", gless); gtk_widget_show (GTK_WIDGET (gless)); gnome_less_show_string (gless, text); gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, "\n", -1); gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (menuWin)->vbox), GTK_WIDGET (gless), TRUE, TRUE, 0); } } void ghack_menu_destroy (GtkWidget *menuWin, gpointer data) { MenuWinType isMenu; isMenu = (MenuWinType) GPOINTER_TO_INT (gtk_object_get_data (GTK_OBJECT (menuWin), "isMenu")); if (isMenu == MenuText) { GnomeLess *gless; gless = GNOME_LESS (gtk_object_get_data (GTK_OBJECT (menuWin), "gless")); g_assert (gless != NULL); g_assert (gless->text != NULL); g_assert (GTK_IS_TEXT (gless->text)); gtk_widget_destroy(GTK_WIDGET(gless)); } else if (isMenu == MenuMenu) { GtkWidget *frame1, *swin, *clist; /* destroy existing menu data, if any */ clist = gtk_object_get_data (GTK_OBJECT (menuWin), "clist"); if (clist) { /* destroy all the row_data we stored in the clist */ int i, numRows; menuItem* item; numRows = GPOINTER_TO_INT( gtk_object_get_data( GTK_OBJECT(clist), "numRows") ); for( i=0; istring[0]; clist = GTK_WIDGET(gtk_object_get_data(GTK_OBJECT(menuWin), "clist")); g_assert(clist != NULL); /* if too long between keystrokes, reset to initial state */ if (event->time - info->lastTime > 500) goto init_state; /* see if current item continue to match */ if (info->charIdx > 0) { if (extcmdlist[info->curItem].ef_txt[info->charIdx] == c) { ++info->charIdx; goto found; } } /* see if the prefix matches a later command in the list */ if (info->curItem >= 0) { for (i = info->curItem + 1; i < info->numRows; ++i) { if (!strncmp(extcmdlist[info->curItem].ef_txt, extcmdlist[i].ef_txt, info->charIdx)) { if (extcmdlist[i].ef_txt[info->charIdx] == c) { ++info->charIdx; info->curItem = i; goto found; } } } } init_state: /* reset to initial state, look for matching 1st character */ for (i = 0; i < info->numRows; ++i) { if (extcmdlist[i].ef_txt[0] == c) { info->charIdx = 1; info->curItem = i; goto found; } } /* no match: leave prior, if any selection in place */ return; found: info->lastTime = event->time; gtk_clist_select_row(GTK_CLIST(clist), info->curItem, 0); if (gtk_clist_row_is_visible(GTK_CLIST(clist), info->curItem) != GTK_VISIBILITY_FULL) gtk_clist_moveto(GTK_CLIST(clist), info->curItem, 0, 0.5, 0); } int ghack_menu_ext_cmd(void) { int n; GtkWidget* dialog; GtkWidget* swin; GtkWidget* frame1; GtkWidget* clist; extMenu info; dialog = gnome_dialog_new("Extended Commands", GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_close_hides(GNOME_DIALOG(dialog), FALSE); gtk_signal_connect(GTK_OBJECT(dialog), "key_press_event", GTK_SIGNAL_FUNC(ghack_ext_key_hit), &info); frame1 = gtk_frame_new("Make your selection"); gtk_object_set_data(GTK_OBJECT(dialog), "frame1", frame1); gtk_widget_show(frame1); gtk_container_border_width(GTK_CONTAINER(frame1), 3); swin = gtk_scrolled_window_new(NULL, NULL); clist = gtk_clist_new(2); gtk_object_set_data(GTK_OBJECT(dialog), "clist", clist); gtk_widget_set_usize(clist, 500, 400); gtk_container_add(GTK_CONTAINER(swin), clist); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect(GTK_OBJECT(clist), "select_row", GTK_SIGNAL_FUNC(ghack_menu_row_selected), NULL); gtk_container_add(GTK_CONTAINER(frame1), swin); gtk_box_pack_start_defaults(GTK_BOX(GNOME_DIALOG(dialog)->vbox), frame1); /* Add the extended commands into the list here... */ for (n = 0; extcmdlist[n].ef_txt; ++n) { const char *text[3]={extcmdlist[n].ef_txt,extcmdlist[n].ef_desc,NULL}; gtk_clist_insert(GTK_CLIST(clist), n, (char**) text); } /* fill in starting info fields */ info.curItem = -1; info.numRows = n; info.charIdx = 0; info.lastTime = 0; gtk_clist_columns_autosize(GTK_CLIST(clist)); gtk_widget_show_all(swin); /* Center the dialog over over parent */ gnome_dialog_set_default(GNOME_DIALOG(dialog), 0); gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); gnome_dialog_set_parent(GNOME_DIALOG(dialog), GTK_WINDOW(ghack_get_main_window())); /* Run the dialog -- returning whichever button was pressed */ n = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); /* Quit on button 2 or error */ return (n != 0) ? -1 : info.curItem; } nethack-3.4.3/win/gnome/gnmenu.h0100644000000000000000000000137007764735042015220 0ustar rootroot/* SCCS Id: @(#)gnmenu.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackMenuWindow_h #define GnomeHackMenuWindow_h #include #include "config.h" #include "global.h" #include "gnomeprv.h" GtkWidget* ghack_init_menu_window( void ); struct _GHackMenuItem { int glyph; const ANY_P *identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; const char* str; BOOLEAN_P presel; }; typedef struct _GHackMenuItem GHackMenuItem; int ghack_menu_window_select_menu (GtkWidget *menuWin, MENU_ITEM_P **_selected, gint how); int ghack_menu_ext_cmd(void); #endif /* GnomeHackMenuWindow_h */ nethack-3.4.3/win/gnome/gnmesg.c0100644000000000000000000000547307764735042015212 0ustar rootroot/* SCCS Id: @(#)gnmesg.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnmesg.h" #include "gnsignal.h" /* Pick an arbitrary number of chars such as 80 col X 40 rows text = 3200 chars */ #define nCharsBeforeDeletingStuff 3200 /* Message Window widgets */ GtkWidget *MW_table; GtkWidget *MW_text; GtkWidget *MW_scrollbar; void ghack_message_window_clear(GtkWidget *widget, gpointer data) { /* Seems nethack calls this after every move -- we don't want * to really clear the window at all though. Ignore the request */ gint len; len = gtk_text_get_length(GTK_TEXT(MW_text)); if(len < nCharsBeforeDeletingStuff) return; gtk_text_freeze(GTK_TEXT(MW_text)); gtk_text_set_point(GTK_TEXT(MW_text), 0); gtk_text_forward_delete(GTK_TEXT(MW_text), len-((guint)(nCharsBeforeDeletingStuff*0.5))); gtk_text_set_point(GTK_TEXT(MW_text), (guint)(nCharsBeforeDeletingStuff*0.5)); gtk_text_thaw(GTK_TEXT(MW_text)); } void ghack_message_window_destroy( GtkWidget *win, gpointer data) { } void ghack_message_window_display(GtkWidget *widget, boolean block, gpointer data) { } void ghack_message_window_put_string(GtkWidget *widget, int attr, const char* text, gpointer data) { if(text == NULL) return; /* Don't bother with attributes yet */ gtk_text_insert(GTK_TEXT(MW_text), NULL, NULL, NULL, text, -1); gtk_text_insert(GTK_TEXT(MW_text), NULL, NULL, NULL, "\n", -1); } void ghack_message_window_use_RIP(int how) { } void ghack_message_window_scroll(int dx, int dy) { } GtkWidget* ghack_init_message_window(void) { MW_table = gtk_table_new(2, 1, FALSE); gtk_table_set_row_spacing(GTK_TABLE(MW_table), 0, 2); MW_text = gtk_text_new(NULL, NULL); gtk_text_set_editable(GTK_TEXT(MW_text), FALSE); gtk_text_set_word_wrap(GTK_TEXT(MW_text), TRUE); gtk_table_attach(GTK_TABLE(MW_table), MW_text, 0, 1, 0, 1, (GTK_EXPAND | GTK_FILL), (GTK_EXPAND | GTK_FILL), 0, 0); MW_scrollbar = gtk_vscrollbar_new(GTK_TEXT(MW_text)->vadj); gtk_table_attach(GTK_TABLE(MW_table), MW_scrollbar, 1, 2, 0, 1, GTK_FILL, (GTK_EXPAND | GTK_FILL), 0, 0); gtk_signal_connect(GTK_OBJECT(MW_table), "ghack_putstr", GTK_SIGNAL_FUNC(ghack_message_window_put_string), NULL); gtk_signal_connect(GTK_OBJECT(MW_table), "ghack_clear", GTK_SIGNAL_FUNC(ghack_message_window_clear), NULL); gtk_signal_connect(GTK_OBJECT(MW_table), "gnome_delay_output", GTK_SIGNAL_FUNC(ghack_delay), NULL); gtk_widget_show_all(MW_table); return GTK_WIDGET(MW_table); } nethack-3.4.3/win/gnome/gnmesg.h0100644000000000000000000000160307764735042015206 0ustar rootroot/* SCCS Id: @(#)gnmesg.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackMessageWindow_h #define GnomeHackMessageWindow_h #include #include "config.h" GtkWidget* ghack_init_message_window ( /* GnomeHackKeyBuffer g_keybuffer, GnomeHackClickBuffer g_clickbuffer */ ); void ghack_message_window_clear(GtkWidget *widget, gpointer data); void ghack_message_window_destroy(); void ghack_message_window_display(GtkWidget *widget, boolean block, gpointer data); void ghack_message_window_put_string(GtkWidget *widget, int attr, const char* text, gpointer data); void ghack_message_window_use_RIP(int how); void ghack_message_window_scroll(int dx, int dy); #endif /* GnomeHackMessageWindow_h */ nethack-3.4.3/win/gnome/gnomeprv.h0100644000000000000000000000057507764735042015572 0ustar rootroot/* SCCS Id: @(#)gnomeprv.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHack_h #define GnomeHack_h /* These are the base nethack include files */ #include "hack.h" #include "dlb.h" #include "patchlevel.h" #include "winGnome.h" #endif /* GnomeHack_h */ nethack-3.4.3/win/gnome/gnopts.c0100644000000000000000000000672307764735042015243 0ustar rootroot/* SCCS Id: @(#)gnopts.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnopts.h" #include "gnglyph.h" #include "gnmain.h" #include "gnmap.h" #include #include #include "hack.h" static gint tileset; static GtkWidget* clist; const char* tilesets[] = { "Traditional (16x16)", "Big (32x32)", 0 }; static void opt_sel_key_hit(GtkWidget *widget, GdkEventKey *event, gpointer data) { int i; for (i = 0; tilesets[i] != 0; ++i) { if (tilesets[i][0] == toupper(event->keyval)) { tileset = i; gtk_clist_select_row( GTK_CLIST (clist), i, 0); } } } static void opt_sel_row_selected(GtkCList *cList, int row, int col, GdkEvent *event) { tileset = row; } void ghack_settings_dialog() { int i; static GtkWidget* dialog; static GtkWidget* swin; static GtkWidget* frame1; dialog = gnome_dialog_new (_("GnomeHack Settings"), GNOME_STOCK_BUTTON_OK, GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_close_hides (GNOME_DIALOG (dialog), FALSE); gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event", GTK_SIGNAL_FUNC (opt_sel_key_hit), tilesets ); frame1 = gtk_frame_new (_("Choose one of the following tilesets:")); gtk_object_set_data (GTK_OBJECT (dialog), "frame1", frame1); gtk_widget_show (frame1); gtk_container_border_width (GTK_CONTAINER (frame1), 3); swin = gtk_scrolled_window_new (NULL, NULL); clist = gtk_clist_new (2); gtk_clist_column_titles_hide (GTK_CLIST (clist)); gtk_widget_set_usize (GTK_WIDGET (clist), 100, 180); gtk_container_add (GTK_CONTAINER (swin), clist); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect (GTK_OBJECT (clist), "select_row", GTK_SIGNAL_FUNC (opt_sel_row_selected), NULL ); gtk_container_add (GTK_CONTAINER (frame1), swin); gtk_box_pack_start_defaults (GTK_BOX (GNOME_DIALOG (dialog)->vbox), frame1); /* Add the tilesets into the list here... */ for (i=0; tilesets[i]; i++) { gchar accelBuf[BUFSZ]; const char *text[3]={accelBuf, tilesets[i],NULL}; sprintf( accelBuf, "%c ", tolower(tilesets[i][0])); gtk_clist_insert (GTK_CLIST (clist), i, (char**)text); } gtk_clist_columns_autosize (GTK_CLIST (clist)); gtk_widget_show_all (swin); /* Center the dialog over over parent */ gnome_dialog_set_default( GNOME_DIALOG(dialog), 0); gtk_window_set_modal( GTK_WINDOW(dialog), TRUE); gnome_dialog_set_parent (GNOME_DIALOG (dialog), GTK_WINDOW (ghack_get_main_window ()) ); /* Run the dialog -- returning whichever button was pressed */ i = gnome_dialog_run (GNOME_DIALOG (dialog)); gnome_dialog_close (GNOME_DIALOG (dialog)); /* They hit Quit or error */ if (i != 0 ) { return; } switch (tileset) { case 0: /* They selected traditional */ ghack_free_glyphs(); if (ghack_init_glyphs(HACKDIR "/x11tiles")) g_error ("ERROR: Could not initialize glyphs.\n"); ghack_reinit_map_window(); break; case 1: ghack_free_glyphs(); if (ghack_init_glyphs(HACKDIR "/t32-1024.xpm")) g_error ("ERROR: Could not initialize glyphs.\n"); ghack_reinit_map_window(); /* They selected big */ break; default: /* This shouldn't happen */ g_warning("This shouldn't happen\n"); } } nethack-3.4.3/win/gnome/gnopts.h0100644000000000000000000000046207764735042015242 0ustar rootroot/* SCCS Id: @(#)gnopts.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackSettings_h #define GnomeHackSettings_h void ghack_settings_dialog( void); #endif /* GnomeHackSettings.h */ nethack-3.4.3/win/gnome/gnplayer.c0100644000000000000000000000613507764735042015547 0ustar rootroot/* SCCS Id: @(#)gnplayer.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include #include #include "gnplayer.h" #include "gnmain.h" #include "hack.h" static gint role_number; static GtkWidget* clist; static void player_sel_key_hit (GtkWidget *widget, GdkEventKey *event, gpointer data) { const char** roles = data; int i; for (i = 0; roles[i] != 0; ++i) { if (tolower(roles[i][0]) == tolower(event->keyval)) { role_number = i; gtk_clist_select_row( GTK_CLIST (clist), i, 0); if (gtk_clist_row_is_visible(GTK_CLIST(clist), i) != GTK_VISIBILITY_FULL) gtk_clist_moveto(GTK_CLIST(clist), i, 0, 0.5, 0); } } } static void player_sel_row_selected (GtkCList *clist, int row, int col, GdkEvent *event) { role_number = row; } int ghack_player_sel_dialog(const char** choices, const gchar* title, const gchar* prompt) { int i; static GtkWidget* dialog; static GtkWidget* swin; static GtkWidget* frame1; dialog = gnome_dialog_new(title, GNOME_STOCK_BUTTON_OK, _("Random"), GNOME_STOCK_BUTTON_CANCEL, NULL); gnome_dialog_close_hides (GNOME_DIALOG (dialog), FALSE); gtk_signal_connect (GTK_OBJECT (dialog), "key_press_event", GTK_SIGNAL_FUNC (player_sel_key_hit), choices ); frame1 = gtk_frame_new(prompt); gtk_object_set_data (GTK_OBJECT (dialog), "frame1", frame1); gtk_widget_show (frame1); gtk_container_border_width (GTK_CONTAINER (frame1), 3); swin = gtk_scrolled_window_new (NULL, NULL); clist = gtk_clist_new (2); gtk_clist_column_titles_hide (GTK_CLIST (clist)); gtk_widget_set_usize (GTK_WIDGET (clist), 100, 180); gtk_container_add (GTK_CONTAINER (swin), clist); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_signal_connect (GTK_OBJECT (clist), "select_row", GTK_SIGNAL_FUNC (player_sel_row_selected), NULL ); gtk_container_add (GTK_CONTAINER (frame1), swin); gtk_box_pack_start_defaults (GTK_BOX (GNOME_DIALOG (dialog)->vbox), frame1); /* Add the roles into the list here... */ for (i=0; choices[i]; i++) { gchar accelBuf[BUFSZ]; const char *text[3]={accelBuf, choices[i],NULL}; sprintf( accelBuf, "%c ", tolower(choices[i][0])); gtk_clist_insert (GTK_CLIST (clist), i, (char**)text); } gtk_clist_columns_autosize (GTK_CLIST (clist)); gtk_widget_show_all (swin); /* Center the dialog over over parent */ gnome_dialog_set_default( GNOME_DIALOG(dialog), 0); gtk_window_set_modal( GTK_WINDOW(dialog), TRUE); gnome_dialog_set_parent (GNOME_DIALOG (dialog), GTK_WINDOW (ghack_get_main_window ()) ); /* Run the dialog -- returning whichever button was pressed */ i = gnome_dialog_run_and_close(GNOME_DIALOG(dialog)); /* Quit on button 2 or error */ if (i < 0 || i > 1) { return(ROLE_NONE); } /* Random is button 1*/ if (i == 1 ) { return(ROLE_RANDOM); } return ( role_number); } nethack-3.4.3/win/gnome/gnplayer.h0100644000000000000000000000055307764735042015552 0ustar rootroot/* SCCS Id: @(#)gnplayer.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackPlayerSelDialog_h #define GnomeHackPlayerSelDialog_h int ghack_player_sel_dialog(const char **, const gchar*, const gchar*); #endif /* GnomeHackPlayerSelDialog_h */ nethack-3.4.3/win/gnome/gnsignal.c0100644000000000000000000002614407764735042015532 0ustar rootroot/* SCCS Id: @(#)gnsignal.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ #include "gnsignal.h" #include "gnmain.h" #include GList *g_keyBuffer; GList *g_clickBuffer; int g_numKeys=0; int g_numClicks=0; int g_askingQuestion=0; static int s_done=FALSE; /* * ghack_init_signals * * Create some signals and attach them to the GtkWidget class. * These are the signals: * * ghack_curs : NONE:INT,INT * INT 1 = x * INT 2 = y * * ghack_putstr : NONE:INT,POINTER * INT = attribute * POINTER = char* string to print * * ghack_print_glyph : NONE:INT,INT,POINTER * INT 1 = x * INT 2 = y * INT 3 = GtkPixmap* to rendered glyph * * ghack_clear : NONE:NONE * * ghack_display : NONE:BOOL * BOOL = blocking flag * * ghack_start_menu : NONE:NONE * * ghack_add_menu : NONE:POINTER * POINTER = GHackMenuItem* * * ghack_end_menu : NONE:POINTER * POINTER = char* to closing string * * ghack_select_menu : NONE:POINTER,INT,POINTER * POINTER = int pointer-- filled with number * of selected items on return * INT = number of items selected * POINTER = structure to fill * * ghack_cliparound : NONE:INT,INT * INT 1 = x * INT 2 = y */ void ghack_init_signals( void) { ghack_signals[GHSIG_CURS] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_curs", GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); ghack_signals[GHSIG_PUTSTR] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_putstr", GTK_RUN_FIRST, gtk_marshal_NONE__INT_POINTER, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_POINTER); ghack_signals[GHSIG_PRINT_GLYPH] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_print_glyph", GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT_POINTER, GTK_TYPE_NONE, 3, GTK_TYPE_INT, GTK_TYPE_INT, GTK_TYPE_POINTER); ghack_signals[GHSIG_CLEAR] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_clear", GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); ghack_signals[GHSIG_DISPLAY] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_display", GTK_RUN_FIRST, gtk_marshal_NONE__BOOL, GTK_TYPE_NONE, 1, GTK_TYPE_BOOL); ghack_signals[GHSIG_START_MENU] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_start_menu", GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); ghack_signals[GHSIG_ADD_MENU] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_add_menu", GTK_RUN_FIRST, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); ghack_signals[GHSIG_END_MENU] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_end_menu", GTK_RUN_FIRST, gtk_marshal_NONE__POINTER, GTK_TYPE_NONE, 1, GTK_TYPE_POINTER); ghack_signals[GHSIG_SELECT_MENU] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_select_menu", GTK_RUN_FIRST, gtk_marshal_NONE__POINTER_INT_POINTER, GTK_TYPE_NONE, 3, GTK_TYPE_POINTER, GTK_TYPE_INT, GTK_TYPE_POINTER); ghack_signals[GHSIG_CLIPAROUND] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_cliparound", GTK_RUN_FIRST, gtk_marshal_NONE__INT_INT, GTK_TYPE_NONE, 2, GTK_TYPE_INT, GTK_TYPE_INT); ghack_signals[GHSIG_FADE_HIGHLIGHT] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "ghack_fade_highlight", GTK_RUN_FIRST, gtk_marshal_NONE__NONE, GTK_TYPE_NONE, 0); ghack_signals[GHSIG_DELAY] = gtk_object_class_user_signal_new (gtk_type_class (gtk_widget_get_type ()), "gnome_delay_output", GTK_RUN_FIRST, gtk_marshal_NONE__INT, GTK_TYPE_NONE, 1, GTK_TYPE_INT); } /* For want of a better place, I'm putting the delay output stuff here * -Erik */ static gint timeout_callback(gpointer data) { s_done=TRUE; return FALSE; } void ghack_delay( GtkWidget *win, int numMillisecs, gpointer data) { s_done=FALSE; gtk_timeout_add( (unsigned int) numMillisecs, timeout_callback, NULL); while( s_done==FALSE) gtk_main_iteration(); } void ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data) { GHClick *click; double x1, y1; if (event->type != GDK_BUTTON_PRESS) return; gnome_canvas_window_to_world( GNOME_CANVAS( widget), event->x, event->y, &x1, &y1); /* g_message("I got a click at %f,%f with button %d \n", x1, y1, event->button); */ /* We allocate storage here, so we need to remember if (g_numClicks>0) * to blow this away when closing the app using something like * while (g_clickBuffer) * { * g_free((GHClick)g_clickBuffer->data); * g_clickBuffer = g_clickBuffer->next; * } * g_list_free( g_clickBuffer ); * */ click = g_new( GHClick, 1); click->x=(int)x1/ghack_glyph_width(); click->y=(int)y1/ghack_glyph_height(); click->mod=(event->button == 1)? CLICK_1 : CLICK_2; g_clickBuffer = g_list_prepend (g_clickBuffer, click); /* Could use g_list_length(), but it is stupid and just * traverses the list while counting, so we'll just do * the counting ourselves in advance. */ g_numClicks++; } #ifndef M # ifndef NHSTDC # define M(c) (0x80 | (c)) # else # define M(c) ((c) - 128) # endif /* NHSTDC */ #endif #ifndef C #define C(c) (0x1f & (c)) #endif void ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data) { static int was_pound = 0; int key = 0; int ctl = GDK_CONTROL_MASK; int alt = GDK_MOD1_MASK; /* Turn this on to debug key events */ #if 0 g_message("I got a \"%s\" key (%d) %s%s", gdk_keyval_name (event->keyval), event->keyval, (event->state&ctl)? "+CONTROL":"", (event->state&alt)? "+ALT":""); #endif switch (event->keyval) { /* special keys to do stuff with */ /* Set up the direction keys */ /* First handle the arrow keys -- these always mean move */ case GDK_Right: case GDK_rightarrow: if (iflags.num_pad) key='6'; else key='l'; break; case GDK_Left: case GDK_leftarrow: if (iflags.num_pad) key='4'; else key='h'; break; case GDK_Up: case GDK_uparrow: if (iflags.num_pad) key='8'; else key='k'; break; case GDK_Down: case GDK_downarrow: if (iflags.num_pad) key='2'; else key='j'; break; case GDK_Home: if (iflags.num_pad) key='7'; else key='y'; break; case GDK_End: if (iflags.num_pad) key='1'; else key='b'; break; case GDK_Page_Down: if (iflags.num_pad) key='3'; else key='n'; break; case GDK_Page_Up: if (iflags.num_pad) key='9'; else key='u'; break; case ' ': key='.'; break; /* Now, handle the numberpad (move or numbers) */ case GDK_KP_Right: case GDK_KP_6: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_6; else key='6'; break; case GDK_KP_Left: case GDK_KP_4: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_4; else key='4'; break; case GDK_KP_Up: case GDK_KP_8: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_8; else key='8'; break; case GDK_KP_Down: case GDK_KP_2: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_2; else key='2'; break; /* Move Top-Left */ case GDK_KP_Home: case GDK_KP_7: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_7; else key='7'; break; case GDK_KP_Page_Up: case GDK_KP_9: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_9; else key='9'; break; case GDK_KP_End: case GDK_KP_1: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_1; else key='1'; break; case GDK_KP_Page_Down: case GDK_KP_3: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_3; else key='3'; break; case GDK_KP_5: if (event->state & (GDK_CONTROL_MASK | GDK_SHIFT_MASK) && iflags.num_pad) key = GDK_KP_5; else key='5'; break; case GDK_KP_Delete: case GDK_KP_Decimal: key='.'; break; /* can't just ignore "#", it's a core feature */ case GDK_numbersign: key='#'; break; /* We will probably want to do something with these later... */ case GDK_KP_Begin: case GDK_KP_F1: case GDK_F1: case GDK_KP_F2: case GDK_F2: case GDK_KP_F3: case GDK_F3: case GDK_KP_F4: case GDK_F4: case GDK_F5: case GDK_F6: case GDK_F7: case GDK_F8: case GDK_F9: case GDK_F10: case GDK_F11: case GDK_F12: break; /* various keys to ignore */ case GDK_KP_Insert: case GDK_Insert: case GDK_Delete: case GDK_Print: case GDK_BackSpace: case GDK_Pause: case GDK_Scroll_Lock: case GDK_Shift_Lock: case GDK_Num_Lock: case GDK_Caps_Lock: case GDK_Control_L: case GDK_Control_R: case GDK_Shift_L: case GDK_Shift_R: case GDK_Alt_L: case GDK_Alt_R: case GDK_Meta_L: case GDK_Meta_R: case GDK_Mode_switch: case GDK_Multi_key: return; default: key = event->keyval; break; } if ((event->state & alt) || was_pound) { key=M(event->keyval); } else if (event->state & ctl) { key=C(event->keyval); } if (was_pound) { was_pound = 0; } /* Ok, here is where we do clever stuff to overide the default * game behavior */ if (g_askingQuestion == 0) { if (key == 'S' || key == M('S') || key == C('S')) { ghack_save_game_cb( NULL, NULL); return; } } g_keyBuffer = g_list_prepend (g_keyBuffer, GINT_TO_POINTER( key)); g_numKeys++; } nethack-3.4.3/win/gnome/gnsignal.h0100644000000000000000000000217307764735042015533 0ustar rootroot/* SCCS Id: @(#)gnsignal.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Anthony Taylor */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackSignals_h #define GnomeHackSignals_h #include #include #include "gnomeprv.h" #include "gnglyph.h" /* The list of custom signals */ enum { GHSIG_CURS, GHSIG_PUTSTR, GHSIG_PRINT_GLYPH, GHSIG_CLEAR, GHSIG_DISPLAY, GHSIG_START_MENU, GHSIG_ADD_MENU, GHSIG_END_MENU, GHSIG_SELECT_MENU, GHSIG_CLIPAROUND, GHSIG_FADE_HIGHLIGHT, GHSIG_DELAY, GHSIG_LAST_SIG }; guint ghack_signals[GHSIG_LAST_SIG]; extern void ghack_init_signals( void); void ghack_handle_key_press(GtkWidget *widget, GdkEventKey *event, gpointer data); void ghack_handle_button_press(GtkWidget *widget, GdkEventButton *event, gpointer data); typedef struct { int x, y, mod; } GHClick; extern GList *g_keyBuffer; extern GList *g_clickBuffer; extern int g_numKeys; extern int g_numClicks; extern int g_askingQuestion; void ghack_delay( GtkWidget *win, int numMillisecs, gpointer data); #endif /* GnomeHackSignals_h */ nethack-3.4.3/win/gnome/gnstatus.c0100644000000000000000000007672707764735042015614 0ustar rootroot/* SCCS Id: @(#)gnstatus.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnstatus.h" #include "gnsignal.h" #include "gn_xpms.h" #include "gnomeprv.h" extern const char *hu_stat[]; /* from eat.c */ extern const char *enc_stat[]; /* from botl.c */ void ghack_status_window_update_stats(); void ghack_status_window_clear(GtkWidget *win, gpointer data); void ghack_status_window_destroy(GtkWidget *win, gpointer data); void ghack_status_window_display(GtkWidget *win, boolean block, gpointer data); void ghack_status_window_cursor_to(GtkWidget *win, int x, int y, gpointer data); void ghack_status_window_put_string(GtkWidget *win, int attr, const char* text, gpointer data); static void ghack_fade_highlighting(); static void ghack_highlight_widget( GtkWidget* widget, GtkStyle* oldStyle, GtkStyle* newStyle); /* some junk to handle when to fade the highlighting */ #define NUM_TURNS_HIGHLIGHTED 3 static GList *s_HighLightList; typedef struct { GtkWidget* widget; GtkStyle* oldStyle; int nTurnsLeft; } Highlight; /* Ok, now for a LONG list of widgets... */ static GtkWidget* statTable = NULL; static GtkWidget* titleLabel = NULL; static GtkWidget* dgnLevelLabel = NULL; static GtkWidget* strPix = NULL; static GtkWidget* strLabel = NULL; static GtkWidget* dexPix = NULL; static GtkWidget* dexLabel = NULL; static GtkWidget* intPix = NULL; static GtkWidget* intLabel = NULL; static GtkWidget* wisPix = NULL; static GtkWidget* wisLabel = NULL; static GtkWidget* conPix = NULL; static GtkWidget* conLabel = NULL; static GtkWidget* chaPix = NULL; static GtkWidget* chaLabel = NULL; static GtkWidget* goldLabel = NULL; static GtkWidget* hpLabel = NULL; static GtkWidget* powLabel = NULL; static GtkWidget* acLabel = NULL; static GtkWidget* levlLabel = NULL; static GtkWidget* expLabel = NULL; static GtkWidget* timeLabel = NULL; static GtkWidget* scoreLabel = NULL; static GtkWidget* alignPix = NULL; static GtkWidget* alignLabel = NULL; static GtkWidget* hungerPix = NULL; static GtkWidget* hungerLabel = NULL; static GtkWidget* sickPix = NULL; static GtkWidget* sickLabel = NULL; static GtkWidget* blindPix = NULL; static GtkWidget* blindLabel = NULL; static GtkWidget* stunPix = NULL; static GtkWidget* stunLabel = NULL; static GtkWidget* halluPix = NULL; static GtkWidget* halluLabel = NULL; static GtkWidget* confuPix = NULL; static GtkWidget* confuLabel = NULL; static GtkWidget* encumbPix = NULL; static GtkWidget* encumbLabel = NULL; static GtkStyle* normalStyle = NULL; static GtkStyle* bigStyle = NULL; static GtkStyle* redStyle = NULL; static GtkStyle* greenStyle = NULL; static GtkStyle* bigRedStyle = NULL; static GtkStyle* bigGreenStyle = NULL; /* Pure red */ static GdkColor color_red = { 0, 0xff00, 0, 0 }; /* ForestGreen (looks better than just pure green) */ static GdkColor color_green = { 0, 0x2200, 0x8b00, 0x2200 }; static int lastDepth; static int lastStr; static int lastInt; static int lastWis; static int lastDex; static int lastCon; static int lastCha; static long lastAu; static int lastHP; static int lastMHP; static int lastLevel; static int lastPOW; static int lastMPOW; static int lastAC; static int lastExp; static aligntyp lastAlignment; static unsigned lastHungr; static long lastConf; static long lastBlind; static long lastStun; static long lastHalu; static long lastSick; static int lastEncumb; void ghack_status_window_clear( GtkWidget *win, gpointer data) { /* Don't think we need this at all */ } void ghack_status_window_destroy(GtkWidget *win, gpointer data) { while (s_HighLightList) { g_free( (Highlight*)s_HighLightList->data); s_HighLightList = s_HighLightList->next; } g_list_free( s_HighLightList ); } void ghack_status_window_display( GtkWidget *win, boolean block, gpointer data) { gtk_widget_show_all( GTK_WIDGET(win)); } void ghack_status_window_cursor_to( GtkWidget *win, int x, int y, gpointer data) { /* Don't think we need this at all */ } void ghack_status_window_put_string( GtkWidget *win, int attr, const char* text, gpointer data) { ghack_status_window_update_stats(); } GtkWidget* ghack_init_status_window () { GtkWidget *horizSep0, *horizSep1, *horizSep2, *horizSep3; GtkWidget *statsHBox, *strVBox, *dexVBox, *intVBox, *statHBox; GtkWidget *wisVBox, *conVBox, *chaVBox; GtkWidget *alignVBox, *hungerVBox, *sickVBox, *blindVBox; GtkWidget *stunVBox, *halluVBox, *confuVBox, *encumbVBox; /* Set up a (ridiculous) initial state */ lastDepth = 9999; lastStr = 9999; lastInt = 9999; lastWis = 9999; lastDex = 9999; lastCon = 9999; lastCha = 9999; lastAu = 9999; lastHP = 9999; lastMHP = 9999; lastLevel = 9999; lastPOW = 9999; lastMPOW = 9999; lastAC = 9999; lastExp = 9999; lastAlignment = A_NEUTRAL; /* start off guessing neutral */ lastHungr = 9999; lastConf = 9999; lastBlind = 9999; lastStun = 9999; lastHalu = 9999; lastSick = 9999; lastEncumb = 9999; statTable = gtk_table_new( 10, 8, FALSE); gtk_table_set_row_spacings( GTK_TABLE( statTable), 1); gtk_table_set_col_spacings( GTK_TABLE( statTable), 1); /* Begin the first row of the table -- the title */ titleLabel = gtk_label_new( _("GnomeHack!")); gtk_table_attach( GTK_TABLE( statTable), titleLabel, 0, 8, 0, 1, GTK_FILL, 0, 0, 0); if (!normalStyle) normalStyle = gtk_style_copy ( gtk_widget_get_style (GTK_WIDGET (titleLabel))); /* Set up some styles to draw stuff with */ if (!redStyle) { g_assert (greenStyle == NULL); g_assert (bigStyle == NULL); g_assert (bigRedStyle == NULL); g_assert (bigGreenStyle == NULL); greenStyle = gtk_style_copy (normalStyle); redStyle = gtk_style_copy (normalStyle); bigRedStyle = gtk_style_copy (normalStyle); bigGreenStyle = gtk_style_copy (normalStyle); bigStyle = gtk_style_copy (normalStyle); greenStyle->fg[GTK_STATE_NORMAL] = color_green; redStyle->fg[GTK_STATE_NORMAL] = color_red; bigRedStyle->fg[GTK_STATE_NORMAL] = color_red; bigGreenStyle->fg[GTK_STATE_NORMAL] = color_green; gdk_font_unref (bigRedStyle->font); gdk_font_unref (bigGreenStyle->font); bigRedStyle->font = gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); bigGreenStyle->font = gdk_font_load("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); gdk_font_unref (bigStyle->font); bigStyle->font = gdk_font_load ("-misc-fixed-*-*-*-*-20-*-*-*-*-*-*-*"); } gtk_widget_set_style (GTK_WIDGET (titleLabel), bigStyle); /* Begin the second row */ dgnLevelLabel = gtk_label_new (_ ("Nethack for Gnome")); gtk_table_attach (GTK_TABLE (statTable), dgnLevelLabel, 0, 8, 1, 2, GTK_FILL, 0, 0, 0); gtk_widget_set_style (GTK_WIDGET (dgnLevelLabel), bigStyle); /* Begin the third row */ horizSep0 = gtk_hseparator_new (); gtk_table_attach (GTK_TABLE (statTable), horizSep0, 0, 8, 2, 3, GTK_FILL, GTK_FILL, 0, 0); /* Begin the fourth row */ statsHBox = gtk_hbox_new (TRUE, 0); strVBox = gtk_vbox_new (FALSE, 0); strPix = gnome_pixmap_new_from_xpm_d( str_xpm); strLabel = gtk_label_new( "STR: "); gtk_box_pack_start (GTK_BOX (strVBox), strPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (strVBox), strLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(strVBox), TRUE, TRUE, 2); dexVBox = gtk_vbox_new (FALSE, 0); dexPix = gnome_pixmap_new_from_xpm_d( dex_xpm); dexLabel = gtk_label_new( "DEX: "); gtk_box_pack_start (GTK_BOX (dexVBox), dexPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (dexVBox), dexLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(dexVBox), TRUE, TRUE, 2); conVBox = gtk_vbox_new (FALSE, 0); conPix = gnome_pixmap_new_from_xpm_d( cns_xpm); conLabel = gtk_label_new( "CON: "); gtk_box_pack_start (GTK_BOX (conVBox), conPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (conVBox), conLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(conVBox), TRUE, TRUE, 2); intVBox = gtk_vbox_new (FALSE, 0); intPix = gnome_pixmap_new_from_xpm_d( int_xpm); intLabel = gtk_label_new( "INT: "); gtk_box_pack_start (GTK_BOX (intVBox), intPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (intVBox), intLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(intVBox), TRUE, TRUE, 2); wisVBox = gtk_vbox_new (FALSE, 0); wisPix = gnome_pixmap_new_from_xpm_d( wis_xpm); wisLabel = gtk_label_new( "WIS: "); gtk_box_pack_start (GTK_BOX (wisVBox), wisPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (wisVBox), wisLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(wisVBox), TRUE, TRUE, 2); chaVBox = gtk_vbox_new (FALSE, 0); chaPix = gnome_pixmap_new_from_xpm_d( cha_xpm); chaLabel = gtk_label_new( "CHA: "); gtk_box_pack_start (GTK_BOX (chaVBox), chaPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (chaVBox), chaLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statsHBox), GTK_WIDGET(chaVBox), TRUE, TRUE, 2); gtk_table_attach( GTK_TABLE( statTable), GTK_WIDGET(statsHBox), 0, 8, 3, 4, GTK_FILL, 0, 0, 0); /* Begin the fifth row */ horizSep1 = gtk_hseparator_new(); gtk_table_attach( GTK_TABLE( statTable), horizSep1, 0, 8, 4, 5, GTK_FILL, GTK_FILL, 0, 0); /* Begin the sixth row */ hpLabel = gtk_label_new( "HP: "); gtk_table_attach( GTK_TABLE( statTable), hpLabel, 0, 1, 5, 6, GTK_FILL, 0, 0, 0); acLabel = gtk_label_new( "AC: "); gtk_table_attach( GTK_TABLE( statTable), acLabel, 2, 3, 5, 6, GTK_FILL, 0, 0, 0); powLabel = gtk_label_new( "Power: "); gtk_table_attach( GTK_TABLE( statTable), powLabel, 4, 5, 5, 6, GTK_FILL, 0, 0, 0); goldLabel = gtk_label_new( "Au: "); gtk_table_attach( GTK_TABLE( statTable), goldLabel, 6, 7, 5, 6, GTK_FILL, 0, 0, 0); /* Begin the seventh row */ horizSep2 = gtk_hseparator_new(); gtk_table_attach( GTK_TABLE( statTable), horizSep2, 0, 8, 6, 7, GTK_FILL, GTK_FILL, 0, 0); /* Begin the eigth row */ levlLabel = gtk_label_new( "Level: "); gtk_table_attach( GTK_TABLE( statTable), levlLabel, 0, 1, 7, 8, GTK_FILL, 0, 0, 0); expLabel = gtk_label_new( "Exp: "); gtk_table_attach( GTK_TABLE( statTable), expLabel, 2, 3, 7, 8, GTK_FILL, 0, 0, 0); timeLabel = gtk_label_new( "Time: "); gtk_table_attach( GTK_TABLE( statTable), timeLabel, 4, 5, 7, 8, GTK_FILL, 0, 0, 0); scoreLabel = gtk_label_new( "Score: "); gtk_table_attach( GTK_TABLE( statTable), scoreLabel, 6, 7, 7, 8, GTK_FILL, 0, 0, 0); /* Begin the ninth row */ horizSep3 = gtk_hseparator_new(); gtk_table_attach( GTK_TABLE( statTable), horizSep3, 0, 8, 8, 9, GTK_FILL, GTK_FILL, 0, 0); /* Begin the tenth and last row */ statHBox = gtk_hbox_new (FALSE, 0); alignVBox = gtk_vbox_new (FALSE, 0); alignPix = gnome_pixmap_new_from_xpm_d( neutral_xpm); alignLabel = gtk_label_new( "Neutral"); gtk_box_pack_start (GTK_BOX (alignVBox), alignPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (alignVBox), alignLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(alignVBox), TRUE, FALSE, 2); hungerVBox = gtk_vbox_new (FALSE, 0); hungerPix = gnome_pixmap_new_from_xpm_d( hungry_xpm); hungerLabel = gtk_label_new( "Hungry"); gtk_box_pack_start (GTK_BOX (hungerVBox), hungerPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (hungerVBox), hungerLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(hungerVBox), TRUE, FALSE, 2); sickVBox = gtk_vbox_new (FALSE, 0); sickPix = gnome_pixmap_new_from_xpm_d( sick_fp_xpm); sickLabel = gtk_label_new( "FoodPois"); gtk_box_pack_start (GTK_BOX (sickVBox), sickPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (sickVBox), sickLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(sickVBox), TRUE, FALSE, 2); blindVBox = gtk_vbox_new (FALSE, 0); blindPix = gnome_pixmap_new_from_xpm_d( blind_xpm); blindLabel = gtk_label_new( "Blind"); gtk_box_pack_start (GTK_BOX (blindVBox), blindPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (blindVBox), blindLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(blindVBox), TRUE, FALSE, 2); stunVBox = gtk_vbox_new (FALSE, 0); stunPix = gnome_pixmap_new_from_xpm_d( stunned_xpm); stunLabel = gtk_label_new( "Stun"); gtk_box_pack_start (GTK_BOX (stunVBox), stunPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (stunVBox), stunLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(stunVBox), TRUE, FALSE, 2); confuVBox = gtk_vbox_new (FALSE, 0); confuPix = gnome_pixmap_new_from_xpm_d( confused_xpm); confuLabel = gtk_label_new( "Confused"); gtk_box_pack_start (GTK_BOX (confuVBox), confuPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (confuVBox), confuLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(confuVBox), TRUE, FALSE, 2); halluVBox = gtk_vbox_new (FALSE, 0); halluPix = gnome_pixmap_new_from_xpm_d( hallu_xpm); halluLabel = gtk_label_new( "Hallu"); gtk_box_pack_start (GTK_BOX (halluVBox), halluPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (halluVBox), halluLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(halluVBox), TRUE, FALSE, 2); encumbVBox = gtk_vbox_new (FALSE, 0); encumbPix = gnome_pixmap_new_from_xpm_d( slt_enc_xpm); encumbLabel = gtk_label_new( "Burdened"); gtk_box_pack_start (GTK_BOX (encumbVBox), encumbPix, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX (encumbVBox), encumbLabel, TRUE, TRUE, 2); gtk_box_pack_start (GTK_BOX(statHBox), GTK_WIDGET(encumbVBox), TRUE, FALSE, 2); gtk_table_attach( GTK_TABLE( statTable), GTK_WIDGET(statHBox), 0, 8, 9, 10, GTK_FILL, GTK_FILL, 0, 0); /* Set up the necessary signals */ gtk_signal_connect (GTK_OBJECT (statTable), "ghack_fade_highlight", GTK_SIGNAL_FUNC (ghack_fade_highlighting), NULL); gtk_signal_connect (GTK_OBJECT (statTable), "ghack_putstr", GTK_SIGNAL_FUNC (ghack_status_window_put_string), NULL); gtk_signal_connect (GTK_OBJECT (statTable), "ghack_clear", GTK_SIGNAL_FUNC (ghack_status_window_clear), NULL); gtk_signal_connect (GTK_OBJECT (statTable), "ghack_curs", GTK_SIGNAL_FUNC (ghack_status_window_cursor_to), NULL); gtk_signal_connect(GTK_OBJECT (statTable), "gnome_delay_output", GTK_SIGNAL_FUNC(ghack_delay), NULL); /* Lastly, show the status window and everything in it */ gtk_widget_show_all( statTable); return GTK_WIDGET(statTable); } void ghack_status_window_update_stats() { char buf[BUFSZ]; gchar *buf1; const char* hung; const char* enc; static int firstTime=TRUE; #ifdef GOLDOBJ long umoney; #endif /* First, fill in the player name and the dungeon level */ strcpy(buf, plname); if ('a' <= buf[0] && buf[0] <= 'z') buf[0] += 'A'-'a'; strcat(buf, " the "); if (u.mtimedone) { char mname[BUFSZ]; int k = 0; strcpy(mname, mons[u.umonnum].mname); while(mname[k] != 0) { if ((k == 0 || (k > 0 && mname[k-1] == ' ')) && 'a' <= mname[k] && mname[k] <= 'z') { mname[k] += 'A' - 'a'; } k++; } strcat(buf, mname); } else { strcat(buf, rank_of(u.ulevel, pl_character[0], flags.female)); } gtk_label_get( GTK_LABEL( titleLabel), &buf1); if (strcmp( buf1, buf) != 0 && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( titleLabel, bigStyle, bigGreenStyle); } gtk_label_set( GTK_LABEL( titleLabel), buf); if (In_endgame(&u.uz)) { strcpy(buf, (Is_astralevel(&u.uz) ? "Astral Plane":"End Game")); } else { sprintf(buf, "%s, level %d", dungeons[u.uz.dnum].dname, depth(&u.uz)); } if (lastDepth > depth(&u.uz) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( dgnLevelLabel, bigStyle, bigRedStyle); } else if (lastDepth < depth(&u.uz) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( dgnLevelLabel, bigStyle, bigGreenStyle); } lastDepth = depth(&u.uz); gtk_label_set( GTK_LABEL( dgnLevelLabel), buf); /* Next, fill in the player's stats */ if (ACURR(A_STR) > 118) { sprintf(buf,"STR:%d",ACURR(A_STR)-100); } else if (ACURR(A_STR)==118) { sprintf(buf,"STR:18/**"); } else if(ACURR(A_STR) > 18) { sprintf(buf,"STR:18/%02d",ACURR(A_STR)-18); } else { sprintf(buf,"STR:%d",ACURR(A_STR)); } if (lastStr < ACURR(A_STR) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( strLabel, normalStyle, greenStyle); } else if (lastStr > ACURR(A_STR) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( strLabel, normalStyle, redStyle); } lastStr = ACURR(A_STR); gtk_label_set( GTK_LABEL( strLabel), buf); sprintf(buf,"INT:%d",ACURR(A_INT)); if (lastInt < ACURR(A_INT) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( intLabel, normalStyle, greenStyle); } else if (lastInt > ACURR(A_INT) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( intLabel, normalStyle, redStyle); } lastInt = ACURR(A_INT); gtk_label_set( GTK_LABEL( intLabel), buf); sprintf(buf,"WIS:%d",ACURR(A_WIS)); if (lastWis < ACURR(A_WIS) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( wisLabel, normalStyle, greenStyle); } else if (lastWis > ACURR(A_WIS) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( wisLabel, normalStyle, redStyle); } lastWis = ACURR(A_WIS); gtk_label_set( GTK_LABEL( wisLabel), buf); sprintf(buf,"DEX:%d",ACURR(A_DEX)); if (lastDex < ACURR(A_DEX) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( dexLabel, normalStyle, greenStyle); } else if (lastDex > ACURR(A_DEX) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( dexLabel, normalStyle, redStyle); } lastDex = ACURR(A_DEX); gtk_label_set( GTK_LABEL( dexLabel), buf); sprintf(buf,"CON:%d",ACURR(A_CON)); if (lastCon < ACURR(A_CON) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( conLabel, normalStyle, greenStyle); } else if (lastCon > ACURR(A_CON) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( conLabel, normalStyle, redStyle); } lastCon = ACURR(A_CON); gtk_label_set( GTK_LABEL( conLabel), buf); sprintf(buf,"CHA:%d",ACURR(A_CHA)); if (lastCha < ACURR(A_CHA) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( chaLabel, normalStyle, greenStyle); } else if (lastCha > ACURR(A_CHA) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( chaLabel, normalStyle, redStyle); } lastCha = ACURR(A_CHA); gtk_label_set( GTK_LABEL( chaLabel), buf); /* Now do the non-pixmaped stats (gold and such) */ #ifndef GOLDOBJ sprintf(buf,"Au:%ld", u.ugold); if (lastAu < u.ugold && firstTime==FALSE) { #else umoney = money_cnt(invent); sprintf(buf,"Au:%ld", umoney); if (lastAu < umoney && firstTime==FALSE) { #endif /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( goldLabel, normalStyle, greenStyle); } #ifndef GOLDOBJ else if (lastAu > u.ugold && firstTime==FALSE) { #else else if (lastAu > umoney && firstTime==FALSE) { #endif /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( goldLabel, normalStyle, redStyle); } #ifndef GOLDOBJ lastAu = u.ugold; #else lastAu = umoney; #endif gtk_label_set( GTK_LABEL( goldLabel), buf); if (u.mtimedone) { /* special case: when polymorphed, show "HD", disable exp */ sprintf(buf,"HP:%d/%d", ( (u.mh > 0)? u.mh : 0), u.mhmax); if ((lastHP < u.mh || lastMHP < u.mhmax ) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( hpLabel, normalStyle, greenStyle); } else if ((lastHP > u.mh || lastMHP > u.mhmax ) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( hpLabel, normalStyle, redStyle); } lastHP = u.mh; lastMHP = u.mhmax; } else { sprintf(buf,"HP:%d/%d", ( (u.uhp > 0)? u.uhp : 0), u.uhpmax); if ((lastHP < u.uhp || lastMHP < u.uhpmax ) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( hpLabel, normalStyle, greenStyle); } else if ((lastHP > u.uhp || lastMHP > u.uhpmax ) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( hpLabel, normalStyle, redStyle); } lastHP = u.uhp; lastMHP = u.uhpmax; } gtk_label_set( GTK_LABEL( hpLabel), buf); if (u.mtimedone) { /* special case: when polymorphed, show "HD", disable exp */ sprintf(buf,"HD:%d", mons[u.umonnum].mlevel); if (lastLevel < mons[u.umonnum].mlevel && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( levlLabel, normalStyle, greenStyle); } else if (lastLevel > mons[u.umonnum].mlevel && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( levlLabel, normalStyle, redStyle); } lastLevel = mons[u.umonnum].mlevel; } else { sprintf(buf,"Level:%d", u.ulevel); if (lastLevel < u.ulevel && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( levlLabel, normalStyle, greenStyle); } else if (lastLevel > u.ulevel && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( levlLabel, normalStyle, redStyle); } lastLevel = u.ulevel; } gtk_label_set( GTK_LABEL( levlLabel), buf); sprintf(buf,"Power:%d/%d", u.uen, u.uenmax); if ((lastPOW < u.uen || lastMPOW < u.uenmax) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( powLabel, normalStyle, greenStyle); } if ((lastPOW > u.uen || lastMPOW > u.uenmax) && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( powLabel, normalStyle, redStyle); } lastPOW = u.uen; lastMPOW = u.uenmax; gtk_label_set( GTK_LABEL( powLabel), buf); sprintf(buf,"AC:%d", u.uac); if (lastAC > u.uac && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( acLabel, normalStyle, greenStyle); } else if (lastAC < u.uac && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( acLabel, normalStyle, redStyle); } lastAC = u.uac; gtk_label_set( GTK_LABEL( acLabel), buf); #ifdef EXP_ON_BOTL if (flags.showexp) { sprintf(buf,"Exp:%ld", u.uexp); if (lastExp < u.uexp && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( expLabel, normalStyle, greenStyle); } else if (lastExp > u.uexp && firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( expLabel, normalStyle, redStyle); } lastExp = u.uexp; gtk_label_set( GTK_LABEL( expLabel), buf); } else #endif { gtk_label_set( GTK_LABEL( expLabel), ""); } if (flags.time) { sprintf(buf,"Time:%ld", moves); gtk_label_set( GTK_LABEL( timeLabel), buf); } else gtk_label_set( GTK_LABEL( timeLabel), ""); #ifdef SCORE_ON_BOTL if (flags.showscore) { sprintf(buf,"Score:%ld", botl_score()); gtk_label_set( GTK_LABEL( scoreLabel), buf); } else gtk_label_set( GTK_LABEL( scoreLabel), ""); #else { gtk_label_set( GTK_LABEL( scoreLabel), ""); } #endif /* See if their alignment has changed */ if (lastAlignment != u.ualign.type) { if (firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( alignLabel, normalStyle, redStyle); } lastAlignment = u.ualign.type; /* looks like their alignment has changed -- change out the icon */ if (u.ualign.type==A_CHAOTIC) { gtk_label_set( GTK_LABEL( alignLabel), "Chaotic"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(alignPix), chaotic_xpm); } else if (u.ualign.type==A_NEUTRAL) { gtk_label_set( GTK_LABEL( alignLabel), "Neutral"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(alignPix), neutral_xpm); } else { gtk_label_set( GTK_LABEL( alignLabel), "Lawful"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(alignPix), lawful_xpm); } } hung=hu_stat[u.uhs]; if (lastHungr != u.uhs) { if (firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( hungerLabel, normalStyle, redStyle); } lastHungr = u.uhs; if (hung[0]==' ') { gtk_label_set( GTK_LABEL( hungerLabel), " "); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(hungerPix), nothing_xpm); } else if (u.uhs == 0 /* SATIATED */) { gtk_label_set( GTK_LABEL( hungerLabel), hung); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(hungerPix), satiated_xpm); } else { gtk_label_set( GTK_LABEL( hungerLabel), hung); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(hungerPix), hungry_xpm); } } if (lastConf != Confusion) { if (firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( confuLabel, normalStyle, redStyle); } lastConf = Confusion; if (Confusion) { gtk_label_set( GTK_LABEL( confuLabel), "Confused"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(confuPix), confused_xpm); } else { gtk_label_set( GTK_LABEL( confuLabel), " "); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(confuPix), nothing_xpm); } } if (lastBlind != Blind) { if (firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( blindLabel, normalStyle, redStyle); } lastBlind = Blind; if (Blind) { gtk_label_set( GTK_LABEL( blindLabel), "Blind"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(blindPix), blind_xpm); } else { gtk_label_set( GTK_LABEL( blindLabel), " "); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(blindPix), nothing_xpm); } } if (lastStun != Stunned) { if (firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( stunLabel, normalStyle, redStyle); } lastStun = Stunned; if (Stunned) { gtk_label_set( GTK_LABEL( stunLabel), "Stun"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(stunPix), stunned_xpm); } else { gtk_label_set( GTK_LABEL( stunLabel), " "); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(stunPix), nothing_xpm); } } if (lastHalu != Hallucination) { if (firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( halluLabel, normalStyle, redStyle); } lastHalu = Hallucination; if (Hallucination) { gtk_label_set( GTK_LABEL( halluLabel), "Hallu"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(halluPix), hallu_xpm); } else { gtk_label_set( GTK_LABEL( halluLabel), " "); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(halluPix), nothing_xpm); } } if (lastSick != Sick) { if (firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( sickLabel, normalStyle, redStyle); } lastSick = Sick; if (Sick) { if (u.usick_type & SICK_VOMITABLE) { gtk_label_set( GTK_LABEL( sickLabel), "FoodPois"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(sickPix), sick_fp_xpm); } else if (u.usick_type & SICK_NONVOMITABLE) { gtk_label_set( GTK_LABEL( sickLabel), "Ill"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(sickPix), sick_il_xpm); } else { gtk_label_set( GTK_LABEL( sickLabel), "FoodPois"); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(sickPix), sick_fp_xpm); } } else { gtk_label_set( GTK_LABEL( sickLabel), " "); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(sickPix), nothing_xpm); } } enc=enc_stat[near_capacity()]; if (lastEncumb != near_capacity()) { if (firstTime==FALSE) { /* Ok, this changed so add it to the highlighing list */ ghack_highlight_widget( encumbLabel, normalStyle, redStyle); } lastEncumb = near_capacity(); switch ( lastEncumb ) { case 0: gtk_label_set( GTK_LABEL( encumbLabel), " "); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), nothing_xpm); break; case 1: gtk_label_set( GTK_LABEL( encumbLabel), enc); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), slt_enc_xpm); break; case 2: gtk_label_set( GTK_LABEL( encumbLabel), enc); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), mod_enc_xpm); break; case 3: gtk_label_set( GTK_LABEL( encumbLabel), enc); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), hvy_enc_xpm); break; case 4: gtk_label_set( GTK_LABEL( encumbLabel), enc); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), ext_enc_xpm); break; case 5: gtk_label_set( GTK_LABEL( encumbLabel), enc); gnome_pixmap_load_xpm_d( GNOME_PIXMAP(encumbPix), ovr_enc_xpm); } } firstTime=FALSE; } static void ghack_fade_highlighting() { GList *item; Highlight *highlt; /* Remove any items from the queue if their time is up */ for (item = g_list_first( s_HighLightList) ; item ; ) { highlt = (Highlight*) item->data; if (highlt) { if ( highlt->nTurnsLeft <= 0) { gtk_widget_set_style( GTK_WIDGET( highlt->widget), highlt->oldStyle); s_HighLightList = g_list_remove_link(s_HighLightList, item); g_free( highlt); g_list_free_1( item); item = g_list_first( s_HighLightList); continue; } else (highlt->nTurnsLeft)--; } if (item) item=item->next; else break; } } /* Widget changed, so add it to the highlighing list */ static void ghack_highlight_widget( GtkWidget* widget, GtkStyle* oldStyle, GtkStyle* newStyle) { Highlight *highlt; GList *item; /* Check if this widget is already in the queue. If so then * remove it, so we will only have the new entry in the queue */ for (item = g_list_first( s_HighLightList) ; item ; ) { highlt = (Highlight*) item->data; if (highlt) { if ( highlt->widget == widget) { s_HighLightList = g_list_remove_link(s_HighLightList, item); g_free( highlt); g_list_free_1( item); break; } } if (item) item=item->next; else break; } /* Ok, now highlight this widget and add it into the fade * highlighting queue */ highlt = g_new( Highlight, 1); highlt->nTurnsLeft=NUM_TURNS_HIGHLIGHTED; highlt->oldStyle=oldStyle; highlt->widget=widget; s_HighLightList = g_list_prepend (s_HighLightList, highlt); gtk_widget_set_style( GTK_WIDGET( widget), newStyle); } nethack-3.4.3/win/gnome/gnstatus.h0100644000000000000000000000057607764735042015606 0ustar rootroot/* SCCS Id: @(#)gnstatus.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackStatusWindow_h #define GnomeHackStatusWindow_h #include #include "config.h" #include "global.h" GtkWidget* ghack_init_status_window (); #endif /* GnomeHackStatusWindow_h */ nethack-3.4.3/win/gnome/gntext.c0100644000000000000000000001122607764735042015234 0ustar rootroot/* SCCS Id: @(#)gntext.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gntext.h" #include "gnmain.h" #include /* include the standard RIP window (win/X11/rip.xpm) */ #include "gn_rip.h" /* dimensions of the pixmap */ #define RIP_IMAGE_WIDTH 400 #define RIP_IMAGE_HEIGHT 200 /* dimensions and location of area where we can draw text on the pixmap */ #define RIP_DRAW_WIDTH 84 #define RIP_DRAW_HEIGHT 89 #define RIP_DRAW_X 114 #define RIP_DRAW_Y 69 /* Text Window widgets */ GtkWidget *RIP = NULL; GtkWidget *RIPlabel = NULL; GtkWidget *TW_window = NULL; GnomeLess *gless; static int showRIP = 0; void ghack_text_window_clear(GtkWidget *widget, gpointer data) { g_assert (gless != NULL); gtk_editable_delete_text (GTK_EDITABLE (gless->text), 0, 0); } void ghack_text_window_destroy() { TW_window = NULL; } void ghack_text_window_display(GtkWidget *widget, boolean block, gpointer data) { if(showRIP == 1) { gtk_widget_show (GTK_WIDGET ( RIP)); gtk_window_set_title(GTK_WINDOW( TW_window), "Rest In Peace"); } gtk_signal_connect (GTK_OBJECT (TW_window), "destroy", (GtkSignalFunc) ghack_text_window_destroy, NULL); if (block) gnome_dialog_run(GNOME_DIALOG(TW_window)); else gnome_dialog_run_and_close(GNOME_DIALOG(TW_window)); if(showRIP == 1) { showRIP = 0; gtk_widget_hide (GTK_WIDGET ( RIP)); gtk_window_set_title(GTK_WINDOW(TW_window), "Text Window"); } } void ghack_text_window_put_string(GtkWidget *widget, int attr, const char* text, gpointer data) { if(text == NULL) return; /* Don't bother with attributes yet */ gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, text, -1); gtk_text_insert (GTK_TEXT (gless->text), NULL, NULL, NULL, "\n", -1); } GtkWidget* ghack_init_text_window ( ) { GtkWidget *pixmap; if(TW_window) return(GTK_WIDGET(TW_window)); TW_window = gnome_dialog_new("Text Window", GNOME_STOCK_BUTTON_OK, NULL); gtk_window_set_default_size( GTK_WINDOW(TW_window), 500, 400); gtk_window_set_policy(GTK_WINDOW(TW_window), TRUE, TRUE, FALSE); gtk_window_set_title(GTK_WINDOW(TW_window), "Text Window"); /* create GNOME pixmap object */ pixmap = gnome_pixmap_new_from_xpm_d (rip_xpm); g_assert (pixmap != NULL); gtk_widget_show (GTK_WIDGET (pixmap)); /* create label with our "death message", sized to fit into the * tombstone */ RIPlabel = gtk_label_new ("RIP"); g_assert (RIPlabel != NULL); /* gtk_label_set_justify is broken? */ gtk_label_set_justify (GTK_LABEL (RIPlabel), GTK_JUSTIFY_CENTER); gtk_label_set_line_wrap (GTK_LABEL (RIPlabel), TRUE); gtk_widget_set_usize (RIPlabel, RIP_DRAW_WIDTH, RIP_DRAW_HEIGHT); gtk_widget_show (RIPlabel); /* create a fixed sized widget for the RIP pixmap */ RIP = gtk_fixed_new (); g_assert (RIP != NULL); gtk_widget_set_usize (RIP, RIP_IMAGE_WIDTH, RIP_IMAGE_HEIGHT); gtk_fixed_put (GTK_FIXED (RIP), pixmap, 0, 0); gtk_fixed_put (GTK_FIXED (RIP), RIPlabel, RIP_DRAW_X, RIP_DRAW_Y); gtk_widget_show (RIP); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(TW_window)->vbox), RIP, TRUE, TRUE, 0); /* create a gnome Less widget for the text stuff */ gless = GNOME_LESS (gnome_less_new ()); g_assert (gless != NULL); gtk_widget_show (GTK_WIDGET (gless)); gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(TW_window)->vbox), GTK_WIDGET (gless), TRUE, TRUE, 0); /* Hook up some signals */ gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_putstr", GTK_SIGNAL_FUNC(ghack_text_window_put_string), NULL); gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_clear", GTK_SIGNAL_FUNC(ghack_text_window_clear), NULL); gtk_signal_connect(GTK_OBJECT(TW_window), "ghack_display", GTK_SIGNAL_FUNC(ghack_text_window_display), NULL); /* Center the dialog over over parent */ gnome_dialog_set_parent( GNOME_DIALOG (TW_window), GTK_WINDOW(ghack_get_main_window()) ); gtk_window_set_modal( GTK_WINDOW(TW_window), TRUE); gtk_widget_show_all(TW_window); gtk_widget_hide (GTK_WIDGET ( RIP)); gnome_dialog_close_hides (GNOME_DIALOG (TW_window), TRUE); return GTK_WIDGET(TW_window); } void ghack_text_window_rip_string( const char* string) { /* This is called to specify that the next message window will * be a RIP window, which will include this text */ showRIP = 1; gtk_label_set( GTK_LABEL( RIPlabel), string); } nethack-3.4.3/win/gnome/gntext.h0100644000000000000000000000140507764735042015237 0ustar rootroot/* SCCS Id: @(#)gntext.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackTextWindow_h #define GnomeHackTextWindow_h #include #include "config.h" #include "global.h" GtkWidget* ghack_init_text_window ( ); void ghack_text_window_clear(GtkWidget *widget, gpointer data); void ghack_text_window_destroy(); void ghack_text_window_display(GtkWidget *widget, boolean block, gpointer data); void ghack_text_window_put_string(GtkWidget *widget, int attr, const char* text, gpointer data); void ghack_text_window_rip_string( const char* ripString); #endif /* GnomeHackTextWindow_h */ nethack-3.4.3/win/gnome/gnworn.c0100644000000000000000000000570007764735042015235 0ustar rootroot/* SCCS Id: @(#)gnbind.c 3.4 2002/04/15 */ /* Copyright (C) 2002, Dylan Alex Simon */ /* NetHack may be freely redistributed. See license for details. */ #include "gnworn.h" #include "gnglyph.h" #include "gnsignal.h" #include "gnomeprv.h" #define WORN_WIDTH 3 #define WORN_HEIGHT 6 #ifdef TOURIST #define WORN_OBJECT_LIST /* struct obj *[WORN_HEIGHT][WORN_WIDTH] = */ { \ { uquiver, uarmh, u.twoweap ? NULL : uswapwep }, \ { u.twoweap ? uswapwep : NULL, ublindf, uwep }, \ { uleft, uamul, uright }, \ { uarms, uarmc, uarmg }, \ { uarmu, uarm, uskin }, \ { uball, uarmf, uchain } \ } #else #define WORN_OBJECT_LIST /* struct obj *[WORN_HEIGHT][WORN_WIDTH] = */ { \ { uquiver, uarmh, u.twoweap ? NULL : uswapwep }, \ { u.twoweap ? uswapwep : NULL, ublindf, uwep }, \ { uleft, uamul, uright }, \ { uarms, uarmc, uarmg }, \ { NULL, uarm, uskin }, \ { uball, uarmf, uchain } \ } #endif static GtkWidget *worn_contents[WORN_HEIGHT][WORN_WIDTH]; static struct obj *last_worn_objects[WORN_HEIGHT][WORN_WIDTH]; GdkImlibImage *image_of_worn_object(struct obj *o); void ghack_worn_display(GtkWidget *win, boolean block, gpointer data); GtkWidget* ghack_init_worn_window() { GtkWidget *top; GtkWidget *table; GtkWidget *tablealign; GtkWidget *label; int i,j; top = gtk_vbox_new(FALSE, 2); table = gtk_table_new(WORN_HEIGHT, WORN_WIDTH, TRUE); for (i = 0; i < WORN_HEIGHT; i++) { for (j = 0; j < WORN_WIDTH; j++) { worn_contents[i][j] = gnome_pixmap_new_from_imlib(image_of_worn_object(NULL)); last_worn_objects[i][j] = NULL; /* a pointer that will never be */ gtk_table_attach(GTK_TABLE(table), GTK_WIDGET(worn_contents[i][j]), j, j+1, i, i+1, 0, 0, 0, 0); } } tablealign = gtk_alignment_new(0.5, 0.0, 0.0, 1.0); gtk_box_pack_start(GTK_BOX(top), tablealign, FALSE, FALSE, 0); gtk_container_add(GTK_CONTAINER(tablealign), table); label = gtk_label_new("Equipment"); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); gtk_box_pack_start(GTK_BOX(top), label, FALSE, FALSE, 0); gtk_signal_connect(GTK_OBJECT(top), "ghack_display", GTK_SIGNAL_FUNC(ghack_worn_display), NULL); return top; } GdkImlibImage* image_of_worn_object(struct obj *o) { int glyph; GdkImlibImage *im; if (o) glyph = obj_to_glyph(o); else glyph = cmap_to_glyph(S_stone); im = ghack_image_from_glyph(glyph, FALSE); return im; } void ghack_worn_display(GtkWidget *win, boolean block, gpointer data) { int i, j; struct obj *worn_objects[WORN_HEIGHT][WORN_WIDTH] = WORN_OBJECT_LIST; for (i = 0; i < WORN_HEIGHT; i++) { for (j = 0; j < WORN_WIDTH; j++) { if (worn_objects[i][j] != last_worn_objects[i][j]) { last_worn_objects[i][j] = worn_objects[i][j]; gnome_pixmap_load_imlib(GNOME_PIXMAP(worn_contents[i][j]), image_of_worn_object(worn_objects[i][j])); } } } } nethack-3.4.3/win/gnome/gnworn.h0100644000000000000000000000054107764735042015240 0ustar rootroot/* SCCS Id: @(#)gnbind.c 3.4 2002/04/15 */ /* Copyright (C) 2002 by Dylan Alex Simon */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackWornWindow_h #define GnomeHackWornWindow_h #include #include "config.h" #include "global.h" GtkWidget* ghack_init_worn_window(); #endif /* GnomeHackWornWindow_h */ nethack-3.4.3/win/gnome/gnyesno.c0100644000000000000000000000440107764735042015402 0ustar rootroot/* SCCS Id: @(#)gnyesno.c 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #include "gnbind.h" #include "gnyesno.h" int ghack_yes_no_dialog( const char *question, const char *choices, int def) { int i=0, ret; gchar button_name[BUFSZ]; GtkWidget *box; GtkWidget* mainWnd=NULL; box = gnome_message_box_new ( question, GNOME_MESSAGE_BOX_QUESTION, NULL); /* add buttons for each choice */ if (!strcmp(GNOME_STOCK_BUTTON_OK, choices)) { gnome_dialog_append_button ( GNOME_DIALOG(box), GNOME_STOCK_BUTTON_OK); gnome_dialog_set_default( GNOME_DIALOG(box), 0); gnome_dialog_set_accelerator( GNOME_DIALOG(box), 0, 'o', 0); #if 0 g_print("Setting accelerator '%c' for button %d\n", 'o', 0); #endif } else { for( ; choices[i]!='\0'; i++) { if (choices[i]=='y') { sprintf( button_name, GNOME_STOCK_BUTTON_YES); } else if (choices[i]=='n') { sprintf( button_name, GNOME_STOCK_BUTTON_NO); } else if (choices[i] == 'q') { sprintf( button_name, "Quit"); } else { sprintf( button_name, "%c", choices[i]); } if (def==choices[i]) gnome_dialog_set_default( GNOME_DIALOG(box), i); gnome_dialog_append_button ( GNOME_DIALOG(box), button_name); gnome_dialog_set_accelerator( GNOME_DIALOG(box), i, choices[i], 0); #if 0 g_print("Setting accelerator '%c' for button %d\n", choices[i], i); #endif } } #if 0 /* Perhaps add in a quit game button, like this... */ gnome_dialog_append_button ( GNOME_DIALOG(box), GNOME_STOCK_BUTTON_CLOSE); gnome_dialog_set_accelerator( GNOME_DIALOG(box), i, choices[i], 0); g_print("Setting accelerator '%c' for button %d\n", 'Q', i); #endif gnome_dialog_set_close(GNOME_DIALOG (box), TRUE); mainWnd = ghack_get_main_window (); gtk_window_set_modal( GTK_WINDOW(box), TRUE); gtk_window_set_title( GTK_WINDOW(box), "GnomeHack"); if ( mainWnd != NULL ) { gnome_dialog_set_parent (GNOME_DIALOG (box), GTK_WINDOW ( mainWnd) ); } ret=gnome_dialog_run_and_close ( GNOME_DIALOG (box)); #if 0 g_print("You selected button %d\n", ret); #endif if (ret==-1) return( '\033'); else return( choices[ret]); } nethack-3.4.3/win/gnome/gnyesno.h0100644000000000000000000000053107764735042015407 0ustar rootroot/* SCCS Id: @(#)gnyesno.h 3.4 2000/07/16 */ /* Copyright (C) 1998 by Erik Andersen */ /* NetHack may be freely redistributed. See license for details. */ #ifndef GnomeHackYesNoDialog_h #define GnomeHackYesNoDialog_h int ghack_yes_no_dialog( const char* szQuestionStr, const char* szChoicesStr, int nDefault); #endif nethack-3.4.3/win/gnome/mapbg.xpm0100644000000000000000000005462507764735042015405 0ustar rootroot/* XPM */ static char * mapbg_xpm[] = { "96 96 254 2", " c None", ". c #BC6C33", "+ c #AC6324", "@ c #B46B2B", "# c #B47734", "$ c #AC6B2C", "% c #B46C3D", "& c #BC7945", "* c #A4774B", "= c #B48643", "- c #AC7F40", "; c #AC773A", "> c #C49054", ", c #C48044", "' c #B4642C", ") c #B45E21", "! c #BC642B", "~ c #BD723E", "{ c #C4884E", "] c #C48F4B", "^ c #C49753", "/ c #CC9052", "( c #CC7234", "_ c #B4804F", ": c #C4985D", "< c #946232", "[ c #AC6431", "} c #C46637", "| c #945222", "1 c #8C5435", "2 c #844C29", "3 c #945836", "4 c #AC653D", "5 c #A45E2B", "6 c #AC5E2A", "7 c #A44D21", "8 c #A45823", "9 c #A4592C", "0 c #B46C34", "a c #B46536", "b c #AC7240", "c c #AC7231", "d c #944C1B", "e c #8C5223", "f c #945722", "g c #AC6B34", "h c #944C24", "i c #9C5222", "j c #B47234", "k c #C4783B", "l c #BC7833", "m c #BC7F3B", "n c #BC8044", "o c #BC783C", "p c #A46332", "q c #9C6331", "r c #B4773C", "s c #B4723D", "t c #A46B33", "u c #B48043", "v c #CC814C", "w c #B46422", "x c #C47946", "y c #C48743", "z c #BC6D3D", "A c #BC6536", "B c #94522E", "C c #A4643E", "D c #B45E2F", "E c #A45223", "F c #9C4C1B", "G c #B47845", "H c #C4804D", "I c #9C5723", "J c #AC5E35", "K c #A45935", "L c #9B5E29", "M c #BE7234", "N c #BC8744", "O c #AC5924", "P c #A45E35", "Q c #9C582C", "R c #AC501F", "S c #9C5935", "T c #8C4D28", "U c #643D21", "V c #845437", "W c #B47E31", "X c #844126", "Y c #B45823", "Z c #954627", "` c #9C4C24", " . c #7C4124", ".. c #B4592D", "+. c #9C5E37", "@. c #945644", "#. c #AC6C3E", "$. c #8C4627", "%. c #9C643E", "&. c #744021", "*. c #A4723C", "=. c #844628", "-. c #743819", ";. c #844019", ">. c #944D2D", ",. c #A4512C", "'. c #B45227", "). c #C4622A", "!. c #9C522E", "~. c #7C3A1A", "{. c #BC5E24", "]. c #CC8243", "^. c #9C664C", "/. c #AC5934", "(. c #9C4E2E", "_. c #7C4B29", ":. c #8C532C", "<. c #A46423", "[. c #7C422C", "}. c #743214", "|. c #AC592C", "1. c #8C4224", "2. c #C47F3C", "3. c #8C421C", "4. c #8C410F", "5. c #8C5D3E", "6. c #8C5B32", "7. c #88461A", "8. c #663626", "9. c #AC6B4C", "0. c #94411A", "a. c #845C30", "b. c #744B20", "c. c #7C4D34", "d. c #CC874A", "e. c #D49053", "f. c #C46C32", "g. c #BC814D", "h. c #CC7842", "i. c #A45A44", "j. c #8C4B1A", "k. c #843204", "l. c #945E37", "m. c #7C564C", "n. c #74422C", "o. c #95461B", "p. c #AC7747", "q. c #745634", "r. c #94572C", "s. c #7C4621", "t. c #CC7A54", "u. c #B47654", "v. c #BC5E2C", "w. c #B49056", "x. c #C4915C", "y. c #B4874E", "z. c #BC884D", "A. c #A46C45", "B. c #D48749", "C. c #BC5A30", "D. c #CCA06C", "E. c #BCA26C", "F. c #BC8F54", "G. c #BC895C", "H. c #BC8F4C", "I. c #BC995E", "J. c #C46D3D", "K. c #D4985A", "L. c #C4562C", "M. c #843A16", "N. c #C49F63", "O. c #BC9652", "P. c #B48F4C", "Q. c #CC915C", "R. c #BC5824", "S. c #B49A60", "T. c #CC9F60", "U. c #DC995F", "V. c #AC8A54", "W. c #B4875F", "X. c #C4885C", "Y. c #BC905E", "Z. c #CC975B", "`. c #D4A167", " + c #7C5334", ".+ c #9C6B39", "++ c #845323", "@+ c #B46D4C", "#+ c #A46B3C", "$+ c #CC9864", "%+ c #8C4E34", "&+ c #743A24", "*+ c #6C3D2E", "=+ c #C45E30", "-+ c #AC7E52", ";+ c #9C6C47", ">+ c #6C3C1B", ",+ c #CC8954", "'+ c #542810", ")+ c #7C5E3C", "!+ c #84532C", "~+ c #946C45", "{+ c #946340", "]+ c #BCA870", "^+ c #B49E5C", "/+ c #C47E5C", "(+ c #AC8E44", "_+ c #8C633A", ":+ c #C4A86C", "<+ c #CCA76E", "[+ c #CCA961", "}+ c #7A462D", "|+ c #8C6644", "1+ c #744623", "2+ c #A47248", "3+ c #94624C", "4+ c #845E3C", "5+ c #7C5329", "6+ c #9C7249", "7+ c #844D34", "8+ c #6C4C30", "9+ c #A46E54", "0+ c #A4624C", "a+ c #6C3E24", "b+ c #5C3224", "c+ c #D4A66C", "d+ c #744B30", "e+ c #BC926C", "f+ c #AC7954", "g+ c #AC522C", "h+ c #6C4526", "i+ c #A47A54", "j+ c #BC6644", "k+ c #BC6E4C", "l+ c #A48650", "m+ c #AC825C", "n+ c #CC6A34", "o+ c #9C7E5C", "p+ c #7C623C", "q+ c #5C3A2C", "r+ c #644A34", "s+ c #4C3624", "t+ c #844B1B", "u+ c #7C4018", "v+ c #D49A68", "w+ c #7C4B1C", "x+ c #742E04", "y+ c #CC8157", "z+ c #745A44", "A+ c #B46644", "B+ c #643614", "C+ c #C4A65C", "D+ c #843A04", "E+ c #6C2E14", ". + @ # @ $ % & * = - ; > , ' . ) ! ~ { ] ^ ] / ( ' , _ : < [ } [ | 1 2 3 4 5 ! 6 7 8 ' 8 9 0 a b c d | [ 0 % e 8 f 5 ~ g h i % & % 5 a ' 8 ' a < j k l m { n o . ! 6 . 0 % p p q g r s 0 @ 0 . ", "j + $ # @ t g s u > u c { v @ ! w ' ~ x y y m u . ) z r > f 5 A [ B 3 2 B C 6 @ D E E 8 F i 6 0 g G 0 o H , j d I I [ & % i f [ . @ . 6 J K 2 3 L $ . M o N # j D ' O % [ 0 p P L g & l 0 0 . % ", "4 Q 5 % j $ @ g u / G t M k ' R 9 9 J A . M p 3 . O ! M { L 3 4 [ Q S T B Q 6 ' 6 6 J a a 9 9 a c & 0 ~ ~ z 0 L 5 8 5 [ [ d 8 & M . x i B 3 U V 3 4 . l & N m W 6 6 8 % [ g 8 5 q % & o j [ [ 0 ", "3 X h [ 0 0 0 0 ~ n j p 0 z Y 7 T Z ` Y ! ' Q .a ..! . , t +.@.#.[ C S S 9 [ . D a J a z J 8 % , o + 8 8 [ @ ' J 9 Q 6 5 5 [ x P [ 4 $.1 %.&.V S p ~ o b *.; c 9 6 5 % [ [ 5 p p b & o 0 $ [ 6 ", "=.-.;.9 a . j j . 0 [ @ z . Y O >.h ,.'.).! !.~.P D {.! ].& ^.T & & s % 4 [ A . 4 /.` Z (.d Q , H #.8 E 8 [ [ [ a 9 /.% z 0 . ~ _.1 :.T S C S | < <.M 0 | 2 T >.Q Q | [ 5 [ p 0 0 % # s j % 5 !.", "[.}.~.!.' 0 @ @ . 6 O 0 ~ a D Y P K |.... . K 1.8 D {.! 2.y b Q o x % % a 6 . A ,.` 3.1.1.4.i ~ & 5 i d 8 J 9 [ A J |.D a D a a 5.3 .;.h 8 a I 6.f $ g 7.}.1.$.T T T +.Q 0 g 0 % % 0 0 0 % 5 h ", "_.8.;.E 6 ' ' @ ' O 8 ' @ . a ..+ D 9 9 0 o ~ p 6 ' ! . , n 0 . 0 o [ A a |.a 6 ` 3.Z (.>.$.I 0 #.e h d !.J I C a D E F F 7 |.D 9.>.>.Z 0.9 a 8 a.b.Q [ =.;.!.K 2 T 7.S 5 #.[ 0 g [ g g % g J Q ", "c.-.;.8 D ) @ w . ' w [ a ~ ~ Y O O 9 S c d.e.d.f.A . H g.# @ h.$ ~ [ % z |.. 6 /.Z ` i.Z d [ o %.j.S P 4 % Q p E 8 O 7 F Z E /.O k.a a 9 & #.l.m.n.B C j.T 5 ) :.:.2 q p % [ [ [ [ [ [ [ 4 p Q ", "o.F i I 9 [ 0 0 ' 6 8 6 # n o 0 @ ) L W d.].0 [ + @ M k m ; $ @ $ 0 j 0 0 0 0 a c g G p.q f p s ' 0 d !.Q h & M Y '.7 E 7 7 7 R [ @ ) |.[ 4 3 b.q.b.2 L % g P r.j.I 6 a a 6 + [ [ p [ [ g & & I ", "I d d E 0 ~ 0 6 ' O E 8 j n m . ( j # N 2.@ O !.@ @ ! M r # # M # m n , & r % s m r & o p I [ [ $ @ 7.Q P Q o j f.. O 8 F 7 O ..6 ' ' ..a a q 2 _.s.;.j.F o.o.j.I 5 p O 8 O @ M [ 0 0 g 0 o ~ L ", "[ 9 F 9 z t.. O ' ) O w r n , ~ A % u.n o w |.|.a ' D ' o o n ~ j l , N n r G _ u 0 #.a |.[ 0 # n r | 9 P 8 0 [ l o o % g [ D 6 7 O ..Y a A 4 p C #.s ' O 6 D a g % 0 a [ 6 [ 0 @ , k o o n o c ", "[ [ [ ' a . a |.8 O Y 0 o ~ . v./.r.S #.z . D D 5 6 ..! s & o ~ # o m r u _ w.x.y.p.[ J 6 % y z.] n p g a 6 @ [ # m y { m ~ @ @ 9 |.D ' A ~ % [ A.G x ~ ' ! 0 z 0 0 0 % . 0 [ [ [ o o $ M # 0 o ", "g s ~ 0 0 a ' ' O ' ~ B.{ o ' C./.$.;.B ' A R ` Z ,...A . o & ~ y m N N ] : : D.E.F.G.g.G _ H.I.y N s % 0 a z M r u m & o o m m & & ~ ~ l j 0 <.t s G j $ 0 # j % [ 8 [ 0 % . ~ @ o o 0 r j # y ", "o o l s o & , x 0 J.B.e.K., . L.a >.M.d 6 ! E 3.M.o...! . & n r 2.y n { > : : F.I.I.N.: y.F.O.P.n o a ' D 6 ' 0 $ c % o & o o m & G # j # r c [ q p L I I L <.p . ' [ 0 o % 0 % o k o o o o o , ", "k n o o & { / Q., l ~ , { m ! R.D !.h 6 . . ) P 7.i ..w M m { n m n N z.z.z.y.= y.z.I.S.w.I.x.g.o ' 6 Y R O 8 [ [ a [ a z o r # s j j j @ 0 . 0 ~ . 0 0 0 0 0 o ! . o H o [ [ a g 6 [ s 0 g g g ", "@ o o r c u > T.U.H # n ] n J.).D 6 0 k ( M ~ & +.[ D w l y / g.{ { { { N z.] > y z.w.w.V.W.X.& ~ 6 Y R Y ! ' 0 ~ a E 7 9 0 m n o k k k . ' D } D D A z z ' [ A 6 ' 0 0 p L [ x a I [ & & & s g ", "I E D ! 0 s z.F.T.H.o o h.d., c j m / Y.Z.`.n t ' ' $ , y y N m m y y ] { z.n N n { ; > H.r / z.~ p E O D 6 ' . @ 5 i d F 5 g r [ j o 0 g % 0 [ ' 6 5 p I 4.4.o.o.d e U +c.6..+[ i j d.# m { p ", "0 5 i O a g.Q.F.T.^ N o & ].n @ # m { b p.Q.N c ! a M , / { m m W m N z.z.n N y n { ; z.] u ] r 0 + 8 ..a D w @ @ ' 8 d T r.g r @ 0 g [ <.[ [ p 5 5 [ p Q Q 5 z 6 p :.b.V _.l.p s 5 0 m @ # { G ", "H ~ [ a & H g._ > Z.: ] z.] , o . o ~ f Q H H j . . x y d., 2.o y N z.z.z.N n & { { ; z.> u { s 0 a D 6 v.a ' w Y O >. .&.2 q $ g 0 [ 5 5 [ [ [ 0 [ | 7.>.Q 9 h !.P ++2 5.=.4 @ C | Q P Q 5 0 k ", "H , s % @+#.#+#+#.z.$+N.: Z.H k 0 a a E 9 & x ~ z k x , , l M k y ] > ^ > G.n m { N u ] ^ { y s k . a |.6 ! ' + {.|.%+&+*+V p l [ $ @ [ $ 0 0 p % S 7.$.B C Q T ;.3 T 2 @.%+a @ +.T $.>.K 9 [ k ", "n & q B +.+.S p :.#+y.Y.w.H.{ , J.a a /.a z a o x k , o ~ . . f.# n ] : Z.: > { o n u > ^ { n o ~ J.a 9 6 0 . @ =+O T 8.8.1 [ 0 $ 0 s j % % g 0 +.Q S !.B h h f ~.4 t %.3 3 4 6 r.T X $.i.J a k ", "~ % B e ^.%.e T 3 q * -+_ u H / x a a a A 0 [ & , { , n l M f.. . o z.> : : ] H o n N F.z.n o J.~ a [ [ 0 % M M w |.Z }.-.T L O j ~ o 0 $ [ [ % p 5 9 K i j.j.| 4.% G p 1 S B r.| T X Z K a [ . ", "' % +.l.* ;+2 2 ;+%.q s b b u x.x % 0 . 0 M j n N z.y n o o f.! ).. & z.F.> z.n n n z.H.z.n 0 . a [ [ b & r g j @ 0 [ >.` K a ' 0 r o % [ 5 5 g $ p 8 9 a ~ o # D @ o #+T @.>+1 K 5 5 [ % ~ z J ", "E a +.1 ;+;+6.A.* %.+.@+% p #+= #.g 0 0 M , r y u N N n o k . {.R.v.0 u G.F.{ z.,+y > H.H.G ' ' @ [ g n z.# $ <.<.0 a |.E a A 0 <.0 x o g L 8 [ <.% 0 8 8 @ k m B.M o g V 1 '+)+h Q @ j M 0 J o.", "_..+^.!+6.l.l.l.~+;+6.V {+:.:.A.r.e q G F.N.]+]+^+I.^ K.d.' 6 z @ M % a /+{ y.H.(+T.^ u ,+2.a ' [ <.t y.x.y.b t L $ @ ' [ 0 # g j j r % [ I p g [ 0 O Y ) w 2.y l j $ @ 5 I P i I <.0 0 0 0 5 e ", ":.%.< :.1 {+l.3 ~+;+_+6.l.!+s.5.3 T q g.> > :+<+:+: H.y ].. ) A + ' 6 9 [ G z.> P.[+^ N { d.0 . . @ s g.z.n 0 @ j o o 0 @ M r # $ j o #.[ <.g #.j . 6 . . 0 , y j l k , g 8 p 5 [ g a z % a 5 i ", "A.%.%.+.l.C #+%.{+~+{+{+5.}+n.}+3 6.#.H { z.> T.<+Z.n o , ~ ! a w ' D 9 !.[ n ] O.<+N.= ] y o l M . o o & s 0 . n n o 0 $ j r # $ j s 0 #.s s # g [ 9 0 z 5 g #+2.o , ,+d.H & 0 s % a a a [ J 5 ", "b S %.C +.^.9.A.5.{+~+^.|+1+*+n.c.1 #.H x o H ,+> { n s x k . . . ! A A O a v y I.[+N.N H.y m 2.h.l l & o r ~ o & m r g g s o G j g b G G r r & r #.[ % 4 | S q o 5 <.~ , d.o $ z a 6 a a /.4 a ", "#.3 +.%.r.+.2+b 5.5.3+;+5.c.n.n.8.T #.~ 0 z x & % & & o x M . z ! D A A D o d.d.: T.: H.z.] y ] 2.m n n z.N N n m G r # r r m r n g c g.{ G j o H r [ #.9 7.e q [ | [ $ g o o o % a [ J [ [ a a ", "C p %.C {+l.;+;+{+4+3+;+l.%+2 .2 Q @+z J 6 K Q [ M & & , s 0 l ~ ' a ' ' o , n F.F.> H.m N N m N N u y.z.H.z.N n n n n z.n G o , s r G.F.r # & o & [ g L j.Q p o 5 0 [ 0 , o x M . s g % % % a ", "C A.#+A.A.;+5.1 ~+5.{+;+^.S +.Q #.g ~ x 6 h $.=.. [ [ r g.o # , , H o 0 j o m N = N { N u u m r N N N n _ u = = & u u _ N _ n r & & n z.z.n o # x x j o o $ o r ].L + [ 0 d.g g 0 n , n u n % p ", "q p.2+A.* ;+5+1+6+a.< A.#+#+~ g v ' . h.a $. .7+. + I #.{ { m / H e.{ k d.y N ] N N ] / n n y m N { { { G G u _ r b r u = u G r ~ g.{ u y.z.n @ 0 0 0 o 2.y ].m , + , o s , 0 & @ , { N , y o 5 ", "k @ j j . H & 6.a.6+a.6+;+s ~ [ 2.j C C !.j.b.8+[ K j.l r H.N.P.= z.K.N Z.; N > r z.H.N ] r t o u u n n u u u V.<.G I p ;.g g u = V.H.u { # o g $ g G z.z.m m , N = = ] # y m # W <.o ~ ; t r t ", ". + $ [ ' ~ & .+l.;+l.2+9+#.~ a n q 1 2 T &.1+q.C [ % { y T.^ I.> z./ o e.r n z.# u N N { u # l u u m r r r p.u s % [ J I 5 r { z.u > u { r r 0 j ~ b g t #.o d.H.y N K.y { o r n g k o g.N { j ", "D 9 + + O ' % b S 0+@.9+C C 4 z A.}+a+b+V &._.7+e p { { { c+F.<+Z.N n $ y 0 ~ % j $ r y n # ~ 0 u m n G r s G n & $ % 5 4 j.t n F.G.] g.{ r n 0 d.n p $.X I # 2.y n u y g 0 0 , 2.' . % & { e.. ", "..|.6 a D D a j S @.2 3+1 5.S #.S [.d+U l.T +.B e b X.g.> D.F.N.x.z.r 6 M D ' |.0 [ o , r j ~ $ r n g.& & r r & s p % P % j.<.p.> z.z._ / n n o y & S ~.~.Q j m / H H v 5 I |.x M ' A /.5 s x a ", "C./.9 9 D v.' . %.7+a+c.d+c.2 q !.1 3+2 #+9 % S u.Z.G.y.e+x.z.f+> { & [ . ....... 0 , v % . ~ ' [ b & n & s ~ s t #.& G & b _ g.z._ z.g./ g.{ H m g Q X >.s { y 5 L p , [ a [ x . ! A |.4.Q z {.", "..g+d 0.7 ..' z %.c.U }+h+5+s.l.$.%+3 h ' ' z g G.$+-+_ Y.* f+r._ H & w D O ..D A z ~ o j % 0 a I [ s G r s b s G x.H X.G X.G.z.G.= G.z.x.z.> > z.u #.C b H > N <.| d % % h.~ ~ . } v./.~.d D v.", "..|.d ;.F ..D . C T _.c.[.B $.P }+ .%+K z ' s _ z.i+-+i+_ 2+;+e t r z [ 6 |.|.A 6 a D [ 0 ~ 0 [ E [ s g.G G r u > : z._ p.G.F.P.Y.F.F.F.: y.> Z.Z.> g.n g.> ] > U.,+o , [ ~ a ! f.{...J 3.| D ! ", "v.J.p h /.A A J.i.B B @.=.i.(.j+a.c.@.k+t.~ A.l+F..+e+m+W.f+;+:.P s % ' D a a z ..D 8 I ~ & 0 a /.@+x z.z.= y.z.x.y.p.A.b y.I.N.: Y.N.: : y.F.N.x.F.N y ] ] : T.r n n , 5 5 [ ' M ! /.k+B 4 . n+", "] u 6 R ! A z g.I #.=.%+l.%+J a B T p [ & C k+g.u ; g.e+o+p+ +3 {+q #.[ 6 . o g [ H [ n { > N j D 6 a & { : I.w._ _ !+_.+.9.Y.N.]+S.I.F.Z.u n n u u - H.Z.N # y I l o u j j m l l l + $ K.] u : ", "z.m @ ' f.~ ~ g.& & :.1 @.S % a %.+.C % @+[ u.& u b _ m+~+)+_+^.#+#.% @ [ . & c s d.g.> ] { z.N ~ z s u G.x.O.F.G -+c.&.1 ^.y.I.]+S.N.G.> n n N ] = ; W Z.] u n @ n o m n m , $ l 2.j k e.{ N Z.", "n , j . k o n > { G e T 3 C H a P 0+J % [ [ % & n G _ f+|+4+2+f+p 4 % a ' ~ , s & % { { F.N z.z., n & n z.z.F.y.s 9+b.U c.@._ O.S.I.N.G.H.n { { N ] H.= H.y m y , , s j g j & . j M . M & [ 5 r ", "n o j . o y z.T.,+_ r.:.:.#.,+a 3 K !.4 8 a % x u G u.A._+|+9+#.4 #.z a [ ~ x % G f u u > ^ z.N N u u g.z.z.g.G p 3 8+q+*+V p.] w.I.T.z.G.z.{ { u ] Z.> z.= r #.~ ].r g <.<.~ o ~ x k z A O i a ", "& o j @ , N ] : K.{ p.#+p #.H g Q P Q a 6 ~ ~ H _ g.& _ p.-+p.#+% % @+0 0 % & #.& | G y.Z.> H.y.> z.u u g.g.G b i 2 r+s+8.7+#+r -+F.T.F.> g.{ g.> ] = u y.g.t t++ & & , r g j 0 o ~ z z z J D z ", "0 o o o n & _ G.x.> { _ G g.H & #.s % s z H H & W.u.g.X.G.e+g.A.i.3 p % % 0 ~ z ~ #.g.> > y.u n Z.> u G r r s #.S 2 +}+n.3 C c u z.Z.> > g.{ & > N y.u p.u #.| g ~ r n H & & 0 r b g a a 6 ' a ", "g o x o @+p +.@+= G.> { ,+{ g.{ g.g., o H v H #.6.1 %.u.-+i+2+l.:.u+!+#.s g M x % & G g.g.G ; u { z.{ n s % g 0 S 2 %.l.Q @+r G G u { G.> _ n G N u > > u p.u.g & G ; r u r u s F.= n & 0 . a a ", "g o n % 9 $.>.0+z.> Z.Q.v+,+n ,+z.n n 0 , & u.I 8+&.1 A.* i+;++.5.&.++b r [ @ ~ % /+5 G g.g.n G c r { H & [ [ p 3 2 C t a ].{ u g.G z.z.: r _ & > u G.x.z._ b r.b n z.> N b G r P.- u n o ~ M 0 ", ";.P 9 ~ #.u+7.6.t u F.y.g.o k m . . a ~ I ~ j p ++s.w+;+{+< _ ;+7+l.2 _ 4 s ' M c c # & s g 0 k @ o u u r g 8 |.2 &.t+b P.w.y.r ; { z.H.; z.o s t ; z.: F.z.n ; # m r t #.c r & u H.; y o ~ ~ Q ", "h T x+K & | r.r.% & y.u s s z s a 9 p [ g & n <.l.>+&.b 2+%.p.f+V 1 3 #.% g % o m u n & & % $ [ p 0 r r n g 9 6 +.e Q u F.P.N r n n ; = u { r s ; r y.x.y.N u # u N o c s s G g.] Z.= ] % a J T ", "X S 3.j.9 K 4 Q A s s % % a 4 +.+.e Q r.G & d.g b 7.:.p.G p.b p.6.6.4 [ x % > z.z.{ { { y n o % $ j r u g.r [ a 3 Q 4 & _ y.n % p.n u g.; ; s H , n z.{ z.g.n o o , n s r & G H = F.= H 9 7 (.T ", "~.P S 3.0.i a K J.~ & & u.@+^.l.l.1 3 e #.G { & u.r.C #.p.H G c .+t % J y+u.T.y.G.g.F.] { r & H ~ o G , ,+& [ [ T K % G ; - & g #.#.s g.s #.s ,+y 2.{ H r b & r #.& o s r o & n z.] z.{ 9 /.,.(.", "S 1.M.,.|./.a a a u.n g.@++.c.8+V {+6.l.< G { / G +.p q #.{ r s u m % % x g.Y.l+X.#.#.u n g [ k+o ~ g & { & [ [ S a k+x p.G & 4 #.r.3 #.& & @+s r s & r 5 | Q p 9 #.s s o n G H H.F.z.n E ,.Z Z ", "4 ` ` |.A ~ z J P #.s r t e q+s+c.~+5.q l.g.g.K.{ % t % s b 4 s r , 0 n H : : w./+r.7.+.; #.[ . s [ I [ & G p 4 S 4 k+n G u g.% 3 t+T Q u.#.#.t C p g % | 4.7.T >.C s r n N n z.F.z.z.G 7 ..Z >.", "J a J.D |.J.~ E 4 C #.o z +.d+r+!+;+%.%.p.g.g.Q.K.X.r G s +.Q %.a o b > : T.T.: ~ Q u+=.P @+~ f.s [ i <.& & @+r | !.[ s G u & @+2 s.:.B #.p #+t 3 !.C a S h B :.$.P G n ] z.N F.Z.x.^ { [ } ..a ", "D R D D O a 6 h (.h i ' a 4 5.z+6.%.A..+G.z.g.u z.K.G #.%.r.r.T 6 ~ n Z.N.F.> { . [ >.X T J . f.H g 8 #.y+H g.H 3 i 9 % ; p.b [ 6.s.=.T #.#.#+l.=.X 3 4 [ +.Q 3 $.C g.{ ^ ^ H.F.x.F.: 2.8 v.R [ ", "E a D 8 8 6 5 I 5+5+!+B [ ~ C 5+#+* L u.#.s p #.0 [ #.3 +.1 1 =.p u.r Z./ n G H % 5 B 2 T L 0 ! $ l W m { n s o p.b g G ~ #.P +.l.w+w+f .+G r L 1+s.f K [ 6 9 o a P g & m m g.z.u m { , 0 O D ..", "R |.O E 8 ' [ [ ++!+1 Q ..a [ {+G -+r.#+4 #+p g 8 5 C e 1 2 2 =.q r #.Q.{ r #.z.% p q L +.#.~ . j 2.m 2.{ { n l b p.n H g 5 +.#.b T j.+.% 0 0 @ 2 T S 5 [ 6 I 4 a 6 0 x & r n g.m u m G @ [ a |.", "D D O O D 0 z ~ Q S K /...D % & _ f+f +.p #.p +.| +.C 2 2 2 5.2 p s g e.{ # c H & % #.b t #.4 ` K % m o g.H g.# p.s s % #.p S S K S J 4 x a [ D r.r.q [ % a i 5 a 6 0 o g [ #.#.o # 0 0 0 z . 6 ", "A ..J D J J z ~ J P J a A ! z g.2+A.e P % @+C r.T l.A.7+2 7++.:.p G g / , n & H /+& u ] / Q.@+1.9 ~ ,+g.G z.,+y & p.#.g g 4 9 T 1.P @+/.~ 4 D 9 +.r.P [ o ~ I 8 a [ a 0 [ 5 P [ 0 g 0 g z , , [ ", "v.O D 4 (.` /.a [ S 3 J . a #.A.l.C Q 5 k+s A.:.=.3 ^.s._.2 3 r.I ~ 0 m o , o s +.B e t z.Q.u.$.1.[ & <.j.r.G # s g.g.r #.[ P !.2 %.#.B C S P 4 P 9 p [ , & 5 8 [ p [ 0 [ [ a a ~ ' [ @ ~ v x 0 ", "v./.D P Z h K 7 P r.T p s ~ q :.6.#+C 9 z C C :._.1 l.s.2 :.q !.Q ~ [ o k , ~ [ C B e L g.`.v+G @+H / #.t+Q & , s & n o r s [ d !+!+1 < 3 7.j.C [ /.[ g H , [ I S I p [ [ % z z % [ 0 z ~ k k 0 ", "! |.P S X B J ` /.K S C z & q _.:.#+% |.4 Q +.V T 7+1 2 3 S [ 5 9 [ Q ~ H v % [ +.r.3 r.+._ : z.g.n y u I p ~ ' g o o r n , a d 2 s.2 b 3 T ;.C D J [ g H H [ 9 T T f [ g . % [ [ 5 ' o . 0 . . ", "' E !.T u+S 4 h g+/.K J z z S . .C & D a >.S 7+%+2 1 2 +.p [ 5 i (.4.~ v x [ 0 +.C 9.+.3 b H.H.,+N ] / G x x 8 8 l Z./ m o ~ 6 :.T T 9.$.+.K A+/.|.[ g , ,+g 5 2 2 +.g % o 0 8 I | [ k % ) A k ", "O O 8 Z h K p p <.+.r.B Q q :.&.&+S @+#.9 B S {+I f r.T 2 l.l.e ;.q 9 x x k ~ 9 q.B+1 0+S C s / 2.N ^ C+O.; [ v.Y 0 M ,+m n [ ' I I 5 % 4 t r r [ [ 0 0 , n { ; R O @ p.; #.p 9 7.Q #.% a O O z ", "i 9 9 i !.L S r.< 3 >.:.Q +.:. .}+3 4 4 6 Q Q +.$ Q L 3 1 :.r.e | p 5 ~ 0 s [ 5 5.s.c.^.0+r.p n H m u H.z.j @ J.+ [ t r r n o k [ i S 4 #.s r # j 0 o 0 , o n n . ' <.p p r.!.Q Q P [ 4 % [ !.9 ", "2 B P J 9 S :.c._.2 =.%+P #.4 @.T >.P 4 J 5 P %.[ % C 3 2 B l.T 9 [ [ . 6 z [ #._.>+'+c.{+_.Q #.,+# j m N r o , e./ ] u = n n s [ 3.3.P u.g.n N o c o 0 ~ g n { , 0 [ a [ B $.2 d Q Q Q C C B T ", "&.1 P [ 6 3 2 1+c.V %+3 4 @+P >.%+%+B J [ K 9 P a P +.B 2 :.%.%.a [ z . 9 % r.C i.@.>+ +|+2 >.6 r M j ~ x d.z.N > Z.T.z.^ > / n J ;.u+Q u.{ { N G 0 % 0 0 5 0 n m j . a ..!.T u+7.5 4 r.>.1 2 =.", "h+7++.J +.r.c.d+_.!+1 C #.o % S T =.>.S K Q Q J 4 7.X 1 1 2 C H ~ % x z 5 [ T B 0+3 V 1+4+l.B a <.0 z ' . , y r - N Z.= H.z./ z.& S | #.G n z.u N j o 0 o O [ [ N , % E ` !.S :.I % @+Q 2 _.n.n.", "n.7+3 3 r.B !+V b.++3 +.j o 0 S =.2 T B >.>.(.K $.T _.&._.A.& ~ b s % & g #.L q d 2 1 a+u+%.I % 6 M ~ w [ o , r n { > n u u N z.,+G s G g.y.z.z.n r r 0 . 8 8 I o d.& |.i J 4 S 6 g p B 1 2 n.a+", "=.=.7+V 6.1 1 r.l.{+S +.5 p r.;.c.7+7+2 T >.>.(. .1 +U _._ ,+6 l.C L s s & g.X.s #.#.C Q p g $ . J.. @ [ . ~ . 0 o o n n z.z.> > , n z.n z.> z.n r r [ 0 O 6 E + o , G & n % I [ [ !.T :.7+}+}+", "$.=._. +V 6.3 9 !+1 %+%+r.C S %+_.7+7+[.=.B (.T 1 n.h+5+|+p.o @ ++l.s.t #.& X.Q.N g.x y+k+0 ,+W A ' @ 0 0 + D ) O [ [ x 0 u ; u y N N u - z.F._ u r o [ ' ' . . E [ r N { y 0 R % 4 p r.B =. .7+", "2 s.7+1 &+1 .:._.1+1+2 1 %+7+1.5+2 X $.[.n._.3 >.Q i [ M g #.p 2 e :.l.f #.[ a g p #.% 0 % z . $ m 8 x |.v.' w *.$ # @ j l p f + , k s d f z.n u ; o # $ o l 2.m $ <.j x o [ L @ j % [ h $.P 1.", "1 2 2 %+ .S T :._._._.2 7+2 %+@.6.T %+X [.n. .T B K 8 6 [ 0 #.p 2 2 !+e T #+Q 9 t p g % [ ' a 5 r.<.I . /.a 6 w p #.~ M z ~ [ 9 $ r g.g f t n z., u m , c , # 2.2.l j s s [ <.[ $ j s % | >.K >.", "S T T T $.%.3 T c.c.2 _.}+=.1 +.+.S B }+n.h+s.1.!.Q 6 |.' o #.p 2 1 :.2 2 #.3 | r.p #.a 9 [ [ I &.2 <.' a A J [ d Q J z z z A+a g s { #.C _ b G.m & r { $ y g 0 j o o g <.[ s o $ & r & 4 L p S ", "p Q S >.>.C P | 2 2 V 2 2 2 3 C P 4 S 2 h+1+7+Z 3 ` |.D J.~ [ p 1 3 :.5+2 2++.T :.p @+[ 9 J [ f 8.>+t + . a 9 P 0.` F |.a D a D I #.& A.G _ *.n n s s n 0 , g @ t s s #.p g r o s & s o & g [ g ", "a [ J K S S 4 r.%+1 3 3 3 S %.C 9 a J %+&.2 S /.+.>.E D } z K S B 3 :._._.A.1 2 3 #.& a 9 9 C r.b+>+#.5 0 J Q B 0 a 8 a z . . a 4.P L #+f+b G g.x g x % & & , m 0 o s [ p #.t <.#.G $ s m % g p ", "5 P 4 P Q T +.Q S P P 4 4 #.p 9 B K D i T S J A+#.0+E D A ..4 q S S 3 2 s.%.7+2 1 +.@+a /.[ #.l.8.1+#.8 6 !.>.2 6 i D+| I F + 8 E #.L #.p.t n & & P & 5 o s H n o s % C p q q f @+#.g r r s b p ", "8 9 P J S M.+.S P [ % 4 [ 4 J Q j.Q ..'.|.D a j+l.u.9 D D E s +.J C p 3 2 3 2 %+2 >.K a a #.4 l.>+1 P O ,.Z r.w+S Q -.r.p L & . z a [ G G ; o j a i a Q 5 p o G M j $ p S r.3 %.t #.s m s b & S ", "9 i 4 4 0+u+%.%.' % . [ 6 |.9 Q w+(.7 L.=+A A ) >+p.J D |.` G T 4 % 4 +.2 1 [.1 3 :.!.a % 4 l.s.&.q 9 /.,.$.r.++T =.E+2 @.T #.% } F % G & { s @ P ` K I d p [ % l M g q | 2 r.A.+.t G n t #.u.B ", "t r.J @+P B 9 ' a [ J |.J p B ;.T Q [ D v.. . + ; l w . 4 T #+e t #+6.!+!+:.f P K S r.S 0 % S &+s.f P Q ` Q 5 Q <.+ | <.0 5 7.l.P I 8 ' . @ 0 % a Q i i ` [ % I 6 & P #.| >+3 S !+p q c b - C C ", "t r.P A+q p % A % [ [ 9 6 P S =.T Q a D A M k m m 2.@ f.P T #+q 4 [ r.T 3 S P [ K S S #.% 4 B }+e L +.Q ` 9 P 6 # l j k o g t+| P !.8 D ' 6 J [ [ 8 9 5 5 5 6 I i 0 g r q u+r.@.6.p p 0 b & #.a ", "#+q J 4 P #+% a [ J O 8 9 !.>.2 ` 9 /...! k ].].y / M M 5 T #.[ z |.K =.C K A+z P S +.4 [ !.>.7+3 3 | ` ` 8 6 a j o l l 0 s p C 9 ` 7 ,.|.8 9 |.K 9 5 a @+6 i 9 i @ j o t j.:.e ++S 9 P p g [ A ", "q C J P p % % |.' [ 6 9 !.| >.T ,.9 |.|.' . k 2.N 2.k k P T 4 g z J p ;.C B 4 A+[ 5 +.P 8 ` >.V T T h (.8 |.D z y 2.o k $ o g I ,.` 7 ,.9 g+9 |.|.[ [ a z [ i 9 I [ [ 0 L T r.:.1 +.S Q +.q P A+", ":.+.J P #.g.% a a a [ P 9 Q !.S |./.|.|.D z M ~ r o h.k [ Q C [ s p #+s.3 s.3 +.5 #.4 9 O 6 3 7+[.T Q |.6 a A A #.o 2.B., d.~ L ,.,.,.K /.K g+/.8 a 6 9 4 4 Q Q Q 9 d h h T 1 V 5+6.1 2 _._.++3 ", ":.C A+4 s & ~ a a p P P K K 9 |.,.,.,.|.D a ' a [ @ f.k #.C [ [ s #+%.b.c.h+_.:.| C 4 6 J a !.&.X T K 5 6 a [ 9 f p [ ~ k y+o a 9 K K K K 9 9 |.6 a |.i 9 [ 9 | Z $.0.0.Z >.%+s.b.++e &.h+U h+_.", "1 #.k+#.s r #.z Q Q B r.K 9 O ..8 !.E 9 O |.Y Y a O . . b b b g #.#+l._.d+&.&.2 | 9 4 J ..D B &.$.B I i 5 g p T Q 4 8 [ 8 [ I [ 9 K 9 Q Q Q 9 [ ' [ [ 6 9 S Q h h !.(.` h >.=.s.++l.+.s.c.U 8+c.", "_.4 @+[ s b a x S T :.S P 6 D v.J K |.|.|...g+'.A O v.. #._ G r a C B }+[.}+ .7+I +.p D D |.3 V B S I d 5 G 4 2 7.C 5 a a ' i % 8 9 Q :.| I p ' . 6 A ~ P I Q B p 6 [ E F d t+w+t+h K .1+b+*+}+", "r.q S f q r z.- !.i Q L g ' ! ).O A O z [ 4.+ ' #.I z ..a K r.#+| T 2 i.[ i [ L h i 7 J I f | Q ` 5 + 0 @ c b f e $ c m j H r #.Q I f [ Q Q 0+T r.q t % [ 6 |...p t m y r L T ;.t+:.r.p u+&.h+q.", "< A.b p g u _ - #.p 5 6 0 . . ! 6 |.d 6 % 6 . O 5 d 9 9 J Q Q q [ S %+C P E [ f T P 9 9 h p +.S 6 6 5 j j j & g o , j $ I g G v #+#.f 5 [ #.g u+f p n r @ [ a a g 0 r o c [ Q T 7.T K a Q | e 6.", "#+G g._ p.u N u f+#.p 6 A . . @ @ [ g % % a A A [ K Q r.r.;.p @+~ C r.S K 8 9 B u+Q ,.` ;.l.I h 8 6 6 2.v # o s . z 0 o o & p | f G & s s s G [ r # 2.<.l l , 0 & n o j c #.p h $.3.` /.a 4 a C ", "f+g.z.n u u y.z.u r a v.A M o # o o , & a . a } z x G p.< u+4 t.~ p r.S 9 ,.Q T ;.P /.8 7.q +.B 8 ' ' , ,+o z g D 8 E 0 x o 5 T D+u.,+].o 0 l { ,+0 @ I k o n p g & o g j ~ #.5 3 1.h F /.J x ~ ", "n u G G u n z.] y.n o . f.k 2.m o j s 0 a % ....a x x.x.G.f % j+0 Q r.S 9 6 9 h T P /.J Q q Q K ' J.[ [ o ~ . ' ,.,.|.6 a 6 4 z r.[ % 0 o l $ n s 5 0 8 o I Q e d [ #.g o n & ~ 2+Q q h p [ & o ", "& r b c u n N n N , x M ~ k 2.m j M ~ s [ ` 8 |.z % & z.Z.% z /.0 I S S /.z a Q B 9 g+a Q 5 B K D z I I g #.5 F d (.a [ % [ a a #.Q I 5 z o j y & p [ 6 ~ !.B T j.[ 0 g x & ~ , g.p.G #.g c o j ", "~ @ j r m G o o m m # j 2.d.2.@ @ 2.& v % 7.6 ~ x + 0 s v & a a a Q +.P J ~ ' g J J '.A 6 % [ z 9 [ h T #.P F 4.K S 9 d 6 J % D C Q % 0 [ M & { / & 0 0 ~ 0 [ +.9 @+[ g x o $ o r & G g.#.o o c ", ". @ j n , r 0 0 x l # # y K.].. M ~ <.y+H 5 & x 2.0 ].x ].z O ' a B P S O ~ . g 5 ..R ..O % a A z 4 u+7.A.+.` E :.p u.9 P 8 A+a 9 9 v ~ [ s % % N ] B.B.k z g g 4 s J [ & M [ o + 0 0 & 0 & l @ "}; nethack-3.4.3/win/share/0040755000000000000000000000000007764735105013555 5ustar rootrootnethack-3.4.3/win/share/gifread.c0100644000000000000000000003702307764735042015324 0ustar rootroot/* GIF reading routines based on those in pbmplus:ppm/giftoppm.c, bearing * following copyright notice: */ /* +-------------------------------------------------------------------+ */ /* | Copyright 1990, David Koblas. | */ /* | Permission to use, copy, modify, and distribute this software | */ /* | and its documentation for any purpose and without fee is hereby | */ /* | granted, provided that the above copyright notice appear in all | */ /* | copies and that both that copyright notice and this permission | */ /* | notice appear in supporting documentation. This software is | */ /* | provided "as is" without express or implied warranty. | */ /* +-------------------------------------------------------------------+ */ #include "config.h" #include "tile.h" #ifndef MONITOR_HEAP extern long *FDECL(alloc, (unsigned int)); #endif #define PPM_ASSIGN(p,red,grn,blu) do { (p).r = (red); (p).g = (grn); (p).b = (blu); } while ( 0 ) #define MAX_LWZ_BITS 12 #define INTERLACE 0x40 #define LOCALCOLORMAP 0x80 #define BitSet(byte, bit) (((byte) & (bit)) == (bit)) #define ReadOK(file,buffer,len) (fread((genericptr_t)buffer, (int)len, 1, file) != 0) #define LM_to_uint(a,b) (((b)<<8)|(a)) struct gifscreen { int Width; int Height; int Colors; int ColorResolution; int Background; int AspectRatio; int Interlace; } GifScreen; struct { int transparent; int delayTime; int inputFlag; int disposal; } Gif89 = { -1, -1, -1, 0 }; int ZeroDataBlock = FALSE; static FILE *gif_file; static int tiles_across, tiles_down, curr_tiles_across, curr_tiles_down; static pixel **image; static unsigned char input_code_size; static int FDECL(GetDataBlock, (FILE *fd, unsigned char *buf)); static void FDECL(DoExtension, (FILE *fd, int label)); static boolean FDECL(ReadColorMap, (FILE *fd, int number)); static void FDECL(read_header, (FILE *fd)); static int FDECL(GetCode, (FILE *fd, int code_size, int flag)); static int FDECL(LWZReadByte, (FILE *fd, int flag, int input_code_size)); static void FDECL(ReadInterleavedImage, (FILE *fd, int len, int height)); static void FDECL(ReadTileStrip, (FILE *fd, int len)); /* These should be in gif.h, but there isn't one. */ boolean FDECL(fopen_gif_file, (const char *, const char *)); boolean FDECL(read_gif_tile, (pixel(*)[])); int NDECL(fclose_gif_file); static int GetDataBlock(fd, buf) FILE *fd; unsigned char *buf; { unsigned char count; if (!ReadOK(fd,&count,1)) { Fprintf(stderr, "error in getting DataBlock size\n"); return -1; } ZeroDataBlock = (count == 0); if ((count != 0) && (!ReadOK(fd, buf, count))) { Fprintf(stderr, "error in reading DataBlock\n"); return -1; } return count; } static void DoExtension(fd, label) FILE *fd; int label; { static char buf[256]; char *str; switch (label) { case 0x01: /* Plain Text Extension */ str = "Plain Text Extension"; #ifdef notdef if (GetDataBlock(fd, (unsigned char*) buf) == 0) ; lpos = LM_to_uint(buf[0], buf[1]); tpos = LM_to_uint(buf[2], buf[3]); width = LM_to_uint(buf[4], buf[5]); height = LM_to_uint(buf[6], buf[7]); cellw = buf[8]; cellh = buf[9]; foreground = buf[10]; background = buf[11]; while (GetDataBlock(fd, (unsigned char*) buf) != 0) { PPM_ASSIGN(image[ypos][xpos], cmap[CM_RED][v], cmap[CM_GREEN][v], cmap[CM_BLUE][v]); ++index; } return; #else break; #endif case 0xff: /* Application Extension */ str = "Application Extension"; break; case 0xfe: /* Comment Extension */ str = "Comment Extension"; while (GetDataBlock(fd, (unsigned char*) buf) != 0) { Fprintf(stderr, "gif comment: %s\n", buf ); } return; case 0xf9: /* Graphic Control Extension */ str = "Graphic Control Extension"; (void) GetDataBlock(fd, (unsigned char*) buf); Gif89.disposal = (buf[0] >> 2) & 0x7; Gif89.inputFlag = (buf[0] >> 1) & 0x1; Gif89.delayTime = LM_to_uint(buf[1],buf[2]); if ((buf[0] & 0x1) != 0) Gif89.transparent = buf[3]; while (GetDataBlock(fd, (unsigned char*) buf) != 0) ; return; default: str = buf; Sprintf(buf, "UNKNOWN (0x%02x)", label); break; } Fprintf(stderr, "got a '%s' extension\n", str); while (GetDataBlock(fd, (unsigned char*) buf) != 0) ; } static boolean ReadColorMap(fd,number) FILE *fd; int number; { int i; unsigned char rgb[3]; for (i = 0; i < number; ++i) { if (!ReadOK(fd, rgb, sizeof(rgb))) { return(FALSE); } ColorMap[CM_RED][i] = rgb[0] ; ColorMap[CM_GREEN][i] = rgb[1] ; ColorMap[CM_BLUE][i] = rgb[2] ; } colorsinmap = number; return TRUE; } /* * Read gif header, including colormaps. We expect only one image per * file, so if that image has a local colormap, overwrite the global one. */ static void read_header(fd) FILE *fd; { unsigned char buf[16]; unsigned char c; char version[4]; if (!ReadOK(fd,buf,6)) { Fprintf(stderr, "error reading magic number\n"); exit(EXIT_FAILURE); } if (strncmp((genericptr_t)buf,"GIF",3) != 0) { Fprintf(stderr, "not a GIF file\n"); exit(EXIT_FAILURE); } (void) strncpy(version, (char *)buf + 3, 3); version[3] = '\0'; if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) { Fprintf(stderr, "bad version number, not '87a' or '89a'\n"); exit(EXIT_FAILURE); } if (!ReadOK(fd,buf,7)) { Fprintf(stderr, "failed to read screen descriptor\n"); exit(EXIT_FAILURE); } GifScreen.Width = LM_to_uint(buf[0],buf[1]); GifScreen.Height = LM_to_uint(buf[2],buf[3]); GifScreen.Colors = 2<<(buf[4]&0x07); GifScreen.ColorResolution = (((buf[4]&0x70)>>3)+1); GifScreen.Background = buf[5]; GifScreen.AspectRatio = buf[6]; if (BitSet(buf[4], LOCALCOLORMAP)) { /* Global Colormap */ if (!ReadColorMap(fd, GifScreen.Colors)) { Fprintf(stderr, "error reading global colormap\n"); exit(EXIT_FAILURE); } } if (GifScreen.AspectRatio != 0 && GifScreen.AspectRatio != 49) { Fprintf(stderr, "warning - non-square pixels\n"); } for (;;) { if (!ReadOK(fd,&c,1)) { Fprintf(stderr, "EOF / read error on image data\n"); exit(EXIT_FAILURE); } if (c == ';') { /* GIF terminator */ return; } if (c == '!') { /* Extension */ if (!ReadOK(fd,&c,1)) { Fprintf(stderr, "EOF / read error on extension function code\n"); exit(EXIT_FAILURE); } DoExtension(fd, (int)c); continue; } if (c != ',') { /* Not a valid start character */ Fprintf(stderr, "bogus character 0x%02x, ignoring\n", (int) c); continue; } if (!ReadOK(fd,buf,9)) { Fprintf(stderr, "couldn't read left/top/width/height\n"); exit(EXIT_FAILURE); } if (BitSet(buf[8], LOCALCOLORMAP)) { /* replace global color map with local */ GifScreen.Colors = 1<<((buf[8]&0x07)+1); if (!ReadColorMap(fd, GifScreen.Colors)) { Fprintf(stderr, "error reading local colormap\n"); exit(EXIT_FAILURE); } } if (GifScreen.Width != LM_to_uint(buf[4],buf[5])) { Fprintf(stderr, "warning: widths don't match\n"); GifScreen.Width = LM_to_uint(buf[4],buf[5]); } if (GifScreen.Height != LM_to_uint(buf[6],buf[7])) { Fprintf(stderr, "warning: heights don't match\n"); GifScreen.Height = LM_to_uint(buf[6],buf[7]); } GifScreen.Interlace = BitSet(buf[8], INTERLACE); return; } } static int GetCode(fd, code_size, flag) FILE *fd; int code_size; int flag; { static unsigned char buf[280]; static int curbit, lastbit, done, last_byte; int i, j, ret; unsigned char count; if (flag) { curbit = 0; lastbit = 0; done = FALSE; return 0; } if ((curbit+code_size) >= lastbit) { if (done) { if (curbit >= lastbit) Fprintf(stderr, "ran off the end of my bits\n"); return -1; } buf[0] = buf[last_byte-2]; buf[1] = buf[last_byte-1]; if ((count = GetDataBlock(fd, &buf[2])) == 0) done = TRUE; last_byte = 2 + count; curbit = (curbit - lastbit) + 16; lastbit = (2+count)*8 ; } ret = 0; for (i = curbit, j = 0; j < code_size; ++i, ++j) ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j; curbit += code_size; return ret; } static int LWZReadByte(fd, flag, input_code_size) FILE *fd; int flag; int input_code_size; { static int fresh = FALSE; int code, incode; static int code_size, set_code_size; static int max_code, max_code_size; static int firstcode, oldcode; static int clear_code, end_code; static int table[2][(1<< MAX_LWZ_BITS)]; static int stack[(1<<(MAX_LWZ_BITS))*2], *sp; register int i; if (flag) { set_code_size = input_code_size; code_size = set_code_size+1; clear_code = 1 << set_code_size ; end_code = clear_code + 1; max_code_size = 2*clear_code; max_code = clear_code+2; (void) GetCode(fd, 0, TRUE); fresh = TRUE; for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for (; i < (1< stack) return *--sp; while ((code = GetCode(fd, code_size, FALSE)) >= 0) { if (code == clear_code) { for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for (; i < (1< 0) ; if (count != 0) Fprintf(stderr, "missing EOD in data stream (common occurrence)\n"); return -2; } incode = code; if (code >= max_code) { *sp++ = firstcode; code = oldcode; } while (code >= clear_code) { *sp++ = table[1][code]; if (code == table[0][code]) { Fprintf(stderr, "circular table entry BIG ERROR\n"); exit(EXIT_FAILURE); } code = table[0][code]; } *sp++ = firstcode = table[1][code]; if ((code = max_code) <(1<= max_code_size) && (max_code_size < (1< stack) return *--sp; } return code; } static void ReadInterleavedImage(fd, len, height) FILE *fd; int len, height; { int v; int xpos = 0, ypos = 0, pass = 0; while ((v = LWZReadByte(fd,FALSE,(int)input_code_size)) >= 0 ) { PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v], ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]); ++xpos; if (xpos == len) { xpos = 0; switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos >= height) { ++pass; switch (pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; default: goto fini; } } } if (ypos >= height) break; } fini: if (LWZReadByte(fd,FALSE,(int)input_code_size)>=0) Fprintf(stderr, "too much input data, ignoring extra...\n"); } static void ReadTileStrip(fd,len) FILE *fd; int len; { int v; int xpos = 0, ypos = 0; while ((v = LWZReadByte(fd,FALSE,(int)input_code_size)) >= 0 ) { PPM_ASSIGN(image[ypos][xpos], ColorMap[CM_RED][v], ColorMap[CM_GREEN][v], ColorMap[CM_BLUE][v]); ++xpos; if (xpos == len) { xpos = 0; ++ypos; } if (ypos >= TILE_Y) break; } } boolean fopen_gif_file(filename, type) const char *filename; const char *type; { int i; if (strcmp(type, RDBMODE)) { Fprintf(stderr, "using reading routine for non-reading?\n"); return FALSE; } gif_file = fopen(filename, type); if (gif_file == (FILE *)0) { Fprintf(stderr, "cannot open gif file %s\n", filename); return FALSE; } read_header(gif_file); if (GifScreen.Width % TILE_X) { Fprintf(stderr, "error: width %d not divisible by %d\n", GifScreen.Width, TILE_X); exit(EXIT_FAILURE); } tiles_across = GifScreen.Width / TILE_X; curr_tiles_across = 0; if (GifScreen.Height % TILE_Y) { Fprintf(stderr, "error: height %d not divisible by %d\n", GifScreen.Height, TILE_Y); /* exit(EXIT_FAILURE) */; } tiles_down = GifScreen.Height / TILE_Y; curr_tiles_down = 0; if (GifScreen.Interlace) { /* sigh -- hope this doesn't happen on micros */ image = (pixel **)alloc(GifScreen.Height * sizeof(pixel *)); for (i = 0; i < GifScreen.Height; i++) { image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel)); } } else { image = (pixel **)alloc(TILE_Y * sizeof(pixel *)); for (i = 0; i < TILE_Y; i++) { image[i] = (pixel *) alloc(GifScreen.Width * sizeof(pixel)); } } /* ** Initialize the Compression routines */ if (!ReadOK(gif_file,&input_code_size,1)) { Fprintf(stderr, "EOF / read error on image data\n"); exit(EXIT_FAILURE); } if (LWZReadByte(gif_file, TRUE, (int)input_code_size) < 0) { Fprintf(stderr, "error reading image\n"); exit(EXIT_FAILURE); } /* read first section */ if (GifScreen.Interlace) { ReadInterleavedImage(gif_file, GifScreen.Width,GifScreen.Height); } else { ReadTileStrip(gif_file,GifScreen.Width); } return TRUE; } /* Read a tile. Returns FALSE when there are no more tiles */ boolean read_gif_tile(pixels) pixel (*pixels)[TILE_X]; { int i, j; if (curr_tiles_down >= tiles_down) return FALSE; if (curr_tiles_across == tiles_across) { curr_tiles_across = 0; curr_tiles_down++; if (curr_tiles_down >= tiles_down) return FALSE; if (!GifScreen.Interlace) ReadTileStrip(gif_file,GifScreen.Width); } if (GifScreen.Interlace) { for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { pixels[j][i] = image[curr_tiles_down*TILE_Y + j] [curr_tiles_across*TILE_X + i]; } } } else { for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { pixels[j][i] = image[j][curr_tiles_across*TILE_X + i]; } } } curr_tiles_across++; /* check for "filler" tile */ for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X && i < 4; i += 2) { if (pixels[j][i].r != ColorMap[CM_RED][0] || pixels[j][i].g != ColorMap[CM_GREEN][0] || pixels[j][i].b != ColorMap[CM_BLUE][0] || pixels[j][i+1].r != ColorMap[CM_RED][1] || pixels[j][i+1].g != ColorMap[CM_GREEN][1] || pixels[j][i+1].b != ColorMap[CM_BLUE][1]) return TRUE; } } return FALSE; } int fclose_gif_file() { int i; if (GifScreen.Interlace) { for (i = 0; i < GifScreen.Height; i++) { free((genericptr_t)image[i]); } free((genericptr_t)image); } else { for (i = 0; i < TILE_Y; i++) { free((genericptr_t)image[i]); } free((genericptr_t)image); } return(fclose(gif_file)); } #ifndef AMIGA static char *std_args[] = { "tilemap", /* dummy argv[0] */ "monsters.gif", "monsters.txt", "objects.gif", "objects.txt", "other.gif", "other.txt" }; int main(argc, argv) int argc; char *argv[]; { pixel pixels[TILE_Y][TILE_X]; if (argc == 1) { argc = SIZE(std_args); argv = std_args; } else if (argc != 3) { Fprintf(stderr, "usage: gif2txt giffile txtfile\n"); exit(EXIT_FAILURE); } while (argc > 1) { if (!fopen_gif_file(argv[1], RDBMODE)) exit(EXIT_FAILURE); init_colormap(); if (!fopen_text_file(argv[2], WRTMODE)) { (void) fclose_gif_file(); exit(EXIT_FAILURE); } while (read_gif_tile(pixels)) (void) write_text_tile(pixels); (void) fclose_gif_file(); (void) fclose_text_file(); argc -= 2; argv += 2; } exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif nethack-3.4.3/win/share/monsters.txt0100644000000000000000000037740007764735042016200 0ustar rootrootA = (0, 0, 0) B = (0, 182, 255) C = (255, 108, 0) D = (255, 0, 0) E = (0, 0, 255) F = (0, 145, 0) G = (108, 255, 0) H = (255, 255, 0) I = (255, 0, 255) J = (145, 71, 0) K = (204, 79, 0) L = (255, 182, 145) M = (71, 108, 108) N = (255, 255, 255) O = (218, 218, 182) P = (108, 145, 182) # tile 0 (giant ant) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMJAJKKAMMM MMMMMJAAAKJJJAMM MMMMMAKJJAJJAAMM MMMKKAJJJAAAMMMM MMBJJAAAAAJJAMMM MMJBJAJAJAAMMMMM MMMMMAJAMJAMMMMM MMMMMMJAMJAMMMMM MMMMMMMMMMMMMMMM } # tile 1 (killer bee) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MPPPMMMMMPPMMMMM PPPPPMMMPBPPMMMM PBPPPMMPBPPPMMMM MPPBPMPPLPLLMMMM MMMPPMPLLALHAHMM MMMAKKKLAHAAHHMM BBJJJJJJJAHHAAMM ABJBBJJJJAHAHHMM MJJABJAJMJMHHMMM MMMMMMMJMJMMMMMM MMMMMMMMMMMMMMMM MMMAAAAAAAAAAAMM MMMMMAAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 2 (soldier ant) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMJAJKKAMMM MMMMMJAAAKJJJAMM MMMMMAKJJAJJAAMM MJJKKAJJJAAAMMMM JBJJJAAAAAJJAMMM JJJBJAJAJAAMMMMM JAAJJAJAMJAMMMMM MMJJAAJAMJAMMMMM MMMMMMMMMMMMMMMM } # tile 3 (fire ant) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMDACCCAMMM MMMMMDAAACDDDAMM MMMMMACDDADDAAMM MMMCCADDDAAAMMMM MMGDDAAAAADDAMMM MMDGDADADAAMMMMM MMMMMADAMDAMMMMM MMMMMMDAMDAMMMMM MMMMMMMMMMMMMMMM } # tile 4 (giant beetle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKKDKKMMMMM MMMMKACLCJJDMMMM MMMKCLCJJDDDKMMM MMMDCCJDADDADMMM MMMADJDDDDDDDMMM MMMBAKDDAADKAAMM MMMABAKDDKMMMMMM MMMMMMAAMAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 5 (queen bee) { MMMMMMMMMMMMMMMM MPPPMMMMMPPMMMMM PPPPPMMMPPPPMMMM PPPPPMMPPBPPMMMM PBPPPMMPBPPPMMMM MPPBPMPPLPLLMMMM MMMPPMPLLALHAHMM MMMAKKKLAHAAHHMM BBJJJJJJJAHHAAHM ABJBBJJJJAHAHHHM MJJABJAJMJHHHAAM MMMJMMMJMJAAAHHM MMJJMMJJMJMHHAHM MMJAAAJAAJMMHHMM MMMMMAAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 6 (acid blob) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMKDDAMMMMMMM MMMDDKDDKAMMMMMM MDDDIIIDJDAMMMMM DMIIOOIIDAIAMMMM MDKNNNODIDAMMIAM IDJNANOJDDJAMMMM ADIDNOIDIDDDAMMM MMMJDIKIADKIAMMM MIAMIDIDMJDAMMMM MMMIMDDAMMMMDAMM MMMMMMMMMIAMMMMM MMIAMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 7 (quivering blob) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPPMMMMMMM MMMMMMMMMPMMMMMM MPMOOOPPEMMAAAMM PMOPBBBPOEAEAAMM PMPBNNNPMOEAAEAM PMPNNNNNPOEEAEAM POPNAANNEOMOAEAM MOPNAANNEMMOAAAM MOPBNNNEPPMOEAAM BPOPEEEBBPOMEEAM BBBPBBBBBBPPPPAM MMBBBBBBBBBBPAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 8 (gelatinous cube) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMLLLMMMMMM MMMMMLLLLLLLLMMM MMMLLLLLLLLLDMMM MMMCLLLLLLLDDAMM MMMCGGCLLLDDDAAM MMMCAGCGGDDDDAAA MMMCCCCAGDDDAAAA MMMMMCCCCDDAAAAM MMMMMMMCCDAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 9 (chickatrice) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMOOMMMMMMM MMMMMMHAOOMMMMMM MMMMMHHOOHMHHAMM MMMMMMMMOOHOAMMM MMMMMMMMOOFAMMMM MMMMMMMMFGGFAMMM MMMMMMMMAGFGAAMM MMMMMMMMMMMGAMMM MMMMMMMFMMFFAMMM MMMMMMMAFFAAMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 10 (cockatrice) { MMMMMMMMMMMMMMMM MMMDMDDMMMMMMMMM MMMMDDMMMMMMMMMM MMMMNLMMAAMMMMMM MMHHANMAAAMMMMMM MHHMNOMMAAAAMMMM MMMAOOLFFFAAMMMM MMMOOLKGGFFAAMMM MMMAOAGGFGFFAAMM MMMMMMMGFFGFAAMM MMMMMMMMMFGGAAMM MMMMMFAMMMFFAMMM MMMMFAMMMMFFAMMM MMMMFAMMFFFAMMMM MMMMMFFFFAMMMMMM MMMMMMMMMMMMMMMM } # tile 11 (pyrolisk) { MMMMMMMMMMMMMMMM MMMDMDDMMMMMMMMM MMMMDDMMMMMMMMMM MMMMNBMMAAMMMMMM MMHHANMAAAMMMMMM MHHMNBMMAAAAMMMM MMMAPBBJJJAAMMMM MMMPPPKDDKJAAMMM MMMAPADDKDKJAAMM MMMMMMMDJKDJAAMM MMMMMMMMMJDDAAMM MMMMMJAMMMJJAMMM MMMMJAMMMMJJAMMM MMMMKAMMKKKAMMMM MMMMMJKKKAMMMMMM MMMMMMMMMMMMMMMM } # tile 12 (jackal) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOMMOMMMMMMMMM MMMOMOOMMMOMMMMM MMOOOOMMMMMOMMMM MMIOIOOMMMMOMAMM MOLLOOOLMMMOMAMM DOOOAOOOOOOOAAMM MMAAOOOOOOOOAAMM MMMMOJOOOOOLAAMM MMMMOJOLKALKAAMM MMMOOAOAAAOAAMMM MMMMMOOMMOOAMMMM MMMMMMMMMMMMMMMM } # tile 13 (fox) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCMMMMMMMMMMM MMMMCMMMMMMMMMMM MMCCACMMMCCCMMMM MMACCCCCCACCCMMM MMMAACCCCMACCMMM MMMMACAACMMAAMMM MMMACMACAMMMMMMM MMMMMMMMMMMMMMMM } # tile 14 (coyote) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMKMMKMMMMMMMMM MMMKMKKMMMMMMKKK MMKKKKMMMMMMKKKA MMNCNKMKKKKKAAAM MKCCKKKKKKKKKMMM KKCKAKKKKKKKKMMM DKKKAKAKKKKAKMMM MMAAKAAKAAAAKMMM MMMMAKAKAAAAKMMM MMMAKKAKAMAKKMMM MMMMMAKKMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 15 (werejackal) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOMMOMMMMMMMMM MMMOMOOMMMOMMMMM MMOOOOMMMMMOMMMM MMIOIOOMMMMOMAMM MOLLOOOLMMMOMAMM DOOOALLOOOOOAAMM MMAALLLLOOOOAAMM MMMMLJLLLOOLAAMM MMMMLJLLKALKAAMM MMLLLALAAAOAAMMM MMMLMLLMMOOAMMMM MMMMMMLMMMMMMMMM } # tile 16 (little dog) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMJMMJMMMMMMMMM MMMJMJJMMMKMMMMM MMJJJJMMMMMKMMMM MMNJNKKMMMMKMAMM MJJJCKKMMMMKMAMM MPJJAKCKKCKKAAMM MDDAACKKCKKKAAMM MMMMKJKJCJKJAAMM MMMMKJKJJAJJAAMM MMMKKAKAAAKAAMMM MMMMMKKMMMKAMMMM MMMMMMMMMMMMMMMM } # tile 17 (dog) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMJMMJMMMMMKMMM MMMJMJJMMMMMMKMM MMJJJJMMMMMMMKMM MMNJNKKMMMMMMKMA MJJJCKKKKMMMMKMA MPJCAKCKKKKCKKAA MDDAACKKKKCKKKAA MMAAKJKKJJCJKJAA MMMMKJKKJJJAJJAA MMMMKAKJAAAAKJAM MMMKKAKAAAAAKAAM MMMMMKKAAMMMKAMM MMMMMMMMMMMMMMMM } # tile 18 (large dog) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMJMMJMMMMMKMMM MMMJMJJMMMMMMKMM MMJJJJMMMMMMMKMM MMNJNKKKMMMMMKMA MJJJCKKKKKMMJKMA MPJCAKCKKKKCKKAA MDDAACKKKKCKKKAA MMAAKJKKJJCJKJAA MMMJKJKKJJJAJJAA MMMMKAKJAAAAKJAM MMMMKAKJAAAAKJAM MMMKKAKAAAAAKAAM MMMMMKKAAMMMKAMM MMMMMMMMMMMMMMMM } # tile 19 (dingo) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMCMM MMMCMMCMMMMMMMCM MMMCMCCMMMMMMMCA MMCCCCKMMMMMMMCA MMACACCKCCCCCCAA MMLLCCCKCCCLCCCA MKCCACKCLLLLACCA MMAACAACLLAAACCA MMMMACACAAAAAACA MMMMCCACAAAMMCCA MMMMMACCAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 20 (wolf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMPMMPMMMMMPMMM MMMPMPPMMMMMMPMM MMPPPPMMMMMMMPMM MMNMNPPMMMMMMPMA MPMMPPPPPMMMMPMA PPMPAPPPPPPPPPAA DPPPAPPPPPPPPPAA MMAAPMPPMMPMPMAA MMMMPMPPMMMAMPAA MMMMPAPMAAAAPMAM MMMPPAPAAAAAPAAM MMMMMPPAAMMPPAMM MMMMMMMMMMMMMMMM } # tile 21 (werewolf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMPMMPMMMMMPMMM MMMPMPPMMMMMMPMM MMPPPPMMMMMMMPMM MMNMNPPMMMMMMPMA MPMMPPPPPMMMMPMA PPMPAPPPPPPPPPAA DPPPALPPPPPPPPAA MMAALLPLMMPMPMAA MMMMLMLLMMMAMPAA MMMMLALMAAAAPMAM MMLLLALAAAAAPPAM MMMLMLLAAMMPPMMM MMMMMLLMMMMMMMMM } # tile 22 (warg) { MMMMMMMMMMMMMMMM MMMPMMPMMMMPPMMM MMMPMPPMMMMMMPMM MMPPPPMMMMMMMPMA MMNMNPPMMMMMMPMA MPMMPPPPPMMMMPMA PPPPDPPPPPPPPPAA DPPNDPPPPPPPPPAA MMDDDPPPPPPPPPAA PNDNPMPPPPPPPPAA MPPPPAPPPPAPPMAM MMMPAAPPAAAAPPAA MMMPAAPMAAAAPMAM MPPPAAPAAAAAPAAM MMMMPPPAAMPPPAMM MMMMMMMMMMMMMMMM } # tile 23 (winter wolf cub) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMNMMMMMMMMM MMMNMNBMMMNMMMMM MMNNNNMMMMMNMMMM MMDNDNBMMMMNMAMM MMNNNNBMMMMNMAMM MNNNNNNNNNNNAAMM MDNBBNNNNNNBAAMM MMMMNNNNNNNBAAMM MMMMNNNBBANBAAMM MMMNBANAAANAAMMM MMMMMNBMMNBAMMMM MMMMMMMMMMMMMMMM } # tile 24 (winter wolf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMNMMMMMNMMM MMMNMNNMMMMMMNMM MMNNNNMMMMMMMNMM MMDODNNMMMMMMNMA MNOONNNNNMMMMNMA NNONANNNNNNNNNAA DNNBANNNNNNNNNAA MMAANNNNNNNBNNAA MMMMNBNNNBBANNAA MMMMNANBAAAANBAM MMMNNANAAAAANAAM MMMMMNNAAMMNNAMM MMMMMMMMMMMMMMMM } # tile 25 (hell hound pup) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMCMMCMMMMMMMMM MMMCMCCMMMCMMMMM MMCCCCMMMMMCMMMM MMDCDCCMMMMCMAMM MCCCCCCMMMMCMAMM MPCCACCCCCCCAAMM MCHAACCCCCCCAAMM CHCMCCCCCCCCAAMM MDMMCCCCCACCAAMM MMMCCACAAACAAMMM MMMMMCCMMMCAMMMM MMMMMMMMMMMMMMMM } # tile 26 (hell hound) { MMMMMMMMMMMMMMMM MMMCMMCMMMMCCMMM MMMCMCCMMMMMMCMM MMCCCCMMMMMMMCMA MMDJDCCMMMMMMCMA MCCCCCCCCMMMMCMA CCCCDCCCCCCCCCAA MCHCMCCCCCCCCCAA CHCMMCCCCCCCCCAA MDMMCCCCCCCCCCAA MMMCCACCCCACCMAM MMMCAACCAAAACCAA MMMCAACMAAAACMAM MCCCAACAAAAACAAM MMMMCCCAAMCCCAMM MMMMMMMMMMMMMMMM } # tile 27 (Cerberus) { MMMMMMMMMMMMMMMM MMJMMJMMMMMMMMMM MMJJJJMJMMJMMMMM MNJNJMMJMJJMMMMM JJJJKAJJJJMMMMJM PJJJJANJNKKMMMJM DJKJAJJJKJJKMMJM MMAAJPJKAJKJKJJM MMJJJDDAJKJJJJJA MMJJJAAJJJJJJJJA MJKKKJJJKJJKJJAA MJJAAKJJKJJJKJAA JJAAAAJJAAAAJJAM JAAAAAJAAAAAJAAM MMMMMJJAAMMMJAMM MMMMMMMMMMMMMMMM } # tile 28 (gas spore) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPFGGFPMMMMM MMMMPGFFFFFPMMMM MMMPFFFFFGGFPMMM MMMFFGGFFGGFFMMM MMMGFGGFFFFFGMMM MMMGFFFFFFFFGMMM MMMFFFFGGFFFFMMM MMMPGGFGGFGGPMMM MMMMPGFFFFGPMMMM MMMMMPFGGFPMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 29 (floating eye) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMONNNOMMMMM MMMMPNNNNNNNPMMM MMMMNNNNNNNNNMMM MMMONNBBBBNNNOMM MMMNNBBEEBBNNNMM MMMNNBEAAEBNNNMM MMMONBEAAEBNNOMM MMMMNBBEEBBNNMMM MMMMPNBBBBNNPAAM MMMMMMONNNOAAAAM MMMMMMAAAAAAAAAM MMMMMMMAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 30 (freezing sphere) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMPBBBPMMMMM MMMMPBBBBBBBPMMM MMMMBBBBBBBBBMMM MMMPBPPPBBBBBPMM MMMBBNNBBPPPBBMM MMMBBANPBNNBBBMM MMMPBBPPBANPBPMM MMMMBBBBBBPPBMMM MMMMPBBBBBBBPAAM MMMMMMPBBBPAAAAM MMMMMMAAAAAAAAAM MMMMMMMAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 31 (flaming sphere) { MMMMMMMMMMMMMMMM MMMMCMMMHMMMMMMM MMMMCMMMMOMMMCMM MMMCMMHMCCMMMCMM MMMCMMCMCCMMCCMM MMMDCAMDDCMACCMM MAHCDCADDCAADCMM MAACDCDDDDDADDMM MMACDDDJJJDDDDMM MMADDCAKDDACDDMM MMMADAKDDCDADMMM MMMADADHCHCADMMM MMMMDADDDCDADMMM MMMMMDADDDADMMMM MMMMMMJJJJJMMMMM MMMMMMMMMMMMMMMM } # tile 32 (shocking sphere) { MMMMMMMMMMMMMMMM MMMMMPPPPPPMMMMM MMMPPIAAADAPPMMM MMPAAAIAAADDAPMM MMPHAAAPBOAAAPMM MPAHHAPBBBOAAAPM MPHAAAPBBBBAHHPM MPAAAAPPBBBAAAPM MPAAAIAPPPAAAIPM MPIIIAAAAAAIIAPM MMPIAANAAPAAAIPM MMPIAANAAAPAAPMM MMMPANANAPAPAPMM MMMMPPAIAPAPPMMM MMMMMMPPPPPMMMMM MMMMMMMMMMMMMMMM } # tile 33 (beholder) { MMMMOAMMOAMMMMMM MMOAMDADAMOAMOAM MMMDAMDADADADDMM MMOADDOOOODDADOM MMMDDHOAAOHDDAMM MMMJDHOAAOHDDJMM MMMDDDOOOODDDDMM MMMDDDDDDDDDDDMM MMMJDAOAAAOADJMM MMMMDDAAOAADDMMM MMMMPDDDDDDDPAAM MMMMMMJDDDJAAAAM MMMMMMAAAAAAAAAM MMMMMMMAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 34 (kitten) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMKMMMM MMMMMMMMMMMMCMMM MMMMCMCMMMMMLMAM MMMCCCCJMMMMCMAM MMMNCNCJCCLCLMAM MMMCCCCJCCLCCAAM MMMMIACCLLCCCAAM MMMMMCACCJCCJAMM MMMMMMCCAMMCAMMM MMMMMMMMMMMMMMMM } # tile 35 (housecat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMKMMMM MMMMMMMMMMMMCMMM MMMCMCMMMMMMLMAM MMCCCCJMMMMMCMAM MCNCNCJCLCLCLMAM MCCCCCJCLCLCCAAM MMCICJCCLCLCLAAM MMMAACCLCLCCCAAM MMMCCACCJJCCJAMM MMMMMCCAMMMCAMMM MMMMMMMMMMMMMMMM } # tile 36 (jaguar) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMCMMCMMMMMMCMMM MMCCMCJMMMMMMCMA MCCCCCJMMMMMMCMA MGCGCCJCAACCJCMA MCCCCCJCCCCCCCAA MCDDDJCAACCAJCAA MMCCACCAJCCAACAA MMMMCACCJJJCCJAM MMMMCACAAAAACJAM MMMCKACAAAAACAAM MMMMMCCAAMMMCAMM MMMMMMMMMMMMMMMM } # tile 37 (lynx) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM OMMMMOMMMMMMMMMM ACMCCAMMMMMMMMMM MCCCAMMMMMMMMCAM MGCGCOAKKKKKMLAM MCKCCAJCCCCCKAMM LLDDLLACLLLCCAAM MMCCMAACLLLCCAAM MMMMMMMCAAAACAAM MMMMCACAAAACCAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 38 (panther) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMAAMM MMMMMMMMMMMMMMAM MMMMMMMMMMMMMMAM MAMMMAMMMMMMMMAM MEAMAEMMMMMMMMAM MAAAAAEAAAAAAAMM MAAAAAEAAAAAAAMM MHAHAAMAAAAAAAAM MAAAAMAAAAAEAAAM MAAAMMAAAAAEAAAM MMMMMAAMMMMAAAMM MMAAAAMMAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 39 (large cat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMKMMM MMMMMMMMMMMMMCMM MMMCMCMMMMMMMLMA MMCCCCJMMMMMMCMA MCNCNCJCLCCLCLMA MCCCCCJCLCCLCCAA MMCDCJCCLCCLCLAA MMMAACCLCCLCCCAA MMMMCACCJJJCCJAM MMMCKALAAAAACAAM MMMMMCCAAMMMCAMM MMMMMMMMMMMMMMMM } # tile 40 (tiger) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMCMMCMMMMMMCMMM MCCJCCMMMMMMMCMA MCAACCJMMMMMMAMA MGAGCCJACACAJCMA MCCCCCACACACACAA MODOCACCACACACAA MOCOACCJACACACAA MMMMCACJAJAJCAAM MMMMAACAAAAAAJAM MMMCKACAAAAACAAM MMMMMCCAAMMCCAMM MMMMMMMMMMMMMMMM } # tile 41 (gremlin) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM GGGAMMMMAGGGMMMM MGGGFAAAGGGMMMMM MMFFFFFFFFMMMMMM MMMNDFFDNAMMMMMM MMMGNFFNGAMMMMMM MMMGFFFFGAMMAAMM MMMAGFFFAFAAAAAM MMGFAGFAFFFAAAAM MGFGFAAFFAFAAAAM MGFMGFAGAAFAAAAM MMMMFFAGFAAMAAMM MMMGFAMFGAMMMMMM MMMMMMMMMMMMMMMM } # tile 42 (gargoyle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMPAPPPPAPMMMMM MMPAMMMMMMAPMMMM MMPMDDMMDDAPMMMM MMMMPDMMDPAMMMMM MMMMPMMMMPAMMAAM MMMMAPMMMAMAAAAA MMMPMAPMAMMMAAAA MMPMPMAAMMAMAAAA MMPAMPMAPAAMAAAA MMPAMPMMMMAMAAMM MMMMMPMMMMAAAAMM MMMMMPMAPMAAMMMM MMMMPFAMFPAMMMMM MMMMMMMMMMMMMMMM } # tile 43 (winged gargoyle) { MMMKMMMMMMKMMMMM MMMKJMMMMKJMMMMM MMKJAPPPPAJJMMMM MMKJMMMMMMAJMMMM MMKJDDMMDDAJMMMM MKJAPDMMDPAJJMMM MKJAPMMMMPAAJAAM KJAMAPMMMAMAJJAA JMMPMAPMAMMMAJAA MMPMPMAAMMAMAAAA MMPAMPMAPAAMAAAA MMPAMPMMMMAMAAMM MMMMMPMMMMAAAAMM MMMMMPMAPMAAMMMM MMMMPFAMFPAMMMMM MMMMMMMMMMMMMMMM } # tile 44 (hobbit) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJJAMMMMMMM MMMMMJJJJAMMMMMM MMMMJLFLFJMMMMMM MMMMJLLLLJMMMMMM MMMMJKLLKJJMAAMM MMMCLLLLLLCAAAMM MMCLALLLLALCAMMM MMLLAJJKJALLAMMM MMMLMLKJLALAAMMM MMMMMLLALLAMAMMM MMMMLLLMLLLMMMMM MMMMMMMMMMMMMMMM } # tile 45 (dwarf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMBMMMMMMMMM MMMMMBEEMMMMMMMM MMMMBBEEEMMMMMMM MMMMBLLLEMMMMMMM MMMMMOLOMMMAAAMM MMMBBOOOEEAAAAMM MMMBABOEAEAAAAMM MMMMLBBELAAAAMMM MMMMEBAEEAAMMMMM MMMMBEAEBMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 46 (bugbear) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKMMMMMMMMM MKMMKKKMMMMMMMMM MKKKKKKMMMMMMMMM KADKADKKKMMMMMMM KKKKKKKJKKMMMMMM KAPAPAKJJKJMMMMM KAAAAAKKJKJJMMMM MKKKKKJKAKKJMMMM MMKAJJCAKKKJMAAM MMKKMKKKKKJJAAMM MMMCMMKJAKJAAMMM MMMMMCCAAKJAMMMM MMMMMMMMCCAMMMMM MMMMMMMMMMMMMMMM } # tile 47 (dwarf lord) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMBMMMMMMMMM MMMMMBEEMMMMMMMM MMMMHHHHHMMMMMMM MMMMBLLLEMMMMMMM MMMMBOLOEMMAAAMM MMMBBOOOEEAAAAMM MMMBABOEAEAAAAMM MMMMLBBELAAAAMMM MMMMEBAEEAAMMMMM MMMMBEAEBMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 48 (dwarf king) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMHMCMHMMMMMMM MMMMHCHCHMMMMMMM MMMMHHHHHMMMMMMM MMMMBLLLEMMMAMMM MMMMMOLOMMMAAAAM MMMEBOOOEEAAAAMM MMMBABOEAEAAAAMM MMMMLBBELAAAAMMM MMMMEBAEEAAMMMMM MMMMBEAEBMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 49 (mind flayer) { MMMMMMMMMMMMMMMM MMMMMMMIIIICMMMM MMMMMIIIIIICMMMM MMMMIIIIIIICMMMM MMMIGIIIIGCMMMMM MMMIIGINGICMMMMM MMMMIIIIICMMMMMM MMMMIAIAIFMMMMMM MMMMIAIAIFMMMMMM MMMMIAIAIFIMMMMM MMMMMFIFIFICMAAM MMMMCBIBBFMCAAAM MMMIIIBBFFACAAAM MMMMMMBBFCAAAAMM MMMMMMCFFCAAMMMM MMMMIICMIIAMMMMM } # tile 50 (master mind flayer) { MMMMMMMMMMMMMMMM MMMMMMMIIIICMMMM MMMMMIIIIIICMMMM MMMMIIIIIIICMMMM MMMIGIIIIGCMMMMM MMMIIGINGICMMMMM MEEEIIIIICEEEEMM MMEEIAIAIEEEEMMM MMMEIAIAIEEEMMMM MMMMIAIAIEEEMMMM MMMMEFIFIEEEMAAM MMMMCBIBBEEEAAAM MMMIIIBBEEEEAAAM MMMMEEBEEEEAAAMM MMMEEECEEEAAMMMM MMMMIICMIIAMMMMM } # tile 51 (manes) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPPMMMMMMMMMM MMMPPPPMMMMMMMMM MMPAPAPMMMMMMMMM MMPPPPPMPPPMPMMM MMPMMPPPPMMMMMMM MMPMMPPPPPMMMPMM MMPPPPPMPPPMMMMM MMPMPMPMPPMPMMMM MPMMMPMPPPPMMMMM MPMMMMPPPMPPMMMM MMPMMMMPMPMPMPMM MMMMMMMMPMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 52 (homunculus) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJJJMMMMMMM MMMMMMLLCMMMMMMM MMMMMMLLCMMMMMMM MMMMMBBPPPAAMMMM MMMMLMBPPACAAMMM MMMMMMBAPAAAAMMM MMMMMLLALCAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 53 (imp) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOMDMOMMMMMM MMMMMOCDDOMMMMMM MMMMMMCDDMMMMMMM MMMMMGGFFFAAMMMM MMMMCMGFFADAAMMM MMMMMMGAFAAAAMMM MMMMMCDADDAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 54 (lemure) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPPMMMMMMMMMM MMMPPPPMMMMMMMMM MMPAPAPMMMMPMMMM MMPPPPPMMPPMPMMM MMPMMPPPPPPPPMMM MMPMMPPPPPPPMMMM MMPPPPPPPPPMMMMM MMMMPPPPPPPPMMMM MMPPPPPPPPPPMMMM MMMPPPPPPPPPPMMM MMPMPMMPPPPMPPMM MMMMMMMMPMPPMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 55 (quasit) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOMDMOMMMMMM MMMMMOCDDODMMMMM MMMMMMCDDMDMMMMM MMMMMGGFFFAAMMMM MMMMCMGFFAAADAMM MMMMCMGFFJJDAMMM MMMMMMGAFAAAAMMM MMMMMCDADDAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 56 (tengu) { MMMMMMMMMMMMMMMM MMMMMMMPPMMMMMMM MMMMMMPPPPMMMMMM MMMMMDPPNPMMMMMM MMMMDDDPPPMMMMMM MMMMDDPPPPMMMMMM MMMMDMMPPAMMMMMM MMMMMPIAAIPMAAAM MMMMPPPIIPPPAAAM MMMMPAPPPPAPAAAM MMMMPAHHHHAPAAAM MMMMLAPPPPALAAAM MMMMMMPPPPAAAAMM MMMMMMPPPPAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM } # tile 57 (blue jelly) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMEMMMMMMMM MMMMMMOBEMMMMMMM MMMBEMOBEBOEMMMM MMOBEOBBEOBBEMMM MMOBEOBBEOBBEMMM MMBBBGGBGGBEEEMM MMBBBAGBAGEEEEAM MMBBBBBBEBEEEEAA MMMBBBBBBBEEEAAA MMMMBBBBBEEEAAAM MMMMMMBBBEEAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 58 (spotted jelly) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMEMMMMMMMM MMMMMMOBEMMMMMMM MMMBEMOCEBOEMMMM MMOCEOCCEOBCEMMM MMOCEOBCEOCBDMMM MMBBBHHBHHBEDDMM MMCCBAHBAHEEEEAM MMBBCBBBEBEEDEAA MMMBBBCBBBEEDAAA MMMMBCCCBEEDAAAM MMMMMMCCBEEAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 59 (ochre jelly) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMDMMMMMMMM MMMMMMLCDMMMMMMM MMMCDMLCDCLDMMMM MMLCDLCCDLCCDMMM MMLCDLCCDLCCDMMM MMCCCGGCGGCDDDMM MMCCCAGCAGDDDDAM MMCCCCCCDCDDDDAA MMMCCCCCCCDDDAAA MMMMCCCCCDDDAAAM MMMMMMCCCDDAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 60 (kobold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMNMMMMMMMM MMMNBPBNMMMMMMMM MMMBABABMMMMMMMM MMMMBBPAMMAMMMMM MMMBBABPAMAAMAMM MMBPBBBBPAAAAAMM MMBAPBPAPAAAAAMM MMMMPBPAAAAAAMMM MMMMBABAAAAMMMMM MMMBBABBAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 61 (large kobold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMNMMMMMMMM MMMNBPBNMMMMMMMM MMMBABABMMMMMMMM MMMMBBPAMMAMMMMM MMMBBABPAMAAMMMM MMBPBBBBPAAAMAMM MMBAPBPAPAAAAAMM MMBAPBPAPAAAAAMM MMMMPBPAAAAAAMMM MMMMBABAAAAMMMMM MMMBBABBAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 62 (kobold lord) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMNMMMMMMMM MMMNCCCNMMMMMMMM MMMCABACMMMMMMMM MMMCBBPCMMAMMMMM MMCCBABCCMAAMMMM MMCCBBBCCAAAMAMM MMBCCBCCPAAAAAMM MMBACBCAPAAAAAMM MMMMBBBAAAAAAMMM MMMMBABAAAAMMMMM MMMBBABBAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 63 (kobold shaman) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMNMMMMMMMM MMMNHHHNMMMMMMMM MMMHABAHMMMMMMMM MMMHBBPHMMAMMMMM MMHHBABHHMAAMMMM MHHHBBBHHHAAMAMM MHBHHBHHPHAAAAMM MMBAHBHAPAAAAAMM MMMMBBBAAAAAAMMM MMMMBABAAAAMMMMM MMMBBABBAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 64 (leprechaun) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMGMMMMMMMMM MMMMMMFMMMMKMMMM MMMMMGFFMMKLKMMM MMMMGFFFFMMKMMMM MMMMMKLKAMGLAAMM MMMFGFJFFFAKAMAM MMMGAGFFAAAKMAAM MMMMLKHKKJAKAAMM MMMMGFAGKJAKAMMM MMMGFAAMGFAKMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 65 (small mimic) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMPOPMMMMMMM MMMMMMNNOMMMMMMM MMMMMMNNOMMMMMMM MMMMMMMOAMMMMMMM MMMMMNNNNNMMAAMM MMMMOONNNOOMAAMM MMMMNANOOANAAAMM MMMMMMNAOAAAAMMM MMMMMMNAOAAMAMMM MMMMMNNMOOAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 66 (large mimic) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMLLOAMMMMMM MMMMMMNNOAMMMMMM MMMMMMNNOAMMMMMM MMMMMMONOAMMMMMM MMMMMNNNNOMMAAAM MMMMOONNNOOMAAAM MMMNOANNNAOOAAAM MMMNAONONOANAAAM MMMMMNOMNOAAAAMM MMMMMNOMNOAAMAMM MMMMNNOMNOOAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 67 (giant mimic) { MMMMMMMMMMMMMMMM MMMMMMNNOMMMMMMM MMMMMNNNNOAMMMMM MMMMMNNNNOAMMMMM MMMMMNNNNOAMMMMM MMMMMONNNOAMMMMM MMPONNOOONOOPAAA MPONONNNNOONOPAA MONOANNNNOAONOAA MNNOANNNNOAOOOAA MMMAANNONNAAAAAA MMMMPNOMNNPAAAAA MMMMONOMNNOAAMMA MMMMNNOMNNOAAMMA MMMNNNOMNNOOAMMM MMMMMMMMMMMMMMMM } # tile 68 (wood nymph) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOHMMMMMMMMMMM MMOHHLMMMMMMMMMM MMOHLLMMMMMMMMMM MMHHLAMMMMMMMMMM MOHLLFKKKKLAMMMM MHKFLFKKKKAMMMMM OHKJFKKJJKMAMMMM HKKLJJGKAAAAAAAM MJJAJGDKJAAAAAMM MMJAMKKJJAAAAMMM MMMJMKKKKJAAMMMM MMMMJKKKKKJAMMMM MMMMKJKJKJKJMMMM MMMMMMMMMMMMMMMM } # tile 69 (water nymph) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOHMMMMMMMMMMM MMOHHLMMMMMMMMMM MMOHLLMMMMMMMMMM MMHHLAMMMMMMMMMM MOHLLJBBBBLAMMMM MHBJLJBBBBAMMMMM OHBPJBBPPBMAMMMM HBBLPPNBAAAAAAAM MPPAPNDBMAAAAAMM MMPAMBBPPAAAAMMM MMMPMBBBBPAAMMMM MMMMPBBBBBPAMMMM MMMMBPBPBPBPMMMM MMMMMMMMMMMMMMMM } # tile 70 (mountain nymph) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOHMMMMMMMMMMM MMOHHLMMMMMMMMMM MMOHLLMMMMMMMMMM MMHHLAMMMMMMMMMM MOHLLCOOOOLAMMMM MHOCLCOOOOAMMMMM OHOLCOOLLOMAMMMM HOOKLLIOAAAAAAAM MLLALIBOKAAAAAMM MMLAMOOLLAAAAMMM MMMLMOOOOLAAMMMM MMMMLOOOOOLAMMMM MMMMOLOLOLOLMMMM MMMMMMMMMMMMMMMM } # tile 71 (goblin) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMLKMMMMMMMMMM MMMCJAMMMMMMMMMM MMKJAMMMMMMMMMMM MJJAMIIKMMMAAMMM MIKMIGIGIJAAMMMM JMICKIIIJKMMMMMM MMMIIJJJKMAMMMMM MMMMKICJAAAAAMMM MMMMICKKJAMMMMMM MMMMIKAIJAMMMMMM MMMIKAAMIKMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 72 (hobgoblin) { MMMMMMMMMMMMMMMM MMMMMLKMMMMMMMMM MMMMCKAMMMMMMMMM MMMCJAMMMMMMMMMM MMKJAMMMMMMMMMMM MJJAMIIKMMMAAMMM MIKMIHIHIJAAMMMM JMICKIIIJKMMMMMM MMMIIJJJKMAMMMMM MMMMKICCAAAAAMMM MMMMIIIIJAMMMMMM MMMMICKKJAMMMMMM MMMMIKAIJAMMMMMM MMMIKAAMIKMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 73 (orc) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMMMMMMM MMMMNOPAMMMMMMMM MMMMLPLAMMMMMMMM MMMMMPMAMMMMMMMM MMKCCAKKKAMAAMMM MMBPCKJMPMAAAMMM MMBAGGFAAPNOMMMM MMBAJJPNOAAAMMMM MMMMBNOJAAAAAAMM MMMBJACPAAAAMMMM MMBPPABPPAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 74 (hill orc) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMMMMMMM MMMMNOPAMMMMMMMM MMMMLKLAMMMMMMMM MMMMMKMAMMMMMMMM MMKGGAFFKAMAAMMM MMJKGFFMKMAAAMMM MMJAHHFAAKNOMMMM MMJAGFFNOAAAMMMM MMMMGNNFAAAAAAMM MMMGGAGFAAAAMMMM MMKJJAKJJAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 75 (Mordor orc) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMMMMMMM MMMMNOPAMMMMMMMM MMMMLPLAMMMMMMMM MMMMMPMAMMMMMMMM MMKIIAIIKAMAAMMM MMBPIDDMPMAAAMMM MMBAGGFAAPMOMMMM MMBAIDDNOAAAMMMM MMMMBNOJAAAAAAMM MMMBIAIPAAAAMMMM MMBPPABPPAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 76 (Uruk-hai) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMMMMMMM MMMMNOPAMMMMMMMM MMMMLPLAMMMMMMMM MMMMMPMAMMMMMMMM MMIIIAIIIAMMMMMM MMBPIKIMBAAAAMMM MMBIGMPPPPAAAMMM MNBADMPDDPAAMMMM MMBNNJPDDPAAMMMM MMMMINPPPPAAAAMM MMMBIAKMAAAAMMMM MMBPPABPPAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 77 (orc shaman) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMMMMMMM MMMMNOPAMMMMMMMM MMMMLPLAMMMMMMMM MMMMMPMAMMMMMMMM MMCCCACCCAMMMMMM MMBPCKCMBAAAAMMM MMBCGGFJBAAAAMMM MMBAJJCJBAAAMMMM MMBAJJCJBAAAMMMM MMMMCACJAAAAAAMM MMMBCACPAAAAMMMM MMBPPABPPAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 78 (orc-captain) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMMMMMMM MMMNNOOPAMMMMMMM MMMMLPLAMMMMMMMM MMMIPPPAMMMMMMMM MMDIIPADDAMAAMMM MMBPIADMPMAAAMMM MMBAGGFAAPMOMMMM MMBAGGFAAPMOMMMM MMBAJJPNOAAAMMMM MMMMBNOJAAAAAAMM MMMBDAIPAAAAMMMM MMBPPABPPAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 79 (rock piercer) { MJKKKKKKKKJAAAMM MMJJGKGKJJAAAAMM MMMJKKKJJAAAAMMM MMMJJKKJJAAAAMMM MMMMJKKJAAAAMMMM MMMMJJKJMAAAMMMM MMMMJJKJMAAAMMMM MMMMJJJJMMAMMMMM MMMMMJJMMMAMMMMM MMMMMJJMMMAMMMMM MMMMMJJMMMMMMMMM MMMMMJJMMMMMMMMM MMMMMJMMMMMMMMMM MMMMMJMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 80 (iron piercer) { MBPPPPPPPPMAAAMM MMBBDPDPMMAAAAMM MMMBPPPMMAAAAMMM MMMPBPPMMAAAAMMM MMMMBPPMAAAAMMMM MMMMBBPMAAAAMMMM MMMMPBPMAAAAMMMM MMMMPBPMMMAMMMMM MMMMMBPMMMAMMMMM MMMMMBPMMMAMMMMM MMMMMBPMMMMMMMMM MMMMMBPMMMMMMMMM MMMMMBMMMMMMMMMM MMMMMPMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 81 (glass piercer) { MNBBBBBBBBPAAAMM MMNNDBDBPPAAAAMM MMMNBBBPPAAAAMMM MMMPNBBPPAAAAMMM MMMMNBBPAAAAMMMM MMMMNNBPAAAAMMMM MMMMPNBPAAAAMMMM MMMMPNBPMMAMMMMM MMMMMNBMMMAMMMMM MMMMMNBMMMAMMMMM MMMMMNBMMMMMMMMM MMMMMNBMMMMMMMMM MMMMMNMMMMMMMMMM MMMMMPMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 82 (rothe) { MMMMMMMMMMMMMMMM MMMMMMMMMMMKMMMM MMMMMMMMMMMMKMMM MMMMMMMMMMMMKMMM MMMMMMMJJJKKJMMM MMMMMJKKKKKKKMMM MMAAAKKKKKKKKMMM MAAAAAKKKKKKKAMM AAKKAAKKKKKAKAMM MKEKKAKKKJAAKAMM MKKKJAKKAJAAKMMM MMKJAAAKAAAMMMMM MMAAKAMKAMMMMMMM MMAMMAMKMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 83 (mumak) { MMMMMMMMMMMMMMMM MMMMMMMMMMMPMMMM MPPMMMMMMMMMPMMM PPPMMMPPPPPMPMMM PPPPPPPPPMPPMMMM PPPPBPPBBPMPPMMM PPPBPPPPPPMPPMMM MPDPPDDPPMPPPMMM MMBPPDDPMPPPPAMM MMPPPPPPPPPPPAMM MMPPPPOMMPAPPAMM MOOPPOOAPPAPPAMM OOPPOOAAPPAMMMMM MPPPAPAMPPMMMMMM PPPAMMMMMMMMMMMM MAAMMMMMMMMMMMMM } # tile 84 (leocrotta) { MMMMMMMMMMMMMMMM MMAMMAMMMMMMMMMM MMAOOAMMMMJMMMMM MMAOOAAMMMMJMMMM MAPOAFAMMMMJMMMM MAPOAAAMJJJJMMMM MAOPAAJKKKKKJMMM MAOAAKJJKKJKJAMM MMMJKKKKKJAKKAMM MMMJKJKKJAAKKAMM MMJKJAKKAAPAPAMM MMKKAAKKAAPAPAMM MPAPAAPAPAMMMMMM MPAPAMPAPAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 85 (wumpus) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMBMMM MMMMMMMMMMMMMBMM MMMMMMMBBBBBMBMM MMMMBBBPPBBBBMMM MMMBOOBBBPBBBBMM MMMOOBBBBBPBBBMM MMDABBAABBPBBBAM MBOOBBDABEBBEBAA MBOBBBBBBEBEBBAA MBBBBBBBEBBABBAA MEBBBBBEABBABBAA MMEEEEEAABBAMMMM MMMMMBBAMBBMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 86 (titanothere) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMPPPMPM MMMMMMMPPPPPPPAP MMMMMPPPPPPPPPMA MMPMPMPPPPPPPPMA MMPPPMPPPPPPPPPA MMPPPPMPPPPPPPPA MPPPPPMPPPPPPPMM MPPEPPMPPPPMPPAM PBPPPMPPPMAAPPAM PPPPMAAPPAAMMMMM MPPMPPAPPAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 87 (baluchitherium) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMPPPMPM MMMMMMMPPPPPPPAP MMMMMPPPPPPPPPMA MMPMPMPPPPPPPPMA MMPPPMPPPPPPPPPA MMPPPPMPPPPPPPPA BPPPPPMPPPPPPPMM BMPEPPMPPPPMPPAM PBMPPMPPPMAAPPAM PPPPMAAPPAAMMMMM MPPMPPAPPAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 88 (mastodon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMOMMMOMMMMMMMMM MNMMPOPMPMMMMMMM NMMPNPPPPPMMMMMM OMPNPPPPPPMPPMMM OMPOPEPPPMPPPPPM MOPOPOPMMPPPPPAP MMPPOPPMPPPPPPAA MMPPAAAPPPPAPPAM MMPMMMAPPAAAPPAM MMMMMMMPPAMMMMMM MMMMMMMMMMMMMMMM } # tile 89 (sewer rat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMKMMKMJKKKKMMMM MMKKKKJKKJKKKMMM MMJAKAKJJJKKKJMM MMGKGKJKAKKAKKAM MKKJJJJKAKAAKKAM MPJJAAKKAJAJKAMM MMAAMKKAMMJKAMMM MMMMMMMMMJJAMMMM MMMMMMMMMMMMMMMM } # tile 90 (giant rat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMKMMKMJKKKKKMMM MMKKKKJKKKJKKKMM MMJAKAKJKJJKKKJM MMGAGAKJKJJKKKKM MMAKAKJKKAKKAKKA MKKJJJJKAJKAAKKA MPJJAAKKAJJAJKAM MMAAMKKAAMMJKAMM MMMMMMMMMMJJAMMM MMMMMMMMMMMMMMMM } # tile 91 (rabid rat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMKMMKMJKKKKKMMM MMKKKKJKKKJKKKMM MMJAKAKJKJJKKKJM MMGAGAKJKJJKKKKM MMAKAKJKKAKKAKKA MKKJOOOKAJKAAKKA MPJOOAKKAJJAJKAM MMAOOOKAAMMJKAMM MOOOOOOOOMJJAMMM MMMMMMMMMMMMMMMM } # tile 92 (wererat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMKMMKMJKKKKKMMM MMKKKKJKKKJKKKMM MMLLLLKJKJJKKKJM MMFLFLLJKJJKKKKM MMLLLLJKKAKKAKKA MKKJJJJKAJKAAKKA MPJJAAKKAJJAJKAM MMAAMKKAAMMJKAMM MMMMMMMMMMJJAMMM MMMMMMMMMMMMMMMM } # tile 93 (rock mole) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMAAAAAMMMM MMMAAAAAAAAAAMMM MMAAAAAAAAAAAAMM MMJAJAAAAAAAAAAM MAAAAAAAAAAAAAAM ANMNAAAAAAAAAAAM AMMMAAAAMMMAAAMM ANMNAAMAAMMMAAMM MAAAAMMMMMMMMMMM } # tile 94 (woodchuck) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMKJAMMMMMM MMMMMMNKKNAMMMMM MMMMMMKNOJAMMMMM MMMMMMKNOJAMMMMM MMMMMKKKKKJAMMMM MMMMJJKLLJJJAAMM MMMMMMKLLJAAAAAM MMMMMMKJJJAAAAMM MMMMMJJAAJJAAMMM MMMMMMMMMMMMMMMM } # tile 95 (cave spider) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMPAMMMMMM MMMMMMMPAMMMMMMM MMMMMMPAPBBAMMMM MMMPAMAPBPPPAMMM MMMABBPPAPPAAMPA MMMGPPPPAAAPPPAA MMMPPGPAAPPAAAAM MMDMPAPAPAAPPAMM MMMMDMPAAPAMAPAM MMMMMPAAMAPAMMMM MMMMMMMMMMMMMMMM } # tile 96 (centipede) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMPBPPMMMMMM MMMMBBPAAAMMMMMM MMPPBAAAMMMMMMMM MPAPBBBPPPPMMMMM MMPAAPPBBBAMMMMM MMMMPAAPAPBPPMMM MMMMMMAABBPPMMMM MMMMMMBBMPPAPMMM MMMMPBBPPAPMAMMM MMMGPPPAPMAPMMMM MMMPPGPAAPMMMMMM MMBMPAAMMMMMMMMM MMMBMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 97 (giant spider) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMJAMMMMMM MMMMMMMJAMMMMMMM MMMMMMJAJKKAMMMM MMMJAMAJKJJJAMMM MMMAKKJJAJJAAMJA MMMGJJJJAAAJJJAA MMMJJGJAAJJAAAAM MMDMJAJAJAAJJAMM MMMMDMJAAJAMAJAM MMMMMJAAMAJAMMMM MMMMMMMMMMMMMMMM } # tile 98 (scorpion) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMJKJKJAAMM MMMMMMJAMJKJKKAM MMMMMMMKAMMMJJJA MMMMMMJAMMMMKKJA MMMMMMMMMMMJJJKA MMMMMMMAJKKAJJAM MMMMMAAJKJJJAAMM MMMAKKJJAJJAAMMM MMMGJJJJAAAJJJAM MMMJJGJAAJJAAAJM MMDMJAJAJAAJJAMM MMMMDMJAAJAMJAAM MMMMMMMJAAJAMMMM MMMMMMMMMMMMMMMM } # tile 99 (lurker above) { MAAAAAAAAAAAAAAA MMMAAGFAAGFAAAMM MMMAAAAAAAAAAAMM MMMMAODODODOAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 100 (trapper) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMAODODODOAMMM MMMAAAAAAAAAAAMM MMMAAGFAAGFAAAMM MAAAAAAAAAAAAAAA } # tile 101 (white unicorn) { MMMMMMMMMMMMMMMM MMHPMMMMMMMMMMMM MMPHOMNNMMMMMMMM MMMPHNNBMMMMMMMM MMMONENBMMMMMMMM MMONNNNBMMMMMMMM MMNOANNBAAMMMMMM MMMAONNBAMMMMMMM MMMONNNONNNMMMMM MMNONNNNONNOAAAM MMNMONONNONAOAMM MMOAANAAAAOAAMMM MMMLAOAAOAOAMMMM MMMMMOAALAOMMMMM MMMMMLAMMMLMMMMM MMMMMMMMMMMMMMMM } # tile 102 (gray unicorn) { MMMMMMMMMMMMMMMM MMHPMMMMMMMMMMMM MMPHOMPPMMMMMMMM MMMPHPPNMMMMMMMM MMMMPGPNMMMMMMMM MMMPPPPNMMMMMMMM MMPPAPPNAAMMMMMM MMMAPPPNAMMMMMMM MMMMPPPMPPPMMMMM MMPMPPPPMPPMAAAM MMPMMPMPPMPAMAMM MMPAAPAAAAMAAMMM MMMLAMAAMAMAMMMM MMMMMMAALAMMMMMM MMMMMLAMMMLMMMMM MMMMMMMMMMMMMMMM } # tile 103 (black unicorn) { MMMMMMMMMMMMMMMM MMHPMMMMMMMMMMMM MMPHOMAAMMMMMMMM MMMPHAAJMMMMMMMM MMMAADAJMMMMMMMM MMAAAAAJMMMMMMMM MMAAPAAJPPMMMMMM MMMPAAAJPMMMMMMM MMMAAAAAAAAMMMMM MMAAAAAAAAAAPPPM MMAMAAAAAAAPAPMM MMAPPAPPAPAPPMMM MMMLPAPPAPAPMMMM MMMMMAPPLPAMMMMM MMMMMLPMMMLMMMMM MMMMMMMMMMMMMMMM } # tile 104 (pony) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMJJMMMMMMMMM MMMMKKKJMMMMMMMM MMMKKEKJMMMMMMMM MMKKJKKJMMMMMMMM MMJJAKKJAAMMMMMM MMMAKKKJAMMMMMMM MMMKKKKKKKJMMMMM MMMKKKKKKKJJAAAM MMMKJKJJJJJAJAMM MMMJAJAAAAJAAMMM MMMJAJAAJAJAMMMM MMMLMJAALAJMMMMM MMMMMLAMMMLMMMMM MMMMMMMMMMMMMMMM } # tile 105 (horse) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMJJMMMMMMMMM MMMMKKKJMMMMMMMM MMKKKEKJMMMMMMMM MKKKJKKJAAMMMMMM MJJJAKKJAAMMMMMM MMMAKKKJAMMMMMMM MMMKKKKKKKKJAMMM MMKKKKKKKKKKJAMM MMKJJKJJJJJKAJAM MMJAAJAAAAAJAJAM MMJAAJAAAJAJAAMM MMLAMJAAMLMJAMMM MMMMMLAMMMMLMMMM MMMMMMMMMMMMMMMM } # tile 106 (warhorse) { MMMMMMMMMMMMMMMM MMMMMJJJMMMMMMMM MMMKKKKJJMMMMMMM MKKKKEKJJMMMMMMM KKKKKKKJJAAMMMMM JKKKJKKJJAAMMMMM MJJJAKKJJAAMMMMM MMMAKKKJJAMMMMMM MMMKKKKKKKKKJAMM MMKKKKKKKKKKKJAM MMKKJKKJKKJKKJJA MMKJAKJAKJAKJAJA MMKJAKJAKJAKJAMM MMLCMKJALCMKJMMM MMMMMLCMMMMLCMMM MMMMMMMMMMMMMMMM } # tile 107 (fog cloud) { MMMMMMMPMMMMMMMM MMMMPMMPMMMMMMMM MMMMMPMPMMMPMMMM MMMPMMMMMMMPMMMM MMPMMPMPMPMMMMMM MMMMPPMPPMPMPMMM MPMMAPAPPPMMPMMM MMMPMPPPPMPPMMMM MMMMMMPPPPPMPMPM MMMPMPPPPPMMPMMM MMMMPMMPMPPMPMMM MPMMMPMPMMMPPPMM MMPMPMMMMPPMMMMM MMMMMMMPMMMMPMMM MMPMMPMPMMPMMMMM MMMMMMMMMMMMMMMM } # tile 108 (dust vortex) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKMMKKKKMMMMM MMMKMMKKJJJKMMMM MMKMMKJJJJMMKMMM MKJMKJJMJKKMMKMM MKJJKJMJJJJKMMMM MKJJJJMMMMJJKMMM MKKJMJMMMJMJKKMM MMKJJMMMMJJJJKMM MMMKJJJJMJKJJKMM MKMMKKJMJJKMJKMM MMKMMJJJJKMMKMMM MMMKJJJKKMMKMMMM MMMMKKKKMMKMMMMM MMMMMMMMMMMMMMMM } # tile 109 (ice vortex) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMNMMNNNNMMMMM MMMNMMNNOOONMMMM MMNMMNOOOOMMNMMM MNOMNOOMONNMMNMM MNOONOMOOOONMMMM MNOOOOMMMMOONMMM MNNOMOMMMOMONNMM MMNOOMMMMOOOONMM MMMNOOOOMONOONMM MNMMNNOMOONMONMM MMNMMOOOONMMNMMM MMMNOOONNMMNMMMM MMMMNNNNMMNMMMMM MMMMMMMMMMMMMMMM } # tile 110 (energy vortex) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMEMMEEEEMMMMM MMMEMMEEAAAEMMMM MMEMMEAAAAMMEMMM MEAMEAAAAIEMMEMM MEAAIAAAAAAEMMMM MEAAAAAAAAAAEMMM MEEAAAAAAAAAEEMM MMEAAAAAAAAAAEMM MMMEAAAAAAIAAEMM MEMMEIAAAAEMAEMM MMEMMAAAAEMMEMMM MMMEAAAEEMMEMMMM MMMMEEEEMMEMMMMM MMMMMMMMMMMMMMMM } # tile 111 (steam vortex) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPMMPPPPMMMMM MMMPMMPPBBBPMMMM MMPMMPBBBBMMPMMM MPBMPBBPBPPMMPMM MPBBPBPBBBBPMMMM MPBBBBPMPPBBPMMM MPPBPBMMMBPBPPMM MMPBBPPMPBBBBPMM MMMPBBBBPBPBBPMM MPMMPPBPBBPMBPMM MMPMMBBBBPMMPMMM MMMPBBBPPMMPMMMM MMMMPPPPMMPMMMMM MMMMMMMMMMMMMMMM } # tile 112 (fire vortex) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMDMMDDDDMMMMM MMMDMMDDCCCDMMMM MMDMMDCCCCMMDMMM MDCMDCCHCDDMMDMM MDCCDCHCCCCDMMMM MDCCCCHHHHCCDMMM MDDCHCHHHCHCDDMM MMDCCHHHHCCCCDMM MMMDCCCCHCDCCDMM MDMMDDCHCCDMCDMM MMDMMCCCCDMMDMMM MMMDCCCDDMMDMMMM MMMMDDDDMMDMMMMM MMMMMMMMMMMMMMMM } # tile 113 (baby long worm) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMCLCMMMMMMM MMMMMMLLLMMMMMMM MMMMMGGAGGMAMMMM MMMMMGGAGGAAAMMM MMMMMMLLLAAAMCMM MMMMMMLLLAAMCCMM MMMMMMCLLCCCCAMM MMMMMMMLLLCCAMMM MMMMMMMMCLLMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 114 (baby purple worm) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMIMMMMMMMM MMMMMMIIIMMMMMMM MMMMMMIIIMMMMMMM MMMMMGGAGGMAMMMM MMMMMGGAGGAAAMMM MMMMMMIIIAAAMDMM MMMMMMIIIAAMDDMM MMMMMMIIIDDDDAMM MMMMMMMIIIDDAMMM MMMMMMMMIIIMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 115 (long worm) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMCLCMMMMMMMM MMMMCLLLCMMMMMMM MMMMLLLLLMMMMMMM MMMGGGLGGGAAMMMM MMMGAGLGAGAAAMMM MMMGGGLGGGAAAMMM MMMMLLLLLAAACCMM MMMMLLLLLAACCCMM MMMMCLLLLCCCCAMM MMMMMLLLLLCCAMMM MMMMMMCLLLLMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 116 (purple worm) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMDIDMMMMMMMM MMMMDIIIDMMMMMMM MMMMIIIIIMMMMMMM MMMGGGIGGGAAMMMM MMMGAGIGAGAAAMMM MMMGGGIGGGAAAMMM MMMMIIIIIAAADDMM MMMMIIIIIAADDDMM MMMMDIIIIDDDDAMM MMMMMIIIIIDDAMMM MMMMMMDIIIIMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 117 (grid bug) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMDMMMMNHCNMMDMM MDMDMMNHDNCNDEDM DMDMDMNNHCNDMDED MDMMMDMNNHDNDMMM MDDDMMENNGMDMDEM MMDDDDEEEEGDMMDE DMMMMMDEHEEMDMMM MDMMMMMMMHMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 118 (xan) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMGGMMMM MMMHHHMMMGOGGMMM MMMMMHHMMGGGGMMM MMMHHHHHMGGGMMMM MMMMMMMGGMMMAAAM MMMMMGOGGHHAAAAM MMMMGOGGMMHHAAAM NNNGOGGMAAHHHAMM NANGGGGMAAHAHMMM NNNGGNNNAAAAAAMM MMGGGNANAAMAAAMM MGGGANNNAAMAMAMM MMGMMAAAAAAMMMMM MMMMMMAAMAAMMMMM } # tile 119 (yellow light) { MMMMMMMMMMMMMMMM MMMMMMNAMMMMMMMM MMMMMMHAMMMMMMMM MMNAMNHNAMNAMMMM MMMLALHLALAMMMMM MMMMNHHHNAMMMMMM MMNLHHHHHLNAMMMM NHHHHHHHHHHHNAMM MMNLHHHHHLNAMMMM MMMMNHHHNAMMMMMM MMMLALHLALAMMMMM MMNAMNNNAMNAMMMM MMMMMMHAMMMMMMMM MMMMMMNAMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 120 (black light) { MMMMMMMMMMMMMMMM MMMMMMAAMMMMMMMM MMMMMMAAMMMMMMMM MMAAMAAAAMAAMMMM MMMAAAAAAAAMMMMM MMMMAAAAAAMMMMMM MMAAAAAAAAAAMMMM AAAAAAAAAAAAAAMM MMAAAAAAAAAAMMMM MMMMAAAAAAMMMMMM MMMAAAAAAAAMMMMM MMAAMAAAAMAAMMMM MMMMMMAAMMMMMMMM MMMMMMAAMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 121 (zruty) { MMMMMMMMMMMMMMMM MMMMMMFFGFMMMMMM MMMMOOFGFFFFMMMM MMMAOFGFOOKFFMMM MMMFFGFAOAJKKFMM MMFFFFFFJAAJKKMM MMODOFFJAJJKKJAM MMDDDDJAJJKJJAAM MMJODOAJJJAJJAAA MKKJAJJJKJAJJAAA MKKAAJKKKKJAAAAA MMMAJJKKKKJJAAAA MMMKJJAAAAKJAAAM MMJKJJJAAJJJJMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 122 (couatl) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMIMMMMIMM MMMMKKAIIIMMIIIM MMMNAOJAKIMIIIII MMMKKJAJJKKKMMII MMMKKAAIJJJJJMMI MMMFAAMIMMMKJMMI MMFAFAMMAAAKJAAM MMMMMMMAAAJJAAAM MMMMMMAKKJJAAAMM MMMMMMKJAAAAAJAM MMMMMJJAAMMMJAMM MMMMMMJJJJJJAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 123 (Aleax) { MMMMMMMMMMMMMMMM MMMMMMBBBBMMIMMM MMIMMBFMMMBMMMMM MMMMBFMHHAMBMMMM MMMBFMHHHHAMBMIM MMMBFMLFLFAMFBMM MIMBFMLLLLAMFBMM MMMBFMALLAMFBMMM MMBFMLLAALLMABAM MBFMLLLLLLLLAFBM MBFMLALLLLALAFBM MBFMLAJJKJALAFBM MMBFMMLJJLAAABAM MMMBFMLLALAABAMM MMBFMLLAALLAFBMM MMMMMMMMMMMMMMMM } # tile 124 (Angel) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMHHHHMMMMMM MMMMMMMMMMMMMMMM MMMMMMMCCMMMMMMM MMMMMMCLLCMMAAMM MMMMMMPLLPMMMMAM MMMMMMNPPPAMAMMM MMMMMBBLLPPAAAMM MMMMMNNLLPPAAAMM MMMMMMBNNPAAAAMM MMMMMMBNNPAAAAMM MMMMMBNNNPAAMAMM MMMMMBNNNNPAMMMM MMMMBNNNNNNPMMMM MMMMMMMMMMMMMMMM } # tile 125 (ki-rin) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMLPMMMMMMMMMMMM MMPLOMCMCMMMMMMM MMMPLCCDMMMMMMMM MMMKCIKDMMMMMMMM MMKCCCCDMMMMMMMM MMCKACCDAMMMMMMM MMMACCCCCCMMMAMM MMMKCCCKCCKAAMMM MMCAKCKCKCAKAMMM MMCAAKAKAKAMMMMM MMMLMKALAKMMMMMM MMMMMLAMMLMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 126 (Archon) { MMMMMMMMMMMMMMMM MMMMMMOOOOMMMMMM MMMMMOOOOOOMMMMM MMMMMOJLLJOMMMMM MMMMMOLLLLOMMMMM MMMMOOJLLJOOMMMM MMMMMMAJJAMMMMMM MMMMMAAAAAAAMMMM MMMMAAAAAAAAAMMM MMMOAAOAAAJLJMMM MMOOAOAAAACJCMMM MMMMLAAAACCJCCMM MMMMMAAAAAJJJMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 127 (bat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMJJJCACJJJMMMM MMJJAAHJHAAJJMMM MMJAMMMJAMMAJMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMAAAAMMMMMM MMMMAAAAAAAAMMMM MMMAAAMAAMAAAMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 128 (giant bat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMJKMJMJMJKMMMM MMKJJJCACJJKJMMM MJJJAAHJHAAJJKMM MKJAMMMJAMMAJJMM MMJAMMMMMMMAJMMM MMMMMMMMMMMMMMMM MMMMMAAAAAAMMMMM MMMAAAAAAAAAAMMM MMAAAAMAAMAAAAMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 129 (raven) { MMAAAAMMMAAAMMMM MAAAAAAMAAAMMMMM AAAAAAAAAAAMAAMM AMMMAAAAAAAAAAAM MMMMMMAAAAAAAAAM MMMMMAAAAMMMMMAA MMMMMADAMMMMMMMA MMMMMPAMMMMMMMMM MMMMMPMMMMMMMMMM MMMMMMMMMPMPMPMM MMMMMMMMPMPMPMPM MMMMMMMPMPMPMMMM MMMMMMMMPMPMPMMM MMMMMMMMMMMPMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 130 (vampire bat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMAAMAMAMAAMMMM MMAAAAAAAAAAAMMM MAAAAMDADMAAAAMM MAAAMMMAMMMAAAMM MMAMMMMMMMMMAMMM MMMMMMMMMMMMMMMM MMMMMAAAAAAMMMMM MMMAAAAAAAAAAMMM MMAAAAMAAMAAAAMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 131 (plains centaur) { MMMMMMMMMMMMMMMM MMMKKAMMMMMMMMMM MMMLLAAMMMMMMMMM MAAKKAAMMMMMMMMM MLLAALLAMMMMMMMM LALLLLALAMMMMMMM LALLLKALAMAMMMMM MMLKLKAAAAAMMMMM MMKLKJKJJKAAMMMM MKJKJKJKJAKAAAAM MKAKJJJJKJAAAMAM MKAAKAAAAKAAMMMM MMCAKAAJAKAMMMMM MMMMKAAKAKMMMMMM MMMMCAMMMCMMMMMM MMMMMMMMMMMMMMMM } # tile 132 (forest centaur) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMKKAMMMMMMMMMM LAMLLAALAMMMMMMM LAALLAALAMMMMMMM MLLAALLAMMMMMMMM MMLLLLAMAMMMMMMM MMLKLKAAAAAMMMMM MMKLKJKJJKAAMMMM MKJKJKJKJAKAMAMM MKAKJJJJKJAAAAMM MKAAKAAJAKAMMMMM MMCMKAAKAKMMMMMM MMMMCAMMMCMMMMMM MMMMMMMMMMMMMMMM } # tile 133 (mountain centaur) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMKKAMMMMMMMMMM MMMLLAAMMMMMMMMM MMAKKAAMMMMMMMMM MLJJJJLAMMMMMMMM LAJKKJALAMAMMMMM LAKKKKALAAAMMMMM MMJJJJKJJKAAMMMM MKJJJKJKJAKAAAAM MKAKJJJJKJAAAMAM MKAAKAAAAKAAMMMM MMCAKAAJAKAMMMMM MMMMKAAKAKMMMMMM MMMMCAMMMCMMMMMM MMMMMMMMMMMMMMMM } # tile 134 (baby gray dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMBBBAMMMMMMM MMMMNPNPPAMMMMMM MMMBPPPPPAMMMMMM MMCHHPABPAMAAAMM MCHCDAMBPAAAAAAM MMDMMBPPAAAAAAAM MMMMBBPPPPPAAAAM MMMBOOPPPPPPAAAM MMBPOBPPPPPPPAAM MMBPPBPPOBPAPPAM MMBPABPMABPAPPAM MMMMMBPAAMMPPAAM MMMMMMMMMMMPAAMM } # tile 135 (baby silver dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPAMMMMMMM MMMMOBOBBAMMMMMM MMMPBBBBBAMMMMMM MMCHHBAPBAMAAAMM MCHCDAMPBAAAAAAM MMDMMPBBAAAAAAAM MMMMPPBBBBBAAAAM MMMPNNBBBBBBAAAM MMPBNPBBBBBBBAAM MMPBBPBBNPBABBAM MMPBAPBMAPBABBAM MMMMMPBAAMMBBAAM MMMMMMMMMMMBAAMM } # tile 136 (baby shimmering dragon) { MIMMMMMMMMMMMMMM MMMBBBBBBBMIMMMM MMBFMFFFMFBMMMIM MBFMMBBBAMFBMMMM BFMMNPNPPAFBMIMM BFMBPPPPPAMBMMMM BMCHHPABPAFBAAIM BCHCDAMBPAAFBAAM BMDMMBPPAAAAFBAM BMMMBBPPPPPAAFBM BFMBOOPPPPPPAAAB BFBPOBPPPPPPPAFB BFBPPBPPOBPAPPFB BMBPABPMABPAPPFB BMMMMBPAAMMPPAAB MBMMMMMMMMMPAABM } # tile 137 (baby red dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMIIIAMMMMMMM MMMMNDNDDAMMMMMM MMMIDDDDDAMMMMMM MMCHHDAIDAMAAAMM MCHCDAMIDAAAAAAM MMDMMIDDAAAAAAAM MMMMIIDDDDDAAAAM MMMIHHDDDDDDAAAM MMIDHIDDDDDDDAAM MMIDDIDDHIDADDAM MMIDAIDMAIDADDAM MMMMMIDAAMMDDAAM MMMMMMMMMMMDAAMM } # tile 138 (baby white dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMNNNAMMMMMMM MMMMIOIOOAMMMMMM MMMNOOOOOAMMMMMM MMCHHOANOAMAAAMM MCHCDAMNOAAAAAAM MMDMMNOOAAAAAAAM MMMMNNOOOOOAAAAM MMMNOOOOOOOOAAAM MMNOONOOOOOOOAAM MMNOONOOONOAOOAM MMNOANOMANOAOOAM MMMMMNOAAMMOOAAM MMMMMMMMMMMOAAMM } # tile 139 (baby orange dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLLLAMMMMMMM MMMMNCNCCAMMMMMM MMMLCCCCCAMMMMMM MMCHHCALCAMAAAMM MCHCDAMLCAAAAAAM MMDMMLCCAAAAAAAM MMMMLLCCCCCAAAAM MMMLOOCCCCCCAAAM MMLCOLCCCCCCCAAM MMLCCLCCOLCACCAM MMLCALCMALCACCAM MMMMMLCAAMMCCAAM MMMMMMMMMMMCAAMM } # tile 140 (baby black dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMAAAMMMMMMMM MMMMNANAAMMMMMMM MMMAAAAAAMMMMMMM MMCHHAMAAMMPPPMM MCHCDMMAAMPPPPPM MMDMMAAAPPPMPPPM MMMMAAAAAAAPPPPM MMMAAAAAAAAAPPPM MMAAAAAAAAAAAPPM MMAAAAAAAAAPAAPM MMAAPAAMPAAPAAPM MMMMMAAPMMMAAPPM MMMMMMMMMMMAPPMM } # tile 141 (baby blue dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMBBBAMMMMMMM MMMMNENEEAMMMMMM MMMBEEEEEAMMMMMM MMCHHEABEAMAAAMM CCHCDAMBEAAAAAAM MMDMMBEEAAAAAAAM MMMMBBEEEEEAAAAM MMMBOOEEEEEEAAAM MMBEOBEEEEEEEAAM MMBEEBEEOBEAEEAM MMBEABEMABEAEEAM MMMMMBEAAMMEEAAM MMMMMMMMMMMEAAMM } # tile 142 (baby green dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMGGGAMMMMMMM MMMMNFNFFAMMMMMM MMMGFFFFFAMMMMMM MMCHHFAGFAMAAAMM MCHCDAMGFAAAAAAM MMDMMGFFAAAAAAAM MMMMGGFFFFFAAAAM MMMGOOFFFFFFAAAM MMGFOGFFFFFFFAAM MMGFFGFFOGFAFFAM MMGFAGFMAGFAFFAM MMMMMGFAAMMFFAAM MMMMMMMMMMMFAAMM } # tile 143 (baby yellow dragon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMNNNAMMMMMMM MMMMDHDHHAMMMMMM MMMNHHHHHAMMMMMM MMCHHHANHAMAAAMM MCHCDAMNHAAAAAAM MMDMMNHHAAAAAAAM MMMMNNHHHHHAAAAM MMMNOOHHHHHHAAAM MMNHONHHHHHHHAAM MMNHHNHHONHAHHAM MMNHANHMANHAHHAM MMMMMNHAAMMHHAAM MMMMMMMMMMMHAAMM } # tile 144 (gray dragon) { MMMMMMBBBPAMMMMM MMMMMNPNPPPAMMMM MMMMBPPPPPPAMMMM MMDCHHPMMPPAMMMM CHCHCDMMBPPAMMMM HDMDMMMBPPAMMMMM MMMMMMOBPAAAAAAM MMMMBOBPAAAAAAAA MMBOOBPAMPPMAAAM MBOOOBPPPPPPMAAM MBOOOBPPPPPPPAAM PPOOBBPPPPPPPPAM BPMOBPPOOPPMPMAM BPAABPMAAPPAPPAM MMMMBPAAMMMPPMAM MMMMMMMMPPPPMAMM } # tile 145 (silver dragon) { MMMMMMPPPBAMMMMM MMMMMOBOBBBAMMMM MMMMPBBBBBBAMMMM MMDCHHBMMBBAMMMM CHCHCDMMPBBAMMMM HDMDMMMPBBAMMMMM MMMMMMNPBAAAAAAM MMMMPNPBAAAAAAAA MMPNNPBAMBBMAAAM MPNNNPBBBBBBMAAM MPNNNPBBBBBBBAAM BBNNPPBBBBBBBBAM PBMNPBBNNBBMBMAM PBAAPBMAABBABBAM MMMMPBAAMMMBBMAM MMMMMMMMBBBBMAMM } # tile 146 (shimmering dragon) { MIMBFMBBBPAFBMMM MMBFMNPNPPPAFBMI MBFMBPPPPPPAFBMM MBDCHHPMMPPAFBIM CBCHCDMMBPPAFBMM HDBBMMMBPPAMBMMI MMBFMMOBPAAAABAM MBFMBOBPAAAAAFBA BFBOOBPAMPPMAAFB MBOOOBPPPPPPMAFB MBOOOBPPPPPPPAFB PPOOBBPPPPPPPPFB BPMOBPPOOPPMPMFB BPAABPMAAPPAPPFB MMMMBPAAMMMPPMAB MMMMMMMMPPPPMABM } # tile 147 (red dragon) { MMMMMMIIIDAMMMMM MMMMMNDNDDDAMMMM MMMMIDDDDDDAMMMM MMDCHHDMMDDAMMMM CHCHCDMMIDDAMMMM HDMDMMMIDDAMMMMM MMMMMMHIDAAAAAAM MMMMIHIDAAAAAAAA MMIHHIDAJDDJAAAM MIHHHIDDDDDDJAAM MIHHHIDDDDDDDAAM DDHHIIDDDDDDDDAM IDMHIDDHHDDJDJAM IDAAIDMAADDADDAM MMMMIDAAJJJDDJAM MMMMMMMMDDDDJAMM } # tile 148 (white dragon) { MMMMMMNNNOAMMMMM MMMMMIOIOOOAMMMM MMMMNOOOOOOAMMMM MMDCHHOMMOOAMMMM CHCHCDMMNOOAMMMM HDMDMMMNOOAMMMMM MMMMMMONOAAAAAAM MMMMNONOAAAAAAAA MMNOONOAMOOMAAAM MNOOONOOOOOOJAAM MNOOONOOOOOOOAAM OOOONNOOOOOOOOAM NOMONOOOOOOMOJAM NOAANOMAAOOAOOAM MMMMNOAAMMMOOJAM MMMMMMMMOOOOJAMM } # tile 149 (orange dragon) { MMMMMMLLLCAMMMMM MMMMMNCNCCCAMMMM MMMMLCCCCCCAMMMM MMDCHHCMMCCAMMMM CHCHCDMMLCCAMMMM HDMDMMMLCCAMMMMM MMMMMMOLCAAAAAAM MMMMLOLCAAAAAAAA MMLOOLCAMCCKAAAM MLOOOLCCCCCCJAAM MLOOOLCCCCCCCAAM CCOOLLCCCCCCCCAM LCMOLCCOOCCKCJAM LCAALCMAACCACCAM MMMMLCAAMKKCCJAM MMMMMMMMCCCCJAMM } # tile 150 (black dragon) { MMMMMMAAAAMMMMMM MMMMMNANAAAMMMMM MMMMAAAAAAAMMMMM MMDCHHAMMAAMMMMM CHCHCDMMAAAMMMMM HDMDMMMAAAMMMMMM MMMMMMAAAMMPPPPM MMMMAAAAPPPPPPPP MMAAAAAAAAAMPPPM MAAAAAAAAAAAAPPM MAAAAAAAAAAAAPPM AAAAAAAAAAAAAAPM AAMAAAAAAAAMAAPM AAPPAAMPPAAPAAPM MMMMAAPPMMMAAAPM MMMMMMMMAAAAAMMM } # tile 151 (blue dragon) { MMMMMMBBBEAMMMMM MMMMMNENEEEAMMMM MMMMBEEEEEEAMMMM MMDCHHEMMEEAMMMM CHCHCDMMBEEAMMMM HDMDMMMBEEAMMMMM MMMMMMOBEAAAAAAM MMMMBOBEAAAAAAAA MMBOOBEAMEEMAAAM MBOOOBEEEEEEJAAM MBOOOBEEEEEEEAAM EEOOBBEEEEEEEEAM BEMOBEEOOEEMEJAM BEAABEMAAEEAEEAM MMMMBEAAMMMEEJAM MMMPMMMMEEEEJAMM } # tile 152 (green dragon) { MMMMMMGGGFAMMMMM MMMMMNFNFFFAMMMM MMMMGFFFFFFAMMMM MMDCHHFMMFFAMMMM CHCHCDMMGFFAMMMM HDMDMMMGFFAMMMMM MMMMMMOGFAAAAAAM MMMMGOGFAAAAAAAA MMGOOGFAMFFMAAAM MGOOOGFFFFFFJAAM MGOOOGFFFFFFFAAM FFOOGGFFFFFFFFAM GFMOGFFOOFFMFJAM GFAAGFMAAFFAFFAM MMMMGFAAMMMFFJAM MMMMMMMMFFFFJAMM } # tile 153 (yellow dragon) { MMMMMMNNNHAMMMMM MMMMMDHDHHHAMMMM MMMMNHHHHHHAMMMM MMDCHHHMMHHAMMMM CHCHCDMMNHHAMMMM HDMDMMMNHHAMMMMM MMMMMMONHAAAAAAM MMMMNONHAAAAAAAA MMNOONHAJHHJAAAM MNOOONHHHHHHJAAM MNOOONHHHHHHHAAM HHOONNHHHHHHHHAM NHMONHHOOHHJHJAM NHAANHMAAHHAHHAM MMMMNHAAJJJHHJAM MMMMMMMMHHHHJAMM } # tile 154 (stalker) { MMMMMMMMMMMMMMMM MMMMMMMPPPMMMMMM MMMMMMPMPMPMMMMM MMMMMPPPPPPMMMMM MMMMMPPMMPPPMMMM MMMMPPPPPPMPMMMM MMMMPMPPPPMPMMMM MMMMPMPPPMMPMMMM MMMMPMMPPMMPMMMM MMMMPMPPPPMPMMMM MMMMPMPMMPMPMMMM MMMMPMPMMPMPMMMM MMMMMMPMMPMMMMMM MMMMMMPMMPMMMMMM MMMMMPPMMPPMMMMM MMMMMMMMMMMMMMMM } # tile 155 (air elemental) { MMMMMMMMMMMMMMMM MMMPMPPPMMPMMMMM MMPMPAPAMPMMMMMM PMMPPPPPPMMPMMMM MPMPPAAPPPMMMPMM MMPPPAAPMPMPMMMM MMPAPAAPAPMMMMMM PMPAPPPMAPMPMAAM MMPAMPPMAPMAAAAM MMPAPPPPAPAAAAMM MMPAPMAPAPAAAAMM MMPAPMAPAPAAAAAM MMMMPMAPAAAAAAAM MMPMPMAPPAAAAAAM MMMPPMAPPPAMMMMM MMMMMMMMMMMMMMMM } # tile 156 (fire elemental) { MMMMMMMMMMMMMMMM MHMMLDDDMMMMMMMM MMMLDADACMHMMMMM HMMDDDDDDMMHMHMM MMLDDAADDDMMMMMM MMDDDAADCDMHMMMM MMDADAACADMMMMMM HMDADDDCADMMMAAM MMDACDDCADMAAAAM MMDADDDDADAAAAMM MMDADCADADAAAAMM HMDADCADADAAAAAM MMMMDCADAAAAAAAM MHMLDCADDAAAAAAM MMLDDCADDDAMMMMM MMMMMMMMMMMMMMMM } # tile 157 (earth elemental) { MMFMMMMMMMMMMMMM MMMMCKKKMMFMMMMM MMMCKAKAJMMMMFMM MMMKKKKKKMMMMMMM MMCKKAAKKKMFMMFM MFKKKAAKJKMMMMMM MMKAKAAJAKMMFMMM MMKAKJJJAKMMMAAM FMKAJKKJAKMAAAAM MMKAKKKKAKAAAAMM MMKAKJAKAKAAAAMM MMKAKJAKAKAAAAAM MMMMKJAKAAAAAAAM MFMCKJAKKAAAAAAM MMCKKJAKKKAMMMMM MMMMMMMMMMMMMMMM } # tile 158 (water elemental) { MMMMMMMMMMMMMMMM MMMMPBBBMMEMMMMM MEMPBABAEMMMEMMM MMMBBBBBBMMMMMMM MMPBBAABBBMEMMEM EMBBBAABEBMMMMMM MMBABAABEBMEMMMM MMBABBBBEBMMMAAM MMBAPBBEABMAAAAM EMBABBBBABAAAAMM MMBABEABABAAAAMM MMBABEABABAAAAAM MMMMBEABAAAAAAAM MEMPBEABBAAAAAAM MMPBBEABBBAMMMMM MMMMMMMMMMMMMMMM } # tile 159 (lichen) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMFFFMMMFFFMMMM MMFCFFFFFCCFAMMM MFCOOFFFCOFFFAMM MFCOOFFFCFFFFAMM MMFFFFFFFFFFAMMM MMMAFFFCCFFFAMMM MMMFFFFCOFFAAMMM MMFCCFFCOFCFAMMM MMFCOFFCFFOCFAMM MMFFCFFFCFFFFAMM MMMFFFAAFFFFFAMM MMMMMAAMAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 160 (brown mold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMJJJMMMJJJMMMM MMJKJJJJJKKJAMMM MJKCCJJJKCJJJAMM MJKCCJJJKJJJJAMM MMJJJJJJJJJJAMMM MMMAJJJKKJJJAMMM MMMJJJJKCJJAAMMM MMJKKJJKCJKJAMMM MMJKCJJKJJCKJAMM MMJJKJJJKJJJJAMM MMMJJJAAJJJJJAMM MMMMMAAMAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 161 (yellow mold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMHHHMMMHHHMMMM MMHHHHHHHNHHAMMM MHHNNOHHNNOHHAMM MHHNNOOHHOOHHAMM MMHHOOHHHHHHAMMM MMMAHHHHHHHHAMMM MMMHHHHNNOHAAMMM MMHHHHHNNOHHAMMM MMHNNOHHHONOHAMM MMHHOHHHHHOOHAMM MMMHHHAAHHHHHAMM MMMMMAAMAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 162 (green mold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMFFFMMMFFFMMMM MMFGFFFFFGGFAMMM MFGOOFFFGOFFFAMM MFGOOFFFGFFFFAMM MMFFFFFFFFFFAMMM MMMAFFFGGFFFAMMM MMMFFFFGOFFAAMMM MMFGGFFGOFGFAMMM MMFGOFFGFFOGFAMM MMFFGFFFGFFFFAMM MMMFFFAAFFFFFAMM MMMMMAAMAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 163 (red mold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMDDDMMMDDDMMMM MMDCDDDDDCCDAMMM MDLLCDDDCLDDDAMM MDCCCDDDCDDDDAMM MMDDDDDDDDDDAMMM MMMADDDCCDDDAMMM MMMDDDDCLDDAAMMM MMDCCDDCLDCDAMMM MMDCLDDCDDLCDAMM MMDDCDDDCDDDDAMM MMMDDDAADDDDDAMM MMMMMAAMAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 164 (shrieker) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMGGGGFFMMMMM MMMGGGGIGIDFFMMM MGGGIIGGGIIFFFFM GIIGIIGGGGGGGDDF GIIGGGGIIGIIGIDF GGGGIGGIIGIIGGFF MMGGGGGGGGGGGMMM MMMMMMFFFMMAAAAA MMMMAGGGFFAAAAAA MMMAGGGGGGFAAAAM MMMAAAAAAAAAAMMM MMMMMMMMMMMMMMMM } # tile 165 (violet fungus) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMIIIMMMIIIMMMM MMILIIIIILLIAMMM MIOOLIIILOIIIAMM MILLLIIILIIIIAMM MMIIIIIIIIIIAMMM MMMAIIILLIIIAMMM MMMIIIILOIIAAMMM MMILLIILOILIAMMM MMILOIILIIOLIAMM MMIILIIILIIIIAMM MMMIIIAAIIIIIAMM MMMMMAAMAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 166 (gnome) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMDFMMMMMMMMM MMMMMMGMMMMMMMMM MMMMMGFFMMMMMMMM MMMMGGFFFMMMMMMM MMMMGLLLFMMMMMMM MMMMMOLOMMMAAAMM MMMFGOOOFFAAAAMM MMMGAGOFAFAAAAMM MMMMLKNKFAAAAMMM MMMMFGAFFAAMMMMM MMMMGFAFGMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 167 (gnome lord) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMDMMMMMMMMM MMMMMMGMMMMMMMMM MMMMMMGMMMMMMMMM MMMMMGFFMMMMMMMM MMMMHHHHHMMMMMMM MMMMGLLLFMMMMMAM MMMMMOLOMMMAAAMM MMMFGOOOFFAAAAMM MMMGAGOFAFAAAAMM MMMMLKNKFAAAAMMM MMMMFGAFFAAMMMMM MMMMGFAFGMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 168 (gnomish wizard) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMGMMMMMMMMM MMMMMGFFMMMMMMMM MMMMGGFFFMMMMMMM MMMMGLLLFMMMMMMM MMMFFOLOFFMAAAMM MMMGFOOOFFAAAAMM MMMFAGOFAFAAAAMM MMMGLKNKFFAAAMMM MMMFFGFFFFAMMMMM MMMGFFFFGFAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 169 (gnome king) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMHMCMHMMMMMMM MMMMHCHCHMMMMMMM MMMMHHHHHMMMMMMM MMMMGLLLFMMMAMMM MMMMMOLOMMMAAAAM MMMFGOOOFFAAAAMM MMMGAGOFAFAAAAMM MMMMLKNKFAAAAMMM MMMMFGAFFAAMMMMM MMMMGFAFGMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 170 (giant) { MMMMMMJJJJAAMMMM MMMMJJJJJJJJAMMM MMMMJJLLLLJJAMMM MMMMJFFLLFFJAMMM MMMMJLLLLLLJAMMM MMMMALLAALLAAAMM MMMMMALLLLJAAAAM MMCCLLJJJJLLCCAA MCLLLCCKCKCLLLCA MLLLKLKCKCLKLLLA MLLAALLCCLLAALLA MLLAAJJJKKJAALLA MCLCMJJJJJKKCLAA MMLLMCLJACLJLLAA MMMMMCLJACLJAAAA MMMLLLLJMCLLLKAA } # tile 171 (stone giant) { MMMMMMJJJJAAMMMM MMMMJJJJJJJJAMMM MMMMJJLLLLJJAMMM MMMMJFFLLFFJAMMM MMMMJLLLLLLJAMMM MMMMALLAALLAAAMM MMMMMALLLLJAAAAM MMCCLLJJJJLLCCAA MCLLLCCKCKCLLLCA MLLLAAKCKCLKLLLA MLLPPPACCLLAALLA MLLPPPPAKKJAALLA MCLCPPPAJJKKCLAA MMLLPPALACLJLLAA MMMMMALJACLJAAAA MMMLLLLJMCLLLKAA } # tile 172 (hill giant) { MMMMMMJJJJAAMMMM MMMMJJJJJJJJAMMM MMMMJJLLLLJJAMMM MMMMJFFLLFFJAMMM MMMMJLLLLLLJAMMM MMMMALLAALLAAAMM MMMMMALLLLJAAAAM MMMJJKJJJJJJJAAM MMLJJCCKCKCJJLAM MMJLKKKCKCKKLJAM MMLAAKKCCKJAALAA MMLAAJJJKKJAALAA MMLCMJJJJJKKCLAA MMLLMCLJACLJLLAA MMMMMCLJACLJAAAA MMMLLLLJMLLLLKAA } # tile 173 (fire giant) { MMMMPPDDDDAAMMMM MMMMPDDDDDDDAMMM MMMPPDLLLLDDAMMM MMMPDPFLLFFDAMMM MMMPPPLLLLLDAMMM MMMMPLLAALLAAAMM MMMPPALLLLJAAAAM MMMJPDJJJJJJJAAM MMLDDHDKCKCJJLAM MMJLHDDCKCKKLJAM MMLAHDHCCKJAALAA JLAADDHJKKJAALAA JJLJDHHJJJKKCLAA MMLLJJJJACLJLLAA MMMMMCLJACLJAAAA MMMLLLLJMLLLLKAA } # tile 174 (frost giant) { MMMMMKJJJJAAMMMM MMMMKJJJJJJJAMMM MMMMJJLLLLJJAMMM MMMMJEELLEEJAMMM MMMMJLLLLLLJAMMM MMMMAKJJJJJAAAMM MMMMMKJAAJJAAAAM MMMMKKJJJJAJAAAA MMMKJKJJJJAJJAAA MMKJKKJJJJJKJJAA MMKAAJKJJAJAAJAA MMJAAJKKAKJAAJAA MMLCMJJJJJKKCLAA MMLLMCJJAJLJLLAA MMMMMCLJACLJAAAA MMMLLLLJMCLLLKAA } # tile 175 (storm giant) { MMMMMMJJJJAAMMMM MMMMJJJJJJJJAMMM MMMMJJLLLLJJAMMM MMMMJFFLLFFJAMMM MMMMJLLLLLLJAMMM MMMMALLAALLAAHMM MMMMMALLLLJAHAAM MMMJJKJJJJJHHAAM MMLJJCCKCKHHLAAM MMJLKKKCKHHHHHHM MMLAAKKCCKJAHHAA MMLAAJJJKKJHHALA MMLCMJJJJJKHAAAA MMLLMCLJACHAAAAA MMMMMCLJACCJAAAA MMMLLLLJMLLLLKAA } # tile 176 (ettin) { MMMMNNMMONOPMMMM MMNNOOPNNOOPPMMM MMNPPMMNPPMMPMMM MMALPPLALPPLAMMM MMAPPPPAPPPPAMMM MMAPAAPAPAAPAAMM MMAPPPPAPPPPAAAM MMBIIIIJJJIIIBAA MBPPPIIIIIIPPPBA MPPPFPIIIIPFPPPA MPPAAPIIIIPAAPPA MPPAAIIIIIIAAPPA MBPBMIIFFIIABPAA MMPPMBPAABPAPPAA MMMMMBPAABPAAAAA MMMPPPPAMBPPPFAA } # tile 177 (titan) { MMMMMAAAAAAAMMMM MMMMAALLLLAAAMMM MMMMAMMLLMMAAMMM MMMMALLLLLLAAMMM MMMMALLAALLAAAMM MMMMMALLLLJAAAAM MMCCJJJJJJJJCCAM MCLLLCCKCKCLLLCA MLLLKJKCKCJKLLLA MLLAAJJCCJJAALLA MLLAAJJCCJJAALLA MLLAAJJJKKJAALLA MCLCMJJJJJKKCLAA MMLLMCLJACLJLLAA MMMMMCLJACLJAAAA MMMLLLLJMCLLLKAA } # tile 178 (minotaur) { MMMMMMMMMMMMMMMM MOMMMMMMMMMMOMMM MOOOJJJJJJOOOMMM MMOOJJKJJJOOMMMM MMMJGAKJGAJAMMMM MMMJJJKJJJJAMMMM MMMMJJKJJJAAAMMM MMMMJKKKJAAAAMMM MMCLJAJAKALCAAMA MCLLJJJJJALLCAAA MLLCLAAAALCLLAAM MLAACLLLLCAALAAM MLLMJJJJJJJLLAAA MLLMJJJJJJJLLAAA MMMMCLCACLCAAAAA MMLLLLLMLLLLLAAM } # tile 179 (jabberwock) { MMMMMMMMMMMMMMMM MMMDPMMMMMMMMMMM MMMMDPMADOOMMMMM MMDAIDADIPADMMMM MMMDIAPIPAMMMMMM MMMDBDDDAMMMMMMM MMIBBDADDAMMAAMM MDDDDAODDIAAAAMM MMOAOAMDDAIAAAMM MMIOAODDAAADDAAM MMDDDADDDDAIDAMM MMMAAADDIDIDDDMM MMMMIDDAIDDDDAMM MMMMIDAAIDAAMMMM MMMIDAAMMIDMMMMM MMMMMMMMMMMMMMMM } # tile 180 (vorpal jabberwock) { MMMMMMMMMMMMMMMM MMMGPMMMMMMMMMMM MMMMGPMAGOOMMMMM MMGAFGAGFPAGMMMM MMMGFAPFPAMMMMMM MMMGHGGGAMMMMMMM MMFHHGAGGAMMAAMM MGGGGAOGGFAAAAMM MMOAOAMGGAFAAAMM MMFOAOGGAAAGGAAM MMGGGAGGGGAFGAMM MMMAAAGGFGFGGGMM MMMMFGGAFGGGGAMM MMMMFGAAFGAAMMMM MMMFGAAMMFGMMMMM MMMMMMMMMMMMMMMM } # tile 181 (Keystone Kop) { MMMMMMMMMMMMMMMM MMMMAAMMMMMMMMMM MMMAAAAMMMMMMMMM MMMAOAAMMMCMMMMM MMAAAAAAMMCMMMMM MMMLLLLMMMCMMMMM MMMMLLMMMMCMMMMM MMMAAAAMAAAMMMMM MMAAAAAAAACMPMMM MAAMAAAAAMPPPPMM MMAAAAAAMPPPPPPM MMMMAAAAPPPAPPMM MAMAAAAAAPAAAMMM AAAAAMPAAAAAMMMM MMAAMMMMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 182 (Kop Sergeant) { MMMMMMMMMMMMMMMM MMMMAAMMMMMMMMMM MMMAOOAMMMMMMMMM MMMAOOAMMMCMMMMM MMAAAAAAMMCMMMMM MMMLLLLMMMCMMMMM MMMMLLMMMMCMMMMM MMMAAAAMAAAMMMMM MMAAAAAAAACMPMMM MAAMAAAAAMCPPPMM MMAAAAAAMPPPPPPM MMMMAAAAPPPAPPMM MAMAAAAAAPAAAMMM AAAAAMPAAAAAMMMM MMAAMMMMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 183 (Kop Lieutenant) { MMMMMMMMMMMMMMMM MMMMAAMMMMMMMMMM MMMAOOAMMMCMMMMM MMMAOOAMMMCMMMMM MMAAAAAAMMCMMMMM MMMLLLLMMMCMMMMM MMMMLLMMMMCMMMMM MMOAAAOMAAAMMMMM MOAAAAAMAACMPMMM MAAMAAAAAMCPPPMM MMAAAAAAMPPPPPPM MMMMAAAAPPPAPPMM MAMAAAAAAPAAAMMM AAAAAMPAAAAAMMMM MMAAMMMMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 184 (Kop Kaptain) { MMMMMMMMMMMMMMMM MMMMAAMMMMCMMMMM MMMAHHAMMMCMMMMM MMMAHHAMMMCMMMMM MMAAAAAAMMCMMMMM MMMLLLLMMMCMMMMM MMMMLLMMMMCMMMMM MHHAAAAHHAAMMMMM MAAAAHAAAACCCMMM MAAMAHAAAMCPPPMM MMAAAHAAMPCPPPPM MMMMAAAAPPPAPPMM MAMAAAAAAPAAAMMM AAAAAMPAAAAAMMMM MMAAMMMMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 185 (lich) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOOOMMMMMMMMMM MMAOAOOMMMMMMMMM MMOOOOOMMMMMMMMM MMOOMOMMMMMMMMMM MMMMMPPPMMMMMMMM MMMOOPPPMMMMAAAM MMOMPPPPPAMMAAAM MOMMMPPPPMAAAAAM MMMMOMPPPAAAAMAM MMMMMMPPPAAAMAMM MMMMMOPAPMAMMMMM MMMOOOAMOAMMMMMM MMMMMMOOOMMMMMMM MMMMMMMMMMMMMMMM } # tile 186 (demilich) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOOOMMMMMMMMMM MMAOAOOMMMMMMMMM MMOOOOOMMMMMMMMM MMOOMOMMMMMMMMMM MMMMMPPPMMMMMMMM MMMOOPPPMMMMAAAM MMOMPPPPPAMMAAAM MOMMMPPPPMAAAAAM MMMMLMPPPAAAAMAM MMMMMMLPPAAAMAMM MMMMMLLALMAMMMMM MMMLLLAMLAMMMMMM MMMMMMLLLMMMMMMM MMMMMMMMMMMMMMMM } # tile 187 (master lich) { MMMHMMMMMMMMMMMM MMMHCHMHMMMMMMMM MMMHHHCHMMMMMMMM MMAOAOHHMMMMMMMM MMOOOOOMMMMMMMMM MMOOMOMMMMMMMMMM MMMMMPPPMMMMMMMM MMMPPPPPMMMMAAAM MMPPPPPPPAMMAAAM MOMMPPPPPMAAAAAM MMMMOPPPPAAAAMAM MMMMMMPPPAAAMAMM MMMMMOPAPMAMMMMM MMMOOOAMOAMMMMMM MMMMMMOOOMMMMMMM MMMMMMMMMMMMMMMM } # tile 188 (arch-lich) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOOOMMMMMMMMMM MMDODOOMMMMMMMMM MMOOOOOMMMMMMMMM HMOOMOMMMMMMMMMM AMMMMPPPMMMMMMMM AMMOOPPPMMMMAAAM MAOMPPPPPAMMAAAM MOMMMPPPPMAAAAAM MAMMOMPPPAAAAMAM MMAMMMPPPAAAMAMM MMAMMOPAPMAMMMMM MMAOOOAMOAMMMMMM MMMMMMOOOMMMMMMM MMMMMMMMMMMMMMMM } # tile 189 (kobold mummy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMNMMMMMMMM MMMNONONOMMMMMMM MMMOAOAOMOPMMMMM MMMMONNMMMAMMMMM MMMONODNAMAAMMMM MMOLONNONAAAMAMM MMNALONANAAAAAMM MMNAOLOAOAAAAAMM MMMMNOLAAAAAAMMM MMMMNANAAAAMMMMM MMMOOANOAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 190 (gnome mummy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMGMMMMMMMMM MMMMMGGFOMMMMMMM MMMMGGFFOOPMMMMM MMMMGDODFMMMMMMM MMMMMONOMMMAAAMM MMMNONOONOAAAAMM MMMOANLOAOAAAAMM MMMMNNOLOAAAAMMM MMMMNOANDAAMMMMM MMMMNOAOOMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 191 (orc mummy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMMMMMMM MMMMNOOPMMMMMMMM MMMMDODPOPMMMMMM MMMMOOOAMMMMMMMM MMOOOOOOOAMAAMMM MMOOOOOOOMAAAMMM MMOAOOOAACCCMMMM MMOAOOOCCAAAMMMM MMMMOCCOAAAAAAMM MMMCCAOOAAAAMMMM MMOOOAOOOAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 192 (dwarf mummy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMBMMMMMMMMM MMMMMBBEOMMMMMMM MMMMBBEEEOPMMMMM MMMMBDODEMMMMMMM MMMMMONOMMMAAAMM MMMNONOONOAAAAMM MMMOANLOAOAAAAMM MMMMNNOLOAAAAMMM MMMMNOANDAAMMMMM MMMMNOAOOMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 193 (elf mummy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMOMMMMMM MMMMMMMOOOPMMMMM MMMMMMOOOOPMMMMM MMMMMMOEOEAPMMMM MMMMMMOOOOAMMMMM MMMMMMAOOAMMMMAM MMMMMMOAAOMMAAAM MMMMMOOOOOOAAAAM MMMMOALOOLAOAAAM MMMMOADOOOAOAAMM MMMMMMOOAOAAMAMM MMMMMOOAMOOAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 194 (human mummy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMONNOMMMMMMMMM MMMNNNNOPMMMMMMM MMPANANMOPPMMMMM MMPNNNNMMMMMMMMM MMONOONNPMMMMMMM MONLNNOOOMMMMMMM MNJNOOOOOMMAAAMM MOJOOOODNMAAAAMM MNJOLNOAOAAAAAAM MOCNOMNKNAAAAAMM MNMOOMOLAAAAAAAM MMMOOAOOAAAMMMMM MMNNNMNNNAMMMMMM MMMMMMMMMMMMMMMM } # tile 195 (ettin mummy) { MMMMMNNMMONOOMMM MMMNNOOONNOOOOMM MMMNOOOONOOOOOOM MMMOFOFOLOFOFOMO MMMOOOOOLOOOOOMP MMMNOOOOLNNOOOAM MMMONOOOLOOOOAAA MMOOOONNNNNNNOAA MONNNNNNOONOOOOA MONODNNOOOOOOOOA MNNAAONNONOAAOOA MNOAAONOONLAAOOA MOOOMONOONOOOOAA MMOOMNNOANOLOOAA MMMMMNOOANOOAAAA MMMOOOOOMOOOOKAA } # tile 196 (giant mummy) { MMMMMMONOOAAMMMM MMMMONNNOOOOAMMM MMMMNNOOOOOOOMMM MMMMNFFOOFFOOPMM MMMMNONOOOOOAOPM MMMMAONOOOOAAAPM MMMMMANOOODAAAAM MMOOOONOOONNNOAA MONNNNNOOOOOOOOA MONODNNLOOOOOOOA MNNAAONOLNOAAOOA MNOAAONOONLAAOOA MOOOMONOONOOOOAA MMOOMNNOANOLOOAA MMMMMNOOANOOAAAA MMMOOOOOMOOOOKAA } # tile 197 (red naga hatchling) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKMMMMMMMMMMM MMMKLKMMMMMMMMMM MMMLLLAMMMMMMMMM MMMALAAMMMMMMMMM MMMLALAMMMMMMMMM MMMLLLAMMMMMMMMM MMMLLLAAMMMMMMMM MMMLDLAAMMMMMMMM MMMIDDAAAAADAMMM MMMIDDDAAADDAMMM MMMMIIDDDDDAMMMM MMMMMMMMMMMMMMMM } # tile 198 (black naga hatchling) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKMMMMMMMMMMM MMMKLKMMMMMMMMMM MMMLLLAMMMMMMMMM MMMALAAMMMMMMMMM MMMLALAMMMMMMMMM MMMLLLAMMMMMMMMM MMMLLLAMMMMMMMMM MMMLALAAMMMMMMMM MMMAAAPAMMPAAMMM MMMAAAAPPPAAAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM } # tile 199 (golden naga hatchling) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKMMMMMMMMMMM MMMKLKMMMMMMMMMM MMMLLLAMMMMMMMMM MMMALAAMMMMMMMMM MMMLALAMMMMMMMMM MMMLLLAMMMMMMMMM MMMLLLAAMMMMMMMM MMMLHLAAMMMMMMMM MMMNHHAAAAAHAMMM MMMNHHHAAAHHAMMM MMMMNNHHHHHAMMMM MMMMMMMMMMMMMMMM } # tile 200 (guardian naga hatchling) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKMMMMMMMMMMM MMMKLKMMMMMMMMMM MMMLLLAMMMMMMMMM MMMALAAMMMMMMMMM MMMLALAMMMMMMMMM MMMLLLAMMMMMMMMM MMMLLLAAMMMMMMMM MMMLFLAAMMMMMMMM MMMGFFAAAAAFAMMM MMMGFFFAAAFFAMMM MMMMGGFFFFFAMMMM MMMMMMMMMMMMMMMM } # tile 201 (red naga) { MMMMMMMMMMMMMMMM MMMMKKMMMMMMMMMM MMMKLLKMMMMMMMMM MMMLLLLAMMMMMMMM MMMALLAAMMMMMMMM MMMLAALAMMMMMMMM MMMLLLLAMMMMMMMM MMMLLLDAMMAAMMMM MMMLDLDAMAAAAMMM MMMIDDDAAAIIAMMM MMMIDDDAIDDDIDAM MMMIDDDIDDDDDDDA MMMIDDDDDDAAMDDA MMMMDDDDDAMMDDAM MMMMMDDAAMMDDAMM MMMMMMMMMMDAMMMM } # tile 202 (black naga) { MMMMMMMMMMMMMMMM MMMMKKMMMMMMMMMM MMMKLLKMMMMMMMMM MMMLLLLAMMMMMMMM MMMALLAAMMMMMMMM MMMLAALAMMMMMMMM MMMLLLLAMMMMMMMM MMMLLLAAMMMMMMMM MMMLALAAMMPPPMMM MMMAAAAPPPAAPMMM MMMAAAAPAAAAAAPM MMMAAAAAAAAAAAAP MMMAAAAAAAPPMAAP MMMMAAAAAPMMAAPM MMMMMAAPPMMAAPMM MMMMMMMMMMAPMMMM } # tile 203 (golden naga) { MMMMMMMMMMMMMMMM MMMMKKMMMMMMMMMM MMMKLLKMMMMMMMMM MMMLLLLAMMMMMMMM MMMALLAAMMMMMMMM MMMLAALAMMMMMMMM MMMLLLLAMMMMMMMM MMMLLLHAMMAAMMMM MMMLHLHAMAAAAMMM MMMNHHHAAANNAMMM MMMNHHHANHHHNHAM MMMNHHHNHHHHHHHA MMMNHHHHHHAAMHHA MMMMHHHHHAMMHHAM MMMMMHHAAMMHHAMM MMMMMMMMMMHAMMMM } # tile 204 (guardian naga) { MMMMMMMMMMMMMMMM MMMMKKMMMMMMMMMM MMMKLLKMMMMMMMMM MMMLLLLAMMMMMMMM MMMALLAAMMMMMMMM MMCLAALCMMMMMMMM MMLLLLLLMMMMMMMM MMCLLCLCMMAAMMMM MMMCLLCAMAAAAMMM MMMGLFCAAAGGAMMM MMMGFFFAAFFFGFAM MMMGFFFGFFFFFFFA MMMGFFFFFFAAMFFA MMMMFFFFFAMMFFAM MMMMMFFAAMMFFAMM MMMMMMMMMMFAMMMM } # tile 205 (ogre) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCLLLCMMMMMMM MMLCKKLKKCLMMMMM MMMLAALAALJAMMMM MMMCLLLLLCJAMMMM MMMMCAAACJAAAMMM MMMMLDDDLAAAAMMM MMCLJLLLKALCAAMA MCLLAJJJJALLCAAA MLLCLAAAALCLLAAM MLAACLLLLCAALAAM MLCMHHHBHHACLAAA MLLMJJJJJJALLAAA MMMMCJJJCLAAAAAA MMLLLLLMLLLLLAAM } # tile 206 (ogre lord) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCLLLCMMMMMMM MMLCKKLKKCLMMMMM MMMLAALAALJAMMMM MMMCLLLLLCJAMMMM MMMMCLLLCJAAAMMM MMMMLAAALAAAAMMM MMJKJLLLKAKJAAMA MCLKAJJJJAKLCAAA MLLJKAAAAKJLLAAM MLAAJKKKKJAALAAM MLCMHHHBHHACLAAA MLLMJJJJJJALLAAA MMMMCJJJCLAAAAAA MMLLLLLMLLLLLAAM } # tile 207 (ogre king) { MMMHMMCMMHMMMMMM MMMHDCHCDHMMMMMM MMMHHHHHHHMMMMMM MMLCKKLKKCLMMMMM MMMLAALAALJAMMMM MMMCLLLLLCJAMMMM MMMMCLLLCJAAAMMM MMMMLAAALAAAAMMM MMJKJLLLKAKJAAMA MCJKAJJJJAKJCAAA MLJJKAAAAKJJLAAM MLAAJKKKKJAALAAM MLCMHHHBHHACLAAA MLLMJJJJJJALLAAA MMMMCJJJCLAAAAAA MMLLLLLMLLLLLAAM } # tile 208 (gray ooze) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPBPAMMMMMMM MMMPBBBPBAMMMMMM MMBBNNBPPBAAMMMM MBBNNPPPBBPAAAMM PBBBPPPBPBBAAAMM BBBPBPPPPPBPAAAM BBPBPPPPPPPBAAAM PBPPBPPPBBPPAAAM MPBBPPPBAAPPPAAM MMMPBBBAAAKPPJMM MMMMMMMMACPPAKMM MMMMMMMMMKCCCJMM MMMMMMMMMMMMMMMM } # tile 209 (brown pudding) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMJMMM MMMMJKKJJJMMJJMM MMMKKKCJJJJJMMMM MMKKNNJNNJJJMMMM MMKJANJANJJJAMMM MMKKJJJJJCJJAAMM MMJKJJCJJJJJAAMM MMMJJJJJJJJAAAMM MMMMJJJJJJAAAMMM MMMMMAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 210 (black pudding) { MMMMMMMMAMMMMMMM MMMMMMMMAAMMMMMM MMMMMAAAMMMMMMMM MMMMAAAAAMMMMMMM MMMMCACAAMMMMMMM MMMMDADAAMMMMMMM MMMMAAAAAMMMMMMM MMMMAAAAAMMMMMMM MMMMAAAAAMMMMMMM MMMMMAAAAAMMMMMM MMMMMAAAAAMMMMMM MMMMMMAAAAAMMMMM MMMMMMAAAAAAMMMM MMMMMMMAAAAAAMAM MMMMMMMMAAAAAAAA MMMMMMMMMMAAAAMM } # tile 211 (green slime) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMGMMM MMMMMGMMMMMMGMMG MGMMMMGMMGMNGNMG MMNGMNGGNGGGGGGG MMGGNGGNGGGFGGFM GGNGGGGGGGGGFFMG MNGGGGGFGFGMMMMM NGGGGFGGFGMGMMGF NGGFGGFMMGFMMMMM MMGGFMMGGFMMGMMM } # tile 212 (quantum mechanic) { MMMMMMMMMMMMMMMM MMMMMMLLLLMMMMMM MMMFGGCLCGGFMMMM MMMGNNGLGNNGLMMM BMBGANGGGANGLMMM BMBFGGCLCGGFLMMM BIBMMCLLLCCLMMMM BILNMLLAALLAAAAM BILNNMLLLLJAAAAM BIBMNNJJJJNAAAMM BIBMBNNNONNNAAMM MBMMMNNNONNLAAMM MMMMMNBEBENAMAMM MMMMMNBEBENNMMMM MMMMNAAEBAANNMMM MMMMMMMMMMMMMMMM } # tile 213 (rust monster) { MMMMMMMMMMMMMMMM MMMMEEEEMMMMMMMM MMMEEHEHEMMMMMMM MMMEEEAEEMMMMMMM MMMEEPAPEMMMMMMM MMMEPEAEPMMMEMMM MMMMEEEEMAAEEMMM MMMMEEEEEAAEEEMM MMMEEEEEEEAEAEEM MMEEEEEEAAAAEMMM MMEEAEEEEAEEEAMM MMAAEEEEEEEEEAAM MMMMAEEEEEEEAAAM MMMMMEEEEEAAMMAM MMMMMMAAAAMMMMMM MMMMMMMMMMMMMMMM } # tile 214 (disenchanter) { MMMMMMMMMMMMMMMM MMMMPPPPMMMMMMMM MMMPPDPDPMMMMMMM MMMPPPAPPMMMMMMM MMMPPOAOPMMMMMMM MMMPOPAPOMMMPMMM MMMMPPPPMAAPPMMM MMMMPPPPPAAPPPMM MMMPPPPPPPAPAPPM MMPPPPPPAAAAPMMM MMPPAPPPPAPPPAMM MMAAPPPPPPPPPAAM MMMMAPPPPPPPAAAM MMMMMPPPPPAAMMAM MMMMMMAAAAMMMMMM MMMMMMMMMMMMMMMM } # tile 215 (garter snake) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKKAMMMMMMMMM MMMNAOKAMMMMMMMM MMMKKAKAMMMMMMMM MMMKKAKAMMMMKAMM MMMMAPKAPMMKAPPM MMMMMPKAPPMKAPMM MMMMMKAAPMMKAPMM MMMMKAAPMMKAAPMM MMMMKAAPPKAAPMMM MMMMKAAKKAAPMMMM MMMMMKAAAAPMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 216 (snake) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKKAMMMMMMMMM MMMNAOJAMMMMMMMM MMMKKJAJMMMMMMMM MMMKKAAJMMMMKKMM MMMFAAKJMMMKJAAM MMFAFAKJAAMKJAMM MMMMMKJAAMMKJAMM MMMMKJAAMMKJJAMM MMMMKJAAAKJJAMMM MMMMKJJJJJJAMMMM MMMMMKJJJJAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 217 (water moccasin) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMAAAMMMMMMMMM MMMAAAAAMMMAAMMM MMMOAOAAAMAAMMMM MMMAAAMAAMAAMMMM MMMDAMMAAMAAMMMM MMDMDMAAAMMAAMMM MMMMMAAAMMMAAMMM MMMMMAAAMMMAAMMM MMMMAAAMMMAAAMMM MMMMAAAAAAAAMMMM MMMMAAAAAAAMMMMM MMMMMAAAAAMMMMMM MMMMMMMMMMMMMMMM } # tile 218 (pit viper) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMAAAMMMMMMMMM MMMAAAAAMMMAAAMM MMMOAAAAAMAAMAAM MMMAAMMAAMAAMAAM MMMDMMMAAMAAMMAM MMMMMMAAAMMAAMAM MMMMMMAAMMMAAMMM MMMMMAAAMMMAAMMM MMMMMAAMMMAAAMMM MMMMMAAMMAAAMMMM MMMMMAAAAAAMMMMM MMMMMMAAAAMMMMMM MMMMMMMMMMMMMMMM } # tile 219 (python) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMKKKAMMMMMJJMM MMMGAGJAMMMJJJMM MMJKKJAJMMKJJMMM MMKKKAJJMMKJJMAA MMKKAAKJAMKKJAAM MMMMMAKJAAMKJAAM MMMMJKJAAMMKJJAM MMMJJJAAMMKJJJAM MMMJJJAAAKJJJAMM MMMJJJJJJJJJAAMM MMMMJJJJJJJAAMMM MMMMMJJJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 220 (cobra) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMAAAMMMMMMMMM MMMAAAAAAMMMMMMM MMPAMMAAAAMMMMMM MMAMMAAAAAMMAAMM MMDMMAAAAAMMMMAM MMMMMMAAAMMMMMAM MMMMMMAAMMAAAAMM MMMMMAAMMAAMMMMM MMMMAAMMMAAMMMMM MMMMAAMMMMAAAAMM MMMMAAAMMMMMMAAM MMMMMAAAAAAAAAMM MMMMMMMMMMMMMMMM } # tile 221 (troll) { MMMMMMMMMMMMMMMM MMAAAAAAMMMMMMMM AAAANANAMMMMMMMM MAAKKKJJAMMMMMMM AAAKAAAKAMMMMMMM AKAKAAAKAAMMMMMM KJJAKKKAJKAMMMMM KJAJAAAJJJAMMMMM KJAJKKJJKJAMMMMM MKJJAFGFJJAAAAMM MMKJAMPFJAAAAMMM MMMAFAGFAAAAAAMM MMMGFAGPMAAMAAMM MMKJJAKJAAMAAMMM MMKJAMMKAMMMMMMM MMMMMMMMMMMMMMMM } # tile 222 (ice troll) { MMMMMMMMMMMMMMMM MMOONOOOMMMMMMMM NONOAOAOOMMMMMMM MNOKKKJJOMMMMMMM NOJKAAAKOOMMMMMM OKJKAAAKAOMMMMMM KJJAKKKAJKAMMMMM KJAJAAAJJJAMMMMM KJAJKKJJKJAMMMMM MKJJAEBEJJAAAAMM MMKJAMPEJAAAAMMM MMMAEABEAAAAAAMM MMMBEABPMAAMAAMM MMKJJAKJAAMAAMMM MMKJAMMKAMMMMMMM MMMMMMMMMMMMMMMM } # tile 223 (rock troll) { MMMMMMMMMMMMMMMM MMMAAAAAMMMMMMMM MAAANANAAAAMMMMM MAAKKKJJAAMMMMMM AAAKAAAKAAAAMMMM AKAKAAAKAAAMMMMM KJJAKKKAJKAAMMMM KJAJAAAJJJAMMMMM KJAPAKJJKJAMMMMM PKJPPAGFJJAAAAMM PPPPPAFFJAAAAMMM MPPPAAGFAAAAAAMM MMMAFAGFMAAMAAMM MMKJJAKJAAMAAMMM MMKJAMMKAMMMMMMM MMMMMMMMMMMMMMMM } # tile 224 (water troll) { MMMMMMMMMMMMMMMM MMMAAAAAMMMMMMMM MMAANANAAMMMMMMM MAAKKKJJAAMMMMMM MAAKAAAKAAMMMMMM MKAKAAAKAAMMMMMM KJJAKKKAJKAMMMMM KJAJAAAJJJAMMMMM KJAJKKJJKJAMMMMM MKJJAEBEJJAAAAMM MMKJAMPEJAAAAMMM MMMAEABEAAAAAAMM MMMBEABPMAAMAAMM MMKJJAKJAAMAAMMM MMKJAMMKAMMMMMMM MMMMMMMMMMMMMMMM } # tile 225 (Olog-hai) { MMMPPPPPMMMMMMMM MMPPAAAPPMMMMMMM MMPANANAPMMMMMMM MMPAAAAAPMMMMMMM MPPAAAAAPPMMMMMM PPPAAAAAPPPMMMMM AAPPAAAPPAAMMMMM AAAPPPPPAAAMMMMM AAAPPPPPAAAMMMMM MAAAAPPPAAAPPPMM PONNNNNNAACPPMMM MMMAPAPPAPPPPPMM MMMPPAPPMPPMPPMM MMAAAAAAAPMPPMMM MMAAAMAAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 226 (umber hulk) { MMMMMMMMMMMMMMMM MMMAAAAAMMMMMMMM MMAAAAAAAMMMMMMM MADADADADAMMMMMM MAAAAAAAAAMAMMMM MAAAOAOAAAMAAMMM MAMAOAOAMAAAMMMM MAMAAAAAPAAMMMMM MAAAAAAAPMMMMMMM MAMAAAAAMPPPPPPM MMMAAMAAMPPPPPMM MMMAAMAAPPPPPPPM MMMAAPAAPPPPMMMM MMAAAPAAAPPMMMMM MAAAPMMAAPMMMMMM MMMMMMMMMMMMMMMM } # tile 227 (vampire) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMAAAMMMMMMMM MMMMAAOAAMMMMMMM MADDAGAGADAMMMMM MMADALLOADMMMMMM MAAAAAAAAAMMMMMM MMAAAAAAAAMMMMMM MMMAAAAAAAMMMMMM MMADAAAAAAPPPPPM MMADDAAAAAPPPPMM MMAAAAAAAAPPPMMM MMMMMAAPAAPPMMMM MMMMAAPMMAPMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 228 (vampire lord) { MMMMMMMMMMMMMMMM MMMMMAAAAMMMMMMM MNMMAAOOAAMMMMMM MNDDAGAAGADAMMMM MNADALLLOADMMMMM AAAAAAAAAAAMMMMM AAAAAAAAAAAMMMMM MAAAAAAAAAAMMMMM MNAAAAAAAAAMMMMM MNMAAAAAAAAPPPPP MNADAAAAAAAPPPPP MNADDAAAAAAPPPPM MNAAAAAAAAAPPPMM MNMMMAAAPAAPPMMM MNMMAAPPMMAPMMMM MMMMMMMMMMMMMMMM } # tile 229 (vampire mage) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMAAAMMMMMMMM MMMMAAOAAMMMMMMM MADDAGAGADAMMMMM MMADALLOADMMMMMM MAAAAMAMAAMMMMMM MMAAAACAAAMMMMMM MMMAAADAAAMMMMMM MMADAAAAAAPPPPPM MMADDAAAAAPPPPMM MMAAAAAAAAPPPMMM MMMMMAAPAAPPMMMM MMMMAAPMMAPMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 230 (Vlad the Impaler) { MMMMMMMMMMMMMMMM MMNMMAAAAMMMMMMM ADNDAAOOAADDDAMM MANDAGAAGADDAMMM MMNDALLLOADAMMMM MMNAAAAAAAAAAAAA MHHHDAAAAADDDDDA HEHEHJAAAADDDAAM LLLLLJAAAADDAAPP MLLLJAAAAADDAPPP MMNJDAAAAADAPPPP MANDDAAAAAAAPPPP MANAAAAAAAAPPPPM MMNMMAAAPAAPPPMM MMNMAAPPMMAPMMMM MMMMMMMMMMMMMMMM } # tile 231 (barrow wight) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMLLOMMMMMMMMMM MMDLDLOMMMMMMMMM MMLLLLOMMMMMMMMM MMLJLMMPMMMMMMMM MMOOOMPPMMMAAAAM MMPOOMPPMAAAAAAM MLPOOMPPMPAAAAMM MJJOOMPPMPAAAAMM MJMOMMPLMPPAAAMM MJMOMPPPPPPAAAMM MJMMMPPPPPPPAAMM MJMMLLPPPPPPAMMM MJMMMMMLLAAMMMMM MMMMMMMMMMMMMMMM } # tile 232 (wraith) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMPPPPPMMMMMMMM MMMPAAPPPMMMMMMM MMMMPAAPPMMMMMMM MMMMPAAPPMMMMMMM MMPPMPPPMPMMMMMM MOLAPPPMPPMMMMMM MMAAPPPPAPMMAAAM MMPPPPPOLPAAAAAM MMMAMPPAAAAPPAMM MMMMMPPAPPPPAMMM MMMMMMPPPPAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 233 (Nazgul) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMPPPPPMMMMMMMM MMMPAAPPPMMMMMMM MMMMPAAPPMMMMMMM MMMMPAAPPMMMMMMM MMPPMPPPMPMMMMMM MOLAPPPMPPMMMMMM MOPAPPPPAPMMAAAM MMPAPPPPAPMMAAAM MMPAMPPPLPMMAAAM MMPPMPPOLPAAAAAM MMMAAPPOAAAPPAMM MMMMMPPAPPPPAMMM MMMMMMPPPPAMMMMM MMMMMMMMMMMMMMMM } # tile 234 (xorn) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOBMOPMBPMMMMM MMMBBBBPPPPMMMMM MMMBMMMMMMMMMMMM MMMDDBBMBDDAMAMM MMMDDBBMPDDAAAAM MMMBMMMMMMMAAAAM MMMBOBMBPPMAAAAM MMMBBBMPPPMAAAAM MMMBMMMMMMMAAAMM MMMBOBBPPBPAAMMM MMMBOMBPMPPAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 235 (monkey) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMKKAMMMMMM MMMMMMKLLJAMMMMM MMMMMMKLLJAMMMMM MMMMMMMKJAMMMMMM MMMMMKKKKKJAAMMM MMMMKJKLLJJJAAMM MMMMLAKLLJALAAMM MMMMMMKJJJAAAAMM MMMMMMJAAJAAAMMM MMMMMJJAMJJAMMMM MMMMMMMMMMMMMMMM } # tile 236 (ape) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKKKJMMMMMM MMMMMJJJJJJMMMMM MMMMKCELECJJMAAM MMMMKLLLLCAJAAAA MMMKKCLACCAJJAAA MMKKKKCCCAJKJJAA MMKKAKJAAJJAJJAA MMKAAKJJJJJAAJAA MMLCMKJJJJJKCLAA MMLLMCJJAKLJLLAA MMMMMCLJACLJAAAA MMMLLLLJACLLLKAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 237 (owlbear) { MMMMMMMMMMMMMMMM MMMMKMMMMMKMMMMM MMMMCKMMMKKMMMMM MMMMCKKKKKKMMMMM MMMKOOOKOOOKMMMM MMMKOOOKOOOKAMMA MMMKOOAJAOOKAAAA MMCKCJJHJJKAKAAA MCKKKCKLKKAJJKAA MKJJJJCKKJJJJJAA MKJJJPAKJPJJJJAA MMKJJJAKJJJJJAAA MMMJJPAKJPJJAAAM MMMJAAJAJAAJAAMM MMMPJPJAJPJPAMMM MMMMMMMMMMMMMMMM } # tile 238 (yeti) { MMMMMMMMMMMMMMMM MMMMBNNNMMMMMMMM MMMBNANAPMMMMMMM MMBNNNNNNPMMMMMM MMNNNADANNMMMMMM MMNNNNNNPNMMMMMM MMNMNNBPPNPMMMMM MMNMNNNNANPMMAAM MMNNBNNNPNMAAAAM MMMMNNNNPMKAAAMM MMMMNNMNPAKKAAMM MMMMNBMNPAACKAAM MMMMNNANPAAKKJAM MMMBNNANNPAACKAM MMBNNAMMNNAMMMMM MMMMMMMMMMMMMMMM } # tile 239 (carnivorous ape) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKKKJMMMMMM MMMMMJJJJJJMMMMM MMMMKCELECJJMAAM MMMMKLLLLCAJAAAA MMMKKCAAACAJJAAA MMKKKCDDDCAKJJAA MMKKAKCCCAJAJJAA MMKAAKJAAJJAAJAA MMLCMAJJJJJKCLAA MMLLDDAJAKLJLLAA MMMDDALJACLJAAAA MMDDALLJACLLLKAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 240 (sasquatch) { MMMMMMMMMMMMMMMM MMMMCCCCCMMMMMMM MMMCGAJGAJMMMMMM MMCKKKKJJJMMMMMM MMCKKAAAKJJMMMMM MCKKKAAAKKJMMMMM MCKJKKKKKKKJMMMM MCKAJJJJJAKJMMMM MCKAJKKKJAKJMAAM MCKJAJKJACKJAAAA MCKJAJJJACKJAAAM MMJMAJAKKAJAAAAA MMMCKJAKKJAAAAAM MKCKJJACKJKJAAMM MCJJJKACKJJKAMMM MMMMMMMMMMMMMMMM } # tile 241 (kobold zombie) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMNMMMMMMMM MMMNGFBNMMMMMMMM MMMGABABMMMMMMMM MMMMGBFAMMAMMMMM MMMGBABFAMAAMMMM MMGFBBBIKAAAMAMM MMBAFBFFEAAAAAMM MMBAFBFFAAAAAAMM MMMMFBFAAAAAAMMM MMMMBABAAAAMMMMM MMMBBABBAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 242 (gnome zombie) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMGMMMMMMMMM MMMMMGFFMMMMMMMM MMMMGGFFFMMMMMMM MMMMGDFDFMMMMMMM MMMMMPFPMMMAAAMM MMMFGFPFEGAAAAMM MMGAAGFFFAGAAAMM MMMMAKNKFAAAAMMM MMMMFGAFFAAMMMMM MMMMGFAFGMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 243 (orc zombie) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMMMMMMM MMMMNOPAMMMMMMMM MMMMGPGAMMMMMMMM MMMMMPFAMMMMMMMM MMKCCAKKKAMAAMMM MBBPCKJMBBAAAMMM BBMAGGFAABBAMMMM BMMAJJPAAABAMMMM MMMMBAPPPAAAAAMM MMMBJAAEPAAAMMMM MMBPPAAAPPMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 244 (dwarf zombie) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMBMMMMMMMMM MMMMMBEEMMMMMMMM MMMMBBEEEMMMMMMM MMMMBFFFEMMMMMMM MMMMMPFPMMMAAAMM MMMBBPPPEEAAAAMM MMFBABPEAEAAAAMM MMFMEBBEFAAAAMMM MMMMEBAEEAAMMMMM MMMMBEAEBMAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 245 (elf zombie) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMGMMMMMM MMMMMMMGGFMMMMMM MMMMMMGGGGAMMMMM MMMMMMFEFEAMMMMM MMMMMMFFFFAMMMMM MMMMMMAFDAMMMMAM MMMMMMGAAGMMAAAM MMMMFFGGGFFFAAAM MMMFAAAGFAAAFAAM MMMMMAGGGFAAAAMM MMMMMMGFAFAAMAMM MMMMMKDAMFKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 246 (human zombie) { MMMMMMAAAMMMMMMM MMMMMFFGAAMMMMMM MMMMMAGAFAMMMMMM MMMMMFFGFAMMMMMM MMMMFKFMMJJMMMMM MMMMJJJFJKJMMMMM MMMFJMKJJAKJMMMM MMFKMMKFJFFJMMMM MMGMMMKKJGMMMMMM MMMMMBPMBPAAAAAM MMMMMFPAPFAAAAMM MMMMMBFABFAAAAMM MMMMMPFABPAAMMMM MMMMMBFABFAMMMMM MMMMGGAGGAMMMMMM MMMMMMMMMMMMMMMM } # tile 247 (ettin zombie) { MMMMNNMMONOPMMMM MMNNOOPNNOOPPMMM MMNFFMMNFFMMPMMM MMADFFDADFFDAMMM MMAFFFFAFFFFAMMM MMAFAAFAFAAFAAMM MMAFFFFAFFFFAAAM MMGIIIIJJJIIIGAA MGFFFIIIIIIFFFGA MGFFFFIIIIFFFFFA MFFAAFIIIIFAAFFA MFFAAIIIIIIAAFFA MFFFMIIFFIIAGFAA MMFFMGFAAGFAFFAA MMMMMGFAAGFAAAAA MMMFFFFAMGFFFFAA } # tile 248 (giant zombie) { MMMMMMJJJJAAMMMM MMMMJJJJJJJJAMMM MMMMJJFFFFJJAMMM MMMMJDDFFDDJAMMM MMMMJFFFFFFJAMMM MMMMAFFAAFFAAAMM MMMMMAFFFFJAAAAM MMGGFFJJJJFFGGAA MGFFFGGFFFFFFFCA MFFFKFFFFFFKFFFA FFFAAFFFFFFAAFFA FFAAMJJJKKJAAFFA FFAMMJJJJJKAGFAA MMMMMGFAGFFAFFAA MMMMGFFAGFFAAAAA MMMGFFAAGFFFAAAA } # tile 249 (ghoul) { MMMMMMAAAMMMMMMM MMMMMOOOAAMMMMMM MMMMMDODOAMMMMMM MMMMMOOOOAMMMMMM MMMMPPOOOPPMMMMM MMMMPPPPPPPMMMMM MMMPPMPPPAPPMMMM MMPPMMPPPOOPMMMM MMOMMMPPPOMMMMMM MMMMMPPMPPAAAAAM MMMMMPPAPPAAAAMM MMMMMPPAPPAAAAMM MMMMMPPAPPAAMMMM MMMMMPPAPPAMMMMM MMMMOOAOOAMMMMMM MMMMMMMMMMMMMMMM } # tile 250 (skeleton) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMOOOMMMMMMMMMM MMAOAOOMMMMMMMMM MMOOOOOMMMMMMMMM MMOOMOMMMMMMMMMM MMMMMMOMMMMMMMMM MMMMOOOOOMMMAAAM MMMOAMOOOAMMAAAM MMOAMOAAOMAAAAAM MMMMOAMOOOAAAMAM MMMMMMOOOAAAMAMM MMMMMOMAOMAMMMMM MMMOOOAMOAMMMMMM MMMMMMOOOMMMMMMM MMMMMMMMMMMMMMMM } # tile 251 (straw golem) { MMMMMMLJMMMMMMMM MMMMMMLJHJMMMMMM MMMMHJLJHMMMAMMM MMMMAAAAALMMMMMA MMMMDAADALMAMAAM MMMMLJHJLMMAAAAM MMMMLLHJLHHCHHLM MMMHHLJLMAJLJLMA MHHJJLLLLAAAMAAM MMJLMMLALHAAAAAA MLLMMCJLHJHAAAAA MMMMMHJLAHJHAAAM MMMMMHJAACALHAAA MMMMCJLAAJHALHAM MMMMHALAMAHAALMM MMMMMMMMMMLMMMMM } # tile 252 (paper golem) { MMMMMMMMMMMMMMMM MMMMMMMOAMMMMMMM MMMMMNNNOAMMMMMM MMMMMONNNOAMMMMM MMMMMMONNOAMMMMM MMMMMMMNOAMMMMMM MMNNOAMNOAMMMMMM MMNONOAOAONNOAMM MMOAOANNOAOOOAMM MMMMMMNNNOAAAAAM MMMMMMONOAAAAAAM MMMMMMMOOAAAAAAM MMMMMNOAAOAAAAAM MMMMMNOAMMNOAAMM MMMMOOAMMMOOAMMM MMMMMMMMMMMMMMMM } # tile 253 (rope golem) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMOOOMMMMMMM MMMMMOMMMOMMMMMM MMMMMOMMMOMMMAAM MOOMMMOMMOMMAMMA OMMOMMMLLMMOOMMA MMMOMMMLOOOMAOAM MMMMOOOOOAAAAOMM MMMMMMMOOMMAAMAM MMMMMMMLOMAAMMMA MMMMMMOMMOOAAMMA MMMMOOMMAMMOMAMM MMMOMMAAMMMOMAMM MMMOMAMMMMOAAMMM MMMMOAMMMMMMMMMM } # tile 254 (gold golem) { MMMMMMMMMMMMMMMM MMMMMMHNHMMMMMMM MMMMMMDNDMMMNMMM MMMMMMHNHMMMJCMM MMMMMMHNHMMMNCMM MMMHHHAAAAHANCMM MMHNJNHNHNJNACMA MMHHHHHHHHHHHAMA MNCACCCCCCCCAMMA MHHMAAAAAAAAAMAA MNHMANCMAHNCMAAA MNJMAHCMAHHCMAAA MMHMANCMAHNCMAAA MMMMHJCMAHJCMAAM HMMMHNCMAHNCMAMH MMHMMMMMMMMMMMMM } # tile 255 (leather golem) { MMMMMMKKKKMMMMMM MMMMMKHKHJMMMMMM MMMMKAKKJJAMMMMM MMMKKAJJJJAJMMMM MMKKJJAJAAKJJMMM MKKKJJAAKKKJJJMM MMKKJJJAKKJJJJMM MMMKKJJJAMAAAMAM MMMMAAAAMKJAAAAM MMMMKJAAAKKAAAAA MMMKJJAAMKJJAAAM MMMKKJAMMKKJAAAM MMKKJJJAKKJJJAAM MMKKKJJAKKKJJAMM MMMKJJAMMKJJAMMM MMMMKAMMMMKAMMMM } # tile 256 (wood golem) { MMMMMMMMMMMMMMMM MMMMMMKCKJMMMMMM MMMMMMHCHJMMCMMM MMMMMMKCKJMMCKMM MMMMMMKCKJMMCKJM MMMKKKAAAAKACKJM MMKCCCCCCCCCAKJA MMKKKKKKKKKKKAJA MCJAJJJJJJJJAMMA MCKJAAAAAAAAAMAA MCKJACKJAKCKJAAA MCKJACKJAKCKJAAA MMKJACKJAKCKJAAA MMMMKCKJAKCKJAAM MMMMKCKJAKCKJAMM MMMMMMMMMMMMMMMM } # tile 257 (flesh golem) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMDMMDDCMMMMMMM MMMMMDLDDLMMMMMM MMDDMMLLLLCMDMMM MMMCDLMLLLLADLMM MMCLDLAMCLLAMLLM MMLLLAAMLLCAMMLM MCLLAAMCLLAAMMCA MLLAMMCLLALLAAAA MMLAMCLCAALCAAAA MMMAMMLLCACLCAAA MMMMLLALLAALLAAA MMCLLLAAAADLLAMM MMLLDDDMMDDDDDMM MMMMMMMMMMMMMMMM } # tile 258 (clay golem) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMLCCCCKMMMMMM MMMLKKKKKKKMMMMM MMMCKAKKAKKMMMMM MMMCKAKKAKKMMMMM MLCKKKKKKKKLCMMM CKKJKKKKKKCKKJMM KKKJKKJJKKJKKJAA MJJAKKJAKKAJJAAA MMAKKKJAKKKAAAAA MMCKKKKKKKKKAAAA MMCKKKAACKKKAAMM MMCKKKAMCKKKAAMM MMMMMMMMMMMMMMMM } # tile 259 (stone golem) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMBBBPPMMMMMMM MMMBBPPPPPMMMMMM MMMBHAPHAPMMMMMM MMMPPPPPPPMMMMMM MBBPPPPPPMBPAMMM BPPPPMMMMPPPPAAM BPPMBPPPPMPPPAAA MPPMBPMPPMPPPAAA MMMBPPMPPPAAAAAA MMBPPPAPPPAAAAAM MMPPPPAPPPPAAAMM MMMPPAAMPPPAMMMM MMMMMMMMMMMMMMMM } # tile 260 (glass golem) { MMMMMMMMMMMMMMMM MMMMMBBBBBBAMMMM MMMMMBPNPPPAMMMM MMMMMBNPPPNAMMMM MMMMMNPPPNPAMMMM MMMMMBPPNPPAMMMM MMMMMMMBAMMMBAMM MBNBBABPBAMBPNAM MNPPNABPNBBANPBA MMMMMBPNPPPAABAA MMMMMBNPPPAAAAAA MMMMMMBPPNAAAAAA MMMMBNABNABPAAAM MMMBNPAMMMBNAAAM MMBNPAMMMMNPAAMM MMMBAMMMMMBPAMMM } # tile 261 (iron golem) { MMMMMMMMMMMMMMMM MMMMMMPBPMMMMMMM MMMMMMHBHMMMBMMM MMMMMMPBPMMMJPMM MMMMMMPBPMMMBPMM MMMPPPAAAAPABPMM MMPBJBBBBBJBAPMA MMPPPPPPPPPPPAMA MBMAMMMMMMMMAMMA MBPMAAAAAAAAAMAA MBPMABPMAPBPMAAA MBJMABPMAPBPMAAA MMPMABPMAPBPMAAA MMMMPJPMAPJPMAAM MMMMPBPMAPBPMAMM MMMMMMMMMMMMMMMM } # tile 262 (human) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMJJAMMMMMM MMMMMMJJJJAMMMMM MMMMMMELELAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCLAALCMAAAM MMMMCLLLLLLCAAAM MMMMLACLLCALAAAM MMMMLAJJKJALAAAM MMMMMMJJJKAAAAMM MMMMMMJJAJAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 263 (wererat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMJJAMMMMMM MMMMMMJJJJAMMMMM MMMMMMGJGJAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCLAALCMAAAM MMMMCLLLLLLCAAAM MMMMLACLLCALAAAM MMMMLAJJKJALAAAM MMMMMMJJJKAAAAMM MMMMMMJJAJAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 264 (werejackal) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMJJAMMMMMM MMMMMMJJJJAMMMMM MMMMMMIPIPAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCLAALCMAAAM MMMMCLLLLLLCAAAM MMMMLACLLCALAAAM MMMMLAJJKJALAAAM MMMMMMJJJKAAAAMM MMMMMMJJAJAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 265 (werewolf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJJAMMMMMMM MMMMMJJJJAMMMMMM MMMMMNJNJAMMMMMM MMMMMLLLLAMMMMMM MMMMMALLAMMMMMMM MMMMCLAALCMAAAMM MMMCLLLLLLCAAAMM MMMLACLLCALAAAMM MMMLAJJKJALAAAMM MMMMMJJJKAAAAMMM MMMMMJJAJAAMAMMM MMMMKLAMLKAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 266 (elf) { MMMMMMMMMMMMMMMM MMMMMMMMMGMMMMMM MMMMMMMGGFMMMMMM MMMMMMGGGGAMMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMAM MMMMMMGAAGMMAAAM MMMMMLGGGFLAAAAM MMMMLAAGFAALAAAM MMMMLAGGGFALAAMM MMMMMMGFAFAAMAMM MMMMMMGFAFAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 267 (Woodland-elf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMKMMMMMM MMMMMMMKKJMMMMMM MMMMMMKKKKAMMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMAM MMMMMMKAAKMMAAAM MMMMMLKKKJLAAAAM MMMMLAPPJAALAAAM MMKKLKKKKJALAAMM MMMMMMPPAJAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 268 (Green-elf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMGMMMMMM MMMMMMMGGFMMMMMM MMMMMMGGGGAMMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMAM MMMMMMGAAGMMAAAM MMMMMLGGGFLAAAAM MMMMLAAGFAALAAAM MMMMLAGGGFALAAMM MMMMMMGFAFAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 269 (Grey-elf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMPMMMMMM MMMMMMMPPMMMMMMM MMMMMMPPPPAMMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMAM MMMMMMPAAPMMAAAM MMMMMLPPPMLAAAAM MMMMLAAPMAALAAAM MMMMLAPPPMALAAMM MMMMMMPMAMAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 270 (elf-lord) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMIIMMMMMM MMMMMMMHGFMMMMMM MMMMMMHGGGAMMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMAM MMMMMMHAAHMMAAAM MMMMMLHHHFLAAAAM MMMMLAAIIAALAAAM MMMMLAHGGFALAAMM MMMMMMHFAFAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 271 (Elvenking) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMHMMHMMMMMM MMMMMMHCHHMMMMMM MMMMMMHHHHAMMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMIALLAIMMMAM MMMMIIIAAIDIAAAM MMMMMLIIGDLAAAAA MMMMLADIFDALAAAA MMMMLAIIGDALAAAM MMMMMIIFAFDAAAMM MMMIIKLAILKDIMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 272 (doppelganger) { MMMMMMMMMMMMMMMM MMMMMMCCCCMMIMMM MMIMMCDMMMCMMMMM MMMMCDMHHAMCMMMM MMMCDMHHHHAMCMIM MMMCDMLFLFAMDCMM MIMCDMLLLLAMDCMM MMMCDMALLAMDCMMM MMCDMLLAALLMACAM MCDMLLLLLLLLADCM MCDMLALLLLALADCM MCDMLAJJKJALADCM MMCDMMLJJLAAACAM MMMCDMLLALAACAMM MMCDMLLAALLADCMM MMMMMMMMMMMMMMMM } # tile 273 (nurse) { MMMMMMMMMMMMMMMM MMMMMMMNOMMMMMMM MMMMMMNDDOMMMMMM MMMMMMNNOOAMMMMM MMMMMDBLBLDMMMMM MMMMMCLLLLDCMMMM MMMMMDALLACDMMMM MMMMMCNAAODCAAAM MMMMMNNNOOLAAAAM MMMMLANNDOALAAAM MMMMLANNOOALAAAM MMMMMMNNOOAAAAMM MMMMMMNNAOAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 274 (shopkeeper) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMAAAAMMMMMM MMMMMAAAAAAMMMMM MMMMMMJLJLMMMMMM MMMMMMLLLLMMMMMM MMMMMMALLAMMMMMM MMMMMEBAABEAMAAM MMMMEBBBBBBEAAAM MMMMBAEBBEABAAAM MMMMLAGFFFALAAAM MMMMMMGFAFAAAAMM MMMMMMGFAFAAMAMM MMMMMJJAMJJAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 275 (guard) { MMMMMMMMMMMMMMMM MMMMMBBPPPAAMMMM MMMMBNPPPPPPAMMM MMMMBPPBPPPPAMMM MMMMBAABPAAPAMMM MMMMBCLBPCLPAMMM MMMMAKCPPCJAAAMM MMMMBKJJJJAPAAAA MMMBPKJAAJAPPAAA MMBPPKJJJJAPPPAA MMPPABKJJAPPAPPA MMPPABPKAPPPAPPA MMLCMBPPPPPPCLAA MMLLMBPPABPPLLAA MMMMMBPPABPPAAAA MMMMBPPPMBPPPAAA } # tile 276 (prisoner) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMNOAMMMMMM MMMMMMMLLAMMMMMM MMMMMMMLLAMMMMMM MMMMMMMNOAMMMMMM MMMMMMNOONAMMMMM MMMMMNOOOONAMMMM MMMMNANOOOANAAMM MMMMPANOOOAPAAAM MMMMLANOOOALAAAM MMMMMMNOOOAAAAMM MMMMMMNAANAAAMMM MMMMMMPAAPAAMMMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM } # tile 277 (Oracle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMNNMMMMMMM LLLMMMGLLGMMMLLL MMLMMNLLLLNMMLMM MMMLMNLAALNMLMMM MMMMLNLLLLNLMMMM MMMMMLNLLNLMMAAM MMMMMNBBEENMAAAA MMMMMMBBEEAAAAAA MLLAMMBBBEAAALLM MLLLLBBBEBELLLLA MMLLCLBLLELLCLAA MMMCLLLLLLLCLAAM MMMMLELLLLELAAMM MMMMMMMMMMMMMMMM } # tile 278 (aligned priest) { MMMMMMMMMMMMMMMM INIMMMMMMMMMMMMM IIIMMKCCKMMMMMMM MJMMKCCCCKMMMMMM MJMMCAAKCCMMMMMM MLCMCAAACCMMMMMM CLLCMCAACJKCMMMM CJLACCCCJKCCCMMM MJAACCJJCKCCCKMM MJKCCCJCCJCCKMAA MJMMCCJCCLJCAAAA MJMMCCJCLLCAAAAM MJMMKCJCCCJAAAAM MJMACCJCCCJAAAMM MJACCCJJCCCAAMMM MMMMMMMMMMMMMMMM } # tile 279 (high priest) { MINIMMMMMMMMMMMM IIIIIMKCCKMMMMMM MIHIMKCAACKMMMMM MMHMMCGAGACMMMMM MMLCMCAAAACMMMMM MCLLCMCAACJCKMMM MCHLACCCCJCCCKMM MMHAACCJJCCCCCKM MMHCCCCJCCJCCCMA MMHMMCCJCCLJCAAA MMHMMCCJCLLCAAAA MMHMMKCJCCCJAAAA MMHMMKCJCCCJAAAA MMHMACCJCCCJAAAM MMHACCCJJCCCAAMM MMMMMMMMMMMMMMMM } # tile 280 (soldier) { MMMMMJMMMMMMMMMM MMMMMJAAAMMMMMMM MMMMMALLLAMMMMMM MMMMMLLLLCMMMMMM MMMMMJLLCMMMMMMM MMMMMJFMMFMMMMMM MMMMFJFFFFFMMAMM MMMMFJFFFAFMAMMM MMMMFLFFFFFAAAMM MMMMFJFFAAAAAAAM MMMMMLFAFFAAAAMM MMMMMFFAFMAAAAMM MMMMMMFAFMAAMMMM MMMMMFFAFFAMMMMM MMMMMJJMJJMMMMMM MMMMMMMMMMMMMMMM } # tile 281 (sergeant) { MMMMMJMMMMMMMMMM MMMMMJFFFMMMMMMM MMMMFFFFFFMMMMMM MMMMMLLLLCMMMMMM MMMMMJLLCMMMMMMM MMMMMJFMMGMMMMMM MMMMFJFFFFFMMAMM MMMMFJFFFAFMAMMM MMMMFLFFFFFAAAMM MMMMFJFFAAAAAAAM MMMMMLFAFFAAAAMM MMMMMFFAFMAAAAMM MMMMMMFAFMAAMMMM MMMMMFFAFFAMMMMM MMMMMAAMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 282 (lieutenant) { MMMMMMMMMMMMMMMM MMMMMMMFFFMMMMMM MMMMMFFFFFFMMMMM MMMMMMLLLLMMMMMM MMMMMMMLLCAMMMMM MMMMMGFMFGAMMMMM MMMMFFFFFFFFMMMM MMMMFAFFFFAFAAAM MMMMFAFFFFAFAAAA MMMMFAFFFFAFAAAM MMMMLFFAFFJLJAMM MMMMMFFAFFJJJAMM MMMMMMFAFMAAMMMM MMMMMFFAFFAMMMMM MMMMMAAMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 283 (captain) { MMMMMMMMMMMMMMMM MMMMMMFHHFMMMMMM MMMMMFFFFFFMMMMM MMMMMMLLLLMMMMMM MMMMMMMLLCAMMMMM MMMMMHFMFHFMMMMM MMMMFFFFFFFFAAMM MMMMFAFFIFAFAAAA MMMMFAFFFFAFAAAM MMMMFAFFFFAFAAAM MMMMLFFAFFJLJAMM MMMMMFFAFFJJJAMM MMMMMMFAFMJJJAMM MMMMMFFAFFJJJAMM MMMMMAAMAAAAAMMM MMMMMMMMMMMMMMMM } # tile 284 (watchman) { MMMMMMMMMMMMMMMM MMMMMMPPPMMMMMMM MMMMPPPPPPMMMMMM MMMMMLLLLCMMMMMM MMMMMMLLCMMMMMMM MMMMMPPMMPMMMMMM MMMMPPPPPPPMMMMM MMMMPAPPHAPPAMMM MMMMPAPPPANNAAAM MMMMPJPPAPNNAAAM MMMMJLPAPPAAAAMM MMMMMJPAPMAAAAMM MMMMMMPAPMAAMMMM MMMMMPPAPPAMMMMM MMMMJJJMJJJMMMMM MMMMMMMMMMMMMMMM } # tile 285 (watch captain) { MMMMMMPPPMMMMMMM MMMMMPHHHPMMMMMM MMMMPPPPPPPMMMMM MMMMMLLLLCMMMMMM MMMMMMLLCMMMMMMM MMMMMHPMMHMMMMMM MMMMPPPPPPPMMMMM MMMMPAPPHAPPAMMM MMMMPAPPPANNAAAM MMMMPJPPAPNNAAAM MMMMJLPAPPAAAAMM MMMMMJPAPMAAAAMM MMMMMJPAPMAAMMMM MMMMMPPAPPAMMMMM MMMMJJJMJJJMMMMM MMMMMMMMMMMMMMMM } # tile 286 (Medusa) { MMMMMMMMMMMMMMMM MMGAMMMGAMMMMMMM MMMFAMFAMMGAMMMM MMMMFJFFFFMMMMMM MMFAFLLFAMMMMAMM MGAFLLLLAMMAMMAM MMMMJLLKAMAMAMAM MMMKBLLBKAAAAAMM MMKIIBBIIIAAAMAM MMIIIKKILLIAAAMM MMKIILLIALIAAMMM MMMKIALKAAIAAMMM MMMIKAAKIIAAAMMM MMMIIKKIIIAAMMMM MMIIKIKIKIAMMMMM MMMMMMMMMMMMMMMM } # tile 287 (Wizard of Yendor) { MEEEMMMMMMMEEEMM EFFAEMMEMMEAFFEM EAAAEMEEEMEAAAEM EAAAEEEAEEEAAAEM EEAAEEDADEEAAEEM MEEEEAAAAAEEEEMM MMEEEEAAAEEEEMMM MMEEEEEEEEEEMMMM MMMEEEEEEEEMMMMM MMMEEEEEEEEMMMMA MMMMEEEEEEMMMAAA MMMMEEEEEEAAAAAA MMMEEEEEEEEAAAAA MMEEEEEEEEEAAAAA MEEEEEEEEEEEAAAM EEEEEEEEEEEEEEAM } # tile 288 (Croesus) { MMMMHMMHMMHMMMMM MMMMHCHEHCHMMMMM MMMMHHHHHHHMMMMM MMMMALLLLLAMMMMM MMMMLLALALLMMMMM MMMMMLLLLLMMMMMM MMMMHLLDLLHMMMMM MMMHIALLLAIHMAMA MMMHIHAAAHIHAAAA MMIIIEHHHIIIIAAA MMIIIIEHIIIIIAAM MMILLIHHHILLIAAA MMMLIIKHIIILAAAA MMGIIIKJIIIIGAAM MGIIIKJJKKIIIGGM MMMMMMMMMMMMMMMM } # tile 289 (Charon) { MMMMMMMMMMMMMMMM MMMMMMMJMMMMMMMM MMMMMMJJJMMMMMMM MMMMJJJAJJJMMMMM MMMMJJDADJJMMMMM MMMJJAAAAAJJMMMM MMMJJJAAAJJJMMMM MMJJJJJJJJJJMMMM MJJJJJJJJJJJJMMM JJJJJJJJJJJJJJMA MOOMJJJJJJMOOAAA MMMMJJJJJJAAAAAA MMMJJJJJJJJAAAAA MMJJJJJJJJJAAAAA MJJJJJJJJJJJAAAM JJJJJJJJJJJJJJAM } # tile 290 (ghost) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNNNMMMMMMMMMM MMNANANNMMMMMMMM MNNNNNNNNNMMMMMM MNNPAAPNNNNNMMMM MNNAAAANNNOONOMM MNNAAAANONNNPNNO MNNPAAPNONNOOOPM MNNNNNNONOPNPPOM MNNONNOPNNOPOOPM MNOPNNOOOPPOOPMM MOOOPOPPOPPPMPPM MPPMPPOPPPMMMPMM MOMMMPMMMMPMMMMM MMMMMMMMPMMMMMMM } # tile 291 (shade) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMAAAAAAAM MMMMAAAAAAAAMMMM MMAAAAAAAAAAAAMM AAAAAAAAAAAAAAAM MMAAAAAAAAAAAAAA MAAAAAAAAAAAAAMM AAAAMAAAAJAMMMMM MMMMMMMMMMMMMMMM } # tile 292 (water demon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMEEMMMMMEEMMMMM MEMEEMMMEEMEMMMM MMMMEEEEEMMMMMMM MMMMEBEBEMMAMMMM MMMEEEEEEEAAAAMM MMEEEMMMEEEAAMAM MMEEEEEEEEEAAAMM MMEEAEEEAEEAAAMM MMMAAEEEAAAAAMMM MMMMEEAEEAAMMMMM MMMMEEAEEAMMMMMM MMMMMMMMMMMMMMMM } # tile 293 (horned devil) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMOMMMMMMMOMMMMM MMOOMMMMMOOMMMMM MMMLOCDCOLMMMMMM MMMCDDDDDCMMMMMM MMMDAADAADAMMDMM MMMDDDDDDDAMDMMM MMCCDDFDDCCADMAM MMCDKDDDKCDADAMM MMCDAKKKACDAAAAM MMDDADDDADDAAAAM MMMMCDDDKAAAAAMM MMMCDDADDKAAMMMM MMCDDAAMDDKMMMMM MMMMMMMMMMMMMMMM } # tile 294 (succubus) { DDMOHHDMMMMMMMMM DDOHHDGDMMMMMMMM DDOHDDDDDMMMMMMM DDHHDDDAMMMMMMMM DHHHDJADDDDMMMMM MHHJJDDDJDDDMMMM OHDDCDCDDJDDMMMM HHHCDDCDLJMDDMMM HHHCDLJJJAADDAMM HHHDJJDDDAADAAMM HHHHDDAADAAAAMMM HHHHMDKJDDAAMMMM HMHMMDDAADDAAMMM MMHMMDDAAMDAAMMM MMMMDDAAMMDDAAMM MMMDDJAMMMDDDAMM } # tile 295 (incubus) { DDMOHHDMMMMMMMMM DDOHHDGDMMMMMMMM DDOHDDDDDMMMMMMM DDHHDDDAMMMMMMMM DDDHDJADDDDMMMMM DDDJDDDDDDDDMMMM MDDDDDCDDMDDDMMM MDDCDDDKKMMDDMMM MMDDKKDDDAADDAMM MMMDDDDDDAAAAAMM MMMMDDDDDDDDDAMM MMMMDDJDJJAAAAAA MMMMJDJJADKAAMMM MMMMDDKAADDKAMMM MMMDDKAAMMDDAAMM MMDDKAAMMMDDDAMM } # tile 296 (erinys) { MMGAMMMGAMMMMMMM MMMFAMFAMMGAMMMM MMMMFJFFFFMMMMMM MMFAFLLFAMMMMMMM MGAFDLDLAMMAMAMM MMMMLLLEAMAMAMAM MMMEBLLBEAAAAMAM MMEBBBBBBBAAAAMM MMBBBEBBLLBAAMAM MMEBBLLBALBAAAMM MMMEBALBAABAAMMM MMMBEAABBBAAAMMM MMMBBBBBBBAAAMMM MMMBBBBBBBAAMMMM MMBBEBEBEBAMMMMM MMMMMMMMMMMMMMMM } # tile 297 (barbed devil) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMOMMMMMMMOMMMMM MMOOMMMMMOOMMMMM MOMLOCDCOLMOMMMM MMMCDDDDDCMMMMDD MMMDAADAADAMMDMD MMMDDDDDDDAMDMMM MMCCDDFDDCCADMAM MMCDKDDDKCDADAMM MCMDAKKKACDKAAAM MMDDADDDADDAAAAM MMMMCDDDKAAAAAMM MKMCDDADDKAAKMMM MCCDDAAMDDKKMMMM MMMMMMMMMMMMMMMM } # tile 298 (marilith) { MDMMHHHMMMMMDMMM DDMHHHHHAMMMDDMM MDCHDDDHHAADMMAM MMHDBDBDHDDAAAAM MCHKDDDKHAAADDMM CDDDKKKDHDDDDFFM DMMCDDCDKAAFFFAA DMKDDKDDDDDDFAAM DMDKDDKDKAFDFAAM MMDMGDDFAAFDFFAA MDMGGFFFAAAFFFFA MMMGFFFFFAAAFFFA MMFGFFFFFFAFFFFA MMFGFFFFFFFFFFAM MMFGFFFFFFFFFAMM MMMMGFFFFFFAAMMM } # tile 299 (vrock) { MMMMMMMMMMMMMMMM MMMMMMOPPMOMMMMM MMMMMMPPPPMMMMMM MMMMMCPPDPMMMMMM MMMMCCCPPPMMMMMM MMMMCCPPPPMMMMMM MMMMCMMPPAMMMMMM MMMMMDDAADDMAAAM MMMMDDDDDDDDAAAM MMMMDADDDDADAAAM MMMMDADDDDADAAAM MMMMDADDDDADAAAM MMMMMMDAADAAAAMM MMMMMMDAADAAMAMM MMMMMDDAMDDAMMMM MMMMMMMMMMMMMMMM } # tile 300 (hezrou) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMGGGFFMMMMMMM MMNGFFNNFFFMMMMM MDFFFDDNFFMFMMMM MGFFFDNFFMFFFAAM MAFAFFFFFFFFFFAA MGFFFFMFFFMFGFAA MGAAAFFMMLFGFFAA MMFFFFMFFLFGFFFA MMLLAMFLLLJJGMFA MLLAFFLLFJJGFFFA MMLAFLLLAAGFMFAA MMMMMLMLAGFFFFAA MMMMMMMMMMMFFFAM MMMMMMMMMMMMMMMM } # tile 301 (bone devil) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMOMMMMMMMOMMMMM MMOOMMMMMOOMMOMM MMMLNLOLOLMMMMOM MMMLOOOOOLMMMMOM MMMNAAOAAOAMMOMM MMMNOOOOOOAMOMMM MMNOOOFOOOOAOMAM MMOOKNOOKOOALAMM MMOOANOOAOOAKAAM MMLLANOOALLAAAAM MMMMNOOOLAAAAAMM MMMNOOAOOLAAMMMM MMNOOAAMOOLMMMMM MMMMMMMMMMMMMMMM } # tile 302 (ice devil) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMNMMMMMMMNMMMMM MMNNMMMMMNNMMMMM MMMPBPNPNPMMBNBM MMMPNNNNNPMMNMNM MMMBAANAANAMMMNM MMMBNNNNNNAMBNBM MMBNNNFNNNNANMAM MMNNKBNNKNNABAMM MMNNABNNANNAMAAM MMPPABNNAPPAAAAM MMMMBNNNPAAAAAMM MMMBNNANNPAAMMMM MMBNNAAMNNPMMMMM MMMMMMMMMMMMMMMM } # tile 303 (nalfeshnee) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMBBMMMBBMMM MMKKKKKBBMBBMMMM MKADKADKKKBMMMMM MKKKKKKKDKKMMMMM MOKDKOKKDDKDMMMM MOKDKOKKKDKDDMMM MKAAAKKDKAKKDMMM MMKKKDDLAKKKDMAM MMMKKMKKKKKDDAMM MMMMLMMKDAKDAAMM MMMMMMLLAAKDAMMM MMMMMMMMMLLAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 304 (pit fiend) { MMMMMMMMMMMMMMMM MKMOMMMMMMMOMKMM MKMOOMMMMMOOMKJM KJJMLOCDCOLMKJJM KJJJKDDDDDKKJJJM KJJCKDNDNDKCJJJA JJCCKDDDDDJCCJJA JJCCCKDIDJDCCJJA JACCDDKJJDDCDAJA JACCKDDDDDKCDAJA MMMCDKDDDKCDDAAA MMMMDKDDDKCDAAAA MMMMMCDDDKAAAAMM MMMMCDDADDKAMMMM MMMCDDAAMDDKMMMM MMMMMMMMMMMMMMMM } # tile 305 (balrog) { MMMMMMMMMMMMMMMM MKMMOMMMMMOMMKMM MKJMOMMMMMOMKJMM KJJLOOCDCOOLJJJM JJJDDDDDDDDDDKJM JCCDDDNDNDDDCCJA CCDKDDDDDDDJCCCA CDDKKKDIDJJDCCDA CDDKDDKJJDDDCDDA CCDKDDDDDDDKCDDA JCCDKKDDDKKCDDDA JJCDKKDDDKKCDDJA JJMMCCDDDKKAAJJA JMMCDDDADDDKAAJA MMCDDDAAMDDDKMAA MMMMMMMMMMMMMMMM } # tile 306 (Juiblex) { MMMMMMMMMMMMMMMM DDMMMMMMMMMDDMMM NDCMKKKKJMCNDMMM MCCKCCCKKCCAAMMM MMKCCCCKCCJAAMMM MMKCCCCCKMJJAAMM MMKCCFCCKMMJAAMM MMFKCFCCKKMJAAAM MFKKFCCKFKMMJAAM MFKCFCCFKFKMJAAM MFCFCCKFCFKMJAAM FKCFCFCFCKKMJAAM CKFCCFCCKKFKJJAM CCKKCFCKFFKKKKAM MCCCCCCCCCCCKAMM MMMMMMMMMMMMMMMM } # tile 307 (Yeenoghu) { MMMMBMHHPMMMMMMM MMMMBPPPPMMMMMMM MMMBPLCPPHMMMMMM MKBPPCCPPHMMMMMM MPPPPPPPMHMMMMMM MPPMMMPMPHMMMMMM MMMMBPPPPPAAAMMM MMBPPPPPPPPAAAAM MBPMPPPPPAPPAAAA MBMMMBPPMAAPAAAA MBMMMBPPMAAPAAAM MMMMMBPPAAAAAMAM MMMMBPMPPAAMMMAM MMMBPMAAPPAMMAMM MMMBPAAMPPAMMMMM MMMMMMMMMMMMMMMM } # tile 308 (Orcus) { MMMMMMMMMMMMMMMM MKMMOMMMMMOMMKMM KJJOMMBBBMMOMKJM KJJLOBPPPPOLKJJM JKJJMPGPGPMJJKJA JJKJKPPPPPJJKJJJ JBPPBMBPPABBPPJJ PJJPPMBPPAPPJJPA PJBPPPMAAPPPPJPA MJBPMPPPPMPMPJAA MJBPPPPMPPPPPJAA MMPPPMPPPMPPPAAA MMMPMPPPPPPPMPMA MMMBPPPAPPPPAAPA MMMOOPPAOOPPAGAM MMMMMMMMMMMMMMMM } # tile 309 (Geryon) { MKMMMMMMMMMMMKMM MKMMMMJJJMMMMKJM KJJMMJJJJJMMKJJM KJJJKLLLLLKKJJJM KJJJKLBLBLKJJJJA JJJJKLLLLLJJJJJA JJALLKLLLJLLAJJA JAMLLLKJJLLLAAJA MMMLJLLLLLKLAAAA MMMLCKLLLKCLAFGF MMMLLGLLFALLFFFA MMMMMGFFFAAAFFAA MMMMGGGGFFAAFFAA MMMMGFFFFFAAFGFA MMMMFGGGFFFFFFFA MMMMMFFFFFFFFFAM } # tile 310 (Dispater) { MMMMMMMMMMMMMMMM MMMMMMOJJOMMMMMM MMMMMMJJJJAMMMMM MMMMMMBLBLAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCKAAKKMAAAM MMMMCKKKKKKKAAAM MMMMKACKKJAKAAAM MMMMKACKKJAKAAJA MMMMKACKKJAKAAJA MMMMLACKKJJLAJAM MMMMMMCKAJAJJAMM MMMMMMCKAPAAAAMM MMMMMPPAMPPAMMMM MMMMMMMMMMMMMMMM } # tile 311 (Baalzebub) { MMMMMMFMMMFMMMMM MMMMMMMFMFMMMMMM MMMMMMBFFFBMMMMM MMMMMBPPFBPPMMMM MMMMMPPPFPPPMMMM MMMMMMPPFPPMMMMM MMMMMCAFFFAKMMMM MMMMCKKAFAKKKAAM MMMMCAKJFAKAKAAM MMMMFACJDAJAFAAM MMMMFACKJJJAFAAM MMMMFACKKKJAFAAM MMMMMMCKKKJAAAMM MMMMMMCKAKJAMAMM MMMMMFFAMMFFMMMM MMMMMMMMMMMMMMMM } # tile 312 (Asmodeus) { MMMMMMMMMMMMMMMM MMMMMMOJJOMMMMMM MMMMMMJJJJAMMMMM MMMMMMBLBLAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCKAAKKMAAAM MMMMCKKKKKKKAAAM MMMKKCKKKKJKKAAM MMMKKAKKKJAKKAJA MMMKAMCKKJAAKAJA MMMLAMCKKJJALJAM MMMMMMCKAJAJJAMM MMMMMMCKAPAAAAMM MMMMMPPAMPPAMMMM MMMMMMMMMMMMMMMM } # tile 313 (Demogorgon) { MMMKKKMMKKKMMMMM MMKBKBKMBKBKMMMM MMKDKKKMKKDKMMMM MMDKKFAMGKKDMMMM MMMMGFAAGFAAAMMM MMMGFFFJFFFAMAAA MMGFAGFFFAFFAAAA MGJFAGJFJAFFFAAM MGFAAGFFFAAFJAMM MGJAMGFJFAAFFAAM MGFAMGFFFAMFJAAM MGJAMGJFJAMFFAAM MGFAGFAAFFAFFAMM MMGAGJAAJFAFAAMM MMGAGFAFFFAFAMMM MMMMMMMMMMMMMMMM } # tile 314 (Death) { MBBBBMMMMJJJMMMM MBPPPPMJJJJMMMMM MCMMMMJJJJJMMMMM MCMMMMJAAAJMMMMM MCMMMJADADAJMAAA OOJMMJAAAAAJAAAM OOOJJJAAAAAJJJAM OOJJJJAAAAJOOJJA MCJJJJAAAJOOOOJA MCMJJAAAAJAOAAJA MCMMJAAAAJAOAAJA MCMMJAAAAAJOAJAA MCMMJAAAAAJJJAAA MCMJAAAAAAAJJAAM MCJJAAAAAAAAJJAM ACJAAAAAAAAAAAJM } # tile 315 (Pestilence) { FMMMMMMMMJJJMMMM MMFMMMMJJJJMMMMM BMMMFMJJJJJMMMMM MMMBMMJAAAJMMMMM MFMMMJADADAJMMMM MMMFMJAAAAAJMAAM MBMMJFAAAAFJAAMM MMMFJJAFABJJAAMM MMFMJFFBAJJJAAAM MMMMFAFFJJJJAAAM MMMMJABAJJJJAAAM MMMFJFFJJJJJJAAM MMMJJBFJJJJJJAAM MMMJAABFBJJJJAAM MMJJFBFAFFAJJJAM MJJAAFAFAAAAAAJM } # tile 316 (Famine) { MMMMMMMMMJJJMMMM MMMMMMMJJJMMMMMM KMMMMMJJJJJMMMMM KMMMMMJAAAJMMMMM KMMMMJADADAJMMMM KMMMMJAAAAAJMMMA KMMMMMJAAAJJMMAA OOJJJJJJAAJAJMAA KMMMJJJAAJJAJAAA KMMMMMJAJJJOJAAM KMMMMMJAOOOAAAMM KMMMMMJAJJAAAMMM KMMMMMJAJJAAMMMM KMMMMMJAAJAAMMMM KMMMJJAAAJJAAMMM KMMJJAAAAAJJJAMM } # tile 317 (mail daemon) { MMMOPMBEEEMPOMMM MMMOOEBEEEEOODMM MMDLOBEEEEOOLDDM MDDDLDDDDDDLDDDM MCCDDDNDDNDDDCCM CCDKDDDDDDDDJCCC CDDKKDDIIDDJJCCD CDDKMKDAADJJECDD CCDKEEKKKJEEKCDD MCCDKMEEEEMMCDDD MCCDAEMEENNNCDDM MDDDAEEEENDNDDDM MMMMBBEEENNNNNMM MMMBEEEAANNNNNAM MMCDDDAAAMDDDKMM MMMMMMMMMMMMMMMM } # tile 318 (djinni) { MLLMMNNNMMLLMMMM MMLMMNGNAMLMMMMM MMLAALLLAALAMMMM MMLAAKKKAALAMMMM MMMLCKKKCLAMMMMM MMMMLCKCLAMMMMMM MMMMLICLIAMMAMMM MMMMIIIIEAMAAMMA MMMMEIEEIAMAAAAA MMMMIEFEAAAAAAAA MMMMMDEAIAAAAAMM MMMMMIGIFAAAAMMM MMMMMMMFEDAAAMMM MMMMMMMIMGEAMAMM MMMMMMMMMIFEDMMM MMMMMMMMMMMMMMMM } # tile 319 (sandestin) { MMMMMCCCCCMMIMMM MIMMCDMMMMCMMMMM MMMCDMDDDMMCMMIM MMCDMDDDDDMMCMMM MMCDMDNDNDAMDCMM IMCDMDDDDDAMDCMM MMCDMADDDAMDCMMA MCDMDDAAADDMDCAA CDMDDDDDDDDDADCA CDMDADDDDDADADCA CDMDADDDDDADADCA CDMDADDDDDADADCM MCDMMDDJDDAADCAM MMCDMDDADDADCAMM MCDMDDAADDDADCMM MMMMMMMMMMMMMMMM } # tile 320 (jellyfish) { MMMMMMMMMMMMMMMM MMMMMPBPAMMMMMMM MMMPBBBPBAMMMMMM MMBBNNBPPBAAMMMM MBBNNPPPBBPAAMMM PBBBPPPBPBBAAAMM BBBPBPPPPPBPAAAM BBPBPPPPPPPBAAAM PBPPBPPPPEPEEEMM MPBBPPPEPEPPEEMM MPEPBBEEPEEPEEMM MPEEEPEEPEEPEMMM MMPEEPEMMPEMPMMM MMPMEPMEEPMMPMMM MMPEEMPMEMMEMMMM MPMMEMPMMEMMMMMM } # tile 321 (piranha) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMOPPMMMMMMMMM MMMMMOPPMMMMMMMM MMOMMPPAPMMMMMEM MMPOPPPPPAMMMEEE MMPPPPPMPPAMEMMM MMMPPMMPPPAAAEEM MMEMPPPPPPPPPEMM MMEMMMPPPPPAAMEM MMMMMEMMPPAEMMMM MMMMMEMMPMMMMMMM MMMMEMMEMMMEMMMM } # tile 322 (shark) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMP MMMMMMMMPMMMMMPP MMMMEMMPPMMMMPPM MMMEMMMPPAMMPPPM MMEEEEPPPAMPPPPP MEMEEPPPMPPPPPPE MMMEPMPMPPPPPEEE MMPPPPPPPPPPEEEM MAPPPPPPPPEEEEME PPPPPPPMMEEMMMMM NDPPAPEPPPMEMMEE PDNPPEEMMEEMMMMM MPPPEMMEEEMMEMMM } # tile 323 (giant eel) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMAAAMMMMMMMMM MMMAAOAAMMMAAAMM MMAAAAAAAMAAMAAM MMAAAAMAAMAAMAAM MMMAAMMAAMAAMMAM MMMMMMAAAMMAAMAM MMMMMMAAMMMAAMMM MMMMMAAAMEMAAMEM MMMEMAAEEMAAAEMM MMMEMAAEEAAAEEMM MMEMMAAAAAAEMEMM MMMEEMAAAAEMEMMM MMEMMMEEMEMMMEMM } # tile 324 (electric eel) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMAAAMMMMMMMMM MMMAAOAAMMMMMMMM MMAAAAAAAMMMMMMM MMAAAAMAAMMMMMMM MMMAAMMAAMMMDDMM MMMMMMAAAMMDDMMM MMMMMMAAMMMDDMMM MMMMMAAAMEMDDMEM MMMEMAAEEMDDMEMM MMMEMAAEEDDMEEMM MMEMMAAADDDEMEMM MMMEEMAAADEMEMMM MMEMMMEEMEMMMEMM } # tile 325 (kraken) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMFFMMFFMMMMMMMM MMDDFDDFMMMMMMMM MMFFFFFMMMMMGGMM MMNCNFFMMMMMMGFA MMCCMFFMMMMMEGFA MMMMGFAAMGFAEGFE MMMGFFAGFFFFAGFE MMMGFAAFFAGFAEEE MMGFFAGFFAGFEEEM EEGFFAGFFAEEEEME MEGFFAGFFEEMMMMM EEGFFEEEEEMEMMEE EEEEEEEMMEEMMMMM MMEEEMMEEEMMEMMM } # tile 326 (newt) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJKKJMMMMMM MMMMMCLCCLLCMMMM MMMMLAAAACCLCAMM MMMMMMMLCCLLLCAM MMMMLCCCLLLAALAM MMMMCALLLLAAAAMM MMMLLLLCLAAAMMMM MMMLLAAALLAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 327 (gecko) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMLLPMM MMMMMMMMMMLLOOAM MMMMMMPOMLLOOOAM MMMMMMOOALOOOAMM MMMMMMMLLOOOAMMM MMMPOALOOOAAMMMM MMMOOLOOOOOOAMMM MMMMALOOOAOPAMMM MMMDOOOOAMAAMMMM MMMOOOAOOAMMMMMM MMMOODAOPAMMMMMM MMFMAAMAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 328 (iguana) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMGPGPGGPFMMMM MMGPAAAAFFGPFMMM MGPAAMPFFGPPPAAM MMMMMMFGGPPFPPAA MPFGGGGPPPFAAPPA MFGPAPPPPFAAAAAM MGPPPPFPFAAAMAMM MPPFFAFPPAAMMMMM DMAAAAAAPPAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 329 (baby crocodile) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMFFOFOFAMMMM MMMMFOGFGGOFFMMM MMMMGAAAAFOGFAMM MMMFAAMGFOGGGFAM MMMGFOOOGGGFAGAM MMMFGAGGGGFAAAMM MMFGGGGFGFAAMMMM MMGGDFAFGGAMMMMM MMMDMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 330 (lizard) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMFFFFGFJMMMMM MMFFAAAJJGFJMMMM MMMMMMJGFFJFAAMM MMMJGGGFFJAAFAMM MMJFAFFFJAAAAMMM MMFFFFJJAAAMMMMM MJFAAAAFAAMMMMMM MDMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 331 (chameleon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMGGGGMMMMMMM MMMGGGGGGGGMMMMM MMMGGFFFFGGFAMMM MMGPAAAGFFGGFAMM MGPAAMPFFGGGGAAM MMMGGGGGGGGFGGAA MPGGBBGGGGFAAGGA MFGGABGGGFAAAAAM MGGGGGFGFAAAMAMM MDGFFAFGGAAMMMMM DMAAAAAAGGAMMMMM MDDMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 332 (crocodile) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMFFOFOOFAMMMM MMMFOGFGFGOFFAMM MMFGAAAAFFOGFFAM MFFAAMGFFOGGGGFA MMMMMMFOOGGGGGGA MGMOOOOGGGGFAGGA MFOGAGGGGGFAAAAM FGGGGGFGGFAAMMMM GGDDFAFGGGAMMMMM GDDFAAAAGGAMMMMM MDFMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 333 (salamander) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMCCCMMMMMMM MMMMCCCCCCCMMMMM MMMCCDDDDCCDAMMM MMMMAAAADDCCDAMM MMMMMMKDDCCCCAAM MMLLLCCCCCCDCCAA MKLCCCLLLCDAACCA MDCEECLKKDAAAAAM DCCAECDKDAAAMAMM CCCCCCDCCAAMMMMM MDAADAAACCAMMMMM MMACCAMMMMMMMMMM MMMAAAMMMMMMMMMM } # tile 334 (long worm tail) { MMMMMMMMILLLLMMM MMMMMMIILLAAMMMM MMMMMILLAAMMMMMM MMMMMILAMMMMMMMM MMMMMILAMMMMMMMM MMMMMMLLAMMMIIMM MMMMMMMLLIIILLLL MMMMMMMMILLAAAML MMMIIIILLALLMMMM MILLLLLAAMMLLMMM ILLAAAAMMMMMLAMM ILAMMMMMMMMMLAMM LLAMMMMMMMMLLAMM LILAMMMMMMLLAMMM MLLLIIIILLLAMMMM MMMLLLLLAAAMMMMM } # tile 335 (archeologist) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKJMJMMMMMM MMMMMMKJJJMMMMMM MMMMKCKKKJJJMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCKAAKJMAAAM MMMMCKKKJJJJAAAM MMMMKACKJJAJAAAM MMMMLACJKJALAAAM MMMMMMCJJKAAAAMM MMMMMKCJAJJAMAMM MMMMMCJJMJKJMMMM MMMMMMMMMMMMMMMM } # tile 336 (barbarian) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMHHAMMMMMM MMMMMMHHHHAMMMMM MMMMMMLFLFAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMLLAALLMAAAM MMMMLLLLLLLLAAAM MMMMLALLLLALAAAM MMMMLAALLAALAAAM MMMMLAJJKJALAAAM MMMMMMLJJLAAAAMM MMMMMMLLALAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM } # tile 337 (caveman) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMJJAMMMMMM MMMMMMJJJJAMMMMM MMMMMJFLFLJMMMMM MMMMMJLLLLJMMMMM MMMMMJJDDJAMMMMM MMMMLLAJJALLAAAM MMMLLLLAALLLLAAM MMMLLALLLLALLAAM MMMMLACKKJALAAAM MMMMMMCKKJAAAAMM MMMMMMLAMLAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 338 (cavewoman) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMJJAMMMMMM MMMMMMJJJJAMMMMM MMMMMJFLFLJMMMMM MMMMMJLLLLJMMMMM MMMMMJLDDLAJMMMM MMMMLJALLAJLAAAM MMMLLJCAAJJLLAAM MMMLLACKKJALLAAM MMMMLACKKJALAAAM MMMMMMCKKJAAAAMM MMMMMMLAMLAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 339 (healer) { MMMMMMMMMMMMMMMM MMMMMMMNNMMMMMMM MMMMMMNDDOMMMMMM MMMMMMNNNNMMMMMM MMMMMMELEPMMMMMM MMMMMMLLLPMMMMMM MMMMMMMLLPMMMMMM MMMMMMOMMPAMAAAM MMMMMNNOOPPAAAAM MMMMOOONOPPPAAMM MMMMLANOOPALAAMM MMMMMMNOOPAAAAMM MMMMMNOOOPAAMAMM MMMMNOOOOOPAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 340 (knight) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMBPAMMMMMM MMMMMMBPPPAMMMMM MMMMMMPEEPAMMMMM MMMMMMPLLPAMMMMM MMMMMMALLAAMMMMM MMMMMBBAABBMAAAM MMMMBPPPPPPPAAAM MMMMPABPPPAPAAAM MMMMLAMPPMALAAAM MMMMMMBPMPAAAAMM MMMMMMBPAPAAMAMM MMMMMPPAMPPAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 341 (monk) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMCCCMMMMMM MMMMMMJCJJJAMMMM MMMMMMCAAAJAMMMM MMMMMMCAAAJAMMMM MMMMMMCKLKCAAAAM MMMMMCDDDDDDAAAA MMMMCDDLALDDDAAA MMMMDALLALLADAAM MMMMDDDDCDDDDAAM MMMMMAACCCDAAAAM MMMMMCDCCCDDAMAM MMMMCCCCCCCDDMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 342 (priest) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJLLJMMMMMM MMMMMMJLLJAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLJAMMMMM MMMMMMIJJIAAAAMM MMMMMODDDDDAAAAM MMMMIDNDDDDDAAAM MMMNLNNNDDALAAMM MMMMMMNDDDAAAAMM MMMMMMDIIDAAAAMM MMMMMDDIIDDAMAMM MMMMDIIIIIDDMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 343 (priestess) { MMMMMMMMMMMMMMMM MMMMMMMJJMMMMMMM MMMMMMJJJJMMMMMM MMMMMMJLLJAMMMMM MMMMMMJLLJJMMMMM MMMMMJJLLJJMMMMM MMMMMJEJJEJAAAMM MMMMMODEEDDAAAAM MMMMIDINDDDDAAAM MMMMLMNNNDALAAMM MMMMMMINDDAAAAMM MMMMMMINDDAAAAMM MMMMMDDIIDDAMAMM MMMMDIIIIIDDMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 344 (ranger) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMCJAMMMMM MMMMMMMCJJJAMMMM MMMMMMMJEEJAMMMM MMMMMMMJLLJAMMMM MMMMMMMALLAAMMMM MMMMMMGGAAGGMAAA MMMMMBPFFFFPPAAA MMMMMPAGFFFAPAAA MMMMMLAMFFMALAAA MMMMMMMBPMPAAAAM MMMMMMMBPAPAAMAM MMMMMMPPAMPPAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 345 (rogue) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOAMMMOAMMMM MMMMMOOIDPPAMMMM MMMMMMIDDDAMMMMM MMMMMMLKLKAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMMBAABAAMMAM MMMMMKEBBEJAAAAM MMMMKAAEEAAKAAMM MMMMLAJJHJALAAMM MMMMMMKKJKAAAAMM MMMMMKKAMKKAMMMM MMMMMMMMMMMMMMMM } # tile 346 (samurai) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMAAMMMMM MMMMMMMAAAMMMMMM MMMMMMAAAAAMMMMM MMMMMALFLFAMMMMM MMMMMALLLLAMMMMM MMMMMMALLAMMMMMM MMMMIIIAAIIIAAAM MMMMLDIIIIDLAAAM MMMMLABBBBALAAAM MMMMLABBBBALAAAM MMMMMMIDDDAAAAMM MMMMMMIDADAAMAMM MMMMMIIAMIIAMMMM MMMMMMMMMMMMMMMM } # tile 347 (tourist) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJKJJAMMMMM MMMMMMKJJJAMMMMM MMMJJJJJJJJJJMMM MMMMMMLFLFAAMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMHGAAGHMAAAM MMMMLLGHHGLLAAAM MMMMLAHGHGALAAAM MMMMLAHHGHALAAAM MMMMMMJJJKAAAAMM MMMMMMLLALAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM } # tile 348 (valkyrie) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMLHHLMMMMMM MMMMMHHHHHLMMMMM MMMMLHELELHMMMMM MMMMHHLLLLHMMMMM MMMHHHALLAMMMMMM MMMHJKJAAKJJAAAM MMHHLJJKKJJLAAAM MMHMLACKJCALAAAM MMMMLAAKKAALAAAM MMMMMMKKJKAAAAMM MMMMMMKJAJAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 349 (wizard) { MMMMMMMMMMMMMMMM MMMMMMMMMBPMMMMM MMMMMMMBBPEMMMMM MMMMMMBPPEAMMMMM MMMMMMBAAEAMMMMM MMMMMMBAAEAMMMMM MMMMMMPLLEMMMMMM MMMMMMPAAEAMAAAM MMMMMBBPBEEAAAAM MMMMPPPBEEEEAAMM MMMMLABPPEALAAMM MMMMMMBPPEAAAAMM MMMMMBPPPEAAMAMM MMMMMBPPPPEAMMMM MMMMBPPPPPPEMMMM MMMMMMMMMMMMMMMM } # tile 350 (Lord Carnarvon) { MMMMMMMJJMMMMMMM MMMMMMKJJJMMMMMM MMMMKCKKKJJJMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCIAAIKMAAAM MMMMCKKIIKKKAAAM MMMKKCKKHKJKKAAM MMMKKAKHKJAKKAAM MMMKAIHKKJIAKAMM MMMLAICKKJIALAMM MMMMMICKAJIAAAMM MMMMMMCKAPAAAAMM MMMMMPPAMPPAMMMM MMMMMMMMMMMMMMMM } # tile 351 (Pelias) { MMMMMMMMMMMMMMMM MMMMMMMJJMMMMMMM MMMMMMKKKJMMMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCKAAKKMAAAM MMMMCKKKKKKKAAAM MMMKKCKKKKJKKAAM MMMKKAKKKKAKKAAM MMMKAMCKKJAAKAMM MMMLAMCKAJAALAMM MMMMMMCKAJAAAAMM MMMMMMCKAPAAAAMM MMMMMPPAMPPAMMMM MMMMMMMMMMMMMMMM } # tile 352 (Shaman Karnov) { MMMMMMMMMMMMMMMM MMMMMMMJJAMMMMMM MMMMMMJJJJAMMMMM MMMMMJFLFLJMMMMM MMMMMJLLLLJMMMMM MMMMMJJDDJAMMMMM MMMMLHAJJAHLAAMM MMMLLLHAAHLLLAAM MMMLLLLHHLLLLAAM MMMLLALHHLALLAAM MMMLLALLLLALLAAM MMMMLACKKJALAAAM MMMMMMCKKJAAAAMM MMMMMMLAMLAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM } # tile 353 (Earendil) { MMMMMMMMMGMMMMMM MMMMBMMGGFMMBMMM MMMBBMGGGGABBMMM MMBPBPLELEABPBMM MMBBBPLLLLABBBMM MMPBPPALLAPPPMMM MMMPPBGAAGBBBMMM MMMBBLGGGFLBBBMM MMBBLAAGFAALBBMM MMMBLAGGGFALBMMM MMMMMMGFAFMMMMMM MMMMMMLMMLMAAAMM MMMMMMAAAAAAAAMM MMMMAAAAAAAAMMMM MMMMMAAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 354 (Elwing) { MMMMMMMMMGMMMMMM MMMMBMMGGFMMBMMM MMMBBMGGGGABBMMM MMBPBHLELEHBPBMM MMBBBHLLLLHBBBMM MMPBHHALLAHHPMMM MMMPHHGAAGHHBMMM MMMBBLGGGFLBBBMM MMBBLAAGFAALBBMM MMMBLAGGGFALBMMM MMMMMMGFAFMMMMMM MMMMMMLMMLMAAAMM MMMMMMAAAAAAAAMM MMMMAAAAAAAAMMMM MMMMMAAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 355 (Hippocrates) { MMMMMMMMMMMMMMMM MMMMLLLCCDMMMMMM MMMLLCCDDAMMMMMM MMMLAAAADAMMMMMM MMMLBABADAMMMMMM MMMLAAAADAMMMMMM MMMCCLLDDMBMMMMM MMMMCKKDDFBFAAAM MMLLLCLDDDBFAAAM MCCCCLDDDFBAAAMM MLALLCCDDFBDAAMM MMMLCCCCDABFAAMM MMMLCCCCDABAAAMM MMLLCCCCDAAMAAMM MLCCCCCCCDAMMMMM MMMMMMMMMMMMMMMM } # tile 356 (King Arthur) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMOHHAMMMMMM MMMMMOHHHHAMMMMM MMMMMHBLBHAMMMMM MMMMMHLLLHAMMMMM MMMMMALLLAAMMMMM MMMMBBAAABBMAAAM MMMBPPPPPPPPAAAM MMMPABPPPPACPAAM MMNNNNNNNNNCLCAM MMMMMBPPMPACAAMM MMMMMBPAPPAAMAMM MMMMMBPAPPAAMAMM MMMMPPAAMPPAMMMM MMMMMMMMMMMMMMMM } # tile 357 (Grand Master) { MMMMMMMMMMMMMMMM MMMMMMMLLMMMMMMM MMMMMMLLLLMMMMMM MMMMMMLLLLMMMMMM MMLCMCALLACMMMMM MCLLCMCAACCCCMMM MCJLACCCCCCCCCMM MMJAACCCCCCCCCCM MMJCCCCCCCCCCCMA MMJMMPPPPPLCCAAA MMJMMCCCCLLCAAAA MMJMMCCCCCCCAAAA MMJMMCCCCCCCAAAA MMJMACCCCCCCAAAM MMJACCCCCCCCAAMM MMMMMMMMMMMMMMMM } # tile 358 (Arch Priest) { MMNMMMMMMMMMMMMM MNNNMMJLLJMMMMMM MMNMMMJLLJMMMMMM MMNMMMLLLLMMMMMM MMLCMCALLACMMMMM MCLLCMCAACJDKMMM MCHLACCCCJCCDKMM MMHAACCJJCCCCDKM MMHCCCCJCCJCCCMA MMHMMDCJCCLJCAAA MMHMMDCJCLLCAAAA MMHMMKCJCCDJAAAA MMHMMKCJCCDJAAAA MMHMACCJCCDJAAAM MMHACCCJJCCCAAMM MMMMMMMMMMMMMMMM } # tile 359 (Orion) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMCJAMMMMMM MMMMMMCJJJAMMMMM MMMMMMJEEJAMMMMM MMMMMMJLLJAMMMMM MMMMMMALLAAMMMMM MMMMMGGAAGGMMMMM MMMMBGFFFFFPMMMM MMMMBPFFFFPPAAAM MMMMPAGFFFAPAAAM MMMMLANNNNALAAAM MMMMMMBPMPAAAAAM MMMMMMBPMPAAAAMM MMMMMMBPAPAAMAMM MMMMMPPAMPPAMMMM } # tile 360 (Master of Thieves) { MMMMMMMMMMMMMMMM MMMHMMMMMHMMMMMM MMMHHIDKHHMMMMMM MMMMIDDDDMMMMMMM MMMMLLLLLAMMMMMM MMMMLBLBLAMMMMMM MMMMLLLLLAMMMMMM MMMMMLLLAMMMMMMM MMMMBMAABAAMMMMM MMMKEBBBEJAAAMMM MMKAEEEEEAJAAAMM MMLAJJHHJALAAAMM MMMMJKKKJAAAAAMM MMMMKJAJKAAAAMMM MMMJJAMMJJAMMMMM MMMMMMMMMMMMMMMM } # tile 361 (Lord Sato) { MMMMMAAAMMMMMMMM MMMMMAAAMMMMMMMM MMMAAAAAAAMMMMMM MMAALLLLLAAMMMMM MMALFFLFFLAMMMMM MMALLLLLLLAMMMMM MMMAALLLAMMMMMMM IIIIIAAAIIIIAAAM LLDIIIIIIDLLAAAM LLABBBBBBALLAAAM LLABBBBBBALLAAAM LLABBBBBBALLAAAM MMMIIDDDDAAAAAAM MMMIIAAIDAAAMMAM MMIIIAMIIIAAMMMM MMMMMMMMMMMMMMMM } # tile 362 (Twoflower) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJKJJAMMMMM MMMMMMKJJJAMMMMM MMMMJJJJJJJJMMMM MMMMMNNLNNAMMMMM MMMMNALNALNAMMMM MMMMMNNANNAAMMMM MMMMMAAAAAAMAAAM MMMMLLHGHGLLAAAM MMMMLAGGGGALAAAM MMMMLAHGHGALAAAM MMMMMMJJJKAAAAMM MMMMMMJJAKAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM } # tile 363 (Norn) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMNNNMMMMMMM MMMMMNNNNNMMMMMM MMMMMNELELNMMMMM MMMMNNLLLLNMMMMM MMMNNNALLAMMMMMM MMMNJKJAAKJJAAAM MMNNLJJKKJJLAAAM MMNMLACKJCALAAAM MMMMLAKKKKALAAAM MMMMMMKKJKAAAAMM MMMMMMKJAJAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 364 (Neferet the Green) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMGGGMMMMMMM MMMMMGFFFGMMMMMM MMMMGFEFEGMMMMMM MMMMGFFFFEGMMMMM MNMGPEFFFEEMMMMM MIMMBBEAAEAMAAMM MIMBBPPBBEEAAAAM MIGBPPPPPEEEAAMM MIMPPMEPEAAGAAMM MIMMMBPPPAAAAAMM MNMMMBPPPEAAMAMM MMMMBPPPPPEAMMMM MMMBPPPPPPPEMMMM MMMMMMMMMMMMMMMM } # tile 365 (Minion of Huhetotl) { MMMOPMMMMMMPOMMM MMMOODDDDDDOODMM MMDLOOCDDCOOLDDM MDDDLDDDDDDLDDDM MCCDDDNDDNDDDCCM CCDKDDDDDDDDJCCC CDDKKDDIIDDJJCCD CDDKKKDAADJJDCDD CCDKDDKKKJDDKCDD MCCDKKDDDDKKCDDD MCCDADKDDKDACDDM MDDDADDDDDDADDDM MMMMCCDDDDKKAAMM MMMCDDDAADDDKAAM MMCDDDAAAMDDDKMM MMMMMMMMMMMMMMMM } # tile 366 (Thoth Amon) { MMMMMMMMMMMMMMMM MMMMMMOJJOMMMMMM MMMMMMJJJJAMMMMM MMMMMMBLBLAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMBPAAPPMAAAM MMMMBPPPPPPPAAAM MMMPPBPPPPJPPAAM MMMPPAPPPMAPPAMA MMMPAMBPPMAAPAMA MMMLAMBPPMMALMAM MMMMMMBPAMAMMAMM MMMMMMBPAPAAAAMM MMMMMPPAMPPAMMMM MMMMMMMMMMMMMMMM } # tile 367 (Chromatic Dragon) { MMMMMMGGGFAMMMMM MMMMMNFNFEEAMMMM MMMMGFFFEECAMMMM MMDCHHFMMCCAMMMM CHCHCDMMBCCAMMMM HDMDMMMBFFAMMMMM MMMMMMOBFAAAAAAM MMMMHOGFAAAAAAAA MMHOOIEAMEFMAAAM MHOOOIEEEEFFJAAM MHOOOIEEFFFDDAAM HBOOIIEFFFDDCCAM HBMOIEFOODDMCJAM HBAAGEMAADDACCAM MMMMGFAAMMMCCJAM MMMMMMMMFFFFJAMM } # tile 368 (Goblin King) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MHMMHMMMHMMMMMMM CLCMHCHCHMMMMMMM CLCMHHHHHMMMMMMM MHMMIIIIIMMMMMMM MHKMIHIHIMIMMMMM MHICKIIIJKKMMMMM MHMIIJJJKMAAMMMM MHMMJICJJAAAAAMM MHMMIIIIJAAAAAMM MMMMJIIJJAAMMMMM MMMMIJKJJAMMMMMM MMMIKAAMIKMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 369 (Cyclops) { MMMMMMMMMMMMMMMM MMMMLLLLLMMMMMMM MMMCLLLLLCMMMMMM MMMLBABNNLMMMMMM MMMLBBBNNLJAMMMM MMMCLNNNLCJAMMMM MMMMLLLLLJAAAMMM MMMMLAALLAAAAMMM MMJKJLLLKAKJAAMA MCLKAJJJJAKLCAAA MLLJKAAAAKJLLAAM MLAAJKKKKJAALAAM MLCMGGGHGGACLAAA MLLMJJJJJJALLAAA MMMMCJJJCLAAAAAA MMLLLLLMLLLLLAAM } # tile 370 (Ixoth) { MMMMOMMMMMMOMMMM MMMMOMMMMMMOMMMM MMMLOOCDDCOOLMMM MMMDDDDDDDDDDDMM MCCDDDGDDGDDDCCM CCDKDDDDDDDDJCCC CDDKKKDIIDJJDCCD CDDKDDKJJJDDDCDD CCDKDDDDDDDDKCDD MCCDKKDDDDKKCDDD MCCDADKDDKDACDDM MDDDADDDDDDADDDM MMMMCCDDDDKKAAMM MMMCDDDAADDDKAAM MMCDDDAAAMDDDKMM MMMMMMMMMMMMMMMM } # tile 371 (Master Kaen) { MMMMMMMMMMMMMMMM MMMMMMMKKAMMMMMM MMMMMMKJJKAMMMMM MMKKAMKAAKAMKKAM MKAAKAKDDKAKAAKA MKOOJKKOOKKKOOJA MKJJJJJJJJJKJJJA MMKJJJJJJJJJJJAM MMMMKJJJJJJJAMMM MMMMMMKJJJAAAAAA MMMMMKJJJJKAAAAA MMMMMKJJJJJAAAAA MMMMKJJJJJJKAAAM MMMKJJJJJJJJKAAM MMMKJJJJJJJJJAMM MMMMMMMMMMMMMMMM } # tile 372 (Nalzok) { MMMMOMMMMMMOMMMM MMMMOMMMMMMOMMMM MMMLOOCDDCOOLMMM MMMDDDDDDDDDDDMM MCCDDDBDDBDDDCCM CCDKDDDDDDDDJCCC CDDKKKDIIDJJDCCD CDDKDDKJJJDDDCDD CCDKDDDDDDDDKCDD MCCDKKDDDDKKCDDD MCCDADKDDKDACDDM MDDDADDDDDDADDDM MMMMCCDDDDKKAAMM MMMCDDDAADDDKAAM MMCDDDAAAMDDDKMM MMMMMMMMMMMMMMMM } # tile 373 (Scorpius) { MMMMMJLJLJAAMMMM MMMMJAMJCJCKAAMM MMMMAJMMMMMJJJAM MMMMLAMMMMMMLCKA MJAKJAMMMMMMJJJA MMJJAMMMMMMALCJA MMMMMMMALLAJCJKA MMMMJJALCCAAJJAM MJJALLAJCJJJAAMM JAMLCCAJAJJAAAAM MMJACJJJAAACCJAA GGJJJJJAACCAAAJA MJJGGAJACAAJJAAA DMJJAAJAACAMJAAM MMMDMMMJAAJAMJJM MMMMMMMMJAMJAMMM } # tile 374 (Master Assassin) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMAAMMMMMMM MMMMMMAAAAMMMMMM MMMMMABLBLAMMMMM MMMMMAAAAAAMMMMM MMMMMMAAAAMMMMMM MMMMMAAAAAAMMPPM MMMMAAAAAAAAPPPM MMMMAAAAAAAAPPPM MMMMLAAAAAALPPPM MMMMMMAAAAAPPPMM MMMMMMAAAAAPMPMM MMMMMAAAMAAAMMMM MMMMMMMMMMMMMMMM } # tile 375 (Ashikaga Takauji) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMAAMMMMMMMM MMMMMMMAAAMMMMMM MMMMMMAAAAAMMMMM MMMMMALFLFAMMMMM MMMMMALLLLAMMMMM MMMMMMALLAMMMMMM MMMMIIIAAIIIAAAM MMMMLDIIIIDLAAAM MMMMLAIIIIALAAAM MMMMLALHHLALAAAM MMMMMMIIIIAAAAMM MMMMMMIIAIAAMAMM MMMMMIIAMIIAMMMM MMMMMMMMMMMMMMMM } # tile 376 (Lord Surtur) { MMMMPPDDDDAAMMMM MMMMPDDDDDDDAMMM MMMPPDLLLLDDAMMM MMMPDPFLLFFDAMMM MMMPPPLLLLLDAMMM MMMMPLLAALLAAAMM MMMPPALLLLBAAAAM MMMPPDBBBBBBBAAM MMBDDHDPBPPPPPAM MMPPHDDPBPPPPPAM MMLAHDHPBPPAALAA JLAADDHBBBBAALAA JJLJDHHPBPPPCLAA MMLLJBPPABPPLLAA MMMMMBPPABPPAAAA MMMLLLLJMBLLLKAA } # tile 377 (Dark One) { MMMMMMMMMMMMMMMM MMMMMMAAAMMMMMMM MMMMMAAAAAMMMMMM MMMMMADADAMMMMMM MMMMMAAAAAMMMMMM MMMMAAAAAAAMMMMM MMMMAAAAAAAMMMMM MMMAAAAAAAAAMMMM MMMAAAAAAAAAMMMM MMAAAAAAAAAAAMMM MMAAAAAAAAAAAMMM MMMAAAAAAAAAMMMM MMMAAAAAAAAAAMMM MMAAAAAAAAAAAAMM AAAAAAAAAAAAAAAA MMMMMMMMMMMMMMMM } # tile 378 (student) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMGGFGGMMMMMM MMMMMMMGMMMMMMMM MMMMMMNDNDMMMMMM MMMDDDDDDDDMMMMM MMMMMMLELEAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMCKAAKJMAAAM MMMMCKKKJJJJAAAM MMMMKACKJJAJAAAM MMMMLACJKJALAAAM MMMMMKCJAJJAMAMM MMMMMCJJMJKJMMMM MMMMMMMMMMMMMMMM } # tile 379 (chieftain) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMHHAMMMMMM MMMMMMHHHHAMMMMM MMMMMMLFLFAMMMMM MMMMMMLLLLAMMMMM MMMMMHALLAHMMMMM MMMMLLHAAHLLAAAM MMMMLLLIILLLAAAM MMMMLALIILALAAAM MMMMLAALLAALAAAM MMMMLAJJKJALAAAM MMMMMMLJJLAAAAMM MMMMMMLLALAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM } # tile 380 (neanderthal) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJJJJMMMMMM MMMMMJJJJJJMMMMM MMMMMJFLFLJMMMMM MMMMMJLLLLJMMMMM MMMMMJJDDJAMMMMM MMMMJJAJJAJJMAAM MMMJLLJAAJLLJAAM MMMLLALJJLALLAAM MMMMLALCCLALAAAM MMMMMMLAMLAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 381 (High-elf) { MMMMMMMMMGMMMMMM MMMMMMMGGFMMMMMM MMMMMMGGGGAMMMMM MMMMMMLILIAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMMGAAGMMAAMM MMMMMLGGGFLAAAAM MMMMLAAGFAALAAAM MMMMLAMGFAALAAMM MMMMLAMGFAALAAMM MMMMLAGGGFALMAMM MMMMMMGFAFAAMAMM MMMMMMGFAFAAMMMM MMMMMMGFAFAAMMMM MMMMMKLAMLKAMMMM } # tile 382 (attendant) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJJJMMMMMMM MMMMMJLLLJMMMMMM MMMMMMBLBMMMMMMM MMMMMCLLLDMMMMMM MMMMMCCKKDAMAAAM MMMMMLLCLDDAAAAM MMMMCCCLDDDDAAMM MMMMLALCCDALAAMM MMMMMMLCCDAAAAMM MMMMMLCCCDAAMAMM MMMMLCCCCCDAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 383 (page) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMBPAMMMMMM MMMMMMBPPPAMMMMM MMMMMMPEEPAMMMMM MMMMMMPLLPAMMMMM MMMMMMMLLAAMMMMM MMMMMMBAABAMAAAM MMMMMBPPPPPAAAAM MMMMPABPPPAPAAAM MMMMLAMPPMALAAAM MMMMMMBPMPAAAAMM MMMMMMLLALAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 384 (abbot) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKLKMMMMMMM MMMMMMLLLMMMMMMM MMMMCCLLLJJMMMMM MMMMKCKLKKJAAAMM MMMMCDDDDDDAAAAM MMMCDDLALDDDAAAM MMMDALLALLADAAMM MMMDDDDCDDDDAAMM MMMMAACCCDAAAAMM MMMMCDCCCDDAMAMM MMMCCCCCCCDDMMMM } # tile 385 (acolyte) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJJJJMMMMMM MMMMMMJLLJAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLJAMMMMM MMMMMMCJJCAAAAMM MMMMMLDDDDDAAAAM MMMMCDCCDDDDAAAM MMMMLMLCCDALAAMM MMMMMMLCCDAAAAMM MMMMMMLCCDAAAAMM MMMMMLDCCDDAMAMM MMMMLCCCCCDDMMMM MMMMMMMMMMMMMMMM } # tile 386 (hunter) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJMMCJAMMMMMM MMMJMMCJJJAMMMMM MMMJMMJEEJAMMMMM MMJMMMJLLJAMMMMM MMJMMMALLAAMMMMM MMJMMGGAAGGMAAAM MMLPBPFFFFPPAAAM MMJMMAGFFFAPAAAM MMJMMMMFFMALAAAM MMMJMMBPMPAAAAMM MMMJMMBPAPAAMAMM MMMMJPPAMPPAMMMM MMMMMMMMMMMMMMMM } # tile 387 (thug) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMIDMMMMMMM MMMMMMIDDDAMMMMM MMMMMMLKLKAMMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMKKAAKKAMMAM MMMMKKJKKJJKAAAM MMMMKAAJJAAKAAMM MMMMLAJJJJALAAMM MMMMMMKKJKAAAAMM MMMMMMKAAKAAAAMM MMMMMKKAMKKAMMMM MMMMMMMMMMMMMMMM } # tile 388 (ninja) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMAAMMMMM MMMMMMMAAAMMMMMM MMMMMMAAAAAMMMMM MMMMMAFLFLAMMMMM MMMMMAAAAAAMMMMM MMMMMMAAAAMMMMMM MMMMAAAAAAAAMPPM MMMMAAAAAAAAPPPM MMMMAAAAAAAAPPPM MMMMLAAAAAALPPPM MMMMMMAAAAAPPPMM MMMMMMAAAAAPMPMM MMMMMAAAMAAAMMMM MMMMMMMMMMMMMMMM } # tile 389 (roshi) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMAAAAAMMMM MMMMMMAAAAAMMMMM MMMMMALFLFAMMMMM MMMMMALLLLAMMMMM MMMMMMALLAMMMMMM MMMMPPPAAPPPAAAM MMMMLMPPPPMLAAAM MMMMLAOOOOALAAAM MMMMLAOOOOALAAAM MMMMMMPMMMAAAAMM MMMMMMPMAMAAMAMM MMMMMPPAMPPAMMMM MMMMMMMMMMMMMMMM } # tile 390 (guide) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJKJJAMMMMM MMMMMMKJJJAMMMMM MMMMJJJJJJJJMMMM MMMMMMLFLFAAMMMM MMMMMMLLLLAMMMMM MMMMMMALLAMMMMMM MMMMMHHAAHHMAAAM MMMMLLHHHHLLAAAM MMMMLAHHHHALAAAM MMMMLAHHHHALAAAM MMMMMMJJJKAAAAMM MMMMMMJJAKAAMAMM MMMMMLLAMLLAMMMM MMMMMMMMMMMMMMMM } # tile 391 (warrior) { MMMMMOMMMMOMMMMM MMMMMNOMMONMMMMM MMMMMMNPPNMMMMMM MMMMMPPPPPPMMMMM MMMMMPELELPMMMMM MMMMHHLLLLHMMMMM MMMHHHALLAMMMMMM MMMHJKJAAKJJAAAM MMHHLJJKKJJLAAAM MMHMLACKJCALAAAM MMMMLAAKKAALAAAM MMMMMMKKJKAAAAMM MMMMMMKJAJAAMAMM MMMMMMKJAJAAMAMM MMMMMKLAMLKAMMMM MMMMMMMMMMMMMMMM } # tile 392 (apprentice) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJJJMMMMMMM MMMMMJLLLJMMMMMM MMMMMMGLGMMMMMMM MMMMMBLLLEMMMMMM MMMMMBBEEEAMAAAM MMMMMBBPBEEAAAAM MMMMPPPBEEEEAAMM MMMMLABPPEALAAMM MMMMMMBPPEAAAAMM MMMMMBPPPEAAMAMM MMMMMBPPPPEAMMMM MMMMBPPPPPPEMMMM MMMMMMMMMMMMMMMM } # tile 393 (invisible monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMNNNNMMMMMMM MMMMNNNNNNMMMMMM MMMNNAAAANNMMMMM MMMNNAMMMNNAMMMM MMMMAAMMMNNAMMMM MMMMMMMMNNAAMMMM MMMMMMMNNAAMMMMM MMMMMMNNAAMMMMMM MMMMMMNNAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMNNMMMMMMMM MMMMMMNNAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM } nethack-3.4.3/win/share/objects.txt0100644000000000000000000044240107764735042015751 0ustar rootrootA = (0, 0, 0) B = (0, 182, 255) C = (255, 108, 0) D = (255, 0, 0) E = (0, 0, 255) F = (0, 145, 0) G = (108, 255, 0) H = (255, 255, 0) I = (255, 0, 255) J = (145, 71, 0) K = (204, 79, 0) L = (255, 182, 145) M = (71, 108, 108) N = (255, 255, 255) O = (218, 218, 182) P = (108, 145, 182) # tile 0 (strange object) { MMMMMMMMMMMMMMMM MMMCJKKKCJKKKCMM MCKJKKCKJKKCJJKM MKJKKKKJKKKKJJJM CJKKKCJKKKCJJJJM CJKKKCJKKKCJJAJM CCCCCHHCCCCJAJJM AADDAAAADDAAJJJM CCCCCHHCCCCJJJJM CJJJHJJHJJJJJJJM CJKKKHHKKKCJJJJA CJKKKHHKKKCJJJJA CJKKKCJKKKCJJJAA CJCCCCJCCCCJJAAM CKKKKKKKKKKJAAMM MAAAAAAAAAAAAMMM } # tile 1 (arrow) { MMMMMMMMMMMMMMMM MMMMMMMMMMPPMMMM MMMMMMMMMPBPOMMM MMMMMMMMMBPOBLMM MMMMMMMMMPOBLAMM MMMMMMMMJPAAAMMM MMMMMMMJKAMMMMMM MMMMMMJKAMMMMMMM MMMMMJKAMMMMMMMM MMMMJKAMMMMMMMMM MMMJKAMMMMMMMMMM MOOCAMMMMMMMMMMM MONNAMMMMMMMMMMM MNNOAMMMMMMMMMMM MMAAAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 2 (runed arrow / elven arrow) { MMMMMMMMMMMMMMMM MMMMMMMMMMFFMMMM MMMMMMMMMFGFOMMM MMMMMMMMMGFOGHMM MMMMMMMMMFOGHAMM MMMMMMMMJFAAAMMM MMMMMMMJKAMMMMMM MMMMMMJKAMMMMMMM MMMMMJKAMMMMMMMM MMMMJKAMMMMMMMMM MMMJKAMMMMMMMMMM MOOCAMMMMMMMMMMM MONNAMMMMMMMMMMM MNNOAMMMMMMMMMMM MMAAAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 3 (crude arrow / orcish arrow) { MMMMMMMMMMMMMMMM MMMMMMMMMMPPMMMM MMMMMMMMMPBPOMMM MMMMMMMMMBPOBLMM MMMMMMMMMPOBLAMM MMMMMMMMJKAAAMMM MMMMMMMJKAMMMMMM MMMMMMJKAMMMMMMM MMMMMJKAMMMMMMMM MMMMJKAMMMMMMMMM MMMJKAMMMMMMMMMM MOJCAMMMMMMMMMMM MONAAMMMMMMMMMMM MNNOAMMMMMMMMMMM MMAAAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 4 (silver arrow) { MMMMMMMMMMMMMMMM MMMMMMMMMMDPMMMM MMMMMMMMMDBDOMMM MMMMMMMMMBDOBDMM MMMMMMMMMDOBDAMM MMMMMMMMPPAAAMMM MMMMMMMPPAMMMMMM MMMMMMPPAMMMMMMM MMMMMPPAMMMMMMMM MMMMPPAMMMMMMMMM MMMPPAMMMMMMMMMM MOPPAMMMMMMMMMMM MOPPAMMMMMMMMMMM MNNOAMMMMMMMMMMM MMAAAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 5 (bamboo arrow / ya) { MMMMMMMMMMMMMMMM MMMMMMMMMMBPMMMM MMMMMMMMMBBPOMMM MMMMMMMMBBPOBLMM MMMMMMMMMPOBLAMM MMMMMMMMCJBLAMMM MMMMMMMCJAMAMMMM MMMMMMCJAMMMMMMM MMMMMCJAMMMMMMMM MMMMCJAMMMMMMMMM MMMCJAMMMMMMMMMM MMCJAMMMMMMMMMMM OCJAMMMMMMMMMMMM ONAMMMMMMMMMMMMM NNPAMMMMMMMMMMMM MAAMMMMMMMMMMMMM } # tile 6 (crossbow bolt) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMMMMMMMMMM MMAONMMMMMMMMMMM MMMAOKMMMMMMMMMM MMMMAJKMMMMMMMMM MMMMMAJKMMMMMMMM MMMMMMAJKMMMMMMM MMMMMMMAJKMMMMMM MMMMMMMMAJKMMMMM MMMMMMMMMAJKMMMM MMMMMMMMMMAJJMMM MMMMMMMMMMMAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 7 (dart) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMOOOMM MMMMMCLCLMOBBAMM MNNNCJDJDCBAAAMM MAAAAJDJDAOBBMMM MMMMMAAAAMMOOOMM MMMMMMMMMMMAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 8 (throwing star / shuriken) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPNMMMMMMMMM MMMMMNAPNNPMMMMM MMMMMNNNNANAMMMM MMMMMPNNNPAAMMMM MMMMNMNNNNMMMMMM MMMMPNNPANAMMMMM MMMMMAAANPAMMMMM MMMMMMMMMAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 9 (boomerang) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKKMMMMMMMMMM MMMMKHKAMMMMMMMM MMMMMKHKAMMMMMMM MMMMMMKKKAMMMMMM MMMMMMMKKKAMMMMM MMMMMMMMKDKAMMMM MMMMMMMMJDKAMMMM MMMMMMMJKDJAMMMM MMMMMMJKDJAMMMMM MMMMMJHDJAMMMMMM MMMMJHDJAMMMMMMM MMMMMKJAMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 10 (spear) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMNM MMMMMMMMMMMMMNOM MMMMMMMMMMMMNOAM MMMMMMMMMMMNOAAM MMMMMMMMMMKJAAMM MMMMMMMMMKJAAMMM MMMMMMMMKJLAMMMM MMMMMMMKJAAJAMMM MMMMMMKJAAKJAMMM MMMMMKJAAMCJAMMM MMMMKJAAMMLAMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MMJAAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 11 (runed spear / elven spear) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMNM MMMMMMMMMMMMMNOM MMMMMMMMMMMMNOAM MMMMMMMMMMMNOAAM MMMMMMMMMMKJAAMM MMMMMMMMMKJAAMMM MMMMMMMMKJLAMMMM MMMMMMMKJAAFAMMM MMMMMMKJAAFFAMMM MMMMMKJAAMGFAMMM MMMMKJAAMMHAMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MMJAAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 12 (crude spear / orcish spear) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMNM MMMMMMMMMMMMMNOM MMMMMMMMMMMMNOAM MMMMMMMMMMMKJAAM MMMMMMMMMMKJAAMM MMMMMMMMMLJAAMMM MMMMMMMMKJLAMMMM MMMMMMMKJAAJAMMM MMMMMMKJAKKJAMMM MMMMMKJAAMCJAMMM MMMMKJAAMMLAMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MMJAAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 13 (stout spear / dwarvish spear) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMNMM MMMMMMMMMMMMNOMM MMMMMMMMMMMNOAMM MMMMMMMMMMNOAAMM MMMMMMMMMKJAAMMM MMMMMMMMKJAAMMMM MMMMMMMKJLAMMMMM MMMMMMKJAAJAMMMM MMMMMKJAACJAMMMM MMMMKJAAMLAMMMMM MMMKJAAMMMMMMMMM MMJJAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 14 (silver spear) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMOA MMMMMMMMMMMMMOAM MMMMMMMMMMMMPAMM MMMMMMMMMMMPAMMM MMMMMMMMMMPAMMMM MMMMMMMMMPAMMMMM MMMMMMMMPAMMMMMM MMMMMMMBAMMMMMMM MMMMMMBAMMMMMMMM MMMMMPAMMMMMMMMM MMMMPAMMMMMMMMMM MMMPAMMMMMMMMMMM MMOAMMMMMMMMMMMM MOAMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 15 (throwing spear / javelin) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMOA MMMMMMMMMMMMMOAM MMMMMMMMMMMMIAMM MMMMMMMMMMMIAMMM MMMMMMMMMMIAMMMM MMMMMMMMMIAMMMMM MMMMMMMMIAMMMMMM MMMMMMMLAMMMMMMM MMMMMMLAMMMMMMMM MMMMMIAMMMMMMMMM MMMMIAMMMMMMMMMM MMMIAMMMMMMMMMMM MMOAMMMMMMMMMMMM MOAMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 16 (trident) { MMMMMMMMMMMMMMMM MMMPAMMMMMMMMMMM MMMMPAMMMMMMMMMM MMPAMPAMMMMMMMMM PAMPAMPAMMMMMMMM MPAMPAPAMMMMMMMM MMPAMPPAMMMMMMMM MMMPPPPAMMMMMMMM MMMMMMMPAMMMMMMM MMMMMMMMPAMMMMMM MMMMMMMMMPAMMMMM MMMMMMMMMMPKAMMM MMMMMMMMMMJPKAMM MMMMMMMMMMMJPKAM MMMMMMMMMMMMJAMM MMMMMMMMMMMMMMMM } # tile 17 (dagger) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMNMMMMMM MMMMMMMMNOAMMMMM MMMMMMMNOAAMMMMM MMMMOONOAAMMMMMM MMMMMKOOAMMMMMMM MMMMKJAOAMMMMMMM MMMKJAAAAMMMMMMM MMMAAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 18 (runed dagger / elven dagger) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMNMMMMMM MMMMMMMMNOAMMMMM MMMMMMMNOAAMMMMM MMMMOONOAAMMMMMM MMMMMKOOAMMMMMMM MMMMKFAOAMMMMMMM MMMKFAAAAMMMMMMM MMMAAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 19 (crude dagger / orcish dagger) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMNMMMMMM MMMMMMMMNOAMMMMM MMMMMMMNOAAMMMMM MMMMOMNOAAMMMMMM MMMMMCOAAMMMMMMM MMMMKJAOAMMMMMMM MMMKJAAAAMMMMMMM MMMAAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 20 (silver dagger) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMNMMMMMM MMMMMMMMNPAMMMMM MMMMMMMNPAAMMMMM MMMMBBNPAAMMMMMM MMMMMKPPAMMMMMMM MMMMKJAPAMMMMMMM MMMKJAAAAMMMMMMM MMMAAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 21 (athame) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMPMM MMMMMMMMMMMMNPAM MMMMMMMMMMMPPAMM MMMMMMMMMMNOAAMM MMMMMMMMMPPAMMMM MMMMMMMMNOAAMMMM MMMMMMPPPAMMMMMM MMMMPONOPAMMMMMM MMMMMKPBAMMMMMMM MMMMKJAOAMMMMMMM MMMKJAMMMMMMMMMM MMMMAMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 22 (scalpel) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMNAMMMMMMMMMM MMMMONAMMMMMMMMM MMMMMPBAMMMMMMMM MMMMMMMPAMMMMMMM MMMMMMMMPAMMMMMM MMMMMMMMMPAMMMMM MMMMMMMMMMPAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 23 (knife) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMNMMMMMM MMMMMMMMNOAMMMMM MMMMMMMNOAAMMMMM MMMMMMNOAAMMMMMM MMMMMKLAAMMMMMMM MMMMKLAAMMMMMMMM MMMKLAAMMMMMMMMM MMMAAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 24 (stiletto) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMOAMMM MMMMMMMMMMOAMMMM MMMMMMMMPOAMMMMM MMMMMMMPOAMMMMMM MMMMMMOOAMMMMMMM MMMOPNOAMMMMMMMM MMMMKJAAMMMMMMMM MMMKJAOPMMMMMMMM MMKJAAMMMMMMMMMM MMAAAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 25 (worm tooth) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMOMMMMMMMMM MMMMMMNAMMMMMMMM MMMMMMNOAMMMMMMM MMMMMMPOAMMMMMMM MMMMMMMOAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 26 (crysknife) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMNOAMMM MMMMMMMMMPPAAMMM MMMMMMMMNOAAMMMM MMMMMMPPPAMMMMMM MMMMPONOPAMMMMMM MMMMMKPBAMMMMMMM MMMMKJAOAMMMMMMM MMMKJAMMMMMMMMMM MMMMAMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 27 (axe) { MMMMMMMMMMMMMMMM MMMMMOPAMMMMMMMM MMMMOPPPAMMMMMMM MMMOPPPPPAMMMMMM MMMKPKPPPAMMMMMM MMMMKPPPAMMMMMMM MMMMMKAAMMMMMMMM MMMMMMKAMMMMMMMM MMMMMMMCAMMMMMMM MMMMMMMMCAMMMMMM MMMMMMMMMCAMMMMM MMMMMMMMMMCAMMMM MMMMMMMMMMMCAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 28 (double-headed axe / battle-axe) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMOPPAMMMMMMMM MMMMOPPPAMMMMMMM MMMKPPPPAMMMMMMM MOPPKPPPAMMMMMMM MOPPPKAAMMMMMMMM MPPPPAKAMMMMMMMM MMPPPAMCAMMMMMMM MMMAAMMMCAMMMMMM MMMMMMMMMCAMMMMM MMMMMMMMMMCAMMMM MMMMMMMMMMMCAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 29 (short sword) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMAONMMMMMMMMMM MMMMAONMMMMMMMMM MMMMMAONMMMMMMMM MMMMMMAONAPOMMMM MMMMMMMAOOKMMMMM MMMMMMAPOAJKMMMM MMMMMMAAAAAJKMMM MMMMMMMMMMAAJMMM MMMMMMMMMMMAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 30 (runed short sword / elven short sword) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMAONMMMMMMMMMM MMMMAONMMMMMMMMM MMMMMAONMMMMMMMM MMMMMMAONAPOMMMM MMMMMMMAOOMMMMMM MMMMMMAPOFGMMMMM MMMMMMAAAAFGMMMM MMMMMMMMMMAFGMMM MMMMMMMMMMMAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 31 (crude short sword / orcish short sword) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMAONMMMMMMMMMM MMMMAONMMMMMMMMM MMMMMAONMMMMMMMM MMMMMAAONAPOMMMM MMMMMMMAOOKMMMMM MMMMMMAPOBJKMMMM MMMMMMAAAABJKMMM MMMMMMMMMMABJMMM MMMMMMMMMMMAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 32 (broad short sword / dwarvish short sword) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMAONMMMMMMMMMM MMMMAONMMMMMMMMM MMMMMAONPMMMMMMM MMMMMAAONAPOMMMM MMMMMMMAOOMMMMMM MMMMMMAPOJJMMMMM MMMMMMAAAAJJMMMM MMMMMMMMMMAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 33 (curved sword / scimitar) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MANMMMMMMMMMMMMM MAPNMMMMMMMMMMMM MMAOOMMMMMMMMMMM MMAANOMMMMMMMMMM MMMAPNOMMMMMMMMM MMMMAPNNMMMMMMMM MMMMMAAONPOMMMMM MMMMMMMAPOAMMMMM MMMMMMAPOJKJMMMM MMMMMMMMAAJKJMMM MMMMMMMMMMAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 34 (silver saber) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNAMMM MMMMMMMMMMPOPAMM MMMMMMMMMPNOPAMM MMMMMMMMPNNPAMMM MMMMPPANNOPAMMMM MMMMMOOOAAMMMMMM MMMMMJJOPAMMMMMM MMMKJJAAAMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 35 (broadsword) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMMMMMMMMMM MMANNMMMMMMMMMMM MMAONNMMMMMMMMMM MMMAONNMMMMMMMMM MMMMAONNMMMMMMMM MMMMMAONNMMMMMMM MMMMMMAONNPOMMMM MMMMMMMAOOKMMMMM MMMMMMAPOAJKMMMM MMMMMMAAAAAJKMMM MMMMMMMMMMAAJMMM MMMMMMMMMMMAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 36 (runed broadsword / elven broadsword) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMMMMMMMMMMMM MMANNMMMMMMMMMMM MMAONNMMMMMMMMMM MMMAONNMMMMMMMMM MMMMAONNMMMMMMMM MMMMMAONNMMMMMMM MMMMMMAONNPOMMMM MMMMMMMAOOGMMMMM MMMMMMAPOFFGMMMM MMMMMMAAAAAFGMMM MMMMMMMMMMAAJMMM MMMMMMMMMMMAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 37 (long sword) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMOMM MMMMMMMMMMMMOPAM MMMMMMMMMMMOPAAM MMMMMMMMMMNPAAMM MMMMMMMMMNPAAMMM MMMMMMMMNPAAMMMM MMMMMMMNPAAMMMMM MMMMMMNOAAMMMMMM MMMMMNOAAMMMMMMM MMOPNOAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAOPMMMMMMMMM MNDAAMMMMMMMMMMM MAAAMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 38 (two-handed sword) { MMMMMMMMMMMMMMNM MMMMMMMMMMMMMNOM MMMMMMMMMMMMNOAM MMMMMMMMMMMNOAAM MMMMMMMMMMNOAAMM MMMMMMMMMNOAAMMM MMMMMMMMNOAAMMMM MMMMMMMNNAAMMMMM MMMMOPNNAAMMMMMM MMMMMKIIAMMMMMMM MMMMKJAOPMMMMMMM MMMKJAAAAMMMMMMM MMKJAAMMMMMMMMMM MNDAAMMMMMMMMMMM MAAAMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 39 (samurai sword / katana) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMNM MMMMMMMMMMMMMONM MMMMMMMMMMMMPNAM MMMMMMMMMMMMNPAM MMMMMMMMMMMOOAMM MMMMMMMMMMONAAMM MMMMMMMMMONPAMMM MMMMMMMMNNPAMMMM MMMMMOPNOAAMMMMM MMMMMAOPAMMMMMMM MMMMJKJOPAMMMMMM MMMJKJAAMMMMMMMM MMJJAAMMMMMMMMMM MMAAMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 40 (long samurai sword / tsurugi) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMNM MMMMMMMMMMMMMNPM MMMMMMMMMMMMNOAM MMMMMMMMMMMOOAMM MMMMMMMMMMONAMMM MMMMMMMMMONAMMMM MMMMMMMMNNAMMMMM MMMMMOPNOAMMMMMM MMMMMAOPAMMMMMMM MMMMJKJOPAMMMMMM MMMJKJAAMMMMMMMM MMJJAAMMMMMMMMMM MMAAMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 41 (runed broadsword / runesword) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMAMM MMMMMMMMMMMMAAPM MMMMMMMMMMMAAPPM MMMMMMMMMMAAPPMM MMMMMMMMMAAPPMMM MMMMMMMMAAPPMMMM MMMMMMMAAPPMMMMM MMMMMMAAPPMMMMMM MMMMMAAPPMMMMMMM MMOPAAPPMMMMMMMM MMMNNPPMMMMMMMMM MMNNPOPMMMMMMMMM MNNPPMMMMMMMMMMM MPPPMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 42 (vulgar polearm / partisan) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMPOM MMMMMMMMMMMMPNPM MMMMMMMMMMMONPAM MMMMMMMMMMONOAAM MMMMMMMMMMNOAAMM MMMMMMMMMKJAAMMM MMMMMMMMKJAAMMMM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MJJAAMMMMMMMMMMM JJAAMMMMMMMMMMMM } # tile 43 (hilted polearm / ranseur) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMPNM MMMMMMMMMMMMPNPM MMMMMMMMMMMPNOAM MMMMMMMPOPPNOAAM MMMMMMMOAONOAMMM MMMMMMMAAKOOPMMM MMMMMMMMKJAAOAMM MMMMMMMKJAAOPAMM MMMMMMKJAAMAAMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MJJAAMMMMMMMMMMM JJAAMMMMMMMMMMMM } # tile 44 (forked polearm / spetum) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMPNM MMMMMMMMMMMMPNPM MMMMMMMMPOMPNOAM MMMMMMMMOPANOAAM MMMMMMMMAONOAMMM MMMMMMMMAKOOPOAM MMMMMMMMKJAAOPAM MMMMMMMKJAAAAAMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MJJAAMMMMMMMMMMM JJAAMMMMMMMMMMMM } # tile 45 (single-edged polearm / glaive) { MMMMMMMMMMMMMKAM MMMMMMMMMMMMKNOA MMMMMMMMMMMKNNPA MMMMMMMMMMKNNPAM MMMMMMMMMKNNPAMM MMMMMMMMKNNPAMMM MMMMMMMKJAAAMMMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MKJAAMMMMMMMMMMM KJAAMMMMMMMMMMMM JAAMMMMMMMMMMMMM AAMMMMMMMMMMMMMM } # tile 46 (lance) { PAMMMMMMMMMMMMMM MPAMMMMMMMMMMMMM MMBAMMMMMMMMMMMM MMMOAMMMMMMMMMMM MMMMOAMMMMMMMMMM MMMMMNAMMMMMMMMM MMMMMMNAMMMMMMMM MMMMMMPNAMMMMMMM MMMMMMMPNAMMMMMM MMMMMMMMBNAMMMMM MMMMMMMMMONAMMMM MMMMMMMMMMNNOOOA MMMMMMMMMMOONOAM MMMMMMMMMMOOONOA MMMMMMMMMMOAMONO MMMMMMMMMMMMMMON } # tile 47 (angled poleaxe / halberd) { MMMMMMMMMMMMMMMM MMMMMMMMMOOOAMMM MMMMMMMMMPPPKKMM MMMMMMMMMPPKKOOM MMMMMMMMMMKJPPPA MMMMMMMMMKJAPPPA MMMMMMMMKJAMAAAM MMMMMMMKJAMMMMMM MMMMMMKJAMMMMMMM MMMMMKJAMMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MKJAAMMMMMMMMMMM JJAAMMMMMMMMMMMM JAAMMMMMMMMMMMMM } # tile 48 (long poleaxe / bardiche) { MMMMMMMMMMMMMNAM MMMMMMMMMMMMPOPA MMMMMMMMMMMPNOPA MMMMMMMMMMPNNPAM MMMMMMMMMNNOPAMM MMMMMMMMKOAAMMMM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MKJAAMMMMMMMMMMM JJAAMMMMMMMMMMMM JAAMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 49 (pole cleaver / voulge) { MMMMMMMMMMMMMNAM MMMMMMMMMMMMNNOA MMMMMMMMMMMNNNPA MMMMMMMMMMNNNPAM MMMMMMMMMNNOPAMM MMMMMMMMKOAAMMMM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MKJAAMMMMMMMMMMM KJAAMMMMMMMMMMMM JAAMMMMMMMMMMMMM AAMMMMMMMMMMMMMM } # tile 50 (broad pick / dwarvish mattock) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMONOAMMMMMM MMMMMMMMPNOAMMMM MMMMMMMMMNONAMMM MMMMMMMMKJAANAMM MMMMMMMKJAMMMNAM MMMMMMKJAMMMMMMM MMMMMKJAMMMMMMMM MMMMKJAMMMMMMMMM MMMKJAMMMMMMMMMM MMKJAMMMMMMMMMMM MKJAMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 51 (pole sickle / fauchard) { MMMMMMMMMMNNNMMM MMMMMMMMMNPPPNMM MMMMMMMMMNPAAPNM MMMMMMMMMNPAMANA MMMMMMMMMMNAMMAA MMMMMMMMMNPAMMMM MMMMMMMMKJAMMMMM MMMMMMMKJAMMMMMM MMMMMMKJAMMMMMMM MMMMMKJAMMMMMMMM MMMMKJAMMMMMMMMM MMMKJAMMMMMMMMMM MMKJAMMMMMMMMMMM MKJAMMMMMMMMMMMM KJAMMMMMMMMMMMMM MAMMMMMMMMMMMMMM } # tile 52 (pruning hook / guisarme) { MMMMMMMMMMMMMNAM MMMMMMMMMMMMPOPA MMMMMMPNNPMPNOPA MMMMMMNAANPNNPAM MMMMMMMAMNNOPAMM MMMMMMMMKOAAMMMM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MKJAAMMMMMMMMMMM KJAAMMMMMMMMMMMM JAAMMMMMMMMMMMMM AAMMMMMMMMMMMMMM } # tile 53 (hooked polearm / bill-guisarme) { MMMMMMMMMMMMMPNM MMMMMMMMMMMMPNAM MMMMMMMMMMMMPOPA MMMMMMPNNPMPNOPA MMMMMMNAANPNNPAM MMMMMMMAMNNOPAMM MMMMMMMMKOAAMMMM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMKKJAMMMMMMM MMMMMKJAMMMMMMMM MMMONJAMMMMMMMMM MMONOAAMMMMMMMMM MPNOAAMMMMMMMMMM PNPAAMMMMMMMMMMM OPAAMMMMMMMMMMMM } # tile 54 (pronged polearm / lucern hammer) { MMMMMMMMMNPMMMMM MMMMMMMMMPNPMMMM MMMMMMMMMAPPPKMM MMMMMMMMMMAPKPPO MMMMMMMMMMMKPPPO MMMMMMMMMMKAPPPP MMMMMMMMMKJAPPPA MMMMMMMMKJAMAAAM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMKJAAMMMMMMMMM MMKJAAMMMMMMMMMM MJJAAMMMMMMMMMMM JJAAMMMMMMMMMMMM } # tile 55 (beaked polearm / bec de corbin) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMPNMMMMMMMM MMMMMPNPAMMMMMMM MMMKPPPAAMMMMMMM AOPPKPAAMMMMMMMM MOPPPKAMMMMMMMMM MPPPPAKAMMMMMMMM MMPPPAMCAMMMMMMM MMMAAMMMCAMMMMMM MMMMMMMMMCAMMMMM MMMMMMMMMMCAMMMM MMMMMMMMMMMCAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 56 (mace) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMBABMMMM MMMMMMMMBMOMPAMM MMMMMMMMAOMBMAMM MMMMMMMMBMBMPAMM MMMMMMMMAPMPAAMM MMMMMMMKJAAAAMMM MMMMMMKJAMMMMMMM MMMMMKJAMMMMMMMM MMMMKJAMMMMMMMMM MMMKJAMMMMMMMMMM MMKJAMMMMMMMMMMM MMMAMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 57 (morning star) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMBABMMM MMMMMMMMMBMOMPAM MMMMMMMMMAOMBMAM MMMPPMMMMBMBMPAM MMPAAPMMMAPMPAAM MMPAAPMMPPAAAAMM MMPAMAPPAAMMMMMM MMPAMMAAMMMMMMMM MMMKAMMMMMMMMMMM MMMMKAMMMMMMMMMM MMMMMKAMMMMMMMMM MMMMMMKAMMMMMMMM MMMMMMMMMMMMMMMM } # tile 58 (war hammer) { MMMMMMMMMMOMMMMM MMMMMMMMMPPOAMMM MMMMMMMMMAPPKKMM MMMMMMMMMMAKKOOM MMMMMMMMMMKJAPPO MMMMMMMMMKJAAAPA MMMMMMMMKJAMMAAM MMMMMMMKJAMMMMMM MMMMMMKJAMMMMMMM MMMMMKJAMMMMMMMM MMMMKJAMMMMMMMMM MMMKJAMMMMMMMMMM MMKJAMMMMMMMMMMM MKJAMMMMMMMMMMMM MJAMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 59 (club) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMKKMMMM MMMMMMMMJCKKAMMM MMMMMMMKKKKKAMMM MMMMMMJKKKKJAMMM MMMMMMKKKCKAAMMM MMMMMJCKKKAAMMMM MMMMJKKKJAAMMMMM MMMJKKJAAMMMMMMM MMMKJAAMMMMMMMMM MMKJAMMMMMMMMMMM MKJAMMMMMMMMMMMM MJAMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 60 (rubber hose) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMFGFMMMMMM MMMMMFGAAAGFMMMM MMMMGAAMMMAAAMMM MMMMGAMMMMMMMMMM MMMMMGAMMMMMMMMM MMMMMMFGAMMMMMMM MMMMMMMMGAMMMMMM MMMMMMMMFAMMMMMM MMMMMMMGAMMMMMMM MMMGGGFAMMMMMMMM MMMMAAAMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 61 (staff / quarterstaff) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMJKM MMMMMMMMMMMMJCJA MMMMMMMMMMMJKJAM MMMMMMMMMMJCJAAM MMMMMMMMMJCJAAMM MMMMMMMMJKJAAMMM MMMMMMMJKJAAMMMM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMJJAAMMMMMMM MMMMKJAAMMMMMMMM MMMJJAAMMMMMMMMM MMKJAAMMMMMMMMMM MJJAAMMMMMMMMMMM MMAMMMMMMMMMMMMM } # tile 62 (thonged club / aklys) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMKJJJMMMM MMMMMMMMKJJAAMMM MMMMMMMKJJAAMMMM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMMKAAMMMMMMMM MMMMKAAMMMMMMMMM MMMMMAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 63 (flail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMKJMM MMMMMMMMMMMKJAMM MMMMMMMMMMKJAMMM MMMMMMMMMKJAMMMM MMMMMMMMKJAMMMMM MMMMMMMKJAMMMMMM MMMMMMKJAMMMMMMM MMMMMKJAMMMMMMMM MMMMPAMMMMMMMMMM MMMKJAMMMMMMMMMM MMMKAMMMMMMMMMMM MMKJAMMMMMMMMMMM MJKAMMMMMMMMMMMM MMJAMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 64 (bullwhip) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMKKKKKKMMM MMMMMKKAAAAAAKAM MMMMKAAMMMMMMKAM MMMKAMMMMMMMKAMM MMMKAMMMMMMMJAMM MMMKAMMMMMMMMJAM MMMMKKKKKKMMMMMM MMMMMAAAAAKAMMMM MPMMMMMMMMKAMMMM MAPPMMMMMMKAMMMM MMMAPKMMMKAMMMMM MMMMMAKKKAMMMMMM MMMMMMAAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 65 (bow) { MMMMMMMMMMMMMMMM MMMMMKMMMMMMMMMM MMMMMKPMMMMMMMMM MMMMMPKMMMMMMMMM MMMMMPKJMMMMMMMM MMMMMPMKJMMMMMMM MMMMMPMMKMMMMMMM MMMMMOMMLMMMMMMM MMMMMPMMOMMMMMMM MMMMMPMMJMMAAMMM MMMMMPMKJMMAMMMM MMMMMPKJMMAAMMMM MMMMMPKMMAAMMMMM MMMMMKPAAAMMMMMM MMMMMKAAMMMMMMMM MMMMMMMMMMMMMMMM } # tile 66 (runed bow / elven bow) { MMMMMKMMMMMMMMMM MMMMMKPMMMMMMMMM MMMMMPKMMMMMMMMM MMMMMPKJMMMMMMMM MMMMMPMKJMMMMMMM MMMMMPMMKMMMMMMM MMMMMPMMKJMMMMMM MMMMMPMMJLMMMMMM MMMMMOMMJJMMMMMM MMMMMPMMJLMMMMMM MMMMMPMMJMMAAMMM MMMMMPMKJMMAMMMM MMMMMPKJMMAAMMMM MMMMMPKMMAAMMMMM MMMMMKPAAAMMMMMM MMMMMKAAMMMMMMMM } # tile 67 (crude bow / orcish bow) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKKPMMMMMMMMM MMMMMPKMMMMMMMMM MMMMMPKJMMMMMMMM MMMMMPMKJMMMMMMM MMMMMPMMKMMMMMMM MMMMMOMMLMMMMMMM MMMMMPMMOMMMAMMM MMMMMPMMJMMAAMMM MMMMMPMKJMMAMMMM MMMMMPKJMMAAMMMM MMMMMPKMAAAMMMMM MMMMKKPAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 68 (long bow / yumi) { MMMMMLMMMMMMMMMM MMMMMLPMMMMMMMMM MMMMMPLMMMMMMMMM MMMMMPLOMMMMMMMM MMMMMPMLOMMMMMMM MMMMMPMMLMMMMMMM MMMMMPMMLOMMMMMM MMMMMPMMOLMMMMMM MMMMMPMMOOMMMMMM MMMMMPMMOLMMMMMM MMMMMPMMOMMAAMMM MMMMMPMLOMMAMMMM MMMMMPLOMMAAMMMM MMMMMPLMMAAMMMMM MMMMMLPAAAMMMMMM MMMMMLAAMMMMMMMM } # tile 69 (sling) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMJJJJMMMMMM MMMMMJAAAAJKMMMM MMMMJAMMMMMKKMMM MMMMMMMMMMJAKAMM MMMMMMJJKKAKKAMM MMMMJJAAAKKJJAMM MMMJAAMMMAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 70 (crossbow) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMCJJMMMMMM MMMMMMMDJJMMMMMM MMMMMDKJJJKMMMMM MMMDKJJJJJJJKMMM MMDJMMMDJJMMJKMM MMMMPMMCJJMPMMMM MMMMMPMCJJPMMMMM MMMMMMPCJPAAAAMM MMMMMMMPPAMAAAAM MMMMMMMCJJAAMMAM MMMMMMMOAOAMMMMM MMMMMMMMOAMMMMMM MMMMMMMMMMMMMMMM } # tile 71 (leather hat / elven leather helm) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMJKKJMMMMMMM MMMMJCKKKJMMMMMM MMMJCKKJJJAMMMMM MMMJKKJJJJAMMMMM MMMJAJJAAJAMMMMM MMMJAJJAMJAMMMMM MMMJAMAMJAMMMMMM MMMMJAMJAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 72 (iron skull cap / orcish helm) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPBBPMMMMMMM MMMMPNBBBPAMMMMM MMMPNBBPPPAMMMMM MMMPBBPPPPAMMMMM MMMJAPPAAJAMMMMM MMMJAPPAMJAMMMMM MMMJAMAMJAMMMMMM MMMMJAMJAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 73 (hard hat / dwarvish iron helm) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPMMMMMMMM MMMMPBBPPAMMMMMM MMMPBNPPPPAMMMMM MMMPNPPPPPAMMMMM MMMPPPPPPPAMMMMM MMMPAPPAAPAMMMMM MMMJAPPAMJAMMMMM MMMJAMAMJAMMMMMM MMMMJAMJAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 74 (fedora) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMAAAAMMMMMM MMMMMAAAAAAMMMMM MMMAAMAAAAAMMMMM MMMAAAMAAAMAMMMM MMMMAAAMMMAAAMMM MMMMKMAAAAAAMMMM MMMKAMMMKAMMMMMM MMMMKAMMKAMMMMMM MMMMMMMKAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 75 (conical hat / cornuthaum) { MMMMMMMMMMMMMMMM MMMMMMMEMMMMMMMM MMMMMMMEMMMMMMMM MMMMMMMBMMMMMMMM MMMMMMEBEMMMMMMM MMMMMMEBEMMMMAMM MMMMMMPBEMMMMAMM MMMMMEBBEEMMAAMM MMMMMEBBPEMAAAMM MMMMMPNBPEAAAMMM MMMMEBNBBEEAAMMM MMMMENNBBPEAAMMM MMMEBBBBPEAEAMMM MMMEEMMAMAEEMMMM MMMMEEEEEEEMMMMM MMMMMMMMMMMMMMMM } # tile 76 (conical hat / dunce cap) { MMMMMMMMMMMMMMMM MMMMMMMEMMMMMMMM MMMMMMMEMMMMMMMM MMMMMMMBMMMMMMMM MMMMMMEBEMMMMMMM MMMMMMEBEMMMMAMM MMMMMMPBEMMMMAMM MMMMMEBBEEMMAAMM MMMMMEBBPEMAAAMM MMMMMPNBPEAAAMMM MMMMEBNBBEEAAMMM MMMMENNBBPEAAMMM MMMEBBBBPEAEAMMM MMMEEMMAMAEEMMMM MMMMEEEEEEEMMMMM MMMMMMMMMMMMMMMM } # tile 77 (dented pot) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMJJMM MMMMMMMMMMMJJMMM MMMMMMMMMMJJMMMM MMMMMMMMMJJMMMAA MMMMMBPPPMJMMAAM MMMMBAAAMMPMAAMM MMMMBPAMMPMAAMMM MMMMBBPPPMMAAMMM MMMMBPPPMMMAAMMM MMMMMBBPPPAAAMMM MMMMMMAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 78 (plumed helmet / helmet) { MMMMMMMDIDMMMMMM MMMMMMDIBIMMMMMM MMMMMMIBIBMMMMMM MMMMMMDIBMMMMMMM MMMMMMMIMMMMMMMM MMMMMMPIPMMMMMMM MMMMMPNIPPAMMMMM MMMMPNBPPPPAMMMM MMMMPBPPPPPAMMMM MMMMPPPPPPPAMMMM MMMMPAPPAAPAMMMM MMMMJAPPAMJAMMMM MMMMMMMAAMMAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 79 (etched helmet / helm of brilliance) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMPPPMMMMMMM MMMMMPNBPPAMMMMM MMMMMNBPPPMAMMMM MMMMPMPMPMPAMMMM MMMMPPPPPPPAMMMM MMMMPAPPAAPAMMMM MMMMJAPPAMJAMMMM MMMMMMMAAMMAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 80 (crested helmet / helm of opposite alignment) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMHHHMMMMMMM MMMMMHHHMMMMMMMM MMMMMHHMMPAMMMMM MMMMPPHMMPPAMMMM MMMMPPPMPPPAMMMM MMMMPPPPPPPAMMMM MMMMPAPPAAPAMMMM MMMMJAPPAMJAMMMM MMMMMMMAAMMAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 81 (visored helmet / helm of telepathy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMPPPMMMMMMM MMMMMPNNPPAMMMMM MMMMPNNPPPPAMMMM MMMMPBBBBBPAMMMM MMMMPPPPPPPAMMMM MMMMPAAAAAPAMMMM MMMMJBPPPPJAMMMM MMMMMMPPAAAAMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 82 (gray dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNMMPMMMPMOAOA MNMNMPMMMPMMOAOA MMANPMMMPMMMOAMA MMMNMMMPMMMPOAMM MMMNMMPMMMPMOAMM MMMMNPMMMPMOAAMM MMMNMNMMPMOAOAMM MMNNNANPMOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 83 (silver dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOBOOMOM MNMNOBNOOBNOBAOA MNMNBNOOBNOBBAOA MMANNOOBNOBBBAMA MMMNOOBNOBBNBAMM MMMNOBNOBBNBBAMM MMMMNNOBBNBBAAMM MMMNMNBBNBBAOAMM MMNNNANNBBAOOOAM MNNNBAMNBAAOOOOA MMNBAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 84 (shimmering dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMBMBBBOOOMOMMM MBMBBBBBOOOOOMOM MBMBEEFFGGHHOAOA MBMBEFFGGHHCOACA MMABFFGGHHCDOAMA MMMBFGGHHCDDOAMM MMMBGGHHCDDKOAMM MMMMBHHCDDKOAAMM MMMBMBCDDKOAOAMM MMBBBABDKOAOOCAM MBBBOAMBBAAOOOCA MMBOAAMMMMMMKCAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 85 (red dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNDDIDDDIDOAOA MNMNDIDDDIDDOAOA MMANIDDDIDDDOAMA MMMNDDDIDDDIOAMM MMMNDDIDDDIDOAMM MMMMNIDDDIDOAAMM MMMNMNDDIDOAOAMM MMNNNANIDOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 86 (white dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNOONOOONOOAOA MNMNONOOONOOOAOA MMANNOOONOOOOAMA MMMNOOONOOONOAMM MMMNOONOOONOOAMM MMMMNNOOONOOAAMM MMMNMNOONOOAOAMM MMNNNANNOOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 87 (orange dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNCCLCCCLCOAOA MNMNCLCCCLCCOAOA MMANLCCCLCCCOAMA MMMNCCCLCCCLOAMM MMMNCCLCCCLCOAMM MMMMNLCCCLCOAAMM MMMNMNCCLCOAOAMM MMNNNANLCOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 88 (black dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNAAMAAAMAOAOA MNMNAMAAAMAAOAOA MMANMAAAMAAAOAMA MMMNAAAMAAAMOAMM MMMNAAMAAAMAOAMM MMMMNMAAAMAOAAMM MMMNMNAAMAOAOAMM MMNNNANMAOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 89 (blue dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNEEBEEEBEOAOA MNMNEBEEEBEEOAOA MMANBEEEBEEEOAMA MMMNEEEBEEEBOAMM MMMNEEBEEEBEOAMM MMMMNBEEEBEOAAMM MMMNMNEEBEOAOAMM MMNNNANBEOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 90 (green dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNFFGFFFGFOAOA MNMNFGFFFGFFOAOA MMANGFFFGFFFOAMA MMMNFFFGFFFGOAMM MMMNFFGFFFGFOAMM MMMMNGFFFGFOAAMM MMMNMNFFGFOAOAMM MMNNNANGFOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 91 (yellow dragon scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNHHNHHHNHOAOA MNMNHNHHHNHHOAOA MMANNHHHNHHHOAMA MMMNHHHNHHHNOAMM MMMNHHNHHHNHOAMM MMMMNNHHHNHOAAMM MMMNMNHHNHOAOAMM MMNNNANNHOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 92 (gray dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMPMMMMMMM MMMMMMMPPPMMMMMM MMMMPMPPPPAMMMMM MMMPPPMPPAAPMMMM MMPPPPAPAAPPAMMM MMMPPAAPPAPAAMMM MMMMAAPPAAAAMMMM MMMMMMMAAPAMMMMM MMMMMMMPPAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 93 (silver dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMNMMMMMMM MMMMMMMNNNMMMMMM MMMMNMNNNNAMMMMM MMMNNNMNNAANMMMM MMNNNNANAANNAMMM MMMNNAANNANAAMMM MMMMAANNAAAAMMMM MMMMMMMAANAMMMMM MMMMMMMNNAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 94 (shimmering dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMPMMMMMMM MMMMMMMPPPMMMMMM MMMMEMPPFPAMMMMM MMMEBBMFFAAHMMMM MMEBBPAFAAHDAMMM MMMEBAAGGADAAMMM MMMMAAGGAAAAMMMM MMMMMMMAADAMMMMM MMMMMMMGHAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 95 (red dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMDMMMMMMM MMMMMMMDDDMMMMMM MMMMDMDDDDAMMMMM MMMDDDMDDAADMMMM MMDDDDADAADDAMMM MMMDDAADDADAAMMM MMMMAADDAAAAMMMM MMMMMMMAADAMMMMM MMMMMMMDDAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 96 (white dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMOMMMMMMM MMMMMMMOOOMMMMMM MMMMOMOOOOAMMMMM MMMOOOMOOAAOMMMM MMOOOOAOAAOOAMMM MMMOOAAOOAOAAMMM MMMMAAOOAAAAMMMM MMMMMMMAAOAMMMMM MMMMMMMOOAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 97 (orange dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMCMMMMMMM MMMMMMMCCCMMMMMM MMMMCMCCCCAMMMMM MMMCCCMCCAACMMMM MMCCCCACAACCAMMM MMMCCAACCACAAMMM MMMMAACCAAAAMMMM MMMMMMMAACAMMMMM MMMMMMMCCAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 98 (black dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMAMMMMMMM MMMMMMMAAAMMMMMM MMMMAMAAAAPMMMMM MMMAAAMAAPAAMMMM MMAAAAPAPAAAPMMM MMMAAPAAAPAPPMMM MMMMPAAAPAPPMMMM MMMMMMMPAAPMMMMM MMMMMMMAAPPMMMMM MMMMMMMMPPMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 99 (blue dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMEMMMMMMM MMMMMMMEEEMMMMMM MMMMEMEEEEAMMMMM MMMEEEMEEAAEMMMM MMEEEEAEAAEEAMMM MMMEEAAEEAEAAMMM MMMMAAEEAAAAMMMM MMMMMMMAAEAMMMMM MMMMMMMEEAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 100 (green dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMFMMMMMMM MMMMMMMFFFMMMMMM MMMMFMFFFFAMMMMM MMMFFFMFFAAFMMMM MMFFFFAFAAFFAMMM MMMFFAAFFAFAAMMM MMMMAAFFAAAAMMMM MMMMMMMAAFAMMMMM MMMMMMMFFAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 101 (yellow dragon scales) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMHMMMMMMM MMMMMMMHHHMMMMMM MMMMHMHHHHAMMMMM MMMHHHMHHAAHMMMM MMHHHHAHAAHHAMMM MMMHHAAHHAHAAMMM MMMMAAHHAAAAMMMM MMMMMMMAAHAMMMMM MMMMMMMHHAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 102 (plate mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNNNNNOOOOOAOA MNMNNNNONOOOOAOA MMANNNOONNOOOAMA MMMNNNOONNOOOAMM MMMNNNNONOOOOAMM MMMMNNNNOOOOAAMM MMMNMNNNOOOAOAMM MMNNNANNOOAOOOAM MNNNOAMNOAAOOOOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 103 (crystal plate mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNBBBMBMMM MNMNNNNNBBBBBMBM MNMNNNNNBBBBBABA MNMNNNNBNBBBBABA MMANNNBBNNBBBAMA MMMNNNBBNNBBBAMM MMMNNNNBNBBBBAMM MMMMNNNNBBBBAAMM MMMNMNNNBBBABAMM MMNNNANNBBABBBAM MNNNBAMNBAABBBBA MMNBAAMMMMMMBBAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 104 (bronze plate mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMLMLLLCCCMCMMM MLMLLLLLCCCCCMCM MLMLLLLLCCCCCACA MLMLLLLCLCCCCACA MMALLLCCLLCCCAMA MMMLLLCCLLCCCAMM MMMLLLLCLCCCCAMM MMMMLLLLCCCCAAMM MMMLMLLLCCCACAMM MMLLLALLCCACCCAM MLLLCAMLCAACCCCA MMLCAAMMMMMMCCAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 105 (splint mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MJMNPPPPMMMMOAJA MNMNKKKKJJJJOAOA MMANPPPPMMMMOAMA MMMNKKKKJJJJOAMM MMMNPPPPMMMMOAMM MMMMNKKKJJJOAAMM MMMNMNPPMMOAOAMM MMNPNANKJOAOPOAM MNPJOAMNOAAOJPOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 106 (banded mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MPMNPNPPPPOPOAPA MNMNMMMMMMMMOAOA MMANPNPPPPOPOAMA MMMNMMMMMMMMOAMM MMMNPNPPPPOPOAMM MMMMNMMMMMMOAAMM MMMNMNPNOPOAOAMM MMNPNANMMOAOPOAM MNPMOAMNOAAOMPOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 107 (dwarvish mithril-coat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNNNNNOOOOOMMM MNMNANANAPAPOMOM MNMNNANAPAPAOAOA MNMNANANAPAPOAOA MMANNANAPAPAOAMA MMMNANANAPAPOAMM MMMNNANAPAPAOAMM MMMMNNANAPAOAAMM MMMNMNNAPAOAOAMM MMNPNANNAOAOMOAM MNPNOAMNOAAOOMOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 108 (elven mithril-coat) { MMMMMMMMMMMMMMMM MMMNMNMNOMOMOMMM MMMNNNNNOOOOOMMM MNMNANANAOAOOMOM MNMONANAPAPAOAOA MNMNANANAPAPOAOA MMAONANAPAPAOAMA MMMNANANAPAPOAMM MMMONANAPAPAOAMM MMMMONANAPAOAAMM MMMNMONAPAOAOAMM MMNPNAONAOAOMOAM MNPNOAMOOAAOOMOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 109 (chain mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MNMNPAPAMAMAOAOA MNMNAPAPAMAMOAOA MMANPAPAMAMAOAMA MMMNAPAPAMAMOAMM MMMNPAPAMAMAOAMM MMMMNPAPAMAOAAMM MMMNMNPAMAOAOAMM MMNPNANPAOAOMOAM MNPNOAMNOAAOOMOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 110 (crude chain mail / orcish chain mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMKMKKKJJJMJMMM MKMKKKKKJJJJJMJM MKMKPAPAMAMAJAJA MKMKAPAPAMAMJAJA MMAKPAPAMAMAJAMA MMMKAPAPAMAMJAMM MMMKPAPAMAMAJAMM MMMMKPAPAMAJAAMM MMMKMKPAMAJAJAMM MMKKKAKPAJAJJJAM MKKKJAMKJAAJJJJA MMKJAAMMMMMMJJAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 111 (scale mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MPMNPAPAAMAMOAMA MNMNAPPPMMMAOAOA MMANPAPAAMAMOAMA MMMNPPAPMAMMOAMM MMMNPAPAAMAMOAMM MMMMNPPPMMMOAAMM MMMNMNPAAMOAOAMM MMNPNANPMOAOMOAM MNPPOAMNOAAOMMOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 112 (studded leather armor) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MKMNKKKKJJJJOAKA MKMNKNKNOJOJOAKA MMANKKKKJJJJOAMA MMMNKNKNOJOJOAMM MMMNKKKKJJJJOAMM MMMMNKNKJOJOAAMM MMMNMNKKJJOAOAMM MMNKKANKJOAOKKAM MNKKJAMNOAAOKKKA MMKJAAMMMMMMKKAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 113 (ring mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MNMNNNNNOOOOOMOM MPMNPAAPMAAMOAMA MNMNABPAAMPAOAOA MMANAPBAAPMAOAMA MMMNPAAPMAAMOAMM MMMNAPBAAPMAOAMM MMMMNBPAAMPOAAMM MMMNMNAPMAOAOAMM MMNPNANAAOAOMOAM MNPBOAMNOAAOPMOA MMNOAAMMMMMMOOAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 114 (crude ring mail / orcish ring mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMKMKKKJJJMJMMM MKMKKKKKJJJJJMJM MBMKPAAPMAAMJAPA MKMKABPAAMPAJAJA MMAKAPBAAPMAJAMA MMMKPAAPMAAMJAMM MMMKAPBAAPMAJAMM MMMMKBPAAMPJAAMM MMMKMKAPMAJAJAMM MMKPKAKAAJAJMJAM MKPBJAMKJAAJPMJA MMKJAAMMMMMMJJAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 115 (leather armor) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MKMNNNNNOOOOOMJM MKMNKKKKJJJJOAJA MKMNKKKJKJJJOAJA MMANKKJJKKJJOAMA MMMNKKJJKKJJOAMM MMMNKKKJKJJJOAMM MMMMNKKKJJJOAAMM MMMKMNKKJJOAJAMM MMKKKANKJOAJJJAM MKKKJAMNOAAJJJJA MMKJAAMMMMMMJJAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 116 (leather jacket) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKAMJAMMMMM MMMMKKKKJJJJAMMM MMMKKKKKJLJJJAMM MMKKKKKKJJJJJJAM MMMKAKKKJLJAJAAM MMMMMKKKJJJAMAMM MMMMMKKKJLJAMMMM MMMMMKKKJJJAMMMM MMMMMMAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 117 (Hawaiian shirt) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCMMMMMCMMMMM MMMGCGGGGGCHMMMM MMGGHCGGGCHHHMMM MHHHJHCCCHJHHHMM MMHHJHHCHHJHHAAM MMMMGHHCGGHAAAMM MMMMHHHCGGHAMMMM MMMMGGHCHHHAMMMM MMMMGGHCHGGAMMMM MMMMHHHCHHHAMMMM MMMMMAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 118 (T-shirt) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPMMMMMPMMMMM MMMNPOOOOOPNMMMM MMNNNPOOOPNNNMMM MNNNONPPPNONNNMM MMNNONNNNNONNAAM MMMMNDODODNAAAMM MMMMNNNNNNNAMMMM MMMMNDODODNAMMMM MMMMNNNNNNNAMMMM MMMMNNNNNNNAMMMM MMMMMAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 119 (mummy wrapping) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMOMM MMMMMMMNMMNMMOMM MMMMOMONOMNNANMM MMMMMNONOMANNOMM OMMMONOOODNNOAAM MOOODNNONNNAOOAM MMAMNNOOAOAAOAAM MMMOODOOAAOOOAMM MMNMAANMNAMOOMMM MMMMMMMMMMMMMMMM } # tile 120 (faded pall / elven cloak) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMOFFMMFOMMMMM MMMMMOFFFOAAMMMM MMMMMMOFOAAMMMMM MMMMMOGAGFAMMMMM MMMMOGOAOFFAMMMM MMMOGOAAGFFFAMMM MMOGOGAAOFFFFAMM MMOOGAAFFOFFFAMM MMOGOAAFFGFFFAMM MMMOGAFFFFGFAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 121 (coarse mantelet / orcish cloak) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCJKMKKCMMMMM MMMMMCJKKCAAMMMM MMMMMMCKCAAMMMMM MMMMMCCACKAMMMMM MMMMCCCACKKAMMMM MMMCCCAACKKKAMMM MMCCCCAACKKKKAMM MMCCCAAJJCKKKAMM MMCCCAAJJCKKKAMM MMMCCAJJJJCKAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 122 (hooded cloak / dwarvish cloak) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMBBPMMMMMMM MMMMMBBBBPMMMMMM MMMMBPAAAPPMMMMM MMMMMBPAPPAAMMMM MMMMMMBPPAAMMMMM MMMMMBBABPAMMMMM MMMMBBBABPPAMMMM MMMBBBAABPPPAMMM MMBBBBAMMBPPPAMM MMMBBAMMMMBPAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 123 (slippery cloak / oilskin cloak) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJAAMAAJMMMMM MMMMMJAAAJAAMMMM MMMMMMJAJAAMMMMM MMMMMJJAJAAMMMMM MMMMJJJAJAAAMMMM MMMJJJAAJAAAAMMM MMJJJJAAJAAAAAMM MMJJJAAAAJAAAAMM MMJJJAAAAJAAAAMM MMMJJAAAAAJAAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 124 (robe) { MMMMMMMMMMMMMMMM MMMMMMCCCMMMMMMM MMMMMCAAAKAMMMMM MMMMCCAJJKKAMMMM MMMMMCAJJKAAMMMM MMMMMCCJKKAAMMMM MMMMCCCAKKKAMMMM MMMMCCCCAKKAAMMM MMMCCCCCCAKKAMMM MMMCCCCCCAKKAMMM MMMCCCCCCCAKAMMM MMMCCCCCCCAKAMMM MMMCCCCCCCAKAMMM MMMCCCCCCCAKAMMM MMMACCCCCCAAAMMM MMMMAAAAAAAAMMMM } # tile 125 (apron / alchemy smock) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMNOMMNOMMMMM MMMMMNAOMNAOMMMM MMMMMNAOMNAOAMMM MMMMMNNNNNAOAMMM MMMMMNNNNNOOAMMM MMMMMNNNNNOOAMMM MMMMONNNNNOAAMMM MMMMONNNNNNAAMMM MMMMNNNNNNNAAMMM MMMMNNNNNNNAAMMM MMMMNNNNNNNAAMMM MMMMNNNNNNNAAMMM MMMMMNNNNNAAMMMM MMMMMMAAAAAMMMMM } # tile 126 (leather cloak) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKJJMJJKMMMMM MMMMMKJJJKAAMMMM MMMMMMKJKAAMMMMM MMMMMKKAKJAMMMMM MMMMKKKAKJJAMMMM MMMKKKAAKJJJAMMM MMKKKKAAKJJJJAMM MMKKKAAJJKJJJAMM MMKKKAAJJKJJJAMM MMMKKAJJJJKJAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 127 (tattered cape / cloak of protection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMPOMMMMM MMMOOOPPPOAAMMMM MMMMMMOPOAAMMMMM MMMMMOOAOPAMMMMM MMMMOOOAOPPAMMMM MMMOOOAAOPPPAMMM MMOOOOAAOPPPPAMM MMOOOAAPPOPPAMMM MMMOOAAPPOPAMMMM MMOOOAMMAPOPAMMM MMMAAMMMMAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 128 (opera cloak / cloak of invisibility) { MMMMMMMMMMMMMMMM MMMMMMNNNMMMMMMM MMMMMNAAAOMMMMMM MMMMNNAAAOOAMMMM MMMMMNAAAOAMMMMM MMMMMNNAOOAAMMMM MMMMNNNAOOOAAMMM MMMNNNNNAOOOAAMM MMNNNNNNNAOOOAAM MMNNNNNNNAOOOOAM MNNNNNNNNNAOOOAM MNNNNNNNNNAOOOAM MNNNNNNNNNNAOOAM MNNNNNNNNNNAOOAM MMAANNNNNNAOOAAM MMMMAAAAAAAAAAMM } # tile 129 (ornamental cope / cloak of magic resistance) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMAAAMMAAMMMMM MMMMMAAAAAPPMMMM MMMMMMAAAPPMMMMM MMMMMAAAAAPMMMMM MMMMAAAAAAAPMMMM MMMAAAAAAAAAPMMM MMMAAAAAAAAAPPMM MMAAAAAAAAAAAPMM MMAAAAAAAAAAAPMM MMAAAAAAAAAAAPMM MMAAAAAAAAAAAPMM MMAAAAAAAAAAAPMM MMMPPPPPPPPPPPMM } # tile 130 (piece of cloth / cloak of displacement) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMPMMMMMMM MMMMMMMPPPAMMMMM MMMMMMPPPBPAAMMM MMMMMPBPBPPPAAMM MMMMPPPBPPPPBAAM MMMPPPBPPBPBPPAA MMPBPBPPPPBPPPPA MPPPBPPPPBPBPPPA MPPBPBPPBPPPBPAA MMBPPPPBPPPPPAAM MMMPPPBPBPPPAAMM MMMMPBPPPBPAAMMM MMMMMPPPPPAAMMMM MMMMMMMPPAAMMMMM } # tile 131 (small shield) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMCMCJJMJMMMMMM MMMCCKKJJJAMMMMM MMMCKKKJJJAMMMMM MMMCKKJJJJAMMMMM MMMCKKJJJJAMMMMM MMMMCKKJJAAMMMMM MMMMMCKJAAMMMMMM MMMMMMCAAMMMMMMM MMMMMMMAMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 132 (blue and green shield / elven shield) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNNMNMMMMM MMMNNNGFNNNAMMMM MMMNGGGFFFNAMMMM MMMNGGFFFFNAMMMM MMMNGGFFFFNAMMMM MMMNGGFFFFNAMMMM MMMMNGGFFNAAMMMM MMMMMNGFNAAMMMMM MMMMMMNNAAMMMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 133 (white-handed shield / Uruk-hai shield) { MMMMMMMMMMMMMMMM MMMKMKKKJJJMJMMM MMMKKKKKJJJJJMMM MMMKPPPPMMMMJAMM MMMKPPPNOOMMJAMM MMMKPPPNOOOMJAMM MMMKPNPNOOOMJAMM MMMKPNNNOOOMJAMM MMMKPPNNOOMMJAMM MMMKPPPNOMMMJAMM MMMMKPPNOMMJAAMM MMMMMKPPMMJAAMMM MMMMMMKPMJAAMMMM MMMMMMMKJAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 134 (red-eyed shield / orcish shield) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMKMKKKJJJMJMMM MMMKKKKKJJJJJMMM MMMKPPPPMMMMJAMM MMMKPPDDDDMMJAMM MMMKPDDAADDMJAMM MMMKPDDAADDMJAMM MMMKPPDDDDMMJAMM MMMMKPPPMMMJAAMM MMMMMKPPMMJAAMMM MMMMMMKPMJAAMMMM MMMMMMMKJAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 135 (large shield) { MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MMMNNNNNOOOOOMMM MMMNPPPPPMMMOAMM MMMNPPPMMMMMOAMM MMMNPPPMMMMMOAMM MMMNPPPPPMMMOAMM MMMNPPPMMMMMOAMM MMMNPPPMMMMMOAMM MMMNPPPPPMMMOAMM MMMMNPPMMMMOAAMM MMMMMNPMMMOAAMMM MMMMMMNPPOAAMMMM MMMMMMMNOAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 136 (large round shield / dwarvish roundshield) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMBBBPMMMMMMM MMMMBKKKKPMMMMMM MMMBKKKKKJPMMMMM MMMBKKKJJJPAMMMM MMMBKKJJJJPAMMMM MMMBKKJJJJPAMMMM MMMMPJJJJPAAMMMM MMMMMPPPPAAMMMMM MMMMMMAAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 137 (polished silver shield / shield of reflection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNMNNNOOOMOMMM MMMNNNNNOOOOOMMM MMMNPPPPPPPPOAMM MMMNPNNPPPPPOAMM MMMNPNNPPPPPOAMM MMMNPPPPPPPPOAMM MMMNPPPPPPPPOAMM MMMMNPPPPPPOAAMM MMMMMNPPPPOAAMMM MMMMMMNPPOAAMMMM MMMMMMMNOAAMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 138 (old gloves / leather gloves) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMKJMMMMMMM MMMMKJMKJMKJMMMM MMMMKJAJJAKJMMMM MMKJMJJAJJAJJMMM MMKJAJJAJJAJJAMM MMMJJAJKJJKJJAMM MMMMJKJJJJJJJAMM MMMKAJJJJJJJJAMM MMMKJJJJJJJJJJAM MMMMJJJJJJJJJJAM MMMMMAAAJJJJJAAM MMMMMMMMAJJJAAMM MMMMMMMMMAAAMMMM MMMMMMMMMMMMMMMM } # tile 139 (padded gloves / gauntlets of fumbling) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMKJMMMMMMM MMMMKJMKJMKJMMMM MMMMKJAJJAKJMMMM MMKJMKJAKJAKJMMM MMKJAJKAKJAKJAMM MMMKJAJKKJKKJAMM MMMMKKJJKJJKJAMM MMMKAJKKKKKKJAMM MMMKKKKKKKKKJJAM MMMMJJJJJKKKKJAM MMMMMAAAJJKKKAAM MMMMMMMMAJJKAAMM MMMMMMMMMAAAMMMM MMMMMMMMMMMMMMMM } # tile 140 (riding gloves / gauntlets of power) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKKJJAMMMMMMM MMMKJJJJJAMMMMMM MMKJJJJJJJAMMMMM MMKJJJJJJJAMMMMM MMMJJJJJJJJAMMMM MMMMJKJJJJJJAMMM MMMKAJJJJJJJAMMM MMMKJJJJJJJJJAMM MMMMJJJJJJJJJJAM MMMMMAAAJJJJJAAM MMMMMMMMAJJJAAMM MMMMMMMMMAAAMMMM MMMMMMMMMMMMMMMM } # tile 141 (fencing gloves / gauntlets of dexterity) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMNOMMMMMMM MMMMNOMNOMNOMMMM MMMMNOAOOANOMMMM MMNOMOOAOOAOOMMM MMNOAOOAOOAOOAMM MMMOOAONOONOOAMM MMMMONOOOOOOOAMM MMMNAOOOOOOOOAMM MMMNOOOOOOOOOOAM MMMMOOOOOOOOOOAM MMMMMAAAOOOOOAAM MMMMMMMMAOOOAAMM MMMMMMMMMAAAMMMM MMMMMMMMMMMMMMMM } # tile 142 (walking shoes / low boots) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMKJKKJMMM MMMCKLKLKJJKJAMM MMCKKLKLKJKKJAMM MMKKKKKKKKKKJAMM MMJJJJJJJJJJJAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 143 (hard shoes / iron shoes) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMPPBBPMMM MMMMMMMMPNPPPAMM MMMMMMMMPPPPMAMM MMMOPNPNMPPPMAMM MMOPPPPNPMMMMAMM MMPPPPPPPPPPMAMM MMMPMMMMMMMMMAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 144 (jackboots / high boots) { MMMMMMMCCKKKKMMM MMMMMMCKAAAAJJMM MMMMMMKKKKKKKJAM MMMMMMMJKKKKKJAM MMMMMMMKJKKKKJAM MMMMMMMMJKKKKAMM MMMMMMMMJKKKKAMM MMMMMMMMJKKKKAMM MMMMMMMMKJKKJAMM MMMCKLKLKJJKJAMM MMCKKLKLKJKKJAMM MMKKKKKKKKKKJAMM MMJJJJJJJJJJJAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 145 (combat boots / speed boots) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMGGFFFFMMM MMMMMMGFAAAAMMMM MMMMMMFFFFFFFMAM MMMMMMMMFFFFFMAM MMMMMMMKMFFFFMAM MMMMMMMMMFFFFAMM MMMMMMMMFMFFMAMM MMMGFLFLFMMFMAMM MMGFFLFLFMFFMAMM MMFFFFFFFFFFMAMM MMJMMMMMMMMMMAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 146 (jungle boots / water walking boots) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMGGGGGGMMM MMMMMMGFAAAAJJMM MMMMMMFFFFFFFJAM MMMMMMMGFFFFFJAM MMMMMMMKGFFFFJAM MMMMMMMMGFFFFAMM MMMMMMMMFGFFJAMM MMMGFLFLFGGFJAMM MMGFFLFLFGFFJAMM MMFFFFFFFFFFJAMM MMJJJJJJJJJJJAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 147 (hiking boots / jumping boots) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMCCKKKJAM MMMMMMMCAAAAKJAM MMMMMMMKJKKKKJAM MMMMMMMMJKKKKAMM MMMMMMMMKJKKJAMM MMMCKLKLKJJKJAMM MMCKKLKLKJKKJAMM MMKKKKKKKKKKJAMM MMJJJJJJJJJJJAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 148 (mud boots / elven boots) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMCCKKKKMMM MMMMMMCKAAAAJJMM MMMMMMKKKKKKKJAM MMMMMMMJKKKKKJAM MMMMMMMKJKKKKJAM MMMMMMMMJKKKKAMM MMMMMMMMKJKKJAMM MMMCKLKLKJJKJAMM MMCKKLKLKJKKJAMM MMKKKKKKKKKKJAMM MMJJJJJJJJJJJAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 149 (buckled boots / kicking boots) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMCCKKKKMMM MMMMMMCKAAAAJJMM MMMMMMKKKKKKKJAM MMMMMMMJKKKKKJAM MMMMMMMCJKKKKJAM MMMMMMHOOKKKCAMM MMMCKHKKHCCCCAMM MMCKKLOHCCCCJAMM MCKKKKKKKJKKJAMM MCKKKKKKKKKKJAMM MMJJJJJJJJJJJAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 150 (riding boots / fumble boots) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMLLLLLLMMM MMMMMMLAAAAAALMM MMMMMMLAAAAAALPM MMMMMMMLLLLLLAPM MMMMMMMAAAAAAAPM MMMMMMMMAAAAAPMM MMMMMMMMAAAAAPMM MMMAALALAAAAAPMM MMAAALALAAAAAPMM MMAAAAAAAAAAAPMM MMMAAAAAAAAAAPMM MMMPPPPPPPPPPPMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 151 (snow boots / levitation boots) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMNNLLLLMMM MMMMMMNOAAAALLMM MMMMMMOOOOOOOLAM MMMMMMMLOOOOOLAM MMMMMMMLLOOOOLAM MMMMMMMMLOOOOAMM MMMMMMMMOLOOLAMM MMMNOAOAOLLOLAMM MMNOOAOAOLOOOLAM MOOOOOOOOOOOOOAM MOOOOOOOOOOOOOAM MMLALALALALALAAM MMMAMAMAMAMAMAMM MMMMMMMMMMMMMMMM } # tile 152 (wooden / adornment) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMKCCKJMMMMMM MMMMKJAAAKJMMMMM MMMMCAMMMAKAMMMM MMMMCAMMMMKAMMMM MMMMJKAMMKJAMMMM MMMMMJKKKJAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 153 (granite / gain strength) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPPPMMMMMM MMMMPBPBPPPMMMMM MMMPPPAAAPBPMMMM MMMPBAAAAAPPAMMM MMMPPAAMMMPPAMMM MMMBPPAMMPPBAMMM MMMMPPPPPBPAAMMM MMMMMPBPPPAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 154 (opal / gain constitution) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMOIOMMMMMMM MMMMMOIOBOAMMMMM MMMMMOOOBOAMMMMM MMMMMCOGOCAMMMMM MMMMHHAAAHNAMMMM MMMMHAAMMMHAMMMM MMMMNHAMMHNAMMMM MMMMMHNHNHAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 155 (clay / increase accuracy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLLLLLMMMMMM MMMMLCCCCLLMMMMM MMMLCCAAALLCMMMM MMMLCAAAAALCAMMM MMMLCAAMMMLCAMMM MMMLCCAMMLLCAMMM MMMMLLLLLCCAAMMM MMMMMCCCCCAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 156 (coral / increase damage) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOOOOOMMMMMM MMMMOOAAAOOMMMMM MMMMOAAMMMNAMMMM MMMMOAMMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 157 (black onyx / protection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMANAAAMMMMMM MMMMMAAAAAMMMMMM MMMMMMAAAMMMMMMM MMMMMOLLLNAMMMMM MMMMOOAAAONAMMMM MMMMOAAMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 158 (moonstone / regeneration) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMOBOMMMMMMM MMMMMOBOOOAMMMMM MMMMMOOOOOAMMMMM MMMMMCCCCCAMMMMM MMMMHHAAAHNAMMMM MMMMHAAMMMHAMMMM MMMMNHAMMHNAMMMM MMMMMHNHNHAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 159 (tiger eye / searching) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMKCACKAMMMMM MMMMMCCACCAMMMMM MMMMMACCCAMMMMMM MMMMMOCOCNAMMMMM MMMMOOAAAONAMMMM MMMMOAAMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 160 (jade / stealth) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMNFFMMMMMMM MMMMMFFFFFAMMMMM MMMMMFFFFFAMMMMM MMMMMOLLLNAMMMMM MMMMOOAAAONAMMMM MMMMOAAMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 161 (bronze / sustain ability) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMCHCCCMMMMMM MMMMCHAAACCMMMMM MMMMCAAMMACAMMMM MMMMCAMMMMCAMMMM MMMMCCAMMCCAMMMM MMMMMCCCCCAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 162 (agate / levitation) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPNOOPAMMMMM MMMMMOIOIOAMMMMM MMMMMAOIOAMMMMMM MMMMMLHHHLAMMMMM MMMMLHAAAHLAMMMM MMMMHAAMMMHAMMMM MMMMLHAMMHLAMMMM MMMMMLHHHLAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 163 (topaz / hunger) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPNBBPAMMMMM MMMMMBOOOBAMMMMM MMMMMABBBAMMMMMM MMMMMOLLLNAMMMMM MMMMOOAAAONAMMMM MMMMOAAMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 164 (sapphire / aggravate monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMNEEMMMMMMM MMMMMEEEEFAMMMMM MMMMMAEEFAMMMMMM MMMMMOFEFNAMMMMM MMMMOOAAAONAMMMM MMMMOAAMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 165 (ruby / conflict) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMJLDDJAMMMMM MMMMMDDDDDAMMMMM MMMMMADDDAMMMMMM MMMMMOLLLNAMMMMM MMMMOOAAAONAMMMM MMMMOAAMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 166 (diamond / warning) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPNNNPAMMMMM MMMMMNNNNBAMMMMM MMMMMANNBAMMMMMM MMMMMPPPPPAMMMMM MMMMPPAAAPPAMMMM MMMMPAAMMMPAMMMM MMMMPPAMMPPAMMMM MMMMMPPPPPAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 167 (pearl / poison resistance) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMNNNMMMMMMM MMMMMNONNNAMMMMM MMMMMNNNNNAMMMMM MMMMMANNNAMMMMMM MMMMMLHHHLAMMMMM MMMMLHAAAHLAMMMM MMMMHAAMMMHAMMMM MMMMLHAMMHLAMMMM MMMMMLHHHLAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 168 (iron / fire resistance) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPPPMMMMMM MMMMPPAAAPPMMMMM MMMMPAMMMMPAMMMM MMMMPAMMMMPAMMMM MMMMPPAMMPPAMMMM MMMMMPPPPPAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 169 (brass / cold resistance) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMHHHCCMMMMMM MMMMHCAAACCMMMMM MMMMHAAMMMCAMMMM MMMMCAMMMMHAMMMM MMMMCCAMMHCAMMMM MMMMMCCCHCAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 170 (copper / shock resistance) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMCCCCCMMMMMM MMMMCCAAACCMMMMM MMMMCAAMMACAMMMM MMMMCAMMMMCAMMMM MMMMCCAMMCCAMMMM MMMMMCCCCCAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 171 (twisted / free action) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMAPPBPMMMMMM MMMMPPAAAAPMMMMM MMMMPAAMMAPAMMMM MMMMPAMMMMBAMMMM MMMMBPAMMAPAMMMM MMMMMAPBPPAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 172 (steel / slow digestion) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPBBPPMMMMMM MMMMPBAAAPPMMMMM MMMMPAAMMAPAMMMM MMMMPAMMMMPAMMMM MMMMPPAMMPPAMMMM MMMMMPPPPPAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 173 (silver / teleportation) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPNBPPMMMMMM MMMMPBAAAPPMMMMM MMMMBAAMMAPAMMMM MMMMBAMMMMPAMMMM MMMMPPAMMPPAMMMM MMMMMPPPBPAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 174 (gold / teleport control) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLHHHLMMMMMM MMMMLHAAAHLMMMMM MMMMHAAMMAHAMMMM MMMMHAMMMMHAMMMM MMMMLHAMMHLAMMMM MMMMMLHHHLAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 175 (ivory / polymorph) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOOONOMMMMMM MMMMOOAAAOOMMMMM MMMMNAAMMANAMMMM MMMMOAMMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 176 (emerald / polymorph control) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPGFFPAMMMMM MMMMMFGFFFAMMMMM MMMMMAFFFAMMMMMM MMMMMOCECNAMMMMM MMMMOOAAAONAMMMM MMMMOAAMMMOAMMMM MMMMNOAMMONAMMMM MMMMMONONOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 177 (wire / invisibility) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPPPMMMMMM MMMMPPAAAPPMMMMM MMMMPAAMMMPAMMMM MMMMPAMMMMMPAMMM MMMMPAMMMMMPAMMM MMMMPAAPPPPAMMMM MMMMMPPPAAAMMMMM MMMMMMAAMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 178 (engagement / see invisible) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPNNNPAMMMMM MMMMMNNNNNAMMMMM MMMMMANNNAMMMMMM MMMMMLHHHLAMMMMM MMMMLHAAAHLAMMMM MMMMHAAMMMHAMMMM MMMMLHAMMHLAMMMM MMMMMLHHHLAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 179 (shiny / protection from shape changers) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMNNNNNMMMMMM MMMMNNAAANNMMMMM MMMMNAMMMMNAMMMM MMMMNAMMMMNAMMMM MMMMNNAMMNNAMMMM MMMMMNNNNNAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 180 (circular / amulet of ESP) { MMMMMMMMMMMMMMMM MMMMMMLLLLLAAMMM MMMMMLAAMMMLAAMM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMMLAAMMMLAAMM MMMMMMLAAMLAAMMM MMMMMMACCCAMMMMM MMMMMMCKKKKAMMMM MMMMMMCKKKKAMMMM MMMMMMMKKKAAMMMM MMMMMMMAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 181 (spherical / amulet of life saving) { MMMMMMMMMMMMMMMM MMMMMMLLLLLAAMMM MMMMMLAAMMMLAAMM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMMLAAMMMLAAMM MMMMMMLAAMLAAMMM MMMMMMAKKKAAMMMM MMMMMMKHCCKAAMMM MMMMMMKCCCKAAMMM MMMMMMAKKKAAMMMM MMMMMMMAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 182 (oval / amulet of strangulation) { MMMMMMMMMMMMMMMM MMMMMMLLLLLLAAMM MMMMMLAAMMMMLAAM MMMMLAAMMMMMMLAA MMMMLAAMMMMMMLAA MMMMLAAMMMMMMLAA MMMMLAAMMMMMMLAA MMMMMLAAMMMMLAAM MMMMMMLAAAMLAAMM MMMMMMACCCCAMMMM MMMMMMCKKKKKAMMM MMMMMMCKKKKKAMMM MMMMMMAKKKKAMMMM MMMMMMMAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 183 (triangular / amulet of restful sleep) { MMMMMMMMMMMMMMMM MMMMMMLLLLLAAMMM MMMMMLAAMMMLAAMM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMMLAAMMMLAAMM MMMMMMLAAMLAAMMM MMMMMMALCLAAMMMM MMMMMMMCKKAMMMMM MMMMMMCKKKKAMMMM MMMMMCKKKKKKAMMM MMMMMMMAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 184 (pyramidal / amulet versus poison) { MMMMMMMMMMMMMMMM MMMMMMLLLLLAAMMM MMMMMLAAMMMLAAMM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMMLAAMMMLAAMM MMMMMMLAAMLAAMMM MMMMMMALCLAAMMMM MMMMMMMCCKAAMMMM MMMMMMCCCKKAMMMM MMMMMCCCKKKKAMMM MMMMCCKJJJJKKAMM MMMMKJJJJJJJJAMM MMMMMMMAAAAAAAMM } # tile 185 (square / amulet of change) { MMMMMMMMMMMMMMMM MMMMMMLLLLLAAMMM MMMMMLAAMMMLAAMM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMMLAAMMMLAAMM MMMMMMLAAMLAAMMM MMMMMMALALAAMMMM MMMMMMCCCCCAMMMM MMMMMMCKKKKAMMMM MMMMMMCKKKKAMMMM MMMMMMCKKKKAMMMM MMMMMMMAAAAAMMMM MMMMMMMMMMMMMMMM } # tile 186 (concave / amulet of unchanging) { MMMMMMMMMMMMMMMM MMMMMMLLLLLAAMMM MMMMMLAAMMMLAAMM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMMLAAMMMLAAMM MMMMMMLAAMLAAMMM MMMMMMAJJKAAMMMM MMMMMMJJJCKAAMMM MMMMMJJJKKCCAMMM MMMMMJJKKCLCAMMM MMMMMMJJCLCAAMMM MMMMMMMKCCAAMMMM MMMMMMMMAAAMMMMM } # tile 187 (hexagonal / amulet of reflection) { MMMMMMMMMMMMMMMM MMMMMMLLLLLAAMMM MMMMMLAAMMMLAAMM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMMLAAMMMLAAMM MMMMMMLAMMLAAMMM MMMMMMACCCAAMMMM MMMMMMCKKKKAAMMM MMMMMCKKKKKKAMMM MMMMMMKKKKKAAMMM MMMMMMMKKKAAMMMM MMMMMMMMAAAMMMMM MMMMMMMMMMMMMMMM } # tile 188 (octagonal / amulet of magical breathing) { MMMMMMMMMMMMMMMM MMMMMMLLLLLAAMMM MMMMMLAAMMMLAAMM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMLAAMMMMMLAAM MMMMMLAAMMMLAAMM MMMMMMLAAMLAAMMM MMMMMMACCCAAMMMM MMMMMMCKKKKAAMMM MMMMMCKKKKKKAMMM MMMMMCKKKKKKAMMM MMMMMMKKKKKAAMMM MMMMMMMKKKAAMMMM MMMMMMMMAAAMMMMM } # tile 189 (Amulet of Yendor / cheap plastic imitation of the Amulet of Yendor) { MMMMMMMMMMMMMMMM MMMMMMHHHHHAAMMM MMMMMHAAMMMHAAMM MMMMHAAMMMMMHAAM MMMMHAAMMMMMHAAM MMMMHAAMMMMMHAAM MMMMHAAMMMMMHAAM MMMMMHAAMMMHAAMM MMMMMMHAAMHAAMMM MMMMMMAHCCAAMMMM MMMMMMBCDDPAAMMM MMMMMMBCDDPAAMMM MMMMMMABPPAAMMMM MMMMMMMAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 190 (Amulet of Yendor / Amulet of Yendor) { MMMMMMMMMMMMMMMM MMMMMMHHHHHAAMMM MMMMMHAAMMMHAAMM MMMMHAAMMMMMHAAM MMMMHAAMMMMMHAAM MMMMHAAMMMMMHAAM MMMMHAAMMMMMHAAM MMMMMHAAMMMHAAMM MMMMMMHAAMHAAMMM MMMMMMAHCCAAMMMM MMMMMMBCDDPAAMMM MMMMMMBCDDPAAMMM MMMMMMABPPAAMMMM MMMMMMMAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 191 (large box) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCCCCCCCCCCJM MMMCKKKKCKKKCJJM MMCKJJKCJJJCJJJM MCJJJKCJJJCJJJJM CCCCCCCCCCCJJJJM CJJJJJJJJJJJJJJA CJKKKCJKKKCJJJJA CJKKKHHKKKCJJJJA CJKKKCJKKKCJJJAA CJCCCCJCCCCJJAAM CKKKKKKKKKKJAAMM MAAAAAAAAAAAAMMM } # tile 192 (chest) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMCJKKKCJKKKCMM MCKJKKCKJKKCJJKM MKJKKKKJKKKKJJJM CJKKKCJKKKCJJJJM CJKKKCJKKKCJJJJM CCCCCHHCCCCJJJJM CJJJHJJHJJJJJJJM CJKKKHHKKKCJJJJA CJKKKHHKKKCJJJJA CJKKKCJKKKCJJJAA CJCCCCJCCCCJJAAM CKKKKKKKKKKJAAMM MAAAAAAAAAAAAMMM } # tile 193 (ice box) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMNNNNNNNNNNNM MMMNPBBBBBBBBNPM MMNPPBBBBBBBNPPM MNPPPBBBBBBNPPPM NNNNNNNNNNNPPPPM NBBBBBBBBBBPPPPA NNNNBBBBBBBPPPPA NBBBBBBBBBBPPPPA NNBBBBBBBBBPPPAA NBBBBBBBBBBPPAAM NBBBBBBBBBBPAAMM MAAAAAAAAAAAAMMM } # tile 194 (bag / sack) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCJKKKKJMMMMM MMMMMCJKKJAAMMMM MMMMOOOOOAAMMMMM MMMOMOKKKJAMMMMM MMMMCOKKKKJAMMMM MMMCCCKKKKKJAMMM MMCCCKKKKKKJJAMM MMCCCKKKKKKJJAMM MMCCKKKKKKJJJAMM MMMCKKKKJJJJAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 195 (bag / oilskin sack) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCJKKKKJMMMMM MMMMMCJKKJAAMMMM MMMMOOOOOAAMMMMM MMMOMOKKKJAMMMMM MMMMCOKKKKJAMMMM MMMCCCKKKKKJAMMM MMCCCKKKKKKJJAMM MMCCCKKKKKKJJAMM MMCCKKKKKKJJJAMM MMMCKKKKJJJJAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 196 (bag / bag of holding) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCJKKKKJMMMMM MMMMMCJKKJAAMMMM MMMMOOOOOAAMMMMM MMMOMOKKKJAMMMMM MMMMCOKKKKJAMMMM MMMCCCKKKKKJAMMM MMCCCKKKKKKJJAMM MMCCCKKKKKKJJAMM MMCCKKKKKKJJJAMM MMMCKKKKJJJJAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 197 (bag / bag of tricks) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMCJKKKKJMMMMM MMMMMCJKKJAAMMMM MMMMOOOOOAAMMMMM MMMOMOKKKJAMMMMM MMMMCOKKKKJAMMMM MMMCCCKKKKKJAMMM MMCCCKKKKKKJJAMM MMCCCKKKKKKJJAMM MMCCKKKKKKJJJAMM MMMCKKKKJJJJAMMM MMMMAAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 198 (key / skeleton key) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMOOMMMMMMMMMMMM MOMAOOOOOOOOOOMM MOAMOAAAAOAOAOAM MOAMOAMMMOAMAOAM MMOOMAMMMMAMMMAM MMMAAMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 199 (lock pick) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MBBBPPPPPMMMMMMM MBPPPPPPPPPPPAMM MBPPAAAAAAAAAAAM MBPPAMMMMMMMMMMM MMAAAMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 200 (credit card) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMPPPPPPPPPPPPMM MPPPDDDDPCCCPPPM MPPDDDDPCCCCCPPA MPPDDDDPCCCCCPPA MPPDDDDPCCCCCPPA MPPPDDDDPCCCPPPA MMPPPPPPPPPPPPAA MMMAAAAAAAAAAAAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 201 (candle / tallow candle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNNAAAMMMMMMMM MMMMMNPOAMMMMMMM MMMMMPNNOAMMMMMM MMMMMOOONOAMMMMM MMMMMMOOONOAMMMM MMMMMMMOOONOAMMM MMMMMMMMOOONOAMM MMMMMMMMMOOONOAM MMMMMMMMMMOOOPAM MMMMMMMMMMMOPAMM MMMMMMMMMMMMAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 202 (candle / wax candle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMNNAAAMMMMMMMM MMMMMNPOAMMMMMMM MMMMMPNNOAMMMMMM MMMMMOOONOAMMMMM MMMMMMOOONOAMMMM MMMMMMMOOONOAMMM MMMMMMMMOOONOAMM MMMMMMMMMOOONOAM MMMMMMMMMMOOOPAM MMMMMMMMMMMOPAMM MMMMMMMMMMMMAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 203 (brass lantern) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMCCCMMMMMMM MMMMMCMAACMMMMMM MMMMMCAMMCAMMMMM MMMMMLHHHLAMMMMM MMMMLNNHNNLAMMMM MMMMHNNHNNHAMMMM MMMMHNNHNNHAMMMM MMMMHNNHNNHAMMMM MMMMLHHHHHLAMMMM MMMMMLHHHLAMMMMM MMMMMLHHHLAMMMMM MMMMLHHHHHLMMMMM MMMMMAAAAAAAMMMM MMMMMMMMMMMMMMMM } # tile 204 (lamp / oil lamp) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMHAMMMMMM MLHCMMLNLLLAMMMM MMMHHHNHHHHHHHMM MMMMCLHHHHHLCHAM MMMMMACLHLCCAAAM MMMMMMLHHHLAAMMM MMMMMMAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 205 (lamp / magic lamp) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMHAMMMMMM MLHCMMLNLLLAMMMM MMMHHHNHHHHHHHMM MMMMCLHHHHHLCHAM MMMMMACLHLCCAAAM MMMMMMLHHHLAAMMM MMMMMMAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 206 (expensive camera) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMAAAMMMMMMM MMMAMAAAAAAAAAMM MMAAAAAAAAABBAMM MMAAAAPPPAABBAMM MMAAAPPBPPAAAAPM MMAAAPBBBPAAAAPM MMAAAPPBPPAAAAPM MMAAAAPPPAAAAAPM MMAAAAAAAAAAAAPM MMMPPPPPPPPPPPPM MMMMMMMMMMMMMMMM } # tile 207 (looking glass / mirror) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMBBBBAMMMMMMM MMMBPPPPBAMMMMMM MMBPPPPPPBAMMMMM MMBPPPPPPPBAMMMM MMBPPPPPPPBAMMMM MMBPPPPPPPBAMMMM MMMBPPPPPPBAMMMM MMMMBPPPPBBAMMMM MMMMMBBBBBBBAMMM MMMMMMMMMMBBBAMM MMMMMMMMMMMBBBAM MMMMMMMMMMMMBBAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 208 (glass orb / crystal ball) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMBBBBMMMMMMM MMMMBNBBBBMMMMMM MMMMBBBBBBMMMMMM MMMMBBBBBBMAAMMM MMMMBBBBBBAAAAMM MMMMCBBBBJAAAMMM MMMCKKKKKJJAMMMM MMMMKKKKJJAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 209 (lenses) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPMMMMMPMMM MMMMPMMPAMMPMPAM MMMPMMAAMMPMAAMM MMPNBAAMNBPAAMMM MMNAABPNAABAAMMM MMBAMPABAMPAAMMM MMMBPAAMBPAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 210 (blindfold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMOOOOOOOOMMMM MMMOOOOOOOOOOMMM MMMOOOOOOOOOOAMM MMOAOOOAAOOOAOAM MMOAAAAAAAAAAOAM MMMOOAMMMMMMMOAM MMMMMOAMMMMMOAMM MMMMMOAMMMMMOAMM MMMMMMOOAMMOAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 211 (towel) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMPPPPPPPM MMMMMMMMOOOOOOOM MMMMMMMMOOOOOOOM MMMOOOOOOBOOOOOM MMOOOOOOOPPOOOAM MMOOOOOOOPPOOOAM MMOOOOOOOPPPOAMM MOOOOOOOPPPPPAMM MOOOOOOOAAAAAMMM MPPPPPPPAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 212 (saddle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJJAMMMJJAMMM MMMMJKJJJJKJAMMM MMMMMJCCKKJAMMMM MMMMMJKKKKJAMMMM MMMMMMJKKJAMMMMM MMMMMMMJJAAMMMMM MMMMMMMJAAMAMMMM MMMMMMMPAMMAMMMM MMMMMMPAPAAMMMMM MMMMMMPPPAMMMMMM MMMMMMMAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 213 (leash) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMKKJMMMMMM MMMMMMJJJJAMMMMM MMMMMJAAAAAMMMMM MMMMKAAMMMMMMMMM MMMMJAMMMMMMMMMM MMMMJAMMMMMMMMMM MMMMMJJJJMMMMMMM MMMMMMAAAJMMMMMM MMMMMMMMMAJMMMMM MMMPPPPPMMKAMMMM MMPPAAAPPKAAMMMM MMMPPPPPAAAMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 214 (stethoscope) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMPNMMMNPMMMMMM MMPAAMMMMAPAMMMM MMPAMMMMMMPAMMMM MMMPAMMMMPAMMMMM MMMPAMMMMPAMMMMM MMMMPAMMPAMMMMMM MMMMPAMMPAPPPMMM MMMMMPPPAMJJPAMM MMMMMPJPAMJPPAMM MMMMMMJAMMJAAAMM MMMMMMJAMJJAMMMM MMMMMMMJJJAMMMMM MMMMMMMMAAAMMMMM MMMMMMMMMMMMMMMM } # tile 215 (tinning kit) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPOOOOOOOOPM MMMMPPOOOOOOOPPM MMMPPPAAAAAAPPPM MMOOOOOOOOOOPPPA MMOOOOBBBOOOPPPA MMOOOBPPPMOOPPAA MMOOOBPBPMOOPAAM MMOOOOBPMMOOAAMM MMMAAOOOPMAAAMMM MMMMMBOOPMAMMMMM MMMMMBPPPMAMMMMM MMMMMABPMAMMMMMM MMMMMMAAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 216 (tin opener) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMBAMMMMMM MMMMMMMMBPAMMMMM MMMMMMPMBPPAMMMM MMMMMMPABPPAMMMM MMMMMMBPPPAAMMMM MMMMMMMBPAAMMMMM MMMMMMMKJAMMMMMM MMMMMMMKJAMMMMMM MMMMMMMKJAMMMMMM MMMMMMMKJAMMMMMM MMMMMMMKJAMMMMMM MMMMMMMKJAMMMMMM MMMMMMMMAAMMMMMM MMMMMMMMMMMMMMMM } # tile 217 (can of grease) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMBPPPPMMMMMM MMMMBAAAAAPMMMMM MMMMBPAAAPMAMMMM MMMMBBPPPMMAAMMM MMMMBBPPPMMAAAMM MMMMBBPPPMMAAMMM MMMMMBPPPMAAMMMM MMMMMMMAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 218 (figurine) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMJJMMMMMM MMMMMMMKCJJMMMMM MMMMMMMKKJJMMMMM MMMMCKMCJMMMMMMM MMMMJJCKJMCJMMMM MMMMMJCKJJJJAAMM MMMMMMCKAAMAAAAM MMMMKCKKAAAAAAMM MMMJCCKKAJJAAMMM MMMJKKKKJJJJAMMM MMMMJJKKJJJAAMMM MMMMMJJJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 219 (magic marker) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMBMMMMM MMMMMMMMMBIEMMMM MMMMMMMMBIEAAMMM MMMMMMMBIEAAMMMM MMMMMMBIEAAMMMMM MMMMMBIEAAMMMMMM MMMMNNEAAMMMMMMM MMMMNNAAMMMMMMMM MMMMMAAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 220 (land mine) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMAMMMMMMMM MMMMMFFAFFMMMMMM MMMMFMAAAMFAMMMM MMMMFGFFFFFAAMMM MMMMMGFFFFAAMMMM MMMMMMAAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 221 (beartrap) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPOMOPMMMMMM MMMMPAMMMAPMMMMM MMMMPPOMOPPAMMMM MMMMPAMMMAPAMMMM MMMMPPOAOPPAAMMM MMMMPAAAAAPAAMMM MMMMPAAMMMPAAMMM MMMMPPAMMPPAMMMM MMMMMPPPPPAAMMMM MMMMMMPPPAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 222 (whistle / tin whistle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMBBABBBBBBBMMMM MBPPPPPPPPPPAMMM MPPPPPPAAAAAAMMM MPPPPPPAMMMMMMMM MMPPPPAAMMMMMMMM MMMAAAAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 223 (whistle / magic whistle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMBBABBBBBBBMMMM MBPPPPPPPPPPAMMM MPPPPPPAAAAAAMMM MPPPPPPAMMMMMMMM MMPPPPAAMMMMMMMM MMMAAAAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 224 (flute / wooden flute) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMJMMM MMMMMMMMMMMAJMMM MMMMMMMMMMKJAMMM MMMMMMMMMKJAMMMM MMMMMMMMKJAMMMMM MMMMMMMJJAMMMMMM MMMMMMKJAMMMMMMM MMMMMJJAMMMMMMMM MMMMKJAMMMMMMMMM MMMJJAMMMMMMMMMM MMKJAMMMMMMMMMMM MJJAMMMMMMMMMMMM MMAMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 225 (flute / magic flute) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMJMMM MMMMMMMMMMMAJMMM MMMMMMMMMMKJAMMM MMMMMMMMMKJAMMMM MMMMMMMMJJAMMMMM MMMMMMMJJAMMMMMM MMMMMMKJAMMMMMMM MMMMMJJAMMMMMMMM MMMMKJAMMMMMMMMM MMMJJAMMMMMMMMMM MMKJAMMMMMMMMMMM MJJAMMMMMMMMMMMM MMAMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 226 (horn / tooled horn) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNMMMM MMMMMMMMMMNOOMMM MMMMMMMMMNOOMMMM MMMMMMMNNOOPMMMM MMMMNNPOOOOMMMMM MMMNKKNPOOPMAMMM MMNKJAANPOMAAAMM MMNKAAANPPAAAMMM MMNKJAJNPAAAMMMM MMMNKKNPAAAMMMMM MMMMNNPAAAMMMMMM MMMMAAAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 227 (horn / frost horn) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNMMMM MMMMMMMMMMNOOMMM MMMMMMMMMNOOMMMM MMMMMMMNNOOPMMMM MMMMNNPOOOOMMMMM MMMNKKNPOOPMAMMM MMNKJAANPOMAAAMM MMNKAAANPPAAAMMM MMNKJAJNPAAAMMMM MMMNKKNPAAAMMMMM MMMMNNPAAAMMMMMM MMMMAAAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 228 (horn / fire horn) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNMMMM MMMMMMMMMMNOOMMM MMMMMMMMMNOOMMMM MMMMMMMNNOOPMMMM MMMMNNPOOOOMMMMM MMMNKKNPOOPMAMMM MMNKJAANPOMAAAMM MMNKAAANPPAAAMMM MMNKJAJNPAAAMMMM MMMNKKNPAAAMMMMM MMMMNNPAAAMMMMMM MMMMAAAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 229 (horn / horn of plenty) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNMMMM MMMMMMMMMMNOOMMM MMMMMMMMMNOOMMMM MMMMMMMNNOOPMMMM MMMMNNPOOOOMMMMM MMMNKKNPOOPMAMMM MMNKJAANPOMAAAMM MMNKAAANPPAAAMMM MMNKJAJNPAAAMMMM MMMNKKNPAAAMMMMM MMMMNNPAAAMMMMMM MMMMAAAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 230 (harp / wooden harp) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMKKKMMMMMMKKKMM MMKAKPPPPPPKAKAM MMMAKAMMMMMKAMAM MMMKPPPPPPPPKMMM MMMKAMMMMMMMKAMM MMMKPPPPPPPPKAMM MMMKAMMMMMMMKAMM MMMMKPPPPPPKMAMM MMMMMKKKKKKMAMMM MMMMMMAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 231 (harp / magic harp) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMKKKMMMMMMKKKMM MMKAKPPPPPPKAKAM MMMAKAMMMMMKAMAM MMMKPPPPPPPPKMMM MMMKAMMMMMMMKAMM MMMKPPPPPPPPKAMM MMMKAMMMMMMMKAMM MMMMKPPPPPPKMAMM MMMMMKKKKKKMAMMM MMMMMMAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 232 (bell) { MMMMMMMMMMMMMMMM MMMMMMMKAMMMMMMM MMMMMMKAKAMMMMMM MMMMMMMKAMMMMMMM MMMMMMLCKAMMMMMM MMMMMLCCCKAMMMMM MMMMMLCCCKAMMMMM MMMMMLCCCKAAMMMM MMMMCLCCCKCAMMMM MMMCLLCCCKLKAMMM MMMCCLLLLLCKAMMM MMMMCCCCCCKAAMMM MMMMMAAKKAAAMMMM MMMMMMMAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 233 (bugle) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMLMMMMMMMMMMMMM MKCLMMMMMMMMMMMM MKCCLMMMMMMMMLLM MKCCCLCCCCCCCLAM MKCCKAAKKKKKAACA MKCKAAJCAAACJAAM MMKAAMMJCCCJAAMM MMMAMMMMAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 234 (drum / leather drum) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPOOOOPMMMMM MMMMOOOOOOOOMMMM MMMOOOOOOOOOOMMM MMMLOOOOOOOOLAAM MMMLKOOOOOOJLAAA MMMKKLKKKKLJJAAA MMMJKLKKKKLJJAAM MMMMJKKKKKKJAAMM MMMMMJJJJJJAAMMM MMMMMMAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 235 (drum / drum of earthquake) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPOOOOPMMMMM MMMMOOOOOOOOMMMM MMMOOOOOOOOOOMMM MMMLOOOOOOOOLAAM MMMLKOOOOOOJLAAM MMMKKLKKKKLJJAAM MMMJKLKKKKLJJAAM MMMMJKKKKKKJAAMM MMMMMJJJJJJAAMMM MMMMMMAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 236 (pick-axe) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMBBAMMMMMMM MMMMMBPPBAMMMMMM MMMMMMPPPBAMMMMM MMMMMMMKPPPAMMMM MMMMMMKJAMPPAMMM MMMMMKJAMMMPAMMM MMMMKJAMMMMMMMMM MMMKJAMMMMMMMMMM MMKJAMMMMMMMMMMM MKJAMMMMMMMMMMMM MMAMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 237 (iron hook / grappling hook) { MMMMMMMMMMMMMNMM MMMMMMMMMMMMMMPM MMMMMMMMMMMNPAPA MMMMMMMMMMMMMPAA MMMMMMMOOEPPPPAM MMMMMOOAAAAAAAPA MMMMOAAMMMMMMMPA MMMMOAMMMMMMMNAM MMMMOAMMMMMMMMMM MMMMMOOAAMMMMMMM MMMMMMMOOOAMMMMM MMMMMMMMMMOAMMMM MMMMMMMMMMOAMMMM MOAMMMMMMMOAMMMM MMOOAMMOOOAMMMMM MMMMOOOAAMMMMMMM } # tile 238 (unicorn horn) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMHMMMMMMMMMMMMM MMMLAMMMMMMMMMMM MMMLHLAMMMMMMMMM MMMMHLHAAMMMMMMM MMMMMLHLHAMMMMMM MMMMMMHLHLAAMMMM MMMMMMLLHLHHAMMM MMMMMMMHHLHDAMMM MMMMMMMMLHDDAMMM MMMMMMMMHDDAMMMM MMMMMMMMMAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 239 (candelabrum / Candelabrum of Invocation) { MMMMMMMNMMMMMMMM MMMMMMMDMMMMMMMM MMMMMMMDMMMNMMMM MMMNMMMDMMMDMMMM MMMDMMMDMMMDMMMM MMMDMMHDHMMDMMMM MMHDHMMHMMHDHMMM MMMHMMMHMMAHMMMM MMMOHHHHHHHOMAMM MMMMMMOHOAAMAMMM MMMMMMMHMMAAAMMA MMMMMMOHOAAAAAAM MMMMMOHHHHAMMAMM MMMMMMHHHAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 240 (silver bell / Bell of Opening) { MMMMMMMMMMMMMMMM MMMMMMMOAMMMMMMM MMMMMMOAOAMMMMMM MMMMMMMOAMMMMMMM MMMMMMNOPAMMMMMM MMMMMNOOOPAMMMMM MMMMMNOOOPAMMMMM MMMMMNOOOPAAMMMM MMMMONOOOPOAMMMM MMMONNOOOPNPAMMM MMMOONNNNNOPAMMM MMMMOOOOOOPAAMMM MMMMMAAPPAAAMMMM MMMMMMMAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 241 (tripe ration) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOOOOMMMMMMM MMMMDODDDOOMMMMM MMMODODOOODAMMMM MMMOOOOODDDAMMMM MMMMDODOOOOAMMMM MMMMMODOODAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 242 (corpse) { MMMMMMMMMMMMMMMM MMMMMDMDPLNMMMMM MMMNOMDDLNOAMMMM MMPOOADMMOONNMMM MONONNMDLNNNNMMM MNPANDCCCNAAAAMM MMAADCCCCAADMMMM MMDDDCCCDADDDDMM MMDMNCDCCNMDMMMM MPNNNOAADNNPNNMM MONPONMDDMNONOAM MMMPNNAMDMPNAAAM MMMLNAAMDMNPAMMM MMMMAAMMMMMAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 243 (egg) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPONOPMMMMMMM MMMMONNNOMMMMMMM MMMPNNNNNPMMMMMM MMMONNNNNOMAAAMM MMMNNNNNNOAAAAMM MMMONNNNOOAAAAMM MMMPONNOOPAAAMMM MMMMPOOOPAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 244 (meatball) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMKKCKMMMMMMM MMMMKCDJDJMMMMMM MMMMCDJDJJAAAMMM MMMMDCDJAJAAAMMM MMMMKDDJJJAAAMMM MMMMMJJAJAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 245 (meat stick) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMCDMMM MMMMMMMMMMCDAAMM MMMMMMMMMLDAAMMM MMMMMMMDLKAAMMMM MMMMMMLCKAAMMMMM MMMMMLCKAAMMMMMM MMMMLLKAAMMMMMMM MMMDCKAAMMMMMMMM MMMCKAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 246 (huge chunk of meat) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMKDKKMMMMMMM MMMKKJJJJKDMMMMM MMKCCKKCJJJKMMMM MMKCKKCJJJJKAMMM MKKKKJJJDDJJKAAM MKKKJJJJJJJJKAAA MKCKDJJJDJJJJAAA MKKJDJJDJJAJAAAA MKKKKJJDKKDJJAAA MDKDJJJKKKKAJAAM DKKKKAJJAJDAJJAM KKKKKKKKKJJJAJAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 247 (meat ring) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOOOAMMMMMMM MMMMOAAMOOAMMMMM MMMMOAAMMMOAMMMM MMMMMOAAMMMOAMMM MMMMMOAAMMMOAMMM MMMMMOAMMMMOAMMM MMMMOAAAMMOAAMMM MMMMMOOOOOAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 248 (kelp frond) { MMMMFAMMMMMMMMMM MMMMFFAMMMMMMMMM MMMMMFFAMMMMMMMM MMMMMMMFFAMMMMMM MMMMMMMMFAMMMMMM MMMMMMMMFFAMMMMM MMMMMMMMFFAMMMMM MMMMMMMMFFAMMMMM MMMMMMMFFAMMMMMM MMMMMMMFFAMMMMMM MMMMMMFFAMMMMMMM MMMMMFFFAMMMMMMM MMMMMFFAMMMMMMMM MMMMMFFFAMMMMMMM MMMMMFFFFAMMMMMM MMMMMMFFFFAMMMMM } # tile 249 (eucalyptus leaf) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMLMMMMMMMM MMMMMMMLAMMMMMMM MMMMMMMLHMMMMMMM MMMMMMGOHAMMMMMM MMMMMMGOOAMMMMMM MMMMMGOOAMMMMMMM MMMMMGOHAMMMMMMM MMMMMOOAMMMMMMMM MMMMOHAMMMMMMMMM MMMMOAMMMMMMMMMM MMMOAMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 250 (apple) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMFFMMMMMMMMMM MMMMMMFMMMMMMMMM MMMMCCFFCCMMMMMM MMMCLLKCDDKMMMMM MMMCLDDDCDKAMMMM MMMCDDDDDDKAAMMM MMMDDDDDDDKAAMMM MMMDDDDDDKKAAMMM MMMMDDKDKKAAMMMM MMMMMKAAKAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 251 (orange) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMFFFMMMMMMMMM MMMMMMMFGGMMMMMM MMMMMCCFCCDMMMMM MMMMCGGCCCCDMMMM MMMDCCCCCCCDAMMM MMMCCCCCCCCDKAMM MMMCCCCCCCDDKAMM MMMDCCCCCDDKJAMM MMMMDCCCDDKKAAMM MMMMMDDDDKKAAMMM MMMMMMAKKJAAMMMM MMMMMMMAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 252 (pear) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMFFCCMMM MMMMMMMMFGCFMMMM MMMMMMMFGGGFAAMM MMMMMFFGHGFAAMMM MMMFGHHHGFFAAMMM MMFGHHGGGFFAMMMM MMFHHGGGGFFAMMMM MMFHHGGGGFMAMMMM MMMFGGGGFMAAMMMM MMMMFFFMMAAMMMMM MMMMMAAAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 253 (melon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMFFFFMMMMMM MMMMFGGGGGFMMMMM MMMFGGGGGGGFAMMM MMMGGGGGGGGFAAMM MMFGGGGGGGGFAAMM MMFGGGGGGGGFAAMM MMFGGGGGGGGAAMMM MMFGGKAGGGFAAMMM MMMFKAGGGFAAMMMM MMMMMFFFAAAMMMMM MMMMMMAAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 254 (banana) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMJMMM MMMMMMMMMMMMHAMM MMMMMMMMMMMMHHMM MMMMMMMMMMMHOHAM MMMMMMMMMMMHOHAM MMMMMMMMMMHOHHAM MMMMMMMMMMHOHJAM MMMMMMMMMHOHHAAM MMMMMMMMHOHHJAMM MMMMMMHHOHHJAAMM MMJHOOOOHHJAAMMM MMMMHHHHJAAAMMMM MMMMMAAAAAMMMMMM MMMMMMMMMMMMMMMM } # tile 255 (carrot) { MMMMMMMMMMMMMMMM MMMMMMMMMMFMMFMM MMMMMMMMMMGFGAAM MMMMMMMMMMFFAMMM MMMMMMMMMMGFFFMM MMMMMMMCCGFAAMMM MMMMMMCCCCAMMMMM MMMMMMDCCCMMMMMM MMMMMCCDCAMMMMMM MMMMCCCCAAMMMMMM MMMMDCAAAMMMMMMM MMMCCAAMMMMMMMMM MMCDAAMMMMMMMMMM MMCAAMMMMMMMMMMM MMMAMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 256 (sprig of wolfsbane) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMHHMMM MMMMMMMMMMHMMHMM MMMHHHFMMMFAAMMM MMHMAAAFMFAMMAMM MMHAAMMMFAMMMMMM MMMAMMMFFAMMMMMM MMMMMMFFAAMMMMMM MMMMMFFAAMMMMMMM MMMFFFAAMMMMMMMM MMMMAAAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 257 (clove of garlic) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOMMMMMMMMMM MMMMOOOAAMMMMMMM MMMMOOOOAAMMMMMM MMMMHOOOOAAMMMMM MMMMHHOOOOAAMMMM MMMMMHHHOOOAAMMM MMMMMMMHOOOAAMMM MMMMMMMMAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 258 (slime mold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMJMMMM MMMMMMMMFGJFMMMM MMMMMMFFGGGFMMMM MMMMFGGGGGGFAMMM MMMFGGGGGCGCAMMM MMMGGGGGGGCCAMMM MMFGGGGCGCCKAMMM MMFGGCGGCCKJAMMM MMMCGGCCCKJAMMMM MMMMCCCKJAAAMMMM MMMMMAAAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 259 (lump of royal jelly) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOHMMMMMMMMM MMMMONHHAAAMMMMM MMMONOHHHAAAMMMM MMHOOOOHHHHAMMMM MMMMHOOHHAAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 260 (cream pie) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMOOOOOOOOMMMM MMMOONNNNOONOAMM MMKNONOOONNNNJAM MMMKKKKKKKKJJAAM MMMMJJJJJJJJAAMM MMMMMMAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 261 (candy bar) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMIAMMMMMM MMMMMMMBIIAMMMMM MMMMMMIBBIIAMMMM MMMMMNIIBBAAMMMM MMMMNNNIIAAMMMMM MMMNNCNNAAMMMMMM MMIINNNAAMMMMMMM MIIIINAAMMMMMMMM MMIIIAAMMMMMMMMM MMMIAAMMMMMMMMMM MMMMAMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 262 (fortune cookie) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLLMMMMMMMMM MMMMLLLLLLMMMMMM MMMLLLLLLLLMMMMM MMMLLLKJJKAAMMMM MMMLLLLLJAAMMMMM MMMMLLLLAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 263 (pancake) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOOOOOOMMMMM MMMMOOOOOOOOMMMM MMMMOOOOKOOOOMMM MMMOOKOOOOOOOAMM MMOOOOOOOKOOOAMM MMOOOOOOOOOOOAMM MMOOKOOOOOOOOAMM MMOOOOOOOKOOAAMM MMMOOOKOOOOOAAMM MMMMOOOOOOOAAMMM MMMMMAAAAAAAMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 264 (lembas wafer) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMOOMMMMMMM MMMMMMOOLOOMMMMM MMMMMOOLOOLOOMMM MMMMOOLOOLOOLOOM MMMOOLOOLOOLOOAM MMOOLOOLOOLOOAMM MMMAOOLOOLOOAMMM MMMMMAOOLOOAMMMM MMMMMMMAOOAMMMMM MMMMMMMMMAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 265 (cram ration) { MMMMMMMMMMMMMMMM MMMJKAMMMMMMMMMM MMMPBAMMMMMMMMMM MMMPBAMMMMMMMMMM MMMPBPAMMMMMMMMM MMMBBPAKKKKKAMMM MMMBBPKKKKKKKAMM MMMOPKKKKKKKAMMM MMMOKKKKKKKJJAMM MMMBPKLLOKJJJAMM MMMPKLOLOLKJJAMM MMMAKOLOLLKJAAMM MMMMKLOLLOKAAMMM MMMMKKKKKKKAMMMM MMMMMAAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 266 (food ration) { MMMJJAMMMMMMMMMM MMMBPAMMMMMMMMMM MMMBPAMMMMMMMMMM MMBBBPAMMMMMMMMM MMBBBPAKKKKKKKAM MBBBBPKKKKKKKKKA MBOOPKKKKKKKKKAM MBOOKKKKKKKKKJJA MBOOPKLLLLOKJJJA MBPPKLOLLLOLKJJA MMPAKOLOOOLLKJJA MPPPKLOLLLOLKJJA MMMAKOLOOOLLKJAA MMMMKLOLLLLOKAAM MMMMKKKKKKKKKAMM MMMMMAAAAAAAAMMM } # tile 267 (K-ration) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMJJAMMMMMMMMMM MMMBPAMMMMMMMMMM MMBBBPAMMMMMMMMM MMBBBPKKKKKKKAMM MMOOPKKKKKKKKKAM MMOOKKKKKKKKKJAM MMOOPKLLLLOKJJAM MMPPKLLELEOLKJAM MMPAKOLEELLLKJAM MMPPKLLEELOLKJAM MMMAKOLELELLKJAM MMMMKLLLLLLOKAAM MMMMKKKKKKKKKAMM MMMMMAAAAAAAAMMM } # tile 268 (C-ration) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMJJAMMMMMMMMMM MMMBPAMMMMMMMMMM MMBBBPAMMMMMMMMM MMBBBPAMMMMMMMMM MMOOPKKKKKKKKAMM MMOOKKKKKKKKKJAM MMOOPKLLLLOKJJAM MMPPKLOEEEOLKJAM MMPAKOLEOOLLKJAM MMPPKLOELLOLKJAM MMMAKOLEEELLKJAM MMMMKLOLLLLOKAAM MMMMKKKKKKKKKAMM MMMMMAAAAAAAAMMM } # tile 269 (tin) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMBBBBMMMMMMM MMMMBPPPPPMAMMMM MMMMBPBBPMAAAMMM MMMMOBPPMMAAAAMM MMMMOOOPMMAAAAMM MMMMOOOPMMAAAMMM MMMMBOOPMMAAMMMM MMMMBBPPMMAMMMMM MMMMMBPPMAMMMMMM MMMMMMAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 270 (ruby / gain ability) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMODDDAMMMMMMM MMMMMCDAMMMMMMMM MMMMCDDDAMMMMMMM MMMCNCDDDAMAAMMM MMMCDDDDDAAAAMMM MMMCDDDDDAAMMMMM MMMMCDDDAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 271 (pink / restore ability) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOIIIAMMMMMMM MMMMMLIAMMMMMMMM MMMMLIIIAMMMMMMM MMMLNLIIIAMAAMMM MMMLIIIIIAAAAMMM MMMLIIIIIAAMMMMM MMMMLIIIAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 272 (orange / confusion) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOCCCAMMMMMMM MMMMMKCAMMMMMMMM MMMMKCCCAMMMMMMM MMMKNKCCCAMAAMMM MMMKCCCCCAAAAMMM MMMKCCCCCAAMMMMM MMMMKCCCAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 273 (yellow / blindness) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOHHHAMMMMMMM MMMMMOHAMMMMMMMM MMMMOHHHAMMMMMMM MMMONOHHHAMAAMMM MMMOHHHHHAAAAMMM MMMOHHHHHAAMMMMM MMMMOHHHAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 274 (emerald / paralysis) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOFFFAMMMMMMM MMMMMGFAMMMMMMMM MMMMGFFFAMMMMMMM MMMGNGFFFAMAAMMM MMMGFFFFFAAAAMMM MMMGFFFFFAAMMMMM MMMMGFFFAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 275 (dark green / speed) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOFFMAMMMMMMM MMMMMFMAMMMMMMMM MMMMFMFMAMMMMMMM MMMFNFMFMAMAAMMM MMMFFMFMMAAAAMMM MMMFMFMMMAAMMMMM MMMMFMFMAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 276 (cyan / levitation) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMBBBEAMMMMMMM MMMMMBEAMMMMMMMM MMMMBBBEAMMMMMMM MMMBNBBEEAMAAMMM MMMBBBBEEAAAAMMM MMMBBBBEEAAMMMMM MMMMBBEEAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 277 (sky blue / hallucination) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMNBBBAMMMMMMM MMMMMNBAMMMMMMMM MMMMNBBBAMMMMMMM MMMNBBBBBAMAAMMM MMMNBBBBBAAAAMMM MMMNBBBBBAAMMMMM MMMMNBBBAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 278 (brilliant blue / invisibility) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOEEEAMMMMMMM MMMMMBEAMMMMMMMM MMMMBEEEAMMMMMMM MMMBNBEEEAMAAMMM MMMBEEEEEAAAAMMM MMMBEEEEEAAMMMMM MMMMBEEEAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 279 (magenta / see invisible) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMDIIDAMMMMMMM MMMMMDIAMMMMMMMM MMMMDIIDAMMMMMMM MMMDLDIIDAMAAMMM MMMDIIIIDAAAAMMM MMMDDIIDDAAMMMMM MMMMDDDDAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 280 (purple-red / healing) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOEDEAMMMMMMM MMMMMDEAMMMMMMMM MMMMDEDEAMMMMMMM MMMDNDEDEAMAAMMM MMMDDEDEEAAAAMMM MMMDEDEDEAAMMMMM MMMMDEDEAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 281 (puce / extra healing) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOKKJAMMMMMMM MMMMMIKAMMMMMMMM MMMMIKDJAMMMMMMM MMMINDKJJAMAAMMM MMMIKKDJJAAAAMMM MMMDKDKJJAAMMMMM MMMMDKKJAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 282 (milky / gain level) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOOOOAMMMMMMM MMMMMNOAMMMMMMMM MMMMNOOOAMMMMMMM MMMNOOOOOAMAAMMM MMMNOOOOOAAAAMMM MMMNOOOOOAAMMMMM MMMMNOOOAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 283 (swirly / enlightenment) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMNOOOAMMMMMMM MMMMMNOAMMMMMMMM MMMMNOIIAMMMMMMM MMMNOIIOOAMAAMMM MMMIIOOOIAAAAMMM MMMNOOIIOAAMMMMM MMMMIIOOAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 284 (bubbly / monster detection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOFFFAMMMMMMM MMMMMNFAMMMMMMMM MMMMFFFNAMMMMMMM MMMNFNFFFAMAAMMM MMMFFFFFNAAAAMMM MMMFNFFFFAAMMMMM MMMMFFNFAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 285 (smoky / object detection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOPPPAMMMMMMM MMMMMOPAMMMMMMMM MMMMOPPPAMMMMMMM MMMONPPPPAMAAMMM MMMOPPPPPAAAAMMM MMMOPPPPPAAMMMMM MMMMOPPPAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 286 (cloudy / gain energy) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOEEEAMMMMMMM MMMMMBPAMMMMMMMM MMMMBEEPAMMMMMMM MMMBEPPPEAMAAMMM MMMBEEPEEAAAAMMM MMMBEPPPPAAMMMMM MMMMBPEEAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 287 (effervescent / sleeping) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOEEOAMMMMMMM MMMMMNNAMMMMMMMM MMMMOFNNAMMMMMMM MMMBFNNFOAMAAMMM MMMOFNFFOAAAAMMM MMMBFFFNEAAMMMMM MMMMBNFFAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 288 (black / full healing) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJMMMMMMMMM MMMMMKJMMMMMMMMM MMMMAAAAMMMMMMMM MMMMMAAMMMMMMMMM MMMMAAAAMMMMMMMM MMMANAAAAMPPPMMM MMMAAAAAAPPPPMMM MMMAAAAAAPPMMMMM MMMAAAAAAPMMMMMM MMMMAAAAPMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 289 (golden / polymorph) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMLHHHAMMMMMMM MMMMMLHAMMMMMMMM MMMMLHHCAMMMMMMM MMMLNLHHCAMAAMMM MMMLHHHHCAAAAMMM MMMLHHHCCAAMMMMM MMMMLCCCAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 290 (brown / booze) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMGFAMMMMMMMM MMMMMFFAMMMMMMMM MMMMCJJJAMMMMMMM MMMMMKJAMMMMMMMM MMMMKJJJAMMMMMMM MMMKCKJJJAMAAMMM MMMKJJJJJAAAAMMM MMMKJJJJJAAMMMMM MMMMKJJJAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 291 (fizzy / sickness) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMOEEOAMMMMMMM MMMMMOOAMMMMMMMM MMMMOEOOAMMMMMMM MMMBEOOEOAMAAMMM MMMOEOEEOAAAAMMM MMMBEEEOEAAMMMMM MMMMBOEEAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 292 (dark / fruit juice) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJMMMMMMMMM MMMMMKJMMMMMMMMM MMMMAAAAMMMMMMMM MMMMMAAMMMMMMMMM MMMMAJJAMMMMMMMM MMMANJJJAMPPPMMM MMMAJJAAAPPPPMMM MMMAJAAAAPPMMMMM MMMAAAAAAPMMMMMM MMMMAAAAPMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 293 (white / acid) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMNNNNAMMMMMMM MMMMMNNAMMMMMMMM MMMMNNNNAMMMMMMM MMMNPNNNNAMAAMMM MMMNNNNNNAAAAMMM MMMNNNNNNAAMMMMM MMMMNNNNAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 294 (murky / oil) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJMMMMMMMMM MMMMMKJMMMMMMMMM MMMMAAAAMMMMMMMM MMMMMAAMMMMMMMMM MMMMAFJAMMMMMMMM MMMANJFJAMPPPMMM MMMAJFAFAPPPPMMM MMMAFAFAAPPMMMMM MMMAAFAFAPMMMMMM MMMMAAAAPMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 295 (clear / water) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMLJAMMMMMMMM MMMMMKJAMMMMMMMM MMMMBPPPAMMMMMMM MMMMMBPAMMMMMMMM MMMMBPPPAMMMMMMM MMMBPPPPPAMAAMMM MMMBEEEEEAAAAMMM MMMBEEEEEAAMMMMM MMMMBEEEAAMMMMMM MMMMMAAAAMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 296 (ZELGO MER / enchant armor) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 297 (JUYED AWK YACC / destroy armor) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 298 (NR 9 / confuse monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 299 (XIXAXA XOXAXA XUXAXA / scare monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 300 (PRATYAVAYAH / remove curse) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 301 (DAIYEN FOOELS / enchant weapon) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 302 (LEP GEX VEN ZEA / create monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 303 (PRIRUTSENIE / taming) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 304 (ELBIB YLOH / genocide) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 305 (VERR YED HORRE / light) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 306 (VENZAR BORGAVVE / teleportation) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 307 (THARR / gold detection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 308 (YUM YUM / food detection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 309 (KERNOD WEL / identify) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 310 (ELAM EBOW / magic mapping) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 311 (DUAM XNAHT / amnesia) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 312 (ANDOVA BEGARIN / fire) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 313 (KIRJE / earth) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 314 (VE FORBRYDERNE / punishment) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 315 (HACKEM MUCHE / charging) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 316 (VELOX NEB / stinking cloud) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 317 (FOOBIE BLETCH) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 318 (TEMOV) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 319 (GARVEN DEH) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 320 (READ ME) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMNJNJAOMAMMM MMMMMLLLLLLPAMMM MMMMMLLJLJLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 321 (stamped / mail) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MOOOOOOOOOEEOMMM MOOOOOOOOOEEOMMM MOOOOOOOOOOOOAMM MOOOJLJJLJOOOAMM MOOOOOOOOOOOOAMM MOOOJJLJOOOOOAMM MOOOOOOOOOOOOAMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 322 (unlabeled / blank paper) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAPAMMM MMMMMLLLLLLPAMMM MMMMMLLLLLLPAMMM MMMMMLLLLLLPAMMM MMMMMLLLLLLPAMMM MMMMPOOOOOPKAMMM MMMDOOOOOOKDJMMM MMMMPOOOOOPJAAMM MMMMMAAAAAAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 323 (parchment / dig) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHHKKKJMMM MMMKKHHKKHKKCMMM MMJKKKHHKKKKOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKOJAMM MKKKKKKKKKCOAAMM MJOOKKKKKKOJAMMM MMJJOOOKKCOAAMMM MMMMJJJOOOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 324 (vellum / magic missile) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHHKKKJMMM MMMKKHHKKHKKCMMM MMJKKKHHKKKKOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKOJAMM MKKKKKKKKKCOAAMM MJOOKKKKKKOJAMMM MMJJOOOKKCOAAMMM MMMMJJJOOOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 325 (ragged / fireball) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHHKKKJMMM MMMKKHHKKHKKCMMM MMJKKKHHKKKKOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKJJAMM MKKKKKKKKKCJAAMM MJOOKKKKKKOJAMMM MMJJOOOKKCOAAMMM MMMMJOOOOOJAMMMM MMMMMMOOJJAAMMMM MMMMMMMMMMMMMMMM } # tile 326 (dog eared / cone of cold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHHKOMMMMM MMMKKHHKKKJOCMMM MMJKKKHHKKJOOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKOJAMM MKKKKKKKKKCOAAMM MJOOKKKKKKOJAMMM MMJJOOOKKCOAAMMM MMMMJJJOOOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 327 (mottled / sleep) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHHKKKJMMM MMMKKHHKKHKKCMMM MMJKKKHHKKKKOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKOJAMM MKKKKKKKKKCLAAMM MJOOKKKKKKOJAMMM MMJJLLOKKCOAAMMM MMMMJJJOLLJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 328 (stained / finger of death) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHCJJJJMMM MMMKKHHKKCJJCMMM MMJJJJCHKJJJLAMM MMKJCJJHHKKCLAAM MJKJJCCCKKKOJAMM MKKKJJJJKKCOAAMM MJOOKJJKKKOJAMMM MMJJOLOKKCOAAMMM MMMMJJJOOOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 329 (cloth / light) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMEPPPMMMMMMMM MMMMPPPEPPMMMMMM MMMEPPHHHPEPPMMM MMMPPHHPPHPPEMMM MMEPPPHHPPPPOAMM MMPPHPPHHEPEOAAM MEPPPHHHPPPOPAMM MPPPEPPPPPEOAAMM MPOOPPPEPPOPAMMM MMPPOOOPPEOAAMMM MMMMPPPOOOPAMMMM MMMMMMMPPPAAMMMM MMMMMMMMMMMMMMMM } # tile 330 (leather / detect monsters) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHHKKKJMMM MMMKKHHKKHKKCMMM MMJKKKHHKKKKOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKOJAMM MKKKKKKKKKCOAAMM MJOOKKKKKKOJAMMM MMJJOOOKKCOAAMMM MMMMJJJOOOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 331 (white / healing) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPNNPMMMMMMMM MMMMNNNNNPMMMMMM MMMPNNAAANNNPMMM MMMNNAANNANNNMMM MMPNNNAANNNNOAMM MMNNANNAANNNOAAM MPNNNAAANNNONAMM MNNNNNNNNNNOAAMM MNOONNNNNNONAMMM MMPNOOONNNOAAMMM MMMMPNNOOONAMMMM MMMMMMMPNNAAMMMM MMMMMMMMMMMMMMMM } # tile 332 (pink / knock) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMDIIDMMMMMMMM MMMMIIIIIDMMMMMM MMMDIIHHHIIIDMMM MMMIIHHIIHIICMMM MMDIIIHHIIIIOAMM MMIIHIIHHIICOAAM MDIIIHHHIIIOIAMM MIIIIIIIIICOAAMM MIOOIIIIIIOIAMMM MMIIOOOIICOAAMMM MMMMIIIOOOIAMMMM MMMMMMMIIIAAMMMM MMMMMMMMMMMMMMMM } # tile 333 (red / force bolt) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKDDKMMMMMMMM MMMMDDDDDKMMMMMM MMMKDDHHHDDDKMMM MMMDDHHDDHDDCMMM MMKDDDHHDDDDOAMM MMDDHDDHHDDCOAAM MKDDDHHHDDDODAMM MDDDDDDDDDCOAAMM MDOODDDDDDODAMMM MMDDOOODDCOAAMMM MMMMDDDOOODAMMMM MMMMMMMDDDAAMMMM MMMMMMMMMMMMMMMM } # tile 334 (orange / confuse monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKCCKMMMMMMMM MMMMCCCCCKMMMMMM MMMKCCAAACCCKMMM MMMCCAACCACCLMMM MMKCCCAACCCCOAMM MMCCACCAACCLOAAM MKCCCAAACCCOCAMM MCCCCCCCCCLOAAMM MCOOCCCCCCOCAMMM MMCCOOOCCLOAAMMM MMMMCCCOOOCAMMMM MMMMMMMCCCAAMMMM MMMMMMMMMMMMMMMM } # tile 335 (yellow / cure blindness) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMOHHOMMMMMMMM MMMMHHHHHOMMMMMM MMMOHHAAAHHHOMMM MMMHHAAHHAHHLMMM MMOHHHAAHHHHOAMM MMHHAHHAAHHLOAAM MOHHHAAAHHHOHAMM MHHHHHHHHHLOAAMM MHOOHHHHHHOHAMMM MMHHOOOHHLOAAMMM MMMMHHHOOOHAMMMM MMMMMMMHHHAAMMMM MMMMMMMMMMMMMMMM } # tile 336 (velvet / drain life) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMIIIIMMMMMMMM MMMMIEEEEEMMMMMM MMMIEENNNEEEEMMM MMMIENNEENEEBMMM MMIEEENNEEEIOAMM MMEENEENNEIBOAAM MIEEENNNEEIOEAMM MEEEEEEEEIBOAAMM MEOOEEEEIIOEAMMM MMEEOOOIIBOAAMMM MMMMEEEOOOEAMMMM MMMMMMMEEEAAMMMM MMMMMMMMMMMMMMMM } # tile 337 (light green / slow monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMFGGFMMMMMMMM MMMMGGGGGFMMMMMM MMMFGGMMMGGGFMMM MMMGGMMGGMGGHMMM MMFGGGMMGGGGOAMM MMGGMGGMMGGHOAAM MFGGGMMMGGGOGAMM MGGGGGGGGGHOAAMM MGOOGGGGGGOGAMMM MMGGOOOGGHOAAMMM MMMMGGGOOOGAMMMM MMMMMMMGGGAAMMMM MMMMMMMMMMMMMMMM } # tile 338 (dark green / wizard lock) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMFFFFMMMMMMMM MMMMFFFFFFMMMMMM MMMFFFHHHFFFFMMM MMMFFHHFFHFFGMMM MMFFFFHHFFFFOAMM MMFFHFFHHFFGOAAM MFFFFHHHFFFOFAMM MFFFFFFFFFGOAAMM MFOOFFFFFFOFAMMM MMFFOOOFFGOAAMMM MMMMFFFOOOFAMMMM MMMMMMMFFFAAMMMM MMMMMMMMMMMMMMMM } # tile 339 (turquoise / create monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMFBBFMMMMMMMM MMMMBBBBBFMMMMMM MMMFBBGGGBBBFMMM MMMBBGGBBGBBBMMM MMFBBBGGBBBBOAMM MMBBGBBGGBBBOAAM MFBBBGGGBBBOBAMM MBBBBBBBBBBOAAMM MFOOBBBBBBOBAMMM MMBBOOOBBBOAAMMM MMMMFBBOOOBAMMMM MMMMMMMFBBAAMMMM MMMMMMMMMMMMMMMM } # tile 340 (cyan / detect food) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMBBBBMMMMMMMM MMMMBBBBBBMMMMMM MMMBBBGGGBBBBMMM MMMBBGGBBGBBBMMM MMBBBBGGBBBBOAMM MMBBGBBGGBBBOAAM MBBBBGGGBBBOBAMM MBBBBBBBBBBOAAMM MBOOBBBBBBOBAMMM MMBBOOOBBBOAAMMM MMMMBBBOOOBAMMMM MMMMMMMBBBAAMMMM MMMMMMMMMMMMMMMM } # tile 341 (light blue / cause fear) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMEBBEMMMMMMMM MMMMBBBBBEMMMMMM MMMEBBAAABBBEMMM MMMBBAABBABBBMMM MMEBBBAABBBBOAMM MMBBABBAABBBOAAM MEBBBAAABBBOBAMM MBBBBBBBBBBOAAMM MBOOBBBBBBOBAMMM MMBBOOOBBBOAAMMM MMMMBBBOOOBAMMMM MMMMMMMBBBAAMMMM MMMMMMMMMMMMMMMM } # tile 342 (dark blue / clairvoyance) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMEEEEMMMMMMMM MMMMEEEEEEMMMMMM MMMEEEHHHEEEEMMM MMMEEHHEEHEEBMMM MMEEEEHHEEEEOAMM MMEEHEEHHEEBOAAM MEEEEHHHEEEOEAMM MEEEEEEEEEBOAAMM MEOOEEEEEEOEAMMM MMEEOOOEEBOAAMMM MMMMEEEOOOEAMMMM MMMMMMMEEEAAMMMM MMMMMMMMMMMMMMMM } # tile 343 (indigo / cure sickness) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMEEEEMMMMMMMM MMMMEEEEEEMMMMMM MMMEEEIIIEEEEMMM MMMEEIIEEIEEBMMM MMEEEEIIEEEEOAMM MMEEIEEIIEEBOAAM MEEEEIIIEEEOEAMM MEEEEEEEEEBOAAMM MEOOEEEEEEOEAMMM MMEEOOOEEBOAAMMM MMMMEEEOOOEAMMMM MMMMMMMEEEAAMMMM MMMMMMMMMMMMMMMM } # tile 344 (magenta / charm monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKIIKMMMMMMMM MMMMIIIIIKMMMMMM MMMKIIEEEIIIKMMM MMMIIEEIIEIICMMM MMKIIIEEIIIIOAMM MMIIEIIEEIICOAAM MKIIIEEEIIIOIAMM MIIIIIIIIICOAAMM MIOOIIIIIIOIAMMM MMIIOOOIICOAAMMM MMMMIIIOOOIAMMMM MMMMMMMIIIAAMMMM MMMMMMMMMMMMMMMM } # tile 345 (purple / haste self) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMEDEDMMMMMMMM MMMMDEDEDEMMMMMM MMMDEDHHHDEDMMMM MMMEDHHEDHDECMMM MMEDEDHHEDEDOAMM MMDEHEDHHEDCOAAM MDEDEHHHEDEOIAMM MEDEDEDEDECOAAMM MDOOEDEDEDOIAMMM MMIIOOOEDCOAAMMM MMMMIIIOOOIAMMMM MMMMMMMIIIAAMMMM MMMMMMMMMMMMMMMM } # tile 346 (violet / detect unseen) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJBIJMMMMMMMM MMMMBIBIBJMMMMMM MMMJIBAAABIBJMMM MMMIBAAIBABICMMM MMJBIBAAIBIBOAMM MMBIAIBAAIBCOAAM MJIBIAAAIBIOIAMM MIBIBIBIBICOAAMM MIOOIBIBIBOIAMMM MMIIOOOIBCOAAMMM MMMMIIIOOOIAMMMM MMMMMMMIIIAAMMMM MMMMMMMMMMMMMMMM } # tile 347 (tan / levitation) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJCKJMMMMMMMM MMMMCKCKCJMMMMMM MMMJKCHHHCKCJMMM MMMKCHHKCHCKCMMM MMJCKCHHKCKCOAMM MMCKHKCHHKCCOAAM MJKCKHHHKCKOKAMM MKCKCKCKCKCOAAMM MJOOKCKCKCOKAMMM MMKKOOOKCCOAAMMM MMMMKKKOOOKAMMMM MMMMMMMKKKAAMMMM MMMMMMMMMMMMMMMM } # tile 348 (plaid / extra healing) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJEEJMMMMMMMM MMMMDEEDDJMMMMMM MMMJDFHHHFFDJMMM MMMDDHHDDHFDCMMM MMJDDEHHDEEDOAMM MMEDHEEHHEECOAAM MJFDDHHHDFFOEAMM MFFDDFFDDFCOAAMM MJOODEEDDEODAMMM MMEDOOODDCOAAMMM MMMMEFDOOOFAMMMM MMMMMMMEFDAAMMMM MMMMMMMMMMMMMMMM } # tile 349 (light brown / restore ability) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHHKKKJMMM MMMKKHHKKHKKCMMM MMJKKKHHKKKKOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKOJAMM MKKKKKKKKKCOAAMM MJOOKKKKKKOJAMMM MMJJOOOKKCOAAMMM MMMMJJJOOOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 350 (dark brown / invisibility) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJJJJMMMMMMMM MMMMJJJJJJMMMMMM MMMJJJHHHJJJJMMM MMMJJHHJJHJJKMMM MMJJJJHHJJJJOAMM MMJJHJJHHJJKOAAM MJJJJHHHJJJOJAMM MJJJJJJJJJKOAAMM MJOOJJJJJJOJAMMM MMJJOOOJJKOAAMMM MMMMJJJOOOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 351 (gray / detect treasure) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPPPPMMMMMMMM MMMMPPPPPPMMMMMM MMMPPPAAAPPPPMMM MMMPPAAPPAPPBMMM MMPPPPAAPPPPOAMM MMPPAPPAAPPBOAAM MPPPPAAAPPPOPAMM MPPPPPPPPPBOAAMM MPOOPPPPPPOPAMMM MMPPOOOPPBOAAMMM MMMMPPPOOOPAMMMM MMMMMMMPPPAAMMMM MMMMMMMMMMMMMMMM } # tile 352 (wrinkled / remove curse) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKMMMMMMM MMMMKKAAAKKKJMMM MMMKKAAKKAKKKMMM MMJKKKAAKKKKOAMM MMKKAKKAAKKKOAAM MJKKKAAAKKKOKAMM MKKKKKKKKKLOAAMM MKOOLKKKKKOKAMMK MMJKOOKKKKOAAMMM MMMMJKLOOOKAMMMM MMMMMMJJKKAAMMMM MMMMMMMMMMMMMMMM } # tile 353 (dusty / magic mapping) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMKMMMMMMMKAMMMM MMKAJKKJMMMMMMMM MMMMKKKKKJMMKMMM MKAJKKHHHKKKJMKA MMMKKHHKKHKKCMMM MMJKAKHHKKAKOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKOJAMM MKKKKKKKKKCOAAMM AJOOKKKKAKOJAMMM MMJJOOOKKCOAAMMM MMMMJJJOOOJAMMMM MKAKAMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 354 (bronze / identify) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKCCKMMMMMMMM MMMMCCCCCKMMMMMM MMMKCCHHHCCCKMMM MMMCCHHCCHCCCMMM MMKCCCHHCCCCOAMM MMCCHCCHHCCCOAAM MKCCCHHHCCCOCAMM MCCCCCCCCCCOAAMM MKOOCCCCCCOCAMMM MMCCOOOCCCOAAMMM MMMMCCCOOOCAMMMM MMMMMMMCCCAAMMMM MMMMMMMMMMMMMMMM } # tile 355 (copper / turn undead) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKCKCKJMMMMMM MMMJCKHHHKCKJMMM MMMCKHHCKHKCCMMM MMJKCKHHCKCKOAMM MMKCHCKHHCKCOAAM MJCKCHHHCKCOJAMM MCKCKCKCKCCOAAMM MJOOCKCKCKOJAMMM MMCJOOOCKCOAAMMM MMMMJCJOOOJAMMMM MMMMMMMJCJAAMMMM MMMMMMMMMMMMMMMM } # tile 356 (silver / polymorph) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPPPPMMMMMMMM MMMMPPPPPPMMMMMM MMMPPPNNNPPPPMMM MMMPPNNPPNPPBMMM MMPPPPNNPPPPOAMM MMPPNPPNNPPBOAAM MPPPPNNNPPPOPAMM MPPPPPPPPPBOAAMM MPOOPPPPPPOPAMMM MMPPOOOPPBOAAMMM MMMMPPPOOOPAMMMM MMMMMMMPPPAAMMMM MMMMMMMMMMMMMMMM } # tile 357 (gold / teleport away) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMLHHLMMMMMMMM MMMMHHHHHLMMMMMM MMMLHHCCCHHHLMMM MMMHHCCHHCHHNMMM MMLHHHCCHHHHOAMM MMHHCHHCCHHNOAAM MLHHHCCCHHHOHAMM MHHHHHHHHHNOAAMM MLOOHHHHHHOHAMMM MMHHOOOHHNOAAMMM MMMMHHHOOOHAMMMM MMMMMMMHHHAAMMMM MMMMMMMMMMMMMMMM } # tile 358 (glittering / create familiar) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMNMMMMMMMMM MMMNPPPPMMNMMMMM MMMMPPPPPPMMMNMM MMMPPPHHHPPPPMMM MMNPPHHPPHPPBMMM MMPPPPHHPPPPONMM MNPPHPPHHPPBOAAM MPPPPHHHPPPOPAMM NPPPPPPPPPBONAMM MPOONPPPPPOPAMMM MMPPOONPPBOAAMMM MMMNMPPOOOPAMMMM MMMMMMMPPPANMMMM MMMMMMMNMMMMMMMM } # tile 359 (shining / cancellation) { MMMMNMMMMMMMMMMM MMMMMMMNMMMMMMMM MMNMMMMMMMMMMMMM MMMMPNPPMMMMMMMM MMMMPNNNPPMMMMMM MMMPNNAAAPPPPMMM MMMPNAAPPAPPBMMM MMPNNPAAPPPPOAMM MMPNAPPAAPPBOAAM MPNPPAAAPPPOPAMM MPPPPPPPPPBOAAMM MPOOPPPPPPOPAMMM MMPPOOOPPBOAAMMM MMMMPPPOOOPAMMMM MMMMMMMPPPAAMMMM MMMMMMMMMMMMMMMM } # tile 360 (dull / protection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKCCCKKKJMMM MMMKKCCKKCKKJMMM MMJKKKCCKKKKPAMM MMKKCKKCCKKJPAAM MJKKKCCCKKKPJAMM MKKKKKKKKKJPAAMM MJPPKKKKKKPJAMMM MMJJPPPKKJPAAMMM MMMMJJJPPPJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 361 (thin / jumping) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMJKJMMMMMMMM MMMMJKKKKKJMMMMM MMMMKKHHHKKKKMMM MMMJKHHKKHKKOAMM MMMKKKHHKKKKOAAM MMJKHKKHHKKCJAMM MMKKKHHHKKKOAAMM MJOCKKKKKKCJAMMM MMJJOOCKKKOAAMMM MMMMJJJOCOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 362 (thick / stone to flesh) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKHHHKKKJMMM MMMKKHHKKHKKCMMM MMJKKKHHKKKKOAMM MMKKHKKHHKKCOAAM MJKKKHHHKKKOLAMM MKKKKKKKKKCOJAMM MJOOKKKKKKOLAMMM MJLLOOOKKCOJAMMM MMJJLLLOOOLAAMMM MMMMJJJLLLJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 363 (plain / blank paper) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMJKKJMMMMMMMM MMMMKKKKKJMMMMMM MMMJKKKKKKKKJMMM MMMKKKKKKKKKCMMM MMJKKKKKKKKKOAMM MMKKKKKKKKKCOAAM MJKKKKKKKKKOJAMM MKKKKKKKKKCOAAMM MJOOKKKKKKOJAMMM MMJJOOOKKCOAAMMM MMMMJJJOOOJAMMMM MMMMMMMJJJAAMMMM MMMMMMMMMMMMMMMM } # tile 364 (papyrus / Book of the Dead) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMAAAAMMMMMMMM MMMMAAAAAAMMMMMM MMMAAAOOOAAAAMMM MMMAAOAOOOAAAMMM MMAAAAOOAOAAOMMM MMAAAOAOOAAAOMMM MAAAAOOOAAAOAMMM MAAAAAAAAAAOMMMM MAOOAAAAAAOAMMMM MMAAOOOAAAOMMMMM MMMMAAAOOOAMMMMM MMMMMMMAAAMMMMMM MMMMMMMMMMMMMMMM } # tile 365 (glass / light) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMNBMMM MMMMMMMMMMNBAAMM MMMMMMMMMNBAAMMM MMMMMMMMNBAAMMMM MMMMMMMNBAAMMMMM MMMMMMNBAAMMMMMM MMMMMNBAAMMMMMMM MMMMNBAAMMMMMMMM MMMNBAAMMMMMMMMM MMMBAFMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 366 (balsa / secret door detection) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMOKMMM MMMMMMMMMMOKAAMM MMMMMMMMMLKAAMMM MMMMMMMMLKAAMMMM MMMMMMMLKAAMMMMM MMMMMMLKAAMMMMMM MMMMMLKAAMMMMMMM MMMMOKAAMMMMMMMM MMMOKAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 367 (crystal / enlightenment) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNMMMM MMMMMMMMMMNBMMMM MMMMMMMMMNBAMMMM MMMMMMMMNBAMMMMM MMMMMMMNBAMMMMMM MMMMMMNBAMMMMMMM MMMMMNBAMMMMMMMM MMMMNBAMMMMMMMMM MMMMBAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 368 (maple / create monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMKJAAMM MMMMMMMMMKJAAMMM MMMMMMMMKJAAMMMM MMMMMMMKJAAMMMMM MMMMMMKJAAMMMMMM MMMMMKJAAMMMMMMM MMMMKJAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 369 (pine / wishing) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMLLAAMM MMMMMMMMMLLAAMMM MMMMMMMMLLAAMMMM MMMMMMMLLAAMMMMM MMMMMMLLAAMMMMMM MMMMMLLAAMMMMMMM MMMMLLAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 370 (oak / nothing) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNMMMM MMMMMMMMMMNNOMMM MMMMMMMMMJKOAAMM MMMMMMMMJJJAAMMM MMMMMMMJJKAAMMMM MMMMMMJKJAAMMMMM MMMMMJJJAAMMMMMM MMMMJJKAAMMMMMMM MMMOKJAAMMMMMMMM MMNNOAAMMMMMMMMM MMMNAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 371 (ebony / striking) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMAJAAMM MMMMMMMMMAJAAMMM MMMMMMMMAJAAMMMM MMMMMMMAJAAMMMMM MMMMMMAJAAMMMMMM MMMMMAJAAMMMMMMM MMMMAJAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 372 (marble / make invisible) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMIOAAMM MMMMMMMMMNIAAMMM MMMMMMMMNNAAMMMM MMMMMMMIIAAMMMMM MMMMMMNNAAMMMMMM MMMMMINAAMMMMMMM MMMMNIAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 373 (tin / slow monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMPPAAMM MMMMMMMMMPPAAMMM MMMMMMMMPPAAMMMM MMMMMMMPPAAMMMMM MMMMMMPPAAMMMMMM MMMMMPPAAMMMMMMM MMMMPPAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 374 (brass / speed monster) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMHCAAMM MMMMMMMMMHCAAMMM MMMMMMMMHCAAMMMM MMMMMMMHCAAMMMMM MMMMMMHCAAMMMMMM MMMMMHCAAMMMMMMM MMMMHCAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 375 (copper / undead turning) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMCCAAMM MMMMMMMMMCCAAMMM MMMMMMMMCCAAMMMM MMMMMMMCCAAMMMMM MMMMMMCCAAMMMMMM MMMMMCCAAMMMMMMM MMMMCCAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 376 (silver / polymorph) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMNPAAMM MMMMMMMMMNPAAMMM MMMMMMMMNPAAMMMM MMMMMMMNPAAMMMMM MMMMMMNPAAMMMMMM MMMMMNPAAMMMMMMM MMMMNPAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 377 (platinum / cancellation) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMNOAAMM MMMMMMMMMNBAAMMM MMMMMMMMNBAAMMMM MMMMMMMNBAAMMMMM MMMMMMNBAAMMMMMM MMMMMNBAAMMMMMMM MMMMNOAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 378 (iridium / teleportation) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMNOAAMM MMMMMMMMMPIAAMMM MMMMMMMMPIAAMMMM MMMMMMMPIAAMMMMM MMMMMMPIAAMMMMMM MMMMMPIAAMMMMMMM MMMMNIAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 379 (zinc / opening) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMLPAAMM MMMMMMMMMLPAAMMM MMMMMMMMLPAAMMMM MMMMMMMLPAAMMMMM MMMMMMLPAAMMMMMM MMMMMLPAAMMMMMMM MMMMLPAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 380 (aluminum / locking) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMPPAAMM MMMMMMMMMBPAAMMM MMMMMMMMPPAAMMMM MMMMMMMBPAAMMMMM MMMMMMPPAAMMMMMM MMMMMBPAAMMMMMMM MMMMPPAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 381 (uranium / probing) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMPNOMMM MMMMMMMMMPPPAAMM MMMMMMMMHHPAAMMM MMMMMMMHAHAAMMMM MMMMMMPAHAAMMMMM MMMMMPPPAAMMMMMM MMMMPPPAAMMMMMMM MMMPPPAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 382 (iron / digging) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMKJMMM MMMMMMMMMMKPAAMM MMMMMMMMMPPAAMMM MMMMMMMMPPAAMMMM MMMMMMMPPAAMMMMM MMMMMMPPAAMMMMMM MMMMMPPAAMMMMMMM MMMMKPAAMMMMMMMM MMMKJAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 383 (steel / magic missile) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMKPMMM MMMMMMMMMMOPAAMM MMMMMMMMMOPAAMMM MMMMMMMMOPAAMMMM MMMMMMMOPAAMMMMM MMMMMMPPAAMMMMMM MMMMMPPAAMMMMMMM MMMMKPAAMMMMMMMM MMMKKAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 384 (hexagonal / fire) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMPNMMMM MMMMMMMMMPNMAAMM MMMMMMMMPNMAAMMM MMMMMMMPNMAAMMMM MMMMMMPNMAAMMMMM MMMMMPNMAAMMMMMM MMMMPNMAAMMMMMMM MMMPNMAAMMMMMMMM MMMNMAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 385 (short / cold) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMNOMMMMM MMMMMMMMNOMMMMMM MMMMMMMDIAAMMMMM MMMMMMDIAAMMMMMM MMMMMDIAAMMMMMMM MMMMNIAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 386 (runed / sleep) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMNOMMM MMMMMMMMMMNOAAMM MMMMMMMMMDIAAMMM MMMMMMMMAIAAMMMM MMMMMMMDIAAMMMMM MMMMMMAIAAMMMMMM MMMMMDIAAMMMMMMM MMMMNIAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 387 (long / death) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMNOM MMMMMMMMMMMMNNMM MMMMMMMMMMMDIMMM MMMMMMMMMMDIAAMM MMMMMMMMMDIAAMMM MMMMMMMMDIAAMMMM MMMMMMMDIAAMMMMM MMMMMMDIAAMMMMMM MMMMMDIAAMMMMMMM MMMMDIAAMMMMMMMM MMMNIAAMMMMMMMMM MMNOAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 388 (curved / lightning) { MMMMMMMMMMMMMMMM MMMMMMMNOMMMMMMM MMMMMMMNOAMMMMMM MMMMMMMCIAMMMMMM MMMMMMMDIAMMMMMM MMMMMMMDIAMMMMMM MMMMMMJIKAMMMMMM MMMMMMKIJAMMMMMM MMMMMMDIAAMMMMMM MMMMMDIAAMMMMMMM MMMMNIAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 389 (forked) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMNMMMMMM MMMMMMMMNMMNOMMM MMMMMMMDMMNOAAMM MMMMMMMDMDIAAMOM MMMMMMMDDIAAMOAM MMMMMMMDIIIIIAMM MMMMMMDIAAAAAMMM MMMMMDIAAMMMMMMM MMMMNIAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 390 (spiked) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMNNOMMM MMMMMMMMMMDIOMMM MMMMMMMMMDIAPMMM MMMMMMMMDIAAMMMM MMMMMMMDIAAMMMMM MMMMMMDIAAMMMMMM MMMMMDIAAMMMMMMM MMMMNIAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 391 (jeweled) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMNNBMMM MMMMMMMMMMNBBMMM MMMMMMMMMMBBBAMM MMMMMMMMMDIAAMMM MMMMMMMMDIAAMMMM MMMMMMMDIAAMMMMM MMMMMMDIAAMMMMMM MMMMMDIAAMMMMMMM MMMMNIAAMMMMMMMM MMMNOAAMMMMMMMMM MMMMAAMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 392 (gold piece) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MJKKKJMJJMMMMMMM JKCKKKJKKKJMMMMM KCKKKJKAAAKAMMMM KKKKKJAHALKAAMMM KKKKJKHLLHAHAMMM MKKJJKLHCALAMMMM MAAAJKLALHCAHAMM MMMAAKAHAHMMMMMM MMMMAAAALAHAMHAM MMMMMMHAMMMMMMMM MMMMMMMMMHAMMMMM MMMMMMMMMMMHAMMM } # tile 393 (white / dilithium crystal) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMONOOOMMMMMM MMMMONOOOBOMMMMM MMMNNNONONBBMMMM MMMMONOOOBOAAMMM MMMMMONOBOAAAAMM MMMMMMOOOAAAMMMM MMMMMMMOAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 394 (white / diamond) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMONOOOMMMMMM MMMMONOOOBOMMMMM MMMNNNONONBBMMMM MMMMONOOOBOAAMMM MMMMMONOBOAAAAMM MMMMMMOOOAAAMMMM MMMMMMMOAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 395 (red / ruby) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMDNDDDMMMMMM MMMMDNDDDKDMMMMM MMMDNDDKDKKKMMMM MMMMDCDDDKDAAMMM MMMMMDCDKDAAAAMM MMMMMMDDDAAAMMMM MMMMMMMDAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 396 (orange / jacinth) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMCNCCCMMMMMM MMMMCNCCCKCMMMMM MMMCNCCKCKKKMMMM MMMMCLCCCKCAAMMM MMMMMCLCKCAAAAMM MMMMMMCCCAAAMMMM MMMMMMMCAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 397 (blue / sapphire) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMBNBBBMMMMMM MMMMBNBBBEBMMMMM MMMNNNBEBEEEMMMM MMMMBNBBBEBAAMMM MMMMMBNBEBAAAAMM MMMMMMBBBAAAMMMM MMMMMMMBAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 398 (black / black opal) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMAAAAAMMMMMM MMMMANAAAAAMMMMM MMMANAAAAAAAMMMM MMMAAAAAAAAAPMMM MMMMAAAAAAAPPPMM MMMMMMAAAPPPMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 399 (green / emerald) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMFGFFFMMMMMM MMMMFGFFFFFMMMMM MMMGGFGFGFFFMMMM MMMMFGFFFFFAAMMM MMMMMFGFFFAAAAMM MMMMMMFGFAAAMMMM MMMMMMMFAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 400 (green / turquoise) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMFGFFFMMMMMM MMMMFGFFFFFMMMMM MMMGGFGFGFFFMMMM MMMMFGFFFFFAAMMM MMMMMFGFFFAAAAMM MMMMMMFGFAAAMMMM MMMMMMMFAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 401 (yellow / citrine) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMHNHHHMMMMMM MMMMHNHHHCHMMMMM MMMHNHHCHCCCMMMM MMMMHLHHHCHAAMMM MMMMMHLHCHAAAAMM MMMMMMHHHAAAMMMM MMMMMMMHAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 402 (green / aquamarine) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMFGFFFMMMMMM MMMMFGFFFFFMMMMM MMMGGFGFGFFFMMMM MMMMFGFFFFFAAMMM MMMMMFGFFFAAAAMM MMMMMMFGFAAAMMMM MMMMMMMFAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 403 (yellowish brown / amber) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMKCKKKMMMMMM MMMMKCKKKJKMMMMM MMMCCCKJKJJJMMMM MMMMKCKKKJKAAMMM MMMMMKCKJKAAAAMM MMMMMMKKKAAAMMMM MMMMMMMKAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 404 (yellowish brown / topaz) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMKCKKKMMMMMM MMMMKCKKKJKMMMMM MMMCCCKJKJJJMMMM MMMMKCKKKJKAAMMM MMMMMKCKJKAAAAMM MMMMMMKKKAAAMMMM MMMMMMMKAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 405 (black / jet) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMAAAAAMMMMMM MMMMANAAAAAMMMMM MMMANAAAAAAAMMMM MMMAAAAAAAAAPMMM MMMMAAAAAAAPPPMM MMMMMMAAAPPPMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 406 (white / opal) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMONOOOMMMMMM MMMMONOOOBOMMMMM MMMNNNONONBBMMMM MMMMONOOOBOAAMMM MMMMMONOBOAAAAMM MMMMMMOOOAAAMMMM MMMMMMMOAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 407 (yellow / chrysoberyl) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMHNHHHMMMMMM MMMMHNHHHCHMMMMM MMMHNHHCHCCCMMMM MMMMHLHHHCHAAMMM MMMMMHLHCHAAAAMM MMMMMMHHHAAAMMMM MMMMMMMHAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 408 (red / garnet) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMDNDDDMMMMMM MMMMDNDDDKDMMMMM MMMDNDDKDKKKMMMM MMMMDCDDDKDAAMMM MMMMMDCDKDAAAAMM MMMMMMDDDAAAMMMM MMMMMMMDAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 409 (violet / amethyst) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMINIIIMMMMMM MMMMINIIIEIMMMMM MMMNNNININEIMMMM MMMMINIIIEIAAMMM MMMMMINIEIAAAAMM MMMMMMIIIAAAMMMM MMMMMMMIAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 410 (red / jasper) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMDNDDDMMMMMM MMMMDNDDDKDMMMMM MMMDNDDKDKKKMMMM MMMMDCDDDKDAAMMM MMMMMDCDKDAAAAMM MMMMMMDDDAAAMMMM MMMMMMMDAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 411 (violet / fluorite) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMINIIIMMMMMM MMMMINIIIEIMMMMM MMMNNNININEIMMMM MMMMINIIIEIAAMMM MMMMMINIEIAAAAMM MMMMMMIIIAAAMMMM MMMMMMMIAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 412 (black / obsidian) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMAAAAAMMMMMM MMMMANAAAAAMMMMM MMMANAAAAAAAMMMM MMMAAAAAAAAAPMMM MMMMAAAAAAAPPPMM MMMMMMAAAPPPMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 413 (orange / agate) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMCNCCCMMMMMM MMMMCNCCCKCMMMMM MMMCNCCKCKKKMMMM MMMMCLCCCKCAAMMM MMMMMCLCKCAAAAMM MMMMMMCCCAAAMMMM MMMMMMMCAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 414 (green / jade) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMFGFFFMMMMMM MMMMFGFFFFFMMMMM MMMGGFGFGFFFMMMM MMMMFGFFFFFAAMMM MMMMMFGFFFAAAAMM MMMMMMFGFAAAMMMM MMMMMMMFAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 415 (white / worthless piece of white glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMONOOOMMMMMM MMMMONOOOBOMMMMM MMMNNNONONBBMMMM MMMMONOOOBOAAMMM MMMMMONOBOAAAAMM MMMMMMOOOAAAMMMM MMMMMMMOAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 416 (blue / worthless piece of blue glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMBNBBBMMMMMM MMMMBNBBBEBMMMMM MMMNNNBEBEEEMMMM MMMMBNBBBEBAAMMM MMMMMBNBEBAAAAMM MMMMMMBBBAAAMMMM MMMMMMMBAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 417 (red / worthless piece of red glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMDNDDDMMMMMM MMMMDNDDDKDMMMMM MMMDNDDKDKKKMMMM MMMMDCDDDKDAAMMM MMMMMDCDKDAAAAMM MMMMMMDDDAAAMMMM MMMMMMMDAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 418 (yellowish brown / worthless piece of yellowish brown glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMKCKKKMMMMMM MMMMKCKKKJKMMMMM MMMCCCKJKJJJMMMM MMMMKCKKKJKAAMMM MMMMMKCKJKAAAAMM MMMMMMKKKAAAMMMM MMMMMMMKAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 419 (orange / worthless piece of orange glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMCNCCCMMMMMM MMMMCNCCCKCMMMMM MMMCNCCKCKKKMMMM MMMMCLCCCKCAAMMM MMMMMCLCKCAAAAMM MMMMMMCCCAAAMMMM MMMMMMMCAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 420 (yellow / worthless piece of yellow glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMHNHHHMMMMMM MMMMHNHHHCHMMMMM MMMHNHHCHCCCMMMM MMMMHLHHHCHAAMMM MMMMMHLHCHAAAAMM MMMMMMHHHAAAMMMM MMMMMMMHAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 421 (black / worthless piece of black glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMAAAAAMMMMMM MMMMANAAAAAMMMMM MMMANAAAAAAAMMMM MMMAAAAAAAAAPMMM MMMMAAAAAAAPPPMM MMMMMMAAAPPPMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 422 (green / worthless piece of green glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMFGFFFMMMMMM MMMMFGFFFFFMMMMM MMMGGFGFGFFFMMMM MMMMFGFFFFFAAMMM MMMMMFGFFFAAAAMM MMMMMMFGFAAAMMMM MMMMMMMFAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 423 (violet / worthless piece of violet glass) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPMMMMMMMM MMPMMMMPMMMMPMMM MMMPMMMMMMMPMMMM MMMMMINIIIMMMMMM MMMMINIIIEIMMMMM MMMNNNININEIMMMM MMMMINIIIEIAAMMM MMMMMINIEIAAAAMM MMMMMMIIIAAAMMMM MMMMMMMIAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 424 (gray / luckstone) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPPPMMMMMM MMMMPNPPPPPMMMMM MMMPNPPPPPPPAMMM MMPPPPPPPPPPPAAM MMPPPPPPPPPPPAAA MMMPPPPPPPPPAAAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 425 (gray / loadstone) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPPPMMMMMM MMMMPNPPPPPMMMMM MMMPNPPPPPPPAMMM MMPPPPPPPPPPPAAM MMPPPPPPPPPPPAAA MMMPPPPPPPPPAAAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 426 (gray / touchstone) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPPPMMMMMM MMMMPNPPPPPMMMMM MMMPNPPPPPPPAMMM MMPPPPPPPPPPPAAM MMPPPPPPPPPPPAAA MMMPPPPPPPPPAAAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 427 (gray / flint) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMPPPPPMMMMMM MMMMPNPPPPPMMMMM MMMPNPPPPPPPAMMM MMPPPPPPPPPPPAAM MMPPPPPPPPPPPAAA MMMPPPPPPPPPAAAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 428 (rock) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKKKMMMMMMM MMMMMKLCKKMMMMMM MMMMMKCCKJAMMMMM MMMMMKKKKJAMMMMM MMMMMMKJJAAMMMMM MMMMMMMAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 429 (boulder) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMKKKJMMMMMM MMMMKKKKKKJJMMMM MMMKCCKKKKKJJMMM MMMKCKKKCKKKJAMM MMKKKKKKKJKKJJAM MMKKKKKKKKKKJJAA MMKJKKKCKKKKJJAA MMKKKKKKJKKKJJAA MMMKKKKKKKKKJAAA MMMJJKKKKKJJJAAM MMMMJJJJJJJJAAMM MMMMMMJJJJAAAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 430 (statue) { MMMMMMMMMMMMMMMM MMMMMMMMJJMMMMMM MMMMMMMKCJJMMMMM MMMMMMMKKJJMMMMM MMMMCKMCKJMMMMMM MMMMJJCKKJMCJMMM MMMMMJCKJJJJJMMM MMMMMJCKJJJMAAMM MMMMMMCKJMMMAAAM MMMMMMCKJAAAAAAA MMMMKCKKJAAAAAAM MMMJCCKKJAJJAAMM MMMJKKKKJJJJJAMM MMMMJJKKKJJJAAMM MMMMMJJJJJJAAMMM MMMMMMMMMMMMMMMM } # tile 431 (heavy iron ball) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMPPPMMMMMMM MMMMMPOBPPMMMMMM MMMMMPBBPMAMMMMM MMMMMPPPPMAMMMMM MMMMMMPMMAAMMMMM MMMMMMMAAAMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 432 (iron chain) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MPPMPPMPPMMMMMMM PMAPMAPMAPPMMMMM MPPAPPAPPPAPMMMM MMAAMAAMAPAPAMMM MMMMMMMMMMPAMMMM MMMMMMMMMPAPMMMM MMMMMMMMMPAPPMPM MMMMMMMMMMPMAPAP MMMMMMMMMMMPPMPA MMMMMMMMMMMMAAMM } # tile 433 (splash of venom / blinding venom) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMHHHHMMMMM MMMMMHHAAAAHHMMM MMMMHAAAAAAAHMMM MMMMHAAAAAAAHMMM MMMMHAAAAHHHMMMM MMMMMHHHHMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 434 (splash of venom / acid venom) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMHHHHMMMMM MMMMMHHGGGGHHMMM MMMMHGGGGGGGHMMM MMMMHGGGGGGGHMMM MMMMHGGGGHHHMMMM MMMMMHHHHMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } nethack-3.4.3/win/share/other.txt0100644000000000000000000022525507764735042015447 0ustar rootrootA = (0, 0, 0) B = (0, 182, 255) C = (255, 108, 0) D = (255, 0, 0) E = (0, 0, 255) F = (0, 145, 0) G = (108, 255, 0) H = (255, 255, 0) I = (255, 0, 255) J = (145, 71, 0) K = (204, 79, 0) L = (255, 182, 145) M = (71, 108, 108) N = (255, 255, 255) O = (218, 218, 182) P = (108, 145, 182) # tile 0 (dark part of a room) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 1 (wall) { ANNOAMPPPPPMNNOA AOOOAMPMPPMMOOOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AOOOAMMPPPPMOOOA AMAAAMMPPPPMMAMA AMMMAMMPPPPMMMMA AOPPAMMPPMPMOPMA ANNOAMPPPPPMNNOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AOOOAMMPMPMMOOOA AMAAAMMPPPPMMAMA AMMMAMMPPPPMMMMA AOPPAMMPPPPMOPMA } # tile 2 (wall) { AAANOOAAAAANOOAA OOONOOAMOOONOOAM POOMMMAMPOOMMMAM MMMMMMMMMMMMMMMM PPMMMPPPPPMMMPPP PPNOOPPPPPNOOPPP OONOOAMOOONOOAMO OOMMMAMPOOMMMAMP MMMMMMMMMMMMMMMM PPMOPPPPMOPPPMOP PPMPPPPPMPPPPMPP MMMMMMMMMMMMMMMM MOPPPPMOPPPPMOPP MPPPPPMPPPPPMPPP MMMMMMMMMMMMMMMM AAAAAAAAAAAAAAAA } # tile 3 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM APPMMMMMMMMMPPPM AOOOAAAAAAAAOOOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AMAAAMMPPPPMMAMA AMMMAMMPPPPMMMMA AOPPAMMPPPPMOPMA } # tile 4 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM APPMMMMMMMMMPPPM AOOOAAAAAAAAOOOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AMAAAMMPPPPMMAMA AMMMAMMPPPPMMMMA AOPPAMMPPPPMOPMA } # tile 5 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM PPMOPPPPMOPPPMOP PPMPPPPPMPPPPMPP MMMMMMMMMMMMMMMM MOPPPPMOPPPPMOPP MPPPPPMPPPPPMPPP MMMMMMMMMMMMMMMM AAAAAAAAAAAAAAAA } # tile 6 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM PPMOPPPPMOPPPMOP PPMPPPPPMPPPPMPP MMMMMMMMMMMMMMMM MOPPPPMOPPPPMOPP MPPPPPMPPPPPMPPP MMMMMMMMMMMMMMMM AAAAAAAAAAAAAAAA } # tile 7 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM APPMMMMMMMMMPPPM AOOOAAAAAAAAOOOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AMAAAMMPPPPMMAMA AMMMAMMPPPPMMMMA AOPPAMMPPPPMOPMA } # tile 8 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM PPMOPPPPMOPPPMOP PPMPPPPPMPPPPMPP MMMMMMMMMMMMMMMM MOPPPPMOPPPPMOPP MPPPPPMPPPPPMPPP MMMMMMMMMMMMMMMM AAAAAAAAAAAAAAAA } # tile 9 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM APPMMMMMMMMMPPPM AOOOAAAAAAAAOOOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AMAAAMMPPPPMMAMA AMMMAMMPPPPMMMMA AOPPAMMPPPPMOPMA } # tile 10 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM APPMMMMMMMMMPPPM AOOOAAAAAAAAOOOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AMAAAMMPPPPMMAMA AMMMAMMPPPPMMMMA AOPPAMMPPPPMOPMA } # tile 11 (wall) { AAANNNNOOOOOOAAA NNNNAAMMPPPPOMMM OOONAMMPPPBBOMMM OOOOOOOOOOOOOMMM OOOPPPPPPPPPPMMM OOOPPPPPPPPPPMMM OOPPPPPPPPPPPPMM OPPPPPPPPPPPPPPM MMMMMMMMMMMMMMMM APPMMMMMMMMMPPPM AOOOAAAAAAAAOOOA AOOOAMPPPPPMOOOA AOOOAMPPPPPMOOOA AMAAAMMPPPPMMAMA AMMMAMMPPPPMMMMA AOPPAMMPPPPMOPMA } # tile 12 (doorway) { AAAAAAAAAAAAAAAA AAMMMMMMMMMMMMAA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AAMMMMMMMMMMMMAA AAAAAAAAAAAAAAAA } # tile 13 (open door) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAJJMJJJJJJJJJAA AJKJJKJJKJJJJJJA AAAAAAAAAAAAAAAA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AMMMMMMMMMMMMMMA AAAAAAAAAAAAAAAA } # tile 14 (open door) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AKMMMMMMMMMMMMAA ACKMMMMMMMMMMMMA APJMMMMMMMMMMMMA AMJMMMMMMMMMMMMA AMJMMMMMMMMMMMMA AMJMMMMMMMMMMMMA AJJMMMMMMMMMMMMA APJMMMMMMMMMMMMA AMJMMMMMMMMMMMMA AMJMMMMMMMMMMMMA AMJMMMMMMMMMMMMA AKMMMMMMMMMMMMMA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 15 (closed door) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AACCKKKKKKKKJJAA ACKJJJJJJJJJJKJA APJJPKJJKJJJJJJA AMPPMPPPPPMBPPJA AMMMMMMMMMBPPMJA AMJJMJJJJJPAPAJA AJJJJKJJJJMPMAJA APKJPKJJJJJAAAJA AMPPMPPPPPPMMPJA AMMMMMMMMMMMMMJA AMJJMJJJJJJJJJJA AJKJJKJJKJJJJJJA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 16 (closed door) { AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AACCKKKKKKKKJJAA ACKJJJJJJJJJJKJA APJJPKJJKJJJJJJA AMPPMPPPPPMBPPJA AMMMMMMMMMBPPMJA AMJJMJJJJJPAPAJA AJJJJKJJJJMPMAJA APKJPKJJJJJAAAJA AMPPMPPPPPPMMPJA AMMMMMMMMMMMMMJA AMJJMJJJJJJJJJJA AJKJJKJJKJJJJJJA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 17 (iron bars) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMBBMMMMMMM MMMMBBMBPMBPMMMM MBBMBPMBPMPPMBPM MBPMBPMBPMPPMPPM MBPMBPMBPMPPMPPM MBPMBPMBPMPPAPPM MBPMBPMBPAPPAPPM MBPMBPABPAPPAPPM MBPABPABPAPPAPPA MBPABPABPAPPAPPA MBPABPABPAPPAPPA MBPABPABPAPPAPPA MBPMBPMBPMPPMPPM MMMMMMMMMMMMMMMM } # tile 18 (tree) { MMMMMMMMMMMMMMMM MMMMMFFFFFFMMMMM MMMFFFFFFFFFFMMM MMFFFFFFFFFFFFMM MMFFFFFFFFFFFFMM MMFFFFJFFFJFFFMM MMMFFFFJFJFFFMMM MMMMFFJJJJFFMMMM MMMMMMMKJJMAAAAM MMMMMMMKJMAAAAAA MMMMMMMJJMAAAAAA MMMMMMMKJMAAAAAM MMMMMMMKJAAAMMMM MMMMMMKJJJAAMMMM MMMJJJJMJMJJJAMM MMMMMMMMMMMMMMMM } # tile 19 (floor of a room) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPPMMMMMMM MMMMMMMPPMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 20 (corridor) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPPMMMMMMM MMMMMMPMMPMMMMMM MMMMMMPMMPMMMMMM MMMMMMMPPMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 21 (lit corridor) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMPPMMMMMMM MMMMMMPPPPMMMMMM MMMMMMPPPPMMMMMM MMMMMMMPPMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 22 (staircase up) { AAAAAAAAAAAAAAMA AADJJJJJJJJJDAMA AACDDJKNKKDDCAMA AAAAAANNNAAAAMMA AAADJNNNNNJDAMMA AAACNOONONNCAMMA AAAAAAOONAAAMMMA AAAAKDOOOKJAMMMA AAAACKPONKCAMMMA AAAAAAOPOAAMMMMA AAAAAKPPPJAMMMMA AAAAACKJJKAMMMMA AAAAAAAAAAAAMMMA AAAAAAAAAAAAAMMA AAAAAAAAAAAAAAMA AAAAAAAAAAAAAAAA } # tile 23 (staircase down) { AAAAAAAAAAAAAAMA AADJJJJJJJJJDAMA AACDDJNNNKDDCAMA AAAAAANNNAAAAMMA AAADJJNONJJDAMMA AAACDDONNKDCAMMA AAAAAAONOAAAMMMA AAAAPOOONONAMMMA AAAACPOOOPCAMMMA AAAAAANPNAAMMMMA AAAAAKKOJJAMMMMA AAAAACKJJKAMMMMA AAAAAAAAAAAAMMMA AAAAAAAAAAAAAMMA AAAAAAAAAAAAAAMA AAAAAAAAAAAAAAAA } # tile 24 (ladder up) { ADAAAAAAAAAAADMA AADAAAANAAAADAMA AACCCCNNNCCCCAMA AADAANANANAADMMA AAADAAANAAADAMMA AAACDDDNDDDCAMMA AAADAAAOAAADMMMA AAAAKAAOAAJAMMMA AAAACKKOKKCAMMMA AAAADAAPAADMMMMA AAAAAKJPJJAMMMMA AAAAADAAAKAMMMMA AAAAAAAAAAAAMMMA AAAAAAAAAAAAAMMA AAAAAAAAAAAAAAMA AAAAAAAAAAAAAAAA } # tile 25 (ladder down) { ADAAAAAAAAAAADMA AADAAAANAAAADAMA AACCCCCNCCCCCAMA AADAAAANAAAADMMA AAADAAANAAADAMMA AAACDDDNDDDCAMMA AAADAAAOAAADMMMA AAAAKAAOAAJAMMMA AAAACOKOKOCAMMMA AAAADAOOOADMMMMA AAAAAKJOJJAMMMMA AAAAADAAAKAMMMMA AAAAAAAAAAAAMMMA AAAAAAAAAAAAAMMA AAAAAAAAAAAAAAMA AAAAAAAAAAAAAAAA } # tile 26 (altar) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMPDPDPDPDPMMMM MMPPPDPDDDPPPMMM MMMBBPPPDPPMAAMM MMMBPPPPPPMMAMMM MMPPMMMMMMMPPMMM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM } # tile 27 (grave) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMONOPPMMMMMM MMMONPPPPPPMMMMM MMOPPPPPPPPPMMMM MOPPPPPPPPPPPMMM MOPAAPPAPAAPPMMM MOPAPAPAPAPAPAAM MOPAAPPAPAAPPAAA MOPAPAPAPAPPPAAA MOPAPAPAPAPPPAAA MOPPPPPPPPPPPAAA MOPPPPPPPFPPPAAM MOPPFMMPPFMPPAMM FFFFFFFFFFFFFFFM MMMMMMMMMMMMMMMM } # tile 28 (opulent throne) { MMMMMMMMMMMMMMMM MMMMMHHHHHMMMMMM MMMMHCCCDDHMMMMM MMMMHCCEDDHMMMMM MMMMHCEEEDHMMMMM MMMMHCCEDDHMMMMM MMMMHCCEDDHMMAAM MMMMMHCDDHAAAAAM MMCCOHCDDHOCCAAA MHHHDHHHHHCHHHAA MHMHODDDCCOHAHAA MMMHHHHHHHHHAAAM MMMHALAAALAHAAMM MMHAMAAAAAAAHMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 29 (sink) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMPMMMMPMMMMMM MMNPPPPPPPPNMMMM MNOMPMPPMPMONMMM MNOBMMPPMMBONMMM MNOBBBPPBBBONAAM MNOBBBBBBBBONAAA MNOOOOOOOOOONAAA MMNNNNNNNNNNAAAA MMMMMOOOOAAAAAAA MMMMMOOOOAAAAAMM MMMMOOOOOOAMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 30 (fountain) { MMMMEMMMMEMMMMMM MMEEEEMMEEEMMMMM MMEMMMEEEMEEMMMM MMMEMEEEEMEMMMMM MMEMMEEOEMEEMAMM MEEMEENOEMEMEAAM MEMMEMNOMEMEAAAM MMMPPPNOPPPAAAMM MMPEEENOEEEPAAMM MOEENNNOOOEEPAMM MNOEEEEEEEEONAAM MPNOOOOOOOONPAAM MMPNNNNNNNNPAAAM MMMPPPPPPPPAAAMM MMMMAAAAAAAAAMMM MMMMMMMMMMMMMMMM } # tile 31 (water) { MMMMMMMMMMNNNMMM MEEEEMMMMNEMENMM MMMMEEMEEEMMMMMM MMMMMEEEMMMMMMMM MNNMMMMMMEEMMMMM EMENMMMMEMEEMMEE MMMENMEMMMMEMMEM MMMMEEMMMMMMEEMM MMMMMMMMMMMMMMMM NMMEEMMMEEEEMMMM NNEMMEMEMMMEEMMN MEMMMMEMNNMMEENM MMMMMMMNEEEEMMMM MMEEEMMEMMMEEEMM MEMMEEMMMEMMEEEM EEMMMMEEEMMMMMEE } # tile 32 (ice) { NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNMMNNNNNNN NNNNNNMNNMNNNNNN NNNNNNMNNMNNNNNN NNNNNNNMMNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN } # tile 33 (molten lava) { DDDDDDCDDDDDDDDD DDDDDCDKDDDDDDDD DDCCDDKDDDDCCCDD DCJJKDDDDDCKJJKD DCJDKDDDDDCJKDKD DDKKDDDDDDCJDKKD DDDDDDDCDDDKKKDD DDDCDDDDDDDDDDDD DDDDJDCDDDDCDDDD DDDDDDDDDDCJKDDD DDDDDDDDDDDKDDDC DDDDCCDDDDDDDDDD DDDCJJKDDDDDDDDD CDDCJDKDDDDDDJDD DDDDKKDDDDCDDDDD DDDDDDDDDDDKDDDD } # tile 34 (lowered drawbridge) { EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA EEJJJJJJJJJJJAAA EJKKKKKKKKKKKJAA EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA EEJJJJJJJJJJKAAA EJKKKKKKKKKKKJAA EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA EEJJJJJJJJJJJAAA EJKKKKKKKKKKKJAA EKKAKKKKKKKAKKAE EJKKKKKKKKKKKJAA EEJJJJJJJJJJJAAA EJKKKKKKKKKKKJAA } # tile 35 (lowered drawbridge) { EEEEEEEEEEEEEEEE JEJKJEJKJEJKJEJK KJKKKJKKKJKKKJKK KJKAKJKAKJKAKJKA KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKKKJKKKJKKKJKK KJKAKJKAKJKAKJKA KJKKKJKKKKKKKJKK JAJKJAJKJAJKJAJK AAAAAAAAAAAAAAAA AAAEAAAEAAAEAAAE } # tile 36 (raised drawbridge) { MMMMMMMMMMMMMMMM MMJKJMJKJMJKJMMM MJKKKJKKKJKKKJMM MJKAKJKAKJKAKJAM MJKKKJKKKJKKKJAM MJKKKJKKKJKKKJAM MJKKKJKKKJKKKJAM MJKKKJKKKJKKKJAM MJKKKJKKKJKKKJAM MJKKKJKKKJKKKJAM MJKKKJKKKJKKKJAM MJKAKJKAKJKAKJAM MJKKKJKKKKKKKJAM MMJKJAJKJAJKJAAM MMMAAAMAAAMAAAMM MMMMMMMMMMMMMMMM } # tile 37 (raised drawbridge) { MMMMMMMMMMMMMMMM MMJJJJJJJJJJJMMM MJKKKKKKKKKKKJMM MKKAKKKKKKKAKKAM MJKKKKKKKKKKKJAM MMJJJJJJJJJJJAAM MJKKKKKKKKKKKJMM MKKAKKKKKKKAKKAM MJKKKKKKKKKKKJAM MMJJJJJJJJJJKAAM MJKKKKKKKKKKKJMM MKKAKKKKKKKAKKAM MJKKKKKKKKKKKJAM MMJJJJJJJJJJJAAM MMMAAAAAAAAAAAMM MMMMMMMMMMMMMMMM } # tile 38 (air) { BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB } # tile 39 (cloud) { BBBBBBBBBBBBBBBB BBBBBNNNNNNNBBBB BBBNNNNNNNNNNBBB BBNNNNNNNNNONNBB BBNNNNNNNNNNNNNB BNNNNNNNNNNNNONB NNNONNNNNNNNONNN NNNNNNNNNNOONNNN NNNNNNNNNNNNNONN NNOONNNNNNNOONNO NNNNNOOOOONNNNOO BONNNNNNNNNNOOOB BBOOONNNNOOOOOOB BBBOOOOOOOOOOBBB BBBBBBOOOOBBBBBB BBBBBBBBBBBBBBBB } # tile 40 (water) { EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE EEEEEEEEEEEEEEEE } # tile 41 (arrow trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCACDDMMMMM MMMDCCAAACCDMMMM MMMCCAAAAACDAMMM MMDCCHHAHHCDDAMM MMDCHHNANHHCDAMM MMDCHNNANNHCDAMM MMDCHNNANNHCDAMM MMDCCHAAAHCCDAMM MMMCCAAAAACCAAMM MMMDCAAAAACDAMMM MMMMDAACAADAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 42 (dart trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCACDDMMMMM MMMDCCCACCCDMMMM MMMCCCHAHCCDAMMM MMDCCHAAAHCDDMMM MMDCHHAAAHHCDAMM MMDCHNAAANHCDAMM MMDCHNNANNHCDAMM MMDCCAAAAACDDAMM MMMCCAACAACDAAMM MMMDCACACACDAMMM MMMMDDCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 43 (falling rock trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDAACDDMMMMM MMMDCCCCCCCDMMMM MMMCCCAAHCCDAMMM MMDCCHHHHHCDDAMM MMDCHHAAHHHCDAMM MMDCHHHHHHHCDAMM MMDCHHAAHHHCDAMM MMDCHAHAAHHCDAMM MMMCCAAAAHCCAAMM MMMDCCAAHCCDAMMM MMMMDCCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 44 (squeaky board) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDDMMMMM MMMDCCCCCCCDMMMM MMMCCCHHHCCDAMMM MMDCCHHNHHCDDAMM MMDAAAAAAAAADAMM MMDAAAAAAAAADAMM MMDAAAAAAAAADAMM MMDAAAAAAAAADAMM MMMCCHHNHHCCAAMM MMMDCCHHHCCDAMMM MMMMDCCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 45 (bear trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDDMMMMM MMMDAAPCPAADMMMM MMMDAHHHHHADAMMM MMDDAAPNPAACDMMM MMDCANNNNNACDAMM MMDCAAPNPAACDAMM MMDCANNNNNACDAMM MMDDAHHHHHACDAMM MMMDAACHCAADAAMM MMMDCAAAAACDAMMM MMMMDDAAADDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 46 (land mine) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDDMMMMM MMMDCCCCCCCDMMMM MMMCCCHHHCCDAMMM MMDCCHHAHHCDDAMM MMDCHHAAAHHCDAMM MMDCAAAAAAACDAMM MMDCAAAAAAACDAMM MMDCHHNNNHHCDAMM MMMCCHHNHHCCAAMM MMMDCCHHHCCDAMMM MMMMDCCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 47 (rolling boulder trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDDMMMMM MMMDCCCCCCCDMMMM MMMCCCHHHCCDAMMM MMDCCAAAAHCDDAMM MMDCAAHAAAHCDAMM MMDCAHAAAAHCDAMM MMDCAAAAAAHCDAMM MMDCAAAAAAHCDAMM MMMCCAAAAHCCAAMM MMMDCCHHHCCDAMMM MMMMDCCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 48 (sleeping gas trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDDMMMMM MMMDCCHHHCCDMMMM MMMCAAAAAAACAMMM MMDCAANNAAACDAMM MMDCHNNAAAHCDAMM MMDCHNAAANHCDAMM MMDCHAAANHHCDAMM MMDCAAAHHHACDAMM MMMCAAAAAAACAAMM MMMDCCHHHCCDAMMM MMMMDDCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 49 (rust trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDDMMMMM MMMDCCCCCCCDMMMM MMMCCCHHHCCDAMMM MMDCCAAAAACDDAMM MMDCAAEEEAACDAMM MMDCAEEEEEACDAMM MMDCAEEEEEACDAMM MMDCAAEEEAACDAMM MMMCCAAAAACCAAMM MMMDCCHHHCCDAMMM MMMMDCCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 50 (fire trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDDMMMMM MMMDCCAAACCDMMMM MMMCCAADAACDAMMM MMDCAADDAAADDAMM MMDCAADDDAACDAMM MMDCADCHCDACDAMM MMDCADHNHDACDAMM MMDCAAHNHAACDAMM MMMCCAANAACCAAMM MMMDCCAAACCDAMMM MMMMDCCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 51 (pit) { AAAAAAAAAAAAAAAA AMAAAAAAAAAAAABA AMMAAAAAAAAAABBA AMMMAAAAAAAABBBA AMMMAMMMMMMABBBA AMMMAMMMMMMABBBA AMMMAMMMMMMABBBA AMMMAMMMMMMABBBA AMMMAMMMMMMABBBA AMMMAMMMMMMABBBA AMMMAMMMMMMABBBA AMMMAAAAAAAABBBA AMMMPPPPPPPPPBBA AMMPPPPPPPPPPPBA AMPPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } # tile 52 (spiked pit) { AAAAAAAAAAAAAAAA AMAAAAAAAAAAAABA AMMAAAAAAAAAABBA AMMMAAAAAAAABBBA AMMMAMMMMMMABBBA AMMMAMNMNMMABBBA AMMMAMMMMMMABBBA AMMMAMMNMNMABBBA AMMMAMMMMMMABBBA AMMMAMNMNMMABBBA AMMMAMMMMMMABBBA AMMMAAAAAAAABBBA AMMMPPPPPPPPPBBA AMMPPPPPPPPPPPBA AMPPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } # tile 53 (hole) { MMMMMMMMMMMMMMMM MMMMMMAAAAMMMMMM MMMMMAAAAAABMMMM MMMMAAAAAAABBMMM MMMAAAAAAAAABBBM MMMAAAAAAAAAABBM MMMAAAAAAAAAABBM MMMAAAAAAAAAABBM MMMAAAAAAAAAABBM MMMMAAAAAAAAABBM MMMMMAAAAAAAABBM MMMMMAAAAAAABBMM MMMMMMAAAAABMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 54 (trap door) { AAAAAAAAAAAAAAAA AMAAAAAAAAAAAABA AMMAAAAAAAAAABBA AMMMAAAAAAAABBBA AMMMAAAAAAAABBBA AMMMAAAAAAAABBBA AMMMAAAAAAAABBBA AMMMAAAAAAAABBBA AMMMAAAAAAAABBBA AMMMAAAAAAAABBBA AMMMAAAAAAAABBBA AMMMAAAAAAAABBBA AMMMPPPPPPPPPBBA AMMPPPPPPPPPPPBA AMPPPPPPPPPPPPPA AAAAAAAAAAAAAAAA } # tile 55 (teleportation trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCACDDMMMMM MMMDCCAAACCDMMMM MMMDCAAAAACCAMMM MMDDCHHAHHCCDMMM MMDCOHAAAHOCDAMM MMDCHOAAAOHCDAMM MMDCHOAAAOHCDAMM MMDDCHHAHHCCDAMM MMMDCAAAAACCAAMM MMMDCCAAACCDAMMM MMMMDDCACDDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 56 (level teleporter) { MMMMMMMMMMMMMMMM MMMMMDDADDMMMMMM MMMMDDAAADDMMMMM MMMDCAAAAADDMMMM MMMDCCCACCCCAMMM MMDDCHAAAHCCDMMM MMDCOAAOAAOCDAMM MMDCHAOOOAHCDAMM MMDCHAAOAAHCDAMM MMDDCHAAAHCCDAMM MMMDCCCACCCCAAMM MMMDCAAAAACDAMMM MMMMDDAAADDAAMMM MMMMMDDADDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 57 (magic portal) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCACDDMMMMM MMMDCCAAACCDMMMM MMMDCAAAAACCAMMM MMDDCHHAHHHADMMM MMDDCHOAOAACDAMM MMDDOAAAAAOCDAMM MMDDAAOAOOCCDAMM MMDAHHHAHHCCDAMM MMMDCAAAAACCAAMM MMMDCCAAACCDAMMM MMMMDDCACDDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 58 (web) { OAOAMOAMMMOMMMMO MOMNNNNMNOAMMOOA OONMNOMNAMMOOAMM MNMMOOMNMNOAMMMM MNMOMMMNOAMMMMMM ONOMOMNAMMMMMMMM MONNNNAMMMMMMMMM MMOMNAMMMMMMMMMM MOAMOAMMMMMMMMMM MOONAMMMMMMMMMMM OAMOAMMMMMMMMMMM MMOAMMMMMMMMMMMM MMOAMMMMMMMMMMMM MOAMMMMMMMMMMMMM MOAMMMMMMMMMMMMM OAMMMMMMMMMMMMMM } # tile 59 (statue trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCAADDMMMMM MMMDCCAJJACDMMMM MMMCCAKCJJADAMMM MMDAAAKKJJADDAMM MMACKACKJAAADAMM MMAJJCKKJACJAAMM MMDAJCKJJJJJAAMM MMDAJCKJJJAADAMM MMMCACKJAACCAAMM MMMDACKJACCDAMMM MMMMDCCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 60 (magic trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDAMMMMM MMMDCCCCCCADMMMM MMMCCCHHHAADAMMM MMDCAHHNHAADDAMM MMDCAANNAAACDAMM MMDCAAAAAAACDAMM MMDCAAANNAACDAMM MMDCAANNNHACDAMM MMMCAAHNHHCCAAMM MMMDACHHHCCDAMMM MMMMACCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 61 (anti-magic field) { MMMMMMMMMMMMMMMM MMMMMMDDDDDMMMMM MMMMMADCCCDDMMMM MMMMDACCCCCCDMMM MMMADAAHHHCCCMMM MMADDAAHNHHACDMM MMADCAAANNAACDMM MMADCAAAAAAACDMM MMADCAANNAAACDMM MMADCAHNNNAACDMM MMAACCHHNHAACMMM MMMADCCHHHCADMMM MMMAADCCCCCAMMMM MMMMAADDDDDMMMMM MMMMMAAAAAMMMMMM MMMMMMMMMMMMMMMM } # tile 62 (polymorph trap) { MMMMMMMMMMMMMMMM MMMMMDDDDDMMMMMM MMMMDDCCCDDMMMMM MMMDCAAAPCCDMMMM MMMCCAAPHCCDAMMM MMDCCAPAAHCDDAMM MMDCHPNAAHHCDAMM MMDCHNPAPNHCDAMM MMDCHNAANPHCDAMM MMDCHHAAPAHCDAMM MMMCCHHPAACCAAMM MMMDCCPAAACDAMMM MMMMDCCCCCDAAMMM MMMMMDDDDDAAMMMM MMMMMMAAAAAMMMMM MMMMMMMMMMMMMMMM } # tile 63 (wall) { MMMMMMMNNMMMMMMM MMMMMMNNMMMMMMMM MMMMMNNMMMMMMMMM MMMMMMNNMMMMMMMM MMMMMMMNNMMMMMMM MMMMMMMMNNMMMMMM MMMMMMMMMNNMMMMM MMMMMMMMNNMMMMMM MMMMMMMNNMMMMMMM MMMMMMNNMMMMMMMM MMMMMNNMMMMMMMMM MMMMMMNNMMMMMMMM MMMMMMMNNMMMMMMM MMMMMMMMNNMMMMMM MMMMMMMMMNNMMMMM MMMMMMMMNNMMMMMM } # tile 64 (wall) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMNMMMMMMMNMMMMM MNNNMMMMMNNNMMMM NNMNNMMMNNMNNMMM NMMMNNMNNMMMNNMN MMMMMNNNMMMMMNNN MMMMMMNMMMMMMMNM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 65 (wall) { NNNNNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNNNNNNNNNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNNNN } # tile 66 (wall) { MMMMMMMMMMMMNNNN MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMMMMMMMMMNMMM MMMMNNNNNNNNNMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM MMMMNMMMMMMMMMMM NNNNNMMMMMMMMMMM } # tile 67 (cmap 67) { MMMMAAAAMMMMMMMM MMAMMMMAAMMAAMMM MAAMAAAMMMMMMAAM MAAMAMMMMAMMAAMM MMAMMMMAMAMAMAAM MAMMAAAMAMMMMAAM MAMAAMMMMMAMAAMM MMMAAMMMMAAMMMMM MAMAMMMAMMMAMAMM MMMAMMMMMMAAMAAM MAMAAAMAAAAMAMAM MAAMMAAMMMMMMMAM MMAMMMAAMMAMMAAM MMAAAAAMMAAAAAMM MMMMAAMMMMAAAMMM MMMMMMMMMMMMMMMM } # tile 68 (cmap 68) { MMMMMMMMMMMMMMMM MMMMMNNNNNNMMMMM MMMNNNNNNNNNNMMM MMNNNNNNNNNNNNMM MMNNNNNNNNNNNNMM MNNNNNNNNNNNNNNM MNNNNNNNNNNNNNNM MNNNNNNNNNNNNNNM MNNNNNNNNNNNNNNM MNNNNNNNNNNNNNNM MNNNNNNNNNNNNNNM MMNNNNNNNNNNNNMM MMNNNNNNNNNNNNMM MMMNNNNNNNNNNMMM MMMMMNNNNNNMMMMM MMMMMMMMMMMMMMMM } # tile 69 (cmap 69) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMKKMMMMMMMMMM MMMMKHKAMMMMMMMM MMMMMKHKAMMMMMMM MMMMMMKKKAMMMMMM MMMMMMMKKKAMMMMM MMMMMMMMKDKAMMMM MMMMMMMMJDKAMMMM MMMMMMMJKDJAMMMM MMMMMMJKDJAMMMMM MMMMMJHDJAMMMMMM MMMMJHDJAMMMMMMM MMMMMKJAMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 70 (cmap 70) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMJKMMMMM MMMMMMMMJDHJMMMM MMMMMMMJDHJAMMMM MMMMMMJDKJAMMMMM MMMMMJDKJAMMMMMM MMMMMKDJAMMMMMMM MMMMMKDKAMMMMMMM MMMMMMKKKAMMMMMM MMMMMMMKKKAMMMMM MMMMMMMMKHKAMMMM MMMMMMMMMKHKAMMM MMMMMMMMMMKKAMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 71 (cmap 71) { MMMMMMMMMMMMMMMM MMMMMIMMMMIMMMMM MMMMIMMMMMMIMMMM MMMIMMMMMMMMIMMM MMIMMMIIIIMMMIMM MIMMMMMMMMMMMMIM MMMMIMMIIMMIMMMM MMMMIMIIIIMIMMMM MMMMIMIIIIMIMMMM MMMMIMMIIMMIMMMM MIMMMMMMMMMMMMIM MMIMMMIIIIMMMIMM MMMIMMMMMMMMIMMM MMMMIMMMMMMIMMMM MMMMMIMMMMIMMMMM MMMMMMMMMMMMMMMM } # tile 72 (cmap 72) { MMMMMMMMMMMMMMMM MCCCCCCCCCCCCCCC MCMMMMMMMMMMMMMM MCMCCCCCCCCCCCCM MCMCMMMMMMMMMMCM MCMCMCCCCCCCCMCM MCMCMCMMMMMMCMCM MCMCMCMCCCCMCMCM MCMCMCMCCMCMCMCM MCMCMCMMMMCMCMCM MCMCMCCCCCCMCMCM MCMCMMMMMMMMCMCM MCMCCCCCCCCCCMCM MCMMMMMMMMMMMMCM MCCCCCCCCCCCCCCM MMMMMMMMMMMMMMMM } # tile 73 (cmap 73) { MMMMMMMHHMMMMMMM MMMMMMMHHMMMMMMM MMMMHHMHHMHHMMMM MMMHMMMHHMMMHMMM MMHMHMMMMMMHMHMM MMHMMHMMMMHMMHMM MMMMMMHMMHMMMMMM HHHHMMMHHMMMHHHH HHHHMMMHHMMMHHHH MMMMMMHMMHMMMMMM MMHMMHMMMMHMMHMM MMHMHMMMMMMHMHMM MMMHMMMHHMMMHMMM MMMMHHMHHMHHMMMM MMMMMMMHHMMMMMMM MMMMMMMHHMMMMMMM } # tile 74 (cmap 74) { MMMMMMMMMMMMMMMM MMMMMMNNNNNMMMMM MMMMMMMMNMMMMMMM MMMNNNNMNMNNNMMM MMMNMMNMNMNMNMMM MNMNNNNMNMNMNMMM MNMMMMMMNMNNNMNM MNNNNNNNNMMMMMNM MNMMMMMNNNNNNNNM MNMNNNMNMMMMMMNM MMMNMNMNMNNNNMNM MMMNMNMNMNMMNMMM MMMNNNMNMNNNNMMM MMMMMMMNMMMMMMMM MMMMMNNNNNMMMMMM MMMMMMMMMMMMMMMM } # tile 75 (cmap 75) { AAAAAAADDDDDDAAA AAAAADDDDDDDDDDD AAAADDDDDDDDDDDD AAADDDDDDCCDDDDD AAADDDCCCCCCDDDD AADDDDCCCCCDDDDD AADDDCCCCCDDDDDD AADDDCCCCDDDDDMM AADDDCCCDDDDMMMM AADDDCCCDDDDMMMM AADDDDDDDDDMMMMM AAADDDDDDDMMMMMM AAADDDDDDDMMMMMM AAAADDDDDDMMMMMM AAAADDDDDDMMMMMM AAAADDDDDDMMMMMM } # tile 76 (cmap 76) { AAAAAAAAAAAAAAAA DDAAAAAAAAAAAAAA DDDDAAAAAAAAAADD DDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDD DDDDDDDCCCCCCDDD MDDDDDDDDCCCCCDD MMMDDDDDDDDDDDDD MMMMDDDDDDDDDDDD MMMMMMDDDDDDDDMM MMMMMMMDDDDMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 77 (cmap 77) { AAAAAAAAAAAAAAAA AAADDDDDAAAAAAAA DDDDDDDDDDDAAAAA DDDDDDDDDDDDAAAA DDDDDCCCDDDDDAAA DDDDDCCCCDDDDDAA DDDDDCCCCDDDDDDA DDDDDCCCCCDDDDDD DDDDDDCCCCCDDDDD DDDDDDDCCCCDDDDD MMMDDDDDCCCDDDDD MMMDDDDDDCCDDDDD MMMMDDDDDDDDDDDD MMMMDDDDDDDDDDDD MMMMDDDDDDDDDDDD MMMMDDDDDDDDDDDA } # tile 78 (cmap 78) { AAAADDDDDDMMMMMM AAAADDDDDDDMMMMM AAAADDDDDDDMMMMM AAAADDDDDDDDMMMM AAAADDCCCDDDMMMM AAADDDDCCDDDMMMM AADDDDCCCDDDMMMM AADDDDCCCDDDMMMM AADDDDCDDDDDMMMM ADDDDDDDDDDMMMMM ADDDDDDDDDMMMMMM DDDDDDDDDMMMMMMM DDDDDDDDMMMMMMMM DDDDDDDMMMMMMMMM DDDDDDDMMMMMMMMM DDCCDDDMMMMMMMMM } # tile 79 (cmap 79) { MMMMDDDDDDDDDDDA MMMMDDDDDDDDDDDA MMMMDDDDDDDDDDAA MMMMDDDDDDDDDDAA MMMDDDDDDDDDDDAA MMDDDCCDDDDDDAAA MMDDDCCDDDDDDAAA MMDDDCCDDDDDAAAA MMDDDCCDDDDDAAAA MMDDDDDDDDDDAAAA MMMDDDDDDDDDAAAA MMMDDDDDDDDDAAAA MMMMDDDDDDDDDAAA MMMMMDDDDDDDDAAA MMMMMMDDDDDDDDAA MMMMMMMDDDDDDDAA } # tile 80 (cmap 80) { DDDCDDDMMMMMMMMM DDDCDDDMMMMMMMMM ADDCDDDMMMMMMMMM ADDDDDDDMMMMMMMM ADDDDDDDDDDDDMMM AADDDDDDDDDDDDDD AADDDDDDDDDDDDDD AAADDDDDDDDCDDDD AAAAADDDDDDCCCCD AAAAAAADDDDDCCCD AAAAAAAAADDDDCCC AAAAAAAAAADDDDCC AAAAAAAAAAADDDDD AAAAAAAAAAADDDDD AAAAAAAAAAAADDDD AAAAAAAAAAAAAADD } # tile 81 (cmap 81) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMDDD MMMMMMMMMMMMDDDD DMMMMMMMMMMMDDDD DDMMMMMMMMMMDDDC DDDMMMMMMMMMDDDC DDDDMMMMMMMMDDDC DDDDDDMMMMDDDDDC DDDDDDDDDDDDDDDC DDDDDDDDDDDDDDDC DDDDDDDDDDDDDDDD DDDDDDDDDDDDDDDD DDDDDDDDDDDDDDAA } # tile 82 (cmap 82) { MMMMMMDDDDDDDDAA MMMMMMDDDDDDDDDA MMMMMDDDDDDDDDDA MMMMDDDDDDDDDDDA DDDDDDDDDDDDDDDA DDDDDDDDDDDDDDDA CCCDDDDDDDDDDDAA CCCCDDDDDDDDDDAA CCCDDDDDDDDDDDAA CCDDDDDDDDDDDAAA CCDDDDDDAAAAAAAA CDDDDDAAAAAAAAAA CDDDDAAAAAAAAAAA DDDDAAAAAAAAAAAA DDAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA } # tile 83 (explosion dark 0) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMAAA MMMMMMAMMMAAAAAA MMMMMMMMMAAAAAAA MMMMMMMMMAAAAAAM MMMMMMMMAAAAMMMA MMMAAAMAAAAMMMAA MAMMMAAAAAAMAAAA MMMMMAAAAAAMAAAA MMMMAAAAAAAMAAAA MMMMMMMMAAMMAAMM MMMMAAAAAAAAAAMM MMMAAAAMMAAAMMMM MMAAAAMMAAAAMMMM MMAAAMMAAAAAMMMM } # tile 84 (explosion dark 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM AMMMMMMMMAAAAAAM AAAAAAMAAAAAAAAM AAAAAAMMMMMAAAAA MMMAAAMAAAAAAAAA AAAAAAMAAAAAAAAA AAAAAAMAAAAAAAAM AAMMMMMMMMMMMAMM MMAAAMAMMMMMAAAA MAMAMAMMMAMMMAAA MPPAMMMAAMMMMMAA MAMMMMMAMMMMAAAA MMMMMAMMAMMMPAAA MMMMMMMMAMAMAPAA MPAMMMAPAAAAAAAA } # tile 85 (explosion dark 2) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMAMMMAMMM AAAAAMMMMMMMMMMM AAAAAAMMMAMMAMMM AAAAAAAMMMMMMMMM MMMMMMAAAAMMMMMM AAAAAMMAAAAMMMMM MMAAAAAAAAAAMMMM AAMAAMMMMAAAMMMM AAMAAAAAMAAAMMMM AAPAAMAAAAAAMAMM AAAMMMMMAAAAMMMM AAMAMMAMAAAAMMMM AMAAMMAMAAAAAMMM } # tile 86 (explosion dark 3) { MMAAAMAMAAAMMMMM MMAAAMAAAAAMAPMM MMMAAMAAMMMMMMMA MMMAAAAAAMMMMPPM MMAAAMAAMMAMMPAP MAAAMMMAMMMMPMAP MAAAMAAAMAMMPMMP MAAAMAAAMMMAAAAP MAAAMAAAMMMMPAAA MAAAMMAAMMMMPPAA MMAAAMMAAMMMPAAP MMMAAAMMMAPMPPPP MMMMAAAMMMPMMPMA MMMMMAAMMMMMAAAM MMAMAMMMAAPMMMPA MMMMAMMMMMMMMMPA } # tile 87 (explosion dark 4) { APAAAMMPPAPAAAAA MAPAMMAMAAAPAAAM AAPMPAAMMAAAAAAM PAPPPAAAMMAAPAMM AAAPPAAAAPAAPMMA AAPPMPPPAAAAAMMA AAPAAAAAAAAAAAMM APPAAAAAAAAAAAMM AAAAAAAAAAAAPAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA AAAAAAAAAAAAAMAA AAAAAAAAAAAMHHMM } # tile 88 (explosion dark 5) { MMAAAMAMAMAAAAMM MMAAAAAMAMAAAAMM MMAAAAAMAMAAAAMM PMAAAAAMMMAAAAMM PMAAPAPAAMAAAAMM PMMMPMMAMMAAAMMM MMMAPMMAAAAAAMMM MPAAPAAAAAAAAMMM AAPMMMPAAAAAMMMM MMAAMPPAAMAMMMAM AMMMPPMMMMMMMMMM MAAAAPPAAMMMAMMM MMAAMPPMAAAMMMMM AMMMMMMAAAAAMMMM AAAMMMAAAAAAAMMM MMMMPPAAAAAAAAMM } # tile 89 (explosion dark 6) { MMMMAMMMMMMMAMMP MMMMAMMMMMMMAAMM MAMMAAMMMPMMAMAM MMMAAAMAMMPMMAAP MMMAAAAMMAAPMMAM MMMAAAAMMMMPMMMA MMMAAAAMMAMMAMMA MMMAAAAAMAAAMMMM MMMAAAAAMMAAMMMM MMMMAAAAAAAAAMMM MMMMMAAAAAAAAAAA MMMAMMAAAAAAAAAA MMMMMMMMAAMAAAAA MMMAMMMMMMMMAAAA MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 90 (explosion dark 7) { PPPAAAAAPAAAMAMM AAPPAAPPPPAMAMMM PPPPPPPPPPAMMAPP MPPAAMAAMAPAAMMM MMAAAAMAMMAAAPAA APPAPAPMAMAMPAAM AMMPPAAAMMMMMMMP AAMMMMMMMAMMMMMM PAPAMAAAAAAAAAAP AAMAPAAAAMMMMMMA AAAMAMPPMMMAAAAA AAAAAAMAMMAAAAAA AAAAAAAAAAAAAAAA AAAAMMMMMMMMMMAA MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 91 (explosion dark 8) { MMMMPMMAAAAAAAMM MMAMMAMAAMAMAAMM PPMMAMMAAMAMAAMM MMMAAAMAAMAMAAMM MAAAAAMAAAMMAAMM MMPAAMMAAAMAAAMM MAAAMMAAAMMAAAMM MAMAAMAAAAAAAAMM AAMAAAAAAMAAAAMM MMMAAAAAAAAAAAMM MAAAAAAAAMAAAMMM AAAAAAAAMMMMMMMM AAAAAAMMMMAMMMMM AAAMMMAMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 92 (explosion noxious 0) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMFFF MMMMMMFMMMFFFFFF MMMMMMMMMFFFFFFF MMMMMMMMMFFFFFFM MMMMMMMMFFFFMMMF MMMFFFMFFFFMMMFF MFMMMFFFFFFMFFFF MMMMMFFFFFFMFFFF MMMMFFFFFFFMFFFF MMMMMMMMFFMMFFMM MMMMFFFFFFFFFFMM MMMFFFFMMFFFMMMM MMFFFFMMFFFFMMMM MMFFFMMFFFFFMMMM } # tile 93 (explosion noxious 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM FMMMMMMMMFFFFFFM FFFFFFMFFFFFFFFM FFFFFFMMMMMFFFFF MMMFFFMFFFFFFFFF FFFFFFMFFFFFFFFF FFFFFFMFFFFFFFFM FFMMMMMMMMMMMFMM MMFFFMFMMMMMFFFF MHMFMFMMMFMMMFFF MGGFMMMFFMMMMMFF MHMMMMMFMMMMFFFF MMMMMFMMFMMMGFFF MMMMMMMMFMFMFGFF MGHMMMHGHHFFFFFF } # tile 94 (explosion noxious 2) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMFMMMFMMM FFFFFMMMMMMMMMMM FFFFFFMMMFMMFMMM FFFFFFFMMMMMMMMM MMMMMMFFFFMMMMMM FFFFFMMFFFFMMMMM MMFFFFFFFFFFMMMM FFMFFMMMMFFFMMMM FFMFFFFFMFFFMMMM FFGFFMFFFFFFMFMM FFFMMMMMFFFFMMMM FFMFMMFMFFFFMMMM FMFFMMFMFFFFFMMM } # tile 95 (explosion noxious 3) { MMFFFMFMFFFMMMMM MMFFFMFFFFFMFGMM MMMFFMFFMMMMMMMF MMMFFFFFFMMMMGGM MMFFFMFFMMFMMGFG MFFFMMMFMMMMGMFG MFFFMFFFMHMMGMMG MFFFMFFFMMMFFFFG MFFFMFFFMMMMGFHH MFFFMMFFMMMMGGHH MMFFFMMFFMMMGHHG MMMFFFMMMFGMGGGG MMMMFFFMMMGMMGMH MMMMMFFMMMMMHHFM MMFMFMMMFHGMMMGH MMMMFMMMMMMMMMGH } # tile 96 (explosion noxious 4) { FGHFFMMGGFGHFFFF MHGHMMFMFFHGFHFM HFGMGHFMMHHHFFHM GFGGGHHHMMHHGFMM HHHGGHHHHGHHGMMF HHGGMGGGHHHHFMMF HHGHHHHHHHHHHFMM HGGHHHHHHHHHHHMM HHHHHHNNNNHHGHNH GHHHHHHHNHHHHHNH GHHGHGNNNNHHHHGF GGNHNHNNNNHHHGGF HHHHNHNNNHHHGGGG HGGNGHNNNHHHGGGF HHHHNHNHNMGGGMGF GGGGNHHHGGGMHHMM } # tile 97 (explosion noxious 5) { MMFFFMFMFMFFFFMM MMFFFFFMFMFFFFMM MMFFFFFMFMFFFFMM GMFFFFFMMMFFFFMM GMFFGFGFFMFFFFMM GMMMGMGFMMFFFMMM MMMFGMMFFFFFFMMM MGFFFFFFFFFFFMMM FFGMMMGFFFFFMMMM MMFFMGGFFMFMMMFM FMMMGGMMMMMMMMMM MFFFFGGFFMMMFMMM MMHFMGGMFFFMMMMM HMMMMMMFFFFFMMMM HFHMMMFFFFFFFMMM MMMMGGFFFFFFFFMM } # tile 98 (explosion noxious 6) { MMMMFMMMMMMMHMMG MMMMFMMMMMMMFHMM MFMMFFMMMGMMFMHM MMMFFFMFMMGMMFFG MMMFFFFMMFFGMMFM MMMFFFFMMMMGMMMF MMMFFFFMMFMMHMMF MMMFFFFFMFFFMMMM MMMFFFFFMMFFMMMM MMMMFFFFFFFFFMMM MMMMMFFFHFFFFFFF MMMFMMFFFFFFFFFF MMMMMMMMFFMFFFFF MMMFMMMMMMMMFFFF MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 99 (explosion noxious 7) { GGGHHHHHGHHHMHMM HHGGHHGGGGHMFMMM GGGGGGGGGGFMMFGG MGGHFMFFMHGFFMMM MMHHHHMFMMFFHGHF HGGFGFGMHMHMGFFM FMMGGFFHMMMMMMMG HFMMMMMMMFMMMMMM GHGFMFFFFFFFFFFG HFMHGHFFFMMMMMMF FFFMFMGGMMMFFFFF FFFFFFMFMMFFFFFF FFFFFFFFFFFFFFFF FFFFMMMMMMMMMMFF MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 100 (explosion noxious 8) { MMMMGMMFFFFFFFMM MMFMMFMFFMFMFFMM GGMMFMMFFMFMFFMM MMMFFFMFFMFMFFMM MFFFFFMFFFMMFFMM MMGFFMMFFFMFFFMM MFFFMMFFFMMFFFMM MFMFFMFFFFFFFFMM FFMFFFFFFMFFFFMM MMMFFFFFFFFFFFMM MFFFFFFFFMFFFMMM FFFFFFFFMMMMMMMM FFFFFFMMMMFMMMMM FFFMMMFMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 101 (explosion muddy 0) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMJJJ MMMMMMJMMMJJJJJJ MMMMMMMMMJJJJJJJ MMMMMMMMMJJJJJJK MMMMMMMMJJJJKKKJ MMMJJJMJJJJKKKJJ MJMMMJJJJJJKJJJJ MMMMMJJJJJJKJJJJ MMMMJJJJJJJKJJJJ MMMMMMMKJJKKJJKK MMMMJJJJJJJJJJKK MMMJJJJKKJJJKKKK MMJJJJKKJJJJKKKK MMJJJKKJJJJJKKKK } # tile 102 (explosion muddy 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM JMMMMMMMMJJJJJJM JJJJJJKJJJJJJJJM JJJJJJKKKKKJJJJJ KKKJJJKJJJJJJJJJ JJJJJJKJJJJJJJJJ JJJJJJKJJJJJJJJK JJKKKKKKKKKKKJKK KKJJJKJKKKKKJJJJ KLKJKJKKKJKKKJJJ KCCJKKKJJKKKKKJJ KLKKKKKJKKKKJJJJ KKKKKJKKJKKKCJJJ KKKKKKKKJKJKJCJJ KCLKKKLCLLJJJJJJ } # tile 103 (explosion muddy 2) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMJMMMJMMM JJJJJMMMMMMMMMMM JJJJJJMMMJMMJMMM JJJJJJJMMMMMMMMM KKKKKKJJJJMMMMMM JJJJJKKJJJJMMMMM KKJJJJJJJJJJMMMM JJKJJKKKKJJJMMMM JJKJJJJJKJJJMMMM JJCJJKJJJJJJMJMM JJJKKKKKJJJJMMMM JJKJKKJKJJJJMMMM JKJJKKJKJJJJJMMM } # tile 104 (explosion muddy 3) { MMJJJKJKJJJKKKKK MMJJJKJJJJJKJCKK MMMJJKJJKKKKKKKJ MMMJJJJJJKKKKCCK MMJJJKJJKKJKKCJC MJJJKKKJKKKKCKJC MJJJKJJJKLKKCKKC MJJJKJJJKKKJJJJC MJJJKJJJKKKKCJLL MJJJKKJJKKKKCCLL MMJJJKKJJKKKCLLC MMMJJJKKKJCKCCCC MMMMJJJKKKCKKCKL MMMMMJJKKKKKLLJK MMJMJKKKJLCKKKCL MMMMJKKKKKKKKKCL } # tile 105 (explosion muddy 4) { JCLJJKKCCJCLJJJJ KLCLKKJKJJLCJLJK LJCKCLJKKLLLJJLK CJCCCLLLKKLLCJKK LLLCCLLLLCLLCKKJ LLCCKCCCLLLLJKKJ LLCLLLLLLLLLLJKK LCCLLLLLLLLLLLKK LLLLLLCCCCLLCLCL CLLLLLLLCLLLLLCL CLLCLCCCCCLLLLCJ CCCLCLCCCCLLLCCJ LLLLCLCCCLLLCCCC LCCCCLCCCLLLCCCJ LLLLCLCLCKCCCKCJ CCCCCLLLCCCKLLKK } # tile 106 (explosion muddy 5) { KKJJJKJKJKJJJJMM KKJJJJJKJKJJJJMM KKJJJJJKJKJJJJMM CKJJJJJKKKJJJJMM CKJJCJCJJKJJJJMM CKKKCKKJKKJJJMMM KKKJCKKJJJJJJMMM KCJJCJJJJJJJJMMM JJCKKKCJJJJJMMMM KKJJKCCJJKJMMMJM JKKKCCKKKKMMMMMM KJJJJCCJJKMMJMMM KKLJKCCKJJJMMMMM LKKKKKKJJJJJMMMM LJLKKKJJJJJJJMMM KKKKCCJJJJJJJJMM } # tile 107 (explosion muddy 6) { MMMMJKKKKKKKLKKC MMMMJKKKKKKKJLKK MJMMJJKKKCKKJKLK MMMJJJKJKKCKKJJC MMMJJJJKKJJCKKJK MMMJJJJKKKKCKKKJ MMMJJJJKKJKKLKKJ MMMJJJJJKJJJKKKK MMMJJJJJKKJJKKKK MMMMJJJJJJJJJKKK MMMMMJJJLJJJJJJJ MMMJMMJJJJJJJJJJ MMMMMMMMJJMJJJJJ MMMJMMMMMMMMJJJJ MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 108 (explosion muddy 7) { CCCLLLLLCLLLKLKK LLCCLLCCCCLKJKKK CCCCCCCCCCJKKJCC KCCLJKJJKLCJJKKK KKLLLLKJKKJJLCLJ LCCJCJCKLKLKCJJK JKKCCJJLKKKKKKKC LJKKKKKKKJKKKKKK CLCJKJJJJJJJJJJC LJKLCLJJJKKKKKKJ JJJKJKCCKKKJJJJJ JJJJJJKJKKJJJJJJ JJJJJJJJJJJJJJJJ JJJJMMMMMMMMMMJJ MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 109 (explosion muddy 8) { KKKKCKKJJJJJJJMM KKJKKJKJJKJKJJMM CCKKJKKJJKJKJJMM KKKJJJKJJKJKJJMM KJJJJJKJJJKKJJMM KKCJJKKJJJKJJJMM KJJJKKJJJKKJJJMM KJKJJKJJJJJJJJMM JJKJJJJJJKJJJJMM KKKJJJJJJJJJJJMM KJJJJJJJJMJJJMMM JJJJJJJJMMMMMMMM JJJJJJMMMMJMMMMM JJJMMMJMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 110 (explosion wet 0) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMEEE MMMMMMEMMMEEEEEE MMMMMMMMMEEEEEEE MMMMMMMMMEEEEEEP MMMMMMMMEEEEPPPE MMMEEEMEEEEPPPEE MEMMMEEEEEEPEEEE MMMMMEEEEEEPEEEE MMMMEEEEEEEPEEEE MMMMMMMPEEPPEEPP MMMMEEEEEEEEEEPP MMMEEEEPPEEEPPPP MMEEEEPPEEEEPPPP MMEEEPPEEEEEPPPP } # tile 111 (explosion wet 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM EMMMMMMMMEEEEEEM EEEEEEPEEEEEEEEM EEEEEEPPPPPEEEEE PPPEEEPEEEEEEEEE EEEEEEPEEEEEEEEE EEEEEEPEEEEEEEEP EEPPPPPPPPPPPEPP PPEEEPEPPPPPEEEE PNPEPEPPPEPPPEEE PBBEPPPEEPPPPPEE PNPPPPPEPPPPEEEE PPPPPEPPEPPPBEEE PPPPPPPPEPEPEBEE PBNPPPNBEEEEEEEE } # tile 112 (explosion wet 2) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMEMMMEMMM EEEEEMMMMMMMMMMM EEEEEEMMMEMMEMMM EEEEEEEMMMMMMMMM PPPPPPEEEEMMMMMM EEEEEPPEEEEMMMMM PPEEEEEEEEEEMMMM EEPEEPPPPEEEMMMM EEPEEEEEPEEEMMMM EEBEEPEEEEEEMEMM EEEPPPPPEEEEMMMM EEPEPPEPEEEEMMMM EPEEPPEPEEEEEMMM } # tile 113 (explosion wet 3) { MMEEEPEPEEEPPPPP MMEEEPEEEEEPEBPP MMMEEPEEPPPPPPPE MMMEEEEEEPPPPBBP MMEEEPEEPPEPPBEB MEEEPPPEPPPPBPEB MEEEPEEEPNPPBPPB MEEEPEEEPPPEEEEB MEEEPEEEPPPPBEEE MEEEPPEEPPPPBBEE MMEEEPPEEPPPBEEB MMMEEEPPPEBPBBBB MMMMEEEPPPBPPBPN MMMMMEEPPPPPNNEP MMEMEPPPENBPPPBE MMMMEPPPPPPPPPBE } # tile 114 (explosion wet 4) { EBNEEPPBBEBNEEEE PNBNPPEPEEEBENEP NEBPBEEPPEEEEENP BEBBBEEEPPEEBEPP EEEBBEEEEBEEBPPE EEBBPBBBEEEEEPPE EEBEEEEEEEEEEEPP EBBEEEEEEEEEEEPP EEEEEEEEEEEEBEEE BEEEEEEEEEEEEEEE BEEBEBEEEEEEEEBE BBEEEEEEEEEEEBBE EEEEEEEEEEEEBBBB EBBEBEEEEEEEBBBE EEEEEEEEEPBBBPBE BBBBEEEEBBBPNNPP } # tile 115 (explosion wet 5) { PPEEEPEPEPEEEEMM PPEEEEEPEPEEEEMM PPEEEEEPEPEEEEMM BPEEEEEPPPEEEEMM BPEEBEBEEPEEEEMM BPPPBPPEPPEEEMMM PPPEBPPEEEEEEMMM PBEEBEEEEEEEEMMM EEBPPPBEEEEEMMMM PPEEPBBEEPEMMMEM EPPPBBPPPPMMMMMM PEEEEBBEEPMMEMMM PPNEPBBPEEEMMMMM NPPPPPPEEEEEMMMM NENPPPEEEEEEEMMM PPPPBBEEEEEEEEMM } # tile 116 (explosion wet 6) { MMMMEPPPPPPPNPPB MMMMEPPPPPPPENPP MEMMEEPPPBPPEPNP MMMEEEPEPPBPPEEB MMMEEEEPPEEBPPEP MMMEEEEPPPPBPPPE MMMEEEEPPEPPNPPE MMMEEEEEPEEEPPPP MMMEEEEEPPEEPPPP MMMMEEEEEEEEEPPP MMMMMEEENEEEEEEE MMMEMMEEEEEEEEEE MMMMMMMMEEMEEEEE MMMEMMMMMMMMEEEE MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 117 (explosion wet 7) { BBBEEEEEBEEEPEPP EEBBEEBBBBEPEPPP BBBBBBBBBBEPPEBB PBBEEPEEPNBEEPPP PPEEEEPEPPEENBNE NBBEBEBPNPNPBEEP EPPBBEENPPPPPPPB NEPPPPPPPEPPPPPP BNBEPEEEEEEEEEEB NEPNBNEEEPPPPPPE EEEPEPBBPPPEEEEE EEEEEEPEPPEEEEEE EEEEEEEEEEEEEEEE EEEEMMMMMMMMMMEE MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 118 (explosion wet 8) { PPPPBPPEEEEEEEMM PPEPPEPEEPEPEEMM BBPPEPPEEPEPEEMM PPPEEEPEEPEPEEMM PEEEEEPEEEPPEEMM PPBEEPPEEEPEEEMM PEEEPPEEEPPEEEMM PEPEEPEEEEEEEEMM EEPEEEEEEPEEEEMM PPPEEEEEEEEEEEMM PEEEEEEEEMEEEMMM EEEEEEEEMMMMMMMM EEEEEEMMMMEMMMMM EEEMMMEMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 119 (explosion magical 0) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMEEE MMMMMMEMMMEEEEEE MMMMMMMMMEEEEEEE MMMMMMMMMEEEEEEC MMMMMMMMEEEEIIIE MMMEEEMEEEEIIIEE MEMMMEEEEEEIEEEE MMMMMEEEEEEIEEEE MMMMEEEEEEEIEEEE MMMMMMMIEEIIEEII MMMMEEEEEEEEEEII MMMEEEEIIEEEIIII MMEEEEIIEEEEIIII MMEEEIIEEEEEIIII } # tile 120 (explosion magical 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM EMMMMMMMMEEEEEEM EEEEEEIEEEEEEEEM EEEEEEIIIIIEEEEE IIIEEEIEEEEEEEEE EEEEEEIEEEEEEEEE EEEEEEIEEEEEEEEI EEIIIIIIIIIIIEII IIEEEIEIIIIIEEEE IHIEIEIIIEIIIEEE ILLEIIIEEIIIIIEE IHIIIIIEIIIIEEEE IIIIIEIIEIIILEEE IIIIIIIIEIEIELEE ILHIIIHLHHEEEEEE } # tile 121 (explosion magical 2) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMEMMMEMMM EEEEEMMMMMMMMMMM EEEEEEMMMEMMEMMM EEEEEEEMMMMMMMMM IIIIIIEEEEMMMMMM EEEEEIIEEEEMMMMM IIEEEEEEEEEEMMMM EEIEEIIIIEEEMMMM EEIEEEEEIEEEMMMM EELEEIEEEEEEMEMM EEEIIIIIEEEEMMMM EEIEIIEIEEEEMMMM EIEEIIEIEEEEEMMM } # tile 122 (explosion magical 3) { MMEEEIEIEEEIIIII MMEEEIEEEEEIEIII MMMEEIEEIIIIIIIE MMMEEEEEEIIIIIII MMEEEIEEIIEIIIEI MEEEIIIEIIIIIIEI MEEEIEEEINIIIIII MEEEIEEEIIIEEEEI MEEEIEEEIIIIIENN MEEEIIEEIIIIIINN MMEEEIIEEIIIINNI MMMEEEIIIEIIIIII MMMMEEEIIIIIIIIN MMMMMEEIIIIINNEI MMEMEIIIENIIIIIN MMMMEIIIIIIIIIIN } # tile 123 (explosion magical 4) { EINEEIIIIEINEEEE ININIIEIEENIENEI NEIIINEIINNNEENI IEIIINNNIINNIEII NNNIINNNNINNIIIE NNIIIIIINNNNEIIE NNINNNNNNNNNNEII NIINNNNNNNNNNNII NNNNNNNNNNNNINNN INNNNNNNNNNNNNNN INNININNNNNNNNIE IINNNNNNNNNNNIIE NNNNNNNNNNNNIIII NIININNNNNNNIIIE NNNNNNNNNIIIIIIE IIIINNNNIIIINNII } # tile 124 (explosion magical 5) { IIEEEIEIEIEEEEMM IIEEEEEIEIEEEEMM IIEEEEEIEIEEEEMM IIEEEEEIIIEEEEMM IIEEIEIEEIEEEEMM IIIIIIIEIIEEEMMM IIIEIIIEEEEEEMMM IIEEIEEEEEEEEMMM EEIIIIIEEEEEMMMM IIEEIIIEEIEMMMEM EIIIIIIIIIMMMMMM IEEEEIIEEIMMEMMM IINEIIIIEEEMMMMM NIIIIIIEEEEEMMMM NENIIIEEEEEEEMMM IIIIIIEEEEEEEEMM } # tile 125 (explosion magical 6) { MMMMEIIIIIIIHIII MMMMEIIIIIIIEHII MEMMEEIIIIIIEIHI MMMEEEIEIIIIIEEI MMMEEEEIIEEIIIEI MMMEEEEIIIIIIIIE MMMEEEEIIEIIHIIE MMMEEEEEIEEEIIII MMMEEEEEIIEEIIII MMMMEEEEEEEEEIII MMMMMEEEHEEEEEEE MMMEMMEEEEEEEEEE MMMMMMMMEEMEEEEE MMMEMMMMMMMMEEEE MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 126 (explosion magical 7) { IIINNNNNINNNINII NNIINNIIIINIEIII IIIIIIIIIIEIIEII IIINEIEEINIEEIII IINNNNIEIIEENINE NIIEIEIININIIEEI EIIIIEENIIIIIIII NEIIIIIIIEIIIIII INIEIEEEEEEEEEEI NEININEEEIIIIIIE EEEIEIIIIIIEEEEE EEEEEEIEIIEEEEEE EEEEEEEEEEEEEEEE EEEEMMMMMMMMMMEE MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 127 (explosion magical 8) { IIIIIIIEEEEEEEMM IIEIIEIEEIEIEEMM IIIIEIIEEIEIEEMM IIIEEEIEEIEIEEMM IEEEEEIEEEIIEEMM IIIEEIIEEEIEEEMM IEEEIIEEEIIEEEMM IEIEEIEEEEEEEEMM EEIEEEEEEIEEEEMM IIIEEEEEEEEEEEMM IEEEEEEEEMEEEMMM EEEEEEEEMMMMMMMM EEEEEEMMMMEMMMMM EEEMMMEMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 128 (explosion fiery 0) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMDDD MMMMMMDMMMDDDDDD MMMMMMMMMDDDDDDD MMMMMMMMMDDDDDDC MMMMMMMMDDDDCCCD MMMDDDMDDDDCCCDD MDMMMDDDDDDCDDDD MMMMMDDDDDDCDDDD MMMMDDDDDDDCDDDD MMMMMMMCDDCCDDCC MMMMDDDDDDDDDDCC MMMDDDDCCDDDCCCC MMDDDDCCDDDDCCCC MMDDDCCDDDDDCCCC } # tile 129 (explosion fiery 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM DMMMMMMMMDDDDDDM DDDDDDCDDDDDDDDM DDDDDDCCCCCDDDDD CCCDDDCDDDDDDDDD DDDDDDCDDDDDDDDD DDDDDDCDDDDDDDDC DDCCCCCCCCCCCDCC CCDDDCDCCCCCDDDD CHCDCDCCCDCCCDDD CLLDCCCDDCCCCCDD CHCCCCCDCCCCDDDD CCCCCDCCDCCCLDDD CCCCCCCCDCDCDLDD CLHCCCHLHHDDDDDD } # tile 130 (explosion fiery 2) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMDMMMDMMM DDDDDMMMMMMMMMMM DDDDDDMMMDMMDMMM DDDDDDDMMMMMMMMM CCCCCCDDDDMMMMMM DDDDDCCDDDDMMMMM CCDDDDDDDDDDMMMM DDCDDCCCCDDDMMMM DDCDDDDDCDDDMMMM DDLDDCDDDDDDMDMM DDDCCCCCDDDDMMMM DDCDCCDCDDDDMMMM DCDDCCDCDDDDDMMM } # tile 131 (explosion fiery 3) { MMDDDCDCDDDCCCCC MMDDDCDDDDDCDLCC MMMDDCDDCCCCCCCD MMMDDDDDDCCCCLLC MMDDDCDDCCDCCLDL MDDDCCCDCCCCLCDL MDDDCDDDCHCCLCCL MDDDCDDDCCCDDDDL MDDDCDDDCCCCLDHH MDDDCCDDCCCCLLHH MMDDDCCDDCCCLHHL MMMDDDCCCDLCLLLL MMMMDDDCCCLCCLCH MMMMMDDCCCCCHHDC MMDMDCCCDHLCCCLH MMMMDCCCCCCCCCLH } # tile 132 (explosion fiery 4) { DLHDDCCLLDLHDDDD CHLHCCDCDDHLDHDC HDLCLHDCCHHHDDHC LDLLLHHHCCHHLDCC HHHLLHHHHLHHLCCD HHLLCLLLHHHHDCCD HHLHHHHHHHHHHDCC HLLHHHHHHHHHHHCC HHHHHHNNNNHHLHNH LHHHHHHHNHHHHHNH LHHLHLNNNNHHHHLD LLNHNHNNNNHHHLLD HHHHNHNNNHHHLLLL HLLNLHNNNHHHLLLD HHHHNHNHNCLLLCLD LLLLNHHHLLLCHHCC } # tile 133 (explosion fiery 5) { CCDDDCDCDCDDDDMM CCDDDDDCDCDDDDMM CCDDDDDCDCDDDDMM LCDDDDDCCCDDDDMM LCDDLDLDDCDDDDMM LCCCLCCDCCDDDMMM CCCDLCCDDDDDDMMM CLDDLDDDDDDDDMMM DDLCCCLDDDDDMMMM CCDDCLLDDCDMMMDM DCCCLLCCCCMMMMMM CDDDDLLDDCMMDMMM CCHDCLLCDDDMMMMM HCCCCCCDDDDDMMMM HDHCCCDDDDDDDMMM CCCCLLDDDDDDDDMM } # tile 134 (explosion fiery 6) { MMMMDCCCCCCCHCCL MMMMDCCCCCCCDHCC MDMMDDCCCLCCDCHC MMMDDDCDCCLCCDDL MMMDDDDCCDDLCCDC MMMDDDDCCCCLCCCD MMMDDDDCCDCCHCCD MMMDDDDDCDDDCCCC MMMDDDDDCCDDCCCC MMMMDDDDDDDDDCCC MMMMMDDDHDDDDDDD MMMDMMDDDDDDDDDD MMMMMMMMDDMDDDDD MMMDMMMMMMMMDDDD MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 135 (explosion fiery 7) { LLLHHHHHLHHHCHCC HHLLHHLLLLHCDCCC LLLLLLLLLLDCCDLL CLLHDCDDCHLDDCCC CCHHHHCDCCDDHLHD HLLDLDLCHCHCLDDC DCCLLDDHCCCCCCCL HDCCCCCCCDCCCCCC LHLDCDDDDDDDDDDL HDCHLHDDDCCCCCCD DDDCDCLLCCCDDDDD DDDDDDCDCCDDDDDD DDDDDDDDDDDDDDDD DDDDMMMMMMMMMMDD MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 136 (explosion fiery 8) { CCCCLCCDDDDDDDMM CCDCCDCDDCDCDDMM LLCCDCCDDCDCDDMM CCCDDDCDDCDCDDMM CDDDDDCDDDCCDDMM CCLDDCCDDDCDDDMM CDDDCCDDDCCDDDMM CDCDDCDDDDDDDDMM DDCDDDDDDCDDDDMM CCCDDDDDDDDDDDMM CDDDDDDDDMDDDMMM DDDDDDDDMMMMMMMM DDDDDDMMMMDMMMMM DDDMMMDMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 137 (explosion frosty 0) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMEEE MMMMMNEMMMEEEEEE MMNMMMNMMENBEEEE MNMNMNMMMEEEEEEP MMMMNMMMEEEEPPPE MMMNENMNEEEPPPEE MENMMENEEEEPNBEE MMMNMEEEEEEPEEEE MMMMEENBEEEPEEEE MMMMMMMPEEPPEEPP MMMMEEEEEEEEEEPP MMMEEEEPPEEEPPPP MMEEEEPPNBEEPPPP MMEEEPPEEEEEPPPP } # tile 138 (explosion frosty 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM EMMMMMMMMEEEEEEM ENBEENPEEEENBEEM EEEEEENPNPNEEEEE PPBEEEPENEEEEEEE EEEEEENNNNNEEEEE EEEEEEPENEEENBEP EEPPPPNPNPNPPPPP PPEEENEPPPPNEEEE PNPEPEPPPEPPPEEE PBBEPPPEEPPNBPEE PNPPPPPEPPPPEEEE PPPPPEPPEPPPBEEE PPPPPPPPEPEPEBEE PBNPPPNBNNEEEEEE } # tile 139 (explosion frosty 2) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMEMMMEMMM EEEEEMMMMMMMMMMM EEEEEEMMMEMMNMMM EEEEEEENMMNNMMMM PPPPPPENENMMMMMM EEEEEPPENENMNMMM PPEEEEEEEEENMNMM EEPEEPPPPNNEMNMM EEPEEEEENEEEMMMM EEBEEPEEEEEEMEMM EEEPPPPPEEEEMMMM EEPEPPEPEEEEMMMM EPEEPPEPEEEEEMMM } # tile 140 (explosion frosty 3) { MMEEEPEPEEEPPPPP MMEEEPEEEEEPEBPP MMMEEPEEPPPPPPPE MMMENENEEPPPPBBP MMEEENEEPPEPPBEB MEEENENEPPPPBPEB MEEEPEEEPNPPBPPB MEEEPEEEPPPEEEEB MEEEPEEEPPPPBENN MEEEPPEEPPPPBBNN MMEEEPNEEPPPBNNB MMMEENNNPEBPBBBB MMMMEENPPPBPPBPN MMMMMEEPPPPPNNEP MMEMEPPPENBPPPBN MMMMEPPPPPPPPPBN } # tile 141 (explosion frosty 4) { EBNEEPPBBEBNEEEE PNBNPPEPEENBENEP NEBPBNEPPNNNEENP BEBBBNNNPPNNBEPP NNNBBNNNNBNNBPPE NNBBPBBBNNNNEPPE NNBNNNNNNNNNNEPP NBBNNNNNNNNNNNPP NNNNNNNNNNNNBNNN BNNNNNNNNNNNNNNN BNNBNBNNNNNNNNBE BBNNNNNNNNNNNBBE NNNNNNNNNNNNBBBB NBBNBNNNNNNNBBBE NNNNNNNNNPBBBPBE BBBBNNNNBBBPNNPP } # tile 142 (explosion frosty 5) { PPEEEPEPEPEEEEMM PPEEEEEPEPEEEEMM PPEEEEEPEPEEEEMM BPEEEEEPPPEEEEMM BPEEBEBEEPEEEEMM BPPPBPPEPPEEEMMM PPPEBPPENEEENMMM PBEEBEEEENENEMMM EEBPPPBNNNNNNNMM PPEEPBBEENENMMEM EPPPBBPPNPMMNMMM PEEEEBBEEPMMEMMM PPNEPBBPEEEMMMMM NPPPPPPEEEEEMMMM NENPPPEEEEEEEMMM PPPPBBEEEEEEEEMM } # tile 143 (explosion frosty 6) { MMMMEPPPPPPPNPPB MMMMEPPPPPPPENPP MEMMEEPPPBPPEPNP MMMEEEPEPPBPPEEB MMMEENEPPEEBPPEP MMMNEEENPPPBPPPE MMNENPNPNEPPNPPE MMMNNENNPEEEPPPP MNMPEEEPPNEEPPPP MMMNNENNEEEEEPPP MMNMNPNENEEEEEEE MMMNMMENEEEEEEEE MMMMMNMMEEMEEEEE MMMEMMMMMMMMEEEE MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 144 (explosion frosty 7) { BBBNNNNNBNNNPNPP NNBBNNBBBBNPEPPP BBBBBBBBBBEPPEBB PBBNEPEEPNBEEPPP PPNNNNPEPPEENBNE NBBEBEBPNPNPBEEP EPPBBEENPPPPPPPB NEPPPPPPPEPPPPPP BNBEPEEEEEEEEEEB NEPNBNEEEPNENPPE EEEPEPBBPPPNEEEE EEEEEEPEPNNNNNEE EEEEEEEEEEENEEEE EEEEMMMMMMNMNMEE MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 145 (explosion frosty 8) { PPPPBPPEEEEEEEMM PPEPPEPEEPEPEEMM BBPPEPPEEPEPNENM PPPEEEPEEPEPENMM PEEEEEPEEEPPNENM PPBEEPNENEPEEEMM PEEEPPENEPPEEEMM PEPEENNNNNEEEEMM EEPEEEENEPEEEEMM PPPEEENENEEEEEMM PEEEEEEEEMEEEMMM EEEEEEEEMMMMMMMM EEEEEEMMMMENMMMM EEEMMMEMMMNMNMMM MMMMMMMMMMMNMMMM MMMMMMMMMMMMMMMM } # tile 146 (zap 0 0) { MMMMMMMIIMMMMMMM MMMMMMIIIIMMMMMM MMMMMMIIIIMMMMMM MMMMMMMIIMMMMMMM MMMMMMMIIMMMMMMM MMMMMMIIIIMMMMMM MMMMMMIIIIMMMMMM MMMMMMMIIMMMMMMM MMMMMMMIIMMMMMMM MMMMMMIIIIMMMMMM MMMMMMIIIIMMMMMM MMMMMMMIIMMMMMMM MMMMMMMIIMMMMMMM MMMMMMIIIIMMMMMM MMMMMMIIIIMMMMMM MMMMMMMIIMMMMMMM } # tile 147 (zap 0 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MIIMMIIMMIIMMIIM IIIIIIIIIIIIIIII IIIIIIIIIIIIIIII MIIMMIIMMIIMMIIM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 148 (zap 0 2) { IIIMMMMMMMMMMMMM IIIIMMMMMMMMMMMM IIIIMMMMMMMMMMMM MIIIIMMMMMMMMMMM MMMIIIIMMMMMMMMM MMMMIIIIMMMMMMMM MMMMIIIIMMMMMMMM MMMMMIIIIMMMMMMM MMMMMMMIIIIMMMMM MMMMMMMMIIIIMMMM MMMMMMMMIIIIMMMM MMMMMMMMMIIIIMMM MMMMMMMMMMMIIIIM MMMMMMMMMMMMIIII MMMMMMMMMMMMIIII MMMMMMMMMMMMMIII } # tile 149 (zap 0 3) { MMMMMMMMMMMMMIII MMMMMMMMMMMMIIII MMMMMMMMMMMMIIII MMMMMMMMMMMIIIIM MMMMMMMMMIIIIMMM MMMMMMMMIIIIMMMM MMMMMMMMIIIIMMMM MMMMMMMIIIIMMMMM MMMMMIIIIMMMMMMM MMMMIIIIMMMMMMMM MMMMIIIIMMMMMMMM MMMIIIIMMMMMMMMM MIIIIMMMMMMMMMMM IIIIMMMMMMMMMMMM IIIIMMMMMMMMMMMM IIIMMMMMMMMMMMMM } # tile 150 (zap 1 0) { MMMMMMMCCMMMMMMM MMMMMMCCCCMMMMMM MMMMMMCCCCMMMMMM MMMMMMMCCMMMMMMM MMMMMMMCCMMMMMMM MMMMMMCCCCMMMMMM MMMMMMCCCCMMMMMM MMMMMMMCCMMMMMMM MMMMMMMCCMMMMMMM MMMMMMCCCCMMMMMM MMMMMMCCCCMMMMMM MMMMMMMCCMMMMMMM MMMMMMMCCMMMMMMM MMMMMMCCCCMMMMMM MMMMMMCCCCMMMMMM MMMMMMMCCMMMMMMM } # tile 151 (zap 1 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MCCMMCCMMCCMMCCM CCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCC MCCMMCCMMCCMMCCM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 152 (zap 1 2) { CCCMMMMMMMMMMMMM CCCCMMMMMMMMMMMM CCCCMMMMMMMMMMMM MCCCCMMMMMMMMMMM MMMCCCCMMMMMMMMM MMMMCCCCMMMMMMMM MMMMCCCCMMMMMMMM MMMMMCCCCMMMMMMM MMMMMMMCCCCMMMMM MMMMMMMMCCCCMMMM MMMMMMMMCCCCMMMM MMMMMMMMMCCCCMMM MMMMMMMMMMMCCCCM MMMMMMMMMMMMCCCC MMMMMMMMMMMMCCCC MMMMMMMMMMMMMCCC } # tile 153 (zap 1 3) { MMMMMMMMMMMMMCCC MMMMMMMMMMMMCCCC MMMMMMMMMMMMCCCC MMMMMMMMMMMCCCCM MMMMMMMMMCCCCMMM MMMMMMMMCCCCMMMM MMMMMMMMCCCCMMMM MMMMMMMCCCCMMMMM MMMMMCCCCMMMMMMM MMMMCCCCMMMMMMMM MMMMCCCCMMMMMMMM MMMCCCCMMMMMMMMM MCCCCMMMMMMMMMMM CCCCMMMMMMMMMMMM CCCCMMMMMMMMMMMM CCCMMMMMMMMMMMMM } # tile 154 (zap 2 0) { MMMMMMMNNMMMMMMM MMMMMMNNNNMMMMMM MMMMMMNNNNMMMMMM MMMMMMMNNMMMMMMM MMMMMMMNNMMMMMMM MMMMMMNNNNMMMMMM MMMMMMNNNNMMMMMM MMMMMMMNNMMMMMMM MMMMMMMNNMMMMMMM MMMMMMNNNNMMMMMM MMMMMMNNNNMMMMMM MMMMMMMNNMMMMMMM MMMMMMMNNMMMMMMM MMMMMMNNNNMMMMMM MMMMMMNNNNMMMMMM MMMMMMMNNMMMMMMM } # tile 155 (zap 2 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MNNMMNNMMNNMMNNM NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN MNNMMNNMMNNMMNNM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 156 (zap 2 2) { NNNMMMMMMMMMMMMM NNNNMMMMMMMMMMMM NNNNMMMMMMMMMMMM MNNNNMMMMMMMMMMM MMMNNNNMMMMMMMMM MMMMNNNNMMMMMMMM MMMMNNNNMMMMMMMM MMMMMNNNNMMMMMMM MMMMMMMNNNNMMMMM MMMMMMMMNNNNMMMM MMMMMMMMNNNNMMMM MMMMMMMMMNNNNMMM MMMMMMMMMMMNNNNM MMMMMMMMMMMMNNNN MMMMMMMMMMMMNNNN MMMMMMMMMMMMMNNN } # tile 157 (zap 2 3) { MMMMMMMMMMMMMNNN MMMMMMMMMMMMNNNN MMMMMMMMMMMMNNNN MMMMMMMMMMMNNNNM MMMMMMMMMNNNNMMM MMMMMMMMNNNNMMMM MMMMMMMMNNNNMMMM MMMMMMMNNNNMMMMM MMMMMNNNNMMMMMMM MMMMNNNNMMMMMMMM MMMMNNNNMMMMMMMM MMMNNNNMMMMMMMMM MNNNNMMMMMMMMMMM NNNNMMMMMMMMMMMM NNNNMMMMMMMMMMMM NNNMMMMMMMMMMMMM } # tile 158 (zap 3 0) { MMMMMMMBBMMMMMMM MMMMMMBBBBMMMMMM MMMMMMBBBBMMMMMM MMMMMMMBBMMMMMMM MMMMMMMBBMMMMMMM MMMMMMBBBBMMMMMM MMMMMMBBBBMMMMMM MMMMMMMBBMMMMMMM MMMMMMMBBMMMMMMM MMMMMMBBBBMMMMMM MMMMMMBBBBMMMMMM MMMMMMMBBMMMMMMM MMMMMMMBBMMMMMMM MMMMMMBBBBMMMMMM MMMMMMBBBBMMMMMM MMMMMMMBBMMMMMMM } # tile 159 (zap 3 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MBBMMBBMMBBMMBBM BBBBBBBBBBBBBBBB BBBBBBBBBBBBBBBB MBBMMBBMMBBMMBBM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 160 (zap 3 2) { BBBMMMMMMMMMMMMM BBBBMMMMMMMMMMMM BBBBMMMMMMMMMMMM MBBBBMMMMMMMMMMM MMMBBBBMMMMMMMMM MMMMBBBBMMMMMMMM MMMMBBBBMMMMMMMM MMMMMBBBBMMMMMMM MMMMMMMBBBBMMMMM MMMMMMMMBBBBMMMM MMMMMMMMBBBBMMMM MMMMMMMMMBBBBMMM MMMMMMMMMMMBBBBM MMMMMMMMMMMMBBBB MMMMMMMMMMMMBBBB MMMMMMMMMMMMMBBB } # tile 161 (zap 3 3) { MMMMMMMMMMMMMBBB MMMMMMMMMMMMBBBB MMMMMMMMMMMMBBBB MMMMMMMMMMMBBBBM MMMMMMMMMBBBBMMM MMMMMMMMBBBBMMMM MMMMMMMMBBBBMMMM MMMMMMMBBBBMMMMM MMMMMBBBBMMMMMMM MMMMBBBBMMMMMMMM MMMMBBBBMMMMMMMM MMMBBBBMMMMMMMMM MBBBBMMMMMMMMMMM BBBBMMMMMMMMMMMM BBBBMMMMMMMMMMMM BBBMMMMMMMMMMMMM } # tile 162 (zap 4 0) { MMMMMMMAAMMMMMMM MMMMMMAAAAMMMMMM MMMMMMAAAAMMMMMM MMMMMMMAAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMAAAAMMMMMM MMMMMMAAAAMMMMMM MMMMMMMAAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMAAAAMMMMMM MMMMMMAAAAMMMMMM MMMMMMMAAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMAAAAMMMMMM MMMMMMAAAAMMMMMM MMMMMMMAAMMMMMMM } # tile 163 (zap 4 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MAAMMAAMMAAMMAAM AAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAA MAAMMAAMMAAMMAAM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 164 (zap 4 2) { AAAMMMMMMMMMMMMM AAAAMMMMMMMMMMMM AAAAMMMMMMMMMMMM MAAAAMMMMMMMMMMM MMMAAAAMMMMMMMMM MMMMAAAAMMMMMMMM MMMMAAAAMMMMMMMM MMMMMAAAAMMMMMMM MMMMMMMAAAAMMMMM MMMMMMMMAAAAMMMM MMMMMMMMAAAAMMMM MMMMMMMMMAAAAMMM MMMMMMMMMMMAAAAM MMMMMMMMMMMMAAAA MMMMMMMMMMMMAAAA MMMMMMMMMMMMMAAA } # tile 165 (zap 4 3) { MMMMMMMMMMMMMAAA MMMMMMMMMMMMAAAA MMMMMMMMMMMMAAAA MMMMMMMMMMMAAAAM MMMMMMMMMAAAAMMM MMMMMMMMAAAAMMMM MMMMMMMMAAAAMMMM MMMMMMMAAAAMMMMM MMMMMAAAAMMMMMMM MMMMAAAAMMMMMMMM MMMMAAAAMMMMMMMM MMMAAAAMMMMMMMMM MAAAAMMMMMMMMMMM AAAAMMMMMMMMMMMM AAAAMMMMMMMMMMMM AAAMMMMMMMMMMMMM } # tile 166 (zap 5 0) { MMMMMMMNNMMMMMMM MMMMMMNNNNMMMMMM MMMMMMNNNNMMMMMM MMMMMMMNNMMMMMMM MMMMMMMNNMMMMMMM MMMMMMNNNNMMMMMM MMMMMMNNNNMMMMMM MMMMMMMNNMMMMMMM MMMMMMMNNMMMMMMM MMMMMMNNNNMMMMMM MMMMMMNNNNMMMMMM MMMMMMMNNMMMMMMM MMMMMMMNNMMMMMMM MMMMMMNNNNMMMMMM MMMMMMNNNNMMMMMM MMMMMMMNNMMMMMMM } # tile 167 (zap 5 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MNNMMNNMMNNMMNNM NNNNNNNNNNNNNNNN NNNNNNNNNNNNNNNN MNNMMNNMMNNMMNNM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 168 (zap 5 2) { NNNMMMMMMMMMMMMM NNNNMMMMMMMMMMMM NNNNMMMMMMMMMMMM MNNNNMMMMMMMMMMM MMMNNNNMMMMMMMMM MMMMNNNNMMMMMMMM MMMMNNNNMMMMMMMM MMMMMNNNNMMMMMMM MMMMMMMNNNNMMMMM MMMMMMMMNNNNMMMM MMMMMMMMNNNNMMMM MMMMMMMMMNNNNMMM MMMMMMMMMMMNNNNM MMMMMMMMMMMMNNNN MMMMMMMMMMMMNNNN MMMMMMMMMMMMMNNN } # tile 169 (zap 5 3) { MMMMMMMMMMMMMNNN MMMMMMMMMMMMNNNN MMMMMMMMMMMMNNNN MMMMMMMMMMMNNNNM MMMMMMMMMNNNNMMM MMMMMMMMNNNNMMMM MMMMMMMMNNNNMMMM MMMMMMMNNNNMMMMM MMMMMNNNNMMMMMMM MMMMNNNNMMMMMMMM MMMMNNNNMMMMMMMM MMMNNNNMMMMMMMMM MNNNNMMMMMMMMMMM NNNNMMMMMMMMMMMM NNNNMMMMMMMMMMMM NNNMMMMMMMMMMMMM } # tile 170 (zap 6 0) { MMMMMMMFFMMMMMMM MMMMMMFFFFMMMMMM MMMMMMFFFFMMMMMM MMMMMMMFFMMMMMMM MMMMMMMFFMMMMMMM MMMMMMFFFFMMMMMM MMMMMMFFFFMMMMMM MMMMMMMFFMMMMMMM MMMMMMMFFMMMMMMM MMMMMMFFFFMMMMMM MMMMMMFFFFMMMMMM MMMMMMMFFMMMMMMM MMMMMMMFFMMMMMMM MMMMMMFFFFMMMMMM MMMMMMFFFFMMMMMM MMMMMMMFFMMMMMMM } # tile 171 (zap 6 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MFFMMFFMMFFMMFFM FFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFF MFFMMFFMMFFMMFFM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 172 (zap 6 2) { FFFMMMMMMMMMMMMM FFFFMMMMMMMMMMMM FFFFMMMMMMMMMMMM MFFFFMMMMMMMMMMM MMMFFFFMMMMMMMMM MMMMFFFFMMMMMMMM MMMMFFFFMMMMMMMM MMMMMFFFFMMMMMMM MMMMMMMFFFFMMMMM MMMMMMMMFFFFMMMM MMMMMMMMFFFFMMMM MMMMMMMMMFFFFMMM MMMMMMMMMMMFFFFM MMMMMMMMMMMMFFFF MMMMMMMMMMMMFFFF MMMMMMMMMMMMMFFF } # tile 173 (zap 6 3) { MMMMMMMMMMMMMFFF MMMMMMMMMMMMFFFF MMMMMMMMMMMMFFFF MMMMMMMMMMMFFFFM MMMMMMMMMFFFFMMM MMMMMMMMFFFFMMMM MMMMMMMMFFFFMMMM MMMMMMMFFFFMMMMM MMMMMFFFFMMMMMMM MMMMFFFFMMMMMMMM MMMMFFFFMMMMMMMM MMMFFFFMMMMMMMMM MFFFFMMMMMMMMMMM FFFFMMMMMMMMMMMM FFFFMMMMMMMMMMMM FFFMMMMMMMMMMMMM } # tile 174 (zap 7 0) { MMMMMMMGGMMMMMMM MMMMMMGGGGMMMMMM MMMMMMGGGGMMMMMM MMMMMMMGGMMMMMMM MMMMMMMGGMMMMMMM MMMMMMGGGGMMMMMM MMMMMMGGGGMMMMMM MMMMMMMGGMMMMMMM MMMMMMMGGMMMMMMM MMMMMMGGGGMMMMMM MMMMMMGGGGMMMMMM MMMMMMMGGMMMMMMM MMMMMMMGGMMMMMMM MMMMMMGGGGMMMMMM MMMMMMGGGGMMMMMM MMMMMMMGGMMMMMMM } # tile 175 (zap 7 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MGGMMGGMMGGMMGGM GGGGGGGGGGGGGGGG GGGGGGGGGGGGGGGG MGGMMGGMMGGMMGGM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM } # tile 176 (zap 7 2) { GGGMMMMMMMMMMMMM GGGGMMMMMMMMMMMM GGGGMMMMMMMMMMMM MGGGGMMMMMMMMMMM MMMGGGGMMMMMMMMM MMMMGGGGMMMMMMMM MMMMGGGGMMMMMMMM MMMMMGGGGMMMMMMM MMMMMMMGGGGMMMMM MMMMMMMMGGGGMMMM MMMMMMMMGGGGMMMM MMMMMMMMMGGGGMMM MMMMMMMMMMMGGGGM MMMMMMMMMMMMGGGG MMMMMMMMMMMMGGGG MMMMMMMMMMMMMGGG } # tile 177 (zap 7 3) { MMMMMMMMMMMMMGGG MMMMMMMMMMMMGGGG MMMMMMMMMMMMGGGG MMMMMMMMMMMGGGGM MMMMMMMMMGGGGMMM MMMMMMMMGGGGMMMM MMMMMMMMGGGGMMMM MMMMMMMGGGGMMMMM MMMMMGGGGMMMMMMM MMMMGGGGMMMMMMMM MMMMGGGGMMMMMMMM MMMGGGGMMMMMMMMM MGGGGMMMMMMMMMMM GGGGMMMMMMMMMMMM GGGGMMMMMMMMMMMM GGGMMMMMMMMMMMMM } # tile 178 (warning 0) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOOOOMMMMMMM MMMMOOOOOOMMMMMM MMMOOAAAAOOMMMMM MMMOOAMMMOOAMMMM MMMMAAMMMOOAMMMM MMMMMMMMOOAAMMMM MMMMMMMOOAAMMMMM MMMMMMOOAAMMMMMM MMMMMMOOAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMOOMMMMMMMM MMMMMMOOAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 179 (warning 1) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMOCOCMMMMMMM MMMMOCOCOCMMMMMM MMMOCAAAAOCMMMMM MMMCOAMMMCOAMMMM MMMMAAMMMOCAMMMM MMMMMMMMOCAAMMMM MMMMMMMOCAAMMMMM MMMMMMOCAAMMMMMM MMMMMMCOAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMCOMMMMMMMM MMMMMMOCAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 180 (warning 2) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMCCCCMMMMMMM MMMMCCCCCCMMMMMM MMMCCAAAACCMMMMM MMMCCAMMMCCAMMMM MMMMAAMMMCCAMMMM MMMMMMMMCCAAMMMM MMMMMMMCCAAMMMMM MMMMMMCCAAMMMMMM MMMMMMCCAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMCCMMMMMMMM MMMMMMCCAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 181 (warning 3) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMDDDDMMMMMMM MMMMDDDDDDMMMMMM MMMDDAAAADDMMMMM MMMDDAMMMDDAMMMM MMMMAAMMMDDAMMMM MMMMMMMMDDAAMMMM MMMMMMMDDAAMMMMM MMMMMMDDAAMMMMMM MMMMMMDDAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMDDMMMMMMMM MMMMMMDDAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 182 (warning 4) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMIIIIMMMMMMM MMMMIIIIIIMMMMMM MMMIIAAAAIIMMMMM MMMIIAMMMIIAMMMM MMMMAAMMMIIAMMMM MMMMMMMMIIAAMMMM MMMMMMMIIAAMMMMM MMMMMMIIAAMMMMMM MMMMMMIIAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMIIMMMMMMMM MMMMMMIIAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 183 (warning 5) { MMMMMMMMMMMMMMMM MMMMMMMMMMMMMMMM MMMMMIEIEMMMMMMM MMMMIEIEIEMMMMMM MMMIEAAAAIEMMMMM MMMEIAMMMEIAMMMM MMMMAAMMMIEAMMMM MMMMMMMMIEAAMMMM MMMMMMMIEAAMMMMM MMMMMMIEAAMMMMMM MMMMMMEIAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMEIMMMMMMMM MMMMMMIEAMMMMMMM MMMMMMMAAMMMMMMM MMMMMMMMMMMMMMMM } # tile 184 (sub mine walls 0) { AJJKKKACJAAJJJAA AJKKKACLJJAJJJJA AJKKACLCKJJAJJJA AAKACLCKJJJJAAAA AAACLLKKJJJJJJAA AACLLKKKAAJJJJJA ACKKKKKACJAJJJJA AKKKKKACLJJAJJJA AAKKKACLKJJJAJAA AAKKACLKKJJJJJAA AACCCKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AAKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 185 (sub mine walls 1) { AJAAAAAAJJAAAJAA JJJAAAJJJJJAAAAJ JJJACJAJJJACCJAJ AAACLJJAJACCLJJA AACLCKJJACCLCKJJ ACKCKKJJJCKCKKJA CJKKKKJJCKCKJJAC KJJKCJJCKKKJJJCK KJKKKJJKJKJJJJKK JJJKCJKKJKJJJCKJ JJJJJJKJKKJJJKKJ JJJJJKJJJJJJJJJJ JJJJJJJJJJJJJJJJ JJJJJJJJJJJJJJJJ JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 186 (sub mine walls 2) { AAAAAAKCCKKJAAAA AAAAKKCLCJKJJAAA AAKKKCLCKJJJKKAA AKKKCLCKJJJJJJKA AKKCLLKKJJJJJJJA AKCLLKKKAAJJJJJJ ACKKKKKACJAJJJJJ AKKKKKACLJJAAJJJ AAKKKCLLKJJJAJAJ AAKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AAKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 187 (sub mine walls 3) { AAAAAAKCCKKJAAAA AAAAKKCLCJKJJAAA AAKKKCLCKJJJKKAA AKKCCLCKJJJJJJKA KKCCLLKKJJJJJJJA KKCLKKKKAAJJJJJA KCLKKKKACJAJJJJA CKKKKKACLJJAAJJA KAKKKCLLKJJJAJAA AKKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AKKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 188 (sub mine walls 4) { AKKKAAKKKKAAJJJA AKKAAKCCCJJJAAJA AKKAALLJJJACCJAA AKAACLJJJACCLJJA AAACCKJJACLLCKJJ AAACLKJJJCKCKKJA AACLKKJJCKCKJJAC AAKKCJJCKKKJJJCK ACKKKJJKJKJJJJKK ACKKCJKKJKJJJCKJ AKKKJJKJKKJJJKKJ ACKJJKJJJJJJJJJJ AKJJJJJJJJJJJJJJ AKJJJJJJJJJJJJJJ AJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 189 (sub mine walls 5) { AKKAAAKKAAAAJJJA AKAAKKLCKAAAAAJA AAKKCLCJJACCAJJA AKKCLJJJACCCLAJA AKCKKKJACCCLCAAA ACKKKKJACCKCKKAA CJKKKKACCKCKJJAA KJJKCJJCKKKJJJAA KJKKKJJKJKJJJJJA JJJKCJKKJKJJJJJA JJJJJJKJKKJJJJJA JJJJJKJJJJJJJJJA JJJJJJJJJJJJJJJA JJJJJJJJJJJJJJJA JJJJJJJJJJJJJJJA AAAAAAAAAAAAAAAA } # tile 190 (sub mine walls 6) { AAAAAAKCCKKJAAAA AAAAKCCLCJKJJAAA AAKKCCLCKJJJKKAA AKKKCLCKJJJJJJKA KKKCLKKKJJJJJJJA KKCLKKKKAAJJJJJJ KCKLKKKACJAJJJJJ CKKKKKACLJJAAJJJ KAKKKCLLKJJJAJAJ AKKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AKKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 191 (sub mine walls 7) { AKKAAAKKKKAAJJJA AKAAKKLCCJJJAAJA AAKKCLCJJJACCJAA AKKCLJJJJACCLJJA AKCLCKJJACCLCKJJ ACKCKKJJJCKCKKJA CJKKKKJJCKCKJJAC KJJKCJJCKKKJJJCK KJKKKJJKJKJJJJKK JJJKCJKKJKJJJCKJ JJJJJJKJKKJJJKKJ JJJJJKJJJJJJJJJJ JJJJJJJJJJJJJJJJ JJJJJJJJJJJJJJJJ JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 192 (sub mine walls 8) { AAAAAAKCCKKJAAAA AAAAKCCLCJKJJAAA AAKKKCLCKJJJKKAA AKKKCLCKJJJJJJKA KKCCLLKKJJJJJJJA KKCLLKKKAAJJJJJJ KCLLKKKACJAJJJJJ CKLKKKACLJJAAJJJ KAKKKCLLKJJJAJAJ AKKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AKKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 193 (sub mine walls 9) { AKKAACKCCKKJAJJA AKACKKKLLJKJJAJA AAKKKCCCKJJJKKAA AKKKCCLKJJJJJJKA AKKCLLKKJJJJJJJA AKCLLKKKAAJJJJJJ ACLKKKKACJAJJJJJ AKKKKKACLJJAAJJJ AAKKKCLLKJJJAJAJ AAKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AAKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 194 (sub mine walls 10) { AKKAACKCCKKJAJJA AKACKKCLCJKJJAJA AAKKCCLCKJJJKKAA AKKCLLCKJJJJJJKA KKCCLLKKJJJJJJJA KCKLLKKKAAJJJJJA CCKKKKKACJAJJJJA CKKKKKACLJJAAJJA KAKKKCLLKJJJAJAA AKKKCCCKKJJJAJAA AACCKKKAAJJJJJJA ACCKKKACJAJJJJJA ACKKKACLJJAJJJJA AKKKACLCKJJAJJAA AAJACKCKKJJJAJAA AAJCKKJAAAJJJJJA } # tile 195 (sub gehennom walls 0) { ALLDAJMMMMMJLLDA ADDDAJMJMMJJDDDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA ADDDAJJMMMMJDDDA AJAAAJJMMMMJJAJA AJJJAJJMMMMJJJJA ADMMAJJMMJMJDMJA ALLDAJMMMMMJLLDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA ADDDAJJMJMJJDDDA AJAAAJJMMMMJJAJA AJJJAJJMMMMJJJJA ADMMAJJMMMMJDMJA } # tile 196 (sub gehennom walls 1) { AAALDDAAAAALDDAA DDDLDDAJDDDLDDAJ MDDJJJAJMDDJJJAJ JJJJJJJJJJJJJJJJ MMJJJMMMMMJJJMMM MMLDDMMMMMLDDMMM DDLDDAJDDDLDDAJD DDJJJAJMDDJJJAJM JJJJJJJJJJJJJJJJ MMJDMMMMJDMMMJDM MMJMMMMMJMMMMJMM JJJJJJJJJJJJJJJJ JDMMMMJDMMMMJDMM JMMMMMJMMMMMJMMM JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 197 (sub gehennom walls 2) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ AMMJJJJJJJJJMMMJ ADDDAAAAAAAADDDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA AJAAAJJMMMMJJAJA AJJJAJJMMMMJJJJA ADMMAJJMMMMJDMJA } # tile 198 (sub gehennom walls 3) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ AMMJJJJJJJJJMMMJ ADDDAAAAAAAADDDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA AJAAAJJMMMMJJAJA AJJJAJJMMMMJJJJA ADMMAJJMMMMJDMJA } # tile 199 (sub gehennom walls 4) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ MMJDMMMMJDMMMJDM MMJMMMMMJMMMMJMM JJJJJJJJJJJJJJJJ JDMMMMJDMMMMJDMM JMMMMMJMMMMMJMMM JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 200 (sub gehennom walls 5) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ MMJDMMMMJDMMMJDM MMJMMMMMJMMMMJMM JJJJJJJJJJJJJJJJ JDMMMMJDMMMMJDMM JMMMMMJMMMMMJMMM JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 201 (sub gehennom walls 6) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ AMMJJJJJJJJJMMMJ ADDDAAAAAAAADDDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA AJAAAJJMMMMJJAJA AJJJAJJMMMMJJJJA ADMMAJJMMMMJDMJA } # tile 202 (sub gehennom walls 7) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ MMJDMMMMJDMMMJDM MMJMMMMMJMMMMJMM JJJJJJJJJJJJJJJJ JDMMMMJDMMMMJDMM JMMMMMJMMMMMJMMM JJJJJJJJJJJJJJJJ AAAAAAAAAAAAAAAA } # tile 203 (sub gehennom walls 8) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ AMMJJJJJJJJJMMMJ ADDDAAAAAAAADDDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA AJAAAJJMMMMJJAJA AJJJAJJMMMMJJJJA ADMMAJJMMMMJDMJA } # tile 204 (sub gehennom walls 9) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ AMMJJJJJJJJJMMMJ ADDDAAAAAAAADDDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA AJAAAJJMMMMJJAJA AJJJAJJMMMMJJJJA ADMMAJJMMMMJDMJA } # tile 205 (sub gehennom walls 10) { AAALLLLDDDDDDAAA LLLLAAJJMMMMDJJJ DDDLAJJMMMCCDJJJ DDDDDDDDDDDDDJJJ DDDMMMMMMMMMMJJJ DDDMMMMMMMMMMJJJ DDMMMMMMMMMMMMJJ DMMMMMMMMMMMMMMJ JJJJJJJJJJJJJJJJ AMMJJJJJJJJJMMMJ ADDDAAAAAAAADDDA ADDDAJMMMMMJDDDA ADDDAJMMMMMJDDDA AJAAAJJMMMMJJAJA AJJJAJJMMMMJJJJA ADMMAJJMMMMJDMJA } # tile 206 (sub knox walls 0) { AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AJJJACLCKJJAJJJA AAAAALCKJJJAAAAA AAJAAAKKJJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 207 (sub knox walls 1) { AJAAAJAAAJAAAJAA JJJAAAJAJJJAAAJA JJJACJAAJJJACJAA AAACLJJAJJACLJJA AACLCKJJAACLCKJJ AAACKKJAAAACKKJA AJAAAJAAAJAAAJAA KJJACJJAKJJACJJA KJJAKJJAKJJACJJA KJJACJAAKJJAKJAA CJJACJAACJJAKJJA KJAACJJACJJACJJA KJAACJJACJAAKJJA KJJAKJJAKJJACJAA KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } # tile 208 (sub knox walls 2) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 209 (sub knox walls 3) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 210 (sub knox walls 4) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AACCCAKJJAJJJAKA AJACAJAJAJAJAJAA KJJACJJAKJJACJJA KJJAKJJAKJJACJJA KJJACJAAKJJAKJAA CJJACJAACJJAKJJA KJAACJJACJJACJJA KJAACJJACJAAKJJA KJJAKJJAKJJACJAA KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } # tile 211 (sub knox walls 5) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AACCCAKJJAJJJAKA AJACAJAJAJAJAJAA KJJACJJAKJJACJJA KJJAKJJAKJJACJJA KJJACJAAKJJAKJAA CJJACJAACJJAKJJA KJAACJJACJJACJJA KJAACJJACJAAKJJA KJJAKJJAKJJACJAA KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } # tile 212 (sub knox walls 6) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 213 (sub knox walls 7) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AACCCAKJJAJJJAKA AJACAJAJAJAJAJAA KJJACJJAKJJACJJA KJJAKJJAKJJACJJA KJJACJAAKJJAKJAA CJJACJAACJJAKJJA KJAACJJACJJACJJA KJAACJJACJAAKJJA KJJAKJJAKJJACJAA KJJACJJAKJJACJJA AAAAAAAAAAAAAAAA } # tile 214 (sub knox walls 8) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 215 (sub knox walls 9) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 216 (sub knox walls 10) { AAAAAAKCJKAAAAAA AAAAKKCLKJKKAAAA AAKKKCLCKJJKKKAA AKKKCLCKKJJJKKKA AKKCCCKKJJJJJKKA AKCCCKKAAJJJJJKA AJJCKKACJAJJJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA AJJJAAACJAAAJJJA AJJJAACLJJAAJJJA AAAAACLCKJJAAAAA AAJAAACKKJAAAJAA ACJJAAAAAAAACJJA } # tile 217 (sub sokoban walls 0) { ANNBAMEEEEEMNNBA ABBBAMEMEEMMBBBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA ABBBAMMEEEEMBBBA AMAAAMMEEEEMMAMA AMMMAMMEEEEMMMMA ABEEAMMEEMEMBEMA ANNBAMEEEEEMNNBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA ABBBAMMEMEMMBBBA AMAAAMMEEEEMMAMA AMMMAMMEEEEMMMMA ABEEAMMEEEEMBEMA } # tile 218 (sub sokoban walls 1) { AAANBBAAAAANBBAA BBBNBBAMBBBNBBAM EBBMMMAMEBBMMMAM MMMMMMMMMMMMMMMM EEMMMEEEEEMMMEEE EENBBEEEEENBBEEE BBNBBAMBBBNBBAMB BBMMMAMEBBMMMAME MMMMMMMMMMMMMMMM EEMBEEEEMBEEEMBE EEMEEEEEMEEEEMEE MMMMMMMMMMMMMMMM MBEEEEMBEEEEMBEE MEEEEEMEEEEEMEEE MMMMMMMMMMMMMMMM AAAAAAAAAAAAAAAA } # tile 219 (sub sokoban walls 2) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM AEEMMMMMMMMMEEEM ABBBAAAAAAAABBBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA AMAAAMMEEEEMMAMA AMMMAMMEEEEMMMMA ABEEAMMEEEEMBEMA } # tile 220 (sub sokoban walls 3) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM AEEMMMMMMMMMEEEM ABBBAAAAAAAABBBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA AMAAAMMEEEEMMAMA AMMMAMMEEEEMMMMA ABEEAMMEEEEMBEMA } # tile 221 (sub sokoban walls 4) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM EEMBEEEEMBEEEMBE EEMEEEEEMEEEEMEE MMMMMMMMMMMMMMMM MBEEEEMBEEEEMBEE MEEEEEMEEEEEMEEE MMMMMMMMMMMMMMMM AAAAAAAAAAAAAAAA } # tile 222 (sub sokoban walls 5) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM EEMBEEEEMBEEEMBE EEMEEEEEMEEEEMEE MMMMMMMMMMMMMMMM MBEEEEMBEEEEMBEE MEEEEEMEEEEEMEEE MMMMMMMMMMMMMMMM AAAAAAAAAAAAAAAA } # tile 223 (sub sokoban walls 6) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM AEEMMMMMMMMMEEEM ABBBAAAAAAAABBBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA AMAAAMMEEEEMMAMA AMMMAMMEEEEMMMMA ABEEAMMEEEEMBEMA } # tile 224 (sub sokoban walls 7) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM EEMBEEEEMBEEEMBE EEMEEEEEMEEEEMEE MMMMMMMMMMMMMMMM MBEEEEMBEEEEMBEE MEEEEEMEEEEEMEEE MMMMMMMMMMMMMMMM AAAAAAAAAAAAAAAA } # tile 225 (sub sokoban walls 8) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM AEEMMMMMMMMMEEEM ABBBAAAAAAAABBBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA AMAAAMMEEEEMMAMA AMMMAMMEEEEMMMMA ABEEAMMEEEEMBEMA } # tile 226 (sub sokoban walls 9) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM AEEMMMMMMMMMEEEM ABBBAAAAAAAABBBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA AMAAAMMEEEEMMAMA AMMMAMMEEEEMMMMA ABEEAMMEEEEMBEMA } # tile 227 (sub sokoban walls 10) { AAANNNNBBBBBBAAA NNNNAAMMEEEEBMMM BBBNAMMEEENNBMMM BBBBBBBBBBBBBMMM BBBEEEEEEEEEEMMM BBBEEEEEEEEEEMMM BBEEEEEEEEEEEEMM BEEEEEEEEEEEEEEM MMMMMMMMMMMMMMMM AEEMMMMMMMMMEEEM ABBBAAAAAAAABBBA ABBBAMEEEEEMBBBA ABBBAMEEEEEMBBBA AMAAAMMEEEEMMAMA AMMMAMMEEEEMMMMA ABEEAMMEEEEMBEMA } nethack-3.4.3/win/share/ppmwrite.c0100644000000000000000000000635207764735042015573 0ustar rootroot/* this produces a raw ppm file, with a 15-character header of * "P6 3-digit-width 3-digit-height 255\n" */ #include "config.h" #include "tile.h" #ifndef MONITOR_HEAP extern long *FDECL(alloc, (unsigned int)); #endif FILE *ppm_file; struct ppmscreen { int Width; int Height; } PpmScreen; static int tiles_across, tiles_down, curr_tiles_across; static pixel **image; static void NDECL(write_header); static void NDECL(WriteTileStrip); static void write_header() { (void) fprintf(ppm_file, "P6 %03d %03d 255\n", PpmScreen.Width, PpmScreen.Height); } static void WriteTileStrip() { int i, j; for (j = 0; j < TILE_Y; j++) { for (i = 0; i < PpmScreen.Width; i++) { (void) fputc((char)image[j][i].r, ppm_file); (void) fputc((char)image[j][i].g, ppm_file); (void) fputc((char)image[j][i].b, ppm_file); } } } boolean fopen_ppm_file(filename, type) const char *filename; const char *type; { int i; if (strcmp(type, WRBMODE)) { Fprintf(stderr, "using writing routine for non-writing?\n"); return FALSE; } ppm_file = fopen(filename, type); if (ppm_file == (FILE *)0) { Fprintf(stderr, "cannot open ppm file %s\n", filename); return FALSE; } if (!colorsinmainmap) { Fprintf(stderr, "no colormap set yet\n"); return FALSE; } tiles_across = 20; curr_tiles_across = 0; PpmScreen.Width = 20 * TILE_X; tiles_down = 0; PpmScreen.Height = 0; /* will be rewritten later */ write_header(); image = (pixel **)alloc(TILE_Y * sizeof(pixel *)); for (i = 0; i < TILE_Y; i++) { image[i] = (pixel *) alloc(PpmScreen.Width * sizeof(pixel)); } return TRUE; } boolean write_ppm_tile(pixels) pixel (*pixels)[TILE_X]; { int i, j; for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { image[j][curr_tiles_across*TILE_X + i] = pixels[j][i]; } } curr_tiles_across++; if (curr_tiles_across == tiles_across) { WriteTileStrip(); curr_tiles_across = 0; tiles_down++; } return TRUE; } int fclose_ppm_file() { int i, j; if (curr_tiles_across) { /* partial row */ /* fill with checkerboard, for lack of a better idea */ for (j = 0; j < TILE_Y; j++) { for (i = curr_tiles_across * TILE_X; i < PpmScreen.Width; i += 2 ) { image[j][i].r = MainColorMap[CM_RED][0]; image[j][i].g = MainColorMap[CM_GREEN][0]; image[j][i].b = MainColorMap[CM_BLUE][0]; image[j][i+1].r = MainColorMap[CM_RED][1]; image[j][i+1].g = MainColorMap[CM_GREEN][1]; image[j][i+1].b = MainColorMap[CM_BLUE][1]; } } WriteTileStrip(); curr_tiles_across = 0; tiles_down++; } for (i = 0; i < TILE_Y; i++) { free((genericptr_t)image[i]); } free((genericptr_t)image); PpmScreen.Height = tiles_down * TILE_Y; rewind(ppm_file); write_header(); /* update size */ return(fclose(ppm_file)); } int main(argc, argv) int argc; char *argv[]; { pixel pixels[TILE_Y][TILE_X]; if (argc != 3) { Fprintf(stderr, "usage: txt2ppm txtfile ppmfile\n"); exit(EXIT_FAILURE); } if (!fopen_text_file(argv[1], RDTMODE)) exit(EXIT_FAILURE); init_colormap(); if (!fopen_ppm_file(argv[2], WRBMODE)) { (void) fclose_text_file(); exit(EXIT_FAILURE); } while (read_text_tile(pixels)) (void) write_ppm_tile(pixels); (void) fclose_text_file(); (void) fclose_ppm_file(); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } nethack-3.4.3/win/share/thintile.c0100644000000000000000000000523307764735042015541 0ustar rootroot/* SCCS Id: @(#)thintile.c 3.4 1995/11/26 */ /* Copyright (c) NetHack Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* Create a set of overview tiles by eliminating even pixels in original */ #include "config.h" #include "tile.h" #ifdef __GO32__ #include #endif static char pixels[TILE_Y][TILE_X]; static char *tilefiles[] = { "../win/share/monsters.txt", "../win/share/objects.txt", "../win/share/other.txt"}; static char *thinfiles[] = { "../win/share/monthin.txt", "../win/share/objthin.txt", "../win/share/oththin.txt"}; static FILE *infile, *outfile; static int tilecount; static int tilecount_per_file; static int filenum; static char comment[BUFSZ]; static void copy_colormap() { int r, g, b; char c[2]; while (fscanf(infile, "%[A-Za-z0-9] = (%d, %d, %d) ", c, &r, &g, &b) == 4) { Fprintf(outfile, "%c = (%d, %d, %d)\n", c[0], r, g, b); } } static boolean read_txttile() { int i, j; char buf[BUFSZ]; char buf2[BUFSZ]; char c[2]; if (fscanf(infile, "# %s %d (%[^)])", buf2, &i, buf) <= 0) return FALSE; Sprintf(comment,"# tile %d (%s)", i, buf); /* look for non-whitespace at each stage */ if (fscanf(infile, "%1s", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } if (c[0] != '{') { Fprintf(stderr, "didn't find expected '{'\n"); return FALSE; } for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { if (fscanf(infile, "%1s", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } pixels[j][i] = c[0]; } } if (fscanf(infile, "%1s ", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } if (c[0] != '}') { Fprintf(stderr, "didn't find expected '}'\n"); return FALSE; } return TRUE; } static void write_thintile() { int i, j; Fprintf(outfile, "%s\n", comment); Fprintf(outfile, "{\n"); for (j = 0; j < TILE_Y; j++) { Fprintf(outfile, " "); for (i = 0; i < TILE_X; i += 2) { (void) fputc(pixels[j][i], outfile); } Fprintf(outfile, "\n"); } Fprintf(outfile, "}\n"); } int main(argc, argv) int argc; char *argv[]; { while (filenum < 3) { tilecount_per_file = 0; infile = fopen(tilefiles[filenum], RDTMODE); outfile = fopen(thinfiles[filenum], WRTMODE); copy_colormap(); while (read_txttile()) { write_thintile(); tilecount_per_file++; tilecount++; } fclose(outfile); fclose(infile); printf("%d tiles processed from %s\n", tilecount_per_file, tilefiles[filenum]); ++filenum; } printf("Grand total of %d tiles processed.\n", tilecount); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } /*thintile.c*/ nethack-3.4.3/win/share/tile.doc0100644000000000000000000001274307764735042015205 0ustar rootrootWindow ports can optionally make use of the tiles (pictures for NetHack symbols) found in this directory. They are distributed in a text format with routines to help in converting them to a system's preferred format and using them there. The original tiles were provided by Warwick Allison. The tile distribution format for monsters.txt, objects.txt, and other.txt starts with a palette header like: A = (0, 0, 0) ... P = (254, 254, 254) and then each tile has an entry like: # tile 292 (comment identifying tile) { AAAAGHPAAAAACDAA AAAFGDEMLOCNAAAA ... } Each port can convert these .txt files to whatever format it wants the game executable to use, probably providing only one merged output file. See the tilemap.c discussion at the bottom for more hints on adding tiles. Shared code provided for conversion utilities: tile.h contains shared declarations. tiletext.c defines the external variables from tile.h and supplies the external routines for reading and writing the defined text format. Each conversion utility is expected to use tiletext.c and provide code of its own for reading and/or writing another format. The important global variables implement a colormap shared between tiletext.c and the other half of utilities. As an example of conversion utilities, we provide txt2ppm (tiletext.c + ppmwrite.c) and gif2txt (tiletext.c + gifread.c). (Sorry, we're not paying Unisys patent royalties for the right to provide you with a gifwrite.c, which would necessarily use the LZW compression algorithm they claim.) The text I/O routines are: boolean fopen_text_file(const char *filename, const char *type); select file for subsequent tile I/O "type" a la fopen returns FALSE if file not opened, otherwise reads/writes header (including colormap) and sets up to decode/encode tiles int fclose_text_file(); close file boolean read_text_tile(pixel[TILE_Y][TILE_X]); returns FALSE if no next tile in current file otherwise TRUE and insert the tile in the provided array boolean write_text_tile(pixel[TILE_Y][TILE_X]); writes tile There are two additional shared routines provided for writers: void init_colormap(); initialize the output colormap from the input one must be called before opening output file as colormap is part of header void merge_colormap(); merge the current input colormap into the output one Due to the amount of state being kept, only one text or gif file can be open at a time. If you are combining multiple files into one other-format file with a single common colormap, you may need to open each source file and merge their colormaps into a common colormap before processing any tiles. Although there are expected to be only 16 colors in the distribution tiles, conversion programs should be prepared to accept up to MAXCOLORMAPSIZE colors and map them to a smaller number if their port requires it. Expected sequence for editing tiles: edit foo.txt -or- run txt2ppm foo.txt foo.ppm convert ppm to gif, either via ppmtogif from pbmplus/netpbm or stripping the first 15 bytes of foo.ppm (containing the size of the image) and feeding the rest to any raw-24bit- image-reading program edit tiles with gif-editing program run gif2txt foo.gif foo.txt When converted to ppm, monsters.ppm, objects.ppm, and other.ppm are: each a single ppm format (rgb triples with header) 20 tiles across, however many down (need "blank" tile to fill in extras on last row -- currently alternating pixels in first and second colors) allows looking at tiles en masse for comparison or whatever The gif reading routines accept further variations so long as the gif is n*TILE_X pixels across. The gif I/O routines are: boolean fopen_gif_file(const char *filename, const char *type); select file for subsequent tile I/O "type" a la fopen returns FALSE if file not opened, otherwise reads gif header (including colormap) and sets up to decode tiles int fclose_gif_file(); tear down decode mechanism close file boolean read_gif_tile(pixel[TILE_Y][TILE_X]); returns FALSE if no next tile in current file (including when any remaining tiles are "blank"), otherwise TRUE and insert the tile in the provided array Array provided by shared code for NetHack use, by compiling and running tilemap.c to form tile.c: short glyph2tile[MAXGLYPH]; maps glyph number to tile number for display purposes, assuming (non-blank) tiles are numbered sequentially through monsters/objects/other tilemap.c (shudder) accounts for things disappearing due to compilation options -- there should be a tile for everything appearing under any supported option, but under some options some tiles won't be referenced. Therefore, tilemap.c has the knowledge to provide the comments for gif2txt and is compiled with GIF2TXT to link in there, along with the various strings for things that are compiled in (monst.o etc.). If you add monsters/objects/other things to NetHack and need to add tiles to go with them, just add an entry in the right place in the appropriate .txt file, and one to tilemap.c if the new item is conditionally compiled. While the "comment identifying tile" in the .txt file must be correct, the number of the tile need not be, and can just be a duplicate of the tile on either side (or any other integer, for that matter). In an official release, the tiles in a .txt file will be numbered consecutively so that you may cross-reference with a graphics format, but the conversion code does not care about the numbering. (In fact, running txt2ppm, ppmtogif, and gif2txt gives you a consecutively numbered version of the .txt file.) nethack-3.4.3/win/share/tile.h0100644000000000000000000000173007764735042014661 0ustar rootroottypedef unsigned char pixval; typedef struct { pixval r, g, b; } pixel; #define MAXCOLORMAPSIZE 256 #define CM_RED 0 #define CM_GREEN 1 #define CM_BLUE 2 /* shared between reader and writer */ extern pixval ColorMap[3][MAXCOLORMAPSIZE]; extern int colorsinmap; /* writer's accumulated colormap */ extern pixval MainColorMap[3][MAXCOLORMAPSIZE]; extern int colorsinmainmap; #include "dlb.h" /* for MODEs */ /* size of tiles */ #ifndef TILE_X #define TILE_X 16 #endif #ifndef TILE_Y #define TILE_Y 16 #endif #define Fprintf (void) fprintf extern boolean FDECL(fopen_text_file, (const char *, const char *)); extern boolean FDECL(read_text_tile, (pixel (*)[TILE_X])); extern boolean FDECL(write_text_tile, (pixel (*)[TILE_X])); extern int NDECL(fclose_text_file); extern void NDECL(init_colormap); extern void NDECL(merge_colormap); #if defined(MICRO) || defined(WIN32) #undef exit # if !defined(MSDOS) && !defined(WIN32) extern void FDECL(exit, (int)); # endif #endif nethack-3.4.3/win/share/tile2bmp.c0100644000000000000000000001674707764735042015453 0ustar rootroot/* SCCS Id: @(#)tile2bmp.c 3.4 2002/03/14 */ /* Copyright (c) NetHack PC Development Team 1995 */ /* NetHack may be freely redistributed. See license for details. */ /* * Edit History: * * Initial Creation M.Allison 1994/01/11 * */ /* #pragma warning(4103:disable) */ #include "hack.h" #include "tile.h" #ifndef __GNUC__ #include "win32api.h" #endif /* #define COLORS_IN_USE MAXCOLORMAPSIZE /* 256 colors */ #if (TILE_X==32) #define COLORS_IN_USE 256 #else #define COLORS_IN_USE 16 /* 16 colors */ #endif #define BITCOUNT 8 extern char *FDECL(tilename, (int, int)); #if BITCOUNT==4 #define MAX_X 320 /* 2 per byte, 4 bits per pixel */ #define MAX_Y 480 #else # if (TILE_X==32) #define MAX_X (32 * 40) #define MAX_Y 960 # else #define MAX_X 640 /* 1 per byte, 8 bits per pixel */ #define MAX_Y 480 # endif #endif /* GCC fix by Paolo Bonzini 1999/03/28 */ #ifdef __GNUC__ #define PACK __attribute__((packed)) #else #define PACK #endif static short leshort(short x) { #ifdef __BIG_ENDIAN__ return ((x&0xff)<<8)|((x>>8)&0xff); #else return x; #endif } static long lelong(long x) { #ifdef __BIG_ENDIAN__ return ((x&0xff)<<24)|((x&0xff00)<<8)|((x>>8)&0xff00)|((x>>24)&0xff); #else return x; #endif } #ifdef __GNUC__ typedef struct tagBMIH { unsigned long biSize; long biWidth; long biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned long biCompression; unsigned long biSizeImage; long biXPelsPerMeter; long biYPelsPerMeter; unsigned long biClrUsed; unsigned long biClrImportant; } PACK BITMAPINFOHEADER; typedef struct tagBMFH { unsigned short bfType; unsigned long bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long bfOffBits; } PACK BITMAPFILEHEADER; typedef struct tagRGBQ { unsigned char rgbBlue; unsigned char rgbGreen; unsigned char rgbRed; unsigned char rgbReserved; } PACK RGBQUAD; #define UINT unsigned int #define DWORD unsigned long #define LONG long #define WORD unsigned short #define BI_RGB 0L #define BI_RLE8 1L #define BI_RLE4 2L #define BI_BITFIELDS 3L #endif /* __GNUC__ */ #pragma pack(1) struct tagBMP{ BITMAPFILEHEADER bmfh; BITMAPINFOHEADER bmih; #if BITCOUNT==4 #define RGBQUAD_COUNT 16 RGBQUAD bmaColors[RGBQUAD_COUNT]; #else #if (TILE_X==32) #define RGBQUAD_COUNT 256 #else #define RGBQUAD_COUNT 16 #endif RGBQUAD bmaColors[RGBQUAD_COUNT]; #endif #if (COLORS_IN_USE==16) uchar packtile[MAX_Y][MAX_X]; #else uchar packtile[MAX_Y][MAX_X]; /* uchar packtile[TILE_Y][TILE_X]; */ #endif } PACK bmp; #pragma pack() #define BMPFILESIZE (sizeof(struct tagBMP)) FILE *tibfile2; pixel tilepixels[TILE_Y][TILE_X]; static void FDECL(build_bmfh,(BITMAPFILEHEADER *)); static void FDECL(build_bmih,(BITMAPINFOHEADER *)); static void FDECL(build_bmptile,(pixel (*)[TILE_X])); char *tilefiles[] = { #if (TILE_X == 32) "../win/share/mon32.txt", "../win/share/obj32.txt", "../win/share/oth32.txt" #else "../win/share/monsters.txt", "../win/share/objects.txt", "../win/share/other.txt" #endif }; int num_colors = 0; int tilecount; int max_tiles_in_row = 40; int tiles_in_row; int filenum; int initflag; int yoffset,xoffset; char bmpname[128]; FILE *fp; int main(argc, argv) int argc; char *argv[]; { int i, j; if (argc != 2) { Fprintf(stderr, "usage: %s outfile.bmp\n", argv[0]); exit(EXIT_FAILURE); } else strcpy(bmpname, argv[1]); #ifdef OBSOLETE bmpfile2 = fopen(NETHACK_PACKED_TILEFILE, WRBMODE); if (bmpfile2 == (FILE *)0) { Fprintf(stderr, "Unable to open output file %s\n", NETHACK_PACKED_TILEFILE); exit(EXIT_FAILURE); } #endif tilecount = 0; xoffset = yoffset = 0; initflag = 0; filenum = 0; fp = fopen(bmpname,"wb"); if (!fp) { printf("Error creating tile file %s, aborting.\n",bmpname); exit(1); } while (filenum < (sizeof(tilefiles) / sizeof(char *))) { if (!fopen_text_file(tilefiles[filenum], RDTMODE)) { Fprintf(stderr, "usage: tile2bmp (from the util directory)\n"); exit(EXIT_FAILURE); } num_colors = colorsinmap; if (num_colors > 62) { Fprintf(stderr, "too many colors (%d)\n", num_colors); exit(EXIT_FAILURE); } if (!initflag) { build_bmfh(&bmp.bmfh); build_bmih(&bmp.bmih); for (i = 0; i < MAX_Y; ++i) for (j = 0; j < MAX_X; ++j) bmp.packtile[i][j] = (uchar)0; for (i = 0; i < num_colors; i++) { bmp.bmaColors[i].rgbRed = ColorMap[CM_RED][i]; bmp.bmaColors[i].rgbGreen = ColorMap[CM_GREEN][i]; bmp.bmaColors[i].rgbBlue = ColorMap[CM_BLUE][i]; bmp.bmaColors[i].rgbReserved = 0; } initflag = 1; } /* printf("Colormap initialized\n"); */ while (read_text_tile(tilepixels)) { build_bmptile(tilepixels); tilecount++; #if BITCOUNT==4 xoffset += (TILE_X / 2); #else xoffset += TILE_X; #endif if (xoffset >= MAX_X) { yoffset += TILE_Y; xoffset = 0; } } (void) fclose_text_file(); ++filenum; } fwrite(&bmp, sizeof(bmp), 1, fp); fclose(fp); Fprintf(stderr, "Total of %d tiles written to %s.\n", tilecount, bmpname); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } static void build_bmfh(pbmfh) BITMAPFILEHEADER *pbmfh; { pbmfh->bfType = leshort(0x4D42); pbmfh->bfSize = lelong(BMPFILESIZE); pbmfh->bfReserved1 = (UINT)0; pbmfh->bfReserved2 = (UINT)0; pbmfh->bfOffBits = lelong(sizeof(bmp.bmfh) + sizeof(bmp.bmih) + (RGBQUAD_COUNT * sizeof(RGBQUAD))); } static void build_bmih(pbmih) BITMAPINFOHEADER *pbmih; { WORD cClrBits; int w,h; pbmih->biSize = lelong(sizeof(bmp.bmih)); #if BITCOUNT==4 pbmih->biWidth = lelong(w = MAX_X * 2); #else pbmih->biWidth = lelong(w = MAX_X); #endif pbmih->biHeight = lelong(h = MAX_Y); pbmih->biPlanes = leshort(1); #if BITCOUNT==4 pbmih->biBitCount = leshort(4); cClrBits = 4; #else pbmih->biBitCount = leshort(8); cClrBits = 8; #endif if (cClrBits == 1) cClrBits = 1; else if (cClrBits <= 4) cClrBits = 4; else if (cClrBits <= 8) cClrBits = 8; else if (cClrBits <= 16) cClrBits = 16; else if (cClrBits <= 24) cClrBits = 24; else cClrBits = 32; pbmih->biCompression = lelong(BI_RGB); pbmih->biXPelsPerMeter = lelong(0); pbmih->biYPelsPerMeter = lelong(0); #if (TILE_X==32) if (cClrBits < 24) pbmih->biClrUsed = lelong(1<biClrUsed = lelong(RGBQUAD_COUNT); #endif #if (TILE_X==16) pbmih->biSizeImage = lelong(0); #else pbmih->biSizeImage = lelong(((w * cClrBits +31) & ~31) /8 * h); #endif pbmih->biClrImportant = (DWORD)0; } static void build_bmptile(pixels) pixel (*pixels)[TILE_X]; { int cur_x, cur_y, cur_color; int x,y; for (cur_y = 0; cur_y < TILE_Y; cur_y++) { for (cur_x = 0; cur_x < TILE_X; cur_x++) { for (cur_color = 0; cur_color < num_colors; cur_color++) { if (ColorMap[CM_RED][cur_color] == pixels[cur_y][cur_x].r && ColorMap[CM_GREEN][cur_color]== pixels[cur_y][cur_x].g && ColorMap[CM_BLUE][cur_color] == pixels[cur_y][cur_x].b) break; } if (cur_color >= num_colors) Fprintf(stderr, "color not in colormap!\n"); y = (MAX_Y - 1) - (cur_y + yoffset); #if BITCOUNT==4 x = (cur_x / 2) + xoffset; bmp.packtile[y][x] = cur_x%2 ? (uchar)(bmp.packtile[y][x] | cur_color) : (uchar)(cur_color<<4); #else x = cur_x + xoffset; bmp.packtile[y][x] = (uchar)cur_color; #endif } } } nethack-3.4.3/win/share/tilemap.c0100644000000000000000000003271607764735042015362 0ustar rootroot/* SCCS Id: @(#)tilemap.c 3.4 2000/06/04 */ /* NetHack may be freely redistributed. See license for details. */ /* * This source file is compiled twice: * once without TILETEXT defined to make tilemap.{o,obj}, * then again with it defined to produce tiletxt.{o,obj}. */ #include "hack.h" const char * FDECL(tilename, (int, int)); void NDECL(init_tilemap); void FDECL(process_substitutions, (FILE *)); #if defined(MICRO) || defined(WIN32) #undef exit #if !defined(MSDOS) && !defined(WIN32) extern void FDECL(exit, (int)); #endif #endif #define MON_GLYPH 1 #define OBJ_GLYPH 2 #define OTH_GLYPH 3 /* fortunately unnecessary */ /* note that the ifdefs here should be the opposite sense from monst.c/ * objects.c/rm.h */ struct conditionals { int sequence, predecessor; const char *name; } conditionals[] = { #ifndef CHARON /* not supported yet */ { MON_GLYPH, PM_HELL_HOUND, "Cerberus" }, #endif /* commented out in monst.c at present */ { MON_GLYPH, PM_SHOCKING_SPHERE, "beholder" }, { MON_GLYPH, PM_BABY_SILVER_DRAGON, "baby shimmering dragon" }, { MON_GLYPH, PM_SILVER_DRAGON, "shimmering dragon" }, { MON_GLYPH, PM_JABBERWOCK, "vorpal jabberwock" }, #ifndef KOPS { MON_GLYPH, PM_JABBERWOCK, "Keystone Kop" }, { MON_GLYPH, PM_JABBERWOCK, "Kop Sergeant" }, { MON_GLYPH, PM_JABBERWOCK, "Kop Lieutenant" }, { MON_GLYPH, PM_JABBERWOCK, "Kop Kaptain" }, #endif { MON_GLYPH, PM_VAMPIRE_LORD, "vampire mage" }, #ifndef CHARON /* not supported yet */ { MON_GLYPH, PM_CROESUS, "Charon" }, #endif #ifndef MAIL { MON_GLYPH, PM_FAMINE, "mail daemon" }, #endif #ifndef TOURIST { MON_GLYPH, PM_SAMURAI, "tourist" }, #endif /* commented out in monst.c at present */ { MON_GLYPH, PM_SHAMAN_KARNOV, "Earendil" }, { MON_GLYPH, PM_SHAMAN_KARNOV, "Elwing" }, #ifndef TOURIST { MON_GLYPH, PM_LORD_SATO, "Twoflower" }, #endif /* commented out in monst.c at present */ { MON_GLYPH, PM_CHROMATIC_DRAGON, "Goblin King" }, { MON_GLYPH, PM_NEANDERTHAL, "High-elf" }, #ifndef TOURIST { MON_GLYPH, PM_ROSHI, "guide" }, #endif #ifndef KOPS { OBJ_GLYPH, CLUB, "rubber hose" }, #endif /* objects commented out in objects.c at present */ { OBJ_GLYPH, SILVER_DRAGON_SCALE_MAIL, "shimmering dragon scale mail" }, { OBJ_GLYPH, SILVER_DRAGON_SCALES, "shimmering dragon scales" }, #ifndef TOURIST { OBJ_GLYPH, LEATHER_JACKET, "Hawaiian shirt" }, { OBJ_GLYPH, LEATHER_JACKET, "T-shirt" }, { OBJ_GLYPH, LOCK_PICK, "credit card" }, { OBJ_GLYPH, MAGIC_LAMP, "expensive camera" }, #endif #ifndef STEED { OBJ_GLYPH, TOWEL, "saddle" }, #endif /* allow slime mold to look like slice of pizza, since we * don't know what a slime mold should look like when renamed anyway */ #ifndef MAIL { OBJ_GLYPH, SCR_STINKING_CLOUD+4, "stamped / mail" }, #endif { 0, 0, 0} }; /* * Some entries in glyph2tile[] should be substituted for on various levels. * The tiles used for the substitute entries will follow the usual ones in * other.til in the order given here, which should have every substitution * for the same set of tiles grouped together. You will have to change * more code in process_substitutions()/substitute_tiles() if the sets * overlap in the future. */ struct substitute { int first_glyph, last_glyph; const char *sub_name; /* for explanations */ const char *level_test; } substitutes[] = { { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "mine walls", "In_mines(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "gehennom walls", "In_hell(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "knox walls", "Is_knox(plev)" }, { GLYPH_CMAP_OFF + S_vwall, GLYPH_CMAP_OFF + S_trwall, "sokoban walls", "In_sokoban(plev)" } }; #ifdef TILETEXT /* * entry is the position of the tile within the monsters/objects/other set */ const char * tilename(set, entry) int set, entry; { int i, j, condnum, tilenum; static char buf[BUFSZ]; /* Note: these initializers don't do anything except guarantee that we're linked properly. */ monst_init(); objects_init(); (void) def_char_to_objclass(']'); condnum = tilenum = 0; for (i = 0; i < NUMMONS; i++) { if (set == MON_GLYPH && tilenum == entry) return mons[i].mname; tilenum++; while (conditionals[condnum].sequence == MON_GLYPH && conditionals[condnum].predecessor == i) { if (set == MON_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } if (set == MON_GLYPH && tilenum == entry) return "invisible monster"; tilenum = 0; /* set-relative number */ for (i = 0; i < NUM_OBJECTS; i++) { /* prefer to give the description - that's all the tile's * appearance should reveal */ if (set == OBJ_GLYPH && tilenum == entry) { if ( !obj_descr[i].oc_descr ) return obj_descr[i].oc_name; if ( !obj_descr[i].oc_name ) return obj_descr[i].oc_descr; Sprintf(buf, "%s / %s", obj_descr[i].oc_descr, obj_descr[i].oc_name); return buf; } tilenum++; while (conditionals[condnum].sequence == OBJ_GLYPH && conditionals[condnum].predecessor == i) { if (set == OBJ_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } tilenum = 0; /* set-relative number */ for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { if (set == OTH_GLYPH && tilenum == entry) { if (*defsyms[i].explanation) return defsyms[i].explanation; else { /* if SINKS are turned off, this * string won't be there (and can't be there * to prevent symbol-identification and * special-level mimic appearances from * thinking the items exist) */ switch (i) { case S_sink: Sprintf(buf, "sink"); break; default: Sprintf(buf, "cmap %d", tilenum); break; } return buf; } } tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == i) { if (set == OTH_GLYPH && tilenum == entry) return conditionals[condnum].name; condnum++; tilenum++; } } /* explosions */ tilenum = MAXPCHARS - MAXEXPCHARS; i = entry - tilenum; if (i < (MAXEXPCHARS * EXPL_MAX)) { if (set == OTH_GLYPH) { static char *explosion_types[] = { /* hack.h */ "dark", "noxious", "muddy", "wet", "magical", "fiery", "frosty" }; Sprintf(buf, "explosion %s %d", explosion_types[i / MAXEXPCHARS], i % MAXEXPCHARS); return buf; } } tilenum += (MAXEXPCHARS * EXPL_MAX); i = entry - tilenum; if (i < (NUM_ZAP << 2)) { if (set == OTH_GLYPH) { Sprintf(buf, "zap %d %d", i/4, i%4); return buf; } } tilenum += (NUM_ZAP << 2); i = entry - tilenum; if (i < WARNCOUNT) { if (set == OTH_GLYPH) { Sprintf(buf, "warning %d", i); return buf; } } tilenum += WARNCOUNT; for (i = 0; i < SIZE(substitutes); i++) { j = entry - tilenum; if (j <= substitutes[i].last_glyph - substitutes[i].first_glyph) { if (set == OTH_GLYPH) { Sprintf(buf, "sub %s %d", substitutes[i].sub_name, j); return buf; } } tilenum += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } Sprintf(buf, "unknown %d %d", set, entry); return buf; } #else /* TILETEXT */ #define TILE_FILE "tile.c" #ifdef AMIGA # define SOURCE_TEMPLATE "NH:src/%s" #else # ifdef MAC # define SOURCE_TEMPLATE ":src:%s" # else # define SOURCE_TEMPLATE "../src/%s" # endif #endif short tilemap[MAX_GLYPH]; int lastmontile, lastobjtile, lastothtile; /* Number of tiles for invisible monsters */ #define NUM_INVIS_TILES 1 /* * set up array to map glyph numbers to tile numbers * * assumes tiles are numbered sequentially through monsters/objects/other, * with entries for all supported compilation options * * "other" contains cmap and zaps (the swallow sets are a repeated portion * of cmap), as well as the "flash" glyphs for the new warning system * introduced in 3.3.1. */ void init_tilemap() { int i, j, condnum, tilenum; int corpsetile, swallowbase; for (i = 0; i < MAX_GLYPH; i++) { tilemap[i] = -1; } corpsetile = NUMMONS + NUM_INVIS_TILES + CORPSE; swallowbase= NUMMONS + NUM_INVIS_TILES + NUM_OBJECTS + S_sw_tl; /* add number compiled out */ for (i = 0; conditionals[i].sequence; i++) { switch (conditionals[i].sequence) { case MON_GLYPH: corpsetile++; swallowbase++; break; case OBJ_GLYPH: if (conditionals[i].predecessor < CORPSE) corpsetile++; swallowbase++; break; case OTH_GLYPH: if (conditionals[i].predecessor < S_sw_tl) swallowbase++; break; } } condnum = tilenum = 0; for (i = 0; i < NUMMONS; i++) { tilemap[GLYPH_MON_OFF+i] = tilenum; tilemap[GLYPH_PET_OFF+i] = tilenum; tilemap[GLYPH_DETECT_OFF+i] = tilenum; tilemap[GLYPH_RIDDEN_OFF+i] = tilenum; tilemap[GLYPH_BODY_OFF+i] = corpsetile; j = GLYPH_SWALLOW_OFF + 8*i; tilemap[j] = swallowbase; tilemap[j+1] = swallowbase+1; tilemap[j+2] = swallowbase+2; tilemap[j+3] = swallowbase+3; tilemap[j+4] = swallowbase+4; tilemap[j+5] = swallowbase+5; tilemap[j+6] = swallowbase+6; tilemap[j+7] = swallowbase+7; tilenum++; while (conditionals[condnum].sequence == MON_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } tilemap[GLYPH_INVISIBLE] = tilenum++; lastmontile = tilenum - 1; for (i = 0; i < NUM_OBJECTS; i++) { tilemap[GLYPH_OBJ_OFF+i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OBJ_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } lastobjtile = tilenum - 1; for (i = 0; i < (MAXPCHARS - MAXEXPCHARS); i++) { tilemap[GLYPH_CMAP_OFF+i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == i) { condnum++; tilenum++; } } for (i = 0; i < (MAXEXPCHARS * EXPL_MAX); i++) { tilemap[GLYPH_EXPLODE_OFF+i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == (i + MAXPCHARS)) { condnum++; tilenum++; } } for (i = 0; i < NUM_ZAP << 2; i++) { tilemap[GLYPH_ZAP_OFF+i] = tilenum; tilenum++; while (conditionals[condnum].sequence == OTH_GLYPH && conditionals[condnum].predecessor == (i + MAXEXPCHARS)) { condnum++; tilenum++; } } for (i = 0; i < WARNCOUNT; i++) { tilemap[GLYPH_WARNING_OFF+i] = tilenum; tilenum++; } lastothtile = tilenum - 1; } const char *prolog[] = { "", "", "void", "substitute_tiles(plev)", "d_level *plev;", "{", "\tint i;", "" }; const char *epilog[] = { "}" }; /* write out the substitutions in an easily-used form. */ void process_substitutions(ofp) FILE *ofp; { int i, j, k, span, start; fprintf(ofp, "\n\n"); j = 0; /* unnecessary */ span = -1; for (i = 0; i < SIZE(substitutes); i++) { if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph || substitutes[i].last_glyph != substitutes[j].last_glyph) { j = i; span++; fprintf(ofp, "short std_tiles%d[] = { ", span); for (k = substitutes[i].first_glyph; k < substitutes[i].last_glyph; k++) fprintf(ofp, "%d, ", tilemap[k]); fprintf(ofp, "%d };\n", tilemap[substitutes[i].last_glyph]); } } for (i = 0; i < SIZE(prolog); i++) { fprintf(ofp, "%s\n", prolog[i]); } j = -1; span = -1; start = lastothtile + 1; for (i = 0; i < SIZE(substitutes); i++) { if (i == 0 || substitutes[i].first_glyph != substitutes[j].first_glyph || substitutes[i].last_glyph != substitutes[j].last_glyph) { if (i != 0) { /* finish previous span */ fprintf(ofp, "\t} else {\n"); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[j].first_glyph, substitutes[j].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", span, substitutes[j].first_glyph); fprintf(ofp, "\t}\n\n"); } j = i; span++; } if (i != j) fprintf(ofp, "\t} else "); fprintf(ofp, "\tif (%s) {\n", substitutes[i].level_test); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[i].first_glyph, substitutes[i].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = %d + i - %d;\n", start, substitutes[i].first_glyph); start += substitutes[i].last_glyph - substitutes[i].first_glyph + 1; } /* finish last span */ fprintf(ofp, "\t} else {\n"); fprintf(ofp, "\t\tfor (i = %d; i <= %d; i++)\n", substitutes[j].first_glyph, substitutes[j].last_glyph); fprintf(ofp, "\t\t\tglyph2tile[i] = std_tiles%d[i - %d];\n", span, substitutes[j].first_glyph); fprintf(ofp, "\t}\n\n"); for (i = 0; i < SIZE(epilog); i++) { fprintf(ofp, "%s\n", epilog[i]); } fprintf(ofp, "\nint total_tiles_used = %d;\n", start); lastothtile = start - 1; } int main() { register int i; char filename[30]; FILE *ofp; init_tilemap(); /* * create the source file, "tile.c" */ Sprintf(filename, SOURCE_TEMPLATE, TILE_FILE); if (!(ofp = fopen(filename, "w"))) { perror(filename); exit(EXIT_FAILURE); } fprintf(ofp,"/* This file is automatically generated. Do not edit. */\n"); fprintf(ofp,"\n#include \"hack.h\"\n\n"); fprintf(ofp,"short glyph2tile[MAX_GLYPH] = {\n"); for (i = 0; i < MAX_GLYPH; i++) { fprintf(ofp,"%2d,%c", tilemap[i], (i % 12) ? ' ' : '\n'); } fprintf(ofp,"%s};\n", (i % 12) ? "\n" : ""); process_substitutions(ofp); fprintf(ofp,"\n#define MAXMONTILE %d\n", lastmontile); fprintf(ofp,"#define MAXOBJTILE %d\n", lastobjtile); fprintf(ofp,"#define MAXOTHTILE %d\n", lastothtile); fprintf(ofp,"\n/*tile.c*/\n"); fclose(ofp); exit(EXIT_SUCCESS); /*NOTREACHED*/ return 0; } #endif /* TILETEXT */ nethack-3.4.3/win/share/tiletext.c0100644000000000000000000001711707764735042015567 0ustar rootroot/* SCCS Id: @(#)tiletext.c 3.4 1999/10/24 */ /* NetHack may be freely redistributed. See license for details. */ #include "config.h" #include "tile.h" pixval ColorMap[3][MAXCOLORMAPSIZE]; int colorsinmap; pixval MainColorMap[3][MAXCOLORMAPSIZE]; int colorsinmainmap; static short color_index[MAXCOLORMAPSIZE]; static int num_colors; static char charcolors[MAXCOLORMAPSIZE]; static int placeholder_init = 0; static pixel placeholder[TILE_Y][TILE_X]; static FILE *tile_file; static int tile_set, tile_set_indx; #if (TILE_X==8) static const char *text_sets[] = { "monthin.txt", "objthin.txt", "oththin.txt" }; #else static const char *text_sets[] = { "monsters.txt", "objects.txt", "other.txt" }; #endif extern const char *FDECL(tilename, (int, int)); static void FDECL(read_text_colormap, (FILE *)); static boolean FDECL(write_text_colormap, (FILE *)); static boolean FDECL(read_txttile, (FILE *, pixel(*)[TILE_X])); static void FDECL(write_txttile, (FILE *, pixel(*)[TILE_X])); /* Ugh. DICE doesn't like %[A-Z], so we have to spell it out... */ #define FORMAT_STRING \ "%[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789] = (%d, %d, %d) " static void read_text_colormap(txtfile) FILE *txtfile; { int i, r, g, b; char c[2]; for (i = 0; i < MAXCOLORMAPSIZE; i++) color_index[i] = -1; num_colors = 0; while (fscanf(txtfile, FORMAT_STRING, c, &r, &g, &b) == 4) { color_index[(int) c[0]] = num_colors; ColorMap[CM_RED][num_colors] = r; ColorMap[CM_GREEN][num_colors] = g; ColorMap[CM_BLUE][num_colors] = b; num_colors++; } colorsinmap = num_colors; } #undef FORMAT_STRING static boolean write_text_colormap(txtfile) FILE *txtfile; { int i; char c; num_colors = colorsinmainmap; if (num_colors > 62) { Fprintf(stderr, "too many colors (%d)\n", num_colors); return FALSE; } for (i = 0; i < num_colors; i++) { if (i < 26) c = 'A' + i; else if (i < 52) c = 'a' + i - 26; else c = '0' + i - 52; charcolors[i] = c; Fprintf(txtfile, "%c = (%d, %d, %d)\n", c, (int)MainColorMap[CM_RED][i], (int)MainColorMap[CM_GREEN][i], (int)MainColorMap[CM_BLUE][i]); } return TRUE; } static boolean read_txttile(txtfile, pixels) FILE *txtfile; pixel (*pixels)[TILE_X]; { int ph, i, j, k; char buf[BUFSZ], ttype[BUFSZ]; const char *p; char c[2]; if (fscanf(txtfile, "# %s %d (%[^)])", ttype, &i, buf) <= 0) return FALSE; ph = strcmp(ttype, "placeholder") == 0; if (!ph && strcmp(ttype,"tile") != 0) Fprintf(stderr, "Keyword \"%s\" unexpected for entry %d\n", ttype, i); if (tile_set != 0) { /* check tile name, but not relative number, which will * change when tiles are added */ p = tilename(tile_set, tile_set_indx); if (p && strcmp(p, buf)) { Fprintf(stderr, "warning: for tile %d (numbered %d) of %s,\n", tile_set_indx, i, text_sets[tile_set-1]); Fprintf(stderr, "\tfound '%s' while expecting '%s'\n", buf, p); } } tile_set_indx++; /* look for non-whitespace at each stage */ if (fscanf(txtfile, "%1s", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } if (c[0] != '{') { Fprintf(stderr, "didn't find expected '{'\n"); return FALSE; } for (j = 0; j < TILE_Y; j++) { for (i = 0; i < TILE_X; i++) { if (fscanf(txtfile, "%1s", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } k = color_index[(int) c[0]]; if (k == -1) Fprintf(stderr, "color %c not in colormap!\n", c[0]); else { pixels[j][i].r = ColorMap[CM_RED][k]; pixels[j][i].g = ColorMap[CM_GREEN][k]; pixels[j][i].b = ColorMap[CM_BLUE][k]; } } } if ( ph ) { /* remember it for later */ memcpy( placeholder, pixels, sizeof(placeholder) ); } if (fscanf(txtfile, "%1s ", c) < 0) { Fprintf(stderr, "unexpected EOF\n"); return FALSE; } if (c[0] != '}') { Fprintf(stderr, "didn't find expected '}'\n"); return FALSE; } #ifdef _DCC /* DICE again... it doesn't seem to eat whitespace after the } like * it should, so we have to do so manually. */ while ((*c = fgetc(txtfile)) != EOF && isspace(*c)) ; ungetc(*c, txtfile); #endif return TRUE; } static void write_txttile(txtfile, pixels) FILE *txtfile; pixel (*pixels)[TILE_X]; { const char *p; const char *type; int i, j, k; if ( memcmp(placeholder, pixels, sizeof(placeholder)) == 0 ) type = "placeholder"; else type = "tile"; if (tile_set == 0) Fprintf(txtfile, "# %s %d (unknown)\n", type, tile_set_indx); else { p = tilename(tile_set, tile_set_indx); if (p) Fprintf(txtfile, "# %s %d (%s)\n", type, tile_set_indx, p); else Fprintf(txtfile, "# %s %d (null)\n", type, tile_set_indx); } tile_set_indx++; Fprintf(txtfile, "{\n"); for (j = 0; j < TILE_Y; j++) { Fprintf(txtfile, " "); for (i = 0; i < TILE_X; i++) { for (k = 0; k < num_colors; k++) { if (ColorMap[CM_RED][k] == pixels[j][i].r && ColorMap[CM_GREEN][k] == pixels[j][i].g && ColorMap[CM_BLUE][k] == pixels[j][i].b) break; } if (k >= num_colors) Fprintf(stderr, "color not in colormap!\n"); (void) fputc(charcolors[k], txtfile); } Fprintf(txtfile, "\n"); } Fprintf(txtfile, "}\n"); } /* initialize main colormap from globally accessed ColorMap */ void init_colormap() { int i; colorsinmainmap = colorsinmap; for (i = 0; i < colorsinmap; i++) { MainColorMap[CM_RED][i] = ColorMap[CM_RED][i]; MainColorMap[CM_GREEN][i] = ColorMap[CM_GREEN][i]; MainColorMap[CM_BLUE][i] = ColorMap[CM_BLUE][i]; } } /* merge new colors from ColorMap into MainColorMap */ void merge_colormap() { int i, j; for (i = 0; i < colorsinmap; i++) { for (j = 0; j < colorsinmainmap; j++) { if (MainColorMap[CM_RED][j] == ColorMap[CM_RED][i] && MainColorMap[CM_GREEN][j] == ColorMap[CM_GREEN][i] && MainColorMap[CM_BLUE][j] == ColorMap[CM_BLUE][i]) break; } if (j >= colorsinmainmap) { /* new color */ if (colorsinmainmap >= MAXCOLORMAPSIZE) { Fprintf(stderr, "Too many colors to merge -- excess ignored.\n"); } j = colorsinmainmap; MainColorMap[CM_RED][j] = ColorMap[CM_RED][i]; MainColorMap[CM_GREEN][j] = ColorMap[CM_GREEN][i]; MainColorMap[CM_BLUE][j] = ColorMap[CM_BLUE][i]; colorsinmainmap++; } } } boolean fopen_text_file(filename, type) const char *filename; const char *type; { const char *p; int i; if (tile_file != (FILE *)0) { Fprintf(stderr, "can only open one text file at at time\n"); return FALSE; } tile_file = fopen(filename, type); if (tile_file == (FILE *)0) { Fprintf(stderr, "cannot open text file %s\n", filename); return FALSE; } p = rindex(filename, '/'); if (p) p++; else p = filename; tile_set = 0; for (i = 0; i < SIZE(text_sets); i++) { if (!strcmp(p, text_sets[i])) tile_set = i+1; } tile_set_indx = 0; if (!strcmp(type, RDTMODE)) { /* Fill placeholder with noise */ if ( !placeholder_init ) { placeholder_init++; for ( i=0; itoplin == 1 && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; ttyDisplay->toplin = 3; /* special prompt state */ ttyDisplay->inread++; pline("%s ", query); *obufp = 0; for(;;) { (void) fflush(stdout); Sprintf(toplines, "%s ", query); Strcat(toplines, obufp); if((c = Getchar()) == EOF) { #ifndef NEWAUTOCOMP *bufp = 0; #endif /* not NEWAUTOCOMP */ break; } if(c == '\033') { *obufp = c; obufp[1] = 0; break; } if (ttyDisplay->intr) { ttyDisplay->intr--; *bufp = 0; } if(c == '\020') { /* ctrl-P */ if (iflags.prevmsg_window != 's') { int sav = ttyDisplay->inread; ttyDisplay->inread = 0; (void) tty_doprev_message(); ttyDisplay->inread = sav; tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; addtopl(query); addtopl(" "); *bufp = 0; addtopl(obufp); } else { if (!doprev) (void) tty_doprev_message();/* need two initially */ (void) tty_doprev_message(); doprev = 1; continue; } } else if (doprev && iflags.prevmsg_window == 's') { tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; doprev = 0; addtopl(query); addtopl(" "); *bufp = 0; addtopl(obufp); } if(c == erase_char || c == '\b') { if(bufp != obufp) { #ifdef NEWAUTOCOMP char *i; #endif /* NEWAUTOCOMP */ bufp--; #ifndef NEWAUTOCOMP putsyms("\b \b");/* putsym converts \b */ #else /* NEWAUTOCOMP */ putsyms("\b"); for (i = bufp; *i; ++i) putsyms(" "); for (; i > bufp; --i) putsyms("\b"); *bufp = 0; #endif /* NEWAUTOCOMP */ } else tty_nhbell(); #if defined(apollo) } else if(c == '\n' || c == '\r') { #else } else if(c == '\n') { #endif #ifndef NEWAUTOCOMP *bufp = 0; #endif /* not NEWAUTOCOMP */ break; } else if(' ' <= (unsigned char) c && c != '\177' && (bufp-obufp < BUFSZ-1 && bufp-obufp < COLNO)) { /* avoid isprint() - some people don't have it ' ' is not always a printing char */ #ifdef NEWAUTOCOMP char *i = eos(bufp); #endif /* NEWAUTOCOMP */ *bufp = c; bufp[1] = 0; putsyms(bufp); bufp++; if (hook && (*hook)(obufp)) { putsyms(bufp); #ifndef NEWAUTOCOMP bufp = eos(bufp); #else /* NEWAUTOCOMP */ /* pointer and cursor left where they were */ for (i = bufp; *i; ++i) putsyms("\b"); } else if (i > bufp) { char *s = i; /* erase rest of prior guess */ for (; i > bufp; --i) putsyms(" "); for (; s > bufp; --s) putsyms("\b"); #endif /* NEWAUTOCOMP */ } } else if(c == kill_char || c == '\177') { /* Robert Viduya */ /* this test last - @ might be the kill_char */ #ifndef NEWAUTOCOMP while(bufp != obufp) { bufp--; putsyms("\b \b"); } #else /* NEWAUTOCOMP */ for (; *bufp; ++bufp) putsyms(" "); for (; bufp != obufp; --bufp) putsyms("\b \b"); *bufp = 0; #endif /* NEWAUTOCOMP */ } else tty_nhbell(); } ttyDisplay->toplin = 2; /* nonempty, no --More-- required */ ttyDisplay->inread--; clear_nhwindow(WIN_MESSAGE); /* clean up after ourselves */ } void xwaitforspace(s) register const char *s; /* chars allowed besides return */ { register int c, x = ttyDisplay ? (int) ttyDisplay->dismiss_more : '\n'; morc = 0; while((c = tty_nhgetch()) != '\n') { if(iflags.cbreak) { if ((s && index(s,c)) || c == x) { morc = (char) c; break; } tty_nhbell(); } } } #endif /* OVL1 */ #ifdef OVL2 /* * Implement extended command completion by using this hook into * tty_getlin. Check the characters already typed, if they uniquely * identify an extended command, expand the string to the whole * command. * * Return TRUE if we've extended the string at base. Otherwise return FALSE. * Assumptions: * * + we don't change the characters that are already in base * + base has enough room to hold our string */ STATIC_OVL boolean ext_cmd_getlin_hook(base) char *base; { int oindex, com_index; com_index = -1; for (oindex = 0; extcmdlist[oindex].ef_txt != (char *)0; oindex++) { if (!strncmpi(base, extcmdlist[oindex].ef_txt, strlen(base))) { if (com_index == -1) /* no matches yet */ com_index = oindex; else /* more than 1 match */ return FALSE; } } if (com_index >= 0) { Strcpy(base, extcmdlist[com_index].ef_txt); return TRUE; } return FALSE; /* didn't match anything */ } /* * Read in an extended command, doing command line completion. We * stop when we have found enough characters to make a unique command. */ int tty_get_ext_cmd() { int i; char buf[BUFSZ]; if (iflags.extmenu) return extcmd_via_menu(); /* maybe a runtime option? */ /* hooked_tty_getlin("#", buf, flags.cmd_comp ? ext_cmd_getlin_hook : (getlin_hook_proc) 0); */ #ifdef REDO hooked_tty_getlin("#", buf, in_doagain ? (getlin_hook_proc)0 : ext_cmd_getlin_hook); #else hooked_tty_getlin("#", buf, ext_cmd_getlin_hook); #endif (void) mungspaces(buf); if (buf[0] == 0 || buf[0] == '\033') return -1; for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++) if (!strcmpi(buf, extcmdlist[i].ef_txt)) break; #ifdef REDO if (!in_doagain) { int j; for (j = 0; buf[j]; j++) savech(buf[j]); savech('\n'); } #endif if (extcmdlist[i].ef_txt == (char *)0) { pline("%s: unknown extended command.", buf); i = -1; } return i; } #endif /* OVL2 */ #endif /* TTY_GRAPHICS */ /*getline.c*/ nethack-3.4.3/win/tty/termcap.c0100644000000000000000000006433107764735042015076 0ustar rootroot/* SCCS Id: @(#)termcap.c 3.4 2000/07/10 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #if defined (TTY_GRAPHICS) && !defined(NO_TERMS) #include "wintty.h" #include "tcap.h" #ifdef MICROPORT_286_BUG #define Tgetstr(key) (tgetstr(key,tbuf)) #else #define Tgetstr(key) (tgetstr(key,&tbufptr)) #endif /* MICROPORT_286_BUG **/ static char * FDECL(s_atr2str, (int)); static char * FDECL(e_atr2str, (int)); void FDECL(cmov, (int, int)); void FDECL(nocmov, (int, int)); #if defined(TEXTCOLOR) && defined(TERMLIB) # ifdef OVLB # if !defined(UNIX) || !defined(TERMINFO) # ifndef TOS static void FDECL(analyze_seq, (char *, int *, int *)); # endif # endif static void NDECL(init_hilite); static void NDECL(kill_hilite); # endif /* OVLB */ #endif #ifdef OVLB /* (see tcap.h) -- nh_CM, nh_ND, nh_CD, nh_HI,nh_HE, nh_US,nh_UE, ul_hack */ struct tc_lcl_data tc_lcl_data = { 0, 0, 0, 0,0, 0,0, FALSE }; #endif /* OVLB */ STATIC_VAR char *HO, *CL, *CE, *UP, *XD, *BC, *SO, *SE, *TI, *TE; STATIC_VAR char *VS, *VE; STATIC_VAR char *ME; STATIC_VAR char *MR; #if 0 STATIC_VAR char *MB, *MH; STATIC_VAR char *MD; /* may already be in use below */ #endif #ifdef TERMLIB # ifdef TEXTCOLOR STATIC_VAR char *MD; # endif STATIC_VAR int SG; #ifdef OVLB STATIC_OVL char PC = '\0'; #else /* OVLB */ STATIC_DCL char PC; #endif /* OVLB */ STATIC_VAR char tbuf[512]; #endif #ifdef TEXTCOLOR # ifdef TOS const char *hilites[CLR_MAX]; /* terminal escapes for the various colors */ # else char NEARDATA *hilites[CLR_MAX]; /* terminal escapes for the various colors */ # endif #endif #ifdef OVLB static char *KS = (char *)0, *KE = (char *)0; /* keypad sequences */ static char nullstr[] = ""; #endif /* OVLB */ #if defined(ASCIIGRAPH) && !defined(NO_TERMS) extern boolean HE_resets_AS; #endif #ifndef TERMLIB STATIC_VAR char tgotobuf[20]; # ifdef TOS #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y+' ', x+' '), tgotobuf) # else #define tgoto(fmt, x, y) (Sprintf(tgotobuf, fmt, y+1, x+1), tgotobuf) # endif #endif /* TERMLIB */ #ifdef OVLB void tty_startup(wid, hgt) int *wid, *hgt; { register int i; #ifdef TERMLIB register const char *term; register char *tptr; char *tbufptr, *pc; # ifdef VMS term = verify_termcap(); if (!term) # endif term = getenv("TERM"); # if defined(TOS) && defined(__GNUC__) if (!term) term = "builtin"; /* library has a default */ # endif if (!term) #endif #ifndef ANSI_DEFAULT error("Can't get TERM."); #else # ifdef TOS { CO = 80; LI = 25; TI = VS = VE = TE = nullstr; HO = "\033H"; CE = "\033K"; /* the VT52 termcap */ UP = "\033A"; nh_CM = "\033Y%c%c"; /* used with function tgoto() */ nh_ND = "\033C"; XD = "\033B"; BC = "\033D"; SO = "\033p"; SE = "\033q"; /* HI and HE will be updated in init_hilite if we're using color */ nh_HI = "\033p"; nh_HE = "\033q"; *wid = CO; *hgt = LI; CL = "\033E"; /* last thing set */ return; } # else /* TOS */ { # ifdef MICRO get_scr_size(); # ifdef CLIPPING if(CO < COLNO || LI < ROWNO+3) setclipped(); # endif # endif HO = "\033[H"; /* nh_CD = "\033[J"; */ CE = "\033[K"; /* the ANSI termcap */ # ifndef TERMLIB nh_CM = "\033[%d;%dH"; # else nh_CM = "\033[%i%d;%dH"; # endif UP = "\033[A"; nh_ND = "\033[C"; XD = "\033[B"; # ifdef MICRO /* backspaces are non-destructive */ BC = "\b"; # else BC = "\033[D"; # endif nh_HI = SO = "\033[1m"; nh_US = "\033[4m"; MR = "\033[7m"; TI = nh_HE = ME = SE = nh_UE = "\033[0m"; /* strictly, SE should be 2, and nh_UE should be 24, but we can't trust all ANSI emulators to be that complete. -3. */ # ifndef MICRO AS = "\016"; AE = "\017"; # endif TE = VS = VE = nullstr; # ifdef TEXTCOLOR for (i = 0; i < CLR_MAX / 2; i++) if (i != CLR_BLACK) { hilites[i|BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm")); Sprintf(hilites[i|BRIGHT], "\033[1;3%dm", i); if (i != CLR_GRAY) # ifdef MICRO if (i == CLR_BLUE) hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT]; else # endif { hilites[i] = (char *) alloc(sizeof("\033[0;3%dm")); Sprintf(hilites[i], "\033[0;3%dm", i); } } # endif *wid = CO; *hgt = LI; CL = "\033[2J"; /* last thing set */ return; } # endif /* TOS */ #endif /* ANSI_DEFAULT */ #ifdef TERMLIB tptr = (char *) alloc(1024); tbufptr = tbuf; if(!strncmp(term, "5620", 4)) flags.null = FALSE; /* this should be a termcap flag */ if(tgetent(tptr, term) < 1) { char buf[BUFSZ]; (void) strncpy(buf, term, (BUFSZ - 1) - (sizeof("Unknown terminal type: . "))); buf[BUFSZ-1] = '\0'; error("Unknown terminal type: %s.", term); } if ((pc = Tgetstr("pc")) != 0) PC = *pc; if(!(BC = Tgetstr("le"))) /* both termcap and terminfo use le */ # ifdef TERMINFO error("Terminal must backspace."); # else if(!(BC = Tgetstr("bc"))) { /* termcap also uses bc/bs */ # ifndef MINIMAL_TERM if(!tgetflag("bs")) error("Terminal must backspace."); # endif BC = tbufptr; tbufptr += 2; *BC = '\b'; } # endif # ifdef MINIMAL_TERM HO = (char *)0; # else HO = Tgetstr("ho"); # endif /* * LI and CO are set in ioctl.c via a TIOCGWINSZ if available. If * the kernel has values for either we should use them rather than * the values from TERMCAP ... */ # ifndef MICRO if (!CO) CO = tgetnum("co"); if (!LI) LI = tgetnum("li"); # else # if defined(TOS) && defined(__GNUC__) if (!strcmp(term, "builtin")) get_scr_size(); else { # endif CO = tgetnum("co"); LI = tgetnum("li"); if (!LI || !CO) /* if we don't override it */ get_scr_size(); # if defined(TOS) && defined(__GNUC__) } # endif # endif # ifdef CLIPPING if(CO < COLNO || LI < ROWNO+3) setclipped(); # endif nh_ND = Tgetstr("nd"); if(tgetflag("os")) error("NetHack can't have OS."); if(tgetflag("ul")) ul_hack = TRUE; CE = Tgetstr("ce"); UP = Tgetstr("up"); /* It seems that xd is no longer supported, and we should use a linefeed instead; unfortunately this requires resetting CRMOD, and many output routines will have to be modified slightly. Let's leave that till the next release. */ XD = Tgetstr("xd"); /* not: XD = Tgetstr("do"); */ if(!(nh_CM = Tgetstr("cm"))) { if(!UP && !HO) error("NetHack needs CM or UP or HO."); tty_raw_print("Playing NetHack on terminals without CM is suspect."); tty_wait_synch(); } SO = Tgetstr("so"); SE = Tgetstr("se"); nh_US = Tgetstr("us"); nh_UE = Tgetstr("ue"); SG = tgetnum("sg"); /* -1: not fnd; else # of spaces left by so */ if(!SO || !SE || (SG > 0)) SO = SE = nh_US = nh_UE = nullstr; TI = Tgetstr("ti"); TE = Tgetstr("te"); VS = VE = nullstr; # ifdef TERMINFO VS = Tgetstr("eA"); /* enable graphics */ # endif KS = Tgetstr("ks"); /* keypad start (special mode) */ KE = Tgetstr("ke"); /* keypad end (ordinary mode [ie, digits]) */ MR = Tgetstr("mr"); /* reverse */ # if 0 MB = Tgetstr("mb"); /* blink */ MD = Tgetstr("md"); /* boldface */ MH = Tgetstr("mh"); /* dim */ # endif ME = Tgetstr("me"); /* turn off all attributes */ if (!ME || (SE == nullstr)) ME = SE; /* default to SE value */ /* Get rid of padding numbers for nh_HI and nh_HE. Hope they * aren't really needed!!! nh_HI and nh_HE are outputted to the * pager as a string - so how can you send it NULs??? * -jsb */ nh_HI = (char *) alloc((unsigned)(strlen(SO)+1)); nh_HE = (char *) alloc((unsigned)(strlen(ME)+1)); i = 0; while (digit(SO[i])) i++; Strcpy(nh_HI, &SO[i]); i = 0; while (digit(ME[i])) i++; Strcpy(nh_HE, &ME[i]); AS = Tgetstr("as"); AE = Tgetstr("ae"); nh_CD = Tgetstr("cd"); # ifdef TEXTCOLOR MD = Tgetstr("md"); # endif # ifdef TEXTCOLOR # if defined(TOS) && defined(__GNUC__) if (!strcmp(term, "builtin") || !strcmp(term, "tw52") || !strcmp(term, "st52")) { init_hilite(); } # else init_hilite(); # endif # endif *wid = CO; *hgt = LI; if (!(CL = Tgetstr("cl"))) /* last thing set */ error("NetHack needs CL."); if ((int)(tbufptr - tbuf) > (int)(sizeof tbuf)) error("TERMCAP entry too big...\n"); free((genericptr_t)tptr); #endif /* TERMLIB */ } /* note: at present, this routine is not part of the formal window interface */ /* deallocate resources prior to final termination */ void tty_shutdown() { #if defined(TEXTCOLOR) && defined(TERMLIB) kill_hilite(); #endif /* we don't attempt to clean up individual termcap variables [yet?] */ return; } void tty_number_pad(state) int state; { switch (state) { case -1: /* activate keypad mode (escape sequences) */ if (KS && *KS) xputs(KS); break; case 1: /* activate numeric mode for keypad (digits) */ if (KE && *KE) xputs(KE); break; case 0: /* don't need to do anything--leave terminal as-is */ default: break; } } #ifdef TERMLIB extern void NDECL((*decgraphics_mode_callback)); /* defined in drawing.c */ static void NDECL(tty_decgraphics_termcap_fixup); /* We call this routine whenever DECgraphics mode is enabled, even if it has been previously set, in case the user manages to reset the fonts. The actual termcap fixup only needs to be done once, but we can't call xputs() from the option setting or graphics assigning routines, so this is a convenient hook. */ static void tty_decgraphics_termcap_fixup() { static char ctrlN[] = "\016"; static char ctrlO[] = "\017"; static char appMode[] = "\033="; static char numMode[] = "\033>"; /* these values are missing from some termcaps */ if (!AS) AS = ctrlN; /* ^N (shift-out [graphics font]) */ if (!AE) AE = ctrlO; /* ^O (shift-in [regular font]) */ if (!KS) KS = appMode; /* ESC= (application keypad mode) */ if (!KE) KE = numMode; /* ESC> (numeric keypad mode) */ /* * Select the line-drawing character set as the alternate font. * Do not select NA ASCII as the primary font since people may * reasonably be using the UK character set. */ if (iflags.DECgraphics) xputs("\033)0"); #ifdef PC9800 init_hilite(); #endif #if defined(ASCIIGRAPH) && !defined(NO_TERMS) /* some termcaps suffer from the bizarre notion that resetting video attributes should also reset the chosen character set */ { const char *nh_he = nh_HE, *ae = AE; int he_limit, ae_length; if (digit(*ae)) { /* skip over delay prefix, if any */ do ++ae; while (digit(*ae)); if (*ae == '.') { ++ae; if (digit(*ae)) ++ae; } if (*ae == '*') ++ae; } /* can't use nethack's case-insensitive strstri() here, and some old systems don't have strstr(), so use brute force substring search */ ae_length = strlen(ae), he_limit = strlen(nh_he); while (he_limit >= ae_length) { if (strncmp(nh_he, ae, ae_length) == 0) { HE_resets_AS = TRUE; break; } ++nh_he, --he_limit; } } #endif } #endif /* TERMLIB */ #if defined(ASCIIGRAPH) && defined(PC9800) extern void NDECL((*ibmgraphics_mode_callback)); /* defined in drawing.c */ #endif #ifdef PC9800 extern void NDECL((*ascgraphics_mode_callback)); /* defined in drawing.c */ static void NDECL(tty_ascgraphics_hilite_fixup); static void tty_ascgraphics_hilite_fixup() { register int c; for (c = 0; c < CLR_MAX / 2; c++) if (c != CLR_BLACK) { hilites[c|BRIGHT] = (char *) alloc(sizeof("\033[1;3%dm")); Sprintf(hilites[c|BRIGHT], "\033[1;3%dm", c); if (c != CLR_GRAY) { hilites[c] = (char *) alloc(sizeof("\033[0;3%dm")); Sprintf(hilites[c], "\033[0;3%dm", c); } } } #endif /* PC9800 */ void tty_start_screen() { xputs(TI); xputs(VS); #ifdef PC9800 if (!iflags.IBMgraphics && !iflags.DECgraphics) tty_ascgraphics_hilite_fixup(); /* set up callback in case option is not set yet but toggled later */ ascgraphics_mode_callback = tty_ascgraphics_hilite_fixup; # ifdef ASCIIGRAPH if (iflags.IBMgraphics) init_hilite(); /* set up callback in case option is not set yet but toggled later */ ibmgraphics_mode_callback = init_hilite; # endif #endif /* PC9800 */ #ifdef TERMLIB if (iflags.DECgraphics) tty_decgraphics_termcap_fixup(); /* set up callback in case option is not set yet but toggled later */ decgraphics_mode_callback = tty_decgraphics_termcap_fixup; #endif if (iflags.num_pad) tty_number_pad(1); /* make keypad send digits */ } void tty_end_screen() { clear_screen(); xputs(VE); xputs(TE); } /* Cursor movements */ #endif /* OVLB */ #ifdef OVL0 /* Note to OVLx tinkerers. The placement of this overlay controls the location of the function xputc(). This function is not currently in trampoli.[ch] files for what is deemed to be performance reasons. If this define is moved and or xputc() is taken out of the ROOT overlay, then action must be taken in trampoli.[ch]. */ void nocmov(x, y) int x,y; { if ((int) ttyDisplay->cury > y) { if(UP) { while ((int) ttyDisplay->cury > y) { /* Go up. */ xputs(UP); ttyDisplay->cury--; } } else if(nh_CM) { cmov(x, y); } else if(HO) { home(); tty_curs(BASE_WINDOW, x+1, y); } /* else impossible("..."); */ } else if ((int) ttyDisplay->cury < y) { if(XD) { while((int) ttyDisplay->cury < y) { xputs(XD); ttyDisplay->cury++; } } else if(nh_CM) { cmov(x, y); } else { while((int) ttyDisplay->cury < y) { xputc('\n'); ttyDisplay->curx = 0; ttyDisplay->cury++; } } } if ((int) ttyDisplay->curx < x) { /* Go to the right. */ if(!nh_ND) cmov(x, y); else /* bah */ /* should instead print what is there already */ while ((int) ttyDisplay->curx < x) { xputs(nh_ND); ttyDisplay->curx++; } } else if ((int) ttyDisplay->curx > x) { while ((int) ttyDisplay->curx > x) { /* Go to the left. */ xputs(BC); ttyDisplay->curx--; } } } void cmov(x, y) register int x, y; { xputs(tgoto(nh_CM, x, y)); ttyDisplay->cury = y; ttyDisplay->curx = x; } /* See note at OVLx ifdef above. xputc() is a special function. */ void xputc(c) #if defined(apollo) int c; #else char c; #endif { (void) putchar(c); } void xputs(s) const char *s; { # ifndef TERMLIB (void) fputs(s, stdout); # else # if defined(NHSTDC) || defined(ULTRIX_PROTO) tputs(s, 1, (int (*)())xputc); # else tputs(s, 1, xputc); # endif # endif } void cl_end() { if(CE) xputs(CE); else { /* no-CE fix - free after Harold Rynes */ /* this looks terrible, especially on a slow terminal but is better than nothing */ register int cx = ttyDisplay->curx+1; while(cx < CO) { xputc(' '); cx++; } tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury); } } #endif /* OVL0 */ #ifdef OVLB void clear_screen() { /* note: if CL is null, then termcap initialization failed, so don't attempt screen-oriented I/O during final cleanup. */ if (CL) { xputs(CL); home(); } } #endif /* OVLB */ #ifdef OVL0 void home() { if(HO) xputs(HO); else if(nh_CM) xputs(tgoto(nh_CM, 0, 0)); else tty_curs(BASE_WINDOW, 1, 0); /* using UP ... */ ttyDisplay->curx = ttyDisplay->cury = 0; } void standoutbeg() { if(SO) xputs(SO); } void standoutend() { if(SE) xputs(SE); } #if 0 /* if you need one of these, uncomment it (here and in extern.h) */ void revbeg() { if(MR) xputs(MR); } void boldbeg() { if(MD) xputs(MD); } void blinkbeg() { if(MB) xputs(MB); } void dimbeg() /* not in most termcap entries */ { if(MH) xputs(MH); } void m_end() { if(ME) xputs(ME); } #endif #endif /* OVL0 */ #ifdef OVLB void backsp() { xputs(BC); } void tty_nhbell() { if (flags.silent) return; (void) putchar('\007'); /* curx does not change */ (void) fflush(stdout); } #endif /* OVLB */ #ifdef OVL0 #ifdef ASCIIGRAPH void graph_on() { if (AS) xputs(AS); } void graph_off() { if (AE) xputs(AE); } #endif #endif /* OVL0 */ #ifdef OVL1 #if !defined(MICRO) # ifdef VMS static const short tmspc10[] = { /* from termcap */ 0, 2000, 1333, 909, 743, 666, 333, 166, 83, 55, 50, 41, 27, 20, 13, 10, 5 }; # else static const short tmspc10[] = { /* from termcap */ 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5 }; # endif #endif /* delay 50 ms */ void tty_delay_output() { #if defined(MICRO) register int i; #endif #ifdef TIMED_DELAY if (flags.nap) { (void) fflush(stdout); msleep(50); /* sleep for 50 milliseconds */ return; } #endif #if defined(MICRO) /* simulate the delay with "cursor here" */ for (i = 0; i < 3; i++) { cmov(ttyDisplay->curx, ttyDisplay->cury); (void) fflush(stdout); } #else /* MICRO */ /* BUG: if the padding character is visible, as it is on the 5620 then this looks terrible. */ if(flags.null) # ifdef TERMINFO /* cbosgd!cbcephus!pds for SYS V R2 */ # ifdef NHSTDC tputs("$<50>", 1, (int (*)())xputc); # else tputs("$<50>", 1, xputc); # endif # else # if defined(NHSTDC) || defined(ULTRIX_PROTO) tputs("50", 1, (int (*)())xputc); # else tputs("50", 1, xputc); # endif # endif else if(ospeed > 0 && ospeed < SIZE(tmspc10) && nh_CM) { /* delay by sending cm(here) an appropriate number of times */ register int cmlen = strlen(tgoto(nh_CM, ttyDisplay->curx, ttyDisplay->cury)); register int i = 500 + tmspc10[ospeed]/2; while(i > 0) { cmov((int)ttyDisplay->curx, (int)ttyDisplay->cury); i -= cmlen*tmspc10[ospeed]; } } #endif /* MICRO */ } #endif /* OVL1 */ #ifdef OVLB void cl_eos() /* free after Robert Viduya */ { /* must only be called with curx = 1 */ if(nh_CD) xputs(nh_CD); else { register int cy = ttyDisplay->cury+1; while(cy <= LI-2) { cl_end(); xputc('\n'); cy++; } cl_end(); tty_curs(BASE_WINDOW, (int)ttyDisplay->curx+1, (int)ttyDisplay->cury); } } #if defined(TEXTCOLOR) && defined(TERMLIB) # if defined(UNIX) && defined(TERMINFO) /* * Sets up color highlighting, using terminfo(4) escape sequences. * * Having never seen a terminfo system without curses, we assume this * inclusion is safe. On systems with color terminfo, it should define * the 8 COLOR_FOOs, and avoid us having to guess whether this particular * terminfo uses BGR or RGB for its indexes. * * If we don't get the definitions, then guess. Original color terminfos * used BGR for the original Sf (setf, Standard foreground) codes, but * there was a near-total lack of user documentation, so some subsequent * terminfos, such as early Linux ncurses and SCO UNIX, used RGB. Possibly * as a result of the confusion, AF (setaf, ANSI Foreground) codes were * introduced, but this caused yet more confusion. Later Linux ncurses * have BGR Sf, RGB AF, and RGB COLOR_FOO, which appears to be the SVR4 * standard. We could switch the colors around when using Sf with ncurses, * which would help things on later ncurses and hurt things on early ncurses. * We'll try just preferring AF and hoping it always agrees with COLOR_FOO, * and falling back to Sf if AF isn't defined. * * In any case, treat black specially so we don't try to display black * characters on the assumed black background. */ /* `curses' is aptly named; various versions don't like these macros used elsewhere within nethack; fortunately they're not needed beyond this point, so we don't need to worry about reconstructing them after the header file inclusion. */ #undef delay_output #undef TRUE #undef FALSE #define m_move curses_m_move /* Some curses.h decl m_move(), not used here */ #include #ifndef LINUX extern char *tparm(); #endif # ifdef COLOR_BLACK /* trust include file */ #undef COLOR_BLACK # else # ifndef _M_UNIX /* guess BGR */ #define COLOR_BLUE 1 #define COLOR_GREEN 2 #define COLOR_CYAN 3 #define COLOR_RED 4 #define COLOR_MAGENTA 5 #define COLOR_YELLOW 6 #define COLOR_WHITE 7 # else /* guess RGB */ #define COLOR_RED 1 #define COLOR_GREEN 2 #define COLOR_YELLOW 3 #define COLOR_BLUE 4 #define COLOR_MAGENTA 5 #define COLOR_CYAN 6 #define COLOR_WHITE 7 # endif # endif #define COLOR_BLACK COLOR_BLUE const int ti_map[8] = { COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE }; static void init_hilite() { register int c; char *setf, *scratch; for (c = 0; c < SIZE(hilites); c++) hilites[c] = nh_HI; hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0; if (tgetnum("Co") < 8 || ((setf = tgetstr("AF", (char **)0)) == (char *)0 && (setf = tgetstr("Sf", (char **)0)) == (char *)0)) return; for (c = 0; c < CLR_MAX / 2; c++) { scratch = tparm(setf, ti_map[c]); if (c != CLR_GRAY) { hilites[c] = (char *) alloc(strlen(scratch) + 1); Strcpy(hilites[c], scratch); } if (c != CLR_BLACK) { hilites[c|BRIGHT] = (char*) alloc(strlen(scratch)+strlen(MD)+1); Strcpy(hilites[c|BRIGHT], MD); Strcat(hilites[c|BRIGHT], scratch); } } } # else /* UNIX && TERMINFO */ # ifndef TOS /* find the foreground and background colors set by nh_HI or nh_HE */ static void analyze_seq (str, fg, bg) char *str; int *fg, *bg; { register int c, code; int len; # ifdef MICRO *fg = CLR_GRAY; *bg = CLR_BLACK; # else *fg = *bg = NO_COLOR; # endif c = (str[0] == '\233') ? 1 : 2; /* index of char beyond esc prefix */ len = strlen(str) - 1; /* length excluding attrib suffix */ if ((c != 1 && (str[0] != '\033' || str[1] != '[')) || (len - c) < 1 || str[len] != 'm') return; while (c < len) { if ((code = atoi(&str[c])) == 0) { /* reset */ /* this also catches errors */ # ifdef MICRO *fg = CLR_GRAY; *bg = CLR_BLACK; # else *fg = *bg = NO_COLOR; # endif } else if (code == 1) { /* bold */ *fg |= BRIGHT; # if 0 /* I doubt we'll ever resort to using blinking characters, unless we want a pulsing glow for something. But, in case we do... - 3. */ } else if (code == 5) { /* blinking */ *fg |= BLINK; } else if (code == 25) { /* stop blinking */ *fg &= ~BLINK; # endif } else if (code == 7 || code == 27) { /* reverse */ code = *fg & ~BRIGHT; *fg = *bg | (*fg & BRIGHT); *bg = code; } else if (code >= 30 && code <= 37) { /* hi_foreground RGB */ *fg = code - 30; } else if (code >= 40 && code <= 47) { /* hi_background RGB */ *bg = code - 40; } while (digit(str[++c])); c++; } } # endif /* * Sets up highlighting sequences, using ANSI escape sequences (highlight code * found in print.c). The nh_HI and nh_HE sequences (usually from SO) are * scanned to find foreground and background colors. */ static void init_hilite() { register int c; # ifdef TOS extern unsigned long tos_numcolors; /* in tos.c */ static char NOCOL[] = "\033b0", COLHE[] = "\033q\033b0"; if (tos_numcolors <= 2) { return; } /* Under TOS, the "bright" and "dim" colors are reversed. Moreover, * on the Falcon the dim colors are *really* dim; so we make most * of the colors the bright versions, with a few exceptions where * the dim ones look OK. */ hilites[0] = NOCOL; for (c = 1; c < SIZE(hilites); c++) { char *foo; foo = (char *) alloc(sizeof("\033b0")); if (tos_numcolors > 4) Sprintf(foo, "\033b%c", (c&~BRIGHT)+'0'); else Strcpy(foo, "\033b0"); hilites[c] = foo; } if (tos_numcolors == 4) { TI = "\033b0\033c3\033E\033e"; TE = "\033b3\033c0\033J"; nh_HE = COLHE; hilites[CLR_GREEN] = hilites[CLR_GREEN|BRIGHT] = "\033b2"; hilites[CLR_RED] = hilites[CLR_RED|BRIGHT] = "\033b1"; } else { sprintf(hilites[CLR_BROWN], "\033b%c", (CLR_BROWN^BRIGHT)+'0'); sprintf(hilites[CLR_GREEN], "\033b%c", (CLR_GREEN^BRIGHT)+'0'); TI = "\033b0\033c\017\033E\033e"; TE = "\033b\017\033c0\033J"; nh_HE = COLHE; hilites[CLR_WHITE] = hilites[CLR_BLACK] = NOCOL; hilites[NO_COLOR] = hilites[CLR_GRAY]; } # else /* TOS */ int backg, foreg, hi_backg, hi_foreg; for (c = 0; c < SIZE(hilites); c++) hilites[c] = nh_HI; hilites[CLR_GRAY] = hilites[NO_COLOR] = (char *)0; analyze_seq(nh_HI, &hi_foreg, &hi_backg); analyze_seq(nh_HE, &foreg, &backg); for (c = 0; c < SIZE(hilites); c++) /* avoid invisibility */ if ((backg & ~BRIGHT) != c) { # ifdef MICRO if (c == CLR_BLUE) continue; # endif if (c == foreg) hilites[c] = (char *)0; else if (c != hi_foreg || backg != hi_backg) { hilites[c] = (char *) alloc(sizeof("\033[%d;3%d;4%dm")); Sprintf(hilites[c], "\033[%d", !!(c & BRIGHT)); if ((c | BRIGHT) != (foreg | BRIGHT)) Sprintf(eos(hilites[c]), ";3%d", c & ~BRIGHT); if (backg != CLR_BLACK) Sprintf(eos(hilites[c]), ";4%d", backg & ~BRIGHT); Strcat(hilites[c], "m"); } } # ifdef MICRO /* brighten low-visibility colors */ hilites[CLR_BLUE] = hilites[CLR_BLUE|BRIGHT]; # endif # endif /* TOS */ } # endif /* UNIX */ static void kill_hilite() { # ifndef TOS register int c; for (c = 0; c < CLR_MAX / 2; c++) { if (hilites[c|BRIGHT] == hilites[c]) hilites[c|BRIGHT] = 0; if (hilites[c] && (hilites[c] != nh_HI)) free((genericptr_t) hilites[c]), hilites[c] = 0; if (hilites[c|BRIGHT] && (hilites[c|BRIGHT] != nh_HI)) free((genericptr_t) hilites[c|BRIGHT]), hilites[c|BRIGHT] = 0; } # endif return; } #endif /* TEXTCOLOR */ static char nulstr[] = ""; static char * s_atr2str(n) int n; { switch (n) { case ATR_ULINE: if(nh_US) return nh_US; case ATR_BOLD: case ATR_BLINK: #if defined(TERMLIB) && defined(TEXTCOLOR) if (MD) return MD; #endif return nh_HI; case ATR_INVERSE: return MR; } return nulstr; } static char * e_atr2str(n) int n; { switch (n) { case ATR_ULINE: if(nh_UE) return nh_UE; case ATR_BOLD: case ATR_BLINK: return nh_HE; case ATR_INVERSE: return ME; } return nulstr; } void term_start_attr(attr) int attr; { if (attr) { xputs(s_atr2str(attr)); } } void term_end_attr(attr) int attr; { if(attr) { xputs(e_atr2str(attr)); } } void term_start_raw_bold() { xputs(nh_HI); } void term_end_raw_bold() { xputs(nh_HE); } #ifdef TEXTCOLOR void term_end_color() { xputs(nh_HE); } void term_start_color(color) int color; { xputs(hilites[color]); } int has_color(color) int color; { #ifdef X11_GRAPHICS /* XXX has_color() should be added to windowprocs */ if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "X11")) return TRUE; #endif #ifdef GEM_GRAPHICS /* XXX has_color() should be added to windowprocs */ if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "Gem")) return TRUE; #endif #ifdef QT_GRAPHICS /* XXX has_color() should be added to windowprocs */ if (windowprocs.name != NULL && !strcmpi(windowprocs.name, "Qt")) return TRUE; #endif #ifdef AMII_GRAPHICS /* hilites[] not used */ return iflags.use_color; #endif return hilites[color] != (char *)0; } #endif /* TEXTCOLOR */ #endif /* OVLB */ #endif /* TTY_GRAPHICS */ /*termcap.c*/ nethack-3.4.3/win/tty/topl.c0100644000000000000000000003127707764735042014424 0ustar rootroot/* SCCS Id: @(#)topl.c 3.4 1996/10/24 */ /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" #ifdef TTY_GRAPHICS #include "tcap.h" #include "wintty.h" #include #ifndef C /* this matches src/cmd.c */ #define C(c) (0x1f & (c)) #endif STATIC_DCL void FDECL(redotoplin, (const char*)); STATIC_DCL void FDECL(topl_putsym, (CHAR_P)); STATIC_DCL void NDECL(remember_topl); STATIC_DCL void FDECL(removetopl, (int)); #ifdef OVLB int tty_doprev_message() { register struct WinDesc *cw = wins[WIN_MESSAGE]; winid prevmsg_win; int i; if ((iflags.prevmsg_window != 's') && !ttyDisplay->inread) { /* not single */ if(iflags.prevmsg_window == 'f') { /* full */ prevmsg_win = create_nhwindow(NHW_MENU); putstr(prevmsg_win, 0, "Message History"); putstr(prevmsg_win, 0, ""); cw->maxcol = cw->maxrow; i = cw->maxcol; do { if(cw->data[i] && strcmp(cw->data[i], "") ) putstr(prevmsg_win, 0, cw->data[i]); i = (i + 1) % cw->rows; } while (i != cw->maxcol); putstr(prevmsg_win, 0, toplines); display_nhwindow(prevmsg_win, TRUE); destroy_nhwindow(prevmsg_win); } else if (iflags.prevmsg_window == 'c') { /* combination */ do { morc = 0; if (cw->maxcol == cw->maxrow) { ttyDisplay->dismiss_more = C('p'); /* allowed at --More-- */ redotoplin(toplines); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows-1; if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } else if (cw->maxcol == (cw->maxrow - 1)){ ttyDisplay->dismiss_more = C('p'); /* allowed at --More-- */ redotoplin(cw->data[cw->maxcol]); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows-1; if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } else { prevmsg_win = create_nhwindow(NHW_MENU); putstr(prevmsg_win, 0, "Message History"); putstr(prevmsg_win, 0, ""); cw->maxcol = cw->maxrow; i = cw->maxcol; do { if(cw->data[i] && strcmp(cw->data[i], "") ) putstr(prevmsg_win, 0, cw->data[i]); i = (i + 1) % cw->rows; } while (i != cw->maxcol); putstr(prevmsg_win, 0, toplines); display_nhwindow(prevmsg_win, TRUE); destroy_nhwindow(prevmsg_win); } } while (morc == C('p')); ttyDisplay->dismiss_more = 0; } else { /* reversed */ morc = 0; prevmsg_win = create_nhwindow(NHW_MENU); putstr(prevmsg_win, 0, "Message History"); putstr(prevmsg_win, 0, ""); putstr(prevmsg_win, 0, toplines); cw->maxcol=cw->maxrow-1; if(cw->maxcol < 0) cw->maxcol = cw->rows-1; do { putstr(prevmsg_win, 0, cw->data[cw->maxcol]); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows-1; if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } while (cw->maxcol != cw->maxrow); display_nhwindow(prevmsg_win, TRUE); destroy_nhwindow(prevmsg_win); cw->maxcol = cw->maxrow; ttyDisplay->dismiss_more = 0; } } else if(iflags.prevmsg_window == 's') { /* single */ ttyDisplay->dismiss_more = C('p'); /* allowed at --More-- */ do { morc = 0; if (cw->maxcol == cw->maxrow) redotoplin(toplines); else if (cw->data[cw->maxcol]) redotoplin(cw->data[cw->maxcol]); cw->maxcol--; if (cw->maxcol < 0) cw->maxcol = cw->rows-1; if (!cw->data[cw->maxcol]) cw->maxcol = cw->maxrow; } while (morc == C('p')); ttyDisplay->dismiss_more = 0; } return 0; } #endif /* OVLB */ #ifdef OVL1 STATIC_OVL void redotoplin(str) const char *str; { int otoplin = ttyDisplay->toplin; home(); if(*str & 0x80) { /* kludge for the / command, the only time we ever want a */ /* graphics character on the top line */ g_putch((int)*str++); ttyDisplay->curx++; } end_glyphout(); /* in case message printed during graphics output */ putsyms(str); cl_end(); ttyDisplay->toplin = 1; if(ttyDisplay->cury && otoplin != 3) more(); } STATIC_OVL void remember_topl() { register struct WinDesc *cw = wins[WIN_MESSAGE]; int idx = cw->maxrow; unsigned len = strlen(toplines) + 1; if (len > (unsigned)cw->datlen[idx]) { if (cw->data[idx]) free(cw->data[idx]); len += (8 - (len & 7)); /* pad up to next multiple of 8 */ cw->data[idx] = (char *)alloc(len); cw->datlen[idx] = (short)len; } Strcpy(cw->data[idx], toplines); cw->maxcol = cw->maxrow = (idx + 1) % cw->rows; } void addtopl(s) const char *s; { register struct WinDesc *cw = wins[WIN_MESSAGE]; tty_curs(BASE_WINDOW,cw->curx+1,cw->cury); putsyms(s); cl_end(); ttyDisplay->toplin = 1; } #endif /* OVL1 */ #ifdef OVL2 void more() { struct WinDesc *cw = wins[WIN_MESSAGE]; /* avoid recursion -- only happens from interrupts */ if(ttyDisplay->inmore++) return; if(ttyDisplay->toplin) { tty_curs(BASE_WINDOW, cw->curx+1, cw->cury); if(cw->curx >= CO - 8) topl_putsym('\n'); } if(flags.standout) standoutbeg(); putsyms(defmorestr); if(flags.standout) standoutend(); xwaitforspace("\033 "); if(morc == '\033') cw->flags |= WIN_STOP; if(ttyDisplay->toplin && cw->cury) { docorner(1, cw->cury+1); cw->curx = cw->cury = 0; home(); } else if(morc == '\033') { cw->curx = cw->cury = 0; home(); cl_end(); } ttyDisplay->toplin = 0; ttyDisplay->inmore = 0; } void update_topl(bp) register const char *bp; { register char *tl, *otl; register int n0; int notdied = 1; struct WinDesc *cw = wins[WIN_MESSAGE]; /* If there is room on the line, print message on same line */ /* But messages like "You die..." deserve their own line */ n0 = strlen(bp); if ((ttyDisplay->toplin == 1 || (cw->flags & WIN_STOP)) && cw->cury == 0 && n0 + (int)strlen(toplines) + 3 < CO-8 && /* room for --More-- */ (notdied = strncmp(bp, "You die", 7))) { Strcat(toplines, " "); Strcat(toplines, bp); cw->curx += 2; if(!(cw->flags & WIN_STOP)) addtopl(bp); return; } else if (!(cw->flags & WIN_STOP)) { if(ttyDisplay->toplin == 1) more(); else if(cw->cury) { /* for when flags.toplin == 2 && cury > 1 */ docorner(1, cw->cury+1); /* reset cury = 0 if redraw screen */ cw->curx = cw->cury = 0;/* from home--cls() & docorner(1,n) */ } } remember_topl(); (void) strncpy(toplines, bp, TBUFSZ); toplines[TBUFSZ - 1] = 0; for(tl = toplines; n0 >= CO; ){ otl = tl; for(tl+=CO-1; tl != otl && !isspace(*tl); --tl) ; if(tl == otl) { /* Eek! A huge token. Try splitting after it. */ tl = index(otl, ' '); if (!tl) break; /* No choice but to spit it out whole. */ } *tl++ = '\n'; n0 = strlen(tl); } if(!notdied) cw->flags &= ~WIN_STOP; if(!(cw->flags & WIN_STOP)) redotoplin(toplines); } STATIC_OVL void topl_putsym(c) char c; { register struct WinDesc *cw = wins[WIN_MESSAGE]; if(cw == (struct WinDesc *) 0) panic("Putsym window MESSAGE nonexistant"); switch(c) { case '\b': if(ttyDisplay->curx == 0 && ttyDisplay->cury > 0) tty_curs(BASE_WINDOW, CO, (int)ttyDisplay->cury-1); backsp(); ttyDisplay->curx--; cw->curx = ttyDisplay->curx; return; case '\n': cl_end(); ttyDisplay->curx = 0; ttyDisplay->cury++; cw->cury = ttyDisplay->cury; #ifdef WIN32CON (void) putchar(c); #endif break; default: if(ttyDisplay->curx == CO-1) topl_putsym('\n'); /* 1 <= curx <= CO; avoid CO */ #ifdef WIN32CON (void) putchar(c); #endif ttyDisplay->curx++; } cw->curx = ttyDisplay->curx; if(cw->curx == 0) cl_end(); #ifndef WIN32CON (void) putchar(c); #endif } void putsyms(str) const char *str; { while(*str) topl_putsym(*str++); } STATIC_OVL void removetopl(n) register int n; { /* assume addtopl() has been done, so ttyDisplay->toplin is already set */ while (n-- > 0) putsyms("\b \b"); } extern char erase_char; /* from xxxtty.c; don't need kill_char */ char tty_yn_function(query,resp, def) const char *query,*resp; char def; /* * Generic yes/no function. 'def' is the default (returned by space or * return; 'esc' returns 'q', or 'n', or the default, depending on * what's in the string. The 'query' string is printed before the user * is asked about the string. * If resp is NULL, any single character is accepted and returned. * If not-NULL, only characters in it are allowed (exceptions: the * quitchars are always allowed, and if it contains '#' then digits * are allowed); if it includes an , anything beyond that won't * be shown in the prompt to the user but will be acceptable as input. */ { register char q; char rtmp[40]; boolean digit_ok, allow_num; struct WinDesc *cw = wins[WIN_MESSAGE]; boolean doprev = 0; char prompt[QBUFSZ]; if(ttyDisplay->toplin == 1 && !(cw->flags & WIN_STOP)) more(); cw->flags &= ~WIN_STOP; ttyDisplay->toplin = 3; /* special prompt state */ ttyDisplay->inread++; if (resp) { char *rb, respbuf[QBUFSZ]; allow_num = (index(resp, '#') != 0); Strcpy(respbuf, resp); /* any acceptable responses that follow aren't displayed */ if ((rb = index(respbuf, '\033')) != 0) *rb = '\0'; Sprintf(prompt, "%s [%s] ", query, respbuf); if (def) Sprintf(eos(prompt), "(%c) ", def); pline("%s", prompt); } else { pline("%s ", query); q = readchar(); goto clean_up; } do { /* loop until we get valid input */ q = lowc(readchar()); if (q == '\020') { /* ctrl-P */ if (iflags.prevmsg_window != 's') { int sav = ttyDisplay->inread; ttyDisplay->inread = 0; (void) tty_doprev_message(); ttyDisplay->inread = sav; tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; addtopl(prompt); } else { if(!doprev) (void) tty_doprev_message(); /* need two initially */ (void) tty_doprev_message(); doprev = 1; } q = '\0'; /* force another loop iteration */ continue; } else if (doprev) { /* BUG[?]: this probably ought to check whether the character which has just been read is an acceptable response; if so, skip the reprompt and use it. */ tty_clear_nhwindow(WIN_MESSAGE); cw->maxcol = cw->maxrow; doprev = 0; addtopl(prompt); q = '\0'; /* force another loop iteration */ continue; } digit_ok = allow_num && digit(q); if (q == '\033') { if (index(resp, 'q')) q = 'q'; else if (index(resp, 'n')) q = 'n'; else q = def; break; } else if (index(quitchars, q)) { q = def; break; } if (!index(resp, q) && !digit_ok) { tty_nhbell(); q = (char)0; } else if (q == '#' || digit_ok) { char z, digit_string[2]; int n_len = 0; long value = 0; addtopl("#"), n_len++; digit_string[1] = '\0'; if (q != '#') { digit_string[0] = q; addtopl(digit_string), n_len++; value = q - '0'; q = '#'; } do { /* loop until we get a non-digit */ z = lowc(readchar()); if (digit(z)) { value = (10 * value) + (z - '0'); if (value < 0) break; /* overflow: try again */ digit_string[0] = z; addtopl(digit_string), n_len++; } else if (z == 'y' || index(quitchars, z)) { if (z == '\033') value = -1; /* abort */ z = '\n'; /* break */ } else if (z == erase_char || z == '\b') { if (n_len <= 1) { value = -1; break; } else { value /= 10; removetopl(1), n_len--; } } else { value = -1; /* abort */ tty_nhbell(); break; } } while (z != '\n'); if (value > 0) yn_number = value; else if (value == 0) q = 'n'; /* 0 => "no" */ else { /* remove number from top line, then try again */ removetopl(n_len), n_len = 0; q = '\0'; } } } while(!q); if (q != '#') { Sprintf(rtmp, "%c", q); addtopl(rtmp); } clean_up: ttyDisplay->inread--; ttyDisplay->toplin = 2; if (ttyDisplay->intr) ttyDisplay->intr--; if(wins[WIN_MESSAGE]->cury) tty_clear_nhwindow(WIN_MESSAGE); return q; } #endif /* OVL2 */ #endif /* TTY_GRAPHICS */ /*topl.c*/ nethack-3.4.3/win/tty/wintty.c0100644000000000000000000020355007764735042014777 0ustar rootroot/* SCCS Id: @(#)wintty.c 3.4 2002/09/27 */ /* Copyright (c) David Cohrs, 1991 */ /* NetHack may be freely redistributed. See license for details. */ /* * Neither a standard out nor character-based control codes should be * part of the "tty look" windowing implementation. * h+ 930227 */ #include "hack.h" #include "dlb.h" #ifdef SHORT_FILENAMES #include "patchlev.h" #else #include "patchlevel.h" #endif #ifdef TTY_GRAPHICS #ifdef MAC # define MICRO /* The Mac is a MICRO only for this file, not in general! */ # ifdef THINK_C extern void msmsg(const char *,...); # endif #endif #ifndef NO_TERMS #include "tcap.h" #endif #include "wintty.h" #ifdef CLIPPING /* might want SIGWINCH */ # if defined(BSD) || defined(ULTRIX) || defined(AIX_31) || defined(_BULL_SOURCE) #include # endif #endif extern char mapped_menu_cmds[]; /* from options.c */ /* Interface definition, for windows.c */ struct window_procs tty_procs = { "tty", #ifdef MSDOS WC_TILED_MAP|WC_ASCII_MAP| #endif #if defined(WIN32CON) WC_MOUSE_SUPPORT| #endif WC_COLOR|WC_HILITE_PET|WC_INVERSE|WC_EIGHT_BIT_IN, 0L, tty_init_nhwindows, tty_player_selection, tty_askname, tty_get_nh_event, tty_exit_nhwindows, tty_suspend_nhwindows, tty_resume_nhwindows, tty_create_nhwindow, tty_clear_nhwindow, tty_display_nhwindow, tty_destroy_nhwindow, tty_curs, tty_putstr, tty_display_file, tty_start_menu, tty_add_menu, tty_end_menu, tty_select_menu, tty_message_menu, tty_update_inventory, tty_mark_synch, tty_wait_synch, #ifdef CLIPPING tty_cliparound, #endif #ifdef POSITIONBAR tty_update_positionbar, #endif tty_print_glyph, tty_raw_print, tty_raw_print_bold, tty_nhgetch, tty_nh_poskey, tty_nhbell, tty_doprev_message, tty_yn_function, tty_getlin, tty_get_ext_cmd, tty_number_pad, tty_delay_output, #ifdef CHANGE_COLOR /* the Mac uses a palette device */ tty_change_color, #ifdef MAC tty_change_background, set_tty_font_name, #endif tty_get_color_string, #endif /* other defs that really should go away (they're tty specific) */ tty_start_screen, tty_end_screen, genl_outrip, #if defined(WIN32CON) nttty_preference_update, #else genl_preference_update, #endif }; static int maxwin = 0; /* number of windows in use */ winid BASE_WINDOW; struct WinDesc *wins[MAXWIN]; struct DisplayDesc *ttyDisplay; /* the tty display descriptor */ extern void FDECL(cmov, (int,int)); /* from termcap.c */ extern void FDECL(nocmov, (int,int)); /* from termcap.c */ #if defined(UNIX) || defined(VMS) static char obuf[BUFSIZ]; /* BUFSIZ is defined in stdio.h */ #endif static char winpanicstr[] = "Bad window id %d"; char defmorestr[] = "--More--"; #ifdef CLIPPING # if defined(USE_TILES) && defined(MSDOS) boolean clipping = FALSE; /* clipping on? */ int clipx = 0, clipxmax = 0; # else static boolean clipping = FALSE; /* clipping on? */ static int clipx = 0, clipxmax = 0; # endif static int clipy = 0, clipymax = 0; #endif /* CLIPPING */ #if defined(USE_TILES) && defined(MSDOS) extern void FDECL(adjust_cursor_flags, (struct WinDesc *)); #endif #if defined(ASCIIGRAPH) && !defined(NO_TERMS) boolean GFlag = FALSE; boolean HE_resets_AS; /* see termcap.c */ #endif #if defined(MICRO) || defined(WIN32CON) static const char to_continue[] = "to continue"; #define getret() getreturn(to_continue) #else STATIC_DCL void NDECL(getret); #endif STATIC_DCL void FDECL(erase_menu_or_text, (winid, struct WinDesc *, BOOLEAN_P)); STATIC_DCL void FDECL(free_window_info, (struct WinDesc *, BOOLEAN_P)); STATIC_DCL void FDECL(dmore,(struct WinDesc *, const char *)); STATIC_DCL void FDECL(set_item_state, (winid, int, tty_menu_item *)); STATIC_DCL void FDECL(set_all_on_page, (winid,tty_menu_item *,tty_menu_item *)); STATIC_DCL void FDECL(unset_all_on_page, (winid,tty_menu_item *,tty_menu_item *)); STATIC_DCL void FDECL(invert_all_on_page, (winid,tty_menu_item *,tty_menu_item *, CHAR_P)); STATIC_DCL void FDECL(invert_all, (winid,tty_menu_item *,tty_menu_item *, CHAR_P)); STATIC_DCL void FDECL(process_menu_window, (winid,struct WinDesc *)); STATIC_DCL void FDECL(process_text_window, (winid,struct WinDesc *)); STATIC_DCL tty_menu_item *FDECL(reverse, (tty_menu_item *)); STATIC_DCL const char * FDECL(compress_str, (const char *)); STATIC_DCL void FDECL(tty_putsym, (winid, int, int, CHAR_P)); static char *FDECL(copy_of, (const char *)); STATIC_DCL void FDECL(bail, (const char *)); /* __attribute__((noreturn)) */ /* * A string containing all the default commands -- to add to a list * of acceptable inputs. */ static const char default_menu_cmds[] = { MENU_FIRST_PAGE, MENU_LAST_PAGE, MENU_NEXT_PAGE, MENU_PREVIOUS_PAGE, MENU_SELECT_ALL, MENU_UNSELECT_ALL, MENU_INVERT_ALL, MENU_SELECT_PAGE, MENU_UNSELECT_PAGE, MENU_INVERT_PAGE, 0 /* null terminator */ }; /* clean up and quit */ STATIC_OVL void bail(mesg) const char *mesg; { clearlocks(); tty_exit_nhwindows(mesg); terminate(EXIT_SUCCESS); /*NOTREACHED*/ } #if defined(SIGWINCH) && defined(CLIPPING) STATIC_OVL void winch() { int oldLI = LI, oldCO = CO, i; register struct WinDesc *cw; getwindowsz(); if((oldLI != LI || oldCO != CO) && ttyDisplay) { ttyDisplay->rows = LI; ttyDisplay->cols = CO; cw = wins[BASE_WINDOW]; cw->rows = ttyDisplay->rows; cw->cols = ttyDisplay->cols; if(iflags.window_inited) { cw = wins[WIN_MESSAGE]; cw->curx = cw->cury = 0; tty_destroy_nhwindow(WIN_STATUS); WIN_STATUS = tty_create_nhwindow(NHW_STATUS); if(u.ux) { #ifdef CLIPPING if(CO < COLNO || LI < ROWNO+3) { setclipped(); tty_cliparound(u.ux, u.uy); } else { clipping = FALSE; clipx = clipy = 0; } #endif i = ttyDisplay->toplin; ttyDisplay->toplin = 0; docrt(); bot(); ttyDisplay->toplin = i; flush_screen(1); if(i) { addtopl(toplines); } else for(i=WIN_INVEN; i < MAXWIN; i++) if(wins[i] && wins[i]->active) { /* cop-out */ addtopl("Press Return to continue: "); break; } (void) fflush(stdout); if(i < 2) flush_screen(1); } } } } #endif /*ARGSUSED*/ void tty_init_nhwindows(argcp,argv) int* argcp; char** argv; { int wid, hgt; /* * Remember tty modes, to be restored on exit. * * gettty() must be called before tty_startup() * due to ordering of LI/CO settings * tty_startup() must be called before initoptions() * due to ordering of graphics settings */ #if defined(UNIX) || defined(VMS) setbuf(stdout,obuf); #endif gettty(); /* to port dependant tty setup */ tty_startup(&wid, &hgt); setftty(); /* calls start_screen */ /* set up tty descriptor */ ttyDisplay = (struct DisplayDesc*) alloc(sizeof(struct DisplayDesc)); ttyDisplay->toplin = 0; ttyDisplay->rows = hgt; ttyDisplay->cols = wid; ttyDisplay->curx = ttyDisplay->cury = 0; ttyDisplay->inmore = ttyDisplay->inread = ttyDisplay->intr = 0; ttyDisplay->dismiss_more = 0; #ifdef TEXTCOLOR ttyDisplay->color = NO_COLOR; #endif ttyDisplay->attrs = 0; /* set up the default windows */ BASE_WINDOW = tty_create_nhwindow(NHW_BASE); wins[BASE_WINDOW]->active = 1; ttyDisplay->lastwin = WIN_ERR; #if defined(SIGWINCH) && defined(CLIPPING) (void) signal(SIGWINCH, winch); #endif /* add one a space forward menu command alias */ add_menu_cmd_alias(' ', MENU_NEXT_PAGE); tty_clear_nhwindow(BASE_WINDOW); tty_putstr(BASE_WINDOW, 0, ""); tty_putstr(BASE_WINDOW, 0, COPYRIGHT_BANNER_A); tty_putstr(BASE_WINDOW, 0, COPYRIGHT_BANNER_B); tty_putstr(BASE_WINDOW, 0, COPYRIGHT_BANNER_C); tty_putstr(BASE_WINDOW, 0, ""); tty_display_nhwindow(BASE_WINDOW, FALSE); } void tty_player_selection() { int i, k, n; char pick4u = 'n', thisch, lastch = 0; char pbuf[QBUFSZ], plbuf[QBUFSZ]; winid win; anything any; menu_item *selected = 0; /* prevent an unnecessary prompt */ rigid_role_checks(); /* Should we randomly pick for the player? */ if (!flags.randomall && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) { int echoline; char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend, flags.initalign); tty_putstr(BASE_WINDOW, 0, ""); echoline = wins[BASE_WINDOW]->cury; tty_putstr(BASE_WINDOW, 0, prompt); do { pick4u = lowc(readchar()); if (index(quitchars, pick4u)) pick4u = 'y'; } while(!index(ynqchars, pick4u)); if ((int)strlen(prompt) + 1 < CO) { /* Echo choice and move back down line */ tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, pick4u); tty_putstr(BASE_WINDOW, 0, ""); } else /* Otherwise it's hard to tell where to echo, and things are * wrapping a bit messily anyway, so (try to) make sure the next * question shows up well and doesn't get wrapped at the * bottom of the window. */ tty_clear_nhwindow(BASE_WINDOW); if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) free((genericptr_t) selected); bail((char *)0); /*NOTREACHED*/ return; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* Select a role, if necessary */ /* we'll try to be compatible with pre-selected race/gender/alignment, * but may not succeed */ if (flags.initrole < 0) { char rolenamebuf[QBUFSZ]; /* Process the choice */ if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); flags.initrole = randrole(); } } else { tty_clear_nhwindow(BASE_WINDOW); tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ thisch = lowc(roles[i].name.m[0]); if (thisch == lastch) thisch = highc(thisch); if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) { if (flags.initgend == 1 && roles[i].name.f) Strcpy(rolenamebuf, roles[i].name.f); else Strcpy(rolenamebuf, roles[i].name.m); } else { if (roles[i].name.f) { Strcpy(rolenamebuf, roles[i].name.m); Strcat(rolenamebuf, "/"); Strcat(rolenamebuf, roles[i].name.f); } else Strcpy(rolenamebuf, roles[i].name.m); } add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED); lastch = thisch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole()+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { tty_clear_nhwindow(BASE_WINDOW); tty_putstr(BASE_WINDOW, 0, "Choosing Race"); win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { tty_clear_nhwindow(BASE_WINDOW); tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { tty_clear_nhwindow(BASE_WINDOW); tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ tty_display_nhwindow(BASE_WINDOW, FALSE); } /* * plname is filled either by an option (-u Player or -uPlayer) or * explicitly (by being the wizard) or by askname. * It may still contain a suffix denoting the role, etc. * Always called after init_nhwindows() and before display_gamewindows(). */ void tty_askname() { static char who_are_you[] = "Who are you? "; register int c, ct, tryct = 0; tty_putstr(BASE_WINDOW, 0, ""); do { if (++tryct > 1) { if (tryct > 10) bail("Giving up after 10 tries.\n"); tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury - 1); tty_putstr(BASE_WINDOW, 0, "Enter a name for your character..."); /* erase previous prompt (in case of ESC after partial response) */ tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury), cl_end(); } tty_putstr(BASE_WINDOW, 0, who_are_you); tty_curs(BASE_WINDOW, (int)(sizeof who_are_you), wins[BASE_WINDOW]->cury - 1); ct = 0; while((c = tty_nhgetch()) != '\n') { if(c == EOF) error("End of input\n"); if (c == '\033') { ct = 0; break; } /* continue outer loop */ #if defined(WIN32CON) if (c == '\003') bail("^C abort.\n"); #endif /* some people get confused when their erase char is not ^H */ if (c == '\b' || c == '\177') { if(ct) { ct--; #ifdef WIN32CON ttyDisplay->curx--; #endif #if defined(MICRO) || defined(WIN32CON) # if defined(WIN32CON) || defined(MSDOS) backsp(); /* \b is visible on NT */ (void) putchar(' '); backsp(); # else msmsg("\b \b"); # endif #else (void) putchar('\b'); (void) putchar(' '); (void) putchar('\b'); #endif } continue; } #if defined(UNIX) || defined(VMS) if(c != '-' && c != '@') if(c < 'A' || (c > 'Z' && c < 'a') || c > 'z') c = '_'; #endif if (ct < (int)(sizeof plname) - 1) { #if defined(MICRO) # if defined(MSDOS) if (iflags.grmode) { (void) putchar(c); } else # endif msmsg("%c", c); #else (void) putchar(c); #endif plname[ct++] = c; #ifdef WIN32CON ttyDisplay->curx++; #endif } } plname[ct] = 0; } while (ct == 0); /* move to next line to simulate echo of user's */ tty_curs(BASE_WINDOW, 1, wins[BASE_WINDOW]->cury + 1); } void tty_get_nh_event() { return; } #if !defined(MICRO) && !defined(WIN32CON) STATIC_OVL void getret() { xputs("\n"); if(flags.standout) standoutbeg(); xputs("Hit "); xputs(iflags.cbreak ? "space" : "return"); xputs(" to continue: "); if(flags.standout) standoutend(); xwaitforspace(" "); } #endif void tty_suspend_nhwindows(str) const char *str; { settty(str); /* calls end_screen, perhaps raw_print */ if (!str) tty_raw_print(""); /* calls fflush(stdout) */ } void tty_resume_nhwindows() { gettty(); setftty(); /* calls start_screen */ docrt(); } void tty_exit_nhwindows(str) const char *str; { winid i; tty_suspend_nhwindows(str); /* Just forget any windows existed, since we're about to exit anyway. * Disable windows to avoid calls to window routines. */ for(i=0; itype = type; newwin->flags = 0; newwin->active = FALSE; newwin->curx = newwin->cury = 0; newwin->morestr = 0; newwin->mlist = (tty_menu_item *) 0; newwin->plist = (tty_menu_item **) 0; newwin->npages = newwin->plist_size = newwin->nitems = newwin->how = 0; switch(type) { case NHW_BASE: /* base window, used for absolute movement on the screen */ newwin->offx = newwin->offy = 0; newwin->rows = ttyDisplay->rows; newwin->cols = ttyDisplay->cols; newwin->maxrow = newwin->maxcol = 0; break; case NHW_MESSAGE: /* message window, 1 line long, very wide, top of screen */ newwin->offx = newwin->offy = 0; /* sanity check */ if(iflags.msg_history < 20) iflags.msg_history = 20; else if(iflags.msg_history > 60) iflags.msg_history = 60; newwin->maxrow = newwin->rows = iflags.msg_history; newwin->maxcol = newwin->cols = 0; break; case NHW_STATUS: /* status window, 2 lines long, full width, bottom of screen */ newwin->offx = 0; #if defined(USE_TILES) && defined(MSDOS) if (iflags.grmode) { newwin->offy = ttyDisplay->rows-2; } else #endif newwin->offy = min((int)ttyDisplay->rows-2, ROWNO+1); newwin->rows = newwin->maxrow = 2; newwin->cols = newwin->maxcol = min(ttyDisplay->cols, COLNO); break; case NHW_MAP: /* map window, ROWNO lines long, full width, below message window */ newwin->offx = 0; newwin->offy = 1; newwin->rows = ROWNO; newwin->cols = COLNO; newwin->maxrow = 0; /* no buffering done -- let gbuf do it */ newwin->maxcol = 0; break; case NHW_MENU: case NHW_TEXT: /* inventory/menu window, variable length, full width, top of screen */ /* help window, the same, different semantics for display, etc */ newwin->offx = newwin->offy = 0; newwin->rows = 0; newwin->cols = ttyDisplay->cols; newwin->maxrow = newwin->maxcol = 0; break; default: panic("Tried to create window type %d\n", (int) type); return WIN_ERR; } for(newid = 0; newidmaxrow) { newwin->data = (char **) alloc(sizeof(char *) * (unsigned)newwin->maxrow); newwin->datlen = (short *) alloc(sizeof(short) * (unsigned)newwin->maxrow); if(newwin->maxcol) { for (i = 0; i < newwin->maxrow; i++) { newwin->data[i] = (char *) alloc((unsigned)newwin->maxcol); newwin->datlen[i] = newwin->maxcol; } } else { for (i = 0; i < newwin->maxrow; i++) { newwin->data[i] = (char *) 0; newwin->datlen[i] = 0; } } if(newwin->type == NHW_MESSAGE) newwin->maxrow = 0; } else { newwin->data = (char **)0; newwin->datlen = (short *)0; } return newid; } STATIC_OVL void erase_menu_or_text(window, cw, clear) winid window; struct WinDesc *cw; boolean clear; { if(cw->offx == 0) if(cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else if (clear) clear_screen(); else docrt(); else docorner((int)cw->offx, cw->maxrow+1); } STATIC_OVL void free_window_info(cw, free_data) struct WinDesc *cw; boolean free_data; { int i; if (cw->data) { if (cw == wins[WIN_MESSAGE] && cw->rows > cw->maxrow) cw->maxrow = cw->rows; /* topl data */ for(i=0; imaxrow; i++) if(cw->data[i]) { free((genericptr_t)cw->data[i]); cw->data[i] = (char *)0; if (cw->datlen) cw->datlen[i] = 0; } if (free_data) { free((genericptr_t)cw->data); cw->data = (char **)0; if (cw->datlen) free((genericptr_t)cw->datlen); cw->datlen = (short *)0; cw->rows = 0; } } cw->maxrow = cw->maxcol = 0; if(cw->mlist) { tty_menu_item *temp; while ((temp = cw->mlist) != 0) { cw->mlist = cw->mlist->next; if (temp->str) free((genericptr_t)temp->str); free((genericptr_t)temp); } } if (cw->plist) { free((genericptr_t)cw->plist); cw->plist = 0; } cw->plist_size = cw->npages = cw->nitems = cw->how = 0; if(cw->morestr) { free((genericptr_t)cw->morestr); cw->morestr = 0; } } void tty_clear_nhwindow(window) winid window; { register struct WinDesc *cw = 0; if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); ttyDisplay->lastwin = window; switch(cw->type) { case NHW_MESSAGE: if(ttyDisplay->toplin) { home(); cl_end(); if(cw->cury) docorner(1, cw->cury+1); ttyDisplay->toplin = 0; } break; case NHW_STATUS: tty_curs(window, 1, 0); cl_end(); tty_curs(window, 1, 1); cl_end(); break; case NHW_MAP: /* cheap -- clear the whole thing and tell nethack to redraw botl */ flags.botlx = 1; /* fall into ... */ case NHW_BASE: clear_screen(); break; case NHW_MENU: case NHW_TEXT: if(cw->active) erase_menu_or_text(window, cw, TRUE); free_window_info(cw, FALSE); break; } cw->curx = cw->cury = 0; } STATIC_OVL void dmore(cw, s) register struct WinDesc *cw; const char *s; /* valid responses */ { const char *prompt = cw->morestr ? cw->morestr : defmorestr; int offset = (cw->type == NHW_TEXT) ? 1 : 2; tty_curs(BASE_WINDOW, (int)ttyDisplay->curx + offset, (int)ttyDisplay->cury); if(flags.standout) standoutbeg(); xputs(prompt); ttyDisplay->curx += strlen(prompt); if(flags.standout) standoutend(); xwaitforspace(s); } STATIC_OVL void set_item_state(window, lineno, item) winid window; int lineno; tty_menu_item *item; { char ch = item->selected ? (item->count == -1L ? '+' : '#') : '-'; tty_curs(window, 4, lineno); term_start_attr(item->attr); (void) putchar(ch); ttyDisplay->curx++; term_end_attr(item->attr); } STATIC_OVL void set_all_on_page(window, page_start, page_end) winid window; tty_menu_item *page_start, *page_end; { tty_menu_item *curr; int n; for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) if (curr->identifier.a_void && !curr->selected) { curr->selected = TRUE; set_item_state(window, n, curr); } } STATIC_OVL void unset_all_on_page(window, page_start, page_end) winid window; tty_menu_item *page_start, *page_end; { tty_menu_item *curr; int n; for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) if (curr->identifier.a_void && curr->selected) { curr->selected = FALSE; curr->count = -1L; set_item_state(window, n, curr); } } STATIC_OVL void invert_all_on_page(window, page_start, page_end, acc) winid window; tty_menu_item *page_start, *page_end; char acc; /* group accelerator, 0 => all */ { tty_menu_item *curr; int n; for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) if (curr->identifier.a_void && (acc == 0 || curr->gselector == acc)) { if (curr->selected) { curr->selected = FALSE; curr->count = -1L; } else curr->selected = TRUE; set_item_state(window, n, curr); } } /* * Invert all entries that match the give group accelerator (or all if * zero). */ STATIC_OVL void invert_all(window, page_start, page_end, acc) winid window; tty_menu_item *page_start, *page_end; char acc; /* group accelerator, 0 => all */ { tty_menu_item *curr; boolean on_curr_page; struct WinDesc *cw = wins[window]; invert_all_on_page(window, page_start, page_end, acc); /* invert the rest */ for (on_curr_page = FALSE, curr = cw->mlist; curr; curr = curr->next) { if (curr == page_start) on_curr_page = TRUE; else if (curr == page_end) on_curr_page = FALSE; if (!on_curr_page && curr->identifier.a_void && (acc == 0 || curr->gselector == acc)) { if (curr->selected) { curr->selected = FALSE; curr->count = -1; } else curr->selected = TRUE; } } } STATIC_OVL void process_menu_window(window, cw) winid window; struct WinDesc *cw; { tty_menu_item *page_start, *page_end, *curr; long count; int n, curr_page, page_lines; boolean finished, counting, reset_count; char *cp, *rp, resp[QBUFSZ], gacc[QBUFSZ], *msave, *morestr; curr_page = page_lines = 0; page_start = page_end = 0; msave = cw->morestr; /* save the morestr */ cw->morestr = morestr = (char*) alloc((unsigned) QBUFSZ); counting = FALSE; count = 0L; reset_count = TRUE; finished = FALSE; /* collect group accelerators; for PICK_NONE, they're ignored; for PICK_ONE, only those which match exactly one entry will be accepted; for PICK_ANY, those which match any entry are okay */ gacc[0] = '\0'; if (cw->how != PICK_NONE) { int i, gcnt[128]; #define GSELIDX(c) (c & 127) /* guard against `signed char' */ for (i = 0; i < SIZE(gcnt); i++) gcnt[i] = 0; for (n = 0, curr = cw->mlist; curr; curr = curr->next) if (curr->gselector && curr->gselector != curr->selector) { ++n; ++gcnt[GSELIDX(curr->gselector)]; } if (n > 0) /* at least one group accelerator found */ for (rp = gacc, curr = cw->mlist; curr; curr = curr->next) if (curr->gselector && !index(gacc, curr->gselector) && (cw->how == PICK_ANY || gcnt[GSELIDX(curr->gselector)] == 1)) { *rp++ = curr->gselector; *rp = '\0'; /* re-terminate for index() */ } } /* loop until finished */ while (!finished) { if (reset_count) { counting = FALSE; count = 0; } else reset_count = TRUE; if (!page_start) { /* new page to be displayed */ if (curr_page < 0 || (cw->npages > 0 && curr_page >= cw->npages)) panic("bad menu screen page #%d", curr_page); /* clear screen */ if (!cw->offx) { /* if not corner, do clearscreen */ if(cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else clear_screen(); } rp = resp; if (cw->npages > 0) { /* collect accelerators */ page_start = cw->plist[curr_page]; page_end = cw->plist[curr_page + 1]; for (page_lines = 0, curr = page_start; curr != page_end; page_lines++, curr = curr->next) { if (curr->selector) *rp++ = curr->selector; tty_curs(window, 1, page_lines); if (cw->offx) cl_end(); (void) putchar(' '); ++ttyDisplay->curx; /* * Don't use xputs() because (1) under unix it calls * tputstr() which will interpret a '*' as some kind * of padding information and (2) it calls xputc to * actually output the character. We're faster doing * this. */ term_start_attr(curr->attr); for (n = 0, cp = curr->str; #ifndef WIN32CON *cp && (int) ++ttyDisplay->curx < (int) ttyDisplay->cols; cp++, n++) #else *cp && (int) ttyDisplay->curx < (int) ttyDisplay->cols; cp++, n++, ttyDisplay->curx++) #endif if (n == 2 && curr->identifier.a_void != 0 && curr->selected) { if (curr->count == -1L) (void) putchar('+'); /* all selected */ else (void) putchar('#'); /* count selected */ } else (void) putchar(*cp); term_end_attr(curr->attr); } } else { page_start = 0; page_end = 0; page_lines = 0; } *rp = 0; /* corner window - clear extra lines from last page */ if (cw->offx) { for (n = page_lines + 1; n < cw->maxrow; n++) { tty_curs(window, 1, n); cl_end(); } } /* set extra chars.. */ Strcat(resp, default_menu_cmds); Strcat(resp, "0123456789\033\n\r"); /* counts, quit */ Strcat(resp, gacc); /* group accelerators */ Strcat(resp, mapped_menu_cmds); if (cw->npages > 1) Sprintf(cw->morestr, "(%d of %d)", curr_page + 1, (int) cw->npages); else if (msave) Strcpy(cw->morestr, msave); else Strcpy(cw->morestr, defmorestr); tty_curs(window, 1, page_lines); cl_end(); dmore(cw, resp); } else { /* just put the cursor back... */ tty_curs(window, (int) strlen(cw->morestr) + 2, page_lines); xwaitforspace(resp); } morc = map_menu_cmd(morc); switch (morc) { case '0': /* special case: '0' is also the default ball class */ if (!counting && index(gacc, morc)) goto group_accel; /* fall through to count the zero */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': count = (count * 10L) + (long) (morc - '0'); /* * It is debatable whether we should allow 0 to * start a count. There is no difference if the * item is selected. If not selected, then * "0b" could mean: * * count starting zero: "zero b's" * ignore starting zero: "select b" * * At present I don't know which is better. */ if (count != 0L) { /* ignore leading zeros */ counting = TRUE; reset_count = FALSE; } break; case '\033': /* cancel - from counting or loop */ if (!counting) { /* deselect everything */ for (curr = cw->mlist; curr; curr = curr->next) { curr->selected = FALSE; curr->count = -1L; } cw->flags |= WIN_CANCELLED; finished = TRUE; } /* else only stop count */ break; case '\0': /* finished (commit) */ case '\n': case '\r': /* only finished if we are actually picking something */ if (cw->how != PICK_NONE) { finished = TRUE; break; } /* else fall through */ case MENU_NEXT_PAGE: if (cw->npages > 0 && curr_page != cw->npages - 1) { curr_page++; page_start = 0; } else finished = TRUE; /* questionable behavior */ break; case MENU_PREVIOUS_PAGE: if (cw->npages > 0 && curr_page != 0) { --curr_page; page_start = 0; } break; case MENU_FIRST_PAGE: if (cw->npages > 0 && curr_page != 0) { page_start = 0; curr_page = 0; } break; case MENU_LAST_PAGE: if (cw->npages > 0 && curr_page != cw->npages - 1) { page_start = 0; curr_page = cw->npages - 1; } break; case MENU_SELECT_PAGE: if (cw->how == PICK_ANY) set_all_on_page(window, page_start, page_end); break; case MENU_UNSELECT_PAGE: unset_all_on_page(window, page_start, page_end); break; case MENU_INVERT_PAGE: if (cw->how == PICK_ANY) invert_all_on_page(window, page_start, page_end, 0); break; case MENU_SELECT_ALL: if (cw->how == PICK_ANY) { set_all_on_page(window, page_start, page_end); /* set the rest */ for (curr = cw->mlist; curr; curr = curr->next) if (curr->identifier.a_void && !curr->selected) curr->selected = TRUE; } break; case MENU_UNSELECT_ALL: unset_all_on_page(window, page_start, page_end); /* unset the rest */ for (curr = cw->mlist; curr; curr = curr->next) if (curr->identifier.a_void && curr->selected) { curr->selected = FALSE; curr->count = -1; } break; case MENU_INVERT_ALL: if (cw->how == PICK_ANY) invert_all(window, page_start, page_end, 0); break; default: if (cw->how == PICK_NONE || !index(resp, morc)) { /* unacceptable input received */ tty_nhbell(); break; } else if (index(gacc, morc)) { group_accel: /* group accelerator; for the PICK_ONE case, we know that it matches exactly one item in order to be in gacc[] */ invert_all(window, page_start, page_end, morc); if (cw->how == PICK_ONE) finished = TRUE; break; } /* find, toggle, and possibly update */ for (n = 0, curr = page_start; curr != page_end; n++, curr = curr->next) if (morc == curr->selector) { if (curr->selected) { if (counting && count > 0) { curr->count = count; set_item_state(window, n, curr); } else { /* change state */ curr->selected = FALSE; curr->count = -1L; set_item_state(window, n, curr); } } else { /* !selected */ if (counting && count > 0) { curr->count = count; curr->selected = TRUE; set_item_state(window, n, curr); } else if (!counting) { curr->selected = TRUE; set_item_state(window, n, curr); } /* do nothing counting&&count==0 */ } if (cw->how == PICK_ONE) finished = TRUE; break; /* from `for' loop */ } break; } } /* while */ cw->morestr = msave; free((genericptr_t)morestr); } STATIC_OVL void process_text_window(window, cw) winid window; struct WinDesc *cw; { int i, n, attr; register char *cp; for (n = 0, i = 0; i < cw->maxrow; i++) { if (!cw->offx && (n + cw->offy == ttyDisplay->rows - 1)) { tty_curs(window, 1, n); cl_end(); dmore(cw, quitchars); if (morc == '\033') { cw->flags |= WIN_CANCELLED; break; } if (cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else clear_screen(); n = 0; } tty_curs(window, 1, n++); if (cw->offx) cl_end(); if (cw->data[i]) { attr = cw->data[i][0] - 1; if (cw->offx) { (void) putchar(' '); ++ttyDisplay->curx; } term_start_attr(attr); for (cp = &cw->data[i][1]; #ifndef WIN32CON *cp && (int) ++ttyDisplay->curx < (int) ttyDisplay->cols; cp++) #else *cp && (int) ttyDisplay->curx < (int) ttyDisplay->cols; cp++, ttyDisplay->curx++) #endif (void) putchar(*cp); term_end_attr(attr); } } if (i == cw->maxrow) { tty_curs(BASE_WINDOW, (int)cw->offx + 1, (cw->type == NHW_TEXT) ? (int) ttyDisplay->rows - 1 : n); cl_end(); dmore(cw, quitchars); if (morc == '\033') cw->flags |= WIN_CANCELLED; } } /*ARGSUSED*/ void tty_display_nhwindow(window, blocking) winid window; boolean blocking; /* with ttys, all windows are blocking */ { register struct WinDesc *cw = 0; if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); if(cw->flags & WIN_CANCELLED) return; ttyDisplay->lastwin = window; ttyDisplay->rawprint = 0; switch(cw->type) { case NHW_MESSAGE: if(ttyDisplay->toplin == 1) { more(); ttyDisplay->toplin = 1; /* more resets this */ tty_clear_nhwindow(window); } else ttyDisplay->toplin = 0; cw->curx = cw->cury = 0; if(!cw->active) iflags.window_inited = TRUE; break; case NHW_MAP: end_glyphout(); if(blocking) { if(!ttyDisplay->toplin) ttyDisplay->toplin = 1; tty_display_nhwindow(WIN_MESSAGE, TRUE); return; } case NHW_BASE: (void) fflush(stdout); break; case NHW_TEXT: cw->maxcol = ttyDisplay->cols; /* force full-screen mode */ /*FALLTHRU*/ case NHW_MENU: cw->active = 1; /* avoid converting to uchar before calculations are finished */ cw->offx = (uchar) (int) max((int) 10, (int) (ttyDisplay->cols - cw->maxcol - 1)); if(cw->type == NHW_MENU) cw->offy = 0; if(ttyDisplay->toplin == 1) tty_display_nhwindow(WIN_MESSAGE, TRUE); if(cw->offx == 10 || cw->maxrow >= (int) ttyDisplay->rows) { cw->offx = 0; if(cw->offy) { tty_curs(window, 1, 0); cl_eos(); } else clear_screen(); ttyDisplay->toplin = 0; } else tty_clear_nhwindow(WIN_MESSAGE); if (cw->data || !cw->maxrow) process_text_window(window, cw); else process_menu_window(window, cw); break; } cw->active = 1; } void tty_dismiss_nhwindow(window) winid window; { register struct WinDesc *cw = 0; if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); switch(cw->type) { case NHW_MESSAGE: if (ttyDisplay->toplin) tty_display_nhwindow(WIN_MESSAGE, TRUE); /*FALLTHRU*/ case NHW_STATUS: case NHW_BASE: case NHW_MAP: /* * these should only get dismissed when the game is going away * or suspending */ tty_curs(BASE_WINDOW, 1, (int)ttyDisplay->rows-1); cw->active = 0; break; case NHW_MENU: case NHW_TEXT: if(cw->active) { if (iflags.window_inited) { /* otherwise dismissing the text endwin after other windows * are dismissed tries to redraw the map and panics. since * the whole reason for dismissing the other windows was to * leave the ending window on the screen, we don't want to * erase it anyway. */ erase_menu_or_text(window, cw, FALSE); } cw->active = 0; } break; } cw->flags = 0; } void tty_destroy_nhwindow(window) winid window; { register struct WinDesc *cw = 0; if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); if(cw->active) tty_dismiss_nhwindow(window); if(cw->type == NHW_MESSAGE) iflags.window_inited = 0; if(cw->type == NHW_MAP) clear_screen(); free_window_info(cw, TRUE); free((genericptr_t)cw); wins[window] = 0; } void tty_curs(window, x, y) winid window; register int x, y; /* not xchar: perhaps xchar is unsigned and curx-x would be unsigned as well */ { struct WinDesc *cw = 0; int cx = ttyDisplay->curx; int cy = ttyDisplay->cury; if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); ttyDisplay->lastwin = window; #if defined(USE_TILES) && defined(MSDOS) adjust_cursor_flags(cw); #endif cw->curx = --x; /* column 0 is never used */ cw->cury = y; #ifdef DEBUG if(x<0 || y<0 || y >= cw->rows || x > cw->cols) { const char *s = "[unknown type]"; switch(cw->type) { case NHW_MESSAGE: s = "[topl window]"; break; case NHW_STATUS: s = "[status window]"; break; case NHW_MAP: s = "[map window]"; break; case NHW_MENU: s = "[corner window]"; break; case NHW_TEXT: s = "[text window]"; break; case NHW_BASE: s = "[base window]"; break; } impossible("bad curs positioning win %d %s (%d,%d)", window, s, x, y); return; } #endif x += cw->offx; y += cw->offy; #ifdef CLIPPING if(clipping && window == WIN_MAP) { x -= clipx; y -= clipy; } #endif if (y == cy && x == cx) return; if(cw->type == NHW_MAP) end_glyphout(); #ifndef NO_TERMS if(!nh_ND && (cx != x || x <= 3)) { /* Extremely primitive */ cmov(x, y); /* bunker!wtm */ return; } #endif if((cy -= y) < 0) cy = -cy; if((cx -= x) < 0) cx = -cx; if(cy <= 3 && cx <= 3) { nocmov(x, y); #ifndef NO_TERMS } else if ((x <= 3 && cy <= 3) || (!nh_CM && x < cx)) { (void) putchar('\r'); ttyDisplay->curx = 0; nocmov(x, y); } else if (!nh_CM) { nocmov(x, y); #endif } else cmov(x, y); ttyDisplay->curx = x; ttyDisplay->cury = y; } STATIC_OVL void tty_putsym(window, x, y, ch) winid window; int x, y; char ch; { register struct WinDesc *cw = 0; if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) panic(winpanicstr, window); switch(cw->type) { case NHW_STATUS: case NHW_MAP: case NHW_BASE: tty_curs(window, x, y); (void) putchar(ch); ttyDisplay->curx++; cw->curx++; break; case NHW_MESSAGE: case NHW_MENU: case NHW_TEXT: impossible("Can't putsym to window type %d", cw->type); break; } } STATIC_OVL const char* compress_str(str) const char *str; { static char cbuf[BUFSZ]; /* compress in case line too long */ if((int)strlen(str) >= CO) { register const char *bp0 = str; register char *bp1 = cbuf; do { #ifdef CLIPPING if(*bp0 != ' ' || bp0[1] != ' ') #else if(*bp0 != ' ' || bp0[1] != ' ' || bp0[2] != ' ') #endif *bp1++ = *bp0; } while(*bp0++); } else return str; return cbuf; } void tty_putstr(window, attr, str) winid window; int attr; const char *str; { register struct WinDesc *cw = 0; register char *ob; register const char *nb; register int i, j, n0; /* Assume there's a real problem if the window is missing -- * probably a panic message */ if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0) { tty_raw_print(str); return; } if(str == (const char*)0 || ((cw->flags & WIN_CANCELLED) && (cw->type != NHW_MESSAGE))) return; if(cw->type != NHW_MESSAGE) str = compress_str(str); ttyDisplay->lastwin = window; switch(cw->type) { case NHW_MESSAGE: /* really do this later */ #if defined(USER_SOUNDS) && defined(WIN32CON) play_sound_for_message(str); #endif update_topl(str); break; case NHW_STATUS: ob = &cw->data[cw->cury][j = cw->curx]; if(flags.botlx) *ob = 0; if(!cw->cury && (int)strlen(str) >= CO) { /* the characters before "St:" are unnecessary */ nb = index(str, ':'); if(nb && nb > str+2) str = nb - 2; } nb = str; for(i = cw->curx+1, n0 = cw->cols; i < n0; i++, nb++) { if(!*nb) { if(*ob || flags.botlx) { /* last char printed may be in middle of line */ tty_curs(WIN_STATUS, i, cw->cury); cl_end(); } break; } if(*ob != *nb) tty_putsym(WIN_STATUS, i, cw->cury, *nb); if(*ob) ob++; } (void) strncpy(&cw->data[cw->cury][j], str, cw->cols - j - 1); cw->data[cw->cury][cw->cols-1] = '\0'; /* null terminate */ cw->cury = (cw->cury+1) % 2; cw->curx = 0; break; case NHW_MAP: tty_curs(window, cw->curx+1, cw->cury); term_start_attr(attr); while(*str && (int) ttyDisplay->curx < (int) ttyDisplay->cols-1) { (void) putchar(*str); str++; ttyDisplay->curx++; } cw->curx = 0; cw->cury++; term_end_attr(attr); break; case NHW_BASE: tty_curs(window, cw->curx+1, cw->cury); term_start_attr(attr); while (*str) { if ((int) ttyDisplay->curx >= (int) ttyDisplay->cols-1) { cw->curx = 0; cw->cury++; tty_curs(window, cw->curx+1, cw->cury); } (void) putchar(*str); str++; ttyDisplay->curx++; } cw->curx = 0; cw->cury++; term_end_attr(attr); break; case NHW_MENU: case NHW_TEXT: if(cw->type == NHW_TEXT && cw->cury == ttyDisplay->rows-1) { /* not a menu, so save memory and output 1 page at a time */ cw->maxcol = ttyDisplay->cols; /* force full-screen mode */ tty_display_nhwindow(window, TRUE); for(i=0; imaxrow; i++) if(cw->data[i]){ free((genericptr_t)cw->data[i]); cw->data[i] = 0; } cw->maxrow = cw->cury = 0; } /* always grows one at a time, but alloc 12 at a time */ if(cw->cury >= cw->rows) { char **tmp; cw->rows += 12; tmp = (char **) alloc(sizeof(char *) * (unsigned)cw->rows); for(i=0; imaxrow; i++) tmp[i] = cw->data[i]; if(cw->data) free((genericptr_t)cw->data); cw->data = tmp; for(i=cw->maxrow; irows; i++) cw->data[i] = 0; } if(cw->data[cw->cury]) free((genericptr_t)cw->data[cw->cury]); n0 = strlen(str) + 1; ob = cw->data[cw->cury] = (char *)alloc((unsigned)n0 + 1); *ob++ = (char)(attr + 1); /* avoid nuls, for convenience */ Strcpy(ob, str); if(n0 > cw->maxcol) cw->maxcol = n0; if(++cw->cury > cw->maxrow) cw->maxrow = cw->cury; if(n0 > CO) { /* attempt to break the line */ for(i = CO-1; i && str[i] != ' ' && str[i] != '\n';) i--; if(i) { cw->data[cw->cury-1][++i] = '\0'; tty_putstr(window, attr, &str[i]); } } break; } } void tty_display_file(fname, complain) const char *fname; boolean complain; { #ifdef DEF_PAGER /* this implies that UNIX is defined */ { /* use external pager; this may give security problems */ register int fd = open(fname, 0); if(fd < 0) { if(complain) pline("Cannot open %s.", fname); else docrt(); return; } if(child(1)) { /* Now that child() does a setuid(getuid()) and a chdir(), we may not be able to open file fname anymore, so make it stdin. */ (void) close(0); if(dup(fd)) { if(complain) raw_printf("Cannot open %s as stdin.", fname); } else { (void) execlp(catmore, "page", (char *)0); if(complain) raw_printf("Cannot exec %s.", catmore); } if(complain) sleep(10); /* want to wait_synch() but stdin is gone */ terminate(EXIT_FAILURE); } (void) close(fd); } #else /* DEF_PAGER */ { dlb *f; char buf[BUFSZ]; char *cr; tty_clear_nhwindow(WIN_MESSAGE); f = dlb_fopen(fname, "r"); if (!f) { if(complain) { home(); tty_mark_synch(); tty_raw_print(""); perror(fname); tty_wait_synch(); pline("Cannot open \"%s\".", fname); } else if(u.ux) docrt(); } else { winid datawin = tty_create_nhwindow(NHW_TEXT); boolean empty = TRUE; if(complain #ifndef NO_TERMS && nh_CD #endif ) { /* attempt to scroll text below map window if there's room */ wins[datawin]->offy = wins[WIN_STATUS]->offy+3; if((int) wins[datawin]->offy + 12 > (int) ttyDisplay->rows) wins[datawin]->offy = 0; } while (dlb_fgets(buf, BUFSZ, f)) { if ((cr = index(buf, '\n')) != 0) *cr = 0; #ifdef MSDOS if ((cr = index(buf, '\r')) != 0) *cr = 0; #endif if (index(buf, '\t') != 0) (void) tabexpand(buf); empty = FALSE; tty_putstr(datawin, 0, buf); if(wins[datawin]->flags & WIN_CANCELLED) break; } if (!empty) tty_display_nhwindow(datawin, FALSE); tty_destroy_nhwindow(datawin); (void) dlb_fclose(f); } } #endif /* DEF_PAGER */ } void tty_start_menu(window) winid window; { tty_clear_nhwindow(window); return; } /*ARGSUSED*/ /* * Add a menu item to the beginning of the menu list. This list is reversed * later. */ void tty_add_menu(window, glyph, identifier, ch, gch, attr, str, preselected) winid window; /* window to use, must be of type NHW_MENU */ int glyph; /* glyph to display with item (unused) */ const anything *identifier; /* what to return if selected */ char ch; /* keyboard accelerator (0 = pick our own) */ char gch; /* group accelerator (0 = no group) */ int attr; /* attribute for string (like tty_putstr()) */ const char *str; /* menu string */ boolean preselected; /* item is marked as selected */ { register struct WinDesc *cw = 0; tty_menu_item *item; const char *newstr; char buf[4+BUFSZ]; if (str == (const char*) 0) return; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 || cw->type != NHW_MENU) panic(winpanicstr, window); cw->nitems++; if (identifier->a_void) { int len = strlen(str); if (len >= BUFSZ) { /* We *think* everything's coming in off at most BUFSZ bufs... */ impossible("Menu item too long (%d).", len); len = BUFSZ - 1; } Sprintf(buf, "%c - ", ch ? ch : '?'); (void) strncpy(buf+4, str, len); buf[4+len] = '\0'; newstr = buf; } else newstr = str; item = (tty_menu_item *) alloc(sizeof(tty_menu_item)); item->identifier = *identifier; item->count = -1L; item->selected = preselected; item->selector = ch; item->gselector = gch; item->attr = attr; item->str = copy_of(newstr); item->next = cw->mlist; cw->mlist = item; } /* Invert the given list, can handle NULL as an input. */ STATIC_OVL tty_menu_item * reverse(curr) tty_menu_item *curr; { tty_menu_item *next, *head = 0; while (curr) { next = curr->next; curr->next = head; head = curr; curr = next; } return head; } /* * End a menu in this window, window must a type NHW_MENU. This routine * processes the string list. We calculate the # of pages, then assign * keyboard accelerators as needed. Finally we decide on the width and * height of the window. */ void tty_end_menu(window, prompt) winid window; /* menu to use */ const char *prompt; /* prompt to for menu */ { struct WinDesc *cw = 0; tty_menu_item *curr; short len; int lmax, n; char menu_ch; if (window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 || cw->type != NHW_MENU) panic(winpanicstr, window); /* Reverse the list so that items are in correct order. */ cw->mlist = reverse(cw->mlist); /* Put the promt at the beginning of the menu. */ if (prompt) { anything any; any.a_void = 0; /* not selectable */ tty_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, "", MENU_UNSELECTED); tty_add_menu(window, NO_GLYPH, &any, 0, 0, ATR_NONE, prompt, MENU_UNSELECTED); } lmax = min(52, (int)ttyDisplay->rows - 1); /* # lines per page */ cw->npages = (cw->nitems + (lmax - 1)) / lmax; /* # of pages */ /* make sure page list is large enough */ if (cw->plist_size < cw->npages+1 /*need 1 slot beyond last*/) { if (cw->plist) free((genericptr_t)cw->plist); cw->plist_size = cw->npages + 1; cw->plist = (tty_menu_item **) alloc(cw->plist_size * sizeof(tty_menu_item *)); } cw->cols = 0; /* cols is set when the win is initialized... (why?) */ menu_ch = '?'; /* lint suppression */ for (n = 0, curr = cw->mlist; curr; n++, curr = curr->next) { /* set page boundaries and character accelerators */ if ((n % lmax) == 0) { menu_ch = 'a'; cw->plist[n/lmax] = curr; } if (curr->identifier.a_void && !curr->selector) { curr->str[0] = curr->selector = menu_ch; if (menu_ch++ == 'z') menu_ch = 'A'; } /* cut off any lines that are too long */ len = strlen(curr->str) + 2; /* extra space at beg & end */ if (len > (int)ttyDisplay->cols) { curr->str[ttyDisplay->cols-2] = 0; len = ttyDisplay->cols; } if (len > cw->cols) cw->cols = len; } cw->plist[cw->npages] = 0; /* plist terminator */ /* * If greater than 1 page, morestr is "(x of y) " otherwise, "(end) " */ if (cw->npages > 1) { char buf[QBUFSZ]; /* produce the largest demo string */ Sprintf(buf, "(%d of %d) ", cw->npages, cw->npages); len = strlen(buf); cw->morestr = copy_of(""); } else { cw->morestr = copy_of("(end) "); len = strlen(cw->morestr); } if (len > (int)ttyDisplay->cols) { /* truncate the prompt if its too long for the screen */ if (cw->npages <= 1) /* only str in single page case */ cw->morestr[ttyDisplay->cols] = 0; len = ttyDisplay->cols; } if (len > cw->cols) cw->cols = len; cw->maxcol = cw->cols; /* * The number of lines in the first page plus the morestr will be the * maximum size of the window. */ if (cw->npages > 1) cw->maxrow = cw->rows = lmax + 1; else cw->maxrow = cw->rows = cw->nitems + 1; } int tty_select_menu(window, how, menu_list) winid window; int how; menu_item **menu_list; { register struct WinDesc *cw = 0; tty_menu_item *curr; menu_item *mi; int n, cancelled; if(window == WIN_ERR || (cw = wins[window]) == (struct WinDesc *) 0 || cw->type != NHW_MENU) panic(winpanicstr, window); *menu_list = (menu_item *) 0; cw->how = (short) how; morc = 0; tty_display_nhwindow(window, TRUE); cancelled = !!(cw->flags & WIN_CANCELLED); tty_dismiss_nhwindow(window); /* does not destroy window data */ if (cancelled) { n = -1; } else { for (n = 0, curr = cw->mlist; curr; curr = curr->next) if (curr->selected) n++; } if (n > 0) { *menu_list = (menu_item *) alloc(n * sizeof(menu_item)); for (mi = *menu_list, curr = cw->mlist; curr; curr = curr->next) if (curr->selected) { mi->item = curr->identifier; mi->count = curr->count; mi++; } } return n; } /* special hack for treating top line --More-- as a one item menu */ char tty_message_menu(let, how, mesg) char let; int how; const char *mesg; { /* "menu" without selection; use ordinary pline, no more() */ if (how == PICK_NONE) { pline("%s", mesg); return 0; } ttyDisplay->dismiss_more = let; morc = 0; /* barebones pline(); since we're only supposed to be called after response to a prompt, we'll assume that the display is up to date */ tty_putstr(WIN_MESSAGE, 0, mesg); /* if `mesg' didn't wrap (triggering --More--), force --More-- now */ if (ttyDisplay->toplin == 1) { more(); ttyDisplay->toplin = 1; /* more resets this */ tty_clear_nhwindow(WIN_MESSAGE); } /* normally means skip further messages, but in this case it means cancel the current prompt; any other messages should continue to be output normally */ wins[WIN_MESSAGE]->flags &= ~WIN_CANCELLED; ttyDisplay->dismiss_more = 0; return ((how == PICK_ONE && morc == let) || morc == '\033') ? morc : '\0'; } void tty_update_inventory() { return; } void tty_mark_synch() { (void) fflush(stdout); } void tty_wait_synch() { /* we just need to make sure all windows are synch'd */ if(!ttyDisplay || ttyDisplay->rawprint) { getret(); if(ttyDisplay) ttyDisplay->rawprint = 0; } else { tty_display_nhwindow(WIN_MAP, FALSE); if(ttyDisplay->inmore) { addtopl("--More--"); (void) fflush(stdout); } else if(ttyDisplay->inread > program_state.gameover) { /* this can only happen if we were reading and got interrupted */ ttyDisplay->toplin = 3; /* do this twice; 1st time gets the Quit? message again */ (void) tty_doprev_message(); (void) tty_doprev_message(); ttyDisplay->intr++; (void) fflush(stdout); } } } void docorner(xmin, ymax) register int xmin, ymax; { register int y; register struct WinDesc *cw = wins[WIN_MAP]; if (u.uswallow) { /* Can be done more efficiently */ swallowed(1); return; } #if defined(SIGWINCH) && defined(CLIPPING) if(ymax > LI) ymax = LI; /* can happen if window gets smaller */ #endif for (y = 0; y < ymax; y++) { tty_curs(BASE_WINDOW, xmin,y); /* move cursor */ cl_end(); /* clear to end of line */ #ifdef CLIPPING if (y<(int) cw->offy || y+clipy > ROWNO) continue; /* only refresh board */ #if defined(USE_TILES) && defined(MSDOS) if (iflags.tile_view) row_refresh((xmin/2)+clipx-((int)cw->offx/2),COLNO-1,y+clipy-(int)cw->offy); else #endif row_refresh(xmin+clipx-(int)cw->offx,COLNO-1,y+clipy-(int)cw->offy); #else if (yoffy || y > ROWNO) continue; /* only refresh board */ row_refresh(xmin-(int)cw->offx,COLNO-1,y-(int)cw->offy); #endif } end_glyphout(); if (ymax >= (int) wins[WIN_STATUS]->offy) { /* we have wrecked the bottom line */ flags.botlx = 1; bot(); } } void end_glyphout() { #if defined(ASCIIGRAPH) && !defined(NO_TERMS) if (GFlag) { GFlag = FALSE; graph_off(); } #endif #ifdef TEXTCOLOR if(ttyDisplay->color != NO_COLOR) { term_end_color(); ttyDisplay->color = NO_COLOR; } #endif } #ifndef WIN32 void g_putch(in_ch) int in_ch; { register char ch = (char)in_ch; # if defined(ASCIIGRAPH) && !defined(NO_TERMS) if (iflags.IBMgraphics || iflags.eight_bit_tty) { /* IBM-compatible displays don't need other stuff */ (void) putchar(ch); } else if (ch & 0x80) { if (!GFlag || HE_resets_AS) { graph_on(); GFlag = TRUE; } (void) putchar((ch ^ 0x80)); /* Strip 8th bit */ } else { if (GFlag) { graph_off(); GFlag = FALSE; } (void) putchar(ch); } #else (void) putchar(ch); #endif /* ASCIIGRAPH && !NO_TERMS */ return; } #endif /* !WIN32 */ #ifdef CLIPPING void setclipped() { clipping = TRUE; clipx = clipy = 0; clipxmax = CO; clipymax = LI - 3; } void tty_cliparound(x, y) int x, y; { extern boolean restoring; int oldx = clipx, oldy = clipy; if (!clipping) return; if (x < clipx + 5) { clipx = max(0, x - 20); clipxmax = clipx + CO; } else if (x > clipxmax - 5) { clipxmax = min(COLNO, clipxmax + 20); clipx = clipxmax - CO; } if (y < clipy + 2) { clipy = max(0, y - (clipymax - clipy) / 2); clipymax = clipy + (LI - 3); } else if (y > clipymax - 2) { clipymax = min(ROWNO, clipymax + (clipymax - clipy) / 2); clipy = clipymax - (LI - 3); } if (clipx != oldx || clipy != oldy) { if (on_level(&u.uz0, &u.uz) && !restoring) (void) doredraw(); } } #endif /* CLIPPING */ /* * tty_print_glyph * * Print the glyph to the output device. Don't flush the output device. * * Since this is only called from show_glyph(), it is assumed that the * position and glyph are always correct (checked there)! */ void tty_print_glyph(window, x, y, glyph) winid window; xchar x, y; int glyph; { int ch; boolean reverse_on = FALSE; int color; unsigned special; #ifdef CLIPPING if(clipping) { if(x <= clipx || y < clipy || x >= clipxmax || y >= clipymax) return; } #endif /* map glyph to character and color */ mapglyph(glyph, &ch, &color, &special, x, y); /* Move the cursor. */ tty_curs(window, x,y); #ifndef NO_TERMS if (ul_hack && ch == '_') { /* non-destructive underscore */ (void) putchar((char) ' '); backsp(); } #endif #ifdef TEXTCOLOR if (color != ttyDisplay->color) { if(ttyDisplay->color != NO_COLOR) term_end_color(); ttyDisplay->color = color; if(color != NO_COLOR) term_start_color(color); } #endif /* TEXTCOLOR */ /* must be after color check; term_end_color may turn off inverse too */ if (((special & MG_PET) && iflags.hilite_pet) || ((special & MG_DETECT) && iflags.use_inverse)) { term_start_attr(ATR_INVERSE); reverse_on = TRUE; } #if defined(USE_TILES) && defined(MSDOS) if (iflags.grmode && iflags.tile_view) xputg(glyph,ch,special); else #endif g_putch(ch); /* print the character */ if (reverse_on) { term_end_attr(ATR_INVERSE); #ifdef TEXTCOLOR /* turn off color as well, ATR_INVERSE may have done this already */ if(ttyDisplay->color != NO_COLOR) { term_end_color(); ttyDisplay->color = NO_COLOR; } #endif } wins[window]->curx++; /* one character over */ ttyDisplay->curx++; /* the real cursor moved too */ } void tty_raw_print(str) const char *str; { if(ttyDisplay) ttyDisplay->rawprint++; #if defined(MICRO) || defined(WIN32CON) msmsg("%s\n", str); #else puts(str); (void) fflush(stdout); #endif } void tty_raw_print_bold(str) const char *str; { if(ttyDisplay) ttyDisplay->rawprint++; term_start_raw_bold(); #if defined(MICRO) || defined(WIN32CON) msmsg("%s", str); #else (void) fputs(str, stdout); #endif term_end_raw_bold(); #if defined(MICRO) || defined(WIN32CON) msmsg("\n"); #else puts(""); (void) fflush(stdout); #endif } int tty_nhgetch() { int i; #ifdef UNIX /* kludge alert: Some Unix variants return funny values if getc() * is called, interrupted, and then called again. There * is non-reentrant code in the internal _filbuf() routine, called by * getc(). */ static volatile int nesting = 0; char nestbuf; #endif (void) fflush(stdout); /* Note: if raw_print() and wait_synch() get called to report terminal * initialization problems, then wins[] and ttyDisplay might not be * available yet. Such problems will probably be fatal before we get * here, but validate those pointers just in case... */ if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE]) wins[WIN_MESSAGE]->flags &= ~WIN_STOP; #ifdef UNIX i = ((++nesting == 1) ? tgetch() : (read(fileno(stdin), (genericptr_t)&nestbuf,1) == 1 ? (int)nestbuf : EOF)); --nesting; #else i = tgetch(); #endif if (!i) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ if (ttyDisplay && ttyDisplay->toplin == 1) ttyDisplay->toplin = 2; return i; } /* * return a key, or 0, in which case a mouse button was pressed * mouse events should be returned as character postitions in the map window. * Since normal tty's don't have mice, just return a key. */ /*ARGSUSED*/ int tty_nh_poskey(x, y, mod) int *x, *y, *mod; { # if defined(WIN32CON) int i; (void) fflush(stdout); /* Note: if raw_print() and wait_synch() get called to report terminal * initialization problems, then wins[] and ttyDisplay might not be * available yet. Such problems will probably be fatal before we get * here, but validate those pointers just in case... */ if (WIN_MESSAGE != WIN_ERR && wins[WIN_MESSAGE]) wins[WIN_MESSAGE]->flags &= ~WIN_STOP; i = ntposkey(x, y, mod); if (!i && mod && *mod == 0) i = '\033'; /* map NUL to ESC since nethack doesn't expect NUL */ if (ttyDisplay && ttyDisplay->toplin == 1) ttyDisplay->toplin = 2; return i; # else return tty_nhgetch(); # endif } void win_tty_init() { # if defined(WIN32CON) nttty_open(); # endif return; } #ifdef POSITIONBAR void tty_update_positionbar(posbar) char *posbar; { # ifdef MSDOS video_update_positionbar(posbar); # endif } #endif /* * Allocate a copy of the given string. If null, return a string of * zero length. * * This is an exact duplicate of copy_of() in X11/winmenu.c. */ static char * copy_of(s) const char *s; { if (!s) s = ""; return strcpy((char *) alloc((unsigned) (strlen(s) + 1)), s); } #endif /* TTY_GRAPHICS */ /*wintty.c*/ nethack-3.4.3/win/win32/0040755000000000000000000000000007764735152013417 5ustar rootrootnethack-3.4.3/win/win32/dgncomp.dsp0100644000000000000000000002031207764735152015551 0ustar rootroot# Microsoft Developer Studio Project File - Name="dgncomp" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=dgncomp - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "dgncomp.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "dgncomp.mak" CFG="dgncomp - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "dgncomp - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "dgncomp - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "dgncomp - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "..\util" # PROP BASE Intermediate_Dir "dgncomp___Win32_Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "..\util" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x1009 /d "NDEBUG" # ADD RSC /l 0x1009 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\dgn_comp.exe" # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=dgncomp PostBuild_Cmds=echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgn_comp.exe dungeon.pdf ..\util\dgn_comp.exe dungeon.pdf echo chdir ..\build chdir ..\build # End Special Build Tool !ELSEIF "$(CFG)" == "dgncomp - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "dgncomp___Win32_Debug" # PROP BASE Intermediate_Dir "dgncomp___Win32_Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "..\util" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c # ADD BASE RSC /l 0x1009 /d "_DEBUG" # ADD RSC /l 0x1009 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\dgn_comp.exe" /pdbtype:sept # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=dgncomp PostBuild_Cmds=echo Building dungeon echo chdir ..\dat chdir ..\dat echo ..\util\dgn_comp.exe dungeon.pdf ..\util\dgn_comp.exe dungeon.pdf echo chdir ..\build chdir ..\build # End Special Build Tool !ENDIF # Begin Target # Name "dgncomp - Win32 Release" # Name "dgncomp - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\src\alloc.c # End Source File # Begin Source File SOURCE=..\util\dgn_lex.c # End Source File # Begin Source File SOURCE=..\util\dgn_main.c # End Source File # Begin Source File SOURCE=..\util\dgn_yacc.c # End Source File # Begin Source File SOURCE=..\util\panic.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\align.h # End Source File # Begin Source File SOURCE=..\include\attrib.h # End Source File # Begin Source File SOURCE=..\include\color.h # End Source File # Begin Source File SOURCE=..\include\config.h # End Source File # Begin Source File SOURCE=..\include\config1.h # End Source File # Begin Source File SOURCE=..\include\coord.h # End Source File # Begin Source File SOURCE=..\include\decl.h # End Source File # Begin Source File SOURCE=..\include\dgn_comp.h # End Source File # Begin Source File SOURCE=..\include\dgn_file.h # End Source File # Begin Source File SOURCE=..\include\display.h # End Source File # Begin Source File SOURCE=..\include\dungeon.h # End Source File # Begin Source File SOURCE=..\include\engrave.h # End Source File # Begin Source File SOURCE=..\include\flag.h # End Source File # Begin Source File SOURCE=..\include\global.h # End Source File # Begin Source File SOURCE=..\include\mkroom.h # End Source File # Begin Source File SOURCE=..\include\monattk.h # End Source File # Begin Source File SOURCE=..\include\monst.h # End Source File # Begin Source File SOURCE=..\include\monsym.h # End Source File # Begin Source File SOURCE=..\include\nhlan.h # End Source File # Begin Source File SOURCE=..\include\ntconf.h # End Source File # Begin Source File SOURCE=..\include\obj.h # End Source File # Begin Source File SOURCE=..\include\objclass.h # End Source File # Begin Source File SOURCE=..\include\onames.h # End Source File # Begin Source File SOURCE=..\include\permonst.h # End Source File # Begin Source File SOURCE=..\include\pm.h # End Source File # Begin Source File SOURCE=..\include\prop.h # End Source File # Begin Source File SOURCE=..\include\quest.h # End Source File # Begin Source File SOURCE=..\include\rect.h # End Source File # Begin Source File SOURCE=..\include\region.h # End Source File # Begin Source File SOURCE=..\include\rm.h # End Source File # Begin Source File SOURCE=..\include\skills.h # End Source File # Begin Source File SOURCE=..\include\spell.h # End Source File # Begin Source File SOURCE=..\include\timeout.h # End Source File # Begin Source File SOURCE=..\include\tradstdc.h # End Source File # Begin Source File SOURCE=..\include\trampoli.h # End Source File # Begin Source File SOURCE=..\include\trap.h # End Source File # Begin Source File SOURCE=..\include\vision.h # End Source File # Begin Source File SOURCE=..\include\winprocs.h # End Source File # Begin Source File SOURCE=..\include\wintty.h # End Source File # Begin Source File SOURCE=..\include\wintype.h # End Source File # Begin Source File SOURCE=..\include\you.h # End Source File # Begin Source File SOURCE=..\include\youprop.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/dgnstuff.dsp0100644000000000000000000000534307764735152015751 0ustar rootroot# Microsoft Developer Studio Project File - Name="dgnstuff" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) External Target" 0x0106 CFG=dgnstuff - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "dgnstuff.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "dgnstuff.mak" CFG="dgnstuff - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "dgnstuff - Win32 Release" (based on "Win32 (x86) External Target") !MESSAGE "dgnstuff - Win32 Debug" (based on "Win32 (x86) External Target") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" !IF "$(CFG)" == "dgnstuff - Win32 Release" # PROP BASE Use_MFC # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Cmd_Line "NMAKE /f dgnstuff.mak" # PROP BASE Rebuild_Opt "/a" # PROP BASE Target_File "dgnstuff.exe" # PROP BASE Bsc_Name "dgnstuff.bsc" # PROP BASE Target_Dir "" # PROP Use_MFC # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Cmd_Line "nmake /f "dgnstuff.mak"" # PROP Rebuild_Opt "/a" # PROP Target_File "..\util\dgncomp.exe" # PROP Bsc_Name "" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "dgnstuff - Win32 Debug" # PROP BASE Use_MFC # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Cmd_Line "NMAKE /f dgnstuff.mak" # PROP BASE Rebuild_Opt "/a" # PROP BASE Target_File "dgnstuff.exe" # PROP BASE Bsc_Name "dgnstuff.bsc" # PROP BASE Target_Dir "" # PROP Use_MFC # PROP Use_Debug_Libraries 1 # PROP Output_Dir "dgnstuff___Win32_Debug" # PROP Intermediate_Dir "Debug" # PROP Cmd_Line "nmake /f "dgnstuff.mak"" # PROP Rebuild_Opt "/a" # PROP Target_File "..\util\dgncomp.exe" # PROP Bsc_Name "" # PROP Target_Dir "" !ENDIF # Begin Target # Name "dgnstuff - Win32 Release" # Name "dgnstuff - Win32 Debug" !IF "$(CFG)" == "dgnstuff - Win32 Release" !ELSEIF "$(CFG)" == "dgnstuff - Win32 Debug" !ENDIF # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/dgnstuff.mak0100644000000000000000000000235207764735042015726 0ustar rootroot#Set all of these or none of them #YACC = byacc.exe #LEX = flex.exe #YTABC = y_tab.c #YTABH = y_tab.h #LEXYYC = lexyy.c !IF "$(YACC)"!="" @echo Yacc-alike set to $(YACC) @echo YTABC set to $(YTABC) @echo YTABH set to $(YTABH) !ENDIF !IF "$(LEX)"!="" @echo Lex-alike set to $(LEX) @echo LEXYYC set to $(LEXYYC) !ENDIF default: all all: ..\util\dgn_yacc.c ..\util\dgn_lex.c rebuild: clean all clean: -del ..\util\dgn_lex.c -del ..\util\dgn_yacc.c -del ..\include\dgn_comp.h #========================================== # Dungeon Compiler Stuff #========================================== ..\util\dgn_yacc.c ..\include\dgn_comp.h : ..\util\dgn_comp.y !IF "$(YACC)"=="" @echo Using pre-built dgn_yacc.c and dgn_comp.h @copy ..\sys\share\dgn_yacc.c ..\util\dgn_yacc.c @copy ..\sys\share\dgn_comp.h ..\include\dgn_comp.h !ELSE chdir ..\util $(YACC) -d dgn_comp.y copy $(YTABC) $@ copy $(YTABH) ..\include\dgn_comp.h @del $(YTABC) @del $(YTABH) chdir ..\build !ENDIF ..\util\dgn_lex.c: ..\util\dgn_comp.l !IF "$(LEX)"=="" @echo Using pre-built dgn_lex.c @copy ..\sys\share\dgn_lex.c $@ !ELSE chdir ..\util $(LEX) dgn_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) chdir ..\build !ENDIF nethack-3.4.3/win/win32/dlb_main.dsp0100644000000000000000000001525107764735152015675 0ustar rootroot# Microsoft Developer Studio Project File - Name="dlb_main" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=dlb_main - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "dlb_main.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "dlb_main.mak" CFG="dlb_main - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "dlb_main - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "dlb_main - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "dlb_main - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "DLB" /D "WIN32CON" /D "MSWIN_GRAPHICS" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x1009 /d "NDEBUG" # ADD RSC /l 0x1009 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\dlb_main.exe" # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=Packaging via DLB PostBuild_Cmds=echo chdir ..\dat \ chdir ..\dat \ chdir \ echo data >dlb.lst \ echo oracles >>dlb.lst \ if exist options echo options >>dlb.lst \ if exist ttyoptions echo ttyoptions >>dlb.lst \ if exist guioptions echo guioptions >>dlb.lst \ if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp \ if exist porthelp echo porthelp >>dlb.lst \ echo quest.dat >>dlb.lst \ echo rumors >>dlb.lst \ echo help >>dlb.lst \ echo hh >>dlb.lst \ echo cmdhelp >>dlb.lst \ echo history >>dlb.lst \ echo opthelp >>dlb.lst \ echo wizhelp >>dlb.lst \ echo dungeon >>dlb.lst \ echo license >>dlb.lst \ for %%N in (*.lev) do echo %%N >>dlb.lst \ ..\util\dlb_main.exe cIf dlb.lst nhdat \ echo chdir ..\build \ chdir ..\build \ echo if NOT exist ..\binary\*.* mkdir ..\binary \ if NOT exist ..\binary\*.* mkdir ..\binary # End Special Build Tool !ELSEIF "$(CFG)" == "dlb_main - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "DLB" /D "WIN32CON" /D "MSWIN_GRAPHICS" /FD /GZ /c # ADD BASE RSC /l 0x1009 /d "_DEBUG" # ADD RSC /l 0x1009 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\dlb_main.exe" /pdbtype:sept # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=Packaging via dlb PostBuild_Cmds=echo chdir ..\dat \ chdir ..\dat \ chdir \ echo data >dlb.lst \ echo oracles >>dlb.lst \ if exist options echo options >>dlb.lst \ if exist ttyoptions echo ttyoptions >>dlb.lst \ if exist guioptions echo guioptions >>dlb.lst \ if NOT exist porthelp copy ..\sys\winnt\porthelp porthelp \ if exist porthelp echo porthelp >>dlb.lst \ echo quest.dat >>dlb.lst \ echo rumors >>dlb.lst \ echo help >>dlb.lst \ echo hh >>dlb.lst \ echo cmdhelp >>dlb.lst \ echo history >>dlb.lst \ echo opthelp >>dlb.lst \ echo wizhelp >>dlb.lst \ echo dungeon >>dlb.lst \ echo license >>dlb.lst \ for %%N in (*.lev) do echo %%N >>dlb.lst \ ..\util\dlb_main.exe cIf dlb.lst nhdat \ echo chdir ..\build \ chdir ..\build \ echo if NOT exist ..\binary\*.* mkdir ..\binary \ if NOT exist ..\binary\*.* mkdir ..\binary # End Special Build Tool !ENDIF # Begin Target # Name "dlb_main - Win32 Release" # Name "dlb_main - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\src\alloc.c # End Source File # Begin Source File SOURCE=..\src\dlb.c # End Source File # Begin Source File SOURCE=..\util\dlb_main.c # End Source File # Begin Source File SOURCE=..\util\panic.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\dlb.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/levcomp.dsp0100644000000000000000000001747007764735152015602 0ustar rootroot# Microsoft Developer Studio Project File - Name="levcomp" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=levcomp - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "levcomp.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "levcomp.mak" CFG="levcomp - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "levcomp - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "levcomp - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "levcomp - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "..\util" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x1009 /d "NDEBUG" # ADD RSC /l 0x1009 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=levcomp PostBuild_Cmds=echo Building special levels echo chdir ..\dat chdir ..\dat \ echo arch.des ..\util\levcomp.exe arch.des \ echo barb.des ..\util\levcomp.exe barb.des \ echo bigroom.des ..\util\levcomp.exe bigroom.des \ echo castle.des ..\util\levcomp.exe castle.des \ echo caveman.des ..\util\levcomp.exe caveman.des \ echo endgame.des ..\util\levcomp.exe endgame.des \ echo gehennom.des ..\util\levcomp.exe gehennom.des \ echo healer.des ..\util\levcomp.exe healer.des \ echo knight.des ..\util\levcomp.exe knight.des \ echo knox.des ..\util\levcomp.exe knox.des \ echo medusa.des ..\util\levcomp.exe medusa.des \ echo mines.des ..\util\levcomp.exe mines.des \ echo monk.des ..\util\levcomp.exe monk.des \ echo oracle.des ..\util\levcomp.exe oracle.des \ echo priest.des ..\util\levcomp.exe priest.des \ echo ranger.des ..\util\levcomp.exe ranger.des \ echo rogue.des ..\util\levcomp.exe rogue.des \ echo samurai.des ..\util\levcomp.exe samurai.des \ echo sokoban.des ..\util\levcomp.exe sokoban.des \ echo tourist.des ..\util\levcomp.exe tourist.des \ echo tower.des ..\util\levcomp.exe tower.des \ echo valkyrie.des ..\util\levcomp.exe valkyrie.des \ echo wizard .des ..\util\levcomp.exe wizard.des \ echo yendor.des ..\util\levcomp.exe yendor.des \ echo chdir ..\build chdir ..\build # End Special Build Tool !ELSEIF "$(CFG)" == "levcomp - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "..\util" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c # ADD BASE RSC /l 0x1009 /d "_DEBUG" # ADD RSC /l 0x1009 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=levcomp PostBuild_Cmds=echo Building special levels echo chdir ..\dat chdir ..\dat \ echo arch.des ..\util\levcomp.exe arch.des \ echo barb.des ..\util\levcomp.exe barb.des \ echo bigroom.des ..\util\levcomp.exe bigroom.des \ echo castle.des ..\util\levcomp.exe castle.des \ echo caveman.des ..\util\levcomp.exe caveman.des \ echo endgame.des ..\util\levcomp.exe endgame.des \ echo gehennom.des ..\util\levcomp.exe gehennom.des \ echo healer.des ..\util\levcomp.exe healer.des \ echo knight.des ..\util\levcomp.exe knight.des \ echo knox.des ..\util\levcomp.exe knox.des \ echo medusa.des ..\util\levcomp.exe medusa.des \ echo mines.des ..\util\levcomp.exe mines.des \ echo monk.des ..\util\levcomp.exe monk.des \ echo oracle.des ..\util\levcomp.exe oracle.des \ echo priest.des ..\util\levcomp.exe priest.des \ echo ranger.des ..\util\levcomp.exe ranger.des \ echo rogue.des ..\util\levcomp.exe rogue.des \ echo samurai.des ..\util\levcomp.exe samurai.des \ echo sokoban.des ..\util\levcomp.exe sokoban.des \ echo tourist.des ..\util\levcomp.exe tourist.des \ echo tower.des ..\util\levcomp.exe tower.des \ echo valkyrie.des ..\util\levcomp.exe valkyrie.des \ echo wizard .des ..\util\levcomp.exe wizard.des \ echo yendor.des ..\util\levcomp.exe yendor.des \ echo chdir ..\build chdir ..\build # End Special Build Tool !ENDIF # Begin Target # Name "levcomp - Win32 Release" # Name "levcomp - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\src\alloc.c # End Source File # Begin Source File SOURCE=..\src\decl.c # End Source File # Begin Source File SOURCE=..\src\drawing.c # End Source File # Begin Source File SOURCE=..\util\lev_lex.c # End Source File # Begin Source File SOURCE=..\util\lev_main.c # End Source File # Begin Source File SOURCE=..\util\lev_yacc.c # End Source File # Begin Source File SOURCE=..\src\monst.c # End Source File # Begin Source File SOURCE=..\src\objects.c # End Source File # Begin Source File SOURCE=..\util\panic.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\lev_comp.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/levstuff.dsp0100644000000000000000000000543607764735152015772 0ustar rootroot# Microsoft Developer Studio Project File - Name="levstuff" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) External Target" 0x0106 CFG=levstuff - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "levstuff.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "levstuff.mak" CFG="levstuff - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "levstuff - Win32 Release" (based on "Win32 (x86) External Target") !MESSAGE "levstuff - Win32 Debug" (based on "Win32 (x86) External Target") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" !IF "$(CFG)" == "levstuff - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Cmd_Line "NMAKE /f levstuff.mak" # PROP BASE Rebuild_Opt "/a" # PROP BASE Target_File "levstuff.exe" # PROP BASE Bsc_Name "levstuff.bsc" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Cmd_Line "nmake /f "levstuff.mak"" # PROP Rebuild_Opt "/a" # PROP Target_File "..\util\lev_lex.c" # PROP Bsc_Name "" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "levstuff - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "levstuff___Win32_Debug0" # PROP BASE Intermediate_Dir "levstuff___Win32_Debug0" # PROP BASE Cmd_Line "NMAKE /f levstuff.mak" # PROP BASE Rebuild_Opt "/a" # PROP BASE Target_File "levstuff.exe" # PROP BASE Bsc_Name "levstuff.bsc" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "levstuff___Win32_Debug0" # PROP Intermediate_Dir "levstuff___Win32_Debug0" # PROP Cmd_Line "nmake /f "levstuff.mak"" # PROP Rebuild_Opt "/a" # PROP Target_File "..\util\lev_lex.c" # PROP Bsc_Name "" # PROP Target_Dir "" !ENDIF # Begin Target # Name "levstuff - Win32 Release" # Name "levstuff - Win32 Debug" !IF "$(CFG)" == "levstuff - Win32 Release" !ELSEIF "$(CFG)" == "levstuff - Win32 Debug" !ENDIF # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/levstuff.mak0100644000000000000000000000230607764735042015743 0ustar rootroot#YACC = byacc.exe #LEX = flex.exe #YTABC = y_tab.c #YTABH = y_tab.h #LEXYYC = lexyy.c !IF "$(YACC)"!="" @echo Yacc-alike set to $(YACC) @echo YTABC set to $(YTABC) @echo YTABH set to $(YTABH) !ENDIF !IF "$(LEX)"!="" @echo Lex-alike set to $(LEX) @echo LEXYYC set to $(LEXYYC) !ENDIF default: all all: ..\util\lev_yacc.c ..\util\lev_lex.c rebuild: clean all clean: -del ..\util\lev_lex.c -del ..\util\lev_yacc.c -del ..\include\lev_comp.h #========================================== # Level Compiler Stuff #========================================== ..\util\lev_yacc.c ..\include\lev_comp.h: ..\util\lev_comp.y !IF "$(YACC)"=="" @echo Using pre-built lev_yacc.c and lev_comp.h @copy ..\sys\share\lev_yacc.c ..\util\lev_yacc.c @copy ..\sys\share\lev_comp.h ..\include\lev_comp.h !ELSE chdir ..\util $(YACC) -d lev_comp.y copy $(YTABC) $@ copy $(YTABH) ..\include\lev_comp.h @del $(YTABC) @del $(YTABH) chdir ..\build !ENDIF ..\util\lev_lex.c: ..\util\lev_comp.l !IF "$(LEX)"=="" @echo Using pre-built lev_lex.c @copy ..\sys\share\lev_lex.c $@ !ELSE chdir ..\util $(LEX) lev_comp.l copy $(LEXYYC) $@ @del $(LEXYYC) chdir ..\build !ENDIF nethack-3.4.3/win/win32/makedefs.dsp0100644000000000000000000001635007764735152015710 0ustar rootroot# Microsoft Developer Studio Project File - Name="makedefs" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=makedefs - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "makedefs.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "makedefs.mak" CFG="makedefs - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "makedefs - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "makedefs - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "makedefs - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "..\util" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "." /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=Running makedefs PostBuild_Cmds=echo chdir ..\util chdir ..\util chdir \ echo makedefs.exe -v makedefs.exe -v \ echo makedefs.exe -o makedefs.exe -o \ echo makedefs.exe -p makedefs.exe -p \ echo makedefs.exe -m makedefs.exe -m \ echo makedefs.exe -z makedefs.exe -z \ echo chdir ..\dat chdir ..\dat chdir \ echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d \ echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r \ echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q \ echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h \ echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e \ echo chdir ..\build chdir ..\build \ copy ..\win\share\tilemap.c ..\win\share\tiletxt.c # End Special Build Tool !ELSEIF "$(CFG)" == "makedefs - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "..\util" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "." /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /pdbtype:sept # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=Running makedefs PostBuild_Cmds=echo chdir ..\util chdir ..\util chdir \ echo makedefs.exe -v makedefs.exe -v \ echo makedefs.exe -o makedefs.exe -o \ echo makedefs.exe -p makedefs.exe -p \ echo makedefs.exe -m makedefs.exe -m \ echo makedefs.exe -z makedefs.exe -z \ echo chdir ..\dat chdir ..\dat chdir \ echo Generating NetHack database echo ..\util\makedefs.exe -d ..\util\makedefs.exe -d \ echo Generating rumors echo ..\util\makedefs.exe -r ..\util\makedefs.exe -r \ echo Generating quests echo ..\util\makedefs.exe -q ..\util\makedefs.exe -q \ echo Generating oracles echo ..\util\makedefs.exe -h ..\util\makedefs.exe -h \ echo Generating dungeon.pdf echo ..\util\makedefs.exe -e ..\util\makedefs.exe -e \ echo chdir ..\build chdir ..\build \ copy ..\win\share\tilemap.c ..\win\share\tiletxt.c # End Special Build Tool !ENDIF # Begin Target # Name "makedefs - Win32 Release" # Name "makedefs - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\util\makedefs.c # End Source File # Begin Source File SOURCE=..\src\monst.c # End Source File # Begin Source File SOURCE=..\src\objects.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\config.h # End Source File # Begin Source File SOURCE=..\include\config1.h # End Source File # Begin Source File SOURCE=..\include\coord.h # End Source File # Begin Source File SOURCE=..\include\global.h # End Source File # Begin Source File SOURCE=..\include\monattk.h # End Source File # Begin Source File SOURCE=..\include\monflag.h # End Source File # Begin Source File SOURCE=..\include\monsym.h # End Source File # Begin Source File SOURCE=..\include\nhlan.h # End Source File # Begin Source File SOURCE=..\include\ntconf.h # End Source File # Begin Source File SOURCE=..\include\objclass.h # End Source File # Begin Source File SOURCE=..\include\patchlevel.h # End Source File # Begin Source File SOURCE=..\include\qtext.h # End Source File # Begin Source File SOURCE=..\include\tradstdc.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/mhaskyn.c0100644000000000000000000000044207764735042015230 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include #include "winMS.h" #include "mhaskyn.h" int mswin_yes_no_dialog( const char *question, const char *choices, int def) { return '\032'; } nethack-3.4.3/win/win32/mhaskyn.h0100644000000000000000000000046507764735042015242 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINAskYesNO_h #define MSWINAskYesNO_h #include "winMS.h" int mswin_yes_no_dialog( const char *question, const char *choices, int def); #endif /* MSWINAskYesNO_h */ nethack-3.4.3/win/win32/mhdlg.c0100644000000000000000000005410607764735042014657 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* various dialog boxes are defined here */ #include "winMS.h" #include "hack.h" #include "func_tab.h" #include "resource.h" #include "mhdlg.h" /*---------------------------------------------------------------*/ /* data for getlin dialog */ struct getlin_data { const char* question; char* result; size_t result_size; }; BOOL CALLBACK GetlinDlgProc(HWND, UINT, WPARAM, LPARAM); int mswin_getlin_window ( const char *question, char *result, size_t result_size ) { int ret; struct getlin_data data; /* initilize dialog data */ ZeroMemory(&data, sizeof(data)); data.question = question; data.result = result; data.result_size = result_size; /* create modal dialog window */ ret = DialogBoxParam( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_GETLIN), GetNHApp()->hMainWnd, GetlinDlgProc, (LPARAM)&data ); if( ret==-1 ) panic("Cannot create getlin window"); return ret; } BOOL CALLBACK GetlinDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct getlin_data* data; RECT main_rt, dlg_rt; SIZE dlg_sz; TCHAR wbuf[BUFSZ]; HDC WindowDC; HWND ControlHWND; SIZE WindowExtents; SIZE ViewPortExtents; RECT ControlRect; RECT ClientRect; LONG Division; LONG ButtonOffset; switch (message) { case WM_INITDIALOG: data = (struct getlin_data*)lParam; SetWindowText(hWnd, NH_A2W(data->question, wbuf, sizeof(wbuf))); SetWindowLong(hWnd, GWL_USERDATA, lParam); /* center dialog in the main window */ GetWindowRect(hWnd, &dlg_rt); GetWindowRect(GetNHApp()->hMainWnd, &main_rt); WindowDC = GetWindowDC(hWnd); if (!GetWindowExtEx(WindowDC, &WindowExtents) || !GetViewportExtEx(WindowDC, &ViewPortExtents) || !GetTextExtentPoint32(GetWindowDC (hWnd), wbuf, _tcslen(wbuf), &dlg_sz)) { dlg_sz.cx = 0; } else { /* I think we need to do the following scaling */ dlg_sz.cx *= ViewPortExtents.cx; dlg_sz.cx /= WindowExtents.cx; /* Add the size of the various items in the caption bar */ dlg_sz.cx += GetSystemMetrics(SM_CXSIZE) + 2 * (GetSystemMetrics (SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME)); } if (dlg_sz.cx < dlg_rt.right - dlg_rt.left) dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow( hWnd, (main_rt.left+main_rt.right-dlg_sz.cx)/2, (main_rt.top+main_rt.bottom-dlg_sz.cy)/2, dlg_sz.cx, dlg_sz.cy, TRUE ); /* set focus and size of the edit control */ ControlHWND = GetDlgItem(hWnd, IDC_GETLIN_EDIT); SetFocus(ControlHWND); GetClientRect (hWnd, &ClientRect); GetWindowRect (ControlHWND, &ControlRect); MoveWindow (ControlHWND, 0, 0, ClientRect.right - ClientRect.left, ControlRect.bottom - ControlRect.top, TRUE); ButtonOffset = ControlRect.bottom - ControlRect.top; /* Now get the OK and CANCEL buttons */ ControlHWND = GetDlgItem(hWnd, IDOK); GetWindowRect (ControlHWND, &ControlRect); Division = ((ClientRect.right - ClientRect.left) - 2 * (ControlRect.right - ControlRect.left)) / 3; MoveWindow (ControlHWND, Division, ButtonOffset, ControlRect.right - ControlRect.left, ControlRect.bottom - ControlRect.top, TRUE); ControlHWND = GetDlgItem(hWnd, IDCANCEL); MoveWindow (ControlHWND, Division * 2 + ControlRect.right - ControlRect.left, ButtonOffset, ControlRect.right - ControlRect.left, ControlRect.bottom - ControlRect.top, TRUE); /* tell windows that we've set the focus */ return FALSE; break; case WM_COMMAND: { TCHAR wbuf[BUFSZ]; switch (LOWORD(wParam)) { /* OK button was pressed */ case IDOK: data = (struct getlin_data*)GetWindowLong(hWnd, GWL_USERDATA); SendDlgItemMessage(hWnd, IDC_GETLIN_EDIT, WM_GETTEXT, (WPARAM)sizeof(wbuf), (LPARAM)wbuf ); NH_W2A(wbuf, data->result, data->result_size); /* Fall through. */ /* cancel button was pressed */ case IDCANCEL: EndDialog(hWnd, wParam); return TRUE; } } break; } /* end switch (message) */ return FALSE; } /*---------------------------------------------------------------*/ /* dialog data for the list of extended commands */ struct extcmd_data { int* selection; }; BOOL CALLBACK ExtCmdDlgProc(HWND, UINT, WPARAM, LPARAM); int mswin_ext_cmd_window (int* selection) { int ret; struct extcmd_data data; /* init dialog data */ ZeroMemory(&data, sizeof(data)); *selection = -1; data.selection = selection; /* create modal dialog window */ ret = DialogBoxParam( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_EXTCMD), GetNHApp()->hMainWnd, ExtCmdDlgProc, (LPARAM)&data ); if( ret==-1 ) panic("Cannot create extcmd window"); return ret; } BOOL CALLBACK ExtCmdDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct extcmd_data* data; RECT main_rt, dlg_rt; SIZE dlg_sz; int i; const char *ptr; TCHAR wbuf[255]; switch (message) { case WM_INITDIALOG: data = (struct extcmd_data*)lParam; SetWindowLong(hWnd, GWL_USERDATA, lParam); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hWnd, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow( hWnd, (main_rt.left+main_rt.right-dlg_sz.cx)/2, (main_rt.top+main_rt.bottom-dlg_sz.cy)/2, dlg_sz.cx, dlg_sz.cy, TRUE ); /* fill combobox with extended commands */ for(i=0; (ptr=extcmdlist[i].ef_txt); i++) { SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(ptr, wbuf, sizeof(wbuf)) ); } /* set focus to the list control */ SetFocus(GetDlgItem(hWnd, IDC_EXTCMD_LIST)); /* tell windows we set the focus */ return FALSE; break; case WM_COMMAND: data = (struct extcmd_data*)GetWindowLong(hWnd, GWL_USERDATA); switch (LOWORD(wParam)) { /* OK button ws clicked */ case IDOK: *data->selection = SendDlgItemMessage(hWnd, IDC_EXTCMD_LIST, LB_GETCURSEL, (WPARAM)0, (LPARAM)0 ); if( *data->selection==LB_ERR ) *data->selection = -1; /* Fall through. */ /* CANCEL button ws clicked */ case IDCANCEL: EndDialog(hWnd, wParam); return TRUE; /* list control events */ case IDC_EXTCMD_LIST: switch(HIWORD(wParam)) { case LBN_DBLCLK: /* double click within the list wParam The low-order word is the list box identifier. The high-order word is the notification message. lParam Handle to the list box */ *data->selection = SendMessage((HWND)lParam, LB_GETCURSEL, (WPARAM)0, (LPARAM)0); if( *data->selection==LB_ERR ) *data->selection = -1; EndDialog(hWnd, IDOK); return TRUE; } break; } } return FALSE; } /*---------------------------------------------------------------*/ /* player selector dialog data */ struct plsel_data { int* selection; }; BOOL CALLBACK PlayerSelectorDlgProc(HWND, UINT, WPARAM, LPARAM); static void plselInitDialog(HWND hWnd); static void plselAdjustLists(HWND hWnd, int changed_opt); static int plselFinalSelection(HWND hWnd, int* selection); int mswin_player_selection_window ( int* selection ) { int ret; struct plsel_data data; /* init dialog data */ ZeroMemory(&data, sizeof(data)); data.selection = selection; /* create modal dialog */ ret = DialogBoxParam( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_PLAYER_SELECTOR), GetNHApp()->hMainWnd, PlayerSelectorDlgProc, (LPARAM)&data ); if( ret==-1 ) panic("Cannot create getlin window"); return ret; } BOOL CALLBACK PlayerSelectorDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { struct plsel_data* data; RECT main_rt, dlg_rt; SIZE dlg_sz; switch (message) { case WM_INITDIALOG: data = (struct plsel_data*)lParam; SetWindowLong(hWnd, GWL_USERDATA, lParam); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hWnd, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow( hWnd, (main_rt.left+main_rt.right-dlg_sz.cx)/2, (main_rt.top+main_rt.bottom-dlg_sz.cy)/2, dlg_sz.cx, dlg_sz.cy, TRUE ); /* init dialog */ plselInitDialog(hWnd); /* set focus on the role checkbox (random) field */ SetFocus(GetDlgItem(hWnd, IDC_PLSEL_ROLE_RANDOM)); /* tell windows we set the focus */ return FALSE; break; case WM_COMMAND: data = (struct plsel_data*)GetWindowLong(hWnd, GWL_USERDATA); switch (LOWORD(wParam)) { /* OK button was clicked */ case IDOK: if( plselFinalSelection(hWnd, data->selection) ) { EndDialog(hWnd, wParam); } else { NHMessageBox(hWnd, TEXT("Cannot match this role. Try something else."), MB_ICONSTOP | MB_OK ); } return TRUE; /* CANCEL button was clicked */ case IDCANCEL: *data->selection = -1; EndDialog(hWnd, wParam); return TRUE; /* following are events from dialog controls: "random" checkboxes send BN_CLICKED messages; role/race/... combo-boxes send CBN_SELENDOK if something was selected; */ case IDC_PLSEL_ROLE_RANDOM: if( HIWORD(wParam)==BN_CLICKED ) { /* enable corresponding list window if "random" checkbox was "unchecked" */ EnableWindow( GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED ); } break; case IDC_PLSEL_RACE_RANDOM: if( HIWORD(wParam)==BN_CLICKED ) { EnableWindow( GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED ); } break; case IDC_PLSEL_GENDER_RANDOM: if( HIWORD(wParam)==BN_CLICKED ) { EnableWindow( GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED ); } break; case IDC_PLSEL_ALIGN_RANDOM: if( HIWORD(wParam)==BN_CLICKED ) { EnableWindow( GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), SendMessage((HWND)lParam, BM_GETCHECK, 0, 0)==BST_UNCHECKED ); } break; case IDC_PLSEL_ROLE_LIST: if( HIWORD(wParam)==CBN_SELENDOK ) { /* filter out invalid options if the selection was made */ plselAdjustLists( hWnd, LOWORD(wParam) ); } break; case IDC_PLSEL_RACE_LIST: if( HIWORD(wParam)==CBN_SELENDOK ) { plselAdjustLists( hWnd, LOWORD(wParam) ); } break; case IDC_PLSEL_GENDER_LIST: if( HIWORD(wParam)==CBN_SELENDOK ) { plselAdjustLists( hWnd, LOWORD(wParam) ); } break; case IDC_PLSEL_ALIGN_LIST: if( HIWORD(wParam)==CBN_SELENDOK ) { plselAdjustLists( hWnd, LOWORD(wParam) ); } break; } break; } return FALSE; } void setComboBoxValue(HWND hWnd, int combo_box, int value) { int index_max = SendDlgItemMessage(hWnd, combo_box, CB_GETCOUNT, 0, 0); int index; int value_to_set = LB_ERR; for (index = 0; index < index_max; index++) { if (SendDlgItemMessage(hWnd, combo_box, CB_GETITEMDATA, (WPARAM)index, 0) == value) { value_to_set = index; break; } } SendDlgItemMessage(hWnd, combo_box, CB_SETCURSEL, (WPARAM)value_to_set, 0); } /* initialize player selector dialog */ void plselInitDialog(HWND hWnd) { TCHAR wbuf[BUFSZ]; /* set player name */ SetDlgItemText(hWnd, IDC_PLSEL_NAME, NH_A2W(plname, wbuf, sizeof(wbuf))); /* check flags for consistency */ if( flags.initrole>=0 ) { if (flags.initrace>=0 && !validrace(flags.initrole, flags.initrace)) { flags.initrace = ROLE_NONE; } if (flags.initgend>=0 && !validgend(flags.initrole, flags.initrace, flags.initgend)) { flags.initgend = ROLE_NONE; } if (flags.initalign>=0 && !validalign(flags.initrole, flags.initrace, flags.initalign)) { flags.initalign = ROLE_NONE; } } /* populate select boxes */ plselAdjustLists(hWnd, -1); /* intialize roles list */ if( flags.initrole<0 || !ok_role(flags.initrole, ROLE_NONE, ROLE_NONE, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_ROLE_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_ROLE_LIST, flags.initrole); } /* intialize races list */ if( flags.initrace<0 || !ok_race(flags.initrole, flags.initrace, ROLE_NONE, ROLE_NONE) ) { CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_RACE_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_RACE_LIST, flags.initrace); } /* intialize genders list */ if( flags.initgend<0 || !ok_gend(flags.initrole, flags.initrace, flags.initgend, ROLE_NONE)) { CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_GENDER_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_GENDER_LIST, flags.initgend); } /* intialize alignments list */ if( flags.initalign<0 || !ok_align(flags.initrole, flags.initrace, flags.initgend, flags.initalign) ) { CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_CHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), FALSE); } else { CheckDlgButton(hWnd, IDC_PLSEL_ALIGN_RANDOM, BST_UNCHECKED); EnableWindow(GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST), TRUE); setComboBoxValue(hWnd, IDC_PLSEL_ALIGN_LIST, flags.initalign); } } /* adjust role/race/alignment/gender list - filter out invalid combinations changed_sel points to the list where selection occured (-1 if unknown) */ void plselAdjustLists(HWND hWnd, int changed_sel) { HWND control_role, control_race, control_gender, control_align; int initrole, initrace, initgend, initalign; int i; int ind; int valid_opt; TCHAR wbuf[255]; /* get control handles */ control_role = GetDlgItem(hWnd, IDC_PLSEL_ROLE_LIST); control_race = GetDlgItem(hWnd, IDC_PLSEL_RACE_LIST); control_gender = GetDlgItem(hWnd, IDC_PLSEL_GENDER_LIST); control_align = GetDlgItem(hWnd, IDC_PLSEL_ALIGN_LIST); /* get current selections */ ind = SendMessage(control_role, CB_GETCURSEL, 0, 0); initrole = (ind==LB_ERR)? flags.initrole : SendMessage(control_role, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_race, CB_GETCURSEL, 0, 0); initrace = (ind==LB_ERR)? flags.initrace : SendMessage(control_race, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_gender, CB_GETCURSEL, 0, 0); initgend = (ind==LB_ERR)? flags.initgend : SendMessage(control_gender, CB_GETITEMDATA, ind, 0); ind = SendMessage(control_align, CB_GETCURSEL, 0, 0); initalign = (ind==LB_ERR)? flags.initalign : SendMessage(control_align, CB_GETITEMDATA, ind, 0); /* intialize roles list */ if( changed_sel==-1 ) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_role, CB_RESETCONTENT, 0, 0); for (i = 0; roles[i].name.m; i++) { if (initgend>=0 && flags.female && roles[i].name.f) ind = SendMessage(control_role, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(roles[i].name.f, wbuf, sizeof(wbuf)) ); else ind = SendMessage(control_role, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(roles[i].name.m, wbuf, sizeof(wbuf)) ); SendMessage(control_role, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); if( i==initrole ) { SendMessage(control_role, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 ); valid_opt = 1; } } /* set selection to the previously selected role if it is still valid */ if( !valid_opt ) { initrole = ROLE_NONE; initrace = ROLE_NONE; initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_role, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 ); } /* trigger change of the races list */ changed_sel=IDC_PLSEL_ROLE_LIST; } /* intialize races list */ if( changed_sel==IDC_PLSEL_ROLE_LIST ) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_race, CB_RESETCONTENT, 0, 0); for (i = 0; races[i].noun; i++) if (ok_race(initrole, i, ROLE_NONE, ROLE_NONE)) { ind = SendMessage(control_race, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(races[i].noun, wbuf, sizeof(wbuf)) ); SendMessage(control_race, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); if( i==initrace ) { SendMessage(control_race, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 ); valid_opt = 1; } } /* set selection to the previously selected race if it is still valid */ if( !valid_opt ) { initrace = ROLE_NONE; initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_race, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 ); } /* trigger change of the genders list */ changed_sel=IDC_PLSEL_RACE_LIST; } /* intialize genders list */ if( changed_sel==IDC_PLSEL_RACE_LIST ) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_gender, CB_RESETCONTENT, 0, 0); for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(initrole, initrace, i, ROLE_NONE)) { ind = SendMessage(control_gender, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(genders[i].adj, wbuf, sizeof(wbuf)) ); SendMessage(control_gender, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); if( i==initgend ) { SendMessage(control_gender, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 ); valid_opt = 1; } } /* set selection to the previously selected gender if it is still valid */ if( !valid_opt ) { initgend = ROLE_NONE; initalign = ROLE_NONE; SendMessage(control_gender, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 ); } /* trigger change of the alignments list */ changed_sel=IDC_PLSEL_GENDER_LIST; } /* intialize alignments list */ if( changed_sel==IDC_PLSEL_GENDER_LIST ) { valid_opt = 0; /* reset content and populate the list */ SendMessage(control_align, CB_RESETCONTENT, 0, 0); for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(initrole, initrace, initgend, i)) { ind = SendMessage(control_align, CB_ADDSTRING, (WPARAM)0, (LPARAM)NH_A2W(aligns[i].adj, wbuf, sizeof(wbuf)) ); SendMessage(control_align, CB_SETITEMDATA, (WPARAM)ind, (LPARAM)i ); if( i==initalign ) { SendMessage(control_align, CB_SETCURSEL, (WPARAM)ind, (LPARAM)0 ); valid_opt = 1; } } /* set selection to the previously selected alignment if it is still valid */ if( !valid_opt ) { initalign = ROLE_NONE; SendMessage(control_align, CB_SETCURSEL, (WPARAM)-1, (LPARAM)0 ); } } } /* player made up his mind - get final selection here */ int plselFinalSelection(HWND hWnd, int* selection) { int ind; /* get current selections */ if( SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) { flags.initrole = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETCURSEL, 0, 0); flags.initrole = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ROLE_LIST, CB_GETITEMDATA, ind, 0); } if( SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) { flags.initrace = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETCURSEL, 0, 0); flags.initrace = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_RACE_LIST, CB_GETITEMDATA, ind, 0); } if( SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) { flags.initgend = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETCURSEL, 0, 0); flags.initgend = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_GENDER_LIST, CB_GETITEMDATA, ind, 0); } if( SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_RANDOM, BM_GETCHECK, 0, 0)==BST_CHECKED ) { flags.initalign = ROLE_RANDOM; } else { ind = SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETCURSEL, 0, 0); flags.initalign = (ind==LB_ERR)? ROLE_RANDOM : SendDlgItemMessage(hWnd, IDC_PLSEL_ALIGN_LIST, CB_GETITEMDATA, ind, 0); } /* check the role */ if( flags.initrole==ROLE_RANDOM ) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { NHMessageBox(hWnd, TEXT("Incompatible role!"), MB_ICONSTOP | MB_OK); return FALSE; } } /* Select a race, if necessary */ /* force compatibility with role */ if (flags.initrace==ROLE_RANDOM || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (flags.initrace == ROLE_RANDOM) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); } if (flags.initrace < 0) { NHMessageBox(hWnd, TEXT("Incompatible race!"), MB_ICONSTOP | MB_OK); return FALSE; } } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (flags.initgend == ROLE_RANDOM) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); } if (flags.initgend < 0) { NHMessageBox(hWnd, TEXT("Incompatible gender!"), MB_ICONSTOP | MB_OK); return FALSE; } } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (flags.initalign == ROLE_RANDOM) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); } else { NHMessageBox(hWnd, TEXT("Incompatible alignment!"), MB_ICONSTOP | MB_OK); return FALSE; } } return TRUE; } nethack-3.4.3/win/win32/mhdlg.h0100644000000000000000000000070307764735042014656 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINDlgWindow_h #define MSWINDlgWindow_h #include "winMS.h" #include "config.h" #include "global.h" int mswin_getlin_window (const char *question, char *result, size_t result_size); int mswin_ext_cmd_window (int* selection); int mswin_player_selection_window(int* selection); #endif /* MSWINDlgWindow_h */ nethack-3.4.3/win/win32/mhfont.c0100644000000000000000000001721207764735042015054 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* font management and such */ #include "mhfont.h" #define MAXFONTS 64 /* font table - 64 fonts ought to be enough */ static struct font_table_entry { int code; HFONT hFont; } font_table[MAXFONTS] ; static int font_table_size = 0; HFONT version_splash_font; #define NHFONT_CODE(win, attr) (((attr&0xFF)<<8)|(win_type&0xFF)) static void __cdecl font_table_cleanup(void); void mswin_init_splashfonts(HWND hWnd) { HDC hdc = GetDC(hWnd); HFONT fnt = NULL; LOGFONT lgfnt; ZeroMemory( &lgfnt, sizeof(lgfnt) ); lgfnt.lfHeight = -80; // height of font lgfnt.lfWidth = 0; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_BOLD; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = ANSI_CHARSET; // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W( "Times New Roman", lgfnt.lfFaceName, LF_FACESIZE); version_splash_font = CreateFontIndirect(&lgfnt); ReleaseDC(hWnd, hdc); } void mswin_destroy_splashfonts() { DeleteObject (version_splash_font); } /* create font based on window type, charater attributes and window device context */ HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace) { HFONT fnt = NULL; LOGFONT lgfnt; int font_size; int font_index; static BOOL once = FALSE; if( !once ) { once = TRUE; atexit(font_table_cleanup); } ZeroMemory( &lgfnt, sizeof(lgfnt) ); /* try find font in the table */ for(font_index=0; font_index=MAXFONTS ) panic( "font table overflow!" ); font_table_size++; } else { DeleteObject(font_table[font_index].hFont); } font_table[font_index].code = NHFONT_CODE(win_type, attr); font_table[font_index].hFont = fnt; return fnt; } UINT mswin_charset() { CHARSETINFO cis; if( iflags.IBMgraphics ) if( TranslateCharsetInfo((DWORD*)GetOEMCP(), &cis, TCI_SRCCODEPAGE) ) return cis.ciCharset; else return OEM_CHARSET; else if( TranslateCharsetInfo((DWORD*)GetACP(), &cis, TCI_SRCCODEPAGE) ) return cis.ciCharset; else return ANSI_CHARSET; } void __cdecl font_table_cleanup(void) { int i; for(i=0; i */ /* NetHack may be freely redistributed. See license for details. */ /* font management functions */ #ifndef MSWINFont_h #define MSWINFont_h #include "winMS.h" HGDIOBJ mswin_get_font(int win_type, int attr, HDC hdc, BOOL replace); void mswin_init_splashfonts(HWND hWnd); void mswin_destroy_splashfonts(void); UINT mswin_charset(void); #endif /* MSWINFont_h */ nethack-3.4.3/win/win32/mhinput.c0100644000000000000000000000343607764735042015250 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include #include "winMS.h" #include "mhinput.h" /* nethack input queue functions */ #define NH_INPUT_BUFFER_SIZE 64 /* as it stands right now we need only one slot since events are processed almost the same time as they occur but I like large round numbers */ static MSNHEvent nhi_input_buffer[NH_INPUT_BUFFER_SIZE]; static int nhi_init_input = 0; static int nhi_read_pos = 0; static int nhi_write_pos = 0; /* initialize input queue */ void mswin_nh_input_init(void) { if( !nhi_init_input ) { nhi_init_input = 1; ZeroMemory( nhi_input_buffer, sizeof(nhi_input_buffer) ); nhi_read_pos = 0; nhi_write_pos = 0; } } /* check for input */ int mswin_have_input() { return (nhi_read_pos!=nhi_write_pos); } /* add event to the queue */ void mswin_input_push(PMSNHEvent event) { int new_write_pos; if( !nhi_init_input ) mswin_nh_input_init(); new_write_pos = (nhi_write_pos+1) % NH_INPUT_BUFFER_SIZE; if(new_write_pos!=nhi_read_pos) { memcpy(nhi_input_buffer+nhi_write_pos, event, sizeof(*event)); nhi_write_pos = new_write_pos; } } /* get event from the queue and delete it */ PMSNHEvent mswin_input_pop() { PMSNHEvent retval; if( !nhi_init_input ) mswin_nh_input_init(); if( nhi_read_pos!=nhi_write_pos ) { retval = &nhi_input_buffer[nhi_read_pos]; nhi_read_pos = (nhi_read_pos+1) % NH_INPUT_BUFFER_SIZE; } else { retval = NULL; } return retval; } /* get event from the queue but leave it there */ PMSNHEvent mswin_input_peek() { PMSNHEvent retval; if( !nhi_init_input ) mswin_nh_input_init(); if( nhi_read_pos!=nhi_write_pos ) { retval = &nhi_input_buffer[nhi_read_pos]; } else { retval = NULL; } return retval; } nethack-3.4.3/win/win32/mhinput.h0100644000000000000000000000157407764735042015256 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINInput_h #define MSWINInput_h /* nethack input queue - store/extract input events */ #include "winMS.h" #define NHEVENT_CHAR 1 #define NHEVENT_MOUSE 2 typedef struct mswin_event { int type; union { struct { int ch; } kbd; struct { int mod; int x, y; } ms; }; } MSNHEvent, *PMSNHEvent; #define NHEVENT_KBD(c) { MSNHEvent e; e.type=NHEVENT_CHAR; e.kbd.ch=(c); mswin_input_push(&e); } #define NHEVENT_MS(_mod, _x, _y) { MSNHEvent e; e.type=NHEVENT_MOUSE; e.ms.mod = (_mod); e.ms.x=(_x); e.ms.y=(_y); mswin_input_push(&e); } void mswin_nh_input_init(void); int mswin_have_input(void); void mswin_input_push(PMSNHEvent event); PMSNHEvent mswin_input_pop(void); PMSNHEvent mswin_input_peek(void); #endif /* MSWINInput_h */ nethack-3.4.3/win/win32/mhmain.c0100644000000000000000000006041107764735042015031 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "patchlevel.h" #include "resource.h" #include "mhmsg.h" #include "mhinput.h" #include "mhmain.h" #include "mhmenu.h" #include "mhstatus.h" #include "mhmsgwnd.h" #include "mhmap.h" typedef struct mswin_nethack_main_window { int mapAcsiiModeSave; } NHMainWindow, *PNHMainWindow; static TCHAR szMainWindowClass[] = TEXT("MSNHMainWndClass"); static TCHAR szTitle[MAX_LOADSTRING]; extern void mswin_display_splash_window(BOOL); LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); static LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void register_main_window_class(void); static int menuid2mapmode(int menuid); static int mapmode2menuid(int map_mode); HWND mswin_init_main_window () { static int run_once = 0; HWND ret; WINDOWPLACEMENT wp; /* register window class */ if( !run_once ) { LoadString(GetNHApp()->hApp, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); register_main_window_class( ); run_once = 1; } /* create the main window */ ret = CreateWindow( szMainWindowClass, /* registered class name */ szTitle, /* window name */ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, /* window style */ CW_USEDEFAULT, /* horizontal position of window */ CW_USEDEFAULT, /* vertical position of window */ CW_USEDEFAULT, /* window width */ CW_USEDEFAULT, /* window height */ NULL, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL /* window-creation data */ ); if( !ret ) panic("Cannot create main window"); if (GetNHApp()->regMainMinX != CW_USEDEFAULT) { wp.length = sizeof(wp); wp.showCmd = GetNHApp()->regMainShowState; wp.ptMinPosition.x = GetNHApp()->regMainMinX; wp.ptMinPosition.y = GetNHApp()->regMainMinY; wp.ptMaxPosition.x = GetNHApp()->regMainMaxX; wp.ptMaxPosition.y = GetNHApp()->regMainMaxY; wp.rcNormalPosition.left = GetNHApp()->regMainLeft; wp.rcNormalPosition.top = GetNHApp()->regMainTop; wp.rcNormalPosition.right = GetNHApp()->regMainRight; wp.rcNormalPosition.bottom = GetNHApp()->regMainBottom; SetWindowPlacement(ret, &wp); } else ShowWindow(ret, SW_SHOWDEFAULT); UpdateWindow(ret); return ret; } void register_main_window_class() { WNDCLASS wcex; ZeroMemory(&wcex, sizeof(wcex)); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)MainWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = LoadIcon(GetNHApp()->hApp, (LPCTSTR)IDI_NETHACKW); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = (TCHAR*)IDC_NETHACKW; wcex.lpszClassName = szMainWindowClass; RegisterClass(&wcex); } /* * Keypad keys are translated to the normal values below. * Shifted keypad keys are translated to the * shift values below. */ enum KEY_INDEXES { KEY_NW, KEY_N, KEY_NE, KEY_MINUS, KEY_W, KEY_GOINTERESTING, KEY_E, KEY_PLUS, KEY_SW, KEY_S, KEY_SE, KEY_INV, KEY_WAITLOOK, KEY_LAST}; static const unsigned char /* normal, shift, control */ keypad[KEY_LAST][3] = { {'y', 'Y', C('y')}, /* 7 */ {'k', 'K', C('k')}, /* 8 */ {'u', 'U', C('u')}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'h', 'H', C('h')}, /* 4 */ {'g', 'G', 'g'}, /* 5 */ {'l', 'L', C('l')}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'b', 'B', C('b')}, /* 1 */ {'j', 'J', C('j')}, /* 2 */ {'n', 'N', C('n')}, /* 3 */ {'i', 'I', C('i')}, /* Ins */ {'.', ':', ':'} /* Del */ }, numpad[KEY_LAST][3] = { {'7', M('7'), '7'}, /* 7 */ {'8', M('8'), '8'}, /* 8 */ {'9', M('9'), '9'}, /* 9 */ {'m', C('p'), C('p')}, /* - */ {'4', M('4'), '4'}, /* 4 */ {'5', M('5'), '5'}, /* 5 */ {'6', M('6'), '6'}, /* 6 */ {'+', 'P', C('p')}, /* + */ {'1', M('1'), '1'}, /* 1 */ {'2', M('2'), '2'}, /* 2 */ {'3', M('3'), '3'}, /* 3 */ {'0', M('0'), '0'}, /* Ins */ {'.', ':', ':'} /* Del */ }; #define STATEON(x) ((GetKeyState(x) & 0xFFFE) != 0) #define KEYTABLE_REGULAR(x) ((iflags.num_pad ? numpad : keypad)[x][0]) #define KEYTABLE_SHIFT(x) ((iflags.num_pad ? numpad : keypad)[x][1]) #define KEYTABLE(x) (STATEON(VK_SHIFT) ? KEYTABLE_SHIFT(x) : KEYTABLE_REGULAR(x)) /* map mode macros */ #define IS_MAP_FIT_TO_SCREEN(mode) ((mode)==MAP_MODE_ASCII_FIT_TO_SCREEN || \ (mode)==MAP_MODE_TILES_FIT_TO_SCREEN ) #define IS_MAP_ASCII(mode) ((mode)!=MAP_MODE_TILES && (mode)!=MAP_MODE_TILES_FIT_TO_SCREEN) static const char *extendedlist = "acdefijlmnopqrstuvw?2"; #define SCANLO 0x02 static const char scanmap[] = { /* ... */ '1','2','3','4','5','6','7','8','9','0',0,0,0,0, 'q','w','e','r','t','y','u','i','o','p','[',']', '\n', 0, 'a','s','d','f','g','h','j','k','l',';','\'', '`', 0, '\\', 'z','x','c','v','b','n','m',',','.','?' /* ... */ }; /* // FUNCTION: WndProc(HWND, unsigned, WORD, LONG) // // PURPOSE: Processes messages for the main window. */ LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMainWindow data; switch (message) { case WM_CREATE: /* set window data */ data = (PNHMainWindow)malloc(sizeof(NHMainWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHMainWindow)); data->mapAcsiiModeSave = MAP_MODE_ASCII12x16; SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); GetNHApp()->hMainWnd = hWnd; break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_KEYDOWN: { data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA); /* translate arrow keys into nethack commands */ switch (wParam) { case VK_LEFT: if( STATEON(VK_CONTROL) ) { /* scroll map window one line left */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_W)); } return 0; case VK_RIGHT: if( STATEON(VK_CONTROL) ) { /* scroll map window one line right */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_E)); } return 0; case VK_UP: if( STATEON(VK_CONTROL) ) { /* scroll map window one line up */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_N)); } return 0; case VK_DOWN: if( STATEON(VK_CONTROL) ) { /* scroll map window one line down */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_S)); } return 0; case VK_HOME: if( STATEON(VK_CONTROL) ) { /* scroll map window to upper left corner */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM)NULL ); SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_NW)); } return 0; case VK_END: if( STATEON(VK_CONTROL) ) { /* scroll map window to lower right corner */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, ROWNO), (LPARAM)NULL ); SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, COLNO), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_SW)); } return 0; case VK_PRIOR: if( STATEON(VK_CONTROL) ) { /* scroll map window one page up */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_PAGEUP, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_NE)); } return 0; case VK_NEXT: if( STATEON(VK_CONTROL) ) { /* scroll map window one page down */ SendMessage( mswin_hwnd_from_winid(WIN_MAP), WM_VSCROLL, MAKEWPARAM(SB_PAGEDOWN, 0), (LPARAM)NULL ); } else { NHEVENT_KBD(KEYTABLE(KEY_SE)); } return 0; case VK_DECIMAL: case VK_DELETE: NHEVENT_KBD(KEYTABLE(KEY_WAITLOOK)); return 0; case VK_INSERT: NHEVENT_KBD(KEYTABLE(KEY_INV)); return 0; case VK_SUBTRACT: NHEVENT_KBD(KEYTABLE(KEY_MINUS)); return 0; case VK_ADD: NHEVENT_KBD(KEYTABLE(KEY_PLUS)); return 0; case VK_CLEAR: /* This is the '5' key */ NHEVENT_KBD(KEYTABLE(KEY_GOINTERESTING)); return 0; case VK_F4: if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) { mswin_select_map_mode( IS_MAP_ASCII(iflags.wc_map_mode)? data->mapAcsiiModeSave : MAP_MODE_TILES ); } else { mswin_select_map_mode( IS_MAP_ASCII(iflags.wc_map_mode)? MAP_MODE_ASCII_FIT_TO_SCREEN : MAP_MODE_TILES_FIT_TO_SCREEN ); } return 0; case VK_F5: if( IS_MAP_ASCII(iflags.wc_map_mode) ) { if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) { mswin_select_map_mode(MAP_MODE_TILES_FIT_TO_SCREEN); } else { mswin_select_map_mode(MAP_MODE_TILES); } } else { if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) { mswin_select_map_mode(MAP_MODE_ASCII_FIT_TO_SCREEN); } else { mswin_select_map_mode(data->mapAcsiiModeSave); } } return 0; default: { WORD c; BYTE kbd_state[256]; c = 0; ZeroMemory(kbd_state, sizeof(kbd_state)); GetKeyboardState(kbd_state); if( ToAscii( wParam, (lParam>>16)&0xFF, kbd_state, &c, 0) ) { NHEVENT_KBD( c&0xFF ); return 0; } else { return 1; } } } /* end switch */ } break; case WM_SYSCHAR: /* Alt-char pressed */ { /* If not nethackmode, don't handle Alt-keys here. If no Alt-key pressed it can never be an extended command */ if (GetNHApp()->regNetHackMode && ((lParam & 1<<29) != 0)) { unsigned char c = (unsigned char)(wParam & 0xFF); unsigned char scancode = (lParam >> 16) & 0xFF; if (index(extendedlist, tolower(c)) != 0) { NHEVENT_KBD(M(tolower(c))); } else if (scancode == (SCANLO + SIZE(scanmap)) - 1) { NHEVENT_KBD(M('?')); } return 0; } return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_COMMAND: /* process commands - menu commands mostly */ if( onWMCommand(hWnd, wParam, lParam) ) return DefWindowProc(hWnd, message, wParam, lParam); else return 0; case WM_MOVE: case WM_SIZE: { WINDOWPLACEMENT wp; mswin_layout_main_window(NULL); wp.length = sizeof(wp); if (GetWindowPlacement(hWnd, &wp)) { GetNHApp()->regMainShowState = (wp.showCmd == SW_SHOWMAXIMIZED ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL); GetNHApp()->regMainMinX = wp.ptMinPosition.x; GetNHApp()->regMainMinY = wp.ptMinPosition.y; GetNHApp()->regMainMaxX = wp.ptMaxPosition.x; GetNHApp()->regMainMaxY = wp.ptMaxPosition.y; GetNHApp()->regMainLeft = wp.rcNormalPosition.left; GetNHApp()->regMainTop = wp.rcNormalPosition.top; GetNHApp()->regMainRight = wp.rcNormalPosition.right; GetNHApp()->regMainBottom = wp.rcNormalPosition.bottom; } break; } case WM_SETFOCUS: /* if there is a menu window out there - transfer input focus to it */ if( IsWindow( GetNHApp()->hPopupWnd ) ) { SetFocus( GetNHApp()->hPopupWnd ); } break; case WM_CLOSE: { /* exit gracefully */ if (program_state.gameover) { /* assume the user really meant this, as the game is already over... */ /* to make sure we still save bones, just set stop printing flag */ program_state.stopprint++; NHEVENT_KBD('\033'); /* and send keyboard input as if user pressed ESC */ /* additional code for this is done in menu and rip windows */ } else if (!program_state.something_worth_saving) { /* User exited before the game started, e.g. during splash display */ /* Just get out. */ bail((char *)0); } else { switch (NHMessageBox(hWnd, TEXT("Save?"), MB_YESNOCANCEL | MB_ICONQUESTION)) { case IDYES: NHEVENT_KBD('y'); dosave(); break; case IDNO: NHEVENT_KBD('q'); done(QUIT); break; case IDCANCEL: break; } } } return 0; case WM_DESTROY: /* apparently we never get here TODO: work on exit routines - need to send WM_QUIT somehow */ /* clean up */ free( (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA) ); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); // PostQuitMessage(0); exit(1); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { switch(wParam) { /* new window was just added */ case MSNH_MSG_ADDWND: { PMSNHMsgAddWnd msg_param = (PMSNHMsgAddWnd)lParam; HWND child; if( GetNHApp()->windowlist[msg_param->wid].type == NHW_MAP ) mswin_select_map_mode(iflags.wc_map_mode); child = GetNHApp()->windowlist[msg_param->wid].win; if( child ) mswin_layout_main_window(child); } break; } } /* adjust windows to fit main window layout --------------------------- | Status | +-------------------------+ | | | | | MAP | | | | | +-------------------------+ | Messages | --------------------------- */ void mswin_layout_main_window(HWND changed_child) { winid i; POINT pt; RECT client_rt, wnd_rect; SIZE menu_size; POINT status_org; SIZE status_size; POINT msg_org; SIZE msg_size; POINT map_org; SIZE map_size; HWND wnd_status, wnd_msg; PNHMainWindow data; GetClientRect(GetNHApp()->hMainWnd, &client_rt); data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA); /* get sizes of child windows */ wnd_status = mswin_hwnd_from_winid(WIN_STATUS); if( IsWindow(wnd_status) ) { mswin_status_window_size(wnd_status, &status_size); } else { status_size.cx = status_size.cy = 0; } wnd_msg = mswin_hwnd_from_winid(WIN_MESSAGE); if( IsWindow(wnd_msg) ) { mswin_message_window_size(wnd_msg, &msg_size); } else { msg_size.cx = msg_size.cy = 0; } /* set window positions */ SetRect(&wnd_rect, client_rt.left, client_rt.top, client_rt.right, client_rt.bottom); switch(iflags.wc_align_status) { case ALIGN_LEFT: status_size.cx = (wnd_rect.right-wnd_rect.left)/4; status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good status_org.x = wnd_rect.left; status_org.y = wnd_rect.top; wnd_rect.left += status_size.cx; break; case ALIGN_RIGHT: status_size.cx = (wnd_rect.right-wnd_rect.left)/4; status_size.cy = (wnd_rect.bottom-wnd_rect.top); // that won't look good status_org.x = wnd_rect.right - status_size.cx; status_org.y = wnd_rect.top; wnd_rect.right -= status_size.cx; break; case ALIGN_TOP: status_size.cx = (wnd_rect.right-wnd_rect.left); status_org.x = wnd_rect.left; status_org.y = wnd_rect.top; wnd_rect.top += status_size.cy; break; case ALIGN_BOTTOM: default: status_size.cx = (wnd_rect.right-wnd_rect.left); status_org.x = wnd_rect.left; status_org.y = wnd_rect.bottom - status_size.cy; wnd_rect.bottom -= status_size.cy; break; } switch(iflags.wc_align_message) { case ALIGN_LEFT: msg_size.cx = (wnd_rect.right-wnd_rect.left)/4; msg_size.cy = (wnd_rect.bottom-wnd_rect.top); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; wnd_rect.left += msg_size.cx; break; case ALIGN_RIGHT: msg_size.cx = (wnd_rect.right-wnd_rect.left)/4; msg_size.cy = (wnd_rect.bottom-wnd_rect.top); msg_org.x = wnd_rect.right - msg_size.cx; msg_org.y = wnd_rect.top; wnd_rect.right -= msg_size.cx; break; case ALIGN_TOP: msg_size.cx = (wnd_rect.right-wnd_rect.left); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.top; wnd_rect.top += msg_size.cy; break; case ALIGN_BOTTOM: default: msg_size.cx = (wnd_rect.right-wnd_rect.left); msg_org.x = wnd_rect.left; msg_org.y = wnd_rect.bottom - msg_size.cy; wnd_rect.bottom -= msg_size.cy; break; } map_org.x = wnd_rect.left; map_org.y = wnd_rect.top; map_size.cx = wnd_rect.right - wnd_rect.left; map_size.cy = wnd_rect.bottom - wnd_rect.top; /* go through the windows list and adjust sizes */ for( i=0; iwindowlist[i].win && !GetNHApp()->windowlist[i].dead) { switch( GetNHApp()->windowlist[i].type ) { case NHW_STATUS: MoveWindow(GetNHApp()->windowlist[i].win, status_org.x, status_org.y, status_size.cx, status_size.cy, TRUE ); break; case NHW_TEXT: // same as the map window case NHW_MAP: MoveWindow(GetNHApp()->windowlist[i].win, map_org.x, map_org.y, map_size.cx, map_size.cy, TRUE ); break; case NHW_MESSAGE: MoveWindow(GetNHApp()->windowlist[i].win, msg_org.x, msg_org.y, msg_size.cx, msg_size.cy, TRUE ); break; case NHW_MENU: mswin_menu_window_size(GetNHApp()->windowlist[i].win, &menu_size); menu_size.cx = min(menu_size.cx, (client_rt.right-client_rt.left)); pt.x = map_org.x + max(0, (int)(map_size.cx-menu_size.cx)); pt.y = map_org.y; MoveWindow(GetNHApp()->windowlist[i].win, pt.x, pt.y, min(menu_size.cx, map_size.cx), map_size.cy, TRUE ); break; } ShowWindow(GetNHApp()->windowlist[i].win, SW_SHOW); } } } LRESULT onWMCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PNHMainWindow data; data = (PNHMainWindow)GetWindowLong(hWnd, GWL_USERDATA); wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: mswin_display_splash_window(TRUE); break; case IDM_EXIT: done2(); break; case IDM_SAVE: if (!program_state.gameover && !program_state.done_hup) dosave(); else MessageBeep(0); break; case IDM_MAP_TILES: case IDM_MAP_ASCII4X6: case IDM_MAP_ASCII6X8: case IDM_MAP_ASCII8X8: case IDM_MAP_ASCII16X8: case IDM_MAP_ASCII7X12: case IDM_MAP_ASCII8X12: case IDM_MAP_ASCII12X16: case IDM_MAP_ASCII16X12: case IDM_MAP_ASCII10X18: mswin_select_map_mode(menuid2mapmode(wmId)); break; case IDM_MAP_FIT_TO_SCREEN: if( IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode) ) { mswin_select_map_mode( IS_MAP_ASCII(iflags.wc_map_mode)? data->mapAcsiiModeSave : MAP_MODE_TILES ); } else { mswin_select_map_mode( IS_MAP_ASCII(iflags.wc_map_mode)? MAP_MODE_ASCII_FIT_TO_SCREEN : MAP_MODE_TILES_FIT_TO_SCREEN ); } break; case IDM_NHMODE: { GetNHApp()->regNetHackMode = GetNHApp()->regNetHackMode ? 0 : 1; mswin_menu_check_intf_mode(); break; } case IDM_CLEARSETTINGS: { mswin_destroy_reg(); /* Notify the user that windows settings will not be saved this time. */ NHMessageBox(GetNHApp()->hMainWnd, "Your Windows Settings will not be stored when you exit this time.", MB_OK | MB_ICONINFORMATION); break; } case IDM_HELP_LONG: display_file(HELP, TRUE); break; case IDM_HELP_COMMANDS: display_file(SHELP, TRUE); break; case IDM_HELP_HISTORY: (void) dohistory(); break; case IDM_HELP_INFO_CHAR: (void) dowhatis(); break; case IDM_HELP_INFO_KEY: (void) dowhatdoes(); break; case IDM_HELP_OPTIONS: option_help(); break; case IDM_HELP_OPTIONS_LONG: display_file(OPTIONFILE, TRUE); break; case IDM_HELP_EXTCMD: (void) doextlist(); break; case IDM_HELP_LICENSE: display_file(LICENSE, TRUE); break; case IDM_HELP_PORTHELP: display_file(PORT_HELP, TRUE); break; default: return 1; } return 0; } // Mesage handler for about box. LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { char buf[BUFSZ]; TCHAR wbuf[BUFSZ]; RECT main_rt, dlg_rt; SIZE dlg_sz; switch (message) { case WM_INITDIALOG: getversionstring(buf); SetDlgItemText(hDlg, IDC_ABOUT_VERSION, NH_A2W(buf, wbuf, sizeof(wbuf))); SetDlgItemText(hDlg, IDC_ABOUT_COPYRIGHT, NH_A2W( COPYRIGHT_BANNER_A "\n" COPYRIGHT_BANNER_B "\n" COPYRIGHT_BANNER_C, wbuf, BUFSZ ) ); /* center dialog in the main window */ GetWindowRect(GetNHApp()->hMainWnd, &main_rt); GetWindowRect(hDlg, &dlg_rt); dlg_sz.cx = dlg_rt.right - dlg_rt.left; dlg_sz.cy = dlg_rt.bottom - dlg_rt.top; dlg_rt.left = (main_rt.left+main_rt.right-dlg_sz.cx)/2; dlg_rt.right = dlg_rt.left + dlg_sz.cx; dlg_rt.top = (main_rt.top+main_rt.bottom-dlg_sz.cy)/2; dlg_rt.bottom = dlg_rt.top + dlg_sz.cy; MoveWindow( hDlg, (main_rt.left+main_rt.right-dlg_sz.cx)/2, (main_rt.top+main_rt.bottom-dlg_sz.cy)/2, dlg_sz.cx, dlg_sz.cy, TRUE ); return TRUE; case WM_COMMAND: if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) { EndDialog(hDlg, LOWORD(wParam)); return TRUE; } break; } return FALSE; } void mswin_menu_check_intf_mode() { HMENU hMenu = GetMenu(GetNHApp()->hMainWnd); if (GetNHApp()->regNetHackMode) CheckMenuItem(hMenu, IDM_NHMODE, MF_CHECKED); else CheckMenuItem(hMenu, IDM_NHMODE, MF_UNCHECKED); } void mswin_select_map_mode(int mode) { PNHMainWindow data; winid map_id; map_id = WIN_MAP; data = (PNHMainWindow)GetWindowLong(GetNHApp()->hMainWnd, GWL_USERDATA); /* override for Rogue level */ #ifdef REINCARNATION if( Is_rogue_level(&u.uz) && !IS_MAP_ASCII(mode) ) return; #endif /* set map mode menu mark */ if( IS_MAP_ASCII(mode) ) { CheckMenuRadioItem( GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES, IDM_MAP_ASCII10X18, mapmode2menuid( IS_MAP_FIT_TO_SCREEN(mode)? data->mapAcsiiModeSave : mode ), MF_BYCOMMAND); } else { CheckMenuRadioItem( GetMenu(GetNHApp()->hMainWnd), IDM_MAP_TILES, IDM_MAP_ASCII10X18, mapmode2menuid( MAP_MODE_TILES ), MF_BYCOMMAND); } /* set fit-to-screen mode mark */ CheckMenuItem( GetMenu(GetNHApp()->hMainWnd), IDM_MAP_FIT_TO_SCREEN, MF_BYCOMMAND | (IS_MAP_FIT_TO_SCREEN(mode)? MF_CHECKED : MF_UNCHECKED) ); if( IS_MAP_ASCII(iflags.wc_map_mode) && !IS_MAP_FIT_TO_SCREEN(iflags.wc_map_mode)) { data->mapAcsiiModeSave = iflags.wc_map_mode; } iflags.wc_map_mode = mode; /* ** first, check if WIN_MAP has been inialized. ** If not - attempt to retrieve it by type, then check it again */ if( map_id==WIN_ERR ) map_id = mswin_winid_from_type(NHW_MAP); if( map_id!=WIN_ERR ) mswin_map_mode(mswin_hwnd_from_winid(map_id), mode); } static struct t_menu2mapmode { int menuID; int mapMode; } _menu2mapmode[] = { { IDM_MAP_TILES, MAP_MODE_TILES }, { IDM_MAP_ASCII4X6, MAP_MODE_ASCII4x6 }, { IDM_MAP_ASCII6X8, MAP_MODE_ASCII6x8 }, { IDM_MAP_ASCII8X8, MAP_MODE_ASCII8x8 }, { IDM_MAP_ASCII16X8, MAP_MODE_ASCII16x8 }, { IDM_MAP_ASCII7X12, MAP_MODE_ASCII7x12 }, { IDM_MAP_ASCII8X12, MAP_MODE_ASCII8x12 }, { IDM_MAP_ASCII12X16, MAP_MODE_ASCII12x16 }, { IDM_MAP_ASCII16X12, MAP_MODE_ASCII16x12 }, { IDM_MAP_ASCII10X18, MAP_MODE_ASCII10x18 }, { IDM_MAP_FIT_TO_SCREEN, MAP_MODE_ASCII_FIT_TO_SCREEN }, { -1, -1 } }; int menuid2mapmode(int menuid) { struct t_menu2mapmode* p; for( p = _menu2mapmode; p->mapMode!=-1; p++ ) if(p->menuID==menuid ) return p->mapMode; return -1; } int mapmode2menuid(int map_mode) { struct t_menu2mapmode* p; for( p = _menu2mapmode; p->mapMode!=-1; p++ ) if(p->mapMode==map_mode ) return p->menuID; return -1; } nethack-3.4.3/win/win32/mhmain.h0100644000000000000000000000067507764735042015044 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMainWindow_h #define MSWINMainWindow_h /* this is a main appliation window */ #include "winMS.h" HWND mswin_init_main_window (void); void mswin_layout_main_window(HWND changed_child); void mswin_select_map_mode(int map_mode); void mswin_menu_check_intf_mode(void); #endif /* MSWINMainWindow_h */ nethack-3.4.3/win/win32/mhmap.c0100644000000000000000000006611607764735042014672 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "resource.h" #include "mhmap.h" #include "mhmsg.h" #include "mhinput.h" #include "mhfont.h" #include "patchlevel.h" #define NHMAP_FONT_NAME TEXT("Terminal") #define MAXWINDOWTEXT 255 extern short glyph2tile[]; /* map window data */ typedef struct mswin_nethack_map_window { int map[COLNO][ROWNO]; /* glyph map */ int mapMode; /* current map mode */ boolean bAsciiMode; /* switch ASCII/tiled mode */ boolean bFitToScreenMode; /* switch Fit map to screen mode on/off */ int xPos, yPos; /* scroll position */ int xPageSize, yPageSize; /* scroll page size */ int xCur, yCur; /* position of the cursor */ int xScrTile, yScrTile; /* size of display tile */ POINT map_orig; /* map origin point */ HFONT hMapFont; /* font for ASCII mode */ } NHMapWindow, *PNHMapWindow; static TCHAR szNHMapWindowClass[] = TEXT("MSNethackMapWndClass"); LRESULT CALLBACK MapWndProc(HWND, UINT, WPARAM, LPARAM); static void register_map_window_class(void); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); static void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) static void nhglyph2charcolor(short glyph, uchar* ch, int* color); #endif static COLORREF nhcolor_to_RGB(int c); HWND mswin_init_map_window () { static int run_once = 0; HWND ret; if( !run_once ) { register_map_window_class(); run_once = 1; } ret = CreateWindow( szNHMapWindowClass, /* registered class name */ NULL, /* window name */ WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_CLIPSIBLINGS, /* window style */ 0, /* horizontal position of window - set it later */ 0, /* vertical position of window - set it later */ 0, /* window width - set it later */ 0, /* window height - set it later*/ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL ); /* window-creation data */ if( !ret ) { panic("Cannot create map window"); } return ret; } void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw) { PNHMapWindow data; RECT client_rt; SCROLLINFO si; SIZE wnd_size; LOGFONT lgfnt; /* check arguments */ if( !IsWindow(hWnd) || !lpsz || lpsz->cx<=0 || lpsz->cy<=0 ) return; /* calculate window size */ GetClientRect(hWnd, &client_rt); wnd_size.cx = client_rt.right - client_rt.left; wnd_size.cy = client_rt.bottom - client_rt.top; /* set new screen tile size */ data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); data->xScrTile = max(1, (data->bFitToScreenMode? wnd_size.cx : lpsz->cx) / COLNO); data->yScrTile = max(1, (data->bFitToScreenMode? wnd_size.cy : lpsz->cy) / ROWNO); /* set map origin point */ data->map_orig.x = max(0, client_rt.left + (wnd_size.cx - data->xScrTile*COLNO)/2 ); data->map_orig.y = max(0, client_rt.top + (wnd_size.cy - data->yScrTile*ROWNO)/2 ); data->map_orig.x -= data->map_orig.x % data->xScrTile; data->map_orig.y -= data->map_orig.y % data->yScrTile; /* adjust horizontal scroll bar */ if( data->bFitToScreenMode ) data->xPageSize = COLNO+1; /* disable scroll bar */ else data->xPageSize = wnd_size.cx/data->xScrTile; if( data->xPageSize >= COLNO ) { data->xPos = 0; GetNHApp()->bNoHScroll = TRUE; } else { GetNHApp()->bNoHScroll = FALSE; data->xPos = max(0, min(COLNO-data->xPageSize+1, u.ux - data->xPageSize/2)); } si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = COLNO; si.nPage = data->xPageSize; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); /* adjust vertical scroll bar */ if( data->bFitToScreenMode ) data->yPageSize = ROWNO+1; /* disable scroll bar */ else data->yPageSize = wnd_size.cy/data->yScrTile; if( data->yPageSize >= ROWNO ) { data->yPos = 0; GetNHApp()->bNoVScroll = TRUE; } else { GetNHApp()->bNoVScroll = FALSE; data->yPos = max(0, min(ROWNO-data->yPageSize+1, u.uy - data->yPageSize/2)); } si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = ROWNO; si.nPage = data->yPageSize; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); /* create font */ if( data->hMapFont ) DeleteObject(data->hMapFont); ZeroMemory(&lgfnt, sizeof(lgfnt)); lgfnt.lfHeight = -data->yScrTile; // height of font lgfnt.lfWidth = -data->xScrTile; // average character width lgfnt.lfEscapement = 0; // angle of escapement lgfnt.lfOrientation = 0; // base-line orientation angle lgfnt.lfWeight = FW_NORMAL; // font weight lgfnt.lfItalic = FALSE; // italic attribute option lgfnt.lfUnderline = FALSE; // underline attribute option lgfnt.lfStrikeOut = FALSE; // strikeout attribute option lgfnt.lfCharSet = mswin_charset(); // character set identifier lgfnt.lfOutPrecision = OUT_DEFAULT_PRECIS; // output precision lgfnt.lfClipPrecision = CLIP_DEFAULT_PRECIS; // clipping precision lgfnt.lfQuality = DEFAULT_QUALITY; // output quality if( iflags.wc_font_map && *iflags.wc_font_map ) { lgfnt.lfPitchAndFamily = DEFAULT_PITCH; // pitch and family NH_A2W(iflags.wc_font_map, lgfnt.lfFaceName, LF_FACESIZE); } else { lgfnt.lfPitchAndFamily = FIXED_PITCH; // pitch and family NH_A2W(NHMAP_FONT_NAME, lgfnt.lfFaceName, LF_FACESIZE); } data->hMapFont = CreateFontIndirect(&lgfnt); mswin_cliparound(data->xCur, data->yCur); if(redraw) InvalidateRect(hWnd, NULL, TRUE); } /* set map mode */ int mswin_map_mode(HWND hWnd, int mode) { PNHMapWindow data; int oldMode; SIZE mapSize; data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); if( mode == data->mapMode ) return mode; oldMode = data->mapMode; data->mapMode = mode; switch( data->mapMode ) { case MAP_MODE_ASCII4x6: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 4*COLNO; mapSize.cy = 6*ROWNO; break; case MAP_MODE_ASCII6x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 6*COLNO; mapSize.cy = 8*ROWNO; break; case MAP_MODE_ASCII8x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 8*COLNO; mapSize.cy = 8*ROWNO; break; case MAP_MODE_ASCII16x8: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 16*COLNO; mapSize.cy = 8*ROWNO; break; case MAP_MODE_ASCII7x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 7*COLNO; mapSize.cy = 12*ROWNO; break; case MAP_MODE_ASCII8x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 8*COLNO; mapSize.cy = 12*ROWNO; break; case MAP_MODE_ASCII16x12: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 16*COLNO; mapSize.cy = 12*ROWNO; break; case MAP_MODE_ASCII12x16: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 12*COLNO; mapSize.cy = 16*ROWNO; break; case MAP_MODE_ASCII10x18: data->bAsciiMode = TRUE; data->bFitToScreenMode = FALSE; mapSize.cx = 10*COLNO; mapSize.cy = 18*ROWNO; break; case MAP_MODE_ASCII_FIT_TO_SCREEN: { RECT client_rt; GetClientRect(hWnd, &client_rt); mapSize.cx = client_rt.right - client_rt.left; mapSize.cy = client_rt.bottom - client_rt.top; data->bAsciiMode = TRUE; data->bFitToScreenMode = TRUE; } break; case MAP_MODE_TILES_FIT_TO_SCREEN: { RECT client_rt; GetClientRect(hWnd, &client_rt); mapSize.cx = client_rt.right - client_rt.left; mapSize.cy = client_rt.bottom - client_rt.top; data->bAsciiMode = FALSE; data->bFitToScreenMode = TRUE; } break; case MAP_MODE_TILES: default: data->bAsciiMode = FALSE; data->bFitToScreenMode = FALSE; mapSize.cx = GetNHApp()->mapTile_X*COLNO; mapSize.cy = GetNHApp()->mapTile_Y*ROWNO; break; } mswin_map_stretch(hWnd, &mapSize, TRUE); return oldMode; } /* register window class for map window */ void register_map_window_class() { WNDCLASS wcex; ZeroMemory( &wcex, sizeof(wcex)); /* window class */ wcex.style = CS_NOCLOSE | CS_DBLCLKS; wcex.lpfnWndProc = (WNDPROC)MapWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = CreateSolidBrush(RGB(0, 0, 0)); /* set backgroup here */ wcex.lpszMenuName = NULL; wcex.lpszClassName = szNHMapWindowClass; if( !RegisterClass(&wcex) ) { panic("cannot register Map window class"); } } /* map window procedure */ LRESULT CALLBACK MapWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_CREATE: onCreate( hWnd, wParam, lParam ); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SETFOCUS: /* transfer focus back to the main window */ SetFocus(GetNHApp()->hMainWnd); break; case WM_HSCROLL: onMSNH_HScroll(hWnd, wParam, lParam); break; case WM_VSCROLL: onMSNH_VScroll(hWnd, wParam, lParam); break; case WM_SIZE: { SIZE size; if( data->bFitToScreenMode ) { size.cx = LOWORD(lParam); size.cy = HIWORD(lParam); } else { /* mapping factor is unchaged we just need to adjust scroll bars */ size.cx = data->xScrTile*COLNO; size.cy = data->yScrTile*ROWNO; } mswin_map_stretch(hWnd, &size, TRUE); } break; case WM_LBUTTONDOWN: NHEVENT_MS( CLICK_1, max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile)) ); return 0; case WM_LBUTTONDBLCLK : NHEVENT_MS( CLICK_2, max(0, min(COLNO, data->xPos + (LOWORD(lParam)-data->map_orig.x)/data->xScrTile)), max(0, min(ROWNO, data->yPos + (HIWORD(lParam)-data->map_orig.y)/data->yScrTile)) ); return 0; case WM_DESTROY: if( data->hMapFont ) DeleteObject(data->hMapFont); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } /* on WM_COMMAND */ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; RECT rt; data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); switch(wParam) { case MSNH_MSG_PRINT_GLYPH: { PMSNHMsgPrintGlyph msg_data = (PMSNHMsgPrintGlyph)lParam; data->map[msg_data->x][msg_data->y] = msg_data->glyph; /* invalidate the update area */ nhcoord2display(data, msg_data->x, msg_data->y, &rt); InvalidateRect(hWnd, &rt, TRUE); } break; case MSNH_MSG_CLIPAROUND: { PMSNHMsgClipAround msg_data = (PMSNHMsgClipAround)lParam; int x, y; BOOL scroll_x, scroll_y; int mcam = iflags.wc_scroll_margin; /* calculate if you should clip around */ scroll_x = !GetNHApp()->bNoHScroll && ( msg_data->x<(data->xPos+mcam) || msg_data->x>(data->xPos+data->xPageSize-mcam) ); scroll_y = !GetNHApp()->bNoVScroll && ( msg_data->y<(data->yPos+mcam) || msg_data->y>(data->yPos+data->yPageSize-mcam) ); mcam += iflags.wc_scroll_amount - 1; /* get page size and center horizontally on x-position */ if( scroll_x ) { if( data->xPageSize<=2*mcam ) { x = max(0, min(COLNO, msg_data->x - data->xPageSize/2)); } else if( msg_data->x < data->xPos+data->xPageSize/2 ) { x = max(0, min(COLNO, msg_data->x - mcam)); } else { x = max(0, min(COLNO, msg_data->x - data->xPageSize + mcam)); } SendMessage( hWnd, WM_HSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, x), (LPARAM)NULL ); } /* get page size and center vertically on y-position */ if( scroll_y ) { if( data->yPageSize<=2*mcam ) { y = max(0, min(ROWNO, msg_data->y - data->yPageSize/2)); } else if( msg_data->y < data->yPos+data->yPageSize/2 ) { y = max(0, min(ROWNO, msg_data->y - mcam)); } else { y = max(0, min(ROWNO, msg_data->y - data->yPageSize + mcam)); } SendMessage( hWnd, WM_VSCROLL, (WPARAM)MAKELONG(SB_THUMBTRACK, y), (LPARAM)NULL ); } } break; case MSNH_MSG_CLEAR_WINDOW: { int i, j; for(i=0; imap[i][j] = -1; } InvalidateRect(hWnd, NULL, TRUE); } break; case MSNH_MSG_CURSOR: { PMSNHMsgCursor msg_data = (PMSNHMsgCursor)lParam; HDC hdc; RECT rt; /* move focus rectangle at the cursor postion */ hdc = GetDC(hWnd); nhcoord2display(data, data->xCur, data->yCur, &rt); if( data->bAsciiMode ) { PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT); } else { DrawFocusRect(hdc, &rt); } data->xCur = msg_data->x; data->yCur = msg_data->y; nhcoord2display(data, data->xCur, data->yCur, &rt); if( data->bAsciiMode ) { PatBlt(hdc, rt.left, rt.top, rt.right-rt.left, rt.bottom-rt.top, DSTINVERT); } else { DrawFocusRect(hdc, &rt); } ReleaseDC(hWnd, hdc); } break; } } /* on WM_CREATE */ void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; int i,j; /* set window data */ data = (PNHMapWindow)malloc(sizeof(NHMapWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHMapWindow)); for(i=0; imap[i][j] = -1; } data->bAsciiMode = FALSE; data->xScrTile = GetNHApp()->mapTile_X; data->yScrTile = GetNHApp()->mapTile_Y; SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); } /* on WM_PAINT */ void onPaint(HWND hWnd) { PNHMapWindow data; PAINTSTRUCT ps; HDC hDC; HDC tileDC; HGDIOBJ saveBmp; RECT paint_rt; int i, j; /* get window data */ data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); hDC = BeginPaint(hWnd, &ps); /* calculate paint rectangle */ if( !IsRectEmpty(&ps.rcPaint) ) { /* calculate paint rectangle */ paint_rt.left = max(data->xPos + (ps.rcPaint.left - data->map_orig.x)/data->xScrTile, 0); paint_rt.top = max(data->yPos + (ps.rcPaint.top - data->map_orig.y)/data->yScrTile, 0); paint_rt.right = min(data->xPos + (ps.rcPaint.right - data->map_orig.x)/data->xScrTile+1, COLNO); paint_rt.bottom = min(data->yPos + (ps.rcPaint.bottom - data->map_orig.y)/data->yScrTile+1, ROWNO); if( data->bAsciiMode #ifdef REINCARNATION || Is_rogue_level(&u.uz) /* You enter a VERY primitive world! */ #endif ) { HGDIOBJ oldFont; oldFont = SelectObject(hDC, data->hMapFont); SetBkMode(hDC, TRANSPARENT); /* draw the map */ for(i=paint_rt.left; imap[i][j]>=0) { char ch; TCHAR wch; RECT glyph_rect; int color; unsigned special; int mgch; HBRUSH back_brush; COLORREF OldFg; nhcoord2display(data, i, j, &glyph_rect); #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) nhglyph2charcolor(data->map[i][j], &ch, &color); OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) ); #else /* rely on NetHack core helper routine */ mapglyph(data->map[i][j], &mgch, &color, &special, i, j); ch = (char)mgch; if (((special & MG_PET) && iflags.hilite_pet) || ((special & MG_DETECT) && iflags.use_inverse)) { back_brush = CreateSolidBrush(nhcolor_to_RGB(CLR_GRAY)); FillRect (hDC, &glyph_rect, back_brush); DeleteObject (back_brush); switch (color) { case CLR_GRAY: case CLR_WHITE: OldFg = SetTextColor( hDC, nhcolor_to_RGB(CLR_BLACK)); break; default: OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) ); } } else { OldFg = SetTextColor (hDC, nhcolor_to_RGB(color) ); } #endif DrawText(hDC, NH_A2W(&ch, &wch, 1), 1, &glyph_rect, DT_CENTER | DT_VCENTER | DT_NOPREFIX ); SetTextColor (hDC, OldFg); } SelectObject(hDC, oldFont); } else { /* prepare tiles DC for mapping */ tileDC = CreateCompatibleDC(hDC); saveBmp = SelectObject(tileDC, GetNHApp()->bmpMapTiles); /* draw the map */ for(i=paint_rt.left; imap[i][j]>=0) { short ntile; int t_x, t_y; RECT glyph_rect; ntile = glyph2tile[ data->map[i][j] ]; t_x = (ntile % GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_X; t_y = (ntile / GetNHApp()->mapTilesPerLine)*GetNHApp()->mapTile_Y; nhcoord2display(data, i, j, &glyph_rect); StretchBlt( hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, tileDC, t_x, t_y, GetNHApp()->mapTile_X, GetNHApp()->mapTile_Y, SRCCOPY ); if( glyph_is_pet(data->map[i][j]) && iflags.wc_hilite_pet ) { /* apply pet mark transparently over pet image */ HDC hdcPetMark; HBITMAP bmPetMarkOld; /* this is DC for petmark bitmap */ hdcPetMark = CreateCompatibleDC(hDC); bmPetMarkOld = SelectObject(hdcPetMark, GetNHApp()->bmpPetMark); nhapply_image_transparent( hDC, glyph_rect.left, glyph_rect.top, data->xScrTile, data->yScrTile, hdcPetMark, 0, 0, TILE_X, TILE_Y, TILE_BK_COLOR ); SelectObject(hdcPetMark, bmPetMarkOld); DeleteDC(hdcPetMark); } } SelectObject(tileDC, saveBmp); DeleteDC(tileDC); } /* draw focus rect */ nhcoord2display(data, data->xCur, data->yCur, &paint_rt); if( data->bAsciiMode ) { PatBlt( hDC, paint_rt.left, paint_rt.top, paint_rt.right-paint_rt.left, paint_rt.bottom-paint_rt.top, DSTINVERT ); } else { DrawFocusRect(hDC, &paint_rt); } } EndPaint(hWnd, &ps); } /* on WM_VSCROLL */ void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; SCROLLINFO si; int yNewPos; int yDelta; /* get window data */ data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); switch(LOWORD (wParam)) { /* User clicked shaft left of the scroll box. */ case SB_PAGEUP: yNewPos = data->yPos-data->yPageSize; break; /* User clicked shaft right of the scroll box. */ case SB_PAGEDOWN: yNewPos = data->yPos+data->yPageSize; break; /* User clicked the left arrow. */ case SB_LINEUP: yNewPos = data->yPos-1; break; /* User clicked the right arrow. */ case SB_LINEDOWN: yNewPos = data->yPos+1; break; /* User dragged the scroll box. */ case SB_THUMBTRACK: yNewPos = HIWORD(wParam); break; default: yNewPos = data->yPos; } yNewPos = max(0, min(ROWNO-data->yPageSize+1, yNewPos)); if( yNewPos == data->yPos ) return; yDelta = yNewPos - data->yPos; data->yPos = yNewPos; ScrollWindowEx (hWnd, 0, -data->yScrTile * yDelta, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } /* on WM_HSCROLL */ void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMapWindow data; SCROLLINFO si; int xNewPos; int xDelta; /* get window data */ data = (PNHMapWindow)GetWindowLong(hWnd, GWL_USERDATA); switch(LOWORD (wParam)) { /* User clicked shaft left of the scroll box. */ case SB_PAGEUP: xNewPos = data->xPos-data->xPageSize; break; /* User clicked shaft right of the scroll box. */ case SB_PAGEDOWN: xNewPos = data->xPos+data->xPageSize; break; /* User clicked the left arrow. */ case SB_LINEUP: xNewPos = data->xPos-1; break; /* User clicked the right arrow. */ case SB_LINEDOWN: xNewPos = data->xPos+1; break; /* User dragged the scroll box. */ case SB_THUMBTRACK: xNewPos = HIWORD(wParam); break; default: xNewPos = data->xPos; } xNewPos = max(0, min(COLNO-data->xPageSize+1, xNewPos)); if( xNewPos == data->xPos ) return; xDelta = xNewPos - data->xPos; data->xPos = xNewPos; ScrollWindowEx (hWnd, -data->xScrTile * xDelta, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); } /* map nethack map coordinates to the screen location */ void nhcoord2display(PNHMapWindow data, int x, int y, LPRECT lpOut) { lpOut->left = (x - data->xPos)*data->xScrTile + data->map_orig.x; lpOut->top = (y - data->yPos)*data->yScrTile + data->map_orig.y; lpOut->right = lpOut->left + data->xScrTile; lpOut->bottom = lpOut->top + data->yScrTile; } #if (VERSION_MAJOR < 4) && (VERSION_MINOR < 4) && (PATCHLEVEL < 2) /* map glyph to character/color combination */ void nhglyph2charcolor(short g, uchar* ch, int* color) { int offset; #ifdef TEXTCOLOR #define zap_color(n) *color = iflags.use_color ? zapcolors[n] : NO_COLOR #define cmap_color(n) *color = iflags.use_color ? defsyms[n].color : NO_COLOR #define obj_color(n) *color = iflags.use_color ? objects[n].oc_color : NO_COLOR #define mon_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define pet_color(n) *color = iflags.use_color ? mons[n].mcolor : NO_COLOR #define warn_color(n) *color = iflags.use_color ? def_warnsyms[n].color : NO_COLOR # else /* no text color */ #define zap_color(n) #define cmap_color(n) #define obj_color(n) #define mon_color(n) #define pet_color(c) #define warn_color(c) *color = CLR_WHITE; #endif if ((offset = (g - GLYPH_WARNING_OFF)) >= 0) { /* a warning flash */ *ch = warnsyms[offset]; warn_color(offset); } else if ((offset = (g - GLYPH_SWALLOW_OFF)) >= 0) { /* swallow */ /* see swallow_to_glyph() in display.c */ *ch = (uchar) showsyms[S_sw_tl + (offset & 0x7)]; mon_color(offset >> 3); } else if ((offset = (g - GLYPH_ZAP_OFF)) >= 0) { /* zap beam */ /* see zapdir_to_glyph() in display.c */ *ch = showsyms[S_vbeam + (offset & 0x3)]; zap_color((offset >> 2)); } else if ((offset = (g - GLYPH_CMAP_OFF)) >= 0) { /* cmap */ *ch = showsyms[offset]; cmap_color(offset); } else if ((offset = (g - GLYPH_OBJ_OFF)) >= 0) { /* object */ *ch = oc_syms[(int)objects[offset].oc_class]; obj_color(offset); } else if ((offset = (g - GLYPH_BODY_OFF)) >= 0) { /* a corpse */ *ch = oc_syms[(int)objects[CORPSE].oc_class]; mon_color(offset); } else if ((offset = (g - GLYPH_PET_OFF)) >= 0) { /* a pet */ *ch = monsyms[(int)mons[offset].mlet]; pet_color(offset); } else { /* a monster */ *ch = monsyms[(int)mons[g].mlet]; mon_color(g); } // end of wintty code } #endif /* map nethack color to RGB */ COLORREF nhcolor_to_RGB(int c) { switch(c) { case CLR_BLACK: return RGB(0x55, 0x55, 0x55); case CLR_RED: return RGB(0xFF, 0x00, 0x00); case CLR_GREEN: return RGB(0x00, 0x80, 0x00); case CLR_BROWN: return RGB(0xA5, 0x2A, 0x2A); case CLR_BLUE: return RGB(0x00, 0x00, 0xFF); case CLR_MAGENTA: return RGB(0xFF, 0x00, 0xFF); case CLR_CYAN: return RGB(0x00, 0xFF, 0xFF); case CLR_GRAY: return RGB(0xC0, 0xC0, 0xC0); case NO_COLOR: return RGB(0xFF, 0xFF, 0xFF); case CLR_ORANGE: return RGB(0xFF, 0xA5, 0x00); case CLR_BRIGHT_GREEN: return RGB(0x00, 0xFF, 0x00); case CLR_YELLOW: return RGB(0xFF, 0xFF, 0x00); case CLR_BRIGHT_BLUE: return RGB(0x00, 0xC0, 0xFF); case CLR_BRIGHT_MAGENTA: return RGB(0xFF, 0x80, 0xFF); case CLR_BRIGHT_CYAN: return RGB(0x80, 0xFF, 0xFF); /* something close to aquamarine */ case CLR_WHITE: return RGB(0xFF, 0xFF, 0xFF); default: return RGB(0x00, 0x00, 0x00); /* black */ } } /* apply bitmap pointed by sourceDc transparently over bitmap pointed by hDC */ typedef BOOL (WINAPI* LPTRANSPARENTBLT)(HDC, int, int, int, int, HDC, int, int, int, int, UINT); void nhapply_image_transparent( HDC hDC, int x, int y, int width, int height, HDC sourceDC, int s_x, int s_y, int s_width, int s_height, COLORREF cTransparent ) { /* Don't use TransparentBlt; According to Microsoft, it contains a memory leak in Window 95/98. */ HDC hdcMem, hdcBack, hdcObject, hdcSave; COLORREF cColor; HBITMAP bmAndBack, bmAndObject, bmAndMem, bmSave; HBITMAP bmBackOld, bmObjectOld, bmMemOld, bmSaveOld; /* Create some DCs to hold temporary data. */ hdcBack = CreateCompatibleDC(hDC); hdcObject = CreateCompatibleDC(hDC); hdcMem = CreateCompatibleDC(hDC); hdcSave = CreateCompatibleDC(hDC); /* this is bitmap for our pet image */ bmSave = CreateCompatibleBitmap(hDC, width, height); /* Monochrome DC */ bmAndBack = CreateBitmap(width, height, 1, 1, NULL); bmAndObject = CreateBitmap(width, height, 1, 1, NULL); /* resulting bitmap */ bmAndMem = CreateCompatibleBitmap(hDC, width, height); /* Each DC must select a bitmap object to store pixel data. */ bmBackOld = SelectObject(hdcBack, bmAndBack); bmObjectOld = SelectObject(hdcObject, bmAndObject); bmMemOld = SelectObject(hdcMem, bmAndMem); bmSaveOld = SelectObject(hdcSave, bmSave); /* copy source image because it is going to be overwritten */ StretchBlt(hdcSave, 0, 0, width, height, sourceDC, s_x, s_y, s_width, s_height, SRCCOPY); /* Set the background color of the source DC to the color. contained in the parts of the bitmap that should be transparent */ cColor = SetBkColor(hdcSave, cTransparent); /* Create the object mask for the bitmap by performing a BitBlt from the source bitmap to a monochrome bitmap. */ BitBlt(hdcObject, 0, 0, width, height, hdcSave, 0, 0, SRCCOPY); /* Set the background color of the source DC back to the original color. */ SetBkColor(hdcSave, cColor); /* Create the inverse of the object mask. */ BitBlt(hdcBack, 0, 0, width, height, hdcObject, 0, 0, NOTSRCCOPY); /* Copy background to the resulting image */ BitBlt(hdcMem, 0, 0, width, height, hDC, x, y, SRCCOPY); /* Mask out the places where the source image will be placed. */ BitBlt(hdcMem, 0, 0, width, height, hdcObject, 0, 0, SRCAND); /* Mask out the transparent colored pixels on the source image. */ BitBlt(hdcSave, 0, 0, width, height, hdcBack, 0, 0, SRCAND); /* XOR the source image with the beckground. */ BitBlt(hdcMem, 0, 0, width, height, hdcSave, 0, 0, SRCPAINT); /* blt resulting image to the screen */ BitBlt( hDC, x, y, width, height, hdcMem, 0, 0, SRCCOPY ); /* cleanup */ DeleteObject(SelectObject(hdcBack, bmBackOld)); DeleteObject(SelectObject(hdcObject, bmObjectOld)); DeleteObject(SelectObject(hdcMem, bmMemOld)); DeleteObject(SelectObject(hdcSave, bmSaveOld)); DeleteDC(hdcMem); DeleteDC(hdcBack); DeleteDC(hdcObject); DeleteDC(hdcSave); } nethack-3.4.3/win/win32/mhmap.h0100644000000000000000000000102307764735042014661 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMapWindow_h #define MSWINMapWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_map_window (void); void mswin_map_stretch(HWND hWnd, LPSIZE lpsz, BOOL redraw); int mswin_map_mode(HWND hWnd, int mode); #define ROGUE_LEVEL_MAP_MODE MAP_MODE_ASCII12x16 #define DEF_CLIPAROUND_MARGIN 5 #define DEF_CLIPAROUND_AMOUNT 1 #endif /* MSWINMapWindow_h */ nethack-3.4.3/win/win32/mhmenu.c0100644000000000000000000012001307764735042015044 0ustar rootroot/* SCCS Id: @(#)mhmenu.c 3.4 2002/03/06 */ /* Copyright (c) Alex Kompel, 2002 */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include #include "resource.h" #include "mhmenu.h" #include "mhmain.h" #include "mhmsg.h" #include "mhfont.h" #include "mhdlg.h" #define MENU_MARGIN 0 #define NHMENU_STR_SIZE BUFSZ #define MIN_TABSTOP_SIZE 0 #define NUMTABS 15 #define TAB_SEPARATION 10 /* pixels between each tab stop */ #define DEFAULT_COLOR_BG_TEXT COLOR_WINDOW #define DEFAULT_COLOR_FG_TEXT COLOR_WINDOWTEXT #define DEFAULT_COLOR_BG_MENU COLOR_WINDOW #define DEFAULT_COLOR_FG_MENU COLOR_WINDOWTEXT typedef struct mswin_menu_item { int glyph; ANY_P identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; char str[NHMENU_STR_SIZE]; BOOLEAN_P presel; int count; BOOL has_focus; } NHMenuItem, *PNHMenuItem; typedef struct mswin_nethack_menu_window { int type; /* MENU_TYPE_TEXT or MENU_TYPE_MENU */ int how; /* for menus: PICK_NONE, PICK_ONE, PICK_ANY */ union { struct menu_list { int size; /* number of items in items[] */ int allocated; /* number of allocated slots in items[] */ PNHMenuItem items; /* menu items */ char gacc[QBUFSZ]; /* group accelerators */ BOOL counting; /* counting flag */ char prompt[QBUFSZ]; /* menu prompt */ int tab_stop_size[NUMTABS];/* tabstops to align option values */ } menu; struct menu_text { TCHAR* text; } text; }; int result; int done; HBITMAP bmpChecked; HBITMAP bmpCheckedCount; HBITMAP bmpNotChecked; } NHMenuWindow, *PNHMenuWindow; extern short glyph2tile[]; static WNDPROC wndProcListViewOrig = NULL; static WNDPROC editControlWndProc = NULL; #define NHMENU_IS_SELECTABLE(item) ((item).identifier.a_obj!=NULL) #define NHMENU_IS_SELECTED(item) ((item).count!=0) BOOL CALLBACK MenuWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuListWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHMenuTextWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static BOOL onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutMenu(HWND hwnd); static void SetMenuType(HWND hwnd, int type); static void SetMenuListType(HWND hwnd, int now); static HWND GetMenuControl(HWND hwnd); static void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count); static void reset_menu_count(HWND hwndList, PNHMenuWindow data); static BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch); /*-----------------------------------------------------------------------------*/ HWND mswin_init_menu_window (int type) { HWND ret; ret = CreateDialog( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_MENU), GetNHApp()->hMainWnd, MenuWndProc ); if( !ret ) { panic("Cannot create menu window"); } SetMenuType(ret, type); return ret; } /*-----------------------------------------------------------------------------*/ int mswin_menu_window_select_menu (HWND hWnd, int how, MENU_ITEM_P ** _selected) { PNHMenuWindow data; int ret_val; MENU_ITEM_P *selected = NULL; int i; char* ap; assert( _selected!=NULL ); *_selected = NULL; ret_val = -1; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); /* set menu type */ SetMenuListType(hWnd, how); /* Ok, now give items a unique accelerators */ if( data->type == MENU_TYPE_MENU ) { char next_char = 'a'; data->menu.gacc[0] = '\0'; ap = data->menu.gacc; for( i=0; imenu.size; i++) { if( data->menu.items[i].accelerator!=0 ) { next_char = (char)(data->menu.items[i].accelerator+1); } else if( NHMENU_IS_SELECTABLE(data->menu.items[i]) ) { if ( (next_char>='a' && next_char<='z') || (next_char>='A' && next_char<='Z') ) { data->menu.items[i].accelerator = next_char; } else { if( next_char > 'z' ) next_char = 'A'; else if ( next_char > 'Z' ) break; data->menu.items[i].accelerator = next_char; } next_char ++; } } /* collect group accelerators */ for( i=0; imenu.size; i++) { if( data->how != PICK_NONE ) { if( data->menu.items[i].group_accel && !strchr(data->menu.gacc, data->menu.items[i].group_accel) ) { *ap++ = data->menu.items[i].group_accel; *ap = '\x0'; } } } reset_menu_count(NULL, data); } mswin_popup_display(hWnd, &data->done); /* get the result */ if( data->result != -1 ) { if(how==PICK_NONE) { if(data->result>=0) ret_val=0; else ret_val=-1; } else if(how==PICK_ONE || how==PICK_ANY) { /* count selected items */ ret_val = 0; for(i=0; imenu.size; i++ ) { if( NHMENU_IS_SELECTABLE(data->menu.items[i]) && NHMENU_IS_SELECTED(data->menu.items[i]) ) { ret_val++; } } if( ret_val > 0 ) { int sel_ind; selected = (MENU_ITEM_P*)malloc(ret_val*sizeof(MENU_ITEM_P)); if( !selected ) panic("out of memory"); sel_ind = 0; for(i=0; imenu.size; i++ ) { if( NHMENU_IS_SELECTABLE(data->menu.items[i]) && NHMENU_IS_SELECTED(data->menu.items[i]) ) { selected[sel_ind].item = data->menu.items[i].identifier; selected[sel_ind].count = data->menu.items[i].count; sel_ind++; } } ret_val = sel_ind; *_selected = selected; } } } mswin_popup_destroy(hWnd); return ret_val; } /*-----------------------------------------------------------------------------*/ BOOL CALLBACK MenuWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { PNHMenuWindow data; HWND control; HDC hdc; TCHAR title[MAX_LOADSTRING]; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_INITDIALOG: data = (PNHMenuWindow)malloc(sizeof(NHMenuWindow)); ZeroMemory(data, sizeof(NHMenuWindow)); data->type = MENU_TYPE_TEXT; data->how = PICK_NONE; data->result = 0; data->done = 0; data->bmpChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL)); data->bmpCheckedCount = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_SEL_COUNT)); data->bmpNotChecked = LoadBitmap(GetNHApp()->hApp, MAKEINTRESOURCE(IDB_MENU_UNSEL)); SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); /* set font for the text cotrol */ control = GetDlgItem(hWnd, IDC_MENU_TEXT); hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM)mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE), (LPARAM)0); ReleaseDC(control, hdc); /* subclass edit control */ editControlWndProc = (WNDPROC)GetWindowLong(control, GWL_WNDPROC); SetWindowLong(control, GWL_WNDPROC, (LONG)NHMenuTextWndProc); /* Even though the dialog has no caption, you can still set the title which shows on Alt-Tab */ LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING); SetWindowText(hWnd, title); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_SIZE: LayoutMenu(hWnd); return FALSE; case WM_CLOSE: if (program_state.gameover) { data->result = -1; data->done = 1; program_state.stopprint++; return TRUE; } else return FALSE; case WM_COMMAND: { switch (LOWORD(wParam)) { case IDCANCEL: if( data->type == MENU_TYPE_MENU && (data->how==PICK_ONE || data->how==PICK_ANY) && data->menu.counting) { HWND list; int i; /* reset counter if counting is in progress */ list = GetMenuControl(hWnd); i = ListView_GetNextItem(list, -1, LVNI_FOCUSED); if( i>=0 ) { SelectMenuItem(list, data, i, 0); } return TRUE; } else { data->result = -1; data->done = 1; } return TRUE; case IDOK: data->done = 1; data->result = 0; return TRUE; case IDC_MENU_TEXT: switch (HIWORD(wParam)) { case EN_SETFOCUS: HideCaret((HWND)lParam); return TRUE; } } } break; case WM_NOTIFY: { LPNMHDR lpnmhdr = (LPNMHDR)lParam; switch (LOWORD(wParam)) { case IDC_MENU_LIST: { if( !data || data->type!=MENU_TYPE_MENU ) break; switch(lpnmhdr->code) { case LVN_ITEMACTIVATE: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam; if(data->how==PICK_ONE) { if( lpnmlv->iItem>=0 && lpnmlv->iItemmenu.size && NHMENU_IS_SELECTABLE(data->menu.items[lpnmlv->iItem]) ) { SelectMenuItem( lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1 ); data->done = 1; data->result = 0; return TRUE; } } } break; case NM_CLICK: { LPNMLISTVIEW lpnmitem = (LPNMLISTVIEW) lParam; if( lpnmitem->iItem==-1 ) return 0; if( data->how==PICK_ANY ) { SelectMenuItem( lpnmitem->hdr.hwndFrom, data, lpnmitem->iItem, NHMENU_IS_SELECTED(data->menu.items[lpnmitem->iItem])? 0 : -1 ); } } break; case LVN_ITEMCHANGED: { LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lParam; if( lpnmlv->iItem==-1 ) return 0; if( !(lpnmlv->uChanged & LVIF_STATE) ) return 0; if( data->how==PICK_ONE || data->how==PICK_ANY ) { data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); } /* update count for single-selection menu (follow the listview selection) */ if( data->how==PICK_ONE ) { if( lpnmlv->uNewState & LVIS_SELECTED ) { SelectMenuItem( lpnmlv->hdr.hwndFrom, data, lpnmlv->iItem, -1 ); } } /* check item focus */ if( data->how==PICK_ONE || data->how==PICK_ANY ) { data->menu.items[lpnmlv->iItem].has_focus = !!(lpnmlv->uNewState & LVIS_FOCUSED); ListView_RedrawItems(lpnmlv->hdr.hwndFrom, lpnmlv->iItem, lpnmlv->iItem); } } break; case NM_KILLFOCUS: reset_menu_count(lpnmhdr->hwndFrom, data); break; } } break; } } break; case WM_SETFOCUS: if( hWnd!=GetNHApp()->hPopupWnd ) { SetFocus(GetNHApp()->hPopupWnd ); } break; case WM_MEASUREITEM: if( wParam==IDC_MENU_LIST ) return onMeasureItem(hWnd, wParam, lParam); else return FALSE; case WM_DRAWITEM: if( wParam==IDC_MENU_LIST ) return onDrawItem(hWnd, wParam, lParam); else return FALSE; case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */ HDC hdcEdit = (HDC) wParam; HWND hwndEdit = (HWND) lParam; if( hwndEdit == GetDlgItem(hWnd, IDC_MENU_TEXT) ) { SetBkColor(hdcEdit, text_bg_brush ? text_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_TEXT) ); SetTextColor(hdcEdit, text_fg_brush ? text_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_TEXT) ); return (BOOL)(text_bg_brush ? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT)); } } return FALSE; case WM_DESTROY: if( data ) { DeleteObject(data->bmpChecked); DeleteObject(data->bmpCheckedCount); DeleteObject(data->bmpNotChecked); if( data->type == MENU_TYPE_TEXT ) { if( data->text.text ) free(data->text.text); } free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); } return TRUE; } return FALSE; } /*-----------------------------------------------------------------------------*/ void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMenuWindow data; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( wParam ) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam; HWND text_view; TCHAR wbuf[BUFSZ]; size_t text_size; if( data->type!=MENU_TYPE_TEXT ) SetMenuType(hWnd, MENU_TYPE_TEXT); if( !data->text.text ) { text_size = strlen(msg_data->text) + 4; data->text.text = (TCHAR*)malloc(text_size*sizeof(data->text.text[0])); ZeroMemory(data->text.text, text_size*sizeof(data->text.text[0])); } else { text_size = _tcslen(data->text.text) + strlen(msg_data->text) + 4; data->text.text = (TCHAR*)realloc(data->text.text, text_size*sizeof(data->text.text[0])); } if( !data->text.text ) break; _tcscat(data->text.text, NH_A2W(msg_data->text, wbuf, BUFSZ)); _tcscat(data->text.text, TEXT("\r\n")); text_view = GetDlgItem(hWnd, IDC_MENU_TEXT); if( !text_view ) panic("cannot get text view window"); SetWindowText(text_view, data->text.text); } break; case MSNH_MSG_STARTMENU: { int i; if( data->type!=MENU_TYPE_MENU ) SetMenuType(hWnd, MENU_TYPE_MENU); if( data->menu.items ) free(data->menu.items); data->how = PICK_NONE; data->menu.items = NULL; data->menu.size = 0; data->menu.allocated = 0; data->done = 0; data->result = 0; for (i = 0; i < NUMTABS; ++i) data->menu.tab_stop_size[i] = MIN_TABSTOP_SIZE; } break; case MSNH_MSG_ADDMENU: { PMSNHMsgAddMenu msg_data = (PMSNHMsgAddMenu)lParam; char *p, *p1; int new_item; HDC hDC; int column; HFONT saveFont; if( data->type!=MENU_TYPE_MENU ) break; if( strlen(msg_data->str)==0 ) break; if( data->menu.size==data->menu.allocated ) { data->menu.allocated += 10; data->menu.items = (PNHMenuItem)realloc(data->menu.items, data->menu.allocated*sizeof(NHMenuItem)); } new_item = data->menu.size; ZeroMemory( &data->menu.items[new_item], sizeof(data->menu.items[new_item])); data->menu.items[new_item].glyph = msg_data->glyph; data->menu.items[new_item].identifier = *msg_data->identifier; data->menu.items[new_item].accelerator = msg_data->accelerator; data->menu.items[new_item].group_accel = msg_data->group_accel; data->menu.items[new_item].attr = msg_data->attr; strncpy(data->menu.items[new_item].str, msg_data->str, NHMENU_STR_SIZE); data->menu.items[new_item].presel = msg_data->presel; /* calculate tabstop size */ hDC = GetDC(hWnd); saveFont = SelectObject(hDC, mswin_get_font(NHW_MENU, msg_data->attr, hDC, FALSE)); p1 = data->menu.items[new_item].str; p = strchr(data->menu.items[new_item].str, '\t'); column = 0; for (;;) { TCHAR wbuf[BUFSZ]; RECT drawRect; SetRect ( &drawRect, 0, 0, 1, 1 ); if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_EXPANDTABS | DT_SINGLELINE ); data->menu.tab_stop_size[column] = max( data->menu.tab_stop_size[column], drawRect.right - drawRect.left ); if (p != NULL) *p = '\t'; else /* last string so, */ break; ++column; p1 = p + 1; p = strchr(p1, '\t'); } SelectObject(hDC, saveFont); ReleaseDC(hWnd, hDC); /* increment size */ data->menu.size++; } break; case MSNH_MSG_ENDMENU: { PMSNHMsgEndMenu msg_data = (PMSNHMsgEndMenu)lParam; if( msg_data->text ) { strncpy( data->menu.prompt, msg_data->text, sizeof(data->menu.prompt)-1 ); } else { ZeroMemory(data->menu.prompt, sizeof(data->menu.prompt)); } } break; } } /*-----------------------------------------------------------------------------*/ void LayoutMenu(HWND hWnd) { PNHMenuWindow data; HWND menu_ok; HWND menu_cancel; RECT clrt, rt; POINT pt_elem, pt_ok, pt_cancel; SIZE sz_elem, sz_ok, sz_cancel; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); menu_ok = GetDlgItem(hWnd, IDOK); menu_cancel = GetDlgItem(hWnd, IDCANCEL); /* get window coordinates */ GetClientRect(hWnd, &clrt ); /* set window placements */ GetWindowRect(menu_ok, &rt); sz_ok.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN; sz_ok.cy = rt.bottom-rt.top; pt_ok.x = clrt.left + MENU_MARGIN; pt_ok.y = clrt.bottom - MENU_MARGIN - sz_ok.cy; GetWindowRect(menu_cancel, &rt); sz_cancel.cx = (clrt.right - clrt.left)/2 - 2*MENU_MARGIN; sz_cancel.cy = rt.bottom-rt.top; pt_cancel.x = (clrt.left + clrt.right)/2 + MENU_MARGIN; pt_cancel.y = clrt.bottom - MENU_MARGIN - sz_cancel.cy; pt_elem.x = clrt.left + MENU_MARGIN; pt_elem.y = clrt.top + MENU_MARGIN; sz_elem.cx = (clrt.right - clrt.left) - 2*MENU_MARGIN; sz_elem.cy = min(pt_cancel.y, pt_ok.y) - 2*MENU_MARGIN; MoveWindow(GetMenuControl(hWnd), pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE ); MoveWindow(menu_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE ); MoveWindow(menu_cancel, pt_cancel.x, pt_cancel.y, sz_cancel.cx, sz_cancel.cy, TRUE ); } /*-----------------------------------------------------------------------------*/ void SetMenuType(HWND hWnd, int type) { PNHMenuWindow data; HWND list, text; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); data->type = type; text = GetDlgItem(hWnd, IDC_MENU_TEXT); list = GetDlgItem(hWnd, IDC_MENU_LIST); if(data->type==MENU_TYPE_TEXT) { ShowWindow(list, SW_HIDE); EnableWindow(list, FALSE); EnableWindow(text, TRUE); ShowWindow(text, SW_SHOW); SetFocus(text); } else { ShowWindow(text, SW_HIDE); EnableWindow(text, FALSE); EnableWindow(list, TRUE); ShowWindow(list, SW_SHOW); SetFocus(list); } LayoutMenu(hWnd); } /*-----------------------------------------------------------------------------*/ void SetMenuListType(HWND hWnd, int how) { PNHMenuWindow data; RECT rt; DWORD dwStyles; char buf[BUFSZ]; TCHAR wbuf[BUFSZ]; int nItem; int i; HWND control; LVCOLUMN lvcol; LRESULT fnt; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); if( data->type != MENU_TYPE_MENU ) return; data->how = how; switch(how) { case PICK_NONE: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; case PICK_ONE: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; case PICK_ANY: dwStyles = WS_VISIBLE | WS_TABSTOP | WS_BORDER | WS_CHILD | WS_VSCROLL | WS_HSCROLL | LVS_REPORT | LVS_OWNERDRAWFIXED | LVS_SINGLESEL; break; default: panic("how should be one of PICK_NONE, PICK_ONE or PICK_ANY"); }; if( strlen(data->menu.prompt)==0 ) { dwStyles |= LVS_NOCOLUMNHEADER ; } GetWindowRect(GetDlgItem(hWnd, IDC_MENU_LIST), &rt); DestroyWindow(GetDlgItem(hWnd, IDC_MENU_LIST)); control = CreateWindow(WC_LISTVIEW, NULL, dwStyles, rt.left, rt.top, rt.right - rt.left, rt.bottom - rt.top, hWnd, (HMENU)IDC_MENU_LIST, GetNHApp()->hApp, NULL ); if( !control ) panic( "cannot create menu control" ); /* install the hook for the control window procedure */ wndProcListViewOrig = (WNDPROC)GetWindowLong(control, GWL_WNDPROC); SetWindowLong(control, GWL_WNDPROC, (LONG)NHMenuListWndProc); /* set control colors */ ListView_SetBkColor(control, menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU)); ListView_SetTextBkColor(control, menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU)); ListView_SetTextColor(control, menu_fg_brush ? menu_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MENU)); /* set control font */ fnt = SendMessage(hWnd, WM_GETFONT, (WPARAM)0, (LPARAM)0); SendMessage(control, WM_SETFONT, (WPARAM)fnt, (LPARAM)0); /* add column to the list view */ ZeroMemory(&lvcol, sizeof(lvcol)); lvcol.mask = LVCF_WIDTH | LVCF_TEXT; lvcol.cx = GetSystemMetrics(SM_CXFULLSCREEN); lvcol.pszText = NH_A2W(data->menu.prompt, wbuf, BUFSZ); ListView_InsertColumn(control, 0, &lvcol); /* add items to the list view */ for(i=0; imenu.size; i++ ) { LVITEM lvitem; ZeroMemory( &lvitem, sizeof(lvitem) ); sprintf(buf, "%c - %s", max(data->menu.items[i].accelerator, ' '), data->menu.items[i].str ); lvitem.mask = LVIF_PARAM | LVIF_STATE | LVIF_TEXT; lvitem.iItem = i; lvitem.iSubItem = 0; lvitem.state = data->menu.items[i].presel? LVIS_SELECTED : 0; lvitem.pszText = NH_A2W(buf, wbuf, BUFSZ); lvitem.lParam = (LPARAM)&data->menu.items[i]; nItem = SendMessage(control, LB_ADDSTRING, (WPARAM)0, (LPARAM) buf); if( ListView_InsertItem(control, &lvitem)==-1 ) { panic("cannot insert menu item"); } } SetFocus(control); } /*-----------------------------------------------------------------------------*/ HWND GetMenuControl(HWND hWnd) { PNHMenuWindow data; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); if(data->type==MENU_TYPE_TEXT) { return GetDlgItem(hWnd, IDC_MENU_TEXT); } else { return GetDlgItem(hWnd, IDC_MENU_LIST); } } /*-----------------------------------------------------------------------------*/ BOOL onMeasureItem(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPMEASUREITEMSTRUCT lpmis; TEXTMETRIC tm; HGDIOBJ saveFont; HDC hdc; PNHMenuWindow data; RECT list_rect; lpmis = (LPMEASUREITEMSTRUCT) lParam; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); GetClientRect(GetMenuControl(hWnd), &list_rect); hdc = GetDC(GetMenuControl(hWnd)); saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, FALSE)); GetTextMetrics(hdc, &tm); /* Set the height of the list box items. */ lpmis->itemHeight = max(tm.tmHeight, TILE_Y)+2; lpmis->itemWidth = list_rect.right - list_rect.left; SelectObject(hdc, saveFont); ReleaseDC(GetMenuControl(hWnd), hdc); return TRUE; } /*-----------------------------------------------------------------------------*/ BOOL onDrawItem(HWND hWnd, WPARAM wParam, LPARAM lParam) { LPDRAWITEMSTRUCT lpdis; PNHMenuItem item; PNHMenuWindow data; TEXTMETRIC tm; HGDIOBJ saveFont; HDC tileDC; short ntile; int t_x, t_y; int x, y; TCHAR wbuf[BUFSZ]; RECT drawRect; COLORREF OldBg, OldFg, NewBg; char *p, *p1; int column; lpdis = (LPDRAWITEMSTRUCT) lParam; /* If there are no list box items, skip this message. */ if (lpdis->itemID == -1) return FALSE; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); item = &data->menu.items[lpdis->itemID]; tileDC = CreateCompatibleDC(lpdis->hDC); saveFont = SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, item->attr, lpdis->hDC, FALSE)); NewBg = menu_bg_brush ? menu_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MENU); OldBg = SetBkColor(lpdis->hDC, NewBg); OldFg = SetTextColor(lpdis->hDC, menu_fg_brush ? menu_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MENU)); GetTextMetrics(lpdis->hDC, &tm); x = lpdis->rcItem.left + 1; /* print check mark and letter */ if( NHMENU_IS_SELECTABLE(*item) ) { char buf[2]; if (data->how != PICK_NONE) { HGDIOBJ saveBrush; HBRUSH hbrCheckMark; switch(item->count) { case -1: hbrCheckMark = CreatePatternBrush(data->bmpChecked); break; case 0: hbrCheckMark = CreatePatternBrush(data->bmpNotChecked); break; default: hbrCheckMark = CreatePatternBrush(data->bmpCheckedCount); break; } y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; SetBrushOrgEx(lpdis->hDC, x, y, NULL); saveBrush = SelectObject(lpdis->hDC, hbrCheckMark); PatBlt(lpdis->hDC, x, y, TILE_X, TILE_Y, PATCOPY); SelectObject(lpdis->hDC, saveBrush); DeleteObject(hbrCheckMark); } x += TILE_X + 5; if(item->accelerator!=0) { buf[0] = item->accelerator; buf[1] = '\x0'; SetRect( &drawRect, x, lpdis->rcItem.top, lpdis->rcItem.right, lpdis->rcItem.bottom ); DrawText(lpdis->hDC, NH_A2W(buf, wbuf, 2), 1, &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); } x += tm.tmAveCharWidth + tm.tmOverhang + 5; } else { x += TILE_X + tm.tmAveCharWidth + tm.tmOverhang + 10; } /* print glyph if present */ if( item->glyph != NO_GLYPH ) { HGDIOBJ saveBmp; saveBmp = SelectObject(tileDC, GetNHApp()->bmpTiles); ntile = glyph2tile[ item->glyph ]; t_x = (ntile % TILES_PER_LINE)*TILE_X; t_y = (ntile / TILES_PER_LINE)*TILE_Y; y = (lpdis->rcItem.bottom + lpdis->rcItem.top - TILE_Y) / 2; nhapply_image_transparent( lpdis->hDC, x, y, TILE_X, TILE_Y, tileDC, t_x, t_y, TILE_X, TILE_Y, TILE_BK_COLOR ); SelectObject(tileDC, saveBmp); } x += TILE_X + 5; /* draw item text */ p1 = item->str; p = strchr(item->str, '\t'); column = 0; SetRect( &drawRect, x, lpdis->rcItem.top, min(x + data->menu.tab_stop_size[0], lpdis->rcItem.right), lpdis->rcItem.bottom ); for (;;) { TCHAR wbuf[BUFSZ]; if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(lpdis->hDC, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &drawRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE ); if (p != NULL) *p = '\t'; else /* last string so, */ break; p1 = p + 1; p = strchr(p1, '\t'); drawRect.left = drawRect.right + TAB_SEPARATION; ++column; drawRect.right = min (drawRect.left + data->menu.tab_stop_size[column], lpdis->rcItem.right); } /* draw focused item */ if( item->has_focus || (NHMENU_IS_SELECTABLE(*item) && data->menu.items[lpdis->itemID].count!=-1)) { RECT client_rt; GetClientRect(lpdis->hwndItem, &client_rt); if( NHMENU_IS_SELECTABLE(*item) && data->menu.items[lpdis->itemID].count!=0 && item->glyph != NO_GLYPH ) { if( data->menu.items[lpdis->itemID].count==-1 ) { _stprintf(wbuf, TEXT("Count: All") ); } else { _stprintf(wbuf, TEXT("Count: %d"), data->menu.items[lpdis->itemID].count ); } SelectObject(lpdis->hDC, mswin_get_font(NHW_MENU, ATR_BLINK, lpdis->hDC, FALSE)); /* calculate text rectangle */ SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom ); DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, DT_CALCRECT | DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX ); /* erase text rectangle */ drawRect.left = max(client_rt.left+1, client_rt.right - (drawRect.right - drawRect.left) - 10); drawRect.right = client_rt.right-1; drawRect.top = lpdis->rcItem.top; drawRect.bottom = lpdis->rcItem.bottom; FillRect(lpdis->hDC, &drawRect, menu_bg_brush ? menu_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MENU)); /* draw text */ DrawText(lpdis->hDC, wbuf, _tcslen(wbuf), &drawRect, DT_RIGHT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX ); } } if (item->has_focus) { /* draw focus rect */ RECT client_rt; GetClientRect(lpdis->hwndItem, &client_rt); SetRect( &drawRect, client_rt.left, lpdis->rcItem.top, client_rt.right, lpdis->rcItem.bottom ); DrawFocusRect(lpdis->hDC, &drawRect); } SetTextColor (lpdis->hDC, OldFg); SetBkColor (lpdis->hDC, OldBg); SelectObject(lpdis->hDC, saveFont); DeleteDC(tileDC); return TRUE; } /*-----------------------------------------------------------------------------*/ BOOL onListChar(HWND hWnd, HWND hwndList, WORD ch) { int i = 0; PNHMenuWindow data; int curIndex, topIndex, pageSize; boolean is_accelerator = FALSE; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( ch ) { case MENU_FIRST_PAGE: i = 0; ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_LAST_PAGE: i = max(0, data->menu.size-1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_NEXT_PAGE: topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus down one page */ i = min(curIndex+pageSize, data->menu.size-1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos down one page */ i = min(topIndex+(2*pageSize - 1), data->menu.size-1); ListView_EnsureVisible(hwndList, i, FALSE); return -2; case MENU_PREVIOUS_PAGE: topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus up one page */ i = max(curIndex-pageSize, 0); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos up one page */ i = max(topIndex-pageSize, 0); ListView_EnsureVisible(hwndList, i, FALSE); break; case MENU_SELECT_ALL: if( data->how == PICK_ANY ) { reset_menu_count(hwndList, data); for(i=0; imenu.size; i++ ) { SelectMenuItem(hwndList, data, i, -1); } return -2; } break; case MENU_UNSELECT_ALL: if( data->how == PICK_ANY ) { reset_menu_count(hwndList, data); for(i=0; imenu.size; i++ ) { SelectMenuItem(hwndList, data, i, 0); } return -2; } break; case MENU_INVERT_ALL: if( data->how == PICK_ANY ) { reset_menu_count(hwndList, data); for(i=0; imenu.size; i++ ) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); } return -2; } break; case MENU_SELECT_PAGE: if( data->how == PICK_ANY ) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); from = max(0, topIndex); to = min(data->menu.size, from+pageSize); for(i=from; ihow == PICK_ANY ) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); from = max(0, topIndex); to = min(data->menu.size, from+pageSize); for(i=from; ihow == PICK_ANY ) { int from, to; reset_menu_count(hwndList, data); topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); from = max(0, topIndex); to = min(data->menu.size, from+pageSize); for(i=from; imenu.items[i])? 0 : -1 ); } return -2; } break; case MENU_SEARCH: if( data->how==PICK_ANY || data->how==PICK_ONE ) { char buf[BUFSZ]; reset_menu_count(hwndList, data); if( mswin_getlin_window("Search for:", buf, BUFSZ)==IDCANCEL ) { strcpy(buf, "\033"); } SetFocus(hwndList); // set focus back to the list control if (!*buf || *buf == '\033') return -2; for(i=0; imenu.size; i++ ) { if( NHMENU_IS_SELECTABLE(data->menu.items[i]) && strstr(data->menu.items[i].str, buf) ) { if (data->how == PICK_ANY) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); } else if( data->how == PICK_ONE ) { SelectMenuItem( hwndList, data, i, -1 ); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); break; } } } } else { mswin_nhbell(); } return -2; case ' ': { if (GetNHApp()->regNetHackMode) { /* NetHack mode: Scroll down one page, ends menu when on last page. */ SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; GetScrollInfo(hwndList, SB_VERT, &si); if ((si.nPos + (int)si.nPage) > (si.nMax - si.nMin)) { /* We're at the bottom: dismiss. */ data->done = 1; data->result = 0; return -2; } /* We're not at the bottom: page down. */ topIndex = ListView_GetTopIndex( hwndList ); pageSize = ListView_GetCountPerPage( hwndList ); curIndex = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); /* Focus down one page */ i = min(curIndex+pageSize, data->menu.size-1); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); /* Scrollpos down one page */ i = min(topIndex+(2*pageSize - 1), data->menu.size-1); ListView_EnsureVisible(hwndList, i, FALSE); return -2; } else { /* Windows mode: ends menu for PICK_ONE/PICK_NONE select item for PICK_ANY */ if( data->how==PICK_ONE || data->how==PICK_NONE ) { data->done = 1; data->result = 0; return -2; } else if( data->how==PICK_ANY ) { i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if( i>=0 ) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); } } } } break; default: if( strchr(data->menu.gacc, ch) && !(ch=='0' && data->menu.counting) ) { /* matched a group accelerator */ if (data->how == PICK_ANY || data->how == PICK_ONE) { reset_menu_count(hwndList, data); for(i=0; imenu.size; i++ ) { if( NHMENU_IS_SELECTABLE(data->menu.items[i]) && data->menu.items[i].group_accel == ch ) { if( data->how == PICK_ANY ) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); } else if( data->how == PICK_ONE ) { SelectMenuItem( hwndList, data, i, -1 ); data->result = 0; data->done = 1; return -2; } } } return -2; } else { mswin_nhbell(); return -2; } } if (isdigit(ch)) { int count; i = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED); if( i>=0 ) { count = data->menu.items[i].count; if( count==-1 ) count=0; count *= 10L; count += (int)(ch - '0'); if (count != 0) /* ignore leading zeros */ { data->menu.counting = TRUE; data->menu.items[i].count = min(100000, count); ListView_RedrawItems( hwndList, i, i ); /* update count mark */ } } return -2; } is_accelerator = FALSE; for(i=0; imenu.size; i++) { if( data->menu.items[i].accelerator == ch ) { is_accelerator = TRUE; break; } } if( (ch>='a' && ch<='z') || (ch>='A' && ch<='Z') || is_accelerator) { if (data->how == PICK_ANY || data->how == PICK_ONE) { for(i=0; imenu.size; i++ ) { if( data->menu.items[i].accelerator == ch ) { if( data->how == PICK_ANY ) { SelectMenuItem( hwndList, data, i, NHMENU_IS_SELECTED(data->menu.items[i])? 0 : -1 ); ListView_SetItemState(hwndList, i, LVIS_FOCUSED, LVIS_FOCUSED); ListView_EnsureVisible(hwndList, i, FALSE); return -2; } else if( data->how == PICK_ONE ) { SelectMenuItem( hwndList, data, i, -1 ); data->result = 0; data->done = 1; return -2; } } } } } break; } reset_menu_count(hwndList, data); return -1; } /*-----------------------------------------------------------------------------*/ void mswin_menu_window_size (HWND hWnd, LPSIZE sz) { TEXTMETRIC tm; HWND control; HGDIOBJ saveFont; HDC hdc; PNHMenuWindow data; int i; RECT rt, wrt; int extra_cx; GetClientRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; GetWindowRect(hWnd, &wrt); extra_cx = (wrt.right-wrt.left) - sz->cx; data = (PNHMenuWindow)GetWindowLong(hWnd, GWL_USERDATA); if(data) { control = GetMenuControl(hWnd); hdc = GetDC(control); if( data->type==MENU_TYPE_MENU ) { /* Calculate the width of the list box. */ saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE)); GetTextMetrics(hdc, &tm); for(i=0; imenu.size; i++ ) { LONG menuitemwidth = 0; int column; char *p, *p1; p1 = data->menu.items[i].str; p = strchr(data->menu.items[i].str, '\t'); column = 0; for (;;) { TCHAR wbuf[BUFSZ]; RECT tabRect; SetRect ( &tabRect, 0, 0, 1, 1 ); if (p != NULL) *p = '\0'; /* for time being, view tab field as zstring */ DrawText(hdc, NH_A2W(p1, wbuf, BUFSZ), strlen(p1), &tabRect, DT_CALCRECT | DT_LEFT | DT_VCENTER | DT_SINGLELINE ); /* it probably isn't necessary to recompute the tab width now, but do so * just in case, honoring the previously computed value */ menuitemwidth += max(data->menu.tab_stop_size[column], tabRect.right - tabRect.left); if (p != NULL) *p = '\t'; else /* last string so, */ break; /* add the separation only when not the last item */ /* in the last item, we break out of the loop, in the statement just above */ menuitemwidth += TAB_SEPARATION; ++column; p1 = p + 1; p = strchr(p1, '\t'); } sz->cx = max(sz->cx, (LONG)(2*TILE_X + menuitemwidth + tm.tmAveCharWidth*12 + tm.tmOverhang)); } SelectObject(hdc, saveFont); } else { /* Calculate the width of the text box. */ RECT text_rt; saveFont = SelectObject(hdc, mswin_get_font(NHW_MENU, ATR_NONE, hdc, FALSE)); GetTextMetrics(hdc, &tm); SetRect(&text_rt, 0, 0, sz->cx, sz->cy); DrawText(hdc, data->text.text, _tcslen(data->text.text), &text_rt, DT_CALCRECT | DT_TOP | DT_LEFT | DT_NOPREFIX); sz->cx = max(sz->cx, text_rt.right - text_rt.left + 5*tm.tmAveCharWidth + tm.tmOverhang); SelectObject(hdc, saveFont); } sz->cx += extra_cx; ReleaseDC(control, hdc); } } /*-----------------------------------------------------------------------------*/ void SelectMenuItem(HWND hwndList, PNHMenuWindow data, int item, int count) { int i; if( item<0 || item>=data->menu.size ) return; if( data->how==PICK_ONE && count!=0 ) { for(i=0; imenu.size; i++) if( item!=i && data->menu.items[i].count!=0 ) { data->menu.items[i].count = 0; ListView_RedrawItems( hwndList, i, i ); }; } data->menu.items[item].count = count; ListView_RedrawItems( hwndList, item, item ); reset_menu_count(hwndList, data); } /*-----------------------------------------------------------------------------*/ void reset_menu_count(HWND hwndList, PNHMenuWindow data) { int i; data->menu.counting = FALSE; if( IsWindow(hwndList) ) { i = ListView_GetNextItem((hwndList), -1, LVNI_FOCUSED); if( i>=0 ) ListView_RedrawItems( hwndList, i, i ); } } /*-----------------------------------------------------------------------------*/ /* List window Proc */ LRESULT CALLBACK NHMenuListWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { BOOL bUpdateFocusItem; bUpdateFocusItem = FALSE; switch(message) { /* filter keyboard input for the control */ case WM_KEYDOWN: case WM_KEYUP: { MSG msg; BOOL processed; processed = FALSE; if( PeekMessage(&msg, hWnd, WM_CHAR, WM_CHAR, PM_REMOVE) ) { if( onListChar(GetParent(hWnd), hWnd, (char)msg.wParam)==-2 ) { processed = TRUE; } } if( processed ) return 0; if( wParam==VK_LEFT || wParam==VK_RIGHT ) bUpdateFocusItem = TRUE; } break; case WM_SIZE: case WM_HSCROLL: bUpdateFocusItem = TRUE; break; } if( bUpdateFocusItem ) { int i; RECT rt; /* invalidate the focus rectangle */ i = ListView_GetNextItem(hWnd, -1, LVNI_FOCUSED); if( i!=-1 ) { ListView_GetItemRect(hWnd, i, &rt, LVIR_BOUNDS); InvalidateRect(hWnd, &rt, TRUE); } } if( wndProcListViewOrig ) return CallWindowProc(wndProcListViewOrig, hWnd, message, wParam, lParam); else return 0; } /*-----------------------------------------------------------------------------*/ /* Text control window proc - implements scrolling without a cursor */ LRESULT CALLBACK NHMenuTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_KEYDOWN: switch (wParam) { /* close on space in Windows mode page down on space in NetHack mode */ case VK_SPACE: { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; GetScrollInfo(hWnd, SB_VERT, &si); /* If nethackmode and not at the end of the list */ if (GetNHApp()->regNetHackMode && (si.nPos + (int)si.nPage) <= (si.nMax - si.nMin)) SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); else PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0); return 0; } case VK_NEXT: SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); return 0; case VK_PRIOR: SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0); return 0; case VK_UP: SendMessage(hWnd, EM_SCROLL, SB_LINEUP, 0); return 0; case VK_DOWN: SendMessage(hWnd, EM_SCROLL, SB_LINEDOWN, 0); return 0; } break; } if( editControlWndProc ) return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam); else return 0; } /*-----------------------------------------------------------------------------*/ nethack-3.4.3/win/win32/mhmenu.h0100644000000000000000000000076607764735042015065 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMenuWindow_h #define MSWINMenuWindow_h #include "winMS.h" #include "config.h" #include "global.h" #define MENU_TYPE_TEXT 1 #define MENU_TYPE_MENU 2 HWND mswin_init_menu_window ( int type ); int mswin_menu_window_select_menu (HWND hwnd, int how, MENU_ITEM_P **); void mswin_menu_window_size (HWND hwnd, LPSIZE sz); #endif /* MSWINTextWindow_h */ nethack-3.4.3/win/win32/mhmsg.h0100644000000000000000000000264407764735042014704 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MHNethackMessages_H #define MHNethackMessages_H /* nethack messages */ #define WM_MSNH_COMMAND (WM_APP+1) #define MSNH_MSG_ADDWND 100 #define MSNH_MSG_PUTSTR 101 #define MSNH_MSG_PRINT_GLYPH 102 #define MSNH_MSG_CLEAR_WINDOW 103 #define MSNH_MSG_CLIPAROUND 104 #define MSNH_MSG_STARTMENU 105 #define MSNH_MSG_ADDMENU 106 #define MSNH_MSG_CURSOR 107 #define MSNH_MSG_ENDMENU 108 #define MSNH_MSG_DIED 109 #define MSNH_MSG_CARET 110 typedef struct mswin_nhmsg_add_wnd { winid wid; } MSNHMsgAddWnd, *PMSNHMsgAddWnd; typedef struct mswin_nhmsg_putstr { int attr; const char* text; boolean append; } MSNHMsgPutstr, *PMSNHMsgPutstr; typedef struct mswin_nhmsg_print_glyph { XCHAR_P x; XCHAR_P y; int glyph; } MSNHMsgPrintGlyph, *PMSNHMsgPrintGlyph; typedef struct mswin_nhmsg_cliparound { int x; int y; } MSNHMsgClipAround, *PMSNHMsgClipAround; typedef struct mswin_nhmsg_add_menu { int glyph; const ANY_P* identifier; CHAR_P accelerator; CHAR_P group_accel; int attr; const char * str; BOOLEAN_P presel; } MSNHMsgAddMenu, *PMSNHMsgAddMenu; typedef struct mswin_nhmsg_cursor { int x; int y; } MSNHMsgCursor, *PMSNHMsgCursor; typedef struct mswin_nhmsg_end_menu { const char* text; } MSNHMsgEndMenu, *PMSNHMsgEndMenu; #endif nethack-3.4.3/win/win32/mhmsgwnd.c0100644000000000000000000005371307764735042015413 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhmsgwnd.h" #include "mhmsg.h" #include "mhfont.h" #define MSG_WRAP_TEXT #define MSG_VISIBLE_LINES max(iflags.wc_vary_msgcount, 2) #define MAX_MSG_LINES 32 #define MSG_LINES (int)min(iflags.msg_history, MAX_MSG_LINES) #define MAXWINDOWTEXT TBUFSZ #define DEFAULT_COLOR_BG_MSG COLOR_WINDOW #define DEFAULT_COLOR_FG_MSG COLOR_WINDOWTEXT #define MORE "--More--" struct window_line { int attr; char text[MAXWINDOWTEXT]; }; typedef struct mswin_nethack_message_window { size_t max_text; struct window_line window_text[MAX_MSG_LINES]; #ifdef MSG_WRAP_TEXT int window_text_lines[MAX_MSG_LINES]; /* How much space this text line takes */ #endif int lines_last_turn; /* lines added during the last turn */ int cleared; /* clear was called */ int last_line; /* last line in the message history */ struct window_line new_line; int lines_not_seen; /* lines not yet seen by user after last turn or --More-- */ int in_more; /* We are in a --More-- prompt */ int nevermore; /* We want no more --More-- prompts */ int xChar; /* horizontal scrolling unit */ int yChar; /* vertical scrolling unit */ int xUpper; /* average width of uppercase letters */ int xPos; /* current horizontal scrolling position */ int yPos; /* current vertical scrolling position */ int xMax; /* maximum horizontal scrolling position */ int yMax; /* maximum vertical scrolling position */ int xPage; /* page size of horizontal scroll bar */ } NHMessageWindow, *PNHMessageWindow; static TCHAR szMessageWindowClass[] = TEXT("MSNHMessageWndClass"); LRESULT CALLBACK NHMessageWndProc(HWND, UINT, WPARAM, LPARAM); static void register_message_window_class(void); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); #ifndef MSG_WRAP_TEXT static void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam); #endif static COLORREF setMsgTextColor(HDC hdc, int gray); static void onPaint(HWND hWnd); static void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam); #ifdef USER_SOUNDS extern void play_sound_for_message(const char* str); #endif HWND mswin_init_message_window () { static int run_once = 0; HWND ret; DWORD style; if( !run_once ) { register_message_window_class( ); run_once = 1; } #ifdef MSG_WRAP_TEXT style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL; #else style = WS_CHILD | WS_CLIPSIBLINGS | WS_VSCROLL | WS_HSCROLL; #endif ret = CreateWindowEx( WS_EX_CLIENTEDGE, szMessageWindowClass, /* registered class name */ NULL, /* window name */ style, /* window style */ 0, /* horizontal position of window */ 0, /* vertical position of window */ 0, /* window width */ 0, /* window height - set it later */ GetNHApp()->hMainWnd, /* handle to parent or owner window */ NULL, /* menu handle or child identifier */ GetNHApp()->hApp, /* handle to application instance */ NULL ); /* window-creation data */ if( !ret ) panic("Cannot create message window"); return ret; } void register_message_window_class() { WNDCLASS wcex; ZeroMemory( &wcex, sizeof(wcex)); wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC)NHMessageWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = message_bg_brush ? message_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_MSG); wcex.lpszMenuName = NULL; wcex.lpszClassName = szMessageWindowClass; RegisterClass(&wcex); } LRESULT CALLBACK NHMessageWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: onCreate( hWnd, wParam, lParam ); break; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: onPaint(hWnd); break; case WM_SETFOCUS: SetFocus(GetNHApp()->hMainWnd); break; #ifndef MSG_WRAP_TEXT case WM_HSCROLL: onMSNH_HScroll(hWnd, wParam, lParam); break; #endif case WM_VSCROLL: onMSNH_VScroll(hWnd, wParam, lParam); break; case WM_DESTROY: { PNHMessageWindow data; data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); } break; case WM_SIZE: { SCROLLINFO si; int xNewSize; int yNewSize; PNHMessageWindow data; data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); xNewSize = LOWORD(lParam); yNewSize = HIWORD(lParam); if( xNewSize>0 || yNewSize>0 ) { #ifndef MSG_WRAP_TEXT data->xPage = xNewSize/data->xChar; data->xMax = max(0, (int)(1 + data->max_text - data->xPage)); data->xPos = min(data->xPos, data->xMax); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = 0; si.nMax = data->max_text; si.nPage = data->xPage; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); #endif data->yMax = MSG_LINES-1; data->yPos = min(data->yPos, data->yMax); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS; si.nMin = MSG_VISIBLE_LINES; si.nMax = data->yMax + MSG_VISIBLE_LINES - 1; si.nPage = MSG_VISIBLE_LINES; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); } } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( wParam ) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam; SCROLLINFO si; if( msg_data->append == 1) { /* Forcibly append to line, even if we pass the edge */ strncat(data->window_text[data->last_line].text, msg_data->text, MAXWINDOWTEXT - strlen(data->window_text[data->last_line].text)); } else if( msg_data->append < 0) { /* remove that many chars */ int len = strlen(data->window_text[data->last_line].text); int newend = max(len + msg_data->append, 0); data->window_text[data->last_line].text[newend] = '\0'; } else { /* Try to append but move the whole message to the next line if it doesn't fit */ /* just schedule for displaying */ data->new_line.attr = msg_data->attr; strncpy(data->new_line.text, msg_data->text, MAXWINDOWTEXT); } /* reset V-scroll position to display new text */ data->yPos = data->yMax; ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); /* update window content */ InvalidateRect(hWnd, NULL, TRUE); #ifdef USER_SOUNDS play_sound_for_message(msg_data->text); #endif } break; case MSNH_MSG_CLEAR_WINDOW: { data->cleared = 1; data->lines_not_seen = 0; /* do --More-- again if needed */ data->nevermore = 0; break; } case MSNH_MSG_CARET: /* Create or destroy a caret */ if (*(int *)lParam) CreateCaret(hWnd, NULL, 0, data->yChar); else { DestroyCaret(); /* this means we just did something interactive in this window, so we don't need a --More-- for the lines above. */ data->lines_not_seen = 0; } break; } } void onMSNH_VScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SCROLLINFO si; int yInc; /* get window data */ data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE | SIF_POS; GetScrollInfo(hWnd, SB_VERT, &si); switch(LOWORD (wParam)) { // User clicked the shaft above the scroll box. case SB_PAGEUP: yInc = -(int)si.nPage; break; // User clicked the shaft below the scroll box. case SB_PAGEDOWN: yInc = si.nPage; break; // User clicked the top arrow. case SB_LINEUP: yInc = -1; break; // User clicked the bottom arrow. case SB_LINEDOWN: yInc = 1; break; // User dragged the scroll box. case SB_THUMBTRACK: yInc = HIWORD(wParam) - data->yPos; break; default: yInc = 0; } // If applying the vertical scrolling increment does not // take the scrolling position out of the scrolling range, // increment the scrolling position, adjust the position // of the scroll box, and update the window. UpdateWindow // sends the WM_PAINT message. if (yInc = max( MSG_VISIBLE_LINES - data->yPos, min(yInc, data->yMax - data->yPos))) { data->yPos += yInc; /* ScrollWindowEx(hWnd, 0, -data->yChar * yInc, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); */ InvalidateRect(hWnd, NULL, TRUE); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->yPos; SetScrollInfo(hWnd, SB_VERT, &si, TRUE); UpdateWindow (hWnd); } } #ifndef MSG_WRAP_TEXT void onMSNH_HScroll(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SCROLLINFO si; int xInc; /* get window data */ data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_PAGE; GetScrollInfo(hWnd, SB_HORZ, &si); switch(LOWORD (wParam)) { // User clicked shaft left of the scroll box. case SB_PAGEUP: xInc = - (int)si.nPage; break; // User clicked shaft right of the scroll box. case SB_PAGEDOWN: xInc = si.nPage; break; // User clicked the left arrow. case SB_LINEUP: xInc = -1; break; // User clicked the right arrow. case SB_LINEDOWN: xInc = 1; break; // User dragged the scroll box. case SB_THUMBTRACK: xInc = HIWORD(wParam) - data->xPos; break; default: xInc = 0; } // If applying the horizontal scrolling increment does not // take the scrolling position out of the scrolling range, // increment the scrolling position, adjust the position // of the scroll box, and update the window. if (xInc = max (-data->xPos, min (xInc, data->xMax - data->xPos))) { data->xPos += xInc; ScrollWindowEx (hWnd, -data->xChar * xInc, 0, (CONST RECT *) NULL, (CONST RECT *) NULL, (HRGN) NULL, (LPRECT) NULL, SW_INVALIDATE | SW_ERASE); ZeroMemory(&si, sizeof(si)); si.cbSize = sizeof(si); si.fMask = SIF_POS; si.nPos = data->xPos; SetScrollInfo(hWnd, SB_HORZ, &si, TRUE); UpdateWindow (hWnd); } } #endif // MSG_WRAP_TEXT COLORREF setMsgTextColor(HDC hdc, int gray) { COLORREF fg, color1, color2; if (gray) { if (message_bg_brush) { color1 = message_bg_color; color2 = message_fg_color; } else { color1 = (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MSG); color2 = (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MSG); } /* Make a "gray" color by taking the average of the individual R,G,B components of two colors. Thanks to Jonathan del Strother */ fg = RGB((GetRValue(color1)+GetRValue(color2))/2, (GetGValue(color1)+GetGValue(color2))/2, (GetBValue(color1)+GetBValue(color2))/2); } else { fg = message_fg_brush ? message_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_MSG); } return SetTextColor(hdc, fg); } void onPaint(HWND hWnd) { PAINTSTRUCT ps; HDC hdc; PNHMessageWindow data; RECT client_rt, draw_rt; int FirstLine, LastLine; int i, x, y; HGDIOBJ oldFont; TCHAR wbuf[MAXWINDOWTEXT+2]; size_t wlen; COLORREF OldBg, OldFg; int do_more = 0; hdc = BeginPaint(hWnd, &ps); OldBg = SetBkColor(hdc, message_bg_brush ? message_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_MSG)); OldFg = setMsgTextColor(hdc, 0); data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); GetClientRect(hWnd, &client_rt); if( !IsRectEmpty(&ps.rcPaint) ) { FirstLine = max (0, data->yPos - (client_rt.bottom - ps.rcPaint.top)/data->yChar + 1); LastLine = min (MSG_LINES-1, data->yPos - (client_rt.bottom - ps.rcPaint.bottom)/data->yChar); y = min( ps.rcPaint.bottom, client_rt.bottom ); for (i=LastLine; i>=FirstLine; i--) { int lineidx = (data->last_line + 1 + i) % MSG_LINES; x = data->xChar * (2 - data->xPos); draw_rt.left = x; draw_rt.right = client_rt.right; draw_rt.top = y - data->yChar; draw_rt.bottom = y; oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[lineidx].attr, hdc, FALSE)); /* find out if we can concatenate the scheduled message without wrapping, but only if no clear_nhwindow was done just before putstr'ing this one, and only if not in a more prompt already (to prevent concatenating to a line containing --More-- when resizing while --More-- is displayed.) */ if (i == MSG_LINES-1 && strlen(data->new_line.text) > 0 && !data->in_more) { /* concatenate to the previous line if that is not empty, and if it has the same attribute, and no clear was done. */ if (strlen(data->window_text[lineidx].text) > 0 && (data->window_text[lineidx].attr == data->new_line.attr) && !data->cleared) { RECT tmpdraw_rt = draw_rt; /* assume this will never work when textsize is near MAXWINDOWTEXT */ char tmptext[MAXWINDOWTEXT]; TCHAR tmpwbuf[MAXWINDOWTEXT+2]; strcpy(tmptext, data->window_text[lineidx].text); strncat(tmptext, " ", MAXWINDOWTEXT - strlen(tmptext)); strncat(tmptext, data->new_line.text, MAXWINDOWTEXT - strlen(tmptext)); /* Always keep room for a --More-- */ strncat(tmptext, MORE, MAXWINDOWTEXT - strlen(tmptext)); NH_A2W(tmptext, tmpwbuf, sizeof(tmpwbuf)); /* Find out how large the bounding rectangle of the text is */ DrawText(hdc, tmpwbuf, _tcslen(tmpwbuf), &tmpdraw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); if ((tmpdraw_rt.bottom - tmpdraw_rt.top) == (draw_rt.bottom - draw_rt.top) /* fits pixelwise */ && (strlen(data->window_text[lineidx].text) + strlen(data->new_line.text) < MAXWINDOWTEXT)) /* fits charwise */ { /* strip off --More-- of this combined line and make it so */ tmptext[strlen(tmptext) - strlen(MORE)] = '\0'; strcpy(data->window_text[lineidx].text, tmptext); data->new_line.text[0] = '\0'; i++; /* Start from the last line again */ continue; } } if (strlen(data->new_line.text) > 0) { /* if we get here, the new line was not concatenated. Add it on a new line, but first check whether we should --More--. */ RECT tmpdraw_rt = draw_rt; TCHAR tmpwbuf[MAXWINDOWTEXT+2]; HGDIOBJ oldFont; int new_screen_lines; int screen_lines_not_seen = 0; /* Count how many screen lines we haven't seen yet. */ #ifdef MSG_WRAP_TEXT { int n; for (n = data->lines_not_seen - 1; n >= 0; n--) { screen_lines_not_seen += data->window_text_lines[(data->last_line - n + MSG_LINES) % MSG_LINES]; } } #else screen_lines_not_seen = data->lines_not_seen; #endif /* Now find out how many screen lines we would like to add */ NH_A2W(data->new_line.text, tmpwbuf, sizeof(tmpwbuf)); /* Find out how large the bounding rectangle of the text is */ oldFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, data->window_text[lineidx].attr, hdc, FALSE)); DrawText(hdc, tmpwbuf, _tcslen(tmpwbuf), &tmpdraw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); SelectObject(hdc, oldFont); new_screen_lines = (tmpdraw_rt.bottom - tmpdraw_rt.top) / data->yChar; /* If this together is more than fits on the window, we must --More--, unless: - We are in --More-- already (the user is scrolling the window) - The user pressed ESC */ if (screen_lines_not_seen + new_screen_lines > MSG_VISIBLE_LINES && !data->in_more && !data->nevermore) { data->in_more = 1; /* Show --More-- on last line */ strcat(data->window_text[data->last_line].text, MORE); /* Go on drawing, but remember we must do a more afterwards */ do_more = 1; } else if (!data->in_more) { data->last_line++; data->last_line %= MSG_LINES; data->window_text[data->last_line].attr = data->new_line.attr; strncpy(data->window_text[data->last_line].text, data->new_line.text, MAXWINDOWTEXT); data->new_line.text[0] = '\0'; if (data->cleared) { /* now we are drawing a new line, the old lines can be redrawn in grey.*/ data->lines_last_turn = 0; data->cleared = 0; } data->lines_last_turn++; data->lines_not_seen++; /* and start over */ i++; /* Start from the last line again */ continue; } } } /* convert to UNICODE */ NH_A2W(data->window_text[lineidx].text, wbuf, sizeof(wbuf)); wlen = _tcslen(wbuf); setMsgTextColor(hdc, i < (MSG_LINES - data->lines_last_turn)); #ifdef MSG_WRAP_TEXT /* Find out how large the bounding rectangle of the text is */ DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK | DT_CALCRECT); /* move that rectangle up, so that the bottom remains at the same height */ draw_rt.top = y - (draw_rt.bottom - draw_rt.top); draw_rt.bottom = y; /* Remember the height of this line for subsequent --More--'s */ data->window_text_lines[lineidx] = (draw_rt.bottom - draw_rt.top) / data->yChar; /* Now really draw it */ DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX | DT_WORDBREAK); /* Find out the cursor (caret) position */ if (i == MSG_LINES-1) { int nnum, numfit; SIZE size; TCHAR *nbuf; int nlen; nbuf = wbuf; nlen = wlen; while (nlen) { /* Get the number of characters that fit on the line */ GetTextExtentExPoint(hdc, nbuf, nlen, draw_rt.right - draw_rt.left, &numfit, NULL, &size); /* Search back to a space */ nnum = numfit; if (numfit < nlen) { while (nnum > 0 && nbuf[nnum] != ' ') nnum--; /* If no space found, break wherever */ if (nnum == 0) nnum = numfit; } nbuf += nnum; nlen -= nnum; if (*nbuf == ' ') { nbuf++; nlen--; } } /* The last size is the size of the last line. Set the caret there. This will fail automatically if we don't own the caret (i.e., when not in a question.) */ SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar); } #else DrawText(hdc, wbuf, wlen, &draw_rt, DT_NOPREFIX ); SetCaretPos(draw_rt.left + size.cx, draw_rt.bottom - data->yChar); #endif SelectObject(hdc, oldFont); y -= draw_rt.bottom - draw_rt.top; } if (do_more) { int okkey = 0; int chop; // @@@ Ok respnses while (!okkey) { char c = mswin_nhgetch(); switch (c) { /* space or enter */ case ' ': case '\015': okkey = 1; break; /* ESC */ case '\033': data->nevermore = 1; okkey = 1; break; default: break; } } chop = strlen(data->window_text[data->last_line].text) - strlen(MORE); data->window_text[data->last_line].text[chop] = '\0'; data->in_more = 0; data->lines_not_seen = 0; /* We did the --More--, reset the lines_not_seen; now draw that new line. This is the easiest method */ InvalidateRect(hWnd, NULL, TRUE); } } SetTextColor (hdc, OldFg); SetBkColor (hdc, OldBg); EndPaint(hWnd, &ps); } void onCreate(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHMessageWindow data; SIZE dummy; /* set window data */ data = (PNHMessageWindow)malloc(sizeof(NHMessageWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHMessageWindow)); data->max_text = MAXWINDOWTEXT; SetWindowLong(hWnd, GWL_USERDATA, (LONG)data); /* re-calculate window size (+ font size) */ mswin_message_window_size(hWnd, &dummy); } void mswin_message_window_size (HWND hWnd, LPSIZE sz) { HDC hdc; HGDIOBJ saveFont; TEXTMETRIC tm; PNHMessageWindow data; RECT rt, client_rt; data = (PNHMessageWindow)GetWindowLong(hWnd, GWL_USERDATA); if( !data ) return; /* -- Calculate the font size -- */ /* Get the handle to the client area's device context. */ hdc = GetDC(hWnd); saveFont = SelectObject(hdc, mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, FALSE)); /* Extract font dimensions from the text metrics. */ GetTextMetrics (hdc, &tm); data->xChar = tm.tmAveCharWidth; data->xUpper = (tm.tmPitchAndFamily & 1 ? 3 : 2) * data->xChar/2; data->yChar = tm.tmHeight + tm.tmExternalLeading; data->xPage = 1; /* Free the device context. */ SelectObject(hdc, saveFont); ReleaseDC (hWnd, hdc); /* -- calculate window size -- */ GetWindowRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; /* set size to accomodate MSG_VISIBLE_LINES and horizontal scroll bar (difference between window rect and client rect */ GetClientRect(hWnd, &client_rt); sz->cy = sz->cy - (client_rt.bottom - client_rt.top) + data->yChar * MSG_VISIBLE_LINES; } nethack-3.4.3/win/win32/mhmsgwnd.h0100644000000000000000000000057507764735042015416 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINMessageWindow_h #define MSWINMessageWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_message_window (void); void mswin_message_window_size (HWND hWnd, LPSIZE sz); #endif /* MSWINMessageWindow_h */ nethack-3.4.3/win/win32/mhrip.c0100644000000000000000000001626607764735042014710 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "resource.h" #include "mhrip.h" #include "mhmsg.h" #include "mhfont.h" #define RIP_WIDTH 400 #define RIP_HEIGHT 200 #define RIP_GRAVE_HEIGHT 120 #define RIP_GRAVE_WIDTH 115 #define RIP_GRAVE_X 90 #define RIP_GRAVE_Y 60 #define RIP_OFFSET_X 10 #define RIP_OFFSET_Y 10 PNHWinApp GetNHApp(void); typedef struct mswin_nethack_text_window { HANDLE rip_bmp; TCHAR* window_text; TCHAR* rip_text; } NHRIPWindow, *PNHRIPWindow; BOOL CALLBACK NHRIPWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); HWND mswin_init_RIP_window () { HWND ret; PNHRIPWindow data; ret = CreateDialog( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_NHRIP), GetNHApp()->hMainWnd, NHRIPWndProc ); if( !ret ) panic("Cannot create rip window"); data = (PNHRIPWindow)malloc(sizeof(NHRIPWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHRIPWindow)); SetWindowLong(ret, GWL_USERDATA, (LONG)data); return ret; } void mswin_display_RIP_window (HWND hWnd) { MSG msg; RECT rt; PNHRIPWindow data; HWND mapWnd; RECT riprt; RECT clientrect; RECT textrect; HDC hdc; HFONT OldFont; data = (PNHRIPWindow)GetWindowLong(hWnd, GWL_USERDATA); GetNHApp()->hPopupWnd = hWnd; mapWnd = mswin_hwnd_from_winid(WIN_MAP); if( !IsWindow(mapWnd) ) mapWnd = GetNHApp()->hMainWnd; GetWindowRect(mapWnd, &rt); GetWindowRect(hWnd, &riprt); GetClientRect (hWnd, &clientrect); textrect = clientrect; textrect.top += RIP_OFFSET_Y; textrect.left += RIP_OFFSET_X; textrect.right -= RIP_OFFSET_X; if (data->window_text) { hdc = GetDC (hWnd); OldFont = SelectObject (hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE)); DrawText (hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); SelectObject (hdc, OldFont); ReleaseDC(hWnd, hdc); } if (textrect.right - textrect.left > RIP_WIDTH) clientrect.right = textrect.right + RIP_OFFSET_X - clientrect.right; else clientrect.right = textrect.left + 2 * RIP_OFFSET_X + RIP_WIDTH - clientrect.right; clientrect.bottom = textrect.bottom + RIP_HEIGHT + RIP_OFFSET_Y - clientrect.bottom; GetWindowRect (GetDlgItem(hWnd, IDOK), &textrect); textrect.right -= textrect.left; textrect.bottom -= textrect.top; clientrect.bottom += textrect.bottom + RIP_OFFSET_Y; riprt.right -= riprt.left; riprt.bottom -= riprt.top; riprt.right += clientrect.right; riprt.bottom += clientrect.bottom; rt.left += (rt.right - rt.left - riprt.right) / 2; rt.top += (rt.bottom - rt.top - riprt.bottom) / 2; MoveWindow(hWnd, rt.left, rt.top, riprt.right, riprt.bottom, TRUE); GetClientRect (hWnd, &clientrect); MoveWindow (GetDlgItem(hWnd, IDOK), (clientrect.right - clientrect.left - textrect.right) / 2, clientrect.bottom - textrect.bottom - RIP_OFFSET_Y, textrect.right, textrect.bottom, TRUE); ShowWindow(hWnd, SW_SHOW); while( IsWindow(hWnd) && GetMessage(&msg, NULL, 0, 0)!=0 ) { if( !IsDialogMessage(hWnd, &msg) ) { TranslateMessage(&msg); DispatchMessage(&msg); } } GetNHApp()->hPopupWnd = NULL; } BOOL CALLBACK NHRIPWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; PNHRIPWindow data; data = (PNHRIPWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_INITDIALOG: /* set text control font */ hdc = GetDC(hWnd); SendMessage(hWnd, WM_SETFONT, (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0); ReleaseDC(hWnd, hdc); SetFocus(GetDlgItem(hWnd, IDOK)); return FALSE; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_PAINT: { int bitmap_offset; RECT clientrect; RECT textrect; HDC hdcBitmap; HANDLE OldBitmap; PAINTSTRUCT ps; HFONT OldFont; hdc = BeginPaint (hWnd, &ps); OldFont = SelectObject (hdc, mswin_get_font(NHW_TEXT, 0, hdc, FALSE)); hdcBitmap = CreateCompatibleDC(hdc); SetBkMode (hdc, TRANSPARENT); GetClientRect (hWnd, &clientrect); textrect = clientrect; textrect.top += RIP_OFFSET_Y; textrect.left += RIP_OFFSET_X; textrect.right -= RIP_OFFSET_X; if (data->window_text) { DrawText (hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); DrawText (hdc, data->window_text, strlen(data->window_text), &textrect, DT_LEFT | DT_NOPREFIX); } OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpRip); SetBkMode (hdc, OPAQUE); bitmap_offset = (textrect.right - textrect.left - RIP_WIDTH) / 2; BitBlt (hdc, textrect.left + bitmap_offset, textrect.bottom, RIP_WIDTH, RIP_HEIGHT, hdcBitmap, 0, 0, SRCCOPY); SetBkMode (hdc, TRANSPARENT); if (data->rip_text) { textrect.left += RIP_GRAVE_X + bitmap_offset; textrect.top = textrect.bottom + RIP_GRAVE_Y; textrect.right = textrect.left + RIP_GRAVE_WIDTH; textrect.bottom = textrect.top + RIP_GRAVE_HEIGHT; DrawText (hdc, data->rip_text, strlen(data->rip_text), &textrect, DT_CENTER | DT_VCENTER | DT_NOPREFIX | DT_WORDBREAK); } SelectObject (hdcBitmap, OldBitmap); SelectObject (hdc, OldFont); DeleteDC (hdcBitmap); EndPaint (hWnd, &ps); } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); if( GetNHApp()->hMainWnd==hWnd ) GetNHApp()->hMainWnd=NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); return TRUE; } break; case WM_CLOSE: /* if we get this here, we saved the bones so we can just force a quit */ mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); if( GetNHApp()->hMainWnd==hWnd ) GetNHApp()->hMainWnd=NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); program_state.stopprint++; return TRUE; case WM_DESTROY: if( data ) { if( data->window_text ) free(data->window_text); if( data->rip_text ) free(data->rip_text); if (data->rip_bmp != NULL) DeleteObject(data->rip_bmp); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); } break; } return FALSE; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHRIPWindow data; static int InRipText = 1; data = (PNHRIPWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( wParam ) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam; TCHAR wbuf[BUFSZ]; size_t text_size; if( !data->window_text ) { text_size = strlen(msg_data->text) + 4; data->window_text = (TCHAR*)malloc(text_size*sizeof(data->window_text[0])); ZeroMemory(data->window_text, text_size*sizeof(data->window_text[0])); } else { text_size = _tcslen(data->window_text) + strlen(msg_data->text) + 4; data->window_text = (TCHAR*)realloc(data->window_text, text_size*sizeof(data->window_text[0])); } if( !data->window_text ) break; _tcscat(data->window_text, NH_A2W(msg_data->text, wbuf, BUFSZ)); _tcscat(data->window_text, TEXT("\r\n")); break; } case MSNH_MSG_DIED: { data->rip_text = data->window_text; data->window_text = NULL; break; } } } void mswin_finish_rip_text(winid wid) { SendMessage (mswin_hwnd_from_winid(wid), WM_MSNH_COMMAND, MSNH_MSG_DIED, 0); } nethack-3.4.3/win/win32/mhrip.h0100644000000000000000000000060707764735042014705 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINRIPWindow_h #define MSWINRIPWindow_h #include "winMS.h" #include "config.h" #include "global.h" void mswin_finish_rip_text(winid wid); HWND mswin_init_RIP_window (void); void mswin_display_RIP_window (HWND hwnd); #endif /* MSWINRIPWindow_h */ nethack-3.4.3/win/win32/mhsplash.c0100644000000000000000000001463307764735042015404 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "resource.h" #include "mhsplash.h" #include "mhmsg.h" #include "mhfont.h" #include "patchlevel.h" #include "dlb.h" #define LLEN 128 PNHWinApp GetNHApp(void); BOOL CALLBACK NHSplashWndProc(HWND, UINT, WPARAM, LPARAM); #define SPLASH_WIDTH 440 #define SPLASH_HEIGHT 322 #define SPLASH_VERSION_X 290 #define SPLASH_VERSION_Y 10 #define SPLASH_OFFSET_X 10 #define SPLASH_OFFSET_Y 10 extern HFONT version_splash_font; void mswin_display_splash_window (BOOL show_ver) { MSG msg; HWND mapWnd; int left, top; RECT splashrt; RECT clientrt; RECT controlrt; HWND hWnd; int buttop; int strsize = 0; int bufsize = BUFSZ; char *buf = malloc(bufsize); if (buf == NULL) panic("out of memory"); buf[0] = '\0'; hWnd = CreateDialog(GetNHApp()->hApp, MAKEINTRESOURCE(IDD_SPLASH), GetNHApp()->hMainWnd, NHSplashWndProc); if( !hWnd ) panic("Cannot create Splash window"); mswin_init_splashfonts(hWnd); GetNHApp()->hPopupWnd = hWnd; mapWnd = mswin_hwnd_from_winid(WIN_MAP); if( !IsWindow(mapWnd) ) mapWnd = GetNHApp()->hMainWnd; /* Get control size */ GetWindowRect (GetDlgItem(hWnd, IDOK), &controlrt); controlrt.right -= controlrt.left; controlrt.bottom -= controlrt.top; /* Get current client area */ GetClientRect (hWnd, &clientrt); /* Get window size */ GetWindowRect(hWnd, &splashrt); splashrt.right -= splashrt.left; splashrt.bottom -= splashrt.top; /* Get difference between requested client area and current value */ splashrt.right += SPLASH_WIDTH + SPLASH_OFFSET_X * 2 - clientrt.right; splashrt.bottom += SPLASH_HEIGHT + controlrt.bottom + SPLASH_OFFSET_Y * 3 - clientrt.bottom; /* Place the window centered */ /* On the screen, not on the parent window */ left = (GetSystemMetrics(SM_CXSCREEN) - splashrt.right) / 2; top = (GetSystemMetrics(SM_CYSCREEN) - splashrt.bottom) / 2; MoveWindow(hWnd, left, top, splashrt.right, splashrt.bottom, TRUE); /* Place the OK control */ GetClientRect (hWnd, &clientrt); MoveWindow (GetDlgItem(hWnd, IDOK), (clientrt.right - clientrt.left - controlrt.right) / 2, clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y, controlrt.right, controlrt.bottom, TRUE); buttop = clientrt.bottom - controlrt.bottom - SPLASH_OFFSET_Y; /* Place the text control */ GetWindowRect (GetDlgItem(hWnd, IDC_EXTRAINFO), &controlrt); controlrt.right -= controlrt.left; controlrt.bottom -= controlrt.top; GetClientRect (hWnd, &clientrt); MoveWindow (GetDlgItem(hWnd, IDC_EXTRAINFO), clientrt.left + SPLASH_OFFSET_X, buttop - controlrt.bottom - SPLASH_OFFSET_Y, clientrt.right - 2 * SPLASH_OFFSET_X, controlrt.bottom, TRUE); /* Fill the text control */ Sprintf(buf, "%s\r\n%s\r\n%s\r\n\r\n", COPYRIGHT_BANNER_A, COPYRIGHT_BANNER_B, COPYRIGHT_BANNER_C); strsize = strlen(buf); if (show_ver) { /* Show complete version information */ dlb *f; getversionstring(buf + strsize); strcat(buf, "\r\n\r\n"); strsize = strlen(buf); /* Add compile options */ f = dlb_fopen(OPTIONS_USED, RDTMODE); if (f) { char line[LLEN + 1]; while (dlb_fgets(line, LLEN, f)) { size_t len; len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\r'; line[len] = '\n'; line[len + 1] = '\0'; len++; } if (strsize + (int)len + 1 > bufsize) { bufsize += BUFSZ; buf = realloc(buf, bufsize); if (buf == NULL) panic("out of memory"); } strcat(buf, line); strsize += len; } (void) dlb_fclose(f); } } else { /* Show news, if any */ if (iflags.news) { FILE *nf; iflags.news = 0; /* prevent newgame() from re-displaying news */ nf = fopen(NEWS, "r"); if (nf != NULL) { char line[LLEN + 1]; while (fgets(line, LLEN, nf)) { size_t len; len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\r'; line[len] = '\n'; line[len + 1] = '\0'; len++; } if (strsize + (int)len + 1 > bufsize) { bufsize += BUFSZ; buf = realloc(buf, bufsize); if (buf == NULL) panic("out of memory"); } strcat(buf, line); strsize += len; } (void) fclose(nf); } else { strcat(buf, "No news."); } } } SetWindowText(GetDlgItem(hWnd, IDC_EXTRAINFO), buf); free(buf); ShowWindow(hWnd, SW_SHOW); while( IsWindow(hWnd) && GetMessage(&msg, NULL, 0, 0)!=0 ) { if( !IsDialogMessage(hWnd, &msg) ) { TranslateMessage(&msg); DispatchMessage(&msg); } } GetNHApp()->hPopupWnd = NULL; mswin_destroy_splashfonts(); } BOOL CALLBACK NHSplashWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; switch (message) { case WM_INITDIALOG: /* set text control font */ hdc = GetDC(hWnd); SendMessage(hWnd, WM_SETFONT, (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0); ReleaseDC(hWnd, hdc); SetFocus(GetDlgItem(hWnd, IDOK)); return FALSE; case WM_PAINT: { char VersionString[BUFSZ]; RECT rt; HDC hdcBitmap; HANDLE OldBitmap; HANDLE OldFont; PAINTSTRUCT ps; hdc = BeginPaint (hWnd, &ps); /* Show splash graphic */ hdcBitmap = CreateCompatibleDC(hdc); SetBkMode (hdc, OPAQUE); OldBitmap = SelectObject(hdcBitmap, GetNHApp()->bmpSplash); nhapply_image_transparent(hdc, SPLASH_OFFSET_X, SPLASH_OFFSET_Y, SPLASH_WIDTH, SPLASH_HEIGHT, hdcBitmap, 0, 0, SPLASH_WIDTH, SPLASH_HEIGHT, TILE_BK_COLOR); SelectObject (hdcBitmap, OldBitmap); DeleteDC (hdcBitmap); SetBkMode (hdc, TRANSPARENT); /* Print version number */ SetTextColor (hdc, RGB(0, 0, 0)); rt.right = rt.left = SPLASH_VERSION_X; rt.bottom = rt.top = SPLASH_VERSION_Y; Sprintf (VersionString, "%d.%d.%d", VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL); OldFont = SelectObject(hdc, version_splash_font); DrawText (hdc, VersionString, strlen(VersionString), &rt, DT_LEFT | DT_NOPREFIX | DT_CALCRECT); DrawText (hdc, VersionString, strlen(VersionString), &rt, DT_LEFT | DT_NOPREFIX); EndPaint (hWnd, &ps); } break; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); if( GetNHApp()->hMainWnd==hWnd ) GetNHApp()->hMainWnd=NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); return TRUE; } break; } return FALSE; } nethack-3.4.3/win/win32/mhsplash.h0100644000000000000000000000045607764735042015407 0ustar rootroot/* Copyright (C) 2002 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINSplashWindow_h #define MSWINSplashWindow_h #include "winMS.h" #include "config.h" #include "global.h" void mswin_display_splash_window (BOOL); #endif /* MSWINSplashWindow_h */ nethack-3.4.3/win/win32/mhstatus.c0100644000000000000000000001063507764735042015433 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "mhstatus.h" #include "mhmsg.h" #include "mhfont.h" #define NHSW_LINES 2 #define MAXWINDOWTEXT BUFSZ typedef struct mswin_nethack_status_window { int index; char window_text[NHSW_LINES][MAXWINDOWTEXT+1]; } NHStatusWindow, *PNHStatusWindow; static TCHAR szStatusWindowClass[] = TEXT("MSNHStatusWndClass"); LRESULT CALLBACK StatusWndProc(HWND, UINT, WPARAM, LPARAM); static void register_status_window_class(void); #define DEFAULT_COLOR_BG_STATUS COLOR_WINDOW #define DEFAULT_COLOR_FG_STATUS COLOR_WINDOWTEXT HWND mswin_init_status_window () { static int run_once = 0; HWND ret; NHStatusWindow* data; if( !run_once ) { register_status_window_class( ); run_once = 1; } ret = CreateWindow( szStatusWindowClass, NULL, WS_CHILD | WS_DISABLED | WS_CLIPSIBLINGS, 0, /* x position */ 0, /* y position */ 0, /* x-size - we will set it later */ 0, /* y-size - we will set it later */ GetNHApp()->hMainWnd, NULL, GetNHApp()->hApp, NULL ); if( !ret ) panic("Cannot create status window"); EnableWindow(ret, FALSE); data = (PNHStatusWindow)malloc(sizeof(NHStatusWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHStatusWindow)); SetWindowLong(ret, GWL_USERDATA, (LONG)data); return ret; } void register_status_window_class() { WNDCLASS wcex; ZeroMemory( &wcex, sizeof(wcex)); wcex.style = CS_NOCLOSE; wcex.lpfnWndProc = (WNDPROC)StatusWndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = GetNHApp()->hApp; wcex.hIcon = NULL; wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = status_bg_brush ? status_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_STATUS); wcex.lpszMenuName = NULL; wcex.lpszClassName = szStatusWindowClass; RegisterClass(&wcex); } LRESULT CALLBACK StatusWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { RECT rt; PAINTSTRUCT ps; HDC hdc; PNHStatusWindow data; data = (PNHStatusWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_MSNH_COMMAND: { switch( wParam ) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam; strncpy(data->window_text[data->index], msg_data->text, MAXWINDOWTEXT); strncat(data->window_text[data->index], "\n", MAXWINDOWTEXT-strlen(data->window_text[data->index])); data->index = (data->index+1) % NHSW_LINES; InvalidateRect(hWnd, NULL, TRUE); break; } case MSNH_MSG_CLEAR_WINDOW: data->index = 0; ZeroMemory(data->window_text, sizeof(data->window_text)); InvalidateRect(hWnd, NULL, TRUE); break; } } break; case WM_PAINT: { int i; SIZE sz; HGDIOBJ oldFont; TCHAR wbuf[BUFSZ]; COLORREF OldBg, OldFg; hdc = BeginPaint(hWnd, &ps); GetClientRect(hWnd, &rt); oldFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); OldBg = SetBkColor(hdc, status_bg_brush ? status_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_STATUS)); OldFg = SetTextColor(hdc, status_fg_brush ? status_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_STATUS)); for(i=0; iwindow_text[i], wbuf, sizeof(wbuf)), strlen(data->window_text[i]), &sz); NH_A2W(data->window_text[i], wbuf, BUFSZ); DrawText(hdc, wbuf, strlen(data->window_text[i]), &rt, DT_LEFT | DT_END_ELLIPSIS); rt.top += sz.cy; } SelectObject(hdc, oldFont); SetTextColor (hdc, OldFg); SetBkColor (hdc, OldBg); EndPaint(hWnd, &ps); } break; case WM_DESTROY: free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); break; case WM_SETFOCUS: SetFocus(GetNHApp()->hMainWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } void mswin_status_window_size (HWND hWnd, LPSIZE sz) { TEXTMETRIC tm; HGDIOBJ saveFont; HDC hdc; PNHStatusWindow data; RECT rt; GetWindowRect(hWnd, &rt); sz->cx = rt.right - rt.left; sz->cy = rt.bottom - rt.top; data = (PNHStatusWindow)GetWindowLong(hWnd, GWL_USERDATA); if(data) { hdc = GetDC(hWnd); saveFont = SelectObject(hdc, mswin_get_font(NHW_STATUS, ATR_NONE, hdc, FALSE)); GetTextMetrics(hdc, &tm); sz->cy = tm.tmHeight * NHSW_LINES; SelectObject(hdc, saveFont); ReleaseDC(hWnd, hdc); } } nethack-3.4.3/win/win32/mhstatus.h0100644000000000000000000000056707764735042015443 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINStatusWindow_h #define MSWINStatusWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_status_window (void); void mswin_status_window_size (HWND hWnd, LPSIZE sz); #endif /* MSWINStatusWindow_h */ nethack-3.4.3/win/win32/mhtext.c0100644000000000000000000001526607764735042015101 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #include "winMS.h" #include "resource.h" #include "mhtext.h" #include "mhmsg.h" #include "mhfont.h" PNHWinApp GetNHApp(void); typedef struct mswin_nethack_text_window { TCHAR* window_text; } NHTextWindow, *PNHTextWindow; static WNDPROC editControlWndProc = 0; #define DEFAULT_COLOR_BG_TEXT COLOR_WINDOW #define DEFAULT_COLOR_FG_TEXT COLOR_WINDOWTEXT BOOL CALLBACK NHTextWndProc(HWND, UINT, WPARAM, LPARAM); LRESULT CALLBACK NHEditHookWndProc(HWND, UINT, WPARAM, LPARAM); static void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam); static void LayoutText(HWND hwnd); HWND mswin_init_text_window () { HWND ret; PNHTextWindow data; ret = CreateDialog( GetNHApp()->hApp, MAKEINTRESOURCE(IDD_NHTEXT), GetNHApp()->hMainWnd, NHTextWndProc ); if( !ret ) panic("Cannot create text window"); data = (PNHTextWindow)malloc(sizeof(NHTextWindow)); if( !data ) panic("out of memory"); ZeroMemory(data, sizeof(NHTextWindow)); SetWindowLong(ret, GWL_USERDATA, (LONG)data); return ret; } void mswin_display_text_window (HWND hWnd) { PNHTextWindow data; data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA); if( data && data->window_text ) { HWND control; control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); SendMessage(control, EM_FMTLINES, 1, 0 ); SetWindowText(GetDlgItem(hWnd, IDC_TEXT_CONTROL), data->window_text); } mswin_popup_display(hWnd, NULL); mswin_popup_destroy(hWnd); } BOOL CALLBACK NHTextWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HWND control; HDC hdc; PNHTextWindow data; TCHAR title[MAX_LOADSTRING]; data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA); switch (message) { case WM_INITDIALOG: /* set text control font */ control = GetDlgItem(hWnd, IDC_TEXT_CONTROL); if( !control ) { panic("cannot get text view window"); } hdc = GetDC(control); SendMessage(control, WM_SETFONT, (WPARAM)mswin_get_font(NHW_TEXT, ATR_NONE, hdc, FALSE), 0); ReleaseDC(control, hdc); /* subclass edit control */ editControlWndProc = (WNDPROC)GetWindowLong(control, GWL_WNDPROC); SetWindowLong(control, GWL_WNDPROC, (LONG)NHEditHookWndProc); SetFocus(control); /* Even though the dialog has no caption, you can still set the title which shows on Alt-Tab */ LoadString(GetNHApp()->hApp, IDS_APP_TITLE, title, MAX_LOADSTRING); SetWindowText(hWnd, title); return FALSE; case WM_MSNH_COMMAND: onMSNHCommand(hWnd, wParam, lParam); break; case WM_SIZE: LayoutText(hWnd); return FALSE; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: case IDCANCEL: mswin_window_mark_dead(mswin_winid_from_handle(hWnd)); if( GetNHApp()->hMainWnd==hWnd ) GetNHApp()->hMainWnd=NULL; DestroyWindow(hWnd); SetFocus(GetNHApp()->hMainWnd); return TRUE; case IDC_TEXT_CONTROL: switch (HIWORD(wParam)) { case EN_SETFOCUS: HideCaret((HWND)lParam); return TRUE; } } break; case WM_CTLCOLORSTATIC: { /* sent by edit control before it is drawn */ HDC hdcEdit = (HDC) wParam; HWND hwndEdit = (HWND) lParam; if( hwndEdit == GetDlgItem(hWnd, IDC_TEXT_CONTROL) ) { SetBkColor(hdcEdit, text_bg_brush ? text_bg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_BG_TEXT) ); SetTextColor(hdcEdit, text_fg_brush ? text_fg_color : (COLORREF)GetSysColor(DEFAULT_COLOR_FG_TEXT) ); return (BOOL)(text_bg_brush ? text_bg_brush : SYSCLR_TO_BRUSH(DEFAULT_COLOR_BG_TEXT)); } } return FALSE; case WM_DESTROY: if( data ) { if( data->window_text ) free(data->window_text); free(data); SetWindowLong(hWnd, GWL_USERDATA, (LONG)0); } break; } return FALSE; } void onMSNHCommand(HWND hWnd, WPARAM wParam, LPARAM lParam) { PNHTextWindow data; data = (PNHTextWindow)GetWindowLong(hWnd, GWL_USERDATA); switch( wParam ) { case MSNH_MSG_PUTSTR: { PMSNHMsgPutstr msg_data = (PMSNHMsgPutstr)lParam; TCHAR wbuf[BUFSZ]; size_t text_size; if( !data->window_text ) { text_size = strlen(msg_data->text) + 4; data->window_text = (TCHAR*)malloc(text_size*sizeof(data->window_text[0])); ZeroMemory(data->window_text, text_size*sizeof(data->window_text[0])); } else { text_size = _tcslen(data->window_text) + strlen(msg_data->text) + 4; data->window_text = (TCHAR*)realloc(data->window_text, text_size*sizeof(data->window_text[0])); } if( !data->window_text ) break; _tcscat(data->window_text, NH_A2W(msg_data->text, wbuf, BUFSZ)); _tcscat(data->window_text, TEXT("\r\n")); break; } } } void LayoutText(HWND hWnd) { HWND btn_ok; HWND text; RECT clrt, rt; POINT pt_elem, pt_ok; SIZE sz_elem, sz_ok; text = GetDlgItem(hWnd, IDC_TEXT_CONTROL); btn_ok = GetDlgItem(hWnd, IDOK); /* get window coordinates */ GetClientRect(hWnd, &clrt ); /* set window placements */ GetWindowRect(btn_ok, &rt); sz_ok.cx = clrt.right - clrt.left; sz_ok.cy = rt.bottom-rt.top; pt_ok.x = clrt.left; pt_ok.y = clrt.bottom - sz_ok.cy; pt_elem.x = clrt.left; pt_elem.y = clrt.top; sz_elem.cx = clrt.right - clrt.left; sz_elem.cy = pt_ok.y; MoveWindow(text, pt_elem.x, pt_elem.y, sz_elem.cx, sz_elem.cy, TRUE ); MoveWindow(btn_ok, pt_ok.x, pt_ok.y, sz_ok.cx, sz_ok.cy, TRUE ); } /* Edit box hook */ LRESULT CALLBACK NHEditHookWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_KEYDOWN: switch (wParam) { /* close on space in Windows mode page down on space in NetHack mode */ case VK_SPACE: { SCROLLINFO si; si.cbSize = sizeof(SCROLLINFO); si.fMask = SIF_POS | SIF_RANGE | SIF_PAGE; GetScrollInfo(hWnd, SB_VERT, &si); /* If nethackmode and not at the end of the list */ if (GetNHApp()->regNetHackMode && (si.nPos + (int)si.nPage) <= (si.nMax - si.nMin)) SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); else PostMessage(GetParent(hWnd), WM_COMMAND, MAKELONG(IDOK, 0), 0); return 0; } case VK_NEXT: SendMessage(hWnd, EM_SCROLL, SB_PAGEDOWN, 0); return 0; case VK_PRIOR: SendMessage(hWnd, EM_SCROLL, SB_PAGEUP, 0); return 0; case VK_UP: SendMessage(hWnd, EM_SCROLL, SB_LINEUP, 0); return 0; case VK_DOWN: SendMessage(hWnd, EM_SCROLL, SB_LINEDOWN, 0); return 0; } break; } if( editControlWndProc ) return CallWindowProc(editControlWndProc, hWnd, message, wParam, lParam); else return 0; } nethack-3.4.3/win/win32/mhtext.h0100644000000000000000000000054507764735042015100 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef MSWINTextWindow_h #define MSWINTextWindow_h #include "winMS.h" #include "config.h" #include "global.h" HWND mswin_init_text_window (void); void mswin_display_text_window (HWND hwnd); #endif /* MSWINTextWindow_h */ nethack-3.4.3/win/win32/mnsel.uu0100644000000000000000000000031007764735042015075 0ustar rootrootbegin 600 mnsel.bmp M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(` M`````````````````/___P```````````#_\```W_```,_P``"7\```F_``` D)WP``">\```_W```/^P``#_T```__```/_P````````````` ` end nethack-3.4.3/win/win32/mnselcnt.uu0100644000000000000000000000031307764735042015605 0ustar rootrootbegin 600 mnselcnt.bmp M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(` M`````````````````/___P```````````#_\```__```.]P``#`,```[W``` D.]P``#O<```[W```,`P``#O<```__```/_P````````````` ` end nethack-3.4.3/win/win32/mnunsel.uu0100644000000000000000000000031207764735042015442 0ustar rootrootbegin 600 mnunsel.bmp M0DU^`````````#X````H````$````!`````!``$``````$````!T$@``=!(` M`````````````````/___P```````````#_\```__```/_P``#_\```__``` D/_P``#_\```__```/_P``#_\```__```/_P````````````` ` end nethack-3.4.3/win/win32/mswproc.c0100644000000000000000000022056407764735042015261 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ /* * This file implements the interface between the window port specific * code in the mswin port and the rest of the nethack game engine. */ #include "hack.h" #include "dlb.h" #include "func_tab.h" /* for extended commands */ #include "winMS.h" #include "mhmap.h" #include "mhstatus.h" #include "mhtext.h" #include "mhmsgwnd.h" #include "mhmenu.h" #include "mhsplash.h" #include "mhmsg.h" #include "mhinput.h" #include "mhaskyn.h" #include "mhdlg.h" #include "mhrip.h" #include "mhmain.h" #include "mhfont.h" #include "resource.h" #define LLEN 128 extern const char *killed_by_prefix[]; #ifdef _DEBUG extern void logDebug(const char *fmt, ...); #else void logDebug(const char *fmt, ...) { } #endif static void mswin_main_loop(void); static BOOL initMapTiles(void); static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr); static void prompt_for_player_selection(void); #define TOTAL_BRUSHES 10 HBRUSH brush_table[TOTAL_BRUSHES]; int max_brush = 0; HBRUSH menu_bg_brush = NULL; HBRUSH menu_fg_brush = NULL; HBRUSH text_bg_brush = NULL; HBRUSH text_fg_brush = NULL; HBRUSH status_bg_brush = NULL; HBRUSH status_fg_brush = NULL; HBRUSH message_bg_brush = NULL; HBRUSH message_fg_brush = NULL; COLORREF menu_bg_color = RGB(0, 0, 0); COLORREF menu_fg_color = RGB(0xFF, 0xFF, 0xFF); COLORREF text_bg_color = RGB(0, 0, 0); COLORREF text_fg_color = RGB(0xFF, 0xFF, 0xFF); COLORREF status_bg_color = RGB(0, 0, 0); COLORREF status_fg_color = RGB(0xFF, 0xFF, 0xFF); COLORREF message_bg_color = RGB(0, 0, 0); COLORREF message_fg_color = RGB(0xFF, 0xFF, 0xFF); /* Interface definition, for windows.c */ struct window_procs mswin_procs = { "MSWIN", WC_COLOR|WC_HILITE_PET|WC_ALIGN_MESSAGE|WC_ALIGN_STATUS| WC_INVERSE|WC_SCROLL_AMOUNT|WC_SCROLL_MARGIN|WC_MAP_MODE| WC_FONT_MESSAGE|WC_FONT_STATUS|WC_FONT_MENU|WC_FONT_TEXT|WC_FONT_MAP| WC_FONTSIZ_MESSAGE|WC_FONTSIZ_STATUS|WC_FONTSIZ_MENU|WC_FONTSIZ_TEXT| WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE|WC_VARY_MSGCOUNT| WC_WINDOWCOLORS|WC_PLAYER_SELECTION|WC_SPLASH_SCREEN|WC_POPUP_DIALOG, 0L, mswin_init_nhwindows, mswin_player_selection, mswin_askname, mswin_get_nh_event, mswin_exit_nhwindows, mswin_suspend_nhwindows, mswin_resume_nhwindows, mswin_create_nhwindow, mswin_clear_nhwindow, mswin_display_nhwindow, mswin_destroy_nhwindow, mswin_curs, mswin_putstr, mswin_display_file, mswin_start_menu, mswin_add_menu, mswin_end_menu, mswin_select_menu, genl_message_menu, /* no need for X-specific handling */ mswin_update_inventory, mswin_mark_synch, mswin_wait_synch, #ifdef CLIPPING mswin_cliparound, #endif #ifdef POSITIONBAR donull, #endif mswin_print_glyph, mswin_raw_print, mswin_raw_print_bold, mswin_nhgetch, mswin_nh_poskey, mswin_nhbell, mswin_doprev_message, mswin_yn_function, mswin_getlin, mswin_get_ext_cmd, mswin_number_pad, mswin_delay_output, #ifdef CHANGE_COLOR /* only a Mac option currently */ mswin, mswin_change_background, #endif /* other defs that really should go away (they're tty specific) */ mswin_start_screen, mswin_end_screen, mswin_outrip, mswin_preference_update, }; /* init_nhwindows(int* argcp, char** argv) -- Initialize the windows used by NetHack. This can also create the standard windows listed at the top, but does not display them. -- Any commandline arguments relevant to the windowport should be interpreted, and *argcp and *argv should be changed to remove those arguments. -- When the message window is created, the variable iflags.window_inited needs to be set to TRUE. Otherwise all plines() will be done via raw_print(). ** Why not have init_nhwindows() create all of the "standard" ** windows? Or at least all but WIN_INFO? -dean */ void mswin_init_nhwindows(int* argc, char** argv) { logDebug("mswin_init_nhwindows()\n"); #ifdef _DEBUG { /* truncate trace file */ FILE *dfp = fopen("nhtrace.log", "w"); fclose(dfp); } #endif mswin_nh_input_init(); /* set it to WIN_ERR so we can detect attempts to use this ID before it is inialized */ WIN_MAP = WIN_ERR; /* Read Windows settings from the reqistry */ /* First set safe defaults */ GetNHApp()->regMainMinX = CW_USEDEFAULT; mswin_read_reg(); /* Create the main window */ GetNHApp()->hMainWnd = mswin_init_main_window(); if (!GetNHApp()->hMainWnd) { panic("Cannot create main window"); } /* Set menu check mark for interface mode */ mswin_menu_check_intf_mode(); /* check default values */ if( iflags.wc_fontsiz_statusNHFONT_SIZE_MAX ) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; if( iflags.wc_fontsiz_messageNHFONT_SIZE_MAX ) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; if( iflags.wc_fontsiz_textNHFONT_SIZE_MAX ) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; if( iflags.wc_fontsiz_menuNHFONT_SIZE_MAX ) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; if( iflags.wc_align_message==0 ) iflags.wc_align_message = ALIGN_TOP; if( iflags.wc_align_status==0 ) iflags.wc_align_status = ALIGN_BOTTOM; if( iflags.wc_scroll_margin==0 ) iflags.wc_scroll_margin = DEF_CLIPAROUND_MARGIN; if( iflags.wc_scroll_amount==0 ) iflags.wc_scroll_amount = DEF_CLIPAROUND_AMOUNT; if( iflags.wc_tile_width==0 ) iflags.wc_tile_width = TILE_X; if( iflags.wc_tile_height==0 ) iflags.wc_tile_height = TILE_Y; if( iflags.wc_vary_msgcount==0 ) iflags.wc_vary_msgcount = 4; /* force tabs in menus */ iflags.menu_tab_sep = 1; /* force toptenwin to be true. toptenwin is the option that decides whether to * write output to a window or stdout. stdout doesn't make sense on Windows * non-console applications */ flags.toptenwin = 1; set_option_mod_status("toptenwin", SET_IN_FILE); set_option_mod_status("perm_invent", SET_IN_FILE); /* initialize map tiles bitmap */ initMapTiles(); /* set tile-related options to readonly */ set_wc_option_mod_status( WC_TILE_WIDTH|WC_TILE_HEIGHT|WC_TILE_FILE, DISP_IN_GAME); /* set font-related options to change in the game */ set_wc_option_mod_status( WC_HILITE_PET | WC_ALIGN_MESSAGE | WC_ALIGN_STATUS | WC_SCROLL_AMOUNT | WC_SCROLL_MARGIN | WC_MAP_MODE | WC_FONT_MESSAGE | WC_FONT_STATUS | WC_FONT_MENU | WC_FONT_TEXT | WC_FONTSIZ_MESSAGE | WC_FONTSIZ_STATUS | WC_FONTSIZ_MENU | WC_FONTSIZ_TEXT | WC_VARY_MSGCOUNT, SET_IN_GAME ); mswin_color_from_string(iflags.wc_foregrnd_menu, &menu_fg_brush, &menu_fg_color); mswin_color_from_string(iflags.wc_foregrnd_message, &message_fg_brush, &message_fg_color); mswin_color_from_string(iflags.wc_foregrnd_status, &status_fg_brush, &status_fg_color); mswin_color_from_string(iflags.wc_foregrnd_text, &text_fg_brush, &text_fg_color); mswin_color_from_string(iflags.wc_backgrnd_menu, &menu_bg_brush, &menu_bg_color); mswin_color_from_string(iflags.wc_backgrnd_message, &message_bg_brush, &message_bg_color); mswin_color_from_string(iflags.wc_backgrnd_status, &status_bg_brush, &status_bg_color); mswin_color_from_string(iflags.wc_backgrnd_text, &text_bg_brush, &text_bg_color); if (iflags.wc_splash_screen) mswin_display_splash_window(FALSE); iflags.window_inited = TRUE; } /* Do a window-port specific player type selection. If player_selection() offers a Quit option, it is its responsibility to clean up and terminate the process. You need to fill in pl_character[0]. */ void mswin_player_selection(void) { int nRole; logDebug("mswin_player_selection()\n"); if (iflags.wc_player_selection == VIA_DIALOG) { /* pick player type randomly (use pre-selected role/race/gender/alignment) */ if( flags.randomall ) { if (flags.initrole < 0) { flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { raw_print("Incompatible role!"); flags.initrole = randrole(); } } if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { raw_print("Incompatible race!"); flags.initrace = randrace(flags.initrole); } } if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { raw_print("Incompatible gender!"); flags.initgend = randgend(flags.initrole, flags.initrace); } } if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { raw_print("Incompatible alignment!"); flags.initalign = randalign(flags.initrole, flags.initrace); } } } else { /* select a role */ if( mswin_player_selection_window( &nRole ) == IDCANCEL ) { bail(0); } } } else { /* iflags.wc_player_selection == VIA_PROMPTS */ prompt_for_player_selection(); } } void prompt_for_player_selection(void) { int i, k, n; char pick4u = 'n', thisch, lastch = 0; char pbuf[QBUFSZ], plbuf[QBUFSZ]; winid win; anything any; menu_item *selected = 0; DWORD box_result; logDebug("prompt_for_player_selection()\n"); /* prevent an unnecessary prompt */ rigid_role_checks(); /* Should we randomly pick for the player? */ if (!flags.randomall && (flags.initrole == ROLE_NONE || flags.initrace == ROLE_NONE || flags.initgend == ROLE_NONE || flags.initalign == ROLE_NONE)) { /* int echoline; */ char *prompt = build_plselection_prompt(pbuf, QBUFSZ, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* tty_putstr(BASE_WINDOW, 0, ""); */ /* echoline = wins[BASE_WINDOW]->cury; */ box_result = NHMessageBox(NULL, prompt, MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON1); pick4u = (box_result == IDYES) ? 'y' : (box_result == IDNO) ? 'n' : '\033'; /* tty_putstr(BASE_WINDOW, 0, prompt); */ do { /* pick4u = lowc(readchar()); */ if (index(quitchars, pick4u)) pick4u = 'y'; } while(!index(ynqchars, pick4u)); if ((int)strlen(prompt) + 1 < CO) { /* Echo choice and move back down line */ /* tty_putsym(BASE_WINDOW, (int)strlen(prompt)+1, echoline, pick4u); */ /* tty_putstr(BASE_WINDOW, 0, ""); */ } else /* Otherwise it's hard to tell where to echo, and things are * wrapping a bit messily anyway, so (try to) make sure the next * question shows up well and doesn't get wrapped at the * bottom of the window. */ /* tty_clear_nhwindow(BASE_WINDOW) */ ; if (pick4u != 'y' && pick4u != 'n') { give_up: /* Quit */ if (selected) free((genericptr_t) selected); bail((char *)0); /*NOTREACHED*/ return; } } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); /* Select a role, if necessary */ /* we'll try to be compatible with pre-selected race/gender/alignment, * but may not succeed */ if (flags.initrole < 0) { char rolenamebuf[QBUFSZ]; /* Process the choice */ if (pick4u == 'y' || flags.initrole == ROLE_RANDOM || flags.randomall) { /* Pick a random role */ flags.initrole = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrole < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible role!"); */ flags.initrole = randrole(); } } else { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Character's Role"); */ /* Prompt for a role */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; roles[i].name.m; i++) { if (ok_role(i, flags.initrace, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ thisch = lowc(roles[i].name.m[0]); if (thisch == lastch) thisch = highc(thisch); if (flags.initgend != ROLE_NONE && flags.initgend != ROLE_RANDOM) { if (flags.initgend == 1 && roles[i].name.f) Strcpy(rolenamebuf, roles[i].name.f); else Strcpy(rolenamebuf, roles[i].name.m); } else { if (roles[i].name.f) { Strcpy(rolenamebuf, roles[i].name.m); Strcat(rolenamebuf, "/"); Strcat(rolenamebuf, roles[i].name.f); } else Strcpy(rolenamebuf, roles[i].name.m); } add_menu(win, NO_GLYPH, &any, thisch, 0, ATR_NONE, an(rolenamebuf), MENU_UNSELECTED); lastch = thisch; } } any.a_int = pick_role(flags.initrace, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrole()+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick a role for your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); /* Process the choice */ if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ flags.initrole = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a race, if necessary */ /* force compatibility with role, try for compatibility with * pre-selected gender/alignment */ if (flags.initrace < 0 || !validrace(flags.initrole, flags.initrace)) { /* pre-selected race not valid */ if (pick4u == 'y' || flags.initrace == ROLE_RANDOM || flags.randomall) { flags.initrace = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM); if (flags.initrace < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible race!"); */ flags.initrace = randrace(flags.initrole); } } else { /* pick4u == 'n' */ /* Count the number of valid races */ n = 0; /* number valid */ k = 0; /* valid race */ for (i = 0; races[i].noun; i++) { if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; races[i].noun; i++) { if (validrace(flags.initrole, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Race"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; races[i].noun; i++) if (ok_race(flags.initrole, i, flags.initgend, flags.initalign)) { any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any, races[i].noun[0], 0, ATR_NONE, races[i].noun, MENU_UNSELECTED); } any.a_int = pick_race(flags.initrole, flags.initgend, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randrace(flags.initrole)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the race of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initrace = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select a gender, if necessary */ /* force compatibility with role/race, try for compatibility with * pre-selected alignment */ if (flags.initgend < 0 || !validgend(flags.initrole, flags.initrace, flags.initgend)) { /* pre-selected gender not valid */ if (pick4u == 'y' || flags.initgend == ROLE_RANDOM || flags.randomall) { flags.initgend = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM); if (flags.initgend < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible gender!"); */ flags.initgend = randgend(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid genders */ n = 0; /* number valid */ k = 0; /* valid gender */ for (i = 0; i < ROLE_GENDERS; i++) { if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_GENDERS; i++) { if (validgend(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Gender"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_GENDERS; i++) if (ok_gend(flags.initrole, flags.initrace, i, flags.initalign)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, genders[i].adj[0], 0, ATR_NONE, genders[i].adj, MENU_UNSELECTED); } any.a_int = pick_gend(flags.initrole, flags.initrace, flags.initalign, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randgend(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the gender of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initgend = k; } (void) root_plselection_prompt(plbuf, QBUFSZ - 1, flags.initrole, flags.initrace, flags.initgend, flags.initalign); } /* Select an alignment, if necessary */ /* force compatibility with role/race/gender */ if (flags.initalign < 0 || !validalign(flags.initrole, flags.initrace, flags.initalign)) { /* pre-selected alignment not valid */ if (pick4u == 'y' || flags.initalign == ROLE_RANDOM || flags.randomall) { flags.initalign = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM); if (flags.initalign < 0) { /* tty_putstr(BASE_WINDOW, 0, "Incompatible alignment!"); */ flags.initalign = randalign(flags.initrole, flags.initrace); } } else { /* pick4u == 'n' */ /* Count the number of valid alignments */ n = 0; /* number valid */ k = 0; /* valid alignment */ for (i = 0; i < ROLE_ALIGNS; i++) { if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { n++; k = i; } } if (n == 0) { for (i = 0; i < ROLE_ALIGNS; i++) { if (validalign(flags.initrole, flags.initrace, i)) { n++; k = i; } } } /* Permit the user to pick, if there is more than one */ if (n > 1) { /* tty_clear_nhwindow(BASE_WINDOW); */ /* tty_putstr(BASE_WINDOW, 0, "Choosing Alignment"); */ win = create_nhwindow(NHW_MENU); start_menu(win); any.a_void = 0; /* zero out all bits */ for (i = 0; i < ROLE_ALIGNS; i++) if (ok_align(flags.initrole, flags.initrace, flags.initgend, i)) { any.a_int = i+1; add_menu(win, NO_GLYPH, &any, aligns[i].adj[0], 0, ATR_NONE, aligns[i].adj, MENU_UNSELECTED); } any.a_int = pick_align(flags.initrole, flags.initrace, flags.initgend, PICK_RANDOM)+1; if (any.a_int == 0) /* must be non-zero */ any.a_int = randalign(flags.initrole, flags.initrace)+1; add_menu(win, NO_GLYPH, &any , '*', 0, ATR_NONE, "Random", MENU_UNSELECTED); any.a_int = i+1; /* must be non-zero */ add_menu(win, NO_GLYPH, &any , 'q', 0, ATR_NONE, "Quit", MENU_UNSELECTED); Sprintf(pbuf, "Pick the alignment of your %s", plbuf); end_menu(win, pbuf); n = select_menu(win, PICK_ONE, &selected); destroy_nhwindow(win); if (n != 1 || selected[0].item.a_int == any.a_int) goto give_up; /* Selected quit */ k = selected[0].item.a_int - 1; free((genericptr_t) selected), selected = 0; } flags.initalign = k; } } /* Success! */ /* tty_display_nhwindow(BASE_WINDOW, FALSE); */ } /* Ask the user for a player name. */ void mswin_askname(void) { logDebug("mswin_askname()\n"); if( mswin_getlin_window("Who are you?", plname, PL_NSIZ)==IDCANCEL ) { bail("bye-bye"); /* not reached */ } } /* Does window event processing (e.g. exposure events). A noop for the tty and X window-ports. */ void mswin_get_nh_event(void) { MSG msg; logDebug("mswin_get_nh_event()\n"); while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)!=0 ) { if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return; } /* Exits the window system. This should dismiss all windows, except the "window" used for raw_print(). str is printed if possible. */ void mswin_exit_nhwindows(const char *str) { logDebug("mswin_exit_nhwindows(%s)\n", str); /* Write Window settings to the registry */ mswin_write_reg(); while (max_brush) DeleteObject(brush_table[--max_brush]); } /* Prepare the window to be suspended. */ void mswin_suspend_nhwindows(const char *str) { logDebug("mswin_suspend_nhwindows(%s)\n", str); return; } /* Restore the windows after being suspended. */ void mswin_resume_nhwindows() { logDebug("mswin_resume_nhwindows()\n"); return; } /* Create a window of type "type" which can be NHW_MESSAGE (top line) NHW_STATUS (bottom lines) NHW_MAP (main dungeon) NHW_MENU (inventory or other "corner" windows) NHW_TEXT (help/text, full screen paged window) */ winid mswin_create_nhwindow(int type) { winid i = 0; MSNHMsgAddWnd data; logDebug("mswin_create_nhwindow(%d)\n", type); /* Return the next available winid */ for (i=1; iwindowlist[i].win == NULL && !GetNHApp()->windowlist[i].dead) break; if (i == MAXWINDOWS) panic ("ERROR: No windows available...\n"); switch (type) { case NHW_MAP: { GetNHApp()->windowlist[i].win = mswin_init_map_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_MESSAGE: { GetNHApp()->windowlist[i].win = mswin_init_message_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_STATUS: { GetNHApp()->windowlist[i].win = mswin_init_status_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } case NHW_MENU: { GetNHApp()->windowlist[i].win = NULL; //will create later GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 1; break; } case NHW_TEXT: { GetNHApp()->windowlist[i].win = mswin_init_text_window(); GetNHApp()->windowlist[i].type = type; GetNHApp()->windowlist[i].dead = 0; break; } } ZeroMemory(&data, sizeof(data) ); data.wid = i; SendMessage( GetNHApp()->hMainWnd, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDWND, (LPARAM)&data ); return i; } /* Clear the given window, when asked to. */ void mswin_clear_nhwindow(winid wid) { logDebug("mswin_clear_nhwindow(%d)\n", wid); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { #ifdef REINCARNATION if( GetNHApp()->windowlist[wid].type == NHW_MAP ) { if( Is_rogue_level(&u.uz) ) mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), ROGUE_LEVEL_MAP_MODE); else mswin_map_mode(mswin_hwnd_from_winid(WIN_MAP), iflags.wc_map_mode); } #endif SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLEAR_WINDOW, (LPARAM)NULL ); } } /* -- Display the window on the screen. If there is data pending for output in that window, it should be sent. If blocking is TRUE, display_nhwindow() will not return until the data has been displayed on the screen, and acknowledged by the user where appropriate. -- All calls are blocking in the tty window-port. -- Calling display_nhwindow(WIN_MESSAGE,???) will do a --more--, if necessary, in the tty window-port. */ void mswin_display_nhwindow(winid wid, BOOLEAN_P block) { logDebug("mswin_display_nhwindow(%d, %d)\n", wid, block); if (GetNHApp()->windowlist[wid].win != NULL) { if (GetNHApp()->windowlist[wid].type == NHW_MENU) { MENU_ITEM_P* p; mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, PICK_NONE, &p); } if (GetNHApp()->windowlist[wid].type == NHW_TEXT) { mswin_display_text_window(GetNHApp()->windowlist[wid].win); } if (GetNHApp()->windowlist[wid].type == NHW_RIP) { mswin_display_RIP_window(GetNHApp()->windowlist[wid].win); } else { if( !block ) { UpdateWindow(GetNHApp()->windowlist[wid].win); } else { if ( GetNHApp()->windowlist[wid].type == NHW_MAP ) { (void) mswin_nhgetch(); } } } SetFocus(GetNHApp()->hMainWnd); } } HWND mswin_hwnd_from_winid(winid wid) { if( wid>=0 && widwindowlist[wid].win; } else { return NULL; } } winid mswin_winid_from_handle(HWND hWnd) { winid i = 0; for (i=1; iwindowlist[i].win == hWnd) return i; return -1; } winid mswin_winid_from_type(int type) { winid i = 0; for (i=1; iwindowlist[i].type == type) return i; return -1; } void mswin_window_mark_dead(winid wid) { if( wid>=0 && widwindowlist[wid].win = NULL; GetNHApp()->windowlist[wid].dead = 1; } } /* Destroy will dismiss the window if the window has not * already been dismissed. */ void mswin_destroy_nhwindow(winid wid) { logDebug("mswin_destroy_nhwindow(%d)\n", wid); if ((GetNHApp()->windowlist[wid].type == NHW_MAP) || (GetNHApp()->windowlist[wid].type == NHW_MESSAGE) || (GetNHApp()->windowlist[wid].type == NHW_STATUS)) { /* main windows is going to take care of those */ return; } if (wid != -1) { if( !GetNHApp()->windowlist[wid].dead && GetNHApp()->windowlist[wid].win != NULL ) DestroyWindow(GetNHApp()->windowlist[wid].win); GetNHApp()->windowlist[wid].win = NULL; GetNHApp()->windowlist[wid].type = 0; GetNHApp()->windowlist[wid].dead = 0; } } /* Next output to window will start at (x,y), also moves displayable cursor to (x,y). For backward compatibility, 1 <= x < cols, 0 <= y < rows, where cols and rows are the size of window. */ void mswin_curs(winid wid, int x, int y) { logDebug("mswin_curs(%d, %d, %d)\n", wid, x, y); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgCursor data; data.x = x; data.y = y; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CURSOR, (LPARAM)&data ); } } /* putstr(window, attr, str) -- Print str on the window with the given attribute. Only printable ASCII characters (040-0126) must be supported. Multiple putstr()s are output on separate lines. Attributes can be one of ATR_NONE (or 0) ATR_ULINE ATR_BOLD ATR_BLINK ATR_INVERSE If a window-port does not support all of these, it may map unsupported attributes to a supported one (e.g. map them all to ATR_INVERSE). putstr() may compress spaces out of str, break str, or truncate str, if necessary for the display. Where putstr() breaks a line, it has to clear to end-of-line. -- putstr should be implemented such that if two putstr()s are done consecutively the user will see the first and then the second. In the tty port, pline() achieves this by calling more() or displaying both on the same line. */ void mswin_putstr(winid wid, int attr, const char *text) { logDebug("mswin_putstr(%d, %d, %s)\n", wid, attr, text); mswin_putstr_ex(wid, attr, text, 0); } void mswin_putstr_ex(winid wid, int attr, const char *text, int app) { if( (wid >= 0) && (wid < MAXWINDOWS) ) { if( GetNHApp()->windowlist[wid].win==NULL && GetNHApp()->windowlist[wid].type==NHW_MENU ) { GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_TEXT); GetNHApp()->windowlist[wid].dead = 0; } if (GetNHApp()->windowlist[wid].win != NULL) { MSNHMsgPutstr data; ZeroMemory(&data, sizeof(data)); data.attr = attr; data.text = text; data.append = app; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PUTSTR, (LPARAM)&data ); } /* yield a bit so it gets done immediately */ mswin_get_nh_event(); } else { // build text to display later in message box GetNHApp()->saved_text = realloc(GetNHApp()->saved_text, strlen(text) + strlen(GetNHApp()->saved_text) + 1); strcat(GetNHApp()->saved_text, text); } } /* Display the file named str. Complain about missing files iff complain is TRUE. */ void mswin_display_file(const char *filename,BOOLEAN_P must_exist) { dlb *f; TCHAR wbuf[BUFSZ]; logDebug("mswin_display_file(%s, %d)\n", filename, must_exist); f = dlb_fopen(filename, RDTMODE); if (!f) { if (must_exist) { TCHAR message[90]; _stprintf(message, TEXT("Warning! Could not find file: %s\n"), NH_A2W(filename, wbuf, sizeof(wbuf))); NHMessageBox(GetNHApp()->hMainWnd, message, MB_OK | MB_ICONEXCLAMATION ); } } else { winid text; char line[LLEN]; text = mswin_create_nhwindow(NHW_TEXT); while (dlb_fgets(line, LLEN, f)) { size_t len; len = strlen(line); if( line[len-1]=='\n' ) line[len-1]='\x0'; mswin_putstr(text, ATR_NONE, line); } (void) dlb_fclose(f); mswin_display_nhwindow(text, 1); mswin_destroy_nhwindow(text); } } /* Start using window as a menu. You must call start_menu() before add_menu(). After calling start_menu() you may not putstr() to the window. Only windows of type NHW_MENU may be used for menus. */ void mswin_start_menu(winid wid) { logDebug("mswin_start_menu(%d)\n", wid); if( (wid >= 0) && (wid < MAXWINDOWS) ) { if( GetNHApp()->windowlist[wid].win==NULL && GetNHApp()->windowlist[wid].type==NHW_MENU ) { GetNHApp()->windowlist[wid].win = mswin_init_menu_window(MENU_TYPE_MENU); GetNHApp()->windowlist[wid].dead = 0; } if(GetNHApp()->windowlist[wid].win != NULL) { SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_STARTMENU, (LPARAM)NULL ); } } } /* add_menu(windid window, int glyph, const anything identifier, char accelerator, char groupacc, int attr, char *str, boolean preselected) -- Add a text line str to the given menu window. If identifier is 0, then the line cannot be selected (e.g. a title). Otherwise, identifier is the value returned if the line is selected. Accelerator is a keyboard key that can be used to select the line. If the accelerator of a selectable item is 0, the window system is free to select its own accelerator. It is up to the window-port to make the accelerator visible to the user (e.g. put "a - " in front of str). The value attr is the same as in putstr(). Glyph is an optional glyph to accompany the line. If window port cannot or does not want to display it, this is OK. If there is no glyph applicable, then this value will be NO_GLYPH. -- All accelerators should be in the range [A-Za-z]. -- It is expected that callers do not mix accelerator choices. Either all selectable items have an accelerator or let the window system pick them. Don't do both. -- Groupacc is a group accelerator. It may be any character outside of the standard accelerator (see above) or a number. If 0, the item is unaffected by any group accelerator. If this accelerator conflicts with the menu command (or their user defined alises), it loses. The menu commands and aliases take care not to interfere with the default object class symbols. -- If you want this choice to be preselected when the menu is displayed, set preselected to TRUE. */ void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel) { logDebug("mswin_add_menu(%d, %d, %p, %c, %c, %d, %s, %d)\n", wid, glyph, identifier, (char)accelerator, (char)group_accel, attr, str, presel); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgAddMenu data; ZeroMemory(&data, sizeof(data)); data.glyph = glyph; data.identifier = identifier; data.accelerator = accelerator; data.group_accel = group_accel; data.attr = attr; data.str = str; data.presel = presel; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ADDMENU, (LPARAM)&data ); } } /* end_menu(window, prompt) -- Stop adding entries to the menu and flushes the window to the screen (brings to front?). Prompt is a prompt to give the user. If prompt is NULL, no prompt will be printed. ** This probably shouldn't flush the window any more (if ** it ever did). That should be select_menu's job. -dean */ void mswin_end_menu(winid wid, const char *prompt) { logDebug("mswin_end_menu(%d, %s)\n", wid, prompt); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgEndMenu data; ZeroMemory(&data, sizeof(data)); data.text = prompt; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_ENDMENU, (LPARAM)&data ); } } /* int select_menu(windid window, int how, menu_item **selected) -- Return the number of items selected; 0 if none were chosen, -1 when explicitly cancelled. If items were selected, then selected is filled in with an allocated array of menu_item structures, one for each selected line. The caller must free this array when done with it. The "count" field of selected is a user supplied count. If the user did not supply a count, then the count field is filled with -1 (meaning all). A count of zero is equivalent to not being selected and should not be in the list. If no items were selected, then selected is NULL'ed out. How is the mode of the menu. Three valid values are PICK_NONE, PICK_ONE, and PICK_N, meaning: nothing is selectable, only one thing is selectable, and any number valid items may selected. If how is PICK_NONE, this function should never return anything but 0 or -1. -- You may call select_menu() on a window multiple times -- the menu is saved until start_menu() or destroy_nhwindow() is called on the window. -- Note that NHW_MENU windows need not have select_menu() called for them. There is no way of knowing whether select_menu() will be called for the window at create_nhwindow() time. */ int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected) { int nReturned = -1; logDebug("mswin_select_menu(%d, %d)\n", wid, how); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { nReturned = mswin_menu_window_select_menu(GetNHApp()->windowlist[wid].win, how, selected); } return nReturned; } /* -- Indicate to the window port that the inventory has been changed. -- Merely calls display_inventory() for window-ports that leave the window up, otherwise empty. */ void mswin_update_inventory() { logDebug("mswin_update_inventory()\n"); } /* mark_synch() -- Don't go beyond this point in I/O on any channel until all channels are caught up to here. Can be an empty call for the moment */ void mswin_mark_synch() { logDebug("mswin_mark_synch()\n"); } /* wait_synch() -- Wait until all pending output is complete (*flush*() for streams goes here). -- May also deal with exposure events etc. so that the display is OK when return from wait_synch(). */ void mswin_wait_synch() { logDebug("mswin_wait_synch()\n"); } /* cliparound(x, y)-- Make sure that the user is more-or-less centered on the screen if the playing area is larger than the screen. -- This function is only defined if CLIPPING is defined. */ void mswin_cliparound(int x, int y) { winid wid = WIN_MAP; logDebug("mswin_cliparound(%d, %d)\n", x, y); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgClipAround data; data.x = x; data.y = y; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CLIPAROUND, (LPARAM)&data ); } } /* print_glyph(window, x, y, glyph) -- Print the glyph at (x,y) on the given window. Glyphs are integers at the interface, mapped to whatever the window- port wants (symbol, font, color, attributes, ...there's a 1-1 map between glyphs and distinct things on the map). */ void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph) { logDebug("mswin_print_glyph(%d, %d, %d, %d)\n", wid, x, y, glyph); if ((wid >= 0) && (wid < MAXWINDOWS) && (GetNHApp()->windowlist[wid].win != NULL)) { MSNHMsgPrintGlyph data; ZeroMemory(&data, sizeof(data) ); data.x = x; data.y = y; data.glyph = glyph; SendMessage( GetNHApp()->windowlist[wid].win, WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_PRINT_GLYPH, (LPARAM)&data ); } } /* raw_print(str) -- Print directly to a screen, or otherwise guarantee that the user sees str. raw_print() appends a newline to str. It need not recognize ASCII control characters. This is used during startup (before windowing system initialization -- maybe this means only error startup messages are raw), for error messages, and maybe other "msg" uses. E.g. updating status for micros (i.e, "saving"). */ void mswin_raw_print(const char *str) { TCHAR wbuf[255]; logDebug("mswin_raw_print(%s)\n", str); if( str && *str ) NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), MB_ICONINFORMATION | MB_OK ); } /* raw_print_bold(str) -- Like raw_print(), but prints in bold/standout (if possible). */ void mswin_raw_print_bold(const char *str) { TCHAR wbuf[255]; logDebug("mswin_raw_print_bold(%s)\n", str); if( str && *str ) NHMessageBox(GetNHApp()->hMainWnd, NH_A2W(str, wbuf, sizeof(wbuf)), MB_ICONINFORMATION | MB_OK ); } /* int nhgetch() -- Returns a single character input from the user. -- In the tty window-port, nhgetch() assumes that tgetch() will be the routine the OS provides to read a character. Returned character _must_ be non-zero. */ int mswin_nhgetch() { PMSNHEvent event; int key = 0; logDebug("mswin_nhgetch()\n"); while( (event = mswin_input_pop()) == NULL || event->type != NHEVENT_CHAR ) mswin_main_loop(); key = event->kbd.ch; return (key); } /* int nh_poskey(int *x, int *y, int *mod) -- Returns a single character input from the user or a a positioning event (perhaps from a mouse). If the return value is non-zero, a character was typed, else, a position in the MAP window is returned in x, y and mod. mod may be one of CLICK_1 -- mouse click type 1 CLICK_2 -- mouse click type 2 The different click types can map to whatever the hardware supports. If no mouse is supported, this routine always returns a non-zero character. */ int mswin_nh_poskey(int *x, int *y, int *mod) { PMSNHEvent event; int key; logDebug("mswin_nh_poskey()\n"); while( (event = mswin_input_pop())==NULL ) mswin_main_loop(); if( event->type==NHEVENT_MOUSE ) { *mod = event->ms.mod; *x = event->ms.x; *y = event->ms.y; key = 0; } else { key = event->kbd.ch; } return (key); } /* nhbell() -- Beep at user. [This will exist at least until sounds are redone, since sounds aren't attributable to windows anyway.] */ void mswin_nhbell() { logDebug("mswin_nhbell()\n"); } /* doprev_message() -- Display previous messages. Used by the ^P command. -- On the tty-port this scrolls WIN_MESSAGE back one line. */ int mswin_doprev_message() { logDebug("mswin_doprev_message()\n"); SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_VSCROLL, MAKEWPARAM(SB_LINEUP, 0), (LPARAM)NULL); return 0; } /* char yn_function(const char *ques, const char *choices, char default) -- Print a prompt made up of ques, choices and default. Read a single character response that is contained in choices or default. If choices is NULL, all possible inputs are accepted and returned. This overrides everything else. The choices are expected to be in lower case. Entering ESC always maps to 'q', or 'n', in that order, if present in choices, otherwise it maps to default. Entering any other quit character (SPACE, RETURN, NEWLINE) maps to default. -- If the choices string contains ESC, then anything after it is an acceptable response, but the ESC and whatever follows is not included in the prompt. -- If the choices string contains a '#' then accept a count. Place this value in the global "yn_number" and return '#'. -- This uses the top line in the tty window-port, other ports might use a popup. */ char mswin_yn_function(const char *question, const char *choices, CHAR_P def) { char ch; char yn_esc_map='\033'; char message[BUFSZ]; char res_ch[2]; int createcaret; boolean digit_ok, allow_num; logDebug("mswin_yn_function(%s, %s, %d)\n", question, choices, def); if (WIN_MESSAGE == WIN_ERR && choices == ynchars) { char *text = realloc(strdup(GetNHApp()->saved_text), strlen(question) + strlen(GetNHApp()->saved_text) + 1); DWORD box_result; strcat(text, question); box_result = NHMessageBox(NULL, NH_W2A(text, message, sizeof(message)), MB_YESNOCANCEL | MB_ICONQUESTION | ((def == 'y') ? MB_DEFBUTTON1 : (def == 'n') ? MB_DEFBUTTON2 : MB_DEFBUTTON3)); free(text); GetNHApp()->saved_text = strdup(""); return box_result == IDYES ? 'y' : box_result == IDNO ? 'n' : '\033'; } if (choices) { char *cb, choicebuf[QBUFSZ]; allow_num = (index(choices, '#') != 0); Strcpy(choicebuf, choices); if ((cb = index(choicebuf, '\033')) != 0) { /* anything beyond is hidden */ *cb = '\0'; } sprintf(message, "%s [%s] ", question, choicebuf); if (def) sprintf(eos(message), "(%c) ", def); /* escape maps to 'q' or 'n' or default, in that order */ yn_esc_map = (index(choices, 'q') ? 'q' : (index(choices, 'n') ? 'n' : def)); } else { Strcpy(message, question); Strcat(message, " "); } createcaret = 1; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret ); mswin_clear_nhwindow(WIN_MESSAGE); mswin_putstr(WIN_MESSAGE, ATR_BOLD, message); /* Only here if main window is not present */ ch = 0; do { ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); ch=mswin_nhgetch(); HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); if (choices) ch = lowc(ch); else break; /* If choices is NULL, all possible inputs are accepted and returned. */ digit_ok = allow_num && digit(ch); if (ch=='\033') { if (index(choices, 'q')) ch = 'q'; else if (index(choices, 'n')) ch = 'n'; else ch = def; break; } else if (index(quitchars, ch)) { ch = def; break; } else if (!index(choices, ch) && !digit_ok) { mswin_nhbell(); ch = (char)0; /* and try again... */ } else if (ch == '#' || digit_ok) { char z, digit_string[2]; int n_len = 0; long value = 0; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, ("#"), 1); n_len++; digit_string[1] = '\0'; if (ch != '#') { digit_string[0] = ch; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1); n_len++; value = ch - '0'; ch = '#'; } do { /* loop until we get a non-digit */ z = lowc(readchar()); if (digit(z)) { value = (10 * value) + (z - '0'); if (value < 0) break; /* overflow: try again */ digit_string[0] = z; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, 1); n_len++; } else if (z == 'y' || index(quitchars, z)) { if (z == '\033') value = -1; /* abort */ z = '\n'; /* break */ } else if (z == '\b') { if (n_len <= 1) { value = -1; break; } else { value /= 10; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -1); n_len--; } } else { value = -1; /* abort */ mswin_nhbell(); break; } } while (z != '\n'); if (value > 0) yn_number = value; else if (value == 0) ch = 'n'; /* 0 => "no" */ else { /* remove number from top line, then try again */ mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, digit_string, -n_len); n_len = 0; ch = (char)0; } } } while( !ch ); createcaret = 0; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret ); /* display selection in the message window */ if( isprint(ch) && ch!='#' ) { res_ch[0] = ch; res_ch[1] = '\x0'; mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, res_ch, 1); } return ch; } /* getlin(const char *ques, char *input) -- Prints ques as a prompt and reads a single line of text, up to a newline. The string entered is returned without the newline. ESC is used to cancel, in which case the string "\033\000" is returned. -- getlin() must call flush_screen(1) before doing anything. -- This uses the top line in the tty window-port, other ports might use a popup. */ void mswin_getlin(const char *question, char *input) { logDebug("mswin_getlin(%s, %p)\n", question, input); if (!iflags.wc_popup_dialog) { char c; int len; int done; int createcaret; createcaret = 1; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret ); mswin_clear_nhwindow(WIN_MESSAGE); mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, question, 0); mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, " ", 1); input[0] = '\0'; len = 0; ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); done = FALSE; while (!done) { c = mswin_nhgetch(); switch (c) { case VK_ESCAPE: strcpy(input, "\033"); done = TRUE; break; case '\n': case '\r': case -115: done = TRUE; break; default: if (input[0]) mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, -len); if (c == VK_BACK) { if (len > 0) len--; input[len] = '\0'; } else { input[len++] = c; input[len] = '\0'; } mswin_putstr_ex(WIN_MESSAGE, ATR_NONE, input, 1); break; } } HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); createcaret = 0; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret ); } else { if( mswin_getlin_window(question, input, BUFSZ)==IDCANCEL ) { strcpy(input, "\033"); } } } /* int get_ext_cmd(void) -- Get an extended command in a window-port specific way. An index into extcmdlist[] is returned on a successful selection, -1 otherwise. */ int mswin_get_ext_cmd() { int ret; logDebug("mswin_get_ext_cmd()\n"); if (!iflags.wc_popup_dialog) { char c; char cmd[BUFSZ]; int i, len; int createcaret; createcaret = 1; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret ); cmd[0] = '\0'; i = -2; mswin_clear_nhwindow(WIN_MESSAGE); mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, "#", 0); len = 0; ShowCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); while (i == -2) { int oindex, com_index; c = mswin_nhgetch(); switch (c) { case VK_ESCAPE: i = -1; break; case '\n': case '\r': case -115: for (i = 0; extcmdlist[i].ef_txt != (char *)0; i++) if (!strcmpi(cmd, extcmdlist[i].ef_txt)) break; if (extcmdlist[i].ef_txt == (char *)0) { pline("%s: unknown extended command.", cmd); i = -1; } break; default: if (cmd[0]) mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, -(int)strlen(cmd)); if (c == VK_BACK) { if (len > 0) len--; cmd[len] = '\0'; } else { cmd[len++] = c; cmd[len] = '\0'; /* Find a command with this prefix in extcmdlist */ com_index = -1; for (oindex = 0; extcmdlist[oindex].ef_txt != (char *)0; oindex++) { if (!strncmpi(cmd, extcmdlist[oindex].ef_txt, len)) { if (com_index == -1) /* no matches yet */ com_index = oindex; else com_index = -2; /* two matches, don't complete */ } } if (com_index >= 0) { Strcpy(cmd, extcmdlist[com_index].ef_txt); } } mswin_putstr_ex(WIN_MESSAGE, ATR_BOLD, cmd, 1); break; } } HideCaret(mswin_hwnd_from_winid(WIN_MESSAGE)); createcaret = 0; SendMessage(mswin_hwnd_from_winid(WIN_MESSAGE), WM_MSNH_COMMAND, (WPARAM)MSNH_MSG_CARET, (LPARAM)&createcaret ); return i; } else { if(mswin_ext_cmd_window (&ret) == IDCANCEL) return -1; else return ret; } } /* number_pad(state) -- Initialize the number pad to the given state. */ void mswin_number_pad(int state) { /* Do Nothing */ logDebug("mswin_number_pad(%d)\n", state); } /* delay_output() -- Causes a visible delay of 50ms in the output. Conceptually, this is similar to wait_synch() followed by a nap(50ms), but allows asynchronous operation. */ void mswin_delay_output() { logDebug("mswin_delay_output()\n"); Sleep(50); } void mswin_change_color() { logDebug("mswin_change_color()\n"); } char *mswin_get_color_string() { logDebug("mswin_get_color_string()\n"); return( "" ); } /* start_screen() -- Only used on Unix tty ports, but must be declared for completeness. Sets up the tty to work in full-screen graphics mode. Look at win/tty/termcap.c for an example. If your window-port does not need this function just declare an empty function. */ void mswin_start_screen() { /* Do Nothing */ logDebug("mswin_start_screen()\n"); } /* end_screen() -- Only used on Unix tty ports, but must be declared for completeness. The complement of start_screen(). */ void mswin_end_screen() { /* Do Nothing */ logDebug("mswin_end_screen()\n"); } /* outrip(winid, int) -- The tombstone code. If you want the traditional code use genl_outrip for the value and check the #if in rip.c. */ #define STONE_LINE_LEN 16 void mswin_outrip(winid wid, int how) { char buf[BUFSZ]; logDebug("mswin_outrip(%d)\n", wid, how); if ((wid >= 0) && (wid < MAXWINDOWS) ) { DestroyWindow(GetNHApp()->windowlist[wid].win); GetNHApp()->windowlist[wid].win = mswin_init_RIP_window(); GetNHApp()->windowlist[wid].type = NHW_RIP; GetNHApp()->windowlist[wid].dead = 0; } /* Put name on stone */ Sprintf(buf, "%s", plname); buf[STONE_LINE_LEN] = 0; putstr(wid, 0, buf); /* Put $ on stone */ #ifndef GOLDOBJ Sprintf(buf, "%ld Au", u.ugold); #else Sprintf(buf, "%ld Au", done_money); #endif buf[STONE_LINE_LEN] = 0; /* It could be a *lot* of gold :-) */ putstr(wid, 0, buf); /* Put together death description */ switch (killer_format) { default: impossible("bad killer format?"); case KILLED_BY_AN: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, an(killer)); break; case KILLED_BY: Strcpy(buf, killed_by_prefix[how]); Strcat(buf, killer); break; case NO_KILLER_PREFIX: Strcpy(buf, killer); break; } /* Put death type on stone */ putstr(wid, 0, buf); /* Put year on stone */ Sprintf(buf, "%4d", getyear()); putstr(wid, 0, buf); mswin_finish_rip_text(wid); } /* handle options updates here */ void mswin_preference_update(const char *pref) { HDC hdc; if( stricmp( pref, "font_menu")==0 || stricmp( pref, "font_size_menu")==0 ) { if( iflags.wc_fontsiz_menuNHFONT_SIZE_MAX ) iflags.wc_fontsiz_menu = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MENU, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_MENU, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if( stricmp( pref, "font_status")==0 || stricmp( pref, "font_size_status")==0 ) { if( iflags.wc_fontsiz_statusNHFONT_SIZE_MAX ) iflags.wc_fontsiz_status = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_STATUS, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_STATUS, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); InvalidateRect(mswin_hwnd_from_winid(WIN_STATUS), NULL, TRUE); mswin_layout_main_window(NULL); return; } if( stricmp( pref, "font_message")==0 || stricmp( pref, "font_size_message")==0 ) { if( iflags.wc_fontsiz_messageNHFONT_SIZE_MAX ) iflags.wc_fontsiz_message = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_MESSAGE, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_MESSAGE, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE); mswin_layout_main_window(NULL); return; } if( stricmp( pref, "font_text")==0 || stricmp( pref, "font_size_text")==0 ) { if( iflags.wc_fontsiz_textNHFONT_SIZE_MAX ) iflags.wc_fontsiz_text = NHFONT_DEFAULT_SIZE; hdc = GetDC(GetNHApp()->hMainWnd); mswin_get_font(NHW_TEXT, ATR_NONE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BOLD, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_DIM, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_ULINE, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_BLINK, hdc, TRUE); mswin_get_font(NHW_TEXT, ATR_INVERSE, hdc, TRUE); ReleaseDC(GetNHApp()->hMainWnd, hdc); mswin_layout_main_window(NULL); return; } if( stricmp( pref, "scroll_amount")==0 ) { mswin_cliparound(u.ux, u.uy); return; } if( stricmp( pref, "scroll_margin")==0 ) { mswin_cliparound(u.ux, u.uy); return; } if( stricmp( pref, "map_mode")==0 ) { mswin_select_map_mode( iflags.wc_map_mode ); return; } if( stricmp( pref, "hilite_pet")==0 ) { InvalidateRect(mswin_hwnd_from_winid(WIN_MAP), NULL, TRUE); return; } if( stricmp( pref, "align_message")==0 || stricmp( pref, "align_status")==0 ) { mswin_layout_main_window(NULL); return; } if( stricmp( pref, "vary_msgcount")==0 ) { InvalidateRect(mswin_hwnd_from_winid(WIN_MESSAGE), NULL, TRUE); mswin_layout_main_window(NULL); return; } } void mswin_main_loop() { MSG msg; while( !mswin_have_input() && GetMessage(&msg, NULL, 0, 0)!=0 ) { if (GetNHApp()->regNetHackMode || !TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } /* clean up and quit */ void bail(const char *mesg) { clearlocks(); mswin_exit_nhwindows(mesg); terminate(EXIT_SUCCESS); /*NOTREACHED*/ } BOOL initMapTiles(void) { HBITMAP hBmp; BITMAP bm; TCHAR wbuf[MAX_PATH]; int tl_num; SIZE map_size; extern int total_tiles_used; /* no file - no tile */ if( !(iflags.wc_tile_file && *iflags.wc_tile_file) ) return TRUE; /* load bitmap */ hBmp = LoadImage( GetNHApp()->hApp, NH_A2W(iflags.wc_tile_file, wbuf, MAX_PATH), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE ); if( hBmp==NULL ) { raw_print("Cannot load tiles from the file. Reverting back to default."); return FALSE; } /* calculate tile dimensions */ GetObject(hBmp, sizeof(BITMAP), (LPVOID)&bm); if( bm.bmWidth%iflags.wc_tile_width || bm.bmHeight%iflags.wc_tile_height ) { DeleteObject(hBmp); raw_print("Tiles bitmap does not match tile_width and tile_height options. Reverting back to default."); return FALSE; } tl_num = (bm.bmWidth/iflags.wc_tile_width)* (bm.bmHeight/iflags.wc_tile_height); if( tl_numbmpMapTiles!=GetNHApp()->bmpTiles ) { DeleteObject(GetNHApp()->bmpMapTiles); } GetNHApp()->bmpMapTiles = hBmp; GetNHApp()->mapTile_X = iflags.wc_tile_width; GetNHApp()->mapTile_Y = iflags.wc_tile_height; GetNHApp()->mapTilesPerLine = bm.bmWidth / iflags.wc_tile_width; map_size.cx = GetNHApp()->mapTile_X * COLNO; map_size.cy = GetNHApp()->mapTile_Y * ROWNO; mswin_map_stretch( mswin_hwnd_from_winid(WIN_MAP), &map_size, TRUE ); return TRUE; } void mswin_popup_display(HWND hWnd, int* done_indicator) { MSG msg; HWND hChild; HMENU hMenu; int mi_count; int i; /* activate the menu window */ GetNHApp()->hPopupWnd = hWnd; mswin_layout_main_window(hWnd); /* disable game windows */ for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild; hChild = GetWindow(hChild, GW_HWNDNEXT) ) { if( hChild!= hWnd) EnableWindow(hChild, FALSE); } /* disable menu */ hMenu = GetMenu( GetNHApp()->hMainWnd ); mi_count = GetMenuItemCount( hMenu ); for( i=0; ihMainWnd ); /* bring menu window on top */ SetWindowPos(hWnd, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW); /* go into message loop */ while( IsWindow(hWnd) && (done_indicator==NULL || !*done_indicator) && GetMessage(&msg, NULL, 0, 0)!=0 ) { if( !IsDialogMessage(hWnd, &msg) ) { if (!TranslateAccelerator(msg.hwnd, GetNHApp()->hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } } } void mswin_popup_destroy(HWND hWnd) { HWND hChild; HMENU hMenu; int mi_count; int i; /* enable game windows */ for( hChild=GetWindow(GetNHApp()->hMainWnd, GW_CHILD); hChild; hChild = GetWindow(hChild, GW_HWNDNEXT) ) { if( hChild!= hWnd) { EnableWindow(hChild, TRUE); } } /* enable menu */ hMenu = GetMenu( GetNHApp()->hMainWnd ); mi_count = GetMenuItemCount( hMenu ); for( i=0; ihMainWnd ); SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_HIDEWINDOW); GetNHApp()->hPopupWnd = NULL; mswin_window_mark_dead( mswin_winid_from_handle(hWnd) ); DestroyWindow(hWnd); mswin_layout_main_window(hWnd); SetFocus(GetNHApp()->hMainWnd ); } #ifdef _DEBUG #include void logDebug(const char *fmt, ...) { FILE *dfp = fopen("nhtrace.log", "a"); if (dfp) { va_list args; va_start(args, fmt); vfprintf(dfp, fmt, args); va_end(args); fclose(dfp); } } #endif /* Reading and writing settings from the registry. */ #define CATEGORYKEY "Software" #define COMPANYKEY "NetHack" #define PRODUCTKEY "NetHack 3.4.3" #define SETTINGSKEY "Settings" #define MAINSHOWSTATEKEY "MainShowState" #define MAINMINXKEY "MainMinX" #define MAINMINYKEY "MainMinY" #define MAINMAXXKEY "MainMaxX" #define MAINMAXYKEY "MainMaxY" #define MAINLEFTKEY "MainLeft" #define MAINRIGHTKEY "MainRight" #define MAINTOPKEY "MainTop" #define MAINBOTTOMKEY "MainBottom" /* #define all the subkeys here */ #define INTFKEY "Interface" void mswin_read_reg() { HKEY key; DWORD size; char keystring[MAX_PATH]; sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY); /* Set the defaults here. The very first time the app is started, nothing is read from the registry, so these defaults apply. */ GetNHApp()->saveRegistrySettings = 1; /* Normally, we always save */ GetNHApp()->regNetHackMode = 0; if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key) != ERROR_SUCCESS) return; size = sizeof(DWORD); /* Read the keys here. */ RegQueryValueEx(key, INTFKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regNetHackMode)), &size); /* Main window placement */ RegQueryValueEx(key, MAINSHOWSTATEKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainShowState)), &size); RegQueryValueEx(key, MAINMINXKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMinX)), &size); RegQueryValueEx(key, MAINMINYKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMinY)), &size); RegQueryValueEx(key, MAINMAXXKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMaxX)), &size); RegQueryValueEx(key, MAINMAXYKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainMaxY)), &size); RegQueryValueEx(key, MAINLEFTKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainLeft)), &size); RegQueryValueEx(key, MAINRIGHTKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainRight)), &size); RegQueryValueEx(key, MAINTOPKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainTop)), &size); RegQueryValueEx(key, MAINBOTTOMKEY, 0, NULL, (unsigned char *)(&(GetNHApp()->regMainBottom)), &size); RegCloseKey(key); } void mswin_write_reg() { HKEY key; DWORD disposition; if (GetNHApp()->saveRegistrySettings) { char keystring[MAX_PATH]; sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY); if (RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_WRITE, &key) != ERROR_SUCCESS) { RegCreateKeyEx(HKEY_CURRENT_USER, keystring, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &key, &disposition); } /* Write the keys here */ RegSetValueEx(key, INTFKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regNetHackMode)), sizeof(DWORD)); /* Main window placement */ RegSetValueEx(key, MAINSHOWSTATEKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainShowState)), sizeof(DWORD)); RegSetValueEx(key, MAINMINXKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMinX)), sizeof(DWORD)); RegSetValueEx(key, MAINMINYKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMinY)), sizeof(DWORD)); RegSetValueEx(key, MAINMAXXKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMaxX)), sizeof(DWORD)); RegSetValueEx(key, MAINMAXYKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainMaxY)), sizeof(DWORD)); RegSetValueEx(key, MAINLEFTKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainLeft)), sizeof(DWORD)); RegSetValueEx(key, MAINRIGHTKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainRight)), sizeof(DWORD)); RegSetValueEx(key, MAINTOPKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainTop)), sizeof(DWORD)); RegSetValueEx(key, MAINBOTTOMKEY, 0, REG_DWORD, (unsigned char *)(&(GetNHApp()->regMainBottom)), sizeof(DWORD)); RegCloseKey(key); } } void mswin_destroy_reg() { char keystring[MAX_PATH]; HKEY key; DWORD nrsubkeys; /* Delete keys one by one, as NT does not delete trees */ sprintf(keystring, "%s\\%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY, SETTINGSKEY); RegDeleteKey(HKEY_CURRENT_USER, keystring); sprintf(keystring, "%s\\%s\\%s", CATEGORYKEY, COMPANYKEY, PRODUCTKEY); RegDeleteKey(HKEY_CURRENT_USER, keystring); /* The company key will also contain information about newer versions of nethack (e.g. a subkey called NetHack 4.0), so only delete that if it's empty now. */ sprintf(keystring, "%s\\%s", CATEGORYKEY, COMPANYKEY); /* If we cannot open it, we probably cannot delete it either... Just go on and see what happens. */ RegOpenKeyEx(HKEY_CURRENT_USER, keystring, 0, KEY_READ, &key); nrsubkeys = 0; RegQueryInfoKey(key, NULL, NULL, NULL, &nrsubkeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL); RegCloseKey(key); if (nrsubkeys == 0) RegDeleteKey(HKEY_CURRENT_USER, keystring); /* Prevent saving on exit */ GetNHApp()->saveRegistrySettings = 0; } typedef struct ctv { const char *colorstring; COLORREF colorvalue; } color_table_value; /* * The color list here is a combination of: * NetHack colors. (See mhmap.c) * HTML colors. (See http://www.w3.org/TR/REC-html40/types.html#h-6.5 ) */ static color_table_value color_table[] = { /* NetHack colors */ { "black", RGB(0x55, 0x55, 0x55)}, { "red", RGB(0xFF, 0x00, 0x00)}, { "green", RGB(0x00, 0x80, 0x00)}, { "brown", RGB(0xA5, 0x2A, 0x2A)}, { "blue", RGB(0x00, 0x00, 0xFF)}, { "magenta", RGB(0xFF, 0x00, 0xFF)}, { "cyan", RGB(0x00, 0xFF, 0xFF)}, { "orange", RGB(0xFF, 0xA5, 0x00)}, { "brightgreen", RGB(0x00, 0xFF, 0x00)}, { "yellow", RGB(0xFF, 0xFF, 0x00)}, { "brightblue", RGB(0x00, 0xC0, 0xFF)}, { "brightmagenta", RGB(0xFF, 0x80, 0xFF)}, { "brightcyan", RGB(0x80, 0xFF, 0xFF)}, { "white", RGB(0xFF, 0xFF, 0xFF)}, /* Remaining HTML colors */ { "trueblack", RGB(0x00, 0x00, 0x00)}, { "gray", RGB(0x80, 0x80, 0x80)}, { "grey", RGB(0x80, 0x80, 0x80)}, { "purple", RGB(0x80, 0x00, 0x80)}, { "silver", RGB(0xC0, 0xC0, 0xC0)}, { "maroon", RGB(0x80, 0x00, 0x00)}, { "fuchsia", RGB(0xFF, 0x00, 0xFF)}, /* = NetHack magenta */ { "lime", RGB(0x00, 0xFF, 0x00)}, /* = NetHack bright green */ { "olive", RGB(0x80, 0x80, 0x00)}, { "navy", RGB(0x00, 0x00, 0x80)}, { "teal", RGB(0x00, 0x80, 0x80)}, { "aqua", RGB(0x00, 0xFF, 0xFF)}, /* = NetHack cyan */ { "", RGB(0x00, 0x00, 0x00)}, }; typedef struct ctbv { char *colorstring; int syscolorvalue; } color_table_brush_value; static color_table_brush_value color_table_brush[] = { { "activeborder", COLOR_ACTIVEBORDER }, { "activecaption", COLOR_ACTIVECAPTION }, { "appworkspace", COLOR_APPWORKSPACE }, { "background", COLOR_BACKGROUND }, { "btnface", COLOR_BTNFACE }, { "btnshadow", COLOR_BTNSHADOW }, { "btntext", COLOR_BTNTEXT }, { "captiontext", COLOR_CAPTIONTEXT }, { "graytext", COLOR_GRAYTEXT }, { "greytext", COLOR_GRAYTEXT }, { "highlight", COLOR_HIGHLIGHT }, { "highlighttext", COLOR_HIGHLIGHTTEXT }, { "inactiveborder", COLOR_INACTIVEBORDER }, { "inactivecaption", COLOR_INACTIVECAPTION }, { "menu", COLOR_MENU }, { "menutext", COLOR_MENUTEXT }, { "scrollbar", COLOR_SCROLLBAR }, { "window", COLOR_WINDOW }, { "windowframe", COLOR_WINDOWFRAME }, { "windowtext", COLOR_WINDOWTEXT }, { "", -1 }, }; static void mswin_color_from_string(char *colorstring, HBRUSH* brushptr, COLORREF *colorptr) { color_table_value *ctv_ptr = color_table; color_table_brush_value *ctbv_ptr = color_table_brush; int red_value, blue_value, green_value; static char *hexadecimals = "0123456789abcdef"; if (colorstring == NULL) return; if (*colorstring == '#') { if (strlen(++colorstring) != 6) return; red_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals; red_value *= 16; red_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals; green_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals; green_value *= 16; green_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals; blue_value = index(hexadecimals, tolower(*colorstring++)) - hexadecimals; blue_value *= 16; blue_value += index(hexadecimals, tolower(*colorstring++)) - hexadecimals; *colorptr = RGB(red_value, green_value, blue_value); } else { while (*ctv_ptr->colorstring && stricmp(ctv_ptr->colorstring, colorstring)) ++ctv_ptr; if (*ctv_ptr->colorstring) { *colorptr = ctv_ptr->colorvalue; } else { while (*ctbv_ptr->colorstring && stricmp(ctbv_ptr->colorstring, colorstring)) ++ctbv_ptr; if (*ctbv_ptr->colorstring) { *brushptr = SYSCLR_TO_BRUSH(ctbv_ptr->syscolorvalue); *colorptr = GetSysColor(ctbv_ptr->syscolorvalue); } } } if (max_brush > TOTAL_BRUSHES) panic("Too many colors!"); *brushptr = CreateSolidBrush(*colorptr); brush_table[max_brush++] = *brushptr; } int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type) { TCHAR title[MAX_LOADSTRING]; LoadString(GetNHApp()->hApp, IDS_APP_TITLE_SHORT, title, MAX_LOADSTRING); return MessageBox(hWnd, text, title, type); } nethack-3.4.3/win/win32/nethack.dsw0100644000000000000000000001015307764735152015550 0ustar rootrootMicrosoft Developer Studio Workspace File, Format Version 6.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "NetHackW"=.\build\NetHackW.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name dgncomp End Project Dependency Begin Project Dependency Project_Dep_Name dlb_main End Project Dependency Begin Project Dependency Project_Dep_Name levcomp End Project Dependency Begin Project Dependency Project_Dep_Name makedefs End Project Dependency Begin Project Dependency Project_Dep_Name tilemap End Project Dependency Begin Project Dependency Project_Dep_Name tiles End Project Dependency Begin Project Dependency Project_Dep_Name uudecode End Project Dependency }}} ############################################################################### Project: "dgncomp"=.\build\dgncomp.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name dgnstuff End Project Dependency }}} ############################################################################### Project: "dgnstuff"=.\build\dgnstuff.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name makedefs End Project Dependency }}} ############################################################################### Project: "dlb_main"=.\build\dlb_main.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name dgncomp End Project Dependency Begin Project Dependency Project_Dep_Name levcomp End Project Dependency Begin Project Dependency Project_Dep_Name makedefs End Project Dependency }}} ############################################################################### Project: "levcomp"=.\build\levcomp.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name levstuff End Project Dependency }}} ############################################################################### Project: "levstuff"=.\build\levstuff.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name makedefs End Project Dependency }}} ############################################################################### Project: "makedefs"=.\build\makedefs.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "recover"=.\build\recover.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name makedefs End Project Dependency Begin Project Dependency Project_Dep_Name dlb_main End Project Dependency }}} ############################################################################### Project: "tile2bmp"=.\build\tile2bmp.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "tilemap"=.\build\tilemap.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "tiles"=.\build\tiles.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ Begin Project Dependency Project_Dep_Name tile2bmp End Project Dependency }}} ############################################################################### Project: "uudecode"=.\build\uudecode.dsp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### nethack-3.4.3/win/win32/nethackw.dsp0100644000000000000000000005274707764735152015747 0ustar rootroot# Microsoft Developer Studio Project File - Name="NetHackW" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Application" 0x0101 CFG=NetHackW - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "NetHackW.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "NetHackW.mak" CFG="NetHackW - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "NetHackW - Win32 Release" (based on "Win32 (x86) Application") !MESSAGE "NetHackW - Win32 Debug" (based on "Win32 (x86) Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe MTL=midl.exe RSC=rc.exe !IF "$(CFG)" == "NetHackW - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /Og /Oy /Ob1 /Gs /Gf /Gy /Oi- /Ot /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c # ADD CPP /nologo /W3 /GX /Og /Oy /Ob1 /Gs /Gf /Gy /Oi- /Ot /I "..\win\win32" /I "..\include" /I "..\sys\winnt" /I "..\sys\share" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c # SUBTRACT CPP /YX /Yc /Yu # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /map /debug /machine:I386 /MAPINFO:EXPORTS /MAPINFO:LINES # SUBTRACT LINK32 /pdb:none # Begin Special Build Tool OutDir=.\Release SOURCE="$(InputPath)" PostBuild_Desc=Install exe PostBuild_Cmds=copy $(OutDir)\NetHackW.exe ..\binary \ copy ..\dat\nhdat ..\binary \ copy ..\dat\license ..\binary \ if exist tiles.bmp copy tiles.bmp ..\binary \ if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt \ if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt \ copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh # End Special Build Tool !ELSEIF "$(CFG)" == "NetHackW - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\win\win32" /I "..\include" /I "..\sys\winnt" /I "..\sys\share" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c # SUBTRACT CPP /YX /Yc /Yu # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib comctl32.lib advapi32.lib winmm.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept # Begin Special Build Tool OutDir=.\Debug SOURCE="$(InputPath)" PostBuild_Desc=Install exe PostBuild_Cmds=if NOT exist ..\binary\*.* mkdir ..\binary \ copy $(OutDir)\NetHackW.exe ..\binary \ copy ..\dat\nhdat ..\binary \ copy ..\dat\license ..\binary \ if exist tiles.bmp copy tiles.bmp ..\binary \ if exist ..\doc\Guidebook.txt copy ..\doc\Guidebook.txt ..\binary\Guidebook.txt \ if exist ..\doc\nethack.txt copy ..\doc\nethack.txt ..\binary\NetHack.txt \ copy ..\sys\winnt\defaults.nh ..\binary\defaults.nh # End Special Build Tool !ENDIF # Begin Target # Name "NetHackW - Win32 Release" # Name "NetHackW - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\src\allmain.c # End Source File # Begin Source File SOURCE=..\src\alloc.c # End Source File # Begin Source File SOURCE=..\src\apply.c # End Source File # Begin Source File SOURCE=..\src\artifact.c # End Source File # Begin Source File SOURCE=..\src\attrib.c # End Source File # Begin Source File SOURCE=..\src\ball.c # End Source File # Begin Source File SOURCE=..\src\bones.c # End Source File # Begin Source File SOURCE=..\src\botl.c # End Source File # Begin Source File SOURCE=..\src\cmd.c # End Source File # Begin Source File SOURCE=..\src\dbridge.c # End Source File # Begin Source File SOURCE=..\src\decl.c # End Source File # Begin Source File SOURCE=..\src\detect.c # End Source File # Begin Source File SOURCE=..\src\dig.c # End Source File # Begin Source File SOURCE=..\src\display.c # End Source File # Begin Source File SOURCE=..\src\dlb.c # End Source File # Begin Source File SOURCE=..\src\do.c # End Source File # Begin Source File SOURCE=..\src\do_name.c # End Source File # Begin Source File SOURCE=..\src\do_wear.c # End Source File # Begin Source File SOURCE=..\src\dog.c # End Source File # Begin Source File SOURCE=..\src\dogmove.c # End Source File # Begin Source File SOURCE=..\src\dokick.c # End Source File # Begin Source File SOURCE=..\src\dothrow.c # End Source File # Begin Source File SOURCE=..\src\drawing.c # End Source File # Begin Source File SOURCE=..\src\dungeon.c # End Source File # Begin Source File SOURCE=..\src\eat.c # End Source File # Begin Source File SOURCE=..\src\end.c # End Source File # Begin Source File SOURCE=..\src\engrave.c # End Source File # Begin Source File SOURCE=..\src\exper.c # End Source File # Begin Source File SOURCE=..\src\explode.c # End Source File # Begin Source File SOURCE=..\src\extralev.c # End Source File # Begin Source File SOURCE=..\src\files.c # End Source File # Begin Source File SOURCE=..\src\fountain.c # End Source File # Begin Source File SOURCE=..\win\tty\getline.c # End Source File # Begin Source File SOURCE=..\src\hack.c # End Source File # Begin Source File SOURCE=..\src\hacklib.c # End Source File # Begin Source File SOURCE=..\src\invent.c # End Source File # Begin Source File SOURCE=..\src\light.c # End Source File # Begin Source File SOURCE=..\src\lock.c # End Source File # Begin Source File SOURCE=..\src\mail.c # End Source File # Begin Source File SOURCE=..\src\makemon.c # End Source File # Begin Source File SOURCE=..\src\mapglyph.c # End Source File # Begin Source File SOURCE=..\src\mcastu.c # End Source File # Begin Source File SOURCE=..\src\mhitm.c # End Source File # Begin Source File SOURCE=..\src\mhitu.c # End Source File # Begin Source File SOURCE=..\src\minion.c # End Source File # Begin Source File SOURCE=..\src\mklev.c # End Source File # Begin Source File SOURCE=..\src\mkmap.c # End Source File # Begin Source File SOURCE=..\src\mkmaze.c # End Source File # Begin Source File SOURCE=..\src\mkobj.c # End Source File # Begin Source File SOURCE=..\src\mkroom.c # End Source File # Begin Source File SOURCE=..\src\mon.c # End Source File # Begin Source File SOURCE=..\src\mondata.c # End Source File # Begin Source File SOURCE=..\src\monmove.c # End Source File # Begin Source File SOURCE=..\src\monst.c # End Source File # Begin Source File SOURCE=..\src\monstr.c # End Source File # Begin Source File SOURCE=..\src\mplayer.c # End Source File # Begin Source File SOURCE=..\src\mthrowu.c # End Source File # Begin Source File SOURCE=..\src\muse.c # End Source File # Begin Source File SOURCE=..\src\music.c # End Source File # Begin Source File SOURCE=..\sys\winnt\ntsound.c # End Source File # Begin Source File SOURCE=..\src\o_init.c # End Source File # Begin Source File SOURCE=..\src\objects.c # End Source File # Begin Source File SOURCE=..\src\objnam.c # End Source File # Begin Source File SOURCE=..\src\options.c # End Source File # Begin Source File SOURCE=..\src\pager.c # End Source File # Begin Source File SOURCE=..\sys\share\pcmain.c # End Source File # Begin Source File SOURCE=..\sys\share\pcsys.c # End Source File # Begin Source File SOURCE=..\sys\share\pcunix.c # End Source File # Begin Source File SOURCE=..\src\pickup.c # End Source File # Begin Source File SOURCE=..\src\pline.c # End Source File # Begin Source File SOURCE=..\src\polyself.c # End Source File # Begin Source File SOURCE=..\src\potion.c # End Source File # Begin Source File SOURCE=..\src\pray.c # End Source File # Begin Source File SOURCE=..\src\priest.c # End Source File # Begin Source File SOURCE=..\src\quest.c # End Source File # Begin Source File SOURCE=..\src\questpgr.c # End Source File # Begin Source File SOURCE=..\sys\share\random.c # End Source File # Begin Source File SOURCE=..\src\read.c # End Source File # Begin Source File SOURCE=..\src\rect.c # End Source File # Begin Source File SOURCE=..\src\region.c # End Source File # Begin Source File SOURCE=..\src\restore.c # End Source File # Begin Source File SOURCE=..\src\rip.c # End Source File # Begin Source File SOURCE=..\src\rnd.c # End Source File # Begin Source File SOURCE=..\src\role.c # End Source File # Begin Source File SOURCE=..\src\rumors.c # End Source File # Begin Source File SOURCE=..\src\save.c # End Source File # Begin Source File SOURCE=..\src\shk.c # End Source File # Begin Source File SOURCE=..\src\shknam.c # End Source File # Begin Source File SOURCE=..\src\sit.c # End Source File # Begin Source File SOURCE=..\src\sounds.c # End Source File # Begin Source File SOURCE=..\src\sp_lev.c # End Source File # Begin Source File SOURCE=..\src\spell.c # End Source File # Begin Source File SOURCE=..\src\steal.c # End Source File # Begin Source File SOURCE=..\src\steed.c # End Source File # Begin Source File SOURCE=..\src\teleport.c # End Source File # Begin Source File SOURCE=..\src\tile.c # End Source File # Begin Source File SOURCE=..\src\timeout.c # End Source File # Begin Source File SOURCE=..\src\topten.c # End Source File # Begin Source File SOURCE=..\src\track.c # End Source File # Begin Source File SOURCE=..\src\trap.c # End Source File # Begin Source File SOURCE=..\src\u_init.c # End Source File # Begin Source File SOURCE=..\src\uhitm.c # End Source File # Begin Source File SOURCE=..\src\vault.c # End Source File # Begin Source File SOURCE=..\src\version.c # End Source File # Begin Source File SOURCE=..\src\vision.c # End Source File # Begin Source File SOURCE=..\src\weapon.c # End Source File # Begin Source File SOURCE=..\src\were.c # End Source File # Begin Source File SOURCE=..\src\wield.c # End Source File # Begin Source File SOURCE=..\src\windows.c # End Source File # Begin Source File SOURCE=..\sys\winnt\winnt.c # End Source File # Begin Source File SOURCE=..\win\tty\wintty.c # End Source File # Begin Source File SOURCE=..\src\wizard.c # End Source File # Begin Source File SOURCE=..\src\worm.c # End Source File # Begin Source File SOURCE=..\src\worn.c # End Source File # Begin Source File SOURCE=..\src\write.c # End Source File # Begin Source File SOURCE=..\src\zap.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\align.h # End Source File # Begin Source File SOURCE=..\include\amiconf.h # End Source File # Begin Source File SOURCE=..\include\artifact.h # End Source File # Begin Source File SOURCE=..\include\artilist.h # End Source File # Begin Source File SOURCE=..\include\attrib.h # End Source File # Begin Source File SOURCE=..\include\beconf.h # End Source File # Begin Source File SOURCE=..\include\bitmfile.h # End Source File # Begin Source File SOURCE=..\include\color.h # End Source File # Begin Source File SOURCE=..\include\config.h # End Source File # Begin Source File SOURCE=..\include\config1.h # End Source File # Begin Source File SOURCE=..\include\coord.h # End Source File # Begin Source File SOURCE=..\include\decl.h # End Source File # Begin Source File SOURCE=..\include\def_os2.h # End Source File # Begin Source File SOURCE=..\include\dgn_file.h # End Source File # Begin Source File SOURCE=..\include\display.h # End Source File # Begin Source File SOURCE=..\include\dlb.h # End Source File # Begin Source File SOURCE=..\include\dungeon.h # End Source File # Begin Source File SOURCE=..\include\edog.h # End Source File # Begin Source File SOURCE=..\include\emin.h # End Source File # Begin Source File SOURCE=..\include\engrave.h # End Source File # Begin Source File SOURCE=..\include\epri.h # End Source File # Begin Source File SOURCE=..\include\eshk.h # End Source File # Begin Source File SOURCE=..\include\extern.h # End Source File # Begin Source File SOURCE=..\include\flag.h # End Source File # Begin Source File SOURCE=..\include\func_tab.h # End Source File # Begin Source File SOURCE=..\include\gem_rsc.h # End Source File # Begin Source File SOURCE=..\include\global.h # End Source File # Begin Source File SOURCE=..\include\hack.h # End Source File # Begin Source File SOURCE=..\include\lev.h # End Source File # Begin Source File SOURCE=..\include\load_img.h # End Source File # Begin Source File SOURCE=..\include\macconf.h # End Source File # Begin Source File SOURCE=..\include\macpopup.h # End Source File # Begin Source File SOURCE=..\include\mactty.h # End Source File # Begin Source File SOURCE=..\include\macwin.h # End Source File # Begin Source File SOURCE=..\include\mail.h # End Source File # Begin Source File SOURCE=..\include\mfndpos.h # End Source File # Begin Source File SOURCE=..\include\micro.h # End Source File # Begin Source File SOURCE=..\include\mkroom.h # End Source File # Begin Source File SOURCE=..\include\monattk.h # End Source File # Begin Source File SOURCE=..\include\mondata.h # End Source File # Begin Source File SOURCE=..\include\monflag.h # End Source File # Begin Source File SOURCE=..\include\monst.h # End Source File # Begin Source File SOURCE=..\include\monsym.h # End Source File # Begin Source File SOURCE=..\include\mttypriv.h # End Source File # Begin Source File SOURCE=..\include\nhlan.h # End Source File # Begin Source File SOURCE=..\include\ntconf.h # End Source File # Begin Source File SOURCE=..\include\obj.h # End Source File # Begin Source File SOURCE=..\include\objclass.h # End Source File # Begin Source File SOURCE=..\include\os2conf.h # End Source File # Begin Source File SOURCE=..\include\patchlevel.h # End Source File # Begin Source File SOURCE=..\include\pcconf.h # End Source File # Begin Source File SOURCE=..\include\permonst.h # End Source File # Begin Source File SOURCE=..\include\prop.h # End Source File # Begin Source File SOURCE=..\include\qt_clust.h # End Source File # Begin Source File SOURCE=..\include\qt_kde0.h # End Source File # Begin Source File SOURCE=..\include\qt_win.h # End Source File # Begin Source File SOURCE=..\include\qt_xpms.h # End Source File # Begin Source File SOURCE=..\include\qtext.h # End Source File # Begin Source File SOURCE=..\include\quest.h # End Source File # Begin Source File SOURCE=..\include\rect.h # End Source File # Begin Source File SOURCE=..\include\region.h # End Source File # Begin Source File SOURCE=..\include\rm.h # End Source File # Begin Source File SOURCE=..\include\skills.h # End Source File # Begin Source File SOURCE=..\include\sp_lev.h # End Source File # Begin Source File SOURCE=..\include\spell.h # End Source File # Begin Source File SOURCE=..\include\system.h # End Source File # Begin Source File SOURCE=..\include\tcap.h # End Source File # Begin Source File SOURCE=..\include\tile2x11.h # End Source File # Begin Source File SOURCE=..\include\timeout.h # End Source File # Begin Source File SOURCE=..\include\tosconf.h # End Source File # Begin Source File SOURCE=..\include\tradstdc.h # End Source File # Begin Source File SOURCE=..\include\trampoli.h # End Source File # Begin Source File SOURCE=..\include\trap.h # End Source File # Begin Source File SOURCE=..\include\unixconf.h # End Source File # Begin Source File SOURCE=..\include\vault.h # End Source File # Begin Source File SOURCE=..\include\vision.h # End Source File # Begin Source File SOURCE=..\include\vmsconf.h # End Source File # Begin Source File SOURCE=..\include\winami.h # End Source File # Begin Source File SOURCE=..\include\wingem.h # End Source File # Begin Source File SOURCE=..\include\winGnome.h # End Source File # Begin Source File SOURCE=..\include\winprocs.h # End Source File # Begin Source File SOURCE=..\include\wintty.h # End Source File # Begin Source File SOURCE=..\include\wintype.h # End Source File # Begin Source File SOURCE=..\include\winX.h # End Source File # Begin Source File SOURCE=..\include\xwindow.h # End Source File # Begin Source File SOURCE=..\include\xwindowp.h # End Source File # Begin Source File SOURCE=..\include\you.h # End Source File # Begin Source File SOURCE=..\include\youprop.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # Begin Source File SOURCE=..\win\win32\bitmap1.bmp # End Source File # Begin Source File SOURCE=..\win\win32\bitmap2.bmp # End Source File # Begin Source File SOURCE=..\win\win32\mnsel.bmp # End Source File # Begin Source File SOURCE=..\win\win32\mnunsel.bmp # End Source File # Begin Source File SOURCE=..\win\win32\NETHACK.ICO # End Source File # Begin Source File SOURCE=..\win\win32\small.ico # End Source File # Begin Source File SOURCE=..\win\win32\tiles.bmp # End Source File # Begin Source File SOURCE=..\win\win32\winhack.ico # End Source File # End Group # Begin Group "wnd" # PROP Default_Filter "" # Begin Source File SOURCE=..\win\win32\mhaskyn.c # End Source File # Begin Source File SOURCE=..\win\win32\mhaskyn.h # End Source File # Begin Source File SOURCE=..\win\win32\mhdlg.c # End Source File # Begin Source File SOURCE=..\win\win32\mhdlg.h # End Source File # Begin Source File SOURCE=..\win\win32\mhfont.c # End Source File # Begin Source File SOURCE=..\win\win32\mhfont.h # End Source File # Begin Source File SOURCE=..\win\win32\mhinput.c # End Source File # Begin Source File SOURCE=..\win\win32\mhinput.h # End Source File # Begin Source File SOURCE=..\win\win32\mhmain.c # End Source File # Begin Source File SOURCE=..\win\win32\mhmain.h # End Source File # Begin Source File SOURCE=..\win\win32\mhmap.c # End Source File # Begin Source File SOURCE=..\win\win32\mhmap.h # End Source File # Begin Source File SOURCE=..\win\win32\mhmenu.c # End Source File # Begin Source File SOURCE=..\win\win32\mhmenu.h # End Source File # Begin Source File SOURCE=..\win\win32\mhmsg.h # End Source File # Begin Source File SOURCE=..\win\win32\mhmsgwnd.c # End Source File # Begin Source File SOURCE=..\win\win32\mhmsgwnd.h # End Source File # Begin Source File SOURCE=..\win\win32\mhsplash.c # End Source File # Begin Source File SOURCE=..\win\win32\mhrip.c # End Source File # Begin Source File SOURCE=..\win\win32\mhsplash.h # End Source File # Begin Source File SOURCE=..\win\win32\mhrip.h # End Source File # Begin Source File SOURCE=..\win\win32\mhstatus.c # End Source File # Begin Source File SOURCE=..\win\win32\mhstatus.h # End Source File # Begin Source File SOURCE=..\win\win32\mhtext.c # End Source File # Begin Source File SOURCE=..\win\win32\mhtext.h # End Source File # Begin Source File SOURCE=..\win\win32\mswproc.c # End Source File # Begin Source File SOURCE=..\win\win32\resource.h # End Source File # Begin Source File SOURCE=..\win\win32\winhack.c # End Source File # Begin Source File SOURCE=..\win\win32\winhack.rc # End Source File # Begin Source File SOURCE=..\win\win32\winMS.h # End Source File # End Group # Begin Source File SOURCE=..\win\win32\ReadMe.txt # End Source File # End Target # End Project nethack-3.4.3/win/win32/petmark.uu0100644000000000000000000000056007764735042015431 0ustar rootrootbegin 600 petmark.bmp M0DWV`````````'8````H````$````!`````!``0``````(`````````````` M````````````;&Q'````_P```````("``(````"``(``@(```,#`P`#`W,`` M\,JF``0$!``("`@`#`P,`!$1$0`6%A8`'!P<```````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````````````$````` 5````$1````````$1$0```````!`0 ` end nethack-3.4.3/win/win32/recover.dsp0100644000000000000000000001266107764735152015577 0ustar rootroot# Microsoft Developer Studio Project File - Name="recover" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=recover - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "recover.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "recover.mak" CFG="recover - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "recover - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "recover - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "recover - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x1009 /d "NDEBUG" # ADD RSC /l 0x1009 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # Begin Special Build Tool OutDir=.\Release SOURCE="$(InputPath)" PostBuild_Cmds=copy $(OutDir)\recover.exe ..\binary \ if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt # End Special Build Tool !ELSEIF "$(CFG)" == "recover - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\include" /I "..\sys\winnt" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x1009 /d "_DEBUG" # ADD RSC /l 0x1009 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # Begin Special Build Tool OutDir=.\Debug SOURCE="$(InputPath)" PostBuild_Desc=install exe PostBuild_Cmds=copy $(OutDir)\recover.exe ..\binary \ if exist ..\doc\recover.txt copy ..\doc\recover.txt ..\binary\recover.txt # End Special Build Tool !ENDIF # Begin Target # Name "recover - Win32 Release" # Name "recover - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\util\recover.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\config.h # End Source File # Begin Source File SOURCE=..\include\config1.h # End Source File # Begin Source File SOURCE=..\include\coord.h # End Source File # Begin Source File SOURCE=..\include\global.h # End Source File # Begin Source File SOURCE=..\include\nhlan.h # End Source File # Begin Source File SOURCE=..\include\ntconf.h # End Source File # Begin Source File SOURCE=..\include\tradstdc.h # End Source File # Begin Source File SOURCE=..\sys\winnt\win32api.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/resource.h0100644000000000000000000001455507764735042015424 0ustar rootroot//{{NO_DEPENDENCIES}} // Microsoft Developer Studio generated include file. // Used by winhack.rc // #define IDC_MYICON 2 #define IDD_WINHACK_DIALOG 102 #define IDD_ABOUTBOX 103 #define IDS_APP_TITLE 103 #define IDM_ABOUT 104 #define IDM_EXIT 105 #define IDS_HELLO 106 #define IDI_NETHACKW 107 #define IDC_NETHACKW 109 #define IDS_APP_TITLE_SHORT 110 #define IDR_MAINFRAME 128 #define IDB_TILES 129 #define IDD_TEXT 130 #define IDD_NHTEXT 130 #define IDD_MENU 132 #define IDB_MENU_SEL 133 #define IDB_MENU_UNSEL 134 #define IDD_COMMANDS 136 #define IDD_GETLIN 138 #define IDD_EXTCMD 139 #define IDD_PLAYER_SELECTOR 141 #define IDB_PETMARK 143 #define IDB_MENU_SEL_COUNT 144 #define IDD_NHRIP 145 #define IDB_SPLASH 146 #define IDB_RIP 147 #define IDD_SPLASH 148 #define IDC_TEXT_VIEW 1000 #define IDC_TEXT_CONTROL 1000 #define IDC_CMD_MOVE_NW 1001 #define IDC_CMD_MOVE_N 1002 #define IDC_MENU_LIST 1003 #define IDC_CMD_MOVE_NE 1003 #define IDC_MENU_TEXT 1004 #define IDC_CMD_MOVE_W 1004 #define IDC_CMD_MOVE_SELF 1005 #define IDC_CMD_MOVE_E 1006 #define IDC_CMD_MOVE_SW 1007 #define IDC_CMD_MOVE_S 1008 #define IDC_CMD_MOVE_SE 1009 #define IDC_CMD_MOVE_UP 1010 #define IDC_CMD_MOVE_DOWN 1011 #define IDC_CMD_5 1012 #define IDC_CMD_A 1013 #define IDC_CMD_B 1014 #define IDC_CMD_C 1015 #define IDC_CMD_D 1016 #define IDC_CMD_E 1017 #define IDC_CMD_F 1018 #define IDC_CMD_G 1019 #define IDC_CMD_H 1020 #define IDC_CMD_I 1021 #define IDC_CMD_J 1022 #define IDC_CMD_K 1023 #define IDC_CMD_L 1024 #define IDC_CMD_M 1025 #define IDC_CMD_N 1026 #define IDC_CMD_O 1027 #define IDC_CMD_P 1028 #define IDC_CMD_Q 1029 #define IDC_CMD_R 1030 #define IDC_CMD_S 1031 #define IDC_CMD_T 1032 #define IDC_CMD_U 1033 #define IDC_CMD_V 1034 #define IDC_CMD_W 1035 #define IDC_CMD_X 1036 #define IDC_CMD_Y 1037 #define IDC_CMD_Z 1038 #define IDC_CMD_AA 1039 #define IDC_CMD_BB 1040 #define IDC_CMD_CC 1041 #define IDC_CMD_DD 1042 #define IDC_CMD_EE 1043 #define IDC_CMD_FF 1044 #define IDC_CMD_GG 1045 #define IDC_CMD_HH 1046 #define IDC_CMD_II 1047 #define IDC_CMD_JJ 1048 #define IDC_CMD_KK 1049 #define IDC_CMD_LL 1050 #define IDC_CMD_MM 1051 #define IDC_CMD_NN 1052 #define IDC_CMD_OO 1053 #define IDC_CMD_PP 1054 #define IDC_CMD_QQ 1055 #define IDC_CMD_RR 1056 #define IDC_CMD_SS 1057 #define IDC_CMD_TT 1058 #define IDC_CMD_UU 1059 #define IDC_CMD_VV 1060 #define IDC_CMD_WW 1061 #define IDC_CMD_XX 1062 #define IDC_CMD_YY 1063 #define IDC_CMD_ZZ 1064 #define IDC_CMD_FIRST 1100 #define IDC_CMD_LAST 1300 #define IDC_GETLIN_EDIT 1309 #define IDC_EXTCMD_LIST 1310 #define IDC_PLSEL_NAME 1314 #define IDC_PLSEL_ROLE_RANDOM 1315 #define IDC_PLSEL_RACE_RANDOM 1318 #define IDC_PLSEL_GENDER_RANDOM 1319 #define IDC_PLSEL_ALIGN_RANDOM 1320 #define IDC_PLSEL_ROLE_LIST 1323 #define IDC_PLSEL_RACE_LIST 1324 #define IDC_PLSEL_ALIGN_LIST 1325 #define IDC_PLSEL_GENDER_LIST 1326 #define IDC_ABOUT_VERSION 1327 #define IDC_ABOUT_COPYRIGHT 1328 #define IDC_EXTRAINFO 1331 #define IDM_SAVE 32771 #define IDM_HELP_LONG 32772 #define IDM_HELP_COMMANDS 32773 #define IDM_HELP_HISTORY 32774 #define IDM_HELP_INFO_CHAR 32775 #define IDM_HELP_INFO_KEY 32776 #define IDM_HELP_OPTIONS 32777 #define IDM_HELP_OPTIONS_LONG 32778 #define IDM_HELP_EXTCMD 32779 #define IDM_HELP_LICENSE 32780 #define IDM_HELP_PORTHELP 32781 #define IDM_MAP_TILES 32782 #define IDM_MAP_ASCII4X6 32783 #define IDM_MAP_ASCII6X8 32784 #define IDM_MAP_ASCII8X8 32785 #define IDM_MAP_ASCII16X8 32786 #define IDM_MAP_ASCII7X12 32787 #define IDM_MAP_ASCII8X12 32788 #define IDM_MAP_ASCII16X12 32789 #define IDM_MAP_ASCII12X16 32790 #define IDM_MAP_ASCII10X18 32791 #define IDM_MAP_FIT_TO_SCREEN 32792 #define IDM_NHMODE 32794 #define IDM_CLEARSETTINGS 32795 #define IDC_STATIC -1 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 145 #define _APS_NEXT_COMMAND_VALUE 32796 #define _APS_NEXT_CONTROL_VALUE 1332 #define _APS_NEXT_SYMED_VALUE 110 #endif #endif nethack-3.4.3/win/win32/rip.uu0100644000000000000000000033216407764735042014570 0ustar rootrootbegin 600 rip.bmp M0DVV/`$``````#8$```H````D`$``,@````!``@``````(`X`0`2"P``$@L` M```!`````0``+C8V`$9!00`Q+R\`(S4U``)'`P`*+A4`'C$P`"LI*0`1-2,` M&B(B`**FI@`X.CH`:W1U`!0:&0!X?G\`#1(2`!,G'P`*,Q8``3X#`!88&``! M.@,``C@$`!06%@!-1D8`)20D``H,#``,%14`145%`#=+2P`/,!\`#RX?`#\_ M/P`]/3T`%1L;``TN&@"#AX@`+2TM`"DI*0![?X``$R\G`#0Q,0!634T`#A@8 M`+&TM`"2F)@`(28E`(J0D``8'!P`?8*#`&1L;0`?("``8FP`)"GZ=`+"8 MJ``I1<8`559;`,"RM0!(7,@`#@\0`%EOO`!_E\\`5B@>`#4_0`!_;WX`04F- M`')P<@#5U-X`SVQ$`*FMKP"B/R<`?HF\`-?+S0#V_?X`XO+T`.#@YP#.VMT` MX^KK`+-9/`"BAYD`)T2E`$AM@@#___\`,4)F`,3$T@!C?<``+#-K````0``` M`(````"@````P````.````#_``!`````0$```$"```!`H```0,```$#@``!` M_P``@````(!```"`@```@*```(#```"`X```@/\``*````"@0```H(```*"@ M``"@P```H.```*#_``#`````P$```,"```#`H```P,```,#@``#`_P``X``` M`.!```#@@```X*```.#```#@X```X/\``/\```#_0```_X```/^@``#_P``` M_^```/__`$````!``$``0`"``$``H`!``,``0`#@`$``_P!`0```0$!``$!` M@`!`0*``0$#``$!`X`!`0/\`0(```$"`0`!`@(``0("@`$"`P`!`@.``0(#_ M`$"@``!`H$``0*"``$"@H`!`H,``0*#@`$"@_P!`P```0,!``$#`@`!`P*`` M0,#``$#`X`!`P/\`0.```$#@0`!`X(``0."@`$#@P`!`X.``0.#_`$#_``!` M_T``0/^``$#_H`!`_\``0/_@`$#__P"`````@`!``(``@`"``*``@`#``(`` MX`"``/\`@$```(!`0`"`0(``@$"@`(!`P`"`0.``@$#_`("```"`@$``@("` M`("`H`"`@,``@(#@`("`_P"`H```@*!``("@@`"`H*``@*#``("@X`"`H/\` M@,```(#`0`"`P(``@,"@`(#`P`"`P.``@,#_`(#@``"`X$``@."``(#@H`"` MX,``@.#@`(#@_P"`_P``@/]``(#_@`"`_Z``@/_``(#_X`"`__\`P````,`` M0`#``(``P`"@`,``P`#``.``P`#_`,!```#`0$``P$"``,!`H`#`0,``P$#@ M`,!`_P#`@```P(!``,"`@`#`@*``P(#``,"`X`#`@/\`P*```,"@0`#`H(`` MP*"@`,"@P`#`H.``P*#_`,#```#`P$``P,"``,#`H`#`P,``P,#@`,#`_P#` MX```P.!``,#@@`#`X*``P.#``,#@X`#`X/\`P/\``,#_0`#`_X``P/^@```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````(:(0`````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````&`X)```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````)`DA*Q8````6"1`````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```0"AHN"0``$"$*"0`````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````!@*#P\)`!8* M#Q4)```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````DH```````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````$!T/#P,)"2(S+@D````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````6"AH)```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````D&`D"'P\/+`H""@\:"0`````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````D/(@D````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````!`*(AL*%1L/+A$=&P\H```````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````"1H;"0()```````````````````````````````````````````````` M````````````````````````````````````````````````````&"(L#PH# M&QL:#@H5%0(````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````A(ALK+A\) M```````````````````````````````````````````````````````````` M```````````````````````````````````````0'AH/'@H5#QLB%2(;#A`8 M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````"1L;#P\/&Q8````````````` M```````````````````````````````````````````````````````````` M`````````````````````````!@."B(*"A,<'!T;&P\/'A`````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````)#RP;-BPB(1@````````````````````````` M```````````````````````````````````````````````````````````` M````````````%!T*'1,3!@4"!@H:&S85&``````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````DB#QLL#P\;"0`````````````````````````````````````` M```````````````````````````````````````````````````````````8 M'@HA$0<&`CD""@HF%0HG```````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````"1L/ M&PH5+#4G```````````````````````````````````````````````````` M`````````````````````````````````````````````!8*+A$"*@8<$0($ M!@8.$Q4)```````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````"+AHF$QL/&@X)```` M```````````````````````````````````````````````````````````` M````````````````````````````````$`H*(0(<#A,.!`<%.08."@X)```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````DP$P8"%1LF#S`H```````````````` M```````````````````````````````````````````````````````````` M```````````````````0'A41!`83'`8"!@X<$1P<%0H6```````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````@HJ`BH<(QP<$PH)```````````````````````````` M```````````````````````````````````````````````````````````` M`````!8.)0<%!`8@!@0&*AP@!!<5"A8````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```)"B,<`@8&!@(.%0D````````````````````````````````````````` M```````````````````````````````````````````````````D`@($!0T& M!@82!1$C(Q<2!B4=&``````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````!`3(P8@(Q,< M!`8<)Q@````````````````````````````````````````````````````` M`````````````````````````````````````"@*$P("!`@2(Q,$!B`@&1D7 M$QP````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````%AP&$@8<(!(7!`8*"A`````` M```````````````````````````````````````````````````````````` M````````````````````````)PH M'PX)````````````````````````````````%AX?%2"@(6```````````````````` M````````````````````````````(1L"%@P,#0@+"!D9$AD+%P0,!`(0```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````%@X3!@@+%QD9&1D%"`@"#!`-'!4*"0D) M)```````````"1H/`Q`4"2$.$1@````````````````````````````````` M```````````````)'0X'!PT$"!<+&1D+"Q(+"P@$*A8````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````%`DJ'`8%"QD2&0L+!`@%!P<-`@T"'1X)```````````4 M*QX""18)$!@)"1`````````````````````````````````````````````` M`!@)*Q,"#`@(!`4("`L+%PL("`(<"0`````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````)`D*"AP$"Q<9&1D("P(-"`4'#`("!A$6`````````!`A#@('!P(4&!8* M"A8```````````````````````````````````````````````D5%0(,#0@( M"`L2%Q(+(`@$!A,)```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````%AX*!@8@ M$AD7&0L2"`0%!`T,#`P-`@()`````````"@"!P81`A80`@H;(20````````` M````````````````````````````````````&`H;#@<,#`8(!@L("PL+"P@" M'0D````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````&!@)"B8J!A(+"Q<(%P8+ M"`<%#`0%$Q,6````````(0X"$0X1`@("$1,*"0`````````````````````` M````````````````````````%B$*!@P(#`@%"!(%"P8(!"HF"0`````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````!0)*`DE%1(+$@@+$@L7"P0&"`(.!B0` M`````!8)$0(1`@("$0(1*AX)```````````````````````````````````` M````````````%`D"#0((!0<&!1(+"P4$!@D8```````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````$!,>(`07"R`+"QD2"PL(!08\&````````"@A!A$A M!P(1$1$"'"$)```````````````````````````````````````````````` M%A$&!PT'!!$&"!(+!@8"%@`````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````4(1$&!`L$"Q<+&1<+!@0,!`D4```````8`AP"`@8"!A$"#00&%148 M```````````````````````````````````````````````8'@H"#`4$!B`7 M"PL&(PXD```````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````!@*%0X% M#`@+"Q(9&1D+!00&`A8``````!0"`@(<`@("`@<"#1P;&Q`````````````` M``````````````````````````````````D:(@('`@83(Q<+!@@E)18````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````8"2$))``````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````4(145`@<,#00+&0L9(`@% M"!,<%```````%`(&`@("!0("!`P"!@H*(10````````````````````````` M````````````````````"0\/`@D-!B4C(`L(%Q4*$``````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````$`(?&S`)$!`````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````6%A`0"2$5$P8%#`T(!0L($AD+!@0%"AT8```````8 M`@8$#00-#`4"#`(-!B8*(1@4```````````````````````````````````` M```````)&P\"!P(1(R`2%P@$&Q46```````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````````"03 M"B,3!A$*"A8````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````!`*#Q45"AP"#`((!PP$"Q<+"P8(`@05'A```````!0J'`("#`P)!PP) M#`P'`A$*"A```````````````````````````````````````````!8/&@(" M"0(<"R`+!`85&@D````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````D`@HC&0L$(Q4F"0D" M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````8"0<6"14:&Q4> M!@P,"`@%"`@7!`4(!`8$`A4*$```````)`X3#0P6#`P,#0P,%!0,!Q45(18` M````````````````````````````````````````&!H5`@<"$082"P@(!1L* M"0`````````````````````````````````````````````````````````` M````````````%`DA`@D6%A08$`D8$"<6%``````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````"<*(R`@&1<+!@83&@HA)``````````` M```````````````````````````````````````````````````````````` M````````````````````````````$`D6``D*"A,A!B$&`@8-`@0(`@@$%P0+ M"!<"$08"%1\)%@D0&!`)&B("#`P0#!00#`T,#`P,`AP=(1`8```````````` M```````````````````````````0$R8"!0@$!@8+!0@",!X6```````````` M````````````````````````````````````````````````````````%@D" M'2X*#AX.(1$"$Q,K"@H)&!88```````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````"0H2&1D9$@L$!08<'A4G```````````````````````` M```````````````````````````````````````````````````````````` M`````````````!@*&AX1!A,<'!$"!PT,!`@(!0@("!<("P42"`0"!@(>)@H> M)1T>(AHS&PX'#`P-#`T,$!8'%A0,"1P5"A`````````````````````````` M```````````````A!@4,"!<&!A(2"P0E$Q`````````````````````````` M`````````````````````````````````````````!`*(AX3'`XJ(1P.$0X1 M'`X3*Q,5"A`````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```))B,2(!<2"P4$#0(3%0D````````````````````````````````````` M```````````````````````````````````````````````````````````8 M$14;,!P"$0(A$08"!PT"#`@($@4(!`L$"P@&!@('#`83"C`*%14*&@\5(10' M"10,$!0,#!0,#0<,!@\*$``````````````````````````````````````8 M"0(%!P4("`0&(`0+`AXI&``````````````````````````````````````` M````````````````````````&`D)$0H;$P(,`@<"!A$&`A$H$0X1$P\N%@`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````8``D>'BH<(08& M!P<-"`83`A8````````````````````````````````````````````````` M`````````!08&````!00"1```````````````````!08$"@*$P8.$1$.$0(" M`A$�@-!@@7"`07"`4+"`4<`@T'!P4&!@8&`@8&`@('`@P-!P<-#!86!PD0 M%`<)'!,)%`````````````````````````````````````(>`A8,!P@$(!P" M#`T''"H4```````````````````````````````````````````````````` M```````4%@DH"@H3$2H""`0"!`@"`@<"`@81`@(.'A,)%``````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````"1X)%BD3#@("$1,)&!`$!`8=#A0` M````````````````````````````````````````````````````````"1X< M`A`4"0(*"A8`````````````````"0H=#@8&`@(.#A$"`A$"`@("!`0("`@( M"P@2"P8+!`8"!PT$!`(%!P0%`@@-!`($`@("`@("`A$"`B@"!PT-$0,)```` M````````````````````````````````%@X&#`P(#0@"`@T'#`<"`A0````` M`````````````````````````````````````````````````````!`#%1X. M!AP&!P<"#0($!00,#`P'`AT*'BL&$PH)```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````)`D."@()$QX=$0D)#A88%`T%`B8*$1@````````````` M````````````````````````````````````````&`DA"A,""0T'!AL5`A@` M````````````)`D3"B8<#0(&$1$1(0<"`@(&`@0"#00+!@L&"P4+"P0"`@4' M`@4"`@4"`@('`@4"!@T&!A$&$08"$0X1$0()`@DA%0X)%``````````````` M````````````````%`D1$0T,"`<(#`('`@P,#`T'"1@````````````````` M```````````````````````````````````````D(14/$P8"!PT"!00(!`@( M#0P0"0D"*QX=#@<.'@D````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`!@""B(;(0D.`QX)"0D)$`$8#`0%`BH=$1`4```````````````````````` M```````````````````````4%A@"$QX1#0P'"0()`@X*$184`````````!0) M"A43!@8"'"$1#A$1`@<&`@8$`@4$%P@+"Q(+"P@+"`4$`@P-!P4$!`(&`@8" M`@(1`@<"`A$A'!$.$0X1#A$.$0XK%1X)$!80)``````````````````````` M```0'Q4"%@<-"`P"!P(("`T'#!$*$0`````````````````````````````` M`````````````````````!@0%@(='`8&!P0%#`0%"P@%#08$`@(6$0(6$!@8 M%!06```````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````*`H>"@\N`Q$. M`@D)*!0!&!0D%@<%/!,5"A`````````````````````````````````````` M`````````!`*%1P1`@P,$`<-"0T'!P85"A@`````````)PHE$P8-!!$<$1$" M`@T"#0($!04(!P4$"Q(%"P42"P8(!`@""`T$#0(%!P4"`@(&`@4"!@(&$0X1 M(1$1(1$1#@X1#A$.*R$3)@H)``````````````````````````DN%0<,"`P, M"`T("`4$"P@-!@HG```````````````````````````````````````````` M````````"0H.$08$!P(-"`@'"`@$!0<((!4;`PDK$Q@````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````"&BL."AHB`A`)`B@)&!80)!@0 M"0($$1H;"0`````````````````````````````````````````````D(2(: M#@P,#`D,#0P'"1`,`@H5`A@````````"+BH"!`81$0X.#@('`@0'`@(%$@8% M$@4&"P@+"R`+"P@&"`@'!P4$!0((`@@%!@(&!P0"!!$A$1$.$0X1#@X1$0(. M#B@1'"85%2$)"1@`````````````````````&!,=`@P,#`((!`4+$A<("P@& M%0(`````````````````````````````````````````````````"0DA%1X& M`@4""`0(!@L%"`@-$`8E'Q4>#@H*%@`````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````DB$R$1#@X0`10)"0D0)`$8)`$0`@("'A,)&``` M````````````````````````````````````````%A$5*P('#10)#`P)$`T0 M#10'!RH>(1``````$`D&!@<"#APA$1$1!P((`@T'!`0(!00&$@4+"Q(+"!<( M"PL(`@T,!P($!`(%!`<"!P(&!P8%`@<1(1$A#A$1$0X1$Q$1$2$1#@(&$QX= M"18D$````````````````!00`A$,#0<4#`P,"PL9"QD$""H*"0`````````` M`````````````````````````````````!@0%@D>$Q$&!@4'"`0%"`8("P8' M%A0-'B8)%B@=&QX8```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````*!43*Q4.`A@!$`X8$!@4`10D%A0)!PT"'!4)```````````````` M`````````````````````````!8*"AP-$`D"`@<)%`P,$!0'"0P'"`X>`Q8` M`"03'@("!!$1$0X1#@8"!0<"`@0%"P@+!!<+"!(9%PL2"P0%!`4'#`<(!04" M#00"!04$!0(%!`($!P8"`A$1(0X.$1$"`A$"$0(<#@(&!A,"$0,)```````` M````````"1X.#`<0#`D,!P42&1<9%PL&!@D6```````````````````````` M````````````````````"0HK'"H"!0<&"`4,!1(+"P4("`P8`1`*%0D`&`D) M"20````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````````````D."BD3 M(A$4$`$)(0D4&!@0&!8D&`('"0<&"@(````````````````````````````` M``````````D)`A\5`@D,#0D0"0T'"10-%`T4#10,!R8P*!04*!,*!@<"`A$. M$0X1`@0"!04'"`@%$@8%$@47$A<9"P8+"`L("`P'!08$`@0(`@4$`@<"!`@$ M!0<%`@0"`A$1#A$.`A$A`@()$0X1$0('!0(3"B$)"0`````````````H&@(, M%A06#`P,#`L9"QD+!B4.%@`````````````````````````````````````` M)`D)"0D1"B4*@<,%`<,"0P-"`8+ M(!(&%1T8````````````````````````````````````&!8)"AL*'"H&`@4" M"`0-"`@+!`L7"PL%(!P")!`)"BX0```````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````D/#QX.'1X.$0D1(0()%B0)"188%!@D%!0" M`@8*'A8``````````````````````````````!@='@(1(0()$0D)`A80%!`) M#1`)"0P,#!8,#0P,!P(<$Q,""0("$1$1#@X1`@0%!`4(!1<(%P47!1D7!!D+ M$@42!1((!P4$!`($#00"!0T$`@(%!`0%!`(%!@0"`A$.'"$"`A$"`@("`@D1 M$081#@X'!08.#A,*'1``````"0H3$Q$0#`P-!PP,#`0,"`8E$P()`A@````` M``````````````````````````````D*&AX.!BH&`@4$#00%"`P2%PL9"Q(( M!`(P&PH.`@(""0`````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````8$1\5$PX.#@XA*`X.*!`)$`())"0!`1@!"0T$`A4*%@`````` M````````````````"100$!00"28*`A`)"0(""0()$!8-"0(1"0<-"106!Q80 M#`<-!"H3$0T'*!$A`@X1(0("!0<%!0<$"!(7!`02"PL&"P4+"P@+!`4$"`4% M#00"!00$"`(%!`8%`@0'!`0&!@(&$081$0X&(0("`@("`@D"`B$1`@("#A$A M$14N(1`6)PDA%0H<#0P-!PT,#0P,#`4''!,K%@`````````````````````` M````````$`DH"1`)"0H5$P0'#`0-!`<("`8""Q<+$@L+"`4,`ALQ&R$H#A@` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````&`(* M$0D)*`(A$1$A'AX)`@D8$!`6`18!%`$0!P('*@X)%``````````)$`D)"1@) M$`(**@(&`@81`@8)!P()$0(,%`T)`@X3"B83`@T'#0P,#`<-#`P-!P4)%`D" M$1$1`@('`@0$!0@$#00%$@L+&0L9"PL+$@L%$A<(!0@'!`0$!0@$!0@"!PT" M!`0%`@4"!@(&$0(J`A$"`A$1`@<-$0("!P("`@D"/`(1`A$.#A,*"2@5"A,. M#0('`@P'"`<(!PT,!!,F(1@4```````````````````````4$!8)$!8)"AL* M$QP"!B$&`@4"!00%%P42"P@2"QD+&00,"1`"%0HH&"@="0`````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````!8>"B$4&!06)!86"0DH M"10)$`$6)!@0&"06`1@-`@T'`@H)````````"1HB&AH/#QHB%1X1!@0"!`8$ M!PP"`@()"0<0`@H"$`DH(0H"$`T'!Q8,#0<,!P@-#`D-!PD-!P(,#0<%!04+ M!!<(!@L+%P07&1<2%PL%"PL+!`@$!`4%`@4'!00%`@4%"`@%!@@'`@8'`@0" M!`0"`@("$0X1`A$"`@<'`@()!PD"`A$1`B$1$2L1(1$.`@<"#`@""`4,!0P- M#`(5%0X4`````````````````````````!@*(A\*'0XJ*@8&!@((!`8(!`4( M!1($"PL7&0L7$@L(#`P0%`D""10`&`DD```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````4$14*`B04%!@4)!@0%A@D&!@6)`$4`0$4 M`204&`<-!PT&%0(````````)"@\/,C(S-C,;,!,.!@0%!@0%"00"*!`-`@8= M"@D````"+B$'"0P-#!`,#`T,!Q`,#`<'`@T"#`@""`<"!!<+"`4$%Q(+"PL9 M"PL2"PL2!0@%"PL7!`@$#00%!`0'!`<&!`4$`@4&`@8'!0('!A$'`@('!@(" M(1$"#0T"'`<-!PD'`@(H$1$"`A$1#0P'#`(-`@@(`@@'#`<-*@H*&``````` M````````````&`()`@D)"1\;%1X3$P<'`@0-!`(%"`8(!!<$!!<2&0L2&1D+ M$@T0"186`A`````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````)"$*)1P%!P("!PT6#!`)$!0D&"04&!`!&`$8%!@D#`T'!P(3 M`A@``````!88"1$B-"P/%28;&Q4@'"`$!0<,#0<"`A$.%0H"``````D*#@P, M`@('#0T'!PT,#0P-`@4'"`<"`@<-`@T'!P0+!`4+"Q<2"Q<+%QD7$@L+$@@& M"`0-!@0%!`4%`@4(#04(`@@$!A(&!@(&!`4"!@(&!@4"`@81!@($$1P"`@(" M`@D"!PT""0<"#0('"`(%!P8'`@<'"`T(!P(>$1`````````8"180&!`4%!`) M"AH>$PX<(1P"!0(&!P(%!08+!`82!0L+"Q(2$AD9&1D9$@8@$0(0!PD3"0`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````````!`3 M'AP&`@(%"`4$`@0-`@P-&!`4&!0D`184)!`D)!84"0(-!Q$5"A8````````` M%@X/,S4E(",5&R`2'`0%!P@-!!,N'P()"0``````&`(3#@T'#0<'%`T4$!0' M#1`4#`("!04%!`($#0T(!0P$"P8+"PL9&1(9"Q(7"`8+"PL$%P0%$@L&!`0" M`@4$!`0"!04%`@0"!@X&!@<&`@0$`@($`AP"*@(.$R$"!`(-!PP,!P<-!P(, M!`4$"`@"`@((!0@"!`T.$R$8````````"14B&PH>'0X.(0(<$RH&!@0&`@<$ M!P(%!`0$`@@%!00C(`L@&2`2&1D9&0L%!!,;&AT)(1LG```````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````&`DG"1XP$08$!`($`@0- M!`($`@<6#!06`18D)`$8%!@8`1`,`@<"#2(5"0``````````&!T/&Q4C(R8F M$A(@'`8�<-#@H*%@``````````&!T>`@<""186$!@4&!80#0D-!P0"!P($ M#00-!`<'#0@("PL+$@L+%QD7"PL$"PL2!0@&!0@+!@L%!0<%!`@%#00"!`0% M!`8)1,<'`8E'QT0%``4 M%A@````````````6*R8""180%!`4$!84$`P(!PD4%@P,`@@%`@0(#0P(!P4$ M$A<9&2`9$@L2"Q<+!0L$"`@&$@42!`8-!`T$!00'!00%!@@"!@X"!A$"!@0& M"`4&"!<$`@81'`X&!A$&`@<-!PT'#0<%"`0("PL&`@(&!`((!0T$$PH>'BL3 M#AX.`@8.!@X1'`8%!@(%`@@$`@0"!`0"#00&$@42!@82%PL9(R,@&1D@&1D+ M"`@-"0T&`A@6)!08%``````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````"0HF$R41`@8-!`('!0T"!P<-`@4"!0($#00-"10!)!06)!@0 M#1`"!`T&`A0``````````````!@)*`(0(14;%0(""0`````````````````` M```)"0(0%A`-!P("!P<%`@(%#0<8)`T,`@0,"`8%!P4%!`4("Q(9&0L9%PL( M$@L2"Q(%"PL+"`@%!`@%!`4'#0@&"!(%!`8@'`8&!@(&!@4$`A(%!`8(!@(& M`@8$!`(-!`T'#0<"#00(%P@%"P4$`@<%#0($!P(.$PXJ`@8A'`("!`4"!0(" M`@0-!P4$!00%!`4(!00(!1P7!`@2!B`9&1(E(R,9&1D2"P(-!PD'"1$)```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````````````````````````````````````````````````````````D. M)B4@!B`&`@(""`((!`0"!0('!`<(!0<%`@0,&"04&`$4`0T0#0<"#`("*!0` M```````````````````)"AH*%@`````````````````````D"0D0"0<4!PT( M!00&!`T$#0<'`A08%`<(`@4""`0'"`4$"`(2"Q<2&1<+"PL7"Q<("`L&"P8+ M!@(%!@4%!`T$!00+!0($'`8&$0("!`82!`(%"`0+!00$!@($!P4%`@($#0<" M`@T$!0@%$@L$!`(&`@0'"`(%`@(1$00%!P(1'`8"!P@"!P4"!0(%!`8(`@(" M!`8$!08&!@0($B`<&1D@$B,E("`9"PL%!PP)#0P"$PD````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````0"AL&!AP@$A("!@T$ M!0@&"PL$!@("!@('`@4"`@T"$!8D$!@D%`D'"0P"!P8>"0`````````````` M`````!@0"1@0```````````````8&!`6&`D*#A$-#`(-!`($#0("!0P$`@@- M!`T4"0(%!P@"#`4'!`(%`@8%!@07$A(7$@L+$@8+!1(+!`4$"`0+$A(%!`@& M!`4$"`8&'`X"'`8&!@8%"`0%!@@2!0@$!0(%!`($`@8"`@(1!@8"!`@($@8& M!00%!P("#`<(`@(&`@<"!0("#0($!0($!00$`@0""`8$!00%!`L+"Q(@%Q(+ M(R`@&1D2("`@"QD+!081`@<"#`X*`@`````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````!`="@(%!A(&"`4$`@P'"`L9&2`&`A$" M!P4(!P4'!00,#10!%`$)#`P,#0<,`A,)```````````````````````````` M`````````````!`*(AX1!`8&!`((!`("`@("!0($`@4-!`((!PT4%`<"!0@" M!00%"`0&`@81!@8+$AD(!@L("PL2"!<(!`4%!@L%!@4""`@(`@0%(!$A$08< M*CD"!@0+!`4$#`8(!0($!@L$!0@"`@<"$2$&'`8&$@(&`CD"!`(&!0T'`@4$ M`@('!0@$!00%!`4-!`<%!P8%"!(%!`@%!AP7%P87!@8+%Q(@(R`9&1D2%Q(+ M!`4$*AH/%1,"!PD8```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````$!,3`@0(#`P""`0("`4$!0L7"P81!@($`@<-!00"`@($ M"18D%@P'`@T'#0P"*A``````````````````````````````````````$`D" M*`H;,"H""`<"!`T"!0(&$1$$!`T(`@0$!00%!Q80#00(!@@'!`T$!@4$(1$. M'`87$A<+"P87$@4+!`4+$@0($@0$!00&!@0%!002!AP"!B$#A8````` M````````````````````````"0H*$R$&!@($!0("!A$&`@<&`@8-!00&`@<$ M!0(%!`0%!`4-#`D-!`8$`@@"!`T%!00"!@X1!@(+&1(7&0L2"`L+$@07"`8$ M!`4&"`8+!`4$"`4&!"`&!@87$@8&!@4&"P4$"PL&!@@"!@8'!@02"Q<2"P02 M$@4&!00&`@0-!0P"!00"!`((`@0&!04$!04&!`4$"!<$PX< M`@(&`@("`@0"!@0"`@8"!00$`@P(`@0"!`8""`T%!`<%!@@0%@<1`@@%!`4+ M!00%#08A$087$@0+$A<+"PL2$@L2!@@%$@42"`8+(`L$!A<&$RH)``````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````8%@(E(!(+"Q(9&1<+"PL&!`0(!`4(`@@$!0($!P<$#`P'#0<$#0<- M!PP'#0P'%@<-!PT,!PT'#0<-#0<'`@T"`@T$`@T"!`4'`@4$#00%`@4"!`4% M!`<"!`4$!@@(!00$!`<$"`@""`((`@<"#0<,#`((!PT1)AL;'`@(!P4$$@4( M!08(!`4-!P($!1(%"`0&$0X<#@X1$0X"`@(%!`4%!`L%!A$3'!,&%P0%!1(+ M!@0$"`L("`(%!P4'!`@(!`@+!0L&"R`2"`L2"PL&"PL7$@L+"Q(+"Q(+$AD7 M"Q<$!`(-`@("!`8$$Q,0%A`6$!8````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````&`<@ M(!(7"Q<2&1(+!`@+!1(%$@0(`@0(!`T%!04"`@@-#0('`@@,%@P'#`T'#`P' M#0<,`@P6#`P'%`(,#`T$#`P%!P<-!`T(`@<"!`4"!`4&"`(%!@@%!P0%"`8$ M!0T$!04%!`4$!0('!@T'%A`4%`D1'1L/%24%#0(,#04("`<(#`T-!P0%`@@% M!`("`@X1#A$1$2$.'`8%$@@(%P0(!083$RLZ#AP&`@07!@8"!@('!0<$#0P" M!`4%!`4(!00+!!<$"`L%$@4+"PL+$@L2%QD7"Q<+"Q<@!B`&"P0"#0<'`A,@ M!@8:+@D````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````!PC(`L9&0L9"Q<+ M"P@$"P@(!@4(!@4"!`("!`(%!`<'#0('`@P,!PT'#`P)#`P,#`<,!PP'#0P- M#`T'`@P-!P<(#0((!P0$!04"!`4$#00"!`0%!`(%!0($!0@$!08&$@L$!0P% M!PT0!Q04`0D6#1T5#QLF!@@'"`<,!`@%"`T,#`0-!P4$`@('!@(1#A$1#@X1 M(1$A!`@(!1(&"P4&!#H<'!,3$08"!@('$1P1!@("#04"!`4(!`@%!!(+!!<( M%P@7"!(+"PL@"PL7"Q<2"Q(+$AD2!!P&#@0"#`4$#1`"'@XA'!4*$``````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````0'14C"PL7"Q(+"PL@"P4+!1(+"`0( M`@0-!00$!04""`T$!PT$`@(,#`T-#`P,!P(,%@P"#`P,!PP$#`T,#`(,#`(( M"`(-!0('!`@"!`($!04%"`<-!`0$!`@"!`4$!`8(!@4$"`0""106$!80!Q`1 M(Q45*@4("`4,#0@-!`@%"`<"!`(%`@0"!A$1`B$"#@X"$0X1'`(%"`0""`@& M!`4"`@X.$1$"#@("`@8"#@(1`@0(!`@(!`@%!`0("`87$@L2""`+%PL7$@L+ M$@L@"PL7"Q(7"P47`CD'`@("`@("#2$5`@(>(188```````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````!@"#A42"!(9%QD2&0L+!`@+"`8%!`4("`<"!0((!A($ M"P8%!PT,#`T'!PP'!PT,#`@'#`P,`@@-#`T,#`(,#`<(#`<""`0'"`(%#00% M!0<%!P0%!@4%!@47!@@&"`("!0('"`T,$!0!%"0)"0(*%1P&!B`$!P@,#`<, M!P@-"`<-#`@-!`0"$1$.`@(&/`(1`@X<(0("`@0"#`4"!0($`@4$$0(H#@X1 M`@8"(3H<$PX&(`8%%P8+!@L"#`L%!`L%"P0+"PL2"PL+!A<2"PL+"Q(@!@8& M!`<""0T.'283(08'`B@D&`D````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````))B4@"PL2%PL7&1<+$@4$!00(`@<"#0@$%Q(+"Q<+!`@"!`('`@T4 M#`T,#`<-#`T"#`<,#`<,!PT'#`<-#`0-"`T$`@4(`@0$!00""`0%!`((!`0( M!`0(!`4,#00'!PP4$!8!&!8)`A$.$145'`($#`T(!P4'"`@-"`0(`@P'#`(& M`@8A$0X1`@(%`@(1$1$1`@(%!P4$`@4$`@4-!`(&!@X1.A,<'`8<$SHK'!P$ M$@0$"`0%"`@(!!(+"!(7"R`7%PL2!1(7"PL7"Q(7"QP&.00%#0<'`@H5"@X. M`@XJ%@`````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````!@)'14& M%P@($@L$$A<+%PL2#00%"`@,`@@$%R`2("`@%Q(%!0<%#`<"$`P,#`P'#`@, M#0T,!0P(#`P-#`@"#`T'!0<%!P((!0T&"`8(`@8("`4"#0<%"`4$#0<"#`T4 M%!80"1`"#AX5%14F(P($"`@(#`<,#`@-#`<(#04(#`4'`@(1#A$1`A$$`@4% M!`8"!@8"!0((`@0(!@@7!!<$"PL&(R43'B4F)1X3$QP3$P8<%PL7!`4$!@@7 M"`07!`@2$@82%PL+"QD+$A<+"Q("!P(-`@("!0("%0HA$!0)'@H8```````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````"00$Q4&"P@7"Q<("`@2 M"`4%!`4%`@<%$A<$"R`5&B8<$0()#`<)#`T,#0(,#0P,`@P4!PP,#0<-!PP' M#`P,!P@,!`4$`@4$!`@-!`4($@8(`@<$`@4'!PP,#`T0%!0D`0<.'1L/&P\; M)@8%"`0,#0<,#0P%#`P,"`4'"`<$#0P"(1$.'`X.'`4+"`82!!((!!<2!1(7 M$@L+"Q(+"`L+"PL7(",E$R8P)1P>$RL<(P87!`8("P@7!`L7$A<+"!<$%PL+ M"Q(+%Q!@T,#0<("`4-"0<'#`@-#`@(#0@' M`@P-`A$)"0<"!P8+%PL+$@L9"PL9"PL+$@L+!0L7$@L+&0L+&1D9!@8C'",1 M.AP3(`87!@0%!`@(!0L+"R`+%PL+(`L&!`L%"`4'#0<-"0D'!P(J"0(P)A,3 M$``````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``````D;+",7"`L+%PL$"`8(!A("!00%!08<)AL5)B`"!`("*!`4!PP'"`44 M!PP'#0T6!PT,`@T,`@T4#`<'#`<%#00(!`((#`4-`@4(!!<%!`4(!`P%!Q80 M"0<)$"<:#Q4;/28E!@T'$!08%`T$!PP'%@T'#`P'#0(,`@@-!`<'#`<,!PP, M#`0("`4+%Q(7&2`+&0L9"QD2$@L$"Q<2"PL@%R`@("`7$@8@(!(%!`0&(`<- M!`42%Q(%"Q(+$A<+"`0-!`(,`A8)!P(,!PP-`@X0)`D)"0D4```````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````&!T*!@8$ M!@L2!0@("P0+!0@"!`('!"45&R8C(`('`A$)%A86#`("!PT0#0(,!PT,!P(( M!P('#`<"#0@"!P($`@<%#`@$`@0'"P@%!`8%!`4("`P,%@P)#`D4"2(Q#B4E M'`8(!Q8,"100"`4(`@<)!PP,#0@'"`P-!`T"#`T-#`P-"1`-#`4,"`07"!(( M"Q(7$@L2%PL+%Q(%"P8(%R`2(R,@$@L$%Q(&!A(%%P8$!0T("`L+"PL$%P07 M"`@&!@<)#`('!PP-'`X&`@<&'0D````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````"2$"("`+"QD+"P0%"`@& M!`4&!@0"'@H;)B4C`@8&$0(8!Q`"!`0-$`D"`@('`@('#0('!@4"`@T'`@(, M`@<%`@($#0(1!@8%$@@+"`0%"`@-!Q0'`@<-!`D"&P\A`@0%!`($!`4'%@P, M!@0-`@8$`@<,!PP-!`('"`((!PP0#0P,#`P'"`<-"`@,"`4("`@(!0L(!`@% M"P0(!0@&(Q,3'"`%"Q(+"PL$%P0$!@0%!`8$%PL$%P@%!@8$"`<)#`<-!PT- M%`(5&@H3!A,5"0`````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````!8*"@8%`@L9&00%"`0%$@@%"`<'#0()#B8; M+@8&!B`"`A8-#00-`@P)!P0"`@T)`@<)`@(1`@T"$00"!P<%`@("!@4$!@8& M$@0%"`8&"`@,!`P,%@P"!`('`A$:#R@$%P8&$@8"`@<'`@0,`@8"!P()"0D, M"`((!04$#0@-%!8'#`(,!P@(#`@%!P4,!P@"!PP(#`(("`<,!0('`@@&'"`@ M!@L$!0L@(`4(!00(!`("!@L&$A<$!0<'"`T)#`<-"18'`@('`A\3*"@5"@(8 M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````&!4:!@P,"!D+"P0""`@%"!(%#`4'!Q8"$QL5!QP<.1$)$`0- M!Q8,"0T"#1$)!P<"#0D'`@("`@("`@("`@0"'`8"!`($PH*(0`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````8)A4C"R`+!@@$!`@9$A<(!0P$!@L9"Q<(!`4,!PT) M#`P'`@4'#`(,!PT)#`T$#0(,!P(-"0P)#0<"#0<-`@(,!P<)#0T'#0(,"104 M$!`0#`($`@<(!P(<&S0R-AL"$!0)%!@D$!`!#0D6%`T4$!@4%A0)%`P,#`0% M!P0,!P<)$!0)%!`-$!06#!0)#`P6%!0,"100%`T'#0P)"0<'#0@,!PP"#`D4 M%A`0$!0)!PD0#`<"!Q0-%34;'1,"`@8#"0$D`2$*(1$5"0`````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````!@)#A,2"PL+!0T%"`L9$@@"!0@(""`9&1((!PT'#0<-!PT$!PT'#0P6 M$!0,$!`"`A80#1`6%"04%A`,%A`0%`T4%A`0&!0,!PP'#`D,#0('#0<%`@<) M`A4V,C(L%0D!`10!%!@!%A0)"2<)&!84&"08$!80#`<-!PT'#0(%#`D6)!84 M%A`6#"00%A`4$!80%A0D%!8'#!8'%!0-$`T0!Q8'%!0-$!0)%!8)%!81`A84 M"18,"0D?,2PQ#Q4E`@(8`0$!"14>'!X)```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````)*@8% M!`0%!`($!@L7"P4$"`@(&1D+"P4-!PT'#0<""`4$#0@($!04&!`6`A$1#0$4 M`100%B06`1`8&!08%!`6`1@4%A$&$1PJ$00$`@0"!`('!@(3-C(S+"X>"18D M&!@)&`DG"2"A,)`18D%B08%!`6%"04 M"0D6"100%`D.$R8E%283'`8&!@8@#@XO+0,/+#$/#@D))PD8+R\W+R\O-S(0D)%`T."@H*"A\5"AH*"@H3*B4F M%2(/&QH?$0D0&``````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````"0H?'@(6&!0,"`8(!@@%!`L7$@L2%P@+"PL+ M!@@'#!0'%`T'!`4'#!@6)!0)"2$:(@DD%"04$!88%!@0&!`='@T8%!8)$!`) M"1`)$1,@'!LL#QL#-R\#+0,M`S'PH#'B$0"1X*%0H;"@HB"A,J$Q,N&Q\/#P\/#P\:(@H" M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````4*`D) M`B@)"0D8%A@)+@H=(204$`T$!`4%"`0+"P@+%P@+!@L2%PL%!`T-%`T0#`T" M#104`104%@X1"0H*`@$6$`DA`A`6$`$8(14*"106"2$"%`$!`0<1*@0@%34S M,0,M)RTM+2\M+S$QP&'1H/#QH;(@\:#P\V+"LG"1@````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````"<5'PH*'PH#'BD.`B$) M"1`4%A8)!08E'!,@!@@&$@@($@4&$B`2$@@2#`<,%`T4!`4'%!`8)!@)%0H6 M&`DA$`$)$PH>`@$8%"@3*!`"$!@H'@,8`20)"B4&"`8C(Q4#`RTO+2DO-R\# M+R<)"2$J+R\O+S$RH&!A,*&QH/ M(@\:#QH/#P\;(AH/#P\Q#P\B'QL/"A@````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````)'0D)%A06&!`8)!@4$!`8%@D)"0T$)145)2`$!00%"`0" M*@H*%2`7&1<2"P@-!PT)%`$4%!@""@D````),!$)#@D)"B$-"0X.$``)"AP. M#A@!)`D."B`($@L9"QD@+2T#`S(1`)(R,+&0L9 M"`(,%`$0&"08)`D*"0````D*$QP*"1@)$R8A+@H0`"0)'1X)`0$""AX&!`L9 M&1D9&2,#`RTM+2DG%@D8`@8"!Q@6&!08+P,:+A\:#@D"'PH)$"$>)Q`'#`<" M#0<"!0("$2D.#BL1"0D1#AT.`PX1`@0"#BD.#A$)%!8)#ATK'`()#`D0`BL> M'1XI#@X="@H#'@H3$Q,<(083'14/&B(5(AH;&@\B&B(;#R(/#P\/#P\/#P\/ M#P\;(AH/#QLG"0D8$`D8$!@4```````````````0&`D=&PH6```````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````%B$;+`\5)@X1 M'!$1$0(H$0DG$0(H`@(C'",,"X;'R(;&B(:(ALB&AL:(AH/&AL:#P\:#QH/&@\/+`\L#S4T#R(: M&AH:#P\/"A``````````````"0HJ!AP5"A8````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````%@HB&QL/)@H>$Q,K$Q$.$0() M*!$"!B,E(R,<'`81$QL*&```&`H5)1D7&1<@#1@!`10D`0D)```````````` M````%@HB"@D`````````)`(1)@8$$A(9&1D9$@8.+2TM+2DM(0X3#A,.)PD" M"0D0`A4/&@H:#QL:"AT>&`$!`0$0`@('#0T"`@4-`@X3#@XK#@XK$QX.`PXJ M!P'0,=$0<)$1X*'AT*'@H*"@,>#A$$`@8J,"X:#QH; M&AHB&QH:'QH;&B(;&B(:#P\/#P\/#P\/#P\/#P\/,0\/+#4S-C,V,S0/#B$) M(2@"(2@""0D""B43(R4K$``````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````%@DG%0\;%145%0H>$PX.#@X<(0XF&PH>'B4= M"A4*$0D`````%A$*(Q<9&1('"0D0%B06'0X6```````````````D$`D6```` M`````!0)'@H<"`L7&1D7$AD&!BD#+2DO"0(=#RP/-1HI#ATB)AT*%1L*'A,E M"A\;)Q`!`0$!`183`@<,!`0$#`0-$2D.#AT.'2L.#BDJ!@(%"2$.`Q,.$PX. M#A,K'0,3'AX##@(.`QT=`QX='A,3'"$&!@8@'0H5'QL:'RX?(A4:(AL;'P\B M&AH/&P\/#QH/#P\/#R(/#P\L#P\L#S4T-0\T#S0U,0\/#P\U+#$L&R(5$P8< M(R4F$18````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````G"2#BL.#ATK$Q$"!0<.*0,3*2L#*1X#'0,='AT#'1T. M'1X#'@H>'0X&`@($!A,3'0H?+A\:'PH;&A45(AL:&@\:%1HB&QH;&B(:&R(: M#P\;&@\/#P\/#P\/+`\/+`\U+`\T-2PS#S0S-C$N)2H$'#`<"0D8```````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````%@H;&Q4>"@H*'PD`````````````````````````%`HF!B`@)1L5 M(0$6$0H*%@````````````````````````````DK%08'"Q<+&1D+$@8J`R$O M*2<0#`(J%30U&RX?*2D##S$L'BD3$PH5#QHB&@D!`0$!`0$6"@('!P(&!P8" M#0X.#@X.#@XK$PX.#0("!@X=#BL3*1,.$RD3`Q,#`Q,>`QT*`QX=*1,.!@<( M!08A'A4?'Q4:'QLN&@H?(AH?&ALB#R(;&@\:(AH/#P\/#P\/&@\/#P\/#P\T M#P\Q#S$/,3$/-BPU,30U-BP/%1,"AXG)S\"$RD#&AL. M(0(G"2@=&PH3"@H:'R(:%0\:$0$!`106$!$*!@T'!0("!`('#A,K$PX3$PX. M`@<$!P(A*RL=*PX#'BD.'@,3'AT>*0,=*QX3#AP.*@(%!`8<'0H?"AL*(AH; M'Q\5(A4B&ALB&A\;&B(B&ALB&AL/&@\/#P\/#P\L#QH/#S4/+`\L-2P/,RP/ M-3$/,RP/&AX<(!PC%28)```````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````!@)'0\;%2@="B$0```````````````````` M````````"0H3!@42&1D+&1(2!@,3#AP5'S<&'`,M`S$U&A$H"1`.'143'14: M"AH*+AHB#QLG`0$!"0H/#Q4&!PT"!P4-!`T.#@XI*RD.#@($!0("*`XI#A,I M'1,.'2LI$RD#*1X='A,J(1P"!`4"!!$3,`HN&BX?"@H:(A\;&Q\5'QHN&A\; M&@\:#QL:#QL/(@\;#P\/#S$/#P\/#P\T#RPQ#P\/,34Q#S8T,S0Q&BL&!B,5 M'P()"10````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````)%34;'AT>&`````````````````````````````D.%08( M"!D+&1D+%P81'1$%`@H=*0XJ+2T#-38/*0()`AX5#QX>'PH?(A\5'QHB&@X) M"0(A&S0S#QP,!P4$`@0"`A$.#@X.*PX"!P($#0(.'BL=*PX>#@,3*Q,#$PHI M$RL=#A$&!`@%!`81$PH?&@H?%0H5"AL?&A\:(AHN&A\5&Q\/'R(:#Q\:(AH; M&@\/&@\:#R(/#P\/#P\/#P\/#S,/#S,Q+#4/#Q4>#AP&(`H*$``````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`!0G+BP*)Q8``````````````````````````!@""A4&$A<+&1D9"P8&#AP& M!@0<(SHJ*0,M+0,Q,RP;"1`.#S8;(@H?%1H5&@HB&QLB'QLB"B83#P\:`@T% M!P(%#0<%#@X3#A,.`@("!@("#@X.*2L3*2LI'@XI$PX=*1,A#A$&!`0&"`8< M$PH*"A4N"@H?"A\*'Q45+A\;"A\?&R(:'Q4:&QH;#P\;(AH/#R(/#P\/#P\T M#P\/#S$U+`\Q+`\T#P\/&C`3*AP3)1,0%A8````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````)`@D0```` M````````````````````````"1T3!@42&1D9$A<&!@<%"P8&$R4F'2T#+0,G M-S,R-AL""1XS-"P:'Q4?"@H?'Q4?&AH;"A,5,`D"`A$'!P<'!@("!`<.*PXK M$2$'!00""1$.#AX.$P,.'0X=#@,=`Q$A`@8Y`@(%"`83'3`?&A\?"A\*&BX* M%1\;'R(5%1\*&QH:&B(;(@HB'QH:#QH/#P\;&@\B#QH/#P\/#QH/#P\/#S4Q M-@\/+C`*AX3$`$8)PT$`@(A`@8-`B$.#@X1`@4'!P(A#@XI M#@X.$PX>`RL.$PX.!@T(#0<&!`8&$P,*'PH5"@H5%0H*"A\*(@H:'Q4B"AH? M(A4B%14:(AH;(ALB#P\/#QH/#P\;#P\/#P\/#P\/#S4L#P\/#PH3!@0&(R,3 M"@D````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````!@"'14< M"PL2&1(9"P0%!`4(!`81)3XP+#$B`P,#&@\R,C4/$RLN&QL:"C@*%1\N"@H* M"@H3!A,*(1`8%B<*`@P%'!$"!PT"$2D<`@($"`(%*!$.*Q,.'2LI#A,I$R$A M`@8$`@0$!081'1X="@H*"@H*"A\?+A\5"AH*'PH*(AH;"AL5&B(:(AH:&Q\: M&AL/#P\:#P\/&AH/#P\/#P\/#P\Q#P\/&Q4J!@0&(!XF"0D0```````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````"1X3!A(9%QD9&1(%!`@% M"`(6"08E%0\S#RDM+0\R,C(R,RP;#RPN%0H*%2(5'Q4?%0,1`B<>'QLA`1@> M"@,"#`(5"@8$`@<.#A$"`@(%`@<.#@X3#BL.'0X<#@($`@('!@8+"`83*1X* M`PH*'0H5"AT*"@H:"A\N"AL*&AL:+A\:(AHN%14B%2(5(@\B#QH:#R(;&AHB M#P\:#P\/+`\/#P\L#QT.!@82(Q4""0D8```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````&`()``````````D.%08(!1D+&1D+"P<%!`@$"0<"(QX;-C(/ M#BT#(C0S,C(R-C0U+!H*'2D*.`,?'0H=#@())PX*&R$0"1\B+0D,!P\;'`4' M#2$.!@<%`@(-`@X>#@XI$PX.$0("`@4'!@($!`42#A,#"@H=%0H*'PH*"A\5 M'PH*%0H?"@H5(A\:(A4?'QH?#QH*&AHB&AL:+B(/#P\B#QL/#P\/#P\Q#P\: M(A\=!@@$("`C'0D````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````6 M"B(1`````!`G"C``A08 M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````!@*+`H)````"0H3 M'`4+%QD9"P42"PT)$`D1("8/,RPN"ALV-`\*'@HI+0,Q+`,U,2L""2<))R!@('(",C)AH*&``````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````8&S(L(0D)'A4J$@L2&1D9"Q(%#!0"#A,&(",3"@H? M,`H*&A\5`RL>&BPB`RDM+2TM-R\W-R\M+RTO-RDO+R\O+0,M`RTI*0H*'`(3 M#S85!@T'!@("#`4'`@("`@0'!0(%`AP$!@0&'!,=$QX*'PH='1\*'14="@,* M'Q4*"AH*%0H*%0H5(@H5'PHB'QL?&RX:(A4B%1\;&AL:&B(:&P\?&QH;"AX" M!@4&("`3"@HH&!`4```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````!8B,C,/&R(3(009&1<9$@0%"`"A\*'0H*'PH>'0H*"@H*"@H?"@H? M"A\*&@H?%1H?&A\:'QHB&AH*&Q\/(B(/#QL:#QL*`RH"!0@+$B8]%1$""0`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````&`H/-30L M&@8("QD9&0L7"P<"%!04!AP<$PH?'PH5.!\*"A\*'RX=$0H;"B,!T*'PH="@,*"AT*"A4?&PH.$1$A$0X.$0("$QT*`A`8"0D8"1@D M%B$*&A\)%@D8```4$1P3+#8L(P<%"`<"!0<$$0(&!P4+!`4$!@X3`PX#`PH# M'0H=`QXI"AT=`S@*"@H*"@H5"@H5'Q4?'PH5(A45'R(:'Q\:+AH;'R(5(AH/ M&QLB%1\5'A,"!087(!,F%28)%@D````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````"143!A<+&1D9"PL+!B,5%1,<$QX*"AT* M"@HX'0H?"@H*'0HB&P\5*PD)"04$$Q4""0D8````````````&`DA"0`````` M`!@&$QXL,@\5'`((`@4$#0(&!`((!`@&!@X=#AT='AT='0H="AT*"AT>*0H= M"@H*.`H>"@H*"@H*'Q4:'Q\5'R(:%1\5%2(5'QL:&BX:#P\B&@H<#A$<#@@+ M!B8/%2$H"1@````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````))@(("QD9"Q<2!!($)0\;,`H3'PH*"@HX"@H*"@H*"@H= M"A4/,P\;#A$"`@83"@D`````````````````````````````%`8<'BPR,Q4E M`@4"!00%!`8"!`@%!AP.*Q,="@H='@,="AT#"AT#'0,*"@H*'0H5"@H*"A4* M'PH*'PH?&Q\;&@H*'QL?&QHB'Q4B"A\;"A4*$P($!0(&("4C%1L>&``````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M``D3(!<9%QD+"`L"*@X<$Q4;%0HX"C@*'PH?"AT*'0H=`QX5+A4L#Q4>"AL5 M*!00```````````````````````````````8$2HP#S0U#PH&`@0(`@@%!`@$ M`@8I'0X='@,=$P,3`QT#"@H='AT*'0,='AT*'PH="@H?'PH*%0H*%0H*%1\N M&B(:%1\:"AH5'QH*'0X.!@(%!@02'"`F%0H""1@````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````@HC(`L+!0@" M*A,'AX*)@8"!04(!`P"`B$.'1,I'BDI'2D= M"AT=%1T=`QT?"@H*"@H*"@H*,!\*'Q4?%0H*"@H?'Q\*'PH:+AHB&B(/(AT> M$Q$&`@07"`L2(Q4;&A$""1@````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````H&R,2(!((`@0"'B$1$PH*"@HX M"AT*'0,='0H3'1,K'`('!@\S#S,L"@\S#R$````````````````````````` M``````````<"`AP1#A,3!@@$"`4$!1$"$1TK`P,3$P,>$P,="A4?"@H>"@H* M.`HX"C`?'1T*"@H*'Q4B"@H?%0H5%0H*"@H?%0H;"A\=*08"!0<(!A(&("`C M"AL*%@`````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````"<5"B,7"Q<�(&!CDJ$P,=*1T*$P,3$QX.!@X" M!0(-`@83,S(U+`\=)AH/`@`````````````````````````````````4$1,Z M$QP'0H?"AT*"A\="AT="AT="AT*"@H;"AH*&A4? M(@H*"@X&*@("`@0%!`87"Q(E&Q4.!R<8```````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````````````$`H5 M,"`7!!P&!`T""`T,#`T'#`<,#00(`@8&!A,C$R8N#S8L,S(T#Q,3"@D````` M````````````````````````````%@H5$R8E&0L7"`0$!P0$(0(.#A$.#A,I M$S@='1,#'1X#"@H*'AT="AT#"@H5"A\*'Q4?&A\*"@H?"@H*'2L3!@('"`4$ M"`8&(",C("45%2@````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````$0,5(QP<(R`&%P4$ M!04"`@0"`@0%!`8$!AXP%1X)%!`A%38V,C(S%1TH&``````````````````` M```````````````8%0\5(R`9"QD+%P8$!0(1!@("`@8A#@X.#@XK*1X=*1T= M'AT="AT*"@H*.`H?"AT*'1T>`Q,>'1,.#A$"!`8%!`4&"P87("`F%28)$`D6 M)``````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````!@*%24F,`85#R85)24C)2,C)3`F,!4: M"@()!P(G`@```"0)#C0R,BPI"10````````````````````````````````` M`!@)#ALE$AD9&0L9&0L$!`8"!P0"#0`Q,I"@,*"AT*"AT* M'0,=`QP<#AP"$0("`@(J!@4(!0L+"Q(@(QL/%0(H"20````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````8`AL;)0H3)PH;"B8>$R,C)1P3)AX*%1L*$``````````` M```)+B(/&R@````````````````````````````````````````)"B4C$B`9 M&1D9(!<2!`4""`4(`@0"`B$"`@X1$PX3`RD3*1TK#A,3*1,>$PX1`@("`@T$ M#`4(!!PA!!(&&2`@(R,E"AH*&``````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````4 M&`(3,"8>`@D4&`D6$!`4)!00%!`)%A8)"18````````````````6"0D6```` M```````````````````````````````````````6$`DF)2,@&0L+&2`@"PL& M"P8%"`4&`@8"!0("!@("!@("`@4'`@T%`@(A`@8'!00%"`4(!`8%(!P@%PLC M"ALP"1`)%A`````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````"0.'A,;&R<````` M```````````````````````````````````````````````````````````` M````````````````````````````%@D)`A4C&1D9(!D9&0L+"P0%!`8"!`4$ M!`($`@("$08$!0<%"`<$!0<<`@0(!0@2"PL9&1DE,"8"%`<)"0D8```````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````)`DH`AXP)1H*"0`````````````````` M```````````````````````````````````````````````````````````` M```````````````````)"B,&)1(9&1(+&1D+%PL7"Q<2!0@%"`0%!`(&`@0% M"`@&!0@(!@0&!!<2&2`7(R4@'",>'@D````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````!@),!43)285(1`````````````````````````````````` M```````````````````````````````````````````````````````````` M`````"00%@(5%24@&1D2&1D9&2`9"Q<9$A(+"PL&(!(2"Q(9"PL9&2`+%R`9 M%P0@$Q,F%0H6%!80```````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M"0H3$R8A"0D8```````````````````````````````````````````````` M````````````````````````````````````````````````````````&"@) M"0(5&QLC)1(@$AD7&0L9&1D+&1(2&0L9$AD9&2`E(R,5%14"#1`'$`DH"1`` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````!81"B4E$PT````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````````$`H:%2,@!A<2 M!1(C(R`2(Q(C(!(C(!(2$@@2("`3$R4F+@D````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````8$!@)$PHE%0H)```````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````%A`8$``4%!`6'AH5&Q45)B85 M)AH5&PH,%``4"100"1`6```````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````!`*%1,C)A43"1@````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````!0)(0DG`@DA"0(H)PDG"20````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````D M$1\;'B,J'B<````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````&"`A08```` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````"0>"B45)@(````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````8"0H5'A4>%@`````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M`````````````````````````````````````````````````````````!00 M%@D3)3`F(1````````````````````````````````$!`0`````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````````````````` M```````````````````````````````````````````````!`0$!`0$!```` M```````````````````````````````````````````````````````````` M````````````````````````````````````````````)PH # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=tile2bmp - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "tile2bmp.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "tile2bmp.mak" CFG="tile2bmp - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "tile2bmp - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "tile2bmp - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "tile2bmp - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x1009 /d "NDEBUG" # ADD RSC /l 0x1009 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\tile2bmp.exe" !ELSEIF "$(CFG)" == "tile2bmp - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c # ADD BASE RSC /l 0x1009 /d "_DEBUG" # ADD RSC /l 0x1009 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\util\tile2bmp.exe" /pdbtype:sept !ENDIF # Begin Target # Name "tile2bmp - Win32 Release" # Name "tile2bmp - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\src\decl.c # End Source File # Begin Source File SOURCE=..\src\drawing.c # End Source File # Begin Source File SOURCE=..\src\monst.c # End Source File # Begin Source File SOURCE=..\src\objects.c # End Source File # Begin Source File SOURCE=..\win\share\tile2bmp.c !IF "$(CFG)" == "tile2bmp - Win32 Release" !ELSEIF "$(CFG)" == "tile2bmp - Win32 Debug" # ADD CPP /D "PACKED_FILE" !ENDIF # End Source File # Begin Source File SOURCE=..\win\share\tiletext.c !IF "$(CFG)" == "tile2bmp - Win32 Release" !ELSEIF "$(CFG)" == "tile2bmp - Win32 Debug" # ADD CPP /Zi !ENDIF # End Source File # Begin Source File SOURCE=..\win\share\tiletxt.c # ADD CPP /D "TILETEXT" # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/tilemap.dsp0100644000000000000000000001751407764735152015567 0ustar rootroot# Microsoft Developer Studio Project File - Name="tilemap" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=tilemap - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "tilemap.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "tilemap.mak" CFG="tilemap - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "tilemap - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "tilemap - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "tilemap - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /I "..\include" /I "..\sys\winnt\include" /I "..\win\share" /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /c # SUBTRACT CPP /YX # ADD BASE RSC /l 0x1009 /d "NDEBUG" # ADD RSC /l 0x1009 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\tilemap.exe" # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=Generating src\tile.c PostBuild_Cmds=echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build # End Special Build Tool !ELSEIF "$(CFG)" == "tilemap - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\include" /I "..\sys\winnt\include" /I "..\win\share" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "WIN32CON" /D "DLB" /D "MSWIN_GRAPHICS" /FD /GZ /c # ADD BASE RSC /l 0x1009 /d "_DEBUG" # ADD RSC /l 0x1009 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /incremental:no /debug /machine:I386 /out:"..\util\tilemap.exe" /pdbtype:sept # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Desc=Generating src\tile.c PostBuild_Cmds=echo chdir ..\src chdir ..\src ..\util\tilemap.exe echo chdir ..\build chdir ..\build # End Special Build Tool !ENDIF # Begin Target # Name "tilemap - Win32 Release" # Name "tilemap - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\win\share\tilemap.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File SOURCE=..\include\align.h # End Source File # Begin Source File SOURCE=..\include\attrib.h # End Source File # Begin Source File SOURCE=..\include\color.h # End Source File # Begin Source File SOURCE=..\include\config.h # End Source File # Begin Source File SOURCE=..\include\config1.h # End Source File # Begin Source File SOURCE=..\include\coord.h # End Source File # Begin Source File SOURCE=..\include\decl.h # End Source File # Begin Source File SOURCE=..\include\dgn_comp.h # End Source File # Begin Source File SOURCE=..\include\dgn_file.h # End Source File # Begin Source File SOURCE=..\include\display.h # End Source File # Begin Source File SOURCE=..\include\dungeon.h # End Source File # Begin Source File SOURCE=..\include\engrave.h # End Source File # Begin Source File SOURCE=..\include\flag.h # End Source File # Begin Source File SOURCE=..\include\global.h # End Source File # Begin Source File SOURCE=..\include\mkroom.h # End Source File # Begin Source File SOURCE=..\include\monattk.h # End Source File # Begin Source File SOURCE=..\include\monst.h # End Source File # Begin Source File SOURCE=..\include\monsym.h # End Source File # Begin Source File SOURCE=..\include\nhlan.h # End Source File # Begin Source File SOURCE=..\include\ntconf.h # End Source File # Begin Source File SOURCE=..\include\obj.h # End Source File # Begin Source File SOURCE=..\include\objclass.h # End Source File # Begin Source File SOURCE=..\include\onames.h # End Source File # Begin Source File SOURCE=..\include\permonst.h # End Source File # Begin Source File SOURCE=..\include\pm.h # End Source File # Begin Source File SOURCE=..\include\prop.h # End Source File # Begin Source File SOURCE=..\include\quest.h # End Source File # Begin Source File SOURCE=..\include\rect.h # End Source File # Begin Source File SOURCE=..\include\region.h # End Source File # Begin Source File SOURCE=..\include\rm.h # End Source File # Begin Source File SOURCE=..\include\skills.h # End Source File # Begin Source File SOURCE=..\include\spell.h # End Source File # Begin Source File SOURCE=..\include\timeout.h # End Source File # Begin Source File SOURCE=..\include\tradstdc.h # End Source File # Begin Source File SOURCE=..\include\trampoli.h # End Source File # Begin Source File SOURCE=..\include\trap.h # End Source File # Begin Source File SOURCE=..\include\vision.h # End Source File # Begin Source File SOURCE=..\include\winprocs.h # End Source File # Begin Source File SOURCE=..\include\wintty.h # End Source File # Begin Source File SOURCE=..\include\wintype.h # End Source File # Begin Source File SOURCE=..\include\you.h # End Source File # Begin Source File SOURCE=..\include\youprop.h # End Source File # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/tiles.dsp0100644000000000000000000000523107764735152015245 0ustar rootroot# Microsoft Developer Studio Project File - Name="tiles" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) External Target" 0x0106 CFG=tiles - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "tiles.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "tiles.mak" CFG="tiles - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "tiles - Win32 Release" (based on "Win32 (x86) External Target") !MESSAGE "tiles - Win32 Debug" (based on "Win32 (x86) External Target") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" !IF "$(CFG)" == "tiles - Win32 Release" # PROP BASE Use_MFC # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Cmd_Line "NMAKE /f tiles.mak" # PROP BASE Rebuild_Opt "/a" # PROP BASE Target_File "tiles.exe" # PROP BASE Bsc_Name "tiles.bsc" # PROP BASE Target_Dir "" # PROP Use_MFC # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Cmd_Line "nmake /f "tiles.mak"" # PROP Rebuild_Opt "/a" # PROP Target_File "..\win\win32\tiles.bmp" # PROP Bsc_Name "" # PROP Target_Dir "" !ELSEIF "$(CFG)" == "tiles - Win32 Debug" # PROP BASE Use_MFC # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Cmd_Line "NMAKE /f tiles.mak" # PROP BASE Rebuild_Opt "/a" # PROP BASE Target_File "tiles.exe" # PROP BASE Bsc_Name "tiles.bsc" # PROP BASE Target_Dir "" # PROP Use_MFC # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Cmd_Line "nmake /f "tiles.mak"" # PROP Rebuild_Opt "/a" # PROP Target_File "..\win\win32\tiles.bmp" # PROP Bsc_Name "" # PROP Target_Dir "" !ENDIF # Begin Target # Name "tiles - Win32 Release" # Name "tiles - Win32 Debug" !IF "$(CFG)" == "tiles - Win32 Release" !ELSEIF "$(CFG)" == "tiles - Win32 Debug" !ENDIF # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/tiles.mak0100644000000000000000000000076107764735042015230 0ustar rootrootdefault: all all: ..\win\win32\tiles.bmp clean: -del ..\src\win\win32\tiles.bmp -del ..\win\win32\tiles.bmp #========================================== # Building the tiles file tile.bmp #========================================== ..\src\tiles.bmp : ..\win\share\monsters.txt ..\win\share\objects.txt \ ..\win\share\other.txt chdir ..\src ..\util\tile2bmp.exe tiles.bmp chdir ..\build ..\win\win32\tiles.bmp: ..\src\tiles.bmp @copy ..\src\tiles.bmp ..\win\win32\tiles.bmp nethack-3.4.3/win/win32/uudecode.dsp0100644000000000000000000001301107764735152015715 0ustar rootroot# Microsoft Developer Studio Project File - Name="uudecode" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Console Application" 0x0103 CFG=uudecode - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "uudecode.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "uudecode.mak" CFG="uudecode - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "uudecode - Win32 Release" (based on "Win32 (x86) Console Application") !MESSAGE "uudecode - Win32 Debug" (based on "Win32 (x86) Console Application") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" CPP=cl.exe RSC=rc.exe !IF "$(CFG)" == "uudecode - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "Release" # PROP BASE Intermediate_Dir "Release" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "Release" # PROP Intermediate_Dir "Release" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c # ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c # SUBTRACT CPP /YX /Yc /Yu # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 # ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /machine:I386 /out:"..\util\uudecode.exe" # SUBTRACT LINK32 /nodefaultlib # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Cmds=echo chdir ..\win\win32 chdir ..\win\win32 \ echo decoding icon (nhico.uu to NetHack.ico) \ ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu \ echo decoding mnsel (mnsel.uu to mnsel.bmp) \ ..\..\util\uudecode.exe mnsel.uu \ echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) \ ..\..\util\uudecode.exe mnselcnt.uu \ echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) \ ..\..\util\uudecode.exe mnunsel.uu \ echo decoding petmark (petmark.uu to petmark.bmp) \ ..\..\util\uudecode.exe petmark.uu \ echo decoding splash (splash.uu to splash.bmp) \ ..\..\util\uudecode.exe splash.uu \ echo decoding tombstone (rip.uu to rip.bmp) \ ..\..\util\uudecode.exe rip.uu \ chdir ..\..\binary # End Special Build Tool !ELSEIF "$(CFG)" == "uudecode - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "Debug" # PROP BASE Intermediate_Dir "Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "Debug" # PROP Intermediate_Dir "Debug" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c # ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c # SUBTRACT CPP /YX /Yc /Yu # ADD BASE RSC /l 0x409 /d "_DEBUG" # ADD RSC /l 0x409 /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept # ADD LINK32 kernel32.lib user32.lib gdi32.lib /nologo /subsystem:console /debug /machine:I386 /out:"..\util\uudecode.exe" /pdbtype:sept # SUBTRACT LINK32 /nodefaultlib # Begin Special Build Tool SOURCE="$(InputPath)" PostBuild_Cmds=echo chdir ..\win\win32 chdir ..\win\win32 \ echo decoding icon (nhico.uu to NetHack.ico) \ ..\..\util\uudecode.exe ../../sys/winnt/nhico.uu \ echo decoding mnsel (mnsel.uu to mnsel.bmp) \ ..\..\util\uudecode.exe mnsel.uu \ echo decoding mnselcnt (mnselcnt.uu to mnselcnt.bmp) \ ..\..\util\uudecode.exe mnselcnt.uu \ echo decoding mnunsel (mnunsel.uu to mnunsel.bmp) \ ..\..\util\uudecode.exe mnunsel.uu \ echo decoding petmark (petmark.uu to petmark.bmp) \ ..\..\util\uudecode.exe petmark.uu \ echo decoding splash (splash.uu to splash.bmp) \ ..\..\util\uudecode.exe splash.uu \ echo decoding tombstone (rip.uu to rip.bmp) \ ..\..\util\uudecode.exe rip.uu \ chdir ..\..\binary # End Special Build Tool !ENDIF # Begin Target # Name "uudecode - Win32 Release" # Name "uudecode - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\sys\share\uudecode.c # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project nethack-3.4.3/win/win32/winMS.h0100644000000000000000000001353707764735042014631 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ #ifndef WINMS_H #define WINMS_H #define WIN32_LEAN_AND_MEAN #include #include #include #include "hack.h" /* Create an array to keep track of the various windows */ #ifndef MAXWINDOWS #define MAXWINDOWS 15 #endif #define NHW_RIP 32 #ifndef TILE_X #define TILE_X 16 #endif #define TILE_Y 16 #define TILES_PER_LINE 40 /* tile background color */ #define TILE_BK_COLOR RGB(71, 108, 108) /* minimum/maximum font size (in points - 1/72 inch) */ #define NHFONT_DEFAULT_SIZE 9 #define NHFONT_SIZE_MIN 3 #define NHFONT_SIZE_MAX 20 #define MAX_LOADSTRING 100 typedef struct mswin_nhwindow_data { HWND win; int type; int dead; } MSNHWinData, *PMSNHWinData; typedef struct mswin_nhwindow_app { HINSTANCE hApp; HWND hMainWnd; HACCEL hAccelTable; HWND hPopupWnd; /* current popup window */ MSNHWinData windowlist[MAXWINDOWS]; HBITMAP bmpTiles; HBITMAP bmpPetMark; HBITMAP bmpMapTiles; /* custom tiles bitmap */ HBITMAP bmpRip; HBITMAP bmpSplash; int mapTile_X; /* tile width */ int mapTile_Y; /* tile height */ int mapTilesPerLine; /* number of tile per row in the bitmap */ boolean bNoHScroll; /* disable cliparound for horizontal grid (map) */ boolean bNoVScroll; /* disable cliparound for vertical grid (map) */ int mapDisplayModeSave; /* saved map display mode */ char* saved_text; DWORD saveRegistrySettings; /* Flag if we should save this time */ DWORD regNetHackMode; /* NetHack mode means no Windows keys in some places */ LONG regMainMinX; LONG regMainMinY; LONG regMainMaxX; LONG regMainMaxY; LONG regMainLeft; LONG regMainTop; LONG regMainBottom; LONG regMainRight; DWORD regMainShowState; } NHWinApp, *PNHWinApp; #define E extern E PNHWinApp GetNHApp(void); E struct window_procs mswin_procs; #undef E /* Some prototypes */ void mswin_init_nhwindows(int* argc, char** argv); void mswin_player_selection(void); void mswin_askname(void); void mswin_get_nh_event(void); void mswin_exit_nhwindows(const char *); void mswin_suspend_nhwindows(const char *); void mswin_resume_nhwindows(void); winid mswin_create_nhwindow(int type); void mswin_clear_nhwindow(winid wid); void mswin_display_nhwindow(winid wid, BOOLEAN_P block); void mswin_destroy_nhwindow(winid wid); void mswin_curs(winid wid, int x, int y); void mswin_putstr(winid wid, int attr, const char *text); void mswin_putstr_ex(winid wid, int attr, const char *text, int); void mswin_display_file(const char *filename,BOOLEAN_P must_exist); void mswin_start_menu(winid wid); void mswin_add_menu(winid wid, int glyph, const ANY_P * identifier, CHAR_P accelerator, CHAR_P group_accel, int attr, const char *str, BOOLEAN_P presel); void mswin_end_menu(winid wid, const char *prompt); int mswin_select_menu(winid wid, int how, MENU_ITEM_P **selected); void mswin_update_inventory(void); void mswin_mark_synch(void); void mswin_wait_synch(void); void mswin_cliparound(int x, int y); void mswin_print_glyph(winid wid,XCHAR_P x,XCHAR_P y,int glyph); void mswin_raw_print(const char *str); void mswin_raw_print_bold(const char *str); int mswin_nhgetch(void); int mswin_nh_poskey(int *x, int *y, int *mod); void mswin_nhbell(void); int mswin_doprev_message(void); char mswin_yn_function(const char *question, const char *choices, CHAR_P def); void mswin_getlin(const char *question, char *input); int mswin_get_ext_cmd(void); void mswin_number_pad(int state); void mswin_delay_output(void); void mswin_change_color(void); char *mswin_get_color_string(void); void mswin_start_screen(void); void mswin_end_screen(void); void mswin_outrip(winid wid, int how); void mswin_preference_update(const char *pref); /* helper function */ HWND mswin_hwnd_from_winid(winid wid); winid mswin_winid_from_type(int type); winid mswin_winid_from_handle(HWND hWnd); void mswin_window_mark_dead(winid wid); void bail(const char *mesg); void nhapply_image_transparent( HDC hDC, int x, int y, int width, int height, HDC sourceDC, int s_x, int s_y, int s_width, int s_height, COLORREF cTransparent ); void mswin_popup_display(HWND popup, int* done_indicator); void mswin_popup_destroy(HWND popup); void mswin_read_reg(void); void mswin_destroy_reg(void); void mswin_write_reg(void); int NHMessageBox(HWND hWnd, LPCTSTR text, UINT type); extern HBRUSH menu_bg_brush; extern HBRUSH menu_fg_brush; extern HBRUSH text_bg_brush; extern HBRUSH text_fg_brush; extern HBRUSH status_bg_brush; extern HBRUSH status_fg_brush; extern HBRUSH message_bg_brush; extern HBRUSH message_fg_brush; extern COLORREF menu_bg_color; extern COLORREF menu_fg_color; extern COLORREF text_bg_color; extern COLORREF text_fg_color; extern COLORREF status_bg_color; extern COLORREF status_fg_color; extern COLORREF message_bg_color; extern COLORREF message_fg_color; #define SYSCLR_TO_BRUSH(x) ((HBRUSH)((x) + 1)) /* unicode stuff */ #ifdef UNICODE #define NH_W2A(w, a, cb) ( WideCharToMultiByte( \ CP_ACP, \ 0, \ (w), \ -1, \ (a), \ (cb), \ NULL, \ NULL), (a) ) #define NH_A2W(a, w, cb) ( MultiByteToWideChar( \ CP_ACP, \ 0, \ (a), \ -1, \ (w), \ (cb)), (w) ) #else #define NH_W2A(w, a, cb) (strncpy((a), (w), (cb))) #define NH_A2W(a, w, cb) (strncpy((w), (a), (cb))) #endif #endif /* WINmswin_H */ nethack-3.4.3/win/win32/winhack.c0100644000000000000000000001716607764735042015215 0ustar rootroot/* Copyright (C) 2001 by Alex Kompel */ /* NetHack may be freely redistributed. See license for details. */ // winhack.cpp : Defines the entry point for the application. // #include #include "winMS.h" #include "hack.h" #include "dlb.h" #include "resource.h" #include "mhmain.h" #include "mhmap.h" #ifndef __BORLANDC__ #include #else /* Borland redefines "boolean" in shlwapi.h so just use the little bit we need */ typedef struct _DLLVERSIONINFO { DWORD cbSize; DWORD dwMajorVersion; // Major version DWORD dwMinorVersion; // Minor version DWORD dwBuildNumber; // Build number DWORD dwPlatformID; // DLLVER_PLATFORM_* } DLLVERSIONINFO; // // The caller should always GetProcAddress("DllGetVersion"), not // implicitly link to it. // typedef HRESULT (CALLBACK* DLLGETVERSIONPROC)(DLLVERSIONINFO *); #endif #ifdef OVL0 #define SHARED_DCL #else #define SHARED_DCL extern #endif /* Minimal common control library version Version _WIN_32IE Platform/IE ======= ========= =========== 4.00 0x0200 Microsoft(r) Windows 95/Windows NT 4.0 4.70 0x0300 Microsoft(r) Internet Explorer 3.x 4.71 0x0400 Microsoft(r) Internet Explorer 4.0 4.72 0x0401 Microsoft(r) Internet Explorer 4.01 ...and probably going on infinitely... */ #define MIN_COMCTLMAJOR 4 #define MIN_COMCTLMINOR 71 #define INSTALL_NOTES "http://www.nethack.org/v340/ports/download-win.html#cc" /*#define COMCTL_URL "http://www.microsoft.com/msdownload/ieplatform/ie/comctrlx86.asp"*/ extern void FDECL(nethack_exit,(int)); static TCHAR* _get_cmd_arg(TCHAR* pCmdLine); static HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor); // Global Variables: NHWinApp _nethack_app; #ifdef __BORLANDC__ #define _stricmp(s1,s2) stricmp(s1,s2) #define _strdup(s1) strdup(s1) #endif // Foward declarations of functions included in this code module: extern void FDECL(pcmain, (int,char **)); static void __cdecl mswin_moveloop(void *); #define MAX_CMDLINE_PARAM 255 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { INITCOMMONCONTROLSEX InitCtrls; int argc; char* argv[MAX_CMDLINE_PARAM]; size_t len; TCHAR *p; TCHAR wbuf[BUFSZ]; char buf[BUFSZ]; DWORD major, minor; /* ensure that we don't access violate on a panic() */ windowprocs.win_raw_print = mswin_raw_print; windowprocs.win_raw_print_bold = mswin_raw_print_bold; /* init applicatio structure */ _nethack_app.hApp = hInstance; _nethack_app.hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_NETHACKW); _nethack_app.hMainWnd = NULL; _nethack_app.hPopupWnd = NULL; _nethack_app.bmpTiles = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_TILES)); if( _nethack_app.bmpTiles==NULL ) panic("cannot load tiles bitmap"); _nethack_app.bmpPetMark = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_PETMARK)); if( _nethack_app.bmpPetMark==NULL ) panic("cannot load pet mark bitmap"); _nethack_app.bmpRip = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_RIP)); if ( _nethack_app.bmpRip == NULL ) panic("cannot load rip bitmap"); _nethack_app.bmpSplash = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_SPLASH)); if ( _nethack_app.bmpSplash == NULL ) panic("cannot load splash bitmap"); _nethack_app.bmpMapTiles = _nethack_app.bmpTiles; _nethack_app.mapTile_X = TILE_X; _nethack_app.mapTile_Y = TILE_Y; _nethack_app.mapTilesPerLine = TILES_PER_LINE; _nethack_app.bNoHScroll = FALSE; _nethack_app.bNoVScroll = FALSE; _nethack_app.saved_text = strdup(""); // init controls if (FAILED(GetComCtlVersion(&major, &minor))) { char buf[TBUFSZ]; Sprintf(buf, "Cannot load common control library.\n%s\n%s", "For further information, refer to the installation notes at", INSTALL_NOTES); panic(buf); } if (major < MIN_COMCTLMAJOR || (major == MIN_COMCTLMAJOR && minor < MIN_COMCTLMINOR)) { char buf[TBUFSZ]; Sprintf(buf, "Common control library is outdated.\n%s %d.%d\n%s\n%s", "NetHack requires at least version ", MIN_COMCTLMAJOR, MIN_COMCTLMINOR, "For further information, refer to the installation notes at", INSTALL_NOTES); panic(buf); } ZeroMemory(&InitCtrls, sizeof(InitCtrls)); InitCtrls.dwSize = sizeof(InitCtrls); InitCtrls.dwICC = ICC_LISTVIEW_CLASSES; InitCommonControlsEx(&InitCtrls); /* get command line parameters */ p = _get_cmd_arg(GetCommandLine()); p = _get_cmd_arg(NULL); /* skip first paramter - command name */ for( argc = 1; p && argc0 ) { argv[argc] = _strdup( NH_W2A(p, buf, BUFSZ) ); } else { argv[argc] = ""; } p = _get_cmd_arg(NULL); } GetModuleFileName(NULL, wbuf, BUFSZ); argv[0] = _strdup(NH_W2A(wbuf, buf, BUFSZ)); if (argc == 2) { TCHAR *savefile = strdup(argv[1]); TCHAR *plname; for (p = savefile; *p && *p != '-'; p++) ; if (*p) { /* we found a '-' */ plname = p + 1; for (p = plname; *p && *p != '.'; p++) ; if (*p) { if (strcmp(p + 1, "NetHack-saved-game") == 0) { *p = '\0'; argv[1] = "-u"; argv[2] = _strdup(plname); argc = 3; } } } free(savefile); } pcmain(argc,argv); moveloop(); return 0; } PNHWinApp GetNHApp() { return &_nethack_app; } TCHAR* _get_cmd_arg(TCHAR* pCmdLine) { static TCHAR* pArgs = NULL; TCHAR *pRetArg; BOOL bQuoted; if( !pCmdLine && !pArgs ) return NULL; if( !pArgs ) pArgs = pCmdLine; /* skip whitespace */ for(pRetArg = pArgs; *pRetArg && _istspace(*pRetArg); pRetArg = CharNext(pRetArg)); if( !*pRetArg ) { pArgs = NULL; return NULL; } /* check for quote */ if( *pRetArg==TEXT('"') ) { bQuoted = TRUE; pRetArg = CharNext(pRetArg); pArgs = _tcschr(pRetArg, TEXT('"')); } else { /* skip to whitespace */ for(pArgs = pRetArg; *pArgs && !_istspace(*pArgs); pArgs = CharNext(pArgs)); } if( pArgs && *pArgs ) { TCHAR* p; p = pArgs; pArgs = CharNext(pArgs); *p = (TCHAR)0; } else { pArgs = NULL; } return pRetArg; } /* Get the version of the Common Control library on this machine. Copied from the Microsoft SDK */ HRESULT GetComCtlVersion(LPDWORD pdwMajor, LPDWORD pdwMinor) { HINSTANCE hComCtl; HRESULT hr = S_OK; DLLGETVERSIONPROC pDllGetVersion; if(IsBadWritePtr(pdwMajor, sizeof(DWORD)) || IsBadWritePtr(pdwMinor, sizeof(DWORD))) return E_INVALIDARG; //load the DLL hComCtl = LoadLibrary(TEXT("comctl32.dll")); if (!hComCtl) return E_FAIL; /* You must get this function explicitly because earlier versions of the DLL don't implement this function. That makes the lack of implementation of the function a version marker in itself. */ pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hComCtl, TEXT("DllGetVersion")); if(pDllGetVersion) { DLLVERSIONINFO dvi; ZeroMemory(&dvi, sizeof(dvi)); dvi.cbSize = sizeof(dvi); hr = (*pDllGetVersion)(&dvi); if(SUCCEEDED(hr)) { *pdwMajor = dvi.dwMajorVersion; *pdwMinor = dvi.dwMinorVersion; } else { hr = E_FAIL; } } else { /* If GetProcAddress failed, then the DLL is a version previous to the one shipped with IE 3.x. */ *pdwMajor = 4; *pdwMinor = 0; } FreeLibrary(hComCtl); return hr; } nethack-3.4.3/win/win32/winhack.rc0100644000000000000000000002571207764735042015373 0ustar rootroot//Microsoft Developer Studio generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #if defined(__BORLANDC__) LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US #endif #define APSTUDIO_HIDDEN_SYMBOLS #include "windows.h" #undef APSTUDIO_HIDDEN_SYMBOLS #include "resource.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_NETHACKW ICON DISCARDABLE "NETHACK.ICO" ///////////////////////////////////////////////////////////////////////////// // // Menu // IDC_NETHACKW MENU DISCARDABLE BEGIN POPUP "&File" BEGIN MENUITEM "&Save and Exit", IDM_SAVE MENUITEM SEPARATOR MENUITEM "&Quit", IDM_EXIT END POPUP "&Map" BEGIN MENUITEM "&0 - Use Tiles", IDM_MAP_TILES MENUITEM "&1 - ASCII (4x6)", IDM_MAP_ASCII4X6 MENUITEM "&2 - ASCII (6x8)", IDM_MAP_ASCII6X8 MENUITEM "&3 - ASCII (8x8)", IDM_MAP_ASCII8X8 MENUITEM "&4 - ASCII (16x8)", IDM_MAP_ASCII16X8 MENUITEM "&5 - ASCII (7x12)", IDM_MAP_ASCII7X12 MENUITEM "&6 - ASCII (8x12)", IDM_MAP_ASCII8X12 MENUITEM "&7 - ASCII (16x12)", IDM_MAP_ASCII16X12 MENUITEM "&8 - ASCII (12x16)", IDM_MAP_ASCII12X16 MENUITEM "&9 - ASCII (10x18)", IDM_MAP_ASCII10X18 MENUITEM SEPARATOR MENUITEM "&Fit To Screen ", IDM_MAP_FIT_TO_SCREEN END POPUP "Windows &Settings" BEGIN MENUITEM "NetHack Mode", IDM_NHMODE MENUITEM SEPARATOR MENUITEM "&Clear All Settings", IDM_CLEARSETTINGS END POPUP "&Help" BEGIN MENUITEM "&About ...", IDM_ABOUT MENUITEM "&Long description of the game", IDM_HELP_LONG MENUITEM "List of &commands", IDM_HELP_COMMANDS MENUITEM "&History of NetHack", IDM_HELP_HISTORY MENUITEM "&Info on a character", IDM_HELP_INFO_CHAR MENUITEM "Info on what a given &key does", IDM_HELP_INFO_KEY MENUITEM "List of game &options", IDM_HELP_OPTIONS MENUITEM "&Longer list of game options", IDM_HELP_OPTIONS_LONG MENUITEM "List of e&xtended commands", IDM_HELP_EXTCMD MENUITEM "The &NetHack license", IDM_HELP_LICENSE MENUITEM "NetHack for &Windows help", IDM_HELP_PORTHELP END END ///////////////////////////////////////////////////////////////////////////// // // Accelerator // IDC_NETHACKW ACCELERATORS MOVEABLE PURE BEGIN "?", IDM_ABOUT, ASCII, ALT "/", IDM_ABOUT, ASCII, ALT END ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75 STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU CAPTION "About" FONT 8, "System" BEGIN LTEXT "NetHack",IDC_ABOUT_VERSION,10,10,170,15,SS_NOPREFIX LTEXT "Copyright",IDC_ABOUT_COPYRIGHT,10,30,210,40 DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP END IDD_NHTEXT DIALOGEX 0, 0, 172, 178 STYLE DS_SETFOREGROUND | WS_CHILD | WS_THICKFRAME EXSTYLE WS_EX_STATICEDGE FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,54,163,50,14 EDITTEXT IDC_TEXT_CONTROL,0,0,170,160,ES_MULTILINE | ES_OEMCONVERT | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_MENU DIALOGEX 0, 0, 187, 153 STYLE WS_CHILD | WS_CLIPSIBLINGS | WS_THICKFRAME EXSTYLE WS_EX_CLIENTEDGE | WS_EX_CONTROLPARENT | WS_EX_STATICEDGE FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,7,132,50,14,BS_FLAT PUSHBUTTON "Cancel",IDCANCEL,130,132,50,14,BS_FLAT LISTBOX IDC_MENU_LIST,10,10,170,55,LBS_SORT | WS_TABSTOP EDITTEXT IDC_MENU_TEXT,10,70,170,60,ES_MULTILINE | ES_OEMCONVERT | ES_READONLY | WS_VSCROLL | WS_HSCROLL END IDD_GETLIN DIALOG DISCARDABLE 0, 0, 131, 29 STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Question?" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,0,15,65,14 PUSHBUTTON "Cancel",IDCANCEL,65,15,65,14 EDITTEXT IDC_GETLIN_EDIT,0,0,130,13,ES_AUTOHSCROLL END IDD_EXTCMD DIALOG DISCARDABLE 0, 0, 137, 117 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Extended Commands" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,80,7,50,14 PUSHBUTTON "Cancel",IDCANCEL,80,24,50,14 LISTBOX IDC_EXTCMD_LIST,7,7,65,103,LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP END IDD_PLAYER_SELECTOR DIALOG DISCARDABLE 0, 0, 152, 169 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "What are you?" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "Play",IDOK,7,148,66,14 PUSHBUTTON "Quit",IDCANCEL,79,148,66,14 LTEXT "Name:",IDC_STATIC,7,8,25,10 EDITTEXT IDC_PLSEL_NAME,40,7,105,12,ES_AUTOHSCROLL | ES_READONLY | NOT WS_TABSTOP GROUPBOX "Role",IDC_STATIC,7,21,138,30 CONTROL "Random",IDC_PLSEL_ROLE_RANDOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,34,40,10 COMBOBOX IDC_PLSEL_ROLE_LIST,63,33,75,50,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Race",IDC_STATIC,7,51,138,30 CONTROL "Random",IDC_PLSEL_RACE_RANDOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,63,40,10 COMBOBOX IDC_PLSEL_RACE_LIST,63,62,75,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Gender",IDC_STATIC,7,81,138,30 CONTROL "Random",IDC_PLSEL_GENDER_RANDOM,"Button", BS_AUTOCHECKBOX | WS_TABSTOP,14,93,40,10 COMBOBOX IDC_PLSEL_GENDER_LIST,63,92,75,40,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP GROUPBOX "Alignment",IDC_STATIC,7,111,138,30 CONTROL "Random",IDC_PLSEL_ALIGN_RANDOM,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,123,40,10 COMBOBOX IDC_PLSEL_ALIGN_LIST,63,122,75,45,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP END IDD_NHRIP DIALOGEX 0, 0, 281, 209 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Here lies..." FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,82,188,50,14 END IDD_SPLASH DIALOG DISCARDABLE 0, 0, 281, 257 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU CAPTION "Welcome to NetHack" FONT 8, "MS Sans Serif" BEGIN DEFPUSHBUTTON "OK",IDOK,224,236,50,14 EDITTEXT IDC_EXTRAINFO,7,176,267,52,ES_MULTILINE | ES_READONLY | WS_VSCROLL END #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 2 TEXTINCLUDE DISCARDABLE BEGIN "#if defined(__BORLANDC__)\r\n" "LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US\r\n" "#endif\r\n" "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""windows.h""\r\n" "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" "#include ""resource.h""\r\n" "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "\r\n" "\0" END 1 TEXTINCLUDE DISCARDABLE BEGIN "resource.h\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Bitmap // IDB_TILES BITMAP DISCARDABLE "tiles.bmp" IDB_MENU_SEL BITMAP DISCARDABLE "mnsel.bmp" IDB_MENU_UNSEL BITMAP DISCARDABLE "mnunsel.bmp" IDB_PETMARK BITMAP DISCARDABLE "petmark.bmp" IDB_MENU_SEL_COUNT BITMAP DISCARDABLE "mnselcnt.bmp" IDB_RIP BITMAP DISCARDABLE "rip.bmp" IDB_SPLASH BITMAP DISCARDABLE "splash.bmp" ///////////////////////////////////////////////////////////////////////////// // // DESIGNINFO // #ifdef APSTUDIO_INVOKED GUIDELINES DESIGNINFO DISCARDABLE BEGIN IDD_NHTEXT, DIALOG BEGIN BOTTOMMARGIN, 177 END IDD_MENU, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 180 TOPMARGIN, 7 BOTTOMMARGIN, 146 END IDD_GETLIN, DIALOG BEGIN BOTTOMMARGIN, 22 END IDD_EXTCMD, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 130 TOPMARGIN, 7 BOTTOMMARGIN, 110 END IDD_PLAYER_SELECTOR, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 145 TOPMARGIN, 7 BOTTOMMARGIN, 162 END IDD_NHRIP, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 274 TOPMARGIN, 7 BOTTOMMARGIN, 202 END IDD_SPLASH, DIALOG BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 274 BOTTOMMARGIN, 250 END END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 3,4,3,0 PRODUCTVERSION 3,4,3,0 FILEFLAGSMASK 0x1fL #ifdef _DEBUG FILEFLAGS 0x9L #else FILEFLAGS 0x8L #endif FILEOS 0x4L FILETYPE 0x0L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904b0" BEGIN VALUE "FileDescription", "NetHack for Windows - Graphical Interface\0" VALUE "FileVersion", "3.4.3\0" VALUE "InternalName", "NetHackW\0" VALUE "LegalCopyright", "Copyright (C) 1985 - 2003. By Stichting Mathematisch Centrum and M. Stephenson. See license for details.\0" VALUE "OriginalFilename", "NetHackW.exe\0" VALUE "PrivateBuild", "031014\0" VALUE "ProductName", "NetHack\0" VALUE "ProductVersion", "3.4.3\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1200 END END ///////////////////////////////////////////////////////////////////////////// // // String Table // STRINGTABLE DISCARDABLE BEGIN IDS_APP_TITLE "NetHack for Windows - Graphical Interface" IDC_NETHACKW "NETHACKW" IDS_APP_TITLE_SHORT "NetHack for Windows" END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED